From ebf4906d72a2d75d9a4cd7a4dbde383e44daf618 Mon Sep 17 00:00:00 2001 From: Ziyan Date: Sun, 11 Oct 2015 00:01:08 +0200 Subject: [PATCH 001/159] Add our organization as a remote --- default.xml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/default.xml b/default.xml index 61d5e05..19f1645 100644 --- a/default.xml +++ b/default.xml @@ -2,7 +2,9 @@ + fetch="https://android.googlesource.com/" /> + From 2ba42e43322e89a44a59c02bf6cdb323cc65d45e Mon Sep 17 00:00:00 2001 From: Ziyan Date: Sun, 11 Oct 2015 00:11:42 +0200 Subject: [PATCH 002/159] Add projects for grouper --- default.xml | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/default.xml b/default.xml index 19f1645..e594bfc 100644 --- a/default.xml +++ b/default.xml @@ -28,6 +28,7 @@ + @@ -340,6 +341,7 @@ + @@ -476,5 +478,12 @@ + + + + + + + From b76d0739178730f471f8873ae71ed7d17429f164 Mon Sep 17 00:00:00 2001 From: Ziyan Date: Sun, 11 Oct 2015 00:18:14 +0200 Subject: [PATCH 003/159] Fork platform/build Change-Id: Ibed3e4106114fa28bc448b100588c3629f83631d --- default.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/default.xml b/default.xml index e594bfc..cb9fec1 100644 --- a/default.xml +++ b/default.xml @@ -9,7 +9,7 @@ remote="aosp" sync-j="4" /> - + From eaa864b392a6a30841d3bf627d2869f5bcd33a90 Mon Sep 17 00:00:00 2001 From: Ziyan Date: Sun, 11 Oct 2015 16:10:09 +0200 Subject: [PATCH 004/159] Fork invensense and nfc repos Change-Id: I7277b6c09cc8d0d256fb500a5c55c8dfe2b6809d --- default.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/default.xml b/default.xml index cb9fec1..dc85588 100644 --- a/default.xml +++ b/default.xml @@ -316,7 +316,7 @@ - + @@ -375,7 +375,7 @@ - + From d30c6c7fa6a316f4e5f5d018f61594f65350ecfd Mon Sep 17 00:00:00 2001 From: AndDiSa Date: Tue, 3 Nov 2015 19:10:00 +0100 Subject: [PATCH 005/159] switch to 6.0.0_r2 Change-Id: Iaa4985f04fe35b48b2bb2ff5f98ebb9c23bfbca3 --- default.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/default.xml b/default.xml index dc85588..b00e095 100644 --- a/default.xml +++ b/default.xml @@ -5,7 +5,7 @@ fetch="https://android.googlesource.com/" /> - From bc482c0fe1ecf492fcee75b8390218b2a0471796 Mon Sep 17 00:00:00 2001 From: AndDiSa Date: Tue, 3 Nov 2015 20:41:41 +0100 Subject: [PATCH 006/159] move to android-6.0.0_r5 Change-Id: I8cdd7173b9b60949e2dff4e23e9eb2e8acc0b169 --- default.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/default.xml b/default.xml index b00e095..0ad6c6f 100644 --- a/default.xml +++ b/default.xml @@ -5,7 +5,7 @@ fetch="https://android.googlesource.com/" /> - From 79ff576ec260e789adb47b1038897bb16d6103ed Mon Sep 17 00:00:00 2001 From: AndDiSa Date: Thu, 26 Nov 2015 20:43:51 +0100 Subject: [PATCH 007/159] use own repositories Change-Id: If60b4b459f635247838d47b9634acc1ea516da66 --- default.xml | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/default.xml b/default.xml index 0ad6c6f..03791ed 100644 --- a/default.xml +++ b/default.xml @@ -5,11 +5,13 @@ fetch="https://android.googlesource.com/" /> + - + @@ -28,7 +30,7 @@ - + @@ -263,7 +265,7 @@ - + @@ -341,7 +343,7 @@ - + From 845465bdc60ada52acc4804c23f1381e1b3e5f2e Mon Sep 17 00:00:00 2001 From: AndDiSa Date: Wed, 2 Dec 2015 08:56:23 +0100 Subject: [PATCH 008/159] Create README.md --- README.md | 1 + 1 file changed, 1 insertion(+) create mode 100644 README.md diff --git a/README.md b/README.md new file mode 100644 index 0000000..8f59924 --- /dev/null +++ b/README.md @@ -0,0 +1 @@ +Manifest project for building AOSP-6.0 for Grouper From 23d8aeb00614e7fabf0da5d9d755a2ecf653e3b8 Mon Sep 17 00:00:00 2001 From: AndDiSa Date: Tue, 8 Dec 2015 15:15:20 +0100 Subject: [PATCH 009/159] prepare 6.0.1_r3 Change-Id: I1c322c776f38aeb9527bfad5b70fcadc833149da --- default.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/default.xml b/default.xml index 03791ed..6d6ff23 100644 --- a/default.xml +++ b/default.xml @@ -7,7 +7,7 @@ fetch="https://github.com/Grouper-AOSP/" /> - From e1c83f2df44202c50041d1e78d17480bc37a66dd Mon Sep 17 00:00:00 2001 From: AndDiSa Date: Sun, 13 Dec 2015 11:31:08 +0100 Subject: [PATCH 010/159] update hardware/inversense repo Change-Id: I359c12dc1cd12c117a0b64bb9e3ad3cb505b027e --- default.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/default.xml b/default.xml index 6d6ff23..254b6cc 100644 --- a/default.xml +++ b/default.xml @@ -318,7 +318,7 @@ - + From 39ba9d23646dee3c14513ae6a6252132c30b5532 Mon Sep 17 00:00:00 2001 From: AndDiSa Date: Wed, 30 Dec 2015 10:53:43 +0100 Subject: [PATCH 011/159] use AOSP package for Nfc Change-Id: Ie6b41dc0eb03fe12d6795079df94cdcf807496db --- default.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/default.xml b/default.xml index 254b6cc..daadd2a 100644 --- a/default.xml +++ b/default.xml @@ -377,7 +377,7 @@ - + From 1fe93b7c2b8a79a93848029818769bfb16aab1c2 Mon Sep 17 00:00:00 2001 From: AndDiSa Date: Thu, 31 Dec 2015 22:52:53 +0100 Subject: [PATCH 012/159] fork some repositories Change-Id: Id9320015fce438a899a2c5f36f3cfa4c6df9e522 --- default.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/default.xml b/default.xml index daadd2a..10176e7 100644 --- a/default.xml +++ b/default.xml @@ -480,11 +480,11 @@ - + - + From 0e444063dc03f098514560d673449cd658c6624a Mon Sep 17 00:00:00 2001 From: AndDiSa Date: Tue, 5 Jan 2016 09:45:55 +0100 Subject: [PATCH 013/159] update to 6.0.1_r10 Change-Id: I824899bf4f811e1aede0f192e7ffb351a657e776 --- default.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/default.xml b/default.xml index 10176e7..5f67e02 100644 --- a/default.xml +++ b/default.xml @@ -7,7 +7,7 @@ fetch="https://github.com/Grouper-AOSP/" /> - From 3b80acf05635927d1fa5d1f740936ea613b431ee Mon Sep 17 00:00:00 2001 From: AndDiSa Date: Wed, 20 Jan 2016 19:40:50 +0100 Subject: [PATCH 014/159] remove widevine Change-Id: I5d69400cd549e9dcb9468775d0f2f921011cda66 --- default.xml | 1 - 1 file changed, 1 deletion(-) diff --git a/default.xml b/default.xml index 5f67e02..3352e21 100644 --- a/default.xml +++ b/default.xml @@ -486,6 +486,5 @@ - From 2a27b9012a884ca22567d7ffe1f06600b01da5a6 Mon Sep 17 00:00:00 2001 From: AndDiSa Date: Tue, 2 Feb 2016 23:14:41 +0100 Subject: [PATCH 015/159] move to 6.0.1_r13 Change-Id: If8f18e71c6e8c3cd8cf1f27eed4fec0aae47d819 --- default.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/default.xml b/default.xml index 3352e21..c0967c7 100644 --- a/default.xml +++ b/default.xml @@ -7,7 +7,7 @@ fetch="https://github.com/Grouper-AOSP/" /> - From 4cc7ab445bc029624af7ad5d0bc880010624876b Mon Sep 17 00:00:00 2001 From: AndDiSa Date: Tue, 8 Mar 2016 18:32:36 +0100 Subject: [PATCH 016/159] update manifest to 6.0.1_r17 Change-Id: I1b079a942d189293d31bad559838359794b45385 --- default.xml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/default.xml b/default.xml index c0967c7..da230be 100644 --- a/default.xml +++ b/default.xml @@ -7,7 +7,7 @@ fetch="https://github.com/Grouper-AOSP/" /> - @@ -481,10 +481,10 @@ - - - + + + - + From 4b455ae0e9713f11c31cd7fbaa379249420da475 Mon Sep 17 00:00:00 2001 From: AndDiSa Date: Tue, 5 Apr 2016 18:03:39 +0200 Subject: [PATCH 017/159] update to 6.0.1_r24 Change-Id: I72fe11f715b52f2992695bf1f910b774482ce947 --- default.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/default.xml b/default.xml index da230be..c90dc49 100644 --- a/default.xml +++ b/default.xml @@ -7,7 +7,7 @@ fetch="https://github.com/Grouper-AOSP/" /> - From 8e4d7447b7314e88d05a15d3f334a3d41d8ca4f6 Mon Sep 17 00:00:00 2001 From: AndDiSa Date: Tue, 5 Apr 2016 19:22:12 +0200 Subject: [PATCH 018/159] remove obsolet paths Change-Id: I21aeff52db26f6a804895a3cae414466649b7166 --- default.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/default.xml b/default.xml index c90dc49..69f6bc6 100644 --- a/default.xml +++ b/default.xml @@ -363,7 +363,7 @@ - + @@ -460,7 +460,7 @@ - + From ec6fba9e8f3feb32e80d0ca94681864a2a2c0db5 Mon Sep 17 00:00:00 2001 From: AndDiSa Date: Tue, 5 Apr 2016 19:29:06 +0200 Subject: [PATCH 019/159] Revert "remove obsolet paths" This reverts commit 8e4d7447b7314e88d05a15d3f334a3d41d8ca4f6. --- default.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/default.xml b/default.xml index 69f6bc6..c90dc49 100644 --- a/default.xml +++ b/default.xml @@ -363,7 +363,7 @@ - + @@ -460,7 +460,7 @@ - + From c8bbd97b9af58c0caf8480bfee50b065b165a53f Mon Sep 17 00:00:00 2001 From: AndDiSa Date: Tue, 5 Apr 2016 19:56:27 +0200 Subject: [PATCH 020/159] remove obsolete path Change-Id: I86a5fadea1cbf52669eda060b5c44d5089dc34d9 --- default.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/default.xml b/default.xml index c90dc49..54edd6b 100644 --- a/default.xml +++ b/default.xml @@ -363,7 +363,7 @@ - + From 243efda76182de1698f8d25ca2a728e0d3c44ba4 Mon Sep 17 00:00:00 2001 From: AndDiSa Date: Tue, 3 May 2016 19:17:31 +0200 Subject: [PATCH 021/159] update to android-6.0.1_r43 Change-Id: I5a2c2322c47a3f4d0cfab18c02d7f95921be35b0 --- default.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/default.xml b/default.xml index 54edd6b..139ff97 100644 --- a/default.xml +++ b/default.xml @@ -7,7 +7,7 @@ fetch="https://github.com/Grouper-AOSP/" /> - From 3540c45d3494823caa4628662962179e5021d792 Mon Sep 17 00:00:00 2001 From: AndDiSa Date: Tue, 3 May 2016 22:01:19 +0200 Subject: [PATCH 022/159] move to 6.0.1_r25 Change-Id: Ie7d164520f9451529f4d3fc155fa5696df65646d --- default.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/default.xml b/default.xml index 139ff97..7025b12 100644 --- a/default.xml +++ b/default.xml @@ -7,7 +7,7 @@ fetch="https://github.com/Grouper-AOSP/" /> - From 10b79205d44020d3489c27e77adb00fd304b8aa6 Mon Sep 17 00:00:00 2001 From: AndDiSa Date: Tue, 7 Jun 2016 18:24:11 +0200 Subject: [PATCH 023/159] update to android-6.0.1_r46 Change-Id: I913760e5a719360418eb6aafe9ef609fddc98329 --- default.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/default.xml b/default.xml index 7025b12..a11cebe 100644 --- a/default.xml +++ b/default.xml @@ -7,7 +7,7 @@ fetch="https://github.com/Grouper-AOSP/" /> - From f11249e74ac893eae47a2d7aca66460a44586404 Mon Sep 17 00:00:00 2001 From: AndDiSa Date: Sat, 11 Jun 2016 13:42:51 +0200 Subject: [PATCH 024/159] new branch 6.0.1 Change-Id: I285ffd78cdfb6c197b83959046ebee15a1249a66 --- default.xml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/default.xml b/default.xml index a11cebe..a37de5d 100644 --- a/default.xml +++ b/default.xml @@ -7,11 +7,11 @@ fetch="https://github.com/Grouper-AOSP/" /> - - + @@ -30,7 +30,7 @@ - + @@ -265,7 +265,7 @@ - + From f024f80e01ba0d6d683ca8f191621df52b32e7f2 Mon Sep 17 00:00:00 2001 From: AndDiSa Date: Sat, 11 Jun 2016 13:50:14 +0200 Subject: [PATCH 025/159] update to android-6.0.1_r45 Change-Id: Icbd597807162fc1bf16727b7107dd9064ba735f0 --- default.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/default.xml b/default.xml index a37de5d..6916f6b 100644 --- a/default.xml +++ b/default.xml @@ -7,7 +7,7 @@ fetch="https://github.com/Grouper-AOSP/" /> - From c8fd2a4627a33426957dcb67d7097de78656596c Mon Sep 17 00:00:00 2001 From: AndDiSa Date: Fri, 8 Jul 2016 18:36:37 +0200 Subject: [PATCH 026/159] update to android-6.0.1_r54 Change-Id: I58fe1a658e30c4c221f6a88cbcd204111d35bdeb --- default.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/default.xml b/default.xml index 6916f6b..4e36022 100644 --- a/default.xml +++ b/default.xml @@ -7,7 +7,7 @@ fetch="https://github.com/Grouper-AOSP/" /> - From 5ef04bbab2578e538206809abcefc457ad1c01bb Mon Sep 17 00:00:00 2001 From: AndDiSa Date: Tue, 2 Aug 2016 19:52:09 +0200 Subject: [PATCH 027/159] update to android-6.0.1_r62 Change-Id: I5336ab52b08a60f3f965dde6f1f00c3413971c22 --- default.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/default.xml b/default.xml index 4e36022..bb6655a 100644 --- a/default.xml +++ b/default.xml @@ -7,7 +7,7 @@ fetch="https://github.com/Grouper-AOSP/" /> - From 895feea571fdf1a96c87e19b8b91886660ef1e1d Mon Sep 17 00:00:00 2001 From: AndDiSa Date: Wed, 3 Aug 2016 19:30:14 +0200 Subject: [PATCH 028/159] update sepolicy config Change-Id: I9c2f0ad1968de14c164e9b0675aa9fa3562d8e52 --- default.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/default.xml b/default.xml index bb6655a..b63bb60 100644 --- a/default.xml +++ b/default.xml @@ -229,7 +229,7 @@ - + From cbd55e5f58b07ffa75f804f5889f52ea9b1354be Mon Sep 17 00:00:00 2001 From: AndDiSa Date: Wed, 3 Aug 2016 19:42:20 +0200 Subject: [PATCH 029/159] correct path for sepolicy Change-Id: I521dfa610517d4a47b2b75ab855b51669445e729 --- default.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/default.xml b/default.xml index b63bb60..321f7b5 100644 --- a/default.xml +++ b/default.xml @@ -229,7 +229,7 @@ - + From 231e603c17629ee9ce633ae5b67fc9ab61fac2b5 Mon Sep 17 00:00:00 2001 From: AndDiSa Date: Wed, 3 Aug 2016 20:25:02 +0200 Subject: [PATCH 030/159] update sepolicy path Change-Id: I6f6b21cc415c2d85c7d76858a9b273f8f0015de1 --- default.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/default.xml b/default.xml index 321f7b5..d875b26 100644 --- a/default.xml +++ b/default.xml @@ -229,7 +229,7 @@ - + From 29e555807ddaf83e440d0c627fd1052d45f68dfb Mon Sep 17 00:00:00 2001 From: AndDiSa Date: Wed, 7 Sep 2016 19:06:34 +0200 Subject: [PATCH 031/159] update to 6.0.1_r67 Change-Id: I1ca9f4d6d0c9b0ed5d44fc7a2583d4120ed76301 --- default.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/default.xml b/default.xml index d875b26..110ded6 100644 --- a/default.xml +++ b/default.xml @@ -7,7 +7,7 @@ fetch="https://github.com/Grouper-AOSP/" /> - From cddafcc0b01b6c049937167674eb79e88541d679 Mon Sep 17 00:00:00 2001 From: AndDiSa Date: Fri, 9 Sep 2016 08:14:46 +0200 Subject: [PATCH 032/159] initial bring up Change-Id: I6281d819f72d1f6f7ffa99cde8fa71ce5bacbe03 --- default.xml | 161 ++++++++++++++++++++++++++++++++-------------------- 1 file changed, 99 insertions(+), 62 deletions(-) diff --git a/default.xml b/default.xml index 110ded6..cbf843c 100644 --- a/default.xml +++ b/default.xml @@ -3,18 +3,27 @@ - - - + - + + + + + + + + @@ -22,15 +31,9 @@ - - - - - - - + @@ -48,17 +51,12 @@ - - - - - - + + - @@ -66,12 +64,16 @@ + + + + @@ -82,44 +84,58 @@ + + + + + + + + + - + + + + + + @@ -128,35 +144,46 @@ - + + + - + + + + + + + + + + @@ -167,10 +194,9 @@ - - + @@ -178,12 +204,11 @@ + - - @@ -193,10 +218,13 @@ + + + @@ -213,27 +241,32 @@ - - + + + + - + + + + @@ -243,34 +276,38 @@ + + + + + - + - @@ -278,7 +315,6 @@ - @@ -294,7 +330,6 @@ - @@ -318,12 +353,11 @@ - + - @@ -332,24 +366,25 @@ + - + - + @@ -362,8 +397,9 @@ + - + @@ -377,7 +413,7 @@ - + @@ -386,13 +422,13 @@ - + @@ -415,70 +451,71 @@ - - - - - - - - + + + - - - - - - - - - + + - + - + + + + + + + + + + + + + - + + + - - + From a47b4e5a89d128f756cc24b9afa06909c3fab11c Mon Sep 17 00:00:00 2001 From: AndDiSa Date: Fri, 9 Sep 2016 09:08:41 +0200 Subject: [PATCH 033/159] update to 7.0.0_r6 Change-Id: I9eac24bf2a13f3603db9db7365d7471a5a8588f2 --- default.xml | 26 +++++++++----------------- 1 file changed, 9 insertions(+), 17 deletions(-) diff --git a/default.xml b/default.xml index cbf843c..898d0fe 100644 --- a/default.xml +++ b/default.xml @@ -5,7 +5,7 @@ fetch="https://android.googlesource.com/" /> - @@ -39,10 +39,8 @@ - - @@ -64,6 +62,7 @@ + @@ -91,17 +90,15 @@ - + - - @@ -131,7 +128,6 @@ - @@ -170,7 +166,6 @@ - @@ -181,6 +176,7 @@ + @@ -213,7 +209,6 @@ - @@ -260,7 +255,6 @@ - @@ -357,8 +351,8 @@ - + @@ -369,7 +363,6 @@ - @@ -395,16 +388,14 @@ + - - - @@ -435,6 +426,7 @@ + @@ -448,6 +440,7 @@ + @@ -455,9 +448,9 @@ - + @@ -486,7 +479,6 @@ - From 99f17c5a3df75e6cfeacfd62d09725ba964baf5f Mon Sep 17 00:00:00 2001 From: AndDiSa Date: Fri, 9 Sep 2016 19:29:11 +0200 Subject: [PATCH 034/159] remove superflouus projects Change-Id: I57a22e4b52566759a46df0860b3b3bdb47b34f99 --- README.md | 2 +- default.xml | 9 +++------ 2 files changed, 4 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index 8f59924..8083f4b 100644 --- a/README.md +++ b/README.md @@ -1 +1 @@ -Manifest project for building AOSP-6.0 for Grouper +Manifest project for building AOSP-7.0 for Grouper diff --git a/default.xml b/default.xml index 898d0fe..6e9cf68 100644 --- a/default.xml +++ b/default.xml @@ -152,7 +152,6 @@ - @@ -179,7 +178,6 @@ - @@ -370,7 +368,7 @@ - + @@ -380,7 +378,6 @@ - @@ -447,7 +444,7 @@ - + @@ -470,7 +467,7 @@ - + From f7d97bde34389a27971e023b66866f70f74c33fe Mon Sep 17 00:00:00 2001 From: AndDiSa Date: Sat, 24 Sep 2016 10:17:44 +0200 Subject: [PATCH 035/159] update some projects Change-Id: I845a3870549227475cac96d2a5c1ac27d02715c2 --- default.xml | 27 +++++++++++++++------------ 1 file changed, 15 insertions(+), 12 deletions(-) diff --git a/default.xml b/default.xml index 6e9cf68..7bbce35 100644 --- a/default.xml +++ b/default.xml @@ -27,13 +27,13 @@ - + - + @@ -129,7 +129,7 @@ - + @@ -279,12 +279,13 @@ + - + @@ -295,7 +296,7 @@ - + @@ -331,6 +332,7 @@ + @@ -369,7 +371,7 @@ - + @@ -443,7 +445,7 @@ - + @@ -504,13 +506,14 @@ - + - - + + - - + + + From 3a31c0c20b6fdc265a34b25414009f92ce52db08 Mon Sep 17 00:00:00 2001 From: AndDiSa Date: Wed, 5 Oct 2016 18:14:01 +0200 Subject: [PATCH 036/159] update to android-7.0.0_r7 Change-Id: I7f0443a7b4acd04e69be034a4df3cf7c4ccc8a25 --- default.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/default.xml b/default.xml index 7bbce35..90d231a 100644 --- a/default.xml +++ b/default.xml @@ -5,7 +5,7 @@ fetch="https://android.googlesource.com/" /> - @@ -513,7 +513,7 @@ - + From 52c0b308862b07e5ebcf6ffe8f849308dcda448d Mon Sep 17 00:00:00 2001 From: AndDiSa Date: Fri, 7 Oct 2016 09:58:45 +0200 Subject: [PATCH 037/159] update to android-7.0.0_r14 Change-Id: I35a63279dceeb4008d4a54adc58faf4cdb3ae1f9 --- default.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/default.xml b/default.xml index 90d231a..e146727 100644 --- a/default.xml +++ b/default.xml @@ -5,7 +5,7 @@ fetch="https://android.googlesource.com/" /> - From cb4664ec9f14eac303b62b4d7d6950e5f0eddfee Mon Sep 17 00:00:00 2001 From: AndDiSa Date: Mon, 24 Oct 2016 11:00:23 +0200 Subject: [PATCH 038/159] merged with android-7.1.0_r4 Change-Id: I65680cab985ce1aad9e0927dbaf26387e6fd2822 --- default.xml | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/default.xml b/default.xml index e146727..6b6a82f 100644 --- a/default.xml +++ b/default.xml @@ -5,7 +5,7 @@ fetch="https://android.googlesource.com/" /> - @@ -136,6 +136,8 @@ + + @@ -173,6 +175,7 @@ + @@ -280,6 +283,7 @@ + @@ -411,11 +415,13 @@ + + From 9a05476004bf37ff1417a34c579472a3f6d009b1 Mon Sep 17 00:00:00 2001 From: AndDiSa Date: Sun, 6 Nov 2016 15:25:06 +0100 Subject: [PATCH 039/159] use own lib for libnfc-nxp Change-Id: I707fdf9e33655773e5771174bb0c4d4b0e92370d --- default.xml | 16 +--------------- 1 file changed, 1 insertion(+), 15 deletions(-) diff --git a/default.xml b/default.xml index 6b6a82f..ed5d41d 100644 --- a/default.xml +++ b/default.xml @@ -12,22 +12,15 @@ - - - @@ -184,7 +177,7 @@ - + @@ -374,7 +367,6 @@ - @@ -451,8 +443,6 @@ - - @@ -475,7 +465,6 @@ - @@ -512,14 +501,11 @@ - - - From 4317bd1a187939b43f8157548d251f4cb6bc7307 Mon Sep 17 00:00:00 2001 From: AndDiSa Date: Tue, 8 Nov 2016 18:13:57 +0100 Subject: [PATCH 040/159] update to android-7.1.0_r Change-Id: Ie41fca9995857649a85afb77cb73add6ceb05b5a --- default.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/default.xml b/default.xml index ed5d41d..39d4866 100644 --- a/default.xml +++ b/default.xml @@ -5,7 +5,7 @@ fetch="https://android.googlesource.com/" /> - From 31776373e7bbd249f7a31947f09a797bc474cd8e Mon Sep 17 00:00:00 2001 From: AndDiSa Date: Tue, 8 Nov 2016 18:38:32 +0100 Subject: [PATCH 041/159] correct library name Change-Id: Ic93b75c798d7017326bbeacb4b014c8975f42463 --- default.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/default.xml b/default.xml index 39d4866..73de1b4 100644 --- a/default.xml +++ b/default.xml @@ -177,7 +177,7 @@ - + From b1123b7566123d0a84b47716f9adccbfb0789835 Mon Sep 17 00:00:00 2001 From: AndDiSa Date: Wed, 23 Nov 2016 18:47:19 +0100 Subject: [PATCH 042/159] add repo for tilapia Change-Id: I6ac4b06fc528e35680e270cbe4eec3648d7197be --- default.xml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/default.xml b/default.xml index 73de1b4..e96bac4 100644 --- a/default.xml +++ b/default.xml @@ -5,6 +5,8 @@ fetch="https://android.googlesource.com/" /> + @@ -27,6 +29,7 @@ + From 75f3cc7af3d2b768045ca3007618469633f5cc25 Mon Sep 17 00:00:00 2001 From: AndDiSa Date: Wed, 23 Nov 2016 19:23:16 +0100 Subject: [PATCH 043/159] add patches for repos not forked (yet) Change-Id: I00ea61ca5b4ab75052c618f99c44945ba8031de4 --- README.md | 46 ++- build.patch | 215 +++++++++++ frameworks_av.patch | 431 +++++++++++++++++++++ frameworks_base.patch | 13 + frameworks_native.patch | 24 ++ packages_apps_music.patch | 13 + system_core.patch | 197 ++++++++++ system_sepolicy.patch | 769 ++++++++++++++++++++++++++++++++++++++ 8 files changed, 1707 insertions(+), 1 deletion(-) create mode 100644 build.patch create mode 100644 frameworks_av.patch create mode 100644 frameworks_base.patch create mode 100644 frameworks_native.patch create mode 100644 packages_apps_music.patch create mode 100644 system_core.patch create mode 100644 system_sepolicy.patch diff --git a/README.md b/README.md index 8083f4b..b351429 100644 --- a/README.md +++ b/README.md @@ -1 +1,45 @@ -Manifest project for building AOSP-7.0 for Grouper +Manifest project for building AOSP-7.1.x for Nexus 7 (2012) Grouper and Tilapia + +Instructions for building: + +repo init -u https://github.com/AndDiSa/platform_manifest-Grouper-AOSP.git -b ads-7.1.0 + +repo sync + +... + +cd build +patch -p 1 < ../.repo/manifests/build.patch +cd .. + +cd frameworks/av +patch -p 1 < ../../.repo/manifests/frameworks_av.patch +cd ../.. + +cd frameworks/base +patch -p 1 < ../../.repo/manifests/frameworks_base.patch +cd ../.. + +cd frameworks/native +patch -p 1 < ../../.repo/manifests/frameworks_native.patch +cd ../.. + +cd packages/aps/Music +patch -p 1 < ../../../.repo/manifests/packages_apps_music.patch +cd ../../.. + +cd system/core +patch -p 1 < ../../.repo/manifests/system_core.patch +cd ../.. + +cd system/core +patch -p 1 < ../../.repo/manifests/system_sepolicy.patch +cd ../.. + +. build/envsetup.sh + +lunch 7 # for making grouper + +make -j otapackage + + diff --git a/build.patch b/build.patch new file mode 100644 index 0000000..d6ed881 --- /dev/null +++ b/build.patch @@ -0,0 +1,215 @@ +diff --git a/core/main.mk b/core/main.mk +index a612f83..921eb32 100644 +--- a/core/main.mk ++++ b/core/main.mk +@@ -215,7 +215,7 @@ endif + # For Java 1.7/1.8, we require OpenJDK on linux and Oracle JDK on Mac OS. + requires_openjdk := false + ifeq ($(BUILD_OS),linux) +-requires_openjdk := true ++requires_openjdk := false + endif + + +diff --git a/core/tasks/kernel.mk b/core/tasks/kernel.mk +new file mode 100644 +index 0000000..9c12bc0 +--- /dev/null ++++ b/core/tasks/kernel.mk +@@ -0,0 +1,196 @@ ++# Copyright (C) 2012 The CyanogenMod 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. ++ ++# Android makefile to build kernel as a part of Android Build ++ ++TARGET_AUTO_KDIR := $(shell echo $(TARGET_DEVICE_DIR) | sed -e 's/^device/kernel/g') ++ ++## Externally influenced variables ++# kernel location - optional, defaults to kernel// ++TARGET_KERNEL_SOURCE ?= $(TARGET_AUTO_KDIR) ++KERNEL_SRC := $(TARGET_KERNEL_SOURCE) ++# kernel configuration - mandatory ++KERNEL_DEFCONFIG := $(TARGET_KERNEL_CONFIG) ++VARIANT_DEFCONFIG := $(TARGET_KERNEL_VARIANT_CONFIG) ++SELINUX_DEFCONFIG := $(TARGET_KERNEL_SELINUX_CONFIG) ++ ++## Internal variables ++KERNEL_OUT := $(ANDROID_BUILD_TOP)/$(TARGET_OUT_INTERMEDIATES)/KERNEL_OBJ ++KERNEL_CONFIG := $(KERNEL_OUT)/.config ++ ++ifneq ($(BOARD_KERNEL_IMAGE_NAME),) ++ TARGET_PREBUILT_INT_KERNEL_TYPE := $(BOARD_KERNEL_IMAGE_NAME) ++ TARGET_PREBUILT_INT_KERNEL := $(TARGET_OUT_INTERMEDUATES)/KERNEL_OBJ/arch/$(TARGET_ARCH)/boot/$(TARGET_PREBUILT_INT_KERNEL_TYPE) ++else ++ TARGET_PREBUILT_INT_KERNEL := $(TARGET_OUT_INTERMEDIATES)/KERNEL_OBJ/arch/$(TARGET_ARCH)/boot/zImage ++ TARGET_PREBUILT_INT_KERNEL_TYPE := zImage ++endif ++ ++## Do be discontinued in a future version. Notify builder about target ++## kernel format requirement ++ifeq ($(BOARD_KERNEL_IMAGE_NAME),) ++ifeq ($(BOARD_USES_UBOOT),true) ++ $(error "Please set BOARD_KERNEL_IMAGE_NAME to uImage") ++else ifeq ($(BOARD_USES_UNCOMPRESSED_BOOT),true) ++ $(error "Please set BOARD_KERNEL_IMAGE_NAME to Image") ++endif ++endif ++ ++ifeq "$(wildcard $(KERNEL_SRC) )" "" ++ ifneq ($(TARGET_PREBUILT_KERNEL),) ++ HAS_PREBUILT_KERNEL := true ++ NEEDS_KERNEL_COPY := true ++ else ++ $(foreach cf,$(PRODUCT_COPY_FILES), \ ++ $(eval _src := $(call word-colon,1,$(cf))) \ ++ $(eval _dest := $(call word-colon,2,$(cf))) \ ++ $(ifeq kernel,$(_dest), \ ++ $(eval HAS_PREBUILT_KERNEL := true))) ++ endif ++ ++ ifneq ($(HAS_PREBUILT_KERNEL),) ++ $(warning ***************************************************************) ++ $(warning * Using prebuilt kernel binary instead of source *) ++ $(warning * THIS IS DEPRECATED, AND WILL BE DISCONTINUED *) ++ $(warning * Please configure your device to download the kernel *) ++ $(warning * source repository to $(KERNEL_SRC)) ++ $(warning * See http://wiki.cyanogenmod.org/w/Doc:_integrated_kernel_building) ++ $(warning * for more information *) ++ $(warning ***************************************************************) ++ FULL_KERNEL_BUILD := false ++ KERNEL_BIN := $(TARGET_PREBUILT_KERNEL) ++ else ++ $(warning ***************************************************************) ++ $(warning * *) ++ $(warning * No kernel source found, and no fallback prebuilt defined. *) ++ $(warning * Please make sure your device is properly configured to *) ++ $(warning * download the kernel repository to $(KERNEL_SRC)) ++ $(warning * and add the TARGET_KERNEL_CONFIG variable to BoardConfig.mk *) ++ $(warning * *) ++ $(warning * As an alternative, define the TARGET_PREBUILT_KERNEL *) ++ $(warning * variable with the path to the prebuilt binary kernel image *) ++ $(warning * in your BoardConfig.mk file *) ++ $(warning * *) ++ $(warning ***************************************************************) ++ $(error "NO KERNEL") ++ endif ++else ++ NEEDS_KERNEL_COPY := true ++ ifeq ($(TARGET_KERNEL_CONFIG),) ++ $(warning **********************************************************) ++ $(warning * Kernel source found, but no configuration was defined *) ++ $(warning * Please add the TARGET_KERNEL_CONFIG variable to your *) ++ $(warning * BoardConfig.mk file *) ++ $(warning **********************************************************) ++ # $(error "NO KERNEL CONFIG") ++ else ++ #$(info Kernel source found, building it) ++ FULL_KERNEL_BUILD := true ++ ifeq ($(TARGET_USES_UNCOMPRESSED_KERNEL),true) ++ $(info Using uncompressed kernel) ++ KERNEL_BIN := $(KERNEL_OUT)/piggy ++ else ++ KERNEL_BIN := $(TARGET_PREBUILT_INT_KERNEL) ++ endif ++ endif ++endif ++ ++ifeq ($(FULL_KERNEL_BUILD),true) ++ ++KERNEL_HEADERS_INSTALL := $(KERNEL_OUT)/usr ++KERNEL_MODULES_INSTALL := system ++KERNEL_MODULES_OUT := $(TARGET_OUT)/lib/modules ++ ++define mv-modules ++ mdpath=`find $(KERNEL_MODULES_OUT) -type f -name modules.order`;\ ++ if [ "$$mdpath" != "" ];then\ ++ mpath=`dirname $$mdpath`;\ ++ ko=`find $$mpath/kernel -type f -name *.ko`;\ ++ for i in $$ko; do $(ARM_EABI_TOOLCHAIN)/arm-abi-strip --strip-unneeded $$i;\ ++ mv $$i $(KERNEL_MODULES_OUT)/; done;\ ++ fi ++endef ++ ++define clean-module-folder ++ mdpath=`find $(KERNEL_MODULES_OUT) -type f -name modules.order`;\ ++ if [ "$$mdpath" != "" ];then\ ++ mpath=`dirname $$mdpath`; rm -rf $$mpath;\ ++ fi ++endef ++ ++ifeq ($(TARGET_ARCH),arm) ++ ifneq ($(USE_CCACHE),) ++ ccache := $(ANDROID_BUILD_TOP)/prebuilts/misc/$(HOST_PREBUILT_TAG)/ccache/ccache ++ # Check that the executable is here. ++ ccache := $(strip $(wildcard $(ccache))) ++ endif ++ ifneq ($(TARGET_KERNEL_CUSTOM_TOOLCHAIN),) ++ ifeq ($(HOST_OS),darwin) ++ ARM_CROSS_COMPILE:=CROSS_COMPILE="$(ccache) $(ANDROID_BUILD_TOP)/prebuilts/gcc/darwin-x86/arm/$(TARGET_KERNEL_CUSTOM_TOOLCHAIN)/bin/arm-eabi-" ++ else ++ ARM_CROSS_COMPILE:=CROSS_COMPILE="$(ccache) $(ANDROID_BUILD_TOP)/prebuilts/gcc/linux-x86/arm/$(TARGET_KERNEL_CUSTOM_TOOLCHAIN)/bin/arm-linux-androidkernel-" ++ endif ++ else ++ ARM_CROSS_COMPILE:=CROSS_COMPILE="$(ccache) $(ARM_EABI_TOOLCHAIN)/arm-linux-androidkernel-" ++ endif ++ ccache = ++endif ++ ++ifeq ($(HOST_OS),darwin) ++ MAKE_FLAGS := C_INCLUDE_PATH=$(ANDROID_BUILD_TOP)/external/elfutils/libelf ++endif ++ ++ifeq ($(TARGET_KERNEL_MODULES),) ++ TARGET_KERNEL_MODULES := no-external-modules ++endif ++ ++$(KERNEL_OUT): ++ mkdir -p $(KERNEL_OUT) ++ mkdir -p $(KERNEL_MODULES_OUT) ++ ++$(KERNEL_CONFIG): $(KERNEL_OUT) ++ $(MAKE) $(MAKE_FLAGS) -C $(KERNEL_SRC) O=$(KERNEL_OUT) ARCH=$(TARGET_ARCH) $(ARM_CROSS_COMPILE) VARIANT_DEFCONFIG=$(VARIANT_DEFCONFIG) SELINUX_DEFCONFIG=$(SELINUX_DEFCONFIG) $(KERNEL_DEFCONFIG) ++ ++$(KERNEL_OUT)/piggy : $(TARGET_PREBUILT_INT_KERNEL) ++ $(hide) gunzip -c $(KERNEL_OUT)/arch/$(TARGET_ARCH)/boot/compressed/piggy.gzip > $(KERNEL_OUT)/piggy ++ ++TARGET_KERNEL_BINARIES: $(KERNEL_OUT) $(KERNEL_CONFIG) $(KERNEL_HEADERS_INSTALL) ++ $(MAKE) $(MAKE_FLAGS) -C $(KERNEL_SRC) O=$(KERNEL_OUT) ARCH=$(TARGET_ARCH) $(ARM_CROSS_COMPILE) $(TARGET_PREBUILT_INT_KERNEL_TYPE) ++ -$(MAKE) $(MAKE_FLAGS) -C $(KERNEL_SRC) O=$(KERNEL_OUT) ARCH=$(TARGET_ARCH) $(ARM_CROSS_COMPILE) dtbs ++ -$(MAKE) $(MAKE_FLAGS) -C $(KERNEL_SRC) O=$(KERNEL_OUT) ARCH=$(TARGET_ARCH) $(ARM_CROSS_COMPILE) modules ++ -$(MAKE) $(MAKE_FLAGS) -C $(KERNEL_SRC) O=$(KERNEL_OUT) INSTALL_MOD_PATH=../../$(KERNEL_MODULES_INSTALL) ARCH=$(TARGET_ARCH) $(ARM_CROSS_COMPILE) modules_install ++ $(mv-modules) ++ $(clean-module-folder) ++ ++$(TARGET_KERNEL_MODULES): TARGET_KERNEL_BINARIES ++ ++$(TARGET_PREBUILT_INT_KERNEL): $(TARGET_KERNEL_MODULES) ++ $(mv-modules) ++ $(clean-module-folder) ++ ++$(KERNEL_HEADERS_INSTALL): $(KERNEL_OUT) $(KERNEL_CONFIG) ++ $(MAKE) $(MAKE_FLAGS) -C $(KERNEL_SRC) O=$(KERNEL_OUT) ARCH=$(TARGET_ARCH) $(ARM_CROSS_COMPILE) headers_install ++ ++endif # FULL_KERNEL_BUILD ++ ++## Install it ++ ++ifeq ($(NEEDS_KERNEL_COPY),true) ++file := $(INSTALLED_KERNEL_TARGET) ++ALL_PREBUILT += $(file) ++$(file) : $(KERNEL_BIN) | $(ACP) ++ $(transform-prebuilt-to-target) ++ ++ALL_PREBUILT += $(INSTALLED_KERNEL_TARGET) ++endif diff --git a/frameworks_av.patch b/frameworks_av.patch new file mode 100644 index 0000000..8e9c84f --- /dev/null +++ b/frameworks_av.patch @@ -0,0 +1,431 @@ +diff --git a/camera/cameraserver/Android.mk b/camera/cameraserver/Android.mk +index 7e36c5e..aca7a19 100644 +--- a/camera/cameraserver/Android.mk ++++ b/camera/cameraserver/Android.mk +@@ -14,6 +14,9 @@ + + LOCAL_PATH:= $(call my-dir) + ++ifeq ($(TARGET_HAS_LEGACY_CAMERA_HAL1),true) ++$(warning Target has integrated cameraserver into mediaserver. This is weakening security measures introduced in 7.0) ++else + include $(CLEAR_VARS) + + LOCAL_SRC_FILES:= \ +@@ -34,3 +37,4 @@ LOCAL_CFLAGS += -Wall -Wextra -Werror -Wno-unused-parameter + LOCAL_INIT_RC := cameraserver.rc + + include $(BUILD_EXECUTABLE) ++endif +diff --git a/include/media/stagefright/MediaBufferGroup.h b/include/media/stagefright/MediaBufferGroup.h +index dfa31b2..2dc77ac 100644 +--- a/include/media/stagefright/MediaBufferGroup.h ++++ b/include/media/stagefright/MediaBufferGroup.h +@@ -49,7 +49,10 @@ public: + // If requestedSize is > 0, the returned MediaBuffer should have buffer + // size of at least requstedSize. + status_t acquire_buffer( +- MediaBuffer **buffer, bool nonBlocking = false, size_t requestedSize = 0); ++ MediaBuffer **buffer, bool nonBlocking, size_t requestedSize); ++ ++ status_t acquire_buffer(MediaBuffer **buffer); ++ status_t acquire_buffer(MediaBuffer **buffer, bool nonBlocking); + + size_t buffers() const { return mBuffers.size(); } + +diff --git a/media/libstagefright/ACodec.cpp b/media/libstagefright/ACodec.cpp +index 37fd5a5..706ba4e 100644 +--- a/media/libstagefright/ACodec.cpp ++++ b/media/libstagefright/ACodec.cpp +@@ -804,13 +804,22 @@ status_t ACodec::allocateBuffersOnPort(OMX_U32 portIndex) { + } else if (type == kMetadataBufferTypeNativeHandleSource) { + bufSize = sizeof(VideoNativeHandleMetadata); + } ++#ifdef CAMCORDER_GRALLOC_SOURCE ++ else if (type == kMetadataBufferTypeGrallocSource) { ++ bufSize = sizeof(VideoGrallocMetadata); ++ } ++#endif + + // If using gralloc or native source input metadata buffers, allocate largest + // metadata size as we prefer to generate native source metadata, but component + // may require gralloc source. For camera source, allocate at least enough + // size for native metadata buffers. + size_t allottedSize = bufSize; ++#ifdef CAMCORDER_GRALLOC_SOURCE ++ if (portIndex == kPortIndexInput && type >= kMetadataBufferTypeGrallocSource) { ++#else + if (portIndex == kPortIndexInput && type == kMetadataBufferTypeANWBuffer) { ++#endif + bufSize = max(sizeof(VideoGrallocMetadata), sizeof(VideoNativeMetadata)); + } else if (portIndex == kPortIndexInput && type == kMetadataBufferTypeCameraSource) { + bufSize = max(bufSize, sizeof(VideoNativeMetadata)); +@@ -1766,6 +1775,14 @@ status_t ACodec::configureCodec( + mInputMetadataType = (MetadataBufferType)storeMeta; + } + ++#ifdef CAMCORDER_GRALLOC_SOURCE ++ // For this specific case we could be using camera source even if storeMetaDataInBuffers ++ // returns Gralloc source. Pretend that we are; this will force us to use nBufferSize. ++ if (mInputMetadataType == kMetadataBufferTypeGrallocSource) { ++ mInputMetadataType = kMetadataBufferTypeCameraSource; ++ } ++#endif ++ + uint32_t usageBits; + if (mOMX->getParameter( + mNode, (OMX_INDEXTYPE)OMX_IndexParamConsumerUsageBits, +@@ -6036,6 +6053,9 @@ void ACodec::BaseState::onInputBufferFilled(const sp &msg) { + status_t err2 = OK; + switch (metaType) { + case kMetadataBufferTypeInvalid: ++#ifdef CAMCORDER_GRALLOC_SOURCE ++ case kMetadataBufferTypeCameraSource: ++#endif + break; + #ifndef OMX_ANDROID_COMPILE_AS_32BIT_ON_64BIT_PLATFORMS + case kMetadataBufferTypeNativeHandleSource: +@@ -6267,6 +6287,10 @@ bool ACodec::BaseState::onOMXFillBufferDone( + native_handle_t *handle = NULL; + VideoNativeHandleMetadata &nativeMeta = + *(VideoNativeHandleMetadata *)info->mData->data(); ++#ifdef CAMCORDER_GRALLOC_SOURCE ++ VideoGrallocMetadata &grallocMeta = ++ *(VideoGrallocMetadata *)info->mData->data(); ++#endif + if (info->mData->size() >= sizeof(nativeMeta) + && nativeMeta.eType == kMetadataBufferTypeNativeHandleSource) { + #ifdef OMX_ANDROID_COMPILE_AS_32BIT_ON_64BIT_PLATFORMS +@@ -6276,6 +6300,12 @@ bool ACodec::BaseState::onOMXFillBufferDone( + handle = (native_handle_t *)nativeMeta.pHandle; + #endif + } ++#ifdef CAMCORDER_GRALLOC_SOURCE ++ else if (info->mData->size() >= sizeof(grallocMeta) ++ && grallocMeta.eType == kMetadataBufferTypeGrallocSource) { ++ handle = (native_handle_t *)(uintptr_t)grallocMeta.pHandle; ++ } ++#endif + info->mData->meta()->setPointer("handle", handle); + info->mData->meta()->setInt32("rangeOffset", rangeOffset); + info->mData->meta()->setInt32("rangeLength", rangeLength); +@@ -6968,10 +6998,12 @@ void ACodec::LoadedState::onCreateInputSurface( + err = mCodec->mOMX->createInputSurface( + mCodec->mNode, kPortIndexInput, dataSpace, &bufferProducer, + &mCodec->mInputMetadataType); ++#ifndef CAMCORDER_GRALLOC_SOURCE + // framework uses ANW buffers internally instead of gralloc handles + if (mCodec->mInputMetadataType == kMetadataBufferTypeGrallocSource) { + mCodec->mInputMetadataType = kMetadataBufferTypeANWBuffer; + } ++#endif + } + + if (err == OK) { +@@ -7014,10 +7046,12 @@ void ACodec::LoadedState::onSetInputSurface( + err = mCodec->mOMX->setInputSurface( + mCodec->mNode, kPortIndexInput, surface->getBufferConsumer(), + &mCodec->mInputMetadataType); ++#ifndef CAMCORDER_GRALLOC_SOURCE + // framework uses ANW buffers internally instead of gralloc handles + if (mCodec->mInputMetadataType == kMetadataBufferTypeGrallocSource) { + mCodec->mInputMetadataType = kMetadataBufferTypeANWBuffer; + } ++#endif + } + + if (err == OK) { +diff --git a/media/libstagefright/Android.mk b/media/libstagefright/Android.mk +index 3848502..c06f6a4 100644 +--- a/media/libstagefright/Android.mk ++++ b/media/libstagefright/Android.mk +@@ -124,6 +124,10 @@ LOCAL_SHARED_LIBRARIES += \ + libdl \ + libRScpp \ + ++ifeq ($(TARGET_HAS_LEGACY_CAMERA_HAL1),true) ++LOCAL_CFLAGS += -DCAMCORDER_GRALLOC_SOURCE ++endif ++ + LOCAL_CFLAGS += -Wno-multichar -Werror -Wno-error=deprecated-declarations -Wall + + # enable experiments only in userdebug and eng builds +diff --git a/media/libstagefright/CameraSource.cpp b/media/libstagefright/CameraSource.cpp +index e087249..c9f60ec 100644 +--- a/media/libstagefright/CameraSource.cpp ++++ b/media/libstagefright/CameraSource.cpp +@@ -1117,6 +1117,9 @@ void CameraSource::releaseRecordingFrameHandle(native_handle_t* handle) { + int64_t token = IPCThreadState::self()->clearCallingIdentity(); + mCamera->releaseRecordingFrameHandle(handle); + IPCThreadState::self()->restoreCallingIdentity(token); ++ } else { ++ native_handle_close(handle); ++ native_handle_delete(handle); + } + } + +@@ -1247,6 +1250,10 @@ void CameraSource::processBufferQueueFrame(BufferItem& buffer) { + MetadataBufferType CameraSource::metaDataStoredInVideoBuffers() const { + ALOGV("metaDataStoredInVideoBuffers"); + ++#ifdef CAMCORDER_GRALLOC_SOURCE ++ return kMetadataBufferTypeGrallocSource; ++#endif ++ + // Output buffers will contain metadata if camera sends us buffer in metadata mode or via + // buffer queue. + switch (mVideoBufferMode) { +diff --git a/media/libstagefright/SurfaceMediaSource.cpp b/media/libstagefright/SurfaceMediaSource.cpp +index 15ff569..0e9b4e6 100644 +--- a/media/libstagefright/SurfaceMediaSource.cpp ++++ b/media/libstagefright/SurfaceMediaSource.cpp +@@ -129,7 +129,11 @@ status_t SurfaceMediaSource::setFrameRate(int32_t fps) + + MetadataBufferType SurfaceMediaSource::metaDataStoredInVideoBuffers() const { + ALOGV("isMetaDataStoredInVideoBuffers"); ++#ifdef CAMCORDER_GRALLOC_SOURCE ++ return kMetadataBufferTypeGrallocSource; ++#else + return kMetadataBufferTypeANWBuffer; ++#endif + } + + int32_t SurfaceMediaSource::getFrameRate( ) const { +@@ -250,6 +254,35 @@ sp SurfaceMediaSource::getFormat() + return meta; + } + ++#ifdef CAMCORDER_GRALLOC_SOURCE ++// Pass the data to the MediaBuffer. Pass in only the metadata ++// The metadata passed consists of two parts: ++// 1. First, there is an integer indicating that it is a GRAlloc ++// source (kMetadataBufferTypeGrallocSource) ++// 2. This is followed by the buffer_handle_t that is a handle to the ++// GRalloc buffer. The encoder needs to interpret this GRalloc handle ++// and encode the frames. ++// -------------------------------------------------------------- ++// | kMetadataBufferTypeGrallocSource | sizeof(buffer_handle_t) | ++// -------------------------------------------------------------- ++// Note: Call only when you have the lock ++static void passMetadataBuffer(MediaBuffer **buffer, ++ buffer_handle_t bufferHandle) { ++ *buffer = new MediaBuffer(4 + sizeof(buffer_handle_t)); ++ char *data = (char *)(*buffer)->data(); ++ if (data == NULL) { ++ ALOGE("Cannot allocate memory for metadata buffer!"); ++ return; ++ } ++ OMX_U32 type = kMetadataBufferTypeGrallocSource; ++ memcpy(data, &type, 4); ++ memcpy(data + 4, &bufferHandle, sizeof(buffer_handle_t)); ++ ++ ALOGV("handle = %p, , offset = %zu, length = %zu", ++ bufferHandle, (*buffer)->range_length(), (*buffer)->range_offset()); ++} ++#endif ++ + // Pass the data to the MediaBuffer. Pass in only the metadata + // Note: Call only when you have the lock + void SurfaceMediaSource::passMetadataBuffer_l(MediaBuffer **buffer, +@@ -352,7 +385,11 @@ status_t SurfaceMediaSource::read( + mNumFramesEncoded++; + // Pass the data to the MediaBuffer. Pass in only the metadata + ++#ifdef CAMCORDER_GRALLOC_SOURCE ++ passMetadataBuffer(buffer, mSlots[mCurrentSlot].mGraphicBuffer->handle); ++#else + passMetadataBuffer_l(buffer, mSlots[mCurrentSlot].mGraphicBuffer->getNativeBuffer()); ++#endif + + (*buffer)->setObserver(this); + (*buffer)->add_ref(); +diff --git a/media/libstagefright/foundation/MediaBufferGroup.cpp b/media/libstagefright/foundation/MediaBufferGroup.cpp +index cb78879..055ac4b 100644 +--- a/media/libstagefright/foundation/MediaBufferGroup.cpp ++++ b/media/libstagefright/foundation/MediaBufferGroup.cpp +@@ -188,6 +188,16 @@ status_t MediaBufferGroup::acquire_buffer( + // Never gets here. + } + ++status_t MediaBufferGroup::acquire_buffer( ++ MediaBuffer **out) { ++ return acquire_buffer(out, false, 0); ++} ++ ++status_t MediaBufferGroup::acquire_buffer( ++ MediaBuffer **out, bool nonBlocking) { ++ return acquire_buffer(out, nonBlocking, 0); ++} ++ + void MediaBufferGroup::signalBufferReturned(MediaBuffer *) { + mCondition.signal(); + } +diff --git a/media/libstagefright/omx/Android.mk b/media/libstagefright/omx/Android.mk +index e4fbd81..8fc788f 100644 +--- a/media/libstagefright/omx/Android.mk ++++ b/media/libstagefright/omx/Android.mk +@@ -31,6 +31,12 @@ LOCAL_SHARED_LIBRARIES := \ + libstagefright_foundation \ + libdl + ++ifneq ($(TARGET_USES_MEDIA_EXTENSIONS),true) ++ifeq ($(TARGET_HAS_LEGACY_CAMERA_HAL1),true) ++LOCAL_CFLAGS += -DCAMCORDER_GRALLOC_SOURCE ++endif ++endif ++ + LOCAL_MODULE:= libstagefright_omx + LOCAL_CFLAGS += -Werror -Wall + LOCAL_CLANG := true +diff --git a/media/libstagefright/omx/OMXMaster.cpp b/media/libstagefright/omx/OMXMaster.cpp +index 6132a2c..7f0d270 100644 +--- a/media/libstagefright/omx/OMXMaster.cpp ++++ b/media/libstagefright/omx/OMXMaster.cpp +@@ -69,6 +69,7 @@ OMXMaster::~OMXMaster() { + + void OMXMaster::addVendorPlugin() { + addPlugin("libstagefrighthw.so"); ++ addPlugin("libsomxcore.so"); + } + + void OMXMaster::addPlugin(const char *libname) { +diff --git a/media/libstagefright/omx/OMXNodeInstance.cpp b/media/libstagefright/omx/OMXNodeInstance.cpp +index 395dad8..c570603 100644 +--- a/media/libstagefright/omx/OMXNodeInstance.cpp ++++ b/media/libstagefright/omx/OMXNodeInstance.cpp +@@ -1286,7 +1286,11 @@ status_t OMXNodeInstance::allocateBufferWithBackup( + } + + // metadata buffers are not connected cross process; only copy if not meta ++#ifdef CAMCORDER_GRALLOC_SOURCE ++ bool copy = true; ++#else + bool copy = mMetadataType[portIndex] == kMetadataBufferTypeInvalid; ++#endif + + BufferMeta *buffer_meta = new BufferMeta( + params, portIndex, +@@ -1404,10 +1408,30 @@ status_t OMXNodeInstance::emptyBuffer( + BufferMeta *buffer_meta = + static_cast(header->pAppPrivate); + ++#ifndef CAMCORDER_GRALLOC_SOURCE + // set up proper filled length if component is configured for gralloc metadata mode + // ignore rangeOffset in this case (as client may be assuming ANW meta buffers). + if (mMetadataType[kPortIndexInput] == kMetadataBufferTypeGrallocSource) { + header->nFilledLen = rangeLength ? sizeof(VideoGrallocMetadata) : 0; ++#else ++ sp backup = buffer_meta->getBuffer(header, true /* backup */, false /* limit */); ++ sp codec = buffer_meta->getBuffer(header, false /* backup */, false /* limit */); ++ ++ // convert incoming ANW meta buffers if component is configured for gralloc metadata mode ++ // ignore rangeOffset in this case ++ if (mMetadataType[kPortIndexInput] == kMetadataBufferTypeGrallocSource ++ && backup->capacity() >= sizeof(VideoNativeMetadata) ++ && codec->capacity() >= sizeof(VideoGrallocMetadata) ++ && ((VideoNativeMetadata *)backup->base())->eType ++ == kMetadataBufferTypeANWBuffer) { ++ VideoNativeMetadata &backupMeta = *(VideoNativeMetadata *)backup->base(); ++ VideoGrallocMetadata &codecMeta = *(VideoGrallocMetadata *)codec->base(); ++ CLOG_BUFFER(emptyBuffer, "converting ANWB %p to handle %p", ++ backupMeta.pBuffer, backupMeta.pBuffer->handle); ++ codecMeta.pHandle = backupMeta.pBuffer != NULL ? backupMeta.pBuffer->handle : NULL; ++ codecMeta.eType = kMetadataBufferTypeGrallocSource; ++ header->nFilledLen = rangeLength ? sizeof(codecMeta) : 0; ++#endif + header->nOffset = 0; + } else { + // rangeLength and rangeOffset must be a subset of the allocated data in the buffer. +diff --git a/media/mediaserver/Android.mk b/media/mediaserver/Android.mk +index 1738df8..c2b9c1f 100644 +--- a/media/mediaserver/Android.mk ++++ b/media/mediaserver/Android.mk +@@ -42,4 +42,8 @@ LOCAL_INIT_RC := mediaserver.rc + + LOCAL_CFLAGS := -Werror -Wall + ++ifeq ($(TARGET_HAS_LEGACY_CAMERA_HAL1),true) ++ LOCAL_CFLAGS += -DNO_CAMERA_SERVER ++endif ++ + include $(BUILD_EXECUTABLE) +diff --git a/media/mediaserver/main_mediaserver.cpp b/media/mediaserver/main_mediaserver.cpp +index ecddc48..0abe6ac 100644 +--- a/media/mediaserver/main_mediaserver.cpp ++++ b/media/mediaserver/main_mediaserver.cpp +@@ -25,6 +25,9 @@ + #include "RegisterExtensions.h" + + // from LOCAL_C_INCLUDES ++#ifdef NO_CAMERA_SERVER ++#include "CameraService.h" ++#endif + #include "IcuUtils.h" + #include "MediaPlayerService.h" + #include "ResourceManagerService.h" +@@ -41,6 +44,9 @@ int main(int argc __unused, char **argv __unused) + InitializeIcuOrDie(); + MediaPlayerService::instantiate(); + ResourceManagerService::instantiate(); ++#ifdef NO_CAMERA_SERVER ++ CameraService::instantiate(); ++#endif + registerExtensions(); + ProcessState::self()->startThreadPool(); + IPCThreadState::self()->joinThreadPool(); +diff --git a/services/camera/libcameraservice/Android.mk b/services/camera/libcameraservice/Android.mk +index 8d7f71c..d98ad47 100644 +--- a/services/camera/libcameraservice/Android.mk ++++ b/services/camera/libcameraservice/Android.mk +@@ -80,6 +80,10 @@ LOCAL_EXPORT_C_INCLUDE_DIRS := \ + + LOCAL_CFLAGS += -Wall -Wextra -Werror + ++ifeq ($(TARGET_HAS_LEGACY_CAMERA_HAL1),true) ++ LOCAL_CFLAGS += -DNO_CAMERA_SERVER ++endif ++ + LOCAL_MODULE:= libcameraservice + + include $(BUILD_SHARED_LIBRARY) +diff --git a/services/camera/libcameraservice/CameraService.cpp b/services/camera/libcameraservice/CameraService.cpp +index d0df6d1..a0c74d8 100644 +--- a/services/camera/libcameraservice/CameraService.cpp ++++ b/services/camera/libcameraservice/CameraService.cpp +@@ -831,7 +831,11 @@ String8 CameraService::toString(std::set intSet) { + Status CameraService::initializeShimMetadata(int cameraId) { + int uid = getCallingUid(); + ++#ifdef NO_CAMERA_SERVER ++ String16 internalPackageName("media"); ++#else + String16 internalPackageName("cameraserver"); ++#endif + String8 id = String8::format("%d", cameraId); + Status ret = Status::ok(); + sp tmp = nullptr; +@@ -912,7 +916,9 @@ Status CameraService::getLegacyParametersLazy(int cameraId, + static bool isTrustedCallingUid(uid_t uid) { + switch (uid) { + case AID_MEDIA: // mediaserver +- case AID_CAMERASERVER: // cameraserver ++#ifndef NO_CAMERA_SERVER ++ case AID_CAMERASERVER: // cameraserver ++#endif + case AID_RADIO: // telephony + return true; + default: +diff --git a/services/camera/libcameraservice/api1/CameraClient.cpp b/services/camera/libcameraservice/api1/CameraClient.cpp +index 266fb03..3c2b98a 100644 +--- a/services/camera/libcameraservice/api1/CameraClient.cpp ++++ b/services/camera/libcameraservice/api1/CameraClient.cpp +@@ -520,6 +520,9 @@ void CameraClient::releaseRecordingFrameHandle(native_handle_t *handle) { + metadata->pHandle = handle; + + mHardware->releaseRecordingFrame(dataPtr); ++ ++ native_handle_close(handle); ++ native_handle_delete(handle); + } + + status_t CameraClient::setVideoBufferMode(int32_t videoBufferMode) { diff --git a/frameworks_base.patch b/frameworks_base.patch new file mode 100644 index 0000000..05d6161 --- /dev/null +++ b/frameworks_base.patch @@ -0,0 +1,13 @@ +diff --git a/libs/hwui/Android.mk b/libs/hwui/Android.mk +index 366ef71..3ecd045 100644 +--- a/libs/hwui/Android.mk ++++ b/libs/hwui/Android.mk +@@ -141,7 +141,7 @@ endif + + ifdef HWUI_COMPILE_FOR_PERF + # TODO: Non-arm? +- hwui_cflags += -fno-omit-frame-pointer -marm -mapcs ++ hwui_cflags += -fno-omit-frame-pointer -marm + endif + + # This has to be lazy-resolved because it depends on the LOCAL_MODULE_CLASS diff --git a/frameworks_native.patch b/frameworks_native.patch new file mode 100644 index 0000000..d289649 --- /dev/null +++ b/frameworks_native.patch @@ -0,0 +1,24 @@ +diff --git a/services/surfaceflinger/SurfaceFlinger_hwc1.cpp b/services/surfaceflinger/SurfaceFlinger_hwc1.cpp +index 650d6b4..2a5e07f 100644 +--- a/services/surfaceflinger/SurfaceFlinger_hwc1.cpp ++++ b/services/surfaceflinger/SurfaceFlinger_hwc1.cpp +@@ -466,13 +466,14 @@ void SurfaceFlinger::init() { + mEventQueue.setEventThread(mSFEventThread); + + // set SFEventThread to SCHED_FIFO to minimize jitter +- struct sched_param param = {0}; +- param.sched_priority = 1; +- if (sched_setscheduler(mSFEventThread->getTid(), SCHED_FIFO, ¶m) != 0) { +- ALOGE("Couldn't set SCHED_FIFO for SFEventThread"); ++ if (mSFEventThread != NULL) { ++ struct sched_param param = {0}; ++ param.sched_priority = 1; ++ if (sched_setscheduler(mSFEventThread->getTid(), SCHED_FIFO, ¶m) != 0) { ++ ALOGE("Couldn't set SCHED_FIFO for SFEventThread"); ++ } + } + +- + // Initialize the H/W composer object. There may or may not be an + // actual hardware composer underneath. + mHwc = new HWComposer(this, diff --git a/packages_apps_music.patch b/packages_apps_music.patch new file mode 100644 index 0000000..4f8a363 --- /dev/null +++ b/packages_apps_music.patch @@ -0,0 +1,13 @@ +diff --git a/src/com/android/music/MediaPlaybackService.java b/src/com/android/music/MediaPlaybackService.java +index 25d60c7..be8142f 100644 +--- a/src/com/android/music/MediaPlaybackService.java ++++ b/src/com/android/music/MediaPlaybackService.java +@@ -335,7 +335,7 @@ public class MediaPlaybackService extends Service { + | RemoteControlClient.FLAG_KEY_MEDIA_STOP; + mRemoteControlClient.setTransportControlFlags(flags); + +- mPreferences = getSharedPreferences("Music", MODE_WORLD_READABLE | MODE_WORLD_WRITEABLE); ++ mPreferences = getSharedPreferences("Music", MODE_PRIVATE); + mCardId = MusicUtils.getCardId(this); + + registerExternalStorageListener(); diff --git a/system_core.patch b/system_core.patch new file mode 100644 index 0000000..356e39a --- /dev/null +++ b/system_core.patch @@ -0,0 +1,197 @@ +diff --git a/include/system/camera.h b/include/system/camera.h +index 5d0873a..e4c0a47 100644 +--- a/include/system/camera.h ++++ b/include/system/camera.h +@@ -88,9 +88,20 @@ enum { + // Notify on autofocus start and stop. This is useful in continuous + // autofocus - FOCUS_MODE_CONTINUOUS_VIDEO and FOCUS_MODE_CONTINUOUS_PICTURE. + CAMERA_MSG_FOCUS_MOVE = 0x0800, // notifyCallback ++ CAMERA_MSG_VENDOR_START = 0x1000, ++ CAMERA_MSG_STATS_DATA = CAMERA_MSG_VENDOR_START, ++ CAMERA_MSG_META_DATA = 0x2000, ++ CAMERA_MSG_VENDOR_END = 0x8000, + CAMERA_MSG_ALL_MSGS = 0xFFFF + }; + ++/** meta data type in CameraMetaDataCallback */ ++enum { ++ CAMERA_META_DATA_ASD = 0x001, //ASD data ++ CAMERA_META_DATA_FD = 0x002, //FD/FP data ++ CAMERA_META_DATA_HDR = 0x003, //Auto HDR data ++}; ++ + /** cmdType in sendCommand functions */ + enum { + CAMERA_CMD_START_SMOOTH_ZOOM = 1, +@@ -189,7 +200,41 @@ enum { + * IMPLEMENTATION_DEFINED, then HALv3 devices will use gralloc usage flags + * of SW_READ_OFTEN. + */ +- CAMERA_CMD_SET_VIDEO_FORMAT = 11 ++#ifndef CAMERA_VENDOR_L_COMPAT ++ CAMERA_CMD_SET_VIDEO_FORMAT = 11, ++ ++ CAMERA_CMD_VENDOR_START = 20, ++ /** ++ * Commands to enable/disable preview histogram ++ * ++ * Based on user's input to enable/disable histogram from the camera ++ * UI, send the appropriate command to the HAL to turn on/off the histogram ++ * stats and start sending the data to the application. ++ */ ++ CAMERA_CMD_HISTOGRAM_ON = CAMERA_CMD_VENDOR_START, ++ CAMERA_CMD_HISTOGRAM_OFF = CAMERA_CMD_VENDOR_START + 1, ++ CAMERA_CMD_HISTOGRAM_SEND_DATA = CAMERA_CMD_VENDOR_START + 2, ++ CAMERA_CMD_LONGSHOT_ON = CAMERA_CMD_VENDOR_START + 3, ++ CAMERA_CMD_LONGSHOT_OFF = CAMERA_CMD_VENDOR_START + 4, ++ CAMERA_CMD_STOP_LONGSHOT = CAMERA_CMD_VENDOR_START + 5, ++ CAMERA_CMD_METADATA_ON = CAMERA_CMD_VENDOR_START + 6, ++ CAMERA_CMD_METADATA_OFF = CAMERA_CMD_VENDOR_START + 7, ++ CAMERA_CMD_VENDOR_END = 200, ++#else ++ ++ /** ++ * Values used by older HALs, provided as an option for compatibility ++ */ ++ CAMERA_CMD_HISTOGRAM_ON = 11, ++ CAMERA_CMD_HISTOGRAM_OFF = 12, ++ CAMERA_CMD_HISTOGRAM_SEND_DATA = 13, ++ CAMERA_CMD_LONGSHOT_ON = 14, ++ CAMERA_CMD_LONGSHOT_OFF = 15, ++ CAMERA_CMD_STOP_LONGSHOT = 16, ++ CAMERA_CMD_METADATA_ON = 100, ++ CAMERA_CMD_METADATA_OFF = 101, ++ CAMERA_CMD_SET_VIDEO_FORMAT = 102, ++#endif + }; + + /** camera fatal errors */ +@@ -275,10 +320,32 @@ typedef struct camera_face { + * -2000, -2000 if this is not supported. + */ + int32_t mouth[2]; ++ int32_t smile_degree; ++ int32_t smile_score; ++ int32_t blink_detected; ++ int32_t face_recognised; ++ int32_t gaze_angle; ++ int32_t updown_dir; ++ int32_t leftright_dir; ++ int32_t roll_dir; ++ int32_t left_right_gaze; ++ int32_t top_bottom_gaze; ++ int32_t leye_blink; ++ int32_t reye_blink; + + } camera_face_t; + + /** ++ * The information of a data type received in a camera frame. ++ */ ++typedef enum { ++ /** Data buffer */ ++ CAMERA_FRAME_DATA_BUF = 0x000, ++ /** File descriptor */ ++ CAMERA_FRAME_DATA_FD = 0x100 ++} camera_frame_data_type_t; ++ ++/** + * The metadata of the frame data. + */ + typedef struct camera_frame_metadata { +diff --git a/init/Android.mk b/init/Android.mk +index 67541b8..ff343e9 100644 +--- a/init/Android.mk ++++ b/init/Android.mk +@@ -10,7 +10,7 @@ else + init_options += -DALLOW_LOCAL_PROP_OVERRIDE=0 -DALLOW_PERMISSIVE_SELINUX=0 + endif + +-init_options += -DLOG_UEVENTS=0 ++init_options += -DLOG_UEVENTS=0 -D__BRILLO__ + + init_cflags += \ + $(init_options) \ +diff --git a/init/init.cpp b/init/init.cpp +index 84da2b9..dc3be38 100644 +--- a/init/init.cpp ++++ b/init/init.cpp +@@ -296,55 +296,6 @@ static bool __attribute__((unused)) set_mmap_rnd_bits_min(int start, int min, bo + return (start >= min); + } + +-/* +- * Set /proc/sys/vm/mmap_rnd_bits and potentially +- * /proc/sys/vm/mmap_rnd_compat_bits to the maximum supported values. +- * Returns -1 if unable to set these to an acceptable value. Apply +- * upstream patch-sets https://lkml.org/lkml/2015/12/21/337 and +- * https://lkml.org/lkml/2016/2/4/831 to enable this. +- */ +-static int set_mmap_rnd_bits_action(const std::vector& args) +-{ +- int ret = -1; +- +- /* values are arch-dependent */ +-#if defined(__aarch64__) +- /* arm64 supports 18 - 33 bits depending on pagesize and VA_SIZE */ +- if (set_mmap_rnd_bits_min(33, 24, false) +- && set_mmap_rnd_bits_min(16, 16, true)) { +- ret = 0; +- } +-#elif defined(__x86_64__) +- /* x86_64 supports 28 - 32 bits */ +- if (set_mmap_rnd_bits_min(32, 32, false) +- && set_mmap_rnd_bits_min(16, 16, true)) { +- ret = 0; +- } +-#elif defined(__arm__) || defined(__i386__) +- /* check to see if we're running on 64-bit kernel */ +- bool h64 = !access(MMAP_RND_COMPAT_PATH, F_OK); +- /* supported 32-bit architecture must have 16 bits set */ +- if (set_mmap_rnd_bits_min(16, 16, h64)) { +- ret = 0; +- } +-#elif defined(__mips__) || defined(__mips64__) +- // TODO: add mips support b/27788820 +- ret = 0; +-#else +- ERROR("Unknown architecture\n"); +-#endif +- +-#ifdef __BRILLO__ +- // TODO: b/27794137 +- ret = 0; +-#endif +- if (ret == -1) { +- ERROR("Unable to set adequate mmap entropy value!\n"); +- security_failure(); +- } +- return ret; +-} +- + static int keychord_init_action(const std::vector& args) + { + keychord_init(); +@@ -695,7 +646,7 @@ int main(int argc, char** argv) { + am.QueueBuiltinAction(wait_for_coldboot_done_action, "wait_for_coldboot_done"); + // ... so that we can start queuing up actions that require stuff from /dev. + am.QueueBuiltinAction(mix_hwrng_into_linux_rng_action, "mix_hwrng_into_linux_rng"); +- am.QueueBuiltinAction(set_mmap_rnd_bits_action, "set_mmap_rnd_bits"); ++ // am.QueueBuiltinAction(set_mmap_rnd_bits_action, "set_mmap_rnd_bits"); + am.QueueBuiltinAction(keychord_init_action, "keychord_init"); + am.QueueBuiltinAction(console_init_action, "console_init"); + +diff --git a/rootdir/init.rc b/rootdir/init.rc +index 56379db..3b0fd4d 100644 +--- a/rootdir/init.rc ++++ b/rootdir/init.rc +@@ -654,6 +654,6 @@ on property:ro.debuggable=1 + chmod 0773 /data/misc/trace + start console + +-service flash_recovery /system/bin/install-recovery.sh +- class main +- oneshot ++#service flash_recovery /system/bin/install-recovery.sh ++# class main ++# oneshot diff --git a/system_sepolicy.patch b/system_sepolicy.patch new file mode 100644 index 0000000..3460484 --- /dev/null +++ b/system_sepolicy.patch @@ -0,0 +1,769 @@ +diff --git a/app.te b/app.te +index e9dd7b3..ef2bd9d 100644 +--- a/app.te ++++ b/app.te +@@ -274,7 +274,7 @@ allow appdomain cache_file:dir getattr; + + # Superuser capabilities. + # bluetooth requires net_admin and wake_alarm. +-neverallow { appdomain -bluetooth } self:capability *; ++neverallow { appdomain -bluetooth -shell } self:capability *; + neverallow { appdomain -bluetooth } self:capability2 *; + + # Block device access. +diff --git a/domain.te b/domain.te +index 45569de..21c9df2 100644 +--- a/domain.te ++++ b/domain.te +@@ -159,6 +159,7 @@ neverallow { + -dumpstate + -system_server + userdebug_or_eng(`-perfprofd') ++ userdebug_or_eng(`-procrank') + } self:capability sys_ptrace; + + # Limit device node creation to these whitelisted domains. +@@ -267,6 +268,7 @@ neverallow { domain -init -ueventd } device:chr_file { open read write }; + # this capability, including device-specific domains. + neverallow { domain -kernel -init -recovery -vold -zygote -update_engine -otapreopt_chroot } { fs_type -sdcard_type }:filesystem { mount remount relabelfrom relabelto }; + ++ + # + # Assert that, to the extent possible, we're not loading executable content from + # outside the rootfs or /system partition except for a few whitelisted domains. +@@ -292,7 +294,9 @@ neverallow domain { cache_file cache_backup_file cache_private_backup_file cache + # Protect most domains from executing arbitrary content from /data. + neverallow { + domain +- -appdomain ++ -untrusted_app ++ -priv_app ++ -shell + } { + data_file_type + -dalvikcache_data_file +@@ -379,6 +383,8 @@ neverallow { + -cppreopts + -dex2oat + -otapreopt_slot ++ -shell ++ -system_app + } dalvikcache_data_file:file no_w_file_perms; + + neverallow { +@@ -390,6 +396,7 @@ neverallow { + -dex2oat + -zygote + -otapreopt_slot ++ -shell + } dalvikcache_data_file:dir no_w_dir_perms; + + # Only system_server should be able to send commands via the zygote socket +@@ -428,13 +435,13 @@ neverallow { domain userdebug_or_eng(`-dumpstate -shell -su') } su_exec:file no_ + # The only exceptions are for NDK text relocations associated with + # https://code.google.com/p/android/issues/detail?id=23203 + # which, long term, need to go away. +-neverallow * { +- file_type +- -system_data_file +- -apk_data_file +- -app_data_file +- -asec_public_file +-}:file execmod; ++#neverallow * { ++# file_type ++# -system_data_file ++# -apk_data_file ++# -app_data_file ++# -asec_public_file ++#}:file execmod; + + # Do not allow making the stack or heap executable. + # We would also like to minimize execmem but it seems to be +@@ -443,7 +450,7 @@ neverallow * self:process { execstack execheap }; + + # prohibit non-zygote spawned processes from using shared libraries + # with text relocations. b/20013628 . +-neverallow { domain -appdomain } file_type:file execmod; ++#neverallow { domain -appdomain } file_type:file execmod; + + neverallow { domain -init } proc:{ file dir } mounton; + +@@ -570,7 +577,7 @@ neverallow * domain:file { execute execute_no_trans entrypoint }; + # Instead, if access to part of debugfs is desired, it should have a + # more specific label. + # TODO: fix system_server and dumpstate +-neverallow { domain -init -system_server -dumpstate } debugfs:file no_rw_file_perms; ++#neverallow { domain -init -system_server -dumpstate } debugfs:file no_rw_file_perms; + + neverallow { + domain +diff --git a/domain.te.orig b/domain.te.orig +new file mode 100644 +index 0000000..ae012ea +--- /dev/null ++++ b/domain.te.orig +@@ -0,0 +1,615 @@ ++# Rules for all domains. ++ ++# Allow reaping by init. ++allow domain init:process sigchld; ++ ++# Intra-domain accesses. ++allow domain self:process { ++ fork ++ sigchld ++ sigkill ++ sigstop ++ signull ++ signal ++ getsched ++ setsched ++ getsession ++ getpgid ++ setpgid ++ getcap ++ setcap ++ getattr ++ setrlimit ++}; ++allow domain self:fd use; ++allow domain proc:dir r_dir_perms; ++allow domain proc_net:dir search; ++r_dir_file(domain, self) ++allow domain self:{ fifo_file file } rw_file_perms; ++allow domain self:unix_dgram_socket { create_socket_perms sendto }; ++allow domain self:unix_stream_socket { create_stream_socket_perms connectto }; ++allowxperm domain domain:{ unix_dgram_socket unix_stream_socket } ioctl unpriv_unix_sock_ioctls; ++ ++# Inherit or receive open files from others. ++allow domain init:fd use; ++ ++userdebug_or_eng(` ++ # Same as adbd rules above, except allow su to do the same thing ++ allow domain su:unix_stream_socket connectto; ++ allow domain su:fd use; ++ allow domain su:unix_stream_socket { getattr getopt read write shutdown }; ++ ++ allow { domain -init } su:binder { call transfer }; ++ allow { domain -init } su:fd use; ++ ++ # Running something like "pm dump com.android.bluetooth" requires ++ # fifo writes ++ allow domain su:fifo_file { write getattr }; ++ ++ # allow "gdbserver --attach" to work for su. ++ allow domain su:process sigchld; ++ ++ # Allow writing coredumps to /cores/* ++ allow domain coredump_file:file create_file_perms; ++ allow domain coredump_file:dir ra_dir_perms; ++') ++ ++### ++### Talk to debuggerd. ++### ++allow domain debuggerd:process sigchld; ++allow domain debuggerd:unix_stream_socket connectto; ++ ++# Root fs. ++allow domain rootfs:dir search; ++allow domain rootfs:lnk_file read; ++ ++# Device accesses. ++allow domain device:dir search; ++allow domain dev_type:lnk_file r_file_perms; ++allow domain devpts:dir search; ++allow domain socket_device:dir r_dir_perms; ++allow domain owntty_device:chr_file rw_file_perms; ++allow domain null_device:chr_file rw_file_perms; ++allow domain zero_device:chr_file rw_file_perms; ++allow domain ashmem_device:chr_file rw_file_perms; ++allow domain binder_device:chr_file rw_file_perms; ++allow domain ptmx_device:chr_file rw_file_perms; ++allow domain alarm_device:chr_file r_file_perms; ++allow domain urandom_device:chr_file rw_file_perms; ++allow domain random_device:chr_file rw_file_perms; ++allow domain properties_device:dir r_dir_perms; ++allow domain properties_serial:file r_file_perms; ++ ++# For now, everyone can access core property files ++# Device specific properties are not granted by default ++get_prop(domain, core_property_type) ++# Let everyone read log properties, so that liblog can avoid sending unloggable ++# messages to logd. ++get_prop(domain, log_property_type) ++dontaudit domain property_type:file audit_access; ++allow domain property_contexts:file r_file_perms; ++ ++allow domain init:key search; ++allow domain vold:key search; ++ ++# logd access ++write_logd(domain) ++ ++# System file accesses. ++allow domain system_file:dir { search getattr }; ++allow domain system_file:file { execute read open getattr }; ++allow domain system_file:lnk_file read; ++ ++# read any sysfs symlinks ++allow domain sysfs:lnk_file read; ++ ++# libc references /data/misc/zoneinfo for timezone related information ++r_dir_file(domain, zoneinfo_data_file) ++ ++# Lots of processes access current CPU information ++r_dir_file(domain, sysfs_devices_system_cpu) ++ ++r_dir_file(domain, sysfs_usb); ++ ++# files under /data. ++allow domain system_data_file:dir { search getattr }; ++allow domain system_data_file:lnk_file read; ++ ++# required by the dynamic linker ++allow domain proc:lnk_file { getattr read }; ++ ++# /proc/cpuinfo ++allow domain proc_cpuinfo:file r_file_perms; ++ ++# toybox loads libselinux which stats /sys/fs/selinux/ ++allow domain selinuxfs:dir search; ++allow domain selinuxfs:file getattr; ++allow domain sysfs:dir search; ++allow domain selinuxfs:filesystem getattr; ++ ++# For /acct/uid/*/tasks. ++allow domain cgroup:dir { search write }; ++allow domain cgroup:file w_file_perms; ++ ++# Almost all processes log tracing information to ++# /sys/kernel/debug/tracing/trace_marker ++# The reason behind this is documented in b/6513400 ++allow domain debugfs:dir search; ++allow domain debugfs_tracing:dir search; ++allow domain debugfs_trace_marker:file w_file_perms; ++ ++# Filesystem access. ++allow domain fs_type:filesystem getattr; ++allow domain fs_type:dir getattr; ++ ++### ++### neverallow rules ++### ++ ++# Do not allow any domain other than init or recovery to create unlabeled files. ++neverallow { domain -init -recovery } unlabeled:dir_file_class_set create; ++ ++# Limit ability to ptrace or read sensitive /proc/pid files of processes ++# with other UIDs to these whitelisted domains. ++neverallow { ++ domain ++ -debuggerd ++ -vold ++ -dumpstate ++ -system_server ++ userdebug_or_eng(`-perfprofd') ++ userdebug_or_eng(`-procrank') ++} self:capability sys_ptrace; ++ ++# Limit device node creation to these whitelisted domains. ++neverallow { ++ domain ++ -kernel ++ -init ++ -ueventd ++ -vold ++} self:capability mknod; ++ ++# Limit raw I/O to these whitelisted domains. Do not apply to debug builds. ++neverallow { ++ domain ++ userdebug_or_eng(`-domain') ++ -kernel ++ -init ++ -recovery ++ -ueventd ++ -healthd ++ -uncrypt ++ -tee ++} self:capability sys_rawio; ++ ++# No process can map low memory (< CONFIG_LSM_MMAP_MIN_ADDR). ++neverallow * self:memprotect mmap_zero; ++ ++# No domain needs mac_override as it is unused by SELinux. ++neverallow * self:capability2 mac_override; ++ ++# Only recovery needs mac_admin to set contexts not defined in current policy. ++neverallow { domain -recovery } self:capability2 mac_admin; ++ ++# Only init should be able to load SELinux policies. ++# The first load technically occurs while still in the kernel domain, ++# but this does not trigger a denial since there is no policy yet. ++# Policy reload requires allowing this to the init domain. ++neverallow { domain -init } kernel:security load_policy; ++ ++# Only init and the system_server can set selinux.reload_policy 1 ++# to trigger a policy reload. ++neverallow { domain -init -system_server } security_prop:property_service set; ++ ++# Only init and system_server can write to /data/security, where runtime ++# policy updates live. ++# Only init can relabel /data/security (for init.rc restorecon_recursive /data). ++neverallow { domain -init } security_file:{ dir file lnk_file } { relabelfrom relabelto }; ++# Only init and system_server can create/setattr directories with this type. ++# init is for init.rc mkdir /data/security. ++# system_server is for creating subdirectories under /data/security. ++neverallow { domain -init -system_server } security_file:dir { create setattr }; ++# Only system_server can create subdirectories and files under /data/security. ++neverallow { domain -system_server } security_file:dir { rename write add_name remove_name rmdir }; ++neverallow { domain -system_server } security_file:file { create setattr write append unlink link rename }; ++neverallow { domain -system_server } security_file:lnk_file { create setattr unlink rename }; ++ ++# Only init prior to switching context should be able to set enforcing mode. ++# init starts in kernel domain and switches to init domain via setcon in ++# the init.rc, so the setenforce occurs while still in kernel. After ++# switching domains, there is never any need to setenforce again by init. ++neverallow * kernel:security setenforce; ++neverallow { domain -kernel } kernel:security setcheckreqprot; ++ ++# No booleans in AOSP policy, so no need to ever set them. ++neverallow * kernel:security setbool; ++ ++# Adjusting the AVC cache threshold. ++# Not presently allowed to anything in policy, but possibly something ++# that could be set from init.rc. ++neverallow { domain -init } kernel:security setsecparam; ++ ++# Only init, ueventd and system_server should be able to access HW RNG ++neverallow { domain -init -system_server -ueventd } hw_random_device:chr_file *; ++ ++# Ensure that all entrypoint executables are in exec_type or postinstall_file. ++neverallow * { file_type -exec_type -postinstall_file }:file entrypoint; ++ ++# Ensure that nothing in userspace can access /dev/mem or /dev/kmem ++neverallow { domain -kernel -ueventd -init } kmem_device:chr_file *; ++neverallow * kmem_device:chr_file ~{ create relabelto unlink setattr }; ++ ++# Only init should be able to configure kernel usermodehelpers or ++# security-sensitive proc settings. ++neverallow { domain -init } usermodehelper:file { append write }; ++neverallow { domain -init } proc_security:file { append write }; ++ ++# No domain should be allowed to ptrace init. ++neverallow * init:process ptrace; ++ ++# Init can't do anything with binder calls. If this neverallow rule is being ++# triggered, it's probably due to a service with no SELinux domain. ++neverallow * init:binder *; ++ ++# Don't allow raw read/write/open access to block_device ++# Rather force a relabel to a more specific type ++neverallow { domain -kernel -init -recovery -uncrypt } block_device:blk_file { open read write }; ++ ++# Don't allow raw read/write/open access to generic devices. ++# Rather force a relabel to a more specific type. ++# init is exempt from this as there are character devices that only it uses. ++# ueventd is exempt from this, as it is managing these devices. ++neverallow { domain -init -ueventd } device:chr_file { open read write }; ++ ++# Limit what domains can mount filesystems or change their mount flags. ++# sdcard_type / vfat is exempt as a larger set of domains need ++# this capability, including device-specific domains. ++neverallow { domain -kernel -init -recovery -vold -zygote -update_engine -otapreopt_chroot } { fs_type -sdcard_type }:filesystem { mount remount relabelfrom relabelto }; ++ ++# ++# Assert that, to the extent possible, we're not loading executable content from ++# outside the rootfs or /system partition except for a few whitelisted domains. ++# ++neverallow { ++ domain ++ -appdomain ++ -autoplay_app ++ -dumpstate ++ -shell ++ userdebug_or_eng(`-su') ++ -system_server ++ -zygote ++} { file_type -system_file -exec_type -postinstall_file }:file execute; ++neverallow { ++ domain ++ -appdomain # for oemfs ++ -recovery # for /tmp/update_binary in tmpfs ++} { fs_type -rootfs }:file execute; ++# Files from cache should never be executed ++neverallow domain { cache_file cache_backup_file cache_private_backup_file cache_recovery_file }:file execute; ++ ++# Protect most domains from executing arbitrary content from /data. ++neverallow { ++ domain ++ -appdomain ++} { ++ data_file_type ++ -dalvikcache_data_file ++ -system_data_file # shared libs in apks ++ -apk_data_file ++}:file no_x_file_perms; ++ ++neverallow { domain userdebug_or_eng(`-shell') } nativetest_data_file:file no_x_file_perms; ++ ++# Only the init property service should write to /data/property and /dev/__properties__ ++neverallow { domain -init } property_data_file:dir no_w_dir_perms; ++neverallow { domain -init } property_data_file:file { no_w_file_perms no_x_file_perms }; ++neverallow { domain -init } property_type:file { no_w_file_perms no_x_file_perms }; ++neverallow { domain -init } properties_device:file { no_w_file_perms no_x_file_perms }; ++neverallow { domain -init } properties_serial:file { no_w_file_perms no_x_file_perms }; ++ ++# Only recovery should be doing writes to /system ++neverallow { domain -recovery } { system_file exec_type }:dir_file_class_set ++ { create write setattr relabelfrom append unlink link rename }; ++neverallow { domain -recovery -kernel } { system_file exec_type }:dir_file_class_set relabelto; ++ ++# Don't allow mounting on top of /system files or directories ++neverallow * exec_type:dir_file_class_set mounton; ++neverallow { domain -init } system_file:dir_file_class_set mounton; ++ ++# Nothing should be writing to files in the rootfs. ++neverallow * rootfs:file { create write setattr relabelto append unlink link rename }; ++ ++# Restrict context mounts to specific types marked with ++# the contextmount_type attribute. ++neverallow * {fs_type -contextmount_type}:filesystem relabelto; ++ ++# Ensure that context mount types are not writable, to ensure that ++# the write to /system restriction above is not bypassed via context= ++# mount to another type. ++neverallow { domain -recovery } contextmount_type:dir_file_class_set ++ { create write setattr relabelfrom relabelto append unlink link rename }; ++ ++# Do not allow service_manager add for default_android_service. ++# Instead domains should use a more specific type such as ++# system_app_service rather than the generic type. ++# New service_types are defined in service.te and new mappings ++# from service name to service_type are defined in service_contexts. ++neverallow * default_android_service:service_manager add; ++ ++# Require that domains explicitly label unknown properties, and do not allow ++# anyone but init to modify unknown properties. ++neverallow { domain -init } default_prop:property_service set; ++neverallow { domain -init } mmc_prop:property_service set; ++ ++neverallow { domain -init -recovery -system_server } frp_block_device:blk_file rw_file_perms; ++ ++# No domain other than recovery and update_engine can write to system partition(s). ++neverallow { domain -recovery -update_engine } system_block_device:blk_file write; ++ ++# No domains other than install_recovery or recovery can write to recovery. ++neverallow { domain -install_recovery -recovery } recovery_block_device:blk_file write; ++ ++# No domains other than a select few can access the misc_block_device. This ++# block device is reserved for OTA use. ++# Do not assert this rule on userdebug/eng builds, due to some devices using ++# this partition for testing purposes. ++neverallow { ++ domain ++ userdebug_or_eng(`-domain') # exclude debuggable builds ++ -init ++ -uncrypt ++ -update_engine ++ -vold ++ -recovery ++ -ueventd ++} misc_block_device:blk_file { append link relabelfrom rename write open read ioctl lock }; ++ ++# Only servicemanager should be able to register with binder as the context manager ++neverallow { domain -servicemanager } *:binder set_context_mgr; ++ ++# Only authorized processes should be writing to files in /data/dalvik-cache ++neverallow { ++ domain ++ -init # TODO: limit init to relabelfrom for files ++ -zygote ++ -installd ++ -postinstall_dexopt ++ -cppreopts ++ -dex2oat ++<<<<<<< HEAD ++ -shell ++ -system_app ++======= ++ -otapreopt_slot ++>>>>>>> android-7.1.0_r4 ++} dalvikcache_data_file:file no_w_file_perms; ++ ++neverallow { ++ domain ++ -init ++ -installd ++ -postinstall_dexopt ++ -cppreopts ++ -dex2oat ++ -zygote ++<<<<<<< HEAD ++ -shell ++======= ++ -otapreopt_slot ++>>>>>>> android-7.1.0_r4 ++} dalvikcache_data_file:dir no_w_dir_perms; ++ ++# Only system_server should be able to send commands via the zygote socket ++neverallow { domain -zygote -system_server } zygote:unix_stream_socket connectto; ++neverallow { domain -system_server } zygote_socket:sock_file write; ++ ++# Android does not support System V IPCs. ++# ++# The reason for this is due to the fact that, by design, they lead to global ++# kernel resource leakage. ++# ++# For example, there is no way to automatically release a SysV semaphore ++# allocated in the kernel when: ++# ++# - a buggy or malicious process exits ++# - a non-buggy and non-malicious process crashes or is explicitly killed. ++# ++# Killing processes automatically to make room for new ones is an ++# important part of Android's application lifecycle implementation. This means ++# that, even assuming only non-buggy and non-malicious code, it is very likely ++# that over time, the kernel global tables used to implement SysV IPCs will fill ++# up. ++neverallow * *:{ shm sem msg msgq } *; ++ ++# Do not mount on top of symlinks, fifos, or sockets. ++# Feature parity with Chromium LSM. ++neverallow * { file_type fs_type dev_type }:{ lnk_file fifo_file sock_file } mounton; ++ ++# Nobody should be able to execute su on user builds. ++# On userdebug/eng builds, only dumpstate, shell, and ++# su itself execute su. ++neverallow { domain userdebug_or_eng(`-dumpstate -shell -su') } su_exec:file no_x_file_perms; ++ ++# Do not allow the introduction of new execmod rules. Text relocations ++# and modification of executable pages are unsafe. ++# The only exceptions are for NDK text relocations associated with ++# https://code.google.com/p/android/issues/detail?id=23203 ++# which, long term, need to go away. ++#neverallow * { ++# file_type ++# -system_data_file ++# -apk_data_file ++# -app_data_file ++# -asec_public_file ++#}:file execmod; ++ ++# Do not allow making the stack or heap executable. ++# We would also like to minimize execmem but it seems to be ++# required by some device-specific service domains. ++neverallow * self:process { execstack execheap }; ++ ++# prohibit non-zygote spawned processes from using shared libraries ++# with text relocations. b/20013628 . ++#neverallow { domain -appdomain } file_type:file execmod; ++ ++neverallow { domain -init } proc:{ file dir } mounton; ++ ++# Ensure that all types assigned to processes are included ++# in the domain attribute, so that all allow and neverallow rules ++# written on domain are applied to all processes. ++# This is achieved by ensuring that it is impossible to transition ++# from a domain to a non-domain type and vice versa. ++neverallow domain ~domain:process { transition dyntransition }; ++neverallow ~domain domain:process { transition dyntransition }; ++ ++# ++# Only system_app and system_server should be creating or writing ++# their files. The proper way to share files is to setup ++# type transitions to a more specific type or assigning a type ++# to its parent directory via a file_contexts entry. ++# Example type transition: ++# mydomain.te:file_type_auto_trans(mydomain, system_data_file, new_file_type) ++# ++neverallow { ++ domain ++ -system_server ++ -system_app ++ -init ++ -installd # for relabelfrom and unlink, check for this in explicit neverallow ++} system_data_file:file no_w_file_perms; ++# do not grant anything greater than r_file_perms and relabelfrom unlink ++# to installd ++neverallow installd system_data_file:file ~{ r_file_perms relabelfrom unlink }; ++ ++# ++# Only these domains should transition to shell domain. This domain is ++# permissible for the "shell user". If you need a process to exec a shell ++# script with differing privilege, define a domain and set up a transition. ++# ++neverallow { ++ domain ++ -adbd ++ -init ++ -runas ++ -zygote ++} shell:process { transition dyntransition }; ++ ++# Only domains spawned from zygote and runas may have the appdomain attribute. ++neverallow { domain -runas -zygote } { ++ appdomain -shell userdebug_or_eng(`-su') -bluetooth ++}:process { transition dyntransition }; ++ ++# Minimize read access to shell- or app-writable symlinks. ++# This is to prevent malicious symlink attacks. ++neverallow { ++ domain ++ -appdomain ++ -installd ++ -uncrypt # TODO: see if we can remove ++} app_data_file:lnk_file read; ++ ++neverallow { ++ domain ++ -shell ++ userdebug_or_eng(`-uncrypt') ++ -installd ++} shell_data_file:lnk_file read; ++ ++# In addition to the symlink reading restrictions above, restrict ++# write access to shell owned directories. The /data/local/tmp ++# directory is untrustworthy, and non-whitelisted domains should ++# not be trusting any content in those directories. ++neverallow { ++ domain ++ -adbd ++ -dumpstate ++ -installd ++ -init ++ -shell ++ -vold ++} shell_data_file:dir no_w_dir_perms; ++ ++neverallow { ++ domain ++ -adbd ++ -appdomain ++ -dumpstate ++ -init ++ -installd ++ -system_server # why? ++ userdebug_or_eng(`-uncrypt') ++} shell_data_file:dir { open search }; ++ ++# Same as above for /data/local/tmp files. We allow shell files ++# to be passed around by file descriptor, but not directly opened. ++neverallow { ++ domain ++ -adbd ++ -appdomain ++ -dumpstate ++ -installd ++ userdebug_or_eng(`-uncrypt') ++} shell_data_file:file open; ++ ++# servicemanager is the only process which handles list request ++neverallow * ~servicemanager:service_manager list; ++ ++# only service_manager_types can be added to service_manager ++neverallow * ~service_manager_type:service_manager { add find }; ++ ++# Prevent assigning non property types to properties ++neverallow * ~property_type:property_service set; ++ ++# Domain types should never be assigned to any files other ++# than the /proc/pid files associated with a process. The ++# executable file used to enter a domain should be labeled ++# with its own _exec type, not with the domain type. ++# Conventionally, this looks something like: ++# $ cat mydaemon.te ++# type mydaemon, domain; ++# type mydaemon_exec, exec_type, file_type; ++# init_daemon_domain(mydaemon) ++# $ grep mydaemon file_contexts ++# /system/bin/mydaemon -- u:object_r:mydaemon_exec:s0 ++neverallow * domain:file { execute execute_no_trans entrypoint }; ++ ++# Do not allow access to the generic debugfs label. This is too broad. ++# Instead, if access to part of debugfs is desired, it should have a ++# more specific label. ++# TODO: fix system_server and dumpstate ++#neverallow { domain -init -system_server -dumpstate } debugfs:file no_rw_file_perms; ++ ++neverallow { ++ domain ++ -init ++ -recovery ++ -sdcardd ++ -vold ++} fuse_device:chr_file open; ++neverallow { ++ domain ++ -dumpstate ++ -init ++ -priv_app ++ -recovery ++ -sdcardd ++ -system_server ++ -ueventd ++ -vold ++} fuse_device:chr_file *; ++ ++# Profiles contain untrusted data and profman parses that. We should only run ++# in from installd forked processes. ++neverallow { ++ domain ++ -installd ++ -profman ++} profman_exec:file no_x_file_perms; ++ ++# Enforce restrictions on kernel module origin. ++# Do not allow kernel module loading except from system, ++# vendor, and boot partitions. ++neverallow * ~{ system_file rootfs }:system module_load; +diff --git a/file.te b/file.te +index 84af4a7..55910d2 100644 +--- a/file.te ++++ b/file.te +@@ -46,6 +46,8 @@ type devpts, fs_type, mlstrustedobject; + type tmpfs, fs_type; + type shm, fs_type; + type mqueue, fs_type; ++type sdcard_internal, sdcard_type, fs_type, mlstrustedobject; ++type sdcard_external, sdcard_type, fs_type, mlstrustedobject; + type fuse, sdcard_type, fs_type, mlstrustedobject; + type sdcardfs, sdcard_type, fs_type, mlstrustedobject; + type vfat, sdcard_type, fs_type, mlstrustedobject; +diff --git a/priv_app.te b/priv_app.te +index 85516a6..e1f96d5 100644 +--- a/priv_app.te ++++ b/priv_app.te +@@ -112,7 +112,7 @@ neverallow priv_app domain:netlink_socket *; + + # Too much leaky information in debugfs. It's a security + # best practice to ensure these files aren't readable. +-neverallow priv_app debugfs:file read; ++#neverallow priv_app debugfs:file read; + + # Do not allow privileged apps to register services. + # Only trusted components of Android should be registering +diff --git a/untrusted_app.te b/untrusted_app.te +index 35c811c..19cfc64 100644 +--- a/untrusted_app.te ++++ b/untrusted_app.te +@@ -62,7 +62,7 @@ allow untrusted_app media_rw_data_file:file create_file_perms; + + # Traverse into /mnt/media_rw for bypassing FUSE daemon + # TODO: narrow this to just MediaProvider +-allow untrusted_app mnt_media_rw_file:dir search; ++#allow untrusted_app mnt_media_rw_file:dir search; + + # allow cts to query all services + allow untrusted_app servicemanager:service_manager list; +@@ -122,7 +122,7 @@ neverallow untrusted_app domain:netlink_socket *; + + # Too much leaky information in debugfs. It's a security + # best practice to ensure these files aren't readable. +-neverallow untrusted_app debugfs_type:file read; ++#neverallow untrusted_app debugfs_type:file read; + + # Do not allow untrusted apps to register services. + # Only trusted components of Android should be registering From 100cbb6387671519c5205c56dc5515fff6534648 Mon Sep 17 00:00:00 2001 From: AndDiSa Date: Wed, 23 Nov 2016 19:30:43 +0100 Subject: [PATCH 044/159] reformat README Change-Id: I45843e2ecd1e290f6a59d14b8395bac509732c94 --- README.md | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/README.md b/README.md index b351429..fb87a41 100644 --- a/README.md +++ b/README.md @@ -9,31 +9,45 @@ repo sync ... cd build + patch -p 1 < ../.repo/manifests/build.patch + cd .. cd frameworks/av + patch -p 1 < ../../.repo/manifests/frameworks_av.patch + cd ../.. cd frameworks/base + patch -p 1 < ../../.repo/manifests/frameworks_base.patch + cd ../.. cd frameworks/native + patch -p 1 < ../../.repo/manifests/frameworks_native.patch + cd ../.. cd packages/aps/Music + patch -p 1 < ../../../.repo/manifests/packages_apps_music.patch + cd ../../.. cd system/core + patch -p 1 < ../../.repo/manifests/system_core.patch + cd ../.. cd system/core + patch -p 1 < ../../.repo/manifests/system_sepolicy.patch + cd ../.. . build/envsetup.sh From ee78443261dec74c92f16750a8010627f95915eb Mon Sep 17 00:00:00 2001 From: AndDiSa Date: Wed, 23 Nov 2016 19:35:54 +0100 Subject: [PATCH 045/159] update patch file Change-Id: I3319c4f0ecb58c4f2a19e06f993e69531d092fd8 --- system_sepolicy.patch | 621 ------------------------------------------ 1 file changed, 621 deletions(-) diff --git a/system_sepolicy.patch b/system_sepolicy.patch index 3460484..1c95f0f 100644 --- a/system_sepolicy.patch +++ b/system_sepolicy.patch @@ -98,627 +98,6 @@ index 45569de..21c9df2 100644 neverallow { domain -diff --git a/domain.te.orig b/domain.te.orig -new file mode 100644 -index 0000000..ae012ea ---- /dev/null -+++ b/domain.te.orig -@@ -0,0 +1,615 @@ -+# Rules for all domains. -+ -+# Allow reaping by init. -+allow domain init:process sigchld; -+ -+# Intra-domain accesses. -+allow domain self:process { -+ fork -+ sigchld -+ sigkill -+ sigstop -+ signull -+ signal -+ getsched -+ setsched -+ getsession -+ getpgid -+ setpgid -+ getcap -+ setcap -+ getattr -+ setrlimit -+}; -+allow domain self:fd use; -+allow domain proc:dir r_dir_perms; -+allow domain proc_net:dir search; -+r_dir_file(domain, self) -+allow domain self:{ fifo_file file } rw_file_perms; -+allow domain self:unix_dgram_socket { create_socket_perms sendto }; -+allow domain self:unix_stream_socket { create_stream_socket_perms connectto }; -+allowxperm domain domain:{ unix_dgram_socket unix_stream_socket } ioctl unpriv_unix_sock_ioctls; -+ -+# Inherit or receive open files from others. -+allow domain init:fd use; -+ -+userdebug_or_eng(` -+ # Same as adbd rules above, except allow su to do the same thing -+ allow domain su:unix_stream_socket connectto; -+ allow domain su:fd use; -+ allow domain su:unix_stream_socket { getattr getopt read write shutdown }; -+ -+ allow { domain -init } su:binder { call transfer }; -+ allow { domain -init } su:fd use; -+ -+ # Running something like "pm dump com.android.bluetooth" requires -+ # fifo writes -+ allow domain su:fifo_file { write getattr }; -+ -+ # allow "gdbserver --attach" to work for su. -+ allow domain su:process sigchld; -+ -+ # Allow writing coredumps to /cores/* -+ allow domain coredump_file:file create_file_perms; -+ allow domain coredump_file:dir ra_dir_perms; -+') -+ -+### -+### Talk to debuggerd. -+### -+allow domain debuggerd:process sigchld; -+allow domain debuggerd:unix_stream_socket connectto; -+ -+# Root fs. -+allow domain rootfs:dir search; -+allow domain rootfs:lnk_file read; -+ -+# Device accesses. -+allow domain device:dir search; -+allow domain dev_type:lnk_file r_file_perms; -+allow domain devpts:dir search; -+allow domain socket_device:dir r_dir_perms; -+allow domain owntty_device:chr_file rw_file_perms; -+allow domain null_device:chr_file rw_file_perms; -+allow domain zero_device:chr_file rw_file_perms; -+allow domain ashmem_device:chr_file rw_file_perms; -+allow domain binder_device:chr_file rw_file_perms; -+allow domain ptmx_device:chr_file rw_file_perms; -+allow domain alarm_device:chr_file r_file_perms; -+allow domain urandom_device:chr_file rw_file_perms; -+allow domain random_device:chr_file rw_file_perms; -+allow domain properties_device:dir r_dir_perms; -+allow domain properties_serial:file r_file_perms; -+ -+# For now, everyone can access core property files -+# Device specific properties are not granted by default -+get_prop(domain, core_property_type) -+# Let everyone read log properties, so that liblog can avoid sending unloggable -+# messages to logd. -+get_prop(domain, log_property_type) -+dontaudit domain property_type:file audit_access; -+allow domain property_contexts:file r_file_perms; -+ -+allow domain init:key search; -+allow domain vold:key search; -+ -+# logd access -+write_logd(domain) -+ -+# System file accesses. -+allow domain system_file:dir { search getattr }; -+allow domain system_file:file { execute read open getattr }; -+allow domain system_file:lnk_file read; -+ -+# read any sysfs symlinks -+allow domain sysfs:lnk_file read; -+ -+# libc references /data/misc/zoneinfo for timezone related information -+r_dir_file(domain, zoneinfo_data_file) -+ -+# Lots of processes access current CPU information -+r_dir_file(domain, sysfs_devices_system_cpu) -+ -+r_dir_file(domain, sysfs_usb); -+ -+# files under /data. -+allow domain system_data_file:dir { search getattr }; -+allow domain system_data_file:lnk_file read; -+ -+# required by the dynamic linker -+allow domain proc:lnk_file { getattr read }; -+ -+# /proc/cpuinfo -+allow domain proc_cpuinfo:file r_file_perms; -+ -+# toybox loads libselinux which stats /sys/fs/selinux/ -+allow domain selinuxfs:dir search; -+allow domain selinuxfs:file getattr; -+allow domain sysfs:dir search; -+allow domain selinuxfs:filesystem getattr; -+ -+# For /acct/uid/*/tasks. -+allow domain cgroup:dir { search write }; -+allow domain cgroup:file w_file_perms; -+ -+# Almost all processes log tracing information to -+# /sys/kernel/debug/tracing/trace_marker -+# The reason behind this is documented in b/6513400 -+allow domain debugfs:dir search; -+allow domain debugfs_tracing:dir search; -+allow domain debugfs_trace_marker:file w_file_perms; -+ -+# Filesystem access. -+allow domain fs_type:filesystem getattr; -+allow domain fs_type:dir getattr; -+ -+### -+### neverallow rules -+### -+ -+# Do not allow any domain other than init or recovery to create unlabeled files. -+neverallow { domain -init -recovery } unlabeled:dir_file_class_set create; -+ -+# Limit ability to ptrace or read sensitive /proc/pid files of processes -+# with other UIDs to these whitelisted domains. -+neverallow { -+ domain -+ -debuggerd -+ -vold -+ -dumpstate -+ -system_server -+ userdebug_or_eng(`-perfprofd') -+ userdebug_or_eng(`-procrank') -+} self:capability sys_ptrace; -+ -+# Limit device node creation to these whitelisted domains. -+neverallow { -+ domain -+ -kernel -+ -init -+ -ueventd -+ -vold -+} self:capability mknod; -+ -+# Limit raw I/O to these whitelisted domains. Do not apply to debug builds. -+neverallow { -+ domain -+ userdebug_or_eng(`-domain') -+ -kernel -+ -init -+ -recovery -+ -ueventd -+ -healthd -+ -uncrypt -+ -tee -+} self:capability sys_rawio; -+ -+# No process can map low memory (< CONFIG_LSM_MMAP_MIN_ADDR). -+neverallow * self:memprotect mmap_zero; -+ -+# No domain needs mac_override as it is unused by SELinux. -+neverallow * self:capability2 mac_override; -+ -+# Only recovery needs mac_admin to set contexts not defined in current policy. -+neverallow { domain -recovery } self:capability2 mac_admin; -+ -+# Only init should be able to load SELinux policies. -+# The first load technically occurs while still in the kernel domain, -+# but this does not trigger a denial since there is no policy yet. -+# Policy reload requires allowing this to the init domain. -+neverallow { domain -init } kernel:security load_policy; -+ -+# Only init and the system_server can set selinux.reload_policy 1 -+# to trigger a policy reload. -+neverallow { domain -init -system_server } security_prop:property_service set; -+ -+# Only init and system_server can write to /data/security, where runtime -+# policy updates live. -+# Only init can relabel /data/security (for init.rc restorecon_recursive /data). -+neverallow { domain -init } security_file:{ dir file lnk_file } { relabelfrom relabelto }; -+# Only init and system_server can create/setattr directories with this type. -+# init is for init.rc mkdir /data/security. -+# system_server is for creating subdirectories under /data/security. -+neverallow { domain -init -system_server } security_file:dir { create setattr }; -+# Only system_server can create subdirectories and files under /data/security. -+neverallow { domain -system_server } security_file:dir { rename write add_name remove_name rmdir }; -+neverallow { domain -system_server } security_file:file { create setattr write append unlink link rename }; -+neverallow { domain -system_server } security_file:lnk_file { create setattr unlink rename }; -+ -+# Only init prior to switching context should be able to set enforcing mode. -+# init starts in kernel domain and switches to init domain via setcon in -+# the init.rc, so the setenforce occurs while still in kernel. After -+# switching domains, there is never any need to setenforce again by init. -+neverallow * kernel:security setenforce; -+neverallow { domain -kernel } kernel:security setcheckreqprot; -+ -+# No booleans in AOSP policy, so no need to ever set them. -+neverallow * kernel:security setbool; -+ -+# Adjusting the AVC cache threshold. -+# Not presently allowed to anything in policy, but possibly something -+# that could be set from init.rc. -+neverallow { domain -init } kernel:security setsecparam; -+ -+# Only init, ueventd and system_server should be able to access HW RNG -+neverallow { domain -init -system_server -ueventd } hw_random_device:chr_file *; -+ -+# Ensure that all entrypoint executables are in exec_type or postinstall_file. -+neverallow * { file_type -exec_type -postinstall_file }:file entrypoint; -+ -+# Ensure that nothing in userspace can access /dev/mem or /dev/kmem -+neverallow { domain -kernel -ueventd -init } kmem_device:chr_file *; -+neverallow * kmem_device:chr_file ~{ create relabelto unlink setattr }; -+ -+# Only init should be able to configure kernel usermodehelpers or -+# security-sensitive proc settings. -+neverallow { domain -init } usermodehelper:file { append write }; -+neverallow { domain -init } proc_security:file { append write }; -+ -+# No domain should be allowed to ptrace init. -+neverallow * init:process ptrace; -+ -+# Init can't do anything with binder calls. If this neverallow rule is being -+# triggered, it's probably due to a service with no SELinux domain. -+neverallow * init:binder *; -+ -+# Don't allow raw read/write/open access to block_device -+# Rather force a relabel to a more specific type -+neverallow { domain -kernel -init -recovery -uncrypt } block_device:blk_file { open read write }; -+ -+# Don't allow raw read/write/open access to generic devices. -+# Rather force a relabel to a more specific type. -+# init is exempt from this as there are character devices that only it uses. -+# ueventd is exempt from this, as it is managing these devices. -+neverallow { domain -init -ueventd } device:chr_file { open read write }; -+ -+# Limit what domains can mount filesystems or change their mount flags. -+# sdcard_type / vfat is exempt as a larger set of domains need -+# this capability, including device-specific domains. -+neverallow { domain -kernel -init -recovery -vold -zygote -update_engine -otapreopt_chroot } { fs_type -sdcard_type }:filesystem { mount remount relabelfrom relabelto }; -+ -+# -+# Assert that, to the extent possible, we're not loading executable content from -+# outside the rootfs or /system partition except for a few whitelisted domains. -+# -+neverallow { -+ domain -+ -appdomain -+ -autoplay_app -+ -dumpstate -+ -shell -+ userdebug_or_eng(`-su') -+ -system_server -+ -zygote -+} { file_type -system_file -exec_type -postinstall_file }:file execute; -+neverallow { -+ domain -+ -appdomain # for oemfs -+ -recovery # for /tmp/update_binary in tmpfs -+} { fs_type -rootfs }:file execute; -+# Files from cache should never be executed -+neverallow domain { cache_file cache_backup_file cache_private_backup_file cache_recovery_file }:file execute; -+ -+# Protect most domains from executing arbitrary content from /data. -+neverallow { -+ domain -+ -appdomain -+} { -+ data_file_type -+ -dalvikcache_data_file -+ -system_data_file # shared libs in apks -+ -apk_data_file -+}:file no_x_file_perms; -+ -+neverallow { domain userdebug_or_eng(`-shell') } nativetest_data_file:file no_x_file_perms; -+ -+# Only the init property service should write to /data/property and /dev/__properties__ -+neverallow { domain -init } property_data_file:dir no_w_dir_perms; -+neverallow { domain -init } property_data_file:file { no_w_file_perms no_x_file_perms }; -+neverallow { domain -init } property_type:file { no_w_file_perms no_x_file_perms }; -+neverallow { domain -init } properties_device:file { no_w_file_perms no_x_file_perms }; -+neverallow { domain -init } properties_serial:file { no_w_file_perms no_x_file_perms }; -+ -+# Only recovery should be doing writes to /system -+neverallow { domain -recovery } { system_file exec_type }:dir_file_class_set -+ { create write setattr relabelfrom append unlink link rename }; -+neverallow { domain -recovery -kernel } { system_file exec_type }:dir_file_class_set relabelto; -+ -+# Don't allow mounting on top of /system files or directories -+neverallow * exec_type:dir_file_class_set mounton; -+neverallow { domain -init } system_file:dir_file_class_set mounton; -+ -+# Nothing should be writing to files in the rootfs. -+neverallow * rootfs:file { create write setattr relabelto append unlink link rename }; -+ -+# Restrict context mounts to specific types marked with -+# the contextmount_type attribute. -+neverallow * {fs_type -contextmount_type}:filesystem relabelto; -+ -+# Ensure that context mount types are not writable, to ensure that -+# the write to /system restriction above is not bypassed via context= -+# mount to another type. -+neverallow { domain -recovery } contextmount_type:dir_file_class_set -+ { create write setattr relabelfrom relabelto append unlink link rename }; -+ -+# Do not allow service_manager add for default_android_service. -+# Instead domains should use a more specific type such as -+# system_app_service rather than the generic type. -+# New service_types are defined in service.te and new mappings -+# from service name to service_type are defined in service_contexts. -+neverallow * default_android_service:service_manager add; -+ -+# Require that domains explicitly label unknown properties, and do not allow -+# anyone but init to modify unknown properties. -+neverallow { domain -init } default_prop:property_service set; -+neverallow { domain -init } mmc_prop:property_service set; -+ -+neverallow { domain -init -recovery -system_server } frp_block_device:blk_file rw_file_perms; -+ -+# No domain other than recovery and update_engine can write to system partition(s). -+neverallow { domain -recovery -update_engine } system_block_device:blk_file write; -+ -+# No domains other than install_recovery or recovery can write to recovery. -+neverallow { domain -install_recovery -recovery } recovery_block_device:blk_file write; -+ -+# No domains other than a select few can access the misc_block_device. This -+# block device is reserved for OTA use. -+# Do not assert this rule on userdebug/eng builds, due to some devices using -+# this partition for testing purposes. -+neverallow { -+ domain -+ userdebug_or_eng(`-domain') # exclude debuggable builds -+ -init -+ -uncrypt -+ -update_engine -+ -vold -+ -recovery -+ -ueventd -+} misc_block_device:blk_file { append link relabelfrom rename write open read ioctl lock }; -+ -+# Only servicemanager should be able to register with binder as the context manager -+neverallow { domain -servicemanager } *:binder set_context_mgr; -+ -+# Only authorized processes should be writing to files in /data/dalvik-cache -+neverallow { -+ domain -+ -init # TODO: limit init to relabelfrom for files -+ -zygote -+ -installd -+ -postinstall_dexopt -+ -cppreopts -+ -dex2oat -+<<<<<<< HEAD -+ -shell -+ -system_app -+======= -+ -otapreopt_slot -+>>>>>>> android-7.1.0_r4 -+} dalvikcache_data_file:file no_w_file_perms; -+ -+neverallow { -+ domain -+ -init -+ -installd -+ -postinstall_dexopt -+ -cppreopts -+ -dex2oat -+ -zygote -+<<<<<<< HEAD -+ -shell -+======= -+ -otapreopt_slot -+>>>>>>> android-7.1.0_r4 -+} dalvikcache_data_file:dir no_w_dir_perms; -+ -+# Only system_server should be able to send commands via the zygote socket -+neverallow { domain -zygote -system_server } zygote:unix_stream_socket connectto; -+neverallow { domain -system_server } zygote_socket:sock_file write; -+ -+# Android does not support System V IPCs. -+# -+# The reason for this is due to the fact that, by design, they lead to global -+# kernel resource leakage. -+# -+# For example, there is no way to automatically release a SysV semaphore -+# allocated in the kernel when: -+# -+# - a buggy or malicious process exits -+# - a non-buggy and non-malicious process crashes or is explicitly killed. -+# -+# Killing processes automatically to make room for new ones is an -+# important part of Android's application lifecycle implementation. This means -+# that, even assuming only non-buggy and non-malicious code, it is very likely -+# that over time, the kernel global tables used to implement SysV IPCs will fill -+# up. -+neverallow * *:{ shm sem msg msgq } *; -+ -+# Do not mount on top of symlinks, fifos, or sockets. -+# Feature parity with Chromium LSM. -+neverallow * { file_type fs_type dev_type }:{ lnk_file fifo_file sock_file } mounton; -+ -+# Nobody should be able to execute su on user builds. -+# On userdebug/eng builds, only dumpstate, shell, and -+# su itself execute su. -+neverallow { domain userdebug_or_eng(`-dumpstate -shell -su') } su_exec:file no_x_file_perms; -+ -+# Do not allow the introduction of new execmod rules. Text relocations -+# and modification of executable pages are unsafe. -+# The only exceptions are for NDK text relocations associated with -+# https://code.google.com/p/android/issues/detail?id=23203 -+# which, long term, need to go away. -+#neverallow * { -+# file_type -+# -system_data_file -+# -apk_data_file -+# -app_data_file -+# -asec_public_file -+#}:file execmod; -+ -+# Do not allow making the stack or heap executable. -+# We would also like to minimize execmem but it seems to be -+# required by some device-specific service domains. -+neverallow * self:process { execstack execheap }; -+ -+# prohibit non-zygote spawned processes from using shared libraries -+# with text relocations. b/20013628 . -+#neverallow { domain -appdomain } file_type:file execmod; -+ -+neverallow { domain -init } proc:{ file dir } mounton; -+ -+# Ensure that all types assigned to processes are included -+# in the domain attribute, so that all allow and neverallow rules -+# written on domain are applied to all processes. -+# This is achieved by ensuring that it is impossible to transition -+# from a domain to a non-domain type and vice versa. -+neverallow domain ~domain:process { transition dyntransition }; -+neverallow ~domain domain:process { transition dyntransition }; -+ -+# -+# Only system_app and system_server should be creating or writing -+# their files. The proper way to share files is to setup -+# type transitions to a more specific type or assigning a type -+# to its parent directory via a file_contexts entry. -+# Example type transition: -+# mydomain.te:file_type_auto_trans(mydomain, system_data_file, new_file_type) -+# -+neverallow { -+ domain -+ -system_server -+ -system_app -+ -init -+ -installd # for relabelfrom and unlink, check for this in explicit neverallow -+} system_data_file:file no_w_file_perms; -+# do not grant anything greater than r_file_perms and relabelfrom unlink -+# to installd -+neverallow installd system_data_file:file ~{ r_file_perms relabelfrom unlink }; -+ -+# -+# Only these domains should transition to shell domain. This domain is -+# permissible for the "shell user". If you need a process to exec a shell -+# script with differing privilege, define a domain and set up a transition. -+# -+neverallow { -+ domain -+ -adbd -+ -init -+ -runas -+ -zygote -+} shell:process { transition dyntransition }; -+ -+# Only domains spawned from zygote and runas may have the appdomain attribute. -+neverallow { domain -runas -zygote } { -+ appdomain -shell userdebug_or_eng(`-su') -bluetooth -+}:process { transition dyntransition }; -+ -+# Minimize read access to shell- or app-writable symlinks. -+# This is to prevent malicious symlink attacks. -+neverallow { -+ domain -+ -appdomain -+ -installd -+ -uncrypt # TODO: see if we can remove -+} app_data_file:lnk_file read; -+ -+neverallow { -+ domain -+ -shell -+ userdebug_or_eng(`-uncrypt') -+ -installd -+} shell_data_file:lnk_file read; -+ -+# In addition to the symlink reading restrictions above, restrict -+# write access to shell owned directories. The /data/local/tmp -+# directory is untrustworthy, and non-whitelisted domains should -+# not be trusting any content in those directories. -+neverallow { -+ domain -+ -adbd -+ -dumpstate -+ -installd -+ -init -+ -shell -+ -vold -+} shell_data_file:dir no_w_dir_perms; -+ -+neverallow { -+ domain -+ -adbd -+ -appdomain -+ -dumpstate -+ -init -+ -installd -+ -system_server # why? -+ userdebug_or_eng(`-uncrypt') -+} shell_data_file:dir { open search }; -+ -+# Same as above for /data/local/tmp files. We allow shell files -+# to be passed around by file descriptor, but not directly opened. -+neverallow { -+ domain -+ -adbd -+ -appdomain -+ -dumpstate -+ -installd -+ userdebug_or_eng(`-uncrypt') -+} shell_data_file:file open; -+ -+# servicemanager is the only process which handles list request -+neverallow * ~servicemanager:service_manager list; -+ -+# only service_manager_types can be added to service_manager -+neverallow * ~service_manager_type:service_manager { add find }; -+ -+# Prevent assigning non property types to properties -+neverallow * ~property_type:property_service set; -+ -+# Domain types should never be assigned to any files other -+# than the /proc/pid files associated with a process. The -+# executable file used to enter a domain should be labeled -+# with its own _exec type, not with the domain type. -+# Conventionally, this looks something like: -+# $ cat mydaemon.te -+# type mydaemon, domain; -+# type mydaemon_exec, exec_type, file_type; -+# init_daemon_domain(mydaemon) -+# $ grep mydaemon file_contexts -+# /system/bin/mydaemon -- u:object_r:mydaemon_exec:s0 -+neverallow * domain:file { execute execute_no_trans entrypoint }; -+ -+# Do not allow access to the generic debugfs label. This is too broad. -+# Instead, if access to part of debugfs is desired, it should have a -+# more specific label. -+# TODO: fix system_server and dumpstate -+#neverallow { domain -init -system_server -dumpstate } debugfs:file no_rw_file_perms; -+ -+neverallow { -+ domain -+ -init -+ -recovery -+ -sdcardd -+ -vold -+} fuse_device:chr_file open; -+neverallow { -+ domain -+ -dumpstate -+ -init -+ -priv_app -+ -recovery -+ -sdcardd -+ -system_server -+ -ueventd -+ -vold -+} fuse_device:chr_file *; -+ -+# Profiles contain untrusted data and profman parses that. We should only run -+# in from installd forked processes. -+neverallow { -+ domain -+ -installd -+ -profman -+} profman_exec:file no_x_file_perms; -+ -+# Enforce restrictions on kernel module origin. -+# Do not allow kernel module loading except from system, -+# vendor, and boot partitions. -+neverallow * ~{ system_file rootfs }:system module_load; diff --git a/file.te b/file.te index 84af4a7..55910d2 100644 --- a/file.te From 9a4765fd0334379f0961c3d1ebc450f4948324f9 Mon Sep 17 00:00:00 2001 From: AndDiSa Date: Fri, 25 Nov 2016 20:33:15 +0100 Subject: [PATCH 046/159] add hardware/ril patch Change-Id: I5c4f179937036eddb4183cd224e9fe6090f02786 --- README.md | 6 ++++++ hardware_ril.patch | 12 ++++++++++++ 2 files changed, 18 insertions(+) create mode 100644 hardware_ril.patch diff --git a/README.md b/README.md index fb87a41..149eaf7 100644 --- a/README.md +++ b/README.md @@ -32,6 +32,12 @@ patch -p 1 < ../../.repo/manifests/frameworks_native.patch cd ../.. +cd hardware/ril + +patch -p 1 < ../../.repo/manifests/hardware_ril.patch + +cd ../.. + cd packages/aps/Music patch -p 1 < ../../../.repo/manifests/packages_apps_music.patch diff --git a/hardware_ril.patch b/hardware_ril.patch new file mode 100644 index 0000000..951db3c --- /dev/null +++ b/hardware_ril.patch @@ -0,0 +1,12 @@ +diff --git a/libril/ril.cpp b/libril/ril.cpp +index e1d30ea..ce9c7a7 100755 +--- a/libril/ril.cpp ++++ b/libril/ril.cpp +@@ -3702,6 +3702,7 @@ static void responseSimStatusV5(Parcel &p, void *response) { + p.writeInt32(p_cur->universal_pin_state); + p.writeInt32(p_cur->gsm_umts_subscription_app_index); + p.writeInt32(p_cur->cdma_subscription_app_index); ++ p.writeInt32(-1); + + sendSimStatusAppInfo(p, p_cur->num_applications, p_cur->applications); + } From 960faa20a796a38c502a9f2fa2a141240c310ba2 Mon Sep 17 00:00:00 2001 From: AndDiSa Date: Sat, 26 Nov 2016 16:50:42 +0100 Subject: [PATCH 047/159] update patches Change-Id: I7e7df4fca516ca9a8d8cd138c9c3cd0545a22ed4 --- frameworks_native.patch | 856 +++++++++++++++++++++++++++++++++++++++- hardware_ril.patch | 4 +- 2 files changed, 857 insertions(+), 3 deletions(-) diff --git a/frameworks_native.patch b/frameworks_native.patch index d289649..e73225c 100644 --- a/frameworks_native.patch +++ b/frameworks_native.patch @@ -1,5 +1,744 @@ +diff --git a/cmds/atrace/atrace.cpp b/cmds/atrace/atrace.cpp +index facf300..10f4d6e 100644 +--- a/cmds/atrace/atrace.cpp ++++ b/cmds/atrace/atrace.cpp +@@ -593,16 +593,30 @@ static bool verifyKernelTraceFuncs(const char* funcs) + return false; + } + +- char buf[4097]; +- ssize_t n = read(fd, buf, 4096); +- close(fd); +- if (n == -1) { +- fprintf(stderr, "error reading %s: %s (%d)\n", k_ftraceFilterPath, +- strerror(errno), errno); +- return false; ++ // read back the filter ++ ssize_t n = 0; ++ ssize_t len = 0; ++ char *r; ++ char *buf = NULL; ++ do { ++ len += n; ++ r = (char *) realloc(buf, len + 4096); ++ if (r == NULL) ++ break; ++ buf = r; ++ } while ( (n = read(fd, (void *)(buf + len), 4095)) > 0 ); ++ ++ if ( ( n == -1 ) || ( r == NULL ) ) { ++ fprintf(stderr, "error reading %s: %s (%d)\n", k_ftraceFilterPath, ++ strerror(errno), errno); ++ close(fd); ++ free(buf); ++ return false; + } + +- buf[n] = '\0'; ++ buf[len] = '\0'; ++ close(fd); ++ + String8 funcList = String8::format("\n%s", buf); + + // Make sure that every function listed in funcs is in the list we just +@@ -622,8 +636,8 @@ static bool verifyKernelTraceFuncs(const char* funcs) + } + func = strtok(NULL, ","); + } ++ free(buf); + free(myFuncs); +- + return ok; + } + +diff --git a/include/gui/ISurfaceComposer.h b/include/gui/ISurfaceComposer.h +index 74a4123..8dc6f6a 100644 +--- a/include/gui/ISurfaceComposer.h ++++ b/include/gui/ISurfaceComposer.h +@@ -32,6 +32,12 @@ + #include + #include + ++#ifndef FORCE_SCREENSHOT_CPU_PATH ++#define SS_CPU_CONSUMER false ++#else ++#define SS_CPU_CONSUMER true ++#endif ++ + namespace android { + // ---------------------------------------------------------------------------- + +@@ -151,7 +157,8 @@ public: + Rect sourceCrop, uint32_t reqWidth, uint32_t reqHeight, + uint32_t minLayerZ, uint32_t maxLayerZ, + bool useIdentityTransform, +- Rotation rotation = eRotateNone) = 0; ++ Rotation rotation = eRotateNone, ++ bool isCpuConsumer = SS_CPU_CONSUMER) = 0; + + /* Clears the frame statistics for animations. + * +diff --git a/libs/binder/IPCThreadState.cpp b/libs/binder/IPCThreadState.cpp +index d90798f..9b5f0d7 100644 +--- a/libs/binder/IPCThreadState.cpp ++++ b/libs/binder/IPCThreadState.cpp +@@ -330,6 +330,7 @@ void IPCThreadState::shutdown() + delete st; + pthread_setspecific(gTLS, NULL); + } ++ pthread_key_delete(gTLS); + gHaveTLS = false; + } + } +diff --git a/libs/binder/ProcessState.cpp b/libs/binder/ProcessState.cpp +index f13f49f..e45b5f1 100644 +--- a/libs/binder/ProcessState.cpp ++++ b/libs/binder/ProcessState.cpp +@@ -366,6 +366,13 @@ ProcessState::ProcessState() + + ProcessState::~ProcessState() + { ++ if (mDriverFD >= 0) { ++ if (mVMStart != MAP_FAILED) { ++ munmap(mVMStart, BINDER_VM_SIZE); ++ } ++ close(mDriverFD); ++ } ++ mDriverFD = -1; + } + + }; // namespace android +diff --git a/libs/gui/Android.mk b/libs/gui/Android.mk +index 46feb1c..1b4a9c5 100644 +--- a/libs/gui/Android.mk ++++ b/libs/gui/Android.mk +@@ -84,6 +84,9 @@ LOCAL_SHARED_LIBRARIES := \ + libutils \ + liblog + ++ifeq ($(TARGET_FORCE_SCREENSHOT_CPU_PATH),true) ++ LOCAL_CFLAGS += -DFORCE_SCREENSHOT_CPU_PATH ++endif + + LOCAL_MODULE := libgui + +diff --git a/libs/gui/ISurfaceComposer.cpp b/libs/gui/ISurfaceComposer.cpp +index f0b0ada..3577a33 100644 +--- a/libs/gui/ISurfaceComposer.cpp ++++ b/libs/gui/ISurfaceComposer.cpp +@@ -106,7 +106,8 @@ public: + Rect sourceCrop, uint32_t reqWidth, uint32_t reqHeight, + uint32_t minLayerZ, uint32_t maxLayerZ, + bool useIdentityTransform, +- ISurfaceComposer::Rotation rotation) ++ ISurfaceComposer::Rotation rotation, ++ bool isCpuConsumer) + { + Parcel data, reply; + data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor()); +@@ -119,6 +120,7 @@ public: + data.writeUint32(maxLayerZ); + data.writeInt32(static_cast(useIdentityTransform)); + data.writeInt32(static_cast(rotation)); ++ data.writeInt32(isCpuConsumer); + remote()->transact(BnSurfaceComposer::CAPTURE_SCREEN, data, &reply); + return reply.readInt32(); + } +@@ -462,11 +464,12 @@ status_t BnSurfaceComposer::onTransact( + uint32_t maxLayerZ = data.readUint32(); + bool useIdentityTransform = static_cast(data.readInt32()); + int32_t rotation = data.readInt32(); +- ++ bool isCpuConsumer = data.readInt32(); + status_t res = captureScreen(display, producer, + sourceCrop, reqWidth, reqHeight, minLayerZ, maxLayerZ, + useIdentityTransform, +- static_cast(rotation)); ++ static_cast(rotation), ++ isCpuConsumer); + reply->writeInt32(res); + return NO_ERROR; + } +diff --git a/libs/ui/Region.cpp b/libs/ui/Region.cpp +index ee152bf..9c82295 100644 +--- a/libs/ui/Region.cpp ++++ b/libs/ui/Region.cpp +@@ -800,6 +800,11 @@ status_t Region::unflatten(void const* buffer, size_t size) { + return NO_MEMORY; + } + ++ if (numRects > (UINT32_MAX / sizeof(Rect))) { ++ android_errorWriteWithInfoLog(0x534e4554, "29983260", -1, NULL, 0); ++ return NO_MEMORY; ++ } ++ + Region result; + result.mStorage.clear(); + for (size_t r = 0; r < numRects; ++r) { +diff --git a/opengl/libs/Android.mk b/opengl/libs/Android.mk +index eb86860..a512ff7 100644 +--- a/opengl/libs/Android.mk ++++ b/opengl/libs/Android.mk +@@ -77,7 +77,6 @@ LOCAL_SRC_FILES:= \ + GLES_CM/gl.cpp.arm \ + # + +-LOCAL_CLANG := false + LOCAL_SHARED_LIBRARIES += libcutils liblog libEGL + LOCAL_MODULE:= libGLESv1_CM + +@@ -105,7 +104,6 @@ LOCAL_SRC_FILES:= \ + GLES2/gl2.cpp \ + # + +-LOCAL_CLANG := false + LOCAL_ARM_MODE := arm + LOCAL_SHARED_LIBRARIES += libcutils libutils liblog libEGL + LOCAL_MODULE:= libGLESv2 +diff --git a/opengl/libs/GLES2/gl2.cpp b/opengl/libs/GLES2/gl2.cpp +index 6034a8e..f1feeda 100644 +--- a/opengl/libs/GLES2/gl2.cpp ++++ b/opengl/libs/GLES2/gl2.cpp +@@ -59,7 +59,7 @@ using namespace android; + : \ + : [tls] "J"(TLS_SLOT_OPENGL_API*4), \ + [api] "J"(__builtin_offsetof(gl_hooks_t, gl._api)) \ +- : "r12" \ ++ : "r0", "r1", "r2", "r3", "r12" \ + ); + + #elif defined(__aarch64__) +@@ -77,7 +77,7 @@ using namespace android; + : \ + : [tls] "i" (TLS_SLOT_OPENGL_API * sizeof(void*)), \ + [api] "i" (__builtin_offsetof(gl_hooks_t, gl._api)) \ +- : "x16" \ ++ : "x0", "x1", "x2", "x3", "x4", "x5", "x6", "x7", "x16" \ + ); + + #elif defined(__i386__) +@@ -115,7 +115,9 @@ using namespace android; + : [fn] "=r" (fn) \ + : [tls] "i" (TLS_SLOT_OPENGL_API*sizeof(void*)), \ + [api] "i" (__builtin_offsetof(gl_hooks_t, gl._api)) \ +- : "cc" \ ++ : "cc", "%rdi", "%rsi", "%rdx", "%rcx", "%r8", "%r9", \ ++ "%xmm0", "%xmm1", "%xmm2", "%xmm3", "%xmm4", "%xmm5", \ ++ "%xmm6", "%xmm7" \ + ); + + #elif defined(__mips64) +@@ -148,7 +150,7 @@ using namespace android; + [v0] "=&r"(_v0) \ + : [OPENGL_API] "I"(TLS_SLOT_OPENGL_API*sizeof(void*)),\ + [API] "I"(__builtin_offsetof(gl_hooks_t, gl._api)) \ +- : \ ++ : "$4", "$5", "$6", "$7", "$8", "$9", "$10", "$11" \ + ); + + #elif defined(__mips__) +@@ -182,7 +184,7 @@ using namespace android; + [v0] "=&r"(_v0) \ + : [OPENGL_API] "I"(TLS_SLOT_OPENGL_API*4), \ + [API] "I"(__builtin_offsetof(gl_hooks_t, gl._api)) \ +- : \ ++ : "$4", "$5", "$6", "$7" \ + ); + + #endif +diff --git a/opengl/libs/GLES_CM/gl.cpp b/opengl/libs/GLES_CM/gl.cpp +index b1b31f8..fc7f2e1 100644 +--- a/opengl/libs/GLES_CM/gl.cpp ++++ b/opengl/libs/GLES_CM/gl.cpp +@@ -115,7 +115,7 @@ GL_API void GL_APIENTRY glWeightPointerOESBounds(GLint size, GLenum type, + : \ + : [tls] "J"(TLS_SLOT_OPENGL_API*4), \ + [api] "J"(__builtin_offsetof(gl_hooks_t, gl._api)) \ +- : "r12" \ ++ : "r0", "r1", "r2", "r3", "r12" \ + ); + + #elif defined(__aarch64__) +@@ -133,7 +133,7 @@ GL_API void GL_APIENTRY glWeightPointerOESBounds(GLint size, GLenum type, + : \ + : [tls] "i" (TLS_SLOT_OPENGL_API * sizeof(void*)), \ + [api] "i" (__builtin_offsetof(gl_hooks_t, gl._api)) \ +- : "x16" \ ++ : "x0", "x1", "x2", "x3", "x4", "x5", "x6", "x7", "x16" \ + ); + + #elif defined(__i386__) +@@ -171,7 +171,9 @@ GL_API void GL_APIENTRY glWeightPointerOESBounds(GLint size, GLenum type, + : [fn] "=r" (fn) \ + : [tls] "i" (TLS_SLOT_OPENGL_API*sizeof(void*)), \ + [api] "i" (__builtin_offsetof(gl_hooks_t, gl._api)) \ +- : "cc" \ ++ : "cc", "%rdi", "%rsi", "%rdx", "%rcx", "%r8", "%r9", \ ++ "%xmm0", "%xmm1", "%xmm2", "%xmm3", "%xmm4", "%xmm5", \ ++ "%xmm6", "%xmm7" \ + ); + + #elif defined(__mips64) +@@ -204,7 +206,7 @@ GL_API void GL_APIENTRY glWeightPointerOESBounds(GLint size, GLenum type, + [v0] "=&r"(_v0) \ + : [OPENGL_API] "I"(TLS_SLOT_OPENGL_API*sizeof(void*)),\ + [API] "I"(__builtin_offsetof(gl_hooks_t, gl._api)) \ +- : \ ++ : "$4", "$5", "$6", "$7", "$8", "$9", "$10", "$11" \ + ); + + #elif defined(__mips__) +@@ -238,7 +240,7 @@ GL_API void GL_APIENTRY glWeightPointerOESBounds(GLint size, GLenum type, + [v0] "=&r"(_v0) \ + : [OPENGL_API] "I"(TLS_SLOT_OPENGL_API*4), \ + [API] "I"(__builtin_offsetof(gl_hooks_t, gl._api)) \ +- : \ ++ : "$4", "$5", "$6", "$7" \ + ); + + #endif +diff --git a/services/inputflinger/InputReader.cpp b/services/inputflinger/InputReader.cpp +index b9be675..4dec34b 100644 +--- a/services/inputflinger/InputReader.cpp ++++ b/services/inputflinger/InputReader.cpp +@@ -6652,6 +6652,7 @@ void MultiTouchInputMapper::syncTouch(nsecs_t when, RawState* outState) { + size_t inCount = mMultiTouchMotionAccumulator.getSlotCount(); + size_t outCount = 0; + BitSet32 newPointerIdBits; ++ mHavePointerIds = true; + + for (size_t inIndex = 0; inIndex < inCount; inIndex++) { + const MultiTouchMotionAccumulator::Slot* inSlot = +@@ -6696,33 +6697,33 @@ void MultiTouchInputMapper::syncTouch(nsecs_t when, RawState* outState) { + outPointer.isHovering = isHovering; + + // Assign pointer id using tracking id if available. +- mHavePointerIds = true; +- int32_t trackingId = inSlot->getTrackingId(); +- int32_t id = -1; +- if (trackingId >= 0) { +- for (BitSet32 idBits(mPointerIdBits); !idBits.isEmpty(); ) { +- uint32_t n = idBits.clearFirstMarkedBit(); +- if (mPointerTrackingIdMap[n] == trackingId) { +- id = n; ++ if (mHavePointerIds) { ++ int32_t trackingId = inSlot->getTrackingId(); ++ int32_t id = -1; ++ if (trackingId >= 0) { ++ for (BitSet32 idBits(mPointerIdBits); !idBits.isEmpty(); ) { ++ uint32_t n = idBits.clearFirstMarkedBit(); ++ if (mPointerTrackingIdMap[n] == trackingId) { ++ id = n; ++ } + } +- } + +- if (id < 0 && !mPointerIdBits.isFull()) { +- id = mPointerIdBits.markFirstUnmarkedBit(); +- mPointerTrackingIdMap[id] = trackingId; ++ if (id < 0 && !mPointerIdBits.isFull()) { ++ id = mPointerIdBits.markFirstUnmarkedBit(); ++ mPointerTrackingIdMap[id] = trackingId; ++ } ++ } ++ if (id < 0) { ++ mHavePointerIds = false; ++ outState->rawPointerData.clearIdBits(); ++ newPointerIdBits.clear(); ++ } else { ++ outPointer.id = id; ++ outState->rawPointerData.idToIndex[id] = outCount; ++ outState->rawPointerData.markIdBit(id, isHovering); ++ newPointerIdBits.markBit(id); + } + } +- if (id < 0) { +- mHavePointerIds = false; +- outState->rawPointerData.clearIdBits(); +- newPointerIdBits.clear(); +- } else { +- outPointer.id = id; +- outState->rawPointerData.idToIndex[id] = outCount; +- outState->rawPointerData.markIdBit(id, isHovering); +- newPointerIdBits.markBit(id); +- } +- + outCount += 1; + } + +diff --git a/services/surfaceflinger/Android.mk b/services/surfaceflinger/Android.mk +index dc5e97b..42ca6d9 100644 +--- a/services/surfaceflinger/Android.mk ++++ b/services/surfaceflinger/Android.mk +@@ -56,6 +56,9 @@ else + DisplayHardware/HWComposer_hwc1.cpp + endif + ++ifeq ($(TARGET_FORCE_SCREENSHOT_CPU_PATH),true) ++ LOCAL_CFLAGS += -DFORCE_SCREENSHOT_CPU_PATH ++endif + ifeq ($(TARGET_BOARD_PLATFORM),omap4) + LOCAL_CFLAGS += -DHAS_CONTEXT_PRIORITY + endif +diff --git a/services/surfaceflinger/RenderEngine/GLES11RenderEngine.cpp b/services/surfaceflinger/RenderEngine/GLES11RenderEngine.cpp +index 847cdb3..b2821b7 100644 +--- a/services/surfaceflinger/RenderEngine/GLES11RenderEngine.cpp ++++ b/services/surfaceflinger/RenderEngine/GLES11RenderEngine.cpp +@@ -92,14 +92,29 @@ void GLES11RenderEngine::setViewportAndProjection( + case Transform::ROT_0: + break; + case Transform::ROT_90: +- glRotatef(90, 0, 0, 1); ++ { ++ float x1 = (l+r)/2; ++ float y1 = (t+b)/2; ++ glTranslatef(x1-y1, x1+y1, 0); ++ glRotatef(270, 0, 0, 1); + break; ++ } + case Transform::ROT_180: ++ { ++ float x1 = (l+r)/2; ++ float y1 = (t+b)/2; ++ glTranslatef(x1*2, y1*2, 0); + glRotatef(180, 0, 0, 1); + break; ++ } + case Transform::ROT_270: +- glRotatef(270, 0, 0, 1); ++ { ++ float x1 = (l+r)/2; ++ float y1 = (t+b)/2; ++ glTranslatef(x1+y1, y1-x1, 0); ++ glRotatef(90, 0, 0, 1); + break; ++ } + default: + break; + } +@@ -239,28 +254,44 @@ void GLES11RenderEngine::disableBlending() { + } + + void GLES11RenderEngine::bindImageAsFramebuffer(EGLImageKHR image, +- uint32_t* texName, uint32_t* fbName, uint32_t* status) { ++ uint32_t* texName, uint32_t* fbName, uint32_t* status, ++ bool useReadPixels, int reqWidth, int reqHeight) { + GLuint tname, name; +- // turn our EGLImage into a texture +- glGenTextures(1, &tname); +- glBindTexture(GL_TEXTURE_2D, tname); +- glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, (GLeglImageOES)image); +- +- // create a Framebuffer Object to render into +- glGenFramebuffersOES(1, &name); +- glBindFramebufferOES(GL_FRAMEBUFFER_OES, name); +- glFramebufferTexture2DOES(GL_FRAMEBUFFER_OES, +- GL_COLOR_ATTACHMENT0_OES, GL_TEXTURE_2D, tname, 0); +- ++ if (!useReadPixels) { ++ // turn our EGLImage into a texture ++ glGenTextures(1, &tname); ++ glBindTexture(GL_TEXTURE_2D, tname); ++ glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, (GLeglImageOES)image); ++ ++ // create a Framebuffer Object to render into ++ glGenFramebuffersOES(1, &name); ++ glBindFramebufferOES(GL_FRAMEBUFFER_OES, name); ++ glFramebufferTexture2DOES(GL_FRAMEBUFFER_OES, ++ GL_COLOR_ATTACHMENT0_OES, GL_TEXTURE_2D, tname, 0); ++ } else { ++ // since we're going to use glReadPixels() anyways, ++ // use an intermediate renderbuffer instead ++ glGenRenderbuffersOES(1, &tname); ++ glBindRenderbufferOES(GL_RENDERBUFFER_OES, tname); ++ glRenderbufferStorageOES(GL_RENDERBUFFER_OES, GL_RGBA8_OES, reqWidth, reqHeight); ++ // create a FBO to render into ++ glGenFramebuffersOES(1, &name); ++ glBindFramebufferOES(GL_FRAMEBUFFER_OES, name); ++ glFramebufferRenderbufferOES(GL_FRAMEBUFFER_OES, GL_COLOR_ATTACHMENT0_OES, GL_RENDERBUFFER_OES, tname); ++ } + *status = glCheckFramebufferStatusOES(GL_FRAMEBUFFER_OES); + *texName = tname; + *fbName = name; + } + +-void GLES11RenderEngine::unbindFramebuffer(uint32_t texName, uint32_t fbName) { ++void GLES11RenderEngine::unbindFramebuffer(uint32_t texName, uint32_t fbName, ++ bool useReadPixels) { + glBindFramebufferOES(GL_FRAMEBUFFER_OES, 0); + glDeleteFramebuffersOES(1, &fbName); +- glDeleteTextures(1, &texName); ++ if (!useReadPixels) ++ glDeleteTextures(1, &texName); ++ else ++ glDeleteRenderbuffersOES(1, &texName); + } + + void GLES11RenderEngine::setupFillWithColor(float r, float g, float b, float a) { +diff --git a/services/surfaceflinger/RenderEngine/GLES11RenderEngine.h b/services/surfaceflinger/RenderEngine/GLES11RenderEngine.h +index 4cd968d..1ef6596 100644 +--- a/services/surfaceflinger/RenderEngine/GLES11RenderEngine.h ++++ b/services/surfaceflinger/RenderEngine/GLES11RenderEngine.h +@@ -40,8 +40,9 @@ class GLES11RenderEngine : public RenderEngine { + GLint mMaxTextureSize; + + virtual void bindImageAsFramebuffer(EGLImageKHR image, +- uint32_t* texName, uint32_t* fbName, uint32_t* status); +- virtual void unbindFramebuffer(uint32_t texName, uint32_t fbName); ++ uint32_t* texName, uint32_t* fbName, uint32_t* status, ++ bool useReadPixels, int reqWidth, int reqHeight); ++ virtual void unbindFramebuffer(uint32_t texName, uint32_t fbName, bool useReadPixels); + + public: + GLES11RenderEngine(); +diff --git a/services/surfaceflinger/RenderEngine/GLES20RenderEngine.cpp b/services/surfaceflinger/RenderEngine/GLES20RenderEngine.cpp +index 406e611..e3cbc70 100644 +--- a/services/surfaceflinger/RenderEngine/GLES20RenderEngine.cpp ++++ b/services/surfaceflinger/RenderEngine/GLES20RenderEngine.cpp +@@ -208,27 +208,44 @@ void GLES20RenderEngine::disableBlending() { + + + void GLES20RenderEngine::bindImageAsFramebuffer(EGLImageKHR image, +- uint32_t* texName, uint32_t* fbName, uint32_t* status) { ++ uint32_t* texName, uint32_t* fbName, uint32_t* status, ++ bool useReadPixels, int reqWidth, int reqHeight) { + GLuint tname, name; +- // turn our EGLImage into a texture +- glGenTextures(1, &tname); +- glBindTexture(GL_TEXTURE_2D, tname); +- glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, (GLeglImageOES)image); +- +- // create a Framebuffer Object to render into +- glGenFramebuffers(1, &name); +- glBindFramebuffer(GL_FRAMEBUFFER, name); +- glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, tname, 0); ++ if (!useReadPixels) { ++ // turn our EGLImage into a texture ++ glGenTextures(1, &tname); ++ glBindTexture(GL_TEXTURE_2D, tname); ++ glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, (GLeglImageOES)image); ++ ++ // create a Framebuffer Object to render into ++ glGenFramebuffers(1, &name); ++ glBindFramebuffer(GL_FRAMEBUFFER, name); ++ glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, tname, 0); ++ } else { ++ // since we're going to use glReadPixels() anyways, ++ // use an intermediate renderbuffer instead ++ glGenRenderbuffers(1, &tname); ++ glBindRenderbuffer(GL_RENDERBUFFER, tname); ++ glRenderbufferStorage(GL_RENDERBUFFER, GL_RGBA8_OES, reqWidth, reqHeight); ++ // create a FBO to render into ++ glGenFramebuffers(1, &name); ++ glBindFramebuffer(GL_FRAMEBUFFER, name); ++ glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, tname); ++ } + + *status = glCheckFramebufferStatus(GL_FRAMEBUFFER); + *texName = tname; + *fbName = name; + } + +-void GLES20RenderEngine::unbindFramebuffer(uint32_t texName, uint32_t fbName) { ++void GLES20RenderEngine::unbindFramebuffer(uint32_t texName, uint32_t fbName, ++ bool useReadPixels) { + glBindFramebuffer(GL_FRAMEBUFFER, 0); + glDeleteFramebuffers(1, &fbName); +- glDeleteTextures(1, &texName); ++ if (!useReadPixels) ++ glDeleteTextures(1, &texName); ++ else ++ glDeleteRenderbuffers(1, &texName); + } + + void GLES20RenderEngine::setupFillWithColor(float r, float g, float b, float a) { +diff --git a/services/surfaceflinger/RenderEngine/GLES20RenderEngine.h b/services/surfaceflinger/RenderEngine/GLES20RenderEngine.h +index 7c3f9b5..b268119 100644 +--- a/services/surfaceflinger/RenderEngine/GLES20RenderEngine.h ++++ b/services/surfaceflinger/RenderEngine/GLES20RenderEngine.h +@@ -55,8 +55,9 @@ class GLES20RenderEngine : public RenderEngine { + Vector mGroupStack; + + virtual void bindImageAsFramebuffer(EGLImageKHR image, +- uint32_t* texName, uint32_t* fbName, uint32_t* status); +- virtual void unbindFramebuffer(uint32_t texName, uint32_t fbName); ++ uint32_t* texName, uint32_t* fbName, uint32_t* status, ++ bool useReadPixels, int reqWidth, int reqHeight); ++ virtual void unbindFramebuffer(uint32_t texName, uint32_t fbName, bool useReadPixels); + + public: + GLES20RenderEngine(); +diff --git a/services/surfaceflinger/RenderEngine/RenderEngine.cpp b/services/surfaceflinger/RenderEngine/RenderEngine.cpp +index d6a032f..d0df8ab 100644 +--- a/services/surfaceflinger/RenderEngine/RenderEngine.cpp ++++ b/services/surfaceflinger/RenderEngine/RenderEngine.cpp +@@ -262,9 +262,11 @@ void RenderEngine::dump(String8& result) { + // --------------------------------------------------------------------------- + + RenderEngine::BindImageAsFramebuffer::BindImageAsFramebuffer( +- RenderEngine& engine, EGLImageKHR image) : mEngine(engine) ++ RenderEngine& engine, EGLImageKHR image, bool useReadPixels, ++ int reqWidth, int reqHeight) : mEngine(engine), mUseReadPixels(useReadPixels) + { +- mEngine.bindImageAsFramebuffer(image, &mTexName, &mFbName, &mStatus); ++ mEngine.bindImageAsFramebuffer(image, &mTexName, &mFbName, &mStatus, ++ useReadPixels, reqWidth, reqHeight); + + ALOGE_IF(mStatus != GL_FRAMEBUFFER_COMPLETE_OES, + "glCheckFramebufferStatusOES error %d", mStatus); +@@ -272,7 +274,7 @@ RenderEngine::BindImageAsFramebuffer::BindImageAsFramebuffer( + + RenderEngine::BindImageAsFramebuffer::~BindImageAsFramebuffer() { + // back to main framebuffer +- mEngine.unbindFramebuffer(mTexName, mFbName); ++ mEngine.unbindFramebuffer(mTexName, mFbName, mUseReadPixels); + } + + status_t RenderEngine::BindImageAsFramebuffer::getStatus() const { +diff --git a/services/surfaceflinger/RenderEngine/RenderEngine.h b/services/surfaceflinger/RenderEngine/RenderEngine.h +index 0259881..5a5910a 100644 +--- a/services/surfaceflinger/RenderEngine/RenderEngine.h ++++ b/services/surfaceflinger/RenderEngine/RenderEngine.h +@@ -51,8 +51,8 @@ class RenderEngine { + EGLContext mEGLContext; + void setEGLHandles(EGLConfig config, EGLContext ctxt); + +- virtual void bindImageAsFramebuffer(EGLImageKHR image, uint32_t* texName, uint32_t* fbName, uint32_t* status) = 0; +- virtual void unbindFramebuffer(uint32_t texName, uint32_t fbName) = 0; ++ virtual void bindImageAsFramebuffer(EGLImageKHR image, uint32_t* texName, uint32_t* fbName, uint32_t* status, bool useReadPixels, int reqWidth, int reqHeight) = 0; ++ virtual void unbindFramebuffer(uint32_t texName, uint32_t fbName, bool useReadPixels) = 0; + + protected: + RenderEngine(); +@@ -85,8 +85,9 @@ public: + RenderEngine& mEngine; + uint32_t mTexName, mFbName; + uint32_t mStatus; ++ bool mUseReadPixels; + public: +- BindImageAsFramebuffer(RenderEngine& engine, EGLImageKHR image); ++ BindImageAsFramebuffer(RenderEngine& engine, EGLImageKHR image, bool useReadPixels, int reqWidth, int reqHeight); + ~BindImageAsFramebuffer(); + int getStatus() const; + }; +diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp +index 2a67f4c..bc99e66 100644 +--- a/services/surfaceflinger/SurfaceFlinger.cpp ++++ b/services/surfaceflinger/SurfaceFlinger.cpp +@@ -3418,7 +3418,8 @@ status_t SurfaceFlinger::captureScreen(const sp& display, + const sp& producer, + Rect sourceCrop, uint32_t reqWidth, uint32_t reqHeight, + uint32_t minLayerZ, uint32_t maxLayerZ, +- bool useIdentityTransform, ISurfaceComposer::Rotation rotation) { ++ bool useIdentityTransform, ISurfaceComposer::Rotation rotation, ++ bool useReadPixels) { + + if (CC_UNLIKELY(display == 0)) + return BAD_VALUE; +@@ -3462,6 +3463,7 @@ status_t SurfaceFlinger::captureScreen(const sp& display, + bool useIdentityTransform; + Transform::orientation_flags rotation; + status_t result; ++ bool useReadPixels; + bool isLocalScreenshot; + public: + MessageCaptureScreen(SurfaceFlinger* flinger, +@@ -3471,12 +3473,13 @@ status_t SurfaceFlinger::captureScreen(const sp& display, + uint32_t minLayerZ, uint32_t maxLayerZ, + bool useIdentityTransform, + Transform::orientation_flags rotation, +- bool isLocalScreenshot) ++ bool isLocalScreenshot, bool useReadPixels) + : flinger(flinger), display(display), producer(producer), + sourceCrop(sourceCrop), reqWidth(reqWidth), reqHeight(reqHeight), + minLayerZ(minLayerZ), maxLayerZ(maxLayerZ), + useIdentityTransform(useIdentityTransform), + rotation(rotation), result(PERMISSION_DENIED), ++ useReadPixels(useReadPixels), + isLocalScreenshot(isLocalScreenshot) + { + } +@@ -3486,9 +3489,10 @@ status_t SurfaceFlinger::captureScreen(const sp& display, + virtual bool handler() { + Mutex::Autolock _l(flinger->mStateLock); + sp hw(flinger->getDisplayDevice(display)); ++ bool useReadPixels = this->useReadPixels && !flinger->mGpuToCpuSupported; + result = flinger->captureScreenImplLocked(hw, producer, + sourceCrop, reqWidth, reqHeight, minLayerZ, maxLayerZ, +- useIdentityTransform, rotation, isLocalScreenshot); ++ useIdentityTransform, rotation, isLocalScreenshot, useReadPixels); + static_cast(IInterface::asBinder(producer).get())->exit(result); + return true; + } +@@ -3504,7 +3508,7 @@ status_t SurfaceFlinger::captureScreen(const sp& display, + sp msg = new MessageCaptureScreen(this, + display, IGraphicBufferProducer::asInterface( wrapper ), + sourceCrop, reqWidth, reqHeight, minLayerZ, maxLayerZ, +- useIdentityTransform, rotationFlags, isLocalScreenshot); ++ useIdentityTransform, rotationFlags, isLocalScreenshot, useReadPixels); + + status_t res = postMessageAsync(msg); + if (res == NO_ERROR) { +@@ -3587,7 +3591,7 @@ status_t SurfaceFlinger::captureScreenImplLocked( + Rect sourceCrop, uint32_t reqWidth, uint32_t reqHeight, + uint32_t minLayerZ, uint32_t maxLayerZ, + bool useIdentityTransform, Transform::orientation_flags rotation, +- bool isLocalScreenshot) ++ bool isLocalScreenshot, bool useReadPixels) + { + ATRACE_CALL(); + +@@ -3665,7 +3669,7 @@ status_t SurfaceFlinger::captureScreenImplLocked( + if (image != EGL_NO_IMAGE_KHR) { + // this binds the given EGLImage as a framebuffer for the + // duration of this scope. +- RenderEngine::BindImageAsFramebuffer imageBond(getRenderEngine(), image); ++ RenderEngine::BindImageAsFramebuffer imageBond(getRenderEngine(), image, useReadPixels, reqWidth, reqHeight); + if (imageBond.getStatus() == NO_ERROR) { + // this will in fact render into our dequeued buffer + // via an FBO, which means we didn't have to create +@@ -3712,6 +3716,16 @@ status_t SurfaceFlinger::captureScreenImplLocked( + ALOGW("captureScreen: error creating EGL fence: %#x", eglGetError()); + } + } ++ ++ if (useReadPixels) { ++ sp buf = static_cast(buffer); ++ void* vaddr; ++ if (buf->lock(GRALLOC_USAGE_SW_WRITE_OFTEN, &vaddr) == NO_ERROR) { ++ getRenderEngine().readPixels(0, 0, buffer->stride, reqHeight, (uint32_t *)vaddr); ++ buf->unlock(); ++ } ++ } ++ + if (DEBUG_SCREENSHOTS) { + uint32_t* pixels = new uint32_t[reqWidth*reqHeight]; + getRenderEngine().readPixels(0, 0, reqWidth, reqHeight, pixels); +diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h +index b98924b..2c3bd19 100644 +--- a/services/surfaceflinger/SurfaceFlinger.h ++++ b/services/surfaceflinger/SurfaceFlinger.h +@@ -218,7 +218,8 @@ private: + const sp& producer, + Rect sourceCrop, uint32_t reqWidth, uint32_t reqHeight, + uint32_t minLayerZ, uint32_t maxLayerZ, +- bool useIdentityTransform, ISurfaceComposer::Rotation rotation); ++ bool useIdentityTransform, ISurfaceComposer::Rotation rotation, ++ bool useReadPixels); + virtual status_t getDisplayStats(const sp& display, + DisplayStatInfo* stats); + virtual status_t getDisplayConfigs(const sp& display, +@@ -350,7 +351,7 @@ private: + Rect sourceCrop, uint32_t reqWidth, uint32_t reqHeight, + uint32_t minLayerZ, uint32_t maxLayerZ, + bool useIdentityTransform, Transform::orientation_flags rotation, +- bool isLocalScreenshot); ++ bool isLocalScreenshot, bool useReadPixels); + + /* ------------------------------------------------------------------------ + * EGL diff --git a/services/surfaceflinger/SurfaceFlinger_hwc1.cpp b/services/surfaceflinger/SurfaceFlinger_hwc1.cpp -index 650d6b4..2a5e07f 100644 +index 650d6b4..74fe9c8 100644 --- a/services/surfaceflinger/SurfaceFlinger_hwc1.cpp +++ b/services/surfaceflinger/SurfaceFlinger_hwc1.cpp @@ -466,13 +466,14 @@ void SurfaceFlinger::init() { @@ -22,3 +761,118 @@ index 650d6b4..2a5e07f 100644 // Initialize the H/W composer object. There may or may not be an // actual hardware composer underneath. mHwc = new HWComposer(this, +@@ -635,10 +636,21 @@ status_t SurfaceFlinger::getDisplayConfigs(const sp& display, + info.orientation = 0; + } + +- info.w = hwConfig.width; +- info.h = hwConfig.height; +- info.xdpi = xdpi; +- info.ydpi = ydpi; ++ char value[PROPERTY_VALUE_MAX]; ++ property_get("ro.sf.hwrotation", value, "0"); ++ int additionalRot = atoi(value) / 90; ++ if ((type == DisplayDevice::DISPLAY_PRIMARY) && (additionalRot & DisplayState::eOrientationSwapMask)) { ++ info.h = hwConfig.width; ++ info.w = hwConfig.height; ++ info.xdpi = ydpi; ++ info.ydpi = xdpi; ++ } ++ else { ++ info.w = hwConfig.width; ++ info.h = hwConfig.height; ++ info.xdpi = xdpi; ++ info.ydpi = ydpi; ++ } + info.fps = float(1e9 / hwConfig.refresh); + info.appVsyncOffset = VSYNC_EVENT_PHASE_OFFSET_NS; + +@@ -3331,7 +3343,8 @@ status_t SurfaceFlinger::captureScreen(const sp& display, + const sp& producer, + Rect sourceCrop, uint32_t reqWidth, uint32_t reqHeight, + uint32_t minLayerZ, uint32_t maxLayerZ, +- bool useIdentityTransform, ISurfaceComposer::Rotation rotation) { ++ bool useIdentityTransform, ISurfaceComposer::Rotation rotation, ++ bool useReadPixels) { + + if (CC_UNLIKELY(display == 0)) + return BAD_VALUE; +@@ -3375,6 +3388,7 @@ status_t SurfaceFlinger::captureScreen(const sp& display, + bool useIdentityTransform; + Transform::orientation_flags rotation; + status_t result; ++ bool useReadPixels; + bool isLocalScreenshot; + public: + MessageCaptureScreen(SurfaceFlinger* flinger, +@@ -3384,12 +3398,13 @@ status_t SurfaceFlinger::captureScreen(const sp& display, + uint32_t minLayerZ, uint32_t maxLayerZ, + bool useIdentityTransform, + Transform::orientation_flags rotation, +- bool isLocalScreenshot) ++ bool isLocalScreenshot, bool useReadPixels) + : flinger(flinger), display(display), producer(producer), + sourceCrop(sourceCrop), reqWidth(reqWidth), reqHeight(reqHeight), + minLayerZ(minLayerZ), maxLayerZ(maxLayerZ), + useIdentityTransform(useIdentityTransform), + rotation(rotation), result(PERMISSION_DENIED), ++ useReadPixels(useReadPixels), + isLocalScreenshot(isLocalScreenshot) + { + } +@@ -3399,9 +3414,10 @@ status_t SurfaceFlinger::captureScreen(const sp& display, + virtual bool handler() { + Mutex::Autolock _l(flinger->mStateLock); + sp hw(flinger->getDisplayDevice(display)); ++ bool useReadPixels = this->useReadPixels && !flinger->mGpuToCpuSupported; + result = flinger->captureScreenImplLocked(hw, producer, + sourceCrop, reqWidth, reqHeight, minLayerZ, maxLayerZ, +- useIdentityTransform, rotation, isLocalScreenshot); ++ useIdentityTransform, rotation, isLocalScreenshot, useReadPixels); + static_cast(IInterface::asBinder(producer).get())->exit(result); + return true; + } +@@ -3417,7 +3433,7 @@ status_t SurfaceFlinger::captureScreen(const sp& display, + sp msg = new MessageCaptureScreen(this, + display, IGraphicBufferProducer::asInterface( wrapper ), + sourceCrop, reqWidth, reqHeight, minLayerZ, maxLayerZ, +- useIdentityTransform, rotationFlags, isLocalScreenshot); ++ useIdentityTransform, rotationFlags, isLocalScreenshot, useReadPixels); + + status_t res = postMessageAsync(msg); + if (res == NO_ERROR) { +@@ -3502,7 +3518,7 @@ status_t SurfaceFlinger::captureScreenImplLocked( + Rect sourceCrop, uint32_t reqWidth, uint32_t reqHeight, + uint32_t minLayerZ, uint32_t maxLayerZ, + bool useIdentityTransform, Transform::orientation_flags rotation, +- bool isLocalScreenshot) ++ bool isLocalScreenshot, bool useReadPixels) + { + ATRACE_CALL(); + +@@ -3572,7 +3588,7 @@ status_t SurfaceFlinger::captureScreenImplLocked( + if (image != EGL_NO_IMAGE_KHR) { + // this binds the given EGLImage as a framebuffer for the + // duration of this scope. +- RenderEngine::BindImageAsFramebuffer imageBond(getRenderEngine(), image); ++ RenderEngine::BindImageAsFramebuffer imageBond(getRenderEngine(), image, useReadPixels, reqWidth, reqHeight); + if (imageBond.getStatus() == NO_ERROR) { + // this will in fact render into our dequeued buffer + // via an FBO, which means we didn't have to create +@@ -3619,6 +3635,16 @@ status_t SurfaceFlinger::captureScreenImplLocked( + ALOGW("captureScreen: error creating EGL fence: %#x", eglGetError()); + } + } ++ ++ if (useReadPixels) { ++ sp buf = static_cast(buffer); ++ void* vaddr; ++ if (buf->lock(GRALLOC_USAGE_SW_WRITE_OFTEN, &vaddr) == NO_ERROR) { ++ getRenderEngine().readPixels(0, 0, buffer->stride, reqHeight, (uint32_t *)vaddr); ++ buf->unlock(); ++ } ++ } ++ + if (DEBUG_SCREENSHOTS) { + uint32_t* pixels = new uint32_t[reqWidth*reqHeight]; + getRenderEngine().readPixels(0, 0, reqWidth, reqHeight, pixels); diff --git a/hardware_ril.patch b/hardware_ril.patch index 951db3c..4b5d125 100644 --- a/hardware_ril.patch +++ b/hardware_ril.patch @@ -1,8 +1,8 @@ diff --git a/libril/ril.cpp b/libril/ril.cpp -index e1d30ea..ce9c7a7 100755 +index d7744c0..561ba55 100644 --- a/libril/ril.cpp +++ b/libril/ril.cpp -@@ -3702,6 +3702,7 @@ static void responseSimStatusV5(Parcel &p, void *response) { +@@ -3804,6 +3804,7 @@ static void responseSimStatusV5(Parcel &p, void *response) { p.writeInt32(p_cur->universal_pin_state); p.writeInt32(p_cur->gsm_umts_subscription_app_index); p.writeInt32(p_cur->cdma_subscription_app_index); From 638f8d2b2812ddbbb1c3ac8e4dd3ffd37cbdb096 Mon Sep 17 00:00:00 2001 From: Arseniy Graur Date: Fri, 2 Dec 2016 14:18:37 +0300 Subject: [PATCH 048/159] README.md: fix a mistake, which failing build further! --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 149eaf7..c92c3dd 100644 --- a/README.md +++ b/README.md @@ -50,7 +50,7 @@ patch -p 1 < ../../.repo/manifests/system_core.patch cd ../.. -cd system/core +cd system/sepolicy patch -p 1 < ../../.repo/manifests/system_sepolicy.patch From e0838a2860275505f80f8ba60080578327cdede4 Mon Sep 17 00:00:00 2001 From: Arseniy Graur Date: Sat, 3 Dec 2016 12:24:15 +0200 Subject: [PATCH 049/159] README.md Make instruction beginner friendly! Fix a mistake again --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index c92c3dd..caf30e2 100644 --- a/README.md +++ b/README.md @@ -38,7 +38,7 @@ patch -p 1 < ../../.repo/manifests/hardware_ril.patch cd ../.. -cd packages/aps/Music +cd packages/apps/Music patch -p 1 < ../../../.repo/manifests/packages_apps_music.patch From 8193df35a8950988d84a4c66ece991568c49a3e8 Mon Sep 17 00:00:00 2001 From: AndDiSa Date: Sun, 4 Dec 2016 18:56:35 +0100 Subject: [PATCH 050/159] update patches Change-Id: I95031dd0eba84bdfeb3e001662ec6931f1f585cb --- frameworks_av.patch | 2082 ++++++++++++++++++++++++++++++++++++- frameworks_base.patch | 321 ++++++ packages_apps_music.patch | 17 +- 3 files changed, 2411 insertions(+), 9 deletions(-) diff --git a/frameworks_av.patch b/frameworks_av.patch index 8e9c84f..ffd0e0f 100644 --- a/frameworks_av.patch +++ b/frameworks_av.patch @@ -240,10 +240,10 @@ index 15ff569..0e9b4e6 100644 (*buffer)->setObserver(this); (*buffer)->add_ref(); diff --git a/media/libstagefright/foundation/MediaBufferGroup.cpp b/media/libstagefright/foundation/MediaBufferGroup.cpp -index cb78879..055ac4b 100644 +index cb78879..ecd9cf9 100644 --- a/media/libstagefright/foundation/MediaBufferGroup.cpp +++ b/media/libstagefright/foundation/MediaBufferGroup.cpp -@@ -188,6 +188,16 @@ status_t MediaBufferGroup::acquire_buffer( +@@ -188,8 +188,23 @@ status_t MediaBufferGroup::acquire_buffer( // Never gets here. } @@ -260,14 +260,27 @@ index cb78879..055ac4b 100644 void MediaBufferGroup::signalBufferReturned(MediaBuffer *) { mCondition.signal(); } + ++/* MediaBufferGroup::MediaBufferGroup */ ++extern "C" int _ZN7android16MediaBufferGroupC1Ej(unsigned int); ++extern "C" int _ZN7android16MediaBufferGroupC1Ev() { ++ return _ZN7android16MediaBufferGroupC1Ej(0); ++} + } // namespace android diff --git a/media/libstagefright/omx/Android.mk b/media/libstagefright/omx/Android.mk -index e4fbd81..8fc788f 100644 +index e4fbd81..c262782 100644 --- a/media/libstagefright/omx/Android.mk +++ b/media/libstagefright/omx/Android.mk -@@ -31,6 +31,12 @@ LOCAL_SHARED_LIBRARIES := \ +@@ -31,6 +31,18 @@ LOCAL_SHARED_LIBRARIES := \ libstagefright_foundation \ libdl ++ifneq ($(TARGET_USES_MEDIA_EXTENSIONS),true) ++ifeq ($(TARGET_HAS_LEGACY_CAMERA_HAL1),true) ++LOCAL_CFLAGS += -DCAMCORDER_GRALLOC_SOURCE ++endif ++endif ++ +ifneq ($(TARGET_USES_MEDIA_EXTENSIONS),true) +ifeq ($(TARGET_HAS_LEGACY_CAMERA_HAL1),true) +LOCAL_CFLAGS += -DCAMCORDER_GRALLOC_SOURCE @@ -290,10 +303,22 @@ index 6132a2c..7f0d270 100644 void OMXMaster::addPlugin(const char *libname) { diff --git a/media/libstagefright/omx/OMXNodeInstance.cpp b/media/libstagefright/omx/OMXNodeInstance.cpp -index 395dad8..c570603 100644 +index 395dad8..c6e3a38 100644 --- a/media/libstagefright/omx/OMXNodeInstance.cpp +++ b/media/libstagefright/omx/OMXNodeInstance.cpp -@@ -1286,7 +1286,11 @@ status_t OMXNodeInstance::allocateBufferWithBackup( +@@ -795,7 +795,11 @@ status_t OMXNodeInstance::useBuffer( + // metadata buffers are not connected cross process + // use a backup buffer instead of the actual buffer + BufferMeta *buffer_meta; ++#ifdef CAMCORDER_GRALLOC_SOURCE ++ bool useBackup = false; ++#else + bool useBackup = mMetadataType[portIndex] != kMetadataBufferTypeInvalid; ++#endif + OMX_U8 *data = static_cast(params->pointer()); + // allocate backup buffer + if (useBackup) { +@@ -1286,7 +1290,11 @@ status_t OMXNodeInstance::allocateBufferWithBackup( } // metadata buffers are not connected cross process; only copy if not meta @@ -305,7 +330,7 @@ index 395dad8..c570603 100644 BufferMeta *buffer_meta = new BufferMeta( params, portIndex, -@@ -1404,10 +1408,30 @@ status_t OMXNodeInstance::emptyBuffer( +@@ -1404,10 +1412,30 @@ status_t OMXNodeInstance::emptyBuffer( BufferMeta *buffer_meta = static_cast(header->pAppPrivate); @@ -336,6 +361,2049 @@ index 395dad8..c570603 100644 header->nOffset = 0; } else { // rangeLength and rangeOffset must be a subset of the allocated data in the buffer. +diff --git a/media/libstagefright/omx/OMXNodeInstance.cpp.orig b/media/libstagefright/omx/OMXNodeInstance.cpp.orig +new file mode 100644 +index 0000000..c570603 +--- /dev/null ++++ b/media/libstagefright/omx/OMXNodeInstance.cpp.orig +@@ -0,0 +1,2037 @@ ++/* ++ * Copyright (C) 2009 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. ++ */ ++ ++//#define LOG_NDEBUG 0 ++#define LOG_TAG "OMXNodeInstance" ++#include ++ ++#include ++ ++#include "../include/OMXNodeInstance.h" ++#include "OMXMaster.h" ++#include "OMXUtils.h" ++#include "GraphicBufferSource.h" ++ ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++static const OMX_U32 kPortIndexInput = 0; ++static const OMX_U32 kPortIndexOutput = 1; ++ ++#define CLOGW(fmt, ...) ALOGW("[%x:%s] " fmt, mNodeID, mName, ##__VA_ARGS__) ++ ++#define CLOG_ERROR_IF(cond, fn, err, fmt, ...) \ ++ ALOGE_IF(cond, #fn "(%x:%s, " fmt ") ERROR: %s(%#x)", \ ++ mNodeID, mName, ##__VA_ARGS__, asString(err), err) ++#define CLOG_ERROR(fn, err, fmt, ...) CLOG_ERROR_IF(true, fn, err, fmt, ##__VA_ARGS__) ++#define CLOG_IF_ERROR(fn, err, fmt, ...) \ ++ CLOG_ERROR_IF((err) != OMX_ErrorNone, fn, err, fmt, ##__VA_ARGS__) ++ ++#define CLOGI_(level, fn, fmt, ...) \ ++ ALOGI_IF(DEBUG >= (level), #fn "(%x:%s, " fmt ")", mNodeID, mName, ##__VA_ARGS__) ++#define CLOGD_(level, fn, fmt, ...) \ ++ ALOGD_IF(DEBUG >= (level), #fn "(%x:%s, " fmt ")", mNodeID, mName, ##__VA_ARGS__) ++ ++#define CLOG_LIFE(fn, fmt, ...) CLOGI_(ADebug::kDebugLifeCycle, fn, fmt, ##__VA_ARGS__) ++#define CLOG_STATE(fn, fmt, ...) CLOGI_(ADebug::kDebugState, fn, fmt, ##__VA_ARGS__) ++#define CLOG_CONFIG(fn, fmt, ...) CLOGI_(ADebug::kDebugConfig, fn, fmt, ##__VA_ARGS__) ++#define CLOG_INTERNAL(fn, fmt, ...) CLOGD_(ADebug::kDebugInternalState, fn, fmt, ##__VA_ARGS__) ++ ++#define CLOG_DEBUG_IF(cond, fn, fmt, ...) \ ++ ALOGD_IF(cond, #fn "(%x, " fmt ")", mNodeID, ##__VA_ARGS__) ++ ++#define CLOG_BUFFER(fn, fmt, ...) \ ++ CLOG_DEBUG_IF(DEBUG >= ADebug::kDebugAll, fn, fmt, ##__VA_ARGS__) ++#define CLOG_BUMPED_BUFFER(fn, fmt, ...) \ ++ CLOG_DEBUG_IF(DEBUG_BUMP >= ADebug::kDebugAll, fn, fmt, ##__VA_ARGS__) ++ ++/* buffer formatting */ ++#define BUFFER_FMT(port, fmt, ...) "%s:%u " fmt, portString(port), (port), ##__VA_ARGS__ ++#define NEW_BUFFER_FMT(buffer_id, port, fmt, ...) \ ++ BUFFER_FMT(port, fmt ") (#%zu => %#x", ##__VA_ARGS__, mActiveBuffers.size(), (buffer_id)) ++ ++#define SIMPLE_BUFFER(port, size, data) BUFFER_FMT(port, "%zu@%p", (size), (data)) ++#define SIMPLE_NEW_BUFFER(buffer_id, port, size, data) \ ++ NEW_BUFFER_FMT(buffer_id, port, "%zu@%p", (size), (data)) ++ ++#define EMPTY_BUFFER(addr, header, fenceFd) "%#x [%u@%p fc=%d]", \ ++ (addr), (header)->nAllocLen, (header)->pBuffer, (fenceFd) ++#define FULL_BUFFER(addr, header, fenceFd) "%#" PRIxPTR " [%u@%p (%u..+%u) f=%x ts=%lld fc=%d]", \ ++ (intptr_t)(addr), (header)->nAllocLen, (header)->pBuffer, \ ++ (header)->nOffset, (header)->nFilledLen, (header)->nFlags, (header)->nTimeStamp, (fenceFd) ++ ++#define WITH_STATS_WRAPPER(fmt, ...) fmt " { IN=%zu/%zu OUT=%zu/%zu }", ##__VA_ARGS__, \ ++ mInputBuffersWithCodec.size(), mNumPortBuffers[kPortIndexInput], \ ++ mOutputBuffersWithCodec.size(), mNumPortBuffers[kPortIndexOutput] ++// TRICKY: this is needed so formatting macros expand before substitution ++#define WITH_STATS(fmt, ...) WITH_STATS_WRAPPER(fmt, ##__VA_ARGS__) ++ ++namespace android { ++ ++struct BufferMeta { ++ BufferMeta( ++ const sp &mem, OMX_U32 portIndex, bool copyToOmx, ++ bool copyFromOmx, OMX_U8 *backup) ++ : mMem(mem), ++ mCopyFromOmx(copyFromOmx), ++ mCopyToOmx(copyToOmx), ++ mPortIndex(portIndex), ++ mBackup(backup) { ++ } ++ ++ BufferMeta(size_t size, OMX_U32 portIndex) ++ : mSize(size), ++ mCopyFromOmx(false), ++ mCopyToOmx(false), ++ mPortIndex(portIndex), ++ mBackup(NULL) { ++ } ++ ++ BufferMeta(const sp &graphicBuffer, OMX_U32 portIndex) ++ : mGraphicBuffer(graphicBuffer), ++ mCopyFromOmx(false), ++ mCopyToOmx(false), ++ mPortIndex(portIndex), ++ mBackup(NULL) { ++ } ++ ++ void CopyFromOMX(const OMX_BUFFERHEADERTYPE *header) { ++ if (!mCopyFromOmx) { ++ return; ++ } ++ ++ // check component returns proper range ++ sp codec = getBuffer(header, false /* backup */, true /* limit */); ++ ++ memcpy((OMX_U8 *)mMem->pointer() + header->nOffset, codec->data(), codec->size()); ++ } ++ ++ void CopyToOMX(const OMX_BUFFERHEADERTYPE *header) { ++ if (!mCopyToOmx) { ++ return; ++ } ++ ++ memcpy(header->pBuffer + header->nOffset, ++ (const OMX_U8 *)mMem->pointer() + header->nOffset, ++ header->nFilledLen); ++ } ++ ++ // return either the codec or the backup buffer ++ sp getBuffer(const OMX_BUFFERHEADERTYPE *header, bool backup, bool limit) { ++ sp buf; ++ if (backup && mMem != NULL) { ++ buf = new ABuffer(mMem->pointer(), mMem->size()); ++ } else { ++ buf = new ABuffer(header->pBuffer, header->nAllocLen); ++ } ++ if (limit) { ++ if (header->nOffset + header->nFilledLen > header->nOffset ++ && header->nOffset + header->nFilledLen <= header->nAllocLen) { ++ buf->setRange(header->nOffset, header->nFilledLen); ++ } else { ++ buf->setRange(0, 0); ++ } ++ } ++ return buf; ++ } ++ ++ void setGraphicBuffer(const sp &graphicBuffer) { ++ mGraphicBuffer = graphicBuffer; ++ } ++ ++ void setNativeHandle(const sp &nativeHandle) { ++ mNativeHandle = nativeHandle; ++ } ++ ++ OMX_U32 getPortIndex() { ++ return mPortIndex; ++ } ++ ++ ~BufferMeta() { ++ delete[] mBackup; ++ } ++ ++private: ++ sp mGraphicBuffer; ++ sp mNativeHandle; ++ sp mMem; ++ size_t mSize; ++ bool mCopyFromOmx; ++ bool mCopyToOmx; ++ OMX_U32 mPortIndex; ++ OMX_U8 *mBackup; ++ ++ BufferMeta(const BufferMeta &); ++ BufferMeta &operator=(const BufferMeta &); ++}; ++ ++// static ++OMX_CALLBACKTYPE OMXNodeInstance::kCallbacks = { ++ &OnEvent, &OnEmptyBufferDone, &OnFillBufferDone ++}; ++ ++static inline const char *portString(OMX_U32 portIndex) { ++ switch (portIndex) { ++ case kPortIndexInput: return "Input"; ++ case kPortIndexOutput: return "Output"; ++ case ~0U: return "All"; ++ default: return "port"; ++ } ++} ++ ++OMXNodeInstance::OMXNodeInstance( ++ OMX *owner, const sp &observer, const char *name) ++ : mOwner(owner), ++ mNodeID(0), ++ mHandle(NULL), ++ mObserver(observer), ++ mDying(false), ++ mSailed(false), ++ mQueriedProhibitedExtensions(false), ++ mBufferIDCount(0) ++{ ++ mName = ADebug::GetDebugName(name); ++ DEBUG = ADebug::GetDebugLevelFromProperty(name, "debug.stagefright.omx-debug"); ++ ALOGV("debug level for %s is %d", name, DEBUG); ++ DEBUG_BUMP = DEBUG; ++ mNumPortBuffers[0] = 0; ++ mNumPortBuffers[1] = 0; ++ mDebugLevelBumpPendingBuffers[0] = 0; ++ mDebugLevelBumpPendingBuffers[1] = 0; ++ mMetadataType[0] = kMetadataBufferTypeInvalid; ++ mMetadataType[1] = kMetadataBufferTypeInvalid; ++ mSecureBufferType[0] = kSecureBufferTypeUnknown; ++ mSecureBufferType[1] = kSecureBufferTypeUnknown; ++ mIsSecure = AString(name).endsWith(".secure"); ++} ++ ++OMXNodeInstance::~OMXNodeInstance() { ++ free(mName); ++ CHECK(mHandle == NULL); ++} ++ ++void OMXNodeInstance::setHandle(OMX::node_id node_id, OMX_HANDLETYPE handle) { ++ mNodeID = node_id; ++ CLOG_LIFE(allocateNode, "handle=%p", handle); ++ CHECK(mHandle == NULL); ++ mHandle = handle; ++} ++ ++sp OMXNodeInstance::getGraphicBufferSource() { ++ Mutex::Autolock autoLock(mGraphicBufferSourceLock); ++ return mGraphicBufferSource; ++} ++ ++void OMXNodeInstance::setGraphicBufferSource( ++ const sp& bufferSource) { ++ Mutex::Autolock autoLock(mGraphicBufferSourceLock); ++ CLOG_INTERNAL(setGraphicBufferSource, "%p", bufferSource.get()); ++ mGraphicBufferSource = bufferSource; ++} ++ ++OMX *OMXNodeInstance::owner() { ++ return mOwner; ++} ++ ++sp OMXNodeInstance::observer() { ++ return mObserver; ++} ++ ++OMX::node_id OMXNodeInstance::nodeID() { ++ return mNodeID; ++} ++ ++status_t OMXNodeInstance::freeNode(OMXMaster *master) { ++ CLOG_LIFE(freeNode, "handle=%p", mHandle); ++ static int32_t kMaxNumIterations = 10; ++ ++ // exit if we have already freed the node ++ if (mHandle == NULL) { ++ return OK; ++ } ++ ++ // Transition the node from its current state all the way down ++ // to "Loaded". ++ // This ensures that all active buffers are properly freed even ++ // for components that don't do this themselves on a call to ++ // "FreeHandle". ++ ++ // The code below may trigger some more events to be dispatched ++ // by the OMX component - we want to ignore them as our client ++ // does not expect them. ++ mDying = true; ++ ++ OMX_STATETYPE state; ++ CHECK_EQ(OMX_GetState(mHandle, &state), OMX_ErrorNone); ++ switch (state) { ++ case OMX_StateExecuting: ++ { ++ ALOGV("forcing Executing->Idle"); ++ sendCommand(OMX_CommandStateSet, OMX_StateIdle); ++ OMX_ERRORTYPE err; ++ int32_t iteration = 0; ++ while ((err = OMX_GetState(mHandle, &state)) == OMX_ErrorNone ++ && state != OMX_StateIdle ++ && state != OMX_StateInvalid) { ++ if (++iteration > kMaxNumIterations) { ++ CLOGW("failed to enter Idle state (now %s(%d), aborting.", ++ asString(state), state); ++ state = OMX_StateInvalid; ++ break; ++ } ++ ++ usleep(100000); ++ } ++ CHECK_EQ(err, OMX_ErrorNone); ++ ++ if (state == OMX_StateInvalid) { ++ break; ++ } ++ ++ // fall through ++ } ++ ++ case OMX_StateIdle: ++ { ++ ALOGV("forcing Idle->Loaded"); ++ sendCommand(OMX_CommandStateSet, OMX_StateLoaded); ++ ++ freeActiveBuffers(); ++ ++ OMX_ERRORTYPE err; ++ int32_t iteration = 0; ++ while ((err = OMX_GetState(mHandle, &state)) == OMX_ErrorNone ++ && state != OMX_StateLoaded ++ && state != OMX_StateInvalid) { ++ if (++iteration > kMaxNumIterations) { ++ CLOGW("failed to enter Loaded state (now %s(%d), aborting.", ++ asString(state), state); ++ state = OMX_StateInvalid; ++ break; ++ } ++ ++ ALOGV("waiting for Loaded state..."); ++ usleep(100000); ++ } ++ CHECK_EQ(err, OMX_ErrorNone); ++ ++ // fall through ++ } ++ ++ case OMX_StateLoaded: ++ case OMX_StateInvalid: ++ break; ++ ++ default: ++ LOG_ALWAYS_FATAL("unknown state %s(%#x).", asString(state), state); ++ break; ++ } ++ ++ ALOGV("[%x:%s] calling destroyComponentInstance", mNodeID, mName); ++ OMX_ERRORTYPE err = master->destroyComponentInstance( ++ static_cast(mHandle)); ++ ++ mHandle = NULL; ++ CLOG_IF_ERROR(freeNode, err, ""); ++ free(mName); ++ mName = NULL; ++ ++ mOwner->invalidateNodeID(mNodeID); ++ mNodeID = 0; ++ ++ ALOGV("OMXNodeInstance going away."); ++ delete this; ++ ++ return StatusFromOMXError(err); ++} ++ ++status_t OMXNodeInstance::sendCommand( ++ OMX_COMMANDTYPE cmd, OMX_S32 param) { ++ if (cmd == OMX_CommandStateSet) { ++ // There are no configurations past first StateSet command. ++ mSailed = true; ++ } ++ const sp bufferSource(getGraphicBufferSource()); ++ if (bufferSource != NULL && cmd == OMX_CommandStateSet) { ++ if (param == OMX_StateIdle) { ++ // Initiating transition from Executing -> Idle ++ // ACodec is waiting for all buffers to be returned, do NOT ++ // submit any more buffers to the codec. ++ bufferSource->omxIdle(); ++ } else if (param == OMX_StateLoaded) { ++ // Initiating transition from Idle/Executing -> Loaded ++ // Buffers are about to be freed. ++ bufferSource->omxLoaded(); ++ setGraphicBufferSource(NULL); ++ } ++ ++ // fall through ++ } ++ ++ Mutex::Autolock autoLock(mLock); ++ ++ // bump internal-state debug level for 2 input and output frames past a command ++ { ++ Mutex::Autolock _l(mDebugLock); ++ bumpDebugLevel_l(2 /* numInputBuffers */, 2 /* numOutputBuffers */); ++ } ++ ++ const char *paramString = ++ cmd == OMX_CommandStateSet ? asString((OMX_STATETYPE)param) : portString(param); ++ CLOG_STATE(sendCommand, "%s(%d), %s(%d)", asString(cmd), cmd, paramString, param); ++ OMX_ERRORTYPE err = OMX_SendCommand(mHandle, cmd, param, NULL); ++ CLOG_IF_ERROR(sendCommand, err, "%s(%d), %s(%d)", asString(cmd), cmd, paramString, param); ++ return StatusFromOMXError(err); ++} ++ ++bool OMXNodeInstance::isProhibitedIndex_l(OMX_INDEXTYPE index) { ++ // these extensions can only be used from OMXNodeInstance, not by clients directly. ++ static const char *restricted_extensions[] = { ++ "OMX.google.android.index.storeMetaDataInBuffers", ++ "OMX.google.android.index.storeANWBufferInMetadata", ++ "OMX.google.android.index.prepareForAdaptivePlayback", ++ "OMX.google.android.index.configureVideoTunnelMode", ++ "OMX.google.android.index.useAndroidNativeBuffer2", ++ "OMX.google.android.index.useAndroidNativeBuffer", ++ "OMX.google.android.index.enableAndroidNativeBuffers", ++ "OMX.google.android.index.allocateNativeHandle", ++ "OMX.google.android.index.getAndroidNativeBufferUsage", ++ }; ++ ++ if ((index > OMX_IndexComponentStartUnused && index <= OMX_IndexParamStandardComponentRole) ++ || (index > OMX_IndexPortStartUnused && index <= OMX_IndexParamCompBufferSupplier) ++ || (index > OMX_IndexAudioStartUnused && index <= OMX_IndexConfigAudioChannelVolume) ++ || (index > OMX_IndexVideoStartUnused && index <= OMX_IndexConfigVideoNalSize) ++ || (index > OMX_IndexCommonStartUnused ++ && index <= OMX_IndexConfigCommonTransitionEffect) ++ || (index > (OMX_INDEXTYPE)OMX_IndexExtAudioStartUnused ++ && index <= (OMX_INDEXTYPE)OMX_IndexParamAudioProfileQuerySupported) ++ || (index > (OMX_INDEXTYPE)OMX_IndexExtVideoStartUnused ++ && index <= (OMX_INDEXTYPE)OMX_IndexConfigAndroidIntraRefresh) ++ || (index > (OMX_INDEXTYPE)OMX_IndexExtOtherStartUnused ++ && index <= (OMX_INDEXTYPE)OMX_IndexParamConsumerUsageBits)) { ++ return false; ++ } ++ ++ if (!mQueriedProhibitedExtensions) { ++ for (size_t i = 0; i < NELEM(restricted_extensions); ++i) { ++ OMX_INDEXTYPE ext; ++ if (OMX_GetExtensionIndex(mHandle, (OMX_STRING)restricted_extensions[i], &ext) == OMX_ErrorNone) { ++ mProhibitedExtensions.add(ext); ++ } ++ } ++ mQueriedProhibitedExtensions = true; ++ } ++ ++ return mProhibitedExtensions.indexOf(index) >= 0; ++} ++ ++status_t OMXNodeInstance::getParameter( ++ OMX_INDEXTYPE index, void *params, size_t /* size */) { ++ Mutex::Autolock autoLock(mLock); ++ ++ if (isProhibitedIndex_l(index)) { ++ android_errorWriteLog(0x534e4554, "29422020"); ++ return BAD_INDEX; ++ } ++ ++ OMX_ERRORTYPE err = OMX_GetParameter(mHandle, index, params); ++ OMX_INDEXEXTTYPE extIndex = (OMX_INDEXEXTTYPE)index; ++ // some errors are expected for getParameter ++ if (err != OMX_ErrorNoMore) { ++ CLOG_IF_ERROR(getParameter, err, "%s(%#x)", asString(extIndex), index); ++ } ++ return StatusFromOMXError(err); ++} ++ ++status_t OMXNodeInstance::setParameter( ++ OMX_INDEXTYPE index, const void *params, size_t size) { ++ Mutex::Autolock autoLock(mLock); ++ OMX_INDEXEXTTYPE extIndex = (OMX_INDEXEXTTYPE)index; ++ CLOG_CONFIG(setParameter, "%s(%#x), %zu@%p)", asString(extIndex), index, size, params); ++ ++ if (isProhibitedIndex_l(index)) { ++ android_errorWriteLog(0x534e4554, "29422020"); ++ return BAD_INDEX; ++ } ++ ++ OMX_ERRORTYPE err = OMX_SetParameter( ++ mHandle, index, const_cast(params)); ++ CLOG_IF_ERROR(setParameter, err, "%s(%#x)", asString(extIndex), index); ++ return StatusFromOMXError(err); ++} ++ ++status_t OMXNodeInstance::getConfig( ++ OMX_INDEXTYPE index, void *params, size_t /* size */) { ++ Mutex::Autolock autoLock(mLock); ++ ++ if (isProhibitedIndex_l(index)) { ++ android_errorWriteLog(0x534e4554, "29422020"); ++ return BAD_INDEX; ++ } ++ ++ OMX_ERRORTYPE err = OMX_GetConfig(mHandle, index, params); ++ OMX_INDEXEXTTYPE extIndex = (OMX_INDEXEXTTYPE)index; ++ // some errors are expected for getConfig ++ if (err != OMX_ErrorNoMore) { ++ CLOG_IF_ERROR(getConfig, err, "%s(%#x)", asString(extIndex), index); ++ } ++ return StatusFromOMXError(err); ++} ++ ++status_t OMXNodeInstance::setConfig( ++ OMX_INDEXTYPE index, const void *params, size_t size) { ++ Mutex::Autolock autoLock(mLock); ++ OMX_INDEXEXTTYPE extIndex = (OMX_INDEXEXTTYPE)index; ++ CLOG_CONFIG(setConfig, "%s(%#x), %zu@%p)", asString(extIndex), index, size, params); ++ ++ if (isProhibitedIndex_l(index)) { ++ android_errorWriteLog(0x534e4554, "29422020"); ++ return BAD_INDEX; ++ } ++ ++ OMX_ERRORTYPE err = OMX_SetConfig( ++ mHandle, index, const_cast(params)); ++ CLOG_IF_ERROR(setConfig, err, "%s(%#x)", asString(extIndex), index); ++ return StatusFromOMXError(err); ++} ++ ++status_t OMXNodeInstance::getState(OMX_STATETYPE* state) { ++ Mutex::Autolock autoLock(mLock); ++ ++ OMX_ERRORTYPE err = OMX_GetState(mHandle, state); ++ CLOG_IF_ERROR(getState, err, ""); ++ return StatusFromOMXError(err); ++} ++ ++status_t OMXNodeInstance::enableNativeBuffers( ++ OMX_U32 portIndex, OMX_BOOL graphic, OMX_BOOL enable) { ++ if (portIndex >= NELEM(mSecureBufferType)) { ++ ALOGE("b/31385713, portIndex(%u)", portIndex); ++ android_errorWriteLog(0x534e4554, "31385713"); ++ return BAD_VALUE; ++ } ++ ++ Mutex::Autolock autoLock(mLock); ++ CLOG_CONFIG(enableNativeBuffers, "%s:%u%s, %d", portString(portIndex), portIndex, ++ graphic ? ", graphic" : "", enable); ++ OMX_STRING name = const_cast( ++ graphic ? "OMX.google.android.index.enableAndroidNativeBuffers" ++ : "OMX.google.android.index.allocateNativeHandle"); ++ ++ OMX_INDEXTYPE index; ++ OMX_ERRORTYPE err = OMX_GetExtensionIndex(mHandle, name, &index); ++ ++ if (err == OMX_ErrorNone) { ++ EnableAndroidNativeBuffersParams params; ++ InitOMXParams(¶ms); ++ params.nPortIndex = portIndex; ++ params.enable = enable; ++ ++ err = OMX_SetParameter(mHandle, index, ¶ms); ++ CLOG_IF_ERROR(setParameter, err, "%s(%#x): %s:%u en=%d", name, index, ++ portString(portIndex), portIndex, enable); ++ if (!graphic) { ++ if (err == OMX_ErrorNone) { ++ mSecureBufferType[portIndex] = ++ enable ? kSecureBufferTypeNativeHandle : kSecureBufferTypeOpaque; ++ } else if (mSecureBufferType[portIndex] == kSecureBufferTypeUnknown) { ++ mSecureBufferType[portIndex] = kSecureBufferTypeOpaque; ++ } ++ } ++ } else { ++ CLOG_ERROR_IF(enable, getExtensionIndex, err, "%s", name); ++ if (!graphic) { ++ // Extension not supported, check for manual override with system property ++ // This is a temporary workaround until partners support the OMX extension ++ char value[PROPERTY_VALUE_MAX]; ++ if (property_get("media.mediadrmservice.enable", value, NULL) ++ && (!strcmp("1", value) || !strcasecmp("true", value))) { ++ CLOG_CONFIG(enableNativeBuffers, "system property override: using native-handles"); ++ mSecureBufferType[portIndex] = kSecureBufferTypeNativeHandle; ++ } else if (mSecureBufferType[portIndex] == kSecureBufferTypeUnknown) { ++ mSecureBufferType[portIndex] = kSecureBufferTypeOpaque; ++ } ++ err = OMX_ErrorNone; ++ } ++ } ++ ++ return StatusFromOMXError(err); ++} ++ ++status_t OMXNodeInstance::getGraphicBufferUsage( ++ OMX_U32 portIndex, OMX_U32* usage) { ++ Mutex::Autolock autoLock(mLock); ++ ++ OMX_INDEXTYPE index; ++ OMX_STRING name = const_cast( ++ "OMX.google.android.index.getAndroidNativeBufferUsage"); ++ OMX_ERRORTYPE err = OMX_GetExtensionIndex(mHandle, name, &index); ++ ++ if (err != OMX_ErrorNone) { ++ CLOG_ERROR(getExtensionIndex, err, "%s", name); ++ return StatusFromOMXError(err); ++ } ++ ++ GetAndroidNativeBufferUsageParams params; ++ InitOMXParams(¶ms); ++ params.nPortIndex = portIndex; ++ ++ err = OMX_GetParameter(mHandle, index, ¶ms); ++ if (err != OMX_ErrorNone) { ++ CLOG_ERROR(getParameter, err, "%s(%#x): %s:%u", name, index, ++ portString(portIndex), portIndex); ++ return StatusFromOMXError(err); ++ } ++ ++ *usage = params.nUsage; ++ ++ return OK; ++} ++ ++status_t OMXNodeInstance::storeMetaDataInBuffers( ++ OMX_U32 portIndex, OMX_BOOL enable, MetadataBufferType *type) { ++ Mutex::Autolock autolock(mLock); ++ CLOG_CONFIG(storeMetaDataInBuffers, "%s:%u en:%d", portString(portIndex), portIndex, enable); ++ return storeMetaDataInBuffers_l(portIndex, enable, type); ++} ++ ++status_t OMXNodeInstance::storeMetaDataInBuffers_l( ++ OMX_U32 portIndex, OMX_BOOL enable, MetadataBufferType *type) { ++ if (mSailed) { ++ android_errorWriteLog(0x534e4554, "29422020"); ++ return INVALID_OPERATION; ++ } ++ if (portIndex != kPortIndexInput && portIndex != kPortIndexOutput) { ++ android_errorWriteLog(0x534e4554, "26324358"); ++ if (type != NULL) { ++ *type = kMetadataBufferTypeInvalid; ++ } ++ return BAD_VALUE; ++ } ++ ++ OMX_INDEXTYPE index; ++ OMX_STRING name = const_cast( ++ "OMX.google.android.index.storeMetaDataInBuffers"); ++ ++ OMX_STRING nativeBufferName = const_cast( ++ "OMX.google.android.index.storeANWBufferInMetadata"); ++ MetadataBufferType negotiatedType; ++ MetadataBufferType requestedType = type != NULL ? *type : kMetadataBufferTypeANWBuffer; ++ ++ StoreMetaDataInBuffersParams params; ++ InitOMXParams(¶ms); ++ params.nPortIndex = portIndex; ++ params.bStoreMetaData = enable; ++ ++ OMX_ERRORTYPE err = ++ requestedType == kMetadataBufferTypeANWBuffer ++ ? OMX_GetExtensionIndex(mHandle, nativeBufferName, &index) ++ : OMX_ErrorUnsupportedIndex; ++ OMX_ERRORTYPE xerr = err; ++ if (err == OMX_ErrorNone) { ++ err = OMX_SetParameter(mHandle, index, ¶ms); ++ if (err == OMX_ErrorNone) { ++ name = nativeBufferName; // set name for debugging ++ negotiatedType = requestedType; ++ } ++ } ++ if (err != OMX_ErrorNone) { ++ err = OMX_GetExtensionIndex(mHandle, name, &index); ++ xerr = err; ++ if (err == OMX_ErrorNone) { ++ negotiatedType = ++ requestedType == kMetadataBufferTypeANWBuffer ++ ? kMetadataBufferTypeGrallocSource : requestedType; ++ err = OMX_SetParameter(mHandle, index, ¶ms); ++ } ++ } ++ ++ // don't log loud error if component does not support metadata mode on the output ++ if (err != OMX_ErrorNone) { ++ if (err == OMX_ErrorUnsupportedIndex && portIndex == kPortIndexOutput) { ++ CLOGW("component does not support metadata mode; using fallback"); ++ } else if (xerr != OMX_ErrorNone) { ++ CLOG_ERROR(getExtensionIndex, xerr, "%s", name); ++ } else { ++ CLOG_ERROR(setParameter, err, "%s(%#x): %s:%u en=%d type=%d", name, index, ++ portString(portIndex), portIndex, enable, negotiatedType); ++ } ++ negotiatedType = mMetadataType[portIndex]; ++ } else { ++ if (!enable) { ++ negotiatedType = kMetadataBufferTypeInvalid; ++ } ++ mMetadataType[portIndex] = negotiatedType; ++ } ++ CLOG_CONFIG(storeMetaDataInBuffers, "%s:%u %srequested %s:%d negotiated %s:%d", ++ portString(portIndex), portIndex, enable ? "" : "UN", ++ asString(requestedType), requestedType, asString(negotiatedType), negotiatedType); ++ ++ if (type != NULL) { ++ *type = negotiatedType; ++ } ++ ++ return StatusFromOMXError(err); ++} ++ ++status_t OMXNodeInstance::prepareForAdaptivePlayback( ++ OMX_U32 portIndex, OMX_BOOL enable, OMX_U32 maxFrameWidth, ++ OMX_U32 maxFrameHeight) { ++ Mutex::Autolock autolock(mLock); ++ if (mSailed) { ++ android_errorWriteLog(0x534e4554, "29422020"); ++ return INVALID_OPERATION; ++ } ++ CLOG_CONFIG(prepareForAdaptivePlayback, "%s:%u en=%d max=%ux%u", ++ portString(portIndex), portIndex, enable, maxFrameWidth, maxFrameHeight); ++ ++ OMX_INDEXTYPE index; ++ OMX_STRING name = const_cast( ++ "OMX.google.android.index.prepareForAdaptivePlayback"); ++ ++ OMX_ERRORTYPE err = OMX_GetExtensionIndex(mHandle, name, &index); ++ if (err != OMX_ErrorNone) { ++ CLOG_ERROR_IF(enable, getExtensionIndex, err, "%s", name); ++ return StatusFromOMXError(err); ++ } ++ ++ PrepareForAdaptivePlaybackParams params; ++ InitOMXParams(¶ms); ++ params.nPortIndex = portIndex; ++ params.bEnable = enable; ++ params.nMaxFrameWidth = maxFrameWidth; ++ params.nMaxFrameHeight = maxFrameHeight; ++ ++ err = OMX_SetParameter(mHandle, index, ¶ms); ++ CLOG_IF_ERROR(setParameter, err, "%s(%#x): %s:%u en=%d max=%ux%u", name, index, ++ portString(portIndex), portIndex, enable, maxFrameWidth, maxFrameHeight); ++ return StatusFromOMXError(err); ++} ++ ++status_t OMXNodeInstance::configureVideoTunnelMode( ++ OMX_U32 portIndex, OMX_BOOL tunneled, OMX_U32 audioHwSync, ++ native_handle_t **sidebandHandle) { ++ Mutex::Autolock autolock(mLock); ++ if (mSailed) { ++ android_errorWriteLog(0x534e4554, "29422020"); ++ return INVALID_OPERATION; ++ } ++ CLOG_CONFIG(configureVideoTunnelMode, "%s:%u tun=%d sync=%u", ++ portString(portIndex), portIndex, tunneled, audioHwSync); ++ ++ OMX_INDEXTYPE index; ++ OMX_STRING name = const_cast( ++ "OMX.google.android.index.configureVideoTunnelMode"); ++ ++ OMX_ERRORTYPE err = OMX_GetExtensionIndex(mHandle, name, &index); ++ if (err != OMX_ErrorNone) { ++ CLOG_ERROR_IF(tunneled, getExtensionIndex, err, "%s", name); ++ return StatusFromOMXError(err); ++ } ++ ++ ConfigureVideoTunnelModeParams tunnelParams; ++ InitOMXParams(&tunnelParams); ++ tunnelParams.nPortIndex = portIndex; ++ tunnelParams.bTunneled = tunneled; ++ tunnelParams.nAudioHwSync = audioHwSync; ++ err = OMX_SetParameter(mHandle, index, &tunnelParams); ++ if (err != OMX_ErrorNone) { ++ CLOG_ERROR(setParameter, err, "%s(%#x): %s:%u tun=%d sync=%u", name, index, ++ portString(portIndex), portIndex, tunneled, audioHwSync); ++ return StatusFromOMXError(err); ++ } ++ ++ err = OMX_GetParameter(mHandle, index, &tunnelParams); ++ if (err != OMX_ErrorNone) { ++ CLOG_ERROR(getParameter, err, "%s(%#x): %s:%u tun=%d sync=%u", name, index, ++ portString(portIndex), portIndex, tunneled, audioHwSync); ++ return StatusFromOMXError(err); ++ } ++ if (sidebandHandle) { ++ *sidebandHandle = (native_handle_t*)tunnelParams.pSidebandWindow; ++ } ++ ++ return OK; ++} ++ ++status_t OMXNodeInstance::useBuffer( ++ OMX_U32 portIndex, const sp ¶ms, ++ OMX::buffer_id *buffer, OMX_U32 allottedSize) { ++ if (params == NULL || buffer == NULL) { ++ ALOGE("b/25884056"); ++ return BAD_VALUE; ++ } ++ ++ Mutex::Autolock autoLock(mLock); ++ if (allottedSize > params->size() || portIndex >= NELEM(mNumPortBuffers)) { ++ return BAD_VALUE; ++ } ++ ++ // metadata buffers are not connected cross process ++ // use a backup buffer instead of the actual buffer ++ BufferMeta *buffer_meta; ++ bool useBackup = mMetadataType[portIndex] != kMetadataBufferTypeInvalid; ++ OMX_U8 *data = static_cast(params->pointer()); ++ // allocate backup buffer ++ if (useBackup) { ++ data = new (std::nothrow) OMX_U8[allottedSize]; ++ if (data == NULL) { ++ return NO_MEMORY; ++ } ++ memset(data, 0, allottedSize); ++ ++ // if we are not connecting the buffers, the sizes must match ++ if (allottedSize != params->size()) { ++ CLOG_ERROR(useBuffer, BAD_VALUE, SIMPLE_BUFFER(portIndex, (size_t)allottedSize, data)); ++ delete[] data; ++ return BAD_VALUE; ++ } ++ ++ buffer_meta = new BufferMeta( ++ params, portIndex, false /* copyToOmx */, false /* copyFromOmx */, data); ++ } else { ++ buffer_meta = new BufferMeta( ++ params, portIndex, false /* copyToOmx */, false /* copyFromOmx */, NULL); ++ } ++ ++ OMX_BUFFERHEADERTYPE *header; ++ ++ OMX_ERRORTYPE err = OMX_UseBuffer( ++ mHandle, &header, portIndex, buffer_meta, ++ allottedSize, data); ++ ++ if (err != OMX_ErrorNone) { ++ CLOG_ERROR(useBuffer, err, SIMPLE_BUFFER( ++ portIndex, (size_t)allottedSize, data)); ++ ++ delete buffer_meta; ++ buffer_meta = NULL; ++ ++ *buffer = 0; ++ ++ return StatusFromOMXError(err); ++ } ++ ++ CHECK_EQ(header->pAppPrivate, buffer_meta); ++ ++ *buffer = makeBufferID(header); ++ ++ addActiveBuffer(portIndex, *buffer); ++ ++ sp bufferSource(getGraphicBufferSource()); ++ if (bufferSource != NULL && portIndex == kPortIndexInput) { ++ bufferSource->addCodecBuffer(header); ++ } ++ ++ CLOG_BUFFER(useBuffer, NEW_BUFFER_FMT( ++ *buffer, portIndex, "%u(%zu)@%p", allottedSize, params->size(), params->pointer())); ++ return OK; ++} ++ ++status_t OMXNodeInstance::useGraphicBuffer2_l( ++ OMX_U32 portIndex, const sp& graphicBuffer, ++ OMX::buffer_id *buffer) { ++ if (graphicBuffer == NULL || buffer == NULL) { ++ ALOGE("b/25884056"); ++ return BAD_VALUE; ++ } ++ ++ // port definition ++ OMX_PARAM_PORTDEFINITIONTYPE def; ++ InitOMXParams(&def); ++ def.nPortIndex = portIndex; ++ OMX_ERRORTYPE err = OMX_GetParameter(mHandle, OMX_IndexParamPortDefinition, &def); ++ if (err != OMX_ErrorNone) { ++ OMX_INDEXTYPE index = OMX_IndexParamPortDefinition; ++ CLOG_ERROR(getParameter, err, "%s(%#x): %s:%u", ++ asString(index), index, portString(portIndex), portIndex); ++ return UNKNOWN_ERROR; ++ } ++ ++ BufferMeta *bufferMeta = new BufferMeta(graphicBuffer, portIndex); ++ ++ OMX_BUFFERHEADERTYPE *header = NULL; ++ OMX_U8* bufferHandle = const_cast( ++ reinterpret_cast(graphicBuffer->handle)); ++ ++ err = OMX_UseBuffer( ++ mHandle, ++ &header, ++ portIndex, ++ bufferMeta, ++ def.nBufferSize, ++ bufferHandle); ++ ++ if (err != OMX_ErrorNone) { ++ CLOG_ERROR(useBuffer, err, BUFFER_FMT(portIndex, "%u@%p", def.nBufferSize, bufferHandle)); ++ delete bufferMeta; ++ bufferMeta = NULL; ++ *buffer = 0; ++ return StatusFromOMXError(err); ++ } ++ ++ CHECK_EQ(header->pBuffer, bufferHandle); ++ CHECK_EQ(header->pAppPrivate, bufferMeta); ++ ++ *buffer = makeBufferID(header); ++ ++ addActiveBuffer(portIndex, *buffer); ++ CLOG_BUFFER(useGraphicBuffer2, NEW_BUFFER_FMT( ++ *buffer, portIndex, "%u@%p", def.nBufferSize, bufferHandle)); ++ return OK; ++} ++ ++// XXX: This function is here for backwards compatibility. Once the OMX ++// implementations have been updated this can be removed and useGraphicBuffer2 ++// can be renamed to useGraphicBuffer. ++status_t OMXNodeInstance::useGraphicBuffer( ++ OMX_U32 portIndex, const sp& graphicBuffer, ++ OMX::buffer_id *buffer) { ++ if (graphicBuffer == NULL || buffer == NULL) { ++ ALOGE("b/25884056"); ++ return BAD_VALUE; ++ } ++ Mutex::Autolock autoLock(mLock); ++ ++ // See if the newer version of the extension is present. ++ OMX_INDEXTYPE index; ++ if (OMX_GetExtensionIndex( ++ mHandle, ++ const_cast("OMX.google.android.index.useAndroidNativeBuffer2"), ++ &index) == OMX_ErrorNone) { ++ return useGraphicBuffer2_l(portIndex, graphicBuffer, buffer); ++ } ++ ++ OMX_STRING name = const_cast( ++ "OMX.google.android.index.useAndroidNativeBuffer"); ++ OMX_ERRORTYPE err = OMX_GetExtensionIndex(mHandle, name, &index); ++ if (err != OMX_ErrorNone) { ++ CLOG_ERROR(getExtensionIndex, err, "%s", name); ++ return StatusFromOMXError(err); ++ } ++ ++ BufferMeta *bufferMeta = new BufferMeta(graphicBuffer, portIndex); ++ ++ OMX_BUFFERHEADERTYPE *header; ++ ++ OMX_VERSIONTYPE ver; ++ ver.s.nVersionMajor = 1; ++ ver.s.nVersionMinor = 0; ++ ver.s.nRevision = 0; ++ ver.s.nStep = 0; ++ UseAndroidNativeBufferParams params = { ++ sizeof(UseAndroidNativeBufferParams), ver, portIndex, bufferMeta, ++ &header, graphicBuffer, ++ }; ++ ++ err = OMX_SetParameter(mHandle, index, ¶ms); ++ ++ if (err != OMX_ErrorNone) { ++ CLOG_ERROR(setParameter, err, "%s(%#x): %s:%u meta=%p GB=%p", name, index, ++ portString(portIndex), portIndex, bufferMeta, graphicBuffer->handle); ++ ++ delete bufferMeta; ++ bufferMeta = NULL; ++ ++ *buffer = 0; ++ ++ return StatusFromOMXError(err); ++ } ++ ++ CHECK_EQ(header->pAppPrivate, bufferMeta); ++ ++ *buffer = makeBufferID(header); ++ ++ addActiveBuffer(portIndex, *buffer); ++ CLOG_BUFFER(useGraphicBuffer, NEW_BUFFER_FMT( ++ *buffer, portIndex, "GB=%p", graphicBuffer->handle)); ++ return OK; ++} ++ ++status_t OMXNodeInstance::updateGraphicBufferInMeta_l( ++ OMX_U32 portIndex, const sp& graphicBuffer, ++ OMX::buffer_id buffer, OMX_BUFFERHEADERTYPE *header, bool updateCodecBuffer) { ++ // No need to check |graphicBuffer| since NULL is valid for it as below. ++ if (header == NULL) { ++ ALOGE("b/25884056"); ++ return BAD_VALUE; ++ } ++ ++ if (portIndex != kPortIndexInput && portIndex != kPortIndexOutput) { ++ return BAD_VALUE; ++ } ++ ++ BufferMeta *bufferMeta = (BufferMeta *)(header->pAppPrivate); ++ sp data = bufferMeta->getBuffer( ++ header, !updateCodecBuffer /* backup */, false /* limit */); ++ bufferMeta->setGraphicBuffer(graphicBuffer); ++ MetadataBufferType metaType = mMetadataType[portIndex]; ++ // we use gralloc source only in the codec buffers ++ if (metaType == kMetadataBufferTypeGrallocSource && !updateCodecBuffer) { ++ metaType = kMetadataBufferTypeANWBuffer; ++ } ++ if (metaType == kMetadataBufferTypeGrallocSource ++ && data->capacity() >= sizeof(VideoGrallocMetadata)) { ++ VideoGrallocMetadata &metadata = *(VideoGrallocMetadata *)(data->data()); ++ metadata.eType = kMetadataBufferTypeGrallocSource; ++ metadata.pHandle = graphicBuffer == NULL ? NULL : graphicBuffer->handle; ++ } else if (metaType == kMetadataBufferTypeANWBuffer ++ && data->capacity() >= sizeof(VideoNativeMetadata)) { ++ VideoNativeMetadata &metadata = *(VideoNativeMetadata *)(data->data()); ++ metadata.eType = kMetadataBufferTypeANWBuffer; ++ metadata.pBuffer = graphicBuffer == NULL ? NULL : graphicBuffer->getNativeBuffer(); ++ metadata.nFenceFd = -1; ++ } else { ++ CLOG_ERROR(updateGraphicBufferInMeta, BAD_VALUE, "%s:%u, %#x bad type (%d) or size (%u)", ++ portString(portIndex), portIndex, buffer, mMetadataType[portIndex], header->nAllocLen); ++ return BAD_VALUE; ++ } ++ ++ CLOG_BUFFER(updateGraphicBufferInMeta, "%s:%u, %#x := %p", ++ portString(portIndex), portIndex, buffer, ++ graphicBuffer == NULL ? NULL : graphicBuffer->handle); ++ return OK; ++} ++ ++status_t OMXNodeInstance::updateGraphicBufferInMeta( ++ OMX_U32 portIndex, const sp& graphicBuffer, ++ OMX::buffer_id buffer) { ++ Mutex::Autolock autoLock(mLock); ++ OMX_BUFFERHEADERTYPE *header = findBufferHeader(buffer, portIndex); ++ // update backup buffer for input, codec buffer for output ++ return updateGraphicBufferInMeta_l( ++ portIndex, graphicBuffer, buffer, header, ++ true /* updateCodecBuffer */); ++} ++ ++status_t OMXNodeInstance::updateNativeHandleInMeta( ++ OMX_U32 portIndex, const sp& nativeHandle, OMX::buffer_id buffer) { ++ Mutex::Autolock autoLock(mLock); ++ OMX_BUFFERHEADERTYPE *header = findBufferHeader(buffer, portIndex); ++ // No need to check |nativeHandle| since NULL is valid for it as below. ++ if (header == NULL) { ++ ALOGE("b/25884056"); ++ return BAD_VALUE; ++ } ++ ++ if (portIndex != kPortIndexInput && portIndex != kPortIndexOutput) { ++ return BAD_VALUE; ++ } ++ ++ BufferMeta *bufferMeta = (BufferMeta *)(header->pAppPrivate); ++ // update backup buffer ++ sp data = bufferMeta->getBuffer( ++ header, false /* backup */, false /* limit */); ++ bufferMeta->setNativeHandle(nativeHandle); ++ if (mMetadataType[portIndex] == kMetadataBufferTypeNativeHandleSource ++ && data->capacity() >= sizeof(VideoNativeHandleMetadata)) { ++ VideoNativeHandleMetadata &metadata = *(VideoNativeHandleMetadata *)(data->data()); ++ metadata.eType = mMetadataType[portIndex]; ++ metadata.pHandle = ++ nativeHandle == NULL ? NULL : const_cast(nativeHandle->handle()); ++ } else { ++ CLOG_ERROR(updateNativeHandleInMeta, BAD_VALUE, "%s:%u, %#x bad type (%d) or size (%zu)", ++ portString(portIndex), portIndex, buffer, mMetadataType[portIndex], data->capacity()); ++ return BAD_VALUE; ++ } ++ ++ CLOG_BUFFER(updateNativeHandleInMeta, "%s:%u, %#x := %p", ++ portString(portIndex), portIndex, buffer, ++ nativeHandle == NULL ? NULL : nativeHandle->handle()); ++ return OK; ++} ++ ++status_t OMXNodeInstance::createGraphicBufferSource( ++ OMX_U32 portIndex, sp bufferConsumer, MetadataBufferType *type) { ++ status_t err; ++ ++ // only allow graphic source on input port, when there are no allocated buffers yet ++ if (portIndex != kPortIndexInput) { ++ android_errorWriteLog(0x534e4554, "29422020"); ++ return BAD_VALUE; ++ } else if (mNumPortBuffers[portIndex] > 0) { ++ android_errorWriteLog(0x534e4554, "29422020"); ++ return INVALID_OPERATION; ++ } ++ ++ const sp surfaceCheck = getGraphicBufferSource(); ++ if (surfaceCheck != NULL) { ++ if (portIndex < NELEM(mMetadataType) && type != NULL) { ++ *type = mMetadataType[portIndex]; ++ } ++ return ALREADY_EXISTS; ++ } ++ ++ // Input buffers will hold meta-data (ANativeWindowBuffer references). ++ if (type != NULL) { ++ *type = kMetadataBufferTypeANWBuffer; ++ } ++ err = storeMetaDataInBuffers_l(portIndex, OMX_TRUE, type); ++ if (err != OK) { ++ return err; ++ } ++ ++ // Retrieve the width and height of the graphic buffer, set when the ++ // codec was configured. ++ OMX_PARAM_PORTDEFINITIONTYPE def; ++ InitOMXParams(&def); ++ def.nPortIndex = portIndex; ++ OMX_ERRORTYPE oerr = OMX_GetParameter( ++ mHandle, OMX_IndexParamPortDefinition, &def); ++ if (oerr != OMX_ErrorNone) { ++ OMX_INDEXTYPE index = OMX_IndexParamPortDefinition; ++ CLOG_ERROR(getParameter, oerr, "%s(%#x): %s:%u", ++ asString(index), index, portString(portIndex), portIndex); ++ return UNKNOWN_ERROR; ++ } ++ ++ if (def.format.video.eColorFormat != OMX_COLOR_FormatAndroidOpaque) { ++ CLOGW("createInputSurface requires COLOR_FormatSurface " ++ "(AndroidOpaque) color format instead of %s(%#x)", ++ asString(def.format.video.eColorFormat), def.format.video.eColorFormat); ++ return INVALID_OPERATION; ++ } ++ ++ uint32_t usageBits; ++ oerr = OMX_GetParameter( ++ mHandle, (OMX_INDEXTYPE)OMX_IndexParamConsumerUsageBits, &usageBits); ++ if (oerr != OMX_ErrorNone) { ++ usageBits = 0; ++ } ++ ++ sp bufferSource = new GraphicBufferSource(this, ++ def.format.video.nFrameWidth, ++ def.format.video.nFrameHeight, ++ def.nBufferCountActual, ++ usageBits, ++ bufferConsumer); ++ ++ if ((err = bufferSource->initCheck()) != OK) { ++ return err; ++ } ++ setGraphicBufferSource(bufferSource); ++ ++ return OK; ++} ++ ++status_t OMXNodeInstance::createInputSurface( ++ OMX_U32 portIndex, android_dataspace dataSpace, ++ sp *bufferProducer, MetadataBufferType *type) { ++ if (bufferProducer == NULL) { ++ ALOGE("b/25884056"); ++ return BAD_VALUE; ++ } ++ ++ Mutex::Autolock autolock(mLock); ++ status_t err = createGraphicBufferSource(portIndex, NULL /* bufferConsumer */, type); ++ ++ if (err != OK) { ++ return err; ++ } ++ ++ mGraphicBufferSource->setDefaultDataSpace(dataSpace); ++ ++ *bufferProducer = mGraphicBufferSource->getIGraphicBufferProducer(); ++ return OK; ++} ++ ++//static ++status_t OMXNodeInstance::createPersistentInputSurface( ++ sp *bufferProducer, ++ sp *bufferConsumer) { ++ if (bufferProducer == NULL || bufferConsumer == NULL) { ++ ALOGE("b/25884056"); ++ return BAD_VALUE; ++ } ++ String8 name("GraphicBufferSource"); ++ ++ sp producer; ++ sp consumer; ++ BufferQueue::createBufferQueue(&producer, &consumer); ++ consumer->setConsumerName(name); ++ consumer->setConsumerUsageBits(GRALLOC_USAGE_HW_VIDEO_ENCODER); ++ ++ sp proxy = ++ new BufferQueue::ProxyConsumerListener(NULL); ++ status_t err = consumer->consumerConnect(proxy, false); ++ if (err != NO_ERROR) { ++ ALOGE("Error connecting to BufferQueue: %s (%d)", ++ strerror(-err), err); ++ return err; ++ } ++ ++ *bufferProducer = producer; ++ *bufferConsumer = consumer; ++ ++ return OK; ++} ++ ++status_t OMXNodeInstance::setInputSurface( ++ OMX_U32 portIndex, const sp &bufferConsumer, ++ MetadataBufferType *type) { ++ Mutex::Autolock autolock(mLock); ++ return createGraphicBufferSource(portIndex, bufferConsumer, type); ++} ++ ++void OMXNodeInstance::signalEvent(OMX_EVENTTYPE event, OMX_U32 arg1, OMX_U32 arg2) { ++ mOwner->OnEvent(mNodeID, event, arg1, arg2, NULL); ++} ++ ++status_t OMXNodeInstance::signalEndOfInputStream() { ++ // For non-Surface input, the MediaCodec should convert the call to a ++ // pair of requests (dequeue input buffer, queue input buffer with EOS ++ // flag set). Seems easier than doing the equivalent from here. ++ sp bufferSource(getGraphicBufferSource()); ++ if (bufferSource == NULL) { ++ CLOGW("signalEndOfInputStream can only be used with Surface input"); ++ return INVALID_OPERATION; ++ } ++ return bufferSource->signalEndOfInputStream(); ++} ++ ++status_t OMXNodeInstance::allocateSecureBuffer( ++ OMX_U32 portIndex, size_t size, OMX::buffer_id *buffer, ++ void **buffer_data, sp *native_handle) { ++ if (buffer == NULL || buffer_data == NULL || native_handle == NULL) { ++ ALOGE("b/25884056"); ++ return BAD_VALUE; ++ } ++ ++ if (portIndex >= NELEM(mSecureBufferType)) { ++ ALOGE("b/31385713, portIndex(%u)", portIndex); ++ android_errorWriteLog(0x534e4554, "31385713"); ++ return BAD_VALUE; ++ } ++ ++ Mutex::Autolock autoLock(mLock); ++ ++ BufferMeta *buffer_meta = new BufferMeta(size, portIndex); ++ ++ OMX_BUFFERHEADERTYPE *header; ++ ++ OMX_ERRORTYPE err = OMX_AllocateBuffer( ++ mHandle, &header, portIndex, buffer_meta, size); ++ ++ if (err != OMX_ErrorNone) { ++ CLOG_ERROR(allocateBuffer, err, BUFFER_FMT(portIndex, "%zu@", size)); ++ delete buffer_meta; ++ buffer_meta = NULL; ++ ++ *buffer = 0; ++ ++ return StatusFromOMXError(err); ++ } ++ ++ CHECK_EQ(header->pAppPrivate, buffer_meta); ++ ++ *buffer = makeBufferID(header); ++ if (mSecureBufferType[portIndex] == kSecureBufferTypeNativeHandle) { ++ *buffer_data = NULL; ++ *native_handle = NativeHandle::create( ++ (native_handle_t *)header->pBuffer, false /* ownsHandle */); ++ } else { ++ *buffer_data = header->pBuffer; ++ *native_handle = NULL; ++ } ++ ++ addActiveBuffer(portIndex, *buffer); ++ ++ sp bufferSource(getGraphicBufferSource()); ++ if (bufferSource != NULL && portIndex == kPortIndexInput) { ++ bufferSource->addCodecBuffer(header); ++ } ++ CLOG_BUFFER(allocateSecureBuffer, NEW_BUFFER_FMT( ++ *buffer, portIndex, "%zu@%p:%p", size, *buffer_data, ++ *native_handle == NULL ? NULL : (*native_handle)->handle())); ++ ++ return OK; ++} ++ ++status_t OMXNodeInstance::allocateBufferWithBackup( ++ OMX_U32 portIndex, const sp ¶ms, ++ OMX::buffer_id *buffer, OMX_U32 allottedSize) { ++ if (params == NULL || buffer == NULL) { ++ ALOGE("b/25884056"); ++ return BAD_VALUE; ++ } ++ ++ Mutex::Autolock autoLock(mLock); ++ if (allottedSize > params->size() || portIndex >= NELEM(mNumPortBuffers)) { ++ return BAD_VALUE; ++ } ++ ++ // metadata buffers are not connected cross process; only copy if not meta ++#ifdef CAMCORDER_GRALLOC_SOURCE ++ bool copy = true; ++#else ++ bool copy = mMetadataType[portIndex] == kMetadataBufferTypeInvalid; ++#endif ++ ++ BufferMeta *buffer_meta = new BufferMeta( ++ params, portIndex, ++ (portIndex == kPortIndexInput) && copy /* copyToOmx */, ++ (portIndex == kPortIndexOutput) && copy /* copyFromOmx */, ++ NULL /* data */); ++ ++ OMX_BUFFERHEADERTYPE *header; ++ ++ OMX_ERRORTYPE err = OMX_AllocateBuffer( ++ mHandle, &header, portIndex, buffer_meta, allottedSize); ++ if (err != OMX_ErrorNone) { ++ CLOG_ERROR(allocateBufferWithBackup, err, ++ SIMPLE_BUFFER(portIndex, (size_t)allottedSize, params->pointer())); ++ delete buffer_meta; ++ buffer_meta = NULL; ++ ++ *buffer = 0; ++ ++ return StatusFromOMXError(err); ++ } ++ ++ CHECK_EQ(header->pAppPrivate, buffer_meta); ++ ++ *buffer = makeBufferID(header); ++ ++ addActiveBuffer(portIndex, *buffer); ++ ++ sp bufferSource(getGraphicBufferSource()); ++ if (bufferSource != NULL && portIndex == kPortIndexInput) { ++ bufferSource->addCodecBuffer(header); ++ } ++ ++ CLOG_BUFFER(allocateBufferWithBackup, NEW_BUFFER_FMT(*buffer, portIndex, "%zu@%p :> %u@%p", ++ params->size(), params->pointer(), allottedSize, header->pBuffer)); ++ ++ return OK; ++} ++ ++status_t OMXNodeInstance::freeBuffer( ++ OMX_U32 portIndex, OMX::buffer_id buffer) { ++ Mutex::Autolock autoLock(mLock); ++ CLOG_BUFFER(freeBuffer, "%s:%u %#x", portString(portIndex), portIndex, buffer); ++ ++ removeActiveBuffer(portIndex, buffer); ++ ++ OMX_BUFFERHEADERTYPE *header = findBufferHeader(buffer, portIndex); ++ if (header == NULL) { ++ ALOGE("b/25884056"); ++ return BAD_VALUE; ++ } ++ BufferMeta *buffer_meta = static_cast(header->pAppPrivate); ++ ++ OMX_ERRORTYPE err = OMX_FreeBuffer(mHandle, portIndex, header); ++ CLOG_IF_ERROR(freeBuffer, err, "%s:%u %#x", portString(portIndex), portIndex, buffer); ++ ++ delete buffer_meta; ++ buffer_meta = NULL; ++ invalidateBufferID(buffer); ++ ++ return StatusFromOMXError(err); ++} ++ ++status_t OMXNodeInstance::fillBuffer(OMX::buffer_id buffer, int fenceFd) { ++ Mutex::Autolock autoLock(mLock); ++ ++ OMX_BUFFERHEADERTYPE *header = findBufferHeader(buffer, kPortIndexOutput); ++ if (header == NULL) { ++ ALOGE("b/25884056"); ++ return BAD_VALUE; ++ } ++ header->nFilledLen = 0; ++ header->nOffset = 0; ++ header->nFlags = 0; ++ ++ // meta now owns fenceFd ++ status_t res = storeFenceInMeta_l(header, fenceFd, kPortIndexOutput); ++ if (res != OK) { ++ CLOG_ERROR(fillBuffer::storeFenceInMeta, res, EMPTY_BUFFER(buffer, header, fenceFd)); ++ return res; ++ } ++ ++ { ++ Mutex::Autolock _l(mDebugLock); ++ mOutputBuffersWithCodec.add(header); ++ CLOG_BUMPED_BUFFER(fillBuffer, WITH_STATS(EMPTY_BUFFER(buffer, header, fenceFd))); ++ } ++ ++ OMX_ERRORTYPE err = OMX_FillThisBuffer(mHandle, header); ++ if (err != OMX_ErrorNone) { ++ CLOG_ERROR(fillBuffer, err, EMPTY_BUFFER(buffer, header, fenceFd)); ++ Mutex::Autolock _l(mDebugLock); ++ mOutputBuffersWithCodec.remove(header); ++ } ++ return StatusFromOMXError(err); ++} ++ ++status_t OMXNodeInstance::emptyBuffer( ++ OMX::buffer_id buffer, ++ OMX_U32 rangeOffset, OMX_U32 rangeLength, ++ OMX_U32 flags, OMX_TICKS timestamp, int fenceFd) { ++ Mutex::Autolock autoLock(mLock); ++ ++ // no emptybuffer if using input surface ++ if (getGraphicBufferSource() != NULL) { ++ android_errorWriteLog(0x534e4554, "29422020"); ++ return INVALID_OPERATION; ++ } ++ ++ OMX_BUFFERHEADERTYPE *header = findBufferHeader(buffer, kPortIndexInput); ++ if (header == NULL) { ++ ALOGE("b/25884056"); ++ return BAD_VALUE; ++ } ++ BufferMeta *buffer_meta = ++ static_cast(header->pAppPrivate); ++ ++#ifndef CAMCORDER_GRALLOC_SOURCE ++ // set up proper filled length if component is configured for gralloc metadata mode ++ // ignore rangeOffset in this case (as client may be assuming ANW meta buffers). ++ if (mMetadataType[kPortIndexInput] == kMetadataBufferTypeGrallocSource) { ++ header->nFilledLen = rangeLength ? sizeof(VideoGrallocMetadata) : 0; ++#else ++ sp backup = buffer_meta->getBuffer(header, true /* backup */, false /* limit */); ++ sp codec = buffer_meta->getBuffer(header, false /* backup */, false /* limit */); ++ ++ // convert incoming ANW meta buffers if component is configured for gralloc metadata mode ++ // ignore rangeOffset in this case ++ if (mMetadataType[kPortIndexInput] == kMetadataBufferTypeGrallocSource ++ && backup->capacity() >= sizeof(VideoNativeMetadata) ++ && codec->capacity() >= sizeof(VideoGrallocMetadata) ++ && ((VideoNativeMetadata *)backup->base())->eType ++ == kMetadataBufferTypeANWBuffer) { ++ VideoNativeMetadata &backupMeta = *(VideoNativeMetadata *)backup->base(); ++ VideoGrallocMetadata &codecMeta = *(VideoGrallocMetadata *)codec->base(); ++ CLOG_BUFFER(emptyBuffer, "converting ANWB %p to handle %p", ++ backupMeta.pBuffer, backupMeta.pBuffer->handle); ++ codecMeta.pHandle = backupMeta.pBuffer != NULL ? backupMeta.pBuffer->handle : NULL; ++ codecMeta.eType = kMetadataBufferTypeGrallocSource; ++ header->nFilledLen = rangeLength ? sizeof(codecMeta) : 0; ++#endif ++ header->nOffset = 0; ++ } else { ++ // rangeLength and rangeOffset must be a subset of the allocated data in the buffer. ++ // corner case: we permit rangeOffset == end-of-buffer with rangeLength == 0. ++ if (rangeOffset > header->nAllocLen ++ || rangeLength > header->nAllocLen - rangeOffset) { ++ CLOG_ERROR(emptyBuffer, OMX_ErrorBadParameter, FULL_BUFFER(NULL, header, fenceFd)); ++ if (fenceFd >= 0) { ++ ::close(fenceFd); ++ } ++ return BAD_VALUE; ++ } ++ header->nFilledLen = rangeLength; ++ header->nOffset = rangeOffset; ++ ++ buffer_meta->CopyToOMX(header); ++ } ++ ++ return emptyBuffer_l(header, flags, timestamp, (intptr_t)buffer, fenceFd); ++} ++ ++// log queued buffer activity for the next few input and/or output frames ++// if logging at internal state level ++void OMXNodeInstance::bumpDebugLevel_l(size_t numInputBuffers, size_t numOutputBuffers) { ++ if (DEBUG == ADebug::kDebugInternalState) { ++ DEBUG_BUMP = ADebug::kDebugAll; ++ if (numInputBuffers > 0) { ++ mDebugLevelBumpPendingBuffers[kPortIndexInput] = numInputBuffers; ++ } ++ if (numOutputBuffers > 0) { ++ mDebugLevelBumpPendingBuffers[kPortIndexOutput] = numOutputBuffers; ++ } ++ } ++} ++ ++void OMXNodeInstance::unbumpDebugLevel_l(size_t portIndex) { ++ if (mDebugLevelBumpPendingBuffers[portIndex]) { ++ --mDebugLevelBumpPendingBuffers[portIndex]; ++ } ++ if (!mDebugLevelBumpPendingBuffers[0] ++ && !mDebugLevelBumpPendingBuffers[1]) { ++ DEBUG_BUMP = DEBUG; ++ } ++} ++ ++status_t OMXNodeInstance::storeFenceInMeta_l( ++ OMX_BUFFERHEADERTYPE *header, int fenceFd, OMX_U32 portIndex) { ++ // propagate fence if component supports it; wait for it otherwise ++ OMX_U32 metaSize = portIndex == kPortIndexInput ? header->nFilledLen : header->nAllocLen; ++ if (mMetadataType[portIndex] == kMetadataBufferTypeANWBuffer ++ && metaSize >= sizeof(VideoNativeMetadata)) { ++ VideoNativeMetadata &nativeMeta = *(VideoNativeMetadata *)(header->pBuffer); ++ if (nativeMeta.nFenceFd >= 0) { ++ ALOGE("fence (%d) already exists in meta", nativeMeta.nFenceFd); ++ if (fenceFd >= 0) { ++ ::close(fenceFd); ++ } ++ return ALREADY_EXISTS; ++ } ++ nativeMeta.nFenceFd = fenceFd; ++ } else if (fenceFd >= 0) { ++ CLOG_BUFFER(storeFenceInMeta, "waiting for fence %d", fenceFd); ++ sp fence = new Fence(fenceFd); ++ return fence->wait(IOMX::kFenceTimeoutMs); ++ } ++ return OK; ++} ++ ++int OMXNodeInstance::retrieveFenceFromMeta_l( ++ OMX_BUFFERHEADERTYPE *header, OMX_U32 portIndex) { ++ OMX_U32 metaSize = portIndex == kPortIndexInput ? header->nAllocLen : header->nFilledLen; ++ int fenceFd = -1; ++ if (mMetadataType[portIndex] == kMetadataBufferTypeANWBuffer ++ && header->nAllocLen >= sizeof(VideoNativeMetadata)) { ++ VideoNativeMetadata &nativeMeta = *(VideoNativeMetadata *)(header->pBuffer); ++ if (nativeMeta.eType == kMetadataBufferTypeANWBuffer) { ++ fenceFd = nativeMeta.nFenceFd; ++ nativeMeta.nFenceFd = -1; ++ } ++ if (metaSize < sizeof(nativeMeta) && fenceFd >= 0) { ++ CLOG_ERROR(foundFenceInEmptyMeta, BAD_VALUE, FULL_BUFFER( ++ NULL, header, nativeMeta.nFenceFd)); ++ fenceFd = -1; ++ } ++ } ++ return fenceFd; ++} ++ ++status_t OMXNodeInstance::emptyBuffer_l( ++ OMX_BUFFERHEADERTYPE *header, OMX_U32 flags, OMX_TICKS timestamp, ++ intptr_t debugAddr, int fenceFd) { ++ header->nFlags = flags; ++ header->nTimeStamp = timestamp; ++ ++ status_t res = storeFenceInMeta_l(header, fenceFd, kPortIndexInput); ++ if (res != OK) { ++ CLOG_ERROR(emptyBuffer::storeFenceInMeta, res, WITH_STATS( ++ FULL_BUFFER(debugAddr, header, fenceFd))); ++ return res; ++ } ++ ++ { ++ Mutex::Autolock _l(mDebugLock); ++ mInputBuffersWithCodec.add(header); ++ ++ // bump internal-state debug level for 2 input frames past a buffer with CSD ++ if ((flags & OMX_BUFFERFLAG_CODECCONFIG) != 0) { ++ bumpDebugLevel_l(2 /* numInputBuffers */, 0 /* numOutputBuffers */); ++ } ++ ++ CLOG_BUMPED_BUFFER(emptyBuffer, WITH_STATS(FULL_BUFFER(debugAddr, header, fenceFd))); ++ } ++ ++ OMX_ERRORTYPE err = OMX_EmptyThisBuffer(mHandle, header); ++ CLOG_IF_ERROR(emptyBuffer, err, FULL_BUFFER(debugAddr, header, fenceFd)); ++ ++ { ++ Mutex::Autolock _l(mDebugLock); ++ if (err != OMX_ErrorNone) { ++ mInputBuffersWithCodec.remove(header); ++ } else if (!(flags & OMX_BUFFERFLAG_CODECCONFIG)) { ++ unbumpDebugLevel_l(kPortIndexInput); ++ } ++ } ++ ++ return StatusFromOMXError(err); ++} ++ ++// like emptyBuffer, but the data is already in header->pBuffer ++status_t OMXNodeInstance::emptyGraphicBuffer( ++ OMX_BUFFERHEADERTYPE *header, const sp &graphicBuffer, ++ OMX_U32 flags, OMX_TICKS timestamp, int fenceFd) { ++ if (header == NULL) { ++ ALOGE("b/25884056"); ++ return BAD_VALUE; ++ } ++ ++ Mutex::Autolock autoLock(mLock); ++ OMX::buffer_id buffer = findBufferID(header); ++ status_t err = updateGraphicBufferInMeta_l( ++ kPortIndexInput, graphicBuffer, buffer, header, ++ true /* updateCodecBuffer */); ++ if (err != OK) { ++ CLOG_ERROR(emptyGraphicBuffer, err, FULL_BUFFER( ++ (intptr_t)header->pBuffer, header, fenceFd)); ++ return err; ++ } ++ ++ header->nOffset = 0; ++ if (graphicBuffer == NULL) { ++ header->nFilledLen = 0; ++ } else if (mMetadataType[kPortIndexInput] == kMetadataBufferTypeGrallocSource) { ++ header->nFilledLen = sizeof(VideoGrallocMetadata); ++ } else { ++ header->nFilledLen = sizeof(VideoNativeMetadata); ++ } ++ return emptyBuffer_l(header, flags, timestamp, (intptr_t)header->pBuffer, fenceFd); ++} ++ ++status_t OMXNodeInstance::getExtensionIndex( ++ const char *parameterName, OMX_INDEXTYPE *index) { ++ Mutex::Autolock autoLock(mLock); ++ ++ OMX_ERRORTYPE err = OMX_GetExtensionIndex( ++ mHandle, const_cast(parameterName), index); ++ ++ return StatusFromOMXError(err); ++} ++ ++inline static const char *asString(IOMX::InternalOptionType i, const char *def = "??") { ++ switch (i) { ++ case IOMX::INTERNAL_OPTION_SUSPEND: return "SUSPEND"; ++ case IOMX::INTERNAL_OPTION_REPEAT_PREVIOUS_FRAME_DELAY: ++ return "REPEAT_PREVIOUS_FRAME_DELAY"; ++ case IOMX::INTERNAL_OPTION_MAX_TIMESTAMP_GAP: return "MAX_TIMESTAMP_GAP"; ++ case IOMX::INTERNAL_OPTION_MAX_FPS: return "MAX_FPS"; ++ case IOMX::INTERNAL_OPTION_START_TIME: return "START_TIME"; ++ case IOMX::INTERNAL_OPTION_TIME_LAPSE: return "TIME_LAPSE"; ++ case IOMX::INTERNAL_OPTION_TIME_OFFSET: return "TIME_OFFSET"; ++ default: return def; ++ } ++} ++ ++template ++static bool getInternalOption( ++ const void *data, size_t size, T *out) { ++ if (size != sizeof(T)) { ++ return false; ++ } ++ *out = *(T*)data; ++ return true; ++} ++ ++status_t OMXNodeInstance::setInternalOption( ++ OMX_U32 portIndex, ++ IOMX::InternalOptionType type, ++ const void *data, ++ size_t size) { ++ CLOG_CONFIG(setInternalOption, "%s(%d): %s:%u %zu@%p", ++ asString(type), type, portString(portIndex), portIndex, size, data); ++ switch (type) { ++ case IOMX::INTERNAL_OPTION_SUSPEND: ++ case IOMX::INTERNAL_OPTION_REPEAT_PREVIOUS_FRAME_DELAY: ++ case IOMX::INTERNAL_OPTION_MAX_TIMESTAMP_GAP: ++ case IOMX::INTERNAL_OPTION_MAX_FPS: ++ case IOMX::INTERNAL_OPTION_START_TIME: ++ case IOMX::INTERNAL_OPTION_TIME_LAPSE: ++ case IOMX::INTERNAL_OPTION_TIME_OFFSET: ++ case IOMX::INTERNAL_OPTION_COLOR_ASPECTS: ++ { ++ const sp &bufferSource = ++ getGraphicBufferSource(); ++ ++ if (bufferSource == NULL || portIndex != kPortIndexInput) { ++ CLOGW("setInternalOption is only for Surface input"); ++ return ERROR_UNSUPPORTED; ++ } ++ ++ if (type == IOMX::INTERNAL_OPTION_SUSPEND) { ++ bool suspend; ++ if (!getInternalOption(data, size, &suspend)) { ++ return INVALID_OPERATION; ++ } ++ ++ CLOG_CONFIG(setInternalOption, "suspend=%d", suspend); ++ bufferSource->suspend(suspend); ++ } else if (type == IOMX::INTERNAL_OPTION_REPEAT_PREVIOUS_FRAME_DELAY) { ++ int64_t delayUs; ++ if (!getInternalOption(data, size, &delayUs)) { ++ return INVALID_OPERATION; ++ } ++ ++ CLOG_CONFIG(setInternalOption, "delayUs=%lld", (long long)delayUs); ++ return bufferSource->setRepeatPreviousFrameDelayUs(delayUs); ++ } else if (type == IOMX::INTERNAL_OPTION_TIME_OFFSET) { ++ int64_t timeOffsetUs; ++ if (!getInternalOption(data, size, &timeOffsetUs)) { ++ return INVALID_OPERATION; ++ } ++ CLOG_CONFIG(setInternalOption, "bufferOffsetUs=%lld", (long long)timeOffsetUs); ++ return bufferSource->setInputBufferTimeOffset(timeOffsetUs); ++ } else if (type == IOMX::INTERNAL_OPTION_MAX_TIMESTAMP_GAP) { ++ int64_t maxGapUs; ++ if (!getInternalOption(data, size, &maxGapUs)) { ++ return INVALID_OPERATION; ++ } ++ ++ CLOG_CONFIG(setInternalOption, "gapUs=%lld", (long long)maxGapUs); ++ return bufferSource->setMaxTimestampGapUs(maxGapUs); ++ } else if (type == IOMX::INTERNAL_OPTION_MAX_FPS) { ++ float maxFps; ++ if (!getInternalOption(data, size, &maxFps)) { ++ return INVALID_OPERATION; ++ } ++ ++ CLOG_CONFIG(setInternalOption, "maxFps=%f", maxFps); ++ return bufferSource->setMaxFps(maxFps); ++ } else if (type == IOMX::INTERNAL_OPTION_START_TIME) { ++ int64_t skipFramesBeforeUs; ++ if (!getInternalOption(data, size, &skipFramesBeforeUs)) { ++ return INVALID_OPERATION; ++ } ++ ++ CLOG_CONFIG(setInternalOption, "beforeUs=%lld", (long long)skipFramesBeforeUs); ++ bufferSource->setSkipFramesBeforeUs(skipFramesBeforeUs); ++ } else if (type == IOMX::INTERNAL_OPTION_TIME_LAPSE) { ++ GraphicBufferSource::TimeLapseConfig config; ++ if (!getInternalOption(data, size, &config)) { ++ return INVALID_OPERATION; ++ } ++ ++ CLOG_CONFIG(setInternalOption, "perFrameUs=%lld perCaptureUs=%lld", ++ (long long)config.mTimePerFrameUs, (long long)config.mTimePerCaptureUs); ++ ++ return bufferSource->setTimeLapseConfig(config); ++ } else if (type == IOMX::INTERNAL_OPTION_COLOR_ASPECTS) { ++ ColorAspects aspects; ++ if (!getInternalOption(data, size, &aspects)) { ++ return INVALID_OPERATION; ++ } ++ ++ CLOG_CONFIG(setInternalOption, "setting color aspects"); ++ bufferSource->setColorAspects(aspects); ++ } ++ ++ return OK; ++ } ++ ++ default: ++ return ERROR_UNSUPPORTED; ++ } ++} ++ ++bool OMXNodeInstance::handleMessage(omx_message &msg) { ++ const sp& bufferSource(getGraphicBufferSource()); ++ ++ if (msg.type == omx_message::FILL_BUFFER_DONE) { ++ OMX_BUFFERHEADERTYPE *buffer = ++ findBufferHeader(msg.u.extended_buffer_data.buffer, kPortIndexOutput); ++ if (buffer == NULL) { ++ ALOGE("b/25884056"); ++ return false; ++ } ++ ++ { ++ Mutex::Autolock _l(mDebugLock); ++ mOutputBuffersWithCodec.remove(buffer); ++ ++ CLOG_BUMPED_BUFFER( ++ FBD, WITH_STATS(FULL_BUFFER( ++ msg.u.extended_buffer_data.buffer, buffer, msg.fenceFd))); ++ ++ unbumpDebugLevel_l(kPortIndexOutput); ++ } ++ ++ BufferMeta *buffer_meta = ++ static_cast(buffer->pAppPrivate); ++ ++ if (buffer->nOffset + buffer->nFilledLen < buffer->nOffset ++ || buffer->nOffset + buffer->nFilledLen > buffer->nAllocLen) { ++ CLOG_ERROR(onFillBufferDone, OMX_ErrorBadParameter, ++ FULL_BUFFER(NULL, buffer, msg.fenceFd)); ++ } ++ buffer_meta->CopyFromOMX(buffer); ++ ++ if (bufferSource != NULL) { ++ // fix up the buffer info (especially timestamp) if needed ++ bufferSource->codecBufferFilled(buffer); ++ ++ msg.u.extended_buffer_data.timestamp = buffer->nTimeStamp; ++ } ++ } else if (msg.type == omx_message::EMPTY_BUFFER_DONE) { ++ OMX_BUFFERHEADERTYPE *buffer = ++ findBufferHeader(msg.u.buffer_data.buffer, kPortIndexInput); ++ if (buffer == NULL) { ++ return false; ++ } ++ ++ { ++ Mutex::Autolock _l(mDebugLock); ++ mInputBuffersWithCodec.remove(buffer); ++ ++ CLOG_BUMPED_BUFFER( ++ EBD, WITH_STATS(EMPTY_BUFFER(msg.u.buffer_data.buffer, buffer, msg.fenceFd))); ++ } ++ ++ if (bufferSource != NULL) { ++ // This is one of the buffers used exclusively by ++ // GraphicBufferSource. ++ // Don't dispatch a message back to ACodec, since it doesn't ++ // know that anyone asked to have the buffer emptied and will ++ // be very confused. ++ bufferSource->codecBufferEmptied(buffer, msg.fenceFd); ++ return true; ++ } ++ } ++ ++ return false; ++} ++ ++void OMXNodeInstance::onMessages(std::list &messages) { ++ for (std::list::iterator it = messages.begin(); it != messages.end(); ) { ++ if (handleMessage(*it)) { ++ messages.erase(it++); ++ } else { ++ ++it; ++ } ++ } ++ ++ if (!messages.empty()) { ++ mObserver->onMessages(messages); ++ } ++} ++ ++void OMXNodeInstance::onObserverDied(OMXMaster *master) { ++ ALOGE("!!! Observer died. Quickly, do something, ... anything..."); ++ ++ // Try to force shutdown of the node and hope for the best. ++ freeNode(master); ++} ++ ++void OMXNodeInstance::onGetHandleFailed() { ++ delete this; ++} ++ ++// OMXNodeInstance::OnEvent calls OMX::OnEvent, which then calls here. ++// Don't try to acquire mLock here -- in rare circumstances this will hang. ++void OMXNodeInstance::onEvent( ++ OMX_EVENTTYPE event, OMX_U32 arg1, OMX_U32 arg2) { ++ const char *arg1String = "??"; ++ const char *arg2String = "??"; ++ ADebug::Level level = ADebug::kDebugInternalState; ++ ++ switch (event) { ++ case OMX_EventCmdComplete: ++ arg1String = asString((OMX_COMMANDTYPE)arg1); ++ switch (arg1) { ++ case OMX_CommandStateSet: ++ arg2String = asString((OMX_STATETYPE)arg2); ++ level = ADebug::kDebugState; ++ break; ++ case OMX_CommandFlush: ++ case OMX_CommandPortEnable: ++ { ++ // bump internal-state debug level for 2 input and output frames ++ Mutex::Autolock _l(mDebugLock); ++ bumpDebugLevel_l(2 /* numInputBuffers */, 2 /* numOutputBuffers */); ++ } ++ // fall through ++ default: ++ arg2String = portString(arg2); ++ } ++ break; ++ case OMX_EventError: ++ arg1String = asString((OMX_ERRORTYPE)arg1); ++ level = ADebug::kDebugLifeCycle; ++ break; ++ case OMX_EventPortSettingsChanged: ++ arg2String = asString((OMX_INDEXEXTTYPE)arg2); ++ // fall through ++ default: ++ arg1String = portString(arg1); ++ } ++ ++ CLOGI_(level, onEvent, "%s(%x), %s(%x), %s(%x)", ++ asString(event), event, arg1String, arg1, arg2String, arg2); ++ const sp& bufferSource(getGraphicBufferSource()); ++ ++ if (bufferSource != NULL ++ && event == OMX_EventCmdComplete ++ && arg1 == OMX_CommandStateSet ++ && arg2 == OMX_StateExecuting) { ++ bufferSource->omxExecuting(); ++ } ++ ++ // allow configuration if we return to the loaded state ++ if (event == OMX_EventCmdComplete ++ && arg1 == OMX_CommandStateSet ++ && arg2 == OMX_StateLoaded) { ++ mSailed = false; ++ } ++} ++ ++// static ++OMX_ERRORTYPE OMXNodeInstance::OnEvent( ++ OMX_IN OMX_HANDLETYPE /* hComponent */, ++ OMX_IN OMX_PTR pAppData, ++ OMX_IN OMX_EVENTTYPE eEvent, ++ OMX_IN OMX_U32 nData1, ++ OMX_IN OMX_U32 nData2, ++ OMX_IN OMX_PTR pEventData) { ++ if (pAppData == NULL) { ++ ALOGE("b/25884056"); ++ return OMX_ErrorBadParameter; ++ } ++ OMXNodeInstance *instance = static_cast(pAppData); ++ if (instance->mDying) { ++ return OMX_ErrorNone; ++ } ++ return instance->owner()->OnEvent( ++ instance->nodeID(), eEvent, nData1, nData2, pEventData); ++} ++ ++// static ++OMX_ERRORTYPE OMXNodeInstance::OnEmptyBufferDone( ++ OMX_IN OMX_HANDLETYPE /* hComponent */, ++ OMX_IN OMX_PTR pAppData, ++ OMX_IN OMX_BUFFERHEADERTYPE* pBuffer) { ++ if (pAppData == NULL) { ++ ALOGE("b/25884056"); ++ return OMX_ErrorBadParameter; ++ } ++ OMXNodeInstance *instance = static_cast(pAppData); ++ if (instance->mDying) { ++ return OMX_ErrorNone; ++ } ++ int fenceFd = instance->retrieveFenceFromMeta_l(pBuffer, kPortIndexOutput); ++ return instance->owner()->OnEmptyBufferDone(instance->nodeID(), ++ instance->findBufferID(pBuffer), pBuffer, fenceFd); ++} ++ ++// static ++OMX_ERRORTYPE OMXNodeInstance::OnFillBufferDone( ++ OMX_IN OMX_HANDLETYPE /* hComponent */, ++ OMX_IN OMX_PTR pAppData, ++ OMX_IN OMX_BUFFERHEADERTYPE* pBuffer) { ++ if (pAppData == NULL) { ++ ALOGE("b/25884056"); ++ return OMX_ErrorBadParameter; ++ } ++ OMXNodeInstance *instance = static_cast(pAppData); ++ if (instance->mDying) { ++ return OMX_ErrorNone; ++ } ++ int fenceFd = instance->retrieveFenceFromMeta_l(pBuffer, kPortIndexOutput); ++ return instance->owner()->OnFillBufferDone(instance->nodeID(), ++ instance->findBufferID(pBuffer), pBuffer, fenceFd); ++} ++ ++void OMXNodeInstance::addActiveBuffer(OMX_U32 portIndex, OMX::buffer_id id) { ++ ActiveBuffer active; ++ active.mPortIndex = portIndex; ++ active.mID = id; ++ mActiveBuffers.push(active); ++ ++ if (portIndex < NELEM(mNumPortBuffers)) { ++ ++mNumPortBuffers[portIndex]; ++ } ++} ++ ++void OMXNodeInstance::removeActiveBuffer( ++ OMX_U32 portIndex, OMX::buffer_id id) { ++ for (size_t i = 0; i < mActiveBuffers.size(); ++i) { ++ if (mActiveBuffers[i].mPortIndex == portIndex ++ && mActiveBuffers[i].mID == id) { ++ mActiveBuffers.removeItemsAt(i); ++ ++ if (portIndex < NELEM(mNumPortBuffers)) { ++ --mNumPortBuffers[portIndex]; ++ } ++ return; ++ } ++ } ++ ++ CLOGW("Attempt to remove an active buffer [%#x] we know nothing about...", id); ++} ++ ++void OMXNodeInstance::freeActiveBuffers() { ++ // Make sure to count down here, as freeBuffer will in turn remove ++ // the active buffer from the vector... ++ for (size_t i = mActiveBuffers.size(); i > 0;) { ++ i--; ++ freeBuffer(mActiveBuffers[i].mPortIndex, mActiveBuffers[i].mID); ++ } ++} ++ ++OMX::buffer_id OMXNodeInstance::makeBufferID(OMX_BUFFERHEADERTYPE *bufferHeader) { ++ if (bufferHeader == NULL) { ++ return 0; ++ } ++ Mutex::Autolock autoLock(mBufferIDLock); ++ OMX::buffer_id buffer; ++ do { // handle the very unlikely case of ID overflow ++ if (++mBufferIDCount == 0) { ++ ++mBufferIDCount; ++ } ++ buffer = (OMX::buffer_id)mBufferIDCount; ++ } while (mBufferIDToBufferHeader.indexOfKey(buffer) >= 0); ++ mBufferIDToBufferHeader.add(buffer, bufferHeader); ++ mBufferHeaderToBufferID.add(bufferHeader, buffer); ++ return buffer; ++} ++ ++OMX_BUFFERHEADERTYPE *OMXNodeInstance::findBufferHeader( ++ OMX::buffer_id buffer, OMX_U32 portIndex) { ++ if (buffer == 0) { ++ return NULL; ++ } ++ Mutex::Autolock autoLock(mBufferIDLock); ++ ssize_t index = mBufferIDToBufferHeader.indexOfKey(buffer); ++ if (index < 0) { ++ CLOGW("findBufferHeader: buffer %u not found", buffer); ++ return NULL; ++ } ++ OMX_BUFFERHEADERTYPE *header = mBufferIDToBufferHeader.valueAt(index); ++ BufferMeta *buffer_meta = ++ static_cast(header->pAppPrivate); ++ if (buffer_meta->getPortIndex() != portIndex) { ++ CLOGW("findBufferHeader: buffer %u found but with incorrect port index.", buffer); ++ android_errorWriteLog(0x534e4554, "28816827"); ++ return NULL; ++ } ++ return header; ++} ++ ++OMX::buffer_id OMXNodeInstance::findBufferID(OMX_BUFFERHEADERTYPE *bufferHeader) { ++ if (bufferHeader == NULL) { ++ return 0; ++ } ++ Mutex::Autolock autoLock(mBufferIDLock); ++ ssize_t index = mBufferHeaderToBufferID.indexOfKey(bufferHeader); ++ if (index < 0) { ++ CLOGW("findBufferID: bufferHeader %p not found", bufferHeader); ++ return 0; ++ } ++ return mBufferHeaderToBufferID.valueAt(index); ++} ++ ++void OMXNodeInstance::invalidateBufferID(OMX::buffer_id buffer) { ++ if (buffer == 0) { ++ return; ++ } ++ Mutex::Autolock autoLock(mBufferIDLock); ++ ssize_t index = mBufferIDToBufferHeader.indexOfKey(buffer); ++ if (index < 0) { ++ CLOGW("invalidateBufferID: buffer %u not found", buffer); ++ return; ++ } ++ mBufferHeaderToBufferID.removeItem(mBufferIDToBufferHeader.valueAt(index)); ++ mBufferIDToBufferHeader.removeItemsAt(index); ++} ++ ++} // namespace android diff --git a/media/mediaserver/Android.mk b/media/mediaserver/Android.mk index 1738df8..c2b9c1f 100644 --- a/media/mediaserver/Android.mk diff --git a/frameworks_base.patch b/frameworks_base.patch index 05d6161..cd0ee1c 100644 --- a/frameworks_base.patch +++ b/frameworks_base.patch @@ -1,3 +1,29 @@ +diff --git a/core/java/android/accounts/ChooseTypeAndAccountActivity.java b/core/java/android/accounts/ChooseTypeAndAccountActivity.java +index 133df2b..fd52616 100644 +--- a/core/java/android/accounts/ChooseTypeAndAccountActivity.java ++++ b/core/java/android/accounts/ChooseTypeAndAccountActivity.java +@@ -250,6 +250,10 @@ public class ChooseTypeAndAccountActivity extends Activity + outState.putParcelableArray(KEY_INSTANCE_STATE_EXISTING_ACCOUNTS, mExistingAccounts); + } + if (mSelectedItemIndex != SELECTED_ITEM_NONE) { ++ if (mAccounts == null) { ++ final AccountManager accountManager = AccountManager.get(this); ++ mAccounts = getAcceptableAccountChoices(accountManager); ++ } + if (mSelectedItemIndex == mAccounts.size()) { + outState.putBoolean(KEY_INSTANCE_STATE_SELECTED_ADD_ACCOUNT, true); + } else { +@@ -291,6 +295,10 @@ public class ChooseTypeAndAccountActivity extends Activity + mPendingRequest = REQUEST_NULL; + + if (resultCode == RESULT_CANCELED) { ++ if (mAccounts == null) { ++ final AccountManager accountManager = AccountManager.get(this); ++ mAccounts = getAcceptableAccountChoices(accountManager); ++ } + // if canceling out of addAccount and the original state caused us to skip this, + // finish this activity + if (mAccounts.isEmpty()) { diff --git a/libs/hwui/Android.mk b/libs/hwui/Android.mk index 366ef71..3ecd045 100644 --- a/libs/hwui/Android.mk @@ -11,3 +37,298 @@ index 366ef71..3ecd045 100644 endif # This has to be lazy-resolved because it depends on the LOCAL_MODULE_CLASS +diff --git a/libs/hwui/Snapshot.cpp b/libs/hwui/Snapshot.cpp +index 2c9c9d9..7c187fb 100644 +--- a/libs/hwui/Snapshot.cpp ++++ b/libs/hwui/Snapshot.cpp +@@ -38,6 +38,7 @@ Snapshot::Snapshot() + , mClipArea(&mClipAreaRoot) { + transform = &mTransformRoot; + region = nullptr; ++ mRelativeLightCenter.x = mRelativeLightCenter.y = mRelativeLightCenter.z = 0; + } + + /** +diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationGuts.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationGuts.java +index c497cfd..f2140f7 100644 +--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationGuts.java ++++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationGuts.java +@@ -221,16 +221,16 @@ public class NotificationGuts extends LinearLayout implements TunerService.Tunab + } + + private int getSelectedImportance() { +- if (mSeekBar!= null && mSeekBar.isShown()) { ++ if (mSeekBar != null && mSeekBar.isShown()) { + if (mSeekBar.isEnabled()) { + return mSeekBar.getProgress(); + } else { + return Ranking.IMPORTANCE_UNSPECIFIED; + } + } else { +- if (mBlock.isChecked()) { ++ if (mBlock != null && mBlock.isChecked()) { + return Ranking.IMPORTANCE_NONE; +- } else if (mSilent.isChecked()) { ++ } else if (mSilent != null && mSilent.isChecked()) { + return Ranking.IMPORTANCE_LOW; + } else { + return Ranking.IMPORTANCE_UNSPECIFIED; +diff --git a/packages/SystemUI/src/com/android/systemui/tuner/TunerFragment.java b/packages/SystemUI/src/com/android/systemui/tuner/TunerFragment.java +index 70f2fdc..ba50161 100644 +--- a/packages/SystemUI/src/com/android/systemui/tuner/TunerFragment.java ++++ b/packages/SystemUI/src/com/android/systemui/tuner/TunerFragment.java +@@ -59,7 +59,10 @@ public class TunerFragment extends PreferenceFragment { + @Override + public void onActivityCreated(Bundle savedInstanceState) { + super.onActivityCreated(savedInstanceState); +- getActivity().getActionBar().setDisplayHomeAsUpEnabled(true); ++ ++ if (getActivity().getActionBar() != null) { ++ getActivity().getActionBar().setDisplayHomeAsUpEnabled(true); ++ } + } + + @Override +diff --git a/services/core/java/com/android/server/AppOpsService.java b/services/core/java/com/android/server/AppOpsService.java +index b5b0cd8..a5c10fb 100644 +--- a/services/core/java/com/android/server/AppOpsService.java ++++ b/services/core/java/com/android/server/AppOpsService.java +@@ -597,7 +597,6 @@ public class AppOpsService extends IAppOpsService.Stub { + ArrayList repCbs = null; + code = AppOpsManager.opToSwitch(code); + synchronized (this) { +- UidState uidState = getUidStateLocked(uid, false); + Op op = getOpLocked(code, uid, packageName, true); + if (op != null) { + if (op.mode != mode) { +@@ -973,7 +972,7 @@ public class AppOpsService extends IAppOpsService.Stub { + public int checkPackage(int uid, String packageName) { + Preconditions.checkNotNull(packageName); + synchronized (this) { +- if (getOpsRawLocked(uid, packageName, true) != null) { ++ if (packageName != null && getOpsRawLocked(uid, packageName, true) != null) { + return AppOpsManager.MODE_ALLOWED; + } else { + return AppOpsManager.MODE_ERRORED; +@@ -1533,8 +1532,6 @@ public class AppOpsService extends IAppOpsService.Stub { + + void writeState() { + synchronized (mFile) { +- List allOps = getPackagesForOps(null); +- + FileOutputStream stream; + try { + stream = mFile.startWrite(); +@@ -1543,15 +1540,33 @@ public class AppOpsService extends IAppOpsService.Stub { + return; + } + ++ SparseArray outUidStates = null; ++ synchronized (this) { ++ final int uidStateCount = mUidStates.size(); ++ for (int i = 0; i < uidStateCount; i++) { ++ UidState uidState = mUidStates.valueAt(i); ++ SparseIntArray opModes = uidState.opModes; ++ if (opModes != null && opModes.size() > 0) { ++ UidState outUidState = new UidState(uidState.uid); ++ outUidState.opModes = opModes.clone(); ++ if (outUidStates == null) { ++ outUidStates = new SparseArray<>(); ++ } ++ outUidStates.put(mUidStates.keyAt(i), outUidState); ++ } ++ } ++ } ++ List allOps = getPackagesForOps(null); ++ + try { + XmlSerializer out = new FastXmlSerializer(); + out.setOutput(stream, StandardCharsets.UTF_8.name()); + out.startDocument(null, true); + out.startTag(null, "app-ops"); + +- final int uidStateCount = mUidStates.size(); ++ final int uidStateCount = outUidStates != null ? outUidStates.size() : 0; + for (int i = 0; i < uidStateCount; i++) { +- UidState uidState = mUidStates.valueAt(i); ++ UidState uidState = outUidStates.valueAt(i); + if (uidState.opModes != null && uidState.opModes.size() > 0) { + out.startTag(null, "uid"); + out.attribute(null, "n", Integer.toString(uidState.uid)); +diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java +index 40f3608..cf99c26 100644 +--- a/services/core/java/com/android/server/am/ActivityManagerService.java ++++ b/services/core/java/com/android/server/am/ActivityManagerService.java +@@ -9576,7 +9576,7 @@ public final class ActivityManagerService extends ActivityManagerNative + for (int i = 0; i < procsToKill.size(); i++) { + ProcessRecord pr = procsToKill.get(i); + if (pr.setSchedGroup == ProcessList.SCHED_GROUP_BACKGROUND +- && pr.curReceiver == null) { ++ && pr.curReceivers.isEmpty()) { + pr.kill("remove task", true); + } else { + // We delay killing processes that are not in the background or running a receiver. +@@ -19146,26 +19146,28 @@ public final class ActivityManagerService extends ActivityManagerNative + // LIFETIME MANAGEMENT + // ========================================================= + +- // Returns which broadcast queue the app is the current [or imminent] receiver +- // on, or 'null' if the app is not an active broadcast recipient. +- private BroadcastQueue isReceivingBroadcast(ProcessRecord app) { +- BroadcastRecord r = app.curReceiver; +- if (r != null) { +- return r.queue; ++ // Returns whether the app is receiving broadcast. ++ // If receiving, fetch all broadcast queues which the app is ++ // the current [or imminent] receiver on. ++ private boolean isReceivingBroadcastLocked(ProcessRecord app, ++ ArraySet receivingQueues) { ++ if (!app.curReceivers.isEmpty()) { ++ for (BroadcastRecord r : app.curReceivers) { ++ receivingQueues.add(r.queue); ++ } ++ return true; + } + + // It's not the current receiver, but it might be starting up to become one +- synchronized (this) { +- for (BroadcastQueue queue : mBroadcastQueues) { +- r = queue.mPendingBroadcast; +- if (r != null && r.curApp == app) { +- // found it; report which queue it's in +- return queue; +- } ++ for (BroadcastQueue queue : mBroadcastQueues) { ++ final BroadcastRecord r = queue.mPendingBroadcast; ++ if (r != null && r.curApp == app) { ++ // found it; report which queue it's in ++ receivingQueues.add(queue); + } + } + +- return null; ++ return !receivingQueues.isEmpty(); + } + + Association startAssociationLocked(int sourceUid, String sourceProcess, int sourceState, +@@ -19332,7 +19334,7 @@ public final class ActivityManagerService extends ActivityManagerNative + int schedGroup; + int procState; + boolean foregroundActivities = false; +- BroadcastQueue queue; ++ final ArraySet queues = new ArraySet(); + if (app == TOP_APP) { + // The last app on the list is the foreground app. + adj = ProcessList.FOREGROUND_APP_ADJ; +@@ -19346,13 +19348,13 @@ public final class ActivityManagerService extends ActivityManagerNative + schedGroup = ProcessList.SCHED_GROUP_DEFAULT; + app.adjType = "instrumentation"; + procState = ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE; +- } else if ((queue = isReceivingBroadcast(app)) != null) { ++ } else if (isReceivingBroadcastLocked(app, queues)) { + // An app that is currently receiving a broadcast also + // counts as being in the foreground for OOM killer purposes. + // It's placed in a sched group based on the nature of the + // broadcast as reflected by which queue it's active in. + adj = ProcessList.FOREGROUND_APP_ADJ; +- schedGroup = (queue == mFgBroadcastQueue) ++ schedGroup = (queues.contains(mFgBroadcastQueue)) + ? ProcessList.SCHED_GROUP_DEFAULT : ProcessList.SCHED_GROUP_BACKGROUND; + app.adjType = "broadcast"; + procState = ActivityManager.PROCESS_STATE_RECEIVER; +@@ -20363,7 +20365,7 @@ public final class ActivityManagerService extends ActivityManagerNative + if (DEBUG_SWITCH || DEBUG_OOM_ADJ) Slog.v(TAG_OOM_ADJ, + "Setting sched group of " + app.processName + + " to " + app.curSchedGroup); +- if (app.waitingToKill != null && app.curReceiver == null ++ if (app.waitingToKill != null && app.curReceivers.isEmpty() + && app.setSchedGroup == ProcessList.SCHED_GROUP_BACKGROUND) { + app.kill(app.waitingToKill, true); + success = false; +@@ -21298,7 +21300,7 @@ public final class ActivityManagerService extends ActivityManagerNative + for (i=mRemovedProcesses.size()-1; i>=0; i--) { + final ProcessRecord app = mRemovedProcesses.get(i); + if (app.activities.size() == 0 +- && app.curReceiver == null && app.services.size() == 0) { ++ && app.curReceivers.isEmpty() && app.services.size() == 0) { + Slog.i( + TAG, "Exiting empty application process " + + app.toShortString() + " (" +diff --git a/services/core/java/com/android/server/am/BroadcastQueue.java b/services/core/java/com/android/server/am/BroadcastQueue.java +index f78f29c..1536235 100644 +--- a/services/core/java/com/android/server/am/BroadcastQueue.java ++++ b/services/core/java/com/android/server/am/BroadcastQueue.java +@@ -265,7 +265,7 @@ public final class BroadcastQueue { + + r.receiver = app.thread.asBinder(); + r.curApp = app; +- app.curReceiver = r; ++ app.curReceivers.add(r); + app.forceProcessStateUpTo(ActivityManager.PROCESS_STATE_RECEIVER); + mService.updateLruProcessLocked(app, false, null); + mService.updateOomAdjLocked(); +@@ -293,7 +293,7 @@ public final class BroadcastQueue { + "Process cur broadcast " + r + ": NOT STARTED!"); + r.receiver = null; + r.curApp = null; +- app.curReceiver = null; ++ app.curReceivers.remove(r); + } + } + } +@@ -394,8 +394,8 @@ public final class BroadcastQueue { + } + r.receiver = null; + r.intent.setComponent(null); +- if (r.curApp != null && r.curApp.curReceiver == r) { +- r.curApp.curReceiver = null; ++ if (r.curApp != null && r.curApp.curReceivers.contains(r)) { ++ r.curApp.curReceivers.remove(r); + } + if (r.curFilter != null) { + r.curFilter.receiverList.curBroadcast = null; +@@ -648,7 +648,7 @@ public final class BroadcastQueue { + // things that directly call the IActivityManager API, which + // are already core system stuff so don't matter for this. + r.curApp = filter.receiverList.app; +- filter.receiverList.app.curReceiver = r; ++ filter.receiverList.app.curReceivers.add(r); + mService.updateOomAdjLocked(r.curApp); + } + } +@@ -676,7 +676,7 @@ public final class BroadcastQueue { + r.curFilter = null; + filter.receiverList.curBroadcast = null; + if (filter.receiverList.app != null) { +- filter.receiverList.app.curReceiver = null; ++ filter.receiverList.app.curReceivers.remove(r); + } + } + } +diff --git a/services/core/java/com/android/server/am/ProcessRecord.java b/services/core/java/com/android/server/am/ProcessRecord.java +index 3fffefb..49fe79c 100644 +--- a/services/core/java/com/android/server/am/ProcessRecord.java ++++ b/services/core/java/com/android/server/am/ProcessRecord.java +@@ -143,7 +143,7 @@ final class ProcessRecord { + Bundle instrumentationArguments;// as given to us + ComponentName instrumentationResultClass;// copy of instrumentationClass + boolean usingWrapper; // Set to true when process was launched with a wrapper attached +- BroadcastRecord curReceiver;// receiver currently running in the app ++ final ArraySet curReceivers = new ArraySet();// receivers currently running in the app + long lastWakeTime; // How long proc held wake lock at last check + long lastCpuTime; // How long proc has run CPU at last check + long curCpuTime; // How long proc has run CPU most recently +@@ -427,8 +427,11 @@ final class ProcessRecord { + pw.print(prefix); pw.print(" - "); pw.println(conProviders.get(i).toShortString()); + } + } +- if (curReceiver != null) { +- pw.print(prefix); pw.print("curReceiver="); pw.println(curReceiver); ++ if (!curReceivers.isEmpty()) { ++ pw.print(prefix); pw.println("Current Receivers:"); ++ for (int i=0; i < curReceivers.size(); i++) { ++ pw.print(prefix); pw.print(" - "); pw.println(curReceivers.valueAt(i)); ++ } + } + if (receivers.size() > 0) { + pw.print(prefix); pw.println("Receivers:"); diff --git a/packages_apps_music.patch b/packages_apps_music.patch index 4f8a363..31640ce 100644 --- a/packages_apps_music.patch +++ b/packages_apps_music.patch @@ -1,5 +1,5 @@ diff --git a/src/com/android/music/MediaPlaybackService.java b/src/com/android/music/MediaPlaybackService.java -index 25d60c7..be8142f 100644 +index 25d60c7..783c1a6 100644 --- a/src/com/android/music/MediaPlaybackService.java +++ b/src/com/android/music/MediaPlaybackService.java @@ -335,7 +335,7 @@ public class MediaPlaybackService extends Service { @@ -7,7 +7,20 @@ index 25d60c7..be8142f 100644 mRemoteControlClient.setTransportControlFlags(flags); - mPreferences = getSharedPreferences("Music", MODE_WORLD_READABLE | MODE_WORLD_WRITEABLE); -+ mPreferences = getSharedPreferences("Music", MODE_PRIVATE); ++ mPreferences = getSharedPreferences("Music", Context.MODE_PRIVATE); mCardId = MusicUtils.getCardId(this); registerExternalStorageListener(); +diff --git a/src/com/android/music/TouchInterceptor.java b/src/com/android/music/TouchInterceptor.java +index 90b208a..fda1e3a 100644 +--- a/src/com/android/music/TouchInterceptor.java ++++ b/src/com/android/music/TouchInterceptor.java +@@ -77,7 +77,7 @@ public class TouchInterceptor extends ListView { + + public TouchInterceptor(Context context, AttributeSet attrs) { + super(context, attrs); +- SharedPreferences pref = context.getSharedPreferences("Music", 3); ++ SharedPreferences pref = context.getSharedPreferences("Music", Context.MODE_PRIVATE); + mRemoveMode = pref.getInt("deletemode", -1); + mTouchSlop = ViewConfiguration.get(context).getScaledTouchSlop(); + Resources res = getResources(); From 7721795def21c7c2611f65792d14170f5bcd4396 Mon Sep 17 00:00:00 2001 From: AndDiSa Date: Tue, 6 Dec 2016 18:14:55 +0100 Subject: [PATCH 051/159] update to android-7.1.1_r1 Change-Id: Ic72f148837fb845d34439adabc2dc7e499da4844 --- default.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/default.xml b/default.xml index e96bac4..e899af0 100644 --- a/default.xml +++ b/default.xml @@ -7,7 +7,7 @@ fetch="https://github.com/AndDiSa/" /> - From 0e7b68e177b8096d003397aedd6b19c82c2f4d53 Mon Sep 17 00:00:00 2001 From: AndDiSa Date: Wed, 7 Dec 2016 17:55:44 +0100 Subject: [PATCH 052/159] update to android-7.1.1_r4 Change-Id: Ifa467284d1634a8c904e5286e156606fcbab45d6 --- default.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/default.xml b/default.xml index e899af0..f213df5 100644 --- a/default.xml +++ b/default.xml @@ -7,7 +7,7 @@ fetch="https://github.com/AndDiSa/" /> - From d7d40f6ffdc6113904a7926e8bb77a57c37dade6 Mon Sep 17 00:00:00 2001 From: AndDiSa Date: Wed, 7 Dec 2016 22:16:34 +0100 Subject: [PATCH 053/159] update patches Change-Id: I30b75c2bd96612ce358736594abc21cefa74cb2b --- build.patch | 28103 ++++++ frameworks_av.patch | 5904 +- frameworks_base.patch | 193082 ++++++++++++++++++++++++++++++++++++- frameworks_native.patch | 5121 +- hardware_ril.patch | 66 +- system_core.patch | 1208 +- system_sepolicy.patch | 88 + 7 files changed, 230967 insertions(+), 2605 deletions(-) diff --git a/build.patch b/build.patch index d6ed881..bfec89e 100644 --- a/build.patch +++ b/build.patch @@ -1,3 +1,35 @@ +diff --git a/core/Makefile b/core/Makefile +index 2031132..5badde5 100644 +--- a/core/Makefile ++++ b/core/Makefile +@@ -1383,6 +1383,8 @@ $(INSTALLED_USERDATATARBALL_TARGET): PRIVATE_USERDATA_TAR := $(userdata_tar) + $(INSTALLED_USERDATATARBALL_TARGET): $(FS_GET_STATS) $(INTERNAL_USERDATAIMAGE_FILES) + $(build-userdatatarball-target) + ++$(call dist-for-goals,userdatatarball,$(INSTALLED_USERDATATARBALL_TARGET)) ++ + .PHONY: userdatatarball-nodeps + userdatatarball-nodeps: $(FS_GET_STATS) + $(build-userdatatarball-target) +@@ -2039,7 +2041,7 @@ PROGUARD_DICT_ZIP := $(PRODUCT_OUT)/$(TARGET_PRODUCT)-proguard-dict-$(FILE_NAME_ + # the dependency will be set up later in build/core/main.mk. + $(PROGUARD_DICT_ZIP) : + @echo "Packaging Proguard obfuscation dictionary files." +- $(hide) dict_files=`find $(TARGET_OUT_COMMON_INTERMEDIATES)/APPS -name proguard_dictionary`; \ ++ $(hide) dict_files=`find $(TARGET_OUT_COMMON_INTERMEDIATES)/APPS -name proguard_dictionary -o -name jack_dictionary`; \ + if [ -n "$$dict_files" ]; then \ + unobfuscated_jars=$${dict_files//proguard_dictionary/classes.jar}; \ + zip -qX $@ $$dict_files $$unobfuscated_jars; \ +diff --git a/core/build_id.mk b/core/build_id.mk +index c8d331d..c3d6c40 100644 +--- a/core/build_id.mk ++++ b/core/build_id.mk +@@ -18,4 +18,4 @@ + # (like "CRB01"). It must be a single word, and is + # capitalized by convention. + +-export BUILD_ID=NDE63U ++export BUILD_ID=NMF26O diff --git a/core/main.mk b/core/main.mk index a612f83..921eb32 100644 --- a/core/main.mk @@ -11,6 +43,18 @@ index a612f83..921eb32 100644 endif +diff --git a/core/pathmap.mk b/core/pathmap.mk +index edc584b..effc878 100644 +--- a/core/pathmap.mk ++++ b/core/pathmap.mk +@@ -121,6 +121,7 @@ FRAMEWORKS_SUPPORT_SUBDIRS := \ + design \ + percent \ + recommendation \ ++ transition \ + v7/preference \ + v14/preference \ + v17/preference-leanback \ diff --git a/core/tasks/kernel.mk b/core/tasks/kernel.mk new file mode 100644 index 0000000..9c12bc0 @@ -213,3 +257,28062 @@ index 0000000..9c12bc0 + +ALL_PREBUILT += $(INSTALLED_KERNEL_TARGET) +endif +diff --git a/core/version_defaults.mk b/core/version_defaults.mk +index 47dc01c..2c8a21f 100644 +--- a/core/version_defaults.mk ++++ b/core/version_defaults.mk +@@ -43,7 +43,7 @@ ifeq "" "$(PLATFORM_VERSION)" + # which is the version that we reveal to the end user. + # Update this value when the platform version changes (rather + # than overriding it somewhere else). Can be an arbitrary string. +- PLATFORM_VERSION := 7.1 ++ PLATFORM_VERSION := 7.1.1 + endif + + ifeq "" "$(PLATFORM_SDK_VERSION)" +@@ -114,7 +114,7 @@ ifeq "" "$(PLATFORM_SECURITY_PATCH)" + # It must be of the form "YYYY-MM-DD" on production devices. + # It must match one of the Android Security Patch Level strings of the Public Security Bulletins. + # If there is no $PLATFORM_SECURITY_PATCH set, keep it empty. +- PLATFORM_SECURITY_PATCH := 2016-11-05 ++ PLATFORM_SECURITY_PATCH := 2016-12-05 + endif + + ifeq "" "$(PLATFORM_BASE_OS)" +diff --git a/core/version_defaults_BACKUP_20377.mk b/core/version_defaults_BACKUP_20377.mk +new file mode 100644 +index 0000000..eb97b11 +--- /dev/null ++++ b/core/version_defaults_BACKUP_20377.mk +@@ -0,0 +1,164 @@ ++# ++# 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. ++# ++ ++# ++# Handle various build version information. ++# ++# Guarantees that the following are defined: ++# PLATFORM_VERSION ++# PLATFORM_SDK_VERSION ++# PLATFORM_VERSION_CODENAME ++# DEFAULT_APP_TARGET_SDK ++# BUILD_ID ++# BUILD_NUMBER ++# BUILD_DATETIME ++# PLATFORM_SECURITY_PATCH ++# ++ ++# Look for an optional file containing overrides of the defaults, ++# but don't cry if we don't find it. We could just use -include, but ++# the build.prop target also wants INTERNAL_BUILD_ID_MAKEFILE to be set ++# if the file exists. ++# ++INTERNAL_BUILD_ID_MAKEFILE := $(wildcard $(BUILD_SYSTEM)/build_id.mk) ++ifneq "" "$(INTERNAL_BUILD_ID_MAKEFILE)" ++ include $(INTERNAL_BUILD_ID_MAKEFILE) ++endif ++ ++ifeq "" "$(PLATFORM_VERSION)" ++ # This is the canonical definition of the platform version, ++ # which is the version that we reveal to the end user. ++ # Update this value when the platform version changes (rather ++ # than overriding it somewhere else). Can be an arbitrary string. ++ PLATFORM_VERSION := 7.1.1 ++endif ++ ++ifeq "" "$(PLATFORM_SDK_VERSION)" ++ # This is the canonical definition of the SDK version, which defines ++ # the set of APIs and functionality available in the platform. It ++ # is a single integer that increases monotonically as updates to ++ # the SDK are released. It should only be incremented when the APIs for ++ # the new release are frozen (so that developers don't write apps against ++ # intermediate builds). During development, this number remains at the ++ # SDK version the branch is based on and PLATFORM_VERSION_CODENAME holds ++ # the code-name of the new development work. ++ PLATFORM_SDK_VERSION := 25 ++endif ++ ++ifeq "" "$(PLATFORM_JACK_MIN_SDK_VERSION)" ++ # This is definition of the min SDK version given to Jack for the current ++ # platform. For released version it should be the same as ++ # PLATFORM_SDK_VERSION. During development, this number may be incremented ++ # before PLATFORM_SDK_VERSION if the plateform starts to add new java ++ # language supports. ++ PLATFORM_JACK_MIN_SDK_VERSION := 25 ++endif ++ ++ifeq "" "$(PLATFORM_VERSION_CODENAME)" ++ # This is the current development code-name, if the build is not a final ++ # release build. If this is a final release build, it is simply "REL". ++ PLATFORM_VERSION_CODENAME := REL ++ ++ # This is all of the development codenames that are active. Should be either ++ # the same as PLATFORM_VERSION_CODENAME or a comma-separated list of additional ++ # codenames after PLATFORM_VERSION_CODENAME. ++ PLATFORM_VERSION_ALL_CODENAMES := $(PLATFORM_VERSION_CODENAME) ++endif ++ ++ifeq "REL" "$(PLATFORM_VERSION_CODENAME)" ++ PLATFORM_PREVIEW_SDK_VERSION := 0 ++else ++ ifeq "" "$(PLATFORM_PREVIEW_SDK_VERSION)" ++ # This is the definition of a preview SDK version over and above the current ++ # platform SDK version. Unlike the platform SDK version, a higher value ++ # for preview SDK version does NOT mean that all prior preview APIs are ++ # included. Packages reading this value to determine compatibility with ++ # known APIs should check that this value is precisely equal to the preview ++ # SDK version the package was built for, otherwise it should fall back to ++ # assuming the device can only support APIs as of the previous official ++ # public release. ++ # This value will always be 0 for release builds. ++ PLATFORM_PREVIEW_SDK_VERSION := 0 ++ endif ++endif ++ ++ifeq "" "$(DEFAULT_APP_TARGET_SDK)" ++ # This is the default minSdkVersion and targetSdkVersion to use for ++ # all .apks created by the build system. It can be overridden by explicitly ++ # setting these in the .apk's AndroidManifest.xml. It is either the code ++ # name of the development build or, if this is a release build, the official ++ # SDK version of this release. ++ ifeq "REL" "$(PLATFORM_VERSION_CODENAME)" ++ DEFAULT_APP_TARGET_SDK := $(PLATFORM_SDK_VERSION) ++ else ++ DEFAULT_APP_TARGET_SDK := $(PLATFORM_VERSION_CODENAME) ++ endif ++endif ++ ++ifeq "" "$(PLATFORM_SECURITY_PATCH)" ++ # Used to indicate the security patch that has been applied to the device. ++ # It must signify that the build includes all security patches issued up through the designated Android Public Security Bulletin. ++ # It must be of the form "YYYY-MM-DD" on production devices. ++ # It must match one of the Android Security Patch Level strings of the Public Security Bulletins. ++ # If there is no $PLATFORM_SECURITY_PATCH set, keep it empty. ++<<<<<<< HEAD ++ PLATFORM_SECURITY_PATCH := 2016-11-05 ++======= ++ PLATFORM_SECURITY_PATCH := 2016-12-05 ++>>>>>>> android-7.1.1_r1 ++endif ++ ++ifeq "" "$(PLATFORM_BASE_OS)" ++ # Used to indicate the base os applied to the device. ++ # Can be an arbitrary string, but must be a single word. ++ # ++ # If there is no $PLATFORM_BASE_OS set, keep it empty. ++ PLATFORM_BASE_OS := ++endif ++ ++ifeq "" "$(BUILD_ID)" ++ # Used to signify special builds. E.g., branches and/or releases, ++ # like "M5-RC7". Can be an arbitrary string, but must be a single ++ # word and a valid file name. ++ # ++ # If there is no BUILD_ID set, make it obvious. ++ BUILD_ID := UNKNOWN ++endif ++ ++ifeq "" "$(BUILD_DATETIME)" ++ # Used to reproduce builds by setting the same time. Must be the number ++ # of seconds since the Epoch. ++ BUILD_DATETIME := $(shell date +%s) ++endif ++ ++ifneq (,$(findstring Darwin,$(shell uname -sm))) ++DATE := date -r $(BUILD_DATETIME) ++else ++DATE := date -d @$(BUILD_DATETIME) ++endif ++ ++ifeq "" "$(BUILD_NUMBER)" ++ # BUILD_NUMBER should be set to the source control value that ++ # represents the current state of the source code. E.g., a ++ # perforce changelist number or a git hash. Can be an arbitrary string ++ # (to allow for source control that uses something other than numbers), ++ # but must be a single word and a valid file name. ++ # ++ # If no BUILD_NUMBER is set, create a useful "I am an engineering build ++ # from this date/time" value. Make it start with a non-digit so that ++ # anyone trying to parse it as an integer will probably get "0". ++ BUILD_NUMBER := eng.$(shell echo $${USER:0:6}).$(shell $(DATE) +%Y%m%d.%H%M%S) ++endif +diff --git a/core/version_defaults_BASE_20377.mk b/core/version_defaults_BASE_20377.mk +new file mode 100644 +index 0000000..b0dfc75 +--- /dev/null ++++ b/core/version_defaults_BASE_20377.mk +@@ -0,0 +1,168 @@ ++# ++# 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. ++# ++ ++# ++# Handle various build version information. ++# ++# Guarantees that the following are defined: ++# PLATFORM_VERSION ++# PLATFORM_SDK_VERSION ++# PLATFORM_VERSION_CODENAME ++# DEFAULT_APP_TARGET_SDK ++# BUILD_ID ++# BUILD_NUMBER ++# BUILD_DATETIME ++# PLATFORM_SECURITY_PATCH ++# ++ ++# Look for an optional file containing overrides of the defaults, ++# but don't cry if we don't find it. We could just use -include, but ++# the build.prop target also wants INTERNAL_BUILD_ID_MAKEFILE to be set ++# if the file exists. ++# ++INTERNAL_BUILD_ID_MAKEFILE := $(wildcard $(BUILD_SYSTEM)/build_id.mk) ++ifneq "" "$(INTERNAL_BUILD_ID_MAKEFILE)" ++ include $(INTERNAL_BUILD_ID_MAKEFILE) ++endif ++ ++ifeq "" "$(PLATFORM_VERSION)" ++ # This is the canonical definition of the platform version, ++ # which is the version that we reveal to the end user. ++ # Update this value when the platform version changes (rather ++ # than overriding it somewhere else). Can be an arbitrary string. ++ PLATFORM_VERSION := 7.1 ++endif ++ ++ifeq "" "$(PLATFORM_SDK_VERSION)" ++ # This is the canonical definition of the SDK version, which defines ++ # the set of APIs and functionality available in the platform. It ++ # is a single integer that increases monotonically as updates to ++ # the SDK are released. It should only be incremented when the APIs for ++ # the new release are frozen (so that developers don't write apps against ++ # intermediate builds). During development, this number remains at the ++ # SDK version the branch is based on and PLATFORM_VERSION_CODENAME holds ++ # the code-name of the new development work. ++ PLATFORM_SDK_VERSION := 25 ++endif ++ ++ifeq "" "$(PLATFORM_JACK_MIN_SDK_VERSION)" ++ # This is definition of the min SDK version given to Jack for the current ++ # platform. For released version it should be the same as ++ # PLATFORM_SDK_VERSION. During development, this number may be incremented ++ # before PLATFORM_SDK_VERSION if the plateform starts to add new java ++ # language supports. ++ PLATFORM_JACK_MIN_SDK_VERSION := 25 ++endif ++ ++ifeq "" "$(PLATFORM_VERSION_CODENAME)" ++ # This is the current development code-name, if the build is not a final ++ # release build. If this is a final release build, it is simply "REL". ++ PLATFORM_VERSION_CODENAME := REL ++ ++ # This is all of the development codenames that are active. Should be either ++ # the same as PLATFORM_VERSION_CODENAME or a comma-separated list of additional ++ # codenames after PLATFORM_VERSION_CODENAME. ++ PLATFORM_VERSION_ALL_CODENAMES := $(PLATFORM_VERSION_CODENAME) ++endif ++ ++ifeq "REL" "$(PLATFORM_VERSION_CODENAME)" ++ PLATFORM_PREVIEW_SDK_VERSION := 0 ++else ++ ifeq "" "$(PLATFORM_PREVIEW_SDK_VERSION)" ++ # This is the definition of a preview SDK version over and above the current ++ # platform SDK version. Unlike the platform SDK version, a higher value ++ # for preview SDK version does NOT mean that all prior preview APIs are ++ # included. Packages reading this value to determine compatibility with ++ # known APIs should check that this value is precisely equal to the preview ++ # SDK version the package was built for, otherwise it should fall back to ++ # assuming the device can only support APIs as of the previous official ++ # public release. ++ # This value will always be 0 for release builds. ++ PLATFORM_PREVIEW_SDK_VERSION := 0 ++ endif ++endif ++ ++ifeq "" "$(DEFAULT_APP_TARGET_SDK)" ++ # This is the default minSdkVersion and targetSdkVersion to use for ++ # all .apks created by the build system. It can be overridden by explicitly ++ # setting these in the .apk's AndroidManifest.xml. It is either the code ++ # name of the development build or, if this is a release build, the official ++ # SDK version of this release. ++ ifeq "REL" "$(PLATFORM_VERSION_CODENAME)" ++ DEFAULT_APP_TARGET_SDK := $(PLATFORM_SDK_VERSION) ++ else ++ DEFAULT_APP_TARGET_SDK := $(PLATFORM_VERSION_CODENAME) ++ endif ++endif ++ ++ifeq "" "$(PLATFORM_SECURITY_PATCH)" ++<<<<<<< Temporary merge branch 1 ++ # Used to indicate the security patch that has been applied to the device. ++ # Must be of the form "YYYY-MM-DD" on production devices. ++ # ++ # If there is no $PLATFORM_SECURITY_PATCH set, keep it empty. ++ PLATFORM_SECURITY_PATCH := 2016-10-05 ++======= ++ # Used to indicate the security patch that has been applied to the device. ++ # It must signify that the build includes all security patches issued up through the designated Android Public Security Bulletin. ++ # It must be of the form "YYYY-MM-DD" on production devices. ++ # It must match one of the Android Security Patch Level strings of the Public Security Bulletins. ++ # If there is no $PLATFORM_SECURITY_PATCH set, keep it empty. ++ PLATFORM_SECURITY_PATCH := 2016-10-05 ++>>>>>>> Temporary merge branch 2 ++endif ++ ++ifeq "" "$(PLATFORM_BASE_OS)" ++ # Used to indicate the base os applied to the device. ++ # Can be an arbitrary string, but must be a single word. ++ # ++ # If there is no $PLATFORM_BASE_OS set, keep it empty. ++ PLATFORM_BASE_OS := ++endif ++ ++ifeq "" "$(BUILD_ID)" ++ # Used to signify special builds. E.g., branches and/or releases, ++ # like "M5-RC7". Can be an arbitrary string, but must be a single ++ # word and a valid file name. ++ # ++ # If there is no BUILD_ID set, make it obvious. ++ BUILD_ID := UNKNOWN ++endif ++ ++ifeq "" "$(BUILD_DATETIME)" ++ # Used to reproduce builds by setting the same time. Must be the number ++ # of seconds since the Epoch. ++ BUILD_DATETIME := $(shell date +%s) ++endif ++ ++ifneq (,$(findstring Darwin,$(shell uname -sm))) ++DATE := date -r $(BUILD_DATETIME) ++else ++DATE := date -d @$(BUILD_DATETIME) ++endif ++ ++ifeq "" "$(BUILD_NUMBER)" ++ # BUILD_NUMBER should be set to the source control value that ++ # represents the current state of the source code. E.g., a ++ # perforce changelist number or a git hash. Can be an arbitrary string ++ # (to allow for source control that uses something other than numbers), ++ # but must be a single word and a valid file name. ++ # ++ # If no BUILD_NUMBER is set, create a useful "I am an engineering build ++ # from this date/time" value. Make it start with a non-digit so that ++ # anyone trying to parse it as an integer will probably get "0". ++ BUILD_NUMBER := eng.$(shell echo $${USER:0:6}).$(shell $(DATE) +%Y%m%d.%H%M%S) ++endif +diff --git a/core/version_defaults_LOCAL_20377.mk b/core/version_defaults_LOCAL_20377.mk +new file mode 100644 +index 0000000..47dc01c +--- /dev/null ++++ b/core/version_defaults_LOCAL_20377.mk +@@ -0,0 +1,160 @@ ++# ++# 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. ++# ++ ++# ++# Handle various build version information. ++# ++# Guarantees that the following are defined: ++# PLATFORM_VERSION ++# PLATFORM_SDK_VERSION ++# PLATFORM_VERSION_CODENAME ++# DEFAULT_APP_TARGET_SDK ++# BUILD_ID ++# BUILD_NUMBER ++# BUILD_DATETIME ++# PLATFORM_SECURITY_PATCH ++# ++ ++# Look for an optional file containing overrides of the defaults, ++# but don't cry if we don't find it. We could just use -include, but ++# the build.prop target also wants INTERNAL_BUILD_ID_MAKEFILE to be set ++# if the file exists. ++# ++INTERNAL_BUILD_ID_MAKEFILE := $(wildcard $(BUILD_SYSTEM)/build_id.mk) ++ifneq "" "$(INTERNAL_BUILD_ID_MAKEFILE)" ++ include $(INTERNAL_BUILD_ID_MAKEFILE) ++endif ++ ++ifeq "" "$(PLATFORM_VERSION)" ++ # This is the canonical definition of the platform version, ++ # which is the version that we reveal to the end user. ++ # Update this value when the platform version changes (rather ++ # than overriding it somewhere else). Can be an arbitrary string. ++ PLATFORM_VERSION := 7.1 ++endif ++ ++ifeq "" "$(PLATFORM_SDK_VERSION)" ++ # This is the canonical definition of the SDK version, which defines ++ # the set of APIs and functionality available in the platform. It ++ # is a single integer that increases monotonically as updates to ++ # the SDK are released. It should only be incremented when the APIs for ++ # the new release are frozen (so that developers don't write apps against ++ # intermediate builds). During development, this number remains at the ++ # SDK version the branch is based on and PLATFORM_VERSION_CODENAME holds ++ # the code-name of the new development work. ++ PLATFORM_SDK_VERSION := 25 ++endif ++ ++ifeq "" "$(PLATFORM_JACK_MIN_SDK_VERSION)" ++ # This is definition of the min SDK version given to Jack for the current ++ # platform. For released version it should be the same as ++ # PLATFORM_SDK_VERSION. During development, this number may be incremented ++ # before PLATFORM_SDK_VERSION if the plateform starts to add new java ++ # language supports. ++ PLATFORM_JACK_MIN_SDK_VERSION := 25 ++endif ++ ++ifeq "" "$(PLATFORM_VERSION_CODENAME)" ++ # This is the current development code-name, if the build is not a final ++ # release build. If this is a final release build, it is simply "REL". ++ PLATFORM_VERSION_CODENAME := REL ++ ++ # This is all of the development codenames that are active. Should be either ++ # the same as PLATFORM_VERSION_CODENAME or a comma-separated list of additional ++ # codenames after PLATFORM_VERSION_CODENAME. ++ PLATFORM_VERSION_ALL_CODENAMES := $(PLATFORM_VERSION_CODENAME) ++endif ++ ++ifeq "REL" "$(PLATFORM_VERSION_CODENAME)" ++ PLATFORM_PREVIEW_SDK_VERSION := 0 ++else ++ ifeq "" "$(PLATFORM_PREVIEW_SDK_VERSION)" ++ # This is the definition of a preview SDK version over and above the current ++ # platform SDK version. Unlike the platform SDK version, a higher value ++ # for preview SDK version does NOT mean that all prior preview APIs are ++ # included. Packages reading this value to determine compatibility with ++ # known APIs should check that this value is precisely equal to the preview ++ # SDK version the package was built for, otherwise it should fall back to ++ # assuming the device can only support APIs as of the previous official ++ # public release. ++ # This value will always be 0 for release builds. ++ PLATFORM_PREVIEW_SDK_VERSION := 0 ++ endif ++endif ++ ++ifeq "" "$(DEFAULT_APP_TARGET_SDK)" ++ # This is the default minSdkVersion and targetSdkVersion to use for ++ # all .apks created by the build system. It can be overridden by explicitly ++ # setting these in the .apk's AndroidManifest.xml. It is either the code ++ # name of the development build or, if this is a release build, the official ++ # SDK version of this release. ++ ifeq "REL" "$(PLATFORM_VERSION_CODENAME)" ++ DEFAULT_APP_TARGET_SDK := $(PLATFORM_SDK_VERSION) ++ else ++ DEFAULT_APP_TARGET_SDK := $(PLATFORM_VERSION_CODENAME) ++ endif ++endif ++ ++ifeq "" "$(PLATFORM_SECURITY_PATCH)" ++ # Used to indicate the security patch that has been applied to the device. ++ # It must signify that the build includes all security patches issued up through the designated Android Public Security Bulletin. ++ # It must be of the form "YYYY-MM-DD" on production devices. ++ # It must match one of the Android Security Patch Level strings of the Public Security Bulletins. ++ # If there is no $PLATFORM_SECURITY_PATCH set, keep it empty. ++ PLATFORM_SECURITY_PATCH := 2016-11-05 ++endif ++ ++ifeq "" "$(PLATFORM_BASE_OS)" ++ # Used to indicate the base os applied to the device. ++ # Can be an arbitrary string, but must be a single word. ++ # ++ # If there is no $PLATFORM_BASE_OS set, keep it empty. ++ PLATFORM_BASE_OS := ++endif ++ ++ifeq "" "$(BUILD_ID)" ++ # Used to signify special builds. E.g., branches and/or releases, ++ # like "M5-RC7". Can be an arbitrary string, but must be a single ++ # word and a valid file name. ++ # ++ # If there is no BUILD_ID set, make it obvious. ++ BUILD_ID := UNKNOWN ++endif ++ ++ifeq "" "$(BUILD_DATETIME)" ++ # Used to reproduce builds by setting the same time. Must be the number ++ # of seconds since the Epoch. ++ BUILD_DATETIME := $(shell date +%s) ++endif ++ ++ifneq (,$(findstring Darwin,$(shell uname -sm))) ++DATE := date -r $(BUILD_DATETIME) ++else ++DATE := date -d @$(BUILD_DATETIME) ++endif ++ ++ifeq "" "$(BUILD_NUMBER)" ++ # BUILD_NUMBER should be set to the source control value that ++ # represents the current state of the source code. E.g., a ++ # perforce changelist number or a git hash. Can be an arbitrary string ++ # (to allow for source control that uses something other than numbers), ++ # but must be a single word and a valid file name. ++ # ++ # If no BUILD_NUMBER is set, create a useful "I am an engineering build ++ # from this date/time" value. Make it start with a non-digit so that ++ # anyone trying to parse it as an integer will probably get "0". ++ BUILD_NUMBER := eng.$(shell echo $${USER:0:6}).$(shell $(DATE) +%Y%m%d.%H%M%S) ++endif +diff --git a/core/version_defaults_REMOTE_20377.mk b/core/version_defaults_REMOTE_20377.mk +new file mode 100644 +index 0000000..2c8a21f +--- /dev/null ++++ b/core/version_defaults_REMOTE_20377.mk +@@ -0,0 +1,160 @@ ++# ++# 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. ++# ++ ++# ++# Handle various build version information. ++# ++# Guarantees that the following are defined: ++# PLATFORM_VERSION ++# PLATFORM_SDK_VERSION ++# PLATFORM_VERSION_CODENAME ++# DEFAULT_APP_TARGET_SDK ++# BUILD_ID ++# BUILD_NUMBER ++# BUILD_DATETIME ++# PLATFORM_SECURITY_PATCH ++# ++ ++# Look for an optional file containing overrides of the defaults, ++# but don't cry if we don't find it. We could just use -include, but ++# the build.prop target also wants INTERNAL_BUILD_ID_MAKEFILE to be set ++# if the file exists. ++# ++INTERNAL_BUILD_ID_MAKEFILE := $(wildcard $(BUILD_SYSTEM)/build_id.mk) ++ifneq "" "$(INTERNAL_BUILD_ID_MAKEFILE)" ++ include $(INTERNAL_BUILD_ID_MAKEFILE) ++endif ++ ++ifeq "" "$(PLATFORM_VERSION)" ++ # This is the canonical definition of the platform version, ++ # which is the version that we reveal to the end user. ++ # Update this value when the platform version changes (rather ++ # than overriding it somewhere else). Can be an arbitrary string. ++ PLATFORM_VERSION := 7.1.1 ++endif ++ ++ifeq "" "$(PLATFORM_SDK_VERSION)" ++ # This is the canonical definition of the SDK version, which defines ++ # the set of APIs and functionality available in the platform. It ++ # is a single integer that increases monotonically as updates to ++ # the SDK are released. It should only be incremented when the APIs for ++ # the new release are frozen (so that developers don't write apps against ++ # intermediate builds). During development, this number remains at the ++ # SDK version the branch is based on and PLATFORM_VERSION_CODENAME holds ++ # the code-name of the new development work. ++ PLATFORM_SDK_VERSION := 25 ++endif ++ ++ifeq "" "$(PLATFORM_JACK_MIN_SDK_VERSION)" ++ # This is definition of the min SDK version given to Jack for the current ++ # platform. For released version it should be the same as ++ # PLATFORM_SDK_VERSION. During development, this number may be incremented ++ # before PLATFORM_SDK_VERSION if the plateform starts to add new java ++ # language supports. ++ PLATFORM_JACK_MIN_SDK_VERSION := 25 ++endif ++ ++ifeq "" "$(PLATFORM_VERSION_CODENAME)" ++ # This is the current development code-name, if the build is not a final ++ # release build. If this is a final release build, it is simply "REL". ++ PLATFORM_VERSION_CODENAME := REL ++ ++ # This is all of the development codenames that are active. Should be either ++ # the same as PLATFORM_VERSION_CODENAME or a comma-separated list of additional ++ # codenames after PLATFORM_VERSION_CODENAME. ++ PLATFORM_VERSION_ALL_CODENAMES := $(PLATFORM_VERSION_CODENAME) ++endif ++ ++ifeq "REL" "$(PLATFORM_VERSION_CODENAME)" ++ PLATFORM_PREVIEW_SDK_VERSION := 0 ++else ++ ifeq "" "$(PLATFORM_PREVIEW_SDK_VERSION)" ++ # This is the definition of a preview SDK version over and above the current ++ # platform SDK version. Unlike the platform SDK version, a higher value ++ # for preview SDK version does NOT mean that all prior preview APIs are ++ # included. Packages reading this value to determine compatibility with ++ # known APIs should check that this value is precisely equal to the preview ++ # SDK version the package was built for, otherwise it should fall back to ++ # assuming the device can only support APIs as of the previous official ++ # public release. ++ # This value will always be 0 for release builds. ++ PLATFORM_PREVIEW_SDK_VERSION := 0 ++ endif ++endif ++ ++ifeq "" "$(DEFAULT_APP_TARGET_SDK)" ++ # This is the default minSdkVersion and targetSdkVersion to use for ++ # all .apks created by the build system. It can be overridden by explicitly ++ # setting these in the .apk's AndroidManifest.xml. It is either the code ++ # name of the development build or, if this is a release build, the official ++ # SDK version of this release. ++ ifeq "REL" "$(PLATFORM_VERSION_CODENAME)" ++ DEFAULT_APP_TARGET_SDK := $(PLATFORM_SDK_VERSION) ++ else ++ DEFAULT_APP_TARGET_SDK := $(PLATFORM_VERSION_CODENAME) ++ endif ++endif ++ ++ifeq "" "$(PLATFORM_SECURITY_PATCH)" ++ # Used to indicate the security patch that has been applied to the device. ++ # It must signify that the build includes all security patches issued up through the designated Android Public Security Bulletin. ++ # It must be of the form "YYYY-MM-DD" on production devices. ++ # It must match one of the Android Security Patch Level strings of the Public Security Bulletins. ++ # If there is no $PLATFORM_SECURITY_PATCH set, keep it empty. ++ PLATFORM_SECURITY_PATCH := 2016-12-05 ++endif ++ ++ifeq "" "$(PLATFORM_BASE_OS)" ++ # Used to indicate the base os applied to the device. ++ # Can be an arbitrary string, but must be a single word. ++ # ++ # If there is no $PLATFORM_BASE_OS set, keep it empty. ++ PLATFORM_BASE_OS := ++endif ++ ++ifeq "" "$(BUILD_ID)" ++ # Used to signify special builds. E.g., branches and/or releases, ++ # like "M5-RC7". Can be an arbitrary string, but must be a single ++ # word and a valid file name. ++ # ++ # If there is no BUILD_ID set, make it obvious. ++ BUILD_ID := UNKNOWN ++endif ++ ++ifeq "" "$(BUILD_DATETIME)" ++ # Used to reproduce builds by setting the same time. Must be the number ++ # of seconds since the Epoch. ++ BUILD_DATETIME := $(shell date +%s) ++endif ++ ++ifneq (,$(findstring Darwin,$(shell uname -sm))) ++DATE := date -r $(BUILD_DATETIME) ++else ++DATE := date -d @$(BUILD_DATETIME) ++endif ++ ++ifeq "" "$(BUILD_NUMBER)" ++ # BUILD_NUMBER should be set to the source control value that ++ # represents the current state of the source code. E.g., a ++ # perforce changelist number or a git hash. Can be an arbitrary string ++ # (to allow for source control that uses something other than numbers), ++ # but must be a single word and a valid file name. ++ # ++ # If no BUILD_NUMBER is set, create a useful "I am an engineering build ++ # from this date/time" value. Make it start with a non-digit so that ++ # anyone trying to parse it as an integer will probably get "0". ++ BUILD_NUMBER := eng.$(shell echo $${USER:0:6}).$(shell $(DATE) +%Y%m%d.%H%M%S) ++endif +diff --git a/target/board/generic/BoardConfig.mk b/target/board/generic/BoardConfig.mk +index 325b0ce..02c1c88 100644 +--- a/target/board/generic/BoardConfig.mk ++++ b/target/board/generic/BoardConfig.mk +@@ -45,28 +45,6 @@ BUILD_EMULATOR_OPENGL := true + # the GLES renderer disables itself if host GL acceleration isn't available. + USE_OPENGL_RENDERER := true + +-# Set the phase offset of the system's vsync event relative to the hardware +-# vsync. The system's vsync event drives Choreographer and SurfaceFlinger's +-# rendering. This value is the number of nanoseconds after the hardware vsync +-# that the system vsync event will occur. +-# +-# This phase offset allows adjustment of the minimum latency from application +-# wake-up (by Choregographer) time to the time at which the resulting window +-# image is displayed. This value may be either positive (after the HW vsync) +-# or negative (before the HW vsync). Setting it to 0 will result in a +-# minimum latency of two vsync periods because the app and SurfaceFlinger +-# will run just after the HW vsync. Setting it to a positive number will +-# result in the minimum latency being: +-# +-# (2 * VSYNC_PERIOD - (vsyncPhaseOffsetNs % VSYNC_PERIOD)) +-# +-# Note that reducing this latency makes it more likely for the applications +-# to not have their window content image ready in time. When this happens +-# the latency will end up being an additional vsync period, and animations +-# will hiccup. Therefore, this latency should be tuned somewhat +-# conservatively (or at least with awareness of the trade-off being made). +-VSYNC_EVENT_PHASE_OFFSET_NS := 0 +- + TARGET_USERIMAGES_USE_EXT4 := true + BOARD_SYSTEMIMAGE_PARTITION_SIZE := 1879048192 # 1.75 GB + BOARD_USERDATAIMAGE_PARTITION_SIZE := 576716800 +diff --git a/target/board/generic/sepolicy/file_contexts b/target/board/generic/sepolicy/file_contexts +index e8d32f7..e9502d9 100644 +--- a/target/board/generic/sepolicy/file_contexts ++++ b/target/board/generic/sepolicy/file_contexts +@@ -9,6 +9,7 @@ + /dev/block/vdc u:object_r:userdata_block_device:s0 + + /dev/goldfish_pipe u:object_r:qemu_device:s0 ++/dev/goldfish_sync u:object_r:qemu_device:s0 + /dev/qemu_.* u:object_r:qemu_device:s0 + /dev/socket/qemud u:object_r:qemud_socket:s0 + /dev/ttyGF[0-9]* u:object_r:serial_device:s0 +diff --git a/target/board/generic_x86_64/BoardConfig.mk b/target/board/generic_x86_64/BoardConfig.mk +index 553bec9..283e9cc 100755 +--- a/target/board/generic_x86_64/BoardConfig.mk ++++ b/target/board/generic_x86_64/BoardConfig.mk +@@ -38,7 +38,7 @@ BUILD_EMULATOR_OPENGL := true + USE_OPENGL_RENDERER := true + + TARGET_USERIMAGES_USE_EXT4 := true +-BOARD_SYSTEMIMAGE_PARTITION_SIZE := 1879048192 # 1.75 GB ++BOARD_SYSTEMIMAGE_PARTITION_SIZE := 2147483648 # 2 GB + BOARD_USERDATAIMAGE_PARTITION_SIZE := 576716800 + BOARD_CACHEIMAGE_PARTITION_SIZE := 69206016 + BOARD_CACHEIMAGE_FILE_SYSTEM_TYPE := ext4 +diff --git a/tools/droiddoc/templates-ndk/assets/css/default.css b/tools/droiddoc/templates-ndk/assets/css/default.css +index f411d93..036c0eb 100644 +--- a/tools/droiddoc/templates-ndk/assets/css/default.css ++++ b/tools/droiddoc/templates-ndk/assets/css/default.css +@@ -4217,7 +4217,7 @@ EndColorStr='#ececec'); + } + + /* offset the tags to account for sticky nav */ +-body.reference a[name] { ++body.reference a[name]:empty { + visibility: hidden; + display: block; + position: relative; +diff --git a/tools/droiddoc/templates-sdk-dev/assets/GPL-LICENSE.txt b/tools/droiddoc/templates-sdk-dev/assets/GPL-LICENSE.txt +deleted file mode 100644 +index 66a0f18..0000000 +--- a/tools/droiddoc/templates-sdk-dev/assets/GPL-LICENSE.txt ++++ /dev/null +@@ -1,278 +0,0 @@ +- GNU GENERAL PUBLIC LICENSE +- Version 2, June 1991 +- +- Copyright (C) 1989, 1991 Free Software Foundation, Inc. +- 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +- Everyone is permitted to copy and distribute verbatim copies +- of this license document, but changing it is not allowed. +- +- Preamble +- +- The licenses for most software are designed to take away your +-freedom to share and change it. By contrast, the GNU General Public +-License is intended to guarantee your freedom to share and change free +-software--to make sure the software is free for all its users. This +-General Public License applies to most of the Free Software +-Foundation's software and to any other program whose authors commit to +-using it. (Some other Free Software Foundation software is covered by +-the GNU Lesser General Public License instead.) You can apply it to +-your programs, too. +- +- When we speak of free software, we are referring to freedom, not +-price. Our General Public Licenses are designed to make sure that you +-have the freedom to distribute copies of free software (and charge for +-this service if you wish), that you receive source code or can get it +-if you want it, that you can change the software or use pieces of it +-in new free programs; and that you know you can do these things. +- +- To protect your rights, we need to make restrictions that forbid +-anyone to deny you these rights or to ask you to surrender the rights. +-These restrictions translate to certain responsibilities for you if you +-distribute copies of the software, or if you modify it. +- +- For example, if you distribute copies of such a program, whether +-gratis or for a fee, you must give the recipients all the rights that +-you have. You must make sure that they, too, receive or can get the +-source code. And you must show them these terms so they know their +-rights. +- +- We protect your rights with two steps: (1) copyright the software, and +-(2) offer you this license which gives you legal permission to copy, +-distribute and/or modify the software. +- +- Also, for each author's protection and ours, we want to make certain +-that everyone understands that there is no warranty for this free +-software. If the software is modified by someone else and passed on, we +-want its recipients to know that what they have is not the original, so +-that any problems introduced by others will not reflect on the original +-authors' reputations. +- +- Finally, any free program is threatened constantly by software +-patents. We wish to avoid the danger that redistributors of a free +-program will individually obtain patent licenses, in effect making the +-program proprietary. To prevent this, we have made it clear that any +-patent must be licensed for everyone's free use or not licensed at all. +- +- The precise terms and conditions for copying, distribution and +-modification follow. +- +- GNU GENERAL PUBLIC LICENSE +- TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION +- +- 0. This License applies to any program or other work which contains +-a notice placed by the copyright holder saying it may be distributed +-under the terms of this General Public License. The "Program", below, +-refers to any such program or work, and a "work based on the Program" +-means either the Program or any derivative work under copyright law: +-that is to say, a work containing the Program or a portion of it, +-either verbatim or with modifications and/or translated into another +-language. (Hereinafter, translation is included without limitation in +-the term "modification".) Each licensee is addressed as "you". +- +-Activities other than copying, distribution and modification are not +-covered by this License; they are outside its scope. The act of +-running the Program is not restricted, and the output from the Program +-is covered only if its contents constitute a work based on the +-Program (independent of having been made by running the Program). +-Whether that is true depends on what the Program does. +- +- 1. You may copy and distribute verbatim copies of the Program's +-source code as you receive it, in any medium, provided that you +-conspicuously and appropriately publish on each copy an appropriate +-copyright notice and disclaimer of warranty; keep intact all the +-notices that refer to this License and to the absence of any warranty; +-and give any other recipients of the Program a copy of this License +-along with the Program. +- +-You may charge a fee for the physical act of transferring a copy, and +-you may at your option offer warranty protection in exchange for a fee. +- +- 2. You may modify your copy or copies of the Program or any portion +-of it, thus forming a work based on the Program, and copy and +-distribute such modifications or work under the terms of Section 1 +-above, provided that you also meet all of these conditions: +- +- a) You must cause the modified files to carry prominent notices +- stating that you changed the files and the date of any change. +- +- b) You must cause any work that you distribute or publish, that in +- whole or in part contains or is derived from the Program or any +- part thereof, to be licensed as a whole at no charge to all third +- parties under the terms of this License. +- +- c) If the modified program normally reads commands interactively +- when run, you must cause it, when started running for such +- interactive use in the most ordinary way, to print or display an +- announcement including an appropriate copyright notice and a +- notice that there is no warranty (or else, saying that you provide +- a warranty) and that users may redistribute the program under +- these conditions, and telling the user how to view a copy of this +- License. (Exception: if the Program itself is interactive but +- does not normally print such an announcement, your work based on +- the Program is not required to print an announcement.) +- +-These requirements apply to the modified work as a whole. If +-identifiable sections of that work are not derived from the Program, +-and can be reasonably considered independent and separate works in +-themselves, then this License, and its terms, do not apply to those +-sections when you distribute them as separate works. But when you +-distribute the same sections as part of a whole which is a work based +-on the Program, the distribution of the whole must be on the terms of +-this License, whose permissions for other licensees extend to the +-entire whole, and thus to each and every part regardless of who wrote it. +- +-Thus, it is not the intent of this section to claim rights or contest +-your rights to work written entirely by you; rather, the intent is to +-exercise the right to control the distribution of derivative or +-collective works based on the Program. +- +-In addition, mere aggregation of another work not based on the Program +-with the Program (or with a work based on the Program) on a volume of +-a storage or distribution medium does not bring the other work under +-the scope of this License. +- +- 3. You may copy and distribute the Program (or a work based on it, +-under Section 2) in object code or executable form under the terms of +-Sections 1 and 2 above provided that you also do one of the following: +- +- a) Accompany it with the complete corresponding machine-readable +- source code, which must be distributed under the terms of Sections +- 1 and 2 above on a medium customarily used for software interchange; or, +- +- b) Accompany it with a written offer, valid for at least three +- years, to give any third party, for a charge no more than your +- cost of physically performing source distribution, a complete +- machine-readable copy of the corresponding source code, to be +- distributed under the terms of Sections 1 and 2 above on a medium +- customarily used for software interchange; or, +- +- c) Accompany it with the information you received as to the offer +- to distribute corresponding source code. (This alternative is +- allowed only for noncommercial distribution and only if you +- received the program in object code or executable form with such +- an offer, in accord with Subsection b above.) +- +-The source code for a work means the preferred form of the work for +-making modifications to it. For an executable work, complete source +-code means all the source code for all modules it contains, plus any +-associated interface definition files, plus the scripts used to +-control compilation and installation of the executable. However, as a +-special exception, the source code distributed need not include +-anything that is normally distributed (in either source or binary +-form) with the major components (compiler, kernel, and so on) of the +-operating system on which the executable runs, unless that component +-itself accompanies the executable. +- +-If distribution of executable or object code is made by offering +-access to copy from a designated place, then offering equivalent +-access to copy the source code from the same place counts as +-distribution of the source code, even though third parties are not +-compelled to copy the source along with the object code. +- +- 4. You may not copy, modify, sublicense, or distribute the Program +-except as expressly provided under this License. Any attempt +-otherwise to copy, modify, sublicense or distribute the Program is +-void, and will automatically terminate your rights under this License. +-However, parties who have received copies, or rights, from you under +-this License will not have their licenses terminated so long as such +-parties remain in full compliance. +- +- 5. You are not required to accept this License, since you have not +-signed it. However, nothing else grants you permission to modify or +-distribute the Program or its derivative works. These actions are +-prohibited by law if you do not accept this License. Therefore, by +-modifying or distributing the Program (or any work based on the +-Program), you indicate your acceptance of this License to do so, and +-all its terms and conditions for copying, distributing or modifying +-the Program or works based on it. +- +- 6. Each time you redistribute the Program (or any work based on the +-Program), the recipient automatically receives a license from the +-original licensor to copy, distribute or modify the Program subject to +-these terms and conditions. You may not impose any further +-restrictions on the recipients' exercise of the rights granted herein. +-You are not responsible for enforcing compliance by third parties to +-this License. +- +- 7. If, as a consequence of a court judgment or allegation of patent +-infringement or for any other reason (not limited to patent issues), +-conditions are imposed on you (whether by court order, agreement or +-otherwise) that contradict the conditions of this License, they do not +-excuse you from the conditions of this License. If you cannot +-distribute so as to satisfy simultaneously your obligations under this +-License and any other pertinent obligations, then as a consequence you +-may not distribute the Program at all. For example, if a patent +-license would not permit royalty-free redistribution of the Program by +-all those who receive copies directly or indirectly through you, then +-the only way you could satisfy both it and this License would be to +-refrain entirely from distribution of the Program. +- +-If any portion of this section is held invalid or unenforceable under +-any particular circumstance, the balance of the section is intended to +-apply and the section as a whole is intended to apply in other +-circumstances. +- +-It is not the purpose of this section to induce you to infringe any +-patents or other property right claims or to contest validity of any +-such claims; this section has the sole purpose of protecting the +-integrity of the free software distribution system, which is +-implemented by public license practices. Many people have made +-generous contributions to the wide range of software distributed +-through that system in reliance on consistent application of that +-system; it is up to the author/donor to decide if he or she is willing +-to distribute software through any other system and a licensee cannot +-impose that choice. +- +-This section is intended to make thoroughly clear what is believed to +-be a consequence of the rest of this License. +- +- 8. If the distribution and/or use of the Program is restricted in +-certain countries either by patents or by copyrighted interfaces, the +-original copyright holder who places the Program under this License +-may add an explicit geographical distribution limitation excluding +-those countries, so that distribution is permitted only in or among +-countries not thus excluded. In such case, this License incorporates +-the limitation as if written in the body of this License. +- +- 9. The Free Software Foundation may publish revised and/or new versions +-of the General Public License from time to time. Such new versions will +-be similar in spirit to the present version, but may differ in detail to +-address new problems or concerns. +- +-Each version is given a distinguishing version number. If the Program +-specifies a version number of this License which applies to it and "any +-later version", you have the option of following the terms and conditions +-either of that version or of any later version published by the Free +-Software Foundation. If the Program does not specify a version number of +-this License, you may choose any version ever published by the Free Software +-Foundation. +- +- 10. If you wish to incorporate parts of the Program into other free +-programs whose distribution conditions are different, write to the author +-to ask for permission. For software which is copyrighted by the Free +-Software Foundation, write to the Free Software Foundation; we sometimes +-make exceptions for this. Our decision will be guided by the two goals +-of preserving the free status of all derivatives of our free software and +-of promoting the sharing and reuse of software generally. +- +- NO WARRANTY +- +- 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +-FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +-OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +-PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +-OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +-MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +-TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +-PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +-REPAIR OR CORRECTION. +- +- 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +-WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +-REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +-INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +-OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +-TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +-YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +-PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +-POSSIBILITY OF SUCH DAMAGES. +\ No newline at end of file +diff --git a/tools/droiddoc/templates-sdk-dev/assets/LICENSE.txt b/tools/droiddoc/templates-sdk-dev/assets/LICENSE.txt +deleted file mode 100644 +index e84328b..0000000 +--- a/tools/droiddoc/templates-sdk-dev/assets/LICENSE.txt ++++ /dev/null +@@ -1,20 +0,0 @@ +-Copyright (c) 2011 John Resig, http://jquery.com/ +- +-Permission is hereby granted, free of charge, to any person obtaining +-a copy of this software and associated documentation files (the +-"Software"), to deal in the Software without restriction, including +-without limitation the rights to use, copy, modify, merge, publish, +-distribute, sublicense, and/or sell copies of the Software, and to +-permit persons to whom the Software is furnished to do so, subject to +-the following conditions: +- +-The above copyright notice and this permission notice shall be +-included in all copies or substantial portions of the Software. +- +-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +-EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +-MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +-NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +-LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +-OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +-WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +\ No newline at end of file +diff --git a/tools/droiddoc/templates-sdk-dev/assets/android-developer-docs.css b/tools/droiddoc/templates-sdk-dev/assets/android-developer-docs.css +deleted file mode 100644 +index cd610f7..0000000 +--- a/tools/droiddoc/templates-sdk-dev/assets/android-developer-docs.css ++++ /dev/null +@@ -1,2768 +0,0 @@ +-/* file: android-developer-core.css +- author: smain +- date: september 2008 +- info: core developer styles (developer.android.com) +- Required by jdiff +-*/ +- +- +-/* RESET STYLES */ +- +-html,body,div,h1,h2,h3,h4,h5,h6,p,img, +-dl,dt,dd,ol,ul,li,table,caption,tbody, +-tfoot,thead,tr,th,td,form,fieldset, +-embed,object,applet { +- margin: 0; +- padding: 0; +- border: 0; +-} +- +-/* BASICS */ +- +-html, body { +- overflow:hidden; /* keeps scrollbar off IE */ +- background-color:#fff; +-} +- +-body { +- font-family:arial,sans-serif; +- color:#000; +- font-size:13px; +- color:#333; +- background-image:url(images/bg_fade.jpg); +- background-repeat:repeat-x; +-} +- +-a, a code { +- color:#006699; +-} +- +-a:active, +-a:active code { +- color:#f00; +-} +- +-a:visited, +-a:visited code { +- color:#006699; +-} +- +-input, select, +-textarea, option, label { +- font-family:inherit; +- font-size:inherit; +- padding:0; +- margin:0; +- vertical-align:middle; +-} +- +-option { +- padding:0 4px; +-} +- +-p, form { +- padding:0; +- margin:0 0 1em; +-} +- +-code, pre { +- color:#007000; +- font-family:monospace; +- line-height:1em; +-} +- +-var { +- color:#007000; +- font-style:italic; +-} +- +-pre { +- border:1px solid #ccc; +- background-color:#fafafa; +- padding:10px; +- margin:0 0 1em 1em; +- overflow:auto; +- line-height:inherit; /* fixes vertical scrolling in webkit */ +-} +- +-h1,h2,h3,h4,h5 { +- margin:1em 0; +- padding:0; +-} +- +-p,ul,ol,dl,dd,dt,li { +- line-height:1.3em; +-} +- +-ul,ol { +- margin:0 0 .8em; +- padding:0 0 0 2em; +-} +- +-li { +- padding:0 0 .5em; +-} +- +-dl { +- margin:0 0 1em 0; +- padding:0; +-} +- +-dt { +- margin:0; +- padding:0; +-} +- +-dd { +- margin:0 0 1em; +- padding:0 0 0 2em; +-} +- +-li p { +- margin:.5em 0 0; +-} +- +-dd p { +- margin:1em 0 0; +-} +- +-li pre, li table, li img { +- margin:.5em 0 0 1em; +-} +- +-dd pre, +-#jd-content dd table, +-#jd-content dd img { +- margin:1em 0 0 1em; +-} +- +-li ul, +-li ol, +-dd ul, +-dd ol { +- margin:0; +- padding: 0 0 0 2em; +-} +- +-li li, +-dd li { +- margin:0; +- padding:.5em 0 0; +-} +- +-dl dl, +-ol dl, +-ul dl { +- margin:0 0 1em; +- padding:0; +-} +- +-table { +- font-size:1em; +- margin:0 0 1em; +- padding:0; +- border-collapse:collapse; +- border-width:0; +- empty-cells:show; +-} +- +-td,th { +- border:1px solid #ccc; +- padding:6px 12px; +- text-align:left; +- vertical-align:top; +- background-color:inherit; +-} +- +-th { +- background-color:#dee8f1; +-} +- +-td > p:last-child { +- margin:0; +-} +- +-hr.blue { +- background-color:#DDF0F2; +- border:none; +- height:5px; +- margin:20px 0 10px; +-} +- +-blockquote { +- margin: 0 0 1em 1em; +- padding: 0 4em 0 1em; +- border-left:2px solid #eee; +-} +-/* LAYOUT */ +- +-#body-content { +- /* "Preliminary" watermark for preview releases and interim builds. +- background:transparent url(images/preliminary.png) repeat scroll 0 0; */ +- margin:0; +- position:relative; +- width:100%; +-} +- +-#header { +- height: 114px; +- position:relative; +- z-index:100; +- min-width:675px; /* min width for the tabs, before they wrap */ +- padding:0 10px; +- border-bottom:3px solid #94b922; +-} +- +-#headerLeft{ +- padding: 25px 0 0; +-} +- +-#headerLeft img{ +- height:50px; +- width:180px; +-} +- +-#headerRight { +- position:absolute; +- right:0; +- top:0; +- text-align:right; +-} +- +-/* Tabs in the header */ +- +-#header ul { +- list-style: none; +- margin: 7px 0 0; +- padding: 0; +- height: 29px; +-} +- +-#header li { +- float: left; +- margin: 0px 2px 0px 0px; +- padding:0; +-} +- +-#header li a { +- text-decoration: none; +- display: block; +- background-image: url(images/bg_images_sprite.png); +- background-position: 0 -58px; +- background-repeat: no-repeat; +- color: #666; +- font-size: 13px; +- font-weight: bold; +- width: 94px; +- height: 29px; +- text-align: center; +- margin: 0px; +-} +- +-#header li a:hover { +- background-image: url(images/bg_images_sprite.png); +- background-position: 0 -29px; +- background-repeat: no-repeat; +-} +- +-#header li a span { +- position:relative; +- top:7px; +-} +- +-#header li a span+span { +- display:none; +-} +- +-/* tab highlighting */ +- +-.home #home-link a, +-.guide #guide-link a, +-.reference #reference-link a, +-.sdk #sdk-link a, +-.resources #resources-link a, +-.videos #videos-link a { +- background-image: url(images/bg_images_sprite.png); +- background-position: 0 0; +- background-repeat: no-repeat; +- color: #fff; +- font-weight: bold; +- cursor:default; +-} +- +-.home #home-link a:hover, +-.guide #guide-link a:hover, +-.reference #reference-link a:hover, +-.sdk #sdk-link a:hover, +-.resources #resources-link a:hover, +-.videos #videos-link a:hover { +- background-image: url(images/bg_images_sprite.png); +- background-position: 0 0; +-} +- +-#headerLinks { +- margin:10px 10px 0 0; +- height:13px; +- font-size: 11px; +- vertical-align: top; +-} +- +-#headerLinks a { +- color: #7FA9B5; +-} +- +-#headerLinks img { +- vertical-align:middle; +-} +- +-#language { +- margin:0 10px 0 4px; +-} +- +-#search { +- height:45px; +- margin:15px 10px 0 0; +-} +- +-/* MAIN BODY */ +- +-#mainBodyFluid { +- margin: 20px 10px; +- color:#333; +-} +- +-#mainBodyFixed { +- margin: 20px 10px; +- color: #333; +- width:930px; +- position:relative; +-} +- +-#mainBodyFixed h3, +-#mainBodyFluid h3 { +- color:#336666; +- font-size:1.25em; +- margin: 0em 0em 0em 0em; +- padding-bottom:.5em; +-} +- +-#mainBodyFixed h2, +-#mainBodyFluid h2 { +- color:#336666; +- font-size:1.25em; +- margin: 0; +- padding-bottom:.5em; +-} +- +-#mainBodyFixed h1, +-#mainBodyFluid h1 { +- color:#435A6E; +- font-size:1.7em; +- margin: 1em 0; +-} +- +-#mainBodyFixed .green, +-#mainBodyFluid .green, +-#jd-content .green { +- color:#7BB026; +- background-color:none; +-} +- +-#mainBodyLeft { +- float: left; +- width: 600px; +- margin-right: 20px; +- color: #333; +- position:relative; +-} +- +-div.indent { +- margin-left: 40px; +- margin-right: 70px; +-} +- +-#mainBodyLeft p { +- color: #333; +- font-size: 13px; +-} +- +-#mainBodyLeft p.blue { +- color: #669999; +-} +- +-#mainBodyLeft #communityDiv { +- float: left; +- background-image:url(images/bg_community_leftDiv.jpg); +- background-repeat: no-repeat; +- width: 581px; +- height: 347px; +- padding: 20px 0px 0px 20px; +-} +- +-#mainBodyRight { +- float: left; +- width: 300px; +- color: #333; +-} +- +-#mainBodyRight p { +- padding-right: 50px; +- color: #333; +-} +- +-#mainBodyRight table { +- width: 100%; +-} +- +-#mainBodyRight td { +- border:0px solid #666; +- padding:0px 5px; +- text-align:left; +-} +- +-#mainBodyRight td p { +- margin:0 0 1em 0; +-} +- +-#mainBodyRight .blueBorderBox { +- border:5px solid #ddf0f2; +- padding:18px 18px 18px 18px; +- text-align:left; +-} +- +-#mainBodyFixed .seperator { +- background-image:url(images/hr_gray_side.jpg); +- background-repeat:no-repeat; +- width: 100%; +- float: left; +- clear: both; +-} +- +-#mainBodyBottom { +- float: left; +- width: 100%; +- clear:both; +- color: #333; +-} +- +-#mainBodyBottom .seperator { +- background-image:url(images/hr_gray_main.jpg); +- background-repeat:no-repeat; +- width: 100%; +- float: left; +- clear: both; +-} +- +-/* FOOTER */ +- +-#footer { +- float: left; +- width:90%; +- margin: 20px; +- color: #aaa; +- font-size: 11px; +-} +- +-#footer a { +- color: #aaa; +- font-size: 11px; +-} +- +-#footer a:hover { +- text-decoration: underline; +- color:#aaa; +-} +- +-#footerlinks { +- margin-top:2px; +-} +- +-#footerlinks a, +-#footerlinks a:visited { +- color:#006699; +-} +- +-/* SEARCH FILTER */ +- +-#search_autocomplete { +- color:#aaa; +-} +- +-#search-button { +- display:inline; +-} +- +-#search_filtered_div { +- position:absolute; +- margin-top:-1px; +- z-index:101; +- border:1px solid #BCCDF0; +- background-color:#fff; +-} +- +-#search_filtered { +- min-width:100%; +-} +-#search_filtered td{ +- background-color:#fff; +- border-bottom: 1px solid #669999; +- line-height:1.5em; +-} +- +-#search_filtered .jd-selected { +- background-color: #94b922; +- cursor:pointer; +-} +-#search_filtered .jd-selected, +-#search_filtered .jd-selected a { +- color:#fff; +-} +- +-.no-display { +- display: none; +-} +- +-.jd-autocomplete { +- font-family: Arial, sans-serif; +- padding-left: 6px; +- padding-right: 6px; +- padding-top: 1px; +- padding-bottom: 1px; +- font-size: 0.81em; +- border: none; +- margin: 0; +- line-height: 1.05em; +-} +- +-.show-row { +- display: table-row; +-} +-.hide-row { +- display: hidden; +-} +- +-/* SEARCH */ +- +-/* restrict global search form width */ +-#searchForm { +- width:350px; +-} +- +-#searchTxt { +- width:200px; +-} +- +-/* disable twiddle and size selectors for left column */ +-#leftSearchControl div { +- width: 100%; +-} +- +-#leftSearchControl .gsc-twiddle { +- background-image : none; +-} +- +-#leftSearchControl td, #searchForm td { +- border: 0px solid #000; +-} +- +-#leftSearchControl .gsc-resultsHeader .gsc-title { +- padding-left : 0px; +- font-weight : bold; +- font-size : 13px; +- color:#006699; +- display : none; +-} +- +-#leftSearchControl .gsc-resultsHeader div.gsc-results-selector { +- display : none; +-} +- +-#leftSearchControl .gsc-resultsRoot { +- padding-top : 6px; +-} +- +-#leftSearchControl div.gs-visibleUrl-long { +- display : block; +- color:#006699; +-} +- +-.gsc-webResult div.gs-visibleUrl-short, +-table.gsc-branding, +-.gsc-clear-button { +- display : none; +-} +- +-.gsc-cursor-box .gsc-cursor div.gsc-cursor-page, +-.gsc-cursor-box .gsc-trailing-more-results a.gsc-trailing-more-results, +-#leftSearchControl a, +-#leftSearchControl a b { +- color:#006699; +-} +- +-.gsc-resultsHeader { +- display: none; +-} +- +-/* Disable built in search forms */ +-.gsc-control form.gsc-search-box { +- display : none; +-} +-table.gsc-search-box { +- margin:6px 0 0 0; +- border-collapse:collapse; +-} +- +-td.gsc-input { +- padding:0 2px; +- width:100%; +- vertical-align:middle; +-} +- +-input.gsc-input { +- border:1px solid #BCCDF0; +- width:99%; +- padding-left:2px; +- font-size:.95em; +-} +- +-td.gsc-search-button { +- text-align: right; +- padding:0; +- vertical-align:top; +-} +- +-#search-button { +- margin:0 0 0 2px; +- font-size:11px; +-} +- +-/* search result tabs */ +- +-#doc-content .gsc-control { +- position:relative; +-} +- +-#doc-content .gsc-tabsArea { +- position:relative; +- white-space:nowrap; +-} +- +-#doc-content .gsc-tabHeader { +- padding: 3px 6px; +- position:relative; +- width:auto; +-} +- +-#doc-content .gsc-tabHeader.gsc-tabhActive { +- border-top: 2px solid #94B922; +-} +- +-#doc-content h2#searchTitle { +- padding:0; +-} +- +-#doc-content .gsc-resultsbox-visible { +- padding:1em 0 0 6px; +-} +- +-/* CAROUSEL */ +- +-#homeMiddle { +- padding: 0px 0px 0px 0px; +- float: left; +- width: 584px; +- height: 627px; +- position:relative; +-} +- +-#topAnnouncement { +- background:url(images/home/bg_home_announcement.png) no-repeat 0 0; +-} +- +-#homeTitle { +- padding:15px 15px 0; +- height:30px; +-} +- +-#homeTitle h2 { +- padding:0; +-} +- +-#announcement-block { +- padding:0 15px 0; +- overflow:hidden; +- background: url(images/hr_gray_side.jpg) no-repeat 15px 0; +- zoom:1; +-} +- +-#announcement-block>* { +- padding:15px 0 0; +-} +- +-#announcement-block img { +- float:left; +- margin:0 30px 0 0; +-} +- +-#announcement { +- float:left; +- margin:0; +-} +- +-#carousel { +- background:url(images/home/bg_home_carousel.png) no-repeat 0 0; +- position:relative; +- height:400px; +-} +- +-#carouselMain { +- background: url(images/home/bg_home_carousel_board.png) 0 0 no-repeat; +- height:auto; +- padding: 25px 21px 0; +- overflow:hidden; +- position:relative; +- zoom:1; /*IE6*/ +-} +- +-#carouselMain img { +- margin:0; +-} +- +-#carouselMain .bulletinDesc h3 { +- margin:0; +- padding:0; +-} +- +-#carouselMain .bulletinDesc p { +- margin:0; +- padding:0.7em 0 0; +-} +- +-#carouselWheel { +- background: url(images/home/bg_home_carousel_wheel.png) 0 0 no-repeat; +- padding-top:40px; +- height:150px; +-} +- +-.clearer { clear:both; } +- +-a#arrow-left, a#arrow-right { +- float:left; +- width:42px; +- height:42px; +- background-image:url(images/home/carousel_buttons_sprite.png); +- background-repeat:no-repeat; +-} +-a#arrow-left { +- margin:35px 3px 0 10px; +-} +-a#arrow-right { +- margin:35px 10px 0 0; +-} +-a.arrow-left-off, +-a#arrow-left.arrow-left-off:hover { +- background-position:0 0; +-} +-a.arrow-right-off, +-a#arrow-right.arrow-right-off:hover { +- background-position:-42px 0; +-} +-a#arrow-left:hover { +- background-position:0 -42px; +-} +-a#arrow-right:hover { +- background-position:-42px -42px; +-} +-a.arrow-left-on { +- background-position:0 0; +-} +-a.arrow-right-on { +- background-position:-42px 0; +-} +-a.arrow-right-off, +-a.arrow-left-off { +- cursor:default; +-} +- +-.app-list-container { +- margin:0 20px; +- position:relative; +- width:100%; +-} +- +-div#list-clip { +- height:110px; +- width:438px; +- overflow:hidden; +- position:relative; +- float:left; +-} +- +-div#app-list { +- left:0; +- z-index:1; +- position:absolute; +- margin:11px 0 0; +- _margin-top:13px; +- width:1000%; +-} +- +-#app-list a { +- display:block; +- float:left; +- height:90px; +- width:90px; +- margin:0 24px 0; +- padding:3px; +- background:#99cccc; +- -webkit-border-radius:7px; +- -moz-border-radius:7px; +- border-radius:7px; +- text-decoration:none; +- text-align:center; +- font-size:11px; +- line-height:11px; +-} +- +-#app-list a span { +- position:relative; +- top:-4px; +-} +- +-#app-list img { +- width:90px; +- height:70px; +- margin:0; +-} +- +-#app-list a.selected, +-#app-list a:active.selected, +-#app-list a:hover.selected { +- background:#A4C639; +- color:#fff; +- cursor:default; +- text-decoration:none; +-} +- +-#app-list a:hover, +-#app-list a:active { +- background:#ff9900; +-} +- +-#app-list a:hover span, +-#app-list a:active span { +- text-decoration:underline; +-} +- +-#droid-name { +- padding-top:.5em; +- color:#666; +- padding-bottom:.25em; +-} +- +-/*IE6*/ +-* html #app-list a { zoom: 1; margin:0 24px 0 15px;} +- +-* html #list-clip { +- width:430px !important; +-} +- +-/*carousel bulletin layouts*/ +-/*460px width*/ +-/*185px height*/ +-.img-left { +- float:left; +- width:230px; +- overflow:hidden; +- padding:8px 0 8px 8px; +-} +-.desc-right { +- float:left; +- width:270px; +- padding:10px; +-} +-.img-right { +- float:right; +- width:220px; +- overflow:hidden; +- padding:8px 8px 8px 0; +-} +-.desc-left { +- float:right; +- width:280px; +- padding:10px; +- text-align:right; +-} +-.img-top { +- padding:20px 20px 0; +-} +-.desc-bottom { +- padding:10px; +-} +- +- +-/* VIDEO PAGE */ +- +-#mainBodyLeft.videoPlayer { +- width:570px; +-} +- +-#mainBodyRight.videoPlayer { +- width:330px; +-} +- +-/* player */ +- +-#videoPlayerBox { +- background-color: #DAF3FC; +- border-radius:7px; +- -moz-border-radius:7px; +- -webkit-border-radius:7px; +- width:530px; +- padding:20px; +- border:1px solid #d3ecf5; +- box-shadow:2px 3px 1px #eee; +- -moz-box-shadow:2px 3px 1px #eee; +- -webkit-box-shadow:2px 3px 1px #eee; +-} +- +-#videoBorder { +- background-color: #FFF; +- min-height:399px; +- height:auto !important; +- border:1px solid #ccdada; +- border-radius:7px 7px 0 0; +- -moz-border-radius:7px 7px 0 0; +- -webkit-border-top-left-radius:7px; +- -webkit-border-top-right-radius:7px; +-} +- +-#videoPlayerTitle { +- width:500px; +- padding:15px 15px 0; +-} +- +-#videoPlayerTitle h2 { +- font-weight:bold; +- font-size:1.2em; +- color:#336666; +- margin:0; +- padding:0; +-} +- +-#objectWrapper { +- padding:15px 15px; +- height:334px; +- width:500px; +-} +- +-/* playlist tabs */ +- +-ul#videoTabs { +- list-style-type:none; +- padding:0; +- clear:both; +- margin:0; +- padding: 20px 0 0 15px; +- zoom:1; /* IE7/8, otherwise top-padding is double */ +-} +- +-ul#videoTabs li { +- display:inline; +- padding:0; +- margin:0 3px 0 0; +- line-height:2em; +-} +- +-ul#videoTabs li a { +- border-radius:7px 7px 0 0; +- -moz-border-radius:7px 7px 0 0; +- -webkit-border-top-left-radius:7px; +- -webkit-border-top-right-radius:7px; +- background:#95c0d0; +- color:#fff; +- text-decoration:none; +- padding:.45em 1.5em; +- font-weight:bold; +-} +- +-ul#videoTabs li.selected a { +- font-weight:bold; +- text-decoration:none; +- color:#555; +- background:#daf3fc; +- border-bottom:1px solid #daf3fc; +-} +- +-ul#videoTabs li:hover a { +- background:#85acba; +-} +- +-ul#videoTabs li.selected:hover a { +- background:#daf3fc; +-} +- +-/* playlists */ +- +-#videos { +- background:#daf3fc; +- margin-bottom:1.5em; +- padding:15px; +- border-radius:5px; +- -moz-border-radius:5px; +- -webkit-border-radius:5px; +- box-shadow:2px 3px 1px #eee; +- -moz-box-shadow:2px 3px 1px #eee; +- -webkit-box-shadow:2px 3px 1px #eee; +-} +- +-#videos div { +- display:none; +-} +- +-#videos div.selected { +- display:block; +-} +- +-ul.videoPreviews { +- list-style:none; +- padding:0; +- margin:0; +- zoom:1; /* IE, otherwise, layout doesn't update when showing 'more' */ +-} +- +-ul.videoPreviews li { +- margin:0 0 5px; +- padding:0; +- overflow:hidden; +- position:relative; +-} +- +-#mainBodyFixed ul.videoPreviews h3 { +- font-size: 12px; +- margin:0 0 1em 130px; +- padding:0; +- font-weight:bold; +- color:inherit; +-} +- +-ul.videoPreviews a { +- margin:1px; +- padding:10px; +- text-decoration:none; +- height:90px; +- display:block; +- border-radius:5px; +- -moz-border-radius:5px; +- -webkit-border-radius:5px; +- background-color:transparent; +-} +- +-ul.videoPreviews a:hover { +- background-color:#FFF; +- border:none; /* IE8, otherwise, bg doesn't work */ +-} +- +-ul.videoPreviews a.selected { +- background-color: #FF9900; +-} +- +-ul.videoPreviews img { +- float:left; +- clear:left; +- margin:0; +-} +- +-ul.videoPreviews h3 { +- font-size:12px; +- font-weight:bold; +- text-decoration:none; +- margin:0 0 1em 130px; +- padding:0; +-} +- +-ul.videoPreviews p { +- font-size: 12px; +- text-decoration:none; +- margin:0 0 1.2em 130px; +-} +- +-ul.videoPreviews p.full { +- display:none; +-} +- +-ul.videoPreviews span.more { +- padding:0 0 0 12px; +- background:url(images/arrow_bluelink_down.png) 0 2px no-repeat; +-} +- +-ul.videoPreviews span.less { +- padding:0 0 0 12px; +- background:url(images/arrow_bluelink_up.png) 0 2px no-repeat; +- display:none; +-} +- +-ul.videoPreviews p.toggle { +- position:absolute; +- margin:0; +- margin-top:-23px; /* instead of bottom:23px, because IE won't do it correctly */ +- left:140px; +-} +- +-ul.videoPreviews p.toggle a { +- height:auto; +- margin:0; +- padding:0; +- zoom:1; /* IE6, otherwise the margin considers the img on redraws */ +-} +- +-ul.videoPreviews p.toggle a:hover { +- text-decoration:underline; +- background:transparent; /* IE6, otherwise it inherits white */ +-} +- +-/* featured videos */ +- +-#mainBodyRight h2 { +- padding:0 0 5px; +-} +- +-#mainBodyRight ul.videoPreviews { +- margin:10px 0 0; +-} +- +-#mainBodyRight ul.videoPreviews li { +- font-size:11px; +- line-height:13px; +- margin:0 0 5px; +- padding:0; +-} +- +-#mainBodyRight ul.videoPreviews h3 { +- padding:0; +- margin:0; +- font-size:100%; +-} +- +-#mainBodyRight ul.videoPreviews a { +- text-decoration:none; +- height:108px; +- border:1px solid #FFF; +-} +- +-#mainBodyRight ul.videoPreviews a:hover { +- border:1px solid #CCDADA; +-} +- +-#mainBodyRight ul.videoPreviews a.selected { +- border:1px solid #FFF; +-} +- +-#mainBodyRight ul.videoPreviews p { +- line-height:1.2em; +- padding:0; +- margin:4px 0 0 130px; +-} +- +-#mainBodyRight ul.videoPreviews img { +- margin-top:5px; +-} +- +-/* Pretty printing styles. Used with prettify.js. */ +- +-.str { color: #080; } +-.kwd { color: #008; } +-.com { color: #800; } +-.typ { color: #606; } +-.lit { color: #066; } +-.pun { color: #660; } +-.pln { color: #000; } +-dl.tag-list dt code, +-.tag { color: #008; } +-dl.atn-list dt code, +-.atn { color: #828; } +-.atv { color: #080; } +-.dec { color: #606; } +- +-@media print { +- .str { color: #060; } +- .kwd { color: #006; font-weight: bold; } +- .com { color: #600; font-style: italic; } +- .typ { color: #404; font-weight: bold; } +- .lit { color: #044; } +- .pun { color: #440; } +- .pln { color: #000; } +- .tag { color: #006; font-weight: bold; } +- .atn { color: #404; } +- .atv { color: #060; } +-} +- +- +-#title { +- border-bottom: 4px solid #ccc; +- display:none; +-} +- +-#title h1 { +- color:#336666; +- margin:0; +- padding: 5px 10px; +- font-size: 1em; +- line-height: 15px; +-} +- +-#title h1 .small{ +- color:#000; +- margin:0; +- font-size: 13px; +- padding:0 0 0 15px; +-} +- +-/* SIDE NAVIGATION */ +- +-#side-nav { +- padding:0 6px 0 0; +- background-color: #fff; +- font-size:12px; +-} +- +-#resize-packages-nav { +-/* keeps the resize handle below the h-scroll handle */ +- height:270px; +- overflow:hidden; +- max-height:100%; +-} +- +-#packages-nav { +- height:270px; +- max-height:inherit; +- position:relative; +- overflow:auto; +-} +- +-#classes-nav, +-#devdoc-nav { +- overflow:auto; +- position:relative; +-} +- +-#side-nav ul { +- list-style: none; +- margin: 0; +- padding:5px 0; +-} +- +-#side-nav ul ul { +- margin: .5em 0 0 0; +- padding: 0; +-} +- +-#side-nav li { +- padding:0; +- padding:1px 0 1px 0; +- zoom:1; +-} +- +-#side-nav li span.heading, +-#side-nav li h2 { +- display:block; +- font-size:12px; +- font-weight: bold; +- margin:.5em 0 0 0; +- padding: 3px 0 1px 9px; +-} +- +-#side-nav li a { +- display: inline-block; /* needed to apply padding to line-wraps */ +- text-decoration:none; +- padding: 0 0 0 18px; +- zoom:1; +-} +- +-#side-nav li a span+span { +- display:none; +-} +- +-#side-nav li a:hover { +- text-decoration:underline; +-} +- +-#side-nav li a+a { +- padding: 0; +-} +-/*second level (nested) list*/ +-#side-nav li li li a { +- padding: 0 0 0 28px; +-} +-/*third level (nested) list*/ +-#side-nav li li li li a { +- padding: 0 0 0 38px; +-} +- +-#side-nav .selected { +- background-color: #435a6e; +- color: #fff; +- font-weight:bold; +-} +- +-#side-nav .selected a { +- color: #fff; +- text-decoration:none; +-} +- +-#side-nav strong { +- display:block; +-} +- +-#side-nav .toggle-list .toggle-img { +- margin:0; +- padding:0; +- position:absolute; +- top:0; +- left:0; +- height:16px; +- width:15px; +- outline-style:none; +-} +-/* second-level toggle */ +-#side-nav .toggle-list .toggle-list .toggle-img { +- left:10px; +-} +- +-#side-nav .closed .toggle-img, +-#side-nav .open .closed .toggle-img { +- background:url('images/triangle-closed-small.png') 7px 4px no-repeat; +-} +-#side-nav .open .toggle-img { +- background:url('images/triangle-opened-small.png') 7px 4px no-repeat; +-} +- +-#side-nav .toggle-list { +- position:relative; +-} +- +-#side-nav .toggle-list ul { +- margin:0; +- display:none; +-} +- +-#side-nav .toggle-list div { +- display:block; +-} +- +-#index-links .selected { +- background-color: #fff; +- color: #000; +- font-weight:normal; +- text-decoration:none; +-} +- +-#index-links { +- padding:7px 0 4px 10px; +-} +- +-/* nav tree */ +- +-#nav-tree ul { +- padding:5px 0 1.5em; +-} +- +-#side-nav #nav-tree ul li a, +-#side-nav #nav-tree ul li span.no-children { +- padding: 0 0 0 0; +- margin: 0; +-} +- +-#nav-tree .plus { +- margin: 0 3px 0 0; +-} +- +-#nav-tree ul ul { +- list-style: none; +- margin: 0; +- padding: 0 0 0 0; +-} +- +-#nav-tree ul li { +- margin: 0; +- padding: 0 0 0 0; +- white-space: nowrap; +-} +- +-#nav-tree .children_ul { +- margin:0; +-} +- +-#nav-tree a.nolink { +- color: black; +- text-decoration: none; +-} +- +-#nav-tree span.label { +- width: 100%; +-} +- +-#nav-tree { +- overflow-x: auto; +- overflow-y: scroll; +-} +- +-#nav-swap { +- font-size:10px; +- line-height:10px; +- margin-left:1em; +- text-decoration:none; +- display:block; +-} +- +-#tree-link { +- +-} +- +-/* DOCUMENT BODY */ +- +-#doc-content { +- overflow:auto; +-} +- +-#jd-header { +- background-color: #E2E2E2; +- padding: 7px 15px; +-} +- +-#jd-header h1 { +- margin: 0 0 10px; +- font-size:1.7em; +-} +- +-#jd-header .crumb { +- font-size:.9em; +- line-height:1em; +- color:#777; +-} +- +-#jd-header .crumb a, +-#jd-header .crumb a:visited { +- text-decoration:none; +- color:#777; +-} +- +-#jd-header .crumb a:hover { +- text-decoration:underline; +-} +- +-#jd-header table { +- margin:0; +- padding:0; +-} +- +-#jd-header td { +- border:none; +- padding:0; +- vertical-align:top; +-} +- +-#jd-header.guide-header { +- background-color:#fff; +- color:#435a6e; +- height:50px; +-} +- +-#jd-descr { +- position:relative; +-} +- +-/* summary tables for reference pages */ +-.jd-sumtable { +- margin: .5em 1em 1em 1em; +- width:95%; /* consistent table widths; within IE's quirks */ +- font-size:.9em; +-} +- +-.jd-sumtable a { +- text-decoration:none; +-} +- +-.jd-sumtable a:hover { +- text-decoration:underline; +-} +- +-/* the link inside a sumtable for "Show All/Hide All" */ +-.toggle-all { +- display:block; +- float:right; +- font-weight:normal; +- font-size:0.9em; +-} +- +-/* adjustments for in/direct subclasses tables */ +-.jd-sumtable-subclasses { +- margin: 1em 0 0 0; +- max-width:968px; +-} +- +-/* extra space between end of method name and open-paren */ +-.sympad { +- margin-right: 2px; +-} +- +-/* right alignment for the return type in sumtable */ +-.jd-sumtable .jd-typecol { +- text-align:right; +-} +- +-/* adjustments for the expando table-in-table */ +-.jd-sumtable-expando { +- margin:.5em 0; +- padding:0; +-} +- +-/* a div that holds a short description */ +-.jd-descrdiv { +- padding:3px 1em 0 1em; +- margin:0; +- border:0; +-} +- +-/* page-top-right container for reference pages (holds +-links to summary tables) */ +-#api-info-block { +- font-size:.8em; +- padding:6px 10px; +- font-weight:normal; +- float:right; +- text-align:right; +- color:#999; +- max-width:70%; +-} +- +-#api-level-toggle { +- padding:0 10px; +- font-size:11px; +- float:right; +-} +- +-#api-level-toggle label.disabled { +- color:#999; +-} +- +-div.api-level { +- font-size:.8em; +- font-weight:normal; +- color:#999; +- float:right; +- padding:0 7px 0; +- margin-top:-25px; +-} +- +-#api-info-block div.api-level { +- font-size:1.3em; +- font-weight:bold; +- float:none; +- color:#444; +- padding:0; +- margin:0; +-} +- +-/* Force link colors for IE6 */ +-div.api-level a { +- color:#999; +-} +-#api-info-block div.api-level a:link { +- color:#444; +-} +-#api-level-toggle a { +- color:#999; +-} +- +-div#deprecatedSticker { +- display:none; +- z-index:99; +- position:fixed; +- right:15px; +- top:114px; +- margin:0; +- padding:1em; +- background:#FFF; +- border:1px solid #dddd00; +- box-shadow:-5px 5px 10px #ccc; +- -moz-box-shadow:-5px 5px 10px #ccc; +- -webkit-box-shadow:-5px 5px 10px #ccc; +-} +- +-div#naMessage { +- display:none; +- width:555px; +- height:0; +- margin:0 auto; +-} +- +-div#naMessage div { +- z-index:99; +- width:450px; +- position:fixed; +- margin:50px 0; +- padding:4em 4em 3em; +- background:#FFF; +- border:1px solid #dddd00; +- box-shadow:-10px 10px 40px #888; +- -moz-box-shadow:-10px 10px 40px #888; +- -webkit-box-shadow:-10px 10px 40px #888; +-} +-/* IE6 can't position fixed */ +-* html div#naMessage div { position:absolute; } +- +-div#naMessage strong { +- font-size:1.1em; +-} +- +-.absent, +-.absent a:link, +-.absent a:visited, +-.absent a:hover, +-.absent * { +- color:#bbb !important; +- cursor:default !important; +- text-decoration:none !important; +-} +- +-#api-level-toggle a, +-.api-level a { +- color:inherit; +- text-decoration:none; +-} +- +-#api-level-toggle a:hover, +-.api-level a:hover { +- color:inherit; +- text-decoration:underline !important; +- cursor:pointer !important; +-} +- +-#side-nav li.absent.selected, +-#side-nav li.absent.selected *, +-#side-nav div.label.absent.selected, +-#side-nav div.label.absent.selected * { +- background-color:#eaeaea !important; +-} +-/* IE6 quirk (won't chain classes, so just keep background blue) */ +-* html #side-nav li.selected, +-* html #side-nav li.selected *, +-* html #side-nav div.label.selected, +-* html #side-nav div.label.selected * { +- background-color: #435a6e !important; +-} +- +- +-.absent h4.jd-details-title, +-.absent h4.jd-details-title * { +- background-color:#f6f6f6 !important; +-} +- +-.absent img { +- opacity: .3; +- filter: alpha(opacity=30); +- -ms-filter:"progid:DXImageTransform.Microsoft.Alpha(Opacity=30)"; +-} +- +- +-/* applies to a div containing links to summary tables */ +-.sum-details-links { +- padding:0; +- font-weight:normal; +-} +- +-.sum-details-links a { +- text-decoration:none; +-} +- +-.sum-details-links a:hover { +- text-decoration:underline; +-} +- +- +-/* inheritance table */ +-.jd-inheritance-table { +- border-spacing:0; +- margin:0; +- padding:0; +- font-size:.9em; +-} +-.jd-inheritance-table td { +- border: none; +- margin: 0; +- padding: 0; +-} +-.jd-inheritance-table .jd-inheritance-space { +- font-weight:bold; +- width:1em; +-} +-.jd-inheritance-table .jd-inheritance-interface-cell { +- padding-left: 17px; +-} +- +-#jd-content { +- padding: 18px 15px; +-} +- +-hr { +- background-color:#ccc; +- border-color:#fff; +- margin:2em 0 1em; +-} +- +-/* DOC CLASSES */ +- +-#jd-content h1 { +-/*sdk page*/ +- font-size:1.6em; +- color:#336666; +- margin:0 0 .5em; +-} +- +-#jd-content h2 { +- font-size:1.45em; +- color:#111; +- border-top:2px solid #ccc; +- padding: .5em 0 0; +- margin: 2em 0 1em 0; +-} +- +-#jd-content h3 { +- font-size:1.3em; +- color:#3a3a3a; +- padding: 0; +- margin: 1.5em 0 .65em 0; +-} +- +-#jd-content h4 { +- font-size:1.1em; +- color:#3a3a3a; +- padding: 0; +- margin: 1.25em 0 .65em 0; +-} +- +-#jd-content h5 { +- font-size:1.0em; +- color:#3a3a3a; +- padding: 0; +- margin: 1em 0 .65em 0; +-} +- +-#jd-content .small-header { +- font-size:1em; +- color:#000; +- font-weight:bold; +- border:none; +- padding:0; +- margin:1em 0 .5em; +- position:inherit; +-} +- +-#jd-content table { +- margin: 0 0 1em 1em; +-} +- +-#jd-content img { +- margin: 0 0 1em 1em; +-} +- +-#jd-content li img, +-#jd-content dd img { +- margin:.5em 0 .5em 1em; +-} +- +-.nolist { +- list-style:none; +- padding:0; +- margin:0 0 1em 1em; +-} +- +-.nolist li { +- padding:0 0 2px; +- margin:0; +-} +- +-h4 .normal { +- font-size:.9em; +- font-weight:normal; +-} +- +-.caps { +- font-variant:small-caps; +- font-size:1.2em; +-} +- +-dl.tag-list dl.atn-list { +- padding:0 0 0 2em; +-} +- +-.jd-details { +-/* border:1px solid #669999; +- padding:4px; */ +- margin:0 0 1em; +-} +- +-/* API reference: a container for the +-.tagdata blocks that make up the detailed +-description */ +-.jd-details-descr { +- padding:0; +- margin:.5em .25em; +-} +- +-/* API reference: a block containing +-a detailed description, a params table, +-seealso list, etc */ +-.jd-tagdata { +- margin:.5em 1em; +-} +- +-.jd-tagdata p { +- margin:0 0 1em 1em; +-} +- +-/* API reference: adjustments to +-the detailed description block */ +-.jd-tagdescr { +- margin:.25em 0 .75em 0; +- line-height:1em; +-} +- +-.jd-tagdescr p { +- margin:.5em 0; +- padding:0; +- +-} +- +-.jd-tagdescr ol, +-.jd-tagdescr ul { +- margin:0 2.5em; +- padding:0; +-} +- +-.jd-tagdescr table, +-.jd-tagdescr img { +- margin:.25em 1em; +-} +- +-.jd-tagdescr li { +-margin:0 0 .25em 0; +-padding:0; +-} +- +-/* API reference: heading marking +-the details section for constants, +-attrs, methods, etc. */ +-h4.jd-details-title { +- font-size:1.15em; +- background-color: #E2E2E2; +- margin:1.5em 0 .6em; +- padding:3px 95px 3px 3px; /* room for api-level */ +-} +- +-h4.jd-tagtitle { +- margin:0; +-} +- +-/* API reference: heading for "Parameters", "See Also", etc., +-in details sections */ +-h5.jd-tagtitle { +- margin:0 0 .25em 0; +- font-size:1em; +-} +- +-.jd-tagtable { +- margin:0; +-} +- +-.jd-tagtable td, +-.jd-tagtable th { +- border:none; +- background-color:#fff; +- vertical-align:top; +- font-weight:normal; +- padding:2px 10px; +-} +- +-.jd-tagtable th { +- font-style:italic; +-} +- +-#jd-content table h2 { +- background-color: #d6d6d6; +- font-size: 1.1em; +- margin:0 0 10px; +- padding:5px; +- left:0; +- width:auto; +-} +- +-div.design-announce { +- border-top:1px solid #33B5E5; +- border-bottom:1px solid #33B5E5; +- padding:5px 10px 10px 55px; +- margin:2em 0; +- background:url('images/icon_design.png') 5px 13px no-repeat; +-} +- +-div.design-announce p { +- margin: .5em 0 0 0; +-} +- +-div.special { +- padding: .5em 1em 1em 1em; +- margin: 0 0 1em; +- background-color: #DAF3FC; +- border:1px solid #d3ecf5; +- border-radius:5px; +- -moz-border-radius:5px; +- -webkit-border-radius:5px; +-} +- +-div.special p { +- margin: .5em 0 0 0; +-} +- +-div.special ol { +- margin: 0; +-} +- +-div.special ol li { +- margin: 0; +- padding: 0; +-} +- +-#jd-content div.special h2, +-#jd-content div.special h3 { +- color:#669999; +- font-size:1.2em; +- border:none; +- margin:0 0 .5em; +- padding:0; +-} +- +-#jd-content div.special.reference h2, +-#jd-content div.special.reference h3, +-#jd-content div.special.reference h4 { +- color:#000; +- font-size:1em; +- border:none; +- font-weight:bold; +- margin:.5em 0; +- padding:0; +-} +- +-p.note, div.note, +-p.caution, div.caution, +-p.warning, div.warning { +- margin: 1em; +- padding: 0 0 0 .5em; +- border-left: 4px solid; +-} +- +-p.special-note, +-div.special-note { +- background-color:#EBF3DB; +- padding:10px 20px; +- margin:0 0 1em; +-} +- +-p.note, +-div.note { +- border-color: #99aacc; +-} +- +-p.warning, +-div.warning { +- border-color: #aa0033; +-} +- +-p.caution, +-div.caution { +- border-color: #ffcf00; +-} +- +-li .note, +-li .caution, +-li .warning { +- margin: .5em 0 0 0; +- padding: .2em .5em .2em .9em; +-} +- +-/* Makes sure the first paragraph does not add top-whitespace within the box*/ +-li .note>p:first-child, +-li .caution>p:first-child, +-li .warning>p:first-child { +- margin-top:0; +- padding-top:0; +-} +- +-dl.xml dt { +- font-variant:small-caps; +- font-size:1.2em; +-} +- +-dl.xml dl { +- padding:0; +-} +- +-dl.xml dl dt { +- font-variant:normal; +- font-size:1em; +-} +- +-.listhead li { +- font-weight: bold; +-} +- +-.listhead li *, /*ie*/.listhead li li { +- font-weight: normal; +-} +- +-ol.no-style, +-ul.no-style { +- list-style:none; +- padding-left:1em; +-} +- +-.new, +-.new-child { +- font-size: .78em; +- font-weight: bold; +- color: #ff3d3d; +- text-decoration: none; +- vertical-align:top; +- line-height:.9em; +- white-space:nowrap; +-} +- +-.toggle-list.open .new-child { +- display:none; +-} +- +-pre.classic { +- background-color:transparent; +- border:none; +- padding:0; +-} +- +-p.img-caption { +- margin: -0.5em 0 1em 1em; /* matches default img left-margin */ +-} +- +-div.figure { +- float:right; +- clear:right; +- margin:1em 0 0 0; +- padding:0 0 0 3em; +- background-color:#fff; +- /* width must be defined w/ an inline style matching the image width */ +-} +- +-#jd-content +-div.figure img { +- margin: 0 0 1em; +-} +- +-div.figure p.img-caption { +- margin: -0.5em 0 1em 0; +-} +- +-p.table-caption { +- margin: 0 0 0.5em 1em; /* matches default table left-margin */ +-} +- +- +-/* toggle for misc content (such as long sample code) +- see toggleContent() script in android-developer-docs.js */ +-.toggle-content.closed .toggle-content-toggleme { +- display:none; +-} +- +-.toggle-content a[href="#"] { +- text-decoration:none; +- color:inherit; +-} +- +-.toggle-content-toggleme { +- padding-bottom:1px; /* fixes animation bounce due to margins */ +-} +- +-#jd-content .toggle-content img.toggle-content-img { +- margin:0; +-} +- +- +-/* BEGIN quickview sidebar element styles */ +- +-#qv-wrapper { +- float: right; +- width:310px; /* +35px padding */ +- background-color:#fff; +- margin:-48px 0 2px 0; +- padding:0 0 20px 35px; +-} +- +-#qv { +- background-color:#fff; +- border:4px solid #dee8f1; +- margin:0; +- padding:0 5px 5px; +- width:292px; /* +10px padding; +8px border */ +- font-size:.9em; +-} +- +-#qv ol { +- list-style:none; +- padding: 0; +-} +- +-#qv ol ol{ +- list-style:none; +- padding: 0 0 0 12px; +- margin:0; +-} +- +-#qv ul { +- padding: 0 10px 0 2em; +-} +- +-#qv li { +- padding: 0 10px 3px; +- line-height: 1.2em; +-} +- +-#qv li li { +- padding: 3px 10px 0; +-} +- +-#qv ul li { +- padding: 0 10px 0 0; +-} +- +-#qv li.selected a { +- color:#555; +- text-decoration:none; +-} +- +-#qv a, +-#qv a code { +- color:#cc6600; +-} +- +-#qv p { +- margin:8px 0 0; +- padding:0 10px; +-} +- +-#jd-content #qv h2 { +- font-size:1.05em; +- font-weight:bold; +- margin:12px 0 .25em 0; +- padding:0 10px; +- background-color:transparent; +- color:#7BB026; +- border:none; +- left:0; +- z-index:1; +-} +- +-#qv-extra #rule { +- padding: 0 10px; +- margin: 0; +-} +- +-#qv-sub-rule { +- padding: 5px 15px 10px; +- margin: 0; +-} +- +-#jd-content +-#qv-sub-rule h2 { +- margin: 0 0 .5em 0; +-} +- +-/* END quickview sidebar element styles */ +- +-/* Begin sidebox sidebar element styles */ +- +-.sidebox-wrapper { +- float:right; +- clear:right; +- width:310px; /* +35px padding */ +- background-color:#fff; +- margin:0; +- padding:0 0 20px 35px; +-} +- +-.sidebox { +- border-left:1px solid #dee8f1; +- background-color:#ffffee; +- margin:0; +- padding:8px 12px; +- font-size:0.9em; +- width:285px; /* +24px padding; +1px border */ +-} +- +-.sidebox p { +- margin-bottom: .75em; +-} +- +-.sidebox ul { +- padding: 0 0 0 1.5em; +-} +- +-.sidebox li ul { +- margin-top:0; +- margin-bottom:.1em; +-} +- +-.sidebox li { +-padding:0 0 0 0em; +-} +- +-#jd-content .sidebox h2, +-#jd-content .sidebox h3, +-#jd-content .sidebox h4, +-#jd-content .sidebox h5 { +- border:none; +- font-size:1em; +- margin:0; +- padding:0 0 8px; +- left:0; +- z-index:0; +-} +- +-.sidebox hr { +- background-color:#ccc; +- border:none; +-} +- +-/* End sidebox sidebar element styles */ +- +-/* BEGIN developer training bar styles */ +- +-div#tb-wrapper { +- float: right; +- clear:right; +- width:380px; /* +25px padding = 405 */ +- background-color:#fff; +- margin:0 0 2px 0; +- padding:0 0 20px 25px; +-} +- +-div#tb { +- margin:0; +- padding:0 15px; +- width:350px; /* +15px padding = 380 */ +- font-size:.9em; +- background:#e9e9e9; +- border:1px solid #aaa; +- border-radius:5px; +- -moz-border-radius:5px; +- -webkit-border-radius:5px; +- overflow:auto; +-} +- +-div#tb h2 { +- font-size:1.3em; +- font-weight:bold; +- margin:1em 0; +- padding:0; +- background-color:transparent; +- border:none; +- clear:both; +-} +- +-div.download-box a.button { +- color: #069; +- font-size:1.1em; +- font-weight:bold; +- text-decoration:none; +- height:27px; +- line-height:27px; +- text-align:center; +- padding:5px 8px; +- background-color: #fff; +- border: 1px solid #aaa; +- -webkit-border-radius: 2px; +- -moz-border-radius: 2px; +- border-radius: 2px; +-} +- +-div.download-box a.button:hover { +- border-color: #09C; +- background-color: #4CADCB; +- background-image: -webkit-gradient(linear,left top,left bottom,from(#5dbcd9),to(#4cadcb)); +- background-image: -webkit-linear-gradient(top,#5dbcd9,#4cadcb); +- background-image: -moz-linear-gradient(top,#5dbcd9,#4cadcb); +- background-image: -ms-linear-gradient(top,#5dbcd9,#4cadcb); +- background-image: -o-linear-gradient(top,#5dbcd9,#4cadcb); +- background-image: linear-gradient(top,#5dbcd9,#4cadcb); +- filter: progid:DXImageTransform.Microsoft.gradient(startColorStr='#5dbcd9',EndColorStr='#4cadcb'); +- color: #fff; +-} +- +-div.download-box a.button:active { +- background-color: #1E799A; +- background-image: none; +- border-color: #30B7E6; +-} +- +-div.download-box p.filename { +- font-size:0.85em; +- color:#888; +- margin:4px 0 1em 10px; +-} +- +-/* End developer training bar */ +- +-/* Training nav bar (previous/next) */ +- +-div.training-nav-top { +- float: right; +- width:380px; /* +25px padding = 405 */ +- margin:-58px 0 0 0; +- padding:0 0 20px 25px; +-} +- +-div.training-nav-bottom { +- padding:1px; /* for weird FF bug (scrollbar appears) */ +- margin:3em 0; +- overflow:auto; +-} +- +-div.training-nav-button-next a, +-div.training-nav-button-previous a { +- display:block; +- width:160px; +- height:55px; +- padding:4px 7px; +- border:1px solid #aaa; +- border-radius:5px; +- -moz-border-radius:5px; +- -webkit-border-radius:5px; +- text-decoration:none; +- font-weight:bold; +-} +- +-div.training-nav-button-next a:hover, +-div.training-nav-button-previous a:hover { +- border:1px solid #069; /* match link color */ +-} +- +-div.training-nav-button-next a:active, +-div.training-nav-button-previous a:active { +- border:1px solid #f00; /* match link color */ +-} +- +-div.training-nav-button-previous { +- float:left; +- text-align:left; +-} +- +-div.training-nav-button-next { +- float:right; +- text-align:right; +-} +- +-span.training-nav-button-title { +- display:block; +- font-size:.85em; +- font-weight:normal; +- line-height:1.3em; +- margin:.5em 0 0; +-} +- +-/* End training nav bar */ +- +-/* BEGIN image and caption styles (originally for UI Guidelines docs) */ +- +-table.image-caption { +- padding:0; +- margin:.5em 0; +- border:0; +-} +- +-td.image-caption-i { +- font-size:92%; +- padding:0 5px; +- margin:0; +- border:0; +-} +- +-td.image-caption-i img { +- padding:0 1em; +- margin:0; +-} +- +-.image-list { +- width:24px; +- text-align:center; +-} +- +-td.image-caption-c { +- font-size:92%; +- padding:1em 2px 2px 2px; +- margin:0; +- border:0; +- width:350px; +-} +- +-.grad-rule-top { +-background-image:url(images/grad-rule-qv.png); +-background-repeat:no-repeat; +-padding-top:1em; +-margin-top:0; +-} +- +-.image-caption-nested { +- margin-top:0; +- padding:0 0 0 1em; +-} +- +-.image-caption-nested td { +- padding:0 4px 2px 0; +- margin:0; +- border:0; +-} +- +-/* END image and caption styles */ +- +-/* table of contents */ +- +-ol.toc { +- margin: 0 0 1em 0; +- padding: 0; +- list-style: none; +- font-size:95%; +-} +- +-ol.toc li { +- font-weight: bold; +- margin: 0 0 .5em 1em; +- padding: 0; +-} +- +-ol.toc li p { +- font-weight: normal; +-} +- +-ol.toc li ol { +- margin: 0; +- padding: 0; +-} +- +-ol.toc li li { +- padding: 0; +- margin: 0 0 0 1em; +- font-weight: normal; +- list-style: none; +-} +- +-table ol.toc { +- margin-left: 0; +-} +- +-.columns td { +- padding:0 5px; +- border:none; +-} +- +-/* link table */ +-.jd-linktable { +- margin: 0 0 1em; +- border-bottom: 1px solid #888; +-} +-.jd-linktable th, +-.jd-linktable td { +- padding: 3px 5px; +- vertical-align: top; +- text-align: left; +- border:none; +-} +-.jd-linktable tr { +- background-color: #fff; +-} +-.jd-linktable td { +- border-top: 1px solid #888; +- background-color: inherit; +-} +-.jd-linktable td p { +- padding: 0 0 5px; +-} +-.jd-linktable .jd-linkcol { +-} +-.jd-linktable .jd-descrcol { +-} +-.jd-linktable .jd-typecol { +- text-align:right; +-} +-.jd-linktable .jd-valcol { +-} +-.jd-linktable .jd-commentrow { +- border-top:none; +- padding-left:25px; +-} +-.jd-deprecated-warning { +- margin-top: 0; +- margin-bottom: 10px; +-} +- +-tr.alt-color { +- background-color: #f6f6f6; +-} +- +-/* expando trigger */ +-#jd-content .jd-expando-trigger-img { +- margin:0; +-} +- +-/* jd-expando */ +-.jd-inheritedlinks { +- padding:0 0 0 13px +-} +- +-/* SDK PAGE */ +-table.download tr { +- background-color:#d9d9d9; +-} +- +-table.download tr.alt-color { +- background-color:#ededed; +-} +- +-table.download td, +-table.download th { +- border:2px solid #fff; +- padding:10px 5px; +-} +- +-table.download th { +- background-color:#6d8293; +- color:#fff; +-} +- +-/* INLAY 180 COPY and 240PX EXTENSION */ +-/* modified to 43px so that all browsers eliminate the package panel h-scroll */ +-.g-tpl-240 .g-unit, +-.g-unit .g-tpl-240 .g-unit, +-.g-unit .g-unit .g-tpl-240 .g-unit { +- display: block; +- margin: 0 0 0 243px; +- width: auto; +- float: none; +-} +-.g-unit .g-unit .g-tpl-240 .g-first, +-.g-unit .g-tpl-240 .g-first, +-.g-tpl-240 .g-first { +- display: block; +- margin: 0; +- width: 243px; +- float: left; +-} +-/* 240px alt */ +-.g-tpl-240-alt .g-unit, +-.g-unit .g-tpl-240-alt .g-unit, +-.g-unit .g-unit .g-tpl-240-alt .g-unit { +- display: block; +- margin: 0 243px 0 0; +- width: auto; +- float: none; +-} +-.g-unit .g-unit .g-tpl-240-alt .g-first, +-.g-unit .g-tpl-240-alt .g-first, +-.g-tpl-240-alt .g-first { +- display: block; +- margin: 0; +- width: 243px; +- float: right; +-} +- +-/* 200px */ +-.g-tpl-200 .g-unit, +-.g-unit .g-tpl-200 .g-unit, +-.g-unit .g-unit .g-tpl-200 .g-unit { +- display: block; +- margin: 0 0 0 200px; +- width: auto; +- float: none; +-} +-.g-unit .g-unit .g-tpl-200 .g-first, +-.g-unit .g-tpl-200 .g-first, +-.g-tpl-200 .g-first { +- display: block; +- margin: 0; +- width: 200px; +- float: left; +-} +-/* 200px alt */ +-.g-tpl-200-alt .g-unit, +-.g-unit .g-tpl-200-alt .g-unit, +-.g-unit .g-unit .g-tpl-200-alt .g-unit { +- display: block; +- margin: 0 200px 0 0; +- width: auto; +- float: none; +-} +-.g-unit .g-unit .g-tpl-200-alt .g-first, +-.g-unit .g-tpl-200-alt .g-first, +-.g-tpl-200-alt .g-first { +- display: block; +- margin: 0; +- width: 200px; +- float: right; +-} +- +-/* 190px */ +-.g-tpl-190 .g-unit, +-.g-unit .g-tpl-190 .g-unit, +-.g-unit .g-unit .g-tpl-190 .g-unit { +- display: block; +- margin: 0 0 0 190px; +- width: auto; +- float: none; +-} +-.g-unit .g-unit .g-tpl-190 .g-first, +-.g-unit .g-tpl-190 .g-first, +-.g-tpl-190 .g-first { +- display: block; +- margin: 0; +- width: 190px; +- float: left; +-} +-/* 190px alt */ +-.g-tpl-190-alt .g-unit, +-.g-unit .g-tpl-190-alt .g-unit, +-.g-unit .g-unit .g-tpl-190-alt .g-unit { +- display: block; +- margin: 0 190px 0 0; +- width: auto; +- float: none; +-} +-.g-unit .g-unit .g-tpl-190-alt .g-first, +-.g-unit .g-tpl-190-alt .g-first, +-.g-tpl-190-alt .g-first { +- display: block; +- margin: 0; +- width: 190px; +- float: right; +-} +- +-/* 180px */ +-.g-tpl-180 .g-unit, +-.g-unit .g-tpl-180 .g-unit, +-.g-unit .g-unit .g-tpl-180 .g-unit { +- display: block; +- margin: 0 0 0 180px; +- width: auto; +- float: none; +-} +-.g-unit .g-unit .g-tpl-180 .g-first, +-.g-unit .g-tpl-180 .g-first, +-.g-tpl-180 .g-first { +- display: block; +- margin: 0; +- width: 180px; +- float: left; +-} +-/* 180px alt */ +-.g-tpl-180-alt .g-unit, +-.g-unit .g-tpl-180-alt .g-unit, +-.g-unit .g-unit .g-tpl-180-alt .g-unit { +- display: block; +- margin: 0 180px 0 0; +- width: auto; +- float: none; +-} +-.g-unit .g-unit .g-tpl-180-alt .g-first, +-.g-unit .g-tpl-180-alt .g-first, +-.g-tpl-180-alt .g-first { +- display: block; +- margin: 0; +- width: 180px; +- float: right; +-} +- +- +-/* JQUERY RESIZABLE STYLES */ +-.ui-resizable { position: relative; } +-.ui-resizable-handle { position: absolute; display: none; font-size: 0.1px; z-index:1; } +-.ui-resizable .ui-resizable-handle { display: block; } +-body .ui-resizable-disabled .ui-resizable-handle { display: none; } +-body .ui-resizable-autohide .ui-resizable-handle { display: none; } +-.ui-resizable-s { cursor: s-resize; height: 6px; width: 100%; bottom: 0px; left: 0px; +- background: transparent url("images/resizable-s2.gif") repeat scroll center top; } +-.ui-resizable-e { cursor: e-resize; width: 6px; right: 0px; top: 0px; height: 100%; +- background: transparent url("images/resizable-e2.gif") repeat scroll right center; } +- +-@media print { +- +- body { +- overflow:visible; +- } +- +- #header { +- height:60px; +- } +- +- #headerLeft { +- padding:0; +- } +- +- #header-tabs, +- #headerRight, +- #side-nav, +- #api-info-block { +- display:none; +- } +- +- #body-content { +- position:inherit; +- } +- +- #doc-content { +- margin-left:0 !important; +- height:auto !important; +- width:auto !important; +- overflow:inherit; +- display:inline; +- } +- +- #jd-header { +- padding:10px 0; +- } +- +- #jd-content { +- padding:15px 0 0; +- } +- +- #footer { +- float:none; +- margin:2em 0 0; +- } +- +- h4.jd-details-title { +- border-bottom:1px solid #666; +- } +- +- pre { +- /* these allow lines to break (if there's a white space) */ +- overflow: visible; +- text-wrap: unrestricted; +- white-space: -moz-pre-wrap; /* Moz */ +- white-space: -pre-wrap; /* Opera 4-6 */ +- white-space: -o-pre-wrap; /* Opera 7 */ +- white-space: pre-wrap; /* CSS3 */ +- word-wrap: break-word; /* IE 5.5+ */ +- } +- +- h1, h2, h3, h4, h5, h6 { +- page-break-after: avoid; +- } +- +- table, img { +- page-break-inside: avoid; +- } +-} +diff --git a/tools/droiddoc/templates-sdk-dev/assets/css/default.css b/tools/droiddoc/templates-sdk-dev/assets/css/default.css +deleted file mode 100644 +index e422d75..0000000 +--- a/tools/droiddoc/templates-sdk-dev/assets/css/default.css ++++ /dev/null +@@ -1,10452 +0,0 @@ +-/* color definitions */ +-/* 16 column layout */ +-/* clearfix idiom */ +-/* common mixins */ +-/* page layout + top-level styles */ +-::selection { +- background-color: #0099cc; +- color: #fff; } +-::-webkit-selection { +- background-color: #0099cc; +- color: #fff; } +-::-moz-selection { +- background-color: #0099cc; +- color: #fff; } +- +-html, body { +- height: 100%; +- margin: 0; +- padding: 0; +- background-color: #fff; +- -webkit-font-smoothing: antialiased; +- -moz-osx-font-smoothing: grayscale; +- /* prevent subpixel antialiasing, which thickens the text */ +- /* text-rendering: optimizeLegibility; */ +- /* turned off ligatures due to bug 5945455 */ } +- +-body { +- color: #515151; +- color: rgba(0, 0, 0, .68); +- font: 14px/24px Roboto, sans-serif; +- font-weight: 400; +- letter-spacing:.1; +- padding: 0 20px; +-} +- +-@media (max-width: 719px) { +- html { +- /* Disable accidental horizontal overflow. */ +- overflow-x: hidden; +- } +- +- body { +- padding-left: 10px; +- padding-right: 10px; +- } +-} +- +-#page-container { +- width: 940px; +- margin: 0 40px; } +- +-#page-header { +- height: 80px; +- margin-bottom: 20px; +- font-size: 48px; +- line-height: 48px; +- font-weight: 100; +- padding-left: 10px; } +- #page-header a { +- display: block; +- position: relative; +- top: 20px; +- text-decoration: none; +- color: #555555 !important; } +- +-#main-row { +- display: inline-block; } +- #main-row:after { +- content: "."; +- display: block; +- height: 0; +- clear: both; +- visibility: hidden; } +- * html #main-row { +- height: 1px; } +- +-#page-footer { +- margin-left: 190px; +- margin-top: 80px; +- color: #999999; +- padding-bottom: 40px; +- font-size: 12px; +- line-height: 15px; } +- #page-footer a { +- color: #777777; } +- #page-footer #copyright { +- margin-bottom: 10px; } +- +-.hide-text { +- position: absolute; +- text-indent: -9999px; +-} +- +-#nav-container { +- width: 160px; +- min-height: 10px; +- margin-right: 20px; +- float: left; } +- +-#devdoc-nav h2 { +- border:0; +-} +- +-#devdoc-nav.fixed { +- position: fixed; +- margin:0; +- top: 84px; /* sticky-header height + 20px gutter */ +-} +- +-.dac-devdoc-toggle { +- cursor: pointer; +- padding: 8px 0; +-} +- +-.scroll-pane { +- /* Match height of fixed parent. */ +- height: 100%; +-} +- +-#content { +- width: 760px; +- float: left; } +- +- +-/***** PREVIOUSLY style.css ******************/ +-/* This should be close to the top, so it is easier to override. */ +-[dir='rtl'] { +- direction: rtl; +-} +-html { +- line-height: 20px; +-} +-pre, table, input, textarea, code { +- font-size: 1em; +-} +-address, abbr, cite { +- font-style: normal; +-} +-[dir='rtl'] th { +- text-align: right; +-} +-html[lang^=ja] blockquote, html[lang^=ja] q, html[lang^=ko] blockquote, html[lang^=ko] q, +-html[lang^=zh] blockquote, html[lang^=zh] q { +- font-style: normal; +-} +-q { +- font-style: italic; +-} +-fieldset, iframe, img { +- border: 0; +-} +-img { +- border: none; +- -ms-interpolation-mode: bicubic; +- max-width: 100%; +- vertical-align: middle; +-} +- +-video { +- cursor: pointer; +- margin-bottom: 10px; /* same as img */ +- max-width: 100%; +- object-fit: cover; +-} +- +-.video-wrapper { +- line-height: 0; +- margin-bottom: 10px; /* same as img */ +- position: relative; +-} +- +-.video-wrapper video { +- margin:0; +-} +- +-.video-wrapper:before { +- background: rgba(0, 0, 0, 0.5) url(//material-design.storage.googleapis.com/images/play.svg) no-repeat center center; +- background-size: 72px 72px; +- bottom: 0; +- content: ""; +- left: 0; +- position: absolute; +- right: 0; +- top: 0; +- transition: opacity .2s; +-} +- +-.video-wrapper:hover:before { +- opacity: .7; +-} +- +-.video-wrapper.playing:before { +- opacity: 0; +-} +- +-q { +- quotes: none; +-} +-sup, sub { +- font-size: 11px; +- line-height: 0; +-} +- +-table, fieldset { +- margin: 0; +-} +-/* Biggest type */ +-.display-1 { +- font-size: 56px; +- line-height: 68px; +-} +-@media (max-width: 719px) { +- .display-1 { +- font-size: 44px; +- line-height: 56px; +- } +-} +-h1, h2, h3 { +- color: #212121; +- color: rgba(0, 0, 0, .87); +-} +-h1 { +- font-size: 44px; +- line-height: 56px; +- font-weight: 300; +- margin: 0; +- padding: 24px 0 12px; +-} +-h1.short { +- padding-right:320px; +-} +-@media (max-width: 719px) { +- h1 { +- font-size: 36px; +- line-height: 48px; +- } +-} +-h2 { +- clear: left; +- font-size: 28px; +- font-weight: 400; +- line-height: 32px; +- margin: 0; +- padding: 12px 0 16px; +-} +-h3 { +- font-size: 24px; +- line-height: 32px; +- font-weight: 400; +- margin: 0; +- padding: 8px 0 12px; +-} +-h4 { +- font-size: 18px; +- line-height: 24px; +- margin: 0; +- padding: 4px 0 8px; +- font-weight: 500; +-} +-h5, h6 { +- font-size: 16px; +- line-height: 24px; +- margin: 0; +- padding: 4px 0 8px; +-} +-th>h3 { +- font-size:inherit; +- line-height:inherit; +- font-weight:inherit; +- margin:0; +- padding:0; +- color:inherit; +-} +-hr { /* applied to the bottom of h2 elements */ +- height: 1px; +- margin: 7px 0 12px; +- border: 0; +- background: rgba(0, 0, 0, 0.1); +-} +-h2[id], h3[id], h4[id], h5[id], h6[id] { +- margin-top: -64px; +- border-top: 64px solid transparent; +- -webkit-background-clip: padding-box; +- -moz-background-clip: padding; +- background-clip: padding-box; +-} +-p, pre, table, form { +- margin: 0 0 12px; +-} +-small { +- font-size: 11.5px; +- color: #000; +-} +-ul, ol { +- margin: 0 0 15px 20px; +- padding: 0; +-} +-[dir='rtl'] ul, [dir='rtl'] ol { +- margin: 10px 30px 10px 10px; +-} +-ul ul, ul ol, ol ul, ol ol { +- margin-bottom: 0; +- margin-top: 0; +-} +-li { +- margin: 0 0 12px; +-} +-dt { +- margin: 24px 0 12px; +-} +-dd { +- margin:0 0 10px 40px; +-} +-dd p, +-dd pre, +-dd ul, +-dd ol, +-dd dl { +- margin-top:10px; +-} +-li p, +-li pre, +-li ul, +-li ol, +-li dl, +-#body-content li img { +- margin-top: 6px; +- margin-bottom: 6px; +-} +-dl dd dl:first-child { +- margin-top: 0; +-} +-pre strong, pre b, a strong, a b, a code { +- color: inherit; +-} +-pre, code { +- color: #060; +- font: 13px/18px Consolas, "Liberation Mono", Menlo, Monaco, Courier, monospace; +- -webkit-font-smoothing: subpixel-antialiased; +- -moz-osx-font-smoothing: auto; +-} +-legend { +- display: none; +-} +-a, .link-color { +- color: #039BE5; +- text-decoration: none; +-} +-a:focus, a:hover { +- color: rgba(3, 155, 229, .7); +- text-decoration: none; +-} +-a.white { +- color: #fff; +- text-decoration:underline; +-} +-a.white:hover, a.white:active { +- color: #ccc; +-} +-strong, b { +- font-weight: bold; +-} +-table { +- border-collapse: collapse; +- border-spacing: 0; +- border:0; +- margin: .5em 1em 1em 0; +- width:100%; /* consistent table widths; within IE's quirks */ +- background-color:#f7f7f7; +-} +-th, td { +- padding: 4px 12px; +- vertical-align: top; +- text-align: left; +-} +-td { +- background-color:inherit; +- border:solid 1px #DDD; +-} +-td *:last-child { +- margin-bottom:0; +-} +-th { +- background-color: #999; +- color: #fff; +- border:solid 1px #DDD; +- font-weight: normal; +-} +-tr.alt th { +- color:inherit; +- background-color: #e0e0e0; +-} +-tr:first-of-type th:first-of-type:empty { +- visibility: hidden; +-} +- +-a.external-link { +- background:url('../images/styles/open_new_page.png') no-repeat 100% 50%; +- padding-right:16px; +-} +- +-#body-content img { +- margin-bottom:12px; +-} +- +-#body-content p>img { +- margin-bottom:0; +-} +- +-#body-content img.inline-icon { +- vertical-align:sub; +- margin:0; +- height:16px; +-} +- +-em { +- font-style: italic; } +- +-acronym, +-.tooltip-link { +- border-bottom: 1px dotted #555555; +- cursor: help; } +- +-acronym:hover, +-.tooltip-link:hover { +- color: #7aa1b0; +- border-bottom-color: #7aa1b0; } +- +-img.with-shadow, +-video.with-shadow { +- box-shadow: 0 2px 4px rgba(0, 0, 0, 0.25); } +- +-/* disclosures mixin */ +-/* content layout */ +-/* This grid is deprecated in favor of .cols and .col-X */ +-.layout-content-row { +- display: inline-block; +- margin-bottom: 10px; } +- * html .layout-content-row { +- height: 1px; } +- +-.layout-content-col { +- float: left; +- margin-left: 20px; } +- .layout-content-col:first-child { +- margin-left: 0; } +- .layout-content-col h3, +- .layout-content-col h4 { +- padding-top:0; } +- +-.layout-content-col.span-1 { +- width: 40px; } +- +-.layout-content-col.span-2 { +- width: 100px; } +- +-.layout-content-col.span-3 { +- width: 160px; } +- +-.layout-content-col.span-4 { +- width: 220px; } +- +-.layout-content-col.span-5 { +- width: 280px; } +- +-.layout-content-col.span-6 { +- width: 340px; } +- +-.layout-content-col.span-7 { +- width: 400px; } +- +-.layout-content-col.span-8 { +- width: 460px; } +- +-.layout-content-col.span-9 { +- width: 520px; } +- +-.layout-content-col.span-10 { +- width: 580px; } +- +-.layout-content-col.span-11 { +- width: 640px; } +- +-.layout-content-col.span-12 { +- width: 700px; } +- +-.layout-content-col.span-13 { +- width: 760px; } +- +-.vspace.size-1 { +- height: 10px; } +- +-.vspace.size-2 { +- height: 20px; } +- +-.vspace.size-3 { +- height: 30px; } +- +-.vspace.size-4 { +- height: 40px; } +- +-.vspace.size-5 { +- height: 50px; } +- +-.vspace.size-6 { +- height: 60px; } +- +-.vspace.size-7 { +- height: 70px; } +- +-.vspace.size-8 { +- height: 80px; } +- +-.vspace.size-9 { +- height: 90px; } +- +-.vspace.size-10 { +- height: 100px; } +- +-.vspace.size-11 { +- height: 110px; } +- +-.vspace.size-12 { +- height: 120px; } +- +-.vspace.size-13 { +- height: 130px; } +- +-.vspace.size-14 { +- height: 140px; } +- +-.vspace.size-15 { +- height: 150px; } +- +-.vspace.size-16 { +- height: 160px; } +- +-.new, +-.new-child { +- font-size: .78em; +- font-weight: bold; +- color: #ff3d3d; +- vertical-align:top; +- white-space:nowrap; +-} +- +-/* content header */ +-.content-header { +- position: relative; +-} +-.content-header:before, +-.content-header:after { +- content: ''; +- display: table; +- /* Clear heading margins, to make absolutely positioned nav a bit more predictable. */ +-} +-.content-header.just-links { +- margin-bottom:0; +- padding-bottom:0;} +- +-.content-footer { +- margin-top: 10px; +- padding-top:10px; +- width:100%; } +- +-.content-footer .col-9 { +- margin-left:0; +-} +-.content-footer .col-4 { +- margin-right:0; +-} +-.content-footer.wrap { +- max-width:940px; +-} +-.content-footer .plus-container { +- margin:5px 0 0; +- text-align:right; +- float:right; +-} +- +-a.back-link { +- text-decoration: none; +- text-transform: uppercase; +-} +- +-.content-header .paging-links { +- position: absolute; +- right: 0; +- top: 8px; +- width: 220px; +-} +-.paging-links { +- position: relative; +- min-height:30px; } +- .paging-links a, +- .training-nav-top a { +- text-decoration: none; } +- .training-nav-top .prev-page-link:before, +- a.back-link:before { +- content: ''; +- background: transparent url(../images/styles/disclosure_left.png) no-repeat scroll 50% 50%; +- width: 10px; +- height: 10px; +- display: inline-block; +- margin-right: 5px; } +- .training-nav-top .next-page-link:after, +- .training-nav-top .start-class-link:after, +- .training-nav-top .start-course-link:after, +- .go-link:after { +- content: ''; +- background: transparent url(../images/styles/disclosure_right.png) no-repeat scroll 50% 50%; +- width: 10px; +- height: 10px; +- display: inline-block; +- margin-left: 5px; } +- .prev-page-link.inline:before { +- content: none; } +- .next-page-link.inline:after { +- content: none; } +- +- .content-footer { +- left:0; +- } +- +- .training-nav-top a { +- border-bottom:0; +- box-sizing: border-box; +- color: inherit; +- display:block; +- float:left; +- padding:10px 0; +- line-height:30px; +- text-align:center; +- width: 50%; +- } +- +- .training-nav-top a.prev-page-link { +- padding-left: 15px; +- text-align: left; +- } +- +- .training-nav-top a.next-page-link { +- padding-right: 15px; +- text-align: right; +- } +- +- .paging-links a.disabled, +- .training-nav-top a.disabled, +- .content-footer a.disabled { +- color:#bbb; +- } +- +- .paging-links a.disabled:hover, +- .training-nav-top a.disabled:hover, +- .content-footer a.disabled:hover { +- cursor:default; +- color:#bbb !important; +- } +- +- .training-nav-top a.start-class-link, +- .training-nav-top a.start-course-link { +- width:100%; +- } +- +- /* list of classes on course landing page */ +- ol.class-list { +- counter-reset: class; +- list-style: none; +- margin: 60px 0 0; +- } +- ol.class-list>li { +- box-shadow: 0px 2px 5px 0 rgba(0, 0, 0, 0.26); +- margin: 0 0 20px; +- overflow: hidden; +- } +- ol.class-list .title { +- background: #00bcd4; +- color: #fff; +- display: block; +- font-size: 20px; +- font-weight: 500; +- height: 32px; +- padding: 52px 16px 12px; +- position: relative; +- } +- ol.class-list .title:before { +- border-bottom: 1px solid white; +- box-sizing: border-box; +- /* Disable the numbers for now, since vert few classes need to be taken in order. */ +- /* content: counter(class); */ +- counter-increment: class; +- height: 40px; +- left: 0; +- padding: 10px 1px 0 5px; +- position: absolute; +- top: 0; +- text-align: right; +- min-width: 30px; +- } +- ol.class-list .title h2 { +- color: currentColor; +- font-size: inherit; +- font-weight: inherit; +- padding:0 0 10px; +- display:block; +- float:left; +- width:675px; +- } +- ol.class-list .title span { +- display:none; +- float:left; +- font-size:18px; +- font-weight:bold; +- background: transparent url(../images/styles/disclosure_right.png) no-repeat scroll 50% 50%; +- width: 10px; +- height: 32px; +- } +- +- ol.class-list .description { +- box-sizing: border-box; +- float:left; +- display:block; +- margin:0; +- padding: 16px 10px 16px 16px; +- width: 50%; +- } +- ol.class-list .description.article { +- width: 550px; +- } +- ol.class-list ol { +- box-sizing: border-box; +- float: left; +- list-style: none; +- margin: 0; +- padding: 16px 16px 16px 10px; +- width: 50%; +- } +- ol.class-list .lessons li { +- margin: 0 0 6px; +- line-height: 16px; +- } +- +- /* Class colors */ +- ol.class-list li:nth-child(10n+1) .title { +- background: #00bcd4; +- } +- ol.class-list li:nth-child(10n+2) .title { +- background: #4db6ac; +- } +- ol.class-list li:nth-child(10n+3) .title { +- background: #66bb6a; +- } +- ol.class-list li:nth-child(10n+4) .title { +- background: #7cb342; +- } +- ol.class-list li:nth-child(10n+5) .title { +- background: #afb42b; +- } +- ol.class-list li:nth-child(10n+6) .title { +- background: #ffb300; +- } +- ol.class-list li:nth-child(10n+7) .title { +- background: #ff7043; +- } +- ol.class-list li:nth-child(10n+8) .title { +- background: #ec407a; +- } +- ol.class-list li:nth-child(10n+9) .title { +- background: #ab47bc; +- } +- ol.class-list li:nth-child(10n+10) .title { +- background: #7e57c2; +- } +- +- @media (max-width: 719px) { +- ol.class-list ol, +- ol.class-list .description { +- float: none; +- margin: 16px; +- padding: 0; +- width: auto; +- } +- } +- +- +- .hide { +- display:none !important; +- } +- +- +- +- /* inner-doc tabs w/ title */ +- +-div#title-tabs-wrapper { +- border-bottom:1px solid #ccc; +- margin:20px 0 30px; +-} +-h1.with-title-tabs { +- display:inline-block; +- margin-bottom: -1px; +- padding:0 60px 0 0; +- border-bottom:1px solid #F9F9F9; +-} +-ul#title-tabs { +- list-style:none; +- padding:0; +- height:29px; +- margin:0; +- font-size:16px; +- line-height:26px; +- display:inline-block; +- vertical-align:bottom; +-} +-ul#title-tabs li { +- display:block; +- float:left; +- margin-right:40px; +- border-bottom: 3px solid transparent; +-} +-ul#title-tabs li.selected { +- border-bottom: 3px solid #93C; +-} +-ul#title-tabs li a { +- color:#333; +-} +-ul#title-tabs li a:hover, +-ul#title-tabs li a:active { +- color:#039BE5 !important; +-} +- +- +- +-/* content body */ +-@-webkit-keyframes glowheader { +- from { +- background-color: #33b5e5; +- color: #000; +- border-bottom-color: #000; } +- +- to { +- background-color: transparent; +- color: #33b5e5; +- border-bottom-color: #33b5e5; } } +- +-@-moz-keyframes glowheader { +- from { +- background-color: #33b5e5; +- color: #000; +- border-bottom-color: #000; } +- +- to { +- background-color: transparent; +- color: #33b5e5; +- border-bottom-color: #33b5e5; } } +- +-@keyframes glowheader { +- from { +- background-color: #33b5e5; +- color: #000; +- border-bottom-color: #000; } +- +- to { +- background-color: transparent; +- color: #33b5e5; +- border-bottom-color: #33b5e5; } } +- +-h1:target, +-h2:target, +-h3:target { +- -webkit-animation-name: glowheader; +- -moz-animation-name: glowheader; +- animation-name: glowheader; +- -webkit-animation-duration: 0.7s; +- -moz-animation-duration: 0.7s; +- animation-duration: 0.7s; +- -webkit-animation-timing-function: ease-out; +- -moz-animation-timing-function: ease-out; +- animation-timing-function: ease-out; } +- +-.design ol h4 { +- padding-bottom:0; +-} +-.design ol { +- counter-reset: item; } +- .design ol>li { +- font-size: 14px; +- line-height: 20px; +- list-style-type: none; +- position: relative; } +- .design ol>li:before { +- content: counter(item) ". "; +- counter-increment: item; +- position: absolute; +- left: -20px; +- top: 0; } +- .design ol li.value-1:before { +- content: "1. "; } +- .design ol li.value-2:before { +- content: "2. "; } +- .design ol li.value-3:before { +- content: "3. "; } +- .design ol li.value-4:before { +- content: "4. "; } +- .design ol li.value-5:before { +- content: "5. "; } +- .design ol li.value-6:before { +- content: "6. "; } +- .design ol li.value-7:before { +- content: "7. "; } +- .design ol li.value-8:before { +- content: "8. "; } +- .design ol li.value-9:before { +- content: "9. "; } +- .design ol li.value-10:before { +- content: "10. "; } +-.design .with-callouts ol>li { +- list-style-position: inside; +- margin-left: 0; } +- .design .with-callouts ol>li:before { +- display: inline; +- left: -20px; +- float: left; +- width: 17px; +- color: #33b5e5; +- font-weight: 500; } +-.design .with-callouts ul>li { +- list-style-position: outside; } +- +-/* special list items */ +-li.no-bullet { +- list-style-type: none !important; } +-li.no-bullet *{ +- margin:0; } +- +-.design li.with-icon { +- position: relative; +- margin-left: 20px; +- min-height: 30px; } +- .design li.with-icon p { +- margin-left: 0 !important; } +- .design li.with-icon:before { +- position: absolute; +- left: -40px; +- top: 0; +- content: ''; +- width: 30px; +- height: 30px; } +- .design li.with-icon.tablet:before { +- background-image: url(../images/styles/ico_phone_tablet.png); } +- .design li.with-icon.web:before { +- background-image: url(../images/styles/ico_web.png); } +- .design li.with-icon.action:before { +- background-image: url(../images/styles/ico_action.png); } +- .design li.with-icon.use:before { +- background-image: url(../images/styles/ico_use.png); } +- +-/* video containers */ +-.framed-galaxynexus-land-span-13 { +- background: transparent url(../images/styles/device_galaxynexus_blank_land_span13.png) no-repeat +-scroll top left; +- padding: 42px 122px 62px 126px; +- overflow: hidden; } +- .framed-galaxynexus-land-span-13, .framed-galaxynexus-land-span-13 video, +-.framed-galaxynexus-land-span-13 img { +- width: 512px; +- height: 286px; } +- +- +-.framed-galaxynexus-land-span-8{ +- background: transparent url(../images/styles/device_galaxynexus_blank_land_span8.png) no-repeat +-scroll top left; +- padding: 26px 68px 38px 72px; +- overflow: hidden; } +- .framed-galaxynexus-land-span-8, .framed-galaxynexus-land-span-8 video, +-.framed-galaxynexus-land-span-8 img { +- width: 320px; +- height: 180px; } +- +-.framed-galaxynexus-port-span-9 { +- background: transparent url(../images/styles/device_galaxynexus_blank_port_span9.png) no-repeat +-scroll top left; +- padding: 95px 122px 107px 124px; +- overflow: hidden; } +- .framed-galaxynexus-port-span-9, .framed-galaxynexus-port-span-9 video, +-.framed-galaxynexus-port-span-9 img { +- width: 274px; +- height: 488px; } +- +-.framed-galaxynexus-port-span-5 { +- background: transparent url(../images/styles/device_galaxynexus_blank_port_span5.png) no-repeat +-scroll top left; +- padding: 75px 31px 76px 33px; +- overflow: hidden; } +- .framed-galaxynexus-port-span-5, .framed-galaxynexus-port-span-5 video, +-.framed-galaxynexus-port-span-5 img { +- width: 216px; +- height: 384px; } +- +-.framed-nexus4-port-216 { +- background: transparent url(../images/styles/device_nexus4_blank_port_432.png) no-repeat +-scroll top left; +- background-size:240px 465px; +- padding: 52px 12px 52px 12px; +- overflow: hidden; } +- .framed-nexus4-port-216, .framed-nexus4-port-216 video, +- .framed-nexus4-port-216 img { +- width: 216px; +- height: 360px; } +- +-.framed-nexus5-port-span-5 { +- background: transparent url(../images/styles/device_nexus5_blank_port_span5.png) no-repeat +- scroll top left; +- padding: 52px 33px 69px 31px; +- overflow: hidden; +-} +- +-.framed-nexus5-port-span-5, +-.framed-nexus5-port-span-5 video, +-.framed-nexus5-port-span-5 img { +- width: 216px; +- height: 384px; +-} +- +-.framed-nexus5-land-span-13 { +- background: transparent url(../images/styles/device_nexus5_blank_land_span13.png) no-repeat scroll top left; +- padding: 36px 119px 54px 108px; +- overflow: hidden; +-} +- +-.framed-nexus5-land-span-13, +-.framed-nexus5-land-span-13 video, +-.framed-nexus5-land-span-13 img { +- width: 533px; +- height: 300px; +-} +- +-.framed-nexus5-port-span-5, +-.framed-nexus5-port-span-5 video, +-.framed-nexus5-port-span-5 img { +- width: 216px; +- height: 384px; +-} +- +-/* wear device frames */ +- +-.framed-wear-square { +- background: transparent url(../images/styles/device_wear_square.png) no-repeat scroll top left; +- background-size: 302px 302px; +- height:222px; +- width:222px; +- padding:40px; +- overflow:hidden; +-} +- +-.framed-wear-square-small { +- background: transparent url(../images/styles/device_wear_square_small.png) no-repeat scroll top left; +- background-size: 169px 200px; +- height:147px; +- width:147px; +- padding:27px 11px; +- overflow:hidden; +-} +- +-#api-info-block { +- color: #999; +- float: right; +- font-size: 12px; +- font-weight: normal; +- line-height: 14px; +- margin: 20px 0 0; +- max-width: 80%; +- padding: 0 10px 6px; +- text-align: right; +-} +- +-#api-info-block a, +-#api-info-block a:active, +-#api-info-block a:visited { +- color: #222; +-} +- +-#jd-header { +- font-size: 12px; +- margin: 20px 0 12px; +- padding: 0 0 12px; +-} +- +-#jd-header h1 { +- margin: 0; +- padding: 0 0 6px; +-} +- +-#jd-content +-.framed-wear-square img { +- height:222px; +- width: 222px; +- padding:0; +- margin:0; +-} +- +-#jd-content +-.framed-wear-square-small img { +- height:147px; +- width: 147px; +- padding:0; +- margin:0; +-} +- +- +- +- +- +- +-/* landing page disclosures */ +-.landing-page-link { +- text-decoration: none; +- font-weight: 500; +- color: #333333; } +- .landing-page-link:after { +- content: ''; +- background: transparent url(../images/styles/disclosure_right.png) no-repeat scroll 50% 50%; +- width: 10px; +- height: 10px; +- display: inline-block; +- margin-left: 5px; } +- +-/* tooltips */ +-.tooltip-box { +- position: absolute; +- background-color: rgba(0, 0, 0, 0.9); +- border-radius: 2px; +- font-size: 14px; +- line-height: 20px; +- color: #fff; +- padding: 6px 10px; +- max-width: 250px; +- z-index: 10000; } +- .tooltip-box.below:after { +- position: absolute; +- content: ''; +- line-height: 0; +- display: block; +- top: -10px; +- left: 5px; +- border: 5px solid transparent; +- border-bottom-color: rgba(0, 0, 0, 0.9); } +- +-/* video note */ +-.video-instructions { +- margin-top: 10px; +- margin-bottom: 10px; } +- .video-instructions:before { +- content: ''; +- background: transparent url(../images/styles/ico_movie_inline.png) no-repeat scroll top left; +- display: inline-block; +- width: 12px; +- height: 12px; +- margin-right: 8px; } +- .video-instructions:after { +- content: 'Click device screen to replay movie.'; } +- +-/* download buttons */ +-.download-button { +- display: block; +- margin-bottom: 5px; +- text-decoration: none; +- background-color: #33b5e5; +- color: #fff !important; +- font-weight: 500; +- box-shadow: 0 1px 1px rgba(0, 0, 0, 0.12); +- padding: 6px 12px; +- border-radius: 2px; } +- .download-button:hover, .download-button:focus { +- background-color: #0099cc; +- color: #fff !important; } +- .download-button:active { +- background-color: #006699; } +- +-/* UI tables and other things found in Writing style and Settings pattern */ +-.ui-table { +- width: 100%; +- background-color: #282828; +- color: #fff; +- border-radius: 2px; +- box-shadow: 0 2px 4px rgba(0, 0, 0, 0.25); +- border-collapse: separate; } +- .ui-table th, +- .ui-table td { +- padding: 5px 10px; +- background-color: inherit; +- border:0;} +- .ui-table thead th { +- font-weight: bold; } +- .ui-table tfoot td { +- border-top: 1px solid #494949; +- border-right: 1px solid #494949; +- text-align: center; } +- .ui-table tfoot td:last-child { +- border-right: 0; } +- +-.layout-with-list-item-margins { +- margin-left: 30px !important; } +- +-.emulate-content-left-padding { +- margin-left: 10px; } +- +-.do-dont-label { +- margin-bottom: 10px; +- padding-left: 20px; +- background: transparent none no-repeat scroll 0px 3px; } +- .do-dont-label.bad { +- background-image: url(../images/styles/ico_wrong.png); } +- .do-dont-label.good { +- background-image: url(../images/styles/ico_good.png); } +- +- +- +- +-/* -------------------------------------------------------------------------- +-Footer +-*/ +-.line { +- clear: both; +- background: #acbc00; +- background: -moz-linear-gradient(top, #acbc00 0, #acbc00 50%, #bdde00 50%, #bdde00 100%); +- background: -webkit-gradient(linear, left top, left bottom, color-stop(0, #acbc00), +-color-stop(50%, #acbc00), color-stop(50%, #bdde00), color-stop(100%, #bdde00)); +- background: -webkit-linear-gradient(top, #acbc00 0, #acbc00 50%, #bdde00 50%, #bdde00 100%); +- background: -o-linear-gradient(top, #acbc00 0, #acbc00 50%, #bdde00 50%, #bdde00 100%); +- background: -ms-linear-gradient(top, #acbc00 0, #acbc00 50%, #bdde00 50%, #bdde00 100%); +- background: linear-gradient(top, #acbc00 0, #acbc00 50%, #bdde00 50%, #bdde00 100%); +- height: 2px; +- margin-top: 150px; +- position: relative; +- z-index: 11; +-} +-#footer { +- font-size:11px; +- clear: both; +- color: #999; +- padding: 15px 0; +- margin-top:10px; +- width:auto; +-} +-#footer-local ul { +- list-style: none; +- margin: 5px 0 30px 0; +-} +-#footer-local li { +- display: inline; +-} +-#footer-local li+li:before { +- content: '|'; +- padding: 0 3px; +- color: #e5e5e5; +-} +-#footer-global { +- padding: 10px 15px; +- background: #f5f5f5; +-} +-#footer-global { +- border-top: 1px solid #ebebeb; +- font-size: 11.5px; +- line-height: 1.8; +- list-style: none; +-} +-#footer-global ul { +- margin: 0; +-} +-#footer-global li { +- display: inline; +- font-weight: bold; +-} +-#footer-global li+li:before { +- content: '¬?'; +- padding: 0 3px; +-} +-* html #footer-global li { +- margin: 0 13px 0 0; +-} +-* [dir='rtl'] #footer-global li { +- margin: 0 0 0 13px; +-} +-*+html #footer-global li { +- margin: 0 13px 0 0; +-} +-*+[dir='rtl'] #footer-global li { +- margin: 0 0 0 13px; +-} +-#footer-global li a { +- font-weight: normal; +-} +-.locales { +- margin: 10px 0 0 0px; +-} +-[dir='rtl'] .locales { +- background-position: right center; +- float: left; +- padding: 0 24px 0 0; +-} +-.locales form { +- margin: 0; +-} +- +-.locales select, +-.locales option { +- text-transform: capitalize; +-} +- +-.locales select, .sites select { +- line-height: 3.08; +- margin: 0px 0; +- border: solid 1px #EBEBEB; +- -webkit-appearance: none; +- background: white url('../images/arrows-up-down.png') right center no-repeat; +- height: 30px; +- color: #222; +- line-height: normal; +- padding: 5px; +- width: 230px; +-} +-} +- +-/* ============================================================================= +- Print Only +- ========================================================================== */ +-@media print { +- /* configure printed page */ +- @page { +- margin: 0.75in 1in; +- widows: 4; +- orphans: 4; +- } +- +- /* reset spacing metrics */ +- html, body, .wrap { +- margin: 0 !important; +- padding: 0 !important; +- width: auto !important; +- } +- +- /* leave enough space on the left for bullets */ +- body { +- padding-left: 20px !important; +- } +- #doc-col { +- margin-left: 0; +- } +- +- /* hide a bunch of non-content elements */ +- #header, #footer, #nav-x, #side-nav, +- .training-nav-top, .training-nav-bottom, +- #doc-col .content-footer, +- .nav-x, .nav-y, +- .paging-links { +- display: none !important; +- } +- +- /* remove extra space above page titles */ +- #doc-col .content-header { +- margin-top: 0; +- } +- +- /* bump up spacing above subheadings */ +- h2 { +- padding-top: 40px !important; +- } +- +- /* print link URLs where possible and give links default text color */ +- p a:after { +- content: " (" attr(href) ")"; +- font-size: 80%; +- } +- p a { +- word-wrap: break-word; +- } +- a { +- color: inherit; +- } +- +- /* syntax highlighting rules */ +- .str { color: #060; } +- .kwd { color: #006; font-weight: bold; } +- .com { color: #600; font-style: italic; } +- .typ { color: #404; font-weight: bold; } +- .lit { color: #044; } +- .pun { color: #440; } +- .pln { color: #000; } +- .tag { color: #006; font-weight: bold; } +- .atn { color: #404; } +- .atv { color: #060; } +-} +- +-/* ============================================================================= +- Layout +- ========================================================================== */ +-@media screen, projection, print { +- +-.training-nav-top { +- border:1px solid #e5e5e5; +- border-width: 1px 1px 0; +- bottom: -56px; +- box-sizing: border-box; +- position: absolute; +- right: 0; +- width: 280px; +-} +- +-.training-nav-bottom { +- float:right; +- margin:0 0 0 20px; +- padding:0 0 20px; +-} +- +-#tb-wrapper, +-#qv-wrapper { +- float:right; +- clear:right; +- margin:6px 0 0 30px; /* negative top-margin to counter the content-header bottom margin */ +- padding:0 0 30px; +-} +- +-#tb-wrapper { +- margin:56px 0 0 20px; /* negative top-margin to counter the content-header bottom margin */ +-} +- +-#tb, +-#qv { +- border: 1px solid #e5e5e5; +- box-sizing: border-box; +- float: right; +- line-height: 16px; +- padding: 5px 0; +- width: 240px; +-} +- +-#tb { +- width:280px; +-} +- +-#tb h2, +-#qv h2 { +- border-top: 1px solid #e5e5e5; +- color: inherit; +- font-size: 16px; +- line-height: 24px; +- margin: 15px 0 4px; +- padding: 10px 15px 0; +-} +- +-#tb h2:first-child, +-#qv h2:first-child { +- border-top: 0; +- padding-top: 0; +- margin-top: 10px; +-} +- +-#tb .download-box, +-#qv .download-box { +- padding:0 0 0 15px; +-} +- +-#tb .download-box .filename, +-#qv .download-box .filename { +- font-size:11px; +- margin:4px 4px 10px; +-} +- +-@media (max-width: 719px) { +- .training-nav-top { +- left: 0; +- width: auto; +- } +- +- #tb-wrapper { +- clear: none; +- float: none; +- margin-left: 0; +- } +- +- #tb { +- float: none; +- width: auto; +- } +- +- #qv-wrapper { +- display: none; +- } +-} +- +- +-/* Dev guide quicknav */ +- +-.sidebox-wrapper { +- float:right; +- clear:right; +- margin:0 0 0 20px; +- padding:0 0 20px; +-} +- +-.sidebox { +- width:226px; +- font-size:13px; +- line-height:18px; +- border-left:3px solid #96ca7c; +- border-left-color: rgba(106, 179, 68, .7); /* #6ab344 * 70% */ +- float:right; +- padding:0 0 0 20px; +- margin:0 0 1em 20px; +-} +- +-.sidebox h2, +-.sidebox h3, +-.sidebox h4, +-.sidebox h5 { +- font-weight:bold; +- padding: 0 0 10px; +- line-height: 16px; +-} +- +-.sidebox * { +- font-size:inherit; +-} +- +-.sidebox > *:last-child { +- margin-bottom:0; +-} +- +-#tb ol, +-#tb ul, +-#tb p, +-#qv ul { +- list-style-type: none; +- margin:0 15px 10px 15px; +-} +- +-#tb li, +-#qv li { +- margin: 8px 0; +- padding: 0 0 0 16px; +- position: relative; +-} +- +-#qv ol { +- list-style:none; +- margin:0 15px 15px; +- font-size:inherit; +- line-height:inherit; +-} +- +-#tb ol ol, +-#tb ul ul, +-#qv ol ol, +-#qv ul ul, +-.sidebox ol ol, +-.sidebox ul ul { +- margin: 8px 0; +-} +- +-.sidebox p, +-#qv p { +- margin: 0 0 10px; +-} +- +-/* related resources blocks in checklists */ +- +-/* related resources sections that have dynamic content */ +- +- +- +-h3.rel-resources { +- padding:1.25em auto; +-} +- +-/* -------------------------------------------------------------------------- +-Form +-*/ +-.article form { +- margin: 0 0 20px; +-} +-.article form .form-required { +- color: #dd4b39; +-} +-.article form fieldset { +- margin: 0 0 20px; +- padding: 0; +-} +-.article form legend { +- display: block; +- line-height: 1.5; +- margin: 0; +- padding: 0; +-} +-/* +-.article form ol, .article form ul { +- margin: 0 0 0 1em; +- padding: 0 0 0 1em; +-} +-[dir='rtl'] .article form ol, [dir='rtl'] .article form ul { +- margin: 0 1em 0 0; +- padding: 0 1em 0 0; +-} +-.article form ol ul, .article form ul ul, [dir='rtl'] .article form ol ul, [dir='rtl'] .article form +-ul ul { +- list-style: none; +- margin: 0; +- padding: 0; +-} +-.article form li { +- margin: 0 0 20px; +-} +-.article form li li { +- margin: 0 0 5px; +-} +-*/ +-.article form label { +- display: block; +- margin: 0 0 5px; +- padding: 0; +-} +-.article form input[type='text'], .article form select, .article form textarea, .article form +-.checkbox-group, .article form .radio-group { +- margin-bottom: 15px; +-} +-.checkbox-group input { +- width: 13px; +- height: 13px; +- background: #fff; +- border: solid 1px #c6c6c6; +- float: left; +-} +-.article form .checkbox-group, .article form .radio-group { +- display: block +-} +-.article form select { +- border: solid 1px #ebebeb; +- border-top-color: #ddd; +- -webkit-appearance: none; +- background: #f3f3f3 url(../images/arrows-up-down.png) right center no-repeat; +- height: 30px; +- color: #222; +- line-height: normal; +- padding: 5px; +- width: 130px; +-} +- +-.article form .browse .browse-msg { +- font-size: 11.5px; +-} +-.article form .browse .button-secondary { +- height: auto; +- line-height: 25px; +- font-size: 11px; +- padding: 0 8px; +- margin: 0 10px 15px 0; +-} +-.article form input[type='text'], .article form textarea { +- border: 1px solid #ebebeb; +- border-top-color: #dcdcdc; +- color: #222; +- line-height: normal; +- padding: 6px 10px; +- width: 300px; +-} +-.article form textarea { +- height: 150px; +-} +-.article form input[type='text']:focus, .article form textarea:focus { +- border-color: #33B5E5; +- -moz-box-shadow: inset 0 1px 2px rgba(0, 0, 0, .2); +- -o-box-shadow: inset 0 1px 2px rgba(0, 0, 0, .2); +- -webkit-box-shadow: inset 0 1px 2px rgba(0, 0, 0, .2); +- box-shadow: inset 0 1px 2px rgba(0, 0, 0, .2); +- outline: 0; +-} +-.article form input[disabled], .article form textarea[disabled], .article form label.form-disabled { +- color: #999; +-} +-.article form input[type='text'][disabled], .article form textarea[disabled] { +- background-color: #ebebeb; +-} +-form .form-error input[type='text'], form .form-error textarea { +- border-color: #dd4b39; +- margin-right: 20px; +-} +-.aside { +- -moz-border-radius: 2px; +- -webkit-border-radius: 2px; +- border-radius: 2px; +- margin: 10px 0; +- padding: 20px; +- position: relative; +- background: #f9f9f9; +-} +-/* +-.aside, .notification, .promo { +- -moz-border-radius: 2px; +- -webkit-border-radius: 2px; +- border-radius: 2px; +- margin: 10px 0; +- padding: 10px; +- position: relative; +-} +-.aside>:first-child, .notification>:first-child, .promo>:first-child { +- margin-top: 0; +-} +-.aside>:last-child, .notification>:last-child, .promo>:last-child { +- margin-bottom: 0; +-} +-.aside { +- background: #f9f9f9; +-} +-.notification { +- background: #fffbe4; +- border-color: #f8f6e6; +-} +-.promo { +- background: #f6f9ff; +- border-color: #eff2f9; +-} +-*/ +- +-/* SDK TOS styles */ +- +-div.sdk-terms { +- white-space: pre-wrap; +- word-wrap: break-word; +- font-family: inherit; +- font-size: inherit; +- padding: 10px; +- height: 370px; +- width: 738px; +- border: 1px solid #444; +- background: transparent; +- overflow:auto; +- margin:0 0 10px; +-} +- +-div.sdk-terms.fullsize { +- padding: 0; +- height: auto; +- width: auto; +- border:none; +-} +- +-div.sdk-terms h3, +-div.sdk-terms h2 { +- padding: 0; +-} +- +-div#sdk-terms-form { +- padding:0 0 0 10px; +-} +- +-div#sdk-terms-form input { +- display:inline; +- margin:4px 4px 4px 0; +-} +- +- +-/* -------------------------------------------------------------------------- +-Code Style +-*/ +-pre { +- margin:0 0 1em 0; +- padding: 1em; +- overflow: auto; +- border: solid 1px #ddd; +- background: #f7f7f7; +-} +- +-p.package-name { +- margin:1em 0; +-} +- +-h1.api-title { +- padding-bottom:0; +-} +- +-h2.api-section { +- margin: 60px 0 0; +-} +- +-h2.api-section+hr { +- margin-bottom: 30px; +-} +- +-h3.api-name { +- margin: 80px 0 12px; +- padding: 0; +-} +- +-/* remove top padding when this h3 (visibly) follows an h2. +- This accounts for the variation in structure, +- including the collapsed mobile headings */ +-h2+hr+div>div>a+div>h3.api-name, +-h2+hr+a+div>h3.api-name, +-h2+hr+a+h3.api-name { +- margin-top: 0; +-} +- +-pre.api-signature, +-code.api-signature { +- color:inherit; +- padding:0; +- margin:1em 0; +- border:0; +- background:transparent; +-} +- +-.str { color: #800; } /* Code string */ +-.kwd { color: #008; } +-.typ { color: #606; } +-.lit { color: #066; } +-.pun { color: #660; } +-.pln { color: #000; } +-.tag { color: #008; } +-.atn { color: #828; } +-.atv { color: #800; } /* XML string */ +-.dec { color: #606; } +- +-/* -------------------------------------------------------------------------- +-Three-Pane +-*/ +-/* Package Nav & Classes Nav */ +-.three-pane { +- position: relative; +- border-top: solid 1px #ebebeb; +-} +-#packages-nav .js-pane, +-#classes-nav .js-pane { +- overflow:visible; +-} +-#packages-nav { +- height:270px; +- max-height: inherit; +- overflow: hidden; +- position: relative; +-} +-#classes-nav { +- overflow: hidden; +- position: relative; +-} +-#packages-nav ul, #classes-nav ul { +- list-style-type: none; +- margin: 10px 0 20px 0; +- padding: 0; +-} +-#classes-nav li { +- font-weight: bold; +- margin: 5px 0; +-} +-#packages-nav li, +-#classes-nav li li { +- margin: 0; +-} +-#packages-nav li a, #packages-nav li a:active, #packages-nav li a:visited, +-#classes-nav li a, #classes-nav li a:active, #classes-nav li a:visited { +- padding: 0 0 0 4px; +-} +-#packages-nav li a, #packages-nav li a:active, #packages-nav li a:visited, +-#classes-nav li li a, #classes-nav li li a:active, #classes-nav li li a:visited { +- color: #222; +- font-weight: normal; +-} +-#packages-nav li a, #packages-nav li a:active, #packages-nav li a:visited, +-#classes-nav li li a, #classes-nav li li a:active, #classes-nav li li a:visited { +- display: block; +-} +-#packages-nav li.selected a, #packages-nav li.selected a:active, #packages-nav li.selected +-a:visited, +-#classes-nav li li.selected a, #classes-nav li li.selected a:active, #classes-nav li li.selected +-a:visited { +- font-weight: 500; +- color: #0099cc; +- background-color:#fff; } +- #packages-nav li.selected ul li a, +- #classes-nav li.selected ul li a { +- /* don't highlight child items */ +- color: #555555; } +- +-#nav-swap { +- height:30px; +- border-top:1px solid #ccc; +-} +-#nav-swap a { +- display:inline-block; +- height:100%; +- color: #222; +- font-size: 12px; +- padding: 5px 0 5px 5px; +-} +- +-#nav-swap .fullscreen { +- float: right; +- width: 24px; +- height: 24px; +- text-indent: -1000em; +- padding:0; +- margin:3px 5px 0; +- background: url(../images/fullscreen.png) no-repeat -24px 0; +-} +-#nav-swap .fullscreen.disabled { +- background-position: 0 0; +-} +-#nav-swap .fullscreen:hover, +-#nav-swap .fullscreen:focus { +- cursor:pointer; +-} +- +-/* Content */ +-#doc-col { +- margin-right:0; +-} +- +-/* Uncomment this for preview release watermark +-#doc-col { +- background: url('../images/preview.png') repeat; +-} +-*/ +- +-#doc-content-container { +- margin-left: 291px +-} +- +-#doc-header, #doc-content { +- padding: 0; +-} +- +-#doc-header { +- background: #f7f7f7; +-} +- +-#doc-header h1 { +- line-height: 0; +- padding-bottom: 15px; +-} +- +- +-#api-info-block { +- float: right; +- font-weight: bold; +-} +- +-#api-info-block a, #api-info-block a:active, #api-info-block a:visited { +- color: #222; +-} +- +-#api-info-block a:hover, #api-info-block a:focus { +- color: #33B5E5; +-} +- +-#api-nav-header { +- height:19px; /* plus 16px padding = 35; same as #nav li */ +- font-size:14px; +- padding: 8px 0; +- margin: 0; +- border-bottom: 1px solid #CCC; +- background:#e9e9e9; +- background: rgba(0, 0, 0, 0.05); /* matches #nav li.expanded */ +- line-height: 19px; /* Fix regression after page line-height is bumped to 24px */ +-} +- +-#api-nav-title { +- padding:0 5px; +- white-space:nowrap; +-} +- +-#api-level-toggle { +- float:right; +- padding:0 5px; +-} +- +-#api-level-toggle label { +- margin:0; +- vertical-align:top; +- line-height: 19px; +- font-size:13px; +- height: 19px; +-} +- +-#api-level-toggle .select-wrapper { +- width: 35px; +- display: inline-block; +- overflow: hidden; +-} +- +-#api-level-toggle select { +- border: 0; +- appearance:none; +- -moz-appearance:none; +- -webkit-appearance: none; +- background: transparent url(../images/arrows-up-down.png) 23px 5px no-repeat; +- color: #222; +- /* remove the lines below after xp testing +- height: 19px; +- line-height: 19px; */ +- padding: 0; +- margin: .5px 0 0 0; +- width:150%; +- font-size:13px; +- vertical-align:top; +- outline:0; +-} +- +- +-/* Toggle for revision notes and stuff */ +-div.toggle-content.closed .toggle-content-toggleme { +- display:none; +-} +- +-#jd-content img.toggle-content-img { +- margin:0 5px 5px 0; +-} +- +-div.toggle-content-toggleme { +- padding:0 0 0 15px; +-} +- +- +-/* API LEVEL FILTERED MEMBERS */ +- +-.absent, +-.absent a:link, +-.absent a:visited, +-.absent a:hover, +-.absent * { +- color:#bbb !important; +- cursor:default !important; +- text-decoration:none !important; +-} +-#devdoc-nav li.absent.selected, +-#devdoc-nav li.absent.selected *, +-#devdoc-nav div.label.absent.selected, +-#devdoc-nav div.label.absent.selected * { +- background-color:#eaeaea !important; +-} +-.absent h4.jd-details-title, +-.absent h4.jd-details-title * { +- background-color:#f6f6f6 !important; +-} +-.absent img { +- opacity: .3; +- filter: alpha(opacity=30); +- -ms-filter:"progid:DXImageTransform.Microsoft.Alpha(Opacity=30)"; +-} +- +- +- +- +- +- +- +- +- +-/* JQUERY RESIZABLE STYLES */ +-.ui-resizable { position: relative; } +-.ui-resizable-handle { position: absolute; display: none; font-size: 0.1px; z-index:1; } +-.ui-resizable .ui-resizable-handle { display: block; border-bottom: 1px solid #e4e4e4; } +-/*body .ui-resizable-disabled .ui-resizable-handle { display: none; } +-body .ui-resizable-autohide .ui-resizable-handle { display: none; }*/ +-.ui-resizable-s { cursor: s-resize; height: 10px; width: 100% !important; bottom: -11px; left: 0; +-border-bottom: solid 1px #ededed; +- background: #f7f7f7 url("../images/resizable-s2.png") no-repeat scroll center center; } +-/* +-.ui-resizable-e { +-cursor: e-resize; width: 10px; right: 0; top: 0; height: 100%; border-right: solid +-1px #ededed;background: #f7f7f7 url("../images/resizable-e2.png") no-repeat scroll center center; } +-*/ +- +-/* -------------------------------------------------------------------------- +-Lightbox +-*/ +-.lightbox { +- width: 769px; +- padding: 1.5em; +- margin: 0 auto; +- border: solid 1px #dcdcdc; +- background: #fff; +- -moz-box-shadow: 1px 1px 5px rgba(0,0,0,0.1); +- -webkit-box-shadow: 1px 1px 5px rgba(0,0,0,0.1); +- box-shadow: 1px 1px 5px rgba(0,0,0,0.1) +-} +-.lightbox .header { +- float: left; +- width: 720px; +- margin: -10px 20px 10px 0; +-} +-.lightbox .close { +- float: right; +- width: 10px; +- height: 10px; +- margin: -10px -10px 10px 0; +- text-indent: -1000em; +- background: url(../images/close.png) no-repeat 0 0; +-} +-.lightbox .close:hover, .lightbox .close:focus { +- background-position: -10px 0; +-} +- +-/* -------------------------------------------------------------------------- +-Styles for samples browser +-*/ +- +-#codesample-wrapper { +- width:100000px; /* super wide to contain floats, but doesn't cause scroll */ +- overflow:visible; +-} +-pre#codesample-block { +- float:left; +- overflow:visible; +- background:transparent; +- border:none; +-} +-pre#codesample-block a.number { +- display:none; +-} +-pre#codesample-block .code-line:hover { +- background:#e7e7e7; +-} +-pre#codesample-line-numbers { +- float:left; +- width:2em; +- background:transparent; +- border:none; +- border-right:1px solid #ccc; +- padding-left:0; +- font-family:monospace; +- text-align:right; +- -webkit-touch-callout: none; +- -webkit-user-select: none; +- -khtml-user-select: none; +- -moz-user-select: -moz-none; +- -ms-user-select: none; +- user-select: none; +-} +-pre#codesample-line-numbers a { +- color:#999; +-} +-pre#codesample-line-numbers.hidden { +- display:none; +-} +-pre#codesample-block span.code-line { +- width:100%; +- display:inline-block; +-} +- +-/* +-Styles for displaying image or video resources in samples browser. +-Resources are marked as no-display if they exceed the size limit. +-*/ +-div#codesample-resource img, div#codesample-resource video { +- border: 1px solid #ececec; +-} +- +-div#codesample-resource.noDisplay div { +- border: 1px solid #ececec; +- width:120px; +- margin-bottom:4px; +- padding:20px; +-} +- +-div#codesample-resource .noDisplay-message:after { +- font-style:italic; +- font-size:12px; +- content: 'This resource is not available for browsing. To view it, please download the project.'; +-} +- +-/* +-Styles for project structure (treeview) page +-*/ +-.structure-dir { +-background-image:url(../images/folder.png); +-background-repeat:no-repeat; +-background-position:16px 2px; +- margin:.25em 0 0 0; +- padding:0 0 0 0; +-} +- +-.structure-toggleme { +- margin:0 0 0 3em; +- padding:0 0 0 0; +- text-decoration:none; +-} +- +-.structure-java{ +-background-image:url(../images/file-java.png); +-background-repeat:no-repeat; +-background-position:0px 2px; +- margin:.3em 0 0 0; +- padding:.3em 0 .3em 22px; +-} +- +-.structure-file { +-background-image:url(../images/file-generic.png); +-background-repeat:no-repeat; +-background-position:0px 2px; +- margin:.3em 0 0 0; +- padding:.3em 0 .3em 22px; +-} +- +-.structure-xml { +-background-image:url(../images/file-xml.png); +-background-repeat:no-repeat; +-background-position:0px 2px; +- margin:.3em 0 0 0; +- padding:.3em 0 .25em 22px; +-} +- +-.structure-img { +-background-image:url(../images/file-image.png); +-background-repeat:no-repeat; +-background-position:0px 2px; +- margin:.3em 0 0 0; +- padding:.3em 0 .25em 22px; +-} +- +-.structure-manifest { +-background-image:url(../images/file-manifest.png); +-background-repeat:no-repeat; +- margin:.0 0 0 1.25em; +- padding:0 0 0 22px; +- text-decoration:none; +-} +- +-#jd-content .structure-toggle-img { +- margin:.5em 0 0 0; +-padding-right:2.1em; +-} +- +-.dirInfo { +- margin-left:2em; +-} +- +-.structure-dir a { +- text-decoration:none; +-} +- +-.structure-manifest a { +- text-decoration: none; +-} +-.structure-file a { +- text-decoration: none; +-} +- +-.sampleEmbed { +- background-color:rgb(249, 249, 249); +-} +- +-.sampleEmbed ol.lineNumbers { +- list-style-type: decimal; +- padding-left:1em; +-} +- +-.sampleEmbed ol.lineNumbers li { +-border-left:1px solid #ddd; +-border-right:1px solid #ddd; +-color:gray; +-background-color:#f7f7f7; +-margin:0 0 0 24px; +-padding: 2px 2px 2px 6px; +-} +- +-.sampleEmbed ol.lineNumbers li:hover { +-background: #efefef; +-} +- +-.samples-nav li a { +- overflow: hidden; +- text-overflow: ellipsis; +- white-space: nowrap; +-} +- +-/* -------------------------------------------------------------------------- +-Styles for raw formatted line numbers (not used with listformatted version) +-div.sampleLine div.lineNumber { +- display: inline; +-} +-div.sampleLine div.lineCode { +- display: inline; +- padding-left:6px; +-} +-div.sampleLine { +- padding:0; +- margin:0; +-}*/ +- +-/* -------------------------------------------------------------------------- +-Misc and article typography +-*/ +- +- +-.clearfix:before, .clearfix:after { +- content: ""; +- display: table +-} +-.clearfix:after { +- clear: both +-} +-.clearfix { +- *zoom: 1 +-} +-table.blank th, table.blank td { +- border: 0; +- background: none +-} +-.caption { +- margin: 0.5em 0 2em 0; +- color: #000; +- font-size: 11.5px; +-} +- +-.nolist, .nolist ul, .nolist ol { +- list-style:none; +- margin-left:0; +-} +- +-ol.callouts { +- counter-reset: item; +- list-style-type: none; +- margin-left:44px; +-} +-ol.callouts>li:before { +- counter-increment: item; +- content: counter(item); +- position: absolute; +- color:#fff; +- font-weight:bold; +- background-image:url(../images/styles/callout-bg_2x.png); +- background-size:24px; +- width:16px; +- padding-left:8px; +- margin-left:-34px; +-} +- +-#tb .nolist { +- margin-left:15px; +-} +- +-dl.xml>dt { +- text-transform:uppercase; +-} +-dl.xml dl.attr { +- margin-top:0; +-} +- +-pre.classic { +- background-color:transparent; +- border:none; +- padding:0; +-} +- +-p.img-caption { +- margin: -10px 0 20px; +- font-size: 13px; +-} +- +-/* figures and callouts */ +-.figure { +- position: relative; +-} +- +-.figure.pad-below { +- margin-bottom: 20px; +-} +- +-.figure .figure-callout { +- position: absolute; +- color: #fff; +- font-weight: 500; +- font-size: 16px; +- line-height: 23px; +- text-align: center; +- background: transparent url(../images/styles/callout.png) no-repeat scroll 50% 50%; +- padding-right: 2px; +- width: 30px; +- height: 29px; +- z-index: 1000; +-} +- +-.figure .figure-callout.top { +- top: -9px; +-} +- +-.figure .figure-callout.right { +- right: -5px; +-} +- +-.figure-caption { +- margin: 0 10px 20px 0; +- font-size: 14px; +- line-height: 20px; +- font-style: italic; +-} +- +-/* rows of figures */ +-.figure-row { +- font-size: 0; +- line-height: 0; +- /* to prevent space between figures */ +-} +- +-.figure-row .figure { +- display: inline-block; +- vertical-align: top; +-} +- +-.figure-row .figure + .figure { +- margin-left: 10px; +- /* reintroduce space between figures */ +-} +- +-.border-img { +- border: 1px solid #CCC; +-} +- +-.center-img { +- margin: auto; +- text-align: center; +-} +-.center-img img { +- margin-bottom: 15px; +-} +- +-.figure img, +-.figure-right img, +-.figure-left img, +-.figure-center img, +-.border-img { +- margin-bottom: 15px; +-} +- +-.figure-center { +- margin: 32px auto 24px; +- max-width: 100%; +-} +- +-.figure, +-.figure-right { +- clear: right; +- float: right; +- margin: 10px 0 0 0; +- padding: 0 0 0 20px; +- max-width: 50%; +- /* width must be defined w/ an inline style matching the image width */ +-} +- +-.figure-left { +- clear: left; +- float: left; +- margin: 10px 0 0 0; +- padding: 0 20px 0 0; +- max-width: 50%; +- /* width must be defined w/ an inline style matching the image width */ +-} +- +-@media (max-width: 719px) { +- /* Collapse on mobile. */ +- .figure, +- .figure-right, +- .figure-left { +- float: none; +- clear: none; +- padding: 0; +- margin: 32px auto 24px; +- max-width: 100%; +- } +-} +- +-img.frame { +- border:1px solid #DDD; +- padding:4px; +-} +- +-p.table-caption { +- margin: 0 0 4px 0; +- font-size:13px; +-} +- +-p.code-caption { +- margin-bottom: 4px; +- font: 12px/1.5 monospace; +-} +- +-p.note, div.note, +-p.caution, div.caution, +-p.warning, div.warning { +- padding: 0 0 0 20px; +- border-left: 3px solid; +- margin: 16px 0; +-} +- +-p.note, div.note { +- border-color: #4eb9ed; +- border-color: rgba(3, 155, 229, .7); /* #039be5 * 70% */ +-} +- +-p.caution, div.caution { +- border-color: #ffbc4c; +- border-color: rgba(255, 160, 0, .7); /* #ffa000 * 70% */ +-} +- +-p.warning, div.warning { +- border-color: #f48684; +- border-color: rgba(239, 83, 80, .7); /* #ef5350 * 70% */ +-} +- +-div.note.design { +- border-left: 4px solid #00bcd4; +-} +- +-div.note.develop { +- border-left: 4px solid #ff7043; +-} +- +-div.note.distribute { +- border-left: 4px solid #afb42b; +-} +- +-.note p, .caution p, .warning p { +- margin:0 0 5px; +-} +- +-.note p:last-child, .caution p:last-child, .warning p:last-child { +- margin-bottom:0; +-} +- +-.summary-table { +- background-color:#eceff1; +- padding:1em; +- margin-bottom:1.5em; +-} +- +-.summary-table h5 { +- line-height:1em; +- font-size:.98em; +-} +- +-body.about blockquote { +- display:block; +- float:right; +- width:280px; +- font-size:20px; +- font-style:italic; +- line-height:24px; +- color:#33B5E5; +- margin:0 0 20px 30px; +-} +- +-div.design-announce p { +- margin:0 0 10px; +-} +- +-.expandable { +- height:34px; +- padding-left:20px; +- position:relative; +-} +-.expandable:before { +- content: ''; +- background-image: url(../images/styles/disclosure_down.png); +- background-repeat:no-repeat; +- background-position: -12px -9px; +- width: 20px; +- height: 20px; +- display: inline-block; +- position: absolute; +- top: 0; +- left: 0; } +-} +-.expandable.expanded:before { +- background-image: url(../images/styles/disclosure_up.png); +-} +- +-/* notice box for cross links between Design/Develop docs */ +-a.notice-developers-video, +-a.notice-developers, +-a.notice-designers-video, +-a.notice-designers { +- float:right; +- clear:right; +- width:238px; +- min-height:50px; +- margin:0 0 20px 20px; +- border:1px solid #ddd; +-} +-a.notice-developers-video.wide, +-a.notice-developers.wide, +-a.notice-designers-video.wide, +-a.notice-designers.wide { +- width:278px; +-} +-a.notice-developers-video div, +-a.notice-developers div, +-a.notice-designers-video div, +-a.notice-designers div { +- min-height:40px; +- background:url('../images/styles/notice-developers_2x.png') no-repeat 10px 10px; +- background-size:40px 40px; +- padding:10px 10px 10px 60px; +-} +-a.notice-designers div { +- background:url('../images/styles/notice-designers_2x.png') no-repeat 10px 10px; +- background-size:40px 40px; +-} +-a.notice-designers-video div { +- background:url('../images/styles/notice-designers-video_2x.png') no-repeat 10px 10px; +- background-size:40px 40px; +-} +-a.notice-developers-video div { +- background:url('../images/styles/notice-developers-video_2x.png') no-repeat 10px 10px; +- background-size:40px 40px; +-} +-a.notice-developers-video:hover, +-a.notice-developers:hover, +-a.notice-designers-video:hover, +-a.notice-designers:hover { +- background:#eee; +-} +-a.notice-developers-video h3, +-a.notice-developers h3, +-a.notice-designers-video h3, +-a.notice-designers h3 { +- font-size:13px; +- line-height:18px; +- font-weight:bold; +- text-transform:uppercase; +- color:#000 !important; +- padding:0 0 1px; +-} +-a.notice-developers-video p, +-a.notice-developers p, +-a.notice-designers-video p, +-a.notice-designers p { +- margin:0; +- line-height:14px; +-} +-a.notice-developers-video.left, +-a.notice-developers.left, +-a.notice-designers-video.left, +-a.notice-designers.left { +- margin-left:0; +- float:left; +-} +- +- +-/* hide nested list items; companion to hideNestedLists() */ +-.hide-nested li ol, +-.hide-nested li ul { +- display:none; +-} +- +-a.header-toggle { +- display:block; +- float:right; +- text-transform:uppercase; +- font-size:.8em !important; +- font-weight:normal; +- margin-top:2px; +-} +- +- +-/* for IDE instruction toggle (Studio/Eclipse/Other) */ +-select.ide { +- background: transparent; +- border: 1px solid #bbb; +- border-left: 0; +- border-right: 0; +- margin: 10px 0; +- padding: 10px 0; +- color:#666; +-} +-select.ide, +-select.ide option { +- font-family: inherit; +- font-size:16px; +- font-weight:500; +-} +-/* hide all except studio by default */ +-.select-ide.eclipse, +-.select-ide.other { +- display:none; +-} +-/* ... unless studio also includes one of the others */ +-.select-ide.studio.eclipse, +-.select-ide.studio.other { +- display:none; +-} +- +- +-/* ----------------------------------------------- +-good/bad example containers +-*/ +- +-div.example-block { +- background-repeat: no-repeat; +- background-position:10px 8px; +- background-color:#ccc; +- padding:4px; +- margin:.8em auto 1.5em 2em; +- width:260px; +- float:right; +-} +-/* red container */ +-.example-block.bad { +- background-image: url(/images/example-bad.png); +- background-color:#f4cccc; +-} +-/* green container */ +-.example-block.good { +- background-image: url(/images/example-good.png); +- background-color:#d9ead3; +-} +-/* container heading div */ +-#jd-content .example-block .heading { +- font-weight:bold; +- margin:6px 0 9px 36px; +- padding:6px auto; +-} +-/* container image (if any) */ +-#jd-content .example-block img { +- margin:0; +- padding:0px; +-} +- +-.example-block table { +- margin:0; +-} +- +-/* ----------------------------------------------- +-Dialog box for popup messages +-*/ +- +-div.dialog { +- height:0; +- margin:0 auto; +-} +- +-div.dialog>div { +- z-index:99; +- position:fixed; +- margin:70px 0; +- width: 391px; +- height: 200px; +- background: #F7F7F7; +--moz-box-shadow: 0 0 15px rgba(0,0,0,0.5); +--webkit-box-shadow: 0 0 15px rgba(0,0,0,0.5); +-box-shadow: 0 0 15px rgba(0,0,0,0.5); +-} +-/* IE6 can't position fixed */ +-* html div.dialog div { position:absolute; } +- +- +-div#deprecatedSticker { +- display:none; +- z-index:99; +- position:fixed; +- right:15px; +- top:114px; +- margin:0; +- padding:1em; +- background:#FFF; +- border:1px solid #dddd00; +- box-shadow:-5px 5px 10px #ccc; +- -moz-box-shadow:-5px 5px 10px #ccc; +- -webkit-box-shadow:-5px 5px 10px #ccc; +-} +- +-div#langMessage, +-div#naMessage { +- display:none; +- width:555px; +- height:0; +- margin:0 auto; +-} +- +- +-div#langMessage>div, +-div#naMessage div { +- z-index:99; +- width:450px; +- position:fixed; +- margin:80px 0; +- padding:4em 4em 3em; +- background:#FFF; +- border:1px solid #999; +- box-shadow:-10px 10px 40px #888; +- -moz-box-shadow:-10px 10px 40px #888; +- -webkit-box-shadow:-10px 10px 40px #888; +-} +-/* IE6 can't position fixed */ +-* html div#langMessage>div, +-* html div#naMessage div { position:absolute; } +- +-div#naMessage strong { +- font-size:1.1em; +-} +- +-div#langMessage .lang { +- display:none; +-} +- +-/* -------------------------------------------------------------------------- +-Slideshow Controls & Next/Prev +-*/ +-.slideshow-next, .slideshow-prev { +- width: 20px; +- height: 36px; +- text-indent: -1000em; +-} +-.slideshow-container { +- margin: 2em 0; +-} +-.slideshow-container:before, .slideshow-container:after { +- content: ""; +- display: table; +- clear: both; +-} +-a.slideshow-next, a.slideshow-next:visited { +- +- float: right; +- +- background: url(../images/arrow-right.png) no-repeat 0 0 +- +-} +- +-a.slideshow-prev, a.slideshow-prev:visited { +- +- float: left; +- +- background: url(../images/arrow-left.png) no-repeat 0 0 +- +-} +- +-.slideshow-next:hover, .slideshow-prev:hover, .slideshow-next:focus, .slideshow-prev:focus { +- +- background-position: 0 -36px +- +-} +- +-.slideshow-next:active, .slideshow-prev:active { +- +- background-position: 0 -72px +- +-} +-.slideshow-nav { +- width: 74px; +- margin: 0 auto; +-} +-.slideshow-nav a, .slideshow-nav a:visited { +- display: inline-block; +- width: 12px; +- height: 12px; +- margin: 0 2px 20px 2px; +- background: #ccc; +- -webkit-border-radius: 50%; +- -moz-border-radius: 50%; +- border-radius: 50%; +-} +-.slideshow-nav a:hover, .slideshow-nav a:focus { +- +- background: #33B5E5 +-} +- +-.slideshow-nav a:active { +- +- background: #1e799a; +- background: #ebebeb; +- -webkit-box-shadow: inset 0px 0px 5px 2px rgba(0, 0, 0, .05); +- -moz-box-shadow: inset 0px 0px 5px 2px rgba(0, 0, 0, .05); +- box-shadow: inset 0px 0px 5px 2px rgba(0, 0, 0, .05); +-} +-.slideshow-nav a.active, .slideshow-nav a.active:active, .slideshow-nav a.active:visited { +- background: #33B5E5 +-} +-/* -------------------------------------------------------------------------- +-Tabs +-*/ +-ul.tabs { +- padding: 0; +- margin: 2em 0 0 0; +-} +-ul.tabs:before, ul.tabs:after { +- content: ""; +- display: table; +- clear: both; +-} +-ul.tabs li { +- list-style-type: none; +- float: left; +-} +-ul.tabs li a, ul.tabs li a:active, ul.tabs li a:visited { +- display: block; +- height: 36px; +- line-height: 36px; +- padding: 0 15px; +- margin-right: 2px; +- color: #222; +- -moz-border-radius-topleft: 2px; +- -moz-border-radius-topright: 2px; +- -moz-border-radius-bottomright: px; +- -moz-border-radius-bottomleft: px; +- -webkit-border-radius: 2px 2px px px; +- border-radius: 2px 2px px px; +- border-top: solid 1px #ebebeb; +- border-left: solid 1px #ebebeb; +- border-right: solid 1px #ebebeb; +- background-color: #fff; +- background-image: -webkit-gradient(linear, left top, left bottom, from(#ffffff), to(#fafafa)); +- background-image: -webkit-linear-gradient(top, #ffffff, #fafafa); +- background-image: -moz-linear-gradient(top, #ffffff, #fafafa); +- background-image: -ms-linear-gradient(top, #ffffff, #fafafa); +- background-image: -o-linear-gradient(top, #ffffff, #fafafa); +- background-image: linear-gradient(top, #ffffff, #fafafa); +- filter: progid:DXImageTransform.Microsoft.gradient(startColorStr='#ffffff', +-EndColorStr='#fafafa'); +-} +-ul.tabs li a:hover { +- color: #33B5E5; +-} +-ul.tabs li a.selected { +- height: 37px; +- color: #33B5E5; +- background-color: #f7f7f7; +- background-image: none; +- border-color: #ddd; +-} +-.tab-content { +- padding: 1.2em; +- margin: -1px 0 2em 0; +- -webkit-border-radius: 2px; +- -moz-border-radius: 2px; +- border-radius: 2px; +- border: solid 1px #ddd; +- background: #f7f7f7; +-} +-/* -------------------------------------------------------------------------- +-Feature Boxes +-*/ +-.feature-box { +- width: 291px; +- height: 200px; +- position: relative; +- background: #F7F7F7; +-} +-.box-border .top, .box-border .bottom, .box-border .left, .box-border .right { +- z-index: 100; +- position: absolute; +- background-color: #aaa; +-} +-.box-border .top, .box-border .bottom { +- width: 291px; +- height: 1px; +-} +-.dialog .box-border .top, +-.dialog .box-border .bottom { width:391px; } +- +-.box-border .left, .box-border .right { +- width: 1px; +- height: 8px; +-} +-.box-border .top { top: 0; left: 0 } +-.box-border .top .left { top: 1px; left: 0 } +-.box-border .top .right { top: 1px; right: 0 } +-.box-border .bottom .left { top: -8px; left: 0 } +-.box-border .bottom { top: 200px; left: 0 } +-.box-border .bottom .right { top: -8px; right: 0 } +- +-.feature-box h4, +-.dialog h4 { +- padding: 15px 18px 10px; +-} +- +-.feature-box p, +-.dialog p { +- margin: 10px 18px; +- padding:0; +-} +-.feature-box .link, +-.dialog .link { +- border-top: 1px solid #dedede; +- bottom: 0; +- position: absolute; +- width: inherit; +-} +-.feature-box a, .feature-box h4, +-.dialog a, .dialog h4 { +- -webkit-transition: color .4s ease; +- -moz-transition: color .4s ease; +- -o-transition: color .4s ease; +- transition: color .4s ease; +-} +-.feature-box:hover { +- cursor: pointer; +-} +-.feature-box:hover .box-border .top, .feature-box:hover .box-border .bottom, .feature-box:hover +-.left, .feature-box:hover .right { +- background-color: #33B5E5; +-} +-.feature-box:hover h4, .feature-box:hover a { +- color: #33B5E5; +-} +-/* -------------------------------------------------------------------------- +-Page-Specific Styles +-*/ +-.colors { +- position: relative; +- float: left; +- width: 92px; +- margin: 40px 0 20px; +-} +-.colors div { +- color: #fff; +- font-size: 11.5px; +- width: 82px; +- height: 82px; +- margin-top:-30px; +- line-height: 82px; +- text-align: center; +- border: solid 5px #fff; +- -webkit-border-radius: 50%; +- -moz-border-radius: 50%; +- border-radius: 50%; +-} +- +- +- +- +- +- +- +- +- +- +- +- +- +- +-/* ########### REFERENCE DOCS ################## */ +- +-#packages-nav h2, +-#classes-nav h2 { +- font-size:18px; +- margin:0; +- padding:0 0 0 4px; +-} +- +-/* not sure if this is needed in the ref docs, disabling for now +-.jd-descr h2 { +- margin:16px 0; +-} +-*/ +- +-/* First paragraph of a content pages is a bit larger +- - note the very specific selector. */ +-.jd-descr > p:first-child, +-.jd-descr > #tb-wrapper + p, +-.jd-descr > #qv-wrapper + p { +- font-size: 16px; +- margin-bottom: 16px; +-} +- +-/* page-top-right container for reference pages (holds +-links to summary tables) */ +-#api-info-block { +- font-size:12px; +- margin:20px 0 0; +- font-weight:normal; +- float:right; +- text-align:right; +- color:#999; +- max-width:300px; +- font-size: 12px; +- line-height:14px; +-} +- +-#api-info-block div.api-level { +- font-weight:bold; +- font-size:inherit; +- float:none; +- color:#222; +- padding:0; +- margin:0; +-} +- +-/* inheritance table */ +-table.inhtable>tbody>tr>td { +- padding-left:0; +-} +-table.inhtable>tbody>tr>td div:first-of-type { +- padding-left:12px; +-} +- +-.jd-inheritance-table { +- border-spacing:0; +- margin:1em 0; +- padding:0; +- background-color:transparent; +-} +-.jd-inheritance-table tr td { +- border: none; +- margin: 0; +- padding: 0; +- background-color:transparent; +-} +-.jd-inheritance-table .jd-inheritance-space { +- width:2em; +-} +-.jd-inheritance-table .jd-inheritance-interface-cell { +- padding-left: 17px; +-} +- +- +-/* the link inside a sumtable for "Show All/Hide All" */ +-.toggle-all { +- display:block; +- float:right; +- font-weight:normal; +- font-size:0.9em; +-} +- +-/* adjustments for in/direct subclasses tables */ +-.jd-sumtable-subclasses { +- margin: 1em 0 0 0; +- max-width:968px; +- background-color:transparent; +-} +- +-/* extra space between end of method name and open-paren */ +-.sympad { +- margin-right: 2px; +-} +- +-/* adjustments for the expando table-in-table */ +-.jd-sumtable-expando { +- margin:.5em 0; +- padding:0; +-} +- +-/* a div that holds a short description */ +-.jd-descrdiv { +- padding:3px 1em 0 1em; +- margin:0; +- border:0; +-} +- +-#jd-content img.jd-expando-trigger-img { +- padding:0 4px 4px 0; +- margin:0; +-} +- +-.jd-sumtable-subclasses div#subclasses-direct, +-.jd-sumtable-subclasses div#subclasses-indirect { +- /* left margin matches width of the toggle image, +- so this section aligns with the text above */ +- margin:0 0 0 34px; +-} +- +- +- +-/********* MEMBER REF *************/ +- +- +-.jd-details { +-/* border:1px solid #669999; +- padding:4px; */ +- margin:0 0 1em; +-} +- +-/* API reference: a container for the +-.tagdata blocks that make up the detailed +-description */ +-.jd-details-descr { +- padding:0; +- margin:.5em .25em; +-} +- +-/* API reference: a block containing +-a detailed description, a params table, +-seealso list, etc */ +-.jd-tagdata { +- margin:.5em 1em; +-} +- +-.jd-tagdata p { +- margin:0 0 1em 1em; +-} +- +-/* API reference: adjustments to +-the detailed description block */ +-.jd-tagdescr { +- margin:.25em 0 .75em 0; +-} +- +-.jd-tagdescr ol, +-.jd-tagdescr ul { +- margin:0 2.5em; +- padding:0; +-} +- +-.jd-tagdescr table, +-.jd-tagdescr img { +- margin:.25em 1em; +-} +- +-.jd-tagdescr li { +-margin:0 0 .25em 0; +-padding:0; +-} +- +-/* API reference: heading marking +-the details section for constants, +-attrs, methods, etc. */ +-h4.jd-details-title { +- font-size:1.15em; +- background-color: #E2E2E2; +- margin:1.5em 0 .6em; +- padding:3px 95px 3px 3px; /* room for api-level */ +-} +-body.google h4.jd-details-title { +- background-color: #FFF; +- padding-top:5px; +- border-top: 1px solid #ccc; +-} +- +-h4.jd-tagtitle { +- padding:0; +-} +- +-h4 .normal { +- font-weight:normal; +-} +- +-/* API reference: heading for "Parameters", "See Also", etc., +-in details sections */ +-h5.jd-tagtitle { +- padding:0 0 .25em 0; +- font-size:1em; +-} +- +-.jd-tagtable { +- margin:0; +- background-color:transparent; +- width:auto; +-} +- +-.jd-tagtable td, +-.jd-tagtable th { +- border:none; +- background-color:#fff; +- vertical-align:top; +- font-weight:normal; +- padding:2px 10px; +-} +- +-.jd-tagtable th { +- font-style:italic; +-} +- +- +-/* Inline api level indicator for methods */ +-div.api-level { +- font-size:.8em; +- font-weight:normal; +- color:#999; +- float:right; +- padding:0 8px 0; +- margin-top:-35px; +-} +- +-table.jd-tagtable td, +-table.jd-tagtable th { +- background-color:transparent; +-} +- +-table.jd-tagtable th { +- color:inherit; +-} +- +-/************ STICKY NAV BAR ******************/ +- +-#context { +- clear: both; +- padding-top: 14px; +-} +-#context .breadcrumb { +- float: left; +- margin-bottom: 10px; +-} +-#context .util { +- float: right; +- margin-right: 20px; +-} +- +-.breadcrumb { +- list-style: none; +- margin: 0; +- padding: 0; +- position: relative; +-} +-.breadcrumb li { +- float: left; +- padding: 0 20px 0 0; +- color: #000; +- white-space: nowrap; +-} +-.breadcrumb li a { +- color: #000; +-} +-.breadcrumb li:after { +- content: url(../images/breadcrumb.png); +- position: relative; +- top: 1px; +- left: 10px; +- width: 5px; +- height: 10px; +-} +-.breadcrumb li.current { +- font-weight: 700; +-} +-.breadcrumb li.current:after { +- display: none; +-} +- +-/* offset the tags to account for sticky nav */ +-body.reference a[name]:not(.nav-start-marker) { +- visibility: hidden; +- display: block; +- position: relative; +- top: -56px; +- +-} +- +-.nav-start-marker { +- position: absolute; +-} +- +- +-/* Quicknav */ +-.btn-quicknav { +- width:20px; +- height:28px; +- float:left; +- margin-left:6px; +- padding-right:10px; +- position:relative; +- cursor:pointer; +- border-right:1px solid #CCC; +-} +- +-.btn-quicknav a { +- zoom:1; +- position:absolute; +- top:13px; +- left:5px; +- display:block; +- text-indent:-9999em; +- width:10px; +- height:5px; +- background:url(../images/quicknav_arrow.png) no-repeat; +-} +- +-.btn-quicknav a.arrow-active { +- background-position: 0 -5px; +- display:none; +-} +- +-#header-wrap.quicknav a.arrow-inactive { +- display:none; +-} +- +-.btn-quicknav.active a.arrow-active { +- display:block; +-} +- +-#header-wrap.quicknav .nav-x li { +- min-width:160px; +- margin-right:20px; +-} +- +-#header-wrap.quicknav li.last { +- margin-right:0px; +-} +- +-#quicknav { +- float:none; +- clear:both; +- margin-left:0; +- margin-top:-30px; +- display:none; +- overflow:hidden; +-} +- +-#header-wrap.quicknav #quicknav { +- +-} +- +-#quicknav ul { +- margin:10px 0; +- padding:0; +-} +- +-#quicknav ul li.about { +- border-top:1px solid #9933CC; +-} +- +-#quicknav ul li.design { +- border-top:1px solid #33b5e5; +-} +- +-#quicknav ul li.develop { +- border-top:1px solid #FF8800; +-} +- +-#quicknav ul li.distribute { +- border-top:1px solid #99cc00; +-} +- +-#quicknav ul li { +- display:block; +- float:left; +- margin:0 20px 0 0; +- min-width:140px; +-} +- +-#quicknav ul li.last { +- margin-right:0px; +-} +- +-#quicknav ul li ul li { +- float:none; +-} +- +-#quicknav ul li ul li a { +- color:#222; +-} +- +-#quicknav ul li li ul, +-#quicknav ul li li ul li { +- margin:0; +-} +- +-#quicknav ul li li ul li:before { +- content:"\21B3"; +-} +- +-#header-wrap { +- -webkit-transition: all 0.25s ease-out; +- -moz-transition: all 0.25s ease-out; +- -ms-transition: all 0.25s ease-out; +- -o-transition: all 0.25s ease-out; +- transition: all 0.25s ease-out; +- +-} +- +-#header-wrap.quicknav { +- height:216px; +- +-} +- +-.moremenu { +- float: right; +- position: relative; +- width: 50px; +- height:28px; +- display: block; +- margin-top:-3px; +- margin-bottom:7px; +- overflow:hidden; +- -webkit-transition: width 0.25s ease; +- -moz-transition: width 0.25s ease; +- -o-transition: width 0.25s ease; +- transition: width 0.25s ease; +-} +- +-.moremenu #more-btn { +- width:40px; +- height:28px; +- background:url(../images/icon_more.png) no-repeat; +- border-left:1px solid #CCC; +- float:left; +- cursor:pointer; +-} +- +-.moremenu:hover #more-btn { +- background-position:0 -28px; +-} +- +-.morehover { +- position:absolute; +- right:6px; +- top:-9px; +- width:40px; +- height:35px; +- z-index:99; +- overflow:hidden; +- +- -webkit-opacity:0; +- -moz-opacity:0; +- -o-opacity:0; +- opacity:0; +- +- -webkit-transform-origin:100% 0%; +- -moz-transform-origin:100% 0%; +- -o-transform-origin:100% 0%; +- transform-origin:100% 0%; +- +- -webkit-transition-property: -webkit-opacity; +- -webkit-transition-duration: .25s; +- -webkit-transition-timing-function:ease; +- +- -moz-transition-property: -moz-opacity; +- -moz-transition-duration: .25s; +- -moz-transition-timing-function:ease; +- +- -o-transition-property: -o-opacity; +- -o-transition-duration: .25s; +- -o-transition-timing-function:ease; +- +- transition-property: opacity; +- transition-duration: .25s; +- transition-timing-function:ease; +-} +- +-.morehover:hover, +-.morehover.hover { +- opacity:1; +- height:385px; +- width:268px; +- -webkit-transition-property:height, -webkit-opacity; +-} +- +-.morehover .top { +- width:268px; +- height:39px; +- background:url(../images/more_top.png) no-repeat; +-} +- +-.morehover .mid { +- width:228px; +- background:url(../images/more_mid.png) repeat-y; +- padding:10px 20px 0 20px; +-} +- +-.morehover .mid .header { +- border-bottom:1px solid #ccc; +- font-weight:bold; +-} +- +-.morehover .bottom { +- width:268px; +- height:6px; +- background:url(../images/more_bottom.png) no-repeat; +-} +- +-.morehover ul { +- margin:10px 10px 20px 0; +-} +- +-.morehover ul li { +- list-style:none; +-} +- +-.morehover ul li.active a, +-.morehover ul li.active a:hover { +- color:#222 !important; +-} +- +-.morehover ul li.active img { +- margin-right:4px; +-} +- +- +- +- +-/* MARQUEE */ +-.slideshow-container { +- width:100%; +- overflow:hidden; +- position:relative; +-} +-.slideshow-container .slideshow-prev { +- position:absolute; +- top:50%; +- left:0px; +- margin-top:-36px; +- z-index:99; +-} +-.slideshow-container .slideshow-next { +- position:absolute; +- top:50%; +- margin-top:-36px; +- z-index:99; +- right:0px; +-} +- +-.slideshow-container .pagination { +- position:absolute; +- bottom:20px; +- width:100%; +- text-align:center; +- z-index:99; +-} +-.slideshow-container .pagination ul { +- margin:0; +-} +-.slideshow-container .pagination ul li{ +- display: inline-block; +- width:12px; +- height:12px; +- text-indent:-8000px; +- list-style:none; +- margin: 0 3px; +- border-radius:6px; +- background-color:#ddd; +- cursor:pointer; +- -webkit-transition:color .5s ease-in; +- -moz-transition:color .5s ease-in; +- -o-transition:color .5s ease-in; +- transition:color .5s ease-in; +-} +-.slideshow-container .pagination ul li:hover { +- background-color:#bbb; +-} +-.slideshow-container .pagination ul li.active { +- background-color:#6ab344; +-} +-.slideshow-container .pagination ul li.active:hover { +- background-color:#6ab344; +-} +-.slideshow-container ul li { +- display:inline; +- list-style:none; +-} +- +- +-#landing h1 { +- padding:17px 0 20px 0 !important; +-} +- +-a.download-sdk { +- float:right; +- margin:-10px 0; +- height:30px; +- padding-top:4px; +- padding-bottom:0px; +-} +- +-#searchResults.wrap { +- max-width:940px; +- border-bottom:1px solid #e5e5e5; +-} +- +-#searchResults.wrap #leftSearchControl { +- min-height:700px +-} +- +- +- +- +- +- +- +- +- +- +-/* +- * CSS Styles that are needed by jScrollPane for it to operate correctly. +- */ +- +-.jspContainer { +- overflow: hidden; +- position: relative; +-} +- +-.jspPane { +- position: absolute; +- width:100% !important; /* to avoid cut-off api names in reference in horiz scroll */ +-} +- +-.jspVerticalBar { +- position: absolute; +- top: 0; +- right: 0; +- width: 4px; +- height: 100%; +- background: #f5f5f5; +-} +- +-.jspHorizontalBar { +- position: absolute; +- bottom: 0; +- left: 0; +- width: 100%; +- height: 4px; +- background: #f5f5f5; +-} +- +-.jspVerticalBar *, +-.jspHorizontalBar * { +- margin: 0; +- padding: 0; +-} +-.jspCap { +- display: block; +-} +- +-.jspVerticalBar .jspCap { +- height: 4px; +-} +- +-.jspHorizontalBar .jspCap { +- width: 0; +- height: 100%; +-} +- +-.jspHorizontalBar .jspCap { +- float: left; +-} +- +-.jspTrack { +- position: relative; +-} +- +-.jspDrag { +- background: #ccc; +- position: relative; +- top: 0; +- left: 0; +- cursor: pointer; +-} +- +-.jspDrag:hover, +-.jspDrag:active { +- border-color: #09c; +- background-color: #4cadcb; +- background-image: -webkit-gradient(linear, left top, right top, from(#5dbcd9), to(#4cadcb)); +- background-image: -webkit-linear-gradient(left, #5dbcd9, #4cadcb); +- background-image: -moz-linear-gradient(left, #5dbcd9, #4cadcb); +- background-image: -ms-linear-gradient(left, #5dbcd9, #4cadcb); +- background-image: -o-linear-gradient(left, #5dbcd9, #4cadcb); +- background-image: linear-gradient(left, #5dbcd9, #4cadcb); +- filter: progid:DXImageTransform.Microsoft.gradient(startColorStr='#5dbcd9', EndColorStr='#4cadcb'); +-} +- +-.jspHorizontalBar .jspTrack, +-.jspHorizontalBar .jspDrag { +- float: left; +- height: 100%; +-} +- +-.jspArrow { +- background: #999; +- text-indent: -20000px; +- display: block; +- cursor: pointer; +-} +- +-.jspArrow.jspDisabled { +- cursor: default; +- background: #ccc; +-} +- +-.jspVerticalBar .jspArrow { +- height: 16px; +-} +- +-.jspHorizontalBar .jspArrow { +- width: 16px; +- float: left; +- height: 100%; +-} +- +-.jspVerticalBar .jspArrow:focus { +- outline: none; +-} +- +-.jspCorner { +- float: left; +- height: 100%; +-} +- +-/* Yuk! CSS Hack for IE6 3 pixel bug :( */ +-* html .jspCorner { +- margin: 0 -3px 0 0; +-} +-/******* end of jscrollpane *********/ +- +- +- +- +- +-/************ DEVELOP HOMEPAGE ******************/ +- +-/* Slideshow */ +-.slideshow-develop { +- height: 316px; +- width: 940px; +- position: relative; +- overflow:hidden; +-} +-.slideshow-develop .frame { +- width: 940px; +- height: 316px; +-} +-.slideshow-develop img.play { +- max-width:350px; +- max-height:240px; +- margin:20px 0 0 90px; +- -webkit-transform: perspective(800px ) rotateY( 35deg ); +- box-shadow: -16px 20px 40px rgba(0, 0, 0, 0.3); +- -moz-box-shadow: -16px 20px 40px rgba(0, 0, 0, 0.3); +- -webkit-box-shadow: -16px 20px 40px rgba(0, 0, 0, 0.3); +-} +-.slideshow-develop img.play.no-shadow { +- box-shadow: none; +- -moz-box-shadow: none; +- -webkit-box-shadow: none; +-} +-.slideshow-develop img.play.no-transform { +- -webkit-transform: none; +-} +-.slideshow-develop a.slideshow-next { +- background: url(../images/arrow-right-develop.png); +-} +-.slideshow-develop a.slideshow-prev { +- background: url(../images/arrow-left-develop.png); +-} +-.slideshow-develop .content-right { +- float: left; +-} +-.slideshow-develop .content-right h2 { +- padding:0; +- padding-bottom:10px; +- border:none; +- font-size:24px; +-} +-.slideshow-develop .item { +- height: 300px; +- width: 940px; +-} +-.slideshow-develop .pagination ul li.active { +- background-color: #F80; +-} +-.slideshow-develop .pagination ul li.active:hover { +- background-color: #F80; +-} +-.slideshow-develop .item hr { +- margin:5px 0 10px; +-} +-.slideshow-develop .item p { +- margin:10px 0; +-} +-.slideshow-develop .item p.title-intro { +- position:absolute; +- margin:0; +-} +- +-/* Feeds */ +-.feed ul { +- margin: 0; +-} +-.feed .feed-nav { +- height: 25px; +- border-bottom: 1px solid #CCC; +-} +-.feed .feed-nav li { +- list-style: none; +- float: left; +- height: 21px; /* +4px bottom border = 25px; same as .feed-nav */ +- margin-right: 25px; +- cursor: pointer; +-} +-.feed .feed-nav li.active { +- color: #000; +- border-bottom: 4px solid #F80; +-} +-.feed .feed-container { +- overflow: hidden; +- width: 460px; +-} +-.feed .feed-container .feed-frame { +- width: 1000px; +-} +-.feed .feed-container .feed-frame ul { +- float: left; +- width:460px; +-} +-.feed .feed-container .feed-frame ul ul { +- float: none; +- margin:10px 0 0 30px; +-} +-.feed .feed-container .feed-frame li { +- list-style: none; +- margin: 20px 0 20px 0; +- width: 460px; +- height:93px; +-} +-.feed .feed-container .feed-frame li.playlist { +- height:auto; +-} +-.feed .feed-container .feed-frame li.playlist a { +- height:93px; +- display:block; +-} +-.feed .feed-container .feed-frame li.more { +- height:20px; +- margin:10px 0 5px 5px; +-} +-.feed .feed-container .feed-frame li.more a { +- height:inherit; +-} +-.feed .feed-container .feed-frame li.playlist-video { +- list-style: none; +- margin: 0; +- width: 460px; +- height:55px; +- font-size:12px; +-} +-.feed .feed-container .feed-frame li.playlist-video a { +- height:45px; +- padding:5px; +-} +-.feed .feed-container .feed-frame li.playlist-video h5 { +- font-size:12px; +- line-height:13px; +- padding:0; +-} +-.feed .feed-container .feed-frame li.playlist-video p { +- margin:5px 0 0; +- line-height:15px; +-} +-.feed-container .feed-frame div.feed-image { +- float: left; +- border: 1px solid #999; +- margin:0 20px 0 0; +- width:122px; +- height:92px; +- background:url('../images/blog-default.png') no-repeat 0 0; +- background-size:180px; +-} +-#jd-content .feed .feed-container .feed-frame li img { +- float: left; +- border: 1px solid #999; +- margin:0 20px 0 0; +- width:122px; +- height:92px; +-} +-#jd-content .feed .feed-container .feed-frame li.playlist-video img { +- width:inherit; +- height:inherit; +-} +- +-.feed .feed-container .feed-frame li a, +-.feed .feed-container .feed-frame li a:active { +- color:#555 !important; +-} +- +-.feed .feed-container .feed-frame li a:hover, +-.feed .feed-container .feed-frame li a:hover * { +- color:#7AA1B0 !important; +-} +- +-/* Video player */ +-#player-wrapper { +- display:none; +- margin: -1px auto 0; +- position: relative; +- max-width: 940px; +- height: 0px; +-} +-#player-frame { +- background: #EFEFEF; +- border: 1px solid #CCC; +- padding: 0px 207px; +- z-index: 10; /* stay above marque, but below search suggestions */ +- width: 525px; +- height: 330px; +- position: relative; +-} +-#player-frame .close { +- position: absolute; +- right: 8px; +- bottom: 4px; +- width: 16px; +- height: 16px; +- margin: 0; +- text-indent: -1000em; +- top: 6px; +- background: url(../images/close.png) no-repeat 0 0; +- z-index:9999; +-} +-#player-frame .close:hover, #player-frame .close:focus { +- background-position: -16px 0; +- cursor:pointer; +-} +- +- +- +-/************ DEVELOP TOPIC CONTAINERS ************/ +- +-.landing-banner, +-.landing-docs { +- margin:20px 0; +-} +-.landing-banner > div:first-child, +-.landing-docs > div:first-child, +-.landing-docs > .col-12 { +- margin-left:0; +- min-height:280px; +-} +-.landing-banner.short > div { +- min-height:50px; +-} +-.landing-banner > div:last-child, +-.landing-docs > div:last-child, +-.landing-docs > .col-12 { +- margin-right:0; +-} +- +-.landing-banner > div > *:last-child { +- margin-bottom:0; +-} +-.landing-banner h1 { +- padding-top:16px; +- padding-bottom:24px; +-} +-.landing-docs, +-.landing-banner { +- clear:both; +- overflow:hidden; +-} +-.landing-docs h3 { +- font-size:14px; +- line-height:21px; +- color:#555; +- text-transform:uppercase; +- border-bottom:1px solid #CCC; +- padding:0 0 20px; +-} +-.landing-docs a { +- color:#333 !important; +-} +- +-.landing-docs a:hover, +-.landing-docs a:hover * { +- color:#7AA1B0 !important +-} +- +-.landing-docs .normal-links a { +- color:#039BE5 !important; +-} +- +-.plusone { +- float:right; +-} +- +- +- +-.next-docs { +- border-top:1px solid #ccc; +- margin:40px 0 0; +- padding:5px 0 0; +- clear:left; +- overflow:hidden; +-} +-.next-docs div:first-child { +- margin-left:0; +-} +-.next-docs div:last-child { +- margin-right:0; +-} +- +-.next-docs h2 { +- font-size:14px; +- line-height:21px; +- color:#555; +- text-transform:uppercase; +- border-bottom:none; +- padding:5px 0 1em; +-} +- +- +- +-/************* HOME/LANDING PAGE *****************/ +- +-.slideshow-home { +- height: 500px; +- width: 940px; +- border-bottom: 1px solid #CCC; +- position: relative; +- margin: 0; +-} +-.slideshow-home .frame { +- width: 940px; +- height: 500px; +-} +-.slideshow-home .content-left { +- float: left; +- text-align: center; +- vertical-align: center; +- margin: 0 0 0 35px; +-} +-.slideshow-home .content-right { +- margin: 80px 0 0 0; +-} +-.slideshow-home .content-right p { +- margin-bottom: 10px; +-} +-.slideshow-home .content-right p:last-child { +- margin-top: 15px; +-} +-.slideshow-home .content-right h1 { +- padding:0; +-} +-.slideshow-home .item { +- height: 500px; +- width: 940px; +-} +-.home-sections { +- padding: 30px 20px 20px; +- margin: 20px 0; +- background: -webkit-linear-gradient(top, #F6F6F6,#F9F9F9); +-} +-.home-sections ul { +- margin: 0; +-} +-.home-sections ul li { +- float: left; +- display: block; +- list-style: none; +- width: 170px; +- height: 35px; +- border: 1px solid #ccc; +- background: white; +- margin-right: 10px; +- border-radius: 1px; +- -webkit-border-radius: 1px; +- -moz-border-radius: 1px; +- box-shadow: 1px 1px 5px #EEE; +- -webkit-box-shadow: 1px 1px 5px #EEE; +- -moz-box-shadow: 1px 1px 5px #EEE; +- background: white; +-} +-.home-sections ul li:hover { +- background: #F9F9F9; +- border: 1px solid #CCC; +-} +-.home-sections ul li a, +-.home-sections ul li a:hover { +- font-weight: bold; +- margin-top: 8px; +- line-height: 18px; +- float: left; +- width: 100%; +- text-align: center; +- color: #039BE5 !important; +-} +-.home-sections ul li a { +- font-weight: bold; +- margin-top: 8px; +- line-height: 18px; +- float: left; +- width:100%; +- text-align:center; +-} +-.home-sections ul li img { +- float: left; +- margin: -8px 0 0 10px; +-} +-.home-sections ul li.last { +- margin-right: 0px; +-} +- +-/************ DISTRIBUTE PAGES ******************/ +- +-.article-detail #body-content { +- padding-top: 10px; +-} +- +-/* A container for grid sets with uppercase h3 and rule */ +-.dynamic-grid h3 { +- font-size:14px; +- line-height:21px; +- color:#555; +- text-transform:uppercase; +- border-bottom:1px solid #CCC; +- padding:8px 0 14px 1px; +- clear:both; +-} +- +-.top-right-float { +- float: right; +-} +- +-.clearfloat { +- float: none; +- clear: both; +-} +- +- +-/** +- * UTILITIES +- */ +- +- +-.border-box { +- box-sizing: border-box; +-} +- +-.vertical-center-outer { +- display: table; +- height: 100%; +- width: 100%; +-} +- +-.vertical-center-inner { +- display: table-cell; +- vertical-align: middle; +-} +- +-/** +- * TYPE STYLES +- */ +- +-.landing-h1 { +- color: #44555d; +- font-weight: 300; +- font-size: 56px; +- line-height: 80px; +- text-align: center; +- letter-spacing: -1px; +- padding-bottom: 6px; +-} +- +-.landing-pre-h1 { +- font-weight: 400; +- font-size: 28px; +- color: #93B73F; +- line-height: 36px; +- text-align: center; +- letter-spacing: -1px; +- text-transform: uppercase; +-} +- +-.landing-h1.hero { +- text-align: left; +- color: #fff; +-} +- +-.landing-h2 { +- font-weight: 300; +- font-size: 42px; +- line-height: 64px; +- text-align: center; +-} +- +-.landing-subhead { +- color: #78868d; +- font-size: 20px; +- font-weight: 300; +- line-height: 32px; +- text-align: center; +-} +-.landing-subhead.hero { +- text-align: left; +- color: white; +-} +- +-.landing-hero-description { +- text-align: left; +- margin: 1em 0; +-} +- +-.landing-hero-description p { +- font-weight: 300; +- margin: 0; +- font-size: 18px; +- line-height: 24px; +-} +- +-.landing-body .landing-small { +- font-size: 14px; +- line-height: 19px; +-} +- +-.landing-body.landing-align-center { +- text-align: center; +-} +- +-.landing-align-left { +- text-align: left; +-} +- +-/** +- * LAYOUT +- */ +- +-.landing-section { +- background: #eceff1; +- clear: both; +- padding: 80px 20px 80px; +- margin: 0 -20px; +- text-rendering: optimizeLegibility; +-} +- +-@media (max-width: 719px) { +- .landing-section { +- margin-left: -10px; +- margin-right: -10px; +- padding-left: 10px; +- padding-right: 10px; +- } +-} +- +-.landing-short-section { +- padding: 40px 10px 28px; +-} +- +-.landing-gray-background { +- background-color: #b0bec5; +-} +- +-.landing-white-background { +- background-color: white; +-} +- +-.landing-red-background { +- color: white; +- background-color: hsl(8, 70%, 54%); +-} +- +-.landing-red-background .landing-h1 { +- color: white; +-} +- +-.landing-red-background .landing-subhead { +- color: hsl(8, 71%, 84%); +- text-align: left; +-} +- +- +-.preview-hero { +- height: calc(100vh - 128px); +- min-height: 504px; +- padding-top: 0; +- padding-bottom: 0; +- background-image: url(../../preview/images/hero.jpg); +- background-size: cover; +- background-position: right center; +- color: white; +- position: relative; +- overflow: hidden; +-} +- +-.wear-hero { +- height: calc(100vh - 128px); +- min-height: 504px; +- padding-top: 0; +- padding-bottom: 0; +- background-image: url(../../wear/images/hero.jpg); +- background-size: cover; +- background-position: top center; +- color: white; +- position: relative; +- overflow: hidden; +-} +- +-.tv-hero { +- height: calc(100vh - 128px); +- min-height: 504px; +- padding-top: 0; +- padding-bottom: 0; +- background-image: url(../../tv/images/hero.jpg); +- background-size: cover; +- background-position: right center; +- color: white; +- position: relative; +- overflow: hidden; +-} +- +-.auto-hero { +- height: calc(100vh - 128px); +- min-height: 504px; +- padding-top: 0; +- padding-bottom: 0; +- background-image: url(../../auto/images/hero.jpg); +- background-size: cover; +- background-position: right center; +- color: white; +- position: relative; +- overflow: hidden; +-} +- +-.landing-hero-scrim { +- background: black; +- height: 100%; +- left: 0; +- position: absolute; +- opacity: .2; +- width: 100%; +-} +- +-.landing-hero-wrap { +- margin: 0 auto; +- max-width: 940px; +- clear: both; +- height: 100%; +- position: relative; +-} +- +-.landing-section-header { +- margin-bottom: 40px; +-} +- +-.landing-hero-wrap .landing-section-header { +- margin-bottom: 16px; +-} +- +-.landing-body { +- font-size: 18px; +- line-height: 24px; +-} +- +-.landing-video-link { +- white-space: nowrap; +- display: inline-block; +- padding: 16px 32px 16px 82px; +- font-size: 18px; +- font-weight: 400; +- line-height: 24px; +- cursor: pointer; +- color: hsla(0, 0%, 100%, .8); +- -webkit-user-select: none; +- -moz-user-select: none; +- -o-user-select: none; +- user-select: none; +- -webkit-transition: .2s color ease-in-out; +- -moz-transition: .2s color ease-in-out; +- -o-transition: .2s color ease-in-out; +- transition: .2s color ease-in-out; +-} +- +-.landing-video-link:before { +- height: 64px; +- width: 64px; +- display: inline-block; +- background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAGAAAABgCAYAAADimHc4AAAFuklEQVR42u2dXWgcVRSAV9LWtBBTTZVWUhNqEQtq1QeroDRKFRFsROqTYPuo+JCiIoJKFC0USqlUfCiowRcfrBgVUUElefAPkW5T8aeaGn9aRbFsjP0x2cx8PuRMvFxmdjeb2Z17Z8+B85DsZPbO+eaec3/OPSkABdXsVI2gABSAqgJQAKoKQAGoKgAFoKoAFICqAlAAqgpAAai6DqDRAiwDeoFtwB7gPaAInABKwKToCWAMeB/YDdwJrAWWNLh9+QMAXABsBQ4A3wFTwAxQBmaBAAhjNJDPy3L938BXwAvArUCHAkh+kCXAVcA+YBw4bRg7MngtkgTlDPA98CywHmhTAP8/xCbgVeAvMZZpwDQllN7xB/AysKGlAQAXAvuBkzW85UVgCBgENlfQQbmuWAXELPAnsAvoaikAQBtwh/j3coLhS2LIfqCzzu/plL8fkvvFgZiR4L2lHrfkHQBgpQTFUwmGnwC212v0KjC2y/3jQPwDPA+05xYAcBHwubx1YZzhC02QBBBRbxgBzssdAOBy4JgRZE0ZTPuNr7FHDCbEhqNAd24AAN0yUbID7QSwsZChABut3hANXY8Bq70HIMb/Ocb4w81+66v0hmGrN0QQ1ngLQJYRvpWHMWWo4KDIaMnuCcVKgdlZAGL8t2J8vpPGrwChDLyWBMFlAA8D0z4ZvwKEs8D93gCQEc9Jy/jFgkdizaRDGUSs8wXAu1bQLQE9ngHosWbPAXDQeQAypT9rBd3+gociyxi2K9riLABZUj5iuZ6RgsciM2OzFxw2A7JrAO6VwGtKTwpG+Anoy9AVmb3gDHCPcwCAFcChRox6jPu9CazMeFQUAKNRL3AJwE2yopjq228BQPZ/d2bcCyaBTa4BeNGa8Q6naIA4GQWubiKEYWvBbp8zAGQt5VfL/fQ3GEAkTzXDLVkjokA2k5a7AuA2GaLNj/tTfvhq0pQgbcwLQtlQusYVALtlzSR191MjADNI9zbJDZWBR10BMGr5/4GMADQ0SAMDlht62xUAxy0AmzMEEMnhtIO0ZF2YAH5wITd0hQw/5wE04M1bjDyXZpC2hqMlYGnWAHqBf40APOEYgChI35VSWyasWfGqrAH0WVkOIw4CSC1IG2tDoSy7XJE1gPs8ArDoIG0BmJGk30wBDHgGYFFBOgbAtqwB7GxxAHerC8rOBU0Dt2gQzjYIb8gawDor+6HVhqFdrkzEwhabiAVOTMSkUb+06FLEUVfWgj5q0cW4g64AeNo66ZLlcnTDNmesBN4y8KArAG6QU42ttCEzBVzpCoAO4EfLDeV5SzIEvgHaXdqUP2BlQud1Ux55zj2uZUX02cPRnKalRLmu17qYmPWF5YbymJgVAh8Ay5wCII3ZEZOYm6fURGT2u9X43Mnk3CDHybmfmRVYXExPv9nKEcpLejqSC3SjdY2TBzTesHqB7wc0onTEV2KucxLApXKkJy9HlAI5anuJFwCkYQ/EuCJfD+mdBnYkXOssgHY53un7MdVZ4CVgqVcADAhjMafkfTioHc14P04yvvMApIEXy5F/+7S8y6UKolPyR4BVVf7Wi2IdawwIPhTrmAW+rmZ8bwBIQ7vloXwoVzNWS6UUrwAYy9YfOlqwKZDkgneA5Qu4l3cly84F9sqGhislywLmaozuYoGFXr0DII1ukxP1hxJ6QzR7HqLxRfumZaRzXZ3f4XXZyi7gCeB3kqsnzs+kSb9s5XHgMeD8RTxDLgq3rmeuYuFvNYCoR8wqujNi+L3UWBcu9wAMt3QZ8LiMlk5RuU50teq6kcEDgTolveIRYHUQBOek1O5cFu/ukLz7/ZJgNSm+OirebWpgaPS7slxfAr4EngGuX8jopqUBxGzyrAVuB54EXgc+lV4yLhO8cfn5E+ZqUD8kBu9sQvv0Hzj4rmoEBaAAVBWAAlBVAApAVQEoAFUFoABUFYACUFUACkC1CfofXVRJocowZVYAAAAASUVORK5CYII=); +- background-size: contain; +- position: absolute; +- content: ""; +- opacity: .7; +- margin-top: -19px; +- margin-left: -64px; +- -webkit-transition: .2s opacity ease-in-out; +- -moz-transition: .2s opacity ease-in-out; +- -o-transition: .2s opacity ease-in-out; +- transition: .2s opacity ease-in-out; +-} +- +-.landing-video-link:hover { +- color: hsla(0, 0%, 100%, 1); +-} +- +-.landing-video-link:hover:before { +- opacity: 1; +-} +- +-.landing-social-image { +- float: left; +- margin-right: 14px; +- height: 64px; +- width: 64px; +-} +- +-.landing-social-copy { +- padding-left: 78px; +-} +- +-.landing-scroll-down-affordance { +- position: absolute; +- bottom: 0; +- width: 100%; +- text-align: center; +- z-index: 10; +-} +- +-.landing-down-arrow { +- padding: 24px; +- display: inline-block; +- opacity: .5; +- -webkit-transition: .2s opacity ease-in-out; +- -moz-transition: .2s opacity ease-in-out; +- -o-transition: .2s opacity ease-in-out; +- transition: .2s opacity ease-in-out; +- +- -webkit-animation-name: pulse-opacity; +- -webkit-animation-duration: 4s; +-} +- +-.landing-down-arrow:hover { +- opacity: 1; +-} +- +-.landing-down-arrow img { +- height: 28px; +- width: 28px; +- margin: 0 auto; +- display: block; +-} +- +-.landing-divider { +- display: inline-block; +- height: 2px; +- background-color: white; +- position: relative; +- margin: 10px 0; +-} +- +-/* 3 CLOLUMN LAYOUT */ +- +-.landing-breakout { +- margin-top: 40px; +- margin-bottom: 40px; +-} +- +-.landing-breakout img { +- margin-bottom: 20px; +-} +- +-.landing-partners img { +- margin-bottom: 20px; +-} +- +-.landing-breakout p { +- padding: 0 23px; +-} +- +-.landing-breakout.landing-partners img { +- margin-bottom: 20px; +-} +- +-/** +- * ANIMATION +- */ +- +-@-webkit-keyframes pulse-opacity { +- 0% { +- opacity: .5; +- } +- 20% { +- opacity: .5; +- } +- 40% { +- opacity: 1; +- } +- 60% { +- opacity: .5; +- } +- 80% { +- opacity: 1; +- } +- 100% { +- opacity: .5; +- } +-} +- +- +-/****************** +-Styles for d.a.c/index: +-*******************/ +- +- +- +-/* Generic full screen carousel styling to be used across pages. */ +-.fullscreen-carousel { +- margin: 0 -20px; +- overflow: hidden; +- position: relative; +-} +- +-.fullscreen-carousel-content { +- width: 100%; +- height: 100%; +- position: relative; +- display: table; /* For vertical centering */ +-} +- +-.fullscreen-carousel .vcenter { +- display: table-cell; +- vertical-align: middle; +- position: relative; +-} +- +-.fullscreen-carousel .vcenter > div { +- margin: 10px auto; +-} +- +-/* Styles for the full-bleed hero image type. */ +-.fullscreen-carousel .hero, .fullscreen-carousel .hero h1 { +- color: #fff; +-} +- +-.fullscreen-carousel .hero h1 { +- font-weight: 300; +- font-size: 60px; +- line-height: 68px; +- letter-spacing: -1px; +- padding-top: 0; +-} +- +-.fullscreen-carousel .hero p { +- font-weight: 300; +- font-size: 18px; +- line-height: 24px; +-} +- +-.fullscreen-carousel .hero .hero-bg { +- background-size: cover; +- width: 100%; +- height: 100%; +- position: absolute; +- left: 0px; +- top: 0px; +-} +- +- +-/* Full screen carousel styling for the resource flow layout type of content */ +-.fullscreen-carousel .resource-flow-layout:after { +- height: 0; /* Dont know why this is set at 10 in default.css */ +-} +- +-.fullscreen-carousel .resource-flow-layout { +- margin-bottom: 20px; +-} +- +- +- +-/* Generic Tab carousel styling to be used across multiple pages. */ +- +-.tab-carousel .tab-nav { +- list-style: none; +- position: relative; +- text-align: center; +-} +- +-.tab-carousel .tab-nav li { +- display: inline-block; +- font-size: 22px; +- font-weight: 400; +- line-height: 50px; +- list-style: none; +- margin: 0; +- padding: 0 25px; +- position: relative; +-} +- +-.tab-carousel .tab-nav li a, +-.tab-carousel .tab-nav li a:hover { +- color: #333 !important; +- padding: 10px 10px 13px 10px; +- position: relative; +- z-index: 1000; +-} +- +-.tab-carousel .tab-nav li:after { +- background: #ddd; +- bottom: 0; +- content: ''; +- height: 4px; +- left: 0; +- position: absolute; +- width: 100%; +- z-index: 0; +-} +- +-.tab-carousel .tab-nav .highlight { +- position: absolute; +- height: 4px; +- width: 100px; +- bottom: 0; +- background: #33b5e5; +-} +- +-.tab-carousel .tab-carousel-content { +- position: relative; +- overflow: hidden; +- white-space: nowrap; +-} +- +-.tab-carousel .tab-carousel-content [data-tab] { +- display: inline-block; +- white-space: normal; +-} +- +- +- +-/* +- Resource styling for the tab carousel. The tab carousel contains either +- a 3 column layout of resources or a single full-width resource. The +- latter has the 18x12 class applied to it and can be styled differently +- that way. +-*/ +- +-.tab-carousel .resource .image { +- width: 100%; +- height: 250px; +- background-repeat: no-repeat; +- background-size: contain; +- background-position: 50% 50%; +-} +- +-.tab-carousel .resource .info .title { +- font-size: 18px; +- line-height: 24px; +-} +- +-.tab-carousel .resource .info .summary, +-.tab-carousel .resource .info .cta { +- line-height: 24px; +- font-size: 16px; +-} +- +-.tab-carousel .resource-card-18x12 { +- position: relative; +- padding-left: 450px; +- box-sizing: border-box; +- display: table-cell; +- vertical-align: middle; +-} +- +-.tab-carousel .resource-card-18x12 .image { +- position: absolute; +- width: 420px; +- height: 100%; +- left: 0; +- top: 0; +-} +- +-.tab-carousel .resource-card-18x12 .info { +- display: inline-block; +-} +- +-.tab-carousel .resource-card-18x12 .info .title { +- margin-bottom: 26px; +-} +- +-/* +- Specific styles for new home page layout of the carousels. +-*/ +- +-/* Big blue button */ +-a.home-new-cta-btn, +-.home-new-carousel-1 .resource-card-18x6 .cta { +- white-space: nowrap; +- display: inline-block; +- padding: 14px 32px; +- font-size: 18px; +- font-weight: 500; +- line-height: 24px; +- cursor: pointer; +- background: #33b5e6; +- border-radius: 4px; +- margin-top: 20px; +- color: #fff; +- transition: 0.2s background-color ease-in-out; +-} +- +-.home-new-carousel-1 .resource-card-18x6 .cta:after { +- display: none; /* Hide the entity for this button */ +-} +- +-a.home-new-cta-btn:hover, +-.home-new-carousel-1 .resource-card-18x6 .cta:hover { +- color: #fff !important; +- background: #2d9fca; +-} +- +-.home-new-carousel-1 .resource-card-18x6 .cta { +- position: absolute; +- bottom: 20px; +- left: 16px; +-} +- +-/* Fullscreen carousel. */ +-.home-new-carousel-1 { +- max-height: 700px; /* Set max height so doesn't get too long */ +-} +- +-.home-new-carousel-1 .fullscreen-carousel-content { +- min-height: 450px; /* Set min height for all content */ +-} +- +-.home-new-carousel-1 .hero { +- background: #000; +-} +- +-.home-new-carousel-1 .hero-bg { +- background-image: url(/home-new/images/hero.jpg); +- background-position: right center; +- opacity: 0.85; +-} +- +-/* +- Styling for special top card of full screen layout resource layout. +- We need to specifically style the 18x6 card to adjust its size and layout, +- since it's not a standard card, not sure if this is unique to the home page +- layout or should be namespaced within the fullscreen-carousel container. +-*/ +-.home-new-carousel-1 .resource-flow-layout.col-16 .resource-card-18x6 { +- height: 320px; +- background-color:#F9F9F9; +- border-radius: 0px; +- box-shadow: 0px 0px 0px rgba(0, 0, 0, 0); +- +-} +- +-.home-new-carousel-1 .resource-card-18x6 .card-bg { +- width: 636px; +- height: 100%; +-} +- +-.home-new-carousel-1 .resource-card-18x6 .card-info { +- right: 0px; +- left: 636px; +- height: 100%; +- top: 0px; +- padding: 15px 22px; +-} +- +-.home-new-carousel-1 .resource-card-18x6 .card-info .util { +- display: none; +-} +- +-.home-new-carousel-1 .resource-card-18x6 .card-info .title { +- font-size: 20px; +- font-weight: 500; +- margin-top: 15px; +- margin-bottom: 15px; +-} +- +-.home-new-carousel-1 .resource-card-18x6 .card-info .text { +- font-size: 15px; +- line-height: 21px; +-} +- +- +-/* Tabbed carousel. */ +-.home-new-carousel-2 { +- margin: 35px auto 100px auto; +-} +- +-.home-new-carousel-2 h1 { +- font-size: 47px; +- font-weight: 100; +- line-height: 54px; +- text-align: center; +-} +- +-.annotation-message { +- display: block; +- font-style: italic; +- color: #F80; +-} +- +- +- +-/* Helpouts widget */ +-.resource-card-6x2.helpouts-card { +- width: 255px; +- height: 40px; +- position:absolute; +- z-index:999; +- top:-8px; +- right:1px; +-} +- +-.resource-card-6x2.helpouts-card > .card-info { +- left:35px; +- height:35px; +- padding:4px 8px 4px 0; +-} +- +-.resource-card-6x2.helpouts-card > .card-info .helpouts-description { +- display:block; +- overflow:visible; +- font-size:12px; +- line-height:12px; +- text-align:right; +- color:#666; +-} +- +-.helpouts-description .link-color { +- text-transform: uppercase; +-} +- +-.resource-card-6x2 > .card-bg.helpouts-card-bg { +- width:35px; +- height:35px; +- margin:2px 0 0 0; +- background-image: url(../images/styles/helpouts-logo-35_2x.png); +- background-image: -webkit-image-set(url(../images/styles/helpouts-logo-35.png) 1x, url(../images/styles/helpouts-logo-35_2x.png) 2x); +-} +- +-.resource-card-6x2 > .card-bg.helpouts-card-bg:after { +- display:none; +-} +- +-#tb li:before, #qv li:before { +- background-position: 0px -196px; +- height: 24px; +- width: 24px; +- content: ''; +- left: -8px; +- opacity: .7; +- position: absolute; +- top: -4px; +-} +- +-/* CHANGE EXISTING SELECTOR FOR ANDROID M HERO ONLY +- REMOVE THE BELOW STYLES WHEN THE ANDROID M CAROUSEL +- GRAPHIC ON THE MAIN LANDING IS TAKEN DOWN */ +-.dac-hero.mprev { +- background-color: #fff; +- background-position: 50% 53%; +- background-size: cover; +- background-image: url(../images/home/android_m_hero_1200.jpg); +- box-sizing: border-box; +- font-size: 16px; +- min-height: 550px; +- padding-top: 88px; +-} +-.dac-hero.dac-darken.mprev::before { +- background: rgba(0, 0, 0, 0.3); +- bottom: 0; +- content: ''; +- display: block; +- left: 0; +- position: absolute; +- right: 0; +- top: 0; +-} +- +-.dac-hero.dac-darken.mprev::before { +- background: -webkit-linear-gradient(top, rgba(0, 0, 0, .05), rgba(0, 0, 0, .05), #000 950px); +- background: linear-gradient(to bottom, rgba(0, 0, 0, .05), rgba(0, 0, 0, 0.05), #000 950px); +-} +- +-@media (max-width: 719px) { +- .dac-hero.dac-darken.mprev { +- background-size: auto 600px; +- background-position: 55% 0; +- background-repeat: no-repeat; +- } +- +- .dac-hero-figure.mprev { +- height: 10px; +- margin: 15px 0; +- } +-} +- +-@media (max-width: 719px) { +- .dac-hero.dac-darken.mprev { +- background-size: auto 600px; +- background-position: 55% 0; +- background-repeat: no-repeat; +- } +- +- .dac-hero-figure.mprev { +- height: 10px; +- margin: 15px 0; +- } +-} +- +-@media (max-width: 1200px) { +- .dac-hero.dac-darken.mprev { +- background-size: auto 700px; +- background-position: 55% 0; +- background-repeat: no-repeat; +- } +- +- .dac-hero-cta.mprev { +- white-space:nowrap; +- } +-} +- +-@charset "UTF-8"; +-/** +- * Fades out an element. +- * Applies visibility hidden when the transition is finished. +- * +- * Use opacity: 1; to show the element. +- */ +-.dac-visible-mobile-block, .dac-mobile-only, +-.dac-visible-mobile-inline, +-.dac-visible-mobile-inline-block, +-.dac-visible-tablet-block, +-.dac-visible-tablet-inline, +-.dac-visible-tablet-inline-block, +-.dac-visible-desktop-block, +-.dac-visible-desktop-inline, +-.dac-visible-desktop-inline-block { +- display: none !important; +-} +- +-@media (max-width: 719px) { +- .dac-hidden-mobile { +- display: none !important; +- } +- +- .dac-visible-mobile-block, .dac-mobile-only { +- display: block !important; +- } +- +- .dac-visible-mobile-inline { +- display: inline !important; +- } +- +- .dac-visible-mobile-inline-block { +- display: inline-block !important; +- } +-} +- +-@media (min-width: 720px) and (max-width: 979px) { +- .dac-hidden-tablet { +- display: none !important; +- } +- +- .dac-visible-tablet-block { +- display: block !important; +- } +- +- .dac-visible-tablet-inline { +- display: inline !important; +- } +- +- .dac-visible-tablet-inline-block { +- display: inline-block !important; +- } +-} +- +-@media (min-width: 980px) { +- .dac-hidden-desktop { +- display: none !important; +- } +- +- .dac-visible-desktop-block { +- display: block !important; +- } +- +- .dac-visible-desktop-inline { +- display: inline !important; +- } +- +- .dac-visible-desktop-inline-block { +- display: inline-block !important; +- } +-} +- +-.dac-offset-parent { +- position: relative !important; +-} +- +-/** +- * Hide from browsers/screenreaders on all sizes. +- */ +-.dac-hidden { +- display: none !important; +-} +- +-/** +- * Break strings when their length exceeds the width of their container. +- */ +-.dac-text-break { +- word-wrap: break-word !important; +-} +- +-/** +- * Horizontal text alignment +- */ +-.dac-text-center { +- text-align: center !important; +-} +- +-.dac-text-left { +- text-align: left !important; +-} +- +-.dac-text-right { +- text-align: right !important; +-} +- +-/** +- * Prevent whitespace wrapping +- */ +-.dac-text-no-wrap { +- white-space: nowrap !important; +-} +- +-/** +- * Prevent text from wrapping onto multiple lines, instead truncate with an ellipsis. +- */ +-.dac-text-truncate { +- max-width: 100%; +- overflow: hidden !important; +- text-overflow: ellipsis !important; +- white-space: nowrap !important; +- word-wrap: normal !important; +-} +- +-/** +- * Floats +- */ +-.dac-float-left { +- float: left !important; +-} +- +-.dac-float-right { +- float: right !important; +-} +- +-/** +- * New block formatting context +- * +- * This affords some useful properties to the element. It won't wrap under +- * floats. Will also contain any floated children. +- * N.B. This will clip overflow. Use the alternative method below if this is +- * problematic. +- */ +-.dac-nbfc { +- overflow: hidden !important; } +- +-/** +- * New block formatting context (alternative) +- * +- * Alternative method when overflow must not be clipped. +- * +- * N.B. This breaks down in some browsers when elements within this element +- * exceed its width. +- */ +-.dac-nbfc-alt { +- display: table-cell !important; +- width: 10000px !important; } +- +-/* New CSS */ +-/************ RESOURCE CARDS ******************/ +-/* Basic card-styling with shadow */ +-.resource-card { +- background: #fff; +- box-shadow: 0px 1px 3px 0px rgba(0, 0, 0, 0.21); +- display: block; +- position: relative; } +- +-/* Play button is only visible on 6by6 cards */ +-.play-button { +- background-color: #000; +- border-radius: 50%; +- box-sizing: border-box; +- display: none; +- height: 70px; +- line-height: 65px; +- padding-left: 4px; +- position: absolute; +- opacity: .6; +- text-align: center; +- -webkit-transition: opacity .5s; +- transition: opacity .5s; +- width: 70px; +- z-index: 1; } +- .resource-card-6x2 .play-button { +- display: block; +- left: 10px; +- top: 15px; +- -webkit-transform: scale(0.73); +- -ms-transform: scale(0.73); +- transform: scale(0.73); } +- .resource-card-6x6 .play-button { +- display: block; +- left: 50%; +- margin-left: -35px; +- top: 50px; } +- +-/* Styling for background image including tinting and section icons in stacks */ +-.card-bg { +- bottom: 131px; +- display: block; +- position: absolute; +- vertical-align: top; +- width: 100%; +- left: 0; +- top: 0; +- background-size: cover; +- background-repeat: no-repeat; +- background-position: center; +- background-image: url(../images/resource-card-default-android.jpg); } +- .card-bg:after { +- content: ""; +- display: block; +- height: 100%; +- width: 100%; +- opacity: 1; +- background: rgba(0, 0, 0, 0.05); +- -webkit-transition: opacity 0.5s; +- transition: opacity 0.5s; } +- .static .card-bg:after { +- display: none; } +- .card-bg .card-section-icon { +- position: absolute; +- top: 50%; +- width: 100%; +- margin-top: -35px; +- text-align: center; +- padding-top: 65px; +- z-index: 100; } +- .card-bg .card-section-icon .icon { +- position: absolute; +- left: 50%; +- margin-left: -28px; +- top: 0px; +- width: 56px; +- height: 56px; +- background-repeat: no-repeat; +- background-position: 50% 50%; +- background-image: url(../images/stack-icon.png); } +- .card-bg .card-section-icon .section { +- text-transform: uppercase; +- color: white; +- font-size: 14px; } +- +-.card-info { +- position: absolute; +- box-sizing: border-box; +- height: 131px; +- right: 0; +- bottom: 0; +- left: 0; +- overflow: hidden; +- background: #fefefe; +- padding: 6px 12px; +-} +- +-.card-info .section { +- color: #898989; +- font-size: 11px; +- font-weight: 700; +- letter-spacing: .3px; +- line-height: 20px; +- text-transform: uppercase; +-} +- +-.card-info .title { +- color: #333; +- font-size: 18px; +- font-weight: 500; +- line-height: 23px; +- margin-bottom: 7px; +- max-height: 46px; +- overflow: hidden; +- text-overflow: ellipsis; +- white-space: normal; +-} +- +-.card-info .description { +- overflow: hidden; +-} +- +-.card-info .description .text { +- color: #666; +- font-size: 14px; +- height: 60px; +- line-height: 20px; +- overflow: hidden; +- width: 100%; +-} +- +-.card-info .description .util { +- position: absolute; +- right: 5px; +- bottom: 70px; +- opacity: 0; +- -webkit-transition: opacity 0.5s; +- transition: opacity 0.5s; +-} +- +-.card-info.empty-desc .title { +- white-space: normal; +- overflow: visible; +-} +- +-.card-info.empty-desc .description { +- display: none; +-} +- +-/* Resource card with icon instead of bg image */ +-.resource-widget-card-icon { +- text-align: center; +-} +- +-.card-icon { +- margin: 20px 0 0; +-} +- +-.resource-widget-card-icon .card-info { +- height: 210px; +-} +- +-.resource-widget-card-icon .card-info .title { +- color: #333; +- line-height: 24px; +-} +- +-.resource-widget-card-icon .card-bg { +- background: none; +- bottom: 220px; +- opacity: 1; +- top: 30px; +- -webkit-transition: opacity .3s; +- transition: opacity .3s; +-} +- +-.resource-widget-card-icon .resource-card:hover .card-bg { +- opacity: .5; +-} +- +-.resource-widget-card-icon .card-bg img { +- max-height: 100%; +-} +- +-.resource-widget-card-icon .card-bg::after { +- background: transparent; +-} +- +-@media (min-width: 1210px) { +- .resource-widget-card-icon .resource { +- height: 240px; +- } +- .resource-widget-card-icon .card-bg { +- bottom: 160px; +- } +- .resource-widget-card-icon .card-info { +- height: 160px; +- } +-} +- +-@media (max-width: 979px) { +- .resource-widget-card-icon .resource { +- height: 240px; +- } +- .resource-widget-card-icon .card-bg { +- bottom: 160px; +- } +- +- .resource-widget-card-icon .card-info { +- height: 160px; +- } +-} +- +-/* Truncate card summaries at bounding box and +- * and apply ellipsis at lower right */ +-.ellipsis { +- overflow: hidden; +- float: right; +- line-height: 15px; +- width: 100%; } +- .ellipsis:before { +- content: ""; +- float: left; +- width: 5px; +- height: 100%; } +- .ellipsis > *:first-child.text { +- float: right; +- width: 100% !important; +- margin-left: -5px; } +- .ellipsis:after { +- content: "\02026"; +- height: 17px; +- padding-bottom: 4px; +- box-sizing: content-box; +- float: right; +- position: relative; +- top: -16px; +- left: 100%; +- width: 4em; +- margin-left: -4em; +- padding-right: 5px; +- background: -webkit-gradient(linear, left top, right top, from(rgba(255, 255, 255, 0)), to(white), color-stop(65%, white)); +- background: -webkit-linear-gradient(left, rgba(255, 255, 255, 0), white 65%, white); +- background: linear-gradient(to right, rgba(255, 255, 255, 0), white 65%, white); } +- .ellipsis:after { +- font-style: normal; +- color: #aaa; +- font-size: 13px; +- text-align: right; } +- +-.resource-card:hover { +- cursor: pointer; } +- .static .resource-card:hover { +- cursor: auto; } +- .resource-card:hover .card-bg:after { +- opacity: 0; } +- .resource-card:hover .play-button { +- opacity: .3; } +- .resource-card:hover .card-info .description .util { +- opacity: 1; } +- +-/* Carousel Layout */ +-/* Carousel styles for landing page */ +-.resource-carousel-layout { +- height: 531px; +- margin: 20px 0 20px 0; +- padding: 0 !important; +- position: relative; +- overflow: hidden; } +- .resource-carousel-layout .slideshow-prev, .resource-carousel-layout .slideshow-next { +- display: none; } +- .resource-carousel-layout .pagination { +- bottom: 97px; +- left: auto; +- padding-right: 10px; +- right: 0; +- text-align: right; +- width: 16.66666667%; } +- .resource-carousel-layout .pagination ul li { +- text-indent: 8000px; } +- .resource-carousel-layout .frame li { +- position: relative; } +- .resource-carousel-layout .frame li .card-bg { +- bottom: 131px; } +- .resource-carousel-layout .frame li .card-info { +- height: 131px; +- padding: 6px 12px; +- top: auto; } +- .resource-carousel-layout .frame li .card-info .title { +- font-size: 28px; +- font-weight: 400; +- line-height: 32px; } +- .resource-carousel-layout .frame li .card-info .description .text { +- height: 40px; } +- .resource-carousel-layout .frame li .card-info .description .util { +- bottom: 97px; +- right: 4px; } +- +-/* Stack Layout */ +-.resource-stack-layout { +- display: inline-block; +- padding: 0; } +- .resource-stack-layout .section-card-menu > .card-info .section, .resource-stack-layout .section-card > .card-info .title { +- /*text-transform: uppercase;*/ +- color: #898989; +- font-size: 17px; +- line-height: 23px; +- margin-bottom: 6px; } +- .resource-stack-layout .section-card { +- height: 284px; } +- .resource-stack-layout .section-card > .card-bg { +- height: 192px; } +- .resource-stack-layout .section-card > .card-info { +- padding: 4px 12px 6px 12px; +- top: 192px; } +- .resource-stack-layout .section-card > .card-info .section { +- display: none; } +- .resource-stack-layout .section-card > .card-info .title { +- font-size: 17px; +- border-bottom: 1px solid #959595; +- padding-bottom: 0px; } +- .resource-stack-layout .section-card > .card-info .description { +- font-size: 13px; +- line-height: 15px; } +- .resource-stack-layout .section-card > .card-info .description .text { +- height: 30px; } +- .resource-stack-layout .related-card { +- height: 90px; } +- .resource-stack-layout .related-card > .card-bg { +- left: 0; +- top: 0; +- width: 90px; +- height: 100%; +- position: absolute; +- display: block; } +- .resource-stack-layout .related-card > .card-info { +- left: 90px; +- padding: 4px 12px 4px 12px; } +- .resource-stack-layout .related-card > .card-info .section { +- font-size: 12px; +- margin-bottom: 1px; +- display: none; } +- .resource-stack-layout .related-card > .card-info .title { +- font-size: 16px; +- margin-bottom: -2px; +- white-space: normal; +- overflow: visible; +- text-overflow: ellipsis; } +- .resource-stack-layout .related-card > .card-info .title:after { +- content: url(../images/link-out.png); +- display: block; } +- .resource-stack-layout .related-card > .card-info .description { +- display: none; } +- .resource-stack-layout .section-card-menu { +- /* Flexible height */ +- display: block; +- height: auto; +- width: auto; } +- .resource-stack-layout .section-card-menu .card-bg { +- height: 155px; +- /* Flexible height */ +- position: relative; +- display: inline-block; +- vertical-align: top; } +- .resource-stack-layout .section-card-menu .card-info { +- padding: 4px 12px 0px 12px; +- /* Flexible height */ +- position: relative; +- left: auto; +- top: auto; +- right: auto; +- bottom: auto; } +- .resource-stack-layout .section-card-menu .card-info ul { +- list-style: none; +- margin: 0; } +- .resource-stack-layout .section-card-menu .card-info ul li { +- list-style: none; +- margin: 0; +- padding: 15px 0; +- border-top-width: 1px; +- border-top-style: solid; +- border-top-color: #959595; } +- .resource-stack-layout .section-card-menu .card-info ul li a, .resource-stack-layout .section-card-menu .card-info ul li a:focus, .resource-stack-layout .section-card-menu .card-info ul li a:hover { +- color: #333 !important; } +- .resource-stack-layout .section-card-menu .card-info ul li:first-child { +- border-top: none; } +- .resource-stack-layout .section-card-menu .card-info ul li:hover .title:after { +- opacity: 1; +- -webkit-transition: opacity 0.5s; +- transition: opacity 0.5s; } +- .resource-stack-layout .section-card-menu .card-info ul li:hover .description { +- max-height: 30px; +- opacity: 1; +- -webkit-transition: max-height 0.5s, opacity 1s; +- transition: max-height 0.5s, opacity 1s; } +- .resource-stack-layout .section-card-menu .card-info .title { +- font-size: 16px; +- margin-bottom: -2px; +- position: relative; } +- .resource-stack-layout .section-card-menu .card-info .title:after { +- background: url(../images/stack-arrow-right.png); +- content: ''; +- opacity: 0; +- -webkit-transition: opacity 0.25s; +- transition: opacity 0.25s; +- position: absolute; +- right: 0px; +- top: 3px; +- width: 10px; +- height: 15px; } +- .resource-stack-layout .section-card-menu .card-info .title.more { +- text-transform: uppercase; +- color: #898989; +- display: inline-block; } +- .resource-stack-layout .section-card-menu .card-info .title.more:after { +- background: url(../images/stack-arrow-right.png); +- content: ''; +- display: block; +- position: absolute; +- right: -20px; +- top: 3px; +- width: 10px; +- height: 15px; } +- .resource-stack-layout .section-card-menu .card-info .description { +- max-height: 0px; +- opacity: 0; +- overflow: hidden; +- font-size: 13px; +- line-height: 15px; +- /* Hover off */ +- -webkit-transition: max-height 0.5s, opacity 0.5s; +- transition: max-height 0.5s, opacity 0.5s; } +- .resource-stack-layout .section-card-menu .card-info .description .text { +- height: 30px; } +- .resource-stack-layout:after { +- content: "."; +- display: block; +- height: 0; +- clear: both; +- visibility: hidden; } +- +-.resource-card, .resource-card-stack { +- margin-bottom: 20px; } +- +-.resource-card-row-stack-last { +- margin-bottom: 0px !important; } +- +-.resource-card-col-stack-last { +- margin-bottom: 0px !important; } +- +-.resource-card-3x6 { +- height: 300px; } +- +-.resource-card-3x12 { +- height: 620px; } +- +-.resource-card-3x18 { +- height: 940px; } +- +-.resource-card-6x6 { +- height: 300px; } +- +-.resource-card-6x12 { +- height: 620px; } +- +-.resource-card-6x18 { +- height: 940px; } +- +-.resource-card-9x6 { +- height: 300px; } +- +-.resource-card-9x12 { +- height: 620px; } +- +-.resource-card-9x18 { +- height: 940px; } +- +-.resource-card-12x6 { +- height: 300px; } +- +-.resource-card-12x12 { +- height: 620px; } +- +-.resource-card-12x18 { +- height: 940px; } +- +-.resource-card-15x6 { +- height: 300px; } +- +-.resource-card-15x12 { +- height: 620px; } +- +-.resource-card-15x18 { +- height: 940px; } +- +-.resource-card-18x6 { +- height: 300px; } +- +-.resource-card-18x12 { +- height: 620px; } +- +-.resource-card-18x18 { +- height: 940px; } +- +-.resource-card-3x2 { +- height: 100px; } +- +-.resource-card-3x2x3 { +- height: 90px; +- margin-bottom: 15px; } +- +-.resource-card-3x3 { +- height: 150px; } +- +-.resource-card-3x3x2 { +- height: 142px; +- margin-bottom: 16px; } +- +-.resource-card-6x2 { +- height: 100px; } +- +-.resource-card-6x2x3 { +- height: 90px; +- margin-bottom: 15px; } +- +-.resource-card-6x3 { +- height: 150px; } +- +-.resource-card-6x3x2 { +- height: 142px; +- margin-bottom: 16px; } +- +-.resource-card-9x2 { +- height: 100px; } +- +-.resource-card-9x2x3 { +- height: 90px; +- margin-bottom: 15px; } +- +-.resource-card-9x3 { +- height: 150px; } +- +-.resource-card-9x3x2 { +- height: 142px; +- margin-bottom: 16px; } +- +-.resource-card-12x2 { +- height: 100px; } +- +-.resource-card-12x2x3 { +- height: 90px; +- margin-bottom: 15px; } +- +-.resource-card-12x3 { +- height: 150px; } +- +-.resource-card-12x3x2 { +- height: 142px; +- margin-bottom: 16px; } +- +-.resource-card-15x2 { +- height: 100px; } +- +-.resource-card-15x2x3 { +- height: 90px; +- margin-bottom: 15px; } +- +-.resource-card-15x3 { +- height: 150px; } +- +-.resource-card-15x3x2 { +- height: 142px; +- margin-bottom: 16px; } +- +-.resource-card-18x2 { +- height: 100px; } +- +-.resource-card-18x2x3 { +- height: 90px; +- margin-bottom: 15px; } +- +-.resource-card-18x3 { +- height: 150px; } +- +-.resource-card-18x3x2 { +- height: 142px; +- margin-bottom: 16px; } +- +-/* +- The following are styles for cards in the flowlayout above, styled by the number of rows they span +-*/ +-/* Single row, 2 column items. */ +-.resource-card-9x6 { +- height: 390px; } +- +-/* Double row, 1 column items. Eg full width video thumbnails. */ +-.resource-card-18x12 { +- height: 558px; } +- +-/* 1/3 row items */ +-.resource-card-3x2 > .card-bg, +-.resource-card-6x2 > .card-bg, +-.resource-card-9x2 > .card-bg, +-.resource-card-12x2 > .card-bg, +-.resource-card-15x2 > .card-bg, +-.resource-card-18x2 > .card-bg { +- left: 0; +- top: 0; +- width: 90px; +- height: 100%; +- position: absolute; +- display: block; +-} +- +-.resource-card-3x2 > .card-info, .resource-card-6x2 > .card-info, .resource-card-9x2 > .card-info, .resource-card-12x2 > .card-info, .resource-card-15x2 > .card-info, .resource-card-18x2 > .card-info { +- height: 100%; +- left: 90px; +- padding: 6px 12px; +- overflow: hidden; +-} +- +-.resource-card-3x2 > .card-info .title, +-.resource-card-6x2 > .card-info .title, +-.resource-card-9x2 > .card-info .title, +-.resource-card-12x2 > .card-info .title, +-.resource-card-15x2 > .card-info .title, +-.resource-card-18x2 > .card-info .title { +- max-height: 69px; +- white-space: normal; +-} +- +-.resource-card-3x2 > .card-info .description, +-.resource-card-6x2 > .card-info .description, +-.resource-card-9x2 > .card-info .description, +-.resource-card-12x2 > .card-info .description, +-.resource-card-15x2 > .card-info .description, +-.resource-card-18x2 > .card-info .description { +- display: none; +-} +- +-.resource-card-3x2 > .card-info .text, +-.resource-card-6x2 > .card-info .text, +-.resource-card-9x2 > .card-info .text, +-.resource-card-12x2 > .card-info .text, +-.resource-card-15x2 > .card-info .text, +-.resource-card-18x2 > .card-info .text { +- height: auto; +-} +- +-/* Override to show the description instead of the content section */ +-.no-section .resource-card-3x2 > .card-info .section, +-.no-section .resource-card-6x2 > .card-info .section { +- display: none; } +- +-.no-section .resource-card-3x2 > .card-info .description, +-.no-section .resource-card-6x2 > .card-info .description { +- display: block; } +- +-/* 1/2 row items */ +-.resource-card-3x3, .resource-card-6x3, .resource-card-9x3, .resource-card-12x3, .resource-card-15x3, .resource-card-18x3 { +- height: 160px; } +- .resource-card-3x3 > .card-bg, .resource-card-6x3 > .card-bg, .resource-card-9x3 > .card-bg, .resource-card-12x3 > .card-bg, .resource-card-15x3 > .card-bg, .resource-card-18x3 > .card-bg { +- left: 0; +- top: 0; +- width: 90px; +- height: 100%; +- position: absolute; +- display: block; } +- .resource-card-3x3 > .card-info, .resource-card-6x3 > .card-info, .resource-card-9x3 > .card-info, .resource-card-12x3 > .card-info, .resource-card-15x3 > .card-info, .resource-card-18x3 > .card-info { +- height: 100%; +- left: 90px; +- padding: 6px 12px; } +- .resource-card-3x3 > .card-info .section, .resource-card-6x3 > .card-info .section, .resource-card-9x3 > .card-info .section, .resource-card-12x3 > .card-info .section, .resource-card-15x3 > .card-info .section, .resource-card-18x3 > .card-info .section { +- display: none; } +- .resource-card-3x3 > .card-info .title, .resource-card-6x3 > .card-info .title, .resource-card-9x3 > .card-info .title, .resource-card-12x3 > .card-info .title, .resource-card-15x3 > .card-info .title, .resource-card-18x3 > .card-info .title { +- max-height: 92px; +- white-space: normal; } +- .resource-card-3x3 > .card-info .text, .resource-card-6x3 > .card-info .text, .resource-card-9x3 > .card-info .text, .resource-card-12x3 > .card-info .text, .resource-card-15x3 > .card-info .text, .resource-card-18x3 > .card-info .text { +- height: auto; } +- .resource-card-3x3 > .card-info .util, .resource-card-6x3 > .card-info .util, .resource-card-9x3 > .card-info .util, .resource-card-12x3 > .card-info .util, .resource-card-15x3 > .card-info .util, .resource-card-18x3 > .card-info .util { +- display: none; } +- +-/* placement of plusone */ +-.resource-card-6x12 > .card-info .description .util, .resource-card-9x12 > .card-info .description .util, .resource-card-12x12 > .card-info .description .util, .resource-card-15x12 > .card-info .description .util { +- bottom: 2px; } +- +-.resource-card-18x12 > .card-info .description .util { +- bottom: 2px; } +- +-/* Overrides for col-16 6x6 cards linking to local content on landing pages. +- Suppresses "section". */ +-.landing .card-info .section { +- display: none; } +- +-/* +- Generate a resource stack layout for a 3 column widget spanning 16 grid cols +-*/ +-.resource-stack-layout.col-16 { +- margin: 0 -14px 0 0; +- width: 954px; } +- .resource-stack-layout.col-16 .resource-card-stack { +- margin: 0 14px 0 0; +- width: 304px; } +- +-/* Example of card menu tinting */ +-.resource-widget[data-section=distribute\/tools] .section-card-menu .card-bg:after { +- background: rgba(126, 55, 148, 0.4) !important; } +- +-.resource-widget[data-section=distribute\/tools] .section-card-menu .card-section-icon .icon { +- background-color: #7e3794 !important; } +- +-.resource-widget[data-section=distribute\/tools] .section-card-menu .card-info ul li { +- border-top-color: #7e3794 !important; } +- +-/* tinting for stacks */ +-div.jd-descr > .resource-widget[data-section=distribute\/tools] +-.section-card-menu .card-info ul li { +- border-top-color: #7e3794 !important; } +- +-/* Show more/less */ +-.dac-show-more, +-.dac-show-less { +- display: none !important; } +- +-.dac-has-more .dac-show-more { +- display: inline-block !important; } +- +-.dac-has-less .dac-show-less { +- display: inline-block !important; } +- +-.dac-fab, .dac-button-social, .button, .landing-button, +-.dac-button { +- background: transparent; +- border: 0; +- border-radius: 3px; +- box-sizing: border-box; +- color: currentColor; +- cursor: pointer; +- display: inline-block; +- font-weight: 500; +- font-size: 14px; +- font-style: inherit; +- font-variant: inherit; +- font-family: inherit; +- letter-spacing: .5px; +- line-height: 24px; +- margin: 6px 16px 6px 0; +- min-width: 88px; +- outline: 0; +- padding: 6px 12px; +- position: relative; +- text-align: center; +- text-decoration: none; +- text-transform: uppercase; +- -webkit-transition: box-shadow 0.4s cubic-bezier(0.25, 0.8, 0.25, 1), background-color 0.4s cubic-bezier(0.25, 0.8, 0.25, 1); +- transition: box-shadow 0.4s cubic-bezier(0.25, 0.8, 0.25, 1), background-color 0.4s cubic-bezier(0.25, 0.8, 0.25, 1); +- -webkit-user-select: none; +- -moz-user-select: none; +- -ms-user-select: none; +- user-select: none; +- white-space: nowrap; } +- +-.button, .landing-button, +-.dac-button.dac-raised { +- background-color: #FAFAFA; +- box-shadow: 0 2px 5px rgba(0, 0, 0, 0.26); } +- +-.dac-button.dac-raised.dac-primary, .landing-secondary, .button { +- background-color: #039bef; } +- .dac-button.dac-raised.dac-primary:hover, .landing-secondary:hover, .button:hover { +- background-color: #0288d1; } +- .dac-button.dac-raised.dac-primary:active, .landing-secondary:active, .button:active { +- background-color: #0277bd; } +- .dac-button.dac-raised.dac-primary.disabled, .button.disabled { +- background-color: #bbb; } +- +-.dac-button.dac-raised.dac-red, .landing-primary { +- background-color: #bf3722; } +- .dac-button.dac-raised.dac-red:hover, .landing-primary:hover { +- background-color: #9c2d1c; } +- .dac-button.dac-raised.dac-red:active, .landing-primary:active { +- background-color: #822517; } +- +-.dac-button.dac-raised.dac-green, .landing-button.green { +- background-color: #90c653; } +- .dac-button.dac-raised.dac-green:hover, .landing-button.green:hover { +- background-color: #79b03b; } +- .dac-button.dac-raised.dac-green:active, .landing-button.green:active { +- background-color: #699933; } +- +-.dac-button.dac-raised.dac-primary, .landing-secondary, .button, +-.dac-button.dac-raised.dac-red, +-.landing-primary, +-.dac-button.dac-raised.dac-green, +-.landing-button.green { +- color: #fff; } +- +-.dac-button.dac-large, .landing-button { +- padding: 12px 24px; } +- +-.landing-button-wrap { +- float: left; +- margin-right: 40px; +- width: auto; +-} +- +-.dac-fab, .dac-button-social { +- background: #fff; +- box-shadow: 0 2px 5px rgba(0, 0, 0, 0.26); +- border-radius: 50%; +- height: 36px; +- line-height: 36px; +- margin: 0; +- min-width: 0; +- overflow: hidden; +- padding: 0; +- vertical-align: middle; +- width: 36px; } +- .dac-fab:hover, .dac-button-social:hover, +- a:hover > .dac-fab, +- a:hover > .dac-button-social { +- box-shadow: 0 3px 8px rgba(0, 0, 0, 0.26); } +- .dac-fab > .dac-sprite, .dac-button-social > .dac-sprite, .dac-fab > .dac-modal-header-close:before, .dac-button-social > .dac-modal-header-close:before, .paging-links .dac-fab > .prev-page-link:before, .paging-links .dac-button-social > .prev-page-link:before, .paging-links .dac-fab > .next-page-link:before, .paging-links .dac-button-social > .next-page-link:before, .paging-links .dac-fab > .next-class-link:before, .paging-links .dac-button-social > .next-class-link:before, .paging-links .dac-fab > .start-class-link:after, .paging-links .dac-button-social > .start-class-link:after { +- margin-top: -2px; } +- .dac-fab.dac-primary, .dac-primary.dac-button-social { +- background: #00c7a0; } +- .dac-fab.dac-large, .dac-large.dac-button-social { +- height: 54px; +- line-height: 54px; +- width: 54px; } +- +-.dac-button-social { +- background: #ccc; +- box-shadow: none; +- position: relative; +- overflow: hidden; } +- .dac-button-social::after { +- background: rgba(0, 0, 0, 0.2); +- border-radius: 50%; +- bottom: 0; +- content: ''; +- display: block; +- left: 0; +- opacity: 0; +- position: absolute; +- right: 0; +- top: 0; +- -webkit-transition: opacity .3s; +- transition: opacity .3s; } +- .dac-button-social:hover { +- box-shadow: none; } +- .dac-button-social:active::after { +- opacity: 1; } +- .dac-button-social:focus.dac-rss, .dac-button-social:hover.dac-rss { +- background: #ff9800; } +- .dac-button-social:focus.dac-youtube, .dac-button-social:hover.dac-youtube { +- background: #f44336; } +- .dac-button-social:focus.dac-gplus, .dac-button-social:hover.dac-gplus { +- background: #f44336; } +- .dac-button-social:focus.dac-twitter, .dac-button-social:hover.dac-twitter { +- background: #55acee; } +- +-.dac-action { +- display: inline-block; +- margin: 0 16px; } +- .dac-action-link { +- color: inherit; +- font-size: 24px; +- font-weight: 300; +- line-height: 50px; +- -webkit-transition: opacity .3s; +- transition: opacity .3s; } +- .dac-action-link:hover { +- color: inherit; +- opacity: .54; } +- .dac-action-sprite { +- margin-left: -12px; +- margin-right: -8px; } +- .dac-actions { +- list-style-type: none; +- margin: 0; +- padding-bottom: 24px; +- padding-top: 24px; +- text-align: center; } +- @media (max-width: 719px) { +- .dac-actions { +- text-align: left; } } +- @media (max-width: 719px) { +- .dac-action { +- display: block; +- margin: 0; } } +- +-.dac-scroll-button { +- height: 54px; +- line-height: 54px; +- margin: 0; +- position: absolute; +- right: 0; +- top: -27px; +- width: 54px; +- z-index: 1; } +- @media (max-width: 719px) { +- .dac-scroll-button { +- display: none; } } +- +-/* Footer component */ +-.dac-footer { +- background-color: #fff; +- border-top: 1px solid #f0f0f0; +- clear: both; +- color: #999; +- font-size: 12px; +- margin-top: 96px; +- padding-bottom: 20px; +- position: relative; +-} +- +-.dac-footer a { +- color: #999; +-} +- +-.dac-footer p { +- margin: 7px 0 0; +-} +- +-.dac-footer-main { +- padding: 30px 0; +-} +- +-.dac-footer-reachout { +- text-align: right; +-} +- +-.dac-footer-contact, +-.dac-footer-social { +- display: inline-block; +-} +- +-.dac-footer .dac-footer-getnews, +-.dac-footer .dac-footer-contact-link { +- color: #000; +- cursor: pointer; +- font-size: 20px; +- font-weight: 300; +- margin: 8px 0; +- vertical-align: middle; +-} +- +-.dac-footer .dac-footer-contact-link, +-.dac-footer .dac-footer-social-link { +- margin-left: 16px; +- margin-right: 0; +-} +- +-.dac-footer-getnews > .dac-fab, .dac-footer-getnews > .dac-button-social { +- margin-left: 4px; +-} +- +-.dac-footer-separator { +- background: #f0f0f0; +- margin: 0 0 12px; +-} +- +-.dac-footer-links { +- float: left; +- margin: 10px 0 60px; +- width: 50%; +-} +- +-.dac-footer-links a + a:before { +- content: '|'; +- cursor: default; +- margin: 0 10px 0 8px; +-} +- +-.devsite-utility-footer-language { +- float: right; +- margin: 10px 0 60px; +- width: 50%; +-} +- +-.dac-footer .locales { +- float: right; +- margin: 0; +-} +- +-.dac-footer .locales select { +- background-color: #f0f0f0; +- border-radius: 3px; +- font-size: 12px; +- height: auto; +- margin-top: -2px; +- padding: 8px 12px; +- width: 146px; +-} +- +-.dac-footer.dac-landing { +- margin-top: 0; +- border-top: 0; +-} +- +-@media (max-width: 719px) { +- .dac-footer-reachout { +- text-align: left; +- } +- +- .dac-footer-social { +- display: block; +- } +- +- .dac-footer-social-link, +- .dac-footer-contact-link { +- display: inline-block; +- } +- +- .dac-footer .dac-footer-contact-link, +- .dac-footer .dac-footer-social-link { +- margin-left: 0; +- margin-right: 16px; +- } +- +- .dac-footer-links { +- display: block; +- float: none; +- width: 100%; +- } +- +- .devsite-utility-footer-language { +- float: none; +- margin: 0 0 20px; +- width: 100%; +- } +- +- .dac-footer .locales { +- display: block; +- float: none; +- margin-top: 15px; +- } +-} +- +-/* ============================================================================= +- Columns +- ========================================================================== */ +-.wrap { +- margin: 0 auto; +- max-width: 940px; +- clear: both; +-} +- +-.dac-fullscreen-mode .wrap { +- max-width: none; +-} +- +-.dac-fullscreen-mode .dac-search-open .wrap { +- max-width: 940px; +-} +- +-.cols { +- margin-left: -10px; +- margin-right: -10px; +- /** +- * For modern browsers +- * 1. The space content is one way to avoid an Opera bug when the +- * contenteditable attribute is included anywhere else in the document. +- * Otherwise it causes space to appear at the top and bottom of elements +- * that are clearfixed. +- * 2. The use of `table` rather than `block` is only necessary if using +- * `:before` to contain the top-margins of child elements. +- */ } +- .cols:before, .cols:after { +- content: ' '; +- /* 1 */ +- display: table; +- /* 2 */ } +- .cols:after { +- clear: both; } +- +-[class*=col-] { +- box-sizing: border-box; +- float: left; +- min-height: 1px; +- padding-left: 10px; +- padding-right: 10px; +- position: relative; } +- +-.col-1 { +- width: 6.25%; } +- +-.col-2 { +- width: 12.5%; } +- +-.col-3 { +- width: 18.75%; } +- +-.col-4 { +- width: 25%; } +- +-.col-5 { +- width: 31.25%; } +- +-.col-6 { +- width: 37.5%; } +- +-.col-7 { +- width: 43.75%; } +- +-.col-8 { +- width: 50%; } +- +-.col-9 { +- width: 56.25%; } +- +-.col-10 { +- width: 62.5%; } +- +-.col-11 { +- width: 68.75%; } +- +-.col-12 { +- width: 75%; } +- +-.col-13 { +- width: 81.25%; } +- +-.col-14 { +- width: 87.5%; } +- +-.col-15 { +- width: 93.75%; } +- +-.col-16 { +- width: 100%; } +- +-.col-13 .col-1 { +- width: 7.69230769%; } +- +-.col-13 .col-2 { +- width: 15.38461538%; } +- +-.col-13 .col-3 { +- width: 23.07692308%; } +- +-.col-13 .col-4 { +- width: 30.76923077%; } +- +-.col-13 .col-5 { +- width: 38.46153846%; } +- +-.col-13 .col-6 { +- width: 46.15384615%; } +- +-.col-13 .col-7 { +- width: 53.84615385%; } +- +-.col-13 .col-8 { +- width: 61.53846154%; } +- +-.col-13 .col-9 { +- width: 69.23076923%; } +- +-.col-13 .col-10 { +- width: 76.92307692%; } +- +-.col-13 .col-11 { +- width: 84.61538462%; } +- +-.col-13 .col-12 { +- width: 92.30769231%; } +- +-.col-13 .col-13 { +- width: 100%; } +- +-.col-12 .col-1 { +- width: 8.33333333%; } +- +-.col-12 .col-2 { +- width: 16.66666667%; } +- +-.col-12 .col-3 { +- width: 25%; } +- +-.col-12 .col-4 { +- width: 33.33333333%; } +- +-.col-12 .col-5 { +- width: 41.66666667%; } +- +-.col-12 .col-6 { +- width: 50%; } +- +-.col-12 .col-7 { +- width: 58.33333333%; } +- +-.col-12 .col-8 { +- width: 66.66666667%; } +- +-.col-12 .col-9 { +- width: 75%; } +- +-.col-12 .col-10 { +- width: 83.33333333%; } +- +-.col-12 .col-11 { +- width: 91.66666667%; } +- +-.col-12 .col-12 { +- width: 100%; } +- +-.col-1of1, .col-2of2, .col-3of3, .col-4of4, .col-5of5, .col-6of6, .col-8of8, .col-10of10, .col-12of12, .col-16of16 { +- width: 100%; } +- +-.col-1of2, .col-2of4, .col-3of6, .col-4of8, .col-5of10, .col-6of12, .col-8of16 { +- width: 50%; } +- +-.col-1of3, .col-2of6, .col-4of12 { +- width: 33.33333333%; } +- +-.col-2of3, .col-4of6, .col-8of12 { +- width: 66.66666667%; } +- +-.col-1of4, .col-2of8, .col-3of12, .col-4of16 { +- width: 25%; } +- +-.col-3of4, .col-6of8, .col-9of12, .col-12of16 { +- width: 75%; } +- +-.col-1of5, .col-2of10 { +- width: 20%; } +- +-.col-2of5, .col-4of10 { +- width: 40%; } +- +-.col-3of5, .col-6of10 { +- width: 60%; } +- +-.col-4of5, .col-8of10 { +- width: 80%; } +- +-.col-1of6, .col-2of12 { +- width: 16.66666667%; } +- +-.col-5of6, .col-10of12 { +- width: 83.33333333%; } +- +-.col-1of8, .col-2of16 { +- width: 12.5%; } +- +-.col-3of8, .col-6of16 { +- width: 37.5%; } +- +-.col-5of8, .col-10of16 { +- width: 62.5%; } +- +-.col-7of8, .col-14of16 { +- width: 87.5%; } +- +-.col-1of10 { +- width: 10%; } +- +-.col-3of10 { +- width: 30%; } +- +-.col-7of10 { +- width: 70%; } +- +-.col-9of10 { +- width: 90%; } +- +-.col-1of12 { +- width: 8.33333333%; } +- +-.col-5of12 { +- width: 41.66666667%; } +- +-.col-7of12 { +- width: 58.33333333%; } +- +-.col-11of12 { +- width: 91.66666667%; } +- +-.col-1of16 { +- width: 6.25%; } +- +-.col-3of16 { +- width: 18.75%; } +- +-.col-5of16 { +- width: 31.25%; } +- +-.col-7of16 { +- width: 43.75%; } +- +-.col-9of16 { +- width: 56.25%; } +- +-.col-11of16 { +- width: 68.75%; } +- +-.col-13of16 { +- width: 81.25%; } +- +-.col-15of16 { +- width: 93.75%; } +- +-.col-pull-1of1, .col-pull-2of2, .col-pull-3of3, .col-pull-4of4, .col-pull-5of5, .col-pull-6of6, .col-pull-8of8, .col-pull-10of10, .col-pull-12of12, .col-pull-16of16 { +- left: -100%; } +- +-.col-pull-1of2, .col-pull-2of4, .col-pull-3of6, .col-pull-4of8, .col-pull-5of10, .col-pull-6of12, .col-pull-8of16 { +- left: -50%; } +- +-.col-pull-1of3, .col-pull-2of6, .col-pull-4of12 { +- left: -33.33333333%; } +- +-.col-pull-2of3, .col-pull-4of6, .col-pull-8of12 { +- left: -66.66666667%; } +- +-.col-pull-1of4, .col-pull-2of8, .col-pull-3of12, .col-pull-4of16 { +- left: -25%; } +- +-.col-pull-3of4, .col-pull-6of8, .col-pull-9of12, .col-pull-12of16 { +- left: -75%; } +- +-.col-pull-1of5, .col-pull-2of10 { +- left: -20%; } +- +-.col-pull-2of5, .col-pull-4of10 { +- left: -40%; } +- +-.col-pull-3of5, .col-pull-6of10 { +- left: -60%; } +- +-.col-pull-4of5, .col-pull-8of10 { +- left: -80%; } +- +-.col-pull-1of6, .col-pull-2of12 { +- left: -16.66666667%; } +- +-.col-pull-5of6, .col-pull-10of12 { +- left: -83.33333333%; } +- +-.col-pull-1of8, .col-pull-2of16 { +- left: -12.5%; } +- +-.col-pull-3of8, .col-pull-6of16 { +- left: -37.5%; } +- +-.col-pull-5of8, .col-pull-10of16 { +- left: -62.5%; } +- +-.col-pull-7of8, .col-pull-14of16 { +- left: -87.5%; } +- +-.col-pull-1of10 { +- left: -10%; } +- +-.col-pull-3of10 { +- left: -30%; } +- +-.col-pull-7of10 { +- left: -70%; } +- +-.col-pull-9of10 { +- left: -90%; } +- +-.col-pull-1of12 { +- left: -8.33333333%; } +- +-.col-pull-5of12 { +- left: -41.66666667%; } +- +-.col-pull-7of12 { +- left: -58.33333333%; } +- +-.col-pull-11of12 { +- left: -91.66666667%; } +- +-.col-pull-1of16 { +- left: -6.25%; } +- +-.col-pull-3of16 { +- left: -18.75%; } +- +-.col-pull-5of16 { +- left: -31.25%; } +- +-.col-pull-7of16 { +- left: -43.75%; } +- +-.col-pull-9of16 { +- left: -56.25%; } +- +-.col-pull-11of16 { +- left: -68.75%; } +- +-.col-pull-13of16 { +- left: -81.25%; } +- +-.col-pull-15of16 { +- left: -93.75%; } +- +-.col-push-1of1, .col-push-2of2, .col-push-3of3, .col-push-4of4, .col-push-5of5, .col-push-6of6, .col-push-8of8, .col-push-10of10, .col-push-12of12, .col-push-16of16 { +- left: 100%; } +- +-.col-push-1of2, .col-push-2of4, .col-push-3of6, .col-push-4of8, .col-push-5of10, .col-push-6of12, .col-push-8of16 { +- left: 50%; } +- +-.col-push-1of3, .col-push-2of6, .col-push-4of12 { +- left: 33.33333333%; } +- +-.col-push-2of3, .col-push-4of6, .col-push-8of12 { +- left: 66.66666667%; } +- +-.col-push-1of4, .col-push-2of8, .col-push-3of12, .col-push-4of16 { +- left: 25%; } +- +-.col-push-3of4, .col-push-6of8, .col-push-9of12, .col-push-12of16 { +- left: 75%; } +- +-.col-push-1of5, .col-push-2of10 { +- left: 20%; } +- +-.col-push-2of5, .col-push-4of10 { +- left: 40%; } +- +-.col-push-3of5, .col-push-6of10 { +- left: 60%; } +- +-.col-push-4of5, .col-push-8of10 { +- left: 80%; } +- +-.col-push-1of6, .col-push-2of12 { +- left: 16.66666667%; } +- +-.col-push-5of6, .col-push-10of12 { +- left: 83.33333333%; } +- +-.col-push-1of8, .col-push-2of16 { +- left: 12.5%; } +- +-.col-push-3of8, .col-push-6of16 { +- left: 37.5%; } +- +-.col-push-5of8, .col-push-10of16 { +- left: 62.5%; } +- +-.col-push-7of8, .col-push-14of16 { +- left: 87.5%; } +- +-.col-push-1of10 { +- left: 10%; } +- +-.col-push-3of10 { +- left: 30%; } +- +-.col-push-7of10 { +- left: 70%; } +- +-.col-push-9of10 { +- left: 90%; } +- +-.col-push-1of12 { +- left: 8.33333333%; } +- +-.col-push-5of12 { +- left: 41.66666667%; } +- +-.col-push-7of12 { +- left: 58.33333333%; } +- +-.col-push-11of12 { +- left: 91.66666667%; } +- +-.col-push-1of16 { +- left: 6.25%; } +- +-.col-push-3of16 { +- left: 18.75%; } +- +-.col-push-5of16 { +- left: 31.25%; } +- +-.col-push-7of16 { +- left: 43.75%; } +- +-.col-push-9of16 { +- left: 56.25%; } +- +-.col-push-11of16 { +- left: 68.75%; } +- +-.col-push-13of16 { +- left: 81.25%; } +- +-.col-push-15of16 { +- left: 93.75%; } +- +-@media (max-width: 959px) and (min-width: 720px) { +- .col-tablet-1of1, .col-tablet-2of2, .col-tablet-3of3, .col-tablet-4of4, .col-tablet-5of5, .col-tablet-6of6, .col-tablet-8of8, .col-tablet-10of10, .col-tablet-12of12, .col-tablet-16of16 { +- width: 100%; } +- .col-tablet-1of2, .col-tablet-2of4, .col-tablet-3of6, .col-tablet-4of8, .col-tablet-5of10, .col-tablet-6of12, .col-tablet-8of16 { +- width: 50%; } +- .col-tablet-1of3, .col-tablet-2of6, .col-tablet-4of12 { +- width: 33.33333333%; } +- .col-tablet-2of3, .col-tablet-4of6, .col-tablet-8of12 { +- width: 66.66666667%; } +- .col-tablet-1of4, .col-tablet-2of8, .col-tablet-3of12, .col-tablet-4of16 { +- width: 25%; } +- .col-tablet-3of4, .col-tablet-6of8, .col-tablet-9of12, .col-tablet-12of16 { +- width: 75%; } +- .col-tablet-1of5, .col-tablet-2of10 { +- width: 20%; } +- .col-tablet-2of5, .col-tablet-4of10 { +- width: 40%; } +- .col-tablet-3of5, .col-tablet-6of10 { +- width: 60%; } +- .col-tablet-4of5, .col-tablet-8of10 { +- width: 80%; } +- .col-tablet-1of6, .col-tablet-2of12 { +- width: 16.66666667%; } +- .col-tablet-5of6, .col-tablet-10of12 { +- width: 83.33333333%; } +- .col-tablet-1of8, .col-tablet-2of16 { +- width: 12.5%; } +- .col-tablet-3of8, .col-tablet-6of16 { +- width: 37.5%; } +- .col-tablet-5of8, .col-tablet-10of16 { +- width: 62.5%; } +- .col-tablet-7of8, .col-tablet-14of16 { +- width: 87.5%; } +- .col-tablet-1of10 { +- width: 10%; } +- .col-tablet-3of10 { +- width: 30%; } +- .col-tablet-7of10 { +- width: 70%; } +- .col-tablet-9of10 { +- width: 90%; } +- .col-tablet-1of12 { +- width: 8.33333333%; } +- .col-tablet-5of12 { +- width: 41.66666667%; } +- .col-tablet-7of12 { +- width: 58.33333333%; } +- .col-tablet-11of12 { +- width: 91.66666667%; } +- .col-tablet-1of16 { +- width: 6.25%; } +- .col-tablet-3of16 { +- width: 18.75%; } +- .col-tablet-5of16 { +- width: 31.25%; } +- .col-tablet-7of16 { +- width: 43.75%; } +- .col-tablet-9of16 { +- width: 56.25%; } +- .col-tablet-11of16 { +- width: 68.75%; } +- .col-tablet-13of16 { +- width: 81.25%; } +- .col-tablet-15of16 { +- width: 93.75%; } +- .col-tablet-pull-1of1, .col-tablet-pull-2of2, .col-tablet-pull-3of3, .col-tablet-pull-4of4, .col-tablet-pull-5of5, .col-tablet-pull-6of6, .col-tablet-pull-8of8, .col-tablet-pull-10of10, .col-tablet-pull-12of12, .col-tablet-pull-16of16 { +- left: -100%; } +- .col-tablet-pull-1of2, .col-tablet-pull-2of4, .col-tablet-pull-3of6, .col-tablet-pull-4of8, .col-tablet-pull-5of10, .col-tablet-pull-6of12, .col-tablet-pull-8of16 { +- left: -50%; } +- .col-tablet-pull-1of3, .col-tablet-pull-2of6, .col-tablet-pull-4of12 { +- left: -33.33333333%; } +- .col-tablet-pull-2of3, .col-tablet-pull-4of6, .col-tablet-pull-8of12 { +- left: -66.66666667%; } +- .col-tablet-pull-1of4, .col-tablet-pull-2of8, .col-tablet-pull-3of12, .col-tablet-pull-4of16 { +- left: -25%; } +- .col-tablet-pull-3of4, .col-tablet-pull-6of8, .col-tablet-pull-9of12, .col-tablet-pull-12of16 { +- left: -75%; } +- .col-tablet-pull-1of5, .col-tablet-pull-2of10 { +- left: -20%; } +- .col-tablet-pull-2of5, .col-tablet-pull-4of10 { +- left: -40%; } +- .col-tablet-pull-3of5, .col-tablet-pull-6of10 { +- left: -60%; } +- .col-tablet-pull-4of5, .col-tablet-pull-8of10 { +- left: -80%; } +- .col-tablet-pull-1of6, .col-tablet-pull-2of12 { +- left: -16.66666667%; } +- .col-tablet-pull-5of6, .col-tablet-pull-10of12 { +- left: -83.33333333%; } +- .col-tablet-pull-1of8, .col-tablet-pull-2of16 { +- left: -12.5%; } +- .col-tablet-pull-3of8, .col-tablet-pull-6of16 { +- left: -37.5%; } +- .col-tablet-pull-5of8, .col-tablet-pull-10of16 { +- left: -62.5%; } +- .col-tablet-pull-7of8, .col-tablet-pull-14of16 { +- left: -87.5%; } +- .col-tablet-pull-1of10 { +- left: -10%; } +- .col-tablet-pull-3of10 { +- left: -30%; } +- .col-tablet-pull-7of10 { +- left: -70%; } +- .col-tablet-pull-9of10 { +- left: -90%; } +- .col-tablet-pull-1of12 { +- left: -8.33333333%; } +- .col-tablet-pull-5of12 { +- left: -41.66666667%; } +- .col-tablet-pull-7of12 { +- left: -58.33333333%; } +- .col-tablet-pull-11of12 { +- left: -91.66666667%; } +- .col-tablet-pull-1of16 { +- left: -6.25%; } +- .col-tablet-pull-3of16 { +- left: -18.75%; } +- .col-tablet-pull-5of16 { +- left: -31.25%; } +- .col-tablet-pull-7of16 { +- left: -43.75%; } +- .col-tablet-pull-9of16 { +- left: -56.25%; } +- .col-tablet-pull-11of16 { +- left: -68.75%; } +- .col-tablet-pull-13of16 { +- left: -81.25%; } +- .col-tablet-pull-15of16 { +- left: -93.75%; } +- .col-tablet-push-1of1, .col-tablet-push-2of2, .col-tablet-push-3of3, .col-tablet-push-4of4, .col-tablet-push-5of5, .col-tablet-push-6of6, .col-tablet-push-8of8, .col-tablet-push-10of10, .col-tablet-push-12of12, .col-tablet-push-16of16 { +- left: 100%; } +- .col-tablet-push-1of2, .col-tablet-push-2of4, .col-tablet-push-3of6, .col-tablet-push-4of8, .col-tablet-push-5of10, .col-tablet-push-6of12, .col-tablet-push-8of16 { +- left: 50%; } +- .col-tablet-push-1of3, .col-tablet-push-2of6, .col-tablet-push-4of12 { +- left: 33.33333333%; } +- .col-tablet-push-2of3, .col-tablet-push-4of6, .col-tablet-push-8of12 { +- left: 66.66666667%; } +- .col-tablet-push-1of4, .col-tablet-push-2of8, .col-tablet-push-3of12, .col-tablet-push-4of16 { +- left: 25%; } +- .col-tablet-push-3of4, .col-tablet-push-6of8, .col-tablet-push-9of12, .col-tablet-push-12of16 { +- left: 75%; } +- .col-tablet-push-1of5, .col-tablet-push-2of10 { +- left: 20%; } +- .col-tablet-push-2of5, .col-tablet-push-4of10 { +- left: 40%; } +- .col-tablet-push-3of5, .col-tablet-push-6of10 { +- left: 60%; } +- .col-tablet-push-4of5, .col-tablet-push-8of10 { +- left: 80%; } +- .col-tablet-push-1of6, .col-tablet-push-2of12 { +- left: 16.66666667%; } +- .col-tablet-push-5of6, .col-tablet-push-10of12 { +- left: 83.33333333%; } +- .col-tablet-push-1of8, .col-tablet-push-2of16 { +- left: 12.5%; } +- .col-tablet-push-3of8, .col-tablet-push-6of16 { +- left: 37.5%; } +- .col-tablet-push-5of8, .col-tablet-push-10of16 { +- left: 62.5%; } +- .col-tablet-push-7of8, .col-tablet-push-14of16 { +- left: 87.5%; } +- .col-tablet-push-1of10 { +- left: 10%; } +- .col-tablet-push-3of10 { +- left: 30%; } +- .col-tablet-push-7of10 { +- left: 70%; } +- .col-tablet-push-9of10 { +- left: 90%; } +- .col-tablet-push-1of12 { +- left: 8.33333333%; } +- .col-tablet-push-5of12 { +- left: 41.66666667%; } +- .col-tablet-push-7of12 { +- left: 58.33333333%; } +- .col-tablet-push-11of12 { +- left: 91.66666667%; } +- .col-tablet-push-1of16 { +- left: 6.25%; } +- .col-tablet-push-3of16 { +- left: 18.75%; } +- .col-tablet-push-5of16 { +- left: 31.25%; } +- .col-tablet-push-7of16 { +- left: 43.75%; } +- .col-tablet-push-9of16 { +- left: 56.25%; } +- .col-tablet-push-11of16 { +- left: 68.75%; } +- .col-tablet-push-13of16 { +- left: 81.25%; } +- .col-tablet-push-15of16 { +- left: 93.75%; } } +- +-.col-3-wide { +- width: 33.3333333333%; } +- +-@media (max-width: 719px) { +- /* Remove .col-12 and .col-13 backward compatibility support as soon as it's been removed. */ +-[class*=col-], +- .col-12 [class*=col-], +- .col-13 [class*=col-] { +- float: none; +- left: 0; +- width: auto; +-} } +- +-/** +- * Fades out an element. +- * Applies visibility hidden when the transition is finished. +- * +- * Use opacity: 1; to show the element. +- */ +-/* Header component */ +-.dac-header { +- box-shadow: 0 2px 2px 0 rgba(0, 0, 0, 0.07); +- box-sizing: border-box; +- background: #6ab344; +- height: 64px; +- margin: 0; +- left: 0; +- position: fixed; +- right: 0; +- top: 0; +- -webkit-transition: background 200ms; +- transition: background 200ms; +- z-index: 61; +-} +- +-.dac-ndk .dac-header { +- background: #00bcd4; +-} +- +-.dac-studio .dac-header { +- background: #424242; +-} +- +-.dac-search-mode .dac-header { +- background: #b0bec5; +- -webkit-transition: background 200ms; +- transition: background 200ms; +-} +- +-.dac-search-mode .dac-header-logo, +- .dac-search-mode .dac-header-console-btn { +- opacity: 0; +- visibility: hidden; +- -webkit-transition: visibility 0s linear 200ms, opacity 200ms linear; +- transition: visibility 0s linear 200ms, opacity 200ms linear; +-} +- +-.dac-header-logo { +- display: block; +- font-size: 20px; +- font-weight: 400; +- float: left; +- letter-spacing: .3px; +- line-height: 36px; +- opacity: 1; +- padding: 13px 48px 15px 0; +-} +- +-.dac-header-logo, .dac-header-logo:hover, .dac-header-logo:focus { +- color: #fff; +-} +- +-@media (min-width: 980px) { +- .dac-header-logo { +- border-right: 1px solid rgba(0, 0, 0, 0.1); +- } +-} +- +-@media (min-width: 720px) and (max-width: 979px) { +- .dac-header-logo { +- padding-right: 10px; +- } +-} +- +-.dac-header-logo-image { +- margin-right: 5px; +- vertical-align: top; +-} +- +-.dac-header-tabs { +- list-style: none; +- margin: 0 10px; +- display: none; +- opacity: 1; +- -webkit-transition: opacity 200ms linear 200ms; +- transition: opacity 200ms linear 200ms; +-} +- +-@media (min-width: 720px) { +- .dac-header-tabs { +- display: inline-block; +- } +- +- /* Do not show nav toggle and up-nav button for left nav, +- when header tabs are visible (when no sub navigation) */ +- body.no-subnav .dac-nav-back-button { +- display:none; +- } +- body.no-subnav .dac-nav-sub { +- top: 0 !important; +- } +-} +- +-.dac-header-tabs li { +- display: inline-block; +-} +- +-.dac-header-tab { +- display: inline-block; +- line-height: 64px; +- height: 64px; +- padding: 0 9px; +- color: #fff; +- color: rgba(255, 255, 255, 0.7); +- font-size: 14px; +- text-transform: uppercase; +- font-weight: 500; +-} +- +-.dac-header-tab:hover, +-.dac-header-tab:focus { +- color: #fff; +-} +- +-.dac-header-tab.selected { +- border-bottom: 4px solid #fff; +- height: 60px; +- color: #fff; +-} +- +-.dac-search-mode .dac-header-tabs { +- opacity: 0; +- -webkit-transition: opacity 0ms linear 0ms; +- transition: opacity 0ms linear 0ms; +-} +- +-.dac-header-console-btn { +- border-radius: 3px; +- box-shadow: 0 1px 4px 0 rgba(0, 0, 0, 0.2); +- float: right; +- font-size: 14px; +- font-weight: 500; +- line-height: 28px; +- margin: 13px 13px 12px 24px; +- opacity: 1; +- padding: 4px 10px; +- position: relative; +- text-transform: uppercase; +- -webkit-transition: box-shadow .2s; +- transition: box-shadow .2s; +- z-index: 60; +-} +- +-@media (min-width: 720px) and (max-width: 979px) { +- .dac-header-console-btn { +- display: none; +- } +-} +- +-.dac-header-console-btn > .dac-sprite, .dac-header-console-btn > .dac-modal-header-close:before, .paging-links .dac-header-console-btn > .prev-page-link:before, .paging-links .dac-header-console-btn > .next-page-link:before, .paging-links .dac-header-console-btn > .next-class-link:before, .paging-links .dac-header-console-btn > .start-class-link:after { +- margin-right: 5px; +-} +- +-.dac-header-console-btn, .dac-header-console-btn:hover, .dac-header-console-btn:focus { +- color: #fff; +-} +- +-.dac-header-console-btn:hover { +- box-shadow: 0 2px 8px 0 rgba(0, 0, 0, 0.3); +-} +- +-.dac-header-console-btn:focus { +- background: rgba(63, 81, 181, 0.1); +- outline: 0; +-} +- +-.dac-studio .dac-header-console-btn { +- color:#fff; +- background:rgba(255, 255, 255, 0.3); +-} +-.dac-studio .dac-header-console-btn:hover { +- background:rgba(255, 255, 255, 0.5); +-} +-.dac-studio .dac-header-console-btn:focus { +- background:rgba(255, 255, 255, 0.7); +- color:#000; +-} +- +-@media (max-width: 719px) { +- .dac-header { +- text-align: center; +- } +- +- .dac-header-logo { +- border-right: 0; +- display: inline-block; +- margin-right: 0; +- float: none; +- padding-left: 0; +- padding-right: 0; +- } +- +- .dac-header-console-btn { +- display: none; +- } +-} +- +-/* Header Breadcrumbs component */ +-.dac-header-crumbs { +- list-style-type: none; +- margin: 23px 0 -13px 0; +- display: inline-block; +-} +- +-body.no-crumbs .dac-header-crumbs { +- display:none; +-} +- +-.dac-header-crumbs.dac-has-content { +- opacity: 1; +-} +- +-.dac-header-crumbs-item { +- float: left; +- position: relative; +- margin: 0; +- padding: 0; +-} +- +-.dac-header-crumbs-item i, .dac-header-crumbs-item .dac-nav-link-forward { +- display: none; +-} +- +-.dac-header-crumbs-item:before { +- content: ''; +- background: transparent url(../images/styles/disclosure_right.png) no-repeat scroll 50% 50%; +- width: 10px; +- height: 10px; +- display: inline-block; +- position: absolute; +- top: 12px; +- left: -15px; +-} +- +-.dac-header-crumbs-item:first-child:before { +- content: none; +-} +- +-.dac-header-crumbs-link { +- display: block; +- font-size: 16px; +- line-height: 32px; +- padding: 0 20px 0 0; +-} +- +-.dac-header-crumbs-link, .dac-header-crumbs-link:hover, .dac-header-crumbs-link:focus { +- color: #666; +-} +- +-.dac-header-crumbs-link:focus { +- outline: 0; +- text-decoration: underline; +-} +- +-.dac-header-crumbs-link.current { +- font-weight: 400; +-} +- +-/* Header site search component */ +-.dac-header-search { +- bottom: 64px; +- position: absolute; +- right: 220px; +- top: 0; +- width: 238px; +- -webkit-transition: width 300ms, right 100ms, margin 100ms; +- transition: width 300ms, right 100ms, margin 100ms; +-} +- +-.dac-studio .dac-header-search { +- right: 20px; /* move searchbar farther right, because there's no button */ +-} +- +-.dac-header-search-inner { +- margin: 0 auto; +- max-width: 940px; +- position: relative; +- width: 100%; +-} +- +-@media (min-width: 980px) { +- .dac-header-search-inner::after { +- background: -webkit-linear-gradient(right, #6ab344, rgba(106, 179, 68, 0)); +- background: linear-gradient(to left, #6ab344, rgba(106, 179, 68, 0)); +- content: ''; +- display: block; +- height: 64px; +- position: absolute; +- right: 100%; +- top: 0; +- -webkit-transition: opacity 200ms, -webkit-transform 300ms; +- transition: opacity 200ms, transform 300ms; +- -webkit-transform-origin: right center; +- -ms-transform-origin: right center; +- transform-origin: right center; +- width: 64px; +- } +- .dac-studio .dac-header-search-inner::after { +- background: -webkit-linear-gradient(right, #424242, rgba(66, 66, 66, 0)); +- background: linear-gradient(to left, #424242, rgba(66, 66, 66, 0)); +- } +- +- .dac-search-mode .dac-header-search-inner::after { +- opacity: 0; +- -webkit-transform: scaleX(0); +- -ms-transform: scaleX(0); +- transform: scaleX(0); +- } +-} +- +-.dac-header-search-icon { +- left: 8px; +- pointer-events: none; +- position: absolute; +- top: 18px; +-} +- +-.dac-header-search-input { +- background: #77be53; +- border-radius: 3px; +- border: none; +- box-sizing: border-box; +- color: #fff; +- font-size: 14px; +- font-weight: 600; +- margin: 13px 0; +- padding: 9px 36px 10px; +- -webkit-transition: background 200ms, color 200ms; +- transition: background 200ms, color 200ms; +- width: 100%; +-} +- +-.dac-studio .dac-header-search-input { +- background: rgba(255, 255, 255, 0.3); +-} +- +-.dac-header-search-close, .dac-header-search-clear { +- background: none; +- border: none; +- cursor: pointer; +- font-size: 0; +- outline: none; +- position: absolute; +- margin: 0; +-} +- +-.dac-header-search-clear { +- display: inline-block; +- opacity: .4; +- padding: 8px; +- top: 15px; +- right: 0; +-} +- +-.dac-header-search-clear:hover, .dac-header-search-clear:focus { +- opacity: .8; +-} +- +-.dac-header-search-close { +- left: -45px; +- top: 20px; +- -webkit-transform: translateX(45px); +- -ms-transform: translateX(45px); +- transform: translateX(45px); +- visibility: hidden; +-} +- +-.dac-header-search ::-webkit-input-placeholder { +- color: #fff; +- font-weight: 300; +- -webkit-transition: color 200ms; +- transition: color 200ms; +-} +- +-.dac-header-search :-moz-placeholder { +- color: #fff; +- font-weight: 300; +- transition: color 200ms; +-} +- +-.dac-header-search ::-moz-placeholder { +- color: #fff; +- font-weight: 300; +- transition: color 200ms; +-} +- +-.dac-header-search :-ms-input-placeholder { +- color: #fff; +- font-weight: 300; +- transition: color 200ms; +-} +- +-.dac-header-search-input:focus { +- outline: 0; +-} +- +-.dac-search-mode .dac-header-search { +- width: 940px; +- right: 50%; +- margin-right: -470px; +-} +- +-.dac-search-mode .dac-header-search .dac-header-search-input::after { +- background: -webkit-linear-gradient(right, #b0bec5, rgba(176, 190, 197, 0)); +- background: linear-gradient(to left, #b0bec5, rgba(176, 190, 197, 0)); +-} +- +-.dac-search-mode .dac-header-search .dac-header-search-close { +- -webkit-transition: -webkit-transform 200ms ease-out 300ms; +- transition: transform 200ms ease-out 300ms; +- -webkit-transform: translateX(0); +- -ms-transform: translateX(0); +- transform: translateX(0); +- visibility: visible; +-} +- +-.dac-search-mode .dac-header-search .dac-header-search-icon { +- left: 23px; +-} +- +-.dac-search-mode .dac-header-search .dac-header-search-input { +- background: #fff; +- border-radius: 0; +- font-size: 18px; +- color: #666; +- padding-left: 55px; +- margin-top: 11px; +-} +- +-.dac-search-mode .dac-header-search ::-webkit-input-placeholder { +- color: #505050; +-} +- +-.dac-search-mode .dac-header-search :-moz-placeholder { +- color: #505050; +-} +- +-.dac-search-mode .dac-header-search ::-moz-placeholder { +- color: #505050; +-} +- +-.dac-search-mode .dac-header-search :-ms-input-placeholder { +- color: #505050; +-} +- +-@media (min-width: 720px) and (max-width: 979px) { +- .dac-studio .dac-header-search, +- .dac-header-search { +- right: 20px; +- width: 200px; +- -webkit-transition: left 200ms, right 200ms, width 200ms; +- transition: left 200ms, right 200ms, width 200ms; +- } +- +- .dac-search-mode .dac-header-search { +- left: 60px; +- right: 0; +- width: 100%; +- } +- +- .dac-search-mode .dac-header-search .dac-header-search-inner { +- margin: 0; +- width: calc(100% - 60px - 10px); +- } +- +- .dac-header-search-close { +- left: -42px; +- } +-} +- +-@media (max-width: 719px) { +- .dac-header-search { +- bottom: 0; +- border-radius: 0; +- border-left: 1px solid rgba(0, 0, 0, 0.1); +- cursor: pointer; +- left: calc(100% - 64px); +- margin: 0; +- overflow: hidden; +- padding-left: 10px; +- padding-right: 10px; +- position: absolute; +- right: 0; +- top: 0; +- } +- +- .dac-header-search-input { +- background: none; +- cursor: pointer; +- opacity: 0; +- } +- +- .dac-search-mode .dac-header-search { +- background: #b0bec5; +- cursor: default; +- overflow: visible; +- left: 60px; +- right: 0; +- width: 100%; +- -webkit-transition: left 200ms, right 200ms, width 200ms; +- transition: left 200ms, right 200ms, width 200ms; +- padding: 0; +- border: none; +- } +- +- .dac-search-mode .dac-header-search .dac-header-search-inner { +- margin: 0; +- width: calc(100% - 60px - 10px); +- } +- +- .dac-search-mode .dac-header-search .dac-header-search-input { +- opacity: 1; +- } +-} +- +-.highlighted em { +- color: #333; +- font-style: normal; +- font-weight: 700; +-} +- +-.card-info .title.highlighted { +- color: #666; +-} +- +-/* Main navigation component */ +-.dac-nav-sidebar { +- background: #f5f8fa; +- border-right: 1px solid rgba(0, 0, 0, 0.1); +- bottom: 0; +- left: 0; +- overflow: hidden; +- padding: 0; +- position: fixed; +- top: 64px; +- -webkit-transform: translate(-100%, 0); +- -ms-transform: translate(-100%, 0); +- transform: translate(-100%, 0); +- width: 250px; +- z-index: 60; +-} +- +-.dac-nav-animating .dac-nav-sidebar { +- -webkit-transition: -webkit-transform .3s; +- transition: transform .3s; +-} +- +-.dac-nav-open .dac-nav-sidebar { +- -webkit-transform: translate(0, 0); +- -ms-transform: translate(0, 0); +- transform: translate(0, 0); +-} +- +-.dac-search-mode .dac-nav-sidebar { +- -webkit-transition: -webkit-transform .3s; +- transition: transform .3s; +- -webkit-transform: translate(-100%, 0); +- -ms-transform: translate(-100%, 0); +- transform: translate(-100%, 0); +-} +- +-.dac-nav .dac-swap-section { +- -webkit-transition-duration: .3s; +- transition-duration: .3s; +-} +- +-.dac-nav-back { +- margin-top: -3px; +- margin-right: 10px; +-} +- +-.dac-nav-fullscreen { +- background: transparent; +- border: none; +- bottom: 100%; +- cursor: pointer; +- display: none; +- opacity: .8; +- outline: none; +- padding: 20px 15px; +- position: absolute; +- right: 0; +-} +- +-@media (min-width: 980px) { +- .dac-nav-fullscreen { +- display: inline-block; +- } +-} +- +-.dac-nav-fullscreen:hover { +- opacity: 1; +-} +- +-.dac-nav-sub-slider { +- cursor: pointer; +- opacity: .5; +- position: absolute; +- right: 7px; +- top: 5px; +-} +- +-.dac-nav-back-button { +- background: #546e7a; +- border-bottom: 1px solid rgba(0, 0, 0, 0.1); +- display: block; +- font-weight: 500; +- font-size: 18px; +- left: 0; +- margin: 0; +- padding: 20px; +- position: absolute !important; +- right: 0; +- top: 0; +- z-index: 1; +-} +- +-.dac-nav-back-button, +-.dac-nav-back-button:hover, +-.dac-nav-back-button:active, +-.dac-nav-back-button:focus { +- color: rgba(255, 255, 255, 0.7); +-} +- +-/* The back button in Studio and NDK left nav */ +-.dac-nav-back-button.back-to-dev { +- background: none; +- color: #444; +- position: relative !important; +- top: -16px; +-} +- +-.dac-nav-back-button.back-to-dev:hover, +-.dac-nav-back-button.back-to-dev:active, +-.dac-nav-back-button.back-to-dev:focus { +- color: rgba(68, 68, 68, .7); +-} +- +-.dac-nav-back-button:focus .dac-nav-back { +- outline-color: rgb(77, 144, 254); +- outline-offset: 15px; +- outline-style: auto; +-} +- +-.dac-nav-back-button > .dac-sprite, .dac-nav-back-button > .dac-modal-header-close:before, .paging-links .dac-nav-back-button > .prev-page-link:before, .paging-links .dac-nav-back-button > .next-page-link:before, .paging-links .dac-nav-back-button > .next-class-link:before, .paging-links .dac-nav-back-button > .start-class-link:after { +- opacity: .7; +-} +- +-.dac-nav-logo { +- font-size: 20px; +- font-weight: 300; +- letter-spacing: .3px; +- line-height: 36px; +- margin: 0; +- padding: 14px 24px; +-} +- +-.dac-nav-logo, .dac-nav-logo:hover, .dac-nav-logo:focus { +- color: #444; +-} +- +-.dac-nav-list { +- bottom: 0; +- left: 0; +- list-style-type: none; +- margin: 0; +- -webkit-overflow-scrolling: touch; +- overflow-y: scroll; +- padding: 16px 0; +- position: absolute !important; +- right: 0; +- top: 0 !important; +- scrollbar-face-color: #b7baba; +- scrollbar-track-color: #e5e8e9; +-} +- +-.dac-nav-list::-webkit-scrollbar { +- width: 4px; +- height: 4px; +-} +- +-.dac-nav-list::-webkit-scrollbar-thumb { +- background: #b7baba; +-} +- +-.dac-nav-list::-webkit-scrollbar-track { +- background: #e5e8e9; +-} +- +-.dac-nav-secondary { +- margin: 0; +-} +- +-.dac-nav-item { +- list-style-type: none; +- margin: 0 0 10px; +- position: relative; +-} +- +-.dac-nav-secondary .dac-nav-item { +- margin-bottom: 0; +-} +- +-.dac-nav-head { +- display: block; +- font-size: 16px; +- font-weight: 300; +- letter-spacing: .24px; +- line-height: 32px; +- margin-bottom: 20px; +- margin-top: 0; +-} +- +-.dac-nav-dimmer { +- background: #000; +- display: block; +- height: 100%; +- left: 0; +- opacity: 0; +- position: fixed; +- top: 0; +- -webkit-transform: translateZ(0); +- transform: translateZ(0); +- visibility: hidden; +- width: 100%; +- z-index: 60; +-} +- +-.dac-nav-animating .dac-nav-dimmer { +- -webkit-transition: visibility 0s linear .3s, opacity .3s linear; +- transition: visibility 0s linear .3s, opacity .3s linear; +-} +- +-.dac-nav-open .dac-nav-dimmer { +- opacity: .8; +- -webkit-transition-delay: 0s; +- transition-delay: 0s; +- visibility: visible; +-} +- +-@media (min-width: 980px) { +- .dac-nav-dimmer { +- display: none; +- } +-} +- +-.dac-nav-hamburger { +- display: inline-block; +- float: left; +- height: 15px; +- padding: 22px 20px; +- width: 18px; +-} +- +-@media (max-width: 719px) { +- .dac-nav-hamburger { +- border-right: 1px solid rgba(0, 0, 0, 0.1); +- left: 0; +- padding-bottom: 27px; +- position: absolute; +- top: 0; +- } +-} +- +-.dac-nav-hamburger-top, .dac-nav-hamburger-mid, .dac-nav-hamburger-bot { +- background: rgba(0, 0, 0, 0.4); +- display: block; +- height: 2px; +- margin: 3px 0 0; +- opacity: .5; +- width: 100%; +-} +- +-.dac-studio .dac-nav-hamburger-top, +-.dac-studio .dac-nav-hamburger-mid, +-.dac-studio .dac-nav-hamburger-bot { +- background: rgba(256, 256, 256, 0.4); +-} +- +-.dac-nav-animating .dac-nav-hamburger-top, .dac-nav-animating .dac-nav-hamburger-mid, .dac-nav-animating .dac-nav-hamburger-bot { +- -webkit-transition: opacity .3s; +- transition: opacity .3s; +-} +- +-@media (max-width: 719px) { +- .dac-nav-hamburger-top, .dac-nav-hamburger-mid, .dac-nav-hamburger-bot { +- background: #fff; +- opacity: 1; +- } +-} +- +-.dac-nav-open .dac-nav-hamburger-top, +- .dac-nav-open .dac-nav-hamburger-mid, +- .dac-nav-open .dac-nav-hamburger-bot { +- opacity: 1; +-} +- +-.dac-search-mode .dac-nav-hamburger { +- opacity: 0; +- visibility: hidden; +- -webkit-transition: visibility 0s linear 200ms, opacity 200ms linear; +- transition: visibility 0s linear 200ms, opacity 200ms linear; +-} +- +-.dac-nav-link { +- color: #444; +- display: block; +- font-size: 14px; +- text-transform: uppercase; +- font-weight: 500; +- letter-spacing: .24px; +- padding: 5px 20px; +- -webkit-transition: background-color 0.35s cubic-bezier(0.35, 0, 0.25, 1); +- transition: background-color 0.35s cubic-bezier(0.35, 0, 0.25, 1); +-} +- +-.dac-nav-link:hover, .dac-nav-link:focus { +- color: rgba(68, 68, 68, 0.7); +-} +- +-.dac-nav-link:focus { +- background: rgba(63, 81, 181, 0.1); +- outline: 0; +-} +- +-.dac-nav-secondary .dac-nav-link { +- font-size: 12px; +- font-weight: 400; +- padding-left: 40px; +- text-transform: none; +-} +- +-.dac-nav-link.selected { +- background: rgba(63, 81, 181, 0.1); +- color: #039bef; +- position: relative; +-} +- +-.dac-nav-link-forward { +- background: #546E7A; +- color: #fff; +- cursor: pointer; +- display: inline-block; +- line-height: 34px; +- padding: 0; +- position: absolute; +- right: 0; +- top: 0; +- text-align: center; +- width: 34px; +-} +- +-.dac-nav-link-forward > .dac-nav-forward { +- opacity: .7; +- vertical-align: -3px; +-} +- +-.dac-nav-sub { +- bottom: 0; +- left: 0; +- position: absolute !important; +- top: 65px !important; +- right: 0; +- z-index: 1; +-} +- +-#body-content { +- padding-top: 64px; +-} +- +-.dac-nav-animating #body-content { +- -webkit-transition: padding .3s; +- transition: padding .3s; +-} +- +-@media (min-width: 980px) { +- .dac-nav-open #body-content { +- padding-left: 250px; +- } +- +- /* Do not show nav toggle on large screens (when no subnav) */ +- body.no-subnav .dac-nav-toggle { +- display:none; +- } +- body.no-subnav .dac-header-logo { +- padding-left:20px; +- } +- /* ...If the page is also full-width, then don't show left nav at all */ +- body.no-subnav.full-width .dac-nav { +- display: none; +- } +- body.no-subnav.full-width #body-content { +- padding-left:0; +- } +-} +- +-.dac-nav-open { +- overflow: hidden; +-} +- +-@media (min-width: 980px) { +- .dac-nav-open { +- overflow: visible; +- } +-} +- +-#devdoc-nav { +- height: 100%; +-} +- +-.data-reference-resources-wrapper { +- display: none; +-} +- +-.dac-reference-nav { +- height: calc(100% - 36px); +- overflow: hidden; +- position: relative; +-} +- +-.dac-reference-nav ul, +- .dac-reference-nav li { +- margin: 0; +- list-style-type: none; +-} +- +-.dac-reference-nav-list { +- bottom: 0; +- overflow: hidden; +- overflow-y: scroll; +- left: 0; +- padding: 10px; +- padding-left: 20px; +- position: absolute; +- right: 0; +- top: 0; +- scrollbar-face-color: #9da4a7; +- scrollbar-track-color: #c4cdd1; +-} +- +-.dac-reference-nav-list::-webkit-scrollbar { +- width: 4px; +- height: 4px; +-} +- +-.dac-reference-nav-list::-webkit-scrollbar-thumb { +- background: #9da4a7; +-} +- +-.dac-reference-nav-list::-webkit-scrollbar-track { +- background: #c4cdd1; +-} +- +-.dac-reference-nav-resources { +- display: none; +- padding: 0 0 0 13px; +-} +- +-.dac-reference-nav-resource, +-.dac-reference-nav-toggle { +- color: #505050; +- cursor: pointer; +- display: block; +- font-size: 12px; +- line-height: 1; +- overflow: hidden; +- margin: 0; +- padding: 3px 0; +- position: relative; +- text-overflow: ellipsis; +- white-space: nowrap; +-} +- +-.dac-reference-nav-toggle { +- margin-left: -12px; +- padding-left: 12px; +-} +- +-.selected > .dac-reference-nav-resource { +- color: #039bef; +- font-weight: 600; +-} +- +-.dac-reference-nav-toggle::before { +- background: transparent url(../images/styles/disclosure_up.png) no-repeat center center; +- content: ''; +- display: block; +- height: 19px; +- left: 0; +- position: absolute; +- top: 0; +- width: 8px; +-} +- +-.dac-reference-nav-toggle.dac-closed::before { +- -webkit-transform: scaleY(-1); +- -ms-transform: scaleY(-1); +- transform: scaleY(-1); +-} +- +-/* nav */ +-#nav { +- background: #cfd8dc; +- bottom: 0; +- left: 0; +- margin: 0; +- -webkit-overflow-scrolling: touch; +- overflow-y: scroll; +- position: absolute !important; +- right: 0; +- top: 0 !important; +- padding: 10px; +- scrollbar-face-color: #9da4a7; +- scrollbar-track-color: #c4cdd1; +- /* section header links */ +- /* nested nav headers */ +-} +- +-#nav::-webkit-scrollbar { +- width: 4px; +- height: 4px; +-} +- +-#nav::-webkit-scrollbar-thumb { +- background: #9da4a7; +-} +- +-#nav::-webkit-scrollbar-track { +- background: #c4cdd1; +-} +- +-#nav li { +- font-size: 12px; +- line-height: 18px; +- list-style-type: none; +- margin: 0; +- padding: 0; +-} +- +-#nav a { +- color: #505050; +- text-decoration: none; +- word-wrap: break-word; +-} +- +-#nav .nav-section-header { +- padding: 0 30px 0 0; +- position: relative; +- -webkit-transition: background-color .1s; +- transition: background-color .1s; +-} +- +-#nav .nav-section-header.empty { +- padding: 0; +-} +- +-#nav .nav-section-header.empty::after { +- display: none; +-} +- +-#nav .nav-section-header .toggle-icon { +- background: transparent url(../images/styles/disclosure_down.png) no-repeat scroll 50% 50%; +- content: ''; +- height: 34px; +- display: block; +- position: absolute; +- right: 0; +- top: 1px; +- width: 34px; +-} +- +-#nav li.selected a { +- color: #0288D1; +-} +- +-#nav li.selected ul li a { +- color: #505050; +-} +- +-#nav li.expanded .nav-section-header { +- background: #bac2c6; +-} +- +-#nav li.expanded .nav-section-header.empty { +- background: none; +-} +- +-#nav li.expanded li .nav-section-header { +- background: none; +-} +- +-#nav li.expanded li ul { +- padding: 0 10px; +-} +- +-#nav li.expanded > .nav-section-header .toggle-icon { +- content: ''; +- background: transparent url(../images/styles/disclosure_up.png) no-repeat scroll 50% 50%; +- width: 34px; +- height: 34px; +-} +- +-#nav li.expanded li ul.tree-list-children { +- padding: 0; +-} +- +-#nav li.expanded li ul.tree-list-children .tree-list-children { +- padding: 0 0 0 10px; +-} +- +-#nav .nav-section .nav-section .nav-section-header { +- /* no white line between second level sections */ +- margin-bottom: 0; +-} +- +-#nav > li > div > a { +- display: block; +- font-weight: 700; +- padding: 10px; +-} +- +-#nav .nav-section .nav-section { +- position: relative; +- padding: 0; +- margin: 0; +-} +- +-#nav .nav-section li a { +- /* first gen child (2nd level li) */ +- display: block; +- font-weight: 700; +- text-transform: none; +- padding: 10px; +-} +- +-#nav .nav-section li li a { +- /* second gen child (3rd level li) */ +- font-weight: 400; +- padding: 6px 6px 6px 10px; +-} +- +-#nav li span.tree-list-subtitle { +- display: inline-block; +- color: #555; +- font-size: 12px; +- padding: 10px; +- text-transform: uppercase; +-} +- +-#nav li span.tree-list-subtitle:before { +- content: '—'; +-} +- +-#nav li span.tree-list-subtitle:after { +- content: '—'; +-} +- +-#nav li span.tree-list-subtitle.package { +- padding-top: 15px; +- cursor: default; +-} +- +-#nav li span.tree-list-subtitle.package:before { +- content: ''; +-} +- +-#nav li span.tree-list-subtitle.package:after { +- content: ''; +-} +- +-#nav li ul.tree-list-children.classes { +- padding-left: 10px; +-} +- +-#nav li ul { +- display: none; +- overflow: hidden; +- margin: 0; +-} +- +-#nav li ul.animate-height-in { +- -webkit-transition: height 0.25s ease-in; +- transition: height 0.25s ease-in; +-} +- +-#nav li ul.animate-height-out { +- -webkit-transition: height 0.25s ease-out; +- transition: height 0.25s ease-out; +-} +- +-#nav li ul li { +- padding: 0; +-} +- +-#nav li li li { +- padding: 0; +-} +- +-#nav li ul > li { +- padding: 0; +-} +- +-#nav li ul > li:last-child { +- padding-bottom: 5px; +-} +- +-#nav li ul.tree-list-children > li:last-child { +- padding-bottom: 0; +-} +- +-#nav li.expanded ul > li { +- background: #c4cdd1; +-} +- +-#nav li.expanded ul > li li { +- background: inherit; +-} +- +-#nav li ul.tree-list-children ul { +- display: block; +-} +- +-#nav.samples-nav li li li a { +- padding-top: 3px; +- padding-bottom: 3px; +-} +- +-#nav.samples-nav li li ul > li:last-child { +- padding-bottom: 3px; +-} +- +-/* Hero carousel */ +-.dac-hero { +- background-color: #fff; +- background-position: 50% 30%; +- background-size: cover; +- box-sizing: border-box; +- font-size: 16px; +- min-height: 550px; +- padding-top: 88px; +-} +- +-.dac-hero.dac-darken::before { +- background: rgba(0, 0, 0, 0.3); +- bottom: 0; +- content: ''; +- display: block; +- left: 0; +- position: absolute; +- right: 0; +- top: 0; +-} +- +-.dac-hero { +- background-size: cover; +- position: relative; +-} +- +-.dac-hero-headline { +- background-color: #fff; +- bottom: 25px; +- float: none !important; +- padding: 0 10px 10px; +- position: absolute; +- right: 0; +- z-index: 2; +-} +- +-@media (max-width: 719px) { +- .dac-hero-headline { +- bottom: 0; +- } +- +- .dac-hero.dac-darken::before { +- background: -webkit-linear-gradient(top, rgba(0, 0, 0, 0.3), rgba(0, 0, 0, 0.8), rgba(0, 0, 0, 0.9) 80%); +- background: linear-gradient(to bottom, rgba(0, 0, 0, 0.3), rgba(0, 0, 0, 0.8), rgba(0, 0, 0, 0.9) 80%); +- } +-} +- +-.dac-hero.dac-darken .dac-hero-content { +- position: relative; +-} +- +-@media (max-width: 719px) { +- .dac-hero { +- padding-bottom: 20px; +- padding-top: 20px; +- } +-} +- +-.dac-hero-tag { +- font-size: 11px; +- font-weight: 700; +- letter-spacing: .07em; +- margin-bottom: 2px; +- text-transform: uppercase; +-} +- +-.dac-hero-title { +- margin: 0 0 14px; +-} +- +-.dac-studio .dac-hero-title { +- padding-top:0; +-} +- +-@media (max-width: 719px) { +- .dac-hero-title { +- font-size: 28px; +- line-height: 35px; +- } +-} +- +-.dac-hero-description { +- margin-bottom: 16px; +-} +- +-@media (max-width: 719px) { +- .dac-hero-description { +- font-size: 14px; +- } +-} +- +-.dac-hero-cta { +- display: inline-block; +- line-height: 40px; +- margin-right: 20px; +- -webkit-transition: opacity .3s; +- transition: opacity .3s; +-} +- +-.dac-hero-cta:hover { +- color: currentColor; +- opacity: .54; +-} +- +-.dac-hero-cta .dac-sprite, .dac-hero-cta .dac-modal-header-close:before, .dac-hero-cta .paging-links .prev-page-link:before, .paging-links .dac-hero-cta .prev-page-link:before, .dac-hero-cta .paging-links .next-page-link:before, .paging-links .dac-hero-cta .next-page-link:before, .dac-hero-cta .paging-links .next-class-link:before, .paging-links .dac-hero-cta .next-class-link:before, .dac-hero-cta .paging-links .start-class-link:after, .paging-links .dac-hero-cta .start-class-link:after { +- margin-left: -8px; +-} +- +-.dac-hero-cta.col-16 { +- line-height: 1.4em; +- margin-top: 20px; +- padding-left: 0; +- position: relative; +-} +- +-.dac-hero-cta.col-16 .dac-sprite { +- position: absolute; +- left: 0; +- top: -3px; +-} +- +-.dac-hero-cta.col-16 .dac-sprite-text { +- position: relative; +- left: 12px; +-} +- +-@media (max-width: 719px) { +- .dac-hero-cta { +- line-height: 28px; +- } +-} +- +-.dac-hero-figure { +- text-align: center; +-} +- +-/* Android Studio download page */ +-.dac-studio section#features { +- padding-top:0; +-} +-.dac-studio .wrap.feature { +- margin:80px auto; +-} +-.dac-studio .dac-section-links.feature-more { +- margin-top:-20px; +-} +-.dac-studio .dac-toggle-content .wrap.feature { +- margin-top:0; +-} +- +-@media (max-width: 719px) { +- .dac-hero-figure { +- height: 150px; +- margin: 15px 0; +- } +- +- .dac-hero-figure img { +- max-height: 150px; +- } +- +- /* Android Studio download page */ +- .dac-studio .feature .dac-hero-figure, +- .dac-studio .feature .dac-hero-figure img { +- height:auto; +- max-height:none; +- } +- .dac-studio .feature .dac-hero-figure img { +- width:90%; +- margin:0 auto; +- } +-} +- +-.dac-hero-carousel { +- height: 550px; +- position: relative; +-} +- +-.dac-hero-carousel > .dac-hero { +- bottom: 0; +- left: 0; +- position: absolute; +- right: 0; +- top: 0; +- will-change: opacity; +-} +- +-.dac-hero-carousel > .dac-hero, +- .dac-hero-carousel > .dac-hero .wrap { +- opacity: 0; +-} +- +-.dac-hero-carousel > .dac-hero.active { +- opacity: 1; +- -webkit-transition: opacity .5s; +- transition: opacity .5s; +- z-index: 1; +-} +- +-.dac-hero-carousel > .dac-hero.active .wrap { +- opacity: 1; +- -webkit-transition: opacity .5s .5s; +- transition: opacity .5s .5s; +-} +- +-.dac-hero-carousel > .dac-hero.out, +- .dac-hero-carousel > .dac-hero.out .wrap { +- -webkit-transition: opacity 0s .5s; +- transition: opacity 0s .5s; +- opacity: 0; +-} +- +-.dac-hero-carousel-action { +- bottom: 0; +- display: block; +- left: 0; +- position: absolute; +- right: 0; +- top: 0; +- z-index: 1; +-} +- +-.dac-hero-carousel .dac-hero-cta { +- position: relative; +- z-index: 1; +-} +- +-.dac-hero-carousel-pagination { +- bottom: 33px; +- left: 0; +- position: absolute; +- right: 0; +-} +- +-@media (max-width: 719px) { +- .dac-hero-carousel-pagination { +- text-align: center; +- bottom: 20px; +- } +-} +- +-.dac-hero-carousel-pagination .dac-pagination-item { +- position: relative; +- z-index: 1; +-} +- +-.dac-pagination { +- list-style: none; +- margin: 0 -6px; +-} +- +-.dac-pagination-item { +- background-clip: content-box; +- background-color: rgba(153, 153, 153, 0.4); +- border-radius: 50%; +- cursor: pointer; +- display: inline-block; +- height: 14px; +- overflow: hidden; +- padding: 6px; +- pointer-events: all; +- text-indent: 100%; +- -webkit-transition: background-color .1s ease-in; +- transition: background-color .1s ease-in; +- white-space: nowrap; +- width: 14px; +- will-change: background-color; +-} +- +-.dac-pagination-item:hover { +- background-color: rgba(153, 153, 153, 0.6); +-} +- +-.dac-pagination-item.active, .dac-pagination-item.active:hover { +- background-color: #6ab344; +-} +- +-.dac-invert .dac-pagination-item { +- background-color: rgba(204, 204, 204, 0.2); +-} +- +-.dac-invert .dac-pagination-item:hover { +- background-color: rgba(153, 153, 153, 0.4); +-} +- +-@media (max-width: 719px) { +- .dac-pagination-item { +- height: 12px; +- width: 12px; +- } +-} +- +-/* Form component */ +-.dac-form { +- color: #505050; +- font-size: 16px; +- /* Modal Responsive */ +-} +- +-.dac-form a { +- color: #000; +-} +- +-.dac-form-aside { +- display: inline-block; +- font-size: 12px; +- margin-top: 0; +-} +- +-.dac-form-required { +- color: #ef4300; +-} +- +-.dac-form-fieldset { +- padding: 0; +-} +- +-.dac-form-legend { +- display: block; +- color: #333; +- font-weight: 500; +- margin: 20px 0 12px; +- padding: 0; +- width: 100%; +-} +- +-.dac-form-legend > .dac-form-required { +- float: right; +- margin-top: 3px; +-} +- +-.dac-form-input { +- border: 0 solid #e3e3e3; +- border-bottom-width: 1px; +- display: block; +- outline: 0; +- padding: 1px 0 8px; +- -webkit-transition: border-color .2s; +- transition: border-color .2s; +- width: 100%; +-} +- +-.dac-form-input-group { +- position: relative; +-} +- +-.dac-form-input-group > .dac-form-required { +- display: block; +- bottom: 3px; +- position: absolute; +- right: 0; +-} +- +-.dac-form-input:focus { +- border-bottom-color: #09f; +-} +- +-.dac-form-floatlabel { +- display: block; +- cursor: text; +- margin-top: 5px; +- pointer-events: none; +- -webkit-transform-origin: 0 100%; +- -ms-transform-origin: 0 100%; +- transform-origin: 0 100%; +- -webkit-transform: translate3d(0, 22px, 0) scale(1); +- transform: translate3d(0, 22px, 0) scale(1); +- -webkit-transition: -webkit-transform .2s; +- transition: transform .2s; +-} +- +-.dac-focused > .dac-form-floatlabel, +- .dac-has-value > .dac-form-floatlabel { +- cursor: default; +- -webkit-transform: translate3d(0, 0, 0) scale(0.75); +- transform: translate3d(0, 0, 0) scale(0.75); +-} +- +-.dac-form-radio, .dac-form-checkbox { +- opacity: 0; +- position: absolute; +- visibility: hidden; +-} +- +-.dac-form-radio-group, .dac-form-checkbox-group { +- display: table; +-} +- +-.dac-form-radio-group + .dac-form-radio-group, .dac-form-checkbox-group + .dac-form-radio-group, .dac-form-radio-group + .dac-form-checkbox-group, .dac-form-checkbox-group + .dac-form-checkbox-group { +- margin-top: 10px; +-} +- +-.dac-form-radio-button, .dac-form-checkbox-button { +- box-sizing: border-box; +- cursor: pointer; +- display: table-cell; +- float: left; +- height: 18px; +- margin: 2px 10px 0 0; +- position: relative; +- width: 18px; +-} +- +-.dac-form-radio-button::after, .dac-form-radio-button::before, .dac-form-checkbox-button::after, .dac-form-checkbox-button::before { +- box-sizing: border-box; +- content: ''; +- display: block; +- position: absolute; +-} +- +-.dac-form-radio-button::after, .dac-form-radio-button::before { +- border-radius: 50%; +- height: 100%; +- width: 100%; +-} +- +-.dac-form-radio-button::before { +- background: rgba(0, 0, 0, 0.7); +- -webkit-transform: translateZ(0) scale(0); +- transform: translateZ(0) scale(0); +- -webkit-transition: -webkit-transform .3s; +- transition: transform .3s; +-} +- +-.dac-form-radio-button::after { +- border: 2px solid rgba(0, 0, 0, 0.7); +-} +- +-.dac-form-radio:checked + .dac-form-radio-button::before { +- -webkit-transform: translateZ(0) scale(0.5); +- transform: translateZ(0) scale(0.5); +-} +- +-.dac-form-radio:focus + .dac-form-radio-button::after { +- border: 2px solid #09f; +-} +- +-.dac-form-checkbox-button::before { +- border: 1px solid #6c6e6f; +- border-radius: 3px; +- height: 100%; +- -webkit-transition: background .1s ease-out, box-shadow .3s ease-out; +- transition: background .1s ease-out, box-shadow .3s ease-out; +- width: 100%; +-} +- +-.dac-form-checkbox-button::after { +- border-bottom: 2px solid #fff; +- border-left: 2px solid #fff; +- bottom: 7px; +- height: 7px; +- left: 3px; +- -webkit-transform: rotate(-45deg); +- -ms-transform: rotate(-45deg); +- transform: rotate(-45deg); +- width: 12px; +-} +- +-.dac-form-checkbox:checked + .dac-form-checkbox-button::before { +- background: #6c6e6f; +- -webkit-transition-timing-function: ease-in; +- transition-timing-function: ease-in; +-} +- +-.dac-form-checkbox:focus + .dac-form-checkbox-button::before, +- .dac-form-checkbox:active + .dac-form-checkbox-button::before { +- box-shadow: 0 0 0 4px rgba(0, 0, 0, 0.05); +-} +- +-.dac-form-label { +- cursor: pointer; +- -webkit-user-select: none; +- -moz-user-select: none; +- -ms-user-select: none; +- user-select: none; +-} +- +-@media (max-width: 719px) { +- .dac-form-legend { +- margin-bottom: 0; +- } +-} +- +-/* Filter Resources Component*/ +-.dac-filter { +- color: #505050; +- margin-bottom: 20px; +- position: relative; +-} +- +-.dac-filter.dac-filter-section { +- margin-top: -45px; +- text-align: right; +-} +- +-@media (max-width: 719px) { +- .dac-filter.dac-filter-section { +- margin-top: 0; +- text-align: left; +- } +-} +- +-.dac-filter-title { +- color: #666; +- cursor: default; +- display: inline-block; +- font-size: 12px; +- font-weight: 500; +- line-height: 24px; +- margin: 0; +- text-transform: uppercase; +-} +- +-@media (max-width: 719px) { +- .dac-filter-title { +- margin-bottom: 20px; +- } +-} +- +-.dac-filter-message { +- color: #78868d; +- font-size: 18px; +- margin: 0 10px 10px; +-} +- +-.dac-filter-count { +- background: #6ab344; +- border-radius: 50%; +- color: #fff; +- display: inline-block; +- font-size: 12px; +- font-weight: 600; +- height: 24px; +- text-align: center; +- width: 24px; +-} +- +-.dac-filter-count.dac-disabled { +- visibility: hidden; +-} +- +-.dac-filter-chip { +- background: #bfc7cb; +- border-radius: 15px; +- color: #333; +- cursor: default; +- display: inline-block; +- line-height: 21px; +- margin: 0 10px 10px 0; +- padding: 4px 26px 4px 10px; +- position: relative; +-} +- +-.dac-filter-chip-close { +- background-color: transparent; +- border: none; +- cursor: pointer; +- outline: 0; +- padding: 3px; +- position: absolute; +- right: 5px; +- top: 5px; +-} +- +-.dac-filter-chip-close-icon { +- opacity: .7; +- margin-top: -2px; +- -webkit-transform: scale(0.57142857); +- -ms-transform: scale(0.57142857); +- transform: scale(0.57142857); +-} +- +-.dac-filter-chip-close:hover > .dac-filter-chip-close-icon { +- opacity: 1; +-} +- +-.dac-filter-chips { +- border-top: 1px solid rgba(0, 0, 0, 0.1); +- margin: 0; +- list-style-type: none; +- padding: 10px 0 0; +- position: relative; +- text-align: left; +-} +- +-.dac-filter-item { +- box-sizing: border-box; +- float: left; +- margin-bottom: 20px; +- padding: 0 10px; +- width: 33.33333333%; +-} +- +-@media (min-width: 720px) and (max-width: 979px) { +- .dac-filter-item { +- width: 50%; +- } +-} +- +-@media (max-width: 719px) { +- .dac-filter-item { +- width: 100%; +- } +-} +- +-/* Media component */ +-.dac-media { +- display: table; +- width: 100%; +-} +- +-.dac-media-body, .dac-media-figure { +- display: table-cell; +- vertical-align: top; +-} +- +-.dac-media-figure { +- padding: 0; +-} +- +-.dac-media-body { +- width: 100%; +-} +- +-.dac-swap { +- overflow: hidden; +- position: relative; +-} +- +-.dac-swap-section { +- left: 0; +- opacity: 0; +- position: absolute; +- top: 0; +- width: 100%; +- -webkit-transition: opacity 1s, -webkit-transform .5s; +- transition: opacity 1s, transform .5s; +-} +- +-.dac-swap-section.dac-no-anim { +- -webkit-transition: none; +- transition: none; +-} +- +-.dac-swap-section.dac-up { +- -webkit-transform: translateY(-100%); +- -ms-transform: translateY(-100%); +- transform: translateY(-100%); +-} +- +-.dac-swap-section.dac-down { +- -webkit-transform: translateY(100%); +- -ms-transform: translateY(100%); +- transform: translateY(100%); +-} +- +-.dac-swap-section.dac-left { +- -webkit-transform: translateX(-100%); +- -ms-transform: translateX(-100%); +- transform: translateX(-100%); +-} +- +-.dac-swap-section.dac-right { +- -webkit-transform: translateX(100%); +- -ms-transform: translateX(100%); +- transform: translateX(100%); +-} +- +-.dac-swap-section.dac-active { +- opacity: 1; +- position: relative; +- -webkit-transform: translate(0, 0); +- -ms-transform: translate(0, 0); +- transform: translate(0, 0); +- width: auto; +-} +- +-/* Modal component */ +-.dac-modal { +- opacity: 0; +- visibility: hidden; +- -webkit-transition: visibility 0s linear 300ms, opacity 300ms linear; +- transition: visibility 0s linear 300ms, opacity 300ms linear; +- background: rgba(0, 0, 0, 0.8); +- bottom: 0; +- left: 0; +- overflow-x: hidden; +- overflow-y: auto; +- position: fixed; +- right: 0; +- top: 0; +- z-index: 70; +-} +- +-.dac-modal.dac-active { +- opacity: 1; +- -webkit-transition-delay: 0s; +- transition-delay: 0s; +- visibility: visible; +-} +- +-.dac-modal-open { +- overflow: hidden; +-} +- +-.dac-modal-container { +- -webkit-box-align: center; +- -webkit-align-items: center; +- -ms-flex-align: center; +- align-items: center; +- display: -webkit-box; +- display: -webkit-flex; +- display: -ms-flexbox; +- display: flex; +- -webkit-filter: drop-shadow(0 5px 15px rgba(0, 0, 0, 0.4)); +- filter: drop-shadow(0 5px 15px rgba(0, 0, 0, 0.4)); +- -webkit-box-pack: center; +- -webkit-justify-content: center; +- -ms-flex-pack: center; +- justify-content: center; +- min-height: 100%; +- width: 100%; +-} +- +-.dac-modal-window { +- background: #fff; +- box-sizing: border-box; +- margin: 20px auto; +- -webkit-transition: -webkit-transform .3s; +- transition: transform .3s; +- -webkit-transform: translate3d(0, -30px, 0); +- transform: translate3d(0, -30px, 0); +- width: 960px; +-} +- +-.dac-modal.dac-active .dac-modal-window { +- -webkit-transform: translate3d(0, 0, 0); +- transform: translate3d(0, 0, 0); +-} +- +-.dac-modal-header { +- background: #00695c; +- padding: 35px 35px 30px; +- position: relative; +-} +- +-.dac-has-small-header .dac-modal-header { +- padding: 10px 20px; +-} +- +-.dac-modal-header-actions { +- padding: 8px; +- position: absolute; +- right: 5px; +- top: 5px; +-} +- +-.dac-modal-header-open, .dac-modal-header-close { +- background: none; +- border: none; +- cursor: pointer; +- line-height: 0; +- outline: 0; +- opacity: .7; +- -webkit-transition: background-color .3s; +- transition: background-color .3s; +-} +- +-.dac-modal-header-open:active, .dac-modal-header-close:active { +- background: rgba(255, 255, 255, 0.2); +-} +- +-.dac-modal-header-close:before { +- content: ''; +- top: -1px; +- position: relative; +-} +- +-.dac-modal-header-open { +- margin: 10px; +-} +- +-.dac-modal-header-title { +- color: #fff; +- font-size: 24px; +- font-weight: 300; +- line-height: 32px; +- padding: 0 150px 0 0; +-} +- +-.dac-has-small-header .dac-modal-header-title { +- font-size: 16px; +- font-weight: 500; +-} +- +-.dac-modal-header-subtitle { +- bottom: 0; +- color: #fff; +- display: inline-block; +- font: inherit; +- font-size: 14px; +- margin: 0; +- opacity: .8; +- position: absolute; +- right: 0; +-} +- +-.dac-modal-content { +- padding: 12px 35px; +-} +- +-.dac-modal-action { +- margin: 0; +-} +- +-.dac-modal-footer { +- padding: 24px 35px; +-} +- +-@media (max-width: 1000px) { +- .dac-modal-window { +- margin: 20px; +- width: auto; +- } +- +- .dac-modal-container { +- z-index: auto; +- } +-} +- +-@media (max-width: 719px) { +- .dac-modal-window { +- margin: 10px; +- } +- +- .dac-modal-header { +- padding: 35px 10px 10px; +- } +- +- .dac-modal-header-title { +- font-size: 16px; +- line-height: 24px; +- padding: 0; +- } +- +- .dac-modal-header-subtitle { +- display: block; +- margin: 0; +- position: static; +- text-align: right; +- } +- +- .dac-modal-header-actions { +- top: 1px; +- } +- +- .dac-modal-content { +- padding: 10px; +- } +- +- .dac-modal-footer { +- border-top: 1px solid #e3e3e3; +- padding: 35px 10px; +- } +-} +- +-.newsletter .dac-modal-footer { +- padding-top: 0; +- text-align: right; +-} +- +-.newsletter-checkboxes { +- padding-top: 20px; +-} +- +-.newsletter-success-message { +- font-size: 32px; +- line-height: 1.4; +- padding: 40px 30px; +- text-align: center; +-} +- +-@media (max-width: 719px) { +- .newsletter-success-message { +- font-size: 16px; +- padding: 12px 0 0; +- } +-} +- +-@media (min-width: 720px) { +- .newsletter-checkboxes { +- padding-top: 46px; +- } +- +- .newsletter-leftCol { +- padding-right: 40px; +- } +- +- .newsletter-rightCol { +- padding-left: 40px; +- } +-} +- +-@media (max-width: 719px) { +- .newsletter .dac-modal-footer { +- margin-top: 30px; +- padding: 30px 10px; +- text-align: center; +- } +-} +- +-.dac-blog-reader { +- padding: 50px 90px; +-} +- +-.dac-blog-reader-title { +- color: #333; +- font-size: 45px; +- font-weight: 300; +- line-height: 1.2; +- padding: 10px 0; +-} +- +-.dac-blog-reader-date { +- color: #b8b8b8; +- font-size: 12px; +- font-weight: 600; +- line-height: 1; +- text-transform: uppercase; +-} +- +-.dac-blog-reader-text > p:first-child i { +- display: inline-block; +- margin-bottom: 40px; +-} +- +-.dac-blog-reader-text li { +- margin-bottom: 0; +-} +- +-.dac-blog-reader-text iframe { +- margin-left: auto !important; +- margin-right: auto !important; +- max-width: 100%; +-} +- +-@media (max-width: 719px) { +- .dac-blog-reader { +- padding: 30px 20px; +- } +-} +- +-.dac-custom-search { +- background: #fff; +- margin: 0 -10px; +- padding: 20px 10px; +- z-index: 1; +-} +- +-.dac-custom-search .dac-fab, .dac-custom-search .dac-button-social { +- top: -48px; +-} +- +-.dac-custom-search-section-title { +- color: #505050; +-} +- +-.dac-custom-search-entry { +- margin-bottom: 36px; +- margin-top: 24px; +- margin-left:10px; +-} +- +-.dac-custom-search-entry.cols:after { +- clear: none; } +- +-.dac-custom-search-image-wrapper { +- float: left; +- position: relative; +-} +- +-.dac-custom-search-image { +- background-size: cover; +- height: 112px; +- width:150px; +- margin-right:15px; +-} +- +-.dac-custom-search-text-wrapper { +- position: relative; +-} +- +-.dac-custom-search-title { +- color: #333; +- font-size: 14px; +- font-weight: 700; +- line-height: 24px; +- padding: 0; +- clear:none; +-} +- +-.dac-custom-search-title a { +- color: inherit; +-} +- +-.dac-custom-search-section { +- color: #999; +- font-size: 16px; +- font-variant: small-caps; +- font-weight: 700; +- margin: -5px 0 0 0; +-} +- +-.dac-custom-search-snippet { +- color: #666; +- margin: 0; +-} +- +-.dac-custom-search-link { +- font-weight: 500; +- word-wrap: break-word; +- width: 100%; +-} +- +-.dac-custom-search-load-more { +- background: none; +- border: none; +- color: #333; +- cursor: pointer; +- display: block; +- font-size: 14px; +- font-weight: 700; +- margin: 75px auto; +- outline: none; +- padding: 10px; +-} +- +-.dac-custom-search-load-more:hover { +- opacity: 0.7; +-} +- +-.dac-custom-search-no-results { +- color: #999; +-} +- +-.dac-search-hero { +- font-size: 16px; +- padding: 50px 0 14px 0; +-} +- +-.dac-search-results { +- opacity: 0; +- visibility: hidden; +- -webkit-transition: visibility 0s linear 300ms, opacity 300ms linear; +- transition: visibility 0s linear 300ms, opacity 300ms linear; +- background-color: #fff; +- bottom: 0; +- left: 0; +- overflow-y: auto; +- padding: 0 10px; +- position: fixed; +- right: 0; +- -webkit-transition: opacity 100ms; +- transition: opacity 100ms; +- top: 64px; +- z-index: 50; +-} +- +-.dac-nav-animating .dac-search-results { +- -webkit-transition: opacity 100ms, padding .3s; +- transition: opacity 100ms, padding .3s; +-} +- +-.dac-search-results * { +- box-sizing: border-box; +-} +- +-.dac-search-open .dac-search-results { +- opacity: 1; +- visibility: visible; +-} +- +-.dac-search-results-content { +- background: #eceff1; +- margin: 0 -10px; +- padding: 0 10px; +-} +- +-.dac-search-results-for { +- margin-bottom: -5px; +- overflow: hidden; +- padding-top: 5px; +-} +- +-.dac-search-results-for span { +- color: #039bef; +-} +- +-.dac-search-mode .dac-search-results-for { +- display: none; +-} +- +-.dac-search-results-history { +- background: #eceff1; +- min-height: 100%; +- margin: 0 -10px; +- padding: 0 10px; +-} +- +-.dac-search-results-hero { +- padding-top: 20px; +-} +- +-.dac-search-results-metadata { +- padding-bottom: 40px; +-} +- +-#dac-search-results-reference { +- float:right; +- z-index:999; +-} +- +-@media (max-width: 719px) { +- #dac-search-results-reference { +- float:none; +- } +-} +- +-.dac-search-results-reference { +- background: white; +- box-shadow: 0px 1px 3px 0px rgba(0, 0, 0, 0.21); +- margin: 0 0 20px 0; +- overflow: hidden; +- padding: 6px 0 4px; +-} +- +-.dac-search-results-reference .namespace { +- color: #666; +-} +- +-.dac-search-results-reference.is-expanded { +- height: auto; +-} +- +-.dac-search-results-reference-header { +- color: #999; +- font-size: 16px; +- font-variant: small-caps; +- font-weight: 700; +- margin: 0; +- padding: 18px 12px 0; +- text-transform: lowercase; +-} +- +-.dac-search-results-reference-header:first-child { +- padding-top: 0; +-} +- +-.dac-search-results-reference-entry { +- margin: 0; +-} +- +-.dac-search-results-reference-entry a { +- color: #333; +- display: block; +- font-size: 0.81em; +- line-height: 1.5em; +- padding: 0 12px 5px 12px; +- width: 100%; +- white-space: nowrap; +-} +- +-ul.dac-search-results-reference { +-list-style: none; +-} +- +-ul.dac-search-results-reference li[data-toggle="show-more"] { +- cursor:pointer; +-} +- +-ul.dac-search-results-reference.is-expanded li[data-toggle="show-more"] { +- display:none; +-} +- +-.dac-search-results-reference-entry a:hover { +- background-color: #eceff1; +-} +- +-.dac-search-results-reference-entry em { +- font-style: normal; +- font-weight: 700; +-} +- +-.dac-search-results-reference-entry-empty { +- color: #999; +- font-size: 0.81em; +- margin: 0; +- padding: 2px 12px 14px; +-} +- +-.dac-search-results-resources { +- margin: 0; +-} +- +-.dac-search-results-resources .resource-card { +- border-right: 2px solid #999; +-} +- +-.dac-search-results-resources .resource-card-about { +- border-right: 2px solid #6ab344; +-} +- +-.dac-search-results-resources .resource-card-about .section { +- color: #6ab344; +-} +- +-.dac-search-results-resources .resource-card-develop { +- border-right: 2px solid #ff7043; +-} +- +-.dac-search-results-resources .resource-card-develop .section { +- color: #ff7043; +-} +- +-.dac-search-results-resources .resource-card-design { +- border-right: 2px solid #00bcd4; +-} +- +-.dac-search-results-resources .resource-card-design .section { +- color: #00bcd4; +-} +- +-.dac-search-results-resources .resource-card-distribute { +- border-right: 2px solid #afb42b; +-} +- +-.dac-search-results-resources .resource-card-distribute .section { +- color: #afb42b; +-} +- +-@media (max-width: 719px) { +- .dac-search-results-reference.no-results { +- display: none; +- } +-} +- +-@media (min-width: 980px) { +- .dac-nav-open.dac-search-open .dac-search-results { +- padding-left: 260px; +- } +- +- .dac-search-mode.dac-search-open .dac-search-results { +- padding-left: 10px; +- } +-} +- +-.dac-selected { +- color: #039bef !important; +-} +- +-.dac-selected em { +- color: #039bef; +-} +- +-.resource-card.dac-selected { +- box-shadow: 0px 1px 10px 0px rgba(3, 155, 239, 0.7); +-} +- +-.resource-card.dac-selected em { +- color: #333; +-} +- +-.dac-expand, .dac-section { +- margin-left: -20px; +- margin-right: -20px; +- padding-left: 20px; +- padding-right: 20px; +-} +- +-@media (max-width: 719px) { +- .dac-expand, .dac-section { +- margin-left: -10px; +- margin-right: -10px; +- padding-left: 10px; +- padding-right: 10px; +- } +-} +- +-.dac-invert { +- color: #b3b3b3; +- color: rgba(255, 255, 255, 0.7); +-} +- +-.dac-invert h1, .dac-invert h2, .dac-invert h3 { +- color: #fff; +-} +- +-.dac-light.dac-hero, .dac-light.dac-section { +- background-color: #eceff1; +-} +- +-.dac-gray.dac-hero, .dac-gray.dac-section { +- background-color: #d8dfe2; +-} +- +-.dac-gray-dark.dac-hero, .dac-gray-dark.dac-section { +- background-color: #b0bec5; +-} +- +-.dac-dark.dac-hero, .dac-dark.dac-section { +- background-color: #37474f; +-} +- +-.dac-red.dac-hero, .dac-red.dac-section { +- background-color: #dc4d38; +-} +- +-.dac-blue.dac-hero, +-.dac-blue.dac-section { +- background-color: #0277bd; +-} +- +-.dac-blue.dac-invert .dac-hero-description, +-.dac-blue.dac-invert .dac-section-subtitle { +- color: #fff; +-} +- +-.dac-dark-gray.dac-hero, +-.dac-dark-gray.dac-section { +- background-color: #455a64; +-} +- +-.dac-bg-opacity::after { +- background-color: rgba(0, 0, 0, .3); +- content : ""; +- display: block; +- position: absolute; +- top: 0; +- left: 0; +- width: 100%; +- height: 100%; +- z-index: 1; +-} +- +-.dac-hero-cta, .dac-section-title, .dac-section-links { +- color: #212121; +- color: rgba(0, 0, 0, 0.87); +-} +- +-.dac-invert .dac-hero-cta, .dac-invert .dac-section-title, .dac-invert .dac-section-links { +- color: white; +-} +- +-.dac-hero-cta .dac-sprite, .dac-section-title .dac-sprite, .dac-section-links .dac-sprite, .dac-hero-cta .dac-modal-header-close:before, .dac-section-title .dac-modal-header-close:before, .dac-section-links .dac-modal-header-close:before, .dac-hero-cta .paging-links .prev-page-link:before, .paging-links .dac-hero-cta .prev-page-link:before, .dac-section-title .paging-links .prev-page-link:before, .paging-links .dac-section-title .prev-page-link:before, .dac-section-links .paging-links .prev-page-link:before, .paging-links .dac-section-links .prev-page-link:before, .dac-hero-cta .paging-links .next-page-link:before, .paging-links .dac-hero-cta .next-page-link:before, .dac-section-title .paging-links .next-page-link:before, .paging-links .dac-section-title .next-page-link:before, .dac-section-links .paging-links .next-page-link:before, .paging-links .dac-section-links .next-page-link:before, .dac-hero-cta .paging-links .next-class-link:before, .paging-links .dac-hero-cta .next-class-link:before, .dac-section-title .paging-links .next-class-link:before, .paging-links .dac-section-title .next-class-link:before, .dac-section-links .paging-links .next-class-link:before, .paging-links .dac-section-links .next-class-link:before, .dac-hero-cta .paging-links .start-class-link:after, .paging-links .dac-hero-cta .start-class-link:after, .dac-section-title .paging-links .start-class-link:after, .paging-links .dac-section-title .start-class-link:after, .dac-section-links .paging-links .start-class-link:after, .paging-links .dac-section-links .start-class-link:after { +- opacity: .87; +-} +- +-.dac-invert .dac-hero-cta .dac-sprite, .dac-invert .dac-section-title .dac-sprite, .dac-invert .dac-section-links .dac-sprite, .dac-invert .dac-hero-cta .dac-modal-header-close:before, .dac-invert .dac-section-title .dac-modal-header-close:before, .dac-invert .dac-section-links .dac-modal-header-close:before, .dac-invert .dac-hero-cta .paging-links .prev-page-link:before, .paging-links .dac-invert .dac-hero-cta .prev-page-link:before, .dac-invert .dac-section-title .paging-links .prev-page-link:before, .paging-links .dac-invert .dac-section-title .prev-page-link:before, .dac-invert .dac-section-links .paging-links .prev-page-link:before, .paging-links .dac-invert .dac-section-links .prev-page-link:before, .dac-invert .dac-hero-cta .paging-links .next-page-link:before, .paging-links .dac-invert .dac-hero-cta .next-page-link:before, .dac-invert .dac-section-title .paging-links .next-page-link:before, .paging-links .dac-invert .dac-section-title .next-page-link:before, .dac-invert .dac-section-links .paging-links .next-page-link:before, .paging-links .dac-invert .dac-section-links .next-page-link:before, .dac-invert .dac-hero-cta .paging-links .next-class-link:before, .paging-links .dac-invert .dac-hero-cta .next-class-link:before, .dac-invert .dac-section-title .paging-links .next-class-link:before, .paging-links .dac-invert .dac-section-title .next-class-link:before, .dac-invert .dac-section-links .paging-links .next-class-link:before, .paging-links .dac-invert .dac-section-links .next-class-link:before, .dac-invert .dac-hero-cta .paging-links .start-class-link:after, .paging-links .dac-invert .dac-hero-cta .start-class-link:after, .dac-invert .dac-section-title .paging-links .start-class-link:after, .paging-links .dac-invert .dac-section-title .start-class-link:after, .dac-invert .dac-section-links .paging-links .start-class-link:after, .paging-links .dac-invert .dac-section-links .start-class-link:after { +- opacity: 1; +-} +- +-.dac-hero-tag, .dac-hero-description, .dac-section-subtitle { +- color: #757575; +- color: rgba(0, 0, 0, 0.54); +-} +- +-.dac-invert .dac-hero-tag, .dac-invert .dac-hero-description, .dac-invert .dac-section-subtitle { +- color: #b3b3b3; +- color: rgba(255, 255, 255, 0.7); +-} +- +-.dac-hero.dac-no-min-height { +- min-height: 0; +-} +- +-.dac-hero-half-bg { +- background-size: cover; +- background-repeat: no-repeat; +- float: right; +- height: 440px; +-} +- +-.dac-hero-half-bg-centered { +- background-position: center; +- background-repeat: no-repeat; +- background-size: cover; +- float: right; +- height: 440px; +-} +- +-@media only screen and (-webkit-min-device-pixel-ratio: 2), +-only screen and (-moz-min-device-pixel-ratio: 2), +-only screen and (min-device-pixel-ratio: 2), +-only screen and (min-resolution: 192dpi), +-only screen and (min-resolution: 2dppx) { +- .dac-hero-half-bg, +- .dac-hero-half-bg-centered { +- background-size: "" ""; +- } +-} +- +-@media (max-width: 719px) { +- .dac-hero-half-bg, +- .dac-hero-half-bg-centered { +- background-position: center; +- background-size: auto 100%; +- float: none; +- height: 200px; +- margin-top: 32px; +- } +-} +- +-.dac-section { +- background-position: 50% 50%; +- background-size: cover; +- padding-bottom: 84px; +- padding-top: 84px; +- position: relative; +-} +- +-@media (max-width: 719px) { +- .dac-section { +- padding-bottom: 52px; +- padding-top: 52px; +- } +-} +- +-.dac-section.dac-small, +-.dac-hero.dac-small { +- padding-bottom: 32px; +- padding-top: 32px; +-} +- +-.dac-section.dac-slim { +- padding-bottom: 0; +- padding-top: 0; +-} +- +-.dac-section-title { +- text-align: center; +- padding-bottom: 40px; +- padding-top: 0; +-} +- +-.dac-section-subtitle { +- font-size: 16px; +- padding-bottom: 40px; +- margin-top: -24px; +- text-align: center; +-} +- +-.dac-section-links { +- font-size: 16px; +- list-style: none; +- line-height: 40px; +- margin: 16px 0 0; +- text-align: center; +-} +- +-@media (max-width: 719px) { +- .dac-section-links { +- margin-left: -8px; +- text-align: left; +- } +-} +- +-.dac-section-link { +- cursor: pointer; +- display: inline-block; +- margin: 0 32px; +- -webkit-transition: opacity .3s; +- transition: opacity .3s; +-} +- +-.dac-section-link:hover { +- opacity: .54; +-} +- +-@media (max-width: 719px) { +- .dac-section-link { +- display: block; +- margin: 0; +- } +-} +- +-.dac-section-link a { +- color: inherit; +-} +- +-/* +-SCSS variables are information about icon's compiled state, stored under its original file name +- +-.icon-home { +- width: $icon-home-width; +-} +- +-The large array-like variables contain all information about a single icon +-$icon-home: x y offset_x offset_y width height total_width total_height image_path; +- +-At the bottom of this section, we provide information about the spritesheet itself +-$spritesheet: width height image $spritesheet-sprites; +-*/ +-.dac-sprite, .dac-modal-header-close:before, .paging-links .prev-page-link:before, .paging-links .next-page-link:before, .paging-links .next-class-link:before, .paging-links .start-class-link:after, .Video-button--picture-in-picture, .Video-button--close, a.video-shadowbox-button.white::after, #tb li:before, +-#qv li:before { +- background-image: url(../images/sprite.png); +- display: inline-block; +- vertical-align: middle; +-} +- +-@media (-webkit-min-device-pixel-ratio: 1.5), (min-resolution: 1.5dppx), (min-resolution: 144px) { +- +- .dac-sprite, +- .dac-modal-header-close:before, +- .paging-links .prev-page-link:before, +- .paging-links .next-page-link:before, +- .paging-links .next-class-link:before, +- .paging-links .start-class-link:after, +- .Video-button--picture-in-picture, +- .Video-button--close, +- a.video-shadowbox-button.white::after, +- #tb li:before, +- #qv li:before { +- background-image: url(../images/sprite_2x.png); +- background-size: 36px 900px; +- } +-} +- +-.dac-chevron { +- background-size: 9px 39px; +- display: inline-block; +- height: 13px; +- text-indent: -9999px; +- width: 9px; +-} +- +-.dac-sprite.dac-auto-chevron, +-.dac-auto-chevron.dac-modal-header-close:before, +-.paging-links .dac-auto-chevron.prev-page-link:before, +-.paging-links .dac-auto-chevron.next-page-link:before, +-.paging-links .dac-auto-chevron.next-class-link:before, +-.paging-links .dac-auto-chevron.start-class-link:after { +- background-position: 0px -669px; +- height: 24px; +- width: 24px; +- vertical-align: -6px; +-} +- +-.dac-invert .dac-sprite.dac-auto-chevron, .dac-invert .dac-auto-chevron.dac-modal-header-close:before, .dac-invert .paging-links .dac-auto-chevron.prev-page-link:before, .paging-links .dac-invert .dac-auto-chevron.prev-page-link:before, .dac-invert .paging-links .dac-auto-chevron.next-page-link:before, .paging-links .dac-invert .dac-auto-chevron.next-page-link:before, .dac-invert .paging-links .dac-auto-chevron.next-class-link:before, .paging-links .dac-invert .dac-auto-chevron.next-class-link:before, .dac-invert .paging-links .dac-auto-chevron.start-class-link:after, .paging-links .dac-invert .dac-auto-chevron.start-class-link:after { +- background-position: 0px -513px; +- height: 24px; +- width: 24px; +-} +- +-.dac-sprite.dac-auto-chevron-large, .dac-auto-chevron-large.dac-modal-header-close:before, .paging-links .dac-auto-chevron-large.prev-page-link:before, .paging-links .dac-auto-chevron-large.next-page-link:before, .paging-links .dac-auto-chevron-large.next-class-link:before, .paging-links .dac-auto-chevron-large.start-class-link:after { +- background-position: 0px -695px; +- height: 36px; +- width: 36px; +- vertical-align: -10px; +-} +- +-.dac-invert .dac-sprite.dac-auto-chevron-large, +-.dac-invert .dac-auto-chevron-large.dac-modal-header-close:before, +-.dac-invert .paging-links .dac-auto-chevron-large.prev-page-link:before, +-.paging-links .dac-invert .dac-auto-chevron-large.prev-page-link:before, +-.dac-invert .paging-links .dac-auto-chevron-large.next-page-link:before, +-.paging-links .dac-invert .dac-auto-chevron-large.next-page-link:before, +-.dac-invert .paging-links .dac-auto-chevron-large.next-class-link:before, +-.paging-links .dac-invert .dac-auto-chevron-large.next-class-link:before, +-.dac-invert .paging-links .dac-auto-chevron-large.start-class-link:after, +-.paging-links .dac-invert .dac-auto-chevron-large.start-class-link:after { +- background-position: 0px -771px; +- height: 36px; +- width: 36px; +-} +- +-.dac-sprite.dac-auto-unfold-less, .dac-auto-unfold-less.dac-modal-header-close:before, .paging-links .dac-auto-unfold-less.prev-page-link:before, .paging-links .dac-auto-unfold-less.next-page-link:before, .paging-links .dac-auto-unfold-less.next-class-link:before, .paging-links .dac-auto-unfold-less.start-class-link:after { +- background-position: 0px -487px; +- height: 24px; +- width: 24px; +- vertical-align: -6px; } +- .dac-invert .dac-sprite.dac-auto-unfold-less, .dac-invert .dac-auto-unfold-less.dac-modal-header-close:before, .dac-invert .paging-links .dac-auto-unfold-less.prev-page-link:before, .paging-links .dac-invert .dac-auto-unfold-less.prev-page-link:before, .dac-invert .paging-links .dac-auto-unfold-less.next-page-link:before, .paging-links .dac-invert .dac-auto-unfold-less.next-page-link:before, .dac-invert .paging-links .dac-auto-unfold-less.next-class-link:before, .paging-links .dac-invert .dac-auto-unfold-less.next-class-link:before, .dac-invert .paging-links .dac-auto-unfold-less.start-class-link:after, .paging-links .dac-invert .dac-auto-unfold-less.start-class-link:after { +- background-position: 0px -565px; +- height: 24px; +- width: 24px; } +- +-.dac-sprite.dac-auto-unfold-more, .dac-auto-unfold-more.dac-modal-header-close:before, .paging-links .dac-auto-unfold-more.prev-page-link:before, .paging-links .dac-auto-unfold-more.next-page-link:before, .paging-links .dac-auto-unfold-more.next-class-link:before, .paging-links .dac-auto-unfold-more.start-class-link:after { +- background-position: 0px -539px; +- height: 24px; +- width: 24px; +- vertical-align: -6px; } +- .dac-invert .dac-sprite.dac-auto-unfold-more, .dac-invert .dac-auto-unfold-more.dac-modal-header-close:before, .dac-invert .paging-links .dac-auto-unfold-more.prev-page-link:before, .paging-links .dac-invert .dac-auto-unfold-more.prev-page-link:before, .dac-invert .paging-links .dac-auto-unfold-more.next-page-link:before, .paging-links .dac-invert .dac-auto-unfold-more.next-page-link:before, .dac-invert .paging-links .dac-auto-unfold-more.next-class-link:before, .paging-links .dac-invert .dac-auto-unfold-more.next-class-link:before, .dac-invert .paging-links .dac-auto-unfold-more.start-class-link:after, .paging-links .dac-invert .dac-auto-unfold-more.start-class-link:after { +- background-position: 0px -305px; +- height: 24px; +- width: 24px; } +- +-.dac-sprite.dac-arrow-down-gray, .dac-arrow-down-gray.dac-modal-header-close:before, .paging-links .dac-arrow-down-gray.prev-page-link:before, .paging-links .dac-arrow-down-gray.next-page-link:before, .paging-links .dac-arrow-down-gray.next-class-link:before, .paging-links .dac-arrow-down-gray.start-class-link:after { +- background-position: 0px 0px; +- height: 11px; +- width: 19px; } +- +-.dac-sprite.dac-arrow-right, .dac-arrow-right.dac-modal-header-close:before, .paging-links .dac-arrow-right.prev-page-link:before, .paging-links .dac-arrow-right.next-page-link:before, .paging-links .dac-arrow-right.next-class-link:before, .paging-links .dac-arrow-right.start-class-link:after { +- background-position: 0px -215px; +- height: 18px; +- width: 11px; } +- +-.dac-sprite.dac-back-arrow, .dac-back-arrow.dac-modal-header-close:before, .paging-links .dac-back-arrow.prev-page-link:before, .paging-links .dac-back-arrow.next-page-link:before, .paging-links .dac-back-arrow.next-class-link:before, .paging-links .dac-back-arrow.start-class-link:after { +- background-position: 0px -123px; +- height: 16px; +- width: 16px; } +- +-.dac-sprite.dac-chevron-large-right-black, .dac-chevron-large-right-black.dac-modal-header-close:before, .paging-links .dac-chevron-large-right-black.prev-page-link:before, .paging-links .dac-chevron-large-right-black.next-page-link:before, .paging-links .dac-chevron-large-right-black.next-class-link:before, .paging-links .dac-chevron-large-right-black.start-class-link:after { +- background-position: 0px -695px; +- height: 36px; +- width: 36px; } +- +-.dac-sprite.dac-chevron-large-right-white, .dac-chevron-large-right-white.dac-modal-header-close:before, .paging-links .dac-chevron-large-right-white.prev-page-link:before, .paging-links .dac-chevron-large-right-white.next-page-link:before, .paging-links .dac-chevron-large-right-white.next-class-link:before, .paging-links .dac-chevron-large-right-white.start-class-link:after { +- background-position: 0px -771px; +- height: 36px; +- width: 36px; } +- +-.dac-sprite.dac-chevron-right-black, .dac-chevron-right-black.dac-modal-header-close:before, .paging-links .dac-chevron-right-black.prev-page-link:before, .paging-links .dac-chevron-right-black.next-page-link:before, .paging-links .dac-chevron-right-black.next-class-link:before, .paging-links .dac-chevron-right-black.start-class-link:after { +- background-position: 0px -669px; +- height: 24px; +- width: 24px; } +- +-.dac-sprite.dac-chevron-right-white, .dac-chevron-right-white.dac-modal-header-close:before, .paging-links .dac-chevron-right-white.prev-page-link:before, .paging-links .dac-chevron-right-white.next-page-link:before, .paging-links .dac-chevron-right-white.next-class-link:before, .paging-links .dac-chevron-right-white.start-class-link:after { +- background-position: 0px -513px; +- height: 24px; +- width: 24px; } +- +-.dac-sprite.dac-close-black, .dac-close-black.dac-modal-header-close:before, .paging-links .dac-close-black.prev-page-link:before, .paging-links .dac-close-black.next-page-link:before, .paging-links .dac-close-black.next-class-link:before, .paging-links .dac-close-black.start-class-link:after { +- background-position: 0px -89px; +- height: 14px; +- width: 14px; } +- +-.dac-sprite.dac-close-video-white, .dac-modal-header-close:before, .paging-links .dac-close-video-white.prev-page-link:before, .paging-links .prev-page-link.dac-modal-header-close:before, .paging-links .dac-close-video-white.next-page-link:before, .paging-links .next-page-link.dac-modal-header-close:before, .paging-links .dac-close-video-white.next-class-link:before, .paging-links .next-class-link.dac-modal-header-close:before, .paging-links .dac-close-video-white.start-class-link:after { +- background-position: 0px -435px; +- height: 24px; +- width: 24px; } +- +-.dac-sprite.dac-close, .dac-close.dac-modal-header-close:before, .paging-links .dac-close.prev-page-link:before, .paging-links .dac-close.next-page-link:before, .paging-links .dac-close.next-class-link:before, .paging-links .dac-close.start-class-link:after { +- background-position: 0px -27px; +- height: 12px; +- width: 12px; } +- +-.dac-sprite.dac-enlarge-video-white, .dac-enlarge-video-white.dac-modal-header-close:before, .paging-links .dac-enlarge-video-white.prev-page-link:before, .paging-links .dac-enlarge-video-white.next-page-link:before, .paging-links .dac-enlarge-video-white.next-class-link:before, .paging-links .dac-enlarge-video-white.start-class-link:after { +- background-position: 0px -409px; +- height: 24px; +- width: 24px; } +- +-.dac-sprite.dac-expand-less-black, .dac-expand-less-black.dac-modal-header-close:before, .paging-links .dac-expand-less-black.prev-page-link:before, .paging-links .dac-expand-less-black.next-page-link:before, .paging-links .dac-expand-less-black.next-class-link:before, .paging-links .dac-expand-less-black.start-class-link:after { +- background-position: 0px -383px; +- height: 24px; +- width: 24px; } +- +-.dac-sprite.dac-expand-more-black, .dac-expand-more-black.dac-modal-header-close:before, .paging-links .dac-expand-more-black.prev-page-link:before, .paging-links .dac-expand-more-black.next-page-link:before, .paging-links .dac-expand-more-black.next-class-link:before, .paging-links .dac-expand-more-black.start-class-link:after { +- background-position: 0px -357px; +- height: 24px; +- width: 24px; } +- +-.dac-sprite.dac-fullscreen-exit, .dac-fullscreen-exit.dac-modal-header-close:before, .paging-links .dac-fullscreen-exit.prev-page-link:before, .paging-links .dac-fullscreen-exit.next-page-link:before, .paging-links .dac-fullscreen-exit.next-class-link:before, .paging-links .dac-fullscreen-exit.start-class-link:after { +- background-position: 0px -331px; +- height: 24px; +- width: 24px; } +- +-.dac-sprite.dac-fullscreen, .dac-fullscreen.dac-modal-header-close:before, .paging-links .dac-fullscreen.prev-page-link:before, .paging-links .dac-fullscreen.next-page-link:before, .paging-links .dac-fullscreen.next-class-link:before, .paging-links .dac-fullscreen.start-class-link:after { +- background-position: 0px -279px; +- height: 24px; +- width: 24px; } +- +-.dac-sprite.dac-google-play, .dac-google-play.dac-modal-header-close:before, .paging-links .dac-google-play.prev-page-link:before, .paging-links .dac-google-play.next-page-link:before, .paging-links .dac-google-play.next-class-link:before, .paging-links .dac-google-play.start-class-link:after { +- background-position: 0px -235px; +- height: 20px; +- width: 17px; } +- +-.dac-sprite.dac-gplus, .dac-gplus.dac-modal-header-close:before, .paging-links .dac-gplus.prev-page-link:before, .paging-links .dac-gplus.next-page-link:before, .paging-links .dac-gplus.next-class-link:before, .paging-links .dac-gplus.start-class-link:after { +- background-position: 0px -809px; +- height: 36px; +- width: 36px; } +- +-.dac-sprite.dac-mail, .dac-mail.dac-modal-header-close:before, .paging-links .dac-mail.prev-page-link:before, .paging-links .dac-mail.next-page-link:before, .paging-links .dac-mail.next-class-link:before, .paging-links .dac-mail.start-class-link:after { +- background-position: 0px -13px; +- height: 12px; +- width: 16px; } +- +-.dac-sprite.dac-nav-back-blue, .dac-nav-back-blue.dac-modal-header-close:before, .paging-links .prev-page-link:before, .paging-links .dac-nav-back-blue.next-page-link:before, .paging-links .dac-nav-back-blue.next-class-link:before, .paging-links .dac-nav-back-blue.start-class-link:after { +- background-position: 0px -105px; +- height: 16px; +- width: 16px; } +- +-.dac-sprite.dac-nav-back, .dac-nav-back.dac-modal-header-close:before, .paging-links .dac-nav-back.prev-page-link:before, .paging-links .dac-nav-back.next-page-link:before, .paging-links .dac-nav-back.next-class-link:before, .paging-links .dac-nav-back.start-class-link:after { +- background-position: 0px -177px; +- height: 16px; +- width: 16px; } +- +-/* The back button in Studio and NDK left nav */ +-.dac-nav-back-button.back-to-dev .dac-sprite.dac-nav-back { +- background-position: 0px -884px; +- height: 16px; +- width: 16px; +-} +- +-.dac-sprite.dac-nav-forward-blue, .dac-nav-forward-blue.dac-modal-header-close:before, .paging-links .dac-nav-forward-blue.prev-page-link:before, .paging-links .next-page-link:before, .paging-links .next-class-link:before, .paging-links .start-class-link:after { +- background-position: 0px -159px; +- height: 16px; +- width: 16px; } +- +-.dac-sprite.dac-nav-forward, .dac-nav-forward.dac-modal-header-close:before, .paging-links .dac-nav-forward.prev-page-link:before, .paging-links .dac-nav-forward.next-page-link:before, .paging-links .dac-nav-forward.next-class-link:before, .paging-links .dac-nav-forward.start-class-link:after { +- background-position: 0px -141px; +- height: 16px; +- width: 16px; } +- +-.dac-sprite.dac-open-in-new, .dac-open-in-new.dac-modal-header-close:before, .paging-links .dac-open-in-new.prev-page-link:before, .paging-links .dac-open-in-new.next-page-link:before, .paging-links .dac-open-in-new.next-class-link:before, .paging-links .dac-open-in-new.start-class-link:after { +- background-position: 0px -195px; +- height: 18px; +- width: 18px; } +- +-.dac-sprite.dac-picture-in-picture-white, .dac-picture-in-picture-white.dac-modal-header-close:before, .paging-links .dac-picture-in-picture-white.prev-page-link:before, .paging-links .dac-picture-in-picture-white.next-page-link:before, .paging-links .dac-picture-in-picture-white.next-class-link:before, .paging-links .dac-picture-in-picture-white.start-class-link:after { +- background-position: 0px -461px; +- height: 24px; +- width: 24px; } +- +-.dac-sprite.dac-play-circle-grey, .dac-play-circle-grey.dac-modal-header-close:before, .paging-links .dac-play-circle-grey.prev-page-link:before, .paging-links .dac-play-circle-grey.next-page-link:before, .paging-links .dac-play-circle-grey.next-class-link:before, .paging-links .dac-play-circle-grey.start-class-link:after { +- background-position: 0px -733px; +- height: 36px; +- width: 36px; } +- +-.dac-sprite.dac-play-circle-white, .dac-play-circle-white.dac-modal-header-close:before, .paging-links .dac-play-circle-white.prev-page-link:before, .paging-links .dac-play-circle-white.next-page-link:before, .paging-links .dac-play-circle-white.next-class-link:before, .paging-links .dac-play-circle-white.start-class-link:after { +- background-position: 0px -847px; +- height: 36px; +- width: 36px; } +- +-.dac-sprite.dac-play-white, .dac-play-white.dac-modal-header-close:before, .paging-links .dac-play-white.prev-page-link:before, .paging-links .dac-play-white.next-page-link:before, .paging-links .dac-play-white.next-class-link:before, .paging-links .dac-play-white.start-class-link:after { +- background-position: 0px -257px; +- height: 20px; +- width: 16px; } +- +-.dac-sprite.dac-rss, .dac-rss.dac-modal-header-close:before, .paging-links .dac-rss.prev-page-link:before, .paging-links .dac-rss.next-page-link:before, .paging-links .dac-rss.next-class-link:before, .paging-links .dac-rss.start-class-link:after { +- background-position: 0px -41px; +- height: 14px; +- width: 14px; } +- +-.dac-sprite.dac-search-white, .dac-search-white.dac-modal-header-close:before, .paging-links .dac-search-white.prev-page-link:before, .paging-links .dac-search-white.next-page-link:before, .paging-links .dac-search-white.next-class-link:before, .paging-links .dac-search-white.start-class-link:after { +- background-position: 0px -591px; +- height: 24px; +- width: 24px; } +- +-.dac-sprite.dac-search, .dac-search.dac-modal-header-close:before, .paging-links .dac-search.prev-page-link:before, .paging-links .dac-search.next-page-link:before, .paging-links .dac-search.next-class-link:before, .paging-links .dac-search.start-class-link:after { +- background-position: 0px -617px; +- height: 24px; +- width: 24px; } +- +-.dac-sprite.dac-star-outline, .dac-star-outline.dac-modal-header-close:before, .paging-links .dac-star-outline.prev-page-link:before, .paging-links .dac-star-outline.next-page-link:before, .paging-links .dac-star-outline.next-class-link:before, .paging-links .dac-star-outline.start-class-link:after { +- background-position: 0px -643px; +- height: 24px; +- width: 24px; } +- +-.dac-sprite.dac-twitter, .dac-twitter.dac-modal-header-close:before, .paging-links .dac-twitter.prev-page-link:before, .paging-links .dac-twitter.next-page-link:before, .paging-links .dac-twitter.next-class-link:before, .paging-links .dac-twitter.start-class-link:after { +- background-position: 0px -73px; +- height: 14px; +- width: 16px; } +- +-.dac-sprite.dac-unfold-less-white, .dac-unfold-less-white.dac-modal-header-close:before, .paging-links .dac-unfold-less-white.prev-page-link:before, .paging-links .dac-unfold-less-white.next-page-link:before, .paging-links .dac-unfold-less-white.next-class-link:before, .paging-links .dac-unfold-less-white.start-class-link:after { +- background-position: 0px -565px; +- height: 24px; +- width: 24px; } +- +-.dac-sprite.dac-unfold-less, .dac-unfold-less.dac-modal-header-close:before, .paging-links .dac-unfold-less.prev-page-link:before, .paging-links .dac-unfold-less.next-page-link:before, .paging-links .dac-unfold-less.next-class-link:before, .paging-links .dac-unfold-less.start-class-link:after { +- background-position: 0px -487px; +- height: 24px; +- width: 24px; } +- +-.dac-sprite.dac-unfold-more-white, .dac-unfold-more-white.dac-modal-header-close:before, .paging-links .dac-unfold-more-white.prev-page-link:before, .paging-links .dac-unfold-more-white.next-page-link:before, .paging-links .dac-unfold-more-white.next-class-link:before, .paging-links .dac-unfold-more-white.start-class-link:after { +- background-position: 0px -305px; +- height: 24px; +- width: 24px; } +- +-.dac-sprite.dac-unfold-more, .dac-unfold-more.dac-modal-header-close:before, .paging-links .dac-unfold-more.prev-page-link:before, .paging-links .dac-unfold-more.next-page-link:before, .paging-links .dac-unfold-more.next-class-link:before, .paging-links .dac-unfold-more.start-class-link:after { +- background-position: 0px -539px; +- height: 24px; +- width: 24px; } +- +-.dac-sprite.dac-youtube, .dac-youtube.dac-modal-header-close:before, .paging-links .dac-youtube.prev-page-link:before, .paging-links .dac-youtube.next-page-link:before, .paging-links .dac-youtube.next-class-link:before, .paging-links .dac-youtube.start-class-link:after { +- background-position: 0px -57px; +- height: 14px; +- width: 18px; } +- +-/* Toast Component */ +-.dac-toast { +- background: #ffebc3; +- border-top: 1px solid #e5d4a1; +- display: none; +- color: rgba(0, 0, 0, .87); +- line-height: 1.4; +- padding: 10px; +-} +- +-.dac-toast.dac-visible { +- display: block; +-} +- +-.dac-toast-wrap { +- box-sizing: border-box; +- margin: 0 auto; +- max-width: 940px; +- padding-right: 20px; +- position: relative; +-} +- +-.dac-toast-close-btn { +- background-color: transparent; +- border: none; +- border-radius: 0; +- cursor: pointer; +- opacity: .4; +- padding: 0; +- position: absolute; +- right: 0; +- top: -2px; +-} +- +-.dac-toast-close-btn:hover, +-.dac-toast-close-btn:focus, +-.dac-toast-close-btn:active { +- opacity: 1; +- outline: none; +-} +- +-.dac-toast-close-btn .dac-button.dac-raised.dac-primary{ +- margin: 0; +- padding: 0; +-} +- +-.dac-toast-group { +- bottom: 0; +- left: 0; +- position: fixed; +- right: 0; +- z-index: 60; +-} +- +-.dac-toast.dac-danger { +- background-color: #ffccbc; +- border-top-color: #e5b7a9; +-} +- +-.dac-toast.dac-success { +- background-color: #cdedc8; +- border-top-color: #c6d5b4; +-} +- +-@media (max-width: 719px) { +- .dac-toast-close-btn { +- position: relative; +- top: 0; +- margin: 10px 0 0; +- display: block; +- } +-} +- +-.dac-tab-item { +- box-sizing: border-box; +- cursor: pointer; +- display: table-cell; +- margin: 0; +- padding: 8px 12px; +- position: relative; +- text-align: left; } +- @media (max-width: 719px) { +- .dac-tab-item { +- padding-right: 12px; +- text-align: center; +- width: 33.33333333%; } } +- +-.dac-tab-title { +- color: #333; +- display: inline-block; +- font-size: 16px; +- font-weight: 500; +- margin: 0; } +- +-.dac-tab-arrow { +- margin-top: -2px; } +- @media (max-width: 719px) { +- .dac-tab-arrow { +- position: absolute; +- visibility: hidden; } } +- +-.dac-tab-bar { +- display: inline-block; +- list-style-type: none; +- margin: 0 0 0 12px; +- vertical-align: middle; +- overflow: hidden; } +- @media (max-width: 719px) { +- .dac-tab-bar { +- display: table; +- margin-left: 0; +- width: 100%; } } +- +-.dac-tab-views { +- list-style-type: none; +- margin: 0; } +- +-.dac-tab-view { +- background: #fff; +- display: none; +- overflow: hidden; +- margin: 0 0 10px; +- padding: 20px 10px 0; +- text-align: left; } +- +-.dac-tab-item.dac-active { +- background: #fff; } +- +-.dac-tab-item.dac-active .dac-tab-arrow { +- -webkit-transform: scaleY(-1); +- -ms-transform: scaleY(-1); +- transform: scaleY(-1); } +- +-.dac-tab-view.dac-active { +- display: block; } +- +-.dac-toggle-expand { +- cursor: pointer; +- display: inline-block; } +- +-.dac-toggle-collapse { +- cursor: pointer; +- display: none; } +- +-.dac-toggle.is-expanded .dac-toggle-expand { +- display: none; } +- +-.dac-toggle.is-expanded .dac-toggle-collapse { +- display: inline-block; } +- +-.dac-toggle-content { +- clear: left; +- overflow: hidden; +- max-height: 0; +- -webkit-transition: .3s max-height; +- transition: .3s max-height; } +- +-.dac-toggle.is-expanded .dac-toggle-content { +- max-height: none; } +- +-.dac-toggle.dac-mobile .dac-toggle-content { +- max-height: none; } +- +-@media (max-width: 719px) { +- .dac-toggle.dac-mobile .dac-toggle-content { +- max-height: 0; } +- .dac-toggle.is-expanded .dac-toggle-content { +- max-height: none; } } +- +-/** +- * Fades out an element. +- * Applies visibility hidden when the transition is finished. +- * +- * Use opacity: 1; to show the element. +- */ +-.dac-visible-mobile-block, .dac-mobile-only, +-.dac-visible-mobile-inline, +-.dac-visible-mobile-inline-block, +-.dac-visible-tablet-block, +-.dac-visible-tablet-inline, +-.dac-visible-tablet-inline-block, +-.dac-visible-desktop-block, +-.dac-visible-desktop-inline, +-.dac-visible-desktop-inline-block { +- display: none !important; } +- +-@media (max-width: 719px) { +- .dac-hidden-mobile { +- display: none !important; } +- .dac-visible-mobile-block, .dac-mobile-only { +- display: block !important; } +- .dac-visible-mobile-inline { +- display: inline !important; } +- .dac-visible-mobile-inline-block { +- display: inline-block !important; } } +- +-@media (min-width: 720px) and (max-width: 979px) { +- .dac-hidden-tablet { +- display: none !important; } +- .dac-visible-tablet-block { +- display: block !important; } +- .dac-visible-tablet-inline { +- display: inline !important; } +- .dac-visible-tablet-inline-block { +- display: inline-block !important; } } +- +-@media (min-width: 980px) { +- .dac-hidden-desktop { +- display: none !important; } +- .dac-visible-desktop-block { +- display: block !important; } +- .dac-visible-desktop-inline { +- display: inline !important; } +- .dac-visible-desktop-inline-block { +- display: inline-block !important; } } +- +-.dac-offset-parent { +- position: relative !important; } +- +-/** +- * Hide from browsers/screenreaders on all sizes. +- */ +-.dac-hidden { +- display: none !important; } +- +-/** +- * Break strings when their length exceeds the width of their container. +- */ +-.dac-text-break { +- word-wrap: break-word !important; } +- +-/** +- * Horizontal text alignment +- */ +-.dac-text-center { +- text-align: center !important; } +- +-.dac-text-left { +- text-align: left !important; } +- +-.dac-text-right { +- text-align: right !important; } +- +-/** +- * Prevent whitespace wrapping +- */ +-.dac-text-no-wrap { +- white-space: nowrap !important; } +- +-/** +- * Prevent text from wrapping onto multiple lines, instead truncate with an ellipsis. +- */ +-.dac-text-truncate { +- max-width: 100%; +- overflow: hidden !important; +- text-overflow: ellipsis !important; +- white-space: nowrap !important; +- word-wrap: normal !important; } +- +-/** +- * Floats +- */ +-.dac-float-left { +- float: left !important; } +- +-.dac-float-right { +- float: right !important; } +- +-/** +- * New block formatting context +- * +- * This affords some useful properties to the element. It won't wrap under +- * floats. Will also contain any floated children. +- * N.B. This will clip overflow. Use the alternative method below if this is +- * problematic. +- */ +-.dac-nbfc { +- overflow: hidden !important; +-} +- +-/** +- * New block formatting context (alternative) +- * +- * Alternative method when overflow must not be clipped. +- * +- * N.B. This breaks down in some browsers when elements within this element +- * exceed its width. +- */ +-.dac-nbfc-alt { +- display: table-cell !important; +- width: 10000px !important; +-} +- +-.Video { +- display: none; +-} +- +-.Video-overlay { +- background-color: rgba(0, 0, 0, 0.8); +- width: 100%; +- height: 100%; +- position: fixed; +- top: 0; +- left: 0; +- z-index: 9999; +-} +- +-.Video-container { +- width: 90vw; +- height: 50.625vw; +- max-height: calc(90vh - 29.25px); +- max-width: calc(160vh - 52px); +- margin: auto; +- position: fixed; +- top: -52px; +- right: 0; +- bottom: 0; +- left: 0; +- z-index: 9999; +-} +- +-@media (min-width: 1422.22222222px) and (min-height: 800px) { +- .Video-container { +- width: 1280px; +- height: 720px; +- } +-} +- +-.Video-controls { +- background: #28655F; +- height: 52px; +- margin: 0 auto; +- position: relative; +- box-shadow: 2px 3px 12px 0px rgba(0, 0, 0, 0.4); +-} +- +-.Video-frame { +- position: relative; +- height: 100%; +- background: black; +- box-shadow: 2px 3px 12px 0px rgba(0, 0, 0, 0.4); +-} +- +-.Video-loading { +- color: rgba(255, 255, 255, 0.35); +- font-size: 16px; +- position: absolute; +- top: 50%; +- left: 50%; +- -webkit-transform: translate(-50%, -50%); +- -ms-transform: translate(-50%, -50%); +- transform: translate(-50%, -50%); +-} +- +-#youTubePlayer { +- max-height: 720px; +- position: absolute; +- top: 0; +- right: 0; +- bottom: 0; +- left: 0; +- width: 100%; +- height: 100%; +-} +- +-.Video-button { +- background-color: transparent; +- border: none; +- display: inline-block; +- height: 100%; +- width: 52px; +- outline: none; +- cursor: pointer; +- -webkit-transition: opacity 200ms; +- transition: opacity 200ms; +-} +- +-.Video-button:hover { +- opacity: 0.8; +-} +- +-.Video-button--picture-in-picture { +- background-position: 0px -461px; +- height: 24px; +- width: 24px; +- display: none; +- position: absolute; +- right: 64px; +- top: 14px; +-} +- +-.Video-button--close { +- background-position: 0px -435px; +- height: 24px; +- width: 24px; +- position: absolute; +- right: 14px; +- top: 14px; +-} +- +-@media (min-width: 720px) { +- .Video--picture-in-picture .Video-overlay { +- display: none; +- } +- +- .Video--picture-in-picture .Video-container { +- top: auto; +- left: auto; +- bottom: 20px; +- right: 20px; +- width: 40%; +- max-width: 420px; +- height: auto; +- } +- +- .Video--picture-in-picture .Video-button--picture-in-picture { +- background-position: 0px -409px; +- height: 24px; +- width: 24px; +- } +- +- .Video--picture-in-picture .Video-frame { +- padding-bottom: 56.25%; +- } +- +- .Video-button--picture-in-picture { +- display: inline-block; +- } +-} +- +-a.video-shadowbox-button.white { +- padding: 16px 42px 16px 8px; +- font-size: 18px; +- font-weight: 500; +- line-height: 24px; +- color: #fff; +- text-decoration: none; +-} +- +-a.video-shadowbox-button.white::after { +- content: ''; +- background-position: 0px -847px; +- height: 36px; +- width: 36px; +-} +- +-a.video-shadowbox-button.white:hover { +- color: #bababa !important; +-} +- +-a.video-shadowbox-button.white:hover::after { +- background-position: 0px -733px; +- height: 36px; +- width: 36px; +-} +- +-#video-frame, #video-container { +- display: none; +-} +- +-@media (max-width: 720px) { +- .wide-table { +- overflow-x: auto; +- } +- +- .wide-table table { +- display: inline-table; +- margin-right: 0; +- } +-} +- +-/* New CSS that isn't part of a component */ +-.paging-links { +- box-shadow: 0px 2px 6px 0px rgba(0, 0, 0, 0.2); +- margin: 30px 0; +- padding: 0 40px; +- /* Start class link doesn't have a caption */ } +- +-.paging-links .start-class-link, .paging-links .next-class-link, .paging-links .prev-page-link, .paging-links .next-page-link { +- font-size: 20px; +- font-weight: 500; +- display: inline-block; +- width: calc(50% - 2px); +- position: relative; +- padding: 46px 0 36px 0; +-} +- +-@media (max-width: 719px) { +- .paging-links .start-class-link, .paging-links .next-class-link, .paging-links .prev-page-link, .paging-links .next-page-link { +- width: 100%; +- } +-} +- +-.paging-links .start-class-link { +- padding: 36px 0; +-} +- +-.paging-links .start-class-link, .paging-links .next-class-link { +- text-align: center; +- width: 100%; +-} +- +-.paging-links .prev-page-link .page-link-caption { +- left: 0; +-} +- +-.paging-links .prev-page-link:before { +- content: ''; +- left: -24px; +- position: absolute; +- bottom: 41px; +-} +- +-@media (max-width: 719px) { +- .paging-links .prev-page-link { +- display: none; +- } +-} +- +-.paging-links .next-page-link, .paging-links .next-class-link { +- text-align: right; +-} +- +-.paging-links .next-page-link .page-link-caption, .paging-links .next-class-link .page-link-caption { +- right: 0; +-} +- +-.paging-links .next-page-link:before, .paging-links .next-class-link:before { +- content: ''; +- right: -24px; +- position: absolute; +- bottom: 41px; +-} +- +-.paging-links .start-class-link:after { +- content: ''; +- right: -12px; +- position: relative; +- bottom: 3px; +-} +- +-.paging-links .page-link-caption { +- position: absolute; +- top: 26px; +- font-size: 14px; +- font-weight: 700; +- opacity: 0.54; +-} +- +-#tb li:before, +-#qv li:before { +- background-position: 0px -669px; +- height: 24px; +- width: 24px; +- content: ''; +- left: -8px; +- opacity: .7; +- position: absolute; +- top: -4px; +-} +- +-#skip-to-main { +- border: 0; +- clip: rect(0 0 0 0); +- height: 1px; +- margin: -1px; +- overflow: hidden; +- padding: 0; +- position: absolute; +- width: 1px; +-} +- +-#skip-to-main:focus { +- background: #fff; +- clip: auto; +- height: auto; +- padding: 10px; +- width: auto; +- z-index: 10000; +-} +diff --git a/tools/droiddoc/templates-sdk-dev/assets/css/fullscreen.css b/tools/droiddoc/templates-sdk-dev/assets/css/fullscreen.css +deleted file mode 100644 +index 0f108e0..0000000 +--- a/tools/droiddoc/templates-sdk-dev/assets/css/fullscreen.css ++++ /dev/null +@@ -1,20 +0,0 @@ +- +-/* ============================================================================= +- Columns +- ========================================================================== */ +-/* Applied to body to debug layout alignments +-.grid { +- width:100%; +- height:100%; +- background:url(../images/grid.png) center repeat-y; +- top:0px; +- margin:auto; +- position:absolute; +-} +-*/ +- +-@media screen, projection, print { +- .wrap { +- max-width: none; +- } +-} +diff --git a/tools/droiddoc/templates-sdk-dev/assets/design/default.js b/tools/droiddoc/templates-sdk-dev/assets/design/default.js +deleted file mode 100644 +index 3ba8486..0000000 +--- a/tools/droiddoc/templates-sdk-dev/assets/design/default.js ++++ /dev/null +@@ -1,188 +0,0 @@ +-$(document).ready(function() { +- // prep nav expandos +- var pagePath = document.location.pathname; +- if (pagePath.indexOf(SITE_ROOT) == 0) { +- pagePath = pagePath.substr(SITE_ROOT.length); +- if (pagePath == '' || pagePath.charAt(pagePath.length - 1) == '/') { +- pagePath += 'index.html'; +- } +- } +- +- if (SITE_ROOT.match(/\.\.\//) || SITE_ROOT == '') { +- // If running locally, SITE_ROOT will be a relative path, so account for that by +- // finding the relative URL to this page. This will allow us to find links on the page +- // leading back to this page. +- var pathParts = pagePath.split('/'); +- var relativePagePathParts = []; +- var upDirs = (SITE_ROOT.match(/(\.\.\/)+/) || [''])[0].length / 3; +- for (var i = 0; i < upDirs; i++) { +- relativePagePathParts.push('..'); +- } +- for (var i = 0; i < upDirs; i++) { +- relativePagePathParts.push(pathParts[pathParts.length - (upDirs - i) - 1]); +- } +- relativePagePathParts.push(pathParts[pathParts.length - 1]); +- pagePath = relativePagePathParts.join('/'); +- } else { +- // Otherwise the page path should be an absolute URL. +- pagePath = SITE_ROOT + pagePath; +- } +- +- // select current page in sidenav and set up prev/next links if they exist +- var $selNavLink = $('.nav-y').find('a[href="' + pagePath + '"]'); +- if ($selNavLink.length) { +- $selListItem = $selNavLink.closest('li'); +- +- $selListItem.addClass('selected'); +- $selListItem.closest('li>ul').addClass('expanded'); +- +- // set up prev links +- var $prevLink = []; +- var $prevListItem = $selListItem.prev('li'); +- if ($prevListItem.length) { +- if ($prevListItem.hasClass('nav-section')) { +- // jump to last topic of previous section +- $prevLink = $prevListItem.find('a:last'); +- } else { +- // jump to previous topic in this section +- $prevLink = $prevListItem.find('a:eq(0)'); +- } +- } else { +- // jump to this section's index page (if it exists) +- $prevLink = $selListItem.parents('li').find('a'); +- } +- +- if ($prevLink.length) { +- var prevHref = $prevLink.attr('href'); +- if (prevHref == SITE_ROOT + 'index.html') { +- // Don't show Previous when it leads to the homepage +- $('.prev-page-link').hide(); +- } else { +- $('.prev-page-link').attr('href', prevHref).show(); +- } +- } else { +- $('.prev-page-link').hide(); +- } +- +- // set up next links +- var $nextLink = []; +- if ($selListItem.hasClass('nav-section')) { +- // we're on an index page, jump to the first topic +- $nextLink = $selListItem.find('ul').find('a:eq(0)') +- } else { +- // jump to the next topic in this section (if it exists) +- $nextLink = $selListItem.next('li').find('a:eq(0)'); +- if (!$nextLink.length) { +- // no more topics in this section, jump to the first topic in the next section +- $nextLink = $selListItem.parents('li').next('li.nav-section').find('a:eq(0)'); +- } +- } +- if ($nextLink.length) { +- $('.next-page-link').attr('href', $nextLink.attr('href')).show(); +- } else { +- $('.next-page-link').hide(); +- } +- } +- +- // Set up expand/collapse behavior +- $('.nav-y li').has('ul').click(function() { +- if ($(this).hasClass('expanded')) { +- return; +- } +- +- // hide other +- var $old = $('.nav-y li.expanded'); +- if ($old.length) { +- var $oldUl = $old.children('ul'); +- $oldUl.css('height', $oldUl.height() + 'px'); +- window.setTimeout(function() { +- $oldUl +- .addClass('animate-height') +- .css('height', ''); +- }, 0); +- $old.removeClass('expanded'); +- } +- +- // show me +- $(this).addClass('expanded'); +- var $ul = $(this).children('ul'); +- var expandedHeight = $ul.height(); +- $ul +- .removeClass('animate-height') +- .css('height', 0); +- window.setTimeout(function() { +- $ul +- .addClass('animate-height') +- .css('height', expandedHeight + 'px'); +- }, 0); +- }); +- +- // Stop expand/collapse behavior when clicking on nav section links (since we're navigating away +- // from the page) +- $('.nav-y li').has('ul').find('a:eq(0)').click(function(evt) { +- window.location.href = $(this).attr('href'); +- return false; +- }); +- +- // Set up play-on-hover
') +- .addClass('tooltip-box') +- .text($target.attr('title')) +- .hide() +- .appendTo('body'); +- $target.removeAttr('title'); +- +- $target.hover(function() { +- // in +- var targetRect = $target.offset(); +- targetRect.width = $target.width(); +- targetRect.height = $target.height(); +- +- $tooltip.css({ +- left: targetRect.left, +- top: targetRect.top + targetRect.height + TOOLTIP_MARGIN +- }); +- $tooltip.addClass('below'); +- $tooltip.show(); +- }, function() { +- // out +- $tooltip.hide(); +- }); +- }); +- +- // Set up

deeplinks +- $('h2').click(function() { +- var id = $(this).attr('id'); +- if (id) { +- document.location.hash = id; +- } +- }); +- +- // Set up fixed navbar +- var navBarIsFixed = false; +- $(window).scroll(function() { +- var scrollTop = $(window).scrollTop(); +- var navBarShouldBeFixed = (scrollTop > (100 - 40)); +- if (navBarIsFixed != navBarShouldBeFixed) { +- if (navBarShouldBeFixed) { +- $('#nav') +- .addClass('fixed') +- .prependTo('#page-container'); +- } else { +- $('#nav') +- .removeClass('fixed') +- .prependTo('#nav-container'); +- } +- navBarIsFixed = navBarShouldBeFixed; +- } +- }); +-}); +\ No newline at end of file +diff --git a/tools/droiddoc/templates-sdk-dev/assets/images/android-developers-logo.png b/tools/droiddoc/templates-sdk-dev/assets/images/android-developers-logo.png +deleted file mode 100644 +index 30a8f62..0000000 +Binary files a/tools/droiddoc/templates-sdk-dev/assets/images/android-developers-logo.png and /dev/null differ +diff --git a/tools/droiddoc/templates-sdk-dev/assets/images/android.png b/tools/droiddoc/templates-sdk-dev/assets/images/android.png +deleted file mode 100644 +index 4040f3f..0000000 +Binary files a/tools/droiddoc/templates-sdk-dev/assets/images/android.png and /dev/null differ +diff --git a/tools/droiddoc/templates-sdk-dev/assets/images/android_logo.png b/tools/droiddoc/templates-sdk-dev/assets/images/android_logo.png +deleted file mode 100644 +index 53f59c6..0000000 +Binary files a/tools/droiddoc/templates-sdk-dev/assets/images/android_logo.png and /dev/null differ +diff --git a/tools/droiddoc/templates-sdk-dev/assets/images/android_logo@2x.png b/tools/droiddoc/templates-sdk-dev/assets/images/android_logo@2x.png +deleted file mode 100644 +index 85b9211..0000000 +Binary files a/tools/droiddoc/templates-sdk-dev/assets/images/android_logo@2x.png and /dev/null differ +diff --git a/tools/droiddoc/templates-sdk-dev/assets/images/android_logo_ndk.png b/tools/droiddoc/templates-sdk-dev/assets/images/android_logo_ndk.png +deleted file mode 100644 +index 3f39f4d..0000000 +Binary files a/tools/droiddoc/templates-sdk-dev/assets/images/android_logo_ndk.png and /dev/null differ +diff --git a/tools/droiddoc/templates-sdk-dev/assets/images/android_logo_ndk@2x.png b/tools/droiddoc/templates-sdk-dev/assets/images/android_logo_ndk@2x.png +deleted file mode 100644 +index 8081ac5..0000000 +Binary files a/tools/droiddoc/templates-sdk-dev/assets/images/android_logo_ndk@2x.png and /dev/null differ +diff --git a/tools/droiddoc/templates-sdk-dev/assets/images/android_wrench.png b/tools/droiddoc/templates-sdk-dev/assets/images/android_wrench.png +deleted file mode 100644 +index 6390a2d..0000000 +Binary files a/tools/droiddoc/templates-sdk-dev/assets/images/android_wrench.png and /dev/null differ +diff --git a/tools/droiddoc/templates-sdk-dev/assets/images/arrow-left-develop.png b/tools/droiddoc/templates-sdk-dev/assets/images/arrow-left-develop.png +deleted file mode 100644 +index 5fdfaa3..0000000 +Binary files a/tools/droiddoc/templates-sdk-dev/assets/images/arrow-left-develop.png and /dev/null differ +diff --git a/tools/droiddoc/templates-sdk-dev/assets/images/arrow-left.png b/tools/droiddoc/templates-sdk-dev/assets/images/arrow-left.png +deleted file mode 100644 +index 43afec8..0000000 +Binary files a/tools/droiddoc/templates-sdk-dev/assets/images/arrow-left.png and /dev/null differ +diff --git a/tools/droiddoc/templates-sdk-dev/assets/images/arrow-right-develop.png b/tools/droiddoc/templates-sdk-dev/assets/images/arrow-right-develop.png +deleted file mode 100644 +index c86f1f3..0000000 +Binary files a/tools/droiddoc/templates-sdk-dev/assets/images/arrow-right-develop.png and /dev/null differ +diff --git a/tools/droiddoc/templates-sdk-dev/assets/images/arrow-right.png b/tools/droiddoc/templates-sdk-dev/assets/images/arrow-right.png +deleted file mode 100644 +index 6f7d6db..0000000 +Binary files a/tools/droiddoc/templates-sdk-dev/assets/images/arrow-right.png and /dev/null differ +diff --git a/tools/droiddoc/templates-sdk-dev/assets/images/arrow_bluelink_down.png b/tools/droiddoc/templates-sdk-dev/assets/images/arrow_bluelink_down.png +deleted file mode 100755 +index 58c248a..0000000 +Binary files a/tools/droiddoc/templates-sdk-dev/assets/images/arrow_bluelink_down.png and /dev/null differ +diff --git a/tools/droiddoc/templates-sdk-dev/assets/images/arrow_bluelink_up.png b/tools/droiddoc/templates-sdk-dev/assets/images/arrow_bluelink_up.png +deleted file mode 100755 +index 7d0f38e..0000000 +Binary files a/tools/droiddoc/templates-sdk-dev/assets/images/arrow_bluelink_up.png and /dev/null differ +diff --git a/tools/droiddoc/templates-sdk-dev/assets/images/arrow_left_off.jpg b/tools/droiddoc/templates-sdk-dev/assets/images/arrow_left_off.jpg +deleted file mode 100755 +index fd32a64..0000000 +Binary files a/tools/droiddoc/templates-sdk-dev/assets/images/arrow_left_off.jpg and /dev/null differ +diff --git a/tools/droiddoc/templates-sdk-dev/assets/images/arrow_left_on.jpg b/tools/droiddoc/templates-sdk-dev/assets/images/arrow_left_on.jpg +deleted file mode 100755 +index 143184b..0000000 +Binary files a/tools/droiddoc/templates-sdk-dev/assets/images/arrow_left_on.jpg and /dev/null differ +diff --git a/tools/droiddoc/templates-sdk-dev/assets/images/arrow_right_off.jpg b/tools/droiddoc/templates-sdk-dev/assets/images/arrow_right_off.jpg +deleted file mode 100755 +index 17d2efe..0000000 +Binary files a/tools/droiddoc/templates-sdk-dev/assets/images/arrow_right_off.jpg and /dev/null differ +diff --git a/tools/droiddoc/templates-sdk-dev/assets/images/arrow_right_on.jpg b/tools/droiddoc/templates-sdk-dev/assets/images/arrow_right_on.jpg +deleted file mode 100755 +index baa2af1..0000000 +Binary files a/tools/droiddoc/templates-sdk-dev/assets/images/arrow_right_on.jpg and /dev/null differ +diff --git a/tools/droiddoc/templates-sdk-dev/assets/images/arrows-up-down.png b/tools/droiddoc/templates-sdk-dev/assets/images/arrows-up-down.png +deleted file mode 100644 +index a2a91ed..0000000 +Binary files a/tools/droiddoc/templates-sdk-dev/assets/images/arrows-up-down.png and /dev/null differ +diff --git a/tools/droiddoc/templates-sdk-dev/assets/images/bg_community_leftDiv.jpg b/tools/droiddoc/templates-sdk-dev/assets/images/bg_community_leftDiv.jpg +deleted file mode 100755 +index a6d6f0e..0000000 +Binary files a/tools/droiddoc/templates-sdk-dev/assets/images/bg_community_leftDiv.jpg and /dev/null differ +diff --git a/tools/droiddoc/templates-sdk-dev/assets/images/bg_fade.jpg b/tools/droiddoc/templates-sdk-dev/assets/images/bg_fade.jpg +deleted file mode 100755 +index c6c70b6..0000000 +Binary files a/tools/droiddoc/templates-sdk-dev/assets/images/bg_fade.jpg and /dev/null differ +diff --git a/tools/droiddoc/templates-sdk-dev/assets/images/bg_gradient.jpg b/tools/droiddoc/templates-sdk-dev/assets/images/bg_gradient.jpg +deleted file mode 100644 +index 884f8f5..0000000 +Binary files a/tools/droiddoc/templates-sdk-dev/assets/images/bg_gradient.jpg and /dev/null differ +diff --git a/tools/droiddoc/templates-sdk-dev/assets/images/bg_images_sprite.png b/tools/droiddoc/templates-sdk-dev/assets/images/bg_images_sprite.png +deleted file mode 100755 +index 84437e7..0000000 +Binary files a/tools/droiddoc/templates-sdk-dev/assets/images/bg_images_sprite.png and /dev/null differ +diff --git a/tools/droiddoc/templates-sdk-dev/assets/images/bg_logo.png b/tools/droiddoc/templates-sdk-dev/assets/images/bg_logo.png +deleted file mode 100755 +index 7cf0cb9..0000000 +Binary files a/tools/droiddoc/templates-sdk-dev/assets/images/bg_logo.png and /dev/null differ +diff --git a/tools/droiddoc/templates-sdk-dev/assets/images/blog-default.png b/tools/droiddoc/templates-sdk-dev/assets/images/blog-default.png +deleted file mode 100644 +index f8ab6c3..0000000 +Binary files a/tools/droiddoc/templates-sdk-dev/assets/images/blog-default.png and /dev/null differ +diff --git a/tools/droiddoc/templates-sdk-dev/assets/images/body-gradient-tab.png b/tools/droiddoc/templates-sdk-dev/assets/images/body-gradient-tab.png +deleted file mode 100644 +index 5223ac3..0000000 +Binary files a/tools/droiddoc/templates-sdk-dev/assets/images/body-gradient-tab.png and /dev/null differ +diff --git a/tools/droiddoc/templates-sdk-dev/assets/images/body-gradient.png b/tools/droiddoc/templates-sdk-dev/assets/images/body-gradient.png +deleted file mode 100755 +index 9d59855..0000000 +Binary files a/tools/droiddoc/templates-sdk-dev/assets/images/body-gradient.png and /dev/null differ +diff --git a/tools/droiddoc/templates-sdk-dev/assets/images/breadcrumb.png b/tools/droiddoc/templates-sdk-dev/assets/images/breadcrumb.png +deleted file mode 100644 +index 407a318..0000000 +Binary files a/tools/droiddoc/templates-sdk-dev/assets/images/breadcrumb.png and /dev/null differ +diff --git a/tools/droiddoc/templates-sdk-dev/assets/images/close-grey.png b/tools/droiddoc/templates-sdk-dev/assets/images/close-grey.png +deleted file mode 100644 +index 1b0d7f1..0000000 +Binary files a/tools/droiddoc/templates-sdk-dev/assets/images/close-grey.png and /dev/null differ +diff --git a/tools/droiddoc/templates-sdk-dev/assets/images/close-grey_2x.png b/tools/droiddoc/templates-sdk-dev/assets/images/close-grey_2x.png +deleted file mode 100644 +index 1355507..0000000 +Binary files a/tools/droiddoc/templates-sdk-dev/assets/images/close-grey_2x.png and /dev/null differ +diff --git a/tools/droiddoc/templates-sdk-dev/assets/images/close-white.png b/tools/droiddoc/templates-sdk-dev/assets/images/close-white.png +deleted file mode 100644 +index ef02018..0000000 +Binary files a/tools/droiddoc/templates-sdk-dev/assets/images/close-white.png and /dev/null differ +diff --git a/tools/droiddoc/templates-sdk-dev/assets/images/close-white_2x.png b/tools/droiddoc/templates-sdk-dev/assets/images/close-white_2x.png +deleted file mode 100644 +index 9b9c41d..0000000 +Binary files a/tools/droiddoc/templates-sdk-dev/assets/images/close-white_2x.png and /dev/null differ +diff --git a/tools/droiddoc/templates-sdk-dev/assets/images/close.png b/tools/droiddoc/templates-sdk-dev/assets/images/close.png +deleted file mode 100644 +index 6ae3391..0000000 +Binary files a/tools/droiddoc/templates-sdk-dev/assets/images/close.png and /dev/null differ +diff --git a/tools/droiddoc/templates-sdk-dev/assets/images/dac_logo.png b/tools/droiddoc/templates-sdk-dev/assets/images/dac_logo.png +deleted file mode 100644 +index 0f11044..0000000 +Binary files a/tools/droiddoc/templates-sdk-dev/assets/images/dac_logo.png and /dev/null differ +diff --git a/tools/droiddoc/templates-sdk-dev/assets/images/dac_logo@2x.png b/tools/droiddoc/templates-sdk-dev/assets/images/dac_logo@2x.png +deleted file mode 100644 +index 0f2784d..0000000 +Binary files a/tools/droiddoc/templates-sdk-dev/assets/images/dac_logo@2x.png and /dev/null differ +diff --git a/tools/droiddoc/templates-sdk-dev/assets/images/developers-logo.png b/tools/droiddoc/templates-sdk-dev/assets/images/developers-logo.png +deleted file mode 100755 +index 08122ee..0000000 +Binary files a/tools/droiddoc/templates-sdk-dev/assets/images/developers-logo.png and /dev/null differ +diff --git a/tools/droiddoc/templates-sdk-dev/assets/images/file-generic.png b/tools/droiddoc/templates-sdk-dev/assets/images/file-generic.png +deleted file mode 100644 +index 1802457..0000000 +Binary files a/tools/droiddoc/templates-sdk-dev/assets/images/file-generic.png and /dev/null differ +diff --git a/tools/droiddoc/templates-sdk-dev/assets/images/file-image.png b/tools/droiddoc/templates-sdk-dev/assets/images/file-image.png +deleted file mode 100644 +index d3aec46..0000000 +Binary files a/tools/droiddoc/templates-sdk-dev/assets/images/file-image.png and /dev/null differ +diff --git a/tools/droiddoc/templates-sdk-dev/assets/images/file-java.png b/tools/droiddoc/templates-sdk-dev/assets/images/file-java.png +deleted file mode 100644 +index ec85e4b..0000000 +Binary files a/tools/droiddoc/templates-sdk-dev/assets/images/file-java.png and /dev/null differ +diff --git a/tools/droiddoc/templates-sdk-dev/assets/images/file-manifest.png b/tools/droiddoc/templates-sdk-dev/assets/images/file-manifest.png +deleted file mode 100644 +index 332d066..0000000 +Binary files a/tools/droiddoc/templates-sdk-dev/assets/images/file-manifest.png and /dev/null differ +diff --git a/tools/droiddoc/templates-sdk-dev/assets/images/file-xml.png b/tools/droiddoc/templates-sdk-dev/assets/images/file-xml.png +deleted file mode 100644 +index 3dd21b6..0000000 +Binary files a/tools/droiddoc/templates-sdk-dev/assets/images/file-xml.png and /dev/null differ +diff --git a/tools/droiddoc/templates-sdk-dev/assets/images/folder.png b/tools/droiddoc/templates-sdk-dev/assets/images/folder.png +deleted file mode 100644 +index 44c6100..0000000 +Binary files a/tools/droiddoc/templates-sdk-dev/assets/images/folder.png and /dev/null differ +diff --git a/tools/droiddoc/templates-sdk-dev/assets/images/fullscreen.png b/tools/droiddoc/templates-sdk-dev/assets/images/fullscreen.png +deleted file mode 100644 +index 01f971c..0000000 +Binary files a/tools/droiddoc/templates-sdk-dev/assets/images/fullscreen.png and /dev/null differ +diff --git a/tools/droiddoc/templates-sdk-dev/assets/images/grad-rule-qv.png b/tools/droiddoc/templates-sdk-dev/assets/images/grad-rule-qv.png +deleted file mode 100644 +index bae2d18..0000000 +Binary files a/tools/droiddoc/templates-sdk-dev/assets/images/grad-rule-qv.png and /dev/null differ +diff --git a/tools/droiddoc/templates-sdk-dev/assets/images/home/Android_Dev_Lab_l.png b/tools/droiddoc/templates-sdk-dev/assets/images/home/Android_Dev_Lab_l.png +deleted file mode 100644 +index 3c04f24..0000000 +Binary files a/tools/droiddoc/templates-sdk-dev/assets/images/home/Android_Dev_Lab_l.png and /dev/null differ +diff --git a/tools/droiddoc/templates-sdk-dev/assets/images/home/GDC2011.png b/tools/droiddoc/templates-sdk-dev/assets/images/home/GDC2011.png +deleted file mode 100644 +index 82ce918..0000000 +Binary files a/tools/droiddoc/templates-sdk-dev/assets/images/home/GDC2011.png and /dev/null differ +diff --git a/tools/droiddoc/templates-sdk-dev/assets/images/home/GTV_icon_large.png b/tools/droiddoc/templates-sdk-dev/assets/images/home/GTV_icon_large.png +deleted file mode 100644 +index 72d54ad..0000000 +Binary files a/tools/droiddoc/templates-sdk-dev/assets/images/home/GTV_icon_large.png and /dev/null differ +diff --git a/tools/droiddoc/templates-sdk-dev/assets/images/home/GTV_icon_small.png b/tools/droiddoc/templates-sdk-dev/assets/images/home/GTV_icon_small.png +deleted file mode 100644 +index 3da1699..0000000 +Binary files a/tools/droiddoc/templates-sdk-dev/assets/images/home/GTV_icon_small.png and /dev/null differ +diff --git a/tools/droiddoc/templates-sdk-dev/assets/images/home/IO-logo-2011.png b/tools/droiddoc/templates-sdk-dev/assets/images/home/IO-logo-2011.png +deleted file mode 100644 +index 4a28447..0000000 +Binary files a/tools/droiddoc/templates-sdk-dev/assets/images/home/IO-logo-2011.png and /dev/null differ +diff --git a/tools/droiddoc/templates-sdk-dev/assets/images/home/IO-logo.png b/tools/droiddoc/templates-sdk-dev/assets/images/home/IO-logo.png +deleted file mode 100644 +index 65334c8..0000000 +Binary files a/tools/droiddoc/templates-sdk-dev/assets/images/home/IO-logo.png and /dev/null differ +diff --git a/tools/droiddoc/templates-sdk-dev/assets/images/home/adc2_l.png b/tools/droiddoc/templates-sdk-dev/assets/images/home/adc2_l.png +deleted file mode 100644 +index 0b101a4..0000000 +Binary files a/tools/droiddoc/templates-sdk-dev/assets/images/home/adc2_l.png and /dev/null differ +diff --git a/tools/droiddoc/templates-sdk-dev/assets/images/home/adc2_s.png b/tools/droiddoc/templates-sdk-dev/assets/images/home/adc2_s.png +deleted file mode 100644 +index 0d36bdb..0000000 +Binary files a/tools/droiddoc/templates-sdk-dev/assets/images/home/adc2_s.png and /dev/null differ +diff --git a/tools/droiddoc/templates-sdk-dev/assets/images/home/android_adc.png b/tools/droiddoc/templates-sdk-dev/assets/images/home/android_adc.png +deleted file mode 100644 +index 9fe7f8f..0000000 +Binary files a/tools/droiddoc/templates-sdk-dev/assets/images/home/android_adc.png and /dev/null differ +diff --git a/tools/droiddoc/templates-sdk-dev/assets/images/home/android_m_hero_1200.jpg b/tools/droiddoc/templates-sdk-dev/assets/images/home/android_m_hero_1200.jpg +deleted file mode 100644 +index 6b79295..0000000 +Binary files a/tools/droiddoc/templates-sdk-dev/assets/images/home/android_m_hero_1200.jpg and /dev/null differ +diff --git a/tools/droiddoc/templates-sdk-dev/assets/images/home/bg_home_announcement.png b/tools/droiddoc/templates-sdk-dev/assets/images/home/bg_home_announcement.png +deleted file mode 100755 +index 91485ff..0000000 +Binary files a/tools/droiddoc/templates-sdk-dev/assets/images/home/bg_home_announcement.png and /dev/null differ +diff --git a/tools/droiddoc/templates-sdk-dev/assets/images/home/bg_home_bottom.jpg b/tools/droiddoc/templates-sdk-dev/assets/images/home/bg_home_bottom.jpg +deleted file mode 100755 +index dacd401..0000000 +Binary files a/tools/droiddoc/templates-sdk-dev/assets/images/home/bg_home_bottom.jpg and /dev/null differ +diff --git a/tools/droiddoc/templates-sdk-dev/assets/images/home/bg_home_carousel.png b/tools/droiddoc/templates-sdk-dev/assets/images/home/bg_home_carousel.png +deleted file mode 100755 +index 5ce5e30..0000000 +Binary files a/tools/droiddoc/templates-sdk-dev/assets/images/home/bg_home_carousel.png and /dev/null differ +diff --git a/tools/droiddoc/templates-sdk-dev/assets/images/home/bg_home_carousel_board.png b/tools/droiddoc/templates-sdk-dev/assets/images/home/bg_home_carousel_board.png +deleted file mode 100755 +index c577e02..0000000 +Binary files a/tools/droiddoc/templates-sdk-dev/assets/images/home/bg_home_carousel_board.png and /dev/null differ +diff --git a/tools/droiddoc/templates-sdk-dev/assets/images/home/bg_home_carousel_wheel.png b/tools/droiddoc/templates-sdk-dev/assets/images/home/bg_home_carousel_wheel.png +deleted file mode 100755 +index aa224ad..0000000 +Binary files a/tools/droiddoc/templates-sdk-dev/assets/images/home/bg_home_carousel_wheel.png and /dev/null differ +diff --git a/tools/droiddoc/templates-sdk-dev/assets/images/home/carousel_buttons_sprite.png b/tools/droiddoc/templates-sdk-dev/assets/images/home/carousel_buttons_sprite.png +deleted file mode 100755 +index e98c942..0000000 +Binary files a/tools/droiddoc/templates-sdk-dev/assets/images/home/carousel_buttons_sprite.png and /dev/null differ +diff --git a/tools/droiddoc/templates-sdk-dev/assets/images/home/devphone-large.png b/tools/droiddoc/templates-sdk-dev/assets/images/home/devphone-large.png +deleted file mode 100644 +index 0db0f6c..0000000 +Binary files a/tools/droiddoc/templates-sdk-dev/assets/images/home/devphone-large.png and /dev/null differ +diff --git a/tools/droiddoc/templates-sdk-dev/assets/images/home/devphone-small.png b/tools/droiddoc/templates-sdk-dev/assets/images/home/devphone-small.png +deleted file mode 100644 +index e10bfa9..0000000 +Binary files a/tools/droiddoc/templates-sdk-dev/assets/images/home/devphone-small.png and /dev/null differ +diff --git a/tools/droiddoc/templates-sdk-dev/assets/images/home/donut-android.png b/tools/droiddoc/templates-sdk-dev/assets/images/home/donut-android.png +deleted file mode 100755 +index 6aba06b..0000000 +Binary files a/tools/droiddoc/templates-sdk-dev/assets/images/home/donut-android.png and /dev/null differ +diff --git a/tools/droiddoc/templates-sdk-dev/assets/images/home/eclair-android.png b/tools/droiddoc/templates-sdk-dev/assets/images/home/eclair-android.png +deleted file mode 100644 +index d476ce9..0000000 +Binary files a/tools/droiddoc/templates-sdk-dev/assets/images/home/eclair-android.png and /dev/null differ +diff --git a/tools/droiddoc/templates-sdk-dev/assets/images/home/froyo-android.png b/tools/droiddoc/templates-sdk-dev/assets/images/home/froyo-android.png +deleted file mode 100644 +index c63f7f0..0000000 +Binary files a/tools/droiddoc/templates-sdk-dev/assets/images/home/froyo-android.png and /dev/null differ +diff --git a/tools/droiddoc/templates-sdk-dev/assets/images/home/gdc-logo.png b/tools/droiddoc/templates-sdk-dev/assets/images/home/gdc-logo.png +deleted file mode 100644 +index 5fb53fb..0000000 +Binary files a/tools/droiddoc/templates-sdk-dev/assets/images/home/gdc-logo.png and /dev/null differ +diff --git a/tools/droiddoc/templates-sdk-dev/assets/images/home/gingerdroid.png b/tools/droiddoc/templates-sdk-dev/assets/images/home/gingerdroid.png +deleted file mode 100644 +index 8399d84..0000000 +Binary files a/tools/droiddoc/templates-sdk-dev/assets/images/home/gingerdroid.png and /dev/null differ +diff --git a/tools/droiddoc/templates-sdk-dev/assets/images/home/google-plus-small.png b/tools/droiddoc/templates-sdk-dev/assets/images/home/google-plus-small.png +deleted file mode 100644 +index 5bb7d7a..0000000 +Binary files a/tools/droiddoc/templates-sdk-dev/assets/images/home/google-plus-small.png and /dev/null differ +diff --git a/tools/droiddoc/templates-sdk-dev/assets/images/home/google-plus.png b/tools/droiddoc/templates-sdk-dev/assets/images/home/google-plus.png +deleted file mode 100644 +index 90871e1..0000000 +Binary files a/tools/droiddoc/templates-sdk-dev/assets/images/home/google-plus.png and /dev/null differ +diff --git a/tools/droiddoc/templates-sdk-dev/assets/images/home/honeycomb-android.png b/tools/droiddoc/templates-sdk-dev/assets/images/home/honeycomb-android.png +deleted file mode 100644 +index 6cc5031..0000000 +Binary files a/tools/droiddoc/templates-sdk-dev/assets/images/home/honeycomb-android.png and /dev/null differ +diff --git a/tools/droiddoc/templates-sdk-dev/assets/images/home/icon-about.png b/tools/droiddoc/templates-sdk-dev/assets/images/home/icon-about.png +deleted file mode 100644 +index 8339762..0000000 +Binary files a/tools/droiddoc/templates-sdk-dev/assets/images/home/icon-about.png and /dev/null differ +diff --git a/tools/droiddoc/templates-sdk-dev/assets/images/home/icon-design.png b/tools/droiddoc/templates-sdk-dev/assets/images/home/icon-design.png +deleted file mode 100644 +index 0d31cdf..0000000 +Binary files a/tools/droiddoc/templates-sdk-dev/assets/images/home/icon-design.png and /dev/null differ +diff --git a/tools/droiddoc/templates-sdk-dev/assets/images/home/icon-develop.png b/tools/droiddoc/templates-sdk-dev/assets/images/home/icon-develop.png +deleted file mode 100644 +index e02b20f..0000000 +Binary files a/tools/droiddoc/templates-sdk-dev/assets/images/home/icon-develop.png and /dev/null differ +diff --git a/tools/droiddoc/templates-sdk-dev/assets/images/home/icon-distribute.png b/tools/droiddoc/templates-sdk-dev/assets/images/home/icon-distribute.png +deleted file mode 100644 +index 4824072..0000000 +Binary files a/tools/droiddoc/templates-sdk-dev/assets/images/home/icon-distribute.png and /dev/null differ +diff --git a/tools/droiddoc/templates-sdk-dev/assets/images/home/ics-android.png b/tools/droiddoc/templates-sdk-dev/assets/images/home/ics-android.png +deleted file mode 100644 +index be62ca8..0000000 +Binary files a/tools/droiddoc/templates-sdk-dev/assets/images/home/ics-android.png and /dev/null differ +diff --git a/tools/droiddoc/templates-sdk-dev/assets/images/home/io-large.png b/tools/droiddoc/templates-sdk-dev/assets/images/home/io-large.png +deleted file mode 100755 +index 986053c..0000000 +Binary files a/tools/droiddoc/templates-sdk-dev/assets/images/home/io-large.png and /dev/null differ +diff --git a/tools/droiddoc/templates-sdk-dev/assets/images/home/io-small.png b/tools/droiddoc/templates-sdk-dev/assets/images/home/io-small.png +deleted file mode 100755 +index 3a22549..0000000 +Binary files a/tools/droiddoc/templates-sdk-dev/assets/images/home/io-small.png and /dev/null differ +diff --git a/tools/droiddoc/templates-sdk-dev/assets/images/home/maps-large.png b/tools/droiddoc/templates-sdk-dev/assets/images/home/maps-large.png +deleted file mode 100644 +index b26f65a..0000000 +Binary files a/tools/droiddoc/templates-sdk-dev/assets/images/home/maps-large.png and /dev/null differ +diff --git a/tools/droiddoc/templates-sdk-dev/assets/images/home/maps-small.png b/tools/droiddoc/templates-sdk-dev/assets/images/home/maps-small.png +deleted file mode 100644 +index cc5f1fa..0000000 +Binary files a/tools/droiddoc/templates-sdk-dev/assets/images/home/maps-small.png and /dev/null differ +diff --git a/tools/droiddoc/templates-sdk-dev/assets/images/home/market-large.png b/tools/droiddoc/templates-sdk-dev/assets/images/home/market-large.png +deleted file mode 100644 +index 069fee7..0000000 +Binary files a/tools/droiddoc/templates-sdk-dev/assets/images/home/market-large.png and /dev/null differ +diff --git a/tools/droiddoc/templates-sdk-dev/assets/images/home/market-small.png b/tools/droiddoc/templates-sdk-dev/assets/images/home/market-small.png +deleted file mode 100644 +index fa1201c..0000000 +Binary files a/tools/droiddoc/templates-sdk-dev/assets/images/home/market-small.png and /dev/null differ +diff --git a/tools/droiddoc/templates-sdk-dev/assets/images/home/sdk-large.png b/tools/droiddoc/templates-sdk-dev/assets/images/home/sdk-large.png +deleted file mode 100644 +index 315a1bf..0000000 +Binary files a/tools/droiddoc/templates-sdk-dev/assets/images/home/sdk-large.png and /dev/null differ +diff --git a/tools/droiddoc/templates-sdk-dev/assets/images/home/sdk-small.png b/tools/droiddoc/templates-sdk-dev/assets/images/home/sdk-small.png +deleted file mode 100644 +index 0f1670d..0000000 +Binary files a/tools/droiddoc/templates-sdk-dev/assets/images/home/sdk-small.png and /dev/null differ +diff --git a/tools/droiddoc/templates-sdk-dev/assets/images/hr_gray_main.jpg b/tools/droiddoc/templates-sdk-dev/assets/images/hr_gray_main.jpg +deleted file mode 100755 +index f7a0a2f..0000000 +Binary files a/tools/droiddoc/templates-sdk-dev/assets/images/hr_gray_main.jpg and /dev/null differ +diff --git a/tools/droiddoc/templates-sdk-dev/assets/images/hr_gray_side.jpg b/tools/droiddoc/templates-sdk-dev/assets/images/hr_gray_side.jpg +deleted file mode 100755 +index 6667476..0000000 +Binary files a/tools/droiddoc/templates-sdk-dev/assets/images/hr_gray_side.jpg and /dev/null differ +diff --git a/tools/droiddoc/templates-sdk-dev/assets/images/icon_contribute.jpg b/tools/droiddoc/templates-sdk-dev/assets/images/icon_contribute.jpg +deleted file mode 100755 +index 1aa12b6..0000000 +Binary files a/tools/droiddoc/templates-sdk-dev/assets/images/icon_contribute.jpg and /dev/null differ +diff --git a/tools/droiddoc/templates-sdk-dev/assets/images/icon_design.png b/tools/droiddoc/templates-sdk-dev/assets/images/icon_design.png +deleted file mode 100644 +index c12907c..0000000 +Binary files a/tools/droiddoc/templates-sdk-dev/assets/images/icon_design.png and /dev/null differ +diff --git a/tools/droiddoc/templates-sdk-dev/assets/images/icon_download.jpg b/tools/droiddoc/templates-sdk-dev/assets/images/icon_download.jpg +deleted file mode 100755 +index f8c1165..0000000 +Binary files a/tools/droiddoc/templates-sdk-dev/assets/images/icon_download.jpg and /dev/null differ +diff --git a/tools/droiddoc/templates-sdk-dev/assets/images/icon_download2.jpg b/tools/droiddoc/templates-sdk-dev/assets/images/icon_download2.jpg +deleted file mode 100755 +index c0af7a2..0000000 +Binary files a/tools/droiddoc/templates-sdk-dev/assets/images/icon_download2.jpg and /dev/null differ +diff --git a/tools/droiddoc/templates-sdk-dev/assets/images/icon_guidelines_logo.png b/tools/droiddoc/templates-sdk-dev/assets/images/icon_guidelines_logo.png +deleted file mode 100644 +index 9362c8f..0000000 +Binary files a/tools/droiddoc/templates-sdk-dev/assets/images/icon_guidelines_logo.png and /dev/null differ +diff --git a/tools/droiddoc/templates-sdk-dev/assets/images/icon_market.jpg b/tools/droiddoc/templates-sdk-dev/assets/images/icon_market.jpg +deleted file mode 100644 +index 0fbb197..0000000 +Binary files a/tools/droiddoc/templates-sdk-dev/assets/images/icon_market.jpg and /dev/null differ +diff --git a/tools/droiddoc/templates-sdk-dev/assets/images/icon_more.png b/tools/droiddoc/templates-sdk-dev/assets/images/icon_more.png +deleted file mode 100644 +index 6cd03a3..0000000 +Binary files a/tools/droiddoc/templates-sdk-dev/assets/images/icon_more.png and /dev/null differ +diff --git a/tools/droiddoc/templates-sdk-dev/assets/images/icon_play.png b/tools/droiddoc/templates-sdk-dev/assets/images/icon_play.png +deleted file mode 100644 +index 8bfdc7b..0000000 +Binary files a/tools/droiddoc/templates-sdk-dev/assets/images/icon_play.png and /dev/null differ +diff --git a/tools/droiddoc/templates-sdk-dev/assets/images/icon_robot.jpg b/tools/droiddoc/templates-sdk-dev/assets/images/icon_robot.jpg +deleted file mode 100755 +index ca0fd39..0000000 +Binary files a/tools/droiddoc/templates-sdk-dev/assets/images/icon_robot.jpg and /dev/null differ +diff --git a/tools/droiddoc/templates-sdk-dev/assets/images/icon_search.png b/tools/droiddoc/templates-sdk-dev/assets/images/icon_search.png +deleted file mode 100644 +index ee90a12..0000000 +Binary files a/tools/droiddoc/templates-sdk-dev/assets/images/icon_search.png and /dev/null differ +diff --git a/tools/droiddoc/templates-sdk-dev/assets/images/icon_world.jpg b/tools/droiddoc/templates-sdk-dev/assets/images/icon_world.jpg +deleted file mode 100755 +index 65b8fa6..0000000 +Binary files a/tools/droiddoc/templates-sdk-dev/assets/images/icon_world.jpg and /dev/null differ +diff --git a/tools/droiddoc/templates-sdk-dev/assets/images/left_off.jpg b/tools/droiddoc/templates-sdk-dev/assets/images/left_off.jpg +deleted file mode 100755 +index fd32a64..0000000 +Binary files a/tools/droiddoc/templates-sdk-dev/assets/images/left_off.jpg and /dev/null differ +diff --git a/tools/droiddoc/templates-sdk-dev/assets/images/left_on.jpg b/tools/droiddoc/templates-sdk-dev/assets/images/left_on.jpg +deleted file mode 100755 +index 143184b..0000000 +Binary files a/tools/droiddoc/templates-sdk-dev/assets/images/left_on.jpg and /dev/null differ +diff --git a/tools/droiddoc/templates-sdk-dev/assets/images/link-out.png b/tools/droiddoc/templates-sdk-dev/assets/images/link-out.png +deleted file mode 100644 +index aa55f9a..0000000 +Binary files a/tools/droiddoc/templates-sdk-dev/assets/images/link-out.png and /dev/null differ +diff --git a/tools/droiddoc/templates-sdk-dev/assets/images/locale.png b/tools/droiddoc/templates-sdk-dev/assets/images/locale.png +deleted file mode 100644 +index de3aae7..0000000 +Binary files a/tools/droiddoc/templates-sdk-dev/assets/images/locale.png and /dev/null differ +diff --git a/tools/droiddoc/templates-sdk-dev/assets/images/logo_breadcrumbz.jpg b/tools/droiddoc/templates-sdk-dev/assets/images/logo_breadcrumbz.jpg +deleted file mode 100755 +index e743f86..0000000 +Binary files a/tools/droiddoc/templates-sdk-dev/assets/images/logo_breadcrumbz.jpg and /dev/null differ +diff --git a/tools/droiddoc/templates-sdk-dev/assets/images/more_bottom.png b/tools/droiddoc/templates-sdk-dev/assets/images/more_bottom.png +deleted file mode 100644 +index 632546a..0000000 +Binary files a/tools/droiddoc/templates-sdk-dev/assets/images/more_bottom.png and /dev/null differ +diff --git a/tools/droiddoc/templates-sdk-dev/assets/images/more_check.png b/tools/droiddoc/templates-sdk-dev/assets/images/more_check.png +deleted file mode 100644 +index f2fcbfc..0000000 +Binary files a/tools/droiddoc/templates-sdk-dev/assets/images/more_check.png and /dev/null differ +diff --git a/tools/droiddoc/templates-sdk-dev/assets/images/more_mid.png b/tools/droiddoc/templates-sdk-dev/assets/images/more_mid.png +deleted file mode 100644 +index 99bc999..0000000 +Binary files a/tools/droiddoc/templates-sdk-dev/assets/images/more_mid.png and /dev/null differ +diff --git a/tools/droiddoc/templates-sdk-dev/assets/images/more_top.png b/tools/droiddoc/templates-sdk-dev/assets/images/more_top.png +deleted file mode 100644 +index 8ead1d3..0000000 +Binary files a/tools/droiddoc/templates-sdk-dev/assets/images/more_top.png and /dev/null differ +diff --git a/tools/droiddoc/templates-sdk-dev/assets/images/open_source.png b/tools/droiddoc/templates-sdk-dev/assets/images/open_source.png +deleted file mode 100755 +index 12bb1fb..0000000 +Binary files a/tools/droiddoc/templates-sdk-dev/assets/images/open_source.png and /dev/null differ +diff --git a/tools/droiddoc/templates-sdk-dev/assets/images/preliminary.png b/tools/droiddoc/templates-sdk-dev/assets/images/preliminary.png +deleted file mode 100644 +index fe0da3d..0000000 +Binary files a/tools/droiddoc/templates-sdk-dev/assets/images/preliminary.png and /dev/null differ +diff --git a/tools/droiddoc/templates-sdk-dev/assets/images/preview.png b/tools/droiddoc/templates-sdk-dev/assets/images/preview.png +deleted file mode 100644 +index e5856db..0000000 +Binary files a/tools/droiddoc/templates-sdk-dev/assets/images/preview.png and /dev/null differ +diff --git a/tools/droiddoc/templates-sdk-dev/assets/images/quicknav_arrow.png b/tools/droiddoc/templates-sdk-dev/assets/images/quicknav_arrow.png +deleted file mode 100644 +index 697ac82..0000000 +Binary files a/tools/droiddoc/templates-sdk-dev/assets/images/quicknav_arrow.png and /dev/null differ +diff --git a/tools/droiddoc/templates-sdk-dev/assets/images/quicknav_btn_bg.png b/tools/droiddoc/templates-sdk-dev/assets/images/quicknav_btn_bg.png +deleted file mode 100644 +index b80c9a8..0000000 +Binary files a/tools/droiddoc/templates-sdk-dev/assets/images/quicknav_btn_bg.png and /dev/null differ +diff --git a/tools/droiddoc/templates-sdk-dev/assets/images/resizable-e.gif b/tools/droiddoc/templates-sdk-dev/assets/images/resizable-e.gif +deleted file mode 100755 +index f748097..0000000 +Binary files a/tools/droiddoc/templates-sdk-dev/assets/images/resizable-e.gif and /dev/null differ +diff --git a/tools/droiddoc/templates-sdk-dev/assets/images/resizable-e2.gif b/tools/droiddoc/templates-sdk-dev/assets/images/resizable-e2.gif +deleted file mode 100755 +index e45d0c5..0000000 +Binary files a/tools/droiddoc/templates-sdk-dev/assets/images/resizable-e2.gif and /dev/null differ +diff --git a/tools/droiddoc/templates-sdk-dev/assets/images/resizable-eg.gif b/tools/droiddoc/templates-sdk-dev/assets/images/resizable-eg.gif +deleted file mode 100755 +index 6196616..0000000 +Binary files a/tools/droiddoc/templates-sdk-dev/assets/images/resizable-eg.gif and /dev/null differ +diff --git a/tools/droiddoc/templates-sdk-dev/assets/images/resizable-s.gif b/tools/droiddoc/templates-sdk-dev/assets/images/resizable-s.gif +deleted file mode 100755 +index 7f6a4eb..0000000 +Binary files a/tools/droiddoc/templates-sdk-dev/assets/images/resizable-s.gif and /dev/null differ +diff --git a/tools/droiddoc/templates-sdk-dev/assets/images/resizable-s2.gif b/tools/droiddoc/templates-sdk-dev/assets/images/resizable-s2.gif +deleted file mode 100755 +index 99e869c..0000000 +Binary files a/tools/droiddoc/templates-sdk-dev/assets/images/resizable-s2.gif and /dev/null differ +diff --git a/tools/droiddoc/templates-sdk-dev/assets/images/resizable-s2.png b/tools/droiddoc/templates-sdk-dev/assets/images/resizable-s2.png +deleted file mode 100644 +index f3a6d2d..0000000 +Binary files a/tools/droiddoc/templates-sdk-dev/assets/images/resizable-s2.png and /dev/null differ +diff --git a/tools/droiddoc/templates-sdk-dev/assets/images/resizable-sg.gif b/tools/droiddoc/templates-sdk-dev/assets/images/resizable-sg.gif +deleted file mode 100755 +index b4bea10..0000000 +Binary files a/tools/droiddoc/templates-sdk-dev/assets/images/resizable-sg.gif and /dev/null differ +diff --git a/tools/droiddoc/templates-sdk-dev/assets/images/resource-article.png b/tools/droiddoc/templates-sdk-dev/assets/images/resource-article.png +deleted file mode 100644 +index 416493f..0000000 +Binary files a/tools/droiddoc/templates-sdk-dev/assets/images/resource-article.png and /dev/null differ +diff --git a/tools/droiddoc/templates-sdk-dev/assets/images/resource-big-article.png b/tools/droiddoc/templates-sdk-dev/assets/images/resource-big-article.png +deleted file mode 100644 +index 7273275..0000000 +Binary files a/tools/droiddoc/templates-sdk-dev/assets/images/resource-big-article.png and /dev/null differ +diff --git a/tools/droiddoc/templates-sdk-dev/assets/images/resource-big-sample.png b/tools/droiddoc/templates-sdk-dev/assets/images/resource-big-sample.png +deleted file mode 100644 +index 59b6b68..0000000 +Binary files a/tools/droiddoc/templates-sdk-dev/assets/images/resource-big-sample.png and /dev/null differ +diff --git a/tools/droiddoc/templates-sdk-dev/assets/images/resource-big-tutorial.png b/tools/droiddoc/templates-sdk-dev/assets/images/resource-big-tutorial.png +deleted file mode 100644 +index c32e89a..0000000 +Binary files a/tools/droiddoc/templates-sdk-dev/assets/images/resource-big-tutorial.png and /dev/null differ +diff --git a/tools/droiddoc/templates-sdk-dev/assets/images/resource-big-video.png b/tools/droiddoc/templates-sdk-dev/assets/images/resource-big-video.png +deleted file mode 100644 +index 59d46a0..0000000 +Binary files a/tools/droiddoc/templates-sdk-dev/assets/images/resource-big-video.png and /dev/null differ +diff --git a/tools/droiddoc/templates-sdk-dev/assets/images/resource-card-default-android.jpg b/tools/droiddoc/templates-sdk-dev/assets/images/resource-card-default-android.jpg +deleted file mode 100644 +index 398030f..0000000 +Binary files a/tools/droiddoc/templates-sdk-dev/assets/images/resource-card-default-android.jpg and /dev/null differ +diff --git a/tools/droiddoc/templates-sdk-dev/assets/images/resource-sample.png b/tools/droiddoc/templates-sdk-dev/assets/images/resource-sample.png +deleted file mode 100644 +index f7a411c..0000000 +Binary files a/tools/droiddoc/templates-sdk-dev/assets/images/resource-sample.png and /dev/null differ +diff --git a/tools/droiddoc/templates-sdk-dev/assets/images/resource-tutorial.png b/tools/droiddoc/templates-sdk-dev/assets/images/resource-tutorial.png +deleted file mode 100644 +index 10a14fe..0000000 +Binary files a/tools/droiddoc/templates-sdk-dev/assets/images/resource-tutorial.png and /dev/null differ +diff --git a/tools/droiddoc/templates-sdk-dev/assets/images/resource-video.png b/tools/droiddoc/templates-sdk-dev/assets/images/resource-video.png +deleted file mode 100644 +index 8fd5cae..0000000 +Binary files a/tools/droiddoc/templates-sdk-dev/assets/images/resource-video.png and /dev/null differ +diff --git a/tools/droiddoc/templates-sdk-dev/assets/images/right_off.jpg b/tools/droiddoc/templates-sdk-dev/assets/images/right_off.jpg +deleted file mode 100755 +index 17d2efe..0000000 +Binary files a/tools/droiddoc/templates-sdk-dev/assets/images/right_off.jpg and /dev/null differ +diff --git a/tools/droiddoc/templates-sdk-dev/assets/images/right_on.jpg b/tools/droiddoc/templates-sdk-dev/assets/images/right_on.jpg +deleted file mode 100755 +index baa2af1..0000000 +Binary files a/tools/droiddoc/templates-sdk-dev/assets/images/right_on.jpg and /dev/null differ +diff --git a/tools/droiddoc/templates-sdk-dev/assets/images/sidenav-rule.png b/tools/droiddoc/templates-sdk-dev/assets/images/sidenav-rule.png +deleted file mode 100644 +index eab9920..0000000 +Binary files a/tools/droiddoc/templates-sdk-dev/assets/images/sidenav-rule.png and /dev/null differ +diff --git a/tools/droiddoc/templates-sdk-dev/assets/images/slide_1.jpg b/tools/droiddoc/templates-sdk-dev/assets/images/slide_1.jpg +deleted file mode 100755 +index 6d75be1..0000000 +Binary files a/tools/droiddoc/templates-sdk-dev/assets/images/slide_1.jpg and /dev/null differ +diff --git a/tools/droiddoc/templates-sdk-dev/assets/images/slide_2.jpg b/tools/droiddoc/templates-sdk-dev/assets/images/slide_2.jpg +deleted file mode 100755 +index aa994c2..0000000 +Binary files a/tools/droiddoc/templates-sdk-dev/assets/images/slide_2.jpg and /dev/null differ +diff --git a/tools/droiddoc/templates-sdk-dev/assets/images/slide_3.jpg b/tools/droiddoc/templates-sdk-dev/assets/images/slide_3.jpg +deleted file mode 100755 +index b04deb3..0000000 +Binary files a/tools/droiddoc/templates-sdk-dev/assets/images/slide_3.jpg and /dev/null differ +diff --git a/tools/droiddoc/templates-sdk-dev/assets/images/slide_large_1.jpg b/tools/droiddoc/templates-sdk-dev/assets/images/slide_large_1.jpg +deleted file mode 100755 +index a992e92..0000000 +Binary files a/tools/droiddoc/templates-sdk-dev/assets/images/slide_large_1.jpg and /dev/null differ +diff --git a/tools/droiddoc/templates-sdk-dev/assets/images/slide_large_2.jpg b/tools/droiddoc/templates-sdk-dev/assets/images/slide_large_2.jpg +deleted file mode 100755 +index 9af63f4..0000000 +Binary files a/tools/droiddoc/templates-sdk-dev/assets/images/slide_large_2.jpg and /dev/null differ +diff --git a/tools/droiddoc/templates-sdk-dev/assets/images/slide_large_3.jpg b/tools/droiddoc/templates-sdk-dev/assets/images/slide_large_3.jpg +deleted file mode 100755 +index fcf236c..0000000 +Binary files a/tools/droiddoc/templates-sdk-dev/assets/images/slide_large_3.jpg and /dev/null differ +diff --git a/tools/droiddoc/templates-sdk-dev/assets/images/slide_off.jpg b/tools/droiddoc/templates-sdk-dev/assets/images/slide_off.jpg +deleted file mode 100755 +index 5971227..0000000 +Binary files a/tools/droiddoc/templates-sdk-dev/assets/images/slide_off.jpg and /dev/null differ +diff --git a/tools/droiddoc/templates-sdk-dev/assets/images/slide_on.jpg b/tools/droiddoc/templates-sdk-dev/assets/images/slide_on.jpg +deleted file mode 100755 +index 7ca3577..0000000 +Binary files a/tools/droiddoc/templates-sdk-dev/assets/images/slide_on.jpg and /dev/null differ +diff --git a/tools/droiddoc/templates-sdk-dev/assets/images/spacer.gif b/tools/droiddoc/templates-sdk-dev/assets/images/spacer.gif +deleted file mode 100755 +index f96b355..0000000 +Binary files a/tools/droiddoc/templates-sdk-dev/assets/images/spacer.gif and /dev/null differ +diff --git a/tools/droiddoc/templates-sdk-dev/assets/images/sprite-2x.png b/tools/droiddoc/templates-sdk-dev/assets/images/sprite-2x.png +deleted file mode 100644 +index 185b7e8..0000000 +Binary files a/tools/droiddoc/templates-sdk-dev/assets/images/sprite-2x.png and /dev/null differ +diff --git a/tools/droiddoc/templates-sdk-dev/assets/images/sprite.png b/tools/droiddoc/templates-sdk-dev/assets/images/sprite.png +deleted file mode 100644 +index 562b23c..0000000 +Binary files a/tools/droiddoc/templates-sdk-dev/assets/images/sprite.png and /dev/null differ +diff --git a/tools/droiddoc/templates-sdk-dev/assets/images/sprite@2x.png b/tools/droiddoc/templates-sdk-dev/assets/images/sprite@2x.png +deleted file mode 100644 +index 2019e02..0000000 +Binary files a/tools/droiddoc/templates-sdk-dev/assets/images/sprite@2x.png and /dev/null differ +diff --git a/tools/droiddoc/templates-sdk-dev/assets/images/stack-arrow-right.png b/tools/droiddoc/templates-sdk-dev/assets/images/stack-arrow-right.png +deleted file mode 100644 +index 46d6a50..0000000 +Binary files a/tools/droiddoc/templates-sdk-dev/assets/images/stack-arrow-right.png and /dev/null differ +diff --git a/tools/droiddoc/templates-sdk-dev/assets/images/styles/callout.png b/tools/droiddoc/templates-sdk-dev/assets/images/styles/callout.png +deleted file mode 100644 +index 5d49f34..0000000 +Binary files a/tools/droiddoc/templates-sdk-dev/assets/images/styles/callout.png and /dev/null differ +diff --git a/tools/droiddoc/templates-sdk-dev/assets/images/styles/device_galaxynexus_blank_land_span13.png b/tools/droiddoc/templates-sdk-dev/assets/images/styles/device_galaxynexus_blank_land_span13.png +deleted file mode 100644 +index bab6aca..0000000 +Binary files a/tools/droiddoc/templates-sdk-dev/assets/images/styles/device_galaxynexus_blank_land_span13.png and /dev/null differ +diff --git a/tools/droiddoc/templates-sdk-dev/assets/images/styles/device_galaxynexus_blank_land_span8.png b/tools/droiddoc/templates-sdk-dev/assets/images/styles/device_galaxynexus_blank_land_span8.png +deleted file mode 100644 +index cb180bf..0000000 +Binary files a/tools/droiddoc/templates-sdk-dev/assets/images/styles/device_galaxynexus_blank_land_span8.png and /dev/null differ +diff --git a/tools/droiddoc/templates-sdk-dev/assets/images/styles/device_galaxynexus_blank_port_span5.png b/tools/droiddoc/templates-sdk-dev/assets/images/styles/device_galaxynexus_blank_port_span5.png +deleted file mode 100644 +index bdccc2f..0000000 +Binary files a/tools/droiddoc/templates-sdk-dev/assets/images/styles/device_galaxynexus_blank_port_span5.png and /dev/null differ +diff --git a/tools/droiddoc/templates-sdk-dev/assets/images/styles/device_galaxynexus_blank_port_span9.png b/tools/droiddoc/templates-sdk-dev/assets/images/styles/device_galaxynexus_blank_port_span9.png +deleted file mode 100644 +index 5e0135b..0000000 +Binary files a/tools/droiddoc/templates-sdk-dev/assets/images/styles/device_galaxynexus_blank_port_span9.png and /dev/null differ +diff --git a/tools/droiddoc/templates-sdk-dev/assets/images/styles/device_nexus4_blank_port_432.png b/tools/droiddoc/templates-sdk-dev/assets/images/styles/device_nexus4_blank_port_432.png +deleted file mode 100644 +index 9d41aa3..0000000 +Binary files a/tools/droiddoc/templates-sdk-dev/assets/images/styles/device_nexus4_blank_port_432.png and /dev/null differ +diff --git a/tools/droiddoc/templates-sdk-dev/assets/images/styles/device_nexus5_blank_land_span13.png b/tools/droiddoc/templates-sdk-dev/assets/images/styles/device_nexus5_blank_land_span13.png +deleted file mode 100644 +index 5d37121..0000000 +Binary files a/tools/droiddoc/templates-sdk-dev/assets/images/styles/device_nexus5_blank_land_span13.png and /dev/null differ +diff --git a/tools/droiddoc/templates-sdk-dev/assets/images/styles/device_nexus5_blank_port_span5.png b/tools/droiddoc/templates-sdk-dev/assets/images/styles/device_nexus5_blank_port_span5.png +deleted file mode 100644 +index df35117..0000000 +Binary files a/tools/droiddoc/templates-sdk-dev/assets/images/styles/device_nexus5_blank_port_span5.png and /dev/null differ +diff --git a/tools/droiddoc/templates-sdk-dev/assets/images/styles/device_wear_square.png b/tools/droiddoc/templates-sdk-dev/assets/images/styles/device_wear_square.png +deleted file mode 100644 +index 077a7e6..0000000 +Binary files a/tools/droiddoc/templates-sdk-dev/assets/images/styles/device_wear_square.png and /dev/null differ +diff --git a/tools/droiddoc/templates-sdk-dev/assets/images/styles/device_wear_square_small.png b/tools/droiddoc/templates-sdk-dev/assets/images/styles/device_wear_square_small.png +deleted file mode 100644 +index e7e1540..0000000 +Binary files a/tools/droiddoc/templates-sdk-dev/assets/images/styles/device_wear_square_small.png and /dev/null differ +diff --git a/tools/droiddoc/templates-sdk-dev/assets/images/styles/disclosure_down.png b/tools/droiddoc/templates-sdk-dev/assets/images/styles/disclosure_down.png +deleted file mode 100644 +index 6a0a8ee..0000000 +Binary files a/tools/droiddoc/templates-sdk-dev/assets/images/styles/disclosure_down.png and /dev/null differ +diff --git a/tools/droiddoc/templates-sdk-dev/assets/images/styles/disclosure_left.png b/tools/droiddoc/templates-sdk-dev/assets/images/styles/disclosure_left.png +deleted file mode 100644 +index e887b2a..0000000 +Binary files a/tools/droiddoc/templates-sdk-dev/assets/images/styles/disclosure_left.png and /dev/null differ +diff --git a/tools/droiddoc/templates-sdk-dev/assets/images/styles/disclosure_right.png b/tools/droiddoc/templates-sdk-dev/assets/images/styles/disclosure_right.png +deleted file mode 100644 +index ced7fa4..0000000 +Binary files a/tools/droiddoc/templates-sdk-dev/assets/images/styles/disclosure_right.png and /dev/null differ +diff --git a/tools/droiddoc/templates-sdk-dev/assets/images/styles/disclosure_up.png b/tools/droiddoc/templates-sdk-dev/assets/images/styles/disclosure_up.png +deleted file mode 100644 +index ddd4ec9..0000000 +Binary files a/tools/droiddoc/templates-sdk-dev/assets/images/styles/disclosure_up.png and /dev/null differ +diff --git a/tools/droiddoc/templates-sdk-dev/assets/images/styles/gototop.png b/tools/droiddoc/templates-sdk-dev/assets/images/styles/gototop.png +deleted file mode 100644 +index 5f09a29..0000000 +Binary files a/tools/droiddoc/templates-sdk-dev/assets/images/styles/gototop.png and /dev/null differ +diff --git a/tools/droiddoc/templates-sdk-dev/assets/images/styles/helpouts-logo-35.png b/tools/droiddoc/templates-sdk-dev/assets/images/styles/helpouts-logo-35.png +deleted file mode 100644 +index 3c2dc1a..0000000 +Binary files a/tools/droiddoc/templates-sdk-dev/assets/images/styles/helpouts-logo-35.png and /dev/null differ +diff --git a/tools/droiddoc/templates-sdk-dev/assets/images/styles/helpouts-logo-35_2x.png b/tools/droiddoc/templates-sdk-dev/assets/images/styles/helpouts-logo-35_2x.png +deleted file mode 100644 +index e34be2e..0000000 +Binary files a/tools/droiddoc/templates-sdk-dev/assets/images/styles/helpouts-logo-35_2x.png and /dev/null differ +diff --git a/tools/droiddoc/templates-sdk-dev/assets/images/styles/ico_action.png b/tools/droiddoc/templates-sdk-dev/assets/images/styles/ico_action.png +deleted file mode 100644 +index 30e4cc7..0000000 +Binary files a/tools/droiddoc/templates-sdk-dev/assets/images/styles/ico_action.png and /dev/null differ +diff --git a/tools/droiddoc/templates-sdk-dev/assets/images/styles/ico_good.png b/tools/droiddoc/templates-sdk-dev/assets/images/styles/ico_good.png +deleted file mode 100644 +index afebe1c..0000000 +Binary files a/tools/droiddoc/templates-sdk-dev/assets/images/styles/ico_good.png and /dev/null differ +diff --git a/tools/droiddoc/templates-sdk-dev/assets/images/styles/ico_movie_inline.png b/tools/droiddoc/templates-sdk-dev/assets/images/styles/ico_movie_inline.png +deleted file mode 100644 +index 7cfb5c5..0000000 +Binary files a/tools/droiddoc/templates-sdk-dev/assets/images/styles/ico_movie_inline.png and /dev/null differ +diff --git a/tools/droiddoc/templates-sdk-dev/assets/images/styles/ico_phone_tablet.png b/tools/droiddoc/templates-sdk-dev/assets/images/styles/ico_phone_tablet.png +deleted file mode 100644 +index 003b876..0000000 +Binary files a/tools/droiddoc/templates-sdk-dev/assets/images/styles/ico_phone_tablet.png and /dev/null differ +diff --git a/tools/droiddoc/templates-sdk-dev/assets/images/styles/ico_use.png b/tools/droiddoc/templates-sdk-dev/assets/images/styles/ico_use.png +deleted file mode 100644 +index 9d868b3..0000000 +Binary files a/tools/droiddoc/templates-sdk-dev/assets/images/styles/ico_use.png and /dev/null differ +diff --git a/tools/droiddoc/templates-sdk-dev/assets/images/styles/ico_web.png b/tools/droiddoc/templates-sdk-dev/assets/images/styles/ico_web.png +deleted file mode 100644 +index 0848e3c..0000000 +Binary files a/tools/droiddoc/templates-sdk-dev/assets/images/styles/ico_web.png and /dev/null differ +diff --git a/tools/droiddoc/templates-sdk-dev/assets/images/styles/ico_wrong.png b/tools/droiddoc/templates-sdk-dev/assets/images/styles/ico_wrong.png +deleted file mode 100644 +index b7d04ce..0000000 +Binary files a/tools/droiddoc/templates-sdk-dev/assets/images/styles/ico_wrong.png and /dev/null differ +diff --git a/tools/droiddoc/templates-sdk-dev/assets/images/styles/notice-designers-video.png b/tools/droiddoc/templates-sdk-dev/assets/images/styles/notice-designers-video.png +deleted file mode 100644 +index eea3485..0000000 +Binary files a/tools/droiddoc/templates-sdk-dev/assets/images/styles/notice-designers-video.png and /dev/null differ +diff --git a/tools/droiddoc/templates-sdk-dev/assets/images/styles/notice-designers-video@2x.png b/tools/droiddoc/templates-sdk-dev/assets/images/styles/notice-designers-video@2x.png +deleted file mode 100644 +index a5fdae3..0000000 +Binary files a/tools/droiddoc/templates-sdk-dev/assets/images/styles/notice-designers-video@2x.png and /dev/null differ +diff --git a/tools/droiddoc/templates-sdk-dev/assets/images/styles/notice-designers.png b/tools/droiddoc/templates-sdk-dev/assets/images/styles/notice-designers.png +deleted file mode 100644 +index 1fb22a2..0000000 +Binary files a/tools/droiddoc/templates-sdk-dev/assets/images/styles/notice-designers.png and /dev/null differ +diff --git a/tools/droiddoc/templates-sdk-dev/assets/images/styles/notice-designers@2x.png b/tools/droiddoc/templates-sdk-dev/assets/images/styles/notice-designers@2x.png +deleted file mode 100644 +index bc2f74b..0000000 +Binary files a/tools/droiddoc/templates-sdk-dev/assets/images/styles/notice-designers@2x.png and /dev/null differ +diff --git a/tools/droiddoc/templates-sdk-dev/assets/images/styles/notice-developers-video.png b/tools/droiddoc/templates-sdk-dev/assets/images/styles/notice-developers-video.png +deleted file mode 100644 +index e9f8ed2..0000000 +Binary files a/tools/droiddoc/templates-sdk-dev/assets/images/styles/notice-developers-video.png and /dev/null differ +diff --git a/tools/droiddoc/templates-sdk-dev/assets/images/styles/notice-developers-video@2x.png b/tools/droiddoc/templates-sdk-dev/assets/images/styles/notice-developers-video@2x.png +deleted file mode 100644 +index c067ac1..0000000 +Binary files a/tools/droiddoc/templates-sdk-dev/assets/images/styles/notice-developers-video@2x.png and /dev/null differ +diff --git a/tools/droiddoc/templates-sdk-dev/assets/images/styles/notice-developers.png b/tools/droiddoc/templates-sdk-dev/assets/images/styles/notice-developers.png +deleted file mode 100644 +index a29c31a..0000000 +Binary files a/tools/droiddoc/templates-sdk-dev/assets/images/styles/notice-developers.png and /dev/null differ +diff --git a/tools/droiddoc/templates-sdk-dev/assets/images/styles/notice-developers@2x.png b/tools/droiddoc/templates-sdk-dev/assets/images/styles/notice-developers@2x.png +deleted file mode 100644 +index d42f537..0000000 +Binary files a/tools/droiddoc/templates-sdk-dev/assets/images/styles/notice-developers@2x.png and /dev/null differ +diff --git a/tools/droiddoc/templates-sdk-dev/assets/images/styles/open_new_page.png b/tools/droiddoc/templates-sdk-dev/assets/images/styles/open_new_page.png +deleted file mode 100644 +index 6197e3a..0000000 +Binary files a/tools/droiddoc/templates-sdk-dev/assets/images/styles/open_new_page.png and /dev/null differ +diff --git a/tools/droiddoc/templates-sdk-dev/assets/images/triangle-closed-small.png b/tools/droiddoc/templates-sdk-dev/assets/images/triangle-closed-small.png +deleted file mode 100644 +index 002364a..0000000 +Binary files a/tools/droiddoc/templates-sdk-dev/assets/images/triangle-closed-small.png and /dev/null differ +diff --git a/tools/droiddoc/templates-sdk-dev/assets/images/triangle-closed.png b/tools/droiddoc/templates-sdk-dev/assets/images/triangle-closed.png +deleted file mode 100644 +index 40a68d9..0000000 +Binary files a/tools/droiddoc/templates-sdk-dev/assets/images/triangle-closed.png and /dev/null differ +diff --git a/tools/droiddoc/templates-sdk-dev/assets/images/triangle-opened-small.png b/tools/droiddoc/templates-sdk-dev/assets/images/triangle-opened-small.png +deleted file mode 100644 +index e1eb784..0000000 +Binary files a/tools/droiddoc/templates-sdk-dev/assets/images/triangle-opened-small.png and /dev/null differ +diff --git a/tools/droiddoc/templates-sdk-dev/assets/images/triangle-opened.png b/tools/droiddoc/templates-sdk-dev/assets/images/triangle-opened.png +deleted file mode 100644 +index 789f5fa..0000000 +Binary files a/tools/droiddoc/templates-sdk-dev/assets/images/triangle-opened.png and /dev/null differ +diff --git a/tools/droiddoc/templates-sdk-dev/assets/images/uiguidelines1.png b/tools/droiddoc/templates-sdk-dev/assets/images/uiguidelines1.png +deleted file mode 100644 +index 5ce1611..0000000 +Binary files a/tools/droiddoc/templates-sdk-dev/assets/images/uiguidelines1.png and /dev/null differ +diff --git a/tools/droiddoc/templates-sdk-dev/assets/images/video-droid.png b/tools/droiddoc/templates-sdk-dev/assets/images/video-droid.png +deleted file mode 100644 +index 25163b6..0000000 +Binary files a/tools/droiddoc/templates-sdk-dev/assets/images/video-droid.png and /dev/null differ +diff --git a/tools/droiddoc/templates-sdk-dev/assets/js/android_3p-bundle.js b/tools/droiddoc/templates-sdk-dev/assets/js/android_3p-bundle.js +deleted file mode 100644 +index 70d6c2f..0000000 +--- a/tools/droiddoc/templates-sdk-dev/assets/js/android_3p-bundle.js ++++ /dev/null +@@ -1,2772 +0,0 @@ +-//third_party/javascript/google_code_prettify/src/prettify.js +-/** +- * @license Copyright (C) 2006 Google Inc. +- * +- * 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. +- */ +- +-/** +- * @fileoverview +- * some functions for browser-side pretty printing of code contained in html. +- *

+- * +- * For a fairly comprehensive set of languages see the +- * README +- * file that came with this source. At a minimum, the lexer should work on a +- * number of languages including C and friends, Java, Python, Bash, SQL, HTML, +- * XML, CSS, Javascript, and Makefiles. It works passably on Ruby, PHP and Awk +- * and a subset of Perl, but, because of commenting conventions, doesn't work on +- * Smalltalk, Lisp-like, or CAML-like languages without an explicit lang class. +- *

+- * Usage:

    +- *
  1. include this source file in an html page via +- * {@code } +- *
  2. define style rules. See the example page for examples. +- *
  3. mark the {@code
    } and {@code } tags in your source with
    +- *    {@code class=prettyprint.}
    +- *    You can also use the (html deprecated) {@code } tag, but the pretty
    +- *    printer needs to do more substantial DOM manipulations to support that, so
    +- *    some css styles may not be preserved.
    +- * </ol>
    +- * That's it.  I wanted to keep the API as simple as possible, so there's no
    +- * need to specify which language the code is in, but if you wish, you can add
    +- * another class to the {@code <pre>} or {@code <code>} element to specify the
    +- * language, as in {@code <pre class="prettyprint lang-java">}.  Any class that
    +- * starts with "lang-" followed by a file extension, specifies the file type.
    +- * See the "lang-*.js" files in this directory for code that implements
    +- * per-language file handlers.
    +- * <p>
    +- * Change log:<br>
    +- * cbeust, 2006/08/22
    +- * <blockquote>
    +- *   Java annotations (start with "@") are now captured as literals ("lit")
    +- * </blockquote>
    +- * @requires console
    +- */
    +-
    +-// JSLint declarations
    +-/*global console, document, navigator, setTimeout, window */
    +-
    +-/**
    +- * Split {@code prettyPrint} into multiple timeouts so as not to interfere with
    +- * UI events.
    +- * If set to {@code false}, {@code prettyPrint()} is synchronous.
    +- */
    +-window['PR_SHOULD_USE_CONTINUATION'] = true;
    +-
    +-/** the number of characters between tab columns */
    +-window['PR_TAB_WIDTH'] = 8;
    +-
    +-/** Walks the DOM returning a properly escaped version of innerHTML.
    +-  * @param {Node} node
    +-  * @param {Array.<string>} out output buffer that receives chunks of HTML.
    +-  */
    +-window['PR_normalizedHtml']
    +-
    +-/** Contains functions for creating and registering new language handlers.
    +-  * @type {Object}
    +-  */
    +-  = window['PR']
    +-
    +-/** Pretty print a chunk of code.
    +-  *
    +-  * @param {string} sourceCodeHtml code as html
    +-  * @return {string} code as html, but prettier
    +-  */
    +-  = window['prettyPrintOne']
    +-/** Find all the {@code <pre>} and {@code <code>} tags in the DOM with
    +-  * {@code class=prettyprint} and prettify them.
    +-  * @param {Function?} opt_whenDone if specified, called when the last entry
    +-  *     has been finished.
    +-  */
    +-  = window['prettyPrint'] = void 0;
    +-
    +-/** browser detection. @extern @returns false if not IE, otherwise the major version. */
    +-window['_pr_isIE6'] = function () {
    +-  var ieVersion = navigator && navigator.userAgent &&
    +-      navigator.userAgent.match(/\bMSIE ([678])\./);
    +-  ieVersion = ieVersion ? +ieVersion[1] : false;
    +-  window['_pr_isIE6'] = function () { return ieVersion; };
    +-  return ieVersion;
    +-};
    +-
    +-
    +-(function () {
    +-  // Keyword lists for various languages.
    +-  var FLOW_CONTROL_KEYWORDS =
    +-      "break continue do else for if return while ";
    +-  var C_KEYWORDS = FLOW_CONTROL_KEYWORDS + "auto case char const default " +
    +-      "double enum extern float goto int long register short signed sizeof " +
    +-      "static struct switch typedef union unsigned void volatile ";
    +-  var COMMON_KEYWORDS = C_KEYWORDS + "catch class delete false import " +
    +-      "new operator private protected public this throw true try typeof ";
    +-  var CPP_KEYWORDS = COMMON_KEYWORDS + "alignof align_union asm axiom bool " +
    +-      "concept concept_map const_cast constexpr decltype " +
    +-      "dynamic_cast explicit export friend inline late_check " +
    +-      "mutable namespace nullptr reinterpret_cast static_assert static_cast " +
    +-      "template typeid typename using virtual wchar_t where ";
    +-  var JAVA_KEYWORDS = COMMON_KEYWORDS +
    +-      "abstract boolean byte extends final finally implements import " +
    +-      "instanceof null native package strictfp super synchronized throws " +
    +-      "transient ";
    +-  var CSHARP_KEYWORDS = JAVA_KEYWORDS +
    +-      "as base by checked decimal delegate descending dynamic event " +
    +-      "fixed foreach from group implicit in interface internal into is lock " +
    +-      "object out override orderby params partial readonly ref sbyte sealed " +
    +-      "stackalloc string select uint ulong unchecked unsafe ushort var ";
    +-  var COFFEE_KEYWORDS = "all and by catch class else extends false finally " +
    +-      "for if in is isnt loop new no not null of off on or return super then " +
    +-      "true try unless until when while yes ";
    +-  var JSCRIPT_KEYWORDS = COMMON_KEYWORDS +
    +-      "debugger eval export function get null set undefined var with " +
    +-      "Infinity NaN ";
    +-  var PERL_KEYWORDS = "caller delete die do dump elsif eval exit foreach for " +
    +-      "goto if import last local my next no our print package redo require " +
    +-      "sub undef unless until use wantarray while BEGIN END ";
    +-  var PYTHON_KEYWORDS = FLOW_CONTROL_KEYWORDS + "and as assert class def del " +
    +-      "elif except exec finally from global import in is lambda " +
    +-      "nonlocal not or pass print raise try with yield " +
    +-      "False True None ";
    +-  var RUBY_KEYWORDS = FLOW_CONTROL_KEYWORDS + "alias and begin case class def" +
    +-      " defined elsif end ensure false in module next nil not or redo rescue " +
    +-      "retry self super then true undef unless until when yield BEGIN END ";
    +-  var SH_KEYWORDS = FLOW_CONTROL_KEYWORDS + "case done elif esac eval fi " +
    +-      "function in local set then until ";
    +-  var ALL_KEYWORDS = (
    +-      CPP_KEYWORDS + CSHARP_KEYWORDS + JSCRIPT_KEYWORDS + PERL_KEYWORDS +
    +-      PYTHON_KEYWORDS + RUBY_KEYWORDS + SH_KEYWORDS);
    +-
    +-  // token style names.  correspond to css classes
    +-  /** token style for a string literal */
    +-  var PR_STRING = 'str';
    +-  /** token style for a keyword */
    +-  var PR_KEYWORD = 'kwd';
    +-  /** token style for a comment */
    +-  var PR_COMMENT = 'com';
    +-  /** token style for a type */
    +-  var PR_TYPE = 'typ';
    +-  /** token style for a literal value.  e.g. 1, null, true. */
    +-  var PR_LITERAL = 'lit';
    +-  /** token style for a punctuation string. */
    +-  var PR_PUNCTUATION = 'pun';
    +-  /** token style for a punctuation string. */
    +-  var PR_PLAIN = 'pln';
    +-
    +-  /** token style for an sgml tag. */
    +-  var PR_TAG = 'tag';
    +-  /** token style for a markup declaration such as a DOCTYPE. */
    +-  var PR_DECLARATION = 'dec';
    +-  /** token style for embedded source. */
    +-  var PR_SOURCE = 'src';
    +-  /** token style for an sgml attribute name. */
    +-  var PR_ATTRIB_NAME = 'atn';
    +-  /** token style for an sgml attribute value. */
    +-  var PR_ATTRIB_VALUE = 'atv';
    +-
    +-  /**
    +-   * A class that indicates a section of markup that is not code, e.g. to allow
    +-   * embedding of line numbers within code listings.
    +-   */
    +-  var PR_NOCODE = 'nocode';
    +-
    +-  /** A set of tokens that can precede a regular expression literal in
    +-    * javascript.
    +-    * http://www.mozilla.org/js/language/js20/rationale/syntax.html has the full
    +-    * list, but I've removed ones that might be problematic when seen in
    +-    * languages that don't support regular expression literals.
    +-    *
    +-    * <p>Specifically, I've removed any keywords that can't precede a regexp
    +-    * literal in a syntactically legal javascript program, and I've removed the
    +-    * "in" keyword since it's not a keyword in many languages, and might be used
    +-    * as a count of inches.
    +-    *
    +-    * <p>The link a above does not accurately describe EcmaScript rules since
    +-    * it fails to distinguish between (a=++/b/i) and (a++/b/i) but it works
    +-    * very well in practice.
    +-    *
    +-    * @private
    +-    */
    +-  var REGEXP_PRECEDER_PATTERN = function () {
    +-      var preceders = [
    +-          "!", "!=", "!==", "#", "%", "%=", "&", "&&", "&&=",
    +-          "&=", "(", "*", "*=", /* "+", */ "+=", ",", /* "-", */ "-=",
    +-          "->", /*".", "..", "...", handled below */ "/", "/=", ":", "::", ";",
    +-          "<", "<<", "<<=", "<=", "=", "==", "===", ">",
    +-          ">=", ">>", ">>=", ">>>", ">>>=", "?", "@", "[",
    +-          "^", "^=", "^^", "^^=", "{", "|", "|=", "||",
    +-          "||=", "~" /* handles =~ and !~ */,
    +-          "break", "case", "continue", "delete",
    +-          "do", "else", "finally", "instanceof",
    +-          "return", "throw", "try", "typeof"
    +-          ];
    +-      var pattern = '(?:^^|[+-]';
    +-      for (var i = 0; i < preceders.length; ++i) {
    +-        pattern += '|' + preceders[i].replace(/([^=<>:&a-z])/g, '\\$1');
    +-      }
    +-      pattern += ')\\s*';  // matches at end, and matches empty string
    +-      return pattern;
    +-      // CAVEAT: this does not properly handle the case where a regular
    +-      // expression immediately follows another since a regular expression may
    +-      // have flags for case-sensitivity and the like.  Having regexp tokens
    +-      // adjacent is not valid in any language I'm aware of, so I'm punting.
    +-      // TODO: maybe style special characters inside a regexp as punctuation.
    +-    }();
    +-
    +-  // Define regexps here so that the interpreter doesn't have to create an
    +-  // object each time the function containing them is called.
    +-  // The language spec requires a new object created even if you don't access
    +-  // the $1 members.
    +-  var pr_amp = /&/g;
    +-  var pr_lt = /</g;
    +-  var pr_gt = />/g;
    +-  var pr_quot = /\"/g;
    +-  /** like textToHtml but escapes double quotes to be attribute safe. */
    +-  function attribToHtml(str) {
    +-    return str.replace(pr_amp, '&amp;')
    +-        .replace(pr_lt, '&lt;')
    +-        .replace(pr_gt, '&gt;')
    +-        .replace(pr_quot, '&quot;');
    +-  }
    +-
    +-  /** escapest html special characters to html. */
    +-  function textToHtml(str) {
    +-    return str.replace(pr_amp, '&amp;')
    +-        .replace(pr_lt, '&lt;')
    +-        .replace(pr_gt, '&gt;');
    +-  }
    +-
    +-
    +-  var pr_ltEnt = /&lt;/g;
    +-  var pr_gtEnt = /&gt;/g;
    +-  var pr_aposEnt = /&apos;/g;
    +-  var pr_quotEnt = /&quot;/g;
    +-  var pr_ampEnt = /&amp;/g;
    +-  var pr_nbspEnt = /&nbsp;/g;
    +-  /** unescapes html to plain text. */
    +-  function htmlToText(html) {
    +-    var pos = html.indexOf('&');
    +-    if (pos < 0) { return html; }
    +-    // Handle numeric entities specially.  We can't use functional substitution
    +-    // since that doesn't work in older versions of Safari.
    +-    // These should be rare since most browsers convert them to normal chars.
    +-    for (--pos; (pos = html.indexOf('&#', pos + 1)) >= 0;) {
    +-      var end = html.indexOf(';', pos);
    +-      if (end >= 0) {
    +-        var num = html.substring(pos + 3, end);
    +-        var radix = 10;
    +-        if (num && num.charAt(0) === 'x') {
    +-          num = num.substring(1);
    +-          radix = 16;
    +-        }
    +-        var codePoint = parseInt(num, radix);
    +-        if (!isNaN(codePoint)) {
    +-          html = (html.substring(0, pos) + String.fromCharCode(codePoint) +
    +-                  html.substring(end + 1));
    +-        }
    +-      }
    +-    }
    +-
    +-    return html.replace(pr_ltEnt, '<')
    +-        .replace(pr_gtEnt, '>')
    +-        .replace(pr_aposEnt, "'")
    +-        .replace(pr_quotEnt, '"')
    +-        .replace(pr_nbspEnt, ' ')
    +-        .replace(pr_ampEnt, '&');
    +-  }
    +-
    +-  /** is the given node's innerHTML normally unescaped? */
    +-  function isRawContent(node) {
    +-    return 'XMP' === node.tagName;
    +-  }
    +-
    +-  var newlineRe = /[\r\n]/g;
    +-  /**
    +-   * Are newlines and adjacent spaces significant in the given node's innerHTML?
    +-   */
    +-  function isPreformatted(node, content) {
    +-    // PRE means preformatted, and is a very common case, so don't create
    +-    // unnecessary computed style objects.
    +-    if ('PRE' === node.tagName) { return true; }
    +-    if (!newlineRe.test(content)) { return true; }  // Don't care
    +-    var whitespace = '';
    +-    // For disconnected nodes, IE has no currentStyle.
    +-    if (node.currentStyle) {
    +-      whitespace = node.currentStyle.whiteSpace;
    +-    } else if (window.getComputedStyle) {
    +-      // Firefox makes a best guess if node is disconnected whereas Safari
    +-      // returns the empty string.
    +-      whitespace = window.getComputedStyle(node, null).whiteSpace;
    +-    }
    +-    return !whitespace || whitespace === 'pre';
    +-  }
    +-
    +-  function normalizedHtml(node, out, opt_sortAttrs) {
    +-    switch (node.nodeType) {
    +-      case 1:  // an element
    +-        var name = node.tagName.toLowerCase();
    +-
    +-        out.push('<', name);
    +-        var attrs = node.attributes;
    +-        var n = attrs.length;
    +-        if (n) {
    +-          if (opt_sortAttrs) {
    +-            var sortedAttrs = [];
    +-            for (var i = n; --i >= 0;) { sortedAttrs[i] = attrs[i]; }
    +-            sortedAttrs.sort(function (a, b) {
    +-                return (a.name < b.name) ? -1 : a.name === b.name ? 0 : 1;
    +-              });
    +-            attrs = sortedAttrs;
    +-          }
    +-          for (var i = 0; i < n; ++i) {
    +-            var attr = attrs[i];
    +-            if (!attr.specified) { continue; }
    +-            out.push(' ', attr.name.toLowerCase(),
    +-                     '="', attribToHtml(attr.value), '"');
    +-          }
    +-        }
    +-        out.push('>');
    +-        for (var child = node.firstChild; child; child = child.nextSibling) {
    +-          normalizedHtml(child, out, opt_sortAttrs);
    +-        }
    +-        if (node.firstChild || !/^(?:br|link|img)$/.test(name)) {
    +-          out.push('<\/', name, '>');
    +-        }
    +-        break;
    +-      case 3: case 4: // text
    +-        out.push(textToHtml(node.nodeValue));
    +-        break;
    +-    }
    +-  }
    +-
    +-  /**
    +-   * Given a group of {@link RegExp}s, returns a {@code RegExp} that globally
    +-   * matches the union o the sets o strings matched d by the input RegExp.
    +-   * Since it matches globally, if the input strings have a start-of-input
    +-   * anchor (/^.../), it is ignored for the purposes of unioning.
    +-   * @param {Array.<RegExp>} regexs non multiline, non-global regexs.
    +-   * @return {RegExp} a global regex.
    +-   */
    +-  function combinePrefixPatterns(regexs) {
    +-    var capturedGroupIndex = 0;
    +-
    +-    var needToFoldCase = false;
    +-    var ignoreCase = false;
    +-    for (var i = 0, n = regexs.length; i < n; ++i) {
    +-      var regex = regexs[i];
    +-      if (regex.ignoreCase) {
    +-        ignoreCase = true;
    +-      } else if (/[a-z]/i.test(regex.source.replace(
    +-                     /\\u[0-9a-f]{4}|\\x[0-9a-f]{2}|\\[^ux]/gi, ''))) {
    +-        needToFoldCase = true;
    +-        ignoreCase = false;
    +-        break;
    +-      }
    +-    }
    +-
    +-    function decodeEscape(charsetPart) {
    +-      if (charsetPart.charAt(0) !== '\\') { return charsetPart.charCodeAt(0); }
    +-      switch (charsetPart.charAt(1)) {
    +-        case 'b': return 8;
    +-        case 't': return 9;
    +-        case 'n': return 0xa;
    +-        case 'v': return 0xb;
    +-        case 'f': return 0xc;
    +-        case 'r': return 0xd;
    +-        case 'u': case 'x':
    +-          return parseInt(charsetPart.substring(2), 16)
    +-              || charsetPart.charCodeAt(1);
    +-        case '0': case '1': case '2': case '3': case '4':
    +-        case '5': case '6': case '7':
    +-          return parseInt(charsetPart.substring(1), 8);
    +-        default: return charsetPart.charCodeAt(1);
    +-      }
    +-    }
    +-
    +-    function encodeEscape(charCode) {
    +-      if (charCode < 0x20) {
    +-        return (charCode < 0x10 ? '\\x0' : '\\x') + charCode.toString(16);
    +-      }
    +-      var ch = String.fromCharCode(charCode);
    +-      if (ch === '\\' || ch === '-' || ch === '[' || ch === ']') {
    +-        ch = '\\' + ch;
    +-      }
    +-      return ch;
    +-    }
    +-
    +-    function caseFoldCharset(charSet) {
    +-      var charsetParts = charSet.substring(1, charSet.length - 1).match(
    +-          new RegExp(
    +-              '\\\\u[0-9A-Fa-f]{4}'
    +-              + '|\\\\x[0-9A-Fa-f]{2}'
    +-              + '|\\\\[0-3][0-7]{0,2}'
    +-              + '|\\\\[0-7]{1,2}'
    +-              + '|\\\\[\\s\\S]'
    +-              + '|-'
    +-              + '|[^-\\\\]',
    +-              'g'));
    +-      var groups = [];
    +-      var ranges = [];
    +-      var inverse = charsetParts[0] === '^';
    +-      for (var i = inverse ? 1 : 0, n = charsetParts.length; i < n; ++i) {
    +-        var p = charsetParts[i];
    +-        switch (p) {
    +-          case '\\B': case '\\b':
    +-          case '\\D': case '\\d':
    +-          case '\\S': case '\\s':
    +-          case '\\W': case '\\w':
    +-            groups.push(p);
    +-            continue;
    +-        }
    +-        var start = decodeEscape(p);
    +-        var end;
    +-        if (i + 2 < n && '-' === charsetParts[i + 1]) {
    +-          end = decodeEscape(charsetParts[i + 2]);
    +-          i += 2;
    +-        } else {
    +-          end = start;
    +-        }
    +-        ranges.push([start, end]);
    +-        // If the range might intersect letters, then expand it.
    +-        if (!(end < 65 || start > 122)) {
    +-          if (!(end < 65 || start > 90)) {
    +-            ranges.push([Math.max(65, start) | 32, Math.min(end, 90) | 32]);
    +-          }
    +-          if (!(end < 97 || start > 122)) {
    +-            ranges.push([Math.max(97, start) & ~32, Math.min(end, 122) & ~32]);
    +-          }
    +-        }
    +-      }
    +-
    +-      // [[1, 10], [3, 4], [8, 12], [14, 14], [16, 16], [17, 17]]
    +-      // -> [[1, 12], [14, 14], [16, 17]]
    +-      ranges.sort(function (a, b) { return (a[0] - b[0]) || (b[1]  - a[1]); });
    +-      var consolidatedRanges = [];
    +-      var lastRange = [NaN, NaN];
    +-      for (var i = 0; i < ranges.length; ++i) {
    +-        var range = ranges[i];
    +-        if (range[0] <= lastRange[1] + 1) {
    +-          lastRange[1] = Math.max(lastRange[1], range[1]);
    +-        } else {
    +-          consolidatedRanges.push(lastRange = range);
    +-        }
    +-      }
    +-
    +-      var out = ['['];
    +-      if (inverse) { out.push('^'); }
    +-      out.push.apply(out, groups);
    +-      for (var i = 0; i < consolidatedRanges.length; ++i) {
    +-        var range = consolidatedRanges[i];
    +-        out.push(encodeEscape(range[0]));
    +-        if (range[1] > range[0]) {
    +-          if (range[1] + 1 > range[0]) { out.push('-'); }
    +-          out.push(encodeEscape(range[1]));
    +-        }
    +-      }
    +-      out.push(']');
    +-      return out.join('');
    +-    }
    +-
    +-    function allowAnywhereFoldCaseAndRenumberGroups(regex) {
    +-      // Split into character sets, escape sequences, punctuation strings
    +-      // like ('(', '(?:', ')', '^'), and runs of characters that do not
    +-      // include any of the above.
    +-      var parts = regex.source.match(
    +-          new RegExp(
    +-              '(?:'
    +-              + '\\[(?:[^\\x5C\\x5D]|\\\\[\\s\\S])*\\]'  // a character set
    +-              + '|\\\\u[A-Fa-f0-9]{4}'  // a unicode escape
    +-              + '|\\\\x[A-Fa-f0-9]{2}'  // a hex escape
    +-              + '|\\\\[0-9]+'  // a back-reference or octal escape
    +-              + '|\\\\[^ux0-9]'  // other escape sequence
    +-              + '|\\(\\?[:!=]'  // start of a non-capturing group
    +-              + '|[\\(\\)\\^]'  // start/emd of a group, or line start
    +-              + '|[^\\x5B\\x5C\\(\\)\\^]+'  // run of other characters
    +-              + ')',
    +-              'g'));
    +-      var n = parts.length;
    +-
    +-      // Maps captured group numbers to the number they will occupy in
    +-      // the output or to -1 if that has not been determined, or to
    +-      // undefined if they need not be capturing in the output.
    +-      var capturedGroups = [];
    +-
    +-      // Walk over and identify back references to build the capturedGroups
    +-      // mapping.
    +-      for (var i = 0, groupIndex = 0; i < n; ++i) {
    +-        var p = parts[i];
    +-        if (p === '(') {
    +-          // groups are 1-indexed, so max group index is count of '('
    +-          ++groupIndex;
    +-        } else if ('\\' === p.charAt(0)) {
    +-          var decimalValue = +p.substring(1);
    +-          if (decimalValue && decimalValue <= groupIndex) {
    +-            capturedGroups[decimalValue] = -1;
    +-          }
    +-        }
    +-      }
    +-
    +-      // Renumber groups and reduce capturing groups to non-capturing groups
    +-      // where possible.
    +-      for (var i = 1; i < capturedGroups.length; ++i) {
    +-        if (-1 === capturedGroups[i]) {
    +-          capturedGroups[i] = ++capturedGroupIndex;
    +-        }
    +-      }
    +-      for (var i = 0, groupIndex = 0; i < n; ++i) {
    +-        var p = parts[i];
    +-        if (p === '(') {
    +-          ++groupIndex;
    +-          if (capturedGroups[groupIndex] === undefined) {
    +-            parts[i] = '(?:';
    +-          }
    +-        } else if ('\\' === p.charAt(0)) {
    +-          var decimalValue = +p.substring(1);
    +-          if (decimalValue && decimalValue <= groupIndex) {
    +-            parts[i] = '\\' + capturedGroups[groupIndex];
    +-          }
    +-        }
    +-      }
    +-
    +-      // Remove any prefix anchors so that the output will match anywhere.
    +-      // ^^ really does mean an anchored match though.
    +-      for (var i = 0, groupIndex = 0; i < n; ++i) {
    +-        if ('^' === parts[i] && '^' !== parts[i + 1]) { parts[i] = ''; }
    +-      }
    +-
    +-      // Expand letters to groupts to handle mixing of case-sensitive and
    +-      // case-insensitive patterns if necessary.
    +-      if (regex.ignoreCase && needToFoldCase) {
    +-        for (var i = 0; i < n; ++i) {
    +-          var p = parts[i];
    +-          var ch0 = p.charAt(0);
    +-          if (p.length >= 2 && ch0 === '[') {
    +-            parts[i] = caseFoldCharset(p);
    +-          } else if (ch0 !== '\\') {
    +-            // TODO: handle letters in numeric escapes.
    +-            parts[i] = p.replace(
    +-                /[a-zA-Z]/g,
    +-                function (ch) {
    +-                  var cc = ch.charCodeAt(0);
    +-                  return '[' + String.fromCharCode(cc & ~32, cc | 32) + ']';
    +-                });
    +-          }
    +-        }
    +-      }
    +-
    +-      return parts.join('');
    +-    }
    +-
    +-    var rewritten = [];
    +-    for (var i = 0, n = regexs.length; i < n; ++i) {
    +-      var regex = regexs[i];
    +-      if (regex.global || regex.multiline) { throw new Error('' + regex); }
    +-      rewritten.push(
    +-          '(?:' + allowAnywhereFoldCaseAndRenumberGroups(regex) + ')');
    +-    }
    +-
    +-    return new RegExp(rewritten.join('|'), ignoreCase ? 'gi' : 'g');
    +-  }
    +-
    +-  var PR_innerHtmlWorks = null;
    +-  function getInnerHtml(node) {
    +-    // inner html is hopelessly broken in Safari 2.0.4 when the content is
    +-    // an html description of well formed XML and the containing tag is a PRE
    +-    // tag, so we detect that case and emulate innerHTML.
    +-    if (null === PR_innerHtmlWorks) {
    +-      var testNode = document.createElement('PRE');
    +-      testNode.appendChild(
    +-          document.createTextNode('<!DOCTYPE foo PUBLIC "foo bar">\n<foo />'));
    +-      PR_innerHtmlWorks = !/</.test(testNode.innerHTML);
    +-    }
    +-
    +-    if (PR_innerHtmlWorks) {
    +-      var content = node.innerHTML;
    +-      // XMP tags contain unescaped entities so require special handling.
    +-      if (isRawContent(node)) {
    +-        content = textToHtml(content);
    +-      } else if (!isPreformatted(node, content)) {
    +-        content = content.replace(/(<br\s*\/?>)[\r\n]+/g, '$1')
    +-            .replace(/(?:[\r\n]+[ \t]*)+/g, ' ');
    +-      }
    +-      return content;
    +-    }
    +-
    +-    var out = [];
    +-    for (var child = node.firstChild; child; child = child.nextSibling) {
    +-      normalizedHtml(child, out);
    +-    }
    +-    return out.join('');
    +-  }
    +-
    +-  /** returns a function that expand tabs to spaces.  This function can be fed
    +-    * successive chunks of text, and will maintain its own internal state to
    +-    * keep track of how tabs are expanded.
    +-    * @return {function (string) : string} a function that takes
    +-    *   plain text and return the text with tabs expanded.
    +-    * @private
    +-    */
    +-  function makeTabExpander(tabWidth) {
    +-    var SPACES = '                ';
    +-    var charInLine = 0;
    +-
    +-    return function (plainText) {
    +-      // walk over each character looking for tabs and newlines.
    +-      // On tabs, expand them.  On newlines, reset charInLine.
    +-      // Otherwise increment charInLine
    +-      var out = null;
    +-      var pos = 0;
    +-      for (var i = 0, n = plainText.length; i < n; ++i) {
    +-        var ch = plainText.charAt(i);
    +-
    +-        switch (ch) {
    +-          case '\t':
    +-            if (!out) { out = []; }
    +-            out.push(plainText.substring(pos, i));
    +-            // calculate how much space we need in front of this part
    +-            // nSpaces is the amount of padding -- the number of spaces needed
    +-            // to move us to the next column, where columns occur at factors of
    +-            // tabWidth.
    +-            var nSpaces = tabWidth - (charInLine % tabWidth);
    +-            charInLine += nSpaces;
    +-            for (; nSpaces >= 0; nSpaces -= SPACES.length) {
    +-              out.push(SPACES.substring(0, nSpaces));
    +-            }
    +-            pos = i + 1;
    +-            break;
    +-          case '\n':
    +-            charInLine = 0;
    +-            break;
    +-          default:
    +-            ++charInLine;
    +-        }
    +-      }
    +-      if (!out) { return plainText; }
    +-      out.push(plainText.substring(pos));
    +-      return out.join('');
    +-    };
    +-  }
    +-
    +-  var pr_chunkPattern = new RegExp(
    +-      '[^<]+'  // A run of characters other than '<'
    +-      + '|<\!--[\\s\\S]*?--\>'  // an HTML comment
    +-      + '|<!\\[CDATA\\[[\\s\\S]*?\\]\\]>'  // a CDATA section
    +-      // a probable tag that should not be highlighted
    +-      + '|<\/?[a-zA-Z](?:[^>\"\']|\'[^\']*\'|\"[^\"]*\")*>'
    +-      + '|<',  // A '<' that does not begin a larger chunk
    +-      'g');
    +-  var pr_commentPrefix = /^<\!--/;
    +-  var pr_cdataPrefix = /^<!\[CDATA\[/;
    +-  var pr_brPrefix = /^<br\b/i;
    +-  var pr_tagNameRe = /^<(\/?)([a-zA-Z][a-zA-Z0-9]*)/;
    +-
    +-  /** split markup into chunks of html tags (style null) and
    +-    * plain text (style {@link #PR_PLAIN}), converting tags which are
    +-    * significant for tokenization (<br>) into their textual equivalent.
    +-    *
    +-    * @param {string} s html where whitespace is considered significant.
    +-    * @return {Object} source code and extracted tags.
    +-    * @private
    +-    */
    +-  function extractTags(s) {
    +-    // since the pattern has the 'g' modifier and defines no capturing groups,
    +-    // this will return a list of all chunks which we then classify and wrap as
    +-    // PR_Tokens
    +-    var matches = s.match(pr_chunkPattern);
    +-    var sourceBuf = [];
    +-    var sourceBufLen = 0;
    +-    var extractedTags = [];
    +-    if (matches) {
    +-      for (var i = 0, n = matches.length; i < n; ++i) {
    +-        var match = matches[i];
    +-        if (match.length > 1 && match.charAt(0) === '<') {
    +-          if (pr_commentPrefix.test(match)) { continue; }
    +-          if (pr_cdataPrefix.test(match)) {
    +-            // strip CDATA prefix and suffix.  Don't unescape since it's CDATA
    +-            sourceBuf.push(match.substring(9, match.length - 3));
    +-            sourceBufLen += match.length - 12;
    +-          } else if (pr_brPrefix.test(match)) {
    +-            // <br> tags are lexically significant so convert them to text.
    +-            // This is undone later.
    +-            sourceBuf.push('\n');
    +-            ++sourceBufLen;
    +-          } else {
    +-            if (match.indexOf(PR_NOCODE) >= 0 && isNoCodeTag(match)) {
    +-              // A <span class="nocode"> will start a section that should be
    +-              // ignored.  Continue walking the list until we see a matching end
    +-              // tag.
    +-              var name = match.match(pr_tagNameRe)[2];
    +-              var depth = 1;
    +-              var j;
    +-              end_tag_loop:
    +-              for (j = i + 1; j < n; ++j) {
    +-                var name2 = matches[j].match(pr_tagNameRe);
    +-                if (name2 && name2[2] === name) {
    +-                  if (name2[1] === '/') {
    +-                    if (--depth === 0) { break end_tag_loop; }
    +-                  } else {
    +-                    ++depth;
    +-                  }
    +-                }
    +-              }
    +-              if (j < n) {
    +-                extractedTags.push(
    +-                    sourceBufLen, matches.slice(i, j + 1).join(''));
    +-                i = j;
    +-              } else {  // Ignore unclosed sections.
    +-                extractedTags.push(sourceBufLen, match);
    +-              }
    +-            } else {
    +-              extractedTags.push(sourceBufLen, match);
    +-            }
    +-          }
    +-        } else {
    +-          var literalText = htmlToText(match);
    +-          sourceBuf.push(literalText);
    +-          sourceBufLen += literalText.length;
    +-        }
    +-      }
    +-    }
    +-    return { source: sourceBuf.join(''), tags: extractedTags };
    +-  }
    +-
    +-  /** True if the given tag contains a class attribute with the nocode class. */
    +-  function isNoCodeTag(tag) {
    +-    return !!tag
    +-        // First canonicalize the representation of attributes
    +-        .replace(/\s(\w+)\s*=\s*(?:\"([^\"]*)\"|'([^\']*)'|(\S+))/g,
    +-                 ' $1="$2$3$4"')
    +-        // Then look for the attribute we want.
    +-        .match(/[cC][lL][aA][sS][sS]=\"[^\"]*\bnocode\b/);
    +-  }
    +-
    +-  /**
    +-   * Apply the given language handler to sourceCode and add the resulting
    +-   * decorations to out.
    +-   * @param {number} basePos the index of sourceCode within the chunk of source
    +-   *    whose decorations are already present on out.
    +-   */
    +-  function appendDecorations(basePos, sourceCode, langHandler, out) {
    +-    if (!sourceCode) { return; }
    +-    var job = {
    +-      source: sourceCode,
    +-      basePos: basePos
    +-    };
    +-    langHandler(job);
    +-    out.push.apply(out, job.decorations);
    +-  }
    +-
    +-  /** Given triples of [style, pattern, context] returns a lexing function,
    +-    * The lexing function interprets the patterns to find token boundaries and
    +-    * returns a decoration list of the form
    +-    * [index_0, style_0, index_1, style_1, ..., index_n, style_n]
    +-    * where index_n is an index into the sourceCode, and style_n is a style
    +-    * constant like PR_PLAIN.  index_n-1 <= index_n, and style_n-1 applies to
    +-    * all characters in sourceCode[index_n-1:index_n].
    +-    *
    +-    * The stylePatterns is a list whose elements have the form
    +-    * [style : string, pattern : RegExp, DEPRECATED, shortcut : string].
    +-    *
    +-    * Style is a style constant like PR_PLAIN, or can be a string of the
    +-    * form 'lang-FOO', where FOO is a language extension describing the
    +-    * language of the portion of the token in $1 after pattern executes.
    +-    * E.g., if style is 'lang-lisp', and group 1 contains the text
    +-    * '(hello (world))', then that portion of the token will be passed to the
    +-    * registered lisp handler for formatting.
    +-    * The text before and after group 1 will be restyled using this decorator
    +-    * so decorators should take care that this doesn't result in infinite
    +-    * recursion.  For example, the HTML lexer rule for SCRIPT elements looks
    +-    * something like ['lang-js', /<[s]cript>(.+?)<\/script>/].  This may match
    +-    * '<script>foo()<\/script>', which would cause the current decorator to
    +-    * be called with '<script>' which would not match the same rule since
    +-    * group 1 must not be empty, so it would be instead styled as PR_TAG by
    +-    * the generic tag rule.  The handler registered for the 'js' extension would
    +-    * then be called with 'foo()', and finally, the current decorator would
    +-    * be called with '<\/script>' which would not match the original rule and
    +-    * so the generic tag rule would identify it as a tag.
    +-    *
    +-    * Pattern must only match prefixes, and if it matches a prefix, then that
    +-    * match is considered a token with the same style.
    +-    *
    +-    * Context is applied to the last non-whitespace, non-comment token
    +-    * recognized.
    +-    *
    +-    * Shortcut is an optional string of characters, any of which, if the first
    +-    * character, gurantee that this pattern and only this pattern matches.
    +-    *
    +-    * @param {Array} shortcutStylePatterns patterns that always start with
    +-    *   a known character.  Must have a shortcut string.
    +-    * @param {Array} fallthroughStylePatterns patterns that will be tried in
    +-    *   order if the shortcut ones fail.  May have shortcuts.
    +-    *
    +-    * @return {function (Object)} a
    +-    *   function that takes source code and returns a list of decorations.
    +-    */
    +-  function createSimpleLexer(shortcutStylePatterns, fallthroughStylePatterns) {
    +-    var shortcuts = {};
    +-    var tokenizer;
    +-    (function () {
    +-      var allPatterns = shortcutStylePatterns.concat(fallthroughStylePatterns);
    +-      var allRegexs = [];
    +-      var regexKeys = {};
    +-      for (var i = 0, n = allPatterns.length; i < n; ++i) {
    +-        var patternParts = allPatterns[i];
    +-        var shortcutChars = patternParts[3];
    +-        if (shortcutChars) {
    +-          for (var c = shortcutChars.length; --c >= 0;) {
    +-            shortcuts[shortcutChars.charAt(c)] = patternParts;
    +-          }
    +-        }
    +-        var regex = patternParts[1];
    +-        var k = '' + regex;
    +-        if (!regexKeys.hasOwnProperty(k)) {
    +-          allRegexs.push(regex);
    +-          regexKeys[k] = null;
    +-        }
    +-      }
    +-      allRegexs.push(/[\0-\uffff]/);
    +-      tokenizer = combinePrefixPatterns(allRegexs);
    +-    })();
    +-
    +-    var nPatterns = fallthroughStylePatterns.length;
    +-    var notWs = /\S/;
    +-
    +-    /**
    +-     * Lexes job.source and produces an output array job.decorations of style
    +-     * classes preceded by the position at which they start in job.source in
    +-     * order.
    +-     *
    +-     * @param {Object} job an object like {@code
    +-     *    source: {string} sourceText plain text,
    +-     *    basePos: {int} position of job.source in the larger chunk of
    +-     *        sourceCode.
    +-     * }
    +-     */
    +-    var decorate = function (job) {
    +-      var sourceCode = job.source, basePos = job.basePos;
    +-      /** Even entries are positions in source in ascending order.  Odd enties
    +-        * are style markers (e.g., PR_COMMENT) that run from that position until
    +-        * the end.
    +-        * @type {Array.<number|string>}
    +-        */
    +-      var decorations = [basePos, PR_PLAIN];
    +-      var pos = 0;  // index into sourceCode
    +-      var tokens = sourceCode.match(tokenizer) || [];
    +-      var styleCache = {};
    +-
    +-      for (var ti = 0, nTokens = tokens.length; ti < nTokens; ++ti) {
    +-        var token = tokens[ti];
    +-        var style = styleCache[token];
    +-        var match = void 0;
    +-
    +-        var isEmbedded;
    +-        if (typeof style === 'string') {
    +-          isEmbedded = false;
    +-        } else {
    +-          var patternParts = shortcuts[token.charAt(0)];
    +-          if (patternParts) {
    +-            match = token.match(patternParts[1]);
    +-            style = patternParts[0];
    +-          } else {
    +-            for (var i = 0; i < nPatterns; ++i) {
    +-              patternParts = fallthroughStylePatterns[i];
    +-              match = token.match(patternParts[1]);
    +-              if (match) {
    +-                style = patternParts[0];
    +-                break;
    +-              }
    +-            }
    +-
    +-            if (!match) {  // make sure that we make progress
    +-              style = PR_PLAIN;
    +-            }
    +-          }
    +-
    +-          isEmbedded = style.length >= 5 && 'lang-' === style.substring(0, 5);
    +-          if (isEmbedded && !(match && typeof match[1] === 'string')) {
    +-            isEmbedded = false;
    +-            style = PR_SOURCE;
    +-          }
    +-
    +-          if (!isEmbedded) { styleCache[token] = style; }
    +-        }
    +-
    +-        var tokenStart = pos;
    +-        pos += token.length;
    +-
    +-        if (!isEmbedded) {
    +-          decorations.push(basePos + tokenStart, style);
    +-        } else {  // Treat group 1 as an embedded block of source code.
    +-          var embeddedSource = match[1];
    +-          var embeddedSourceStart = token.indexOf(embeddedSource);
    +-          var embeddedSourceEnd = embeddedSourceStart + embeddedSource.length;
    +-          if (match[2]) {
    +-            // If embeddedSource can be blank, then it would match at the
    +-            // beginning which would cause us to infinitely recurse on the
    +-            // entire token, so we catch the right context in match[2].
    +-            embeddedSourceEnd = token.length - match[2].length;
    +-            embeddedSourceStart = embeddedSourceEnd - embeddedSource.length;
    +-          }
    +-          var lang = style.substring(5);
    +-          // Decorate the left of the embedded source
    +-          appendDecorations(
    +-              basePos + tokenStart,
    +-              token.substring(0, embeddedSourceStart),
    +-              decorate, decorations);
    +-          // Decorate the embedded source
    +-          appendDecorations(
    +-              basePos + tokenStart + embeddedSourceStart,
    +-              embeddedSource,
    +-              langHandlerForExtension(lang, embeddedSource),
    +-              decorations);
    +-          // Decorate the right of the embedded section
    +-          appendDecorations(
    +-              basePos + tokenStart + embeddedSourceEnd,
    +-              token.substring(embeddedSourceEnd),
    +-              decorate, decorations);
    +-        }
    +-      }
    +-      job.decorations = decorations;
    +-    };
    +-    return decorate;
    +-  }
    +-
    +-  /** returns a function that produces a list of decorations from source text.
    +-    *
    +-    * This code treats ", ', and ` as string delimiters, and \ as a string
    +-    * escape.  It does not recognize perl's qq() style strings.
    +-    * It has no special handling for double delimiter escapes as in basic, or
    +-    * the tripled delimiters used in python, but should work on those regardless
    +-    * although in those cases a single string literal may be broken up into
    +-    * multiple adjacent string literals.
    +-    *
    +-    * It recognizes C, C++, and shell style comments.
    +-    *
    +-    * @param {Object} options a set of optional parameters.
    +-    * @return {function (Object)} a function that examines the source code
    +-    *     in the input job and builds the decoration list.
    +-    */
    +-  function sourceDecorator(options) {
    +-    var shortcutStylePatterns = [], fallthroughStylePatterns = [];
    +-    if (options['tripleQuotedStrings']) {
    +-      // '''multi-line-string''', 'single-line-string', and double-quoted
    +-      shortcutStylePatterns.push(
    +-          [PR_STRING,  /^(?:\'\'\'(?:[^\'\\]|\\[\s\S]|\'{1,2}(?=[^\']))*(?:\'\'\'|$)|\"\"\"(?:[^\"\\]|\\[\s\S]|\"{1,2}(?=[^\"]))*(?:\"\"\"|$)|\'(?:[^\\\']|\\[\s\S])*(?:\'|$)|\"(?:[^\\\"]|\\[\s\S])*(?:\"|$))/,
    +-           null, '\'"']);
    +-    } else if (options['multiLineStrings']) {
    +-      // 'multi-line-string', "multi-line-string"
    +-      shortcutStylePatterns.push(
    +-          [PR_STRING,  /^(?:\'(?:[^\\\']|\\[\s\S])*(?:\'|$)|\"(?:[^\\\"]|\\[\s\S])*(?:\"|$)|\`(?:[^\\\`]|\\[\s\S])*(?:\`|$))/,
    +-           null, '\'"`']);
    +-    } else {
    +-      // 'single-line-string', "single-line-string"
    +-      shortcutStylePatterns.push(
    +-          [PR_STRING,
    +-           /^(?:\'(?:[^\\\'\r\n]|\\.)*(?:\'|$)|\"(?:[^\\\"\r\n]|\\.)*(?:\"|$))/,
    +-           null, '"\'']);
    +-    }
    +-    if (options['verbatimStrings']) {
    +-      // verbatim-string-literal production from the C# grammar.  See issue 93.
    +-      fallthroughStylePatterns.push(
    +-          [PR_STRING, /^@\"(?:[^\"]|\"\")*(?:\"|$)/, null]);
    +-    }
    +-    var hc = options['hashComments'];
    +-    if (hc) {
    +-      if (options['cStyleComments']) {
    +-        if (hc > 1) {  // multiline hash comments
    +-          shortcutStylePatterns.push(
    +-              [PR_COMMENT, /^#(?:##(?:[^#]|#(?!##))*(?:###|$)|.*)/, null, '#']);
    +-        } else {
    +-          // Stop C preprocessor declarations at an unclosed open comment
    +-          shortcutStylePatterns.push(
    +-              [PR_COMMENT, /^#(?:(?:define|elif|else|endif|error|ifdef|include|ifndef|line|pragma|undef|warning)\b|[^\r\n]*)/,
    +-               null, '#']);
    +-        }
    +-        fallthroughStylePatterns.push(
    +-            [PR_STRING,
    +-             /^<(?:(?:(?:\.\.\/)*|\/?)(?:[\w-]+(?:\/[\w-]+)+)?[\w-]+\.h|[a-z]\w*)>/,
    +-             null]);
    +-      } else {
    +-        shortcutStylePatterns.push([PR_COMMENT, /^#[^\r\n]*/, null, '#']);
    +-      }
    +-    }
    +-    if (options['cStyleComments']) {
    +-      fallthroughStylePatterns.push([PR_COMMENT, /^\/\/[^\r\n]*/, null]);
    +-      fallthroughStylePatterns.push(
    +-          [PR_COMMENT, /^\/\*[\s\S]*?(?:\*\/|$)/, null]);
    +-    }
    +-    if (options['regexLiterals']) {
    +-      var REGEX_LITERAL = (
    +-          // A regular expression literal starts with a slash that is
    +-          // not followed by * or / so that it is not confused with
    +-          // comments.
    +-          '/(?=[^/*])'
    +-          // and then contains any number of raw characters,
    +-          + '(?:[^/\\x5B\\x5C]'
    +-          // escape sequences (\x5C),
    +-          +    '|\\x5C[\\s\\S]'
    +-          // or non-nesting character sets (\x5B\x5D);
    +-          +    '|\\x5B(?:[^\\x5C\\x5D]|\\x5C[\\s\\S])*(?:\\x5D|$))+'
    +-          // finally closed by a /.
    +-          + '/');
    +-      fallthroughStylePatterns.push(
    +-          ['lang-regex',
    +-           new RegExp('^' + REGEXP_PRECEDER_PATTERN + '(' + REGEX_LITERAL + ')')
    +-           ]);
    +-    }
    +-
    +-    var keywords = options['keywords'].replace(/^\s+|\s+$/g, '');
    +-    if (keywords.length) {
    +-      fallthroughStylePatterns.push(
    +-          [PR_KEYWORD,
    +-           new RegExp('^(?:' + keywords.replace(/\s+/g, '|') + ')\\b'), null]);
    +-    }
    +-
    +-    shortcutStylePatterns.push([PR_PLAIN,       /^\s+/, null, ' \r\n\t\xA0']);
    +-    fallthroughStylePatterns.push(
    +-        // TODO(mikesamuel): recognize non-latin letters and numerals in idents
    +-        [PR_LITERAL,     /^@[a-z_$][a-z_$@0-9]*/i, null],
    +-        [PR_TYPE,        /^@?[A-Z]+[a-z][A-Za-z_$@0-9]*/, null],
    +-        [PR_PLAIN,       /^[a-z_$][a-z_$@0-9]*/i, null],
    +-        [PR_LITERAL,
    +-         new RegExp(
    +-             '^(?:'
    +-             // A hex number
    +-             + '0x[a-f0-9]+'
    +-             // or an octal or decimal number,
    +-             + '|(?:\\d(?:_\\d+)*\\d*(?:\\.\\d*)?|\\.\\d\\+)'
    +-             // possibly in scientific notation
    +-             + '(?:e[+\\-]?\\d+)?'
    +-             + ')'
    +-             // with an optional modifier like UL for unsigned long
    +-             + '[a-z]*', 'i'),
    +-         null, '0123456789'],
    +-        [PR_PUNCTUATION, /^.[^\s\w\.$@\'\"\`\/\#]*/, null]);
    +-
    +-    return createSimpleLexer(shortcutStylePatterns, fallthroughStylePatterns);
    +-  }
    +-
    +-  var decorateSource = sourceDecorator({
    +-        'keywords': ALL_KEYWORDS,
    +-        'hashComments': true,
    +-        'cStyleComments': true,
    +-        'multiLineStrings': true,
    +-        'regexLiterals': true
    +-      });
    +-
    +-  /** Breaks {@code job.source} around style boundaries in
    +-    * {@code job.decorations} while re-interleaving {@code job.extractedTags},
    +-    * and leaves the result in {@code job.prettyPrintedHtml}.
    +-    * @param {Object} job like {
    +-    *    source: {string} source as plain text,
    +-    *    extractedTags: {Array.<number|string>} extractedTags chunks of raw
    +-    *                   html preceded by their position in {@code job.source}
    +-    *                   in order
    +-    *    decorations: {Array.<number|string} an array of style classes preceded
    +-    *                 by the position at which they start in job.source in order
    +-    * }
    +-    * @private
    +-    */
    +-  function recombineTagsAndDecorations(job) {
    +-    var sourceText = job.source;
    +-    var extractedTags = job.extractedTags;
    +-    var decorations = job.decorations;
    +-    var numberLines = job.numberLines;
    +-    var sourceNode = job.sourceNode;
    +-
    +-    var html = [];
    +-    // index past the last char in sourceText written to html
    +-    var outputIdx = 0;
    +-
    +-    var openDecoration = null;
    +-    var currentDecoration = null;
    +-    var tagPos = 0;  // index into extractedTags
    +-    var decPos = 0;  // index into decorations
    +-    var tabExpander = makeTabExpander(window['PR_TAB_WIDTH']);
    +-
    +-    var adjacentSpaceRe = /([\r\n ]) /g;
    +-    var startOrSpaceRe = /(^| ) /gm;
    +-    var newlineRe = /\r\n?|\n/g;
    +-    var trailingSpaceRe = /[ \r\n]$/;
    +-    var lastWasSpace = true;  // the last text chunk emitted ended with a space.
    +-
    +-    // See bug 71 and http://stackoverflow.com/questions/136443/why-doesnt-ie7-
    +-    var isIE678 = window['_pr_isIE6']();
    +-    var lineBreakHtml = (
    +-        isIE678
    +-        ? (sourceNode && sourceNode.tagName === 'PRE'
    +-           // Use line feeds instead of <br>s so that copying and pasting works
    +-           // on IE.
    +-           // See Issue 104 for the derivation of this mess.
    +-           ? (isIE678 === 6 ? '&#160;\r\n' :
    +-              isIE678 === 7 ? '&#160;<br />\r' :
    +-              isIE678 === 8 ? '&#160;<br />' : '&#160;\r')
    +-           // IE collapses multiple adjacent <br>s into 1 line break.
    +-           // Prefix every newline with '&#160;' to prevent such behavior.
    +-           // &nbsp; is the same as &#160; but works in XML as well as HTML.
    +-           : '&#160;<br />')
    +-        : '<br />');
    +-
    +-    var lineBreaker;
    +-    if (numberLines) {
    +-      var lineBreaks = [];
    +-      for (var i = 0; i < 10; ++i) {
    +-        lineBreaks[i] = lineBreakHtml + '</li><li class="L' + i + '">';
    +-      }
    +-      var lineNum = typeof numberLines === 'number'
    +-          ? numberLines - 1 /* number lines are 1 indexed */ : 0;
    +-      html.push('<ol class="linenums"><li class="L', (lineNum) % 10, '"');
    +-      if (lineNum) {
    +-        html.push(' value="', lineNum + 1, '"');
    +-      }
    +-      html.push('>');
    +-      lineBreaker = function () {
    +-        var lb = lineBreaks[++lineNum % 10];
    +-        // If a decoration is open, we need to close it before closing a list-item
    +-        // and reopen it on the other side of the list item.
    +-        return openDecoration
    +-            ? ('</span>' + lb + '<span class="' + openDecoration + '">') : lb;
    +-      };
    +-    } else {
    +-      lineBreaker = lineBreakHtml;
    +-    }
    +-
    +-    // A helper function that is responsible for opening sections of decoration
    +-    // and outputing properly escaped chunks of source
    +-    function emitTextUpTo(sourceIdx) {
    +-      if (sourceIdx > outputIdx) {
    +-        if (openDecoration && openDecoration !== currentDecoration) {
    +-          // Close the current decoration
    +-          html.push('</span>');
    +-          openDecoration = null;
    +-        }
    +-        if (!openDecoration && currentDecoration) {
    +-          openDecoration = currentDecoration;
    +-          html.push('<span class="', openDecoration, '">');
    +-        }
    +-        // This interacts badly with some wikis which introduces paragraph tags
    +-        // into pre blocks for some strange reason.
    +-        // It's necessary for IE though which seems to lose the preformattedness
    +-        // of <pre> tags when their innerHTML is assigned.
    +-        // http://stud3.tuwien.ac.at/~e0226430/innerHtmlQuirk.html
    +-        // and it serves to undo the conversion of <br>s to newlines done in
    +-        // chunkify.
    +-        var htmlChunk = textToHtml(
    +-            tabExpander(sourceText.substring(outputIdx, sourceIdx)))
    +-            .replace(lastWasSpace
    +-                     ? startOrSpaceRe
    +-                     : adjacentSpaceRe, '$1&#160;');
    +-        // Keep track of whether we need to escape space at the beginning of the
    +-        // next chunk.
    +-        lastWasSpace = trailingSpaceRe.test(htmlChunk);
    +-        html.push(htmlChunk.replace(newlineRe, lineBreaker));
    +-        outputIdx = sourceIdx;
    +-      }
    +-    }
    +-
    +-    while (true) {
    +-      // Determine if we're going to consume a tag this time around.  Otherwise
    +-      // we consume a decoration or exit.
    +-      var outputTag;
    +-      if (tagPos < extractedTags.length) {
    +-        if (decPos < decorations.length) {
    +-          // Pick one giving preference to extractedTags since we shouldn't open
    +-          // a new style that we're going to have to immediately close in order
    +-          // to output a tag.
    +-          outputTag = extractedTags[tagPos] <= decorations[decPos];
    +-        } else {
    +-          outputTag = true;
    +-        }
    +-      } else {
    +-        outputTag = false;
    +-      }
    +-      // Consume either a decoration or a tag or exit.
    +-      if (outputTag) {
    +-        emitTextUpTo(extractedTags[tagPos]);
    +-        if (openDecoration) {
    +-          // Close the current decoration
    +-          html.push('</span>');
    +-          openDecoration = null;
    +-        }
    +-        html.push(extractedTags[tagPos + 1]);
    +-        tagPos += 2;
    +-      } else if (decPos < decorations.length) {
    +-        emitTextUpTo(decorations[decPos]);
    +-        currentDecoration = decorations[decPos + 1];
    +-        decPos += 2;
    +-      } else {
    +-        break;
    +-      }
    +-    }
    +-    emitTextUpTo(sourceText.length);
    +-    if (openDecoration) {
    +-      html.push('</span>');
    +-    }
    +-    if (numberLines) { html.push('</li></ol>'); }
    +-    job.prettyPrintedHtml = html.join('');
    +-  }
    +-
    +-  /** Maps language-specific file extensions to handlers. */
    +-  var langHandlerRegistry = {};
    +-  /** Register a language handler for the given file extensions.
    +-    * @param {function (Object)} handler a function from source code to a list
    +-    *      of decorations.  Takes a single argument job which describes the
    +-    *      state of the computation.   The single parameter has the form
    +-    *      {@code {
    +-    *        source: {string} as plain text.
    +-    *        decorations: {Array.<number|string>} an array of style classes
    +-    *                     preceded by the position at which they start in
    +-    *                     job.source in order.
    +-    *                     The language handler should assigned this field.
    +-    *        basePos: {int} the position of source in the larger source chunk.
    +-    *                 All positions in the output decorations array are relative
    +-    *                 to the larger source chunk.
    +-    *      } }
    +-    * @param {Array.<string>} fileExtensions
    +-    */
    +-  function registerLangHandler(handler, fileExtensions) {
    +-    for (var i = fileExtensions.length; --i >= 0;) {
    +-      var ext = fileExtensions[i];
    +-      if (!langHandlerRegistry.hasOwnProperty(ext)) {
    +-        langHandlerRegistry[ext] = handler;
    +-      } else if ('console' in window) {
    +-        console['warn']('cannot override language handler %s', ext);
    +-      }
    +-    }
    +-  }
    +-  function langHandlerForExtension(extension, source) {
    +-    if (!(extension && langHandlerRegistry.hasOwnProperty(extension))) {
    +-      // Treat it as markup if the first non whitespace character is a < and
    +-      // the last non-whitespace character is a >.
    +-      extension = /^\s*</.test(source)
    +-          ? 'default-markup'
    +-          : 'default-code';
    +-    }
    +-    return langHandlerRegistry[extension];
    +-  }
    +-  registerLangHandler(decorateSource, ['default-code']);
    +-  registerLangHandler(
    +-      createSimpleLexer(
    +-          [],
    +-          [
    +-           [PR_PLAIN,       /^[^<?]+/],
    +-           [PR_DECLARATION, /^<!\w[^>]*(?:>|$)/],
    +-           [PR_COMMENT,     /^<\!--[\s\S]*?(?:-\->|$)/],
    +-           // Unescaped content in an unknown language
    +-           ['lang-',        /^<\?([\s\S]+?)(?:\?>|$)/],
    +-           ['lang-',        /^<%([\s\S]+?)(?:%>|$)/],
    +-           [PR_PUNCTUATION, /^(?:<[%?]|[%?]>)/],
    +-           ['lang-',        /^<xmp\b[^>]*>([\s\S]+?)<\/xmp\b[^>]*>/i],
    +-           // Unescaped content in javascript.  (Or possibly vbscript).
    +-           ['lang-js',      /^<script\b[^>]*>([\s\S]*?)(<\/script\b[^>]*>)/i],
    +-           // Contains unescaped stylesheet content
    +-           ['lang-css',     /^<style\b[^>]*>([\s\S]*?)(<\/style\b[^>]*>)/i],
    +-           ['lang-in.tag',  /^(<\/?[a-z][^<>]*>)/i]
    +-          ]),
    +-      ['default-markup', 'htm', 'html', 'mxml', 'xhtml', 'xml', 'xsl']);
    +-  registerLangHandler(
    +-      createSimpleLexer(
    +-          [
    +-           [PR_PLAIN,        /^[\s]+/, null, ' \t\r\n'],
    +-           [PR_ATTRIB_VALUE, /^(?:\"[^\"]*\"?|\'[^\']*\'?)/, null, '\"\'']
    +-           ],
    +-          [
    +-           [PR_TAG,          /^^<\/?[a-z](?:[\w.:-]*\w)?|\/?>$/i],
    +-           [PR_ATTRIB_NAME,  /^(?!style[\s=]|on)[a-z](?:[\w:-]*\w)?/i],
    +-           ['lang-uq.val',   /^=\s*([^>\'\"\s]*(?:[^>\'\"\s\/]|\/(?=\s)))/],
    +-           [PR_PUNCTUATION,  /^[=<>\/]+/],
    +-           ['lang-js',       /^on\w+\s*=\s*\"([^\"]+)\"/i],
    +-           ['lang-js',       /^on\w+\s*=\s*\'([^\']+)\'/i],
    +-           ['lang-js',       /^on\w+\s*=\s*([^\"\'>\s]+)/i],
    +-           ['lang-css',      /^style\s*=\s*\"([^\"]+)\"/i],
    +-           ['lang-css',      /^style\s*=\s*\'([^\']+)\'/i],
    +-           ['lang-css',      /^style\s*=\s*([^\"\'>\s]+)/i]
    +-           ]),
    +-      ['in.tag']);
    +-  registerLangHandler(
    +-      createSimpleLexer([], [[PR_ATTRIB_VALUE, /^[\s\S]+/]]), ['uq.val']);
    +-  registerLangHandler(sourceDecorator({
    +-          'keywords': CPP_KEYWORDS,
    +-          'hashComments': true,
    +-          'cStyleComments': true
    +-        }), ['c', 'cc', 'cpp', 'cxx', 'cyc', 'm']);
    +-  registerLangHandler(sourceDecorator({
    +-          'keywords': 'null true false'
    +-        }), ['json']);
    +-  registerLangHandler(sourceDecorator({
    +-          'keywords': CSHARP_KEYWORDS,
    +-          'hashComments': true,
    +-          'cStyleComments': true,
    +-          'verbatimStrings': true
    +-        }), ['cs']);
    +-  registerLangHandler(sourceDecorator({
    +-          'keywords': JAVA_KEYWORDS,
    +-          'cStyleComments': true
    +-        }), ['java']);
    +-  registerLangHandler(sourceDecorator({
    +-          'keywords': SH_KEYWORDS,
    +-          'hashComments': true,
    +-          'multiLineStrings': true
    +-        }), ['bsh', 'csh', 'sh']);
    +-  registerLangHandler(sourceDecorator({
    +-          'keywords': PYTHON_KEYWORDS,
    +-          'hashComments': true,
    +-          'multiLineStrings': true,
    +-          'tripleQuotedStrings': true
    +-        }), ['cv', 'py']);
    +-  registerLangHandler(sourceDecorator({
    +-          'keywords': PERL_KEYWORDS,
    +-          'hashComments': true,
    +-          'multiLineStrings': true,
    +-          'regexLiterals': true
    +-        }), ['perl', 'pl', 'pm']);
    +-  registerLangHandler(sourceDecorator({
    +-          'keywords': RUBY_KEYWORDS,
    +-          'hashComments': true,
    +-          'multiLineStrings': true,
    +-          'regexLiterals': true
    +-        }), ['rb']);
    +-  registerLangHandler(sourceDecorator({
    +-          'keywords': JSCRIPT_KEYWORDS,
    +-          'cStyleComments': true,
    +-          'regexLiterals': true
    +-        }), ['js']);
    +-  registerLangHandler(sourceDecorator({
    +-          'keywords': COFFEE_KEYWORDS,
    +-          'hashComments': 3,  // ### style block comments
    +-          'cStyleComments': true,
    +-          'multilineStrings': true,
    +-          'tripleQuotedStrings': true,
    +-          'regexLiterals': true
    +-        }), ['coffee']);
    +-  registerLangHandler(createSimpleLexer([], [[PR_STRING, /^[\s\S]+/]]), ['regex']);
    +-
    +-  function applyDecorator(job) {
    +-    var sourceCodeHtml = job.sourceCodeHtml;
    +-    var opt_langExtension = job.langExtension;
    +-
    +-    // Prepopulate output in case processing fails with an exception.
    +-    job.prettyPrintedHtml = sourceCodeHtml;
    +-
    +-    try {
    +-      // Extract tags, and convert the source code to plain text.
    +-      var sourceAndExtractedTags = extractTags(sourceCodeHtml);
    +-      /** Plain text. @type {string} */
    +-      var source = sourceAndExtractedTags.source;
    +-      job.source = source;
    +-      job.basePos = 0;
    +-
    +-      /** Even entries are positions in source in ascending order.  Odd entries
    +-        * are tags that were extracted at that position.
    +-        * @type {Array.<number|string>}
    +-        */
    +-      job.extractedTags = sourceAndExtractedTags.tags;
    +-
    +-      // Apply the appropriate language handler
    +-      langHandlerForExtension(opt_langExtension, source)(job);
    +-      // Integrate the decorations and tags back into the source code to produce
    +-      // a decorated html string which is left in job.prettyPrintedHtml.
    +-      recombineTagsAndDecorations(job);
    +-    } catch (e) {
    +-      if ('console' in window) {
    +-        console['log'](e && e['stack'] ? e['stack'] : e);
    +-      }
    +-    }
    +-  }
    +-
    +-  /**
    +-   * @param sourceCodeHtml {string} The HTML to pretty print.
    +-   * @param opt_langExtension {string} The language name to use.
    +-   *     Typically, a filename extension like 'cpp' or 'java'.
    +-   * @param opt_numberLines {number|boolean} True to number lines,
    +-   *     or the 1-indexed number of the first line in sourceCodeHtml.
    +-   */
    +-  function prettyPrintOne(sourceCodeHtml, opt_langExtension, opt_numberLines) {
    +-    var job = {
    +-      sourceCodeHtml: sourceCodeHtml,
    +-      langExtension: opt_langExtension,
    +-      numberLines: opt_numberLines
    +-    };
    +-    applyDecorator(job);
    +-    return job.prettyPrintedHtml;
    +-  }
    +-
    +-  function prettyPrint(opt_whenDone) {
    +-    function byTagName(tn) { return document.getElementsByTagName(tn); }
    +-    // fetch a list of nodes to rewrite
    +-    var codeSegments = [byTagName('pre'), byTagName('code'), byTagName('xmp')];
    +-    var elements = [];
    +-    for (var i = 0; i < codeSegments.length; ++i) {
    +-      for (var j = 0, n = codeSegments[i].length; j < n; ++j) {
    +-        elements.push(codeSegments[i][j]);
    +-      }
    +-    }
    +-    codeSegments = null;
    +-
    +-    var clock = Date;
    +-    if (!clock['now']) {
    +-      clock = { 'now': function () { return (new Date).getTime(); } };
    +-    }
    +-
    +-    // The loop is broken into a series of continuations to make sure that we
    +-    // don't make the browser unresponsive when rewriting a large page.
    +-    var k = 0;
    +-    var prettyPrintingJob;
    +-
    +-    function doWork() {
    +-      var endTime = (window['PR_SHOULD_USE_CONTINUATION'] ?
    +-                     clock.now() + 250 /* ms */ :
    +-                     Infinity);
    +-      for (; k < elements.length && clock.now() < endTime; k++) {
    +-        var cs = elements[k];
    +-        if (cs.className && cs.className.indexOf('prettyprint') >= 0) {
    +-          // If the classes includes a language extensions, use it.
    +-          // Language extensions can be specified like
    +-          //     <pre class="prettyprint lang-cpp">
    +-          // the language extension "cpp" is used to find a language handler as
    +-          // passed to PR.registerLangHandler.
    +-          var langExtension = cs.className.match(/\blang-(\w+)\b/);
    +-          if (langExtension) { langExtension = langExtension[1]; }
    +-
    +-          // make sure this is not nested in an already prettified element
    +-          var nested = false;
    +-          for (var p = cs.parentNode; p; p = p.parentNode) {
    +-            if ((p.tagName === 'pre' || p.tagName === 'code' ||
    +-                 p.tagName === 'xmp') &&
    +-                p.className && p.className.indexOf('prettyprint') >= 0) {
    +-              nested = true;
    +-              break;
    +-            }
    +-          }
    +-          if (!nested) {
    +-            // fetch the content as a snippet of properly escaped HTML.
    +-            // Firefox adds newlines at the end.
    +-            var content = getInnerHtml(cs);
    +-            content = content.replace(/(?:\r\n?|\n)$/, '');
    +-
    +-            // Look for a class like linenums or linenums:<n> where <n> is the
    +-            // 1-indexed number of the first line.
    +-            var numberLines = cs.className.match(/\blinenums\b(?::(\d+))?/);
    +-
    +-            // do the pretty printing
    +-            prettyPrintingJob = {
    +-              sourceCodeHtml: content,
    +-              langExtension: langExtension,
    +-              sourceNode: cs,
    +-              numberLines: numberLines
    +-                  ? numberLines[1] && numberLines[1].length ? +numberLines[1] : true
    +-                  : false
    +-            };
    +-            applyDecorator(prettyPrintingJob);
    +-            replaceWithPrettyPrintedHtml();
    +-          }
    +-        }
    +-      }
    +-      if (k < elements.length) {
    +-        // finish up in a continuation
    +-        setTimeout(doWork, 250);
    +-      } else if (opt_whenDone) {
    +-        opt_whenDone();
    +-      }
    +-    }
    +-
    +-    function replaceWithPrettyPrintedHtml() {
    +-      var newContent = prettyPrintingJob.prettyPrintedHtml;
    +-      if (!newContent) { return; }
    +-      var cs = prettyPrintingJob.sourceNode;
    +-
    +-      // push the prettified html back into the tag.
    +-      if (!isRawContent(cs)) {
    +-        // just replace the old html with the new
    +-        cs.innerHTML = newContent;
    +-      } else {
    +-        // we need to change the tag to a <pre> since <xmp>s do not allow
    +-        // embedded tags such as the span tags used to attach styles to
    +-        // sections of source code.
    +-        var pre = document.createElement('PRE');
    +-        for (var i = 0; i < cs.attributes.length; ++i) {
    +-          var a = cs.attributes[i];
    +-          if (a.specified) {
    +-            var aname = a.name.toLowerCase();
    +-            if (aname === 'class') {
    +-              pre.className = a.value;  // For IE 6
    +-            } else {
    +-              pre.setAttribute(a.name, a.value);
    +-            }
    +-          }
    +-        }
    +-        pre.innerHTML = newContent;
    +-
    +-        // remove the old
    +-        cs.parentNode.replaceChild(pre, cs);
    +-        cs = pre;
    +-      }
    +-    }
    +-
    +-    doWork();
    +-  }
    +-
    +-  window['PR_normalizedHtml'] = normalizedHtml;
    +-  window['prettyPrintOne'] = prettyPrintOne;
    +-  window['prettyPrint'] = prettyPrint;
    +-  window['PR'] = {
    +-        'combinePrefixPatterns': combinePrefixPatterns,
    +-        'createSimpleLexer': createSimpleLexer,
    +-        'registerLangHandler': registerLangHandler,
    +-        'sourceDecorator': sourceDecorator,
    +-        'PR_ATTRIB_NAME': PR_ATTRIB_NAME,
    +-        'PR_ATTRIB_VALUE': PR_ATTRIB_VALUE,
    +-        'PR_COMMENT': PR_COMMENT,
    +-        'PR_DECLARATION': PR_DECLARATION,
    +-        'PR_KEYWORD': PR_KEYWORD,
    +-        'PR_LITERAL': PR_LITERAL,
    +-        'PR_NOCODE': PR_NOCODE,
    +-        'PR_PLAIN': PR_PLAIN,
    +-        'PR_PUNCTUATION': PR_PUNCTUATION,
    +-        'PR_SOURCE': PR_SOURCE,
    +-        'PR_STRING': PR_STRING,
    +-        'PR_TAG': PR_TAG,
    +-        'PR_TYPE': PR_TYPE
    +-      };
    +-})();
    +-
    +-//third_party/javascript/google_code_prettify/src/lang-apollo.js
    +-/**
    +- * @license Copyright (C) 2009 Onno Hommes.
    +- *
    +- * 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.
    +- */
    +-
    +-/**
    +- * @fileoverview
    +- * Registers a language handler for the AGC/AEA Assembly Language as described
    +- * at http://virtualagc.googlecode.com
    +- * <p>
    +- * This file could be used by goodle code to allow syntax highlight for
    +- * Virtual AGC SVN repository or if you don't want to commonize
    +- * the header for the agc/aea html assembly listing.
    +- *
    +- * @author ohommes@alumni.cmu.edu
    +- */
    +-
    +-PR['registerLangHandler'](
    +-    PR['createSimpleLexer'](
    +-        [
    +-         // A line comment that starts with ;
    +-         [PR['PR_COMMENT'],     /^#[^\r\n]*/, null, '#'],
    +-         // Whitespace
    +-         [PR['PR_PLAIN'],       /^[\t\n\r \xA0]+/, null, '\t\n\r \xA0'],
    +-         // A double quoted, possibly multi-line, string.
    +-         [PR['PR_STRING'],      /^\"(?:[^\"\\]|\\[\s\S])*(?:\"|$)/, null, '"']
    +-        ],
    +-        [
    +-         [PR['PR_KEYWORD'], /^(?:ADS|AD|AUG|BZF|BZMF|CAE|CAF|CA|CCS|COM|CS|DAS|DCA|DCOM|DCS|DDOUBL|DIM|DOUBLE|DTCB|DTCF|DV|DXCH|EDRUPT|EXTEND|INCR|INDEX|NDX|INHINT|LXCH|MASK|MSK|MP|MSU|NOOP|OVSK|QXCH|RAND|READ|RELINT|RESUME|RETURN|ROR|RXOR|SQUARE|SU|TCR|TCAA|OVSK|TCF|TC|TS|WAND|WOR|WRITE|XCH|XLQ|XXALQ|ZL|ZQ|ADD|ADZ|SUB|SUZ|MPY|MPR|MPZ|DVP|COM|ABS|CLA|CLZ|LDQ|STO|STQ|ALS|LLS|LRS|TRA|TSQ|TMI|TOV|AXT|TIX|DLY|INP|OUT)\s/,null],
    +-         [PR['PR_TYPE'], /^(?:-?GENADR|=MINUS|2BCADR|VN|BOF|MM|-?2CADR|-?[1-6]DNADR|ADRES|BBCON|[SE]?BANK\=?|BLOCK|BNKSUM|E?CADR|COUNT\*?|2?DEC\*?|-?DNCHAN|-?DNPTR|EQUALS|ERASE|MEMORY|2?OCT|REMADR|SETLOC|SUBRO|ORG|BSS|BES|SYN|EQU|DEFINE|END)\s/,null],
    +-         // A single quote possibly followed by a word that optionally ends with
    +-         // = ! or ?.
    +-         [PR['PR_LITERAL'],
    +-          /^\'(?:-*(?:\w|\\[\x21-\x7e])(?:[\w-]*|\\[\x21-\x7e])[=!?]?)?/],
    +-         // Any word including labels that optionally ends with = ! or ?.
    +-         [PR['PR_PLAIN'],
    +-          /^-*(?:[!-z_]|\\[\x21-\x7e])(?:[\w-]*|\\[\x21-\x7e])[=!?]?/i],
    +-         // A printable non-space non-special character
    +-         [PR['PR_PUNCTUATION'], /^[^\w\t\n\r \xA0()\"\\\';]+/]
    +-        ]),
    +-    ['apollo', 'agc', 'aea']);
    +-
    +-//third_party/javascript/google_code_prettify/src/lang-clj.js
    +-/**
    +- * @license Copyright (C) 2011 Google Inc.
    +- *
    +- * 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.
    +- */
    +-
    +-/**
    +- * @fileoverview
    +- * Registers a language handler for Clojure.
    +- *
    +- *
    +- * To use, include prettify.js and this file in your HTML page.
    +- * Then put your code in an HTML tag like
    +- *      <pre class="prettyprint lang-lisp">(my lisp code)</pre>
    +- * The lang-cl class identifies the language as common lisp.
    +- * This file supports the following language extensions:
    +- *     lang-clj - Clojure
    +- *
    +- *
    +- * I used lang-lisp.js as the basis for this adding the clojure specific
    +- * keywords and syntax.
    +- *
    +- * "Name"    = 'Clojure'
    +- * "Author"  = 'Rich Hickey'
    +- * "Version" = '1.2'
    +- * "About"   = 'Clojure is a lisp for the jvm with concurrency primitives and a richer set of types.'
    +- *
    +- *
    +- * I used <a href="http://clojure.org/Reference">Clojure.org Reference</a> as
    +- * the basis for the reserved word list.
    +- *
    +- *
    +- * @author jwall@google.com
    +- */
    +-
    +-PR['registerLangHandler'](
    +-    PR['createSimpleLexer'](
    +-        [
    +-         // clojure has more paren types than minimal lisp.
    +-         ['opn',             /^[\(\{\[]+/, null, '([{'],
    +-         ['clo',             /^[\)\}\]]+/, null, ')]}'],
    +-         // A line comment that starts with ;
    +-         [PR['PR_COMMENT'],     /^;[^\r\n]*/, null, ';'],
    +-         // Whitespace
    +-         [PR['PR_PLAIN'],       /^[\t\n\r \xA0]+/, null, '\t\n\r \xA0'],
    +-         // A double quoted, possibly multi-line, string.
    +-         [PR['PR_STRING'],      /^\"(?:[^\"\\]|\\[\s\S])*(?:\"|$)/, null, '"']
    +-        ],
    +-        [
    +-         // clojure has a much larger set of keywords
    +-         [PR['PR_KEYWORD'],     /^(?:def|if|do|let|quote|var|fn|loop|recur|throw|try|monitor-enter|monitor-exit|defmacro|defn|defn-|macroexpand|macroexpand-1|for|doseq|dosync|dotimes|and|or|when|not|assert|doto|proxy|defstruct|first|rest|cons|defprotocol|deftype|defrecord|reify|defmulti|defmethod|meta|with-meta|ns|in-ns|create-ns|import|intern|refer|alias|namespace|resolve|ref|deref|refset|new|set!|memfn|to-array|into-array|aset|gen-class|reduce|map|filter|find|nil?|empty?|hash-map|hash-set|vec|vector|seq|flatten|reverse|assoc|dissoc|list|list?|disj|get|union|difference|intersection|extend|extend-type|extend-protocol|prn)\b/, null],
    +-         [PR['PR_TYPE'], /^:[0-9a-zA-Z\-]+/]
    +-        ]),
    +-    ['clj']);
    +-
    +-//third_party/javascript/google_code_prettify/src/lang-css.js
    +-/**
    +- * @license Copyright (C) 2009 Google Inc.
    +- *
    +- * 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.
    +- */
    +-
    +-/**
    +- * @fileoverview
    +- * Registers a language handler for CSS.
    +- *
    +- *
    +- * To use, include prettify.js and this file in your HTML page.
    +- * Then put your code in an HTML tag like
    +- *      <pre class="prettyprint lang-css"></pre>
    +- *
    +- *
    +- * http://www.w3.org/TR/CSS21/grammar.html Section G2 defines the lexical
    +- * grammar.  This scheme does not recognize keywords containing escapes.
    +- *
    +- * @author mikesamuel@gmail.com
    +- */
    +-
    +-PR['registerLangHandler'](
    +-    PR['createSimpleLexer'](
    +-        [
    +-         // The space production <s>
    +-         [PR['PR_PLAIN'],       /^[ \t\r\n\f]+/, null, ' \t\r\n\f']
    +-        ],
    +-        [
    +-         // Quoted strings.  <string1> and <string2>
    +-         [PR['PR_STRING'],
    +-          /^\"(?:[^\n\r\f\\\"]|\\(?:\r\n?|\n|\f)|\\[\s\S])*\"/, null],
    +-         [PR['PR_STRING'],
    +-          /^\'(?:[^\n\r\f\\\']|\\(?:\r\n?|\n|\f)|\\[\s\S])*\'/, null],
    +-         ['lang-css-str', /^url\(([^\)\"\']*)\)/i],
    +-         [PR['PR_KEYWORD'],
    +-          /^(?:url|rgb|\!important|@import|@page|@media|@charset|inherit)(?=[^\-\w]|$)/i,
    +-          null],
    +-         // A property name -- an identifier followed by a colon.
    +-         ['lang-css-kw', /^(-?(?:[_a-z]|(?:\\[0-9a-f]+ ?))(?:[_a-z0-9\-]|\\(?:\\[0-9a-f]+ ?))*)\s*:/i],
    +-         // A C style block comment.  The <comment> production.
    +-         [PR['PR_COMMENT'], /^\/\*[^*]*\*+(?:[^\/*][^*]*\*+)*\//],
    +-         // Escaping text spans
    +-         [PR['PR_COMMENT'], /^(?:<!--|-->)/],
    +-         // A number possibly containing a suffix.
    +-         [PR['PR_LITERAL'], /^(?:\d+|\d*\.\d+)(?:%|[a-z]+)?/i],
    +-         // A hex color
    +-         [PR['PR_LITERAL'], /^#(?:[0-9a-f]{3}){1,2}/i],
    +-         // An identifier
    +-         [PR['PR_PLAIN'],
    +-          /^-?(?:[_a-z]|(?:\\[\da-f]+ ?))(?:[_a-z\d\-]|\\(?:\\[\da-f]+ ?))*/i],
    +-         // A run of punctuation
    +-         [PR['PR_PUNCTUATION'], /^[^\s\w\'\"]+/]
    +-        ]),
    +-    ['css']);
    +-PR['registerLangHandler'](
    +-    PR['createSimpleLexer']([],
    +-        [
    +-         [PR['PR_KEYWORD'],
    +-          /^-?(?:[_a-z]|(?:\\[\da-f]+ ?))(?:[_a-z\d\-]|\\(?:\\[\da-f]+ ?))*/i]
    +-        ]),
    +-    ['css-kw']);
    +-PR['registerLangHandler'](
    +-    PR['createSimpleLexer']([],
    +-        [
    +-         [PR['PR_STRING'], /^[^\)\"\']+/]
    +-        ]),
    +-    ['css-str']);
    +-
    +-//third_party/javascript/google_code_prettify/src/lang-go.js
    +-/**
    +- * @license Copyright (C) 2010 Google Inc.
    +- *
    +- * 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.
    +- */
    +-
    +-/**
    +- * @fileoverview
    +- * Registers a language handler for the Go language..
    +- * <p>
    +- * Based on the lexical grammar at 
    +- * http://golang.org/doc/go_spec.html#Lexical_elements
    +- * <p>
    +- * Go uses a minimal style for highlighting so the below does not distinguish
    +- * strings, keywords, literals, etc. by design.
    +- * From a discussion with the Go designers:
    +- * <pre>
    +- * On Thursday, July 22, 2010, Mike Samuel <...> wrote:
    +- * > On Thu, Jul 22, 2010, Rob 'Commander' Pike <...> wrote:
    +- * >> Personally, I would vote for the subdued style godoc presents at http://golang.org
    +- * >>
    +- * >> Not as fancy as some like, but a case can be made it's the official style.
    +- * >> If people want more colors, I wouldn't fight too hard, in the interest of
    +- * >> encouragement through familiarity, but even then I would ask to shy away
    +- * >> from technicolor starbursts.
    +- * >
    +- * > Like http://golang.org/pkg/go/scanner/ where comments are blue and all
    +- * > other content is black?  I can do that.
    +- * </pre>
    +- *
    +- * @author mikesamuel@gmail.com
    +- */
    +-
    +-PR['registerLangHandler'](
    +-    PR['createSimpleLexer'](
    +-        [
    +-         // Whitespace is made up of spaces, tabs and newline characters.
    +-         [PR['PR_PLAIN'],       /^[\t\n\r \xA0]+/, null, '\t\n\r \xA0'],
    +-         // Not escaped as a string.  See note on minimalism above.
    +-         [PR['PR_PLAIN'],       /^(?:\"(?:[^\"\\]|\\[\s\S])*(?:\"|$)|\'(?:[^\'\\]|\\[\s\S])+(?:\'|$))/, null, '"\'']
    +-        ],
    +-        [
    +-         // Block comments are delimited by /* and */.
    +-         // Single-line comments begin with // and extend to the end of a line.
    +-         [PR['PR_COMMENT'],     /^(?:\/\/[^\r\n]*|\/\*[\s\S]*?\*\/)/],
    +-         [PR['PR_PLAIN'],       /^(?:[^\/\"\']|\/(?![\/\*]))+/i]
    +-        ]),
    +-    ['go']);
    +-
    +-//third_party/javascript/google_code_prettify/src/lang-hs.js
    +-/**
    +- * @license Copyright (C) 2009 Google Inc.
    +- *
    +- * 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.
    +- */
    +-
    +-/**
    +- * @fileoverview
    +- * Registers a language handler for Haskell.
    +- *
    +- *
    +- * To use, include prettify.js and this file in your HTML page.
    +- * Then put your code in an HTML tag like
    +- *      <pre class="prettyprint lang-hs">(my lisp code)</pre>
    +- * The lang-cl class identifies the language as common lisp.
    +- * This file supports the following language extensions:
    +- *     lang-cl - Common Lisp
    +- *     lang-el - Emacs Lisp
    +- *     lang-lisp - Lisp
    +- *     lang-scm - Scheme
    +- *
    +- *
    +- * I used http://www.informatik.uni-freiburg.de/~thiemann/haskell/haskell98-report-html/syntax-iso.html
    +- * as the basis, but ignore the way the ncomment production nests since this
    +- * makes the lexical grammar irregular.  It might be possible to support
    +- * ncomments using the lookbehind filter.
    +- *
    +- *
    +- * @author mikesamuel@gmail.com
    +- */
    +-
    +-PR['registerLangHandler'](
    +-    PR['createSimpleLexer'](
    +-        [
    +-         // Whitespace
    +-         // whitechar    ->    newline | vertab | space | tab | uniWhite
    +-         // newline      ->    return linefeed | return | linefeed | formfeed
    +-         [PR['PR_PLAIN'],       /^[\t\n\x0B\x0C\r ]+/, null, '\t\n\x0B\x0C\r '],
    +-         // Single line double and single-quoted strings.
    +-         // char         ->    ' (graphic<' | \> | space | escape<\&>) '
    +-         // string       ->    " {graphic<" | \> | space | escape | gap}"
    +-         // escape       ->    \ ( charesc | ascii | decimal | o octal
    +-         //                        | x hexadecimal )
    +-         // charesc      ->    a | b | f | n | r | t | v | \ | " | ' | &
    +-         [PR['PR_STRING'],      /^\"(?:[^\"\\\n\x0C\r]|\\[\s\S])*(?:\"|$)/,
    +-          null, '"'],
    +-         [PR['PR_STRING'],      /^\'(?:[^\'\\\n\x0C\r]|\\[^&])\'?/,
    +-          null, "'"],
    +-         // decimal      ->    digit{digit}
    +-         // octal        ->    octit{octit}
    +-         // hexadecimal  ->    hexit{hexit}
    +-         // integer      ->    decimal
    +-         //               |    0o octal | 0O octal
    +-         //               |    0x hexadecimal | 0X hexadecimal
    +-         // float        ->    decimal . decimal [exponent]
    +-         //               |    decimal exponent
    +-         // exponent     ->    (e | E) [+ | -] decimal
    +-         [PR['PR_LITERAL'],
    +-          /^(?:0o[0-7]+|0x[\da-f]+|\d+(?:\.\d+)?(?:e[+\-]?\d+)?)/i,
    +-          null, '0123456789']
    +-        ],
    +-        [
    +-         // Haskell does not have a regular lexical grammar due to the nested
    +-         // ncomment.
    +-         // comment      ->    dashes [ any<symbol> {any}] newline
    +-         // ncomment     ->    opencom ANYseq {ncomment ANYseq}closecom
    +-         // dashes       ->    '--' {'-'}
    +-         // opencom      ->    '{-'
    +-         // closecom     ->    '-}'
    +-         [PR['PR_COMMENT'],     /^(?:(?:--+(?:[^\r\n\x0C]*)?)|(?:\{-(?:[^-]|-+[^-\}])*-\}))/],
    +-         // reservedid   ->    case | class | data | default | deriving | do
    +-         //               |    else | if | import | in | infix | infixl | infixr
    +-         //               |    instance | let | module | newtype | of | then
    +-         //               |    type | where | _
    +-         [PR['PR_KEYWORD'],     /^(?:case|class|data|default|deriving|do|else|if|import|in|infix|infixl|infixr|instance|let|module|newtype|of|then|type|where|_)(?=[^a-zA-Z0-9\']|$)/, null],
    +-         // qvarid       ->    [ modid . ] varid
    +-         // qconid       ->    [ modid . ] conid
    +-         // varid        ->    (small {small | large | digit | ' })<reservedid>
    +-         // conid        ->    large {small | large | digit | ' }
    +-         // modid        ->    conid
    +-         // small        ->    ascSmall | uniSmall | _
    +-         // ascSmall     ->    a | b | ... | z
    +-         // uniSmall     ->    any Unicode lowercase letter
    +-         // large        ->    ascLarge | uniLarge
    +-         // ascLarge     ->    A | B | ... | Z
    +-         // uniLarge     ->    any uppercase or titlecase Unicode letter
    +-         [PR['PR_PLAIN'],  /^(?:[A-Z][\w\']*\.)*[a-zA-Z][\w\']*/],
    +-         // matches the symbol production
    +-         [PR['PR_PUNCTUATION'], /^[^\t\n\x0B\x0C\r a-zA-Z0-9\'\"]+/]
    +-        ]),
    +-    ['hs']);
    +-
    +-//third_party/javascript/google_code_prettify/src/lang-lisp.js
    +-/**
    +- * @license Copyright (C) 2008 Google Inc.
    +- *
    +- * 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.
    +- */
    +-
    +-/**
    +- * @fileoverview
    +- * Registers a language handler for Common Lisp and related languages.
    +- *
    +- *
    +- * To use, include prettify.js and this file in your HTML page.
    +- * Then put your code in an HTML tag like
    +- *      <pre class="prettyprint lang-lisp">(my lisp code)</pre>
    +- * The lang-cl class identifies the language as common lisp.
    +- * This file supports the following language extensions:
    +- *     lang-cl - Common Lisp
    +- *     lang-el - Emacs Lisp
    +- *     lang-lisp - Lisp
    +- *     lang-scm - Scheme
    +- *
    +- *
    +- * I used http://www.devincook.com/goldparser/doc/meta-language/grammar-LISP.htm
    +- * as the basis, but added line comments that start with ; and changed the atom
    +- * production to disallow unquoted semicolons.
    +- *
    +- * "Name"    = 'LISP'
    +- * "Author"  = 'John McCarthy'
    +- * "Version" = 'Minimal'
    +- * "About"   = 'LISP is an abstract language that organizes ALL'
    +- *           | 'data around "lists".'
    +- *
    +- * "Start Symbol" = [s-Expression]
    +- *
    +- * {Atom Char}   = {Printable} - {Whitespace} - [()"\'']
    +- *
    +- * Atom = ( {Atom Char} | '\'{Printable} )+
    +- *
    +- * [s-Expression] ::= [Quote] Atom
    +- *                  | [Quote] '(' [Series] ')'
    +- *                  | [Quote] '(' [s-Expression] '.' [s-Expression] ')'
    +- *
    +- * [Series] ::= [s-Expression] [Series]
    +- *            |
    +- *
    +- * [Quote]  ::= ''      !Quote = do not evaluate
    +- *            |
    +- *
    +- *
    +- * I used <a href="http://gigamonkeys.com/book/">Practical Common Lisp</a> as
    +- * the basis for the reserved word list.
    +- *
    +- *
    +- * @author mikesamuel@gmail.com
    +- */
    +-
    +-PR['registerLangHandler'](
    +-    PR['createSimpleLexer'](
    +-        [
    +-         ['opn',             /^\(+/, null, '('],
    +-         ['clo',             /^\)+/, null, ')'],
    +-         // A line comment that starts with ;
    +-         [PR['PR_COMMENT'],     /^;[^\r\n]*/, null, ';'],
    +-         // Whitespace
    +-         [PR['PR_PLAIN'],       /^[\t\n\r \xA0]+/, null, '\t\n\r \xA0'],
    +-         // A double quoted, possibly multi-line, string.
    +-         [PR['PR_STRING'],      /^\"(?:[^\"\\]|\\[\s\S])*(?:\"|$)/, null, '"']
    +-        ],
    +-        [
    +-         [PR['PR_KEYWORD'],     /^(?:block|c[ad]+r|catch|con[ds]|def(?:ine|un)|do|eq|eql|equal|equalp|eval-when|flet|format|go|if|labels|lambda|let|load-time-value|locally|macrolet|multiple-value-call|nil|progn|progv|quote|require|return-from|setq|symbol-macrolet|t|tagbody|the|throw|unwind)\b/, null],
    +-         [PR['PR_LITERAL'],
    +-          /^[+\-]?(?:[0#]x[0-9a-f]+|\d+\/\d+|(?:\.\d+|\d+(?:\.\d*)?)(?:[ed][+\-]?\d+)?)/i],
    +-         // A single quote possibly followed by a word that optionally ends with
    +-         // = ! or ?.
    +-         [PR['PR_LITERAL'],
    +-          /^\'(?:-*(?:\w|\\[\x21-\x7e])(?:[\w-]*|\\[\x21-\x7e])[=!?]?)?/],
    +-         // A word that optionally ends with = ! or ?.
    +-         [PR['PR_PLAIN'],
    +-          /^-*(?:[a-z_]|\\[\x21-\x7e])(?:[\w-]*|\\[\x21-\x7e])[=!?]?/i],
    +-         // A printable non-space non-special character
    +-         [PR['PR_PUNCTUATION'], /^[^\w\t\n\r \xA0()\"\\\';]+/]
    +-        ]),
    +-    ['cl', 'el', 'lisp', 'scm']);
    +-
    +-//third_party/javascript/google_code_prettify/src/lang-lua.js
    +-/**
    +- * @license Copyright (C) 2008 Google Inc.
    +- *
    +- * 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.
    +- */
    +-
    +-/**
    +- * @fileoverview
    +- * Registers a language handler for Lua.
    +- *
    +- *
    +- * To use, include prettify.js and this file in your HTML page.
    +- * Then put your code in an HTML tag like
    +- *      <pre class="prettyprint lang-lua">(my Lua code)</pre>
    +- *
    +- *
    +- * I used http://www.lua.org/manual/5.1/manual.html#2.1
    +- * Because of the long-bracket concept used in strings and comments, Lua does
    +- * not have a regular lexical grammar, but luckily it fits within the space
    +- * of irregular grammars supported by javascript regular expressions.
    +- *
    +- * @author mikesamuel@gmail.com
    +- */
    +-
    +-PR['registerLangHandler'](
    +-    PR['createSimpleLexer'](
    +-        [
    +-         // Whitespace
    +-         [PR['PR_PLAIN'],       /^[\t\n\r \xA0]+/, null, '\t\n\r \xA0'],
    +-         // A double or single quoted, possibly multi-line, string.
    +-         [PR['PR_STRING'],      /^(?:\"(?:[^\"\\]|\\[\s\S])*(?:\"|$)|\'(?:[^\'\\]|\\[\s\S])*(?:\'|$))/, null, '"\'']
    +-        ],
    +-        [
    +-         // A comment is either a line comment that starts with two dashes, or
    +-         // two dashes preceding a long bracketed block.
    +-         [PR['PR_COMMENT'], /^--(?:\[(=*)\[[\s\S]*?(?:\]\1\]|$)|[^\r\n]*)/],
    +-         // A long bracketed block not preceded by -- is a string.
    +-         [PR['PR_STRING'],  /^\[(=*)\[[\s\S]*?(?:\]\1\]|$)/],
    +-         [PR['PR_KEYWORD'], /^(?:and|break|do|else|elseif|end|false|for|function|if|in|local|nil|not|or|repeat|return|then|true|until|while)\b/, null],
    +-         // A number is a hex integer literal, a decimal real literal, or in
    +-         // scientific notation.
    +-         [PR['PR_LITERAL'],
    +-          /^[+-]?(?:0x[\da-f]+|(?:(?:\.\d+|\d+(?:\.\d*)?)(?:e[+\-]?\d+)?))/i],
    +-         // An identifier
    +-         [PR['PR_PLAIN'], /^[a-z_]\w*/i],
    +-         // A run of punctuation
    +-         [PR['PR_PUNCTUATION'], /^[^\w\t\n\r \xA0][^\w\t\n\r \xA0\"\'\-\+=]*/]
    +-        ]),
    +-    ['lua']);
    +-
    +-//third_party/javascript/google_code_prettify/src/lang-ml.js
    +-/**
    +- * @license Copyright (C) 2008 Google Inc.
    +- *
    +- * 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.
    +- */
    +-
    +-/**
    +- * @fileoverview
    +- * Registers a language handler for OCaml, SML, F# and similar languages.
    +- *
    +- * Based on the lexical grammar at
    +- * http://research.microsoft.com/en-us/um/cambridge/projects/fsharp/manual/spec.html#_Toc270597388
    +- *
    +- * @author mikesamuel@gmail.com
    +- */
    +-
    +-PR['registerLangHandler'](
    +-    PR['createSimpleLexer'](
    +-        [
    +-         // Whitespace is made up of spaces, tabs and newline characters.
    +-         [PR['PR_PLAIN'],       /^[\t\n\r \xA0]+/, null, '\t\n\r \xA0'],
    +-         // #if ident/#else/#endif directives delimit conditional compilation
    +-         // sections
    +-         [PR['PR_COMMENT'],
    +-          /^#(?:if[\t\n\r \xA0]+(?:[a-z_$][\w\']*|``[^\r\n\t`]*(?:``|$))|else|endif|light)/i,
    +-          null, '#'],
    +-         // A double or single quoted, possibly multi-line, string.
    +-         // F# allows escaped newlines in strings.
    +-         [PR['PR_STRING'],      /^(?:\"(?:[^\"\\]|\\[\s\S])*(?:\"|$)|\'(?:[^\'\\]|\\[\s\S])(?:\'|$))/, null, '"\'']
    +-        ],
    +-        [
    +-         // Block comments are delimited by (* and *) and may be
    +-         // nested. Single-line comments begin with // and extend to
    +-         // the end of a line.
    +-         // TODO: (*...*) comments can be nested.  This does not handle that.
    +-         [PR['PR_COMMENT'],     /^(?:\/\/[^\r\n]*|\(\*[\s\S]*?\*\))/],
    +-         [PR['PR_KEYWORD'],     /^(?:abstract|and|as|assert|begin|class|default|delegate|do|done|downcast|downto|elif|else|end|exception|extern|false|finally|for|fun|function|if|in|inherit|inline|interface|internal|lazy|let|match|member|module|mutable|namespace|new|null|of|open|or|override|private|public|rec|return|static|struct|then|to|true|try|type|upcast|use|val|void|when|while|with|yield|asr|land|lor|lsl|lsr|lxor|mod|sig|atomic|break|checked|component|const|constraint|constructor|continue|eager|event|external|fixed|functor|global|include|method|mixin|object|parallel|process|protected|pure|sealed|trait|virtual|volatile)\b/],
    +-         // A number is a hex integer literal, a decimal real literal, or in
    +-         // scientific notation.
    +-         [PR['PR_LITERAL'],
    +-          /^[+\-]?(?:0x[\da-f]+|(?:(?:\.\d+|\d+(?:\.\d*)?)(?:e[+\-]?\d+)?))/i],
    +-         [PR['PR_PLAIN'],       /^(?:[a-z_][\w']*[!?#]?|``[^\r\n\t`]*(?:``|$))/i],
    +-         // A printable non-space non-special character
    +-         [PR['PR_PUNCTUATION'], /^[^\t\n\r \xA0\"\'\w]+/]
    +-        ]),
    +-    ['fs', 'ml']);
    +-
    +-//third_party/javascript/google_code_prettify/src/lang-proto.js
    +-/**
    +- * @license Copyright (C) 2006 Google Inc.
    +- *
    +- * 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.
    +- */
    +-
    +-/**
    +- * @fileoverview
    +- * Registers a language handler for Protocol Buffers as described at
    +- * http://code.google.com/p/protobuf/.
    +- *
    +- * Based on the lexical grammar at
    +- * http://research.microsoft.com/fsharp/manual/spec2.aspx#_Toc202383715
    +- *
    +- * @author mikesamuel@gmail.com
    +- */
    +-
    +-PR['registerLangHandler'](PR['sourceDecorator']({
    +-        keywords: (
    +-            'bool bytes default double enum extend extensions false fixed32 '
    +-            + 'fixed64 float group import int32 int64 max message option '
    +-            + 'optional package repeated required returns rpc service '
    +-            + 'sfixed32 sfixed64 sint32 sint64 string syntax to true uint32 '
    +-            + 'uint64'),
    +-        cStyleComments: true
    +-      }), ['proto']);
    +-
    +-//third_party/javascript/google_code_prettify/src/lang-scala.js
    +-/**
    +- * @license Copyright (C) 2010 Google Inc.
    +- *
    +- * 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.
    +- */
    +-
    +-/**
    +- * @fileoverview
    +- * Registers a language handler for Scala.
    +- *
    +- * Derived from http://lampsvn.epfl.ch/svn-repos/scala/scala-documentation/trunk/src/reference/SyntaxSummary.tex
    +- *
    +- * @author mikesamuel@gmail.com
    +- */
    +-
    +-PR['registerLangHandler'](
    +-    PR['createSimpleLexer'](
    +-        [
    +-         // Whitespace
    +-         [PR['PR_PLAIN'],       /^[\t\n\r \xA0]+/, null, '\t\n\r \xA0'],
    +-         // A double or single quoted string
    +-          // or a triple double-quoted multi-line string.
    +-         [PR['PR_STRING'],
    +-          /^(?:"(?:(?:""(?:""?(?!")|[^\\"]|\\.)*"{0,3})|(?:[^"\r\n\\]|\\.)*"?))/,
    +-          null, '"'],
    +-         [PR['PR_LITERAL'],     /^`(?:[^\r\n\\`]|\\.)*`?/, null, '`'],
    +-         [PR['PR_PUNCTUATION'], /^[!#%&()*+,\-:;<=>?@\[\\\]^{|}~]+/, null,
    +-          '!#%&()*+,-:;<=>?@[\\]^{|}~']
    +-        ],
    +-        [
    +-         // A symbol literal is a single quote followed by an identifier with no
    +-         // single quote following
    +-         // A character literal has single quotes on either side
    +-         [PR['PR_STRING'],      /^'(?:[^\r\n\\']|\\(?:'|[^\r\n']+))'/],
    +-         [PR['PR_LITERAL'],     /^'[a-zA-Z_$][\w$]*(?!['$\w])/],
    +-         [PR['PR_KEYWORD'],     /^(?:abstract|case|catch|class|def|do|else|extends|final|finally|for|forSome|if|implicit|import|lazy|match|new|object|override|package|private|protected|requires|return|sealed|super|throw|trait|try|type|val|var|while|with|yield)\b/],
    +-         [PR['PR_LITERAL'],     /^(?:true|false|null|this)\b/],
    +-         [PR['PR_LITERAL'],     /^(?:(?:0(?:[0-7]+|X[0-9A-F]+))L?|(?:(?:0|[1-9][0-9]*)(?:(?:\.[0-9]+)?(?:E[+\-]?[0-9]+)?F?|L?))|\\.[0-9]+(?:E[+\-]?[0-9]+)?F?)/i],
    +-         // Treat upper camel case identifiers as types.
    +-         [PR['PR_TYPE'],        /^[$_]*[A-Z][_$A-Z0-9]*[a-z][\w$]*/],
    +-         [PR['PR_PLAIN'],       /^[$a-zA-Z_][\w$]*/],
    +-         [PR['PR_COMMENT'],     /^\/(?:\/.*|\*(?:\/|\**[^*/])*(?:\*+\/?)?)/],
    +-         [PR['PR_PUNCTUATION'], /^(?:\.+|\/)/]
    +-        ]),
    +-    ['scala']);
    +-
    +-//third_party/javascript/google_code_prettify/src/lang-sql.js
    +-/**
    +- * @license Copyright (C) 2008 Google Inc.
    +- *
    +- * 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.
    +- */
    +-
    +-
    +-/**
    +- * @fileoverview
    +- * Registers a language handler for SQL.
    +- *
    +- *
    +- * To use, include prettify.js and this file in your HTML page.
    +- * Then put your code in an HTML tag like
    +- *      <pre class="prettyprint lang-sql">(my SQL code)</pre>
    +- *
    +- *
    +- * http://savage.net.au/SQL/sql-99.bnf.html is the basis for the grammar, and
    +- * http://msdn.microsoft.com/en-us/library/aa238507(SQL.80).aspx as the basis
    +- * for the keyword list.
    +- *
    +- * @author mikesamuel@gmail.com
    +- */
    +-
    +-PR['registerLangHandler'](
    +-    PR['createSimpleLexer'](
    +-        [
    +-         // Whitespace
    +-         [PR['PR_PLAIN'],       /^[\t\n\r \xA0]+/, null, '\t\n\r \xA0'],
    +-         // A double or single quoted, possibly multi-line, string.
    +-         [PR['PR_STRING'],      /^(?:"(?:[^\"\\]|\\.)*"|'(?:[^\'\\]|\\.)*')/, null,
    +-          '"\'']
    +-        ],
    +-        [
    +-         // A comment is either a line comment that starts with two dashes, or
    +-         // two dashes preceding a long bracketed block.
    +-         [PR['PR_COMMENT'], /^(?:--[^\r\n]*|\/\*[\s\S]*?(?:\*\/|$))/],
    +-         [PR['PR_KEYWORD'], /^(?:ADD|ALL|ALTER|AND|ANY|AS|ASC|AUTHORIZATION|BACKUP|BEGIN|BETWEEN|BREAK|BROWSE|BULK|BY|CASCADE|CASE|CHECK|CHECKPOINT|CLOSE|CLUSTERED|COALESCE|COLLATE|COLUMN|COMMIT|COMPUTE|CONSTRAINT|CONTAINS|CONTAINSTABLE|CONTINUE|CONVERT|CREATE|CROSS|CURRENT|CURRENT_DATE|CURRENT_TIME|CURRENT_TIMESTAMP|CURRENT_USER|CURSOR|DATABASE|DBCC|DEALLOCATE|DECLARE|DEFAULT|DELETE|DENY|DESC|DISK|DISTINCT|DISTRIBUTED|DOUBLE|DROP|DUMMY|DUMP|ELSE|END|ERRLVL|ESCAPE|EXCEPT|EXEC|EXECUTE|EXISTS|EXIT|FETCH|FILE|FILLFACTOR|FOR|FOREIGN|FREETEXT|FREETEXTTABLE|FROM|FULL|FUNCTION|GOTO|GRANT|GROUP|HAVING|HOLDLOCK|IDENTITY|IDENTITYCOL|IDENTITY_INSERT|IF|IN|INDEX|INNER|INSERT|INTERSECT|INTO|IS|JOIN|KEY|KILL|LEFT|LIKE|LINENO|LOAD|NATIONAL|NOCHECK|NONCLUSTERED|NOT|NULL|NULLIF|OF|OFF|OFFSETS|ON|OPEN|OPENDATASOURCE|OPENQUERY|OPENROWSET|OPENXML|OPTION|OR|ORDER|OUTER|OVER|PERCENT|PLAN|PRECISION|PRIMARY|PRINT|PROC|PROCEDURE|PUBLIC|RAISERROR|READ|READTEXT|RECONFIGURE|REFERENCES|REPLICATION|RESTORE|RESTRICT|RETURN|REVOKE|RIGHT|ROLLBACK|ROWCOUNT|ROWGUIDCOL|RULE|SAVE|SCHEMA|SELECT|SESSION_USER|SET|SETUSER|SHUTDOWN|SOME|STATISTICS|SYSTEM_USER|TABLE|TEXTSIZE|THEN|TO|TOP|TRAN|TRANSACTION|TRIGGER|TRUNCATE|TSEQUAL|UNION|UNIQUE|UPDATE|UPDATETEXT|USE|USER|VALUES|VARYING|VIEW|WAITFOR|WHEN|WHERE|WHILE|WITH|WRITETEXT)(?=[^\w-]|$)/i, null],
    +-         // A number is a hex integer literal, a decimal real literal, or in
    +-         // scientific notation.
    +-         [PR['PR_LITERAL'],
    +-          /^[+-]?(?:0x[\da-f]+|(?:(?:\.\d+|\d+(?:\.\d*)?)(?:e[+\-]?\d+)?))/i],
    +-         // An identifier
    +-         [PR['PR_PLAIN'], /^[a-z_][\w-]*/i],
    +-         // A run of punctuation
    +-         [PR['PR_PUNCTUATION'], /^[^\w\t\n\r \xA0\"\'][^\w\t\n\r \xA0+\-\"\']*/]
    +-        ]),
    +-    ['sql']);
    +-
    +-//third_party/javascript/google_code_prettify/src/lang-vb.js
    +-/**
    +- * @license Copyright (C) 2009 Google Inc.
    +- *
    +- * 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.
    +- */
    +-
    +-
    +-
    +-/**
    +- * @fileoverview
    +- * Registers a language handler for various flavors of basic.
    +- *
    +- *
    +- * To use, include prettify.js and this file in your HTML page.
    +- * Then put your code in an HTML tag like
    +- *      <pre class="prettyprint lang-vb"></pre>
    +- *
    +- *
    +- * http://msdn.microsoft.com/en-us/library/aa711638(VS.71).aspx defines the
    +- * visual basic grammar lexical grammar.
    +- *
    +- * @author mikesamuel@gmail.com
    +- */
    +-
    +-PR['registerLangHandler'](
    +-    PR['createSimpleLexer'](
    +-        [
    +-         // Whitespace
    +-         [PR['PR_PLAIN'],       /^[\t\n\r \xA0\u2028\u2029]+/, null, '\t\n\r \xA0\u2028\u2029'],
    +-         // A double quoted string with quotes escaped by doubling them.
    +-         // A single character can be suffixed with C.
    +-         [PR['PR_STRING'],      /^(?:[\"\u201C\u201D](?:[^\"\u201C\u201D]|[\"\u201C\u201D]{2})(?:[\"\u201C\u201D]c|$)|[\"\u201C\u201D](?:[^\"\u201C\u201D]|[\"\u201C\u201D]{2})*(?:[\"\u201C\u201D]|$))/i, null,
    +-          '"\u201C\u201D'],
    +-         // A comment starts with a single quote and runs until the end of the
    +-         // line.
    +-         [PR['PR_COMMENT'],     /^[\'\u2018\u2019][^\r\n\u2028\u2029]*/, null, '\'\u2018\u2019']
    +-        ],
    +-        [
    +-         [PR['PR_KEYWORD'], /^(?:AddHandler|AddressOf|Alias|And|AndAlso|Ansi|As|Assembly|Auto|Boolean|ByRef|Byte|ByVal|Call|Case|Catch|CBool|CByte|CChar|CDate|CDbl|CDec|Char|CInt|Class|CLng|CObj|Const|CShort|CSng|CStr|CType|Date|Decimal|Declare|Default|Delegate|Dim|DirectCast|Do|Double|Each|Else|ElseIf|End|EndIf|Enum|Erase|Error|Event|Exit|Finally|For|Friend|Function|Get|GetType|GoSub|GoTo|Handles|If|Implements|Imports|In|Inherits|Integer|Interface|Is|Let|Lib|Like|Long|Loop|Me|Mod|Module|MustInherit|MustOverride|MyBase|MyClass|Namespace|New|Next|Not|NotInheritable|NotOverridable|Object|On|Option|Optional|Or|OrElse|Overloads|Overridable|Overrides|ParamArray|Preserve|Private|Property|Protected|Public|RaiseEvent|ReadOnly|ReDim|RemoveHandler|Resume|Return|Select|Set|Shadows|Shared|Short|Single|Static|Step|Stop|String|Structure|Sub|SyncLock|Then|Throw|To|Try|TypeOf|Unicode|Until|Variant|Wend|When|While|With|WithEvents|WriteOnly|Xor|EndIf|GoSub|Let|Variant|Wend)\b/i, null],
    +-         // A second comment form
    +-         [PR['PR_COMMENT'], /^REM[^\r\n\u2028\u2029]*/i],
    +-         // A boolean, numeric, or date literal.
    +-         [PR['PR_LITERAL'],
    +-          /^(?:True\b|False\b|Nothing\b|\d+(?:E[+\-]?\d+[FRD]?|[FRDSIL])?|(?:&H[0-9A-F]+|&O[0-7]+)[SIL]?|\d*\.\d+(?:E[+\-]?\d+)?[FRD]?|#\s+(?:\d+[\-\/]\d+[\-\/]\d+(?:\s+\d+:\d+(?::\d+)?(\s*(?:AM|PM))?)?|\d+:\d+(?::\d+)?(\s*(?:AM|PM))?)\s+#)/i],
    +-         // An identifier?
    +-         [PR['PR_PLAIN'], /^(?:(?:[a-z]|_\w)\w*|\[(?:[a-z]|_\w)\w*\])/i],
    +-         // A run of punctuation
    +-         [PR['PR_PUNCTUATION'],
    +-          /^[^\w\t\n\r \"\'\[\]\xA0\u2018\u2019\u201C\u201D\u2028\u2029]+/],
    +-         // Square brackets
    +-         [PR['PR_PUNCTUATION'], /^(?:\[|\])/]
    +-        ]),
    +-    ['vb', 'vbs']);
    +-
    +-//third_party/javascript/google_code_prettify/src/lang-vhdl.js
    +-/**
    +- * @fileoverview
    +- * Registers a language handler for VHDL '93.
    +- *
    +- * Based on the lexical grammar and keywords at
    +- * http://www.iis.ee.ethz.ch/~zimmi/download/vhdl93_syntax.html
    +- *
    +- * @author benoit@ryder.fr
    +- */
    +-
    +-PR['registerLangHandler'](
    +-    PR['createSimpleLexer'](
    +-        [
    +-         // Whitespace
    +-         [PR['PR_PLAIN'], /^[\t\n\r \xA0]+/, null, '\t\n\r \xA0']
    +-        ],
    +-        [
    +-         // String, character or bit string
    +-         [PR['PR_STRING'], /^(?:[BOX]?"(?:[^\"]|"")*"|'.')/i],
    +-         // Comment, from two dashes until end of line.
    +-         [PR['PR_COMMENT'], /^--[^\r\n]*/],
    +-         [PR['PR_KEYWORD'], /^(?:abs|access|after|alias|all|and|architecture|array|assert|attribute|begin|block|body|buffer|bus|case|component|configuration|constant|disconnect|downto|else|elsif|end|entity|exit|file|for|function|generate|generic|group|guarded|if|impure|in|inertial|inout|is|label|library|linkage|literal|loop|map|mod|nand|new|next|nor|not|null|of|on|open|or|others|out|package|port|postponed|procedure|process|pure|range|record|register|reject|rem|report|return|rol|ror|select|severity|shared|signal|sla|sll|sra|srl|subtype|then|to|transport|type|unaffected|units|until|use|variable|wait|when|while|with|xnor|xor)(?=[^\w-]|$)/i, null],
    +-         // Type, predefined or standard
    +-         [PR['PR_TYPE'], /^(?:bit|bit_vector|character|boolean|integer|real|time|string|severity_level|positive|natural|signed|unsigned|line|text|std_u?logic(?:_vector)?)(?=[^\w-]|$)/i, null],
    +-         // Predefined attributes
    +-         [PR['PR_TYPE'], /^\'(?:ACTIVE|ASCENDING|BASE|DELAYED|DRIVING|DRIVING_VALUE|EVENT|HIGH|IMAGE|INSTANCE_NAME|LAST_ACTIVE|LAST_EVENT|LAST_VALUE|LEFT|LEFTOF|LENGTH|LOW|PATH_NAME|POS|PRED|QUIET|RANGE|REVERSE_RANGE|RIGHT|RIGHTOF|SIMPLE_NAME|STABLE|SUCC|TRANSACTION|VAL|VALUE)(?=[^\w-]|$)/i, null],
    +-         // Number, decimal or based literal
    +-         [PR['PR_LITERAL'], /^\d+(?:_\d+)*(?:#[\w\\.]+#(?:[+\-]?\d+(?:_\d+)*)?|(?:\.\d+(?:_\d+)*)?(?:E[+\-]?\d+(?:_\d+)*)?)/i],
    +-         // Identifier, basic or extended
    +-         [PR['PR_PLAIN'], /^(?:[a-z]\w*|\\[^\\]*\\)/i],
    +-         // Punctuation
    +-         [PR['PR_PUNCTUATION'], /^[^\w\t\n\r \xA0\"\'][^\w\t\n\r \xA0\-\"\']*/]
    +-        ]),
    +-    ['vhdl', 'vhd']);
    +-
    +-//third_party/javascript/google_code_prettify/src/lang-wiki.js
    +-/**
    +- * @license Copyright (C) 2009 Google Inc.
    +- *
    +- * 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.
    +- */
    +-
    +-/**
    +- * @fileoverview
    +- * Registers a language handler for Wiki pages.
    +- *
    +- * Based on WikiSyntax at http://code.google.com/p/support/wiki/WikiSyntax
    +- *
    +- * @author mikesamuel@gmail.com
    +- */
    +-
    +-PR['registerLangHandler'](
    +-    PR['createSimpleLexer'](
    +-        [
    +-         // Whitespace
    +-         [PR['PR_PLAIN'],       /^[\t \xA0a-gi-z0-9]+/, null,
    +-          '\t \xA0abcdefgijklmnopqrstuvwxyz0123456789'],
    +-         // Wiki formatting
    +-         [PR['PR_PUNCTUATION'], /^[=*~\^\[\]]+/, null, '=*~^[]']
    +-        ],
    +-        [
    +-         // Meta-info like #summary, #labels, etc.
    +-         ['lang-wiki.meta',  /(?:^^|\r\n?|\n)(#[a-z]+)\b/],
    +-         // A WikiWord
    +-         [PR['PR_LITERAL'],     /^(?:[A-Z][a-z][a-z0-9]+[A-Z][a-z][a-zA-Z0-9]+)\b/
    +-          ],
    +-         // A preformatted block in an unknown language
    +-         ['lang-',           /^\{\{\{([\s\S]+?)\}\}\}/],
    +-         // A block of source code in an unknown language
    +-         ['lang-',           /^`([^\r\n`]+)`/],
    +-         // An inline URL.
    +-         [PR['PR_STRING'],
    +-          /^https?:\/\/[^\/?#\s]*(?:\/[^?#\s]*)?(?:\?[^#\s]*)?(?:#\S*)?/i],
    +-         [PR['PR_PLAIN'],       /^(?:\r\n|[\s\S])[^#=*~^A-Zh\{`\[\r\n]*/]
    +-        ]),
    +-    ['wiki']);
    +-
    +-PR['registerLangHandler'](
    +-    PR['createSimpleLexer']([[PR['PR_KEYWORD'], /^#[a-z]+/i, null, '#']], []),
    +-    ['wiki.meta']);
    +-
    +-//third_party/javascript/google_code_prettify/src/lang-yaml.js
    +-/** Contributed by ribrdb @ code.google.com
    +- */
    +-
    +-/**
    +- * @fileoverview
    +- * Registers a language handler for YAML.
    +- *
    +- * @author ribrdb
    +- */
    +-
    +-PR['registerLangHandler'](
    +-  PR['createSimpleLexer'](
    +-    [
    +-      [PR['PR_PUNCTUATION'], /^[:|>?]+/, null, ':|>?'],
    +-      [PR['PR_DECLARATION'],  /^%(?:YAML|TAG)[^#\r\n]+/, null, '%'],
    +-      [PR['PR_TYPE'], /^[&]\S+/, null, '&'],
    +-      [PR['PR_TYPE'], /^!\S*/, null, '!'],
    +-      [PR['PR_STRING'], /^"(?:[^\\"]|\\.)*(?:"|$)/, null, '"'],
    +-      [PR['PR_STRING'], /^'(?:[^']|'')*(?:'|$)/, null, "'"],
    +-      [PR['PR_COMMENT'], /^#[^\r\n]*/, null, '#'],
    +-      [PR['PR_PLAIN'], /^\s+/, null, ' \t\r\n']
    +-    ],
    +-    [
    +-      [PR['PR_DECLARATION'], /^(?:---|\.\.\.)(?:[\r\n]|$)/],
    +-      [PR['PR_PUNCTUATION'], /^-/],
    +-      [PR['PR_KEYWORD'], /^\w+:[ \r\n]/],
    +-      [PR['PR_PLAIN'], /^\w+/]
    +-    ]), ['yaml', 'yml']);
    +-
    +-//third_party/javascript/jquery/v1_7_2/jquery-1.7.2.min.js
    +-/**
    +- * @license jQuery JavaScript Library v1.7.2
    +- * http://jquery.com/
    +- *
    +- * Copyright 2011, John Resig
    +- * Dual licensed under the MIT or GPL Version 2 licenses.
    +- * http://jquery.org/license
    +- *
    +- * Includes Sizzle.js
    +- * http://sizzlejs.com/
    +- * Copyright 2011, The Dojo Foundation
    +- * Released under the MIT, BSD, and GPL Licenses.
    +- *
    +- * Date: Wed Mar 21 12:46:34 2012 -0700
    +- */
    +-(function(a,b){function cy(a){return f.isWindow(a)?a:a.nodeType===9?a.defaultView||a.parentWindow:!1}function cu(a){if(!cj[a]){var b=c.body,d=f("<"+a+">").appendTo(b),e=d.css("display");d.remove();if(e==="none"||e===""){ck||(ck=c.createElement("iframe"),ck.frameBorder=ck.width=ck.height=0),b.appendChild(ck);if(!cl||!ck.createElement)cl=(ck.contentWindow||ck.contentDocument).document,cl.write((f.support.boxModel?"<!doctype html>":"")+"<html><body>"),cl.close();d=cl.createElement(a),cl.body.appendChild(d),e=f.css(d,"display"),b.removeChild(ck)}cj[a]=e}return cj[a]}function ct(a,b){var c={};f.each(cp.concat.apply([],cp.slice(0,b)),function(){c[this]=a});return c}function cs(){cq=b}function cr(){setTimeout(cs,0);return cq=f.now()}function ci(){try{return new a.ActiveXObject("Microsoft.XMLHTTP")}catch(b){}}function ch(){try{return new a.XMLHttpRequest}catch(b){}}function cb(a,c){a.dataFilter&&(c=a.dataFilter(c,a.dataType));var d=a.dataTypes,e={},g,h,i=d.length,j,k=d[0],l,m,n,o,p;for(g=1;g<i;g++){if(g===1)for(h in a.converters)typeof h=="string"&&(e[h.toLowerCase()]=a.converters[h]);l=k,k=d[g];if(k==="*")k=l;else if(l!=="*"&&l!==k){m=l+" "+k,n=e[m]||e["* "+k];if(!n){p=b;for(o in e){j=o.split(" ");if(j[0]===l||j[0]==="*"){p=e[j[1]+" "+k];if(p){o=e[o],o===!0?n=p:p===!0&&(n=o);break}}}}!n&&!p&&f.error("No conversion from "+m.replace(" "," to ")),n!==!0&&(c=n?n(c):p(o(c)))}}return c}function ca(a,c,d){var e=a.contents,f=a.dataTypes,g=a.responseFields,h,i,j,k;for(i in g)i in d&&(c[g[i]]=d[i]);while(f[0]==="*")f.shift(),h===b&&(h=a.mimeType||c.getResponseHeader("content-type"));if(h)for(i in e)if(e[i]&&e[i].test(h)){f.unshift(i);break}if(f[0]in d)j=f[0];else{for(i in d){if(!f[0]||a.converters[i+" "+f[0]]){j=i;break}k||(k=i)}j=j||k}if(j){j!==f[0]&&f.unshift(j);return d[j]}}function b_(a,b,c,d){if(f.isArray(b))f.each(b,function(b,e){c||bD.test(a)?d(a,e):b_(a+"["+(typeof e=="object"?b:"")+"]",e,c,d)});else if(!c&&f.type(b)==="object")for(var e in b)b_(a+"["+e+"]",b[e],c,d);else d(a,b)}function b$(a,c){var d,e,g=f.ajaxSettings.flatOptions||{};for(d in c)c[d]!==b&&((g[d]?a:e||(e={}))[d]=c[d]);e&&f.extend(!0,a,e)}function bZ(a,c,d,e,f,g){f=f||c.dataTypes[0],g=g||{},g[f]=!0;var h=a[f],i=0,j=h?h.length:0,k=a===bS,l;for(;i<j&&(k||!l);i++)l=h[i](c,d,e),typeof l=="string"&&(!k||g[l]?l=b:(c.dataTypes.unshift(l),l=bZ(a,c,d,e,l,g)));(k||!l)&&!g["*"]&&(l=bZ(a,c,d,e,"*",g));return l}function bY(a){return function(b,c){typeof b!="string"&&(c=b,b="*");if(f.isFunction(c)){var d=b.toLowerCase().split(bO),e=0,g=d.length,h,i,j;for(;e<g;e++)h=d[e],j=/^\+/.test(h),j&&(h=h.substr(1)||"*"),i=a[h]=a[h]||[],i[j?"unshift":"push"](c)}}}function bB(a,b,c){var d=b==="width"?a.offsetWidth:a.offsetHeight,e=b==="width"?1:0,g=4;if(d>0){if(c!=="border")for(;e<g;e+=2)c||(d-=parseFloat(f.css(a,"padding"+bx[e]))||0),c==="margin"?d+=parseFloat(f.css(a,c+bx[e]))||0:d-=parseFloat(f.css(a,"border"+bx[e]+"Width"))||0;return d+"px"}d=by(a,b);if(d<0||d==null)d=a.style[b];if(bt.test(d))return d;d=parseFloat(d)||0;if(c)for(;e<g;e+=2)d+=parseFloat(f.css(a,"padding"+bx[e]))||0,c!=="padding"&&(d+=parseFloat(f.css(a,"border"+bx[e]+"Width"))||0),c==="margin"&&(d+=parseFloat(f.css(a,c+bx[e]))||0);return d+"px"}function bo(a){var b=c.createElement("div");bh.appendChild(b),b.innerHTML=a.outerHTML;return b.firstChild}function bn(a){var b=(a.nodeName||"").toLowerCase();b==="input"?bm(a):b!=="script"&&typeof a.getElementsByTagName!="undefined"&&f.grep(a.getElementsByTagName("input"),bm)}function bm(a){if(a.type==="checkbox"||a.type==="radio")a.defaultChecked=a.checked}function bl(a){return typeof a.getElementsByTagName!="undefined"?a.getElementsByTagName("*"):typeof a.querySelectorAll!="undefined"?a.querySelectorAll("*"):[]}function bk(a,b){var c;b.nodeType===1&&(b.clearAttributes&&b.clearAttributes(),b.mergeAttributes&&b.mergeAttributes(a),c=b.nodeName.toLowerCase(),c==="object"?b.outerHTML=a.outerHTML:c!=="input"||a.type!=="checkbox"&&a.type!=="radio"?c==="option"?b.selected=a.defaultSelected:c==="input"||c==="textarea"?b.defaultValue=a.defaultValue:c==="script"&&b.text!==a.text&&(b.text=a.text):(a.checked&&(b.defaultChecked=b.checked=a.checked),b.value!==a.value&&(b.value=a.value)),b.removeAttribute(f.expando),b.removeAttribute("_submit_attached"),b.removeAttribute("_change_attached"))}function bj(a,b){if(b.nodeType===1&&!!f.hasData(a)){var c,d,e,g=f._data(a),h=f._data(b,g),i=g.events;if(i){delete h.handle,h.events={};for(c in i)for(d=0,e=i[c].length;d<e;d++)f.event.add(b,c,i[c][d])}h.data&&(h.data=f.extend({},h.data))}}function bi(a,b){return f.nodeName(a,"table")?a.getElementsByTagName("tbody")[0]||a.appendChild(a.ownerDocument.createElement("tbody")):a}function U(a){var b=V.split("|"),c=a.createDocumentFragment();if(c.createElement)while(b.length)c.createElement(b.pop());return c}function T(a,b,c){b=b||0;if(f.isFunction(b))return f.grep(a,function(a,d){var e=!!b.call(a,d,a);return e===c});if(b.nodeType)return f.grep(a,function(a,d){return a===b===c});if(typeof b=="string"){var d=f.grep(a,function(a){return a.nodeType===1});if(O.test(b))return f.filter(b,d,!c);b=f.filter(b,d)}return f.grep(a,function(a,d){return f.inArray(a,b)>=0===c})}function S(a){return!a||!a.parentNode||a.parentNode.nodeType===11}function K(){return!0}function J(){return!1}function n(a,b,c){var d=b+"defer",e=b+"queue",g=b+"mark",h=f._data(a,d);h&&(c==="queue"||!f._data(a,e))&&(c==="mark"||!f._data(a,g))&&setTimeout(function(){!f._data(a,e)&&!f._data(a,g)&&(f.removeData(a,d,!0),h.fire())},0)}function m(a){for(var b in a){if(b==="data"&&f.isEmptyObject(a[b]))continue;if(b!=="toJSON")return!1}return!0}function l(a,c,d){if(d===b&&a.nodeType===1){var e="data-"+c.replace(k,"-$1").toLowerCase();d=a.getAttribute(e);if(typeof d=="string"){try{d=d==="true"?!0:d==="false"?!1:d==="null"?null:f.isNumeric(d)?+d:j.test(d)?f.parseJSON(d):d}catch(g){}f.data(a,c,d)}else d=b}return d}function h(a){var b=g[a]={},c,d;a=a.split(/\s+/);for(c=0,d=a.length;c<d;c++)b[a[c]]=!0;return b}var c=a.document,d=a.navigator,e=a.location,f=function(){function J(){if(!e.isReady){try{c.documentElement.doScroll("left")}catch(a){setTimeout(J,1);return}e.ready()}}var e=function(a,b){return new e.fn.init(a,b,h)},f=a.jQuery,g=a.$,h,i=/^(?:[^#<]*(<[\w\W]+>)[^>]*$|#([\w\-]*)$)/,j=/\S/,k=/^\s+/,l=/\s+$/,m=/^<(\w+)\s*\/?>(?:<\/\1>)?$/,n=/^[\],:{}\s]*$/,o=/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g,p=/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g,q=/(?:^|:|,)(?:\s*\[)+/g,r=/(webkit)[ \/]([\w.]+)/,s=/(opera)(?:.*version)?[ \/]([\w.]+)/,t=/(msie) ([\w.]+)/,u=/(mozilla)(?:.*? rv:([\w.]+))?/,v=/-([a-z]|[0-9])/ig,w=/^-ms-/,x=function(a,b){return(b+"").toUpperCase()},y=d.userAgent,z,A,B,C=Object.prototype.toString,D=Object.prototype.hasOwnProperty,E=Array.prototype.push,F=Array.prototype.slice,G=String.prototype.trim,H=Array.prototype.indexOf,I={};e.fn=e.prototype={constructor:e,init:function(a,d,f){var g,h,j,k;if(!a)return this;if(a.nodeType){this.context=this[0]=a,this.length=1;return this}if(a==="body"&&!d&&c.body){this.context=c,this[0]=c.body,this.selector=a,this.length=1;return this}if(typeof a=="string"){a.charAt(0)!=="<"||a.charAt(a.length-1)!==">"||a.length<3?g=i.exec(a):g=[null,a,null];if(g&&(g[1]||!d)){if(g[1]){d=d instanceof e?d[0]:d,k=d?d.ownerDocument||d:c,j=m.exec(a),j?e.isPlainObject(d)?(a=[c.createElement(j[1])],e.fn.attr.call(a,d,!0)):a=[k.createElement(j[1])]:(j=e.buildFragment([g[1]],[k]),a=(j.cacheable?e.clone(j.fragment):j.fragment).childNodes);return e.merge(this,a)}h=c.getElementById(g[2]);if(h&&h.parentNode){if(h.id!==g[2])return f.find(a);this.length=1,this[0]=h}this.context=c,this.selector=a;return this}return!d||d.jquery?(d||f).find(a):this.constructor(d).find(a)}if(e.isFunction(a))return f.ready(a);a.selector!==b&&(this.selector=a.selector,this.context=a.context);return e.makeArray(a,this)},selector:"",jquery:"1.7.2",length:0,size:function(){return this.length},toArray:function(){return F.call(this,0)},get:function(a){return a==null?this.toArray():a<0?this[this.length+a]:this[a]},pushStack:function(a,b,c){var d=this.constructor();e.isArray(a)?E.apply(d,a):e.merge(d,a),d.prevObject=this,d.context=this.context,b==="find"?d.selector=this.selector+(this.selector?" ":"")+c:b&&(d.selector=this.selector+"."+b+"("+c+")");return d},each:function(a,b){return e.each(this,a,b)},ready:function(a){e.bindReady(),A.add(a);return this},eq:function(a){a=+a;return a===-1?this.slice(a):this.slice(a,a+1)},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},slice:function(){return this.pushStack(F.apply(this,arguments),"slice",F.call(arguments).join(","))},map:function(a){return this.pushStack(e.map(this,function(b,c){return a.call(b,c,b)}))},end:function(){return this.prevObject||this.constructor(null)},push:E,sort:[].sort,splice:[].splice},e.fn.init.prototype=e.fn,e.extend=e.fn.extend=function(){var a,c,d,f,g,h,i=arguments[0]||{},j=1,k=arguments.length,l=!1;typeof i=="boolean"&&(l=i,i=arguments[1]||{},j=2),typeof i!="object"&&!e.isFunction(i)&&(i={}),k===j&&(i=this,--j);for(;j<k;j++)if((a=arguments[j])!=null)for(c in a){d=i[c],f=a[c];if(i===f)continue;l&&f&&(e.isPlainObject(f)||(g=e.isArray(f)))?(g?(g=!1,h=d&&e.isArray(d)?d:[]):h=d&&e.isPlainObject(d)?d:{},i[c]=e.extend(l,h,f)):f!==b&&(i[c]=f)}return i},e.extend({noConflict:function(b){a.$===e&&(a.$=g),b&&a.jQuery===e&&(a.jQuery=f);return e},isReady:!1,readyWait:1,holdReady:function(a){a?e.readyWait++:e.ready(!0)},ready:function(a){if(a===!0&&!--e.readyWait||a!==!0&&!e.isReady){if(!c.body)return setTimeout(e.ready,1);e.isReady=!0;if(a!==!0&&--e.readyWait>0)return;A.fireWith(c,[e]),e.fn.trigger&&e(c).trigger("ready").off("ready")}},bindReady:function(){if(!A){A=e.Callbacks("once memory");if(c.readyState==="complete")return setTimeout(e.ready,1);if(c.addEventListener)c.addEventListener("DOMContentLoaded",B,!1),a.addEventListener("load",e.ready,!1);else if(c.attachEvent){c.attachEvent("onreadystatechange",B),a.attachEvent("onload",e.ready);var b=!1;try{b=a.frameElement==null}catch(d){}c.documentElement.doScroll&&b&&J()}}},isFunction:function(a){return e.type(a)==="function"},isArray:Array.isArray||function(a){return e.type(a)==="array"},isWindow:function(a){return a!=null&&a==a.window},isNumeric:function(a){return!isNaN(parseFloat(a))&&isFinite(a)},type:function(a){return a==null?String(a):I[C.call(a)]||"object"},isPlainObject:function(a){if(!a||e.type(a)!=="object"||a.nodeType||e.isWindow(a))return!1;try{if(a.constructor&&!D.call(a,"constructor")&&!D.call(a.constructor.prototype,"isPrototypeOf"))return!1}catch(c){return!1}var d;for(d in a);return d===b||D.call(a,d)},isEmptyObject:function(a){for(var b in a)return!1;return!0},error:function(a){throw new Error(a)},parseJSON:function(b){if(typeof b!="string"||!b)return null;b=e.trim(b);if(a.JSON&&a.JSON.parse)return a.JSON.parse(b);if(n.test(b.replace(o,"@").replace(p,"]").replace(q,"")))return(new Function("return "+b))();e.error("Invalid JSON: "+b)},parseXML:function(c){if(typeof c!="string"||!c)return null;var d,f;try{a.DOMParser?(f=new DOMParser,d=f.parseFromString(c,"text/xml")):(d=new ActiveXObject("Microsoft.XMLDOM"),d.async="false",d.loadXML(c))}catch(g){d=b}(!d||!d.documentElement||d.getElementsByTagName("parsererror").length)&&e.error("Invalid XML: "+c);return d},noop:function(){},globalEval:function(b){b&&j.test(b)&&(a.execScript||function(b){a.eval.call(a,b)})(b)},camelCase:function(a){return a.replace(w,"ms-").replace(v,x)},nodeName:function(a,b){return a.nodeName&&a.nodeName.toUpperCase()===b.toUpperCase()},each:function(a,c,d){var f,g=0,h=a.length,i=h===b||e.isFunction(a);if(d){if(i){for(f in a)if(c.apply(a[f],d)===!1)break}else for(;g<h;)if(c.apply(a[g++],d)===!1)break}else if(i){for(f in a)if(c.call(a[f],f,a[f])===!1)break}else for(;g<h;)if(c.call(a[g],g,a[g++])===!1)break;return a},trim:G?function(a){return a==null?"":G.call(a)}:function(a){return a==null?"":(a+"").replace(k,"").replace(l,"")},makeArray:function(a,b){var c=b||[];if(a!=null){var d=e.type(a);a.length==null||d==="string"||d==="function"||d==="regexp"||e.isWindow(a)?E.call(c,a):e.merge(c,a)}return c},inArray:function(a,b,c){var d;if(b){if(H)return H.call(b,a,c);d=b.length,c=c?c<0?Math.max(0,d+c):c:0;for(;c<d;c++)if(c in b&&b[c]===a)return c}return-1},merge:function(a,c){var d=a.length,e=0;if(typeof c.length=="number")for(var f=c.length;e<f;e++)a[d++]=c[e];else while(c[e]!==b)a[d++]=c[e++];a.length=d;return a},grep:function(a,b,c){var d=[],e;c=!!c;for(var f=0,g=a.length;f<g;f++)e=!!b(a[f],f),c!==e&&d.push(a[f]);return d},map:function(a,c,d){var f,g,h=[],i=0,j=a.length,k=a instanceof e||j!==b&&typeof j=="number"&&(j>0&&a[0]&&a[j-1]||j===0||e.isArray(a));if(k)for(;i<j;i++)f=c(a[i],i,d),f!=null&&(h[h.length]=f);else for(g in a)f=c(a[g],g,d),f!=null&&(h[h.length]=f);return h.concat.apply([],h)},guid:1,proxy:function(a,c){if(typeof c=="string"){var d=a[c];c=a,a=d}if(!e.isFunction(a))return b;var f=F.call(arguments,2),g=function(){return a.apply(c,f.concat(F.call(arguments)))};g.guid=a.guid=a.guid||g.guid||e.guid++;return g},access:function(a,c,d,f,g,h,i){var j,k=d==null,l=0,m=a.length;if(d&&typeof d=="object"){for(l in d)e.access(a,c,l,d[l],1,h,f);g=1}else if(f!==b){j=i===b&&e.isFunction(f),k&&(j?(j=c,c=function(a,b,c){return j.call(e(a),c)}):(c.call(a,f),c=null));if(c)for(;l<m;l++)c(a[l],d,j?f.call(a[l],l,c(a[l],d)):f,i);g=1}return g?a:k?c.call(a):m?c(a[0],d):h},now:function(){return(new Date).getTime()},uaMatch:function(a){a=a.toLowerCase();var b=r.exec(a)||s.exec(a)||t.exec(a)||a.indexOf("compatible")<0&&u.exec(a)||[];return{browser:b[1]||"",version:b[2]||"0"}},sub:function(){function a(b,c){return new a.fn.init(b,c)}e.extend(!0,a,this),a.superclass=this,a.fn=a.prototype=this(),a.fn.constructor=a,a.sub=this.sub,a.fn.init=function(d,f){f&&f instanceof e&&!(f instanceof a)&&(f=a(f));return e.fn.init.call(this,d,f,b)},a.fn.init.prototype=a.fn;var b=a(c);return a},browser:{}}),e.each("Boolean Number String Function Array Date RegExp Object".split(" "),function(a,b){I["[object "+b+"]"]=b.toLowerCase()}),z=e.uaMatch(y),z.browser&&(e.browser[z.browser]=!0,e.browser.version=z.version),e.browser.webkit&&(e.browser.safari=!0),j.test("Â ")&&(k=/^[\s\xA0]+/,l=/[\s\xA0]+$/),h=e(c),c.addEventListener?B=function(){c.removeEventListener("DOMContentLoaded",B,!1),e.ready()}:c.attachEvent&&(B=function(){c.readyState==="complete"&&(c.detachEvent("onreadystatechange",B),e.ready())});return e}(),g={};f.Callbacks=function(a){a=a?g[a]||h(a):{};var c=[],d=[],e,i,j,k,l,m,n=function(b){var d,e,g,h,i;for(d=0,e=b.length;d<e;d++)g=b[d],h=f.type(g),h==="array"?n(g):h==="function"&&(!a.unique||!p.has(g))&&c.push(g)},o=function(b,f){f=f||[],e=!a.memory||[b,f],i=!0,j=!0,m=k||0,k=0,l=c.length;for(;c&&m<l;m++)if(c[m].apply(b,f)===!1&&a.stopOnFalse){e=!0;break}j=!1,c&&(a.once?e===!0?p.disable():c=[]:d&&d.length&&(e=d.shift(),p.fireWith(e[0],e[1])))},p={add:function(){if(c){var a=c.length;n(arguments),j?l=c.length:e&&e!==!0&&(k=a,o(e[0],e[1]))}return this},remove:function(){if(c){var b=arguments,d=0,e=b.length;for(;d<e;d++)for(var f=0;f<c.length;f++)if(b[d]===c[f]){j&&f<=l&&(l--,f<=m&&m--),c.splice(f--,1);if(a.unique)break}}return this},has:function(a){if(c){var b=0,d=c.length;for(;b<d;b++)if(a===c[b])return!0}return!1},empty:function(){c=[];return this},disable:function(){c=d=e=b;return this},disabled:function(){return!c},lock:function(){d=b,(!e||e===!0)&&p.disable();return this},locked:function(){return!d},fireWith:function(b,c){d&&(j?a.once||d.push([b,c]):(!a.once||!e)&&o(b,c));return this},fire:function(){p.fireWith(this,arguments);return this},fired:function(){return!!i}};return p};var i=[].slice;f.extend({Deferred:function(a){var b=f.Callbacks("once memory"),c=f.Callbacks("once memory"),d=f.Callbacks("memory"),e="pending",g={resolve:b,reject:c,notify:d},h={done:b.add,fail:c.add,progress:d.add,state:function(){return e},isResolved:b.fired,isRejected:c.fired,then:function(a,b,c){i.done(a).fail(b).progress(c);return this},always:function(){i.done.apply(i,arguments).fail.apply(i,arguments);return this},pipe:function(a,b,c){return f.Deferred(function(d){f.each({done:[a,"resolve"],fail:[b,"reject"],progress:[c,"notify"]},function(a,b){var c=b[0],e=b[1],g;f.isFunction(c)?i[a](function(){g=c.apply(this,arguments),g&&f.isFunction(g.promise)?g.promise().then(d.resolve,d.reject,d.notify):d[e+"With"](this===i?d:this,[g])}):i[a](d[e])})}).promise()},promise:function(a){if(a==null)a=h;else for(var b in h)a[b]=h[b];return a}},i=h.promise({}),j;for(j in g)i[j]=g[j].fire,i[j+"With"]=g[j].fireWith;i.done(function(){e="resolved"},c.disable,d.lock).fail(function(){e="rejected"},b.disable,d.lock),a&&a.call(i,i);return i},when:function(a){function m(a){return function(b){e[a]=arguments.length>1?i.call(arguments,0):b,j.notifyWith(k,e)}}function l(a){return function(c){b[a]=arguments.length>1?i.call(arguments,0):c,--g||j.resolveWith(j,b)}}var b=i.call(arguments,0),c=0,d=b.length,e=Array(d),g=d,h=d,j=d<=1&&a&&f.isFunction(a.promise)?a:f.Deferred(),k=j.promise();if(d>1){for(;c<d;c++)b[c]&&b[c].promise&&f.isFunction(b[c].promise)?b[c].promise().then(l(c),j.reject,m(c)):--g;g||j.resolveWith(j,b)}else j!==a&&j.resolveWith(j,d?[a]:[]);return k}}),f.support=function(){var b,d,e,g,h,i,j,k,l,m,n,o,p=c.createElement("div"),q=c.documentElement;p.setAttribute("className","t"),p.innerHTML="   <link/><table></table><a href='/a' style='top:1px;float:left;opacity:.55;'>a</a><input type='checkbox'/>",d=p.getElementsByTagName("*"),e=p.getElementsByTagName("a")[0];if(!d||!d.length||!e)return{};g=c.createElement("select"),h=g.appendChild(c.createElement("option")),i=p.getElementsByTagName("input")[0],b={leadingWhitespace:p.firstChild.nodeType===3,tbody:!p.getElementsByTagName("tbody").length,htmlSerialize:!!p.getElementsByTagName("link").length,style:/top/.test(e.getAttribute("style")),hrefNormalized:e.getAttribute("href")==="/a",opacity:/^0.55/.test(e.style.opacity),cssFloat:!!e.style.cssFloat,checkOn:i.value==="on",optSelected:h.selected,getSetAttribute:p.className!=="t",enctype:!!c.createElement("form").enctype,html5Clone:c.createElement("nav").cloneNode(!0).outerHTML!=="<:nav></:nav>",submitBubbles:!0,changeBubbles:!0,focusinBubbles:!1,deleteExpando:!0,noCloneEvent:!0,inlineBlockNeedsLayout:!1,shrinkWrapBlocks:!1,reliableMarginRight:!0,pixelMargin:!0},f.boxModel=b.boxModel=c.compatMode==="CSS1Compat",i.checked=!0,b.noCloneChecked=i.cloneNode(!0).checked,g.disabled=!0,b.optDisabled=!h.disabled;try{delete p.test}catch(r){b.deleteExpando=!1}!p.addEventListener&&p.attachEvent&&p.fireEvent&&(p.attachEvent("onclick",function(){b.noCloneEvent=!1}),p.cloneNode(!0).fireEvent("onclick")),i=c.createElement("input"),i.value="t",i.setAttribute("type","radio"),b.radioValue=i.value==="t",i.setAttribute("checked","checked"),i.setAttribute("name","t"),p.appendChild(i),j=c.createDocumentFragment(),j.appendChild(p.lastChild),b.checkClone=j.cloneNode(!0).cloneNode(!0).lastChild.checked,b.appendChecked=i.checked,j.removeChild(i),j.appendChild(p);if(p.attachEvent)for(n in{submit:1,change:1,focusin:1})m="on"+n,o=m in p,o||(p.setAttribute(m,"return;"),o=typeof p[m]=="function"),b[n+"Bubbles"]=o;j.removeChild(p),j=g=h=p=i=null,f(function(){var d,e,g,h,i,j,l,m,n,q,r,s,t,u=c.getElementsByTagName("body")[0];!u||(m=1,t="padding:0;margin:0;border:",r="position:absolute;top:0;left:0;width:1px;height:1px;",s=t+"0;visibility:hidden;",n="style='"+r+t+"5px solid #000;",q="<div "+n+"display:block;'><div style='"+t+"0;display:block;overflow:hidden;'></div></div>"+"<table "+n+"' cellpadding='0' cellspacing='0'>"+"<tr><td></td></tr></table>",d=c.createElement("div"),d.style.cssText=s+"width:0;height:0;position:static;top:0;margin-top:"+m+"px",u.insertBefore(d,u.firstChild),p=c.createElement("div"),d.appendChild(p),p.innerHTML="<table><tr><td style='"+t+"0;display:none'></td><td>t</td></tr></table>",k=p.getElementsByTagName("td"),o=k[0].offsetHeight===0,k[0].style.display="",k[1].style.display="none",b.reliableHiddenOffsets=o&&k[0].offsetHeight===0,a.getComputedStyle&&(p.innerHTML="",l=c.createElement("div"),l.style.width="0",l.style.marginRight="0",p.style.width="2px",p.appendChild(l),b.reliableMarginRight=(parseInt((a.getComputedStyle(l,null)||{marginRight:0}).marginRight,10)||0)===0),typeof p.style.zoom!="undefined"&&(p.innerHTML="",p.style.width=p.style.padding="1px",p.style.border=0,p.style.overflow="hidden",p.style.display="inline",p.style.zoom=1,b.inlineBlockNeedsLayout=p.offsetWidth===3,p.style.display="block",p.style.overflow="visible",p.innerHTML="<div style='width:5px;'></div>",b.shrinkWrapBlocks=p.offsetWidth!==3),p.style.cssText=r+s,p.innerHTML=q,e=p.firstChild,g=e.firstChild,i=e.nextSibling.firstChild.firstChild,j={doesNotAddBorder:g.offsetTop!==5,doesAddBorderForTableAndCells:i.offsetTop===5},g.style.position="fixed",g.style.top="20px",j.fixedPosition=g.offsetTop===20||g.offsetTop===15,g.style.position=g.style.top="",e.style.overflow="hidden",e.style.position="relative",j.subtractsBorderForOverflowNotVisible=g.offsetTop===-5,j.doesNotIncludeMarginInBodyOffset=u.offsetTop!==m,a.getComputedStyle&&(p.style.marginTop="1%",b.pixelMargin=(a.getComputedStyle(p,null)||{marginTop:0}).marginTop!=="1%"),typeof d.style.zoom!="undefined"&&(d.style.zoom=1),u.removeChild(d),l=p=d=null,f.extend(b,j))});return b}();var j=/^(?:\{.*\}|\[.*\])$/,k=/([A-Z])/g;f.extend({cache:{},uuid:0,expando:"jQuery"+(f.fn.jquery+Math.random()).replace(/\D/g,""),noData:{embed:!0,object:"clsid:D27CDB6E-AE6D-11cf-96B8-444553540000",applet:!0},hasData:function(a){a=a.nodeType?f.cache[a[f.expando]]:a[f.expando];return!!a&&!m(a)},data:function(a,c,d,e){if(!!f.acceptData(a)){var g,h,i,j=f.expando,k=typeof c=="string",l=a.nodeType,m=l?f.cache:a,n=l?a[j]:a[j]&&j,o=c==="events";if((!n||!m[n]||!o&&!e&&!m[n].data)&&k&&d===b)return;n||(l?a[j]=n=++f.uuid:n=j),m[n]||(m[n]={},l||(m[n].toJSON=f.noop));if(typeof c=="object"||typeof c=="function")e?m[n]=f.extend(m[n],c):m[n].data=f.extend(m[n].data,c);g=h=m[n],e||(h.data||(h.data={}),h=h.data),d!==b&&(h[f.camelCase(c)]=d);if(o&&!h[c])return g.events;k?(i=h[c],i==null&&(i=h[f.camelCase(c)])):i=h;return i}},removeData:function(a,b,c){if(!!f.acceptData(a)){var d,e,g,h=f.expando,i=a.nodeType,j=i?f.cache:a,k=i?a[h]:h;if(!j[k])return;if(b){d=c?j[k]:j[k].data;if(d){f.isArray(b)||(b in d?b=[b]:(b=f.camelCase(b),b in d?b=[b]:b=b.split(" ")));for(e=0,g=b.length;e<g;e++)delete d[b[e]];if(!(c?m:f.isEmptyObject)(d))return}}if(!c){delete j[k].data;if(!m(j[k]))return}f.support.deleteExpando||!j.setInterval?delete j[k]:j[k]=null,i&&(f.support.deleteExpando?delete a[h]:a.removeAttribute?a.removeAttribute(h):a[h]=null)}},_data:function(a,b,c){return f.data(a,b,c,!0)},acceptData:function(a){if(a.nodeName){var b=f.noData[a.nodeName.toLowerCase()];if(b)return b!==!0&&a.getAttribute("classid")===b}return!0}}),f.fn.extend({data:function(a,c){var d,e,g,h,i,j=this[0],k=0,m=null;if(a===b){if(this.length){m=f.data(j);if(j.nodeType===1&&!f._data(j,"parsedAttrs")){g=j.attributes;for(i=g.length;k<i;k++)h=g[k].name,h.indexOf("data-")===0&&(h=f.camelCase(h.substring(5)),l(j,h,m[h]));f._data(j,"parsedAttrs",!0)}}return m}if(typeof a=="object")return this.each(function(){f.data(this,a)});d=a.split(".",2),d[1]=d[1]?"."+d[1]:"",e=d[1]+"!";return f.access(this,function(c){if(c===b){m=this.triggerHandler("getData"+e,[d[0]]),m===b&&j&&(m=f.data(j,a),m=l(j,a,m));return m===b&&d[1]?this.data(d[0]):m}d[1]=c,this.each(function(){var b=f(this);b.triggerHandler("setData"+e,d),f.data(this,a,c),b.triggerHandler("changeData"+e,d)})},null,c,arguments.length>1,null,!1)},removeData:function(a){return this.each(function(){f.removeData(this,a)})}}),f.extend({_mark:function(a,b){a&&(b=(b||"fx")+"mark",f._data(a,b,(f._data(a,b)||0)+1))},_unmark:function(a,b,c){a!==!0&&(c=b,b=a,a=!1);if(b){c=c||"fx";var d=c+"mark",e=a?0:(f._data(b,d)||1)-1;e?f._data(b,d,e):(f.removeData(b,d,!0),n(b,c,"mark"))}},queue:function(a,b,c){var d;if(a){b=(b||"fx")+"queue",d=f._data(a,b),c&&(!d||f.isArray(c)?d=f._data(a,b,f.makeArray(c)):d.push(c));return d||[]}},dequeue:function(a,b){b=b||"fx";var c=f.queue(a,b),d=c.shift(),e={};d==="inprogress"&&(d=c.shift()),d&&(b==="fx"&&c.unshift("inprogress"),f._data(a,b+".run",e),d.call(a,function(){f.dequeue(a,b)},e)),c.length||(f.removeData(a,b+"queue "+b+".run",!0),n(a,b,"queue"))}}),f.fn.extend({queue:function(a,c){var d=2;typeof a!="string"&&(c=a,a="fx",d--);if(arguments.length<d)return f.queue(this[0],a);return c===b?this:this.each(function(){var b=f.queue(this,a,c);a==="fx"&&b[0]!=="inprogress"&&f.dequeue(this,a)})},dequeue:function(a){return this.each(function(){f.dequeue(this,a)})},delay:function(a,b){a=f.fx?f.fx.speeds[a]||a:a,b=b||"fx";return this.queue(b,function(b,c){var d=setTimeout(b,a);c.stop=function(){clearTimeout(d)}})},clearQueue:function(a){return this.queue(a||"fx",[])},promise:function(a,c){function m(){--h||d.resolveWith(e,[e])}typeof a!="string"&&(c=a,a=b),a=a||"fx";var d=f.Deferred(),e=this,g=e.length,h=1,i=a+"defer",j=a+"queue",k=a+"mark",l;while(g--)if(l=f.data(e[g],i,b,!0)||(f.data(e[g],j,b,!0)||f.data(e[g],k,b,!0))&&f.data(e[g],i,f.Callbacks("once memory"),!0))h++,l.add(m);m();return d.promise(c)}});var o=/[\n\t\r]/g,p=/\s+/,q=/\r/g,r=/^(?:button|input)$/i,s=/^(?:button|input|object|select|textarea)$/i,t=/^a(?:rea)?$/i,u=/^(?:autofocus|autoplay|async|checked|controls|defer|disabled|hidden|loop|multiple|open|readonly|required|scoped|selected)$/i,v=f.support.getSetAttribute,w,x,y;f.fn.extend({attr:function(a,b){return f.access(this,f.attr,a,b,arguments.length>1)},removeAttr:function(a){return this.each(function(){f.removeAttr(this,a)})},prop:function(a,b){return f.access(this,f.prop,a,b,arguments.length>1)},removeProp:function(a){a=f.propFix[a]||a;return this.each(function(){try{this[a]=b,delete this[a]}catch(c){}})},addClass:function(a){var b,c,d,e,g,h,i;if(f.isFunction(a))return this.each(function(b){f(this).addClass(a.call(this,b,this.className))});if(a&&typeof a=="string"){b=a.split(p);for(c=0,d=this.length;c<d;c++){e=this[c];if(e.nodeType===1)if(!e.className&&b.length===1)e.className=a;else{g=" "+e.className+" ";for(h=0,i=b.length;h<i;h++)~g.indexOf(" "+b[h]+" ")||(g+=b[h]+" ");e.className=f.trim(g)}}}return this},removeClass:function(a){var c,d,e,g,h,i,j;if(f.isFunction(a))return this.each(function(b){f(this).removeClass(a.call(this,b,this.className))});if(a&&typeof a=="string"||a===b){c=(a||"").split(p);for(d=0,e=this.length;d<e;d++){g=this[d];if(g.nodeType===1&&g.className)if(a){h=(" "+g.className+" ").replace(o," ");for(i=0,j=c.length;i<j;i++)h=h.replace(" "+c[i]+" "," ");g.className=f.trim(h)}else g.className=""}}return this},toggleClass:function(a,b){var c=typeof a,d=typeof b=="boolean";if(f.isFunction(a))return this.each(function(c){f(this).toggleClass(a.call(this,c,this.className,b),b)});return this.each(function(){if(c==="string"){var e,g=0,h=f(this),i=b,j=a.split(p);while(e=j[g++])i=d?i:!h.hasClass(e),h[i?"addClass":"removeClass"](e)}else if(c==="undefined"||c==="boolean")this.className&&f._data(this,"__className__",this.className),this.className=this.className||a===!1?"":f._data(this,"__className__")||""})},hasClass:function(a){var b=" "+a+" ",c=0,d=this.length;for(;c<d;c++)if(this[c].nodeType===1&&(" "+this[c].className+" ").replace(o," ").indexOf(b)>-1)return!0;return!1},val:function(a){var c,d,e,g=this[0];{if(!!arguments.length){e=f.isFunction(a);return this.each(function(d){var g=f(this),h;if(this.nodeType===1){e?h=a.call(this,d,g.val()):h=a,h==null?h="":typeof h=="number"?h+="":f.isArray(h)&&(h=f.map(h,function(a){return a==null?"":a+""})),c=f.valHooks[this.type]||f.valHooks[this.nodeName.toLowerCase()];if(!c||!("set"in c)||c.set(this,h,"value")===b)this.value=h}})}if(g){c=f.valHooks[g.type]||f.valHooks[g.nodeName.toLowerCase()];if(c&&"get"in c&&(d=c.get(g,"value"))!==b)return d;d=g.value;return typeof d=="string"?d.replace(q,""):d==null?"":d}}}}),f.extend({valHooks:{option:{get:function(a){var b=a.attributes.value;return!b||b.specified?a.value:a.text}},select:{get:function(a){var b,c,d,e,g=a.selectedIndex,h=[],i=a.options,j=a.type==="select-one";if(g<0)return null;c=j?g:0,d=j?g+1:i.length;for(;c<d;c++){e=i[c];if(e.selected&&(f.support.optDisabled?!e.disabled:e.getAttribute("disabled")===null)&&(!e.parentNode.disabled||!f.nodeName(e.parentNode,"optgroup"))){b=f(e).val();if(j)return b;h.push(b)}}if(j&&!h.length&&i.length)return f(i[g]).val();return h},set:function(a,b){var c=f.makeArray(b);f(a).find("option").each(function(){this.selected=f.inArray(f(this).val(),c)>=0}),c.length||(a.selectedIndex=-1);return c}}},attrFn:{val:!0,css:!0,html:!0,text:!0,data:!0,width:!0,height:!0,offset:!0},attr:function(a,c,d,e){var g,h,i,j=a.nodeType;if(!!a&&j!==3&&j!==8&&j!==2){if(e&&c in f.attrFn)return f(a)[c](d);if(typeof a.getAttribute=="undefined")return f.prop(a,c,d);i=j!==1||!f.isXMLDoc(a),i&&(c=c.toLowerCase(),h=f.attrHooks[c]||(u.test(c)?x:w));if(d!==b){if(d===null){f.removeAttr(a,c);return}if(h&&"set"in h&&i&&(g=h.set(a,d,c))!==b)return g;a.setAttribute(c,""+d);return d}if(h&&"get"in h&&i&&(g=h.get(a,c))!==null)return g;g=a.getAttribute(c);return g===null?b:g}},removeAttr:function(a,b){var c,d,e,g,h,i=0;if(b&&a.nodeType===1){d=b.toLowerCase().split(p),g=d.length;for(;i<g;i++)e=d[i],e&&(c=f.propFix[e]||e,h=u.test(e),h||f.attr(a,e,""),a.removeAttribute(v?e:c),h&&c in a&&(a[c]=!1))}},attrHooks:{type:{set:function(a,b){if(r.test(a.nodeName)&&a.parentNode)f.error("type property can't be changed");else if(!f.support.radioValue&&b==="radio"&&f.nodeName(a,"input")){var c=a.value;a.setAttribute("type",b),c&&(a.value=c);return b}}},value:{get:function(a,b){if(w&&f.nodeName(a,"button"))return w.get(a,b);return b in a?a.value:null},set:function(a,b,c){if(w&&f.nodeName(a,"button"))return w.set(a,b,c);a.value=b}}},propFix:{tabindex:"tabIndex",readonly:"readOnly","for":"htmlFor","class":"className",maxlength:"maxLength",cellspacing:"cellSpacing",cellpadding:"cellPadding",rowspan:"rowSpan",colspan:"colSpan",usemap:"useMap",frameborder:"frameBorder",contenteditable:"contentEditable"},prop:function(a,c,d){var e,g,h,i=a.nodeType;if(!!a&&i!==3&&i!==8&&i!==2){h=i!==1||!f.isXMLDoc(a),h&&(c=f.propFix[c]||c,g=f.propHooks[c]);return d!==b?g&&"set"in g&&(e=g.set(a,d,c))!==b?e:a[c]=d:g&&"get"in g&&(e=g.get(a,c))!==null?e:a[c]}},propHooks:{tabIndex:{get:function(a){var c=a.getAttributeNode("tabindex");return c&&c.specified?parseInt(c.value,10):s.test(a.nodeName)||t.test(a.nodeName)&&a.href?0:b}}}}),f.attrHooks.tabindex=f.propHooks.tabIndex,x={get:function(a,c){var d,e=f.prop(a,c);return e===!0||typeof e!="boolean"&&(d=a.getAttributeNode(c))&&d.nodeValue!==!1?c.toLowerCase():b},set:function(a,b,c){var d;b===!1?f.removeAttr(a,c):(d=f.propFix[c]||c,d in a&&(a[d]=!0),a.setAttribute(c,c.toLowerCase()));return c}},v||(y={name:!0,id:!0,coords:!0},w=f.valHooks.button={get:function(a,c){var d;d=a.getAttributeNode(c);return d&&(y[c]?d.nodeValue!=="":d.specified)?d.nodeValue:b},set:function(a,b,d){var e=a.getAttributeNode(d);e||(e=c.createAttribute(d),a.setAttributeNode(e));return e.nodeValue=b+""}},f.attrHooks.tabindex.set=w.set,f.each(["width","height"],function(a,b){f.attrHooks[b]=f.extend(f.attrHooks[b],{set:function(a,c){if(c===""){a.setAttribute(b,"auto");return c}}})}),f.attrHooks.contenteditable={get:w.get,set:function(a,b,c){b===""&&(b="false"),w.set(a,b,c)}}),f.support.hrefNormalized||f.each(["href","src","width","height"],function(a,c){f.attrHooks[c]=f.extend(f.attrHooks[c],{get:function(a){var d=a.getAttribute(c,2);return d===null?b:d}})}),f.support.style||(f.attrHooks.style={get:function(a){return a.style.cssText.toLowerCase()||b},set:function(a,b){return a.style.cssText=""+b}}),f.support.optSelected||(f.propHooks.selected=f.extend(f.propHooks.selected,{get:function(a){var b=a.parentNode;b&&(b.selectedIndex,b.parentNode&&b.parentNode.selectedIndex);return null}})),f.support.enctype||(f.propFix.enctype="encoding"),f.support.checkOn||f.each(["radio","checkbox"],function(){f.valHooks[this]={get:function(a){return a.getAttribute("value")===null?"on":a.value}}}),f.each(["radio","checkbox"],function(){f.valHooks[this]=f.extend(f.valHooks[this],{set:function(a,b){if(f.isArray(b))return a.checked=f.inArray(f(a).val(),b)>=0}})});var z=/^(?:textarea|input|select)$/i,A=/^([^\.]*)?(?:\.(.+))?$/,B=/(?:^|\s)hover(\.\S+)?\b/,C=/^key/,D=/^(?:mouse|contextmenu)|click/,E=/^(?:focusinfocus|focusoutblur)$/,F=/^(\w*)(?:#([\w\-]+))?(?:\.([\w\-]+))?$/,G=function(
    +-a){var b=F.exec(a);b&&(b[1]=(b[1]||"").toLowerCase(),b[3]=b[3]&&new RegExp("(?:^|\\s)"+b[3]+"(?:\\s|$)"));return b},H=function(a,b){var c=a.attributes||{};return(!b[1]||a.nodeName.toLowerCase()===b[1])&&(!b[2]||(c.id||{}).value===b[2])&&(!b[3]||b[3].test((c["class"]||{}).value))},I=function(a){return f.event.special.hover?a:a.replace(B,"mouseenter$1 mouseleave$1")};f.event={add:function(a,c,d,e,g){var h,i,j,k,l,m,n,o,p,q,r,s;if(!(a.nodeType===3||a.nodeType===8||!c||!d||!(h=f._data(a)))){d.handler&&(p=d,d=p.handler,g=p.selector),d.guid||(d.guid=f.guid++),j=h.events,j||(h.events=j={}),i=h.handle,i||(h.handle=i=function(a){return typeof f!="undefined"&&(!a||f.event.triggered!==a.type)?f.event.dispatch.apply(i.elem,arguments):b},i.elem=a),c=f.trim(I(c)).split(" ");for(k=0;k<c.length;k++){l=A.exec(c[k])||[],m=l[1],n=(l[2]||"").split(".").sort(),s=f.event.special[m]||{},m=(g?s.delegateType:s.bindType)||m,s=f.event.special[m]||{},o=f.extend({type:m,origType:l[1],data:e,handler:d,guid:d.guid,selector:g,quick:g&&G(g),namespace:n.join(".")},p),r=j[m];if(!r){r=j[m]=[],r.delegateCount=0;if(!s.setup||s.setup.call(a,e,n,i)===!1)a.addEventListener?a.addEventListener(m,i,!1):a.attachEvent&&a.attachEvent("on"+m,i)}s.add&&(s.add.call(a,o),o.handler.guid||(o.handler.guid=d.guid)),g?r.splice(r.delegateCount++,0,o):r.push(o),f.event.global[m]=!0}a=null}},global:{},remove:function(a,b,c,d,e){var g=f.hasData(a)&&f._data(a),h,i,j,k,l,m,n,o,p,q,r,s;if(!!g&&!!(o=g.events)){b=f.trim(I(b||"")).split(" ");for(h=0;h<b.length;h++){i=A.exec(b[h])||[],j=k=i[1],l=i[2];if(!j){for(j in o)f.event.remove(a,j+b[h],c,d,!0);continue}p=f.event.special[j]||{},j=(d?p.delegateType:p.bindType)||j,r=o[j]||[],m=r.length,l=l?new RegExp("(^|\\.)"+l.split(".").sort().join("\\.(?:.*\\.)?")+"(\\.|$)"):null;for(n=0;n<r.length;n++)s=r[n],(e||k===s.origType)&&(!c||c.guid===s.guid)&&(!l||l.test(s.namespace))&&(!d||d===s.selector||d==="**"&&s.selector)&&(r.splice(n--,1),s.selector&&r.delegateCount--,p.remove&&p.remove.call(a,s));r.length===0&&m!==r.length&&((!p.teardown||p.teardown.call(a,l)===!1)&&f.removeEvent(a,j,g.handle),delete o[j])}f.isEmptyObject(o)&&(q=g.handle,q&&(q.elem=null),f.removeData(a,["events","handle"],!0))}},customEvent:{getData:!0,setData:!0,changeData:!0},trigger:function(c,d,e,g){if(!e||e.nodeType!==3&&e.nodeType!==8){var h=c.type||c,i=[],j,k,l,m,n,o,p,q,r,s;if(E.test(h+f.event.triggered))return;h.indexOf("!")>=0&&(h=h.slice(0,-1),k=!0),h.indexOf(".")>=0&&(i=h.split("."),h=i.shift(),i.sort());if((!e||f.event.customEvent[h])&&!f.event.global[h])return;c=typeof c=="object"?c[f.expando]?c:new f.Event(h,c):new f.Event(h),c.type=h,c.isTrigger=!0,c.exclusive=k,c.namespace=i.join("."),c.namespace_re=c.namespace?new RegExp("(^|\\.)"+i.join("\\.(?:.*\\.)?")+"(\\.|$)"):null,o=h.indexOf(":")<0?"on"+h:"";if(!e){j=f.cache;for(l in j)j[l].events&&j[l].events[h]&&f.event.trigger(c,d,j[l].handle.elem,!0);return}c.result=b,c.target||(c.target=e),d=d!=null?f.makeArray(d):[],d.unshift(c),p=f.event.special[h]||{};if(p.trigger&&p.trigger.apply(e,d)===!1)return;r=[[e,p.bindType||h]];if(!g&&!p.noBubble&&!f.isWindow(e)){s=p.delegateType||h,m=E.test(s+h)?e:e.parentNode,n=null;for(;m;m=m.parentNode)r.push([m,s]),n=m;n&&n===e.ownerDocument&&r.push([n.defaultView||n.parentWindow||a,s])}for(l=0;l<r.length&&!c.isPropagationStopped();l++)m=r[l][0],c.type=r[l][1],q=(f._data(m,"events")||{})[c.type]&&f._data(m,"handle"),q&&q.apply(m,d),q=o&&m[o],q&&f.acceptData(m)&&q.apply(m,d)===!1&&c.preventDefault();c.type=h,!g&&!c.isDefaultPrevented()&&(!p._default||p._default.apply(e.ownerDocument,d)===!1)&&(h!=="click"||!f.nodeName(e,"a"))&&f.acceptData(e)&&o&&e[h]&&(h!=="focus"&&h!=="blur"||c.target.offsetWidth!==0)&&!f.isWindow(e)&&(n=e[o],n&&(e[o]=null),f.event.triggered=h,e[h](),f.event.triggered=b,n&&(e[o]=n));return c.result}},dispatch:function(c){c=f.event.fix(c||a.event);var d=(f._data(this,"events")||{})[c.type]||[],e=d.delegateCount,g=[].slice.call(arguments,0),h=!c.exclusive&&!c.namespace,i=f.event.special[c.type]||{},j=[],k,l,m,n,o,p,q,r,s,t,u;g[0]=c,c.delegateTarget=this;if(!i.preDispatch||i.preDispatch.call(this,c)!==!1){if(e&&(!c.button||c.type!=="click")){n=f(this),n.context=this.ownerDocument||this;for(m=c.target;m!=this;m=m.parentNode||this)if(m.disabled!==!0){p={},r=[],n[0]=m;for(k=0;k<e;k++)s=d[k],t=s.selector,p[t]===b&&(p[t]=s.quick?H(m,s.quick):n.is(t)),p[t]&&r.push(s);r.length&&j.push({elem:m,matches:r})}}d.length>e&&j.push({elem:this,matches:d.slice(e)});for(k=0;k<j.length&&!c.isPropagationStopped();k++){q=j[k],c.currentTarget=q.elem;for(l=0;l<q.matches.length&&!c.isImmediatePropagationStopped();l++){s=q.matches[l];if(h||!c.namespace&&!s.namespace||c.namespace_re&&c.namespace_re.test(s.namespace))c.data=s.data,c.handleObj=s,o=((f.event.special[s.origType]||{}).handle||s.handler).apply(q.elem,g),o!==b&&(c.result=o,o===!1&&(c.preventDefault(),c.stopPropagation()))}}i.postDispatch&&i.postDispatch.call(this,c);return c.result}},props:"attrChange attrName relatedNode srcElement altKey bubbles cancelable ctrlKey currentTarget eventPhase metaKey relatedTarget shiftKey target timeStamp view which".split(" "),fixHooks:{},keyHooks:{props:"char charCode key keyCode".split(" "),filter:function(a,b){a.which==null&&(a.which=b.charCode!=null?b.charCode:b.keyCode);return a}},mouseHooks:{props:"button buttons clientX clientY fromElement offsetX offsetY pageX pageY screenX screenY toElement".split(" "),filter:function(a,d){var e,f,g,h=d.button,i=d.fromElement;a.pageX==null&&d.clientX!=null&&(e=a.target.ownerDocument||c,f=e.documentElement,g=e.body,a.pageX=d.clientX+(f&&f.scrollLeft||g&&g.scrollLeft||0)-(f&&f.clientLeft||g&&g.clientLeft||0),a.pageY=d.clientY+(f&&f.scrollTop||g&&g.scrollTop||0)-(f&&f.clientTop||g&&g.clientTop||0)),!a.relatedTarget&&i&&(a.relatedTarget=i===a.target?d.toElement:i),!a.which&&h!==b&&(a.which=h&1?1:h&2?3:h&4?2:0);return a}},fix:function(a){if(a[f.expando])return a;var d,e,g=a,h=f.event.fixHooks[a.type]||{},i=h.props?this.props.concat(h.props):this.props;a=f.Event(g);for(d=i.length;d;)e=i[--d],a[e]=g[e];a.target||(a.target=g.srcElement||c),a.target.nodeType===3&&(a.target=a.target.parentNode),a.metaKey===b&&(a.metaKey=a.ctrlKey);return h.filter?h.filter(a,g):a},special:{ready:{setup:f.bindReady},load:{noBubble:!0},focus:{delegateType:"focusin"},blur:{delegateType:"focusout"},beforeunload:{setup:function(a,b,c){f.isWindow(this)&&(this.onbeforeunload=c)},teardown:function(a,b){this.onbeforeunload===b&&(this.onbeforeunload=null)}}},simulate:function(a,b,c,d){var e=f.extend(new f.Event,c,{type:a,isSimulated:!0,originalEvent:{}});d?f.event.trigger(e,null,b):f.event.dispatch.call(b,e),e.isDefaultPrevented()&&c.preventDefault()}},f.event.handle=f.event.dispatch,f.removeEvent=c.removeEventListener?function(a,b,c){a.removeEventListener&&a.removeEventListener(b,c,!1)}:function(a,b,c){a.detachEvent&&a.detachEvent("on"+b,c)},f.Event=function(a,b){if(!(this instanceof f.Event))return new f.Event(a,b);a&&a.type?(this.originalEvent=a,this.type=a.type,this.isDefaultPrevented=a.defaultPrevented||a.returnValue===!1||a.getPreventDefault&&a.getPreventDefault()?K:J):this.type=a,b&&f.extend(this,b),this.timeStamp=a&&a.timeStamp||f.now(),this[f.expando]=!0},f.Event.prototype={preventDefault:function(){this.isDefaultPrevented=K;var a=this.originalEvent;!a||(a.preventDefault?a.preventDefault():a.returnValue=!1)},stopPropagation:function(){this.isPropagationStopped=K;var a=this.originalEvent;!a||(a.stopPropagation&&a.stopPropagation(),a.cancelBubble=!0)},stopImmediatePropagation:function(){this.isImmediatePropagationStopped=K,this.stopPropagation()},isDefaultPrevented:J,isPropagationStopped:J,isImmediatePropagationStopped:J},f.each({mouseenter:"mouseover",mouseleave:"mouseout"},function(a,b){f.event.special[a]={delegateType:b,bindType:b,handle:function(a){var c=this,d=a.relatedTarget,e=a.handleObj,g=e.selector,h;if(!d||d!==c&&!f.contains(c,d))a.type=e.origType,h=e.handler.apply(this,arguments),a.type=b;return h}}}),f.support.submitBubbles||(f.event.special.submit={setup:function(){if(f.nodeName(this,"form"))return!1;f.event.add(this,"click._submit keypress._submit",function(a){var c=a.target,d=f.nodeName(c,"input")||f.nodeName(c,"button")?c.form:b;d&&!d._submit_attached&&(f.event.add(d,"submit._submit",function(a){a._submit_bubble=!0}),d._submit_attached=!0)})},postDispatch:function(a){a._submit_bubble&&(delete a._submit_bubble,this.parentNode&&!a.isTrigger&&f.event.simulate("submit",this.parentNode,a,!0))},teardown:function(){if(f.nodeName(this,"form"))return!1;f.event.remove(this,"._submit")}}),f.support.changeBubbles||(f.event.special.change={setup:function(){if(z.test(this.nodeName)){if(this.type==="checkbox"||this.type==="radio")f.event.add(this,"propertychange._change",function(a){a.originalEvent.propertyName==="checked"&&(this._just_changed=!0)}),f.event.add(this,"click._change",function(a){this._just_changed&&!a.isTrigger&&(this._just_changed=!1,f.event.simulate("change",this,a,!0))});return!1}f.event.add(this,"beforeactivate._change",function(a){var b=a.target;z.test(b.nodeName)&&!b._change_attached&&(f.event.add(b,"change._change",function(a){this.parentNode&&!a.isSimulated&&!a.isTrigger&&f.event.simulate("change",this.parentNode,a,!0)}),b._change_attached=!0)})},handle:function(a){var b=a.target;if(this!==b||a.isSimulated||a.isTrigger||b.type!=="radio"&&b.type!=="checkbox")return a.handleObj.handler.apply(this,arguments)},teardown:function(){f.event.remove(this,"._change");return z.test(this.nodeName)}}),f.support.focusinBubbles||f.each({focus:"focusin",blur:"focusout"},function(a,b){var d=0,e=function(a){f.event.simulate(b,a.target,f.event.fix(a),!0)};f.event.special[b]={setup:function(){d++===0&&c.addEventListener(a,e,!0)},teardown:function(){--d===0&&c.removeEventListener(a,e,!0)}}}),f.fn.extend({on:function(a,c,d,e,g){var h,i;if(typeof a=="object"){typeof c!="string"&&(d=d||c,c=b);for(i in a)this.on(i,c,d,a[i],g);return this}d==null&&e==null?(e=c,d=c=b):e==null&&(typeof c=="string"?(e=d,d=b):(e=d,d=c,c=b));if(e===!1)e=J;else if(!e)return this;g===1&&(h=e,e=function(a){f().off(a);return h.apply(this,arguments)},e.guid=h.guid||(h.guid=f.guid++));return this.each(function(){f.event.add(this,a,e,d,c)})},one:function(a,b,c,d){return this.on(a,b,c,d,1)},off:function(a,c,d){if(a&&a.preventDefault&&a.handleObj){var e=a.handleObj;f(a.delegateTarget).off(e.namespace?e.origType+"."+e.namespace:e.origType,e.selector,e.handler);return this}if(typeof a=="object"){for(var g in a)this.off(g,c,a[g]);return this}if(c===!1||typeof c=="function")d=c,c=b;d===!1&&(d=J);return this.each(function(){f.event.remove(this,a,d,c)})},bind:function(a,b,c){return this.on(a,null,b,c)},unbind:function(a,b){return this.off(a,null,b)},live:function(a,b,c){f(this.context).on(a,this.selector,b,c);return this},die:function(a,b){f(this.context).off(a,this.selector||"**",b);return this},delegate:function(a,b,c,d){return this.on(b,a,c,d)},undelegate:function(a,b,c){return arguments.length==1?this.off(a,"**"):this.off(b,a,c)},trigger:function(a,b){return this.each(function(){f.event.trigger(a,b,this)})},triggerHandler:function(a,b){if(this[0])return f.event.trigger(a,b,this[0],!0)},toggle:function(a){var b=arguments,c=a.guid||f.guid++,d=0,e=function(c){var e=(f._data(this,"lastToggle"+a.guid)||0)%d;f._data(this,"lastToggle"+a.guid,e+1),c.preventDefault();return b[e].apply(this,arguments)||!1};e.guid=c;while(d<b.length)b[d++].guid=c;return this.click(e)},hover:function(a,b){return this.mouseenter(a).mouseleave(b||a)}}),f.each("blur focus focusin focusout load resize scroll unload click dblclick mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave change select submit keydown keypress keyup error contextmenu".split(" "),function(a,b){f.fn[b]=function(a,c){c==null&&(c=a,a=null);return arguments.length>0?this.on(b,null,a,c):this.trigger(b)},f.attrFn&&(f.attrFn[b]=!0),C.test(b)&&(f.event.fixHooks[b]=f.event.keyHooks),D.test(b)&&(f.event.fixHooks[b]=f.event.mouseHooks)}),function(){function x(a,b,c,e,f,g){for(var h=0,i=e.length;h<i;h++){var j=e[h];if(j){var k=!1;j=j[a];while(j){if(j[d]===c){k=e[j.sizset];break}if(j.nodeType===1){g||(j[d]=c,j.sizset=h);if(typeof b!="string"){if(j===b){k=!0;break}}else if(m.filter(b,[j]).length>0){k=j;break}}j=j[a]}e[h]=k}}}function w(a,b,c,e,f,g){for(var h=0,i=e.length;h<i;h++){var j=e[h];if(j){var k=!1;j=j[a];while(j){if(j[d]===c){k=e[j.sizset];break}j.nodeType===1&&!g&&(j[d]=c,j.sizset=h);if(j.nodeName.toLowerCase()===b){k=j;break}j=j[a]}e[h]=k}}}var a=/((?:\((?:\([^()]+\)|[^()]+)+\)|\[(?:\[[^\[\]]*\]|['"][^'"]*['"]|[^\[\]'"]+)+\]|\\.|[^ >+~,(\[\\]+)+|[>+~])(\s*,\s*)?((?:.|\r|\n)*)/g,d="sizcache"+(Math.random()+"").replace(".",""),e=0,g=Object.prototype.toString,h=!1,i=!0,j=/\\/g,k=/\r\n/g,l=/\W/;[0,0].sort(function(){i=!1;return 0});var m=function(b,d,e,f){e=e||[],d=d||c;var h=d;if(d.nodeType!==1&&d.nodeType!==9)return[];if(!b||typeof b!="string")return e;var i,j,k,l,n,q,r,t,u=!0,v=m.isXML(d),w=[],x=b;do{a.exec(""),i=a.exec(x);if(i){x=i[3],w.push(i[1]);if(i[2]){l=i[3];break}}}while(i);if(w.length>1&&p.exec(b))if(w.length===2&&o.relative[w[0]])j=y(w[0]+w[1],d,f);else{j=o.relative[w[0]]?[d]:m(w.shift(),d);while(w.length)b=w.shift(),o.relative[b]&&(b+=w.shift()),j=y(b,j,f)}else{!f&&w.length>1&&d.nodeType===9&&!v&&o.match.ID.test(w[0])&&!o.match.ID.test(w[w.length-1])&&(n=m.find(w.shift(),d,v),d=n.expr?m.filter(n.expr,n.set)[0]:n.set[0]);if(d){n=f?{expr:w.pop(),set:s(f)}:m.find(w.pop(),w.length===1&&(w[0]==="~"||w[0]==="+")&&d.parentNode?d.parentNode:d,v),j=n.expr?m.filter(n.expr,n.set):n.set,w.length>0?k=s(j):u=!1;while(w.length)q=w.pop(),r=q,o.relative[q]?r=w.pop():q="",r==null&&(r=d),o.relative[q](k,r,v)}else k=w=[]}k||(k=j),k||m.error(q||b);if(g.call(k)==="[object Array]")if(!u)e.push.apply(e,k);else if(d&&d.nodeType===1)for(t=0;k[t]!=null;t++)k[t]&&(k[t]===!0||k[t].nodeType===1&&m.contains(d,k[t]))&&e.push(j[t]);else for(t=0;k[t]!=null;t++)k[t]&&k[t].nodeType===1&&e.push(j[t]);else s(k,e);l&&(m(l,h,e,f),m.uniqueSort(e));return e};m.uniqueSort=function(a){if(u){h=i,a.sort(u);if(h)for(var b=1;b<a.length;b++)a[b]===a[b-1]&&a.splice(b--,1)}return a},m.matches=function(a,b){return m(a,null,null,b)},m.matchesSelector=function(a,b){return m(b,null,null,[a]).length>0},m.find=function(a,b,c){var d,e,f,g,h,i;if(!a)return[];for(e=0,f=o.order.length;e<f;e++){h=o.order[e];if(g=o.leftMatch[h].exec(a)){i=g[1],g.splice(1,1);if(i.substr(i.length-1)!=="\\"){g[1]=(g[1]||"").replace(j,""),d=o.find[h](g,b,c);if(d!=null){a=a.replace(o.match[h],"");break}}}}d||(d=typeof b.getElementsByTagName!="undefined"?b.getElementsByTagName("*"):[]);return{set:d,expr:a}},m.filter=function(a,c,d,e){var f,g,h,i,j,k,l,n,p,q=a,r=[],s=c,t=c&&c[0]&&m.isXML(c[0]);while(a&&c.length){for(h in o.filter)if((f=o.leftMatch[h].exec(a))!=null&&f[2]){k=o.filter[h],l=f[1],g=!1,f.splice(1,1);if(l.substr(l.length-1)==="\\")continue;s===r&&(r=[]);if(o.preFilter[h]){f=o.preFilter[h](f,s,d,r,e,t);if(!f)g=i=!0;else if(f===!0)continue}if(f)for(n=0;(j=s[n])!=null;n++)j&&(i=k(j,f,n,s),p=e^i,d&&i!=null?p?g=!0:s[n]=!1:p&&(r.push(j),g=!0));if(i!==b){d||(s=r),a=a.replace(o.match[h],"");if(!g)return[];break}}if(a===q)if(g==null)m.error(a);else break;q=a}return s},m.error=function(a){throw new Error("Syntax error, unrecognized expression: "+a)};var n=m.getText=function(a){var b,c,d=a.nodeType,e="";if(d){if(d===1||d===9||d===11){if(typeof a.textContent=="string")return a.textContent;if(typeof a.innerText=="string")return a.innerText.replace(k,"");for(a=a.firstChild;a;a=a.nextSibling)e+=n(a)}else if(d===3||d===4)return a.nodeValue}else for(b=0;c=a[b];b++)c.nodeType!==8&&(e+=n(c));return e},o=m.selectors={order:["ID","NAME","TAG"],match:{ID:/#((?:[\w\u00c0-\uFFFF\-]|\\.)+)/,CLASS:/\.((?:[\w\u00c0-\uFFFF\-]|\\.)+)/,NAME:/\[name=['"]*((?:[\w\u00c0-\uFFFF\-]|\\.)+)['"]*\]/,ATTR:/\[\s*((?:[\w\u00c0-\uFFFF\-]|\\.)+)\s*(?:(\S?=)\s*(?:(['"])(.*?)\3|(#?(?:[\w\u00c0-\uFFFF\-]|\\.)*)|)|)\s*\]/,TAG:/^((?:[\w\u00c0-\uFFFF\*\-]|\\.)+)/,CHILD:/:(only|nth|last|first)-child(?:\(\s*(even|odd|(?:[+\-]?\d+|(?:[+\-]?\d*)?n\s*(?:[+\-]\s*\d+)?))\s*\))?/,POS:/:(nth|eq|gt|lt|first|last|even|odd)(?:\((\d*)\))?(?=[^\-]|$)/,PSEUDO:/:((?:[\w\u00c0-\uFFFF\-]|\\.)+)(?:\((['"]?)((?:\([^\)]+\)|[^\(\)]*)+)\2\))?/},leftMatch:{},attrMap:{"class":"className","for":"htmlFor"},attrHandle:{href:function(a){return a.getAttribute("href")},type:function(a){return a.getAttribute("type")}},relative:{"+":function(a,b){var c=typeof b=="string",d=c&&!l.test(b),e=c&&!d;d&&(b=b.toLowerCase());for(var f=0,g=a.length,h;f<g;f++)if(h=a[f]){while((h=h.previousSibling)&&h.nodeType!==1);a[f]=e||h&&h.nodeName.toLowerCase()===b?h||!1:h===b}e&&m.filter(b,a,!0)},">":function(a,b){var c,d=typeof b=="string",e=0,f=a.length;if(d&&!l.test(b)){b=b.toLowerCase();for(;e<f;e++){c=a[e];if(c){var g=c.parentNode;a[e]=g.nodeName.toLowerCase()===b?g:!1}}}else{for(;e<f;e++)c=a[e],c&&(a[e]=d?c.parentNode:c.parentNode===b);d&&m.filter(b,a,!0)}},"":function(a,b,c){var d,f=e++,g=x;typeof b=="string"&&!l.test(b)&&(b=b.toLowerCase(),d=b,g=w),g("parentNode",b,f,a,d,c)},"~":function(a,b,c){var d,f=e++,g=x;typeof b=="string"&&!l.test(b)&&(b=b.toLowerCase(),d=b,g=w),g("previousSibling",b,f,a,d,c)}},find:{ID:function(a,b,c){if(typeof b.getElementById!="undefined"&&!c){var d=b.getElementById(a[1]);return d&&d.parentNode?[d]:[]}},NAME:function(a,b){if(typeof b.getElementsByName!="undefined"){var c=[],d=b.getElementsByName(a[1]);for(var e=0,f=d.length;e<f;e++)d[e].getAttribute("name")===a[1]&&c.push(d[e]);return c.length===0?null:c}},TAG:function(a,b){if(typeof b.getElementsByTagName!="undefined")return b.getElementsByTagName(a[1])}},preFilter:{CLASS:function(a,b,c,d,e,f){a=" "+a[1].replace(j,"")+" ";if(f)return a;for(var g=0,h;(h=b[g])!=null;g++)h&&(e^(h.className&&(" "+h.className+" ").replace(/[\t\n\r]/g," ").indexOf(a)>=0)?c||d.push(h):c&&(b[g]=!1));return!1},ID:function(a){return a[1].replace(j,"")},TAG:function(a,b){return a[1].replace(j,"").toLowerCase()},CHILD:function(a){if(a[1]==="nth"){a[2]||m.error(a[0]),a[2]=a[2].replace(/^\+|\s*/g,"");var b=/(-?)(\d*)(?:n([+\-]?\d*))?/.exec(a[2]==="even"&&"2n"||a[2]==="odd"&&"2n+1"||!/\D/.test(a[2])&&"0n+"+a[2]||a[2]);a[2]=b[1]+(b[2]||1)-0,a[3]=b[3]-0}else a[2]&&m.error(a[0]);a[0]=e++;return a},ATTR:function(a,b,c,d,e,f){var g=a[1]=a[1].replace(j,"");!f&&o.attrMap[g]&&(a[1]=o.attrMap[g]),a[4]=(a[4]||a[5]||"").replace(j,""),a[2]==="~="&&(a[4]=" "+a[4]+" ");return a},PSEUDO:function(b,c,d,e,f){if(b[1]==="not")if((a.exec(b[3])||"").length>1||/^\w/.test(b[3]))b[3]=m(b[3],null,null,c);else{var g=m.filter(b[3],c,d,!0^f);d||e.push.apply(e,g);return!1}else if(o.match.POS.test(b[0])||o.match.CHILD.test(b[0]))return!0;return b},POS:function(a){a.unshift(!0);return a}},filters:{enabled:function(a){return a.disabled===!1&&a.type!=="hidden"},disabled:function(a){return a.disabled===!0},checked:function(a){return a.checked===!0},selected:function(a){a.parentNode&&a.parentNode.selectedIndex;return a.selected===!0},parent:function(a){return!!a.firstChild},empty:function(a){return!a.firstChild},has:function(a,b,c){return!!m(c[3],a).length},header:function(a){return/h\d/i.test(a.nodeName)},text:function(a){var b=a.getAttribute("type"),c=a.type;return a.nodeName.toLowerCase()==="input"&&"text"===c&&(b===c||b===null)},radio:function(a){return a.nodeName.toLowerCase()==="input"&&"radio"===a.type},checkbox:function(a){return a.nodeName.toLowerCase()==="input"&&"checkbox"===a.type},file:function(a){return a.nodeName.toLowerCase()==="input"&&"file"===a.type},password:function(a){return a.nodeName.toLowerCase()==="input"&&"password"===a.type},submit:function(a){var b=a.nodeName.toLowerCase();return(b==="input"||b==="button")&&"submit"===a.type},image:function(a){return a.nodeName.toLowerCase()==="input"&&"image"===a.type},reset:function(a){var b=a.nodeName.toLowerCase();return(b==="input"||b==="button")&&"reset"===a.type},button:function(a){var b=a.nodeName.toLowerCase();return b==="input"&&"button"===a.type||b==="button"},input:function(a){return/input|select|textarea|button/i.test(a.nodeName)},focus:function(a){return a===a.ownerDocument.activeElement}},setFilters:{first:function(a,b){return b===0},last:function(a,b,c,d){return b===d.length-1},even:function(a,b){return b%2===0},odd:function(a,b){return b%2===1},lt:function(a,b,c){return b<c[3]-0},gt:function(a,b,c){return b>c[3]-0},nth:function(a,b,c){return c[3]-0===b},eq:function(a,b,c){return c[3]-0===b}},filter:{PSEUDO:function(a,b,c,d){var e=b[1],f=o.filters[e];if(f)return f(a,c,b,d);if(e==="contains")return(a.textContent||a.innerText||n([a])||"").indexOf(b[3])>=0;if(e==="not"){var g=b[3];for(var h=0,i=g.length;h<i;h++)if(g[h]===a)return!1;return!0}m.error(e)},CHILD:function(a,b){var c,e,f,g,h,i,j,k=b[1],l=a;switch(k){case"only":case"first":while(l=l.previousSibling)if(l.nodeType===1)return!1;if(k==="first")return!0;l=a;case"last":while(l=l.nextSibling)if(l.nodeType===1)return!1;return!0;case"nth":c=b[2],e=b[3];if(c===1&&e===0)return!0;f=b[0],g=a.parentNode;if(g&&(g[d]!==f||!a.nodeIndex)){i=0;for(l=g.firstChild;l;l=l.nextSibling)l.nodeType===1&&(l.nodeIndex=++i);g[d]=f}j=a.nodeIndex-e;return c===0?j===0:j%c===0&&j/c>=0}},ID:function(a,b){return a.nodeType===1&&a.getAttribute("id")===b},TAG:function(a,b){return b==="*"&&a.nodeType===1||!!a.nodeName&&a.nodeName.toLowerCase()===b},CLASS:function(a,b){return(" "+(a.className||a.getAttribute("class"))+" ").indexOf(b)>-1},ATTR:function(a,b){var c=b[1],d=m.attr?m.attr(a,c):o.attrHandle[c]?o.attrHandle[c](a):a[c]!=null?a[c]:a.getAttribute(c),e=d+"",f=b[2],g=b[4];return d==null?f==="!=":!f&&m.attr?d!=null:f==="="?e===g:f==="*="?e.indexOf(g)>=0:f==="~="?(" "+e+" ").indexOf(g)>=0:g?f==="!="?e!==g:f==="^="?e.indexOf(g)===0:f==="$="?e.substr(e.length-g.length)===g:f==="|="?e===g||e.substr(0,g.length+1)===g+"-":!1:e&&d!==!1},POS:function(a,b,c,d){var e=b[2],f=o.setFilters[e];if(f)return f(a,c,b,d)}}},p=o.match.POS,q=function(a,b){return"\\"+(b-0+1)};for(var r in o.match)o.match[r]=new RegExp(o.match[r].source+/(?![^\[]*\])(?![^\(]*\))/.source),o.leftMatch[r]=new RegExp(/(^(?:.|\r|\n)*?)/.source+o.match[r].source.replace(/\\(\d+)/g,q));o.match.globalPOS=p;var s=function(a,b){a=Array.prototype.slice.call(a,0);if(b){b.push.apply(b,a);return b}return a};try{Array.prototype.slice.call(c.documentElement.childNodes,0)[0].nodeType}catch(t){s=function(a,b){var c=0,d=b||[];if(g.call(a)==="[object Array]")Array.prototype.push.apply(d,a);else if(typeof a.length=="number")for(var e=a.length;c<e;c++)d.push(a[c]);else for(;a[c];c++)d.push(a[c]);return d}}var u,v;c.documentElement.compareDocumentPosition?u=function(a,b){if(a===b){h=!0;return 0}if(!a.compareDocumentPosition||!b.compareDocumentPosition)return a.compareDocumentPosition?-1:1;return a.compareDocumentPosition(b)&4?-1:1}:(u=function(a,b){if(a===b){h=!0;return 0}if(a.sourceIndex&&b.sourceIndex)return a.sourceIndex-b.sourceIndex;var c,d,e=[],f=[],g=a.parentNode,i=b.parentNode,j=g;if(g===i)return v(a,b);if(!g)return-1;if(!i)return 1;while(j)e.unshift(j),j=j.parentNode;j=i;while(j)f.unshift(j),j=j.parentNode;c=e.length,d=f.length;for(var k=0;k<c&&k<d;k++)if(e[k]!==f[k])return v(e[k],f[k]);return k===c?v(a,f[k],-1):v(e[k],b,1)},v=function(a,b,c){if(a===b)return c;var d=a.nextSibling;while(d){if(d===b)return-1;d=d.nextSibling}return 1}),function(){var a=c.createElement("div"),d="script"+(new Date).getTime(),e=c.documentElement;a.innerHTML="<a name='"+d+"'/>",e.insertBefore(a,e.firstChild),c.getElementById(d)&&(o.find.ID=function(a,c,d){if(typeof c.getElementById!="undefined"&&!d){var e=c.getElementById(a[1]);return e?e.id===a[1]||typeof e.getAttributeNode!="undefined"&&e.getAttributeNode("id").nodeValue===a[1]?[e]:b:[]}},o.filter.ID=function(a,b){var c=typeof a.getAttributeNode!="undefined"&&a.getAttributeNode("id");return a.nodeType===1&&c&&c.nodeValue===b}),e.removeChild(a),e=a=null}(),function(){var a=c.createElement("div");a.appendChild(c.createComment("")),a.getElementsByTagName("*").length>0&&(o.find.TAG=function(a,b){var c=b.getElementsByTagName(a[1]);if(a[1]==="*"){var d=[];for(var e=0;c[e];e++)c[e].nodeType===1&&d.push(c[e]);c=d}return c}),a.innerHTML="<a href='#'></a>",a.firstChild&&typeof a.firstChild.getAttribute!="undefined"&&a.firstChild.getAttribute("href")!=="#"&&(o.attrHandle.href=function(a){return a.getAttribute("href",2)}),a=null}(),c.querySelectorAll&&function(){var a=m,b=c.createElement("div"),d="__sizzle__";b.innerHTML="<p class='TEST'></p>";if(!b.querySelectorAll||b.querySelectorAll(".TEST").length!==0){m=function(b,e,f,g){e=e||c;if(!g&&!m.isXML(e)){var h=/^(\w+$)|^\.([\w\-]+$)|^#([\w\-]+$)/.exec(b);if(h&&(e.nodeType===1||e.nodeType===9)){if(h[1])return s(e.getElementsByTagName(b),f);if(h[2]&&o.find.CLASS&&e.getElementsByClassName)return s(e.getElementsByClassName(h[2]),f)}if(e.nodeType===9){if(b==="body"&&e.body)return s([e.body],f);if(h&&h[3]){var i=e.getElementById(h[3]);if(!i||!i.parentNode)return s([],f);if(i.id===h[3])return s([i],f)}try{return s(e.querySelectorAll(b),f)}catch(j){}}else if(e.nodeType===1&&e.nodeName.toLowerCase()!=="object"){var k=e,l=e.getAttribute("id"),n=l||d,p=e.parentNode,q=/^\s*[+~]/.test(b);l?n=n.replace(/'/g,"\\$&"):e.setAttribute("id",n),q&&p&&(e=e.parentNode);try{if(!q||p)return s(e.querySelectorAll("[id='"+n+"'] "+b),f)}catch(r){}finally{l||k.removeAttribute("id")}}}return a(b,e,f,g)};for(var e in a)m[e]=a[e];b=null}}(),function(){var a=c.documentElement,b=a.matchesSelector||a.mozMatchesSelector||a.webkitMatchesSelector||a.msMatchesSelector;if(b){var d=!b.call(c.createElement("div"),"div"),e=!1;try{b.call(c.documentElement,"[test!='']:sizzle")}catch(f){e=!0}m.matchesSelector=function(a,c){c=c.replace(/\=\s*([^'"\]]*)\s*\]/g,"='$1']");if(!m.isXML(a))try{if(e||!o.match.PSEUDO.test(c)&&!/!=/.test(c)){var f=b.call(a,c);if(f||!d||a.document&&a.document.nodeType!==11)return f}}catch(g){}return m(c,null,null,[a]).length>0}}}(),function(){var a=c.createElement("div");a.innerHTML="<div class='test e'></div><div class='test'></div>";if(!!a.getElementsByClassName&&a.getElementsByClassName("e").length!==0){a.lastChild.className="e";if(a.getElementsByClassName("e").length===1)return;o.order.splice(1,0,"CLASS"),o.find.CLASS=function(a,b,c){if(typeof b.getElementsByClassName!="undefined"&&!c)return b.getElementsByClassName(a[1])},a=null}}(),c.documentElement.contains?m.contains=function(a,b){return a!==b&&(a.contains?a.contains(b):!0)}:c.documentElement.compareDocumentPosition?m.contains=function(a,b){return!!(a.compareDocumentPosition(b)&16)}:m.contains=function(){return!1},m.isXML=function(a){var b=(a?a.ownerDocument||a:0).documentElement;return b?b.nodeName!=="HTML":!1};var y=function(a,b,c){var d,e=[],f="",g=b.nodeType?[b]:b;while(d=o.match.PSEUDO.exec(a))f+=d[0],a=a.replace(o.match.PSEUDO,"");a=o.relative[a]?a+"*":a;for(var h=0,i=g.length;h<i;h++)m(a,g[h],e,c);return m.filter(f,e)};m.attr=f.attr,m.selectors.attrMap={},f.find=m,f.expr=m.selectors,f.expr[":"]=f.expr.filters,f.unique=m.uniqueSort,f.text=m.getText,f.isXMLDoc=m.isXML,f.contains=m.contains}();var L=/Until$/,M=/^(?:parents|prevUntil|prevAll)/,N=/,/,O=/^.[^:#\[\.,]*$/,P=Array.prototype.slice,Q=f.expr.match.globalPOS,R={children:!0,contents:!0,next:!0,prev:!0};f.fn.extend({find:function(a){var b=this,c,d;if(typeof a!="string")return f(a).filter(function(){for(c=0,d=b.length;c<d;c++)if(f.contains(b[c],this))return!0});var e=this.pushStack("","find",a),g,h,i;for(c=0,d=this.length;c<d;c++){g=e.length,f.find(a,this[c],e);if(c>0)for(h=g;h<e.length;h++)for(i=0;i<g;i++)if(e[i]===e[h]){e.splice(h--,1);break}}return e},has:function(a){var b=f(a);return this.filter(function(){for(var a=0,c=b.length;a<c;a++)if(f.contains(this,b[a]))return!0})},not:function(a){return this.pushStack(T(this,a,!1),"not",a)},filter:function(a){return this.pushStack(T(this,a,!0),"filter",a)},is:function(a){return!!a&&(typeof a=="string"?Q.test(a)?f(a,this.context).index(this[0])>=0:f.filter(a,this).length>0:this.filter(a).length>0)},closest:function(a,b){var c=[],d,e,g=this[0];if(f.isArray(a)){var h=1;while(g&&g.ownerDocument&&g!==b){for(d=0;d<a.length;d++)f(g).is(a[d])&&c.push({selector:a[d],elem:g,level:h});g=g.parentNode,h++}return c}var i=Q.test(a)||typeof a!="string"?f(a,b||this.context):0;for(d=0,e=this.length;d<e;d++){g=this[d];while(g){if(i?i.index(g)>-1:f.find.matchesSelector(g,a)){c.push(g);break}g=g.parentNode;if(!g||!g.ownerDocument||g===b||g.nodeType===11)break}}c=c.length>1?f.unique(c):c;return this.pushStack(c,"closest",a)},index:function(a){if(!a)return this[0]&&this[0].parentNode?this.prevAll().length:-1;if(typeof a=="string")return f.inArray(this[0],f(a));return f.inArray(a.jquery?a[0]:a,this)},add:function(a,b){var c=typeof a=="string"?f(a,b):f.makeArray(a&&a.nodeType?[a]:a),d=f.merge(this.get(),c);return this.pushStack(S(c[0])||S(d[0])?d:f.unique(d))},andSelf:function(){return this.add(this.prevObject)}}),f.each({parent:function(a){var b=a.parentNode;return b&&b.nodeType!==11?b:null},parents:function(a){return f.dir(a,"parentNode")},parentsUntil:function(a,b,c){return f.dir(a,"parentNode",c)},next:function(a){return f.nth(a,2,"nextSibling")},prev:function(a){return f.nth(a,2,"previousSibling")},nextAll:function(a){return f.dir(a,"nextSibling")},prevAll:function(a){return f.dir(a,"previousSibling")},nextUntil:function(a,b,c){return f.dir(a,"nextSibling",c)},prevUntil:function(a,b,c){return f.dir(a,"previousSibling",c)},siblings:function(a){return f.sibling((a.parentNode||{}).firstChild,a)},children:function(a){return f.sibling(a.firstChild)},contents:function(a){return f.nodeName(a,"iframe")?a.contentDocument||a.contentWindow.document:f.makeArray(a.childNodes)}},function(a,b){f.fn[a]=function(c,d){var e=f.map(this,b,c);L.test(a)||(d=c),d&&typeof d=="string"&&(e=f.filter(d,e)),e=this.length>1&&!R[a]?f.unique(e):e,(this.length>1||N.test(d))&&M.test(a)&&(e=e.reverse());return this.pushStack(e,a,P.call(arguments).join(","))}}),f.extend({filter:function(a,b,c){c&&(a=":not("+a+")");return b.length===1?f.find.matchesSelector(b[0],a)?[b[0]]:[]:f.find.matches(a,b)},dir:function(a,c,d){var e=[],g=a[c];while(g&&g.nodeType!==9&&(d===b||g.nodeType!==1||!f(g).is(d)))g.nodeType===1&&e.push(g),g=g[c];return e},nth:function(a,b,c,d){b=b||1;var e=0;for(;a;a=a[c])if(a.nodeType===1&&++e===b)break;return a},sibling:function(a,b){var c=[];for(;a;a=a.nextSibling)a.nodeType===1&&a!==b&&c.push(a);return c}});var V="abbr|article|aside|audio|bdi|canvas|data|datalist|details|figcaption|figure|footer|header|hgroup|mark|meter|nav|output|progress|section|summary|time|video",W=/ jQuery\d+="(?:\d+|null)"/g,X=/^\s+/,Y=/<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/ig,Z=/<([\w:]+)/,$=/<tbody/i,_=/<|&#?\w+;/,ba=/<(?:script|style)/i,bb=/<(?:script|object|embed|option|style)/i,bc=new RegExp("<(?:"+V+")[\\s/>]","i"),bd=/checked\s*(?:[^=]|=\s*.checked.)/i,be=/\/(java|ecma)script/i,bf=/^\s*<!(?:\[CDATA\[|\-\-)/,bg={option:[1,"<select multiple='multiple'>","</select>"],legend:[1,"<fieldset>","</fieldset>"],thead:[1,"<table>","</table>"],tr:[2,"<table><tbody>","</tbody></table>"],td:[3,"<table><tbody><tr>","</tr></tbody></table>"],col:[2,"<table><tbody></tbody><colgroup>","</colgroup></table>"],area:[1,"<map>","</map>"],_default:[0,"",""]},bh=U(c);bg.optgroup=bg.option,bg.tbody=bg.tfoot=bg.colgroup=bg.caption=bg.thead,bg.th=bg.td,f.support.htmlSerialize||(bg._default=[1,"div<div>","</div>"]),f.fn.extend({text:function(a){return f.access(this,function(a){return a===b?f.text(this):this.empty().append((this[0]&&this[0].ownerDocument||c).createTextNode(a))},null,a,arguments.length)},wrapAll:function(a){if(f.isFunction(a))return this.each(function(b){f(this).wrapAll(a.call(this,b))});if(this[0]){var b=f(a,this[0].ownerDocument).eq(0).clone(!0);this[0].parentNode&&b.insertBefore(this[0]),b.map(function(){var a=this;while(a.firstChild&&a.firstChild.nodeType===1)a=a.firstChild;return a}).append(this)}return this},wrapInner:function(a){if(f.isFunction(a))return this.each(function(b){f(this).wrapInner(a.call(this,b))});return this.each(function(){var b=f(this),c=b.contents();c.length?c.wrapAll(a):b.append(a)})},wrap:function(a){var b=f.isFunction(a);return this.each(function(c){f(this).wrapAll(b?a.call(this,c):a)})},unwrap:function(){return this.parent().each(function(){f.nodeName(this,"body")||f(this).replaceWith(this.childNodes)}).end()},append:function(){return this.domManip(arguments,!0,function(a){this.nodeType===1&&this.appendChild(a)})},prepend:function(){return this.domManip(arguments,!0,function(a){this.nodeType===1&&this.insertBefore(a,this.firstChild)})},before:function(){if(this[0]&&this[0].parentNode)return this.domManip(arguments,!1,function(a){this.parentNode.insertBefore(a,this)});if(arguments.length){var a=f
    +-.clean(arguments);a.push.apply(a,this.toArray());return this.pushStack(a,"before",arguments)}},after:function(){if(this[0]&&this[0].parentNode)return this.domManip(arguments,!1,function(a){this.parentNode.insertBefore(a,this.nextSibling)});if(arguments.length){var a=this.pushStack(this,"after",arguments);a.push.apply(a,f.clean(arguments));return a}},remove:function(a,b){for(var c=0,d;(d=this[c])!=null;c++)if(!a||f.filter(a,[d]).length)!b&&d.nodeType===1&&(f.cleanData(d.getElementsByTagName("*")),f.cleanData([d])),d.parentNode&&d.parentNode.removeChild(d);return this},empty:function(){for(var a=0,b;(b=this[a])!=null;a++){b.nodeType===1&&f.cleanData(b.getElementsByTagName("*"));while(b.firstChild)b.removeChild(b.firstChild)}return this},clone:function(a,b){a=a==null?!1:a,b=b==null?a:b;return this.map(function(){return f.clone(this,a,b)})},html:function(a){return f.access(this,function(a){var c=this[0]||{},d=0,e=this.length;if(a===b)return c.nodeType===1?c.innerHTML.replace(W,""):null;if(typeof a=="string"&&!ba.test(a)&&(f.support.leadingWhitespace||!X.test(a))&&!bg[(Z.exec(a)||["",""])[1].toLowerCase()]){a=a.replace(Y,"<$1></$2>");try{for(;d<e;d++)c=this[d]||{},c.nodeType===1&&(f.cleanData(c.getElementsByTagName("*")),c.innerHTML=a);c=0}catch(g){}}c&&this.empty().append(a)},null,a,arguments.length)},replaceWith:function(a){if(this[0]&&this[0].parentNode){if(f.isFunction(a))return this.each(function(b){var c=f(this),d=c.html();c.replaceWith(a.call(this,b,d))});typeof a!="string"&&(a=f(a).detach());return this.each(function(){var b=this.nextSibling,c=this.parentNode;f(this).remove(),b?f(b).before(a):f(c).append(a)})}return this.length?this.pushStack(f(f.isFunction(a)?a():a),"replaceWith",a):this},detach:function(a){return this.remove(a,!0)},domManip:function(a,c,d){var e,g,h,i,j=a[0],k=[];if(!f.support.checkClone&&arguments.length===3&&typeof j=="string"&&bd.test(j))return this.each(function(){f(this).domManip(a,c,d,!0)});if(f.isFunction(j))return this.each(function(e){var g=f(this);a[0]=j.call(this,e,c?g.html():b),g.domManip(a,c,d)});if(this[0]){i=j&&j.parentNode,f.support.parentNode&&i&&i.nodeType===11&&i.childNodes.length===this.length?e={fragment:i}:e=f.buildFragment(a,this,k),h=e.fragment,h.childNodes.length===1?g=h=h.firstChild:g=h.firstChild;if(g){c=c&&f.nodeName(g,"tr");for(var l=0,m=this.length,n=m-1;l<m;l++)d.call(c?bi(this[l],g):this[l],e.cacheable||m>1&&l<n?f.clone(h,!0,!0):h)}k.length&&f.each(k,function(a,b){b.src?f.ajax({type:"GET",global:!1,url:b.src,async:!1,dataType:"script"}):f.globalEval((b.text||b.textContent||b.innerHTML||"").replace(bf,"/*$0*/")),b.parentNode&&b.parentNode.removeChild(b)})}return this}}),f.buildFragment=function(a,b,d){var e,g,h,i,j=a[0];b&&b[0]&&(i=b[0].ownerDocument||b[0]),i.createDocumentFragment||(i=c),a.length===1&&typeof j=="string"&&j.length<512&&i===c&&j.charAt(0)==="<"&&!bb.test(j)&&(f.support.checkClone||!bd.test(j))&&(f.support.html5Clone||!bc.test(j))&&(g=!0,h=f.fragments[j],h&&h!==1&&(e=h)),e||(e=i.createDocumentFragment(),f.clean(a,i,e,d)),g&&(f.fragments[j]=h?e:1);return{fragment:e,cacheable:g}},f.fragments={},f.each({appendTo:"append",prependTo:"prepend",insertBefore:"before",insertAfter:"after",replaceAll:"replaceWith"},function(a,b){f.fn[a]=function(c){var d=[],e=f(c),g=this.length===1&&this[0].parentNode;if(g&&g.nodeType===11&&g.childNodes.length===1&&e.length===1){e[b](this[0]);return this}for(var h=0,i=e.length;h<i;h++){var j=(h>0?this.clone(!0):this).get();f(e[h])[b](j),d=d.concat(j)}return this.pushStack(d,a,e.selector)}}),f.extend({clone:function(a,b,c){var d,e,g,h=f.support.html5Clone||f.isXMLDoc(a)||!bc.test("<"+a.nodeName+">")?a.cloneNode(!0):bo(a);if((!f.support.noCloneEvent||!f.support.noCloneChecked)&&(a.nodeType===1||a.nodeType===11)&&!f.isXMLDoc(a)){bk(a,h),d=bl(a),e=bl(h);for(g=0;d[g];++g)e[g]&&bk(d[g],e[g])}if(b){bj(a,h);if(c){d=bl(a),e=bl(h);for(g=0;d[g];++g)bj(d[g],e[g])}}d=e=null;return h},clean:function(a,b,d,e){var g,h,i,j=[];b=b||c,typeof b.createElement=="undefined"&&(b=b.ownerDocument||b[0]&&b[0].ownerDocument||c);for(var k=0,l;(l=a[k])!=null;k++){typeof l=="number"&&(l+="");if(!l)continue;if(typeof l=="string")if(!_.test(l))l=b.createTextNode(l);else{l=l.replace(Y,"<$1></$2>");var m=(Z.exec(l)||["",""])[1].toLowerCase(),n=bg[m]||bg._default,o=n[0],p=b.createElement("div"),q=bh.childNodes,r;b===c?bh.appendChild(p):U(b).appendChild(p),p.innerHTML=n[1]+l+n[2];while(o--)p=p.lastChild;if(!f.support.tbody){var s=$.test(l),t=m==="table"&&!s?p.firstChild&&p.firstChild.childNodes:n[1]==="<table>"&&!s?p.childNodes:[];for(i=t.length-1;i>=0;--i)f.nodeName(t[i],"tbody")&&!t[i].childNodes.length&&t[i].parentNode.removeChild(t[i])}!f.support.leadingWhitespace&&X.test(l)&&p.insertBefore(b.createTextNode(X.exec(l)[0]),p.firstChild),l=p.childNodes,p&&(p.parentNode.removeChild(p),q.length>0&&(r=q[q.length-1],r&&r.parentNode&&r.parentNode.removeChild(r)))}var u;if(!f.support.appendChecked)if(l[0]&&typeof (u=l.length)=="number")for(i=0;i<u;i++)bn(l[i]);else bn(l);l.nodeType?j.push(l):j=f.merge(j,l)}if(d){g=function(a){return!a.type||be.test(a.type)};for(k=0;j[k];k++){h=j[k];if(e&&f.nodeName(h,"script")&&(!h.type||be.test(h.type)))e.push(h.parentNode?h.parentNode.removeChild(h):h);else{if(h.nodeType===1){var v=f.grep(h.getElementsByTagName("script"),g);j.splice.apply(j,[k+1,0].concat(v))}d.appendChild(h)}}}return j},cleanData:function(a){var b,c,d=f.cache,e=f.event.special,g=f.support.deleteExpando;for(var h=0,i;(i=a[h])!=null;h++){if(i.nodeName&&f.noData[i.nodeName.toLowerCase()])continue;c=i[f.expando];if(c){b=d[c];if(b&&b.events){for(var j in b.events)e[j]?f.event.remove(i,j):f.removeEvent(i,j,b.handle);b.handle&&(b.handle.elem=null)}g?delete i[f.expando]:i.removeAttribute&&i.removeAttribute(f.expando),delete d[c]}}}});var bp=/alpha\([^)]*\)/i,bq=/opacity=([^)]*)/,br=/([A-Z]|^ms)/g,bs=/^[\-+]?(?:\d*\.)?\d+$/i,bt=/^-?(?:\d*\.)?\d+(?!px)[^\d\s]+$/i,bu=/^([\-+])=([\-+.\de]+)/,bv=/^margin/,bw={position:"absolute",visibility:"hidden",display:"block"},bx=["Top","Right","Bottom","Left"],by,bz,bA;f.fn.css=function(a,c){return f.access(this,function(a,c,d){return d!==b?f.style(a,c,d):f.css(a,c)},a,c,arguments.length>1)},f.extend({cssHooks:{opacity:{get:function(a,b){if(b){var c=by(a,"opacity");return c===""?"1":c}return a.style.opacity}}},cssNumber:{fillOpacity:!0,fontWeight:!0,lineHeight:!0,opacity:!0,orphans:!0,widows:!0,zIndex:!0,zoom:!0},cssProps:{"float":f.support.cssFloat?"cssFloat":"styleFloat"},style:function(a,c,d,e){if(!!a&&a.nodeType!==3&&a.nodeType!==8&&!!a.style){var g,h,i=f.camelCase(c),j=a.style,k=f.cssHooks[i];c=f.cssProps[i]||i;if(d===b){if(k&&"get"in k&&(g=k.get(a,!1,e))!==b)return g;return j[c]}h=typeof d,h==="string"&&(g=bu.exec(d))&&(d=+(g[1]+1)*+g[2]+parseFloat(f.css(a,c)),h="number");if(d==null||h==="number"&&isNaN(d))return;h==="number"&&!f.cssNumber[i]&&(d+="px");if(!k||!("set"in k)||(d=k.set(a,d))!==b)try{j[c]=d}catch(l){}}},css:function(a,c,d){var e,g;c=f.camelCase(c),g=f.cssHooks[c],c=f.cssProps[c]||c,c==="cssFloat"&&(c="float");if(g&&"get"in g&&(e=g.get(a,!0,d))!==b)return e;if(by)return by(a,c)},swap:function(a,b,c){var d={},e,f;for(f in b)d[f]=a.style[f],a.style[f]=b[f];e=c.call(a);for(f in b)a.style[f]=d[f];return e}}),f.curCSS=f.css,c.defaultView&&c.defaultView.getComputedStyle&&(bz=function(a,b){var c,d,e,g,h=a.style;b=b.replace(br,"-$1").toLowerCase(),(d=a.ownerDocument.defaultView)&&(e=d.getComputedStyle(a,null))&&(c=e.getPropertyValue(b),c===""&&!f.contains(a.ownerDocument.documentElement,a)&&(c=f.style(a,b))),!f.support.pixelMargin&&e&&bv.test(b)&&bt.test(c)&&(g=h.width,h.width=c,c=e.width,h.width=g);return c}),c.documentElement.currentStyle&&(bA=function(a,b){var c,d,e,f=a.currentStyle&&a.currentStyle[b],g=a.style;f==null&&g&&(e=g[b])&&(f=e),bt.test(f)&&(c=g.left,d=a.runtimeStyle&&a.runtimeStyle.left,d&&(a.runtimeStyle.left=a.currentStyle.left),g.left=b==="fontSize"?"1em":f,f=g.pixelLeft+"px",g.left=c,d&&(a.runtimeStyle.left=d));return f===""?"auto":f}),by=bz||bA,f.each(["height","width"],function(a,b){f.cssHooks[b]={get:function(a,c,d){if(c)return a.offsetWidth!==0?bB(a,b,d):f.swap(a,bw,function(){return bB(a,b,d)})},set:function(a,b){return bs.test(b)?b+"px":b}}}),f.support.opacity||(f.cssHooks.opacity={get:function(a,b){return bq.test((b&&a.currentStyle?a.currentStyle.filter:a.style.filter)||"")?parseFloat(RegExp.$1)/100+"":b?"1":""},set:function(a,b){var c=a.style,d=a.currentStyle,e=f.isNumeric(b)?"alpha(opacity="+b*100+")":"",g=d&&d.filter||c.filter||"";c.zoom=1;if(b>=1&&f.trim(g.replace(bp,""))===""){c.removeAttribute("filter");if(d&&!d.filter)return}c.filter=bp.test(g)?g.replace(bp,e):g+" "+e}}),f(function(){f.support.reliableMarginRight||(f.cssHooks.marginRight={get:function(a,b){return f.swap(a,{display:"inline-block"},function(){return b?by(a,"margin-right"):a.style.marginRight})}})}),f.expr&&f.expr.filters&&(f.expr.filters.hidden=function(a){var b=a.offsetWidth,c=a.offsetHeight;return b===0&&c===0||!f.support.reliableHiddenOffsets&&(a.style&&a.style.display||f.css(a,"display"))==="none"},f.expr.filters.visible=function(a){return!f.expr.filters.hidden(a)}),f.each({margin:"",padding:"",border:"Width"},function(a,b){f.cssHooks[a+b]={expand:function(c){var d,e=typeof c=="string"?c.split(" "):[c],f={};for(d=0;d<4;d++)f[a+bx[d]+b]=e[d]||e[d-2]||e[0];return f}}});var bC=/%20/g,bD=/\[\]$/,bE=/\r?\n/g,bF=/#.*$/,bG=/^(.*?):[ \t]*([^\r\n]*)\r?$/mg,bH=/^(?:color|date|datetime|datetime-local|email|hidden|month|number|password|range|search|tel|text|time|url|week)$/i,bI=/^(?:about|app|app\-storage|.+\-extension|file|res|widget):$/,bJ=/^(?:GET|HEAD)$/,bK=/^\/\//,bL=/\?/,bM=/<script\b[^<]*(?:(?!<\/script>)<[^<]*)*<\/script>/gi,bN=/^(?:select|textarea)/i,bO=/\s+/,bP=/([?&])_=[^&]*/,bQ=/^([\w\+\.\-]+:)(?:\/\/([^\/?#:]*)(?::(\d+))?)?/,bR=f.fn.load,bS={},bT={},bU,bV,bW=["*/"]+["*"];try{bU=e.href}catch(bX){bU=c.createElement("a"),bU.href="",bU=bU.href}bV=bQ.exec(bU.toLowerCase())||[],f.fn.extend({load:function(a,c,d){if(typeof a!="string"&&bR)return bR.apply(this,arguments);if(!this.length)return this;var e=a.indexOf(" ");if(e>=0){var g=a.slice(e,a.length);a=a.slice(0,e)}var h="GET";c&&(f.isFunction(c)?(d=c,c=b):typeof c=="object"&&(c=f.param(c,f.ajaxSettings.traditional),h="POST"));var i=this;f.ajax({url:a,type:h,dataType:"html",data:c,complete:function(a,b,c){c=a.responseText,a.isResolved()&&(a.done(function(a){c=a}),i.html(g?f("<div>").append(c.replace(bM,"")).find(g):c)),d&&i.each(d,[c,b,a])}});return this},serialize:function(){return f.param(this.serializeArray())},serializeArray:function(){return this.map(function(){return this.elements?f.makeArray(this.elements):this}).filter(function(){return this.name&&!this.disabled&&(this.checked||bN.test(this.nodeName)||bH.test(this.type))}).map(function(a,b){var c=f(this).val();return c==null?null:f.isArray(c)?f.map(c,function(a,c){return{name:b.name,value:a.replace(bE,"\r\n")}}):{name:b.name,value:c.replace(bE,"\r\n")}}).get()}}),f.each("ajaxStart ajaxStop ajaxComplete ajaxError ajaxSuccess ajaxSend".split(" "),function(a,b){f.fn[b]=function(a){return this.on(b,a)}}),f.each(["get","post"],function(a,c){f[c]=function(a,d,e,g){f.isFunction(d)&&(g=g||e,e=d,d=b);return f.ajax({type:c,url:a,data:d,success:e,dataType:g})}}),f.extend({getScript:function(a,c){return f.get(a,b,c,"script")},getJSON:function(a,b,c){return f.get(a,b,c,"json")},ajaxSetup:function(a,b){b?b$(a,f.ajaxSettings):(b=a,a=f.ajaxSettings),b$(a,b);return a},ajaxSettings:{url:bU,isLocal:bI.test(bV[1]),global:!0,type:"GET",contentType:"application/x-www-form-urlencoded; charset=UTF-8",processData:!0,async:!0,accepts:{xml:"application/xml, text/xml",html:"text/html",text:"text/plain",json:"application/json, text/javascript","*":bW},contents:{xml:/xml/,html:/html/,json:/json/},responseFields:{xml:"responseXML",text:"responseText"},converters:{"* text":a.String,"text html":!0,"text json":f.parseJSON,"text xml":f.parseXML},flatOptions:{context:!0,url:!0}},ajaxPrefilter:bY(bS),ajaxTransport:bY(bT),ajax:function(a,c){function w(a,c,l,m){if(s!==2){s=2,q&&clearTimeout(q),p=b,n=m||"",v.readyState=a>0?4:0;var o,r,u,w=c,x=l?ca(d,v,l):b,y,z;if(a>=200&&a<300||a===304){if(d.ifModified){if(y=v.getResponseHeader("Last-Modified"))f.lastModified[k]=y;if(z=v.getResponseHeader("Etag"))f.etag[k]=z}if(a===304)w="notmodified",o=!0;else try{r=cb(d,x),w="success",o=!0}catch(A){w="parsererror",u=A}}else{u=w;if(!w||a)w="error",a<0&&(a=0)}v.status=a,v.statusText=""+(c||w),o?h.resolveWith(e,[r,w,v]):h.rejectWith(e,[v,w,u]),v.statusCode(j),j=b,t&&g.trigger("ajax"+(o?"Success":"Error"),[v,d,o?r:u]),i.fireWith(e,[v,w]),t&&(g.trigger("ajaxComplete",[v,d]),--f.active||f.event.trigger("ajaxStop"))}}typeof a=="object"&&(c=a,a=b),c=c||{};var d=f.ajaxSetup({},c),e=d.context||d,g=e!==d&&(e.nodeType||e instanceof f)?f(e):f.event,h=f.Deferred(),i=f.Callbacks("once memory"),j=d.statusCode||{},k,l={},m={},n,o,p,q,r,s=0,t,u,v={readyState:0,setRequestHeader:function(a,b){if(!s){var c=a.toLowerCase();a=m[c]=m[c]||a,l[a]=b}return this},getAllResponseHeaders:function(){return s===2?n:null},getResponseHeader:function(a){var c;if(s===2){if(!o){o={};while(c=bG.exec(n))o[c[1].toLowerCase()]=c[2]}c=o[a.toLowerCase()]}return c===b?null:c},overrideMimeType:function(a){s||(d.mimeType=a);return this},abort:function(a){a=a||"abort",p&&p.abort(a),w(0,a);return this}};h.promise(v),v.success=v.done,v.error=v.fail,v.complete=i.add,v.statusCode=function(a){if(a){var b;if(s<2)for(b in a)j[b]=[j[b],a[b]];else b=a[v.status],v.then(b,b)}return this},d.url=((a||d.url)+"").replace(bF,"").replace(bK,bV[1]+"//"),d.dataTypes=f.trim(d.dataType||"*").toLowerCase().split(bO),d.crossDomain==null&&(r=bQ.exec(d.url.toLowerCase()),d.crossDomain=!(!r||r[1]==bV[1]&&r[2]==bV[2]&&(r[3]||(r[1]==="http:"?80:443))==(bV[3]||(bV[1]==="http:"?80:443)))),d.data&&d.processData&&typeof d.data!="string"&&(d.data=f.param(d.data,d.traditional)),bZ(bS,d,c,v);if(s===2)return!1;t=d.global,d.type=d.type.toUpperCase(),d.hasContent=!bJ.test(d.type),t&&f.active++===0&&f.event.trigger("ajaxStart");if(!d.hasContent){d.data&&(d.url+=(bL.test(d.url)?"&":"?")+d.data,delete d.data),k=d.url;if(d.cache===!1){var x=f.now(),y=d.url.replace(bP,"$1_="+x);d.url=y+(y===d.url?(bL.test(d.url)?"&":"?")+"_="+x:"")}}(d.data&&d.hasContent&&d.contentType!==!1||c.contentType)&&v.setRequestHeader("Content-Type",d.contentType),d.ifModified&&(k=k||d.url,f.lastModified[k]&&v.setRequestHeader("If-Modified-Since",f.lastModified[k]),f.etag[k]&&v.setRequestHeader("If-None-Match",f.etag[k])),v.setRequestHeader("Accept",d.dataTypes[0]&&d.accepts[d.dataTypes[0]]?d.accepts[d.dataTypes[0]]+(d.dataTypes[0]!=="*"?", "+bW+"; q=0.01":""):d.accepts["*"]);for(u in d.headers)v.setRequestHeader(u,d.headers[u]);if(d.beforeSend&&(d.beforeSend.call(e,v,d)===!1||s===2)){v.abort();return!1}for(u in{success:1,error:1,complete:1})v[u](d[u]);p=bZ(bT,d,c,v);if(!p)w(-1,"No Transport");else{v.readyState=1,t&&g.trigger("ajaxSend",[v,d]),d.async&&d.timeout>0&&(q=setTimeout(function(){v.abort("timeout")},d.timeout));try{s=1,p.send(l,w)}catch(z){if(s<2)w(-1,z);else throw z}}return v},param:function(a,c){var d=[],e=function(a,b){b=f.isFunction(b)?b():b,d[d.length]=encodeURIComponent(a)+"="+encodeURIComponent(b)};c===b&&(c=f.ajaxSettings.traditional);if(f.isArray(a)||a.jquery&&!f.isPlainObject(a))f.each(a,function(){e(this.name,this.value)});else for(var g in a)b_(g,a[g],c,e);return d.join("&").replace(bC,"+")}}),f.extend({active:0,lastModified:{},etag:{}});var cc=f.now(),cd=/(\=)\?(&|$)|\?\?/i;f.ajaxSetup({jsonp:"callback",jsonpCallback:function(){return f.expando+"_"+cc++}}),f.ajaxPrefilter("json jsonp",function(b,c,d){var e=typeof b.data=="string"&&/^application\/x\-www\-form\-urlencoded/.test(b.contentType);if(b.dataTypes[0]==="jsonp"||b.jsonp!==!1&&(cd.test(b.url)||e&&cd.test(b.data))){var g,h=b.jsonpCallback=f.isFunction(b.jsonpCallback)?b.jsonpCallback():b.jsonpCallback,i=a[h],j=b.url,k=b.data,l="$1"+h+"$2";b.jsonp!==!1&&(j=j.replace(cd,l),b.url===j&&(e&&(k=k.replace(cd,l)),b.data===k&&(j+=(/\?/.test(j)?"&":"?")+b.jsonp+"="+h))),b.url=j,b.data=k,a[h]=function(a){g=[a]},d.always(function(){a[h]=i,g&&f.isFunction(i)&&a[h](g[0])}),b.converters["script json"]=function(){g||f.error(h+" was not called");return g[0]},b.dataTypes[0]="json";return"script"}}),f.ajaxSetup({accepts:{script:"text/javascript, application/javascript, application/ecmascript, application/x-ecmascript"},contents:{script:/javascript|ecmascript/},converters:{"text script":function(a){f.globalEval(a);return a}}}),f.ajaxPrefilter("script",function(a){a.cache===b&&(a.cache=!1),a.crossDomain&&(a.type="GET",a.global=!1)}),f.ajaxTransport("script",function(a){if(a.crossDomain){var d,e=c.head||c.getElementsByTagName("head")[0]||c.documentElement;return{send:function(f,g){d=c.createElement("script"),d.async="async",a.scriptCharset&&(d.charset=a.scriptCharset),d.src=a.url,d.onload=d.onreadystatechange=function(a,c){if(c||!d.readyState||/loaded|complete/.test(d.readyState))d.onload=d.onreadystatechange=null,e&&d.parentNode&&e.removeChild(d),d=b,c||g(200,"success")},e.insertBefore(d,e.firstChild)},abort:function(){d&&d.onload(0,1)}}}});var ce=a.ActiveXObject?function(){for(var a in cg)cg[a](0,1)}:!1,cf=0,cg;f.ajaxSettings.xhr=a.ActiveXObject?function(){return!this.isLocal&&ch()||ci()}:ch,function(a){f.extend(f.support,{ajax:!!a,cors:!!a&&"withCredentials"in a})}(f.ajaxSettings.xhr()),f.support.ajax&&f.ajaxTransport(function(c){if(!c.crossDomain||f.support.cors){var d;return{send:function(e,g){var h=c.xhr(),i,j;c.username?h.open(c.type,c.url,c.async,c.username,c.password):h.open(c.type,c.url,c.async);if(c.xhrFields)for(j in c.xhrFields)h[j]=c.xhrFields[j];c.mimeType&&h.overrideMimeType&&h.overrideMimeType(c.mimeType),!c.crossDomain&&!e["X-Requested-With"]&&(e["X-Requested-With"]="XMLHttpRequest");try{for(j in e)h.setRequestHeader(j,e[j])}catch(k){}h.send(c.hasContent&&c.data||null),d=function(a,e){var j,k,l,m,n;try{if(d&&(e||h.readyState===4)){d=b,i&&(h.onreadystatechange=f.noop,ce&&delete cg[i]);if(e)h.readyState!==4&&h.abort();else{j=h.status,l=h.getAllResponseHeaders(),m={},n=h.responseXML,n&&n.documentElement&&(m.xml=n);try{m.text=h.responseText}catch(a){}try{k=h.statusText}catch(o){k=""}!j&&c.isLocal&&!c.crossDomain?j=m.text?200:404:j===1223&&(j=204)}}}catch(p){e||g(-1,p)}m&&g(j,k,m,l)},!c.async||h.readyState===4?d():(i=++cf,ce&&(cg||(cg={},f(a).unload(ce)),cg[i]=d),h.onreadystatechange=d)},abort:function(){d&&d(0,1)}}}});var cj={},ck,cl,cm=/^(?:toggle|show|hide)$/,cn=/^([+\-]=)?([\d+.\-]+)([a-z%]*)$/i,co,cp=[["height","marginTop","marginBottom","paddingTop","paddingBottom"],["width","marginLeft","marginRight","paddingLeft","paddingRight"],["opacity"]],cq;f.fn.extend({show:function(a,b,c){var d,e;if(a||a===0)return this.animate(ct("show",3),a,b,c);for(var g=0,h=this.length;g<h;g++)d=this[g],d.style&&(e=d.style.display,!f._data(d,"olddisplay")&&e==="none"&&(e=d.style.display=""),(e===""&&f.css(d,"display")==="none"||!f.contains(d.ownerDocument.documentElement,d))&&f._data(d,"olddisplay",cu(d.nodeName)));for(g=0;g<h;g++){d=this[g];if(d.style){e=d.style.display;if(e===""||e==="none")d.style.display=f._data(d,"olddisplay")||""}}return this},hide:function(a,b,c){if(a||a===0)return this.animate(ct("hide",3),a,b,c);var d,e,g=0,h=this.length;for(;g<h;g++)d=this[g],d.style&&(e=f.css(d,"display"),e!=="none"&&!f._data(d,"olddisplay")&&f._data(d,"olddisplay",e));for(g=0;g<h;g++)this[g].style&&(this[g].style.display="none");return this},_toggle:f.fn.toggle,toggle:function(a,b,c){var d=typeof a=="boolean";f.isFunction(a)&&f.isFunction(b)?this._toggle.apply(this,arguments):a==null||d?this.each(function(){var b=d?a:f(this).is(":hidden");f(this)[b?"show":"hide"]()}):this.animate(ct("toggle",3),a,b,c);return this},fadeTo:function(a,b,c,d){return this.filter(":hidden").css("opacity",0).show().end().animate({opacity:b},a,c,d)},animate:function(a,b,c,d){function g(){e.queue===!1&&f._mark(this);var b=f.extend({},e),c=this.nodeType===1,d=c&&f(this).is(":hidden"),g,h,i,j,k,l,m,n,o,p,q;b.animatedProperties={};for(i in a){g=f.camelCase(i),i!==g&&(a[g]=a[i],delete a[i]);if((k=f.cssHooks[g])&&"expand"in k){l=k.expand(a[g]),delete a[g];for(i in l)i in a||(a[i]=l[i])}}for(g in a){h=a[g],f.isArray(h)?(b.animatedProperties[g]=h[1],h=a[g]=h[0]):b.animatedProperties[g]=b.specialEasing&&b.specialEasing[g]||b.easing||"swing";if(h==="hide"&&d||h==="show"&&!d)return b.complete.call(this);c&&(g==="height"||g==="width")&&(b.overflow=[this.style.overflow,this.style.overflowX,this.style.overflowY],f.css(this,"display")==="inline"&&f.css(this,"float")==="none"&&(!f.support.inlineBlockNeedsLayout||cu(this.nodeName)==="inline"?this.style.display="inline-block":this.style.zoom=1))}b.overflow!=null&&(this.style.overflow="hidden");for(i in a)j=new f.fx(this,b,i),h=a[i],cm.test(h)?(q=f._data(this,"toggle"+i)||(h==="toggle"?d?"show":"hide":0),q?(f._data(this,"toggle"+i,q==="show"?"hide":"show"),j[q]()):j[h]()):(m=cn.exec(h),n=j.cur(),m?(o=parseFloat(m[2]),p=m[3]||(f.cssNumber[i]?"":"px"),p!=="px"&&(f.style(this,i,(o||1)+p),n=(o||1)/j.cur()*n,f.style(this,i,n+p)),m[1]&&(o=(m[1]==="-="?-1:1)*o+n),j.custom(n,o,p)):j.custom(n,h,""));return!0}var e=f.speed(b,c,d);if(f.isEmptyObject(a))return this.each(e.complete,[!1]);a=f.extend({},a);return e.queue===!1?this.each(g):this.queue(e.queue,g)},stop:function(a,c,d){typeof a!="string"&&(d=c,c=a,a=b),c&&a!==!1&&this.queue(a||"fx",[]);return this.each(function(){function h(a,b,c){var e=b[c];f.removeData(a,c,!0),e.stop(d)}var b,c=!1,e=f.timers,g=f._data(this);d||f._unmark(!0,this);if(a==null)for(b in g)g[b]&&g[b].stop&&b.indexOf(".run")===b.length-4&&h(this,g,b);else g[b=a+".run"]&&g[b].stop&&h(this,g,b);for(b=e.length;b--;)e[b].elem===this&&(a==null||e[b].queue===a)&&(d?e[b](!0):e[b].saveState(),c=!0,e.splice(b,1));(!d||!c)&&f.dequeue(this,a)})}}),f.each({slideDown:ct("show",1),slideUp:ct("hide",1),slideToggle:ct("toggle",1),fadeIn:{opacity:"show"},fadeOut:{opacity:"hide"},fadeToggle:{opacity:"toggle"}},function(a,b){f.fn[a]=function(a,c,d){return this.animate(b,a,c,d)}}),f.extend({speed:function(a,b,c){var d=a&&typeof a=="object"?f.extend({},a):{complete:c||!c&&b||f.isFunction(a)&&a,duration:a,easing:c&&b||b&&!f.isFunction(b)&&b};d.duration=f.fx.off?0:typeof d.duration=="number"?d.duration:d.duration in f.fx.speeds?f.fx.speeds[d.duration]:f.fx.speeds._default;if(d.queue==null||d.queue===!0)d.queue="fx";d.old=d.complete,d.complete=function(a){f.isFunction(d.old)&&d.old.call(this),d.queue?f.dequeue(this,d.queue):a!==!1&&f._unmark(this)};return d},easing:{linear:function(a){return a},swing:function(a){return-Math.cos(a*Math.PI)/2+.5}},timers:[],fx:function(a,b,c){this.options=b,this.elem=a,this.prop=c,b.orig=b.orig||{}}}),f.fx.prototype={update:function(){this.options.step&&this.options.step.call(this.elem,this.now,this),(f.fx.step[this.prop]||f.fx.step._default)(this)},cur:function(){if(this.elem[this.prop]!=null&&(!this.elem.style||this.elem.style[this.prop]==null))return this.elem[this.prop];var a,b=f.css(this.elem,this.prop);return isNaN(a=parseFloat(b))?!b||b==="auto"?0:b:a},custom:function(a,c,d){function h(a){return e.step(a)}var e=this,g=f.fx;this.startTime=cq||cr(),this.end=c,this.now=this.start=a,this.pos=this.state=0,this.unit=d||this.unit||(f.cssNumber[this.prop]?"":"px"),h.queue=this.options.queue,h.elem=this.elem,h.saveState=function(){f._data(e.elem,"fxshow"+e.prop)===b&&(e.options.hide?f._data(e.elem,"fxshow"+e.prop,e.start):e.options.show&&f._data(e.elem,"fxshow"+e.prop,e.end))},h()&&f.timers.push(h)&&!co&&(co=setInterval(g.tick,g.interval))},show:function(){var a=f._data(this.elem,"fxshow"+this.prop);this.options.orig[this.prop]=a||f.style(this.elem,this.prop),this.options.show=!0,a!==b?this.custom(this.cur(),a):this.custom(this.prop==="width"||this.prop==="height"?1:0,this.cur()),f(this.elem).show()},hide:function(){this.options.orig[this.prop]=f._data(this.elem,"fxshow"+this.prop)||f.style(this.elem,this.prop),this.options.hide=!0,this.custom(this.cur(),0)},step:function(a){var b,c,d,e=cq||cr(),g=!0,h=this.elem,i=this.options;if(a||e>=i.duration+this.startTime){this.now=this.end,this.pos=this.state=1,this.update(),i.animatedProperties[this.prop]=!0;for(b in i.animatedProperties)i.animatedProperties[b]!==!0&&(g=!1);if(g){i.overflow!=null&&!f.support.shrinkWrapBlocks&&f.each(["","X","Y"],function(a,b){h.style["overflow"+b]=i.overflow[a]}),i.hide&&f(h).hide();if(i.hide||i.show)for(b in i.animatedProperties)f.style(h,b,i.orig[b]),f.removeData(h,"fxshow"+b,!0),f.removeData(h,"toggle"+b,!0);d=i.complete,d&&(i.complete=!1,d.call(h))}return!1}i.duration==Infinity?this.now=e:(c=e-this.startTime,this.state=c/i.duration,this.pos=f.easing[i.animatedProperties[this.prop]](this.state,c,0,1,i.duration),this.now=this.start+(this.end-this.start)*this.pos),this.update();return!0}},f.extend(f.fx,{tick:function(){var a,b=f.timers,c=0;for(;c<b.length;c++)a=b[c],!a()&&b[c]===a&&b.splice(c--,1);b.length||f.fx.stop()},interval:13,stop:function(){clearInterval(co),co=null},speeds:{slow:600,fast:200,_default:400},step:{opacity:function(a){f.style(a.elem,"opacity",a.now)},_default:function(a){a.elem.style&&a.elem.style[a.prop]!=null?a.elem.style[a.prop]=a.now+a.unit:a.elem[a.prop]=a.now}}}),f.each(cp.concat.apply([],cp),function(a,b){b.indexOf("margin")&&(f.fx.step[b]=function(a){f.style(a.elem,b,Math.max(0,a.now)+a.unit)})}),f.expr&&f.expr.filters&&(f.expr.filters.animated=function(a){return f.grep(f.timers,function(b){return a===b.elem}).length});var cv,cw=/^t(?:able|d|h)$/i,cx=/^(?:body|html)$/i;"getBoundingClientRect"in c.documentElement?cv=function(a,b,c,d){try{d=a.getBoundingClientRect()}catch(e){}if(!d||!f.contains(c,a))return d?{top:d.top,left:d.left}:{top:0,left:0};var g=b.body,h=cy(b),i=c.clientTop||g.clientTop||0,j=c.clientLeft||g.clientLeft||0,k=h.pageYOffset||f.support.boxModel&&c.scrollTop||g.scrollTop,l=h.pageXOffset||f.support.boxModel&&c.scrollLeft||g.scrollLeft,m=d.top+k-i,n=d.left+l-j;return{top:m,left:n}}:cv=function(a,b,c){var d,e=a.offsetParent,g=a,h=b.body,i=b.defaultView,j=i?i.getComputedStyle(a,null):a.currentStyle,k=a.offsetTop,l=a.offsetLeft;while((a=a.parentNode)&&a!==h&&a!==c){if(f.support.fixedPosition&&j.position==="fixed")break;d=i?i.getComputedStyle(a,null):a.currentStyle,k-=a.scrollTop,l-=a.scrollLeft,a===e&&(k+=a.offsetTop,l+=a.offsetLeft,f.support.doesNotAddBorder&&(!f.support.doesAddBorderForTableAndCells||!cw.test(a.nodeName))&&(k+=parseFloat(d.borderTopWidth)||0,l+=parseFloat(d.borderLeftWidth)||0),g=e,e=a.offsetParent),f.support.subtractsBorderForOverflowNotVisible&&d.overflow!=="visible"&&(k+=parseFloat(d.borderTopWidth)||0,l+=parseFloat(d.borderLeftWidth)||0),j=d}if(j.position==="relative"||j.position==="static")k+=h.offsetTop,l+=h.offsetLeft;f.support.fixedPosition&&j.position==="fixed"&&(k+=Math.max(c.scrollTop,h.scrollTop),l+=Math.max(c.scrollLeft,h.scrollLeft));return{top:k,left:l}},f.fn.offset=function(a){if(arguments.length)return a===b?this:this.each(function(b){f.offset.setOffset(this,a,b)});var c=this[0],d=c&&c.ownerDocument;if(!d)return null;if(c===d.body)return f.offset.bodyOffset(c);return cv(c,d,d.documentElement)},f.offset={bodyOffset:function(a){var b=a.offsetTop,c=a.offsetLeft;f.support.doesNotIncludeMarginInBodyOffset&&(b+=parseFloat(f.css(a,"marginTop"))||0,c+=parseFloat(f.css(a,"marginLeft"))||0);return{top:b,left:c}},setOffset:function(a,b,c){var d=f.css(a,"position");d==="static"&&(a.style.position="relative");var e=f(a),g=e.offset(),h=f.css(a,"top"),i=f.css(a,"left"),j=(d==="absolute"||d==="fixed")&&f.inArray("auto",[h,i])>-1,k={},l={},m,n;j?(l=e.position(),m=l.top,n=l.left):(m=parseFloat(h)||0,n=parseFloat(i)||0),f.isFunction(b)&&(b=b.call(a,c,g)),b.top!=null&&(k.top=b.top-g.top+m),b.left!=null&&(k.left=b.left-g.left+n),"using"in b?b.using.call(a,k):e.css(k)}},f.fn.extend({position:function(){if(!this[0])return null;var a=this[0],b=this.offsetParent(),c=this.offset(),d=cx.test(b[0].nodeName)?{top:0,left:0}:b.offset();c.top-=parseFloat(f.css(a,"marginTop"))||0,c.left-=parseFloat(f.css(a,"marginLeft"))||0,d.top+=parseFloat(f.css(b[0],"borderTopWidth"))||0,d.left+=parseFloat(f.css(b[0],"borderLeftWidth"))||0;return{top:c.top-d.top,left:c.left-d.left}},offsetParent:function(){return this.map(function(){var a=this.offsetParent||c.body;while(a&&!cx.test(a.nodeName)&&f.css(a,"position")==="static")a=a.offsetParent;return a})}}),f.each({scrollLeft:"pageXOffset",scrollTop:"pageYOffset"},function(a,c){var d=/Y/.test(c);f.fn[a]=function(e){return f.access(this,function(a,e,g){var h=cy(a);if(g===b)return h?c in h?h[c]:f.support.boxModel&&h.document.documentElement[e]||h.document.body[e]:a[e];h?h.scrollTo(d?f(h).scrollLeft():g,d?g:f(h).scrollTop()):a[e]=g},a,e,arguments.length,null)}}),f.each({Height:"height",Width:"width"},function(a,c){var d="client"+a,e="scroll"+a,g="offset"+a;f.fn["inner"+a]=function(){var a=this[0];return a?a.style?parseFloat(f.css(a,c,"padding")):this[c]():null},f.fn["outer"+a]=function(a){var b=this[0];return b?b.style?parseFloat(f.css(b,c,a?"margin":"border")):this[c]():null},f.fn[c]=function(a){return f.access(this,function(a,c,h){var i,j,k,l;if(f.isWindow(a)){i=a.document,j=i.documentElement[d];return f.support.boxModel&&j||i.body&&i.body[d]||j}if(a.nodeType===9){i=a.documentElement;if(i[d]>=i[e])return i[d];return Math.max(a.body[e],i[e],a.body[g],i[g])}if(h===b){k=f.css(a,c),l=parseFloat(k);return f.isNumeric(l)?l:k}f(a).css(c,h)},c,a,arguments.length,null)}}),a.jQuery=a.$=f,typeof define=="function"&&define.amd&&define.amd.jQuery&&define("jquery",[],function(){return f})})(window);
    +-
    +-//third_party/javascript/jquery_hashchange/jquery.hashchange.js
    +-/**
    +- * @license
    +- * jQuery hashchange 1.0.0
    +- * 
    +- * (based on jquery.history)
    +- *
    +- * Copyright (c) 2008 Chris Leishman (chrisleishman.com)
    +- * Dual licensed under the MIT (MIT-LICENSE.txt)
    +- * and GPL (GPL-LICENSE.txt) licenses.
    +- */
    +-(function($) {
    +-
    +-$.fn.extend({
    +-    hashchange: function(callback) { this.bind('hashchange', callback) },
    +-    openOnClick: function(href) {
    +-		if (href === undefined || href.length == 0)
    +-			href = '#';
    +-		return this.click(function(ev) {
    +-			if (href && href.charAt(0) == '#') {
    +-				// execute load in separate call stack
    +-				window.setTimeout(function() { $.locationHash(href) }, 0);
    +-			} else {
    +-				window.location(href);
    +-			}
    +-			ev.stopPropagation();
    +-			return false;
    +-		});
    +-    }
    +-});
    +-
    +-// IE 8 introduces the hashchange event natively - so nothing more to do
    +-if ($.browser.msie && document.documentMode && document.documentMode >= 8) {
    +-	$.extend({
    +-		locationHash: function(hash) {
    +-	        if (!hash) hash = '#';
    +-	        else if (hash.charAt(0) != '#') hash = '#' + hash;
    +-	        location.hash = hash;
    +-	    }
    +-	});
    +-	return;
    +-}
    +-
    +-var curHash;
    +-// hidden iframe for IE (earlier than 8)
    +-var iframe;
    +-
    +-$.extend({
    +-	locationHash: function(hash) {
    +-		if (curHash === undefined) return;
    +-
    +-		if (!hash) hash = '#';
    +-		else if (hash.charAt(0) != '#') hash = '#' + hash;
    +-		
    +-		location.hash = hash;
    +-		
    +-		if (curHash == hash) return;
    +-		curHash = hash;
    +-		
    +-		if ($.browser.msie) updateIEFrame(hash);
    +-		$.event.trigger('hashchange');
    +-	}
    +-});
    +-
    +-$(document).ready(function() {
    +-    curHash = location.hash;
    +-    if ($.browser.msie) {
    +-        // stop the callback firing twice during init if no hash present
    +-        if (curHash == '') curHash = '#';
    +-        // add hidden iframe for IE
    +-        iframe = $('<iframe />').hide().get(0);
    +-        $('body').prepend(iframe);
    +-        updateIEFrame(location.hash);
    +-        setInterval(checkHashIE, 100);
    +-    } else {
    +-        setInterval(checkHash, 100);
    +-    }
    +-});
    +-$(window).unload(function() { iframe = null });
    +-
    +-function checkHash() {
    +-    var hash = location.hash;
    +-    if (hash != curHash) {
    +-        curHash = hash;
    +-        $.event.trigger('hashchange');
    +-    }
    +-}
    +-
    +-if ($.browser.msie) {
    +-    // Attach a live handler for any anchor links
    +-    $('a[href^=#]').live('click', function() {
    +-        var hash = $(this).attr('href');
    +-        // Don't intercept the click if there is an existing anchor on the page
    +-        // that matches this hash
    +-        if ($(hash).length == 0 && $('a[name='+hash.slice(1)+']').length == 0) {
    +-            $.locationHash(hash);
    +-            return false;
    +-        }
    +-    });
    +-}
    +-
    +-function checkHashIE() {
    +-    // On IE, check for location.hash of iframe
    +-    var idoc = iframe.contentDocument || iframe.contentWindow.document;
    +-    var hash = idoc.location.hash;
    +-    if (hash == '') hash = '#';
    +-
    +-    if (hash != curHash) {
    +-        if (location.hash != hash) location.hash = hash;
    +-        curHash = hash;
    +-        $.event.trigger('hashchange');
    +-    }
    +-}
    +-
    +-function updateIEFrame(hash) {
    +-    if (hash == '#') hash = '';
    +-    var idoc = iframe.contentWindow.document;
    +-    idoc.open();
    +-    idoc.close();
    +-    if (idoc.location.hash != hash) idoc.location.hash = hash;
    +-}
    +-
    +-})(jQuery);
    +-
    +-//third_party/javascript/jquery_jscrollpane/jquery.jscrollpane.min.js
    +-/*
    +- * @license
    +- * jScrollPane - v2.0.0beta12 - 2012-09-27
    +- * http://jscrollpane.kelvinluck.com/
    +- *
    +- * Copyright (c) 2010 Kelvin Luck
    +- * Dual licensed under the MIT or GPL licenses.
    +- */
    +-(function(b,a,c){b.fn.jScrollPane=function(e){function d(D,O){var ay,Q=this,Y,aj,v,al,T,Z,y,q,az,aE,au,i,I,h,j,aa,U,ap,X,t,A,aq,af,am,G,l,at,ax,x,av,aH,f,L,ai=true,P=true,aG=false,k=false,ao=D.clone(false,false).empty(),ac=b.fn.mwheelIntent?"mwheelIntent.jsp":"mousewheel.jsp";aH=D.css("paddingTop")+" "+D.css("paddingRight")+" "+D.css("paddingBottom")+" "+D.css("paddingLeft");f=(parseInt(D.css("paddingLeft"),10)||0)+(parseInt(D.css("paddingRight"),10)||0);function ar(aQ){var aL,aN,aM,aJ,aI,aP,aO=false,aK=false;ay=aQ;if(Y===c){aI=D.scrollTop();aP=D.scrollLeft();D.css({overflow:"hidden",padding:0});aj=D.innerWidth()+f;v=D.innerHeight();D.width(aj);Y=b('<div class="jspPane" />').css("padding",aH).append(D.children());al=b('<div class="jspContainer" />').css({width:aj+"px",height:v+"px"}).append(Y).appendTo(D)}else{D.css("width","");aO=ay.stickToBottom&&K();aK=ay.stickToRight&&B();aJ=D.innerWidth()+f!=aj||D.outerHeight()!=v;if(aJ){aj=D.innerWidth()+f;v=D.innerHeight();al.css({width:aj+"px",height:v+"px"})}if(!aJ&&L==T&&Y.outerHeight()==Z){D.width(aj);return}L=T;Y.css("width","");D.width(aj);al.find(">.jspVerticalBar,>.jspHorizontalBar").remove().end()}Y.css("overflow","auto");if(aQ.contentWidth){T=aQ.contentWidth}else{T=Y[0].scrollWidth}Z=Y[0].scrollHeight;Y.css("overflow","");y=T/aj;q=Z/v;az=q>1;aE=y>1;if(!(aE||az)){D.removeClass("jspScrollable");Y.css({top:0,width:al.width()-f});n();E();R();w()}else{D.addClass("jspScrollable");aL=ay.maintainPosition&&(I||aa);if(aL){aN=aC();aM=aA()}aF();z();F();if(aL){N(aK?(T-aj):aN,false);M(aO?(Z-v):aM,false)}J();ag();an();if(ay.enableKeyboardNavigation){S()}if(ay.clickOnTrack){p()}C();if(ay.hijackInternalLinks){m()}}if(ay.autoReinitialise&&!av){av=setInterval(function(){ar(ay)},ay.autoReinitialiseDelay)}else{if(!ay.autoReinitialise&&av){clearInterval(av)}}aI&&D.scrollTop(0)&&M(aI,false);aP&&D.scrollLeft(0)&&N(aP,false);D.trigger("jsp-initialised",[aE||az])}function aF(){if(az){al.append(b('<div class="jspVerticalBar" />').append(b('<div class="jspCap jspCapTop" />'),b('<div class="jspTrack" />').append(b('<div class="jspDrag" />').append(b('<div class="jspDragTop" />'),b('<div class="jspDragBottom" />'))),b('<div class="jspCap jspCapBottom" />')));U=al.find(">.jspVerticalBar");ap=U.find(">.jspTrack");au=ap.find(">.jspDrag");if(ay.showArrows){aq=b('<a class="jspArrow jspArrowUp" />').bind("mousedown.jsp",aD(0,-1)).bind("click.jsp",aB);af=b('<a class="jspArrow jspArrowDown" />').bind("mousedown.jsp",aD(0,1)).bind("click.jsp",aB);if(ay.arrowScrollOnHover){aq.bind("mouseover.jsp",aD(0,-1,aq));af.bind("mouseover.jsp",aD(0,1,af))}ak(ap,ay.verticalArrowPositions,aq,af)}t=v;al.find(">.jspVerticalBar>.jspCap:visible,>.jspVerticalBar>.jspArrow").each(function(){t-=b(this).outerHeight()});au.hover(function(){au.addClass("jspHover")},function(){au.removeClass("jspHover")}).bind("mousedown.jsp",function(aI){b("html").bind("dragstart.jsp selectstart.jsp",aB);au.addClass("jspActive");var s=aI.pageY-au.position().top;b("html").bind("mousemove.jsp",function(aJ){V(aJ.pageY-s,false)}).bind("mouseup.jsp mouseleave.jsp",aw);return false});o()}}function o(){ap.height(t+"px");I=0;X=ay.verticalGutter+ap.outerWidth();Y.width(aj-X-f);try{if(U.position().left===0){Y.css("margin-left",X+"px")}}catch(s){}}function z(){if(aE){al.append(b('<div class="jspHorizontalBar" />').append(b('<div class="jspCap jspCapLeft" />'),b('<div class="jspTrack" />').append(b('<div class="jspDrag" />').append(b('<div class="jspDragLeft" />'),b('<div class="jspDragRight" />'))),b('<div class="jspCap jspCapRight" />')));am=al.find(">.jspHorizontalBar");G=am.find(">.jspTrack");h=G.find(">.jspDrag");if(ay.showArrows){ax=b('<a class="jspArrow jspArrowLeft" />').bind("mousedown.jsp",aD(-1,0)).bind("click.jsp",aB);x=b('<a class="jspArrow jspArrowRight" />').bind("mousedown.jsp",aD(1,0)).bind("click.jsp",aB);
    +-if(ay.arrowScrollOnHover){ax.bind("mouseover.jsp",aD(-1,0,ax));x.bind("mouseover.jsp",aD(1,0,x))}ak(G,ay.horizontalArrowPositions,ax,x)}h.hover(function(){h.addClass("jspHover")},function(){h.removeClass("jspHover")}).bind("mousedown.jsp",function(aI){b("html").bind("dragstart.jsp selectstart.jsp",aB);h.addClass("jspActive");var s=aI.pageX-h.position().left;b("html").bind("mousemove.jsp",function(aJ){W(aJ.pageX-s,false)}).bind("mouseup.jsp mouseleave.jsp",aw);return false});l=al.innerWidth();ah()}}function ah(){al.find(">.jspHorizontalBar>.jspCap:visible,>.jspHorizontalBar>.jspArrow").each(function(){l-=b(this).outerWidth()});G.width(l+"px");aa=0}function F(){if(aE&&az){var aI=G.outerHeight(),s=ap.outerWidth();t-=aI;b(am).find(">.jspCap:visible,>.jspArrow").each(function(){l+=b(this).outerWidth()});l-=s;v-=s;aj-=aI;G.parent().append(b('<div class="jspCorner" />').css("width",aI+"px"));o();ah()}if(aE){Y.width((al.outerWidth()-f)+"px")}Z=Y.outerHeight();q=Z/v;if(aE){at=Math.ceil(1/y*l);if(at>ay.horizontalDragMaxWidth){at=ay.horizontalDragMaxWidth}else{if(at<ay.horizontalDragMinWidth){at=ay.horizontalDragMinWidth}}h.width(at+"px");j=l-at;ae(aa)}if(az){A=Math.ceil(1/q*t);if(A>ay.verticalDragMaxHeight){A=ay.verticalDragMaxHeight}else{if(A<ay.verticalDragMinHeight){A=ay.verticalDragMinHeight}}au.height(A+"px");i=t-A;ad(I)}}function ak(aJ,aL,aI,s){var aN="before",aK="after",aM;if(aL=="os"){aL=/Mac/.test(navigator.platform)?"after":"split"}if(aL==aN){aK=aL}else{if(aL==aK){aN=aL;aM=aI;aI=s;s=aM}}aJ[aN](aI)[aK](s)}function aD(aI,s,aJ){return function(){H(aI,s,this,aJ);this.blur();return false}}function H(aL,aK,aO,aN){aO=b(aO).addClass("jspActive");var aM,aJ,aI=true,s=function(){if(aL!==0){Q.scrollByX(aL*ay.arrowButtonSpeed)}if(aK!==0){Q.scrollByY(aK*ay.arrowButtonSpeed)}aJ=setTimeout(s,aI?ay.initialDelay:ay.arrowRepeatFreq);aI=false};s();aM=aN?"mouseout.jsp":"mouseup.jsp";aN=aN||b("html");aN.bind(aM,function(){aO.removeClass("jspActive");aJ&&clearTimeout(aJ);aJ=null;aN.unbind(aM)})}function p(){w();if(az){ap.bind("mousedown.jsp",function(aN){if(aN.originalTarget===c||aN.originalTarget==aN.currentTarget){var aL=b(this),aO=aL.offset(),aM=aN.pageY-aO.top-I,aJ,aI=true,s=function(){var aR=aL.offset(),aS=aN.pageY-aR.top-A/2,aP=v*ay.scrollPagePercent,aQ=i*aP/(Z-v);if(aM<0){if(I-aQ>aS){Q.scrollByY(-aP)}else{V(aS)}}else{if(aM>0){if(I+aQ<aS){Q.scrollByY(aP)}else{V(aS)}}else{aK();return}}aJ=setTimeout(s,aI?ay.initialDelay:ay.trackClickRepeatFreq);aI=false},aK=function(){aJ&&clearTimeout(aJ);aJ=null;b(document).unbind("mouseup.jsp",aK)};s();b(document).bind("mouseup.jsp",aK);return false}})}if(aE){G.bind("mousedown.jsp",function(aN){if(aN.originalTarget===c||aN.originalTarget==aN.currentTarget){var aL=b(this),aO=aL.offset(),aM=aN.pageX-aO.left-aa,aJ,aI=true,s=function(){var aR=aL.offset(),aS=aN.pageX-aR.left-at/2,aP=aj*ay.scrollPagePercent,aQ=j*aP/(T-aj);if(aM<0){if(aa-aQ>aS){Q.scrollByX(-aP)}else{W(aS)}}else{if(aM>0){if(aa+aQ<aS){Q.scrollByX(aP)}else{W(aS)}}else{aK();return}}aJ=setTimeout(s,aI?ay.initialDelay:ay.trackClickRepeatFreq);aI=false},aK=function(){aJ&&clearTimeout(aJ);aJ=null;b(document).unbind("mouseup.jsp",aK)};s();b(document).bind("mouseup.jsp",aK);return false}})}}function w(){if(G){G.unbind("mousedown.jsp")}if(ap){ap.unbind("mousedown.jsp")}}function aw(){b("html").unbind("dragstart.jsp selectstart.jsp mousemove.jsp mouseup.jsp mouseleave.jsp");if(au){au.removeClass("jspActive")}if(h){h.removeClass("jspActive")}}function V(s,aI){if(!az){return}if(s<0){s=0}else{if(s>i){s=i}}if(aI===c){aI=ay.animateScroll}if(aI){Q.animate(au,"top",s,ad)}else{au.css("top",s);ad(s)}}function ad(aI){if(aI===c){aI=au.position().top}al.scrollTop(0);I=aI;var aL=I===0,aJ=I==i,aK=aI/i,s=-aK*(Z-v);if(ai!=aL||aG!=aJ){ai=aL;aG=aJ;D.trigger("jsp-arrow-change",[ai,aG,P,k])}u(aL,aJ);Y.css("top",s);D.trigger("jsp-scroll-y",[-s,aL,aJ]).trigger("scroll")}function W(aI,s){if(!aE){return}if(aI<0){aI=0}else{if(aI>j){aI=j}}if(s===c){s=ay.animateScroll}if(s){Q.animate(h,"left",aI,ae)
    +-}else{h.css("left",aI);ae(aI)}}function ae(aI){if(aI===c){aI=h.position().left}al.scrollTop(0);aa=aI;var aL=aa===0,aK=aa==j,aJ=aI/j,s=-aJ*(T-aj);if(P!=aL||k!=aK){P=aL;k=aK;D.trigger("jsp-arrow-change",[ai,aG,P,k])}r(aL,aK);Y.css("left",s);D.trigger("jsp-scroll-x",[-s,aL,aK]).trigger("scroll")}function u(aI,s){if(ay.showArrows){aq[aI?"addClass":"removeClass"]("jspDisabled");af[s?"addClass":"removeClass"]("jspDisabled")}}function r(aI,s){if(ay.showArrows){ax[aI?"addClass":"removeClass"]("jspDisabled");x[s?"addClass":"removeClass"]("jspDisabled")}}function M(s,aI){var aJ=s/(Z-v);V(aJ*i,aI)}function N(aI,s){var aJ=aI/(T-aj);W(aJ*j,s)}function ab(aV,aQ,aJ){var aN,aK,aL,s=0,aU=0,aI,aP,aO,aS,aR,aT;try{aN=b(aV)}catch(aM){return}aK=aN.outerHeight();aL=aN.outerWidth();al.scrollTop(0);al.scrollLeft(0);while(!aN.is(".jspPane")){s+=aN.position().top;aU+=aN.position().left;aN=aN.offsetParent();if(/^body|html$/i.test(aN[0].nodeName)){return}}aI=aA();aO=aI+v;if(s<aI||aQ){aR=s-ay.verticalGutter}else{if(s+aK>aO){aR=s-v+aK+ay.verticalGutter}}if(aR){M(aR,aJ)}aP=aC();aS=aP+aj;if(aU<aP||aQ){aT=aU-ay.horizontalGutter}else{if(aU+aL>aS){aT=aU-aj+aL+ay.horizontalGutter}}if(aT){N(aT,aJ)}}function aC(){return -Y.position().left}function aA(){return -Y.position().top}function K(){var s=Z-v;return(s>20)&&(s-aA()<10)}function B(){var s=T-aj;return(s>20)&&(s-aC()<10)}function ag(){al.unbind(ac).bind(ac,function(aL,aM,aK,aI){var aJ=aa,s=I;Q.scrollBy(aK*ay.mouseWheelSpeed,-aI*ay.mouseWheelSpeed,false);return aJ==aa&&s==I})}function n(){al.unbind(ac)}function aB(){return false}function J(){Y.find(":input,a").unbind("focus.jsp").bind("focus.jsp",function(s){ab(s.target,false)})}function E(){Y.find(":input,a").unbind("focus.jsp")}function S(){var s,aI,aK=[];aE&&aK.push(am[0]);az&&aK.push(U[0]);Y.focus(function(){D.focus()});D.attr("tabindex",0).unbind("keydown.jsp keypress.jsp").bind("keydown.jsp",function(aN){if(aN.target!==this&&!(aK.length&&b(aN.target).closest(aK).length)){return}var aM=aa,aL=I;switch(aN.keyCode){case 40:case 38:case 34:case 32:case 33:case 39:case 37:s=aN.keyCode;aJ();break;case 35:M(Z-v);s=null;break;case 36:M(0);s=null;break}aI=aN.keyCode==s&&aM!=aa||aL!=I;return !aI}).bind("keypress.jsp",function(aL){if(aL.keyCode==s){aJ()}return !aI});if(ay.hideFocus){D.css("outline","none");if("hideFocus" in al[0]){D.attr("hideFocus",true)}}else{D.css("outline","");if("hideFocus" in al[0]){D.attr("hideFocus",false)}}function aJ(){var aM=aa,aL=I;switch(s){case 40:Q.scrollByY(ay.keyboardSpeed,false);break;case 38:Q.scrollByY(-ay.keyboardSpeed,false);break;case 34:case 32:Q.scrollByY(v*ay.scrollPagePercent,false);break;case 33:Q.scrollByY(-v*ay.scrollPagePercent,false);break;case 39:Q.scrollByX(ay.keyboardSpeed,false);break;case 37:Q.scrollByX(-ay.keyboardSpeed,false);break}aI=aM!=aa||aL!=I;return aI}}function R(){D.attr("tabindex","-1").removeAttr("tabindex").unbind("keydown.jsp keypress.jsp")}function C(){if(location.hash&&location.hash.length>1){var aK,aI,aJ=escape(location.hash.substr(1));try{aK=b("#"+aJ+', a[name="'+aJ+'"]')}catch(s){return}if(aK.length&&Y.find(aJ)){if(al.scrollTop()===0){aI=setInterval(function(){if(al.scrollTop()>0){ab(aK,true);b(document).scrollTop(al.position().top);clearInterval(aI)}},50)}else{ab(aK,true);b(document).scrollTop(al.position().top)}}}}function m(){if(b(document.body).data("jspHijack")){return}b(document.body).data("jspHijack",true);b(document.body).delegate("a[href*=#]","click",function(s){var aI=this.href.substr(0,this.href.indexOf("#")),aK=location.href,aO,aP,aJ,aM,aL,aN;if(location.href.indexOf("#")!==-1){aK=location.href.substr(0,location.href.indexOf("#"))}if(aI!==aK){return}aO=escape(this.href.substr(this.href.indexOf("#")+1));aP;try{aP=b("#"+aO+', a[name="'+aO+'"]')}catch(aQ){return}if(!aP.length){return}aJ=aP.closest(".jspScrollable");aM=aJ.data("jsp");aM.scrollToElement(aP,true);if(aJ[0].scrollIntoView){aL=b(a).scrollTop();aN=aP.offset().top;if(aN<aL||aN>aL+b(a).height()){aJ[0].scrollIntoView()}}s.preventDefault()
    +-})}function an(){var aJ,aI,aL,aK,aM,s=false;al.unbind("touchstart.jsp touchmove.jsp touchend.jsp click.jsp-touchclick").bind("touchstart.jsp",function(aN){var aO=aN.originalEvent.touches[0];aJ=aC();aI=aA();aL=aO.pageX;aK=aO.pageY;aM=false;s=true}).bind("touchmove.jsp",function(aQ){if(!s){return}var aP=aQ.originalEvent.touches[0],aO=aa,aN=I;Q.scrollTo(aJ+aL-aP.pageX,aI+aK-aP.pageY);aM=aM||Math.abs(aL-aP.pageX)>5||Math.abs(aK-aP.pageY)>5;return aO==aa&&aN==I}).bind("touchend.jsp",function(aN){s=false}).bind("click.jsp-touchclick",function(aN){if(aM){aM=false;return false}})}function g(){var s=aA(),aI=aC();D.removeClass("jspScrollable").unbind(".jsp");D.replaceWith(ao.append(Y.children()));ao.scrollTop(s);ao.scrollLeft(aI);if(av){clearInterval(av)}}b.extend(Q,{reinitialise:function(aI){aI=b.extend({},ay,aI);ar(aI)},scrollToElement:function(aJ,aI,s){ab(aJ,aI,s)},scrollTo:function(aJ,s,aI){N(aJ,aI);M(s,aI)},scrollToX:function(aI,s){N(aI,s)},scrollToY:function(s,aI){M(s,aI)},scrollToPercentX:function(aI,s){N(aI*(T-aj),s)},scrollToPercentY:function(aI,s){M(aI*(Z-v),s)},scrollBy:function(aI,s,aJ){Q.scrollByX(aI,aJ);Q.scrollByY(s,aJ)},scrollByX:function(s,aJ){var aI=aC()+Math[s<0?"floor":"ceil"](s),aK=aI/(T-aj);W(aK*j,aJ)},scrollByY:function(s,aJ){var aI=aA()+Math[s<0?"floor":"ceil"](s),aK=aI/(Z-v);V(aK*i,aJ)},positionDragX:function(s,aI){W(s,aI)},positionDragY:function(aI,s){V(aI,s)},animate:function(aI,aL,s,aK){var aJ={};aJ[aL]=s;aI.animate(aJ,{duration:ay.animateDuration,easing:ay.animateEase,queue:false,step:aK})},getContentPositionX:function(){return aC()},getContentPositionY:function(){return aA()},getContentWidth:function(){return T},getContentHeight:function(){return Z},getPercentScrolledX:function(){return aC()/(T-aj)},getPercentScrolledY:function(){return aA()/(Z-v)},getIsScrollableH:function(){return aE},getIsScrollableV:function(){return az},getContentPane:function(){return Y},scrollToBottom:function(s){V(i,s)},hijackInternalLinks:b.noop,destroy:function(){g()}});ar(O)}e=b.extend({},b.fn.jScrollPane.defaults,e);b.each(["mouseWheelSpeed","arrowButtonSpeed","trackClickSpeed","keyboardSpeed"],function(){e[this]=e[this]||e.speed});return this.each(function(){var f=b(this),g=f.data("jsp");if(g){g.reinitialise(e)}else{b("script",f).filter('[type="text/javascript"],:not([type])').remove();g=new d(f,e);f.data("jsp",g)}})};b.fn.jScrollPane.defaults={showArrows:false,maintainPosition:true,stickToBottom:false,stickToRight:false,clickOnTrack:true,autoReinitialise:false,autoReinitialiseDelay:500,verticalDragMinHeight:0,verticalDragMaxHeight:99999,horizontalDragMinWidth:0,horizontalDragMaxWidth:99999,contentWidth:c,animateScroll:false,animateDuration:300,animateEase:"linear",hijackInternalLinks:false,verticalGutter:4,horizontalGutter:4,mouseWheelSpeed:0,arrowButtonSpeed:0,arrowRepeatFreq:50,arrowScrollOnHover:false,trackClickSpeed:0,trackClickRepeatFreq:70,verticalArrowPositions:"split",horizontalArrowPositions:"split",enableKeyboardNavigation:true,hideFocus:false,keyboardSpeed:0,initialDelay:300,speed:30,scrollPagePercent:0.8}})(jQuery,this);
    +-
    +-//third_party/javascript/jquery_mousewheel/jquery.mousewheel.min.js
    +-/**
    +- * @license
    +- * Copyright (c) 2011 Brandon Aaron (http://brandonaaron.net)
    +- * Licensed under the MIT License (LICENSE.txt).
    +- *
    +- * Thanks to: http://adomas.org/javascript-mouse-wheel/ for some pointers.
    +- * Thanks to: Mathias Bank(http://www.mathias-bank.de) for a scope bug fix.
    +- * Thanks to: Seamus Leahy for adding deltaX and deltaY
    +- *
    +- * Version: 3.0.6
    +- * 
    +- * Requires: 1.2.2+
    +- */
    +-(function(a){function d(b){var c=b||window.event,d=[].slice.call(arguments,1),e=0,f=!0,g=0,h=0;return b=a.event.fix(c),b.type="mousewheel",c.wheelDelta&&(e=c.wheelDelta/120),c.detail&&(e=-c.detail/3),h=e,c.axis!==undefined&&c.axis===c.HORIZONTAL_AXIS&&(h=0,g=-1*e),c.wheelDeltaY!==undefined&&(h=c.wheelDeltaY/120),c.wheelDeltaX!==undefined&&(g=-1*c.wheelDeltaX/120),d.unshift(b,e,g,h),(a.event.dispatch||a.event.handle).apply(this,d)}var b=["DOMMouseScroll","mousewheel"];if(a.event.fixHooks)for(var c=b.length;c;)a.event.fixHooks[b[--c]]=a.event.mouseHooks;a.event.special.mousewheel={setup:function(){if(this.addEventListener)for(var a=b.length;a;)this.addEventListener(b[--a],d,!1);else this.onmousewheel=d},teardown:function(){if(this.removeEventListener)for(var a=b.length;a;)this.removeEventListener(b[--a],d,!1);else this.onmousewheel=null}},a.fn.extend({mousewheel:function(a){return a?this.bind("mousewheel",a):this.trigger("mousewheel")},unmousewheel:function(a){return this.unbind("mousewheel",a)}})})(jQuery);
    +-
    +-//third_party/javascript/jquery_ui/v1_8_23/js/jquery-ui-1.8.23.custom.min.js
    +-/**
    +- * jQuery UI
    +- * @version 1.8.23
    +- * @date 2012-08-15
    +- * @link https://github.com/jquery/jquery-ui
    +- * Includes: jquery.ui.core.js
    +- * Copyright 2012, AUTHORS.txt (http://jqueryui.com/about)
    +- * @license MIT (Dual licensed with GPL Version 2 license).
    +- * http://jquery.org/license
    +- */
    +-(function(a,b){function c(b,c){var e=b.nodeName.toLowerCase();if("area"===e){var f=b.parentNode,g=f.name,h;return!b.href||!g||f.nodeName.toLowerCase()!=="map"?!1:(h=a("img[usemap=#"+g+"]")[0],!!h&&d(h))}return(/input|select|textarea|button|object/.test(e)?!b.disabled:"a"==e?b.href||c:c)&&d(b)}function d(b){return!a(b).parents().andSelf().filter(function(){return a.curCSS(this,"visibility")==="hidden"||a.expr.filters.hidden(this)}).length}a.ui=a.ui||{};if(a.ui.version)return;a.extend(a.ui,{version:"1.8.23",keyCode:{ALT:18,BACKSPACE:8,CAPS_LOCK:20,COMMA:188,COMMAND:91,COMMAND_LEFT:91,COMMAND_RIGHT:93,CONTROL:17,DELETE:46,DOWN:40,END:35,ENTER:13,ESCAPE:27,HOME:36,INSERT:45,LEFT:37,MENU:93,NUMPAD_ADD:107,NUMPAD_DECIMAL:110,NUMPAD_DIVIDE:111,NUMPAD_ENTER:108,NUMPAD_MULTIPLY:106,NUMPAD_SUBTRACT:109,PAGE_DOWN:34,PAGE_UP:33,PERIOD:190,RIGHT:39,SHIFT:16,SPACE:32,TAB:9,UP:38,WINDOWS:91}}),a.fn.extend({propAttr:a.fn.prop||a.fn.attr,_focus:a.fn.focus,focus:function(b,c){return typeof b=="number"?this.each(function(){var d=this;setTimeout(function(){a(d).focus(),c&&c.call(d)},b)}):this._focus.apply(this,arguments)},scrollParent:function(){var b;return a.browser.msie&&/(static|relative)/.test(this.css("position"))||/absolute/.test(this.css("position"))?b=this.parents().filter(function(){return/(relative|absolute|fixed)/.test(a.curCSS(this,"position",1))&&/(auto|scroll)/.test(a.curCSS(this,"overflow",1)+a.curCSS(this,"overflow-y",1)+a.curCSS(this,"overflow-x",1))}).eq(0):b=this.parents().filter(function(){return/(auto|scroll)/.test(a.curCSS(this,"overflow",1)+a.curCSS(this,"overflow-y",1)+a.curCSS(this,"overflow-x",1))}).eq(0),/fixed/.test(this.css("position"))||!b.length?a(document):b},zIndex:function(c){if(c!==b)return this.css("zIndex",c);if(this.length){var d=a(this[0]),e,f;while(d.length&&d[0]!==document){e=d.css("position");if(e==="absolute"||e==="relative"||e==="fixed"){f=parseInt(d.css("zIndex"),10);if(!isNaN(f)&&f!==0)return f}d=d.parent()}}return 0},disableSelection:function(){return this.bind((a.support.selectstart?"selectstart":"mousedown")+".ui-disableSelection",function(a){a.preventDefault()})},enableSelection:function(){return this.unbind(".ui-disableSelection")}}),a("<a>").outerWidth(1).jquery||a.each(["Width","Height"],function(c,d){function h(b,c,d,f){return a.each(e,function(){c-=parseFloat(a.curCSS(b,"padding"+this,!0))||0,d&&(c-=parseFloat(a.curCSS(b,"border"+this+"Width",!0))||0),f&&(c-=parseFloat(a.curCSS(b,"margin"+this,!0))||0)}),c}var e=d==="Width"?["Left","Right"]:["Top","Bottom"],f=d.toLowerCase(),g={innerWidth:a.fn.innerWidth,innerHeight:a.fn.innerHeight,outerWidth:a.fn.outerWidth,outerHeight:a.fn.outerHeight};a.fn["inner"+d]=function(c){return c===b?g["inner"+d].call(this):this.each(function(){a(this).css(f,h(this,c)+"px")})},a.fn["outer"+d]=function(b,c){return typeof b!="number"?g["outer"+d].call(this,b):this.each(function(){a(this).css(f,h(this,b,!0,c)+"px")})}}),a.extend(a.expr[":"],{data:a.expr.createPseudo?a.expr.createPseudo(function(b){return function(c){return!!a.data(c,b)}}):function(b,c,d){return!!a.data(b,d[3])},focusable:function(b){return c(b,!isNaN(a.attr(b,"tabindex")))},tabbable:function(b){var d=a.attr(b,"tabindex"),e=isNaN(d);return(e||d>=0)&&c(b,!e)}}),a(function(){var b=document.body,c=b.appendChild(c=document.createElement("div"));c.offsetHeight,a.extend(c.style,{minHeight:"100px",height:"auto",padding:0,borderWidth:0}),a.support.minHeight=c.offsetHeight===100,a.support.selectstart="onselectstart"in c,b.removeChild(c).style.display="none"}),a.curCSS||(a.curCSS=a.css),a.extend(a.ui,{plugin:{add:function(b,c,d){var e=a.ui[b].prototype;for(var f in d)e.plugins[f]=e.plugins[f]||[],e.plugins[f].push([c,d[f]])},call:function(a,b,c){var d=a.plugins[b];if(!d||!a.element[0].parentNode)return;for(var e=0;e<d.length;e++)a.options[d[e][0]]&&d[e][1].apply(a.element,c)}},contains:function(a,b){return document.compareDocumentPosition?a.compareDocumentPosition(b)&16:a!==b&&a.contains(b)},hasScroll:function(b,c){if(a(b).css("overflow")==="hidden")return!1;var d=c&&c==="left"?"scrollLeft":"scrollTop",e=!1;return b[d]>0?!0:(b[d]=1,e=b[d]>0,b[d]=0,e)},isOverAxis:function(a,b,c){return a>b&&a<b+c},isOver:function(b,c,d,e,f,g){return a.ui.isOverAxis(b,d,f)&&a.ui.isOverAxis(c,e,g)}})})(jQuery);;/*! jQuery UI - v1.8.23 - 2012-08-15
    +-* https://github.com/jquery/jquery-ui
    +-* Includes: jquery.ui.widget.js
    +-* Copyright (c) 2012 AUTHORS.txt; Licensed MIT, GPL */
    +-(function(a,b){if(a.cleanData){var c=a.cleanData;a.cleanData=function(b){for(var d=0,e;(e=b[d])!=null;d++)try{a(e).triggerHandler("remove")}catch(f){}c(b)}}else{var d=a.fn.remove;a.fn.remove=function(b,c){return this.each(function(){return c||(!b||a.filter(b,[this]).length)&&a("*",this).add([this]).each(function(){try{a(this).triggerHandler("remove")}catch(b){}}),d.call(a(this),b,c)})}}a.widget=function(b,c,d){var e=b.split(".")[0],f;b=b.split(".")[1],f=e+"-"+b,d||(d=c,c=a.Widget),a.expr[":"][f]=function(c){return!!a.data(c,b)},a[e]=a[e]||{},a[e][b]=function(a,b){arguments.length&&this._createWidget(a,b)};var g=new c;g.options=a.extend(!0,{},g.options),a[e][b].prototype=a.extend(!0,g,{namespace:e,widgetName:b,widgetEventPrefix:a[e][b].prototype.widgetEventPrefix||b,widgetBaseClass:f},d),a.widget.bridge(b,a[e][b])},a.widget.bridge=function(c,d){a.fn[c]=function(e){var f=typeof e=="string",g=Array.prototype.slice.call(arguments,1),h=this;return e=!f&&g.length?a.extend.apply(null,[!0,e].concat(g)):e,f&&e.charAt(0)==="_"?h:(f?this.each(function(){var d=a.data(this,c),f=d&&a.isFunction(d[e])?d[e].apply(d,g):d;if(f!==d&&f!==b)return h=f,!1}):this.each(function(){var b=a.data(this,c);b?b.option(e||{})._init():a.data(this,c,new d(e,this))}),h)}},a.Widget=function(a,b){arguments.length&&this._createWidget(a,b)},a.Widget.prototype={widgetName:"widget",widgetEventPrefix:"",options:{disabled:!1},_createWidget:function(b,c){a.data(c,this.widgetName,this),this.element=a(c),this.options=a.extend(!0,{},this.options,this._getCreateOptions(),b);var d=this;this.element.bind("remove."+this.widgetName,function(){d.destroy()}),this._create(),this._trigger("create"),this._init()},_getCreateOptions:function(){return a.metadata&&a.metadata.get(this.element[0])[this.widgetName]},_create:function(){},_init:function(){},destroy:function(){this.element.unbind("."+this.widgetName).removeData(this.widgetName),this.widget().unbind("."+this.widgetName).removeAttr("aria-disabled").removeClass(this.widgetBaseClass+"-disabled "+"ui-state-disabled")},widget:function(){return this.element},option:function(c,d){var e=c;if(arguments.length===0)return a.extend({},this.options);if(typeof c=="string"){if(d===b)return this.options[c];e={},e[c]=d}return this._setOptions(e),this},_setOptions:function(b){var c=this;return a.each(b,function(a,b){c._setOption(a,b)}),this},_setOption:function(a,b){return this.options[a]=b,a==="disabled"&&this.widget()[b?"addClass":"removeClass"](this.widgetBaseClass+"-disabled"+" "+"ui-state-disabled").attr("aria-disabled",b),this},enable:function(){return this._setOption("disabled",!1)},disable:function(){return this._setOption("disabled",!0)},_trigger:function(b,c,d){var e,f,g=this.options[b];d=d||{},c=a.Event(c),c.type=(b===this.widgetEventPrefix?b:this.widgetEventPrefix+b).toLowerCase(),c.target=this.element[0],f=c.originalEvent;if(f)for(e in f)e in c||(c[e]=f[e]);return this.element.trigger(c,d),!(a.isFunction(g)&&g.call(this.element[0],c,d)===!1||c.isDefaultPrevented())}}})(jQuery);;/*! jQuery UI - v1.8.23 - 2012-08-15
    +-* https://github.com/jquery/jquery-ui
    +-* Includes: jquery.ui.mouse.js
    +-* Copyright (c) 2012 AUTHORS.txt; Licensed MIT, GPL */
    +-(function(a,b){var c=!1;a(document).mouseup(function(a){c=!1}),a.widget("ui.mouse",{options:{cancel:":input,option",distance:1,delay:0},_mouseInit:function(){var b=this;this.element.bind("mousedown."+this.widgetName,function(a){return b._mouseDown(a)}).bind("click."+this.widgetName,function(c){if(!0===a.data(c.target,b.widgetName+".preventClickEvent"))return a.removeData(c.target,b.widgetName+".preventClickEvent"),c.stopImmediatePropagation(),!1}),this.started=!1},_mouseDestroy:function(){this.element.unbind("."+this.widgetName),this._mouseMoveDelegate&&a(document).unbind("mousemove."+this.widgetName,this._mouseMoveDelegate).unbind("mouseup."+this.widgetName,this._mouseUpDelegate)},_mouseDown:function(b){if(c)return;this._mouseStarted&&this._mouseUp(b),this._mouseDownEvent=b;var d=this,e=b.which==1,f=typeof this.options.cancel=="string"&&b.target.nodeName?a(b.target).closest(this.options.cancel).length:!1;if(!e||f||!this._mouseCapture(b))return!0;this.mouseDelayMet=!this.options.delay,this.mouseDelayMet||(this._mouseDelayTimer=setTimeout(function(){d.mouseDelayMet=!0},this.options.delay));if(this._mouseDistanceMet(b)&&this._mouseDelayMet(b)){this._mouseStarted=this._mouseStart(b)!==!1;if(!this._mouseStarted)return b.preventDefault(),!0}return!0===a.data(b.target,this.widgetName+".preventClickEvent")&&a.removeData(b.target,this.widgetName+".preventClickEvent"),this._mouseMoveDelegate=function(a){return d._mouseMove(a)},this._mouseUpDelegate=function(a){return d._mouseUp(a)},a(document).bind("mousemove."+this.widgetName,this._mouseMoveDelegate).bind("mouseup."+this.widgetName,this._mouseUpDelegate),b.preventDefault(),c=!0,!0},_mouseMove:function(b){return!a.browser.msie||document.documentMode>=9||!!b.button?this._mouseStarted?(this._mouseDrag(b),b.preventDefault()):(this._mouseDistanceMet(b)&&this._mouseDelayMet(b)&&(this._mouseStarted=this._mouseStart(this._mouseDownEvent,b)!==!1,this._mouseStarted?this._mouseDrag(b):this._mouseUp(b)),!this._mouseStarted):this._mouseUp(b)},_mouseUp:function(b){return a(document).unbind("mousemove."+this.widgetName,this._mouseMoveDelegate).unbind("mouseup."+this.widgetName,this._mouseUpDelegate),this._mouseStarted&&(this._mouseStarted=!1,b.target==this._mouseDownEvent.target&&a.data(b.target,this.widgetName+".preventClickEvent",!0),this._mouseStop(b)),!1},_mouseDistanceMet:function(a){return Math.max(Math.abs(this._mouseDownEvent.pageX-a.pageX),Math.abs(this._mouseDownEvent.pageY-a.pageY))>=this.options.distance},_mouseDelayMet:function(a){return this.mouseDelayMet},_mouseStart:function(a){},_mouseDrag:function(a){},_mouseStop:function(a){},_mouseCapture:function(a){return!0}})})(jQuery);;/*! jQuery UI - v1.8.23 - 2012-08-15
    +-* https://github.com/jquery/jquery-ui
    +-* Includes: jquery.ui.position.js
    +-* Copyright (c) 2012 AUTHORS.txt; Licensed MIT, GPL */
    +-(function(a,b){a.ui=a.ui||{};var c=/left|center|right/,d=/top|center|bottom/,e="center",f={},g=a.fn.position,h=a.fn.offset;a.fn.position=function(b){if(!b||!b.of)return g.apply(this,arguments);b=a.extend({},b);var h=a(b.of),i=h[0],j=(b.collision||"flip").split(" "),k=b.offset?b.offset.split(" "):[0,0],l,m,n;return i.nodeType===9?(l=h.width(),m=h.height(),n={top:0,left:0}):i.setTimeout?(l=h.width(),m=h.height(),n={top:h.scrollTop(),left:h.scrollLeft()}):i.preventDefault?(b.at="left top",l=m=0,n={top:b.of.pageY,left:b.of.pageX}):(l=h.outerWidth(),m=h.outerHeight(),n=h.offset()),a.each(["my","at"],function(){var a=(b[this]||"").split(" ");a.length===1&&(a=c.test(a[0])?a.concat([e]):d.test(a[0])?[e].concat(a):[e,e]),a[0]=c.test(a[0])?a[0]:e,a[1]=d.test(a[1])?a[1]:e,b[this]=a}),j.length===1&&(j[1]=j[0]),k[0]=parseInt(k[0],10)||0,k.length===1&&(k[1]=k[0]),k[1]=parseInt(k[1],10)||0,b.at[0]==="right"?n.left+=l:b.at[0]===e&&(n.left+=l/2),b.at[1]==="bottom"?n.top+=m:b.at[1]===e&&(n.top+=m/2),n.left+=k[0],n.top+=k[1],this.each(function(){var c=a(this),d=c.outerWidth(),g=c.outerHeight(),h=parseInt(a.curCSS(this,"marginLeft",!0))||0,i=parseInt(a.curCSS(this,"marginTop",!0))||0,o=d+h+(parseInt(a.curCSS(this,"marginRight",!0))||0),p=g+i+(parseInt(a.curCSS(this,"marginBottom",!0))||0),q=a.extend({},n),r;b.my[0]==="right"?q.left-=d:b.my[0]===e&&(q.left-=d/2),b.my[1]==="bottom"?q.top-=g:b.my[1]===e&&(q.top-=g/2),f.fractions||(q.left=Math.round(q.left),q.top=Math.round(q.top)),r={left:q.left-h,top:q.top-i},a.each(["left","top"],function(c,e){a.ui.position[j[c]]&&a.ui.position[j[c]][e](q,{targetWidth:l,targetHeight:m,elemWidth:d,elemHeight:g,collisionPosition:r,collisionWidth:o,collisionHeight:p,offset:k,my:b.my,at:b.at})}),a.fn.bgiframe&&c.bgiframe(),c.offset(a.extend(q,{using:b.using}))})},a.ui.position={fit:{left:function(b,c){var d=a(window),e=c.collisionPosition.left+c.collisionWidth-d.width()-d.scrollLeft();b.left=e>0?b.left-e:Math.max(b.left-c.collisionPosition.left,b.left)},top:function(b,c){var d=a(window),e=c.collisionPosition.top+c.collisionHeight-d.height()-d.scrollTop();b.top=e>0?b.top-e:Math.max(b.top-c.collisionPosition.top,b.top)}},flip:{left:function(b,c){if(c.at[0]===e)return;var d=a(window),f=c.collisionPosition.left+c.collisionWidth-d.width()-d.scrollLeft(),g=c.my[0]==="left"?-c.elemWidth:c.my[0]==="right"?c.elemWidth:0,h=c.at[0]==="left"?c.targetWidth:-c.targetWidth,i=-2*c.offset[0];b.left+=c.collisionPosition.left<0?g+h+i:f>0?g+h+i:0},top:function(b,c){if(c.at[1]===e)return;var d=a(window),f=c.collisionPosition.top+c.collisionHeight-d.height()-d.scrollTop(),g=c.my[1]==="top"?-c.elemHeight:c.my[1]==="bottom"?c.elemHeight:0,h=c.at[1]==="top"?c.targetHeight:-c.targetHeight,i=-2*c.offset[1];b.top+=c.collisionPosition.top<0?g+h+i:f>0?g+h+i:0}}},a.offset.setOffset||(a.offset.setOffset=function(b,c){/static/.test(a.curCSS(b,"position"))&&(b.style.position="relative");var d=a(b),e=d.offset(),f=parseInt(a.curCSS(b,"top",!0),10)||0,g=parseInt(a.curCSS(b,"left",!0),10)||0,h={top:c.top-e.top+f,left:c.left-e.left+g};"using"in c?c.using.call(b,h):d.css(h)},a.fn.offset=function(b){var c=this[0];return!c||!c.ownerDocument?null:b?a.isFunction(b)?this.each(function(c){a(this).offset(b.call(this,c,a(this).offset()))}):this.each(function(){a.offset.setOffset(this,b)}):h.call(this)}),a.curCSS||(a.curCSS=a.css),function(){var b=document.getElementsByTagName("body")[0],c=document.createElement("div"),d,e,g,h,i;d=document.createElement(b?"div":"body"),g={visibility:"hidden",width:0,height:0,border:0,margin:0,background:"none"},b&&a.extend(g,{position:"absolute",left:"-1000px",top:"-1000px"});for(var j in g)d.style[j]=g[j];d.appendChild(c),e=b||document.documentElement,e.insertBefore(d,e.firstChild),c.style.cssText="position: absolute; left: 10.7432222px; top: 10.432325px; height: 30px; width: 201px;",h=a(c).offset(function(a,b){return b}).offset(),d.innerHTML="",e.removeChild(d),i=h.top+h.left+(b?2e3:0),f.fractions=i>21&&i<22}()})(jQuery);;/*! jQuery UI - v1.8.23 - 2012-08-15
    +-* https://github.com/jquery/jquery-ui
    +-* Includes: jquery.ui.draggable.js
    +-* Copyright (c) 2012 AUTHORS.txt; Licensed MIT, GPL */
    +-(function(a,b){a.widget("ui.draggable",a.ui.mouse,{widgetEventPrefix:"drag",options:{addClasses:!0,appendTo:"parent",axis:!1,connectToSortable:!1,containment:!1,cursor:"auto",cursorAt:!1,grid:!1,handle:!1,helper:"original",iframeFix:!1,opacity:!1,refreshPositions:!1,revert:!1,revertDuration:500,scope:"default",scroll:!0,scrollSensitivity:20,scrollSpeed:20,snap:!1,snapMode:"both",snapTolerance:20,stack:!1,zIndex:!1},_create:function(){this.options.helper=="original"&&!/^(?:r|a|f)/.test(this.element.css("position"))&&(this.element[0].style.position="relative"),this.options.addClasses&&this.element.addClass("ui-draggable"),this.options.disabled&&this.element.addClass("ui-draggable-disabled"),this._mouseInit()},destroy:function(){if(!this.element.data("draggable"))return;return this.element.removeData("draggable").unbind(".draggable").removeClass("ui-draggable ui-draggable-dragging ui-draggable-disabled"),this._mouseDestroy(),this},_mouseCapture:function(b){var c=this.options;return this.helper||c.disabled||a(b.target).is(".ui-resizable-handle")?!1:(this.handle=this._getHandle(b),this.handle?(c.iframeFix&&a(c.iframeFix===!0?"iframe":c.iframeFix).each(function(){a('<div class="ui-draggable-iframeFix" style="background: #fff;"></div>').css({width:this.offsetWidth+"px",height:this.offsetHeight+"px",position:"absolute",opacity:"0.001",zIndex:1e3}).css(a(this).offset()).appendTo("body")}),!0):!1)},_mouseStart:function(b){var c=this.options;return this.helper=this._createHelper(b),this.helper.addClass("ui-draggable-dragging"),this._cacheHelperProportions(),a.ui.ddmanager&&(a.ui.ddmanager.current=this),this._cacheMargins(),this.cssPosition=this.helper.css("position"),this.scrollParent=this.helper.scrollParent(),this.offset=this.positionAbs=this.element.offset(),this.offset={top:this.offset.top-this.margins.top,left:this.offset.left-this.margins.left},a.extend(this.offset,{click:{left:b.pageX-this.offset.left,top:b.pageY-this.offset.top},parent:this._getParentOffset(),relative:this._getRelativeOffset()}),this.originalPosition=this.position=this._generatePosition(b),this.originalPageX=b.pageX,this.originalPageY=b.pageY,c.cursorAt&&this._adjustOffsetFromHelper(c.cursorAt),c.containment&&this._setContainment(),this._trigger("start",b)===!1?(this._clear(),!1):(this._cacheHelperProportions(),a.ui.ddmanager&&!c.dropBehaviour&&a.ui.ddmanager.prepareOffsets(this,b),this._mouseDrag(b,!0),a.ui.ddmanager&&a.ui.ddmanager.dragStart(this,b),!0)},_mouseDrag:function(b,c){this.position=this._generatePosition(b),this.positionAbs=this._convertPositionTo("absolute");if(!c){var d=this._uiHash();if(this._trigger("drag",b,d)===!1)return this._mouseUp({}),!1;this.position=d.position}if(!this.options.axis||this.options.axis!="y")this.helper[0].style.left=this.position.left+"px";if(!this.options.axis||this.options.axis!="x")this.helper[0].style.top=this.position.top+"px";return a.ui.ddmanager&&a.ui.ddmanager.drag(this,b),!1},_mouseStop:function(b){var c=!1;a.ui.ddmanager&&!this.options.dropBehaviour&&(c=a.ui.ddmanager.drop(this,b)),this.dropped&&(c=this.dropped,this.dropped=!1);var d=this.element[0],e=!1;while(d&&(d=d.parentNode))d==document&&(e=!0);if(!e&&this.options.helper==="original")return!1;if(this.options.revert=="invalid"&&!c||this.options.revert=="valid"&&c||this.options.revert===!0||a.isFunction(this.options.revert)&&this.options.revert.call(this.element,c)){var f=this;a(this.helper).animate(this.originalPosition,parseInt(this.options.revertDuration,10),function(){f._trigger("stop",b)!==!1&&f._clear()})}else this._trigger("stop",b)!==!1&&this._clear();return!1},_mouseUp:function(b){return this.options.iframeFix===!0&&a("div.ui-draggable-iframeFix").each(function(){this.parentNode.removeChild(this)}),a.ui.ddmanager&&a.ui.ddmanager.dragStop(this,b),a.ui.mouse.prototype._mouseUp.call(this,b)},cancel:function(){return this.helper.is(".ui-draggable-dragging")?this._mouseUp({}):this._clear(),this},_getHandle:function(b){var c=!this.options.handle||!a(this.options.handle,this.element).length?!0:!1;return a(this.options.handle,this.element).find("*").andSelf().each(function(){this==b.target&&(c=!0)}),c},_createHelper:function(b){var c=this.options,d=a.isFunction(c.helper)?a(c.helper.apply(this.element[0],[b])):c.helper=="clone"?this.element.clone().removeAttr("id"):this.element;return d.parents("body").length||d.appendTo(c.appendTo=="parent"?this.element[0].parentNode:c.appendTo),d[0]!=this.element[0]&&!/(fixed|absolute)/.test(d.css("position"))&&d.css("position","absolute"),d},_adjustOffsetFromHelper:function(b){typeof b=="string"&&(b=b.split(" ")),a.isArray(b)&&(b={left:+b[0],top:+b[1]||0}),"left"in b&&(this.offset.click.left=b.left+this.margins.left),"right"in b&&(this.offset.click.left=this.helperProportions.width-b.right+this.margins.left),"top"in b&&(this.offset.click.top=b.top+this.margins.top),"bottom"in b&&(this.offset.click.top=this.helperProportions.height-b.bottom+this.margins.top)},_getParentOffset:function(){this.offsetParent=this.helper.offsetParent();var b=this.offsetParent.offset();this.cssPosition=="absolute"&&this.scrollParent[0]!=document&&a.ui.contains(this.scrollParent[0],this.offsetParent[0])&&(b.left+=this.scrollParent.scrollLeft(),b.top+=this.scrollParent.scrollTop());if(this.offsetParent[0]==document.body||this.offsetParent[0].tagName&&this.offsetParent[0].tagName.toLowerCase()=="html"&&a.browser.msie)b={top:0,left:0};return{top:b.top+(parseInt(this.offsetParent.css("borderTopWidth"),10)||0),left:b.left+(parseInt(this.offsetParent.css("borderLeftWidth"),10)||0)}},_getRelativeOffset:function(){if(this.cssPosition=="relative"){var a=this.element.position();return{top:a.top-(parseInt(this.helper.css("top"),10)||0)+this.scrollParent.scrollTop(),left:a.left-(parseInt(this.helper.css("left"),10)||0)+this.scrollParent.scrollLeft()}}return{top:0,left:0}},_cacheMargins:function(){this.margins={left:parseInt(this.element.css("marginLeft"),10)||0,top:parseInt(this.element.css("marginTop"),10)||0,right:parseInt(this.element.css("marginRight"),10)||0,bottom:parseInt(this.element.css("marginBottom"),10)||0}},_cacheHelperProportions:function(){this.helperProportions={width:this.helper.outerWidth(),height:this.helper.outerHeight()}},_setContainment:function(){var b=this.options;b.containment=="parent"&&(b.containment=this.helper[0].parentNode);if(b.containment=="document"||b.containment=="window")this.containment=[b.containment=="document"?0:a(window).scrollLeft()-this.offset.relative.left-this.offset.parent.left,b.containment=="document"?0:a(window).scrollTop()-this.offset.relative.top-this.offset.parent.top,(b.containment=="document"?0:a(window).scrollLeft())+a(b.containment=="document"?document:window).width()-this.helperProportions.width-this.margins.left,(b.containment=="document"?0:a(window).scrollTop())+(a(b.containment=="document"?document:window).height()||document.body.parentNode.scrollHeight)-this.helperProportions.height-this.margins.top];if(!/^(document|window|parent)$/.test(b.containment)&&b.containment.constructor!=Array){var c=a(b.containment),d=c[0];if(!d)return;var e=c.offset(),f=a(d).css("overflow")!="hidden";this.containment=[(parseInt(a(d).css("borderLeftWidth"),10)||0)+(parseInt(a(d).css("paddingLeft"),10)||0),(parseInt(a(d).css("borderTopWidth"),10)||0)+(parseInt(a(d).css("paddingTop"),10)||0),(f?Math.max(d.scrollWidth,d.offsetWidth):d.offsetWidth)-(parseInt(a(d).css("borderLeftWidth"),10)||0)-(parseInt(a(d).css("paddingRight"),10)||0)-this.helperProportions.width-this.margins.left-this.margins.right,(f?Math.max(d.scrollHeight,d.offsetHeight):d.offsetHeight)-(parseInt(a(d).css("borderTopWidth"),10)||0)-(parseInt(a(d).css("paddingBottom"),10)||0)-this.helperProportions.height-this.margins.top-this.margins.bottom],this.relative_container=c}else b.containment.constructor==Array&&(this.containment=b.containment)},_convertPositionTo:function(b,c){c||(c=this.position);var d=b=="absolute"?1:-1,e=this.options,f=this.cssPosition=="absolute"&&(this.scrollParent[0]==document||!a.ui.contains(this.scrollParent[0],this.offsetParent[0]))?this.offsetParent:this.scrollParent,g=/(html|body)/i.test(f[0].tagName);return{top:c.top+this.offset.relative.top*d+this.offset.parent.top*d-(a.browser.safari&&a.browser.version<526&&this.cssPosition=="fixed"?0:(this.cssPosition=="fixed"?-this.scrollParent.scrollTop():g?0:f.scrollTop())*d),left:c.left+this.offset.relative.left*d+this.offset.parent.left*d-(a.browser.safari&&a.browser.version<526&&this.cssPosition=="fixed"?0:(this.cssPosition=="fixed"?-this.scrollParent.scrollLeft():g?0:f.scrollLeft())*d)}},_generatePosition:function(b){var c=this.options,d=this.cssPosition=="absolute"&&(this.scrollParent[0]==document||!a.ui.contains(this.scrollParent[0],this.offsetParent[0]))?this.offsetParent:this.scrollParent,e=/(html|body)/i.test(d[0].tagName),f=b.pageX,g=b.pageY;if(this.originalPosition){var h;if(this.containment){if(this.relative_container){var i=this.relative_container.offset();h=[this.containment[0]+i.left,this.containment[1]+i.top,this.containment[2]+i.left,this.containment[3]+i.top]}else h=this.containment;b.pageX-this.offset.click.left<h[0]&&(f=h[0]+this.offset.click.left),b.pageY-this.offset.click.top<h[1]&&(g=h[1]+this.offset.click.top),b.pageX-this.offset.click.left>h[2]&&(f=h[2]+this.offset.click.left),b.pageY-this.offset.click.top>h[3]&&(g=h[3]+this.offset.click.top)}if(c.grid){var j=c.grid[1]?this.originalPageY+Math.round((g-this.originalPageY)/c.grid[1])*c.grid[1]:this.originalPageY;g=h?j-this.offset.click.top<h[1]||j-this.offset.click.top>h[3]?j-this.offset.click.top<h[1]?j+c.grid[1]:j-c.grid[1]:j:j;var k=c.grid[0]?this.originalPageX+Math.round((f-this.originalPageX)/c.grid[0])*c.grid[0]:this.originalPageX;f=h?k-this.offset.click.left<h[0]||k-this.offset.click.left>h[2]?k-this.offset.click.left<h[0]?k+c.grid[0]:k-c.grid[0]:k:k}}return{top:g-this.offset.click.top-this.offset.relative.top-this.offset.parent.top+(a.browser.safari&&a.browser.version<526&&this.cssPosition=="fixed"?0:this.cssPosition=="fixed"?-this.scrollParent.scrollTop():e?0:d.scrollTop()),left:f-this.offset.click.left-this.offset.relative.left-this.offset.parent.left+(a.browser.safari&&a.browser.version<526&&this.cssPosition=="fixed"?0:this.cssPosition=="fixed"?-this.scrollParent.scrollLeft():e?0:d.scrollLeft())}},_clear:function(){this.helper.removeClass("ui-draggable-dragging"),this.helper[0]!=this.element[0]&&!this.cancelHelperRemoval&&this.helper.remove(),this.helper=null,this.cancelHelperRemoval=!1},_trigger:function(b,c,d){return d=d||this._uiHash(),a.ui.plugin.call(this,b,[c,d]),b=="drag"&&(this.positionAbs=this._convertPositionTo("absolute")),a.Widget.prototype._trigger.call(this,b,c,d)},plugins:{},_uiHash:function(a){return{helper:this.helper,position:this.position,originalPosition:this.originalPosition,offset:this.positionAbs}}}),a.extend(a.ui.draggable,{version:"1.8.23"}),a.ui.plugin.add("draggable","connectToSortable",{start:function(b,c){var d=a(this).data("draggable"),e=d.options,f=a.extend({},c,{item:d.element});d.sortables=[],a(e.connectToSortable).each(function(){var c=a.data(this,"sortable");c&&!c.options.disabled&&(d.sortables.push({instance:c,shouldRevert:c.options.revert}),c.refreshPositions(),c._trigger("activate",b,f))})},stop:function(b,c){var d=a(this).data("draggable"),e=a.extend({},c,{item:d.element});a.each(d.sortables,function(){this.instance.isOver?(this.instance.isOver=0,d.cancelHelperRemoval=!0,this.instance.cancelHelperRemoval=!1,this.shouldRevert&&(this.instance.options.revert=!0),this.instance._mouseStop(b),this.instance.options.helper=this.instance.options._helper,d.options.helper=="original"&&this.instance.currentItem.css({top:"auto",left:"auto"})):(this.instance.cancelHelperRemoval=!1,this.instance._trigger("deactivate",b,e))})},drag:function(b,c){var d=a(this).data("draggable"),e=this,f=function(b){var c=this.offset.click.top,d=this.offset.click.left,e=this.positionAbs.top,f=this.positionAbs.left,g=b.height,h=b.width,i=b.top,j=b.left;return a.ui.isOver(e+c,f+d,i,j,g,h)};a.each(d.sortables,function(f){this.instance.positionAbs=d.positionAbs,this.instance.helperProportions=d.helperProportions,this.instance.offset.click=d.offset.click,this.instance._intersectsWith(this.instance.containerCache)?(this.instance.isOver||(this.instance.isOver=1,this.instance.currentItem=a(e).clone().removeAttr("id").appendTo(this.instance.element).data("sortable-item",!0),this.instance.options._helper=this.instance.options.helper,this.instance.options.helper=function(){return c.helper[0]},b.target=this.instance.currentItem[0],this.instance._mouseCapture(b,!0),this.instance._mouseStart(b,!0,!0),this.instance.offset.click.top=d.offset.click.top,this.instance.offset.click.left=d.offset.click.left,this.instance.offset.parent.left-=d.offset.parent.left-this.instance.offset.parent.left,this.instance.offset.parent.top-=d.offset.parent.top-this.instance.offset.parent.top,d._trigger("toSortable",b),d.dropped=this.instance.element,d.currentItem=d.element,this.instance.fromOutside=d),this.instance.currentItem&&this.instance._mouseDrag(b)):this.instance.isOver&&(this.instance.isOver=0,this.instance.cancelHelperRemoval=!0,this.instance.options.revert=!1,this.instance._trigger("out",b,this.instance._uiHash(this.instance)),this.instance._mouseStop(b,!0),this.instance.options.helper=this.instance.options._helper,this.instance.currentItem.remove(),this.instance.placeholder&&this.instance.placeholder.remove(),d._trigger("fromSortable",b),d.dropped=!1)})}}),a.ui.plugin.add("draggable","cursor",{start:function(b,c){var d=a("body"),e=a(this).data("draggable").options;d.css("cursor")&&(e._cursor=d.css("cursor")),d.css("cursor",e.cursor)},stop:function(b,c){var d=a(this).data("draggable").options;d._cursor&&a("body").css("cursor",d._cursor)}}),a.ui.plugin.add("draggable","opacity",{start:function(b,c){var d=a(c.helper),e=a(this).data("draggable").options;d.css("opacity")&&(e._opacity=d.css("opacity")),d.css("opacity",e.opacity)},stop:function(b,c){var d=a(this).data("draggable").options;d._opacity&&a(c.helper).css("opacity",d._opacity)}}),a.ui.plugin.add("draggable","scroll",{start:function(b,c){var d=a(this).data("draggable");d.scrollParent[0]!=document&&d.scrollParent[0].tagName!="HTML"&&(d.overflowOffset=d.scrollParent.offset())},drag:function(b,c){var d=a(this).data("draggable"),e=d.options,f=!1;if(d.scrollParent[0]!=document&&d.scrollParent[0].tagName!="HTML"){if(!e.axis||e.axis!="x")d.overflowOffset.top+d.scrollParent[0].offsetHeight-b.pageY<e.scrollSensitivity?d.scrollParent[0].scrollTop=f=d.scrollParent[0].scrollTop+e.scrollSpeed:b.pageY-d.overflowOffset.top<e.scrollSensitivity&&(d.scrollParent[0].scrollTop=f=d.scrollParent[0].scrollTop-e.scrollSpeed);if(!e.axis||e.axis!="y")d.overflowOffset.left+d.scrollParent[0].offsetWidth-b.pageX<e.scrollSensitivity?d.scrollParent[0].scrollLeft=f=d.scrollParent[0].scrollLeft+e.scrollSpeed:b.pageX-d.overflowOffset.left<e.scrollSensitivity&&(d.scrollParent[0].scrollLeft=f=d.scrollParent[0].scrollLeft-e.scrollSpeed)}else{if(!e.axis||e.axis!="x")b.pageY-a(document).scrollTop()<e.scrollSensitivity?f=a(document).scrollTop(a(document).scrollTop()-e.scrollSpeed):a(window).height()-(b.pageY-a(document).scrollTop())<e.scrollSensitivity&&(f=a(document).scrollTop(a(document).scrollTop()+e.scrollSpeed));if(!e.axis||e.axis!="y")b.pageX-a(document).scrollLeft()<e.scrollSensitivity?f=a(document).scrollLeft(a(document).scrollLeft()-e.scrollSpeed):a(window).width()-(b.pageX-a(document).scrollLeft())<e.scrollSensitivity&&(f=a(document).scrollLeft(a(document).scrollLeft()+e.scrollSpeed))}f!==!1&&a.ui.ddmanager&&!e.dropBehaviour&&a.ui.ddmanager.prepareOffsets(d,b)}}),a.ui.plugin.add("draggable","snap",{start:function(b,c){var d=a(this).data("draggable"),e=d.options;d.snapElements=[],a(e.snap.constructor!=String?e.snap.items||":data(draggable)":e.snap).each(function(){var b=a(this),c=b.offset();this!=d.element[0]&&d.snapElements.push({item:this,width:b.outerWidth(),height:b.outerHeight(),top:c.top,left:c.left})})},drag:function(b,c){var d=a(this).data("draggable"),e=d.options,f=e.snapTolerance,g=c.offset.left,h=g+d.helperProportions.width,i=c.offset.top,j=i+d.helperProportions.height;for(var k=d.snapElements.length-1;k>=0;k--){var l=d.snapElements[k].left,m=l+d.snapElements[k].width,n=d.snapElements[k].top,o=n+d.snapElements[k].height;if(!(l-f<g&&g<m+f&&n-f<i&&i<o+f||l-f<g&&g<m+f&&n-f<j&&j<o+f||l-f<h&&h<m+f&&n-f<i&&i<o+f||l-f<h&&h<m+f&&n-f<j&&j<o+f)){d.snapElements[k].snapping&&d.options.snap.release&&d.options.snap.release.call(d.element,b,a.extend(d._uiHash(),{snapItem:d.snapElements[k].item})),d.snapElements[k].snapping=!1;continue}if(e.snapMode!="inner"){var p=Math.abs(n-j)<=f,q=Math.abs(o-i)<=f,r=Math.abs(l-h)<=f,s=Math.abs(m-g)<=f;p&&(c.position.top=d._convertPositionTo("relative",{top:n-d.helperProportions.height,left:0}).top-d.margins.top),q&&(c.position.top=d._convertPositionTo("relative",{top:o,left:0}).top-d.margins.top),r&&(c.position.left=d._convertPositionTo("relative",{top:0,left:l-d.helperProportions.width}).left-d.margins.left),s&&(c.position.left=d._convertPositionTo("relative",{top:0,left:m}).left-d.margins.left)}var t=p||q||r||s;if(e.snapMode!="outer"){var p=Math.abs(n-i)<=f,q=Math.abs(o-j)<=f,r=Math.abs(l-g)<=f,s=Math.abs(m-h)<=f;p&&(c.position.top=d._convertPositionTo("relative",{top:n,left:0}).top-d.margins.top),q&&(c.position.top=d._convertPositionTo("relative",{top:o-d.helperProportions.height,left:0}).top-d.margins.top),r&&(c.position.left=d._convertPositionTo("relative",{top:0,left:l}).left-d.margins.left),s&&(c.position.left=d._convertPositionTo("relative",{top:0,left:m-d.helperProportions.width}).left-d.margins.left)}!d.snapElements[k].snapping&&(p||q||r||s||t)&&d.options.snap.snap&&d.options.snap.snap.call(d.element,b,a.extend(d._uiHash(),{snapItem:d.snapElements[k].item})),d.snapElements[k].snapping=p||q||r||s||t}}}),a.ui.plugin.add("draggable","stack",{start:function(b,c){var d=a(this).data("draggable").options,e=a.makeArray(a(d.stack)).sort(function(b,c){return(parseInt(a(b).css("zIndex"),10)||0)-(parseInt(a(c).css("zIndex"),10)||0)});if(!e.length)return;var f=parseInt(e[0].style.zIndex)||0;a(e).each(function(a){this.style.zIndex=f+a}),this[0].style.zIndex=f+e.length}}),a.ui.plugin.add("draggable","zIndex",{start:function(b,c){var d=a(c.helper),e=a(this).data("draggable").options;d.css("zIndex")&&(e._zIndex=d.css("zIndex")),d.css("zIndex",e.zIndex)},stop:function(b,c){var d=a(this).data("draggable").options;d._zIndex&&a(c.helper).css("zIndex",d._zIndex)}})})(jQuery);;/*! jQuery UI - v1.8.23 - 2012-08-15
    +-* https://github.com/jquery/jquery-ui
    +-* Includes: jquery.ui.droppable.js
    +-* Copyright (c) 2012 AUTHORS.txt; Licensed MIT, GPL */
    +-(function(a,b){a.widget("ui.droppable",{widgetEventPrefix:"drop",options:{accept:"*",activeClass:!1,addClasses:!0,greedy:!1,hoverClass:!1,scope:"default",tolerance:"intersect"},_create:function(){var b=this.options,c=b.accept;this.isover=0,this.isout=1,this.accept=a.isFunction(c)?c:function(a){return a.is(c)},this.proportions={width:this.element[0].offsetWidth,height:this.element[0].offsetHeight},a.ui.ddmanager.droppables[b.scope]=a.ui.ddmanager.droppables[b.scope]||[],a.ui.ddmanager.droppables[b.scope].push(this),b.addClasses&&this.element.addClass("ui-droppable")},destroy:function(){var b=a.ui.ddmanager.droppables[this.options.scope];for(var c=0;c<b.length;c++)b[c]==this&&b.splice(c,1);return this.element.removeClass("ui-droppable ui-droppable-disabled").removeData("droppable").unbind(".droppable"),this},_setOption:function(b,c){b=="accept"&&(this.accept=a.isFunction(c)?c:function(a){return a.is(c)}),a.Widget.prototype._setOption.apply(this,arguments)},_activate:function(b){var c=a.ui.ddmanager.current;this.options.activeClass&&this.element.addClass(this.options.activeClass),c&&this._trigger("activate",b,this.ui(c))},_deactivate:function(b){var c=a.ui.ddmanager.current;this.options.activeClass&&this.element.removeClass(this.options.activeClass),c&&this._trigger("deactivate",b,this.ui(c))},_over:function(b){var c=a.ui.ddmanager.current;if(!c||(c.currentItem||c.element)[0]==this.element[0])return;this.accept.call(this.element[0],c.currentItem||c.element)&&(this.options.hoverClass&&this.element.addClass(this.options.hoverClass),this._trigger("over",b,this.ui(c)))},_out:function(b){var c=a.ui.ddmanager.current;if(!c||(c.currentItem||c.element)[0]==this.element[0])return;this.accept.call(this.element[0],c.currentItem||c.element)&&(this.options.hoverClass&&this.element.removeClass(this.options.hoverClass),this._trigger("out",b,this.ui(c)))},_drop:function(b,c){var d=c||a.ui.ddmanager.current;if(!d||(d.currentItem||d.element)[0]==this.element[0])return!1;var e=!1;return this.element.find(":data(droppable)").not(".ui-draggable-dragging").each(function(){var b=a.data(this,"droppable");if(b.options.greedy&&!b.options.disabled&&b.options.scope==d.options.scope&&b.accept.call(b.element[0],d.currentItem||d.element)&&a.ui.intersect(d,a.extend(b,{offset:b.element.offset()}),b.options.tolerance))return e=!0,!1}),e?!1:this.accept.call(this.element[0],d.currentItem||d.element)?(this.options.activeClass&&this.element.removeClass(this.options.activeClass),this.options.hoverClass&&this.element.removeClass(this.options.hoverClass),this._trigger("drop",b,this.ui(d)),this.element):!1},ui:function(a){return{draggable:a.currentItem||a.element,helper:a.helper,position:a.position,offset:a.positionAbs}}}),a.extend(a.ui.droppable,{version:"1.8.23"}),a.ui.intersect=function(b,c,d){if(!c.offset)return!1;var e=(b.positionAbs||b.position.absolute).left,f=e+b.helperProportions.width,g=(b.positionAbs||b.position.absolute).top,h=g+b.helperProportions.height,i=c.offset.left,j=i+c.proportions.width,k=c.offset.top,l=k+c.proportions.height;switch(d){case"fit":return i<=e&&f<=j&&k<=g&&h<=l;case"intersect":return i<e+b.helperProportions.width/2&&f-b.helperProportions.width/2<j&&k<g+b.helperProportions.height/2&&h-b.helperProportions.height/2<l;case"pointer":var m=(b.positionAbs||b.position.absolute).left+(b.clickOffset||b.offset.click).left,n=(b.positionAbs||b.position.absolute).top+(b.clickOffset||b.offset.click).top,o=a.ui.isOver(n,m,k,i,c.proportions.height,c.proportions.width);return o;case"touch":return(g>=k&&g<=l||h>=k&&h<=l||g<k&&h>l)&&(e>=i&&e<=j||f>=i&&f<=j||e<i&&f>j);default:return!1}},a.ui.ddmanager={current:null,droppables:{"default":[]},prepareOffsets:function(b,c){var d=a.ui.ddmanager.droppables[b.options.scope]||[],e=c?c.type:null,f=(b.currentItem||b.element).find(":data(droppable)").andSelf();g:for(var h=0;h<d.length;h++){if(d[h].options.disabled||b&&!d[h].accept.call(d[h].element[0],b.currentItem||b.element))continue;for(var i=0;i<f.length;i++)if(f[i]==d[h].element[0]){d[h].proportions.height=0;continue g}d[h].visible=d[h].element.css("display")!="none";if(!d[h].visible)continue;e=="mousedown"&&d[h]._activate.call(d[h],c),d[h].offset=d[h].element.offset(),d[h].proportions={width:d[h].element[0].offsetWidth,height:d[h].element[0].offsetHeight}}},drop:function(b,c){var d=!1;return a.each(a.ui.ddmanager.droppables[b.options.scope]||[],function(){if(!this.options)return;!this.options.disabled&&this.visible&&a.ui.intersect(b,this,this.options.tolerance)&&(d=this._drop.call(this,c)||d),!this.options.disabled&&this.visible&&this.accept.call(this.element[0],b.currentItem||b.element)&&(this.isout=1,this.isover=0,this._deactivate.call(this,c))}),d},dragStart:function(b,c){b.element.parents(":not(body,html)").bind("scroll.droppable",function(){b.options.refreshPositions||a.ui.ddmanager.prepareOffsets(b,c)})},drag:function(b,c){b.options.refreshPositions&&a.ui.ddmanager.prepareOffsets(b,c),a.each(a.ui.ddmanager.droppables[b.options.scope]||[],function(){if(this.options.disabled||this.greedyChild||!this.visible)return;var d=a.ui.intersect(b,this,this.options.tolerance),e=!d&&this.isover==1?"isout":d&&this.isover==0?"isover":null;if(!e)return;var f;if(this.options.greedy){var g=this.element.parents(":data(droppable):eq(0)");g.length&&(f=a.data(g[0],"droppable"),f.greedyChild=e=="isover"?1:0)}f&&e=="isover"&&(f.isover=0,f.isout=1,f._out.call(f,c)),this[e]=1,this[e=="isout"?"isover":"isout"]=0,this[e=="isover"?"_over":"_out"].call(this,c),f&&e=="isout"&&(f.isout=0,f.isover=1,f._over.call(f,c))})},dragStop:function(b,c){b.element.parents(":not(body,html)").unbind("scroll.droppable"),b.options.refreshPositions||a.ui.ddmanager.prepareOffsets(b,c)}}})(jQuery);;/*! jQuery UI - v1.8.23 - 2012-08-15
    +-* https://github.com/jquery/jquery-ui
    +-* Includes: jquery.ui.resizable.js
    +-* Copyright (c) 2012 AUTHORS.txt; Licensed MIT, GPL */
    +-(function(a,b){a.widget("ui.resizable",a.ui.mouse,{widgetEventPrefix:"resize",options:{alsoResize:!1,animate:!1,animateDuration:"slow",animateEasing:"swing",aspectRatio:!1,autoHide:!1,containment:!1,ghost:!1,grid:!1,handles:"e,s,se",helper:!1,maxHeight:null,maxWidth:null,minHeight:10,minWidth:10,zIndex:1e3},_create:function(){var b=this,c=this.options;this.element.addClass("ui-resizable"),a.extend(this,{_aspectRatio:!!c.aspectRatio,aspectRatio:c.aspectRatio,originalElement:this.element,_proportionallyResizeElements:[],_helper:c.helper||c.ghost||c.animate?c.helper||"ui-resizable-helper":null}),this.element[0].nodeName.match(/canvas|textarea|input|select|button|img/i)&&(this.element.wrap(a('<div class="ui-wrapper" style="overflow: hidden;"></div>').css({position:this.element.css("position"),width:this.element.outerWidth(),height:this.element.outerHeight(),top:this.element.css("top"),left:this.element.css("left")})),this.element=this.element.parent().data("resizable",this.element.data("resizable")),this.elementIsWrapper=!0,this.element.css({marginLeft:this.originalElement.css("marginLeft"),marginTop:this.originalElement.css("marginTop"),marginRight:this.originalElement.css("marginRight"),marginBottom:this.originalElement.css("marginBottom")}),this.originalElement.css({marginLeft:0,marginTop:0,marginRight:0,marginBottom:0}),this.originalResizeStyle=this.originalElement.css("resize"),this.originalElement.css("resize","none"),this._proportionallyResizeElements.push(this.originalElement.css({position:"static",zoom:1,display:"block"})),this.originalElement.css({margin:this.originalElement.css("margin")}),this._proportionallyResize()),this.handles=c.handles||(a(".ui-resizable-handle",this.element).length?{n:".ui-resizable-n",e:".ui-resizable-e",s:".ui-resizable-s",w:".ui-resizable-w",se:".ui-resizable-se",sw:".ui-resizable-sw",ne:".ui-resizable-ne",nw:".ui-resizable-nw"}:"e,s,se");if(this.handles.constructor==String){this.handles=="all"&&(this.handles="n,e,s,w,se,sw,ne,nw");var d=this.handles.split(",");this.handles={};for(var e=0;e<d.length;e++){var f=a.trim(d[e]),g="ui-resizable-"+f,h=a('<div class="ui-resizable-handle '+g+'"></div>');h.css({zIndex:c.zIndex}),"se"==f&&h.addClass("ui-icon ui-icon-gripsmall-diagonal-se"),this.handles[f]=".ui-resizable-"+f,this.element.append(h)}}this._renderAxis=function(b){b=b||this.element;for(var c in this.handles){this.handles[c].constructor==String&&(this.handles[c]=a(this.handles[c],this.element).show());if(this.elementIsWrapper&&this.originalElement[0].nodeName.match(/textarea|input|select|button/i)){var d=a(this.handles[c],this.element),e=0;e=/sw|ne|nw|se|n|s/.test(c)?d.outerHeight():d.outerWidth();var f=["padding",/ne|nw|n/.test(c)?"Top":/se|sw|s/.test(c)?"Bottom":/^e$/.test(c)?"Right":"Left"].join("");b.css(f,e),this._proportionallyResize()}if(!a(this.handles[c]).length)continue}},this._renderAxis(this.element),this._handles=a(".ui-resizable-handle",this.element).disableSelection(),this._handles.mouseover(function(){if(!b.resizing){if(this.className)var a=this.className.match(/ui-resizable-(se|sw|ne|nw|n|e|s|w)/i);b.axis=a&&a[1]?a[1]:"se"}}),c.autoHide&&(this._handles.hide(),a(this.element).addClass("ui-resizable-autohide").hover(function(){if(c.disabled)return;a(this).removeClass("ui-resizable-autohide"),b._handles.show()},function(){if(c.disabled)return;b.resizing||(a(this).addClass("ui-resizable-autohide"),b._handles.hide())})),this._mouseInit()},destroy:function(){this._mouseDestroy();var b=function(b){a(b).removeClass("ui-resizable ui-resizable-disabled ui-resizable-resizing").removeData("resizable").unbind(".resizable").find(".ui-resizable-handle").remove()};if(this.elementIsWrapper){b(this.element);var c=this.element;c.after(this.originalElement.css({position:c.css("position"),width:c.outerWidth(),height:c.outerHeight(),top:c.css("top"),left:c.css("left")})).remove()}return this.originalElement.css("resize",this.originalResizeStyle),b(this.originalElement),this},_mouseCapture:function(b){var c=!1;for(var d in this.handles)a(this.handles[d])[0]==b.target&&(c=!0);return!this.options.disabled&&c},_mouseStart:function(b){var d=this.options,e=this.element.position(),f=this.element;this.resizing=!0,this.documentScroll={top:a(document).scrollTop(),left:a(document).scrollLeft()},(f.is(".ui-draggable")||/absolute/.test(f.css("position")))&&f.css({position:"absolute",top:e.top,left:e.left}),this._renderProxy();var g=c(this.helper.css("left")),h=c(this.helper.css("top"));d.containment&&(g+=a(d.containment).scrollLeft()||0,h+=a(d.containment).scrollTop()||0),this.offset=this.helper.offset(),this.position={left:g,top:h},this.size=this._helper?{width:f.outerWidth(),height:f.outerHeight()}:{width:f.width(),height:f.height()},this.originalSize=this._helper?{width:f.outerWidth(),height:f.outerHeight()}:{width:f.width(),height:f.height()},this.originalPosition={left:g,top:h},this.sizeDiff={width:f.outerWidth()-f.width(),height:f.outerHeight()-f.height()},this.originalMousePosition={left:b.pageX,top:b.pageY},this.aspectRatio=typeof d.aspectRatio=="number"?d.aspectRatio:this.originalSize.width/this.originalSize.height||1;var i=a(".ui-resizable-"+this.axis).css("cursor");return a("body").css("cursor",i=="auto"?this.axis+"-resize":i),f.addClass("ui-resizable-resizing"),this._propagate("start",b),!0},_mouseDrag:function(b){var c=this.helper,d=this.options,e={},f=this,g=this.originalMousePosition,h=this.axis,i=b.pageX-g.left||0,j=b.pageY-g.top||0,k=this._change[h];if(!k)return!1;var l=k.apply(this,[b,i,j]),m=a.browser.msie&&a.browser.version<7,n=this.sizeDiff;this._updateVirtualBoundaries(b.shiftKey);if(this._aspectRatio||b.shiftKey)l=this._updateRatio(l,b);return l=this._respectSize(l,b),this._propagate("resize",b),c.css({top:this.position.top+"px",left:this.position.left+"px",width:this.size.width+"px",height:this.size.height+"px"}),!this._helper&&this._proportionallyResizeElements.length&&this._proportionallyResize(),this._updateCache(l),this._trigger("resize",b,this.ui()),!1},_mouseStop:function(b){this.resizing=!1;var c=this.options,d=this;if(this._helper){var e=this._proportionallyResizeElements,f=e.length&&/textarea/i.test(e[0].nodeName),g=f&&a.ui.hasScroll(e[0],"left")?0:d.sizeDiff.height,h=f?0:d.sizeDiff.width,i={width:d.helper.width()-h,height:d.helper.height()-g},j=parseInt(d.element.css("left"),10)+(d.position.left-d.originalPosition.left)||null,k=parseInt(d.element.css("top"),10)+(d.position.top-d.originalPosition.top)||null;c.animate||this.element.css(a.extend(i,{top:k,left:j})),d.helper.height(d.size.height),d.helper.width(d.size.width),this._helper&&!c.animate&&this._proportionallyResize()}return a("body").css("cursor","auto"),this.element.removeClass("ui-resizable-resizing"),this._propagate("stop",b),this._helper&&this.helper.remove(),!1},_updateVirtualBoundaries:function(a){var b=this.options,c,e,f,g,h;h={minWidth:d(b.minWidth)?b.minWidth:0,maxWidth:d(b.maxWidth)?b.maxWidth:Infinity,minHeight:d(b.minHeight)?b.minHeight:0,maxHeight:d(b.maxHeight)?b.maxHeight:Infinity};if(this._aspectRatio||a)c=h.minHeight*this.aspectRatio,f=h.minWidth/this.aspectRatio,e=h.maxHeight*this.aspectRatio,g=h.maxWidth/this.aspectRatio,c>h.minWidth&&(h.minWidth=c),f>h.minHeight&&(h.minHeight=f),e<h.maxWidth&&(h.maxWidth=e),g<h.maxHeight&&(h.maxHeight=g);this._vBoundaries=h},_updateCache:function(a){var b=this.options;this.offset=this.helper.offset(),d(a.left)&&(this.position.left=a.left),d(a.top)&&(this.position.top=a.top),d(a.height)&&(this.size.height=a.height),d(a.width)&&(this.size.width=a.width)},_updateRatio:function(a,b){var c=this.options,e=this.position,f=this.size,g=this.axis;return d(a.height)?a.width=a.height*this.aspectRatio:d(a.width)&&(a.height=a.width/this.aspectRatio),g=="sw"&&(a.left=e.left+(f.width-a.width),a.top=null),g=="nw"&&(a.top=e.top+(f.height-a.height),a.left=e.left+(f.width-a.width)),a},_respectSize:function(a,b){var c=this.helper,e=this._vBoundaries,f=this._aspectRatio||b.shiftKey,g=this.axis,h=d(a.width)&&e.maxWidth&&e.maxWidth<a.width,i=d(a.height)&&e.maxHeight&&e.maxHeight<a.height,j=d(a.width)&&e.minWidth&&e.minWidth>a.width,k=d(a.height)&&e.minHeight&&e.minHeight>a.height;j&&(a.width=e.minWidth),k&&(a.height=e.minHeight),h&&(a.width=e.maxWidth),i&&(a.height=e.maxHeight);var l=this.originalPosition.left+this.originalSize.width,m=this.position.top+this.size.height,n=/sw|nw|w/.test(g),o=/nw|ne|n/.test(g);j&&n&&(a.left=l-e.minWidth),h&&n&&(a.left=l-e.maxWidth),k&&o&&(a.top=m-e.minHeight),i&&o&&(a.top=m-e.maxHeight);var p=!a.width&&!a.height;return p&&!a.left&&a.top?a.top=null:p&&!a.top&&a.left&&(a.left=null),a},_proportionallyResize:function(){var b=this.options;if(!this._proportionallyResizeElements.length)return;var c=this.helper||this.element;for(var d=0;d<this._proportionallyResizeElements.length;d++){var e=this._proportionallyResizeElements[d];if(!this.borderDif){var f=[e.css("borderTopWidth"),e.css("borderRightWidth"),e.css("borderBottomWidth"),e.css("borderLeftWidth")],g=[e.css("paddingTop"),e.css("paddingRight"),e.css("paddingBottom"),e.css("paddingLeft")];this.borderDif=a.map(f,function(a,b){var c=parseInt(a,10)||0,d=parseInt(g[b],10)||0;return c+d})}if(!a.browser.msie||!a(c).is(":hidden")&&!a(c).parents(":hidden").length)e.css({height:c.height()-this.borderDif[0]-this.borderDif[2]||0,width:c.width()-this.borderDif[1]-this.borderDif[3]||0});else continue}},_renderProxy:function(){var b=this.element,c=this.options;this.elementOffset=b.offset();if(this._helper){this.helper=this.helper||a('<div style="overflow:hidden;"></div>');var d=a.browser.msie&&a.browser.version<7,e=d?1:0,f=d?2:-1;this.helper.addClass(this._helper).css({width:this.element.outerWidth()+f,height:this.element.outerHeight()+f,position:"absolute",left:this.elementOffset.left-e+"px",top:this.elementOffset.top-e+"px",zIndex:++c.zIndex}),this.helper.appendTo("body").disableSelection()}else this.helper=this.element},_change:{e:function(a,b,c){return{width:this.originalSize.width+b}},w:function(a,b,c){var d=this.options,e=this.originalSize,f=this.originalPosition;return{left:f.left+b,width:e.width-b}},n:function(a,b,c){var d=this.options,e=this.originalSize,f=this.originalPosition;return{top:f.top+c,height:e.height-c}},s:function(a,b,c){return{height:this.originalSize.height+c}},se:function(b,c,d){return a.extend(this._change.s.apply(this,arguments),this._change.e.apply(this,[b,c,d]))},sw:function(b,c,d){return a.extend(this._change.s.apply(this,arguments),this._change.w.apply(this,[b,c,d]))},ne:function(b,c,d){return a.extend(this._change.n.apply(this,arguments),this._change.e.apply(this,[b,c,d]))},nw:function(b,c,d){return a.extend(this._change.n.apply(this,arguments),this._change.w.apply(this,[b,c,d]))}},_propagate:function(b,c){a.ui.plugin.call(this,b,[c,this.ui()]),b!="resize"&&this._trigger(b,c,this.ui())},plugins:{},ui:function(){return{originalElement:this.originalElement,element:this.element,helper:this.helper,position:this.position,size:this.size,originalSize:this.originalSize,originalPosition:this.originalPosition}}}),a.extend(a.ui.resizable,{version:"1.8.23"}),a.ui.plugin.add("resizable","alsoResize",{start:function(b,c){var d=a(this).data("resizable"),e=d.options,f=function(b){a(b).each(function(){var b=a(this);b.data("resizable-alsoresize",{width:parseInt(b.width(),10),height:parseInt(b.height(),10),left:parseInt(b.css("left"),10),top:parseInt(b.css("top"),10)})})};typeof e.alsoResize=="object"&&!e.alsoResize.parentNode?e.alsoResize.length?(e.alsoResize=e.alsoResize[0],f(e.alsoResize)):a.each(e.alsoResize,function(a){f(a)}):f(e.alsoResize)},resize:function(b,c){var d=a(this).data("resizable"),e=d.options,f=d.originalSize,g=d.originalPosition,h={height:d.size.height-f.height||0,width:d.size.width-f.width||0,top:d.position.top-g.top||0,left:d.position.left-g.left||0},i=function(b,d){a(b).each(function(){var b=a(this),e=a(this).data("resizable-alsoresize"),f={},g=d&&d.length?d:b.parents(c.originalElement[0]).length?["width","height"]:["width","height","top","left"];a.each(g,function(a,b){var c=(e[b]||0)+(h[b]||0);c&&c>=0&&(f[b]=c||null)}),b.css(f)})};typeof e.alsoResize=="object"&&!e.alsoResize.nodeType?a.each(e.alsoResize,function(a,b){i(a,b)}):i(e.alsoResize)},stop:function(b,c){a(this).removeData("resizable-alsoresize")}}),a.ui.plugin.add("resizable","animate",{stop:function(b,c){var d=a(this).data("resizable"),e=d.options,f=d._proportionallyResizeElements,g=f.length&&/textarea/i.test(f[0].nodeName),h=g&&a.ui.hasScroll(f[0],"left")?0:d.sizeDiff.height,i=g?0:d.sizeDiff.width,j={width:d.size.width-i,height:d.size.height-h},k=parseInt(d.element.css("left"),10)+(d.position.left-d.originalPosition.left)||null,l=parseInt(d.element.css("top"),10)+(d.position.top-d.originalPosition.top)||null;d.element.animate(a.extend(j,l&&k?{top:l,left:k}:{}),{duration:e.animateDuration,easing:e.animateEasing,step:function(){var c={width:parseInt(d.element.css("width"),10),height:parseInt(d.element.css("height"),10),top:parseInt(d.element.css("top"),10),left:parseInt(d.element.css("left"),10)};f&&f.length&&a(f[0]).css({width:c.width,height:c.height}),d._updateCache(c),d._propagate("resize",b)}})}}),a.ui.plugin.add("resizable","containment",{start:function(b,d){var e=a(this).data("resizable"),f=e.options,g=e.element,h=f.containment,i=h instanceof a?h.get(0):/parent/.test(h)?g.parent().get(0):h;if(!i)return;e.containerElement=a(i);if(/document/.test(h)||h==document)e.containerOffset={left:0,top:0},e.containerPosition={left:0,top:0},e.parentData={element:a(document),left:0,top:0,width:a(document).width(),height:a(document).height()||document.body.parentNode.scrollHeight};else{var j=a(i),k=[];a(["Top","Right","Left","Bottom"]).each(function(a,b){k[a]=c(j.css("padding"+b))}),e.containerOffset=j.offset(),e.containerPosition=j.position(),e.containerSize={height:j.innerHeight()-k[3],width:j.innerWidth()-k[1]};var l=e.containerOffset,m=e.containerSize.height,n=e.containerSize.width,o=a.ui.hasScroll(i,"left")?i.scrollWidth:n,p=a.ui.hasScroll(i)?i.scrollHeight:m;e.parentData={element:i,left:l.left,top:l.top,width:o,height:p}}},resize:function(b,c){var d=a(this).data("resizable"),e=d.options,f=d.containerSize,g=d.containerOffset,h=d.size,i=d.position,j=d._aspectRatio||b.shiftKey,k={top:0,left:0},l=d.containerElement;l[0]!=document&&/static/.test(l.css("position"))&&(k=g),i.left<(d._helper?g.left:0)&&(d.size.width=d.size.width+(d._helper?d.position.left-g.left:d.position.left-k.left),j&&(d.size.height=d.size.width/d.aspectRatio),d.position.left=e.helper?g.left:0),i.top<(d._helper?g.top:0)&&(d.size.height=d.size.height+(d._helper?d.position.top-g.top:d.position.top),j&&(d.size.width=d.size.height*d.aspectRatio),d.position.top=d._helper?g.top:0),d.offset.left=d.parentData.left+d.position.left,d.offset.top=d.parentData.top+d.position.top;var m=Math.abs((d._helper?d.offset.left-k.left:d.offset.left-k.left)+d.sizeDiff.width),n=Math.abs((d._helper?d.offset.top-k.top:d.offset.top-g.top)+d.sizeDiff.height),o=d.containerElement.get(0)==d.element.parent().get(0),p=/relative|absolute/.test(d.containerElement.css("position"));o&&p&&(m-=d.parentData.left),m+d.size.width>=d.parentData.width&&(d.size.width=d.parentData.width-m,j&&(d.size.height=d.size.width/d.aspectRatio)),n+d.size.height>=d.parentData.height&&(d.size.height=d.parentData.height-n,j&&(d.size.width=d.size.height*d.aspectRatio))},stop:function(b,c){var d=a(this).data("resizable"),e=d.options,f=d.position,g=d.containerOffset,h=d.containerPosition,i=d.containerElement,j=a(d.helper),k=j.offset(),l=j.outerWidth()-d.sizeDiff.width,m=j.outerHeight()-d.sizeDiff.height;d._helper&&!e.animate&&/relative/.test(i.css("position"))&&a(this).css({left:k.left-h.left-g.left,width:l,height:m}),d._helper&&!e.animate&&/static/.test(i.css("position"))&&a(this).css({left:k.left-h.left-g.left,width:l,height:m})}}),a.ui.plugin.add("resizable","ghost",{start:function(b,c){var d=a(this).data("resizable"),e=d.options,f=d.size;d.ghost=d.originalElement.clone(),d.ghost.css({opacity:.25,display:"block",position:"relative",height:f.height,width:f.width,margin:0,left:0,top:0}).addClass("ui-resizable-ghost").addClass(typeof e.ghost=="string"?e.ghost:""),d.ghost.appendTo(d.helper)},resize:function(b,c){var d=a(this).data("resizable"),e=d.options;d.ghost&&d.ghost.css({position:"relative",height:d.size.height,width:d.size.width})},stop:function(b,c){var d=a(this).data("resizable"),e=d.options;d.ghost&&d.helper&&d.helper.get(0).removeChild(d.ghost.get(0))}}),a.ui.plugin.add("resizable","grid",{resize:function(b,c){var d=a(this).data("resizable"),e=d.options,f=d.size,g=d.originalSize,h=d.originalPosition,i=d.axis,j=e._aspectRatio||b.shiftKey;e.grid=typeof e.grid=="number"?[e.grid,e.grid]:e.grid;var k=Math.round((f.width-g.width)/(e.grid[0]||1))*(e.grid[0]||1),l=Math.round((f.height-g.height)/(e.grid[1]||1))*(e.grid[1]||1);/^(se|s|e)$/.test(i)?(d.size.width=g.width+k,d.size.height=g.height+l):/^(ne)$/.test(i)?(d.size.width=g.width+k,d.size.height=g.height+l,d.position.top=h.top-l):/^(sw)$/.test(i)?(d.size.width=g.width+k,d.size.height=g.height+l,d.position.left=h.left-k):(d.size.width=g.width+k,d.size.height=g.height+l,d.position.top=h.top-l,d.position.left=h.left-k)}});var c=function(a){return parseInt(a,10)||0},d=function(a){return!isNaN(parseInt(a,10))}})(jQuery);;/*! jQuery UI - v1.8.23 - 2012-08-15
    +-* https://github.com/jquery/jquery-ui
    +-* Includes: jquery.ui.selectable.js
    +-* Copyright (c) 2012 AUTHORS.txt; Licensed MIT, GPL */
    +-(function(a,b){a.widget("ui.selectable",a.ui.mouse,{options:{appendTo:"body",autoRefresh:!0,distance:0,filter:"*",tolerance:"touch"},_create:function(){var b=this;this.element.addClass("ui-selectable"),this.dragged=!1;var c;this.refresh=function(){c=a(b.options.filter,b.element[0]),c.addClass("ui-selectee"),c.each(function(){var b=a(this),c=b.offset();a.data(this,"selectable-item",{element:this,$element:b,left:c.left,top:c.top,right:c.left+b.outerWidth(),bottom:c.top+b.outerHeight(),startselected:!1,selected:b.hasClass("ui-selected"),selecting:b.hasClass("ui-selecting"),unselecting:b.hasClass("ui-unselecting")})})},this.refresh(),this.selectees=c.addClass("ui-selectee"),this._mouseInit(),this.helper=a("<div class='ui-selectable-helper'></div>")},destroy:function(){return this.selectees.removeClass("ui-selectee").removeData("selectable-item"),this.element.removeClass("ui-selectable ui-selectable-disabled").removeData("selectable").unbind(".selectable"),this._mouseDestroy(),this},_mouseStart:function(b){var c=this;this.opos=[b.pageX,b.pageY];if(this.options.disabled)return;var d=this.options;this.selectees=a(d.filter,this.element[0]),this._trigger("start",b),a(d.appendTo).append(this.helper),this.helper.css({left:b.clientX,top:b.clientY,width:0,height:0}),d.autoRefresh&&this.refresh(),this.selectees.filter(".ui-selected").each(function(){var d=a.data(this,"selectable-item");d.startselected=!0,!b.metaKey&&!b.ctrlKey&&(d.$element.removeClass("ui-selected"),d.selected=!1,d.$element.addClass("ui-unselecting"),d.unselecting=!0,c._trigger("unselecting",b,{unselecting:d.element}))}),a(b.target).parents().andSelf().each(function(){var d=a.data(this,"selectable-item");if(d){var e=!b.metaKey&&!b.ctrlKey||!d.$element.hasClass("ui-selected");return d.$element.removeClass(e?"ui-unselecting":"ui-selected").addClass(e?"ui-selecting":"ui-unselecting"),d.unselecting=!e,d.selecting=e,d.selected=e,e?c._trigger("selecting",b,{selecting:d.element}):c._trigger("unselecting",b,{unselecting:d.element}),!1}})},_mouseDrag:function(b){var c=this;this.dragged=!0;if(this.options.disabled)return;var d=this.options,e=this.opos[0],f=this.opos[1],g=b.pageX,h=b.pageY;if(e>g){var i=g;g=e,e=i}if(f>h){var i=h;h=f,f=i}return this.helper.css({left:e,top:f,width:g-e,height:h-f}),this.selectees.each(function(){var i=a.data(this,"selectable-item");if(!i||i.element==c.element[0])return;var j=!1;d.tolerance=="touch"?j=!(i.left>g||i.right<e||i.top>h||i.bottom<f):d.tolerance=="fit"&&(j=i.left>e&&i.right<g&&i.top>f&&i.bottom<h),j?(i.selected&&(i.$element.removeClass("ui-selected"),i.selected=!1),i.unselecting&&(i.$element.removeClass("ui-unselecting"),i.unselecting=!1),i.selecting||(i.$element.addClass("ui-selecting"),i.selecting=!0,c._trigger("selecting",b,{selecting:i.element}))):(i.selecting&&((b.metaKey||b.ctrlKey)&&i.startselected?(i.$element.removeClass("ui-selecting"),i.selecting=!1,i.$element.addClass("ui-selected"),i.selected=!0):(i.$element.removeClass("ui-selecting"),i.selecting=!1,i.startselected&&(i.$element.addClass("ui-unselecting"),i.unselecting=!0),c._trigger("unselecting",b,{unselecting:i.element}))),i.selected&&!b.metaKey&&!b.ctrlKey&&!i.startselected&&(i.$element.removeClass("ui-selected"),i.selected=!1,i.$element.addClass("ui-unselecting"),i.unselecting=!0,c._trigger("unselecting",b,{unselecting:i.element})))}),!1},_mouseStop:function(b){var c=this;this.dragged=!1;var d=this.options;return a(".ui-unselecting",this.element[0]).each(function(){var d=a.data(this,"selectable-item");d.$element.removeClass("ui-unselecting"),d.unselecting=!1,d.startselected=!1,c._trigger("unselected",b,{unselected:d.element})}),a(".ui-selecting",this.element[0]).each(function(){var d=a.data(this,"selectable-item");d.$element.removeClass("ui-selecting").addClass("ui-selected"),d.selecting=!1,d.selected=!0,d.startselected=!0,c._trigger("selected",b,{selected:d.element})}),this._trigger("stop",b),this.helper.remove(),!1}}),a.extend(a.ui.selectable,{version:"1.8.23"})})(jQuery);;/*! jQuery UI - v1.8.23 - 2012-08-15
    +-* https://github.com/jquery/jquery-ui
    +-* Includes: jquery.ui.sortable.js
    +-* Copyright (c) 2012 AUTHORS.txt; Licensed MIT, GPL */
    +-(function(a,b){a.widget("ui.sortable",a.ui.mouse,{widgetEventPrefix:"sort",ready:!1,options:{appendTo:"parent",axis:!1,connectWith:!1,containment:!1,cursor:"auto",cursorAt:!1,dropOnEmpty:!0,forcePlaceholderSize:!1,forceHelperSize:!1,grid:!1,handle:!1,helper:"original",items:"> *",opacity:!1,placeholder:!1,revert:!1,scroll:!0,scrollSensitivity:20,scrollSpeed:20,scope:"default",tolerance:"intersect",zIndex:1e3},_create:function(){var a=this.options;this.containerCache={},this.element.addClass("ui-sortable"),this.refresh(),this.floating=this.items.length?a.axis==="x"||/left|right/.test(this.items[0].item.css("float"))||/inline|table-cell/.test(this.items[0].item.css("display")):!1,this.offset=this.element.offset(),this._mouseInit(),this.ready=!0},destroy:function(){a.Widget.prototype.destroy.call(this),this.element.removeClass("ui-sortable ui-sortable-disabled"),this._mouseDestroy();for(var b=this.items.length-1;b>=0;b--)this.items[b].item.removeData(this.widgetName+"-item");return this},_setOption:function(b,c){b==="disabled"?(this.options[b]=c,this.widget()[c?"addClass":"removeClass"]("ui-sortable-disabled")):a.Widget.prototype._setOption.apply(this,arguments)},_mouseCapture:function(b,c){var d=this;if(this.reverting)return!1;if(this.options.disabled||this.options.type=="static")return!1;this._refreshItems(b);var e=null,f=this,g=a(b.target).parents().each(function(){if(a.data(this,d.widgetName+"-item")==f)return e=a(this),!1});a.data(b.target,d.widgetName+"-item")==f&&(e=a(b.target));if(!e)return!1;if(this.options.handle&&!c){var h=!1;a(this.options.handle,e).find("*").andSelf().each(function(){this==b.target&&(h=!0)});if(!h)return!1}return this.currentItem=e,this._removeCurrentsFromItems(),!0},_mouseStart:function(b,c,d){var e=this.options,f=this;this.currentContainer=this,this.refreshPositions(),this.helper=this._createHelper(b),this._cacheHelperProportions(),this._cacheMargins(),this.scrollParent=this.helper.scrollParent(),this.offset=this.currentItem.offset(),this.offset={top:this.offset.top-this.margins.top,left:this.offset.left-this.margins.left},a.extend(this.offset,{click:{left:b.pageX-this.offset.left,top:b.pageY-this.offset.top},parent:this._getParentOffset(),relative:this._getRelativeOffset()}),this.helper.css("position","absolute"),this.cssPosition=this.helper.css("position"),this.originalPosition=this._generatePosition(b),this.originalPageX=b.pageX,this.originalPageY=b.pageY,e.cursorAt&&this._adjustOffsetFromHelper(e.cursorAt),this.domPosition={prev:this.currentItem.prev()[0],parent:this.currentItem.parent()[0]},this.helper[0]!=this.currentItem[0]&&this.currentItem.hide(),this._createPlaceholder(),e.containment&&this._setContainment(),e.cursor&&(a("body").css("cursor")&&(this._storedCursor=a("body").css("cursor")),a("body").css("cursor",e.cursor)),e.opacity&&(this.helper.css("opacity")&&(this._storedOpacity=this.helper.css("opacity")),this.helper.css("opacity",e.opacity)),e.zIndex&&(this.helper.css("zIndex")&&(this._storedZIndex=this.helper.css("zIndex")),this.helper.css("zIndex",e.zIndex)),this.scrollParent[0]!=document&&this.scrollParent[0].tagName!="HTML"&&(this.overflowOffset=this.scrollParent.offset()),this._trigger("start",b,this._uiHash()),this._preserveHelperProportions||this._cacheHelperProportions();if(!d)for(var g=this.containers.length-1;g>=0;g--)this.containers[g]._trigger("activate",b,f._uiHash(this));return a.ui.ddmanager&&(a.ui.ddmanager.current=this),a.ui.ddmanager&&!e.dropBehaviour&&a.ui.ddmanager.prepareOffsets(this,b),this.dragging=!0,this.helper.addClass("ui-sortable-helper"),this._mouseDrag(b),!0},_mouseDrag:function(b){this.position=this._generatePosition(b),this.positionAbs=this._convertPositionTo("absolute"),this.lastPositionAbs||(this.lastPositionAbs=this.positionAbs);if(this.options.scroll){var c=this.options,d=!1;this.scrollParent[0]!=document&&this.scrollParent[0].tagName!="HTML"?(this.overflowOffset.top+this.scrollParent[0].offsetHeight-b.pageY<c.scrollSensitivity?this.scrollParent[0].scrollTop=d=this.scrollParent[0].scrollTop+c.scrollSpeed:b.pageY-this.overflowOffset.top<c.scrollSensitivity&&(this.scrollParent[0].scrollTop=d=this.scrollParent[0].scrollTop-c.scrollSpeed),this.overflowOffset.left+this.scrollParent[0].offsetWidth-b.pageX<c.scrollSensitivity?this.scrollParent[0].scrollLeft=d=this.scrollParent[0].scrollLeft+c.scrollSpeed:b.pageX-this.overflowOffset.left<c.scrollSensitivity&&(this.scrollParent[0].scrollLeft=d=this.scrollParent[0].scrollLeft-c.scrollSpeed)):(b.pageY-a(document).scrollTop()<c.scrollSensitivity?d=a(document).scrollTop(a(document).scrollTop()-c.scrollSpeed):a(window).height()-(b.pageY-a(document).scrollTop())<c.scrollSensitivity&&(d=a(document).scrollTop(a(document).scrollTop()+c.scrollSpeed)),b.pageX-a(document).scrollLeft()<c.scrollSensitivity?d=a(document).scrollLeft(a(document).scrollLeft()-c.scrollSpeed):a(window).width()-(b.pageX-a(document).scrollLeft())<c.scrollSensitivity&&(d=a(document).scrollLeft(a(document).scrollLeft()+c.scrollSpeed))),d!==!1&&a.ui.ddmanager&&!c.dropBehaviour&&a.ui.ddmanager.prepareOffsets(this,b)}this.positionAbs=this._convertPositionTo("absolute");if(!this.options.axis||this.options.axis!="y")this.helper[0].style.left=this.position.left+"px";if(!this.options.axis||this.options.axis!="x")this.helper[0].style.top=this.position.top+"px";for(var e=this.items.length-1;e>=0;e--){var f=this.items[e],g=f.item[0],h=this._intersectsWithPointer(f);if(!h)continue;if(g!=this.currentItem[0]&&this.placeholder[h==1?"next":"prev"]()[0]!=g&&!a.ui.contains(this.placeholder[0],g)&&(this.options.type=="semi-dynamic"?!a.ui.contains(this.element[0],g):!0)){this.direction=h==1?"down":"up";if(this.options.tolerance=="pointer"||this._intersectsWithSides(f))this._rearrange(b,f);else break;this._trigger("change",b,this._uiHash());break}}return this._contactContainers(b),a.ui.ddmanager&&a.ui.ddmanager.drag(this,b),this._trigger("sort",b,this._uiHash()),this.lastPositionAbs=this.positionAbs,!1},_mouseStop:function(b,c){if(!b)return;a.ui.ddmanager&&!this.options.dropBehaviour&&a.ui.ddmanager.drop(this,b);if(this.options.revert){var d=this,e=d.placeholder.offset();d.reverting=!0,a(this.helper).animate({left:e.left-this.offset.parent.left-d.margins.left+(this.offsetParent[0]==document.body?0:this.offsetParent[0].scrollLeft),top:e.top-this.offset.parent.top-d.margins.top+(this.offsetParent[0]==document.body?0:this.offsetParent[0].scrollTop)},parseInt(this.options.revert,10)||500,function(){d._clear(b)})}else this._clear(b,c);return!1},cancel:function(){var b=this;if(this.dragging){this._mouseUp({target:null}),this.options.helper=="original"?this.currentItem.css(this._storedCSS).removeClass("ui-sortable-helper"):this.currentItem.show();for(var c=this.containers.length-1;c>=0;c--)this.containers[c]._trigger("deactivate",null,b._uiHash(this)),this.containers[c].containerCache.over&&(this.containers[c]._trigger("out",null,b._uiHash(this)),this.containers[c].containerCache.over=0)}return this.placeholder&&(this.placeholder[0].parentNode&&this.placeholder[0].parentNode.removeChild(this.placeholder[0]),this.options.helper!="original"&&this.helper&&this.helper[0].parentNode&&this.helper.remove(),a.extend(this,{helper:null,dragging:!1,reverting:!1,_noFinalSort:null}),this.domPosition.prev?a(this.domPosition.prev).after(this.currentItem):a(this.domPosition.parent).prepend(this.currentItem)),this},serialize:function(b){var c=this._getItemsAsjQuery(b&&b.connected),d=[];return b=b||{},a(c).each(function(){var c=(a(b.item||this).attr(b.attribute||"id")||"").match(b.expression||/(.+)[-=_](.+)/);c&&d.push((b.key||c[1]+"[]")+"="+(b.key&&b.expression?c[1]:c[2]))}),!d.length&&b.key&&d.push(b.key+"="),d.join("&")},toArray:function(b){var c=this._getItemsAsjQuery(b&&b.connected),d=[];return b=b||{},c.each(function(){d.push(a(b.item||this).attr(b.attribute||"id")||"")}),d},_intersectsWith:function(a){var b=this.positionAbs.left,c=b+this.helperProportions.width,d=this.positionAbs.top,e=d+this.helperProportions.height,f=a.left,g=f+a.width,h=a.top,i=h+a.height,j=this.offset.click.top,k=this.offset.click.left,l=d+j>h&&d+j<i&&b+k>f&&b+k<g;return this.options.tolerance=="pointer"||this.options.forcePointerForContainers||this.options.tolerance!="pointer"&&this.helperProportions[this.floating?"width":"height"]>a[this.floating?"width":"height"]?l:f<b+this.helperProportions.width/2&&c-this.helperProportions.width/2<g&&h<d+this.helperProportions.height/2&&e-this.helperProportions.height/2<i},_intersectsWithPointer:function(b){var c=this.options.axis==="x"||a.ui.isOverAxis(this.positionAbs.top+this.offset.click.top,b.top,b.height),d=this.options.axis==="y"||a.ui.isOverAxis(this.positionAbs.left+this.offset.click.left,b.left,b.width),e=c&&d,f=this._getDragVerticalDirection(),g=this._getDragHorizontalDirection();return e?this.floating?g&&g=="right"||f=="down"?2:1:f&&(f=="down"?2:1):!1},_intersectsWithSides:function(b){var c=a.ui.isOverAxis(this.positionAbs.top+this.offset.click.top,b.top+b.height/2,b.height),d=a.ui.isOverAxis(this.positionAbs.left+this.offset.click.left,b.left+b.width/2,b.width),e=this._getDragVerticalDirection(),f=this._getDragHorizontalDirection();return this.floating&&f?f=="right"&&d||f=="left"&&!d:e&&(e=="down"&&c||e=="up"&&!c)},_getDragVerticalDirection:function(){var a=this.positionAbs.top-this.lastPositionAbs.top;return a!=0&&(a>0?"down":"up")},_getDragHorizontalDirection:function(){var a=this.positionAbs.left-this.lastPositionAbs.left;return a!=0&&(a>0?"right":"left")},refresh:function(a){return this._refreshItems(a),this.refreshPositions(),this},_connectWith:function(){var a=this.options;return a.connectWith.constructor==String?[a.connectWith]:a.connectWith},_getItemsAsjQuery:function(b){var c=this,d=[],e=[],f=this._connectWith();if(f&&b)for(var g=f.length-1;g>=0;g--){var h=a(f[g]);for(var i=h.length-1;i>=0;i--){var j=a.data(h[i],this.widgetName);j&&j!=this&&!j.options.disabled&&e.push([a.isFunction(j.options.items)?j.options.items.call(j.element):a(j.options.items,j.element).not(".ui-sortable-helper").not(".ui-sortable-placeholder"),j])}}e.push([a.isFunction(this.options.items)?this.options.items.call(this.element,null,{options:this.options,item:this.currentItem}):a(this.options.items,this.element).not(".ui-sortable-helper").not(".ui-sortable-placeholder"),this]);for(var g=e.length-1;g>=0;g--)e[g][0].each(function(){d.push(this)});return a(d)},_removeCurrentsFromItems:function(){var a=this.currentItem.find(":data("+this.widgetName+"-item)");for(var b=0;b<this.items.length;b++)for(var c=0;c<a.length;c++)a[c]==this.items[b].item[0]&&this.items.splice(b,1)},_refreshItems:function(b){this.items=[],this.containers=[this];var c=this.items,d=this,e=[[a.isFunction(this.options.items)?this.options.items.call(this.element[0],b,{item:this.currentItem}):a(this.options.items,this.element),this]],f=this._connectWith();if(f&&this.ready)for(var g=f.length-1;g>=0;g--){var h=a(f[g]);for(var i=h.length-1;i>=0;i--){var j=a.data(h[i],this.widgetName);j&&j!=this&&!j.options.disabled&&(e.push([a.isFunction(j.options.items)?j.options.items.call(j.element[0],b,{item:this.currentItem}):a(j.options.items,j.element),j]),this.containers.push(j))}}for(var g=e.length-1;g>=0;g--){var k=e[g][1],l=e[g][0];for(var i=0,m=l.length;i<m;i++){var n=a(l[i]);n.data(this.widgetName+"-item",k),c.push({item:n,instance:k,width:0,height:0,left:0,top:0})}}},refreshPositions:function(b){this.offsetParent&&this.helper&&(this.offset.parent=this._getParentOffset());for(var c=this.items.length-1;c>=0;c--){var d=this.items[c];if(d.instance!=this.currentContainer&&this.currentContainer&&d.item[0]!=this.currentItem[0])continue;var e=this.options.toleranceElement?a(this.options.toleranceElement,d.item):d.item;b||(d.width=e.outerWidth(),d.height=e.outerHeight());var f=e.offset();d.left=f.left,d.top=f.top}if(this.options.custom&&this.options.custom.refreshContainers)this.options.custom.refreshContainers.call(this);else for(var c=this.containers.length-1;c>=0;c--){var f=this.containers[c].element.offset();this.containers[c].containerCache.left=f.left,this.containers[c].containerCache.top=f.top,this.containers[c].containerCache.width=this.containers[c].element.outerWidth(),this.containers[c].containerCache.height=this.containers[c].element.outerHeight()}return this},_createPlaceholder:function(b){var c=b||this,d=c.options;if(!d.placeholder||d.placeholder.constructor==String){var e=d.placeholder;d.placeholder={element:function(){var b=a(document.createElement(c.currentItem[0].nodeName)).addClass(e||c.currentItem[0].className+" ui-sortable-placeholder").removeClass("ui-sortable-helper")[0];return e||(b.style.visibility="hidden"),b},update:function(a,b){if(e&&!d.forcePlaceholderSize)return;b.height()||b.height(c.currentItem.innerHeight()-parseInt(c.currentItem.css("paddingTop")||0,10)-parseInt(c.currentItem.css("paddingBottom")||0,10)),b.width()||b.width(c.currentItem.innerWidth()-parseInt(c.currentItem.css("paddingLeft")||0,10)-parseInt(c.currentItem.css("paddingRight")||0,10))}}}c.placeholder=a(d.placeholder.element.call(c.element,c.currentItem)),c.currentItem.after(c.placeholder),d.placeholder.update(c,c.placeholder)},_contactContainers:function(b){var c=null,d=null;for(var e=this.containers.length-1;e>=0;e--){if(a.ui.contains(this.currentItem[0],this.containers[e].element[0]))continue;if(this._intersectsWith(this.containers[e].containerCache)){if(c&&a.ui.contains(this.containers[e].element[0],c.element[0]))continue;c=this.containers[e],d=e}else this.containers[e].containerCache.over&&(this.containers[e]._trigger("out",b,this._uiHash(this)),this.containers[e].containerCache.over=0)}if(!c)return;if(this.containers.length===1)this.containers[d]._trigger("over",b,this._uiHash(this)),this.containers[d].containerCache.over=1;else if(this.currentContainer!=this.containers[d]){var f=1e4,g=null,h=this.positionAbs[this.containers[d].floating?"left":"top"];for(var i=this.items.length-1;i>=0;i--){if(!a.ui.contains(this.containers[d].element[0],this.items[i].item[0]))continue;var j=this.containers[d].floating?this.items[i].item.offset().left:this.items[i].item.offset().top;Math.abs(j-h)<f&&(f=Math.abs(j-h),g=this.items[i],this.direction=j-h>0?"down":"up")}if(!g&&!this.options.dropOnEmpty)return;this.currentContainer=this.containers[d],g?this._rearrange(b,g,null,!0):this._rearrange(b,null,this.containers[d].element,!0),this._trigger("change",b,this._uiHash()),this.containers[d]._trigger("change",b,this._uiHash(this)),this.options.placeholder.update(this.currentContainer,this.placeholder),this.containers[d]._trigger("over",b,this._uiHash(this)),this.containers[d].containerCache.over=1}},_createHelper:function(b){var c=this.options,d=a.isFunction(c.helper)?a(c.helper.apply(this.element[0],[b,this.currentItem])):c.helper=="clone"?this.currentItem.clone():this.currentItem;return d.parents("body").length||a(c.appendTo!="parent"?c.appendTo:this.currentItem[0].parentNode)[0].appendChild(d[0]),d[0]==this.currentItem[0]&&(this._storedCSS={width:this.currentItem[0].style.width,height:this.currentItem[0].style.height,position:this.currentItem.css("position"),top:this.currentItem.css("top"),left:this.currentItem.css("left")}),(d[0].style.width==""||c.forceHelperSize)&&d.width(this.currentItem.width()),(d[0].style.height==""||c.forceHelperSize)&&d.height(this.currentItem.height()),d},_adjustOffsetFromHelper:function(b){typeof b=="string"&&(b=b.split(" ")),a.isArray(b)&&(b={left:+b[0],top:+b[1]||0}),"left"in b&&(this.offset.click.left=b.left+this.margins.left),"right"in b&&(this.offset.click.left=this.helperProportions.width-b.right+this.margins.left),"top"in b&&(this.offset.click.top=b.top+this.margins.top),"bottom"in b&&(this.offset.click.top=this.helperProportions.height-b.bottom+this.margins.top)},_getParentOffset:function(){this.offsetParent=this.helper.offsetParent();var b=this.offsetParent.offset();this.cssPosition=="absolute"&&this.scrollParent[0]!=document&&a.ui.contains(this.scrollParent[0],this.offsetParent[0])&&(b.left+=this.scrollParent.scrollLeft(),b.top+=this.scrollParent.scrollTop());if(this.offsetParent[0]==document.body||this.offsetParent[0].tagName&&this.offsetParent[0].tagName.toLowerCase()=="html"&&a.browser.msie)b={top:0,left:0};return{top:b.top+(parseInt(this.offsetParent.css("borderTopWidth"),10)||0),left:b.left+(parseInt(this.offsetParent.css("borderLeftWidth"),10)||0)}},_getRelativeOffset:function(){if(this.cssPosition=="relative"){var a=this.currentItem.position();return{top:a.top-(parseInt(this.helper.css("top"),10)||0)+this.scrollParent.scrollTop(),left:a.left-(parseInt(this.helper.css("left"),10)||0)+this.scrollParent.scrollLeft()}}return{top:0,left:0}},_cacheMargins:function(){this.margins={left:parseInt(this.currentItem.css("marginLeft"),10)||0,top:parseInt(this.currentItem.css("marginTop"),10)||0}},_cacheHelperProportions:function(){this.helperProportions={width:this.helper.outerWidth(),height:this.helper.outerHeight()}},_setContainment:function(){var b=this.options;b.containment=="parent"&&(b.containment=this.helper[0].parentNode);if(b.containment=="document"||b.containment=="window")this.containment=[0-this.offset.relative.left-this.offset.parent.left,0-this.offset.relative.top-this.offset.parent.top,a(b.containment=="document"?document:window).width()-this.helperProportions.width-this.margins.left,(a(b.containment=="document"?document:window).height()||document.body.parentNode.scrollHeight)-this.helperProportions.height-this.margins.top];if(!/^(document|window|parent)$/.test(b.containment)){var c=a(b.containment)[0],d=a(b.containment).offset(),e=a(c).css("overflow")!="hidden";this.containment=[d.left+(parseInt(a(c).css("borderLeftWidth"),10)||0)+(parseInt(a(c).css("paddingLeft"),10)||0)-this.margins.left,d.top+(parseInt(a(c).css("borderTopWidth"),10)||0)+(parseInt(a(c).css("paddingTop"),10)||0)-this.margins.top,d.left+(e?Math.max(c.scrollWidth,c.offsetWidth):c.offsetWidth)-(parseInt(a(c).css("borderLeftWidth"),10)||0)-(parseInt(a(c).css("paddingRight"),10)||0)-this.helperProportions.width-this.margins.left,d.top+(e?Math.max(c.scrollHeight,c.offsetHeight):c.offsetHeight)-(parseInt(a(c).css("borderTopWidth"),10)||0)-(parseInt(a(c).css("paddingBottom"),10)||0)-this.helperProportions.height-this.margins.top]}},_convertPositionTo:function(b,c){c||(c=this.position);var d=b=="absolute"?1:-1,e=this.options,f=this.cssPosition=="absolute"&&(this.scrollParent[0]==document||!a.ui.contains(this.scrollParent[0],this.offsetParent[0]))?this.offsetParent:this.scrollParent,g=/(html|body)/i.test(f[0].tagName);return{top:c.top+this.offset.relative.top*d+this.offset.parent.top*d-(a.browser.safari&&this.cssPosition=="fixed"?0:(this.cssPosition=="fixed"?-this.scrollParent.scrollTop():g?0:f.scrollTop())*d),left:c.left+this.offset.relative.left*d+this.offset.parent.left*d-(a.browser.safari&&this.cssPosition=="fixed"?0:(this.cssPosition=="fixed"?-this.scrollParent.scrollLeft():g?0:f.scrollLeft())*d)}},_generatePosition:function(b){var c=this.options,d=this.cssPosition=="absolute"&&(this.scrollParent[0]==document||!a.ui.contains(this.scrollParent[0],this.offsetParent[0]))?this.offsetParent:this.scrollParent,e=/(html|body)/i.test(d[0].tagName);this.cssPosition=="relative"&&(this.scrollParent[0]==document||this.scrollParent[0]==this.offsetParent[0])&&(this.offset.relative=this._getRelativeOffset());var f=b.pageX,g=b.pageY;if(this.originalPosition){this.containment&&(b.pageX-this.offset.click.left<this.containment[0]&&(f=this.containment[0]+this.offset.click.left),b.pageY-this.offset.click.top<this.containment[1]&&(g=this.containment[1]+this.offset.click.top),b.pageX-this.offset.click.left>this.containment[2]&&(f=this.containment[2]+this.offset.click.left),b.pageY-this.offset.click.top>this.containment[3]&&(g=this.containment[3]+this.offset.click.top));if(c.grid){var h=this.originalPageY+Math.round((g-this.originalPageY)/c.grid[1])*c.grid[1];g=this.containment?h-this.offset.click.top<this.containment[1]||h-this.offset.click.top>this.containment[3]?h-this.offset.click.top<this.containment[1]?h+c.grid[1]:h-c.grid[1]:h:h;var i=this.originalPageX+Math.round((f-this.originalPageX)/c.grid[0])*c.grid[0];f=this.containment?i-this.offset.click.left<this.containment[0]||i-this.offset.click.left>this.containment[2]?i-this.offset.click.left<this.containment[0]?i+c.grid[0]:i-c.grid[0]:i:i}}return{top:g-this.offset.click.top-this.offset.relative.top-this.offset.parent.top+(a.browser.safari&&this.cssPosition=="fixed"?0:this.cssPosition=="fixed"?-this.scrollParent.scrollTop():e?0:d.scrollTop()),left:f-this.offset.click.left-this.offset.relative.left-this.offset.parent.left+(a.browser.safari&&this.cssPosition=="fixed"?0:this.cssPosition=="fixed"?-this.scrollParent.scrollLeft():e?0:d.scrollLeft())}},_rearrange:function(a,b,c,d){c?c[0].appendChild(this.placeholder[0]):b.item[0].parentNode.insertBefore(this.placeholder[0],this.direction=="down"?b.item[0]:b.item[0].nextSibling),this.counter=this.counter?++this.counter:1;var e=this,f=this.counter;window.setTimeout(function(){f==e.counter&&e.refreshPositions(!d)},0)},_clear:function(b,c){this.reverting=!1;var d=[],e=this;!this._noFinalSort&&this.currentItem.parent().length&&this.placeholder.before(this.currentItem),this._noFinalSort=null;if(this.helper[0]==this.currentItem[0]){for(var f in this._storedCSS)if(this._storedCSS[f]=="auto"||this._storedCSS[f]=="static")this._storedCSS[f]="";this.currentItem.css(this._storedCSS).removeClass("ui-sortable-helper")}else this.currentItem.show();this.fromOutside&&!c&&d.push(function(a){this._trigger("receive",a,this._uiHash(this.fromOutside))}),(this.fromOutside||this.domPosition.prev!=this.currentItem.prev().not(".ui-sortable-helper")[0]||this.domPosition.parent!=this.currentItem.parent()[0])&&!c&&d.push(function(a){this._trigger("update",a,this._uiHash())});if(!a.ui.contains(this.element[0],this.currentItem[0])){c||d.push(function(a){this._trigger("remove",a,this._uiHash())});for(var f=this.containers.length-1;f>=0;f--)a.ui.contains(this.containers[f].element[0],this.currentItem[0])&&!c&&(d.push(function(a){return function(b){a._trigger("receive",b,this._uiHash(this))}}.call(this,this.containers[f])),d.push(function(a){return function(b){a._trigger("update",b,this._uiHash(this))}}.call(this,this.containers[f])))}for(var f=this.containers.length-1;f>=0;f--)c||d.push(function(a){return function(b){a._trigger("deactivate",b,this._uiHash(this))}}.call(this,this.containers[f])),this.containers[f].containerCache.over&&(d.push(function(a){return function(b){a._trigger("out",b,this._uiHash(this))}}.call(this,this.containers[f])),this.containers[f].containerCache.over=0);this._storedCursor&&a("body").css("cursor",this._storedCursor),this._storedOpacity&&this.helper.css("opacity",this._storedOpacity),this._storedZIndex&&this.helper.css("zIndex",this._storedZIndex=="auto"?"":this._storedZIndex),this.dragging=!1;if(this.cancelHelperRemoval){if(!c){this._trigger("beforeStop",b,this._uiHash());for(var f=0;f<d.length;f++)d[f].call(this,b);this._trigger("stop",b,this._uiHash())}return this.fromOutside=!1,!1}c||this._trigger("beforeStop",b,this._uiHash()),this.placeholder[0].parentNode.removeChild(this.placeholder[0]),this.helper[0]!=this.currentItem[0]&&this.helper.remove(),this.helper=null;if(!c){for(var f=0;f<d.length;f++)d[f].call(this,b);this._trigger("stop",b,this._uiHash())}return this.fromOutside=!1,!0},_trigger:function(){a.Widget.prototype._trigger.apply(this,arguments)===!1&&this.cancel()},_uiHash:function(b){var c=b||this;return{helper:c.helper,placeholder:c.placeholder||a([]),position:c.position,originalPosition:c.originalPosition,offset:c.positionAbs,item:c.currentItem,sender:b?b.element:null}}}),a.extend(a.ui.sortable,{version:"1.8.23"})})(jQuery);;/*! jQuery UI - v1.8.23 - 2012-08-15
    +-* https://github.com/jquery/jquery-ui
    +-* Includes: jquery.ui.accordion.js
    +-* Copyright (c) 2012 AUTHORS.txt; Licensed MIT, GPL */
    +-(function(a,b){a.widget("ui.accordion",{options:{active:0,animated:"slide",autoHeight:!0,clearStyle:!1,collapsible:!1,event:"click",fillSpace:!1,header:"> li > :first-child,> :not(li):even",icons:{header:"ui-icon-triangle-1-e",headerSelected:"ui-icon-triangle-1-s"},navigation:!1,navigationFilter:function(){return this.href.toLowerCase()===location.href.toLowerCase()}},_create:function(){var b=this,c=b.options;b.running=0,b.element.addClass("ui-accordion ui-widget ui-helper-reset").children("li").addClass("ui-accordion-li-fix"),b.headers=b.element.find(c.header).addClass("ui-accordion-header ui-helper-reset ui-state-default ui-corner-all").bind("mouseenter.accordion",function(){if(c.disabled)return;a(this).addClass("ui-state-hover")}).bind("mouseleave.accordion",function(){if(c.disabled)return;a(this).removeClass("ui-state-hover")}).bind("focus.accordion",function(){if(c.disabled)return;a(this).addClass("ui-state-focus")}).bind("blur.accordion",function(){if(c.disabled)return;a(this).removeClass("ui-state-focus")}),b.headers.next().addClass("ui-accordion-content ui-helper-reset ui-widget-content ui-corner-bottom");if(c.navigation){var d=b.element.find("a").filter(c.navigationFilter).eq(0);if(d.length){var e=d.closest(".ui-accordion-header");e.length?b.active=e:b.active=d.closest(".ui-accordion-content").prev()}}b.active=b._findActive(b.active||c.active).addClass("ui-state-default ui-state-active").toggleClass("ui-corner-all").toggleClass("ui-corner-top"),b.active.next().addClass("ui-accordion-content-active"),b._createIcons(),b.resize(),b.element.attr("role","tablist"),b.headers.attr("role","tab").bind("keydown.accordion",function(a){return b._keydown(a)}).next().attr("role","tabpanel"),b.headers.not(b.active||"").attr({"aria-expanded":"false","aria-selected":"false",tabIndex:-1}).next().hide(),b.active.length?b.active.attr({"aria-expanded":"true","aria-selected":"true",tabIndex:0}):b.headers.eq(0).attr("tabIndex",0),a.browser.safari||b.headers.find("a").attr("tabIndex",-1),c.event&&b.headers.bind(c.event.split(" ").join(".accordion ")+".accordion",function(a){b._clickHandler.call(b,a,this),a.preventDefault()})},_createIcons:function(){var b=this.options;b.icons&&(a("<span></span>").addClass("ui-icon "+b.icons.header).prependTo(this.headers),this.active.children(".ui-icon").toggleClass(b.icons.header).toggleClass(b.icons.headerSelected),this.element.addClass("ui-accordion-icons"))},_destroyIcons:function(){this.headers.children(".ui-icon").remove(),this.element.removeClass("ui-accordion-icons")},destroy:function(){var b=this.options;this.element.removeClass("ui-accordion ui-widget ui-helper-reset").removeAttr("role"),this.headers.unbind(".accordion").removeClass("ui-accordion-header ui-accordion-disabled ui-helper-reset ui-state-default ui-corner-all ui-state-active ui-state-disabled ui-corner-top").removeAttr("role").removeAttr("aria-expanded").removeAttr("aria-selected").removeAttr("tabIndex"),this.headers.find("a").removeAttr("tabIndex"),this._destroyIcons();var c=this.headers.next().css("display","").removeAttr("role").removeClass("ui-helper-reset ui-widget-content ui-corner-bottom ui-accordion-content ui-accordion-content-active ui-accordion-disabled ui-state-disabled");return(b.autoHeight||b.fillHeight)&&c.css("height",""),a.Widget.prototype.destroy.call(this)},_setOption:function(b,c){a.Widget.prototype._setOption.apply(this,arguments),b=="active"&&this.activate(c),b=="icons"&&(this._destroyIcons(),c&&this._createIcons()),b=="disabled"&&this.headers.add(this.headers.next())[c?"addClass":"removeClass"]("ui-accordion-disabled ui-state-disabled")},_keydown:function(b){if(this.options.disabled||b.altKey||b.ctrlKey)return;var c=a.ui.keyCode,d=this.headers.length,e=this.headers.index(b.target),f=!1;switch(b.keyCode){case c.RIGHT:case c.DOWN:f=this.headers[(e+1)%d];break;case c.LEFT:case c.UP:f=this.headers[(e-1+d)%d];break;case c.SPACE:case c.ENTER:this._clickHandler({target:b.target},b.target),b.preventDefault()}return f?(a(b.target).attr("tabIndex",-1),a(f).attr("tabIndex",0),f.focus(),!1):!0},resize:function(){var b=this.options,c;if(b.fillSpace){if(a.browser.msie){var d=this.element.parent().css("overflow");this.element.parent().css("overflow","hidden")}c=this.element.parent().height(),a.browser.msie&&this.element.parent().css("overflow",d),this.headers.each(function(){c-=a(this).outerHeight(!0)}),this.headers.next().each(function(){a(this).height(Math.max(0,c-a(this).innerHeight()+a(this).height()))}).css("overflow","auto")}else b.autoHeight&&(c=0,this.headers.next().each(function(){c=Math.max(c,a(this).height("").height())}).height(c));return this},activate:function(a){this.options.active=a;var b=this._findActive(a)[0];return this._clickHandler({target:b},b),this},_findActive:function(b){return b?typeof b=="number"?this.headers.filter(":eq("+b+")"):this.headers.not(this.headers.not(b)):b===!1?a([]):this.headers.filter(":eq(0)")},_clickHandler:function(b,c){var d=this.options;if(d.disabled)return;if(!b.target){if(!d.collapsible)return;this.active.removeClass("ui-state-active ui-corner-top").addClass("ui-state-default ui-corner-all").children(".ui-icon").removeClass(d.icons.headerSelected).addClass(d.icons.header),this.active.next().addClass("ui-accordion-content-active");var e=this.active.next(),f={options:d,newHeader:a([]),oldHeader:d.active,newContent:a([]),oldContent:e},g=this.active=a([]);this._toggle(g,e,f);return}var h=a(b.currentTarget||c),i=h[0]===this.active[0];d.active=d.collapsible&&i?!1:this.headers.index(h);if(this.running||!d.collapsible&&i)return;var j=this.active,g=h.next(),e=this.active.next(),f={options:d,newHeader:i&&d.collapsible?a([]):h,oldHeader:this.active,newContent:i&&d.collapsible?a([]):g,oldContent:e},k=this.headers.index(this.active[0])>this.headers.index(h[0]);this.active=i?a([]):h,this._toggle(g,e,f,i,k),j.removeClass("ui-state-active ui-corner-top").addClass("ui-state-default ui-corner-all").children(".ui-icon").removeClass(d.icons.headerSelected).addClass(d.icons.header),i||(h.removeClass("ui-state-default ui-corner-all").addClass("ui-state-active ui-corner-top").children(".ui-icon").removeClass(d.icons.header).addClass(d.icons.headerSelected),h.next().addClass("ui-accordion-content-active"));return},_toggle:function(b,c,d,e,f){var g=this,h=g.options;g.toShow=b,g.toHide=c,g.data=d;var i=function(){if(!g)return;return g._completed.apply(g,arguments)};g._trigger("changestart",null,g.data),g.running=c.size()===0?b.size():c.size();if(h.animated){var j={};h.collapsible&&e?j={toShow:a([]),toHide:c,complete:i,down:f,autoHeight:h.autoHeight||h.fillSpace}:j={toShow:b,toHide:c,complete:i,down:f,autoHeight:h.autoHeight||h.fillSpace},h.proxied||(h.proxied=h.animated),h.proxiedDuration||(h.proxiedDuration=h.duration),h.animated=a.isFunction(h.proxied)?h.proxied(j):h.proxied,h.duration=a.isFunction(h.proxiedDuration)?h.proxiedDuration(j):h.proxiedDuration;var k=a.ui.accordion.animations,l=h.duration,m=h.animated;m&&!k[m]&&!a.easing[m]&&(m="slide"),k[m]||(k[m]=function(a){this.slide(a,{easing:m,duration:l||700})}),k[m](j)}else h.collapsible&&e?b.toggle():(c.hide(),b.show()),i(!0);c.prev().attr({"aria-expanded":"false","aria-selected":"false",tabIndex:-1}).blur(),b.prev().attr({"aria-expanded":"true","aria-selected":"true",tabIndex:0}).focus()},_completed:function(a){this.running=a?0:--this.running;if(this.running)return;this.options.clearStyle&&this.toShow.add(this.toHide).css({height:"",overflow:""}),this.toHide.removeClass("ui-accordion-content-active"),this.toHide.length&&(this.toHide.parent()[0].className=this.toHide.parent()[0].className),this._trigger("change",null,this.data)}}),a.extend(a.ui.accordion,{version:"1.8.23",animations:{slide:function(b,c){b=a.extend({easing:"swing",duration:300},b,c);if(!b.toHide.size()){b.toShow.animate({height:"show",paddingTop:"show",paddingBottom:"show"},b);return}if(!b.toShow.size()){b.toHide.animate({height:"hide",paddingTop:"hide",paddingBottom:"hide"},b);return}var d=b.toShow.css("overflow"),e=0,f={},g={},h=["height","paddingTop","paddingBottom"],i,j=b.toShow;i=j[0].style.width,j.width(j.parent().width()-parseFloat(j.css("paddingLeft"))-parseFloat(j.css("paddingRight"))-(parseFloat(j.css("borderLeftWidth"))||0)-(parseFloat(j.css("borderRightWidth"))||0)),a.each(h,function(c,d){g[d]="hide";var e=(""+a.css(b.toShow[0],d)).match(/^([\d+-.]+)(.*)$/);f[d]={value:e[1],unit:e[2]||"px"}}),b.toShow.css({height:0,overflow:"hidden"}).show(),b.toHide.filter(":hidden").each(b.complete).end().filter(":visible").animate(g,{step:function(a,c){c.prop=="height"&&(e=c.end-c.start===0?0:(c.now-c.start)/(c.end-c.start)),b.toShow[0].style[c.prop]=e*f[c.prop].value+f[c.prop].unit},duration:b.duration,easing:b.easing,complete:function(){b.autoHeight||b.toShow.css("height",""),b.toShow.css({width:i,overflow:d}),b.complete()}})},bounceslide:function(a){this.slide(a,{easing:a.down?"easeOutBounce":"swing",duration:a.down?1e3:200})}}})})(jQuery);;/*! jQuery UI - v1.8.23 - 2012-08-15
    +-* https://github.com/jquery/jquery-ui
    +-* Includes: jquery.ui.autocomplete.js
    +-* Copyright (c) 2012 AUTHORS.txt; Licensed MIT, GPL */
    +-(function(a,b){var c=0;a.widget("ui.autocomplete",{options:{appendTo:"body",autoFocus:!1,delay:300,minLength:1,position:{my:"left top",at:"left bottom",collision:"none"},source:null},pending:0,_create:function(){var b=this,c=this.element[0].ownerDocument,d;this.isMultiLine=this.element.is("textarea"),this.element.addClass("ui-autocomplete-input").attr("autocomplete","off").attr({role:"textbox","aria-autocomplete":"list","aria-haspopup":"true"}).bind("keydown.autocomplete",function(c){if(b.options.disabled||b.element.propAttr("readOnly"))return;d=!1;var e=a.ui.keyCode;switch(c.keyCode){case e.PAGE_UP:b._move("previousPage",c);break;case e.PAGE_DOWN:b._move("nextPage",c);break;case e.UP:b._keyEvent("previous",c);break;case e.DOWN:b._keyEvent("next",c);break;case e.ENTER:case e.NUMPAD_ENTER:b.menu.active&&(d=!0,c.preventDefault());case e.TAB:if(!b.menu.active)return;b.menu.select(c);break;case e.ESCAPE:b.element.val(b.term),b.close(c);break;default:clearTimeout(b.searching),b.searching=setTimeout(function(){b.term!=b.element.val()&&(b.selectedItem=null,b.search(null,c))},b.options.delay)}}).bind("keypress.autocomplete",function(a){d&&(d=!1,a.preventDefault())}).bind("focus.autocomplete",function(){if(b.options.disabled)return;b.selectedItem=null,b.previous=b.element.val()}).bind("blur.autocomplete",function(a){if(b.options.disabled)return;clearTimeout(b.searching),b.closing=setTimeout(function(){b.close(a),b._change(a)},150)}),this._initSource(),this.menu=a("<ul></ul>").addClass("ui-autocomplete").appendTo(a(this.options.appendTo||"body",c)[0]).mousedown(function(c){var d=b.menu.element[0];a(c.target).closest(".ui-menu-item").length||setTimeout(function(){a(document).one("mousedown",function(c){c.target!==b.element[0]&&c.target!==d&&!a.ui.contains(d,c.target)&&b.close()})},1),setTimeout(function(){clearTimeout(b.closing)},13)}).menu({focus:function(a,c){var d=c.item.data("item.autocomplete");!1!==b._trigger("focus",a,{item:d})&&/^key/.test(a.originalEvent.type)&&b.element.val(d.value)},selected:function(a,d){var e=d.item.data("item.autocomplete"),f=b.previous;b.element[0]!==c.activeElement&&(b.element.focus(),b.previous=f,setTimeout(function(){b.previous=f,b.selectedItem=e},1)),!1!==b._trigger("select",a,{item:e})&&b.element.val(e.value),b.term=b.element.val(),b.close(a),b.selectedItem=e},blur:function(a,c){b.menu.element.is(":visible")&&b.element.val()!==b.term&&b.element.val(b.term)}}).zIndex(this.element.zIndex()+1).css({top:0,left:0}).hide().data("menu"),a.fn.bgiframe&&this.menu.element.bgiframe(),b.beforeunloadHandler=function(){b.element.removeAttr("autocomplete")},a(window).bind("beforeunload",b.beforeunloadHandler)},destroy:function(){this.element.removeClass("ui-autocomplete-input").removeAttr("autocomplete").removeAttr("role").removeAttr("aria-autocomplete").removeAttr("aria-haspopup"),this.menu.element.remove(),a(window).unbind("beforeunload",this.beforeunloadHandler),a.Widget.prototype.destroy.call(this)},_setOption:function(b,c){a.Widget.prototype._setOption.apply(this,arguments),b==="source"&&this._initSource(),b==="appendTo"&&this.menu.element.appendTo(a(c||"body",this.element[0].ownerDocument)[0]),b==="disabled"&&c&&this.xhr&&this.xhr.abort()},_initSource:function(){var b=this,c,d;a.isArray(this.options.source)?(c=this.options.source,this.source=function(b,d){d(a.ui.autocomplete.filter(c,b.term))}):typeof this.options.source=="string"?(d=this.options.source,this.source=function(c,e){b.xhr&&b.xhr.abort(),b.xhr=a.ajax({url:d,data:c,dataType:"json",success:function(a,b){e(a)},error:function(){e([])}})}):this.source=this.options.source},search:function(a,b){a=a!=null?a:this.element.val(),this.term=this.element.val();if(a.length<this.options.minLength)return this.close(b);clearTimeout(this.closing);if(this._trigger("search",b)===!1)return;return this._search(a)},_search:function(a){this.pending++,this.element.addClass("ui-autocomplete-loading"),this.source({term:a},this._response())},_response:function(){var a=this,b=++c;return function(d){b===c&&a.__response(d),a.pending--,a.pending||a.element.removeClass("ui-autocomplete-loading")}},__response:function(a){!this.options.disabled&&a&&a.length?(a=this._normalize(a),this._suggest(a),this._trigger("open")):this.close()},close:function(a){clearTimeout(this.closing),this.menu.element.is(":visible")&&(this.menu.element.hide(),this.menu.deactivate(),this._trigger("close",a))},_change:function(a){this.previous!==this.element.val()&&this._trigger("change",a,{item:this.selectedItem})},_normalize:function(b){return b.length&&b[0].label&&b[0].value?b:a.map(b,function(b){return typeof b=="string"?{label:b,value:b}:a.extend({label:b.label||b.value,value:b.value||b.label},b)})},_suggest:function(b){var c=this.menu.element.empty().zIndex(this.element.zIndex()+1);this._renderMenu(c,b),this.menu.deactivate(),this.menu.refresh(),c.show(),this._resizeMenu(),c.position(a.extend({of:this.element},this.options.position)),this.options.autoFocus&&this.menu.next(new a.Event("mouseover"))},_resizeMenu:function(){var a=this.menu.element;a.outerWidth(Math.max(a.width("").outerWidth()+1,this.element.outerWidth()))},_renderMenu:function(b,c){var d=this;a.each(c,function(a,c){d._renderItem(b,c)})},_renderItem:function(b,c){return a("<li></li>").data("item.autocomplete",c).append(a("<a></a>").text(c.label)).appendTo(b)},_move:function(a,b){if(!this.menu.element.is(":visible")){this.search(null,b);return}if(this.menu.first()&&/^previous/.test(a)||this.menu.last()&&/^next/.test(a)){this.element.val(this.term),this.menu.deactivate();return}this.menu[a](b)},widget:function(){return this.menu.element},_keyEvent:function(a,b){if(!this.isMultiLine||this.menu.element.is(":visible"))this._move(a,b),b.preventDefault()}}),a.extend(a.ui.autocomplete,{escapeRegex:function(a){return a.replace(/[-[\]{}()*+?.,\\^$|#\s]/g,"\\$&")},filter:function(b,c){var d=new RegExp(a.ui.autocomplete.escapeRegex(c),"i");return a.grep(b,function(a){return d.test(a.label||a.value||a)})}})})(jQuery),function(a){a.widget("ui.menu",{_create:function(){var b=this;this.element.addClass("ui-menu ui-widget ui-widget-content ui-corner-all").attr({role:"listbox","aria-activedescendant":"ui-active-menuitem"}).click(function(c){if(!a(c.target).closest(".ui-menu-item a").length)return;c.preventDefault(),b.select(c)}),this.refresh()},refresh:function(){var b=this,c=this.element.children("li:not(.ui-menu-item):has(a)").addClass("ui-menu-item").attr("role","menuitem");c.children("a").addClass("ui-corner-all").attr("tabindex",-1).mouseenter(function(c){b.activate(c,a(this).parent())}).mouseleave(function(){b.deactivate()})},activate:function(a,b){this.deactivate();if(this.hasScroll()){var c=b.offset().top-this.element.offset().top,d=this.element.scrollTop(),e=this.element.height();c<0?this.element.scrollTop(d+c):c>=e&&this.element.scrollTop(d+c-e+b.height())}this.active=b.eq(0).children("a").addClass("ui-state-hover").attr("id","ui-active-menuitem").end(),this._trigger("focus",a,{item:b})},deactivate:function(){if(!this.active)return;this.active.children("a").removeClass("ui-state-hover").removeAttr("id"),this._trigger("blur"),this.active=null},next:function(a){this.move("next",".ui-menu-item:first",a)},previous:function(a){this.move("prev",".ui-menu-item:last",a)},first:function(){return this.active&&!this.active.prevAll(".ui-menu-item").length},last:function(){return this.active&&!this.active.nextAll(".ui-menu-item").length},move:function(a,b,c){if(!this.active){this.activate(c,this.element.children(b));return}var d=this.active[a+"All"](".ui-menu-item").eq(0);d.length?this.activate(c,d):this.activate(c,this.element.children(b))},nextPage:function(b){if(this.hasScroll()){if(!this.active||this.last()){this.activate(b,this.element.children(".ui-menu-item:first"));return}var c=this.active.offset().top,d=this.element.height(),e=this.element.children(".ui-menu-item").filter(function(){var b=a(this).offset().top-c-d+a(this).height();return b<10&&b>-10});e.length||(e=this.element.children(".ui-menu-item:last")),this.activate(b,e)}else this.activate(b,this.element.children(".ui-menu-item").filter(!this.active||this.last()?":first":":last"))},previousPage:function(b){if(this.hasScroll()){if(!this.active||this.first()){this.activate(b,this.element.children(".ui-menu-item:last"));return}var c=this.active.offset().top,d=this.element.height(),e=this.element.children(".ui-menu-item").filter(function(){var b=a(this).offset().top-c+d-a(this).height();return b<10&&b>-10});e.length||(e=this.element.children(".ui-menu-item:first")),this.activate(b,e)}else this.activate(b,this.element.children(".ui-menu-item").filter(!this.active||this.first()?":last":":first"))},hasScroll:function(){return this.element.height()<this.element[a.fn.prop?"prop":"attr"]("scrollHeight")},select:function(a){this._trigger("selected",a,{item:this.active})}})}(jQuery);;/*! jQuery UI - v1.8.23 - 2012-08-15
    +-* https://github.com/jquery/jquery-ui
    +-* Includes: jquery.ui.button.js
    +-* Copyright (c) 2012 AUTHORS.txt; Licensed MIT, GPL */
    +-(function(a,b){var c,d,e,f,g="ui-button ui-widget ui-state-default ui-corner-all",h="ui-state-hover ui-state-active ",i="ui-button-icons-only ui-button-icon-only ui-button-text-icons ui-button-text-icon-primary ui-button-text-icon-secondary ui-button-text-only",j=function(){var b=a(this).find(":ui-button");setTimeout(function(){b.button("refresh")},1)},k=function(b){var c=b.name,d=b.form,e=a([]);return c&&(d?e=a(d).find("[name='"+c+"']"):e=a("[name='"+c+"']",b.ownerDocument).filter(function(){return!this.form})),e};a.widget("ui.button",{options:{disabled:null,text:!0,label:null,icons:{primary:null,secondary:null}},_create:function(){this.element.closest("form").unbind("reset.button").bind("reset.button",j),typeof this.options.disabled!="boolean"?this.options.disabled=!!this.element.propAttr("disabled"):this.element.propAttr("disabled",this.options.disabled),this._determineButtonType(),this.hasTitle=!!this.buttonElement.attr("title");var b=this,h=this.options,i=this.type==="checkbox"||this.type==="radio",l="ui-state-hover"+(i?"":" ui-state-active"),m="ui-state-focus";h.label===null&&(h.label=this.buttonElement.html()),this.buttonElement.addClass(g).attr("role","button").bind("mouseenter.button",function(){if(h.disabled)return;a(this).addClass("ui-state-hover"),this===c&&a(this).addClass("ui-state-active")}).bind("mouseleave.button",function(){if(h.disabled)return;a(this).removeClass(l)}).bind("click.button",function(a){h.disabled&&(a.preventDefault(),a.stopImmediatePropagation())}),this.element.bind("focus.button",function(){b.buttonElement.addClass(m)}).bind("blur.button",function(){b.buttonElement.removeClass(m)}),i&&(this.element.bind("change.button",function(){if(f)return;b.refresh()}),this.buttonElement.bind("mousedown.button",function(a){if(h.disabled)return;f=!1,d=a.pageX,e=a.pageY}).bind("mouseup.button",function(a){if(h.disabled)return;if(d!==a.pageX||e!==a.pageY)f=!0})),this.type==="checkbox"?this.buttonElement.bind("click.button",function(){if(h.disabled||f)return!1;a(this).toggleClass("ui-state-active"),b.buttonElement.attr("aria-pressed",b.element[0].checked)}):this.type==="radio"?this.buttonElement.bind("click.button",function(){if(h.disabled||f)return!1;a(this).addClass("ui-state-active"),b.buttonElement.attr("aria-pressed","true");var c=b.element[0];k(c).not(c).map(function(){return a(this).button("widget")[0]}).removeClass("ui-state-active").attr("aria-pressed","false")}):(this.buttonElement.bind("mousedown.button",function(){if(h.disabled)return!1;a(this).addClass("ui-state-active"),c=this,a(document).one("mouseup",function(){c=null})}).bind("mouseup.button",function(){if(h.disabled)return!1;a(this).removeClass("ui-state-active")}).bind("keydown.button",function(b){if(h.disabled)return!1;(b.keyCode==a.ui.keyCode.SPACE||b.keyCode==a.ui.keyCode.ENTER)&&a(this).addClass("ui-state-active")}).bind("keyup.button",function(){a(this).removeClass("ui-state-active")}),this.buttonElement.is("a")&&this.buttonElement.keyup(function(b){b.keyCode===a.ui.keyCode.SPACE&&a(this).click()})),this._setOption("disabled",h.disabled),this._resetButton()},_determineButtonType:function(){this.element.is(":checkbox")?this.type="checkbox":this.element.is(":radio")?this.type="radio":this.element.is("input")?this.type="input":this.type="button";if(this.type==="checkbox"||this.type==="radio"){var a=this.element.parents().filter(":last"),b="label[for='"+this.element.attr("id")+"']";this.buttonElement=a.find(b),this.buttonElement.length||(a=a.length?a.siblings():this.element.siblings(),this.buttonElement=a.filter(b),this.buttonElement.length||(this.buttonElement=a.find(b))),this.element.addClass("ui-helper-hidden-accessible");var c=this.element.is(":checked");c&&this.buttonElement.addClass("ui-state-active"),this.buttonElement.attr("aria-pressed",c)}else this.buttonElement=this.element},widget:function(){return this.buttonElement},destroy:function(){this.element.removeClass("ui-helper-hidden-accessible"),this.buttonElement.removeClass(g+" "+h+" "+i).removeAttr("role").removeAttr("aria-pressed").html(this.buttonElement.find(".ui-button-text").html()),this.hasTitle||this.buttonElement.removeAttr("title"),a.Widget.prototype.destroy.call(this)},_setOption:function(b,c){a.Widget.prototype._setOption.apply(this,arguments);if(b==="disabled"){c?this.element.propAttr("disabled",!0):this.element.propAttr("disabled",!1);return}this._resetButton()},refresh:function(){var b=this.element.is(":disabled");b!==this.options.disabled&&this._setOption("disabled",b),this.type==="radio"?k(this.element[0]).each(function(){a(this).is(":checked")?a(this).button("widget").addClass("ui-state-active").attr("aria-pressed","true"):a(this).button("widget").removeClass("ui-state-active").attr("aria-pressed","false")}):this.type==="checkbox"&&(this.element.is(":checked")?this.buttonElement.addClass("ui-state-active").attr("aria-pressed","true"):this.buttonElement.removeClass("ui-state-active").attr("aria-pressed","false"))},_resetButton:function(){if(this.type==="input"){this.options.label&&this.element.val(this.options.label);return}var b=this.buttonElement.removeClass(i),c=a("<span></span>",this.element[0].ownerDocument).addClass("ui-button-text").html(this.options.label).appendTo(b.empty()).text(),d=this.options.icons,e=d.primary&&d.secondary,f=[];d.primary||d.secondary?(this.options.text&&f.push("ui-button-text-icon"+(e?"s":d.primary?"-primary":"-secondary")),d.primary&&b.prepend("<span class='ui-button-icon-primary ui-icon "+d.primary+"'></span>"),d.secondary&&b.append("<span class='ui-button-icon-secondary ui-icon "+d.secondary+"'></span>"),this.options.text||(f.push(e?"ui-button-icons-only":"ui-button-icon-only"),this.hasTitle||b.attr("title",c))):f.push("ui-button-text-only"),b.addClass(f.join(" "))}}),a.widget("ui.buttonset",{options:{items:":button, :submit, :reset, :checkbox, :radio, a, :data(button)"},_create:function(){this.element.addClass("ui-buttonset")},_init:function(){this.refresh()},_setOption:function(b,c){b==="disabled"&&this.buttons.button("option",b,c),a.Widget.prototype._setOption.apply(this,arguments)},refresh:function(){var b=this.element.css("direction")==="rtl";this.buttons=this.element.find(this.options.items).filter(":ui-button").button("refresh").end().not(":ui-button").button().end().map(function(){return a(this).button("widget")[0]}).removeClass("ui-corner-all ui-corner-left ui-corner-right").filter(":first").addClass(b?"ui-corner-right":"ui-corner-left").end().filter(":last").addClass(b?"ui-corner-left":"ui-corner-right").end().end()},destroy:function(){this.element.removeClass("ui-buttonset"),this.buttons.map(function(){return a(this).button("widget")[0]}).removeClass("ui-corner-left ui-corner-right").end().button("destroy"),a.Widget.prototype.destroy.call(this)}})})(jQuery);;/*! jQuery UI - v1.8.23 - 2012-08-15
    +-* https://github.com/jquery/jquery-ui
    +-* Includes: jquery.ui.dialog.js
    +-* Copyright (c) 2012 AUTHORS.txt; Licensed MIT, GPL */
    +-(function(a,b){var c="ui-dialog ui-widget ui-widget-content ui-corner-all ",d={buttons:!0,height:!0,maxHeight:!0,maxWidth:!0,minHeight:!0,minWidth:!0,width:!0},e={maxHeight:!0,maxWidth:!0,minHeight:!0,minWidth:!0};a.widget("ui.dialog",{options:{autoOpen:!0,buttons:{},closeOnEscape:!0,closeText:"close",dialogClass:"",draggable:!0,hide:null,height:"auto",maxHeight:!1,maxWidth:!1,minHeight:150,minWidth:150,modal:!1,position:{my:"center",at:"center",collision:"fit",using:function(b){var c=a(this).css(b).offset().top;c<0&&a(this).css("top",b.top-c)}},resizable:!0,show:null,stack:!0,title:"",width:300,zIndex:1e3},_create:function(){this.originalTitle=this.element.attr("title"),typeof this.originalTitle!="string"&&(this.originalTitle=""),this.options.title=this.options.title||this.originalTitle;var b=this,d=b.options,e=d.title||"&#160;",f=a.ui.dialog.getTitleId(b.element),g=(b.uiDialog=a("<div></div>")).appendTo(document.body).hide().addClass(c+d.dialogClass).css({zIndex:d.zIndex}).attr("tabIndex",-1).css("outline",0).keydown(function(c){d.closeOnEscape&&!c.isDefaultPrevented()&&c.keyCode&&c.keyCode===a.ui.keyCode.ESCAPE&&(b.close(c),c.preventDefault())}).attr({role:"dialog","aria-labelledby":f}).mousedown(function(a){b.moveToTop(!1,a)}),h=b.element.show().removeAttr("title").addClass("ui-dialog-content ui-widget-content").appendTo(g),i=(b.uiDialogTitlebar=a("<div></div>")).addClass("ui-dialog-titlebar ui-widget-header ui-corner-all ui-helper-clearfix").prependTo(g),j=a('<a href="#"></a>').addClass("ui-dialog-titlebar-close ui-corner-all").attr("role","button").hover(function(){j.addClass("ui-state-hover")},function(){j.removeClass("ui-state-hover")}).focus(function(){j.addClass("ui-state-focus")}).blur(function(){j.removeClass("ui-state-focus")}).click(function(a){return b.close(a),!1}).appendTo(i),k=(b.uiDialogTitlebarCloseText=a("<span></span>")).addClass("ui-icon ui-icon-closethick").text(d.closeText).appendTo(j),l=a("<span></span>").addClass("ui-dialog-title").attr("id",f).html(e).prependTo(i);a.isFunction(d.beforeclose)&&!a.isFunction(d.beforeClose)&&(d.beforeClose=d.beforeclose),i.find("*").add(i).disableSelection(),d.draggable&&a.fn.draggable&&b._makeDraggable(),d.resizable&&a.fn.resizable&&b._makeResizable(),b._createButtons(d.buttons),b._isOpen=!1,a.fn.bgiframe&&g.bgiframe()},_init:function(){this.options.autoOpen&&this.open()},destroy:function(){var a=this;return a.overlay&&a.overlay.destroy(),a.uiDialog.hide(),a.element.unbind(".dialog").removeData("dialog").removeClass("ui-dialog-content ui-widget-content").hide().appendTo("body"),a.uiDialog.remove(),a.originalTitle&&a.element.attr("title",a.originalTitle),a},widget:function(){return this.uiDialog},close:function(b){var c=this,d,e;if(!1===c._trigger("beforeClose",b))return;return c.overlay&&c.overlay.destroy(),c.uiDialog.unbind("keypress.ui-dialog"),c._isOpen=!1,c.options.hide?c.uiDialog.hide(c.options.hide,function(){c._trigger("close",b)}):(c.uiDialog.hide(),c._trigger("close",b)),a.ui.dialog.overlay.resize(),c.options.modal&&(d=0,a(".ui-dialog").each(function(){this!==c.uiDialog[0]&&(e=a(this).css("z-index"),isNaN(e)||(d=Math.max(d,e)))}),a.ui.dialog.maxZ=d),c},isOpen:function(){return this._isOpen},moveToTop:function(b,c){var d=this,e=d.options,f;return e.modal&&!b||!e.stack&&!e.modal?d._trigger("focus",c):(e.zIndex>a.ui.dialog.maxZ&&(a.ui.dialog.maxZ=e.zIndex),d.overlay&&(a.ui.dialog.maxZ+=1,d.overlay.$el.css("z-index",a.ui.dialog.overlay.maxZ=a.ui.dialog.maxZ)),f={scrollTop:d.element.scrollTop(),scrollLeft:d.element.scrollLeft()},a.ui.dialog.maxZ+=1,d.uiDialog.css("z-index",a.ui.dialog.maxZ),d.element.attr(f),d._trigger("focus",c),d)},open:function(){if(this._isOpen)return;var b=this,c=b.options,d=b.uiDialog;return b.overlay=c.modal?new a.ui.dialog.overlay(b):null,b._size(),b._position(c.position),d.show(c.show),b.moveToTop(!0),c.modal&&d.bind("keydown.ui-dialog",function(b){if(b.keyCode!==a.ui.keyCode.TAB)return;var c=a(":tabbable",this),d=c.filter(":first"),e=c.filter(":last");if(b.target===e[0]&&!b.shiftKey)return d.focus(1),!1;if(b.target===d[0]&&b.shiftKey)return e.focus(1),!1}),a(b.element.find(":tabbable").get().concat(d.find(".ui-dialog-buttonpane :tabbable").get().concat(d.get()))).eq(0).focus(),b._isOpen=!0,b._trigger("open"),b},_createButtons:function(b){var c=this,d=!1,e=a("<div></div>").addClass("ui-dialog-buttonpane ui-widget-content ui-helper-clearfix"),f=a("<div></div>").addClass("ui-dialog-buttonset").appendTo(e);c.uiDialog.find(".ui-dialog-buttonpane").remove(),typeof b=="object"&&b!==null&&a.each(b,function(){return!(d=!0)}),d&&(a.each(b,function(b,d){d=a.isFunction(d)?{click:d,text:b}:d;var e=a('<button type="button"></button>').click(function(){d.click.apply(c.element[0],arguments)}).appendTo(f);a.each(d,function(a,b){if(a==="click")return;a in e?e[a](b):e.attr(a,b)}),a.fn.button&&e.button()}),e.appendTo(c.uiDialog))},_makeDraggable:function(){function f(a){return{position:a.position,offset:a.offset}}var b=this,c=b.options,d=a(document),e;b.uiDialog.draggable({cancel:".ui-dialog-content, .ui-dialog-titlebar-close",handle:".ui-dialog-titlebar",containment:"document",start:function(d,g){e=c.height==="auto"?"auto":a(this).height(),a(this).height(a(this).height()).addClass("ui-dialog-dragging"),b._trigger("dragStart",d,f(g))},drag:function(a,c){b._trigger("drag",a,f(c))},stop:function(g,h){c.position=[h.position.left-d.scrollLeft(),h.position.top-d.scrollTop()],a(this).removeClass("ui-dialog-dragging").height(e),b._trigger("dragStop",g,f(h)),a.ui.dialog.overlay.resize()}})},_makeResizable:function(c){function h(a){return{originalPosition:a.originalPosition,originalSize:a.originalSize,position:a.position,size:a.size}}c=c===b?this.options.resizable:c;var d=this,e=d.options,f=d.uiDialog.css("position"),g=typeof c=="string"?c:"n,e,s,w,se,sw,ne,nw";d.uiDialog.resizable({cancel:".ui-dialog-content",containment:"document",alsoResize:d.element,maxWidth:e.maxWidth,maxHeight:e.maxHeight,minWidth:e.minWidth,minHeight:d._minHeight(),handles:g,start:function(b,c){a(this).addClass("ui-dialog-resizing"),d._trigger("resizeStart",b,h(c))},resize:function(a,b){d._trigger("resize",a,h(b))},stop:function(b,c){a(this).removeClass("ui-dialog-resizing"),e.height=a(this).height(),e.width=a(this).width(),d._trigger("resizeStop",b,h(c)),a.ui.dialog.overlay.resize()}}).css("position",f).find(".ui-resizable-se").addClass("ui-icon ui-icon-grip-diagonal-se")},_minHeight:function(){var a=this.options;return a.height==="auto"?a.minHeight:Math.min(a.minHeight,a.height)},_position:function(b){var c=[],d=[0,0],e;if(b){if(typeof b=="string"||typeof b=="object"&&"0"in b)c=b.split?b.split(" "):[b[0],b[1]],c.length===1&&(c[1]=c[0]),a.each(["left","top"],function(a,b){+c[a]===c[a]&&(d[a]=c[a],c[a]=b)}),b={my:c.join(" "),at:c.join(" "),offset:d.join(" ")};b=a.extend({},a.ui.dialog.prototype.options.position,b)}else b=a.ui.dialog.prototype.options.position;e=this.uiDialog.is(":visible"),e||this.uiDialog.show(),this.uiDialog.css({top:0,left:0}).position(a.extend({of:window},b)),e||this.uiDialog.hide()},_setOptions:function(b){var c=this,f={},g=!1;a.each(b,function(a,b){c._setOption(a,b),a in d&&(g=!0),a in e&&(f[a]=b)}),g&&this._size(),this.uiDialog.is(":data(resizable)")&&this.uiDialog.resizable("option",f)},_setOption:function(b,d){var e=this,f=e.uiDialog;switch(b){case"beforeclose":b="beforeClose";break;case"buttons":e._createButtons(d);break;case"closeText":e.uiDialogTitlebarCloseText.text(""+d);break;case"dialogClass":f.removeClass(e.options.dialogClass).addClass(c+d);break;case"disabled":d?f.addClass("ui-dialog-disabled"):f.removeClass("ui-dialog-disabled");break;case"draggable":var g=f.is(":data(draggable)");g&&!d&&f.draggable("destroy"),!g&&d&&e._makeDraggable();break;case"position":e._position(d);break;case"resizable":var h=f.is(":data(resizable)");h&&!d&&f.resizable("destroy"),h&&typeof d=="string"&&f.resizable("option","handles",d),!h&&d!==!1&&e._makeResizable(d);break;case"title":a(".ui-dialog-title",e.uiDialogTitlebar).html(""+(d||"&#160;"))}a.Widget.prototype._setOption.apply(e,arguments)},_size:function(){var b=this.options,c,d,e=this.uiDialog.is(":visible");this.element.show().css({width:"auto",minHeight:0,height:0}),b.minWidth>b.width&&(b.width=b.minWidth),c=this.uiDialog.css({height:"auto",width:b.width}).height(),d=Math.max(0,b.minHeight-c);if(b.height==="auto")if(a.support.minHeight)this.element.css({minHeight:d,height:"auto"});else{this.uiDialog.show();var f=this.element.css("height","auto").height();e||this.uiDialog.hide(),this.element.height(Math.max(f,d))}else this.element.height(Math.max(b.height-c,0));this.uiDialog.is(":data(resizable)")&&this.uiDialog.resizable("option","minHeight",this._minHeight())}}),a.extend(a.ui.dialog,{version:"1.8.23",uuid:0,maxZ:0,getTitleId:function(a){var b=a.attr("id");return b||(this.uuid+=1,b=this.uuid),"ui-dialog-title-"+b},overlay:function(b){this.$el=a.ui.dialog.overlay.create(b)}}),a.extend(a.ui.dialog.overlay,{instances:[],oldInstances:[],maxZ:0,events:a.map("focus,mousedown,mouseup,keydown,keypress,click".split(","),function(a){return a+".dialog-overlay"}).join(" "),create:function(b){this.instances.length===0&&(setTimeout(function(){a.ui.dialog.overlay.instances.length&&a(document).bind(a.ui.dialog.overlay.events,function(b){if(a(b.target).zIndex()<a.ui.dialog.overlay.maxZ)return!1})},1),a(document).bind("keydown.dialog-overlay",function(c){b.options.closeOnEscape&&!c.isDefaultPrevented()&&c.keyCode&&c.keyCode===a.ui.keyCode.ESCAPE&&(b.close(c),c.preventDefault())}),a(window).bind("resize.dialog-overlay",a.ui.dialog.overlay.resize));var c=(this.oldInstances.pop()||a("<div></div>").addClass("ui-widget-overlay")).appendTo(document.body).css({width:this.width(),height:this.height()});return a.fn.bgiframe&&c.bgiframe(),this.instances.push(c),c},destroy:function(b){var c=a.inArray(b,this.instances);c!=-1&&this.oldInstances.push(this.instances.splice(c,1)[0]),this.instances.length===0&&a([document,window]).unbind(".dialog-overlay"),b.remove();var d=0;a.each(this.instances,function(){d=Math.max(d,this.css("z-index"))}),this.maxZ=d},height:function(){var b,c;return a.browser.msie&&a.browser.version<7?(b=Math.max(document.documentElement.scrollHeight,document.body.scrollHeight),c=Math.max(document.documentElement.offsetHeight,document.body.offsetHeight),b<c?a(window).height()+"px":b+"px"):a(document).height()+"px"},width:function(){var b,c;return a.browser.msie?(b=Math.max(document.documentElement.scrollWidth,document.body.scrollWidth),c=Math.max(document.documentElement.offsetWidth,document.body.offsetWidth),b<c?a(window).width()+"px":b+"px"):a(document).width()+"px"},resize:function(){var b=a([]);a.each(a.ui.dialog.overlay.instances,function(){b=b.add(this)}),b.css({width:0,height:0}).css({width:a.ui.dialog.overlay.width(),height:a.ui.dialog.overlay.height()})}}),a.extend(a.ui.dialog.overlay.prototype,{destroy:function(){a.ui.dialog.overlay.destroy(this.$el)}})})(jQuery);;/*! jQuery UI - v1.8.23 - 2012-08-15
    +-* https://github.com/jquery/jquery-ui
    +-* Includes: jquery.ui.slider.js
    +-* Copyright (c) 2012 AUTHORS.txt; Licensed MIT, GPL */
    +-(function(a,b){var c=5;a.widget("ui.slider",a.ui.mouse,{widgetEventPrefix:"slide",options:{animate:!1,distance:0,max:100,min:0,orientation:"horizontal",range:!1,step:1,value:0,values:null},_create:function(){var b=this,d=this.options,e=this.element.find(".ui-slider-handle").addClass("ui-state-default ui-corner-all"),f="<a class='ui-slider-handle ui-state-default ui-corner-all' href='#'></a>",g=d.values&&d.values.length||1,h=[];this._keySliding=!1,this._mouseSliding=!1,this._animateOff=!0,this._handleIndex=null,this._detectOrientation(),this._mouseInit(),this.element.addClass("ui-slider ui-slider-"+this.orientation+" ui-widget"+" ui-widget-content"+" ui-corner-all"+(d.disabled?" ui-slider-disabled ui-disabled":"")),this.range=a([]),d.range&&(d.range===!0&&(d.values||(d.values=[this._valueMin(),this._valueMin()]),d.values.length&&d.values.length!==2&&(d.values=[d.values[0],d.values[0]])),this.range=a("<div></div>").appendTo(this.element).addClass("ui-slider-range ui-widget-header"+(d.range==="min"||d.range==="max"?" ui-slider-range-"+d.range:"")));for(var i=e.length;i<g;i+=1)h.push(f);this.handles=e.add(a(h.join("")).appendTo(b.element)),this.handle=this.handles.eq(0),this.handles.add(this.range).filter("a").click(function(a){a.preventDefault()}).hover(function(){d.disabled||a(this).addClass("ui-state-hover")},function(){a(this).removeClass("ui-state-hover")}).focus(function(){d.disabled?a(this).blur():(a(".ui-slider .ui-state-focus").removeClass("ui-state-focus"),a(this).addClass("ui-state-focus"))}).blur(function(){a(this).removeClass("ui-state-focus")}),this.handles.each(function(b){a(this).data("index.ui-slider-handle",b)}),this.handles.keydown(function(d){var e=a(this).data("index.ui-slider-handle"),f,g,h,i;if(b.options.disabled)return;switch(d.keyCode){case a.ui.keyCode.HOME:case a.ui.keyCode.END:case a.ui.keyCode.PAGE_UP:case a.ui.keyCode.PAGE_DOWN:case a.ui.keyCode.UP:case a.ui.keyCode.RIGHT:case a.ui.keyCode.DOWN:case a.ui.keyCode.LEFT:d.preventDefault();if(!b._keySliding){b._keySliding=!0,a(this).addClass("ui-state-active"),f=b._start(d,e);if(f===!1)return}}i=b.options.step,b.options.values&&b.options.values.length?g=h=b.values(e):g=h=b.value();switch(d.keyCode){case a.ui.keyCode.HOME:h=b._valueMin();break;case a.ui.keyCode.END:h=b._valueMax();break;case a.ui.keyCode.PAGE_UP:h=b._trimAlignValue(g+(b._valueMax()-b._valueMin())/c);break;case a.ui.keyCode.PAGE_DOWN:h=b._trimAlignValue(g-(b._valueMax()-b._valueMin())/c);break;case a.ui.keyCode.UP:case a.ui.keyCode.RIGHT:if(g===b._valueMax())return;h=b._trimAlignValue(g+i);break;case a.ui.keyCode.DOWN:case a.ui.keyCode.LEFT:if(g===b._valueMin())return;h=b._trimAlignValue(g-i)}b._slide(d,e,h)}).keyup(function(c){var d=a(this).data("index.ui-slider-handle");b._keySliding&&(b._keySliding=!1,b._stop(c,d),b._change(c,d),a(this).removeClass("ui-state-active"))}),this._refreshValue(),this._animateOff=!1},destroy:function(){return this.handles.remove(),this.range.remove(),this.element.removeClass("ui-slider ui-slider-horizontal ui-slider-vertical ui-slider-disabled ui-widget ui-widget-content ui-corner-all").removeData("slider").unbind(".slider"),this._mouseDestroy(),this},_mouseCapture:function(b){var c=this.options,d,e,f,g,h,i,j,k,l;return c.disabled?!1:(this.elementSize={width:this.element.outerWidth(),height:this.element.outerHeight()},this.elementOffset=this.element.offset(),d={x:b.pageX,y:b.pageY},e=this._normValueFromMouse(d),f=this._valueMax()-this._valueMin()+1,h=this,this.handles.each(function(b){var c=Math.abs(e-h.values(b));f>c&&(f=c,g=a(this),i=b)}),c.range===!0&&this.values(1)===c.min&&(i+=1,g=a(this.handles[i])),j=this._start(b,i),j===!1?!1:(this._mouseSliding=!0,h._handleIndex=i,g.addClass("ui-state-active").focus(),k=g.offset(),l=!a(b.target).parents().andSelf().is(".ui-slider-handle"),this._clickOffset=l?{left:0,top:0}:{left:b.pageX-k.left-g.width()/2,top:b.pageY-k.top-g.height()/2-(parseInt(g.css("borderTopWidth"),10)||0)-(parseInt(g.css("borderBottomWidth"),10)||0)+(parseInt(g.css("marginTop"),10)||0)},this.handles.hasClass("ui-state-hover")||this._slide(b,i,e),this._animateOff=!0,!0))},_mouseStart:function(a){return!0},_mouseDrag:function(a){var b={x:a.pageX,y:a.pageY},c=this._normValueFromMouse(b);return this._slide(a,this._handleIndex,c),!1},_mouseStop:function(a){return this.handles.removeClass("ui-state-active"),this._mouseSliding=!1,this._stop(a,this._handleIndex),this._change(a,this._handleIndex),this._handleIndex=null,this._clickOffset=null,this._animateOff=!1,!1},_detectOrientation:function(){this.orientation=this.options.orientation==="vertical"?"vertical":"horizontal"},_normValueFromMouse:function(a){var b,c,d,e,f;return this.orientation==="horizontal"?(b=this.elementSize.width,c=a.x-this.elementOffset.left-(this._clickOffset?this._clickOffset.left:0)):(b=this.elementSize.height,c=a.y-this.elementOffset.top-(this._clickOffset?this._clickOffset.top:0)),d=c/b,d>1&&(d=1),d<0&&(d=0),this.orientation==="vertical"&&(d=1-d),e=this._valueMax()-this._valueMin(),f=this._valueMin()+d*e,this._trimAlignValue(f)},_start:function(a,b){var c={handle:this.handles[b],value:this.value()};return this.options.values&&this.options.values.length&&(c.value=this.values(b),c.values=this.values()),this._trigger("start",a,c)},_slide:function(a,b,c){var d,e,f;this.options.values&&this.options.values.length?(d=this.values(b?0:1),this.options.values.length===2&&this.options.range===!0&&(b===0&&c>d||b===1&&c<d)&&(c=d),c!==this.values(b)&&(e=this.values(),e[b]=c,f=this._trigger("slide",a,{handle:this.handles[b],value:c,values:e}),d=this.values(b?0:1),f!==!1&&this.values(b,c,!0))):c!==this.value()&&(f=this._trigger("slide",a,{handle:this.handles[b],value:c}),f!==!1&&this.value(c))},_stop:function(a,b){var c={handle:this.handles[b],value:this.value()};this.options.values&&this.options.values.length&&(c.value=this.values(b),c.values=this.values()),this._trigger("stop",a,c)},_change:function(a,b){if(!this._keySliding&&!this._mouseSliding){var c={handle:this.handles[b],value:this.value()};this.options.values&&this.options.values.length&&(c.value=this.values(b),c.values=this.values()),this._trigger("change",a,c)}},value:function(a){if(arguments.length){this.options.value=this._trimAlignValue(a),this._refreshValue(),this._change(null,0);return}return this._value()},values:function(b,c){var d,e,f;if(arguments.length>1){this.options.values[b]=this._trimAlignValue(c),this._refreshValue(),this._change(null,b);return}if(!arguments.length)return this._values();if(!a.isArray(arguments[0]))return this.options.values&&this.options.values.length?this._values(b):this.value();d=this.options.values,e=arguments[0];for(f=0;f<d.length;f+=1)d[f]=this._trimAlignValue(e[f]),this._change(null,f);this._refreshValue()},_setOption:function(b,c){var d,e=0;a.isArray(this.options.values)&&(e=this.options.values.length),a.Widget.prototype._setOption.apply(this,arguments);switch(b){case"disabled":c?(this.handles.filter(".ui-state-focus").blur(),this.handles.removeClass("ui-state-hover"),this.handles.propAttr("disabled",!0),this.element.addClass("ui-disabled")):(this.handles.propAttr("disabled",!1),this.element.removeClass("ui-disabled"));break;case"orientation":this._detectOrientation(),this.element.removeClass("ui-slider-horizontal ui-slider-vertical").addClass("ui-slider-"+this.orientation),this._refreshValue();break;case"value":this._animateOff=!0,this._refreshValue(),this._change(null,0),this._animateOff=!1;break;case"values":this._animateOff=!0,this._refreshValue();for(d=0;d<e;d+=1)this._change(null,d);this._animateOff=!1}},_value:function(){var a=this.options.value;return a=this._trimAlignValue(a),a},_values:function(a){var b,c,d;if(arguments.length)return b=this.options.values[a],b=this._trimAlignValue(b),b;c=this.options.values.slice();for(d=0;d<c.length;d+=1)c[d]=this._trimAlignValue(c[d]);return c},_trimAlignValue:function(a){if(a<=this._valueMin())return this._valueMin();if(a>=this._valueMax())return this._valueMax();var b=this.options.step>0?this.options.step:1,c=(a-this._valueMin())%b,d=a-c;return Math.abs(c)*2>=b&&(d+=c>0?b:-b),parseFloat(d.toFixed(5))},_valueMin:function(){return this.options.min},_valueMax:function(){return this.options.max},_refreshValue:function(){var b=this.options.range,c=this.options,d=this,e=this._animateOff?!1:c.animate,f,g={},h,i,j,k;this.options.values&&this.options.values.length?this.handles.each(function(b,i){f=(d.values(b)-d._valueMin())/(d._valueMax()-d._valueMin())*100,g[d.orientation==="horizontal"?"left":"bottom"]=f+"%",a(this).stop(1,1)[e?"animate":"css"](g,c.animate),d.options.range===!0&&(d.orientation==="horizontal"?(b===0&&d.range.stop(1,1)[e?"animate":"css"]({left:f+"%"},c.animate),b===1&&d.range[e?"animate":"css"]({width:f-h+"%"},{queue:!1,duration:c.animate})):(b===0&&d.range.stop(1,1)[e?"animate":"css"]({bottom:f+"%"},c.animate),b===1&&d.range[e?"animate":"css"]({height:f-h+"%"},{queue:!1,duration:c.animate}))),h=f}):(i=this.value(),j=this._valueMin(),k=this._valueMax(),f=k!==j?(i-j)/(k-j)*100:0,g[d.orientation==="horizontal"?"left":"bottom"]=f+"%",this.handle.stop(1,1)[e?"animate":"css"](g,c.animate),b==="min"&&this.orientation==="horizontal"&&this.range.stop(1,1)[e?"animate":"css"]({width:f+"%"},c.animate),b==="max"&&this.orientation==="horizontal"&&this.range[e?"animate":"css"]({width:100-f+"%"},{queue:!1,duration:c.animate}),b==="min"&&this.orientation==="vertical"&&this.range.stop(1,1)[e?"animate":"css"]({height:f+"%"},c.animate),b==="max"&&this.orientation==="vertical"&&this.range[e?"animate":"css"]({height:100-f+"%"},{queue:!1,duration:c.animate}))}}),a.extend(a.ui.slider,{version:"1.8.23"})})(jQuery);;/*! jQuery UI - v1.8.23 - 2012-08-15
    +-* https://github.com/jquery/jquery-ui
    +-* Includes: jquery.ui.tabs.js
    +-* Copyright (c) 2012 AUTHORS.txt; Licensed MIT, GPL */
    +-(function(a,b){function e(){return++c}function f(){return++d}var c=0,d=0;a.widget("ui.tabs",{options:{add:null,ajaxOptions:null,cache:!1,cookie:null,collapsible:!1,disable:null,disabled:[],enable:null,event:"click",fx:null,idPrefix:"ui-tabs-",load:null,panelTemplate:"<div></div>",remove:null,select:null,show:null,spinner:"<em>Loading&#8230;</em>",tabTemplate:"<li><a href='#{href}'><span>#{label}</span></a></li>"},_create:function(){this._tabify(!0)},_setOption:function(a,b){if(a=="selected"){if(this.options.collapsible&&b==this.options.selected)return;this.select(b)}else this.options[a]=b,this._tabify()},_tabId:function(a){return a.title&&a.title.replace(/\s/g,"_").replace(/[^\w\u00c0-\uFFFF-]/g,"")||this.options.idPrefix+e()},_sanitizeSelector:function(a){return a.replace(/:/g,"\\:")},_cookie:function(){var b=this.cookie||(this.cookie=this.options.cookie.name||"ui-tabs-"+f());return a.cookie.apply(null,[b].concat(a.makeArray(arguments)))},_ui:function(a,b){return{tab:a,panel:b,index:this.anchors.index(a)}},_cleanup:function(){this.lis.filter(".ui-state-processing").removeClass("ui-state-processing").find("span:data(label.tabs)").each(function(){var b=a(this);b.html(b.data("label.tabs")).removeData("label.tabs")})},_tabify:function(c){function m(b,c){b.css("display",""),!a.support.opacity&&c.opacity&&b[0].style.removeAttribute("filter")}var d=this,e=this.options,f=/^#.+/;this.list=this.element.find("ol,ul").eq(0),this.lis=a(" > li:has(a[href])",this.list),this.anchors=this.lis.map(function(){return a("a",this)[0]}),this.panels=a([]),this.anchors.each(function(b,c){var g=a(c).attr("href"),h=g.split("#")[0],i;h&&(h===location.toString().split("#")[0]||(i=a("base")[0])&&h===i.href)&&(g=c.hash,c.href=g);if(f.test(g))d.panels=d.panels.add(d.element.find(d._sanitizeSelector(g)));else if(g&&g!=="#"){a.data(c,"href.tabs",g),a.data(c,"load.tabs",g.replace(/#.*$/,""));var j=d._tabId(c);c.href="#"+j;var k=d.element.find("#"+j);k.length||(k=a(e.panelTemplate).attr("id",j).addClass("ui-tabs-panel ui-widget-content ui-corner-bottom").insertAfter(d.panels[b-1]||d.list),k.data("destroy.tabs",!0)),d.panels=d.panels.add(k)}else e.disabled.push(b)}),c?(this.element.addClass("ui-tabs ui-widget ui-widget-content ui-corner-all"),this.list.addClass("ui-tabs-nav ui-helper-reset ui-helper-clearfix ui-widget-header ui-corner-all"),this.lis.addClass("ui-state-default ui-corner-top"),this.panels.addClass("ui-tabs-panel ui-widget-content ui-corner-bottom"),e.selected===b?(location.hash&&this.anchors.each(function(a,b){if(b.hash==location.hash)return e.selected=a,!1}),typeof e.selected!="number"&&e.cookie&&(e.selected=parseInt(d._cookie(),10)),typeof e.selected!="number"&&this.lis.filter(".ui-tabs-selected").length&&(e.selected=this.lis.index(this.lis.filter(".ui-tabs-selected"))),e.selected=e.selected||(this.lis.length?0:-1)):e.selected===null&&(e.selected=-1),e.selected=e.selected>=0&&this.anchors[e.selected]||e.selected<0?e.selected:0,e.disabled=a.unique(e.disabled.concat(a.map(this.lis.filter(".ui-state-disabled"),function(a,b){return d.lis.index(a)}))).sort(),a.inArray(e.selected,e.disabled)!=-1&&e.disabled.splice(a.inArray(e.selected,e.disabled),1),this.panels.addClass("ui-tabs-hide"),this.lis.removeClass("ui-tabs-selected ui-state-active"),e.selected>=0&&this.anchors.length&&(d.element.find(d._sanitizeSelector(d.anchors[e.selected].hash)).removeClass("ui-tabs-hide"),this.lis.eq(e.selected).addClass("ui-tabs-selected ui-state-active"),d.element.queue("tabs",function(){d._trigger("show",null,d._ui(d.anchors[e.selected],d.element.find(d._sanitizeSelector(d.anchors[e.selected].hash))[0]))}),this.load(e.selected)),a(window).bind("unload",function(){d.lis.add(d.anchors).unbind(".tabs"),d.lis=d.anchors=d.panels=null})):e.selected=this.lis.index(this.lis.filter(".ui-tabs-selected")),this.element[e.collapsible?"addClass":"removeClass"]("ui-tabs-collapsible"),e.cookie&&this._cookie(e.selected,e.cookie);for(var g=0,h;h=this.lis[g];g++)a(h)[a.inArray(g,e.disabled)!=-1&&!a(h).hasClass("ui-tabs-selected")?"addClass":"removeClass"]("ui-state-disabled");e.cache===!1&&this.anchors.removeData("cache.tabs"),this.lis.add(this.anchors).unbind(".tabs");if(e.event!=="mouseover"){var i=function(a,b){b.is(":not(.ui-state-disabled)")&&b.addClass("ui-state-"+a)},j=function(a,b){b.removeClass("ui-state-"+a)};this.lis.bind("mouseover.tabs",function(){i("hover",a(this))}),this.lis.bind("mouseout.tabs",function(){j("hover",a(this))}),this.anchors.bind("focus.tabs",function(){i("focus",a(this).closest("li"))}),this.anchors.bind("blur.tabs",function(){j("focus",a(this).closest("li"))})}var k,l;e.fx&&(a.isArray(e.fx)?(k=e.fx[0],l=e.fx[1]):k=l=e.fx);var n=l?function(b,c){a(b).closest("li").addClass("ui-tabs-selected ui-state-active"),c.hide().removeClass("ui-tabs-hide").animate(l,l.duration||"normal",function(){m(c,l),d._trigger("show",null,d._ui(b,c[0]))})}:function(b,c){a(b).closest("li").addClass("ui-tabs-selected ui-state-active"),c.removeClass("ui-tabs-hide"),d._trigger("show",null,d._ui(b,c[0]))},o=k?function(a,b){b.animate(k,k.duration||"normal",function(){d.lis.removeClass("ui-tabs-selected ui-state-active"),b.addClass("ui-tabs-hide"),m(b,k),d.element.dequeue("tabs")})}:function(a,b,c){d.lis.removeClass("ui-tabs-selected ui-state-active"),b.addClass("ui-tabs-hide"),d.element.dequeue("tabs")};this.anchors.bind(e.event+".tabs",function(){var b=this,c=a(b).closest("li"),f=d.panels.filter(":not(.ui-tabs-hide)"),g=d.element.find(d._sanitizeSelector(b.hash));if(c.hasClass("ui-tabs-selected")&&!e.collapsible||c.hasClass("ui-state-disabled")||c.hasClass("ui-state-processing")||d.panels.filter(":animated").length||d._trigger("select",null,d._ui(this,g[0]))===!1)return this.blur(),!1;e.selected=d.anchors.index(this),d.abort();if(e.collapsible){if(c.hasClass("ui-tabs-selected"))return e.selected=-1,e.cookie&&d._cookie(e.selected,e.cookie),d.element.queue("tabs",function(){o(b,f)}).dequeue("tabs"),this.blur(),!1;if(!f.length)return e.cookie&&d._cookie(e.selected,e.cookie),d.element.queue("tabs",function(){n(b,g)}),d.load(d.anchors.index(this)),this.blur(),!1}e.cookie&&d._cookie(e.selected,e.cookie);if(g.length)f.length&&d.element.queue("tabs",function(){o(b,f)}),d.element.queue("tabs",function(){n(b,g)}),d.load(d.anchors.index(this));else throw"jQuery UI Tabs: Mismatching fragment identifier.";a.browser.msie&&this.blur()}),this.anchors.bind("click.tabs",function(){return!1})},_getIndex:function(a){return typeof a=="string"&&(a=this.anchors.index(this.anchors.filter("[href$='"+a+"']"))),a},destroy:function(){var b=this.options;return this.abort(),this.element.unbind(".tabs").removeClass("ui-tabs ui-widget ui-widget-content ui-corner-all ui-tabs-collapsible").removeData("tabs"),this.list.removeClass("ui-tabs-nav ui-helper-reset ui-helper-clearfix ui-widget-header ui-corner-all"),this.anchors.each(function(){var b=a.data(this,"href.tabs");b&&(this.href=b);var c=a(this).unbind(".tabs");a.each(["href","load","cache"],function(a,b){c.removeData(b+".tabs")})}),this.lis.unbind(".tabs").add(this.panels).each(function(){a.data(this,"destroy.tabs")?a(this).remove():a(this).removeClass(["ui-state-default","ui-corner-top","ui-tabs-selected","ui-state-active","ui-state-hover","ui-state-focus","ui-state-disabled","ui-tabs-panel","ui-widget-content","ui-corner-bottom","ui-tabs-hide"].join(" "))}),b.cookie&&this._cookie(null,b.cookie),this},add:function(c,d,e){e===b&&(e=this.anchors.length);var f=this,g=this.options,h=a(g.tabTemplate.replace(/#\{href\}/g,c).replace(/#\{label\}/g,d)),i=c.indexOf("#")?this._tabId(a("a",h)[0]):c.replace("#","");h.addClass("ui-state-default ui-corner-top").data("destroy.tabs",!0);var j=f.element.find("#"+i);return j.length||(j=a(g.panelTemplate).attr("id",i).data("destroy.tabs",!0)),j.addClass("ui-tabs-panel ui-widget-content ui-corner-bottom ui-tabs-hide"),e>=this.lis.length?(h.appendTo(this.list),j.appendTo(this.list[0].parentNode)):(h.insertBefore(this.lis[e]),j.insertBefore(this.panels[e])),g.disabled=a.map(g.disabled,function(a,b){return a>=e?++a:a}),this._tabify(),this.anchors.length==1&&(g.selected=0,h.addClass("ui-tabs-selected ui-state-active"),j.removeClass("ui-tabs-hide"),this.element.queue("tabs",function(){f._trigger("show",null,f._ui(f.anchors[0],f.panels[0]))}),this.load(0)),this._trigger("add",null,this._ui(this.anchors[e],this.panels[e])),this},remove:function(b){b=this._getIndex(b);var c=this.options,d=this.lis.eq(b).remove(),e=this.panels.eq(b).remove();return d.hasClass("ui-tabs-selected")&&this.anchors.length>1&&this.select(b+(b+1<this.anchors.length?1:-1)),c.disabled=a.map(a.grep(c.disabled,function(a,c){return a!=b}),function(a,c){return a>=b?--a:a}),this._tabify(),this._trigger("remove",null,this._ui(d.find("a")[0],e[0])),this},enable:function(b){b=this._getIndex(b);var c=this.options;if(a.inArray(b,c.disabled)==-1)return;return this.lis.eq(b).removeClass("ui-state-disabled"),c.disabled=a.grep(c.disabled,function(a,c){return a!=b}),this._trigger("enable",null,this._ui(this.anchors[b],this.panels[b])),this},disable:function(a){a=this._getIndex(a);var b=this,c=this.options;return a!=c.selected&&(this.lis.eq(a).addClass("ui-state-disabled"),c.disabled.push(a),c.disabled.sort(),this._trigger("disable",null,this._ui(this.anchors[a],this.panels[a]))),this},select:function(a){a=this._getIndex(a);if(a==-1)if(this.options.collapsible&&this.options.selected!=-1)a=this.options.selected;else return this;return this.anchors.eq(a).trigger(this.options.event+".tabs"),this},load:function(b){b=this._getIndex(b);var c=this,d=this.options,e=this.anchors.eq(b)[0],f=a.data(e,"load.tabs");this.abort();if(!f||this.element.queue("tabs").length!==0&&a.data(e,"cache.tabs")){this.element.dequeue("tabs");return}this.lis.eq(b).addClass("ui-state-processing");if(d.spinner){var g=a("span",e);g.data("label.tabs",g.html()).html(d.spinner)}return this.xhr=a.ajax(a.extend({},d.ajaxOptions,{url:f,success:function(f,g){c.element.find(c._sanitizeSelector(e.hash)).html(f),c._cleanup(),d.cache&&a.data(e,"cache.tabs",!0),c._trigger("load",null,c._ui(c.anchors[b],c.panels[b]));try{d.ajaxOptions.success(f,g)}catch(h){}},error:function(a,f,g){c._cleanup(),c._trigger("load",null,c._ui(c.anchors[b],c.panels[b]));try{d.ajaxOptions.error(a,f,b,e)}catch(g){}}})),c.element.dequeue("tabs"),this},abort:function(){return this.element.queue([]),this.panels.stop(!1,!0),this.element.queue("tabs",this.element.queue("tabs").splice(-2,2)),this.xhr&&(this.xhr.abort(),delete this.xhr),this._cleanup(),this},url:function(a,b){return this.anchors.eq(a).removeData("cache.tabs").data("load.tabs",b),this},length:function(){return this.anchors.length}}),a.extend(a.ui.tabs,{version:"1.8.23"}),a.extend(a.ui.tabs.prototype,{rotation:null,rotate:function(a,b){var c=this,d=this.options,e=c._rotate||(c._rotate=function(b){clearTimeout(c.rotation),c.rotation=setTimeout(function(){var a=d.selected;c.select(++a<c.anchors.length?a:0)},a),b&&b.stopPropagation()}),f=c._unrotate||(c._unrotate=b?function(a){e()}:function(a){a.clientX&&c.rotate(null)});return a?(this.element.bind("tabsshow",e),this.anchors.bind(d.event+".tabs",f),e()):(clearTimeout(c.rotation),this.element.unbind("tabsshow",e),this.anchors.unbind(d.event+".tabs",f),delete this._rotate,delete this._unrotate),this}})})(jQuery);;/*! jQuery UI - v1.8.23 - 2012-08-15
    +-* https://github.com/jquery/jquery-ui
    +-* Includes: jquery.ui.datepicker.js
    +-* Copyright (c) 2012 AUTHORS.txt; Licensed MIT, GPL */
    +-(function($,undefined){function Datepicker(){this.debug=!1,this._curInst=null,this._keyEvent=!1,this._disabledInputs=[],this._datepickerShowing=!1,this._inDialog=!1,this._mainDivId="ui-datepicker-div",this._inlineClass="ui-datepicker-inline",this._appendClass="ui-datepicker-append",this._triggerClass="ui-datepicker-trigger",this._dialogClass="ui-datepicker-dialog",this._disableClass="ui-datepicker-disabled",this._unselectableClass="ui-datepicker-unselectable",this._currentClass="ui-datepicker-current-day",this._dayOverClass="ui-datepicker-days-cell-over",this.regional=[],this.regional[""]={closeText:"Done",prevText:"Prev",nextText:"Next",currentText:"Today",monthNames:["January","February","March","April","May","June","July","August","September","October","November","December"],monthNamesShort:["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"],dayNames:["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"],dayNamesShort:["Sun","Mon","Tue","Wed","Thu","Fri","Sat"],dayNamesMin:["Su","Mo","Tu","We","Th","Fr","Sa"],weekHeader:"Wk",dateFormat:"mm/dd/yy",firstDay:0,isRTL:!1,showMonthAfterYear:!1,yearSuffix:""},this._defaults={showOn:"focus",showAnim:"fadeIn",showOptions:{},defaultDate:null,appendText:"",buttonText:"...",buttonImage:"",buttonImageOnly:!1,hideIfNoPrevNext:!1,navigationAsDateFormat:!1,gotoCurrent:!1,changeMonth:!1,changeYear:!1,yearRange:"c-10:c+10",showOtherMonths:!1,selectOtherMonths:!1,showWeek:!1,calculateWeek:this.iso8601Week,shortYearCutoff:"+10",minDate:null,maxDate:null,duration:"fast",beforeShowDay:null,beforeShow:null,onSelect:null,onChangeMonthYear:null,onClose:null,numberOfMonths:1,showCurrentAtPos:0,stepMonths:1,stepBigMonths:12,altField:"",altFormat:"",constrainInput:!0,showButtonPanel:!1,autoSize:!1,disabled:!1},$.extend(this._defaults,this.regional[""]),this.dpDiv=bindHover($('<div id="'+this._mainDivId+'" class="ui-datepicker ui-widget ui-widget-content ui-helper-clearfix ui-corner-all"></div>'))}function bindHover(a){var b="button, .ui-datepicker-prev, .ui-datepicker-next, .ui-datepicker-calendar td a";return a.bind("mouseout",function(a){var c=$(a.target).closest(b);if(!c.length)return;c.removeClass("ui-state-hover ui-datepicker-prev-hover ui-datepicker-next-hover")}).bind("mouseover",function(c){var d=$(c.target).closest(b);if($.datepicker._isDisabledDatepicker(instActive.inline?a.parent()[0]:instActive.input[0])||!d.length)return;d.parents(".ui-datepicker-calendar").find("a").removeClass("ui-state-hover"),d.addClass("ui-state-hover"),d.hasClass("ui-datepicker-prev")&&d.addClass("ui-datepicker-prev-hover"),d.hasClass("ui-datepicker-next")&&d.addClass("ui-datepicker-next-hover")})}function extendRemove(a,b){$.extend(a,b);for(var c in b)if(b[c]==null||b[c]==undefined)a[c]=b[c];return a}function isArray(a){return a&&($.browser.safari&&typeof a=="object"&&a.length||a.constructor&&a.constructor.toString().match(/\Array\(\)/))}$.extend($.ui,{datepicker:{version:"1.8.23"}});var PROP_NAME="datepicker",dpuuid=(new Date).getTime(),instActive;$.extend(Datepicker.prototype,{markerClassName:"hasDatepicker",maxRows:4,log:function(){this.debug&&console.log.apply("",arguments)},_widgetDatepicker:function(){return this.dpDiv},setDefaults:function(a){return extendRemove(this._defaults,a||{}),this},_attachDatepicker:function(target,settings){var inlineSettings=null;for(var attrName in this._defaults){var attrValue=target.getAttribute("date:"+attrName);if(attrValue){inlineSettings=inlineSettings||{};try{inlineSettings[attrName]=eval(attrValue)}catch(err){inlineSettings[attrName]=attrValue}}}var nodeName=target.nodeName.toLowerCase(),inline=nodeName=="div"||nodeName=="span";target.id||(this.uuid+=1,target.id="dp"+this.uuid);var inst=this._newInst($(target),inline);inst.settings=$.extend({},settings||{},inlineSettings||{}),nodeName=="input"?this._connectDatepicker(target,inst):inline&&this._inlineDatepicker(target,inst)},_newInst:function(a,b){var c=a[0].id.replace(/([^A-Za-z0-9_-])/g,"\\\\$1");return{id:c,input:a,selectedDay:0,selectedMonth:0,selectedYear:0,drawMonth:0,drawYear:0,inline:b,dpDiv:b?bindHover($('<div class="'+this._inlineClass+' ui-datepicker ui-widget ui-widget-content ui-helper-clearfix ui-corner-all"></div>')):this.dpDiv}},_connectDatepicker:function(a,b){var c=$(a);b.append=$([]),b.trigger=$([]);if(c.hasClass(this.markerClassName))return;this._attachments(c,b),c.addClass(this.markerClassName).keydown(this._doKeyDown).keypress(this._doKeyPress).keyup(this._doKeyUp).bind("setData.datepicker",function(a,c,d){b.settings[c]=d}).bind("getData.datepicker",function(a,c){return this._get(b,c)}),this._autoSize(b),$.data(a,PROP_NAME,b),b.settings.disabled&&this._disableDatepicker(a)},_attachments:function(a,b){var c=this._get(b,"appendText"),d=this._get(b,"isRTL");b.append&&b.append.remove(),c&&(b.append=$('<span class="'+this._appendClass+'">'+c+"</span>"),a[d?"before":"after"](b.append)),a.unbind("focus",this._showDatepicker),b.trigger&&b.trigger.remove();var e=this._get(b,"showOn");(e=="focus"||e=="both")&&a.focus(this._showDatepicker);if(e=="button"||e=="both"){var f=this._get(b,"buttonText"),g=this._get(b,"buttonImage");b.trigger=$(this._get(b,"buttonImageOnly")?$("<img/>").addClass(this._triggerClass).attr({src:g,alt:f,title:f}):$('<button type="button"></button>').addClass(this._triggerClass).html(g==""?f:$("<img/>").attr({src:g,alt:f,title:f}))),a[d?"before":"after"](b.trigger),b.trigger.click(function(){return $.datepicker._datepickerShowing&&$.datepicker._lastInput==a[0]?$.datepicker._hideDatepicker():$.datepicker._datepickerShowing&&$.datepicker._lastInput!=a[0]?($.datepicker._hideDatepicker(),$.datepicker._showDatepicker(a[0])):$.datepicker._showDatepicker(a[0]),!1})}},_autoSize:function(a){if(this._get(a,"autoSize")&&!a.inline){var b=new Date(2009,11,20),c=this._get(a,"dateFormat");if(c.match(/[DM]/)){var d=function(a){var b=0,c=0;for(var d=0;d<a.length;d++)a[d].length>b&&(b=a[d].length,c=d);return c};b.setMonth(d(this._get(a,c.match(/MM/)?"monthNames":"monthNamesShort"))),b.setDate(d(this._get(a,c.match(/DD/)?"dayNames":"dayNamesShort"))+20-b.getDay())}a.input.attr("size",this._formatDate(a,b).length)}},_inlineDatepicker:function(a,b){var c=$(a);if(c.hasClass(this.markerClassName))return;c.addClass(this.markerClassName).append(b.dpDiv).bind("setData.datepicker",function(a,c,d){b.settings[c]=d}).bind("getData.datepicker",function(a,c){return this._get(b,c)}),$.data(a,PROP_NAME,b),this._setDate(b,this._getDefaultDate(b),!0),this._updateDatepicker(b),this._updateAlternate(b),b.settings.disabled&&this._disableDatepicker(a),b.dpDiv.css("display","block")},_dialogDatepicker:function(a,b,c,d,e){var f=this._dialogInst;if(!f){this.uuid+=1;var g="dp"+this.uuid;this._dialogInput=$('<input type="text" id="'+g+'" style="position: absolute; top: -100px; width: 0px;"/>'),this._dialogInput.keydown(this._doKeyDown),$("body").append(this._dialogInput),f=this._dialogInst=this._newInst(this._dialogInput,!1),f.settings={},$.data(this._dialogInput[0],PROP_NAME,f)}extendRemove(f.settings,d||{}),b=b&&b.constructor==Date?this._formatDate(f,b):b,this._dialogInput.val(b),this._pos=e?e.length?e:[e.pageX,e.pageY]:null;if(!this._pos){var h=document.documentElement.clientWidth,i=document.documentElement.clientHeight,j=document.documentElement.scrollLeft||document.body.scrollLeft,k=document.documentElement.scrollTop||document.body.scrollTop;this._pos=[h/2-100+j,i/2-150+k]}return this._dialogInput.css("left",this._pos[0]+20+"px").css("top",this._pos[1]+"px"),f.settings.onSelect=c,this._inDialog=!0,this.dpDiv.addClass(this._dialogClass),this._showDatepicker(this._dialogInput[0]),$.blockUI&&$.blockUI(this.dpDiv),$.data(this._dialogInput[0],PROP_NAME,f),this},_destroyDatepicker:function(a){var b=$(a),c=$.data(a,PROP_NAME);if(!b.hasClass(this.markerClassName))return;var d=a.nodeName.toLowerCase();$.removeData(a,PROP_NAME),d=="input"?(c.append.remove(),c.trigger.remove(),b.removeClass(this.markerClassName).unbind("focus",this._showDatepicker).unbind("keydown",this._doKeyDown).unbind("keypress",this._doKeyPress).unbind("keyup",this._doKeyUp)):(d=="div"||d=="span")&&b.removeClass(this.markerClassName).empty()},_enableDatepicker:function(a){var b=$(a),c=$.data(a,PROP_NAME);if(!b.hasClass(this.markerClassName))return;var d=a.nodeName.toLowerCase();if(d=="input")a.disabled=!1,c.trigger.filter("button").each(function(){this.disabled=!1}).end().filter("img").css({opacity:"1.0",cursor:""});else if(d=="div"||d=="span"){var e=b.children("."+this._inlineClass);e.children().removeClass("ui-state-disabled"),e.find("select.ui-datepicker-month, select.ui-datepicker-year").removeAttr("disabled")}this._disabledInputs=$.map(this._disabledInputs,function(b){return b==a?null:b})},_disableDatepicker:function(a){var b=$(a),c=$.data(a,PROP_NAME);if(!b.hasClass(this.markerClassName))return;var d=a.nodeName.toLowerCase();if(d=="input")a.disabled=!0,c.trigger.filter("button").each(function(){this.disabled=!0}).end().filter("img").css({opacity:"0.5",cursor:"default"});else if(d=="div"||d=="span"){var e=b.children("."+this._inlineClass);e.children().addClass("ui-state-disabled"),e.find("select.ui-datepicker-month, select.ui-datepicker-year").attr("disabled","disabled")}this._disabledInputs=$.map(this._disabledInputs,function(b){return b==a?null:b}),this._disabledInputs[this._disabledInputs.length]=a},_isDisabledDatepicker:function(a){if(!a)return!1;for(var b=0;b<this._disabledInputs.length;b++)if(this._disabledInputs[b]==a)return!0;return!1},_getInst:function(a){try{return $.data(a,PROP_NAME)}catch(b){throw"Missing instance data for this datepicker"}},_optionDatepicker:function(a,b,c){var d=this._getInst(a);if(arguments.length==2&&typeof b=="string")return b=="defaults"?$.extend({},$.datepicker._defaults):d?b=="all"?$.extend({},d.settings):this._get(d,b):null;var e=b||{};typeof b=="string"&&(e={},e[b]=c);if(d){this._curInst==d&&this._hideDatepicker();var f=this._getDateDatepicker(a,!0),g=this._getMinMaxDate(d,"min"),h=this._getMinMaxDate(d,"max");extendRemove(d.settings,e),g!==null&&e.dateFormat!==undefined&&e.minDate===undefined&&(d.settings.minDate=this._formatDate(d,g)),h!==null&&e.dateFormat!==undefined&&e.maxDate===undefined&&(d.settings.maxDate=this._formatDate(d,h)),this._attachments($(a),d),this._autoSize(d),this._setDate(d,f),this._updateAlternate(d),this._updateDatepicker(d)}},_changeDatepicker:function(a,b,c){this._optionDatepicker(a,b,c)},_refreshDatepicker:function(a){var b=this._getInst(a);b&&this._updateDatepicker(b)},_setDateDatepicker:function(a,b){var c=this._getInst(a);c&&(this._setDate(c,b),this._updateDatepicker(c),this._updateAlternate(c))},_getDateDatepicker:function(a,b){var c=this._getInst(a);return c&&!c.inline&&this._setDateFromField(c,b),c?this._getDate(c):null},_doKeyDown:function(a){var b=$.datepicker._getInst(a.target),c=!0,d=b.dpDiv.is(".ui-datepicker-rtl");b._keyEvent=!0;if($.datepicker._datepickerShowing)switch(a.keyCode){case 9:$.datepicker._hideDatepicker(),c=!1;break;case 13:var e=$("td."+$.datepicker._dayOverClass+":not(."+$.datepicker._currentClass+")",b.dpDiv);e[0]&&$.datepicker._selectDay(a.target,b.selectedMonth,b.selectedYear,e[0]);var f=$.datepicker._get(b,"onSelect");if(f){var g=$.datepicker._formatDate(b);f.apply(b.input?b.input[0]:null,[g,b])}else $.datepicker._hideDatepicker();return!1;case 27:$.datepicker._hideDatepicker();break;case 33:$.datepicker._adjustDate(a.target,a.ctrlKey?-$.datepicker._get(b,"stepBigMonths"):-$.datepicker._get(b,"stepMonths"),"M");break;case 34:$.datepicker._adjustDate(a.target,a.ctrlKey?+$.datepicker._get(b,"stepBigMonths"):+$.datepicker._get(b,"stepMonths"),"M");break;case 35:(a.ctrlKey||a.metaKey)&&$.datepicker._clearDate(a.target),c=a.ctrlKey||a.metaKey;break;case 36:(a.ctrlKey||a.metaKey)&&$.datepicker._gotoToday(a.target),c=a.ctrlKey||a.metaKey;break;case 37:(a.ctrlKey||a.metaKey)&&$.datepicker._adjustDate(a.target,d?1:-1,"D"),c=a.ctrlKey||a.metaKey,a.originalEvent.altKey&&$.datepicker._adjustDate(a.target,a.ctrlKey?-$.datepicker._get(b,"stepBigMonths"):-$.datepicker._get(b,"stepMonths"),"M");break;case 38:(a.ctrlKey||a.metaKey)&&$.datepicker._adjustDate(a.target,-7,"D"),c=a.ctrlKey||a.metaKey;break;case 39:(a.ctrlKey||a.metaKey)&&$.datepicker._adjustDate(a.target,d?-1:1,"D"),c=a.ctrlKey||a.metaKey,a.originalEvent.altKey&&$.datepicker._adjustDate(a.target,a.ctrlKey?+$.datepicker._get(b,"stepBigMonths"):+$.datepicker._get(b,"stepMonths"),"M");break;case 40:(a.ctrlKey||a.metaKey)&&$.datepicker._adjustDate(a.target,7,"D"),c=a.ctrlKey||a.metaKey;break;default:c=!1}else a.keyCode==36&&a.ctrlKey?$.datepicker._showDatepicker(this):c=!1;c&&(a.preventDefault(),a.stopPropagation())},_doKeyPress:function(a){var b=$.datepicker._getInst(a.target);if($.datepicker._get(b,"constrainInput")){var c=$.datepicker._possibleChars($.datepicker._get(b,"dateFormat")),d=String.fromCharCode(a.charCode==undefined?a.keyCode:a.charCode);return a.ctrlKey||a.metaKey||d<" "||!c||c.indexOf(d)>-1}},_doKeyUp:function(a){var b=$.datepicker._getInst(a.target);if(b.input.val()!=b.lastVal)try{var c=$.datepicker.parseDate($.datepicker._get(b,"dateFormat"),b.input?b.input.val():null,$.datepicker._getFormatConfig(b));c&&($.datepicker._setDateFromField(b),$.datepicker._updateAlternate(b),$.datepicker._updateDatepicker(b))}catch(d){$.datepicker.log(d)}return!0},_showDatepicker:function(a){a=a.target||a,a.nodeName.toLowerCase()!="input"&&(a=$("input",a.parentNode)[0]);if($.datepicker._isDisabledDatepicker(a)||$.datepicker._lastInput==a)return;var b=$.datepicker._getInst(a);$.datepicker._curInst&&$.datepicker._curInst!=b&&($.datepicker._curInst.dpDiv.stop(!0,!0),b&&$.datepicker._datepickerShowing&&$.datepicker._hideDatepicker($.datepicker._curInst.input[0]));var c=$.datepicker._get(b,"beforeShow"),d=c?c.apply(a,[a,b]):{};if(d===!1)return;extendRemove(b.settings,d),b.lastVal=null,$.datepicker._lastInput=a,$.datepicker._setDateFromField(b),$.datepicker._inDialog&&(a.value=""),$.datepicker._pos||($.datepicker._pos=$.datepicker._findPos(a),$.datepicker._pos[1]+=a.offsetHeight);var e=!1;$(a).parents().each(function(){return e|=$(this).css("position")=="fixed",!e}),e&&$.browser.opera&&($.datepicker._pos[0]-=document.documentElement.scrollLeft,$.datepicker._pos[1]-=document.documentElement.scrollTop);var f={left:$.datepicker._pos[0],top:$.datepicker._pos[1]};$.datepicker._pos=null,b.dpDiv.empty(),b.dpDiv.css({position:"absolute",display:"block",top:"-1000px"}),$.datepicker._updateDatepicker(b),f=$.datepicker._checkOffset(b,f,e),b.dpDiv.css({position:$.datepicker._inDialog&&$.blockUI?"static":e?"fixed":"absolute",display:"none",left:f.left+"px",top:f.top+"px"});if(!b.inline){var g=$.datepicker._get(b,"showAnim"),h=$.datepicker._get(b,"duration"),i=function(){var a=b.dpDiv.find("iframe.ui-datepicker-cover");if(!!a.length){var c=$.datepicker._getBorders(b.dpDiv);a.css({left:-c[0],top:-c[1],width:b.dpDiv.outerWidth(),height:b.dpDiv.outerHeight()})}};b.dpDiv.zIndex($(a).zIndex()+1),$.datepicker._datepickerShowing=!0,$.effects&&$.effects[g]?b.dpDiv.show(g,$.datepicker._get(b,"showOptions"),h,i):b.dpDiv[g||"show"](g?h:null,i),(!g||!h)&&i(),b.input.is(":visible")&&!b.input.is(":disabled")&&b.input.focus(),$.datepicker._curInst=b}},_updateDatepicker:function(a){var b=this;b.maxRows=4;var c=$.datepicker._getBorders(a.dpDiv);instActive=a,a.dpDiv.empty().append(this._generateHTML(a)),this._attachHandlers(a);var d=a.dpDiv.find("iframe.ui-datepicker-cover");!d.length||d.css({left:-c[0],top:-c[1],width:a.dpDiv.outerWidth(),height:a.dpDiv.outerHeight()}),a.dpDiv.find("."+this._dayOverClass+" a").mouseover();var e=this._getNumberOfMonths(a),f=e[1],g=17;a.dpDiv.removeClass("ui-datepicker-multi-2 ui-datepicker-multi-3 ui-datepicker-multi-4").width(""),f>1&&a.dpDiv.addClass("ui-datepicker-multi-"+f).css("width",g*f+"em"),a.dpDiv[(e[0]!=1||e[1]!=1?"add":"remove")+"Class"]("ui-datepicker-multi"),a.dpDiv[(this._get(a,"isRTL")?"add":"remove")+"Class"]("ui-datepicker-rtl"),a==$.datepicker._curInst&&$.datepicker._datepickerShowing&&a.input&&a.input.is(":visible")&&!a.input.is(":disabled")&&a.input[0]!=document.activeElement&&a.input.focus();if(a.yearshtml){var h=a.yearshtml;setTimeout(function(){h===a.yearshtml&&a.yearshtml&&a.dpDiv.find("select.ui-datepicker-year:first").replaceWith(a.yearshtml),h=a.yearshtml=null},0)}},_getBorders:function(a){var b=function(a){return{thin:1,medium:2,thick:3}[a]||a};return[parseFloat(b(a.css("border-left-width"))),parseFloat(b(a.css("border-top-width")))]},_checkOffset:function(a,b,c){var d=a.dpDiv.outerWidth(),e=a.dpDiv.outerHeight(),f=a.input?a.input.outerWidth():0,g=a.input?a.input.outerHeight():0,h=document.documentElement.clientWidth+(c?0:$(document).scrollLeft()),i=document.documentElement.clientHeight+(c?0:$(document).scrollTop());return b.left-=this._get(a,"isRTL")?d-f:0,b.left-=c&&b.left==a.input.offset().left?$(document).scrollLeft():0,b.top-=c&&b.top==a.input.offset().top+g?$(document).scrollTop():0,b.left-=Math.min(b.left,b.left+d>h&&h>d?Math.abs(b.left+d-h):0),b.top-=Math.min(b.top,b.top+e>i&&i>e?Math.abs(e+g):0),b},_findPos:function(a){var b=this._getInst(a),c=this._get(b,"isRTL");while(a&&(a.type=="hidden"||a.nodeType!=1||$.expr.filters.hidden(a)))a=a[c?"previousSibling":"nextSibling"];var d=$(a).offset();return[d.left,d.top]},_hideDatepicker:function(a){var b=this._curInst;if(!b||a&&b!=$.data(a,PROP_NAME))return;if(this._datepickerShowing){var c=this._get(b,"showAnim"),d=this._get(b,"duration"),e=function(){$.datepicker._tidyDialog(b)};$.effects&&$.effects[c]?b.dpDiv.hide(c,$.datepicker._get(b,"showOptions"),d,e):b.dpDiv[c=="slideDown"?"slideUp":c=="fadeIn"?"fadeOut":"hide"](c?d:null,e),c||e(),this._datepickerShowing=!1;var f=this._get(b,"onClose");f&&f.apply(b.input?b.input[0]:null,[b.input?b.input.val():"",b]),this._lastInput=null,this._inDialog&&(this._dialogInput.css({position:"absolute",left:"0",top:"-100px"}),$.blockUI&&($.unblockUI(),$("body").append(this.dpDiv))),this._inDialog=!1}},_tidyDialog:function(a){a.dpDiv.removeClass(this._dialogClass).unbind(".ui-datepicker-calendar")},_checkExternalClick:function(a){if(!$.datepicker._curInst)return;var b=$(a.target),c=$.datepicker._getInst(b[0]);(b[0].id!=$.datepicker._mainDivId&&b.parents("#"+$.datepicker._mainDivId).length==0&&!b.hasClass($.datepicker.markerClassName)&&!b.closest("."+$.datepicker._triggerClass).length&&$.datepicker._datepickerShowing&&(!$.datepicker._inDialog||!$.blockUI)||b.hasClass($.datepicker.markerClassName)&&$.datepicker._curInst!=c)&&$.datepicker._hideDatepicker()},_adjustDate:function(a,b,c){var d=$(a),e=this._getInst(d[0]);if(this._isDisabledDatepicker(d[0]))return;this._adjustInstDate(e,b+(c=="M"?this._get(e,"showCurrentAtPos"):0),c),this._updateDatepicker(e)},_gotoToday:function(a){var b=$(a),c=this._getInst(b[0]);if(this._get(c,"gotoCurrent")&&c.currentDay)c.selectedDay=c.currentDay,c.drawMonth=c.selectedMonth=c.currentMonth,c.drawYear=c.selectedYear=c.currentYear;else{var d=new Date;c.selectedDay=d.getDate(),c.drawMonth=c.selectedMonth=d.getMonth(),c.drawYear=c.selectedYear=d.getFullYear()}this._notifyChange(c),this._adjustDate(b)},_selectMonthYear:function(a,b,c){var d=$(a),e=this._getInst(d[0]);e["selected"+(c=="M"?"Month":"Year")]=e["draw"+(c=="M"?"Month":"Year")]=parseInt(b.options[b.selectedIndex].value,10),this._notifyChange(e),this._adjustDate(d)},_selectDay:function(a,b,c,d){var e=$(a);if($(d).hasClass(this._unselectableClass)||this._isDisabledDatepicker(e[0]))return;var f=this._getInst(e[0]);f.selectedDay=f.currentDay=$("a",d).html(),f.selectedMonth=f.currentMonth=b,f.selectedYear=f.currentYear=c,this._selectDate(a,this._formatDate(f,f.currentDay,f.currentMonth,f.currentYear))},_clearDate:function(a){var b=$(a),c=this._getInst(b[0]);this._selectDate(b,"")},_selectDate:function(a,b){var c=$(a),d=this._getInst(c[0]);b=b!=null?b:this._formatDate(d),d.input&&d.input.val(b),this._updateAlternate(d);var e=this._get(d,"onSelect");e?e.apply(d.input?d.input[0]:null,[b,d]):d.input&&d.input.trigger("change"),d.inline?this._updateDatepicker(d):(this._hideDatepicker(),this._lastInput=d.input[0],typeof d.input[0]!="object"&&d.input.focus(),this._lastInput=null)},_updateAlternate:function(a){var b=this._get(a,"altField");if(b){var c=this._get(a,"altFormat")||this._get(a,"dateFormat"),d=this._getDate(a),e=this.formatDate(c,d,this._getFormatConfig(a));$(b).each(function(){$(this).val(e)})}},noWeekends:function(a){var b=a.getDay();return[b>0&&b<6,""]},iso8601Week:function(a){var b=new Date(a.getTime());b.setDate(b.getDate()+4-(b.getDay()||7));var c=b.getTime();return b.setMonth(0),b.setDate(1),Math.floor(Math.round((c-b)/864e5)/7)+1},parseDate:function(a,b,c){if(a==null||b==null)throw"Invalid arguments";b=typeof b=="object"?b.toString():b+"";if(b=="")return null;var d=(c?c.shortYearCutoff:null)||this._defaults.shortYearCutoff;d=typeof d!="string"?d:(new Date).getFullYear()%100+parseInt(d,10);var e=(c?c.dayNamesShort:null)||this._defaults.dayNamesShort,f=(c?c.dayNames:null)||this._defaults.dayNames,g=(c?c.monthNamesShort:null)||this._defaults.monthNamesShort,h=(c?c.monthNames:null)||this._defaults.monthNames,i=-1,j=-1,k=-1,l=-1,m=!1,n=function(b){var c=s+1<a.length&&a.charAt(s+1)==b;return c&&s++,c},o=function(a){var c=n(a),d=a=="@"?14:a=="!"?20:a=="y"&&c?4:a=="o"?3:2,e=new RegExp("^\\d{1,"+d+"}"),f=b.substring(r).match(e);if(!f)throw"Missing number at position "+r;return r+=f[0].length,parseInt(f[0],10)},p=function(a,c,d){var e=$.map(n(a)?d:c,function(a,b){return[[b,a]]}).sort(function(a,b){return-(a[1].length-b[1].length)}),f=-1;$.each(e,function(a,c){var d=c[1];if(b.substr(r,d.length).toLowerCase()==d.toLowerCase())return f=c[0],r+=d.length,!1});if(f!=-1)return f+1;throw"Unknown name at position "+r},q=function(){if(b.charAt(r)!=a.charAt(s))throw"Unexpected literal at position "+r;r++},r=0;for(var s=0;s<a.length;s++)if(m)a.charAt(s)=="'"&&!n("'")?m=!1:q();else switch(a.charAt(s)){case"d":k=o("d");break;case"D":p("D",e,f);break;case"o":l=o("o");break;case"m":j=o("m");break;case"M":j=p("M",g,h);break;case"y":i=o("y");break;case"@":var t=new Date(o("@"));i=t.getFullYear(),j=t.getMonth()+1,k=t.getDate();break;case"!":var t=new Date((o("!")-this._ticksTo1970)/1e4);i=t.getFullYear(),j=t.getMonth()+1,k=t.getDate();break;case"'":n("'")?q():m=!0;break;default:q()}if(r<b.length)throw"Extra/unparsed characters found in date: "+b.substring(r);i==-1?i=(new Date).getFullYear():i<100&&(i+=(new Date).getFullYear()-(new Date).getFullYear()%100+(i<=d?0:-100));if(l>-1){j=1,k=l;do{var u=this._getDaysInMonth(i,j-1);if(k<=u)break;j++,k-=u}while(!0)}var t=this._daylightSavingAdjust(new Date(i,j-1,k));if(t.getFullYear()!=i||t.getMonth()+1!=j||t.getDate()!=k)throw"Invalid date";return t},ATOM:"yy-mm-dd",COOKIE:"D, dd M yy",ISO_8601:"yy-mm-dd",RFC_822:"D, d M y",RFC_850:"DD, dd-M-y",RFC_1036:"D, d M y",RFC_1123:"D, d M yy",RFC_2822:"D, d M yy",RSS:"D, d M y",TICKS:"!",TIMESTAMP:"@",W3C:"yy-mm-dd",_ticksTo1970:(718685+Math.floor(492.5)-Math.floor(19.7)+Math.floor(4.925))*24*60*60*1e7,formatDate:function(a,b,c){if(!b)return"";var d=(c?c.dayNamesShort:null)||this._defaults.dayNamesShort,e=(c?c.dayNames:null)||this._defaults.dayNames,f=(c?c.monthNamesShort:null)||this._defaults.monthNamesShort,g=(c?c.monthNames:null)||this._defaults.monthNames,h=function(b){var c=m+1<a.length&&a.charAt(m+1)==b;return c&&m++,c},i=function(a,b,c){var d=""+b;if(h(a))while(d.length<c)d="0"+d;return d},j=function(a,b,c,d){return h(a)?d[b]:c[b]},k="",l=!1;if(b)for(var m=0;m<a.length;m++)if(l)a.charAt(m)=="'"&&!h("'")?l=!1:k+=a.charAt(m);else switch(a.charAt(m)){case"d":k+=i("d",b.getDate(),2);break;case"D":k+=j("D",b.getDay(),d,e);break;case"o":k+=i("o",Math.round(((new Date(b.getFullYear(),b.getMonth(),b.getDate())).getTime()-(new Date(b.getFullYear(),0,0)).getTime())/864e5),3);break;case"m":k+=i("m",b.getMonth()+1,2);break;case"M":k+=j("M",b.getMonth(),f,g);break;case"y":k+=h("y")?b.getFullYear():(b.getYear()%100<10?"0":"")+b.getYear()%100;break;case"@":k+=b.getTime();break;case"!":k+=b.getTime()*1e4+this._ticksTo1970;break;case"'":h("'")?k+="'":l=!0;break;default:k+=a.charAt(m)}return k},_possibleChars:function(a){var b="",c=!1,d=function(b){var c=e+1<a.length&&a.charAt(e+1)==b;return c&&e++,c};for(var e=0;e<a.length;e++)if(c)a.charAt(e)=="'"&&!d("'")?c=!1:b+=a.charAt(e);else switch(a.charAt(e)){case"d":case"m":case"y":case"@":b+="0123456789";break;case"D":case"M":return null;case"'":d("'")?b+="'":c=!0;break;default:b+=a.charAt(e)}return b},_get:function(a,b){return a.settings[b]!==undefined?a.settings[b]:this._defaults[b]},_setDateFromField:function(a,b){if(a.input.val()==a.lastVal)return;var c=this._get(a,"dateFormat"),d=a.lastVal=a.input?a.input.val():null,e,f;e=f=this._getDefaultDate(a);var g=this._getFormatConfig(a);try{e=this.parseDate(c,d,g)||f}catch(h){this.log(h),d=b?"":d}a.selectedDay=e.getDate(),a.drawMonth=a.selectedMonth=e.getMonth(),a.drawYear=a.selectedYear=e.getFullYear(),a.currentDay=d?e.getDate():0,a.currentMonth=d?e.getMonth():0,a.currentYear=d?e.getFullYear():0,this._adjustInstDate(a)},_getDefaultDate:function(a){return this._restrictMinMax(a,this._determineDate(a,this._get(a,"defaultDate"),new Date))},_determineDate:function(a,b,c){var d=function(a){var b=new Date;return b.setDate(b.getDate()+a),b},e=function(b){try{return $.datepicker.parseDate($.datepicker._get(a,"dateFormat"),b,$.datepicker._getFormatConfig(a))}catch(c){}var d=(b.toLowerCase().match(/^c/)?$.datepicker._getDate(a):null)||new Date,e=d.getFullYear(),f=d.getMonth(),g=d.getDate(),h=/([+-]?[0-9]+)\s*(d|D|w|W|m|M|y|Y)?/g,i=h.exec(b);while(i){switch(i[2]||"d"){case"d":case"D":g+=parseInt(i[1],10);break;case"w":case"W":g+=parseInt(i[1],10)*7;break;case"m":case"M":f+=parseInt(i[1],10),g=Math.min(g,$.datepicker._getDaysInMonth(e,f));break;case"y":case"Y":e+=parseInt(i[1],10),g=Math.min(g,$.datepicker._getDaysInMonth(e,f))}i=h.exec(b)}return new Date(e,f,g)},f=b==null||b===""?c:typeof b=="string"?e(b):typeof b=="number"?isNaN(b)?c:d(b):new Date(b.getTime());return f=f&&f.toString()=="Invalid Date"?c:f,f&&(f.setHours(0),f.setMinutes(0),f.setSeconds(0),f.setMilliseconds(0)),this._daylightSavingAdjust(f)},_daylightSavingAdjust:function(a){return a?(a.setHours(a.getHours()>12?a.getHours()+2:0),a):null},_setDate:function(a,b,c){var d=!b,e=a.selectedMonth,f=a.selectedYear,g=this._restrictMinMax(a,this._determineDate(a,b,new Date));a.selectedDay=a.currentDay=g.getDate(),a.drawMonth=a.selectedMonth=a.currentMonth=g.getMonth(),a.drawYear=a.selectedYear=a.currentYear=g.getFullYear(),(e!=a.selectedMonth||f!=a.selectedYear)&&!c&&this._notifyChange(a),this._adjustInstDate(a),a.input&&a.input.val(d?"":this._formatDate(a))},_getDate:function(a){var b=!a.currentYear||a.input&&a.input.val()==""?null:this._daylightSavingAdjust(new Date(a.currentYear,a.currentMonth,a.currentDay));return b},_attachHandlers:function(a){var b=this._get(a,"stepMonths"),c="#"+a.id.replace(/\\\\/g,"\\");a.dpDiv.find("[data-handler]").map(function(){var a={prev:function(){window["DP_jQuery_"+dpuuid].datepicker._adjustDate(c,-b,"M")},next:function(){window["DP_jQuery_"+dpuuid].datepicker._adjustDate(c,+b,"M")},hide:function(){window["DP_jQuery_"+dpuuid].datepicker._hideDatepicker()},today:function(){window["DP_jQuery_"+dpuuid].datepicker._gotoToday(c)},selectDay:function(){return window["DP_jQuery_"+dpuuid].datepicker._selectDay(c,+this.getAttribute("data-month"),+this.getAttribute("data-year"),this),!1},selectMonth:function(){return window["DP_jQuery_"+dpuuid].datepicker._selectMonthYear(c,this,"M"),!1},selectYear:function(){return window["DP_jQuery_"+dpuuid].datepicker._selectMonthYear(c,this,"Y"),!1}};$(this).bind(this.getAttribute("data-event"),a[this.getAttribute("data-handler")])})},_generateHTML:function(a){var b=new Date;b=this._daylightSavingAdjust(new Date(b.getFullYear(),b.getMonth(),b.getDate()));var c=this._get(a,"isRTL"),d=this._get(a,"showButtonPanel"),e=this._get(a,"hideIfNoPrevNext"),f=this._get(a,"navigationAsDateFormat"),g=this._getNumberOfMonths(a),h=this._get(a,"showCurrentAtPos"),i=this._get(a,"stepMonths"),j=g[0]!=1||g[1]!=1,k=this._daylightSavingAdjust(a.currentDay?new Date(a.currentYear,a.currentMonth,a.currentDay):new Date(9999,9,9)),l=this._getMinMaxDate(a,"min"),m=this._getMinMaxDate(a,"max"),n=a.drawMonth-h,o=a.drawYear;n<0&&(n+=12,o--);if(m){var p=this._daylightSavingAdjust(new Date(m.getFullYear(),m.getMonth()-g[0]*g[1]+1,m.getDate()));p=l&&p<l?l:p;while(this._daylightSavingAdjust(new Date(o,n,1))>p)n--,n<0&&(n=11,o--)}a.drawMonth=n,a.drawYear=o;var q=this._get(a,"prevText");q=f?this.formatDate(q,this._daylightSavingAdjust(new Date(o,n-i,1)),this._getFormatConfig(a)):q;var r=this._canAdjustMonth(a,-1,o,n)?'<a class="ui-datepicker-prev ui-corner-all" data-handler="prev" data-event="click" title="'+q+'"><span class="ui-icon ui-icon-circle-triangle-'+(c?"e":"w")+'">'+q+"</span></a>":e?"":'<a class="ui-datepicker-prev ui-corner-all ui-state-disabled" title="'+q+'"><span class="ui-icon ui-icon-circle-triangle-'+(c?"e":"w")+'">'+q+"</span></a>",s=this._get(a,"nextText");s=f?this.formatDate(s,this._daylightSavingAdjust(new Date(o,n+i,1)),this._getFormatConfig(a)):s;var t=this._canAdjustMonth(a,1,o,n)?'<a class="ui-datepicker-next ui-corner-all" data-handler="next" data-event="click" title="'+s+'"><span class="ui-icon ui-icon-circle-triangle-'+(c?"w":"e")+'">'+s+"</span></a>":e?"":'<a class="ui-datepicker-next ui-corner-all ui-state-disabled" title="'+s+'"><span class="ui-icon ui-icon-circle-triangle-'+(c?"w":"e")+'">'+s+"</span></a>",u=this._get(a,"currentText"),v=this._get(a,"gotoCurrent")&&a.currentDay?k:b;u=f?this.formatDate(u,v,this._getFormatConfig(a)):u;var w=a.inline?"":'<button type="button" class="ui-datepicker-close ui-state-default ui-priority-primary ui-corner-all" data-handler="hide" data-event="click">'+this._get(a,"closeText")+"</button>",x=d?'<div class="ui-datepicker-buttonpane ui-widget-content">'+(c?w:"")+(this._isInRange(a,v)?'<button type="button" class="ui-datepicker-current ui-state-default ui-priority-secondary ui-corner-all" data-handler="today" data-event="click">'+u+"</button>":"")+(c?"":w)+"</div>":"",y=parseInt(this._get(a,"firstDay"),10);y=isNaN(y)?0:y;var z=this._get(a,"showWeek"),A=this._get(a,"dayNames"),B=this._get(a,"dayNamesShort"),C=this._get(a,"dayNamesMin"),D=this._get(a,"monthNames"),E=this._get(a,"monthNamesShort"),F=this._get(a,"beforeShowDay"),G=this._get(a,"showOtherMonths"),H=this._get(a,"selectOtherMonths"),I=this._get(a,"calculateWeek")||this.iso8601Week,J=this._getDefaultDate(a),K="";for(var L=0;L<g[0];L++){var M="";this.maxRows=4;for(var N=0;N<g[1];N++){var O=this._daylightSavingAdjust(new Date(o,n,a.selectedDay)),P=" ui-corner-all",Q="";if(j){Q+='<div class="ui-datepicker-group';if(g[1]>1)switch(N){case 0:Q+=" ui-datepicker-group-first",P=" ui-corner-"+(c?"right":"left");break;case g[1]-1:Q+=" ui-datepicker-group-last",P=" ui-corner-"+(c?"left":"right");break;default:Q+=" ui-datepicker-group-middle",P=""}Q+='">'}Q+='<div class="ui-datepicker-header ui-widget-header ui-helper-clearfix'+P+'">'+(/all|left/.test(P)&&L==0?c?t:r:"")+(/all|right/.test(P)&&L==0?c?r:t:"")+this._generateMonthYearHeader(a,n,o,l,m,L>0||N>0,D,E)+'</div><table class="ui-datepicker-calendar"><thead>'+"<tr>";var R=z?'<th class="ui-datepicker-week-col">'+this._get(a,"weekHeader")+"</th>":"";for(var S=0;S<7;S++){var T=(S+y)%7;R+="<th"+((S+y+6)%7>=5?' class="ui-datepicker-week-end"':"")+">"+'<span title="'+A[T]+'">'+C[T]+"</span></th>"}Q+=R+"</tr></thead><tbody>";var U=this._getDaysInMonth(o,n);o==a.selectedYear&&n==a.selectedMonth&&(a.selectedDay=Math.min(a.selectedDay,U));var V=(this._getFirstDayOfMonth(o,n)-y+7)%7,W=Math.ceil((V+U)/7),X=j?this.maxRows>W?this.maxRows:W:W;this.maxRows=X;var Y=this._daylightSavingAdjust(new Date(o,n,1-V));for(var Z=0;Z<X;Z++){Q+="<tr>";var _=z?'<td class="ui-datepicker-week-col">'+this._get(a,"calculateWeek")(Y)+"</td>":"";for(var S=0;S<7;S++){var ba=F?F.apply(a.input?a.input[0]:null,[Y]):[!0,""],bb=Y.getMonth()!=n,bc=bb&&!H||!ba[0]||l&&Y<l||m&&Y>m;_+='<td class="'+((S+y+6)%7>=5?" ui-datepicker-week-end":"")+(bb?" ui-datepicker-other-month":"")+(Y.getTime()==O.getTime()&&n==a.selectedMonth&&a._keyEvent||J.getTime()==Y.getTime()&&J.getTime()==O.getTime()?" "+this._dayOverClass:"")+(bc?" "+this._unselectableClass+" ui-state-disabled":"")+(bb&&!G?"":" "+ba[1]+(Y.getTime()==k.getTime()?" "+this._currentClass:"")+(Y.getTime()==b.getTime()?" ui-datepicker-today":""))+'"'+((!bb||G)&&ba[2]?' title="'+ba[2]+'"':"")+(bc?"":' data-handler="selectDay" data-event="click" data-month="'+Y.getMonth()+'" data-year="'+Y.getFullYear()+'"')+">"+(bb&&!G?"&#xa0;":bc?'<span class="ui-state-default">'+Y.getDate()+"</span>":'<a class="ui-state-default'+(Y.getTime()==b.getTime()?" ui-state-highlight":"")+(Y.getTime()==k.getTime()?" ui-state-active":"")+(bb?" ui-priority-secondary":"")+'" href="#">'+Y.getDate()+"</a>")+"</td>",Y.setDate(Y.getDate()+1),Y=this._daylightSavingAdjust(Y)}Q+=_+"</tr>"}n++,n>11&&(n=0,o++),Q+="</tbody></table>"+(j?"</div>"+(g[0]>0&&N==g[1]-1?'<div class="ui-datepicker-row-break"></div>':""):""),M+=Q}K+=M}return K+=x+($.browser.msie&&parseInt($.browser.version,10)<7&&!a.inline?'<iframe src="javascript:false;" class="ui-datepicker-cover" frameborder="0"></iframe>':""),a._keyEvent=!1,K},_generateMonthYearHeader:function(a,b,c,d,e,f,g,h){var i=this._get(a,"changeMonth"),j=this._get(a,"changeYear"),k=this._get(a,"showMonthAfterYear"),l='<div class="ui-datepicker-title">',m="";if(f||!i)m+='<span class="ui-datepicker-month">'+g[b]+"</span>";else{var n=d&&d.getFullYear()==c,o=e&&e.getFullYear()==c;m+='<select class="ui-datepicker-month" data-handler="selectMonth" data-event="change">';for(var p=0;p<12;p++)(!n||p>=d.getMonth())&&(!o||p<=e.getMonth())&&(m+='<option value="'+p+'"'+(p==b?' selected="selected"':"")+">"+h[p]+"</option>");m+="</select>"}k||(l+=m+(f||!i||!j?"&#xa0;":""));if(!a.yearshtml){a.yearshtml="";if(f||!j)l+='<span class="ui-datepicker-year">'+c+"</span>";else{var q=this._get(a,"yearRange").split(":"),r=(new Date).getFullYear(),s=function(a){var b=a.match(/c[+-].*/)?c+parseInt(a.substring(1),10):a.match(/[+-].*/)?r+parseInt(a,10):parseInt(a,10);return isNaN(b)?r:b},t=s(q[0]),u=Math.max(t,s(q[1]||""));t=d?Math.max(t,d.getFullYear()):t,u=e?Math.min(u,e.getFullYear()):u,a.yearshtml+='<select class="ui-datepicker-year" data-handler="selectYear" data-event="change">';for(;t<=u;t++)a.yearshtml+='<option value="'+t+'"'+(t==c?' selected="selected"':"")+">"+t+"</option>";a.yearshtml+="</select>",l+=a.yearshtml,a.yearshtml=null}}return l+=this._get(a,"yearSuffix"),k&&(l+=(f||!i||!j?"&#xa0;":"")+m),l+="</div>",l},_adjustInstDate:function(a,b,c){var d=a.drawYear+(c=="Y"?b:0),e=a.drawMonth+(c=="M"?b:0),f=Math.min(a.selectedDay,this._getDaysInMonth(d,e))+(c=="D"?b:0),g=this._restrictMinMax(a,this._daylightSavingAdjust(new Date(d,e,f)));a.selectedDay=g.getDate(),a.drawMonth=a.selectedMonth=g.getMonth(),a.drawYear=a.selectedYear=g.getFullYear(),(c=="M"||c=="Y")&&this._notifyChange(a)},_restrictMinMax:function(a,b){var c=this._getMinMaxDate(a,"min"),d=this._getMinMaxDate(a,"max"),e=c&&b<c?c:b;return e=d&&e>d?d:e,e},_notifyChange:function(a){var b=this._get(a,"onChangeMonthYear");b&&b.apply(a.input?a.input[0]:null,[a.selectedYear,a.selectedMonth+1,a])},_getNumberOfMonths:function(a){var b=this._get(a,"numberOfMonths");return b==null?[1,1]:typeof b=="number"?[1,b]:b},_getMinMaxDate:function(a,b){return this._determineDate(a,this._get(a,b+"Date"),null)},_getDaysInMonth:function(a,b){return 32-this._daylightSavingAdjust(new Date(a,b,32)).getDate()},_getFirstDayOfMonth:function(a,b){return(new Date(a,b,1)).getDay()},_canAdjustMonth:function(a,b,c,d){var e=this._getNumberOfMonths(a),f=this._daylightSavingAdjust(new Date(c,d+(b<0?b:e[0]*e[1]),1));return b<0&&f.setDate(this._getDaysInMonth(f.getFullYear(),f.getMonth())),this._isInRange(a,f)},_isInRange:function(a,b){var c=this._getMinMaxDate(a,"min"),d=this._getMinMaxDate(a,"max");return(!c||b.getTime()>=c.getTime())&&(!d||b.getTime()<=d.getTime())},_getFormatConfig:function(a){var b=this._get(a,"shortYearCutoff");return b=typeof b!="string"?b:(new Date).getFullYear()%100+parseInt(b,10),{shortYearCutoff:b,dayNamesShort:this._get(a,"dayNamesShort"),dayNames:this._get(a,"dayNames"),monthNamesShort:this._get(a,"monthNamesShort"),monthNames:this._get(a,"monthNames")}},_formatDate:function(a,b,c,d){b||(a.currentDay=a.selectedDay,a.currentMonth=a.selectedMonth,a.currentYear=a.selectedYear);var e=b?typeof b=="object"?b:this._daylightSavingAdjust(new Date(d,c,b)):this._daylightSavingAdjust(new Date(a.currentYear,a.currentMonth,a.currentDay));return this.formatDate(this._get(a,"dateFormat"),e,this._getFormatConfig(a))}}),$.fn.datepicker=function(a){if(!this.length)return this;$.datepicker.initialized||($(document).mousedown($.datepicker._checkExternalClick).find("body").append($.datepicker.dpDiv),$.datepicker.initialized=!0);var b=Array.prototype.slice.call(arguments,1);return typeof a!="string"||a!="isDisabled"&&a!="getDate"&&a!="widget"?a=="option"&&arguments.length==2&&typeof arguments[1]=="string"?$.datepicker["_"+a+"Datepicker"].apply($.datepicker,[this[0]].concat(b)):this.each(function(){typeof a=="string"?$.datepicker["_"+a+"Datepicker"].apply($.datepicker,[this].concat(b)):$.datepicker._attachDatepicker(this,a)}):$.datepicker["_"+a+"Datepicker"].apply($.datepicker,[this[0]].concat(b))},$.datepicker=new Datepicker,$.datepicker.initialized=!1,$.datepicker.uuid=(new Date).getTime(),$.datepicker.version="1.8.23",window["DP_jQuery_"+dpuuid]=$})(jQuery);;/*! jQuery UI - v1.8.23 - 2012-08-15
    +-* https://github.com/jquery/jquery-ui
    +-* Includes: jquery.ui.progressbar.js
    +-* Copyright (c) 2012 AUTHORS.txt; Licensed MIT, GPL */
    +-(function(a,b){a.widget("ui.progressbar",{options:{value:0,max:100},min:0,_create:function(){this.element.addClass("ui-progressbar ui-widget ui-widget-content ui-corner-all").attr({role:"progressbar","aria-valuemin":this.min,"aria-valuemax":this.options.max,"aria-valuenow":this._value()}),this.valueDiv=a("<div class='ui-progressbar-value ui-widget-header ui-corner-left'></div>").appendTo(this.element),this.oldValue=this._value(),this._refreshValue()},destroy:function(){this.element.removeClass("ui-progressbar ui-widget ui-widget-content ui-corner-all").removeAttr("role").removeAttr("aria-valuemin").removeAttr("aria-valuemax").removeAttr("aria-valuenow"),this.valueDiv.remove(),a.Widget.prototype.destroy.apply(this,arguments)},value:function(a){return a===b?this._value():(this._setOption("value",a),this)},_setOption:function(b,c){b==="value"&&(this.options.value=c,this._refreshValue(),this._value()===this.options.max&&this._trigger("complete")),a.Widget.prototype._setOption.apply(this,arguments)},_value:function(){var a=this.options.value;return typeof a!="number"&&(a=0),Math.min(this.options.max,Math.max(this.min,a))},_percentage:function(){return 100*this._value()/this.options.max},_refreshValue:function(){var a=this.value(),b=this._percentage();this.oldValue!==a&&(this.oldValue=a,this._trigger("change")),this.valueDiv.toggle(a>this.min).toggleClass("ui-corner-right",a===this.options.max).width(b.toFixed(0)+"%"),this.element.attr("aria-valuenow",a)}}),a.extend(a.ui.progressbar,{version:"1.8.23"})})(jQuery);;/*! jQuery UI - v1.8.23 - 2012-08-15
    +-* https://github.com/jquery/jquery-ui
    +-* Includes: jquery.effects.core.js
    +-* Copyright (c) 2012 AUTHORS.txt; Licensed MIT, GPL */
    +-jQuery.effects||function(a,b){function c(b){var c;return b&&b.constructor==Array&&b.length==3?b:(c=/rgb\(\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*\)/.exec(b))?[parseInt(c[1],10),parseInt(c[2],10),parseInt(c[3],10)]:(c=/rgb\(\s*([0-9]+(?:\.[0-9]+)?)\%\s*,\s*([0-9]+(?:\.[0-9]+)?)\%\s*,\s*([0-9]+(?:\.[0-9]+)?)\%\s*\)/.exec(b))?[parseFloat(c[1])*2.55,parseFloat(c[2])*2.55,parseFloat(c[3])*2.55]:(c=/#([a-fA-F0-9]{2})([a-fA-F0-9]{2})([a-fA-F0-9]{2})/.exec(b))?[parseInt(c[1],16),parseInt(c[2],16),parseInt(c[3],16)]:(c=/#([a-fA-F0-9])([a-fA-F0-9])([a-fA-F0-9])/.exec(b))?[parseInt(c[1]+c[1],16),parseInt(c[2]+c[2],16),parseInt(c[3]+c[3],16)]:(c=/rgba\(0, 0, 0, 0\)/.exec(b))?e.transparent:e[a.trim(b).toLowerCase()]}function d(b,d){var e;do{e=(a.curCSS||a.css)(b,d);if(e!=""&&e!="transparent"||a.nodeName(b,"body"))break;d="backgroundColor"}while(b=b.parentNode);return c(e)}function h(){var a=document.defaultView?document.defaultView.getComputedStyle(this,null):this.currentStyle,b={},c,d;if(a&&a.length&&a[0]&&a[a[0]]){var e=a.length;while(e--)c=a[e],typeof a[c]=="string"&&(d=c.replace(/\-(\w)/g,function(a,b){return b.toUpperCase()}),b[d]=a[c])}else for(c in a)typeof a[c]=="string"&&(b[c]=a[c]);return b}function i(b){var c,d;for(c in b)d=b[c],(d==null||a.isFunction(d)||c in g||/scrollbar/.test(c)||!/color/i.test(c)&&isNaN(parseFloat(d)))&&delete b[c];return b}function j(a,b){var c={_:0},d;for(d in b)a[d]!=b[d]&&(c[d]=b[d]);return c}function k(b,c,d,e){typeof b=="object"&&(e=c,d=null,c=b,b=c.effect),a.isFunction(c)&&(e=c,d=null,c={});if(typeof c=="number"||a.fx.speeds[c])e=d,d=c,c={};return a.isFunction(d)&&(e=d,d=null),c=c||{},d=d||c.duration,d=a.fx.off?0:typeof d=="number"?d:d in a.fx.speeds?a.fx.speeds[d]:a.fx.speeds._default,e=e||c.complete,[b,c,d,e]}function l(b){return!b||typeof b=="number"||a.fx.speeds[b]?!0:typeof b=="string"&&!a.effects[b]?!0:!1}a.effects={},a.each(["backgroundColor","borderBottomColor","borderLeftColor","borderRightColor","borderTopColor","borderColor","color","outlineColor"],function(b,e){a.fx.step[e]=function(a){a.colorInit||(a.start=d(a.elem,e),a.end=c(a.end),a.colorInit=!0),a.elem.style[e]="rgb("+Math.max(Math.min(parseInt(a.pos*(a.end[0]-a.start[0])+a.start[0],10),255),0)+","+Math.max(Math.min(parseInt(a.pos*(a.end[1]-a.start[1])+a.start[1],10),255),0)+","+Math.max(Math.min(parseInt(a.pos*(a.end[2]-a.start[2])+a.start[2],10),255),0)+")"}});var e={aqua:[0,255,255],azure:[240,255,255],beige:[245,245,220],black:[0,0,0],blue:[0,0,255],brown:[165,42,42],cyan:[0,255,255],darkblue:[0,0,139],darkcyan:[0,139,139],darkgrey:[169,169,169],darkgreen:[0,100,0],darkkhaki:[189,183,107],darkmagenta:[139,0,139],darkolivegreen:[85,107,47],darkorange:[255,140,0],darkorchid:[153,50,204],darkred:[139,0,0],darksalmon:[233,150,122],darkviolet:[148,0,211],fuchsia:[255,0,255],gold:[255,215,0],green:[0,128,0],indigo:[75,0,130],khaki:[240,230,140],lightblue:[173,216,230],lightcyan:[224,255,255],lightgreen:[144,238,144],lightgrey:[211,211,211],lightpink:[255,182,193],lightyellow:[255,255,224],lime:[0,255,0],magenta:[255,0,255],maroon:[128,0,0],navy:[0,0,128],olive:[128,128,0],orange:[255,165,0],pink:[255,192,203],purple:[128,0,128],violet:[128,0,128],red:[255,0,0],silver:[192,192,192],white:[255,255,255],yellow:[255,255,0],transparent:[255,255,255]},f=["add","remove","toggle"],g={border:1,borderBottom:1,borderColor:1,borderLeft:1,borderRight:1,borderTop:1,borderWidth:1,margin:1,padding:1};a.effects.animateClass=function(b,c,d,e){return a.isFunction(d)&&(e=d,d=null),this.queue(function(){var g=a(this),k=g.attr("style")||" ",l=i(h.call(this)),m,n=g.attr("class")||"";a.each(f,function(a,c){b[c]&&g[c+"Class"](b[c])}),m=i(h.call(this)),g.attr("class",n),g.animate(j(l,m),{queue:!1,duration:c,easing:d,complete:function(){a.each(f,function(a,c){b[c]&&g[c+"Class"](b[c])}),typeof g.attr("style")=="object"?(g.attr("style").cssText="",g.attr("style").cssText=k):g.attr("style",k),e&&e.apply(this,arguments),a.dequeue(this)}})})},a.fn.extend({_addClass:a.fn.addClass,addClass:function(b,c,d,e){return c?a.effects.animateClass.apply(this,[{add:b},c,d,e]):this._addClass(b)},_removeClass:a.fn.removeClass,removeClass:function(b,c,d,e){return c?a.effects.animateClass.apply(this,[{remove:b},c,d,e]):this._removeClass(b)},_toggleClass:a.fn.toggleClass,toggleClass:function(c,d,e,f,g){return typeof d=="boolean"||d===b?e?a.effects.animateClass.apply(this,[d?{add:c}:{remove:c},e,f,g]):this._toggleClass(c,d):a.effects.animateClass.apply(this,[{toggle:c},d,e,f])},switchClass:function(b,c,d,e,f){return a.effects.animateClass.apply(this,[{add:c,remove:b},d,e,f])}}),a.extend(a.effects,{version:"1.8.23",save:function(a,b){for(var c=0;c<b.length;c++)b[c]!==null&&a.data("ec.storage."+b[c],a[0].style[b[c]])},restore:function(a,b){for(var c=0;c<b.length;c++)b[c]!==null&&a.css(b[c],a.data("ec.storage."+b[c]))},setMode:function(a,b){return b=="toggle"&&(b=a.is(":hidden")?"show":"hide"),b},getBaseline:function(a,b){var c,d;switch(a[0]){case"top":c=0;break;case"middle":c=.5;break;case"bottom":c=1;break;default:c=a[0]/b.height}switch(a[1]){case"left":d=0;break;case"center":d=.5;break;case"right":d=1;break;default:d=a[1]/b.width}return{x:d,y:c}},createWrapper:function(b){if(b.parent().is(".ui-effects-wrapper"))return b.parent();var c={width:b.outerWidth(!0),height:b.outerHeight(!0),"float":b.css("float")},d=a("<div></div>").addClass("ui-effects-wrapper").css({fontSize:"100%",background:"transparent",border:"none",margin:0,padding:0}),e=document.activeElement;try{e.id}catch(f){e=document.body}return b.wrap(d),(b[0]===e||a.contains(b[0],e))&&a(e).focus(),d=b.parent(),b.css("position")=="static"?(d.css({position:"relative"}),b.css({position:"relative"})):(a.extend(c,{position:b.css("position"),zIndex:b.css("z-index")}),a.each(["top","left","bottom","right"],function(a,d){c[d]=b.css(d),isNaN(parseInt(c[d],10))&&(c[d]="auto")}),b.css({position:"relative",top:0,left:0,right:"auto",bottom:"auto"})),d.css(c).show()},removeWrapper:function(b){var c,d=document.activeElement;return b.parent().is(".ui-effects-wrapper")?(c=b.parent().replaceWith(b),(b[0]===d||a.contains(b[0],d))&&a(d).focus(),c):b},setTransition:function(b,c,d,e){return e=e||{},a.each(c,function(a,c){var f=b.cssUnit(c);f[0]>0&&(e[c]=f[0]*d+f[1])}),e}}),a.fn.extend({effect:function(b,c,d,e){var f=k.apply(this,arguments),g={options:f[1],duration:f[2],callback:f[3]},h=g.options.mode,i=a.effects[b];return a.fx.off||!i?h?this[h](g.duration,g.callback):this.each(function(){g.callback&&g.callback.call(this)}):i.call(this,g)},_show:a.fn.show,show:function(a){if(l(a))return this._show.apply(this,arguments);var b=k.apply(this,arguments);return b[1].mode="show",this.effect.apply(this,b)},_hide:a.fn.hide,hide:function(a){if(l(a))return this._hide.apply(this,arguments);var b=k.apply(this,arguments);return b[1].mode="hide",this.effect.apply(this,b)},__toggle:a.fn.toggle,toggle:function(b){if(l(b)||typeof b=="boolean"||a.isFunction(b))return this.__toggle.apply(this,arguments);var c=k.apply(this,arguments);return c[1].mode="toggle",this.effect.apply(this,c)},cssUnit:function(b){var c=this.css(b),d=[];return a.each(["em","px","%","pt"],function(a,b){c.indexOf(b)>0&&(d=[parseFloat(c),b])}),d}});var m={};a.each(["Quad","Cubic","Quart","Quint","Expo"],function(a,b){m[b]=function(b){return Math.pow(b,a+2)}}),a.extend(m,{Sine:function(a){return 1-Math.cos(a*Math.PI/2)},Circ:function(a){return 1-Math.sqrt(1-a*a)},Elastic:function(a){return a===0||a===1?a:-Math.pow(2,8*(a-1))*Math.sin(((a-1)*80-7.5)*Math.PI/15)},Back:function(a){return a*a*(3*a-2)},Bounce:function(a){var b,c=4;while(a<((b=Math.pow(2,--c))-1)/11);return 1/Math.pow(4,3-c)-7.5625*Math.pow((b*3-2)/22-a,2)}}),a.each(m,function(b,c){a.easing["easeIn"+b]=c,a.easing["easeOut"+b]=function(a){return 1-c(1-a)},a.easing["easeInOut"+b]=function(a){return a<.5?c(a*2)/2:c(a*-2+2)/-2+1}})}(jQuery);;/*! jQuery UI - v1.8.23 - 2012-08-15
    +-* https://github.com/jquery/jquery-ui
    +-* Includes: jquery.effects.blind.js
    +-* Copyright (c) 2012 AUTHORS.txt; Licensed MIT, GPL */
    +-(function(a,b){a.effects.blind=function(b){return this.queue(function(){var c=a(this),d=["position","top","bottom","left","right"],e=a.effects.setMode(c,b.options.mode||"hide"),f=b.options.direction||"vertical";a.effects.save(c,d),c.show();var g=a.effects.createWrapper(c).css({overflow:"hidden"}),h=f=="vertical"?"height":"width",i=f=="vertical"?g.height():g.width();e=="show"&&g.css(h,0);var j={};j[h]=e=="show"?i:0,g.animate(j,b.duration,b.options.easing,function(){e=="hide"&&c.hide(),a.effects.restore(c,d),a.effects.removeWrapper(c),b.callback&&b.callback.apply(c[0],arguments),c.dequeue()})})}})(jQuery);;/*! jQuery UI - v1.8.23 - 2012-08-15
    +-* https://github.com/jquery/jquery-ui
    +-* Includes: jquery.effects.bounce.js
    +-* Copyright (c) 2012 AUTHORS.txt; Licensed MIT, GPL */
    +-(function(a,b){a.effects.bounce=function(b){return this.queue(function(){var c=a(this),d=["position","top","bottom","left","right"],e=a.effects.setMode(c,b.options.mode||"effect"),f=b.options.direction||"up",g=b.options.distance||20,h=b.options.times||5,i=b.duration||250;/show|hide/.test(e)&&d.push("opacity"),a.effects.save(c,d),c.show(),a.effects.createWrapper(c);var j=f=="up"||f=="down"?"top":"left",k=f=="up"||f=="left"?"pos":"neg",g=b.options.distance||(j=="top"?c.outerHeight(!0)/3:c.outerWidth(!0)/3);e=="show"&&c.css("opacity",0).css(j,k=="pos"?-g:g),e=="hide"&&(g=g/(h*2)),e!="hide"&&h--;if(e=="show"){var l={opacity:1};l[j]=(k=="pos"?"+=":"-=")+g,c.animate(l,i/2,b.options.easing),g=g/2,h--}for(var m=0;m<h;m++){var n={},p={};n[j]=(k=="pos"?"-=":"+=")+g,p[j]=(k=="pos"?"+=":"-=")+g,c.animate(n,i/2,b.options.easing).animate(p,i/2,b.options.easing),g=e=="hide"?g*2:g/2}if(e=="hide"){var l={opacity:0};l[j]=(k=="pos"?"-=":"+=")+g,c.animate(l,i/2,b.options.easing,function(){c.hide(),a.effects.restore(c,d),a.effects.removeWrapper(c),b.callback&&b.callback.apply(this,arguments)})}else{var n={},p={};n[j]=(k=="pos"?"-=":"+=")+g,p[j]=(k=="pos"?"+=":"-=")+g,c.animate(n,i/2,b.options.easing).animate(p,i/2,b.options.easing,function(){a.effects.restore(c,d),a.effects.removeWrapper(c),b.callback&&b.callback.apply(this,arguments)})}c.queue("fx",function(){c.dequeue()}),c.dequeue()})}})(jQuery);;/*! jQuery UI - v1.8.23 - 2012-08-15
    +-* https://github.com/jquery/jquery-ui
    +-* Includes: jquery.effects.clip.js
    +-* Copyright (c) 2012 AUTHORS.txt; Licensed MIT, GPL */
    +-(function(a,b){a.effects.clip=function(b){return this.queue(function(){var c=a(this),d=["position","top","bottom","left","right","height","width"],e=a.effects.setMode(c,b.options.mode||"hide"),f=b.options.direction||"vertical";a.effects.save(c,d),c.show();var g=a.effects.createWrapper(c).css({overflow:"hidden"}),h=c[0].tagName=="IMG"?g:c,i={size:f=="vertical"?"height":"width",position:f=="vertical"?"top":"left"},j=f=="vertical"?h.height():h.width();e=="show"&&(h.css(i.size,0),h.css(i.position,j/2));var k={};k[i.size]=e=="show"?j:0,k[i.position]=e=="show"?0:j/2,h.animate(k,{queue:!1,duration:b.duration,easing:b.options.easing,complete:function(){e=="hide"&&c.hide(),a.effects.restore(c,d),a.effects.removeWrapper(c),b.callback&&b.callback.apply(c[0],arguments),c.dequeue()}})})}})(jQuery);;/*! jQuery UI - v1.8.23 - 2012-08-15
    +-* https://github.com/jquery/jquery-ui
    +-* Includes: jquery.effects.drop.js
    +-* Copyright (c) 2012 AUTHORS.txt; Licensed MIT, GPL */
    +-(function(a,b){a.effects.drop=function(b){return this.queue(function(){var c=a(this),d=["position","top","bottom","left","right","opacity"],e=a.effects.setMode(c,b.options.mode||"hide"),f=b.options.direction||"left";a.effects.save(c,d),c.show(),a.effects.createWrapper(c);var g=f=="up"||f=="down"?"top":"left",h=f=="up"||f=="left"?"pos":"neg",i=b.options.distance||(g=="top"?c.outerHeight(!0)/2:c.outerWidth(!0)/2);e=="show"&&c.css("opacity",0).css(g,h=="pos"?-i:i);var j={opacity:e=="show"?1:0};j[g]=(e=="show"?h=="pos"?"+=":"-=":h=="pos"?"-=":"+=")+i,c.animate(j,{queue:!1,duration:b.duration,easing:b.options.easing,complete:function(){e=="hide"&&c.hide(),a.effects.restore(c,d),a.effects.removeWrapper(c),b.callback&&b.callback.apply(this,arguments),c.dequeue()}})})}})(jQuery);;/*! jQuery UI - v1.8.23 - 2012-08-15
    +-* https://github.com/jquery/jquery-ui
    +-* Includes: jquery.effects.explode.js
    +-* Copyright (c) 2012 AUTHORS.txt; Licensed MIT, GPL */
    +-(function(a,b){a.effects.explode=function(b){return this.queue(function(){var c=b.options.pieces?Math.round(Math.sqrt(b.options.pieces)):3,d=b.options.pieces?Math.round(Math.sqrt(b.options.pieces)):3;b.options.mode=b.options.mode=="toggle"?a(this).is(":visible")?"hide":"show":b.options.mode;var e=a(this).show().css("visibility","hidden"),f=e.offset();f.top-=parseInt(e.css("marginTop"),10)||0,f.left-=parseInt(e.css("marginLeft"),10)||0;var g=e.outerWidth(!0),h=e.outerHeight(!0);for(var i=0;i<c;i++)for(var j=0;j<d;j++)e.clone().appendTo("body").wrap("<div></div>").css({position:"absolute",visibility:"visible",left:-j*(g/d),top:-i*(h/c)}).parent().addClass("ui-effects-explode").css({position:"absolute",overflow:"hidden",width:g/d,height:h/c,left:f.left+j*(g/d)+(b.options.mode=="show"?(j-Math.floor(d/2))*(g/d):0),top:f.top+i*(h/c)+(b.options.mode=="show"?(i-Math.floor(c/2))*(h/c):0),opacity:b.options.mode=="show"?0:1}).animate({left:f.left+j*(g/d)+(b.options.mode=="show"?0:(j-Math.floor(d/2))*(g/d)),top:f.top+i*(h/c)+(b.options.mode=="show"?0:(i-Math.floor(c/2))*(h/c)),opacity:b.options.mode=="show"?1:0},b.duration||500);setTimeout(function(){b.options.mode=="show"?e.css({visibility:"visible"}):e.css({visibility:"visible"}).hide(),b.callback&&b.callback.apply(e[0]),e.dequeue(),a("div.ui-effects-explode").remove()},b.duration||500)})}})(jQuery);;/*! jQuery UI - v1.8.23 - 2012-08-15
    +-* https://github.com/jquery/jquery-ui
    +-* Includes: jquery.effects.fade.js
    +-* Copyright (c) 2012 AUTHORS.txt; Licensed MIT, GPL */
    +-(function(a,b){a.effects.fade=function(b){return this.queue(function(){var c=a(this),d=a.effects.setMode(c,b.options.mode||"hide");c.animate({opacity:d},{queue:!1,duration:b.duration,easing:b.options.easing,complete:function(){b.callback&&b.callback.apply(this,arguments),c.dequeue()}})})}})(jQuery);;/*! jQuery UI - v1.8.23 - 2012-08-15
    +-* https://github.com/jquery/jquery-ui
    +-* Includes: jquery.effects.fold.js
    +-* Copyright (c) 2012 AUTHORS.txt; Licensed MIT, GPL */
    +-(function(a,b){a.effects.fold=function(b){return this.queue(function(){var c=a(this),d=["position","top","bottom","left","right"],e=a.effects.setMode(c,b.options.mode||"hide"),f=b.options.size||15,g=!!b.options.horizFirst,h=b.duration?b.duration/2:a.fx.speeds._default/2;a.effects.save(c,d),c.show();var i=a.effects.createWrapper(c).css({overflow:"hidden"}),j=e=="show"!=g,k=j?["width","height"]:["height","width"],l=j?[i.width(),i.height()]:[i.height(),i.width()],m=/([0-9]+)%/.exec(f);m&&(f=parseInt(m[1],10)/100*l[e=="hide"?0:1]),e=="show"&&i.css(g?{height:0,width:f}:{height:f,width:0});var n={},p={};n[k[0]]=e=="show"?l[0]:f,p[k[1]]=e=="show"?l[1]:0,i.animate(n,h,b.options.easing).animate(p,h,b.options.easing,function(){e=="hide"&&c.hide(),a.effects.restore(c,d),a.effects.removeWrapper(c),b.callback&&b.callback.apply(c[0],arguments),c.dequeue()})})}})(jQuery);;/*! jQuery UI - v1.8.23 - 2012-08-15
    +-* https://github.com/jquery/jquery-ui
    +-* Includes: jquery.effects.highlight.js
    +-* Copyright (c) 2012 AUTHORS.txt; Licensed MIT, GPL */
    +-(function(a,b){a.effects.highlight=function(b){return this.queue(function(){var c=a(this),d=["backgroundImage","backgroundColor","opacity"],e=a.effects.setMode(c,b.options.mode||"show"),f={backgroundColor:c.css("backgroundColor")};e=="hide"&&(f.opacity=0),a.effects.save(c,d),c.show().css({backgroundImage:"none",backgroundColor:b.options.color||"#ffff99"}).animate(f,{queue:!1,duration:b.duration,easing:b.options.easing,complete:function(){e=="hide"&&c.hide(),a.effects.restore(c,d),e=="show"&&!a.support.opacity&&this.style.removeAttribute("filter"),b.callback&&b.callback.apply(this,arguments),c.dequeue()}})})}})(jQuery);;/*! jQuery UI - v1.8.23 - 2012-08-15
    +-* https://github.com/jquery/jquery-ui
    +-* Includes: jquery.effects.pulsate.js
    +-* Copyright (c) 2012 AUTHORS.txt; Licensed MIT, GPL */
    +-(function(a,b){a.effects.pulsate=function(b){return this.queue(function(){var c=a(this),d=a.effects.setMode(c,b.options.mode||"show"),e=(b.options.times||5)*2-1,f=b.duration?b.duration/2:a.fx.speeds._default/2,g=c.is(":visible"),h=0;g||(c.css("opacity",0).show(),h=1),(d=="hide"&&g||d=="show"&&!g)&&e--;for(var i=0;i<e;i++)c.animate({opacity:h},f,b.options.easing),h=(h+1)%2;c.animate({opacity:h},f,b.options.easing,function(){h==0&&c.hide(),b.callback&&b.callback.apply(this,arguments)}),c.queue("fx",function(){c.dequeue()}).dequeue()})}})(jQuery);;/*! jQuery UI - v1.8.23 - 2012-08-15
    +-* https://github.com/jquery/jquery-ui
    +-* Includes: jquery.effects.scale.js
    +-* Copyright (c) 2012 AUTHORS.txt; Licensed MIT, GPL */
    +-(function(a,b){a.effects.puff=function(b){return this.queue(function(){var c=a(this),d=a.effects.setMode(c,b.options.mode||"hide"),e=parseInt(b.options.percent,10)||150,f=e/100,g={height:c.height(),width:c.width()};a.extend(b.options,{fade:!0,mode:d,percent:d=="hide"?e:100,from:d=="hide"?g:{height:g.height*f,width:g.width*f}}),c.effect("scale",b.options,b.duration,b.callback),c.dequeue()})},a.effects.scale=function(b){return this.queue(function(){var c=a(this),d=a.extend(!0,{},b.options),e=a.effects.setMode(c,b.options.mode||"effect"),f=parseInt(b.options.percent,10)||(parseInt(b.options.percent,10)==0?0:e=="hide"?0:100),g=b.options.direction||"both",h=b.options.origin;e!="effect"&&(d.origin=h||["middle","center"],d.restore=!0);var i={height:c.height(),width:c.width()};c.from=b.options.from||(e=="show"?{height:0,width:0}:i);var j={y:g!="horizontal"?f/100:1,x:g!="vertical"?f/100:1};c.to={height:i.height*j.y,width:i.width*j.x},b.options.fade&&(e=="show"&&(c.from.opacity=0,c.to.opacity=1),e=="hide"&&(c.from.opacity=1,c.to.opacity=0)),d.from=c.from,d.to=c.to,d.mode=e,c.effect("size",d,b.duration,b.callback),c.dequeue()})},a.effects.size=function(b){return this.queue(function(){var c=a(this),d=["position","top","bottom","left","right","width","height","overflow","opacity"],e=["position","top","bottom","left","right","overflow","opacity"],f=["width","height","overflow"],g=["fontSize"],h=["borderTopWidth","borderBottomWidth","paddingTop","paddingBottom"],i=["borderLeftWidth","borderRightWidth","paddingLeft","paddingRight"],j=a.effects.setMode(c,b.options.mode||"effect"),k=b.options.restore||!1,l=b.options.scale||"both",m=b.options.origin,n={height:c.height(),width:c.width()};c.from=b.options.from||n,c.to=b.options.to||n;if(m){var p=a.effects.getBaseline(m,n);c.from.top=(n.height-c.from.height)*p.y,c.from.left=(n.width-c.from.width)*p.x,c.to.top=(n.height-c.to.height)*p.y,c.to.left=(n.width-c.to.width)*p.x}var q={from:{y:c.from.height/n.height,x:c.from.width/n.width},to:{y:c.to.height/n.height,x:c.to.width/n.width}};if(l=="box"||l=="both")q.from.y!=q.to.y&&(d=d.concat(h),c.from=a.effects.setTransition(c,h,q.from.y,c.from),c.to=a.effects.setTransition(c,h,q.to.y,c.to)),q.from.x!=q.to.x&&(d=d.concat(i),c.from=a.effects.setTransition(c,i,q.from.x,c.from),c.to=a.effects.setTransition(c,i,q.to.x,c.to));(l=="content"||l=="both")&&q.from.y!=q.to.y&&(d=d.concat(g),c.from=a.effects.setTransition(c,g,q.from.y,c.from),c.to=a.effects.setTransition(c,g,q.to.y,c.to)),a.effects.save(c,k?d:e),c.show(),a.effects.createWrapper(c),c.css("overflow","hidden").css(c.from);if(l=="content"||l=="both")h=h.concat(["marginTop","marginBottom"]).concat(g),i=i.concat(["marginLeft","marginRight"]),f=d.concat(h).concat(i),c.find("*[width]").each(function(){var c=a(this);k&&a.effects.save(c,f);var d={height:c.height(),width:c.width()};c.from={height:d.height*q.from.y,width:d.width*q.from.x},c.to={height:d.height*q.to.y,width:d.width*q.to.x},q.from.y!=q.to.y&&(c.from=a.effects.setTransition(c,h,q.from.y,c.from),c.to=a.effects.setTransition(c,h,q.to.y,c.to)),q.from.x!=q.to.x&&(c.from=a.effects.setTransition(c,i,q.from.x,c.from),c.to=a.effects.setTransition(c,i,q.to.x,c.to)),c.css(c.from),c.animate(c.to,b.duration,b.options.easing,function(){k&&a.effects.restore(c,f)})});c.animate(c.to,{queue:!1,duration:b.duration,easing:b.options.easing,complete:function(){c.to.opacity===0&&c.css("opacity",c.from.opacity),j=="hide"&&c.hide(),a.effects.restore(c,k?d:e),a.effects.removeWrapper(c),b.callback&&b.callback.apply(this,arguments),c.dequeue()}})})}})(jQuery);;/*! jQuery UI - v1.8.23 - 2012-08-15
    +-* https://github.com/jquery/jquery-ui
    +-* Includes: jquery.effects.shake.js
    +-* Copyright (c) 2012 AUTHORS.txt; Licensed MIT, GPL */
    +-(function(a,b){a.effects.shake=function(b){return this.queue(function(){var c=a(this),d=["position","top","bottom","left","right"],e=a.effects.setMode(c,b.options.mode||"effect"),f=b.options.direction||"left",g=b.options.distance||20,h=b.options.times||3,i=b.duration||b.options.duration||140;a.effects.save(c,d),c.show(),a.effects.createWrapper(c);var j=f=="up"||f=="down"?"top":"left",k=f=="up"||f=="left"?"pos":"neg",l={},m={},n={};l[j]=(k=="pos"?"-=":"+=")+g,m[j]=(k=="pos"?"+=":"-=")+g*2,n[j]=(k=="pos"?"-=":"+=")+g*2,c.animate(l,i,b.options.easing);for(var p=1;p<h;p++)c.animate(m,i,b.options.easing).animate(n,i,b.options.easing);c.animate(m,i,b.options.easing).animate(l,i/2,b.options.easing,function(){a.effects.restore(c,d),a.effects.removeWrapper(c),b.callback&&b.callback.apply(this,arguments)}),c.queue("fx",function(){c.dequeue()}),c.dequeue()})}})(jQuery);;/*! jQuery UI - v1.8.23 - 2012-08-15
    +-* https://github.com/jquery/jquery-ui
    +-* Includes: jquery.effects.slide.js
    +-* Copyright (c) 2012 AUTHORS.txt; Licensed MIT, GPL */
    +-(function(a,b){a.effects.slide=function(b){return this.queue(function(){var c=a(this),d=["position","top","bottom","left","right"],e=a.effects.setMode(c,b.options.mode||"show"),f=b.options.direction||"left";a.effects.save(c,d),c.show(),a.effects.createWrapper(c).css({overflow:"hidden"});var g=f=="up"||f=="down"?"top":"left",h=f=="up"||f=="left"?"pos":"neg",i=b.options.distance||(g=="top"?c.outerHeight(!0):c.outerWidth(!0));e=="show"&&c.css(g,h=="pos"?isNaN(i)?"-"+i:-i:i);var j={};j[g]=(e=="show"?h=="pos"?"+=":"-=":h=="pos"?"-=":"+=")+i,c.animate(j,{queue:!1,duration:b.duration,easing:b.options.easing,complete:function(){e=="hide"&&c.hide(),a.effects.restore(c,d),a.effects.removeWrapper(c),b.callback&&b.callback.apply(this,arguments),c.dequeue()}})})}})(jQuery);;/*! jQuery UI - v1.8.23 - 2012-08-15
    +-* https://github.com/jquery/jquery-ui
    +-* Includes: jquery.effects.transfer.js
    +-* Copyright (c) 2012 AUTHORS.txt; Licensed MIT, GPL */
    +-(function(a,b){a.effects.transfer=function(b){return this.queue(function(){var c=a(this),d=a(b.options.to),e=d.offset(),f={top:e.top,left:e.left,height:d.innerHeight(),width:d.innerWidth()},g=c.offset(),h=a('<div class="ui-effects-transfer"></div>').appendTo(document.body).addClass(b.options.className).css({top:g.top,left:g.left,height:c.innerHeight(),width:c.innerWidth(),position:"absolute"}).animate(f,b.duration,b.options.easing,function(){h.remove(),b.callback&&b.callback.apply(c[0],arguments),c.dequeue()})})}})(jQuery);;
    +-/*! (c) 2012 Airbnb, Inc.
    +-*
    +-* polyglot.js 0.4.3 may be freely distributed under the terms of the BSD
    +-* license. For all licensing information, details, and documention:
    +-* http://airbnb.github.com/polyglot.js */
    +-(function(e,t){typeof define=="function"&&define.amd?define([],function(){return t(e)}):typeof exports=="object"?module.exports=t(e):e.Polyglot=t(e)})(this,function(e){"use strict";function t(e){e=e||{},this.phrases={},this.extend(e.phrases||{}),this.currentLocale=e.locale||"en",this.allowMissing=!!e.allowMissing,this.warn=e.warn||c}function s(e){var t,n,r,i={};for(t in e)if(e.hasOwnProperty(t)){n=e[t];for(r in n)i[n[r]]=t}return i}function o(e){var t=/^\s+|\s+$/g;return e.replace(t,"")}function u(e,t,r){var i,s,u;return r!=null&&e?(s=e.split(n),u=s[f(t,r)]||s[0],i=o(u)):i=e,i}function a(e){var t=s(i);return t[e]||t.en}function f(e,t){return r[a(e)](t)}function l(e,t){for(var n in t)n!=="_"&&t.hasOwnProperty(n)&&(e=e.replace(new RegExp("%\\{"+n+"\\}","g"),t[n]));return e}function c(t){e.console&&e.console.warn&&e.console.warn("WARNING: "+t)}function h(e){var t={};for(var n in e)t[n]=e[n];return t}t.VERSION="0.4.3",t.prototype.locale=function(e){return e&&(this.currentLocale=e),this.currentLocale},t.prototype.extend=function(e,t){var n;for(var r in e)e.hasOwnProperty(r)&&(n=e[r],t&&(r=t+"."+r),typeof n=="object"?this.extend(n,r):this.phrases[r]=n)},t.prototype.clear=function(){this.phrases={}},t.prototype.replace=function(e){this.clear(),this.extend(e)},t.prototype.t=function(e,t){var n,r;return t=t==null?{}:t,typeof t=="number"&&(t={smart_count:t}),typeof this.phrases[e]=="string"?n=this.phrases[e]:typeof t._=="string"?n=t._:this.allowMissing?n=e:(this.warn('Missing translation for key: "'+e+'"'),r=e),typeof n=="string"&&(t=h(t),r=u(n,this.currentLocale,t.smart_count),r=l(r,t)),r},t.prototype.has=function(e){return e in this.phrases};var n="||||",r={chinese:function(e){return 0},german:function(e){return e!==1?1:0},french:function(e){return e>1?1:0},russian:function(e){return e%10===1&&e%100!==11?0:e%10>=2&&e%10<=4&&(e%100<10||e%100>=20)?1:2},czech:function(e){return e===1?0:e>=2&&e<=4?1:2},polish:function(e){return e===1?0:e%10>=2&&e%10<=4&&(e%100<10||e%100>=20)?1:2},icelandic:function(e){return e%10!==1||e%100===11?1:0}},i={chinese:["fa","id","ja","ko","lo","ms","th","tr","zh"],german:["da","de","en","es","fi","el","he","hu","it","nl","no","pt","sv"],french:["fr","tl","pt-br"],russian:["hr","ru"],czech:["cs"],polish:["pl"],icelandic:["is"]};return t});
    +diff --git a/tools/droiddoc/templates-sdk-dev/assets/js/docs.js b/tools/droiddoc/templates-sdk-dev/assets/js/docs.js
    +deleted file mode 100644
    +index 5ed947c..0000000
    +--- a/tools/droiddoc/templates-sdk-dev/assets/js/docs.js
    ++++ /dev/null
    +@@ -1,6690 +0,0 @@
    +-var cookie_namespace = 'android_developer';
    +-var isMobile = false; // true if mobile, so we can adjust some layout
    +-var mPagePath; // initialized in ready() function
    +-
    +-var basePath = getBaseUri(location.pathname);
    +-var SITE_ROOT = toRoot + basePath.substring(1, basePath.indexOf("/", 1));
    +-
    +-// TODO(akassay) generate this var in the reference doc build.
    +-var API_LEVELS = ['1', '2', '3', '4', '5', '6', '7', '8', '9',
    +-      '10', '11', '12', '13', '14', '15', '16',
    +-      '17', '18', '19', '20', '21', '22', '23', '24'];
    +-var METADATA = METADATA || {};
    +-var RESERVED_METADATA_CATEGORY_NAMES = ['extras', 'carousel', 'collections',
    +-                                        'searchHeroCollections'];
    +-
    +-// Ensure that all ajax getScript() requests allow caching
    +-$.ajaxSetup({
    +-  cache: true
    +-});
    +-
    +-/******  ON LOAD SET UP STUFF *********/
    +-
    +-$(document).ready(function() {
    +-
    +-  // prep nav expandos
    +-  var pagePath = location.href.replace(location.hash, '');
    +-  // account for intl docs by removing the intl/*/ path
    +-  if (pagePath.indexOf("/intl/") == 0) {
    +-    pagePath = pagePath.substr(pagePath.indexOf("/", 6)); // start after intl/ to get last /
    +-  }
    +-
    +-  if (pagePath.indexOf(SITE_ROOT) == 0) {
    +-    if (pagePath == '' || pagePath.charAt(pagePath.length - 1) == '/') {
    +-      pagePath += 'index.html';
    +-    }
    +-  }
    +-
    +-  // Need a copy of the pagePath before it gets changed in the next block;
    +-  // it's needed to perform proper tab highlighting in offline docs (see rootDir below)
    +-  var pagePathOriginal = pagePath;
    +-  if (SITE_ROOT.match(/\.\.\//) || SITE_ROOT == '') {
    +-    // If running locally, SITE_ROOT will be a relative path, so account for that by
    +-    // finding the relative URL to this page. This will allow us to find links on the page
    +-    // leading back to this page.
    +-    var pathParts = pagePath.split('/');
    +-    var relativePagePathParts = [];
    +-    var upDirs = (SITE_ROOT.match(/(\.\.\/)+/) || [''])[0].length / 3;
    +-    for (var i = 0; i < upDirs; i++) {
    +-      relativePagePathParts.push('..');
    +-    }
    +-    for (var i = 0; i < upDirs; i++) {
    +-      relativePagePathParts.push(pathParts[pathParts.length - (upDirs - i) - 1]);
    +-    }
    +-    relativePagePathParts.push(pathParts[pathParts.length - 1]);
    +-    pagePath = relativePagePathParts.join('/');
    +-  } else {
    +-    // Otherwise the page path is already an absolute URL
    +-  }
    +-
    +-  // set global variable so we can highlight the sidenav a bit later (such as for google reference)
    +-  // and highlight the sidenav
    +-  mPagePath = pagePath;
    +-
    +-  // Check for params and remove them.
    +-  mPagePath = mPagePath.split('?')[0];
    +-  highlightSidenav();
    +-
    +-  // set up prev/next links if they exist
    +-  var $selNavLink = $('#nav').find('a[href="' + pagePath + '"]');
    +-  var $selListItem;
    +-  if ($selNavLink.length) {
    +-    $selListItem = $selNavLink.closest('li');
    +-
    +-    // set up prev links
    +-    var $prevLink = [];
    +-    var $prevListItem = $selListItem.prev('li');
    +-
    +-    var crossBoundaries = ($("body.design").length > 0) || ($("body.guide").length > 0) ? true :
    +-false; // navigate across topic boundaries only in design docs
    +-    if ($prevListItem.length) {
    +-      if ($prevListItem.hasClass('nav-section') || crossBoundaries) {
    +-        // jump to last topic of previous section
    +-        $prevLink = $prevListItem.find('a:last');
    +-      } else if (!$selListItem.hasClass('nav-section')) {
    +-        // jump to previous topic in this section
    +-        $prevLink = $prevListItem.find('a:eq(0)');
    +-      }
    +-    } else {
    +-      // jump to this section's index page (if it exists)
    +-      var $parentListItem = $selListItem.parents('li');
    +-      $prevLink = $selListItem.parents('li').find('a');
    +-
    +-      // except if cross boundaries aren't allowed, and we're at the top of a section already
    +-      // (and there's another parent)
    +-      if (!crossBoundaries && $parentListItem.hasClass('nav-section') &&
    +-                           $selListItem.hasClass('nav-section')) {
    +-        $prevLink = [];
    +-      }
    +-    }
    +-
    +-    // set up next links
    +-    var $nextLink = [];
    +-    var startClass = false;
    +-    var isCrossingBoundary = false;
    +-
    +-    if ($selListItem.hasClass('nav-section') && $selListItem.children('div.empty').length == 0) {
    +-      // we're on an index page, jump to the first topic
    +-      $nextLink = $selListItem.find('ul:eq(0)').find('a:eq(0)');
    +-
    +-      // if there aren't any children, go to the next section (required for About pages)
    +-      if ($nextLink.length == 0) {
    +-        $nextLink = $selListItem.next('li').find('a');
    +-      } else if ($('.topic-start-link').length) {
    +-        // as long as there's a child link and there is a "topic start link" (we're on a landing)
    +-        // then set the landing page "start link" text to be the first doc title
    +-        $('.topic-start-link').text($nextLink.text().toUpperCase());
    +-      }
    +-
    +-      // If the selected page has a description, then it's a class or article homepage
    +-      if ($selListItem.find('a[description]').length) {
    +-        // this means we're on a class landing page
    +-        startClass = true;
    +-      }
    +-    } else {
    +-      // jump to the next topic in this section (if it exists)
    +-      $nextLink = $selListItem.next('li').find('a:eq(0)');
    +-      if ($nextLink.length == 0) {
    +-        isCrossingBoundary = true;
    +-        // no more topics in this section, jump to the first topic in the next section
    +-        $nextLink = $selListItem.parents('li:eq(0)').next('li').find('a:eq(0)');
    +-        if (!$nextLink.length) {  // Go up another layer to look for next page (lesson > class > course)
    +-          $nextLink = $selListItem.parents('li:eq(1)').next('li.nav-section').find('a:eq(0)');
    +-          if ($nextLink.length == 0) {
    +-            // if that doesn't work, we're at the end of the list, so disable NEXT link
    +-            $('.next-page-link').attr('href', '').addClass("disabled")
    +-                                .click(function() { return false; });
    +-            // and completely hide the one in the footer
    +-            $('.content-footer .next-page-link').hide();
    +-          }
    +-        }
    +-      }
    +-    }
    +-
    +-    if (startClass) {
    +-      $('.start-class-link').attr('href', $nextLink.attr('href')).removeClass("hide");
    +-
    +-      // if there's no training bar (below the start button),
    +-      // then we need to add a bottom border to button
    +-      if (!$("#tb").length) {
    +-        $('.start-class-link').css({'border-bottom':'1px solid #DADADA'});
    +-      }
    +-    } else if (isCrossingBoundary && !$('body.design').length) {  // Design always crosses boundaries
    +-      $('.content-footer.next-class').show();
    +-      $('.next-page-link').attr('href', '')
    +-                          .removeClass("hide").addClass("disabled")
    +-                          .click(function() { return false; });
    +-      // and completely hide the one in the footer
    +-      $('.content-footer .next-page-link').hide();
    +-      $('.content-footer .prev-page-link').hide();
    +-
    +-      if ($nextLink.length) {
    +-        $('.next-class-link').attr('href', $nextLink.attr('href'))
    +-                             .removeClass("hide");
    +-
    +-        $('.content-footer .next-class-link').append($nextLink.html());
    +-
    +-        $('.next-class-link').find('.new').empty();
    +-      }
    +-    } else {
    +-      $('.next-page-link').attr('href', $nextLink.attr('href'))
    +-                          .removeClass("hide");
    +-      // for the footer link, also add the previous and next page titles
    +-      if ($prevLink.length) {
    +-        $('.content-footer .prev-page-link').append($prevLink.html());
    +-      }
    +-      if ($nextLink.length) {
    +-        $('.content-footer .next-page-link').append($nextLink.html());
    +-      }
    +-    }
    +-
    +-    if (!startClass && $prevLink.length) {
    +-      var prevHref = $prevLink.attr('href');
    +-      if (prevHref == SITE_ROOT + 'index.html') {
    +-        // Don't show Previous when it leads to the homepage
    +-      } else {
    +-        $('.prev-page-link').attr('href', $prevLink.attr('href')).removeClass("hide");
    +-      }
    +-    }
    +-  }
    +-
    +-  // Set up the course landing pages for Training with class names and descriptions
    +-  if ($('body.trainingcourse').length) {
    +-    var $classLinks = $selListItem.find('ul li a').not('#nav .nav-section .nav-section ul a');
    +-
    +-    // create an array for all the class descriptions
    +-    var $classDescriptions = new Array($classLinks.length);
    +-    var lang = getLangPref();
    +-    $classLinks.each(function(index) {
    +-      var langDescr = $(this).attr(lang + "-description");
    +-      if (typeof langDescr !== 'undefined' && langDescr !== false) {
    +-        // if there's a class description in the selected language, use that
    +-        $classDescriptions[index] = langDescr;
    +-      } else {
    +-        // otherwise, use the default english description
    +-        $classDescriptions[index] = $(this).attr("description");
    +-      }
    +-    });
    +-
    +-    var $olClasses  = $('<ol class="class-list"></ol>');
    +-    var $liClass;
    +-    var $h2Title;
    +-    var $pSummary;
    +-    var $olLessons;
    +-    var $liLesson;
    +-    $classLinks.each(function(index) {
    +-      $liClass  = $('<li class="clearfix"></li>');
    +-      $h2Title  = $('<a class="title" href="' + $(this).attr('href') + '"><h2 class="norule">' + $(this).html() + '</h2><span></span></a>');
    +-      $pSummary = $('<p class="description">' + $classDescriptions[index] + '</p>');
    +-
    +-      $olLessons  = $('<ol class="lesson-list"></ol>');
    +-
    +-      $lessons = $(this).closest('li').find('ul li a');
    +-
    +-      if ($lessons.length) {
    +-        $lessons.each(function(index) {
    +-          $olLessons.append('<li><a href="' + $(this).attr('href') + '">' + $(this).html() + '</a></li>');
    +-        });
    +-      } else {
    +-        $pSummary.addClass('article');
    +-      }
    +-
    +-      $liClass.append($h2Title).append($pSummary).append($olLessons);
    +-      $olClasses.append($liClass);
    +-    });
    +-    $('#classes').append($olClasses);
    +-  }
    +-
    +-  // Set up expand/collapse behavior
    +-  initExpandableNavItems("#nav");
    +-
    +-  // Set up play-on-hover <video> tags.
    +-  $('video.play-on-hover').bind('click', function() {
    +-    $(this).get(0).load(); // in case the video isn't seekable
    +-    $(this).get(0).play();
    +-  });
    +-
    +-  // Set up play-on-click for <video> tags with a "video-wrapper".
    +-  $('.video-wrapper > video').bind('click', function() {
    +-    this.play();
    +-    $(this.parentElement).addClass('playing');
    +-  });
    +-
    +-  // Set up tooltips
    +-  var TOOLTIP_MARGIN = 10;
    +-  $('acronym,.tooltip-link').each(function() {
    +-    var $target = $(this);
    +-    var $tooltip = $('<div>')
    +-        .addClass('tooltip-box')
    +-        .append($target.attr('title'))
    +-        .hide()
    +-        .appendTo('body');
    +-    $target.removeAttr('title');
    +-
    +-    $target.hover(function() {
    +-      // in
    +-      var targetRect = $target.offset();
    +-      targetRect.width = $target.width();
    +-      targetRect.height = $target.height();
    +-
    +-      $tooltip.css({
    +-        left: targetRect.left,
    +-        top: targetRect.top + targetRect.height + TOOLTIP_MARGIN
    +-      });
    +-      $tooltip.addClass('below');
    +-      $tooltip.show();
    +-    }, function() {
    +-      // out
    +-      $tooltip.hide();
    +-    });
    +-  });
    +-
    +-  // Set up <h2> deeplinks
    +-  $('h2').click(function() {
    +-    var id = $(this).attr('id');
    +-    if (id) {
    +-      if (history && history.replaceState) {
    +-        // Change url without scrolling.
    +-        history.replaceState({}, '', '#' + id);
    +-      } else {
    +-        document.location.hash = id;
    +-      }
    +-    }
    +-  });
    +-
    +-  //Loads the +1 button
    +-  //var po = document.createElement('script'); po.type = 'text/javascript'; po.async = true;
    +-  //po.src = 'https://apis.google.com/js/plusone.js';
    +-  //var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(po, s);
    +-});
    +-// END of the onload event
    +-
    +-function initExpandableNavItems(rootTag) {
    +-  var toggleIcon = $(
    +-      rootTag + ' li.nav-section .nav-section-header .toggle-icon, ' +
    +-      rootTag + ' li.nav-section .nav-section-header a[href="#"]');
    +-
    +-  toggleIcon.on('click keypress', function(e) {
    +-    if (e.type == 'keypress' && e.which == 13 || e.type == 'click') {
    +-      doNavToggle(this);
    +-    }
    +-  });
    +-
    +-  // Stop expand/collapse behavior when clicking on nav section links
    +-  // (since we're navigating away from the page)
    +-  // This selector captures the first instance of <a>, but not those with "#" as the href.
    +-  $('.nav-section-header').find('a:eq(0)').not('a[href="#"]').click(function(evt) {
    +-    window.location.href = $(this).attr('href');
    +-    return false;
    +-  });
    +-}
    +-
    +-function doNavToggle(el) {
    +-  var section = $(el).closest('li.nav-section');
    +-  if (section.hasClass('expanded')) {
    +-    /* hide me and descendants */
    +-    section.find('ul').slideUp(250, function() {
    +-      // remove 'expanded' class from my section and any children
    +-      section.closest('li').removeClass('expanded');
    +-      $('li.nav-section', section).removeClass('expanded');
    +-    });
    +-  } else {
    +-    /* show me */
    +-    // first hide all other siblings
    +-    var $others = $('li.nav-section.expanded', $(el).closest('ul')).not('.sticky');
    +-    $others.removeClass('expanded').children('ul').slideUp(250);
    +-
    +-    // now expand me
    +-    section.closest('li').addClass('expanded');
    +-    section.children('ul').slideDown(250);
    +-  }
    +-}
    +-
    +-/** Highlight the current page in sidenav, expanding children as appropriate */
    +-function highlightSidenav() {
    +-  // if something is already highlighted, undo it. This is for dynamic navigation (Samples index)
    +-  if ($("ul#nav li.selected").length) {
    +-    unHighlightSidenav();
    +-  }
    +-  // look for URL in sidenav, including the hash
    +-  var $selNavLink = $('#nav').find('a[href="' + mPagePath + location.hash + '"]');
    +-
    +-  // If the selNavLink is still empty, look for it without the hash
    +-  if ($selNavLink.length == 0) {
    +-    $selNavLink = $('#nav').find('a[href="' + mPagePath + '"]');
    +-  }
    +-
    +-  var $selListItem;
    +-  var breadcrumb = [];
    +-
    +-  if ($selNavLink.length) {
    +-    // Find this page's <li> in sidenav and set selected
    +-    $selListItem = $selNavLink.closest('li');
    +-    $selListItem.addClass('selected');
    +-
    +-    // Traverse up the tree and expand all parent nav-sections
    +-    $selNavLink.parents('li.nav-section').each(function() {
    +-      $(this).addClass('expanded');
    +-      $(this).children('ul').show();
    +-
    +-      var link = $(this).find('a').first();
    +-
    +-      if (!$(this).is($selListItem)) {
    +-        breadcrumb.unshift(link)
    +-      }
    +-    });
    +-
    +-    $('#nav').scrollIntoView($selNavLink);
    +-  }
    +-
    +-  breadcrumb.forEach(function(link) {
    +-    link.dacCrumbs();
    +-  });
    +-}
    +-
    +-function unHighlightSidenav() {
    +-  $("ul#nav li.selected").removeClass("selected");
    +-  $('ul#nav li.nav-section.expanded').removeClass('expanded').children('ul').hide();
    +-}
    +-
    +-var agent = navigator['userAgent'].toLowerCase();
    +-// If a mobile phone, set flag and do mobile setup
    +-if ((agent.indexOf("mobile") != -1) ||      // android, iphone, ipod
    +-    (agent.indexOf("blackberry") != -1) ||
    +-    (agent.indexOf("webos") != -1) ||
    +-    (agent.indexOf("mini") != -1)) {        // opera mini browsers
    +-  isMobile = true;
    +-}
    +-
    +-$(document).ready(function() {
    +-  $("pre:not(.no-pretty-print)").addClass("prettyprint");
    +-  prettyPrint();
    +-});
    +-
    +-/* Show popup dialogs */
    +-function showDialog(id) {
    +-  $dialog = $("#" + id);
    +-  $dialog.prepend('<div class="box-border"><div class="top"> <div class="left"></div> <div class="right"></div></div><div class="bottom"> <div class="left"></div> <div class="right"></div> </div> </div>');
    +-  $dialog.wrapInner('<div/>');
    +-  $dialog.removeClass("hide");
    +-}
    +-
    +-/* #########    COOKIES!     ########## */
    +-
    +-function readCookie(cookie) {
    +-  var myCookie = cookie_namespace + "_" + cookie + "=";
    +-  if (document.cookie) {
    +-    var index = document.cookie.indexOf(myCookie);
    +-    if (index != -1) {
    +-      var valStart = index + myCookie.length;
    +-      var valEnd = document.cookie.indexOf(";", valStart);
    +-      if (valEnd == -1) {
    +-        valEnd = document.cookie.length;
    +-      }
    +-      var val = document.cookie.substring(valStart, valEnd);
    +-      return val;
    +-    }
    +-  }
    +-  return 0;
    +-}
    +-
    +-function writeCookie(cookie, val, section) {
    +-  if (val == undefined) return;
    +-  section = section == null ? "_" : "_" + section + "_";
    +-  var age = 2 * 365 * 24 * 60 * 60; // set max-age to 2 years
    +-  var cookieValue = cookie_namespace + section + cookie + "=" + val +
    +-                    "; max-age=" + age + "; path=/";
    +-  document.cookie = cookieValue;
    +-}
    +-
    +-/* #########     END COOKIES!     ########## */
    +-
    +-/*
    +- * Manages secion card states and nav resize to conclude loading
    +- */
    +-(function() {
    +-  $(document).ready(function() {
    +-
    +-    // Stack hover states
    +-    $('.section-card-menu').each(function(index, el) {
    +-      var height = $(el).height();
    +-      $(el).css({height:height + 'px', position:'relative'});
    +-      var $cardInfo = $(el).find('.card-info');
    +-
    +-      $cardInfo.css({position: 'absolute', bottom:'0px', left:'0px', right:'0px', overflow:'visible'});
    +-    });
    +-
    +-  });
    +-
    +-})();
    +-
    +-/*      MISC LIBRARY FUNCTIONS     */
    +-
    +-function toggle(obj, slide) {
    +-  var ul = $("ul:first", obj);
    +-  var li = ul.parent();
    +-  if (li.hasClass("closed")) {
    +-    if (slide) {
    +-      ul.slideDown("fast");
    +-    } else {
    +-      ul.show();
    +-    }
    +-    li.removeClass("closed");
    +-    li.addClass("open");
    +-    $(".toggle-img", li).attr("title", "hide pages");
    +-  } else {
    +-    ul.slideUp("fast");
    +-    li.removeClass("open");
    +-    li.addClass("closed");
    +-    $(".toggle-img", li).attr("title", "show pages");
    +-  }
    +-}
    +-
    +-function buildToggleLists() {
    +-  $(".toggle-list").each(
    +-    function(i) {
    +-      $("div:first", this).append("<a class='toggle-img' href='#' title='show pages' onClick='toggle(this.parentNode.parentNode, true); return false;'></a>");
    +-      $(this).addClass("closed");
    +-    });
    +-}
    +-
    +-function hideNestedItems(list, toggle) {
    +-  $list = $(list);
    +-  // hide nested lists
    +-  if ($list.hasClass('showing')) {
    +-    $("li ol", $list).hide('fast');
    +-    $list.removeClass('showing');
    +-  // show nested lists
    +-  } else {
    +-    $("li ol", $list).show('fast');
    +-    $list.addClass('showing');
    +-  }
    +-  $(".more,.less", $(toggle)).toggle();
    +-}
    +-
    +-/* Call this to add listeners to a <select> element for Studio/Eclipse/Other docs */
    +-function setupIdeDocToggle() {
    +-  $("select.ide").change(function() {
    +-    var selected = $(this).find("option:selected").attr("value");
    +-    $(".select-ide").hide();
    +-    $(".select-ide." + selected).show();
    +-
    +-    $("select.ide").val(selected);
    +-  });
    +-}
    +-
    +-/* Used to hide and reveal supplemental content, such as long code samples.
    +-   See the companion CSS in android-developer-docs.css */
    +-function toggleContent(obj) {
    +-  var div = $(obj).closest(".toggle-content");
    +-  var toggleMe = $(".toggle-content-toggleme:eq(0)", div);
    +-  if (div.hasClass("closed")) { // if it's closed, open it
    +-    toggleMe.slideDown();
    +-    $(".toggle-content-text:eq(0)", obj).toggle();
    +-    div.removeClass("closed").addClass("open");
    +-    $(".toggle-content-img:eq(0)", div).attr("title", "hide").attr("src", toRoot +
    +-                  "assets/images/styles/disclosure_up.png");
    +-  } else { // if it's open, close it
    +-    toggleMe.slideUp('fast', function() {  // Wait until the animation is done before closing arrow
    +-      $(".toggle-content-text:eq(0)", obj).toggle();
    +-      div.removeClass("open").addClass("closed");
    +-      div.find(".toggle-content").removeClass("open").addClass("closed")
    +-              .find(".toggle-content-toggleme").hide();
    +-      $(".toggle-content-img", div).attr("title", "show").attr("src", toRoot +
    +-                  "assets/images/styles/disclosure_down.png");
    +-    });
    +-  }
    +-  return false;
    +-}
    +-
    +-/* New version of expandable content */
    +-function toggleExpandable(link, id) {
    +-  if ($(id).is(':visible')) {
    +-    $(id).slideUp();
    +-    $(link).removeClass('expanded');
    +-  } else {
    +-    $(id).slideDown();
    +-    $(link).addClass('expanded');
    +-  }
    +-}
    +-
    +-function hideExpandable(ids) {
    +-  $(ids).slideUp();
    +-  $(ids).prev('h4').find('a.expandable').removeClass('expanded');
    +-}
    +-
    +-/*
    +- *  Slideshow 1.0
    +- *  Used on /index.html and /develop/index.html for carousel
    +- *
    +- *  Sample usage:
    +- *  HTML -
    +- *  <div class="slideshow-container">
    +- *   <a href="" class="slideshow-prev">Prev</a>
    +- *   <a href="" class="slideshow-next">Next</a>
    +- *   <ul>
    +- *       <li class="item"><img src="images/marquee1.jpg"></li>
    +- *       <li class="item"><img src="images/marquee2.jpg"></li>
    +- *       <li class="item"><img src="images/marquee3.jpg"></li>
    +- *       <li class="item"><img src="images/marquee4.jpg"></li>
    +- *   </ul>
    +- *  </div>
    +- *
    +- *   <script type="text/javascript">
    +- *   $('.slideshow-container').dacSlideshow({
    +- *       auto: true,
    +- *       btnPrev: '.slideshow-prev',
    +- *       btnNext: '.slideshow-next'
    +- *   });
    +- *   </script>
    +- *
    +- *  Options:
    +- *  btnPrev:    optional identifier for previous button
    +- *  btnNext:    optional identifier for next button
    +- *  btnPause:   optional identifier for pause button
    +- *  auto:       whether or not to auto-proceed
    +- *  speed:      animation speed
    +- *  autoTime:   time between auto-rotation
    +- *  easing:     easing function for transition
    +- *  start:      item to select by default
    +- *  scroll:     direction to scroll in
    +- *  pagination: whether or not to include dotted pagination
    +- *
    +- */
    +-
    +-(function($) {
    +-  $.fn.dacSlideshow = function(o) {
    +-
    +-    //Options - see above
    +-    o = $.extend({
    +-      btnPrev:   null,
    +-      btnNext:   null,
    +-      btnPause:  null,
    +-      auto:      true,
    +-      speed:     500,
    +-      autoTime:  12000,
    +-      easing:    null,
    +-      start:     0,
    +-      scroll:    1,
    +-      pagination: true
    +-
    +-    }, o || {});
    +-
    +-    //Set up a carousel for each
    +-    return this.each(function() {
    +-
    +-      var running = false;
    +-      var animCss = o.vertical ? "top" : "left";
    +-      var sizeCss = o.vertical ? "height" : "width";
    +-      var div = $(this);
    +-      var ul = $("ul", div);
    +-      var tLi = $("li", ul);
    +-      var tl = tLi.size();
    +-      var timer = null;
    +-
    +-      var li = $("li", ul);
    +-      var itemLength = li.size();
    +-      var curr = o.start;
    +-
    +-      li.css({float: o.vertical ? "none" : "left"});
    +-      ul.css({margin: "0", padding: "0", position: "relative", "list-style-type": "none", "z-index": "1"});
    +-      div.css({position: "relative", "z-index": "2", left: "0px"});
    +-
    +-      var liSize = o.vertical ? height(li) : width(li);
    +-      var ulSize = liSize * itemLength;
    +-      var divSize = liSize;
    +-
    +-      li.css({width: li.width(), height: li.height()});
    +-      ul.css(sizeCss, ulSize + "px").css(animCss, -(curr * liSize));
    +-
    +-      div.css(sizeCss, divSize + "px");
    +-
    +-      //Pagination
    +-      if (o.pagination) {
    +-        var pagination = $("<div class='pagination'></div>");
    +-        var pag_ul = $("<ul></ul>");
    +-        if (tl > 1) {
    +-          for (var i = 0; i < tl; i++) {
    +-            var li = $("<li>" + i + "</li>");
    +-            pag_ul.append(li);
    +-            if (i == o.start) li.addClass('active');
    +-            li.click(function() {
    +-              go(parseInt($(this).text()));
    +-            })
    +-          }
    +-          pagination.append(pag_ul);
    +-          div.append(pagination);
    +-        }
    +-      }
    +-
    +-      //Previous button
    +-      if (o.btnPrev)
    +-             $(o.btnPrev).click(function(e) {
    +-               e.preventDefault();
    +-               return go(curr - o.scroll);
    +-             });
    +-
    +-      //Next button
    +-      if (o.btnNext)
    +-             $(o.btnNext).click(function(e) {
    +-               e.preventDefault();
    +-               return go(curr + o.scroll);
    +-             });
    +-
    +-      //Pause button
    +-      if (o.btnPause)
    +-             $(o.btnPause).click(function(e) {
    +-               e.preventDefault();
    +-               if ($(this).hasClass('paused')) {
    +-                 startRotateTimer();
    +-               } else {
    +-                 pauseRotateTimer();
    +-               }
    +-             });
    +-
    +-      //Auto rotation
    +-      if (o.auto) startRotateTimer();
    +-
    +-      function startRotateTimer() {
    +-        clearInterval(timer);
    +-        timer = setInterval(function() {
    +-          if (curr == tl - 1) {
    +-            go(0);
    +-          } else {
    +-            go(curr + o.scroll);
    +-          }
    +-        }, o.autoTime);
    +-        $(o.btnPause).removeClass('paused');
    +-      }
    +-
    +-      function pauseRotateTimer() {
    +-        clearInterval(timer);
    +-        $(o.btnPause).addClass('paused');
    +-      }
    +-
    +-      //Go to an item
    +-      function go(to) {
    +-        if (!running) {
    +-
    +-          if (to < 0) {
    +-            to = itemLength - 1;
    +-          } else if (to > itemLength - 1) {
    +-            to = 0;
    +-          }
    +-          curr = to;
    +-
    +-          running = true;
    +-
    +-          ul.animate(
    +-              animCss == "left" ? {left: -(curr * liSize)} : {top: -(curr * liSize)} , o.speed, o.easing,
    +-                     function() {
    +-                       running = false;
    +-                     }
    +-                 );
    +-
    +-          $(o.btnPrev + "," + o.btnNext).removeClass("disabled");
    +-          $((curr - o.scroll < 0 && o.btnPrev)              ||
    +-             (curr + o.scroll > itemLength && o.btnNext)              ||
    +-             []
    +-           ).addClass("disabled");
    +-
    +-          var nav_items = $('li', pagination);
    +-          nav_items.removeClass('active');
    +-          nav_items.eq(to).addClass('active');
    +-
    +-        }
    +-        if (o.auto) startRotateTimer();
    +-        return false;
    +-      };
    +-    });
    +-  };
    +-
    +-  function css(el, prop) {
    +-    return parseInt($.css(el[0], prop)) || 0;
    +-  };
    +-  function width(el) {
    +-    return el[0].offsetWidth + css(el, 'marginLeft') + css(el, 'marginRight');
    +-  };
    +-  function height(el) {
    +-    return el[0].offsetHeight + css(el, 'marginTop') + css(el, 'marginBottom');
    +-  };
    +-
    +-})(jQuery);
    +-
    +-/*
    +- *  dacSlideshow 1.0
    +- *  Used on develop/index.html for side-sliding tabs
    +- *
    +- *  Sample usage:
    +- *  HTML -
    +- *  <div class="slideshow-container">
    +- *   <a href="" class="slideshow-prev">Prev</a>
    +- *   <a href="" class="slideshow-next">Next</a>
    +- *   <ul>
    +- *       <li class="item"><img src="images/marquee1.jpg"></li>
    +- *       <li class="item"><img src="images/marquee2.jpg"></li>
    +- *       <li class="item"><img src="images/marquee3.jpg"></li>
    +- *       <li class="item"><img src="images/marquee4.jpg"></li>
    +- *   </ul>
    +- *  </div>
    +- *
    +- *   <script type="text/javascript">
    +- *   $('.slideshow-container').dacSlideshow({
    +- *       auto: true,
    +- *       btnPrev: '.slideshow-prev',
    +- *       btnNext: '.slideshow-next'
    +- *   });
    +- *   </script>
    +- *
    +- *  Options:
    +- *  btnPrev:    optional identifier for previous button
    +- *  btnNext:    optional identifier for next button
    +- *  auto:       whether or not to auto-proceed
    +- *  speed:      animation speed
    +- *  autoTime:   time between auto-rotation
    +- *  easing:     easing function for transition
    +- *  start:      item to select by default
    +- *  scroll:     direction to scroll in
    +- *  pagination: whether or not to include dotted pagination
    +- *
    +- */
    +-(function($) {
    +-  $.fn.dacTabbedList = function(o) {
    +-
    +-    //Options - see above
    +-    o = $.extend({
    +-      speed : 250,
    +-      easing: null,
    +-      nav_id: null,
    +-      frame_id: null
    +-    }, o || {});
    +-
    +-    //Set up a carousel for each
    +-    return this.each(function() {
    +-
    +-      var curr = 0;
    +-      var running = false;
    +-      var animCss = "margin-left";
    +-      var sizeCss = "width";
    +-      var div = $(this);
    +-
    +-      var nav = $(o.nav_id, div);
    +-      var nav_li = $("li", nav);
    +-      var nav_size = nav_li.size();
    +-      var frame = div.find(o.frame_id);
    +-      var content_width = $(frame).find('ul').width();
    +-      //Buttons
    +-      $(nav_li).click(function(e) {
    +-           go($(nav_li).index($(this)));
    +-         })
    +-
    +-      //Go to an item
    +-      function go(to) {
    +-        if (!running) {
    +-          curr = to;
    +-          running = true;
    +-
    +-          frame.animate({'margin-left' : -(curr * content_width)}, o.speed, o.easing,
    +-                     function() {
    +-                       running = false;
    +-                     }
    +-                 );
    +-
    +-          nav_li.removeClass('active');
    +-          nav_li.eq(to).addClass('active');
    +-
    +-        }
    +-        return false;
    +-      };
    +-    });
    +-  };
    +-
    +-  function css(el, prop) {
    +-    return parseInt($.css(el[0], prop)) || 0;
    +-  };
    +-  function width(el) {
    +-    return el[0].offsetWidth + css(el, 'marginLeft') + css(el, 'marginRight');
    +-  };
    +-  function height(el) {
    +-    return el[0].offsetHeight + css(el, 'marginTop') + css(el, 'marginBottom');
    +-  };
    +-
    +-})(jQuery);
    +-
    +-/* ######################################################## */
    +-/* #################  JAVADOC REFERENCE ################### */
    +-/* ######################################################## */
    +-
    +-
    +-
    +-var API_LEVEL_COOKIE = "api_level";
    +-var minLevel = 1;
    +-var maxLevel = 1;
    +-
    +-function buildApiLevelSelector() {
    +-  maxLevel = API_LEVELS.length;
    +-  var userApiLevel = parseInt(readCookie(API_LEVEL_COOKIE));
    +-  userApiLevel = userApiLevel == 0 ? maxLevel : userApiLevel; // If there's no cookie (zero), use the max by default
    +-
    +-  minLevel = parseInt($("#doc-api-level").attr("class"));
    +-  // Handle provisional api levels; the provisional level will always be the highest possible level
    +-  // Provisional api levels will also have a length; other stuff that's just missing a level won't,
    +-  // so leave those kinds of entities at the default level of 1 (for example, the R.styleable class)
    +-  if (isNaN(minLevel) && minLevel.length) {
    +-    minLevel = maxLevel;
    +-  }
    +-  var select = $("#apiLevelSelector").html("").change(changeApiLevel);
    +-  for (var i = maxLevel - 1; i >= 0; i--) {
    +-    var option = $("<option />").attr("value", "" + API_LEVELS[i]).append("" + API_LEVELS[i]);
    +-    //  if (API_LEVELS[i] < minLevel) option.addClass("absent"); // always false for strings (codenames)
    +-    select.append(option);
    +-  }
    +-
    +-  // get the DOM element and use setAttribute cuz IE6 fails when using jquery .attr('selected',true)
    +-  var selectedLevelItem = $("#apiLevelSelector option[value='" + userApiLevel + "']").get(0);
    +-  selectedLevelItem.setAttribute('selected', true);
    +-}
    +-
    +-function changeApiLevel() {
    +-  maxLevel = API_LEVELS.length;
    +-  minLevel = parseInt($('#doc-api-level').attr('class'));
    +-  var selectedLevel = maxLevel;
    +-
    +-  selectedLevel = parseInt($("#apiLevelSelector option:selected").val());
    +-  toggleVisisbleApis(selectedLevel, "body");
    +-
    +-  writeCookie(API_LEVEL_COOKIE, selectedLevel, null);
    +-
    +-  if (selectedLevel < minLevel) {
    +-      // Show the API notice dialog, set number values and button event
    +-      $('#api-unavailable').trigger('modal-open');
    +-      $('#api-unavailable .selected-level').text(selectedLevel);
    +-      $('#api-unavailable .api-level').text(minLevel);
    +-      $('#api-unavailable button.ok').attr('onclick','$("#apiLevelSelector").val("' + minLevel + '");changeApiLevel();');
    +-  }
    +-}
    +-
    +-function toggleVisisbleApis(selectedLevel, context) {
    +-  var apis = $(".api", context);
    +-  apis.each(function(i) {
    +-    var obj = $(this);
    +-    var className = obj.attr("class");
    +-    var apiLevelIndex = className.lastIndexOf("-") + 1;
    +-    var apiLevelEndIndex = className.indexOf(" ", apiLevelIndex);
    +-    apiLevelEndIndex = apiLevelEndIndex != -1 ? apiLevelEndIndex : className.length;
    +-    var apiLevel = className.substring(apiLevelIndex, apiLevelEndIndex);
    +-    if (apiLevel.length == 0) { // for odd cases when the since data is actually missing, just bail
    +-      return;
    +-    }
    +-    apiLevel = parseInt(apiLevel);
    +-
    +-    // Handle provisional api levels; if this item's level is the provisional one, set it to the max
    +-    var selectedLevelNum = parseInt(selectedLevel)
    +-    var apiLevelNum = parseInt(apiLevel);
    +-    if (isNaN(apiLevelNum)) {
    +-      apiLevelNum = maxLevel;
    +-    }
    +-
    +-    // Grey things out that aren't available and give a tooltip title
    +-    if (apiLevelNum > selectedLevelNum) {
    +-      obj.addClass("absent").attr("title", "Requires API Level \"" +
    +-            apiLevel + "\" or higher. To reveal, change the target API level " +
    +-              "above the left navigation.");
    +-    } else obj.removeClass("absent").removeAttr("title");
    +-  });
    +-}
    +-
    +-/* #################  SIDENAV TREE VIEW ################### */
    +-/* TODO: eliminate redundancy with non-google functions */
    +-function init_google_navtree(navtree_id, toroot, root_nodes) {
    +-  var me = new Object();
    +-  me.toroot = toroot;
    +-  me.node = new Object();
    +-
    +-  me.node.li = document.getElementById(navtree_id);
    +-  if (!me.node.li) {
    +-    return;
    +-  }
    +-
    +-  me.node.children_data = root_nodes;
    +-  me.node.children = new Array();
    +-  me.node.children_ul = document.createElement("ul");
    +-  me.node.get_children_ul = function() { return me.node.children_ul; };
    +-  //me.node.children_ul.className = "children_ul";
    +-  me.node.li.appendChild(me.node.children_ul);
    +-  me.node.depth = 0;
    +-
    +-  get_google_node(me, me.node);
    +-}
    +-
    +-function new_google_node(me, mom, text, link, children_data, api_level) {
    +-  var node = new Object();
    +-  var child;
    +-  node.children = Array();
    +-  node.children_data = children_data;
    +-  node.depth = mom.depth + 1;
    +-  node.get_children_ul = function() {
    +-      if (!node.children_ul) {
    +-        node.children_ul = document.createElement("ul");
    +-        node.children_ul.className = "tree-list-children";
    +-        node.li.appendChild(node.children_ul);
    +-      }
    +-      return node.children_ul;
    +-    };
    +-  node.li = document.createElement("li");
    +-
    +-  mom.get_children_ul().appendChild(node.li);
    +-
    +-  if (link) {
    +-    child = document.createElement("a");
    +-
    +-  } else {
    +-    child = document.createElement("span");
    +-    child.className = "tree-list-subtitle";
    +-
    +-  }
    +-  if (children_data != null) {
    +-    node.li.className = "nav-section";
    +-    node.label_div = document.createElement("div");
    +-    node.label_div.className = "nav-section-header-ref";
    +-    node.li.appendChild(node.label_div);
    +-    get_google_node(me, node);
    +-    node.label_div.appendChild(child);
    +-  } else {
    +-    node.li.appendChild(child);
    +-  }
    +-  if (link) {
    +-    child.href = me.toroot + link;
    +-  }
    +-  node.label = document.createTextNode(text);
    +-  child.appendChild(node.label);
    +-
    +-  node.children_ul = null;
    +-
    +-  return node;
    +-}
    +-
    +-function get_google_node(me, mom) {
    +-  mom.children_visited = true;
    +-  var linkText;
    +-  for (var i in mom.children_data) {
    +-    var node_data = mom.children_data[i];
    +-    linkText = node_data[0];
    +-
    +-    if (linkText.match("^" + "com.google.android") == "com.google.android") {
    +-      linkText = linkText.substr(19, linkText.length);
    +-    }
    +-    mom.children[i] = new_google_node(me, mom, linkText, node_data[1],
    +-        node_data[2], node_data[3]);
    +-  }
    +-}
    +-
    +-/****** NEW version of script to build google and sample navs dynamically ******/
    +-// TODO: update Google reference docs to tolerate this new implementation
    +-
    +-var NODE_NAME = 0;
    +-var NODE_HREF = 1;
    +-var NODE_GROUP = 2;
    +-var NODE_TAGS = 3;
    +-var NODE_CHILDREN = 4;
    +-
    +-function init_google_navtree2(navtree_id, data) {
    +-  var $containerUl = $("#" + navtree_id);
    +-  for (var i in data) {
    +-    var node_data = data[i];
    +-    $containerUl.append(new_google_node2(node_data));
    +-  }
    +-
    +-  // Make all third-generation list items 'sticky' to prevent them from collapsing
    +-  $containerUl.find('li li li.nav-section').addClass('sticky');
    +-
    +-  initExpandableNavItems("#" + navtree_id);
    +-}
    +-
    +-function new_google_node2(node_data) {
    +-  var linkText = node_data[NODE_NAME];
    +-  if (linkText.match("^" + "com.google.android") == "com.google.android") {
    +-    linkText = linkText.substr(19, linkText.length);
    +-  }
    +-  var $li = $('<li>');
    +-  var $a;
    +-  if (node_data[NODE_HREF] != null) {
    +-    $a = $('<a href="' + toRoot + node_data[NODE_HREF] + '" title="' + linkText + '" >' +
    +-        linkText + '</a>');
    +-  } else {
    +-    $a = $('<a href="#" onclick="return false;" title="' + linkText + '" >' +
    +-        linkText + '/</a>');
    +-  }
    +-  var $childUl = $('<ul>');
    +-  if (node_data[NODE_CHILDREN] != null) {
    +-    $li.addClass("nav-section");
    +-    $a = $('<div class="nav-section-header">').append($a);
    +-    if (node_data[NODE_HREF] == null) $a.addClass('empty');
    +-
    +-    for (var i in node_data[NODE_CHILDREN]) {
    +-      var child_node_data = node_data[NODE_CHILDREN][i];
    +-      $childUl.append(new_google_node2(child_node_data));
    +-    }
    +-    $li.append($childUl);
    +-  }
    +-  $li.prepend($a);
    +-
    +-  return $li;
    +-}
    +-
    +-function showGoogleRefTree() {
    +-  init_default_google_navtree(toRoot);
    +-  init_default_gcm_navtree(toRoot);
    +-}
    +-
    +-function init_default_google_navtree(toroot) {
    +-  // load json file for navtree data
    +-  $.getScript(toRoot + 'gms_navtree_data.js', function(data, textStatus, jqxhr) {
    +-    // when the file is loaded, initialize the tree
    +-    if (jqxhr.status === 200) {
    +-      init_google_navtree("gms-tree-list", toroot, GMS_NAVTREE_DATA);
    +-      highlightSidenav();
    +-    }
    +-  });
    +-}
    +-
    +-function init_default_gcm_navtree(toroot) {
    +-  // load json file for navtree data
    +-  $.getScript(toRoot + 'gcm_navtree_data.js', function(data, textStatus, jqxhr) {
    +-    // when the file is loaded, initialize the tree
    +-    if (jqxhr.status === 200) {
    +-      init_google_navtree("gcm-tree-list", toroot, GCM_NAVTREE_DATA);
    +-      highlightSidenav();
    +-    }
    +-  });
    +-}
    +-
    +-/* TOGGLE INHERITED MEMBERS */
    +-
    +-/* Toggle an inherited class (arrow toggle)
    +- * @param linkObj  The link that was clicked.
    +- * @param expand  'true' to ensure it's expanded. 'false' to ensure it's closed.
    +- *                'null' to simply toggle.
    +- */
    +-function toggleInherited(linkObj, expand) {
    +-  var base = linkObj.getAttribute("id");
    +-  var list = document.getElementById(base + "-list");
    +-  var summary = document.getElementById(base + "-summary");
    +-  var trigger = document.getElementById(base + "-trigger");
    +-  var a = $(linkObj);
    +-  if ((expand == null && a.hasClass("closed")) || expand) {
    +-    list.style.display = "none";
    +-    summary.style.display = "block";
    +-    trigger.src = toRoot + "assets/images/styles/disclosure_up.png";
    +-    a.removeClass("closed");
    +-    a.addClass("opened");
    +-  } else if ((expand == null && a.hasClass("opened")) || (expand == false)) {
    +-    list.style.display = "block";
    +-    summary.style.display = "none";
    +-    trigger.src = toRoot + "assets/images/styles/disclosure_down.png";
    +-    a.removeClass("opened");
    +-    a.addClass("closed");
    +-  }
    +-  return false;
    +-}
    +-
    +-/* Toggle all inherited classes in a single table (e.g. all inherited methods)
    +- * @param linkObj  The link that was clicked.
    +- * @param expand  'true' to ensure it's expanded. 'false' to ensure it's closed.
    +- *                'null' to simply toggle.
    +- */
    +-function toggleAllInherited(linkObj, expand) {
    +-  var a = $(linkObj);
    +-  var table = $(a.parent().parent().parent()); // ugly way to get table/tbody
    +-  var expandos = $(".jd-expando-trigger", table);
    +-  if ((expand == null && a.text() == "[Expand]") || expand) {
    +-    expandos.each(function(i) {
    +-      toggleInherited(this, true);
    +-    });
    +-    a.text("[Collapse]");
    +-  } else if ((expand == null && a.text() == "[Collapse]") || (expand == false)) {
    +-    expandos.each(function(i) {
    +-      toggleInherited(this, false);
    +-    });
    +-    a.text("[Expand]");
    +-  }
    +-  return false;
    +-}
    +-
    +-/* Toggle all inherited members in the class (link in the class title)
    +- */
    +-function toggleAllClassInherited() {
    +-  var a = $("#toggleAllClassInherited"); // get toggle link from class title
    +-  var toggles = $(".toggle-all", $("#body-content"));
    +-  if (a.text() == "[Expand All]") {
    +-    toggles.each(function(i) {
    +-      toggleAllInherited(this, true);
    +-    });
    +-    a.text("[Collapse All]");
    +-  } else {
    +-    toggles.each(function(i) {
    +-      toggleAllInherited(this, false);
    +-    });
    +-    a.text("[Expand All]");
    +-  }
    +-  return false;
    +-}
    +-
    +-/* Expand all inherited members in the class. Used when initiating page search */
    +-function ensureAllInheritedExpanded() {
    +-  var toggles = $(".toggle-all", $("#body-content"));
    +-  toggles.each(function(i) {
    +-    toggleAllInherited(this, true);
    +-  });
    +-  $("#toggleAllClassInherited").text("[Collapse All]");
    +-}
    +-
    +-/* HANDLE KEY EVENTS
    +- * - Listen for Ctrl+F (Cmd on Mac) and expand all inherited members (to aid page search)
    +- */
    +-var agent = navigator['userAgent'].toLowerCase();
    +-var mac = agent.indexOf("macintosh") != -1;
    +-
    +-$(document).keydown(function(e) {
    +-  var control = mac ? e.metaKey && !e.ctrlKey : e.ctrlKey; // get ctrl key
    +-  if (control && e.which == 70) {  // 70 is "F"
    +-    ensureAllInheritedExpanded();
    +-  }
    +-});
    +-
    +-/* On-demand functions */
    +-
    +-/** Move sample code line numbers out of PRE block and into non-copyable column */
    +-function initCodeLineNumbers() {
    +-  var numbers = $("#codesample-block a.number");
    +-  if (numbers.length) {
    +-    $("#codesample-line-numbers").removeClass("hidden").append(numbers);
    +-  }
    +-
    +-  $(document).ready(function() {
    +-    // select entire line when clicked
    +-    $("span.code-line").click(function() {
    +-      if (!shifted) {
    +-        selectText(this);
    +-      }
    +-    });
    +-    // invoke line link on double click
    +-    $(".code-line").dblclick(function() {
    +-      document.location.hash = $(this).attr('id');
    +-    });
    +-    // highlight the line when hovering on the number
    +-    $("#codesample-line-numbers a.number").mouseover(function() {
    +-      var id = $(this).attr('href');
    +-      $(id).css('background', '#e7e7e7');
    +-    });
    +-    $("#codesample-line-numbers a.number").mouseout(function() {
    +-      var id = $(this).attr('href');
    +-      $(id).css('background', 'none');
    +-    });
    +-  });
    +-}
    +-
    +-// create SHIFT key binder to avoid the selectText method when selecting multiple lines
    +-var shifted = false;
    +-$(document).bind('keyup keydown', function(e) {
    +-  shifted = e.shiftKey; return true;
    +-});
    +-
    +-// courtesy of jasonedelman.com
    +-function selectText(element) {
    +-  var doc = document      ,
    +-        range, selection
    +-  ;
    +-  if (doc.body.createTextRange) { //ms
    +-    range = doc.body.createTextRange();
    +-    range.moveToElementText(element);
    +-    range.select();
    +-  } else if (window.getSelection) { //all others
    +-    selection = window.getSelection();
    +-    range = doc.createRange();
    +-    range.selectNodeContents(element);
    +-    selection.removeAllRanges();
    +-    selection.addRange(range);
    +-  }
    +-}
    +-
    +-/** Display links and other information about samples that match the
    +-    group specified by the URL */
    +-function showSamples() {
    +-  var group = $("#samples").attr('class');
    +-  $("#samples").html("<p>Here are some samples for <b>" + group + "</b> apps:</p>");
    +-
    +-  var $ul = $("<ul>");
    +-  $selectedLi = $("#nav li.selected");
    +-
    +-  $selectedLi.children("ul").children("li").each(function() {
    +-    var $li = $("<li>").append($(this).find("a").first().clone());
    +-    var $samplesLink = $li.find("a");
    +-    if ($samplesLink.text().endsWith('/')) {
    +-      $samplesLink.text($samplesLink.text().slice(0,-1));
    +-    }
    +-    $ul.append($li);
    +-  });
    +-
    +-  $("#samples").append($ul);
    +-
    +-}
    +-
    +-/* ########################################################## */
    +-/* ###################  RESOURCE CARDS  ##################### */
    +-/* ########################################################## */
    +-
    +-/** Handle resource queries, collections, and grids (sections). Requires
    +-    jd_tag_helpers.js and the *_unified_data.js to be loaded. */
    +-
    +-(function() {
    +-  $(document).ready(function() {
    +-    // Need to initialize hero carousel before other sections for dedupe
    +-    // to work correctly.
    +-    $('[data-carousel-query]').dacCarouselQuery();
    +-
    +-    // Iterate over all instances and initialize a resource widget.
    +-    $('.resource-widget').resourceWidget();
    +-  });
    +-
    +-  $.fn.widgetOptions = function() {
    +-    return {
    +-      cardSizes: (this.data('cardsizes') || '').split(','),
    +-      maxResults: parseInt(this.data('maxresults'), 10) || Infinity,
    +-      initialResults: this.data('initialResults'),
    +-      itemsPerPage: this.data('itemsPerPage'),
    +-      sortOrder: this.data('sortorder'),
    +-      query: this.data('query'),
    +-      section: this.data('section'),
    +-      /* Added by LFL 6/6/14 */
    +-      resourceStyle: this.data('resourcestyle') || 'card',
    +-      stackSort: this.data('stacksort') || 'true',
    +-      // For filter based resources
    +-      allowDuplicates: this.data('allow-duplicates') || 'false'
    +-    };
    +-  };
    +-
    +-  $.fn.deprecateOldGridStyles = function() {
    +-    var m = this.get(0).className.match(/\bcol-(\d+)\b/);
    +-    if (m && !this.is('.cols > *')) {
    +-      this.removeClass('col-' + m[1]);
    +-    }
    +-    return this;
    +-  }
    +-
    +-  /*
    +-   * Three types of resource layouts:
    +-   * Flow - Uses a fixed row-height flow using float left style.
    +-   * Carousel - Single card slideshow all same dimension absolute.
    +-   * Stack - Uses fixed columns and flexible element height.
    +-   */
    +-  function initResourceWidget(widget, resources, opts) {
    +-    var $widget = $(widget).deprecateOldGridStyles();
    +-    var isFlow = $widget.hasClass('resource-flow-layout');
    +-    var isCarousel = $widget.hasClass('resource-carousel-layout');
    +-    var isStack = $widget.hasClass('resource-stack-layout');
    +-
    +-    opts = opts || $widget.widgetOptions();
    +-    resources = resources || metadata.query(opts);
    +-
    +-    if (opts.maxResults !== undefined) {
    +-      resources = resources.slice(0, opts.maxResults);
    +-    }
    +-
    +-    if (isFlow) {
    +-      drawResourcesFlowWidget($widget, opts, resources);
    +-    } else if (isCarousel) {
    +-      drawResourcesCarouselWidget($widget, opts, resources);
    +-    } else if (isStack) {
    +-      opts.numStacks = $widget.data('numstacks');
    +-      drawResourcesStackWidget($widget, opts, resources);
    +-    }
    +-  }
    +-
    +-  $.fn.resourceWidget = function(resources, options) {
    +-    return this.each(function() {
    +-      initResourceWidget(this, resources, options);
    +-    });
    +-  };
    +-
    +-  /* Initializes a Resource Carousel Widget */
    +-  function drawResourcesCarouselWidget($widget, opts, resources) {
    +-    $widget.empty();
    +-    var plusone = false; // stop showing plusone buttons on cards
    +-
    +-    $widget.addClass('resource-card slideshow-container')
    +-      .append($('<a>').addClass('slideshow-prev').text('Prev'))
    +-      .append($('<a>').addClass('slideshow-next').text('Next'));
    +-
    +-    var css = {'width': $widget.width() + 'px',
    +-                'height': $widget.height() + 'px'};
    +-
    +-    var $ul = $('<ul>');
    +-
    +-    for (var i = 0; i < resources.length; ++i) {
    +-      var $card = $('<a>')
    +-        .attr('href', cleanUrl(resources[i].url))
    +-        .decorateResourceCard(resources[i], plusone);
    +-
    +-      $('<li>').css(css)
    +-          .append($card)
    +-          .appendTo($ul);
    +-    }
    +-
    +-    $('<div>').addClass('frame')
    +-      .append($ul)
    +-      .appendTo($widget);
    +-
    +-    $widget.dacSlideshow({
    +-      auto: true,
    +-      btnPrev: '.slideshow-prev',
    +-      btnNext: '.slideshow-next'
    +-    });
    +-  }
    +-
    +-  /* Initializes a Resource Card Stack Widget (column-based layout)
    +-     Modified by LFL 6/6/14
    +-   */
    +-  function drawResourcesStackWidget($widget, opts, resources, sections) {
    +-    // Don't empty widget, grab all items inside since they will be the first
    +-    // items stacked, followed by the resource query
    +-    var plusone = false; // stop showing plusone buttons on cards
    +-    var cards = $widget.find('.resource-card').detach().toArray();
    +-    var numStacks = opts.numStacks || 1;
    +-    var $stacks = [];
    +-
    +-    for (var i = 0; i < numStacks; ++i) {
    +-      $stacks[i] = $('<div>').addClass('resource-card-stack')
    +-          .appendTo($widget);
    +-    }
    +-
    +-    var sectionResources = [];
    +-
    +-    // Extract any subsections that are actually resource cards
    +-    if (sections) {
    +-      for (i = 0; i < sections.length; ++i) {
    +-        if (!sections[i].sections || !sections[i].sections.length) {
    +-          // Render it as a resource card
    +-          sectionResources.push(
    +-            $('<a>')
    +-              .addClass('resource-card section-card')
    +-              .attr('href', cleanUrl(sections[i].resource.url))
    +-              .decorateResourceCard(sections[i].resource, plusone)[0]
    +-          );
    +-
    +-        } else {
    +-          cards.push(
    +-            $('<div>')
    +-              .addClass('resource-card section-card-menu')
    +-              .decorateResourceSection(sections[i], plusone)[0]
    +-          );
    +-        }
    +-      }
    +-    }
    +-
    +-    cards = cards.concat(sectionResources);
    +-
    +-    for (i = 0; i < resources.length; ++i) {
    +-      var $card = createResourceElement(resources[i], opts);
    +-
    +-      if (opts.resourceStyle.indexOf('related') > -1) {
    +-        $card.addClass('related-card');
    +-      }
    +-
    +-      cards.push($card[0]);
    +-    }
    +-
    +-    if (opts.stackSort !== 'false') {
    +-      for (i = 0; i < cards.length; ++i) {
    +-        // Find the stack with the shortest height, but give preference to
    +-        // left to right order.
    +-        var minHeight = $stacks[0].height();
    +-        var minIndex = 0;
    +-
    +-        for (var j = 1; j < numStacks; ++j) {
    +-          var height = $stacks[j].height();
    +-          if (height < minHeight - 45) {
    +-            minHeight = height;
    +-            minIndex = j;
    +-          }
    +-        }
    +-
    +-        $stacks[minIndex].append($(cards[i]));
    +-      }
    +-    }
    +-  }
    +-
    +-  /*
    +-    Create a resource card using the given resource object and a list of html
    +-     configured options. Returns a jquery object containing the element.
    +-  */
    +-  function createResourceElement(resource, opts, plusone) {
    +-    var $el;
    +-
    +-    // The difference here is that generic cards are not entirely clickable
    +-    // so its a div instead of an a tag, also the generic one is not given
    +-    // the resource-card class so it appears with a transparent background
    +-    // and can be styled in whatever way the css setup.
    +-    if (opts.resourceStyle === 'generic') {
    +-      $el = $('<div>')
    +-        .addClass('resource')
    +-        .attr('href', cleanUrl(resource.url))
    +-        .decorateResource(resource, opts);
    +-    } else {
    +-      var cls = 'resource resource-card';
    +-
    +-      $el = $('<a>')
    +-        .addClass(cls)
    +-        .attr('href', cleanUrl(resource.url))
    +-        .decorateResourceCard(resource, plusone);
    +-    }
    +-
    +-    return $el;
    +-  }
    +-
    +-  function createResponsiveFlowColumn(cardSize) {
    +-    var cardWidth = parseInt(cardSize.match(/(\d+)/)[1], 10);
    +-    var column = $('<div>').addClass('col-' + (cardWidth / 3) + 'of6');
    +-    if (cardWidth < 9) {
    +-      column.addClass('col-tablet-1of2');
    +-    } else if (cardWidth > 9 && cardWidth < 18) {
    +-      column.addClass('col-tablet-1of1');
    +-    }
    +-    if (cardWidth < 18) {
    +-      column.addClass('col-mobile-1of1');
    +-    }
    +-    return column;
    +-  }
    +-
    +-  /* Initializes a flow widget, see distribute.scss for generating accompanying css */
    +-  function drawResourcesFlowWidget($widget, opts, resources) {
    +-    // We'll be doing our own modifications to opts.
    +-    opts = $.extend({}, opts);
    +-
    +-    $widget.empty().addClass('cols');
    +-    if (opts.itemsPerPage) {
    +-      $('<div class="col-1of1 dac-section-links dac-text-center">')
    +-        .append(
    +-          $('<div class="dac-section-link dac-show-less" data-toggle="show-less">Less<i class="dac-sprite dac-auto-unfold-less"></i></div>'),
    +-          $('<div class="dac-section-link dac-show-more" data-toggle="show-more">More<i class="dac-sprite dac-auto-unfold-more"></i></div>')
    +-        )
    +-        .appendTo($widget);
    +-    }
    +-
    +-    $widget.data('options.resourceflow', opts);
    +-    $widget.data('resources.resourceflow', resources);
    +-
    +-    drawResourceFlowPage($widget, opts, resources);
    +-  }
    +-
    +-  function drawResourceFlowPage($widget, opts, resources) {
    +-    var cardSizes = opts.cardSizes || ['6x6']; // 2015-08-09: dynamic card sizes are deprecated
    +-    var i = opts.currentIndex || 0;
    +-    var j = 0;
    +-    var plusone = false; // stop showing plusone buttons on cards
    +-    var firstPage = i === 0;
    +-    var initialResults = opts.initialResults || opts.itemsPerPage || resources.length;
    +-    var max = firstPage ? initialResults : i + opts.itemsPerPage;
    +-    max = Math.min(resources.length, max);
    +-
    +-    var page = $('<div class="resource-flow-page">');
    +-    if (opts.itemsPerPage) {
    +-      $widget.find('.dac-section-links').before(page);
    +-    } else {
    +-      $widget.append(page);
    +-    }
    +-
    +-    while (i < max) {
    +-      var cardSize = cardSizes[j++ % cardSizes.length];
    +-      cardSize = cardSize.replace(/^\s+|\s+$/, '');
    +-
    +-      var column = createResponsiveFlowColumn(cardSize).appendTo(page);
    +-
    +-      // A stack has a third dimension which is the number of stacked items
    +-      var isStack = cardSize.match(/(\d+)x(\d+)x(\d+)/);
    +-      var stackCount = 0;
    +-      var $stackDiv = null;
    +-
    +-      if (isStack) {
    +-        // Create a stack container which should have the dimensions defined
    +-        // by the product of the items inside.
    +-        $stackDiv = $('<div>').addClass('resource-card-stack resource-card-' + isStack[1] +
    +-          'x' + isStack[2] * isStack[3]) .appendTo(column);
    +-      }
    +-
    +-      // Build each stack item or just a single item
    +-      do {
    +-        var resource = resources[i];
    +-
    +-        var $card = createResourceElement(resources[i], opts, plusone);
    +-
    +-        $card.addClass('resource-card-' + cardSize +
    +-          ' resource-card-' + resource.type.toLowerCase());
    +-
    +-        if (isStack) {
    +-          $card.addClass('resource-card-' + isStack[1] + 'x' + isStack[2]);
    +-          if (++stackCount === parseInt(isStack[3])) {
    +-            $card.addClass('resource-card-row-stack-last');
    +-            stackCount = 0;
    +-          }
    +-        } else {
    +-          stackCount = 0;
    +-        }
    +-
    +-        $card.appendTo($stackDiv || column);
    +-
    +-      } while (++i < max && stackCount > 0);
    +-
    +-      // Record number of pages viewed in analytics.
    +-      if (!firstPage) {
    +-        var clicks = Math.ceil((i - initialResults) / opts.itemsPerPage);
    +-        devsite.analytics.trackAnalyticsEvent('event',
    +-            'Cards', 'Click More', clicks);
    +-      }
    +-    }
    +-
    +-    opts.currentIndex = i;
    +-    $widget.toggleClass('dac-has-more', i < resources.length);
    +-    $widget.toggleClass('dac-has-less', !firstPage);
    +-
    +-    $widget.trigger('dac:domchange');
    +-    if (opts.onRenderPage) {
    +-      opts.onRenderPage(page);
    +-    }
    +-  }
    +-
    +-  function drawResourceFlowReset($widget, opts, resources) {
    +-    $widget.find('.resource-flow-page')
    +-        .slice(1)
    +-        .remove();
    +-    $widget.toggleClass('dac-has-more', true);
    +-    $widget.toggleClass('dac-has-less', false);
    +-
    +-    opts.currentIndex = Math.min(opts.initialResults, resources.length);
    +-    devsite.analytics.trackAnalyticsEvent('event', 'Cards', 'Click Less');
    +-  }
    +-
    +-  /* A decorator for event functions which finds the surrounding widget and it's options */
    +-  function wrapWithWidget(func) {
    +-    return function(e) {
    +-      if (e) e.preventDefault();
    +-
    +-      var $widget = $(this).closest('.resource-flow-layout');
    +-      var opts = $widget.data('options.resourceflow');
    +-      var resources = $widget.data('resources.resourceflow');
    +-      func($widget, opts, resources);
    +-    };
    +-  }
    +-
    +-  /* Build a site map of resources using a section as a root. */
    +-  function buildSectionList(opts) {
    +-    if (opts.section && SECTION_BY_ID[opts.section]) {
    +-      return SECTION_BY_ID[opts.section].sections || [];
    +-    }
    +-    return [];
    +-  }
    +-
    +-  function cleanUrl(url) {
    +-    if (url && url.indexOf('//') === -1) {
    +-      url = toRoot + url;
    +-    }
    +-
    +-    return url;
    +-  }
    +-
    +-  // Delegated events for resources.
    +-  $(document).on('click', '.resource-flow-layout [data-toggle="show-more"]', wrapWithWidget(drawResourceFlowPage));
    +-  $(document).on('click', '.resource-flow-layout [data-toggle="show-less"]', wrapWithWidget(drawResourceFlowReset));
    +-})();
    +-
    +-(function($) {
    +-  // A mapping from category and type values to new values or human presentable strings.
    +-  var SECTION_MAP = {
    +-    googleplay: 'google play'
    +-  };
    +-
    +-  /*
    +-    Utility method for creating dom for the description area of a card.
    +-    Used in decorateResourceCard and decorateResource.
    +-  */
    +-  function buildResourceCardDescription(resource, plusone) {
    +-    var $description = $('<div>').addClass('description ellipsis');
    +-
    +-    $description.append($('<div>').addClass('text').html(resource.summary));
    +-
    +-    if (resource.cta) {
    +-      $description.append($('<a>').addClass('cta').html(resource.cta));
    +-    }
    +-
    +-    if (plusone) {
    +-      var plusurl = resource.url.indexOf("//") > -1 ? resource.url :
    +-        "//developer.android.com/" + resource.url;
    +-
    +-      $description.append($('<div>').addClass('util')
    +-        .append($('<div>').addClass('g-plusone')
    +-          .attr('data-size', 'small')
    +-          .attr('data-align', 'right')
    +-          .attr('data-href', plusurl)));
    +-    }
    +-
    +-    return $description;
    +-  }
    +-
    +-  /* Simple jquery function to create dom for a standard resource card */
    +-  $.fn.decorateResourceCard = function(resource, plusone) {
    +-    var section = resource.category || resource.type;
    +-    section = (SECTION_MAP[section] || section).toLowerCase();
    +-    var imgUrl = resource.image ||
    +-      'assets/images/resource-card-default-android.jpg';
    +-
    +-    if (imgUrl.indexOf('//') === -1) {
    +-      imgUrl = toRoot + imgUrl;
    +-    }
    +-
    +-    if (resource.type === 'youtube' || resource.type === 'video') {
    +-      $('<div>').addClass('play-button')
    +-        .append($('<i class="dac-sprite dac-play-white">'))
    +-        .appendTo(this);
    +-    }
    +-
    +-    $('<div>').addClass('card-bg')
    +-      .css('background-image', 'url(' + (imgUrl || toRoot +
    +-        'assets/images/resource-card-default-android.jpg') + ')')
    +-      .appendTo(this);
    +-
    +-    $('<div>').addClass('card-info' + (!resource.summary ? ' empty-desc' : ''))
    +-      .append($('<div>').addClass('section').text(section))
    +-      .append($('<div>').addClass('title' + (resource.title_highlighted ? ' highlighted' : ''))
    +-        .html(resource.title_highlighted || resource.title))
    +-      .append(buildResourceCardDescription(resource, plusone))
    +-      .appendTo(this);
    +-
    +-    return this;
    +-  };
    +-
    +-  /* Simple jquery function to create dom for a resource section card (menu) */
    +-  $.fn.decorateResourceSection = function(section, plusone) {
    +-    var resource = section.resource;
    +-    //keep url clean for matching and offline mode handling
    +-    var urlPrefix = resource.image.indexOf("//") > -1 ? "" : toRoot;
    +-    var $base = $('<a>')
    +-        .addClass('card-bg')
    +-        .attr('href', resource.url)
    +-        .append($('<div>').addClass('card-section-icon')
    +-          .append($('<div>').addClass('icon'))
    +-          .append($('<div>').addClass('section').html(resource.title)))
    +-      .appendTo(this);
    +-
    +-    var $cardInfo = $('<div>').addClass('card-info').appendTo(this);
    +-
    +-    if (section.sections && section.sections.length) {
    +-      // Recurse the section sub-tree to find a resource image.
    +-      var stack = [section];
    +-
    +-      while (stack.length) {
    +-        if (stack[0].resource.image) {
    +-          $base.css('background-image', 'url(' + urlPrefix + stack[0].resource.image + ')');
    +-          break;
    +-        }
    +-
    +-        if (stack[0].sections) {
    +-          stack = stack.concat(stack[0].sections);
    +-        }
    +-
    +-        stack.shift();
    +-      }
    +-
    +-      var $ul = $('<ul>')
    +-        .appendTo($cardInfo);
    +-
    +-      var max = section.sections.length > 3 ? 3 : section.sections.length;
    +-
    +-      for (var i = 0; i < max; ++i) {
    +-
    +-        var subResource = section.sections[i];
    +-        if (!plusone) {
    +-          $('<li>')
    +-            .append($('<a>').attr('href', subResource.url)
    +-              .append($('<div>').addClass('title').html(subResource.title))
    +-              .append($('<div>').addClass('description ellipsis')
    +-                .append($('<div>').addClass('text').html(subResource.summary))
    +-                .append($('<div>').addClass('util'))))
    +-          .appendTo($ul);
    +-        } else {
    +-          $('<li>')
    +-            .append($('<a>').attr('href', subResource.url)
    +-              .append($('<div>').addClass('title').html(subResource.title))
    +-              .append($('<div>').addClass('description ellipsis')
    +-                .append($('<div>').addClass('text').html(subResource.summary))
    +-                .append($('<div>').addClass('util')
    +-                  .append($('<div>').addClass('g-plusone')
    +-                    .attr('data-size', 'small')
    +-                    .attr('data-align', 'right')
    +-                    .attr('data-href', resource.url)))))
    +-          .appendTo($ul);
    +-        }
    +-      }
    +-
    +-      // Add a more row
    +-      if (max < section.sections.length) {
    +-        $('<li>')
    +-          .append($('<a>').attr('href', resource.url)
    +-            .append($('<div>')
    +-              .addClass('title')
    +-              .text('More')))
    +-        .appendTo($ul);
    +-      }
    +-    } else {
    +-      // No sub-resources, just render description?
    +-    }
    +-
    +-    return this;
    +-  };
    +-
    +-  /* Render other types of resource styles that are not cards. */
    +-  $.fn.decorateResource = function(resource, opts) {
    +-    var imgUrl = resource.image ||
    +-      'assets/images/resource-card-default-android.jpg';
    +-    var linkUrl = resource.url;
    +-
    +-    if (imgUrl.indexOf('//') === -1) {
    +-      imgUrl = toRoot + imgUrl;
    +-    }
    +-
    +-    if (linkUrl && linkUrl.indexOf('//') === -1) {
    +-      linkUrl = toRoot + linkUrl;
    +-    }
    +-
    +-    $(this).append(
    +-      $('<div>').addClass('image')
    +-        .css('background-image', 'url(' + imgUrl + ')'),
    +-      $('<div>').addClass('info').append(
    +-        $('<h4>').addClass('title').html(resource.title_highlighted || resource.title),
    +-        $('<p>').addClass('summary').html(resource.summary),
    +-        $('<a>').attr('href', linkUrl).addClass('cta').html('Learn More')
    +-      )
    +-    );
    +-
    +-    return this;
    +-  };
    +-})(jQuery);
    +-
    +-/*
    +-  Fullscreen Carousel
    +-
    +-  The following allows for an area at the top of the page that takes over the
    +-  entire browser height except for its top offset and an optional bottom
    +-  padding specified as a data attribute.
    +-
    +-  HTML:
    +-
    +-  <div class="fullscreen-carousel">
    +-    <div class="fullscreen-carousel-content">
    +-      <!-- content here -->
    +-    </div>
    +-    <div class="fullscreen-carousel-content">
    +-      <!-- content here -->
    +-    </div>
    +-
    +-    etc ...
    +-
    +-  </div>
    +-
    +-  Control over how the carousel takes over the screen can mostly be defined in
    +-  a css file. Setting min-height on the .fullscreen-carousel-content elements
    +-  will prevent them from shrinking to far vertically when the browser is very
    +-  short, and setting max-height on the .fullscreen-carousel itself will prevent
    +-  the area from becoming to long in the case that the browser is stretched very
    +-  tall.
    +-
    +-  There is limited functionality for having multiple sections since that request
    +-  was removed, but it is possible to add .next-arrow and .prev-arrow elements to
    +-  scroll between multiple content areas.
    +-*/
    +-
    +-(function() {
    +-  $(document).ready(function() {
    +-    $('.fullscreen-carousel').each(function() {
    +-      initWidget(this);
    +-    });
    +-  });
    +-
    +-  function initWidget(widget) {
    +-    var $widget = $(widget);
    +-
    +-    var topOffset = $widget.offset().top;
    +-    var padBottom = parseInt($widget.data('paddingbottom')) || 0;
    +-    var maxHeight = 0;
    +-    var minHeight = 0;
    +-    var $content = $widget.find('.fullscreen-carousel-content');
    +-    var $nextArrow = $widget.find('.next-arrow');
    +-    var $prevArrow = $widget.find('.prev-arrow');
    +-    var $curSection = $($content[0]);
    +-
    +-    if ($content.length <= 1) {
    +-      $nextArrow.hide();
    +-      $prevArrow.hide();
    +-    } else {
    +-      $nextArrow.click(function() {
    +-        var index = ($content.index($curSection) + 1);
    +-        $curSection.hide();
    +-        $curSection = $($content[index >= $content.length ? 0 : index]);
    +-        $curSection.show();
    +-      });
    +-
    +-      $prevArrow.click(function() {
    +-        var index = ($content.index($curSection) - 1);
    +-        $curSection.hide();
    +-        $curSection = $($content[index < 0 ? $content.length - 1 : 0]);
    +-        $curSection.show();
    +-      });
    +-    }
    +-
    +-    // Just hide all content sections except first.
    +-    $content.each(function(index) {
    +-      if ($(this).height() > minHeight) minHeight = $(this).height();
    +-      $(this).css({position: 'absolute',  display: index > 0 ? 'none' : ''});
    +-    });
    +-
    +-    // Register for changes to window size, and trigger.
    +-    $(window).resize(resizeWidget);
    +-    resizeWidget();
    +-
    +-    function resizeWidget() {
    +-      var height = $(window).height() - topOffset - padBottom;
    +-      $widget.width($(window).width());
    +-      $widget.height(height < minHeight ? minHeight :
    +-        (maxHeight && height > maxHeight ? maxHeight : height));
    +-    }
    +-  }
    +-})();
    +-
    +-/*
    +-  Tab Carousel
    +-
    +-  The following allows tab widgets to be installed via the html below. Each
    +-  tab content section should have a data-tab attribute matching one of the
    +-  nav items'. Also each tab content section should have a width matching the
    +-  tab carousel.
    +-
    +-  HTML:
    +-
    +-  <div class="tab-carousel">
    +-    <ul class="tab-nav">
    +-      <li><a href="#" data-tab="handsets">Handsets</a>
    +-      <li><a href="#" data-tab="wearable">Wearable</a>
    +-      <li><a href="#" data-tab="tv">TV</a>
    +-    </ul>
    +-
    +-    <div class="tab-carousel-content">
    +-      <div data-tab="handsets">
    +-        <!--Full width content here-->
    +-      </div>
    +-
    +-      <div data-tab="wearable">
    +-        <!--Full width content here-->
    +-      </div>
    +-
    +-      <div data-tab="tv">
    +-        <!--Full width content here-->
    +-      </div>
    +-    </div>
    +-  </div>
    +-
    +-*/
    +-(function() {
    +-  $(document).ready(function() {
    +-    $('.tab-carousel').each(function() {
    +-      initWidget(this);
    +-    });
    +-  });
    +-
    +-  function initWidget(widget) {
    +-    var $widget = $(widget);
    +-    var $nav = $widget.find('.tab-nav');
    +-    var $anchors = $nav.find('[data-tab]');
    +-    var $li = $nav.find('li');
    +-    var $contentContainer = $widget.find('.tab-carousel-content');
    +-    var $tabs = $contentContainer.find('[data-tab]');
    +-    var $curTab = $($tabs[0]); // Current tab is first tab.
    +-    var width = $widget.width();
    +-
    +-    // Setup nav interactivity.
    +-    $anchors.click(function(evt) {
    +-      evt.preventDefault();
    +-      var query = '[data-tab=' + $(this).data('tab') + ']';
    +-      transitionWidget($tabs.filter(query));
    +-    });
    +-
    +-    // Add highlight for navigation on first item.
    +-    var $highlight = $('<div>').addClass('highlight')
    +-      .css({left:$li.position().left + 'px', width:$li.outerWidth() + 'px'})
    +-      .appendTo($nav);
    +-
    +-    // Store height since we will change contents to absolute.
    +-    $contentContainer.height($contentContainer.height());
    +-
    +-    // Absolutely position tabs so they're ready for transition.
    +-    $tabs.each(function(index) {
    +-      $(this).css({position: 'absolute', left: index > 0 ? width + 'px' : '0'});
    +-    });
    +-
    +-    function transitionWidget($toTab) {
    +-      if (!$curTab.is($toTab)) {
    +-        var curIndex = $tabs.index($curTab[0]);
    +-        var toIndex = $tabs.index($toTab[0]);
    +-        var dir = toIndex > curIndex ? 1 : -1;
    +-
    +-        // Animate content sections.
    +-        $toTab.css({left:(width * dir) + 'px'});
    +-        $curTab.animate({left:(width * -dir) + 'px'});
    +-        $toTab.animate({left:'0'});
    +-
    +-        // Animate navigation highlight.
    +-        $highlight.animate({left:$($li[toIndex]).position().left + 'px',
    +-          width:$($li[toIndex]).outerWidth() + 'px'})
    +-
    +-        // Store new current section.
    +-        $curTab = $toTab;
    +-      }
    +-    }
    +-  }
    +-})();
    +-
    +-/**
    +- * Auto TOC
    +- *
    +- * Upgrades h2s on the page to have a rule and be toggle-able on mobile.
    +- */
    +-(function($) {
    +-  var upgraded = false;
    +-  var h2Titles;
    +-
    +-  function initWidget() {
    +-    // add HRs below all H2s (except for a few other h2 variants)
    +-    // Consider doing this with css instead.
    +-    h2Titles = $('h2').not('#qv h2, #tb h2, .sidebox h2, #devdoc-nav h2, h2.norule');
    +-    h2Titles.css({paddingBottom:0}).after('<hr/>');
    +-
    +-    // Exit early if on older browser.
    +-    if (!window.matchMedia) {
    +-      return;
    +-    }
    +-
    +-    // Only run logic in mobile layout.
    +-    var query = window.matchMedia('(max-width: 719px)');
    +-    if (query.matches) {
    +-      makeTogglable();
    +-    } else {
    +-      query.addListener(makeTogglable);
    +-    }
    +-  }
    +-
    +-  function makeTogglable() {
    +-    // Only run this logic once.
    +-    if (upgraded) { return; }
    +-    upgraded = true;
    +-
    +-    // Only make content h2s togglable.
    +-    var contentTitles = h2Titles.filter('#jd-content *');
    +-
    +-    // If there are more than 1
    +-    if (contentTitles.size() < 2) {
    +-      return;
    +-    }
    +-
    +-    contentTitles.each(function() {
    +-      // Find all the relevant nodes.
    +-      var $title = $(this);
    +-      var $hr = $title.next();
    +-      var $contents = allNextUntil($hr[0], 'h2, .next-docs');
    +-      var $section = $($title)
    +-        .add($hr)
    +-        .add($title.prev('a[name]'))
    +-        .add($contents);
    +-      var $anchor = $section.first().prev();
    +-      var anchorMethod = 'after';
    +-      if ($anchor.length === 0) {
    +-        $anchor = $title.parent();
    +-        anchorMethod = 'prepend';
    +-      }
    +-
    +-      // Some h2s are in their own container making it pretty hard to find the end, so skip.
    +-      if ($contents.length === 0) {
    +-        return;
    +-      }
    +-
    +-      // Remove from DOM before messing with it. DOM is slow!
    +-      $section.detach();
    +-
    +-      // Add mobile-only expand arrows.
    +-      $title.prepend('<span class="dac-visible-mobile-inline-block">' +
    +-          '<i class="dac-toggle-expand dac-sprite dac-expand-more-black"></i>' +
    +-          '<i class="dac-toggle-collapse dac-sprite dac-expand-less-black"></i>' +
    +-          '</span>')
    +-        .attr('data-toggle', 'section');
    +-
    +-      // Wrap in magic markup.
    +-      $section = $section.wrapAll('<div class="dac-toggle dac-mobile">').parent();
    +-
    +-      // extra div used for max-height calculation.
    +-      $contents.wrapAll('<div class="dac-toggle-content dac-expand"><div>');
    +-
    +-      // Pre-expand section if requested.
    +-      if ($title.hasClass('is-expanded')) {
    +-        $section.addClass('is-expanded');
    +-      }
    +-
    +-      // Pre-expand section if targetted by hash.
    +-      if (location.hash && $section.find(location.hash).length) {
    +-        $section.addClass('is-expanded');
    +-      }
    +-
    +-      // Add it back to the dom.
    +-      $anchor[anchorMethod].call($anchor, $section);
    +-    });
    +-  }
    +-
    +-  // Similar to $.fn.nextUntil() except we need all nodes, jQuery skips text nodes.
    +-  function allNextUntil(elem, until) {
    +-    var matched = [];
    +-
    +-    while ((elem = elem.nextSibling) && elem.nodeType !== 9) {
    +-      if (elem.nodeType === 1 && jQuery(elem).is(until)) {
    +-        break;
    +-      }
    +-      matched.push(elem);
    +-    }
    +-    return $(matched);
    +-  }
    +-
    +-  $(function() {
    +-    initWidget();
    +-  });
    +-})(jQuery);
    +-
    +-(function($, window) {
    +-  'use strict';
    +-
    +-  // Blogger API info
    +-  var apiUrl = 'https://www.googleapis.com/blogger/v3';
    +-  var apiKey = 'AIzaSyCFhbGnjW06dYwvRCU8h_zjdpS4PYYbEe8';
    +-
    +-  // Blog IDs can be found in the markup of the blog posts
    +-  var blogs = {
    +-    'android-developers': {
    +-      id: '6755709643044947179',
    +-      title: 'Android Developers Blog'
    +-    }
    +-  };
    +-  var monthNames = ['January', 'February', 'March', 'April', 'May', 'June',
    +-      'July', 'August', 'September', 'October', 'November', 'December'];
    +-
    +-  var BlogReader = (function() {
    +-    var reader;
    +-
    +-    function BlogReader() {
    +-      this.doneSetup = false;
    +-    }
    +-
    +-    /**
    +-     * Initialize the blog reader and modal.
    +-     */
    +-    BlogReader.prototype.setup = function() {
    +-      $('#jd-content').append(
    +-          '<div id="blog-reader" data-modal="blog-reader" class="dac-modal dac-has-small-header">' +
    +-            '<div class="dac-modal-container">' +
    +-              '<div class="dac-modal-window">' +
    +-                '<header class="dac-modal-header">' +
    +-                  '<div class="dac-modal-header-actions">' +
    +-                    '<a href="" class="dac-modal-header-open" target="_blank">' +
    +-                      '<i class="dac-sprite dac-open-in-new"></i>' +
    +-                    '</a>' +
    +-                    '<button class="dac-modal-header-close" data-modal-toggle>' +
    +-                    '</button>' +
    +-                  '</div>' +
    +-                  '<h2 class="norule dac-modal-header-title"></h2>' +
    +-                '</header>' +
    +-                '<div class="dac-modal-content dac-blog-reader">' +
    +-                  '<time class="dac-blog-reader-date" pubDate></time>' +
    +-                  '<h3 class="dac-blog-reader-title"></h3>' +
    +-                  '<div class="dac-blog-reader-text clearfix"></div>' +
    +-                '</div>' +
    +-              '</div>' +
    +-            '</div>' +
    +-          '</div>');
    +-
    +-      this.blogReader = $('#blog-reader').dacModal();
    +-
    +-      this.doneSetup = true;
    +-    };
    +-
    +-    BlogReader.prototype.openModal_ = function(blog, post) {
    +-      var published = new Date(post.published);
    +-      var formattedDate = monthNames[published.getMonth()] + ' ' + published.getDate() + ' ' + published.getFullYear();
    +-      this.blogReader.find('.dac-modal-header-open').attr('href', post.url);
    +-      this.blogReader.find('.dac-modal-header-title').text(blog.title);
    +-      this.blogReader.find('.dac-blog-reader-title').html(post.title);
    +-      this.blogReader.find('.dac-blog-reader-date').html(formattedDate);
    +-      this.blogReader.find('.dac-blog-reader-text').html(post.content);
    +-      this.blogReader.trigger('modal-open');
    +-    };
    +-
    +-    /**
    +-     * Show a blog post in a modal
    +-     * @param  {string} blogName - The name of the Blogspot blog.
    +-     * @param  {string} postPath - The path to the blog post.
    +-     * @param  {bool} secondTry - Has it failed once?
    +-     */
    +-    BlogReader.prototype.showPost = function(blogName, postPath, secondTry) {
    +-      var blog = blogs[blogName];
    +-      var postUrl = 'https://' + blogName + '.blogspot.com' + postPath;
    +-
    +-      var url = apiUrl + '/blogs/' + blog.id + '/posts/bypath?path=' + encodeURIComponent(postPath) + '&key=' + apiKey;
    +-      $.ajax(url, {timeout: 650}).done(this.openModal_.bind(this, blog)).fail(function(error) {
    +-        // Retry once if we get an error
    +-        if (error.status === 500 && !secondTry) {
    +-          this.showPost(blogName, postPath, true);
    +-        } else {
    +-          window.location.href = postUrl;
    +-        }
    +-      }.bind(this));
    +-    };
    +-
    +-    return {
    +-      getReader: function() {
    +-        if (!reader) {
    +-          reader = new BlogReader();
    +-        }
    +-        return reader;
    +-      }
    +-    };
    +-  })();
    +-
    +-  var blogReader = BlogReader.getReader();
    +-
    +-  function wrapLinkWithReader(e) {
    +-    var el = $(e.currentTarget);
    +-    if (el.hasClass('dac-modal-header-open')) {
    +-      return;
    +-    }
    +-
    +-    // Only catch links on blogspot.com
    +-    var matches = el.attr('href').match(/https?:\/\/([^\.]*).blogspot.com([^$]*)/);
    +-    if (matches && matches.length === 3) {
    +-      var blogName = matches[1];
    +-      var postPath = matches[2];
    +-
    +-      // Check if we have information about the blog
    +-      if (!blogs[blogName]) {
    +-        return;
    +-      }
    +-
    +-      // Setup the first time it's used
    +-      if (!blogReader.doneSetup) {
    +-        blogReader.setup();
    +-      }
    +-
    +-      e.preventDefault();
    +-      blogReader.showPost(blogName, postPath);
    +-    }
    +-  }
    +-
    +-  $(document).on('click.blog-reader', 'a.resource-card[href*="blogspot.com/"]',
    +-      wrapLinkWithReader);
    +-})(jQuery, window);
    +-
    +-(function($) {
    +-  $.fn.debounce = function(func, wait, immediate) {
    +-    var timeout;
    +-
    +-    return function() {
    +-      var context = this;
    +-      var args = arguments;
    +-
    +-      var later = function() {
    +-        timeout = null;
    +-        if (!immediate) {
    +-          func.apply(context, args);
    +-        }
    +-      };
    +-
    +-      var callNow = immediate && !timeout;
    +-      clearTimeout(timeout);
    +-      timeout = setTimeout(later, wait);
    +-
    +-      if (callNow) {
    +-        func.apply(context, args);
    +-      }
    +-    };
    +-  };
    +-})(jQuery);
    +-
    +-/* Calculate the vertical area remaining */
    +-(function($) {
    +-  $.fn.ellipsisfade = function() {
    +-    // Only fetch line-height of first element to avoid recalculate style.
    +-    // Will be NaN if no elements match, which is ok.
    +-    var lineHeight = parseInt(this.css('line-height'), 10);
    +-
    +-    this.each(function() {
    +-      // get element text
    +-      var $this = $(this);
    +-      var remainingHeight = $this.parent().parent().height();
    +-      $this.parent().siblings().each(function() {
    +-        var elHeight;
    +-        if ($(this).is(':visible')) {
    +-          elHeight = $(this).outerHeight(true);
    +-          remainingHeight = remainingHeight - elHeight;
    +-        }
    +-      });
    +-
    +-      var adjustedRemainingHeight = ((remainingHeight) / lineHeight >> 0) * lineHeight;
    +-      $this.parent().css({height: adjustedRemainingHeight});
    +-      $this.css({height: 'auto'});
    +-    });
    +-
    +-    return this;
    +-  };
    +-
    +-  /* Pass the line height to ellipsisfade() to adjust the height of the
    +-   text container to show the max number of lines possible, without
    +-   showing lines that are cut off. This works with the css ellipsis
    +-   classes to fade last text line and apply an ellipsis char. */
    +-  function updateEllipsis(context) {
    +-    if (!(context instanceof jQuery)) {
    +-      context = $('html');
    +-    }
    +-
    +-    context.find('.card-info .text').ellipsisfade();
    +-  }
    +-
    +-  $(window).on('resize', $.fn.debounce(updateEllipsis, 500));
    +-  $(updateEllipsis);
    +-  $('html').on('dac:domchange', function(e) { updateEllipsis($(e.target)); });
    +-})(jQuery);
    +-
    +-/* Filter */
    +-(function($) {
    +-  'use strict';
    +-
    +-  /**
    +-   * A single filter item content.
    +-   * @type {string} - Element template.
    +-   * @private
    +-   */
    +-  var ITEM_STR_ = '<input type="checkbox" value="{{value}}" class="dac-form-checkbox" id="{{id}}">' +
    +-      '<label for="{{id}}" class="dac-form-checkbox-button"></label>' +
    +-      '<label for="{{id}}" class="dac-form-label">{{name}}</label>';
    +-
    +-  /**
    +-   * Template for a chip element.
    +-   * @type {*|HTMLElement}
    +-   * @private
    +-   */
    +-  var CHIP_BASE_ = $('<li class="dac-filter-chip">' +
    +-    '<button class="dac-filter-chip-close">' +
    +-      '<i class="dac-sprite dac-close-black dac-filter-chip-close-icon"></i>' +
    +-    '</button>' +
    +-  '</li>');
    +-
    +-  /**
    +-   * Component to handle narrowing down resources.
    +-   * @param {HTMLElement} el - The DOM element.
    +-   * @param {Object} options
    +-   * @constructor
    +-   */
    +-  function Filter(el, options) {
    +-    this.el = $(el);
    +-    this.options = $.extend({}, Filter.DEFAULTS_, options);
    +-    this.init();
    +-  }
    +-
    +-  Filter.DEFAULTS_ = {
    +-    activeClass: 'dac-active',
    +-    chipsDataAttr: 'filter-chips',
    +-    nameDataAttr: 'filter-name',
    +-    countDataAttr: 'filter-count',
    +-    tabViewDataAttr: 'tab-view',
    +-    valueDataAttr: 'filter-value'
    +-  };
    +-
    +-  /**
    +-   * Draw resource cards.
    +-   * @param {Array} resources
    +-   * @private
    +-   */
    +-  Filter.prototype.draw_ = function(resources) {
    +-    var that = this;
    +-
    +-    if (resources.length === 0) {
    +-      this.containerEl_.html('<p class="dac-filter-message">Nothing matches selected filters.</p>');
    +-      return;
    +-    }
    +-
    +-    // Draw resources.
    +-    that.containerEl_.resourceWidget(resources, that.data_.options);
    +-  };
    +-
    +-  /**
    +-   * Initialize a Filter component.
    +-   */
    +-  Filter.prototype.init = function() {
    +-    this.containerEl_ = $(this.options.filter);
    +-
    +-    // Setup data settings
    +-    this.data_ = {};
    +-    this.data_.chips = {};
    +-    this.data_.options = this.containerEl_.widgetOptions();
    +-    this.data_.all = window.metadata.query(this.data_.options);
    +-
    +-    // Initialize filter UI
    +-    this.initUi();
    +-  };
    +-
    +-  /**
    +-   * Generate a chip for a given filter item.
    +-   * @param {Object} item - A single filter option (checkbox container).
    +-   * @returns {HTMLElement} A new Chip element.
    +-   */
    +-  Filter.prototype.chipForItem = function(item) {
    +-    var chip = CHIP_BASE_.clone();
    +-    chip.prepend(this.data_.chips[item.data('filter-value')]);
    +-    chip.data('item.dac-filter', item);
    +-    item.data('chip.dac-filter', chip);
    +-    this.addToItemValue(item, 1);
    +-    return chip[0];
    +-  };
    +-
    +-  /**
    +-   * Update count of checked filter items.
    +-   * @param {Object} item - A single filter option (checkbox container).
    +-   * @param {Number} value - Either -1 or 1.
    +-   */
    +-  Filter.prototype.addToItemValue = function(item, value) {
    +-    var tab = item.parent().data(this.options.tabViewDataAttr);
    +-    var countEl = this.countEl_.filter('[data-' + this.options.countDataAttr + '="' + tab + '"]');
    +-    var count = value + parseInt(countEl.text(), 10);
    +-    countEl.text(count);
    +-    countEl.toggleClass('dac-disabled', count === 0);
    +-  };
    +-
    +-  /**
    +-   * Set event listeners.
    +-   * @private
    +-   */
    +-  Filter.prototype.setEventListeners_ = function() {
    +-    this.chipsEl_.on('click.dac-filter', '.dac-filter-chip-close', this.closeChipHandler_.bind(this));
    +-    this.tabViewEl_.on('change.dac-filter', ':checkbox', this.toggleCheckboxHandler_.bind(this));
    +-  };
    +-
    +-  /**
    +-   * Check filter items that are active by default.
    +-   */
    +-  Filter.prototype.activateInitialFilters_ = function() {
    +-    var id = (new Date()).getTime();
    +-    var initiallyCheckedValues = this.data_.options.query.replace(/,\s*/g, '+').split('+');
    +-    var chips = document.createDocumentFragment();
    +-    var that = this;
    +-
    +-    this.items_.each(function(i) {
    +-      var item = $(this);
    +-      var opts = item.data();
    +-      that.data_.chips[opts.filterValue] = opts.filterName;
    +-
    +-      var checkbox = $(ITEM_STR_.replace(/\{\{name\}\}/g, opts.filterName)
    +-        .replace(/\{\{value\}\}/g, opts.filterValue)
    +-        .replace(/\{\{id\}\}/g, 'filter-' + id + '-' + (i + 1)));
    +-
    +-      if (initiallyCheckedValues.indexOf(opts.filterValue) > -1) {
    +-        checkbox[0].checked = true;
    +-        chips.appendChild(that.chipForItem(item));
    +-      }
    +-
    +-      item.append(checkbox);
    +-    });
    +-
    +-    this.chipsEl_.append(chips);
    +-  };
    +-
    +-  /**
    +-   * Initialize the Filter view
    +-   */
    +-  Filter.prototype.initUi = function() {
    +-    // Cache DOM elements
    +-    this.chipsEl_ = this.el.find('[data-' + this.options.chipsDataAttr + ']');
    +-    this.countEl_ = this.el.find('[data-' + this.options.countDataAttr + ']');
    +-    this.tabViewEl_ = this.el.find('[data-' + this.options.tabViewDataAttr + ']');
    +-    this.items_ = this.el.find('[data-' + this.options.nameDataAttr + ']');
    +-
    +-    // Setup UI
    +-    this.draw_(this.data_.all);
    +-    this.activateInitialFilters_();
    +-    this.setEventListeners_();
    +-  };
    +-
    +-  /**
    +-   * @returns {[types|Array, tags|Array, category|Array]}
    +-   */
    +-  Filter.prototype.getActiveClauses = function() {
    +-    var tags = [];
    +-    var types = [];
    +-    var categories = [];
    +-
    +-    this.items_.find(':checked').each(function(i, checkbox) {
    +-      // Currently, there is implicit business logic here that `tag` is AND'ed together
    +-      // while `type` is OR'ed. So , and + do the same thing here. It would be great to
    +-      // reuse the same query engine for filters, but it would need more powerful syntax.
    +-      // Probably parenthesis, to support "tag:dog + tag:cat + (type:video, type:blog)"
    +-      var expression = $(checkbox).val();
    +-      var regex = /(\w+):(\w+)/g;
    +-      var match;
    +-
    +-      while (match = regex.exec(expression)) {
    +-        switch (match[1]) {
    +-          case 'category':
    +-            categories.push(match[2]);
    +-            break;
    +-          case 'tag':
    +-            tags.push(match[2]);
    +-            break;
    +-          case 'type':
    +-            types.push(match[2]);
    +-            break;
    +-        }
    +-      }
    +-    });
    +-
    +-    return [types, tags, categories];
    +-  };
    +-
    +-  /**
    +-   * Actual filtering logic.
    +-   * @returns {Array}
    +-   */
    +-  Filter.prototype.filteredResources = function() {
    +-    var data = this.getActiveClauses();
    +-    var types = data[0];
    +-    var tags = data[1];
    +-    var categories = data[2];
    +-    var resources = [];
    +-    var resource = {};
    +-    var tag = '';
    +-    var shouldAddResource = true;
    +-
    +-    for (var resourceIndex = 0; resourceIndex < this.data_.all.length; resourceIndex++) {
    +-      resource = this.data_.all[resourceIndex];
    +-      shouldAddResource = types.indexOf(resource.type) > -1;
    +-
    +-      if (categories && categories.length > 0) {
    +-        shouldAddResource = shouldAddResource && categories.indexOf(resource.category) > -1;
    +-      }
    +-
    +-      for (var tagIndex = 0; shouldAddResource && tagIndex < tags.length; tagIndex++) {
    +-        tag = tags[tagIndex];
    +-        shouldAddResource = resource.tags.indexOf(tag) > -1;
    +-      }
    +-
    +-      if (shouldAddResource) {
    +-        resources.push(resource);
    +-      }
    +-    }
    +-
    +-    return resources;
    +-  };
    +-
    +-  /**
    +-   * Close Chip Handler
    +-   * @param {Event} event - Click event
    +-   * @private
    +-   */
    +-  Filter.prototype.closeChipHandler_ = function(event) {
    +-    var chip = $(event.currentTarget).parent();
    +-    var checkbox = chip.data('item.dac-filter').find(':first-child')[0];
    +-    checkbox.checked = false;
    +-    this.changeStateForCheckbox(checkbox);
    +-  };
    +-
    +-  /**
    +-   * Handle filter item state change.
    +-   * @param {Event} event - Change event
    +-   * @private
    +-   */
    +-  Filter.prototype.toggleCheckboxHandler_ = function(event) {
    +-    this.changeStateForCheckbox(event.currentTarget);
    +-  };
    +-
    +-  /**
    +-   * Redraw resource view based on new state.
    +-   * @param checkbox
    +-   */
    +-  Filter.prototype.changeStateForCheckbox = function(checkbox) {
    +-    var item = $(checkbox).parent();
    +-
    +-    if (checkbox.checked) {
    +-      this.chipsEl_.append(this.chipForItem(item));
    +-      devsite.analytics.trackAnalyticsEvent('event',
    +-          'Filters', 'Check', $(checkbox).val());
    +-    } else {
    +-      item.data('chip.dac-filter').remove();
    +-      this.addToItemValue(item, -1);
    +-      devsite.analytics.trackAnalyticsEvent('event',
    +-          'Filters', 'Uncheck', $(checkbox).val());
    +-    }
    +-
    +-    this.draw_(this.filteredResources());
    +-  };
    +-
    +-  /**
    +-   * jQuery plugin
    +-   */
    +-  $.fn.dacFilter = function() {
    +-    return this.each(function() {
    +-      var el = $(this);
    +-      new Filter(el, el.data());
    +-    });
    +-  };
    +-
    +-  /**
    +-   * Data Attribute API
    +-   */
    +-  $(function() {
    +-    $('[data-filter]').dacFilter();
    +-  });
    +-})(jQuery);
    +-
    +-(function($) {
    +-  'use strict';
    +-
    +-  /**
    +-   * Toggle Floating Label state.
    +-   * @param {HTMLElement} el - The DOM element.
    +-   * @param options
    +-   * @constructor
    +-   */
    +-  function FloatingLabel(el, options) {
    +-    this.el = $(el);
    +-    this.options = $.extend({}, FloatingLabel.DEFAULTS_, options);
    +-    this.group = this.el.closest('.dac-form-input-group');
    +-    this.input = this.group.find('.dac-form-input');
    +-
    +-    this.checkValue_ = this.checkValue_.bind(this);
    +-    this.checkValue_();
    +-
    +-    this.input.on('focus', function() {
    +-      this.group.addClass('dac-focused');
    +-    }.bind(this));
    +-    this.input.on('blur', function() {
    +-      this.group.removeClass('dac-focused');
    +-      this.checkValue_();
    +-    }.bind(this));
    +-    this.input.on('keyup', this.checkValue_);
    +-  }
    +-
    +-  /**
    +-   * The label is moved out of the textbox when it has a value.
    +-   */
    +-  FloatingLabel.prototype.checkValue_ = function() {
    +-    if (this.input.val().length) {
    +-      this.group.addClass('dac-has-value');
    +-    } else {
    +-      this.group.removeClass('dac-has-value');
    +-    }
    +-  };
    +-
    +-  /**
    +-   * jQuery plugin
    +-   * @param  {object} options - Override default options.
    +-   */
    +-  $.fn.dacFloatingLabel = function(options) {
    +-    return this.each(function() {
    +-      new FloatingLabel(this, options);
    +-    });
    +-  };
    +-
    +-  $(document).on('ready.aranja', function() {
    +-    $('.dac-form-floatlabel').each(function() {
    +-      $(this).dacFloatingLabel($(this).data());
    +-    });
    +-  });
    +-})(jQuery);
    +-
    +-(function($) {
    +-  'use strict';
    +-
    +-  /**
    +-   * @param {HTMLElement} el - The DOM element.
    +-   * @param {Object} options
    +-   * @constructor
    +-   */
    +-  function Crumbs(selected, options) {
    +-    this.options = $.extend({}, Crumbs.DEFAULTS_, options);
    +-    this.el = $(this.options.container);
    +-
    +-    // Do not build breadcrumbs for landing site.
    +-    if (!selected || location.pathname === '/index.html' || location.pathname === '/') {
    +-      return;
    +-    }
    +-
    +-    // Cache navigation resources
    +-    this.selected = $(selected);
    +-    this.selectedParent = this.selected.closest('.dac-nav-secondary').siblings('a');
    +-
    +-    // Build the breadcrumb list.
    +-    this.init();
    +-  }
    +-
    +-  Crumbs.DEFAULTS_ = {
    +-    container: '.dac-header-crumbs',
    +-    crumbItem: $('<li class="dac-header-crumbs-item">'),
    +-    linkClass: 'dac-header-crumbs-link'
    +-  };
    +-
    +-  Crumbs.prototype.init = function() {
    +-    Crumbs.buildCrumbForLink(this.selected.clone()).appendTo(this.el);
    +-
    +-    if (this.selectedParent.length) {
    +-      Crumbs.buildCrumbForLink(this.selectedParent.clone()).prependTo(this.el);
    +-    }
    +-
    +-    // Reveal the breadcrumbs
    +-    this.el.addClass('dac-has-content');
    +-  };
    +-
    +-  /**
    +-   * Build a HTML structure for a breadcrumb.
    +-   * @param {string} link
    +-   * @return {jQuery}
    +-   */
    +-  Crumbs.buildCrumbForLink = function(link) {
    +-    link.find('br').replaceWith(' ');
    +-
    +-    var crumbLink = $('<a>')
    +-      .attr('class', Crumbs.DEFAULTS_.linkClass)
    +-      .attr('href', link.attr('href'))
    +-      .text(link.text());
    +-
    +-    return Crumbs.DEFAULTS_.crumbItem.clone().append(crumbLink);
    +-  };
    +-
    +-  /**
    +-   * jQuery plugin
    +-   */
    +-  $.fn.dacCrumbs = function(options) {
    +-    return this.each(function() {
    +-      new Crumbs(this, options);
    +-    });
    +-  };
    +-})(jQuery);
    +-
    +-(function($) {
    +-  'use strict';
    +-
    +-  /**
    +-   * @param {HTMLElement} el - The DOM element.
    +-   * @param {Object} options
    +-   * @constructor
    +-   */
    +-  function SearchInput(el, options) {
    +-    this.el = $(el);
    +-    this.options = $.extend({}, SearchInput.DEFAULTS_, options);
    +-    this.body = $('body');
    +-    this.input = this.el.find('input');
    +-    this.close = this.el.find(this.options.closeButton);
    +-    this.clear = this.el.find(this.options.clearButton);
    +-    this.icon = this.el.find('.' + this.options.iconClass);
    +-    this.init();
    +-  }
    +-
    +-  SearchInput.DEFAULTS_ = {
    +-    activeClass: 'dac-active',
    +-    activeIconClass: 'dac-search',
    +-    closeButton: '[data-search-close]',
    +-    clearButton: '[data-search-clear]',
    +-    hiddenClass: 'dac-hidden',
    +-    iconClass: 'dac-header-search-icon',
    +-    searchModeClass: 'dac-search-mode',
    +-    transitionDuration: 250
    +-  };
    +-
    +-  SearchInput.prototype.init = function() {
    +-    this.input.on('focus.dac-search', this.setActiveState.bind(this))
    +-              .on('input.dac-search', this.checkInputValue.bind(this));
    +-    this.close.on('click.dac-search', this.unsetActiveStateHandler_.bind(this));
    +-    this.clear.on('click.dac-search', this.clearInput.bind(this));
    +-  };
    +-
    +-  SearchInput.prototype.setActiveState = function() {
    +-    var that = this;
    +-
    +-    this.clear.addClass(this.options.hiddenClass);
    +-    this.body.addClass(this.options.searchModeClass);
    +-    this.checkInputValue();
    +-
    +-    // Set icon to black after background has faded to white.
    +-    setTimeout(function() {
    +-      that.icon.addClass(that.options.activeIconClass);
    +-    }, this.options.transitionDuration);
    +-  };
    +-
    +-  SearchInput.prototype.unsetActiveStateHandler_ = function(event) {
    +-    event.preventDefault();
    +-    this.unsetActiveState();
    +-  };
    +-
    +-  SearchInput.prototype.unsetActiveState = function() {
    +-    this.icon.removeClass(this.options.activeIconClass);
    +-    this.clear.addClass(this.options.hiddenClass);
    +-    this.body.removeClass(this.options.searchModeClass);
    +-  };
    +-
    +-  SearchInput.prototype.clearInput = function(event) {
    +-    event.preventDefault();
    +-    this.input.val('');
    +-    this.clear.addClass(this.options.hiddenClass);
    +-  };
    +-
    +-  SearchInput.prototype.checkInputValue = function() {
    +-    if (this.input.val().length) {
    +-      this.clear.removeClass(this.options.hiddenClass);
    +-    } else {
    +-      this.clear.addClass(this.options.hiddenClass);
    +-    }
    +-  };
    +-
    +-  /**
    +-   * jQuery plugin
    +-   * @param {object} options - Override default options.
    +-   */
    +-  $.fn.dacSearchInput = function() {
    +-    return this.each(function() {
    +-      var el = $(this);
    +-      el.data('search-input.dac', new SearchInput(el, el.data()));
    +-    });
    +-  };
    +-
    +-  /**
    +-   * Data Attribute API
    +-   */
    +-  $(function() {
    +-    $('[data-search]').dacSearchInput();
    +-  });
    +-})(jQuery);
    +-
    +-/* global METADATA */
    +-(function($) {
    +-  function DacCarouselQuery(el) {
    +-    el = $(el);
    +-
    +-    var opts = el.data();
    +-    opts.maxResults = parseInt(opts.maxResults || '100', 10);
    +-    opts.query = opts.carouselQuery;
    +-    var resources = window.metadata.query(opts);
    +-
    +-    el.empty();
    +-    $(resources).each(function() {
    +-      var resource = $.extend({}, this, METADATA.carousel[this.url]);
    +-      el.dacHero(resource);
    +-    });
    +-
    +-    // Pagination element.
    +-    el.append('<div class="dac-hero-carousel-pagination"><div class="wrap" data-carousel-pagination>');
    +-
    +-    el.dacCarousel();
    +-  }
    +-
    +-  // jQuery plugin
    +-  $.fn.dacCarouselQuery = function() {
    +-    return this.each(function() {
    +-      var el = $(this);
    +-      var data = el.data('dac.carouselQuery');
    +-
    +-      if (!data) { el.data('dac.carouselQuery', (data = new DacCarouselQuery(el))); }
    +-    });
    +-  };
    +-
    +-  // Data API
    +-  $(function() {
    +-    $('[data-carousel-query]').dacCarouselQuery();
    +-  });
    +-})(jQuery);
    +-
    +-(function($) {
    +-  /**
    +-   * A CSS based carousel, inspired by SequenceJS.
    +-   * @param {jQuery} el
    +-   * @param {object} options
    +-   * @constructor
    +-   */
    +-  function DacCarousel(el, options) {
    +-    this.el = $(el);
    +-    this.options = options = $.extend({}, DacCarousel.OPTIONS, this.el.data(), options || {});
    +-    this.frames = this.el.find(options.frameSelector);
    +-    this.count = this.frames.size();
    +-    this.current = options.start;
    +-
    +-    this.initPagination();
    +-    this.initEvents();
    +-    this.initFrame();
    +-  }
    +-
    +-  DacCarousel.OPTIONS = {
    +-    auto:      true,
    +-    autoTime:  10000,
    +-    autoMinTime: 5000,
    +-    btnPrev:   '[data-carousel-prev]',
    +-    btnNext:   '[data-carousel-next]',
    +-    frameSelector: 'article',
    +-    loop:      true,
    +-    start:     0,
    +-    swipeThreshold: 160,
    +-    pagination: '[data-carousel-pagination]'
    +-  };
    +-
    +-  DacCarousel.prototype.initPagination = function() {
    +-    this.pagination = $([]);
    +-    if (!this.options.pagination) { return; }
    +-
    +-    var pagination = $('<ul class="dac-pagination">');
    +-    var parent = this.el;
    +-    if (typeof this.options.pagination === 'string') { parent = this.el.find(this.options.pagination); }
    +-
    +-    if (this.count > 1) {
    +-      for (var i = 0; i < this.count; i++) {
    +-        var li = $('<li class="dac-pagination-item">').text(i);
    +-        if (i === this.options.start) { li.addClass('active'); }
    +-        li.click(this.go.bind(this, i));
    +-
    +-        pagination.append(li);
    +-      }
    +-      this.pagination = pagination.children();
    +-      parent.append(pagination);
    +-    }
    +-  };
    +-
    +-  DacCarousel.prototype.initEvents = function() {
    +-    var that = this;
    +-
    +-    this.touch = {
    +-      start: {x: 0, y: 0},
    +-      end:   {x: 0, y: 0}
    +-    };
    +-
    +-    this.el.on('touchstart', this.touchstart_.bind(this));
    +-    this.el.on('touchend', this.touchend_.bind(this));
    +-    this.el.on('touchmove', this.touchmove_.bind(this));
    +-
    +-    this.el.hover(function() {
    +-      that.pauseRotateTimer();
    +-    }, function() {
    +-      that.startRotateTimer();
    +-    });
    +-
    +-    $(this.options.btnPrev).click(function(e) {
    +-      e.preventDefault();
    +-      that.prev();
    +-    });
    +-
    +-    $(this.options.btnNext).click(function(e) {
    +-      e.preventDefault();
    +-      that.next();
    +-    });
    +-  };
    +-
    +-  DacCarousel.prototype.touchstart_ = function(event) {
    +-    var t = event.originalEvent.touches[0];
    +-    this.touch.start = {x: t.screenX, y: t.screenY};
    +-  };
    +-
    +-  DacCarousel.prototype.touchend_ = function() {
    +-    var deltaX = this.touch.end.x - this.touch.start.x;
    +-    var deltaY = Math.abs(this.touch.end.y - this.touch.start.y);
    +-    var shouldSwipe = (deltaY < Math.abs(deltaX)) && (Math.abs(deltaX) >= this.options.swipeThreshold);
    +-
    +-    if (shouldSwipe) {
    +-      if (deltaX > 0) {
    +-        this.prev();
    +-      } else {
    +-        this.next();
    +-      }
    +-    }
    +-  };
    +-
    +-  DacCarousel.prototype.touchmove_ = function(event) {
    +-    var t = event.originalEvent.touches[0];
    +-    this.touch.end = {x: t.screenX, y: t.screenY};
    +-  };
    +-
    +-  DacCarousel.prototype.initFrame = function() {
    +-    this.frames.removeClass('active').eq(this.options.start).addClass('active');
    +-  };
    +-
    +-  DacCarousel.prototype.startRotateTimer = function() {
    +-    if (!this.options.auto || this.rotateTimer) { return; }
    +-    this.rotateTimer = setTimeout(this.next.bind(this), this.options.autoTime);
    +-  };
    +-
    +-  DacCarousel.prototype.pauseRotateTimer = function() {
    +-    clearTimeout(this.rotateTimer);
    +-    this.rotateTimer = null;
    +-  };
    +-
    +-  DacCarousel.prototype.prev = function() {
    +-    this.go(this.current - 1);
    +-  };
    +-
    +-  DacCarousel.prototype.next = function() {
    +-    this.go(this.current + 1);
    +-  };
    +-
    +-  DacCarousel.prototype.go = function(next) {
    +-    // Figure out what the next slide is.
    +-    while (this.count > 0 && next >= this.count) { next -= this.count; }
    +-    while (next < 0) { next += this.count; }
    +-
    +-    // Cancel if we're already on that slide.
    +-    if (next === this.current) { return; }
    +-
    +-    // Prepare next slide.
    +-    this.frames.eq(next).removeClass('out');
    +-
    +-    // Recalculate styles before starting slide transition.
    +-    this.el.resolveStyles();
    +-    // Update pagination
    +-    this.pagination.removeClass('active').eq(next).addClass('active');
    +-
    +-    // Transition out current frame
    +-    this.frames.eq(this.current).toggleClass('active out');
    +-
    +-    // Transition in a new frame
    +-    this.frames.eq(next).toggleClass('active');
    +-
    +-    this.current = next;
    +-  };
    +-
    +-  // Helper which resolves new styles for an element, so it can start transitioning
    +-  // from the new values.
    +-  $.fn.resolveStyles = function() {
    +-    /*jshint expr:true*/
    +-    this[0] && this[0].offsetTop;
    +-    return this;
    +-  };
    +-
    +-  // jQuery plugin
    +-  $.fn.dacCarousel = function() {
    +-    this.each(function() {
    +-      var $el = $(this);
    +-      $el.data('dac-carousel', new DacCarousel(this));
    +-    });
    +-    return this;
    +-  };
    +-
    +-  // Data API
    +-  $(function() {
    +-    $('[data-carousel]').dacCarousel();
    +-  });
    +-})(jQuery);
    +-
    +-/* global toRoot */
    +-
    +-(function($) {
    +-  // Ordering matters
    +-  var TAG_MAP = [
    +-    {from: 'developerstory', to: 'Android Developer Story'},
    +-    {from: 'googleplay', to: 'Google Play'}
    +-  ];
    +-
    +-  function DacHero(el, resource, isSearch) {
    +-    var slide = $('<article>');
    +-    slide.addClass(isSearch ? 'dac-search-hero' : 'dac-expand dac-hero');
    +-    var image = cleanUrl(resource.heroImage || resource.image);
    +-    var fullBleed = image && !resource.heroColor;
    +-
    +-    if (!isSearch) {
    +-      // Configure background
    +-      slide.css({
    +-        backgroundImage: fullBleed ? 'url(' + image + ')' : '',
    +-        backgroundColor: resource.heroColor || ''
    +-      });
    +-
    +-      // Should copy be inverted
    +-      slide.toggleClass('dac-invert', resource.heroInvert || fullBleed);
    +-      slide.toggleClass('dac-darken', fullBleed);
    +-
    +-      // Should be clickable
    +-      slide.append($('<a class="dac-hero-carousel-action">').attr('href', cleanUrl(resource.url)));
    +-    }
    +-
    +-    var cols = $('<div class="cols dac-hero-content">');
    +-
    +-    // inline image column
    +-    var rightCol = $('<div class="col-1of2 col-push-1of2 dac-hero-figure">')
    +-      .appendTo(cols);
    +-
    +-    if ((!fullBleed || isSearch) && image) {
    +-      rightCol.append($('<img>').attr('src', image));
    +-    }
    +-
    +-    // info column
    +-    $('<div class="col-1of2 col-pull-1of2">')
    +-      .append($('<div class="dac-hero-tag">').text(formatTag(resource)))
    +-      .append($('<h1 class="dac-hero-title">').text(formatTitle(resource)))
    +-      .append($('<p class="dac-hero-description">').text(resource.summary))
    +-      .append($('<a class="dac-hero-cta">')
    +-        .text(formatCTA(resource))
    +-        .attr('href', cleanUrl(resource.url))
    +-        .prepend($('<span class="dac-sprite dac-auto-chevron">'))
    +-      )
    +-      .appendTo(cols);
    +-
    +-    slide.append(cols.wrap('<div class="wrap">').parent());
    +-    el.append(slide);
    +-  }
    +-
    +-  function cleanUrl(url) {
    +-    if (url && url.indexOf('//') === -1) {
    +-      url = toRoot + url;
    +-    }
    +-    return url;
    +-  }
    +-
    +-  function formatTag(resource) {
    +-    // Hmm, need a better more scalable solution for this.
    +-    for (var i = 0, mapping; mapping = TAG_MAP[i]; i++) {
    +-      if (resource.tags.indexOf(mapping.from) > -1) {
    +-        return mapping.to;
    +-      }
    +-    }
    +-    return resource.type;
    +-  }
    +-
    +-  function formatTitle(resource) {
    +-    return resource.title.replace(/android developer story: /i, '');
    +-  }
    +-
    +-  function formatCTA(resource) {
    +-    return resource.type === 'youtube' ? 'Watch the video' : 'Learn more';
    +-  }
    +-
    +-  // jQuery plugin
    +-  $.fn.dacHero = function(resource, isSearch) {
    +-    return this.each(function() {
    +-      var el = $(this);
    +-      return new DacHero(el, resource, isSearch);
    +-    });
    +-  };
    +-})(jQuery);
    +-
    +-(function($) {
    +-  'use strict';
    +-
    +-  function highlightString(label, query) {
    +-    query = query || '';
    +-    //query = query.replace('<wbr>', '').replace('.', '\\.');
    +-    var queryRE = new RegExp('(' + query + ')', 'ig');
    +-    return label.replace(queryRE, '<em>$1</em>');
    +-  }
    +-
    +-  $.fn.highlightMatches = function(query) {
    +-    return this.each(function() {
    +-      var el = $(this);
    +-      var label = el.html();
    +-      var highlighted = highlightString(label, query);
    +-      el.html(highlighted);
    +-      el.addClass('highlighted');
    +-    });
    +-  };
    +-})(jQuery);
    +-
    +-/**
    +- * History tracking.
    +- * Track visited urls in localStorage.
    +- */
    +-(function($) {
    +-  var PAGES_TO_STORE_ = 100;
    +-  var MIN_NUMBER_OF_PAGES_TO_DISPLAY_ = 6;
    +-  var CONTAINER_SELECTOR_ = '.dac-search-results-history-wrap';
    +-
    +-  /**
    +-   * Generate resource cards for visited pages.
    +-   * @param {HTMLElement} el
    +-   * @constructor
    +-   */
    +-  function HistoryQuery(el) {
    +-    this.el = $(el);
    +-
    +-    // Only show history component if enough pages have been visited.
    +-    if (getVisitedPages().length < MIN_NUMBER_OF_PAGES_TO_DISPLAY_) {
    +-      this.el.closest(CONTAINER_SELECTOR_).addClass('dac-hidden');
    +-      return;
    +-    }
    +-
    +-    // Rename query
    +-    this.el.data('query', this.el.data('history-query'));
    +-
    +-    // jQuery method to populate cards.
    +-    this.el.resourceWidget();
    +-  }
    +-
    +-  /**
    +-   * Fetch from localStorage an array of visted pages
    +-   * @returns {Array}
    +-   */
    +-  function getVisitedPages() {
    +-    var visited = localStorage.getItem('visited-pages');
    +-    return visited ? JSON.parse(visited) : [];
    +-  }
    +-
    +-  /**
    +-   * Return a page corresponding to cuurent pathname. If none exists, create one.
    +-   * @param {Array} pages
    +-   * @param {String} path
    +-   * @returns {Object} Page
    +-   */
    +-  function getPageForPath(pages, path) {
    +-    var page;
    +-
    +-    // Backwards lookup for current page, last pages most likely to be visited again.
    +-    for (var i = pages.length - 1; i >= 0; i--) {
    +-      if (pages[i].path === path) {
    +-        page = pages[i];
    +-
    +-        // Remove page object from pages list to ensure correct ordering.
    +-        pages.splice(i, 1);
    +-
    +-        return page;
    +-      }
    +-    }
    +-
    +-    // If storage limit is exceeded, remove last visited path.
    +-    if (pages.length >= PAGES_TO_STORE_) {
    +-      pages.shift();
    +-    }
    +-
    +-    return {path: path};
    +-  }
    +-
    +-  /**
    +-   * Add current page to back of visited array, increase hit count by 1.
    +-   */
    +-  function addCurrectPage() {
    +-    var path = location.pathname;
    +-
    +-    // Do not track frontpage visits.
    +-    if (path === '/' || path === '/index.html') {return;}
    +-
    +-    var pages = getVisitedPages();
    +-    var page = getPageForPath(pages, path);
    +-
    +-    // New page visits have no hit count.
    +-    page.hit = ~~page.hit + 1;
    +-
    +-    // Most recently visted pages are located at the end of the visited array.
    +-    pages.push(page);
    +-
    +-    localStorage.setItem('visited-pages', JSON.stringify(pages));
    +-  }
    +-
    +-  /**
    +-   * Hit count compare function.
    +-   * @param {Object} a - page
    +-   * @param {Object} b - page
    +-   * @returns {number}
    +-   */
    +-  function byHit(a, b) {
    +-    if (a.hit > b.hit) {
    +-      return -1;
    +-    } else if (a.hit < b.hit) {
    +-      return 1;
    +-    }
    +-
    +-    return 0;
    +-  }
    +-
    +-  /**
    +-   * Return a list of visited urls in a given order.
    +-   * @param {String} order - (recent|most-visited)
    +-   * @returns {Array}
    +-   */
    +-  $.dacGetVisitedUrls = function(order) {
    +-    var pages = getVisitedPages();
    +-
    +-    if (order === 'recent') {
    +-      pages.reverse();
    +-    } else {
    +-      pages.sort(byHit);
    +-    }
    +-
    +-    return pages.map(function(page) {
    +-      return page.path.replace(/^\//, '');
    +-    });
    +-  };
    +-
    +-  // jQuery plugin
    +-  $.fn.dacHistoryQuery = function() {
    +-    return this.each(function() {
    +-      var el = $(this);
    +-      var data = el.data('dac.recentlyVisited');
    +-
    +-      if (!data) {
    +-        el.data('dac.recentlyVisited', (data = new HistoryQuery(el)));
    +-      }
    +-    });
    +-  };
    +-
    +-  $(function() {
    +-    $('[data-history-query]').dacHistoryQuery();
    +-    // Do not block page rendering.
    +-    setTimeout(addCurrectPage, 0);
    +-  });
    +-})(jQuery);
    +-
    +-/* ############################################ */
    +-/* ##########     LOCALIZATION     ############ */
    +-/* ############################################ */
    +-/**
    +- * Global helpers.
    +- */
    +-function getBaseUri(uri) {
    +-  var intlUrl = (uri.substring(0, 6) === '/intl/');
    +-  if (intlUrl) {
    +-    var base = uri.substring(uri.indexOf('intl/') + 5, uri.length);
    +-    base = base.substring(base.indexOf('/') + 1, base.length);
    +-    return '/' + base;
    +-  } else {
    +-    return uri;
    +-  }
    +-}
    +-
    +-function changeLangPref(targetLang, submit) {
    +-  window.writeCookie('pref_lang', targetLang, null);
    +-  $('#language').find('option[value="' + targetLang + '"]').attr('selected', true);
    +-  if (submit) {
    +-    $('#setlang').submit();
    +-  }
    +-}
    +-// Redundant usage to appease jshint.
    +-window.changeLangPref = changeLangPref;
    +-
    +-(function() {
    +-  /**
    +-   * Whitelisted locales. Should match choices in language dropdown. Repeated here
    +-   * as a lot of i18n logic happens before page load and dropdown is ready.
    +-   */
    +-  var LANGUAGES = [
    +-    'en',
    +-    'es',
    +-    'in',
    +-    'ja',
    +-    'ko',
    +-    'pt-br',
    +-    'ru',
    +-    'vi',
    +-    'zh-cn',
    +-    'zh-tw'
    +-  ];
    +-
    +-  /**
    +-   * Master list of translated strings for template files.
    +-   */
    +-  var PHRASES = {
    +-    'newsletter': {
    +-      'title': 'Get the latest Android developer news and tips that will help you find success on Google Play.',
    +-      'requiredHint': '* Required Fields',
    +-      'name': 'Full name',
    +-      'email': 'Email address',
    +-      'company': 'Company / developer name',
    +-      'appUrl': 'One of your Play Store app URLs',
    +-      'business': {
    +-        'label': 'Which best describes your business:',
    +-        'apps': 'Apps',
    +-        'games': 'Games',
    +-        'both': 'Apps & Games'
    +-      },
    +-      'confirmMailingList': 'Add me to the mailing list for the monthly newsletter and occasional emails about ' +
    +-                            'development and Google Play opportunities.',
    +-      'privacyPolicy': 'I acknowledge that the information provided in this form will be subject to Google\'s ' +
    +-                       '<a href="https://www.google.com/policies/privacy/" target="_blank">privacy policy</a>.',
    +-      'languageVal': 'English',
    +-      'successTitle': 'Hooray!',
    +-      'successDetails': 'You have successfully signed up for the latest Android developer news and tips.',
    +-      'languageValTarget': {
    +-        'en': 'English',
    +-        'ar': 'Arabic (العربيّة)',
    +-        'in': 'Indonesian (Bahasa)',
    +-        'fr': 'French (français)',
    +-        'de': 'German (Deutsch)',
    +-        'ja': 'Japanese (日本語)',
    +-        'ko': 'Korean (한국어)',
    +-        'ru': 'Russian (Русский)',
    +-        'es': 'Spanish (español)',
    +-        'th': 'Thai (ภาษาไทย)',
    +-        'tr': 'Turkish (Türkçe)',
    +-        'vi': 'Vietnamese (tiếng Việt)',
    +-        'pt-br': 'Brazilian Portuguese (Português Brasileiro)',
    +-        'zh-cn': 'Simplified Chinese (简体中文)',
    +-        'zh-tw': 'Traditional Chinese (繁體中文)',
    +-      },
    +-      'resetLangTitle': "Browse this site in %{targetLang}?",
    +-      'resetLangTextIntro': 'You requested a page in %{targetLang}, but your language preference for this site is %{lang}.',
    +-      'resetLangTextCta': 'Would you like to change your language preference and browse this site in %{targetLang}? ' +
    +-                          'If you want to change your language preference later, use the language menu at the bottom of each page.',
    +-      'resetLangButtonYes': 'Change Language',
    +-      'resetLangButtonNo': 'Not Now'
    +-    }
    +-  };
    +-
    +-  /**
    +-   * Current locale.
    +-   */
    +-  var locale = (function() {
    +-    var lang = window.readCookie('pref_lang');
    +-    if (lang === 0 || LANGUAGES.indexOf(lang) === -1) {
    +-      lang = 'en';
    +-    }
    +-    return lang;
    +-  })();
    +-  var localeTarget = (function() {
    +-    var lang = getQueryVariable('hl');
    +-    if (lang === false || LANGUAGES.indexOf(lang) === -1) {
    +-      lang = locale;
    +-    }
    +-    return lang;
    +-  })();
    +-
    +-  /**
    +-   * Global function shims for backwards compatibility
    +-   */
    +-  window.changeNavLang = function() {
    +-    // Already done.
    +-  };
    +-
    +-  window.loadLangPref = function() {
    +-    // Languages pref already loaded.
    +-  };
    +-
    +-  window.getLangPref = function() {
    +-    return locale;
    +-  };
    +-
    +-  window.getLangTarget = function() {
    +-    return localeTarget;
    +-  };
    +-
    +-  // Expose polyglot instance for advanced localization.
    +-  var polyglot = window.polyglot = new window.Polyglot({
    +-    locale: locale,
    +-    phrases: PHRASES
    +-  });
    +-
    +-  // When DOM is ready.
    +-  $(function() {
    +-    // Mark current locale in language picker.
    +-    $('#language').find('option[value="' + locale + '"]').attr('selected', true);
    +-
    +-    $('html').dacTranslate().on('dac:domchange', function(e) {
    +-      $(e.target).dacTranslate();
    +-    });
    +-  });
    +-
    +-  $.fn.dacTranslate = function() {
    +-    // Translate strings in template markup:
    +-
    +-    // OLD
    +-    // Having all translations in HTML does not scale well and bloats every page.
    +-    // Need to migrate this to data-l JS translations below.
    +-    if (locale !== 'en') {
    +-      var $links = this.find('a[' + locale + '-lang]');
    +-      $links.each(function() { // for each link with a translation
    +-        var $link = $(this);
    +-        // put the desired language from the attribute as the text
    +-        $link.text($link.attr(locale + '-lang'));
    +-      });
    +-    }
    +-
    +-    // NEW
    +-    // A simple declarative api for JS translations. Feel free to extend as appropriate.
    +-
    +-    // Miscellaneous string compilations
    +-    // Build full strings from localized substrings:
    +-    var myLocaleTarget = window.getLangTarget();
    +-    var myTargetLang = window.polyglot.t("newsletter.languageValTarget." + myLocaleTarget);
    +-    var myLang = window.polyglot.t("newsletter.languageVal");
    +-    var myTargetLangTitleString = window.polyglot.t("newsletter.resetLangTitle", {targetLang: myTargetLang});
    +-    var myResetLangTextIntro = window.polyglot.t("newsletter.resetLangTextIntro", {targetLang: myTargetLang, lang: myLang});
    +-    var myResetLangTextCta = window.polyglot.t("newsletter.resetLangTextCta", {targetLang: myTargetLang});
    +-    //var myResetLangButtonYes = window.polyglot.t("newsletter.resetLangButtonYes", {targetLang: myTargetLang});
    +-
    +-    // Inject strings as text values in dialog components:
    +-    $("#langform .dac-modal-header-title").text(myTargetLangTitleString);
    +-    $("#langform #resetLangText").text(myResetLangTextIntro);
    +-    $("#langform #resetLangCta").text(myResetLangTextCta);
    +-    //$("#resetLangButtonYes").attr("data-t", window.polyglot.t(myResetLangButtonYes));
    +-
    +-    // Text: <div data-t="nav.home"></div>
    +-    // HTML: <div data-t="privacy" data-t-html></html>
    +-    this.find('[data-t]').each(function() {
    +-      var el = $(this);
    +-      var data = el.data();
    +-      if (data.t) {
    +-        el[data.tHtml === '' ? 'html' : 'text'](polyglot.t(data.t));
    +-      }
    +-    });
    +-
    +-    return this;
    +-  };
    +-})();
    +-/* ##########     END LOCALIZATION     ############ */
    +-
    +-// Translations. These should eventually be moved into language-specific files and loaded on demand.
    +-// jshint nonbsp:false
    +-switch (window.getLangPref()) {
    +-  case 'ar':
    +-    window.polyglot.extend({
    +-      'newsletter': {
    +-        'title': 'Google Play. يمكنك الحصول على آخر الأخبار والنصائح من مطوّري تطبيقات Android، مما يساعدك ' +
    +-          'على تحقيق النجاح على',
    +-        'requiredHint': '* حقول مطلوبة',
    +-        'name': '. الاسم بالكامل ',
    +-        'email': '. عنوان البريد الإلكتروني ',
    +-        'company': '. اسم الشركة / اسم مطوّر البرامج',
    +-        'appUrl': '. أحد عناوين URL لتطبيقاتك في متجر Play',
    +-        'business': {
    +-          'label': '. ما العنصر الذي يوضح طبيعة نشاطك التجاري بدقة؟ ',
    +-          'apps': 'التطبيقات',
    +-          'games': 'الألعاب',
    +-          'both': 'التطبيقات والألعاب'
    +-        },
    +-        'confirmMailingList': 'إضافتي إلى القائمة البريدية للنشرة الإخبارية الشهرية والرسائل الإلكترونية التي يتم' +
    +-          ' إرسالها من حين لآخر بشأن التطوير وفرص Google Play.',
    +-        'privacyPolicy': 'أقر بأن المعلومات المقدَّمة في هذا النموذج تخضع لسياسة خصوصية ' +
    +-          '<a href="https://www.google.com/intl/ar/policies/privacy/" target="_blank">Google</a>.',
    +-        'languageVal': 'Arabic (العربيّة)',
    +-        'successTitle': 'رائع!',
    +-        'successDetails': 'لقد اشتركت بنجاح للحصول على آخر الأخبار والنصائح من مطوّري برامج Android.'
    +-      }
    +-    });
    +-    break;
    +-  case 'zh-cn':
    +-    window.polyglot.extend({
    +-      'newsletter': {
    +-        'title': '获取最新的 Android 开发者资讯和提示,助您在 Google Play 上取得成功。',
    +-        'requiredHint': '* 必填字段',
    +-        'name': '全名',
    +-        'email': '电子邮件地址',
    +-        'company': '公司/开发者名称',
    +-        'appUrl': '您的某个 Play 商店应用网址',
    +-        'business': {
    +-          'label': '哪一项能够最准确地描述您的业务?',
    +-          'apps': '应用',
    +-          'games': '游戏',
    +-          'both': '应用和游戏'
    +-        },
    +-        'confirmMailingList': '将我添加到邮寄名单,以便接收每月简报以及不定期发送的关于开发和 Google Play 商机的电子邮件。',
    +-        'privacyPolicy': '我确认自己了解在此表单中提供的信息受 <a href="https://www.google.com/intl/zh-CN/' +
    +-        'policies/privacy/" target="_blank">Google</a> 隐私权政策的约束。',
    +-        'languageVal': 'Simplified Chinese (简体中文)',
    +-        'successTitle': '太棒了!',
    +-        'successDetails': '您已成功订阅最新的 Android 开发者资讯和提示。'
    +-      }
    +-    });
    +-    break;
    +-  case 'zh-tw':
    +-    window.polyglot.extend({
    +-      'newsletter': {
    +-        'title': '獲得 Android 開發人員的最新消息和各項秘訣,讓您在 Google Play 上輕鬆邁向成功之路。',
    +-        'requiredHint': '* 必要欄位',
    +-        'name': '全名',
    +-        'email': '電子郵件地址',
    +-        'company': '公司/開發人員名稱',
    +-        'appUrl': '您其中一個 Play 商店應用程式的網址',
    +-        'business': {
    +-          'label': '為您的商家選取最合適的產品類別。',
    +-          'apps': '應用程式',
    +-          'games': '遊戲',
    +-          'both': '應用程式和遊戲'
    +-        },
    +-        'confirmMailingList': '我想加入 Google Play 的郵寄清單,以便接收每月電子報和 Google Play 不定期寄送的電子郵件,' +
    +-          '瞭解關於開發和 Google Play 商機的資訊。',
    +-        'privacyPolicy': '我瞭解,我在這張表單中提供的資訊將受到 <a href="' +
    +-        'https://www.google.com/intl/zh-TW/policies/privacy/" target="_blank">Google</a> 隱私權政策.',
    +-        'languageVal': 'Traditional Chinese (繁體中文)',
    +-        'successTitle': '太棒了!',
    +-        'successDetails': '您已經成功訂閱 Android 開發人員的最新消息和各項秘訣。'
    +-      }
    +-    });
    +-    break;
    +-  case 'fr':
    +-    window.polyglot.extend({
    +-      'newsletter': {
    +-        'title': 'Recevez les dernières actualités destinées aux développeurs Android, ainsi que des conseils qui ' +
    +-          'vous mèneront vers le succès sur Google Play.',
    +-        'requiredHint': '* Champs obligatoires',
    +-        'name': 'Nom complet',
    +-        'email': 'Adresse e-mail',
    +-        'company': 'Nom de la société ou du développeur',
    +-        'appUrl': 'Une de vos URL Play Store',
    +-        'business': {
    +-          'label': 'Quelle option décrit le mieux votre activité ?',
    +-          'apps': 'Applications',
    +-          'games': 'Jeux',
    +-          'both': 'Applications et jeux'
    +-        },
    +-        'confirmMailingList': 'Ajoutez-moi à la liste de diffusion de la newsletter mensuelle et tenez-moi informé ' +
    +-          'par des e-mails occasionnels de l\'évolution et des opportunités de Google Play.',
    +-        'privacyPolicy': 'Je comprends que les renseignements fournis dans ce formulaire seront soumis aux <a href="' +
    +-        'https://www.google.com/intl/fr/policies/privacy/" target="_blank">règles de confidentialité</a> de Google.',
    +-        'languageVal': 'French (français)',
    +-        'successTitle': 'Super !',
    +-        'successDetails': 'Vous êtes bien inscrit pour recevoir les actualités et les conseils destinés aux ' +
    +-          'développeurs Android.'
    +-      }
    +-    });
    +-    break;
    +-  case 'de':
    +-    window.polyglot.extend({
    +-      'newsletter': {
    +-        'title': 'Abonniere aktuelle Informationen und Tipps für Android-Entwickler und werde noch erfolgreicher ' +
    +-          'bei Google Play.',
    +-        'requiredHint': '* Pflichtfelder',
    +-        'name': 'Vollständiger Name',
    +-        'email': 'E-Mail-Adresse',
    +-        'company': 'Unternehmens-/Entwicklername',
    +-        'appUrl': 'Eine der URLs deiner Play Store App',
    +-        'business': {
    +-          'label': 'Welche der folgenden Kategorien beschreibt dein Unternehmen am besten?',
    +-          'apps': 'Apps',
    +-          'games': 'Spiele',
    +-          'both': 'Apps und Spiele'
    +-        },
    +-        'confirmMailingList': 'Meine E-Mail-Adresse soll zur Mailingliste hinzugefügt werden, damit ich den ' +
    +-          'monatlichen Newsletter sowie gelegentlich E-Mails zu Entwicklungen und Optionen bei Google Play erhalte.',
    +-        'privacyPolicy': 'Ich bestätige, dass die in diesem Formular bereitgestellten Informationen gemäß der ' +
    +-          '<a href="https://www.google.com/intl/de/policies/privacy/" target="_blank">Datenschutzerklärung</a> von ' +
    +-          'Google verwendet werden dürfen.',
    +-        'languageVal': 'German (Deutsch)',
    +-        'successTitle': 'Super!',
    +-        'successDetails': 'Du hast dich erfolgreich angemeldet und erhältst jetzt aktuelle Informationen und Tipps ' +
    +-          'für Android-Entwickler.'
    +-      }
    +-    });
    +-    break;
    +-  case 'in':
    +-    window.polyglot.extend({
    +-      'newsletter': {
    +-        'title': 'Receba as dicas e as notícias mais recentes para os desenvolvedores Android e seja bem-sucedido ' +
    +-        'no Google Play.',
    +-        'requiredHint': '* Bidang Wajib Diisi',
    +-        'name': 'Nama lengkap',
    +-        'email': 'Alamat email',
    +-        'company': 'Nama pengembang / perusahaan',
    +-        'appUrl': 'Salah satu URL aplikasi Play Store Anda',
    +-        'business': {
    +-          'label': 'Dari berikut ini, mana yang paling cocok dengan bisnis Anda?',
    +-          'apps': 'Aplikasi',
    +-          'games': 'Game',
    +-          'both': 'Aplikasi dan Game'
    +-        },
    +-        'confirmMailingList': 'Tambahkan saya ke milis untuk mendapatkan buletin bulanan dan email sesekali mengenai ' +
    +-          'perkembangan dan kesempatan yang ada di Google Play.',
    +-        'privacyPolicy': 'Saya memahami bahwa informasi yang diberikan dalam formulir ini tunduk pada <a href="' +
    +-        'https://www.google.com/intl/in/policies/privacy/" target="_blank">kebijakan privasi</a> Google.',
    +-        'languageVal': 'Indonesian (Bahasa)',
    +-        'successTitle': 'Hore!',
    +-        'successDetails': 'Anda berhasil mendaftar untuk kiat dan berita pengembang Android terbaru.'
    +-      }
    +-    });
    +-    break;
    +-  case 'it':
    +-    //window.polyglot.extend({
    +-    //  'newsletter': {
    +-    //    'title': 'Receba as dicas e as notícias mais recentes para os desenvolvedores Android e seja bem-sucedido ' +
    +-    //    'no Google Play.',
    +-    //    'requiredHint': '* Campos obrigatórios',
    +-    //    'name': 'Nome completo',
    +-    //    'email': 'Endereço de Email',
    +-    //    'company': 'Nome da empresa / do desenvolvedor',
    +-    //    'appUrl': 'URL de um dos seus apps da Play Store',
    +-    //    'business': {
    +-    //      'label': 'Qual das seguintes opções melhor descreve sua empresa?',
    +-    //      'apps': 'Apps',
    +-    //      'games': 'Jogos',
    +-    //      'both': 'Apps e Jogos'
    +-    //    },
    +-    //    'confirmMailingList': 'Inscreva-me na lista de e-mails para que eu receba o boletim informativo mensal, ' +
    +-    //    'bem como e-mails ocasionais sobre o desenvolvimento e as oportunidades do Google Play.',
    +-    //    'privacyPolicy': 'Reconheço que as informações fornecidas neste formulário estão sujeitas à <a href="' +
    +-    //    'https://www.google.com.br/policies/privacy/" target="_blank">Política de Privacidade</a> do Google.',
    +-    //    'languageVal': 'Italian (italiano)',
    +-    //    'successTitle': 'Uhu!',
    +-    //    'successDetails': 'Você se inscreveu para receber as notícias e as dicas mais recentes para os ' +
    +-    //    'desenvolvedores Android.',
    +-    //  }
    +-    //});
    +-    break;
    +-  case 'ja':
    +-    window.polyglot.extend({
    +-      'newsletter': {
    +-        'title': 'Google Play での成功に役立つ Android デベロッパー向けの最新ニュースやおすすめの情報をお届けします。',
    +-        'requiredHint': '* 必須',
    +-        'name': '氏名',
    +-        'email': 'メールアドレス',
    +-        'company': '会社名 / デベロッパー名',
    +-        'appUrl': 'Play ストア アプリの URL(いずれか 1 つ)',
    +-        'business': {
    +-          'label': 'お客様のビジネスに最もよく当てはまるものをお選びください。',
    +-          'apps': 'アプリ',
    +-          'games': 'ゲーム',
    +-          'both': 'アプリとゲーム'
    +-        },
    +-        'confirmMailingList': '開発や Google Play の最新情報に関する毎月発行のニュースレターや不定期発行のメールを受け取る',
    +-        'privacyPolicy': 'このフォームに入力した情報に <a href="https://www.google.com/intl/ja/policies/privacy/" ' +
    +-          'target="_blank">Google</a> のプライバシー ポリシーが適用',
    +-        'languageVal': 'Japanese (日本語)',
    +-        'successTitle': '完了です!',
    +-        'successDetails': 'Android デベロッパー向けの最新ニュースやおすすめの情報の配信登録が完了しました。'
    +-      }
    +-    });
    +-    break;
    +-  case 'ko':
    +-    window.polyglot.extend({
    +-      'newsletter': {
    +-        'title': 'Google Play에서 성공을 거두는 데 도움이 되는 최신 Android 개발자 소식 및 도움말을 받아 보세요.',
    +-        'requiredHint': '* 필수 입력란',
    +-        'name': '이름',
    +-        'email': '이메일 주소',
    +-        'company': '회사/개발자 이름',
    +-        'appUrl': 'Play 스토어 앱 URL 중 1개',
    +-        'business': {
    +-          'label': '다음 중 내 비즈니스를 가장 잘 설명하는 단어는 무엇인가요?',
    +-          'apps': '앱',
    +-          'games': '게임',
    +-          'both': '앱 및 게임'
    +-        },
    +-        'confirmMailingList': '개발 및 Google Play 관련 소식에 관한 월별 뉴스레터 및 비정기 이메일을 받아보겠습니다.',
    +-        'privacyPolicy': '이 양식에 제공한 정보는 <a href="https://www.google.com/intl/ko/policies/privacy/" ' +
    +-          'target="_blank">Google의</a> 개인정보취급방침에 따라 사용됨을',
    +-        'languageVal':'Korean (한국어)',
    +-        'successTitle': '축하합니다!',
    +-        'successDetails': '최신 Android 개발자 뉴스 및 도움말을 받아볼 수 있도록 가입을 완료했습니다.'
    +-      }
    +-    });
    +-    break;
    +-  case 'pt-br':
    +-    window.polyglot.extend({
    +-      'newsletter': {
    +-        'title': 'Receba as dicas e as notícias mais recentes para os desenvolvedores Android e seja bem-sucedido ' +
    +-        'no Google Play.',
    +-        'requiredHint': '* Campos obrigatórios',
    +-        'name': 'Nome completo',
    +-        'email': 'Endereço de Email',
    +-        'company': 'Nome da empresa / do desenvolvedor',
    +-        'appUrl': 'URL de um dos seus apps da Play Store',
    +-        'business': {
    +-          'label': 'Qual das seguintes opções melhor descreve sua empresa?',
    +-          'apps': 'Apps',
    +-          'games': 'Jogos',
    +-          'both': 'Apps e Jogos'
    +-        },
    +-        'confirmMailingList': 'Inscreva-me na lista de e-mails para que eu receba o boletim informativo mensal, ' +
    +-        'bem como e-mails ocasionais sobre o desenvolvimento e as oportunidades do Google Play.',
    +-        'privacyPolicy': 'Reconheço que as informações fornecidas neste formulário estão sujeitas à <a href="' +
    +-        'https://www.google.com.br/policies/privacy/" target="_blank">Política de Privacidade</a> do Google.',
    +-        'languageVal': 'Brazilian Portuguese (Português Brasileiro)',
    +-        'successTitle': 'Uhu!',
    +-        'successDetails': 'Você se inscreveu para receber as notícias e as dicas mais recentes para os ' +
    +-        'desenvolvedores Android.'
    +-      }
    +-    });
    +-    break;
    +-  case 'ru':
    +-    window.polyglot.extend({
    +-      'newsletter': {
    +-        'title': 'Хотите получать последние новости и советы для разработчиков Google Play? Заполните эту форму.',
    +-        'requiredHint': '* Обязательные поля',
    +-        'name': 'Полное имя',
    +-        'email': 'Адрес электронной почты',
    +-        'company': 'Название компании или имя разработчика',
    +-        'appUrl': 'Ссылка на любое ваше приложение в Google Play',
    +-        'business': {
    +-          'label': 'Что вы создаете?',
    +-          'apps': 'Приложения',
    +-          'games': 'Игры',
    +-          'both': 'Игры и приложения'
    +-        },
    +-        'confirmMailingList': 'Я хочу получать ежемесячную рассылку для разработчиков и другие полезные новости ' +
    +-          'Google Play.',
    +-        'privacyPolicy': 'Я предоставляю эти данные в соответствии с <a href="' +
    +-          'https://www.google.com/intl/ru/policies/privacy/" target="_blank">Политикой конфиденциальности</a> Google.',
    +-        'languageVal': 'Russian (Русский)',
    +-        'successTitle': 'Поздравляем!',
    +-        'successDetails': 'Теперь вы подписаны на последние новости и советы для разработчиков Android.'
    +-      }
    +-    });
    +-    break;
    +-  case 'es':
    +-    window.polyglot.extend({
    +-      'newsletter': {
    +-        'title': 'Recibe las últimas noticias y sugerencias para programadores de Android y logra tener éxito en ' +
    +-          'Google Play.',
    +-        'requiredHint': '* Campos obligatorios',
    +-        'name': 'Dirección de correo electrónico',
    +-        'email': 'Endereço de Email',
    +-        'company': 'Nombre de la empresa o del programador',
    +-        'appUrl': 'URL de una de tus aplicaciones de Play Store',
    +-        'business': {
    +-          'label': '¿Qué describe mejor a tu empresa?',
    +-          'apps': 'Aplicaciones',
    +-          'games': 'Juegos',
    +-          'both': 'Juegos y aplicaciones'
    +-        },
    +-        'confirmMailingList': 'Deseo unirme a la lista de distribución para recibir el boletín informativo mensual ' +
    +-          'y correos electrónicos ocasionales sobre desarrollo y oportunidades de Google Play.',
    +-        'privacyPolicy': 'Acepto que la información que proporcioné en este formulario cumple con la <a href="' +
    +-        'https://www.google.com/intl/es/policies/privacy/" target="_blank">política de privacidad</a> de Google.',
    +-        'languageVal': 'Spanish (español)',
    +-        'successTitle': '¡Felicitaciones!',
    +-        'successDetails': 'El registro para recibir las últimas noticias y sugerencias para programadores de Android ' +
    +-          'se realizó correctamente.'
    +-      }
    +-    });
    +-    break;
    +-  case 'th':
    +-    window.polyglot.extend({
    +-      'newsletter': {
    +-        'title': 'รับข่าวสารล่าสุดสำหรับนักพัฒนาซอฟต์แวร์ Android ตลอดจนเคล็ดลับที่จะช่วยให้คุณประสบความสำเร็จบน ' +
    +-          'Google Play',
    +-        'requiredHint': '* ช่องที่ต้องกรอก',
    +-        'name': 'ชื่อและนามสกุล',
    +-        'email': 'ที่อยู่อีเมล',
    +-        'company': 'ชื่อบริษัท/นักพัฒนาซอฟต์แวร์',
    +-        'appUrl': 'URL แอปใดแอปหนึ่งของคุณใน Play สโตร์',
    +-        'business': {
    +-          'label': 'ข้อใดตรงกับธุรกิจของคุณมากที่สุด',
    +-          'apps': 'แอป',
    +-          'games': 'เกม',
    +-          'both': 'แอปและเกม'
    +-        },
    +-        'confirmMailingList': 'เพิ่มฉันลงในรายชื่ออีเมลเพื่อรับจดหมายข่าวรายเดือนและอีเมลเป็นครั้งคราวเกี่ยวกับก' +
    +-          'ารพัฒนาซอฟต์แวร์และโอกาสใน Google Play',
    +-        'privacyPolicy': 'ฉันรับทราบว่าข้อมูลที่ให้ไว้ในแบบฟอร์มนี้จะเป็นไปตามนโยบายส่วนบุคคลของ ' +
    +-          '<a href="https://www.google.com/intl/th/policies/privacy/" target="_blank">Google</a>',
    +-        'languageVal': 'Thai (ภาษาไทย)',
    +-        'successTitle': 'ไชโย!',
    +-        'successDetails': 'คุณลงชื่อสมัครรับข่าวสารและเคล็ดลับล่าสุดสำหรับนักพัฒนาซอฟต์แวร์ Android เสร็จเรียบร้อยแล้ว'
    +-      }
    +-    });
    +-    break;
    +-  case 'tr':
    +-    window.polyglot.extend({
    +-      'newsletter': {
    +-        'title': 'Google Play\'de başarılı olmanıza yardımcı olacak en son Android geliştirici haberleri ve ipuçları.',
    +-        'requiredHint': '* Zorunlu Alanlar',
    +-        'name': 'Tam ad',
    +-        'email': 'E-posta adresi',
    +-        'company': 'Şirket / geliştirici adı',
    +-        'appUrl': 'Play Store uygulama URL\'lerinizden biri',
    +-        'business': {
    +-          'label': 'İşletmenizi en iyi hangisi tanımlar?',
    +-          'apps': 'Uygulamalar',
    +-          'games': 'Oyunlar',
    +-          'both': 'Uygulamalar ve Oyunlar'
    +-        },
    +-        'confirmMailingList': 'Beni, geliştirme ve Google Play fırsatlarıyla ilgili ara sıra gönderilen e-posta ' +
    +-          'iletilerine ilişkin posta listesine ve aylık haber bültenine ekle.',
    +-        'privacyPolicy': 'Bu formda sağlanan bilgilerin Google\'ın ' +
    +-          '<a href="https://www.google.com/intl/tr/policies/privacy/" target="_blank">Gizlilik Politikası\'na</a> ' +
    +-          'tabi olacağını kabul ediyorum.',
    +-        'languageVal': 'Turkish (Türkçe)',
    +-        'successTitle': 'Yaşasın!',
    +-        'successDetails': 'En son Android geliştirici haberleri ve ipuçlarına başarıyla kaydoldunuz.'
    +-      }
    +-    });
    +-    break;
    +-  case 'vi':
    +-    window.polyglot.extend({
    +-      'newsletter': {
    +-        'title': 'Nhận tin tức và mẹo mới nhất dành cho nhà phát triển Android sẽ giúp bạn tìm thấy thành công trên ' +
    +-          'Google Play.',
    +-        'requiredHint': '* Các trường bắt buộc',
    +-        'name': 'Tên đầy đủ',
    +-        'email': 'Địa chỉ email',
    +-        'company': 'Tên công ty/nhà phát triển',
    +-        'appUrl': 'Một trong số các URL ứng dụng trên cửa hàng Play của bạn',
    +-        'business': {
    +-          'label': 'Lựa chọn nào sau đây mô tả chính xác nhất doanh nghiệp của bạn?',
    +-          'apps': 'Ứng dụng',
    +-          'games': 'Trò chơi',
    +-          'both': 'Ứng dụng và trò chơi'
    +-        },
    +-        'confirmMailingList': 'Thêm tôi vào danh sách gửi thư cho bản tin hàng tháng và email định kỳ về việc phát ' +
    +-          'triển và cơ hội của Google Play.',
    +-        'privacyPolicy': 'Tôi xác nhận rằng thông tin được cung cấp trong biểu mẫu này tuân thủ chính sách bảo mật ' +
    +-          'của <a href="https://www.google.com/intl/vi/policies/privacy/" target="_blank">Google</a>.',
    +-        'languageVal': 'Vietnamese (tiếng Việt)',
    +-        'successTitle': 'Thật tuyệt!',
    +-        'successDetails': 'Bạn đã đăng ký thành công nhận tin tức và mẹo mới nhất dành cho nhà phát triển của Android.'
    +-      }
    +-    });
    +-    break;
    +-}
    +-
    +-(function($) {
    +-  'use strict';
    +-
    +-  function Modal(el, options) {
    +-    this.el = $(el);
    +-    this.options = $.extend({}, options);
    +-    this.isOpen = false;
    +-
    +-    this.el.on('click', function(event) {
    +-      if (!$.contains(this.el.find('.dac-modal-window')[0], event.target)) {
    +-        return this.el.trigger('modal-close');
    +-      }
    +-    }.bind(this));
    +-
    +-    this.el.on('modal-open', this.open_.bind(this));
    +-    this.el.on('modal-close', this.close_.bind(this));
    +-    this.el.on('modal-toggle', this.toggle_.bind(this));
    +-  }
    +-
    +-  Modal.prototype.toggle_ = function() {
    +-    this.el.trigger('modal-' + (this.isOpen ? 'close' : 'open'));
    +-  };
    +-
    +-  Modal.prototype.close_ = function() {
    +-    // When closing the modal for Android Studio downloads, reload the page
    +-    // because otherwise we might get stuck with post-download dialog state
    +-    if ($("[data-modal='studio_tos'].dac-active").length) {
    +-      location.reload();
    +-    }
    +-    this.el.removeClass('dac-active');
    +-    $('body').removeClass('dac-modal-open');
    +-    this.isOpen = false;
    +-  };
    +-
    +-  Modal.prototype.open_ = function() {
    +-    this.el.addClass('dac-active');
    +-    $('body').addClass('dac-modal-open');
    +-    this.isOpen = true;
    +-  };
    +-
    +-  function onClickToggleModal(event) {
    +-    event.preventDefault();
    +-    var toggle = $(event.currentTarget);
    +-    var options = toggle.data();
    +-    var modal = options.modalToggle ? $('[data-modal="' + options.modalToggle + '"]') :
    +-      toggle.closest('[data-modal]');
    +-    modal.trigger('modal-toggle');
    +-  }
    +-
    +-  /**
    +-   * jQuery plugin
    +-   * @param  {object} options - Override default options.
    +-   */
    +-  $.fn.dacModal = function(options) {
    +-    return this.each(function() {
    +-      new Modal(this, options);
    +-    });
    +-  };
    +-
    +-  $.fn.dacToggleModal = function(options) {
    +-    return this.each(function() {
    +-      new ToggleModal(this, options);
    +-    });
    +-  };
    +-
    +-  /**
    +-   * Data Attribute API
    +-   */
    +-  $(document).on('ready.aranja', function() {
    +-    $('[data-modal]').each(function() {
    +-      $(this).dacModal($(this).data());
    +-    });
    +-
    +-    $('html').on('click.modal', '[data-modal-toggle]', onClickToggleModal);
    +-
    +-    // Check if url anchor is targetting a toggle to open the modal.
    +-    if (location.hash) {
    +-      var $elem = $(document.getElementById(location.hash.substr(1)));
    +-      if ($elem.attr('data-modal-toggle')) {
    +-        $elem.trigger('click');
    +-      }
    +-    }
    +-
    +-    var isTargetLangValid = false;
    +-    $(ANDROID_LANGUAGES).each(function(index, langCode) {
    +-      if (langCode == window.getLangTarget()) {
    +-        isTargetLangValid = true;
    +-        return;
    +-      }
    +-    });
    +-    if (window.getLangTarget() !== window.getLangPref() && isTargetLangValid) {
    +-        $('#langform').trigger('modal-open');
    +-        $("#langform button.yes").attr("onclick","window.changeLangPref('" + window.getLangTarget() + "', true);  return false;");
    +-        $("#langform button.no").attr("onclick","window.changeLangPref('" + window.getLangPref() + "', true); return false;");
    +-    }
    +-
    +-    /* Check the current API level, but only if we're in the reference */
    +-    if (location.pathname.indexOf('/reference') == 0) {
    +-      // init available apis based on user pref
    +-      changeApiLevel();
    +-    }
    +-  });
    +-})(jQuery);
    +-
    +-/* Fullscreen - Toggle fullscreen mode for reference pages */
    +-(function($) {
    +-  'use strict';
    +-
    +-  /**
    +-   * @param {HTMLElement} el - The DOM element.
    +-   * @constructor
    +-   */
    +-  function Fullscreen(el) {
    +-    this.el = $(el);
    +-    this.html = $('html');
    +-    this.icon = this.el.find('.dac-sprite');
    +-    this.isFullscreen = window.readCookie(Fullscreen.COOKIE_) === 'true';
    +-    this.activate_();
    +-    this.el.on('click.dac-fullscreen', this.toggleHandler_.bind(this));
    +-  }
    +-
    +-  /**
    +-   * Cookie name for storing the state
    +-   * @type {string}
    +-   * @private
    +-   */
    +-  Fullscreen.COOKIE_ = 'fullscreen';
    +-
    +-  /**
    +-   * Classes to modify the DOM
    +-   * @type {{mode: string, fullscreen: string, fullscreenExit: string}}
    +-   * @private
    +-   */
    +-  Fullscreen.CLASSES_ = {
    +-    mode: 'dac-fullscreen-mode',
    +-    fullscreen: 'dac-fullscreen',
    +-    fullscreenExit: 'dac-fullscreen-exit'
    +-  };
    +-
    +-  /**
    +-   * Event listener for toggling fullscreen mode
    +-   * @param {MouseEvent} event
    +-   * @private
    +-   */
    +-  Fullscreen.prototype.toggleHandler_ = function(event) {
    +-    event.stopPropagation();
    +-    this.toggle(!this.isFullscreen, true);
    +-  };
    +-
    +-  /**
    +-   * Change the DOM based on current state.
    +-   * @private
    +-   */
    +-  Fullscreen.prototype.activate_ = function() {
    +-    this.icon.toggleClass(Fullscreen.CLASSES_.fullscreen, !this.isFullscreen);
    +-    this.icon.toggleClass(Fullscreen.CLASSES_.fullscreenExit, this.isFullscreen);
    +-    this.html.toggleClass(Fullscreen.CLASSES_.mode, this.isFullscreen);
    +-  };
    +-
    +-  /**
    +-   * Toggle fullscreen mode and store the state in a cookie.
    +-   */
    +-  Fullscreen.prototype.toggle = function() {
    +-    this.isFullscreen = !this.isFullscreen;
    +-    window.writeCookie(Fullscreen.COOKIE_, this.isFullscreen, null);
    +-    this.activate_();
    +-  };
    +-
    +-  /**
    +-   * jQuery plugin
    +-   */
    +-  $.fn.dacFullscreen = function() {
    +-    return this.each(function() {
    +-      new Fullscreen($(this));
    +-    });
    +-  };
    +-})(jQuery);
    +-
    +-(function($) {
    +-  'use strict';
    +-
    +-  /**
    +-   * @param {HTMLElement} selected - The link that is selected in the nav.
    +-   * @constructor
    +-   */
    +-  function HeaderTabs(selected) {
    +-
    +-    // Don't highlight any tabs on the index page
    +-    if (location.pathname === '/index.html' || location.pathname === '/') {
    +-      //return;
    +-    }
    +-
    +-    this.selected = $(selected);
    +-    this.selectedParent = this.selected.closest('.dac-nav-secondary').siblings('a');
    +-    this.links = $('.dac-header-tabs a');
    +-
    +-    this.selectActiveTab();
    +-  }
    +-
    +-  HeaderTabs.prototype.selectActiveTab = function() {
    +-    var section = null;
    +-
    +-    if (this.selectedParent.length) {
    +-      section = this.selectedParent.text();
    +-    } else {
    +-      section = this.selected.text();
    +-    }
    +-
    +-    if (section) {
    +-      this.links.removeClass('selected');
    +-
    +-      this.links.filter(function() {
    +-        return $(this).text() === $.trim(section);
    +-      }).addClass('selected');
    +-    }
    +-  };
    +-
    +-  /**
    +-   * jQuery plugin
    +-   */
    +-  $.fn.dacHeaderTabs = function() {
    +-    return this.each(function() {
    +-      new HeaderTabs(this);
    +-    });
    +-  };
    +-})(jQuery);
    +-
    +-(function($) {
    +-  'use strict';
    +-  var icon = $('<i/>').addClass('dac-sprite dac-nav-forward');
    +-  var config = JSON.parse(window.localStorage.getItem('global-navigation') || '{}');
    +-  var forwardLink = $('<span/>')
    +-    .addClass('dac-nav-link-forward')
    +-    .html(icon)
    +-    .attr('tabindex', 0)
    +-    .on('click keypress', function(e) {
    +-      if (e.type == 'keypress' && e.which == 13 || e.type == 'click') {
    +-        swap_(e);
    +-      }
    +-    });
    +-
    +-  /**
    +-   * @constructor
    +-   */
    +-  function Nav(navigation) {
    +-    $('.dac-nav-list').dacCurrentPage().dacHeaderTabs().dacSidebarToggle($('body'));
    +-
    +-    navigation.find('[data-reference-tree]').dacReferenceNav();
    +-
    +-    setupViews_(navigation.children().eq(0).children());
    +-
    +-    initCollapsedNavs(navigation.find('.dac-nav-sub-slider'));
    +-
    +-    $('#dac-main-navigation').scrollIntoView('.selected')
    +-  }
    +-
    +-  function updateStore(icon) {
    +-    var navClass = getCurrentLandingPage_(icon);
    +-    var isExpanded = icon.hasClass('dac-expand-less-black');
    +-    var expandedNavs = config.expanded || [];
    +-    if (isExpanded) {
    +-      expandedNavs.push(navClass);
    +-    } else {
    +-      expandedNavs = expandedNavs.filter(function(item) {
    +-        return item !== navClass;
    +-      });
    +-    }
    +-    config.expanded = expandedNavs;
    +-    window.localStorage.setItem('global-navigation', JSON.stringify(config));
    +-  }
    +-
    +-  function toggleSubNav_(icon) {
    +-    var isExpanded = icon.hasClass('dac-expand-less-black');
    +-    icon.toggleClass('dac-expand-less-black', !isExpanded);
    +-    icon.toggleClass('dac-expand-more-black', isExpanded);
    +-    icon.data('sub-navigation.dac').slideToggle(200);
    +-
    +-    updateStore(icon);
    +-  }
    +-
    +-  function handleSubNavToggle_(event) {
    +-    event.preventDefault();
    +-    var icon = $(event.target);
    +-    toggleSubNav_(icon);
    +-  }
    +-
    +-  function getCurrentLandingPage_(icon) {
    +-    return icon.closest('li')[0].className.replace('dac-nav-item ', '');
    +-  }
    +-
    +-  // Setup sub navigation collapse/expand
    +-  function initCollapsedNavs(toggleIcons) {
    +-    toggleIcons.each(setInitiallyActive_($('body')));
    +-    toggleIcons.on('click keypress', function(e) {
    +-      if (e.type == 'keypress' && e.which == 13 || e.type == 'click') {
    +-        handleSubNavToggle_(e);
    +-      }
    +-    });
    +-  }
    +-
    +-  function setInitiallyActive_(body) {
    +-    var expandedNavs = config.expanded || [];
    +-    return function(i, icon) {
    +-      icon = $(icon);
    +-      var subNav = icon.next();
    +-
    +-      if (!subNav.length) {
    +-        return;
    +-      }
    +-
    +-      var landingPageClass = getCurrentLandingPage_(icon);
    +-      var expanded = expandedNavs.indexOf(landingPageClass) >= 0;
    +-      landingPageClass = landingPageClass === 'home' ? 'about' : landingPageClass;
    +-
    +-      if (landingPageClass == 'about' && location.pathname == '/index.html') {
    +-        expanded = true;
    +-      }
    +-
    +-      // TODO: Should read from localStorage
    +-      var visible = body.hasClass(landingPageClass) || expanded;
    +-
    +-      icon.data('sub-navigation.dac', subNav);
    +-      icon.toggleClass('dac-expand-less-black', visible);
    +-      icon.toggleClass('dac-expand-more-black', !visible);
    +-      subNav.toggle(visible);
    +-    };
    +-  }
    +-
    +-  function setupViews_(views) {
    +-    if (views.length === 1) {
    +-      // Active tier 1 nav.
    +-      views.addClass('dac-active');
    +-    } else {
    +-      // Activate back button and tier 2 nav.
    +-      views.slice(0, 2).addClass('dac-active');
    +-      var selectedNav = views.eq(2).find('.selected').after(forwardLink);
    +-      var langAttr = selectedNav.attr(window.getLangPref() + '-lang');
    +-      //form the label from locale attr if possible, else set to selectedNav text value
    +-      if ((typeof langAttr !== typeof undefined &&  langAttr !== false) && (langAttr !== '')) {
    +-        $('.dac-nav-back-title').text(langAttr);
    +-      } else {
    +-        $('.dac-nav-back-title').text(selectedNav.text());
    +-      }
    +-    }
    +-
    +-    // Navigation should animate.
    +-    setTimeout(function() {
    +-      views.removeClass('dac-no-anim');
    +-    }, 10);
    +-  }
    +-
    +-  function swap_(event) {
    +-    event.preventDefault();
    +-    $(event.currentTarget).trigger('swap-content');
    +-  }
    +-
    +-  /**
    +-   * jQuery plugin
    +-   */
    +-  $.fn.dacNav = function() {
    +-    return this.each(function() {
    +-      new Nav($(this));
    +-    });
    +-  };
    +-})(jQuery);
    +-
    +-/* global NAVTREE_DATA */
    +-(function($) {
    +-  /**
    +-   * Build the reference navigation with namespace dropdowns.
    +-   * @param {jQuery} el - The DOM element.
    +-   */
    +-  function buildReferenceNav(el) {
    +-    var supportLibraryPath = '/reference/android/support/';
    +-    var currPath = location.pathname;
    +-
    +-    if (currPath.indexOf(supportLibraryPath) > -1) {
    +-      updateSupportLibrariesNav(supportLibraryPath, currPath);
    +-    }
    +-    var namespaceList = el.find('[data-reference-namespaces]');
    +-    var resources = $('[data-reference-resources]').detach();
    +-    var selected = namespaceList.find('.selected');
    +-    resources.appendTo(el);
    +-
    +-    // Links should be toggleable.
    +-    namespaceList.find('a').addClass('dac-reference-nav-toggle dac-closed');
    +-
    +-    // Set the path for the navtree data to use.
    +-    var navtree_filepath = getNavtreeFilePath(supportLibraryPath, currPath);
    +-
    +-    // Load in all resources
    +-    $.getScript(navtree_filepath, function(data, textStatus, xhr) {
    +-      if (xhr.status === 200) {
    +-        namespaceList.on(
    +-            'click', 'a.dac-reference-nav-toggle', toggleResourcesHandler);
    +-      }
    +-    });
    +-
    +-    // No setup required if no resources are present
    +-    if (!resources.length) {
    +-      return;
    +-    }
    +-
    +-    // The resources should be a part of selected namespace.
    +-    var overview = addResourcesToView(resources, selected);
    +-
    +-    // Currently viewing Overview
    +-    if (location.href === overview.attr('href')) {
    +-      overview.parent().addClass('selected');
    +-    }
    +-
    +-    // Open currently selected resource
    +-    var listsToOpen = selected.children().eq(1);
    +-    listsToOpen = listsToOpen.add(
    +-        listsToOpen.find('.selected').parent()).show();
    +-
    +-    // Mark dropdowns as open
    +-    listsToOpen.prev().removeClass('dac-closed');
    +-
    +-    // Scroll into view
    +-    namespaceList.scrollIntoView(selected);
    +-  }
    +-
    +-  function getNavtreeFilePath(supportLibraryPath, currPath) {
    +-    var navtree_filepath = '';
    +-    var navtree_filename = 'navtree_data.js';
    +-    if (currPath.indexOf(supportLibraryPath + 'test') > -1) {
    +-      navtree_filepath = supportLibraryPath + 'test/' + navtree_filename;
    +-    } else if (currPath.indexOf(supportLibraryPath + 'wearable') > -1) {
    +-      navtree_filepath = supportLibraryPath + 'wearable/' + navtree_filename;
    +-    } else {
    +-      navtree_filepath = '/' + navtree_filename;
    +-    }
    +-    return navtree_filepath;
    +-  }
    +-
    +-  function updateSupportLibrariesNav(supportLibraryPath, currPath) {
    +-    var navTitle = '';
    +-    if (currPath.indexOf(supportLibraryPath + 'test') > -1) {
    +-      navTitle = 'Test Support APIs';
    +-    } else if (currPath.indexOf(supportLibraryPath + 'wearable') > -1) {
    +-      navTitle = 'Wearable Support APIs';
    +-    }
    +-    $('#api-nav-title').text(navTitle);
    +-    $('#api-level-toggle').hide();
    +-  }
    +-
    +-  /**
    +-   * Handles the toggling of resources.
    +-   * @param {Event} event
    +-   */
    +-  function toggleResourcesHandler(event) {
    +-    event.preventDefault();
    +-    if (event.type == 'click' || event.type == 'keypress' && event.which == 13) {
    +-      var el = $(this);
    +-      // If resources for given namespace is not present, fetch correct data.
    +-      if (this.tagName === 'A' && !this.hasResources) {
    +-        addResourcesToView(buildResourcesViewForData(getDataForNamespace(el.text())), el.parent());
    +-      }
    +-
    +-      el.toggleClass('dac-closed').next().slideToggle(200);
    +-    }
    +-  }
    +-
    +-  /**
    +-   * @param {String} namespace
    +-   * @returns {Array} namespace data
    +-   */
    +-  function getDataForNamespace(namespace) {
    +-    var namespaceData = NAVTREE_DATA.filter(function(data) {
    +-      return data[0] === namespace;
    +-    });
    +-
    +-    return namespaceData.length ? namespaceData[0][2] : [];
    +-  }
    +-
    +-  /**
    +-   * Build a list item for a resource
    +-   * @param {Array} resource
    +-   * @returns {String}
    +-   */
    +-  function buildResourceItem(resource) {
    +-    return '<li class="api apilevel-' + resource[3] + '"><a href="/' + resource[1] + '">' + resource[0] + '</a></li>';
    +-  }
    +-
    +-  /**
    +-   * Build resources list items.
    +-   * @param {Array} resources
    +-   * @returns {String}
    +-   */
    +-  function buildResourceList(resources) {
    +-    return '<li><h2>' + resources[0] + '</h2><ul>' + resources[2].map(buildResourceItem).join('') + '</ul>';
    +-  }
    +-
    +-  /**
    +-   * Build a resources view
    +-   * @param {Array} data
    +-   * @returns {jQuery} resources in an unordered list.
    +-   */
    +-  function buildResourcesViewForData(data) {
    +-    return $('<ul>' + data.map(buildResourceList).join('') + '</ul>');
    +-  }
    +-
    +-  /**
    +-   * Add resources to a containing view.
    +-   * @param {jQuery} resources
    +-   * @param {jQuery} view
    +-   * @returns {jQuery} the overview link.
    +-   */
    +-  function addResourcesToView(resources, view) {
    +-    var namespace = view.children().eq(0);
    +-    var overview = $('<a href="' + namespace.attr('href') + '">Overview</a>');
    +-
    +-    // Mark namespace with content;
    +-    namespace[0].hasResources = true;
    +-
    +-    // Add correct classes / event listeners to resources.
    +-    resources.prepend($('<li>').html(overview))
    +-      .find('a')
    +-        .addClass('dac-reference-nav-resource')
    +-      .end()
    +-        .find('h2').attr('tabindex', 0)
    +-        .addClass('dac-reference-nav-toggle dac-closed')
    +-        .on('click keypress', toggleResourcesHandler)
    +-      .end()
    +-        .add(resources.find('ul'))
    +-        .addClass('dac-reference-nav-resources')
    +-      .end()
    +-        .appendTo(view);
    +-
    +-    return overview;
    +-  }
    +-
    +-  function setActiveReferencePackage(el) {
    +-    var packageLinkEls = el.find('[data-reference-namespaces] a');
    +-    var selected = null;
    +-    var highestMatchCount = 0;
    +-    packageLinkEls.each(function(index, linkEl) {
    +-      var matchCount = 0;
    +-      $(location.pathname.split('/')).each(function(index, subpath) {
    +-        if (linkEl.href.indexOf('/' + subpath + '/') > -1) {
    +-          matchCount++;
    +-        }
    +-      });
    +-      if (matchCount > highestMatchCount) {
    +-        selected = linkEl;
    +-        highestMatchCount = matchCount;
    +-      }
    +-    });
    +-    $(selected).parent().addClass('selected');
    +-  }
    +-
    +-  /**
    +-   * jQuery plugin
    +-   */
    +-  $.fn.dacReferenceNav = function() {
    +-    return this.each(function() {
    +-      setActiveReferencePackage($(this));
    +-      buildReferenceNav($(this));
    +-    });
    +-  };
    +-})(jQuery);
    +-
    +-/** Scroll a container to make a target element visible
    +- This is called when the page finished loading. */
    +-$.fn.scrollIntoView = function(target) {
    +-  if ('string' === typeof target) {
    +-    target = this.find(target);
    +-  }
    +-  if (this.is(':visible')) {
    +-    if (target.length == 0) {
    +-      // If no selected item found, exit
    +-      return;
    +-    }
    +-
    +-    // get the target element's offset from its container nav by measuring the element's offset
    +-    // relative to the document then subtract the container nav's offset relative to the document
    +-    var targetOffset = target.offset().top - this.offset().top;
    +-    var containerHeight = this.height();
    +-    if (targetOffset > containerHeight * .8) { // multiply nav height by .8 so we move up the item
    +-      // if it's more than 80% down the nav
    +-      // scroll the item up by an amount equal to 80% the container height
    +-      this.scrollTop(targetOffset - (containerHeight * .8));
    +-    }
    +-  }
    +-};
    +-
    +-(function($) {
    +-  $.fn.dacCurrentPage = function() {
    +-    // Highlight the header tabs...
    +-    // highlight Design tab
    +-    var baseurl = getBaseUri(window.location.pathname);
    +-    var urlSegments = baseurl.split('/');
    +-    var navEl = this;
    +-    var body = $('body');
    +-    var subNavEl = navEl.find('.dac-nav-secondary');
    +-    var parentNavEl;
    +-    var selected;
    +-    // In NDK docs, highlight appropriate sub-nav
    +-    if (body.hasClass('dac-ndk')) {
    +-      if (body.hasClass('guide')) {
    +-        selected = navEl.find('> li.guides > a').addClass('selected');
    +-      } else if (body.hasClass('reference')) {
    +-        selected = navEl.find('> li.reference > a').addClass('selected');
    +-      } else if (body.hasClass('samples')) {
    +-        selected = navEl.find('> li.samples > a').addClass('selected');
    +-      } else if (body.hasClass('downloads')) {
    +-        selected = navEl.find('> li.downloads > a').addClass('selected');
    +-      }
    +-    } else if (body.hasClass('dac-studio')) {
    +-      if (body.hasClass('download')) {
    +-        selected = navEl.find('> li.download > a').addClass('selected');
    +-      } else if (body.hasClass('features')) {
    +-        selected = navEl.find('> li.features > a').addClass('selected');
    +-      } else if (body.hasClass('guide')) {
    +-        selected = navEl.find('> li.guide > a').addClass('selected');
    +-      } else if (body.hasClass('preview')) {
    +-        selected = navEl.find('> li.preview > a').addClass('selected');
    +-      }
    +-    } else if (body.hasClass('design')) {
    +-      selected = navEl.find('> li.design > a').addClass('selected');
    +-      // highlight Home nav
    +-    } else if (body.hasClass('about') || location.pathname == '/index.html') {
    +-      parentNavEl = navEl.find('> li.home > a');
    +-      parentNavEl.addClass('has-subnav');
    +-      // In Home docs, also highlight appropriate sub-nav
    +-      if (urlSegments[1] === 'wear' || urlSegments[1] === 'tv' ||
    +-        urlSegments[1] === 'auto') {
    +-        selected = subNavEl.find('li.' + urlSegments[1] + ' > a').addClass('selected');
    +-      } else if (urlSegments[1] === 'about') {
    +-        selected = subNavEl.find('li.versions > a').addClass('selected');
    +-      } else {
    +-        selected = parentNavEl.removeClass('has-subnav').addClass('selected');
    +-      }
    +-      // highlight Develop nav
    +-    } else if (body.hasClass('develop') || body.hasClass('google')) {
    +-      parentNavEl = navEl.find('> li.develop > a');
    +-      parentNavEl.addClass('has-subnav');
    +-      // In Develop docs, also highlight appropriate sub-nav
    +-      if (urlSegments[1] === 'training') {
    +-        selected = subNavEl.find('li.training > a').addClass('selected');
    +-      } else if (urlSegments[1] === 'guide') {
    +-        selected = subNavEl.find('li.guide > a').addClass('selected');
    +-      } else if (urlSegments[1] === 'reference') {
    +-        // If the root is reference, but page is also part of Google Services, select Google
    +-        if (body.hasClass('google')) {
    +-          selected = subNavEl.find('li.google > a').addClass('selected');
    +-        } else {
    +-          selected = subNavEl.find('li.reference > a').addClass('selected');
    +-        }
    +-      } else if (body.hasClass('google')) {
    +-        selected = subNavEl.find('li.google > a').addClass('selected');
    +-      } else if (body.hasClass('samples')) {
    +-        selected = subNavEl.find('li.samples > a').addClass('selected');
    +-      } else {
    +-        selected = parentNavEl.removeClass('has-subnav').addClass('selected');
    +-      }
    +-      // highlight Distribute nav
    +-    } else if (body.hasClass('distribute')) {
    +-      parentNavEl = navEl.find('> li.distribute > a');
    +-      parentNavEl.addClass('has-subnav');
    +-      // In Distribute docs, also highlight appropriate sub-nav
    +-      if (urlSegments[2] === 'users') {
    +-        selected = subNavEl.find('li.users > a').addClass('selected');
    +-      } else if (urlSegments[2] === 'engage') {
    +-        selected = subNavEl.find('li.engage > a').addClass('selected');
    +-      } else if (urlSegments[2] === 'monetize') {
    +-        selected = subNavEl.find('li.monetize > a').addClass('selected');
    +-      } else if (urlSegments[2] === 'analyze') {
    +-        selected = subNavEl.find('li.analyze > a').addClass('selected');
    +-      } else if (urlSegments[2] === 'tools') {
    +-        selected = subNavEl.find('li.disttools > a').addClass('selected');
    +-      } else if (urlSegments[2] === 'stories') {
    +-        selected = subNavEl.find('li.stories > a').addClass('selected');
    +-      } else if (urlSegments[2] === 'essentials') {
    +-        selected = subNavEl.find('li.essentials > a').addClass('selected');
    +-      } else if (urlSegments[2] === 'googleplay') {
    +-        selected = subNavEl.find('li.googleplay > a').addClass('selected');
    +-      } else {
    +-        selected = parentNavEl.removeClass('has-subnav').addClass('selected');
    +-      }
    +-    } else if (body.hasClass('preview')) {
    +-      selected = navEl.find('> li.preview > a').addClass('selected');
    +-    }
    +-    return $(selected);
    +-  };
    +-})(jQuery);
    +-
    +-(function($) {
    +-  'use strict';
    +-
    +-  /**
    +-   * Toggle the visabilty of the mobile navigation.
    +-   * @param {HTMLElement} el - The DOM element.
    +-   * @param {Object} options
    +-   * @constructor
    +-   */
    +-  function ToggleNav(el, options) {
    +-    this.el = $(el);
    +-    this.options = $.extend({}, ToggleNav.DEFAULTS_, options);
    +-    this.body = $(document.body);
    +-    this.navigation_ = this.body.find(this.options.navigation);
    +-    this.el.on('click', this.clickHandler_.bind(this));
    +-  }
    +-
    +-  ToggleNav.BREAKPOINT_ = 980;
    +-
    +-  /**
    +-   * Open on correct sizes
    +-   */
    +-  function toggleSidebarVisibility(body) {
    +-    var wasClosed = ('' + localStorage.getItem('navigation-open')) === 'false';
    +-    // Override the local storage setting for navigation-open for child sites
    +-    // with no-subnav class.
    +-    if (document.body.classList.contains('no-subnav')) {
    +-      wasClosed = false;
    +-    }
    +-
    +-    if (wasClosed) {
    +-      body.removeClass(ToggleNav.DEFAULTS_.activeClass);
    +-    } else if (window.innerWidth >= ToggleNav.BREAKPOINT_) {
    +-      body.addClass(ToggleNav.DEFAULTS_.activeClass);
    +-    } else {
    +-      body.removeClass(ToggleNav.DEFAULTS_.activeClass);
    +-    }
    +-  }
    +-
    +-  /**
    +-   * ToggleNav Default Settings
    +-   * @type {{body: boolean, dimmer: string, navigation: string, activeClass: string}}
    +-   * @private
    +-   */
    +-  ToggleNav.DEFAULTS_ = {
    +-    body: true,
    +-    dimmer: '.dac-nav-dimmer',
    +-    animatingClass: 'dac-nav-animating',
    +-    navigation: '[data-dac-nav]',
    +-    activeClass: 'dac-nav-open'
    +-  };
    +-
    +-  /**
    +-   * The actual toggle logic.
    +-   * @param {Event} event
    +-   * @private
    +-   */
    +-  ToggleNav.prototype.clickHandler_ = function(event) {
    +-    event.preventDefault();
    +-    var animatingClass = this.options.animatingClass;
    +-    var body = this.body;
    +-
    +-    body.addClass(animatingClass);
    +-    body.toggleClass(this.options.activeClass);
    +-
    +-    setTimeout(function() {
    +-      body.removeClass(animatingClass);
    +-    }, this.navigation_.transitionDuration());
    +-
    +-    if (window.innerWidth >= ToggleNav.BREAKPOINT_) {
    +-      localStorage.setItem('navigation-open', body.hasClass(this.options.activeClass));
    +-    }
    +-  };
    +-
    +-  /**
    +-   * jQuery plugin
    +-   * @param  {object} options - Override default options.
    +-   */
    +-  $.fn.dacToggleMobileNav = function() {
    +-    return this.each(function() {
    +-      var el = $(this);
    +-      new ToggleNav(el, el.data());
    +-    });
    +-  };
    +-
    +-  $.fn.dacSidebarToggle = function(body) {
    +-    toggleSidebarVisibility(body);
    +-    $(window).on('resize', toggleSidebarVisibility.bind(null, body));
    +-  };
    +-
    +-  /**
    +-   * Data Attribute API
    +-   */
    +-  $(function() {
    +-    $('[data-dac-toggle-nav]').dacToggleMobileNav();
    +-  });
    +-})(jQuery);
    +-
    +-(function($) {
    +-  'use strict';
    +-
    +-  /**
    +-   * Submit the newsletter form to a Google Form.
    +-   * @param {HTMLElement} el - The Form DOM element.
    +-   * @constructor
    +-   */
    +-  function NewsletterForm(el) {
    +-    this.el = $(el);
    +-    this.form = this.el.find('form');
    +-    $('<iframe/>').hide()
    +-      .attr('name', 'dac-newsletter-iframe')
    +-      .attr('src', '')
    +-      .insertBefore(this.form);
    +-    this.el.find('[data-newsletter-language]').val(window.polyglot.t('newsletter.languageVal'));
    +-    this.form.on('submit', this.submitHandler_.bind(this));
    +-  }
    +-
    +-  /**
    +-   * Milliseconds until modal has vanished after modal-close is triggered.
    +-   * @type {number}
    +-   * @private
    +-   */
    +-  NewsletterForm.CLOSE_DELAY_ = 300;
    +-
    +-  /**
    +-   * Switch view to display form after close.
    +-   * @private
    +-   */
    +-  NewsletterForm.prototype.closeHandler_ = function() {
    +-    setTimeout(function() {
    +-      this.el.trigger('swap-reset');
    +-    }.bind(this), NewsletterForm.CLOSE_DELAY_);
    +-  };
    +-
    +-  /**
    +-   * Reset the modal to initial state.
    +-   * @private
    +-   */
    +-  NewsletterForm.prototype.reset_ = function() {
    +-    this.form.trigger('reset');
    +-    this.el.one('modal-close', this.closeHandler_.bind(this));
    +-  };
    +-
    +-  /**
    +-   * Display a success view on submit.
    +-   * @private
    +-   */
    +-  NewsletterForm.prototype.submitHandler_ = function() {
    +-    this.el.one('swap-complete', this.reset_.bind(this));
    +-    this.el.trigger('swap-content');
    +-  };
    +-
    +-  /**
    +-   * jQuery plugin
    +-   * @param  {object} options - Override default options.
    +-   */
    +-  $.fn.dacNewsletterForm = function(options) {
    +-    return this.each(function() {
    +-      new NewsletterForm(this, options);
    +-    });
    +-  };
    +-
    +-  /**
    +-   * Data Attribute API
    +-   */
    +-  $(document).on('ready.aranja', function() {
    +-    $('[data-newsletter]').each(function() {
    +-      $(this).dacNewsletterForm();
    +-    });
    +-  });
    +-})(jQuery);
    +-
    +-/* globals METADATA, YOUTUBE_RESOURCES, BLOGGER_RESOURCES */
    +-window.metadata = {};
    +-
    +-/**
    +- * Prepare metadata and indices for querying.
    +- */
    +-window.metadata.prepare = (function() {
    +-  // Helper functions.
    +-  function mergeArrays() {
    +-    return Array.prototype.concat.apply([], arguments);
    +-  }
    +-
    +-  /**
    +-   * Creates lookup maps for a resource index.
    +-   * I.e. where MAP['some tag'][resource.id] === true when that resource has 'some tag'.
    +-   * @param resourceDict
    +-   * @returns {{}}
    +-   */
    +-  function buildResourceLookupMap(resourceDict) {
    +-    var map = {};
    +-    for (var key in resourceDict) {
    +-      var dictForKey = {};
    +-      var srcArr = resourceDict[key];
    +-      for (var i = 0; i < srcArr.length; i++) {
    +-        dictForKey[srcArr[i].index] = true;
    +-      }
    +-      map[key] = dictForKey;
    +-    }
    +-    return map;
    +-  }
    +-
    +-  /**
    +-   * Merges metadata maps for english and the current language into the global store.
    +-   */
    +-  function mergeMetadataMap(name, locale) {
    +-    if (locale && locale !== 'en' && METADATA[locale]) {
    +-      METADATA[name] = $.extend(METADATA.en[name], METADATA[locale][name]);
    +-    } else {
    +-      METADATA[name] = METADATA.en[name];
    +-    }
    +-  }
    +-
    +-  /**
    +-   * Index all resources by type, url, tag and category.
    +-   * @param resources
    +-   */
    +-  function createIndices(resources) {
    +-    // URL, type, tag and category lookups
    +-    var byType = METADATA.byType = {};
    +-    var byUrl = METADATA.byUrl = {};
    +-    var byTag = METADATA.byTag = {};
    +-    var byCategory = METADATA.byCategory = {};
    +-
    +-    for (var i = 0; i < resources.length; i++) {
    +-      var res = resources[i];
    +-
    +-      // Store index.
    +-      res.index = i;
    +-
    +-      // Index by type.
    +-      var type = res.type;
    +-      if (type) {
    +-        byType[type] = byType[type] || [];
    +-        byType[type].push(res);
    +-      }
    +-
    +-      // Index by tag.
    +-      var tags = res.tags || [];
    +-      for (var j = 0; j < tags.length; j++) {
    +-        var tag = tags[j];
    +-        if (tag) {
    +-          byTag[tag] = byTag[tag] || [];
    +-          byTag[tag].push(res);
    +-        }
    +-      }
    +-
    +-      // Index by category.
    +-      var category = res.category;
    +-      if (category) {
    +-        byCategory[category] = byCategory[category] || [];
    +-        byCategory[category].push(res);
    +-      }
    +-
    +-      // Index by url.
    +-      var url = res.url;
    +-      if (url) {
    +-        res.baseUrl = url.replace(/^intl\/\w+[\/]/, '');
    +-        byUrl[res.baseUrl] = res;
    +-      }
    +-    }
    +-    METADATA.hasType = buildResourceLookupMap(byType);
    +-    METADATA.hasTag = buildResourceLookupMap(byTag);
    +-    METADATA.hasCategory = buildResourceLookupMap(byCategory);
    +-  }
    +-
    +-  return function() {
    +-    // Only once.
    +-    if (METADATA.all) { return; }
    +-
    +-    // Get current language.
    +-    var locale = getLangPref();
    +-    // Merge english resources.
    +-    if (useDevsiteMetadata) {
    +-      var all_keys = Object.keys(METADATA['en']);
    +-      METADATA.all = []
    +-
    +-      $(all_keys).each(function(index, category) {
    +-        if (RESERVED_METADATA_CATEGORY_NAMES.indexOf(category) == -1) {
    +-          METADATA.all = mergeArrays(
    +-            METADATA.all,
    +-            METADATA.en[category]
    +-          );
    +-        }
    +-      });
    +-
    +-      METADATA.all = mergeArrays(
    +-        METADATA.all,
    +-        YOUTUBE_RESOURCES,
    +-        BLOGGER_RESOURCES,
    +-        METADATA.en.extras
    +-      );
    +-    } else {
    +-      METADATA.all = mergeArrays(
    +-        METADATA.en.about,
    +-        METADATA.en.design,
    +-        METADATA.en.distribute,
    +-        METADATA.en.develop,
    +-        YOUTUBE_RESOURCES,
    +-        BLOGGER_RESOURCES,
    +-        METADATA.en.extras
    +-      );
    +-    }
    +-
    +-    // Merge local language resources.
    +-    if (locale !== 'en' && METADATA[locale]) {
    +-      if (useDevsiteMetadata) {
    +-        all_keys = Object.keys(METADATA[locale]);
    +-        $(all_keys).each(function(index, category) {
    +-          if (RESERVED_METADATA_CATEGORY_NAMES.indexOf(category) == -1) {
    +-            METADATA.all = mergeArrays(
    +-              METADATA.all,
    +-              METADATA.en[category]
    +-            );
    +-          }
    +-        });
    +-
    +-        METADATA.all = mergeArrays(
    +-          METADATA.all,
    +-          METADATA[locale].extras
    +-        );
    +-      } else {
    +-        METADATA.all = mergeArrays(
    +-          METADATA.all,
    +-          METADATA[locale].about,
    +-          METADATA[locale].design,
    +-          METADATA[locale].distribute,
    +-          METADATA[locale].develop,
    +-          METADATA[locale].extras
    +-        );
    +-
    +-      }
    +-    }
    +-
    +-    mergeMetadataMap('collections', locale);
    +-    mergeMetadataMap('searchHeroCollections', locale);
    +-    mergeMetadataMap('carousel', locale);
    +-
    +-    // Create query indicies for resources.
    +-    createIndices(METADATA.all, locale);
    +-
    +-    // Reference metadata.
    +-    METADATA.androidReference = mergeArrays(
    +-        window.DATA, window.SUPPORT_WEARABLE_DATA, window.SUPPORT_TEST_DATA);
    +-    METADATA.googleReference = mergeArrays(window.GMS_DATA, window.GCM_DATA);
    +-  };
    +-})();
    +-
    +-/* global METADATA, util */
    +-window.metadata.query = (function($) {
    +-  var pageMap = {};
    +-
    +-  function buildResourceList(opts) {
    +-    window.metadata.prepare();
    +-    var expressions = parseResourceQuery(opts.query || '');
    +-    var instanceMap = {};
    +-    var results = [];
    +-
    +-    for (var i = 0; i < expressions.length; i++) {
    +-      var clauses = expressions[i];
    +-
    +-      // Get all resources for first clause
    +-      var resources = getResourcesForClause(clauses.shift());
    +-
    +-      // Concat to final results list
    +-      results = results.concat(resources.map(filterResources(clauses, i > 0, instanceMap)).filter(filterEmpty));
    +-    }
    +-
    +-    // Set correct order
    +-    if (opts.sortOrder && results.length) {
    +-      results = opts.sortOrder === 'random' ? util.shuffle(results) : results.sort(sortResultsByKey(opts.sortOrder));
    +-    }
    +-
    +-    // Slice max results.
    +-    if (opts.maxResults !== Infinity) {
    +-      results = results.slice(0, opts.maxResults);
    +-    }
    +-
    +-    // Remove page level duplicates
    +-    if (opts.allowDuplicates === undefined || opts.allowDuplicates === 'false') {
    +-      results = results.filter(removePageLevelDuplicates);
    +-
    +-      for (var index = 0; index < results.length; ++index) {
    +-        pageMap[results[index].index] = 1;
    +-      }
    +-    }
    +-
    +-    return results;
    +-  }
    +-
    +-  function filterResources(clauses, removeDuplicates, map) {
    +-    return function(resource) {
    +-      var resourceIsAllowed = true;
    +-
    +-      // References must be defined.
    +-      if (resource === undefined) {
    +-        return;
    +-      }
    +-
    +-      // Get canonical (localized) version of resource if possible.
    +-      resource = METADATA.byUrl[resource.baseUrl] || METADATA.byUrl[resource.url] || resource;
    +-
    +-      // Filter out resources already used
    +-      if (removeDuplicates) {
    +-        resourceIsAllowed = !map[resource.index];
    +-      }
    +-
    +-      // Must fulfill all criteria
    +-      if (clauses.length > 0) {
    +-        resourceIsAllowed = resourceIsAllowed && doesResourceMatchClauses(resource, clauses);
    +-      }
    +-
    +-      // Mark resource as used.
    +-      if (resourceIsAllowed) {
    +-        map[resource.index] = 1;
    +-      }
    +-
    +-      return resourceIsAllowed && resource;
    +-    };
    +-  }
    +-
    +-  function filterEmpty(resource) {
    +-    return resource;
    +-  }
    +-
    +-  function sortResultsByKey(key) {
    +-    var desc = key.charAt(0) === '-';
    +-
    +-    if (desc) {
    +-      key = key.substring(1);
    +-    }
    +-
    +-    return function(x, y) {
    +-      return (desc ? -1 : 1) * (parseInt(x[key], 10) - parseInt(y[key], 10));
    +-    };
    +-  }
    +-
    +-  function getResourcesForClause(clause) {
    +-    switch (clause.attr) {
    +-      case 'type':
    +-        return METADATA.byType[clause.value];
    +-      case 'tag':
    +-        return METADATA.byTag[clause.value];
    +-      case 'collection':
    +-        var resources = METADATA.collections[clause.value] || {};
    +-        return getResourcesByUrlCollection(resources.resources);
    +-      case 'history':
    +-        return getResourcesByUrlCollection($.dacGetVisitedUrls(clause.value));
    +-      case 'section':
    +-        return getResourcesByUrlCollection([clause.value].sections);
    +-      default:
    +-        return [];
    +-    }
    +-  }
    +-
    +-  function getResourcesByUrlCollection(resources) {
    +-    return (resources || []).map(function(url) {
    +-      return METADATA.byUrl[url];
    +-    });
    +-  }
    +-
    +-  function removePageLevelDuplicates(resource) {
    +-    return resource && !pageMap[resource.index];
    +-  }
    +-
    +-  function doesResourceMatchClauses(resource, clauses) {
    +-    for (var i = 0; i < clauses.length; i++) {
    +-      var map;
    +-      switch (clauses[i].attr) {
    +-        case 'type':
    +-          map = METADATA.hasType[clauses[i].value];
    +-          break;
    +-        case 'tag':
    +-          map = METADATA.hasTag[clauses[i].value];
    +-          break;
    +-      }
    +-
    +-      if (!map || (!!clauses[i].negative ? map[resource.index] : !map[resource.index])) {
    +-        return clauses[i].negative;
    +-      }
    +-    }
    +-
    +-    return true;
    +-  }
    +-
    +-  function parseResourceQuery(query) {
    +-    // Parse query into array of expressions (expression e.g. 'tag:foo + type:video')
    +-    var expressions = [];
    +-    var expressionStrs = query.split(',') || [];
    +-    for (var i = 0; i < expressionStrs.length; i++) {
    +-      var expr = expressionStrs[i] || '';
    +-
    +-      // Break expression into clauses (clause e.g. 'tag:foo')
    +-      var clauses = [];
    +-      var clauseStrs = expr.split(/(?=[\+\-])/);
    +-      for (var j = 0; j < clauseStrs.length; j++) {
    +-        var clauseStr = clauseStrs[j] || '';
    +-
    +-        // Get attribute and value from clause (e.g. attribute='tag', value='foo')
    +-        var parts = clauseStr.split(':');
    +-        var clause = {};
    +-
    +-        clause.attr = parts[0].replace(/^\s+|\s+$/g, '');
    +-        if (clause.attr) {
    +-          if (clause.attr.charAt(0) === '+') {
    +-            clause.attr = clause.attr.substring(1);
    +-          } else if (clause.attr.charAt(0) === '-') {
    +-            clause.negative = true;
    +-            clause.attr = clause.attr.substring(1);
    +-          }
    +-        }
    +-
    +-        if (parts.length > 1) {
    +-          clause.value = parts[1].replace(/^\s+|\s+$/g, '');
    +-        }
    +-
    +-        clauses.push(clause);
    +-      }
    +-
    +-      if (!clauses.length) {
    +-        continue;
    +-      }
    +-
    +-      expressions.push(clauses);
    +-    }
    +-
    +-    return expressions;
    +-  }
    +-
    +-  return buildResourceList;
    +-})(jQuery);
    +-
    +-/* global METADATA, getLangPref */
    +-
    +-window.metadata.search = (function() {
    +-  'use strict';
    +-
    +-  var currentLang = getLangPref();
    +-
    +-  function search(query) {
    +-    window.metadata.prepare();
    +-    return {
    +-      android: findDocsMatches(query, METADATA.androidReference),
    +-      docs: findDocsMatches(query, METADATA.googleReference),
    +-      resources: findResourceMatches(query)
    +-    };
    +-  }
    +-
    +-  function findDocsMatches(query, data) {
    +-    var results = [];
    +-
    +-    for (var i = 0; i < data.length; i++) {
    +-      var s = data[i];
    +-      if (query.length !== 0 && s.label.toLowerCase().indexOf(query.toLowerCase()) !== -1) {
    +-        results.push(s);
    +-      }
    +-    }
    +-
    +-    rankAutocompleteApiResults(query, results);
    +-
    +-    return results;
    +-  }
    +-
    +-  function findResourceMatches(query) {
    +-    var results = [];
    +-
    +-    // Search for matching JD docs
    +-    if (query.length >= 2) {
    +-      /* In some langs, spaces may be optional between certain non-Ascii word-glyphs. For
    +-       * those langs, only match query at word boundaries if query includes Ascii chars only.
    +-       */
    +-      var NO_BOUNDARY_LANGUAGES = ['ja','ko','vi','zh-cn','zh-tw'];
    +-      var isAsciiOnly = /^[\u0000-\u007f]*$/.test(query);
    +-      var noBoundaries = (NO_BOUNDARY_LANGUAGES.indexOf(window.getLangPref()) !== -1);
    +-      var exprBoundary = (!isAsciiOnly && noBoundaries) ? '' : '(?:^|\\s)';
    +-      var queryRegex = new RegExp(exprBoundary + query.toLowerCase(), 'g');
    +-
    +-      var all = METADATA.all;
    +-      for (var i = 0; i < all.length; i++) {
    +-        // current search comparison, with counters for tag and title,
    +-        // used later to improve ranking
    +-        var s = all[i];
    +-        s.matched_tag = 0;
    +-        s.matched_title = 0;
    +-        var matched = false;
    +-
    +-        // Check if query matches any tags; work backwards toward 1 to assist ranking
    +-        if (s.keywords) {
    +-          for (var j = s.keywords.length - 1; j >= 0; j--) {
    +-            // it matches a tag
    +-            if (s.keywords[j].toLowerCase().match(queryRegex)) {
    +-              matched = true;
    +-              s.matched_tag = j + 1; // add 1 to index position
    +-            }
    +-          }
    +-        }
    +-
    +-        // Check if query matches doc title
    +-        if (s.title.toLowerCase().match(queryRegex)) {
    +-          matched = true;
    +-          s.matched_title = 1;
    +-        }
    +-
    +-        // Remember the doc if it matches either
    +-        if (matched) {
    +-          results.push(s);
    +-        }
    +-      }
    +-
    +-      // Improve the current results
    +-      results = lookupBetterResult(results);
    +-
    +-      // Rank/sort all the matched pages
    +-      rankAutocompleteDocResults(results);
    +-
    +-      return results;
    +-    }
    +-  }
    +-
    +-  // Replaces a match with another resource by url, if it exists.
    +-  function lookupReplacementByUrl(match, url) {
    +-    var replacement = METADATA.byUrl[url];
    +-
    +-    // Replacement resource does not exists.
    +-    if (!replacement) { return; }
    +-
    +-    replacement.matched_title = Math.max(replacement.matched_title, match.matched_title);
    +-    replacement.matched_tag = Math.max(replacement.matched_tag, match.matched_tag);
    +-
    +-    return replacement;
    +-  }
    +-
    +-  // Find the localized version of a page if it exists.
    +-  function lookupLocalizedVersion(match) {
    +-    return METADATA.byUrl[match.baseUrl] || METADATA.byUrl[match.url];
    +-  }
    +-
    +-  // Find the main page for a tutorial when matching a subpage.
    +-  function lookupTutorialIndex(match) {
    +-    // Guard for non index tutorial pages.
    +-    if (match.type !== 'training' || match.url.indexOf('index.html') >= 0) { return; }
    +-
    +-    var indexUrl = match.url.replace(/[^\/]+$/, 'index.html');
    +-    return lookupReplacementByUrl(match, indexUrl);
    +-  }
    +-
    +-  // Find related results which are a better match for the user.
    +-  function lookupBetterResult(matches) {
    +-    var newMatches = [];
    +-
    +-    matches = matches.filter(function(match) {
    +-      var newMatch = match;
    +-      newMatch = lookupTutorialIndex(newMatch) || newMatch;
    +-      newMatch = lookupLocalizedVersion(newMatch) || newMatch;
    +-
    +-      if (newMatch !== match) {
    +-        newMatches.push(newMatch);
    +-      }
    +-
    +-      return newMatch === match;
    +-    });
    +-
    +-    return toUnique(newMatches.concat(matches));
    +-  }
    +-
    +-  /* Order the jd doc result list based on match quality */
    +-  function rankAutocompleteDocResults(matches) {
    +-    if (!matches || !matches.length) {
    +-      return;
    +-    }
    +-
    +-    var _resultScoreFn = function(match) {
    +-      var score = 1.0;
    +-
    +-      // if the query matched a tag
    +-      if (match.matched_tag > 0) {
    +-        // multiply score by factor relative to position in tags list (max of 3)
    +-        score *= 3 / match.matched_tag;
    +-
    +-        // if it also matched the title
    +-        if (match.matched_title > 0) {
    +-          score *= 2;
    +-        }
    +-      } else if (match.matched_title > 0) {
    +-        score *= 3;
    +-      }
    +-
    +-      if (match.lang === currentLang) {
    +-        score *= 5;
    +-      }
    +-
    +-      return score;
    +-    };
    +-
    +-    for (var i = 0; i < matches.length; i++) {
    +-      matches[i].__resultScore = _resultScoreFn(matches[i]);
    +-    }
    +-
    +-    matches.sort(function(a, b) {
    +-      var n = b.__resultScore - a.__resultScore;
    +-
    +-      if (n === 0) {
    +-        // lexicographical sort if scores are the same
    +-        n = (a.title < b.title) ? -1 : 1;
    +-      }
    +-
    +-      return n;
    +-    });
    +-  }
    +-
    +-  /* Order the result list based on match quality */
    +-  function rankAutocompleteApiResults(query, matches) {
    +-    query = query || '';
    +-    if (!matches || !matches.length) {
    +-      return;
    +-    }
    +-
    +-    // helper function that gets the last occurence index of the given regex
    +-    // in the given string, or -1 if not found
    +-    var _lastSearch = function(s, re) {
    +-      if (s === '') {
    +-        return -1;
    +-      }
    +-      var l = -1;
    +-      var tmp;
    +-      while ((tmp = s.search(re)) >= 0) {
    +-        if (l < 0) {
    +-          l = 0;
    +-        }
    +-        l += tmp;
    +-        s = s.substr(tmp + 1);
    +-      }
    +-      return l;
    +-    };
    +-
    +-    // helper function that counts the occurrences of a given character in
    +-    // a given string
    +-    var _countChar = function(s, c) {
    +-      var n = 0;
    +-      for (var i = 0; i < s.length; i++) {
    +-        if (s.charAt(i) === c) {
    +-          ++n;
    +-        }
    +-      }
    +-      return n;
    +-    };
    +-
    +-    var queryLower = query.toLowerCase();
    +-    var queryAlnum = (queryLower.match(/\w+/) || [''])[0];
    +-    var partPrefixAlnumRE = new RegExp('\\b' + queryAlnum);
    +-    var partExactAlnumRE = new RegExp('\\b' + queryAlnum + '\\b');
    +-
    +-    var _resultScoreFn = function(result) {
    +-      // scores are calculated based on exact and prefix matches,
    +-      // and then number of path separators (dots) from the last
    +-      // match (i.e. favoring classes and deep package names)
    +-      var score = 1.0;
    +-      var labelLower = result.label.toLowerCase();
    +-      var t;
    +-      var partsAfter;
    +-      t = _lastSearch(labelLower, partExactAlnumRE);
    +-      if (t >= 0) {
    +-        // exact part match
    +-        partsAfter = _countChar(labelLower.substr(t + 1), '.');
    +-        score *= 200 / (partsAfter + 1);
    +-      } else {
    +-        t = _lastSearch(labelLower, partPrefixAlnumRE);
    +-        if (t >= 0) {
    +-          // part prefix match
    +-          partsAfter = _countChar(labelLower.substr(t + 1), '.');
    +-          score *= 20 / (partsAfter + 1);
    +-        }
    +-      }
    +-
    +-      return score;
    +-    };
    +-
    +-    for (var i = 0; i < matches.length; i++) {
    +-      // if the API is deprecated, default score is 0; otherwise, perform scoring
    +-      if (matches[i].deprecated === 'true') {
    +-        matches[i].__resultScore = 0;
    +-      } else {
    +-        matches[i].__resultScore = _resultScoreFn(matches[i]);
    +-      }
    +-    }
    +-
    +-    matches.sort(function(a, b) {
    +-      var n = b.__resultScore - a.__resultScore;
    +-
    +-      if (n === 0) {
    +-        // lexicographical sort if scores are the same
    +-        n = (a.label < b.label) ? -1 : 1;
    +-      }
    +-
    +-      return n;
    +-    });
    +-  }
    +-
    +-  // Destructive but fast toUnique.
    +-  // http://stackoverflow.com/a/25082874
    +-  function toUnique(array) {
    +-    var c;
    +-    var b = array.length || 1;
    +-
    +-    while (c = --b) {
    +-      while (c--) {
    +-        if (array[b] === array[c]) {
    +-          array.splice(c, 1);
    +-        }
    +-      }
    +-    }
    +-    return array;
    +-  }
    +-
    +-  return search;
    +-})();
    +-
    +-(function($) {
    +-  'use strict';
    +-
    +-  /**
    +-   * Smoothly scroll to location on current page.
    +-   * @param el
    +-   * @param options
    +-   * @constructor
    +-   */
    +-  function ScrollButton(el, options) {
    +-    this.el = $(el);
    +-    this.target = $(this.el.attr('href'));
    +-    this.options = $.extend({}, ScrollButton.DEFAULTS_, options);
    +-
    +-    if (typeof this.options.offset === 'string') {
    +-      this.options.offset = $(this.options.offset).height();
    +-    }
    +-
    +-    this.el.on('click', this.clickHandler_.bind(this));
    +-  }
    +-
    +-  /**
    +-   * Default options
    +-   * @type {{duration: number, easing: string, offset: number, scrollContainer: string}}
    +-   * @private
    +-   */
    +-  ScrollButton.DEFAULTS_ = {
    +-    duration: 300,
    +-    easing: 'swing',
    +-    offset: '.dac-header',
    +-    scrollContainer: 'html, body'
    +-  };
    +-
    +-  /**
    +-   * Scroll logic
    +-   * @param event
    +-   * @private
    +-   */
    +-  ScrollButton.prototype.clickHandler_ = function(event) {
    +-    if (event.altKey || event.ctrlKey || event.metaKey || event.shiftKey) {
    +-      return;
    +-    }
    +-
    +-    event.preventDefault();
    +-
    +-    var position = this.getTargetPosition();
    +-    $(this.options.scrollContainer).animate({
    +-      scrollTop: position - this.options.offset
    +-    }, this.options);
    +-  };
    +-
    +-  ScrollButton.prototype.getTargetPosition = function() {
    +-    if (this.options.scrollContainer === ScrollButton.DEFAULTS_.scrollContainer) {
    +-      return this.target.offset().top;
    +-    }
    +-    var scrollContainer = $(this.options.scrollContainer)[0];
    +-    var currentEl = this.target[0];
    +-    var pos = 0;
    +-    while (currentEl !== scrollContainer && currentEl !== null) {
    +-      pos += currentEl.offsetTop;
    +-      currentEl = currentEl.offsetParent;
    +-    }
    +-    return pos;
    +-  };
    +-
    +-  /**
    +-   * jQuery plugin
    +-   * @param  {object} options - Override default options.
    +-   */
    +-  $.fn.dacScrollButton = function(options) {
    +-    return this.each(function() {
    +-      new ScrollButton(this, options);
    +-    });
    +-  };
    +-
    +-  /**
    +-   * Data Attribute API
    +-   */
    +-  $(document).on('ready.aranja', function() {
    +-    $('[data-scroll-button]').each(function() {
    +-      $(this).dacScrollButton($(this).data());
    +-    });
    +-  });
    +-})(jQuery);
    +-
    +-/* global getLangPref */
    +-(function($) {
    +-  var LANG;
    +-
    +-  function getSearchLang() {
    +-    if (!LANG) {
    +-      LANG = getLangPref();
    +-
    +-      // Fix zh-cn to be zh-CN.
    +-      LANG = LANG.replace(/-\w+/, function(m) { return m.toUpperCase(); });
    +-    }
    +-    return LANG;
    +-  }
    +-
    +-  function customSearch(query, start) {
    +-    var searchParams = {
    +-      // current cse instance:
    +-      //cx: '001482626316274216503:zu90b7s047u',
    +-      // new cse instance:
    +-      cx: '000521750095050289010:zpcpi1ea4s8',
    +-      key: 'AIzaSyCFhbGnjW06dYwvRCU8h_zjdpS4PYYbEe8',
    +-      q: query,
    +-      start: start || 1,
    +-      num: 9,
    +-      hl: getSearchLang(),
    +-      fields: 'queries,items(pagemap,link,title,htmlSnippet,formattedUrl)'
    +-    };
    +-
    +-    return $.get('https://content.googleapis.com/customsearch/v1?' +  $.param(searchParams));
    +-  }
    +-
    +-  function renderResults(el, results, searchAppliance) {
    +-    var referenceResults = searchAppliance.getReferenceResults();
    +-    if (!results.items) {
    +-      el.append($('<div>').text('No results'));
    +-      return;
    +-    }
    +-
    +-    for (var i = 0; i < results.items.length; i++) {
    +-      var item = results.items[i];
    +-      var isDuplicate = false;
    +-      $(referenceResults.android).each(function(index, result) {
    +-        if (item.link.indexOf(result.link) > -1) {
    +-          isDuplicate = true;
    +-          return false;
    +-        }
    +-      });
    +-
    +-      if (!isDuplicate) {
    +-        var hasImage = item.pagemap && item.pagemap.cse_thumbnail;
    +-        var sectionMatch = item.link.match(/developer\.android\.com\/(\w*)/);
    +-        var section = (sectionMatch && sectionMatch[1]) || 'blog';
    +-
    +-        var entry = $('<div>').addClass('dac-custom-search-entry cols');
    +-
    +-        if (hasImage) {
    +-          var image = item.pagemap.cse_thumbnail[0];
    +-          entry.append($('<div>').addClass('dac-custom-search-image-wrapper')
    +-            .append($('<div>').addClass('dac-custom-search-image').css('background-image', 'url(' + image.src + ')')));
    +-        }
    +-
    +-        entry.append($('<div>').addClass('dac-custom-search-text-wrapper')
    +-          .append($('<p>').addClass('dac-custom-search-section').text(section))
    +-          .append(
    +-            $('<a>').text(item.title).attr('href', item.link).wrap('<h2>').parent().addClass('dac-custom-search-title')
    +-          )
    +-          .append($('<p>').addClass('dac-custom-search-snippet').html(item.htmlSnippet.replace(/<br>/g, '')))
    +-          .append($('<a>').addClass('dac-custom-search-link').text(item.formattedUrl).attr('href', item.link)));
    +-
    +-        el.append(entry);
    +-      }
    +-    }
    +-
    +-    if (results.queries.nextPage) {
    +-      var loadMoreButton = $('<button id="dac-custom-search-load-more">')
    +-        .addClass('dac-custom-search-load-more')
    +-        .text('Load more')
    +-        .click(function() {
    +-          loadMoreResults(el, results, searchAppliance);
    +-        });
    +-
    +-      el.append(loadMoreButton);
    +-    }
    +-  };
    +-
    +-  function loadMoreResults(el, results, searchAppliance) {
    +-    var query = results.queries.request[0].searchTerms;
    +-    var start = results.queries.nextPage[0].startIndex;
    +-    var loadMoreButton = el.find('#dac-custom-search-load-more');
    +-
    +-    loadMoreButton.text('Loading more...');
    +-
    +-    customSearch(query, start).then(function(results) {
    +-      loadMoreButton.remove();
    +-      renderResults(el, results, searchAppliance);
    +-    });
    +-  }
    +-
    +-  $.fn.customSearch = function(query, searchAppliance) {
    +-    var el = $(this);
    +-
    +-    customSearch(query).then(function(results) {
    +-      el.empty();
    +-      renderResults(el, results, searchAppliance);
    +-    });
    +-  };
    +-})(jQuery);
    +-
    +-/* global METADATA */
    +-
    +-(function($) {
    +-  $.fn.dacSearchRenderHero = function(resources, query) {
    +-    var el = $(this);
    +-    el.empty();
    +-
    +-    var resource = METADATA.searchHeroCollections[query];
    +-
    +-    if (resource) {
    +-      el.dacHero(resource, true);
    +-      el.show();
    +-
    +-      return true;
    +-    } else {
    +-      el.hide();
    +-    }
    +-  };
    +-})(jQuery);
    +-
    +-(function($) {
    +-  $.fn.dacSearchRenderReferences = function(results, query) {
    +-    var referenceCard = $('.suggest-card.reference');
    +-    referenceCard.data('searchreferences.dac', {results: results, query: query});
    +-    renderResults(referenceCard, results, query, false);
    +-  };
    +-
    +-  var ROW_COUNT_COLLAPSED = 20;
    +-  var ROW_COUNT_EXPANDED = 40;
    +-  var ROW_COUNT_GOOGLE_COLLAPSED = 1;
    +-  var ROW_COUNT_GOOGLE_EXPANDED = 8;
    +-
    +-  function onSuggestionClick(e) {
    +-    devsite.analytics.trackAnalyticsEvent('event',
    +-        'Suggestion Click', 'clicked: ' + $(e.currentTarget).attr('href'),
    +-        'query: ' + $('#search_autocomplete').val().toLowerCase());
    +-  }
    +-
    +-  function buildLink(match) {
    +-    var link = $('<a>').attr('href', window.toRoot + match.link);
    +-
    +-    var label = match.label;
    +-    var classNameStart = label.match(/[A-Z]/) ? label.search(/[A-Z]/) : label.lastIndexOf('.') + 1;
    +-    var newLink = '<span class="namespace">' +
    +-      label.substr(0, classNameStart) +
    +-      '</span>' +
    +-      label.substr(classNameStart, label.length);
    +-
    +-    link.html(newLink);
    +-    return link;
    +-  }
    +-
    +-  function buildSuggestion(match, query) {
    +-    var li = $('<li>').addClass('dac-search-results-reference-entry');
    +-
    +-    var link = buildLink(match);
    +-    link.highlightMatches(query);
    +-    li.append(link);
    +-    return li[0];
    +-  }
    +-
    +-  function buildResults(results, query) {
    +-    return results.map(function(match) {
    +-      return buildSuggestion(match, query);
    +-    });
    +-  }
    +-
    +-  function renderAndroidResults(list, gMatches, query) {
    +-    list.empty();
    +-
    +-    var header = $('<li class="dac-search-results-reference-header">android APIs</li>');
    +-    list.append(header);
    +-
    +-    if (gMatches.length > 0) {
    +-      list.removeClass('no-results');
    +-
    +-      var resources = buildResults(gMatches, query);
    +-      list.append(resources);
    +-      return true;
    +-    } else {
    +-      list.append('<li class="dac-search-results-reference-entry-empty">No results</li>');
    +-    }
    +-  }
    +-
    +-  function renderGoogleDocsResults(list, gGoogleMatches, query) {
    +-    list = $('.suggest-card.reference ul');
    +-
    +-    if (gGoogleMatches.length > 0) {
    +-      list.append('<li class="dac-search-results-reference-header">in Google Services</li>');
    +-
    +-      var resources = buildResults(gGoogleMatches, query);
    +-      list.append(resources);
    +-
    +-      return true;
    +-    }
    +-  }
    +-
    +-  function renderResults(referenceCard, results, query, expanded) {
    +-    var list = referenceCard.find('ul');
    +-    list.toggleClass('is-expanded', !!expanded);
    +-
    +-    // Figure out how many results we can show in our fixed size box.
    +-    var total = expanded ? ROW_COUNT_EXPANDED : ROW_COUNT_COLLAPSED;
    +-    var googleCount = expanded ? ROW_COUNT_GOOGLE_EXPANDED : ROW_COUNT_GOOGLE_COLLAPSED;
    +-    googleCount = Math.max(googleCount, total - results.android.length);
    +-    googleCount = Math.min(googleCount, results.docs.length);
    +-
    +-    if (googleCount > 0) {
    +-      // If there are google results, reserve space for its header.
    +-      googleCount++;
    +-    }
    +-
    +-    var androidCount = Math.max(0, total - googleCount);
    +-    if (androidCount === 0) {
    +-      // Reserve space for "No reference results"
    +-      googleCount--;
    +-    }
    +-
    +-    renderAndroidResults(list, results.android.slice(0, androidCount), query);
    +-    renderGoogleDocsResults(list, results.docs.slice(0, googleCount - 1), query);
    +-
    +-    var totalResults = results.android.length + results.docs.length;
    +-    if (totalResults === 0) {
    +-      list.addClass('no-results');
    +-    }
    +-
    +-    // Tweak see more logic to account for references.
    +-    var hasMore = totalResults > ROW_COUNT_COLLAPSED && !util.matchesMedia('mobile');
    +-    if (hasMore) {
    +-      // We can't actually show all matches, only as many as the expanded list
    +-      // will fit, so we actually lie if the total results count is more
    +-      var moreCount = Math.min(totalResults, ROW_COUNT_EXPANDED + ROW_COUNT_GOOGLE_EXPANDED);
    +-      var $moreLink = $('<li class="dac-search-results-reference-entry-empty " data-toggle="show-more">see more matches</li>');
    +-      list.append($moreLink.on('click', onToggleMore));
    +-    }
    +-    var searchEl = $('#search-resources');
    +-    searchEl.toggleClass('dac-has-more', searchEl.hasClass('dac-has-more') || (hasMore && !expanded));
    +-    searchEl.toggleClass('dac-has-less', searchEl.hasClass('dac-has-less') || (hasMore && expanded));
    +-  }
    +-
    +-  function onToggleMore(e) {
    +-    var link = $(e.currentTarget);
    +-    var referenceCard = $('.suggest-card.reference');
    +-    var data = referenceCard.data('searchreferences.dac');
    +-
    +-    if (util.matchesMedia('mobile')) { return; }
    +-
    +-    renderResults(referenceCard, data.results, data.query, link.data('toggle') === 'show-more');
    +-  }
    +-
    +-  $(document).on('click', '.dac-search-results-resources [data-toggle="show-more"]', onToggleMore);
    +-  $(document).on('click', '.dac-search-results-resources [data-toggle="show-less"]', onToggleMore);
    +-  $(document).on('click', '.suggest-card.reference a', onSuggestionClick);
    +-})(jQuery);
    +-
    +-(function($) {
    +-  function highlightPage(query, page) {
    +-    page.find('.title').highlightMatches(query);
    +-  }
    +-
    +-  $.fn.dacSearchRenderResources = function(gDocsMatches, query) {
    +-    this.resourceWidget(gDocsMatches, {
    +-      itemsPerPage: 18,
    +-      initialResults: 6,
    +-      cardSizes: ['6x2'],
    +-      onRenderPage: highlightPage.bind(null, query)
    +-    });
    +-
    +-    return this;
    +-  };
    +-})(jQuery);
    +-
    +-/*global metadata */
    +-
    +-(function($, metadata) {
    +-  'use strict';
    +-
    +-  function Search() {
    +-    this.body = $('body');
    +-    this.lastQuery = null;
    +-    this.searchResults = $('#search-results');
    +-    this.searchClose = $('[data-search-close]');
    +-    this.searchClear = $('[data-search-clear]');
    +-    this.searchInput = $('#search_autocomplete');
    +-    this.searchResultsContent = $('#dac-search-results-content');
    +-    this.searchResultsFor = $('#search-results-for');
    +-    this.searchResultsHistory = $('#dac-search-results-history');
    +-    this.searchResultsResources = $('#search-resources');
    +-    this.searchResultsHero = $('#dac-search-results-hero');
    +-    this.searchResultsReference = $('#dac-search-results-reference');
    +-    this.searchHeader = $('[data-search]').data('search-input.dac');
    +-    this.pageNav = $('a[name=navigation]');
    +-    this.currQueryReferenceResults = {};
    +-    this.isOpen = false;
    +-  }
    +-
    +-  Search.prototype.init = function() {
    +-    this.searchHistory = window.dacStore('search-history');
    +-
    +-    this.searchInput.focus(this.onSearchChanged.bind(this));
    +-    this.searchInput.keypress(this.handleKeyboardShortcut.bind(this));
    +-    this.pageNav.keyup(this.handleTabbedToNav.bind(this));
    +-    this.searchResults.keyup(this.handleKeyboardShortcut.bind(this));
    +-    this.searchInput.on('input', this.onSearchChanged.bind(this));
    +-    this.searchClear.click(this.clear.bind(this));
    +-    this.searchClose.click(this.close.bind(this));
    +-
    +-    this.customSearch = $.fn.debounce(function(query) {
    +-      $('#dac-custom-search-results').customSearch(query, this);
    +-    }.bind(this), 1000);
    +-    // Start search shortcut (/)
    +-    $('body').keyup(function(event) {
    +-      if (event.which === 191 && $(event.target).is(':not(:input)')) {
    +-        this.searchInput.focus();
    +-      }
    +-    }.bind(this));
    +-
    +-    $(window).on('popstate', this.onPopState.bind(this));
    +-    $(window).hashchange(this.onHashChange.bind(this));
    +-    this.onHashChange();
    +-  };
    +-
    +-  Search.prototype.checkRedirectToIndex = function() {
    +-    var query = this.getUrlQuery();
    +-    var target = window.getLangTarget();
    +-    var prefix = (target !== 'en') ? '/intl/' + target : '';
    +-    var pathname = location.pathname.slice(prefix.length);
    +-    if (query != null && pathname !== '/index.html') {
    +-      location.href = prefix + '/index.html' + location.hash;
    +-      return true;
    +-    }
    +-  };
    +-
    +-  Search.prototype.handleKeyboardShortcut = function(event) {
    +-    // Close (esc)
    +-    if (event.which === 27) {
    +-      this.searchClose.trigger('click');
    +-      event.preventDefault();
    +-    }
    +-
    +-    // Previous result (up arrow)
    +-    if (event.which === 38) {
    +-      this.previousResult();
    +-      event.preventDefault();
    +-    }
    +-
    +-    // Next result (down arrow)
    +-    if (event.which === 40) {
    +-      this.nextResult();
    +-      event.preventDefault();
    +-    }
    +-
    +-    // Navigate to result (enter)
    +-    if (event.which === 13) {
    +-      this.navigateToResult();
    +-      event.preventDefault();
    +-    }
    +-  };
    +-
    +-  Search.prototype.handleTabbedToNav = function(event) {
    +-    if (this.isOpen) {
    +-      this.searchClose.trigger('click');
    +-    }
    +-  }
    +-
    +-  Search.prototype.goToResult = function(relativeIndex) {
    +-    var links = this.searchResults.find('a').filter(':visible');
    +-    var selectedLink = this.searchResults.find('.dac-selected');
    +-
    +-    if (selectedLink.length) {
    +-      var found = $.inArray(selectedLink[0], links);
    +-
    +-      selectedLink.removeClass('dac-selected');
    +-      links.eq(found + relativeIndex).addClass('dac-selected');
    +-      return true;
    +-    } else {
    +-      if (relativeIndex > 0) {
    +-        links.first().addClass('dac-selected');
    +-      }
    +-    }
    +-  };
    +-
    +-  Search.prototype.previousResult = function() {
    +-    this.goToResult(-1);
    +-  };
    +-
    +-  Search.prototype.nextResult = function() {
    +-    this.goToResult(1);
    +-  };
    +-
    +-  Search.prototype.navigateToResult = function() {
    +-    var query = this.getQuery();
    +-    var selectedLink = this.searchResults.find('.dac-selected');
    +-
    +-    if (selectedLink.length) {
    +-      selectedLink[0].click();
    +-    } else {
    +-      this.searchHistory.push(query);
    +-      this.addQueryToUrl(query);
    +-
    +-      var isMobileOrTablet = typeof window.orientation !== 'undefined';
    +-
    +-      if (isMobileOrTablet) {
    +-        this.searchInput.blur();
    +-      }
    +-    }
    +-  };
    +-
    +-  Search.prototype.onHashChange = function() {
    +-    var query = this.getUrlQuery();
    +-    if (query != null && query !== this.getQuery()) {
    +-      this.searchInput.val(query);
    +-      this.onSearchChanged();
    +-    }
    +-  };
    +-
    +-  Search.prototype.clear = function() {
    +-    this.searchInput.val('');
    +-    window.location.hash = '';
    +-    this.onSearchChanged();
    +-    this.searchInput.focus();
    +-  };
    +-
    +-  Search.prototype.close = function() {
    +-    this.removeQueryFromUrl();
    +-    this.searchInput.blur();
    +-    this.hideOverlay();
    +-    this.pageNav.focus();
    +-    this.isOpen = false;
    +-  };
    +-
    +-  Search.prototype.getUrlQuery = function() {
    +-    var queryMatch = location.hash.match(/q=(.*)&?/);
    +-    return queryMatch && queryMatch[1] && decodeURI(queryMatch[1]);
    +-  };
    +-
    +-  Search.prototype.getQuery = function() {
    +-    return this.searchInput.val().replace(/(^ +)|( +$)/g, '');
    +-  };
    +-
    +-  Search.prototype.getReferenceResults = function() {
    +-    return this.currQueryReferenceResults;
    +-  };
    +-
    +-  Search.prototype.onSearchChanged = function() {
    +-    var query = this.getQuery();
    +-
    +-    this.showOverlay();
    +-    this.render(query);
    +-  };
    +-
    +-  Search.prototype.render = function(query) {
    +-    if (this.lastQuery === query) { return; }
    +-
    +-    if (query.length < 2) {
    +-      query = '';
    +-    }
    +-
    +-    this.lastQuery = query;
    +-    this.searchResultsFor.text(query);
    +-
    +-    // CSE results lag behind the metadata/reference results. We need to empty
    +-    // the CSE results and add 'Loading' text so user's aren't looking at two
    +-    // different sets of search results at one time.
    +-    var $loadingEl =
    +-        $('<div class="loadingCustomSearchResults">Loading Results...</div>');
    +-    $('#dac-custom-search-results').empty().prepend($loadingEl);
    +-
    +-    this.customSearch(query);
    +-    var metadataResults = metadata.search(query);
    +-    this.searchResultsResources.dacSearchRenderResources(metadataResults.resources, query);
    +-    this.searchResultsReference.dacSearchRenderReferences(metadataResults, query);
    +-    this.currQueryReferenceResults = metadataResults;
    +-    var hasHero = this.searchResultsHero.dacSearchRenderHero(metadataResults.resources, query);
    +-    var hasQuery = !!query;
    +-
    +-    this.searchResultsReference.toggle(!hasHero);
    +-    this.searchResultsContent.toggle(hasQuery);
    +-    this.searchResultsHistory.toggle(!hasQuery);
    +-    this.addQueryToUrl(query);
    +-    this.pushState();
    +-  };
    +-
    +-  Search.prototype.addQueryToUrl = function(query) {
    +-    var hash = 'q=' + encodeURI(query);
    +-
    +-    if (query) {
    +-      if (window.history.replaceState) {
    +-        window.history.replaceState(null, '', '#' + hash);
    +-      } else {
    +-        window.location.hash = hash;
    +-      }
    +-    }
    +-  };
    +-
    +-  Search.prototype.onPopState = function() {
    +-    if (!this.getUrlQuery()) {
    +-      this.hideOverlay();
    +-      this.searchHeader.unsetActiveState();
    +-    }
    +-  };
    +-
    +-  Search.prototype.removeQueryFromUrl = function() {
    +-    window.location.hash = '';
    +-  };
    +-
    +-  Search.prototype.pushState = function() {
    +-    if (window.history.pushState && !this.lastQuery.length) {
    +-      window.history.pushState(null, '');
    +-    }
    +-  };
    +-
    +-  Search.prototype.showOverlay = function() {
    +-    this.isOpen = true;
    +-    this.body.addClass('dac-modal-open dac-search-open');
    +-  };
    +-
    +-  Search.prototype.hideOverlay = function() {
    +-    this.body.removeClass('dac-modal-open dac-search-open');
    +-  };
    +-
    +-  $(document).on('ready.aranja', function() {
    +-    var search = new Search();
    +-    search.init();
    +-  });
    +-})(jQuery, metadata);
    +-
    +-window.dacStore = (function(window) {
    +-  /**
    +-   * Creates a new persistent store.
    +-   * If localStorage is unavailable, the items are stored in memory.
    +-   *
    +-   * @constructor
    +-   * @param {string} name    The name of the store
    +-   * @param {number} maxSize The maximum number of items the store can hold.
    +-   */
    +-  var Store = function(name, maxSize) {
    +-    var content = [];
    +-
    +-    var hasLocalStorage = !!window.localStorage;
    +-
    +-    if (hasLocalStorage) {
    +-      try {
    +-        content = JSON.parse(window.localStorage.getItem(name) || []);
    +-      } catch (e) {
    +-        // Store contains invalid data
    +-        window.localStorage.removeItem(name);
    +-      }
    +-    }
    +-
    +-    function push(item) {
    +-      if (content[0] === item) {
    +-        return;
    +-      }
    +-
    +-      content.unshift(item);
    +-
    +-      if (maxSize) {
    +-        content.splice(maxSize, content.length);
    +-      }
    +-
    +-      if (hasLocalStorage) {
    +-        window.localStorage.setItem(name, JSON.stringify(content));
    +-      }
    +-    }
    +-
    +-    function all() {
    +-      // Return a copy
    +-      return content.slice();
    +-    }
    +-
    +-    return {
    +-      push: push,
    +-      all: all
    +-    };
    +-  };
    +-
    +-  var stores = {
    +-    'search-history': new Store('search-history', 3)
    +-  };
    +-
    +-  /**
    +-   * Get a named persistent store.
    +-   * @param  {string} name
    +-   * @return {Store}
    +-   */
    +-  return function getStore(name) {
    +-    return stores[name];
    +-  };
    +-})(window);
    +-
    +-(function($) {
    +-  'use strict';
    +-
    +-  /**
    +-   * A component that swaps two dynamic height views with an animation.
    +-   * Listens for the following events:
    +-   * * swap-content: triggers SwapContent.swap_()
    +-   * * swap-reset: triggers SwapContent.reset()
    +-   * @param el
    +-   * @param options
    +-   * @constructor
    +-   */
    +-  function SwapContent(el, options) {
    +-    this.el = $(el);
    +-    this.options = $.extend({}, SwapContent.DEFAULTS_, options);
    +-    this.options.dynamic = this.options.dynamic === 'true';
    +-    this.containers = this.el.find(this.options.container);
    +-    this.initiallyActive = this.containers.children('.' + this.options.activeClass).eq(0);
    +-    this.el.on('swap-content', this.swap.bind(this));
    +-    this.el.on('swap-reset', this.reset.bind(this));
    +-    this.el.find(this.options.swapButton).on('click keypress', function(e) {
    +-      if (e.type == 'keypress' && e.which == 13 || e.type == 'click') {
    +-        this.swap();
    +-      }
    +-    }.bind(this));
    +-  }
    +-
    +-  /**
    +-   * SwapContent's default settings.
    +-   * @type {{activeClass: string, container: string, transitionSpeed: number}}
    +-   * @private
    +-   */
    +-  SwapContent.DEFAULTS_ = {
    +-    activeClass: 'dac-active',
    +-    container: '[data-swap-container]',
    +-    dynamic: 'true',
    +-    swapButton: '[data-swap-button]',
    +-    transitionSpeed: 500
    +-  };
    +-
    +-  /**
    +-   * Returns container's visible height.
    +-   * @param container
    +-   * @returns {number}
    +-   */
    +-  SwapContent.prototype.currentHeight = function(container) {
    +-    return container.children('.' + this.options.activeClass).outerHeight();
    +-  };
    +-
    +-  /**
    +-   * Reset to show initial content
    +-   */
    +-  SwapContent.prototype.reset = function() {
    +-    if (!this.initiallyActive.hasClass(this.initiallyActive)) {
    +-      this.containers.children().toggleClass(this.options.activeClass);
    +-    }
    +-  };
    +-
    +-  /**
    +-   * Complete the swap.
    +-   */
    +-  SwapContent.prototype.complete = function() {
    +-    this.containers.height('auto');
    +-    this.containers.trigger('swap-complete');
    +-  };
    +-
    +-  /**
    +-   * Perform the swap of content.
    +-   */
    +-  SwapContent.prototype.swap = function() {
    +-    this.containers.each(function(index, container) {
    +-      container = $(container);
    +-
    +-      if (!this.options.dynamic) {
    +-        container.children().toggleClass(this.options.activeClass);
    +-        this.complete.bind(this);
    +-        $('.' + this.options.activeClass).focus();
    +-        return;
    +-      }
    +-
    +-      container.height(this.currentHeight(container)).children().toggleClass(this.options.activeClass);
    +-      container.animate({height: this.currentHeight(container)}, this.options.transitionSpeed,
    +-        this.complete.bind(this));
    +-    }.bind(this));
    +-  };
    +-
    +-  /**
    +-   * jQuery plugin
    +-   * @param  {object} options - Override default options.
    +-   */
    +-  $.fn.dacSwapContent = function(options) {
    +-    return this.each(function() {
    +-      new SwapContent(this, options);
    +-    });
    +-  };
    +-
    +-  /**
    +-   * Data Attribute API
    +-   */
    +-  $(document).on('ready.aranja', function() {
    +-    $('[data-swap]').each(function() {
    +-      $(this).dacSwapContent($(this).data());
    +-    });
    +-  });
    +-})(jQuery);
    +-
    +-/* Tabs */
    +-(function($) {
    +-  'use strict';
    +-
    +-  /**
    +-   * @param {HTMLElement} el - The DOM element.
    +-   * @param {Object} options
    +-   * @constructor
    +-   */
    +-  function Tabs(el, options) {
    +-    this.el = $(el);
    +-    this.options = $.extend({}, Tabs.DEFAULTS_, options);
    +-    this.init();
    +-  }
    +-
    +-  Tabs.DEFAULTS_ = {
    +-    activeClass: 'dac-active',
    +-    viewDataAttr: 'tab-view',
    +-    itemDataAttr: 'tab-item'
    +-  };
    +-
    +-  Tabs.prototype.init = function() {
    +-    var itemDataAttribute = '[data-' + this.options.itemDataAttr + ']';
    +-    this.tabEl_ = this.el.find(itemDataAttribute);
    +-    this.tabViewEl_ = this.el.find('[data-' + this.options.viewDataAttr + ']');
    +-    this.el.on('click.dac-tabs', itemDataAttribute, this.changeTabs.bind(this));
    +-  };
    +-
    +-  Tabs.prototype.changeTabs = function(event) {
    +-    var current = $(event.currentTarget);
    +-    var index = current.index();
    +-
    +-    if (current.hasClass(this.options.activeClass)) {
    +-      current.add(this.tabViewEl_.eq(index)).removeClass(this.options.activeClass);
    +-    } else {
    +-      this.tabEl_.add(this.tabViewEl_).removeClass(this.options.activeClass);
    +-      current.add(this.tabViewEl_.eq(index)).addClass(this.options.activeClass);
    +-    }
    +-  };
    +-
    +-  /**
    +-   * jQuery plugin
    +-   */
    +-  $.fn.dacTabs = function() {
    +-    return this.each(function() {
    +-      var el = $(this);
    +-      new Tabs(el, el.data());
    +-    });
    +-  };
    +-
    +-  /**
    +-   * Data Attribute API
    +-   */
    +-  $(function() {
    +-    $('[data-tabs]').dacTabs();
    +-  });
    +-})(jQuery);
    +-
    +-/* Toast Component */
    +-(function($) {
    +-  'use strict';
    +-  /**
    +-   * @constant
    +-   * @type {String}
    +-   */
    +-  var LOCAL_STORAGE_KEY = 'toast-closed-index';
    +-
    +-  /**
    +-   * Dictionary from local storage.
    +-   */
    +-  var toastDictionary = localStorage.getItem(LOCAL_STORAGE_KEY);
    +-  toastDictionary = toastDictionary ? JSON.parse(toastDictionary) : {};
    +-
    +-  /**
    +-   * Variable used for caching the body.
    +-   */
    +-  var bodyCached;
    +-
    +-  /**
    +-   * @param {HTMLElement} el - The DOM element.
    +-   * @param {Object} options
    +-   * @constructor
    +-   */
    +-  function Toast(el, options) {
    +-    this.el = $(el);
    +-    this.options = $.extend({}, Toast.DEFAULTS_, options);
    +-    this.init();
    +-  }
    +-
    +-  Toast.DEFAULTS_ = {
    +-    closeBtnClass: 'dac-toast-close-btn',
    +-    closeDuration: 200,
    +-    visibleClass: 'dac-visible',
    +-    wrapClass: 'dac-toast-wrap'
    +-  };
    +-
    +-  /**
    +-   * Generate a close button.
    +-   * @returns {*|HTMLElement}
    +-   */
    +-  Toast.prototype.closeBtn = function() {
    +-    this.closeBtnEl = this.closeBtnEl || $('<button class="' + this.options.closeBtnClass + '">' +
    +-      '<span class="dac-button dac-raised dac-primary">OK</span>' +
    +-    '</button>');
    +-    return this.closeBtnEl;
    +-  };
    +-
    +-  /**
    +-   * Initialize a new toast element
    +-   */
    +-  Toast.prototype.init = function() {
    +-    this.hash = this.el.text().replace(/[\s\n\t]/g, '').split('').slice(0, 128).join('');
    +-
    +-    if (toastDictionary[this.hash]) {
    +-      return;
    +-    }
    +-
    +-    this.closeBtn().on('click', this.onClickHandler.bind(this));
    +-    this.el.find('.' + this.options.wrapClass).append(this.closeBtn());
    +-    this.el.addClass(this.options.visibleClass);
    +-    this.dynamicPadding(this.el.outerHeight());
    +-  };
    +-
    +-  /**
    +-   * Add padding to make sure all page is visible.
    +-   */
    +-  Toast.prototype.dynamicPadding = function(val) {
    +-    var currentPadding = parseInt(bodyCached.css('padding-bottom') || 0);
    +-    bodyCached.css('padding-bottom', val + currentPadding);
    +-  };
    +-
    +-  /**
    +-   * Remove a toast from the DOM
    +-   */
    +-  Toast.prototype.remove = function() {
    +-    this.dynamicPadding(-this.el.outerHeight());
    +-    this.el.remove();
    +-  };
    +-
    +-  /**
    +-   * Handle removal of the toast.
    +-   */
    +-  Toast.prototype.onClickHandler = function() {
    +-    // Only fadeout toasts from top of stack. Others are removed immediately.
    +-    var duration = this.el.index() === 0 ? this.options.closeDuration : 0;
    +-    this.el.fadeOut(duration, this.remove.bind(this));
    +-
    +-    // Save closed state.
    +-    toastDictionary[this.hash] = 1;
    +-    localStorage.setItem(LOCAL_STORAGE_KEY, JSON.stringify(toastDictionary));
    +-  };
    +-
    +-  /**
    +-   * jQuery plugin
    +-   * @param  {object} options - Override default options.
    +-   */
    +-  $.fn.dacToast = function() {
    +-    return this.each(function() {
    +-      var el = $(this);
    +-      new Toast(el, el.data());
    +-    });
    +-  };
    +-
    +-  /**
    +-   * Data Attribute API
    +-   */
    +-  $(function() {
    +-    bodyCached = $('#body-content');
    +-    $('[data-toast]').dacToast();
    +-  });
    +-})(jQuery);
    +-
    +-(function($) {
    +-  function Toggle(el) {
    +-    $(el).on('click.dac.togglesection', this.toggle);
    +-  }
    +-
    +-  Toggle.prototype.toggle = function() {
    +-    var $this = $(this);
    +-
    +-    var $parent = getParent($this);
    +-    var isExpanded = $parent.hasClass('is-expanded');
    +-
    +-    transitionMaxHeight($parent.find('.dac-toggle-content'), !isExpanded);
    +-    $parent.toggleClass('is-expanded');
    +-
    +-    return false;
    +-  };
    +-
    +-  function getParent($this) {
    +-    var selector = $this.attr('data-target');
    +-
    +-    if (!selector) {
    +-      selector = $this.attr('href');
    +-      selector = selector && /#[A-Za-z]/.test(selector) && selector.replace(/.*(?=#[^\s]*$)/, '');
    +-    }
    +-
    +-    var $parent = selector && $(selector);
    +-
    +-    $parent = $parent && $parent.length ? $parent : $this.closest('.dac-toggle');
    +-
    +-    return $parent.length ? $parent : $this.parent();
    +-  }
    +-
    +-  /**
    +-   * Runs a transition of max-height along with responsive styles which hide or expand the element.
    +-   * @param $el
    +-   * @param visible
    +-   */
    +-  function transitionMaxHeight($el, visible) {
    +-    var contentHeight = $el.prop('scrollHeight');
    +-    var targetHeight = visible ? contentHeight : 0;
    +-    var duration = $el.transitionDuration();
    +-
    +-    // If we're hiding, first set the maxHeight we're transitioning from.
    +-    if (!visible) {
    +-      $el.css({
    +-          transitionDuration: '0s',
    +-          maxHeight: contentHeight + 'px'
    +-        })
    +-        .resolveStyles()
    +-        .css('transitionDuration', '');
    +-    }
    +-
    +-    // Transition to new state
    +-    $el.css('maxHeight', targetHeight);
    +-
    +-    // Reset maxHeight to css value after transition.
    +-    setTimeout(function() {
    +-      $el.css({
    +-          transitionDuration: '0s',
    +-          maxHeight: ''
    +-        })
    +-        .resolveStyles()
    +-        .css('transitionDuration', '');
    +-    }, duration);
    +-  }
    +-
    +-  // Utility to get the transition duration for the element.
    +-  $.fn.transitionDuration = function() {
    +-    var d = $(this).css('transitionDuration') || '0s';
    +-
    +-    return +(parseFloat(d) * (/ms/.test(d) ? 1 : 1000)).toFixed(0);
    +-  };
    +-
    +-  // jQuery plugin
    +-  $.fn.toggleSection = function(option) {
    +-    return this.each(function() {
    +-      var $this = $(this);
    +-      var data = $this.data('dac.togglesection');
    +-      if (!data) {$this.data('dac.togglesection', (data = new Toggle(this)));}
    +-      if (typeof option === 'string') {data[option].call($this);}
    +-    });
    +-  };
    +-
    +-  // Data api
    +-  $(document)
    +-    .on('click.toggle', '[data-toggle="section"]', Toggle.prototype.toggle);
    +-})(jQuery);
    +-
    +-(function(window) {
    +-  /**
    +-   * Media query breakpoints. Should match CSS.
    +-   */
    +-  var BREAKPOINTS = {
    +-    mobile: [0, 719],
    +-    tablet: [720, 959],
    +-    desktop: [960, 9999]
    +-  };
    +-
    +-  /**
    +-   * Fisher-Yates Shuffle (Knuth shuffle).
    +-   * @param {Array} input
    +-   * @returns {Array} shuffled array.
    +-   */
    +-  function shuffle(input) {
    +-    for (var i = input.length; i >= 0; i--) {
    +-      var randomIndex = Math.floor(Math.random() * (i + 1));
    +-      var randomItem = input[randomIndex];
    +-      input[randomIndex] = input[i];
    +-      input[i] = randomItem;
    +-    }
    +-
    +-    return input;
    +-  }
    +-
    +-  /**
    +-   * Matches media breakpoints like in CSS.
    +-   * @param {string} form of either mobile, tablet or desktop.
    +-   */
    +-  function matchesMedia(form) {
    +-    var breakpoint = BREAKPOINTS[form];
    +-    return window.innerWidth >= breakpoint[0] && window.innerWidth <= breakpoint[1];
    +-  }
    +-
    +-  window.util = {
    +-    shuffle: shuffle,
    +-    matchesMedia: matchesMedia
    +-  };
    +-})(window);
    +-
    +-(function($, window) {
    +-  'use strict';
    +-
    +-  var YouTubePlayer = (function() {
    +-    var player;
    +-
    +-    function VideoPlayer() {
    +-      this.mPlayerPaused = false;
    +-      this.doneSetup = false;
    +-    }
    +-
    +-    VideoPlayer.prototype.setup = function() {
    +-      // loads the IFrame Player API code asynchronously.
    +-      $.getScript('https://www.youtube.com/iframe_api');
    +-
    +-      // Add the shadowbox HTML to the body
    +-      $('body').prepend(
    +-'<div id="video-player" class="Video">' +
    +-  '<div id="video-overlay" class="Video-overlay" />' +
    +-  '<div class="Video-container">' +
    +-    '<div class="Video-frame">' +
    +-      '<span class="Video-loading">Loading&hellip;</span>' +
    +-      '<div id="youTubePlayer"></div>' +
    +-    '</div>' +
    +-    '<div class="Video-controls">' +
    +-      '<button id="picture-in-picture" class="Video-button Video-button--picture-in-picture">' +
    +-      '<button id="close-video" class="Video-button Video-button--close" />' +
    +-    '</div>' +
    +-  '</div>' +
    +-'</div>');
    +-
    +-      this.videoPlayer = $('#video-player');
    +-
    +-      var pictureInPictureButton = this.videoPlayer.find('#picture-in-picture');
    +-      pictureInPictureButton.on('click.aranja', this.toggleMinimizeVideo.bind(this));
    +-
    +-      var videoOverlay = this.videoPlayer.find('#video-overlay');
    +-      var closeButton = this.videoPlayer.find('#close-video');
    +-      var closeVideo = this.closeVideo.bind(this);
    +-      videoOverlay.on('click.aranja', closeVideo);
    +-      closeButton.on('click.aranja', closeVideo);
    +-
    +-      this.doneSetup = true;
    +-    };
    +-
    +-    VideoPlayer.prototype.startYouTubePlayer = function(videoId) {
    +-      this.videoPlayer.show();
    +-
    +-      if (!this.isLoaded) {
    +-        this.queueVideo = videoId;
    +-        return;
    +-      }
    +-
    +-      this.mPlayerPaused = false;
    +-      // check if we've already created this player
    +-      if (!this.youTubePlayer) {
    +-        // check if there's a start time specified
    +-        var idAndHash = videoId.split('#');
    +-        var startTime = 0;
    +-        if (idAndHash.length > 1) {
    +-          startTime = idAndHash[1].split('t=')[1] !== undefined ? idAndHash[1].split('t=')[1] : 0;
    +-        }
    +-        // enable localized player
    +-        var lang = getLangPref();
    +-        var captionsOn = lang === 'en' ? 0 : 1;
    +-
    +-        this.youTubePlayer = new YT.Player('youTubePlayer', {
    +-          height: 720,
    +-          width: 1280,
    +-          videoId: idAndHash[0],
    +-          // jscs:disable requireCamelCaseOrUpperCaseIdentifiers
    +-          playerVars: {start: startTime, hl: lang, cc_load_policy: captionsOn},
    +-          // jscs:enable
    +-          events: {
    +-            'onReady': this.onPlayerReady.bind(this),
    +-            'onStateChange': this.onPlayerStateChange.bind(this)
    +-          }
    +-        });
    +-      } else {
    +-        // if a video different from the one already playing was requested, cue it up
    +-        if (videoId !== this.getVideoId()) {
    +-          this.youTubePlayer.cueVideoById(videoId);
    +-        }
    +-        this.youTubePlayer.playVideo();
    +-      }
    +-    };
    +-
    +-    VideoPlayer.prototype.onPlayerReady = function(event) {
    +-      if (!isMobile) {
    +-        event.target.playVideo();
    +-        this.mPlayerPaused = false;
    +-      }
    +-    };
    +-
    +-    VideoPlayer.prototype.toggleMinimizeVideo = function(event) {
    +-      event.stopPropagation();
    +-      this.videoPlayer.toggleClass('Video--picture-in-picture');
    +-    };
    +-
    +-    VideoPlayer.prototype.closeVideo = function() {
    +-      try {
    +-        this.youTubePlayer.pauseVideo();
    +-      } catch (e) {
    +-      }
    +-      this.videoPlayer.fadeOut(200, function() {
    +-        this.videoPlayer.removeClass('Video--picture-in-picture');
    +-      }.bind(this));
    +-    };
    +-
    +-    VideoPlayer.prototype.getVideoId = function() {
    +-      // jscs:disable requireCamelCaseOrUpperCaseIdentifiers
    +-      return this.youTubePlayer && this.youTubePlayer.getVideoData().video_id;
    +-      // jscs:enable
    +-    };
    +-
    +-    /* Track youtube playback for analytics */
    +-    VideoPlayer.prototype.onPlayerStateChange = function(event) {
    +-      var videoId = this.getVideoId();
    +-      var currentTime = this.youTubePlayer && this.youTubePlayer.getCurrentTime();
    +-
    +-      // Video starts, send the video ID
    +-      if (event.data === YT.PlayerState.PLAYING) {
    +-        if (this.mPlayerPaused) {
    +-          devsite.analytics.trackAnalyticsEvent('event',
    +-              'Videos', 'Resume', videoId);
    +-        } else {
    +-          // track the start playing event so we know from which page the video was selected
    +-          devsite.analytics.trackAnalyticsEvent('event',
    +-              'Videos', 'Start: ' + videoId, 'on: ' + document.location.href);
    +-        }
    +-        this.mPlayerPaused = false;
    +-      }
    +-
    +-      // Video paused, send video ID and video elapsed time
    +-      if (event.data === YT.PlayerState.PAUSED) {
    +-        devsite.analytics.trackAnalyticsEvent('event',
    +-            'Videos', 'Paused: ' + videoId, 'on: ' + currentTime);
    +-        this.mPlayerPaused = true;
    +-      }
    +-
    +-      // Video finished, send video ID and video elapsed time
    +-      if (event.data === YT.PlayerState.ENDED) {
    +-        devsite.analytics.trackAnalyticsEvent('event',
    +-            'Videos', 'Finished: ' + videoId, 'on: ' + currentTime);
    +-        this.mPlayerPaused = true;
    +-      }
    +-    };
    +-
    +-    return {
    +-      getPlayer: function() {
    +-        if (!player) {
    +-          player = new VideoPlayer();
    +-        }
    +-
    +-        return player;
    +-      }
    +-    };
    +-  })();
    +-
    +-  var videoPlayer = YouTubePlayer.getPlayer();
    +-
    +-  window.onYouTubeIframeAPIReady = function() {
    +-    videoPlayer.isLoaded = true;
    +-
    +-    if (videoPlayer.queueVideo) {
    +-      videoPlayer.startYouTubePlayer(videoPlayer.queueVideo);
    +-    }
    +-  };
    +-
    +-  function wrapLinkInPlayer(e) {
    +-    e.preventDefault();
    +-
    +-    if (!videoPlayer.doneSetup) {
    +-      videoPlayer.setup();
    +-    }
    +-
    +-    var videoIdMatches = $(e.currentTarget).attr('href').match(/(?:youtu.be\/|v=)([^&]*)/);
    +-    var videoId = videoIdMatches && videoIdMatches[1];
    +-
    +-    if (videoId) {
    +-      videoPlayer.startYouTubePlayer(videoId);
    +-    }
    +-  }
    +-
    +-  $(document).on('click.video', 'a[href*="youtube.com/watch"], a[href*="youtu.be"]', wrapLinkInPlayer);
    +-})(jQuery, window);
    +-
    +-/**
    +- * Wide table
    +- *
    +- * Wraps tables in a scrollable area so you can read them on mobile.
    +- */
    +-(function($) {
    +-  function initWideTable() {
    +-    $('table.jd-sumtable').each(function(i, table) {
    +-      $(table).wrap('<div class="dac-expand wide-table">');
    +-    });
    +-  }
    +-
    +-  $(function() {
    +-    initWideTable();
    +-  });
    +-})(jQuery);
    +-
    +-/** Utilities */
    +-
    +-/* returns the given string with all HTML brackets converted to entities
    +-    TODO: move this to the site's JS library */
    +-function escapeHTML(string) {
    +-  return string.replace(/</g,"&lt;")
    +-                .replace(/>/g,"&gt;");
    +-};
    +-
    +-function getQueryVariable(variable) {
    +-  var query = window.location.search.substring(1);
    +-  var vars = query.split("&");
    +-  for (var i=0;i<vars.length;i++) {
    +-    var pair = vars[i].split("=");
    +-    if(pair[0] == variable){return pair[1];}
    +-  }
    +-  return(false);
    +-};
    +diff --git a/tools/droiddoc/templates-sdk-dev/assets/js/prettify.js b/tools/droiddoc/templates-sdk-dev/assets/js/prettify.js
    +deleted file mode 100644
    +index eef5ad7..0000000
    +--- a/tools/droiddoc/templates-sdk-dev/assets/js/prettify.js
    ++++ /dev/null
    +@@ -1,28 +0,0 @@
    +-var q=null;window.PR_SHOULD_USE_CONTINUATION=!0;
    +-(function(){function L(a){function m(a){var f=a.charCodeAt(0);if(f!==92)return f;var b=a.charAt(1);return(f=r[b])?f:"0"<=b&&b<="7"?parseInt(a.substring(1),8):b==="u"||b==="x"?parseInt(a.substring(2),16):a.charCodeAt(1)}function e(a){if(a<32)return(a<16?"\\x0":"\\x")+a.toString(16);a=String.fromCharCode(a);if(a==="\\"||a==="-"||a==="["||a==="]")a="\\"+a;return a}function h(a){for(var f=a.substring(1,a.length-1).match(/\\u[\dA-Fa-f]{4}|\\x[\dA-Fa-f]{2}|\\[0-3][0-7]{0,2}|\\[0-7]{1,2}|\\[\S\s]|[^\\]/g),a=
    +-[],b=[],o=f[0]==="^",c=o?1:0,i=f.length;c<i;++c){var j=f[c];if(/\\[bdsw]/i.test(j))a.push(j);else{var j=m(j),d;c+2<i&&"-"===f[c+1]?(d=m(f[c+2]),c+=2):d=j;b.push([j,d]);d<65||j>122||(d<65||j>90||b.push([Math.max(65,j)|32,Math.min(d,90)|32]),d<97||j>122||b.push([Math.max(97,j)&-33,Math.min(d,122)&-33]))}}b.sort(function(a,f){return a[0]-f[0]||f[1]-a[1]});f=[];j=[NaN,NaN];for(c=0;c<b.length;++c)i=b[c],i[0]<=j[1]+1?j[1]=Math.max(j[1],i[1]):f.push(j=i);b=["["];o&&b.push("^");b.push.apply(b,a);for(c=0;c<
    +-f.length;++c)i=f[c],b.push(e(i[0])),i[1]>i[0]&&(i[1]+1>i[0]&&b.push("-"),b.push(e(i[1])));b.push("]");return b.join("")}function y(a){for(var f=a.source.match(/\[(?:[^\\\]]|\\[\S\s])*]|\\u[\dA-Fa-f]{4}|\\x[\dA-Fa-f]{2}|\\\d+|\\[^\dux]|\(\?[!:=]|[()^]|[^()[\\^]+/g),b=f.length,d=[],c=0,i=0;c<b;++c){var j=f[c];j==="("?++i:"\\"===j.charAt(0)&&(j=+j.substring(1))&&j<=i&&(d[j]=-1)}for(c=1;c<d.length;++c)-1===d[c]&&(d[c]=++t);for(i=c=0;c<b;++c)j=f[c],j==="("?(++i,d[i]===void 0&&(f[c]="(?:")):"\\"===j.charAt(0)&&
    +-(j=+j.substring(1))&&j<=i&&(f[c]="\\"+d[i]);for(i=c=0;c<b;++c)"^"===f[c]&&"^"!==f[c+1]&&(f[c]="");if(a.ignoreCase&&s)for(c=0;c<b;++c)j=f[c],a=j.charAt(0),j.length>=2&&a==="["?f[c]=h(j):a!=="\\"&&(f[c]=j.replace(/[A-Za-z]/g,function(a){a=a.charCodeAt(0);return"["+String.fromCharCode(a&-33,a|32)+"]"}));return f.join("")}for(var t=0,s=!1,l=!1,p=0,d=a.length;p<d;++p){var g=a[p];if(g.ignoreCase)l=!0;else if(/[a-z]/i.test(g.source.replace(/\\u[\da-f]{4}|\\x[\da-f]{2}|\\[^UXux]/gi,""))){s=!0;l=!1;break}}for(var r=
    +-{b:8,t:9,n:10,v:11,f:12,r:13},n=[],p=0,d=a.length;p<d;++p){g=a[p];if(g.global||g.multiline)throw Error(""+g);n.push("(?:"+y(g)+")")}return RegExp(n.join("|"),l?"gi":"g")}function M(a){function m(a){switch(a.nodeType){case 1:if(e.test(a.className))break;for(var g=a.firstChild;g;g=g.nextSibling)m(g);g=a.nodeName;if("BR"===g||"LI"===g)h[s]="\n",t[s<<1]=y++,t[s++<<1|1]=a;break;case 3:case 4:g=a.nodeValue,g.length&&(g=p?g.replace(/\r\n?/g,"\n"):g.replace(/[\t\n\r ]+/g," "),h[s]=g,t[s<<1]=y,y+=g.length,
    +-t[s++<<1|1]=a)}}var e=/(?:^|\s)nocode(?:\s|$)/,h=[],y=0,t=[],s=0,l;a.currentStyle?l=a.currentStyle.whiteSpace:window.getComputedStyle&&(l=document.defaultView.getComputedStyle(a,q).getPropertyValue("white-space"));var p=l&&"pre"===l.substring(0,3);m(a);return{a:h.join("").replace(/\n$/,""),c:t}}function B(a,m,e,h){m&&(a={a:m,d:a},e(a),h.push.apply(h,a.e))}function x(a,m){function e(a){for(var l=a.d,p=[l,"pln"],d=0,g=a.a.match(y)||[],r={},n=0,z=g.length;n<z;++n){var f=g[n],b=r[f],o=void 0,c;if(typeof b===
    +-"string")c=!1;else{var i=h[f.charAt(0)];if(i)o=f.match(i[1]),b=i[0];else{for(c=0;c<t;++c)if(i=m[c],o=f.match(i[1])){b=i[0];break}o||(b="pln")}if((c=b.length>=5&&"lang-"===b.substring(0,5))&&!(o&&typeof o[1]==="string"))c=!1,b="src";c||(r[f]=b)}i=d;d+=f.length;if(c){c=o[1];var j=f.indexOf(c),k=j+c.length;o[2]&&(k=f.length-o[2].length,j=k-c.length);b=b.substring(5);B(l+i,f.substring(0,j),e,p);B(l+i+j,c,C(b,c),p);B(l+i+k,f.substring(k),e,p)}else p.push(l+i,b)}a.e=p}var h={},y;(function(){for(var e=a.concat(m),
    +-l=[],p={},d=0,g=e.length;d<g;++d){var r=e[d],n=r[3];if(n)for(var k=n.length;--k>=0;)h[n.charAt(k)]=r;r=r[1];n=""+r;p.hasOwnProperty(n)||(l.push(r),p[n]=q)}l.push(/[\S\s]/);y=L(l)})();var t=m.length;return e}function u(a){var m=[],e=[];a.tripleQuotedStrings?m.push(["str",/^(?:'''(?:[^'\\]|\\[\S\s]|''?(?=[^']))*(?:'''|$)|"""(?:[^"\\]|\\[\S\s]|""?(?=[^"]))*(?:"""|$)|'(?:[^'\\]|\\[\S\s])*(?:'|$)|"(?:[^"\\]|\\[\S\s])*(?:"|$))/,q,"'\""]):a.multiLineStrings?m.push(["str",/^(?:'(?:[^'\\]|\\[\S\s])*(?:'|$)|"(?:[^"\\]|\\[\S\s])*(?:"|$)|`(?:[^\\`]|\\[\S\s])*(?:`|$))/,
    +-q,"'\"`"]):m.push(["str",/^(?:'(?:[^\n\r'\\]|\\.)*(?:'|$)|"(?:[^\n\r"\\]|\\.)*(?:"|$))/,q,"\"'"]);a.verbatimStrings&&e.push(["str",/^@"(?:[^"]|"")*(?:"|$)/,q]);var h=a.hashComments;h&&(a.cStyleComments?(h>1?m.push(["com",/^#(?:##(?:[^#]|#(?!##))*(?:###|$)|.*)/,q,"#"]):m.push(["com",/^#(?:(?:define|elif|else|endif|error|ifdef|include|ifndef|line|pragma|undef|warning)\b|[^\n\r]*)/,q,"#"]),e.push(["str",/^<(?:(?:(?:\.\.\/)*|\/?)(?:[\w-]+(?:\/[\w-]+)+)?[\w-]+\.h|[a-z]\w*)>/,q])):m.push(["com",/^#[^\n\r]*/,
    +-q,"#"]));a.cStyleComments&&(e.push(["com",/^\/\/[^\n\r]*/,q]),e.push(["com",/^\/\*[\S\s]*?(?:\*\/|$)/,q]));a.regexLiterals&&e.push(["lang-regex",/^(?:^^\.?|[!+-]|!=|!==|#|%|%=|&|&&|&&=|&=|\(|\*|\*=|\+=|,|-=|->|\/|\/=|:|::|;|<|<<|<<=|<=|=|==|===|>|>=|>>|>>=|>>>|>>>=|[?@[^]|\^=|\^\^|\^\^=|{|\||\|=|\|\||\|\|=|~|break|case|continue|delete|do|else|finally|instanceof|return|throw|try|typeof)\s*(\/(?=[^*/])(?:[^/[\\]|\\[\S\s]|\[(?:[^\\\]]|\\[\S\s])*(?:]|$))+\/)/]);(h=a.types)&&e.push(["typ",h]);a=(""+a.keywords).replace(/^ | $/g,
    +-"");a.length&&e.push(["kwd",RegExp("^(?:"+a.replace(/[\s,]+/g,"|")+")\\b"),q]);m.push(["pln",/^\s+/,q," \r\n\t\xa0"]);e.push(["lit",/^@[$_a-z][\w$@]*/i,q],["typ",/^(?:[@_]?[A-Z]+[a-z][\w$@]*|\w+_t\b)/,q],["pln",/^[$_a-z][\w$@]*/i,q],["lit",/^(?:0x[\da-f]+|(?:\d(?:_\d+)*\d*(?:\.\d*)?|\.\d\+)(?:e[+-]?\d+)?)[a-z]*/i,q,"0123456789"],["pln",/^\\[\S\s]?/,q],["pun",/^.[^\s\w"-$'./@\\`]*/,q]);return x(m,e)}function D(a,m){function e(a){switch(a.nodeType){case 1:if(k.test(a.className))break;if("BR"===a.nodeName)h(a),
    +-a.parentNode&&a.parentNode.removeChild(a);else for(a=a.firstChild;a;a=a.nextSibling)e(a);break;case 3:case 4:if(p){var b=a.nodeValue,d=b.match(t);if(d){var c=b.substring(0,d.index);a.nodeValue=c;(b=b.substring(d.index+d[0].length))&&a.parentNode.insertBefore(s.createTextNode(b),a.nextSibling);h(a);c||a.parentNode.removeChild(a)}}}}function h(a){function b(a,d){var e=d?a.cloneNode(!1):a,f=a.parentNode;if(f){var f=b(f,1),g=a.nextSibling;f.appendChild(e);for(var h=g;h;h=g)g=h.nextSibling,f.appendChild(h)}return e}
    +-for(;!a.nextSibling;)if(a=a.parentNode,!a)return;for(var a=b(a.nextSibling,0),e;(e=a.parentNode)&&e.nodeType===1;)a=e;d.push(a)}var k=/(?:^|\s)nocode(?:\s|$)/,t=/\r\n?|\n/,s=a.ownerDocument,l;a.currentStyle?l=a.currentStyle.whiteSpace:window.getComputedStyle&&(l=s.defaultView.getComputedStyle(a,q).getPropertyValue("white-space"));var p=l&&"pre"===l.substring(0,3);for(l=s.createElement("LI");a.firstChild;)l.appendChild(a.firstChild);for(var d=[l],g=0;g<d.length;++g)e(d[g]);m===(m|0)&&d[0].setAttribute("value",
    +-m);var r=s.createElement("OL");r.className="linenums";for(var n=Math.max(0,m-1|0)||0,g=0,z=d.length;g<z;++g)l=d[g],l.className="L"+(g+n)%10,l.firstChild||l.appendChild(s.createTextNode("\xa0")),r.appendChild(l);a.appendChild(r)}function k(a,m){for(var e=m.length;--e>=0;){var h=m[e];A.hasOwnProperty(h)?window.console&&console.warn("cannot override language handler %s",h):A[h]=a}}function C(a,m){if(!a||!A.hasOwnProperty(a))a=/^\s*</.test(m)?"default-markup":"default-code";return A[a]}function E(a){var m=
    +-a.g;try{var e=M(a.h),h=e.a;a.a=h;a.c=e.c;a.d=0;C(m,h)(a);var k=/\bMSIE\b/.test(navigator.userAgent),m=/\n/g,t=a.a,s=t.length,e=0,l=a.c,p=l.length,h=0,d=a.e,g=d.length,a=0;d[g]=s;var r,n;for(n=r=0;n<g;)d[n]!==d[n+2]?(d[r++]=d[n++],d[r++]=d[n++]):n+=2;g=r;for(n=r=0;n<g;){for(var z=d[n],f=d[n+1],b=n+2;b+2<=g&&d[b+1]===f;)b+=2;d[r++]=z;d[r++]=f;n=b}for(d.length=r;h<p;){var o=l[h+2]||s,c=d[a+2]||s,b=Math.min(o,c),i=l[h+1],j;if(i.nodeType!==1&&(j=t.substring(e,b))){k&&(j=j.replace(m,"\r"));i.nodeValue=
    +-j;var u=i.ownerDocument,v=u.createElement("SPAN");v.className=d[a+1];var x=i.parentNode;x.replaceChild(v,i);v.appendChild(i);e<o&&(l[h+1]=i=u.createTextNode(t.substring(b,o)),x.insertBefore(i,v.nextSibling))}e=b;e>=o&&(h+=2);e>=c&&(a+=2)}}catch(w){"console"in window&&console.log(w&&w.stack?w.stack:w)}}var v=["break,continue,do,else,for,if,return,while"],w=[[v,"auto,case,char,const,default,double,enum,extern,float,goto,int,long,register,short,signed,sizeof,static,struct,switch,typedef,union,unsigned,void,volatile"],
    +-"catch,class,delete,false,import,new,operator,private,protected,public,this,throw,true,try,typeof"],F=[w,"alignof,align_union,asm,axiom,bool,concept,concept_map,const_cast,constexpr,decltype,dynamic_cast,explicit,export,friend,inline,late_check,mutable,namespace,nullptr,reinterpret_cast,static_assert,static_cast,template,typeid,typename,using,virtual,where"],G=[w,"abstract,boolean,byte,extends,final,finally,implements,import,instanceof,null,native,package,strictfp,super,synchronized,throws,transient"],
    +-H=[G,"as,base,by,checked,decimal,delegate,descending,dynamic,event,fixed,foreach,from,group,implicit,in,interface,internal,into,is,lock,object,out,override,orderby,params,partial,readonly,ref,sbyte,sealed,stackalloc,string,select,uint,ulong,unchecked,unsafe,ushort,var"],w=[w,"debugger,eval,export,function,get,null,set,undefined,var,with,Infinity,NaN"],I=[v,"and,as,assert,class,def,del,elif,except,exec,finally,from,global,import,in,is,lambda,nonlocal,not,or,pass,print,raise,try,with,yield,False,True,None"],
    +-J=[v,"alias,and,begin,case,class,def,defined,elsif,end,ensure,false,in,module,next,nil,not,or,redo,rescue,retry,self,super,then,true,undef,unless,until,when,yield,BEGIN,END"],v=[v,"case,done,elif,esac,eval,fi,function,in,local,set,then,until"],K=/^(DIR|FILE|vector|(de|priority_)?queue|list|stack|(const_)?iterator|(multi)?(set|map)|bitset|u?(int|float)\d*)/,N=/\S/,O=u({keywords:[F,H,w,"caller,delete,die,do,dump,elsif,eval,exit,foreach,for,goto,if,import,last,local,my,next,no,our,print,package,redo,require,sub,undef,unless,until,use,wantarray,while,BEGIN,END"+
    +-I,J,v],hashComments:!0,cStyleComments:!0,multiLineStrings:!0,regexLiterals:!0}),A={};k(O,["default-code"]);k(x([],[["pln",/^[^<?]+/],["dec",/^<!\w[^>]*(?:>|$)/],["com",/^<\!--[\S\s]*?(?:--\>|$)/],["lang-",/^<\?([\S\s]+?)(?:\?>|$)/],["lang-",/^<%([\S\s]+?)(?:%>|$)/],["pun",/^(?:<[%?]|[%?]>)/],["lang-",/^<xmp\b[^>]*>([\S\s]+?)<\/xmp\b[^>]*>/i],["lang-js",/^<script\b[^>]*>([\S\s]*?)(<\/script\b[^>]*>)/i],["lang-css",/^<style\b[^>]*>([\S\s]*?)(<\/style\b[^>]*>)/i],["lang-in.tag",/^(<\/?[a-z][^<>]*>)/i]]),
    +-["default-markup","htm","html","mxml","xhtml","xml","xsl"]);k(x([["pln",/^\s+/,q," \t\r\n"],["atv",/^(?:"[^"]*"?|'[^']*'?)/,q,"\"'"]],[["tag",/^^<\/?[a-z](?:[\w-.:]*\w)?|\/?>$/i],["atn",/^(?!style[\s=]|on)[a-z](?:[\w:-]*\w)?/i],["lang-uq.val",/^=\s*([^\s"'>]*(?:[^\s"'/>]|\/(?=\s)))/],["pun",/^[/<->]+/],["lang-js",/^on\w+\s*=\s*"([^"]+)"/i],["lang-js",/^on\w+\s*=\s*'([^']+)'/i],["lang-js",/^on\w+\s*=\s*([^\s"'>]+)/i],["lang-css",/^style\s*=\s*"([^"]+)"/i],["lang-css",/^style\s*=\s*'([^']+)'/i],["lang-css",
    +-/^style\s*=\s*([^\s"'>]+)/i]]),["in.tag"]);k(x([],[["atv",/^[\S\s]+/]]),["uq.val"]);k(u({keywords:F,hashComments:!0,cStyleComments:!0,types:K}),["c","cc","cpp","cxx","cyc","m"]);k(u({keywords:"null,true,false"}),["json"]);k(u({keywords:H,hashComments:!0,cStyleComments:!0,verbatimStrings:!0,types:K}),["cs"]);k(u({keywords:G,cStyleComments:!0}),["java"]);k(u({keywords:v,hashComments:!0,multiLineStrings:!0}),["bsh","csh","sh"]);k(u({keywords:I,hashComments:!0,multiLineStrings:!0,tripleQuotedStrings:!0}),
    +-["cv","py"]);k(u({keywords:"caller,delete,die,do,dump,elsif,eval,exit,foreach,for,goto,if,import,last,local,my,next,no,our,print,package,redo,require,sub,undef,unless,until,use,wantarray,while,BEGIN,END",hashComments:!0,multiLineStrings:!0,regexLiterals:!0}),["perl","pl","pm"]);k(u({keywords:J,hashComments:!0,multiLineStrings:!0,regexLiterals:!0}),["rb"]);k(u({keywords:w,cStyleComments:!0,regexLiterals:!0}),["js"]);k(u({keywords:"all,and,by,catch,class,else,extends,false,finally,for,if,in,is,isnt,loop,new,no,not,null,of,off,on,or,return,super,then,true,try,unless,until,when,while,yes",
    +-hashComments:3,cStyleComments:!0,multilineStrings:!0,tripleQuotedStrings:!0,regexLiterals:!0}),["coffee"]);k(x([],[["str",/^[\S\s]+/]]),["regex"]);window.prettyPrintOne=function(a,m,e){var h=document.createElement("PRE");h.innerHTML=a;e&&D(h,e);E({g:m,i:e,h:h});return h.innerHTML};window.prettyPrint=function(a){function m(){for(var e=window.PR_SHOULD_USE_CONTINUATION?l.now()+250:Infinity;p<h.length&&l.now()<e;p++){var n=h[p],k=n.className;if(k.indexOf("prettyprint")>=0){var k=k.match(g),f,b;if(b=
    +-!k){b=n;for(var o=void 0,c=b.firstChild;c;c=c.nextSibling)var i=c.nodeType,o=i===1?o?b:c:i===3?N.test(c.nodeValue)?b:o:o;b=(f=o===b?void 0:o)&&"CODE"===f.tagName}b&&(k=f.className.match(g));k&&(k=k[1]);b=!1;for(o=n.parentNode;o;o=o.parentNode)if((o.tagName==="pre"||o.tagName==="code"||o.tagName==="xmp")&&o.className&&o.className.indexOf("prettyprint")>=0){b=!0;break}b||((b=(b=n.className.match(/\blinenums\b(?::(\d+))?/))?b[1]&&b[1].length?+b[1]:!0:!1)&&D(n,b),d={g:k,h:n,i:b},E(d))}}p<h.length?setTimeout(m,
    +-250):a&&a()}for(var e=[document.getElementsByTagName("pre"),document.getElementsByTagName("code"),document.getElementsByTagName("xmp")],h=[],k=0;k<e.length;++k)for(var t=0,s=e[k].length;t<s;++t)h.push(e[k][t]);var e=q,l=Date;l.now||(l={now:function(){return+new Date}});var p=0,d,g=/\blang(?:uage)?-([\w.]+)(?!\S)/;m()};window.PR={createSimpleLexer:x,registerLangHandler:k,sourceDecorator:u,PR_ATTRIB_NAME:"atn",PR_ATTRIB_VALUE:"atv",PR_COMMENT:"com",PR_DECLARATION:"dec",PR_KEYWORD:"kwd",PR_LITERAL:"lit",
    +-PR_NOCODE:"nocode",PR_PLAIN:"pln",PR_PUNCTUATION:"pun",PR_SOURCE:"src",PR_STRING:"str",PR_TAG:"tag",PR_TYPE:"typ"}})();
    +diff --git a/tools/droiddoc/templates-sdk-dev/body_tag.cs b/tools/droiddoc/templates-sdk-dev/body_tag.cs
    +deleted file mode 100644
    +index 5761b71..0000000
    +--- a/tools/droiddoc/templates-sdk-dev/body_tag.cs
    ++++ /dev/null
    +@@ -1,15 +0,0 @@
    +-<body class="gc-documentation <?cs
    +-  if:(reference.gms || reference.gcm)
    +-    ?>google<?cs
    +-  /if ?><?cs
    +-  if:(guide||develop||training||reference||tools||sdk)
    +-    ?>develop<?cs
    +-    if:reference
    +-      ?> reference api apilevel-<?cs var:class.since ?><?cs var:package.since ?><?cs
    +-    /if ?><?cs
    +-  elif:design
    +-    ?>design<?cs
    +-  elif:distribute
    +-    ?>distribute<?cs
    +-  /if ?>">
    +-<div id="doc-api-level" class="<?cs var:class.since ?><?cs var:package.since ?>" style="display:none"></div>
    +diff --git a/tools/droiddoc/templates-sdk-dev/class.cs b/tools/droiddoc/templates-sdk-dev/class.cs
    +deleted file mode 100644
    +index dee7a4c..0000000
    +--- a/tools/droiddoc/templates-sdk-dev/class.cs
    ++++ /dev/null
    +@@ -1,646 +0,0 @@
    +-<?cs # THIS CREATES A CLASS OR INTERFACE PAGE FROM .java FILES ?>
    +-<?cs include:"macros.cs" ?>
    +-<?cs include:"macros_override.cs" ?>
    +-<?cs
    +-####################
    +-# MACRO FUNCTION USED ONLY IN THIS TEMPLATE TO GENERATE API REFERENCE
    +-# FIRST, THE FUNCTIONS FOR THE SUMMARY AT THE TOP OF THE PAGE
    +-####################
    +-?>
    +-
    +-<?cs
    +-# Prints the table cells for the summary of methods.
    +-?><?cs def:write_method_summary(methods, included) ?>
    +-<?cs set:count = #1 ?>
    +-<?cs each:method = methods ?>
    +-  <?cs # The apilevel-N class MUST BE LAST in the sequence of class names ?>
    +-  <tr class="api apilevel-<?cs var:method.since ?>" >
    +-  <?cs # leave out this cell if there is no return type = if constructors ?>
    +-  <?cs if:subcount(method.returnType) ?>
    +-    <td><code>
    +-        <?cs var:method.abstract ?>
    +-        <?cs var:method.default ?>
    +-        <?cs var:method.static ?>
    +-        <?cs var:method.final ?>
    +-        <?cs call:type_link(method.generic) ?>
    +-        <?cs call:type_link(method.returnType) ?></code>
    +-    </td>
    +-  <?cs /if ?>
    +-    <td width="100%">
    +-      <code>
    +-      <?cs call:cond_link(method.name, toroot, method.href, included) ?>(<?cs call:parameter_list(method.params, 0) ?>)
    +-      </code>
    +-      <?cs if:subcount(method.shortDescr) || subcount(method.deprecated) ?>
    +-        <p><?cs call:short_descr(method) ?>
    +-        <?cs call:show_annotations_list(method) ?></p>
    +-      <?cs /if ?>
    +-    </td>
    +-  </tr>
    +-  <?cs set:count = count + #1 ?>
    +-<?cs /each ?>
    +-<?cs /def ?>
    +-
    +-<?cs
    +-# Print the table cells for the summary of fields.
    +-?><?cs def:write_field_summary(fields, included) ?>
    +-<?cs set:count = #1 ?>
    +-<?cs each:field=fields ?>
    +-  <tr class="api apilevel-<?cs var:field.since ?>" >
    +-    <td><code>
    +-    <?cs var:field.scope ?>
    +-    <?cs var:field.static ?>
    +-    <?cs var:field.final ?>
    +-    <?cs call:type_link(field.type) ?></code></td>
    +-    <td width="100%">
    +-      <code><?cs call:cond_link(field.name, toroot, field.href, included) ?></code>
    +-      <p><?cs call:short_descr(field) ?>
    +-      <?cs call:show_annotations_list(field) ?></p>
    +-    </td>
    +-  </tr>
    +-  <?cs set:count = count + #1 ?>
    +-<?cs /each ?>
    +-<?cs /def ?>
    +-
    +-<?cs
    +-# Print the table cells for the summary of constants
    +-?><?cs def:write_constant_summary(fields, included) ?>
    +-<?cs set:count = #1 ?>
    +-    <?cs each:field=fields ?>
    +-    <tr class="api apilevel-<?cs var:field.since ?>" >
    +-        <td><code><?cs call:type_link(field.type) ?></code></td>
    +-        <td width="100%">
    +-          <code><?cs call:cond_link(field.name, toroot, field.href, included) ?></code>
    +-          <p><?cs call:short_descr(field) ?>
    +-          <?cs call:show_annotations_list(field) ?></p>
    +-        </td>
    +-    </tr>
    +-    <?cs set:count = count + #1 ?>
    +-    <?cs /each ?>
    +-<?cs /def ?>
    +-
    +-<?cs
    +-# Print the table cells for the summary of attributes
    +-?><?cs def:write_attr_summary(attrs, included) ?>
    +-<?cs set:count = #1 ?>
    +-    <?cs each:attr=attrs ?>
    +-    <tr class="api apilevel-<?cs var:attr.since ?>" >
    +-        <td><?cs if:included ?><a href="<?cs var:toroot ?><?cs var:attr.href ?>"><?cs /if
    +-          ?><code><?cs var:attr.name ?></code><?cs if:included ?></a><?cs /if ?></td>
    +-        <td width="100%">
    +-          <?cs call:short_descr(attr) ?>&nbsp;
    +-          <?cs call:show_annotations_list(attr) ?>
    +-        </td>
    +-    </tr>
    +-    <?cs set:count = count + #1 ?>
    +-    <?cs /each ?>
    +-<?cs /def ?>
    +-
    +-<?cs
    +-# Print the table cells for the inner classes
    +-?><?cs def:write_inners_summary(classes) ?>
    +-<?cs set:count = #1 ?>
    +-  <?cs each:cl=class.inners ?>
    +-    <tr class="api apilevel-<?cs var:cl.since ?>" >
    +-      <td class="jd-typecol"><code>
    +-        <?cs var:cl.scope ?>
    +-        <?cs var:cl.static ?>
    +-        <?cs var:cl.final ?>
    +-        <?cs var:cl.abstract ?>
    +-        <?cs var:cl.kind ?></code></td>
    +-      <td class="jd-descrcol" width="100%">
    +-        <code><?cs call:type_link(cl.type) ?></code>
    +-        <p><?cs call:short_descr(cl) ?>&nbsp;
    +-        <?cs call:show_annotations_list(cl) ?></p>
    +-      </td>
    +-    </tr>
    +-    <?cs set:count = count + #1 ?>
    +-    <?cs /each ?>
    +-<?cs /def ?>
    +-<?cs
    +-###################
    +-# END OF FUNCTIONS FOR API SUMMARY
    +-# START OF FUNCTIONS FOR THE API DETAILS
    +-###################
    +-?>
    +-<?cs
    +-# Print the table cells for the summary of constants
    +-?>
    +-<?cs def:write_field_details(fields) ?>
    +-<?cs each:field=fields ?>
    +-<?cs # this next line must be exactly like this to be parsed by eclipse ?>
    +-<?cs # the A tag in the next line must remain where it is, so that Eclipse can parse the docs ?>
    +-<A NAME="<?cs var:field.anchor ?>"></A>
    +-<?cs # The apilevel-N class MUST BE LAST in the sequence of class names ?>
    +-<div class="api apilevel-<?cs var:field.since ?>">
    +-    <h3 class="api-name"><?cs var:field.name ?></h3>
    +-    <div class="api-level">
    +-      <?cs call:since_tags(field) ?>
    +-      <?cs call:federated_refs(field) ?>
    +-    </div>
    +-<pre class="api-signature no-pretty-print">
    +-<?cs if:subcount(field.scope) ?><?cs var:field.scope
    +-?> <?cs /if ?><?cs if:subcount(field.static) ?><?cs var:field.static
    +-?> <?cs /if ?><?cs if:subcount(field.final) ?><?cs var:field.final
    +-?> <?cs /if ?><?cs if:subcount(field.type) ?><?cs call:type_link(field.type)
    +-?> <?cs /if ?><?cs var:field.name ?></pre>
    +-    <?cs call:show_annotations_list(field) ?>
    +-    <?cs call:description(field) ?>
    +-    <?cs if:subcount(field.constantValue) ?>
    +-      <p>Constant Value:
    +-      <?cs if:field.constantValue.isString ?>
    +-          <?cs var:field.constantValue.str ?>
    +-      <?cs else ?>
    +-          <?cs var:field.constantValue.dec ?>
    +-          (<?cs var:field.constantValue.hex ?>)
    +-      <?cs /if ?>
    +-    <?cs /if ?>
    +-</div>
    +-<?cs /each ?>
    +-<?cs /def ?>
    +-
    +-<?cs def:write_method_details(methods) ?>
    +-<?cs each:method=methods ?>
    +-<?cs # the A tag in the next line must remain where it is, so that Eclipse can parse the docs ?>
    +-<A NAME="<?cs var:method.anchor ?>"></A>
    +-<?cs # The apilevel-N class MUST BE LAST in the sequence of class names ?>
    +-<div class="api apilevel-<?cs var:method.since ?>">
    +-    <h3 class="api-name"><?cs var:method.name ?></h3>
    +-    <div class="api-level">
    +-      <div><?cs call:since_tags(method) ?></div>
    +-      <?cs call:federated_refs(method) ?>
    +-    </div>
    +-<pre class="api-signature no-pretty-print">
    +-<?cs if:subcount(method.scope) ?><?cs var:method.scope
    +-?> <?cs /if ?><?cs if:subcount(method.static) ?><?cs var:method.static
    +-?> <?cs /if ?><?cs if:subcount(method.final) ?><?cs var:method.final
    +-?> <?cs /if ?><?cs if:subcount(method.abstract) ?><?cs var:method.abstract
    +-?> <?cs /if ?><?cs if:subcount(method.returnType) ?><?cs call:type_link(method.returnType)
    +-?> <?cs /if ?><?cs var:method.name ?> (<?cs call:parameter_list(method.params, 1) ?>)</pre>
    +-    <?cs call:show_annotations_list(method) ?>
    +-    <?cs call:description(method) ?>
    +-</div>
    +-<?cs /each ?>
    +-<?cs /def ?>
    +-
    +-<?cs def:write_attr_details(attrs) ?>
    +-<?cs each:attr=attrs ?>
    +-<?cs # the A tag in the next line must remain where it is, so that Eclipse can parse the docs ?>
    +-<A NAME="<?cs var:attr.anchor ?>"></A>
    +-<h3 class="api-name"><?cs var:attr.name ?></h3>
    +-<?cs call:show_annotations_list(attr) ?>
    +-<?cs call:description(attr) ?>
    +-<?cs if:subcount(attr.methods) ?>
    +-  <p><b>Related methods:</b></p>
    +-  <ul class="nolist">
    +-  <?cs each:m=attr.methods ?>
    +-    <li><a href="<?cs var:toroot ?><?cs var:m.href ?>"><?cs var:m.name ?></a></li>
    +-  <?cs /each ?>
    +-  </ul>
    +-<?cs /if ?>
    +-<?cs /each ?>
    +-<?cs /def ?>
    +-<?cs
    +-#########################
    +-# END OF MACROS
    +-# START OF PAGE PRINTING
    +-#########################
    +-?>
    +-<?cs include:"doctype.cs" ?>
    +-<html<?cs if:devsite ?> devsite<?cs /if ?>>
    +-<?cs include:"head_tag.cs" ?>
    +-<?cs include:"body_tag.cs" ?>
    +-<?cs include:"header.cs" ?>
    +-<?cs include:"page_info.cs" ?>
    +-<?cs # This DIV spans the entire document to provide scope for some scripts ?>
    +-<div class="api apilevel-<?cs var:class.since ?>" id="jd-content">
    +-<?cs # this next line must be exactly like this to be parsed by eclipse ?>
    +-<!-- ======== START OF CLASS DATA ======== -->
    +-<?cs
    +-#
    +-# Page header with class name and signature
    +-#
    +-?>
    +-<h1 class="api-title"><?cs var:class.name ?></h1>
    +-<p>
    +-<code class="api-signature">
    +-  <?cs var:class.scope ?>
    +-  <?cs var:class.static ?>
    +-  <?cs var:class.final ?>
    +-  <?cs var:class.abstract ?>
    +-  <?cs var:class.kind ?>
    +-  <?cs var:class.name ?>
    +-</code>
    +-<br>
    +-<?cs set:colspan = subcount(class.inheritance) ?>
    +-<?cs each:supr = class.inheritance ?>
    +-<code class="api-signature">
    +-  <?cs if:colspan == 2 ?>
    +-    extends <?cs call:type_link(supr.short_class) ?>
    +-  <?cs /if ?>
    +-  <?cs if:last(supr) && subcount(supr.interfaces) ?>
    +-      implements
    +-      <?cs each:t=supr.interfaces ?>
    +-        <?cs call:type_link(t) ?><?cs
    +-          if: name(t)!=subcount(supr.interfaces)-1
    +-            ?>, <?cs /if ?>
    +-      <?cs /each ?>
    +-  <?cs /if ?>
    +-  <?cs set:colspan = colspan-1 ?>
    +-</code>
    +-<?cs /each ?>
    +-</p><?cs
    +-#
    +-# Class inheritance tree
    +-#
    +-?><table class="jd-inheritance-table">
    +-<?cs set:colspan = subcount(class.inheritance) ?>
    +-<?cs each:supr = class.inheritance ?>
    +-  <tr>
    +-    <?cs loop:i = 1, (subcount(class.inheritance)-colspan), 1 ?>
    +-      <td class="jd-inheritance-space">&nbsp;<?cs
    +-        if:(subcount(class.inheritance)-colspan) == i
    +-          ?>&nbsp;&nbsp;&#x21b3;<?cs
    +-        /if ?></td>
    +-    <?cs /loop ?>
    +-    <td colspan="<?cs var:colspan ?>" class="jd-inheritance-class-cell"><?cs
    +-      if:colspan == 1
    +-          ?><?cs call:class_name(class.qualifiedType) ?><?cs
    +-      else
    +-          ?><?cs call:type_link(supr.class) ?><?cs
    +-      /if ?>
    +-    </td>
    +-  </tr>
    +-  <?cs set:colspan = colspan-1 ?>
    +-<?cs /each ?>
    +-</table><?cs
    +-#
    +-# Collapsible list of subclasses
    +-#
    +-?><?cs
    +-if:subcount(class.subclasses.direct) && !class.subclasses.hidden ?>
    +-  <table class="jd-sumtable jd-sumtable-subclasses">
    +-  <tr><td style="border:none;margin:0;padding:0;">
    +-    <?cs call:expando_trigger("subclasses-direct", "closed") ?>Known Direct Subclasses
    +-    <?cs call:expandable_class_list("subclasses-direct", class.subclasses.direct, "list") ?>
    +-  </td></tr>
    +-  </table>
    +-  <?cs /if ?>
    +-  <?cs if:subcount(class.subclasses.indirect) && !class.subclasses.hidden ?>
    +-  <table class="jd-sumtable jd-sumtable-subclasses"><tr><td colspan="2" style="border:none;margin:0;padding:0;">
    +-  <?cs call:expando_trigger("subclasses-indirect", "closed") ?>Known Indirect Subclasses
    +-  <?cs call:expandable_class_list("subclasses-indirect", class.subclasses.indirect, "list") ?>
    +-  </td></tr></table><?cs
    +-/if ?>
    +-<?cs call:show_annotations_list(class) ?>
    +-<br><hr><?cs
    +-#
    +-# The long-form class description.
    +-#
    +-?><?cs call:deprecated_warning(class) ?>
    +-
    +-<?cs if:subcount(class.descr) ?>
    +-  <p><?cs call:tag_list(class.descr) ?></p>
    +-<?cs /if ?>
    +-
    +-<?cs call:see_also_tags(class.seeAlso) ?>
    +-<?cs
    +-#################
    +-# CLASS SUMMARY
    +-#################
    +-?>
    +-<?cs # make sure there is a summary view to display ?>
    +-<?cs if:subcount(class.inners)
    +-     || subcount(class.attrs)
    +-     || inhattrs
    +-     || subcount(class.enumConstants)
    +-     || subcount(class.constants)
    +-     || inhconstants
    +-     || subcount(class.fields)
    +-     || inhfields
    +-     || subcount(class.ctors.public)
    +-     || subcount(class.ctors.protected)
    +-     || subcount(class.methods.public)
    +-     || subcount(class.methods.protected)
    +-     || inhmethods ?>
    +-<h2 class="api-section">Summary</h2>
    +-
    +-<?cs if:subcount(class.inners) ?>
    +-<?cs # this next line must be exactly like this to be parsed by eclipse ?>
    +-<!-- ======== NESTED CLASS SUMMARY ======== -->
    +-<table id="nestedclasses" class="responsive">
    +-<tr><th colspan="2"><h3>Nested classes</h3></th></tr>
    +-<?cs call:write_inners_summary(class.inners) ?>
    +-<?cs /if ?>
    +-
    +-<?cs # this next line must be exactly like this to be parsed by eclipse ?>
    +-<?cs if:subcount(class.attrs) ?>
    +-<!-- =========== FIELD SUMMARY =========== -->
    +-<table id="lattrs" class="responsive">
    +-<tr><th colspan="2"><h3>XML attributes</h3></th></tr>
    +-<?cs call:write_attr_summary(class.attrs, 1) ?>
    +-<?cs /if ?>
    +-
    +-<?cs # if there are inherited attrs, write the table ?>
    +-<?cs if:inhattrs ?>
    +-<?cs # this next line must be exactly like this to be parsed by eclipse ?>
    +-<!-- =========== FIELD SUMMARY =========== -->
    +-<table id="inhattrs" class="responsive inhtable">
    +-<tr><th><h3>Inherited XML attributes</h3></th></tr>
    +-<?cs each:cl=class.inherited ?>
    +-<?cs if:subcount(cl.attrs) ?>
    +-<tr class="api apilevel-<?cs var:cl.since ?>" >
    +-<td colspan="2">
    +-<?cs call:expando_trigger("inherited-attrs-"+cl.qualified, "closed") ?>From
    +-<?cs var:cl.kind ?>
    +-<code>
    +-  <?cs call:cond_link(cl.qualified, toroot, cl.link, cl.included) ?>
    +-</code>
    +-<div id="inherited-attrs-<?cs var:cl.qualified ?>">
    +-  <div id="inherited-attrs-<?cs var:cl.qualified ?>-list"
    +-        class="jd-inheritedlinks">
    +-  </div>
    +-  <div id="inherited-attrs-<?cs var:cl.qualified ?>-summary" style="display: none;">
    +-    <table class="jd-sumtable-expando">
    +-    <?cs call:write_attr_summary(cl.attrs, cl.included) ?></table>
    +-  </div>
    +-</div>
    +-</td></tr>
    +-<?cs /if ?>
    +-<?cs /each ?>
    +-</table>
    +-<?cs /if ?>
    +-
    +-<?cs if:subcount(class.enumConstants) ?>
    +-<?cs # this next line must be exactly like this to be parsed by eclipse ?>
    +-<!-- =========== ENUM CONSTANT SUMMARY =========== -->
    +-<table id="enumconstants" class="responsive constants">
    +-  <tr><th colspan="2"><h3>Enum values</h3></th></tr>
    +-<?cs set:count = #1 ?>
    +-  <?cs each:field=class.enumConstants ?>
    +-  <tr class="api apilevel-<?cs var:field.since ?>" >
    +-    <td><code><?cs call:type_link(field.type) ?></code>&nbsp;</td>
    +-    <td width="100%">
    +-      <code><?cs call:cond_link(field.name, toroot, field.href, cl.included) ?></code>
    +-      <p><?cs call:short_descr(field) ?>&nbsp;
    +-      <?cs call:show_annotations_list(field) ?></p>
    +-    </td>
    +-  </tr>
    +-  <?cs set:count = count + #1 ?>
    +-  <?cs /each ?>
    +-<?cs /if ?>
    +-
    +-<?cs if:subcount(class.constants) ?>
    +-<?cs # this next line must be exactly like this to be parsed by eclipse ?>
    +-<!-- =========== ENUM CONSTANT SUMMARY =========== -->
    +-<table id="constants" class="responsive constants">
    +-<tr><th colspan="2"><h3>Constants</h3></th></tr>
    +-<?cs call:write_constant_summary(class.constants, 1) ?>
    +-</table>
    +-<?cs /if ?>
    +-
    +-<?cs # if there are inherited constants, write the table ?>
    +-<?cs if:inhconstants ?>
    +-<?cs # this next line must be exactly like this to be parsed by eclipse ?>
    +-<!-- =========== ENUM CONSTANT SUMMARY =========== -->
    +-<table id="inhconstants" class="responsive constants inhtable">
    +-<tr><th><h3>Inherited constants</h3></th></tr>
    +-<?cs each:cl=class.inherited ?>
    +-<?cs if:subcount(cl.constants) ?>
    +-  <tr class="api apilevel-<?cs var:cl.since ?>" >
    +-  <td>
    +-  <?cs call:expando_trigger("inherited-constants-"+cl.qualified, "closed") ?>From
    +-  <?cs var:cl.kind ?>
    +-  <code>
    +-    <?cs call:cond_link(cl.qualified, toroot, cl.link, cl.included) ?>
    +-  </code>
    +-  <div id="inherited-constants-<?cs var:cl.qualified ?>">
    +-    <div id="inherited-constants-<?cs var:cl.qualified ?>-list"
    +-          class="jd-inheritedlinks">
    +-    </div>
    +-    <div id="inherited-constants-<?cs var:cl.qualified ?>-summary" style="display: none;">
    +-      <table class="jd-sumtable-expando responsive">
    +-      <?cs call:write_constant_summary(cl.constants, cl.included) ?></table>
    +-    </div>
    +-  </div>
    +-  </td></tr>
    +-<?cs /if ?>
    +-<?cs /each ?>
    +-</table>
    +-<?cs /if ?>
    +-
    +-<?cs if:subcount(class.fields) ?>
    +-<?cs # this next line must be exactly like this to be parsed by eclipse ?>
    +-<!-- =========== FIELD SUMMARY =========== -->
    +-<table id="lfields" class="responsive properties">
    +-<tr><th colspan="2"><h3>Fields</h3></th></tr>
    +-<?cs call:write_field_summary(class.fields, 1) ?>
    +-</table>
    +-<?cs /if ?>
    +-
    +-<?cs # if there are inherited fields, write the table ?>
    +-<?cs if:inhfields ?>
    +-<?cs # this next line must be exactly like this to be parsed by eclipse ?>
    +-<!-- =========== FIELD SUMMARY =========== -->
    +-<table id="inhfields" class="properties inhtable">
    +-<tr><th><h3>Inherited fields</h3></th></tr>
    +-<?cs each:cl=class.inherited ?>
    +-<?cs if:subcount(cl.fields) ?>
    +-  <tr class="api apilevel-<?cs var:cl.since ?>" >
    +-  <td>
    +-  <?cs call:expando_trigger("inherited-fields-"+cl.qualified, "closed") ?>From
    +-  <?cs var:cl.kind ?>
    +-  <code>
    +-    <?cs call:cond_link(cl.qualified, toroot, cl.link, cl.included) ?>
    +-  </code>
    +-  <div id="inherited-fields-<?cs var:cl.qualified ?>">
    +-    <div id="inherited-fields-<?cs var:cl.qualified ?>-list"
    +-          class="jd-inheritedlinks">
    +-    </div>
    +-    <div id="inherited-fields-<?cs var:cl.qualified ?>-summary" style="display: none;">
    +-      <table class="jd-sumtable-expando responsive">
    +-      <?cs call:write_field_summary(cl.fields, cl.included) ?></table>
    +-    </div>
    +-  </div>
    +-  </td></tr>
    +-<?cs /if ?>
    +-<?cs /each ?>
    +-</table>
    +-<?cs /if ?>
    +-
    +-<?cs if:subcount(class.ctors.public) ?>
    +-<?cs # this next line must be exactly like this to be parsed by eclipse ?>
    +-<!-- ======== CONSTRUCTOR SUMMARY ======== -->
    +-<table id="pubctors" class="responsive constructors">
    +-<tr><th colspan="2"><h3>Public constructors</h3></th></tr>
    +-<?cs call:write_method_summary(class.ctors.public, 1) ?>
    +-</table>
    +-<?cs /if ?>
    +-
    +-<?cs if:subcount(class.ctors.protected) ?>
    +-<?cs # this next line must be exactly like this to be parsed by eclipse ?>
    +-<!-- ======== CONSTRUCTOR SUMMARY ======== -->
    +-<table id="proctors" class="responsive constructors">
    +-<tr><th colspan="2"><h3>Protected constructors</h3></th></tr>
    +-<?cs call:write_method_summary(class.ctors.protected, 1) ?>
    +-</table>
    +-<?cs /if ?>
    +-
    +-<?cs if:subcount(class.methods.public) ?>
    +-<?cs # this next line must be exactly like this to be parsed by eclipse ?>
    +-<!-- ========== METHOD SUMMARY =========== -->
    +-<table id="pubmethods" class="responsive methods">
    +-<tr><th colspan="2"><h3>Public methods</h3></th></tr>
    +-<?cs call:write_method_summary(class.methods.public, 1) ?>
    +-</table>
    +-<?cs /if ?>
    +-
    +-<?cs if:subcount(class.methods.protected) ?>
    +-<?cs # this next line must be exactly like this to be parsed by eclipse ?>
    +-<!-- ========== METHOD SUMMARY =========== -->
    +-<table id="promethods" class="reponsive methods">
    +-<tr><th colspan="2"><h3>Protected methods</h3></th></tr>
    +-<?cs call:write_method_summary(class.methods.protected, 1) ?>
    +-</table>
    +-<?cs /if ?>
    +-
    +-<?cs # if there are inherited methods, write the table ?>
    +-<?cs if:inhmethods ?>
    +-<?cs # this next line must be exactly like this to be parsed by eclipse ?>
    +-<!-- ========== METHOD SUMMARY =========== -->
    +-<table id="inhmethods" class="methods inhtable">
    +-<tr><th><h3>Inherited methods</h3></th></tr>
    +-<?cs each:cl=class.inherited ?>
    +-<?cs if:subcount(cl.methods) ?>
    +-<tr class="api apilevel-<?cs var:cl.since ?>" >
    +-<td colspan="2">
    +-<?cs call:expando_trigger("inherited-methods-"+cl.qualified, "closed") ?>From
    +-<?cs var:cl.kind ?>
    +-<code>
    +-  <?cs if:cl.included ?>
    +-    <a href="<?cs var:toroot ?><?cs var:cl.link ?>"><?cs var:cl.qualified ?></a>
    +-  <?cs elif:cl.federated ?>
    +-    <a href="<?cs var:cl.link ?>"><?cs var:cl.qualified ?></a>
    +-  <?cs else ?>
    +-    <?cs var:cl.qualified ?>
    +-  <?cs /if ?>
    +-</code>
    +-<div id="inherited-methods-<?cs var:cl.qualified ?>">
    +-  <div id="inherited-methods-<?cs var:cl.qualified ?>-list"
    +-        class="jd-inheritedlinks">
    +-  </div>
    +-  <div id="inherited-methods-<?cs var:cl.qualified ?>-summary" style="display: none;">
    +-    <table class="jd-sumtable-expando responsive">
    +-      <?cs call:write_method_summary(cl.methods, cl.included) ?>
    +-    </table>
    +-  </div>
    +-</div>
    +-</td></tr>
    +-<?cs /if ?>
    +-<?cs /each ?>
    +-</table>
    +-<?cs /if ?>
    +-<?cs /if ?>
    +-<?cs
    +-################
    +-# CLASS DETAILS
    +-################
    +-?>
    +-<!-- XML Attributes -->
    +-<?cs if:subcount(class.attrs) ?>
    +-<?cs # this next line must be exactly like this to be parsed by eclipse ?>
    +-<!-- ========= FIELD DETAIL ======== -->
    +-<h2 class="api-section">XML attributes</h2>
    +-<?cs call:write_attr_details(class.attrs) ?>
    +-<?cs /if ?>
    +-
    +-<!-- Enum Values -->
    +-<?cs if:subcount(class.enumConstants) ?>
    +-<?cs # this next line must be exactly like this to be parsed by eclipse ?>
    +-<!-- ========= ENUM CONSTANTS DETAIL ======== -->
    +-<h2 class="api-section">Enum values</h2>
    +-<?cs call:write_field_details(class.enumConstants) ?>
    +-<?cs /if ?>
    +-
    +-<!-- Constants -->
    +-<?cs if:subcount(class.constants) ?>
    +-<?cs # this next line must be exactly like this to be parsed by eclipse ?>
    +-<!-- ========= ENUM CONSTANTS DETAIL ======== -->
    +-<h2 class="api-section">Constants</h2>
    +-<?cs call:write_field_details(class.constants) ?>
    +-<?cs /if ?>
    +-
    +-<!-- Fields -->
    +-<?cs if:subcount(class.fields) ?>
    +-<?cs # this next line must be exactly like this to be parsed by eclipse ?>
    +-<!-- ========= FIELD DETAIL ======== -->
    +-<h2 class="api-section">Fields</h2>
    +-<?cs call:write_field_details(class.fields) ?>
    +-<?cs /if ?>
    +-
    +-<!-- Public ctors -->
    +-<?cs if:subcount(class.ctors.public) ?>
    +-<?cs # this next line must be exactly like this to be parsed by eclipse ?>
    +-<!-- ========= CONSTRUCTOR DETAIL ======== -->
    +-<h2 class="api-section">Public constructors</h2>
    +-<?cs call:write_method_details(class.ctors.public) ?>
    +-<?cs /if ?>
    +-
    +-<?cs # this next line must be exactly like this to be parsed by eclipse ?>
    +-<!-- ========= CONSTRUCTOR DETAIL ======== -->
    +-<!-- Protected ctors -->
    +-<?cs if:subcount(class.ctors.protected) ?>
    +-<h2 class="api-section">Protected constructors</h2>
    +-<?cs call:write_method_details(class.ctors.protected) ?>
    +-<?cs /if ?>
    +-
    +-<?cs # this next line must be exactly like this to be parsed by eclipse ?>
    +-<!-- ========= METHOD DETAIL ======== -->
    +-<!-- Public methdos -->
    +-<?cs if:subcount(class.methods.public) ?>
    +-<h2 class="api-section">Public methods</h2>
    +-<?cs call:write_method_details(class.methods.public) ?>
    +-<?cs /if ?>
    +-
    +-<?cs # this next line must be exactly like this to be parsed by eclipse ?>
    +-<!-- ========= METHOD DETAIL ======== -->
    +-<?cs if:subcount(class.methods.protected) ?>
    +-<h2 class="api-section">Protected methods</h2>
    +-<?cs call:write_method_details(class.methods.protected) ?>
    +-<?cs /if ?>
    +-
    +-<?cs # the next two lines must be exactly like this to be parsed by eclipse ?>
    +-<!-- ========= END OF CLASS DATA ========= -->
    +-
    +-</div><!-- end jd-content -->
    +-
    +-<?cs if:devsite ?>
    +-
    +-<div class="data-reference-resources-wrapper">
    +-  <?cs if:subcount(class.package) ?>
    +-  <ul data-reference-resources>
    +-    <?cs call:list("Annotations", class.package.annotations) ?>
    +-    <?cs call:list("Interfaces", class.package.interfaces) ?>
    +-    <?cs call:list("Classes", class.package.classes) ?>
    +-    <?cs call:list("Enums", class.package.enums) ?>
    +-    <?cs call:list("Exceptions", class.package.exceptions) ?>
    +-    <?cs call:list("Errors", class.package.errors) ?>
    +-  </ul>
    +-  <?cs elif:subcount(package) ?>
    +-  <ul data-reference-resources>
    +-    <?cs call:class_link_list("Annotations", package.annotations) ?>
    +-    <?cs call:class_link_list("Interfaces", package.interfaces) ?>
    +-    <?cs call:class_link_list("Classes", package.classes) ?>
    +-    <?cs call:class_link_list("Enums", package.enums) ?>
    +-    <?cs call:class_link_list("Exceptions", package.exceptions) ?>
    +-    <?cs call:class_link_list("Errors", package.errors) ?>
    +-  </ul>
    +-  <?cs /if ?>
    +-</div>
    +-<?cs /if ?>
    +-
    +-<?cs if:!devsite ?>
    +-<?cs include:"footer.cs" ?>
    +-<?cs include:"trailer.cs" ?>
    +-<?cs /if ?>
    +-</body>
    +-</html>
    +diff --git a/tools/droiddoc/templates-sdk-dev/classes.cs b/tools/droiddoc/templates-sdk-dev/classes.cs
    +deleted file mode 100644
    +index 007b57e..0000000
    +--- a/tools/droiddoc/templates-sdk-dev/classes.cs
    ++++ /dev/null
    +@@ -1,69 +0,0 @@
    +-<?cs # THIS CREATES A LIST OF ALL PACKAGES AND NAMES IT packages.html ?>
    +-<?cs include:"macros.cs" ?>
    +-<?cs include:"macros_override.cs" ?>
    +-<?cs include:"doctype.cs" ?>
    +-<html<?cs if:devsite ?> devsite<?cs /if ?>>
    +-<?cs include:"head_tag.cs" ?>
    +-<?cs include:"body_tag.cs" ?>
    +-<?cs include:"header.cs" ?>
    +-
    +-<h1><?cs var:page.title ?></h1>
    +-<p>These are the API classes. See all
    +-<a href="packages.html">API packages</a>.</p>
    +-
    +-<div class="jd-letterlist"><?cs
    +-  each:letter=docs.classes ?>
    +-    <a href="#letter_<?cs name:letter ?>"><?cs
    +-      name:letter ?></a>&nbsp;&nbsp;<?cs
    +-  /each?>
    +-</div>
    +-
    +-<?cs each:letter=docs.classes ?>
    +-<?cs set:count = #1 ?>
    +-<h2 id="letter_<?cs name:letter ?>"><?cs name:letter ?></h2>
    +-<table>
    +-    <?cs set:cur_row = #0 ?>
    +-    <?cs each:cl = letter ?>
    +-        <tr class="<?cs if:count % #2 ?>alt-color<?cs /if ?> api apilevel-<?cs var:cl.since ?>" >
    +-            <td class="jd-linkcol"><?cs call:type_link(cl.type) ?></td>
    +-            <td class="jd-descrcol" width="100%">
    +-              <?cs call:short_descr(cl) ?>&nbsp;
    +-              <?cs call:show_annotations_list(cl) ?>
    +-            </td>
    +-        </tr>
    +-    <?cs set:count = count + #1 ?>
    +-    <?cs /each ?>
    +-</table>
    +-<?cs /each ?>
    +-
    +-<?cs if:devsite ?>
    +-<div class="data-reference-resources-wrapper">
    +-  <?cs if:subcount(class.package) ?>
    +-  <ul data-reference-resources>
    +-    <?cs call:list("Annotations", class.package.annotations) ?>
    +-    <?cs call:list("Interfaces", class.package.interfaces) ?>
    +-    <?cs call:list("Classes", class.package.classes) ?>
    +-    <?cs call:list("Enums", class.package.enums) ?>
    +-    <?cs call:list("Exceptions", class.package.exceptions) ?>
    +-    <?cs call:list("Errors", class.package.errors) ?>
    +-  </ul>
    +-  <?cs elif:subcount(package) ?>
    +-  <ul data-reference-resources>
    +-    <?cs call:class_link_list("Annotations", package.annotations) ?>
    +-    <?cs call:class_link_list("Interfaces", package.interfaces) ?>
    +-    <?cs call:class_link_list("Classes", package.classes) ?>
    +-    <?cs call:class_link_list("Enums", package.enums) ?>
    +-    <?cs call:class_link_list("Exceptions", package.exceptions) ?>
    +-    <?cs call:class_link_list("Errors", package.errors) ?>
    +-  </ul>
    +-  <?cs /if ?>
    +-</div>
    +-<?cs /if ?>
    +-
    +-
    +-<?cs if:!devsite ?>
    +-<?cs include:"footer.cs" ?>
    +-<?cs include:"trailer.cs" ?>
    +-<?cs /if ?>
    +-</body>
    +-</html>
    +diff --git a/tools/droiddoc/templates-sdk-dev/components/masthead.cs b/tools/droiddoc/templates-sdk-dev/components/masthead.cs
    +deleted file mode 100644
    +index 1fef965..0000000
    +--- a/tools/droiddoc/templates-sdk-dev/components/masthead.cs
    ++++ /dev/null
    +@@ -1,322 +0,0 @@
    +-<?cs def:custom_masthead() ?>
    +-  <a name="top"></a>
    +-  <!-- Header -->
    +-  <div id="header-wrapper">
    +-    <div class="dac-header <?cs if:ndk ?>dac-ndk<?cs /if ?>" id="header">
    +-      <div class="dac-header-inner">
    +-        <a class="dac-nav-toggle" data-dac-toggle-nav href="javascript:;" title="Open navigation">
    +-          <span class="dac-nav-hamburger">
    +-            <span class="dac-nav-hamburger-top"></span>
    +-            <span class="dac-nav-hamburger-mid"></span>
    +-            <span class="dac-nav-hamburger-bot"></span>
    +-          </span>
    +-        </a>
    +-        <?cs if:ndk ?><a class="dac-header-logo" style="width:144px;" href="<?cs var:toroot
    +-        ?>ndk/index.html">
    +-          <img class="dac-header-logo-image" src="<?cs var:toroot ?>assets/images/android_logo.png"
    +-              srcset="<?cs var:toroot ?>assets/images/android_logo@2x.png 2x"
    +-              width="32" height="36" alt="Android" /> NDK
    +-          </a><?cs else ?><a class="dac-header-logo" href="<?cs var:toroot ?>index.html">
    +-          <img class="dac-header-logo-image" src="<?cs var:toroot ?>assets/images/android_logo.png"
    +-              srcset="<?cs var:toroot ?>assets/images/android_logo@2x.png 2x"
    +-              width="32" height="36" alt="Android" /> Developers
    +-          </a><?cs /if ?>
    +-
    +-        <?cs if:ndk
    +-        ?><ul class="dac-header-tabs">
    +-          <li>
    +-            <a href="<?cs var:toroot ?>ndk/guides/index.html" class="dac-header-tab"
    +-            zh-tw-lang="API 指南"
    +-            zh-cn-lang="API 指南"
    +-            ru-lang="Руководства по API"
    +-            ko-lang="API 가이드"
    +-            ja-lang="API ガイド"
    +-            es-lang="Guías de la API">Guides</a>
    +-          </li>
    +-          <li>
    +-            <a href="<?cs var:toroot ?>ndk/reference/index.html" class="dac-header-tab"
    +-            zh-tw-lang="參考資源"
    +-            zh-cn-lang="参考"
    +-            ru-lang="Справочник"
    +-            ko-lang="참조문서"
    +-            ja-lang="リファレンス"
    +-            es-lang="Referencia">Reference</a>
    +-          </li>
    +-          <li>
    +-            <a href="<?cs var:toroot ?>ndk/samples/index.html" class="dac-header-tab"
    +-           >Samples</a>
    +-          </li>
    +-          <li>
    +-            <a href="<?cs var:toroot ?>ndk/downloads/index.html" class="dac-header-tab"
    +-            >Downloads</a>
    +-          </li>
    +-        </ul><?cs else
    +-        ?><?cs
    +-        #
    +-        # For the reference only docs, include just one tab
    +-        #
    +-        ?><?cs if:referenceonly
    +-          ?><ul class="dac-header-tabs">
    +-            <li><a href="<?cs var:toroot ?>reference/packages.html" class="dac-header-tab"><?cs
    +-              if:sdk.preview
    +-                ?>Android <?cs var:sdk.codename ?>
    +-                  Preview <?cs var:sdk.preview.version ?><?cs
    +-              else
    +-                ?>Android <?cs var:sdk.version ?>
    +-                  r<?cs var:sdk.rel.id ?><?cs
    +-              /if ?></a>
    +-            </li>
    +-          </ul>
    +-        <?cs else ?><?cs
    +-        #
    +-        # End reference only docs, now the online DAC tabs...
    +-        #
    +-        ?><ul class="dac-header-tabs">
    +-          <li>
    +-          <a class="dac-header-tab" href="<?cs var:toroot ?>design/index.html"
    +-             zh-tw-lang="設計"
    +-             zh-cn-lang="设计"
    +-             ru-lang="Проектирование"
    +-             ko-lang="디자인"
    +-             ja-lang="設計"
    +-             es-lang="Diseñar">Design</a>
    +-          </li>
    +-          <li>
    +-          <a class="dac-header-tab" href="<?cs var:toroot ?>develop/index.html"
    +-             zh-tw-lang="開發"
    +-             zh-cn-lang="开发"
    +-             ru-lang="Разработка"
    +-             ko-lang="개발"
    +-             ja-lang="開発"
    +-             es-lang="Desarrollar">Develop</a>
    +-          </li>
    +-          <li>
    +-          <a class="dac-header-tab" href="<?cs var:toroot ?>distribute/index.html"
    +-             zh-tw-lang="發佈"
    +-             zh-cn-lang="分发"
    +-             ru-lang="Распространение"
    +-             ko-lang="배포"
    +-             ja-lang="配布"
    +-             es-lang="Distribuir">Distribute</a>
    +-          </li>
    +-        </ul><?cs
    +-        /if ?><?cs
    +-        #
    +-        # End if/else reference only docs
    +-        #
    +-        ?><?cs
    +-        /if ?><?cs # end if/else ndk ?>
    +-
    +-        <?cs if:ndk ?><a class="dac-header-console-btn" href="http://developer.android.com">
    +-          Back to Android Developers
    +-        </a><?cs else ?><a class="dac-header-console-btn" href="https://play.google.com/apps/publish/">
    +-          <span class="dac-sprite dac-google-play"></span>
    +-          <span class="dac-visible-desktop-inline">Developer</span>
    +-          Console
    +-        </a><?cs /if ?><?cs
    +-
    +-        # ADD SEARCH AND MENU ?><?cs
    +-        if:!ndk ?><?cs
    +-          if:!referenceonly ?><?cs
    +-            call:header_search_widget() ?><?cs
    +-          /if ?><?cs
    +-        /if ?>
    +-      </div><!-- end header-wrap.wrap -->
    +-    </div><!-- end header -->
    +-  </div> <!--end header-wrapper -->
    +-
    +-  <?cs if:ndk ?>
    +-  <!-- NDK Navigation-->
    +-  <nav class="dac-nav">
    +-    <div class="dac-nav-dimmer" data-dac-toggle-nav></div>
    +-
    +-    <div class="dac-nav-sidebar" data-swap data-dynamic="false" data-transition-speed="300" data-dac-nav>
    +-                   <div data-swap-container>
    +-        <?cs call:custom_left_nav() ?>
    +-      <ul id="dac-main-navigation" class="dac-nav-list dac-swap-section dac-left dac-no-anim">
    +-      <li class="dac-nav-item guides">
    +-        <a class="dac-nav-link" href="<?cs var:toroot ?>ndk/guides/index.html"
    +-           zh-tw-lang="API 指南"
    +-           zh-cn-lang="API 指南"
    +-           ru-lang="Руководства по API"
    +-           ko-lang="API 가이드"
    +-           ja-lang="API ガイド"
    +-           es-lang="Guías de la API">Guides</a>
    +-      </li>
    +-      <li class="dac-nav-item reference">
    +-        <a class="dac-nav-link" href="<?cs var:toroot ?>ndk/reference/index.html"
    +-           zh-tw-lang="參考資源"
    +-           zh-cn-lang="参考"
    +-           ru-lang="Справочник"
    +-           ko-lang="참조문서"
    +-           ja-lang="リファレンス"
    +-           es-lang="Referencia">Reference</a>
    +-      </li>
    +-      <li class="dac-nav-item samples">
    +-        <a class="dac-nav-link" href="<?cs var:toroot ?>ndk/samples/index.html"
    +-           >Samples</a>
    +-      </li>
    +-      <li class="dac-nav-item downloads">
    +-        <a class="dac-nav-link" href="<?cs var:toroot ?>ndk/downloads/index.html"
    +-           >Downloads</a>
    +-      </li>
    +-      </ul>
    +-    </div>
    +-                       </div>
    +-  </nav>
    +-  <!-- end NDK navigation-->
    +-
    +-
    +-
    +-  <?cs else ?>
    +-  <!-- Navigation-->
    +-  <nav class="dac-nav">
    +-    <div class="dac-nav-dimmer" data-dac-toggle-nav></div>
    +-
    +-    <div class="dac-nav-sidebar" data-swap data-dynamic="false" data-transition-speed="300" data-dac-nav>
    +-      <div <?cs if:!referenceonly ?>data-swap-container<?cs /if ?>>
    +-        <?cs call:custom_left_nav() ?>
    +-        <?cs if:!referenceonly ?>
    +-        <ul id="dac-main-navigation" class="dac-nav-list dac-swap-section dac-left dac-no-anim">
    +-        <li class="dac-nav-item home">
    +-          <a class="dac-nav-link" href="<?cs var:toroot ?>index.html">Home</a>
    +-          <i class="dac-sprite dac-expand-more-black dac-nav-sub-slider"></i>
    +-          <ul class="dac-nav-secondary about">
    +-            <li class="dac-nav-item versions">
    +-              <a class="dac-nav-link" href="<?cs var:toroot ?>about/versions/nougat/index.html">Android</a>
    +-            </li>
    +-            <li class="dac-nav-item wear">
    +-              <a class="dac-nav-link" href="<?cs var:toroot ?>wear/index.html">Wear</a>
    +-            </li>
    +-            <li class="dac-nav-item tv">
    +-              <a class="dac-nav-link" href="<?cs var:toroot ?>tv/index.html">TV</a>
    +-            </li>
    +-            <li class="dac-nav-item auto">
    +-              <a class="dac-nav-link" href="<?cs var:toroot ?>auto/index.html">Auto</a>
    +-            </li>
    +-          </ul>
    +-        </li>
    +-        <li class="dac-nav-item design">
    +-          <a class="dac-nav-link" href="<?cs var:toroot ?>design/index.html"
    +-             zh-tw-lang="設計"
    +-             zh-cn-lang="设计"
    +-             ru-lang="Проектирование"
    +-             ko-lang="디자인"
    +-             ja-lang="設計"
    +-             es-lang="Diseñar">Design</a>
    +-        </li>
    +-        <li class="dac-nav-item develop">
    +-          <a class="dac-nav-link" href="<?cs var:toroot ?>develop/index.html"
    +-             zh-tw-lang="開發"
    +-             zh-cn-lang="开发"
    +-             ru-lang="Разработка"
    +-             ko-lang="개발"
    +-             ja-lang="開発"
    +-             es-lang="Desarrollar">Develop</a>
    +-          <i class="dac-sprite dac-expand-more-black dac-nav-sub-slider"></i>
    +-          <ul class="dac-nav-secondary develop">
    +-            <li class="dac-nav-item training">
    +-              <a class="dac-nav-link" href="<?cs var:toroot ?>training/index.html"
    +-                 zh-tw-lang="訓練課程"
    +-                 zh-cn-lang="培训"
    +-                 ru-lang="Курсы"
    +-                 ko-lang="교육"
    +-                 ja-lang="トレーニング"
    +-                 es-lang="Capacitación">Training</a>
    +-            </li>
    +-            <li class="dac-nav-item guide">
    +-              <a class="dac-nav-link" href="<?cs var:toroot ?>guide/index.html"
    +-                 zh-tw-lang="API 指南"
    +-                 zh-cn-lang="API 指南"
    +-                 ru-lang="Руководства по API"
    +-                 ko-lang="API 가이드"
    +-                 ja-lang="API ガイド"
    +-                 es-lang="Guías de la API">API Guides</a>
    +-            </li>
    +-            <li class="dac-nav-item reference">
    +-              <a class="dac-nav-link" href="<?cs var:toroot ?>reference/packages.html"
    +-                 zh-tw-lang="參考資源"
    +-                 zh-cn-lang="参考"
    +-                 ru-lang="Справочник"
    +-                 ko-lang="참조문서"
    +-                 ja-lang="リファレンス"
    +-                 es-lang="Referencia">Reference</a>
    +-            </li>
    +-            <li class="dac-nav-item tools">
    +-              <a class="dac-nav-link" href="<?cs var:toroot ?>sdk/index.html"
    +-                 zh-tw-lang="相關工具"
    +-                 zh-cn-lang="工具"
    +-                 ru-lang="Инструменты"
    +-                 ko-lang="도구"
    +-                 ja-lang="ツール"
    +-                 es-lang="Herramientas">Tools</a></li>
    +-            <li class="dac-nav-item google">
    +-              <a class="dac-nav-link" href="<?cs var:toroot ?>google/index.html">Google Services</a>
    +-            </li>
    +-            <?cs if:android.hasSamples ?>
    +-            <li class="dac-nav-item samples">
    +-              <a class="dac-nav-link" href="<?cs var:toroot ?>samples/index.html">Samples</a>
    +-            </li>
    +-            <?cs /if ?>
    +-          </ul>
    +-        </li>
    +-        <li class="dac-nav-item distribute">
    +-          <a class="dac-nav-link" href="<?cs var:toroot ?>distribute/<?cs if:android.whichdoc == 'offline' ?>googleplay/<?cs /if ?>index.html"
    +-             zh-tw-lang="發佈"
    +-             zh-cn-lang="分发"
    +-             ru-lang="Распространение"
    +-             ko-lang="배포"
    +-             ja-lang="配布"
    +-             es-lang="Distribuir">Distribute</a>
    +-          <i class="dac-sprite dac-expand-more-black dac-nav-sub-slider"></i>
    +-          <ul class="dac-nav-secondary distribute">
    +-            <li class="dac-nav-item googleplay">
    +-              <a class="dac-nav-link" href="<?cs var:toroot ?>distribute/googleplay/index.html">Google Play</a></li>
    +-            <li class="dac-nav-item essentials">
    +-              <a class="dac-nav-link" href="<?cs var:toroot ?>distribute/essentials/index.html">Essentials</a></li>
    +-            <li class="dac-nav-item users">
    +-              <a class="dac-nav-link" href="<?cs var:toroot ?>distribute/users/index.html">Get Users</a></li>
    +-            <li class="dac-nav-item engage">
    +-              <a class="dac-nav-link" href="<?cs var:toroot ?>distribute/engage/index.html">Engage &amp; Retain</a></li>
    +-            <li class="dac-nav-item monetize">
    +-              <a class="dac-nav-link" href="<?cs var:toroot ?>distribute/monetize/index.html">Earn</a>
    +-            </li>
    +-            <li class="dac-nav-item analyze">
    +-              <a class="dac-nav-link" href="<?cs var:toroot ?>distribute/analyze/index.html">Analyze</a>
    +-            </li>
    +-            <li class="dac-nav-item stories">
    +-              <a class="dac-nav-link" href="<?cs var:toroot ?>distribute/stories/index.html">Stories</a>
    +-            </li>
    +-          </ul>
    +-        </li>
    +-        <!--<li class="dac-nav-item preview">
    +-          <a class="dac-nav-link" href="<?cs var:toroot ?>preview/index.html">Preview</a>
    +-        </li>-->
    +-        </ul>
    +-        <?cs /if ?><?cs # end if referenceonly ?>
    +-      </div>
    +-    </div>
    +-  </nav>
    +-  <!-- end navigation-->
    +-  <?cs /if ?>
    +-
    +-<!-- Nav Setup -->
    +-<script>$('[data-dac-nav]').dacNav();</script>
    +-
    +-<?cs
    +-/def ?><?cs # end custom_masthead() ?><?cs
    +-
    +-def:toast() ?><?cs
    +-
    +-# (UN)COMMENT TO TOGGLE VISIBILITY
    +-
    +-  <div class="dac-toast-group">
    +-    <div class="dac-toast" data-toast>
    +-      <div class="dac-toast-wrap">
    +-        This is a demo notification <a href="#">Learn more</a>.
    +-      </div>
    +-    </div>
    +-  </div>
    +-
    +-?><?cs
    +-/def ?>
    +\ No newline at end of file
    +diff --git a/tools/droiddoc/templates-sdk-dev/customizations.cs b/tools/droiddoc/templates-sdk-dev/customizations.cs
    +deleted file mode 100644
    +index 0b938ac..0000000
    +--- a/tools/droiddoc/templates-sdk-dev/customizations.cs
    ++++ /dev/null
    +@@ -1,248 +0,0 @@
    +-<?cs def:body_content_wrap_start() ?>
    +-  <div class="wrap clearfix" id="body-content">
    +-<?cs /def ?><?cs
    +-
    +-def:fullpage() ?>
    +-  <div id="body-content">
    +-    <div>
    +-<?cs /def ?><?cs
    +-
    +-# The default side navigation for the reference docs ?><?cs
    +-def:reference_default_nav() ?>
    +-  <!-- Fullscreen toggler -->
    +-  <button data-fullscreen class="dac-nav-fullscreen">
    +-    <i class="dac-sprite dac-fullscreen"></i>
    +-  </button>
    +-
    +-  <script>$('[data-fullscreen]').dacFullscreen();</script>
    +-  <!-- End: Fullscreen toggler -->
    +-
    +-  <?cs if:reference.gcm || reference.gms ?>
    +-    <?cs include:"../../../../frameworks/base/docs/html/google/google_toc.cs" ?>
    +-    <script type="text/javascript">
    +-      showGoogleRefTree();
    +-    </script>
    +-  <?cs else ?>
    +-    <div id="devdoc-nav">
    +-      <div id="api-nav-header">
    +-        <div id="api-level-toggle">
    +-          <label for="apiLevelCheckbox" class="disabled"
    +-                 title="Select your target API level to dim unavailable APIs">API level: </label>
    +-          <div class="select-wrapper">
    +-            <select id="apiLevelSelector">
    +-              <!-- option elements added by buildApiLevelSelector() -->
    +-            </select>
    +-          </div>
    +-        </div><!-- end toggle -->
    +-        <div id="api-nav-title">Android APIs</div>
    +-      </div><!-- end nav header -->
    +-      <script>
    +-        var SINCE_DATA = [ <?cs
    +-          each:since = since ?>'<?cs
    +-            var:since.name ?>'<?cs
    +-            if:!last(since) ?>, <?cs /if ?><?cs
    +-            /each
    +-          ?> ];
    +-        buildApiLevelSelector();
    +-      </script>
    +-
    +-      <div class="dac-reference-nav" data-reference-tree>
    +-        <ul class="dac-reference-nav-list" data-reference-namespaces>
    +-          <?cs call:package_link_list(docs.packages) ?>
    +-        </ul>
    +-
    +-        <?cs if:subcount(class.package) ?>
    +-        <ul data-reference-resources>
    +-          <?cs call:list("Annotations", class.package.annotations) ?>
    +-          <?cs call:list("Interfaces", class.package.interfaces) ?>
    +-          <?cs call:list("Classes", class.package.classes) ?>
    +-          <?cs call:list("Enums", class.package.enums) ?>
    +-          <?cs call:list("Exceptions", class.package.exceptions) ?>
    +-          <?cs call:list("Errors", class.package.errors) ?>
    +-        </ul>
    +-        <?cs elif:subcount(package) ?>
    +-        <ul data-reference-resources>
    +-          <?cs call:class_link_list("Annotations", package.annotations) ?>
    +-          <?cs call:class_link_list("Interfaces", package.interfaces) ?>
    +-          <?cs call:class_link_list("Classes", package.classes) ?>
    +-          <?cs call:class_link_list("Enums", package.enums) ?>
    +-          <?cs call:class_link_list("Exceptions", package.exceptions) ?>
    +-          <?cs call:class_link_list("Errors", package.errors) ?>
    +-        </ul>
    +-        <?cs /if ?>
    +-      </div>
    +-    </div>
    +-  <?cs /if ?>
    +-<?cs /def ?><?cs
    +-
    +-def:ndk_nav() ?>
    +-  <div class="wrap clearfix" id="body-content"><div class="cols">
    +-    <div class="col-3 dac-toggle dac-mobile" id="side-nav" itemscope itemtype="http://schema.org/SiteNavigationElement">
    +-      <?cs call:mobile_nav_toggle() ?>
    +-      <div class="dac-toggle-content" id="devdoc-nav">
    +-        <div class="scroll-pane">
    +-<?cs
    +-if:guide ?><?cs include:"../../../../frameworks/base/docs/html/ndk/guides/guides_toc.cs" ?><?cs
    +-elif:reference ?><?cs include:"../../../../frameworks/base/docs/html/ndk/reference/reference_toc.cs" ?><?cs
    +-elif:downloads ?><?cs include:"../../../../frameworks/base/docs/html/ndk/downloads/downloads_toc.cs" ?><?cs
    +-elif:samples ?><?cs include:"../../../../frameworks/base/docs/html/ndk/samples/samples_toc.cs" ?><?cs
    +-/if ?>
    +-        </div>
    +-      </div>
    +-    </div> <!-- end side-nav -->
    +-<?cs /def ?><?cs
    +-
    +-def:header_search_widget() ?>
    +-  <form data-search class="dac-header-search">
    +-    <button class="dac-header-search-close" data-search-close>
    +-      <i class="dac-sprite dac-back-arrow"></i>
    +-    </button>
    +-
    +-    <div class="dac-header-search-inner">
    +-      <i class="dac-sprite dac-search-white dac-header-search-icon"></i>
    +-      <input id="search_autocomplete" type="text" value="" autocomplete="off" name="q" class="dac-header-search-input" placeholder="Search" />
    +-      <button class="dac-header-search-clear dac-hidden" data-search-clear>
    +-        <i class="dac-sprite dac-close-black"></i>
    +-      </button>
    +-    </div>
    +-  </form>
    +-<?cs /def ?><?cs
    +-
    +-def:search_results() ?>
    +-  <div id="search-results" class="dac-search-results">
    +-    <div id="dac-search-results-history" class="dac-search-results-history">
    +-      <div class="wrap dac-search-results-history-wrap">
    +-        <div class="cols">
    +-          <div class="col-1of2 col-tablet-1of2 col-mobile-1of1">
    +-            <h2>Most visited</h2>
    +-            <div class="resource-flow-layout" data-history-query="history:most/visited" data-maxresults="3" data-cardsizes="18x2"></div>
    +-          </div>
    +-
    +-          <div class="col-1of2 col-tablet-1of2 col-mobile-1of1">
    +-            <h2>Recently visited</h2>
    +-            <div class="resource-flow-layout cols" data-history-query="history:recent" data-allow-duplicates="true" data-maxresults="3" data-cardsizes="18x2"></div>
    +-          </div>
    +-        </div>
    +-      </div>
    +-    </div>
    +-
    +-    <div id="dac-search-results-content" class="dac-search-results-content">
    +-      <div class="dac-search-results-metadata wrap">
    +-        <div class="dac-search-results-for">
    +-          <h2>Results for <span id="search-results-for"></span></h2>
    +-        </div>
    +-
    +-        <div id="dac-search-results-hero"></div>
    +-
    +-        <div class="dac-search-results-hero cols">
    +-          <div id="dac-search-results-reference" class="col-3of6 col-tablet-1of2 col-mobile-1of1">
    +-            <div class="suggest-card reference no-display">
    +-              <ul class="dac-search-results-reference">
    +-              </ul>
    +-            </div>
    +-          </div>
    +-          <div id="dac-custom-search-results"></div>
    +-        </div>
    +-      </div>
    +-
    +-    </div>
    +-  </div>
    +-<?cs /def ?><?cs
    +-
    +-def:custom_left_nav() ?>
    +-  <?cs if:(!fullpage && !nonavpage) || forcelocalnav ?>
    +-    <?cs if:!referenceonly ?>
    +-    <a class="dac-nav-back-button dac-swap-section dac-up dac-no-anim" data-swap-button href="javascript:;">
    +-      <i class="dac-sprite dac-nav-back"></i> <span class="dac-nav-back-title">Back</span>
    +-    </a>
    +-    <?cs /if ?>
    +-    <div class="dac-nav-sub dac-swap-section dac-right dac-active" itemscope
    +-      itemtype="http://schema.org/SiteNavigationElement" <?cs
    +-        if:referenceonly ?>style="top:0 !important;"<?cs /if ?>>
    +-      <?cs if:ndk ?>
    +-        <?cs if:guide ?>
    +-          <?cs include:"../../../../frameworks/base/docs/html/ndk/guides/guides_toc.cs" ?>
    +-        <?cs elif:reference ?>
    +-          <?cs include:"../../../../frameworks/base/docs/html/ndk/reference/reference_toc.cs" ?>
    +-        <?cs elif:downloads ?>
    +-          <?cs include:"../../../../frameworks/base/docs/html/ndk/downloads/downloads_toc.cs" ?>
    +-        <?cs elif:samples ?>
    +-          <?cs include:"../../../../frameworks/base/docs/html/ndk/samples/samples_toc.cs" ?>
    +-        <?cs else ?>
    +-          <?cs call:reference_default_nav() ?>
    +-        <?cs /if ?>
    +-      <?cs elif:guide ?>
    +-        <?cs include:"../../../../frameworks/base/docs/html/guide/guide_toc.cs" ?>
    +-      <?cs elif:design ?>
    +-        <?cs include:"../../../../frameworks/base/docs/html/design/design_toc.cs" ?>
    +-      <?cs elif:training ?>
    +-        <?cs include:"../../../../frameworks/base/docs/html/training/training_toc.cs" ?>
    +-      <?cs elif:tools ?>
    +-        <?cs include:"../../../../frameworks/base/docs/html/tools/tools_toc.cs" ?>
    +-      <?cs elif:google ?>
    +-        <?cs include:"../../../../frameworks/base/docs/html/google/google_toc.cs" ?>
    +-      <?cs elif:samples ?>
    +-        <?cs include:"../../../../frameworks/base/docs/html/samples/samples_toc.cs" ?>
    +-      <?cs elif:preview ?>
    +-        <?cs include:"../../../../frameworks/base/docs/html/preview/preview_toc.cs" ?>
    +-      <?cs elif:preview ?>
    +-        <?cs include:"../../../../frameworks/base/docs/html/wear/preview/preview_toc.cs" ?>
    +-      <?cs elif:distribute ?>
    +-        <?cs if:googleplay ?>
    +-          <?cs include:"../../../../frameworks/base/docs/html/distribute/googleplay/googleplay_toc.cs" ?>
    +-        <?cs elif:essentials ?>
    +-          <?cs include:"../../../../frameworks/base/docs/html/distribute/essentials/essentials_toc.cs" ?>
    +-        <?cs elif:users ?>
    +-          <?cs include:"../../../../frameworks/base/docs/html/distribute/users/users_toc.cs" ?>
    +-        <?cs elif:engage ?>
    +-          <?cs include:"../../../../frameworks/base/docs/html/distribute/engage/engage_toc.cs" ?>
    +-        <?cs elif:monetize ?>
    +-          <?cs include:"../../../../frameworks/base/docs/html/distribute/monetize/monetize_toc.cs" ?>
    +-        <?cs elif:analyze ?>
    +-          <?cs include:"../../../../frameworks/base/docs/html/distribute/analyze/analyze_toc.cs" ?>
    +-        <?cs elif:disttools ?>
    +-          <?cs include:"../../../../frameworks/base/docs/html/distribute/tools/disttools_toc.cs" ?>
    +-        <?cs elif:stories ?>
    +-          <?cs include:"../../../../frameworks/base/docs/html/distribute/stories/stories_toc.cs" ?>
    +-        <?cs /if ?>
    +-      <?cs elif:about ?>
    +-        <?cs include:"../../../../frameworks/base/docs/html/about/about_toc.cs" ?>
    +-      <?cs else ?>
    +-        <?cs call:reference_default_nav() ?>
    +-      <?cs /if ?>
    +-    </div>
    +-  <?cs /if ?>
    +-<?cs /def ?><?cs
    +-
    +-# appears at the bottom of every page ?><?cs
    +-def:custom_cc_copyright() ?>
    +-  Except as noted, this content is
    +-  licensed under <a href="http://creativecommons.org/licenses/by/2.5/">
    +-  Creative Commons Attribution 2.5</a>. For details and
    +-  restrictions, see the <a href="<?cs var:toroot ?>license.html">Content
    +-  License</a>.
    +-<?cs /def ?><?cs
    +-
    +-def:custom_copyright() ?>
    +-  Except as noted, this content is licensed under <a
    +-  href="http://www.apache.org/licenses/LICENSE-2.0">Apache 2.0</a>.
    +-  For details and restrictions, see the <a href="<?cs var:toroot ?>license.html">
    +-  Content License</a>.
    +-<?cs /def ?><?cs
    +-
    +-def:custom_footerlinks() ?>
    +-  <a href="<?cs var:toroot ?>about/android.html">About Android</a>
    +-  <a href="<?cs var:toroot ?>auto/index.html">Auto</a>
    +-  <a href="<?cs var:toroot ?>tv/index.html">TV</a>
    +-  <a href="<?cs var:toroot ?>wear/index.html">Wear</a>
    +-  <a href="<?cs var:toroot ?>legal.html">Legal</a>
    +-<?cs /def ?><?cs
    +-
    +-# appears on the right side of the blue bar at the bottom off every page ?><?cs
    +-def:custom_buildinfo() ?>
    +-  <?cs if:!google && !reference.gcm && !reference.gms ?>
    +-    Android <?cs var:sdk.version ?>&nbsp;r<?cs var:sdk.rel.id ?> &mdash;
    +-  <?cs /if ?>
    +-  <script src="<?cs var:toroot ?>timestamp.js" type="text/javascript"></script>
    +-  <script>document.write(BUILD_TIMESTAMP)</script>
    +-<?cs /def ?>
    +\ No newline at end of file
    +diff --git a/tools/droiddoc/templates-sdk-dev/data.hdf b/tools/droiddoc/templates-sdk-dev/data.hdf
    +deleted file mode 100644
    +index 9411b78..0000000
    +--- a/tools/droiddoc/templates-sdk-dev/data.hdf
    ++++ /dev/null
    +@@ -1,4 +0,0 @@
    +-template {
    +-    which = normal
    +-}
    +-
    +diff --git a/tools/droiddoc/templates-sdk-dev/designpage.cs b/tools/droiddoc/templates-sdk-dev/designpage.cs
    +deleted file mode 100644
    +index d75ce0a..0000000
    +--- a/tools/droiddoc/templates-sdk-dev/designpage.cs
    ++++ /dev/null
    +@@ -1,104 +0,0 @@
    +-<!DOCTYPE html>
    +-<?cs include:"macros.cs" ?>
    +-<html lang="en">
    +-  <head>
    +-    <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
    +-    <title>
    +-      Android Design<?cs if:page.title ?> - <?cs var:page.title ?><?cs /if ?>
    +-    </title>
    +-    <link rel="shortcut icon" type="image/x-icon" href="/favicon.ico">
    +-    <link rel="stylesheet" href="http://fonts.googleapis.com/css?family=Roboto:regular,medium,thin,italic,mediumitalic">
    +-    <link rel="stylesheet" href="<?cs var:toroot ?>assets/yui-3.3.0-reset-min.css">
    +-    <link rel="stylesheet" href="<?cs var:toroot ?>assets/design/default.css">
    +-    <script src="<?cs var:toroot ?>assets/jquery-1.6.2.min.js"></script>
    +-    <script>var SITE_ROOT = '<?cs var:toroot ?>design';</script>
    +-    <script src="<?cs var:toroot ?>assets/design/default.js"></script>
    +-  </head>
    +-  <body class="gc-documentation 
    +-    <?cs if:(guide||develop||training||reference||tools||sdk) ?>develop<?cs
    +-    elif:design ?>design<?cs
    +-    elif:distribute ?>distribute<?cs
    +-    /if ?>" itemscope itemtype="http://schema.org/Article">
    +-    <a name="top"></a>
    +-
    +-    <div id="page-container">
    +-
    +-      <div id="page-header" itemscope itemtype="http://schema.org/WPHeader"><a href="<?cs var:toroot ?>design/index.html">Android Design</a></div>
    +-
    +-      <div id="main-row">
    +-
    +-        <div id="nav-container" itemscope itemtype="http://schema.org/SiteNavigationElement">
    +-
    +-        <?cs call:design_nav() ?>
    +-
    +-        </div>
    +-
    +-        <div id="content">
    +-
    +-<?cs if:header.hide ?>
    +-<?cs else ?>
    +-<div class="content-header <?cs if:header.justLinks ?>just-links<?cs /if ?>">
    +-    <?cs if:header.justLinks ?>&nbsp;
    +-      <?cs elif:header.title ?><h2><?cs var:header.title ?></h2>
    +-                   <?cs else ?><h2><?cs var:page.title ?></h2>
    +-    <?cs /if ?>
    +-</div>
    +-<?cs /if ?>
    +-
    +-<?cs call:tag_list(root.descr) ?>
    +-
    +-<?cs if:footer.hide ?>
    +-<?cs else ?>
    +-<div class="cols content-footer" itemscope itemtype="http://schema.org/SiteNavigationElement">
    +-  <div class="paging-links col-9">&nbsp;</div>
    +-  <div class="paging-links col-4">
    +-    <a href="#" class="prev-page-link">Previous</a>
    +-    <a href="#" class="next-page-link">Next</a>
    +-  </div>
    +-</div>
    +-<?cs /if ?>
    +-
    +-        </div>
    +-
    +-      </div>
    +-
    +-      <div id="page-footer" itemscope itemtype="http://schema.org/WPFooter">
    +-
    +-        <p id="copyright">
    +-          Except as noted, this content is licensed under
    +-          <a href="http://creativecommons.org/licenses/by/2.5/">
    +-          Creative Commons Attribution 2.5</a>.<br>
    +-          For details and restrictions, see the
    +-          <a href="http://developer.android.com/license.html">Content License</a>.
    +-        </p>
    +-
    +-        <p>
    +-          <a href="http://www.android.com/terms.html">Site Terms of Service</a> &ndash;
    +-          <a href="http://www.android.com/privacy.html">Privacy Policy</a> &ndash;
    +-          <a href="http://www.android.com/branding.html">Brand Guidelines</a>
    +-        </p>
    +-
    +-      </div>
    +-    </div>
    +-
    +-    <script type="text/javascript">
    +-    var gaJsHost = (("https:" == document.location.protocol) ? "https://ssl." : "http://www.");
    +-    document.write(unescape("%3Cscript src='" + gaJsHost + "google-analytics.com/ga.js' type='text/javascript'%3E%3C/script%3E"));
    +-    </script>
    +-    <script type="text/javascript">
    +-    var pageTracker = _gat._getTracker("UA-5831155-1");
    +-    pageTracker._trackPageview();
    +-    </script>
    +-
    +-<!-- Start of Tag -->
    +-<script type="text/javascript">
    +-var axel = Math.random() + "";
    +-var a = axel * 10000000000000;
    +-document.write('<iframe src="https://2507573.fls.doubleclick.net/activityi;src=2507573;type=other026;cat=googl348;ord=' + a + '?" width="1" height="1" frameborder="0" style="display:none"></iframe>');
    +-</script>
    +-<noscript>
    +-<iframe src="https://2507573.fls.doubleclick.net/activityi;src=2507573;type=other026;cat=googl348;ord=1?" width="1" height="1" frameborder="0" style="display:none"></iframe>
    +-</noscript>
    +-<!-- End of Tag -->
    +-  </body>
    +-</html>
    +diff --git a/tools/droiddoc/templates-sdk-dev/docpage.cs b/tools/droiddoc/templates-sdk-dev/docpage.cs
    +deleted file mode 100644
    +index e8a5ba3..0000000
    +--- a/tools/droiddoc/templates-sdk-dev/docpage.cs
    ++++ /dev/null
    +@@ -1,261 +0,0 @@
    +-<?cs if:!devsite ?><?cs
    +-  include:"doctype.cs" ?><?cs /if ?><?cs
    +-  include:"macros.cs" ?><html<?cs if:devsite ?> devsite<?cs /if ?>>
    +-<?cs include:"head_tag.cs" ?>
    +-<body<?cs
    +-if:!devsite ?> class="gc-documentation<?cs
    +-# add document classes for navigation header selection (and other stuff) ?>
    +-<?cs
    +-  if:(google || reference.gms || reference.gcm) ?>google <?cs /if ?><?cs
    +-  if:ndk ?>ndk<?cs
    +-    if:guide ?> guide<?cs /if ?><?cs
    +-    if:samples ?> samples<?cs /if ?><?cs
    +-    if:reference ?> reference<?cs /if ?><?cs
    +-    if:downloads ?> downloads<?cs /if ?><?cs
    +-  else ?><?cs
    +-    if:(guide||develop||training||reference||tools||sdk||google||samples) ?>develop<?cs
    +-      if:guide ?> guide<?cs /if ?><?cs
    +-      if:samples ?> samples<?cs /if ?><?cs
    +-    elif:(distribute||googleplay||essentials||users||engage||monetize||disttools||stories||analyze) ?>distribute<?cs
    +-      if:googleplay ?> googleplay<?cs /if ?><?cs
    +-      if:essentials ?> essentials<?cs /if ?><?cs
    +-      if:users ?> users<?cs /if ?><?cs
    +-      if:engage ?> engage<?cs /if ?><?cs
    +-      if:monetize ?> monetize<?cs /if ?><?cs
    +-      if:disttools ?> disttools<?cs /if ?><?cs
    +-      if:stories ?> stories<?cs /if ?><?cs
    +-      if:analyze ?> analyze<?cs /if ?><?cs
    +-    elif:(design||vision||material||patterns||devices||designdownloads) ?> design<?cs
    +-      if:vision ?> vision<?cs /if ?><?cs
    +-      if:material ?> material<?cs /if ?><?cs
    +-      if:patterns ?> patterns<?cs /if ?><?cs
    +-      if:devices ?> devices<?cs /if ?><?cs
    +-      if:designdownloads ?> designdownloads<?cs /if ?><?cs
    +-    elif:(about||versions||wear||tv||auto) ?> about<?cs
    +-      if:versions ?> versions<?cs /if ?><?cs
    +-      if:wear ?> wear<?cs /if ?><?cs
    +-      if:tv ?> tv<?cs /if ?><?cs
    +-      if:auto ?> auto<?cs /if ?><?cs
    +-    elif:(preview) ?> preview<?cs
    +-    /if ?><?cs
    +-    if:page.trainingcourse ?> trainingcourse<?cs /if ?><?cs
    +-  /if ?>" itemscope itemtype="http://schema.org/Article"><?cs
    +-/if ?>><?cs
    +-include:"header.cs" ?><?cs
    +-
    +-if:(design||training||walkthru) && !page.trainingcourse && !page.article ?><?cs
    +-# header logic for docs that provide previous/next buttons ?><?cs
    +-  if:(header.hide||devsite) ?><?cs
    +-  else ?>
    +-    <div class="content-header <?cs if:header.justLinks ?>just-links<?cs /if ?>">
    +-      <?cs if:header.justLinks ?>&nbsp;
    +-      <?cs else ?>
    +-        <ul class="dac-header-crumbs">
    +-          <?cs # More <li> elements added here with javascript ?>
    +-        </ul>
    +-
    +-        <!-- Breadcrumb Setup -->
    +-        <script>$('.dac-nav-list').dacCurrentPage().dacCrumbs();</script>
    +-
    +-        <h1 itemprop="name"><?cs var:page.title ?>
    +-      </h1><?cs
    +-      /if ?><?cs
    +-      if:training ?>
    +-      <div class="training-nav-top" itemscope itemtype="http://schema.org/SiteNavigationElement">
    +-        <a href="#" class="prev-page-link hide"
    +-            zh-tw-lang="上一堂課"
    +-            zh-cn-lang="上一课"
    +-            ru-lang="Предыдущий"
    +-            ko-lang="이전"
    +-            ja-lang="前へ"
    +-            es-lang="Anterior"
    +-            >Previous</a>
    +-        <a href="#" class="next-page-link hide"
    +-            zh-tw-lang="下一堂課"
    +-            zh-cn-lang="下一课"
    +-            ru-lang="Следующий"
    +-            ko-lang="다음"
    +-            ja-lang="次へ"
    +-            es-lang="Siguiente"
    +-            >Next</a>
    +-        <a href="#" class="start-class-link hide"
    +-            zh-tw-lang="開始上課"
    +-            zh-cn-lang="开始"
    +-            ru-lang="Начало работы"
    +-            ko-lang="시작하기"
    +-            ja-lang="開始する"
    +-            es-lang="Empezar"
    +-            >Get started</a>
    +-      </div><?cs
    +-      elif:!page.trainingcourse ?>
    +-      <?cs # <div class="paging-linkss" itemscope itemtype="http://schema.org/SiteNavigationElement">
    +-        <a href="#" class="prev-page-link hide"
    +-            zh-tw-lang="上一堂課"
    +-            zh-cn-lang="上一课"
    +-            ru-lang="Предыдущий"
    +-            ko-lang="이전"
    +-            ja-lang="前へ"
    +-            es-lang="Anterior"
    +-            >Previous</a>
    +-        <a href="#" class="next-page-link hide"
    +-            zh-tw-lang="下一堂課"
    +-            zh-cn-lang="下一课"
    +-            ru-lang="Следующий"
    +-            ko-lang="다음"
    +-            ja-lang="次へ"
    +-            es-lang="Siguiente"
    +-            >Next</a>
    +-      </div> ?><?cs
    +-      /if ?><?cs # end if training ?>
    +-  </div>
    +-  <?cs /if ?><?cs # end if header.hide ?><?cs
    +-
    +-elif:samplesProjectIndex ?>
    +-  <div id="api-info-block">
    +-  <div class="sum-details-links">
    +-  Overview
    +-  &#124; <a href="<?cs var:toroot ?>samples/<?cs var:projectDir ?>/project.html">Project</a>
    +-  &#124; <a href="<?cs var:toroot ?>downloads/samples/<?cs var:projectDir ?>.zip">Download</a>
    +-  </div><!-- end sum-details-links -->
    +-  </div><!-- end breadcurmb block -->
    +-  <h1 itemprop="name"><?cs var:projectDir ?></h1>
    +-
    +-<?cs else ?><?cs
    +-  if:(!fullpage && !header.hide && !devsite) ?><?cs
    +-    if:page.landing ?><?cs # header logic for docs that are landing pages ?>
    +-      <div class="landing-banner">
    +-        <?cs if:page.landing.image ?><?cs # use two-column layout only if there is an image ?>
    +-        <div class="cols">
    +-          <div class="col-6">
    +-            <img src="<?cs var:toroot ?><?cs var:page.landing.image ?>" alt="" />
    +-          </div>
    +-          <div class="col-6">
    +-        <?cs /if ?>
    +-          <h1 itemprop="name" style="margin-bottom:0;"><?cs var:page.title ?></h1>
    +-          <p itemprop="description"><?cs var:page.landing.intro ?></p>
    +-
    +-          <p><a class="next-page-link topic-start-link"></a></p>
    +-        <?cs if:page.landing.image ?>
    +-          </div>
    +-        </div>
    +-        <?cs /if ?>
    +-      </div>
    +-    <?cs else ?><?cs
    +-      if:tab1 ?><div id="title-tabs-wrapper"><?cs /if ?>
    +-        <ul class="dac-header-crumbs">
    +-          <?cs # More <li> elements added here with javascript ?>
    +-        </ul>
    +-
    +-        <!-- Breadcrumb Setup -->
    +-        <p><script>$('.dac-nav-list').dacCurrentPage().dacCrumbs();</script></p>
    +-
    +-        <h1 itemprop="name" <?cs if:tab1 ?>class="with-title-tabs"<?cs /if ?>><?cs var:page.title ?></h1><?cs
    +-          if:tab1 ?><ul id="title-tabs">
    +-              <li class="selected"><a href="<?cs var:tab1.link ?>"><?cs var:tab1 ?></a></li>
    +-              <?cs if:tab2 ?>
    +-              <li><a href="<?cs var:tab2.link ?>"><?cs var:tab2 ?></a></li><?cs /if ?>
    +-              <?cs if:tab3 ?>
    +-              <li><a href="<?cs var:tab3.link ?>"><?cs var:tab3 ?></a></li><?cs /if ?>
    +-            </ul>
    +-          <?cs /if ?>
    +-      <?cs if:tab1 ?></div><!-- end tab-wrapper --><?cs /if ?><?cs
    +-    /if ?><?cs
    +-  /if ?><?cs
    +-/if ?><?cs # end if design ?><?cs
    +-
    +-if devsite ?><?cs
    +-  if:tab1 ?>
    +-  <div id="title-tabs-wrapper">
    +-    <ul id="title-tabs">
    +-      <li class="selected"><a href="<?cs var:tab1.link ?>"><?cs var:tab1 ?></a></li>
    +-      <?cs if:tab2 ?>
    +-      <li><a href="<?cs var:tab2.link ?>"><?cs var:tab2 ?></a></li><?cs /if ?>
    +-      <?cs if:tab3 ?>
    +-      <li><a href="<?cs var:tab3.link ?>"><?cs var:tab3 ?></a></li><?cs /if ?>
    +-    </ul>
    +-  </div><!-- end tab-wrapper --><?cs
    +-  /if ?><?cs
    +-/if ?><?cs
    +-
    +-# THIS IS THE MAIN DOC CONTENT ?><?cs
    +-  if:!devsite ?>
    +-  <div id="jd-content">
    +-    <div class="jd-descr" itemprop="articleBody"><?cs
    +-  /if ?><?cs
    +-  if:(!fullpage && !header.hide && devsite) ?><?cs
    +-    if:page.landing ?><?cs # header logic for docs that are landing pages ?>
    +-        <div class="landing-banner">
    +-          <?cs if:page.landing.image ?><?cs # use two-column layout only if there is an image ?>
    +-          <div class="cols">
    +-            <div class="col-6">
    +-              <img src="<?cs var:toroot ?><?cs var:page.landing.image ?>" alt="" />
    +-            </div>
    +-            <div class="col-6">
    +-          <?cs /if ?>
    +-            <h1 itemprop="name" style="margin-bottom:0;"><?cs var:page.title ?></h1>
    +-            <p itemprop="description"><?cs var:page.landing.intro ?></p>
    +-
    +-            <p><a class="next-page-link topic-start-link"></a></p><?cs
    +-            if:page.landing.image ?>
    +-            </div>
    +-          </div><?cs
    +-          /if ?>
    +-        </div><?cs
    +-    /if ?><?cs
    +-  /if ?>
    +-
    +-<?cs call:tag_list(root.descr) ?><?cs
    +-
    +-if:!devsite ?>
    +-    </div><!-- end jd-descr --><?cs
    +-/if ?><?cs
    +-
    +-if:!fullscreen && (design||training||walkthru) && !page.landing && !page.trainingcourse
    +-      && !footer.hide && !devsite?>
    +-      <div class="content-footer <?cs
    +-                    if:fullpage ?>wrap<?cs /if ?>"
    +-                    itemscope itemtype="http://schema.org/SiteNavigationElement">
    +-          <div class="paging-links">
    +-            <a href="#" class="prev-page-link hide"
    +-              zh-tw-lang="上一堂課"
    +-              zh-cn-lang="上一课"
    +-              ru-lang="Предыдущий"
    +-              ko-lang="이전"
    +-              ja-lang="前へ"
    +-              es-lang="Anterior"
    +-              ><span class="page-link-caption">Previous</span>
    +-            </a>
    +-            <a href="#" class="next-page-link hide"
    +-                zh-tw-lang="下一堂課"
    +-                zh-cn-lang="下一课"
    +-                ru-lang="Следующий"
    +-                ko-lang="다음"
    +-                ja-lang="次へ"
    +-                es-lang="Siguiente"
    +-                ><span class="page-link-caption">Next</span>
    +-            </a>
    +-            <a href="#" class="start-class-link hide"
    +-                zh-tw-lang="開始上課"
    +-                zh-cn-lang="开始"
    +-                ru-lang="Начало работы"
    +-                ko-lang="시작하기"
    +-                ja-lang="開始する"
    +-                es-lang="Empezar"
    +-                >Get started</a>
    +-            <a href="#" class="next-class-link hide">
    +-              <span class="page-link-caption">Next class</span>
    +-            </a>
    +-          </div>
    +-      </div><?cs
    +-    /if ?><?cs
    +-if:!devsite ?>
    +-  </div> <!-- end jd-content --><?cs
    +-/if ?><?cs
    +-
    +-if:!devsite ?>
    +-<?cs include:"footer.cs" ?>
    +-<?cs include:"trailer.cs" ?>
    +-<?cs /if ?>
    +-
    +-</body>
    +-</html>
    +diff --git a/tools/droiddoc/templates-sdk-dev/footer.cs b/tools/droiddoc/templates-sdk-dev/footer.cs
    +deleted file mode 100644
    +index af34a1a..0000000
    +--- a/tools/droiddoc/templates-sdk-dev/footer.cs
    ++++ /dev/null
    +@@ -1,219 +0,0 @@
    +-<?cs # page footer content ?>
    +-<div class="wrap">
    +-  <div class="dac-footer<?cs if:fullpage ?> dac-landing<?cs /if ?>">
    +-    <div class="cols dac-footer-main">
    +-      <div class="col-1of2">
    +-        <a class="dac-footer-getnews" id="newsletter" data-modal-toggle="newsletter" href="javascript:;">Get news &amp; tips <span
    +-          class="dac-fab dac-primary"><i class="dac-sprite dac-mail"></i></span></a>
    +-      </div>
    +-      <div class="col-1of2 dac-footer-reachout">
    +-        <div class="dac-footer-contact">
    +-          <a class="dac-footer-contact-link" href="http://android-developers.blogspot.com/">Blog</a>
    +-          <a class="dac-footer-contact-link" href="/support.html">Support</a>
    +-        </div>
    +-        <div class="dac-footer-social">
    +-          <a class="dac-button-social dac-youtube dac-footer-social-link" href="https://www.youtube.com/user/androiddevelopers"><i class="dac-sprite dac-youtube"></i></a>
    +-          <a class="dac-button-social dac-gplus dac-footer-social-link" href="https://plus.google.com/+AndroidDevelopers"><i class="dac-sprite dac-gplus"></i></a>
    +-          <a class="dac-button-social dac-twitter dac-footer-social-link" href="https://twitter.com/AndroidDev"><i class="dac-sprite dac-twitter"></i></a>
    +-        </div>
    +-      </div>
    +-    </div>
    +-
    +-    <hr class="dac-footer-separator"/>
    +-
    +-    <?cs if:reference ?>
    +-      <p class="dac-footer-copyright">
    +-        <?cs call:custom_copyright() ?>
    +-      </p>
    +-      <p class="dac-footer-build">
    +-        <?cs call:custom_buildinfo() ?>
    +-      </p>
    +-    <?cs elif:!hide_license_footer ?>
    +-      <p class="dac-footer-copyright">
    +-        <?cs call:custom_cc_copyright() ?>
    +-      </p>
    +-    <?cs /if ?>
    +-
    +-    <p class="dac-footer-links">
    +-      <a href="/about/android.html">About Android</a>
    +-      <a href="/auto/index.html">Auto</a>
    +-      <a href="/tv/index.html">TV</a>
    +-      <a href="/wear/index.html">Wear</a>
    +-      <a href="/legal.html">Legal</a>
    +-
    +-      <span id="language" class="locales">
    +-        <select name="language" onchange="changeLangPref(this.value, true)">
    +-          <option value="en" selected="selected">English</option>
    +-          <option value="es">Español</option>
    +-          <option value="in">Bahasa Indonesia</option>
    +-          <option value="ja">日本語</option>
    +-          <option value="ko">한국어</option>
    +-          <option value="pt-br">Português Brasileiro</option>
    +-          <option value="ru">Русский</option>
    +-          <option value="vi">tiếng Việt</option>
    +-          <option value="zh-cn">中文(简体)</option>
    +-          <option value="zh-tw">中文(繁體)</option>
    +-        </select>
    +-      </span>
    +-    </p>
    +-  </div>
    +-</div>
    +-<!-- end footer -->
    +-
    +-<?cs call:toast() ?>
    +-
    +-<div data-modal="newsletter" data-newsletter data-swap class="dac-modal newsletter">
    +-  <div class="dac-modal-container">
    +-    <div class="dac-modal-window">
    +-      <header class="dac-modal-header">
    +-        <div class="dac-modal-header-actions">
    +-          <button class="dac-modal-header-close" data-modal-toggle></button>
    +-        </div>
    +-        <div class="dac-swap" data-swap-container>
    +-          <section class="dac-swap-section dac-active dac-down">
    +-            <h2 class="norule dac-modal-header-title" data-t="newsletter.title"></h2>
    +-            <p class="dac-modal-header-subtitle" data-t="newsletter.requiredHint"></p>
    +-          </section>
    +-          <section class="dac-swap-section dac-up">
    +-            <h2 class="norule dac-modal-header-title" data-t="newsletter.successTitle">Hooray!</h2>
    +-          </section>
    +-        </div>
    +-      </header>
    +-      <div class="dac-swap" data-swap-container>
    +-        <section class="dac-swap-section dac-active dac-left">
    +-          <form action="https://docs.google.com/forms/d/1QgnkzbEJIDu9lMEea0mxqWrXUJu0oBCLD7ar23V0Yys/formResponse" class="dac-form" method="post" target="dac-newsletter-iframe">
    +-            <input type="hidden" name="entry.935454734" data-newsletter-language>
    +-            <section class="dac-modal-content">
    +-              <fieldset class="dac-form-fieldset">
    +-                <div class="cols">
    +-                  <div class="col-1of2 newsletter-leftCol">
    +-                    <div class="dac-form-input-group">
    +-                      <label for="newsletter-full-name" class="dac-form-floatlabel" data-t="newsletter.name">Full name</label>
    +-                      <input type="text" class="dac-form-input" name="entry.1357890476" id="newsletter-full-name" required>
    +-                      <span class="dac-form-required">*</span>
    +-                    </div>
    +-                    <div class="dac-form-input-group">
    +-                      <label for="newsletter-email" class="dac-form-floatlabel" data-t="newsletter.email">Email address</label>
    +-                      <input type="email" class="dac-form-input" name="entry.472100832" id="newsletter-email" required>
    +-                      <span class="dac-form-required">*</span>
    +-                    </div>
    +-                  </div>
    +-                  <div class="col-1of2 newsletter-rightCol">
    +-                    <div class="dac-form-input-group">
    +-                      <label for="newsletter-company" class="dac-form-floatlabel" data-t="newsletter.company">Company / developer name</label>
    +-                      <input type="text" class="dac-form-input" name="entry.1664780309" id="newsletter-company">
    +-                    </div>
    +-                    <div class="dac-form-input-group">
    +-                      <label for="newsletter-play-store" class="dac-form-floatlabel" data-t="newsletter.appUrl">One of your Play Store app URLs</label>
    +-                      <input type="url" class="dac-form-input" name="entry.47013838" id="newsletter-play-store" required>
    +-                      <span class="dac-form-required">*</span>
    +-                    </div>
    +-                  </div>
    +-                </div>
    +-              </fieldset>
    +-              <fieldset class="dac-form-fieldset">
    +-                <div class="cols">
    +-                  <div class="col-1of2 newsletter-leftCol">
    +-                    <legend class="dac-form-legend"><span data-t="newsletter.business.label">Which best describes your business:</span><span class="dac-form-required">*</span>
    +-                    </legend>
    +-                    <div class="dac-form-radio-group">
    +-                      <input type="radio" value="Apps" class="dac-form-radio" name="entry.1796324055" id="newsletter-business-type-app" required>
    +-                      <label for="newsletter-business-type-app" class="dac-form-radio-button"></label>
    +-                      <label for="newsletter-business-type-app" class="dac-form-label" data-t="newsletter.business.apps">Apps</label>
    +-                    </div>
    +-                    <div class="dac-form-radio-group">
    +-                      <input type="radio" value="Games" class="dac-form-radio" name="entry.1796324055" id="newsletter-business-type-games" required>
    +-                      <label for="newsletter-business-type-games" class="dac-form-radio-button"></label>
    +-                      <label for="newsletter-business-type-games" class="dac-form-label" data-t="newsletter.business.games">Games</label>
    +-                    </div>
    +-                    <div class="dac-form-radio-group">
    +-                      <input type="radio" value="Apps and Games" class="dac-form-radio" name="entry.1796324055" id="newsletter-business-type-appsgames" required>
    +-                      <label for="newsletter-business-type-appsgames" class="dac-form-radio-button"></label>
    +-                      <label for="newsletter-business-type-appsgames" class="dac-form-label" data-t="newsletter.business.both">Apps &amp; Games</label>
    +-                    </div>
    +-                  </div>
    +-                  <div class="col-1of2 newsletter-rightCol newsletter-checkboxes">
    +-                    <div class="dac-form-radio-group">
    +-                      <div class="dac-media">
    +-                        <div class="dac-media-figure">
    +-                          <input type="checkbox" class="dac-form-checkbox" name="entry.732309842" id="newsletter-add" required value="Add me to the mailing list for the monthly newsletter and occasional emails about development and Google Play opportunities.">
    +-                          <label for="newsletter-add" class="dac-form-checkbox-button"></label>
    +-                        </div>
    +-                        <div class="dac-media-body">
    +-                          <label for="newsletter-add" class="dac-form-label dac-form-aside"><span data-t="newsletter.confirmMailingList"></span><span class="dac-form-required">*</span></label>
    +-                        </div>
    +-                      </div>
    +-                    </div>
    +-                    <div class="dac-form-radio-group">
    +-                      <div class="dac-media">
    +-                        <div class="dac-media-figure">
    +-                          <input type="checkbox" class="dac-form-checkbox" name="entry.2045036090" id="newsletter-terms" required value="I acknowledge that the information provided in this form will be subject to Google's privacy policy (https://www.google.com/policies/privacy/).">
    +-                          <label for="newsletter-terms" class="dac-form-checkbox-button"></label>
    +-                        </div>
    +-                        <div class="dac-media-body">
    +-                          <label for="newsletter-terms" class="dac-form-label dac-form-aside"><span data-t="newsletter.privacyPolicy" data-t-html></span><span class="dac-form-required">*</span></label>
    +-                        </div>
    +-                      </div>
    +-                    </div>
    +-                  </div>
    +-                </div>
    +-              </fieldset>
    +-            </section>
    +-            <footer class="dac-modal-footer">
    +-              <div class="cols">
    +-                <div class="col-2of5">
    +-                </div>
    +-              </div>
    +-              <button type="submit" value="Submit" class="dac-fab dac-primary dac-large dac-modal-action"><i class="dac-sprite dac-arrow-right"></i></button>
    +-            </footer>
    +-          </form>
    +-        </section>
    +-        <section class="dac-swap-section dac-right">
    +-          <div class="dac-modal-content">
    +-            <p class="newsletter-success-message" data-t="newsletter.successDetails"></p>
    +-          </div>
    +-        </section>
    +-      </div>
    +-    </div>
    +-  </div>
    +-</div>
    +-<!-- end newsletter modal -->
    +-
    +-<!-- start reset language header modal -->
    +-<div data-modal="langform" class="dac-modal" id="langform">
    +-  <div class="dac-modal-container">
    +-    <div class="dac-modal-window">
    +-      <header class="dac-modal-header">
    +-        <div class="dac-modal-header-actions">
    +-          <button class="dac-modal-header-close" data-modal-toggle></button>
    +-        </div>
    +-        <section class="dac-swap-section dac-active dac-down">
    +-          <h2 class="norule dac-modal-header-title"></h2>
    +-        </section>
    +-      </header>
    +-      <section class="dac-swap-section dac-active dac-left">
    +-          <section class="dac-modal-content">
    +-            <fieldset class="dac-form-fieldset">
    +-              <div class="cols">
    +-                <div class="col-2of2 langform-leftCol">
    +-                  <p id="resetLangText"></p>
    +-                  <p id="resetLangCta"></p>
    +-                </div>
    +-              </div>
    +-            </fieldset>
    +-          </section>
    +-          <footer class="dac-modal-footer" id="langfooter">
    +-            <div class="cols">
    +-              <div class="col-2of5">
    +-              </div>
    +-            </div>
    +-              <button class="button dac-primary dac-modal-action lang yes" data-t="newsletter.resetLangButtonYes" data-modal-toggle></button>
    +-              <button class="button dac-primary dac-modal-action lang no" data-t="newsletter.resetLangButtonNo" data-modal-toggle></button>
    +-            </a>
    +-          </footer>
    +-        </form>
    +-      </section>
    +-    </div>
    +-  </div>
    +-</div>
    +-<!-- end langreset modal -->
    +diff --git a/tools/droiddoc/templates-sdk-dev/gcm_navtree_data.cs b/tools/droiddoc/templates-sdk-dev/gcm_navtree_data.cs
    +deleted file mode 100644
    +index 6f33d88..0000000
    +--- a/tools/droiddoc/templates-sdk-dev/gcm_navtree_data.cs
    ++++ /dev/null
    +@@ -1,3 +0,0 @@
    +-var GCM_NAVTREE_DATA =
    +-<?cs var:reference_tree ?>
    +-;
    +diff --git a/tools/droiddoc/templates-sdk-dev/gms_navtree_data.cs b/tools/droiddoc/templates-sdk-dev/gms_navtree_data.cs
    +deleted file mode 100644
    +index 66b7d55..0000000
    +--- a/tools/droiddoc/templates-sdk-dev/gms_navtree_data.cs
    ++++ /dev/null
    +@@ -1,3 +0,0 @@
    +-var GMS_NAVTREE_DATA =
    +-<?cs var:reference_tree ?>
    +-;
    +diff --git a/tools/droiddoc/templates-sdk-dev/head_tag.cs b/tools/droiddoc/templates-sdk-dev/head_tag.cs
    +deleted file mode 100644
    +index 0c5bb78..0000000
    +--- a/tools/droiddoc/templates-sdk-dev/head_tag.cs
    ++++ /dev/null
    +@@ -1,219 +0,0 @@
    +-<head>
    +-  <title><?cs
    +-if:devsite ?><?cs
    +-  if:page.title ?><?cs
    +-    var:html_strip(page.title) ?><?cs
    +-  else ?>Android Developers<?cs
    +-  /if ?><?cs
    +-else ?><?cs
    +-  if:page.title ?><?cs
    +-    var:page.title ?> | <?cs
    +-  /if ?>Android Developers
    +-<?cs /if ?><?cs
    +-# END if/else devsite ?></title><?cs
    +-  ####### If building devsite, add some meta data needed for when generating the top nav ######### ?><?cs
    +-if:devsite ?>
    +-  <meta name="top_category" value="<?cs
    +-      if:ndk ?>ndk<?cs
    +-      elif:(guide||develop||training||reference||tools||sdk||google||reference.gms||reference.gcm||samples) ?>develop<?cs
    +-      elif:(topic||libraries||instantapps||perf||arc) ?>develop<?cs
    +-      elif:(distribute||googleplay||essentials||users||engage||monetize||disttools||stories||analyze) ?>distribute<?cs
    +-      elif:(design||vision||material||patterns||devices||designdownloads) ?>design<?cs
    +-      elif:(about||versions||wear||tv||auto) ?>about<?cs
    +-      elif:wearpreview ?>about<?cs
    +-      elif:work ?>about<?cs
    +-      elif:preview ?>preview<?cs
    +-      else ?>none<?cs
    +-      /if ?>" /><?cs set:dac_subcategory_set = #1 ?>
    +-  <meta name="subcategory" value="<?cs
    +-      if:ndk ?><?cs
    +-        if:guide ?>guide<?cs
    +-        elif:samples ?>samples<?cs
    +-          if:(samplesDocPage&&!samplesProjectIndex) ?> samples-docpage<?cs /if ?><?cs
    +-        elif:reference ?>reference<?cs
    +-        elif:downloads ?>downloads<?cs
    +-        else ?>none<?cs set:dac_subcategory_set = #0 ?><?cs /if ?><?cs
    +-      else ?><?cs
    +-        if:(guide||develop||training||reference||tools||sdk||samples) ?><?cs
    +-          if:guide ?>guide<?cs
    +-          elif:training ?><?cs
    +-            if:page.trainingcourse ?>trainingcourse<?cs
    +-            else ?>training<?cs /if ?><?cs
    +-          elif:reference ?>reference<?cs
    +-          elif:samples ?>samples<?cs
    +-            if:(samplesDocPage&&!samplesProjectIndex) ?> samples-docpage<?cs /if ?><?cs
    +-          else ?>none<?cs set:dac_subcategory_set = #0 ?><?cs /if ?><?cs
    +-        elif:(google||reference.gms||reference.gcm) ?>google<?cs
    +-        elif:(topic||libraries||perf||arc) ?><?cs
    +-          if:libraries ?>libraries<?cs
    +-          elif:instantapps ?>instantapps<?cs
    +-          elif:perf ?>perf<?cs
    +-          elif:arc ?>arc<?cs
    +-          else ?>none<?cs set:dac_subcategory_set = #0 ?><?cs /if ?><?cs
    +-        elif:(distribute||googleplay||essentials||users||engage||monetize||disttools||stories||analyze) ?><?cs
    +-          if:googleplay ?>googleplay<?cs
    +-          elif:essentials ?>essentials<?cs
    +-          elif:users ?>users<?cs
    +-          elif:engage ?>engage<?cs
    +-          elif:monetize ?>monetize<?cs
    +-          elif:disttools ?>disttools<?cs
    +-          elif:stories ?>stories<?cs
    +-          elif:analyze ?>analyze<?cs
    +-          else ?>none<?cs set:dac_subcategory_set = #0 ?><?cs /if ?><?cs
    +-        elif:(about||versions||wear||tv||auto) ?>about<?cs
    +-        elif:preview ?>preview<?cs
    +-        elif:wearpreview ?>wear<?cs
    +-        elif:work ?>work<?cs
    +-        elif:design ?>design<?cs
    +-        elif:walkthru ?>walkthru<?cs
    +-        else ?>none<?cs set:dac_subcategory_set = #0 ?><?cs /if ?><?cs
    +-      /if ?>" /><?cs
    +-      if:nonavpage ?>
    +-  <meta name="hide_toc" value='True' /><?cs
    +-      elif: !nonavpage && dac_subcategory_set && !tools && !sdk ?>
    +-  <meta name="book_path" value="<?cs
    +-        if:ndk ?>/ndk<?cs
    +-          if:guide ?>/guides<?cs
    +-          elif:samples ?>/samples<?cs
    +-          elif:reference ?>/reference<?cs
    +-          elif:downloads ?>/downloads<?cs /if ?><?cs
    +-        else ?><?cs
    +-          if:(guide||develop||training||reference||tools||sdk||samples) ?><?cs
    +-            if:guide ?>/guide<?cs
    +-            elif:training ?>/training<?cs
    +-            elif:reference ?>/reference<?cs
    +-            elif:samples ?>/samples<?cs /if ?><?cs
    +-          elif:(google||reference.gms||reference.gcm) ?>/google<?cs
    +-          elif:(topic||libraries||perf) ?>/topic<?cs
    +-            if:libraries ?>/libraries<?cs
    +-            elif:instantapps ?>/instant-apps<?cs
    +-            elif:perf ?>/performance<?cs
    +-            elif:arc ?>/arc<?cs /if ?><?cs
    +-          elif:(distribute||googleplay||essentials||users||engage||monetize||disttools||stories||analyze) ?>/distribute<?cs
    +-            if:googleplay ?>/googleplay<?cs
    +-            elif:essentials ?>/essentials<?cs
    +-            elif:users ?>/users<?cs
    +-            elif:engage ?>/engage<?cs
    +-            elif:monetize ?>/monetize<?cs
    +-            elif:disttools ?>/tools<?cs
    +-            elif:stories ?>/stories<?cs
    +-            elif:analyze ?>/analyze<?cs /if ?><?cs
    +-          elif:(about||versions||wear||tv||auto) ?>/about<?cs
    +-          elif:preview ?>/preview<?cs
    +-          elif:wearpreview ?>/wear/preview<?cs
    +-          elif:work ?>/work<?cs
    +-          elif:design ?>/design<?cs
    +-          elif:reference.testSupport ?>/reference/android/support/test<?cs
    +-          elif:reference.wearableSupport ?>/reference/android/support/wearable<?cs
    +-          elif:walkthru ?>/walkthru<?cs /if ?><?cs
    +-        /if ?>/_book.yaml" /><?cs
    +-        /if ?>
    +-  <meta name="project_path" value="<?cs
    +-      if:(guide||develop||training||reference||tools||sdk||samples) ?><?cs
    +-        if:guide ?>/guide<?cs
    +-        elif:training ?>/training<?cs
    +-        elif:reference ?>/reference<?cs
    +-        elif:samples ?>/samples<?cs /if ?><?cs
    +-      elif:(google||reference.gms||reference.gcm) ?>/google<?cs
    +-      elif:(topic||libraries) ?>/develop<?cs
    +-      elif:(distribute||googleplay||essentials||users||engage||monetize||disttools||stories||analyze) ?>/distribute<?cs
    +-        if:googleplay ?>/googleplay<?cs
    +-        elif:essentials ?>/essentials<?cs
    +-        elif:users ?>/users<?cs
    +-        elif:engage ?>/engage<?cs
    +-        elif:monetize ?>/monetize<?cs
    +-        elif:disttools ?>/tools<?cs
    +-        elif:stories ?>/stories<?cs
    +-        elif:analyze ?>/analyze<?cs
    +-        else ?><?cs /if ?><?cs
    +-      elif:(about||versions||wear||tv||auto) ?>/about<?cs
    +-      elif:wearpreview ?>/wear<?cs
    +-      elif:work ?>/work<?cs
    +-      elif:preview ?>/preview<?cs
    +-      elif:design ?>/design<?cs /if ?>/_project.yaml" /><?cs
    +-
    +-      if:page.tags && page.tags != "" ?>
    +-  <meta name="keywords" value='<?cs var:page.tags ?>' /><?cs
    +-      /if ?><?cs
    +-      if:meta.tags && meta.tags != "" ?>
    +-  <meta name="meta_tags" value='<?cs var:meta.tags ?>' /><?cs
    +-      /if ?><?cs
    +-      if:fullpage ?>
    +-  <meta name="full_width" value="True" /><?cs
    +-      /if ?><?cs
    +-      if:page.landing ?>
    +-  <meta name="page_type" value="landing" /><?cs
    +-      /if ?><?cs
    +-      if:page.article ?>
    +-  <meta name="page_type" value="article" /><?cs
    +-      /if ?><?cs
    +-      if:page.image ?>
    +-  <meta name="image_path" value='<?cs var:page.image ?>' /><?cs
    +-      /if ?><?cs
    +-/if ?><?cs # END if/else devsite ?><?cs
    +-
    +-  if:!devsite ?>
    +-<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
    +-<meta name="viewport" content="width=device-width,initial-scale=1.0,minimum-scale=1.0,maximum-scale=1.0,user-scalable=no" />
    +-<meta content="IE=edge" http-equiv="X-UA-Compatible">
    +-<link rel="shortcut icon" type="image/x-icon" href="<?cs var:toroot ?>favicon.ico" />
    +-<link rel="alternate" href="http://developer.android.com/<?cs var:path.canonical ?>" hreflang="en" />
    +-<link rel="alternate" href="http://developer.android.com/intl/es/<?cs var:path.canonical ?>" hreflang="es" />
    +-<link rel="alternate" href="http://developer.android.com/intl/id/<?cs var:path.canonical ?>" hreflang="id" />
    +-<link rel="alternate" href="http://developer.android.com/intl/ja/<?cs var:path.canonical ?>" hreflang="ja" />
    +-<link rel="alternate" href="http://developer.android.com/intl/ko/<?cs var:path.canonical ?>" hreflang="ko" />
    +-<link rel="alternate" href="http://developer.android.com/intl/pt-br/<?cs var:path.canonical ?>" hreflang="pt-br" />
    +-<link rel="alternate" href="http://developer.android.com/intl/ru/<?cs var:path.canonical ?>" hreflang="ru" />
    +-<link rel="alternate" href="http://developer.android.com/intl/vi/<?cs var:path.canonical ?>" hreflang="vi" />
    +-<link rel="alternate" href="http://developer.android.com/intl/zh-cn/<?cs var:path.canonical ?>" hreflang="zh-cn" />
    +-<link rel="alternate" href="http://developer.android.com/intl/zh-tw/<?cs var:path.canonical ?>" hreflang="zh-tw" />
    +-<?cs /if ?><?cs
    +-# END if/else !devsite ?><?cs
    +-
    +-      if:page.metaDescription ?>
    +-  <meta name="description" content="<?cs var:page.metaDescription ?>"><?cs
    +-      /if ?><?cs
    +-  if:!devsite ?>
    +-<!-- STYLESHEETS -->
    +-<link rel="stylesheet"
    +-href="<?cs
    +-if:android.whichdoc != 'online' ?>http:<?cs
    +-/if ?>//fonts.googleapis.com/css?family=Roboto+Condensed">
    +-<link rel="stylesheet" href="<?cs
    +-if:android.whichdoc != 'online' ?>http:<?cs
    +-/if ?>//fonts.googleapis.com/css?family=Roboto:light,regular,medium,thin,italic,mediumitalic,bold"
    +-  title="roboto">
    +-<?cs
    +-  if:ndk ?><link rel="stylesheet" href="<?cs
    +-  if:android.whichdoc != 'online' ?>http:<?cs
    +-  /if ?>//fonts.googleapis.com/css?family=Roboto+Mono:400,500,700" title="roboto-mono" type="text/css"><?cs
    +-/if ?>
    +-<link href="<?cs var:toroot ?>assets/css/default.css?v=16" rel="stylesheet" type="text/css">
    +-
    +-<!-- JAVASCRIPT -->
    +-<script src="<?cs if:android.whichdoc != 'online' ?>http:<?cs /if ?>//www.google.com/jsapi" type="text/javascript"></script>
    +-<script src="<?cs var:toroot ?>assets/js/android_3p-bundle.js" type="text/javascript"></script><?cs
    +-  if:page.customHeadTag ?>
    +-<?cs var:page.customHeadTag ?><?cs
    +-  /if ?>
    +-<script type="text/javascript">
    +-  var toRoot = "<?cs var:toroot ?>";
    +-  var metaTags = [<?cs var:meta.tags ?>];
    +-  var devsite = <?cs if:devsite ?>true<?cs else ?>false<?cs /if ?>;
    +-  var useUpdatedTemplates = <?cs if:useUpdatedTemplates ?>true<?cs else ?>false<?cs /if ?>;
    +-</script>
    +-<script src="<?cs var:toroot ?>assets/js/docs.js?v=17" type="text/javascript"></script>
    +-
    +-<script>
    +-  (function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
    +-  (i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
    +-  m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
    +-  })(window,document,'script','//www.google-analytics.com/analytics.js','ga');
    +-
    +-  ga('create', 'UA-5831155-1', 'android.com');
    +-  ga('create', 'UA-49880327-2', 'android.com', {'name': 'universal'});  // New tracker);
    +-  ga('send', 'pageview');
    +-  ga('universal.send', 'pageview'); // Send page view for new tracker.
    +-</script><?cs /if ?><?cs
    +-# END if/else !devsite ?>
    +-</head>
    +diff --git a/tools/droiddoc/templates-sdk-dev/header.cs b/tools/droiddoc/templates-sdk-dev/header.cs
    +deleted file mode 100644
    +index a927393..0000000
    +--- a/tools/droiddoc/templates-sdk-dev/header.cs
    ++++ /dev/null
    +@@ -1,11 +0,0 @@
    +-<?cs if:!devsite ?><?cs # leave out the global header for devsite; it is in devsite template ?>
    +-  <?cs call:custom_masthead() ?>
    +-
    +-  <?cs if:(fullpage) ?>
    +-    <?cs call:fullpage() ?>
    +-  <?cs else ?>
    +-    <?cs call:body_content_wrap_start() ?>
    +-  <?cs /if ?>
    +-
    +-  <?cs call:search_results() ?>
    +-<?cs /if ?><?cs # end if/else !devsite ?>
    +\ No newline at end of file
    +diff --git a/tools/droiddoc/templates-sdk-dev/header_tabs.cs b/tools/droiddoc/templates-sdk-dev/header_tabs.cs
    +deleted file mode 100644
    +index 38c9da8..0000000
    +--- a/tools/droiddoc/templates-sdk-dev/header_tabs.cs
    ++++ /dev/null
    +@@ -1,2 +0,0 @@
    +-
    +-<!-- CURRENTLY NOT USED... ALL TABS ARE IN masthead.cs -->
    +diff --git a/tools/droiddoc/templates-sdk-dev/jd_lists_unified.cs b/tools/droiddoc/templates-sdk-dev/jd_lists_unified.cs
    +deleted file mode 100644
    +index 4a6f4f7..0000000
    +--- a/tools/droiddoc/templates-sdk-dev/jd_lists_unified.cs
    ++++ /dev/null
    +@@ -1,10 +0,0 @@
    +-window.METADATA = window.METADATA || {};
    +-METADATA['<?cs var:metadata.lang ?>'] = {};
    +-
    +-METADATA['<?cs var:metadata.lang ?>'].about = [];
    +-METADATA['<?cs var:metadata.lang ?>'].design = [];
    +-METADATA['<?cs var:metadata.lang ?>'].develop = [];
    +-METADATA['<?cs var:metadata.lang ?>'].distribute = [];
    +-METADATA['<?cs var:metadata.lang ?>'].extras = [];
    +-
    +-<?cs var:reference_tree ?>
    +diff --git a/tools/droiddoc/templates-sdk-dev/lists.cs b/tools/droiddoc/templates-sdk-dev/lists.cs
    +deleted file mode 100644
    +index ede8c43..0000000
    +--- a/tools/droiddoc/templates-sdk-dev/lists.cs
    ++++ /dev/null
    +@@ -1,8 +0,0 @@
    +-var <?cs
    +-  if:reference.testSupport ?>SUPPORT_TEST_<?cs
    +-  elif: reference.wearableSupport ?>SUPPORT_WEARABLE_<?cs 
    +-  /if ?>DATA = [
    +-<?cs each:page = docs.pages
    +-?>      { id:<?cs var: page.id ?>, label:"<?cs var:page.label ?>", link:"<?cs var:page.link ?>", type:"<?cs var:page.type ?>", deprecated:"<?cs var:page.deprecated ?>" }<?cs if:!last(page) ?>,<?cs /if ?>
    +-<?cs /each ?>
    +-    ];
    +diff --git a/tools/droiddoc/templates-sdk-dev/macros_override.cs b/tools/droiddoc/templates-sdk-dev/macros_override.cs
    +deleted file mode 100644
    +index 5b92fe3..0000000
    +--- a/tools/droiddoc/templates-sdk-dev/macros_override.cs
    ++++ /dev/null
    +@@ -1,51 +0,0 @@
    +-<?cs # Create a comma separated list of annotations on obj that were in showAnnotations in Doclava ?>
    +-<?cs # pre is an HTML string to start the list, post is an HTML string to close the list ?>
    +-<?cs # for example call:show_annotations_list(cl, "<td>Annotations: ", "</td>") ?>
    +-<?cs # if obj has nothing on obj.showAnnotations, nothing will be output ?>
    +-<?cs def:show_annotations_list(obj) ?>
    +-    <?cs each:anno = obj.showAnnotations ?>
    +-      <?cs if:first(anno) ?>
    +-        <span class='annotation-message'>
    +-          Included in documentation by the annotations:
    +-      <?cs /if ?>
    +-      @<?cs var:anno.type.label ?>
    +-      <?cs if:last(anno) == 0 ?>
    +-        , &nbsp;
    +-      <?cs /if ?>
    +-      <?cs if:last(anno)?>
    +-        </span>
    +-      <?cs /if ?>
    +-    <?cs /each ?>
    +-<?cs /def ?>
    +-
    +-<?cs # Override default class_link_table to display annotations ?>
    +-<?cs def:class_link_table(classes) ?>
    +-  <?cs set:count = #1 ?>
    +-  <table class="jd-sumtable-expando">
    +-    <?cs each:cl=classes ?>
    +-      <tr class="<?cs if:count % #2 ?>alt-color<?cs /if ?> api apilevel-<?cs var:cl.type.since ?>" >
    +-        <td class="jd-linkcol"><?cs call:type_link(cl.type) ?></td>
    +-        <td class="jd-descrcol" width="100%">
    +-          <?cs call:short_descr(cl) ?>&nbsp;
    +-          <?cs call:show_annotations_list(cl) ?>
    +-        </td>
    +-      </tr>
    +-      <?cs set:count = count + #1 ?>
    +-    <?cs /each ?>
    +-  </table>
    +-<?cs /def ?>
    +-
    +-<?cs
    +-# Prints a comma separated list of parameters with optional line breaks
    +-?><?cs
    +-def:parameter_list(params, linebreaks) ?><?cs
    +-  each:param = params ?><?cs
    +-      call:simple_type_link(param.type)?> <?cs
    +-      var:param.name ?><?cs
    +-      if: name(param)!=subcount(params)-1
    +-        ?>, <?cs if:linebreaks
    +-?>
    +-                <?cs /if ?><?cs
    +-      /if ?><?cs
    +-  /each ?><?cs
    +-/def ?>
    +\ No newline at end of file
    +diff --git a/tools/droiddoc/templates-sdk-dev/navtree_data.cs b/tools/droiddoc/templates-sdk-dev/navtree_data.cs
    +deleted file mode 100644
    +index 73aa199..0000000
    +--- a/tools/droiddoc/templates-sdk-dev/navtree_data.cs
    ++++ /dev/null
    +@@ -1,3 +0,0 @@
    +-var NAVTREE_DATA =
    +-<?cs var:reference_tree ?>
    +-;
    +diff --git a/tools/droiddoc/templates-sdk-dev/nosidenavpage.cs b/tools/droiddoc/templates-sdk-dev/nosidenavpage.cs
    +deleted file mode 100644
    +index 61754f0..0000000
    +--- a/tools/droiddoc/templates-sdk-dev/nosidenavpage.cs
    ++++ /dev/null
    +@@ -1,28 +0,0 @@
    +-<?cs include:"doctype.cs" ?>
    +-<?cs include:"macros.cs" ?>
    +-<html<?cs if:devsite ?> devsite<?cs /if ?>>
    +-<?cs include:"head_tag.cs" ?>
    +-<body class="gc-documentation 
    +-  <?cs if:(guide||develop||training||reference||tools||sdk) ?>develop<?cs
    +-  elif:design ?>design<?cs
    +-  elif:distribute ?>distribute<?cs
    +-  /if ?>" itemscope itemtype="http://schema.org/Article">
    +-<a name="top"></a>
    +-<?cs call:custom_masthead() ?>
    +-
    +-<div id="body-content">
    +-<div>
    +-<div id="doc-content" style="position:relative;">
    +-
    +-<?cs call:tag_list(root.descr) ?>
    +-
    +-<?cs include:"footer.cs" ?>
    +-</div><!-- end doc-content -->
    +-
    +-<?cs include:"trailer.cs" ?>
    +-
    +-</body>
    +-</html>
    +-
    +-
    +-
    +diff --git a/tools/droiddoc/templates-sdk-dev/package.cs b/tools/droiddoc/templates-sdk-dev/package.cs
    +deleted file mode 100644
    +index d3efdda..0000000
    +--- a/tools/droiddoc/templates-sdk-dev/package.cs
    ++++ /dev/null
    +@@ -1,64 +0,0 @@
    +-<?cs # THIS CREATES A PACKAGE SUMMARY PAGE FROM EACH package.html FILES
    +-     # AND NAMES IT package-summary.html ?>
    +-<?cs include:"macros.cs" ?>
    +-<?cs include:"macros_override.cs" ?>
    +-<?cs include:"doctype.cs" ?>
    +-<html<?cs if:devsite ?> devsite<?cs /if ?>>
    +-<?cs include:"head_tag.cs" ?>
    +-<?cs include:"body_tag.cs" ?>
    +-<?cs include:"header.cs" ?>
    +-<?cs include:"page_info.cs" ?>
    +-<div class="api apilevel-<?cs var:package.since ?>" id="jd-content">
    +-
    +-<h1><?cs var:package.name ?></h1>
    +-
    +-<?cs if:subcount(package.descr) ?>
    +-  <?cs call:tag_list(package.descr) ?>
    +-<?cs /if ?>
    +-
    +-<?cs def:class_table(label, classes) ?>
    +-  <?cs if:subcount(classes) ?>
    +-    <h2><?cs var:label ?></h2>
    +-    <?cs call:class_link_table(classes) ?>
    +-  <?cs /if ?>
    +-<?cs /def ?>
    +-
    +-<?cs call:class_table("Annotations", package.annotations) ?>
    +-<?cs call:class_table("Interfaces", package.interfaces) ?>
    +-<?cs call:class_table("Classes", package.classes) ?>
    +-<?cs call:class_table("Enums", package.enums) ?>
    +-<?cs call:class_table("Exceptions", package.exceptions) ?>
    +-<?cs call:class_table("Errors", package.errors) ?>
    +-
    +-</div><!-- end apilevel -->
    +-
    +-<?cs if:devsite ?>
    +-<div class="data-reference-resources-wrapper">
    +-  <?cs if:subcount(class.package) ?>
    +-  <ul data-reference-resources>
    +-    <?cs call:list("Annotations", class.package.annotations) ?>
    +-    <?cs call:list("Interfaces", class.package.interfaces) ?>
    +-    <?cs call:list("Classes", class.package.classes) ?>
    +-    <?cs call:list("Enums", class.package.enums) ?>
    +-    <?cs call:list("Exceptions", class.package.exceptions) ?>
    +-    <?cs call:list("Errors", class.package.errors) ?>
    +-  </ul>
    +-  <?cs elif:subcount(package) ?>
    +-  <ul data-reference-resources>
    +-    <?cs call:class_link_list("Annotations", package.annotations) ?>
    +-    <?cs call:class_link_list("Interfaces", package.interfaces) ?>
    +-    <?cs call:class_link_list("Classes", package.classes) ?>
    +-    <?cs call:class_link_list("Enums", package.enums) ?>
    +-    <?cs call:class_link_list("Exceptions", package.exceptions) ?>
    +-    <?cs call:class_link_list("Errors", package.errors) ?>
    +-  </ul>
    +-  <?cs /if ?>
    +-</div>
    +-<?cs /if ?>
    +-
    +-<?cs if:!devsite ?>
    +-<?cs include:"footer.cs" ?>
    +-<?cs include:"trailer.cs" ?>
    +-<?cs /if ?>
    +-</body>
    +-</html>
    +diff --git a/tools/droiddoc/templates-sdk-dev/packages.cs b/tools/droiddoc/templates-sdk-dev/packages.cs
    +deleted file mode 100644
    +index 3fcfb81..0000000
    +--- a/tools/droiddoc/templates-sdk-dev/packages.cs
    ++++ /dev/null
    +@@ -1,53 +0,0 @@
    +-<?cs # THIS CREATES A LIST OF ALL PACKAGES AND NAMES IT packages.html ?>
    +-<?cs include:"macros.cs" ?>
    +-<?cs include:"doctype.cs" ?>
    +-<html<?cs if:devsite ?> devsite<?cs /if ?>>
    +-<?cs include:"head_tag.cs" ?>
    +-<?cs include:"body_tag.cs" ?>
    +-<?cs include:"header.cs" ?>
    +-
    +-<h1><?cs var:page.title ?></h1>
    +-<p>These are the API packages.
    +-See all <a href="classes.html">API classes</a>.</p>
    +-
    +-<?cs set:count = #1 ?>
    +-<table>
    +-<?cs each:pkg = docs.packages ?>
    +-    <tr class="api apilevel-<?cs var:pkg.since ?>" >
    +-        <td class="jd-linkcol"><?cs call:package_link(pkg) ?></td>
    +-        <td class="jd-descrcol" width="100%"><?cs call:tag_list(pkg.shortDescr) ?></td>
    +-    </tr>
    +-<?cs set:count = count + #1 ?>
    +-<?cs /each ?>
    +-</table>
    +-
    +-<?cs if:devsite ?>
    +-<div class="data-reference-resources-wrapper">
    +-  <?cs if:subcount(class.package) ?>
    +-  <ul data-reference-resources>
    +-    <?cs call:list("Annotations", class.package.annotations) ?>
    +-    <?cs call:list("Interfaces", class.package.interfaces) ?>
    +-    <?cs call:list("Classes", class.package.classes) ?>
    +-    <?cs call:list("Enums", class.package.enums) ?>
    +-    <?cs call:list("Exceptions", class.package.exceptions) ?>
    +-    <?cs call:list("Errors", class.package.errors) ?>
    +-  </ul>
    +-  <?cs elif:subcount(package) ?>
    +-  <ul data-reference-resources>
    +-    <?cs call:class_link_list("Annotations", package.annotations) ?>
    +-    <?cs call:class_link_list("Interfaces", package.interfaces) ?>
    +-    <?cs call:class_link_list("Classes", package.classes) ?>
    +-    <?cs call:class_link_list("Enums", package.enums) ?>
    +-    <?cs call:class_link_list("Exceptions", package.exceptions) ?>
    +-    <?cs call:class_link_list("Errors", package.errors) ?>
    +-  </ul>
    +-  <?cs /if ?>
    +-</div>
    +-<?cs /if ?>
    +-
    +-<?cs if:!devsite ?>
    +-<?cs include:"footer.cs" ?>
    +-<?cs include:"trailer.cs" ?>
    +-<?cs /if ?>
    +-</body>
    +-</html>
    +diff --git a/tools/droiddoc/templates-sdk-dev/page_info.cs b/tools/droiddoc/templates-sdk-dev/page_info.cs
    +deleted file mode 100644
    +index fad1274..0000000
    +--- a/tools/droiddoc/templates-sdk-dev/page_info.cs
    ++++ /dev/null
    +@@ -1,109 +0,0 @@
    +-<?cs # optional, more info about the page, such as API level and links ?>
    +-<?cs
    +-# A modal dialog when API level is set too low for this page
    +-?><div id="naMessage"></div>
    +-<?cs
    +-#
    +-# If this is a package summary page...
    +-#
    +-?><?cs
    +-if:subcount(package)
    +-?>
    +-<div id="api-info-block">
    +-<div class="api-level">
    +-  <?cs call:since_tags(package) ?>
    +-  <?cs call:federated_refs(package) ?>
    +-</div>
    +-</div><?cs
    +-#
    +-# Or if this is a class page...
    +-#
    +-?><?cs
    +-elif:subcount(class)
    +-?>
    +-<div id="api-info-block">
    +-<div class="api-level">
    +-  <?cs call:since_tags(class) ?><?cs
    +-  if:class.deprecatedsince
    +-    ?><br>Deprecated since <a href="<?cs var:toroot ?>guide/topics/manifest/uses-sdk-element.html#ApiLevels"
    +-        >API level <?cs var:class.deprecatedsince ?></a><?cs
    +-  /if ?>
    +-  <?cs call:federated_refs(class) ?>
    +-</div>
    +-
    +-<?cs # Set variables about whether there are inherited members; no output ?>
    +-<?cs each:cl=class.inherited ?>
    +-  <?cs if:subcount(cl.methods) ?>
    +-   <?cs set:inhmethods = #1 ?>
    +-  <?cs /if ?>
    +-  <?cs if:subcount(cl.constants) ?>
    +-   <?cs set:inhconstants = #1 ?>
    +-  <?cs /if ?>
    +-  <?cs if:subcount(cl.fields) ?>
    +-   <?cs set:inhfields = #1 ?>
    +-  <?cs /if ?>
    +-  <?cs if:subcount(cl.attrs) ?>
    +-   <?cs set:inhattrs = #1 ?>
    +-  <?cs /if ?>
    +-<?cs /each ?>
    +-
    +-<div class="sum-details-links">
    +-<?cs if:inhattrs || inhconstants || inhfields || inhmethods || (!class.subclasses.hidden &&
    +-     (subcount(class.subclasses.direct) || subcount(class.subclasses.indirect))) ?>
    +-Summary:
    +-<?cs if:subcount(class.inners) ?>
    +-  <a href="#nestedclasses">Nested Classes</a>
    +-  <?cs set:linkcount = #1 ?>
    +-<?cs /if ?>
    +-<?cs if:subcount(class.attrs) ?>
    +-  <?cs if:linkcount ?>&#124; <?cs /if ?><a href="#lattrs">XML Attrs</a>
    +-  <?cs set:linkcount = #1 ?>
    +-<?cs /if ?>
    +-<?cs if:inhattrs ?>
    +-  <?cs if:linkcount ?>&#124; <?cs /if ?><a href="#inhattrs">Inherited XML Attrs</a>
    +-  <?cs set:linkcount = #1 ?>
    +-<?cs /if ?>
    +-<?cs if:subcount(class.enumConstants) ?>
    +-  <?cs if:linkcount ?>&#124; <?cs /if ?><a href="#enumconstants">Enums</a>
    +-  <?cs set:linkcount = #1 ?>
    +-<?cs /if ?>
    +-<?cs if:subcount(class.constants) ?>
    +-  <?cs if:linkcount ?>&#124; <?cs /if ?><a href="#constants">Constants</a>
    +-  <?cs set:linkcount = #1 ?>
    +-<?cs /if ?>
    +-<?cs if:inhconstants ?>
    +-  <?cs if:linkcount ?>&#124; <?cs /if ?><a href="#inhconstants">Inherited Constants</a>
    +-  <?cs set:linkcount = #1 ?>
    +-<?cs /if ?>
    +-<?cs if:subcount(class.fields) ?>
    +-  <?cs if:linkcount ?>&#124; <?cs /if ?><a href="#lfields">Fields</a>
    +-  <?cs set:linkcount = #1 ?>
    +-<?cs /if ?>
    +-<?cs if:inhfields ?>
    +-  <?cs if:linkcount ?>&#124; <?cs /if ?><a href="#inhfields">Inherited Fields</a>
    +-  <?cs set:linkcount = #1 ?>
    +-<?cs /if ?>
    +-<?cs if:subcount(class.ctors.public) ?>
    +-  <?cs if:linkcount ?>&#124; <?cs /if ?><a href="#pubctors">Ctors</a>
    +-  <?cs set:linkcount = #1 ?>
    +-<?cs /if ?>
    +-<?cs if:subcount(class.ctors.protected) ?>
    +-  <?cs if:linkcount ?>&#124; <?cs /if ?><a href="#proctors">Protected Ctors</a>
    +-  <?cs set:linkcount = #1 ?>
    +-<?cs /if ?>
    +-<?cs if:subcount(class.methods.public) ?>
    +-  <?cs if:linkcount ?>&#124; <?cs /if ?><a href="#pubmethods">Methods</a>
    +-  <?cs set:linkcount = #1 ?>
    +-<?cs /if ?>
    +-<?cs if:subcount(class.methods.protected) ?>
    +-  <?cs if:linkcount ?>&#124; <?cs /if ?><a href="#promethods">Protected Methods</a>
    +-  <?cs set:linkcount = #1 ?>
    +-<?cs /if ?>
    +-<?cs if:inhmethods ?>
    +-  <?cs if:linkcount ?>&#124; <?cs /if ?><a href="#inhmethods">Inherited Methods</a>
    +-<?cs /if ?>
    +-&#124; <a href="#" onclick="return toggleAllClassInherited()" id="toggleAllClassInherited">[Expand All]</a>
    +-<?cs /if ?>
    +-</div><!-- end sum-details-links -->
    +-</div><!-- end api-info-block --><?cs
    +-/if ?><?cs # end of if package or class ?>
    +\ No newline at end of file
    +diff --git a/tools/droiddoc/templates-sdk-dev/sample.cs b/tools/droiddoc/templates-sdk-dev/sample.cs
    +deleted file mode 100644
    +index 2c5b9d2..0000000
    +--- a/tools/droiddoc/templates-sdk-dev/sample.cs
    ++++ /dev/null
    +@@ -1,139 +0,0 @@
    +-<?cs include:"doctype.cs" ?>
    +-<?cs include:"macros.cs" ?>
    +-<html<?cs if:devsite ?> devsite<?cs /if ?>>
    +-<?cs include:"head_tag.cs" ?>
    +-<body class="gc-documentation develop samples" itemscope itemtype="http://schema.org/Article">
    +-<?cs include:"header.cs" ?>
    +-
    +-<!-- start breadcrumb block -->
    +-<div id="api-info-block">
    +-  <div class="sum-details-links">
    +-
    +-  <!-- related links -->
    +-  <a href="<?cs var:toroot ?>samples/<?cs var:projectDir ?>/index.html">Overview</a>
    +-  &#124; <a href="<?cs var:toroot ?>samples/<?cs var:projectDir ?>/project.html">Project</a>
    +-  &#124; <a href="<?cs var:toroot ?>downloads/samples/<?cs var:projectDir ?>.zip"
    +-    onclick="ga('send', 'event', 'Samples', 'Download', <?cs var:projectDir ?>);"
    +-    >Download</a>
    +-
    +-</div><!-- end sum-details-links -->
    +-
    +-</div><!-- end breadcurmb block -->
    +-
    +-<div id="jd-header" style="border:0;">
    +-
    +-<div id="pathCrumb">
    +-<?cs each:item = parentdirs ?>
    +-  <?cs if:LinkifyPathCrumb
    +-    ?><a href="<?cs var:toroot ?><?cs var:item.Link ?>"><?cs var:item.Name ?></a> /
    +-  <?cs else
    +-    ?><?cs var:item.Name ?> / <?cs /if ?>
    +-<?cs /each ?>
    +-</div>
    +-
    +-  <h1 itemprop="name"><?cs var:page.title ?></h1>
    +-</div>
    +-<!-- end breadcrumb block -->
    +-
    +-
    +-<?cs # THIS IS THE MAIN DOC CONTENT ?>
    +-<div id="jd-content">
    +-
    +-<?cs if:android.whichdoc == "online" ?>
    +-
    +-<?cs # If this is the online docs, build the src code navigation links ?>
    +-
    +-
    +-<?cs var:summary ?>
    +-
    +-<!-- begin file contents -->
    +-
    +-<?cs # embed image/videos if below maxsize (show message otherwise), else display source code ?>
    +-<?cs if:resType == "img" ?>
    +-  <div id="codesample-resource"
    +-    <?cs if:noDisplay ?>
    +-      class="noDisplay"><div class="noDisplay-message"></div>
    +-    <?cs else ?>
    +-      ><img src="<?cs var:realFile ?>" title="<?cs var:page.title ?>">
    +-    <?cs /if ?>
    +-  </div>
    +-<?cs elif:resType == "video" ?>
    +-  <div id="codesample-resource"
    +-    <?cs if:noDisplay ?>
    +-      class="noDisplay"><div class="noDisplay-message"></div>
    +-    <?cs else ?>
    +-      ><video class="play-on-hover" controls style="border:1px solid #ececec;background-color:#f9f9f9;" poster="">
    +-        <source src="<?cs var:page.title ?>">
    +-      </video>
    +-    <?cs /if ?>
    +-  </div>
    +-<?cs else ?>
    +-  <div id="codesample-wrapper">
    +-    <pre id="codesample-line-numbers" class="no-pretty-print hidden"></pre>
    +-    <pre id="codesample-block"><?cs var:fileContents ?></pre>
    +-  </div>
    +-  <script type="text/javascript">
    +-  initCodeLineNumbers();
    +-  </script>
    +-<?cs /if ?>
    +-
    +-<!-- end file contents -->
    +-
    +-<?cs else ?><?cs
    +-  # else, this means it's offline docs,
    +-          so don't show src links (we dont have the pages!) ?>
    +-
    +-<?cs /if ?><?cs # end if/else online docs ?>
    +-
    +-      <div class="content-footer <?cs
    +-                    if:fullpage ?>wrap<?cs
    +-                    else ?>cols<?cs /if ?>"
    +-                    itemscope itemtype="http://schema.org/SiteNavigationElement">
    +-        <div class="<?cs
    +-                    if:fullpage ?>col-16<?cs
    +-                    elif:training||guide ?>col-8<?cs
    +-                    else ?>col-9<?cs /if ?>" style="padding-top:4px">
    +-          <?cs if:!page.noplus ?><?cs if:fullpage ?><style>#___plusone_0 {float:right !important;}</style><?cs /if ?>
    +-            <div class="g-plusone" data-size="medium"></div>
    +-          <?cs /if ?>
    +-        </div>
    +-        <?cs if:!fullscreen ?>
    +-        <div class="paging-links col-4">
    +-          <?cs if:(design||training||walkthru) && !page.landing && !page.trainingcourse && !footer.hide ?>
    +-            <a href="#" class="prev-page-link hide"
    +-                zh-tw-lang="上一堂課"
    +-                zh-cn-lang="上一课"
    +-                ru-lang="Предыдущий"
    +-                ko-lang="이전"
    +-                ja-lang="前へ"
    +-                es-lang="Anterior"
    +-                >Previous</a>
    +-            <a href="#" class="next-page-link hide"
    +-                zh-tw-lang="下一堂課"
    +-                zh-cn-lang="下一课"
    +-                ru-lang="Следующий"
    +-                ko-lang="다음"
    +-                ja-lang="次へ"
    +-                es-lang="Siguiente"
    +-                >Next</a>
    +-          <?cs /if ?>
    +-        </div>
    +-        <?cs /if ?>
    +-      </div>
    +-
    +-      <?cs # for training classes, provide a different kind of link when the next page is a different class ?>
    +-      <?cs if:training && !page.article ?>
    +-      <div class="content-footer next-class" style="display:none" itemscope itemtype="http://schema.org/SiteNavigationElement">
    +-          <a href="#" class="next-class-link hide">Next class: </a>
    +-      </div>
    +-      <?cs /if ?>
    +-
    +-  </div> <!-- end jd-content -->
    +-
    +-  <?cs if:!devsite ?>
    +-  <?cs include:"footer.cs" ?>
    +-  <?cs include:"trailer.cs" ?>
    +-  <?cs /if ?>
    +-
    +-</body>
    +-</html>
    +diff --git a/tools/droiddoc/templates-sdk-dev/sampleindex.cs b/tools/droiddoc/templates-sdk-dev/sampleindex.cs
    +deleted file mode 100644
    +index db648ff..0000000
    +--- a/tools/droiddoc/templates-sdk-dev/sampleindex.cs
    ++++ /dev/null
    +@@ -1,130 +0,0 @@
    +-<?cs include:"doctype.cs" ?>
    +-<?cs include:"macros.cs" ?>
    +-<html<?cs if:devsite ?> devsite<?cs /if ?>>
    +-<?cs include:"head_tag.cs" ?>
    +-<body class="gc-documentation develop samples" itemscope itemtype="http://schema.org/Article">
    +-<?cs include:"header.cs" ?>
    +-
    +-<!-- start breadcrumb block -->
    +-<div id="api-info-block">
    +-<div class="sum-details-links">
    +-
    +-<!-- related links -->
    +-<?cs if:projectStructure ?>
    +-<a href="<?cs var:toroot ?>samples/<?cs var:projectDir ?>/index.html">Overview</a>
    +-&#124; Project<?cs else ?>Overview
    +-&#124; <a href="<?cs var:toroot ?>samples/<?cs var:projectDir ?>/project.html">Project</a>
    +-<?cs /if ?>
    +-&#124; <a href="<?cs var:toroot ?>downloads/samples/<?cs var:projectDir ?>.zip"
    +-    onclick="ga('send', 'event', 'Samples', 'Download', <?cs var:projectDir ?>);"
    +-    >Download</a>
    +-
    +-</div><!-- end sum-details-links -->
    +-
    +-</div><!-- end breadcurmb block -->
    +-
    +-<h1 itemprop="name"><?cs var:projectDir ?></h1>
    +-  
    +-<div id="jd-content">
    +-<?cs def:display_files(files) ?>
    +-
    +-    <?cs each:file = files ?>
    +-        <?cs if:file.Type != "dir" ?>
    +-            <div class="structure-<?cs var:file.Type ?>">
    +-            <a href="<?cs var:toroot ?><?cs var:file.Href ?>"><?cs var:file.Name ?></a>
    +-            </div>
    +-        <?cs else ?>
    +-            <div class="toggle-content opened structure-dir">
    +-               <a href="#" onclick="return toggleContent(this)">
    +-               <img src="<?cs var:toroot ?>assets/images/triangle-opened.png"
    +-                  class="toggle-content-img structure-toggle-img" height="9px" width="9px" />
    +-               <?cs var:file.Name ?></a><?cs 
    +-                  if:file.SummaryFlag == "true" ?><span class="dirInfo"
    +-                    >[&nbsp;<a href="file.SummaryHref">Info</a>&nbsp;]</a></span><?cs 
    +-                  /if ?>
    +-               <div class="toggle-content-toggleme structure-toggleme"> 
    +-            <?cs if:file.Sub.0.Name ?>
    +-                 <?cs call:display_files(file.Sub) ?>
    +-            <?cs /if ?>
    +-               </div> <?cs # /toggleme ?>
    +-            </div> <?cs # /toggle-content ?>
    +-         <?cs /if ?>
    +-    <?cs /each ?>
    +-<?cs /def ?>
    +-
    +-<?cs if:android.whichdoc == "online" ?>
    +-  <?cs # If this is the online docs, build the src code navigation links ?>
    +-
    +-  <?cs if:projectStructure ?>
    +-
    +-    <?cs call:display_files(Files) ?>
    +-
    +-  <?cs else ?> <?cs # else not project structure doc ?>
    +-
    +-    <?cs var:summary ?>
    +-
    +-    <?cs # Remove project structure from landing pages for now
    +-         # <h2>Project Structure</h2>
    +-         # <p>Decide what to do with this ...</p>
    +-         # <?cs call:display_files(Files) ?>
    +-
    +-  <?cs /if ?> <?cs # end if projectStructure ?>
    +-
    +-<?cs else ?><?cs
    +-  # else, this means it's offline docs,
    +-          so don't show src links (we dont have the pages!) ?>
    +-
    +-<?cs /if ?><?cs # end if/else online docs ?>
    +-      <div class="content-footer <?cs
    +-                    if:fullpage ?>wrap<?cs
    +-                    else ?>cols<?cs /if ?>"
    +-                    itemscope itemtype="http://schema.org/SiteNavigationElement">
    +-        <div class="<?cs
    +-                    if:fullpage ?>col-16<?cs
    +-                    elif:training||guide ?>col-8<?cs
    +-                    else ?>col-9<?cs /if ?>" style="padding-top:4px">
    +-          <?cs if:!page.noplus ?><?cs if:fullpage ?><style>#___plusone_0 {float:right !important;}</style><?cs /if ?>
    +-            <div class="g-plusone" data-size="medium"></div>
    +-          <?cs /if ?>
    +-        </div>
    +-        <?cs if:!fullscreen ?>
    +-        <div class="paging-links col-4">
    +-          <?cs if:(design||training||walkthru) && !page.landing && !page.trainingcourse && !footer.hide ?>
    +-            <a href="#" class="prev-page-link hide"
    +-                zh-tw-lang="上一堂課"
    +-                zh-cn-lang="上一课"
    +-                ru-lang="Предыдущий"
    +-                ko-lang="이전"
    +-                ja-lang="前へ"
    +-                es-lang="Anterior"
    +-                >Previous</a>
    +-            <a href="#" class="next-page-link hide"
    +-                zh-tw-lang="下一堂課"
    +-                zh-cn-lang="下一课"
    +-                ru-lang="Следующий"
    +-                ko-lang="다음"
    +-                ja-lang="次へ"
    +-                es-lang="Siguiente"
    +-                >Next</a>
    +-          <?cs /if ?>
    +-        </div>
    +-        <?cs /if ?>
    +-      </div>
    +-
    +-      <?cs # for training classes, provide a different kind of link when the next page is a different class ?>
    +-      <?cs if:training && !page.article ?>
    +-      <div class="content-footer next-class" style="display:none" itemscope itemtype="http://schema.org/SiteNavigationElement">
    +-          <a href="#" class="next-class-link hide">Next class: </a>
    +-      </div>
    +-      <?cs /if ?>
    +-
    +-  </div> <!-- end jd-content -->
    +-
    +-<?cs include:"footer.cs" ?>
    +-
    +-<?cs include:"trailer.cs" ?>
    +-
    +-</body>
    +-</html>
    +-
    +-
    +diff --git a/tools/droiddoc/templates-sdk-dev/samples_navtree_data.cs b/tools/droiddoc/templates-sdk-dev/samples_navtree_data.cs
    +deleted file mode 100644
    +index b9b4214..0000000
    +--- a/tools/droiddoc/templates-sdk-dev/samples_navtree_data.cs
    ++++ /dev/null
    +@@ -1,8 +0,0 @@
    +-toc:
    +-- title: About the Samples
    +-  path: /samples/index.html
    +-
    +-- title: What's New
    +-  path: /samples/new/index.html
    +-
    +-<?cs var:samples_toc_tree ?>
    +\ No newline at end of file
    +diff --git a/tools/droiddoc/templates-sdk-dev/timestamp.cs b/tools/droiddoc/templates-sdk-dev/timestamp.cs
    +deleted file mode 100644
    +index 4bf502a..0000000
    +--- a/tools/droiddoc/templates-sdk-dev/timestamp.cs
    ++++ /dev/null
    +@@ -1 +0,0 @@
    +-var BUILD_TIMESTAMP = "<?cs var:page.now ?>";
    +diff --git a/tools/droiddoc/templates-sdk-dev/trailer.cs b/tools/droiddoc/templates-sdk-dev/trailer.cs
    +deleted file mode 100644
    +index 2050475..0000000
    +--- a/tools/droiddoc/templates-sdk-dev/trailer.cs
    ++++ /dev/null
    +@@ -1,38 +0,0 @@
    +-<?cs
    +-# Other, non-visible things needed at the end of the page,
    +-# because not every page needs footer content, but does need other stuff
    +-?>
    +-</div> <!-- end body-content --> <?cs # normally opened by header.cs ?>
    +-
    +-<?cs if:carousel ?>
    +-<script type="text/javascript">
    +-$('.slideshow-container').dacSlideshow({
    +-    btnPrev: '.slideshow-prev',
    +-    btnNext: '.slideshow-next',
    +-    btnPause: '#pauseButton'
    +-});
    +-</script>
    +-<?cs /if ?>
    +-<?cs if:tabbedList ?>
    +-<script type="text/javascript">
    +-$(".feed").dacTabbedList({
    +-    nav_id: '.feed-nav',
    +-    frame_id: '.feed-frame'
    +-});
    +-</script>
    +-<?cs /if ?>
    +-
    +-<script src="https://developer.android.com/ytblogger_lists_unified.js" defer></script>
    +-<script src="/jd_lists_unified_en.js?v=17" defer></script>
    +-<script src="/reference/lists.js?v=17" defer></script>
    +-<script src="/reference/gcm_lists.js?v=17" defer></script>
    +-<script src="/reference/gms_lists.js?v=17" defer></script>
    +-<script>
    +-  // Load localized metadata.
    +-  (function(lang) {
    +-    if (lang === 'en') { return; }
    +-
    +-    // Write it to the document so it gets evaluated before DOMContentReady.
    +-    document.write('<script src="/jd_lists_unified_' + lang + '.js?v=14" defer></' + 'script>');
    +-  })(getLangPref())
    +-</script>
    +diff --git a/tools/droiddoc/templates-sdk-dev/yaml_navtree.cs b/tools/droiddoc/templates-sdk-dev/yaml_navtree.cs
    +deleted file mode 100644
    +index e5a6404..0000000
    +--- a/tools/droiddoc/templates-sdk-dev/yaml_navtree.cs
    ++++ /dev/null
    +@@ -1,14 +0,0 @@
    +-<?cs
    +-
    +-# print out the yaml nav for the reference docs, only printing the title,
    +-path, and status_text (API level) for each package.
    +-
    +-?>
    +-reference:<?cs
    +-each:page = docs.pages?><?cs
    +-  if:page.type == "package"?>
    +-- title: <?cs var:page.label ?>
    +-  path: /<?cs var:page.link ?>
    +-  status_text: apilevel-<?cs var:page.apilevel ?><?cs
    +-  /if?><?cs
    +-/each ?>
    +diff --git a/tools/droiddoc/templates-sdk/assets/css/default.css b/tools/droiddoc/templates-sdk/assets/css/default.css
    +index e422d75..9e5df48 100644
    +--- a/tools/droiddoc/templates-sdk/assets/css/default.css
    ++++ b/tools/droiddoc/templates-sdk/assets/css/default.css
    +@@ -3322,20 +3322,18 @@ table.jd-tagtable th {
    +   display: none;
    + }
    + 
    +-/* offset the <a name=""> tags to account for sticky nav */
    +-body.reference a[name]:not(.nav-start-marker) {
    ++/* offset the empty <a name=""> tags to account for sticky nav */
    ++body.reference a[name]:not(.nav-start-marker):empty {
    +   visibility: hidden;
    +   display: block;
    +   position: relative;
    +   top: -56px;
    +-
    + }
    + 
    + .nav-start-marker {
    +   position: absolute;
    + }
    + 
    +-
    + /* Quicknav */
    + .btn-quicknav {
    +   width:20px;
    +diff --git a/tools/droiddoc/templates-sdk/assets/js/docs.js b/tools/droiddoc/templates-sdk/assets/js/docs.js
    +index 5ed947c..9709f50 100644
    +--- a/tools/droiddoc/templates-sdk/assets/js/docs.js
    ++++ b/tools/droiddoc/templates-sdk/assets/js/docs.js
    +@@ -3314,7 +3314,7 @@ window.changeLangPref = changeLangPref;
    +   var LANGUAGES = [
    +     'en',
    +     'es',
    +-    'in',
    ++    'id',
    +     'ja',
    +     'ko',
    +     'pt-br',
    +@@ -3351,7 +3351,7 @@ window.changeLangPref = changeLangPref;
    +       'languageValTarget': {
    +         'en': 'English',
    +         'ar': 'Arabic (العربيّة)',
    +-        'in': 'Indonesian (Bahasa)',
    ++        'id': 'Indonesian (Bahasa)',
    +         'fr': 'French (français)',
    +         'de': 'German (Deutsch)',
    +         'ja': 'Japanese (日本語)',
    +@@ -3609,7 +3609,7 @@ switch (window.getLangPref()) {
    +       }
    +     });
    +     break;
    +-  case 'in':
    ++  case 'id':
    +     window.polyglot.extend({
    +       'newsletter': {
    +         'title': 'Receba as dicas e as notícias mais recentes para os desenvolvedores Android e seja bem-sucedido ' +
    +diff --git a/tools/droiddoc/templates-sdk/footer.cs b/tools/droiddoc/templates-sdk/footer.cs
    +index af34a1a..452a811 100644
    +--- a/tools/droiddoc/templates-sdk/footer.cs
    ++++ b/tools/droiddoc/templates-sdk/footer.cs
    +@@ -45,7 +45,7 @@
    +         <select name="language" onchange="changeLangPref(this.value, true)">
    +           <option value="en" selected="selected">English</option>
    +           <option value="es">Español</option>
    +-          <option value="in">Bahasa Indonesia</option>
    ++          <option value="id">Bahasa Indonesia</option>
    +           <option value="ja">日本語</option>
    +           <option value="ko">한국어</option>
    +           <option value="pt-br">Português Brasileiro</option>
    +diff --git a/tools/droiddoc/templates-sdk/head_tag.cs b/tools/droiddoc/templates-sdk/head_tag.cs
    +index 0c5bb78..dd67aa5 100644
    +--- a/tools/droiddoc/templates-sdk/head_tag.cs
    ++++ b/tools/droiddoc/templates-sdk/head_tag.cs
    +@@ -126,8 +126,13 @@ if:devsite ?>
    +         elif:stories ?>/stories<?cs
    +         elif:analyze ?>/analyze<?cs
    +         else ?><?cs /if ?><?cs
    +-      elif:(about||versions||wear||tv||auto) ?>/about<?cs
    +-      elif:wearpreview ?>/wear<?cs
    ++      elif:(about||versions||wear||tv||auto) ?><?cs
    ++        if:versions ?>/about/versions<?cs
    ++        elif:wear ?>/wear<?cs
    ++        elif:tv ?>/tv<?cs
    ++        elif:auto ?>/auto<?cs
    ++        else ?>/about<?cs /if ?><?cs
    ++      elif:wearpreview ?>/wear/preview<?cs
    +       elif:work ?>/work<?cs
    +       elif:preview ?>/preview<?cs
    +       elif:design ?>/design<?cs /if ?>/_project.yaml" /><?cs
    +@@ -150,6 +155,9 @@ if:devsite ?>
    +       if:page.image ?>
    +   <meta name="image_path" value='<?cs var:page.image ?>' /><?cs
    +       /if ?><?cs
    ++      if:excludeFromSuggestions ?>
    ++  <meta name="hide_from_search_suggest" value="true" /><?cs
    ++      /if ?><?cs
    + /if ?><?cs # END if/else devsite ?><?cs
    + 
    +   if:!devsite ?>
    +diff --git a/tools/droiddoc/templates-sdk/jd_lists_unified.cs b/tools/droiddoc/templates-sdk/jd_lists_unified.cs
    +index 4a6f4f7..03141b0 100644
    +--- a/tools/droiddoc/templates-sdk/jd_lists_unified.cs
    ++++ b/tools/droiddoc/templates-sdk/jd_lists_unified.cs
    +@@ -1,4 +1,9 @@
    +-window.METADATA = window.METADATA || {};
    ++<?cs # generate metadata file for samples only ?><?cs
    ++if:samples_only ?>METADATA['<?cs var:metadata.lang ?>'].develop = METADATA['<?cs var:metadata.lang ?>'].develop.concat([
    ++<?cs var:reference_tree ?>
    ++]);
    ++<?cs # generate standard unified metadata file ?><?cs
    ++else ?>window.METADATA = window.METADATA || {};
    + METADATA['<?cs var:metadata.lang ?>'] = {};
    + 
    + METADATA['<?cs var:metadata.lang ?>'].about = [];
    +@@ -8,3 +13,4 @@ METADATA['<?cs var:metadata.lang ?>'].distribute = [];
    + METADATA['<?cs var:metadata.lang ?>'].extras = [];
    + 
    + <?cs var:reference_tree ?>
    ++<?cs /if ?>
    +\ No newline at end of file
    +diff --git a/tools/droiddoc/templates-sdk/lists.cs b/tools/droiddoc/templates-sdk/lists.cs
    +index ede8c43..f08abba 100644
    +--- a/tools/droiddoc/templates-sdk/lists.cs
    ++++ b/tools/droiddoc/templates-sdk/lists.cs
    +@@ -1,6 +1,7 @@
    + var <?cs
    +   if:reference.testSupport ?>SUPPORT_TEST_<?cs
    +-  elif: reference.wearableSupport ?>SUPPORT_WEARABLE_<?cs 
    ++  elif: reference.wearableSupport ?>SUPPORT_WEARABLE_<?cs
    ++  elif: reference.constraintSupport ?>CONSTRAINT_<?cs
    +   /if ?>DATA = [
    + <?cs each:page = docs.pages
    + ?>      { id:<?cs var: page.id ?>, label:"<?cs var:page.label ?>", link:"<?cs var:page.link ?>", type:"<?cs var:page.type ?>", deprecated:"<?cs var:page.deprecated ?>" }<?cs if:!last(page) ?>,<?cs /if ?>
    +diff --git a/tools/releasetools/blockimgdiff.py b/tools/releasetools/blockimgdiff.py
    +index 0d9aabd..31dabc7 100644
    +--- a/tools/releasetools/blockimgdiff.py
    ++++ b/tools/releasetools/blockimgdiff.py
    +@@ -696,10 +696,19 @@ class BlockImageDiff(object):
    +     with open(prefix + ".new.dat", "wb") as new_f:
    +       for xf in self.transfers:
    +         if xf.style == "zero":
    +-          pass
    ++          tgt_size = xf.tgt_ranges.size() * self.tgt.blocksize
    ++          print("%10d %10d (%6.2f%%) %7s %s %s" % (
    ++              tgt_size, tgt_size, 100.0, xf.style, xf.tgt_name,
    ++              str(xf.tgt_ranges)))
    ++
    +         elif xf.style == "new":
    +           for piece in self.tgt.ReadRangeSet(xf.tgt_ranges):
    +             new_f.write(piece)
    ++          tgt_size = xf.tgt_ranges.size() * self.tgt.blocksize
    ++          print("%10d %10d (%6.2f%%) %7s %s %s" % (
    ++              tgt_size, tgt_size, 100.0, xf.style,
    ++              xf.tgt_name, str(xf.tgt_ranges)))
    ++
    +         elif xf.style == "diff":
    +           src = self.src.ReadRangeSet(xf.src_ranges)
    +           tgt = self.tgt.ReadRangeSet(xf.tgt_ranges)
    +@@ -726,6 +735,12 @@ class BlockImageDiff(object):
    +             # These are identical; we don't need to generate a patch,
    +             # just issue copy commands on the device.
    +             xf.style = "move"
    ++            if xf.src_ranges != xf.tgt_ranges:
    ++              print("%10d %10d (%6.2f%%) %7s %s %s (from %s)" % (
    ++                  tgt_size, tgt_size, 100.0, xf.style,
    ++                  xf.tgt_name if xf.tgt_name == xf.src_name else (
    ++                      xf.tgt_name + " (from " + xf.src_name + ")"),
    ++                  str(xf.tgt_ranges), str(xf.src_ranges)))
    +           else:
    +             # For files in zip format (eg, APKs, JARs, etc.) we would
    +             # like to use imgdiff -z if possible (because it usually
    +@@ -773,10 +788,11 @@ class BlockImageDiff(object):
    +           size = len(patch)
    +           with lock:
    +             patches[patchnum] = (patch, xf)
    +-            print("%10d %10d (%6.2f%%) %7s %s" % (
    ++            print("%10d %10d (%6.2f%%) %7s %s %s %s" % (
    +                 size, tgt_size, size * 100.0 / tgt_size, xf.style,
    +                 xf.tgt_name if xf.tgt_name == xf.src_name else (
    +-                    xf.tgt_name + " (from " + xf.src_name + ")")))
    ++                    xf.tgt_name + " (from " + xf.src_name + ")"),
    ++                str(xf.tgt_ranges), str(xf.src_ranges)))
    + 
    +       threads = [threading.Thread(target=diff_worker)
    +                  for _ in range(self.threads)]
    +@@ -1102,27 +1118,23 @@ class BlockImageDiff(object):
    +   def FindTransfers(self):
    +     """Parse the file_map to generate all the transfers."""
    + 
    +-    def AddTransfer(tgt_name, src_name, tgt_ranges, src_ranges, style, by_id,
    +-                    split=False):
    +-      """Wrapper function for adding a Transfer().
    ++    def AddSplitTransfers(tgt_name, src_name, tgt_ranges, src_ranges,
    ++                          style, by_id):
    ++      """Add one or multiple Transfer()s by splitting large files.
    + 
    +       For BBOTA v3, we need to stash source blocks for resumable feature.
    +       However, with the growth of file size and the shrink of the cache
    +       partition source blocks are too large to be stashed. If a file occupies
    +-      too many blocks (greater than MAX_BLOCKS_PER_DIFF_TRANSFER), we split it
    +-      into smaller pieces by getting multiple Transfer()s.
    ++      too many blocks, we split it into smaller pieces by getting multiple
    ++      Transfer()s.
    + 
    +       The downside is that after splitting, we may increase the package size
    +       since the split pieces don't align well. According to our experiments,
    +       1/8 of the cache size as the per-piece limit appears to be optimal.
    +       Compared to the fixed 1024-block limit, it reduces the overall package
    +-      size by 30% volantis, and 20% for angler and bullhead."""
    +-
    +-      # We care about diff transfers only.
    +-      if style != "diff" or not split:
    +-        Transfer(tgt_name, src_name, tgt_ranges, src_ranges, style, by_id)
    +-        return
    ++      size by 30% for volantis, and 20% for angler and bullhead."""
    + 
    ++      # Possibly split large files into smaller chunks.
    +       pieces = 0
    +       cache_size = common.OPTIONS.cache_size
    +       split_threshold = 0.125
    +@@ -1158,6 +1170,74 @@ class BlockImageDiff(object):
    +         Transfer(tgt_split_name, src_split_name, tgt_ranges, src_ranges, style,
    +                  by_id)
    + 
    ++    def AddTransfer(tgt_name, src_name, tgt_ranges, src_ranges, style, by_id,
    ++                    split=False):
    ++      """Wrapper function for adding a Transfer()."""
    ++
    ++      # We specialize diff transfers only (which covers bsdiff/imgdiff/move);
    ++      # otherwise add the Transfer() as is.
    ++      if style != "diff" or not split:
    ++        Transfer(tgt_name, src_name, tgt_ranges, src_ranges, style, by_id)
    ++        return
    ++
    ++      # Handle .odex files specially to analyze the block-wise difference. If
    ++      # most of the blocks are identical with only few changes (e.g. header),
    ++      # we will patch the changed blocks only. This avoids stashing unchanged
    ++      # blocks while patching. We limit the analysis to files without size
    ++      # changes only. This is to avoid sacrificing the OTA generation cost too
    ++      # much.
    ++      if (tgt_name.split(".")[-1].lower() == 'odex' and
    ++          tgt_ranges.size() == src_ranges.size()):
    ++
    ++        # 0.5 threshold can be further tuned. The tradeoff is: if only very
    ++        # few blocks remain identical, we lose the opportunity to use imgdiff
    ++        # that may have better compression ratio than bsdiff.
    ++        crop_threshold = 0.5
    ++
    ++        tgt_skipped = RangeSet()
    ++        src_skipped = RangeSet()
    ++        tgt_size = tgt_ranges.size()
    ++        tgt_changed = 0
    ++        for src_block, tgt_block in zip(src_ranges.next_item(),
    ++                                        tgt_ranges.next_item()):
    ++          src_rs = RangeSet(str(src_block))
    ++          tgt_rs = RangeSet(str(tgt_block))
    ++          if self.src.ReadRangeSet(src_rs) == self.tgt.ReadRangeSet(tgt_rs):
    ++            tgt_skipped = tgt_skipped.union(tgt_rs)
    ++            src_skipped = src_skipped.union(src_rs)
    ++          else:
    ++            tgt_changed += tgt_rs.size()
    ++
    ++          # Terminate early if no clear sign of benefits.
    ++          if tgt_changed > tgt_size * crop_threshold:
    ++            break
    ++
    ++        if tgt_changed < tgt_size * crop_threshold:
    ++          assert tgt_changed + tgt_skipped.size() == tgt_size
    ++          print('%10d %10d (%6.2f%%) %s' % (tgt_skipped.size(), tgt_size,
    ++                tgt_skipped.size() * 100.0 / tgt_size, tgt_name))
    ++          AddSplitTransfers(
    ++              "%s-skipped" % (tgt_name,),
    ++              "%s-skipped" % (src_name,),
    ++              tgt_skipped, src_skipped, style, by_id)
    ++
    ++          # Intentionally change the file extension to avoid being imgdiff'd as
    ++          # the files are no longer in their original format.
    ++          tgt_name = "%s-cropped" % (tgt_name,)
    ++          src_name = "%s-cropped" % (src_name,)
    ++          tgt_ranges = tgt_ranges.subtract(tgt_skipped)
    ++          src_ranges = src_ranges.subtract(src_skipped)
    ++
    ++          # Possibly having no changed blocks.
    ++          if not tgt_ranges:
    ++            return
    ++
    ++      # Add the transfer(s).
    ++      AddSplitTransfers(
    ++          tgt_name, src_name, tgt_ranges, src_ranges, style, by_id)
    ++
    ++    print("Finding transfers...")
    ++
    +     empty = RangeSet()
    +     for tgt_fn, tgt_ranges in self.tgt.file_map.items():
    +       if tgt_fn == "__ZERO":
    +diff --git a/tools/releasetools/rangelib.py b/tools/releasetools/rangelib.py
    +index aa572cc..c9bd375 100644
    +--- a/tools/releasetools/rangelib.py
    ++++ b/tools/releasetools/rangelib.py
    +@@ -300,6 +300,20 @@ class RangeSet(object):
    +         n -= e - s
    +     return RangeSet(data=out)
    + 
    ++  def next_item(self):
    ++    """Return the next integer represented by the RangeSet.
    ++
    ++    >>> list(RangeSet("0-9").next_item())
    ++    [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
    ++    >>> list(RangeSet("10-19 3-5").next_item())
    ++    [3, 4, 5, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19]
    ++    >>> list(rangelib.RangeSet("10-19 3 5 7").next_item())
    ++    [3, 5, 7, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19]
    ++    """
    ++    for s, e in self:
    ++      for element in range(s, e):
    ++        yield element
    ++
    + 
    + if __name__ == "__main__":
    +   import doctest
    +diff --git a/tools/releasetools/test_rangelib.py b/tools/releasetools/test_rangelib.py
    +index a61a64e..edf1c4b 100644
    +--- a/tools/releasetools/test_rangelib.py
    ++++ b/tools/releasetools/test_rangelib.py
    +@@ -124,3 +124,14 @@ class RangeSetTest(unittest.TestCase):
    +     self.assertTrue(RangeSet(data=[2, 9, 30, 31, 31, 32, 35, 36]).monotonic)
    +     self.assertTrue(RangeSet(data=[0, 5, 5, 10]).monotonic)
    +     self.assertFalse(RangeSet(data=[5, 10, 0, 5]).monotonic)
    ++
    ++  def test_next_item(self):
    ++    self.assertEqual(
    ++        list(RangeSet("0-9").next_item()),
    ++        [0, 1, 2, 3, 4, 5, 6, 7, 8, 9])
    ++    self.assertEqual(
    ++        list(RangeSet("10-19 3-5").next_item()),
    ++        [3, 4, 5, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19])
    ++    self.assertEqual(
    ++        list(RangeSet("10-19 3 5 7").next_item()),
    ++        [3, 5, 7, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19])
    diff --git a/frameworks_av.patch b/frameworks_av.patch
    index ffd0e0f..df12cda 100644
    --- a/frameworks_av.patch
    +++ b/frameworks_av.patch
    @@ -1,3 +1,82 @@
    +diff --git a/camera/camera2/CaptureRequest.cpp b/camera/camera2/CaptureRequest.cpp
    +index fb43708..0d689a6 100644
    +--- a/camera/camera2/CaptureRequest.cpp
    ++++ b/camera/camera2/CaptureRequest.cpp
    +@@ -37,7 +37,7 @@ status_t CaptureRequest::readFromParcel(const Parcel* parcel) {
    +     mMetadata.clear();
    +     mSurfaceList.clear();
    + 
    +-    status_t err;
    ++    status_t err = OK;
    + 
    +     if ((err = mMetadata.readFromParcel(parcel)) != OK) {
    +         ALOGE("%s: Failed to read metadata from parcel", __FUNCTION__);
    +@@ -65,19 +65,16 @@ status_t CaptureRequest::readFromParcel(const Parcel* parcel) {
    +         }
    + 
    +         // Surface.writeToParcel
    +-        const char16_t* name = parcel->readString16Inplace(&len);
    +-        ALOGV("%s: Read surface name = %s", __FUNCTION__,
    +-            name != NULL ? String8(name).string() : "<null>");
    +-        sp<IBinder> binder(parcel->readStrongBinder());
    +-        ALOGV("%s: Read surface binder = %p",
    +-              __FUNCTION__, binder.get());
    ++        view::Surface surfaceShim;
    ++        if ((err = surfaceShim.readFromParcel(parcel)) != OK) {
    ++            ALOGE("%s: Failed to read output target Surface %d from parcel: %s (%d)",
    ++                    __FUNCTION__, i, strerror(-err), err);
    ++            return err;
    ++        }
    + 
    +         sp<Surface> surface;
    +-
    +-        if (binder != NULL) {
    +-            sp<IGraphicBufferProducer> gbp =
    +-                    interface_cast<IGraphicBufferProducer>(binder);
    +-            surface = new Surface(gbp);
    ++        if (surfaceShim.graphicBufferProducer != NULL) {
    ++            surface = new Surface(surfaceShim.graphicBufferProducer);
    +         }
    + 
    +         mSurfaceList.push_back(surface);
    +@@ -99,7 +96,7 @@ status_t CaptureRequest::writeToParcel(Parcel* parcel) const {
    +         return BAD_VALUE;
    +     }
    + 
    +-    status_t err;
    ++    status_t err = OK;
    + 
    +     if ((err = mMetadata.writeToParcel(parcel)) != OK) {
    +         return err;
    +@@ -111,20 +108,18 @@ status_t CaptureRequest::writeToParcel(Parcel* parcel) const {
    +     parcel->writeInt32(size);
    + 
    +     for (int32_t i = 0; i < size; ++i) {
    +-        sp<Surface> surface = mSurfaceList[i];
    +-
    +-        sp<IBinder> binder;
    +-        if (surface != 0) {
    +-            binder = IInterface::asBinder(surface->getIGraphicBufferProducer());
    +-        }
    +-
    +         // not sure if readParcelableArray does this, hard to tell from source
    +         parcel->writeString16(String16("android.view.Surface"));
    + 
    +         // Surface.writeToParcel
    +-        parcel->writeString16(String16("unknown_name"));
    +-        // Surface.nativeWriteToParcel
    +-        parcel->writeStrongBinder(binder);
    ++        view::Surface surfaceShim;
    ++        surfaceShim.name = String16("unknown_name");
    ++        surfaceShim.graphicBufferProducer = mSurfaceList[i]->getIGraphicBufferProducer();
    ++        if ((err = surfaceShim.writeToParcel(parcel)) != OK) {
    ++            ALOGE("%s: Failed to write output target Surface %d to parcel: %s (%d)",
    ++                    __FUNCTION__, i, strerror(-err), err);
    ++            return err;
    ++        }
    +     }
    + 
    +     parcel->writeInt32(mIsReprocess ? 1 : 0);
     diff --git a/camera/cameraserver/Android.mk b/camera/cameraserver/Android.mk
     index 7e36c5e..aca7a19 100644
     --- a/camera/cameraserver/Android.mk
    @@ -17,2393 +96,2742 @@ index 7e36c5e..aca7a19 100644
      
      include $(BUILD_EXECUTABLE)
     +endif
    +diff --git a/drm/mediadrm/plugins/clearkey/DrmFactory.cpp b/drm/mediadrm/plugins/clearkey/DrmFactory.cpp
    +index 40275cf..d27956c 100644
    +--- a/drm/mediadrm/plugins/clearkey/DrmFactory.cpp
    ++++ b/drm/mediadrm/plugins/clearkey/DrmFactory.cpp
    +@@ -24,6 +24,7 @@
    + 
    + #include "DrmPlugin.h"
    + #include "ClearKeyUUID.h"
    ++#include "MimeType.h"
    + #include "SessionLibrary.h"
    + 
    + namespace clearkeydrm {
    +@@ -32,10 +33,14 @@ bool DrmFactory::isCryptoSchemeSupported(const uint8_t uuid[16]) {
    +     return isClearKeyUUID(uuid);
    + }
    + 
    +-bool DrmFactory::isContentTypeSupported(const android::String8 &initDataType) {
    ++bool DrmFactory::isContentTypeSupported(const android::String8 &type) {
    +     // This should match the types handed by InitDataParser.
    +-    return initDataType == "cenc" ||
    +-           initDataType == "webm";
    ++    return type == kIsoBmffVideoMimeType ||
    ++        type == kIsoBmffAudioMimeType ||
    ++        type == kCencInitDataFormat ||
    ++        type == kWebmVideoMimeType ||
    ++        type == kWebmAudioMimeType ||
    ++        type == kWebmInitDataFormat;
    + }
    + 
    + android::status_t DrmFactory::createDrmPlugin(
    +diff --git a/drm/mediadrm/plugins/clearkey/DrmFactory.h b/drm/mediadrm/plugins/clearkey/DrmFactory.h
    +index 164d3d0..87db982 100644
    +--- a/drm/mediadrm/plugins/clearkey/DrmFactory.h
    ++++ b/drm/mediadrm/plugins/clearkey/DrmFactory.h
    +@@ -32,7 +32,7 @@ public:
    + 
    +     virtual bool isCryptoSchemeSupported(const uint8_t uuid[16]);
    + 
    +-    virtual bool isContentTypeSupported(const android::String8 &initDataType);
    ++    virtual bool isContentTypeSupported(const android::String8 &mimeType);
    + 
    +     virtual android::status_t createDrmPlugin(
    +             const uint8_t uuid[16], android::DrmPlugin** plugin);
    +diff --git a/drm/mediadrm/plugins/clearkey/DrmPlugin.cpp b/drm/mediadrm/plugins/clearkey/DrmPlugin.cpp
    +index e5ee403..86bf047 100644
    +--- a/drm/mediadrm/plugins/clearkey/DrmPlugin.cpp
    ++++ b/drm/mediadrm/plugins/clearkey/DrmPlugin.cpp
    +@@ -46,7 +46,7 @@ status_t DrmPlugin::closeSession(const Vector<uint8_t>& sessionId) {
    + status_t DrmPlugin::getKeyRequest(
    +         const Vector<uint8_t>& scope,
    +         const Vector<uint8_t>& initData,
    +-        const String8& initDataType,
    ++        const String8& mimeType,
    +         KeyType keyType,
    +         const KeyedVector<String8, String8>& optionalParameters,
    +         Vector<uint8_t>& request,
    +@@ -62,7 +62,7 @@ status_t DrmPlugin::getKeyRequest(
    +     if (!session.get()) {
    +         return android::ERROR_DRM_SESSION_NOT_OPENED;
    +     }
    +-    return session->getKeyRequest(initData, initDataType, &request);
    ++    return session->getKeyRequest(initData, mimeType, &request);
    + }
    + 
    + status_t DrmPlugin::provideKeyResponse(
    +diff --git a/drm/mediadrm/plugins/clearkey/DrmPlugin.h b/drm/mediadrm/plugins/clearkey/DrmPlugin.h
    +index 9095045..efb9f8b 100644
    +--- a/drm/mediadrm/plugins/clearkey/DrmPlugin.h
    ++++ b/drm/mediadrm/plugins/clearkey/DrmPlugin.h
    +@@ -49,7 +49,7 @@ public:
    + 
    +     virtual status_t getKeyRequest(
    +             const Vector<uint8_t>& scope,
    +-            const Vector<uint8_t>& initData,
    ++            const Vector<uint8_t>& mimeType,
    +             const String8& initDataType,
    +             KeyType keyType,
    +             const KeyedVector<String8, String8>& optionalParameters,
    +diff --git a/drm/mediadrm/plugins/clearkey/InitDataParser.cpp b/drm/mediadrm/plugins/clearkey/InitDataParser.cpp
    +index c22d73a..0216b8d 100644
    +--- a/drm/mediadrm/plugins/clearkey/InitDataParser.cpp
    ++++ b/drm/mediadrm/plugins/clearkey/InitDataParser.cpp
    +@@ -27,6 +27,7 @@
    + #include "InitDataParser.h"
    + 
    + #include "ClearKeyUUID.h"
    ++#include "MimeType.h"
    + #include "Utils.h"
    + 
    + namespace clearkeydrm {
    +@@ -41,16 +42,20 @@ namespace {
    + }
    + 
    + android::status_t InitDataParser::parse(const Vector<uint8_t>& initData,
    +-        const String8& initDataType,
    ++        const String8& type,
    +         Vector<uint8_t>* licenseRequest) {
    +     // Build a list of the key IDs
    +     Vector<const uint8_t*> keyIds;
    +-    if (initDataType == "cenc") {
    ++    if (type == kIsoBmffVideoMimeType ||
    ++        type == kIsoBmffAudioMimeType ||
    ++        type == kCencInitDataFormat) {
    +         android::status_t res = parsePssh(initData, &keyIds);
    +         if (res != android::OK) {
    +             return res;
    +         }
    +-    } else if (initDataType == "webm") {
    ++    } else if (type == kWebmVideoMimeType ||
    ++        type == kWebmAudioMimeType ||
    ++        type == kWebmInitDataFormat) {
    +         // WebM "init data" is just a single key ID
    +         if (initData.size() != kKeyIdSize) {
    +             return android::ERROR_DRM_CANNOT_HANDLE;
    +diff --git a/drm/mediadrm/plugins/clearkey/InitDataParser.h b/drm/mediadrm/plugins/clearkey/InitDataParser.h
    +index 9505d2a..a9707bf 100644
    +--- a/drm/mediadrm/plugins/clearkey/InitDataParser.h
    ++++ b/drm/mediadrm/plugins/clearkey/InitDataParser.h
    +@@ -29,7 +29,7 @@ public:
    +     InitDataParser() {}
    + 
    +     android::status_t parse(const android::Vector<uint8_t>& initData,
    +-            const android::String8& initDataType,
    ++            const android::String8& type,
    +             android::Vector<uint8_t>* licenseRequest);
    + 
    + private:
    +diff --git a/drm/mediadrm/plugins/clearkey/MimeType.h b/drm/mediadrm/plugins/clearkey/MimeType.h
    +new file mode 100644
    +index 0000000..085f17a
    +--- /dev/null
    ++++ b/drm/mediadrm/plugins/clearkey/MimeType.h
    +@@ -0,0 +1,15 @@
    ++#ifndef CLEARKEY_MIMETYPE_H_
    ++#define CLEARKEY_MIMETYPE_H_
    ++
    ++#include <utils/String8.h>
    ++
    ++namespace {
    ++    const android::String8 kCencInitDataFormat("cenc");
    ++    const android::String8 kIsoBmffAudioMimeType("audio/mp4");
    ++    const android::String8 kIsoBmffVideoMimeType("video/mp4");
    ++    const android::String8 kWebmInitDataFormat("webm");
    ++    const android::String8 kWebmAudioMimeType("audio/webm");
    ++    const android::String8 kWebmVideoMimeType("video/webm");
    ++}
    ++
    ++#endif // CLEARKEY_MIMETYPE_H_
    +diff --git a/drm/mediadrm/plugins/clearkey/Session.cpp b/drm/mediadrm/plugins/clearkey/Session.cpp
    +index 95016f5..d210f5e 100644
    +--- a/drm/mediadrm/plugins/clearkey/Session.cpp
    ++++ b/drm/mediadrm/plugins/clearkey/Session.cpp
    +@@ -36,10 +36,10 @@ using android::status_t;
    + 
    + status_t Session::getKeyRequest(
    +         const Vector<uint8_t>& initData,
    +-        const String8& initDataType,
    ++        const String8& mimeType,
    +         Vector<uint8_t>* keyRequest) const {
    +     InitDataParser parser;
    +-    return parser.parse(initData, initDataType, keyRequest);
    ++    return parser.parse(initData, mimeType, keyRequest);
    + }
    + 
    + status_t Session::provideKeyResponse(const Vector<uint8_t>& response) {
    +diff --git a/drm/mediadrm/plugins/clearkey/Session.h b/drm/mediadrm/plugins/clearkey/Session.h
    +index cab0dc3..0933506 100644
    +--- a/drm/mediadrm/plugins/clearkey/Session.h
    ++++ b/drm/mediadrm/plugins/clearkey/Session.h
    +@@ -38,7 +38,7 @@ public:
    +     const android::Vector<uint8_t>& sessionId() const { return mSessionId; }
    + 
    +     android::status_t getKeyRequest(
    +-            const android::Vector<uint8_t>& initData,
    ++            const android::Vector<uint8_t>& mimeType,
    +             const android::String8& initDataType,
    +             android::Vector<uint8_t>* keyRequest) const;
    + 
    +diff --git a/drm/mediadrm/plugins/clearkey/tests/InitDataParserUnittest.cpp b/drm/mediadrm/plugins/clearkey/tests/InitDataParserUnittest.cpp
    +index 4ba65ed..e275108 100644
    +--- a/drm/mediadrm/plugins/clearkey/tests/InitDataParserUnittest.cpp
    ++++ b/drm/mediadrm/plugins/clearkey/tests/InitDataParserUnittest.cpp
    +@@ -30,27 +30,27 @@ using namespace android;
    + 
    + namespace {
    +     const size_t kKeyIdSize = 16;
    +-    const String8 kCencType("cenc");
    +-    const String8 kWebMType("webm");
    ++    const String8 kCencMimeType("video/mp4");
    ++    const String8 kWebmMimeType("video/webm");
    +     const String8 kBase64Padding("=");
    + }
    + 
    + class InitDataParserTest : public ::testing::Test {
    +   protected:
    +     status_t attemptParse(const Vector<uint8_t>& initData,
    +-                          const String8& initDataType,
    ++                          const String8& mimeType,
    +                           Vector<uint8_t>* licenseRequest) {
    +         InitDataParser parser;
    +-        return parser.parse(initData, initDataType, licenseRequest);
    ++        return parser.parse(initData, mimeType, licenseRequest);
    +     }
    + 
    +     void attemptParseExpectingSuccess(const Vector<uint8_t>& initData,
    +-                                      const String8& initDataType,
    ++                                      const String8& mimeType,
    +                                       const Vector<String8>& expectedKeys) {
    +         const String8 kRequestPrefix("{\"kids\":[");
    +         const String8 kRequestSuffix("],\"type\":\"temporary\"}");
    +         Vector<uint8_t> request;
    +-        ASSERT_EQ(android::OK, attemptParse(initData, initDataType, &request));
    ++        ASSERT_EQ(android::OK, attemptParse(initData, mimeType, &request));
    + 
    +         String8 requestString(reinterpret_cast<const char*>(request.array()),
    +                               request.size());
    +@@ -68,9 +68,9 @@ class InitDataParserTest : public ::testing::Test {
    +     }
    + 
    +     void attemptParseExpectingFailure(const Vector<uint8_t>& initData,
    +-                                      const String8& initDataType) {
    ++                                      const String8& mimeType) {
    +         Vector<uint8_t> request;
    +-        ASSERT_NE(android::OK, attemptParse(initData, initDataType, &request));
    ++        ASSERT_NE(android::OK, attemptParse(initData, mimeType, &request));
    +         EXPECT_EQ(0, request.size());
    +     }
    + };
    +@@ -93,7 +93,7 @@ TEST_F(InitDataParserTest, ParsesSingleKeyPssh) {
    +     Vector<String8> expectedKeys;
    +     expectedKeys.push(String8("01234567890ABCDE"));
    + 
    +-    attemptParseExpectingSuccess(initData, kCencType, expectedKeys);
    ++    attemptParseExpectingSuccess(initData, kCencMimeType, expectedKeys);
    + }
    + 
    + TEST_F(InitDataParserTest, ParsesMultipleKeyPssh) {
    +@@ -120,7 +120,7 @@ TEST_F(InitDataParserTest, ParsesMultipleKeyPssh) {
    +     expectedKeys.push(String8("ClearKeyClearKey"));
    +     expectedKeys.push(String8(" GOOGLE  GOOGLE "));
    + 
    +-    attemptParseExpectingSuccess(initData, kCencType, expectedKeys);
    ++    attemptParseExpectingSuccess(initData, kCencMimeType, expectedKeys);
    + }
    + 
    + TEST_F(InitDataParserTest, ParsesWebM) {
    +@@ -134,7 +134,7 @@ TEST_F(InitDataParserTest, ParsesWebM) {
    +     Vector<String8> expectedKeys;
    +     expectedKeys.push(String8("01234567890ABCDE"));
    + 
    +-    attemptParseExpectingSuccess(initData, kWebMType, expectedKeys);
    ++    attemptParseExpectingSuccess(initData, kWebmMimeType, expectedKeys);
    + }
    + 
    + TEST_F(InitDataParserTest, FailsForPsshTooSmall) {
    +@@ -147,7 +147,7 @@ TEST_F(InitDataParserTest, FailsForPsshTooSmall) {
    +     Vector<uint8_t> initData;
    +     initData.appendArray(pssh, 16);
    + 
    +-    attemptParseExpectingFailure(initData, kCencType);
    ++    attemptParseExpectingFailure(initData, kCencMimeType);
    + }
    + 
    + TEST_F(InitDataParserTest, FailsForWebMTooSmall) {
    +@@ -157,7 +157,7 @@ TEST_F(InitDataParserTest, FailsForWebMTooSmall) {
    +     Vector<uint8_t> initData;
    +     initData.appendArray(initDataRaw, 8);
    + 
    +-    attemptParseExpectingFailure(initData, kWebMType);
    ++    attemptParseExpectingFailure(initData, kWebmMimeType);
    + }
    + 
    + TEST_F(InitDataParserTest, FailsForPsshBadSystemId) {
    +@@ -175,7 +175,7 @@ TEST_F(InitDataParserTest, FailsForPsshBadSystemId) {
    +     Vector<uint8_t> initData;
    +     initData.appendArray(pssh, 52);
    + 
    +-    attemptParseExpectingFailure(initData, kCencType);
    ++    attemptParseExpectingFailure(initData, kCencMimeType);
    + }
    + 
    + TEST_F(InitDataParserTest, FailsForPsshBadSize) {
    +@@ -193,7 +193,7 @@ TEST_F(InitDataParserTest, FailsForPsshBadSize) {
    +     Vector<uint8_t> initData;
    +     initData.appendArray(pssh, 52);
    + 
    +-    attemptParseExpectingFailure(initData, kCencType);
    ++    attemptParseExpectingFailure(initData, kCencMimeType);
    + }
    + 
    + TEST_F(InitDataParserTest, FailsForPsshWrongVersion) {
    +@@ -211,7 +211,7 @@ TEST_F(InitDataParserTest, FailsForPsshWrongVersion) {
    +     Vector<uint8_t> initData;
    +     initData.appendArray(pssh, 52);
    + 
    +-    attemptParseExpectingFailure(initData, kCencType);
    ++    attemptParseExpectingFailure(initData, kCencMimeType);
    + }
    + 
    + TEST_F(InitDataParserTest, FailsForPsshBadKeyCount) {
    +@@ -229,7 +229,7 @@ TEST_F(InitDataParserTest, FailsForPsshBadKeyCount) {
    +     Vector<uint8_t> initData;
    +     initData.appendArray(pssh, 52);
    + 
    +-    attemptParseExpectingFailure(initData, kCencType);
    ++    attemptParseExpectingFailure(initData, kCencMimeType);
    + }
    + 
    + }  // namespace clearkeydrm
    +diff --git a/include/media/ToneGenerator.h b/include/media/ToneGenerator.h
    +index 75515ac..9fd5f61 100644
    +--- a/include/media/ToneGenerator.h
    ++++ b/include/media/ToneGenerator.h
    +@@ -193,8 +193,8 @@ private:
    +         TONE_JAPAN_DIAL,            // Dial tone: 400Hz, continuous
    +         TONE_JAPAN_BUSY,            // Busy tone: 400Hz, 500ms ON, 500ms OFF...
    +         TONE_JAPAN_RADIO_ACK,       // Radio path acknowlegment: 400Hz, 1s ON, 2s OFF...
    +-        // UK Supervisory tones
    +-        TONE_UK_RINGTONE,           // Ring Tone: A 400Hz + 450Hz tone repeated in a 0.4s on, 0.2s off, 0.4s on, 2.0s off pattern.
    ++        // GB Supervisory tones
    ++        TONE_GB_RINGTONE,           // Ring Tone: A 400Hz + 450Hz tone repeated in a 0.4s on, 0.2s off, 0.4s on, 2.0s off pattern.
    +         // AUSTRALIA Supervisory tones
    +         TONE_AUSTRALIA_RINGTONE,    // Ring tone: A 400Hz + 450Hz tone repeated in a 0.4s on, 0.2s off, 0.4s on, 2.0s off pattern.
    +         TONE_AUSTRALIA_BUSY,        // Busy tone: 425 Hz repeated in a 0.375s on, 0.375s off pattern.
    +@@ -206,7 +206,7 @@ private:
    +     enum region {
    +         ANSI,
    +         JAPAN,
    +-        UK,
    ++        GB,
    +         AUSTRALIA,
    +         CEPT,
    +         NUM_REGIONS
    +@@ -313,7 +313,7 @@ private:
    + 
    +         short mA1_Q14;  // Q14 coefficient
    +         // delay line of full amplitude generator
    +-        short mS1, mS2;  // delay line S2 oldest
    ++        long mS1, mS2;  // delay line S2 oldest
    +         short mS2_0;  // saved value for reinitialisation
    +         short mAmplitude_Q15;  // Q15 amplitude
    +     };
    +diff --git a/include/media/Visualizer.h b/include/media/Visualizer.h
    +index ec0dad5..7bb9e8b 100644
    +--- a/include/media/Visualizer.h
    ++++ b/include/media/Visualizer.h
    +@@ -95,8 +95,7 @@ public:
    + 
    +     // install a callback to receive periodic captures. The capture rate is specified in milliHertz
    +     // and the capture format is according to flags  (see callback_flags).
    +-    status_t setCaptureCallBack(capture_cbk_t cbk, void* user, uint32_t flags, uint32_t rate,
    +-                                bool force = false);
    ++    status_t setCaptureCallBack(capture_cbk_t cbk, void* user, uint32_t flags, uint32_t rate);
    + 
    +     // set the capture size capture size must be a power of two in the range
    +     // [VISUALIZER_CAPTURE_SIZE_MAX. VISUALIZER_CAPTURE_SIZE_MIN]
    +diff --git a/include/media/stagefright/MediaBuffer.h b/include/media/stagefright/MediaBuffer.h
    +index abfe068..a61ddaa 100644
    +--- a/include/media/stagefright/MediaBuffer.h
    ++++ b/include/media/stagefright/MediaBuffer.h
    +@@ -68,11 +68,16 @@ public:
    +         mMemory = mem;
    +     }
    + 
    +-    // Decrements the reference count and returns the buffer to its
    +-    // associated MediaBufferGroup if the reference count drops to 0.
    ++    // If MediaBufferGroup is set, decrement the local reference count;
    ++    // if the local reference count drops to 0, return the buffer to the
    ++    // associated MediaBufferGroup.
    ++    //
    ++    // If no MediaBufferGroup is set, the local reference count must be zero
    ++    // when called, whereupon the MediaBuffer is deleted.
    +     virtual void release();
    + 
    +-    // Increments the reference count.
    ++    // Increments the local reference count.
    ++    // Use only when MediaBufferGroup is set.
    +     virtual void add_ref();
    + 
    +     void *data() const;
    +@@ -97,7 +102,28 @@ public:
    +     // MetaData.
    +     MediaBuffer *clone();
    + 
    +-    int refcount() const;
    ++    // sum of localRefcount() and remoteRefcount()
    ++    int refcount() const {
    ++        return localRefcount() + remoteRefcount();
    ++    }
    ++
    ++    int localRefcount() const {
    ++        return mRefCount;
    ++    }
    ++
    ++    int remoteRefcount() const {
    ++        if (mMemory.get() == nullptr || mMemory->pointer() == nullptr) return 0;
    ++        int32_t remoteRefcount =
    ++                reinterpret_cast<SharedControl *>(mMemory->pointer())->getRemoteRefcount();
    ++        // Sanity check so that remoteRefCount() is non-negative.
    ++        return remoteRefcount >= 0 ? remoteRefcount : 0; // do not allow corrupted data.
    ++    }
    ++
    ++    // returns old value
    ++    int addRemoteRefcount(int32_t value) {
    ++        if (mMemory.get() == nullptr || mMemory->pointer() == nullptr) return 0;
    ++        return reinterpret_cast<SharedControl *>(mMemory->pointer())->addRemoteRefcount(value);
    ++    }
    + 
    +     bool isDeadObject() const {
    +         return isDeadObject(mMemory);
    +@@ -117,25 +143,6 @@ public:
    +     }
    + 
    + protected:
    +-    // MediaBuffer remote releases are handled through a
    +-    // pending release count variable stored in a SharedControl block
    +-    // at the start of the IMemory.
    +-
    +-    // Returns old value of pending release count.
    +-    inline int32_t addPendingRelease(int32_t value) {
    +-        return getSharedControl()->addPendingRelease(value);
    +-    }
    +-
    +-    // Issues all pending releases (works in parallel).
    +-    // Assumes there is a MediaBufferObserver.
    +-    inline void resolvePendingRelease() {
    +-        if (mMemory.get() == nullptr) return;
    +-        while (addPendingRelease(-1) > 0) {
    +-            release();
    +-        }
    +-        addPendingRelease(1);
    +-    }
    +-
    +     // true if MediaBuffer is observed (part of a MediaBufferGroup).
    +     inline bool isObserved() const {
    +         return mObserver != nullptr;
    +@@ -181,18 +188,18 @@ private:
    +         };
    + 
    +         // returns old value
    +-        inline int32_t addPendingRelease(int32_t value) {
    ++        inline int32_t addRemoteRefcount(int32_t value) {
    +             return std::atomic_fetch_add_explicit(
    +-                    &mPendingRelease, (int_least32_t)value, std::memory_order_seq_cst);
    ++                    &mRemoteRefcount, (int_least32_t)value, std::memory_order_seq_cst);
    +         }
    + 
    +-        inline int32_t getPendingRelease() const {
    +-            return std::atomic_load_explicit(&mPendingRelease, std::memory_order_seq_cst);
    ++        inline int32_t getRemoteRefcount() const {
    ++            return std::atomic_load_explicit(&mRemoteRefcount, std::memory_order_seq_cst);
    +         }
    + 
    +-        inline void setPendingRelease(int32_t value) {
    ++        inline void setRemoteRefcount(int32_t value) {
    +             std::atomic_store_explicit(
    +-                    &mPendingRelease, (int_least32_t)value, std::memory_order_seq_cst);
    ++                    &mRemoteRefcount, (int_least32_t)value, std::memory_order_seq_cst);
    +         }
    + 
    +         inline bool isDeadObject() const {
    +@@ -209,13 +216,13 @@ private:
    +             std::atomic_store_explicit(
    +                     &mFlags, (int_least32_t)0, std::memory_order_seq_cst);
    +             std::atomic_store_explicit(
    +-                    &mPendingRelease, (int_least32_t)0, std::memory_order_seq_cst);
    ++                    &mRemoteRefcount, (int_least32_t)0, std::memory_order_seq_cst);
    +         }
    + 
    +     private:
    +         // Caution: atomic_int_fast32_t is 64 bits on LP64.
    +         std::atomic_int_least32_t mFlags;
    +-        std::atomic_int_least32_t mPendingRelease;
    ++        std::atomic_int_least32_t mRemoteRefcount;
    +         int32_t unused[6]; // additional buffer space
    +     };
    + 
     diff --git a/include/media/stagefright/MediaBufferGroup.h b/include/media/stagefright/MediaBufferGroup.h
    -index dfa31b2..2dc77ac 100644
    +index dfa31b2..e0e5856 100644
     --- a/include/media/stagefright/MediaBufferGroup.h
     +++ b/include/media/stagefright/MediaBufferGroup.h
    -@@ -49,7 +49,10 @@ public:
    +@@ -49,14 +49,14 @@ public:
          // If requestedSize is > 0, the returned MediaBuffer should have buffer
          // size of at least requstedSize.
          status_t acquire_buffer(
     -            MediaBuffer **buffer, bool nonBlocking = false, size_t requestedSize = 0);
     +            MediaBuffer **buffer, bool nonBlocking, size_t requestedSize);
    -+
    + 
    +-    size_t buffers() const { return mBuffers.size(); }
     +    status_t acquire_buffer(MediaBuffer **buffer);
     +    status_t acquire_buffer(MediaBuffer **buffer, bool nonBlocking);
      
    -     size_t buffers() const { return mBuffers.size(); }
    +-    // freeBuffers is the number of free buffers allowed to remain.
    +-    void gc(size_t freeBuffers = 0);
    ++    size_t buffers() const { return mBuffers.size(); }
      
    -diff --git a/media/libstagefright/ACodec.cpp b/media/libstagefright/ACodec.cpp
    -index 37fd5a5..706ba4e 100644
    ---- a/media/libstagefright/ACodec.cpp
    -+++ b/media/libstagefright/ACodec.cpp
    -@@ -804,13 +804,22 @@ status_t ACodec::allocateBuffersOnPort(OMX_U32 portIndex) {
    -             } else if (type == kMetadataBufferTypeNativeHandleSource) {
    -                 bufSize = sizeof(VideoNativeHandleMetadata);
    -             }
    -+#ifdef CAMCORDER_GRALLOC_SOURCE
    -+            else if (type == kMetadataBufferTypeGrallocSource) {
    -+                bufSize = sizeof(VideoGrallocMetadata);
    -+            }
    -+#endif
    +-protected:
    ++    // If buffer is nullptr, have acquire_buffer() check for remote release.
    +     virtual void signalBufferReturned(MediaBuffer *buffer);
      
    -             // If using gralloc or native source input metadata buffers, allocate largest
    -             // metadata size as we prefer to generate native source metadata, but component
    -             // may require gralloc source. For camera source, allocate at least enough
    -             // size for native metadata buffers.
    -             size_t allottedSize = bufSize;
    -+#ifdef CAMCORDER_GRALLOC_SOURCE
    -+            if (portIndex == kPortIndexInput && type >= kMetadataBufferTypeGrallocSource) {
    -+#else
    -             if (portIndex == kPortIndexInput && type == kMetadataBufferTypeANWBuffer) {
    -+#endif
    -                 bufSize = max(sizeof(VideoGrallocMetadata), sizeof(VideoNativeMetadata));
    -             } else if (portIndex == kPortIndexInput && type == kMetadataBufferTypeCameraSource) {
    -                 bufSize = max(bufSize, sizeof(VideoNativeMetadata));
    -@@ -1766,6 +1775,14 @@ status_t ACodec::configureCodec(
    -             mInputMetadataType = (MetadataBufferType)storeMeta;
    + private:
    +diff --git a/include/private/media/AudioTrackShared.h b/include/private/media/AudioTrackShared.h
    +index ffdb9b5..7becf57 100644
    +--- a/include/private/media/AudioTrackShared.h
    ++++ b/include/private/media/AudioTrackShared.h
    +@@ -522,6 +522,12 @@ public:
    +         mTimestampMutator.push(timestamp);
    +     }
    + 
    ++    // Flushes the shared ring buffer if the client had requested it using mStreaming.mFlush.
    ++    // If flush occurs then:
    ++    //   cblk->u.mStreaming.mFront, ServerProxy::mFlush and ServerProxy::mFlushed will be modified
    ++    //   client will be notified via Futex
    ++    virtual void    flushBufferIfNeeded();
    ++
    +     // Total count of the number of flushed frames since creation (never reset).
    +     virtual int64_t     framesFlushed() const { return mFlushed; }
    + 
    +diff --git a/media/libeffects/visualizer/EffectVisualizer.cpp b/media/libeffects/visualizer/EffectVisualizer.cpp
    +index 91f9fc7..21fddb1 100644
    +--- a/media/libeffects/visualizer/EffectVisualizer.cpp
    ++++ b/media/libeffects/visualizer/EffectVisualizer.cpp
    +@@ -602,9 +602,14 @@ int Visualizer_command(effect_handle_t self, uint32_t cmdCode, uint32_t cmdSize,
    +     case VISUALIZER_CMD_MEASURE: {
    +         if (pReplyData == NULL || replySize == NULL ||
    +                 *replySize < (sizeof(int32_t) * MEASUREMENT_COUNT)) {
    +-            ALOGV("VISUALIZER_CMD_MEASURE() error *replySize %" PRIu32
    +-                    " < (sizeof(int32_t) * MEASUREMENT_COUNT) %" PRIu32, *replySize,
    +-                    sizeof(int32_t) * MEASUREMENT_COUNT);
    ++            if (replySize == NULL) {
    ++                ALOGV("VISUALIZER_CMD_MEASURE() error replySize NULL");
    ++            } else {
    ++                ALOGV("VISUALIZER_CMD_MEASURE() error *replySize %" PRIu32
    ++                        " < (sizeof(int32_t) * MEASUREMENT_COUNT) %" PRIu32,
    ++                        *replySize,
    ++                        uint32_t(sizeof(int32_t)) * MEASUREMENT_COUNT);
    ++            }
    +             android_errorWriteLog(0x534e4554, "30229821");
    +             return -EINVAL;
              }
    +diff --git a/media/libmedia/AudioTrackShared.cpp b/media/libmedia/AudioTrackShared.cpp
    +index 7119517..846f8b8 100644
    +--- a/media/libmedia/AudioTrackShared.cpp
    ++++ b/media/libmedia/AudioTrackShared.cpp
    +@@ -622,6 +622,56 @@ ServerProxy::ServerProxy(audio_track_cblk_t* cblk, void *buffers, size_t frameCo
    + }
      
    -+#ifdef CAMCORDER_GRALLOC_SOURCE
    -+        // For this specific case we could be using camera source even if storeMetaDataInBuffers
    -+        // returns Gralloc source. Pretend that we are; this will force us to use nBufferSize.
    -+        if (mInputMetadataType == kMetadataBufferTypeGrallocSource) {
    -+            mInputMetadataType = kMetadataBufferTypeCameraSource;
    + __attribute__((no_sanitize("integer")))
    ++void ServerProxy::flushBufferIfNeeded()
    ++{
    ++    audio_track_cblk_t* cblk = mCblk;
    ++    // The acquire_load is not really required. But since the write is a release_store in the
    ++    // client, using acquire_load here makes it easier for people to maintain the code,
    ++    // and the logic for communicating ipc variables seems somewhat standard,
    ++    // and there really isn't much penalty for 4 or 8 byte atomics.
    ++    int32_t flush = android_atomic_acquire_load(&cblk->u.mStreaming.mFlush);
    ++    if (flush != mFlush) {
    ++        ALOGV("ServerProxy::flushBufferIfNeeded() mStreaming.mFlush = 0x%x, mFlush = 0x%0x",
    ++                flush, mFlush);
    ++        int32_t rear = android_atomic_acquire_load(&cblk->u.mStreaming.mRear);
    ++        int32_t front = cblk->u.mStreaming.mFront;
    ++
    ++        // effectively obtain then release whatever is in the buffer
    ++        const size_t overflowBit = mFrameCountP2 << 1;
    ++        const size_t mask = overflowBit - 1;
    ++        int32_t newFront = (front & ~mask) | (flush & mask);
    ++        ssize_t filled = rear - newFront;
    ++        if (filled >= (ssize_t)overflowBit) {
    ++            // front and rear offsets span the overflow bit of the p2 mask
    ++            // so rebasing newFront on the front offset is off by the overflow bit.
    ++            // adjust newFront to match rear offset.
    ++            ALOGV("flush wrap: filled %zx >= overflowBit %zx", filled, overflowBit);
    ++            newFront += overflowBit;
    ++            filled -= overflowBit;
     +        }
    -+#endif
    -+
    -         uint32_t usageBits;
    -         if (mOMX->getParameter(
    -                 mNode, (OMX_INDEXTYPE)OMX_IndexParamConsumerUsageBits,
    -@@ -6036,6 +6053,9 @@ void ACodec::BaseState::onInputBufferFilled(const sp<AMessage> &msg) {
    -                 status_t err2 = OK;
    -                 switch (metaType) {
    -                 case kMetadataBufferTypeInvalid:
    -+#ifdef CAMCORDER_GRALLOC_SOURCE
    -+                case kMetadataBufferTypeCameraSource:
    -+#endif
    -                     break;
    - #ifndef OMX_ANDROID_COMPILE_AS_32BIT_ON_64BIT_PLATFORMS
    -                 case kMetadataBufferTypeNativeHandleSource:
    -@@ -6267,6 +6287,10 @@ bool ACodec::BaseState::onOMXFillBufferDone(
    -                 native_handle_t *handle = NULL;
    -                 VideoNativeHandleMetadata &nativeMeta =
    -                     *(VideoNativeHandleMetadata *)info->mData->data();
    -+#ifdef CAMCORDER_GRALLOC_SOURCE
    -+                VideoGrallocMetadata &grallocMeta =
    -+                    *(VideoGrallocMetadata *)info->mData->data();
    -+#endif
    -                 if (info->mData->size() >= sizeof(nativeMeta)
    -                         && nativeMeta.eType == kMetadataBufferTypeNativeHandleSource) {
    - #ifdef OMX_ANDROID_COMPILE_AS_32BIT_ON_64BIT_PLATFORMS
    -@@ -6276,6 +6300,12 @@ bool ACodec::BaseState::onOMXFillBufferDone(
    -                     handle = (native_handle_t *)nativeMeta.pHandle;
    - #endif
    ++        // Rather than shutting down on a corrupt flush, just treat it as a full flush
    ++        if (!(0 <= filled && (size_t) filled <= mFrameCount)) {
    ++            ALOGE("mFlush %#x -> %#x, front %#x, rear %#x, mask %#x, newFront %#x, "
    ++                    "filled %zd=%#x",
    ++                    mFlush, flush, front, rear,
    ++                    (unsigned)mask, newFront, filled, (unsigned)filled);
    ++            newFront = rear;
    ++        }
    ++        mFlush = flush;
    ++        android_atomic_release_store(newFront, &cblk->u.mStreaming.mFront);
    ++        // There is no danger from a false positive, so err on the side of caution
    ++        if (true /*front != newFront*/) {
    ++            int32_t old = android_atomic_or(CBLK_FUTEX_WAKE, &cblk->mFutex);
    ++            if (!(old & CBLK_FUTEX_WAKE)) {
    ++                (void) syscall(__NR_futex, &cblk->mFutex,
    ++                        mClientInServer ? FUTEX_WAKE_PRIVATE : FUTEX_WAKE, 1);
    ++            }
    ++        }
    ++        mFlushed += (newFront - front) & mask;
    ++    }
    ++}
    ++
    ++__attribute__((no_sanitize("integer")))
    + status_t ServerProxy::obtainBuffer(Buffer* buffer, bool ackFlush)
    + {
    +     LOG_ALWAYS_FATAL_IF(buffer == NULL || buffer->mFrameCount == 0);
    +@@ -636,44 +686,9 @@ status_t ServerProxy::obtainBuffer(Buffer* buffer, bool ackFlush)
    +     int32_t rear;
    +     // See notes on barriers at ClientProxy::obtainBuffer()
    +     if (mIsOut) {
    +-        int32_t flush = cblk->u.mStreaming.mFlush;
    ++        flushBufferIfNeeded(); // might modify mFront
    +         rear = android_atomic_acquire_load(&cblk->u.mStreaming.mRear);
    +         front = cblk->u.mStreaming.mFront;
    +-        if (flush != mFlush) {
    +-            // effectively obtain then release whatever is in the buffer
    +-            const size_t overflowBit = mFrameCountP2 << 1;
    +-            const size_t mask = overflowBit - 1;
    +-            int32_t newFront = (front & ~mask) | (flush & mask);
    +-            ssize_t filled = rear - newFront;
    +-            if (filled >= (ssize_t)overflowBit) {
    +-                // front and rear offsets span the overflow bit of the p2 mask
    +-                // so rebasing newFront on the front offset is off by the overflow bit.
    +-                // adjust newFront to match rear offset.
    +-                ALOGV("flush wrap: filled %zx >= overflowBit %zx", filled, overflowBit);
    +-                newFront += overflowBit;
    +-                filled -= overflowBit;
    +-            }
    +-            // Rather than shutting down on a corrupt flush, just treat it as a full flush
    +-            if (!(0 <= filled && (size_t) filled <= mFrameCount)) {
    +-                ALOGE("mFlush %#x -> %#x, front %#x, rear %#x, mask %#x, newFront %#x, "
    +-                        "filled %zd=%#x",
    +-                        mFlush, flush, front, rear,
    +-                        (unsigned)mask, newFront, filled, (unsigned)filled);
    +-                newFront = rear;
    +-            }
    +-            mFlush = flush;
    +-            android_atomic_release_store(newFront, &cblk->u.mStreaming.mFront);
    +-            // There is no danger from a false positive, so err on the side of caution
    +-            if (true /*front != newFront*/) {
    +-                int32_t old = android_atomic_or(CBLK_FUTEX_WAKE, &cblk->mFutex);
    +-                if (!(old & CBLK_FUTEX_WAKE)) {
    +-                    (void) syscall(__NR_futex, &cblk->mFutex,
    +-                            mClientInServer ? FUTEX_WAKE_PRIVATE : FUTEX_WAKE, 1);
    +-                }
    +-            }
    +-            mFlushed += (newFront - front) & mask;
    +-            front = newFront;
    +-        }
    +     } else {
    +         front = android_atomic_acquire_load(&cblk->u.mStreaming.mFront);
    +         rear = cblk->u.mStreaming.mRear;
    +diff --git a/media/libmedia/ICrypto.cpp b/media/libmedia/ICrypto.cpp
    +index 26dd2c9..302e6ee 100644
    +--- a/media/libmedia/ICrypto.cpp
    ++++ b/media/libmedia/ICrypto.cpp
    +@@ -150,10 +150,10 @@ struct BpCrypto : public BpInterface<ICrypto> {
    + 
    +         if (isCryptoError(result)) {
    +             errorDetailMsg->setTo(reply.readCString());
    +-        }
    +-
    +-        if (dstType == kDestinationTypeVmPointer && result >= 0) {
    +-            reply.read(dstPtr, result);
    ++        } else if (dstType == kDestinationTypeVmPointer) {
    ++            // For the non-secure case, copy the decrypted
    ++            // data from shared memory to its final destination
    ++            memcpy(dstPtr, sharedBuffer->pointer(), result);
    +         }
    + 
    +         return result;
    +@@ -369,7 +369,11 @@ status_t BnCrypto::onTransact(
    +             if (dstType == kDestinationTypeVmPointer) {
    +                 if (result >= 0) {
    +                     CHECK_LE(result, static_cast<ssize_t>(totalSize));
    +-                    reply->write(dstPtr, result);
    ++                    // For the non-secure case, pass the decrypted
    ++                    // data back via the shared buffer rather than
    ++                    // copying it separately over binder to avoid
    ++                    // binder's 1MB limit.
    ++                    memcpy(sharedBuffer->pointer(), dstPtr, result);
                      }
    -+#ifdef CAMCORDER_GRALLOC_SOURCE
    -+                else if (info->mData->size() >= sizeof(grallocMeta)
    -+                        && grallocMeta.eType == kMetadataBufferTypeGrallocSource) {
    -+                    handle = (native_handle_t *)(uintptr_t)grallocMeta.pHandle;
    +                 free(dstPtr);
    +                 dstPtr = NULL;
    +diff --git a/media/libmedia/IMediaExtractor.cpp b/media/libmedia/IMediaExtractor.cpp
    +index e8ad75b..72d1d7c 100644
    +--- a/media/libmedia/IMediaExtractor.cpp
    ++++ b/media/libmedia/IMediaExtractor.cpp
    +@@ -160,6 +160,9 @@ status_t BnMediaExtractor::onTransact(
    +             if (data.readUint32(&idx) == NO_ERROR &&
    +                     data.readUint32(&flags) == NO_ERROR) {
    +                 sp<MetaData> meta = getTrackMetaData(idx, flags);
    ++                if (meta == NULL) {
    ++                    return UNKNOWN_ERROR;
     +                }
    -+#endif
    -                 info->mData->meta()->setPointer("handle", handle);
    -                 info->mData->meta()->setInt32("rangeOffset", rangeOffset);
    -                 info->mData->meta()->setInt32("rangeLength", rangeLength);
    -@@ -6968,10 +6998,12 @@ void ACodec::LoadedState::onCreateInputSurface(
    -         err = mCodec->mOMX->createInputSurface(
    -                 mCodec->mNode, kPortIndexInput, dataSpace, &bufferProducer,
    -                 &mCodec->mInputMetadataType);
    -+#ifndef CAMCORDER_GRALLOC_SOURCE
    -         // framework uses ANW buffers internally instead of gralloc handles
    -         if (mCodec->mInputMetadataType == kMetadataBufferTypeGrallocSource) {
    -             mCodec->mInputMetadataType = kMetadataBufferTypeANWBuffer;
    +                 meta->writeToParcel(*reply);
    +                 return NO_ERROR;
    +             }
    +diff --git a/media/libmedia/IMediaSource.cpp b/media/libmedia/IMediaSource.cpp
    +index dd94ccf..595bad9 100644
    +--- a/media/libmedia/IMediaSource.cpp
    ++++ b/media/libmedia/IMediaSource.cpp
    +@@ -58,9 +58,9 @@ public:
    + 
    + protected:
    +     virtual ~RemoteMediaBufferWrapper() {
    +-        // Indicate to MediaBufferGroup to release.
    +-        int32_t old = addPendingRelease(1);
    +-        ALOGV("RemoteMediaBufferWrapper: releasing %p, old %d", this, old);
    ++        // Release our interest in the MediaBuffer's shared memory.
    ++        int32_t old = addRemoteRefcount(-1);
    ++        ALOGV("RemoteMediaBufferWrapper: releasing %p, refcount %d", this, old - 1);
    +         mMemory.clear(); // don't set the dead object flag.
    +     }
    + };
    +@@ -296,8 +296,8 @@ status_t BnMediaSource::onTransact(
    +         case STOP: {
    +             ALOGV("stop");
    +             CHECK_INTERFACE(IMediaSource, data, reply);
    ++            mGroup->signalBufferReturned(nullptr);
    +             status_t status = stop();
    +-            mGroup->gc();
    +             mIndexCache.reset();
    +             mBuffersSinceStop = 0;
    +             return status;
    +@@ -305,6 +305,7 @@ status_t BnMediaSource::onTransact(
    +         case PAUSE: {
    +             ALOGV("pause");
    +             CHECK_INTERFACE(IMediaSource, data, reply);
    ++            mGroup->signalBufferReturned(nullptr);
    +             return pause();
              }
    -+#endif
    +         case GETFORMAT: {
    +@@ -336,7 +337,7 @@ status_t BnMediaSource::onTransact(
    +                     && len == sizeof(opts)
    +                     && data.read((void *)&opts, len) == NO_ERROR;
    + 
    +-            mGroup->gc(kBinderMediaBuffers /* freeBuffers */);
    ++            mGroup->signalBufferReturned(nullptr);
    +             mIndexCache.gc();
    +             size_t inlineTransferSize = 0;
    +             status_t ret = NO_ERROR;
    +@@ -411,8 +412,9 @@ status_t BnMediaSource::onTransact(
    +                     reply->writeInt32(offset);
    +                     reply->writeInt32(length);
    +                     buf->meta_data()->writeToParcel(*reply);
    ++                    transferBuf->addRemoteRefcount(1);
    +                     if (transferBuf != buf) {
    +-                        buf->release();
    ++                        transferBuf->release(); // release local ref
    +                     } else if (!supportNonblockingRead()) {
    +                         maxNumBuffers = 0; // stop readMultiple with one shared buffer.
    +                     }
    +@@ -423,12 +425,12 @@ status_t BnMediaSource::onTransact(
    +                     reply->writeInt32(INLINE_BUFFER);
    +                     reply->writeByteArray(length, (uint8_t*)buf->data() + offset);
    +                     buf->meta_data()->writeToParcel(*reply);
    +-                    buf->release();
    +                     inlineTransferSize += length;
    +                     if (inlineTransferSize > kInlineMaxTransfer) {
    +                         maxNumBuffers = 0; // stop readMultiple if inline transfer is too large.
    +                     }
    +                 }
    ++                buf->release();
    +             }
    +             reply->writeInt32(NULL_BUFFER); // Indicate no more MediaBuffers.
    +             reply->writeInt32(ret);
    +diff --git a/media/libmedia/ToneGenerator.cpp b/media/libmedia/ToneGenerator.cpp
    +index 2f53637..7a72237 100644
    +--- a/media/libmedia/ToneGenerator.cpp
    ++++ b/media/libmedia/ToneGenerator.cpp
    +@@ -746,7 +746,7 @@ const ToneGenerator::ToneDescriptor ToneGenerator::sToneDescriptors[] = {
    +                         { .duration = 2000, .waveFreq = { 0 }, 0, 0},
    +                         { .duration = 0, .waveFreq = { 0 }, 0, 0}},
    +           .repeatCnt = ToneGenerator::TONEGEN_INF,
    +-          .repeatSegment = 0 },                              // TONE_UK_RINGTONE
    ++          .repeatSegment = 0 },                              // TONE_GB_RINGTONE
    +         { .segments = { { .duration = 400, .waveFreq = { 400, 450, 0 }, 0, 0 },
    +                         { .duration = 200, .waveFreq = { 0 }, 0, 0 },
    +                         { .duration = 400, .waveFreq = { 400, 450, 0 }, 0, 0 },
    +@@ -796,7 +796,7 @@ const unsigned char /*tone_type*/ ToneGenerator::sToneMappingTable[NUM_REGIONS-1
    +             TONE_SUP_CALL_WAITING,       // TONE_SUP_CALL_WAITING
    +             TONE_SUP_RINGTONE            // TONE_SUP_RINGTONE
    +         },
    +-        {   // UK
    ++        {   // GB
    +             TONE_SUP_DIAL,               // TONE_SUP_DIAL
    +             TONE_SUP_BUSY,               // TONE_SUP_BUSY
    +             TONE_SUP_CONGESTION,         // TONE_SUP_CONGESTION
    +@@ -804,7 +804,7 @@ const unsigned char /*tone_type*/ ToneGenerator::sToneMappingTable[NUM_REGIONS-1
    +             TONE_SUP_RADIO_NOTAVAIL,     // TONE_SUP_RADIO_NOTAVAIL
    +             TONE_SUP_ERROR,              // TONE_SUP_ERROR
    +             TONE_SUP_CALL_WAITING,       // TONE_SUP_CALL_WAITING
    +-            TONE_UK_RINGTONE             // TONE_SUP_RINGTONE
    ++            TONE_GB_RINGTONE             // TONE_SUP_RINGTONE
    +         },
    +         {   // AUSTRALIA
    +             TONE_ANSI_DIAL,             // TONE_SUP_DIAL
    +@@ -869,8 +869,8 @@ ToneGenerator::ToneGenerator(audio_stream_type_t streamType, float volume, bool
    +         mRegion = ANSI;
    +     } else if (strstr(value, "jp") != NULL) {
    +         mRegion = JAPAN;
    +-    } else if (strstr(value, "uk") != NULL) {
    +-        mRegion = UK;
    ++    } else if (strstr(value, "gb") != NULL) {
    ++        mRegion = GB;
    +     } else if (strstr(value, "au") != NULL) {
    +         mRegion = AUSTRALIA;
    +     } else {
    +@@ -1612,8 +1612,8 @@ void ToneGenerator::WaveGenerator::getSamples(short *outBuffer,
    +         lS1 = (long)0;
    +         lS2 = (long)mS2_0;
    +     } else {
    +-        lS1 = (long)mS1;
    +-        lS2 = (long)mS2;
    ++        lS1 = mS1;
    ++        lS2 = mS2;
    +     }
    +     lA1 = (long)mA1_Q14;
    +     lAmplitude = (long)mAmplitude_Q15;
    +@@ -1649,8 +1649,8 @@ void ToneGenerator::WaveGenerator::getSamples(short *outBuffer,
          }
      
    -     if (err == OK) {
    -@@ -7014,10 +7046,12 @@ void ACodec::LoadedState::onSetInputSurface(
    -         err = mCodec->mOMX->setInputSurface(
    -                 mCodec->mNode, kPortIndexInput, surface->getBufferConsumer(),
    -                 &mCodec->mInputMetadataType);
    -+#ifndef CAMCORDER_GRALLOC_SOURCE
    -         // framework uses ANW buffers internally instead of gralloc handles
    -         if (mCodec->mInputMetadataType == kMetadataBufferTypeGrallocSource) {
    -             mCodec->mInputMetadataType = kMetadataBufferTypeANWBuffer;
    +     // save status
    +-    mS1 = (short)lS1;
    +-    mS2 = (short)lS2;
    ++    mS1 = lS1;
    ++    mS2 = lS2;
    + }
    + 
    + }  // end namespace android
    +diff --git a/media/libmedia/Visualizer.cpp b/media/libmedia/Visualizer.cpp
    +index 31e310b..37bf0bd 100644
    +--- a/media/libmedia/Visualizer.cpp
    ++++ b/media/libmedia/Visualizer.cpp
    +@@ -55,7 +55,7 @@ Visualizer::~Visualizer()
    + {
    +     ALOGV("Visualizer::~Visualizer()");
    +     setEnabled(false);
    +-    setCaptureCallBack(NULL, NULL, 0, 0, true);
    ++    setCaptureCallBack(NULL, NULL, 0, 0);
    + }
    + 
    + status_t Visualizer::setEnabled(bool enabled)
    +@@ -77,13 +77,11 @@ status_t Visualizer::setEnabled(bool enabled)
    + 
    +     status_t status = AudioEffect::setEnabled(enabled);
    + 
    +-    if (status == NO_ERROR) {
    +-        if (t != 0) {
    +-            if (enabled) {
    +-                t->run("Visualizer");
    +-            } else {
    +-                t->requestExit();
    +-            }
    ++    if (t != 0) {
    ++        if (enabled && status == NO_ERROR) {
    ++            t->run("Visualizer");
    ++        } else {
    ++            t->requestExit();
              }
    -+#endif
          }
      
    -     if (err == OK) {
    -diff --git a/media/libstagefright/Android.mk b/media/libstagefright/Android.mk
    -index 3848502..c06f6a4 100644
    ---- a/media/libstagefright/Android.mk
    -+++ b/media/libstagefright/Android.mk
    -@@ -124,6 +124,10 @@ LOCAL_SHARED_LIBRARIES += \
    -         libdl \
    -         libRScpp \
    +@@ -95,14 +93,14 @@ status_t Visualizer::setEnabled(bool enabled)
    + }
      
    -+ifeq ($(TARGET_HAS_LEGACY_CAMERA_HAL1),true)
    -+LOCAL_CFLAGS += -DCAMCORDER_GRALLOC_SOURCE
    -+endif
    -+
    - LOCAL_CFLAGS += -Wno-multichar -Werror -Wno-error=deprecated-declarations -Wall
    + status_t Visualizer::setCaptureCallBack(capture_cbk_t cbk, void* user, uint32_t flags,
    +-        uint32_t rate, bool force)
    ++        uint32_t rate)
    + {
    +     if (rate > CAPTURE_RATE_MAX) {
    +         return BAD_VALUE;
    +     }
    +     Mutex::Autolock _l(mCaptureLock);
      
    - # enable experiments only in userdebug and eng builds
    -diff --git a/media/libstagefright/CameraSource.cpp b/media/libstagefright/CameraSource.cpp
    -index e087249..c9f60ec 100644
    ---- a/media/libstagefright/CameraSource.cpp
    -+++ b/media/libstagefright/CameraSource.cpp
    -@@ -1117,6 +1117,9 @@ void CameraSource::releaseRecordingFrameHandle(native_handle_t* handle) {
    -         int64_t token = IPCThreadState::self()->clearCallingIdentity();
    -         mCamera->releaseRecordingFrameHandle(handle);
    -         IPCThreadState::self()->restoreCallingIdentity(token);
    -+    } else {
    -+        native_handle_close(handle);
    -+        native_handle_delete(handle);
    +-    if (force || mEnabled) {
    ++    if (mEnabled) {
    +         return INVALID_OPERATION;
          }
    - }
      
    -@@ -1247,6 +1250,10 @@ void CameraSource::processBufferQueueFrame(BufferItem& buffer) {
    - MetadataBufferType CameraSource::metaDataStoredInVideoBuffers() const {
    -     ALOGV("metaDataStoredInVideoBuffers");
    +diff --git a/media/libmediaplayerservice/nuplayer/HTTPLiveSource.cpp b/media/libmediaplayerservice/nuplayer/HTTPLiveSource.cpp
    +index 3fffdc1..5027e01 100644
    +--- a/media/libmediaplayerservice/nuplayer/HTTPLiveSource.cpp
    ++++ b/media/libmediaplayerservice/nuplayer/HTTPLiveSource.cpp
    +@@ -30,6 +30,7 @@
    + #include <media/stagefright/MediaErrors.h>
    + #include <media/stagefright/MetaData.h>
    + #include <media/stagefright/MediaDefs.h>
    ++#include <media/stagefright/Utils.h>
      
    -+#ifdef CAMCORDER_GRALLOC_SOURCE
    -+    return kMetadataBufferTypeGrallocSource;
    -+#endif
    -+
    -     // Output buffers will contain metadata if camera sends us buffer in metadata mode or via
    -     // buffer queue.
    -     switch (mVideoBufferMode) {
    -diff --git a/media/libstagefright/SurfaceMediaSource.cpp b/media/libstagefright/SurfaceMediaSource.cpp
    -index 15ff569..0e9b4e6 100644
    ---- a/media/libstagefright/SurfaceMediaSource.cpp
    -+++ b/media/libstagefright/SurfaceMediaSource.cpp
    -@@ -129,7 +129,11 @@ status_t SurfaceMediaSource::setFrameRate(int32_t fps)
    + namespace android {
      
    - MetadataBufferType SurfaceMediaSource::metaDataStoredInVideoBuffers() const {
    -     ALOGV("isMetaDataStoredInVideoBuffers");
    -+#ifdef CAMCORDER_GRALLOC_SOURCE
    -+    return kMetadataBufferTypeGrallocSource;
    -+#else
    -     return kMetadataBufferTypeANWBuffer;
    -+#endif
    +@@ -100,26 +101,38 @@ void NuPlayer::HTTPLiveSource::prepareAsync() {
    + void NuPlayer::HTTPLiveSource::start() {
      }
      
    - int32_t SurfaceMediaSource::getFrameRate( ) const {
    -@@ -250,6 +254,35 @@ sp<MetaData> SurfaceMediaSource::getFormat()
    -     return meta;
    ++sp<MetaData> NuPlayer::HTTPLiveSource::getFormatMeta(bool audio) {
    ++    sp<MetaData> meta;
    ++    if (mLiveSession != NULL) {
    ++        mLiveSession->getStreamFormatMeta(
    ++                audio ? LiveSession::STREAMTYPE_AUDIO
    ++                      : LiveSession::STREAMTYPE_VIDEO,
    ++                &meta);
    ++    }
    ++
    ++    return meta;
    ++}
    ++
    + sp<AMessage> NuPlayer::HTTPLiveSource::getFormat(bool audio) {
    +-    sp<AMessage> format;
    ++    sp<MetaData> meta;
    +     status_t err = -EWOULDBLOCK;
    +     if (mLiveSession != NULL) {
    +-        err = mLiveSession->getStreamFormat(
    ++        err = mLiveSession->getStreamFormatMeta(
    +                 audio ? LiveSession::STREAMTYPE_AUDIO
    +                       : LiveSession::STREAMTYPE_VIDEO,
    +-                &format);
    ++                &meta);
    +     }
    + 
    ++    sp<AMessage> format;
    +     if (err == -EWOULDBLOCK) {
    +         format = new AMessage();
    +         format->setInt32("err", err);
    +         return format;
    +     }
    + 
    +-    if (err != OK) {
    ++    if (err != OK || convertMetaDataToMessage(meta, &format) != OK) {
    +         return NULL;
    +     }
    +-
    +     return format;
      }
      
    -+#ifdef CAMCORDER_GRALLOC_SOURCE
    -+// Pass the data to the MediaBuffer. Pass in only the metadata
    -+// The metadata passed consists of two parts:
    -+// 1. First, there is an integer indicating that it is a GRAlloc
    -+// source (kMetadataBufferTypeGrallocSource)
    -+// 2. This is followed by the buffer_handle_t that is a handle to the
    -+// GRalloc buffer. The encoder needs to interpret this GRalloc handle
    -+// and encode the frames.
    -+// --------------------------------------------------------------
    -+// |  kMetadataBufferTypeGrallocSource | sizeof(buffer_handle_t) |
    -+// --------------------------------------------------------------
    -+// Note: Call only when you have the lock
    -+static void passMetadataBuffer(MediaBuffer **buffer,
    -+        buffer_handle_t bufferHandle) {
    -+    *buffer = new MediaBuffer(4 + sizeof(buffer_handle_t));
    -+    char *data = (char *)(*buffer)->data();
    -+    if (data == NULL) {
    -+        ALOGE("Cannot allocate memory for metadata buffer!");
    +diff --git a/media/libmediaplayerservice/nuplayer/HTTPLiveSource.h b/media/libmediaplayerservice/nuplayer/HTTPLiveSource.h
    +index 9e0ec2f..574937d 100644
    +--- a/media/libmediaplayerservice/nuplayer/HTTPLiveSource.h
    ++++ b/media/libmediaplayerservice/nuplayer/HTTPLiveSource.h
    +@@ -38,6 +38,7 @@ struct NuPlayer::HTTPLiveSource : public NuPlayer::Source {
    +     virtual void start();
    + 
    +     virtual status_t dequeueAccessUnit(bool audio, sp<ABuffer> *accessUnit);
    ++    virtual sp<MetaData> getFormatMeta(bool audio);
    +     virtual sp<AMessage> getFormat(bool audio);
    + 
    +     virtual status_t feedMoreTSData();
    +diff --git a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp
    +index 134da14..dc4e5d4 100644
    +--- a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp
    ++++ b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp
    +@@ -1339,7 +1339,16 @@ void NuPlayer::onStart(int64_t startPositionUs) {
    +     }
    + 
    +     sp<MetaData> audioMeta = mSource->getFormatMeta(true /* audio */);
    ++    sp<MetaData> videoMeta = mSource->getFormatMeta(false /* audio */);
    ++    if (audioMeta == NULL && videoMeta == NULL) {
    ++        ALOGE("no metadata for either audio or video source");
    ++        mSource->stop();
    ++        mSourceStarted = false;
    ++        notifyListener(MEDIA_ERROR, MEDIA_ERROR_UNKNOWN, ERROR_MALFORMED);
     +        return;
     +    }
    -+    OMX_U32 type = kMetadataBufferTypeGrallocSource;
    -+    memcpy(data, &type, 4);
    -+    memcpy(data + 4, &bufferHandle, sizeof(buffer_handle_t));
    +     ALOGV_IF(audioMeta == NULL, "no metadata for audio source");  // video only stream
     +
    -+    ALOGV("handle = %p, , offset = %zu, length = %zu",
    -+            bufferHandle, (*buffer)->range_length(), (*buffer)->range_offset());
    -+}
    -+#endif
    +     audio_stream_type_t streamType = AUDIO_STREAM_MUSIC;
    +     if (mAudioSink != NULL) {
    +         streamType = mAudioSink->getAudioStreamType();
    +diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp b/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp
    +index cf38efc..594128c 100644
    +--- a/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp
    ++++ b/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp
    +@@ -754,7 +754,7 @@ bool NuPlayer::Decoder::isStaleReply(const sp<AMessage> &msg) {
    + 
    + status_t NuPlayer::Decoder::fetchInputData(sp<AMessage> &reply) {
    +     sp<ABuffer> accessUnit;
    +-    bool dropAccessUnit;
    ++    bool dropAccessUnit = true;
    +     do {
    +         status_t err = mSource->dequeueAccessUnit(mIsAudio, &accessUnit);
    + 
    +diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp b/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp
    +index b47a4f1..b742762 100644
    +--- a/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp
    ++++ b/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp
    +@@ -141,6 +141,17 @@ NuPlayer::Renderer::~Renderer() {
    +         mAudioSink->flush();
    +         mAudioSink->close();
    +     }
     +
    - // Pass the data to the MediaBuffer. Pass in only the metadata
    - // Note: Call only when you have the lock
    - void SurfaceMediaSource::passMetadataBuffer_l(MediaBuffer **buffer,
    -@@ -352,7 +385,11 @@ status_t SurfaceMediaSource::read(
    -     mNumFramesEncoded++;
    -     // Pass the data to the MediaBuffer. Pass in only the metadata
    ++    // Try to avoid racing condition in case callback is still on.
    ++    Mutex::Autolock autoLock(mLock);
    ++    mUseAudioCallback = false;
    ++    flushQueue(&mAudioQueue);
    ++    flushQueue(&mVideoQueue);
    ++    mWakeLock.clear();
    ++    mMediaClock.clear();
    ++    mVideoScheduler.clear();
    ++    mNotify.clear();
    ++    mAudioSink.clear();
    + }
      
    -+#ifdef CAMCORDER_GRALLOC_SOURCE
    -+    passMetadataBuffer(buffer, mSlots[mCurrentSlot].mGraphicBuffer->handle);
    -+#else
    -     passMetadataBuffer_l(buffer, mSlots[mCurrentSlot].mGraphicBuffer->getNativeBuffer());
    -+#endif
    + void NuPlayer::Renderer::queueBuffer(
    +@@ -744,7 +755,7 @@ size_t NuPlayer::Renderer::AudioSinkCallback(
    +         case MediaPlayerBase::AudioSink::CB_EVENT_STREAM_END:
    +         {
    +             ALOGV("AudioSink::CB_EVENT_STREAM_END");
    +-            me->notifyEOS(true /* audio */, ERROR_END_OF_STREAM);
    ++            me->notifyEOSCallback();
    +             break;
    +         }
      
    -     (*buffer)->setObserver(this);
    -     (*buffer)->add_ref();
    -diff --git a/media/libstagefright/foundation/MediaBufferGroup.cpp b/media/libstagefright/foundation/MediaBufferGroup.cpp
    -index cb78879..ecd9cf9 100644
    ---- a/media/libstagefright/foundation/MediaBufferGroup.cpp
    -+++ b/media/libstagefright/foundation/MediaBufferGroup.cpp
    -@@ -188,8 +188,23 @@ status_t MediaBufferGroup::acquire_buffer(
    -     // Never gets here.
    +@@ -759,6 +770,16 @@ size_t NuPlayer::Renderer::AudioSinkCallback(
    +     return 0;
      }
      
    -+status_t MediaBufferGroup::acquire_buffer(
    -+       MediaBuffer **out) {
    -+   return acquire_buffer(out, false, 0);
    -+}
    ++void NuPlayer::Renderer::notifyEOSCallback() {
    ++    Mutex::Autolock autoLock(mLock);
     +
    -+status_t MediaBufferGroup::acquire_buffer(
    -+        MediaBuffer **out, bool nonBlocking) {
    -+    return acquire_buffer(out, nonBlocking, 0);
    ++    if (!mUseAudioCallback) {
    ++        return;
    ++    }
    ++
    ++    notifyEOS(true /* audio */, ERROR_END_OF_STREAM);
     +}
     +
    - void MediaBufferGroup::signalBufferReturned(MediaBuffer *) {
    -     mCondition.signal();
    - }
    + size_t NuPlayer::Renderer::fillAudioBuffer(void *buffer, size_t size) {
    +     Mutex::Autolock autoLock(mLock);
      
    -+/* MediaBufferGroup::MediaBufferGroup */
    -+extern "C" int _ZN7android16MediaBufferGroupC1Ej(unsigned int);
    -+extern "C" int _ZN7android16MediaBufferGroupC1Ev() {
    -+    return _ZN7android16MediaBufferGroupC1Ej(0);
    -+}
    - }  // namespace android
    -diff --git a/media/libstagefright/omx/Android.mk b/media/libstagefright/omx/Android.mk
    -index e4fbd81..c262782 100644
    ---- a/media/libstagefright/omx/Android.mk
    -+++ b/media/libstagefright/omx/Android.mk
    -@@ -31,6 +31,18 @@ LOCAL_SHARED_LIBRARIES :=               \
    -         libstagefright_foundation       \
    -         libdl
    +@@ -1190,8 +1211,10 @@ void NuPlayer::Renderer::postDrainVideoQueue() {
    +             msg->setWhat(kWhatPostDrainVideoQueue);
    +             msg->post(postDelayUs);
    +             mVideoScheduler->restart();
    +-            ALOGI("possible video time jump of %dms or uninitialized media clock, retrying in %dms",
    +-                    (int)(delayUs / 1000), (int)(postDelayUs / 1000));
    ++            ALOGI("possible video time jump of %dms (%lld : %lld) or uninitialized media clock,"
    ++                    " retrying in %dms",
    ++                    (int)(delayUs / 1000), (long long)mediaTimeUs,
    ++                    (long long)mAudioFirstAnchorTimeMediaUs, (int)(postDelayUs / 1000));
    +             mDrainVideoQueuePending = true;
    +             return;
    +         }
    +diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.h b/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.h
    +index 004e21c..fe7f8fa 100644
    +--- a/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.h
    ++++ b/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.h
    +@@ -212,6 +212,7 @@ private:
    +     status_t getCurrentPositionFromAnchor(
    +             int64_t *mediaUs, int64_t nowUs, bool allowPastQueuedVideo = false);
      
    -+ifneq ($(TARGET_USES_MEDIA_EXTENSIONS),true)
    -+ifeq ($(TARGET_HAS_LEGACY_CAMERA_HAL1),true)
    -+LOCAL_CFLAGS += -DCAMCORDER_GRALLOC_SOURCE
    -+endif
    -+endif
    -+
    -+ifneq ($(TARGET_USES_MEDIA_EXTENSIONS),true)
    -+ifeq ($(TARGET_HAS_LEGACY_CAMERA_HAL1),true)
    -+LOCAL_CFLAGS += -DCAMCORDER_GRALLOC_SOURCE
    -+endif
    -+endif
    -+
    - LOCAL_MODULE:= libstagefright_omx
    - LOCAL_CFLAGS += -Werror -Wall
    - LOCAL_CLANG := true
    -diff --git a/media/libstagefright/omx/OMXMaster.cpp b/media/libstagefright/omx/OMXMaster.cpp
    -index 6132a2c..7f0d270 100644
    ---- a/media/libstagefright/omx/OMXMaster.cpp
    -+++ b/media/libstagefright/omx/OMXMaster.cpp
    -@@ -69,6 +69,7 @@ OMXMaster::~OMXMaster() {
    ++    void notifyEOSCallback();
    +     size_t fillAudioBuffer(void *buffer, size_t size);
      
    - void OMXMaster::addVendorPlugin() {
    -     addPlugin("libstagefrighthw.so");
    -+    addPlugin("libsomxcore.so");
    +     bool onDrainAudioQueue();
    +diff --git a/media/libmediaplayerservice/nuplayer/RTSPSource.cpp b/media/libmediaplayerservice/nuplayer/RTSPSource.cpp
    +index 8a305de..c4e5df7 100644
    +--- a/media/libmediaplayerservice/nuplayer/RTSPSource.cpp
    ++++ b/media/libmediaplayerservice/nuplayer/RTSPSource.cpp
    +@@ -58,6 +58,7 @@ NuPlayer::RTSPSource::RTSPSource(
    +       mDisconnectReplyID(0),
    +       mBuffering(false),
    +       mInPreparationPhase(true),
    ++      mEOSPending(false),
    +       mSeekGeneration(0),
    +       mEOSTimeoutAudio(0),
    +       mEOSTimeoutVideo(0) {
    +@@ -200,34 +201,28 @@ status_t NuPlayer::RTSPSource::dequeueAccessUnit(
    +     status_t finalResult;
    +     if (!source->hasBufferAvailable(&finalResult)) {
    +         if (finalResult == OK) {
    +-            int64_t mediaDurationUs = 0;
    +-            getDuration(&mediaDurationUs);
    +-            sp<AnotherPacketSource> otherSource = getSource(!audio);
    +-            status_t otherFinalResult;
    +-
    +-            // If other source already signaled EOS, this source should also signal EOS
    +-            if (otherSource != NULL &&
    +-                    !otherSource->hasBufferAvailable(&otherFinalResult) &&
    +-                    otherFinalResult == ERROR_END_OF_STREAM) {
    +-                source->signalEOS(ERROR_END_OF_STREAM);
    ++
    ++            // If other source already signaled EOS, this source should also return EOS
    ++            if (sourceReachedEOS(!audio)) {
    +                 return ERROR_END_OF_STREAM;
    +             }
    + 
    +             // If this source has detected near end, give it some time to retrieve more
    +-            // data before signaling EOS
    ++            // data before returning EOS
    ++            int64_t mediaDurationUs = 0;
    ++            getDuration(&mediaDurationUs);
    +             if (source->isFinished(mediaDurationUs)) {
    +                 int64_t eosTimeout = audio ? mEOSTimeoutAudio : mEOSTimeoutVideo;
    +                 if (eosTimeout == 0) {
    +                     setEOSTimeout(audio, ALooper::GetNowUs());
    +                 } else if ((ALooper::GetNowUs() - eosTimeout) > kNearEOSTimeoutUs) {
    +                     setEOSTimeout(audio, 0);
    +-                    source->signalEOS(ERROR_END_OF_STREAM);
    +                     return ERROR_END_OF_STREAM;
    +                 }
    +                 return -EWOULDBLOCK;
    +             }
    + 
    +-            if (!(otherSource != NULL && otherSource->isFinished(mediaDurationUs))) {
    ++            if (!sourceNearEOS(!audio)) {
    +                 // We should not enter buffering mode
    +                 // if any of the sources already have detected EOS.
    +                 startBufferingIfNecessary();
    +@@ -306,6 +301,7 @@ void NuPlayer::RTSPSource::performSeek(int64_t seekTimeUs) {
    + 
    +     mState = SEEKING;
    +     mHandler->seek(seekTimeUs);
    ++    mEOSPending = false;
      }
      
    - void OMXMaster::addPlugin(const char *libname) {
    -diff --git a/media/libstagefright/omx/OMXNodeInstance.cpp b/media/libstagefright/omx/OMXNodeInstance.cpp
    -index 395dad8..c6e3a38 100644
    ---- a/media/libstagefright/omx/OMXNodeInstance.cpp
    -+++ b/media/libstagefright/omx/OMXNodeInstance.cpp
    -@@ -795,7 +795,11 @@ status_t OMXNodeInstance::useBuffer(
    -     // metadata buffers are not connected cross process
    -     // use a backup buffer instead of the actual buffer
    -     BufferMeta *buffer_meta;
    -+#ifdef CAMCORDER_GRALLOC_SOURCE
    -+    bool useBackup = false;
    -+#else
    -     bool useBackup = mMetadataType[portIndex] != kMetadataBufferTypeInvalid;
    -+#endif
    -     OMX_U8 *data = static_cast<OMX_U8 *>(params->pointer());
    -     // allocate backup buffer
    -     if (useBackup) {
    -@@ -1286,7 +1290,11 @@ status_t OMXNodeInstance::allocateBufferWithBackup(
    -     }
    + void NuPlayer::RTSPSource::schedulePollBuffering() {
    +@@ -314,10 +310,10 @@ void NuPlayer::RTSPSource::schedulePollBuffering() {
    + }
      
    -     // metadata buffers are not connected cross process; only copy if not meta
    -+#ifdef CAMCORDER_GRALLOC_SOURCE
    -+    bool copy = true;
    -+#else
    -     bool copy = mMetadataType[portIndex] == kMetadataBufferTypeInvalid;
    -+#endif
    + void NuPlayer::RTSPSource::checkBuffering(
    +-        bool *prepared, bool *underflow, bool *overflow, bool *startServer) {
    ++        bool *prepared, bool *underflow, bool *overflow, bool *startServer, bool *finished) {
    +     size_t numTracks = mTracks.size();
    +-    size_t preparedCount, underflowCount, overflowCount, startCount;
    +-    preparedCount = underflowCount = overflowCount = startCount = 0;
    ++    size_t preparedCount, underflowCount, overflowCount, startCount, finishedCount;
    ++    preparedCount = underflowCount = overflowCount = startCount = finishedCount = 0;
      
    -     BufferMeta *buffer_meta = new BufferMeta(
    -             params, portIndex,
    -@@ -1404,10 +1412,30 @@ status_t OMXNodeInstance::emptyBuffer(
    -     BufferMeta *buffer_meta =
    -         static_cast<BufferMeta *>(header->pAppPrivate);
    +     size_t count = numTracks;
    +     for (size_t i = 0; i < count; ++i) {
    +@@ -337,6 +333,7 @@ void NuPlayer::RTSPSource::checkBuffering(
      
    -+#ifndef CAMCORDER_GRALLOC_SOURCE
    -     // set up proper filled length if component is configured for gralloc metadata mode
    -     // ignore rangeOffset in this case (as client may be assuming ANW meta buffers).
    -     if (mMetadataType[kPortIndexInput] == kMetadataBufferTypeGrallocSource) {
    -         header->nFilledLen = rangeLength ? sizeof(VideoGrallocMetadata) : 0;
    -+#else
    -+    sp<ABuffer> backup = buffer_meta->getBuffer(header, true /* backup */, false /* limit */);
    -+    sp<ABuffer> codec = buffer_meta->getBuffer(header, false /* backup */, false /* limit */);
    -+
    -+    // convert incoming ANW meta buffers if component is configured for gralloc metadata mode
    -+    // ignore rangeOffset in this case
    -+    if (mMetadataType[kPortIndexInput] == kMetadataBufferTypeGrallocSource
    -+            && backup->capacity() >= sizeof(VideoNativeMetadata)
    -+            && codec->capacity() >= sizeof(VideoGrallocMetadata)
    -+            && ((VideoNativeMetadata *)backup->base())->eType
    -+                    == kMetadataBufferTypeANWBuffer) {
    -+        VideoNativeMetadata &backupMeta = *(VideoNativeMetadata *)backup->base();
    -+        VideoGrallocMetadata &codecMeta = *(VideoGrallocMetadata *)codec->base();
    -+        CLOG_BUFFER(emptyBuffer, "converting ANWB %p to handle %p",
    -+                backupMeta.pBuffer, backupMeta.pBuffer->handle);
    -+        codecMeta.pHandle = backupMeta.pBuffer != NULL ? backupMeta.pBuffer->handle : NULL;
    -+        codecMeta.eType = kMetadataBufferTypeGrallocSource;
    -+        header->nFilledLen = rangeLength ? sizeof(codecMeta) : 0;
    -+#endif
    -         header->nOffset = 0;
    -     } else {
    -         // rangeLength and rangeOffset must be a subset of the allocated data in the buffer.
    -diff --git a/media/libstagefright/omx/OMXNodeInstance.cpp.orig b/media/libstagefright/omx/OMXNodeInstance.cpp.orig
    -new file mode 100644
    -index 0000000..c570603
    ---- /dev/null
    -+++ b/media/libstagefright/omx/OMXNodeInstance.cpp.orig
    -@@ -0,0 +1,2037 @@
    -+/*
    -+ * Copyright (C) 2009 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.
    -+ */
    -+
    -+//#define LOG_NDEBUG 0
    -+#define LOG_TAG "OMXNodeInstance"
    -+#include <utils/Log.h>
    -+
    -+#include <inttypes.h>
    -+
    -+#include "../include/OMXNodeInstance.h"
    -+#include "OMXMaster.h"
    -+#include "OMXUtils.h"
    -+#include "GraphicBufferSource.h"
    -+
    -+#include <OMX_Component.h>
    -+#include <OMX_IndexExt.h>
    -+#include <OMX_AsString.h>
    -+
    -+#include <binder/IMemory.h>
    -+#include <cutils/properties.h>
    -+#include <gui/BufferQueue.h>
    -+#include <HardwareAPI.h>
    -+#include <media/stagefright/foundation/ADebug.h>
    -+#include <media/stagefright/foundation/ABuffer.h>
    -+#include <media/stagefright/MediaErrors.h>
    -+#include <utils/misc.h>
    -+#include <utils/NativeHandle.h>
    -+
    -+static const OMX_U32 kPortIndexInput = 0;
    -+static const OMX_U32 kPortIndexOutput = 1;
    -+
    -+#define CLOGW(fmt, ...) ALOGW("[%x:%s] " fmt, mNodeID, mName, ##__VA_ARGS__)
    -+
    -+#define CLOG_ERROR_IF(cond, fn, err, fmt, ...) \
    -+    ALOGE_IF(cond, #fn "(%x:%s, " fmt ") ERROR: %s(%#x)", \
    -+    mNodeID, mName, ##__VA_ARGS__, asString(err), err)
    -+#define CLOG_ERROR(fn, err, fmt, ...) CLOG_ERROR_IF(true, fn, err, fmt, ##__VA_ARGS__)
    -+#define CLOG_IF_ERROR(fn, err, fmt, ...) \
    -+    CLOG_ERROR_IF((err) != OMX_ErrorNone, fn, err, fmt, ##__VA_ARGS__)
    -+
    -+#define CLOGI_(level, fn, fmt, ...) \
    -+    ALOGI_IF(DEBUG >= (level), #fn "(%x:%s, " fmt ")", mNodeID, mName, ##__VA_ARGS__)
    -+#define CLOGD_(level, fn, fmt, ...) \
    -+    ALOGD_IF(DEBUG >= (level), #fn "(%x:%s, " fmt ")", mNodeID, mName, ##__VA_ARGS__)
    -+
    -+#define CLOG_LIFE(fn, fmt, ...)     CLOGI_(ADebug::kDebugLifeCycle,     fn, fmt, ##__VA_ARGS__)
    -+#define CLOG_STATE(fn, fmt, ...)    CLOGI_(ADebug::kDebugState,         fn, fmt, ##__VA_ARGS__)
    -+#define CLOG_CONFIG(fn, fmt, ...)   CLOGI_(ADebug::kDebugConfig,        fn, fmt, ##__VA_ARGS__)
    -+#define CLOG_INTERNAL(fn, fmt, ...) CLOGD_(ADebug::kDebugInternalState, fn, fmt, ##__VA_ARGS__)
    -+
    -+#define CLOG_DEBUG_IF(cond, fn, fmt, ...) \
    -+    ALOGD_IF(cond, #fn "(%x, " fmt ")", mNodeID, ##__VA_ARGS__)
    -+
    -+#define CLOG_BUFFER(fn, fmt, ...) \
    -+    CLOG_DEBUG_IF(DEBUG >= ADebug::kDebugAll, fn, fmt, ##__VA_ARGS__)
    -+#define CLOG_BUMPED_BUFFER(fn, fmt, ...) \
    -+    CLOG_DEBUG_IF(DEBUG_BUMP >= ADebug::kDebugAll, fn, fmt, ##__VA_ARGS__)
    -+
    -+/* buffer formatting */
    -+#define BUFFER_FMT(port, fmt, ...) "%s:%u " fmt, portString(port), (port), ##__VA_ARGS__
    -+#define NEW_BUFFER_FMT(buffer_id, port, fmt, ...) \
    -+    BUFFER_FMT(port, fmt ") (#%zu => %#x", ##__VA_ARGS__, mActiveBuffers.size(), (buffer_id))
    -+
    -+#define SIMPLE_BUFFER(port, size, data) BUFFER_FMT(port, "%zu@%p", (size), (data))
    -+#define SIMPLE_NEW_BUFFER(buffer_id, port, size, data) \
    -+    NEW_BUFFER_FMT(buffer_id, port, "%zu@%p", (size), (data))
    -+
    -+#define EMPTY_BUFFER(addr, header, fenceFd) "%#x [%u@%p fc=%d]", \
    -+    (addr), (header)->nAllocLen, (header)->pBuffer, (fenceFd)
    -+#define FULL_BUFFER(addr, header, fenceFd) "%#" PRIxPTR " [%u@%p (%u..+%u) f=%x ts=%lld fc=%d]", \
    -+    (intptr_t)(addr), (header)->nAllocLen, (header)->pBuffer, \
    -+    (header)->nOffset, (header)->nFilledLen, (header)->nFlags, (header)->nTimeStamp, (fenceFd)
    -+
    -+#define WITH_STATS_WRAPPER(fmt, ...) fmt " { IN=%zu/%zu OUT=%zu/%zu }", ##__VA_ARGS__, \
    -+    mInputBuffersWithCodec.size(), mNumPortBuffers[kPortIndexInput], \
    -+    mOutputBuffersWithCodec.size(), mNumPortBuffers[kPortIndexOutput]
    -+// TRICKY: this is needed so formatting macros expand before substitution
    -+#define WITH_STATS(fmt, ...) WITH_STATS_WRAPPER(fmt, ##__VA_ARGS__)
    -+
    -+namespace android {
    -+
    -+struct BufferMeta {
    -+    BufferMeta(
    -+            const sp<IMemory> &mem, OMX_U32 portIndex, bool copyToOmx,
    -+            bool copyFromOmx, OMX_U8 *backup)
    -+        : mMem(mem),
    -+          mCopyFromOmx(copyFromOmx),
    -+          mCopyToOmx(copyToOmx),
    -+          mPortIndex(portIndex),
    -+          mBackup(backup) {
    -+    }
    -+
    -+    BufferMeta(size_t size, OMX_U32 portIndex)
    -+        : mSize(size),
    -+          mCopyFromOmx(false),
    -+          mCopyToOmx(false),
    -+          mPortIndex(portIndex),
    -+          mBackup(NULL) {
    -+    }
    -+
    -+    BufferMeta(const sp<GraphicBuffer> &graphicBuffer, OMX_U32 portIndex)
    -+        : mGraphicBuffer(graphicBuffer),
    -+          mCopyFromOmx(false),
    -+          mCopyToOmx(false),
    -+          mPortIndex(portIndex),
    -+          mBackup(NULL) {
    +         if (src->isFinished(/* duration */ 0)) {
    +             ++overflowCount;
    ++            ++finishedCount;
    +         } else {
    +             if (bufferedDurationUs < kUnderflowMarkUs) {
    +                 ++underflowCount;
    +@@ -354,11 +351,12 @@ void NuPlayer::RTSPSource::checkBuffering(
    +     *underflow   = (underflowCount > 0);
    +     *overflow    = (overflowCount == numTracks);
    +     *startServer = (startCount > 0);
    ++    *finished    = (finishedCount > 0);
    + }
    + 
    + void NuPlayer::RTSPSource::onPollBuffering() {
    +-    bool prepared, underflow, overflow, startServer;
    +-    checkBuffering(&prepared, &underflow, &overflow, &startServer);
    ++    bool prepared, underflow, overflow, startServer, finished;
    ++    checkBuffering(&prepared, &underflow, &overflow, &startServer, &finished);
    + 
    +     if (prepared && mInPreparationPhase) {
    +         mInPreparationPhase = false;
    +@@ -369,8 +367,11 @@ void NuPlayer::RTSPSource::onPollBuffering() {
    +         startBufferingIfNecessary();
    +     }
    + 
    +-    if (overflow && mHandler != NULL) {
    ++    if (haveSufficientDataOnAllTracks()) {
    +         stopBufferingIfNecessary();
     +    }
     +
    -+    void CopyFromOMX(const OMX_BUFFERHEADERTYPE *header) {
    -+        if (!mCopyFromOmx) {
    -+            return;
    -+        }
    -+
    -+        // check component returns proper range
    -+        sp<ABuffer> codec = getBuffer(header, false /* backup */, true /* limit */);
    -+
    -+        memcpy((OMX_U8 *)mMem->pointer() + header->nOffset, codec->data(), codec->size());
    ++    if (overflow && mHandler != NULL) {
    +         mHandler->pause();
    +     }
    + 
    +@@ -378,9 +379,72 @@ void NuPlayer::RTSPSource::onPollBuffering() {
    +         mHandler->resume();
    +     }
    + 
    ++    if (finished && mHandler != NULL) {
    ++        mHandler->cancelAccessUnitTimeoutCheck();
     +    }
     +
    -+    void CopyToOMX(const OMX_BUFFERHEADERTYPE *header) {
    -+        if (!mCopyToOmx) {
    -+            return;
    -+        }
    +     schedulePollBuffering();
    + }
    + 
    ++void NuPlayer::RTSPSource::signalSourceEOS(status_t result) {
    ++    const bool audio = true;
    ++    const bool video = false;
     +
    -+        memcpy(header->pBuffer + header->nOffset,
    -+                (const OMX_U8 *)mMem->pointer() + header->nOffset,
    -+                header->nFilledLen);
    ++    sp<AnotherPacketSource> source = getSource(audio);
    ++    if (source != NULL) {
    ++        source->signalEOS(result);
     +    }
     +
    -+    // return either the codec or the backup buffer
    -+    sp<ABuffer> getBuffer(const OMX_BUFFERHEADERTYPE *header, bool backup, bool limit) {
    -+        sp<ABuffer> buf;
    -+        if (backup && mMem != NULL) {
    -+            buf = new ABuffer(mMem->pointer(), mMem->size());
    -+        } else {
    -+            buf = new ABuffer(header->pBuffer, header->nAllocLen);
    -+        }
    -+        if (limit) {
    -+            if (header->nOffset + header->nFilledLen > header->nOffset
    -+                    && header->nOffset + header->nFilledLen <= header->nAllocLen) {
    -+                buf->setRange(header->nOffset, header->nFilledLen);
    -+            } else {
    -+                buf->setRange(0, 0);
    -+            }
    -+        }
    -+        return buf;
    ++    source = getSource(video);
    ++    if (source != NULL) {
    ++        source->signalEOS(result);
     +    }
    ++}
     +
    -+    void setGraphicBuffer(const sp<GraphicBuffer> &graphicBuffer) {
    -+        mGraphicBuffer = graphicBuffer;
    -+    }
    ++bool NuPlayer::RTSPSource::sourceReachedEOS(bool audio) {
    ++    sp<AnotherPacketSource> source = getSource(audio);
    ++    status_t finalResult;
    ++    return (source != NULL &&
    ++            !source->hasBufferAvailable(&finalResult) &&
    ++            finalResult == ERROR_END_OF_STREAM);
    ++}
     +
    -+    void setNativeHandle(const sp<NativeHandle> &nativeHandle) {
    -+        mNativeHandle = nativeHandle;
    -+    }
    ++bool NuPlayer::RTSPSource::sourceNearEOS(bool audio) {
    ++    sp<AnotherPacketSource> source = getSource(audio);
    ++    int64_t mediaDurationUs = 0;
    ++    getDuration(&mediaDurationUs);
    ++    return (source != NULL && source->isFinished(mediaDurationUs));
    ++}
     +
    -+    OMX_U32 getPortIndex() {
    -+        return mPortIndex;
    -+    }
    ++void NuPlayer::RTSPSource::onSignalEOS(const sp<AMessage> &msg) {
    ++    int32_t generation;
    ++    CHECK(msg->findInt32("generation", &generation));
     +
    -+    ~BufferMeta() {
    -+        delete[] mBackup;
    ++    if (generation != mSeekGeneration) {
    ++        return;
     +    }
     +
    -+private:
    -+    sp<GraphicBuffer> mGraphicBuffer;
    -+    sp<NativeHandle> mNativeHandle;
    -+    sp<IMemory> mMem;
    -+    size_t mSize;
    -+    bool mCopyFromOmx;
    -+    bool mCopyToOmx;
    -+    OMX_U32 mPortIndex;
    -+    OMX_U8 *mBackup;
    -+
    -+    BufferMeta(const BufferMeta &);
    -+    BufferMeta &operator=(const BufferMeta &);
    -+};
    -+
    -+// static
    -+OMX_CALLBACKTYPE OMXNodeInstance::kCallbacks = {
    -+    &OnEvent, &OnEmptyBufferDone, &OnFillBufferDone
    -+};
    -+
    -+static inline const char *portString(OMX_U32 portIndex) {
    -+    switch (portIndex) {
    -+        case kPortIndexInput:  return "Input";
    -+        case kPortIndexOutput: return "Output";
    -+        case ~0U:              return "All";
    -+        default:               return "port";
    ++    if (mEOSPending) {
    ++        signalSourceEOS(ERROR_END_OF_STREAM);
    ++        mEOSPending = false;
     +    }
     +}
     +
    -+OMXNodeInstance::OMXNodeInstance(
    -+        OMX *owner, const sp<IOMXObserver> &observer, const char *name)
    -+    : mOwner(owner),
    -+      mNodeID(0),
    -+      mHandle(NULL),
    -+      mObserver(observer),
    -+      mDying(false),
    -+      mSailed(false),
    -+      mQueriedProhibitedExtensions(false),
    -+      mBufferIDCount(0)
    -+{
    -+    mName = ADebug::GetDebugName(name);
    -+    DEBUG = ADebug::GetDebugLevelFromProperty(name, "debug.stagefright.omx-debug");
    -+    ALOGV("debug level for %s is %d", name, DEBUG);
    -+    DEBUG_BUMP = DEBUG;
    -+    mNumPortBuffers[0] = 0;
    -+    mNumPortBuffers[1] = 0;
    -+    mDebugLevelBumpPendingBuffers[0] = 0;
    -+    mDebugLevelBumpPendingBuffers[1] = 0;
    -+    mMetadataType[0] = kMetadataBufferTypeInvalid;
    -+    mMetadataType[1] = kMetadataBufferTypeInvalid;
    -+    mSecureBufferType[0] = kSecureBufferTypeUnknown;
    -+    mSecureBufferType[1] = kSecureBufferTypeUnknown;
    -+    mIsSecure = AString(name).endsWith(".secure");
    -+}
    -+
    -+OMXNodeInstance::~OMXNodeInstance() {
    -+    free(mName);
    -+    CHECK(mHandle == NULL);
    -+}
    -+
    -+void OMXNodeInstance::setHandle(OMX::node_id node_id, OMX_HANDLETYPE handle) {
    -+    mNodeID = node_id;
    -+    CLOG_LIFE(allocateNode, "handle=%p", handle);
    -+    CHECK(mHandle == NULL);
    -+    mHandle = handle;
    ++void NuPlayer::RTSPSource::postSourceEOSIfNecessary() {
    ++    const bool audio = true;
    ++    const bool video = false;
    ++    // If a source has detected near end, give it some time to retrieve more
    ++    // data before signaling EOS
    ++    if (sourceNearEOS(audio) || sourceNearEOS(video)) {
    ++        if (!mEOSPending) {
    ++            sp<AMessage> msg = new AMessage(kWhatSignalEOS, this);
    ++            msg->setInt32("generation", mSeekGeneration);
    ++            msg->post(kNearEOSTimeoutUs);
    ++            mEOSPending = true;
    ++        }
    ++    }
     +}
     +
    -+sp<GraphicBufferSource> OMXNodeInstance::getGraphicBufferSource() {
    -+    Mutex::Autolock autoLock(mGraphicBufferSourceLock);
    -+    return mGraphicBufferSource;
    -+}
    + void NuPlayer::RTSPSource::onMessageReceived(const sp<AMessage> &msg) {
    +     if (msg->what() == kWhatDisconnect) {
    +         sp<AReplyToken> replyID;
    +@@ -408,6 +472,9 @@ void NuPlayer::RTSPSource::onMessageReceived(const sp<AMessage> &msg) {
    +     } else if (msg->what() == kWhatPollBuffering) {
    +         onPollBuffering();
    +         return;
    ++    } else if (msg->what() == kWhatSignalEOS) {
    ++        onSignalEOS(msg);
    ++        return;
    +     }
    + 
    +     CHECK_EQ(msg->what(), (int)kWhatNotify);
    +@@ -517,16 +584,10 @@ void NuPlayer::RTSPSource::onMessageReceived(const sp<AMessage> &msg) {
    +                 }
    + 
    +                 if (err != OK) {
    +-                    sp<AnotherPacketSource> source = getSource(false /* audio */);
    +-                    if (source != NULL) {
    +-                        source->signalEOS(err);
    +-                    }
    +-
    +-                    source = getSource(true /* audio */);
    +-                    if (source != NULL) {
    +-                        source->signalEOS(err);
    +-                    }
    ++                    signalSourceEOS(err);
    +                 }
     +
    -+void OMXNodeInstance::setGraphicBufferSource(
    -+        const sp<GraphicBufferSource>& bufferSource) {
    -+    Mutex::Autolock autoLock(mGraphicBufferSourceLock);
    -+    CLOG_INTERNAL(setGraphicBufferSource, "%p", bufferSource.get());
    -+    mGraphicBufferSource = bufferSource;
    -+}
    ++                postSourceEOSIfNecessary();
    +                 break;
    +             }
    + 
    +@@ -554,6 +615,7 @@ void NuPlayer::RTSPSource::onMessageReceived(const sp<AMessage> &msg) {
    + 
    +                 source->queueAccessUnit(accessUnit);
    +             }
    ++            postSourceEOSIfNecessary();
    +             break;
    +         }
    + 
    +@@ -564,17 +626,7 @@ void NuPlayer::RTSPSource::onMessageReceived(const sp<AMessage> &msg) {
    +             CHECK_NE(finalResult, (status_t)OK);
    + 
    +             if (mTSParser != NULL) {
    +-                sp<AnotherPacketSource> source = getSource(false /* audio */);
    +-                if (source != NULL) {
    +-                    source->signalEOS(finalResult);
    +-                }
    +-
    +-                source = getSource(true /* audio */);
    +-                if (source != NULL) {
    +-                    source->signalEOS(finalResult);
    +-                }
    +-
    +-                return;
    ++                signalSourceEOS(finalResult);
    +             }
    + 
    +             size_t trackIndex;
    +diff --git a/media/libmediaplayerservice/nuplayer/RTSPSource.h b/media/libmediaplayerservice/nuplayer/RTSPSource.h
    +index a6a7644..c7834ef 100644
    +--- a/media/libmediaplayerservice/nuplayer/RTSPSource.h
    ++++ b/media/libmediaplayerservice/nuplayer/RTSPSource.h
    +@@ -64,6 +64,7 @@ private:
    +         kWhatDisconnect      = 'disc',
    +         kWhatPerformSeek     = 'seek',
    +         kWhatPollBuffering   = 'poll',
    ++        kWhatSignalEOS       = 'eos ',
    +     };
    + 
    +     enum State {
    +@@ -106,6 +107,7 @@ private:
    +     Mutex mBufferingLock;
    +     bool mBuffering;
    +     bool mInPreparationPhase;
    ++    bool mEOSPending;
    + 
    +     sp<ALooper> mLooper;
    +     sp<MyHandler> mHandler;
    +@@ -133,7 +135,12 @@ private:
    + 
    +     void performSeek(int64_t seekTimeUs);
    +     void schedulePollBuffering();
    +-    void checkBuffering(bool *prepared, bool *underflow, bool *overflow, bool *startServer);
    ++    void checkBuffering(
    ++            bool *prepared,
    ++            bool *underflow,
    ++            bool *overflow,
    ++            bool *startServer,
    ++            bool *finished);
    +     void onPollBuffering();
    + 
    +     bool haveSufficientDataOnAllTracks();
    +@@ -144,6 +151,13 @@ private:
    +     bool stopBufferingIfNecessary();
    +     void finishSeek(status_t err);
    + 
    ++    void postSourceEOSIfNecessary();
    ++    void signalSourceEOS(status_t result);
    ++    void onSignalEOS(const sp<AMessage> &msg);
     +
    -+OMX *OMXNodeInstance::owner() {
    -+    return mOwner;
    -+}
    ++    bool sourceNearEOS(bool audio);
    ++    bool sourceReachedEOS(bool audio);
     +
    -+sp<IOMXObserver> OMXNodeInstance::observer() {
    -+    return mObserver;
    -+}
    -+
    -+OMX::node_id OMXNodeInstance::nodeID() {
    -+    return mNodeID;
    -+}
    -+
    -+status_t OMXNodeInstance::freeNode(OMXMaster *master) {
    -+    CLOG_LIFE(freeNode, "handle=%p", mHandle);
    -+    static int32_t kMaxNumIterations = 10;
    -+
    -+    // exit if we have already freed the node
    -+    if (mHandle == NULL) {
    -+        return OK;
    -+    }
    +     DISALLOW_EVIL_CONSTRUCTORS(RTSPSource);
    + };
    + 
    +diff --git a/media/libstagefright/ACodec.cpp b/media/libstagefright/ACodec.cpp
    +index 37fd5a5..706ba4e 100644
    +--- a/media/libstagefright/ACodec.cpp
    ++++ b/media/libstagefright/ACodec.cpp
    +@@ -804,13 +804,22 @@ status_t ACodec::allocateBuffersOnPort(OMX_U32 portIndex) {
    +             } else if (type == kMetadataBufferTypeNativeHandleSource) {
    +                 bufSize = sizeof(VideoNativeHandleMetadata);
    +             }
    ++#ifdef CAMCORDER_GRALLOC_SOURCE
    ++            else if (type == kMetadataBufferTypeGrallocSource) {
    ++                bufSize = sizeof(VideoGrallocMetadata);
    ++            }
    ++#endif
    + 
    +             // If using gralloc or native source input metadata buffers, allocate largest
    +             // metadata size as we prefer to generate native source metadata, but component
    +             // may require gralloc source. For camera source, allocate at least enough
    +             // size for native metadata buffers.
    +             size_t allottedSize = bufSize;
    ++#ifdef CAMCORDER_GRALLOC_SOURCE
    ++            if (portIndex == kPortIndexInput && type >= kMetadataBufferTypeGrallocSource) {
    ++#else
    +             if (portIndex == kPortIndexInput && type == kMetadataBufferTypeANWBuffer) {
    ++#endif
    +                 bufSize = max(sizeof(VideoGrallocMetadata), sizeof(VideoNativeMetadata));
    +             } else if (portIndex == kPortIndexInput && type == kMetadataBufferTypeCameraSource) {
    +                 bufSize = max(bufSize, sizeof(VideoNativeMetadata));
    +@@ -1766,6 +1775,14 @@ status_t ACodec::configureCodec(
    +             mInputMetadataType = (MetadataBufferType)storeMeta;
    +         }
    + 
    ++#ifdef CAMCORDER_GRALLOC_SOURCE
    ++        // For this specific case we could be using camera source even if storeMetaDataInBuffers
    ++        // returns Gralloc source. Pretend that we are; this will force us to use nBufferSize.
    ++        if (mInputMetadataType == kMetadataBufferTypeGrallocSource) {
    ++            mInputMetadataType = kMetadataBufferTypeCameraSource;
    ++        }
    ++#endif
     +
    -+    // Transition the node from its current state all the way down
    -+    // to "Loaded".
    -+    // This ensures that all active buffers are properly freed even
    -+    // for components that don't do this themselves on a call to
    -+    // "FreeHandle".
    -+
    -+    // The code below may trigger some more events to be dispatched
    -+    // by the OMX component - we want to ignore them as our client
    -+    // does not expect them.
    -+    mDying = true;
    -+
    -+    OMX_STATETYPE state;
    -+    CHECK_EQ(OMX_GetState(mHandle, &state), OMX_ErrorNone);
    -+    switch (state) {
    -+        case OMX_StateExecuting:
    -+        {
    -+            ALOGV("forcing Executing->Idle");
    -+            sendCommand(OMX_CommandStateSet, OMX_StateIdle);
    -+            OMX_ERRORTYPE err;
    -+            int32_t iteration = 0;
    -+            while ((err = OMX_GetState(mHandle, &state)) == OMX_ErrorNone
    -+                    && state != OMX_StateIdle
    -+                    && state != OMX_StateInvalid) {
    -+                if (++iteration > kMaxNumIterations) {
    -+                    CLOGW("failed to enter Idle state (now %s(%d), aborting.",
    -+                            asString(state), state);
    -+                    state = OMX_StateInvalid;
    -+                    break;
    +         uint32_t usageBits;
    +         if (mOMX->getParameter(
    +                 mNode, (OMX_INDEXTYPE)OMX_IndexParamConsumerUsageBits,
    +@@ -6036,6 +6053,9 @@ void ACodec::BaseState::onInputBufferFilled(const sp<AMessage> &msg) {
    +                 status_t err2 = OK;
    +                 switch (metaType) {
    +                 case kMetadataBufferTypeInvalid:
    ++#ifdef CAMCORDER_GRALLOC_SOURCE
    ++                case kMetadataBufferTypeCameraSource:
    ++#endif
    +                     break;
    + #ifndef OMX_ANDROID_COMPILE_AS_32BIT_ON_64BIT_PLATFORMS
    +                 case kMetadataBufferTypeNativeHandleSource:
    +@@ -6267,6 +6287,10 @@ bool ACodec::BaseState::onOMXFillBufferDone(
    +                 native_handle_t *handle = NULL;
    +                 VideoNativeHandleMetadata &nativeMeta =
    +                     *(VideoNativeHandleMetadata *)info->mData->data();
    ++#ifdef CAMCORDER_GRALLOC_SOURCE
    ++                VideoGrallocMetadata &grallocMeta =
    ++                    *(VideoGrallocMetadata *)info->mData->data();
    ++#endif
    +                 if (info->mData->size() >= sizeof(nativeMeta)
    +                         && nativeMeta.eType == kMetadataBufferTypeNativeHandleSource) {
    + #ifdef OMX_ANDROID_COMPILE_AS_32BIT_ON_64BIT_PLATFORMS
    +@@ -6276,6 +6300,12 @@ bool ACodec::BaseState::onOMXFillBufferDone(
    +                     handle = (native_handle_t *)nativeMeta.pHandle;
    + #endif
    +                 }
    ++#ifdef CAMCORDER_GRALLOC_SOURCE
    ++                else if (info->mData->size() >= sizeof(grallocMeta)
    ++                        && grallocMeta.eType == kMetadataBufferTypeGrallocSource) {
    ++                    handle = (native_handle_t *)(uintptr_t)grallocMeta.pHandle;
     +                }
    ++#endif
    +                 info->mData->meta()->setPointer("handle", handle);
    +                 info->mData->meta()->setInt32("rangeOffset", rangeOffset);
    +                 info->mData->meta()->setInt32("rangeLength", rangeLength);
    +@@ -6968,10 +6998,12 @@ void ACodec::LoadedState::onCreateInputSurface(
    +         err = mCodec->mOMX->createInputSurface(
    +                 mCodec->mNode, kPortIndexInput, dataSpace, &bufferProducer,
    +                 &mCodec->mInputMetadataType);
    ++#ifndef CAMCORDER_GRALLOC_SOURCE
    +         // framework uses ANW buffers internally instead of gralloc handles
    +         if (mCodec->mInputMetadataType == kMetadataBufferTypeGrallocSource) {
    +             mCodec->mInputMetadataType = kMetadataBufferTypeANWBuffer;
    +         }
    ++#endif
    +     }
    + 
    +     if (err == OK) {
    +@@ -7014,10 +7046,12 @@ void ACodec::LoadedState::onSetInputSurface(
    +         err = mCodec->mOMX->setInputSurface(
    +                 mCodec->mNode, kPortIndexInput, surface->getBufferConsumer(),
    +                 &mCodec->mInputMetadataType);
    ++#ifndef CAMCORDER_GRALLOC_SOURCE
    +         // framework uses ANW buffers internally instead of gralloc handles
    +         if (mCodec->mInputMetadataType == kMetadataBufferTypeGrallocSource) {
    +             mCodec->mInputMetadataType = kMetadataBufferTypeANWBuffer;
    +         }
    ++#endif
    +     }
    + 
    +     if (err == OK) {
    +diff --git a/media/libstagefright/Android.mk b/media/libstagefright/Android.mk
    +index 3848502..c06f6a4 100644
    +--- a/media/libstagefright/Android.mk
    ++++ b/media/libstagefright/Android.mk
    +@@ -124,6 +124,10 @@ LOCAL_SHARED_LIBRARIES += \
    +         libdl \
    +         libRScpp \
    + 
    ++ifeq ($(TARGET_HAS_LEGACY_CAMERA_HAL1),true)
    ++LOCAL_CFLAGS += -DCAMCORDER_GRALLOC_SOURCE
    ++endif
     +
    -+                usleep(100000);
    -+            }
    -+            CHECK_EQ(err, OMX_ErrorNone);
    + LOCAL_CFLAGS += -Wno-multichar -Werror -Wno-error=deprecated-declarations -Wall
    + 
    + # enable experiments only in userdebug and eng builds
    +diff --git a/media/libstagefright/CameraSource.cpp b/media/libstagefright/CameraSource.cpp
    +index e087249..c9f60ec 100644
    +--- a/media/libstagefright/CameraSource.cpp
    ++++ b/media/libstagefright/CameraSource.cpp
    +@@ -1117,6 +1117,9 @@ void CameraSource::releaseRecordingFrameHandle(native_handle_t* handle) {
    +         int64_t token = IPCThreadState::self()->clearCallingIdentity();
    +         mCamera->releaseRecordingFrameHandle(handle);
    +         IPCThreadState::self()->restoreCallingIdentity(token);
    ++    } else {
    ++        native_handle_close(handle);
    ++        native_handle_delete(handle);
    +     }
    + }
    + 
    +@@ -1247,6 +1250,10 @@ void CameraSource::processBufferQueueFrame(BufferItem& buffer) {
    + MetadataBufferType CameraSource::metaDataStoredInVideoBuffers() const {
    +     ALOGV("metaDataStoredInVideoBuffers");
    + 
    ++#ifdef CAMCORDER_GRALLOC_SOURCE
    ++    return kMetadataBufferTypeGrallocSource;
    ++#endif
     +
    -+            if (state == OMX_StateInvalid) {
    -+                break;
    +     // Output buffers will contain metadata if camera sends us buffer in metadata mode or via
    +     // buffer queue.
    +     switch (mVideoBufferMode) {
    +diff --git a/media/libstagefright/MPEG4Extractor.cpp b/media/libstagefright/MPEG4Extractor.cpp
    +index 70a294c..f42fbcf 100644
    +--- a/media/libstagefright/MPEG4Extractor.cpp
    ++++ b/media/libstagefright/MPEG4Extractor.cpp
    +@@ -374,7 +374,6 @@ MPEG4Extractor::MPEG4Extractor(const sp<DataSource> &source)
    +       mMdatFound(false),
    +       mDataSource(source),
    +       mInitCheck(NO_INIT),
    +-      mHasVideo(false),
    +       mHeaderTimescale(0),
    +       mIsQT(false),
    +       mFirstTrack(NULL),
    +@@ -479,7 +478,8 @@ sp<MetaData> MPEG4Extractor::getTrackMetaData(
    +             } else {
    +                 uint32_t sampleIndex;
    +                 uint32_t sampleTime;
    +-                if (track->sampleTable->findThumbnailSample(&sampleIndex) == OK
    ++                if (track->timescale != 0 &&
    ++                        track->sampleTable->findThumbnailSample(&sampleIndex) == OK
    +                         && track->sampleTable->getMetaDataForSample(
    +                             sampleIndex, NULL /* offset */, NULL /* size */,
    +                             &sampleTime) == OK) {
    +@@ -545,11 +545,13 @@ status_t MPEG4Extractor::readMetaData() {
    +     }
    + 
    +     if (mInitCheck == OK) {
    +-        if (mHasVideo) {
    ++        if (findTrackByMimePrefix("video/") != NULL) {
    +             mFileMetaData->setCString(
    +                     kKeyMIMEType, MEDIA_MIMETYPE_CONTAINER_MPEG4);
    +-        } else {
    ++        } else if (findTrackByMimePrefix("audio/") != NULL) {
    +             mFileMetaData->setCString(kKeyMIMEType, "audio/mp4");
    ++        } else {
    ++            mFileMetaData->setCString(kKeyMIMEType, "application/octet-stream");
    +         }
    +     } else {
    +         mInitCheck = err;
    +@@ -929,6 +931,10 @@ status_t MPEG4Extractor::parseChunk(off64_t *offset, int depth) {
    +         case FOURCC('e', 'd', 't', 's'):
    +         case FOURCC('w', 'a', 'v', 'e'):
    +         {
    ++            if (chunk_type == FOURCC('m', 'o', 'o', 'v') && depth != 0) {
    ++                ALOGE("moov: depth %d", depth);
    ++                return ERROR_MALFORMED;
     +            }
    -+
    -+            // fall through
    -+        }
    -+
    -+        case OMX_StateIdle:
    -+        {
    -+            ALOGV("forcing Idle->Loaded");
    -+            sendCommand(OMX_CommandStateSet, OMX_StateLoaded);
    -+
    -+            freeActiveBuffers();
    -+
    -+            OMX_ERRORTYPE err;
    -+            int32_t iteration = 0;
    -+            while ((err = OMX_GetState(mHandle, &state)) == OMX_ErrorNone
    -+                    && state != OMX_StateLoaded
    -+                    && state != OMX_StateInvalid) {
    -+                if (++iteration > kMaxNumIterations) {
    -+                    CLOGW("failed to enter Loaded state (now %s(%d), aborting.",
    -+                            asString(state), state);
    -+                    state = OMX_StateInvalid;
    -+                    break;
    +             if (chunk_type == FOURCC('m', 'o', 'o', 'f') && !mMoofFound) {
    +                 // store the offset of the first segment
    +                 mMoofFound = true;
    +@@ -957,6 +963,10 @@ status_t MPEG4Extractor::parseChunk(off64_t *offset, int depth) {
    + 
    +             bool isTrack = false;
    +             if (chunk_type == FOURCC('t', 'r', 'a', 'k')) {
    ++                if (depth != 1) {
    ++                    ALOGE("trak: depth %d", depth);
    ++                    return ERROR_MALFORMED;
     +                }
    -+
    -+                ALOGV("waiting for Loaded state...");
    -+                usleep(100000);
    +                 isTrack = true;
    + 
    +                 Track *track = new Track;
    +@@ -980,6 +990,10 @@ status_t MPEG4Extractor::parseChunk(off64_t *offset, int depth) {
    +             while (*offset < stop_offset) {
    +                 status_t err = parseChunk(offset, depth + 1);
    +                 if (err != OK) {
    ++                    if (isTrack) {
    ++                        mLastTrack->skipTrack = true;
    ++                        break;
    ++                    }
    +                     return err;
    +                 }
    +             }
    +@@ -1325,10 +1339,6 @@ status_t MPEG4Extractor::parseChunk(off64_t *offset, int depth) {
    + 
    +         case FOURCC('s', 't', 's', 'd'):
    +         {
    +-            if (chunk_data_size < 8) {
    +-                return ERROR_MALFORMED;
    +-            }
    +-
    +             uint8_t buffer[8];
    +             if (chunk_data_size < (off64_t)sizeof(buffer)) {
    +                 return ERROR_MALFORMED;
    +@@ -1481,8 +1491,6 @@ status_t MPEG4Extractor::parseChunk(off64_t *offset, int depth) {
    +         case FOURCC('h', 'v', 'c', '1'):
    +         case FOURCC('h', 'e', 'v', '1'):
    +         {
    +-            mHasVideo = true;
    +-
    +             uint8_t buffer[78];
    +             if (chunk_data_size < (ssize_t)sizeof(buffer)) {
    +                 // Basic VideoSampleEntry size.
    +@@ -1825,6 +1833,9 @@ status_t MPEG4Extractor::parseChunk(off64_t *offset, int depth) {
    +         case FOURCC('b', 't', 'r', 't'):
    +         {
    +             *offset += chunk_size;
    ++            if (mLastTrack == NULL) {
    ++                return ERROR_MALFORMED;
     +            }
    -+            CHECK_EQ(err, OMX_ErrorNone);
    -+
    -+            // fall through
    -+        }
    -+
    -+        case OMX_StateLoaded:
    -+        case OMX_StateInvalid:
    + 
    +             uint8_t buffer[12];
    +             if (chunk_data_size != sizeof(buffer)) {
    +@@ -1994,6 +2005,10 @@ status_t MPEG4Extractor::parseChunk(off64_t *offset, int depth) {
    +         {
    +             *offset += chunk_size;
    + 
    ++            if (depth != 1) {
    ++                ALOGE("mvhd: depth %d", depth);
    ++                return ERROR_MALFORMED;
    ++            }
    +             if (chunk_data_size < 32) {
    +                 return ERROR_MALFORMED;
    +             }
    +@@ -4121,11 +4136,13 @@ status_t MPEG4Source::parseTrackFragmentRun(off64_t offset, off64_t size) {
    +     if (!mDataSource->getUInt32(offset, &flags)) {
    +         return ERROR_MALFORMED;
    +     }
    +-    ALOGV("fragment run flags: %08x", flags);
    +-
    +-    if (flags & 0xff000000) {
    +-        return -EINVAL;
    +-    }
    ++    // |version| only affects SampleCompositionTimeOffset field.
    ++    // If version == 0, SampleCompositionTimeOffset is uint32_t;
    ++    // Otherwise, SampleCompositionTimeOffset is int32_t.
    ++    // Sample.compositionOffset is defined as int32_t.
    ++    uint8_t version = flags >> 24;
    ++    flags &= 0xffffff;
    ++    ALOGV("fragment run version: 0x%02x, flags: 0x%06x", version, flags);
    + 
    +     if ((flags & kFirstSampleFlagsPresent) && (flags & kSampleFlagsPresent)) {
    +         // These two shall not be used together.
    +diff --git a/media/libstagefright/MPEG4Writer.cpp b/media/libstagefright/MPEG4Writer.cpp
    +index 4681abd..5e96c2b 100644
    +--- a/media/libstagefright/MPEG4Writer.cpp
    ++++ b/media/libstagefright/MPEG4Writer.cpp
    +@@ -272,6 +272,7 @@ private:
    +     bool mIsHevc;
    +     bool mIsAudio;
    +     bool mIsMPEG4;
    ++    bool mIsMalformed;
    +     int32_t mTrackId;
    +     int64_t mTrackDurationUs;
    +     int64_t mMaxChunkDurationUs;
    +@@ -1536,6 +1537,7 @@ MPEG4Writer::Track::Track(
    +       mPaused(false),
    +       mResumed(false),
    +       mStarted(false),
    ++      mIsMalformed(false),
    +       mTrackId(trackId),
    +       mTrackDurationUs(0),
    +       mEstimatedTrackSizeBytes(0),
    +@@ -2479,12 +2481,16 @@ status_t MPEG4Writer::Track::threadEntry() {
    +             ALOGW("Recorded file size exceeds limit %" PRId64 "bytes",
    +                     mOwner->mMaxFileSizeLimitBytes);
    +             mOwner->notify(MEDIA_RECORDER_EVENT_INFO, MEDIA_RECORDER_INFO_MAX_FILESIZE_REACHED, 0);
    ++            copy->release();
    ++            mSource->stop();
    +             break;
    +         }
    +         if (mOwner->exceedsFileDurationLimit()) {
    +             ALOGW("Recorded file duration exceeds limit %" PRId64 "microseconds",
    +                     mOwner->mMaxFileDurationLimitUs);
    +             mOwner->notify(MEDIA_RECORDER_EVENT_INFO, MEDIA_RECORDER_INFO_MAX_DURATION_REACHED, 0);
    ++            copy->release();
    ++            mSource->stop();
    +             break;
    +         }
    + 
    +@@ -2505,13 +2511,17 @@ status_t MPEG4Writer::Track::threadEntry() {
    +             int64_t durExcludingEarlierPausesUs = timestampUs - previousPausedDurationUs;
    +             if (WARN_UNLESS(durExcludingEarlierPausesUs >= 0ll, "for %s track", trackName)) {
    +                 copy->release();
    +-                return ERROR_MALFORMED;
    ++                mSource->stop();
    ++                mIsMalformed = true;
    ++                break;
    +             }
    + 
    +             int64_t pausedDurationUs = durExcludingEarlierPausesUs - mTrackDurationUs;
    +             if (WARN_UNLESS(pausedDurationUs >= lastDurationUs, "for %s track", trackName)) {
    +                 copy->release();
    +-                return ERROR_MALFORMED;
    ++                mSource->stop();
    ++                mIsMalformed = true;
    ++                break;
    +             }
    + 
    +             previousPausedDurationUs += pausedDurationUs - lastDurationUs;
    +@@ -2521,7 +2531,9 @@ status_t MPEG4Writer::Track::threadEntry() {
    +         timestampUs -= previousPausedDurationUs;
    +         if (WARN_UNLESS(timestampUs >= 0ll, "for %s track", trackName)) {
    +             copy->release();
    +-            return ERROR_MALFORMED;
    ++            mSource->stop();
    ++            mIsMalformed = true;
     +            break;
    -+
    -+        default:
    -+            LOG_ALWAYS_FATAL("unknown state %s(%#x).", asString(state), state);
    +         }
    + 
    +         if (!mIsAudio) {
    +@@ -2548,7 +2560,9 @@ status_t MPEG4Writer::Track::threadEntry() {
    +                     timestampUs + kMaxCttsOffsetTimeUs - decodingTimeUs;
    +             if (WARN_UNLESS(cttsOffsetTimeUs >= 0ll, "for %s track", trackName)) {
    +                 copy->release();
    +-                return ERROR_MALFORMED;
    ++                mSource->stop();
    ++                mIsMalformed = true;
    ++                break;
    +             }
    + 
    +             timestampUs = decodingTimeUs;
    +@@ -2560,7 +2574,9 @@ status_t MPEG4Writer::Track::threadEntry() {
    +                     (cttsOffsetTimeUs * mTimeScale + 500000LL) / 1000000LL;
    +             if (WARN_UNLESS(currCttsOffsetTimeTicks <= 0x0FFFFFFFFLL, "for %s track", trackName)) {
    +                 copy->release();
    +-                return ERROR_MALFORMED;
    ++                mSource->stop();
    ++                mIsMalformed = true;
    ++                break;
    +             }
    + 
    +             if (mStszTableEntries->count() == 0) {
    +@@ -2602,7 +2618,9 @@ status_t MPEG4Writer::Track::threadEntry() {
    + 
    +         if (WARN_UNLESS(timestampUs >= 0ll, "for %s track", trackName)) {
    +             copy->release();
    +-            return ERROR_MALFORMED;
    ++            mSource->stop();
    ++            mIsMalformed = true;
     +            break;
    +         }
    + 
    +         ALOGV("%s media time stamp: %" PRId64 " and previous paused duration %" PRId64,
    +@@ -2624,7 +2642,8 @@ status_t MPEG4Writer::Track::threadEntry() {
    +                     (long long)timestampUs, (long long)lastTimestampUs, trackName);
    +             copy->release();
    +             mSource->stop();
    +-            return UNKNOWN_ERROR;
    ++            mIsMalformed = true;
    ++            break;
    +         }
    + 
    +         // if the duration is different for this sample, see if it is close enough to the previous
    +@@ -2780,6 +2799,10 @@ status_t MPEG4Writer::Track::threadEntry() {
    + }
    + 
    + bool MPEG4Writer::Track::isTrackMalFormed() const {
    ++    if (mIsMalformed) {
    ++        return true;
    ++    }
    ++
    +     if (mStszTableEntries->count() == 0) {                      // no samples written
    +         ALOGE("The number of recorded samples is 0");
    +         return true;
    +diff --git a/media/libstagefright/MediaCodec.cpp b/media/libstagefright/MediaCodec.cpp
    +index ff5c4d4..e476424 100644
    +--- a/media/libstagefright/MediaCodec.cpp
    ++++ b/media/libstagefright/MediaCodec.cpp
    +@@ -2160,14 +2160,19 @@ void MediaCodec::onMessageReceived(const sp<AMessage> &msg) {
    +             CHECK(msg->findPointer("buffers", (void **)&dstBuffers));
    + 
    +             dstBuffers->clear();
    +-            const Vector<BufferInfo> &srcBuffers = mPortBuffers[portIndex];
    +-
    +-            for (size_t i = 0; i < srcBuffers.size(); ++i) {
    +-                const BufferInfo &info = srcBuffers.itemAt(i);
    +-
    +-                dstBuffers->push_back(
    +-                        (portIndex == kPortIndexInput && mCrypto != NULL)
    +-                                ? info.mEncryptedData : info.mData);
    ++            // If we're using input surface (either non-persistent created by
    ++            // createInputSurface(), or persistent set by setInputSurface()),
    ++            // give the client an empty input buffers array.
    ++            if (portIndex != kPortIndexInput || !mHaveInputSurface) {
    ++                const Vector<BufferInfo> &srcBuffers = mPortBuffers[portIndex];
    ++
    ++                for (size_t i = 0; i < srcBuffers.size(); ++i) {
    ++                    const BufferInfo &info = srcBuffers.itemAt(i);
    ++
    ++                    dstBuffers->push_back(
    ++                            (portIndex == kPortIndexInput && mCrypto != NULL)
    ++                                    ? info.mEncryptedData : info.mData);
    ++                }
    +             }
    + 
    +             (new AMessage)->postReply(replyID);
    +diff --git a/media/libstagefright/MediaCodecSource.cpp b/media/libstagefright/MediaCodecSource.cpp
    +index 33d624e..ea5ef06 100644
    +--- a/media/libstagefright/MediaCodecSource.cpp
    ++++ b/media/libstagefright/MediaCodecSource.cpp
    +@@ -859,6 +859,7 @@ void MediaCodecSource::onMessageReceived(const sp<AMessage> &msg) {
    +             }
    + 
    +             MediaBuffer *mbuf = new MediaBuffer(outbuf->size());
    ++            mbuf->setObserver(this);
    +             mbuf->add_ref();
    + 
    +             if (!(flags & MediaCodec::BUFFER_FLAG_CODECCONFIG)) {
    +@@ -911,7 +912,6 @@ void MediaCodecSource::onMessageReceived(const sp<AMessage> &msg) {
    +                 mbuf->meta_data()->setInt32(kKeyIsSyncFrame, true);
    +             }
    +             memcpy(mbuf->data(), outbuf->data(), outbuf->size());
    +-            mbuf->setObserver(this);
    + 
    +             {
    +                 Mutexed<Output>::Locked output(mOutput);
    +diff --git a/media/libstagefright/NuMediaExtractor.cpp b/media/libstagefright/NuMediaExtractor.cpp
    +index a669dca..276d731 100644
    +--- a/media/libstagefright/NuMediaExtractor.cpp
    ++++ b/media/libstagefright/NuMediaExtractor.cpp
    +@@ -305,7 +305,10 @@ status_t NuMediaExtractor::selectTrack(size_t index) {
    + 
    +     sp<IMediaSource> source = mImpl->getTrack(index);
    + 
    +-    CHECK_EQ((status_t)OK, source->start());
    ++    status_t ret = source->start();
    ++    if (ret != OK) {
    ++        return ret;
     +    }
    -+
    -+    ALOGV("[%x:%s] calling destroyComponentInstance", mNodeID, mName);
    -+    OMX_ERRORTYPE err = master->destroyComponentInstance(
    -+            static_cast<OMX_COMPONENTTYPE *>(mHandle));
    -+
    -+    mHandle = NULL;
    -+    CLOG_IF_ERROR(freeNode, err, "");
    -+    free(mName);
    -+    mName = NULL;
    -+
    -+    mOwner->invalidateNodeID(mNodeID);
    -+    mNodeID = 0;
    -+
    -+    ALOGV("OMXNodeInstance going away.");
    -+    delete this;
    -+
    -+    return StatusFromOMXError(err);
    -+}
    -+
    -+status_t OMXNodeInstance::sendCommand(
    -+        OMX_COMMANDTYPE cmd, OMX_S32 param) {
    -+    if (cmd == OMX_CommandStateSet) {
    -+        // There are no configurations past first StateSet command.
    -+        mSailed = true;
    -+    }
    -+    const sp<GraphicBufferSource> bufferSource(getGraphicBufferSource());
    -+    if (bufferSource != NULL && cmd == OMX_CommandStateSet) {
    -+        if (param == OMX_StateIdle) {
    -+            // Initiating transition from Executing -> Idle
    -+            // ACodec is waiting for all buffers to be returned, do NOT
    -+            // submit any more buffers to the codec.
    -+            bufferSource->omxIdle();
    -+        } else if (param == OMX_StateLoaded) {
    -+            // Initiating transition from Idle/Executing -> Loaded
    -+            // Buffers are about to be freed.
    -+            bufferSource->omxLoaded();
    -+            setGraphicBufferSource(NULL);
    -+        }
    -+
    -+        // fall through
    -+    }
    -+
    -+    Mutex::Autolock autoLock(mLock);
    -+
    -+    // bump internal-state debug level for 2 input and output frames past a command
    -+    {
    -+        Mutex::Autolock _l(mDebugLock);
    -+        bumpDebugLevel_l(2 /* numInputBuffers */, 2 /* numOutputBuffers */);
    + 
    +     mSelectedTracks.push();
    +     TrackInfo *info = &mSelectedTracks.editItemAt(mSelectedTracks.size() - 1);
    +diff --git a/media/libstagefright/OMXClient.cpp b/media/libstagefright/OMXClient.cpp
    +index e994069..e40dbcf 100644
    +--- a/media/libstagefright/OMXClient.cpp
    ++++ b/media/libstagefright/OMXClient.cpp
    +@@ -303,6 +303,12 @@ status_t MuxOMX::allocateNode(
    + status_t MuxOMX::freeNode(node_id node) {
    +     Mutex::Autolock autoLock(mLock);
    + 
    ++    // exit if we have already freed the node
    ++    if (mNodeLocation.indexOfKey(node) < 0) {
    ++        ALOGD("MuxOMX::freeNode: node %d seems to be released already --- ignoring.", node);
    ++        return OK;
     +    }
     +
    -+    const char *paramString =
    -+        cmd == OMX_CommandStateSet ? asString((OMX_STATETYPE)param) : portString(param);
    -+    CLOG_STATE(sendCommand, "%s(%d), %s(%d)", asString(cmd), cmd, paramString, param);
    -+    OMX_ERRORTYPE err = OMX_SendCommand(mHandle, cmd, param, NULL);
    -+    CLOG_IF_ERROR(sendCommand, err, "%s(%d), %s(%d)", asString(cmd), cmd, paramString, param);
    -+    return StatusFromOMXError(err);
    -+}
    -+
    -+bool OMXNodeInstance::isProhibitedIndex_l(OMX_INDEXTYPE index) {
    -+    // these extensions can only be used from OMXNodeInstance, not by clients directly.
    -+    static const char *restricted_extensions[] = {
    -+        "OMX.google.android.index.storeMetaDataInBuffers",
    -+        "OMX.google.android.index.storeANWBufferInMetadata",
    -+        "OMX.google.android.index.prepareForAdaptivePlayback",
    -+        "OMX.google.android.index.configureVideoTunnelMode",
    -+        "OMX.google.android.index.useAndroidNativeBuffer2",
    -+        "OMX.google.android.index.useAndroidNativeBuffer",
    -+        "OMX.google.android.index.enableAndroidNativeBuffers",
    -+        "OMX.google.android.index.allocateNativeHandle",
    -+        "OMX.google.android.index.getAndroidNativeBufferUsage",
    -+    };
    -+
    -+    if ((index > OMX_IndexComponentStartUnused && index <= OMX_IndexParamStandardComponentRole)
    -+            || (index > OMX_IndexPortStartUnused && index <= OMX_IndexParamCompBufferSupplier)
    -+            || (index > OMX_IndexAudioStartUnused && index <= OMX_IndexConfigAudioChannelVolume)
    -+            || (index > OMX_IndexVideoStartUnused && index <= OMX_IndexConfigVideoNalSize)
    -+            || (index > OMX_IndexCommonStartUnused
    -+                    && index <= OMX_IndexConfigCommonTransitionEffect)
    -+            || (index > (OMX_INDEXTYPE)OMX_IndexExtAudioStartUnused
    -+                    && index <= (OMX_INDEXTYPE)OMX_IndexParamAudioProfileQuerySupported)
    -+            || (index > (OMX_INDEXTYPE)OMX_IndexExtVideoStartUnused
    -+                    && index <= (OMX_INDEXTYPE)OMX_IndexConfigAndroidIntraRefresh)
    -+            || (index > (OMX_INDEXTYPE)OMX_IndexExtOtherStartUnused
    -+                    && index <= (OMX_INDEXTYPE)OMX_IndexParamConsumerUsageBits)) {
    -+        return false;
    +     status_t err = getOMX_l(node)->freeNode(node);
    + 
    +     if (err != OK) {
    +diff --git a/media/libstagefright/StagefrightMetadataRetriever.cpp b/media/libstagefright/StagefrightMetadataRetriever.cpp
    +index d2ba02e..be5067d 100644
    +--- a/media/libstagefright/StagefrightMetadataRetriever.cpp
    ++++ b/media/libstagefright/StagefrightMetadataRetriever.cpp
    +@@ -158,11 +158,14 @@ static VideoFrame *extractVideoFrame(
    +     // TODO: Use Flexible color instead
    +     videoFormat->setInt32("color-format", OMX_COLOR_FormatYUV420Planar);
    + 
    +-    // For the thumbnail extraction case, try to allocate single buffer
    +-    // in both input and output ports. NOTE: This request may fail if
    +-    // component requires more than that for decoding.
    +-    videoFormat->setInt32("android._num-input-buffers", 1);
    +-    videoFormat->setInt32("android._num-output-buffers", 1);
    ++    // For the thumbnail extraction case, try to allocate single buffer in both
    ++    // input and output ports, if seeking to a sync frame. NOTE: This request may
    ++    // fail if component requires more than that for decoding.
    ++    bool isSeekingClosest = (seekMode == MediaSource::ReadOptions::SEEK_CLOSEST);
    ++    if (!isSeekingClosest) {
    ++        videoFormat->setInt32("android._num-input-buffers", 1);
    ++        videoFormat->setInt32("android._num-output-buffers", 1);
     +    }
    -+
    -+    if (!mQueriedProhibitedExtensions) {
    -+        for (size_t i = 0; i < NELEM(restricted_extensions); ++i) {
    -+            OMX_INDEXTYPE ext;
    -+            if (OMX_GetExtensionIndex(mHandle, (OMX_STRING)restricted_extensions[i], &ext) == OMX_ErrorNone) {
    -+                mProhibitedExtensions.add(ext);
    + 
    +     status_t err;
    +     sp<ALooper> looper = new ALooper;
    +@@ -254,6 +257,9 @@ static VideoFrame *extractVideoFrame(
    +     bool isAvcOrHevc = !strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_AVC)
    +             || !strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_HEVC);
    + 
    ++    bool firstSample = true;
    ++    int64_t targetTimeUs = -1ll;
    ++
    +     do {
    +         size_t inputIndex = -1;
    +         int64_t ptsUs = 0ll;
    +@@ -280,6 +286,11 @@ static VideoFrame *extractVideoFrame(
    +                 haveMoreInputs = false;
    +                 break;
    +             }
    ++            if (firstSample && isSeekingClosest) {
    ++                mediaBuffer->meta_data()->findInt64(kKeyTargetTime, &targetTimeUs);
    ++                ALOGV("Seeking closest: targetTimeUs=%lld", (long long)targetTimeUs);
     +            }
    -+        }
    -+        mQueriedProhibitedExtensions = true;
    -+    }
    -+
    -+    return mProhibitedExtensions.indexOf(index) >= 0;
    -+}
    -+
    -+status_t OMXNodeInstance::getParameter(
    -+        OMX_INDEXTYPE index, void *params, size_t /* size */) {
    -+    Mutex::Autolock autoLock(mLock);
    -+
    -+    if (isProhibitedIndex_l(index)) {
    -+        android_errorWriteLog(0x534e4554, "29422020");
    -+        return BAD_INDEX;
    -+    }
    -+
    -+    OMX_ERRORTYPE err = OMX_GetParameter(mHandle, index, params);
    -+    OMX_INDEXEXTTYPE extIndex = (OMX_INDEXEXTTYPE)index;
    -+    // some errors are expected for getParameter
    -+    if (err != OMX_ErrorNoMore) {
    -+        CLOG_IF_ERROR(getParameter, err, "%s(%#x)", asString(extIndex), index);
    -+    }
    -+    return StatusFromOMXError(err);
    -+}
    -+
    -+status_t OMXNodeInstance::setParameter(
    -+        OMX_INDEXTYPE index, const void *params, size_t size) {
    -+    Mutex::Autolock autoLock(mLock);
    -+    OMX_INDEXEXTTYPE extIndex = (OMX_INDEXEXTTYPE)index;
    -+    CLOG_CONFIG(setParameter, "%s(%#x), %zu@%p)", asString(extIndex), index, size, params);
    -+
    -+    if (isProhibitedIndex_l(index)) {
    -+        android_errorWriteLog(0x534e4554, "29422020");
    -+        return BAD_INDEX;
    -+    }
    -+
    -+    OMX_ERRORTYPE err = OMX_SetParameter(
    -+            mHandle, index, const_cast<void *>(params));
    -+    CLOG_IF_ERROR(setParameter, err, "%s(%#x)", asString(extIndex), index);
    -+    return StatusFromOMXError(err);
    -+}
    -+
    -+status_t OMXNodeInstance::getConfig(
    -+        OMX_INDEXTYPE index, void *params, size_t /* size */) {
    -+    Mutex::Autolock autoLock(mLock);
    -+
    -+    if (isProhibitedIndex_l(index)) {
    -+        android_errorWriteLog(0x534e4554, "29422020");
    -+        return BAD_INDEX;
    -+    }
    -+
    -+    OMX_ERRORTYPE err = OMX_GetConfig(mHandle, index, params);
    -+    OMX_INDEXEXTTYPE extIndex = (OMX_INDEXEXTTYPE)index;
    -+    // some errors are expected for getConfig
    -+    if (err != OMX_ErrorNoMore) {
    -+        CLOG_IF_ERROR(getConfig, err, "%s(%#x)", asString(extIndex), index);
    -+    }
    -+    return StatusFromOMXError(err);
    -+}
    -+
    -+status_t OMXNodeInstance::setConfig(
    -+        OMX_INDEXTYPE index, const void *params, size_t size) {
    -+    Mutex::Autolock autoLock(mLock);
    -+    OMX_INDEXEXTTYPE extIndex = (OMX_INDEXEXTTYPE)index;
    -+    CLOG_CONFIG(setConfig, "%s(%#x), %zu@%p)", asString(extIndex), index, size, params);
    -+
    -+    if (isProhibitedIndex_l(index)) {
    -+        android_errorWriteLog(0x534e4554, "29422020");
    -+        return BAD_INDEX;
    -+    }
    -+
    -+    OMX_ERRORTYPE err = OMX_SetConfig(
    -+            mHandle, index, const_cast<void *>(params));
    -+    CLOG_IF_ERROR(setConfig, err, "%s(%#x)", asString(extIndex), index);
    -+    return StatusFromOMXError(err);
    -+}
    -+
    -+status_t OMXNodeInstance::getState(OMX_STATETYPE* state) {
    -+    Mutex::Autolock autoLock(mLock);
    -+
    -+    OMX_ERRORTYPE err = OMX_GetState(mHandle, state);
    -+    CLOG_IF_ERROR(getState, err, "");
    -+    return StatusFromOMXError(err);
    -+}
    -+
    -+status_t OMXNodeInstance::enableNativeBuffers(
    -+        OMX_U32 portIndex, OMX_BOOL graphic, OMX_BOOL enable) {
    -+    if (portIndex >= NELEM(mSecureBufferType)) {
    -+        ALOGE("b/31385713, portIndex(%u)", portIndex);
    -+        android_errorWriteLog(0x534e4554, "31385713");
    -+        return BAD_VALUE;
    -+    }
    -+
    -+    Mutex::Autolock autoLock(mLock);
    -+    CLOG_CONFIG(enableNativeBuffers, "%s:%u%s, %d", portString(portIndex), portIndex,
    -+                graphic ? ", graphic" : "", enable);
    -+    OMX_STRING name = const_cast<OMX_STRING>(
    -+            graphic ? "OMX.google.android.index.enableAndroidNativeBuffers"
    -+                    : "OMX.google.android.index.allocateNativeHandle");
    -+
    -+    OMX_INDEXTYPE index;
    -+    OMX_ERRORTYPE err = OMX_GetExtensionIndex(mHandle, name, &index);
    -+
    -+    if (err == OMX_ErrorNone) {
    -+        EnableAndroidNativeBuffersParams params;
    -+        InitOMXParams(&params);
    -+        params.nPortIndex = portIndex;
    -+        params.enable = enable;
    -+
    -+        err = OMX_SetParameter(mHandle, index, &params);
    -+        CLOG_IF_ERROR(setParameter, err, "%s(%#x): %s:%u en=%d", name, index,
    -+                      portString(portIndex), portIndex, enable);
    -+        if (!graphic) {
    -+            if (err == OMX_ErrorNone) {
    -+                mSecureBufferType[portIndex] =
    -+                    enable ? kSecureBufferTypeNativeHandle : kSecureBufferTypeOpaque;
    -+            } else if (mSecureBufferType[portIndex] == kSecureBufferTypeUnknown) {
    -+                mSecureBufferType[portIndex] = kSecureBufferTypeOpaque;
    -+            }
    -+        }
    -+    } else {
    -+        CLOG_ERROR_IF(enable, getExtensionIndex, err, "%s", name);
    -+        if (!graphic) {
    -+            // Extension not supported, check for manual override with system property
    -+            // This is a temporary workaround until partners support the OMX extension
    -+            char value[PROPERTY_VALUE_MAX];
    -+            if (property_get("media.mediadrmservice.enable", value, NULL)
    -+                && (!strcmp("1", value) || !strcasecmp("true", value))) {
    -+                CLOG_CONFIG(enableNativeBuffers, "system property override: using native-handles");
    -+                mSecureBufferType[portIndex] = kSecureBufferTypeNativeHandle;
    -+            } else if (mSecureBufferType[portIndex] == kSecureBufferTypeUnknown) {
    -+                mSecureBufferType[portIndex] = kSecureBufferTypeOpaque;
    -+            }
    -+            err = OMX_ErrorNone;
    -+        }
    -+    }
    -+
    -+    return StatusFromOMXError(err);
    -+}
    -+
    -+status_t OMXNodeInstance::getGraphicBufferUsage(
    -+        OMX_U32 portIndex, OMX_U32* usage) {
    -+    Mutex::Autolock autoLock(mLock);
    -+
    -+    OMX_INDEXTYPE index;
    -+    OMX_STRING name = const_cast<OMX_STRING>(
    -+            "OMX.google.android.index.getAndroidNativeBufferUsage");
    -+    OMX_ERRORTYPE err = OMX_GetExtensionIndex(mHandle, name, &index);
    -+
    -+    if (err != OMX_ErrorNone) {
    -+        CLOG_ERROR(getExtensionIndex, err, "%s", name);
    -+        return StatusFromOMXError(err);
    -+    }
    -+
    -+    GetAndroidNativeBufferUsageParams params;
    -+    InitOMXParams(&params);
    -+    params.nPortIndex = portIndex;
    -+
    -+    err = OMX_GetParameter(mHandle, index, &params);
    -+    if (err != OMX_ErrorNone) {
    -+        CLOG_ERROR(getParameter, err, "%s(%#x): %s:%u", name, index,
    -+                portString(portIndex), portIndex);
    -+        return StatusFromOMXError(err);
    -+    }
    -+
    -+    *usage = params.nUsage;
    -+
    -+    return OK;
    -+}
    -+
    -+status_t OMXNodeInstance::storeMetaDataInBuffers(
    -+        OMX_U32 portIndex, OMX_BOOL enable, MetadataBufferType *type) {
    -+    Mutex::Autolock autolock(mLock);
    -+    CLOG_CONFIG(storeMetaDataInBuffers, "%s:%u en:%d", portString(portIndex), portIndex, enable);
    -+    return storeMetaDataInBuffers_l(portIndex, enable, type);
    -+}
    -+
    -+status_t OMXNodeInstance::storeMetaDataInBuffers_l(
    -+        OMX_U32 portIndex, OMX_BOOL enable, MetadataBufferType *type) {
    -+    if (mSailed) {
    -+        android_errorWriteLog(0x534e4554, "29422020");
    -+        return INVALID_OPERATION;
    -+    }
    -+    if (portIndex != kPortIndexInput && portIndex != kPortIndexOutput) {
    -+        android_errorWriteLog(0x534e4554, "26324358");
    -+        if (type != NULL) {
    -+            *type = kMetadataBufferTypeInvalid;
    -+        }
    -+        return BAD_VALUE;
    -+    }
    -+
    -+    OMX_INDEXTYPE index;
    -+    OMX_STRING name = const_cast<OMX_STRING>(
    -+            "OMX.google.android.index.storeMetaDataInBuffers");
    -+
    -+    OMX_STRING nativeBufferName = const_cast<OMX_STRING>(
    -+            "OMX.google.android.index.storeANWBufferInMetadata");
    -+    MetadataBufferType negotiatedType;
    -+    MetadataBufferType requestedType = type != NULL ? *type : kMetadataBufferTypeANWBuffer;
    -+
    -+    StoreMetaDataInBuffersParams params;
    -+    InitOMXParams(&params);
    -+    params.nPortIndex = portIndex;
    -+    params.bStoreMetaData = enable;
    -+
    -+    OMX_ERRORTYPE err =
    -+        requestedType == kMetadataBufferTypeANWBuffer
    -+                ? OMX_GetExtensionIndex(mHandle, nativeBufferName, &index)
    -+                : OMX_ErrorUnsupportedIndex;
    -+    OMX_ERRORTYPE xerr = err;
    -+    if (err == OMX_ErrorNone) {
    -+        err = OMX_SetParameter(mHandle, index, &params);
    -+        if (err == OMX_ErrorNone) {
    -+            name = nativeBufferName; // set name for debugging
    -+            negotiatedType = requestedType;
    -+        }
    -+    }
    -+    if (err != OMX_ErrorNone) {
    -+        err = OMX_GetExtensionIndex(mHandle, name, &index);
    -+        xerr = err;
    -+        if (err == OMX_ErrorNone) {
    -+            negotiatedType =
    -+                requestedType == kMetadataBufferTypeANWBuffer
    -+                        ? kMetadataBufferTypeGrallocSource : requestedType;
    -+            err = OMX_SetParameter(mHandle, index, &params);
    -+        }
    -+    }
    -+
    -+    // don't log loud error if component does not support metadata mode on the output
    -+    if (err != OMX_ErrorNone) {
    -+        if (err == OMX_ErrorUnsupportedIndex && portIndex == kPortIndexOutput) {
    -+            CLOGW("component does not support metadata mode; using fallback");
    -+        } else if (xerr != OMX_ErrorNone) {
    -+            CLOG_ERROR(getExtensionIndex, xerr, "%s", name);
    -+        } else {
    -+            CLOG_ERROR(setParameter, err, "%s(%#x): %s:%u en=%d type=%d", name, index,
    -+                    portString(portIndex), portIndex, enable, negotiatedType);
    -+        }
    -+        negotiatedType = mMetadataType[portIndex];
    -+    } else {
    -+        if (!enable) {
    -+            negotiatedType = kMetadataBufferTypeInvalid;
    -+        }
    -+        mMetadataType[portIndex] = negotiatedType;
    -+    }
    -+    CLOG_CONFIG(storeMetaDataInBuffers, "%s:%u %srequested %s:%d negotiated %s:%d",
    -+            portString(portIndex), portIndex, enable ? "" : "UN",
    -+            asString(requestedType), requestedType, asString(negotiatedType), negotiatedType);
    -+
    -+    if (type != NULL) {
    -+        *type = negotiatedType;
    -+    }
    -+
    -+    return StatusFromOMXError(err);
    -+}
    -+
    -+status_t OMXNodeInstance::prepareForAdaptivePlayback(
    -+        OMX_U32 portIndex, OMX_BOOL enable, OMX_U32 maxFrameWidth,
    -+        OMX_U32 maxFrameHeight) {
    -+    Mutex::Autolock autolock(mLock);
    -+    if (mSailed) {
    -+        android_errorWriteLog(0x534e4554, "29422020");
    -+        return INVALID_OPERATION;
    -+    }
    -+    CLOG_CONFIG(prepareForAdaptivePlayback, "%s:%u en=%d max=%ux%u",
    -+            portString(portIndex), portIndex, enable, maxFrameWidth, maxFrameHeight);
    -+
    -+    OMX_INDEXTYPE index;
    -+    OMX_STRING name = const_cast<OMX_STRING>(
    -+            "OMX.google.android.index.prepareForAdaptivePlayback");
    -+
    -+    OMX_ERRORTYPE err = OMX_GetExtensionIndex(mHandle, name, &index);
    -+    if (err != OMX_ErrorNone) {
    -+        CLOG_ERROR_IF(enable, getExtensionIndex, err, "%s", name);
    -+        return StatusFromOMXError(err);
    -+    }
    -+
    -+    PrepareForAdaptivePlaybackParams params;
    -+    InitOMXParams(&params);
    -+    params.nPortIndex = portIndex;
    -+    params.bEnable = enable;
    -+    params.nMaxFrameWidth = maxFrameWidth;
    -+    params.nMaxFrameHeight = maxFrameHeight;
    -+
    -+    err = OMX_SetParameter(mHandle, index, &params);
    -+    CLOG_IF_ERROR(setParameter, err, "%s(%#x): %s:%u en=%d max=%ux%u", name, index,
    -+            portString(portIndex), portIndex, enable, maxFrameWidth, maxFrameHeight);
    -+    return StatusFromOMXError(err);
    -+}
    -+
    -+status_t OMXNodeInstance::configureVideoTunnelMode(
    -+        OMX_U32 portIndex, OMX_BOOL tunneled, OMX_U32 audioHwSync,
    -+        native_handle_t **sidebandHandle) {
    -+    Mutex::Autolock autolock(mLock);
    -+    if (mSailed) {
    -+        android_errorWriteLog(0x534e4554, "29422020");
    -+        return INVALID_OPERATION;
    -+    }
    -+    CLOG_CONFIG(configureVideoTunnelMode, "%s:%u tun=%d sync=%u",
    -+            portString(portIndex), portIndex, tunneled, audioHwSync);
    -+
    -+    OMX_INDEXTYPE index;
    -+    OMX_STRING name = const_cast<OMX_STRING>(
    -+            "OMX.google.android.index.configureVideoTunnelMode");
    -+
    -+    OMX_ERRORTYPE err = OMX_GetExtensionIndex(mHandle, name, &index);
    -+    if (err != OMX_ErrorNone) {
    -+        CLOG_ERROR_IF(tunneled, getExtensionIndex, err, "%s", name);
    -+        return StatusFromOMXError(err);
    -+    }
    -+
    -+    ConfigureVideoTunnelModeParams tunnelParams;
    -+    InitOMXParams(&tunnelParams);
    -+    tunnelParams.nPortIndex = portIndex;
    -+    tunnelParams.bTunneled = tunneled;
    -+    tunnelParams.nAudioHwSync = audioHwSync;
    -+    err = OMX_SetParameter(mHandle, index, &tunnelParams);
    -+    if (err != OMX_ErrorNone) {
    -+        CLOG_ERROR(setParameter, err, "%s(%#x): %s:%u tun=%d sync=%u", name, index,
    -+                portString(portIndex), portIndex, tunneled, audioHwSync);
    -+        return StatusFromOMXError(err);
    -+    }
    -+
    -+    err = OMX_GetParameter(mHandle, index, &tunnelParams);
    -+    if (err != OMX_ErrorNone) {
    -+        CLOG_ERROR(getParameter, err, "%s(%#x): %s:%u tun=%d sync=%u", name, index,
    -+                portString(portIndex), portIndex, tunneled, audioHwSync);
    -+        return StatusFromOMXError(err);
    -+    }
    -+    if (sidebandHandle) {
    -+        *sidebandHandle = (native_handle_t*)tunnelParams.pSidebandWindow;
    -+    }
    -+
    -+    return OK;
    -+}
    -+
    -+status_t OMXNodeInstance::useBuffer(
    -+        OMX_U32 portIndex, const sp<IMemory> &params,
    -+        OMX::buffer_id *buffer, OMX_U32 allottedSize) {
    -+    if (params == NULL || buffer == NULL) {
    -+        ALOGE("b/25884056");
    -+        return BAD_VALUE;
    -+    }
    -+
    -+    Mutex::Autolock autoLock(mLock);
    -+    if (allottedSize > params->size() || portIndex >= NELEM(mNumPortBuffers)) {
    -+        return BAD_VALUE;
    -+    }
    -+
    -+    // metadata buffers are not connected cross process
    -+    // use a backup buffer instead of the actual buffer
    -+    BufferMeta *buffer_meta;
    -+    bool useBackup = mMetadataType[portIndex] != kMetadataBufferTypeInvalid;
    -+    OMX_U8 *data = static_cast<OMX_U8 *>(params->pointer());
    -+    // allocate backup buffer
    -+    if (useBackup) {
    -+        data = new (std::nothrow) OMX_U8[allottedSize];
    -+        if (data == NULL) {
    -+            return NO_MEMORY;
    -+        }
    -+        memset(data, 0, allottedSize);
    -+
    -+        // if we are not connecting the buffers, the sizes must match
    -+        if (allottedSize != params->size()) {
    -+            CLOG_ERROR(useBuffer, BAD_VALUE, SIMPLE_BUFFER(portIndex, (size_t)allottedSize, data));
    -+            delete[] data;
    -+            return BAD_VALUE;
    -+        }
    -+
    -+        buffer_meta = new BufferMeta(
    -+                params, portIndex, false /* copyToOmx */, false /* copyFromOmx */, data);
    -+    } else {
    -+        buffer_meta = new BufferMeta(
    -+                params, portIndex, false /* copyToOmx */, false /* copyFromOmx */, NULL);
    -+    }
    -+
    -+    OMX_BUFFERHEADERTYPE *header;
    -+
    -+    OMX_ERRORTYPE err = OMX_UseBuffer(
    -+            mHandle, &header, portIndex, buffer_meta,
    -+            allottedSize, data);
    -+
    -+    if (err != OMX_ErrorNone) {
    -+        CLOG_ERROR(useBuffer, err, SIMPLE_BUFFER(
    -+                portIndex, (size_t)allottedSize, data));
    -+
    -+        delete buffer_meta;
    -+        buffer_meta = NULL;
    -+
    -+        *buffer = 0;
    -+
    -+        return StatusFromOMXError(err);
    -+    }
    -+
    -+    CHECK_EQ(header->pAppPrivate, buffer_meta);
    -+
    -+    *buffer = makeBufferID(header);
    -+
    -+    addActiveBuffer(portIndex, *buffer);
    -+
    -+    sp<GraphicBufferSource> bufferSource(getGraphicBufferSource());
    -+    if (bufferSource != NULL && portIndex == kPortIndexInput) {
    -+        bufferSource->addCodecBuffer(header);
    -+    }
    -+
    -+    CLOG_BUFFER(useBuffer, NEW_BUFFER_FMT(
    -+            *buffer, portIndex, "%u(%zu)@%p", allottedSize, params->size(), params->pointer()));
    -+    return OK;
    -+}
    -+
    -+status_t OMXNodeInstance::useGraphicBuffer2_l(
    -+        OMX_U32 portIndex, const sp<GraphicBuffer>& graphicBuffer,
    -+        OMX::buffer_id *buffer) {
    -+    if (graphicBuffer == NULL || buffer == NULL) {
    -+        ALOGE("b/25884056");
    -+        return BAD_VALUE;
    -+    }
    -+
    -+    // port definition
    -+    OMX_PARAM_PORTDEFINITIONTYPE def;
    -+    InitOMXParams(&def);
    -+    def.nPortIndex = portIndex;
    -+    OMX_ERRORTYPE err = OMX_GetParameter(mHandle, OMX_IndexParamPortDefinition, &def);
    -+    if (err != OMX_ErrorNone) {
    -+        OMX_INDEXTYPE index = OMX_IndexParamPortDefinition;
    -+        CLOG_ERROR(getParameter, err, "%s(%#x): %s:%u",
    -+                asString(index), index, portString(portIndex), portIndex);
    -+        return UNKNOWN_ERROR;
    -+    }
    -+
    -+    BufferMeta *bufferMeta = new BufferMeta(graphicBuffer, portIndex);
    -+
    -+    OMX_BUFFERHEADERTYPE *header = NULL;
    -+    OMX_U8* bufferHandle = const_cast<OMX_U8*>(
    -+            reinterpret_cast<const OMX_U8*>(graphicBuffer->handle));
    -+
    -+    err = OMX_UseBuffer(
    -+            mHandle,
    -+            &header,
    -+            portIndex,
    -+            bufferMeta,
    -+            def.nBufferSize,
    -+            bufferHandle);
    -+
    -+    if (err != OMX_ErrorNone) {
    -+        CLOG_ERROR(useBuffer, err, BUFFER_FMT(portIndex, "%u@%p", def.nBufferSize, bufferHandle));
    -+        delete bufferMeta;
    -+        bufferMeta = NULL;
    -+        *buffer = 0;
    -+        return StatusFromOMXError(err);
    -+    }
    -+
    -+    CHECK_EQ(header->pBuffer, bufferHandle);
    -+    CHECK_EQ(header->pAppPrivate, bufferMeta);
    -+
    -+    *buffer = makeBufferID(header);
    -+
    -+    addActiveBuffer(portIndex, *buffer);
    -+    CLOG_BUFFER(useGraphicBuffer2, NEW_BUFFER_FMT(
    -+            *buffer, portIndex, "%u@%p", def.nBufferSize, bufferHandle));
    -+    return OK;
    -+}
    -+
    -+// XXX: This function is here for backwards compatibility.  Once the OMX
    -+// implementations have been updated this can be removed and useGraphicBuffer2
    -+// can be renamed to useGraphicBuffer.
    -+status_t OMXNodeInstance::useGraphicBuffer(
    -+        OMX_U32 portIndex, const sp<GraphicBuffer>& graphicBuffer,
    -+        OMX::buffer_id *buffer) {
    -+    if (graphicBuffer == NULL || buffer == NULL) {
    -+        ALOGE("b/25884056");
    -+        return BAD_VALUE;
    -+    }
    -+    Mutex::Autolock autoLock(mLock);
    -+
    -+    // See if the newer version of the extension is present.
    -+    OMX_INDEXTYPE index;
    -+    if (OMX_GetExtensionIndex(
    -+            mHandle,
    -+            const_cast<OMX_STRING>("OMX.google.android.index.useAndroidNativeBuffer2"),
    -+            &index) == OMX_ErrorNone) {
    -+        return useGraphicBuffer2_l(portIndex, graphicBuffer, buffer);
    -+    }
    -+
    -+    OMX_STRING name = const_cast<OMX_STRING>(
    -+        "OMX.google.android.index.useAndroidNativeBuffer");
    -+    OMX_ERRORTYPE err = OMX_GetExtensionIndex(mHandle, name, &index);
    -+    if (err != OMX_ErrorNone) {
    -+        CLOG_ERROR(getExtensionIndex, err, "%s", name);
    -+        return StatusFromOMXError(err);
    -+    }
    -+
    -+    BufferMeta *bufferMeta = new BufferMeta(graphicBuffer, portIndex);
    -+
    -+    OMX_BUFFERHEADERTYPE *header;
    -+
    -+    OMX_VERSIONTYPE ver;
    -+    ver.s.nVersionMajor = 1;
    -+    ver.s.nVersionMinor = 0;
    -+    ver.s.nRevision = 0;
    -+    ver.s.nStep = 0;
    -+    UseAndroidNativeBufferParams params = {
    -+        sizeof(UseAndroidNativeBufferParams), ver, portIndex, bufferMeta,
    -+        &header, graphicBuffer,
    -+    };
    -+
    -+    err = OMX_SetParameter(mHandle, index, &params);
    -+
    -+    if (err != OMX_ErrorNone) {
    -+        CLOG_ERROR(setParameter, err, "%s(%#x): %s:%u meta=%p GB=%p", name, index,
    -+                portString(portIndex), portIndex, bufferMeta, graphicBuffer->handle);
    -+
    -+        delete bufferMeta;
    -+        bufferMeta = NULL;
    -+
    -+        *buffer = 0;
    -+
    -+        return StatusFromOMXError(err);
    -+    }
    -+
    -+    CHECK_EQ(header->pAppPrivate, bufferMeta);
    -+
    -+    *buffer = makeBufferID(header);
    -+
    -+    addActiveBuffer(portIndex, *buffer);
    -+    CLOG_BUFFER(useGraphicBuffer, NEW_BUFFER_FMT(
    -+            *buffer, portIndex, "GB=%p", graphicBuffer->handle));
    -+    return OK;
    -+}
    -+
    -+status_t OMXNodeInstance::updateGraphicBufferInMeta_l(
    -+        OMX_U32 portIndex, const sp<GraphicBuffer>& graphicBuffer,
    -+        OMX::buffer_id buffer, OMX_BUFFERHEADERTYPE *header, bool updateCodecBuffer) {
    -+    // No need to check |graphicBuffer| since NULL is valid for it as below.
    -+    if (header == NULL) {
    -+        ALOGE("b/25884056");
    -+        return BAD_VALUE;
    -+    }
    -+
    -+    if (portIndex != kPortIndexInput && portIndex != kPortIndexOutput) {
    -+        return BAD_VALUE;
    -+    }
    -+
    -+    BufferMeta *bufferMeta = (BufferMeta *)(header->pAppPrivate);
    -+    sp<ABuffer> data = bufferMeta->getBuffer(
    -+            header, !updateCodecBuffer /* backup */, false /* limit */);
    -+    bufferMeta->setGraphicBuffer(graphicBuffer);
    -+    MetadataBufferType metaType = mMetadataType[portIndex];
    -+    // we use gralloc source only in the codec buffers
    -+    if (metaType == kMetadataBufferTypeGrallocSource && !updateCodecBuffer) {
    -+        metaType = kMetadataBufferTypeANWBuffer;
    -+    }
    -+    if (metaType == kMetadataBufferTypeGrallocSource
    -+            && data->capacity() >= sizeof(VideoGrallocMetadata)) {
    -+        VideoGrallocMetadata &metadata = *(VideoGrallocMetadata *)(data->data());
    -+        metadata.eType = kMetadataBufferTypeGrallocSource;
    -+        metadata.pHandle = graphicBuffer == NULL ? NULL : graphicBuffer->handle;
    -+    } else if (metaType == kMetadataBufferTypeANWBuffer
    -+            && data->capacity() >= sizeof(VideoNativeMetadata)) {
    -+        VideoNativeMetadata &metadata = *(VideoNativeMetadata *)(data->data());
    -+        metadata.eType = kMetadataBufferTypeANWBuffer;
    -+        metadata.pBuffer = graphicBuffer == NULL ? NULL : graphicBuffer->getNativeBuffer();
    -+        metadata.nFenceFd = -1;
    -+    } else {
    -+        CLOG_ERROR(updateGraphicBufferInMeta, BAD_VALUE, "%s:%u, %#x bad type (%d) or size (%u)",
    -+            portString(portIndex), portIndex, buffer, mMetadataType[portIndex], header->nAllocLen);
    -+        return BAD_VALUE;
    -+    }
    -+
    -+    CLOG_BUFFER(updateGraphicBufferInMeta, "%s:%u, %#x := %p",
    -+            portString(portIndex), portIndex, buffer,
    -+            graphicBuffer == NULL ? NULL : graphicBuffer->handle);
    -+    return OK;
    -+}
    -+
    -+status_t OMXNodeInstance::updateGraphicBufferInMeta(
    -+        OMX_U32 portIndex, const sp<GraphicBuffer>& graphicBuffer,
    -+        OMX::buffer_id buffer) {
    -+    Mutex::Autolock autoLock(mLock);
    -+    OMX_BUFFERHEADERTYPE *header = findBufferHeader(buffer, portIndex);
    -+    // update backup buffer for input, codec buffer for output
    -+    return updateGraphicBufferInMeta_l(
    -+            portIndex, graphicBuffer, buffer, header,
    -+            true /* updateCodecBuffer */);
    -+}
    -+
    -+status_t OMXNodeInstance::updateNativeHandleInMeta(
    -+        OMX_U32 portIndex, const sp<NativeHandle>& nativeHandle, OMX::buffer_id buffer) {
    -+    Mutex::Autolock autoLock(mLock);
    -+    OMX_BUFFERHEADERTYPE *header = findBufferHeader(buffer, portIndex);
    -+    // No need to check |nativeHandle| since NULL is valid for it as below.
    -+    if (header == NULL) {
    -+        ALOGE("b/25884056");
    -+        return BAD_VALUE;
    -+    }
    -+
    -+    if (portIndex != kPortIndexInput && portIndex != kPortIndexOutput) {
    -+        return BAD_VALUE;
    -+    }
    -+
    -+    BufferMeta *bufferMeta = (BufferMeta *)(header->pAppPrivate);
    -+    // update backup buffer
    -+    sp<ABuffer> data = bufferMeta->getBuffer(
    -+            header, false /* backup */, false /* limit */);
    -+    bufferMeta->setNativeHandle(nativeHandle);
    -+    if (mMetadataType[portIndex] == kMetadataBufferTypeNativeHandleSource
    -+            && data->capacity() >= sizeof(VideoNativeHandleMetadata)) {
    -+        VideoNativeHandleMetadata &metadata = *(VideoNativeHandleMetadata *)(data->data());
    -+        metadata.eType = mMetadataType[portIndex];
    -+        metadata.pHandle =
    -+            nativeHandle == NULL ? NULL : const_cast<native_handle*>(nativeHandle->handle());
    -+    } else {
    -+        CLOG_ERROR(updateNativeHandleInMeta, BAD_VALUE, "%s:%u, %#x bad type (%d) or size (%zu)",
    -+            portString(portIndex), portIndex, buffer, mMetadataType[portIndex], data->capacity());
    -+        return BAD_VALUE;
    -+    }
    -+
    -+    CLOG_BUFFER(updateNativeHandleInMeta, "%s:%u, %#x := %p",
    -+            portString(portIndex), portIndex, buffer,
    -+            nativeHandle == NULL ? NULL : nativeHandle->handle());
    -+    return OK;
    -+}
    -+
    -+status_t OMXNodeInstance::createGraphicBufferSource(
    -+        OMX_U32 portIndex, sp<IGraphicBufferConsumer> bufferConsumer, MetadataBufferType *type) {
    -+    status_t err;
    -+
    -+    // only allow graphic source on input port, when there are no allocated buffers yet
    -+    if (portIndex != kPortIndexInput) {
    -+        android_errorWriteLog(0x534e4554, "29422020");
    -+        return BAD_VALUE;
    -+    } else if (mNumPortBuffers[portIndex] > 0) {
    -+        android_errorWriteLog(0x534e4554, "29422020");
    -+        return INVALID_OPERATION;
    -+    }
    -+
    -+    const sp<GraphicBufferSource> surfaceCheck = getGraphicBufferSource();
    -+    if (surfaceCheck != NULL) {
    -+        if (portIndex < NELEM(mMetadataType) && type != NULL) {
    -+            *type = mMetadataType[portIndex];
    -+        }
    -+        return ALREADY_EXISTS;
    -+    }
    -+
    -+    // Input buffers will hold meta-data (ANativeWindowBuffer references).
    -+    if (type != NULL) {
    -+        *type = kMetadataBufferTypeANWBuffer;
    -+    }
    -+    err = storeMetaDataInBuffers_l(portIndex, OMX_TRUE, type);
    -+    if (err != OK) {
    -+        return err;
    -+    }
    -+
    -+    // Retrieve the width and height of the graphic buffer, set when the
    -+    // codec was configured.
    -+    OMX_PARAM_PORTDEFINITIONTYPE def;
    -+    InitOMXParams(&def);
    -+    def.nPortIndex = portIndex;
    -+    OMX_ERRORTYPE oerr = OMX_GetParameter(
    -+            mHandle, OMX_IndexParamPortDefinition, &def);
    -+    if (oerr != OMX_ErrorNone) {
    -+        OMX_INDEXTYPE index = OMX_IndexParamPortDefinition;
    -+        CLOG_ERROR(getParameter, oerr, "%s(%#x): %s:%u",
    -+                asString(index), index, portString(portIndex), portIndex);
    -+        return UNKNOWN_ERROR;
    -+    }
    -+
    -+    if (def.format.video.eColorFormat != OMX_COLOR_FormatAndroidOpaque) {
    -+        CLOGW("createInputSurface requires COLOR_FormatSurface "
    -+                "(AndroidOpaque) color format instead of %s(%#x)",
    -+                asString(def.format.video.eColorFormat), def.format.video.eColorFormat);
    -+        return INVALID_OPERATION;
    -+    }
    -+
    -+    uint32_t usageBits;
    -+    oerr = OMX_GetParameter(
    -+            mHandle, (OMX_INDEXTYPE)OMX_IndexParamConsumerUsageBits, &usageBits);
    -+    if (oerr != OMX_ErrorNone) {
    -+        usageBits = 0;
    -+    }
    -+
    -+    sp<GraphicBufferSource> bufferSource = new GraphicBufferSource(this,
    -+            def.format.video.nFrameWidth,
    -+            def.format.video.nFrameHeight,
    -+            def.nBufferCountActual,
    -+            usageBits,
    -+            bufferConsumer);
    -+
    -+    if ((err = bufferSource->initCheck()) != OK) {
    -+        return err;
    -+    }
    -+    setGraphicBufferSource(bufferSource);
    -+
    -+    return OK;
    -+}
    -+
    -+status_t OMXNodeInstance::createInputSurface(
    -+        OMX_U32 portIndex, android_dataspace dataSpace,
    -+        sp<IGraphicBufferProducer> *bufferProducer, MetadataBufferType *type) {
    -+    if (bufferProducer == NULL) {
    -+        ALOGE("b/25884056");
    -+        return BAD_VALUE;
    -+    }
    -+
    -+    Mutex::Autolock autolock(mLock);
    -+    status_t err = createGraphicBufferSource(portIndex, NULL /* bufferConsumer */, type);
    -+
    -+    if (err != OK) {
    -+        return err;
    -+    }
    -+
    -+    mGraphicBufferSource->setDefaultDataSpace(dataSpace);
    -+
    -+    *bufferProducer = mGraphicBufferSource->getIGraphicBufferProducer();
    -+    return OK;
    -+}
    -+
    -+//static
    -+status_t OMXNodeInstance::createPersistentInputSurface(
    -+        sp<IGraphicBufferProducer> *bufferProducer,
    -+        sp<IGraphicBufferConsumer> *bufferConsumer) {
    -+    if (bufferProducer == NULL || bufferConsumer == NULL) {
    -+        ALOGE("b/25884056");
    -+        return BAD_VALUE;
    -+    }
    -+    String8 name("GraphicBufferSource");
    -+
    -+    sp<IGraphicBufferProducer> producer;
    -+    sp<IGraphicBufferConsumer> consumer;
    -+    BufferQueue::createBufferQueue(&producer, &consumer);
    -+    consumer->setConsumerName(name);
    -+    consumer->setConsumerUsageBits(GRALLOC_USAGE_HW_VIDEO_ENCODER);
    -+
    -+    sp<BufferQueue::ProxyConsumerListener> proxy =
    -+        new BufferQueue::ProxyConsumerListener(NULL);
    -+    status_t err = consumer->consumerConnect(proxy, false);
    -+    if (err != NO_ERROR) {
    -+        ALOGE("Error connecting to BufferQueue: %s (%d)",
    -+                strerror(-err), err);
    -+        return err;
    -+    }
    -+
    -+    *bufferProducer = producer;
    -+    *bufferConsumer = consumer;
    -+
    -+    return OK;
    -+}
    -+
    -+status_t OMXNodeInstance::setInputSurface(
    -+        OMX_U32 portIndex, const sp<IGraphicBufferConsumer> &bufferConsumer,
    -+        MetadataBufferType *type) {
    -+    Mutex::Autolock autolock(mLock);
    -+    return createGraphicBufferSource(portIndex, bufferConsumer, type);
    -+}
    -+
    -+void OMXNodeInstance::signalEvent(OMX_EVENTTYPE event, OMX_U32 arg1, OMX_U32 arg2) {
    -+    mOwner->OnEvent(mNodeID, event, arg1, arg2, NULL);
    -+}
    -+
    -+status_t OMXNodeInstance::signalEndOfInputStream() {
    -+    // For non-Surface input, the MediaCodec should convert the call to a
    -+    // pair of requests (dequeue input buffer, queue input buffer with EOS
    -+    // flag set).  Seems easier than doing the equivalent from here.
    -+    sp<GraphicBufferSource> bufferSource(getGraphicBufferSource());
    -+    if (bufferSource == NULL) {
    -+        CLOGW("signalEndOfInputStream can only be used with Surface input");
    -+        return INVALID_OPERATION;
    -+    }
    -+    return bufferSource->signalEndOfInputStream();
    -+}
    -+
    -+status_t OMXNodeInstance::allocateSecureBuffer(
    -+        OMX_U32 portIndex, size_t size, OMX::buffer_id *buffer,
    -+        void **buffer_data, sp<NativeHandle> *native_handle) {
    -+    if (buffer == NULL || buffer_data == NULL || native_handle == NULL) {
    -+        ALOGE("b/25884056");
    -+        return BAD_VALUE;
    -+    }
    -+
    -+    if (portIndex >= NELEM(mSecureBufferType)) {
    -+        ALOGE("b/31385713, portIndex(%u)", portIndex);
    -+        android_errorWriteLog(0x534e4554, "31385713");
    -+        return BAD_VALUE;
    -+    }
    -+
    -+    Mutex::Autolock autoLock(mLock);
    -+
    -+    BufferMeta *buffer_meta = new BufferMeta(size, portIndex);
    -+
    -+    OMX_BUFFERHEADERTYPE *header;
    -+
    -+    OMX_ERRORTYPE err = OMX_AllocateBuffer(
    -+            mHandle, &header, portIndex, buffer_meta, size);
    -+
    -+    if (err != OMX_ErrorNone) {
    -+        CLOG_ERROR(allocateBuffer, err, BUFFER_FMT(portIndex, "%zu@", size));
    -+        delete buffer_meta;
    -+        buffer_meta = NULL;
    -+
    -+        *buffer = 0;
    -+
    -+        return StatusFromOMXError(err);
    -+    }
    -+
    -+    CHECK_EQ(header->pAppPrivate, buffer_meta);
    -+
    -+    *buffer = makeBufferID(header);
    -+    if (mSecureBufferType[portIndex] == kSecureBufferTypeNativeHandle) {
    -+        *buffer_data = NULL;
    -+        *native_handle = NativeHandle::create(
    -+                (native_handle_t *)header->pBuffer, false /* ownsHandle */);
    -+    } else {
    -+        *buffer_data = header->pBuffer;
    -+        *native_handle = NULL;
    -+    }
    -+
    -+    addActiveBuffer(portIndex, *buffer);
    -+
    -+    sp<GraphicBufferSource> bufferSource(getGraphicBufferSource());
    -+    if (bufferSource != NULL && portIndex == kPortIndexInput) {
    -+        bufferSource->addCodecBuffer(header);
    -+    }
    -+    CLOG_BUFFER(allocateSecureBuffer, NEW_BUFFER_FMT(
    -+            *buffer, portIndex, "%zu@%p:%p", size, *buffer_data,
    -+            *native_handle == NULL ? NULL : (*native_handle)->handle()));
    -+
    -+    return OK;
    -+}
    -+
    -+status_t OMXNodeInstance::allocateBufferWithBackup(
    -+        OMX_U32 portIndex, const sp<IMemory> &params,
    -+        OMX::buffer_id *buffer, OMX_U32 allottedSize) {
    -+    if (params == NULL || buffer == NULL) {
    -+        ALOGE("b/25884056");
    -+        return BAD_VALUE;
    -+    }
    -+
    -+    Mutex::Autolock autoLock(mLock);
    -+    if (allottedSize > params->size() || portIndex >= NELEM(mNumPortBuffers)) {
    -+        return BAD_VALUE;
    -+    }
    -+
    -+    // metadata buffers are not connected cross process; only copy if not meta
    ++            firstSample = false;
    + 
    +             if (mediaBuffer->range_length() > codecBuffer->capacity()) {
    +                 ALOGE("buffer size (%zu) too large for codec input size (%zu)",
    +@@ -292,8 +303,9 @@ static VideoFrame *extractVideoFrame(
    +                 memcpy(codecBuffer->data(),
    +                         (const uint8_t*)mediaBuffer->data() + mediaBuffer->range_offset(),
    +                         mediaBuffer->range_length());
    +-                if (isAvcOrHevc && IsIDR(codecBuffer)) {
    +-                    // Only need to decode one IDR frame.
    ++                if (isAvcOrHevc && IsIDR(codecBuffer) && !isSeekingClosest) {
    ++                    // Only need to decode one IDR frame, unless we're seeking with CLOSEST
    ++                    // option, in which case we need to actually decode to targetTimeUs.
    +                     haveMoreInputs = false;
    +                     flags |= MediaCodec::BUFFER_FLAG_EOS;
    +                 }
    +@@ -340,8 +352,13 @@ static VideoFrame *extractVideoFrame(
    +                     ALOGV("Timed-out waiting for output.. retries left = %zu", retriesLeft);
    +                     err = OK;
    +                 } else if (err == OK) {
    +-                    ALOGV("Received an output buffer");
    +-                    done = true;
    ++                    // If we're seeking with CLOSEST option and obtained a valid targetTimeUs
    ++                    // from the extractor, decode to the specified frame. Otherwise we're done.
    ++                    done = (targetTimeUs < 0ll) || (timeUs >= targetTimeUs);
    ++                    ALOGV("Received an output buffer, timeUs=%lld", (long long)timeUs);
    ++                    if (!done) {
    ++                        err = decoder->releaseOutputBuffer(index);
    ++                    }
    +                 } else {
    +                     ALOGW("Received error %d (%s) instead of output", err, asString(err));
    +                     done = true;
    +diff --git a/media/libstagefright/SurfaceMediaSource.cpp b/media/libstagefright/SurfaceMediaSource.cpp
    +index 15ff569..0e9b4e6 100644
    +--- a/media/libstagefright/SurfaceMediaSource.cpp
    ++++ b/media/libstagefright/SurfaceMediaSource.cpp
    +@@ -129,7 +129,11 @@ status_t SurfaceMediaSource::setFrameRate(int32_t fps)
    + 
    + MetadataBufferType SurfaceMediaSource::metaDataStoredInVideoBuffers() const {
    +     ALOGV("isMetaDataStoredInVideoBuffers");
     +#ifdef CAMCORDER_GRALLOC_SOURCE
    -+    bool copy = true;
    -+#else
    -+    bool copy = mMetadataType[portIndex] == kMetadataBufferTypeInvalid;
    -+#endif
    -+
    -+    BufferMeta *buffer_meta = new BufferMeta(
    -+            params, portIndex,
    -+            (portIndex == kPortIndexInput) && copy /* copyToOmx */,
    -+            (portIndex == kPortIndexOutput) && copy /* copyFromOmx */,
    -+            NULL /* data */);
    -+
    -+    OMX_BUFFERHEADERTYPE *header;
    -+
    -+    OMX_ERRORTYPE err = OMX_AllocateBuffer(
    -+            mHandle, &header, portIndex, buffer_meta, allottedSize);
    -+    if (err != OMX_ErrorNone) {
    -+        CLOG_ERROR(allocateBufferWithBackup, err,
    -+                SIMPLE_BUFFER(portIndex, (size_t)allottedSize, params->pointer()));
    -+        delete buffer_meta;
    -+        buffer_meta = NULL;
    -+
    -+        *buffer = 0;
    -+
    -+        return StatusFromOMXError(err);
    -+    }
    -+
    -+    CHECK_EQ(header->pAppPrivate, buffer_meta);
    -+
    -+    *buffer = makeBufferID(header);
    -+
    -+    addActiveBuffer(portIndex, *buffer);
    -+
    -+    sp<GraphicBufferSource> bufferSource(getGraphicBufferSource());
    -+    if (bufferSource != NULL && portIndex == kPortIndexInput) {
    -+        bufferSource->addCodecBuffer(header);
    -+    }
    -+
    -+    CLOG_BUFFER(allocateBufferWithBackup, NEW_BUFFER_FMT(*buffer, portIndex, "%zu@%p :> %u@%p",
    -+            params->size(), params->pointer(), allottedSize, header->pBuffer));
    -+
    -+    return OK;
    -+}
    -+
    -+status_t OMXNodeInstance::freeBuffer(
    -+        OMX_U32 portIndex, OMX::buffer_id buffer) {
    -+    Mutex::Autolock autoLock(mLock);
    -+    CLOG_BUFFER(freeBuffer, "%s:%u %#x", portString(portIndex), portIndex, buffer);
    -+
    -+    removeActiveBuffer(portIndex, buffer);
    -+
    -+    OMX_BUFFERHEADERTYPE *header = findBufferHeader(buffer, portIndex);
    -+    if (header == NULL) {
    -+        ALOGE("b/25884056");
    -+        return BAD_VALUE;
    -+    }
    -+    BufferMeta *buffer_meta = static_cast<BufferMeta *>(header->pAppPrivate);
    -+
    -+    OMX_ERRORTYPE err = OMX_FreeBuffer(mHandle, portIndex, header);
    -+    CLOG_IF_ERROR(freeBuffer, err, "%s:%u %#x", portString(portIndex), portIndex, buffer);
    -+
    -+    delete buffer_meta;
    -+    buffer_meta = NULL;
    -+    invalidateBufferID(buffer);
    -+
    -+    return StatusFromOMXError(err);
    -+}
    -+
    -+status_t OMXNodeInstance::fillBuffer(OMX::buffer_id buffer, int fenceFd) {
    -+    Mutex::Autolock autoLock(mLock);
    -+
    -+    OMX_BUFFERHEADERTYPE *header = findBufferHeader(buffer, kPortIndexOutput);
    -+    if (header == NULL) {
    -+        ALOGE("b/25884056");
    -+        return BAD_VALUE;
    -+    }
    -+    header->nFilledLen = 0;
    -+    header->nOffset = 0;
    -+    header->nFlags = 0;
    -+
    -+    // meta now owns fenceFd
    -+    status_t res = storeFenceInMeta_l(header, fenceFd, kPortIndexOutput);
    -+    if (res != OK) {
    -+        CLOG_ERROR(fillBuffer::storeFenceInMeta, res, EMPTY_BUFFER(buffer, header, fenceFd));
    -+        return res;
    -+    }
    -+
    -+    {
    -+        Mutex::Autolock _l(mDebugLock);
    -+        mOutputBuffersWithCodec.add(header);
    -+        CLOG_BUMPED_BUFFER(fillBuffer, WITH_STATS(EMPTY_BUFFER(buffer, header, fenceFd)));
    -+    }
    -+
    -+    OMX_ERRORTYPE err = OMX_FillThisBuffer(mHandle, header);
    -+    if (err != OMX_ErrorNone) {
    -+        CLOG_ERROR(fillBuffer, err, EMPTY_BUFFER(buffer, header, fenceFd));
    -+        Mutex::Autolock _l(mDebugLock);
    -+        mOutputBuffersWithCodec.remove(header);
    -+    }
    -+    return StatusFromOMXError(err);
    -+}
    -+
    -+status_t OMXNodeInstance::emptyBuffer(
    -+        OMX::buffer_id buffer,
    -+        OMX_U32 rangeOffset, OMX_U32 rangeLength,
    -+        OMX_U32 flags, OMX_TICKS timestamp, int fenceFd) {
    -+    Mutex::Autolock autoLock(mLock);
    -+
    -+    // no emptybuffer if using input surface
    -+    if (getGraphicBufferSource() != NULL) {
    -+        android_errorWriteLog(0x534e4554, "29422020");
    -+        return INVALID_OPERATION;
    -+    }
    -+
    -+    OMX_BUFFERHEADERTYPE *header = findBufferHeader(buffer, kPortIndexInput);
    -+    if (header == NULL) {
    -+        ALOGE("b/25884056");
    -+        return BAD_VALUE;
    -+    }
    -+    BufferMeta *buffer_meta =
    -+        static_cast<BufferMeta *>(header->pAppPrivate);
    -+
    -+#ifndef CAMCORDER_GRALLOC_SOURCE
    -+    // set up proper filled length if component is configured for gralloc metadata mode
    -+    // ignore rangeOffset in this case (as client may be assuming ANW meta buffers).
    -+    if (mMetadataType[kPortIndexInput] == kMetadataBufferTypeGrallocSource) {
    -+        header->nFilledLen = rangeLength ? sizeof(VideoGrallocMetadata) : 0;
    ++    return kMetadataBufferTypeGrallocSource;
     +#else
    -+    sp<ABuffer> backup = buffer_meta->getBuffer(header, true /* backup */, false /* limit */);
    -+    sp<ABuffer> codec = buffer_meta->getBuffer(header, false /* backup */, false /* limit */);
    -+
    -+    // convert incoming ANW meta buffers if component is configured for gralloc metadata mode
    -+    // ignore rangeOffset in this case
    -+    if (mMetadataType[kPortIndexInput] == kMetadataBufferTypeGrallocSource
    -+            && backup->capacity() >= sizeof(VideoNativeMetadata)
    -+            && codec->capacity() >= sizeof(VideoGrallocMetadata)
    -+            && ((VideoNativeMetadata *)backup->base())->eType
    -+                    == kMetadataBufferTypeANWBuffer) {
    -+        VideoNativeMetadata &backupMeta = *(VideoNativeMetadata *)backup->base();
    -+        VideoGrallocMetadata &codecMeta = *(VideoGrallocMetadata *)codec->base();
    -+        CLOG_BUFFER(emptyBuffer, "converting ANWB %p to handle %p",
    -+                backupMeta.pBuffer, backupMeta.pBuffer->handle);
    -+        codecMeta.pHandle = backupMeta.pBuffer != NULL ? backupMeta.pBuffer->handle : NULL;
    -+        codecMeta.eType = kMetadataBufferTypeGrallocSource;
    -+        header->nFilledLen = rangeLength ? sizeof(codecMeta) : 0;
    +     return kMetadataBufferTypeANWBuffer;
     +#endif
    -+        header->nOffset = 0;
    -+    } else {
    -+        // rangeLength and rangeOffset must be a subset of the allocated data in the buffer.
    -+        // corner case: we permit rangeOffset == end-of-buffer with rangeLength == 0.
    -+        if (rangeOffset > header->nAllocLen
    -+                || rangeLength > header->nAllocLen - rangeOffset) {
    -+            CLOG_ERROR(emptyBuffer, OMX_ErrorBadParameter, FULL_BUFFER(NULL, header, fenceFd));
    -+            if (fenceFd >= 0) {
    -+                ::close(fenceFd);
    -+            }
    -+            return BAD_VALUE;
    -+        }
    -+        header->nFilledLen = rangeLength;
    -+        header->nOffset = rangeOffset;
    -+
    -+        buffer_meta->CopyToOMX(header);
    -+    }
    -+
    -+    return emptyBuffer_l(header, flags, timestamp, (intptr_t)buffer, fenceFd);
    -+}
    -+
    -+// log queued buffer activity for the next few input and/or output frames
    -+// if logging at internal state level
    -+void OMXNodeInstance::bumpDebugLevel_l(size_t numInputBuffers, size_t numOutputBuffers) {
    -+    if (DEBUG == ADebug::kDebugInternalState) {
    -+        DEBUG_BUMP = ADebug::kDebugAll;
    -+        if (numInputBuffers > 0) {
    -+            mDebugLevelBumpPendingBuffers[kPortIndexInput] = numInputBuffers;
    -+        }
    -+        if (numOutputBuffers > 0) {
    -+            mDebugLevelBumpPendingBuffers[kPortIndexOutput] = numOutputBuffers;
    -+        }
    -+    }
    -+}
    -+
    -+void OMXNodeInstance::unbumpDebugLevel_l(size_t portIndex) {
    -+    if (mDebugLevelBumpPendingBuffers[portIndex]) {
    -+        --mDebugLevelBumpPendingBuffers[portIndex];
    -+    }
    -+    if (!mDebugLevelBumpPendingBuffers[0]
    -+            && !mDebugLevelBumpPendingBuffers[1]) {
    -+        DEBUG_BUMP = DEBUG;
    -+    }
    -+}
    -+
    -+status_t OMXNodeInstance::storeFenceInMeta_l(
    -+        OMX_BUFFERHEADERTYPE *header, int fenceFd, OMX_U32 portIndex) {
    -+    // propagate fence if component supports it; wait for it otherwise
    -+    OMX_U32 metaSize = portIndex == kPortIndexInput ? header->nFilledLen : header->nAllocLen;
    -+    if (mMetadataType[portIndex] == kMetadataBufferTypeANWBuffer
    -+            && metaSize >= sizeof(VideoNativeMetadata)) {
    -+        VideoNativeMetadata &nativeMeta = *(VideoNativeMetadata *)(header->pBuffer);
    -+        if (nativeMeta.nFenceFd >= 0) {
    -+            ALOGE("fence (%d) already exists in meta", nativeMeta.nFenceFd);
    -+            if (fenceFd >= 0) {
    -+                ::close(fenceFd);
    -+            }
    -+            return ALREADY_EXISTS;
    -+        }
    -+        nativeMeta.nFenceFd = fenceFd;
    -+    } else if (fenceFd >= 0) {
    -+        CLOG_BUFFER(storeFenceInMeta, "waiting for fence %d", fenceFd);
    -+        sp<Fence> fence = new Fence(fenceFd);
    -+        return fence->wait(IOMX::kFenceTimeoutMs);
    -+    }
    -+    return OK;
    -+}
    -+
    -+int OMXNodeInstance::retrieveFenceFromMeta_l(
    -+        OMX_BUFFERHEADERTYPE *header, OMX_U32 portIndex) {
    -+    OMX_U32 metaSize = portIndex == kPortIndexInput ? header->nAllocLen : header->nFilledLen;
    -+    int fenceFd = -1;
    -+    if (mMetadataType[portIndex] == kMetadataBufferTypeANWBuffer
    -+            && header->nAllocLen >= sizeof(VideoNativeMetadata)) {
    -+        VideoNativeMetadata &nativeMeta = *(VideoNativeMetadata *)(header->pBuffer);
    -+        if (nativeMeta.eType == kMetadataBufferTypeANWBuffer) {
    -+            fenceFd = nativeMeta.nFenceFd;
    -+            nativeMeta.nFenceFd = -1;
    -+        }
    -+        if (metaSize < sizeof(nativeMeta) && fenceFd >= 0) {
    -+            CLOG_ERROR(foundFenceInEmptyMeta, BAD_VALUE, FULL_BUFFER(
    -+                    NULL, header, nativeMeta.nFenceFd));
    -+            fenceFd = -1;
    -+        }
    -+    }
    -+    return fenceFd;
    -+}
    -+
    -+status_t OMXNodeInstance::emptyBuffer_l(
    -+        OMX_BUFFERHEADERTYPE *header, OMX_U32 flags, OMX_TICKS timestamp,
    -+        intptr_t debugAddr, int fenceFd) {
    -+    header->nFlags = flags;
    -+    header->nTimeStamp = timestamp;
    -+
    -+    status_t res = storeFenceInMeta_l(header, fenceFd, kPortIndexInput);
    -+    if (res != OK) {
    -+        CLOG_ERROR(emptyBuffer::storeFenceInMeta, res, WITH_STATS(
    -+                FULL_BUFFER(debugAddr, header, fenceFd)));
    -+        return res;
    -+    }
    -+
    -+    {
    -+        Mutex::Autolock _l(mDebugLock);
    -+        mInputBuffersWithCodec.add(header);
    -+
    -+        // bump internal-state debug level for 2 input frames past a buffer with CSD
    -+        if ((flags & OMX_BUFFERFLAG_CODECCONFIG) != 0) {
    -+            bumpDebugLevel_l(2 /* numInputBuffers */, 0 /* numOutputBuffers */);
    -+        }
    -+
    -+        CLOG_BUMPED_BUFFER(emptyBuffer, WITH_STATS(FULL_BUFFER(debugAddr, header, fenceFd)));
    -+    }
    -+
    -+    OMX_ERRORTYPE err = OMX_EmptyThisBuffer(mHandle, header);
    -+    CLOG_IF_ERROR(emptyBuffer, err, FULL_BUFFER(debugAddr, header, fenceFd));
    -+
    -+    {
    -+        Mutex::Autolock _l(mDebugLock);
    -+        if (err != OMX_ErrorNone) {
    -+            mInputBuffersWithCodec.remove(header);
    -+        } else if (!(flags & OMX_BUFFERFLAG_CODECCONFIG)) {
    -+            unbumpDebugLevel_l(kPortIndexInput);
    -+        }
    -+    }
    -+
    -+    return StatusFromOMXError(err);
    -+}
    -+
    -+// like emptyBuffer, but the data is already in header->pBuffer
    -+status_t OMXNodeInstance::emptyGraphicBuffer(
    -+        OMX_BUFFERHEADERTYPE *header, const sp<GraphicBuffer> &graphicBuffer,
    -+        OMX_U32 flags, OMX_TICKS timestamp, int fenceFd) {
    -+    if (header == NULL) {
    -+        ALOGE("b/25884056");
    -+        return BAD_VALUE;
    -+    }
    -+
    -+    Mutex::Autolock autoLock(mLock);
    -+    OMX::buffer_id buffer = findBufferID(header);
    -+    status_t err = updateGraphicBufferInMeta_l(
    -+            kPortIndexInput, graphicBuffer, buffer, header,
    -+            true /* updateCodecBuffer */);
    -+    if (err != OK) {
    -+        CLOG_ERROR(emptyGraphicBuffer, err, FULL_BUFFER(
    -+                (intptr_t)header->pBuffer, header, fenceFd));
    -+        return err;
    -+    }
    -+
    -+    header->nOffset = 0;
    -+    if (graphicBuffer == NULL) {
    -+        header->nFilledLen = 0;
    -+    } else if (mMetadataType[kPortIndexInput] == kMetadataBufferTypeGrallocSource) {
    -+        header->nFilledLen = sizeof(VideoGrallocMetadata);
    -+    } else {
    -+        header->nFilledLen = sizeof(VideoNativeMetadata);
    -+    }
    -+    return emptyBuffer_l(header, flags, timestamp, (intptr_t)header->pBuffer, fenceFd);
    -+}
    -+
    -+status_t OMXNodeInstance::getExtensionIndex(
    -+        const char *parameterName, OMX_INDEXTYPE *index) {
    -+    Mutex::Autolock autoLock(mLock);
    -+
    -+    OMX_ERRORTYPE err = OMX_GetExtensionIndex(
    -+            mHandle, const_cast<char *>(parameterName), index);
    -+
    -+    return StatusFromOMXError(err);
    -+}
    -+
    -+inline static const char *asString(IOMX::InternalOptionType i, const char *def = "??") {
    -+    switch (i) {
    -+        case IOMX::INTERNAL_OPTION_SUSPEND:           return "SUSPEND";
    -+        case IOMX::INTERNAL_OPTION_REPEAT_PREVIOUS_FRAME_DELAY:
    -+            return "REPEAT_PREVIOUS_FRAME_DELAY";
    -+        case IOMX::INTERNAL_OPTION_MAX_TIMESTAMP_GAP: return "MAX_TIMESTAMP_GAP";
    -+        case IOMX::INTERNAL_OPTION_MAX_FPS:           return "MAX_FPS";
    -+        case IOMX::INTERNAL_OPTION_START_TIME:        return "START_TIME";
    -+        case IOMX::INTERNAL_OPTION_TIME_LAPSE:        return "TIME_LAPSE";
    -+        case IOMX::INTERNAL_OPTION_TIME_OFFSET:       return "TIME_OFFSET";
    -+        default:                                      return def;
    + }
    + 
    + int32_t SurfaceMediaSource::getFrameRate( ) const {
    +@@ -250,6 +254,35 @@ sp<MetaData> SurfaceMediaSource::getFormat()
    +     return meta;
    + }
    + 
    ++#ifdef CAMCORDER_GRALLOC_SOURCE
    ++// Pass the data to the MediaBuffer. Pass in only the metadata
    ++// The metadata passed consists of two parts:
    ++// 1. First, there is an integer indicating that it is a GRAlloc
    ++// source (kMetadataBufferTypeGrallocSource)
    ++// 2. This is followed by the buffer_handle_t that is a handle to the
    ++// GRalloc buffer. The encoder needs to interpret this GRalloc handle
    ++// and encode the frames.
    ++// --------------------------------------------------------------
    ++// |  kMetadataBufferTypeGrallocSource | sizeof(buffer_handle_t) |
    ++// --------------------------------------------------------------
    ++// Note: Call only when you have the lock
    ++static void passMetadataBuffer(MediaBuffer **buffer,
    ++        buffer_handle_t bufferHandle) {
    ++    *buffer = new MediaBuffer(4 + sizeof(buffer_handle_t));
    ++    char *data = (char *)(*buffer)->data();
    ++    if (data == NULL) {
    ++        ALOGE("Cannot allocate memory for metadata buffer!");
    ++        return;
     +    }
    -+}
    ++    OMX_U32 type = kMetadataBufferTypeGrallocSource;
    ++    memcpy(data, &type, 4);
    ++    memcpy(data + 4, &bufferHandle, sizeof(buffer_handle_t));
     +
    -+template<typename T>
    -+static bool getInternalOption(
    -+        const void *data, size_t size, T *out) {
    -+    if (size != sizeof(T)) {
    -+        return false;
    -+    }
    -+    *out = *(T*)data;
    -+    return true;
    ++    ALOGV("handle = %p, , offset = %zu, length = %zu",
    ++            bufferHandle, (*buffer)->range_length(), (*buffer)->range_offset());
     +}
    ++#endif
     +
    -+status_t OMXNodeInstance::setInternalOption(
    -+        OMX_U32 portIndex,
    -+        IOMX::InternalOptionType type,
    -+        const void *data,
    -+        size_t size) {
    -+    CLOG_CONFIG(setInternalOption, "%s(%d): %s:%u %zu@%p",
    -+            asString(type), type, portString(portIndex), portIndex, size, data);
    -+    switch (type) {
    -+        case IOMX::INTERNAL_OPTION_SUSPEND:
    -+        case IOMX::INTERNAL_OPTION_REPEAT_PREVIOUS_FRAME_DELAY:
    -+        case IOMX::INTERNAL_OPTION_MAX_TIMESTAMP_GAP:
    -+        case IOMX::INTERNAL_OPTION_MAX_FPS:
    -+        case IOMX::INTERNAL_OPTION_START_TIME:
    -+        case IOMX::INTERNAL_OPTION_TIME_LAPSE:
    -+        case IOMX::INTERNAL_OPTION_TIME_OFFSET:
    -+        case IOMX::INTERNAL_OPTION_COLOR_ASPECTS:
    -+        {
    -+            const sp<GraphicBufferSource> &bufferSource =
    -+                getGraphicBufferSource();
    -+
    -+            if (bufferSource == NULL || portIndex != kPortIndexInput) {
    -+                CLOGW("setInternalOption is only for Surface input");
    -+                return ERROR_UNSUPPORTED;
    -+            }
    -+
    -+            if (type == IOMX::INTERNAL_OPTION_SUSPEND) {
    -+                bool suspend;
    -+                if (!getInternalOption(data, size, &suspend)) {
    -+                    return INVALID_OPERATION;
    -+                }
    -+
    -+                CLOG_CONFIG(setInternalOption, "suspend=%d", suspend);
    -+                bufferSource->suspend(suspend);
    -+            } else if (type == IOMX::INTERNAL_OPTION_REPEAT_PREVIOUS_FRAME_DELAY) {
    -+                int64_t delayUs;
    -+                if (!getInternalOption(data, size, &delayUs)) {
    -+                    return INVALID_OPERATION;
    -+                }
    -+
    -+                CLOG_CONFIG(setInternalOption, "delayUs=%lld", (long long)delayUs);
    -+                return bufferSource->setRepeatPreviousFrameDelayUs(delayUs);
    -+            } else if (type == IOMX::INTERNAL_OPTION_TIME_OFFSET) {
    -+                int64_t timeOffsetUs;
    -+                if (!getInternalOption(data, size, &timeOffsetUs)) {
    -+                    return INVALID_OPERATION;
    -+                }
    -+                CLOG_CONFIG(setInternalOption, "bufferOffsetUs=%lld", (long long)timeOffsetUs);
    -+                return bufferSource->setInputBufferTimeOffset(timeOffsetUs);
    -+            } else if (type == IOMX::INTERNAL_OPTION_MAX_TIMESTAMP_GAP) {
    -+                int64_t maxGapUs;
    -+                if (!getInternalOption(data, size, &maxGapUs)) {
    -+                    return INVALID_OPERATION;
    -+                }
    -+
    -+                CLOG_CONFIG(setInternalOption, "gapUs=%lld", (long long)maxGapUs);
    -+                return bufferSource->setMaxTimestampGapUs(maxGapUs);
    -+            } else if (type == IOMX::INTERNAL_OPTION_MAX_FPS) {
    -+                float maxFps;
    -+                if (!getInternalOption(data, size, &maxFps)) {
    -+                    return INVALID_OPERATION;
    -+                }
    -+
    -+                CLOG_CONFIG(setInternalOption, "maxFps=%f", maxFps);
    -+                return bufferSource->setMaxFps(maxFps);
    -+            } else if (type == IOMX::INTERNAL_OPTION_START_TIME) {
    -+                int64_t skipFramesBeforeUs;
    -+                if (!getInternalOption(data, size, &skipFramesBeforeUs)) {
    -+                    return INVALID_OPERATION;
    -+                }
    -+
    -+                CLOG_CONFIG(setInternalOption, "beforeUs=%lld", (long long)skipFramesBeforeUs);
    -+                bufferSource->setSkipFramesBeforeUs(skipFramesBeforeUs);
    -+            } else if (type == IOMX::INTERNAL_OPTION_TIME_LAPSE) {
    -+                GraphicBufferSource::TimeLapseConfig config;
    -+                if (!getInternalOption(data, size, &config)) {
    -+                    return INVALID_OPERATION;
    -+                }
    -+
    -+                CLOG_CONFIG(setInternalOption, "perFrameUs=%lld perCaptureUs=%lld",
    -+                        (long long)config.mTimePerFrameUs, (long long)config.mTimePerCaptureUs);
    -+
    -+                return bufferSource->setTimeLapseConfig(config);
    -+            } else if (type == IOMX::INTERNAL_OPTION_COLOR_ASPECTS) {
    -+                ColorAspects aspects;
    -+                if (!getInternalOption(data, size, &aspects)) {
    -+                    return INVALID_OPERATION;
    -+                }
    -+
    -+                CLOG_CONFIG(setInternalOption, "setting color aspects");
    -+                bufferSource->setColorAspects(aspects);
    -+            }
    -+
    -+            return OK;
    + // Pass the data to the MediaBuffer. Pass in only the metadata
    + // Note: Call only when you have the lock
    + void SurfaceMediaSource::passMetadataBuffer_l(MediaBuffer **buffer,
    +@@ -352,7 +385,11 @@ status_t SurfaceMediaSource::read(
    +     mNumFramesEncoded++;
    +     // Pass the data to the MediaBuffer. Pass in only the metadata
    + 
    ++#ifdef CAMCORDER_GRALLOC_SOURCE
    ++    passMetadataBuffer(buffer, mSlots[mCurrentSlot].mGraphicBuffer->handle);
    ++#else
    +     passMetadataBuffer_l(buffer, mSlots[mCurrentSlot].mGraphicBuffer->getNativeBuffer());
    ++#endif
    + 
    +     (*buffer)->setObserver(this);
    +     (*buffer)->add_ref();
    +diff --git a/media/libstagefright/SurfaceUtils.cpp b/media/libstagefright/SurfaceUtils.cpp
    +index 60ef662..568837a 100644
    +--- a/media/libstagefright/SurfaceUtils.cpp
    ++++ b/media/libstagefright/SurfaceUtils.cpp
    +@@ -186,10 +186,6 @@ status_t pushBlankBuffersToNativeWindow(ANativeWindow *nativeWindow /* nonnull *
    +             break;
    +         }
    + 
    +-        if (img == NULL) {
    +-            ALOGE("error pushing blank frames: lock returned NULL buffer");
    +-            break;
    +-        }
    +         *img = 0;
    + 
    +         err = buf->unlock();
    +diff --git a/media/libstagefright/foundation/ColorUtils.cpp b/media/libstagefright/foundation/ColorUtils.cpp
    +index e329766..d7439b2 100644
    +--- a/media/libstagefright/foundation/ColorUtils.cpp
    ++++ b/media/libstagefright/foundation/ColorUtils.cpp
    +@@ -286,6 +286,7 @@ ALookup<int32_t, ColorAspects::Transfer> sIsoTransfers {
    +         { 15, ColorAspects::TransferSMPTE170M },
    +         { 16, ColorAspects::TransferST2084 },
    +         { 17, ColorAspects::TransferST428 },
    ++        { 18, ColorAspects::TransferHLG },
    +     }
    + };
    + 
    +diff --git a/media/libstagefright/foundation/MediaBuffer.cpp b/media/libstagefright/foundation/MediaBuffer.cpp
    +index 718b7e5..16000ef 100644
    +--- a/media/libstagefright/foundation/MediaBuffer.cpp
    ++++ b/media/libstagefright/foundation/MediaBuffer.cpp
    +@@ -105,14 +105,7 @@ MediaBuffer::MediaBuffer(const sp<ABuffer> &buffer)
    + 
    + void MediaBuffer::release() {
    +     if (mObserver == NULL) {
    +-        if (mMemory.get() != nullptr) {
    +-            // See if there is a pending release and there are no observers.
    +-            // Ideally this never happens.
    +-            while (addPendingRelease(-1) > 0) {
    +-                __sync_fetch_and_sub(&mRefCount, 1);
    +-            }
    +-            addPendingRelease(1);
    +-        }
    ++        // Legacy contract for MediaBuffer without a MediaBufferGroup.
    +         CHECK_EQ(mRefCount, 0);
    +         delete this;
    +         return;
    +@@ -205,10 +198,6 @@ void MediaBuffer::setObserver(MediaBufferObserver *observer) {
    +     mObserver = observer;
    + }
    + 
    +-int MediaBuffer::refcount() const {
    +-    return mRefCount;
    +-}
    +-
    + MediaBuffer *MediaBuffer::clone() {
    +     CHECK(mGraphicBuffer == NULL);
    + 
    +diff --git a/media/libstagefright/foundation/MediaBufferGroup.cpp b/media/libstagefright/foundation/MediaBufferGroup.cpp
    +index cb78879..1334f93 100644
    +--- a/media/libstagefright/foundation/MediaBufferGroup.cpp
    ++++ b/media/libstagefright/foundation/MediaBufferGroup.cpp
    +@@ -51,7 +51,7 @@ MediaBufferGroup::MediaBufferGroup(size_t buffers, size_t buffer_size, size_t gr
    + 
    +         for (size_t i = 0; i < buffers; ++i) {
    +             sp<IMemory> mem = memoryDealer->allocate(augmented_size);
    +-            if (mem.get() == nullptr) {
    ++            if (mem.get() == nullptr || mem->pointer() == nullptr) {
    +                 ALOGW("Only allocated %zu shared buffers of size %zu", i, buffer_size);
    +                 break;
    +             }
    +@@ -76,11 +76,24 @@ MediaBufferGroup::MediaBufferGroup(size_t buffers, size_t buffer_size, size_t gr
    + 
    + MediaBufferGroup::~MediaBufferGroup() {
    +     for (MediaBuffer *buffer : mBuffers) {
    +-        buffer->resolvePendingRelease();
    +-        // If we don't release it, perhaps noone will release it.
    +-        LOG_ALWAYS_FATAL_IF(buffer->refcount() != 0,
    +-                "buffer refcount %p = %d != 0", buffer, buffer->refcount());
    +-        // actually delete it.
    ++        if (buffer->refcount() != 0) {
    ++            const int localRefcount = buffer->localRefcount();
    ++            const int remoteRefcount = buffer->remoteRefcount();
    ++
    ++            // Fatal if we have a local refcount.
    ++            LOG_ALWAYS_FATAL_IF(localRefcount != 0,
    ++                    "buffer(%p) localRefcount %d != 0, remoteRefcount %d",
    ++                    buffer, localRefcount, remoteRefcount);
    ++
    ++            // Log an error if we have a remaining remote refcount,
    ++            // as the remote process may have died or may have inappropriate behavior.
    ++            // The shared memory associated with the MediaBuffer will
    ++            // automatically be reclaimed when there are no remaining fds
    ++            // associated with it.
    ++            ALOGE("buffer(%p) has residual remoteRefcount %d",
    ++                    buffer, remoteRefcount);
     +        }
    -+
    -+        default:
    -+            return ERROR_UNSUPPORTED;
    -+    }
    ++        // gracefully delete.
    +         buffer->setObserver(nullptr);
    +         buffer->release();
    +     }
    +@@ -94,32 +107,11 @@ void MediaBufferGroup::add_buffer(MediaBuffer *buffer) {
    +     // optionally: mGrowthLimit = max(mGrowthLimit, mBuffers.size());
    + }
    + 
    +-void MediaBufferGroup::gc(size_t freeBuffers) {
    +-    Mutex::Autolock autoLock(mLock);
    +-
    +-    size_t freeCount = 0;
    +-    for (auto it = mBuffers.begin(); it != mBuffers.end(); ) {
    +-        (*it)->resolvePendingRelease();
    +-        if ((*it)->isDeadObject()) {
    +-            // The MediaBuffer has been deleted, why is it in the MediaBufferGroup?
    +-            LOG_ALWAYS_FATAL("buffer(%p) has dead object with refcount %d",
    +-                    (*it), (*it)->refcount());
    +-        } else if ((*it)->refcount() == 0 && ++freeCount > freeBuffers) {
    +-            (*it)->setObserver(nullptr);
    +-            (*it)->release();
    +-            it = mBuffers.erase(it);
    +-        } else {
    +-            ++it;
    +-        }
    +-    }
    +-}
    +-
    + bool MediaBufferGroup::has_buffers() {
    +     if (mBuffers.size() < mGrowthLimit) {
    +         return true; // We can add more buffers internally.
    +     }
    +     for (MediaBuffer *buffer : mBuffers) {
    +-        buffer->resolvePendingRelease();
    +         if (buffer->refcount() == 0) {
    +             return true;
    +         }
    +@@ -135,7 +127,6 @@ status_t MediaBufferGroup::acquire_buffer(
    +         MediaBuffer *buffer = nullptr;
    +         auto free = mBuffers.end();
    +         for (auto it = mBuffers.begin(); it != mBuffers.end(); ++it) {
    +-            (*it)->resolvePendingRelease();
    +             if ((*it)->refcount() == 0) {
    +                 const size_t size = (*it)->size();
    +                 if (size >= requestedSize) {
    +@@ -188,6 +179,16 @@ status_t MediaBufferGroup::acquire_buffer(
    +     // Never gets here.
    + }
    + 
    ++status_t MediaBufferGroup::acquire_buffer(
    ++       MediaBuffer **out) {
    ++   return acquire_buffer(out, false, 0);
     +}
     +
    -+bool OMXNodeInstance::handleMessage(omx_message &msg) {
    -+    const sp<GraphicBufferSource>& bufferSource(getGraphicBufferSource());
    -+
    -+    if (msg.type == omx_message::FILL_BUFFER_DONE) {
    -+        OMX_BUFFERHEADERTYPE *buffer =
    -+            findBufferHeader(msg.u.extended_buffer_data.buffer, kPortIndexOutput);
    -+        if (buffer == NULL) {
    -+            ALOGE("b/25884056");
    -+            return false;
    -+        }
    -+
    -+        {
    -+            Mutex::Autolock _l(mDebugLock);
    -+            mOutputBuffersWithCodec.remove(buffer);
    -+
    -+            CLOG_BUMPED_BUFFER(
    -+                    FBD, WITH_STATS(FULL_BUFFER(
    -+                            msg.u.extended_buffer_data.buffer, buffer, msg.fenceFd)));
    -+
    -+            unbumpDebugLevel_l(kPortIndexOutput);
    -+        }
    -+
    -+        BufferMeta *buffer_meta =
    -+            static_cast<BufferMeta *>(buffer->pAppPrivate);
    -+
    -+        if (buffer->nOffset + buffer->nFilledLen < buffer->nOffset
    -+                || buffer->nOffset + buffer->nFilledLen > buffer->nAllocLen) {
    -+            CLOG_ERROR(onFillBufferDone, OMX_ErrorBadParameter,
    -+                    FULL_BUFFER(NULL, buffer, msg.fenceFd));
    -+        }
    -+        buffer_meta->CopyFromOMX(buffer);
    -+
    -+        if (bufferSource != NULL) {
    -+            // fix up the buffer info (especially timestamp) if needed
    -+            bufferSource->codecBufferFilled(buffer);
    -+
    -+            msg.u.extended_buffer_data.timestamp = buffer->nTimeStamp;
    -+        }
    -+    } else if (msg.type == omx_message::EMPTY_BUFFER_DONE) {
    -+        OMX_BUFFERHEADERTYPE *buffer =
    -+            findBufferHeader(msg.u.buffer_data.buffer, kPortIndexInput);
    -+        if (buffer == NULL) {
    -+            return false;
    -+        }
    -+
    -+        {
    -+            Mutex::Autolock _l(mDebugLock);
    -+            mInputBuffersWithCodec.remove(buffer);
    ++status_t MediaBufferGroup::acquire_buffer(
    ++        MediaBuffer **out, bool nonBlocking) {
    ++    return acquire_buffer(out, nonBlocking, 0);
    ++}
     +
    -+            CLOG_BUMPED_BUFFER(
    -+                    EBD, WITH_STATS(EMPTY_BUFFER(msg.u.buffer_data.buffer, buffer, msg.fenceFd)));
    + void MediaBufferGroup::signalBufferReturned(MediaBuffer *) {
    +     mCondition.signal();
    + }
    +diff --git a/media/libstagefright/foundation/MetaData.cpp b/media/libstagefright/foundation/MetaData.cpp
    +index b4abc60..a8965f0 100644
    +--- a/media/libstagefright/foundation/MetaData.cpp
    ++++ b/media/libstagefright/foundation/MetaData.cpp
    +@@ -392,8 +392,12 @@ void MetaData::dumpToLog() const {
    + }
    + 
    + status_t MetaData::writeToParcel(Parcel &parcel) {
    ++    status_t ret;
    +     size_t numItems = mItems.size();
    +-    parcel.writeUint32(uint32_t(numItems));
    ++    ret = parcel.writeUint32(uint32_t(numItems));
    ++    if (ret) {
    ++        return ret;
    ++    }
    +     for (size_t i = 0; i < numItems; i++) {
    +         int32_t key = mItems.keyAt(i);
    +         const typed_data &item = mItems.valueAt(i);
    +@@ -401,9 +405,32 @@ status_t MetaData::writeToParcel(Parcel &parcel) {
    +         const void *data;
    +         size_t size;
    +         item.getData(&type, &data, &size);
    +-        parcel.writeInt32(key);
    +-        parcel.writeUint32(type);
    +-        parcel.writeByteArray(size, (uint8_t*)data);
    ++        ret = parcel.writeInt32(key);
    ++        if (ret) {
    ++            return ret;
     +        }
    -+
    -+        if (bufferSource != NULL) {
    -+            // This is one of the buffers used exclusively by
    -+            // GraphicBufferSource.
    -+            // Don't dispatch a message back to ACodec, since it doesn't
    -+            // know that anyone asked to have the buffer emptied and will
    -+            // be very confused.
    -+            bufferSource->codecBufferEmptied(buffer, msg.fenceFd);
    -+            return true;
    ++        ret = parcel.writeUint32(type);
    ++        if (ret) {
    ++            return ret;
     +        }
    -+    }
    -+
    -+    return false;
    -+}
    -+
    -+void OMXNodeInstance::onMessages(std::list<omx_message> &messages) {
    -+    for (std::list<omx_message>::iterator it = messages.begin(); it != messages.end(); ) {
    -+        if (handleMessage(*it)) {
    -+            messages.erase(it++);
    ++        if (type == TYPE_NONE) {
    ++            android::Parcel::WritableBlob blob;
    ++            ret = parcel.writeUint32(static_cast<uint32_t>(size));
    ++            if (ret) {
    ++                return ret;
    ++            }
    ++            ret = parcel.writeBlob(size, false, &blob);
    ++            if (ret) {
    ++                return ret;
    ++            }
    ++            memcpy(blob.data(), data, size);
    ++            blob.release();
     +        } else {
    -+            ++it;
    ++            ret = parcel.writeByteArray(size, (uint8_t*)data);
    ++            if (ret) {
    ++                return ret;
    ++            }
     +        }
    -+    }
    -+
    -+    if (!messages.empty()) {
    -+        mObserver->onMessages(messages);
    -+    }
    -+}
    -+
    -+void OMXNodeInstance::onObserverDied(OMXMaster *master) {
    -+    ALOGE("!!! Observer died. Quickly, do something, ... anything...");
    -+
    -+    // Try to force shutdown of the node and hope for the best.
    -+    freeNode(master);
    -+}
    -+
    -+void OMXNodeInstance::onGetHandleFailed() {
    -+    delete this;
    -+}
    -+
    -+// OMXNodeInstance::OnEvent calls OMX::OnEvent, which then calls here.
    -+// Don't try to acquire mLock here -- in rare circumstances this will hang.
    -+void OMXNodeInstance::onEvent(
    -+        OMX_EVENTTYPE event, OMX_U32 arg1, OMX_U32 arg2) {
    -+    const char *arg1String = "??";
    -+    const char *arg2String = "??";
    -+    ADebug::Level level = ADebug::kDebugInternalState;
    -+
    -+    switch (event) {
    -+        case OMX_EventCmdComplete:
    -+            arg1String = asString((OMX_COMMANDTYPE)arg1);
    -+            switch (arg1) {
    -+                case OMX_CommandStateSet:
    -+                    arg2String = asString((OMX_STATETYPE)arg2);
    -+                    level = ADebug::kDebugState;
    +     }
    +     return OK;
    + }
    +@@ -422,8 +449,20 @@ status_t MetaData::updateFromParcel(const Parcel &parcel) {
    +             if (ret != OK) {
    +                 break;
    +             }
    +-            // copy data directly from Parcel storage, then advance position
    +-            setData(key, type, parcel.readInplace(size), size);
    ++            // copy data from Blob, which may be inline in Parcel storage,
    ++            // then advance position
    ++            if (type == TYPE_NONE) {
    ++                android::Parcel::ReadableBlob blob;
    ++                ret = parcel.readBlob(size, &blob);
    ++                if (ret != OK) {
     +                    break;
    -+                case OMX_CommandFlush:
    -+                case OMX_CommandPortEnable:
    -+                {
    -+                    // bump internal-state debug level for 2 input and output frames
    -+                    Mutex::Autolock _l(mDebugLock);
    -+                    bumpDebugLevel_l(2 /* numInputBuffers */, 2 /* numOutputBuffers */);
     +                }
    -+                // fall through
    -+                default:
    -+                    arg2String = portString(arg2);
    ++                setData(key, type, blob.data(), size);
    ++                blob.release();
    ++            } else {
    ++                // copy data directly from Parcel storage, then advance position
    ++                setData(key, type, parcel.readInplace(size), size);
     +            }
    -+            break;
    -+        case OMX_EventError:
    -+            arg1String = asString((OMX_ERRORTYPE)arg1);
    -+            level = ADebug::kDebugLifeCycle;
    -+            break;
    -+        case OMX_EventPortSettingsChanged:
    -+            arg2String = asString((OMX_INDEXEXTTYPE)arg2);
    -+            // fall through
    -+        default:
    -+            arg1String = portString(arg1);
    -+    }
    +          }
    + 
    +         return OK;
    +diff --git a/media/libstagefright/httplive/LiveSession.cpp b/media/libstagefright/httplive/LiveSession.cpp
    +index cebf95c..7abc019 100644
    +--- a/media/libstagefright/httplive/LiveSession.cpp
    ++++ b/media/libstagefright/httplive/LiveSession.cpp
    +@@ -467,28 +467,28 @@ status_t LiveSession::dequeueAccessUnit(
    +     return err;
    + }
    + 
    +-status_t LiveSession::getStreamFormat(StreamType stream, sp<AMessage> *format) {
    ++status_t LiveSession::getStreamFormatMeta(StreamType stream, sp<MetaData> *meta) {
    +     if (!(mStreamMask & stream)) {
    +         return UNKNOWN_ERROR;
    +     }
    + 
    +     sp<AnotherPacketSource> packetSource = mPacketSources.valueFor(stream);
    + 
    +-    sp<MetaData> meta = packetSource->getFormat();
    ++    *meta = packetSource->getFormat();
    + 
    +-    if (meta == NULL) {
    ++    if (*meta == NULL) {
    +         return -EWOULDBLOCK;
    +     }
    + 
    +     if (stream == STREAMTYPE_AUDIO) {
    +         // set AAC input buffer size to 32K bytes (256kbps x 1sec)
    +-        meta->setInt32(kKeyMaxInputSize, 32 * 1024);
    ++        (*meta)->setInt32(kKeyMaxInputSize, 32 * 1024);
    +     } else if (stream == STREAMTYPE_VIDEO) {
    +-        meta->setInt32(kKeyMaxWidth, mMaxWidth);
    +-        meta->setInt32(kKeyMaxHeight, mMaxHeight);
    ++        (*meta)->setInt32(kKeyMaxWidth, mMaxWidth);
    ++        (*meta)->setInt32(kKeyMaxHeight, mMaxHeight);
    +     }
    + 
    +-    return convertMetaDataToMessage(meta, format);
    ++    return OK;
    + }
    + 
    + sp<HTTPDownloader> LiveSession::getHTTPDownloader() {
    +diff --git a/media/libstagefright/httplive/LiveSession.h b/media/libstagefright/httplive/LiveSession.h
    +index 90d56d0..b600eba 100644
    +--- a/media/libstagefright/httplive/LiveSession.h
    ++++ b/media/libstagefright/httplive/LiveSession.h
    +@@ -75,7 +75,7 @@ struct LiveSession : public AHandler {
    +     int64_t calculateMediaTimeUs(int64_t firstTimeUs, int64_t timeUs, int32_t discontinuitySeq);
    +     status_t dequeueAccessUnit(StreamType stream, sp<ABuffer> *accessUnit);
    + 
    +-    status_t getStreamFormat(StreamType stream, sp<AMessage> *format);
    ++    status_t getStreamFormatMeta(StreamType stream, sp<MetaData> *meta);
    + 
    +     sp<HTTPDownloader> getHTTPDownloader();
    + 
    +diff --git a/media/libstagefright/include/MPEG4Extractor.h b/media/libstagefright/include/MPEG4Extractor.h
    +index 37c35e3..836cb08 100644
    +--- a/media/libstagefright/include/MPEG4Extractor.h
    ++++ b/media/libstagefright/include/MPEG4Extractor.h
    +@@ -93,7 +93,6 @@ private:
    + 
    +     sp<DataSource> mDataSource;
    +     status_t mInitCheck;
    +-    bool mHasVideo;
    +     uint32_t mHeaderTimescale;
    +     bool mIsQT;
    + 
    +diff --git a/media/libstagefright/mpeg2ts/ATSParser.cpp b/media/libstagefright/mpeg2ts/ATSParser.cpp
    +index b863d67..844479e 100644
    +--- a/media/libstagefright/mpeg2ts/ATSParser.cpp
    ++++ b/media/libstagefright/mpeg2ts/ATSParser.cpp
    +@@ -701,6 +701,10 @@ status_t ATSParser::Stream::parse(
    +         }
    + 
    +         mPayloadStarted = true;
    ++        // There should be at most 2 elements in |mPesStartOffsets|.
    ++        while (mPesStartOffsets.size() >= 2) {
    ++            mPesStartOffsets.erase(mPesStartOffsets.begin());
    ++        }
    +         mPesStartOffsets.push_back(offset);
    +     }
    + 
    +@@ -1104,15 +1108,20 @@ void ATSParser::Stream::onPayloadData(
    +             mSource->queueAccessUnit(accessUnit);
    +         }
    + 
    +-        if ((event != NULL) && !found && mQueue->getFormat() != NULL) {
    ++        // Every access unit has a pesStartOffset queued in |mPesStartOffsets|.
    ++        off64_t pesStartOffset = -1;
    ++        if (!mPesStartOffsets.empty()) {
    ++            pesStartOffset = *mPesStartOffsets.begin();
    ++            mPesStartOffsets.erase(mPesStartOffsets.begin());
    ++        }
     +
    -+    CLOGI_(level, onEvent, "%s(%x), %s(%x), %s(%x)",
    -+            asString(event), event, arg1String, arg1, arg2String, arg2);
    -+    const sp<GraphicBufferSource>& bufferSource(getGraphicBufferSource());
    ++        if (pesStartOffset >= 0 && (event != NULL) && !found && mQueue->getFormat() != NULL) {
    +             int32_t sync = 0;
    +             if (accessUnit->meta()->findInt32("isSync", &sync) && sync) {
    +                 int64_t timeUs;
    +                 if (accessUnit->meta()->findInt64("timeUs", &timeUs)) {
    +                     found = true;
    +-                    off64_t pesStartOffset = *mPesStartOffsets.begin();
    +                     event->init(pesStartOffset, mSource, timeUs);
    +-                    mPesStartOffsets.erase(mPesStartOffsets.begin());
    +                 }
    +             }
    +         }
    +diff --git a/media/libstagefright/omx/Android.mk b/media/libstagefright/omx/Android.mk
    +index e4fbd81..c262782 100644
    +--- a/media/libstagefright/omx/Android.mk
    ++++ b/media/libstagefright/omx/Android.mk
    +@@ -31,6 +31,18 @@ LOCAL_SHARED_LIBRARIES :=               \
    +         libstagefright_foundation       \
    +         libdl
    + 
    ++ifneq ($(TARGET_USES_MEDIA_EXTENSIONS),true)
    ++ifeq ($(TARGET_HAS_LEGACY_CAMERA_HAL1),true)
    ++LOCAL_CFLAGS += -DCAMCORDER_GRALLOC_SOURCE
    ++endif
    ++endif
     +
    -+    if (bufferSource != NULL
    -+            && event == OMX_EventCmdComplete
    -+            && arg1 == OMX_CommandStateSet
    -+            && arg2 == OMX_StateExecuting) {
    -+        bufferSource->omxExecuting();
    -+    }
    ++ifneq ($(TARGET_USES_MEDIA_EXTENSIONS),true)
    ++ifeq ($(TARGET_HAS_LEGACY_CAMERA_HAL1),true)
    ++LOCAL_CFLAGS += -DCAMCORDER_GRALLOC_SOURCE
    ++endif
    ++endif
     +
    -+    // allow configuration if we return to the loaded state
    -+    if (event == OMX_EventCmdComplete
    -+            && arg1 == OMX_CommandStateSet
    -+            && arg2 == OMX_StateLoaded) {
    -+        mSailed = false;
    -+    }
    -+}
    + LOCAL_MODULE:= libstagefright_omx
    + LOCAL_CFLAGS += -Werror -Wall
    + LOCAL_CLANG := true
    +diff --git a/media/libstagefright/omx/GraphicBufferSource.cpp b/media/libstagefright/omx/GraphicBufferSource.cpp
    +index e025653..50cc940 100644
    +--- a/media/libstagefright/omx/GraphicBufferSource.cpp
    ++++ b/media/libstagefright/omx/GraphicBufferSource.cpp
    +@@ -139,7 +139,6 @@ GraphicBufferSource::GraphicBufferSource(
    +     mRepeatLastFrameTimestamp(-1ll),
    +     mLatestBufferId(-1),
    +     mLatestBufferFrameNum(0),
    +-    mLatestBufferUseCount(0),
    +     mLatestBufferFence(Fence::NO_FENCE),
    +     mRepeatBufferDeferred(false),
    +     mTimePerCaptureUs(-1ll),
    +@@ -398,12 +397,16 @@ void GraphicBufferSource::codecBufferEmptied(OMX_BUFFERHEADERTYPE* header, int f
    +     sp<Fence> fence = new Fence(fenceFd);
    +     if (mBufferSlot[id] != NULL &&
    +         mBufferSlot[id]->handle == codecBuffer.mGraphicBuffer->handle) {
    +-        ALOGV("cbi %d matches bq slot %d, handle=%p",
    +-                cbi, id, mBufferSlot[id]->handle);
    ++        mBufferUseCount[id]--;
    + 
    +-        if (id == mLatestBufferId) {
    +-            CHECK_GT(mLatestBufferUseCount--, 0);
    +-        } else {
    ++        ALOGV("codecBufferEmptied: slot=%d, cbi=%d, useCount=%d, handle=%p",
    ++                id, cbi, mBufferUseCount[id], mBufferSlot[id]->handle);
    ++
    ++        if (mBufferUseCount[id] < 0) {
    ++            ALOGW("mBufferUseCount for bq slot %d < 0 (=%d)", id, mBufferUseCount[id]);
    ++            mBufferUseCount[id] = 0;
    ++        }
    ++        if (id != mLatestBufferId && mBufferUseCount[id] == 0) {
    +             releaseBuffer(id, codecBuffer.mFrameNumber, mBufferSlot[id], fence);
    +         }
    +     } else {
    +@@ -614,6 +617,7 @@ bool GraphicBufferSource::fillCodecBuffer_l() {
    +     if (item.mGraphicBuffer != NULL) {
    +         ALOGV("fillCodecBuffer_l: setting mBufferSlot %d", item.mSlot);
    +         mBufferSlot[item.mSlot] = item.mGraphicBuffer;
    ++        mBufferUseCount[item.mSlot] = 0;
    +     }
    + 
    +     if (item.mDataSpace != mLastDataSpace) {
    +@@ -699,7 +703,7 @@ bool GraphicBufferSource::repeatLatestBuffer_l() {
    +         return false;
    +     }
    + 
    +-    ++mLatestBufferUseCount;
    ++    ++mBufferUseCount[item.mSlot];
    + 
    +     /* repeat last frame up to kRepeatLastFrameCount times.
    +      * in case of static scene, a single repeat might not get rid of encoder
    +@@ -723,7 +727,7 @@ void GraphicBufferSource::setLatestBuffer_l(
    +     ALOGV("setLatestBuffer_l");
    + 
    +     if (mLatestBufferId >= 0) {
    +-        if (mLatestBufferUseCount == 0) {
    ++        if (mBufferUseCount[mLatestBufferId] == 0) {
    +             releaseBuffer(mLatestBufferId, mLatestBufferFrameNum,
    +                     mBufferSlot[mLatestBufferId], mLatestBufferFence);
    +             // mLatestBufferFence will be set to new fence just below
    +@@ -734,7 +738,13 @@ void GraphicBufferSource::setLatestBuffer_l(
    +     mLatestBufferFrameNum = item.mFrameNumber;
    +     mRepeatLastFrameTimestamp = item.mTimestamp + mRepeatAfterUs * 1000;
    + 
    +-    mLatestBufferUseCount = dropped ? 0 : 1;
    ++    if (!dropped) {
    ++        ++mBufferUseCount[item.mSlot];
    ++    }
    ++
    ++    ALOGV("setLatestBuffer_l: slot=%d, useCount=%d",
    ++            item.mSlot, mBufferUseCount[item.mSlot]);
    ++
    +     mRepeatBufferDeferred = false;
    +     mRepeatLastFrameCount = kRepeatLastFrameCount;
    +     mLatestBufferFence = item.mFence;
    +@@ -827,11 +837,11 @@ int64_t GraphicBufferSource::getTimestamp(const BufferItem &item) {
    +                 int64_t timestampGapUs = originalTimeUs - mPrevOriginalTimeUs;
    +                 timeUs = (timestampGapUs < mMaxTimestampGapUs ?
    +                     timestampGapUs : mMaxTimestampGapUs) + mPrevModifiedTimeUs;
    +-                mOriginalTimeUs.add(timeUs, originalTimeUs);
    +-                ALOGV("IN  timestamp: %lld -> %lld",
    +-                    static_cast<long long>(originalTimeUs),
    +-                    static_cast<long long>(timeUs));
    +             }
    ++            mOriginalTimeUs.add(timeUs, originalTimeUs);
    ++            ALOGV("IN  timestamp: %lld -> %lld",
    ++                static_cast<long long>(originalTimeUs),
    ++                static_cast<long long>(timeUs));
    +         }
    + 
    +         mPrevOriginalTimeUs = originalTimeUs;
    +@@ -842,7 +852,7 @@ int64_t GraphicBufferSource::getTimestamp(const BufferItem &item) {
    + }
    + 
    + status_t GraphicBufferSource::submitBuffer_l(const BufferItem &item, int cbi) {
    +-    ALOGV("submitBuffer_l cbi=%d", cbi);
    ++    ALOGV("submitBuffer_l: slot=%d, cbi=%d", item.mSlot, cbi);
    + 
    +     int64_t timeUs = getTimestamp(item);
    +     if (timeUs < 0ll) {
    +@@ -935,6 +945,7 @@ int GraphicBufferSource::findMatchingCodecBuffer_l(
    + void GraphicBufferSource::releaseBuffer(
    +         int &id, uint64_t frameNum,
    +         const sp<GraphicBuffer> buffer, const sp<Fence> &fence) {
    ++    ALOGV("releaseBuffer: slot=%d", id);
    +     if (mIsPersistent) {
    +         mConsumer->detachBuffer(id);
    +         mBufferSlot[id] = NULL;
    +@@ -978,6 +989,7 @@ void GraphicBufferSource::onFrameAvailable(const BufferItem& /*item*/) {
    +             if (item.mGraphicBuffer != NULL) {
    +                 ALOGV("onFrameAvailable: setting mBufferSlot %d", item.mSlot);
    +                 mBufferSlot[item.mSlot] = item.mGraphicBuffer;
    ++                mBufferUseCount[item.mSlot] = 0;
    +             }
    + 
    +             releaseBuffer(item.mSlot, item.mFrameNumber,
    +@@ -1011,6 +1023,7 @@ void GraphicBufferSource::onBuffersReleased() {
    +     for (int i = 0; i < BufferQueue::NUM_BUFFER_SLOTS; i++) {
    +         if ((slotMask & 0x01) != 0) {
    +             mBufferSlot[i] = NULL;
    ++            mBufferUseCount[i] = 0;
    +         }
    +         slotMask >>= 1;
    +     }
    +diff --git a/media/libstagefright/omx/GraphicBufferSource.h b/media/libstagefright/omx/GraphicBufferSource.h
    +index 30bfddb..aa4ceb3 100644
    +--- a/media/libstagefright/omx/GraphicBufferSource.h
    ++++ b/media/libstagefright/omx/GraphicBufferSource.h
    +@@ -295,6 +295,7 @@ private:
    +     // is done processing a GraphicBuffer, we can use this to map back
    +     // to a slot number.
    +     sp<GraphicBuffer> mBufferSlot[BufferQueue::NUM_BUFFER_SLOTS];
    ++    int32_t mBufferUseCount[BufferQueue::NUM_BUFFER_SLOTS];
    + 
    +     // Tracks codec buffers.
    +     Vector<CodecBuffer> mCodecBuffers;
    +@@ -327,7 +328,6 @@ private:
    + 
    +     int mLatestBufferId;
    +     uint64_t mLatestBufferFrameNum;
    +-    int32_t mLatestBufferUseCount;
    +     sp<Fence> mLatestBufferFence;
    + 
    +     // The previous buffer should've been repeated but
    +diff --git a/media/libstagefright/omx/OMXMaster.cpp b/media/libstagefright/omx/OMXMaster.cpp
    +index 6132a2c..7f0d270 100644
    +--- a/media/libstagefright/omx/OMXMaster.cpp
    ++++ b/media/libstagefright/omx/OMXMaster.cpp
    +@@ -69,6 +69,7 @@ OMXMaster::~OMXMaster() {
    + 
    + void OMXMaster::addVendorPlugin() {
    +     addPlugin("libstagefrighthw.so");
    ++    addPlugin("libsomxcore.so");
    + }
    + 
    + void OMXMaster::addPlugin(const char *libname) {
    +diff --git a/media/libstagefright/omx/OMXNodeInstance.cpp b/media/libstagefright/omx/OMXNodeInstance.cpp
    +index 395dad8..3cf9c3b 100644
    +--- a/media/libstagefright/omx/OMXNodeInstance.cpp
    ++++ b/media/libstagefright/omx/OMXNodeInstance.cpp
    +@@ -431,7 +431,7 @@ bool OMXNodeInstance::isProhibitedIndex_l(OMX_INDEXTYPE index) {
    +             || (index > (OMX_INDEXTYPE)OMX_IndexExtAudioStartUnused
    +                     && index <= (OMX_INDEXTYPE)OMX_IndexParamAudioProfileQuerySupported)
    +             || (index > (OMX_INDEXTYPE)OMX_IndexExtVideoStartUnused
    +-                    && index <= (OMX_INDEXTYPE)OMX_IndexConfigAndroidIntraRefresh)
    ++                    && index <= (OMX_INDEXTYPE)OMX_IndexConfigAndroidVideoTemporalLayering)
    +             || (index > (OMX_INDEXTYPE)OMX_IndexExtOtherStartUnused
    +                     && index <= (OMX_INDEXTYPE)OMX_IndexParamConsumerUsageBits)) {
    +         return false;
    +@@ -795,7 +795,11 @@ status_t OMXNodeInstance::useBuffer(
    +     // metadata buffers are not connected cross process
    +     // use a backup buffer instead of the actual buffer
    +     BufferMeta *buffer_meta;
    ++#ifdef CAMCORDER_GRALLOC_SOURCE
    ++    bool useBackup = false;
    ++#else
    +     bool useBackup = mMetadataType[portIndex] != kMetadataBufferTypeInvalid;
    ++#endif
    +     OMX_U8 *data = static_cast<OMX_U8 *>(params->pointer());
    +     // allocate backup buffer
    +     if (useBackup) {
    +@@ -1286,7 +1290,11 @@ status_t OMXNodeInstance::allocateBufferWithBackup(
    +     }
    + 
    +     // metadata buffers are not connected cross process; only copy if not meta
    ++#ifdef CAMCORDER_GRALLOC_SOURCE
    ++    bool copy = true;
    ++#else
    +     bool copy = mMetadataType[portIndex] == kMetadataBufferTypeInvalid;
    ++#endif
    + 
    +     BufferMeta *buffer_meta = new BufferMeta(
    +             params, portIndex,
    +@@ -1404,10 +1412,30 @@ status_t OMXNodeInstance::emptyBuffer(
    +     BufferMeta *buffer_meta =
    +         static_cast<BufferMeta *>(header->pAppPrivate);
    + 
    ++#ifndef CAMCORDER_GRALLOC_SOURCE
    +     // set up proper filled length if component is configured for gralloc metadata mode
    +     // ignore rangeOffset in this case (as client may be assuming ANW meta buffers).
    +     if (mMetadataType[kPortIndexInput] == kMetadataBufferTypeGrallocSource) {
    +         header->nFilledLen = rangeLength ? sizeof(VideoGrallocMetadata) : 0;
    ++#else
    ++    sp<ABuffer> backup = buffer_meta->getBuffer(header, true /* backup */, false /* limit */);
    ++    sp<ABuffer> codec = buffer_meta->getBuffer(header, false /* backup */, false /* limit */);
     +
    -+// static
    -+OMX_ERRORTYPE OMXNodeInstance::OnEvent(
    -+        OMX_IN OMX_HANDLETYPE /* hComponent */,
    -+        OMX_IN OMX_PTR pAppData,
    -+        OMX_IN OMX_EVENTTYPE eEvent,
    -+        OMX_IN OMX_U32 nData1,
    -+        OMX_IN OMX_U32 nData2,
    -+        OMX_IN OMX_PTR pEventData) {
    -+    if (pAppData == NULL) {
    -+        ALOGE("b/25884056");
    -+        return OMX_ErrorBadParameter;
    -+    }
    -+    OMXNodeInstance *instance = static_cast<OMXNodeInstance *>(pAppData);
    -+    if (instance->mDying) {
    -+        return OMX_ErrorNone;
    -+    }
    -+    return instance->owner()->OnEvent(
    -+            instance->nodeID(), eEvent, nData1, nData2, pEventData);
    -+}
    ++    // convert incoming ANW meta buffers if component is configured for gralloc metadata mode
    ++    // ignore rangeOffset in this case
    ++    if (mMetadataType[kPortIndexInput] == kMetadataBufferTypeGrallocSource
    ++            && backup->capacity() >= sizeof(VideoNativeMetadata)
    ++            && codec->capacity() >= sizeof(VideoGrallocMetadata)
    ++            && ((VideoNativeMetadata *)backup->base())->eType
    ++                    == kMetadataBufferTypeANWBuffer) {
    ++        VideoNativeMetadata &backupMeta = *(VideoNativeMetadata *)backup->base();
    ++        VideoGrallocMetadata &codecMeta = *(VideoGrallocMetadata *)codec->base();
    ++        CLOG_BUFFER(emptyBuffer, "converting ANWB %p to handle %p",
    ++                backupMeta.pBuffer, backupMeta.pBuffer->handle);
    ++        codecMeta.pHandle = backupMeta.pBuffer != NULL ? backupMeta.pBuffer->handle : NULL;
    ++        codecMeta.eType = kMetadataBufferTypeGrallocSource;
    ++        header->nFilledLen = rangeLength ? sizeof(codecMeta) : 0;
    ++#endif
    +         header->nOffset = 0;
    +     } else {
    +         // rangeLength and rangeOffset must be a subset of the allocated data in the buffer.
    +diff --git a/media/libstagefright/omx/SimpleSoftOMXComponent.cpp b/media/libstagefright/omx/SimpleSoftOMXComponent.cpp
    +index 13afd45..7c975f7 100644
    +--- a/media/libstagefright/omx/SimpleSoftOMXComponent.cpp
    ++++ b/media/libstagefright/omx/SimpleSoftOMXComponent.cpp
    +@@ -426,7 +426,19 @@ void SimpleSoftOMXComponent::onSendCommand(
    + }
    + 
    + void SimpleSoftOMXComponent::onChangeState(OMX_STATETYPE state) {
    ++    ALOGV("%p requesting change from %d to %d", this, mState, state);
    +     // We shouldn't be in a state transition already.
     +
    -+// static
    -+OMX_ERRORTYPE OMXNodeInstance::OnEmptyBufferDone(
    -+        OMX_IN OMX_HANDLETYPE /* hComponent */,
    -+        OMX_IN OMX_PTR pAppData,
    -+        OMX_IN OMX_BUFFERHEADERTYPE* pBuffer) {
    -+    if (pAppData == NULL) {
    -+        ALOGE("b/25884056");
    -+        return OMX_ErrorBadParameter;
    ++    if (mState == OMX_StateLoaded
    ++            && mTargetState == OMX_StateIdle
    ++            && state == OMX_StateLoaded) {
    ++        // OMX specifically allows "canceling" a state transition from loaded
    ++        // to idle. Pretend we made it to idle, and go back to loaded
    ++        ALOGV("load->idle canceled");
    ++        mState = mTargetState = OMX_StateIdle;
    ++        state = OMX_StateLoaded;
     +    }
    -+    OMXNodeInstance *instance = static_cast<OMXNodeInstance *>(pAppData);
    -+    if (instance->mDying) {
    -+        return OMX_ErrorNone;
    -+    }
    -+    int fenceFd = instance->retrieveFenceFromMeta_l(pBuffer, kPortIndexOutput);
    -+    return instance->owner()->OnEmptyBufferDone(instance->nodeID(),
    -+            instance->findBufferID(pBuffer), pBuffer, fenceFd);
    -+}
     +
    -+// static
    -+OMX_ERRORTYPE OMXNodeInstance::OnFillBufferDone(
    -+        OMX_IN OMX_HANDLETYPE /* hComponent */,
    -+        OMX_IN OMX_PTR pAppData,
    -+        OMX_IN OMX_BUFFERHEADERTYPE* pBuffer) {
    -+    if (pAppData == NULL) {
    -+        ALOGE("b/25884056");
    -+        return OMX_ErrorBadParameter;
    -+    }
    -+    OMXNodeInstance *instance = static_cast<OMXNodeInstance *>(pAppData);
    -+    if (instance->mDying) {
    -+        return OMX_ErrorNone;
    +     CHECK_EQ((int)mState, (int)mTargetState);
    + 
    +     switch (mState) {
    +@@ -606,6 +618,7 @@ void SimpleSoftOMXComponent::checkTransitions() {
    +         }
    + 
    +         if (transitionComplete) {
    ++            ALOGV("state transition from %d to %d complete", mState, mTargetState);
    +             mState = mTargetState;
    + 
    +             if (mState == OMX_StateLoaded) {
    +@@ -613,6 +626,8 @@ void SimpleSoftOMXComponent::checkTransitions() {
    +             }
    + 
    +             notify(OMX_EventCmdComplete, OMX_CommandStateSet, mState, NULL);
    ++        } else {
    ++            ALOGV("state transition from %d to %d not yet complete", mState, mTargetState);
    +         }
    +     }
    + 
    +diff --git a/media/libstagefright/rtsp/MyHandler.h b/media/libstagefright/rtsp/MyHandler.h
    +index 42a1182..76e2e6e 100644
    +--- a/media/libstagefright/rtsp/MyHandler.h
    ++++ b/media/libstagefright/rtsp/MyHandler.h
    +@@ -1408,6 +1408,11 @@ struct MyHandler : public AHandler {
    +         msg->post((mKeepAliveTimeoutUs * 9) / 10);
    +     }
    + 
    ++    void cancelAccessUnitTimeoutCheck() {
    ++        ALOGV("cancelAccessUnitTimeoutCheck");
    ++        ++mCheckGeneration;
     +    }
    -+    int fenceFd = instance->retrieveFenceFromMeta_l(pBuffer, kPortIndexOutput);
    -+    return instance->owner()->OnFillBufferDone(instance->nodeID(),
    -+            instance->findBufferID(pBuffer), pBuffer, fenceFd);
    -+}
     +
    -+void OMXNodeInstance::addActiveBuffer(OMX_U32 portIndex, OMX::buffer_id id) {
    -+    ActiveBuffer active;
    -+    active.mPortIndex = portIndex;
    -+    active.mID = id;
    -+    mActiveBuffers.push(active);
    -+
    -+    if (portIndex < NELEM(mNumPortBuffers)) {
    -+        ++mNumPortBuffers[portIndex];
    +     void postAccessUnitTimeoutCheck() {
    +         if (mCheckPending) {
    +             return;
    +@@ -1792,14 +1797,8 @@ private:
    + 
    +             // Time is now established, lets start timestamping immediately
    +             for (size_t i = 0; i < mTracks.size(); ++i) {
    +-                TrackInfo *trackInfo = &mTracks.editItemAt(i);
    +-                while (!trackInfo->mPackets.empty()) {
    +-                    sp<ABuffer> accessUnit = *trackInfo->mPackets.begin();
    +-                    trackInfo->mPackets.erase(trackInfo->mPackets.begin());
    +-
    +-                    if (addMediaTimestamp(i, trackInfo, accessUnit)) {
    +-                        postQueueAccessUnit(i, accessUnit);
    +-                    }
    ++                if (OK != processAccessUnitQueue(i)) {
    ++                    return;
    +                 }
    +             }
    +             for (size_t i = 0; i < mTracks.size(); ++i) {
    +@@ -1812,26 +1811,8 @@ private:
    +         }
    +     }
    + 
    +-    void onAccessUnitComplete(
    +-            int32_t trackIndex, const sp<ABuffer> &accessUnit) {
    +-        ALOGV("onAccessUnitComplete track %d", trackIndex);
    +-
    ++    status_t processAccessUnitQueue(int32_t trackIndex) {
    +         TrackInfo *track = &mTracks.editItemAt(trackIndex);
    +-        if(!mPlayResponseParsed){
    +-            uint32_t seqNum = (uint32_t)accessUnit->int32Data();
    +-            ALOGI("play response is not parsed, storing accessunit %u", seqNum);
    +-            track->mPackets.push_back(accessUnit);
    +-            return;
    +-        }
    +-
    +-        handleFirstAccessUnit();
    +-
    +-        if (!mAllTracksHaveTime) {
    +-            ALOGV("storing accessUnit, no time established yet");
    +-            track->mPackets.push_back(accessUnit);
    +-            return;
    +-        }
    +-
    +         while (!track->mPackets.empty()) {
    +             sp<ABuffer> accessUnit = *track->mPackets.begin();
    +             track->mPackets.erase(track->mPackets.begin());
    +@@ -1842,27 +1823,29 @@ private:
    +                 // by ARTPSource. Only the low 16 bits of seq in RTP-Info of reply of
    +                 // RTSP "PLAY" command should be used to detect the first RTP packet
    +                 // after seeking.
    +-                if (track->mAllowedStaleAccessUnits > 0) {
    +-                    uint32_t seqNum16 = seqNum & 0xffff;
    +-                    uint32_t firstSeqNumInSegment16 = track->mFirstSeqNumInSegment & 0xffff;
    +-                    if (seqNum16 > firstSeqNumInSegment16 + kMaxAllowedStaleAccessUnits
    +-                            || seqNum16 < firstSeqNumInSegment16) {
    +-                        // Not the first rtp packet of the stream after seeking, discarding.
    +-                        track->mAllowedStaleAccessUnits--;
    +-                        ALOGV("discarding stale access unit (0x%x : 0x%x)",
    +-                             seqNum, track->mFirstSeqNumInSegment);
    +-                        continue;
    ++                if (mSeekable) {
    ++                    if (track->mAllowedStaleAccessUnits > 0) {
    ++                        uint32_t seqNum16 = seqNum & 0xffff;
    ++                        uint32_t firstSeqNumInSegment16 = track->mFirstSeqNumInSegment & 0xffff;
    ++                        if (seqNum16 > firstSeqNumInSegment16 + kMaxAllowedStaleAccessUnits
    ++                                || seqNum16 < firstSeqNumInSegment16) {
    ++                            // Not the first rtp packet of the stream after seeking, discarding.
    ++                            track->mAllowedStaleAccessUnits--;
    ++                            ALOGV("discarding stale access unit (0x%x : 0x%x)",
    ++                                 seqNum, track->mFirstSeqNumInSegment);
    ++                            continue;
    ++                        }
    ++                        ALOGW_IF(seqNum16 != firstSeqNumInSegment16,
    ++                                "Missing the first packet(%u), now take packet(%u) as first one",
    ++                                track->mFirstSeqNumInSegment, seqNum);
    ++                    } else { // track->mAllowedStaleAccessUnits <= 0
    ++                        mNumAccessUnitsReceived = 0;
    ++                        ALOGW_IF(track->mAllowedStaleAccessUnits == 0,
    ++                             "Still no first rtp packet after %d stale ones",
    ++                             kMaxAllowedStaleAccessUnits);
    ++                        track->mAllowedStaleAccessUnits = -1;
    ++                        return UNKNOWN_ERROR;
    +                     }
    +-                    ALOGW_IF(seqNum16 != firstSeqNumInSegment16,
    +-                            "Missing the first packet(%u), now take packet(%u) as first one",
    +-                            track->mFirstSeqNumInSegment, seqNum);
    +-                } else { // track->mAllowedStaleAccessUnits <= 0
    +-                    mNumAccessUnitsReceived = 0;
    +-                    ALOGW_IF(track->mAllowedStaleAccessUnits == 0,
    +-                         "Still no first rtp packet after %d stale ones",
    +-                         kMaxAllowedStaleAccessUnits);
    +-                    track->mAllowedStaleAccessUnits = -1;
    +-                    return;
    +                 }
    + 
    +                 // Now found the first rtp packet of the stream after seeking.
    +@@ -1876,14 +1859,35 @@ private:
    +                 continue;
    +             }
    + 
    +-
    +             if (addMediaTimestamp(trackIndex, track, accessUnit)) {
    +                 postQueueAccessUnit(trackIndex, accessUnit);
    +             }
    +         }
    ++        return OK;
     +    }
    -+}
    -+
    -+void OMXNodeInstance::removeActiveBuffer(
    -+        OMX_U32 portIndex, OMX::buffer_id id) {
    -+    for (size_t i = 0; i < mActiveBuffers.size(); ++i) {
    -+        if (mActiveBuffers[i].mPortIndex == portIndex
    -+                && mActiveBuffers[i].mID == id) {
    -+            mActiveBuffers.removeItemsAt(i);
    -+
    -+            if (portIndex < NELEM(mNumPortBuffers)) {
    -+                --mNumPortBuffers[portIndex];
    -+            }
    + 
    +-        if (addMediaTimestamp(trackIndex, track, accessUnit)) {
    +-            postQueueAccessUnit(trackIndex, accessUnit);
    ++    void onAccessUnitComplete(
    ++            int32_t trackIndex, const sp<ABuffer> &accessUnit) {
    ++        TrackInfo *track = &mTracks.editItemAt(trackIndex);
    ++        track->mPackets.push_back(accessUnit);
    ++
    ++        uint32_t seqNum = (uint32_t)accessUnit->int32Data();
    ++        ALOGV("onAccessUnitComplete track %d storing accessunit %u", trackIndex, seqNum);
    ++
    ++        if(!mPlayResponseParsed){
    ++            ALOGV("play response is not parsed");
     +            return;
     +        }
    -+    }
     +
    -+     CLOGW("Attempt to remove an active buffer [%#x] we know nothing about...", id);
    -+}
    -+
    -+void OMXNodeInstance::freeActiveBuffers() {
    -+    // Make sure to count down here, as freeBuffer will in turn remove
    -+    // the active buffer from the vector...
    -+    for (size_t i = mActiveBuffers.size(); i > 0;) {
    -+        i--;
    -+        freeBuffer(mActiveBuffers[i].mPortIndex, mActiveBuffers[i].mID);
    -+    }
    -+}
    ++        handleFirstAccessUnit();
     +
    -+OMX::buffer_id OMXNodeInstance::makeBufferID(OMX_BUFFERHEADERTYPE *bufferHeader) {
    -+    if (bufferHeader == NULL) {
    -+        return 0;
    -+    }
    -+    Mutex::Autolock autoLock(mBufferIDLock);
    -+    OMX::buffer_id buffer;
    -+    do { // handle the very unlikely case of ID overflow
    -+        if (++mBufferIDCount == 0) {
    -+            ++mBufferIDCount;
    ++        if (!mAllTracksHaveTime) {
    ++            ALOGV("storing accessUnit, no time established yet");
    ++            return;
     +        }
    -+        buffer = (OMX::buffer_id)mBufferIDCount;
    -+    } while (mBufferIDToBufferHeader.indexOfKey(buffer) >= 0);
    -+    mBufferIDToBufferHeader.add(buffer, bufferHeader);
    -+    mBufferHeaderToBufferID.add(bufferHeader, buffer);
    -+    return buffer;
    -+}
    -+
    -+OMX_BUFFERHEADERTYPE *OMXNodeInstance::findBufferHeader(
    -+        OMX::buffer_id buffer, OMX_U32 portIndex) {
    -+    if (buffer == 0) {
    -+        return NULL;
    -+    }
    -+    Mutex::Autolock autoLock(mBufferIDLock);
    -+    ssize_t index = mBufferIDToBufferHeader.indexOfKey(buffer);
    -+    if (index < 0) {
    -+        CLOGW("findBufferHeader: buffer %u not found", buffer);
    -+        return NULL;
    -+    }
    -+    OMX_BUFFERHEADERTYPE *header = mBufferIDToBufferHeader.valueAt(index);
    -+    BufferMeta *buffer_meta =
    -+        static_cast<BufferMeta *>(header->pAppPrivate);
    -+    if (buffer_meta->getPortIndex() != portIndex) {
    -+        CLOGW("findBufferHeader: buffer %u found but with incorrect port index.", buffer);
    -+        android_errorWriteLog(0x534e4554, "28816827");
    -+        return NULL;
    -+    }
    -+    return header;
    -+}
     +
    -+OMX::buffer_id OMXNodeInstance::findBufferID(OMX_BUFFERHEADERTYPE *bufferHeader) {
    -+    if (bufferHeader == NULL) {
    -+        return 0;
    -+    }
    -+    Mutex::Autolock autoLock(mBufferIDLock);
    -+    ssize_t index = mBufferHeaderToBufferID.indexOfKey(bufferHeader);
    -+    if (index < 0) {
    -+        CLOGW("findBufferID: bufferHeader %p not found", bufferHeader);
    -+        return 0;
    -+    }
    -+    return mBufferHeaderToBufferID.valueAt(index);
    -+}
    -+
    -+void OMXNodeInstance::invalidateBufferID(OMX::buffer_id buffer) {
    -+    if (buffer == 0) {
    -+        return;
    -+    }
    -+    Mutex::Autolock autoLock(mBufferIDLock);
    -+    ssize_t index = mBufferIDToBufferHeader.indexOfKey(buffer);
    -+    if (index < 0) {
    -+        CLOGW("invalidateBufferID: buffer %u not found", buffer);
    -+        return;
    -+    }
    -+    mBufferHeaderToBufferID.removeItem(mBufferIDToBufferHeader.valueAt(index));
    -+    mBufferIDToBufferHeader.removeItemsAt(index);
    -+}
    -+
    -+}  // namespace android
    ++        if (OK != processAccessUnitQueue(trackIndex)) {
    ++            return;
    +         }
    + 
    +         if (track->mEOSReceived) {
     diff --git a/media/mediaserver/Android.mk b/media/mediaserver/Android.mk
     index 1738df8..c2b9c1f 100644
     --- a/media/mediaserver/Android.mk
    @@ -2441,6 +2869,716 @@ index ecddc48..0abe6ac 100644
          registerExtensions();
          ProcessState::self()->startThreadPool();
          IPCThreadState::self()->joinThreadPool();
    +diff --git a/media/mtp/MtpServer.cpp b/media/mtp/MtpServer.cpp
    +index 90f1a77..e39dcdd 100644
    +--- a/media/mtp/MtpServer.cpp
    ++++ b/media/mtp/MtpServer.cpp
    +@@ -927,6 +927,10 @@ MtpResponseCode MtpServer::doSendObjectInfo() {
    +     if (!mData.getUInt32(temp32)) return MTP_RESPONSE_INVALID_PARAMETER;  // sequence number
    +     MtpStringBuffer name, created, modified;
    +     if (!mData.getString(name)) return MTP_RESPONSE_INVALID_PARAMETER;    // file name
    ++    if (name.getCharCount() == 0) {
    ++        ALOGE("empty name");
    ++        return MTP_RESPONSE_INVALID_PARAMETER;
    ++    }
    +     if (!mData.getString(created)) return MTP_RESPONSE_INVALID_PARAMETER;      // date created
    +     if (!mData.getString(modified)) return MTP_RESPONSE_INVALID_PARAMETER;     // date modified
    +     // keywords follow
    +diff --git a/media/ndk/NdkMediaExtractor.cpp b/media/ndk/NdkMediaExtractor.cpp
    +index 1118959..89f2d9c 100644
    +--- a/media/ndk/NdkMediaExtractor.cpp
    ++++ b/media/ndk/NdkMediaExtractor.cpp
    +@@ -148,7 +148,14 @@ media_status_t AMediaExtractor_unselectTrack(AMediaExtractor *mData, size_t idx)
    + EXPORT
    + bool AMediaExtractor_advance(AMediaExtractor *mData) {
    +     //ALOGV("advance");
    +-    return mData->mImpl->advance();
    ++    status_t err = mData->mImpl->advance();
    ++    if (err == ERROR_END_OF_STREAM) {
    ++        return false;
    ++    } else if (err != OK) {
    ++        ALOGE("sf error code: %d", err);
    ++        return false;
    ++    }
    ++    return true;
    + }
    + 
    + EXPORT
    +@@ -343,9 +350,9 @@ AMediaCodecCryptoInfo *AMediaExtractor_getSampleCryptoInfo(AMediaExtractor *ex)
    + 
    +     const void *key;
    +     size_t keysize;
    +-    if (meta->findData(kKeyCryptoIV, &type, &key, &keysize)) {
    ++    if (meta->findData(kKeyCryptoKey, &type, &key, &keysize)) {
    +         if (keysize != 16) {
    +-            // IVs must be 16 bytes in length.
    ++            // Keys must be 16 bytes in length.
    +             return NULL;
    +         }
    +     }
    +diff --git a/services/audioflinger/AudioFlinger.cpp b/services/audioflinger/AudioFlinger.cpp
    +index 79f4a66..1785a03 100644
    +--- a/services/audioflinger/AudioFlinger.cpp
    ++++ b/services/audioflinger/AudioFlinger.cpp
    +@@ -1104,14 +1104,20 @@ status_t AudioFlinger::setParameters(audio_io_handle_t ioHandle, const String8&
    +     // AUDIO_IO_HANDLE_NONE means the parameters are global to the audio hardware interface
    +     if (ioHandle == AUDIO_IO_HANDLE_NONE) {
    +         Mutex::Autolock _l(mLock);
    +-        status_t final_result = NO_ERROR;
    ++        // result will remain NO_INIT if no audio device is present
    ++        status_t final_result = NO_INIT;
    +         {
    +             AutoMutex lock(mHardwareLock);
    +             mHardwareStatus = AUDIO_HW_SET_PARAMETER;
    +             for (size_t i = 0; i < mAudioHwDevs.size(); i++) {
    +                 audio_hw_device_t *dev = mAudioHwDevs.valueAt(i)->hwDevice();
    +                 status_t result = dev->set_parameters(dev, keyValuePairs.string());
    +-                final_result = result ?: final_result;
    ++                // return success if at least one audio device accepts the parameters as not all
    ++                // HALs are requested to support all parameters. If no audio device supports the
    ++                // requested parameters, the last error is reported.
    ++                if (final_result != NO_ERROR) {
    ++                    final_result = result;
    ++                }
    +             }
    +             mHardwareStatus = AUDIO_HW_IDLE;
    +         }
    +diff --git a/services/audioflinger/BufferProviders.cpp b/services/audioflinger/BufferProviders.cpp
    +index 2ca2cac..7b6dfcb 100644
    +--- a/services/audioflinger/BufferProviders.cpp
    ++++ b/services/audioflinger/BufferProviders.cpp
    +@@ -474,18 +474,18 @@ void TimestretchBufferProvider::processFrames(void *dstBuffer, size_t *dstFrames
    +     ALOGV("processFrames(%zu %zu)  remaining(%zu)", *dstFrames, *srcFrames, mRemaining);
    +     // Note dstFrames is the required number of frames.
    + 
    +-    // Ensure consumption from src is as expected.
    +-    //TODO: add logic to track "very accurate" consumption related to speed, original sampling
    +-    //rate, actual frames processed.
    +-    const size_t targetSrc = *dstFrames * mPlaybackRate.mSpeed;
    +-    if (*srcFrames < targetSrc) { // limit dst frames to that possible
    +-        *dstFrames = *srcFrames / mPlaybackRate.mSpeed;
    +-    } else if (*srcFrames > targetSrc + 1) {
    +-        *srcFrames = targetSrc + 1;
    +-    }
    +-
    +     if (!mAudioPlaybackRateValid) {
    +         //fallback mode
    ++        // Ensure consumption from src is as expected.
    ++        // TODO: add logic to track "very accurate" consumption related to speed, original sampling
    ++        // rate, actual frames processed.
    ++
    ++        const size_t targetSrc = *dstFrames * mPlaybackRate.mSpeed;
    ++        if (*srcFrames < targetSrc) { // limit dst frames to that possible
    ++            *dstFrames = *srcFrames / mPlaybackRate.mSpeed;
    ++        } else if (*srcFrames > targetSrc + 1) {
    ++            *srcFrames = targetSrc + 1;
    ++        }
    +         if (*dstFrames > 0) {
    +             switch(mPlaybackRate.mFallbackMode) {
    +             case AUDIO_TIMESTRETCH_FALLBACK_CUT_REPEAT:
    +diff --git a/services/audioflinger/Effects.cpp b/services/audioflinger/Effects.cpp
    +index bbea971..9711f2d 100644
    +--- a/services/audioflinger/Effects.cpp
    ++++ b/services/audioflinger/Effects.cpp
    +@@ -279,12 +279,29 @@ void AudioFlinger::EffectModule::process()
    +                                         mConfig.inputCfg.buffer.s32,
    +                                         mConfig.inputCfg.buffer.frameCount/2);
    +         }
    +-
    +-        // do the actual processing in the effect engine
    +-        int ret = (*mEffectInterface)->process(mEffectInterface,
    +-                                               &mConfig.inputCfg.buffer,
    +-                                               &mConfig.outputCfg.buffer);
    +-
    ++        int ret;
    ++        if (isProcessImplemented()) {
    ++            // do the actual processing in the effect engine
    ++            ret = (*mEffectInterface)->process(mEffectInterface,
    ++                                                   &mConfig.inputCfg.buffer,
    ++                                                   &mConfig.outputCfg.buffer);
    ++        } else {
    ++            if (mConfig.inputCfg.buffer.raw != mConfig.outputCfg.buffer.raw) {
    ++                size_t frameCnt = mConfig.inputCfg.buffer.frameCount * FCC_2;  //always stereo here
    ++                int16_t *in = mConfig.inputCfg.buffer.s16;
    ++                int16_t *out = mConfig.outputCfg.buffer.s16;
    ++
    ++                if (mConfig.outputCfg.accessMode == EFFECT_BUFFER_ACCESS_ACCUMULATE) {
    ++                    for (size_t i = 0; i < frameCnt; i++) {
    ++                        out[i] = clamp16((int32_t)out[i] + (int32_t)in[i]);
    ++                    }
    ++                } else {
    ++                    memcpy(mConfig.outputCfg.buffer.raw, mConfig.inputCfg.buffer.raw,
    ++                           frameCnt * sizeof(int16_t));
    ++                }
    ++            }
    ++            ret = -ENODATA;
    ++        }
    +         // force transition to IDLE state when engine is ready
    +         if (mState == STOPPED && ret == -ENODATA) {
    +             mDisableWaitCnt = 1;
    +@@ -301,7 +318,7 @@ void AudioFlinger::EffectModule::process()
    +         // accumulate input onto output
    +         sp<EffectChain> chain = mChain.promote();
    +         if (chain != 0 && chain->activeTrackCnt() != 0) {
    +-            size_t frameCnt = mConfig.inputCfg.buffer.frameCount * 2;  //always stereo here
    ++            size_t frameCnt = mConfig.inputCfg.buffer.frameCount * FCC_2;  //always stereo here
    +             int16_t *in = mConfig.inputCfg.buffer.s16;
    +             int16_t *out = mConfig.outputCfg.buffer.s16;
    +             for (size_t i = 0; i < frameCnt; i++) {
    +@@ -2015,15 +2032,49 @@ void AudioFlinger::EffectChain::setThread(const sp<ThreadBase>& thread)
    +     }
    + }
    + 
    +-bool AudioFlinger::EffectChain::hasSoftwareEffect() const
    ++void AudioFlinger::EffectChain::checkOutputFlagCompatibility(audio_output_flags_t *flags) const
    ++{
    ++    if ((*flags & AUDIO_OUTPUT_FLAG_RAW) != 0 && !isRawCompatible()) {
    ++        *flags = (audio_output_flags_t)(*flags & ~AUDIO_OUTPUT_FLAG_RAW);
    ++    }
    ++    if ((*flags & AUDIO_OUTPUT_FLAG_FAST) != 0 && !isFastCompatible()) {
    ++        *flags = (audio_output_flags_t)(*flags & ~AUDIO_OUTPUT_FLAG_FAST);
    ++    }
    ++}
    ++
    ++void AudioFlinger::EffectChain::checkInputFlagCompatibility(audio_input_flags_t *flags) const
    ++{
    ++    if ((*flags & AUDIO_INPUT_FLAG_RAW) != 0 && !isRawCompatible()) {
    ++        *flags = (audio_input_flags_t)(*flags & ~AUDIO_INPUT_FLAG_RAW);
    ++    }
    ++    if ((*flags & AUDIO_INPUT_FLAG_FAST) != 0 && !isFastCompatible()) {
    ++        *flags = (audio_input_flags_t)(*flags & ~AUDIO_INPUT_FLAG_FAST);
    ++    }
    ++}
    ++
    ++bool AudioFlinger::EffectChain::isRawCompatible() const
    + {
    +     Mutex::Autolock _l(mLock);
    +-    for (size_t i = 0; i < mEffects.size(); i++) {
    +-        if (mEffects[i]->isImplementationSoftware()) {
    +-            return true;
    ++    for (const auto &effect : mEffects) {
    ++        if (effect->isProcessImplemented()) {
    ++            return false;
    +         }
    +     }
    +-    return false;
    ++    // Allow effects without processing.
    ++    return true;
    ++}
    ++
    ++bool AudioFlinger::EffectChain::isFastCompatible() const
    ++{
    ++    Mutex::Autolock _l(mLock);
    ++    for (const auto &effect : mEffects) {
    ++        if (effect->isProcessImplemented()
    ++                && effect->isImplementationSoftware()) {
    ++            return false;
    ++        }
    ++    }
    ++    // Allow effects without processing or hw accelerated effects.
    ++    return true;
    + }
    + 
    + // isCompatibleWithThread_l() must be called with thread->mLock held
    +diff --git a/services/audioflinger/Effects.h b/services/audioflinger/Effects.h
    +index 322c06a..818bf94 100644
    +--- a/services/audioflinger/Effects.h
    ++++ b/services/audioflinger/Effects.h
    +@@ -119,6 +119,8 @@ public:
    +                         { return (mDescriptor.flags & EFFECT_FLAG_OFFLOAD_SUPPORTED) != 0; }
    +     bool             isImplementationSoftware() const
    +                         { return (mDescriptor.flags & EFFECT_FLAG_HW_ACC_MASK) == 0; }
    ++    bool             isProcessImplemented() const
    ++                        { return (mDescriptor.flags & EFFECT_FLAG_NO_PROCESS) == 0; }
    +     status_t         setOffloaded(bool offloaded, audio_io_handle_t io);
    +     bool             isOffloaded() const;
    +     void             addEffectToHal_l();
    +@@ -326,7 +328,17 @@ public:
    + 
    +     void syncHalEffectsState();
    + 
    +-    bool hasSoftwareEffect() const;
    ++    // flags is an ORed set of audio_output_flags_t which is updated on return.
    ++    void checkOutputFlagCompatibility(audio_output_flags_t *flags) const;
    ++
    ++    // flags is an ORed set of audio_input_flags_t which is updated on return.
    ++    void checkInputFlagCompatibility(audio_input_flags_t *flags) const;
    ++
    ++    // Is this EffectChain compatible with the RAW audio flag.
    ++    bool isRawCompatible() const;
    ++
    ++    // Is this EffectChain compatible with the FAST audio flag.
    ++    bool isFastCompatible() const;
    + 
    +     // isCompatibleWithThread_l() must be called with thread->mLock held
    +     bool isCompatibleWithThread_l(const sp<ThreadBase>& thread) const;
    +diff --git a/services/audioflinger/FastMixer.cpp b/services/audioflinger/FastMixer.cpp
    +index b0780a4..93f7ce5 100644
    +--- a/services/audioflinger/FastMixer.cpp
    ++++ b/services/audioflinger/FastMixer.cpp
    +@@ -412,6 +412,7 @@ void FastMixer::onWork()
    +             }
    +             ftDump->mUnderruns = underruns;
    +             ftDump->mFramesReady = framesReady;
    ++            ftDump->mFramesWritten = trackFramesWritten;
    +         }
    + 
    +         if (anyEnabledTracks) {
    +diff --git a/services/audioflinger/FastMixerDumpState.cpp b/services/audioflinger/FastMixerDumpState.cpp
    +index 2326e2a..6475f22 100644
    +--- a/services/audioflinger/FastMixerDumpState.cpp
    ++++ b/services/audioflinger/FastMixerDumpState.cpp
    +@@ -168,7 +168,7 @@ void FastMixerDumpState::dump(int fd) const
    +     uint32_t trackMask = mTrackMask;
    +     dprintf(fd, "  Fast tracks: sMaxFastTracks=%u activeMask=%#x\n",
    +             FastMixerState::sMaxFastTracks, trackMask);
    +-    dprintf(fd, "  Index Active Full Partial Empty  Recent Ready\n");
    ++    dprintf(fd, "  Index Active Full Partial Empty  Recent Ready    Written\n");
    +     for (uint32_t i = 0; i < FastMixerState::sMaxFastTracks; ++i, trackMask >>= 1) {
    +         bool isActive = trackMask & 1;
    +         const FastTrackDump *ftDump = &mTracks[i];
    +@@ -188,11 +188,13 @@ void FastMixerDumpState::dump(int fd) const
    +             mostRecent = "?";
    +             break;
    +         }
    +-        dprintf(fd, "  %5u %6s %4u %7u %5u %7s %5zu\n", i, isActive ? "yes" : "no",
    ++        dprintf(fd, "  %5u %6s %4u %7u %5u %7s %5zu %10lld\n",
    ++                i, isActive ? "yes" : "no",
    +                 (underruns.mBitFields.mFull) & UNDERRUN_MASK,
    +                 (underruns.mBitFields.mPartial) & UNDERRUN_MASK,
    +                 (underruns.mBitFields.mEmpty) & UNDERRUN_MASK,
    +-                mostRecent, ftDump->mFramesReady);
    ++                mostRecent, ftDump->mFramesReady,
    ++                (long long)ftDump->mFramesWritten);
    +     }
    + }
    + 
    +diff --git a/services/audioflinger/FastMixerDumpState.h b/services/audioflinger/FastMixerDumpState.h
    +index ac15e7c..301c5b1 100644
    +--- a/services/audioflinger/FastMixerDumpState.h
    ++++ b/services/audioflinger/FastMixerDumpState.h
    +@@ -57,6 +57,7 @@ struct FastTrackDump {
    +     /*virtual*/ ~FastTrackDump() { }
    +     FastTrackUnderruns  mUnderruns;
    +     size_t              mFramesReady;        // most recent value only; no long-term statistics kept
    ++    int64_t             mFramesWritten;      // last value from track
    + };
    + 
    + struct FastMixerDumpState : FastThreadDumpState {
    +diff --git a/services/audioflinger/Threads.cpp b/services/audioflinger/Threads.cpp
    +index a671128..0f403ae 100644
    +--- a/services/audioflinger/Threads.cpp
    ++++ b/services/audioflinger/Threads.cpp
    +@@ -1272,6 +1272,12 @@ status_t AudioFlinger::RecordThread::checkEffectCompatibility_l(
    +                 desc->name, mThreadName);
    +         return BAD_VALUE;
    +     }
    ++
    ++    // always allow effects without processing load or latency
    ++    if ((desc->flags & EFFECT_FLAG_NO_PROCESS_MASK) == EFFECT_FLAG_NO_PROCESS) {
    ++        return NO_ERROR;
    ++    }
    ++
    +     audio_input_flags_t flags = mInput->flags;
    +     if (hasFastCapture() || (flags & AUDIO_INPUT_FLAG_FAST)) {
    +         if (flags & AUDIO_INPUT_FLAG_RAW) {
    +@@ -1328,6 +1334,11 @@ status_t AudioFlinger::PlaybackThread::checkEffectCompatibility_l(
    +                     break;
    +                 }
    +             }
    ++
    ++            // always allow effects without processing load or latency
    ++            if ((desc->flags & EFFECT_FLAG_NO_PROCESS_MASK) == EFFECT_FLAG_NO_PROCESS) {
    ++                break;
    ++            }
    +             if (flags & AUDIO_OUTPUT_FLAG_RAW) {
    +                 ALOGW("checkEffectCompatibility_l(): effect %s on playback thread in raw mode",
    +                       desc->name);
    +@@ -1815,6 +1826,15 @@ void AudioFlinger::PlaybackThread::dumpInternals(int fd, const Vector<String16>&
    +     audio_output_flags_t flags = output != NULL ? output->flags : AUDIO_OUTPUT_FLAG_NONE;
    +     String8 flagsAsString = outputFlagsToString(flags);
    +     dprintf(fd, "  AudioStreamOut: %p flags %#x (%s)\n", output, flags, flagsAsString.string());
    ++    dprintf(fd, "  Frames written: %lld\n", (long long)mFramesWritten);
    ++    dprintf(fd, "  Suspended frames: %lld\n", (long long)mSuspendedFrames);
    ++    if (mPipeSink.get() != nullptr) {
    ++        dprintf(fd, "  PipeSink frames written: %lld\n", (long long)mPipeSink->framesWritten());
    ++    }
    ++    if (output != nullptr) {
    ++        dprintf(fd, "  Hal stream dump:\n");
    ++        (void)output->stream->common.dump(&output->stream->common, fd);
    ++    }
    + }
    + 
    + // Thread virtuals
    +@@ -1898,34 +1918,19 @@ sp<AudioFlinger::PlaybackThread::Track> AudioFlinger::PlaybackThread::createTrac
    +         // check compatibility with audio effects.
    +         { // scope for mLock
    +             Mutex::Autolock _l(mLock);
    +-            // do not accept RAW flag if post processing are present. Note that post processing on
    +-            // a fast mixer are necessarily hardware
    +-            sp<EffectChain> chain = getEffectChain_l(AUDIO_SESSION_OUTPUT_STAGE);
    +-            if (chain != 0) {
    +-                ALOGV_IF((*flags & AUDIO_OUTPUT_FLAG_RAW) != 0,
    +-                        "AUDIO_OUTPUT_FLAG_RAW denied: post processing effect present");
    +-                *flags = (audio_output_flags_t)(*flags & ~AUDIO_OUTPUT_FLAG_RAW);
    +-            }
    +-            // Do not accept FAST flag if software global effects are present
    +-            chain = getEffectChain_l(AUDIO_SESSION_OUTPUT_MIX);
    +-            if (chain != 0) {
    +-                ALOGV_IF((*flags & AUDIO_OUTPUT_FLAG_RAW) != 0,
    +-                        "AUDIO_OUTPUT_FLAG_RAW denied: global effect present");
    +-                *flags = (audio_output_flags_t)(*flags & ~AUDIO_OUTPUT_FLAG_RAW);
    +-                if (chain->hasSoftwareEffect()) {
    +-                    ALOGV("AUDIO_OUTPUT_FLAG_FAST denied: software global effect present");
    +-                    *flags = (audio_output_flags_t)(*flags & ~AUDIO_OUTPUT_FLAG_FAST);
    +-                }
    +-            }
    +-            // Do not accept FAST flag if the session has software effects
    +-            chain = getEffectChain_l(sessionId);
    +-            if (chain != 0) {
    +-                ALOGV_IF((*flags & AUDIO_OUTPUT_FLAG_RAW) != 0,
    +-                        "AUDIO_OUTPUT_FLAG_RAW denied: effect present on session");
    +-                *flags = (audio_output_flags_t)(*flags & ~AUDIO_OUTPUT_FLAG_RAW);
    +-                if (chain->hasSoftwareEffect()) {
    +-                    ALOGV("AUDIO_OUTPUT_FLAG_FAST denied: software effect present on session");
    +-                    *flags = (audio_output_flags_t)(*flags & ~AUDIO_OUTPUT_FLAG_FAST);
    ++            for (audio_session_t session : {
    ++                    AUDIO_SESSION_OUTPUT_STAGE,
    ++                    AUDIO_SESSION_OUTPUT_MIX,
    ++                    sessionId,
    ++                }) {
    ++                sp<EffectChain> chain = getEffectChain_l(session);
    ++                if (chain.get() != nullptr) {
    ++                    audio_output_flags_t old = *flags;
    ++                    chain->checkOutputFlagCompatibility(flags);
    ++                    if (old != *flags) {
    ++                        ALOGV("AUDIO_OUTPUT_FLAGS denied by effect, session=%d old=%#x new=%#x",
    ++                                (int)session, (int)old, (int)*flags);
    ++                    }
    +                 }
    +             }
    +         }
    +@@ -3106,9 +3111,9 @@ bool AudioFlinger::PlaybackThread::threadLoop()
    +                 if (!keepWakeLock()) {
    +                     releaseWakeLock_l();
    +                     released = true;
    ++                    mWakeLockUids.clear();
    ++                    mActiveTracksGeneration++;
    +                 }
    +-                mWakeLockUids.clear();
    +-                mActiveTracksGeneration++;
    +                 ALOGV("wait async completion");
    +                 mWaitWorkCV.wait(mLock);
    +                 ALOGV("async completion/wake");
    +@@ -4577,10 +4582,25 @@ AudioFlinger::PlaybackThread::mixer_state AudioFlinger::MixerThread::prepareTrac
    +     return mixerStatus;
    + }
    + 
    ++// trackCountForUid_l() must be called with ThreadBase::mLock held
    ++uint32_t AudioFlinger::PlaybackThread::trackCountForUid_l(uid_t uid)
    ++{
    ++    uint32_t trackCount = 0;
    ++    for (size_t i = 0; i < mTracks.size() ; i++) {
    ++        if (mTracks[i]->uid() == (int)uid) {
    ++            trackCount++;
    ++        }
    ++    }
    ++    return trackCount;
    ++}
    ++
    + // getTrackName_l() must be called with ThreadBase::mLock held
    + int AudioFlinger::MixerThread::getTrackName_l(audio_channel_mask_t channelMask,
    +-        audio_format_t format, audio_session_t sessionId)
    ++        audio_format_t format, audio_session_t sessionId, uid_t uid)
    + {
    ++    if (trackCountForUid_l(uid) > (PlaybackThread::kMaxTracksPerUid - 1)) {
    ++        return -1;
    ++    }
    +     return mAudioMixer->getTrackName(channelMask, format, sessionId);
    + }
    + 
    +@@ -4685,7 +4705,7 @@ bool AudioFlinger::MixerThread::checkForNewParameter_l(const String8& keyValuePa
    +             mAudioMixer = new AudioMixer(mNormalFrameCount, mSampleRate);
    +             for (size_t i = 0; i < mTracks.size() ; i++) {
    +                 int name = getTrackName_l(mTracks[i]->mChannelMask,
    +-                        mTracks[i]->mFormat, mTracks[i]->mSessionId);
    ++                        mTracks[i]->mFormat, mTracks[i]->mSessionId, mTracks[i]->uid());
    +                 if (name < 0) {
    +                     break;
    +                 }
    +@@ -5130,8 +5150,11 @@ bool AudioFlinger::DirectOutputThread::shouldStandby_l()
    + 
    + // getTrackName_l() must be called with ThreadBase::mLock held
    + int AudioFlinger::DirectOutputThread::getTrackName_l(audio_channel_mask_t channelMask __unused,
    +-        audio_format_t format __unused, audio_session_t sessionId __unused)
    ++        audio_format_t format __unused, audio_session_t sessionId __unused, uid_t uid)
    + {
    ++    if (trackCountForUid_l(uid) > (PlaybackThread::kMaxTracksPerUid - 1)) {
    ++        return -1;
    ++    }
    +     return 0;
    + }
    + 
    +@@ -6556,12 +6579,11 @@ sp<AudioFlinger::RecordThread::RecordTrack> AudioFlinger::RecordThread::createRe
    +           // Do not accept FAST flag if the session has software effects
    +           sp<EffectChain> chain = getEffectChain_l(sessionId);
    +           if (chain != 0) {
    +-              ALOGV_IF((*flags & AUDIO_INPUT_FLAG_RAW) != 0,
    +-                      "AUDIO_INPUT_FLAG_RAW denied: effect present on session");
    +-              *flags = (audio_input_flags_t)(*flags & ~AUDIO_INPUT_FLAG_RAW);
    +-              if (chain->hasSoftwareEffect()) {
    +-                  ALOGV("AUDIO_INPUT_FLAG_FAST denied: software effect present on session");
    +-                  *flags = (audio_input_flags_t)(*flags & ~AUDIO_INPUT_FLAG_FAST);
    ++              audio_input_flags_t old = *flags;
    ++              chain->checkInputFlagCompatibility(flags);
    ++              if (old != *flags) {
    ++                  ALOGV("AUDIO_INPUT_FLAGS denied by effect old=%#x new=%#x",
    ++                          (int)old, (int)*flags);
    +               }
    +           }
    +           ALOGV_IF((*flags & AUDIO_INPUT_FLAG_FAST) != 0,
    +diff --git a/services/audioflinger/Threads.h b/services/audioflinger/Threads.h
    +index 1d5d3c8..f353f3b 100644
    +--- a/services/audioflinger/Threads.h
    ++++ b/services/audioflinger/Threads.h
    +@@ -506,6 +506,8 @@ public:
    +     static const int8_t kMaxTrackRetriesOffload = 20;
    +     static const int8_t kMaxTrackStartupRetriesOffload = 100;
    +     static const int8_t kMaxTrackStopRetriesOffload = 2;
    ++    // 14 tracks max per client allows for 2 misbehaving application leaving 4 available tracks.
    ++    static const uint32_t kMaxTracksPerUid = 14;
    + 
    +     PlaybackThread(const sp<AudioFlinger>& audioFlinger, AudioStreamOut* output,
    +                    audio_io_handle_t id, audio_devices_t device, type_t type, bool systemReady);
    +@@ -736,8 +738,8 @@ protected:
    + 
    +     // Allocate a track name for a given channel mask.
    +     //   Returns name >= 0 if successful, -1 on failure.
    +-    virtual int             getTrackName_l(audio_channel_mask_t channelMask,
    +-                                           audio_format_t format, audio_session_t sessionId) = 0;
    ++    virtual int             getTrackName_l(audio_channel_mask_t channelMask, audio_format_t format,
    ++                                           audio_session_t sessionId, uid_t uid) = 0;
    +     virtual void            deleteTrackName_l(int name) = 0;
    + 
    +     // Time to sleep between cycles when:
    +@@ -767,6 +769,8 @@ protected:
    +                                     && mHwSupportsPause
    +                                     && (mOutput->flags & AUDIO_OUTPUT_FLAG_HW_AV_SYNC); }
    + 
    ++                uint32_t    trackCountForUid_l(uid_t uid);
    ++
    + private:
    + 
    +     friend class AudioFlinger;      // for numerous
    +@@ -889,8 +893,8 @@ public:
    + 
    + protected:
    +     virtual     mixer_state prepareTracks_l(Vector< sp<Track> > *tracksToRemove);
    +-    virtual     int         getTrackName_l(audio_channel_mask_t channelMask,
    +-                                           audio_format_t format, audio_session_t sessionId);
    ++    virtual     int         getTrackName_l(audio_channel_mask_t channelMask, audio_format_t format,
    ++                                           audio_session_t sessionId, uid_t uid);
    +     virtual     void        deleteTrackName_l(int name);
    +     virtual     uint32_t    idleSleepTimeUs() const;
    +     virtual     uint32_t    suspendSleepTimeUs() const;
    +@@ -969,8 +973,8 @@ public:
    +     virtual     void        flushHw_l();
    + 
    + protected:
    +-    virtual     int         getTrackName_l(audio_channel_mask_t channelMask,
    +-                                           audio_format_t format, audio_session_t sessionId);
    ++    virtual     int         getTrackName_l(audio_channel_mask_t channelMask, audio_format_t format,
    ++                                           audio_session_t sessionId, uid_t uid);
    +     virtual     void        deleteTrackName_l(int name);
    +     virtual     uint32_t    activeSleepTimeUs() const;
    +     virtual     uint32_t    idleSleepTimeUs() const;
    +diff --git a/services/audioflinger/Tracks.cpp b/services/audioflinger/Tracks.cpp
    +index b387af3..ba6e6e5 100644
    +--- a/services/audioflinger/Tracks.cpp
    ++++ b/services/audioflinger/Tracks.cpp
    +@@ -388,7 +388,7 @@ AudioFlinger::PlaybackThread::Track::Track(
    +     }
    +     mServerProxy = mAudioTrackServerProxy;
    + 
    +-    mName = thread->getTrackName_l(channelMask, format, sessionId);
    ++    mName = thread->getTrackName_l(channelMask, format, sessionId, uid);
    +     if (mName < 0) {
    +         ALOGE("no more track names available");
    +         return;
    +@@ -777,6 +777,13 @@ void AudioFlinger::PlaybackThread::Track::flush()
    +         Mutex::Autolock _l(thread->mLock);
    +         PlaybackThread *playbackThread = (PlaybackThread *)thread.get();
    + 
    ++        // Flush the ring buffer now if the track is not active in the PlaybackThread.
    ++        // Otherwise the flush would not be done until the track is resumed.
    ++        // Requires FastTrack removal be BLOCK_UNTIL_ACKED
    ++        if (playbackThread->mActiveTracks.indexOf(this) < 0) {
    ++            (void)mServerProxy->flushBufferIfNeeded();
    ++        }
    ++
    +         if (isOffloaded()) {
    +             // If offloaded we allow flush during any state except terminated
    +             // and keep the track active to avoid problems if user is seeking
    +@@ -828,6 +835,10 @@ void AudioFlinger::PlaybackThread::Track::flushAck()
    +     if (!isOffloaded() && !isDirect())
    +         return;
    + 
    ++    // Clear the client ring buffer so that the app can prime the buffer while paused.
    ++    // Otherwise it might not get cleared until playback is resumed and obtainBuffer() is called.
    ++    mServerProxy->flushBufferIfNeeded();
    ++
    +     mFlushHwPending = false;
    + }
    + 
    +diff --git a/services/audiopolicy/common/managerdefinitions/include/AudioInputDescriptor.h b/services/audiopolicy/common/managerdefinitions/include/AudioInputDescriptor.h
    +index 46309ed..f2b39f2 100644
    +--- a/services/audiopolicy/common/managerdefinitions/include/AudioInputDescriptor.h
    ++++ b/services/audiopolicy/common/managerdefinitions/include/AudioInputDescriptor.h
    +@@ -93,7 +93,9 @@ public:
    + 
    +     sp<AudioInputDescriptor> getInputFromId(audio_port_handle_t id) const;
    + 
    +-    uint32_t activeInputsCount() const;
    ++    // count active capture sessions using one of the specified devices.
    ++    // ignore devices if AUDIO_DEVICE_IN_DEFAULT is passed
    ++    uint32_t activeInputsCountOnDevices(audio_devices_t devices = AUDIO_DEVICE_IN_DEFAULT) const;
    + 
    +     /**
    +      * return io handle of active input or 0 if no input is active
    +diff --git a/services/audiopolicy/common/managerdefinitions/src/AudioInputDescriptor.cpp b/services/audiopolicy/common/managerdefinitions/src/AudioInputDescriptor.cpp
    +index 6dacaa4..c7d2ee4 100644
    +--- a/services/audiopolicy/common/managerdefinitions/src/AudioInputDescriptor.cpp
    ++++ b/services/audiopolicy/common/managerdefinitions/src/AudioInputDescriptor.cpp
    +@@ -222,12 +222,14 @@ sp<AudioInputDescriptor> AudioInputCollection::getInputFromId(audio_port_handle_
    +     return inputDesc;
    + }
    + 
    +-uint32_t AudioInputCollection::activeInputsCount() const
    ++uint32_t AudioInputCollection::activeInputsCountOnDevices(audio_devices_t devices) const
    + {
    +     uint32_t count = 0;
    +     for (size_t i = 0; i < size(); i++) {
    +         const sp<AudioInputDescriptor>  inputDescriptor = valueAt(i);
    +-        if (inputDescriptor->isActive()) {
    ++        if (inputDescriptor->isActive() &&
    ++                ((devices == AUDIO_DEVICE_IN_DEFAULT) ||
    ++                 ((inputDescriptor->mDevice & devices & ~AUDIO_DEVICE_BIT_IN) != 0))) {
    +             count++;
    +         }
    +     }
    +diff --git a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
    +index b752541..968b80f 100644
    +--- a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
    ++++ b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
    +@@ -1315,16 +1315,23 @@ status_t AudioPolicyManager::stopSource(sp<AudioOutputDescriptor> outputDesc,
    + 
    +             // force restoring the device selection on other active outputs if it differs from the
    +             // one being selected for this output
    ++            uint32_t delayMs = outputDesc->latency()*2;
    +             for (size_t i = 0; i < mOutputs.size(); i++) {
    +                 sp<AudioOutputDescriptor> desc = mOutputs.valueAt(i);
    +                 if (desc != outputDesc &&
    +                         desc->isActive() &&
    +                         outputDesc->sharesHwModuleWith(desc) &&
    +                         (newDevice != desc->device())) {
    ++                    audio_devices_t newDevice2 = getNewOutputDevice(desc, false /*fromCache*/);
    ++                    bool force = desc->device() != newDevice2;
    +                     setOutputDevice(desc,
    +-                                    getNewOutputDevice(desc, false /*fromCache*/),
    +-                                    true,
    +-                                    outputDesc->latency()*2);
    ++                                    newDevice2,
    ++                                    force,
    ++                                    delayMs);
    ++                    // re-apply device specific volume if not done by setOutputDevice()
    ++                    if (!force) {
    ++                        applyStreamVolumes(desc, newDevice2, delayMs);
    ++                    }
    +                 }
    +             }
    +             // update the outputs if stopping one with a stream that can affect notification routing
    +@@ -1681,10 +1688,15 @@ status_t AudioPolicyManager::startInput(audio_io_handle_t input,
    +                     MIX_STATE_MIXING);
    +         }
    + 
    +-        if (mInputs.activeInputsCount() == 0) {
    ++        // indicate active capture to sound trigger service if starting capture from a mic on
    ++        // primary HW module
    ++        audio_devices_t device = getNewInputDevice(input);
    ++        audio_devices_t primaryInputDevices = availablePrimaryInputDevices();
    ++        if (((device & primaryInputDevices & ~AUDIO_DEVICE_BIT_IN) != 0) &&
    ++                mInputs.activeInputsCountOnDevices(primaryInputDevices) == 0) {
    +             SoundTrigger::setCaptureState(true);
    +         }
    +-        setInputDevice(input, getNewInputDevice(input), true /* force */);
    ++        setInputDevice(input, device, true /* force */);
    + 
    +         // automatically enable the remote submix output when input is started if not
    +         // used by a policy mix of type MIX_TYPE_RECORDERS
    +@@ -1761,9 +1773,14 @@ status_t AudioPolicyManager::stopInput(audio_io_handle_t input,
    +             }
    +         }
    + 
    ++        audio_devices_t device = inputDesc->mDevice;
    +         resetInputDevice(input);
    + 
    +-        if (mInputs.activeInputsCount() == 0) {
    ++        // indicate inactive capture to sound trigger service if stopping capture from a mic on
    ++        // primary HW module
    ++        audio_devices_t primaryInputDevices = availablePrimaryInputDevices();
    ++        if (((device & primaryInputDevices & ~AUDIO_DEVICE_BIT_IN) != 0) &&
    ++                mInputs.activeInputsCountOnDevices(primaryInputDevices) == 0) {
    +             SoundTrigger::setCaptureState(false);
    +         }
    +         inputDesc->clearPreemptedSessions();
    +@@ -1901,19 +1918,21 @@ status_t AudioPolicyManager::setStreamVolumeIndex(audio_stream_type_t stream,
    +                 continue;
    +             }
    +             routing_strategy curStrategy = getStrategy((audio_stream_type_t)curStream);
    +-            audio_devices_t curStreamDevice = getDeviceForStrategy(curStrategy, true /*fromCache*/);
    +-            if ((curStreamDevice & device) == 0) {
    ++            audio_devices_t curStreamDevice = getDeviceForStrategy(curStrategy, false /*fromCache*/);
    ++            if ((device != AUDIO_DEVICE_OUT_DEFAULT_FOR_VOLUME) &&
    ++                    ((curStreamDevice & device) == 0)) {
    +                 continue;
    +             }
    +-            bool applyDefault = false;
    ++            bool applyVolume;
    +             if (device != AUDIO_DEVICE_OUT_DEFAULT_FOR_VOLUME) {
    +                 curStreamDevice |= device;
    +-            } else if (!mVolumeCurves->hasVolumeIndexForDevice(
    +-                    stream, Volume::getDeviceForVolume(curStreamDevice))) {
    +-                applyDefault = true;
    ++                applyVolume = (curDevice & curStreamDevice) != 0;
    ++            } else {
    ++                applyVolume = !mVolumeCurves->hasVolumeIndexForDevice(
    ++                        stream, Volume::getDeviceForVolume(curStreamDevice));
    +             }
    + 
    +-            if (applyDefault || ((curDevice & curStreamDevice) != 0)) {
    ++            if (applyVolume) {
    +                 //FIXME: workaround for truncated touch sounds
    +                 // delayed volume change for system stream to be removed when the problem is
    +                 // handled by system UI
    +@@ -4937,6 +4956,18 @@ float AudioPolicyManager::computeVolume(audio_stream_type_t stream,
    +                                         audio_devices_t device)
    + {
    +     float volumeDB = mVolumeCurves->volIndexToDb(stream, Volume::getDeviceCategory(device), index);
    ++
    ++    // handle the case of accessibility active while a ringtone is playing: if the ringtone is much
    ++    // louder than the accessibility prompt, the prompt cannot be heard, thus masking the touch
    ++    // exploration of the dialer UI. In this situation, bring the accessibility volume closer to
    ++    // the ringtone volume
    ++    if ((stream == AUDIO_STREAM_ACCESSIBILITY)
    ++            && (AUDIO_MODE_RINGTONE == mEngine->getPhoneState())
    ++            && isStreamActive(AUDIO_STREAM_RING, 0)) {
    ++        const float ringVolumeDB = computeVolume(AUDIO_STREAM_RING, index, device);
    ++        return ringVolumeDB - 4 > volumeDB ? ringVolumeDB - 4 : volumeDB;
    ++    }
    ++
    +     // if a headset is connected, apply the following rules to ring tones and notifications
    +     // to avoid sound level bursts in user's ears:
    +     // - always attenuate notifications volume by 6dB
     diff --git a/services/camera/libcameraservice/Android.mk b/services/camera/libcameraservice/Android.mk
     index 8d7f71c..d98ad47 100644
     --- a/services/camera/libcameraservice/Android.mk
    @@ -2497,3 +3635,241 @@ index 266fb03..3c2b98a 100644
      }
      
      status_t CameraClient::setVideoBufferMode(int32_t videoBufferMode) {
    +diff --git a/services/camera/libcameraservice/api1/client2/Parameters.cpp b/services/camera/libcameraservice/api1/client2/Parameters.cpp
    +index 9d5f33c..9a7839b 100644
    +--- a/services/camera/libcameraservice/api1/client2/Parameters.cpp
    ++++ b/services/camera/libcameraservice/api1/client2/Parameters.cpp
    +@@ -238,6 +238,10 @@ status_t Parameters::initialize(const CameraMetadata *info, int deviceVersion) {
    +     {
    +         String8 supportedPreviewFpsRange;
    +         for (size_t i=0; i < availableFpsRanges.count; i += 2) {
    ++            if (!isFpsSupported(availablePreviewSizes,
    ++                HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED, availableFpsRanges.data.i32[i+1])) {
    ++                continue;
    ++            }
    +             if (i != 0) supportedPreviewFpsRange += ",";
    +             supportedPreviewFpsRange += String8::format("(%d,%d)",
    +                     availableFpsRanges.data.i32[i] * kFpsToApiScale,
    +@@ -255,7 +259,10 @@ status_t Parameters::initialize(const CameraMetadata *info, int deviceVersion) {
    +             // from the [min, max] fps range use the max value
    +             int fps = fpsFromRange(availableFpsRanges.data.i32[i],
    +                                    availableFpsRanges.data.i32[i+1]);
    +-
    ++            if (!isFpsSupported(availablePreviewSizes,
    ++                    HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED, fps)) {
    ++                continue;
    ++            }
    +             // de-dupe frame rates
    +             if (sortedPreviewFrameRates.indexOf(fps) == NAME_NOT_FOUND) {
    +                 sortedPreviewFrameRates.add(fps);
    +@@ -951,21 +958,40 @@ status_t Parameters::buildFastInfo() {
    +         return NO_INIT;
    +     }
    + 
    ++    // Get supported preview fps ranges.
    ++    Vector<Size> supportedPreviewSizes;
    ++    Vector<FpsRange> supportedPreviewFpsRanges;
    ++    const Size PREVIEW_SIZE_BOUND = { MAX_PREVIEW_WIDTH, MAX_PREVIEW_HEIGHT };
    ++    status_t res = getFilteredSizes(PREVIEW_SIZE_BOUND, &supportedPreviewSizes);
    ++    if (res != OK) return res;
    ++    for (size_t i=0; i < availableFpsRanges.count; i += 2) {
    ++        if (!isFpsSupported(supportedPreviewSizes,
    ++                HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED, availableFpsRanges.data.i32[i+1])) {
    ++            continue;
    ++        }
    ++        FpsRange fpsRange = {availableFpsRanges.data.i32[i], availableFpsRanges.data.i32[i+1]};
    ++        supportedPreviewFpsRanges.add(fpsRange);
    ++    }
    ++    if (supportedPreviewFpsRanges.size() == 0) {
    ++        ALOGE("Supported preview fps range is empty");
    ++        return NO_INIT;
    ++    }
    ++
    +     int32_t bestStillCaptureFpsRange[2] = {
    +-        availableFpsRanges.data.i32[0], availableFpsRanges.data.i32[1]
    ++        supportedPreviewFpsRanges[0].low, supportedPreviewFpsRanges[0].high
    +     };
    +     int32_t curRange =
    +             bestStillCaptureFpsRange[1] - bestStillCaptureFpsRange[0];
    +-    for (size_t i = 2; i < availableFpsRanges.count; i += 2) {
    ++    for (size_t i = 1; i < supportedPreviewFpsRanges.size(); i ++) {
    +         int32_t nextRange =
    +-                availableFpsRanges.data.i32[i + 1] -
    +-                availableFpsRanges.data.i32[i];
    ++                supportedPreviewFpsRanges[i].high -
    ++                supportedPreviewFpsRanges[i].low;
    +         if ( (nextRange > curRange) ||       // Maximize size of FPS range first
    +                 (nextRange == curRange &&    // Then minimize low-end FPS
    +-                 bestStillCaptureFpsRange[0] > availableFpsRanges.data.i32[i])) {
    ++                 bestStillCaptureFpsRange[0] > supportedPreviewFpsRanges[i].low)) {
    + 
    +-            bestStillCaptureFpsRange[0] = availableFpsRanges.data.i32[i];
    +-            bestStillCaptureFpsRange[1] = availableFpsRanges.data.i32[i + 1];
    ++            bestStillCaptureFpsRange[0] = supportedPreviewFpsRanges[i].low;
    ++            bestStillCaptureFpsRange[1] = supportedPreviewFpsRanges[i].high;
    +             curRange = nextRange;
    +         }
    +     }
    +@@ -2836,22 +2862,7 @@ Vector<Parameters::StreamConfiguration> Parameters::getStreamConfigurations() {
    + 
    + int64_t Parameters::getJpegStreamMinFrameDurationNs(Parameters::Size size) {
    +     if (mDeviceVersion >= CAMERA_DEVICE_API_VERSION_3_2) {
    +-        const int STREAM_DURATION_SIZE = 4;
    +-        const int STREAM_FORMAT_OFFSET = 0;
    +-        const int STREAM_WIDTH_OFFSET = 1;
    +-        const int STREAM_HEIGHT_OFFSET = 2;
    +-        const int STREAM_DURATION_OFFSET = 3;
    +-        camera_metadata_ro_entry_t availableStreamMinDurations =
    +-                    staticInfo(ANDROID_SCALER_AVAILABLE_MIN_FRAME_DURATIONS);
    +-        for (size_t i = 0; i < availableStreamMinDurations.count; i+= STREAM_DURATION_SIZE) {
    +-            int64_t format = availableStreamMinDurations.data.i64[i + STREAM_FORMAT_OFFSET];
    +-            int64_t width = availableStreamMinDurations.data.i64[i + STREAM_WIDTH_OFFSET];
    +-            int64_t height = availableStreamMinDurations.data.i64[i + STREAM_HEIGHT_OFFSET];
    +-            int64_t duration = availableStreamMinDurations.data.i64[i + STREAM_DURATION_OFFSET];
    +-            if (format == HAL_PIXEL_FORMAT_BLOB && width == size.width && height == size.height) {
    +-                return duration;
    +-            }
    +-        }
    ++        return getMinFrameDurationNs(size, HAL_PIXEL_FORMAT_BLOB);
    +     } else {
    +         Vector<Size> availableJpegSizes = getAvailableJpegSizes();
    +         size_t streamIdx = availableJpegSizes.size();
    +@@ -2875,6 +2886,57 @@ int64_t Parameters::getJpegStreamMinFrameDurationNs(Parameters::Size size) {
    +     return -1;
    + }
    + 
    ++int64_t Parameters::getMinFrameDurationNs(Parameters::Size size, int fmt) {
    ++    if (mDeviceVersion < CAMERA_DEVICE_API_VERSION_3_2) {
    ++        ALOGE("Min frame duration for HAL 3.1 or lower is not supported");
    ++        return -1;
    ++    }
    ++
    ++    const int STREAM_DURATION_SIZE = 4;
    ++    const int STREAM_FORMAT_OFFSET = 0;
    ++    const int STREAM_WIDTH_OFFSET = 1;
    ++    const int STREAM_HEIGHT_OFFSET = 2;
    ++    const int STREAM_DURATION_OFFSET = 3;
    ++    camera_metadata_ro_entry_t availableStreamMinDurations =
    ++                staticInfo(ANDROID_SCALER_AVAILABLE_MIN_FRAME_DURATIONS);
    ++    for (size_t i = 0; i < availableStreamMinDurations.count; i+= STREAM_DURATION_SIZE) {
    ++        int64_t format = availableStreamMinDurations.data.i64[i + STREAM_FORMAT_OFFSET];
    ++        int64_t width = availableStreamMinDurations.data.i64[i + STREAM_WIDTH_OFFSET];
    ++        int64_t height = availableStreamMinDurations.data.i64[i + STREAM_HEIGHT_OFFSET];
    ++        int64_t duration = availableStreamMinDurations.data.i64[i + STREAM_DURATION_OFFSET];
    ++        if (format == fmt && width == size.width && height == size.height) {
    ++            return duration;
    ++        }
    ++    }
    ++
    ++    return -1;
    ++}
    ++
    ++bool Parameters::isFpsSupported(const Vector<Size> &sizes, int format, int32_t fps) {
    ++    // Skip the check for older HAL version, as the min duration is not supported.
    ++    if (mDeviceVersion < CAMERA_DEVICE_API_VERSION_3_2) {
    ++        return true;
    ++    }
    ++
    ++    // Get min frame duration for each size and check if the given fps range can be supported.
    ++    const int32_t FPS_MARGIN = 1;
    ++    for (size_t i = 0 ; i < sizes.size(); i++) {
    ++        int64_t minFrameDuration = getMinFrameDurationNs(sizes[i], format);
    ++        if (minFrameDuration <= 0) {
    ++            ALOGE("Min frame duration (%" PRId64") for size (%dx%d) and format 0x%x is wrong!",
    ++                minFrameDuration, sizes[i].width, sizes[i].height, format);
    ++            return false;
    ++        }
    ++        int32_t maxSupportedFps = 1e9 / minFrameDuration;
    ++        // Add some margin here for the case where the hal supports 29.xxxfps.
    ++        maxSupportedFps += FPS_MARGIN;
    ++        if (fps > maxSupportedFps) {
    ++            return false;
    ++        }
    ++    }
    ++    return true;
    ++}
    ++
    + SortedVector<int32_t> Parameters::getAvailableOutputFormats() {
    +     SortedVector<int32_t> outputFormats; // Non-duplicated output formats
    +     if (mDeviceVersion >= CAMERA_DEVICE_API_VERSION_3_2) {
    +diff --git a/services/camera/libcameraservice/api1/client2/Parameters.h b/services/camera/libcameraservice/api1/client2/Parameters.h
    +index f4bb34c..687ac3e 100644
    +--- a/services/camera/libcameraservice/api1/client2/Parameters.h
    ++++ b/services/camera/libcameraservice/api1/client2/Parameters.h
    +@@ -115,6 +115,11 @@ struct Parameters {
    +         int32_t height;
    +     };
    + 
    ++    struct FpsRange {
    ++        int32_t low;
    ++        int32_t high;
    ++    };
    ++
    +     int32_t exposureCompensation;
    +     bool autoExposureLock;
    +     bool autoWhiteBalanceLock;
    +@@ -390,6 +395,15 @@ private:
    +     // return -1 if input jpeg size cannot be found in supported size list
    +     int64_t getJpegStreamMinFrameDurationNs(Parameters::Size size);
    + 
    ++    // Helper function to get minimum frame duration for a size/format combination
    ++    // return -1 if input size/format combination cannot be found.
    ++    int64_t getMinFrameDurationNs(Parameters::Size size, int format);
    ++
    ++    // Helper function to check if a given fps is supported by all the sizes with
    ++    // the same format.
    ++    // return true if the device doesn't support min frame duration metadata tag.
    ++    bool isFpsSupported(const Vector<Size> &size, int format, int32_t fps);
    ++
    +     // Helper function to get non-duplicated available output formats
    +     SortedVector<int32_t> getAvailableOutputFormats();
    +     // Helper function to get available output jpeg sizes
    +diff --git a/services/camera/libcameraservice/device3/Camera3Device.cpp b/services/camera/libcameraservice/device3/Camera3Device.cpp
    +index aeab451..48a2a99 100644
    +--- a/services/camera/libcameraservice/device3/Camera3Device.cpp
    ++++ b/services/camera/libcameraservice/device3/Camera3Device.cpp
    +@@ -170,6 +170,9 @@ status_t Camera3Device::initialize(CameraModule *module)
    +         return res;
    +     }
    + 
    ++    /** Register in-flight map to the status tracker */
    ++    mInFlightStatusId = mStatusTracker->addComponent();
    ++
    +     /** Create buffer manager */
    +     mBufferManager = new Camera3BufferManager();
    + 
    +@@ -2196,6 +2199,10 @@ status_t Camera3Device::registerInFlight(uint32_t frameNumber,
    +             aeTriggerCancelOverride));
    +     if (res < 0) return res;
    + 
    ++    if (mInFlightMap.size() == 1) {
    ++        mStatusTracker->markComponentActive(mInFlightStatusId);
    ++    }
    ++
    +     return OK;
    + }
    + 
    +@@ -2252,6 +2259,11 @@ void Camera3Device::removeInFlightRequestIfReadyLocked(int idx) {
    + 
    +         mInFlightMap.removeItemsAt(idx, 1);
    + 
    ++        // Indicate idle inFlightMap to the status tracker
    ++        if (mInFlightMap.size() == 0) {
    ++            mStatusTracker->markComponentIdle(mInFlightStatusId, Fence::NO_FENCE);
    ++        }
    ++
    +         ALOGVV("%s: removed frame %d from InFlightMap", __FUNCTION__, frameNumber);
    +      }
    + 
    +diff --git a/services/camera/libcameraservice/device3/Camera3Device.h b/services/camera/libcameraservice/device3/Camera3Device.h
    +index 3244258..17893a9 100644
    +--- a/services/camera/libcameraservice/device3/Camera3Device.h
    ++++ b/services/camera/libcameraservice/device3/Camera3Device.h
    +@@ -725,6 +725,7 @@ class Camera3Device :
    + 
    +     Mutex                  mInFlightLock; // Protects mInFlightMap
    +     InFlightMap            mInFlightMap;
    ++    int                    mInFlightStatusId;
    + 
    +     status_t registerInFlight(uint32_t frameNumber,
    +             int32_t numBuffers, CaptureResultExtras resultExtras, bool hasInput,
    diff --git a/frameworks_base.patch b/frameworks_base.patch
    index cd0ee1c..ee99cdf 100644
    --- a/frameworks_base.patch
    +++ b/frameworks_base.patch
    @@ -1,334 +1,192820 @@
    +diff --git a/Android.mk b/Android.mk
    +index 2c99df7..d813c91 100644
    +--- a/Android.mk
    ++++ b/Android.mk
    +@@ -199,6 +199,7 @@ LOCAL_SRC_FILES += \
    + 	core/java/android/net/ICaptivePortal.aidl \
    + 	core/java/android/net/IConnectivityManager.aidl \
    + 	core/java/android/net/IConnectivityMetricsLogger.aidl \
    ++	core/java/android/net/IIpConnectivityMetrics.aidl \
    + 	core/java/android/net/IEthernetManager.aidl \
    + 	core/java/android/net/IEthernetServiceListener.aidl \
    + 	core/java/android/net/INetworkManagementEventObserver.aidl \
    +@@ -859,6 +860,7 @@ framework_docs_LOCAL_DROIDDOC_OPTIONS := \
    +     -since $(SRC_API_DIR)/22.txt 22 \
    +     -since $(SRC_API_DIR)/23.txt 23 \
    +     -since $(SRC_API_DIR)/24.txt 24 \
    ++    -since $(SRC_API_DIR)/25.txt 25 \
    + 		-werror -hide 111 -hide 113 \
    + 		-overview $(LOCAL_PATH)/core/java/overview.html
    + 
    +@@ -926,6 +928,7 @@ LOCAL_DROIDDOC_STUB_OUT_DIR := $(TARGET_OUT_COMMON_INTERMEDIATES)/JAVA_LIBRARIES
    + 
    + LOCAL_DROIDDOC_OPTIONS:=\
    + 		$(framework_docs_LOCAL_DROIDDOC_OPTIONS) \
    ++		-referenceonly \
    + 		-api $(INTERNAL_PLATFORM_API_FILE) \
    + 		-removedApi $(INTERNAL_PLATFORM_REMOVED_API_FILE) \
    + 		-nodocs
    +@@ -959,6 +962,7 @@ LOCAL_DROIDDOC_STUB_OUT_DIR := $(TARGET_OUT_COMMON_INTERMEDIATES)/JAVA_LIBRARIES
    + 
    + LOCAL_DROIDDOC_OPTIONS:=\
    + 		$(framework_docs_LOCAL_DROIDDOC_OPTIONS) \
    ++		-referenceonly \
    + 		-showAnnotation android.annotation.SystemApi \
    + 		-api $(INTERNAL_PLATFORM_SYSTEM_API_FILE) \
    + 		-removedApi $(INTERNAL_PLATFORM_SYSTEM_REMOVED_API_FILE) \
    +@@ -993,6 +997,7 @@ LOCAL_DROIDDOC_STUB_OUT_DIR := $(TARGET_OUT_COMMON_INTERMEDIATES)/JAVA_LIBRARIES
    + 
    + LOCAL_DROIDDOC_OPTIONS:=\
    +                $(framework_docs_LOCAL_DROIDDOC_OPTIONS) \
    ++               -referenceonly \
    +                -stubs $(TARGET_OUT_COMMON_INTERMEDIATES)/JAVA_LIBRARIES/android_test_stubs_current_intermediates/src \
    +                -showAnnotation android.annotation.TestApi \
    +                -api $(INTERNAL_PLATFORM_TEST_API_FILE) \
    +@@ -1026,6 +1031,7 @@ LOCAL_MODULE := doc-comment-check
    + 
    + LOCAL_DROIDDOC_OPTIONS:=\
    + 		$(framework_docs_LOCAL_DROIDDOC_OPTIONS) \
    ++		-referenceonly \
    + 		-parsecomments
    + 
    + LOCAL_DROIDDOC_CUSTOM_TEMPLATE_DIR:=build/tools/droiddoc/templates-sdk
    +@@ -1064,7 +1070,7 @@ LOCAL_DROIDDOC_OPTIONS:=\
    + 		-sdkvalues $(OUT_DOCS) \
    + 		-hdf android.whichdoc offline
    + 
    +-LOCAL_DROIDDOC_CUSTOM_TEMPLATE_DIR:=build/tools/droiddoc/templates-sdk-dev
    ++LOCAL_DROIDDOC_CUSTOM_TEMPLATE_DIR:=build/tools/droiddoc/templates-sdk
    + 
    + include $(BUILD_DROIDDOC)
    + 
    +@@ -1101,7 +1107,7 @@ LOCAL_DROIDDOC_OPTIONS:=\
    + 		-hdf android.whichdoc offline \
    + 		-referenceonly
    + 
    +-LOCAL_DROIDDOC_CUSTOM_TEMPLATE_DIR:=build/tools/droiddoc/templates-sdk-dev
    ++LOCAL_DROIDDOC_CUSTOM_TEMPLATE_DIR:=build/tools/droiddoc/templates-sdk
    + 
    + include $(BUILD_DROIDDOC)
    + 
    +@@ -1111,7 +1117,14 @@ $(static_doc_index_redirect): \
    + 	$(hide) mkdir -p $(dir $@)
    + 	$(hide) $(ACP) $< $@
    + 
    ++static_doc_properties := $(out_dir)/source.properties
    ++$(static_doc_properties): \
    ++	$(LOCAL_PATH)/docs/source.properties | $(ACP)
    ++	$(hide) mkdir -p $(dir $@)
    ++	$(hide) $(ACP) $< $@
    ++
    + $(full_target): $(static_doc_index_redirect)
    ++$(full_target): $(static_doc_properties)
    + $(full_target): $(framework_built)
    + 
    + 
    +@@ -1139,7 +1152,7 @@ LOCAL_DROIDDOC_OPTIONS:= \
    + 		-hdf android.hasSamples true \
    + 		-samplesdir $(samples_dir)
    + 
    +-LOCAL_DROIDDOC_CUSTOM_TEMPLATE_DIR:=build/tools/droiddoc/templates-sdk-dev
    ++LOCAL_DROIDDOC_CUSTOM_TEMPLATE_DIR:=build/tools/droiddoc/templates-sdk
    + 
    + include $(BUILD_DROIDDOC)
    + 
    +@@ -1163,6 +1176,7 @@ LOCAL_MODULE := online-system-api-sdk
    + 
    + LOCAL_DROIDDOC_OPTIONS:= \
    + 		$(framework_docs_LOCAL_DROIDDOC_OPTIONS) \
    ++		-referenceonly \
    + 		-showAnnotation android.annotation.SystemApi \
    + 		-title "Android SDK - Including system APIs." \
    + 		-toroot / \
    +@@ -1206,7 +1220,7 @@ LOCAL_DROIDDOC_OPTIONS:= \
    + 		-hdf android.hasSamples true \
    + 		-samplesdir $(samples_dir)
    + 
    +-LOCAL_DROIDDOC_CUSTOM_TEMPLATE_DIR:=build/tools/droiddoc/templates-sdk-dev
    ++LOCAL_DROIDDOC_CUSTOM_TEMPLATE_DIR:=build/tools/droiddoc/templates-sdk
    + 
    + include $(BUILD_DROIDDOC)
    + 
    +@@ -1234,7 +1248,32 @@ LOCAL_DROIDDOC_OPTIONS:= \
    + 		-devsite \
    + 		-ignoreJdLinks
    + 
    +-LOCAL_DROIDDOC_CUSTOM_TEMPLATE_DIR:=build/tools/droiddoc/templates-sdk-dev
    ++LOCAL_DROIDDOC_CUSTOM_TEMPLATE_DIR:=build/tools/droiddoc/templates-sdk
    ++
    ++include $(BUILD_DROIDDOC)
    ++
    ++# ==== generates full navtree for resolving @links in ds postprocessing ====
    ++include $(CLEAR_VARS)
    ++
    ++LOCAL_SRC_FILES:=$(framework_docs_LOCAL_SRC_FILES)
    ++LOCAL_INTERMEDIATE_SOURCES:=$(framework_docs_LOCAL_INTERMEDIATE_SOURCES)
    ++LOCAL_STATIC_JAVA_LIBRARIES:=$(framework_docs_LOCAL_STATIC_JAVA_LIBRARIES)
    ++LOCAL_JAVA_LIBRARIES:=$(framework_docs_LOCAL_JAVA_LIBRARIES)
    ++LOCAL_MODULE_CLASS:=$(framework_docs_LOCAL_MODULE_CLASS)
    ++LOCAL_DROIDDOC_SOURCE_PATH:=$(framework_docs_LOCAL_DROIDDOC_SOURCE_PATH)
    ++LOCAL_ADDITIONAL_JAVA_DIR:=$(framework_docs_LOCAL_ADDITIONAL_JAVA_DIR)
    ++LOCAL_ADDITIONAL_DEPENDENCIES:=$(framework_docs_LOCAL_ADDITIONAL_DEPENDENCIES)
    ++
    ++LOCAL_MODULE := ds-ref-navtree
    ++
    ++LOCAL_DROIDDOC_OPTIONS:= \
    ++		$(framework_docs_LOCAL_DROIDDOC_OPTIONS) \
    ++		-hdf android.whichdoc online \
    ++		-toroot / \
    ++		-atLinksNavtree \
    ++		-navtreeonly
    ++
    ++LOCAL_DROIDDOC_CUSTOM_TEMPLATE_DIR:=build/tools/droiddoc/templates-sdk
    + 
    + include $(BUILD_DROIDDOC)
    + 
    +@@ -1259,11 +1298,10 @@ LOCAL_DROIDDOC_OPTIONS:= \
    + 		-toroot / \
    + 		-hdf android.whichdoc online \
    + 		$(sample_groups) \
    +-		-useUpdatedTemplates \
    + 		-hdf android.hasSamples true \
    + 		-samplesdir $(samples_dir)
    + 
    +-LOCAL_DROIDDOC_CUSTOM_TEMPLATE_DIR:=build/tools/droiddoc/templates-sdk-dev
    ++LOCAL_DROIDDOC_CUSTOM_TEMPLATE_DIR:=build/tools/droiddoc/templates-sdk
    + 
    + include $(BUILD_DROIDDOC)
    + 
    +@@ -1282,6 +1320,7 @@ LOCAL_ADDITIONAL_DEPENDENCIES:=$(framework_docs_LOCAL_ADDITIONAL_DEPENDENCIES)
    + LOCAL_MODULE := hidden
    + LOCAL_DROIDDOC_OPTIONS:=\
    + 		$(framework_docs_LOCAL_DROIDDOC_OPTIONS) \
    ++		-referenceonly \
    + 		-title "Android SDK - Including hidden APIs."
    + #		-hidden
    + 
    +diff --git a/api/current.txt b/api/current.txt
    +index 533b577..8655d89 100644
    +--- a/api/current.txt
    ++++ b/api/current.txt
    +@@ -2906,11 +2906,11 @@ package android.accounts {
    +     field public static final java.lang.String LOGIN_ACCOUNTS_CHANGED_ACTION = "android.accounts.LOGIN_ACCOUNTS_CHANGED";
    +   }
    + 
    +-  public abstract interface AccountManagerCallback {
    ++  public abstract interface AccountManagerCallback<V> {
    +     method public abstract void run(android.accounts.AccountManagerFuture<V>);
    +   }
    + 
    +-  public abstract interface AccountManagerFuture {
    ++  public abstract interface AccountManagerFuture<V> {
    +     method public abstract boolean cancel(boolean);
    +     method public abstract V getResult() throws android.accounts.AuthenticatorException, java.io.IOException, android.accounts.OperationCanceledException;
    +     method public abstract V getResult(long, java.util.concurrent.TimeUnit) throws android.accounts.AuthenticatorException, java.io.IOException, android.accounts.OperationCanceledException;
    +@@ -3056,7 +3056,7 @@ package android.animation {
    +     method public java.lang.Object evaluate(float, java.lang.Object, java.lang.Object);
    +   }
    + 
    +-  public abstract class BidirectionalTypeConverter extends android.animation.TypeConverter {
    ++  public abstract class BidirectionalTypeConverter<T, V> extends android.animation.TypeConverter {
    +     ctor public BidirectionalTypeConverter(java.lang.Class<T>, java.lang.Class<V>);
    +     method public abstract T convertBack(V);
    +     method public android.animation.BidirectionalTypeConverter<V, T> invert();
    +@@ -3148,26 +3148,26 @@ package android.animation {
    +     method public java.lang.String getPropertyName();
    +     method public java.lang.Object getTarget();
    +     method public static android.animation.ObjectAnimator ofArgb(java.lang.Object, java.lang.String, int...);
    +-    method public static android.animation.ObjectAnimator ofArgb(T, android.util.Property<T, java.lang.Integer>, int...);
    ++    method public static <T> android.animation.ObjectAnimator ofArgb(T, android.util.Property<T, java.lang.Integer>, int...);
    +     method public static android.animation.ObjectAnimator ofFloat(java.lang.Object, java.lang.String, float...);
    +     method public static android.animation.ObjectAnimator ofFloat(java.lang.Object, java.lang.String, java.lang.String, android.graphics.Path);
    +-    method public static android.animation.ObjectAnimator ofFloat(T, android.util.Property<T, java.lang.Float>, float...);
    +-    method public static android.animation.ObjectAnimator ofFloat(T, android.util.Property<T, java.lang.Float>, android.util.Property<T, java.lang.Float>, android.graphics.Path);
    ++    method public static <T> android.animation.ObjectAnimator ofFloat(T, android.util.Property<T, java.lang.Float>, float...);
    ++    method public static <T> android.animation.ObjectAnimator ofFloat(T, android.util.Property<T, java.lang.Float>, android.util.Property<T, java.lang.Float>, android.graphics.Path);
    +     method public static android.animation.ObjectAnimator ofInt(java.lang.Object, java.lang.String, int...);
    +     method public static android.animation.ObjectAnimator ofInt(java.lang.Object, java.lang.String, java.lang.String, android.graphics.Path);
    +-    method public static android.animation.ObjectAnimator ofInt(T, android.util.Property<T, java.lang.Integer>, int...);
    +-    method public static android.animation.ObjectAnimator ofInt(T, android.util.Property<T, java.lang.Integer>, android.util.Property<T, java.lang.Integer>, android.graphics.Path);
    ++    method public static <T> android.animation.ObjectAnimator ofInt(T, android.util.Property<T, java.lang.Integer>, int...);
    ++    method public static <T> android.animation.ObjectAnimator ofInt(T, android.util.Property<T, java.lang.Integer>, android.util.Property<T, java.lang.Integer>, android.graphics.Path);
    +     method public static android.animation.ObjectAnimator ofMultiFloat(java.lang.Object, java.lang.String, float[][]);
    +     method public static android.animation.ObjectAnimator ofMultiFloat(java.lang.Object, java.lang.String, android.graphics.Path);
    +-    method public static android.animation.ObjectAnimator ofMultiFloat(java.lang.Object, java.lang.String, android.animation.TypeConverter<T, float[]>, android.animation.TypeEvaluator<T>, T...);
    ++    method public static <T> android.animation.ObjectAnimator ofMultiFloat(java.lang.Object, java.lang.String, android.animation.TypeConverter<T, float[]>, android.animation.TypeEvaluator<T>, T...);
    +     method public static android.animation.ObjectAnimator ofMultiInt(java.lang.Object, java.lang.String, int[][]);
    +     method public static android.animation.ObjectAnimator ofMultiInt(java.lang.Object, java.lang.String, android.graphics.Path);
    +-    method public static android.animation.ObjectAnimator ofMultiInt(java.lang.Object, java.lang.String, android.animation.TypeConverter<T, int[]>, android.animation.TypeEvaluator<T>, T...);
    ++    method public static <T> android.animation.ObjectAnimator ofMultiInt(java.lang.Object, java.lang.String, android.animation.TypeConverter<T, int[]>, android.animation.TypeEvaluator<T>, T...);
    +     method public static android.animation.ObjectAnimator ofObject(java.lang.Object, java.lang.String, android.animation.TypeEvaluator, java.lang.Object...);
    +     method public static android.animation.ObjectAnimator ofObject(java.lang.Object, java.lang.String, android.animation.TypeConverter<android.graphics.PointF, ?>, android.graphics.Path);
    +-    method public static android.animation.ObjectAnimator ofObject(T, android.util.Property<T, V>, android.animation.TypeEvaluator<V>, V...);
    +-    method public static android.animation.ObjectAnimator ofObject(T, android.util.Property<T, P>, android.animation.TypeConverter<V, P>, android.animation.TypeEvaluator<V>, V...);
    +-    method public static android.animation.ObjectAnimator ofObject(T, android.util.Property<T, V>, android.animation.TypeConverter<android.graphics.PointF, V>, android.graphics.Path);
    ++    method public static <T, V> android.animation.ObjectAnimator ofObject(T, android.util.Property<T, V>, android.animation.TypeEvaluator<V>, V...);
    ++    method public static <T, V, P> android.animation.ObjectAnimator ofObject(T, android.util.Property<T, P>, android.animation.TypeConverter<V, P>, android.animation.TypeEvaluator<V>, V...);
    ++    method public static <T, V> android.animation.ObjectAnimator ofObject(T, android.util.Property<T, V>, android.animation.TypeConverter<android.graphics.PointF, V>, android.graphics.Path);
    +     method public static android.animation.ObjectAnimator ofPropertyValuesHolder(java.lang.Object, android.animation.PropertyValuesHolder...);
    +     method public void setAutoCancel(boolean);
    +     method public void setProperty(android.util.Property);
    +@@ -3191,17 +3191,17 @@ package android.animation {
    +     method public static android.animation.PropertyValuesHolder ofKeyframe(android.util.Property, android.animation.Keyframe...);
    +     method public static android.animation.PropertyValuesHolder ofMultiFloat(java.lang.String, float[][]);
    +     method public static android.animation.PropertyValuesHolder ofMultiFloat(java.lang.String, android.graphics.Path);
    +-    method public static android.animation.PropertyValuesHolder ofMultiFloat(java.lang.String, android.animation.TypeConverter<V, float[]>, android.animation.TypeEvaluator<V>, V...);
    +-    method public static android.animation.PropertyValuesHolder ofMultiFloat(java.lang.String, android.animation.TypeConverter<T, float[]>, android.animation.TypeEvaluator<T>, android.animation.Keyframe...);
    ++    method public static <V> android.animation.PropertyValuesHolder ofMultiFloat(java.lang.String, android.animation.TypeConverter<V, float[]>, android.animation.TypeEvaluator<V>, V...);
    ++    method public static <T> android.animation.PropertyValuesHolder ofMultiFloat(java.lang.String, android.animation.TypeConverter<T, float[]>, android.animation.TypeEvaluator<T>, android.animation.Keyframe...);
    +     method public static android.animation.PropertyValuesHolder ofMultiInt(java.lang.String, int[][]);
    +     method public static android.animation.PropertyValuesHolder ofMultiInt(java.lang.String, android.graphics.Path);
    +-    method public static android.animation.PropertyValuesHolder ofMultiInt(java.lang.String, android.animation.TypeConverter<V, int[]>, android.animation.TypeEvaluator<V>, V...);
    +-    method public static android.animation.PropertyValuesHolder ofMultiInt(java.lang.String, android.animation.TypeConverter<T, int[]>, android.animation.TypeEvaluator<T>, android.animation.Keyframe...);
    ++    method public static <V> android.animation.PropertyValuesHolder ofMultiInt(java.lang.String, android.animation.TypeConverter<V, int[]>, android.animation.TypeEvaluator<V>, V...);
    ++    method public static <T> android.animation.PropertyValuesHolder ofMultiInt(java.lang.String, android.animation.TypeConverter<T, int[]>, android.animation.TypeEvaluator<T>, android.animation.Keyframe...);
    +     method public static android.animation.PropertyValuesHolder ofObject(java.lang.String, android.animation.TypeEvaluator, java.lang.Object...);
    +     method public static android.animation.PropertyValuesHolder ofObject(java.lang.String, android.animation.TypeConverter<android.graphics.PointF, ?>, android.graphics.Path);
    +-    method public static android.animation.PropertyValuesHolder ofObject(android.util.Property, android.animation.TypeEvaluator<V>, V...);
    +-    method public static android.animation.PropertyValuesHolder ofObject(android.util.Property<?, V>, android.animation.TypeConverter<T, V>, android.animation.TypeEvaluator<T>, T...);
    +-    method public static android.animation.PropertyValuesHolder ofObject(android.util.Property<?, V>, android.animation.TypeConverter<android.graphics.PointF, V>, android.graphics.Path);
    ++    method public static <V> android.animation.PropertyValuesHolder ofObject(android.util.Property, android.animation.TypeEvaluator<V>, V...);
    ++    method public static <T, V> android.animation.PropertyValuesHolder ofObject(android.util.Property<?, V>, android.animation.TypeConverter<T, V>, android.animation.TypeEvaluator<T>, T...);
    ++    method public static <V> android.animation.PropertyValuesHolder ofObject(android.util.Property<?, V>, android.animation.TypeConverter<android.graphics.PointF, V>, android.graphics.Path);
    +     method public void setConverter(android.animation.TypeConverter);
    +     method public void setEvaluator(android.animation.TypeEvaluator);
    +     method public void setFloatValues(float...);
    +@@ -3238,12 +3238,12 @@ package android.animation {
    +     method public abstract float getInterpolation(float);
    +   }
    + 
    +-  public abstract class TypeConverter {
    ++  public abstract class TypeConverter<T, V> {
    +     ctor public TypeConverter(java.lang.Class<T>, java.lang.Class<V>);
    +     method public abstract V convert(T);
    +   }
    + 
    +-  public abstract interface TypeEvaluator {
    ++  public abstract interface TypeEvaluator<T> {
    +     method public abstract T evaluate(float, T, T);
    +   }
    + 
    +@@ -4571,7 +4571,7 @@ package android.app {
    +     method public android.os.Parcelable saveAllState();
    +   }
    + 
    +-  public abstract class FragmentHostCallback extends android.app.FragmentContainer {
    ++  public abstract class FragmentHostCallback<E> extends android.app.FragmentContainer {
    +     ctor public FragmentHostCallback(android.content.Context, android.os.Handler, int);
    +     method public void onAttachFragment(android.app.Fragment);
    +     method public void onDump(java.lang.String, java.io.FileDescriptor, java.io.PrintWriter, java.lang.String[]);
    +@@ -4838,12 +4838,12 @@ package android.app {
    +     method public abstract void destroyLoader(int);
    +     method public abstract void dump(java.lang.String, java.io.FileDescriptor, java.io.PrintWriter, java.lang.String[]);
    +     method public static void enableDebugLogging(boolean);
    +-    method public abstract android.content.Loader<D> getLoader(int);
    +-    method public abstract android.content.Loader<D> initLoader(int, android.os.Bundle, android.app.LoaderManager.LoaderCallbacks<D>);
    +-    method public abstract android.content.Loader<D> restartLoader(int, android.os.Bundle, android.app.LoaderManager.LoaderCallbacks<D>);
    ++    method public abstract <D> android.content.Loader<D> getLoader(int);
    ++    method public abstract <D> android.content.Loader<D> initLoader(int, android.os.Bundle, android.app.LoaderManager.LoaderCallbacks<D>);
    ++    method public abstract <D> android.content.Loader<D> restartLoader(int, android.os.Bundle, android.app.LoaderManager.LoaderCallbacks<D>);
    +   }
    + 
    +-  public static abstract interface LoaderManager.LoaderCallbacks {
    ++  public static abstract interface LoaderManager.LoaderCallbacks<D> {
    +     method public abstract android.content.Loader<D> onCreateLoader(int, android.os.Bundle);
    +     method public abstract void onLoadFinished(android.content.Loader<D>, D);
    +     method public abstract void onLoaderReset(android.content.Loader<D>);
    +@@ -7629,7 +7629,7 @@ package android.content {
    +     ctor public AsyncQueryHandler.WorkerHandler(android.os.Looper);
    +   }
    + 
    +-  public abstract class AsyncTaskLoader extends android.content.Loader {
    ++  public abstract class AsyncTaskLoader<D> extends android.content.Loader {
    +     ctor public AsyncTaskLoader(android.content.Context);
    +     method public void cancelLoadInBackground();
    +     method public boolean isLoadInBackgroundCanceled();
    +@@ -7811,7 +7811,7 @@ package android.content {
    +     method public android.os.ParcelFileDescriptor openFile(android.net.Uri, java.lang.String) throws java.io.FileNotFoundException;
    +     method public android.os.ParcelFileDescriptor openFile(android.net.Uri, java.lang.String, android.os.CancellationSignal) throws java.io.FileNotFoundException;
    +     method protected final android.os.ParcelFileDescriptor openFileHelper(android.net.Uri, java.lang.String) throws java.io.FileNotFoundException;
    +-    method public android.os.ParcelFileDescriptor openPipeHelper(android.net.Uri, java.lang.String, android.os.Bundle, T, android.content.ContentProvider.PipeDataWriter<T>) throws java.io.FileNotFoundException;
    ++    method public <T> android.os.ParcelFileDescriptor openPipeHelper(android.net.Uri, java.lang.String, android.os.Bundle, T, android.content.ContentProvider.PipeDataWriter<T>) throws java.io.FileNotFoundException;
    +     method public android.content.res.AssetFileDescriptor openTypedAssetFile(android.net.Uri, java.lang.String, android.os.Bundle) throws java.io.FileNotFoundException;
    +     method public android.content.res.AssetFileDescriptor openTypedAssetFile(android.net.Uri, java.lang.String, android.os.Bundle, android.os.CancellationSignal) throws java.io.FileNotFoundException;
    +     method public abstract android.database.Cursor query(android.net.Uri, java.lang.String[], java.lang.String, java.lang.String[], java.lang.String);
    +@@ -7824,7 +7824,7 @@ package android.content {
    +     method public abstract int update(android.net.Uri, android.content.ContentValues, java.lang.String, java.lang.String[]);
    +   }
    + 
    +-  public static abstract interface ContentProvider.PipeDataWriter {
    ++  public static abstract interface ContentProvider.PipeDataWriter<T> {
    +     method public abstract void writeDataToPipe(android.os.ParcelFileDescriptor, android.net.Uri, java.lang.String, android.os.Bundle, T);
    +   }
    + 
    +@@ -8095,7 +8095,7 @@ package android.content {
    +     method public final java.lang.String getString(int);
    +     method public final java.lang.String getString(int, java.lang.Object...);
    +     method public abstract java.lang.Object getSystemService(java.lang.String);
    +-    method public final T getSystemService(java.lang.Class<T>);
    ++    method public final <T> T getSystemService(java.lang.Class<T>);
    +     method public abstract java.lang.String getSystemServiceName(java.lang.Class<?>);
    +     method public final java.lang.CharSequence getText(int);
    +     method public abstract android.content.res.Resources.Theme getTheme();
    +@@ -8450,8 +8450,8 @@ package android.content {
    +     method public long getLongExtra(java.lang.String, long);
    +     method public java.lang.String getPackage();
    +     method public android.os.Parcelable[] getParcelableArrayExtra(java.lang.String);
    +-    method public java.util.ArrayList<T> getParcelableArrayListExtra(java.lang.String);
    +-    method public T getParcelableExtra(java.lang.String);
    ++    method public <T extends android.os.Parcelable> java.util.ArrayList<T> getParcelableArrayListExtra(java.lang.String);
    ++    method public <T extends android.os.Parcelable> T getParcelableExtra(java.lang.String);
    +     method public java.lang.String getScheme();
    +     method public android.content.Intent getSelector();
    +     method public java.io.Serializable getSerializableExtra(java.lang.String);
    +@@ -8926,7 +8926,7 @@ package android.content {
    +     ctor public IntentSender.SendIntentException(java.lang.Exception);
    +   }
    + 
    +-  public class Loader {
    ++  public class Loader<D> {
    +     ctor public Loader(android.content.Context);
    +     method public void abandon();
    +     method public boolean cancelLoad();
    +@@ -8963,11 +8963,11 @@ package android.content {
    +     ctor public Loader.ForceLoadContentObserver();
    +   }
    + 
    +-  public static abstract interface Loader.OnLoadCanceledListener {
    ++  public static abstract interface Loader.OnLoadCanceledListener<D> {
    +     method public abstract void onLoadCanceled(android.content.Loader<D>);
    +   }
    + 
    +-  public static abstract interface Loader.OnLoadCompleteListener {
    ++  public static abstract interface Loader.OnLoadCompleteListener<D> {
    +     method public abstract void onLoadComplete(android.content.Loader<D>, D);
    +   }
    + 
    +@@ -10839,7 +10839,7 @@ package android.database {
    +     method public boolean isNull(int);
    +   }
    + 
    +-  public abstract class Observable {
    ++  public abstract class Observable<T> {
    +     ctor public Observable();
    +     method public void registerObserver(T);
    +     method public void unregisterAll();
    +@@ -12729,7 +12729,7 @@ package android.graphics.drawable {
    +   public class AnimatedStateListDrawable extends android.graphics.drawable.StateListDrawable {
    +     ctor public AnimatedStateListDrawable();
    +     method public void addState(int[], android.graphics.drawable.Drawable, int);
    +-    method public void addTransition(int, int, T, boolean);
    ++    method public <T extends android.graphics.drawable.Drawable & android.graphics.drawable.Animatable> void addTransition(int, int, T, boolean);
    +   }
    + 
    +   public class AnimatedVectorDrawable extends android.graphics.drawable.Drawable implements android.graphics.drawable.Animatable2 {
    +@@ -13853,7 +13853,7 @@ package android.hardware.camera2 {
    +   }
    + 
    +   public final class CameraCharacteristics extends android.hardware.camera2.CameraMetadata {
    +-    method public T get(android.hardware.camera2.CameraCharacteristics.Key<T>);
    ++    method public <T> T get(android.hardware.camera2.CameraCharacteristics.Key<T>);
    +     method public java.util.List<android.hardware.camera2.CaptureRequest.Key<?>> getAvailableCaptureRequestKeys();
    +     method public java.util.List<android.hardware.camera2.CaptureResult.Key<?>> getAvailableCaptureResultKeys();
    +     field public static final android.hardware.camera2.CameraCharacteristics.Key<int[]> COLOR_CORRECTION_AVAILABLE_ABERRATION_MODES;
    +@@ -13938,7 +13938,7 @@ package android.hardware.camera2 {
    +     field public static final android.hardware.camera2.CameraCharacteristics.Key<java.lang.Integer> TONEMAP_MAX_CURVE_POINTS;
    +   }
    + 
    +-  public static final class CameraCharacteristics.Key {
    ++  public static final class CameraCharacteristics.Key<T> {
    +     method public final boolean equals(java.lang.Object);
    +     method public java.lang.String getName();
    +     method public final int hashCode();
    +@@ -14003,7 +14003,7 @@ package android.hardware.camera2 {
    +     method public void onTorchModeUnavailable(java.lang.String);
    +   }
    + 
    +-  public abstract class CameraMetadata {
    ++  public abstract class CameraMetadata<TKey> {
    +     method public java.util.List<TKey> getKeys();
    +     field public static final int COLOR_CORRECTION_ABERRATION_MODE_FAST = 1; // 0x1
    +     field public static final int COLOR_CORRECTION_ABERRATION_MODE_HIGH_QUALITY = 2; // 0x2
    +@@ -14211,7 +14211,7 @@ package android.hardware.camera2 {
    + 
    +   public final class CaptureRequest extends android.hardware.camera2.CameraMetadata implements android.os.Parcelable {
    +     method public int describeContents();
    +-    method public T get(android.hardware.camera2.CaptureRequest.Key<T>);
    ++    method public <T> T get(android.hardware.camera2.CaptureRequest.Key<T>);
    +     method public java.lang.Object getTag();
    +     method public boolean isReprocess();
    +     method public void writeToParcel(android.os.Parcel, int);
    +@@ -14274,20 +14274,20 @@ package android.hardware.camera2 {
    +   public static final class CaptureRequest.Builder {
    +     method public void addTarget(android.view.Surface);
    +     method public android.hardware.camera2.CaptureRequest build();
    +-    method public T get(android.hardware.camera2.CaptureRequest.Key<T>);
    ++    method public <T> T get(android.hardware.camera2.CaptureRequest.Key<T>);
    +     method public void removeTarget(android.view.Surface);
    +-    method public void set(android.hardware.camera2.CaptureRequest.Key<T>, T);
    ++    method public <T> void set(android.hardware.camera2.CaptureRequest.Key<T>, T);
    +     method public void setTag(java.lang.Object);
    +   }
    + 
    +-  public static final class CaptureRequest.Key {
    ++  public static final class CaptureRequest.Key<T> {
    +     method public final boolean equals(java.lang.Object);
    +     method public java.lang.String getName();
    +     method public final int hashCode();
    +   }
    + 
    +   public class CaptureResult extends android.hardware.camera2.CameraMetadata {
    +-    method public T get(android.hardware.camera2.CaptureResult.Key<T>);
    ++    method public <T> T get(android.hardware.camera2.CaptureResult.Key<T>);
    +     method public long getFrameNumber();
    +     method public android.hardware.camera2.CaptureRequest getRequest();
    +     method public int getSequenceId();
    +@@ -14368,7 +14368,7 @@ package android.hardware.camera2 {
    +     field public static final android.hardware.camera2.CaptureResult.Key<java.lang.Integer> TONEMAP_PRESET_CURVE;
    +   }
    + 
    +-  public static final class CaptureResult.Key {
    ++  public static final class CaptureResult.Key<T> {
    +     method public final boolean equals(java.lang.Object);
    +     method public java.lang.String getName();
    +     method public final int hashCode();
    +@@ -14493,14 +14493,14 @@ package android.hardware.camera2.params {
    +     method public android.util.Size[] getInputSizes(int);
    +     method public final int[] getOutputFormats();
    +     method public long getOutputMinFrameDuration(int, android.util.Size);
    +-    method public long getOutputMinFrameDuration(java.lang.Class<T>, android.util.Size);
    +-    method public android.util.Size[] getOutputSizes(java.lang.Class<T>);
    ++    method public <T> long getOutputMinFrameDuration(java.lang.Class<T>, android.util.Size);
    ++    method public <T> android.util.Size[] getOutputSizes(java.lang.Class<T>);
    +     method public android.util.Size[] getOutputSizes(int);
    +     method public long getOutputStallDuration(int, android.util.Size);
    +-    method public long getOutputStallDuration(java.lang.Class<T>, android.util.Size);
    ++    method public <T> long getOutputStallDuration(java.lang.Class<T>, android.util.Size);
    +     method public final int[] getValidOutputFormatsForInput(int);
    +     method public boolean isOutputSupportedFor(int);
    +-    method public static boolean isOutputSupportedFor(java.lang.Class<T>);
    ++    method public static <T> boolean isOutputSupportedFor(java.lang.Class<T>);
    +     method public boolean isOutputSupportedFor(android.view.Surface);
    +   }
    + 
    +@@ -16201,7 +16201,7 @@ package android.icu.math {
    + 
    + package android.icu.text {
    + 
    +-  public final class AlphabeticIndex implements java.lang.Iterable {
    ++  public final class AlphabeticIndex<V> implements java.lang.Iterable {
    +     ctor public AlphabeticIndex(android.icu.util.ULocale);
    +     ctor public AlphabeticIndex(java.util.Locale);
    +     ctor public AlphabeticIndex(android.icu.text.RuleBasedCollator);
    +@@ -16227,7 +16227,7 @@ package android.icu.text {
    +     method public android.icu.text.AlphabeticIndex<V> setUnderflowLabel(java.lang.String);
    +   }
    + 
    +-  public static class AlphabeticIndex.Bucket implements java.lang.Iterable {
    ++  public static class AlphabeticIndex.Bucket<V> implements java.lang.Iterable {
    +     method public java.lang.String getLabel();
    +     method public android.icu.text.AlphabeticIndex.Bucket.LabelType getLabelType();
    +     method public java.util.Iterator<android.icu.text.AlphabeticIndex.Record<V>> iterator();
    +@@ -16243,14 +16243,14 @@ package android.icu.text {
    +     enum_constant public static final android.icu.text.AlphabeticIndex.Bucket.LabelType UNDERFLOW;
    +   }
    + 
    +-  public static final class AlphabeticIndex.ImmutableIndex implements java.lang.Iterable {
    ++  public static final class AlphabeticIndex.ImmutableIndex<V> implements java.lang.Iterable {
    +     method public android.icu.text.AlphabeticIndex.Bucket<V> getBucket(int);
    +     method public int getBucketCount();
    +     method public int getBucketIndex(java.lang.CharSequence);
    +     method public java.util.Iterator<android.icu.text.AlphabeticIndex.Bucket<V>> iterator();
    +   }
    + 
    +-  public static class AlphabeticIndex.Record {
    ++  public static class AlphabeticIndex.Record<V> {
    +     method public V getData();
    +     method public java.lang.CharSequence getName();
    +   }
    +@@ -17763,8 +17763,8 @@ package android.icu.text {
    +     method public final android.icu.text.UnicodeSet addAll(java.lang.CharSequence);
    +     method public android.icu.text.UnicodeSet addAll(android.icu.text.UnicodeSet);
    +     method public android.icu.text.UnicodeSet addAll(java.lang.Iterable<?>);
    +-    method public android.icu.text.UnicodeSet addAll(T...);
    +-    method public T addAllTo(T);
    ++    method public <T extends java.lang.CharSequence> android.icu.text.UnicodeSet addAll(T...);
    ++    method public <T extends java.util.Collection<java.lang.String>> T addAllTo(T);
    +     method public void addMatchSetTo(android.icu.text.UnicodeSet);
    +     method public android.icu.text.UnicodeSet applyIntPropertyValue(int, int);
    +     method public final android.icu.text.UnicodeSet applyPattern(java.lang.String);
    +@@ -17792,15 +17792,15 @@ package android.icu.text {
    +     method public final boolean contains(java.lang.CharSequence);
    +     method public boolean containsAll(android.icu.text.UnicodeSet);
    +     method public boolean containsAll(java.lang.String);
    +-    method public boolean containsAll(java.lang.Iterable<T>);
    ++    method public <T extends java.lang.CharSequence> boolean containsAll(java.lang.Iterable<T>);
    +     method public boolean containsNone(int, int);
    +     method public boolean containsNone(android.icu.text.UnicodeSet);
    +     method public boolean containsNone(java.lang.CharSequence);
    +-    method public boolean containsNone(java.lang.Iterable<T>);
    ++    method public <T extends java.lang.CharSequence> boolean containsNone(java.lang.Iterable<T>);
    +     method public final boolean containsSome(int, int);
    +     method public final boolean containsSome(android.icu.text.UnicodeSet);
    +     method public final boolean containsSome(java.lang.CharSequence);
    +-    method public final boolean containsSome(java.lang.Iterable<T>);
    ++    method public final <T extends java.lang.CharSequence> boolean containsSome(java.lang.Iterable<T>);
    +     method public android.icu.text.UnicodeSet freeze();
    +     method public static android.icu.text.UnicodeSet from(java.lang.CharSequence);
    +     method public static android.icu.text.UnicodeSet fromAll(java.lang.CharSequence);
    +@@ -17818,14 +17818,14 @@ package android.icu.text {
    +     method public final android.icu.text.UnicodeSet remove(java.lang.CharSequence);
    +     method public final android.icu.text.UnicodeSet removeAll(java.lang.CharSequence);
    +     method public android.icu.text.UnicodeSet removeAll(android.icu.text.UnicodeSet);
    +-    method public android.icu.text.UnicodeSet removeAll(java.lang.Iterable<T>);
    ++    method public <T extends java.lang.CharSequence> android.icu.text.UnicodeSet removeAll(java.lang.Iterable<T>);
    +     method public final android.icu.text.UnicodeSet removeAllStrings();
    +     method public android.icu.text.UnicodeSet retain(int, int);
    +     method public final android.icu.text.UnicodeSet retain(int);
    +     method public final android.icu.text.UnicodeSet retain(java.lang.CharSequence);
    +     method public final android.icu.text.UnicodeSet retainAll(java.lang.CharSequence);
    +     method public android.icu.text.UnicodeSet retainAll(android.icu.text.UnicodeSet);
    +-    method public android.icu.text.UnicodeSet retainAll(java.lang.Iterable<T>);
    ++    method public <T extends java.lang.CharSequence> android.icu.text.UnicodeSet retainAll(java.lang.Iterable<T>);
    +     method public android.icu.text.UnicodeSet set(int, int);
    +     method public android.icu.text.UnicodeSet set(android.icu.text.UnicodeSet);
    +     method public int size();
    +@@ -18235,7 +18235,7 @@ package android.icu.util {
    +     method public long getToDate();
    +   }
    + 
    +-  public abstract interface Freezable implements java.lang.Cloneable {
    ++  public abstract interface Freezable<T> implements java.lang.Cloneable {
    +     method public abstract T cloneAsThawed();
    +     method public abstract T freeze();
    +     method public abstract boolean isFrozen();
    +@@ -18517,7 +18517,7 @@ package android.icu.util {
    +     field public static final android.icu.util.TimeUnit YEAR;
    +   }
    + 
    +-  public class Output {
    ++  public class Output<T> {
    +     ctor public Output();
    +     ctor public Output(T);
    +     field public T value;
    +@@ -28169,7 +28169,7 @@ package android.opengl {
    + 
    + package android.os {
    + 
    +-  public abstract class AsyncTask {
    ++  public abstract class AsyncTask<Params, Progress, Result> {
    +     ctor public AsyncTask();
    +     method public final boolean cancel(boolean);
    +     method protected abstract Result doInBackground(Params...);
    +@@ -28396,16 +28396,16 @@ package android.os {
    +     method public float getFloat(java.lang.String, float);
    +     method public float[] getFloatArray(java.lang.String);
    +     method public java.util.ArrayList<java.lang.Integer> getIntegerArrayList(java.lang.String);
    +-    method public T getParcelable(java.lang.String);
    ++    method public <T extends android.os.Parcelable> T getParcelable(java.lang.String);
    +     method public android.os.Parcelable[] getParcelableArray(java.lang.String);
    +-    method public java.util.ArrayList<T> getParcelableArrayList(java.lang.String);
    ++    method public <T extends android.os.Parcelable> java.util.ArrayList<T> getParcelableArrayList(java.lang.String);
    +     method public java.io.Serializable getSerializable(java.lang.String);
    +     method public short getShort(java.lang.String);
    +     method public short getShort(java.lang.String, short);
    +     method public short[] getShortArray(java.lang.String);
    +     method public android.util.Size getSize(java.lang.String);
    +     method public android.util.SizeF getSizeF(java.lang.String);
    +-    method public android.util.SparseArray<T> getSparseParcelableArray(java.lang.String);
    ++    method public <T extends android.os.Parcelable> android.util.SparseArray<T> getSparseParcelableArray(java.lang.String);
    +     method public java.util.ArrayList<java.lang.String> getStringArrayList(java.lang.String);
    +     method public boolean hasFileDescriptors();
    +     method public void putAll(android.os.Bundle);
    +@@ -28910,8 +28910,8 @@ package android.os {
    +     method public final long[] createLongArray();
    +     method public final java.lang.String[] createStringArray();
    +     method public final java.util.ArrayList<java.lang.String> createStringArrayList();
    +-    method public final T[] createTypedArray(android.os.Parcelable.Creator<T>);
    +-    method public final java.util.ArrayList<T> createTypedArrayList(android.os.Parcelable.Creator<T>);
    ++    method public final <T> T[] createTypedArray(android.os.Parcelable.Creator<T>);
    ++    method public final <T> java.util.ArrayList<T> createTypedArrayList(android.os.Parcelable.Creator<T>);
    +     method public final int dataAvail();
    +     method public final int dataCapacity();
    +     method public final int dataPosition();
    +@@ -28944,7 +28944,7 @@ package android.os {
    +     method public final long readLong();
    +     method public final void readLongArray(long[]);
    +     method public final void readMap(java.util.Map, java.lang.ClassLoader);
    +-    method public final T readParcelable(java.lang.ClassLoader);
    ++    method public final <T extends android.os.Parcelable> T readParcelable(java.lang.ClassLoader);
    +     method public final android.os.Parcelable[] readParcelableArray(java.lang.ClassLoader);
    +     method public final android.os.PersistableBundle readPersistableBundle();
    +     method public final android.os.PersistableBundle readPersistableBundle(java.lang.ClassLoader);
    +@@ -28957,9 +28957,9 @@ package android.os {
    +     method public final void readStringArray(java.lang.String[]);
    +     method public final void readStringList(java.util.List<java.lang.String>);
    +     method public final android.os.IBinder readStrongBinder();
    +-    method public final void readTypedArray(T[], android.os.Parcelable.Creator<T>);
    +-    method public final void readTypedList(java.util.List<T>, android.os.Parcelable.Creator<T>);
    +-    method public final T readTypedObject(android.os.Parcelable.Creator<T>);
    ++    method public final <T> void readTypedArray(T[], android.os.Parcelable.Creator<T>);
    ++    method public final <T> void readTypedList(java.util.List<T>, android.os.Parcelable.Creator<T>);
    ++    method public final <T> T readTypedObject(android.os.Parcelable.Creator<T>);
    +     method public final java.lang.Object readValue(java.lang.ClassLoader);
    +     method public final void recycle();
    +     method public final void setDataCapacity(int);
    +@@ -28990,7 +28990,7 @@ package android.os {
    +     method public final void writeMap(java.util.Map);
    +     method public final void writeNoException();
    +     method public final void writeParcelable(android.os.Parcelable, int);
    +-    method public final void writeParcelableArray(T[], int);
    ++    method public final <T extends android.os.Parcelable> void writeParcelableArray(T[], int);
    +     method public final void writePersistableBundle(android.os.PersistableBundle);
    +     method public final void writeSerializable(java.io.Serializable);
    +     method public final void writeSize(android.util.Size);
    +@@ -29002,9 +29002,9 @@ package android.os {
    +     method public final void writeStringList(java.util.List<java.lang.String>);
    +     method public final void writeStrongBinder(android.os.IBinder);
    +     method public final void writeStrongInterface(android.os.IInterface);
    +-    method public final void writeTypedArray(T[], int);
    +-    method public final void writeTypedList(java.util.List<T>);
    +-    method public final void writeTypedObject(T, int);
    ++    method public final <T extends android.os.Parcelable> void writeTypedArray(T[], int);
    ++    method public final <T extends android.os.Parcelable> void writeTypedList(java.util.List<T>);
    ++    method public final <T extends android.os.Parcelable> void writeTypedObject(T, int);
    +     method public final void writeValue(java.lang.Object);
    +     field public static final android.os.Parcelable.Creator<java.lang.String> STRING_CREATOR;
    +   }
    +@@ -29082,11 +29082,11 @@ package android.os {
    +     field public static final int PARCELABLE_WRITE_RETURN_VALUE = 1; // 0x1
    +   }
    + 
    +-  public static abstract interface Parcelable.ClassLoaderCreator implements android.os.Parcelable.Creator {
    ++  public static abstract interface Parcelable.ClassLoaderCreator<T> implements android.os.Parcelable.Creator {
    +     method public abstract T createFromParcel(android.os.Parcel, java.lang.ClassLoader);
    +   }
    + 
    +-  public static abstract interface Parcelable.Creator {
    ++  public static abstract interface Parcelable.Creator<T> {
    +     method public abstract T createFromParcel(android.os.Parcel);
    +     method public abstract T[] newArray(int);
    +   }
    +@@ -29200,7 +29200,7 @@ package android.os {
    +     method public abstract void onProgress(int);
    +   }
    + 
    +-  public class RemoteCallbackList {
    ++  public class RemoteCallbackList<E extends android.os.IInterface> {
    +     ctor public RemoteCallbackList();
    +     method public int beginBroadcast();
    +     method public void finishBroadcast();
    +@@ -32482,7 +32482,7 @@ package android.provider {
    +     field public static final java.lang.String RADIO_CELL = "cell";
    +     field public static final java.lang.String RADIO_NFC = "nfc";
    +     field public static final java.lang.String RADIO_WIFI = "wifi";
    +-    field public static final java.lang.String SHOW_PROCESSES = "show_processes";
    ++    field public static final deprecated java.lang.String SHOW_PROCESSES = "show_processes";
    +     field public static final java.lang.String STAY_ON_WHILE_PLUGGED_IN = "stay_on_while_plugged_in";
    +     field public static final java.lang.String TRANSITION_ANIMATION_SCALE = "transition_animation_scale";
    +     field public static final java.lang.String USB_MASS_STORAGE_ENABLED = "usb_mass_storage_enabled";
    +@@ -34520,7 +34520,7 @@ package android.service.carrier {
    +     field public static final java.lang.String SERVICE_INTERFACE = "android.service.carrier.CarrierMessagingService";
    +   }
    + 
    +-  public static abstract interface CarrierMessagingService.ResultCallback {
    ++  public static abstract interface CarrierMessagingService.ResultCallback<T> {
    +     method public abstract void onReceiveResult(T) throws android.os.RemoteException;
    +   }
    + 
    +@@ -34671,7 +34671,7 @@ package android.service.media {
    +     field public static final java.lang.String EXTRA_SUGGESTED = "android.service.media.extra.SUGGESTED";
    +   }
    + 
    +-  public class MediaBrowserService.Result {
    ++  public class MediaBrowserService.Result<T> {
    +     method public void detach();
    +     method public void sendResult(T);
    +   }
    +@@ -37584,14 +37584,14 @@ package android.telephony.gsm {
    + 
    + package android.test {
    + 
    +-  public abstract deprecated class ActivityInstrumentationTestCase extends android.test.ActivityTestCase {
    ++  public abstract deprecated class ActivityInstrumentationTestCase<T extends android.app.Activity> extends android.test.ActivityTestCase {
    +     ctor public ActivityInstrumentationTestCase(java.lang.String, java.lang.Class<T>);
    +     ctor public ActivityInstrumentationTestCase(java.lang.String, java.lang.Class<T>, boolean);
    +     method public T getActivity();
    +     method public void testActivityTestCaseSetUpProperly() throws java.lang.Exception;
    +   }
    + 
    +-  public abstract deprecated class ActivityInstrumentationTestCase2 extends android.test.ActivityTestCase {
    ++  public abstract deprecated class ActivityInstrumentationTestCase2<T extends android.app.Activity> extends android.test.ActivityTestCase {
    +     ctor public deprecated ActivityInstrumentationTestCase2(java.lang.String, java.lang.Class<T>);
    +     ctor public ActivityInstrumentationTestCase2(java.lang.Class<T>);
    +     method public T getActivity();
    +@@ -37606,7 +37606,7 @@ package android.test {
    +     method protected void setActivity(android.app.Activity);
    +   }
    + 
    +-  public abstract deprecated class ActivityUnitTestCase extends android.test.ActivityTestCase {
    ++  public abstract deprecated class ActivityUnitTestCase<T extends android.app.Activity> extends android.test.ActivityTestCase {
    +     ctor public ActivityUnitTestCase(java.lang.Class<T>);
    +     method public T getActivity();
    +     method public int getFinishedActivityRequest();
    +@@ -37652,7 +37652,7 @@ package android.test {
    +     method public void testStarted(java.lang.String);
    +   }
    + 
    +-  public abstract deprecated class ApplicationTestCase extends android.test.AndroidTestCase {
    ++  public abstract deprecated class ApplicationTestCase<T extends android.app.Application> extends android.test.AndroidTestCase {
    +     ctor public ApplicationTestCase(java.lang.Class<T>);
    +     method protected final void createApplication();
    +     method public T getApplication();
    +@@ -37678,8 +37678,8 @@ package android.test {
    +     method public android.app.Instrumentation getInstrumentation();
    +     method public deprecated void injectInsrumentation(android.app.Instrumentation);
    +     method public void injectInstrumentation(android.app.Instrumentation);
    +-    method public final T launchActivity(java.lang.String, java.lang.Class<T>, android.os.Bundle);
    +-    method public final T launchActivityWithIntent(java.lang.String, java.lang.Class<T>, android.content.Intent);
    ++    method public final <T extends android.app.Activity> T launchActivity(java.lang.String, java.lang.Class<T>, android.os.Bundle);
    ++    method public final <T extends android.app.Activity> T launchActivityWithIntent(java.lang.String, java.lang.Class<T>, android.content.Intent);
    +     method public void runTestOnUiThread(java.lang.Runnable) throws java.lang.Throwable;
    +     method public void sendKeys(java.lang.String);
    +     method public void sendKeys(int...);
    +@@ -37719,7 +37719,7 @@ package android.test {
    + 
    +   public class LoaderTestCase extends android.test.AndroidTestCase {
    +     ctor public LoaderTestCase();
    +-    method public T getLoaderResultSynchronously(android.content.Loader<T>);
    ++    method public <T> T getLoaderResultSynchronously(android.content.Loader<T>);
    +   }
    + 
    +   public final deprecated class MoreAsserts {
    +@@ -37774,20 +37774,20 @@ package android.test {
    +     method public abstract void startTiming(boolean);
    +   }
    + 
    +-  public abstract deprecated class ProviderTestCase extends android.test.InstrumentationTestCase {
    ++  public abstract deprecated class ProviderTestCase<T extends android.content.ContentProvider> extends android.test.InstrumentationTestCase {
    +     ctor public ProviderTestCase(java.lang.Class<T>, java.lang.String);
    +     method public android.test.mock.MockContentResolver getMockContentResolver();
    +     method public android.test.IsolatedContext getMockContext();
    +     method public T getProvider();
    +-    method public static android.content.ContentResolver newResolverWithContentProviderFromSql(android.content.Context, java.lang.Class<T>, java.lang.String, java.lang.String, int, java.lang.String) throws java.lang.IllegalAccessException, java.lang.InstantiationException;
    ++    method public static <T extends android.content.ContentProvider> android.content.ContentResolver newResolverWithContentProviderFromSql(android.content.Context, java.lang.Class<T>, java.lang.String, java.lang.String, int, java.lang.String) throws java.lang.IllegalAccessException, java.lang.InstantiationException;
    +   }
    + 
    +-  public abstract class ProviderTestCase2 extends android.test.AndroidTestCase {
    ++  public abstract class ProviderTestCase2<T extends android.content.ContentProvider> extends android.test.AndroidTestCase {
    +     ctor public ProviderTestCase2(java.lang.Class<T>, java.lang.String);
    +     method public android.test.mock.MockContentResolver getMockContentResolver();
    +     method public android.test.IsolatedContext getMockContext();
    +     method public T getProvider();
    +-    method public static android.content.ContentResolver newResolverWithContentProviderFromSql(android.content.Context, java.lang.String, java.lang.Class<T>, java.lang.String, java.lang.String, int, java.lang.String) throws java.lang.IllegalAccessException, java.lang.InstantiationException;
    ++    method public static <T extends android.content.ContentProvider> android.content.ContentResolver newResolverWithContentProviderFromSql(android.content.Context, java.lang.String, java.lang.Class<T>, java.lang.String, java.lang.String, int, java.lang.String) throws java.lang.IllegalAccessException, java.lang.InstantiationException;
    +   }
    + 
    +   public deprecated class RenamingDelegatingContext extends android.content.ContextWrapper {
    +@@ -37795,11 +37795,11 @@ package android.test {
    +     ctor public RenamingDelegatingContext(android.content.Context, android.content.Context, java.lang.String);
    +     method public java.lang.String getDatabasePrefix();
    +     method public void makeExistingFilesAndDbsAccessible();
    +-    method public static T providerWithRenamedContext(java.lang.Class<T>, android.content.Context, java.lang.String) throws java.lang.IllegalAccessException, java.lang.InstantiationException;
    +-    method public static T providerWithRenamedContext(java.lang.Class<T>, android.content.Context, java.lang.String, boolean) throws java.lang.IllegalAccessException, java.lang.InstantiationException;
    ++    method public static <T extends android.content.ContentProvider> T providerWithRenamedContext(java.lang.Class<T>, android.content.Context, java.lang.String) throws java.lang.IllegalAccessException, java.lang.InstantiationException;
    ++    method public static <T extends android.content.ContentProvider> T providerWithRenamedContext(java.lang.Class<T>, android.content.Context, java.lang.String, boolean) throws java.lang.IllegalAccessException, java.lang.InstantiationException;
    +   }
    + 
    +-  public abstract deprecated class ServiceTestCase extends android.test.AndroidTestCase {
    ++  public abstract deprecated class ServiceTestCase<T extends android.app.Service> extends android.test.AndroidTestCase {
    +     ctor public ServiceTestCase(java.lang.Class<T>);
    +     method protected android.os.IBinder bindService(android.content.Intent);
    +     method public android.app.Application getApplication();
    +@@ -37812,7 +37812,7 @@ package android.test {
    +     method public void testServiceTestCaseSetUpProperly() throws java.lang.Exception;
    +   }
    + 
    +-  public abstract deprecated class SingleLaunchActivityTestCase extends android.test.InstrumentationTestCase {
    ++  public abstract deprecated class SingleLaunchActivityTestCase<T extends android.app.Activity> extends android.test.InstrumentationTestCase {
    +     ctor public SingleLaunchActivityTestCase(java.lang.String, java.lang.Class<T>);
    +     method public T getActivity();
    +     method public void testActivityTestCaseSetUpProperly() throws java.lang.Exception;
    +@@ -38167,7 +38167,7 @@ package android.test.suitebuilder {
    +     ctor public TestMethod(java.lang.String, java.lang.Class<? extends junit.framework.TestCase>);
    +     ctor public TestMethod(junit.framework.TestCase);
    +     method public junit.framework.TestCase createTest() throws java.lang.IllegalAccessException, java.lang.InstantiationException, java.lang.reflect.InvocationTargetException;
    +-    method public T getAnnotation(java.lang.Class<T>);
    ++    method public <T extends java.lang.annotation.Annotation> T getAnnotation(java.lang.Class<T>);
    +     method public java.lang.Class<? extends junit.framework.TestCase> getEnclosingClass();
    +     method public java.lang.String getEnclosingClassname();
    +     method public java.lang.String getName();
    +@@ -38610,7 +38610,7 @@ package android.text {
    +     method public int getSpanEnd(java.lang.Object);
    +     method public int getSpanFlags(java.lang.Object);
    +     method public int getSpanStart(java.lang.Object);
    +-    method public T[] getSpans(int, int, java.lang.Class<T>);
    ++    method public <T> T[] getSpans(int, int, java.lang.Class<T>);
    +     method public deprecated int getTextRunCursor(int, int, int, int, int, android.graphics.Paint);
    +     method public int getTextWatcherDepth();
    +     method public android.text.SpannableStringBuilder insert(int, java.lang.CharSequence, int, int);
    +@@ -38632,7 +38632,7 @@ package android.text {
    +     method public int getSpanEnd(java.lang.Object);
    +     method public int getSpanFlags(java.lang.Object);
    +     method public int getSpanStart(java.lang.Object);
    +-    method public T[] getSpans(int, int, java.lang.Class<T>);
    ++    method public <T> T[] getSpans(int, int, java.lang.Class<T>);
    +     method public final int length();
    +     method public int nextSpanTransition(int, int, java.lang.Class);
    +     method public final java.lang.String toString();
    +@@ -38642,7 +38642,7 @@ package android.text {
    +     method public abstract int getSpanEnd(java.lang.Object);
    +     method public abstract int getSpanFlags(java.lang.Object);
    +     method public abstract int getSpanStart(java.lang.Object);
    +-    method public abstract T[] getSpans(int, int, java.lang.Class<T>);
    ++    method public abstract <T> T[] getSpans(int, int, java.lang.Class<T>);
    +     method public abstract int nextSpanTransition(int, int, java.lang.Class);
    +     field public static final int SPAN_COMPOSING = 256; // 0x100
    +     field public static final int SPAN_EXCLUSIVE_EXCLUSIVE = 33; // 0x21
    +@@ -39619,7 +39619,7 @@ package android.text.style {
    +     field public static final int WEEKDAY_WEDNESDAY = 4; // 0x4
    +   }
    + 
    +-  public static class TtsSpan.Builder {
    ++  public static class TtsSpan.Builder<C extends android.text.style.TtsSpan.Builder<?>> {
    +     ctor public TtsSpan.Builder(java.lang.String);
    +     method public android.text.style.TtsSpan build();
    +     method public C setIntArgument(java.lang.String, int);
    +@@ -39715,7 +39715,7 @@ package android.text.style {
    +     method public android.text.style.TtsSpan.OrdinalBuilder setNumber(java.lang.String);
    +   }
    + 
    +-  public static class TtsSpan.SemioticClassBuilder extends android.text.style.TtsSpan.Builder {
    ++  public static class TtsSpan.SemioticClassBuilder<C extends android.text.style.TtsSpan.SemioticClassBuilder<?>> extends android.text.style.TtsSpan.Builder {
    +     ctor public TtsSpan.SemioticClassBuilder(java.lang.String);
    +     method public C setAnimacy(java.lang.String);
    +     method public C setCase(java.lang.String);
    +@@ -40122,7 +40122,7 @@ package android.util {
    +     ctor public AndroidRuntimeException(java.lang.Exception);
    +   }
    + 
    +-  public final class ArrayMap implements java.util.Map {
    ++  public final class ArrayMap<K, V> implements java.util.Map {
    +     ctor public ArrayMap();
    +     ctor public ArrayMap(int);
    +     ctor public ArrayMap(android.util.ArrayMap<K, V>);
    +@@ -40150,7 +40150,7 @@ package android.util {
    +     method public java.util.Collection<V> values();
    +   }
    + 
    +-  public final class ArraySet implements java.util.Collection java.util.Set {
    ++  public final class ArraySet<E> implements java.util.Collection java.util.Set {
    +     ctor public ArraySet();
    +     ctor public ArraySet(int);
    +     ctor public ArraySet(android.util.ArraySet<E>);
    +@@ -40171,7 +40171,7 @@ package android.util {
    +     method public boolean retainAll(java.util.Collection<?>);
    +     method public int size();
    +     method public java.lang.Object[] toArray();
    +-    method public T[] toArray(T[]);
    ++    method public <T> T[] toArray(T[]);
    +     method public E valueAt(int);
    +   }
    + 
    +@@ -40316,13 +40316,13 @@ package android.util {
    +   public deprecated class FloatMath {
    +   }
    + 
    +-  public abstract class FloatProperty extends android.util.Property {
    ++  public abstract class FloatProperty<T> extends android.util.Property {
    +     ctor public FloatProperty(java.lang.String);
    +     method public final void set(T, java.lang.Float);
    +     method public abstract void setValue(T, float);
    +   }
    + 
    +-  public abstract class IntProperty extends android.util.Property {
    ++  public abstract class IntProperty<T> extends android.util.Property {
    +     ctor public IntProperty(java.lang.String);
    +     method public final void set(T, java.lang.Integer);
    +     method public abstract void setValue(T, int);
    +@@ -40422,7 +40422,7 @@ package android.util {
    +     method public void println(java.lang.String);
    +   }
    + 
    +-  public class LongSparseArray implements java.lang.Cloneable {
    ++  public class LongSparseArray<E> implements java.lang.Cloneable {
    +     ctor public LongSparseArray();
    +     ctor public LongSparseArray(int);
    +     method public void append(long, E);
    +@@ -40442,7 +40442,7 @@ package android.util {
    +     method public E valueAt(int);
    +   }
    + 
    +-  public class LruCache {
    ++  public class LruCache<K, V> {
    +     ctor public LruCache(int);
    +     method protected V create(K);
    +     method public final synchronized int createCount();
    +@@ -40530,9 +40530,9 @@ package android.util {
    +     ctor public NoSuchPropertyException(java.lang.String);
    +   }
    + 
    +-  public class Pair {
    ++  public class Pair<F, S> {
    +     ctor public Pair(F, S);
    +-    method public static android.util.Pair<A, B> create(A, B);
    ++    method public static <A, B> android.util.Pair<A, B> create(A, B);
    +     field public final F first;
    +     field public final S second;
    +   }
    +@@ -40565,22 +40565,22 @@ package android.util {
    +     method public abstract void println(java.lang.String);
    +   }
    + 
    +-  public abstract class Property {
    ++  public abstract class Property<T, V> {
    +     ctor public Property(java.lang.Class<V>, java.lang.String);
    +     method public abstract V get(T);
    +     method public java.lang.String getName();
    +     method public java.lang.Class<V> getType();
    +     method public boolean isReadOnly();
    +-    method public static android.util.Property<T, V> of(java.lang.Class<T>, java.lang.Class<V>, java.lang.String);
    ++    method public static <T, V> android.util.Property<T, V> of(java.lang.Class<T>, java.lang.Class<V>, java.lang.String);
    +     method public void set(T, V);
    +   }
    + 
    +-  public final class Range {
    ++  public final class Range<T extends java.lang.Comparable<? super T>> {
    +     ctor public Range(T, T);
    +     method public T clamp(T);
    +     method public boolean contains(T);
    +     method public boolean contains(android.util.Range<T>);
    +-    method public static android.util.Range<T> create(T, T);
    ++    method public static <T extends java.lang.Comparable<? super T>> android.util.Range<T> create(T, T);
    +     method public android.util.Range<T> extend(android.util.Range<T>);
    +     method public android.util.Range<T> extend(T, T);
    +     method public android.util.Range<T> extend(T);
    +@@ -40624,7 +40624,7 @@ package android.util {
    +     method public static android.util.SizeF parseSizeF(java.lang.String) throws java.lang.NumberFormatException;
    +   }
    + 
    +-  public class SparseArray implements java.lang.Cloneable {
    ++  public class SparseArray<E> implements java.lang.Cloneable {
    +     ctor public SparseArray();
    +     ctor public SparseArray(int);
    +     method public void append(int, E);
    +@@ -45353,7 +45353,7 @@ package android.webkit {
    +     method public static java.lang.String stripAnchor(java.lang.String);
    +   }
    + 
    +-  public abstract interface ValueCallback {
    ++  public abstract interface ValueCallback<T> {
    +     method public abstract void onReceiveValue(T);
    +   }
    + 
    +@@ -46087,7 +46087,7 @@ package android.widget {
    +     field public static final int NO_SELECTION = -2147483648; // 0x80000000
    +   }
    + 
    +-  public abstract class AdapterView extends android.view.ViewGroup {
    ++  public abstract class AdapterView<T extends android.widget.Adapter> extends android.view.ViewGroup {
    +     ctor public AdapterView(android.content.Context);
    +     ctor public AdapterView(android.content.Context, android.util.AttributeSet);
    +     ctor public AdapterView(android.content.Context, android.util.AttributeSet, int);
    +@@ -46210,7 +46210,7 @@ package android.widget {
    +     ctor public AnalogClock(android.content.Context, android.util.AttributeSet, int, int);
    +   }
    + 
    +-  public class ArrayAdapter extends android.widget.BaseAdapter implements android.widget.Filterable android.widget.ThemedSpinnerAdapter {
    ++  public class ArrayAdapter<T> extends android.widget.BaseAdapter implements android.widget.Filterable android.widget.ThemedSpinnerAdapter {
    +     ctor public ArrayAdapter(android.content.Context, int);
    +     ctor public ArrayAdapter(android.content.Context, int, int);
    +     ctor public ArrayAdapter(android.content.Context, int, T[]);
    +@@ -46271,7 +46271,7 @@ package android.widget {
    +     method protected void performFiltering(java.lang.CharSequence, int);
    +     method public void performValidation();
    +     method protected void replaceText(java.lang.CharSequence);
    +-    method public void setAdapter(T);
    ++    method public <T extends android.widget.ListAdapter & android.widget.Filterable> void setAdapter(T);
    +     method public void setCompletionHint(java.lang.CharSequence);
    +     method public void setDropDownAnchor(int);
    +     method public void setDropDownBackgroundDrawable(android.graphics.drawable.Drawable);
    +@@ -48556,7 +48556,7 @@ package android.widget {
    + 
    + package com.android.internal.util {
    + 
    +-  public abstract interface Predicate {
    ++  public abstract interface Predicate<T> {
    +     method public abstract boolean apply(T);
    +   }
    + 
    +@@ -50603,13 +50603,13 @@ package java.lang {
    +     enum_constant public static final java.lang.Character.UnicodeScript YI;
    +   }
    + 
    +-  public final class Class implements java.lang.reflect.AnnotatedElement java.lang.reflect.GenericDeclaration java.io.Serializable java.lang.reflect.Type {
    +-    method public java.lang.Class<? extends U> asSubclass(java.lang.Class<U>);
    ++  public final class Class<T> implements java.lang.reflect.AnnotatedElement java.lang.reflect.GenericDeclaration java.io.Serializable java.lang.reflect.Type {
    ++    method public <U> java.lang.Class<? extends U> asSubclass(java.lang.Class<U>);
    +     method public T cast(java.lang.Object);
    +     method public boolean desiredAssertionStatus();
    +     method public static java.lang.Class<?> forName(java.lang.String) throws java.lang.ClassNotFoundException;
    +     method public static java.lang.Class<?> forName(java.lang.String, boolean, java.lang.ClassLoader) throws java.lang.ClassNotFoundException;
    +-    method public A getAnnotation(java.lang.Class<A>);
    ++    method public <A extends java.lang.annotation.Annotation> A getAnnotation(java.lang.Class<A>);
    +     method public java.lang.annotation.Annotation[] getAnnotations();
    +     method public java.lang.String getCanonicalName();
    +     method public java.lang.ClassLoader getClassLoader();
    +@@ -50726,7 +50726,7 @@ package java.lang {
    +   public abstract interface Cloneable {
    +   }
    + 
    +-  public abstract interface Comparable {
    ++  public abstract interface Comparable<T> {
    +     method public abstract int compareTo(T);
    +   }
    + 
    +@@ -50780,7 +50780,7 @@ package java.lang {
    +     field public static final java.lang.Class<java.lang.Double> TYPE;
    +   }
    + 
    +-  public abstract class Enum implements java.lang.Comparable java.io.Serializable {
    ++  public abstract class Enum<E extends java.lang.Enum<E>> implements java.lang.Comparable java.io.Serializable {
    +     ctor protected Enum(java.lang.String, int);
    +     method protected final java.lang.Object clone() throws java.lang.CloneNotSupportedException;
    +     method public final int compareTo(E);
    +@@ -50790,7 +50790,7 @@ package java.lang {
    +     method public final int hashCode();
    +     method public final java.lang.String name();
    +     method public final int ordinal();
    +-    method public static T valueOf(java.lang.Class<T>, java.lang.String);
    ++    method public static <T extends java.lang.Enum<T>> T valueOf(java.lang.Class<T>, java.lang.String);
    +   }
    + 
    +   public class EnumConstantNotPresentException extends java.lang.RuntimeException {
    +@@ -50909,7 +50909,7 @@ package java.lang {
    +     ctor public IndexOutOfBoundsException(java.lang.String);
    +   }
    + 
    +-  public class InheritableThreadLocal extends java.lang.ThreadLocal {
    ++  public class InheritableThreadLocal<T> extends java.lang.ThreadLocal {
    +     ctor public InheritableThreadLocal();
    +     method protected T childValue(T);
    +   }
    +@@ -50980,7 +50980,7 @@ package java.lang {
    +     ctor public InterruptedException(java.lang.String);
    +   }
    + 
    +-  public abstract interface Iterable {
    ++  public abstract interface Iterable<T> {
    +     method public default void forEach(java.util.function.Consumer<? super T>);
    +     method public abstract java.util.Iterator<T> iterator();
    +     method public default java.util.Spliterator<T> spliterator();
    +@@ -51188,12 +51188,12 @@ package java.lang {
    +   }
    + 
    +   public class Package implements java.lang.reflect.AnnotatedElement {
    +-    method public A getAnnotation(java.lang.Class<A>);
    ++    method public <A extends java.lang.annotation.Annotation> A getAnnotation(java.lang.Class<A>);
    +     method public java.lang.annotation.Annotation[] getAnnotations();
    +-    method public A[] getAnnotationsByType(java.lang.Class<A>);
    +-    method public A getDeclaredAnnotation(java.lang.Class<A>);
    ++    method public <A extends java.lang.annotation.Annotation> A[] getAnnotationsByType(java.lang.Class<A>);
    ++    method public <A extends java.lang.annotation.Annotation> A getDeclaredAnnotation(java.lang.Class<A>);
    +     method public java.lang.annotation.Annotation[] getDeclaredAnnotations();
    +-    method public A[] getDeclaredAnnotationsByType(java.lang.Class<A>);
    ++    method public <A extends java.lang.annotation.Annotation> A[] getDeclaredAnnotationsByType(java.lang.Class<A>);
    +     method public java.lang.String getImplementationTitle();
    +     method public java.lang.String getImplementationVendor();
    +     method public java.lang.String getImplementationVersion();
    +@@ -51753,7 +51753,7 @@ package java.lang {
    +     method public void uncaughtException(java.lang.Thread, java.lang.Throwable);
    +   }
    + 
    +-  public class ThreadLocal {
    ++  public class ThreadLocal<T> {
    +     ctor public ThreadLocal();
    +     method public T get();
    +     method protected T initialValue();
    +@@ -51893,30 +51893,30 @@ package java.lang.annotation {
    + 
    + package java.lang.ref {
    + 
    +-  public class PhantomReference extends java.lang.ref.Reference {
    ++  public class PhantomReference<T> extends java.lang.ref.Reference {
    +     ctor public PhantomReference(T, java.lang.ref.ReferenceQueue<? super T>);
    +   }
    + 
    +-  public abstract class Reference {
    ++  public abstract class Reference<T> {
    +     method public void clear();
    +     method public boolean enqueue();
    +     method public T get();
    +     method public boolean isEnqueued();
    +   }
    + 
    +-  public class ReferenceQueue {
    ++  public class ReferenceQueue<T> {
    +     ctor public ReferenceQueue();
    +     method public java.lang.ref.Reference<? extends T> poll();
    +     method public java.lang.ref.Reference<? extends T> remove(long) throws java.lang.IllegalArgumentException, java.lang.InterruptedException;
    +     method public java.lang.ref.Reference<? extends T> remove() throws java.lang.InterruptedException;
    +   }
    + 
    +-  public class SoftReference extends java.lang.ref.Reference {
    ++  public class SoftReference<T> extends java.lang.ref.Reference {
    +     ctor public SoftReference(T);
    +     ctor public SoftReference(T, java.lang.ref.ReferenceQueue<? super T>);
    +   }
    + 
    +-  public class WeakReference extends java.lang.ref.Reference {
    ++  public class WeakReference<T> extends java.lang.ref.Reference {
    +     ctor public WeakReference(T);
    +     ctor public WeakReference(T, java.lang.ref.ReferenceQueue<? super T>);
    +   }
    +@@ -51927,7 +51927,7 @@ package java.lang.reflect {
    + 
    +   public class AccessibleObject implements java.lang.reflect.AnnotatedElement {
    +     ctor protected AccessibleObject();
    +-    method public T getAnnotation(java.lang.Class<T>);
    ++    method public <T extends java.lang.annotation.Annotation> T getAnnotation(java.lang.Class<T>);
    +     method public java.lang.annotation.Annotation[] getAnnotations();
    +     method public java.lang.annotation.Annotation[] getDeclaredAnnotations();
    +     method public boolean isAccessible();
    +@@ -51936,12 +51936,12 @@ package java.lang.reflect {
    +   }
    + 
    +   public abstract interface AnnotatedElement {
    +-    method public abstract T getAnnotation(java.lang.Class<T>);
    ++    method public abstract <T extends java.lang.annotation.Annotation> T getAnnotation(java.lang.Class<T>);
    +     method public abstract java.lang.annotation.Annotation[] getAnnotations();
    +-    method public default T[] getAnnotationsByType(java.lang.Class<T>);
    +-    method public default java.lang.annotation.Annotation getDeclaredAnnotation(java.lang.Class<T>);
    ++    method public default <T extends java.lang.annotation.Annotation> T[] getAnnotationsByType(java.lang.Class<T>);
    ++    method public default <T extends java.lang.annotation.Annotation> java.lang.annotation.Annotation getDeclaredAnnotation(java.lang.Class<T>);
    +     method public abstract java.lang.annotation.Annotation[] getDeclaredAnnotations();
    +-    method public default T[] getDeclaredAnnotationsByType(java.lang.Class<T>);
    ++    method public default <T extends java.lang.annotation.Annotation> T[] getDeclaredAnnotationsByType(java.lang.Class<T>);
    +     method public default boolean isAnnotationPresent(java.lang.Class<? extends java.lang.annotation.Annotation>);
    +   }
    + 
    +@@ -51969,8 +51969,8 @@ package java.lang.reflect {
    +     method public static void setShort(java.lang.Object, int, short) throws java.lang.ArrayIndexOutOfBoundsException, java.lang.IllegalArgumentException;
    +   }
    + 
    +-  public final class Constructor extends java.lang.reflect.AccessibleObject implements java.lang.reflect.GenericDeclaration java.lang.reflect.Member {
    +-    method public A getAnnotation(java.lang.Class<A>);
    ++  public final class Constructor<T> extends java.lang.reflect.AccessibleObject implements java.lang.reflect.GenericDeclaration java.lang.reflect.Member {
    ++    method public <A extends java.lang.annotation.Annotation> A getAnnotation(java.lang.Class<A>);
    +     method public java.lang.Class<T> getDeclaringClass();
    +     method public java.lang.Class<?>[] getExceptionTypes();
    +     method public java.lang.reflect.Type[] getGenericExceptionTypes();
    +@@ -51989,7 +51989,7 @@ package java.lang.reflect {
    + 
    +   public final class Field extends java.lang.reflect.AccessibleObject implements java.lang.reflect.Member {
    +     method public java.lang.Object get(java.lang.Object) throws java.lang.IllegalAccessException, java.lang.IllegalArgumentException;
    +-    method public A getAnnotation(java.lang.Class<A>);
    ++    method public <A extends java.lang.annotation.Annotation> A getAnnotation(java.lang.Class<A>);
    +     method public boolean getBoolean(java.lang.Object) throws java.lang.IllegalAccessException, java.lang.IllegalArgumentException;
    +     method public byte getByte(java.lang.Object) throws java.lang.IllegalAccessException, java.lang.IllegalArgumentException;
    +     method public char getChar(java.lang.Object) throws java.lang.IllegalAccessException, java.lang.IllegalArgumentException;
    +@@ -52055,7 +52055,7 @@ package java.lang.reflect {
    +   }
    + 
    +   public final class Method extends java.lang.reflect.AccessibleObject implements java.lang.reflect.GenericDeclaration java.lang.reflect.Member {
    +-    method public A getAnnotation(java.lang.Class<A>);
    ++    method public <A extends java.lang.annotation.Annotation> A getAnnotation(java.lang.Class<A>);
    +     method public java.lang.Class<?> getDeclaringClass();
    +     method public java.lang.Object getDefaultValue();
    +     method public java.lang.Class<?>[] getExceptionTypes();
    +@@ -52133,7 +52133,7 @@ package java.lang.reflect {
    +   public abstract interface Type {
    +   }
    + 
    +-  public abstract interface TypeVariable implements java.lang.reflect.Type {
    ++  public abstract interface TypeVariable<D extends java.lang.reflect.GenericDeclaration> implements java.lang.reflect.Type {
    +     method public abstract java.lang.reflect.Type[] getBounds();
    +     method public abstract D getGenericDeclaration();
    +     method public abstract java.lang.String getName();
    +@@ -52922,7 +52922,7 @@ package java.net {
    +     method public abstract java.net.SocketImpl createSocketImpl();
    +   }
    + 
    +-  public abstract interface SocketOption {
    ++  public abstract interface SocketOption<T> {
    +     method public abstract java.lang.String name();
    +     method public abstract java.lang.Class<T> type();
    +   }
    +@@ -53506,7 +53506,7 @@ package java.nio.channels {
    +     method public final long read(java.nio.ByteBuffer[]) throws java.io.IOException;
    +     method public abstract java.net.SocketAddress receive(java.nio.ByteBuffer) throws java.io.IOException;
    +     method public abstract int send(java.nio.ByteBuffer, java.net.SocketAddress) throws java.io.IOException;
    +-    method public abstract java.nio.channels.DatagramChannel setOption(java.net.SocketOption<T>, T) throws java.io.IOException;
    ++    method public abstract <T> java.nio.channels.DatagramChannel setOption(java.net.SocketOption<T>, T) throws java.io.IOException;
    +     method public abstract java.net.DatagramSocket socket();
    +     method public final int validOps();
    +     method public abstract int write(java.nio.ByteBuffer) throws java.io.IOException;
    +@@ -53582,8 +53582,8 @@ package java.nio.channels {
    +   public abstract interface NetworkChannel implements java.nio.channels.Channel {
    +     method public abstract java.nio.channels.NetworkChannel bind(java.net.SocketAddress) throws java.io.IOException;
    +     method public abstract java.net.SocketAddress getLocalAddress() throws java.io.IOException;
    +-    method public abstract T getOption(java.net.SocketOption<T>) throws java.io.IOException;
    +-    method public abstract java.nio.channels.NetworkChannel setOption(java.net.SocketOption<T>, T) throws java.io.IOException;
    ++    method public abstract <T> T getOption(java.net.SocketOption<T>) throws java.io.IOException;
    ++    method public abstract <T> java.nio.channels.NetworkChannel setOption(java.net.SocketOption<T>, T) throws java.io.IOException;
    +     method public abstract java.util.Set<java.net.SocketOption<?>> supportedOptions();
    +   }
    + 
    +@@ -53700,7 +53700,7 @@ package java.nio.channels {
    +     method public final java.nio.channels.ServerSocketChannel bind(java.net.SocketAddress) throws java.io.IOException;
    +     method public abstract java.nio.channels.ServerSocketChannel bind(java.net.SocketAddress, int) throws java.io.IOException;
    +     method public static java.nio.channels.ServerSocketChannel open() throws java.io.IOException;
    +-    method public abstract java.nio.channels.ServerSocketChannel setOption(java.net.SocketOption<T>, T) throws java.io.IOException;
    ++    method public abstract <T> java.nio.channels.ServerSocketChannel setOption(java.net.SocketOption<T>, T) throws java.io.IOException;
    +     method public abstract java.net.ServerSocket socket();
    +     method public final int validOps();
    +   }
    +@@ -53718,7 +53718,7 @@ package java.nio.channels {
    +     method public abstract int read(java.nio.ByteBuffer) throws java.io.IOException;
    +     method public abstract long read(java.nio.ByteBuffer[], int, int) throws java.io.IOException;
    +     method public final long read(java.nio.ByteBuffer[]) throws java.io.IOException;
    +-    method public abstract java.nio.channels.SocketChannel setOption(java.net.SocketOption<T>, T) throws java.io.IOException;
    ++    method public abstract <T> java.nio.channels.SocketChannel setOption(java.net.SocketOption<T>, T) throws java.io.IOException;
    +     method public abstract java.nio.channels.SocketChannel shutdownInput() throws java.io.IOException;
    +     method public abstract java.nio.channels.SocketChannel shutdownOutput() throws java.io.IOException;
    +     method public abstract java.net.Socket socket();
    +@@ -53965,12 +53965,12 @@ package java.security {
    + 
    +   public final class AccessController {
    +     method public static void checkPermission(java.security.Permission) throws java.security.AccessControlException;
    +-    method public static T doPrivileged(java.security.PrivilegedAction<T>);
    +-    method public static T doPrivileged(java.security.PrivilegedAction<T>, java.security.AccessControlContext);
    +-    method public static T doPrivileged(java.security.PrivilegedExceptionAction<T>) throws java.security.PrivilegedActionException;
    +-    method public static T doPrivileged(java.security.PrivilegedExceptionAction<T>, java.security.AccessControlContext) throws java.security.PrivilegedActionException;
    +-    method public static T doPrivilegedWithCombiner(java.security.PrivilegedAction<T>);
    +-    method public static T doPrivilegedWithCombiner(java.security.PrivilegedExceptionAction<T>) throws java.security.PrivilegedActionException;
    ++    method public static <T> T doPrivileged(java.security.PrivilegedAction<T>);
    ++    method public static <T> T doPrivileged(java.security.PrivilegedAction<T>, java.security.AccessControlContext);
    ++    method public static <T> T doPrivileged(java.security.PrivilegedExceptionAction<T>) throws java.security.PrivilegedActionException;
    ++    method public static <T> T doPrivileged(java.security.PrivilegedExceptionAction<T>, java.security.AccessControlContext) throws java.security.PrivilegedActionException;
    ++    method public static <T> T doPrivilegedWithCombiner(java.security.PrivilegedAction<T>);
    ++    method public static <T> T doPrivilegedWithCombiner(java.security.PrivilegedExceptionAction<T>) throws java.security.PrivilegedActionException;
    +     method public static java.security.AccessControlContext getContext();
    +   }
    + 
    +@@ -54009,7 +54009,7 @@ package java.security {
    +     method public static java.security.AlgorithmParameters getInstance(java.lang.String) throws java.security.NoSuchAlgorithmException;
    +     method public static java.security.AlgorithmParameters getInstance(java.lang.String, java.lang.String) throws java.security.NoSuchAlgorithmException, java.security.NoSuchProviderException;
    +     method public static java.security.AlgorithmParameters getInstance(java.lang.String, java.security.Provider) throws java.security.NoSuchAlgorithmException;
    +-    method public final T getParameterSpec(java.lang.Class<T>) throws java.security.spec.InvalidParameterSpecException;
    ++    method public final <T extends java.security.spec.AlgorithmParameterSpec> T getParameterSpec(java.lang.Class<T>) throws java.security.spec.InvalidParameterSpecException;
    +     method public final java.security.Provider getProvider();
    +     method public final void init(java.security.spec.AlgorithmParameterSpec) throws java.security.spec.InvalidParameterSpecException;
    +     method public final void init(byte[]) throws java.io.IOException;
    +@@ -54021,7 +54021,7 @@ package java.security {
    +     ctor public AlgorithmParametersSpi();
    +     method protected abstract byte[] engineGetEncoded() throws java.io.IOException;
    +     method protected abstract byte[] engineGetEncoded(java.lang.String) throws java.io.IOException;
    +-    method protected abstract T engineGetParameterSpec(java.lang.Class<T>) throws java.security.spec.InvalidParameterSpecException;
    ++    method protected abstract <T extends java.security.spec.AlgorithmParameterSpec> T engineGetParameterSpec(java.lang.Class<T>) throws java.security.spec.InvalidParameterSpecException;
    +     method protected abstract void engineInit(java.security.spec.AlgorithmParameterSpec) throws java.security.spec.InvalidParameterSpecException;
    +     method protected abstract void engineInit(byte[]) throws java.io.IOException;
    +     method protected abstract void engineInit(byte[], java.lang.String) throws java.io.IOException;
    +@@ -54206,7 +54206,7 @@ package java.security {
    +     method public static java.security.KeyFactory getInstance(java.lang.String) throws java.security.NoSuchAlgorithmException;
    +     method public static java.security.KeyFactory getInstance(java.lang.String, java.lang.String) throws java.security.NoSuchAlgorithmException, java.security.NoSuchProviderException;
    +     method public static java.security.KeyFactory getInstance(java.lang.String, java.security.Provider) throws java.security.NoSuchAlgorithmException;
    +-    method public final T getKeySpec(java.security.Key, java.lang.Class<T>) throws java.security.spec.InvalidKeySpecException;
    ++    method public final <T extends java.security.spec.KeySpec> T getKeySpec(java.security.Key, java.lang.Class<T>) throws java.security.spec.InvalidKeySpecException;
    +     method public final java.security.Provider getProvider();
    +     method public final java.security.Key translateKey(java.security.Key) throws java.security.InvalidKeyException;
    +   }
    +@@ -54215,7 +54215,7 @@ package java.security {
    +     ctor public KeyFactorySpi();
    +     method protected abstract java.security.PrivateKey engineGeneratePrivate(java.security.spec.KeySpec) throws java.security.spec.InvalidKeySpecException;
    +     method protected abstract java.security.PublicKey engineGeneratePublic(java.security.spec.KeySpec) throws java.security.spec.InvalidKeySpecException;
    +-    method protected abstract T engineGetKeySpec(java.security.Key, java.lang.Class<T>) throws java.security.spec.InvalidKeySpecException;
    ++    method protected abstract <T extends java.security.spec.KeySpec> T engineGetKeySpec(java.security.Key, java.lang.Class<T>) throws java.security.spec.InvalidKeySpecException;
    +     method protected abstract java.security.Key engineTranslateKey(java.security.Key) throws java.security.InvalidKeyException;
    +   }
    + 
    +@@ -54484,7 +54484,7 @@ package java.security {
    +     field public static final long serialVersionUID = 6034044314589513430L; // 0x53bd3b559a12c6d6L
    +   }
    + 
    +-  public abstract interface PrivilegedAction {
    ++  public abstract interface PrivilegedAction<T> {
    +     method public abstract T run();
    +   }
    + 
    +@@ -54493,7 +54493,7 @@ package java.security {
    +     method public java.lang.Exception getException();
    +   }
    + 
    +-  public abstract interface PrivilegedExceptionAction {
    ++  public abstract interface PrivilegedExceptionAction<T> {
    +     method public abstract T run() throws java.lang.Exception;
    +   }
    + 
    +@@ -56675,11 +56675,11 @@ package java.sql {
    +     method public abstract void free() throws java.sql.SQLException;
    +     method public abstract java.io.InputStream getBinaryStream() throws java.sql.SQLException;
    +     method public abstract java.io.Reader getCharacterStream() throws java.sql.SQLException;
    +-    method public abstract T getSource(java.lang.Class<T>) throws java.sql.SQLException;
    ++    method public abstract <T extends javax.xml.transform.Source> T getSource(java.lang.Class<T>) throws java.sql.SQLException;
    +     method public abstract java.lang.String getString() throws java.sql.SQLException;
    +     method public abstract java.io.OutputStream setBinaryStream() throws java.sql.SQLException;
    +     method public abstract java.io.Writer setCharacterStream() throws java.sql.SQLException;
    +-    method public abstract T setResult(java.lang.Class<T>) throws java.sql.SQLException;
    ++    method public abstract <T extends javax.xml.transform.Result> T setResult(java.lang.Class<T>) throws java.sql.SQLException;
    +     method public abstract void setString(java.lang.String) throws java.sql.SQLException;
    +   }
    + 
    +@@ -56803,7 +56803,7 @@ package java.sql {
    + 
    +   public abstract interface Wrapper {
    +     method public abstract boolean isWrapperFor(java.lang.Class<?>) throws java.sql.SQLException;
    +-    method public abstract T unwrap(java.lang.Class<T>) throws java.sql.SQLException;
    ++    method public abstract <T> T unwrap(java.lang.Class<T>) throws java.sql.SQLException;
    +   }
    + 
    + }
    +@@ -57336,7 +57336,7 @@ package java.text {
    + 
    + package java.util {
    + 
    +-  public abstract class AbstractCollection implements java.util.Collection {
    ++  public abstract class AbstractCollection<E> implements java.util.Collection {
    +     ctor protected AbstractCollection();
    +     method public boolean add(E);
    +     method public boolean addAll(java.util.Collection<? extends E>);
    +@@ -57350,10 +57350,10 @@ package java.util {
    +     method public boolean retainAll(java.util.Collection<?>);
    +     method public abstract int size();
    +     method public java.lang.Object[] toArray();
    +-    method public T[] toArray(T[]);
    ++    method public <T> T[] toArray(T[]);
    +   }
    + 
    +-  public abstract class AbstractList extends java.util.AbstractCollection implements java.util.List {
    ++  public abstract class AbstractList<E> extends java.util.AbstractCollection implements java.util.List {
    +     ctor protected AbstractList();
    +     method public void add(int, E);
    +     method public boolean addAll(int, java.util.Collection<? extends E>);
    +@@ -57370,7 +57370,7 @@ package java.util {
    +     field protected transient int modCount;
    +   }
    + 
    +-  public abstract class AbstractMap implements java.util.Map {
    ++  public abstract class AbstractMap<K, V> implements java.util.Map {
    +     ctor protected AbstractMap();
    +     method public void clear();
    +     method public boolean containsKey(java.lang.Object);
    +@@ -57386,7 +57386,7 @@ package java.util {
    +     method public java.util.Collection<V> values();
    +   }
    + 
    +-  public static class AbstractMap.SimpleEntry implements java.util.Map.Entry java.io.Serializable {
    ++  public static class AbstractMap.SimpleEntry<K, V> implements java.util.Map.Entry java.io.Serializable {
    +     ctor public AbstractMap.SimpleEntry(K, V);
    +     ctor public AbstractMap.SimpleEntry(java.util.Map.Entry<? extends K, ? extends V>);
    +     method public K getKey();
    +@@ -57394,7 +57394,7 @@ package java.util {
    +     method public V setValue(V);
    +   }
    + 
    +-  public static class AbstractMap.SimpleImmutableEntry implements java.util.Map.Entry java.io.Serializable {
    ++  public static class AbstractMap.SimpleImmutableEntry<K, V> implements java.util.Map.Entry java.io.Serializable {
    +     ctor public AbstractMap.SimpleImmutableEntry(K, V);
    +     ctor public AbstractMap.SimpleImmutableEntry(java.util.Map.Entry<? extends K, ? extends V>);
    +     method public K getKey();
    +@@ -57402,23 +57402,23 @@ package java.util {
    +     method public V setValue(V);
    +   }
    + 
    +-  public abstract class AbstractQueue extends java.util.AbstractCollection implements java.util.Queue {
    ++  public abstract class AbstractQueue<E> extends java.util.AbstractCollection implements java.util.Queue {
    +     ctor protected AbstractQueue();
    +     method public E element();
    +     method public E remove();
    +   }
    + 
    +-  public abstract class AbstractSequentialList extends java.util.AbstractList {
    ++  public abstract class AbstractSequentialList<E> extends java.util.AbstractList {
    +     ctor protected AbstractSequentialList();
    +     method public E get(int);
    +     method public abstract java.util.ListIterator<E> listIterator(int);
    +   }
    + 
    +-  public abstract class AbstractSet extends java.util.AbstractCollection implements java.util.Set {
    ++  public abstract class AbstractSet<E> extends java.util.AbstractCollection implements java.util.Set {
    +     ctor protected AbstractSet();
    +   }
    + 
    +-  public class ArrayDeque extends java.util.AbstractCollection implements java.lang.Cloneable java.util.Deque java.io.Serializable {
    ++  public class ArrayDeque<E> extends java.util.AbstractCollection implements java.lang.Cloneable java.util.Deque java.io.Serializable {
    +     ctor public ArrayDeque();
    +     ctor public ArrayDeque(int);
    +     ctor public ArrayDeque(java.util.Collection<? extends E>);
    +@@ -57450,7 +57450,7 @@ package java.util {
    +     method public java.util.Spliterator<E> spliterator();
    +   }
    + 
    +-  public class ArrayList extends java.util.AbstractList implements java.lang.Cloneable java.util.List java.util.RandomAccess java.io.Serializable {
    ++  public class ArrayList<E> extends java.util.AbstractList implements java.lang.Cloneable java.util.List java.util.RandomAccess java.io.Serializable {
    +     ctor public ArrayList(int);
    +     ctor public ArrayList();
    +     ctor public ArrayList(java.util.Collection<? extends E>);
    +@@ -57467,7 +57467,7 @@ package java.util {
    +   }
    + 
    +   public class Arrays {
    +-    method public static java.util.List<T> asList(T...);
    ++    method public static <T> java.util.List<T> asList(T...);
    +     method public static int binarySearch(long[], long);
    +     method public static int binarySearch(long[], int, int, long);
    +     method public static int binarySearch(int[], int);
    +@@ -57484,10 +57484,10 @@ package java.util {
    +     method public static int binarySearch(float[], int, int, float);
    +     method public static int binarySearch(java.lang.Object[], java.lang.Object);
    +     method public static int binarySearch(java.lang.Object[], int, int, java.lang.Object);
    +-    method public static int binarySearch(T[], T, java.util.Comparator<? super T>);
    +-    method public static int binarySearch(T[], int, int, T, java.util.Comparator<? super T>);
    +-    method public static T[] copyOf(T[], int);
    +-    method public static T[] copyOf(U[], int, java.lang.Class<? extends T[]>);
    ++    method public static <T> int binarySearch(T[], T, java.util.Comparator<? super T>);
    ++    method public static <T> int binarySearch(T[], int, int, T, java.util.Comparator<? super T>);
    ++    method public static <T> T[] copyOf(T[], int);
    ++    method public static <T, U> T[] copyOf(U[], int, java.lang.Class<? extends T[]>);
    +     method public static byte[] copyOf(byte[], int);
    +     method public static short[] copyOf(short[], int);
    +     method public static int[] copyOf(int[], int);
    +@@ -57496,8 +57496,8 @@ package java.util {
    +     method public static float[] copyOf(float[], int);
    +     method public static double[] copyOf(double[], int);
    +     method public static boolean[] copyOf(boolean[], int);
    +-    method public static T[] copyOfRange(T[], int, int);
    +-    method public static T[] copyOfRange(U[], int, int, java.lang.Class<? extends T[]>);
    ++    method public static <T> T[] copyOfRange(T[], int, int);
    ++    method public static <T, U> T[] copyOfRange(U[], int, int, java.lang.Class<? extends T[]>);
    +     method public static byte[] copyOfRange(byte[], int, int);
    +     method public static short[] copyOfRange(short[], int, int);
    +     method public static int[] copyOfRange(int[], int, int);
    +@@ -57545,15 +57545,15 @@ package java.util {
    +     method public static int hashCode(float[]);
    +     method public static int hashCode(double[]);
    +     method public static int hashCode(java.lang.Object[]);
    +-    method public static void parallelPrefix(T[], java.util.function.BinaryOperator<T>);
    +-    method public static void parallelPrefix(T[], int, int, java.util.function.BinaryOperator<T>);
    ++    method public static <T> void parallelPrefix(T[], java.util.function.BinaryOperator<T>);
    ++    method public static <T> void parallelPrefix(T[], int, int, java.util.function.BinaryOperator<T>);
    +     method public static void parallelPrefix(long[], java.util.function.LongBinaryOperator);
    +     method public static void parallelPrefix(long[], int, int, java.util.function.LongBinaryOperator);
    +     method public static void parallelPrefix(double[], java.util.function.DoubleBinaryOperator);
    +     method public static void parallelPrefix(double[], int, int, java.util.function.DoubleBinaryOperator);
    +     method public static void parallelPrefix(int[], java.util.function.IntBinaryOperator);
    +     method public static void parallelPrefix(int[], int, int, java.util.function.IntBinaryOperator);
    +-    method public static void parallelSetAll(T[], java.util.function.IntFunction<? extends T>);
    ++    method public static <T> void parallelSetAll(T[], java.util.function.IntFunction<? extends T>);
    +     method public static void parallelSetAll(int[], java.util.function.IntUnaryOperator);
    +     method public static void parallelSetAll(long[], java.util.function.IntToLongFunction);
    +     method public static void parallelSetAll(double[], java.util.function.IntToDoubleFunction);
    +@@ -57571,11 +57571,11 @@ package java.util {
    +     method public static void parallelSort(float[], int, int);
    +     method public static void parallelSort(double[]);
    +     method public static void parallelSort(double[], int, int);
    +-    method public static void parallelSort(T[]);
    +-    method public static void parallelSort(T[], int, int);
    +-    method public static void parallelSort(T[], java.util.Comparator<? super T>);
    +-    method public static void parallelSort(T[], int, int, java.util.Comparator<? super T>);
    +-    method public static void setAll(T[], java.util.function.IntFunction<? extends T>);
    ++    method public static <T extends java.lang.Comparable<? super T>> void parallelSort(T[]);
    ++    method public static <T extends java.lang.Comparable<? super T>> void parallelSort(T[], int, int);
    ++    method public static <T> void parallelSort(T[], java.util.Comparator<? super T>);
    ++    method public static <T> void parallelSort(T[], int, int, java.util.Comparator<? super T>);
    ++    method public static <T> void setAll(T[], java.util.function.IntFunction<? extends T>);
    +     method public static void setAll(int[], java.util.function.IntUnaryOperator);
    +     method public static void setAll(long[], java.util.function.IntToLongFunction);
    +     method public static void setAll(double[], java.util.function.IntToDoubleFunction);
    +@@ -57595,18 +57595,18 @@ package java.util {
    +     method public static void sort(double[], int, int);
    +     method public static void sort(java.lang.Object[]);
    +     method public static void sort(java.lang.Object[], int, int);
    +-    method public static void sort(T[], java.util.Comparator<? super T>);
    +-    method public static void sort(T[], int, int, java.util.Comparator<? super T>);
    +-    method public static java.util.Spliterator<T> spliterator(T[]);
    +-    method public static java.util.Spliterator<T> spliterator(T[], int, int);
    ++    method public static <T> void sort(T[], java.util.Comparator<? super T>);
    ++    method public static <T> void sort(T[], int, int, java.util.Comparator<? super T>);
    ++    method public static <T> java.util.Spliterator<T> spliterator(T[]);
    ++    method public static <T> java.util.Spliterator<T> spliterator(T[], int, int);
    +     method public static java.util.Spliterator.OfInt spliterator(int[]);
    +     method public static java.util.Spliterator.OfInt spliterator(int[], int, int);
    +     method public static java.util.Spliterator.OfLong spliterator(long[]);
    +     method public static java.util.Spliterator.OfLong spliterator(long[], int, int);
    +     method public static java.util.Spliterator.OfDouble spliterator(double[]);
    +     method public static java.util.Spliterator.OfDouble spliterator(double[], int, int);
    +-    method public static java.util.stream.Stream<T> stream(T[]);
    +-    method public static java.util.stream.Stream<T> stream(T[], int, int);
    ++    method public static <T> java.util.stream.Stream<T> stream(T[]);
    ++    method public static <T> java.util.stream.Stream<T> stream(T[], int, int);
    +     method public static java.util.stream.IntStream stream(int[]);
    +     method public static java.util.stream.IntStream stream(int[], int, int);
    +     method public static java.util.stream.LongStream stream(long[]);
    +@@ -57763,7 +57763,7 @@ package java.util {
    +     field protected long time;
    +   }
    + 
    +-  public abstract interface Collection implements java.lang.Iterable {
    ++  public abstract interface Collection<E> implements java.lang.Iterable {
    +     method public abstract boolean add(E);
    +     method public abstract boolean addAll(java.util.Collection<? extends E>);
    +     method public abstract void clear();
    +@@ -57781,86 +57781,86 @@ package java.util {
    +     method public abstract int size();
    +     method public default java.util.stream.Stream<E> stream();
    +     method public abstract java.lang.Object[] toArray();
    +-    method public abstract T[] toArray(T[]);
    ++    method public abstract <T> T[] toArray(T[]);
    +   }
    + 
    +   public class Collections {
    +-    method public static boolean addAll(java.util.Collection<? super T>, T...);
    +-    method public static java.util.Queue<T> asLifoQueue(java.util.Deque<T>);
    +-    method public static int binarySearch(java.util.List<? extends java.lang.Comparable<? super T>>, T);
    +-    method public static int binarySearch(java.util.List<? extends T>, T, java.util.Comparator<? super T>);
    +-    method public static java.util.Collection<E> checkedCollection(java.util.Collection<E>, java.lang.Class<E>);
    +-    method public static java.util.List<E> checkedList(java.util.List<E>, java.lang.Class<E>);
    +-    method public static java.util.Map<K, V> checkedMap(java.util.Map<K, V>, java.lang.Class<K>, java.lang.Class<V>);
    +-    method public static java.util.Set<E> checkedSet(java.util.Set<E>, java.lang.Class<E>);
    +-    method public static java.util.SortedMap<K, V> checkedSortedMap(java.util.SortedMap<K, V>, java.lang.Class<K>, java.lang.Class<V>);
    +-    method public static java.util.SortedSet<E> checkedSortedSet(java.util.SortedSet<E>, java.lang.Class<E>);
    +-    method public static void copy(java.util.List<? super T>, java.util.List<? extends T>);
    ++    method public static <T> boolean addAll(java.util.Collection<? super T>, T...);
    ++    method public static <T> java.util.Queue<T> asLifoQueue(java.util.Deque<T>);
    ++    method public static <T> int binarySearch(java.util.List<? extends java.lang.Comparable<? super T>>, T);
    ++    method public static <T> int binarySearch(java.util.List<? extends T>, T, java.util.Comparator<? super T>);
    ++    method public static <E> java.util.Collection<E> checkedCollection(java.util.Collection<E>, java.lang.Class<E>);
    ++    method public static <E> java.util.List<E> checkedList(java.util.List<E>, java.lang.Class<E>);
    ++    method public static <K, V> java.util.Map<K, V> checkedMap(java.util.Map<K, V>, java.lang.Class<K>, java.lang.Class<V>);
    ++    method public static <E> java.util.Set<E> checkedSet(java.util.Set<E>, java.lang.Class<E>);
    ++    method public static <K, V> java.util.SortedMap<K, V> checkedSortedMap(java.util.SortedMap<K, V>, java.lang.Class<K>, java.lang.Class<V>);
    ++    method public static <E> java.util.SortedSet<E> checkedSortedSet(java.util.SortedSet<E>, java.lang.Class<E>);
    ++    method public static <T> void copy(java.util.List<? super T>, java.util.List<? extends T>);
    +     method public static boolean disjoint(java.util.Collection<?>, java.util.Collection<?>);
    +-    method public static java.util.Enumeration<T> emptyEnumeration();
    +-    method public static java.util.Iterator<T> emptyIterator();
    +-    method public static final java.util.List<T> emptyList();
    +-    method public static java.util.ListIterator<T> emptyListIterator();
    +-    method public static final java.util.Map<K, V> emptyMap();
    +-    method public static final java.util.Set<T> emptySet();
    +-    method public static java.util.Enumeration<T> enumeration(java.util.Collection<T>);
    +-    method public static void fill(java.util.List<? super T>, T);
    ++    method public static <T> java.util.Enumeration<T> emptyEnumeration();
    ++    method public static <T> java.util.Iterator<T> emptyIterator();
    ++    method public static final <T> java.util.List<T> emptyList();
    ++    method public static <T> java.util.ListIterator<T> emptyListIterator();
    ++    method public static final <K, V> java.util.Map<K, V> emptyMap();
    ++    method public static final <T> java.util.Set<T> emptySet();
    ++    method public static <T> java.util.Enumeration<T> enumeration(java.util.Collection<T>);
    ++    method public static <T> void fill(java.util.List<? super T>, T);
    +     method public static int frequency(java.util.Collection<?>, java.lang.Object);
    +     method public static int indexOfSubList(java.util.List<?>, java.util.List<?>);
    +     method public static int lastIndexOfSubList(java.util.List<?>, java.util.List<?>);
    +-    method public static java.util.ArrayList<T> list(java.util.Enumeration<T>);
    +-    method public static T max(java.util.Collection<? extends T>);
    +-    method public static T max(java.util.Collection<? extends T>, java.util.Comparator<? super T>);
    +-    method public static T min(java.util.Collection<? extends T>);
    +-    method public static T min(java.util.Collection<? extends T>, java.util.Comparator<? super T>);
    +-    method public static java.util.List<T> nCopies(int, T);
    +-    method public static java.util.Set<E> newSetFromMap(java.util.Map<E, java.lang.Boolean>);
    +-    method public static boolean replaceAll(java.util.List<T>, T, T);
    ++    method public static <T> java.util.ArrayList<T> list(java.util.Enumeration<T>);
    ++    method public static <T extends java.lang.Object & java.lang.Comparable<? super T>> T max(java.util.Collection<? extends T>);
    ++    method public static <T> T max(java.util.Collection<? extends T>, java.util.Comparator<? super T>);
    ++    method public static <T extends java.lang.Object & java.lang.Comparable<? super T>> T min(java.util.Collection<? extends T>);
    ++    method public static <T> T min(java.util.Collection<? extends T>, java.util.Comparator<? super T>);
    ++    method public static <T> java.util.List<T> nCopies(int, T);
    ++    method public static <E> java.util.Set<E> newSetFromMap(java.util.Map<E, java.lang.Boolean>);
    ++    method public static <T> boolean replaceAll(java.util.List<T>, T, T);
    +     method public static void reverse(java.util.List<?>);
    +-    method public static java.util.Comparator<T> reverseOrder();
    +-    method public static java.util.Comparator<T> reverseOrder(java.util.Comparator<T>);
    ++    method public static <T> java.util.Comparator<T> reverseOrder();
    ++    method public static <T> java.util.Comparator<T> reverseOrder(java.util.Comparator<T>);
    +     method public static void rotate(java.util.List<?>, int);
    +     method public static void shuffle(java.util.List<?>);
    +     method public static void shuffle(java.util.List<?>, java.util.Random);
    +-    method public static java.util.Set<E> singleton(E);
    +-    method public static java.util.List<E> singletonList(E);
    +-    method public static java.util.Map<K, V> singletonMap(K, V);
    +-    method public static void sort(java.util.List<T>);
    +-    method public static void sort(java.util.List<T>, java.util.Comparator<? super T>);
    ++    method public static <E> java.util.Set<E> singleton(E);
    ++    method public static <E> java.util.List<E> singletonList(E);
    ++    method public static <K, V> java.util.Map<K, V> singletonMap(K, V);
    ++    method public static <T extends java.lang.Comparable<? super T>> void sort(java.util.List<T>);
    ++    method public static <T> void sort(java.util.List<T>, java.util.Comparator<? super T>);
    +     method public static void swap(java.util.List<?>, int, int);
    +-    method public static java.util.Collection<T> synchronizedCollection(java.util.Collection<T>);
    +-    method public static java.util.List<T> synchronizedList(java.util.List<T>);
    +-    method public static java.util.Map<K, V> synchronizedMap(java.util.Map<K, V>);
    +-    method public static java.util.Set<T> synchronizedSet(java.util.Set<T>);
    +-    method public static java.util.SortedMap<K, V> synchronizedSortedMap(java.util.SortedMap<K, V>);
    +-    method public static java.util.SortedSet<T> synchronizedSortedSet(java.util.SortedSet<T>);
    +-    method public static java.util.Collection<T> unmodifiableCollection(java.util.Collection<? extends T>);
    +-    method public static java.util.List<T> unmodifiableList(java.util.List<? extends T>);
    +-    method public static java.util.Map<K, V> unmodifiableMap(java.util.Map<? extends K, ? extends V>);
    +-    method public static java.util.Set<T> unmodifiableSet(java.util.Set<? extends T>);
    +-    method public static java.util.SortedMap<K, V> unmodifiableSortedMap(java.util.SortedMap<K, ? extends V>);
    +-    method public static java.util.SortedSet<T> unmodifiableSortedSet(java.util.SortedSet<T>);
    ++    method public static <T> java.util.Collection<T> synchronizedCollection(java.util.Collection<T>);
    ++    method public static <T> java.util.List<T> synchronizedList(java.util.List<T>);
    ++    method public static <K, V> java.util.Map<K, V> synchronizedMap(java.util.Map<K, V>);
    ++    method public static <T> java.util.Set<T> synchronizedSet(java.util.Set<T>);
    ++    method public static <K, V> java.util.SortedMap<K, V> synchronizedSortedMap(java.util.SortedMap<K, V>);
    ++    method public static <T> java.util.SortedSet<T> synchronizedSortedSet(java.util.SortedSet<T>);
    ++    method public static <T> java.util.Collection<T> unmodifiableCollection(java.util.Collection<? extends T>);
    ++    method public static <T> java.util.List<T> unmodifiableList(java.util.List<? extends T>);
    ++    method public static <K, V> java.util.Map<K, V> unmodifiableMap(java.util.Map<? extends K, ? extends V>);
    ++    method public static <T> java.util.Set<T> unmodifiableSet(java.util.Set<? extends T>);
    ++    method public static <K, V> java.util.SortedMap<K, V> unmodifiableSortedMap(java.util.SortedMap<K, ? extends V>);
    ++    method public static <T> java.util.SortedSet<T> unmodifiableSortedSet(java.util.SortedSet<T>);
    +     field public static final java.util.List EMPTY_LIST;
    +     field public static final java.util.Map EMPTY_MAP;
    +     field public static final java.util.Set EMPTY_SET;
    +   }
    + 
    +-  public abstract interface Comparator {
    ++  public abstract interface Comparator<T> {
    +     method public abstract int compare(T, T);
    +-    method public static java.util.Comparator<T> comparing(java.util.function.Function<? super T, ? extends U>, java.util.Comparator<? super U>);
    +-    method public static java.util.Comparator<T> comparing(java.util.function.Function<? super T, ? extends U>);
    +-    method public static java.util.Comparator<T> comparingDouble(java.util.function.ToDoubleFunction<? super T>);
    +-    method public static java.util.Comparator<T> comparingInt(java.util.function.ToIntFunction<? super T>);
    +-    method public static java.util.Comparator<T> comparingLong(java.util.function.ToLongFunction<? super T>);
    ++    method public static <T, U> java.util.Comparator<T> comparing(java.util.function.Function<? super T, ? extends U>, java.util.Comparator<? super U>);
    ++    method public static <T, U extends java.lang.Comparable<? super U>> java.util.Comparator<T> comparing(java.util.function.Function<? super T, ? extends U>);
    ++    method public static <T> java.util.Comparator<T> comparingDouble(java.util.function.ToDoubleFunction<? super T>);
    ++    method public static <T> java.util.Comparator<T> comparingInt(java.util.function.ToIntFunction<? super T>);
    ++    method public static <T> java.util.Comparator<T> comparingLong(java.util.function.ToLongFunction<? super T>);
    +     method public abstract boolean equals(java.lang.Object);
    +-    method public static java.util.Comparator<T> naturalOrder();
    +-    method public static java.util.Comparator<T> nullsFirst(java.util.Comparator<? super T>);
    +-    method public static java.util.Comparator<T> nullsLast(java.util.Comparator<? super T>);
    +-    method public static java.util.Comparator<T> reverseOrder();
    ++    method public static <T extends java.lang.Comparable<? super T>> java.util.Comparator<T> naturalOrder();
    ++    method public static <T> java.util.Comparator<T> nullsFirst(java.util.Comparator<? super T>);
    ++    method public static <T> java.util.Comparator<T> nullsLast(java.util.Comparator<? super T>);
    ++    method public static <T extends java.lang.Comparable<? super T>> java.util.Comparator<T> reverseOrder();
    +     method public default java.util.Comparator<T> reversed();
    +     method public default java.util.Comparator<T> thenComparing(java.util.Comparator<? super T>);
    +-    method public default java.util.Comparator<T> thenComparing(java.util.function.Function<? super T, ? extends U>, java.util.Comparator<? super U>);
    +-    method public default java.util.Comparator<T> thenComparing(java.util.function.Function<? super T, ? extends U>);
    ++    method public default <U> java.util.Comparator<T> thenComparing(java.util.function.Function<? super T, ? extends U>, java.util.Comparator<? super U>);
    ++    method public default <U extends java.lang.Comparable<? super U>> java.util.Comparator<T> thenComparing(java.util.function.Function<? super T, ? extends U>);
    +     method public default java.util.Comparator<T> thenComparingDouble(java.util.function.ToDoubleFunction<? super T>);
    +     method public default java.util.Comparator<T> thenComparingInt(java.util.function.ToIntFunction<? super T>);
    +     method public default java.util.Comparator<T> thenComparingLong(java.util.function.ToLongFunction<? super T>);
    +@@ -57919,7 +57919,7 @@ package java.util {
    +     method public deprecated java.lang.String toLocaleString();
    +   }
    + 
    +-  public abstract interface Deque implements java.util.Queue {
    ++  public abstract interface Deque<E> implements java.util.Queue {
    +     method public abstract boolean add(E);
    +     method public abstract void addFirst(E);
    +     method public abstract void addLast(E);
    +@@ -57949,7 +57949,7 @@ package java.util {
    +     method public abstract int size();
    +   }
    + 
    +-  public abstract class Dictionary {
    ++  public abstract class Dictionary<K, V> {
    +     ctor public Dictionary();
    +     method public abstract java.util.Enumeration<V> elements();
    +     method public abstract V get(java.lang.Object);
    +@@ -57980,7 +57980,7 @@ package java.util {
    +     ctor public EmptyStackException();
    +   }
    + 
    +-  public class EnumMap extends java.util.AbstractMap implements java.lang.Cloneable java.io.Serializable {
    ++  public class EnumMap<K extends java.lang.Enum<K>, V> extends java.util.AbstractMap implements java.lang.Cloneable java.io.Serializable {
    +     ctor public EnumMap(java.lang.Class<K>);
    +     ctor public EnumMap(java.util.EnumMap<K, ? extends V>);
    +     ctor public EnumMap(java.util.Map<K, ? extends V>);
    +@@ -57988,23 +57988,23 @@ package java.util {
    +     method public java.util.Set<java.util.Map.Entry<K, V>> entrySet();
    +   }
    + 
    +-  public abstract class EnumSet extends java.util.AbstractSet implements java.lang.Cloneable java.io.Serializable {
    +-    method public static java.util.EnumSet<E> allOf(java.lang.Class<E>);
    ++  public abstract class EnumSet<E extends java.lang.Enum<E>> extends java.util.AbstractSet implements java.lang.Cloneable java.io.Serializable {
    ++    method public static <E extends java.lang.Enum<E>> java.util.EnumSet<E> allOf(java.lang.Class<E>);
    +     method public java.util.EnumSet<E> clone();
    +-    method public static java.util.EnumSet<E> complementOf(java.util.EnumSet<E>);
    +-    method public static java.util.EnumSet<E> copyOf(java.util.EnumSet<E>);
    +-    method public static java.util.EnumSet<E> copyOf(java.util.Collection<E>);
    +-    method public static java.util.EnumSet<E> noneOf(java.lang.Class<E>);
    +-    method public static java.util.EnumSet<E> of(E);
    +-    method public static java.util.EnumSet<E> of(E, E);
    +-    method public static java.util.EnumSet<E> of(E, E, E);
    +-    method public static java.util.EnumSet<E> of(E, E, E, E);
    +-    method public static java.util.EnumSet<E> of(E, E, E, E, E);
    +-    method public static java.util.EnumSet<E> of(E, E...);
    +-    method public static java.util.EnumSet<E> range(E, E);
    +-  }
    +-
    +-  public abstract interface Enumeration {
    ++    method public static <E extends java.lang.Enum<E>> java.util.EnumSet<E> complementOf(java.util.EnumSet<E>);
    ++    method public static <E extends java.lang.Enum<E>> java.util.EnumSet<E> copyOf(java.util.EnumSet<E>);
    ++    method public static <E extends java.lang.Enum<E>> java.util.EnumSet<E> copyOf(java.util.Collection<E>);
    ++    method public static <E extends java.lang.Enum<E>> java.util.EnumSet<E> noneOf(java.lang.Class<E>);
    ++    method public static <E extends java.lang.Enum<E>> java.util.EnumSet<E> of(E);
    ++    method public static <E extends java.lang.Enum<E>> java.util.EnumSet<E> of(E, E);
    ++    method public static <E extends java.lang.Enum<E>> java.util.EnumSet<E> of(E, E, E);
    ++    method public static <E extends java.lang.Enum<E>> java.util.EnumSet<E> of(E, E, E, E);
    ++    method public static <E extends java.lang.Enum<E>> java.util.EnumSet<E> of(E, E, E, E, E);
    ++    method public static <E extends java.lang.Enum<E>> java.util.EnumSet<E> of(E, E...);
    ++    method public static <E extends java.lang.Enum<E>> java.util.EnumSet<E> range(E, E);
    ++  }
    ++
    ++  public abstract interface Enumeration<E> {
    +     method public abstract boolean hasMoreElements();
    +     method public abstract E nextElement();
    +   }
    +@@ -58012,7 +58012,7 @@ package java.util {
    +   public abstract interface EventListener {
    +   }
    + 
    +-  public abstract class EventListenerProxy implements java.util.EventListener {
    ++  public abstract class EventListenerProxy<T extends java.util.EventListener> implements java.util.EventListener {
    +     ctor public EventListenerProxy(T);
    +     method public T getListener();
    +   }
    +@@ -58098,7 +58098,7 @@ package java.util {
    +     field public static final int BC = 0; // 0x0
    +   }
    + 
    +-  public class HashMap extends java.util.AbstractMap implements java.lang.Cloneable java.util.Map java.io.Serializable {
    ++  public class HashMap<K, V> extends java.util.AbstractMap implements java.lang.Cloneable java.util.Map java.io.Serializable {
    +     ctor public HashMap(int, float);
    +     ctor public HashMap(int);
    +     ctor public HashMap();
    +@@ -58110,7 +58110,7 @@ package java.util {
    +     method public void replaceAll(java.util.function.BiFunction<? super K, ? super V, ? extends V>);
    +   }
    + 
    +-  public class HashSet extends java.util.AbstractSet implements java.lang.Cloneable java.io.Serializable java.util.Set {
    ++  public class HashSet<E> extends java.util.AbstractSet implements java.lang.Cloneable java.io.Serializable java.util.Set {
    +     ctor public HashSet();
    +     ctor public HashSet(java.util.Collection<? extends E>);
    +     ctor public HashSet(int, float);
    +@@ -58121,7 +58121,7 @@ package java.util {
    +     method public java.util.Spliterator<E> spliterator();
    +   }
    + 
    +-  public class Hashtable extends java.util.Dictionary implements java.lang.Cloneable java.util.Map java.io.Serializable {
    ++  public class Hashtable<K, V> extends java.util.Dictionary implements java.lang.Cloneable java.util.Map java.io.Serializable {
    +     ctor public Hashtable(int, float);
    +     ctor public Hashtable(int);
    +     ctor public Hashtable();
    +@@ -58156,7 +58156,7 @@ package java.util {
    +     method public java.util.Collection<V> values();
    +   }
    + 
    +-  public class IdentityHashMap extends java.util.AbstractMap implements java.lang.Cloneable java.util.Map java.io.Serializable {
    ++  public class IdentityHashMap<K, V> extends java.util.AbstractMap implements java.lang.Cloneable java.util.Map java.io.Serializable {
    +     ctor public IdentityHashMap();
    +     ctor public IdentityHashMap(int);
    +     ctor public IdentityHashMap(java.util.Map<? extends K, ? extends V>);
    +@@ -58223,14 +58223,14 @@ package java.util {
    +     ctor public InvalidPropertiesFormatException(java.lang.String);
    +   }
    + 
    +-  public abstract interface Iterator {
    ++  public abstract interface Iterator<E> {
    +     method public default void forEachRemaining(java.util.function.Consumer<? super E>);
    +     method public abstract boolean hasNext();
    +     method public abstract E next();
    +     method public default void remove();
    +   }
    + 
    +-  public class LinkedHashMap extends java.util.HashMap implements java.util.Map {
    ++  public class LinkedHashMap<K, V> extends java.util.HashMap implements java.util.Map {
    +     ctor public LinkedHashMap(int, float);
    +     ctor public LinkedHashMap(int);
    +     ctor public LinkedHashMap();
    +@@ -58239,14 +58239,14 @@ package java.util {
    +     method protected boolean removeEldestEntry(java.util.Map.Entry<K, V>);
    +   }
    + 
    +-  public class LinkedHashSet extends java.util.HashSet implements java.lang.Cloneable java.io.Serializable java.util.Set {
    ++  public class LinkedHashSet<E> extends java.util.HashSet implements java.lang.Cloneable java.io.Serializable java.util.Set {
    +     ctor public LinkedHashSet(int, float);
    +     ctor public LinkedHashSet(int);
    +     ctor public LinkedHashSet();
    +     ctor public LinkedHashSet(java.util.Collection<? extends E>);
    +   }
    + 
    +-  public class LinkedList extends java.util.AbstractSequentialList implements java.lang.Cloneable java.util.Deque java.util.List java.io.Serializable {
    ++  public class LinkedList<E> extends java.util.AbstractSequentialList implements java.lang.Cloneable java.util.Deque java.util.List java.io.Serializable {
    +     ctor public LinkedList();
    +     ctor public LinkedList(java.util.Collection<? extends E>);
    +     method public void addFirst(E);
    +@@ -58277,7 +58277,7 @@ package java.util {
    +     method public java.util.Spliterator<E> spliterator();
    +   }
    + 
    +-  public abstract interface List implements java.util.Collection {
    ++  public abstract interface List<E> implements java.util.Collection {
    +     method public abstract boolean add(E);
    +     method public abstract void add(int, E);
    +     method public abstract boolean addAll(java.util.Collection<? extends E>);
    +@@ -58304,10 +58304,10 @@ package java.util {
    +     method public default void sort(java.util.Comparator<? super E>);
    +     method public abstract java.util.List<E> subList(int, int);
    +     method public abstract java.lang.Object[] toArray();
    +-    method public abstract T[] toArray(T[]);
    ++    method public abstract <T> T[] toArray(T[]);
    +   }
    + 
    +-  public abstract interface ListIterator implements java.util.Iterator {
    ++  public abstract interface ListIterator<E> implements java.util.Iterator {
    +     method public abstract void add(E);
    +     method public abstract boolean hasNext();
    +     method public abstract boolean hasPrevious();
    +@@ -58424,7 +58424,7 @@ package java.util {
    +     method public final long getSum();
    +   }
    + 
    +-  public abstract interface Map {
    ++  public abstract interface Map<K, V> {
    +     method public abstract void clear();
    +     method public default V compute(K, java.util.function.BiFunction<? super K, ? super V, ? extends V>);
    +     method public default V computeIfAbsent(K, java.util.function.Function<? super K, ? extends V>);
    +@@ -58452,11 +58452,11 @@ package java.util {
    +     method public abstract java.util.Collection<V> values();
    +   }
    + 
    +-  public static abstract interface Map.Entry {
    +-    method public static java.util.Comparator<java.util.Map.Entry<K, V>> comparingByKey();
    +-    method public static java.util.Comparator<java.util.Map.Entry<K, V>> comparingByKey(java.util.Comparator<? super K>);
    +-    method public static java.util.Comparator<java.util.Map.Entry<K, V>> comparingByValue();
    +-    method public static java.util.Comparator<java.util.Map.Entry<K, V>> comparingByValue(java.util.Comparator<? super V>);
    ++  public static abstract interface Map.Entry<K, V> {
    ++    method public static <K extends java.lang.Comparable<? super K>, V> java.util.Comparator<java.util.Map.Entry<K, V>> comparingByKey();
    ++    method public static <K, V> java.util.Comparator<java.util.Map.Entry<K, V>> comparingByKey(java.util.Comparator<? super K>);
    ++    method public static <K, V extends java.lang.Comparable<? super V>> java.util.Comparator<java.util.Map.Entry<K, V>> comparingByValue();
    ++    method public static <K, V> java.util.Comparator<java.util.Map.Entry<K, V>> comparingByValue(java.util.Comparator<? super V>);
    +     method public abstract boolean equals(java.lang.Object);
    +     method public abstract K getKey();
    +     method public abstract V getValue();
    +@@ -58480,7 +58480,7 @@ package java.util {
    +     method public java.lang.String getKey();
    +   }
    + 
    +-  public abstract interface NavigableMap implements java.util.SortedMap {
    ++  public abstract interface NavigableMap<K, V> implements java.util.SortedMap {
    +     method public abstract java.util.Map.Entry<K, V> ceilingEntry(K);
    +     method public abstract K ceilingKey(K);
    +     method public abstract java.util.NavigableSet<K> descendingKeySet();
    +@@ -58504,7 +58504,7 @@ package java.util {
    +     method public abstract java.util.SortedMap<K, V> tailMap(K);
    +   }
    + 
    +-  public abstract interface NavigableSet implements java.util.SortedSet {
    ++  public abstract interface NavigableSet<E> implements java.util.SortedSet {
    +     method public abstract E ceiling(E);
    +     method public abstract java.util.Iterator<E> descendingIterator();
    +     method public abstract java.util.NavigableSet<E> descendingSet();
    +@@ -58528,16 +58528,16 @@ package java.util {
    +   }
    + 
    +   public final class Objects {
    +-    method public static int compare(T, T, java.util.Comparator<? super T>);
    ++    method public static <T> int compare(T, T, java.util.Comparator<? super T>);
    +     method public static boolean deepEquals(java.lang.Object, java.lang.Object);
    +     method public static boolean equals(java.lang.Object, java.lang.Object);
    +     method public static int hash(java.lang.Object...);
    +     method public static int hashCode(java.lang.Object);
    +     method public static boolean isNull(java.lang.Object);
    +     method public static boolean nonNull(java.lang.Object);
    +-    method public static T requireNonNull(T);
    +-    method public static T requireNonNull(T, java.lang.String);
    +-    method public static T requireNonNull(T, java.util.function.Supplier<java.lang.String>);
    ++    method public static <T> T requireNonNull(T);
    ++    method public static <T> T requireNonNull(T, java.lang.String);
    ++    method public static <T> T requireNonNull(T, java.util.function.Supplier<java.lang.String>);
    +     method public static java.lang.String toString(java.lang.Object);
    +     method public static java.lang.String toString(java.lang.Object, java.lang.String);
    +   }
    +@@ -58559,19 +58559,19 @@ package java.util {
    +     method public abstract void update(java.util.Observable, java.lang.Object);
    +   }
    + 
    +-  public final class Optional {
    +-    method public static java.util.Optional<T> empty();
    ++  public final class Optional<T> {
    ++    method public static <T> java.util.Optional<T> empty();
    +     method public java.util.Optional<T> filter(java.util.function.Predicate<? super T>);
    +-    method public java.util.Optional<U> flatMap(java.util.function.Function<? super T, java.util.Optional<U>>);
    ++    method public <U> java.util.Optional<U> flatMap(java.util.function.Function<? super T, java.util.Optional<U>>);
    +     method public T get();
    +     method public void ifPresent(java.util.function.Consumer<? super T>);
    +     method public boolean isPresent();
    +-    method public java.util.Optional<U> map(java.util.function.Function<? super T, ? extends U>);
    +-    method public static java.util.Optional<T> of(T);
    +-    method public static java.util.Optional<T> ofNullable(T);
    ++    method public <U> java.util.Optional<U> map(java.util.function.Function<? super T, ? extends U>);
    ++    method public static <T> java.util.Optional<T> of(T);
    ++    method public static <T> java.util.Optional<T> ofNullable(T);
    +     method public T orElse(T);
    +     method public T orElseGet(java.util.function.Supplier<? extends T>);
    +-    method public T orElseThrow(java.util.function.Supplier<? extends X>) throws java.lang.Throwable;
    ++    method public <X extends java.lang.Throwable> T orElseThrow(java.util.function.Supplier<? extends X>) throws java.lang.Throwable;
    +   }
    + 
    +   public final class OptionalDouble {
    +@@ -58582,7 +58582,7 @@ package java.util {
    +     method public static java.util.OptionalDouble of(double);
    +     method public double orElse(double);
    +     method public double orElseGet(java.util.function.DoubleSupplier);
    +-    method public double orElseThrow(java.util.function.Supplier<X>) throws java.lang.Throwable;
    ++    method public <X extends java.lang.Throwable> double orElseThrow(java.util.function.Supplier<X>) throws java.lang.Throwable;
    +   }
    + 
    +   public final class OptionalInt {
    +@@ -58593,7 +58593,7 @@ package java.util {
    +     method public static java.util.OptionalInt of(int);
    +     method public int orElse(int);
    +     method public int orElseGet(java.util.function.IntSupplier);
    +-    method public int orElseThrow(java.util.function.Supplier<X>) throws java.lang.Throwable;
    ++    method public <X extends java.lang.Throwable> int orElseThrow(java.util.function.Supplier<X>) throws java.lang.Throwable;
    +   }
    + 
    +   public final class OptionalLong {
    +@@ -58604,10 +58604,10 @@ package java.util {
    +     method public static java.util.OptionalLong of(long);
    +     method public long orElse(long);
    +     method public long orElseGet(java.util.function.LongSupplier);
    +-    method public long orElseThrow(java.util.function.Supplier<X>) throws java.lang.Throwable;
    ++    method public <X extends java.lang.Throwable> long orElseThrow(java.util.function.Supplier<X>) throws java.lang.Throwable;
    +   }
    + 
    +-  public abstract interface PrimitiveIterator implements java.util.Iterator {
    ++  public abstract interface PrimitiveIterator<T, T_CONS> implements java.util.Iterator {
    +     method public abstract void forEachRemaining(T_CONS);
    +   }
    + 
    +@@ -58632,7 +58632,7 @@ package java.util {
    +     method public abstract long nextLong();
    +   }
    + 
    +-  public class PriorityQueue extends java.util.AbstractQueue implements java.io.Serializable {
    ++  public class PriorityQueue<E> extends java.util.AbstractQueue implements java.io.Serializable {
    +     ctor public PriorityQueue();
    +     ctor public PriorityQueue(int);
    +     ctor public PriorityQueue(java.util.Comparator<? super E>);
    +@@ -58681,7 +58681,7 @@ package java.util {
    +     method public java.lang.Object handleGetObject(java.lang.String);
    +   }
    + 
    +-  public abstract interface Queue implements java.util.Collection {
    ++  public abstract interface Queue<E> implements java.util.Collection {
    +     method public abstract boolean add(E);
    +     method public abstract E element();
    +     method public abstract boolean offer(E);
    +@@ -58831,15 +58831,15 @@ package java.util {
    +     ctor public ServiceConfigurationError(java.lang.String, java.lang.Throwable);
    +   }
    + 
    +-  public final class ServiceLoader implements java.lang.Iterable {
    ++  public final class ServiceLoader<S> implements java.lang.Iterable {
    +     method public java.util.Iterator<S> iterator();
    +-    method public static java.util.ServiceLoader<S> load(java.lang.Class<S>, java.lang.ClassLoader);
    +-    method public static java.util.ServiceLoader<S> load(java.lang.Class<S>);
    +-    method public static java.util.ServiceLoader<S> loadInstalled(java.lang.Class<S>);
    ++    method public static <S> java.util.ServiceLoader<S> load(java.lang.Class<S>, java.lang.ClassLoader);
    ++    method public static <S> java.util.ServiceLoader<S> load(java.lang.Class<S>);
    ++    method public static <S> java.util.ServiceLoader<S> loadInstalled(java.lang.Class<S>);
    +     method public void reload();
    +   }
    + 
    +-  public abstract interface Set implements java.util.Collection {
    ++  public abstract interface Set<E> implements java.util.Collection {
    +     method public abstract boolean add(E);
    +     method public abstract boolean addAll(java.util.Collection<? extends E>);
    +     method public abstract void clear();
    +@@ -58854,7 +58854,7 @@ package java.util {
    +     method public abstract boolean retainAll(java.util.Collection<?>);
    +     method public abstract int size();
    +     method public abstract java.lang.Object[] toArray();
    +-    method public abstract T[] toArray(T[]);
    ++    method public abstract <T> T[] toArray(T[]);
    +   }
    + 
    +   public class SimpleTimeZone extends java.util.TimeZone {
    +@@ -58880,7 +58880,7 @@ package java.util {
    +     field public static final int WALL_TIME = 0; // 0x0
    +   }
    + 
    +-  public abstract interface SortedMap implements java.util.Map {
    ++  public abstract interface SortedMap<K, V> implements java.util.Map {
    +     method public abstract java.util.Comparator<? super K> comparator();
    +     method public abstract java.util.Set<java.util.Map.Entry<K, V>> entrySet();
    +     method public abstract K firstKey();
    +@@ -58892,7 +58892,7 @@ package java.util {
    +     method public abstract java.util.Collection<V> values();
    +   }
    + 
    +-  public abstract interface SortedSet implements java.util.Set {
    ++  public abstract interface SortedSet<E> implements java.util.Set {
    +     method public abstract java.util.Comparator<? super E> comparator();
    +     method public abstract E first();
    +     method public abstract java.util.SortedSet<E> headSet(E);
    +@@ -58901,7 +58901,7 @@ package java.util {
    +     method public abstract java.util.SortedSet<E> tailSet(E);
    +   }
    + 
    +-  public abstract interface Spliterator {
    ++  public abstract interface Spliterator<T> {
    +     method public abstract int characteristics();
    +     method public abstract long estimateSize();
    +     method public default void forEachRemaining(java.util.function.Consumer<? super T>);
    +@@ -58944,7 +58944,7 @@ package java.util {
    +     method public abstract java.util.Spliterator.OfLong trySplit();
    +   }
    + 
    +-  public static abstract interface Spliterator.OfPrimitive implements java.util.Spliterator {
    ++  public static abstract interface Spliterator.OfPrimitive<T, T_CONS, T_SPLITR extends java.util.Spliterator.OfPrimitive<T, T_CONS, T_SPLITR>> implements java.util.Spliterator {
    +     method public default void forEachRemaining(T_CONS);
    +     method public abstract boolean tryAdvance(T_CONS);
    +     method public abstract T_SPLITR trySplit();
    +@@ -58954,25 +58954,25 @@ package java.util {
    +     method public static java.util.Spliterator.OfDouble emptyDoubleSpliterator();
    +     method public static java.util.Spliterator.OfInt emptyIntSpliterator();
    +     method public static java.util.Spliterator.OfLong emptyLongSpliterator();
    +-    method public static java.util.Spliterator<T> emptySpliterator();
    +-    method public static java.util.Iterator<T> iterator(java.util.Spliterator<? extends T>);
    ++    method public static <T> java.util.Spliterator<T> emptySpliterator();
    ++    method public static <T> java.util.Iterator<T> iterator(java.util.Spliterator<? extends T>);
    +     method public static java.util.PrimitiveIterator.OfInt iterator(java.util.Spliterator.OfInt);
    +     method public static java.util.PrimitiveIterator.OfLong iterator(java.util.Spliterator.OfLong);
    +     method public static java.util.PrimitiveIterator.OfDouble iterator(java.util.Spliterator.OfDouble);
    +-    method public static java.util.Spliterator<T> spliterator(java.lang.Object[], int);
    +-    method public static java.util.Spliterator<T> spliterator(java.lang.Object[], int, int, int);
    ++    method public static <T> java.util.Spliterator<T> spliterator(java.lang.Object[], int);
    ++    method public static <T> java.util.Spliterator<T> spliterator(java.lang.Object[], int, int, int);
    +     method public static java.util.Spliterator.OfInt spliterator(int[], int);
    +     method public static java.util.Spliterator.OfInt spliterator(int[], int, int, int);
    +     method public static java.util.Spliterator.OfLong spliterator(long[], int);
    +     method public static java.util.Spliterator.OfLong spliterator(long[], int, int, int);
    +     method public static java.util.Spliterator.OfDouble spliterator(double[], int);
    +     method public static java.util.Spliterator.OfDouble spliterator(double[], int, int, int);
    +-    method public static java.util.Spliterator<T> spliterator(java.util.Collection<? extends T>, int);
    +-    method public static java.util.Spliterator<T> spliterator(java.util.Iterator<? extends T>, long, int);
    ++    method public static <T> java.util.Spliterator<T> spliterator(java.util.Collection<? extends T>, int);
    ++    method public static <T> java.util.Spliterator<T> spliterator(java.util.Iterator<? extends T>, long, int);
    +     method public static java.util.Spliterator.OfInt spliterator(java.util.PrimitiveIterator.OfInt, long, int);
    +     method public static java.util.Spliterator.OfLong spliterator(java.util.PrimitiveIterator.OfLong, long, int);
    +     method public static java.util.Spliterator.OfDouble spliterator(java.util.PrimitiveIterator.OfDouble, long, int);
    +-    method public static java.util.Spliterator<T> spliteratorUnknownSize(java.util.Iterator<? extends T>, int);
    ++    method public static <T> java.util.Spliterator<T> spliteratorUnknownSize(java.util.Iterator<? extends T>, int);
    +     method public static java.util.Spliterator.OfInt spliteratorUnknownSize(java.util.PrimitiveIterator.OfInt, int);
    +     method public static java.util.Spliterator.OfLong spliteratorUnknownSize(java.util.PrimitiveIterator.OfLong, int);
    +     method public static java.util.Spliterator.OfDouble spliteratorUnknownSize(java.util.PrimitiveIterator.OfDouble, int);
    +@@ -58999,7 +58999,7 @@ package java.util {
    +     method public java.util.Spliterator.OfLong trySplit();
    +   }
    + 
    +-  public static abstract class Spliterators.AbstractSpliterator implements java.util.Spliterator {
    ++  public static abstract class Spliterators.AbstractSpliterator<T> implements java.util.Spliterator {
    +     ctor protected Spliterators.AbstractSpliterator(long, int);
    +     method public int characteristics();
    +     method public long estimateSize();
    +@@ -59034,7 +59034,7 @@ package java.util {
    +     method public java.util.SplittableRandom split();
    +   }
    + 
    +-  public class Stack extends java.util.Vector {
    ++  public class Stack<E> extends java.util.Vector {
    +     ctor public Stack();
    +     method public boolean empty();
    +     method public synchronized E peek();
    +@@ -59118,7 +59118,7 @@ package java.util {
    +     ctor public TooManyListenersException(java.lang.String);
    +   }
    + 
    +-  public class TreeMap extends java.util.AbstractMap implements java.lang.Cloneable java.util.NavigableMap java.io.Serializable {
    ++  public class TreeMap<K, V> extends java.util.AbstractMap implements java.lang.Cloneable java.util.NavigableMap java.io.Serializable {
    +     ctor public TreeMap();
    +     ctor public TreeMap(java.util.Comparator<? super K>);
    +     ctor public TreeMap(java.util.Map<? extends K, ? extends V>);
    +@@ -59155,7 +59155,7 @@ package java.util {
    +     method public java.util.SortedMap<K, V> tailMap(K);
    +   }
    + 
    +-  public class TreeSet extends java.util.AbstractSet implements java.lang.Cloneable java.util.NavigableSet java.io.Serializable {
    ++  public class TreeSet<E> extends java.util.AbstractSet implements java.lang.Cloneable java.util.NavigableSet java.io.Serializable {
    +     ctor public TreeSet();
    +     ctor public TreeSet(java.util.Comparator<? super E>);
    +     ctor public TreeSet(java.util.Collection<? extends E>);
    +@@ -59208,7 +59208,7 @@ package java.util {
    +     method public java.lang.String getFlags();
    +   }
    + 
    +-  public class Vector extends java.util.AbstractList implements java.lang.Cloneable java.util.List java.util.RandomAccess java.io.Serializable {
    ++  public class Vector<E> extends java.util.AbstractList implements java.lang.Cloneable java.util.List java.util.RandomAccess java.io.Serializable {
    +     ctor public Vector(int, int);
    +     ctor public Vector(int);
    +     ctor public Vector();
    +@@ -59243,7 +59243,7 @@ package java.util {
    +     field protected java.lang.Object[] elementData;
    +   }
    + 
    +-  public class WeakHashMap extends java.util.AbstractMap implements java.util.Map {
    ++  public class WeakHashMap<K, V> extends java.util.AbstractMap implements java.util.Map {
    +     ctor public WeakHashMap(int, float);
    +     ctor public WeakHashMap(int);
    +     ctor public WeakHashMap();
    +@@ -59259,18 +59259,18 @@ package java.util.concurrent {
    + 
    +   public abstract class AbstractExecutorService implements java.util.concurrent.ExecutorService {
    +     ctor public AbstractExecutorService();
    +-    method public java.util.List<java.util.concurrent.Future<T>> invokeAll(java.util.Collection<? extends java.util.concurrent.Callable<T>>) throws java.lang.InterruptedException;
    +-    method public java.util.List<java.util.concurrent.Future<T>> invokeAll(java.util.Collection<? extends java.util.concurrent.Callable<T>>, long, java.util.concurrent.TimeUnit) throws java.lang.InterruptedException;
    +-    method public T invokeAny(java.util.Collection<? extends java.util.concurrent.Callable<T>>) throws java.util.concurrent.ExecutionException, java.lang.InterruptedException;
    +-    method public T invokeAny(java.util.Collection<? extends java.util.concurrent.Callable<T>>, long, java.util.concurrent.TimeUnit) throws java.util.concurrent.ExecutionException, java.lang.InterruptedException, java.util.concurrent.TimeoutException;
    +-    method protected java.util.concurrent.RunnableFuture<T> newTaskFor(java.lang.Runnable, T);
    +-    method protected java.util.concurrent.RunnableFuture<T> newTaskFor(java.util.concurrent.Callable<T>);
    ++    method public <T> java.util.List<java.util.concurrent.Future<T>> invokeAll(java.util.Collection<? extends java.util.concurrent.Callable<T>>) throws java.lang.InterruptedException;
    ++    method public <T> java.util.List<java.util.concurrent.Future<T>> invokeAll(java.util.Collection<? extends java.util.concurrent.Callable<T>>, long, java.util.concurrent.TimeUnit) throws java.lang.InterruptedException;
    ++    method public <T> T invokeAny(java.util.Collection<? extends java.util.concurrent.Callable<T>>) throws java.util.concurrent.ExecutionException, java.lang.InterruptedException;
    ++    method public <T> T invokeAny(java.util.Collection<? extends java.util.concurrent.Callable<T>>, long, java.util.concurrent.TimeUnit) throws java.util.concurrent.ExecutionException, java.lang.InterruptedException, java.util.concurrent.TimeoutException;
    ++    method protected <T> java.util.concurrent.RunnableFuture<T> newTaskFor(java.lang.Runnable, T);
    ++    method protected <T> java.util.concurrent.RunnableFuture<T> newTaskFor(java.util.concurrent.Callable<T>);
    +     method public java.util.concurrent.Future<?> submit(java.lang.Runnable);
    +-    method public java.util.concurrent.Future<T> submit(java.lang.Runnable, T);
    +-    method public java.util.concurrent.Future<T> submit(java.util.concurrent.Callable<T>);
    ++    method public <T> java.util.concurrent.Future<T> submit(java.lang.Runnable, T);
    ++    method public <T> java.util.concurrent.Future<T> submit(java.util.concurrent.Callable<T>);
    +   }
    + 
    +-  public class ArrayBlockingQueue extends java.util.AbstractQueue implements java.util.concurrent.BlockingQueue java.io.Serializable {
    ++  public class ArrayBlockingQueue<E> extends java.util.AbstractQueue implements java.util.concurrent.BlockingQueue java.io.Serializable {
    +     ctor public ArrayBlockingQueue(int);
    +     ctor public ArrayBlockingQueue(int, boolean);
    +     ctor public ArrayBlockingQueue(int, boolean, java.util.Collection<? extends E>);
    +@@ -59289,7 +59289,7 @@ package java.util.concurrent {
    +     method public E take() throws java.lang.InterruptedException;
    +   }
    + 
    +-  public abstract interface BlockingDeque implements java.util.concurrent.BlockingQueue java.util.Deque {
    ++  public abstract interface BlockingDeque<E> implements java.util.concurrent.BlockingQueue java.util.Deque {
    +     method public abstract boolean add(E);
    +     method public abstract void addFirst(E);
    +     method public abstract void addLast(E);
    +@@ -59321,7 +59321,7 @@ package java.util.concurrent {
    +     method public abstract E takeLast() throws java.lang.InterruptedException;
    +   }
    + 
    +-  public abstract interface BlockingQueue implements java.util.Queue {
    ++  public abstract interface BlockingQueue<E> implements java.util.Queue {
    +     method public abstract boolean add(E);
    +     method public abstract boolean contains(java.lang.Object);
    +     method public abstract int drainTo(java.util.Collection<? super E>);
    +@@ -59340,7 +59340,7 @@ package java.util.concurrent {
    +     ctor public BrokenBarrierException(java.lang.String);
    +   }
    + 
    +-  public abstract interface Callable {
    ++  public abstract interface Callable<V> {
    +     method public abstract V call() throws java.lang.Exception;
    +   }
    + 
    +@@ -59349,28 +59349,28 @@ package java.util.concurrent {
    +     ctor public CancellationException(java.lang.String);
    +   }
    + 
    +-  public class CompletableFuture implements java.util.concurrent.CompletionStage java.util.concurrent.Future {
    ++  public class CompletableFuture<T> implements java.util.concurrent.CompletionStage java.util.concurrent.Future {
    +     ctor public CompletableFuture();
    +     method public java.util.concurrent.CompletableFuture<java.lang.Void> acceptEither(java.util.concurrent.CompletionStage<? extends T>, java.util.function.Consumer<? super T>);
    +     method public java.util.concurrent.CompletableFuture<java.lang.Void> acceptEitherAsync(java.util.concurrent.CompletionStage<? extends T>, java.util.function.Consumer<? super T>);
    +     method public java.util.concurrent.CompletableFuture<java.lang.Void> acceptEitherAsync(java.util.concurrent.CompletionStage<? extends T>, java.util.function.Consumer<? super T>, java.util.concurrent.Executor);
    +     method public static java.util.concurrent.CompletableFuture<java.lang.Void> allOf(java.util.concurrent.CompletableFuture<?>...);
    +     method public static java.util.concurrent.CompletableFuture<java.lang.Object> anyOf(java.util.concurrent.CompletableFuture<?>...);
    +-    method public java.util.concurrent.CompletableFuture<U> applyToEither(java.util.concurrent.CompletionStage<? extends T>, java.util.function.Function<? super T, U>);
    +-    method public java.util.concurrent.CompletableFuture<U> applyToEitherAsync(java.util.concurrent.CompletionStage<? extends T>, java.util.function.Function<? super T, U>);
    +-    method public java.util.concurrent.CompletableFuture<U> applyToEitherAsync(java.util.concurrent.CompletionStage<? extends T>, java.util.function.Function<? super T, U>, java.util.concurrent.Executor);
    ++    method public <U> java.util.concurrent.CompletableFuture<U> applyToEither(java.util.concurrent.CompletionStage<? extends T>, java.util.function.Function<? super T, U>);
    ++    method public <U> java.util.concurrent.CompletableFuture<U> applyToEitherAsync(java.util.concurrent.CompletionStage<? extends T>, java.util.function.Function<? super T, U>);
    ++    method public <U> java.util.concurrent.CompletableFuture<U> applyToEitherAsync(java.util.concurrent.CompletionStage<? extends T>, java.util.function.Function<? super T, U>, java.util.concurrent.Executor);
    +     method public boolean cancel(boolean);
    +     method public boolean complete(T);
    +     method public boolean completeExceptionally(java.lang.Throwable);
    +-    method public static java.util.concurrent.CompletableFuture<U> completedFuture(U);
    ++    method public static <U> java.util.concurrent.CompletableFuture<U> completedFuture(U);
    +     method public java.util.concurrent.CompletableFuture<T> exceptionally(java.util.function.Function<java.lang.Throwable, ? extends T>);
    +     method public T get() throws java.util.concurrent.ExecutionException, java.lang.InterruptedException;
    +     method public T get(long, java.util.concurrent.TimeUnit) throws java.util.concurrent.ExecutionException, java.lang.InterruptedException, java.util.concurrent.TimeoutException;
    +     method public T getNow(T);
    +     method public int getNumberOfDependents();
    +-    method public java.util.concurrent.CompletableFuture<U> handle(java.util.function.BiFunction<? super T, java.lang.Throwable, ? extends U>);
    +-    method public java.util.concurrent.CompletableFuture<U> handleAsync(java.util.function.BiFunction<? super T, java.lang.Throwable, ? extends U>);
    +-    method public java.util.concurrent.CompletableFuture<U> handleAsync(java.util.function.BiFunction<? super T, java.lang.Throwable, ? extends U>, java.util.concurrent.Executor);
    ++    method public <U> java.util.concurrent.CompletableFuture<U> handle(java.util.function.BiFunction<? super T, java.lang.Throwable, ? extends U>);
    ++    method public <U> java.util.concurrent.CompletableFuture<U> handleAsync(java.util.function.BiFunction<? super T, java.lang.Throwable, ? extends U>);
    ++    method public <U> java.util.concurrent.CompletableFuture<U> handleAsync(java.util.function.BiFunction<? super T, java.lang.Throwable, ? extends U>, java.util.concurrent.Executor);
    +     method public boolean isCancelled();
    +     method public boolean isCompletedExceptionally();
    +     method public boolean isDone();
    +@@ -59385,23 +59385,23 @@ package java.util.concurrent {
    +     method public java.util.concurrent.CompletableFuture<java.lang.Void> runAfterEitherAsync(java.util.concurrent.CompletionStage<?>, java.lang.Runnable, java.util.concurrent.Executor);
    +     method public static java.util.concurrent.CompletableFuture<java.lang.Void> runAsync(java.lang.Runnable);
    +     method public static java.util.concurrent.CompletableFuture<java.lang.Void> runAsync(java.lang.Runnable, java.util.concurrent.Executor);
    +-    method public static java.util.concurrent.CompletableFuture<U> supplyAsync(java.util.function.Supplier<U>);
    +-    method public static java.util.concurrent.CompletableFuture<U> supplyAsync(java.util.function.Supplier<U>, java.util.concurrent.Executor);
    ++    method public static <U> java.util.concurrent.CompletableFuture<U> supplyAsync(java.util.function.Supplier<U>);
    ++    method public static <U> java.util.concurrent.CompletableFuture<U> supplyAsync(java.util.function.Supplier<U>, java.util.concurrent.Executor);
    +     method public java.util.concurrent.CompletableFuture<java.lang.Void> thenAccept(java.util.function.Consumer<? super T>);
    +     method public java.util.concurrent.CompletableFuture<java.lang.Void> thenAcceptAsync(java.util.function.Consumer<? super T>);
    +     method public java.util.concurrent.CompletableFuture<java.lang.Void> thenAcceptAsync(java.util.function.Consumer<? super T>, java.util.concurrent.Executor);
    +-    method public java.util.concurrent.CompletableFuture<java.lang.Void> thenAcceptBoth(java.util.concurrent.CompletionStage<? extends U>, java.util.function.BiConsumer<? super T, ? super U>);
    +-    method public java.util.concurrent.CompletableFuture<java.lang.Void> thenAcceptBothAsync(java.util.concurrent.CompletionStage<? extends U>, java.util.function.BiConsumer<? super T, ? super U>);
    +-    method public java.util.concurrent.CompletableFuture<java.lang.Void> thenAcceptBothAsync(java.util.concurrent.CompletionStage<? extends U>, java.util.function.BiConsumer<? super T, ? super U>, java.util.concurrent.Executor);
    +-    method public java.util.concurrent.CompletableFuture<U> thenApply(java.util.function.Function<? super T, ? extends U>);
    +-    method public java.util.concurrent.CompletableFuture<U> thenApplyAsync(java.util.function.Function<? super T, ? extends U>);
    +-    method public java.util.concurrent.CompletableFuture<U> thenApplyAsync(java.util.function.Function<? super T, ? extends U>, java.util.concurrent.Executor);
    +-    method public java.util.concurrent.CompletableFuture<V> thenCombine(java.util.concurrent.CompletionStage<? extends U>, java.util.function.BiFunction<? super T, ? super U, ? extends V>);
    +-    method public java.util.concurrent.CompletableFuture<V> thenCombineAsync(java.util.concurrent.CompletionStage<? extends U>, java.util.function.BiFunction<? super T, ? super U, ? extends V>);
    +-    method public java.util.concurrent.CompletableFuture<V> thenCombineAsync(java.util.concurrent.CompletionStage<? extends U>, java.util.function.BiFunction<? super T, ? super U, ? extends V>, java.util.concurrent.Executor);
    +-    method public java.util.concurrent.CompletableFuture<U> thenCompose(java.util.function.Function<? super T, ? extends java.util.concurrent.CompletionStage<U>>);
    +-    method public java.util.concurrent.CompletableFuture<U> thenComposeAsync(java.util.function.Function<? super T, ? extends java.util.concurrent.CompletionStage<U>>);
    +-    method public java.util.concurrent.CompletableFuture<U> thenComposeAsync(java.util.function.Function<? super T, ? extends java.util.concurrent.CompletionStage<U>>, java.util.concurrent.Executor);
    ++    method public <U> java.util.concurrent.CompletableFuture<java.lang.Void> thenAcceptBoth(java.util.concurrent.CompletionStage<? extends U>, java.util.function.BiConsumer<? super T, ? super U>);
    ++    method public <U> java.util.concurrent.CompletableFuture<java.lang.Void> thenAcceptBothAsync(java.util.concurrent.CompletionStage<? extends U>, java.util.function.BiConsumer<? super T, ? super U>);
    ++    method public <U> java.util.concurrent.CompletableFuture<java.lang.Void> thenAcceptBothAsync(java.util.concurrent.CompletionStage<? extends U>, java.util.function.BiConsumer<? super T, ? super U>, java.util.concurrent.Executor);
    ++    method public <U> java.util.concurrent.CompletableFuture<U> thenApply(java.util.function.Function<? super T, ? extends U>);
    ++    method public <U> java.util.concurrent.CompletableFuture<U> thenApplyAsync(java.util.function.Function<? super T, ? extends U>);
    ++    method public <U> java.util.concurrent.CompletableFuture<U> thenApplyAsync(java.util.function.Function<? super T, ? extends U>, java.util.concurrent.Executor);
    ++    method public <U, V> java.util.concurrent.CompletableFuture<V> thenCombine(java.util.concurrent.CompletionStage<? extends U>, java.util.function.BiFunction<? super T, ? super U, ? extends V>);
    ++    method public <U, V> java.util.concurrent.CompletableFuture<V> thenCombineAsync(java.util.concurrent.CompletionStage<? extends U>, java.util.function.BiFunction<? super T, ? super U, ? extends V>);
    ++    method public <U, V> java.util.concurrent.CompletableFuture<V> thenCombineAsync(java.util.concurrent.CompletionStage<? extends U>, java.util.function.BiFunction<? super T, ? super U, ? extends V>, java.util.concurrent.Executor);
    ++    method public <U> java.util.concurrent.CompletableFuture<U> thenCompose(java.util.function.Function<? super T, ? extends java.util.concurrent.CompletionStage<U>>);
    ++    method public <U> java.util.concurrent.CompletableFuture<U> thenComposeAsync(java.util.function.Function<? super T, ? extends java.util.concurrent.CompletionStage<U>>);
    ++    method public <U> java.util.concurrent.CompletableFuture<U> thenComposeAsync(java.util.function.Function<? super T, ? extends java.util.concurrent.CompletionStage<U>>, java.util.concurrent.Executor);
    +     method public java.util.concurrent.CompletableFuture<java.lang.Void> thenRun(java.lang.Runnable);
    +     method public java.util.concurrent.CompletableFuture<java.lang.Void> thenRunAsync(java.lang.Runnable);
    +     method public java.util.concurrent.CompletableFuture<java.lang.Void> thenRunAsync(java.lang.Runnable, java.util.concurrent.Executor);
    +@@ -59421,7 +59421,7 @@ package java.util.concurrent {
    +     ctor public CompletionException(java.lang.Throwable);
    +   }
    + 
    +-  public abstract interface CompletionService {
    ++  public abstract interface CompletionService<V> {
    +     method public abstract java.util.concurrent.Future<V> poll();
    +     method public abstract java.util.concurrent.Future<V> poll(long, java.util.concurrent.TimeUnit) throws java.lang.InterruptedException;
    +     method public abstract java.util.concurrent.Future<V> submit(java.util.concurrent.Callable<V>);
    +@@ -59429,17 +59429,17 @@ package java.util.concurrent {
    +     method public abstract java.util.concurrent.Future<V> take() throws java.lang.InterruptedException;
    +   }
    + 
    +-  public abstract interface CompletionStage {
    ++  public abstract interface CompletionStage<T> {
    +     method public abstract java.util.concurrent.CompletionStage<java.lang.Void> acceptEither(java.util.concurrent.CompletionStage<? extends T>, java.util.function.Consumer<? super T>);
    +     method public abstract java.util.concurrent.CompletionStage<java.lang.Void> acceptEitherAsync(java.util.concurrent.CompletionStage<? extends T>, java.util.function.Consumer<? super T>);
    +     method public abstract java.util.concurrent.CompletionStage<java.lang.Void> acceptEitherAsync(java.util.concurrent.CompletionStage<? extends T>, java.util.function.Consumer<? super T>, java.util.concurrent.Executor);
    +-    method public abstract java.util.concurrent.CompletionStage<U> applyToEither(java.util.concurrent.CompletionStage<? extends T>, java.util.function.Function<? super T, U>);
    +-    method public abstract java.util.concurrent.CompletionStage<U> applyToEitherAsync(java.util.concurrent.CompletionStage<? extends T>, java.util.function.Function<? super T, U>);
    +-    method public abstract java.util.concurrent.CompletionStage<U> applyToEitherAsync(java.util.concurrent.CompletionStage<? extends T>, java.util.function.Function<? super T, U>, java.util.concurrent.Executor);
    ++    method public abstract <U> java.util.concurrent.CompletionStage<U> applyToEither(java.util.concurrent.CompletionStage<? extends T>, java.util.function.Function<? super T, U>);
    ++    method public abstract <U> java.util.concurrent.CompletionStage<U> applyToEitherAsync(java.util.concurrent.CompletionStage<? extends T>, java.util.function.Function<? super T, U>);
    ++    method public abstract <U> java.util.concurrent.CompletionStage<U> applyToEitherAsync(java.util.concurrent.CompletionStage<? extends T>, java.util.function.Function<? super T, U>, java.util.concurrent.Executor);
    +     method public abstract java.util.concurrent.CompletionStage<T> exceptionally(java.util.function.Function<java.lang.Throwable, ? extends T>);
    +-    method public abstract java.util.concurrent.CompletionStage<U> handle(java.util.function.BiFunction<? super T, java.lang.Throwable, ? extends U>);
    +-    method public abstract java.util.concurrent.CompletionStage<U> handleAsync(java.util.function.BiFunction<? super T, java.lang.Throwable, ? extends U>);
    +-    method public abstract java.util.concurrent.CompletionStage<U> handleAsync(java.util.function.BiFunction<? super T, java.lang.Throwable, ? extends U>, java.util.concurrent.Executor);
    ++    method public abstract <U> java.util.concurrent.CompletionStage<U> handle(java.util.function.BiFunction<? super T, java.lang.Throwable, ? extends U>);
    ++    method public abstract <U> java.util.concurrent.CompletionStage<U> handleAsync(java.util.function.BiFunction<? super T, java.lang.Throwable, ? extends U>);
    ++    method public abstract <U> java.util.concurrent.CompletionStage<U> handleAsync(java.util.function.BiFunction<? super T, java.lang.Throwable, ? extends U>, java.util.concurrent.Executor);
    +     method public abstract java.util.concurrent.CompletionStage<java.lang.Void> runAfterBoth(java.util.concurrent.CompletionStage<?>, java.lang.Runnable);
    +     method public abstract java.util.concurrent.CompletionStage<java.lang.Void> runAfterBothAsync(java.util.concurrent.CompletionStage<?>, java.lang.Runnable);
    +     method public abstract java.util.concurrent.CompletionStage<java.lang.Void> runAfterBothAsync(java.util.concurrent.CompletionStage<?>, java.lang.Runnable, java.util.concurrent.Executor);
    +@@ -59449,18 +59449,18 @@ package java.util.concurrent {
    +     method public abstract java.util.concurrent.CompletionStage<java.lang.Void> thenAccept(java.util.function.Consumer<? super T>);
    +     method public abstract java.util.concurrent.CompletionStage<java.lang.Void> thenAcceptAsync(java.util.function.Consumer<? super T>);
    +     method public abstract java.util.concurrent.CompletionStage<java.lang.Void> thenAcceptAsync(java.util.function.Consumer<? super T>, java.util.concurrent.Executor);
    +-    method public abstract java.util.concurrent.CompletionStage<java.lang.Void> thenAcceptBoth(java.util.concurrent.CompletionStage<? extends U>, java.util.function.BiConsumer<? super T, ? super U>);
    +-    method public abstract java.util.concurrent.CompletionStage<java.lang.Void> thenAcceptBothAsync(java.util.concurrent.CompletionStage<? extends U>, java.util.function.BiConsumer<? super T, ? super U>);
    +-    method public abstract java.util.concurrent.CompletionStage<java.lang.Void> thenAcceptBothAsync(java.util.concurrent.CompletionStage<? extends U>, java.util.function.BiConsumer<? super T, ? super U>, java.util.concurrent.Executor);
    +-    method public abstract java.util.concurrent.CompletionStage<U> thenApply(java.util.function.Function<? super T, ? extends U>);
    +-    method public abstract java.util.concurrent.CompletionStage<U> thenApplyAsync(java.util.function.Function<? super T, ? extends U>);
    +-    method public abstract java.util.concurrent.CompletionStage<U> thenApplyAsync(java.util.function.Function<? super T, ? extends U>, java.util.concurrent.Executor);
    +-    method public abstract java.util.concurrent.CompletionStage<V> thenCombine(java.util.concurrent.CompletionStage<? extends U>, java.util.function.BiFunction<? super T, ? super U, ? extends V>);
    +-    method public abstract java.util.concurrent.CompletionStage<V> thenCombineAsync(java.util.concurrent.CompletionStage<? extends U>, java.util.function.BiFunction<? super T, ? super U, ? extends V>);
    +-    method public abstract java.util.concurrent.CompletionStage<V> thenCombineAsync(java.util.concurrent.CompletionStage<? extends U>, java.util.function.BiFunction<? super T, ? super U, ? extends V>, java.util.concurrent.Executor);
    +-    method public abstract java.util.concurrent.CompletionStage<U> thenCompose(java.util.function.Function<? super T, ? extends java.util.concurrent.CompletionStage<U>>);
    +-    method public abstract java.util.concurrent.CompletionStage<U> thenComposeAsync(java.util.function.Function<? super T, ? extends java.util.concurrent.CompletionStage<U>>);
    +-    method public abstract java.util.concurrent.CompletionStage<U> thenComposeAsync(java.util.function.Function<? super T, ? extends java.util.concurrent.CompletionStage<U>>, java.util.concurrent.Executor);
    ++    method public abstract <U> java.util.concurrent.CompletionStage<java.lang.Void> thenAcceptBoth(java.util.concurrent.CompletionStage<? extends U>, java.util.function.BiConsumer<? super T, ? super U>);
    ++    method public abstract <U> java.util.concurrent.CompletionStage<java.lang.Void> thenAcceptBothAsync(java.util.concurrent.CompletionStage<? extends U>, java.util.function.BiConsumer<? super T, ? super U>);
    ++    method public abstract <U> java.util.concurrent.CompletionStage<java.lang.Void> thenAcceptBothAsync(java.util.concurrent.CompletionStage<? extends U>, java.util.function.BiConsumer<? super T, ? super U>, java.util.concurrent.Executor);
    ++    method public abstract <U> java.util.concurrent.CompletionStage<U> thenApply(java.util.function.Function<? super T, ? extends U>);
    ++    method public abstract <U> java.util.concurrent.CompletionStage<U> thenApplyAsync(java.util.function.Function<? super T, ? extends U>);
    ++    method public abstract <U> java.util.concurrent.CompletionStage<U> thenApplyAsync(java.util.function.Function<? super T, ? extends U>, java.util.concurrent.Executor);
    ++    method public abstract <U, V> java.util.concurrent.CompletionStage<V> thenCombine(java.util.concurrent.CompletionStage<? extends U>, java.util.function.BiFunction<? super T, ? super U, ? extends V>);
    ++    method public abstract <U, V> java.util.concurrent.CompletionStage<V> thenCombineAsync(java.util.concurrent.CompletionStage<? extends U>, java.util.function.BiFunction<? super T, ? super U, ? extends V>);
    ++    method public abstract <U, V> java.util.concurrent.CompletionStage<V> thenCombineAsync(java.util.concurrent.CompletionStage<? extends U>, java.util.function.BiFunction<? super T, ? super U, ? extends V>, java.util.concurrent.Executor);
    ++    method public abstract <U> java.util.concurrent.CompletionStage<U> thenCompose(java.util.function.Function<? super T, ? extends java.util.concurrent.CompletionStage<U>>);
    ++    method public abstract <U> java.util.concurrent.CompletionStage<U> thenComposeAsync(java.util.function.Function<? super T, ? extends java.util.concurrent.CompletionStage<U>>);
    ++    method public abstract <U> java.util.concurrent.CompletionStage<U> thenComposeAsync(java.util.function.Function<? super T, ? extends java.util.concurrent.CompletionStage<U>>, java.util.concurrent.Executor);
    +     method public abstract java.util.concurrent.CompletionStage<java.lang.Void> thenRun(java.lang.Runnable);
    +     method public abstract java.util.concurrent.CompletionStage<java.lang.Void> thenRunAsync(java.lang.Runnable);
    +     method public abstract java.util.concurrent.CompletionStage<java.lang.Void> thenRunAsync(java.lang.Runnable, java.util.concurrent.Executor);
    +@@ -59470,7 +59470,7 @@ package java.util.concurrent {
    +     method public abstract java.util.concurrent.CompletionStage<T> whenCompleteAsync(java.util.function.BiConsumer<? super T, ? super java.lang.Throwable>, java.util.concurrent.Executor);
    +   }
    + 
    +-  public class ConcurrentHashMap extends java.util.AbstractMap implements java.util.concurrent.ConcurrentMap java.io.Serializable {
    ++  public class ConcurrentHashMap<K, V> extends java.util.AbstractMap implements java.util.concurrent.ConcurrentMap java.io.Serializable {
    +     ctor public ConcurrentHashMap();
    +     ctor public ConcurrentHashMap(int);
    +     ctor public ConcurrentHashMap(java.util.Map<? extends K, ? extends V>);
    +@@ -59484,29 +59484,29 @@ package java.util.concurrent {
    +     method public java.util.Set<java.util.Map.Entry<K, V>> entrySet();
    +     method public void forEach(java.util.function.BiConsumer<? super K, ? super V>);
    +     method public void forEach(long, java.util.function.BiConsumer<? super K, ? super V>);
    +-    method public void forEach(long, java.util.function.BiFunction<? super K, ? super V, ? extends U>, java.util.function.Consumer<? super U>);
    ++    method public <U> void forEach(long, java.util.function.BiFunction<? super K, ? super V, ? extends U>, java.util.function.Consumer<? super U>);
    +     method public void forEachEntry(long, java.util.function.Consumer<? super java.util.Map.Entry<K, V>>);
    +-    method public void forEachEntry(long, java.util.function.Function<java.util.Map.Entry<K, V>, ? extends U>, java.util.function.Consumer<? super U>);
    ++    method public <U> void forEachEntry(long, java.util.function.Function<java.util.Map.Entry<K, V>, ? extends U>, java.util.function.Consumer<? super U>);
    +     method public void forEachKey(long, java.util.function.Consumer<? super K>);
    +-    method public void forEachKey(long, java.util.function.Function<? super K, ? extends U>, java.util.function.Consumer<? super U>);
    ++    method public <U> void forEachKey(long, java.util.function.Function<? super K, ? extends U>, java.util.function.Consumer<? super U>);
    +     method public void forEachValue(long, java.util.function.Consumer<? super V>);
    +-    method public void forEachValue(long, java.util.function.Function<? super V, ? extends U>, java.util.function.Consumer<? super U>);
    ++    method public <U> void forEachValue(long, java.util.function.Function<? super V, ? extends U>, java.util.function.Consumer<? super U>);
    +     method public V getOrDefault(java.lang.Object, V);
    +     method public java.util.concurrent.ConcurrentHashMap.KeySetView<K, V> keySet(V);
    +     method public java.util.Enumeration<K> keys();
    +     method public long mappingCount();
    +     method public V merge(K, V, java.util.function.BiFunction<? super V, ? super V, ? extends V>);
    +-    method public static java.util.concurrent.ConcurrentHashMap.KeySetView<K, java.lang.Boolean> newKeySet();
    +-    method public static java.util.concurrent.ConcurrentHashMap.KeySetView<K, java.lang.Boolean> newKeySet(int);
    ++    method public static <K> java.util.concurrent.ConcurrentHashMap.KeySetView<K, java.lang.Boolean> newKeySet();
    ++    method public static <K> java.util.concurrent.ConcurrentHashMap.KeySetView<K, java.lang.Boolean> newKeySet(int);
    +     method public V putIfAbsent(K, V);
    +-    method public U reduce(long, java.util.function.BiFunction<? super K, ? super V, ? extends U>, java.util.function.BiFunction<? super U, ? super U, ? extends U>);
    ++    method public <U> U reduce(long, java.util.function.BiFunction<? super K, ? super V, ? extends U>, java.util.function.BiFunction<? super U, ? super U, ? extends U>);
    +     method public java.util.Map.Entry<K, V> reduceEntries(long, java.util.function.BiFunction<java.util.Map.Entry<K, V>, java.util.Map.Entry<K, V>, ? extends java.util.Map.Entry<K, V>>);
    +-    method public U reduceEntries(long, java.util.function.Function<java.util.Map.Entry<K, V>, ? extends U>, java.util.function.BiFunction<? super U, ? super U, ? extends U>);
    ++    method public <U> U reduceEntries(long, java.util.function.Function<java.util.Map.Entry<K, V>, ? extends U>, java.util.function.BiFunction<? super U, ? super U, ? extends U>);
    +     method public double reduceEntriesToDouble(long, java.util.function.ToDoubleFunction<java.util.Map.Entry<K, V>>, double, java.util.function.DoubleBinaryOperator);
    +     method public int reduceEntriesToInt(long, java.util.function.ToIntFunction<java.util.Map.Entry<K, V>>, int, java.util.function.IntBinaryOperator);
    +     method public long reduceEntriesToLong(long, java.util.function.ToLongFunction<java.util.Map.Entry<K, V>>, long, java.util.function.LongBinaryOperator);
    +     method public K reduceKeys(long, java.util.function.BiFunction<? super K, ? super K, ? extends K>);
    +-    method public U reduceKeys(long, java.util.function.Function<? super K, ? extends U>, java.util.function.BiFunction<? super U, ? super U, ? extends U>);
    ++    method public <U> U reduceKeys(long, java.util.function.Function<? super K, ? extends U>, java.util.function.BiFunction<? super U, ? super U, ? extends U>);
    +     method public double reduceKeysToDouble(long, java.util.function.ToDoubleFunction<? super K>, double, java.util.function.DoubleBinaryOperator);
    +     method public int reduceKeysToInt(long, java.util.function.ToIntFunction<? super K>, int, java.util.function.IntBinaryOperator);
    +     method public long reduceKeysToLong(long, java.util.function.ToLongFunction<? super K>, long, java.util.function.LongBinaryOperator);
    +@@ -59514,7 +59514,7 @@ package java.util.concurrent {
    +     method public int reduceToInt(long, java.util.function.ToIntBiFunction<? super K, ? super V>, int, java.util.function.IntBinaryOperator);
    +     method public long reduceToLong(long, java.util.function.ToLongBiFunction<? super K, ? super V>, long, java.util.function.LongBinaryOperator);
    +     method public V reduceValues(long, java.util.function.BiFunction<? super V, ? super V, ? extends V>);
    +-    method public U reduceValues(long, java.util.function.Function<? super V, ? extends U>, java.util.function.BiFunction<? super U, ? super U, ? extends U>);
    ++    method public <U> U reduceValues(long, java.util.function.Function<? super V, ? extends U>, java.util.function.BiFunction<? super U, ? super U, ? extends U>);
    +     method public double reduceValuesToDouble(long, java.util.function.ToDoubleFunction<? super V>, double, java.util.function.DoubleBinaryOperator);
    +     method public int reduceValuesToInt(long, java.util.function.ToIntFunction<? super V>, int, java.util.function.IntBinaryOperator);
    +     method public long reduceValuesToLong(long, java.util.function.ToLongFunction<? super V>, long, java.util.function.LongBinaryOperator);
    +@@ -59522,13 +59522,13 @@ package java.util.concurrent {
    +     method public boolean replace(K, V, V);
    +     method public V replace(K, V);
    +     method public void replaceAll(java.util.function.BiFunction<? super K, ? super V, ? extends V>);
    +-    method public U search(long, java.util.function.BiFunction<? super K, ? super V, ? extends U>);
    +-    method public U searchEntries(long, java.util.function.Function<java.util.Map.Entry<K, V>, ? extends U>);
    +-    method public U searchKeys(long, java.util.function.Function<? super K, ? extends U>);
    +-    method public U searchValues(long, java.util.function.Function<? super V, ? extends U>);
    ++    method public <U> U search(long, java.util.function.BiFunction<? super K, ? super V, ? extends U>);
    ++    method public <U> U searchEntries(long, java.util.function.Function<java.util.Map.Entry<K, V>, ? extends U>);
    ++    method public <U> U searchKeys(long, java.util.function.Function<? super K, ? extends U>);
    ++    method public <U> U searchValues(long, java.util.function.Function<? super V, ? extends U>);
    +   }
    + 
    +-   static abstract class ConcurrentHashMap.CollectionView implements java.util.Collection java.io.Serializable {
    ++   static abstract class ConcurrentHashMap.CollectionView<K, V, E> implements java.util.Collection java.io.Serializable {
    +     method public final void clear();
    +     method public abstract boolean contains(java.lang.Object);
    +     method public final boolean containsAll(java.util.Collection<?>);
    +@@ -59540,11 +59540,11 @@ package java.util.concurrent {
    +     method public final boolean retainAll(java.util.Collection<?>);
    +     method public final int size();
    +     method public final java.lang.Object[] toArray();
    +-    method public final T[] toArray(T[]);
    ++    method public final <T> T[] toArray(T[]);
    +     method public final java.lang.String toString();
    +   }
    + 
    +-  public static class ConcurrentHashMap.KeySetView extends java.util.concurrent.ConcurrentHashMap.CollectionView implements java.io.Serializable java.util.Set {
    ++  public static class ConcurrentHashMap.KeySetView<K, V> extends java.util.concurrent.ConcurrentHashMap.CollectionView implements java.io.Serializable java.util.Set {
    +     method public boolean add(K);
    +     method public boolean addAll(java.util.Collection<? extends K>);
    +     method public boolean contains(java.lang.Object);
    +@@ -59555,7 +59555,7 @@ package java.util.concurrent {
    +     method public java.util.Spliterator<K> spliterator();
    +   }
    + 
    +-  public class ConcurrentLinkedDeque extends java.util.AbstractCollection implements java.util.Deque java.io.Serializable {
    ++  public class ConcurrentLinkedDeque<E> extends java.util.AbstractCollection implements java.util.Deque java.io.Serializable {
    +     ctor public ConcurrentLinkedDeque();
    +     ctor public ConcurrentLinkedDeque(java.util.Collection<? extends E>);
    +     method public void addFirst(E);
    +@@ -59585,7 +59585,7 @@ package java.util.concurrent {
    +     method public java.util.Spliterator<E> spliterator();
    +   }
    + 
    +-  public class ConcurrentLinkedQueue extends java.util.AbstractQueue implements java.util.Queue java.io.Serializable {
    ++  public class ConcurrentLinkedQueue<E> extends java.util.AbstractQueue implements java.util.Queue java.io.Serializable {
    +     ctor public ConcurrentLinkedQueue();
    +     ctor public ConcurrentLinkedQueue(java.util.Collection<? extends E>);
    +     method public java.util.Iterator<E> iterator();
    +@@ -59596,14 +59596,14 @@ package java.util.concurrent {
    +     method public java.util.Spliterator<E> spliterator();
    +   }
    + 
    +-  public abstract interface ConcurrentMap implements java.util.Map {
    ++  public abstract interface ConcurrentMap<K, V> implements java.util.Map {
    +     method public abstract V putIfAbsent(K, V);
    +     method public abstract boolean remove(java.lang.Object, java.lang.Object);
    +     method public abstract boolean replace(K, V, V);
    +     method public abstract V replace(K, V);
    +   }
    + 
    +-  public abstract interface ConcurrentNavigableMap implements java.util.concurrent.ConcurrentMap java.util.NavigableMap {
    ++  public abstract interface ConcurrentNavigableMap<K, V> implements java.util.concurrent.ConcurrentMap java.util.NavigableMap {
    +     method public abstract java.util.NavigableSet<K> descendingKeySet();
    +     method public abstract java.util.concurrent.ConcurrentNavigableMap<K, V> descendingMap();
    +     method public abstract java.util.concurrent.ConcurrentNavigableMap<K, V> headMap(K, boolean);
    +@@ -59616,7 +59616,7 @@ package java.util.concurrent {
    +     method public abstract java.util.concurrent.ConcurrentNavigableMap<K, V> tailMap(K);
    +   }
    + 
    +-  public class ConcurrentSkipListMap extends java.util.AbstractMap implements java.lang.Cloneable java.util.concurrent.ConcurrentNavigableMap java.io.Serializable {
    ++  public class ConcurrentSkipListMap<K, V> extends java.util.AbstractMap implements java.lang.Cloneable java.util.concurrent.ConcurrentNavigableMap java.io.Serializable {
    +     ctor public ConcurrentSkipListMap();
    +     ctor public ConcurrentSkipListMap(java.util.Comparator<? super K>);
    +     ctor public ConcurrentSkipListMap(java.util.Map<? extends K, ? extends V>);
    +@@ -59660,7 +59660,7 @@ package java.util.concurrent {
    +     method public java.util.concurrent.ConcurrentNavigableMap<K, V> tailMap(K);
    +   }
    + 
    +-  public class ConcurrentSkipListSet extends java.util.AbstractSet implements java.lang.Cloneable java.util.NavigableSet java.io.Serializable {
    ++  public class ConcurrentSkipListSet<E> extends java.util.AbstractSet implements java.lang.Cloneable java.util.NavigableSet java.io.Serializable {
    +     ctor public ConcurrentSkipListSet();
    +     ctor public ConcurrentSkipListSet(java.util.Comparator<? super E>);
    +     ctor public ConcurrentSkipListSet(java.util.Collection<? extends E>);
    +@@ -59688,7 +59688,7 @@ package java.util.concurrent {
    +     method public java.util.NavigableSet<E> tailSet(E);
    +   }
    + 
    +-  public class CopyOnWriteArrayList implements java.lang.Cloneable java.util.List java.util.RandomAccess java.io.Serializable {
    ++  public class CopyOnWriteArrayList<E> implements java.lang.Cloneable java.util.List java.util.RandomAccess java.io.Serializable {
    +     ctor public CopyOnWriteArrayList();
    +     ctor public CopyOnWriteArrayList(java.util.Collection<? extends E>);
    +     ctor public CopyOnWriteArrayList(E[]);
    +@@ -59720,10 +59720,10 @@ package java.util.concurrent {
    +     method public int size();
    +     method public java.util.List<E> subList(int, int);
    +     method public java.lang.Object[] toArray();
    +-    method public T[] toArray(T[]);
    ++    method public <T> T[] toArray(T[]);
    +   }
    + 
    +-  public class CopyOnWriteArraySet extends java.util.AbstractSet implements java.io.Serializable {
    ++  public class CopyOnWriteArraySet<E> extends java.util.AbstractSet implements java.io.Serializable {
    +     ctor public CopyOnWriteArraySet();
    +     ctor public CopyOnWriteArraySet(java.util.Collection<? extends E>);
    +     method public void forEach(java.util.function.Consumer<? super E>);
    +@@ -59741,7 +59741,7 @@ package java.util.concurrent {
    +     method public long getCount();
    +   }
    + 
    +-  public abstract class CountedCompleter extends java.util.concurrent.ForkJoinTask {
    ++  public abstract class CountedCompleter<T> extends java.util.concurrent.ForkJoinTask {
    +     ctor protected CountedCompleter(java.util.concurrent.CountedCompleter<?>, int);
    +     ctor protected CountedCompleter(java.util.concurrent.CountedCompleter<?>);
    +     ctor protected CountedCompleter();
    +@@ -59778,7 +59778,7 @@ package java.util.concurrent {
    +     method public void reset();
    +   }
    + 
    +-  public class DelayQueue extends java.util.AbstractQueue implements java.util.concurrent.BlockingQueue {
    ++  public class DelayQueue<E extends java.util.concurrent.Delayed> extends java.util.AbstractQueue implements java.util.concurrent.BlockingQueue {
    +     ctor public DelayQueue();
    +     ctor public DelayQueue(java.util.Collection<? extends E>);
    +     method public int drainTo(java.util.Collection<? super E>);
    +@@ -59799,7 +59799,7 @@ package java.util.concurrent {
    +     method public abstract long getDelay(java.util.concurrent.TimeUnit);
    +   }
    + 
    +-  public class Exchanger {
    ++  public class Exchanger<V> {
    +     ctor public Exchanger();
    +     method public V exchange(V) throws java.lang.InterruptedException;
    +     method public V exchange(V, long, java.util.concurrent.TimeUnit) throws java.lang.InterruptedException, java.util.concurrent.TimeoutException;
    +@@ -59816,7 +59816,7 @@ package java.util.concurrent {
    +     method public abstract void execute(java.lang.Runnable);
    +   }
    + 
    +-  public class ExecutorCompletionService implements java.util.concurrent.CompletionService {
    ++  public class ExecutorCompletionService<V> implements java.util.concurrent.CompletionService {
    +     ctor public ExecutorCompletionService(java.util.concurrent.Executor);
    +     ctor public ExecutorCompletionService(java.util.concurrent.Executor, java.util.concurrent.BlockingQueue<java.util.concurrent.Future<V>>);
    +     method public java.util.concurrent.Future<V> poll();
    +@@ -59828,21 +59828,21 @@ package java.util.concurrent {
    + 
    +   public abstract interface ExecutorService implements java.util.concurrent.Executor {
    +     method public abstract boolean awaitTermination(long, java.util.concurrent.TimeUnit) throws java.lang.InterruptedException;
    +-    method public abstract java.util.List<java.util.concurrent.Future<T>> invokeAll(java.util.Collection<? extends java.util.concurrent.Callable<T>>) throws java.lang.InterruptedException;
    +-    method public abstract java.util.List<java.util.concurrent.Future<T>> invokeAll(java.util.Collection<? extends java.util.concurrent.Callable<T>>, long, java.util.concurrent.TimeUnit) throws java.lang.InterruptedException;
    +-    method public abstract T invokeAny(java.util.Collection<? extends java.util.concurrent.Callable<T>>) throws java.util.concurrent.ExecutionException, java.lang.InterruptedException;
    +-    method public abstract T invokeAny(java.util.Collection<? extends java.util.concurrent.Callable<T>>, long, java.util.concurrent.TimeUnit) throws java.util.concurrent.ExecutionException, java.lang.InterruptedException, java.util.concurrent.TimeoutException;
    ++    method public abstract <T> java.util.List<java.util.concurrent.Future<T>> invokeAll(java.util.Collection<? extends java.util.concurrent.Callable<T>>) throws java.lang.InterruptedException;
    ++    method public abstract <T> java.util.List<java.util.concurrent.Future<T>> invokeAll(java.util.Collection<? extends java.util.concurrent.Callable<T>>, long, java.util.concurrent.TimeUnit) throws java.lang.InterruptedException;
    ++    method public abstract <T> T invokeAny(java.util.Collection<? extends java.util.concurrent.Callable<T>>) throws java.util.concurrent.ExecutionException, java.lang.InterruptedException;
    ++    method public abstract <T> T invokeAny(java.util.Collection<? extends java.util.concurrent.Callable<T>>, long, java.util.concurrent.TimeUnit) throws java.util.concurrent.ExecutionException, java.lang.InterruptedException, java.util.concurrent.TimeoutException;
    +     method public abstract boolean isShutdown();
    +     method public abstract boolean isTerminated();
    +     method public abstract void shutdown();
    +     method public abstract java.util.List<java.lang.Runnable> shutdownNow();
    +-    method public abstract java.util.concurrent.Future<T> submit(java.util.concurrent.Callable<T>);
    +-    method public abstract java.util.concurrent.Future<T> submit(java.lang.Runnable, T);
    ++    method public abstract <T> java.util.concurrent.Future<T> submit(java.util.concurrent.Callable<T>);
    ++    method public abstract <T> java.util.concurrent.Future<T> submit(java.lang.Runnable, T);
    +     method public abstract java.util.concurrent.Future<?> submit(java.lang.Runnable);
    +   }
    + 
    +   public class Executors {
    +-    method public static java.util.concurrent.Callable<T> callable(java.lang.Runnable, T);
    ++    method public static <T> java.util.concurrent.Callable<T> callable(java.lang.Runnable, T);
    +     method public static java.util.concurrent.Callable<java.lang.Object> callable(java.lang.Runnable);
    +     method public static java.util.concurrent.Callable<java.lang.Object> callable(java.security.PrivilegedAction<?>);
    +     method public static java.util.concurrent.Callable<java.lang.Object> callable(java.security.PrivilegedExceptionAction<?>);
    +@@ -59859,8 +59859,8 @@ package java.util.concurrent {
    +     method public static java.util.concurrent.ScheduledExecutorService newSingleThreadScheduledExecutor(java.util.concurrent.ThreadFactory);
    +     method public static java.util.concurrent.ExecutorService newWorkStealingPool(int);
    +     method public static java.util.concurrent.ExecutorService newWorkStealingPool();
    +-    method public static java.util.concurrent.Callable<T> privilegedCallable(java.util.concurrent.Callable<T>);
    +-    method public static java.util.concurrent.Callable<T> privilegedCallableUsingCurrentClassLoader(java.util.concurrent.Callable<T>);
    ++    method public static <T> java.util.concurrent.Callable<T> privilegedCallable(java.util.concurrent.Callable<T>);
    ++    method public static <T> java.util.concurrent.Callable<T> privilegedCallableUsingCurrentClassLoader(java.util.concurrent.Callable<T>);
    +     method public static java.util.concurrent.ThreadFactory privilegedThreadFactory();
    +     method public static java.util.concurrent.ExecutorService unconfigurableExecutorService(java.util.concurrent.ExecutorService);
    +     method public static java.util.concurrent.ScheduledExecutorService unconfigurableScheduledExecutorService(java.util.concurrent.ScheduledExecutorService);
    +@@ -59888,7 +59888,7 @@ package java.util.concurrent {
    +     method public long getStealCount();
    +     method public java.lang.Thread.UncaughtExceptionHandler getUncaughtExceptionHandler();
    +     method public boolean hasQueuedSubmissions();
    +-    method public T invoke(java.util.concurrent.ForkJoinTask<T>);
    ++    method public <T> T invoke(java.util.concurrent.ForkJoinTask<T>);
    +     method public boolean isQuiescent();
    +     method public boolean isShutdown();
    +     method public boolean isTerminated();
    +@@ -59897,7 +59897,7 @@ package java.util.concurrent {
    +     method protected java.util.concurrent.ForkJoinTask<?> pollSubmission();
    +     method public void shutdown();
    +     method public java.util.List<java.lang.Runnable> shutdownNow();
    +-    method public java.util.concurrent.ForkJoinTask<T> submit(java.util.concurrent.ForkJoinTask<T>);
    ++    method public <T> java.util.concurrent.ForkJoinTask<T> submit(java.util.concurrent.ForkJoinTask<T>);
    +     field public static final java.util.concurrent.ForkJoinPool.ForkJoinWorkerThreadFactory defaultForkJoinWorkerThreadFactory;
    +   }
    + 
    +@@ -59910,11 +59910,11 @@ package java.util.concurrent {
    +     method public abstract boolean isReleasable();
    +   }
    + 
    +-  public abstract class ForkJoinTask implements java.util.concurrent.Future java.io.Serializable {
    ++  public abstract class ForkJoinTask<V> implements java.util.concurrent.Future java.io.Serializable {
    +     ctor public ForkJoinTask();
    +     method public static java.util.concurrent.ForkJoinTask<?> adapt(java.lang.Runnable);
    +-    method public static java.util.concurrent.ForkJoinTask<T> adapt(java.lang.Runnable, T);
    +-    method public static java.util.concurrent.ForkJoinTask<T> adapt(java.util.concurrent.Callable<? extends T>);
    ++    method public static <T> java.util.concurrent.ForkJoinTask<T> adapt(java.lang.Runnable, T);
    ++    method public static <T> java.util.concurrent.ForkJoinTask<T> adapt(java.util.concurrent.Callable<? extends T>);
    +     method public boolean cancel(boolean);
    +     method public final boolean compareAndSetForkJoinTaskTag(short, short);
    +     method public void complete(V);
    +@@ -59934,7 +59934,7 @@ package java.util.concurrent {
    +     method public final V invoke();
    +     method public static void invokeAll(java.util.concurrent.ForkJoinTask<?>, java.util.concurrent.ForkJoinTask<?>);
    +     method public static void invokeAll(java.util.concurrent.ForkJoinTask<?>...);
    +-    method public static java.util.Collection<T> invokeAll(java.util.Collection<T>);
    ++    method public static <T extends java.util.concurrent.ForkJoinTask<?>> java.util.Collection<T> invokeAll(java.util.Collection<T>);
    +     method public final boolean isCancelled();
    +     method public final boolean isCompletedAbnormally();
    +     method public final boolean isCompletedNormally();
    +@@ -59960,7 +59960,7 @@ package java.util.concurrent {
    +     method protected void onTermination(java.lang.Throwable);
    +   }
    + 
    +-  public abstract interface Future {
    ++  public abstract interface Future<V> {
    +     method public abstract boolean cancel(boolean);
    +     method public abstract V get() throws java.util.concurrent.ExecutionException, java.lang.InterruptedException;
    +     method public abstract V get(long, java.util.concurrent.TimeUnit) throws java.util.concurrent.ExecutionException, java.lang.InterruptedException, java.util.concurrent.TimeoutException;
    +@@ -59968,7 +59968,7 @@ package java.util.concurrent {
    +     method public abstract boolean isDone();
    +   }
    + 
    +-  public class FutureTask implements java.util.concurrent.RunnableFuture {
    ++  public class FutureTask<V> implements java.util.concurrent.RunnableFuture {
    +     ctor public FutureTask(java.util.concurrent.Callable<V>);
    +     ctor public FutureTask(java.lang.Runnable, V);
    +     method public boolean cancel(boolean);
    +@@ -59983,7 +59983,7 @@ package java.util.concurrent {
    +     method protected void setException(java.lang.Throwable);
    +   }
    + 
    +-  public class LinkedBlockingDeque extends java.util.AbstractQueue implements java.util.concurrent.BlockingDeque java.io.Serializable {
    ++  public class LinkedBlockingDeque<E> extends java.util.AbstractQueue implements java.util.concurrent.BlockingDeque java.io.Serializable {
    +     ctor public LinkedBlockingDeque();
    +     ctor public LinkedBlockingDeque(int);
    +     ctor public LinkedBlockingDeque(java.util.Collection<? extends E>);
    +@@ -60027,7 +60027,7 @@ package java.util.concurrent {
    +     method public E takeLast() throws java.lang.InterruptedException;
    +   }
    + 
    +-  public class LinkedBlockingQueue extends java.util.AbstractQueue implements java.util.concurrent.BlockingQueue java.io.Serializable {
    ++  public class LinkedBlockingQueue<E> extends java.util.AbstractQueue implements java.util.concurrent.BlockingQueue java.io.Serializable {
    +     ctor public LinkedBlockingQueue();
    +     ctor public LinkedBlockingQueue(int);
    +     ctor public LinkedBlockingQueue(java.util.Collection<? extends E>);
    +@@ -60046,7 +60046,7 @@ package java.util.concurrent {
    +     method public E take() throws java.lang.InterruptedException;
    +   }
    + 
    +-  public class LinkedTransferQueue extends java.util.AbstractQueue implements java.io.Serializable java.util.concurrent.TransferQueue {
    ++  public class LinkedTransferQueue<E> extends java.util.AbstractQueue implements java.io.Serializable java.util.concurrent.TransferQueue {
    +     ctor public LinkedTransferQueue();
    +     ctor public LinkedTransferQueue(java.util.Collection<? extends E>);
    +     method public int drainTo(java.util.Collection<? super E>);
    +@@ -60093,7 +60093,7 @@ package java.util.concurrent {
    +     method public int register();
    +   }
    + 
    +-  public class PriorityBlockingQueue extends java.util.AbstractQueue implements java.util.concurrent.BlockingQueue java.io.Serializable {
    ++  public class PriorityBlockingQueue<E> extends java.util.AbstractQueue implements java.util.concurrent.BlockingQueue java.io.Serializable {
    +     ctor public PriorityBlockingQueue();
    +     ctor public PriorityBlockingQueue(int);
    +     ctor public PriorityBlockingQueue(int, java.util.Comparator<? super E>);
    +@@ -60122,7 +60122,7 @@ package java.util.concurrent {
    +     method protected final void setRawResult(java.lang.Void);
    +   }
    + 
    +-  public abstract class RecursiveTask extends java.util.concurrent.ForkJoinTask {
    ++  public abstract class RecursiveTask<V> extends java.util.concurrent.ForkJoinTask {
    +     ctor public RecursiveTask();
    +     method protected abstract V compute();
    +     method protected final boolean exec();
    +@@ -60141,22 +60141,22 @@ package java.util.concurrent {
    +     method public abstract void rejectedExecution(java.lang.Runnable, java.util.concurrent.ThreadPoolExecutor);
    +   }
    + 
    +-  public abstract interface RunnableFuture implements java.util.concurrent.Future java.lang.Runnable {
    ++  public abstract interface RunnableFuture<V> implements java.util.concurrent.Future java.lang.Runnable {
    +     method public abstract void run();
    +   }
    + 
    +-  public abstract interface RunnableScheduledFuture implements java.util.concurrent.RunnableFuture java.util.concurrent.ScheduledFuture {
    ++  public abstract interface RunnableScheduledFuture<V> implements java.util.concurrent.RunnableFuture java.util.concurrent.ScheduledFuture {
    +     method public abstract boolean isPeriodic();
    +   }
    + 
    +   public abstract interface ScheduledExecutorService implements java.util.concurrent.ExecutorService {
    +     method public abstract java.util.concurrent.ScheduledFuture<?> schedule(java.lang.Runnable, long, java.util.concurrent.TimeUnit);
    +-    method public abstract java.util.concurrent.ScheduledFuture<V> schedule(java.util.concurrent.Callable<V>, long, java.util.concurrent.TimeUnit);
    ++    method public abstract <V> java.util.concurrent.ScheduledFuture<V> schedule(java.util.concurrent.Callable<V>, long, java.util.concurrent.TimeUnit);
    +     method public abstract java.util.concurrent.ScheduledFuture<?> scheduleAtFixedRate(java.lang.Runnable, long, long, java.util.concurrent.TimeUnit);
    +     method public abstract java.util.concurrent.ScheduledFuture<?> scheduleWithFixedDelay(java.lang.Runnable, long, long, java.util.concurrent.TimeUnit);
    +   }
    + 
    +-  public abstract interface ScheduledFuture implements java.util.concurrent.Delayed java.util.concurrent.Future {
    ++  public abstract interface ScheduledFuture<V> implements java.util.concurrent.Delayed java.util.concurrent.Future {
    +   }
    + 
    +   public class ScheduledThreadPoolExecutor extends java.util.concurrent.ThreadPoolExecutor implements java.util.concurrent.ScheduledExecutorService {
    +@@ -60164,13 +60164,13 @@ package java.util.concurrent {
    +     ctor public ScheduledThreadPoolExecutor(int, java.util.concurrent.ThreadFactory);
    +     ctor public ScheduledThreadPoolExecutor(int, java.util.concurrent.RejectedExecutionHandler);
    +     ctor public ScheduledThreadPoolExecutor(int, java.util.concurrent.ThreadFactory, java.util.concurrent.RejectedExecutionHandler);
    +-    method protected java.util.concurrent.RunnableScheduledFuture<V> decorateTask(java.lang.Runnable, java.util.concurrent.RunnableScheduledFuture<V>);
    +-    method protected java.util.concurrent.RunnableScheduledFuture<V> decorateTask(java.util.concurrent.Callable<V>, java.util.concurrent.RunnableScheduledFuture<V>);
    ++    method protected <V> java.util.concurrent.RunnableScheduledFuture<V> decorateTask(java.lang.Runnable, java.util.concurrent.RunnableScheduledFuture<V>);
    ++    method protected <V> java.util.concurrent.RunnableScheduledFuture<V> decorateTask(java.util.concurrent.Callable<V>, java.util.concurrent.RunnableScheduledFuture<V>);
    +     method public boolean getContinueExistingPeriodicTasksAfterShutdownPolicy();
    +     method public boolean getExecuteExistingDelayedTasksAfterShutdownPolicy();
    +     method public boolean getRemoveOnCancelPolicy();
    +     method public java.util.concurrent.ScheduledFuture<?> schedule(java.lang.Runnable, long, java.util.concurrent.TimeUnit);
    +-    method public java.util.concurrent.ScheduledFuture<V> schedule(java.util.concurrent.Callable<V>, long, java.util.concurrent.TimeUnit);
    ++    method public <V> java.util.concurrent.ScheduledFuture<V> schedule(java.util.concurrent.Callable<V>, long, java.util.concurrent.TimeUnit);
    +     method public java.util.concurrent.ScheduledFuture<?> scheduleAtFixedRate(java.lang.Runnable, long, long, java.util.concurrent.TimeUnit);
    +     method public java.util.concurrent.ScheduledFuture<?> scheduleWithFixedDelay(java.lang.Runnable, long, long, java.util.concurrent.TimeUnit);
    +     method public void setContinueExistingPeriodicTasksAfterShutdownPolicy(boolean);
    +@@ -60200,7 +60200,7 @@ package java.util.concurrent {
    +     method public boolean tryAcquire(int, long, java.util.concurrent.TimeUnit) throws java.lang.InterruptedException;
    +   }
    + 
    +-  public class SynchronousQueue extends java.util.AbstractQueue implements java.util.concurrent.BlockingQueue java.io.Serializable {
    ++  public class SynchronousQueue<E> extends java.util.AbstractQueue implements java.util.concurrent.BlockingQueue java.io.Serializable {
    +     ctor public SynchronousQueue();
    +     ctor public SynchronousQueue(boolean);
    +     method public int drainTo(java.util.Collection<? super E>);
    +@@ -60318,7 +60318,7 @@ package java.util.concurrent {
    +     ctor public TimeoutException(java.lang.String);
    +   }
    + 
    +-  public abstract interface TransferQueue implements java.util.concurrent.BlockingQueue {
    ++  public abstract interface TransferQueue<E> implements java.util.concurrent.BlockingQueue {
    +     method public abstract int getWaitingConsumerCount();
    +     method public abstract boolean hasWaitingConsumer();
    +     method public abstract void transfer(E) throws java.lang.InterruptedException;
    +@@ -60388,7 +60388,7 @@ package java.util.concurrent.atomic {
    +     method public final boolean weakCompareAndSet(int, int, int);
    +   }
    + 
    +-  public abstract class AtomicIntegerFieldUpdater {
    ++  public abstract class AtomicIntegerFieldUpdater<T> {
    +     ctor protected AtomicIntegerFieldUpdater();
    +     method public final int accumulateAndGet(T, int, java.util.function.IntBinaryOperator);
    +     method public int addAndGet(T, int);
    +@@ -60403,7 +60403,7 @@ package java.util.concurrent.atomic {
    +     method public final int getAndUpdate(T, java.util.function.IntUnaryOperator);
    +     method public int incrementAndGet(T);
    +     method public abstract void lazySet(T, int);
    +-    method public static java.util.concurrent.atomic.AtomicIntegerFieldUpdater<U> newUpdater(java.lang.Class<U>, java.lang.String);
    ++    method public static <U> java.util.concurrent.atomic.AtomicIntegerFieldUpdater<U> newUpdater(java.lang.Class<U>, java.lang.String);
    +     method public abstract void set(T, int);
    +     method public final int updateAndGet(T, java.util.function.IntUnaryOperator);
    +     method public abstract boolean weakCompareAndSet(T, int, int);
    +@@ -60456,7 +60456,7 @@ package java.util.concurrent.atomic {
    +     method public final boolean weakCompareAndSet(int, long, long);
    +   }
    + 
    +-  public abstract class AtomicLongFieldUpdater {
    ++  public abstract class AtomicLongFieldUpdater<T> {
    +     ctor protected AtomicLongFieldUpdater();
    +     method public final long accumulateAndGet(T, long, java.util.function.LongBinaryOperator);
    +     method public long addAndGet(T, long);
    +@@ -60471,13 +60471,13 @@ package java.util.concurrent.atomic {
    +     method public final long getAndUpdate(T, java.util.function.LongUnaryOperator);
    +     method public long incrementAndGet(T);
    +     method public abstract void lazySet(T, long);
    +-    method public static java.util.concurrent.atomic.AtomicLongFieldUpdater<U> newUpdater(java.lang.Class<U>, java.lang.String);
    ++    method public static <U> java.util.concurrent.atomic.AtomicLongFieldUpdater<U> newUpdater(java.lang.Class<U>, java.lang.String);
    +     method public abstract void set(T, long);
    +     method public final long updateAndGet(T, java.util.function.LongUnaryOperator);
    +     method public abstract boolean weakCompareAndSet(T, long, long);
    +   }
    + 
    +-  public class AtomicMarkableReference {
    ++  public class AtomicMarkableReference<V> {
    +     ctor public AtomicMarkableReference(V, boolean);
    +     method public boolean attemptMark(V, boolean);
    +     method public boolean compareAndSet(V, V, boolean, boolean);
    +@@ -60488,7 +60488,7 @@ package java.util.concurrent.atomic {
    +     method public boolean weakCompareAndSet(V, V, boolean, boolean);
    +   }
    + 
    +-  public class AtomicReference implements java.io.Serializable {
    ++  public class AtomicReference<V> implements java.io.Serializable {
    +     ctor public AtomicReference(V);
    +     ctor public AtomicReference();
    +     method public final V accumulateAndGet(V, java.util.function.BinaryOperator<V>);
    +@@ -60503,7 +60503,7 @@ package java.util.concurrent.atomic {
    +     method public final boolean weakCompareAndSet(V, V);
    +   }
    + 
    +-  public class AtomicReferenceArray implements java.io.Serializable {
    ++  public class AtomicReferenceArray<E> implements java.io.Serializable {
    +     ctor public AtomicReferenceArray(int);
    +     ctor public AtomicReferenceArray(E[]);
    +     method public final E accumulateAndGet(int, E, java.util.function.BinaryOperator<E>);
    +@@ -60519,7 +60519,7 @@ package java.util.concurrent.atomic {
    +     method public final boolean weakCompareAndSet(int, E, E);
    +   }
    + 
    +-  public abstract class AtomicReferenceFieldUpdater {
    ++  public abstract class AtomicReferenceFieldUpdater<T, V> {
    +     ctor protected AtomicReferenceFieldUpdater();
    +     method public final V accumulateAndGet(T, V, java.util.function.BinaryOperator<V>);
    +     method public abstract boolean compareAndSet(T, V, V);
    +@@ -60528,13 +60528,13 @@ package java.util.concurrent.atomic {
    +     method public V getAndSet(T, V);
    +     method public final V getAndUpdate(T, java.util.function.UnaryOperator<V>);
    +     method public abstract void lazySet(T, V);
    +-    method public static java.util.concurrent.atomic.AtomicReferenceFieldUpdater<U, W> newUpdater(java.lang.Class<U>, java.lang.Class<W>, java.lang.String);
    ++    method public static <U, W> java.util.concurrent.atomic.AtomicReferenceFieldUpdater<U, W> newUpdater(java.lang.Class<U>, java.lang.Class<W>, java.lang.String);
    +     method public abstract void set(T, V);
    +     method public final V updateAndGet(T, java.util.function.UnaryOperator<V>);
    +     method public abstract boolean weakCompareAndSet(T, V, V);
    +   }
    + 
    +-  public class AtomicStampedReference {
    ++  public class AtomicStampedReference<V> {
    +     ctor public AtomicStampedReference(V, int);
    +     method public boolean attemptStamp(V, int);
    +     method public boolean compareAndSet(V, V, int, int);
    +@@ -60837,33 +60837,33 @@ package java.util.concurrent.locks {
    + 
    + package java.util.function {
    + 
    +-  public abstract interface BiConsumer {
    ++  public abstract interface BiConsumer<T, U> {
    +     method public abstract void accept(T, U);
    +     method public default java.util.function.BiConsumer<T, U> andThen(java.util.function.BiConsumer<? super T, ? super U>);
    +   }
    + 
    +-  public abstract interface BiFunction {
    +-    method public default java.util.function.BiFunction<T, U, V> andThen(java.util.function.Function<? super R, ? extends V>);
    ++  public abstract interface BiFunction<T, U, R> {
    ++    method public default <V> java.util.function.BiFunction<T, U, V> andThen(java.util.function.Function<? super R, ? extends V>);
    +     method public abstract R apply(T, U);
    +   }
    + 
    +-  public abstract interface BiPredicate {
    ++  public abstract interface BiPredicate<T, U> {
    +     method public default java.util.function.BiPredicate<T, U> and(java.util.function.BiPredicate<? super T, ? super U>);
    +     method public default java.util.function.BiPredicate<T, U> negate();
    +     method public default java.util.function.BiPredicate<T, U> or(java.util.function.BiPredicate<? super T, ? super U>);
    +     method public abstract boolean test(T, U);
    +   }
    + 
    +-  public abstract interface BinaryOperator implements java.util.function.BiFunction {
    +-    method public static java.util.function.BinaryOperator<T> maxBy(java.util.Comparator<? super T>);
    +-    method public static java.util.function.BinaryOperator<T> minBy(java.util.Comparator<? super T>);
    ++  public abstract interface BinaryOperator<T> implements java.util.function.BiFunction {
    ++    method public static <T> java.util.function.BinaryOperator<T> maxBy(java.util.Comparator<? super T>);
    ++    method public static <T> java.util.function.BinaryOperator<T> minBy(java.util.Comparator<? super T>);
    +   }
    + 
    +   public abstract interface BooleanSupplier {
    +     method public abstract boolean getAsBoolean();
    +   }
    + 
    +-  public abstract interface Consumer {
    ++  public abstract interface Consumer<T> {
    +     method public abstract void accept(T);
    +     method public default java.util.function.Consumer<T> andThen(java.util.function.Consumer<? super T>);
    +   }
    +@@ -60877,7 +60877,7 @@ package java.util.function {
    +     method public default java.util.function.DoubleConsumer andThen(java.util.function.DoubleConsumer);
    +   }
    + 
    +-  public abstract interface DoubleFunction {
    ++  public abstract interface DoubleFunction<R> {
    +     method public abstract R apply(double);
    +   }
    + 
    +@@ -60907,11 +60907,11 @@ package java.util.function {
    +     method public static java.util.function.DoubleUnaryOperator identity();
    +   }
    + 
    +-  public abstract interface Function {
    +-    method public default java.util.function.Function<T, V> andThen(java.util.function.Function<? super R, ? extends V>);
    ++  public abstract interface Function<T, R> {
    ++    method public default <V> java.util.function.Function<T, V> andThen(java.util.function.Function<? super R, ? extends V>);
    +     method public abstract R apply(T);
    +-    method public default java.util.function.Function<V, R> compose(java.util.function.Function<? super V, ? extends T>);
    +-    method public static java.util.function.Function<T, T> identity();
    ++    method public default <V> java.util.function.Function<V, R> compose(java.util.function.Function<? super V, ? extends T>);
    ++    method public static <T> java.util.function.Function<T, T> identity();
    +   }
    + 
    +   public abstract interface IntBinaryOperator {
    +@@ -60923,7 +60923,7 @@ package java.util.function {
    +     method public default java.util.function.IntConsumer andThen(java.util.function.IntConsumer);
    +   }
    + 
    +-  public abstract interface IntFunction {
    ++  public abstract interface IntFunction<R> {
    +     method public abstract R apply(int);
    +   }
    + 
    +@@ -60962,7 +60962,7 @@ package java.util.function {
    +     method public default java.util.function.LongConsumer andThen(java.util.function.LongConsumer);
    +   }
    + 
    +-  public abstract interface LongFunction {
    ++  public abstract interface LongFunction<R> {
    +     method public abstract R apply(long);
    +   }
    + 
    +@@ -60992,56 +60992,56 @@ package java.util.function {
    +     method public static java.util.function.LongUnaryOperator identity();
    +   }
    + 
    +-  public abstract interface ObjDoubleConsumer {
    ++  public abstract interface ObjDoubleConsumer<T> {
    +     method public abstract void accept(T, double);
    +   }
    + 
    +-  public abstract interface ObjIntConsumer {
    ++  public abstract interface ObjIntConsumer<T> {
    +     method public abstract void accept(T, int);
    +   }
    + 
    +-  public abstract interface ObjLongConsumer {
    ++  public abstract interface ObjLongConsumer<T> {
    +     method public abstract void accept(T, long);
    +   }
    + 
    +-  public abstract interface Predicate {
    ++  public abstract interface Predicate<T> {
    +     method public default java.util.function.Predicate<T> and(java.util.function.Predicate<? super T>);
    +-    method public static java.util.function.Predicate<T> isEqual(java.lang.Object);
    ++    method public static <T> java.util.function.Predicate<T> isEqual(java.lang.Object);
    +     method public default java.util.function.Predicate<T> negate();
    +     method public default java.util.function.Predicate<T> or(java.util.function.Predicate<? super T>);
    +     method public abstract boolean test(T);
    +   }
    + 
    +-  public abstract interface Supplier {
    ++  public abstract interface Supplier<T> {
    +     method public abstract T get();
    +   }
    + 
    +-  public abstract interface ToDoubleBiFunction {
    ++  public abstract interface ToDoubleBiFunction<T, U> {
    +     method public abstract double applyAsDouble(T, U);
    +   }
    + 
    +-  public abstract interface ToDoubleFunction {
    ++  public abstract interface ToDoubleFunction<T> {
    +     method public abstract double applyAsDouble(T);
    +   }
    + 
    +-  public abstract interface ToIntBiFunction {
    ++  public abstract interface ToIntBiFunction<T, U> {
    +     method public abstract int applyAsInt(T, U);
    +   }
    + 
    +-  public abstract interface ToIntFunction {
    ++  public abstract interface ToIntFunction<T> {
    +     method public abstract int applyAsInt(T);
    +   }
    + 
    +-  public abstract interface ToLongBiFunction {
    ++  public abstract interface ToLongBiFunction<T, U> {
    +     method public abstract long applyAsLong(T, U);
    +   }
    + 
    +-  public abstract interface ToLongFunction {
    ++  public abstract interface ToLongFunction<T> {
    +     method public abstract long applyAsLong(T);
    +   }
    + 
    +-  public abstract interface UnaryOperator implements java.util.function.Function {
    +-    method public static java.util.function.UnaryOperator<T> identity();
    ++  public abstract interface UnaryOperator<T> implements java.util.function.Function {
    ++    method public static <T> java.util.function.UnaryOperator<T> identity();
    +   }
    + 
    + }
    +@@ -61629,7 +61629,7 @@ package java.util.regex {
    + 
    + package java.util.stream {
    + 
    +-  public abstract interface BaseStream implements java.lang.AutoCloseable {
    ++  public abstract interface BaseStream<T, S extends java.util.stream.BaseStream<T, S>> implements java.lang.AutoCloseable {
    +     method public abstract void close();
    +     method public abstract boolean isParallel();
    +     method public abstract java.util.Iterator<T> iterator();
    +@@ -61640,13 +61640,13 @@ package java.util.stream {
    +     method public abstract S unordered();
    +   }
    + 
    +-  public abstract interface Collector {
    ++  public abstract interface Collector<T, A, R> {
    +     method public abstract java.util.function.BiConsumer<A, T> accumulator();
    +     method public abstract java.util.Set<java.util.stream.Collector.Characteristics> characteristics();
    +     method public abstract java.util.function.BinaryOperator<A> combiner();
    +     method public abstract java.util.function.Function<A, R> finisher();
    +-    method public static java.util.stream.Collector<T, R, R> of(java.util.function.Supplier<R>, java.util.function.BiConsumer<R, T>, java.util.function.BinaryOperator<R>, java.util.stream.Collector.Characteristics...);
    +-    method public static java.util.stream.Collector<T, A, R> of(java.util.function.Supplier<A>, java.util.function.BiConsumer<A, T>, java.util.function.BinaryOperator<A>, java.util.function.Function<A, R>, java.util.stream.Collector.Characteristics...);
    ++    method public static <T, R> java.util.stream.Collector<T, R, R> of(java.util.function.Supplier<R>, java.util.function.BiConsumer<R, T>, java.util.function.BinaryOperator<R>, java.util.stream.Collector.Characteristics...);
    ++    method public static <T, A, R> java.util.stream.Collector<T, A, R> of(java.util.function.Supplier<A>, java.util.function.BiConsumer<A, T>, java.util.function.BinaryOperator<A>, java.util.function.Function<A, R>, java.util.stream.Collector.Characteristics...);
    +     method public abstract java.util.function.Supplier<A> supplier();
    +   }
    + 
    +@@ -61659,43 +61659,43 @@ package java.util.stream {
    +   }
    + 
    +   public final class Collectors {
    +-    method public static java.util.stream.Collector<T, ?, java.lang.Double> averagingDouble(java.util.function.ToDoubleFunction<? super T>);
    +-    method public static java.util.stream.Collector<T, ?, java.lang.Double> averagingInt(java.util.function.ToIntFunction<? super T>);
    +-    method public static java.util.stream.Collector<T, ?, java.lang.Double> averagingLong(java.util.function.ToLongFunction<? super T>);
    +-    method public static java.util.stream.Collector<T, A, RR> collectingAndThen(java.util.stream.Collector<T, A, R>, java.util.function.Function<R, RR>);
    +-    method public static java.util.stream.Collector<T, ?, java.lang.Long> counting();
    +-    method public static java.util.stream.Collector<T, ?, java.util.Map<K, java.util.List<T>>> groupingBy(java.util.function.Function<? super T, ? extends K>);
    +-    method public static java.util.stream.Collector<T, ?, java.util.Map<K, D>> groupingBy(java.util.function.Function<? super T, ? extends K>, java.util.stream.Collector<? super T, A, D>);
    +-    method public static java.util.stream.Collector<T, ?, M> groupingBy(java.util.function.Function<? super T, ? extends K>, java.util.function.Supplier<M>, java.util.stream.Collector<? super T, A, D>);
    +-    method public static java.util.stream.Collector<T, ?, java.util.concurrent.ConcurrentMap<K, java.util.List<T>>> groupingByConcurrent(java.util.function.Function<? super T, ? extends K>);
    +-    method public static java.util.stream.Collector<T, ?, java.util.concurrent.ConcurrentMap<K, D>> groupingByConcurrent(java.util.function.Function<? super T, ? extends K>, java.util.stream.Collector<? super T, A, D>);
    +-    method public static java.util.stream.Collector<T, ?, M> groupingByConcurrent(java.util.function.Function<? super T, ? extends K>, java.util.function.Supplier<M>, java.util.stream.Collector<? super T, A, D>);
    ++    method public static <T> java.util.stream.Collector<T, ?, java.lang.Double> averagingDouble(java.util.function.ToDoubleFunction<? super T>);
    ++    method public static <T> java.util.stream.Collector<T, ?, java.lang.Double> averagingInt(java.util.function.ToIntFunction<? super T>);
    ++    method public static <T> java.util.stream.Collector<T, ?, java.lang.Double> averagingLong(java.util.function.ToLongFunction<? super T>);
    ++    method public static <T, A, R, RR> java.util.stream.Collector<T, A, RR> collectingAndThen(java.util.stream.Collector<T, A, R>, java.util.function.Function<R, RR>);
    ++    method public static <T> java.util.stream.Collector<T, ?, java.lang.Long> counting();
    ++    method public static <T, K> java.util.stream.Collector<T, ?, java.util.Map<K, java.util.List<T>>> groupingBy(java.util.function.Function<? super T, ? extends K>);
    ++    method public static <T, K, A, D> java.util.stream.Collector<T, ?, java.util.Map<K, D>> groupingBy(java.util.function.Function<? super T, ? extends K>, java.util.stream.Collector<? super T, A, D>);
    ++    method public static <T, K, D, A, M extends java.util.Map<K, D>> java.util.stream.Collector<T, ?, M> groupingBy(java.util.function.Function<? super T, ? extends K>, java.util.function.Supplier<M>, java.util.stream.Collector<? super T, A, D>);
    ++    method public static <T, K> java.util.stream.Collector<T, ?, java.util.concurrent.ConcurrentMap<K, java.util.List<T>>> groupingByConcurrent(java.util.function.Function<? super T, ? extends K>);
    ++    method public static <T, K, A, D> java.util.stream.Collector<T, ?, java.util.concurrent.ConcurrentMap<K, D>> groupingByConcurrent(java.util.function.Function<? super T, ? extends K>, java.util.stream.Collector<? super T, A, D>);
    ++    method public static <T, K, A, D, M extends java.util.concurrent.ConcurrentMap<K, D>> java.util.stream.Collector<T, ?, M> groupingByConcurrent(java.util.function.Function<? super T, ? extends K>, java.util.function.Supplier<M>, java.util.stream.Collector<? super T, A, D>);
    +     method public static java.util.stream.Collector<java.lang.CharSequence, ?, java.lang.String> joining();
    +     method public static java.util.stream.Collector<java.lang.CharSequence, ?, java.lang.String> joining(java.lang.CharSequence);
    +     method public static java.util.stream.Collector<java.lang.CharSequence, ?, java.lang.String> joining(java.lang.CharSequence, java.lang.CharSequence, java.lang.CharSequence);
    +-    method public static java.util.stream.Collector<T, ?, R> mapping(java.util.function.Function<? super T, ? extends U>, java.util.stream.Collector<? super U, A, R>);
    +-    method public static java.util.stream.Collector<T, ?, java.util.Optional<T>> maxBy(java.util.Comparator<? super T>);
    +-    method public static java.util.stream.Collector<T, ?, java.util.Optional<T>> minBy(java.util.Comparator<? super T>);
    +-    method public static java.util.stream.Collector<T, ?, java.util.Map<java.lang.Boolean, java.util.List<T>>> partitioningBy(java.util.function.Predicate<? super T>);
    +-    method public static java.util.stream.Collector<T, ?, java.util.Map<java.lang.Boolean, D>> partitioningBy(java.util.function.Predicate<? super T>, java.util.stream.Collector<? super T, A, D>);
    +-    method public static java.util.stream.Collector<T, ?, T> reducing(T, java.util.function.BinaryOperator<T>);
    +-    method public static java.util.stream.Collector<T, ?, java.util.Optional<T>> reducing(java.util.function.BinaryOperator<T>);
    +-    method public static java.util.stream.Collector<T, ?, U> reducing(U, java.util.function.Function<? super T, ? extends U>, java.util.function.BinaryOperator<U>);
    +-    method public static java.util.stream.Collector<T, ?, java.util.DoubleSummaryStatistics> summarizingDouble(java.util.function.ToDoubleFunction<? super T>);
    +-    method public static java.util.stream.Collector<T, ?, java.util.IntSummaryStatistics> summarizingInt(java.util.function.ToIntFunction<? super T>);
    +-    method public static java.util.stream.Collector<T, ?, java.util.LongSummaryStatistics> summarizingLong(java.util.function.ToLongFunction<? super T>);
    +-    method public static java.util.stream.Collector<T, ?, java.lang.Double> summingDouble(java.util.function.ToDoubleFunction<? super T>);
    +-    method public static java.util.stream.Collector<T, ?, java.lang.Integer> summingInt(java.util.function.ToIntFunction<? super T>);
    +-    method public static java.util.stream.Collector<T, ?, java.lang.Long> summingLong(java.util.function.ToLongFunction<? super T>);
    +-    method public static java.util.stream.Collector<T, ?, C> toCollection(java.util.function.Supplier<C>);
    +-    method public static java.util.stream.Collector<T, ?, java.util.concurrent.ConcurrentMap<K, U>> toConcurrentMap(java.util.function.Function<? super T, ? extends K>, java.util.function.Function<? super T, ? extends U>);
    +-    method public static java.util.stream.Collector<T, ?, java.util.concurrent.ConcurrentMap<K, U>> toConcurrentMap(java.util.function.Function<? super T, ? extends K>, java.util.function.Function<? super T, ? extends U>, java.util.function.BinaryOperator<U>);
    +-    method public static java.util.stream.Collector<T, ?, M> toConcurrentMap(java.util.function.Function<? super T, ? extends K>, java.util.function.Function<? super T, ? extends U>, java.util.function.BinaryOperator<U>, java.util.function.Supplier<M>);
    +-    method public static java.util.stream.Collector<T, ?, java.util.List<T>> toList();
    +-    method public static java.util.stream.Collector<T, ?, java.util.Map<K, U>> toMap(java.util.function.Function<? super T, ? extends K>, java.util.function.Function<? super T, ? extends U>);
    +-    method public static java.util.stream.Collector<T, ?, java.util.Map<K, U>> toMap(java.util.function.Function<? super T, ? extends K>, java.util.function.Function<? super T, ? extends U>, java.util.function.BinaryOperator<U>);
    +-    method public static java.util.stream.Collector<T, ?, M> toMap(java.util.function.Function<? super T, ? extends K>, java.util.function.Function<? super T, ? extends U>, java.util.function.BinaryOperator<U>, java.util.function.Supplier<M>);
    +-    method public static java.util.stream.Collector<T, ?, java.util.Set<T>> toSet();
    ++    method public static <T, U, A, R> java.util.stream.Collector<T, ?, R> mapping(java.util.function.Function<? super T, ? extends U>, java.util.stream.Collector<? super U, A, R>);
    ++    method public static <T> java.util.stream.Collector<T, ?, java.util.Optional<T>> maxBy(java.util.Comparator<? super T>);
    ++    method public static <T> java.util.stream.Collector<T, ?, java.util.Optional<T>> minBy(java.util.Comparator<? super T>);
    ++    method public static <T> java.util.stream.Collector<T, ?, java.util.Map<java.lang.Boolean, java.util.List<T>>> partitioningBy(java.util.function.Predicate<? super T>);
    ++    method public static <T, D, A> java.util.stream.Collector<T, ?, java.util.Map<java.lang.Boolean, D>> partitioningBy(java.util.function.Predicate<? super T>, java.util.stream.Collector<? super T, A, D>);
    ++    method public static <T> java.util.stream.Collector<T, ?, T> reducing(T, java.util.function.BinaryOperator<T>);
    ++    method public static <T> java.util.stream.Collector<T, ?, java.util.Optional<T>> reducing(java.util.function.BinaryOperator<T>);
    ++    method public static <T, U> java.util.stream.Collector<T, ?, U> reducing(U, java.util.function.Function<? super T, ? extends U>, java.util.function.BinaryOperator<U>);
    ++    method public static <T> java.util.stream.Collector<T, ?, java.util.DoubleSummaryStatistics> summarizingDouble(java.util.function.ToDoubleFunction<? super T>);
    ++    method public static <T> java.util.stream.Collector<T, ?, java.util.IntSummaryStatistics> summarizingInt(java.util.function.ToIntFunction<? super T>);
    ++    method public static <T> java.util.stream.Collector<T, ?, java.util.LongSummaryStatistics> summarizingLong(java.util.function.ToLongFunction<? super T>);
    ++    method public static <T> java.util.stream.Collector<T, ?, java.lang.Double> summingDouble(java.util.function.ToDoubleFunction<? super T>);
    ++    method public static <T> java.util.stream.Collector<T, ?, java.lang.Integer> summingInt(java.util.function.ToIntFunction<? super T>);
    ++    method public static <T> java.util.stream.Collector<T, ?, java.lang.Long> summingLong(java.util.function.ToLongFunction<? super T>);
    ++    method public static <T, C extends java.util.Collection<T>> java.util.stream.Collector<T, ?, C> toCollection(java.util.function.Supplier<C>);
    ++    method public static <T, K, U> java.util.stream.Collector<T, ?, java.util.concurrent.ConcurrentMap<K, U>> toConcurrentMap(java.util.function.Function<? super T, ? extends K>, java.util.function.Function<? super T, ? extends U>);
    ++    method public static <T, K, U> java.util.stream.Collector<T, ?, java.util.concurrent.ConcurrentMap<K, U>> toConcurrentMap(java.util.function.Function<? super T, ? extends K>, java.util.function.Function<? super T, ? extends U>, java.util.function.BinaryOperator<U>);
    ++    method public static <T, K, U, M extends java.util.concurrent.ConcurrentMap<K, U>> java.util.stream.Collector<T, ?, M> toConcurrentMap(java.util.function.Function<? super T, ? extends K>, java.util.function.Function<? super T, ? extends U>, java.util.function.BinaryOperator<U>, java.util.function.Supplier<M>);
    ++    method public static <T> java.util.stream.Collector<T, ?, java.util.List<T>> toList();
    ++    method public static <T, K, U> java.util.stream.Collector<T, ?, java.util.Map<K, U>> toMap(java.util.function.Function<? super T, ? extends K>, java.util.function.Function<? super T, ? extends U>);
    ++    method public static <T, K, U> java.util.stream.Collector<T, ?, java.util.Map<K, U>> toMap(java.util.function.Function<? super T, ? extends K>, java.util.function.Function<? super T, ? extends U>, java.util.function.BinaryOperator<U>);
    ++    method public static <T, K, U, M extends java.util.Map<K, U>> java.util.stream.Collector<T, ?, M> toMap(java.util.function.Function<? super T, ? extends K>, java.util.function.Function<? super T, ? extends U>, java.util.function.BinaryOperator<U>, java.util.function.Supplier<M>);
    ++    method public static <T> java.util.stream.Collector<T, ?, java.util.Set<T>> toSet();
    +   }
    + 
    +   public abstract interface DoubleStream implements java.util.stream.BaseStream {
    +@@ -61704,7 +61704,7 @@ package java.util.stream {
    +     method public abstract java.util.OptionalDouble average();
    +     method public abstract java.util.stream.Stream<java.lang.Double> boxed();
    +     method public static java.util.stream.DoubleStream.Builder builder();
    +-    method public abstract R collect(java.util.function.Supplier<R>, java.util.function.ObjDoubleConsumer<R>, java.util.function.BiConsumer<R, R>);
    ++    method public abstract <R> R collect(java.util.function.Supplier<R>, java.util.function.ObjDoubleConsumer<R>, java.util.function.BiConsumer<R, R>);
    +     method public static java.util.stream.DoubleStream concat(java.util.stream.DoubleStream, java.util.stream.DoubleStream);
    +     method public abstract long count();
    +     method public abstract java.util.stream.DoubleStream distinct();
    +@@ -61722,7 +61722,7 @@ package java.util.stream {
    +     method public abstract java.util.stream.DoubleStream map(java.util.function.DoubleUnaryOperator);
    +     method public abstract java.util.stream.IntStream mapToInt(java.util.function.DoubleToIntFunction);
    +     method public abstract java.util.stream.LongStream mapToLong(java.util.function.DoubleToLongFunction);
    +-    method public abstract java.util.stream.Stream<U> mapToObj(java.util.function.DoubleFunction<? extends U>);
    ++    method public abstract <U> java.util.stream.Stream<U> mapToObj(java.util.function.DoubleFunction<? extends U>);
    +     method public abstract java.util.OptionalDouble max();
    +     method public abstract java.util.OptionalDouble min();
    +     method public abstract boolean noneMatch(java.util.function.DoublePredicate);
    +@@ -61755,7 +61755,7 @@ package java.util.stream {
    +     method public abstract java.util.OptionalDouble average();
    +     method public abstract java.util.stream.Stream<java.lang.Integer> boxed();
    +     method public static java.util.stream.IntStream.Builder builder();
    +-    method public abstract R collect(java.util.function.Supplier<R>, java.util.function.ObjIntConsumer<R>, java.util.function.BiConsumer<R, R>);
    ++    method public abstract <R> R collect(java.util.function.Supplier<R>, java.util.function.ObjIntConsumer<R>, java.util.function.BiConsumer<R, R>);
    +     method public static java.util.stream.IntStream concat(java.util.stream.IntStream, java.util.stream.IntStream);
    +     method public abstract long count();
    +     method public abstract java.util.stream.IntStream distinct();
    +@@ -61773,7 +61773,7 @@ package java.util.stream {
    +     method public abstract java.util.stream.IntStream map(java.util.function.IntUnaryOperator);
    +     method public abstract java.util.stream.DoubleStream mapToDouble(java.util.function.IntToDoubleFunction);
    +     method public abstract java.util.stream.LongStream mapToLong(java.util.function.IntToLongFunction);
    +-    method public abstract java.util.stream.Stream<U> mapToObj(java.util.function.IntFunction<? extends U>);
    ++    method public abstract <U> java.util.stream.Stream<U> mapToObj(java.util.function.IntFunction<? extends U>);
    +     method public abstract java.util.OptionalInt max();
    +     method public abstract java.util.OptionalInt min();
    +     method public abstract boolean noneMatch(java.util.function.IntPredicate);
    +@@ -61807,7 +61807,7 @@ package java.util.stream {
    +     method public abstract java.util.OptionalDouble average();
    +     method public abstract java.util.stream.Stream<java.lang.Long> boxed();
    +     method public static java.util.stream.LongStream.Builder builder();
    +-    method public abstract R collect(java.util.function.Supplier<R>, java.util.function.ObjLongConsumer<R>, java.util.function.BiConsumer<R, R>);
    ++    method public abstract <R> R collect(java.util.function.Supplier<R>, java.util.function.ObjLongConsumer<R>, java.util.function.BiConsumer<R, R>);
    +     method public static java.util.stream.LongStream concat(java.util.stream.LongStream, java.util.stream.LongStream);
    +     method public abstract long count();
    +     method public abstract java.util.stream.LongStream distinct();
    +@@ -61825,7 +61825,7 @@ package java.util.stream {
    +     method public abstract java.util.stream.LongStream map(java.util.function.LongUnaryOperator);
    +     method public abstract java.util.stream.DoubleStream mapToDouble(java.util.function.LongToDoubleFunction);
    +     method public abstract java.util.stream.IntStream mapToInt(java.util.function.LongToIntFunction);
    +-    method public abstract java.util.stream.Stream<U> mapToObj(java.util.function.LongFunction<? extends U>);
    ++    method public abstract <U> java.util.stream.Stream<U> mapToObj(java.util.function.LongFunction<? extends U>);
    +     method public abstract java.util.OptionalLong max();
    +     method public abstract java.util.OptionalLong min();
    +     method public abstract boolean noneMatch(java.util.function.LongPredicate);
    +@@ -61852,49 +61852,49 @@ package java.util.stream {
    +     method public abstract java.util.stream.LongStream build();
    +   }
    + 
    +-  public abstract interface Stream implements java.util.stream.BaseStream {
    ++  public abstract interface Stream<T> implements java.util.stream.BaseStream {
    +     method public abstract boolean allMatch(java.util.function.Predicate<? super T>);
    +     method public abstract boolean anyMatch(java.util.function.Predicate<? super T>);
    +-    method public static java.util.stream.Stream.Builder<T> builder();
    +-    method public abstract R collect(java.util.function.Supplier<R>, java.util.function.BiConsumer<R, ? super T>, java.util.function.BiConsumer<R, R>);
    +-    method public abstract R collect(java.util.stream.Collector<? super T, A, R>);
    +-    method public static java.util.stream.Stream<T> concat(java.util.stream.Stream<? extends T>, java.util.stream.Stream<? extends T>);
    ++    method public static <T> java.util.stream.Stream.Builder<T> builder();
    ++    method public abstract <R> R collect(java.util.function.Supplier<R>, java.util.function.BiConsumer<R, ? super T>, java.util.function.BiConsumer<R, R>);
    ++    method public abstract <R, A> R collect(java.util.stream.Collector<? super T, A, R>);
    ++    method public static <T> java.util.stream.Stream<T> concat(java.util.stream.Stream<? extends T>, java.util.stream.Stream<? extends T>);
    +     method public abstract long count();
    +     method public abstract java.util.stream.Stream<T> distinct();
    +-    method public static java.util.stream.Stream<T> empty();
    ++    method public static <T> java.util.stream.Stream<T> empty();
    +     method public abstract java.util.stream.Stream<T> filter(java.util.function.Predicate<? super T>);
    +     method public abstract java.util.Optional<T> findAny();
    +     method public abstract java.util.Optional<T> findFirst();
    +-    method public abstract java.util.stream.Stream<R> flatMap(java.util.function.Function<? super T, ? extends java.util.stream.Stream<? extends R>>);
    ++    method public abstract <R> java.util.stream.Stream<R> flatMap(java.util.function.Function<? super T, ? extends java.util.stream.Stream<? extends R>>);
    +     method public abstract java.util.stream.DoubleStream flatMapToDouble(java.util.function.Function<? super T, ? extends java.util.stream.DoubleStream>);
    +     method public abstract java.util.stream.IntStream flatMapToInt(java.util.function.Function<? super T, ? extends java.util.stream.IntStream>);
    +     method public abstract java.util.stream.LongStream flatMapToLong(java.util.function.Function<? super T, ? extends java.util.stream.LongStream>);
    +     method public abstract void forEach(java.util.function.Consumer<? super T>);
    +     method public abstract void forEachOrdered(java.util.function.Consumer<? super T>);
    +-    method public static java.util.stream.Stream<T> generate(java.util.function.Supplier<T>);
    +-    method public static java.util.stream.Stream<T> iterate(T, java.util.function.UnaryOperator<T>);
    ++    method public static <T> java.util.stream.Stream<T> generate(java.util.function.Supplier<T>);
    ++    method public static <T> java.util.stream.Stream<T> iterate(T, java.util.function.UnaryOperator<T>);
    +     method public abstract java.util.stream.Stream<T> limit(long);
    +-    method public abstract java.util.stream.Stream<R> map(java.util.function.Function<? super T, ? extends R>);
    ++    method public abstract <R> java.util.stream.Stream<R> map(java.util.function.Function<? super T, ? extends R>);
    +     method public abstract java.util.stream.DoubleStream mapToDouble(java.util.function.ToDoubleFunction<? super T>);
    +     method public abstract java.util.stream.IntStream mapToInt(java.util.function.ToIntFunction<? super T>);
    +     method public abstract java.util.stream.LongStream mapToLong(java.util.function.ToLongFunction<? super T>);
    +     method public abstract java.util.Optional<T> max(java.util.Comparator<? super T>);
    +     method public abstract java.util.Optional<T> min(java.util.Comparator<? super T>);
    +     method public abstract boolean noneMatch(java.util.function.Predicate<? super T>);
    +-    method public static java.util.stream.Stream<T> of(T);
    +-    method public static java.util.stream.Stream<T> of(T...);
    ++    method public static <T> java.util.stream.Stream<T> of(T);
    ++    method public static <T> java.util.stream.Stream<T> of(T...);
    +     method public abstract java.util.stream.Stream<T> peek(java.util.function.Consumer<? super T>);
    +     method public abstract T reduce(T, java.util.function.BinaryOperator<T>);
    +     method public abstract java.util.Optional<T> reduce(java.util.function.BinaryOperator<T>);
    +-    method public abstract U reduce(U, java.util.function.BiFunction<U, ? super T, U>, java.util.function.BinaryOperator<U>);
    ++    method public abstract <U> U reduce(U, java.util.function.BiFunction<U, ? super T, U>, java.util.function.BinaryOperator<U>);
    +     method public abstract java.util.stream.Stream<T> skip(long);
    +     method public abstract java.util.stream.Stream<T> sorted();
    +     method public abstract java.util.stream.Stream<T> sorted(java.util.Comparator<? super T>);
    +     method public abstract java.lang.Object[] toArray();
    +-    method public abstract A[] toArray(java.util.function.IntFunction<A[]>);
    ++    method public abstract <A> A[] toArray(java.util.function.IntFunction<A[]>);
    +   }
    + 
    +-  public static abstract interface Stream.Builder implements java.util.function.Consumer {
    ++  public static abstract interface Stream.Builder<T> implements java.util.function.Consumer {
    +     method public abstract void accept(T);
    +     method public default java.util.stream.Stream.Builder<T> add(T);
    +     method public abstract java.util.stream.Stream<T> build();
    +@@ -61907,8 +61907,8 @@ package java.util.stream {
    +     method public static java.util.stream.IntStream intStream(java.util.function.Supplier<? extends java.util.Spliterator.OfInt>, int, boolean);
    +     method public static java.util.stream.LongStream longStream(java.util.Spliterator.OfLong, boolean);
    +     method public static java.util.stream.LongStream longStream(java.util.function.Supplier<? extends java.util.Spliterator.OfLong>, int, boolean);
    +-    method public static java.util.stream.Stream<T> stream(java.util.Spliterator<T>, boolean);
    +-    method public static java.util.stream.Stream<T> stream(java.util.function.Supplier<? extends java.util.Spliterator<T>>, int, boolean);
    ++    method public static <T> java.util.stream.Stream<T> stream(java.util.Spliterator<T>, boolean);
    ++    method public static <T> java.util.stream.Stream<T> stream(java.util.function.Supplier<? extends java.util.Spliterator<T>>, int, boolean);
    +   }
    + 
    + }
    +@@ -64079,16 +64079,16 @@ package javax.security.auth {
    +   public final class Subject implements java.io.Serializable {
    +     ctor public Subject();
    +     ctor public Subject(boolean, java.util.Set<? extends java.security.Principal>, java.util.Set<?>, java.util.Set<?>);
    +-    method public static T doAs(javax.security.auth.Subject, java.security.PrivilegedAction<T>);
    +-    method public static T doAs(javax.security.auth.Subject, java.security.PrivilegedExceptionAction<T>) throws java.security.PrivilegedActionException;
    +-    method public static T doAsPrivileged(javax.security.auth.Subject, java.security.PrivilegedAction<T>, java.security.AccessControlContext);
    +-    method public static T doAsPrivileged(javax.security.auth.Subject, java.security.PrivilegedExceptionAction<T>, java.security.AccessControlContext) throws java.security.PrivilegedActionException;
    ++    method public static <T> T doAs(javax.security.auth.Subject, java.security.PrivilegedAction<T>);
    ++    method public static <T> T doAs(javax.security.auth.Subject, java.security.PrivilegedExceptionAction<T>) throws java.security.PrivilegedActionException;
    ++    method public static <T> T doAsPrivileged(javax.security.auth.Subject, java.security.PrivilegedAction<T>, java.security.AccessControlContext);
    ++    method public static <T> T doAsPrivileged(javax.security.auth.Subject, java.security.PrivilegedExceptionAction<T>, java.security.AccessControlContext) throws java.security.PrivilegedActionException;
    +     method public java.util.Set<java.security.Principal> getPrincipals();
    +-    method public java.util.Set<T> getPrincipals(java.lang.Class<T>);
    ++    method public <T extends java.security.Principal> java.util.Set<T> getPrincipals(java.lang.Class<T>);
    +     method public java.util.Set<java.lang.Object> getPrivateCredentials();
    +-    method public java.util.Set<T> getPrivateCredentials(java.lang.Class<T>);
    ++    method public <T> java.util.Set<T> getPrivateCredentials(java.lang.Class<T>);
    +     method public java.util.Set<java.lang.Object> getPublicCredentials();
    +-    method public java.util.Set<T> getPublicCredentials(java.lang.Class<T>);
    ++    method public <T> java.util.Set<T> getPublicCredentials(java.lang.Class<T>);
    +     method public static javax.security.auth.Subject getSubject(java.security.AccessControlContext);
    +     method public boolean isReadOnly();
    +     method public void setReadOnly();
    +diff --git a/api/system-current.txt b/api/system-current.txt
    +index c33fe6e..0fe164a 100644
    +--- a/api/system-current.txt
    ++++ b/api/system-current.txt
    +@@ -3031,11 +3031,11 @@ package android.accounts {
    +     field public static final java.lang.String LOGIN_ACCOUNTS_CHANGED_ACTION = "android.accounts.LOGIN_ACCOUNTS_CHANGED";
    +   }
    + 
    +-  public abstract interface AccountManagerCallback {
    ++  public abstract interface AccountManagerCallback<V> {
    +     method public abstract void run(android.accounts.AccountManagerFuture<V>);
    +   }
    + 
    +-  public abstract interface AccountManagerFuture {
    ++  public abstract interface AccountManagerFuture<V> {
    +     method public abstract boolean cancel(boolean);
    +     method public abstract V getResult() throws android.accounts.AuthenticatorException, java.io.IOException, android.accounts.OperationCanceledException;
    +     method public abstract V getResult(long, java.util.concurrent.TimeUnit) throws android.accounts.AuthenticatorException, java.io.IOException, android.accounts.OperationCanceledException;
    +@@ -3181,7 +3181,7 @@ package android.animation {
    +     method public java.lang.Object evaluate(float, java.lang.Object, java.lang.Object);
    +   }
    + 
    +-  public abstract class BidirectionalTypeConverter extends android.animation.TypeConverter {
    ++  public abstract class BidirectionalTypeConverter<T, V> extends android.animation.TypeConverter {
    +     ctor public BidirectionalTypeConverter(java.lang.Class<T>, java.lang.Class<V>);
    +     method public abstract T convertBack(V);
    +     method public android.animation.BidirectionalTypeConverter<V, T> invert();
    +@@ -3273,26 +3273,26 @@ package android.animation {
    +     method public java.lang.String getPropertyName();
    +     method public java.lang.Object getTarget();
    +     method public static android.animation.ObjectAnimator ofArgb(java.lang.Object, java.lang.String, int...);
    +-    method public static android.animation.ObjectAnimator ofArgb(T, android.util.Property<T, java.lang.Integer>, int...);
    ++    method public static <T> android.animation.ObjectAnimator ofArgb(T, android.util.Property<T, java.lang.Integer>, int...);
    +     method public static android.animation.ObjectAnimator ofFloat(java.lang.Object, java.lang.String, float...);
    +     method public static android.animation.ObjectAnimator ofFloat(java.lang.Object, java.lang.String, java.lang.String, android.graphics.Path);
    +-    method public static android.animation.ObjectAnimator ofFloat(T, android.util.Property<T, java.lang.Float>, float...);
    +-    method public static android.animation.ObjectAnimator ofFloat(T, android.util.Property<T, java.lang.Float>, android.util.Property<T, java.lang.Float>, android.graphics.Path);
    ++    method public static <T> android.animation.ObjectAnimator ofFloat(T, android.util.Property<T, java.lang.Float>, float...);
    ++    method public static <T> android.animation.ObjectAnimator ofFloat(T, android.util.Property<T, java.lang.Float>, android.util.Property<T, java.lang.Float>, android.graphics.Path);
    +     method public static android.animation.ObjectAnimator ofInt(java.lang.Object, java.lang.String, int...);
    +     method public static android.animation.ObjectAnimator ofInt(java.lang.Object, java.lang.String, java.lang.String, android.graphics.Path);
    +-    method public static android.animation.ObjectAnimator ofInt(T, android.util.Property<T, java.lang.Integer>, int...);
    +-    method public static android.animation.ObjectAnimator ofInt(T, android.util.Property<T, java.lang.Integer>, android.util.Property<T, java.lang.Integer>, android.graphics.Path);
    ++    method public static <T> android.animation.ObjectAnimator ofInt(T, android.util.Property<T, java.lang.Integer>, int...);
    ++    method public static <T> android.animation.ObjectAnimator ofInt(T, android.util.Property<T, java.lang.Integer>, android.util.Property<T, java.lang.Integer>, android.graphics.Path);
    +     method public static android.animation.ObjectAnimator ofMultiFloat(java.lang.Object, java.lang.String, float[][]);
    +     method public static android.animation.ObjectAnimator ofMultiFloat(java.lang.Object, java.lang.String, android.graphics.Path);
    +-    method public static android.animation.ObjectAnimator ofMultiFloat(java.lang.Object, java.lang.String, android.animation.TypeConverter<T, float[]>, android.animation.TypeEvaluator<T>, T...);
    ++    method public static <T> android.animation.ObjectAnimator ofMultiFloat(java.lang.Object, java.lang.String, android.animation.TypeConverter<T, float[]>, android.animation.TypeEvaluator<T>, T...);
    +     method public static android.animation.ObjectAnimator ofMultiInt(java.lang.Object, java.lang.String, int[][]);
    +     method public static android.animation.ObjectAnimator ofMultiInt(java.lang.Object, java.lang.String, android.graphics.Path);
    +-    method public static android.animation.ObjectAnimator ofMultiInt(java.lang.Object, java.lang.String, android.animation.TypeConverter<T, int[]>, android.animation.TypeEvaluator<T>, T...);
    ++    method public static <T> android.animation.ObjectAnimator ofMultiInt(java.lang.Object, java.lang.String, android.animation.TypeConverter<T, int[]>, android.animation.TypeEvaluator<T>, T...);
    +     method public static android.animation.ObjectAnimator ofObject(java.lang.Object, java.lang.String, android.animation.TypeEvaluator, java.lang.Object...);
    +     method public static android.animation.ObjectAnimator ofObject(java.lang.Object, java.lang.String, android.animation.TypeConverter<android.graphics.PointF, ?>, android.graphics.Path);
    +-    method public static android.animation.ObjectAnimator ofObject(T, android.util.Property<T, V>, android.animation.TypeEvaluator<V>, V...);
    +-    method public static android.animation.ObjectAnimator ofObject(T, android.util.Property<T, P>, android.animation.TypeConverter<V, P>, android.animation.TypeEvaluator<V>, V...);
    +-    method public static android.animation.ObjectAnimator ofObject(T, android.util.Property<T, V>, android.animation.TypeConverter<android.graphics.PointF, V>, android.graphics.Path);
    ++    method public static <T, V> android.animation.ObjectAnimator ofObject(T, android.util.Property<T, V>, android.animation.TypeEvaluator<V>, V...);
    ++    method public static <T, V, P> android.animation.ObjectAnimator ofObject(T, android.util.Property<T, P>, android.animation.TypeConverter<V, P>, android.animation.TypeEvaluator<V>, V...);
    ++    method public static <T, V> android.animation.ObjectAnimator ofObject(T, android.util.Property<T, V>, android.animation.TypeConverter<android.graphics.PointF, V>, android.graphics.Path);
    +     method public static android.animation.ObjectAnimator ofPropertyValuesHolder(java.lang.Object, android.animation.PropertyValuesHolder...);
    +     method public void setAutoCancel(boolean);
    +     method public void setProperty(android.util.Property);
    +@@ -3316,17 +3316,17 @@ package android.animation {
    +     method public static android.animation.PropertyValuesHolder ofKeyframe(android.util.Property, android.animation.Keyframe...);
    +     method public static android.animation.PropertyValuesHolder ofMultiFloat(java.lang.String, float[][]);
    +     method public static android.animation.PropertyValuesHolder ofMultiFloat(java.lang.String, android.graphics.Path);
    +-    method public static android.animation.PropertyValuesHolder ofMultiFloat(java.lang.String, android.animation.TypeConverter<V, float[]>, android.animation.TypeEvaluator<V>, V...);
    +-    method public static android.animation.PropertyValuesHolder ofMultiFloat(java.lang.String, android.animation.TypeConverter<T, float[]>, android.animation.TypeEvaluator<T>, android.animation.Keyframe...);
    ++    method public static <V> android.animation.PropertyValuesHolder ofMultiFloat(java.lang.String, android.animation.TypeConverter<V, float[]>, android.animation.TypeEvaluator<V>, V...);
    ++    method public static <T> android.animation.PropertyValuesHolder ofMultiFloat(java.lang.String, android.animation.TypeConverter<T, float[]>, android.animation.TypeEvaluator<T>, android.animation.Keyframe...);
    +     method public static android.animation.PropertyValuesHolder ofMultiInt(java.lang.String, int[][]);
    +     method public static android.animation.PropertyValuesHolder ofMultiInt(java.lang.String, android.graphics.Path);
    +-    method public static android.animation.PropertyValuesHolder ofMultiInt(java.lang.String, android.animation.TypeConverter<V, int[]>, android.animation.TypeEvaluator<V>, V...);
    +-    method public static android.animation.PropertyValuesHolder ofMultiInt(java.lang.String, android.animation.TypeConverter<T, int[]>, android.animation.TypeEvaluator<T>, android.animation.Keyframe...);
    ++    method public static <V> android.animation.PropertyValuesHolder ofMultiInt(java.lang.String, android.animation.TypeConverter<V, int[]>, android.animation.TypeEvaluator<V>, V...);
    ++    method public static <T> android.animation.PropertyValuesHolder ofMultiInt(java.lang.String, android.animation.TypeConverter<T, int[]>, android.animation.TypeEvaluator<T>, android.animation.Keyframe...);
    +     method public static android.animation.PropertyValuesHolder ofObject(java.lang.String, android.animation.TypeEvaluator, java.lang.Object...);
    +     method public static android.animation.PropertyValuesHolder ofObject(java.lang.String, android.animation.TypeConverter<android.graphics.PointF, ?>, android.graphics.Path);
    +-    method public static android.animation.PropertyValuesHolder ofObject(android.util.Property, android.animation.TypeEvaluator<V>, V...);
    +-    method public static android.animation.PropertyValuesHolder ofObject(android.util.Property<?, V>, android.animation.TypeConverter<T, V>, android.animation.TypeEvaluator<T>, T...);
    +-    method public static android.animation.PropertyValuesHolder ofObject(android.util.Property<?, V>, android.animation.TypeConverter<android.graphics.PointF, V>, android.graphics.Path);
    ++    method public static <V> android.animation.PropertyValuesHolder ofObject(android.util.Property, android.animation.TypeEvaluator<V>, V...);
    ++    method public static <T, V> android.animation.PropertyValuesHolder ofObject(android.util.Property<?, V>, android.animation.TypeConverter<T, V>, android.animation.TypeEvaluator<T>, T...);
    ++    method public static <V> android.animation.PropertyValuesHolder ofObject(android.util.Property<?, V>, android.animation.TypeConverter<android.graphics.PointF, V>, android.graphics.Path);
    +     method public void setConverter(android.animation.TypeConverter);
    +     method public void setEvaluator(android.animation.TypeEvaluator);
    +     method public void setFloatValues(float...);
    +@@ -3363,12 +3363,12 @@ package android.animation {
    +     method public abstract float getInterpolation(float);
    +   }
    + 
    +-  public abstract class TypeConverter {
    ++  public abstract class TypeConverter<T, V> {
    +     ctor public TypeConverter(java.lang.Class<T>, java.lang.Class<V>);
    +     method public abstract V convert(T);
    +   }
    + 
    +-  public abstract interface TypeEvaluator {
    ++  public abstract interface TypeEvaluator<T> {
    +     method public abstract T evaluate(float, T, T);
    +   }
    + 
    +@@ -4726,7 +4726,7 @@ package android.app {
    +     method public android.os.Parcelable saveAllState();
    +   }
    + 
    +-  public abstract class FragmentHostCallback extends android.app.FragmentContainer {
    ++  public abstract class FragmentHostCallback<E> extends android.app.FragmentContainer {
    +     ctor public FragmentHostCallback(android.content.Context, android.os.Handler, int);
    +     method public void onAttachFragment(android.app.Fragment);
    +     method public void onDump(java.lang.String, java.io.FileDescriptor, java.io.PrintWriter, java.lang.String[]);
    +@@ -4993,12 +4993,12 @@ package android.app {
    +     method public abstract void destroyLoader(int);
    +     method public abstract void dump(java.lang.String, java.io.FileDescriptor, java.io.PrintWriter, java.lang.String[]);
    +     method public static void enableDebugLogging(boolean);
    +-    method public abstract android.content.Loader<D> getLoader(int);
    +-    method public abstract android.content.Loader<D> initLoader(int, android.os.Bundle, android.app.LoaderManager.LoaderCallbacks<D>);
    +-    method public abstract android.content.Loader<D> restartLoader(int, android.os.Bundle, android.app.LoaderManager.LoaderCallbacks<D>);
    ++    method public abstract <D> android.content.Loader<D> getLoader(int);
    ++    method public abstract <D> android.content.Loader<D> initLoader(int, android.os.Bundle, android.app.LoaderManager.LoaderCallbacks<D>);
    ++    method public abstract <D> android.content.Loader<D> restartLoader(int, android.os.Bundle, android.app.LoaderManager.LoaderCallbacks<D>);
    +   }
    + 
    +-  public static abstract interface LoaderManager.LoaderCallbacks {
    ++  public static abstract interface LoaderManager.LoaderCallbacks<D> {
    +     method public abstract android.content.Loader<D> onCreateLoader(int, android.os.Bundle);
    +     method public abstract void onLoadFinished(android.content.Loader<D>, D);
    +     method public abstract void onLoaderReset(android.content.Loader<D>);
    +@@ -7952,7 +7952,7 @@ package android.content {
    +     ctor public AsyncQueryHandler.WorkerHandler(android.os.Looper);
    +   }
    + 
    +-  public abstract class AsyncTaskLoader extends android.content.Loader {
    ++  public abstract class AsyncTaskLoader<D> extends android.content.Loader {
    +     ctor public AsyncTaskLoader(android.content.Context);
    +     method public void cancelLoadInBackground();
    +     method public boolean isLoadInBackgroundCanceled();
    +@@ -8134,7 +8134,7 @@ package android.content {
    +     method public android.os.ParcelFileDescriptor openFile(android.net.Uri, java.lang.String) throws java.io.FileNotFoundException;
    +     method public android.os.ParcelFileDescriptor openFile(android.net.Uri, java.lang.String, android.os.CancellationSignal) throws java.io.FileNotFoundException;
    +     method protected final android.os.ParcelFileDescriptor openFileHelper(android.net.Uri, java.lang.String) throws java.io.FileNotFoundException;
    +-    method public android.os.ParcelFileDescriptor openPipeHelper(android.net.Uri, java.lang.String, android.os.Bundle, T, android.content.ContentProvider.PipeDataWriter<T>) throws java.io.FileNotFoundException;
    ++    method public <T> android.os.ParcelFileDescriptor openPipeHelper(android.net.Uri, java.lang.String, android.os.Bundle, T, android.content.ContentProvider.PipeDataWriter<T>) throws java.io.FileNotFoundException;
    +     method public android.content.res.AssetFileDescriptor openTypedAssetFile(android.net.Uri, java.lang.String, android.os.Bundle) throws java.io.FileNotFoundException;
    +     method public android.content.res.AssetFileDescriptor openTypedAssetFile(android.net.Uri, java.lang.String, android.os.Bundle, android.os.CancellationSignal) throws java.io.FileNotFoundException;
    +     method public abstract android.database.Cursor query(android.net.Uri, java.lang.String[], java.lang.String, java.lang.String[], java.lang.String);
    +@@ -8147,7 +8147,7 @@ package android.content {
    +     method public abstract int update(android.net.Uri, android.content.ContentValues, java.lang.String, java.lang.String[]);
    +   }
    + 
    +-  public static abstract interface ContentProvider.PipeDataWriter {
    ++  public static abstract interface ContentProvider.PipeDataWriter<T> {
    +     method public abstract void writeDataToPipe(android.os.ParcelFileDescriptor, android.net.Uri, java.lang.String, android.os.Bundle, T);
    +   }
    + 
    +@@ -8420,7 +8420,7 @@ package android.content {
    +     method public final java.lang.String getString(int);
    +     method public final java.lang.String getString(int, java.lang.Object...);
    +     method public abstract java.lang.Object getSystemService(java.lang.String);
    +-    method public final T getSystemService(java.lang.Class<T>);
    ++    method public final <T> T getSystemService(java.lang.Class<T>);
    +     method public abstract java.lang.String getSystemServiceName(java.lang.Class<?>);
    +     method public final java.lang.CharSequence getText(int);
    +     method public abstract android.content.res.Resources.Theme getTheme();
    +@@ -8789,8 +8789,8 @@ package android.content {
    +     method public long getLongExtra(java.lang.String, long);
    +     method public java.lang.String getPackage();
    +     method public android.os.Parcelable[] getParcelableArrayExtra(java.lang.String);
    +-    method public java.util.ArrayList<T> getParcelableArrayListExtra(java.lang.String);
    +-    method public T getParcelableExtra(java.lang.String);
    ++    method public <T extends android.os.Parcelable> java.util.ArrayList<T> getParcelableArrayListExtra(java.lang.String);
    ++    method public <T extends android.os.Parcelable> T getParcelableExtra(java.lang.String);
    +     method public java.lang.String getScheme();
    +     method public android.content.Intent getSelector();
    +     method public java.io.Serializable getSerializableExtra(java.lang.String);
    +@@ -9277,7 +9277,7 @@ package android.content {
    +     ctor public IntentSender.SendIntentException(java.lang.Exception);
    +   }
    + 
    +-  public class Loader {
    ++  public class Loader<D> {
    +     ctor public Loader(android.content.Context);
    +     method public void abandon();
    +     method public boolean cancelLoad();
    +@@ -9314,11 +9314,11 @@ package android.content {
    +     ctor public Loader.ForceLoadContentObserver();
    +   }
    + 
    +-  public static abstract interface Loader.OnLoadCanceledListener {
    ++  public static abstract interface Loader.OnLoadCanceledListener<D> {
    +     method public abstract void onLoadCanceled(android.content.Loader<D>);
    +   }
    + 
    +-  public static abstract interface Loader.OnLoadCompleteListener {
    ++  public static abstract interface Loader.OnLoadCompleteListener<D> {
    +     method public abstract void onLoadComplete(android.content.Loader<D>, D);
    +   }
    + 
    +@@ -11287,7 +11287,7 @@ package android.database {
    +     method public boolean isNull(int);
    +   }
    + 
    +-  public abstract class Observable {
    ++  public abstract class Observable<T> {
    +     ctor public Observable();
    +     method public void registerObserver(T);
    +     method public void unregisterAll();
    +@@ -13177,7 +13177,7 @@ package android.graphics.drawable {
    +   public class AnimatedStateListDrawable extends android.graphics.drawable.StateListDrawable {
    +     ctor public AnimatedStateListDrawable();
    +     method public void addState(int[], android.graphics.drawable.Drawable, int);
    +-    method public void addTransition(int, int, T, boolean);
    ++    method public <T extends android.graphics.drawable.Drawable & android.graphics.drawable.Animatable> void addTransition(int, int, T, boolean);
    +   }
    + 
    +   public class AnimatedVectorDrawable extends android.graphics.drawable.Drawable implements android.graphics.drawable.Animatable2 {
    +@@ -14309,7 +14309,7 @@ package android.hardware.camera2 {
    +   }
    + 
    +   public final class CameraCharacteristics extends android.hardware.camera2.CameraMetadata {
    +-    method public T get(android.hardware.camera2.CameraCharacteristics.Key<T>);
    ++    method public <T> T get(android.hardware.camera2.CameraCharacteristics.Key<T>);
    +     method public java.util.List<android.hardware.camera2.CaptureRequest.Key<?>> getAvailableCaptureRequestKeys();
    +     method public java.util.List<android.hardware.camera2.CaptureResult.Key<?>> getAvailableCaptureResultKeys();
    +     field public static final android.hardware.camera2.CameraCharacteristics.Key<int[]> COLOR_CORRECTION_AVAILABLE_ABERRATION_MODES;
    +@@ -14394,7 +14394,7 @@ package android.hardware.camera2 {
    +     field public static final android.hardware.camera2.CameraCharacteristics.Key<java.lang.Integer> TONEMAP_MAX_CURVE_POINTS;
    +   }
    + 
    +-  public static final class CameraCharacteristics.Key {
    ++  public static final class CameraCharacteristics.Key<T> {
    +     method public final boolean equals(java.lang.Object);
    +     method public java.lang.String getName();
    +     method public final int hashCode();
    +@@ -14459,7 +14459,7 @@ package android.hardware.camera2 {
    +     method public void onTorchModeUnavailable(java.lang.String);
    +   }
    + 
    +-  public abstract class CameraMetadata {
    ++  public abstract class CameraMetadata<TKey> {
    +     method public java.util.List<TKey> getKeys();
    +     field public static final int COLOR_CORRECTION_ABERRATION_MODE_FAST = 1; // 0x1
    +     field public static final int COLOR_CORRECTION_ABERRATION_MODE_HIGH_QUALITY = 2; // 0x2
    +@@ -14667,7 +14667,7 @@ package android.hardware.camera2 {
    + 
    +   public final class CaptureRequest extends android.hardware.camera2.CameraMetadata implements android.os.Parcelable {
    +     method public int describeContents();
    +-    method public T get(android.hardware.camera2.CaptureRequest.Key<T>);
    ++    method public <T> T get(android.hardware.camera2.CaptureRequest.Key<T>);
    +     method public java.lang.Object getTag();
    +     method public boolean isReprocess();
    +     method public void writeToParcel(android.os.Parcel, int);
    +@@ -14730,20 +14730,20 @@ package android.hardware.camera2 {
    +   public static final class CaptureRequest.Builder {
    +     method public void addTarget(android.view.Surface);
    +     method public android.hardware.camera2.CaptureRequest build();
    +-    method public T get(android.hardware.camera2.CaptureRequest.Key<T>);
    ++    method public <T> T get(android.hardware.camera2.CaptureRequest.Key<T>);
    +     method public void removeTarget(android.view.Surface);
    +-    method public void set(android.hardware.camera2.CaptureRequest.Key<T>, T);
    ++    method public <T> void set(android.hardware.camera2.CaptureRequest.Key<T>, T);
    +     method public void setTag(java.lang.Object);
    +   }
    + 
    +-  public static final class CaptureRequest.Key {
    ++  public static final class CaptureRequest.Key<T> {
    +     method public final boolean equals(java.lang.Object);
    +     method public java.lang.String getName();
    +     method public final int hashCode();
    +   }
    + 
    +   public class CaptureResult extends android.hardware.camera2.CameraMetadata {
    +-    method public T get(android.hardware.camera2.CaptureResult.Key<T>);
    ++    method public <T> T get(android.hardware.camera2.CaptureResult.Key<T>);
    +     method public long getFrameNumber();
    +     method public android.hardware.camera2.CaptureRequest getRequest();
    +     method public int getSequenceId();
    +@@ -14824,7 +14824,7 @@ package android.hardware.camera2 {
    +     field public static final android.hardware.camera2.CaptureResult.Key<java.lang.Integer> TONEMAP_PRESET_CURVE;
    +   }
    + 
    +-  public static final class CaptureResult.Key {
    ++  public static final class CaptureResult.Key<T> {
    +     method public final boolean equals(java.lang.Object);
    +     method public java.lang.String getName();
    +     method public final int hashCode();
    +@@ -14956,14 +14956,14 @@ package android.hardware.camera2.params {
    +     method public android.util.Size[] getInputSizes(int);
    +     method public final int[] getOutputFormats();
    +     method public long getOutputMinFrameDuration(int, android.util.Size);
    +-    method public long getOutputMinFrameDuration(java.lang.Class<T>, android.util.Size);
    +-    method public android.util.Size[] getOutputSizes(java.lang.Class<T>);
    ++    method public <T> long getOutputMinFrameDuration(java.lang.Class<T>, android.util.Size);
    ++    method public <T> android.util.Size[] getOutputSizes(java.lang.Class<T>);
    +     method public android.util.Size[] getOutputSizes(int);
    +     method public long getOutputStallDuration(int, android.util.Size);
    +-    method public long getOutputStallDuration(java.lang.Class<T>, android.util.Size);
    ++    method public <T> long getOutputStallDuration(java.lang.Class<T>, android.util.Size);
    +     method public final int[] getValidOutputFormatsForInput(int);
    +     method public boolean isOutputSupportedFor(int);
    +-    method public static boolean isOutputSupportedFor(java.lang.Class<T>);
    ++    method public static <T> boolean isOutputSupportedFor(java.lang.Class<T>);
    +     method public boolean isOutputSupportedFor(android.view.Surface);
    +   }
    + 
    +@@ -17411,7 +17411,7 @@ package android.icu.math {
    + 
    + package android.icu.text {
    + 
    +-  public final class AlphabeticIndex implements java.lang.Iterable {
    ++  public final class AlphabeticIndex<V> implements java.lang.Iterable {
    +     ctor public AlphabeticIndex(android.icu.util.ULocale);
    +     ctor public AlphabeticIndex(java.util.Locale);
    +     ctor public AlphabeticIndex(android.icu.text.RuleBasedCollator);
    +@@ -17437,7 +17437,7 @@ package android.icu.text {
    +     method public android.icu.text.AlphabeticIndex<V> setUnderflowLabel(java.lang.String);
    +   }
    + 
    +-  public static class AlphabeticIndex.Bucket implements java.lang.Iterable {
    ++  public static class AlphabeticIndex.Bucket<V> implements java.lang.Iterable {
    +     method public java.lang.String getLabel();
    +     method public android.icu.text.AlphabeticIndex.Bucket.LabelType getLabelType();
    +     method public java.util.Iterator<android.icu.text.AlphabeticIndex.Record<V>> iterator();
    +@@ -17453,14 +17453,14 @@ package android.icu.text {
    +     enum_constant public static final android.icu.text.AlphabeticIndex.Bucket.LabelType UNDERFLOW;
    +   }
    + 
    +-  public static final class AlphabeticIndex.ImmutableIndex implements java.lang.Iterable {
    ++  public static final class AlphabeticIndex.ImmutableIndex<V> implements java.lang.Iterable {
    +     method public android.icu.text.AlphabeticIndex.Bucket<V> getBucket(int);
    +     method public int getBucketCount();
    +     method public int getBucketIndex(java.lang.CharSequence);
    +     method public java.util.Iterator<android.icu.text.AlphabeticIndex.Bucket<V>> iterator();
    +   }
    + 
    +-  public static class AlphabeticIndex.Record {
    ++  public static class AlphabeticIndex.Record<V> {
    +     method public V getData();
    +     method public java.lang.CharSequence getName();
    +   }
    +@@ -18973,8 +18973,8 @@ package android.icu.text {
    +     method public final android.icu.text.UnicodeSet addAll(java.lang.CharSequence);
    +     method public android.icu.text.UnicodeSet addAll(android.icu.text.UnicodeSet);
    +     method public android.icu.text.UnicodeSet addAll(java.lang.Iterable<?>);
    +-    method public android.icu.text.UnicodeSet addAll(T...);
    +-    method public T addAllTo(T);
    ++    method public <T extends java.lang.CharSequence> android.icu.text.UnicodeSet addAll(T...);
    ++    method public <T extends java.util.Collection<java.lang.String>> T addAllTo(T);
    +     method public void addMatchSetTo(android.icu.text.UnicodeSet);
    +     method public android.icu.text.UnicodeSet applyIntPropertyValue(int, int);
    +     method public final android.icu.text.UnicodeSet applyPattern(java.lang.String);
    +@@ -19002,15 +19002,15 @@ package android.icu.text {
    +     method public final boolean contains(java.lang.CharSequence);
    +     method public boolean containsAll(android.icu.text.UnicodeSet);
    +     method public boolean containsAll(java.lang.String);
    +-    method public boolean containsAll(java.lang.Iterable<T>);
    ++    method public <T extends java.lang.CharSequence> boolean containsAll(java.lang.Iterable<T>);
    +     method public boolean containsNone(int, int);
    +     method public boolean containsNone(android.icu.text.UnicodeSet);
    +     method public boolean containsNone(java.lang.CharSequence);
    +-    method public boolean containsNone(java.lang.Iterable<T>);
    ++    method public <T extends java.lang.CharSequence> boolean containsNone(java.lang.Iterable<T>);
    +     method public final boolean containsSome(int, int);
    +     method public final boolean containsSome(android.icu.text.UnicodeSet);
    +     method public final boolean containsSome(java.lang.CharSequence);
    +-    method public final boolean containsSome(java.lang.Iterable<T>);
    ++    method public final <T extends java.lang.CharSequence> boolean containsSome(java.lang.Iterable<T>);
    +     method public android.icu.text.UnicodeSet freeze();
    +     method public static android.icu.text.UnicodeSet from(java.lang.CharSequence);
    +     method public static android.icu.text.UnicodeSet fromAll(java.lang.CharSequence);
    +@@ -19028,14 +19028,14 @@ package android.icu.text {
    +     method public final android.icu.text.UnicodeSet remove(java.lang.CharSequence);
    +     method public final android.icu.text.UnicodeSet removeAll(java.lang.CharSequence);
    +     method public android.icu.text.UnicodeSet removeAll(android.icu.text.UnicodeSet);
    +-    method public android.icu.text.UnicodeSet removeAll(java.lang.Iterable<T>);
    ++    method public <T extends java.lang.CharSequence> android.icu.text.UnicodeSet removeAll(java.lang.Iterable<T>);
    +     method public final android.icu.text.UnicodeSet removeAllStrings();
    +     method public android.icu.text.UnicodeSet retain(int, int);
    +     method public final android.icu.text.UnicodeSet retain(int);
    +     method public final android.icu.text.UnicodeSet retain(java.lang.CharSequence);
    +     method public final android.icu.text.UnicodeSet retainAll(java.lang.CharSequence);
    +     method public android.icu.text.UnicodeSet retainAll(android.icu.text.UnicodeSet);
    +-    method public android.icu.text.UnicodeSet retainAll(java.lang.Iterable<T>);
    ++    method public <T extends java.lang.CharSequence> android.icu.text.UnicodeSet retainAll(java.lang.Iterable<T>);
    +     method public android.icu.text.UnicodeSet set(int, int);
    +     method public android.icu.text.UnicodeSet set(android.icu.text.UnicodeSet);
    +     method public int size();
    +@@ -19445,7 +19445,7 @@ package android.icu.util {
    +     method public long getToDate();
    +   }
    + 
    +-  public abstract interface Freezable implements java.lang.Cloneable {
    ++  public abstract interface Freezable<T> implements java.lang.Cloneable {
    +     method public abstract T cloneAsThawed();
    +     method public abstract T freeze();
    +     method public abstract boolean isFrozen();
    +@@ -19727,7 +19727,7 @@ package android.icu.util {
    +     field public static final android.icu.util.TimeUnit YEAR;
    +   }
    + 
    +-  public class Output {
    ++  public class Output<T> {
    +     ctor public Output();
    +     ctor public Output(T);
    +     field public T value;
    +@@ -30658,7 +30658,7 @@ package android.opengl {
    + 
    + package android.os {
    + 
    +-  public abstract class AsyncTask {
    ++  public abstract class AsyncTask<Params, Progress, Result> {
    +     ctor public AsyncTask();
    +     method public final boolean cancel(boolean);
    +     method protected abstract Result doInBackground(Params...);
    +@@ -30886,16 +30886,16 @@ package android.os {
    +     method public float getFloat(java.lang.String, float);
    +     method public float[] getFloatArray(java.lang.String);
    +     method public java.util.ArrayList<java.lang.Integer> getIntegerArrayList(java.lang.String);
    +-    method public T getParcelable(java.lang.String);
    ++    method public <T extends android.os.Parcelable> T getParcelable(java.lang.String);
    +     method public android.os.Parcelable[] getParcelableArray(java.lang.String);
    +-    method public java.util.ArrayList<T> getParcelableArrayList(java.lang.String);
    ++    method public <T extends android.os.Parcelable> java.util.ArrayList<T> getParcelableArrayList(java.lang.String);
    +     method public java.io.Serializable getSerializable(java.lang.String);
    +     method public short getShort(java.lang.String);
    +     method public short getShort(java.lang.String, short);
    +     method public short[] getShortArray(java.lang.String);
    +     method public android.util.Size getSize(java.lang.String);
    +     method public android.util.SizeF getSizeF(java.lang.String);
    +-    method public android.util.SparseArray<T> getSparseParcelableArray(java.lang.String);
    ++    method public <T extends android.os.Parcelable> android.util.SparseArray<T> getSparseParcelableArray(java.lang.String);
    +     method public java.util.ArrayList<java.lang.String> getStringArrayList(java.lang.String);
    +     method public boolean hasFileDescriptors();
    +     method public void putAll(android.os.Bundle);
    +@@ -31400,8 +31400,8 @@ package android.os {
    +     method public final long[] createLongArray();
    +     method public final java.lang.String[] createStringArray();
    +     method public final java.util.ArrayList<java.lang.String> createStringArrayList();
    +-    method public final T[] createTypedArray(android.os.Parcelable.Creator<T>);
    +-    method public final java.util.ArrayList<T> createTypedArrayList(android.os.Parcelable.Creator<T>);
    ++    method public final <T> T[] createTypedArray(android.os.Parcelable.Creator<T>);
    ++    method public final <T> java.util.ArrayList<T> createTypedArrayList(android.os.Parcelable.Creator<T>);
    +     method public final int dataAvail();
    +     method public final int dataCapacity();
    +     method public final int dataPosition();
    +@@ -31434,7 +31434,7 @@ package android.os {
    +     method public final long readLong();
    +     method public final void readLongArray(long[]);
    +     method public final void readMap(java.util.Map, java.lang.ClassLoader);
    +-    method public final T readParcelable(java.lang.ClassLoader);
    ++    method public final <T extends android.os.Parcelable> T readParcelable(java.lang.ClassLoader);
    +     method public final android.os.Parcelable[] readParcelableArray(java.lang.ClassLoader);
    +     method public final android.os.PersistableBundle readPersistableBundle();
    +     method public final android.os.PersistableBundle readPersistableBundle(java.lang.ClassLoader);
    +@@ -31447,9 +31447,9 @@ package android.os {
    +     method public final void readStringArray(java.lang.String[]);
    +     method public final void readStringList(java.util.List<java.lang.String>);
    +     method public final android.os.IBinder readStrongBinder();
    +-    method public final void readTypedArray(T[], android.os.Parcelable.Creator<T>);
    +-    method public final void readTypedList(java.util.List<T>, android.os.Parcelable.Creator<T>);
    +-    method public final T readTypedObject(android.os.Parcelable.Creator<T>);
    ++    method public final <T> void readTypedArray(T[], android.os.Parcelable.Creator<T>);
    ++    method public final <T> void readTypedList(java.util.List<T>, android.os.Parcelable.Creator<T>);
    ++    method public final <T> T readTypedObject(android.os.Parcelable.Creator<T>);
    +     method public final java.lang.Object readValue(java.lang.ClassLoader);
    +     method public final void recycle();
    +     method public final void setDataCapacity(int);
    +@@ -31480,7 +31480,7 @@ package android.os {
    +     method public final void writeMap(java.util.Map);
    +     method public final void writeNoException();
    +     method public final void writeParcelable(android.os.Parcelable, int);
    +-    method public final void writeParcelableArray(T[], int);
    ++    method public final <T extends android.os.Parcelable> void writeParcelableArray(T[], int);
    +     method public final void writePersistableBundle(android.os.PersistableBundle);
    +     method public final void writeSerializable(java.io.Serializable);
    +     method public final void writeSize(android.util.Size);
    +@@ -31492,9 +31492,9 @@ package android.os {
    +     method public final void writeStringList(java.util.List<java.lang.String>);
    +     method public final void writeStrongBinder(android.os.IBinder);
    +     method public final void writeStrongInterface(android.os.IInterface);
    +-    method public final void writeTypedArray(T[], int);
    +-    method public final void writeTypedList(java.util.List<T>);
    +-    method public final void writeTypedObject(T, int);
    ++    method public final <T extends android.os.Parcelable> void writeTypedArray(T[], int);
    ++    method public final <T extends android.os.Parcelable> void writeTypedList(java.util.List<T>);
    ++    method public final <T extends android.os.Parcelable> void writeTypedObject(T, int);
    +     method public final void writeValue(java.lang.Object);
    +     field public static final android.os.Parcelable.Creator<java.lang.String> STRING_CREATOR;
    +   }
    +@@ -31572,11 +31572,11 @@ package android.os {
    +     field public static final int PARCELABLE_WRITE_RETURN_VALUE = 1; // 0x1
    +   }
    + 
    +-  public static abstract interface Parcelable.ClassLoaderCreator implements android.os.Parcelable.Creator {
    ++  public static abstract interface Parcelable.ClassLoaderCreator<T> implements android.os.Parcelable.Creator {
    +     method public abstract T createFromParcel(android.os.Parcel, java.lang.ClassLoader);
    +   }
    + 
    +-  public static abstract interface Parcelable.Creator {
    ++  public static abstract interface Parcelable.Creator<T> {
    +     method public abstract T createFromParcel(android.os.Parcel);
    +     method public abstract T[] newArray(int);
    +   }
    +@@ -31718,7 +31718,7 @@ package android.os {
    +     method public abstract void onResult(android.os.Bundle);
    +   }
    + 
    +-  public class RemoteCallbackList {
    ++  public class RemoteCallbackList<E extends android.os.IInterface> {
    +     ctor public RemoteCallbackList();
    +     method public int beginBroadcast();
    +     method public void finishBroadcast();
    +@@ -35238,7 +35238,7 @@ package android.provider {
    +     field public static final java.lang.String RADIO_CELL = "cell";
    +     field public static final java.lang.String RADIO_NFC = "nfc";
    +     field public static final java.lang.String RADIO_WIFI = "wifi";
    +-    field public static final java.lang.String SHOW_PROCESSES = "show_processes";
    ++    field public static final deprecated java.lang.String SHOW_PROCESSES = "show_processes";
    +     field public static final java.lang.String STAY_ON_WHILE_PLUGGED_IN = "stay_on_while_plugged_in";
    +     field public static final java.lang.String THEATER_MODE_ON = "theater_mode_on";
    +     field public static final java.lang.String TRANSITION_ANIMATION_SCALE = "transition_animation_scale";
    +@@ -37278,7 +37278,7 @@ package android.service.carrier {
    +     field public static final java.lang.String SERVICE_INTERFACE = "android.service.carrier.CarrierMessagingService";
    +   }
    + 
    +-  public static abstract interface CarrierMessagingService.ResultCallback {
    ++  public static abstract interface CarrierMessagingService.ResultCallback<T> {
    +     method public abstract void onReceiveResult(T) throws android.os.RemoteException;
    +   }
    + 
    +@@ -37429,7 +37429,7 @@ package android.service.media {
    +     field public static final java.lang.String EXTRA_SUGGESTED = "android.service.media.extra.SUGGESTED";
    +   }
    + 
    +-  public class MediaBrowserService.Result {
    ++  public class MediaBrowserService.Result<T> {
    +     method public void detach();
    +     method public void sendResult(T);
    +   }
    +@@ -40749,14 +40749,14 @@ package android.telephony.gsm {
    + 
    + package android.test {
    + 
    +-  public abstract deprecated class ActivityInstrumentationTestCase extends android.test.ActivityTestCase {
    ++  public abstract deprecated class ActivityInstrumentationTestCase<T extends android.app.Activity> extends android.test.ActivityTestCase {
    +     ctor public ActivityInstrumentationTestCase(java.lang.String, java.lang.Class<T>);
    +     ctor public ActivityInstrumentationTestCase(java.lang.String, java.lang.Class<T>, boolean);
    +     method public T getActivity();
    +     method public void testActivityTestCaseSetUpProperly() throws java.lang.Exception;
    +   }
    + 
    +-  public abstract deprecated class ActivityInstrumentationTestCase2 extends android.test.ActivityTestCase {
    ++  public abstract deprecated class ActivityInstrumentationTestCase2<T extends android.app.Activity> extends android.test.ActivityTestCase {
    +     ctor public deprecated ActivityInstrumentationTestCase2(java.lang.String, java.lang.Class<T>);
    +     ctor public ActivityInstrumentationTestCase2(java.lang.Class<T>);
    +     method public T getActivity();
    +@@ -40771,7 +40771,7 @@ package android.test {
    +     method protected void setActivity(android.app.Activity);
    +   }
    + 
    +-  public abstract deprecated class ActivityUnitTestCase extends android.test.ActivityTestCase {
    ++  public abstract deprecated class ActivityUnitTestCase<T extends android.app.Activity> extends android.test.ActivityTestCase {
    +     ctor public ActivityUnitTestCase(java.lang.Class<T>);
    +     method public T getActivity();
    +     method public int getFinishedActivityRequest();
    +@@ -40817,7 +40817,7 @@ package android.test {
    +     method public void testStarted(java.lang.String);
    +   }
    + 
    +-  public abstract deprecated class ApplicationTestCase extends android.test.AndroidTestCase {
    ++  public abstract deprecated class ApplicationTestCase<T extends android.app.Application> extends android.test.AndroidTestCase {
    +     ctor public ApplicationTestCase(java.lang.Class<T>);
    +     method protected final void createApplication();
    +     method public T getApplication();
    +@@ -40843,8 +40843,8 @@ package android.test {
    +     method public android.app.Instrumentation getInstrumentation();
    +     method public deprecated void injectInsrumentation(android.app.Instrumentation);
    +     method public void injectInstrumentation(android.app.Instrumentation);
    +-    method public final T launchActivity(java.lang.String, java.lang.Class<T>, android.os.Bundle);
    +-    method public final T launchActivityWithIntent(java.lang.String, java.lang.Class<T>, android.content.Intent);
    ++    method public final <T extends android.app.Activity> T launchActivity(java.lang.String, java.lang.Class<T>, android.os.Bundle);
    ++    method public final <T extends android.app.Activity> T launchActivityWithIntent(java.lang.String, java.lang.Class<T>, android.content.Intent);
    +     method public void runTestOnUiThread(java.lang.Runnable) throws java.lang.Throwable;
    +     method public void sendKeys(java.lang.String);
    +     method public void sendKeys(int...);
    +@@ -40884,7 +40884,7 @@ package android.test {
    + 
    +   public class LoaderTestCase extends android.test.AndroidTestCase {
    +     ctor public LoaderTestCase();
    +-    method public T getLoaderResultSynchronously(android.content.Loader<T>);
    ++    method public <T> T getLoaderResultSynchronously(android.content.Loader<T>);
    +   }
    + 
    +   public final deprecated class MoreAsserts {
    +@@ -40939,20 +40939,20 @@ package android.test {
    +     method public abstract void startTiming(boolean);
    +   }
    + 
    +-  public abstract deprecated class ProviderTestCase extends android.test.InstrumentationTestCase {
    ++  public abstract deprecated class ProviderTestCase<T extends android.content.ContentProvider> extends android.test.InstrumentationTestCase {
    +     ctor public ProviderTestCase(java.lang.Class<T>, java.lang.String);
    +     method public android.test.mock.MockContentResolver getMockContentResolver();
    +     method public android.test.IsolatedContext getMockContext();
    +     method public T getProvider();
    +-    method public static android.content.ContentResolver newResolverWithContentProviderFromSql(android.content.Context, java.lang.Class<T>, java.lang.String, java.lang.String, int, java.lang.String) throws java.lang.IllegalAccessException, java.lang.InstantiationException;
    ++    method public static <T extends android.content.ContentProvider> android.content.ContentResolver newResolverWithContentProviderFromSql(android.content.Context, java.lang.Class<T>, java.lang.String, java.lang.String, int, java.lang.String) throws java.lang.IllegalAccessException, java.lang.InstantiationException;
    +   }
    + 
    +-  public abstract class ProviderTestCase2 extends android.test.AndroidTestCase {
    ++  public abstract class ProviderTestCase2<T extends android.content.ContentProvider> extends android.test.AndroidTestCase {
    +     ctor public ProviderTestCase2(java.lang.Class<T>, java.lang.String);
    +     method public android.test.mock.MockContentResolver getMockContentResolver();
    +     method public android.test.IsolatedContext getMockContext();
    +     method public T getProvider();
    +-    method public static android.content.ContentResolver newResolverWithContentProviderFromSql(android.content.Context, java.lang.String, java.lang.Class<T>, java.lang.String, java.lang.String, int, java.lang.String) throws java.lang.IllegalAccessException, java.lang.InstantiationException;
    ++    method public static <T extends android.content.ContentProvider> android.content.ContentResolver newResolverWithContentProviderFromSql(android.content.Context, java.lang.String, java.lang.Class<T>, java.lang.String, java.lang.String, int, java.lang.String) throws java.lang.IllegalAccessException, java.lang.InstantiationException;
    +   }
    + 
    +   public deprecated class RenamingDelegatingContext extends android.content.ContextWrapper {
    +@@ -40960,11 +40960,11 @@ package android.test {
    +     ctor public RenamingDelegatingContext(android.content.Context, android.content.Context, java.lang.String);
    +     method public java.lang.String getDatabasePrefix();
    +     method public void makeExistingFilesAndDbsAccessible();
    +-    method public static T providerWithRenamedContext(java.lang.Class<T>, android.content.Context, java.lang.String) throws java.lang.IllegalAccessException, java.lang.InstantiationException;
    +-    method public static T providerWithRenamedContext(java.lang.Class<T>, android.content.Context, java.lang.String, boolean) throws java.lang.IllegalAccessException, java.lang.InstantiationException;
    ++    method public static <T extends android.content.ContentProvider> T providerWithRenamedContext(java.lang.Class<T>, android.content.Context, java.lang.String) throws java.lang.IllegalAccessException, java.lang.InstantiationException;
    ++    method public static <T extends android.content.ContentProvider> T providerWithRenamedContext(java.lang.Class<T>, android.content.Context, java.lang.String, boolean) throws java.lang.IllegalAccessException, java.lang.InstantiationException;
    +   }
    + 
    +-  public abstract deprecated class ServiceTestCase extends android.test.AndroidTestCase {
    ++  public abstract deprecated class ServiceTestCase<T extends android.app.Service> extends android.test.AndroidTestCase {
    +     ctor public ServiceTestCase(java.lang.Class<T>);
    +     method protected android.os.IBinder bindService(android.content.Intent);
    +     method public android.app.Application getApplication();
    +@@ -40977,7 +40977,7 @@ package android.test {
    +     method public void testServiceTestCaseSetUpProperly() throws java.lang.Exception;
    +   }
    + 
    +-  public abstract deprecated class SingleLaunchActivityTestCase extends android.test.InstrumentationTestCase {
    ++  public abstract deprecated class SingleLaunchActivityTestCase<T extends android.app.Activity> extends android.test.InstrumentationTestCase {
    +     ctor public SingleLaunchActivityTestCase(java.lang.String, java.lang.Class<T>);
    +     method public T getActivity();
    +     method public void testActivityTestCaseSetUpProperly() throws java.lang.Exception;
    +@@ -41344,7 +41344,7 @@ package android.test.suitebuilder {
    +     ctor public TestMethod(java.lang.String, java.lang.Class<? extends junit.framework.TestCase>);
    +     ctor public TestMethod(junit.framework.TestCase);
    +     method public junit.framework.TestCase createTest() throws java.lang.IllegalAccessException, java.lang.InstantiationException, java.lang.reflect.InvocationTargetException;
    +-    method public T getAnnotation(java.lang.Class<T>);
    ++    method public <T extends java.lang.annotation.Annotation> T getAnnotation(java.lang.Class<T>);
    +     method public java.lang.Class<? extends junit.framework.TestCase> getEnclosingClass();
    +     method public java.lang.String getEnclosingClassname();
    +     method public java.lang.String getName();
    +@@ -41787,7 +41787,7 @@ package android.text {
    +     method public int getSpanEnd(java.lang.Object);
    +     method public int getSpanFlags(java.lang.Object);
    +     method public int getSpanStart(java.lang.Object);
    +-    method public T[] getSpans(int, int, java.lang.Class<T>);
    ++    method public <T> T[] getSpans(int, int, java.lang.Class<T>);
    +     method public deprecated int getTextRunCursor(int, int, int, int, int, android.graphics.Paint);
    +     method public int getTextWatcherDepth();
    +     method public android.text.SpannableStringBuilder insert(int, java.lang.CharSequence, int, int);
    +@@ -41809,7 +41809,7 @@ package android.text {
    +     method public int getSpanEnd(java.lang.Object);
    +     method public int getSpanFlags(java.lang.Object);
    +     method public int getSpanStart(java.lang.Object);
    +-    method public T[] getSpans(int, int, java.lang.Class<T>);
    ++    method public <T> T[] getSpans(int, int, java.lang.Class<T>);
    +     method public final int length();
    +     method public int nextSpanTransition(int, int, java.lang.Class);
    +     method public final java.lang.String toString();
    +@@ -41819,7 +41819,7 @@ package android.text {
    +     method public abstract int getSpanEnd(java.lang.Object);
    +     method public abstract int getSpanFlags(java.lang.Object);
    +     method public abstract int getSpanStart(java.lang.Object);
    +-    method public abstract T[] getSpans(int, int, java.lang.Class<T>);
    ++    method public abstract <T> T[] getSpans(int, int, java.lang.Class<T>);
    +     method public abstract int nextSpanTransition(int, int, java.lang.Class);
    +     field public static final int SPAN_COMPOSING = 256; // 0x100
    +     field public static final int SPAN_EXCLUSIVE_EXCLUSIVE = 33; // 0x21
    +@@ -42796,7 +42796,7 @@ package android.text.style {
    +     field public static final int WEEKDAY_WEDNESDAY = 4; // 0x4
    +   }
    + 
    +-  public static class TtsSpan.Builder {
    ++  public static class TtsSpan.Builder<C extends android.text.style.TtsSpan.Builder<?>> {
    +     ctor public TtsSpan.Builder(java.lang.String);
    +     method public android.text.style.TtsSpan build();
    +     method public C setIntArgument(java.lang.String, int);
    +@@ -42892,7 +42892,7 @@ package android.text.style {
    +     method public android.text.style.TtsSpan.OrdinalBuilder setNumber(java.lang.String);
    +   }
    + 
    +-  public static class TtsSpan.SemioticClassBuilder extends android.text.style.TtsSpan.Builder {
    ++  public static class TtsSpan.SemioticClassBuilder<C extends android.text.style.TtsSpan.SemioticClassBuilder<?>> extends android.text.style.TtsSpan.Builder {
    +     ctor public TtsSpan.SemioticClassBuilder(java.lang.String);
    +     method public C setAnimacy(java.lang.String);
    +     method public C setCase(java.lang.String);
    +@@ -43299,7 +43299,7 @@ package android.util {
    +     ctor public AndroidRuntimeException(java.lang.Exception);
    +   }
    + 
    +-  public final class ArrayMap implements java.util.Map {
    ++  public final class ArrayMap<K, V> implements java.util.Map {
    +     ctor public ArrayMap();
    +     ctor public ArrayMap(int);
    +     ctor public ArrayMap(android.util.ArrayMap<K, V>);
    +@@ -43327,7 +43327,7 @@ package android.util {
    +     method public java.util.Collection<V> values();
    +   }
    + 
    +-  public final class ArraySet implements java.util.Collection java.util.Set {
    ++  public final class ArraySet<E> implements java.util.Collection java.util.Set {
    +     ctor public ArraySet();
    +     ctor public ArraySet(int);
    +     ctor public ArraySet(android.util.ArraySet<E>);
    +@@ -43348,7 +43348,7 @@ package android.util {
    +     method public boolean retainAll(java.util.Collection<?>);
    +     method public int size();
    +     method public java.lang.Object[] toArray();
    +-    method public T[] toArray(T[]);
    ++    method public <T> T[] toArray(T[]);
    +     method public E valueAt(int);
    +   }
    + 
    +@@ -43493,13 +43493,13 @@ package android.util {
    +   public deprecated class FloatMath {
    +   }
    + 
    +-  public abstract class FloatProperty extends android.util.Property {
    ++  public abstract class FloatProperty<T> extends android.util.Property {
    +     ctor public FloatProperty(java.lang.String);
    +     method public final void set(T, java.lang.Float);
    +     method public abstract void setValue(T, float);
    +   }
    + 
    +-  public abstract class IntProperty extends android.util.Property {
    ++  public abstract class IntProperty<T> extends android.util.Property {
    +     ctor public IntProperty(java.lang.String);
    +     method public final void set(T, java.lang.Integer);
    +     method public abstract void setValue(T, int);
    +@@ -43599,7 +43599,7 @@ package android.util {
    +     method public void println(java.lang.String);
    +   }
    + 
    +-  public class LongSparseArray implements java.lang.Cloneable {
    ++  public class LongSparseArray<E> implements java.lang.Cloneable {
    +     ctor public LongSparseArray();
    +     ctor public LongSparseArray(int);
    +     method public void append(long, E);
    +@@ -43619,7 +43619,7 @@ package android.util {
    +     method public E valueAt(int);
    +   }
    + 
    +-  public class LruCache {
    ++  public class LruCache<K, V> {
    +     ctor public LruCache(int);
    +     method protected V create(K);
    +     method public final synchronized int createCount();
    +@@ -43707,9 +43707,9 @@ package android.util {
    +     ctor public NoSuchPropertyException(java.lang.String);
    +   }
    + 
    +-  public class Pair {
    ++  public class Pair<F, S> {
    +     ctor public Pair(F, S);
    +-    method public static android.util.Pair<A, B> create(A, B);
    ++    method public static <A, B> android.util.Pair<A, B> create(A, B);
    +     field public final F first;
    +     field public final S second;
    +   }
    +@@ -43742,22 +43742,22 @@ package android.util {
    +     method public abstract void println(java.lang.String);
    +   }
    + 
    +-  public abstract class Property {
    ++  public abstract class Property<T, V> {
    +     ctor public Property(java.lang.Class<V>, java.lang.String);
    +     method public abstract V get(T);
    +     method public java.lang.String getName();
    +     method public java.lang.Class<V> getType();
    +     method public boolean isReadOnly();
    +-    method public static android.util.Property<T, V> of(java.lang.Class<T>, java.lang.Class<V>, java.lang.String);
    ++    method public static <T, V> android.util.Property<T, V> of(java.lang.Class<T>, java.lang.Class<V>, java.lang.String);
    +     method public void set(T, V);
    +   }
    + 
    +-  public final class Range {
    ++  public final class Range<T extends java.lang.Comparable<? super T>> {
    +     ctor public Range(T, T);
    +     method public T clamp(T);
    +     method public boolean contains(T);
    +     method public boolean contains(android.util.Range<T>);
    +-    method public static android.util.Range<T> create(T, T);
    ++    method public static <T extends java.lang.Comparable<? super T>> android.util.Range<T> create(T, T);
    +     method public android.util.Range<T> extend(android.util.Range<T>);
    +     method public android.util.Range<T> extend(T, T);
    +     method public android.util.Range<T> extend(T);
    +@@ -43801,7 +43801,7 @@ package android.util {
    +     method public static android.util.SizeF parseSizeF(java.lang.String) throws java.lang.NumberFormatException;
    +   }
    + 
    +-  public class SparseArray implements java.lang.Cloneable {
    ++  public class SparseArray<E> implements java.lang.Cloneable {
    +     ctor public SparseArray();
    +     ctor public SparseArray(int);
    +     method public void append(int, E);
    +@@ -48606,7 +48606,7 @@ package android.webkit {
    +     method public static java.lang.String stripAnchor(java.lang.String);
    +   }
    + 
    +-  public abstract interface ValueCallback {
    ++  public abstract interface ValueCallback<T> {
    +     method public abstract void onReceiveValue(T);
    +   }
    + 
    +@@ -49621,7 +49621,7 @@ package android.widget {
    +     field public static final int NO_SELECTION = -2147483648; // 0x80000000
    +   }
    + 
    +-  public abstract class AdapterView extends android.view.ViewGroup {
    ++  public abstract class AdapterView<T extends android.widget.Adapter> extends android.view.ViewGroup {
    +     ctor public AdapterView(android.content.Context);
    +     ctor public AdapterView(android.content.Context, android.util.AttributeSet);
    +     ctor public AdapterView(android.content.Context, android.util.AttributeSet, int);
    +@@ -49744,7 +49744,7 @@ package android.widget {
    +     ctor public AnalogClock(android.content.Context, android.util.AttributeSet, int, int);
    +   }
    + 
    +-  public class ArrayAdapter extends android.widget.BaseAdapter implements android.widget.Filterable android.widget.ThemedSpinnerAdapter {
    ++  public class ArrayAdapter<T> extends android.widget.BaseAdapter implements android.widget.Filterable android.widget.ThemedSpinnerAdapter {
    +     ctor public ArrayAdapter(android.content.Context, int);
    +     ctor public ArrayAdapter(android.content.Context, int, int);
    +     ctor public ArrayAdapter(android.content.Context, int, T[]);
    +@@ -49805,7 +49805,7 @@ package android.widget {
    +     method protected void performFiltering(java.lang.CharSequence, int);
    +     method public void performValidation();
    +     method protected void replaceText(java.lang.CharSequence);
    +-    method public void setAdapter(T);
    ++    method public <T extends android.widget.ListAdapter & android.widget.Filterable> void setAdapter(T);
    +     method public void setCompletionHint(java.lang.CharSequence);
    +     method public void setDropDownAnchor(int);
    +     method public void setDropDownBackgroundDrawable(android.graphics.drawable.Drawable);
    +@@ -52090,7 +52090,7 @@ package android.widget {
    + 
    + package com.android.internal.util {
    + 
    +-  public abstract interface Predicate {
    ++  public abstract interface Predicate<T> {
    +     method public abstract boolean apply(T);
    +   }
    + 
    +@@ -54137,13 +54137,13 @@ package java.lang {
    +     enum_constant public static final java.lang.Character.UnicodeScript YI;
    +   }
    + 
    +-  public final class Class implements java.lang.reflect.AnnotatedElement java.lang.reflect.GenericDeclaration java.io.Serializable java.lang.reflect.Type {
    +-    method public java.lang.Class<? extends U> asSubclass(java.lang.Class<U>);
    ++  public final class Class<T> implements java.lang.reflect.AnnotatedElement java.lang.reflect.GenericDeclaration java.io.Serializable java.lang.reflect.Type {
    ++    method public <U> java.lang.Class<? extends U> asSubclass(java.lang.Class<U>);
    +     method public T cast(java.lang.Object);
    +     method public boolean desiredAssertionStatus();
    +     method public static java.lang.Class<?> forName(java.lang.String) throws java.lang.ClassNotFoundException;
    +     method public static java.lang.Class<?> forName(java.lang.String, boolean, java.lang.ClassLoader) throws java.lang.ClassNotFoundException;
    +-    method public A getAnnotation(java.lang.Class<A>);
    ++    method public <A extends java.lang.annotation.Annotation> A getAnnotation(java.lang.Class<A>);
    +     method public java.lang.annotation.Annotation[] getAnnotations();
    +     method public java.lang.String getCanonicalName();
    +     method public java.lang.ClassLoader getClassLoader();
    +@@ -54260,7 +54260,7 @@ package java.lang {
    +   public abstract interface Cloneable {
    +   }
    + 
    +-  public abstract interface Comparable {
    ++  public abstract interface Comparable<T> {
    +     method public abstract int compareTo(T);
    +   }
    + 
    +@@ -54314,7 +54314,7 @@ package java.lang {
    +     field public static final java.lang.Class<java.lang.Double> TYPE;
    +   }
    + 
    +-  public abstract class Enum implements java.lang.Comparable java.io.Serializable {
    ++  public abstract class Enum<E extends java.lang.Enum<E>> implements java.lang.Comparable java.io.Serializable {
    +     ctor protected Enum(java.lang.String, int);
    +     method protected final java.lang.Object clone() throws java.lang.CloneNotSupportedException;
    +     method public final int compareTo(E);
    +@@ -54324,7 +54324,7 @@ package java.lang {
    +     method public final int hashCode();
    +     method public final java.lang.String name();
    +     method public final int ordinal();
    +-    method public static T valueOf(java.lang.Class<T>, java.lang.String);
    ++    method public static <T extends java.lang.Enum<T>> T valueOf(java.lang.Class<T>, java.lang.String);
    +   }
    + 
    +   public class EnumConstantNotPresentException extends java.lang.RuntimeException {
    +@@ -54443,7 +54443,7 @@ package java.lang {
    +     ctor public IndexOutOfBoundsException(java.lang.String);
    +   }
    + 
    +-  public class InheritableThreadLocal extends java.lang.ThreadLocal {
    ++  public class InheritableThreadLocal<T> extends java.lang.ThreadLocal {
    +     ctor public InheritableThreadLocal();
    +     method protected T childValue(T);
    +   }
    +@@ -54514,7 +54514,7 @@ package java.lang {
    +     ctor public InterruptedException(java.lang.String);
    +   }
    + 
    +-  public abstract interface Iterable {
    ++  public abstract interface Iterable<T> {
    +     method public default void forEach(java.util.function.Consumer<? super T>);
    +     method public abstract java.util.Iterator<T> iterator();
    +     method public default java.util.Spliterator<T> spliterator();
    +@@ -54722,12 +54722,12 @@ package java.lang {
    +   }
    + 
    +   public class Package implements java.lang.reflect.AnnotatedElement {
    +-    method public A getAnnotation(java.lang.Class<A>);
    ++    method public <A extends java.lang.annotation.Annotation> A getAnnotation(java.lang.Class<A>);
    +     method public java.lang.annotation.Annotation[] getAnnotations();
    +-    method public A[] getAnnotationsByType(java.lang.Class<A>);
    +-    method public A getDeclaredAnnotation(java.lang.Class<A>);
    ++    method public <A extends java.lang.annotation.Annotation> A[] getAnnotationsByType(java.lang.Class<A>);
    ++    method public <A extends java.lang.annotation.Annotation> A getDeclaredAnnotation(java.lang.Class<A>);
    +     method public java.lang.annotation.Annotation[] getDeclaredAnnotations();
    +-    method public A[] getDeclaredAnnotationsByType(java.lang.Class<A>);
    ++    method public <A extends java.lang.annotation.Annotation> A[] getDeclaredAnnotationsByType(java.lang.Class<A>);
    +     method public java.lang.String getImplementationTitle();
    +     method public java.lang.String getImplementationVendor();
    +     method public java.lang.String getImplementationVersion();
    +@@ -55287,7 +55287,7 @@ package java.lang {
    +     method public void uncaughtException(java.lang.Thread, java.lang.Throwable);
    +   }
    + 
    +-  public class ThreadLocal {
    ++  public class ThreadLocal<T> {
    +     ctor public ThreadLocal();
    +     method public T get();
    +     method protected T initialValue();
    +@@ -55427,30 +55427,30 @@ package java.lang.annotation {
    + 
    + package java.lang.ref {
    + 
    +-  public class PhantomReference extends java.lang.ref.Reference {
    ++  public class PhantomReference<T> extends java.lang.ref.Reference {
    +     ctor public PhantomReference(T, java.lang.ref.ReferenceQueue<? super T>);
    +   }
    + 
    +-  public abstract class Reference {
    ++  public abstract class Reference<T> {
    +     method public void clear();
    +     method public boolean enqueue();
    +     method public T get();
    +     method public boolean isEnqueued();
    +   }
    + 
    +-  public class ReferenceQueue {
    ++  public class ReferenceQueue<T> {
    +     ctor public ReferenceQueue();
    +     method public java.lang.ref.Reference<? extends T> poll();
    +     method public java.lang.ref.Reference<? extends T> remove(long) throws java.lang.IllegalArgumentException, java.lang.InterruptedException;
    +     method public java.lang.ref.Reference<? extends T> remove() throws java.lang.InterruptedException;
    +   }
    + 
    +-  public class SoftReference extends java.lang.ref.Reference {
    ++  public class SoftReference<T> extends java.lang.ref.Reference {
    +     ctor public SoftReference(T);
    +     ctor public SoftReference(T, java.lang.ref.ReferenceQueue<? super T>);
    +   }
    + 
    +-  public class WeakReference extends java.lang.ref.Reference {
    ++  public class WeakReference<T> extends java.lang.ref.Reference {
    +     ctor public WeakReference(T);
    +     ctor public WeakReference(T, java.lang.ref.ReferenceQueue<? super T>);
    +   }
    +@@ -55461,7 +55461,7 @@ package java.lang.reflect {
    + 
    +   public class AccessibleObject implements java.lang.reflect.AnnotatedElement {
    +     ctor protected AccessibleObject();
    +-    method public T getAnnotation(java.lang.Class<T>);
    ++    method public <T extends java.lang.annotation.Annotation> T getAnnotation(java.lang.Class<T>);
    +     method public java.lang.annotation.Annotation[] getAnnotations();
    +     method public java.lang.annotation.Annotation[] getDeclaredAnnotations();
    +     method public boolean isAccessible();
    +@@ -55470,12 +55470,12 @@ package java.lang.reflect {
    +   }
    + 
    +   public abstract interface AnnotatedElement {
    +-    method public abstract T getAnnotation(java.lang.Class<T>);
    ++    method public abstract <T extends java.lang.annotation.Annotation> T getAnnotation(java.lang.Class<T>);
    +     method public abstract java.lang.annotation.Annotation[] getAnnotations();
    +-    method public default T[] getAnnotationsByType(java.lang.Class<T>);
    +-    method public default java.lang.annotation.Annotation getDeclaredAnnotation(java.lang.Class<T>);
    ++    method public default <T extends java.lang.annotation.Annotation> T[] getAnnotationsByType(java.lang.Class<T>);
    ++    method public default <T extends java.lang.annotation.Annotation> java.lang.annotation.Annotation getDeclaredAnnotation(java.lang.Class<T>);
    +     method public abstract java.lang.annotation.Annotation[] getDeclaredAnnotations();
    +-    method public default T[] getDeclaredAnnotationsByType(java.lang.Class<T>);
    ++    method public default <T extends java.lang.annotation.Annotation> T[] getDeclaredAnnotationsByType(java.lang.Class<T>);
    +     method public default boolean isAnnotationPresent(java.lang.Class<? extends java.lang.annotation.Annotation>);
    +   }
    + 
    +@@ -55503,8 +55503,8 @@ package java.lang.reflect {
    +     method public static void setShort(java.lang.Object, int, short) throws java.lang.ArrayIndexOutOfBoundsException, java.lang.IllegalArgumentException;
    +   }
    + 
    +-  public final class Constructor extends java.lang.reflect.AccessibleObject implements java.lang.reflect.GenericDeclaration java.lang.reflect.Member {
    +-    method public A getAnnotation(java.lang.Class<A>);
    ++  public final class Constructor<T> extends java.lang.reflect.AccessibleObject implements java.lang.reflect.GenericDeclaration java.lang.reflect.Member {
    ++    method public <A extends java.lang.annotation.Annotation> A getAnnotation(java.lang.Class<A>);
    +     method public java.lang.Class<T> getDeclaringClass();
    +     method public java.lang.Class<?>[] getExceptionTypes();
    +     method public java.lang.reflect.Type[] getGenericExceptionTypes();
    +@@ -55523,7 +55523,7 @@ package java.lang.reflect {
    + 
    +   public final class Field extends java.lang.reflect.AccessibleObject implements java.lang.reflect.Member {
    +     method public java.lang.Object get(java.lang.Object) throws java.lang.IllegalAccessException, java.lang.IllegalArgumentException;
    +-    method public A getAnnotation(java.lang.Class<A>);
    ++    method public <A extends java.lang.annotation.Annotation> A getAnnotation(java.lang.Class<A>);
    +     method public boolean getBoolean(java.lang.Object) throws java.lang.IllegalAccessException, java.lang.IllegalArgumentException;
    +     method public byte getByte(java.lang.Object) throws java.lang.IllegalAccessException, java.lang.IllegalArgumentException;
    +     method public char getChar(java.lang.Object) throws java.lang.IllegalAccessException, java.lang.IllegalArgumentException;
    +@@ -55589,7 +55589,7 @@ package java.lang.reflect {
    +   }
    + 
    +   public final class Method extends java.lang.reflect.AccessibleObject implements java.lang.reflect.GenericDeclaration java.lang.reflect.Member {
    +-    method public A getAnnotation(java.lang.Class<A>);
    ++    method public <A extends java.lang.annotation.Annotation> A getAnnotation(java.lang.Class<A>);
    +     method public java.lang.Class<?> getDeclaringClass();
    +     method public java.lang.Object getDefaultValue();
    +     method public java.lang.Class<?>[] getExceptionTypes();
    +@@ -55667,7 +55667,7 @@ package java.lang.reflect {
    +   public abstract interface Type {
    +   }
    + 
    +-  public abstract interface TypeVariable implements java.lang.reflect.Type {
    ++  public abstract interface TypeVariable<D extends java.lang.reflect.GenericDeclaration> implements java.lang.reflect.Type {
    +     method public abstract java.lang.reflect.Type[] getBounds();
    +     method public abstract D getGenericDeclaration();
    +     method public abstract java.lang.String getName();
    +@@ -56456,7 +56456,7 @@ package java.net {
    +     method public abstract java.net.SocketImpl createSocketImpl();
    +   }
    + 
    +-  public abstract interface SocketOption {
    ++  public abstract interface SocketOption<T> {
    +     method public abstract java.lang.String name();
    +     method public abstract java.lang.Class<T> type();
    +   }
    +@@ -57040,7 +57040,7 @@ package java.nio.channels {
    +     method public final long read(java.nio.ByteBuffer[]) throws java.io.IOException;
    +     method public abstract java.net.SocketAddress receive(java.nio.ByteBuffer) throws java.io.IOException;
    +     method public abstract int send(java.nio.ByteBuffer, java.net.SocketAddress) throws java.io.IOException;
    +-    method public abstract java.nio.channels.DatagramChannel setOption(java.net.SocketOption<T>, T) throws java.io.IOException;
    ++    method public abstract <T> java.nio.channels.DatagramChannel setOption(java.net.SocketOption<T>, T) throws java.io.IOException;
    +     method public abstract java.net.DatagramSocket socket();
    +     method public final int validOps();
    +     method public abstract int write(java.nio.ByteBuffer) throws java.io.IOException;
    +@@ -57116,8 +57116,8 @@ package java.nio.channels {
    +   public abstract interface NetworkChannel implements java.nio.channels.Channel {
    +     method public abstract java.nio.channels.NetworkChannel bind(java.net.SocketAddress) throws java.io.IOException;
    +     method public abstract java.net.SocketAddress getLocalAddress() throws java.io.IOException;
    +-    method public abstract T getOption(java.net.SocketOption<T>) throws java.io.IOException;
    +-    method public abstract java.nio.channels.NetworkChannel setOption(java.net.SocketOption<T>, T) throws java.io.IOException;
    ++    method public abstract <T> T getOption(java.net.SocketOption<T>) throws java.io.IOException;
    ++    method public abstract <T> java.nio.channels.NetworkChannel setOption(java.net.SocketOption<T>, T) throws java.io.IOException;
    +     method public abstract java.util.Set<java.net.SocketOption<?>> supportedOptions();
    +   }
    + 
    +@@ -57234,7 +57234,7 @@ package java.nio.channels {
    +     method public final java.nio.channels.ServerSocketChannel bind(java.net.SocketAddress) throws java.io.IOException;
    +     method public abstract java.nio.channels.ServerSocketChannel bind(java.net.SocketAddress, int) throws java.io.IOException;
    +     method public static java.nio.channels.ServerSocketChannel open() throws java.io.IOException;
    +-    method public abstract java.nio.channels.ServerSocketChannel setOption(java.net.SocketOption<T>, T) throws java.io.IOException;
    ++    method public abstract <T> java.nio.channels.ServerSocketChannel setOption(java.net.SocketOption<T>, T) throws java.io.IOException;
    +     method public abstract java.net.ServerSocket socket();
    +     method public final int validOps();
    +   }
    +@@ -57252,7 +57252,7 @@ package java.nio.channels {
    +     method public abstract int read(java.nio.ByteBuffer) throws java.io.IOException;
    +     method public abstract long read(java.nio.ByteBuffer[], int, int) throws java.io.IOException;
    +     method public final long read(java.nio.ByteBuffer[]) throws java.io.IOException;
    +-    method public abstract java.nio.channels.SocketChannel setOption(java.net.SocketOption<T>, T) throws java.io.IOException;
    ++    method public abstract <T> java.nio.channels.SocketChannel setOption(java.net.SocketOption<T>, T) throws java.io.IOException;
    +     method public abstract java.nio.channels.SocketChannel shutdownInput() throws java.io.IOException;
    +     method public abstract java.nio.channels.SocketChannel shutdownOutput() throws java.io.IOException;
    +     method public abstract java.net.Socket socket();
    +@@ -57499,12 +57499,12 @@ package java.security {
    + 
    +   public final class AccessController {
    +     method public static void checkPermission(java.security.Permission) throws java.security.AccessControlException;
    +-    method public static T doPrivileged(java.security.PrivilegedAction<T>);
    +-    method public static T doPrivileged(java.security.PrivilegedAction<T>, java.security.AccessControlContext);
    +-    method public static T doPrivileged(java.security.PrivilegedExceptionAction<T>) throws java.security.PrivilegedActionException;
    +-    method public static T doPrivileged(java.security.PrivilegedExceptionAction<T>, java.security.AccessControlContext) throws java.security.PrivilegedActionException;
    +-    method public static T doPrivilegedWithCombiner(java.security.PrivilegedAction<T>);
    +-    method public static T doPrivilegedWithCombiner(java.security.PrivilegedExceptionAction<T>) throws java.security.PrivilegedActionException;
    ++    method public static <T> T doPrivileged(java.security.PrivilegedAction<T>);
    ++    method public static <T> T doPrivileged(java.security.PrivilegedAction<T>, java.security.AccessControlContext);
    ++    method public static <T> T doPrivileged(java.security.PrivilegedExceptionAction<T>) throws java.security.PrivilegedActionException;
    ++    method public static <T> T doPrivileged(java.security.PrivilegedExceptionAction<T>, java.security.AccessControlContext) throws java.security.PrivilegedActionException;
    ++    method public static <T> T doPrivilegedWithCombiner(java.security.PrivilegedAction<T>);
    ++    method public static <T> T doPrivilegedWithCombiner(java.security.PrivilegedExceptionAction<T>) throws java.security.PrivilegedActionException;
    +     method public static java.security.AccessControlContext getContext();
    +   }
    + 
    +@@ -57543,7 +57543,7 @@ package java.security {
    +     method public static java.security.AlgorithmParameters getInstance(java.lang.String) throws java.security.NoSuchAlgorithmException;
    +     method public static java.security.AlgorithmParameters getInstance(java.lang.String, java.lang.String) throws java.security.NoSuchAlgorithmException, java.security.NoSuchProviderException;
    +     method public static java.security.AlgorithmParameters getInstance(java.lang.String, java.security.Provider) throws java.security.NoSuchAlgorithmException;
    +-    method public final T getParameterSpec(java.lang.Class<T>) throws java.security.spec.InvalidParameterSpecException;
    ++    method public final <T extends java.security.spec.AlgorithmParameterSpec> T getParameterSpec(java.lang.Class<T>) throws java.security.spec.InvalidParameterSpecException;
    +     method public final java.security.Provider getProvider();
    +     method public final void init(java.security.spec.AlgorithmParameterSpec) throws java.security.spec.InvalidParameterSpecException;
    +     method public final void init(byte[]) throws java.io.IOException;
    +@@ -57555,7 +57555,7 @@ package java.security {
    +     ctor public AlgorithmParametersSpi();
    +     method protected abstract byte[] engineGetEncoded() throws java.io.IOException;
    +     method protected abstract byte[] engineGetEncoded(java.lang.String) throws java.io.IOException;
    +-    method protected abstract T engineGetParameterSpec(java.lang.Class<T>) throws java.security.spec.InvalidParameterSpecException;
    ++    method protected abstract <T extends java.security.spec.AlgorithmParameterSpec> T engineGetParameterSpec(java.lang.Class<T>) throws java.security.spec.InvalidParameterSpecException;
    +     method protected abstract void engineInit(java.security.spec.AlgorithmParameterSpec) throws java.security.spec.InvalidParameterSpecException;
    +     method protected abstract void engineInit(byte[]) throws java.io.IOException;
    +     method protected abstract void engineInit(byte[], java.lang.String) throws java.io.IOException;
    +@@ -57740,7 +57740,7 @@ package java.security {
    +     method public static java.security.KeyFactory getInstance(java.lang.String) throws java.security.NoSuchAlgorithmException;
    +     method public static java.security.KeyFactory getInstance(java.lang.String, java.lang.String) throws java.security.NoSuchAlgorithmException, java.security.NoSuchProviderException;
    +     method public static java.security.KeyFactory getInstance(java.lang.String, java.security.Provider) throws java.security.NoSuchAlgorithmException;
    +-    method public final T getKeySpec(java.security.Key, java.lang.Class<T>) throws java.security.spec.InvalidKeySpecException;
    ++    method public final <T extends java.security.spec.KeySpec> T getKeySpec(java.security.Key, java.lang.Class<T>) throws java.security.spec.InvalidKeySpecException;
    +     method public final java.security.Provider getProvider();
    +     method public final java.security.Key translateKey(java.security.Key) throws java.security.InvalidKeyException;
    +   }
    +@@ -57749,7 +57749,7 @@ package java.security {
    +     ctor public KeyFactorySpi();
    +     method protected abstract java.security.PrivateKey engineGeneratePrivate(java.security.spec.KeySpec) throws java.security.spec.InvalidKeySpecException;
    +     method protected abstract java.security.PublicKey engineGeneratePublic(java.security.spec.KeySpec) throws java.security.spec.InvalidKeySpecException;
    +-    method protected abstract T engineGetKeySpec(java.security.Key, java.lang.Class<T>) throws java.security.spec.InvalidKeySpecException;
    ++    method protected abstract <T extends java.security.spec.KeySpec> T engineGetKeySpec(java.security.Key, java.lang.Class<T>) throws java.security.spec.InvalidKeySpecException;
    +     method protected abstract java.security.Key engineTranslateKey(java.security.Key) throws java.security.InvalidKeyException;
    +   }
    + 
    +@@ -58018,7 +58018,7 @@ package java.security {
    +     field public static final long serialVersionUID = 6034044314589513430L; // 0x53bd3b559a12c6d6L
    +   }
    + 
    +-  public abstract interface PrivilegedAction {
    ++  public abstract interface PrivilegedAction<T> {
    +     method public abstract T run();
    +   }
    + 
    +@@ -58027,7 +58027,7 @@ package java.security {
    +     method public java.lang.Exception getException();
    +   }
    + 
    +-  public abstract interface PrivilegedExceptionAction {
    ++  public abstract interface PrivilegedExceptionAction<T> {
    +     method public abstract T run() throws java.lang.Exception;
    +   }
    + 
    +@@ -60209,11 +60209,11 @@ package java.sql {
    +     method public abstract void free() throws java.sql.SQLException;
    +     method public abstract java.io.InputStream getBinaryStream() throws java.sql.SQLException;
    +     method public abstract java.io.Reader getCharacterStream() throws java.sql.SQLException;
    +-    method public abstract T getSource(java.lang.Class<T>) throws java.sql.SQLException;
    ++    method public abstract <T extends javax.xml.transform.Source> T getSource(java.lang.Class<T>) throws java.sql.SQLException;
    +     method public abstract java.lang.String getString() throws java.sql.SQLException;
    +     method public abstract java.io.OutputStream setBinaryStream() throws java.sql.SQLException;
    +     method public abstract java.io.Writer setCharacterStream() throws java.sql.SQLException;
    +-    method public abstract T setResult(java.lang.Class<T>) throws java.sql.SQLException;
    ++    method public abstract <T extends javax.xml.transform.Result> T setResult(java.lang.Class<T>) throws java.sql.SQLException;
    +     method public abstract void setString(java.lang.String) throws java.sql.SQLException;
    +   }
    + 
    +@@ -60337,7 +60337,7 @@ package java.sql {
    + 
    +   public abstract interface Wrapper {
    +     method public abstract boolean isWrapperFor(java.lang.Class<?>) throws java.sql.SQLException;
    +-    method public abstract T unwrap(java.lang.Class<T>) throws java.sql.SQLException;
    ++    method public abstract <T> T unwrap(java.lang.Class<T>) throws java.sql.SQLException;
    +   }
    + 
    + }
    +@@ -60870,7 +60870,7 @@ package java.text {
    + 
    + package java.util {
    + 
    +-  public abstract class AbstractCollection implements java.util.Collection {
    ++  public abstract class AbstractCollection<E> implements java.util.Collection {
    +     ctor protected AbstractCollection();
    +     method public boolean add(E);
    +     method public boolean addAll(java.util.Collection<? extends E>);
    +@@ -60884,10 +60884,10 @@ package java.util {
    +     method public boolean retainAll(java.util.Collection<?>);
    +     method public abstract int size();
    +     method public java.lang.Object[] toArray();
    +-    method public T[] toArray(T[]);
    ++    method public <T> T[] toArray(T[]);
    +   }
    + 
    +-  public abstract class AbstractList extends java.util.AbstractCollection implements java.util.List {
    ++  public abstract class AbstractList<E> extends java.util.AbstractCollection implements java.util.List {
    +     ctor protected AbstractList();
    +     method public void add(int, E);
    +     method public boolean addAll(int, java.util.Collection<? extends E>);
    +@@ -60904,7 +60904,7 @@ package java.util {
    +     field protected transient int modCount;
    +   }
    + 
    +-  public abstract class AbstractMap implements java.util.Map {
    ++  public abstract class AbstractMap<K, V> implements java.util.Map {
    +     ctor protected AbstractMap();
    +     method public void clear();
    +     method public boolean containsKey(java.lang.Object);
    +@@ -60920,7 +60920,7 @@ package java.util {
    +     method public java.util.Collection<V> values();
    +   }
    + 
    +-  public static class AbstractMap.SimpleEntry implements java.util.Map.Entry java.io.Serializable {
    ++  public static class AbstractMap.SimpleEntry<K, V> implements java.util.Map.Entry java.io.Serializable {
    +     ctor public AbstractMap.SimpleEntry(K, V);
    +     ctor public AbstractMap.SimpleEntry(java.util.Map.Entry<? extends K, ? extends V>);
    +     method public K getKey();
    +@@ -60928,7 +60928,7 @@ package java.util {
    +     method public V setValue(V);
    +   }
    + 
    +-  public static class AbstractMap.SimpleImmutableEntry implements java.util.Map.Entry java.io.Serializable {
    ++  public static class AbstractMap.SimpleImmutableEntry<K, V> implements java.util.Map.Entry java.io.Serializable {
    +     ctor public AbstractMap.SimpleImmutableEntry(K, V);
    +     ctor public AbstractMap.SimpleImmutableEntry(java.util.Map.Entry<? extends K, ? extends V>);
    +     method public K getKey();
    +@@ -60936,23 +60936,23 @@ package java.util {
    +     method public V setValue(V);
    +   }
    + 
    +-  public abstract class AbstractQueue extends java.util.AbstractCollection implements java.util.Queue {
    ++  public abstract class AbstractQueue<E> extends java.util.AbstractCollection implements java.util.Queue {
    +     ctor protected AbstractQueue();
    +     method public E element();
    +     method public E remove();
    +   }
    + 
    +-  public abstract class AbstractSequentialList extends java.util.AbstractList {
    ++  public abstract class AbstractSequentialList<E> extends java.util.AbstractList {
    +     ctor protected AbstractSequentialList();
    +     method public E get(int);
    +     method public abstract java.util.ListIterator<E> listIterator(int);
    +   }
    + 
    +-  public abstract class AbstractSet extends java.util.AbstractCollection implements java.util.Set {
    ++  public abstract class AbstractSet<E> extends java.util.AbstractCollection implements java.util.Set {
    +     ctor protected AbstractSet();
    +   }
    + 
    +-  public class ArrayDeque extends java.util.AbstractCollection implements java.lang.Cloneable java.util.Deque java.io.Serializable {
    ++  public class ArrayDeque<E> extends java.util.AbstractCollection implements java.lang.Cloneable java.util.Deque java.io.Serializable {
    +     ctor public ArrayDeque();
    +     ctor public ArrayDeque(int);
    +     ctor public ArrayDeque(java.util.Collection<? extends E>);
    +@@ -60984,7 +60984,7 @@ package java.util {
    +     method public java.util.Spliterator<E> spliterator();
    +   }
    + 
    +-  public class ArrayList extends java.util.AbstractList implements java.lang.Cloneable java.util.List java.util.RandomAccess java.io.Serializable {
    ++  public class ArrayList<E> extends java.util.AbstractList implements java.lang.Cloneable java.util.List java.util.RandomAccess java.io.Serializable {
    +     ctor public ArrayList(int);
    +     ctor public ArrayList();
    +     ctor public ArrayList(java.util.Collection<? extends E>);
    +@@ -61001,7 +61001,7 @@ package java.util {
    +   }
    + 
    +   public class Arrays {
    +-    method public static java.util.List<T> asList(T...);
    ++    method public static <T> java.util.List<T> asList(T...);
    +     method public static int binarySearch(long[], long);
    +     method public static int binarySearch(long[], int, int, long);
    +     method public static int binarySearch(int[], int);
    +@@ -61018,10 +61018,10 @@ package java.util {
    +     method public static int binarySearch(float[], int, int, float);
    +     method public static int binarySearch(java.lang.Object[], java.lang.Object);
    +     method public static int binarySearch(java.lang.Object[], int, int, java.lang.Object);
    +-    method public static int binarySearch(T[], T, java.util.Comparator<? super T>);
    +-    method public static int binarySearch(T[], int, int, T, java.util.Comparator<? super T>);
    +-    method public static T[] copyOf(T[], int);
    +-    method public static T[] copyOf(U[], int, java.lang.Class<? extends T[]>);
    ++    method public static <T> int binarySearch(T[], T, java.util.Comparator<? super T>);
    ++    method public static <T> int binarySearch(T[], int, int, T, java.util.Comparator<? super T>);
    ++    method public static <T> T[] copyOf(T[], int);
    ++    method public static <T, U> T[] copyOf(U[], int, java.lang.Class<? extends T[]>);
    +     method public static byte[] copyOf(byte[], int);
    +     method public static short[] copyOf(short[], int);
    +     method public static int[] copyOf(int[], int);
    +@@ -61030,8 +61030,8 @@ package java.util {
    +     method public static float[] copyOf(float[], int);
    +     method public static double[] copyOf(double[], int);
    +     method public static boolean[] copyOf(boolean[], int);
    +-    method public static T[] copyOfRange(T[], int, int);
    +-    method public static T[] copyOfRange(U[], int, int, java.lang.Class<? extends T[]>);
    ++    method public static <T> T[] copyOfRange(T[], int, int);
    ++    method public static <T, U> T[] copyOfRange(U[], int, int, java.lang.Class<? extends T[]>);
    +     method public static byte[] copyOfRange(byte[], int, int);
    +     method public static short[] copyOfRange(short[], int, int);
    +     method public static int[] copyOfRange(int[], int, int);
    +@@ -61079,15 +61079,15 @@ package java.util {
    +     method public static int hashCode(float[]);
    +     method public static int hashCode(double[]);
    +     method public static int hashCode(java.lang.Object[]);
    +-    method public static void parallelPrefix(T[], java.util.function.BinaryOperator<T>);
    +-    method public static void parallelPrefix(T[], int, int, java.util.function.BinaryOperator<T>);
    ++    method public static <T> void parallelPrefix(T[], java.util.function.BinaryOperator<T>);
    ++    method public static <T> void parallelPrefix(T[], int, int, java.util.function.BinaryOperator<T>);
    +     method public static void parallelPrefix(long[], java.util.function.LongBinaryOperator);
    +     method public static void parallelPrefix(long[], int, int, java.util.function.LongBinaryOperator);
    +     method public static void parallelPrefix(double[], java.util.function.DoubleBinaryOperator);
    +     method public static void parallelPrefix(double[], int, int, java.util.function.DoubleBinaryOperator);
    +     method public static void parallelPrefix(int[], java.util.function.IntBinaryOperator);
    +     method public static void parallelPrefix(int[], int, int, java.util.function.IntBinaryOperator);
    +-    method public static void parallelSetAll(T[], java.util.function.IntFunction<? extends T>);
    ++    method public static <T> void parallelSetAll(T[], java.util.function.IntFunction<? extends T>);
    +     method public static void parallelSetAll(int[], java.util.function.IntUnaryOperator);
    +     method public static void parallelSetAll(long[], java.util.function.IntToLongFunction);
    +     method public static void parallelSetAll(double[], java.util.function.IntToDoubleFunction);
    +@@ -61105,11 +61105,11 @@ package java.util {
    +     method public static void parallelSort(float[], int, int);
    +     method public static void parallelSort(double[]);
    +     method public static void parallelSort(double[], int, int);
    +-    method public static void parallelSort(T[]);
    +-    method public static void parallelSort(T[], int, int);
    +-    method public static void parallelSort(T[], java.util.Comparator<? super T>);
    +-    method public static void parallelSort(T[], int, int, java.util.Comparator<? super T>);
    +-    method public static void setAll(T[], java.util.function.IntFunction<? extends T>);
    ++    method public static <T extends java.lang.Comparable<? super T>> void parallelSort(T[]);
    ++    method public static <T extends java.lang.Comparable<? super T>> void parallelSort(T[], int, int);
    ++    method public static <T> void parallelSort(T[], java.util.Comparator<? super T>);
    ++    method public static <T> void parallelSort(T[], int, int, java.util.Comparator<? super T>);
    ++    method public static <T> void setAll(T[], java.util.function.IntFunction<? extends T>);
    +     method public static void setAll(int[], java.util.function.IntUnaryOperator);
    +     method public static void setAll(long[], java.util.function.IntToLongFunction);
    +     method public static void setAll(double[], java.util.function.IntToDoubleFunction);
    +@@ -61129,18 +61129,18 @@ package java.util {
    +     method public static void sort(double[], int, int);
    +     method public static void sort(java.lang.Object[]);
    +     method public static void sort(java.lang.Object[], int, int);
    +-    method public static void sort(T[], java.util.Comparator<? super T>);
    +-    method public static void sort(T[], int, int, java.util.Comparator<? super T>);
    +-    method public static java.util.Spliterator<T> spliterator(T[]);
    +-    method public static java.util.Spliterator<T> spliterator(T[], int, int);
    ++    method public static <T> void sort(T[], java.util.Comparator<? super T>);
    ++    method public static <T> void sort(T[], int, int, java.util.Comparator<? super T>);
    ++    method public static <T> java.util.Spliterator<T> spliterator(T[]);
    ++    method public static <T> java.util.Spliterator<T> spliterator(T[], int, int);
    +     method public static java.util.Spliterator.OfInt spliterator(int[]);
    +     method public static java.util.Spliterator.OfInt spliterator(int[], int, int);
    +     method public static java.util.Spliterator.OfLong spliterator(long[]);
    +     method public static java.util.Spliterator.OfLong spliterator(long[], int, int);
    +     method public static java.util.Spliterator.OfDouble spliterator(double[]);
    +     method public static java.util.Spliterator.OfDouble spliterator(double[], int, int);
    +-    method public static java.util.stream.Stream<T> stream(T[]);
    +-    method public static java.util.stream.Stream<T> stream(T[], int, int);
    ++    method public static <T> java.util.stream.Stream<T> stream(T[]);
    ++    method public static <T> java.util.stream.Stream<T> stream(T[], int, int);
    +     method public static java.util.stream.IntStream stream(int[]);
    +     method public static java.util.stream.IntStream stream(int[], int, int);
    +     method public static java.util.stream.LongStream stream(long[]);
    +@@ -61297,7 +61297,7 @@ package java.util {
    +     field protected long time;
    +   }
    + 
    +-  public abstract interface Collection implements java.lang.Iterable {
    ++  public abstract interface Collection<E> implements java.lang.Iterable {
    +     method public abstract boolean add(E);
    +     method public abstract boolean addAll(java.util.Collection<? extends E>);
    +     method public abstract void clear();
    +@@ -61315,86 +61315,86 @@ package java.util {
    +     method public abstract int size();
    +     method public default java.util.stream.Stream<E> stream();
    +     method public abstract java.lang.Object[] toArray();
    +-    method public abstract T[] toArray(T[]);
    ++    method public abstract <T> T[] toArray(T[]);
    +   }
    + 
    +   public class Collections {
    +-    method public static boolean addAll(java.util.Collection<? super T>, T...);
    +-    method public static java.util.Queue<T> asLifoQueue(java.util.Deque<T>);
    +-    method public static int binarySearch(java.util.List<? extends java.lang.Comparable<? super T>>, T);
    +-    method public static int binarySearch(java.util.List<? extends T>, T, java.util.Comparator<? super T>);
    +-    method public static java.util.Collection<E> checkedCollection(java.util.Collection<E>, java.lang.Class<E>);
    +-    method public static java.util.List<E> checkedList(java.util.List<E>, java.lang.Class<E>);
    +-    method public static java.util.Map<K, V> checkedMap(java.util.Map<K, V>, java.lang.Class<K>, java.lang.Class<V>);
    +-    method public static java.util.Set<E> checkedSet(java.util.Set<E>, java.lang.Class<E>);
    +-    method public static java.util.SortedMap<K, V> checkedSortedMap(java.util.SortedMap<K, V>, java.lang.Class<K>, java.lang.Class<V>);
    +-    method public static java.util.SortedSet<E> checkedSortedSet(java.util.SortedSet<E>, java.lang.Class<E>);
    +-    method public static void copy(java.util.List<? super T>, java.util.List<? extends T>);
    ++    method public static <T> boolean addAll(java.util.Collection<? super T>, T...);
    ++    method public static <T> java.util.Queue<T> asLifoQueue(java.util.Deque<T>);
    ++    method public static <T> int binarySearch(java.util.List<? extends java.lang.Comparable<? super T>>, T);
    ++    method public static <T> int binarySearch(java.util.List<? extends T>, T, java.util.Comparator<? super T>);
    ++    method public static <E> java.util.Collection<E> checkedCollection(java.util.Collection<E>, java.lang.Class<E>);
    ++    method public static <E> java.util.List<E> checkedList(java.util.List<E>, java.lang.Class<E>);
    ++    method public static <K, V> java.util.Map<K, V> checkedMap(java.util.Map<K, V>, java.lang.Class<K>, java.lang.Class<V>);
    ++    method public static <E> java.util.Set<E> checkedSet(java.util.Set<E>, java.lang.Class<E>);
    ++    method public static <K, V> java.util.SortedMap<K, V> checkedSortedMap(java.util.SortedMap<K, V>, java.lang.Class<K>, java.lang.Class<V>);
    ++    method public static <E> java.util.SortedSet<E> checkedSortedSet(java.util.SortedSet<E>, java.lang.Class<E>);
    ++    method public static <T> void copy(java.util.List<? super T>, java.util.List<? extends T>);
    +     method public static boolean disjoint(java.util.Collection<?>, java.util.Collection<?>);
    +-    method public static java.util.Enumeration<T> emptyEnumeration();
    +-    method public static java.util.Iterator<T> emptyIterator();
    +-    method public static final java.util.List<T> emptyList();
    +-    method public static java.util.ListIterator<T> emptyListIterator();
    +-    method public static final java.util.Map<K, V> emptyMap();
    +-    method public static final java.util.Set<T> emptySet();
    +-    method public static java.util.Enumeration<T> enumeration(java.util.Collection<T>);
    +-    method public static void fill(java.util.List<? super T>, T);
    ++    method public static <T> java.util.Enumeration<T> emptyEnumeration();
    ++    method public static <T> java.util.Iterator<T> emptyIterator();
    ++    method public static final <T> java.util.List<T> emptyList();
    ++    method public static <T> java.util.ListIterator<T> emptyListIterator();
    ++    method public static final <K, V> java.util.Map<K, V> emptyMap();
    ++    method public static final <T> java.util.Set<T> emptySet();
    ++    method public static <T> java.util.Enumeration<T> enumeration(java.util.Collection<T>);
    ++    method public static <T> void fill(java.util.List<? super T>, T);
    +     method public static int frequency(java.util.Collection<?>, java.lang.Object);
    +     method public static int indexOfSubList(java.util.List<?>, java.util.List<?>);
    +     method public static int lastIndexOfSubList(java.util.List<?>, java.util.List<?>);
    +-    method public static java.util.ArrayList<T> list(java.util.Enumeration<T>);
    +-    method public static T max(java.util.Collection<? extends T>);
    +-    method public static T max(java.util.Collection<? extends T>, java.util.Comparator<? super T>);
    +-    method public static T min(java.util.Collection<? extends T>);
    +-    method public static T min(java.util.Collection<? extends T>, java.util.Comparator<? super T>);
    +-    method public static java.util.List<T> nCopies(int, T);
    +-    method public static java.util.Set<E> newSetFromMap(java.util.Map<E, java.lang.Boolean>);
    +-    method public static boolean replaceAll(java.util.List<T>, T, T);
    ++    method public static <T> java.util.ArrayList<T> list(java.util.Enumeration<T>);
    ++    method public static <T extends java.lang.Object & java.lang.Comparable<? super T>> T max(java.util.Collection<? extends T>);
    ++    method public static <T> T max(java.util.Collection<? extends T>, java.util.Comparator<? super T>);
    ++    method public static <T extends java.lang.Object & java.lang.Comparable<? super T>> T min(java.util.Collection<? extends T>);
    ++    method public static <T> T min(java.util.Collection<? extends T>, java.util.Comparator<? super T>);
    ++    method public static <T> java.util.List<T> nCopies(int, T);
    ++    method public static <E> java.util.Set<E> newSetFromMap(java.util.Map<E, java.lang.Boolean>);
    ++    method public static <T> boolean replaceAll(java.util.List<T>, T, T);
    +     method public static void reverse(java.util.List<?>);
    +-    method public static java.util.Comparator<T> reverseOrder();
    +-    method public static java.util.Comparator<T> reverseOrder(java.util.Comparator<T>);
    ++    method public static <T> java.util.Comparator<T> reverseOrder();
    ++    method public static <T> java.util.Comparator<T> reverseOrder(java.util.Comparator<T>);
    +     method public static void rotate(java.util.List<?>, int);
    +     method public static void shuffle(java.util.List<?>);
    +     method public static void shuffle(java.util.List<?>, java.util.Random);
    +-    method public static java.util.Set<E> singleton(E);
    +-    method public static java.util.List<E> singletonList(E);
    +-    method public static java.util.Map<K, V> singletonMap(K, V);
    +-    method public static void sort(java.util.List<T>);
    +-    method public static void sort(java.util.List<T>, java.util.Comparator<? super T>);
    ++    method public static <E> java.util.Set<E> singleton(E);
    ++    method public static <E> java.util.List<E> singletonList(E);
    ++    method public static <K, V> java.util.Map<K, V> singletonMap(K, V);
    ++    method public static <T extends java.lang.Comparable<? super T>> void sort(java.util.List<T>);
    ++    method public static <T> void sort(java.util.List<T>, java.util.Comparator<? super T>);
    +     method public static void swap(java.util.List<?>, int, int);
    +-    method public static java.util.Collection<T> synchronizedCollection(java.util.Collection<T>);
    +-    method public static java.util.List<T> synchronizedList(java.util.List<T>);
    +-    method public static java.util.Map<K, V> synchronizedMap(java.util.Map<K, V>);
    +-    method public static java.util.Set<T> synchronizedSet(java.util.Set<T>);
    +-    method public static java.util.SortedMap<K, V> synchronizedSortedMap(java.util.SortedMap<K, V>);
    +-    method public static java.util.SortedSet<T> synchronizedSortedSet(java.util.SortedSet<T>);
    +-    method public static java.util.Collection<T> unmodifiableCollection(java.util.Collection<? extends T>);
    +-    method public static java.util.List<T> unmodifiableList(java.util.List<? extends T>);
    +-    method public static java.util.Map<K, V> unmodifiableMap(java.util.Map<? extends K, ? extends V>);
    +-    method public static java.util.Set<T> unmodifiableSet(java.util.Set<? extends T>);
    +-    method public static java.util.SortedMap<K, V> unmodifiableSortedMap(java.util.SortedMap<K, ? extends V>);
    +-    method public static java.util.SortedSet<T> unmodifiableSortedSet(java.util.SortedSet<T>);
    ++    method public static <T> java.util.Collection<T> synchronizedCollection(java.util.Collection<T>);
    ++    method public static <T> java.util.List<T> synchronizedList(java.util.List<T>);
    ++    method public static <K, V> java.util.Map<K, V> synchronizedMap(java.util.Map<K, V>);
    ++    method public static <T> java.util.Set<T> synchronizedSet(java.util.Set<T>);
    ++    method public static <K, V> java.util.SortedMap<K, V> synchronizedSortedMap(java.util.SortedMap<K, V>);
    ++    method public static <T> java.util.SortedSet<T> synchronizedSortedSet(java.util.SortedSet<T>);
    ++    method public static <T> java.util.Collection<T> unmodifiableCollection(java.util.Collection<? extends T>);
    ++    method public static <T> java.util.List<T> unmodifiableList(java.util.List<? extends T>);
    ++    method public static <K, V> java.util.Map<K, V> unmodifiableMap(java.util.Map<? extends K, ? extends V>);
    ++    method public static <T> java.util.Set<T> unmodifiableSet(java.util.Set<? extends T>);
    ++    method public static <K, V> java.util.SortedMap<K, V> unmodifiableSortedMap(java.util.SortedMap<K, ? extends V>);
    ++    method public static <T> java.util.SortedSet<T> unmodifiableSortedSet(java.util.SortedSet<T>);
    +     field public static final java.util.List EMPTY_LIST;
    +     field public static final java.util.Map EMPTY_MAP;
    +     field public static final java.util.Set EMPTY_SET;
    +   }
    + 
    +-  public abstract interface Comparator {
    ++  public abstract interface Comparator<T> {
    +     method public abstract int compare(T, T);
    +-    method public static java.util.Comparator<T> comparing(java.util.function.Function<? super T, ? extends U>, java.util.Comparator<? super U>);
    +-    method public static java.util.Comparator<T> comparing(java.util.function.Function<? super T, ? extends U>);
    +-    method public static java.util.Comparator<T> comparingDouble(java.util.function.ToDoubleFunction<? super T>);
    +-    method public static java.util.Comparator<T> comparingInt(java.util.function.ToIntFunction<? super T>);
    +-    method public static java.util.Comparator<T> comparingLong(java.util.function.ToLongFunction<? super T>);
    ++    method public static <T, U> java.util.Comparator<T> comparing(java.util.function.Function<? super T, ? extends U>, java.util.Comparator<? super U>);
    ++    method public static <T, U extends java.lang.Comparable<? super U>> java.util.Comparator<T> comparing(java.util.function.Function<? super T, ? extends U>);
    ++    method public static <T> java.util.Comparator<T> comparingDouble(java.util.function.ToDoubleFunction<? super T>);
    ++    method public static <T> java.util.Comparator<T> comparingInt(java.util.function.ToIntFunction<? super T>);
    ++    method public static <T> java.util.Comparator<T> comparingLong(java.util.function.ToLongFunction<? super T>);
    +     method public abstract boolean equals(java.lang.Object);
    +-    method public static java.util.Comparator<T> naturalOrder();
    +-    method public static java.util.Comparator<T> nullsFirst(java.util.Comparator<? super T>);
    +-    method public static java.util.Comparator<T> nullsLast(java.util.Comparator<? super T>);
    +-    method public static java.util.Comparator<T> reverseOrder();
    ++    method public static <T extends java.lang.Comparable<? super T>> java.util.Comparator<T> naturalOrder();
    ++    method public static <T> java.util.Comparator<T> nullsFirst(java.util.Comparator<? super T>);
    ++    method public static <T> java.util.Comparator<T> nullsLast(java.util.Comparator<? super T>);
    ++    method public static <T extends java.lang.Comparable<? super T>> java.util.Comparator<T> reverseOrder();
    +     method public default java.util.Comparator<T> reversed();
    +     method public default java.util.Comparator<T> thenComparing(java.util.Comparator<? super T>);
    +-    method public default java.util.Comparator<T> thenComparing(java.util.function.Function<? super T, ? extends U>, java.util.Comparator<? super U>);
    +-    method public default java.util.Comparator<T> thenComparing(java.util.function.Function<? super T, ? extends U>);
    ++    method public default <U> java.util.Comparator<T> thenComparing(java.util.function.Function<? super T, ? extends U>, java.util.Comparator<? super U>);
    ++    method public default <U extends java.lang.Comparable<? super U>> java.util.Comparator<T> thenComparing(java.util.function.Function<? super T, ? extends U>);
    +     method public default java.util.Comparator<T> thenComparingDouble(java.util.function.ToDoubleFunction<? super T>);
    +     method public default java.util.Comparator<T> thenComparingInt(java.util.function.ToIntFunction<? super T>);
    +     method public default java.util.Comparator<T> thenComparingLong(java.util.function.ToLongFunction<? super T>);
    +@@ -61453,7 +61453,7 @@ package java.util {
    +     method public deprecated java.lang.String toLocaleString();
    +   }
    + 
    +-  public abstract interface Deque implements java.util.Queue {
    ++  public abstract interface Deque<E> implements java.util.Queue {
    +     method public abstract boolean add(E);
    +     method public abstract void addFirst(E);
    +     method public abstract void addLast(E);
    +@@ -61483,7 +61483,7 @@ package java.util {
    +     method public abstract int size();
    +   }
    + 
    +-  public abstract class Dictionary {
    ++  public abstract class Dictionary<K, V> {
    +     ctor public Dictionary();
    +     method public abstract java.util.Enumeration<V> elements();
    +     method public abstract V get(java.lang.Object);
    +@@ -61514,7 +61514,7 @@ package java.util {
    +     ctor public EmptyStackException();
    +   }
    + 
    +-  public class EnumMap extends java.util.AbstractMap implements java.lang.Cloneable java.io.Serializable {
    ++  public class EnumMap<K extends java.lang.Enum<K>, V> extends java.util.AbstractMap implements java.lang.Cloneable java.io.Serializable {
    +     ctor public EnumMap(java.lang.Class<K>);
    +     ctor public EnumMap(java.util.EnumMap<K, ? extends V>);
    +     ctor public EnumMap(java.util.Map<K, ? extends V>);
    +@@ -61522,23 +61522,23 @@ package java.util {
    +     method public java.util.Set<java.util.Map.Entry<K, V>> entrySet();
    +   }
    + 
    +-  public abstract class EnumSet extends java.util.AbstractSet implements java.lang.Cloneable java.io.Serializable {
    +-    method public static java.util.EnumSet<E> allOf(java.lang.Class<E>);
    ++  public abstract class EnumSet<E extends java.lang.Enum<E>> extends java.util.AbstractSet implements java.lang.Cloneable java.io.Serializable {
    ++    method public static <E extends java.lang.Enum<E>> java.util.EnumSet<E> allOf(java.lang.Class<E>);
    +     method public java.util.EnumSet<E> clone();
    +-    method public static java.util.EnumSet<E> complementOf(java.util.EnumSet<E>);
    +-    method public static java.util.EnumSet<E> copyOf(java.util.EnumSet<E>);
    +-    method public static java.util.EnumSet<E> copyOf(java.util.Collection<E>);
    +-    method public static java.util.EnumSet<E> noneOf(java.lang.Class<E>);
    +-    method public static java.util.EnumSet<E> of(E);
    +-    method public static java.util.EnumSet<E> of(E, E);
    +-    method public static java.util.EnumSet<E> of(E, E, E);
    +-    method public static java.util.EnumSet<E> of(E, E, E, E);
    +-    method public static java.util.EnumSet<E> of(E, E, E, E, E);
    +-    method public static java.util.EnumSet<E> of(E, E...);
    +-    method public static java.util.EnumSet<E> range(E, E);
    +-  }
    +-
    +-  public abstract interface Enumeration {
    ++    method public static <E extends java.lang.Enum<E>> java.util.EnumSet<E> complementOf(java.util.EnumSet<E>);
    ++    method public static <E extends java.lang.Enum<E>> java.util.EnumSet<E> copyOf(java.util.EnumSet<E>);
    ++    method public static <E extends java.lang.Enum<E>> java.util.EnumSet<E> copyOf(java.util.Collection<E>);
    ++    method public static <E extends java.lang.Enum<E>> java.util.EnumSet<E> noneOf(java.lang.Class<E>);
    ++    method public static <E extends java.lang.Enum<E>> java.util.EnumSet<E> of(E);
    ++    method public static <E extends java.lang.Enum<E>> java.util.EnumSet<E> of(E, E);
    ++    method public static <E extends java.lang.Enum<E>> java.util.EnumSet<E> of(E, E, E);
    ++    method public static <E extends java.lang.Enum<E>> java.util.EnumSet<E> of(E, E, E, E);
    ++    method public static <E extends java.lang.Enum<E>> java.util.EnumSet<E> of(E, E, E, E, E);
    ++    method public static <E extends java.lang.Enum<E>> java.util.EnumSet<E> of(E, E...);
    ++    method public static <E extends java.lang.Enum<E>> java.util.EnumSet<E> range(E, E);
    ++  }
    ++
    ++  public abstract interface Enumeration<E> {
    +     method public abstract boolean hasMoreElements();
    +     method public abstract E nextElement();
    +   }
    +@@ -61546,7 +61546,7 @@ package java.util {
    +   public abstract interface EventListener {
    +   }
    + 
    +-  public abstract class EventListenerProxy implements java.util.EventListener {
    ++  public abstract class EventListenerProxy<T extends java.util.EventListener> implements java.util.EventListener {
    +     ctor public EventListenerProxy(T);
    +     method public T getListener();
    +   }
    +@@ -61632,7 +61632,7 @@ package java.util {
    +     field public static final int BC = 0; // 0x0
    +   }
    + 
    +-  public class HashMap extends java.util.AbstractMap implements java.lang.Cloneable java.util.Map java.io.Serializable {
    ++  public class HashMap<K, V> extends java.util.AbstractMap implements java.lang.Cloneable java.util.Map java.io.Serializable {
    +     ctor public HashMap(int, float);
    +     ctor public HashMap(int);
    +     ctor public HashMap();
    +@@ -61644,7 +61644,7 @@ package java.util {
    +     method public void replaceAll(java.util.function.BiFunction<? super K, ? super V, ? extends V>);
    +   }
    + 
    +-  public class HashSet extends java.util.AbstractSet implements java.lang.Cloneable java.io.Serializable java.util.Set {
    ++  public class HashSet<E> extends java.util.AbstractSet implements java.lang.Cloneable java.io.Serializable java.util.Set {
    +     ctor public HashSet();
    +     ctor public HashSet(java.util.Collection<? extends E>);
    +     ctor public HashSet(int, float);
    +@@ -61655,7 +61655,7 @@ package java.util {
    +     method public java.util.Spliterator<E> spliterator();
    +   }
    + 
    +-  public class Hashtable extends java.util.Dictionary implements java.lang.Cloneable java.util.Map java.io.Serializable {
    ++  public class Hashtable<K, V> extends java.util.Dictionary implements java.lang.Cloneable java.util.Map java.io.Serializable {
    +     ctor public Hashtable(int, float);
    +     ctor public Hashtable(int);
    +     ctor public Hashtable();
    +@@ -61690,7 +61690,7 @@ package java.util {
    +     method public java.util.Collection<V> values();
    +   }
    + 
    +-  public class IdentityHashMap extends java.util.AbstractMap implements java.lang.Cloneable java.util.Map java.io.Serializable {
    ++  public class IdentityHashMap<K, V> extends java.util.AbstractMap implements java.lang.Cloneable java.util.Map java.io.Serializable {
    +     ctor public IdentityHashMap();
    +     ctor public IdentityHashMap(int);
    +     ctor public IdentityHashMap(java.util.Map<? extends K, ? extends V>);
    +@@ -61757,14 +61757,14 @@ package java.util {
    +     ctor public InvalidPropertiesFormatException(java.lang.String);
    +   }
    + 
    +-  public abstract interface Iterator {
    ++  public abstract interface Iterator<E> {
    +     method public default void forEachRemaining(java.util.function.Consumer<? super E>);
    +     method public abstract boolean hasNext();
    +     method public abstract E next();
    +     method public default void remove();
    +   }
    + 
    +-  public class LinkedHashMap extends java.util.HashMap implements java.util.Map {
    ++  public class LinkedHashMap<K, V> extends java.util.HashMap implements java.util.Map {
    +     ctor public LinkedHashMap(int, float);
    +     ctor public LinkedHashMap(int);
    +     ctor public LinkedHashMap();
    +@@ -61773,14 +61773,14 @@ package java.util {
    +     method protected boolean removeEldestEntry(java.util.Map.Entry<K, V>);
    +   }
    + 
    +-  public class LinkedHashSet extends java.util.HashSet implements java.lang.Cloneable java.io.Serializable java.util.Set {
    ++  public class LinkedHashSet<E> extends java.util.HashSet implements java.lang.Cloneable java.io.Serializable java.util.Set {
    +     ctor public LinkedHashSet(int, float);
    +     ctor public LinkedHashSet(int);
    +     ctor public LinkedHashSet();
    +     ctor public LinkedHashSet(java.util.Collection<? extends E>);
    +   }
    + 
    +-  public class LinkedList extends java.util.AbstractSequentialList implements java.lang.Cloneable java.util.Deque java.util.List java.io.Serializable {
    ++  public class LinkedList<E> extends java.util.AbstractSequentialList implements java.lang.Cloneable java.util.Deque java.util.List java.io.Serializable {
    +     ctor public LinkedList();
    +     ctor public LinkedList(java.util.Collection<? extends E>);
    +     method public void addFirst(E);
    +@@ -61811,7 +61811,7 @@ package java.util {
    +     method public java.util.Spliterator<E> spliterator();
    +   }
    + 
    +-  public abstract interface List implements java.util.Collection {
    ++  public abstract interface List<E> implements java.util.Collection {
    +     method public abstract boolean add(E);
    +     method public abstract void add(int, E);
    +     method public abstract boolean addAll(java.util.Collection<? extends E>);
    +@@ -61838,10 +61838,10 @@ package java.util {
    +     method public default void sort(java.util.Comparator<? super E>);
    +     method public abstract java.util.List<E> subList(int, int);
    +     method public abstract java.lang.Object[] toArray();
    +-    method public abstract T[] toArray(T[]);
    ++    method public abstract <T> T[] toArray(T[]);
    +   }
    + 
    +-  public abstract interface ListIterator implements java.util.Iterator {
    ++  public abstract interface ListIterator<E> implements java.util.Iterator {
    +     method public abstract void add(E);
    +     method public abstract boolean hasNext();
    +     method public abstract boolean hasPrevious();
    +@@ -61958,7 +61958,7 @@ package java.util {
    +     method public final long getSum();
    +   }
    + 
    +-  public abstract interface Map {
    ++  public abstract interface Map<K, V> {
    +     method public abstract void clear();
    +     method public default V compute(K, java.util.function.BiFunction<? super K, ? super V, ? extends V>);
    +     method public default V computeIfAbsent(K, java.util.function.Function<? super K, ? extends V>);
    +@@ -61986,11 +61986,11 @@ package java.util {
    +     method public abstract java.util.Collection<V> values();
    +   }
    + 
    +-  public static abstract interface Map.Entry {
    +-    method public static java.util.Comparator<java.util.Map.Entry<K, V>> comparingByKey();
    +-    method public static java.util.Comparator<java.util.Map.Entry<K, V>> comparingByKey(java.util.Comparator<? super K>);
    +-    method public static java.util.Comparator<java.util.Map.Entry<K, V>> comparingByValue();
    +-    method public static java.util.Comparator<java.util.Map.Entry<K, V>> comparingByValue(java.util.Comparator<? super V>);
    ++  public static abstract interface Map.Entry<K, V> {
    ++    method public static <K extends java.lang.Comparable<? super K>, V> java.util.Comparator<java.util.Map.Entry<K, V>> comparingByKey();
    ++    method public static <K, V> java.util.Comparator<java.util.Map.Entry<K, V>> comparingByKey(java.util.Comparator<? super K>);
    ++    method public static <K, V extends java.lang.Comparable<? super V>> java.util.Comparator<java.util.Map.Entry<K, V>> comparingByValue();
    ++    method public static <K, V> java.util.Comparator<java.util.Map.Entry<K, V>> comparingByValue(java.util.Comparator<? super V>);
    +     method public abstract boolean equals(java.lang.Object);
    +     method public abstract K getKey();
    +     method public abstract V getValue();
    +@@ -62014,7 +62014,7 @@ package java.util {
    +     method public java.lang.String getKey();
    +   }
    + 
    +-  public abstract interface NavigableMap implements java.util.SortedMap {
    ++  public abstract interface NavigableMap<K, V> implements java.util.SortedMap {
    +     method public abstract java.util.Map.Entry<K, V> ceilingEntry(K);
    +     method public abstract K ceilingKey(K);
    +     method public abstract java.util.NavigableSet<K> descendingKeySet();
    +@@ -62038,7 +62038,7 @@ package java.util {
    +     method public abstract java.util.SortedMap<K, V> tailMap(K);
    +   }
    + 
    +-  public abstract interface NavigableSet implements java.util.SortedSet {
    ++  public abstract interface NavigableSet<E> implements java.util.SortedSet {
    +     method public abstract E ceiling(E);
    +     method public abstract java.util.Iterator<E> descendingIterator();
    +     method public abstract java.util.NavigableSet<E> descendingSet();
    +@@ -62062,16 +62062,16 @@ package java.util {
    +   }
    + 
    +   public final class Objects {
    +-    method public static int compare(T, T, java.util.Comparator<? super T>);
    ++    method public static <T> int compare(T, T, java.util.Comparator<? super T>);
    +     method public static boolean deepEquals(java.lang.Object, java.lang.Object);
    +     method public static boolean equals(java.lang.Object, java.lang.Object);
    +     method public static int hash(java.lang.Object...);
    +     method public static int hashCode(java.lang.Object);
    +     method public static boolean isNull(java.lang.Object);
    +     method public static boolean nonNull(java.lang.Object);
    +-    method public static T requireNonNull(T);
    +-    method public static T requireNonNull(T, java.lang.String);
    +-    method public static T requireNonNull(T, java.util.function.Supplier<java.lang.String>);
    ++    method public static <T> T requireNonNull(T);
    ++    method public static <T> T requireNonNull(T, java.lang.String);
    ++    method public static <T> T requireNonNull(T, java.util.function.Supplier<java.lang.String>);
    +     method public static java.lang.String toString(java.lang.Object);
    +     method public static java.lang.String toString(java.lang.Object, java.lang.String);
    +   }
    +@@ -62093,19 +62093,19 @@ package java.util {
    +     method public abstract void update(java.util.Observable, java.lang.Object);
    +   }
    + 
    +-  public final class Optional {
    +-    method public static java.util.Optional<T> empty();
    ++  public final class Optional<T> {
    ++    method public static <T> java.util.Optional<T> empty();
    +     method public java.util.Optional<T> filter(java.util.function.Predicate<? super T>);
    +-    method public java.util.Optional<U> flatMap(java.util.function.Function<? super T, java.util.Optional<U>>);
    ++    method public <U> java.util.Optional<U> flatMap(java.util.function.Function<? super T, java.util.Optional<U>>);
    +     method public T get();
    +     method public void ifPresent(java.util.function.Consumer<? super T>);
    +     method public boolean isPresent();
    +-    method public java.util.Optional<U> map(java.util.function.Function<? super T, ? extends U>);
    +-    method public static java.util.Optional<T> of(T);
    +-    method public static java.util.Optional<T> ofNullable(T);
    ++    method public <U> java.util.Optional<U> map(java.util.function.Function<? super T, ? extends U>);
    ++    method public static <T> java.util.Optional<T> of(T);
    ++    method public static <T> java.util.Optional<T> ofNullable(T);
    +     method public T orElse(T);
    +     method public T orElseGet(java.util.function.Supplier<? extends T>);
    +-    method public T orElseThrow(java.util.function.Supplier<? extends X>) throws java.lang.Throwable;
    ++    method public <X extends java.lang.Throwable> T orElseThrow(java.util.function.Supplier<? extends X>) throws java.lang.Throwable;
    +   }
    + 
    +   public final class OptionalDouble {
    +@@ -62116,7 +62116,7 @@ package java.util {
    +     method public static java.util.OptionalDouble of(double);
    +     method public double orElse(double);
    +     method public double orElseGet(java.util.function.DoubleSupplier);
    +-    method public double orElseThrow(java.util.function.Supplier<X>) throws java.lang.Throwable;
    ++    method public <X extends java.lang.Throwable> double orElseThrow(java.util.function.Supplier<X>) throws java.lang.Throwable;
    +   }
    + 
    +   public final class OptionalInt {
    +@@ -62127,7 +62127,7 @@ package java.util {
    +     method public static java.util.OptionalInt of(int);
    +     method public int orElse(int);
    +     method public int orElseGet(java.util.function.IntSupplier);
    +-    method public int orElseThrow(java.util.function.Supplier<X>) throws java.lang.Throwable;
    ++    method public <X extends java.lang.Throwable> int orElseThrow(java.util.function.Supplier<X>) throws java.lang.Throwable;
    +   }
    + 
    +   public final class OptionalLong {
    +@@ -62138,10 +62138,10 @@ package java.util {
    +     method public static java.util.OptionalLong of(long);
    +     method public long orElse(long);
    +     method public long orElseGet(java.util.function.LongSupplier);
    +-    method public long orElseThrow(java.util.function.Supplier<X>) throws java.lang.Throwable;
    ++    method public <X extends java.lang.Throwable> long orElseThrow(java.util.function.Supplier<X>) throws java.lang.Throwable;
    +   }
    + 
    +-  public abstract interface PrimitiveIterator implements java.util.Iterator {
    ++  public abstract interface PrimitiveIterator<T, T_CONS> implements java.util.Iterator {
    +     method public abstract void forEachRemaining(T_CONS);
    +   }
    + 
    +@@ -62166,7 +62166,7 @@ package java.util {
    +     method public abstract long nextLong();
    +   }
    + 
    +-  public class PriorityQueue extends java.util.AbstractQueue implements java.io.Serializable {
    ++  public class PriorityQueue<E> extends java.util.AbstractQueue implements java.io.Serializable {
    +     ctor public PriorityQueue();
    +     ctor public PriorityQueue(int);
    +     ctor public PriorityQueue(java.util.Comparator<? super E>);
    +@@ -62215,7 +62215,7 @@ package java.util {
    +     method public java.lang.Object handleGetObject(java.lang.String);
    +   }
    + 
    +-  public abstract interface Queue implements java.util.Collection {
    ++  public abstract interface Queue<E> implements java.util.Collection {
    +     method public abstract boolean add(E);
    +     method public abstract E element();
    +     method public abstract boolean offer(E);
    +@@ -62365,15 +62365,15 @@ package java.util {
    +     ctor public ServiceConfigurationError(java.lang.String, java.lang.Throwable);
    +   }
    + 
    +-  public final class ServiceLoader implements java.lang.Iterable {
    ++  public final class ServiceLoader<S> implements java.lang.Iterable {
    +     method public java.util.Iterator<S> iterator();
    +-    method public static java.util.ServiceLoader<S> load(java.lang.Class<S>, java.lang.ClassLoader);
    +-    method public static java.util.ServiceLoader<S> load(java.lang.Class<S>);
    +-    method public static java.util.ServiceLoader<S> loadInstalled(java.lang.Class<S>);
    ++    method public static <S> java.util.ServiceLoader<S> load(java.lang.Class<S>, java.lang.ClassLoader);
    ++    method public static <S> java.util.ServiceLoader<S> load(java.lang.Class<S>);
    ++    method public static <S> java.util.ServiceLoader<S> loadInstalled(java.lang.Class<S>);
    +     method public void reload();
    +   }
    + 
    +-  public abstract interface Set implements java.util.Collection {
    ++  public abstract interface Set<E> implements java.util.Collection {
    +     method public abstract boolean add(E);
    +     method public abstract boolean addAll(java.util.Collection<? extends E>);
    +     method public abstract void clear();
    +@@ -62388,7 +62388,7 @@ package java.util {
    +     method public abstract boolean retainAll(java.util.Collection<?>);
    +     method public abstract int size();
    +     method public abstract java.lang.Object[] toArray();
    +-    method public abstract T[] toArray(T[]);
    ++    method public abstract <T> T[] toArray(T[]);
    +   }
    + 
    +   public class SimpleTimeZone extends java.util.TimeZone {
    +@@ -62414,7 +62414,7 @@ package java.util {
    +     field public static final int WALL_TIME = 0; // 0x0
    +   }
    + 
    +-  public abstract interface SortedMap implements java.util.Map {
    ++  public abstract interface SortedMap<K, V> implements java.util.Map {
    +     method public abstract java.util.Comparator<? super K> comparator();
    +     method public abstract java.util.Set<java.util.Map.Entry<K, V>> entrySet();
    +     method public abstract K firstKey();
    +@@ -62426,7 +62426,7 @@ package java.util {
    +     method public abstract java.util.Collection<V> values();
    +   }
    + 
    +-  public abstract interface SortedSet implements java.util.Set {
    ++  public abstract interface SortedSet<E> implements java.util.Set {
    +     method public abstract java.util.Comparator<? super E> comparator();
    +     method public abstract E first();
    +     method public abstract java.util.SortedSet<E> headSet(E);
    +@@ -62435,7 +62435,7 @@ package java.util {
    +     method public abstract java.util.SortedSet<E> tailSet(E);
    +   }
    + 
    +-  public abstract interface Spliterator {
    ++  public abstract interface Spliterator<T> {
    +     method public abstract int characteristics();
    +     method public abstract long estimateSize();
    +     method public default void forEachRemaining(java.util.function.Consumer<? super T>);
    +@@ -62478,7 +62478,7 @@ package java.util {
    +     method public abstract java.util.Spliterator.OfLong trySplit();
    +   }
    + 
    +-  public static abstract interface Spliterator.OfPrimitive implements java.util.Spliterator {
    ++  public static abstract interface Spliterator.OfPrimitive<T, T_CONS, T_SPLITR extends java.util.Spliterator.OfPrimitive<T, T_CONS, T_SPLITR>> implements java.util.Spliterator {
    +     method public default void forEachRemaining(T_CONS);
    +     method public abstract boolean tryAdvance(T_CONS);
    +     method public abstract T_SPLITR trySplit();
    +@@ -62488,25 +62488,25 @@ package java.util {
    +     method public static java.util.Spliterator.OfDouble emptyDoubleSpliterator();
    +     method public static java.util.Spliterator.OfInt emptyIntSpliterator();
    +     method public static java.util.Spliterator.OfLong emptyLongSpliterator();
    +-    method public static java.util.Spliterator<T> emptySpliterator();
    +-    method public static java.util.Iterator<T> iterator(java.util.Spliterator<? extends T>);
    ++    method public static <T> java.util.Spliterator<T> emptySpliterator();
    ++    method public static <T> java.util.Iterator<T> iterator(java.util.Spliterator<? extends T>);
    +     method public static java.util.PrimitiveIterator.OfInt iterator(java.util.Spliterator.OfInt);
    +     method public static java.util.PrimitiveIterator.OfLong iterator(java.util.Spliterator.OfLong);
    +     method public static java.util.PrimitiveIterator.OfDouble iterator(java.util.Spliterator.OfDouble);
    +-    method public static java.util.Spliterator<T> spliterator(java.lang.Object[], int);
    +-    method public static java.util.Spliterator<T> spliterator(java.lang.Object[], int, int, int);
    ++    method public static <T> java.util.Spliterator<T> spliterator(java.lang.Object[], int);
    ++    method public static <T> java.util.Spliterator<T> spliterator(java.lang.Object[], int, int, int);
    +     method public static java.util.Spliterator.OfInt spliterator(int[], int);
    +     method public static java.util.Spliterator.OfInt spliterator(int[], int, int, int);
    +     method public static java.util.Spliterator.OfLong spliterator(long[], int);
    +     method public static java.util.Spliterator.OfLong spliterator(long[], int, int, int);
    +     method public static java.util.Spliterator.OfDouble spliterator(double[], int);
    +     method public static java.util.Spliterator.OfDouble spliterator(double[], int, int, int);
    +-    method public static java.util.Spliterator<T> spliterator(java.util.Collection<? extends T>, int);
    +-    method public static java.util.Spliterator<T> spliterator(java.util.Iterator<? extends T>, long, int);
    ++    method public static <T> java.util.Spliterator<T> spliterator(java.util.Collection<? extends T>, int);
    ++    method public static <T> java.util.Spliterator<T> spliterator(java.util.Iterator<? extends T>, long, int);
    +     method public static java.util.Spliterator.OfInt spliterator(java.util.PrimitiveIterator.OfInt, long, int);
    +     method public static java.util.Spliterator.OfLong spliterator(java.util.PrimitiveIterator.OfLong, long, int);
    +     method public static java.util.Spliterator.OfDouble spliterator(java.util.PrimitiveIterator.OfDouble, long, int);
    +-    method public static java.util.Spliterator<T> spliteratorUnknownSize(java.util.Iterator<? extends T>, int);
    ++    method public static <T> java.util.Spliterator<T> spliteratorUnknownSize(java.util.Iterator<? extends T>, int);
    +     method public static java.util.Spliterator.OfInt spliteratorUnknownSize(java.util.PrimitiveIterator.OfInt, int);
    +     method public static java.util.Spliterator.OfLong spliteratorUnknownSize(java.util.PrimitiveIterator.OfLong, int);
    +     method public static java.util.Spliterator.OfDouble spliteratorUnknownSize(java.util.PrimitiveIterator.OfDouble, int);
    +@@ -62533,7 +62533,7 @@ package java.util {
    +     method public java.util.Spliterator.OfLong trySplit();
    +   }
    + 
    +-  public static abstract class Spliterators.AbstractSpliterator implements java.util.Spliterator {
    ++  public static abstract class Spliterators.AbstractSpliterator<T> implements java.util.Spliterator {
    +     ctor protected Spliterators.AbstractSpliterator(long, int);
    +     method public int characteristics();
    +     method public long estimateSize();
    +@@ -62568,7 +62568,7 @@ package java.util {
    +     method public java.util.SplittableRandom split();
    +   }
    + 
    +-  public class Stack extends java.util.Vector {
    ++  public class Stack<E> extends java.util.Vector {
    +     ctor public Stack();
    +     method public boolean empty();
    +     method public synchronized E peek();
    +@@ -62652,7 +62652,7 @@ package java.util {
    +     ctor public TooManyListenersException(java.lang.String);
    +   }
    + 
    +-  public class TreeMap extends java.util.AbstractMap implements java.lang.Cloneable java.util.NavigableMap java.io.Serializable {
    ++  public class TreeMap<K, V> extends java.util.AbstractMap implements java.lang.Cloneable java.util.NavigableMap java.io.Serializable {
    +     ctor public TreeMap();
    +     ctor public TreeMap(java.util.Comparator<? super K>);
    +     ctor public TreeMap(java.util.Map<? extends K, ? extends V>);
    +@@ -62689,7 +62689,7 @@ package java.util {
    +     method public java.util.SortedMap<K, V> tailMap(K);
    +   }
    + 
    +-  public class TreeSet extends java.util.AbstractSet implements java.lang.Cloneable java.util.NavigableSet java.io.Serializable {
    ++  public class TreeSet<E> extends java.util.AbstractSet implements java.lang.Cloneable java.util.NavigableSet java.io.Serializable {
    +     ctor public TreeSet();
    +     ctor public TreeSet(java.util.Comparator<? super E>);
    +     ctor public TreeSet(java.util.Collection<? extends E>);
    +@@ -62742,7 +62742,7 @@ package java.util {
    +     method public java.lang.String getFlags();
    +   }
    + 
    +-  public class Vector extends java.util.AbstractList implements java.lang.Cloneable java.util.List java.util.RandomAccess java.io.Serializable {
    ++  public class Vector<E> extends java.util.AbstractList implements java.lang.Cloneable java.util.List java.util.RandomAccess java.io.Serializable {
    +     ctor public Vector(int, int);
    +     ctor public Vector(int);
    +     ctor public Vector();
    +@@ -62777,7 +62777,7 @@ package java.util {
    +     field protected java.lang.Object[] elementData;
    +   }
    + 
    +-  public class WeakHashMap extends java.util.AbstractMap implements java.util.Map {
    ++  public class WeakHashMap<K, V> extends java.util.AbstractMap implements java.util.Map {
    +     ctor public WeakHashMap(int, float);
    +     ctor public WeakHashMap(int);
    +     ctor public WeakHashMap();
    +@@ -62793,18 +62793,18 @@ package java.util.concurrent {
    + 
    +   public abstract class AbstractExecutorService implements java.util.concurrent.ExecutorService {
    +     ctor public AbstractExecutorService();
    +-    method public java.util.List<java.util.concurrent.Future<T>> invokeAll(java.util.Collection<? extends java.util.concurrent.Callable<T>>) throws java.lang.InterruptedException;
    +-    method public java.util.List<java.util.concurrent.Future<T>> invokeAll(java.util.Collection<? extends java.util.concurrent.Callable<T>>, long, java.util.concurrent.TimeUnit) throws java.lang.InterruptedException;
    +-    method public T invokeAny(java.util.Collection<? extends java.util.concurrent.Callable<T>>) throws java.util.concurrent.ExecutionException, java.lang.InterruptedException;
    +-    method public T invokeAny(java.util.Collection<? extends java.util.concurrent.Callable<T>>, long, java.util.concurrent.TimeUnit) throws java.util.concurrent.ExecutionException, java.lang.InterruptedException, java.util.concurrent.TimeoutException;
    +-    method protected java.util.concurrent.RunnableFuture<T> newTaskFor(java.lang.Runnable, T);
    +-    method protected java.util.concurrent.RunnableFuture<T> newTaskFor(java.util.concurrent.Callable<T>);
    ++    method public <T> java.util.List<java.util.concurrent.Future<T>> invokeAll(java.util.Collection<? extends java.util.concurrent.Callable<T>>) throws java.lang.InterruptedException;
    ++    method public <T> java.util.List<java.util.concurrent.Future<T>> invokeAll(java.util.Collection<? extends java.util.concurrent.Callable<T>>, long, java.util.concurrent.TimeUnit) throws java.lang.InterruptedException;
    ++    method public <T> T invokeAny(java.util.Collection<? extends java.util.concurrent.Callable<T>>) throws java.util.concurrent.ExecutionException, java.lang.InterruptedException;
    ++    method public <T> T invokeAny(java.util.Collection<? extends java.util.concurrent.Callable<T>>, long, java.util.concurrent.TimeUnit) throws java.util.concurrent.ExecutionException, java.lang.InterruptedException, java.util.concurrent.TimeoutException;
    ++    method protected <T> java.util.concurrent.RunnableFuture<T> newTaskFor(java.lang.Runnable, T);
    ++    method protected <T> java.util.concurrent.RunnableFuture<T> newTaskFor(java.util.concurrent.Callable<T>);
    +     method public java.util.concurrent.Future<?> submit(java.lang.Runnable);
    +-    method public java.util.concurrent.Future<T> submit(java.lang.Runnable, T);
    +-    method public java.util.concurrent.Future<T> submit(java.util.concurrent.Callable<T>);
    ++    method public <T> java.util.concurrent.Future<T> submit(java.lang.Runnable, T);
    ++    method public <T> java.util.concurrent.Future<T> submit(java.util.concurrent.Callable<T>);
    +   }
    + 
    +-  public class ArrayBlockingQueue extends java.util.AbstractQueue implements java.util.concurrent.BlockingQueue java.io.Serializable {
    ++  public class ArrayBlockingQueue<E> extends java.util.AbstractQueue implements java.util.concurrent.BlockingQueue java.io.Serializable {
    +     ctor public ArrayBlockingQueue(int);
    +     ctor public ArrayBlockingQueue(int, boolean);
    +     ctor public ArrayBlockingQueue(int, boolean, java.util.Collection<? extends E>);
    +@@ -62823,7 +62823,7 @@ package java.util.concurrent {
    +     method public E take() throws java.lang.InterruptedException;
    +   }
    + 
    +-  public abstract interface BlockingDeque implements java.util.concurrent.BlockingQueue java.util.Deque {
    ++  public abstract interface BlockingDeque<E> implements java.util.concurrent.BlockingQueue java.util.Deque {
    +     method public abstract boolean add(E);
    +     method public abstract void addFirst(E);
    +     method public abstract void addLast(E);
    +@@ -62855,7 +62855,7 @@ package java.util.concurrent {
    +     method public abstract E takeLast() throws java.lang.InterruptedException;
    +   }
    + 
    +-  public abstract interface BlockingQueue implements java.util.Queue {
    ++  public abstract interface BlockingQueue<E> implements java.util.Queue {
    +     method public abstract boolean add(E);
    +     method public abstract boolean contains(java.lang.Object);
    +     method public abstract int drainTo(java.util.Collection<? super E>);
    +@@ -62874,7 +62874,7 @@ package java.util.concurrent {
    +     ctor public BrokenBarrierException(java.lang.String);
    +   }
    + 
    +-  public abstract interface Callable {
    ++  public abstract interface Callable<V> {
    +     method public abstract V call() throws java.lang.Exception;
    +   }
    + 
    +@@ -62883,28 +62883,28 @@ package java.util.concurrent {
    +     ctor public CancellationException(java.lang.String);
    +   }
    + 
    +-  public class CompletableFuture implements java.util.concurrent.CompletionStage java.util.concurrent.Future {
    ++  public class CompletableFuture<T> implements java.util.concurrent.CompletionStage java.util.concurrent.Future {
    +     ctor public CompletableFuture();
    +     method public java.util.concurrent.CompletableFuture<java.lang.Void> acceptEither(java.util.concurrent.CompletionStage<? extends T>, java.util.function.Consumer<? super T>);
    +     method public java.util.concurrent.CompletableFuture<java.lang.Void> acceptEitherAsync(java.util.concurrent.CompletionStage<? extends T>, java.util.function.Consumer<? super T>);
    +     method public java.util.concurrent.CompletableFuture<java.lang.Void> acceptEitherAsync(java.util.concurrent.CompletionStage<? extends T>, java.util.function.Consumer<? super T>, java.util.concurrent.Executor);
    +     method public static java.util.concurrent.CompletableFuture<java.lang.Void> allOf(java.util.concurrent.CompletableFuture<?>...);
    +     method public static java.util.concurrent.CompletableFuture<java.lang.Object> anyOf(java.util.concurrent.CompletableFuture<?>...);
    +-    method public java.util.concurrent.CompletableFuture<U> applyToEither(java.util.concurrent.CompletionStage<? extends T>, java.util.function.Function<? super T, U>);
    +-    method public java.util.concurrent.CompletableFuture<U> applyToEitherAsync(java.util.concurrent.CompletionStage<? extends T>, java.util.function.Function<? super T, U>);
    +-    method public java.util.concurrent.CompletableFuture<U> applyToEitherAsync(java.util.concurrent.CompletionStage<? extends T>, java.util.function.Function<? super T, U>, java.util.concurrent.Executor);
    ++    method public <U> java.util.concurrent.CompletableFuture<U> applyToEither(java.util.concurrent.CompletionStage<? extends T>, java.util.function.Function<? super T, U>);
    ++    method public <U> java.util.concurrent.CompletableFuture<U> applyToEitherAsync(java.util.concurrent.CompletionStage<? extends T>, java.util.function.Function<? super T, U>);
    ++    method public <U> java.util.concurrent.CompletableFuture<U> applyToEitherAsync(java.util.concurrent.CompletionStage<? extends T>, java.util.function.Function<? super T, U>, java.util.concurrent.Executor);
    +     method public boolean cancel(boolean);
    +     method public boolean complete(T);
    +     method public boolean completeExceptionally(java.lang.Throwable);
    +-    method public static java.util.concurrent.CompletableFuture<U> completedFuture(U);
    ++    method public static <U> java.util.concurrent.CompletableFuture<U> completedFuture(U);
    +     method public java.util.concurrent.CompletableFuture<T> exceptionally(java.util.function.Function<java.lang.Throwable, ? extends T>);
    +     method public T get() throws java.util.concurrent.ExecutionException, java.lang.InterruptedException;
    +     method public T get(long, java.util.concurrent.TimeUnit) throws java.util.concurrent.ExecutionException, java.lang.InterruptedException, java.util.concurrent.TimeoutException;
    +     method public T getNow(T);
    +     method public int getNumberOfDependents();
    +-    method public java.util.concurrent.CompletableFuture<U> handle(java.util.function.BiFunction<? super T, java.lang.Throwable, ? extends U>);
    +-    method public java.util.concurrent.CompletableFuture<U> handleAsync(java.util.function.BiFunction<? super T, java.lang.Throwable, ? extends U>);
    +-    method public java.util.concurrent.CompletableFuture<U> handleAsync(java.util.function.BiFunction<? super T, java.lang.Throwable, ? extends U>, java.util.concurrent.Executor);
    ++    method public <U> java.util.concurrent.CompletableFuture<U> handle(java.util.function.BiFunction<? super T, java.lang.Throwable, ? extends U>);
    ++    method public <U> java.util.concurrent.CompletableFuture<U> handleAsync(java.util.function.BiFunction<? super T, java.lang.Throwable, ? extends U>);
    ++    method public <U> java.util.concurrent.CompletableFuture<U> handleAsync(java.util.function.BiFunction<? super T, java.lang.Throwable, ? extends U>, java.util.concurrent.Executor);
    +     method public boolean isCancelled();
    +     method public boolean isCompletedExceptionally();
    +     method public boolean isDone();
    +@@ -62919,23 +62919,23 @@ package java.util.concurrent {
    +     method public java.util.concurrent.CompletableFuture<java.lang.Void> runAfterEitherAsync(java.util.concurrent.CompletionStage<?>, java.lang.Runnable, java.util.concurrent.Executor);
    +     method public static java.util.concurrent.CompletableFuture<java.lang.Void> runAsync(java.lang.Runnable);
    +     method public static java.util.concurrent.CompletableFuture<java.lang.Void> runAsync(java.lang.Runnable, java.util.concurrent.Executor);
    +-    method public static java.util.concurrent.CompletableFuture<U> supplyAsync(java.util.function.Supplier<U>);
    +-    method public static java.util.concurrent.CompletableFuture<U> supplyAsync(java.util.function.Supplier<U>, java.util.concurrent.Executor);
    ++    method public static <U> java.util.concurrent.CompletableFuture<U> supplyAsync(java.util.function.Supplier<U>);
    ++    method public static <U> java.util.concurrent.CompletableFuture<U> supplyAsync(java.util.function.Supplier<U>, java.util.concurrent.Executor);
    +     method public java.util.concurrent.CompletableFuture<java.lang.Void> thenAccept(java.util.function.Consumer<? super T>);
    +     method public java.util.concurrent.CompletableFuture<java.lang.Void> thenAcceptAsync(java.util.function.Consumer<? super T>);
    +     method public java.util.concurrent.CompletableFuture<java.lang.Void> thenAcceptAsync(java.util.function.Consumer<? super T>, java.util.concurrent.Executor);
    +-    method public java.util.concurrent.CompletableFuture<java.lang.Void> thenAcceptBoth(java.util.concurrent.CompletionStage<? extends U>, java.util.function.BiConsumer<? super T, ? super U>);
    +-    method public java.util.concurrent.CompletableFuture<java.lang.Void> thenAcceptBothAsync(java.util.concurrent.CompletionStage<? extends U>, java.util.function.BiConsumer<? super T, ? super U>);
    +-    method public java.util.concurrent.CompletableFuture<java.lang.Void> thenAcceptBothAsync(java.util.concurrent.CompletionStage<? extends U>, java.util.function.BiConsumer<? super T, ? super U>, java.util.concurrent.Executor);
    +-    method public java.util.concurrent.CompletableFuture<U> thenApply(java.util.function.Function<? super T, ? extends U>);
    +-    method public java.util.concurrent.CompletableFuture<U> thenApplyAsync(java.util.function.Function<? super T, ? extends U>);
    +-    method public java.util.concurrent.CompletableFuture<U> thenApplyAsync(java.util.function.Function<? super T, ? extends U>, java.util.concurrent.Executor);
    +-    method public java.util.concurrent.CompletableFuture<V> thenCombine(java.util.concurrent.CompletionStage<? extends U>, java.util.function.BiFunction<? super T, ? super U, ? extends V>);
    +-    method public java.util.concurrent.CompletableFuture<V> thenCombineAsync(java.util.concurrent.CompletionStage<? extends U>, java.util.function.BiFunction<? super T, ? super U, ? extends V>);
    +-    method public java.util.concurrent.CompletableFuture<V> thenCombineAsync(java.util.concurrent.CompletionStage<? extends U>, java.util.function.BiFunction<? super T, ? super U, ? extends V>, java.util.concurrent.Executor);
    +-    method public java.util.concurrent.CompletableFuture<U> thenCompose(java.util.function.Function<? super T, ? extends java.util.concurrent.CompletionStage<U>>);
    +-    method public java.util.concurrent.CompletableFuture<U> thenComposeAsync(java.util.function.Function<? super T, ? extends java.util.concurrent.CompletionStage<U>>);
    +-    method public java.util.concurrent.CompletableFuture<U> thenComposeAsync(java.util.function.Function<? super T, ? extends java.util.concurrent.CompletionStage<U>>, java.util.concurrent.Executor);
    ++    method public <U> java.util.concurrent.CompletableFuture<java.lang.Void> thenAcceptBoth(java.util.concurrent.CompletionStage<? extends U>, java.util.function.BiConsumer<? super T, ? super U>);
    ++    method public <U> java.util.concurrent.CompletableFuture<java.lang.Void> thenAcceptBothAsync(java.util.concurrent.CompletionStage<? extends U>, java.util.function.BiConsumer<? super T, ? super U>);
    ++    method public <U> java.util.concurrent.CompletableFuture<java.lang.Void> thenAcceptBothAsync(java.util.concurrent.CompletionStage<? extends U>, java.util.function.BiConsumer<? super T, ? super U>, java.util.concurrent.Executor);
    ++    method public <U> java.util.concurrent.CompletableFuture<U> thenApply(java.util.function.Function<? super T, ? extends U>);
    ++    method public <U> java.util.concurrent.CompletableFuture<U> thenApplyAsync(java.util.function.Function<? super T, ? extends U>);
    ++    method public <U> java.util.concurrent.CompletableFuture<U> thenApplyAsync(java.util.function.Function<? super T, ? extends U>, java.util.concurrent.Executor);
    ++    method public <U, V> java.util.concurrent.CompletableFuture<V> thenCombine(java.util.concurrent.CompletionStage<? extends U>, java.util.function.BiFunction<? super T, ? super U, ? extends V>);
    ++    method public <U, V> java.util.concurrent.CompletableFuture<V> thenCombineAsync(java.util.concurrent.CompletionStage<? extends U>, java.util.function.BiFunction<? super T, ? super U, ? extends V>);
    ++    method public <U, V> java.util.concurrent.CompletableFuture<V> thenCombineAsync(java.util.concurrent.CompletionStage<? extends U>, java.util.function.BiFunction<? super T, ? super U, ? extends V>, java.util.concurrent.Executor);
    ++    method public <U> java.util.concurrent.CompletableFuture<U> thenCompose(java.util.function.Function<? super T, ? extends java.util.concurrent.CompletionStage<U>>);
    ++    method public <U> java.util.concurrent.CompletableFuture<U> thenComposeAsync(java.util.function.Function<? super T, ? extends java.util.concurrent.CompletionStage<U>>);
    ++    method public <U> java.util.concurrent.CompletableFuture<U> thenComposeAsync(java.util.function.Function<? super T, ? extends java.util.concurrent.CompletionStage<U>>, java.util.concurrent.Executor);
    +     method public java.util.concurrent.CompletableFuture<java.lang.Void> thenRun(java.lang.Runnable);
    +     method public java.util.concurrent.CompletableFuture<java.lang.Void> thenRunAsync(java.lang.Runnable);
    +     method public java.util.concurrent.CompletableFuture<java.lang.Void> thenRunAsync(java.lang.Runnable, java.util.concurrent.Executor);
    +@@ -62955,7 +62955,7 @@ package java.util.concurrent {
    +     ctor public CompletionException(java.lang.Throwable);
    +   }
    + 
    +-  public abstract interface CompletionService {
    ++  public abstract interface CompletionService<V> {
    +     method public abstract java.util.concurrent.Future<V> poll();
    +     method public abstract java.util.concurrent.Future<V> poll(long, java.util.concurrent.TimeUnit) throws java.lang.InterruptedException;
    +     method public abstract java.util.concurrent.Future<V> submit(java.util.concurrent.Callable<V>);
    +@@ -62963,17 +62963,17 @@ package java.util.concurrent {
    +     method public abstract java.util.concurrent.Future<V> take() throws java.lang.InterruptedException;
    +   }
    + 
    +-  public abstract interface CompletionStage {
    ++  public abstract interface CompletionStage<T> {
    +     method public abstract java.util.concurrent.CompletionStage<java.lang.Void> acceptEither(java.util.concurrent.CompletionStage<? extends T>, java.util.function.Consumer<? super T>);
    +     method public abstract java.util.concurrent.CompletionStage<java.lang.Void> acceptEitherAsync(java.util.concurrent.CompletionStage<? extends T>, java.util.function.Consumer<? super T>);
    +     method public abstract java.util.concurrent.CompletionStage<java.lang.Void> acceptEitherAsync(java.util.concurrent.CompletionStage<? extends T>, java.util.function.Consumer<? super T>, java.util.concurrent.Executor);
    +-    method public abstract java.util.concurrent.CompletionStage<U> applyToEither(java.util.concurrent.CompletionStage<? extends T>, java.util.function.Function<? super T, U>);
    +-    method public abstract java.util.concurrent.CompletionStage<U> applyToEitherAsync(java.util.concurrent.CompletionStage<? extends T>, java.util.function.Function<? super T, U>);
    +-    method public abstract java.util.concurrent.CompletionStage<U> applyToEitherAsync(java.util.concurrent.CompletionStage<? extends T>, java.util.function.Function<? super T, U>, java.util.concurrent.Executor);
    ++    method public abstract <U> java.util.concurrent.CompletionStage<U> applyToEither(java.util.concurrent.CompletionStage<? extends T>, java.util.function.Function<? super T, U>);
    ++    method public abstract <U> java.util.concurrent.CompletionStage<U> applyToEitherAsync(java.util.concurrent.CompletionStage<? extends T>, java.util.function.Function<? super T, U>);
    ++    method public abstract <U> java.util.concurrent.CompletionStage<U> applyToEitherAsync(java.util.concurrent.CompletionStage<? extends T>, java.util.function.Function<? super T, U>, java.util.concurrent.Executor);
    +     method public abstract java.util.concurrent.CompletionStage<T> exceptionally(java.util.function.Function<java.lang.Throwable, ? extends T>);
    +-    method public abstract java.util.concurrent.CompletionStage<U> handle(java.util.function.BiFunction<? super T, java.lang.Throwable, ? extends U>);
    +-    method public abstract java.util.concurrent.CompletionStage<U> handleAsync(java.util.function.BiFunction<? super T, java.lang.Throwable, ? extends U>);
    +-    method public abstract java.util.concurrent.CompletionStage<U> handleAsync(java.util.function.BiFunction<? super T, java.lang.Throwable, ? extends U>, java.util.concurrent.Executor);
    ++    method public abstract <U> java.util.concurrent.CompletionStage<U> handle(java.util.function.BiFunction<? super T, java.lang.Throwable, ? extends U>);
    ++    method public abstract <U> java.util.concurrent.CompletionStage<U> handleAsync(java.util.function.BiFunction<? super T, java.lang.Throwable, ? extends U>);
    ++    method public abstract <U> java.util.concurrent.CompletionStage<U> handleAsync(java.util.function.BiFunction<? super T, java.lang.Throwable, ? extends U>, java.util.concurrent.Executor);
    +     method public abstract java.util.concurrent.CompletionStage<java.lang.Void> runAfterBoth(java.util.concurrent.CompletionStage<?>, java.lang.Runnable);
    +     method public abstract java.util.concurrent.CompletionStage<java.lang.Void> runAfterBothAsync(java.util.concurrent.CompletionStage<?>, java.lang.Runnable);
    +     method public abstract java.util.concurrent.CompletionStage<java.lang.Void> runAfterBothAsync(java.util.concurrent.CompletionStage<?>, java.lang.Runnable, java.util.concurrent.Executor);
    +@@ -62983,18 +62983,18 @@ package java.util.concurrent {
    +     method public abstract java.util.concurrent.CompletionStage<java.lang.Void> thenAccept(java.util.function.Consumer<? super T>);
    +     method public abstract java.util.concurrent.CompletionStage<java.lang.Void> thenAcceptAsync(java.util.function.Consumer<? super T>);
    +     method public abstract java.util.concurrent.CompletionStage<java.lang.Void> thenAcceptAsync(java.util.function.Consumer<? super T>, java.util.concurrent.Executor);
    +-    method public abstract java.util.concurrent.CompletionStage<java.lang.Void> thenAcceptBoth(java.util.concurrent.CompletionStage<? extends U>, java.util.function.BiConsumer<? super T, ? super U>);
    +-    method public abstract java.util.concurrent.CompletionStage<java.lang.Void> thenAcceptBothAsync(java.util.concurrent.CompletionStage<? extends U>, java.util.function.BiConsumer<? super T, ? super U>);
    +-    method public abstract java.util.concurrent.CompletionStage<java.lang.Void> thenAcceptBothAsync(java.util.concurrent.CompletionStage<? extends U>, java.util.function.BiConsumer<? super T, ? super U>, java.util.concurrent.Executor);
    +-    method public abstract java.util.concurrent.CompletionStage<U> thenApply(java.util.function.Function<? super T, ? extends U>);
    +-    method public abstract java.util.concurrent.CompletionStage<U> thenApplyAsync(java.util.function.Function<? super T, ? extends U>);
    +-    method public abstract java.util.concurrent.CompletionStage<U> thenApplyAsync(java.util.function.Function<? super T, ? extends U>, java.util.concurrent.Executor);
    +-    method public abstract java.util.concurrent.CompletionStage<V> thenCombine(java.util.concurrent.CompletionStage<? extends U>, java.util.function.BiFunction<? super T, ? super U, ? extends V>);
    +-    method public abstract java.util.concurrent.CompletionStage<V> thenCombineAsync(java.util.concurrent.CompletionStage<? extends U>, java.util.function.BiFunction<? super T, ? super U, ? extends V>);
    +-    method public abstract java.util.concurrent.CompletionStage<V> thenCombineAsync(java.util.concurrent.CompletionStage<? extends U>, java.util.function.BiFunction<? super T, ? super U, ? extends V>, java.util.concurrent.Executor);
    +-    method public abstract java.util.concurrent.CompletionStage<U> thenCompose(java.util.function.Function<? super T, ? extends java.util.concurrent.CompletionStage<U>>);
    +-    method public abstract java.util.concurrent.CompletionStage<U> thenComposeAsync(java.util.function.Function<? super T, ? extends java.util.concurrent.CompletionStage<U>>);
    +-    method public abstract java.util.concurrent.CompletionStage<U> thenComposeAsync(java.util.function.Function<? super T, ? extends java.util.concurrent.CompletionStage<U>>, java.util.concurrent.Executor);
    ++    method public abstract <U> java.util.concurrent.CompletionStage<java.lang.Void> thenAcceptBoth(java.util.concurrent.CompletionStage<? extends U>, java.util.function.BiConsumer<? super T, ? super U>);
    ++    method public abstract <U> java.util.concurrent.CompletionStage<java.lang.Void> thenAcceptBothAsync(java.util.concurrent.CompletionStage<? extends U>, java.util.function.BiConsumer<? super T, ? super U>);
    ++    method public abstract <U> java.util.concurrent.CompletionStage<java.lang.Void> thenAcceptBothAsync(java.util.concurrent.CompletionStage<? extends U>, java.util.function.BiConsumer<? super T, ? super U>, java.util.concurrent.Executor);
    ++    method public abstract <U> java.util.concurrent.CompletionStage<U> thenApply(java.util.function.Function<? super T, ? extends U>);
    ++    method public abstract <U> java.util.concurrent.CompletionStage<U> thenApplyAsync(java.util.function.Function<? super T, ? extends U>);
    ++    method public abstract <U> java.util.concurrent.CompletionStage<U> thenApplyAsync(java.util.function.Function<? super T, ? extends U>, java.util.concurrent.Executor);
    ++    method public abstract <U, V> java.util.concurrent.CompletionStage<V> thenCombine(java.util.concurrent.CompletionStage<? extends U>, java.util.function.BiFunction<? super T, ? super U, ? extends V>);
    ++    method public abstract <U, V> java.util.concurrent.CompletionStage<V> thenCombineAsync(java.util.concurrent.CompletionStage<? extends U>, java.util.function.BiFunction<? super T, ? super U, ? extends V>);
    ++    method public abstract <U, V> java.util.concurrent.CompletionStage<V> thenCombineAsync(java.util.concurrent.CompletionStage<? extends U>, java.util.function.BiFunction<? super T, ? super U, ? extends V>, java.util.concurrent.Executor);
    ++    method public abstract <U> java.util.concurrent.CompletionStage<U> thenCompose(java.util.function.Function<? super T, ? extends java.util.concurrent.CompletionStage<U>>);
    ++    method public abstract <U> java.util.concurrent.CompletionStage<U> thenComposeAsync(java.util.function.Function<? super T, ? extends java.util.concurrent.CompletionStage<U>>);
    ++    method public abstract <U> java.util.concurrent.CompletionStage<U> thenComposeAsync(java.util.function.Function<? super T, ? extends java.util.concurrent.CompletionStage<U>>, java.util.concurrent.Executor);
    +     method public abstract java.util.concurrent.CompletionStage<java.lang.Void> thenRun(java.lang.Runnable);
    +     method public abstract java.util.concurrent.CompletionStage<java.lang.Void> thenRunAsync(java.lang.Runnable);
    +     method public abstract java.util.concurrent.CompletionStage<java.lang.Void> thenRunAsync(java.lang.Runnable, java.util.concurrent.Executor);
    +@@ -63004,7 +63004,7 @@ package java.util.concurrent {
    +     method public abstract java.util.concurrent.CompletionStage<T> whenCompleteAsync(java.util.function.BiConsumer<? super T, ? super java.lang.Throwable>, java.util.concurrent.Executor);
    +   }
    + 
    +-  public class ConcurrentHashMap extends java.util.AbstractMap implements java.util.concurrent.ConcurrentMap java.io.Serializable {
    ++  public class ConcurrentHashMap<K, V> extends java.util.AbstractMap implements java.util.concurrent.ConcurrentMap java.io.Serializable {
    +     ctor public ConcurrentHashMap();
    +     ctor public ConcurrentHashMap(int);
    +     ctor public ConcurrentHashMap(java.util.Map<? extends K, ? extends V>);
    +@@ -63018,29 +63018,29 @@ package java.util.concurrent {
    +     method public java.util.Set<java.util.Map.Entry<K, V>> entrySet();
    +     method public void forEach(java.util.function.BiConsumer<? super K, ? super V>);
    +     method public void forEach(long, java.util.function.BiConsumer<? super K, ? super V>);
    +-    method public void forEach(long, java.util.function.BiFunction<? super K, ? super V, ? extends U>, java.util.function.Consumer<? super U>);
    ++    method public <U> void forEach(long, java.util.function.BiFunction<? super K, ? super V, ? extends U>, java.util.function.Consumer<? super U>);
    +     method public void forEachEntry(long, java.util.function.Consumer<? super java.util.Map.Entry<K, V>>);
    +-    method public void forEachEntry(long, java.util.function.Function<java.util.Map.Entry<K, V>, ? extends U>, java.util.function.Consumer<? super U>);
    ++    method public <U> void forEachEntry(long, java.util.function.Function<java.util.Map.Entry<K, V>, ? extends U>, java.util.function.Consumer<? super U>);
    +     method public void forEachKey(long, java.util.function.Consumer<? super K>);
    +-    method public void forEachKey(long, java.util.function.Function<? super K, ? extends U>, java.util.function.Consumer<? super U>);
    ++    method public <U> void forEachKey(long, java.util.function.Function<? super K, ? extends U>, java.util.function.Consumer<? super U>);
    +     method public void forEachValue(long, java.util.function.Consumer<? super V>);
    +-    method public void forEachValue(long, java.util.function.Function<? super V, ? extends U>, java.util.function.Consumer<? super U>);
    ++    method public <U> void forEachValue(long, java.util.function.Function<? super V, ? extends U>, java.util.function.Consumer<? super U>);
    +     method public V getOrDefault(java.lang.Object, V);
    +     method public java.util.concurrent.ConcurrentHashMap.KeySetView<K, V> keySet(V);
    +     method public java.util.Enumeration<K> keys();
    +     method public long mappingCount();
    +     method public V merge(K, V, java.util.function.BiFunction<? super V, ? super V, ? extends V>);
    +-    method public static java.util.concurrent.ConcurrentHashMap.KeySetView<K, java.lang.Boolean> newKeySet();
    +-    method public static java.util.concurrent.ConcurrentHashMap.KeySetView<K, java.lang.Boolean> newKeySet(int);
    ++    method public static <K> java.util.concurrent.ConcurrentHashMap.KeySetView<K, java.lang.Boolean> newKeySet();
    ++    method public static <K> java.util.concurrent.ConcurrentHashMap.KeySetView<K, java.lang.Boolean> newKeySet(int);
    +     method public V putIfAbsent(K, V);
    +-    method public U reduce(long, java.util.function.BiFunction<? super K, ? super V, ? extends U>, java.util.function.BiFunction<? super U, ? super U, ? extends U>);
    ++    method public <U> U reduce(long, java.util.function.BiFunction<? super K, ? super V, ? extends U>, java.util.function.BiFunction<? super U, ? super U, ? extends U>);
    +     method public java.util.Map.Entry<K, V> reduceEntries(long, java.util.function.BiFunction<java.util.Map.Entry<K, V>, java.util.Map.Entry<K, V>, ? extends java.util.Map.Entry<K, V>>);
    +-    method public U reduceEntries(long, java.util.function.Function<java.util.Map.Entry<K, V>, ? extends U>, java.util.function.BiFunction<? super U, ? super U, ? extends U>);
    ++    method public <U> U reduceEntries(long, java.util.function.Function<java.util.Map.Entry<K, V>, ? extends U>, java.util.function.BiFunction<? super U, ? super U, ? extends U>);
    +     method public double reduceEntriesToDouble(long, java.util.function.ToDoubleFunction<java.util.Map.Entry<K, V>>, double, java.util.function.DoubleBinaryOperator);
    +     method public int reduceEntriesToInt(long, java.util.function.ToIntFunction<java.util.Map.Entry<K, V>>, int, java.util.function.IntBinaryOperator);
    +     method public long reduceEntriesToLong(long, java.util.function.ToLongFunction<java.util.Map.Entry<K, V>>, long, java.util.function.LongBinaryOperator);
    +     method public K reduceKeys(long, java.util.function.BiFunction<? super K, ? super K, ? extends K>);
    +-    method public U reduceKeys(long, java.util.function.Function<? super K, ? extends U>, java.util.function.BiFunction<? super U, ? super U, ? extends U>);
    ++    method public <U> U reduceKeys(long, java.util.function.Function<? super K, ? extends U>, java.util.function.BiFunction<? super U, ? super U, ? extends U>);
    +     method public double reduceKeysToDouble(long, java.util.function.ToDoubleFunction<? super K>, double, java.util.function.DoubleBinaryOperator);
    +     method public int reduceKeysToInt(long, java.util.function.ToIntFunction<? super K>, int, java.util.function.IntBinaryOperator);
    +     method public long reduceKeysToLong(long, java.util.function.ToLongFunction<? super K>, long, java.util.function.LongBinaryOperator);
    +@@ -63048,7 +63048,7 @@ package java.util.concurrent {
    +     method public int reduceToInt(long, java.util.function.ToIntBiFunction<? super K, ? super V>, int, java.util.function.IntBinaryOperator);
    +     method public long reduceToLong(long, java.util.function.ToLongBiFunction<? super K, ? super V>, long, java.util.function.LongBinaryOperator);
    +     method public V reduceValues(long, java.util.function.BiFunction<? super V, ? super V, ? extends V>);
    +-    method public U reduceValues(long, java.util.function.Function<? super V, ? extends U>, java.util.function.BiFunction<? super U, ? super U, ? extends U>);
    ++    method public <U> U reduceValues(long, java.util.function.Function<? super V, ? extends U>, java.util.function.BiFunction<? super U, ? super U, ? extends U>);
    +     method public double reduceValuesToDouble(long, java.util.function.ToDoubleFunction<? super V>, double, java.util.function.DoubleBinaryOperator);
    +     method public int reduceValuesToInt(long, java.util.function.ToIntFunction<? super V>, int, java.util.function.IntBinaryOperator);
    +     method public long reduceValuesToLong(long, java.util.function.ToLongFunction<? super V>, long, java.util.function.LongBinaryOperator);
    +@@ -63056,13 +63056,13 @@ package java.util.concurrent {
    +     method public boolean replace(K, V, V);
    +     method public V replace(K, V);
    +     method public void replaceAll(java.util.function.BiFunction<? super K, ? super V, ? extends V>);
    +-    method public U search(long, java.util.function.BiFunction<? super K, ? super V, ? extends U>);
    +-    method public U searchEntries(long, java.util.function.Function<java.util.Map.Entry<K, V>, ? extends U>);
    +-    method public U searchKeys(long, java.util.function.Function<? super K, ? extends U>);
    +-    method public U searchValues(long, java.util.function.Function<? super V, ? extends U>);
    ++    method public <U> U search(long, java.util.function.BiFunction<? super K, ? super V, ? extends U>);
    ++    method public <U> U searchEntries(long, java.util.function.Function<java.util.Map.Entry<K, V>, ? extends U>);
    ++    method public <U> U searchKeys(long, java.util.function.Function<? super K, ? extends U>);
    ++    method public <U> U searchValues(long, java.util.function.Function<? super V, ? extends U>);
    +   }
    + 
    +-   static abstract class ConcurrentHashMap.CollectionView implements java.util.Collection java.io.Serializable {
    ++   static abstract class ConcurrentHashMap.CollectionView<K, V, E> implements java.util.Collection java.io.Serializable {
    +     method public final void clear();
    +     method public abstract boolean contains(java.lang.Object);
    +     method public final boolean containsAll(java.util.Collection<?>);
    +@@ -63074,11 +63074,11 @@ package java.util.concurrent {
    +     method public final boolean retainAll(java.util.Collection<?>);
    +     method public final int size();
    +     method public final java.lang.Object[] toArray();
    +-    method public final T[] toArray(T[]);
    ++    method public final <T> T[] toArray(T[]);
    +     method public final java.lang.String toString();
    +   }
    + 
    +-  public static class ConcurrentHashMap.KeySetView extends java.util.concurrent.ConcurrentHashMap.CollectionView implements java.io.Serializable java.util.Set {
    ++  public static class ConcurrentHashMap.KeySetView<K, V> extends java.util.concurrent.ConcurrentHashMap.CollectionView implements java.io.Serializable java.util.Set {
    +     method public boolean add(K);
    +     method public boolean addAll(java.util.Collection<? extends K>);
    +     method public boolean contains(java.lang.Object);
    +@@ -63089,7 +63089,7 @@ package java.util.concurrent {
    +     method public java.util.Spliterator<K> spliterator();
    +   }
    + 
    +-  public class ConcurrentLinkedDeque extends java.util.AbstractCollection implements java.util.Deque java.io.Serializable {
    ++  public class ConcurrentLinkedDeque<E> extends java.util.AbstractCollection implements java.util.Deque java.io.Serializable {
    +     ctor public ConcurrentLinkedDeque();
    +     ctor public ConcurrentLinkedDeque(java.util.Collection<? extends E>);
    +     method public void addFirst(E);
    +@@ -63119,7 +63119,7 @@ package java.util.concurrent {
    +     method public java.util.Spliterator<E> spliterator();
    +   }
    + 
    +-  public class ConcurrentLinkedQueue extends java.util.AbstractQueue implements java.util.Queue java.io.Serializable {
    ++  public class ConcurrentLinkedQueue<E> extends java.util.AbstractQueue implements java.util.Queue java.io.Serializable {
    +     ctor public ConcurrentLinkedQueue();
    +     ctor public ConcurrentLinkedQueue(java.util.Collection<? extends E>);
    +     method public java.util.Iterator<E> iterator();
    +@@ -63130,14 +63130,14 @@ package java.util.concurrent {
    +     method public java.util.Spliterator<E> spliterator();
    +   }
    + 
    +-  public abstract interface ConcurrentMap implements java.util.Map {
    ++  public abstract interface ConcurrentMap<K, V> implements java.util.Map {
    +     method public abstract V putIfAbsent(K, V);
    +     method public abstract boolean remove(java.lang.Object, java.lang.Object);
    +     method public abstract boolean replace(K, V, V);
    +     method public abstract V replace(K, V);
    +   }
    + 
    +-  public abstract interface ConcurrentNavigableMap implements java.util.concurrent.ConcurrentMap java.util.NavigableMap {
    ++  public abstract interface ConcurrentNavigableMap<K, V> implements java.util.concurrent.ConcurrentMap java.util.NavigableMap {
    +     method public abstract java.util.NavigableSet<K> descendingKeySet();
    +     method public abstract java.util.concurrent.ConcurrentNavigableMap<K, V> descendingMap();
    +     method public abstract java.util.concurrent.ConcurrentNavigableMap<K, V> headMap(K, boolean);
    +@@ -63150,7 +63150,7 @@ package java.util.concurrent {
    +     method public abstract java.util.concurrent.ConcurrentNavigableMap<K, V> tailMap(K);
    +   }
    + 
    +-  public class ConcurrentSkipListMap extends java.util.AbstractMap implements java.lang.Cloneable java.util.concurrent.ConcurrentNavigableMap java.io.Serializable {
    ++  public class ConcurrentSkipListMap<K, V> extends java.util.AbstractMap implements java.lang.Cloneable java.util.concurrent.ConcurrentNavigableMap java.io.Serializable {
    +     ctor public ConcurrentSkipListMap();
    +     ctor public ConcurrentSkipListMap(java.util.Comparator<? super K>);
    +     ctor public ConcurrentSkipListMap(java.util.Map<? extends K, ? extends V>);
    +@@ -63194,7 +63194,7 @@ package java.util.concurrent {
    +     method public java.util.concurrent.ConcurrentNavigableMap<K, V> tailMap(K);
    +   }
    + 
    +-  public class ConcurrentSkipListSet extends java.util.AbstractSet implements java.lang.Cloneable java.util.NavigableSet java.io.Serializable {
    ++  public class ConcurrentSkipListSet<E> extends java.util.AbstractSet implements java.lang.Cloneable java.util.NavigableSet java.io.Serializable {
    +     ctor public ConcurrentSkipListSet();
    +     ctor public ConcurrentSkipListSet(java.util.Comparator<? super E>);
    +     ctor public ConcurrentSkipListSet(java.util.Collection<? extends E>);
    +@@ -63222,7 +63222,7 @@ package java.util.concurrent {
    +     method public java.util.NavigableSet<E> tailSet(E);
    +   }
    + 
    +-  public class CopyOnWriteArrayList implements java.lang.Cloneable java.util.List java.util.RandomAccess java.io.Serializable {
    ++  public class CopyOnWriteArrayList<E> implements java.lang.Cloneable java.util.List java.util.RandomAccess java.io.Serializable {
    +     ctor public CopyOnWriteArrayList();
    +     ctor public CopyOnWriteArrayList(java.util.Collection<? extends E>);
    +     ctor public CopyOnWriteArrayList(E[]);
    +@@ -63254,10 +63254,10 @@ package java.util.concurrent {
    +     method public int size();
    +     method public java.util.List<E> subList(int, int);
    +     method public java.lang.Object[] toArray();
    +-    method public T[] toArray(T[]);
    ++    method public <T> T[] toArray(T[]);
    +   }
    + 
    +-  public class CopyOnWriteArraySet extends java.util.AbstractSet implements java.io.Serializable {
    ++  public class CopyOnWriteArraySet<E> extends java.util.AbstractSet implements java.io.Serializable {
    +     ctor public CopyOnWriteArraySet();
    +     ctor public CopyOnWriteArraySet(java.util.Collection<? extends E>);
    +     method public void forEach(java.util.function.Consumer<? super E>);
    +@@ -63275,7 +63275,7 @@ package java.util.concurrent {
    +     method public long getCount();
    +   }
    + 
    +-  public abstract class CountedCompleter extends java.util.concurrent.ForkJoinTask {
    ++  public abstract class CountedCompleter<T> extends java.util.concurrent.ForkJoinTask {
    +     ctor protected CountedCompleter(java.util.concurrent.CountedCompleter<?>, int);
    +     ctor protected CountedCompleter(java.util.concurrent.CountedCompleter<?>);
    +     ctor protected CountedCompleter();
    +@@ -63312,7 +63312,7 @@ package java.util.concurrent {
    +     method public void reset();
    +   }
    + 
    +-  public class DelayQueue extends java.util.AbstractQueue implements java.util.concurrent.BlockingQueue {
    ++  public class DelayQueue<E extends java.util.concurrent.Delayed> extends java.util.AbstractQueue implements java.util.concurrent.BlockingQueue {
    +     ctor public DelayQueue();
    +     ctor public DelayQueue(java.util.Collection<? extends E>);
    +     method public int drainTo(java.util.Collection<? super E>);
    +@@ -63333,7 +63333,7 @@ package java.util.concurrent {
    +     method public abstract long getDelay(java.util.concurrent.TimeUnit);
    +   }
    + 
    +-  public class Exchanger {
    ++  public class Exchanger<V> {
    +     ctor public Exchanger();
    +     method public V exchange(V) throws java.lang.InterruptedException;
    +     method public V exchange(V, long, java.util.concurrent.TimeUnit) throws java.lang.InterruptedException, java.util.concurrent.TimeoutException;
    +@@ -63350,7 +63350,7 @@ package java.util.concurrent {
    +     method public abstract void execute(java.lang.Runnable);
    +   }
    + 
    +-  public class ExecutorCompletionService implements java.util.concurrent.CompletionService {
    ++  public class ExecutorCompletionService<V> implements java.util.concurrent.CompletionService {
    +     ctor public ExecutorCompletionService(java.util.concurrent.Executor);
    +     ctor public ExecutorCompletionService(java.util.concurrent.Executor, java.util.concurrent.BlockingQueue<java.util.concurrent.Future<V>>);
    +     method public java.util.concurrent.Future<V> poll();
    +@@ -63362,21 +63362,21 @@ package java.util.concurrent {
    + 
    +   public abstract interface ExecutorService implements java.util.concurrent.Executor {
    +     method public abstract boolean awaitTermination(long, java.util.concurrent.TimeUnit) throws java.lang.InterruptedException;
    +-    method public abstract java.util.List<java.util.concurrent.Future<T>> invokeAll(java.util.Collection<? extends java.util.concurrent.Callable<T>>) throws java.lang.InterruptedException;
    +-    method public abstract java.util.List<java.util.concurrent.Future<T>> invokeAll(java.util.Collection<? extends java.util.concurrent.Callable<T>>, long, java.util.concurrent.TimeUnit) throws java.lang.InterruptedException;
    +-    method public abstract T invokeAny(java.util.Collection<? extends java.util.concurrent.Callable<T>>) throws java.util.concurrent.ExecutionException, java.lang.InterruptedException;
    +-    method public abstract T invokeAny(java.util.Collection<? extends java.util.concurrent.Callable<T>>, long, java.util.concurrent.TimeUnit) throws java.util.concurrent.ExecutionException, java.lang.InterruptedException, java.util.concurrent.TimeoutException;
    ++    method public abstract <T> java.util.List<java.util.concurrent.Future<T>> invokeAll(java.util.Collection<? extends java.util.concurrent.Callable<T>>) throws java.lang.InterruptedException;
    ++    method public abstract <T> java.util.List<java.util.concurrent.Future<T>> invokeAll(java.util.Collection<? extends java.util.concurrent.Callable<T>>, long, java.util.concurrent.TimeUnit) throws java.lang.InterruptedException;
    ++    method public abstract <T> T invokeAny(java.util.Collection<? extends java.util.concurrent.Callable<T>>) throws java.util.concurrent.ExecutionException, java.lang.InterruptedException;
    ++    method public abstract <T> T invokeAny(java.util.Collection<? extends java.util.concurrent.Callable<T>>, long, java.util.concurrent.TimeUnit) throws java.util.concurrent.ExecutionException, java.lang.InterruptedException, java.util.concurrent.TimeoutException;
    +     method public abstract boolean isShutdown();
    +     method public abstract boolean isTerminated();
    +     method public abstract void shutdown();
    +     method public abstract java.util.List<java.lang.Runnable> shutdownNow();
    +-    method public abstract java.util.concurrent.Future<T> submit(java.util.concurrent.Callable<T>);
    +-    method public abstract java.util.concurrent.Future<T> submit(java.lang.Runnable, T);
    ++    method public abstract <T> java.util.concurrent.Future<T> submit(java.util.concurrent.Callable<T>);
    ++    method public abstract <T> java.util.concurrent.Future<T> submit(java.lang.Runnable, T);
    +     method public abstract java.util.concurrent.Future<?> submit(java.lang.Runnable);
    +   }
    + 
    +   public class Executors {
    +-    method public static java.util.concurrent.Callable<T> callable(java.lang.Runnable, T);
    ++    method public static <T> java.util.concurrent.Callable<T> callable(java.lang.Runnable, T);
    +     method public static java.util.concurrent.Callable<java.lang.Object> callable(java.lang.Runnable);
    +     method public static java.util.concurrent.Callable<java.lang.Object> callable(java.security.PrivilegedAction<?>);
    +     method public static java.util.concurrent.Callable<java.lang.Object> callable(java.security.PrivilegedExceptionAction<?>);
    +@@ -63393,8 +63393,8 @@ package java.util.concurrent {
    +     method public static java.util.concurrent.ScheduledExecutorService newSingleThreadScheduledExecutor(java.util.concurrent.ThreadFactory);
    +     method public static java.util.concurrent.ExecutorService newWorkStealingPool(int);
    +     method public static java.util.concurrent.ExecutorService newWorkStealingPool();
    +-    method public static java.util.concurrent.Callable<T> privilegedCallable(java.util.concurrent.Callable<T>);
    +-    method public static java.util.concurrent.Callable<T> privilegedCallableUsingCurrentClassLoader(java.util.concurrent.Callable<T>);
    ++    method public static <T> java.util.concurrent.Callable<T> privilegedCallable(java.util.concurrent.Callable<T>);
    ++    method public static <T> java.util.concurrent.Callable<T> privilegedCallableUsingCurrentClassLoader(java.util.concurrent.Callable<T>);
    +     method public static java.util.concurrent.ThreadFactory privilegedThreadFactory();
    +     method public static java.util.concurrent.ExecutorService unconfigurableExecutorService(java.util.concurrent.ExecutorService);
    +     method public static java.util.concurrent.ScheduledExecutorService unconfigurableScheduledExecutorService(java.util.concurrent.ScheduledExecutorService);
    +@@ -63422,7 +63422,7 @@ package java.util.concurrent {
    +     method public long getStealCount();
    +     method public java.lang.Thread.UncaughtExceptionHandler getUncaughtExceptionHandler();
    +     method public boolean hasQueuedSubmissions();
    +-    method public T invoke(java.util.concurrent.ForkJoinTask<T>);
    ++    method public <T> T invoke(java.util.concurrent.ForkJoinTask<T>);
    +     method public boolean isQuiescent();
    +     method public boolean isShutdown();
    +     method public boolean isTerminated();
    +@@ -63431,7 +63431,7 @@ package java.util.concurrent {
    +     method protected java.util.concurrent.ForkJoinTask<?> pollSubmission();
    +     method public void shutdown();
    +     method public java.util.List<java.lang.Runnable> shutdownNow();
    +-    method public java.util.concurrent.ForkJoinTask<T> submit(java.util.concurrent.ForkJoinTask<T>);
    ++    method public <T> java.util.concurrent.ForkJoinTask<T> submit(java.util.concurrent.ForkJoinTask<T>);
    +     field public static final java.util.concurrent.ForkJoinPool.ForkJoinWorkerThreadFactory defaultForkJoinWorkerThreadFactory;
    +   }
    + 
    +@@ -63444,11 +63444,11 @@ package java.util.concurrent {
    +     method public abstract boolean isReleasable();
    +   }
    + 
    +-  public abstract class ForkJoinTask implements java.util.concurrent.Future java.io.Serializable {
    ++  public abstract class ForkJoinTask<V> implements java.util.concurrent.Future java.io.Serializable {
    +     ctor public ForkJoinTask();
    +     method public static java.util.concurrent.ForkJoinTask<?> adapt(java.lang.Runnable);
    +-    method public static java.util.concurrent.ForkJoinTask<T> adapt(java.lang.Runnable, T);
    +-    method public static java.util.concurrent.ForkJoinTask<T> adapt(java.util.concurrent.Callable<? extends T>);
    ++    method public static <T> java.util.concurrent.ForkJoinTask<T> adapt(java.lang.Runnable, T);
    ++    method public static <T> java.util.concurrent.ForkJoinTask<T> adapt(java.util.concurrent.Callable<? extends T>);
    +     method public boolean cancel(boolean);
    +     method public final boolean compareAndSetForkJoinTaskTag(short, short);
    +     method public void complete(V);
    +@@ -63468,7 +63468,7 @@ package java.util.concurrent {
    +     method public final V invoke();
    +     method public static void invokeAll(java.util.concurrent.ForkJoinTask<?>, java.util.concurrent.ForkJoinTask<?>);
    +     method public static void invokeAll(java.util.concurrent.ForkJoinTask<?>...);
    +-    method public static java.util.Collection<T> invokeAll(java.util.Collection<T>);
    ++    method public static <T extends java.util.concurrent.ForkJoinTask<?>> java.util.Collection<T> invokeAll(java.util.Collection<T>);
    +     method public final boolean isCancelled();
    +     method public final boolean isCompletedAbnormally();
    +     method public final boolean isCompletedNormally();
    +@@ -63494,7 +63494,7 @@ package java.util.concurrent {
    +     method protected void onTermination(java.lang.Throwable);
    +   }
    + 
    +-  public abstract interface Future {
    ++  public abstract interface Future<V> {
    +     method public abstract boolean cancel(boolean);
    +     method public abstract V get() throws java.util.concurrent.ExecutionException, java.lang.InterruptedException;
    +     method public abstract V get(long, java.util.concurrent.TimeUnit) throws java.util.concurrent.ExecutionException, java.lang.InterruptedException, java.util.concurrent.TimeoutException;
    +@@ -63502,7 +63502,7 @@ package java.util.concurrent {
    +     method public abstract boolean isDone();
    +   }
    + 
    +-  public class FutureTask implements java.util.concurrent.RunnableFuture {
    ++  public class FutureTask<V> implements java.util.concurrent.RunnableFuture {
    +     ctor public FutureTask(java.util.concurrent.Callable<V>);
    +     ctor public FutureTask(java.lang.Runnable, V);
    +     method public boolean cancel(boolean);
    +@@ -63517,7 +63517,7 @@ package java.util.concurrent {
    +     method protected void setException(java.lang.Throwable);
    +   }
    + 
    +-  public class LinkedBlockingDeque extends java.util.AbstractQueue implements java.util.concurrent.BlockingDeque java.io.Serializable {
    ++  public class LinkedBlockingDeque<E> extends java.util.AbstractQueue implements java.util.concurrent.BlockingDeque java.io.Serializable {
    +     ctor public LinkedBlockingDeque();
    +     ctor public LinkedBlockingDeque(int);
    +     ctor public LinkedBlockingDeque(java.util.Collection<? extends E>);
    +@@ -63561,7 +63561,7 @@ package java.util.concurrent {
    +     method public E takeLast() throws java.lang.InterruptedException;
    +   }
    + 
    +-  public class LinkedBlockingQueue extends java.util.AbstractQueue implements java.util.concurrent.BlockingQueue java.io.Serializable {
    ++  public class LinkedBlockingQueue<E> extends java.util.AbstractQueue implements java.util.concurrent.BlockingQueue java.io.Serializable {
    +     ctor public LinkedBlockingQueue();
    +     ctor public LinkedBlockingQueue(int);
    +     ctor public LinkedBlockingQueue(java.util.Collection<? extends E>);
    +@@ -63580,7 +63580,7 @@ package java.util.concurrent {
    +     method public E take() throws java.lang.InterruptedException;
    +   }
    + 
    +-  public class LinkedTransferQueue extends java.util.AbstractQueue implements java.io.Serializable java.util.concurrent.TransferQueue {
    ++  public class LinkedTransferQueue<E> extends java.util.AbstractQueue implements java.io.Serializable java.util.concurrent.TransferQueue {
    +     ctor public LinkedTransferQueue();
    +     ctor public LinkedTransferQueue(java.util.Collection<? extends E>);
    +     method public int drainTo(java.util.Collection<? super E>);
    +@@ -63627,7 +63627,7 @@ package java.util.concurrent {
    +     method public int register();
    +   }
    + 
    +-  public class PriorityBlockingQueue extends java.util.AbstractQueue implements java.util.concurrent.BlockingQueue java.io.Serializable {
    ++  public class PriorityBlockingQueue<E> extends java.util.AbstractQueue implements java.util.concurrent.BlockingQueue java.io.Serializable {
    +     ctor public PriorityBlockingQueue();
    +     ctor public PriorityBlockingQueue(int);
    +     ctor public PriorityBlockingQueue(int, java.util.Comparator<? super E>);
    +@@ -63656,7 +63656,7 @@ package java.util.concurrent {
    +     method protected final void setRawResult(java.lang.Void);
    +   }
    + 
    +-  public abstract class RecursiveTask extends java.util.concurrent.ForkJoinTask {
    ++  public abstract class RecursiveTask<V> extends java.util.concurrent.ForkJoinTask {
    +     ctor public RecursiveTask();
    +     method protected abstract V compute();
    +     method protected final boolean exec();
    +@@ -63675,22 +63675,22 @@ package java.util.concurrent {
    +     method public abstract void rejectedExecution(java.lang.Runnable, java.util.concurrent.ThreadPoolExecutor);
    +   }
    + 
    +-  public abstract interface RunnableFuture implements java.util.concurrent.Future java.lang.Runnable {
    ++  public abstract interface RunnableFuture<V> implements java.util.concurrent.Future java.lang.Runnable {
    +     method public abstract void run();
    +   }
    + 
    +-  public abstract interface RunnableScheduledFuture implements java.util.concurrent.RunnableFuture java.util.concurrent.ScheduledFuture {
    ++  public abstract interface RunnableScheduledFuture<V> implements java.util.concurrent.RunnableFuture java.util.concurrent.ScheduledFuture {
    +     method public abstract boolean isPeriodic();
    +   }
    + 
    +   public abstract interface ScheduledExecutorService implements java.util.concurrent.ExecutorService {
    +     method public abstract java.util.concurrent.ScheduledFuture<?> schedule(java.lang.Runnable, long, java.util.concurrent.TimeUnit);
    +-    method public abstract java.util.concurrent.ScheduledFuture<V> schedule(java.util.concurrent.Callable<V>, long, java.util.concurrent.TimeUnit);
    ++    method public abstract <V> java.util.concurrent.ScheduledFuture<V> schedule(java.util.concurrent.Callable<V>, long, java.util.concurrent.TimeUnit);
    +     method public abstract java.util.concurrent.ScheduledFuture<?> scheduleAtFixedRate(java.lang.Runnable, long, long, java.util.concurrent.TimeUnit);
    +     method public abstract java.util.concurrent.ScheduledFuture<?> scheduleWithFixedDelay(java.lang.Runnable, long, long, java.util.concurrent.TimeUnit);
    +   }
    + 
    +-  public abstract interface ScheduledFuture implements java.util.concurrent.Delayed java.util.concurrent.Future {
    ++  public abstract interface ScheduledFuture<V> implements java.util.concurrent.Delayed java.util.concurrent.Future {
    +   }
    + 
    +   public class ScheduledThreadPoolExecutor extends java.util.concurrent.ThreadPoolExecutor implements java.util.concurrent.ScheduledExecutorService {
    +@@ -63698,13 +63698,13 @@ package java.util.concurrent {
    +     ctor public ScheduledThreadPoolExecutor(int, java.util.concurrent.ThreadFactory);
    +     ctor public ScheduledThreadPoolExecutor(int, java.util.concurrent.RejectedExecutionHandler);
    +     ctor public ScheduledThreadPoolExecutor(int, java.util.concurrent.ThreadFactory, java.util.concurrent.RejectedExecutionHandler);
    +-    method protected java.util.concurrent.RunnableScheduledFuture<V> decorateTask(java.lang.Runnable, java.util.concurrent.RunnableScheduledFuture<V>);
    +-    method protected java.util.concurrent.RunnableScheduledFuture<V> decorateTask(java.util.concurrent.Callable<V>, java.util.concurrent.RunnableScheduledFuture<V>);
    ++    method protected <V> java.util.concurrent.RunnableScheduledFuture<V> decorateTask(java.lang.Runnable, java.util.concurrent.RunnableScheduledFuture<V>);
    ++    method protected <V> java.util.concurrent.RunnableScheduledFuture<V> decorateTask(java.util.concurrent.Callable<V>, java.util.concurrent.RunnableScheduledFuture<V>);
    +     method public boolean getContinueExistingPeriodicTasksAfterShutdownPolicy();
    +     method public boolean getExecuteExistingDelayedTasksAfterShutdownPolicy();
    +     method public boolean getRemoveOnCancelPolicy();
    +     method public java.util.concurrent.ScheduledFuture<?> schedule(java.lang.Runnable, long, java.util.concurrent.TimeUnit);
    +-    method public java.util.concurrent.ScheduledFuture<V> schedule(java.util.concurrent.Callable<V>, long, java.util.concurrent.TimeUnit);
    ++    method public <V> java.util.concurrent.ScheduledFuture<V> schedule(java.util.concurrent.Callable<V>, long, java.util.concurrent.TimeUnit);
    +     method public java.util.concurrent.ScheduledFuture<?> scheduleAtFixedRate(java.lang.Runnable, long, long, java.util.concurrent.TimeUnit);
    +     method public java.util.concurrent.ScheduledFuture<?> scheduleWithFixedDelay(java.lang.Runnable, long, long, java.util.concurrent.TimeUnit);
    +     method public void setContinueExistingPeriodicTasksAfterShutdownPolicy(boolean);
    +@@ -63734,7 +63734,7 @@ package java.util.concurrent {
    +     method public boolean tryAcquire(int, long, java.util.concurrent.TimeUnit) throws java.lang.InterruptedException;
    +   }
    + 
    +-  public class SynchronousQueue extends java.util.AbstractQueue implements java.util.concurrent.BlockingQueue java.io.Serializable {
    ++  public class SynchronousQueue<E> extends java.util.AbstractQueue implements java.util.concurrent.BlockingQueue java.io.Serializable {
    +     ctor public SynchronousQueue();
    +     ctor public SynchronousQueue(boolean);
    +     method public int drainTo(java.util.Collection<? super E>);
    +@@ -63852,7 +63852,7 @@ package java.util.concurrent {
    +     ctor public TimeoutException(java.lang.String);
    +   }
    + 
    +-  public abstract interface TransferQueue implements java.util.concurrent.BlockingQueue {
    ++  public abstract interface TransferQueue<E> implements java.util.concurrent.BlockingQueue {
    +     method public abstract int getWaitingConsumerCount();
    +     method public abstract boolean hasWaitingConsumer();
    +     method public abstract void transfer(E) throws java.lang.InterruptedException;
    +@@ -63922,7 +63922,7 @@ package java.util.concurrent.atomic {
    +     method public final boolean weakCompareAndSet(int, int, int);
    +   }
    + 
    +-  public abstract class AtomicIntegerFieldUpdater {
    ++  public abstract class AtomicIntegerFieldUpdater<T> {
    +     ctor protected AtomicIntegerFieldUpdater();
    +     method public final int accumulateAndGet(T, int, java.util.function.IntBinaryOperator);
    +     method public int addAndGet(T, int);
    +@@ -63937,7 +63937,7 @@ package java.util.concurrent.atomic {
    +     method public final int getAndUpdate(T, java.util.function.IntUnaryOperator);
    +     method public int incrementAndGet(T);
    +     method public abstract void lazySet(T, int);
    +-    method public static java.util.concurrent.atomic.AtomicIntegerFieldUpdater<U> newUpdater(java.lang.Class<U>, java.lang.String);
    ++    method public static <U> java.util.concurrent.atomic.AtomicIntegerFieldUpdater<U> newUpdater(java.lang.Class<U>, java.lang.String);
    +     method public abstract void set(T, int);
    +     method public final int updateAndGet(T, java.util.function.IntUnaryOperator);
    +     method public abstract boolean weakCompareAndSet(T, int, int);
    +@@ -63990,7 +63990,7 @@ package java.util.concurrent.atomic {
    +     method public final boolean weakCompareAndSet(int, long, long);
    +   }
    + 
    +-  public abstract class AtomicLongFieldUpdater {
    ++  public abstract class AtomicLongFieldUpdater<T> {
    +     ctor protected AtomicLongFieldUpdater();
    +     method public final long accumulateAndGet(T, long, java.util.function.LongBinaryOperator);
    +     method public long addAndGet(T, long);
    +@@ -64005,13 +64005,13 @@ package java.util.concurrent.atomic {
    +     method public final long getAndUpdate(T, java.util.function.LongUnaryOperator);
    +     method public long incrementAndGet(T);
    +     method public abstract void lazySet(T, long);
    +-    method public static java.util.concurrent.atomic.AtomicLongFieldUpdater<U> newUpdater(java.lang.Class<U>, java.lang.String);
    ++    method public static <U> java.util.concurrent.atomic.AtomicLongFieldUpdater<U> newUpdater(java.lang.Class<U>, java.lang.String);
    +     method public abstract void set(T, long);
    +     method public final long updateAndGet(T, java.util.function.LongUnaryOperator);
    +     method public abstract boolean weakCompareAndSet(T, long, long);
    +   }
    + 
    +-  public class AtomicMarkableReference {
    ++  public class AtomicMarkableReference<V> {
    +     ctor public AtomicMarkableReference(V, boolean);
    +     method public boolean attemptMark(V, boolean);
    +     method public boolean compareAndSet(V, V, boolean, boolean);
    +@@ -64022,7 +64022,7 @@ package java.util.concurrent.atomic {
    +     method public boolean weakCompareAndSet(V, V, boolean, boolean);
    +   }
    + 
    +-  public class AtomicReference implements java.io.Serializable {
    ++  public class AtomicReference<V> implements java.io.Serializable {
    +     ctor public AtomicReference(V);
    +     ctor public AtomicReference();
    +     method public final V accumulateAndGet(V, java.util.function.BinaryOperator<V>);
    +@@ -64037,7 +64037,7 @@ package java.util.concurrent.atomic {
    +     method public final boolean weakCompareAndSet(V, V);
    +   }
    + 
    +-  public class AtomicReferenceArray implements java.io.Serializable {
    ++  public class AtomicReferenceArray<E> implements java.io.Serializable {
    +     ctor public AtomicReferenceArray(int);
    +     ctor public AtomicReferenceArray(E[]);
    +     method public final E accumulateAndGet(int, E, java.util.function.BinaryOperator<E>);
    +@@ -64053,7 +64053,7 @@ package java.util.concurrent.atomic {
    +     method public final boolean weakCompareAndSet(int, E, E);
    +   }
    + 
    +-  public abstract class AtomicReferenceFieldUpdater {
    ++  public abstract class AtomicReferenceFieldUpdater<T, V> {
    +     ctor protected AtomicReferenceFieldUpdater();
    +     method public final V accumulateAndGet(T, V, java.util.function.BinaryOperator<V>);
    +     method public abstract boolean compareAndSet(T, V, V);
    +@@ -64062,13 +64062,13 @@ package java.util.concurrent.atomic {
    +     method public V getAndSet(T, V);
    +     method public final V getAndUpdate(T, java.util.function.UnaryOperator<V>);
    +     method public abstract void lazySet(T, V);
    +-    method public static java.util.concurrent.atomic.AtomicReferenceFieldUpdater<U, W> newUpdater(java.lang.Class<U>, java.lang.Class<W>, java.lang.String);
    ++    method public static <U, W> java.util.concurrent.atomic.AtomicReferenceFieldUpdater<U, W> newUpdater(java.lang.Class<U>, java.lang.Class<W>, java.lang.String);
    +     method public abstract void set(T, V);
    +     method public final V updateAndGet(T, java.util.function.UnaryOperator<V>);
    +     method public abstract boolean weakCompareAndSet(T, V, V);
    +   }
    + 
    +-  public class AtomicStampedReference {
    ++  public class AtomicStampedReference<V> {
    +     ctor public AtomicStampedReference(V, int);
    +     method public boolean attemptStamp(V, int);
    +     method public boolean compareAndSet(V, V, int, int);
    +@@ -64371,33 +64371,33 @@ package java.util.concurrent.locks {
    + 
    + package java.util.function {
    + 
    +-  public abstract interface BiConsumer {
    ++  public abstract interface BiConsumer<T, U> {
    +     method public abstract void accept(T, U);
    +     method public default java.util.function.BiConsumer<T, U> andThen(java.util.function.BiConsumer<? super T, ? super U>);
    +   }
    + 
    +-  public abstract interface BiFunction {
    +-    method public default java.util.function.BiFunction<T, U, V> andThen(java.util.function.Function<? super R, ? extends V>);
    ++  public abstract interface BiFunction<T, U, R> {
    ++    method public default <V> java.util.function.BiFunction<T, U, V> andThen(java.util.function.Function<? super R, ? extends V>);
    +     method public abstract R apply(T, U);
    +   }
    + 
    +-  public abstract interface BiPredicate {
    ++  public abstract interface BiPredicate<T, U> {
    +     method public default java.util.function.BiPredicate<T, U> and(java.util.function.BiPredicate<? super T, ? super U>);
    +     method public default java.util.function.BiPredicate<T, U> negate();
    +     method public default java.util.function.BiPredicate<T, U> or(java.util.function.BiPredicate<? super T, ? super U>);
    +     method public abstract boolean test(T, U);
    +   }
    + 
    +-  public abstract interface BinaryOperator implements java.util.function.BiFunction {
    +-    method public static java.util.function.BinaryOperator<T> maxBy(java.util.Comparator<? super T>);
    +-    method public static java.util.function.BinaryOperator<T> minBy(java.util.Comparator<? super T>);
    ++  public abstract interface BinaryOperator<T> implements java.util.function.BiFunction {
    ++    method public static <T> java.util.function.BinaryOperator<T> maxBy(java.util.Comparator<? super T>);
    ++    method public static <T> java.util.function.BinaryOperator<T> minBy(java.util.Comparator<? super T>);
    +   }
    + 
    +   public abstract interface BooleanSupplier {
    +     method public abstract boolean getAsBoolean();
    +   }
    + 
    +-  public abstract interface Consumer {
    ++  public abstract interface Consumer<T> {
    +     method public abstract void accept(T);
    +     method public default java.util.function.Consumer<T> andThen(java.util.function.Consumer<? super T>);
    +   }
    +@@ -64411,7 +64411,7 @@ package java.util.function {
    +     method public default java.util.function.DoubleConsumer andThen(java.util.function.DoubleConsumer);
    +   }
    + 
    +-  public abstract interface DoubleFunction {
    ++  public abstract interface DoubleFunction<R> {
    +     method public abstract R apply(double);
    +   }
    + 
    +@@ -64441,11 +64441,11 @@ package java.util.function {
    +     method public static java.util.function.DoubleUnaryOperator identity();
    +   }
    + 
    +-  public abstract interface Function {
    +-    method public default java.util.function.Function<T, V> andThen(java.util.function.Function<? super R, ? extends V>);
    ++  public abstract interface Function<T, R> {
    ++    method public default <V> java.util.function.Function<T, V> andThen(java.util.function.Function<? super R, ? extends V>);
    +     method public abstract R apply(T);
    +-    method public default java.util.function.Function<V, R> compose(java.util.function.Function<? super V, ? extends T>);
    +-    method public static java.util.function.Function<T, T> identity();
    ++    method public default <V> java.util.function.Function<V, R> compose(java.util.function.Function<? super V, ? extends T>);
    ++    method public static <T> java.util.function.Function<T, T> identity();
    +   }
    + 
    +   public abstract interface IntBinaryOperator {
    +@@ -64457,7 +64457,7 @@ package java.util.function {
    +     method public default java.util.function.IntConsumer andThen(java.util.function.IntConsumer);
    +   }
    + 
    +-  public abstract interface IntFunction {
    ++  public abstract interface IntFunction<R> {
    +     method public abstract R apply(int);
    +   }
    + 
    +@@ -64496,7 +64496,7 @@ package java.util.function {
    +     method public default java.util.function.LongConsumer andThen(java.util.function.LongConsumer);
    +   }
    + 
    +-  public abstract interface LongFunction {
    ++  public abstract interface LongFunction<R> {
    +     method public abstract R apply(long);
    +   }
    + 
    +@@ -64526,56 +64526,56 @@ package java.util.function {
    +     method public static java.util.function.LongUnaryOperator identity();
    +   }
    + 
    +-  public abstract interface ObjDoubleConsumer {
    ++  public abstract interface ObjDoubleConsumer<T> {
    +     method public abstract void accept(T, double);
    +   }
    + 
    +-  public abstract interface ObjIntConsumer {
    ++  public abstract interface ObjIntConsumer<T> {
    +     method public abstract void accept(T, int);
    +   }
    + 
    +-  public abstract interface ObjLongConsumer {
    ++  public abstract interface ObjLongConsumer<T> {
    +     method public abstract void accept(T, long);
    +   }
    + 
    +-  public abstract interface Predicate {
    ++  public abstract interface Predicate<T> {
    +     method public default java.util.function.Predicate<T> and(java.util.function.Predicate<? super T>);
    +-    method public static java.util.function.Predicate<T> isEqual(java.lang.Object);
    ++    method public static <T> java.util.function.Predicate<T> isEqual(java.lang.Object);
    +     method public default java.util.function.Predicate<T> negate();
    +     method public default java.util.function.Predicate<T> or(java.util.function.Predicate<? super T>);
    +     method public abstract boolean test(T);
    +   }
    + 
    +-  public abstract interface Supplier {
    ++  public abstract interface Supplier<T> {
    +     method public abstract T get();
    +   }
    + 
    +-  public abstract interface ToDoubleBiFunction {
    ++  public abstract interface ToDoubleBiFunction<T, U> {
    +     method public abstract double applyAsDouble(T, U);
    +   }
    + 
    +-  public abstract interface ToDoubleFunction {
    ++  public abstract interface ToDoubleFunction<T> {
    +     method public abstract double applyAsDouble(T);
    +   }
    + 
    +-  public abstract interface ToIntBiFunction {
    ++  public abstract interface ToIntBiFunction<T, U> {
    +     method public abstract int applyAsInt(T, U);
    +   }
    + 
    +-  public abstract interface ToIntFunction {
    ++  public abstract interface ToIntFunction<T> {
    +     method public abstract int applyAsInt(T);
    +   }
    + 
    +-  public abstract interface ToLongBiFunction {
    ++  public abstract interface ToLongBiFunction<T, U> {
    +     method public abstract long applyAsLong(T, U);
    +   }
    + 
    +-  public abstract interface ToLongFunction {
    ++  public abstract interface ToLongFunction<T> {
    +     method public abstract long applyAsLong(T);
    +   }
    + 
    +-  public abstract interface UnaryOperator implements java.util.function.Function {
    +-    method public static java.util.function.UnaryOperator<T> identity();
    ++  public abstract interface UnaryOperator<T> implements java.util.function.Function {
    ++    method public static <T> java.util.function.UnaryOperator<T> identity();
    +   }
    + 
    + }
    +@@ -65163,7 +65163,7 @@ package java.util.regex {
    + 
    + package java.util.stream {
    + 
    +-  public abstract interface BaseStream implements java.lang.AutoCloseable {
    ++  public abstract interface BaseStream<T, S extends java.util.stream.BaseStream<T, S>> implements java.lang.AutoCloseable {
    +     method public abstract void close();
    +     method public abstract boolean isParallel();
    +     method public abstract java.util.Iterator<T> iterator();
    +@@ -65174,13 +65174,13 @@ package java.util.stream {
    +     method public abstract S unordered();
    +   }
    + 
    +-  public abstract interface Collector {
    ++  public abstract interface Collector<T, A, R> {
    +     method public abstract java.util.function.BiConsumer<A, T> accumulator();
    +     method public abstract java.util.Set<java.util.stream.Collector.Characteristics> characteristics();
    +     method public abstract java.util.function.BinaryOperator<A> combiner();
    +     method public abstract java.util.function.Function<A, R> finisher();
    +-    method public static java.util.stream.Collector<T, R, R> of(java.util.function.Supplier<R>, java.util.function.BiConsumer<R, T>, java.util.function.BinaryOperator<R>, java.util.stream.Collector.Characteristics...);
    +-    method public static java.util.stream.Collector<T, A, R> of(java.util.function.Supplier<A>, java.util.function.BiConsumer<A, T>, java.util.function.BinaryOperator<A>, java.util.function.Function<A, R>, java.util.stream.Collector.Characteristics...);
    ++    method public static <T, R> java.util.stream.Collector<T, R, R> of(java.util.function.Supplier<R>, java.util.function.BiConsumer<R, T>, java.util.function.BinaryOperator<R>, java.util.stream.Collector.Characteristics...);
    ++    method public static <T, A, R> java.util.stream.Collector<T, A, R> of(java.util.function.Supplier<A>, java.util.function.BiConsumer<A, T>, java.util.function.BinaryOperator<A>, java.util.function.Function<A, R>, java.util.stream.Collector.Characteristics...);
    +     method public abstract java.util.function.Supplier<A> supplier();
    +   }
    + 
    +@@ -65193,43 +65193,43 @@ package java.util.stream {
    +   }
    + 
    +   public final class Collectors {
    +-    method public static java.util.stream.Collector<T, ?, java.lang.Double> averagingDouble(java.util.function.ToDoubleFunction<? super T>);
    +-    method public static java.util.stream.Collector<T, ?, java.lang.Double> averagingInt(java.util.function.ToIntFunction<? super T>);
    +-    method public static java.util.stream.Collector<T, ?, java.lang.Double> averagingLong(java.util.function.ToLongFunction<? super T>);
    +-    method public static java.util.stream.Collector<T, A, RR> collectingAndThen(java.util.stream.Collector<T, A, R>, java.util.function.Function<R, RR>);
    +-    method public static java.util.stream.Collector<T, ?, java.lang.Long> counting();
    +-    method public static java.util.stream.Collector<T, ?, java.util.Map<K, java.util.List<T>>> groupingBy(java.util.function.Function<? super T, ? extends K>);
    +-    method public static java.util.stream.Collector<T, ?, java.util.Map<K, D>> groupingBy(java.util.function.Function<? super T, ? extends K>, java.util.stream.Collector<? super T, A, D>);
    +-    method public static java.util.stream.Collector<T, ?, M> groupingBy(java.util.function.Function<? super T, ? extends K>, java.util.function.Supplier<M>, java.util.stream.Collector<? super T, A, D>);
    +-    method public static java.util.stream.Collector<T, ?, java.util.concurrent.ConcurrentMap<K, java.util.List<T>>> groupingByConcurrent(java.util.function.Function<? super T, ? extends K>);
    +-    method public static java.util.stream.Collector<T, ?, java.util.concurrent.ConcurrentMap<K, D>> groupingByConcurrent(java.util.function.Function<? super T, ? extends K>, java.util.stream.Collector<? super T, A, D>);
    +-    method public static java.util.stream.Collector<T, ?, M> groupingByConcurrent(java.util.function.Function<? super T, ? extends K>, java.util.function.Supplier<M>, java.util.stream.Collector<? super T, A, D>);
    ++    method public static <T> java.util.stream.Collector<T, ?, java.lang.Double> averagingDouble(java.util.function.ToDoubleFunction<? super T>);
    ++    method public static <T> java.util.stream.Collector<T, ?, java.lang.Double> averagingInt(java.util.function.ToIntFunction<? super T>);
    ++    method public static <T> java.util.stream.Collector<T, ?, java.lang.Double> averagingLong(java.util.function.ToLongFunction<? super T>);
    ++    method public static <T, A, R, RR> java.util.stream.Collector<T, A, RR> collectingAndThen(java.util.stream.Collector<T, A, R>, java.util.function.Function<R, RR>);
    ++    method public static <T> java.util.stream.Collector<T, ?, java.lang.Long> counting();
    ++    method public static <T, K> java.util.stream.Collector<T, ?, java.util.Map<K, java.util.List<T>>> groupingBy(java.util.function.Function<? super T, ? extends K>);
    ++    method public static <T, K, A, D> java.util.stream.Collector<T, ?, java.util.Map<K, D>> groupingBy(java.util.function.Function<? super T, ? extends K>, java.util.stream.Collector<? super T, A, D>);
    ++    method public static <T, K, D, A, M extends java.util.Map<K, D>> java.util.stream.Collector<T, ?, M> groupingBy(java.util.function.Function<? super T, ? extends K>, java.util.function.Supplier<M>, java.util.stream.Collector<? super T, A, D>);
    ++    method public static <T, K> java.util.stream.Collector<T, ?, java.util.concurrent.ConcurrentMap<K, java.util.List<T>>> groupingByConcurrent(java.util.function.Function<? super T, ? extends K>);
    ++    method public static <T, K, A, D> java.util.stream.Collector<T, ?, java.util.concurrent.ConcurrentMap<K, D>> groupingByConcurrent(java.util.function.Function<? super T, ? extends K>, java.util.stream.Collector<? super T, A, D>);
    ++    method public static <T, K, A, D, M extends java.util.concurrent.ConcurrentMap<K, D>> java.util.stream.Collector<T, ?, M> groupingByConcurrent(java.util.function.Function<? super T, ? extends K>, java.util.function.Supplier<M>, java.util.stream.Collector<? super T, A, D>);
    +     method public static java.util.stream.Collector<java.lang.CharSequence, ?, java.lang.String> joining();
    +     method public static java.util.stream.Collector<java.lang.CharSequence, ?, java.lang.String> joining(java.lang.CharSequence);
    +     method public static java.util.stream.Collector<java.lang.CharSequence, ?, java.lang.String> joining(java.lang.CharSequence, java.lang.CharSequence, java.lang.CharSequence);
    +-    method public static java.util.stream.Collector<T, ?, R> mapping(java.util.function.Function<? super T, ? extends U>, java.util.stream.Collector<? super U, A, R>);
    +-    method public static java.util.stream.Collector<T, ?, java.util.Optional<T>> maxBy(java.util.Comparator<? super T>);
    +-    method public static java.util.stream.Collector<T, ?, java.util.Optional<T>> minBy(java.util.Comparator<? super T>);
    +-    method public static java.util.stream.Collector<T, ?, java.util.Map<java.lang.Boolean, java.util.List<T>>> partitioningBy(java.util.function.Predicate<? super T>);
    +-    method public static java.util.stream.Collector<T, ?, java.util.Map<java.lang.Boolean, D>> partitioningBy(java.util.function.Predicate<? super T>, java.util.stream.Collector<? super T, A, D>);
    +-    method public static java.util.stream.Collector<T, ?, T> reducing(T, java.util.function.BinaryOperator<T>);
    +-    method public static java.util.stream.Collector<T, ?, java.util.Optional<T>> reducing(java.util.function.BinaryOperator<T>);
    +-    method public static java.util.stream.Collector<T, ?, U> reducing(U, java.util.function.Function<? super T, ? extends U>, java.util.function.BinaryOperator<U>);
    +-    method public static java.util.stream.Collector<T, ?, java.util.DoubleSummaryStatistics> summarizingDouble(java.util.function.ToDoubleFunction<? super T>);
    +-    method public static java.util.stream.Collector<T, ?, java.util.IntSummaryStatistics> summarizingInt(java.util.function.ToIntFunction<? super T>);
    +-    method public static java.util.stream.Collector<T, ?, java.util.LongSummaryStatistics> summarizingLong(java.util.function.ToLongFunction<? super T>);
    +-    method public static java.util.stream.Collector<T, ?, java.lang.Double> summingDouble(java.util.function.ToDoubleFunction<? super T>);
    +-    method public static java.util.stream.Collector<T, ?, java.lang.Integer> summingInt(java.util.function.ToIntFunction<? super T>);
    +-    method public static java.util.stream.Collector<T, ?, java.lang.Long> summingLong(java.util.function.ToLongFunction<? super T>);
    +-    method public static java.util.stream.Collector<T, ?, C> toCollection(java.util.function.Supplier<C>);
    +-    method public static java.util.stream.Collector<T, ?, java.util.concurrent.ConcurrentMap<K, U>> toConcurrentMap(java.util.function.Function<? super T, ? extends K>, java.util.function.Function<? super T, ? extends U>);
    +-    method public static java.util.stream.Collector<T, ?, java.util.concurrent.ConcurrentMap<K, U>> toConcurrentMap(java.util.function.Function<? super T, ? extends K>, java.util.function.Function<? super T, ? extends U>, java.util.function.BinaryOperator<U>);
    +-    method public static java.util.stream.Collector<T, ?, M> toConcurrentMap(java.util.function.Function<? super T, ? extends K>, java.util.function.Function<? super T, ? extends U>, java.util.function.BinaryOperator<U>, java.util.function.Supplier<M>);
    +-    method public static java.util.stream.Collector<T, ?, java.util.List<T>> toList();
    +-    method public static java.util.stream.Collector<T, ?, java.util.Map<K, U>> toMap(java.util.function.Function<? super T, ? extends K>, java.util.function.Function<? super T, ? extends U>);
    +-    method public static java.util.stream.Collector<T, ?, java.util.Map<K, U>> toMap(java.util.function.Function<? super T, ? extends K>, java.util.function.Function<? super T, ? extends U>, java.util.function.BinaryOperator<U>);
    +-    method public static java.util.stream.Collector<T, ?, M> toMap(java.util.function.Function<? super T, ? extends K>, java.util.function.Function<? super T, ? extends U>, java.util.function.BinaryOperator<U>, java.util.function.Supplier<M>);
    +-    method public static java.util.stream.Collector<T, ?, java.util.Set<T>> toSet();
    ++    method public static <T, U, A, R> java.util.stream.Collector<T, ?, R> mapping(java.util.function.Function<? super T, ? extends U>, java.util.stream.Collector<? super U, A, R>);
    ++    method public static <T> java.util.stream.Collector<T, ?, java.util.Optional<T>> maxBy(java.util.Comparator<? super T>);
    ++    method public static <T> java.util.stream.Collector<T, ?, java.util.Optional<T>> minBy(java.util.Comparator<? super T>);
    ++    method public static <T> java.util.stream.Collector<T, ?, java.util.Map<java.lang.Boolean, java.util.List<T>>> partitioningBy(java.util.function.Predicate<? super T>);
    ++    method public static <T, D, A> java.util.stream.Collector<T, ?, java.util.Map<java.lang.Boolean, D>> partitioningBy(java.util.function.Predicate<? super T>, java.util.stream.Collector<? super T, A, D>);
    ++    method public static <T> java.util.stream.Collector<T, ?, T> reducing(T, java.util.function.BinaryOperator<T>);
    ++    method public static <T> java.util.stream.Collector<T, ?, java.util.Optional<T>> reducing(java.util.function.BinaryOperator<T>);
    ++    method public static <T, U> java.util.stream.Collector<T, ?, U> reducing(U, java.util.function.Function<? super T, ? extends U>, java.util.function.BinaryOperator<U>);
    ++    method public static <T> java.util.stream.Collector<T, ?, java.util.DoubleSummaryStatistics> summarizingDouble(java.util.function.ToDoubleFunction<? super T>);
    ++    method public static <T> java.util.stream.Collector<T, ?, java.util.IntSummaryStatistics> summarizingInt(java.util.function.ToIntFunction<? super T>);
    ++    method public static <T> java.util.stream.Collector<T, ?, java.util.LongSummaryStatistics> summarizingLong(java.util.function.ToLongFunction<? super T>);
    ++    method public static <T> java.util.stream.Collector<T, ?, java.lang.Double> summingDouble(java.util.function.ToDoubleFunction<? super T>);
    ++    method public static <T> java.util.stream.Collector<T, ?, java.lang.Integer> summingInt(java.util.function.ToIntFunction<? super T>);
    ++    method public static <T> java.util.stream.Collector<T, ?, java.lang.Long> summingLong(java.util.function.ToLongFunction<? super T>);
    ++    method public static <T, C extends java.util.Collection<T>> java.util.stream.Collector<T, ?, C> toCollection(java.util.function.Supplier<C>);
    ++    method public static <T, K, U> java.util.stream.Collector<T, ?, java.util.concurrent.ConcurrentMap<K, U>> toConcurrentMap(java.util.function.Function<? super T, ? extends K>, java.util.function.Function<? super T, ? extends U>);
    ++    method public static <T, K, U> java.util.stream.Collector<T, ?, java.util.concurrent.ConcurrentMap<K, U>> toConcurrentMap(java.util.function.Function<? super T, ? extends K>, java.util.function.Function<? super T, ? extends U>, java.util.function.BinaryOperator<U>);
    ++    method public static <T, K, U, M extends java.util.concurrent.ConcurrentMap<K, U>> java.util.stream.Collector<T, ?, M> toConcurrentMap(java.util.function.Function<? super T, ? extends K>, java.util.function.Function<? super T, ? extends U>, java.util.function.BinaryOperator<U>, java.util.function.Supplier<M>);
    ++    method public static <T> java.util.stream.Collector<T, ?, java.util.List<T>> toList();
    ++    method public static <T, K, U> java.util.stream.Collector<T, ?, java.util.Map<K, U>> toMap(java.util.function.Function<? super T, ? extends K>, java.util.function.Function<? super T, ? extends U>);
    ++    method public static <T, K, U> java.util.stream.Collector<T, ?, java.util.Map<K, U>> toMap(java.util.function.Function<? super T, ? extends K>, java.util.function.Function<? super T, ? extends U>, java.util.function.BinaryOperator<U>);
    ++    method public static <T, K, U, M extends java.util.Map<K, U>> java.util.stream.Collector<T, ?, M> toMap(java.util.function.Function<? super T, ? extends K>, java.util.function.Function<? super T, ? extends U>, java.util.function.BinaryOperator<U>, java.util.function.Supplier<M>);
    ++    method public static <T> java.util.stream.Collector<T, ?, java.util.Set<T>> toSet();
    +   }
    + 
    +   public abstract interface DoubleStream implements java.util.stream.BaseStream {
    +@@ -65238,7 +65238,7 @@ package java.util.stream {
    +     method public abstract java.util.OptionalDouble average();
    +     method public abstract java.util.stream.Stream<java.lang.Double> boxed();
    +     method public static java.util.stream.DoubleStream.Builder builder();
    +-    method public abstract R collect(java.util.function.Supplier<R>, java.util.function.ObjDoubleConsumer<R>, java.util.function.BiConsumer<R, R>);
    ++    method public abstract <R> R collect(java.util.function.Supplier<R>, java.util.function.ObjDoubleConsumer<R>, java.util.function.BiConsumer<R, R>);
    +     method public static java.util.stream.DoubleStream concat(java.util.stream.DoubleStream, java.util.stream.DoubleStream);
    +     method public abstract long count();
    +     method public abstract java.util.stream.DoubleStream distinct();
    +@@ -65256,7 +65256,7 @@ package java.util.stream {
    +     method public abstract java.util.stream.DoubleStream map(java.util.function.DoubleUnaryOperator);
    +     method public abstract java.util.stream.IntStream mapToInt(java.util.function.DoubleToIntFunction);
    +     method public abstract java.util.stream.LongStream mapToLong(java.util.function.DoubleToLongFunction);
    +-    method public abstract java.util.stream.Stream<U> mapToObj(java.util.function.DoubleFunction<? extends U>);
    ++    method public abstract <U> java.util.stream.Stream<U> mapToObj(java.util.function.DoubleFunction<? extends U>);
    +     method public abstract java.util.OptionalDouble max();
    +     method public abstract java.util.OptionalDouble min();
    +     method public abstract boolean noneMatch(java.util.function.DoublePredicate);
    +@@ -65289,7 +65289,7 @@ package java.util.stream {
    +     method public abstract java.util.OptionalDouble average();
    +     method public abstract java.util.stream.Stream<java.lang.Integer> boxed();
    +     method public static java.util.stream.IntStream.Builder builder();
    +-    method public abstract R collect(java.util.function.Supplier<R>, java.util.function.ObjIntConsumer<R>, java.util.function.BiConsumer<R, R>);
    ++    method public abstract <R> R collect(java.util.function.Supplier<R>, java.util.function.ObjIntConsumer<R>, java.util.function.BiConsumer<R, R>);
    +     method public static java.util.stream.IntStream concat(java.util.stream.IntStream, java.util.stream.IntStream);
    +     method public abstract long count();
    +     method public abstract java.util.stream.IntStream distinct();
    +@@ -65307,7 +65307,7 @@ package java.util.stream {
    +     method public abstract java.util.stream.IntStream map(java.util.function.IntUnaryOperator);
    +     method public abstract java.util.stream.DoubleStream mapToDouble(java.util.function.IntToDoubleFunction);
    +     method public abstract java.util.stream.LongStream mapToLong(java.util.function.IntToLongFunction);
    +-    method public abstract java.util.stream.Stream<U> mapToObj(java.util.function.IntFunction<? extends U>);
    ++    method public abstract <U> java.util.stream.Stream<U> mapToObj(java.util.function.IntFunction<? extends U>);
    +     method public abstract java.util.OptionalInt max();
    +     method public abstract java.util.OptionalInt min();
    +     method public abstract boolean noneMatch(java.util.function.IntPredicate);
    +@@ -65341,7 +65341,7 @@ package java.util.stream {
    +     method public abstract java.util.OptionalDouble average();
    +     method public abstract java.util.stream.Stream<java.lang.Long> boxed();
    +     method public static java.util.stream.LongStream.Builder builder();
    +-    method public abstract R collect(java.util.function.Supplier<R>, java.util.function.ObjLongConsumer<R>, java.util.function.BiConsumer<R, R>);
    ++    method public abstract <R> R collect(java.util.function.Supplier<R>, java.util.function.ObjLongConsumer<R>, java.util.function.BiConsumer<R, R>);
    +     method public static java.util.stream.LongStream concat(java.util.stream.LongStream, java.util.stream.LongStream);
    +     method public abstract long count();
    +     method public abstract java.util.stream.LongStream distinct();
    +@@ -65359,7 +65359,7 @@ package java.util.stream {
    +     method public abstract java.util.stream.LongStream map(java.util.function.LongUnaryOperator);
    +     method public abstract java.util.stream.DoubleStream mapToDouble(java.util.function.LongToDoubleFunction);
    +     method public abstract java.util.stream.IntStream mapToInt(java.util.function.LongToIntFunction);
    +-    method public abstract java.util.stream.Stream<U> mapToObj(java.util.function.LongFunction<? extends U>);
    ++    method public abstract <U> java.util.stream.Stream<U> mapToObj(java.util.function.LongFunction<? extends U>);
    +     method public abstract java.util.OptionalLong max();
    +     method public abstract java.util.OptionalLong min();
    +     method public abstract boolean noneMatch(java.util.function.LongPredicate);
    +@@ -65386,49 +65386,49 @@ package java.util.stream {
    +     method public abstract java.util.stream.LongStream build();
    +   }
    + 
    +-  public abstract interface Stream implements java.util.stream.BaseStream {
    ++  public abstract interface Stream<T> implements java.util.stream.BaseStream {
    +     method public abstract boolean allMatch(java.util.function.Predicate<? super T>);
    +     method public abstract boolean anyMatch(java.util.function.Predicate<? super T>);
    +-    method public static java.util.stream.Stream.Builder<T> builder();
    +-    method public abstract R collect(java.util.function.Supplier<R>, java.util.function.BiConsumer<R, ? super T>, java.util.function.BiConsumer<R, R>);
    +-    method public abstract R collect(java.util.stream.Collector<? super T, A, R>);
    +-    method public static java.util.stream.Stream<T> concat(java.util.stream.Stream<? extends T>, java.util.stream.Stream<? extends T>);
    ++    method public static <T> java.util.stream.Stream.Builder<T> builder();
    ++    method public abstract <R> R collect(java.util.function.Supplier<R>, java.util.function.BiConsumer<R, ? super T>, java.util.function.BiConsumer<R, R>);
    ++    method public abstract <R, A> R collect(java.util.stream.Collector<? super T, A, R>);
    ++    method public static <T> java.util.stream.Stream<T> concat(java.util.stream.Stream<? extends T>, java.util.stream.Stream<? extends T>);
    +     method public abstract long count();
    +     method public abstract java.util.stream.Stream<T> distinct();
    +-    method public static java.util.stream.Stream<T> empty();
    ++    method public static <T> java.util.stream.Stream<T> empty();
    +     method public abstract java.util.stream.Stream<T> filter(java.util.function.Predicate<? super T>);
    +     method public abstract java.util.Optional<T> findAny();
    +     method public abstract java.util.Optional<T> findFirst();
    +-    method public abstract java.util.stream.Stream<R> flatMap(java.util.function.Function<? super T, ? extends java.util.stream.Stream<? extends R>>);
    ++    method public abstract <R> java.util.stream.Stream<R> flatMap(java.util.function.Function<? super T, ? extends java.util.stream.Stream<? extends R>>);
    +     method public abstract java.util.stream.DoubleStream flatMapToDouble(java.util.function.Function<? super T, ? extends java.util.stream.DoubleStream>);
    +     method public abstract java.util.stream.IntStream flatMapToInt(java.util.function.Function<? super T, ? extends java.util.stream.IntStream>);
    +     method public abstract java.util.stream.LongStream flatMapToLong(java.util.function.Function<? super T, ? extends java.util.stream.LongStream>);
    +     method public abstract void forEach(java.util.function.Consumer<? super T>);
    +     method public abstract void forEachOrdered(java.util.function.Consumer<? super T>);
    +-    method public static java.util.stream.Stream<T> generate(java.util.function.Supplier<T>);
    +-    method public static java.util.stream.Stream<T> iterate(T, java.util.function.UnaryOperator<T>);
    ++    method public static <T> java.util.stream.Stream<T> generate(java.util.function.Supplier<T>);
    ++    method public static <T> java.util.stream.Stream<T> iterate(T, java.util.function.UnaryOperator<T>);
    +     method public abstract java.util.stream.Stream<T> limit(long);
    +-    method public abstract java.util.stream.Stream<R> map(java.util.function.Function<? super T, ? extends R>);
    ++    method public abstract <R> java.util.stream.Stream<R> map(java.util.function.Function<? super T, ? extends R>);
    +     method public abstract java.util.stream.DoubleStream mapToDouble(java.util.function.ToDoubleFunction<? super T>);
    +     method public abstract java.util.stream.IntStream mapToInt(java.util.function.ToIntFunction<? super T>);
    +     method public abstract java.util.stream.LongStream mapToLong(java.util.function.ToLongFunction<? super T>);
    +     method public abstract java.util.Optional<T> max(java.util.Comparator<? super T>);
    +     method public abstract java.util.Optional<T> min(java.util.Comparator<? super T>);
    +     method public abstract boolean noneMatch(java.util.function.Predicate<? super T>);
    +-    method public static java.util.stream.Stream<T> of(T);
    +-    method public static java.util.stream.Stream<T> of(T...);
    ++    method public static <T> java.util.stream.Stream<T> of(T);
    ++    method public static <T> java.util.stream.Stream<T> of(T...);
    +     method public abstract java.util.stream.Stream<T> peek(java.util.function.Consumer<? super T>);
    +     method public abstract T reduce(T, java.util.function.BinaryOperator<T>);
    +     method public abstract java.util.Optional<T> reduce(java.util.function.BinaryOperator<T>);
    +-    method public abstract U reduce(U, java.util.function.BiFunction<U, ? super T, U>, java.util.function.BinaryOperator<U>);
    ++    method public abstract <U> U reduce(U, java.util.function.BiFunction<U, ? super T, U>, java.util.function.BinaryOperator<U>);
    +     method public abstract java.util.stream.Stream<T> skip(long);
    +     method public abstract java.util.stream.Stream<T> sorted();
    +     method public abstract java.util.stream.Stream<T> sorted(java.util.Comparator<? super T>);
    +     method public abstract java.lang.Object[] toArray();
    +-    method public abstract A[] toArray(java.util.function.IntFunction<A[]>);
    ++    method public abstract <A> A[] toArray(java.util.function.IntFunction<A[]>);
    +   }
    + 
    +-  public static abstract interface Stream.Builder implements java.util.function.Consumer {
    ++  public static abstract interface Stream.Builder<T> implements java.util.function.Consumer {
    +     method public abstract void accept(T);
    +     method public default java.util.stream.Stream.Builder<T> add(T);
    +     method public abstract java.util.stream.Stream<T> build();
    +@@ -65441,8 +65441,8 @@ package java.util.stream {
    +     method public static java.util.stream.IntStream intStream(java.util.function.Supplier<? extends java.util.Spliterator.OfInt>, int, boolean);
    +     method public static java.util.stream.LongStream longStream(java.util.Spliterator.OfLong, boolean);
    +     method public static java.util.stream.LongStream longStream(java.util.function.Supplier<? extends java.util.Spliterator.OfLong>, int, boolean);
    +-    method public static java.util.stream.Stream<T> stream(java.util.Spliterator<T>, boolean);
    +-    method public static java.util.stream.Stream<T> stream(java.util.function.Supplier<? extends java.util.Spliterator<T>>, int, boolean);
    ++    method public static <T> java.util.stream.Stream<T> stream(java.util.Spliterator<T>, boolean);
    ++    method public static <T> java.util.stream.Stream<T> stream(java.util.function.Supplier<? extends java.util.Spliterator<T>>, int, boolean);
    +   }
    + 
    + }
    +@@ -67613,16 +67613,16 @@ package javax.security.auth {
    +   public final class Subject implements java.io.Serializable {
    +     ctor public Subject();
    +     ctor public Subject(boolean, java.util.Set<? extends java.security.Principal>, java.util.Set<?>, java.util.Set<?>);
    +-    method public static T doAs(javax.security.auth.Subject, java.security.PrivilegedAction<T>);
    +-    method public static T doAs(javax.security.auth.Subject, java.security.PrivilegedExceptionAction<T>) throws java.security.PrivilegedActionException;
    +-    method public static T doAsPrivileged(javax.security.auth.Subject, java.security.PrivilegedAction<T>, java.security.AccessControlContext);
    +-    method public static T doAsPrivileged(javax.security.auth.Subject, java.security.PrivilegedExceptionAction<T>, java.security.AccessControlContext) throws java.security.PrivilegedActionException;
    ++    method public static <T> T doAs(javax.security.auth.Subject, java.security.PrivilegedAction<T>);
    ++    method public static <T> T doAs(javax.security.auth.Subject, java.security.PrivilegedExceptionAction<T>) throws java.security.PrivilegedActionException;
    ++    method public static <T> T doAsPrivileged(javax.security.auth.Subject, java.security.PrivilegedAction<T>, java.security.AccessControlContext);
    ++    method public static <T> T doAsPrivileged(javax.security.auth.Subject, java.security.PrivilegedExceptionAction<T>, java.security.AccessControlContext) throws java.security.PrivilegedActionException;
    +     method public java.util.Set<java.security.Principal> getPrincipals();
    +-    method public java.util.Set<T> getPrincipals(java.lang.Class<T>);
    ++    method public <T extends java.security.Principal> java.util.Set<T> getPrincipals(java.lang.Class<T>);
    +     method public java.util.Set<java.lang.Object> getPrivateCredentials();
    +-    method public java.util.Set<T> getPrivateCredentials(java.lang.Class<T>);
    ++    method public <T> java.util.Set<T> getPrivateCredentials(java.lang.Class<T>);
    +     method public java.util.Set<java.lang.Object> getPublicCredentials();
    +-    method public java.util.Set<T> getPublicCredentials(java.lang.Class<T>);
    ++    method public <T> java.util.Set<T> getPublicCredentials(java.lang.Class<T>);
    +     method public static javax.security.auth.Subject getSubject(java.security.AccessControlContext);
    +     method public boolean isReadOnly();
    +     method public void setReadOnly();
    +diff --git a/api/test-current.txt b/api/test-current.txt
    +index 3b5c223..d74526b 100644
    +--- a/api/test-current.txt
    ++++ b/api/test-current.txt
    +@@ -2906,11 +2906,11 @@ package android.accounts {
    +     field public static final java.lang.String LOGIN_ACCOUNTS_CHANGED_ACTION = "android.accounts.LOGIN_ACCOUNTS_CHANGED";
    +   }
    + 
    +-  public abstract interface AccountManagerCallback {
    ++  public abstract interface AccountManagerCallback<V> {
    +     method public abstract void run(android.accounts.AccountManagerFuture<V>);
    +   }
    + 
    +-  public abstract interface AccountManagerFuture {
    ++  public abstract interface AccountManagerFuture<V> {
    +     method public abstract boolean cancel(boolean);
    +     method public abstract V getResult() throws android.accounts.AuthenticatorException, java.io.IOException, android.accounts.OperationCanceledException;
    +     method public abstract V getResult(long, java.util.concurrent.TimeUnit) throws android.accounts.AuthenticatorException, java.io.IOException, android.accounts.OperationCanceledException;
    +@@ -3056,7 +3056,7 @@ package android.animation {
    +     method public java.lang.Object evaluate(float, java.lang.Object, java.lang.Object);
    +   }
    + 
    +-  public abstract class BidirectionalTypeConverter extends android.animation.TypeConverter {
    ++  public abstract class BidirectionalTypeConverter<T, V> extends android.animation.TypeConverter {
    +     ctor public BidirectionalTypeConverter(java.lang.Class<T>, java.lang.Class<V>);
    +     method public abstract T convertBack(V);
    +     method public android.animation.BidirectionalTypeConverter<V, T> invert();
    +@@ -3148,26 +3148,26 @@ package android.animation {
    +     method public java.lang.String getPropertyName();
    +     method public java.lang.Object getTarget();
    +     method public static android.animation.ObjectAnimator ofArgb(java.lang.Object, java.lang.String, int...);
    +-    method public static android.animation.ObjectAnimator ofArgb(T, android.util.Property<T, java.lang.Integer>, int...);
    ++    method public static <T> android.animation.ObjectAnimator ofArgb(T, android.util.Property<T, java.lang.Integer>, int...);
    +     method public static android.animation.ObjectAnimator ofFloat(java.lang.Object, java.lang.String, float...);
    +     method public static android.animation.ObjectAnimator ofFloat(java.lang.Object, java.lang.String, java.lang.String, android.graphics.Path);
    +-    method public static android.animation.ObjectAnimator ofFloat(T, android.util.Property<T, java.lang.Float>, float...);
    +-    method public static android.animation.ObjectAnimator ofFloat(T, android.util.Property<T, java.lang.Float>, android.util.Property<T, java.lang.Float>, android.graphics.Path);
    ++    method public static <T> android.animation.ObjectAnimator ofFloat(T, android.util.Property<T, java.lang.Float>, float...);
    ++    method public static <T> android.animation.ObjectAnimator ofFloat(T, android.util.Property<T, java.lang.Float>, android.util.Property<T, java.lang.Float>, android.graphics.Path);
    +     method public static android.animation.ObjectAnimator ofInt(java.lang.Object, java.lang.String, int...);
    +     method public static android.animation.ObjectAnimator ofInt(java.lang.Object, java.lang.String, java.lang.String, android.graphics.Path);
    +-    method public static android.animation.ObjectAnimator ofInt(T, android.util.Property<T, java.lang.Integer>, int...);
    +-    method public static android.animation.ObjectAnimator ofInt(T, android.util.Property<T, java.lang.Integer>, android.util.Property<T, java.lang.Integer>, android.graphics.Path);
    ++    method public static <T> android.animation.ObjectAnimator ofInt(T, android.util.Property<T, java.lang.Integer>, int...);
    ++    method public static <T> android.animation.ObjectAnimator ofInt(T, android.util.Property<T, java.lang.Integer>, android.util.Property<T, java.lang.Integer>, android.graphics.Path);
    +     method public static android.animation.ObjectAnimator ofMultiFloat(java.lang.Object, java.lang.String, float[][]);
    +     method public static android.animation.ObjectAnimator ofMultiFloat(java.lang.Object, java.lang.String, android.graphics.Path);
    +-    method public static android.animation.ObjectAnimator ofMultiFloat(java.lang.Object, java.lang.String, android.animation.TypeConverter<T, float[]>, android.animation.TypeEvaluator<T>, T...);
    ++    method public static <T> android.animation.ObjectAnimator ofMultiFloat(java.lang.Object, java.lang.String, android.animation.TypeConverter<T, float[]>, android.animation.TypeEvaluator<T>, T...);
    +     method public static android.animation.ObjectAnimator ofMultiInt(java.lang.Object, java.lang.String, int[][]);
    +     method public static android.animation.ObjectAnimator ofMultiInt(java.lang.Object, java.lang.String, android.graphics.Path);
    +-    method public static android.animation.ObjectAnimator ofMultiInt(java.lang.Object, java.lang.String, android.animation.TypeConverter<T, int[]>, android.animation.TypeEvaluator<T>, T...);
    ++    method public static <T> android.animation.ObjectAnimator ofMultiInt(java.lang.Object, java.lang.String, android.animation.TypeConverter<T, int[]>, android.animation.TypeEvaluator<T>, T...);
    +     method public static android.animation.ObjectAnimator ofObject(java.lang.Object, java.lang.String, android.animation.TypeEvaluator, java.lang.Object...);
    +     method public static android.animation.ObjectAnimator ofObject(java.lang.Object, java.lang.String, android.animation.TypeConverter<android.graphics.PointF, ?>, android.graphics.Path);
    +-    method public static android.animation.ObjectAnimator ofObject(T, android.util.Property<T, V>, android.animation.TypeEvaluator<V>, V...);
    +-    method public static android.animation.ObjectAnimator ofObject(T, android.util.Property<T, P>, android.animation.TypeConverter<V, P>, android.animation.TypeEvaluator<V>, V...);
    +-    method public static android.animation.ObjectAnimator ofObject(T, android.util.Property<T, V>, android.animation.TypeConverter<android.graphics.PointF, V>, android.graphics.Path);
    ++    method public static <T, V> android.animation.ObjectAnimator ofObject(T, android.util.Property<T, V>, android.animation.TypeEvaluator<V>, V...);
    ++    method public static <T, V, P> android.animation.ObjectAnimator ofObject(T, android.util.Property<T, P>, android.animation.TypeConverter<V, P>, android.animation.TypeEvaluator<V>, V...);
    ++    method public static <T, V> android.animation.ObjectAnimator ofObject(T, android.util.Property<T, V>, android.animation.TypeConverter<android.graphics.PointF, V>, android.graphics.Path);
    +     method public static android.animation.ObjectAnimator ofPropertyValuesHolder(java.lang.Object, android.animation.PropertyValuesHolder...);
    +     method public void setAutoCancel(boolean);
    +     method public void setProperty(android.util.Property);
    +@@ -3191,17 +3191,17 @@ package android.animation {
    +     method public static android.animation.PropertyValuesHolder ofKeyframe(android.util.Property, android.animation.Keyframe...);
    +     method public static android.animation.PropertyValuesHolder ofMultiFloat(java.lang.String, float[][]);
    +     method public static android.animation.PropertyValuesHolder ofMultiFloat(java.lang.String, android.graphics.Path);
    +-    method public static android.animation.PropertyValuesHolder ofMultiFloat(java.lang.String, android.animation.TypeConverter<V, float[]>, android.animation.TypeEvaluator<V>, V...);
    +-    method public static android.animation.PropertyValuesHolder ofMultiFloat(java.lang.String, android.animation.TypeConverter<T, float[]>, android.animation.TypeEvaluator<T>, android.animation.Keyframe...);
    ++    method public static <V> android.animation.PropertyValuesHolder ofMultiFloat(java.lang.String, android.animation.TypeConverter<V, float[]>, android.animation.TypeEvaluator<V>, V...);
    ++    method public static <T> android.animation.PropertyValuesHolder ofMultiFloat(java.lang.String, android.animation.TypeConverter<T, float[]>, android.animation.TypeEvaluator<T>, android.animation.Keyframe...);
    +     method public static android.animation.PropertyValuesHolder ofMultiInt(java.lang.String, int[][]);
    +     method public static android.animation.PropertyValuesHolder ofMultiInt(java.lang.String, android.graphics.Path);
    +-    method public static android.animation.PropertyValuesHolder ofMultiInt(java.lang.String, android.animation.TypeConverter<V, int[]>, android.animation.TypeEvaluator<V>, V...);
    +-    method public static android.animation.PropertyValuesHolder ofMultiInt(java.lang.String, android.animation.TypeConverter<T, int[]>, android.animation.TypeEvaluator<T>, android.animation.Keyframe...);
    ++    method public static <V> android.animation.PropertyValuesHolder ofMultiInt(java.lang.String, android.animation.TypeConverter<V, int[]>, android.animation.TypeEvaluator<V>, V...);
    ++    method public static <T> android.animation.PropertyValuesHolder ofMultiInt(java.lang.String, android.animation.TypeConverter<T, int[]>, android.animation.TypeEvaluator<T>, android.animation.Keyframe...);
    +     method public static android.animation.PropertyValuesHolder ofObject(java.lang.String, android.animation.TypeEvaluator, java.lang.Object...);
    +     method public static android.animation.PropertyValuesHolder ofObject(java.lang.String, android.animation.TypeConverter<android.graphics.PointF, ?>, android.graphics.Path);
    +-    method public static android.animation.PropertyValuesHolder ofObject(android.util.Property, android.animation.TypeEvaluator<V>, V...);
    +-    method public static android.animation.PropertyValuesHolder ofObject(android.util.Property<?, V>, android.animation.TypeConverter<T, V>, android.animation.TypeEvaluator<T>, T...);
    +-    method public static android.animation.PropertyValuesHolder ofObject(android.util.Property<?, V>, android.animation.TypeConverter<android.graphics.PointF, V>, android.graphics.Path);
    ++    method public static <V> android.animation.PropertyValuesHolder ofObject(android.util.Property, android.animation.TypeEvaluator<V>, V...);
    ++    method public static <T, V> android.animation.PropertyValuesHolder ofObject(android.util.Property<?, V>, android.animation.TypeConverter<T, V>, android.animation.TypeEvaluator<T>, T...);
    ++    method public static <V> android.animation.PropertyValuesHolder ofObject(android.util.Property<?, V>, android.animation.TypeConverter<android.graphics.PointF, V>, android.graphics.Path);
    +     method public void setConverter(android.animation.TypeConverter);
    +     method public void setEvaluator(android.animation.TypeEvaluator);
    +     method public void setFloatValues(float...);
    +@@ -3238,12 +3238,12 @@ package android.animation {
    +     method public abstract float getInterpolation(float);
    +   }
    + 
    +-  public abstract class TypeConverter {
    ++  public abstract class TypeConverter<T, V> {
    +     ctor public TypeConverter(java.lang.Class<T>, java.lang.Class<V>);
    +     method public abstract V convert(T);
    +   }
    + 
    +-  public abstract interface TypeEvaluator {
    ++  public abstract interface TypeEvaluator<T> {
    +     method public abstract T evaluate(float, T, T);
    +   }
    + 
    +@@ -3255,6 +3255,7 @@ package android.animation {
    +     method public java.lang.Object getAnimatedValue(java.lang.String);
    +     method public long getCurrentPlayTime();
    +     method public long getDuration();
    ++    method public static float getDurationScale();
    +     method public static long getFrameDelay();
    +     method public int getRepeatCount();
    +     method public int getRepeatMode();
    +@@ -3272,6 +3273,7 @@ package android.animation {
    +     method public void setCurrentFraction(float);
    +     method public void setCurrentPlayTime(long);
    +     method public android.animation.ValueAnimator setDuration(long);
    ++    method public static void setDurationScale(float);
    +     method public void setEvaluator(android.animation.TypeEvaluator);
    +     method public void setFloatValues(float...);
    +     method public static void setFrameDelay(long);
    +@@ -4572,7 +4574,7 @@ package android.app {
    +     method public android.os.Parcelable saveAllState();
    +   }
    + 
    +-  public abstract class FragmentHostCallback extends android.app.FragmentContainer {
    ++  public abstract class FragmentHostCallback<E> extends android.app.FragmentContainer {
    +     ctor public FragmentHostCallback(android.content.Context, android.os.Handler, int);
    +     method public void onAttachFragment(android.app.Fragment);
    +     method public void onDump(java.lang.String, java.io.FileDescriptor, java.io.PrintWriter, java.lang.String[]);
    +@@ -4839,12 +4841,12 @@ package android.app {
    +     method public abstract void destroyLoader(int);
    +     method public abstract void dump(java.lang.String, java.io.FileDescriptor, java.io.PrintWriter, java.lang.String[]);
    +     method public static void enableDebugLogging(boolean);
    +-    method public abstract android.content.Loader<D> getLoader(int);
    +-    method public abstract android.content.Loader<D> initLoader(int, android.os.Bundle, android.app.LoaderManager.LoaderCallbacks<D>);
    +-    method public abstract android.content.Loader<D> restartLoader(int, android.os.Bundle, android.app.LoaderManager.LoaderCallbacks<D>);
    ++    method public abstract <D> android.content.Loader<D> getLoader(int);
    ++    method public abstract <D> android.content.Loader<D> initLoader(int, android.os.Bundle, android.app.LoaderManager.LoaderCallbacks<D>);
    ++    method public abstract <D> android.content.Loader<D> restartLoader(int, android.os.Bundle, android.app.LoaderManager.LoaderCallbacks<D>);
    +   }
    + 
    +-  public static abstract interface LoaderManager.LoaderCallbacks {
    ++  public static abstract interface LoaderManager.LoaderCallbacks<D> {
    +     method public abstract android.content.Loader<D> onCreateLoader(int, android.os.Bundle);
    +     method public abstract void onLoadFinished(android.content.Loader<D>, D);
    +     method public abstract void onLoaderReset(android.content.Loader<D>);
    +@@ -5629,6 +5631,7 @@ package android.app {
    +   public class TimePickerDialog extends android.app.AlertDialog implements android.content.DialogInterface.OnClickListener android.widget.TimePicker.OnTimeChangedListener {
    +     ctor public TimePickerDialog(android.content.Context, android.app.TimePickerDialog.OnTimeSetListener, int, int, boolean);
    +     ctor public TimePickerDialog(android.content.Context, int, android.app.TimePickerDialog.OnTimeSetListener, int, int, boolean);
    ++    method public android.widget.TimePicker getTimePicker();
    +     method public void onClick(android.content.DialogInterface, int);
    +     method public void onTimeChanged(android.widget.TimePicker, int, int);
    +     method public void updateTime(int, int);
    +@@ -7635,7 +7638,7 @@ package android.content {
    +     ctor public AsyncQueryHandler.WorkerHandler(android.os.Looper);
    +   }
    + 
    +-  public abstract class AsyncTaskLoader extends android.content.Loader {
    ++  public abstract class AsyncTaskLoader<D> extends android.content.Loader {
    +     ctor public AsyncTaskLoader(android.content.Context);
    +     method public void cancelLoadInBackground();
    +     method public boolean isLoadInBackgroundCanceled();
    +@@ -7817,7 +7820,7 @@ package android.content {
    +     method public android.os.ParcelFileDescriptor openFile(android.net.Uri, java.lang.String) throws java.io.FileNotFoundException;
    +     method public android.os.ParcelFileDescriptor openFile(android.net.Uri, java.lang.String, android.os.CancellationSignal) throws java.io.FileNotFoundException;
    +     method protected final android.os.ParcelFileDescriptor openFileHelper(android.net.Uri, java.lang.String) throws java.io.FileNotFoundException;
    +-    method public android.os.ParcelFileDescriptor openPipeHelper(android.net.Uri, java.lang.String, android.os.Bundle, T, android.content.ContentProvider.PipeDataWriter<T>) throws java.io.FileNotFoundException;
    ++    method public <T> android.os.ParcelFileDescriptor openPipeHelper(android.net.Uri, java.lang.String, android.os.Bundle, T, android.content.ContentProvider.PipeDataWriter<T>) throws java.io.FileNotFoundException;
    +     method public android.content.res.AssetFileDescriptor openTypedAssetFile(android.net.Uri, java.lang.String, android.os.Bundle) throws java.io.FileNotFoundException;
    +     method public android.content.res.AssetFileDescriptor openTypedAssetFile(android.net.Uri, java.lang.String, android.os.Bundle, android.os.CancellationSignal) throws java.io.FileNotFoundException;
    +     method public abstract android.database.Cursor query(android.net.Uri, java.lang.String[], java.lang.String, java.lang.String[], java.lang.String);
    +@@ -7830,7 +7833,7 @@ package android.content {
    +     method public abstract int update(android.net.Uri, android.content.ContentValues, java.lang.String, java.lang.String[]);
    +   }
    + 
    +-  public static abstract interface ContentProvider.PipeDataWriter {
    ++  public static abstract interface ContentProvider.PipeDataWriter<T> {
    +     method public abstract void writeDataToPipe(android.os.ParcelFileDescriptor, android.net.Uri, java.lang.String, android.os.Bundle, T);
    +   }
    + 
    +@@ -8102,7 +8105,7 @@ package android.content {
    +     method public final java.lang.String getString(int);
    +     method public final java.lang.String getString(int, java.lang.Object...);
    +     method public abstract java.lang.Object getSystemService(java.lang.String);
    +-    method public final T getSystemService(java.lang.Class<T>);
    ++    method public final <T> T getSystemService(java.lang.Class<T>);
    +     method public abstract java.lang.String getSystemServiceName(java.lang.Class<?>);
    +     method public final java.lang.CharSequence getText(int);
    +     method public abstract android.content.res.Resources.Theme getTheme();
    +@@ -8459,8 +8462,8 @@ package android.content {
    +     method public long getLongExtra(java.lang.String, long);
    +     method public java.lang.String getPackage();
    +     method public android.os.Parcelable[] getParcelableArrayExtra(java.lang.String);
    +-    method public java.util.ArrayList<T> getParcelableArrayListExtra(java.lang.String);
    +-    method public T getParcelableExtra(java.lang.String);
    ++    method public <T extends android.os.Parcelable> java.util.ArrayList<T> getParcelableArrayListExtra(java.lang.String);
    ++    method public <T extends android.os.Parcelable> T getParcelableExtra(java.lang.String);
    +     method public java.lang.String getScheme();
    +     method public android.content.Intent getSelector();
    +     method public java.io.Serializable getSerializableExtra(java.lang.String);
    +@@ -8935,7 +8938,7 @@ package android.content {
    +     ctor public IntentSender.SendIntentException(java.lang.Exception);
    +   }
    + 
    +-  public class Loader {
    ++  public class Loader<D> {
    +     ctor public Loader(android.content.Context);
    +     method public void abandon();
    +     method public boolean cancelLoad();
    +@@ -8972,11 +8975,11 @@ package android.content {
    +     ctor public Loader.ForceLoadContentObserver();
    +   }
    + 
    +-  public static abstract interface Loader.OnLoadCanceledListener {
    ++  public static abstract interface Loader.OnLoadCanceledListener<D> {
    +     method public abstract void onLoadCanceled(android.content.Loader<D>);
    +   }
    + 
    +-  public static abstract interface Loader.OnLoadCompleteListener {
    ++  public static abstract interface Loader.OnLoadCompleteListener<D> {
    +     method public abstract void onLoadComplete(android.content.Loader<D>, D);
    +   }
    + 
    +@@ -10853,7 +10856,7 @@ package android.database {
    +     method public boolean isNull(int);
    +   }
    + 
    +-  public abstract class Observable {
    ++  public abstract class Observable<T> {
    +     ctor public Observable();
    +     method public void registerObserver(T);
    +     method public void unregisterAll();
    +@@ -12743,7 +12746,7 @@ package android.graphics.drawable {
    +   public class AnimatedStateListDrawable extends android.graphics.drawable.StateListDrawable {
    +     ctor public AnimatedStateListDrawable();
    +     method public void addState(int[], android.graphics.drawable.Drawable, int);
    +-    method public void addTransition(int, int, T, boolean);
    ++    method public <T extends android.graphics.drawable.Drawable & android.graphics.drawable.Animatable> void addTransition(int, int, T, boolean);
    +   }
    + 
    +   public class AnimatedVectorDrawable extends android.graphics.drawable.Drawable implements android.graphics.drawable.Animatable2 {
    +@@ -13867,7 +13870,7 @@ package android.hardware.camera2 {
    +   }
    + 
    +   public final class CameraCharacteristics extends android.hardware.camera2.CameraMetadata {
    +-    method public T get(android.hardware.camera2.CameraCharacteristics.Key<T>);
    ++    method public <T> T get(android.hardware.camera2.CameraCharacteristics.Key<T>);
    +     method public java.util.List<android.hardware.camera2.CaptureRequest.Key<?>> getAvailableCaptureRequestKeys();
    +     method public java.util.List<android.hardware.camera2.CaptureResult.Key<?>> getAvailableCaptureResultKeys();
    +     field public static final android.hardware.camera2.CameraCharacteristics.Key<int[]> COLOR_CORRECTION_AVAILABLE_ABERRATION_MODES;
    +@@ -13952,7 +13955,7 @@ package android.hardware.camera2 {
    +     field public static final android.hardware.camera2.CameraCharacteristics.Key<java.lang.Integer> TONEMAP_MAX_CURVE_POINTS;
    +   }
    + 
    +-  public static final class CameraCharacteristics.Key {
    ++  public static final class CameraCharacteristics.Key<T> {
    +     method public final boolean equals(java.lang.Object);
    +     method public java.lang.String getName();
    +     method public final int hashCode();
    +@@ -14017,7 +14020,7 @@ package android.hardware.camera2 {
    +     method public void onTorchModeUnavailable(java.lang.String);
    +   }
    + 
    +-  public abstract class CameraMetadata {
    ++  public abstract class CameraMetadata<TKey> {
    +     method public java.util.List<TKey> getKeys();
    +     field public static final int COLOR_CORRECTION_ABERRATION_MODE_FAST = 1; // 0x1
    +     field public static final int COLOR_CORRECTION_ABERRATION_MODE_HIGH_QUALITY = 2; // 0x2
    +@@ -14225,7 +14228,7 @@ package android.hardware.camera2 {
    + 
    +   public final class CaptureRequest extends android.hardware.camera2.CameraMetadata implements android.os.Parcelable {
    +     method public int describeContents();
    +-    method public T get(android.hardware.camera2.CaptureRequest.Key<T>);
    ++    method public <T> T get(android.hardware.camera2.CaptureRequest.Key<T>);
    +     method public java.lang.Object getTag();
    +     method public boolean isReprocess();
    +     method public void writeToParcel(android.os.Parcel, int);
    +@@ -14288,20 +14291,20 @@ package android.hardware.camera2 {
    +   public static final class CaptureRequest.Builder {
    +     method public void addTarget(android.view.Surface);
    +     method public android.hardware.camera2.CaptureRequest build();
    +-    method public T get(android.hardware.camera2.CaptureRequest.Key<T>);
    ++    method public <T> T get(android.hardware.camera2.CaptureRequest.Key<T>);
    +     method public void removeTarget(android.view.Surface);
    +-    method public void set(android.hardware.camera2.CaptureRequest.Key<T>, T);
    ++    method public <T> void set(android.hardware.camera2.CaptureRequest.Key<T>, T);
    +     method public void setTag(java.lang.Object);
    +   }
    + 
    +-  public static final class CaptureRequest.Key {
    ++  public static final class CaptureRequest.Key<T> {
    +     method public final boolean equals(java.lang.Object);
    +     method public java.lang.String getName();
    +     method public final int hashCode();
    +   }
    + 
    +   public class CaptureResult extends android.hardware.camera2.CameraMetadata {
    +-    method public T get(android.hardware.camera2.CaptureResult.Key<T>);
    ++    method public <T> T get(android.hardware.camera2.CaptureResult.Key<T>);
    +     method public long getFrameNumber();
    +     method public android.hardware.camera2.CaptureRequest getRequest();
    +     method public int getSequenceId();
    +@@ -14382,7 +14385,7 @@ package android.hardware.camera2 {
    +     field public static final android.hardware.camera2.CaptureResult.Key<java.lang.Integer> TONEMAP_PRESET_CURVE;
    +   }
    + 
    +-  public static final class CaptureResult.Key {
    ++  public static final class CaptureResult.Key<T> {
    +     method public final boolean equals(java.lang.Object);
    +     method public java.lang.String getName();
    +     method public final int hashCode();
    +@@ -14507,14 +14510,14 @@ package android.hardware.camera2.params {
    +     method public android.util.Size[] getInputSizes(int);
    +     method public final int[] getOutputFormats();
    +     method public long getOutputMinFrameDuration(int, android.util.Size);
    +-    method public long getOutputMinFrameDuration(java.lang.Class<T>, android.util.Size);
    +-    method public android.util.Size[] getOutputSizes(java.lang.Class<T>);
    ++    method public <T> long getOutputMinFrameDuration(java.lang.Class<T>, android.util.Size);
    ++    method public <T> android.util.Size[] getOutputSizes(java.lang.Class<T>);
    +     method public android.util.Size[] getOutputSizes(int);
    +     method public long getOutputStallDuration(int, android.util.Size);
    +-    method public long getOutputStallDuration(java.lang.Class<T>, android.util.Size);
    ++    method public <T> long getOutputStallDuration(java.lang.Class<T>, android.util.Size);
    +     method public final int[] getValidOutputFormatsForInput(int);
    +     method public boolean isOutputSupportedFor(int);
    +-    method public static boolean isOutputSupportedFor(java.lang.Class<T>);
    ++    method public static <T> boolean isOutputSupportedFor(java.lang.Class<T>);
    +     method public boolean isOutputSupportedFor(android.view.Surface);
    +   }
    + 
    +@@ -16215,7 +16218,7 @@ package android.icu.math {
    + 
    + package android.icu.text {
    + 
    +-  public final class AlphabeticIndex implements java.lang.Iterable {
    ++  public final class AlphabeticIndex<V> implements java.lang.Iterable {
    +     ctor public AlphabeticIndex(android.icu.util.ULocale);
    +     ctor public AlphabeticIndex(java.util.Locale);
    +     ctor public AlphabeticIndex(android.icu.text.RuleBasedCollator);
    +@@ -16241,7 +16244,7 @@ package android.icu.text {
    +     method public android.icu.text.AlphabeticIndex<V> setUnderflowLabel(java.lang.String);
    +   }
    + 
    +-  public static class AlphabeticIndex.Bucket implements java.lang.Iterable {
    ++  public static class AlphabeticIndex.Bucket<V> implements java.lang.Iterable {
    +     method public java.lang.String getLabel();
    +     method public android.icu.text.AlphabeticIndex.Bucket.LabelType getLabelType();
    +     method public java.util.Iterator<android.icu.text.AlphabeticIndex.Record<V>> iterator();
    +@@ -16257,14 +16260,14 @@ package android.icu.text {
    +     enum_constant public static final android.icu.text.AlphabeticIndex.Bucket.LabelType UNDERFLOW;
    +   }
    + 
    +-  public static final class AlphabeticIndex.ImmutableIndex implements java.lang.Iterable {
    ++  public static final class AlphabeticIndex.ImmutableIndex<V> implements java.lang.Iterable {
    +     method public android.icu.text.AlphabeticIndex.Bucket<V> getBucket(int);
    +     method public int getBucketCount();
    +     method public int getBucketIndex(java.lang.CharSequence);
    +     method public java.util.Iterator<android.icu.text.AlphabeticIndex.Bucket<V>> iterator();
    +   }
    + 
    +-  public static class AlphabeticIndex.Record {
    ++  public static class AlphabeticIndex.Record<V> {
    +     method public V getData();
    +     method public java.lang.CharSequence getName();
    +   }
    +@@ -17777,8 +17780,8 @@ package android.icu.text {
    +     method public final android.icu.text.UnicodeSet addAll(java.lang.CharSequence);
    +     method public android.icu.text.UnicodeSet addAll(android.icu.text.UnicodeSet);
    +     method public android.icu.text.UnicodeSet addAll(java.lang.Iterable<?>);
    +-    method public android.icu.text.UnicodeSet addAll(T...);
    +-    method public T addAllTo(T);
    ++    method public <T extends java.lang.CharSequence> android.icu.text.UnicodeSet addAll(T...);
    ++    method public <T extends java.util.Collection<java.lang.String>> T addAllTo(T);
    +     method public void addMatchSetTo(android.icu.text.UnicodeSet);
    +     method public android.icu.text.UnicodeSet applyIntPropertyValue(int, int);
    +     method public final android.icu.text.UnicodeSet applyPattern(java.lang.String);
    +@@ -17806,15 +17809,15 @@ package android.icu.text {
    +     method public final boolean contains(java.lang.CharSequence);
    +     method public boolean containsAll(android.icu.text.UnicodeSet);
    +     method public boolean containsAll(java.lang.String);
    +-    method public boolean containsAll(java.lang.Iterable<T>);
    ++    method public <T extends java.lang.CharSequence> boolean containsAll(java.lang.Iterable<T>);
    +     method public boolean containsNone(int, int);
    +     method public boolean containsNone(android.icu.text.UnicodeSet);
    +     method public boolean containsNone(java.lang.CharSequence);
    +-    method public boolean containsNone(java.lang.Iterable<T>);
    ++    method public <T extends java.lang.CharSequence> boolean containsNone(java.lang.Iterable<T>);
    +     method public final boolean containsSome(int, int);
    +     method public final boolean containsSome(android.icu.text.UnicodeSet);
    +     method public final boolean containsSome(java.lang.CharSequence);
    +-    method public final boolean containsSome(java.lang.Iterable<T>);
    ++    method public final <T extends java.lang.CharSequence> boolean containsSome(java.lang.Iterable<T>);
    +     method public android.icu.text.UnicodeSet freeze();
    +     method public static android.icu.text.UnicodeSet from(java.lang.CharSequence);
    +     method public static android.icu.text.UnicodeSet fromAll(java.lang.CharSequence);
    +@@ -17832,14 +17835,14 @@ package android.icu.text {
    +     method public final android.icu.text.UnicodeSet remove(java.lang.CharSequence);
    +     method public final android.icu.text.UnicodeSet removeAll(java.lang.CharSequence);
    +     method public android.icu.text.UnicodeSet removeAll(android.icu.text.UnicodeSet);
    +-    method public android.icu.text.UnicodeSet removeAll(java.lang.Iterable<T>);
    ++    method public <T extends java.lang.CharSequence> android.icu.text.UnicodeSet removeAll(java.lang.Iterable<T>);
    +     method public final android.icu.text.UnicodeSet removeAllStrings();
    +     method public android.icu.text.UnicodeSet retain(int, int);
    +     method public final android.icu.text.UnicodeSet retain(int);
    +     method public final android.icu.text.UnicodeSet retain(java.lang.CharSequence);
    +     method public final android.icu.text.UnicodeSet retainAll(java.lang.CharSequence);
    +     method public android.icu.text.UnicodeSet retainAll(android.icu.text.UnicodeSet);
    +-    method public android.icu.text.UnicodeSet retainAll(java.lang.Iterable<T>);
    ++    method public <T extends java.lang.CharSequence> android.icu.text.UnicodeSet retainAll(java.lang.Iterable<T>);
    +     method public android.icu.text.UnicodeSet set(int, int);
    +     method public android.icu.text.UnicodeSet set(android.icu.text.UnicodeSet);
    +     method public int size();
    +@@ -18249,7 +18252,7 @@ package android.icu.util {
    +     method public long getToDate();
    +   }
    + 
    +-  public abstract interface Freezable implements java.lang.Cloneable {
    ++  public abstract interface Freezable<T> implements java.lang.Cloneable {
    +     method public abstract T cloneAsThawed();
    +     method public abstract T freeze();
    +     method public abstract boolean isFrozen();
    +@@ -18531,7 +18534,7 @@ package android.icu.util {
    +     field public static final android.icu.util.TimeUnit YEAR;
    +   }
    + 
    +-  public class Output {
    ++  public class Output<T> {
    +     ctor public Output();
    +     ctor public Output(T);
    +     field public T value;
    +@@ -28239,7 +28242,7 @@ package android.opengl {
    + 
    + package android.os {
    + 
    +-  public abstract class AsyncTask {
    ++  public abstract class AsyncTask<Params, Progress, Result> {
    +     ctor public AsyncTask();
    +     method public final boolean cancel(boolean);
    +     method protected abstract Result doInBackground(Params...);
    +@@ -28466,16 +28469,16 @@ package android.os {
    +     method public float getFloat(java.lang.String, float);
    +     method public float[] getFloatArray(java.lang.String);
    +     method public java.util.ArrayList<java.lang.Integer> getIntegerArrayList(java.lang.String);
    +-    method public T getParcelable(java.lang.String);
    ++    method public <T extends android.os.Parcelable> T getParcelable(java.lang.String);
    +     method public android.os.Parcelable[] getParcelableArray(java.lang.String);
    +-    method public java.util.ArrayList<T> getParcelableArrayList(java.lang.String);
    ++    method public <T extends android.os.Parcelable> java.util.ArrayList<T> getParcelableArrayList(java.lang.String);
    +     method public java.io.Serializable getSerializable(java.lang.String);
    +     method public short getShort(java.lang.String);
    +     method public short getShort(java.lang.String, short);
    +     method public short[] getShortArray(java.lang.String);
    +     method public android.util.Size getSize(java.lang.String);
    +     method public android.util.SizeF getSizeF(java.lang.String);
    +-    method public android.util.SparseArray<T> getSparseParcelableArray(java.lang.String);
    ++    method public <T extends android.os.Parcelable> android.util.SparseArray<T> getSparseParcelableArray(java.lang.String);
    +     method public java.util.ArrayList<java.lang.String> getStringArrayList(java.lang.String);
    +     method public boolean hasFileDescriptors();
    +     method public void putAll(android.os.Bundle);
    +@@ -28980,8 +28983,8 @@ package android.os {
    +     method public final long[] createLongArray();
    +     method public final java.lang.String[] createStringArray();
    +     method public final java.util.ArrayList<java.lang.String> createStringArrayList();
    +-    method public final T[] createTypedArray(android.os.Parcelable.Creator<T>);
    +-    method public final java.util.ArrayList<T> createTypedArrayList(android.os.Parcelable.Creator<T>);
    ++    method public final <T> T[] createTypedArray(android.os.Parcelable.Creator<T>);
    ++    method public final <T> java.util.ArrayList<T> createTypedArrayList(android.os.Parcelable.Creator<T>);
    +     method public final int dataAvail();
    +     method public final int dataCapacity();
    +     method public final int dataPosition();
    +@@ -29014,7 +29017,7 @@ package android.os {
    +     method public final long readLong();
    +     method public final void readLongArray(long[]);
    +     method public final void readMap(java.util.Map, java.lang.ClassLoader);
    +-    method public final T readParcelable(java.lang.ClassLoader);
    ++    method public final <T extends android.os.Parcelable> T readParcelable(java.lang.ClassLoader);
    +     method public final android.os.Parcelable[] readParcelableArray(java.lang.ClassLoader);
    +     method public final android.os.PersistableBundle readPersistableBundle();
    +     method public final android.os.PersistableBundle readPersistableBundle(java.lang.ClassLoader);
    +@@ -29027,9 +29030,9 @@ package android.os {
    +     method public final void readStringArray(java.lang.String[]);
    +     method public final void readStringList(java.util.List<java.lang.String>);
    +     method public final android.os.IBinder readStrongBinder();
    +-    method public final void readTypedArray(T[], android.os.Parcelable.Creator<T>);
    +-    method public final void readTypedList(java.util.List<T>, android.os.Parcelable.Creator<T>);
    +-    method public final T readTypedObject(android.os.Parcelable.Creator<T>);
    ++    method public final <T> void readTypedArray(T[], android.os.Parcelable.Creator<T>);
    ++    method public final <T> void readTypedList(java.util.List<T>, android.os.Parcelable.Creator<T>);
    ++    method public final <T> T readTypedObject(android.os.Parcelable.Creator<T>);
    +     method public final java.lang.Object readValue(java.lang.ClassLoader);
    +     method public final void recycle();
    +     method public final void setDataCapacity(int);
    +@@ -29060,7 +29063,7 @@ package android.os {
    +     method public final void writeMap(java.util.Map);
    +     method public final void writeNoException();
    +     method public final void writeParcelable(android.os.Parcelable, int);
    +-    method public final void writeParcelableArray(T[], int);
    ++    method public final <T extends android.os.Parcelable> void writeParcelableArray(T[], int);
    +     method public final void writePersistableBundle(android.os.PersistableBundle);
    +     method public final void writeSerializable(java.io.Serializable);
    +     method public final void writeSize(android.util.Size);
    +@@ -29072,9 +29075,9 @@ package android.os {
    +     method public final void writeStringList(java.util.List<java.lang.String>);
    +     method public final void writeStrongBinder(android.os.IBinder);
    +     method public final void writeStrongInterface(android.os.IInterface);
    +-    method public final void writeTypedArray(T[], int);
    +-    method public final void writeTypedList(java.util.List<T>);
    +-    method public final void writeTypedObject(T, int);
    ++    method public final <T extends android.os.Parcelable> void writeTypedArray(T[], int);
    ++    method public final <T extends android.os.Parcelable> void writeTypedList(java.util.List<T>);
    ++    method public final <T extends android.os.Parcelable> void writeTypedObject(T, int);
    +     method public final void writeValue(java.lang.Object);
    +     field public static final android.os.Parcelable.Creator<java.lang.String> STRING_CREATOR;
    +   }
    +@@ -29152,11 +29155,11 @@ package android.os {
    +     field public static final int PARCELABLE_WRITE_RETURN_VALUE = 1; // 0x1
    +   }
    + 
    +-  public static abstract interface Parcelable.ClassLoaderCreator implements android.os.Parcelable.Creator {
    ++  public static abstract interface Parcelable.ClassLoaderCreator<T> implements android.os.Parcelable.Creator {
    +     method public abstract T createFromParcel(android.os.Parcel, java.lang.ClassLoader);
    +   }
    + 
    +-  public static abstract interface Parcelable.Creator {
    ++  public static abstract interface Parcelable.Creator<T> {
    +     method public abstract T createFromParcel(android.os.Parcel);
    +     method public abstract T[] newArray(int);
    +   }
    +@@ -29271,7 +29274,7 @@ package android.os {
    +     method public abstract void onProgress(int);
    +   }
    + 
    +-  public class RemoteCallbackList {
    ++  public class RemoteCallbackList<E extends android.os.IInterface> {
    +     ctor public RemoteCallbackList();
    +     method public int beginBroadcast();
    +     method public void finishBroadcast();
    +@@ -32557,7 +32560,7 @@ package android.provider {
    +     field public static final java.lang.String RADIO_CELL = "cell";
    +     field public static final java.lang.String RADIO_NFC = "nfc";
    +     field public static final java.lang.String RADIO_WIFI = "wifi";
    +-    field public static final java.lang.String SHOW_PROCESSES = "show_processes";
    ++    field public static final deprecated java.lang.String SHOW_PROCESSES = "show_processes";
    +     field public static final java.lang.String STAY_ON_WHILE_PLUGGED_IN = "stay_on_while_plugged_in";
    +     field public static final java.lang.String TRANSITION_ANIMATION_SCALE = "transition_animation_scale";
    +     field public static final java.lang.String USB_MASS_STORAGE_ENABLED = "usb_mass_storage_enabled";
    +@@ -34599,7 +34602,7 @@ package android.service.carrier {
    +     field public static final java.lang.String SERVICE_INTERFACE = "android.service.carrier.CarrierMessagingService";
    +   }
    + 
    +-  public static abstract interface CarrierMessagingService.ResultCallback {
    ++  public static abstract interface CarrierMessagingService.ResultCallback<T> {
    +     method public abstract void onReceiveResult(T) throws android.os.RemoteException;
    +   }
    + 
    +@@ -34750,7 +34753,7 @@ package android.service.media {
    +     field public static final java.lang.String EXTRA_SUGGESTED = "android.service.media.extra.SUGGESTED";
    +   }
    + 
    +-  public class MediaBrowserService.Result {
    ++  public class MediaBrowserService.Result<T> {
    +     method public void detach();
    +     method public void sendResult(T);
    +   }
    +@@ -37663,14 +37666,14 @@ package android.telephony.gsm {
    + 
    + package android.test {
    + 
    +-  public abstract deprecated class ActivityInstrumentationTestCase extends android.test.ActivityTestCase {
    ++  public abstract deprecated class ActivityInstrumentationTestCase<T extends android.app.Activity> extends android.test.ActivityTestCase {
    +     ctor public ActivityInstrumentationTestCase(java.lang.String, java.lang.Class<T>);
    +     ctor public ActivityInstrumentationTestCase(java.lang.String, java.lang.Class<T>, boolean);
    +     method public T getActivity();
    +     method public void testActivityTestCaseSetUpProperly() throws java.lang.Exception;
    +   }
    + 
    +-  public abstract deprecated class ActivityInstrumentationTestCase2 extends android.test.ActivityTestCase {
    ++  public abstract deprecated class ActivityInstrumentationTestCase2<T extends android.app.Activity> extends android.test.ActivityTestCase {
    +     ctor public deprecated ActivityInstrumentationTestCase2(java.lang.String, java.lang.Class<T>);
    +     ctor public ActivityInstrumentationTestCase2(java.lang.Class<T>);
    +     method public T getActivity();
    +@@ -37685,7 +37688,7 @@ package android.test {
    +     method protected void setActivity(android.app.Activity);
    +   }
    + 
    +-  public abstract deprecated class ActivityUnitTestCase extends android.test.ActivityTestCase {
    ++  public abstract deprecated class ActivityUnitTestCase<T extends android.app.Activity> extends android.test.ActivityTestCase {
    +     ctor public ActivityUnitTestCase(java.lang.Class<T>);
    +     method public T getActivity();
    +     method public int getFinishedActivityRequest();
    +@@ -37731,7 +37734,7 @@ package android.test {
    +     method public void testStarted(java.lang.String);
    +   }
    + 
    +-  public abstract deprecated class ApplicationTestCase extends android.test.AndroidTestCase {
    ++  public abstract deprecated class ApplicationTestCase<T extends android.app.Application> extends android.test.AndroidTestCase {
    +     ctor public ApplicationTestCase(java.lang.Class<T>);
    +     method protected final void createApplication();
    +     method public T getApplication();
    +@@ -37757,8 +37760,8 @@ package android.test {
    +     method public android.app.Instrumentation getInstrumentation();
    +     method public deprecated void injectInsrumentation(android.app.Instrumentation);
    +     method public void injectInstrumentation(android.app.Instrumentation);
    +-    method public final T launchActivity(java.lang.String, java.lang.Class<T>, android.os.Bundle);
    +-    method public final T launchActivityWithIntent(java.lang.String, java.lang.Class<T>, android.content.Intent);
    ++    method public final <T extends android.app.Activity> T launchActivity(java.lang.String, java.lang.Class<T>, android.os.Bundle);
    ++    method public final <T extends android.app.Activity> T launchActivityWithIntent(java.lang.String, java.lang.Class<T>, android.content.Intent);
    +     method public void runTestOnUiThread(java.lang.Runnable) throws java.lang.Throwable;
    +     method public void sendKeys(java.lang.String);
    +     method public void sendKeys(int...);
    +@@ -37798,7 +37801,7 @@ package android.test {
    + 
    +   public class LoaderTestCase extends android.test.AndroidTestCase {
    +     ctor public LoaderTestCase();
    +-    method public T getLoaderResultSynchronously(android.content.Loader<T>);
    ++    method public <T> T getLoaderResultSynchronously(android.content.Loader<T>);
    +   }
    + 
    +   public final deprecated class MoreAsserts {
    +@@ -37853,20 +37856,20 @@ package android.test {
    +     method public abstract void startTiming(boolean);
    +   }
    + 
    +-  public abstract deprecated class ProviderTestCase extends android.test.InstrumentationTestCase {
    ++  public abstract deprecated class ProviderTestCase<T extends android.content.ContentProvider> extends android.test.InstrumentationTestCase {
    +     ctor public ProviderTestCase(java.lang.Class<T>, java.lang.String);
    +     method public android.test.mock.MockContentResolver getMockContentResolver();
    +     method public android.test.IsolatedContext getMockContext();
    +     method public T getProvider();
    +-    method public static android.content.ContentResolver newResolverWithContentProviderFromSql(android.content.Context, java.lang.Class<T>, java.lang.String, java.lang.String, int, java.lang.String) throws java.lang.IllegalAccessException, java.lang.InstantiationException;
    ++    method public static <T extends android.content.ContentProvider> android.content.ContentResolver newResolverWithContentProviderFromSql(android.content.Context, java.lang.Class<T>, java.lang.String, java.lang.String, int, java.lang.String) throws java.lang.IllegalAccessException, java.lang.InstantiationException;
    +   }
    + 
    +-  public abstract class ProviderTestCase2 extends android.test.AndroidTestCase {
    ++  public abstract class ProviderTestCase2<T extends android.content.ContentProvider> extends android.test.AndroidTestCase {
    +     ctor public ProviderTestCase2(java.lang.Class<T>, java.lang.String);
    +     method public android.test.mock.MockContentResolver getMockContentResolver();
    +     method public android.test.IsolatedContext getMockContext();
    +     method public T getProvider();
    +-    method public static android.content.ContentResolver newResolverWithContentProviderFromSql(android.content.Context, java.lang.String, java.lang.Class<T>, java.lang.String, java.lang.String, int, java.lang.String) throws java.lang.IllegalAccessException, java.lang.InstantiationException;
    ++    method public static <T extends android.content.ContentProvider> android.content.ContentResolver newResolverWithContentProviderFromSql(android.content.Context, java.lang.String, java.lang.Class<T>, java.lang.String, java.lang.String, int, java.lang.String) throws java.lang.IllegalAccessException, java.lang.InstantiationException;
    +   }
    + 
    +   public deprecated class RenamingDelegatingContext extends android.content.ContextWrapper {
    +@@ -37874,11 +37877,11 @@ package android.test {
    +     ctor public RenamingDelegatingContext(android.content.Context, android.content.Context, java.lang.String);
    +     method public java.lang.String getDatabasePrefix();
    +     method public void makeExistingFilesAndDbsAccessible();
    +-    method public static T providerWithRenamedContext(java.lang.Class<T>, android.content.Context, java.lang.String) throws java.lang.IllegalAccessException, java.lang.InstantiationException;
    +-    method public static T providerWithRenamedContext(java.lang.Class<T>, android.content.Context, java.lang.String, boolean) throws java.lang.IllegalAccessException, java.lang.InstantiationException;
    ++    method public static <T extends android.content.ContentProvider> T providerWithRenamedContext(java.lang.Class<T>, android.content.Context, java.lang.String) throws java.lang.IllegalAccessException, java.lang.InstantiationException;
    ++    method public static <T extends android.content.ContentProvider> T providerWithRenamedContext(java.lang.Class<T>, android.content.Context, java.lang.String, boolean) throws java.lang.IllegalAccessException, java.lang.InstantiationException;
    +   }
    + 
    +-  public abstract deprecated class ServiceTestCase extends android.test.AndroidTestCase {
    ++  public abstract deprecated class ServiceTestCase<T extends android.app.Service> extends android.test.AndroidTestCase {
    +     ctor public ServiceTestCase(java.lang.Class<T>);
    +     method protected android.os.IBinder bindService(android.content.Intent);
    +     method public android.app.Application getApplication();
    +@@ -37891,7 +37894,7 @@ package android.test {
    +     method public void testServiceTestCaseSetUpProperly() throws java.lang.Exception;
    +   }
    + 
    +-  public abstract deprecated class SingleLaunchActivityTestCase extends android.test.InstrumentationTestCase {
    ++  public abstract deprecated class SingleLaunchActivityTestCase<T extends android.app.Activity> extends android.test.InstrumentationTestCase {
    +     ctor public SingleLaunchActivityTestCase(java.lang.String, java.lang.Class<T>);
    +     method public T getActivity();
    +     method public void testActivityTestCaseSetUpProperly() throws java.lang.Exception;
    +@@ -38248,7 +38251,7 @@ package android.test.suitebuilder {
    +     ctor public TestMethod(java.lang.String, java.lang.Class<? extends junit.framework.TestCase>);
    +     ctor public TestMethod(junit.framework.TestCase);
    +     method public junit.framework.TestCase createTest() throws java.lang.IllegalAccessException, java.lang.InstantiationException, java.lang.reflect.InvocationTargetException;
    +-    method public T getAnnotation(java.lang.Class<T>);
    ++    method public <T extends java.lang.annotation.Annotation> T getAnnotation(java.lang.Class<T>);
    +     method public java.lang.Class<? extends junit.framework.TestCase> getEnclosingClass();
    +     method public java.lang.String getEnclosingClassname();
    +     method public java.lang.String getName();
    +@@ -38691,7 +38694,7 @@ package android.text {
    +     method public int getSpanEnd(java.lang.Object);
    +     method public int getSpanFlags(java.lang.Object);
    +     method public int getSpanStart(java.lang.Object);
    +-    method public T[] getSpans(int, int, java.lang.Class<T>);
    ++    method public <T> T[] getSpans(int, int, java.lang.Class<T>);
    +     method public deprecated int getTextRunCursor(int, int, int, int, int, android.graphics.Paint);
    +     method public int getTextWatcherDepth();
    +     method public android.text.SpannableStringBuilder insert(int, java.lang.CharSequence, int, int);
    +@@ -38713,7 +38716,7 @@ package android.text {
    +     method public int getSpanEnd(java.lang.Object);
    +     method public int getSpanFlags(java.lang.Object);
    +     method public int getSpanStart(java.lang.Object);
    +-    method public T[] getSpans(int, int, java.lang.Class<T>);
    ++    method public <T> T[] getSpans(int, int, java.lang.Class<T>);
    +     method public final int length();
    +     method public int nextSpanTransition(int, int, java.lang.Class);
    +     method public final java.lang.String toString();
    +@@ -38723,7 +38726,7 @@ package android.text {
    +     method public abstract int getSpanEnd(java.lang.Object);
    +     method public abstract int getSpanFlags(java.lang.Object);
    +     method public abstract int getSpanStart(java.lang.Object);
    +-    method public abstract T[] getSpans(int, int, java.lang.Class<T>);
    ++    method public abstract <T> T[] getSpans(int, int, java.lang.Class<T>);
    +     method public abstract int nextSpanTransition(int, int, java.lang.Class);
    +     field public static final int SPAN_COMPOSING = 256; // 0x100
    +     field public static final int SPAN_EXCLUSIVE_EXCLUSIVE = 33; // 0x21
    +@@ -39700,7 +39703,7 @@ package android.text.style {
    +     field public static final int WEEKDAY_WEDNESDAY = 4; // 0x4
    +   }
    + 
    +-  public static class TtsSpan.Builder {
    ++  public static class TtsSpan.Builder<C extends android.text.style.TtsSpan.Builder<?>> {
    +     ctor public TtsSpan.Builder(java.lang.String);
    +     method public android.text.style.TtsSpan build();
    +     method public C setIntArgument(java.lang.String, int);
    +@@ -39796,7 +39799,7 @@ package android.text.style {
    +     method public android.text.style.TtsSpan.OrdinalBuilder setNumber(java.lang.String);
    +   }
    + 
    +-  public static class TtsSpan.SemioticClassBuilder extends android.text.style.TtsSpan.Builder {
    ++  public static class TtsSpan.SemioticClassBuilder<C extends android.text.style.TtsSpan.SemioticClassBuilder<?>> extends android.text.style.TtsSpan.Builder {
    +     ctor public TtsSpan.SemioticClassBuilder(java.lang.String);
    +     method public C setAnimacy(java.lang.String);
    +     method public C setCase(java.lang.String);
    +@@ -40203,7 +40206,7 @@ package android.util {
    +     ctor public AndroidRuntimeException(java.lang.Exception);
    +   }
    + 
    +-  public final class ArrayMap implements java.util.Map {
    ++  public final class ArrayMap<K, V> implements java.util.Map {
    +     ctor public ArrayMap();
    +     ctor public ArrayMap(int);
    +     ctor public ArrayMap(android.util.ArrayMap<K, V>);
    +@@ -40231,7 +40234,7 @@ package android.util {
    +     method public java.util.Collection<V> values();
    +   }
    + 
    +-  public final class ArraySet implements java.util.Collection java.util.Set {
    ++  public final class ArraySet<E> implements java.util.Collection java.util.Set {
    +     ctor public ArraySet();
    +     ctor public ArraySet(int);
    +     ctor public ArraySet(android.util.ArraySet<E>);
    +@@ -40252,7 +40255,7 @@ package android.util {
    +     method public boolean retainAll(java.util.Collection<?>);
    +     method public int size();
    +     method public java.lang.Object[] toArray();
    +-    method public T[] toArray(T[]);
    ++    method public <T> T[] toArray(T[]);
    +     method public E valueAt(int);
    +   }
    + 
    +@@ -40397,13 +40400,13 @@ package android.util {
    +   public deprecated class FloatMath {
    +   }
    + 
    +-  public abstract class FloatProperty extends android.util.Property {
    ++  public abstract class FloatProperty<T> extends android.util.Property {
    +     ctor public FloatProperty(java.lang.String);
    +     method public final void set(T, java.lang.Float);
    +     method public abstract void setValue(T, float);
    +   }
    + 
    +-  public abstract class IntProperty extends android.util.Property {
    ++  public abstract class IntProperty<T> extends android.util.Property {
    +     ctor public IntProperty(java.lang.String);
    +     method public final void set(T, java.lang.Integer);
    +     method public abstract void setValue(T, int);
    +@@ -40503,7 +40506,7 @@ package android.util {
    +     method public void println(java.lang.String);
    +   }
    + 
    +-  public class LongSparseArray implements java.lang.Cloneable {
    ++  public class LongSparseArray<E> implements java.lang.Cloneable {
    +     ctor public LongSparseArray();
    +     ctor public LongSparseArray(int);
    +     method public void append(long, E);
    +@@ -40523,7 +40526,7 @@ package android.util {
    +     method public E valueAt(int);
    +   }
    + 
    +-  public class LruCache {
    ++  public class LruCache<K, V> {
    +     ctor public LruCache(int);
    +     method protected V create(K);
    +     method public final synchronized int createCount();
    +@@ -40611,9 +40614,9 @@ package android.util {
    +     ctor public NoSuchPropertyException(java.lang.String);
    +   }
    + 
    +-  public class Pair {
    ++  public class Pair<F, S> {
    +     ctor public Pair(F, S);
    +-    method public static android.util.Pair<A, B> create(A, B);
    ++    method public static <A, B> android.util.Pair<A, B> create(A, B);
    +     field public final F first;
    +     field public final S second;
    +   }
    +@@ -40646,22 +40649,22 @@ package android.util {
    +     method public abstract void println(java.lang.String);
    +   }
    + 
    +-  public abstract class Property {
    ++  public abstract class Property<T, V> {
    +     ctor public Property(java.lang.Class<V>, java.lang.String);
    +     method public abstract V get(T);
    +     method public java.lang.String getName();
    +     method public java.lang.Class<V> getType();
    +     method public boolean isReadOnly();
    +-    method public static android.util.Property<T, V> of(java.lang.Class<T>, java.lang.Class<V>, java.lang.String);
    ++    method public static <T, V> android.util.Property<T, V> of(java.lang.Class<T>, java.lang.Class<V>, java.lang.String);
    +     method public void set(T, V);
    +   }
    + 
    +-  public final class Range {
    ++  public final class Range<T extends java.lang.Comparable<? super T>> {
    +     ctor public Range(T, T);
    +     method public T clamp(T);
    +     method public boolean contains(T);
    +     method public boolean contains(android.util.Range<T>);
    +-    method public static android.util.Range<T> create(T, T);
    ++    method public static <T extends java.lang.Comparable<? super T>> android.util.Range<T> create(T, T);
    +     method public android.util.Range<T> extend(android.util.Range<T>);
    +     method public android.util.Range<T> extend(T, T);
    +     method public android.util.Range<T> extend(T);
    +@@ -40705,7 +40708,7 @@ package android.util {
    +     method public static android.util.SizeF parseSizeF(java.lang.String) throws java.lang.NumberFormatException;
    +   }
    + 
    +-  public class SparseArray implements java.lang.Cloneable {
    ++  public class SparseArray<E> implements java.lang.Cloneable {
    +     ctor public SparseArray();
    +     ctor public SparseArray(int);
    +     method public void append(int, E);
    +@@ -45434,7 +45437,7 @@ package android.webkit {
    +     method public static java.lang.String stripAnchor(java.lang.String);
    +   }
    + 
    +-  public abstract interface ValueCallback {
    ++  public abstract interface ValueCallback<T> {
    +     method public abstract void onReceiveValue(T);
    +   }
    + 
    +@@ -46168,7 +46171,7 @@ package android.widget {
    +     field public static final int NO_SELECTION = -2147483648; // 0x80000000
    +   }
    + 
    +-  public abstract class AdapterView extends android.view.ViewGroup {
    ++  public abstract class AdapterView<T extends android.widget.Adapter> extends android.view.ViewGroup {
    +     ctor public AdapterView(android.content.Context);
    +     ctor public AdapterView(android.content.Context, android.util.AttributeSet);
    +     ctor public AdapterView(android.content.Context, android.util.AttributeSet, int);
    +@@ -46291,7 +46294,7 @@ package android.widget {
    +     ctor public AnalogClock(android.content.Context, android.util.AttributeSet, int, int);
    +   }
    + 
    +-  public class ArrayAdapter extends android.widget.BaseAdapter implements android.widget.Filterable android.widget.ThemedSpinnerAdapter {
    ++  public class ArrayAdapter<T> extends android.widget.BaseAdapter implements android.widget.Filterable android.widget.ThemedSpinnerAdapter {
    +     ctor public ArrayAdapter(android.content.Context, int);
    +     ctor public ArrayAdapter(android.content.Context, int, int);
    +     ctor public ArrayAdapter(android.content.Context, int, T[]);
    +@@ -46352,7 +46355,7 @@ package android.widget {
    +     method protected void performFiltering(java.lang.CharSequence, int);
    +     method public void performValidation();
    +     method protected void replaceText(java.lang.CharSequence);
    +-    method public void setAdapter(T);
    ++    method public <T extends android.widget.ListAdapter & android.widget.Filterable> void setAdapter(T);
    +     method public void setCompletionHint(java.lang.CharSequence);
    +     method public void setDropDownAnchor(int);
    +     method public void setDropDownBackgroundDrawable(android.graphics.drawable.Drawable);
    +@@ -46603,6 +46606,7 @@ package android.widget {
    +     method public int getFirstDayOfWeek();
    +     method public long getMaxDate();
    +     method public long getMinDate();
    ++    method public int getMode();
    +     method public int getMonth();
    +     method public deprecated boolean getSpinnersShown();
    +     method public int getYear();
    +@@ -46613,6 +46617,8 @@ package android.widget {
    +     method public void setMinDate(long);
    +     method public deprecated void setSpinnersShown(boolean);
    +     method public void updateDate(int, int, int);
    ++    field public static final int MODE_CALENDAR = 2; // 0x2
    ++    field public static final int MODE_SPINNER = 1; // 0x1
    +   }
    + 
    +   public static abstract interface DatePicker.OnDateChangedListener {
    +@@ -48377,6 +48383,7 @@ package android.widget {
    +     method public deprecated java.lang.Integer getCurrentMinute();
    +     method public int getHour();
    +     method public int getMinute();
    ++    method public int getMode();
    +     method public boolean is24HourView();
    +     method public deprecated void setCurrentHour(java.lang.Integer);
    +     method public deprecated void setCurrentMinute(java.lang.Integer);
    +@@ -48384,6 +48391,8 @@ package android.widget {
    +     method public void setIs24HourView(java.lang.Boolean);
    +     method public void setMinute(int);
    +     method public void setOnTimeChangedListener(android.widget.TimePicker.OnTimeChangedListener);
    ++    field public static final int MODE_CLOCK = 2; // 0x2
    ++    field public static final int MODE_SPINNER = 1; // 0x1
    +   }
    + 
    +   public static abstract interface TimePicker.OnTimeChangedListener {
    +@@ -48638,7 +48647,7 @@ package android.widget {
    + 
    + package com.android.internal.util {
    + 
    +-  public abstract interface Predicate {
    ++  public abstract interface Predicate<T> {
    +     method public abstract boolean apply(T);
    +   }
    + 
    +@@ -50685,13 +50694,13 @@ package java.lang {
    +     enum_constant public static final java.lang.Character.UnicodeScript YI;
    +   }
    + 
    +-  public final class Class implements java.lang.reflect.AnnotatedElement java.lang.reflect.GenericDeclaration java.io.Serializable java.lang.reflect.Type {
    +-    method public java.lang.Class<? extends U> asSubclass(java.lang.Class<U>);
    ++  public final class Class<T> implements java.lang.reflect.AnnotatedElement java.lang.reflect.GenericDeclaration java.io.Serializable java.lang.reflect.Type {
    ++    method public <U> java.lang.Class<? extends U> asSubclass(java.lang.Class<U>);
    +     method public T cast(java.lang.Object);
    +     method public boolean desiredAssertionStatus();
    +     method public static java.lang.Class<?> forName(java.lang.String) throws java.lang.ClassNotFoundException;
    +     method public static java.lang.Class<?> forName(java.lang.String, boolean, java.lang.ClassLoader) throws java.lang.ClassNotFoundException;
    +-    method public A getAnnotation(java.lang.Class<A>);
    ++    method public <A extends java.lang.annotation.Annotation> A getAnnotation(java.lang.Class<A>);
    +     method public java.lang.annotation.Annotation[] getAnnotations();
    +     method public java.lang.String getCanonicalName();
    +     method public java.lang.ClassLoader getClassLoader();
    +@@ -50808,7 +50817,7 @@ package java.lang {
    +   public abstract interface Cloneable {
    +   }
    + 
    +-  public abstract interface Comparable {
    ++  public abstract interface Comparable<T> {
    +     method public abstract int compareTo(T);
    +   }
    + 
    +@@ -50862,7 +50871,7 @@ package java.lang {
    +     field public static final java.lang.Class<java.lang.Double> TYPE;
    +   }
    + 
    +-  public abstract class Enum implements java.lang.Comparable java.io.Serializable {
    ++  public abstract class Enum<E extends java.lang.Enum<E>> implements java.lang.Comparable java.io.Serializable {
    +     ctor protected Enum(java.lang.String, int);
    +     method protected final java.lang.Object clone() throws java.lang.CloneNotSupportedException;
    +     method public final int compareTo(E);
    +@@ -50872,7 +50881,7 @@ package java.lang {
    +     method public final int hashCode();
    +     method public final java.lang.String name();
    +     method public final int ordinal();
    +-    method public static T valueOf(java.lang.Class<T>, java.lang.String);
    ++    method public static <T extends java.lang.Enum<T>> T valueOf(java.lang.Class<T>, java.lang.String);
    +   }
    + 
    +   public class EnumConstantNotPresentException extends java.lang.RuntimeException {
    +@@ -50991,7 +51000,7 @@ package java.lang {
    +     ctor public IndexOutOfBoundsException(java.lang.String);
    +   }
    + 
    +-  public class InheritableThreadLocal extends java.lang.ThreadLocal {
    ++  public class InheritableThreadLocal<T> extends java.lang.ThreadLocal {
    +     ctor public InheritableThreadLocal();
    +     method protected T childValue(T);
    +   }
    +@@ -51062,7 +51071,7 @@ package java.lang {
    +     ctor public InterruptedException(java.lang.String);
    +   }
    + 
    +-  public abstract interface Iterable {
    ++  public abstract interface Iterable<T> {
    +     method public default void forEach(java.util.function.Consumer<? super T>);
    +     method public abstract java.util.Iterator<T> iterator();
    +     method public default java.util.Spliterator<T> spliterator();
    +@@ -51270,12 +51279,12 @@ package java.lang {
    +   }
    + 
    +   public class Package implements java.lang.reflect.AnnotatedElement {
    +-    method public A getAnnotation(java.lang.Class<A>);
    ++    method public <A extends java.lang.annotation.Annotation> A getAnnotation(java.lang.Class<A>);
    +     method public java.lang.annotation.Annotation[] getAnnotations();
    +-    method public A[] getAnnotationsByType(java.lang.Class<A>);
    +-    method public A getDeclaredAnnotation(java.lang.Class<A>);
    ++    method public <A extends java.lang.annotation.Annotation> A[] getAnnotationsByType(java.lang.Class<A>);
    ++    method public <A extends java.lang.annotation.Annotation> A getDeclaredAnnotation(java.lang.Class<A>);
    +     method public java.lang.annotation.Annotation[] getDeclaredAnnotations();
    +-    method public A[] getDeclaredAnnotationsByType(java.lang.Class<A>);
    ++    method public <A extends java.lang.annotation.Annotation> A[] getDeclaredAnnotationsByType(java.lang.Class<A>);
    +     method public java.lang.String getImplementationTitle();
    +     method public java.lang.String getImplementationVendor();
    +     method public java.lang.String getImplementationVersion();
    +@@ -51835,7 +51844,7 @@ package java.lang {
    +     method public void uncaughtException(java.lang.Thread, java.lang.Throwable);
    +   }
    + 
    +-  public class ThreadLocal {
    ++  public class ThreadLocal<T> {
    +     ctor public ThreadLocal();
    +     method public T get();
    +     method protected T initialValue();
    +@@ -51975,30 +51984,30 @@ package java.lang.annotation {
    + 
    + package java.lang.ref {
    + 
    +-  public class PhantomReference extends java.lang.ref.Reference {
    ++  public class PhantomReference<T> extends java.lang.ref.Reference {
    +     ctor public PhantomReference(T, java.lang.ref.ReferenceQueue<? super T>);
    +   }
    + 
    +-  public abstract class Reference {
    ++  public abstract class Reference<T> {
    +     method public void clear();
    +     method public boolean enqueue();
    +     method public T get();
    +     method public boolean isEnqueued();
    +   }
    + 
    +-  public class ReferenceQueue {
    ++  public class ReferenceQueue<T> {
    +     ctor public ReferenceQueue();
    +     method public java.lang.ref.Reference<? extends T> poll();
    +     method public java.lang.ref.Reference<? extends T> remove(long) throws java.lang.IllegalArgumentException, java.lang.InterruptedException;
    +     method public java.lang.ref.Reference<? extends T> remove() throws java.lang.InterruptedException;
    +   }
    + 
    +-  public class SoftReference extends java.lang.ref.Reference {
    ++  public class SoftReference<T> extends java.lang.ref.Reference {
    +     ctor public SoftReference(T);
    +     ctor public SoftReference(T, java.lang.ref.ReferenceQueue<? super T>);
    +   }
    + 
    +-  public class WeakReference extends java.lang.ref.Reference {
    ++  public class WeakReference<T> extends java.lang.ref.Reference {
    +     ctor public WeakReference(T);
    +     ctor public WeakReference(T, java.lang.ref.ReferenceQueue<? super T>);
    +   }
    +@@ -52009,7 +52018,7 @@ package java.lang.reflect {
    + 
    +   public class AccessibleObject implements java.lang.reflect.AnnotatedElement {
    +     ctor protected AccessibleObject();
    +-    method public T getAnnotation(java.lang.Class<T>);
    ++    method public <T extends java.lang.annotation.Annotation> T getAnnotation(java.lang.Class<T>);
    +     method public java.lang.annotation.Annotation[] getAnnotations();
    +     method public java.lang.annotation.Annotation[] getDeclaredAnnotations();
    +     method public boolean isAccessible();
    +@@ -52018,12 +52027,12 @@ package java.lang.reflect {
    +   }
    + 
    +   public abstract interface AnnotatedElement {
    +-    method public abstract T getAnnotation(java.lang.Class<T>);
    ++    method public abstract <T extends java.lang.annotation.Annotation> T getAnnotation(java.lang.Class<T>);
    +     method public abstract java.lang.annotation.Annotation[] getAnnotations();
    +-    method public default T[] getAnnotationsByType(java.lang.Class<T>);
    +-    method public default java.lang.annotation.Annotation getDeclaredAnnotation(java.lang.Class<T>);
    ++    method public default <T extends java.lang.annotation.Annotation> T[] getAnnotationsByType(java.lang.Class<T>);
    ++    method public default <T extends java.lang.annotation.Annotation> java.lang.annotation.Annotation getDeclaredAnnotation(java.lang.Class<T>);
    +     method public abstract java.lang.annotation.Annotation[] getDeclaredAnnotations();
    +-    method public default T[] getDeclaredAnnotationsByType(java.lang.Class<T>);
    ++    method public default <T extends java.lang.annotation.Annotation> T[] getDeclaredAnnotationsByType(java.lang.Class<T>);
    +     method public default boolean isAnnotationPresent(java.lang.Class<? extends java.lang.annotation.Annotation>);
    +   }
    + 
    +@@ -52051,8 +52060,8 @@ package java.lang.reflect {
    +     method public static void setShort(java.lang.Object, int, short) throws java.lang.ArrayIndexOutOfBoundsException, java.lang.IllegalArgumentException;
    +   }
    + 
    +-  public final class Constructor extends java.lang.reflect.AccessibleObject implements java.lang.reflect.GenericDeclaration java.lang.reflect.Member {
    +-    method public A getAnnotation(java.lang.Class<A>);
    ++  public final class Constructor<T> extends java.lang.reflect.AccessibleObject implements java.lang.reflect.GenericDeclaration java.lang.reflect.Member {
    ++    method public <A extends java.lang.annotation.Annotation> A getAnnotation(java.lang.Class<A>);
    +     method public java.lang.Class<T> getDeclaringClass();
    +     method public java.lang.Class<?>[] getExceptionTypes();
    +     method public java.lang.reflect.Type[] getGenericExceptionTypes();
    +@@ -52071,7 +52080,7 @@ package java.lang.reflect {
    + 
    +   public final class Field extends java.lang.reflect.AccessibleObject implements java.lang.reflect.Member {
    +     method public java.lang.Object get(java.lang.Object) throws java.lang.IllegalAccessException, java.lang.IllegalArgumentException;
    +-    method public A getAnnotation(java.lang.Class<A>);
    ++    method public <A extends java.lang.annotation.Annotation> A getAnnotation(java.lang.Class<A>);
    +     method public boolean getBoolean(java.lang.Object) throws java.lang.IllegalAccessException, java.lang.IllegalArgumentException;
    +     method public byte getByte(java.lang.Object) throws java.lang.IllegalAccessException, java.lang.IllegalArgumentException;
    +     method public char getChar(java.lang.Object) throws java.lang.IllegalAccessException, java.lang.IllegalArgumentException;
    +@@ -52137,7 +52146,7 @@ package java.lang.reflect {
    +   }
    + 
    +   public final class Method extends java.lang.reflect.AccessibleObject implements java.lang.reflect.GenericDeclaration java.lang.reflect.Member {
    +-    method public A getAnnotation(java.lang.Class<A>);
    ++    method public <A extends java.lang.annotation.Annotation> A getAnnotation(java.lang.Class<A>);
    +     method public java.lang.Class<?> getDeclaringClass();
    +     method public java.lang.Object getDefaultValue();
    +     method public java.lang.Class<?>[] getExceptionTypes();
    +@@ -52215,7 +52224,7 @@ package java.lang.reflect {
    +   public abstract interface Type {
    +   }
    + 
    +-  public abstract interface TypeVariable implements java.lang.reflect.Type {
    ++  public abstract interface TypeVariable<D extends java.lang.reflect.GenericDeclaration> implements java.lang.reflect.Type {
    +     method public abstract java.lang.reflect.Type[] getBounds();
    +     method public abstract D getGenericDeclaration();
    +     method public abstract java.lang.String getName();
    +@@ -53004,7 +53013,7 @@ package java.net {
    +     method public abstract java.net.SocketImpl createSocketImpl();
    +   }
    + 
    +-  public abstract interface SocketOption {
    ++  public abstract interface SocketOption<T> {
    +     method public abstract java.lang.String name();
    +     method public abstract java.lang.Class<T> type();
    +   }
    +@@ -53588,7 +53597,7 @@ package java.nio.channels {
    +     method public final long read(java.nio.ByteBuffer[]) throws java.io.IOException;
    +     method public abstract java.net.SocketAddress receive(java.nio.ByteBuffer) throws java.io.IOException;
    +     method public abstract int send(java.nio.ByteBuffer, java.net.SocketAddress) throws java.io.IOException;
    +-    method public abstract java.nio.channels.DatagramChannel setOption(java.net.SocketOption<T>, T) throws java.io.IOException;
    ++    method public abstract <T> java.nio.channels.DatagramChannel setOption(java.net.SocketOption<T>, T) throws java.io.IOException;
    +     method public abstract java.net.DatagramSocket socket();
    +     method public final int validOps();
    +     method public abstract int write(java.nio.ByteBuffer) throws java.io.IOException;
    +@@ -53664,8 +53673,8 @@ package java.nio.channels {
    +   public abstract interface NetworkChannel implements java.nio.channels.Channel {
    +     method public abstract java.nio.channels.NetworkChannel bind(java.net.SocketAddress) throws java.io.IOException;
    +     method public abstract java.net.SocketAddress getLocalAddress() throws java.io.IOException;
    +-    method public abstract T getOption(java.net.SocketOption<T>) throws java.io.IOException;
    +-    method public abstract java.nio.channels.NetworkChannel setOption(java.net.SocketOption<T>, T) throws java.io.IOException;
    ++    method public abstract <T> T getOption(java.net.SocketOption<T>) throws java.io.IOException;
    ++    method public abstract <T> java.nio.channels.NetworkChannel setOption(java.net.SocketOption<T>, T) throws java.io.IOException;
    +     method public abstract java.util.Set<java.net.SocketOption<?>> supportedOptions();
    +   }
    + 
    +@@ -53782,7 +53791,7 @@ package java.nio.channels {
    +     method public final java.nio.channels.ServerSocketChannel bind(java.net.SocketAddress) throws java.io.IOException;
    +     method public abstract java.nio.channels.ServerSocketChannel bind(java.net.SocketAddress, int) throws java.io.IOException;
    +     method public static java.nio.channels.ServerSocketChannel open() throws java.io.IOException;
    +-    method public abstract java.nio.channels.ServerSocketChannel setOption(java.net.SocketOption<T>, T) throws java.io.IOException;
    ++    method public abstract <T> java.nio.channels.ServerSocketChannel setOption(java.net.SocketOption<T>, T) throws java.io.IOException;
    +     method public abstract java.net.ServerSocket socket();
    +     method public final int validOps();
    +   }
    +@@ -53800,7 +53809,7 @@ package java.nio.channels {
    +     method public abstract int read(java.nio.ByteBuffer) throws java.io.IOException;
    +     method public abstract long read(java.nio.ByteBuffer[], int, int) throws java.io.IOException;
    +     method public final long read(java.nio.ByteBuffer[]) throws java.io.IOException;
    +-    method public abstract java.nio.channels.SocketChannel setOption(java.net.SocketOption<T>, T) throws java.io.IOException;
    ++    method public abstract <T> java.nio.channels.SocketChannel setOption(java.net.SocketOption<T>, T) throws java.io.IOException;
    +     method public abstract java.nio.channels.SocketChannel shutdownInput() throws java.io.IOException;
    +     method public abstract java.nio.channels.SocketChannel shutdownOutput() throws java.io.IOException;
    +     method public abstract java.net.Socket socket();
    +@@ -54047,12 +54056,12 @@ package java.security {
    + 
    +   public final class AccessController {
    +     method public static void checkPermission(java.security.Permission) throws java.security.AccessControlException;
    +-    method public static T doPrivileged(java.security.PrivilegedAction<T>);
    +-    method public static T doPrivileged(java.security.PrivilegedAction<T>, java.security.AccessControlContext);
    +-    method public static T doPrivileged(java.security.PrivilegedExceptionAction<T>) throws java.security.PrivilegedActionException;
    +-    method public static T doPrivileged(java.security.PrivilegedExceptionAction<T>, java.security.AccessControlContext) throws java.security.PrivilegedActionException;
    +-    method public static T doPrivilegedWithCombiner(java.security.PrivilegedAction<T>);
    +-    method public static T doPrivilegedWithCombiner(java.security.PrivilegedExceptionAction<T>) throws java.security.PrivilegedActionException;
    ++    method public static <T> T doPrivileged(java.security.PrivilegedAction<T>);
    ++    method public static <T> T doPrivileged(java.security.PrivilegedAction<T>, java.security.AccessControlContext);
    ++    method public static <T> T doPrivileged(java.security.PrivilegedExceptionAction<T>) throws java.security.PrivilegedActionException;
    ++    method public static <T> T doPrivileged(java.security.PrivilegedExceptionAction<T>, java.security.AccessControlContext) throws java.security.PrivilegedActionException;
    ++    method public static <T> T doPrivilegedWithCombiner(java.security.PrivilegedAction<T>);
    ++    method public static <T> T doPrivilegedWithCombiner(java.security.PrivilegedExceptionAction<T>) throws java.security.PrivilegedActionException;
    +     method public static java.security.AccessControlContext getContext();
    +   }
    + 
    +@@ -54091,7 +54100,7 @@ package java.security {
    +     method public static java.security.AlgorithmParameters getInstance(java.lang.String) throws java.security.NoSuchAlgorithmException;
    +     method public static java.security.AlgorithmParameters getInstance(java.lang.String, java.lang.String) throws java.security.NoSuchAlgorithmException, java.security.NoSuchProviderException;
    +     method public static java.security.AlgorithmParameters getInstance(java.lang.String, java.security.Provider) throws java.security.NoSuchAlgorithmException;
    +-    method public final T getParameterSpec(java.lang.Class<T>) throws java.security.spec.InvalidParameterSpecException;
    ++    method public final <T extends java.security.spec.AlgorithmParameterSpec> T getParameterSpec(java.lang.Class<T>) throws java.security.spec.InvalidParameterSpecException;
    +     method public final java.security.Provider getProvider();
    +     method public final void init(java.security.spec.AlgorithmParameterSpec) throws java.security.spec.InvalidParameterSpecException;
    +     method public final void init(byte[]) throws java.io.IOException;
    +@@ -54103,7 +54112,7 @@ package java.security {
    +     ctor public AlgorithmParametersSpi();
    +     method protected abstract byte[] engineGetEncoded() throws java.io.IOException;
    +     method protected abstract byte[] engineGetEncoded(java.lang.String) throws java.io.IOException;
    +-    method protected abstract T engineGetParameterSpec(java.lang.Class<T>) throws java.security.spec.InvalidParameterSpecException;
    ++    method protected abstract <T extends java.security.spec.AlgorithmParameterSpec> T engineGetParameterSpec(java.lang.Class<T>) throws java.security.spec.InvalidParameterSpecException;
    +     method protected abstract void engineInit(java.security.spec.AlgorithmParameterSpec) throws java.security.spec.InvalidParameterSpecException;
    +     method protected abstract void engineInit(byte[]) throws java.io.IOException;
    +     method protected abstract void engineInit(byte[], java.lang.String) throws java.io.IOException;
    +@@ -54288,7 +54297,7 @@ package java.security {
    +     method public static java.security.KeyFactory getInstance(java.lang.String) throws java.security.NoSuchAlgorithmException;
    +     method public static java.security.KeyFactory getInstance(java.lang.String, java.lang.String) throws java.security.NoSuchAlgorithmException, java.security.NoSuchProviderException;
    +     method public static java.security.KeyFactory getInstance(java.lang.String, java.security.Provider) throws java.security.NoSuchAlgorithmException;
    +-    method public final T getKeySpec(java.security.Key, java.lang.Class<T>) throws java.security.spec.InvalidKeySpecException;
    ++    method public final <T extends java.security.spec.KeySpec> T getKeySpec(java.security.Key, java.lang.Class<T>) throws java.security.spec.InvalidKeySpecException;
    +     method public final java.security.Provider getProvider();
    +     method public final java.security.Key translateKey(java.security.Key) throws java.security.InvalidKeyException;
    +   }
    +@@ -54297,7 +54306,7 @@ package java.security {
    +     ctor public KeyFactorySpi();
    +     method protected abstract java.security.PrivateKey engineGeneratePrivate(java.security.spec.KeySpec) throws java.security.spec.InvalidKeySpecException;
    +     method protected abstract java.security.PublicKey engineGeneratePublic(java.security.spec.KeySpec) throws java.security.spec.InvalidKeySpecException;
    +-    method protected abstract T engineGetKeySpec(java.security.Key, java.lang.Class<T>) throws java.security.spec.InvalidKeySpecException;
    ++    method protected abstract <T extends java.security.spec.KeySpec> T engineGetKeySpec(java.security.Key, java.lang.Class<T>) throws java.security.spec.InvalidKeySpecException;
    +     method protected abstract java.security.Key engineTranslateKey(java.security.Key) throws java.security.InvalidKeyException;
    +   }
    + 
    +@@ -54566,7 +54575,7 @@ package java.security {
    +     field public static final long serialVersionUID = 6034044314589513430L; // 0x53bd3b559a12c6d6L
    +   }
    + 
    +-  public abstract interface PrivilegedAction {
    ++  public abstract interface PrivilegedAction<T> {
    +     method public abstract T run();
    +   }
    + 
    +@@ -54575,7 +54584,7 @@ package java.security {
    +     method public java.lang.Exception getException();
    +   }
    + 
    +-  public abstract interface PrivilegedExceptionAction {
    ++  public abstract interface PrivilegedExceptionAction<T> {
    +     method public abstract T run() throws java.lang.Exception;
    +   }
    + 
    +@@ -56757,11 +56766,11 @@ package java.sql {
    +     method public abstract void free() throws java.sql.SQLException;
    +     method public abstract java.io.InputStream getBinaryStream() throws java.sql.SQLException;
    +     method public abstract java.io.Reader getCharacterStream() throws java.sql.SQLException;
    +-    method public abstract T getSource(java.lang.Class<T>) throws java.sql.SQLException;
    ++    method public abstract <T extends javax.xml.transform.Source> T getSource(java.lang.Class<T>) throws java.sql.SQLException;
    +     method public abstract java.lang.String getString() throws java.sql.SQLException;
    +     method public abstract java.io.OutputStream setBinaryStream() throws java.sql.SQLException;
    +     method public abstract java.io.Writer setCharacterStream() throws java.sql.SQLException;
    +-    method public abstract T setResult(java.lang.Class<T>) throws java.sql.SQLException;
    ++    method public abstract <T extends javax.xml.transform.Result> T setResult(java.lang.Class<T>) throws java.sql.SQLException;
    +     method public abstract void setString(java.lang.String) throws java.sql.SQLException;
    +   }
    + 
    +@@ -56885,7 +56894,7 @@ package java.sql {
    + 
    +   public abstract interface Wrapper {
    +     method public abstract boolean isWrapperFor(java.lang.Class<?>) throws java.sql.SQLException;
    +-    method public abstract T unwrap(java.lang.Class<T>) throws java.sql.SQLException;
    ++    method public abstract <T> T unwrap(java.lang.Class<T>) throws java.sql.SQLException;
    +   }
    + 
    + }
    +@@ -57418,7 +57427,7 @@ package java.text {
    + 
    + package java.util {
    + 
    +-  public abstract class AbstractCollection implements java.util.Collection {
    ++  public abstract class AbstractCollection<E> implements java.util.Collection {
    +     ctor protected AbstractCollection();
    +     method public boolean add(E);
    +     method public boolean addAll(java.util.Collection<? extends E>);
    +@@ -57432,10 +57441,10 @@ package java.util {
    +     method public boolean retainAll(java.util.Collection<?>);
    +     method public abstract int size();
    +     method public java.lang.Object[] toArray();
    +-    method public T[] toArray(T[]);
    ++    method public <T> T[] toArray(T[]);
    +   }
    + 
    +-  public abstract class AbstractList extends java.util.AbstractCollection implements java.util.List {
    ++  public abstract class AbstractList<E> extends java.util.AbstractCollection implements java.util.List {
    +     ctor protected AbstractList();
    +     method public void add(int, E);
    +     method public boolean addAll(int, java.util.Collection<? extends E>);
    +@@ -57452,7 +57461,7 @@ package java.util {
    +     field protected transient int modCount;
    +   }
    + 
    +-  public abstract class AbstractMap implements java.util.Map {
    ++  public abstract class AbstractMap<K, V> implements java.util.Map {
    +     ctor protected AbstractMap();
    +     method public void clear();
    +     method public boolean containsKey(java.lang.Object);
    +@@ -57468,7 +57477,7 @@ package java.util {
    +     method public java.util.Collection<V> values();
    +   }
    + 
    +-  public static class AbstractMap.SimpleEntry implements java.util.Map.Entry java.io.Serializable {
    ++  public static class AbstractMap.SimpleEntry<K, V> implements java.util.Map.Entry java.io.Serializable {
    +     ctor public AbstractMap.SimpleEntry(K, V);
    +     ctor public AbstractMap.SimpleEntry(java.util.Map.Entry<? extends K, ? extends V>);
    +     method public K getKey();
    +@@ -57476,7 +57485,7 @@ package java.util {
    +     method public V setValue(V);
    +   }
    + 
    +-  public static class AbstractMap.SimpleImmutableEntry implements java.util.Map.Entry java.io.Serializable {
    ++  public static class AbstractMap.SimpleImmutableEntry<K, V> implements java.util.Map.Entry java.io.Serializable {
    +     ctor public AbstractMap.SimpleImmutableEntry(K, V);
    +     ctor public AbstractMap.SimpleImmutableEntry(java.util.Map.Entry<? extends K, ? extends V>);
    +     method public K getKey();
    +@@ -57484,23 +57493,23 @@ package java.util {
    +     method public V setValue(V);
    +   }
    + 
    +-  public abstract class AbstractQueue extends java.util.AbstractCollection implements java.util.Queue {
    ++  public abstract class AbstractQueue<E> extends java.util.AbstractCollection implements java.util.Queue {
    +     ctor protected AbstractQueue();
    +     method public E element();
    +     method public E remove();
    +   }
    + 
    +-  public abstract class AbstractSequentialList extends java.util.AbstractList {
    ++  public abstract class AbstractSequentialList<E> extends java.util.AbstractList {
    +     ctor protected AbstractSequentialList();
    +     method public E get(int);
    +     method public abstract java.util.ListIterator<E> listIterator(int);
    +   }
    + 
    +-  public abstract class AbstractSet extends java.util.AbstractCollection implements java.util.Set {
    ++  public abstract class AbstractSet<E> extends java.util.AbstractCollection implements java.util.Set {
    +     ctor protected AbstractSet();
    +   }
    + 
    +-  public class ArrayDeque extends java.util.AbstractCollection implements java.lang.Cloneable java.util.Deque java.io.Serializable {
    ++  public class ArrayDeque<E> extends java.util.AbstractCollection implements java.lang.Cloneable java.util.Deque java.io.Serializable {
    +     ctor public ArrayDeque();
    +     ctor public ArrayDeque(int);
    +     ctor public ArrayDeque(java.util.Collection<? extends E>);
    +@@ -57532,7 +57541,7 @@ package java.util {
    +     method public java.util.Spliterator<E> spliterator();
    +   }
    + 
    +-  public class ArrayList extends java.util.AbstractList implements java.lang.Cloneable java.util.List java.util.RandomAccess java.io.Serializable {
    ++  public class ArrayList<E> extends java.util.AbstractList implements java.lang.Cloneable java.util.List java.util.RandomAccess java.io.Serializable {
    +     ctor public ArrayList(int);
    +     ctor public ArrayList();
    +     ctor public ArrayList(java.util.Collection<? extends E>);
    +@@ -57549,7 +57558,7 @@ package java.util {
    +   }
    + 
    +   public class Arrays {
    +-    method public static java.util.List<T> asList(T...);
    ++    method public static <T> java.util.List<T> asList(T...);
    +     method public static int binarySearch(long[], long);
    +     method public static int binarySearch(long[], int, int, long);
    +     method public static int binarySearch(int[], int);
    +@@ -57566,10 +57575,10 @@ package java.util {
    +     method public static int binarySearch(float[], int, int, float);
    +     method public static int binarySearch(java.lang.Object[], java.lang.Object);
    +     method public static int binarySearch(java.lang.Object[], int, int, java.lang.Object);
    +-    method public static int binarySearch(T[], T, java.util.Comparator<? super T>);
    +-    method public static int binarySearch(T[], int, int, T, java.util.Comparator<? super T>);
    +-    method public static T[] copyOf(T[], int);
    +-    method public static T[] copyOf(U[], int, java.lang.Class<? extends T[]>);
    ++    method public static <T> int binarySearch(T[], T, java.util.Comparator<? super T>);
    ++    method public static <T> int binarySearch(T[], int, int, T, java.util.Comparator<? super T>);
    ++    method public static <T> T[] copyOf(T[], int);
    ++    method public static <T, U> T[] copyOf(U[], int, java.lang.Class<? extends T[]>);
    +     method public static byte[] copyOf(byte[], int);
    +     method public static short[] copyOf(short[], int);
    +     method public static int[] copyOf(int[], int);
    +@@ -57578,8 +57587,8 @@ package java.util {
    +     method public static float[] copyOf(float[], int);
    +     method public static double[] copyOf(double[], int);
    +     method public static boolean[] copyOf(boolean[], int);
    +-    method public static T[] copyOfRange(T[], int, int);
    +-    method public static T[] copyOfRange(U[], int, int, java.lang.Class<? extends T[]>);
    ++    method public static <T> T[] copyOfRange(T[], int, int);
    ++    method public static <T, U> T[] copyOfRange(U[], int, int, java.lang.Class<? extends T[]>);
    +     method public static byte[] copyOfRange(byte[], int, int);
    +     method public static short[] copyOfRange(short[], int, int);
    +     method public static int[] copyOfRange(int[], int, int);
    +@@ -57627,15 +57636,15 @@ package java.util {
    +     method public static int hashCode(float[]);
    +     method public static int hashCode(double[]);
    +     method public static int hashCode(java.lang.Object[]);
    +-    method public static void parallelPrefix(T[], java.util.function.BinaryOperator<T>);
    +-    method public static void parallelPrefix(T[], int, int, java.util.function.BinaryOperator<T>);
    ++    method public static <T> void parallelPrefix(T[], java.util.function.BinaryOperator<T>);
    ++    method public static <T> void parallelPrefix(T[], int, int, java.util.function.BinaryOperator<T>);
    +     method public static void parallelPrefix(long[], java.util.function.LongBinaryOperator);
    +     method public static void parallelPrefix(long[], int, int, java.util.function.LongBinaryOperator);
    +     method public static void parallelPrefix(double[], java.util.function.DoubleBinaryOperator);
    +     method public static void parallelPrefix(double[], int, int, java.util.function.DoubleBinaryOperator);
    +     method public static void parallelPrefix(int[], java.util.function.IntBinaryOperator);
    +     method public static void parallelPrefix(int[], int, int, java.util.function.IntBinaryOperator);
    +-    method public static void parallelSetAll(T[], java.util.function.IntFunction<? extends T>);
    ++    method public static <T> void parallelSetAll(T[], java.util.function.IntFunction<? extends T>);
    +     method public static void parallelSetAll(int[], java.util.function.IntUnaryOperator);
    +     method public static void parallelSetAll(long[], java.util.function.IntToLongFunction);
    +     method public static void parallelSetAll(double[], java.util.function.IntToDoubleFunction);
    +@@ -57653,11 +57662,11 @@ package java.util {
    +     method public static void parallelSort(float[], int, int);
    +     method public static void parallelSort(double[]);
    +     method public static void parallelSort(double[], int, int);
    +-    method public static void parallelSort(T[]);
    +-    method public static void parallelSort(T[], int, int);
    +-    method public static void parallelSort(T[], java.util.Comparator<? super T>);
    +-    method public static void parallelSort(T[], int, int, java.util.Comparator<? super T>);
    +-    method public static void setAll(T[], java.util.function.IntFunction<? extends T>);
    ++    method public static <T extends java.lang.Comparable<? super T>> void parallelSort(T[]);
    ++    method public static <T extends java.lang.Comparable<? super T>> void parallelSort(T[], int, int);
    ++    method public static <T> void parallelSort(T[], java.util.Comparator<? super T>);
    ++    method public static <T> void parallelSort(T[], int, int, java.util.Comparator<? super T>);
    ++    method public static <T> void setAll(T[], java.util.function.IntFunction<? extends T>);
    +     method public static void setAll(int[], java.util.function.IntUnaryOperator);
    +     method public static void setAll(long[], java.util.function.IntToLongFunction);
    +     method public static void setAll(double[], java.util.function.IntToDoubleFunction);
    +@@ -57677,18 +57686,18 @@ package java.util {
    +     method public static void sort(double[], int, int);
    +     method public static void sort(java.lang.Object[]);
    +     method public static void sort(java.lang.Object[], int, int);
    +-    method public static void sort(T[], java.util.Comparator<? super T>);
    +-    method public static void sort(T[], int, int, java.util.Comparator<? super T>);
    +-    method public static java.util.Spliterator<T> spliterator(T[]);
    +-    method public static java.util.Spliterator<T> spliterator(T[], int, int);
    ++    method public static <T> void sort(T[], java.util.Comparator<? super T>);
    ++    method public static <T> void sort(T[], int, int, java.util.Comparator<? super T>);
    ++    method public static <T> java.util.Spliterator<T> spliterator(T[]);
    ++    method public static <T> java.util.Spliterator<T> spliterator(T[], int, int);
    +     method public static java.util.Spliterator.OfInt spliterator(int[]);
    +     method public static java.util.Spliterator.OfInt spliterator(int[], int, int);
    +     method public static java.util.Spliterator.OfLong spliterator(long[]);
    +     method public static java.util.Spliterator.OfLong spliterator(long[], int, int);
    +     method public static java.util.Spliterator.OfDouble spliterator(double[]);
    +     method public static java.util.Spliterator.OfDouble spliterator(double[], int, int);
    +-    method public static java.util.stream.Stream<T> stream(T[]);
    +-    method public static java.util.stream.Stream<T> stream(T[], int, int);
    ++    method public static <T> java.util.stream.Stream<T> stream(T[]);
    ++    method public static <T> java.util.stream.Stream<T> stream(T[], int, int);
    +     method public static java.util.stream.IntStream stream(int[]);
    +     method public static java.util.stream.IntStream stream(int[], int, int);
    +     method public static java.util.stream.LongStream stream(long[]);
    +@@ -57845,7 +57854,7 @@ package java.util {
    +     field protected long time;
    +   }
    + 
    +-  public abstract interface Collection implements java.lang.Iterable {
    ++  public abstract interface Collection<E> implements java.lang.Iterable {
    +     method public abstract boolean add(E);
    +     method public abstract boolean addAll(java.util.Collection<? extends E>);
    +     method public abstract void clear();
    +@@ -57863,86 +57872,86 @@ package java.util {
    +     method public abstract int size();
    +     method public default java.util.stream.Stream<E> stream();
    +     method public abstract java.lang.Object[] toArray();
    +-    method public abstract T[] toArray(T[]);
    ++    method public abstract <T> T[] toArray(T[]);
    +   }
    + 
    +   public class Collections {
    +-    method public static boolean addAll(java.util.Collection<? super T>, T...);
    +-    method public static java.util.Queue<T> asLifoQueue(java.util.Deque<T>);
    +-    method public static int binarySearch(java.util.List<? extends java.lang.Comparable<? super T>>, T);
    +-    method public static int binarySearch(java.util.List<? extends T>, T, java.util.Comparator<? super T>);
    +-    method public static java.util.Collection<E> checkedCollection(java.util.Collection<E>, java.lang.Class<E>);
    +-    method public static java.util.List<E> checkedList(java.util.List<E>, java.lang.Class<E>);
    +-    method public static java.util.Map<K, V> checkedMap(java.util.Map<K, V>, java.lang.Class<K>, java.lang.Class<V>);
    +-    method public static java.util.Set<E> checkedSet(java.util.Set<E>, java.lang.Class<E>);
    +-    method public static java.util.SortedMap<K, V> checkedSortedMap(java.util.SortedMap<K, V>, java.lang.Class<K>, java.lang.Class<V>);
    +-    method public static java.util.SortedSet<E> checkedSortedSet(java.util.SortedSet<E>, java.lang.Class<E>);
    +-    method public static void copy(java.util.List<? super T>, java.util.List<? extends T>);
    ++    method public static <T> boolean addAll(java.util.Collection<? super T>, T...);
    ++    method public static <T> java.util.Queue<T> asLifoQueue(java.util.Deque<T>);
    ++    method public static <T> int binarySearch(java.util.List<? extends java.lang.Comparable<? super T>>, T);
    ++    method public static <T> int binarySearch(java.util.List<? extends T>, T, java.util.Comparator<? super T>);
    ++    method public static <E> java.util.Collection<E> checkedCollection(java.util.Collection<E>, java.lang.Class<E>);
    ++    method public static <E> java.util.List<E> checkedList(java.util.List<E>, java.lang.Class<E>);
    ++    method public static <K, V> java.util.Map<K, V> checkedMap(java.util.Map<K, V>, java.lang.Class<K>, java.lang.Class<V>);
    ++    method public static <E> java.util.Set<E> checkedSet(java.util.Set<E>, java.lang.Class<E>);
    ++    method public static <K, V> java.util.SortedMap<K, V> checkedSortedMap(java.util.SortedMap<K, V>, java.lang.Class<K>, java.lang.Class<V>);
    ++    method public static <E> java.util.SortedSet<E> checkedSortedSet(java.util.SortedSet<E>, java.lang.Class<E>);
    ++    method public static <T> void copy(java.util.List<? super T>, java.util.List<? extends T>);
    +     method public static boolean disjoint(java.util.Collection<?>, java.util.Collection<?>);
    +-    method public static java.util.Enumeration<T> emptyEnumeration();
    +-    method public static java.util.Iterator<T> emptyIterator();
    +-    method public static final java.util.List<T> emptyList();
    +-    method public static java.util.ListIterator<T> emptyListIterator();
    +-    method public static final java.util.Map<K, V> emptyMap();
    +-    method public static final java.util.Set<T> emptySet();
    +-    method public static java.util.Enumeration<T> enumeration(java.util.Collection<T>);
    +-    method public static void fill(java.util.List<? super T>, T);
    ++    method public static <T> java.util.Enumeration<T> emptyEnumeration();
    ++    method public static <T> java.util.Iterator<T> emptyIterator();
    ++    method public static final <T> java.util.List<T> emptyList();
    ++    method public static <T> java.util.ListIterator<T> emptyListIterator();
    ++    method public static final <K, V> java.util.Map<K, V> emptyMap();
    ++    method public static final <T> java.util.Set<T> emptySet();
    ++    method public static <T> java.util.Enumeration<T> enumeration(java.util.Collection<T>);
    ++    method public static <T> void fill(java.util.List<? super T>, T);
    +     method public static int frequency(java.util.Collection<?>, java.lang.Object);
    +     method public static int indexOfSubList(java.util.List<?>, java.util.List<?>);
    +     method public static int lastIndexOfSubList(java.util.List<?>, java.util.List<?>);
    +-    method public static java.util.ArrayList<T> list(java.util.Enumeration<T>);
    +-    method public static T max(java.util.Collection<? extends T>);
    +-    method public static T max(java.util.Collection<? extends T>, java.util.Comparator<? super T>);
    +-    method public static T min(java.util.Collection<? extends T>);
    +-    method public static T min(java.util.Collection<? extends T>, java.util.Comparator<? super T>);
    +-    method public static java.util.List<T> nCopies(int, T);
    +-    method public static java.util.Set<E> newSetFromMap(java.util.Map<E, java.lang.Boolean>);
    +-    method public static boolean replaceAll(java.util.List<T>, T, T);
    ++    method public static <T> java.util.ArrayList<T> list(java.util.Enumeration<T>);
    ++    method public static <T extends java.lang.Object & java.lang.Comparable<? super T>> T max(java.util.Collection<? extends T>);
    ++    method public static <T> T max(java.util.Collection<? extends T>, java.util.Comparator<? super T>);
    ++    method public static <T extends java.lang.Object & java.lang.Comparable<? super T>> T min(java.util.Collection<? extends T>);
    ++    method public static <T> T min(java.util.Collection<? extends T>, java.util.Comparator<? super T>);
    ++    method public static <T> java.util.List<T> nCopies(int, T);
    ++    method public static <E> java.util.Set<E> newSetFromMap(java.util.Map<E, java.lang.Boolean>);
    ++    method public static <T> boolean replaceAll(java.util.List<T>, T, T);
    +     method public static void reverse(java.util.List<?>);
    +-    method public static java.util.Comparator<T> reverseOrder();
    +-    method public static java.util.Comparator<T> reverseOrder(java.util.Comparator<T>);
    ++    method public static <T> java.util.Comparator<T> reverseOrder();
    ++    method public static <T> java.util.Comparator<T> reverseOrder(java.util.Comparator<T>);
    +     method public static void rotate(java.util.List<?>, int);
    +     method public static void shuffle(java.util.List<?>);
    +     method public static void shuffle(java.util.List<?>, java.util.Random);
    +-    method public static java.util.Set<E> singleton(E);
    +-    method public static java.util.List<E> singletonList(E);
    +-    method public static java.util.Map<K, V> singletonMap(K, V);
    +-    method public static void sort(java.util.List<T>);
    +-    method public static void sort(java.util.List<T>, java.util.Comparator<? super T>);
    ++    method public static <E> java.util.Set<E> singleton(E);
    ++    method public static <E> java.util.List<E> singletonList(E);
    ++    method public static <K, V> java.util.Map<K, V> singletonMap(K, V);
    ++    method public static <T extends java.lang.Comparable<? super T>> void sort(java.util.List<T>);
    ++    method public static <T> void sort(java.util.List<T>, java.util.Comparator<? super T>);
    +     method public static void swap(java.util.List<?>, int, int);
    +-    method public static java.util.Collection<T> synchronizedCollection(java.util.Collection<T>);
    +-    method public static java.util.List<T> synchronizedList(java.util.List<T>);
    +-    method public static java.util.Map<K, V> synchronizedMap(java.util.Map<K, V>);
    +-    method public static java.util.Set<T> synchronizedSet(java.util.Set<T>);
    +-    method public static java.util.SortedMap<K, V> synchronizedSortedMap(java.util.SortedMap<K, V>);
    +-    method public static java.util.SortedSet<T> synchronizedSortedSet(java.util.SortedSet<T>);
    +-    method public static java.util.Collection<T> unmodifiableCollection(java.util.Collection<? extends T>);
    +-    method public static java.util.List<T> unmodifiableList(java.util.List<? extends T>);
    +-    method public static java.util.Map<K, V> unmodifiableMap(java.util.Map<? extends K, ? extends V>);
    +-    method public static java.util.Set<T> unmodifiableSet(java.util.Set<? extends T>);
    +-    method public static java.util.SortedMap<K, V> unmodifiableSortedMap(java.util.SortedMap<K, ? extends V>);
    +-    method public static java.util.SortedSet<T> unmodifiableSortedSet(java.util.SortedSet<T>);
    ++    method public static <T> java.util.Collection<T> synchronizedCollection(java.util.Collection<T>);
    ++    method public static <T> java.util.List<T> synchronizedList(java.util.List<T>);
    ++    method public static <K, V> java.util.Map<K, V> synchronizedMap(java.util.Map<K, V>);
    ++    method public static <T> java.util.Set<T> synchronizedSet(java.util.Set<T>);
    ++    method public static <K, V> java.util.SortedMap<K, V> synchronizedSortedMap(java.util.SortedMap<K, V>);
    ++    method public static <T> java.util.SortedSet<T> synchronizedSortedSet(java.util.SortedSet<T>);
    ++    method public static <T> java.util.Collection<T> unmodifiableCollection(java.util.Collection<? extends T>);
    ++    method public static <T> java.util.List<T> unmodifiableList(java.util.List<? extends T>);
    ++    method public static <K, V> java.util.Map<K, V> unmodifiableMap(java.util.Map<? extends K, ? extends V>);
    ++    method public static <T> java.util.Set<T> unmodifiableSet(java.util.Set<? extends T>);
    ++    method public static <K, V> java.util.SortedMap<K, V> unmodifiableSortedMap(java.util.SortedMap<K, ? extends V>);
    ++    method public static <T> java.util.SortedSet<T> unmodifiableSortedSet(java.util.SortedSet<T>);
    +     field public static final java.util.List EMPTY_LIST;
    +     field public static final java.util.Map EMPTY_MAP;
    +     field public static final java.util.Set EMPTY_SET;
    +   }
    + 
    +-  public abstract interface Comparator {
    ++  public abstract interface Comparator<T> {
    +     method public abstract int compare(T, T);
    +-    method public static java.util.Comparator<T> comparing(java.util.function.Function<? super T, ? extends U>, java.util.Comparator<? super U>);
    +-    method public static java.util.Comparator<T> comparing(java.util.function.Function<? super T, ? extends U>);
    +-    method public static java.util.Comparator<T> comparingDouble(java.util.function.ToDoubleFunction<? super T>);
    +-    method public static java.util.Comparator<T> comparingInt(java.util.function.ToIntFunction<? super T>);
    +-    method public static java.util.Comparator<T> comparingLong(java.util.function.ToLongFunction<? super T>);
    ++    method public static <T, U> java.util.Comparator<T> comparing(java.util.function.Function<? super T, ? extends U>, java.util.Comparator<? super U>);
    ++    method public static <T, U extends java.lang.Comparable<? super U>> java.util.Comparator<T> comparing(java.util.function.Function<? super T, ? extends U>);
    ++    method public static <T> java.util.Comparator<T> comparingDouble(java.util.function.ToDoubleFunction<? super T>);
    ++    method public static <T> java.util.Comparator<T> comparingInt(java.util.function.ToIntFunction<? super T>);
    ++    method public static <T> java.util.Comparator<T> comparingLong(java.util.function.ToLongFunction<? super T>);
    +     method public abstract boolean equals(java.lang.Object);
    +-    method public static java.util.Comparator<T> naturalOrder();
    +-    method public static java.util.Comparator<T> nullsFirst(java.util.Comparator<? super T>);
    +-    method public static java.util.Comparator<T> nullsLast(java.util.Comparator<? super T>);
    +-    method public static java.util.Comparator<T> reverseOrder();
    ++    method public static <T extends java.lang.Comparable<? super T>> java.util.Comparator<T> naturalOrder();
    ++    method public static <T> java.util.Comparator<T> nullsFirst(java.util.Comparator<? super T>);
    ++    method public static <T> java.util.Comparator<T> nullsLast(java.util.Comparator<? super T>);
    ++    method public static <T extends java.lang.Comparable<? super T>> java.util.Comparator<T> reverseOrder();
    +     method public default java.util.Comparator<T> reversed();
    +     method public default java.util.Comparator<T> thenComparing(java.util.Comparator<? super T>);
    +-    method public default java.util.Comparator<T> thenComparing(java.util.function.Function<? super T, ? extends U>, java.util.Comparator<? super U>);
    +-    method public default java.util.Comparator<T> thenComparing(java.util.function.Function<? super T, ? extends U>);
    ++    method public default <U> java.util.Comparator<T> thenComparing(java.util.function.Function<? super T, ? extends U>, java.util.Comparator<? super U>);
    ++    method public default <U extends java.lang.Comparable<? super U>> java.util.Comparator<T> thenComparing(java.util.function.Function<? super T, ? extends U>);
    +     method public default java.util.Comparator<T> thenComparingDouble(java.util.function.ToDoubleFunction<? super T>);
    +     method public default java.util.Comparator<T> thenComparingInt(java.util.function.ToIntFunction<? super T>);
    +     method public default java.util.Comparator<T> thenComparingLong(java.util.function.ToLongFunction<? super T>);
    +@@ -58001,7 +58010,7 @@ package java.util {
    +     method public deprecated java.lang.String toLocaleString();
    +   }
    + 
    +-  public abstract interface Deque implements java.util.Queue {
    ++  public abstract interface Deque<E> implements java.util.Queue {
    +     method public abstract boolean add(E);
    +     method public abstract void addFirst(E);
    +     method public abstract void addLast(E);
    +@@ -58031,7 +58040,7 @@ package java.util {
    +     method public abstract int size();
    +   }
    + 
    +-  public abstract class Dictionary {
    ++  public abstract class Dictionary<K, V> {
    +     ctor public Dictionary();
    +     method public abstract java.util.Enumeration<V> elements();
    +     method public abstract V get(java.lang.Object);
    +@@ -58062,7 +58071,7 @@ package java.util {
    +     ctor public EmptyStackException();
    +   }
    + 
    +-  public class EnumMap extends java.util.AbstractMap implements java.lang.Cloneable java.io.Serializable {
    ++  public class EnumMap<K extends java.lang.Enum<K>, V> extends java.util.AbstractMap implements java.lang.Cloneable java.io.Serializable {
    +     ctor public EnumMap(java.lang.Class<K>);
    +     ctor public EnumMap(java.util.EnumMap<K, ? extends V>);
    +     ctor public EnumMap(java.util.Map<K, ? extends V>);
    +@@ -58070,23 +58079,23 @@ package java.util {
    +     method public java.util.Set<java.util.Map.Entry<K, V>> entrySet();
    +   }
    + 
    +-  public abstract class EnumSet extends java.util.AbstractSet implements java.lang.Cloneable java.io.Serializable {
    +-    method public static java.util.EnumSet<E> allOf(java.lang.Class<E>);
    ++  public abstract class EnumSet<E extends java.lang.Enum<E>> extends java.util.AbstractSet implements java.lang.Cloneable java.io.Serializable {
    ++    method public static <E extends java.lang.Enum<E>> java.util.EnumSet<E> allOf(java.lang.Class<E>);
    +     method public java.util.EnumSet<E> clone();
    +-    method public static java.util.EnumSet<E> complementOf(java.util.EnumSet<E>);
    +-    method public static java.util.EnumSet<E> copyOf(java.util.EnumSet<E>);
    +-    method public static java.util.EnumSet<E> copyOf(java.util.Collection<E>);
    +-    method public static java.util.EnumSet<E> noneOf(java.lang.Class<E>);
    +-    method public static java.util.EnumSet<E> of(E);
    +-    method public static java.util.EnumSet<E> of(E, E);
    +-    method public static java.util.EnumSet<E> of(E, E, E);
    +-    method public static java.util.EnumSet<E> of(E, E, E, E);
    +-    method public static java.util.EnumSet<E> of(E, E, E, E, E);
    +-    method public static java.util.EnumSet<E> of(E, E...);
    +-    method public static java.util.EnumSet<E> range(E, E);
    +-  }
    +-
    +-  public abstract interface Enumeration {
    ++    method public static <E extends java.lang.Enum<E>> java.util.EnumSet<E> complementOf(java.util.EnumSet<E>);
    ++    method public static <E extends java.lang.Enum<E>> java.util.EnumSet<E> copyOf(java.util.EnumSet<E>);
    ++    method public static <E extends java.lang.Enum<E>> java.util.EnumSet<E> copyOf(java.util.Collection<E>);
    ++    method public static <E extends java.lang.Enum<E>> java.util.EnumSet<E> noneOf(java.lang.Class<E>);
    ++    method public static <E extends java.lang.Enum<E>> java.util.EnumSet<E> of(E);
    ++    method public static <E extends java.lang.Enum<E>> java.util.EnumSet<E> of(E, E);
    ++    method public static <E extends java.lang.Enum<E>> java.util.EnumSet<E> of(E, E, E);
    ++    method public static <E extends java.lang.Enum<E>> java.util.EnumSet<E> of(E, E, E, E);
    ++    method public static <E extends java.lang.Enum<E>> java.util.EnumSet<E> of(E, E, E, E, E);
    ++    method public static <E extends java.lang.Enum<E>> java.util.EnumSet<E> of(E, E...);
    ++    method public static <E extends java.lang.Enum<E>> java.util.EnumSet<E> range(E, E);
    ++  }
    ++
    ++  public abstract interface Enumeration<E> {
    +     method public abstract boolean hasMoreElements();
    +     method public abstract E nextElement();
    +   }
    +@@ -58094,7 +58103,7 @@ package java.util {
    +   public abstract interface EventListener {
    +   }
    + 
    +-  public abstract class EventListenerProxy implements java.util.EventListener {
    ++  public abstract class EventListenerProxy<T extends java.util.EventListener> implements java.util.EventListener {
    +     ctor public EventListenerProxy(T);
    +     method public T getListener();
    +   }
    +@@ -58180,7 +58189,7 @@ package java.util {
    +     field public static final int BC = 0; // 0x0
    +   }
    + 
    +-  public class HashMap extends java.util.AbstractMap implements java.lang.Cloneable java.util.Map java.io.Serializable {
    ++  public class HashMap<K, V> extends java.util.AbstractMap implements java.lang.Cloneable java.util.Map java.io.Serializable {
    +     ctor public HashMap(int, float);
    +     ctor public HashMap(int);
    +     ctor public HashMap();
    +@@ -58192,7 +58201,7 @@ package java.util {
    +     method public void replaceAll(java.util.function.BiFunction<? super K, ? super V, ? extends V>);
    +   }
    + 
    +-  public class HashSet extends java.util.AbstractSet implements java.lang.Cloneable java.io.Serializable java.util.Set {
    ++  public class HashSet<E> extends java.util.AbstractSet implements java.lang.Cloneable java.io.Serializable java.util.Set {
    +     ctor public HashSet();
    +     ctor public HashSet(java.util.Collection<? extends E>);
    +     ctor public HashSet(int, float);
    +@@ -58203,7 +58212,7 @@ package java.util {
    +     method public java.util.Spliterator<E> spliterator();
    +   }
    + 
    +-  public class Hashtable extends java.util.Dictionary implements java.lang.Cloneable java.util.Map java.io.Serializable {
    ++  public class Hashtable<K, V> extends java.util.Dictionary implements java.lang.Cloneable java.util.Map java.io.Serializable {
    +     ctor public Hashtable(int, float);
    +     ctor public Hashtable(int);
    +     ctor public Hashtable();
    +@@ -58238,7 +58247,7 @@ package java.util {
    +     method public java.util.Collection<V> values();
    +   }
    + 
    +-  public class IdentityHashMap extends java.util.AbstractMap implements java.lang.Cloneable java.util.Map java.io.Serializable {
    ++  public class IdentityHashMap<K, V> extends java.util.AbstractMap implements java.lang.Cloneable java.util.Map java.io.Serializable {
    +     ctor public IdentityHashMap();
    +     ctor public IdentityHashMap(int);
    +     ctor public IdentityHashMap(java.util.Map<? extends K, ? extends V>);
    +@@ -58305,14 +58314,14 @@ package java.util {
    +     ctor public InvalidPropertiesFormatException(java.lang.String);
    +   }
    + 
    +-  public abstract interface Iterator {
    ++  public abstract interface Iterator<E> {
    +     method public default void forEachRemaining(java.util.function.Consumer<? super E>);
    +     method public abstract boolean hasNext();
    +     method public abstract E next();
    +     method public default void remove();
    +   }
    + 
    +-  public class LinkedHashMap extends java.util.HashMap implements java.util.Map {
    ++  public class LinkedHashMap<K, V> extends java.util.HashMap implements java.util.Map {
    +     ctor public LinkedHashMap(int, float);
    +     ctor public LinkedHashMap(int);
    +     ctor public LinkedHashMap();
    +@@ -58321,14 +58330,14 @@ package java.util {
    +     method protected boolean removeEldestEntry(java.util.Map.Entry<K, V>);
    +   }
    + 
    +-  public class LinkedHashSet extends java.util.HashSet implements java.lang.Cloneable java.io.Serializable java.util.Set {
    ++  public class LinkedHashSet<E> extends java.util.HashSet implements java.lang.Cloneable java.io.Serializable java.util.Set {
    +     ctor public LinkedHashSet(int, float);
    +     ctor public LinkedHashSet(int);
    +     ctor public LinkedHashSet();
    +     ctor public LinkedHashSet(java.util.Collection<? extends E>);
    +   }
    + 
    +-  public class LinkedList extends java.util.AbstractSequentialList implements java.lang.Cloneable java.util.Deque java.util.List java.io.Serializable {
    ++  public class LinkedList<E> extends java.util.AbstractSequentialList implements java.lang.Cloneable java.util.Deque java.util.List java.io.Serializable {
    +     ctor public LinkedList();
    +     ctor public LinkedList(java.util.Collection<? extends E>);
    +     method public void addFirst(E);
    +@@ -58359,7 +58368,7 @@ package java.util {
    +     method public java.util.Spliterator<E> spliterator();
    +   }
    + 
    +-  public abstract interface List implements java.util.Collection {
    ++  public abstract interface List<E> implements java.util.Collection {
    +     method public abstract boolean add(E);
    +     method public abstract void add(int, E);
    +     method public abstract boolean addAll(java.util.Collection<? extends E>);
    +@@ -58386,10 +58395,10 @@ package java.util {
    +     method public default void sort(java.util.Comparator<? super E>);
    +     method public abstract java.util.List<E> subList(int, int);
    +     method public abstract java.lang.Object[] toArray();
    +-    method public abstract T[] toArray(T[]);
    ++    method public abstract <T> T[] toArray(T[]);
    +   }
    + 
    +-  public abstract interface ListIterator implements java.util.Iterator {
    ++  public abstract interface ListIterator<E> implements java.util.Iterator {
    +     method public abstract void add(E);
    +     method public abstract boolean hasNext();
    +     method public abstract boolean hasPrevious();
    +@@ -58506,7 +58515,7 @@ package java.util {
    +     method public final long getSum();
    +   }
    + 
    +-  public abstract interface Map {
    ++  public abstract interface Map<K, V> {
    +     method public abstract void clear();
    +     method public default V compute(K, java.util.function.BiFunction<? super K, ? super V, ? extends V>);
    +     method public default V computeIfAbsent(K, java.util.function.Function<? super K, ? extends V>);
    +@@ -58534,11 +58543,11 @@ package java.util {
    +     method public abstract java.util.Collection<V> values();
    +   }
    + 
    +-  public static abstract interface Map.Entry {
    +-    method public static java.util.Comparator<java.util.Map.Entry<K, V>> comparingByKey();
    +-    method public static java.util.Comparator<java.util.Map.Entry<K, V>> comparingByKey(java.util.Comparator<? super K>);
    +-    method public static java.util.Comparator<java.util.Map.Entry<K, V>> comparingByValue();
    +-    method public static java.util.Comparator<java.util.Map.Entry<K, V>> comparingByValue(java.util.Comparator<? super V>);
    ++  public static abstract interface Map.Entry<K, V> {
    ++    method public static <K extends java.lang.Comparable<? super K>, V> java.util.Comparator<java.util.Map.Entry<K, V>> comparingByKey();
    ++    method public static <K, V> java.util.Comparator<java.util.Map.Entry<K, V>> comparingByKey(java.util.Comparator<? super K>);
    ++    method public static <K, V extends java.lang.Comparable<? super V>> java.util.Comparator<java.util.Map.Entry<K, V>> comparingByValue();
    ++    method public static <K, V> java.util.Comparator<java.util.Map.Entry<K, V>> comparingByValue(java.util.Comparator<? super V>);
    +     method public abstract boolean equals(java.lang.Object);
    +     method public abstract K getKey();
    +     method public abstract V getValue();
    +@@ -58562,7 +58571,7 @@ package java.util {
    +     method public java.lang.String getKey();
    +   }
    + 
    +-  public abstract interface NavigableMap implements java.util.SortedMap {
    ++  public abstract interface NavigableMap<K, V> implements java.util.SortedMap {
    +     method public abstract java.util.Map.Entry<K, V> ceilingEntry(K);
    +     method public abstract K ceilingKey(K);
    +     method public abstract java.util.NavigableSet<K> descendingKeySet();
    +@@ -58586,7 +58595,7 @@ package java.util {
    +     method public abstract java.util.SortedMap<K, V> tailMap(K);
    +   }
    + 
    +-  public abstract interface NavigableSet implements java.util.SortedSet {
    ++  public abstract interface NavigableSet<E> implements java.util.SortedSet {
    +     method public abstract E ceiling(E);
    +     method public abstract java.util.Iterator<E> descendingIterator();
    +     method public abstract java.util.NavigableSet<E> descendingSet();
    +@@ -58610,16 +58619,16 @@ package java.util {
    +   }
    + 
    +   public final class Objects {
    +-    method public static int compare(T, T, java.util.Comparator<? super T>);
    ++    method public static <T> int compare(T, T, java.util.Comparator<? super T>);
    +     method public static boolean deepEquals(java.lang.Object, java.lang.Object);
    +     method public static boolean equals(java.lang.Object, java.lang.Object);
    +     method public static int hash(java.lang.Object...);
    +     method public static int hashCode(java.lang.Object);
    +     method public static boolean isNull(java.lang.Object);
    +     method public static boolean nonNull(java.lang.Object);
    +-    method public static T requireNonNull(T);
    +-    method public static T requireNonNull(T, java.lang.String);
    +-    method public static T requireNonNull(T, java.util.function.Supplier<java.lang.String>);
    ++    method public static <T> T requireNonNull(T);
    ++    method public static <T> T requireNonNull(T, java.lang.String);
    ++    method public static <T> T requireNonNull(T, java.util.function.Supplier<java.lang.String>);
    +     method public static java.lang.String toString(java.lang.Object);
    +     method public static java.lang.String toString(java.lang.Object, java.lang.String);
    +   }
    +@@ -58641,19 +58650,19 @@ package java.util {
    +     method public abstract void update(java.util.Observable, java.lang.Object);
    +   }
    + 
    +-  public final class Optional {
    +-    method public static java.util.Optional<T> empty();
    ++  public final class Optional<T> {
    ++    method public static <T> java.util.Optional<T> empty();
    +     method public java.util.Optional<T> filter(java.util.function.Predicate<? super T>);
    +-    method public java.util.Optional<U> flatMap(java.util.function.Function<? super T, java.util.Optional<U>>);
    ++    method public <U> java.util.Optional<U> flatMap(java.util.function.Function<? super T, java.util.Optional<U>>);
    +     method public T get();
    +     method public void ifPresent(java.util.function.Consumer<? super T>);
    +     method public boolean isPresent();
    +-    method public java.util.Optional<U> map(java.util.function.Function<? super T, ? extends U>);
    +-    method public static java.util.Optional<T> of(T);
    +-    method public static java.util.Optional<T> ofNullable(T);
    ++    method public <U> java.util.Optional<U> map(java.util.function.Function<? super T, ? extends U>);
    ++    method public static <T> java.util.Optional<T> of(T);
    ++    method public static <T> java.util.Optional<T> ofNullable(T);
    +     method public T orElse(T);
    +     method public T orElseGet(java.util.function.Supplier<? extends T>);
    +-    method public T orElseThrow(java.util.function.Supplier<? extends X>) throws java.lang.Throwable;
    ++    method public <X extends java.lang.Throwable> T orElseThrow(java.util.function.Supplier<? extends X>) throws java.lang.Throwable;
    +   }
    + 
    +   public final class OptionalDouble {
    +@@ -58664,7 +58673,7 @@ package java.util {
    +     method public static java.util.OptionalDouble of(double);
    +     method public double orElse(double);
    +     method public double orElseGet(java.util.function.DoubleSupplier);
    +-    method public double orElseThrow(java.util.function.Supplier<X>) throws java.lang.Throwable;
    ++    method public <X extends java.lang.Throwable> double orElseThrow(java.util.function.Supplier<X>) throws java.lang.Throwable;
    +   }
    + 
    +   public final class OptionalInt {
    +@@ -58675,7 +58684,7 @@ package java.util {
    +     method public static java.util.OptionalInt of(int);
    +     method public int orElse(int);
    +     method public int orElseGet(java.util.function.IntSupplier);
    +-    method public int orElseThrow(java.util.function.Supplier<X>) throws java.lang.Throwable;
    ++    method public <X extends java.lang.Throwable> int orElseThrow(java.util.function.Supplier<X>) throws java.lang.Throwable;
    +   }
    + 
    +   public final class OptionalLong {
    +@@ -58686,10 +58695,10 @@ package java.util {
    +     method public static java.util.OptionalLong of(long);
    +     method public long orElse(long);
    +     method public long orElseGet(java.util.function.LongSupplier);
    +-    method public long orElseThrow(java.util.function.Supplier<X>) throws java.lang.Throwable;
    ++    method public <X extends java.lang.Throwable> long orElseThrow(java.util.function.Supplier<X>) throws java.lang.Throwable;
    +   }
    + 
    +-  public abstract interface PrimitiveIterator implements java.util.Iterator {
    ++  public abstract interface PrimitiveIterator<T, T_CONS> implements java.util.Iterator {
    +     method public abstract void forEachRemaining(T_CONS);
    +   }
    + 
    +@@ -58714,7 +58723,7 @@ package java.util {
    +     method public abstract long nextLong();
    +   }
    + 
    +-  public class PriorityQueue extends java.util.AbstractQueue implements java.io.Serializable {
    ++  public class PriorityQueue<E> extends java.util.AbstractQueue implements java.io.Serializable {
    +     ctor public PriorityQueue();
    +     ctor public PriorityQueue(int);
    +     ctor public PriorityQueue(java.util.Comparator<? super E>);
    +@@ -58763,7 +58772,7 @@ package java.util {
    +     method public java.lang.Object handleGetObject(java.lang.String);
    +   }
    + 
    +-  public abstract interface Queue implements java.util.Collection {
    ++  public abstract interface Queue<E> implements java.util.Collection {
    +     method public abstract boolean add(E);
    +     method public abstract E element();
    +     method public abstract boolean offer(E);
    +@@ -58913,15 +58922,15 @@ package java.util {
    +     ctor public ServiceConfigurationError(java.lang.String, java.lang.Throwable);
    +   }
    + 
    +-  public final class ServiceLoader implements java.lang.Iterable {
    ++  public final class ServiceLoader<S> implements java.lang.Iterable {
    +     method public java.util.Iterator<S> iterator();
    +-    method public static java.util.ServiceLoader<S> load(java.lang.Class<S>, java.lang.ClassLoader);
    +-    method public static java.util.ServiceLoader<S> load(java.lang.Class<S>);
    +-    method public static java.util.ServiceLoader<S> loadInstalled(java.lang.Class<S>);
    ++    method public static <S> java.util.ServiceLoader<S> load(java.lang.Class<S>, java.lang.ClassLoader);
    ++    method public static <S> java.util.ServiceLoader<S> load(java.lang.Class<S>);
    ++    method public static <S> java.util.ServiceLoader<S> loadInstalled(java.lang.Class<S>);
    +     method public void reload();
    +   }
    + 
    +-  public abstract interface Set implements java.util.Collection {
    ++  public abstract interface Set<E> implements java.util.Collection {
    +     method public abstract boolean add(E);
    +     method public abstract boolean addAll(java.util.Collection<? extends E>);
    +     method public abstract void clear();
    +@@ -58936,7 +58945,7 @@ package java.util {
    +     method public abstract boolean retainAll(java.util.Collection<?>);
    +     method public abstract int size();
    +     method public abstract java.lang.Object[] toArray();
    +-    method public abstract T[] toArray(T[]);
    ++    method public abstract <T> T[] toArray(T[]);
    +   }
    + 
    +   public class SimpleTimeZone extends java.util.TimeZone {
    +@@ -58962,7 +58971,7 @@ package java.util {
    +     field public static final int WALL_TIME = 0; // 0x0
    +   }
    + 
    +-  public abstract interface SortedMap implements java.util.Map {
    ++  public abstract interface SortedMap<K, V> implements java.util.Map {
    +     method public abstract java.util.Comparator<? super K> comparator();
    +     method public abstract java.util.Set<java.util.Map.Entry<K, V>> entrySet();
    +     method public abstract K firstKey();
    +@@ -58974,7 +58983,7 @@ package java.util {
    +     method public abstract java.util.Collection<V> values();
    +   }
    + 
    +-  public abstract interface SortedSet implements java.util.Set {
    ++  public abstract interface SortedSet<E> implements java.util.Set {
    +     method public abstract java.util.Comparator<? super E> comparator();
    +     method public abstract E first();
    +     method public abstract java.util.SortedSet<E> headSet(E);
    +@@ -58983,7 +58992,7 @@ package java.util {
    +     method public abstract java.util.SortedSet<E> tailSet(E);
    +   }
    + 
    +-  public abstract interface Spliterator {
    ++  public abstract interface Spliterator<T> {
    +     method public abstract int characteristics();
    +     method public abstract long estimateSize();
    +     method public default void forEachRemaining(java.util.function.Consumer<? super T>);
    +@@ -59026,7 +59035,7 @@ package java.util {
    +     method public abstract java.util.Spliterator.OfLong trySplit();
    +   }
    + 
    +-  public static abstract interface Spliterator.OfPrimitive implements java.util.Spliterator {
    ++  public static abstract interface Spliterator.OfPrimitive<T, T_CONS, T_SPLITR extends java.util.Spliterator.OfPrimitive<T, T_CONS, T_SPLITR>> implements java.util.Spliterator {
    +     method public default void forEachRemaining(T_CONS);
    +     method public abstract boolean tryAdvance(T_CONS);
    +     method public abstract T_SPLITR trySplit();
    +@@ -59036,25 +59045,25 @@ package java.util {
    +     method public static java.util.Spliterator.OfDouble emptyDoubleSpliterator();
    +     method public static java.util.Spliterator.OfInt emptyIntSpliterator();
    +     method public static java.util.Spliterator.OfLong emptyLongSpliterator();
    +-    method public static java.util.Spliterator<T> emptySpliterator();
    +-    method public static java.util.Iterator<T> iterator(java.util.Spliterator<? extends T>);
    ++    method public static <T> java.util.Spliterator<T> emptySpliterator();
    ++    method public static <T> java.util.Iterator<T> iterator(java.util.Spliterator<? extends T>);
    +     method public static java.util.PrimitiveIterator.OfInt iterator(java.util.Spliterator.OfInt);
    +     method public static java.util.PrimitiveIterator.OfLong iterator(java.util.Spliterator.OfLong);
    +     method public static java.util.PrimitiveIterator.OfDouble iterator(java.util.Spliterator.OfDouble);
    +-    method public static java.util.Spliterator<T> spliterator(java.lang.Object[], int);
    +-    method public static java.util.Spliterator<T> spliterator(java.lang.Object[], int, int, int);
    ++    method public static <T> java.util.Spliterator<T> spliterator(java.lang.Object[], int);
    ++    method public static <T> java.util.Spliterator<T> spliterator(java.lang.Object[], int, int, int);
    +     method public static java.util.Spliterator.OfInt spliterator(int[], int);
    +     method public static java.util.Spliterator.OfInt spliterator(int[], int, int, int);
    +     method public static java.util.Spliterator.OfLong spliterator(long[], int);
    +     method public static java.util.Spliterator.OfLong spliterator(long[], int, int, int);
    +     method public static java.util.Spliterator.OfDouble spliterator(double[], int);
    +     method public static java.util.Spliterator.OfDouble spliterator(double[], int, int, int);
    +-    method public static java.util.Spliterator<T> spliterator(java.util.Collection<? extends T>, int);
    +-    method public static java.util.Spliterator<T> spliterator(java.util.Iterator<? extends T>, long, int);
    ++    method public static <T> java.util.Spliterator<T> spliterator(java.util.Collection<? extends T>, int);
    ++    method public static <T> java.util.Spliterator<T> spliterator(java.util.Iterator<? extends T>, long, int);
    +     method public static java.util.Spliterator.OfInt spliterator(java.util.PrimitiveIterator.OfInt, long, int);
    +     method public static java.util.Spliterator.OfLong spliterator(java.util.PrimitiveIterator.OfLong, long, int);
    +     method public static java.util.Spliterator.OfDouble spliterator(java.util.PrimitiveIterator.OfDouble, long, int);
    +-    method public static java.util.Spliterator<T> spliteratorUnknownSize(java.util.Iterator<? extends T>, int);
    ++    method public static <T> java.util.Spliterator<T> spliteratorUnknownSize(java.util.Iterator<? extends T>, int);
    +     method public static java.util.Spliterator.OfInt spliteratorUnknownSize(java.util.PrimitiveIterator.OfInt, int);
    +     method public static java.util.Spliterator.OfLong spliteratorUnknownSize(java.util.PrimitiveIterator.OfLong, int);
    +     method public static java.util.Spliterator.OfDouble spliteratorUnknownSize(java.util.PrimitiveIterator.OfDouble, int);
    +@@ -59081,7 +59090,7 @@ package java.util {
    +     method public java.util.Spliterator.OfLong trySplit();
    +   }
    + 
    +-  public static abstract class Spliterators.AbstractSpliterator implements java.util.Spliterator {
    ++  public static abstract class Spliterators.AbstractSpliterator<T> implements java.util.Spliterator {
    +     ctor protected Spliterators.AbstractSpliterator(long, int);
    +     method public int characteristics();
    +     method public long estimateSize();
    +@@ -59116,7 +59125,7 @@ package java.util {
    +     method public java.util.SplittableRandom split();
    +   }
    + 
    +-  public class Stack extends java.util.Vector {
    ++  public class Stack<E> extends java.util.Vector {
    +     ctor public Stack();
    +     method public boolean empty();
    +     method public synchronized E peek();
    +@@ -59200,7 +59209,7 @@ package java.util {
    +     ctor public TooManyListenersException(java.lang.String);
    +   }
    + 
    +-  public class TreeMap extends java.util.AbstractMap implements java.lang.Cloneable java.util.NavigableMap java.io.Serializable {
    ++  public class TreeMap<K, V> extends java.util.AbstractMap implements java.lang.Cloneable java.util.NavigableMap java.io.Serializable {
    +     ctor public TreeMap();
    +     ctor public TreeMap(java.util.Comparator<? super K>);
    +     ctor public TreeMap(java.util.Map<? extends K, ? extends V>);
    +@@ -59237,7 +59246,7 @@ package java.util {
    +     method public java.util.SortedMap<K, V> tailMap(K);
    +   }
    + 
    +-  public class TreeSet extends java.util.AbstractSet implements java.lang.Cloneable java.util.NavigableSet java.io.Serializable {
    ++  public class TreeSet<E> extends java.util.AbstractSet implements java.lang.Cloneable java.util.NavigableSet java.io.Serializable {
    +     ctor public TreeSet();
    +     ctor public TreeSet(java.util.Comparator<? super E>);
    +     ctor public TreeSet(java.util.Collection<? extends E>);
    +@@ -59290,7 +59299,7 @@ package java.util {
    +     method public java.lang.String getFlags();
    +   }
    + 
    +-  public class Vector extends java.util.AbstractList implements java.lang.Cloneable java.util.List java.util.RandomAccess java.io.Serializable {
    ++  public class Vector<E> extends java.util.AbstractList implements java.lang.Cloneable java.util.List java.util.RandomAccess java.io.Serializable {
    +     ctor public Vector(int, int);
    +     ctor public Vector(int);
    +     ctor public Vector();
    +@@ -59325,7 +59334,7 @@ package java.util {
    +     field protected java.lang.Object[] elementData;
    +   }
    + 
    +-  public class WeakHashMap extends java.util.AbstractMap implements java.util.Map {
    ++  public class WeakHashMap<K, V> extends java.util.AbstractMap implements java.util.Map {
    +     ctor public WeakHashMap(int, float);
    +     ctor public WeakHashMap(int);
    +     ctor public WeakHashMap();
    +@@ -59341,18 +59350,18 @@ package java.util.concurrent {
    + 
    +   public abstract class AbstractExecutorService implements java.util.concurrent.ExecutorService {
    +     ctor public AbstractExecutorService();
    +-    method public java.util.List<java.util.concurrent.Future<T>> invokeAll(java.util.Collection<? extends java.util.concurrent.Callable<T>>) throws java.lang.InterruptedException;
    +-    method public java.util.List<java.util.concurrent.Future<T>> invokeAll(java.util.Collection<? extends java.util.concurrent.Callable<T>>, long, java.util.concurrent.TimeUnit) throws java.lang.InterruptedException;
    +-    method public T invokeAny(java.util.Collection<? extends java.util.concurrent.Callable<T>>) throws java.util.concurrent.ExecutionException, java.lang.InterruptedException;
    +-    method public T invokeAny(java.util.Collection<? extends java.util.concurrent.Callable<T>>, long, java.util.concurrent.TimeUnit) throws java.util.concurrent.ExecutionException, java.lang.InterruptedException, java.util.concurrent.TimeoutException;
    +-    method protected java.util.concurrent.RunnableFuture<T> newTaskFor(java.lang.Runnable, T);
    +-    method protected java.util.concurrent.RunnableFuture<T> newTaskFor(java.util.concurrent.Callable<T>);
    ++    method public <T> java.util.List<java.util.concurrent.Future<T>> invokeAll(java.util.Collection<? extends java.util.concurrent.Callable<T>>) throws java.lang.InterruptedException;
    ++    method public <T> java.util.List<java.util.concurrent.Future<T>> invokeAll(java.util.Collection<? extends java.util.concurrent.Callable<T>>, long, java.util.concurrent.TimeUnit) throws java.lang.InterruptedException;
    ++    method public <T> T invokeAny(java.util.Collection<? extends java.util.concurrent.Callable<T>>) throws java.util.concurrent.ExecutionException, java.lang.InterruptedException;
    ++    method public <T> T invokeAny(java.util.Collection<? extends java.util.concurrent.Callable<T>>, long, java.util.concurrent.TimeUnit) throws java.util.concurrent.ExecutionException, java.lang.InterruptedException, java.util.concurrent.TimeoutException;
    ++    method protected <T> java.util.concurrent.RunnableFuture<T> newTaskFor(java.lang.Runnable, T);
    ++    method protected <T> java.util.concurrent.RunnableFuture<T> newTaskFor(java.util.concurrent.Callable<T>);
    +     method public java.util.concurrent.Future<?> submit(java.lang.Runnable);
    +-    method public java.util.concurrent.Future<T> submit(java.lang.Runnable, T);
    +-    method public java.util.concurrent.Future<T> submit(java.util.concurrent.Callable<T>);
    ++    method public <T> java.util.concurrent.Future<T> submit(java.lang.Runnable, T);
    ++    method public <T> java.util.concurrent.Future<T> submit(java.util.concurrent.Callable<T>);
    +   }
    + 
    +-  public class ArrayBlockingQueue extends java.util.AbstractQueue implements java.util.concurrent.BlockingQueue java.io.Serializable {
    ++  public class ArrayBlockingQueue<E> extends java.util.AbstractQueue implements java.util.concurrent.BlockingQueue java.io.Serializable {
    +     ctor public ArrayBlockingQueue(int);
    +     ctor public ArrayBlockingQueue(int, boolean);
    +     ctor public ArrayBlockingQueue(int, boolean, java.util.Collection<? extends E>);
    +@@ -59371,7 +59380,7 @@ package java.util.concurrent {
    +     method public E take() throws java.lang.InterruptedException;
    +   }
    + 
    +-  public abstract interface BlockingDeque implements java.util.concurrent.BlockingQueue java.util.Deque {
    ++  public abstract interface BlockingDeque<E> implements java.util.concurrent.BlockingQueue java.util.Deque {
    +     method public abstract boolean add(E);
    +     method public abstract void addFirst(E);
    +     method public abstract void addLast(E);
    +@@ -59403,7 +59412,7 @@ package java.util.concurrent {
    +     method public abstract E takeLast() throws java.lang.InterruptedException;
    +   }
    + 
    +-  public abstract interface BlockingQueue implements java.util.Queue {
    ++  public abstract interface BlockingQueue<E> implements java.util.Queue {
    +     method public abstract boolean add(E);
    +     method public abstract boolean contains(java.lang.Object);
    +     method public abstract int drainTo(java.util.Collection<? super E>);
    +@@ -59422,7 +59431,7 @@ package java.util.concurrent {
    +     ctor public BrokenBarrierException(java.lang.String);
    +   }
    + 
    +-  public abstract interface Callable {
    ++  public abstract interface Callable<V> {
    +     method public abstract V call() throws java.lang.Exception;
    +   }
    + 
    +@@ -59431,28 +59440,28 @@ package java.util.concurrent {
    +     ctor public CancellationException(java.lang.String);
    +   }
    + 
    +-  public class CompletableFuture implements java.util.concurrent.CompletionStage java.util.concurrent.Future {
    ++  public class CompletableFuture<T> implements java.util.concurrent.CompletionStage java.util.concurrent.Future {
    +     ctor public CompletableFuture();
    +     method public java.util.concurrent.CompletableFuture<java.lang.Void> acceptEither(java.util.concurrent.CompletionStage<? extends T>, java.util.function.Consumer<? super T>);
    +     method public java.util.concurrent.CompletableFuture<java.lang.Void> acceptEitherAsync(java.util.concurrent.CompletionStage<? extends T>, java.util.function.Consumer<? super T>);
    +     method public java.util.concurrent.CompletableFuture<java.lang.Void> acceptEitherAsync(java.util.concurrent.CompletionStage<? extends T>, java.util.function.Consumer<? super T>, java.util.concurrent.Executor);
    +     method public static java.util.concurrent.CompletableFuture<java.lang.Void> allOf(java.util.concurrent.CompletableFuture<?>...);
    +     method public static java.util.concurrent.CompletableFuture<java.lang.Object> anyOf(java.util.concurrent.CompletableFuture<?>...);
    +-    method public java.util.concurrent.CompletableFuture<U> applyToEither(java.util.concurrent.CompletionStage<? extends T>, java.util.function.Function<? super T, U>);
    +-    method public java.util.concurrent.CompletableFuture<U> applyToEitherAsync(java.util.concurrent.CompletionStage<? extends T>, java.util.function.Function<? super T, U>);
    +-    method public java.util.concurrent.CompletableFuture<U> applyToEitherAsync(java.util.concurrent.CompletionStage<? extends T>, java.util.function.Function<? super T, U>, java.util.concurrent.Executor);
    ++    method public <U> java.util.concurrent.CompletableFuture<U> applyToEither(java.util.concurrent.CompletionStage<? extends T>, java.util.function.Function<? super T, U>);
    ++    method public <U> java.util.concurrent.CompletableFuture<U> applyToEitherAsync(java.util.concurrent.CompletionStage<? extends T>, java.util.function.Function<? super T, U>);
    ++    method public <U> java.util.concurrent.CompletableFuture<U> applyToEitherAsync(java.util.concurrent.CompletionStage<? extends T>, java.util.function.Function<? super T, U>, java.util.concurrent.Executor);
    +     method public boolean cancel(boolean);
    +     method public boolean complete(T);
    +     method public boolean completeExceptionally(java.lang.Throwable);
    +-    method public static java.util.concurrent.CompletableFuture<U> completedFuture(U);
    ++    method public static <U> java.util.concurrent.CompletableFuture<U> completedFuture(U);
    +     method public java.util.concurrent.CompletableFuture<T> exceptionally(java.util.function.Function<java.lang.Throwable, ? extends T>);
    +     method public T get() throws java.util.concurrent.ExecutionException, java.lang.InterruptedException;
    +     method public T get(long, java.util.concurrent.TimeUnit) throws java.util.concurrent.ExecutionException, java.lang.InterruptedException, java.util.concurrent.TimeoutException;
    +     method public T getNow(T);
    +     method public int getNumberOfDependents();
    +-    method public java.util.concurrent.CompletableFuture<U> handle(java.util.function.BiFunction<? super T, java.lang.Throwable, ? extends U>);
    +-    method public java.util.concurrent.CompletableFuture<U> handleAsync(java.util.function.BiFunction<? super T, java.lang.Throwable, ? extends U>);
    +-    method public java.util.concurrent.CompletableFuture<U> handleAsync(java.util.function.BiFunction<? super T, java.lang.Throwable, ? extends U>, java.util.concurrent.Executor);
    ++    method public <U> java.util.concurrent.CompletableFuture<U> handle(java.util.function.BiFunction<? super T, java.lang.Throwable, ? extends U>);
    ++    method public <U> java.util.concurrent.CompletableFuture<U> handleAsync(java.util.function.BiFunction<? super T, java.lang.Throwable, ? extends U>);
    ++    method public <U> java.util.concurrent.CompletableFuture<U> handleAsync(java.util.function.BiFunction<? super T, java.lang.Throwable, ? extends U>, java.util.concurrent.Executor);
    +     method public boolean isCancelled();
    +     method public boolean isCompletedExceptionally();
    +     method public boolean isDone();
    +@@ -59467,23 +59476,23 @@ package java.util.concurrent {
    +     method public java.util.concurrent.CompletableFuture<java.lang.Void> runAfterEitherAsync(java.util.concurrent.CompletionStage<?>, java.lang.Runnable, java.util.concurrent.Executor);
    +     method public static java.util.concurrent.CompletableFuture<java.lang.Void> runAsync(java.lang.Runnable);
    +     method public static java.util.concurrent.CompletableFuture<java.lang.Void> runAsync(java.lang.Runnable, java.util.concurrent.Executor);
    +-    method public static java.util.concurrent.CompletableFuture<U> supplyAsync(java.util.function.Supplier<U>);
    +-    method public static java.util.concurrent.CompletableFuture<U> supplyAsync(java.util.function.Supplier<U>, java.util.concurrent.Executor);
    ++    method public static <U> java.util.concurrent.CompletableFuture<U> supplyAsync(java.util.function.Supplier<U>);
    ++    method public static <U> java.util.concurrent.CompletableFuture<U> supplyAsync(java.util.function.Supplier<U>, java.util.concurrent.Executor);
    +     method public java.util.concurrent.CompletableFuture<java.lang.Void> thenAccept(java.util.function.Consumer<? super T>);
    +     method public java.util.concurrent.CompletableFuture<java.lang.Void> thenAcceptAsync(java.util.function.Consumer<? super T>);
    +     method public java.util.concurrent.CompletableFuture<java.lang.Void> thenAcceptAsync(java.util.function.Consumer<? super T>, java.util.concurrent.Executor);
    +-    method public java.util.concurrent.CompletableFuture<java.lang.Void> thenAcceptBoth(java.util.concurrent.CompletionStage<? extends U>, java.util.function.BiConsumer<? super T, ? super U>);
    +-    method public java.util.concurrent.CompletableFuture<java.lang.Void> thenAcceptBothAsync(java.util.concurrent.CompletionStage<? extends U>, java.util.function.BiConsumer<? super T, ? super U>);
    +-    method public java.util.concurrent.CompletableFuture<java.lang.Void> thenAcceptBothAsync(java.util.concurrent.CompletionStage<? extends U>, java.util.function.BiConsumer<? super T, ? super U>, java.util.concurrent.Executor);
    +-    method public java.util.concurrent.CompletableFuture<U> thenApply(java.util.function.Function<? super T, ? extends U>);
    +-    method public java.util.concurrent.CompletableFuture<U> thenApplyAsync(java.util.function.Function<? super T, ? extends U>);
    +-    method public java.util.concurrent.CompletableFuture<U> thenApplyAsync(java.util.function.Function<? super T, ? extends U>, java.util.concurrent.Executor);
    +-    method public java.util.concurrent.CompletableFuture<V> thenCombine(java.util.concurrent.CompletionStage<? extends U>, java.util.function.BiFunction<? super T, ? super U, ? extends V>);
    +-    method public java.util.concurrent.CompletableFuture<V> thenCombineAsync(java.util.concurrent.CompletionStage<? extends U>, java.util.function.BiFunction<? super T, ? super U, ? extends V>);
    +-    method public java.util.concurrent.CompletableFuture<V> thenCombineAsync(java.util.concurrent.CompletionStage<? extends U>, java.util.function.BiFunction<? super T, ? super U, ? extends V>, java.util.concurrent.Executor);
    +-    method public java.util.concurrent.CompletableFuture<U> thenCompose(java.util.function.Function<? super T, ? extends java.util.concurrent.CompletionStage<U>>);
    +-    method public java.util.concurrent.CompletableFuture<U> thenComposeAsync(java.util.function.Function<? super T, ? extends java.util.concurrent.CompletionStage<U>>);
    +-    method public java.util.concurrent.CompletableFuture<U> thenComposeAsync(java.util.function.Function<? super T, ? extends java.util.concurrent.CompletionStage<U>>, java.util.concurrent.Executor);
    ++    method public <U> java.util.concurrent.CompletableFuture<java.lang.Void> thenAcceptBoth(java.util.concurrent.CompletionStage<? extends U>, java.util.function.BiConsumer<? super T, ? super U>);
    ++    method public <U> java.util.concurrent.CompletableFuture<java.lang.Void> thenAcceptBothAsync(java.util.concurrent.CompletionStage<? extends U>, java.util.function.BiConsumer<? super T, ? super U>);
    ++    method public <U> java.util.concurrent.CompletableFuture<java.lang.Void> thenAcceptBothAsync(java.util.concurrent.CompletionStage<? extends U>, java.util.function.BiConsumer<? super T, ? super U>, java.util.concurrent.Executor);
    ++    method public <U> java.util.concurrent.CompletableFuture<U> thenApply(java.util.function.Function<? super T, ? extends U>);
    ++    method public <U> java.util.concurrent.CompletableFuture<U> thenApplyAsync(java.util.function.Function<? super T, ? extends U>);
    ++    method public <U> java.util.concurrent.CompletableFuture<U> thenApplyAsync(java.util.function.Function<? super T, ? extends U>, java.util.concurrent.Executor);
    ++    method public <U, V> java.util.concurrent.CompletableFuture<V> thenCombine(java.util.concurrent.CompletionStage<? extends U>, java.util.function.BiFunction<? super T, ? super U, ? extends V>);
    ++    method public <U, V> java.util.concurrent.CompletableFuture<V> thenCombineAsync(java.util.concurrent.CompletionStage<? extends U>, java.util.function.BiFunction<? super T, ? super U, ? extends V>);
    ++    method public <U, V> java.util.concurrent.CompletableFuture<V> thenCombineAsync(java.util.concurrent.CompletionStage<? extends U>, java.util.function.BiFunction<? super T, ? super U, ? extends V>, java.util.concurrent.Executor);
    ++    method public <U> java.util.concurrent.CompletableFuture<U> thenCompose(java.util.function.Function<? super T, ? extends java.util.concurrent.CompletionStage<U>>);
    ++    method public <U> java.util.concurrent.CompletableFuture<U> thenComposeAsync(java.util.function.Function<? super T, ? extends java.util.concurrent.CompletionStage<U>>);
    ++    method public <U> java.util.concurrent.CompletableFuture<U> thenComposeAsync(java.util.function.Function<? super T, ? extends java.util.concurrent.CompletionStage<U>>, java.util.concurrent.Executor);
    +     method public java.util.concurrent.CompletableFuture<java.lang.Void> thenRun(java.lang.Runnable);
    +     method public java.util.concurrent.CompletableFuture<java.lang.Void> thenRunAsync(java.lang.Runnable);
    +     method public java.util.concurrent.CompletableFuture<java.lang.Void> thenRunAsync(java.lang.Runnable, java.util.concurrent.Executor);
    +@@ -59503,7 +59512,7 @@ package java.util.concurrent {
    +     ctor public CompletionException(java.lang.Throwable);
    +   }
    + 
    +-  public abstract interface CompletionService {
    ++  public abstract interface CompletionService<V> {
    +     method public abstract java.util.concurrent.Future<V> poll();
    +     method public abstract java.util.concurrent.Future<V> poll(long, java.util.concurrent.TimeUnit) throws java.lang.InterruptedException;
    +     method public abstract java.util.concurrent.Future<V> submit(java.util.concurrent.Callable<V>);
    +@@ -59511,17 +59520,17 @@ package java.util.concurrent {
    +     method public abstract java.util.concurrent.Future<V> take() throws java.lang.InterruptedException;
    +   }
    + 
    +-  public abstract interface CompletionStage {
    ++  public abstract interface CompletionStage<T> {
    +     method public abstract java.util.concurrent.CompletionStage<java.lang.Void> acceptEither(java.util.concurrent.CompletionStage<? extends T>, java.util.function.Consumer<? super T>);
    +     method public abstract java.util.concurrent.CompletionStage<java.lang.Void> acceptEitherAsync(java.util.concurrent.CompletionStage<? extends T>, java.util.function.Consumer<? super T>);
    +     method public abstract java.util.concurrent.CompletionStage<java.lang.Void> acceptEitherAsync(java.util.concurrent.CompletionStage<? extends T>, java.util.function.Consumer<? super T>, java.util.concurrent.Executor);
    +-    method public abstract java.util.concurrent.CompletionStage<U> applyToEither(java.util.concurrent.CompletionStage<? extends T>, java.util.function.Function<? super T, U>);
    +-    method public abstract java.util.concurrent.CompletionStage<U> applyToEitherAsync(java.util.concurrent.CompletionStage<? extends T>, java.util.function.Function<? super T, U>);
    +-    method public abstract java.util.concurrent.CompletionStage<U> applyToEitherAsync(java.util.concurrent.CompletionStage<? extends T>, java.util.function.Function<? super T, U>, java.util.concurrent.Executor);
    ++    method public abstract <U> java.util.concurrent.CompletionStage<U> applyToEither(java.util.concurrent.CompletionStage<? extends T>, java.util.function.Function<? super T, U>);
    ++    method public abstract <U> java.util.concurrent.CompletionStage<U> applyToEitherAsync(java.util.concurrent.CompletionStage<? extends T>, java.util.function.Function<? super T, U>);
    ++    method public abstract <U> java.util.concurrent.CompletionStage<U> applyToEitherAsync(java.util.concurrent.CompletionStage<? extends T>, java.util.function.Function<? super T, U>, java.util.concurrent.Executor);
    +     method public abstract java.util.concurrent.CompletionStage<T> exceptionally(java.util.function.Function<java.lang.Throwable, ? extends T>);
    +-    method public abstract java.util.concurrent.CompletionStage<U> handle(java.util.function.BiFunction<? super T, java.lang.Throwable, ? extends U>);
    +-    method public abstract java.util.concurrent.CompletionStage<U> handleAsync(java.util.function.BiFunction<? super T, java.lang.Throwable, ? extends U>);
    +-    method public abstract java.util.concurrent.CompletionStage<U> handleAsync(java.util.function.BiFunction<? super T, java.lang.Throwable, ? extends U>, java.util.concurrent.Executor);
    ++    method public abstract <U> java.util.concurrent.CompletionStage<U> handle(java.util.function.BiFunction<? super T, java.lang.Throwable, ? extends U>);
    ++    method public abstract <U> java.util.concurrent.CompletionStage<U> handleAsync(java.util.function.BiFunction<? super T, java.lang.Throwable, ? extends U>);
    ++    method public abstract <U> java.util.concurrent.CompletionStage<U> handleAsync(java.util.function.BiFunction<? super T, java.lang.Throwable, ? extends U>, java.util.concurrent.Executor);
    +     method public abstract java.util.concurrent.CompletionStage<java.lang.Void> runAfterBoth(java.util.concurrent.CompletionStage<?>, java.lang.Runnable);
    +     method public abstract java.util.concurrent.CompletionStage<java.lang.Void> runAfterBothAsync(java.util.concurrent.CompletionStage<?>, java.lang.Runnable);
    +     method public abstract java.util.concurrent.CompletionStage<java.lang.Void> runAfterBothAsync(java.util.concurrent.CompletionStage<?>, java.lang.Runnable, java.util.concurrent.Executor);
    +@@ -59531,18 +59540,18 @@ package java.util.concurrent {
    +     method public abstract java.util.concurrent.CompletionStage<java.lang.Void> thenAccept(java.util.function.Consumer<? super T>);
    +     method public abstract java.util.concurrent.CompletionStage<java.lang.Void> thenAcceptAsync(java.util.function.Consumer<? super T>);
    +     method public abstract java.util.concurrent.CompletionStage<java.lang.Void> thenAcceptAsync(java.util.function.Consumer<? super T>, java.util.concurrent.Executor);
    +-    method public abstract java.util.concurrent.CompletionStage<java.lang.Void> thenAcceptBoth(java.util.concurrent.CompletionStage<? extends U>, java.util.function.BiConsumer<? super T, ? super U>);
    +-    method public abstract java.util.concurrent.CompletionStage<java.lang.Void> thenAcceptBothAsync(java.util.concurrent.CompletionStage<? extends U>, java.util.function.BiConsumer<? super T, ? super U>);
    +-    method public abstract java.util.concurrent.CompletionStage<java.lang.Void> thenAcceptBothAsync(java.util.concurrent.CompletionStage<? extends U>, java.util.function.BiConsumer<? super T, ? super U>, java.util.concurrent.Executor);
    +-    method public abstract java.util.concurrent.CompletionStage<U> thenApply(java.util.function.Function<? super T, ? extends U>);
    +-    method public abstract java.util.concurrent.CompletionStage<U> thenApplyAsync(java.util.function.Function<? super T, ? extends U>);
    +-    method public abstract java.util.concurrent.CompletionStage<U> thenApplyAsync(java.util.function.Function<? super T, ? extends U>, java.util.concurrent.Executor);
    +-    method public abstract java.util.concurrent.CompletionStage<V> thenCombine(java.util.concurrent.CompletionStage<? extends U>, java.util.function.BiFunction<? super T, ? super U, ? extends V>);
    +-    method public abstract java.util.concurrent.CompletionStage<V> thenCombineAsync(java.util.concurrent.CompletionStage<? extends U>, java.util.function.BiFunction<? super T, ? super U, ? extends V>);
    +-    method public abstract java.util.concurrent.CompletionStage<V> thenCombineAsync(java.util.concurrent.CompletionStage<? extends U>, java.util.function.BiFunction<? super T, ? super U, ? extends V>, java.util.concurrent.Executor);
    +-    method public abstract java.util.concurrent.CompletionStage<U> thenCompose(java.util.function.Function<? super T, ? extends java.util.concurrent.CompletionStage<U>>);
    +-    method public abstract java.util.concurrent.CompletionStage<U> thenComposeAsync(java.util.function.Function<? super T, ? extends java.util.concurrent.CompletionStage<U>>);
    +-    method public abstract java.util.concurrent.CompletionStage<U> thenComposeAsync(java.util.function.Function<? super T, ? extends java.util.concurrent.CompletionStage<U>>, java.util.concurrent.Executor);
    ++    method public abstract <U> java.util.concurrent.CompletionStage<java.lang.Void> thenAcceptBoth(java.util.concurrent.CompletionStage<? extends U>, java.util.function.BiConsumer<? super T, ? super U>);
    ++    method public abstract <U> java.util.concurrent.CompletionStage<java.lang.Void> thenAcceptBothAsync(java.util.concurrent.CompletionStage<? extends U>, java.util.function.BiConsumer<? super T, ? super U>);
    ++    method public abstract <U> java.util.concurrent.CompletionStage<java.lang.Void> thenAcceptBothAsync(java.util.concurrent.CompletionStage<? extends U>, java.util.function.BiConsumer<? super T, ? super U>, java.util.concurrent.Executor);
    ++    method public abstract <U> java.util.concurrent.CompletionStage<U> thenApply(java.util.function.Function<? super T, ? extends U>);
    ++    method public abstract <U> java.util.concurrent.CompletionStage<U> thenApplyAsync(java.util.function.Function<? super T, ? extends U>);
    ++    method public abstract <U> java.util.concurrent.CompletionStage<U> thenApplyAsync(java.util.function.Function<? super T, ? extends U>, java.util.concurrent.Executor);
    ++    method public abstract <U, V> java.util.concurrent.CompletionStage<V> thenCombine(java.util.concurrent.CompletionStage<? extends U>, java.util.function.BiFunction<? super T, ? super U, ? extends V>);
    ++    method public abstract <U, V> java.util.concurrent.CompletionStage<V> thenCombineAsync(java.util.concurrent.CompletionStage<? extends U>, java.util.function.BiFunction<? super T, ? super U, ? extends V>);
    ++    method public abstract <U, V> java.util.concurrent.CompletionStage<V> thenCombineAsync(java.util.concurrent.CompletionStage<? extends U>, java.util.function.BiFunction<? super T, ? super U, ? extends V>, java.util.concurrent.Executor);
    ++    method public abstract <U> java.util.concurrent.CompletionStage<U> thenCompose(java.util.function.Function<? super T, ? extends java.util.concurrent.CompletionStage<U>>);
    ++    method public abstract <U> java.util.concurrent.CompletionStage<U> thenComposeAsync(java.util.function.Function<? super T, ? extends java.util.concurrent.CompletionStage<U>>);
    ++    method public abstract <U> java.util.concurrent.CompletionStage<U> thenComposeAsync(java.util.function.Function<? super T, ? extends java.util.concurrent.CompletionStage<U>>, java.util.concurrent.Executor);
    +     method public abstract java.util.concurrent.CompletionStage<java.lang.Void> thenRun(java.lang.Runnable);
    +     method public abstract java.util.concurrent.CompletionStage<java.lang.Void> thenRunAsync(java.lang.Runnable);
    +     method public abstract java.util.concurrent.CompletionStage<java.lang.Void> thenRunAsync(java.lang.Runnable, java.util.concurrent.Executor);
    +@@ -59552,7 +59561,7 @@ package java.util.concurrent {
    +     method public abstract java.util.concurrent.CompletionStage<T> whenCompleteAsync(java.util.function.BiConsumer<? super T, ? super java.lang.Throwable>, java.util.concurrent.Executor);
    +   }
    + 
    +-  public class ConcurrentHashMap extends java.util.AbstractMap implements java.util.concurrent.ConcurrentMap java.io.Serializable {
    ++  public class ConcurrentHashMap<K, V> extends java.util.AbstractMap implements java.util.concurrent.ConcurrentMap java.io.Serializable {
    +     ctor public ConcurrentHashMap();
    +     ctor public ConcurrentHashMap(int);
    +     ctor public ConcurrentHashMap(java.util.Map<? extends K, ? extends V>);
    +@@ -59566,29 +59575,29 @@ package java.util.concurrent {
    +     method public java.util.Set<java.util.Map.Entry<K, V>> entrySet();
    +     method public void forEach(java.util.function.BiConsumer<? super K, ? super V>);
    +     method public void forEach(long, java.util.function.BiConsumer<? super K, ? super V>);
    +-    method public void forEach(long, java.util.function.BiFunction<? super K, ? super V, ? extends U>, java.util.function.Consumer<? super U>);
    ++    method public <U> void forEach(long, java.util.function.BiFunction<? super K, ? super V, ? extends U>, java.util.function.Consumer<? super U>);
    +     method public void forEachEntry(long, java.util.function.Consumer<? super java.util.Map.Entry<K, V>>);
    +-    method public void forEachEntry(long, java.util.function.Function<java.util.Map.Entry<K, V>, ? extends U>, java.util.function.Consumer<? super U>);
    ++    method public <U> void forEachEntry(long, java.util.function.Function<java.util.Map.Entry<K, V>, ? extends U>, java.util.function.Consumer<? super U>);
    +     method public void forEachKey(long, java.util.function.Consumer<? super K>);
    +-    method public void forEachKey(long, java.util.function.Function<? super K, ? extends U>, java.util.function.Consumer<? super U>);
    ++    method public <U> void forEachKey(long, java.util.function.Function<? super K, ? extends U>, java.util.function.Consumer<? super U>);
    +     method public void forEachValue(long, java.util.function.Consumer<? super V>);
    +-    method public void forEachValue(long, java.util.function.Function<? super V, ? extends U>, java.util.function.Consumer<? super U>);
    ++    method public <U> void forEachValue(long, java.util.function.Function<? super V, ? extends U>, java.util.function.Consumer<? super U>);
    +     method public V getOrDefault(java.lang.Object, V);
    +     method public java.util.concurrent.ConcurrentHashMap.KeySetView<K, V> keySet(V);
    +     method public java.util.Enumeration<K> keys();
    +     method public long mappingCount();
    +     method public V merge(K, V, java.util.function.BiFunction<? super V, ? super V, ? extends V>);
    +-    method public static java.util.concurrent.ConcurrentHashMap.KeySetView<K, java.lang.Boolean> newKeySet();
    +-    method public static java.util.concurrent.ConcurrentHashMap.KeySetView<K, java.lang.Boolean> newKeySet(int);
    ++    method public static <K> java.util.concurrent.ConcurrentHashMap.KeySetView<K, java.lang.Boolean> newKeySet();
    ++    method public static <K> java.util.concurrent.ConcurrentHashMap.KeySetView<K, java.lang.Boolean> newKeySet(int);
    +     method public V putIfAbsent(K, V);
    +-    method public U reduce(long, java.util.function.BiFunction<? super K, ? super V, ? extends U>, java.util.function.BiFunction<? super U, ? super U, ? extends U>);
    ++    method public <U> U reduce(long, java.util.function.BiFunction<? super K, ? super V, ? extends U>, java.util.function.BiFunction<? super U, ? super U, ? extends U>);
    +     method public java.util.Map.Entry<K, V> reduceEntries(long, java.util.function.BiFunction<java.util.Map.Entry<K, V>, java.util.Map.Entry<K, V>, ? extends java.util.Map.Entry<K, V>>);
    +-    method public U reduceEntries(long, java.util.function.Function<java.util.Map.Entry<K, V>, ? extends U>, java.util.function.BiFunction<? super U, ? super U, ? extends U>);
    ++    method public <U> U reduceEntries(long, java.util.function.Function<java.util.Map.Entry<K, V>, ? extends U>, java.util.function.BiFunction<? super U, ? super U, ? extends U>);
    +     method public double reduceEntriesToDouble(long, java.util.function.ToDoubleFunction<java.util.Map.Entry<K, V>>, double, java.util.function.DoubleBinaryOperator);
    +     method public int reduceEntriesToInt(long, java.util.function.ToIntFunction<java.util.Map.Entry<K, V>>, int, java.util.function.IntBinaryOperator);
    +     method public long reduceEntriesToLong(long, java.util.function.ToLongFunction<java.util.Map.Entry<K, V>>, long, java.util.function.LongBinaryOperator);
    +     method public K reduceKeys(long, java.util.function.BiFunction<? super K, ? super K, ? extends K>);
    +-    method public U reduceKeys(long, java.util.function.Function<? super K, ? extends U>, java.util.function.BiFunction<? super U, ? super U, ? extends U>);
    ++    method public <U> U reduceKeys(long, java.util.function.Function<? super K, ? extends U>, java.util.function.BiFunction<? super U, ? super U, ? extends U>);
    +     method public double reduceKeysToDouble(long, java.util.function.ToDoubleFunction<? super K>, double, java.util.function.DoubleBinaryOperator);
    +     method public int reduceKeysToInt(long, java.util.function.ToIntFunction<? super K>, int, java.util.function.IntBinaryOperator);
    +     method public long reduceKeysToLong(long, java.util.function.ToLongFunction<? super K>, long, java.util.function.LongBinaryOperator);
    +@@ -59596,7 +59605,7 @@ package java.util.concurrent {
    +     method public int reduceToInt(long, java.util.function.ToIntBiFunction<? super K, ? super V>, int, java.util.function.IntBinaryOperator);
    +     method public long reduceToLong(long, java.util.function.ToLongBiFunction<? super K, ? super V>, long, java.util.function.LongBinaryOperator);
    +     method public V reduceValues(long, java.util.function.BiFunction<? super V, ? super V, ? extends V>);
    +-    method public U reduceValues(long, java.util.function.Function<? super V, ? extends U>, java.util.function.BiFunction<? super U, ? super U, ? extends U>);
    ++    method public <U> U reduceValues(long, java.util.function.Function<? super V, ? extends U>, java.util.function.BiFunction<? super U, ? super U, ? extends U>);
    +     method public double reduceValuesToDouble(long, java.util.function.ToDoubleFunction<? super V>, double, java.util.function.DoubleBinaryOperator);
    +     method public int reduceValuesToInt(long, java.util.function.ToIntFunction<? super V>, int, java.util.function.IntBinaryOperator);
    +     method public long reduceValuesToLong(long, java.util.function.ToLongFunction<? super V>, long, java.util.function.LongBinaryOperator);
    +@@ -59604,13 +59613,13 @@ package java.util.concurrent {
    +     method public boolean replace(K, V, V);
    +     method public V replace(K, V);
    +     method public void replaceAll(java.util.function.BiFunction<? super K, ? super V, ? extends V>);
    +-    method public U search(long, java.util.function.BiFunction<? super K, ? super V, ? extends U>);
    +-    method public U searchEntries(long, java.util.function.Function<java.util.Map.Entry<K, V>, ? extends U>);
    +-    method public U searchKeys(long, java.util.function.Function<? super K, ? extends U>);
    +-    method public U searchValues(long, java.util.function.Function<? super V, ? extends U>);
    ++    method public <U> U search(long, java.util.function.BiFunction<? super K, ? super V, ? extends U>);
    ++    method public <U> U searchEntries(long, java.util.function.Function<java.util.Map.Entry<K, V>, ? extends U>);
    ++    method public <U> U searchKeys(long, java.util.function.Function<? super K, ? extends U>);
    ++    method public <U> U searchValues(long, java.util.function.Function<? super V, ? extends U>);
    +   }
    + 
    +-   static abstract class ConcurrentHashMap.CollectionView implements java.util.Collection java.io.Serializable {
    ++   static abstract class ConcurrentHashMap.CollectionView<K, V, E> implements java.util.Collection java.io.Serializable {
    +     method public final void clear();
    +     method public abstract boolean contains(java.lang.Object);
    +     method public final boolean containsAll(java.util.Collection<?>);
    +@@ -59622,11 +59631,11 @@ package java.util.concurrent {
    +     method public final boolean retainAll(java.util.Collection<?>);
    +     method public final int size();
    +     method public final java.lang.Object[] toArray();
    +-    method public final T[] toArray(T[]);
    ++    method public final <T> T[] toArray(T[]);
    +     method public final java.lang.String toString();
    +   }
    + 
    +-  public static class ConcurrentHashMap.KeySetView extends java.util.concurrent.ConcurrentHashMap.CollectionView implements java.io.Serializable java.util.Set {
    ++  public static class ConcurrentHashMap.KeySetView<K, V> extends java.util.concurrent.ConcurrentHashMap.CollectionView implements java.io.Serializable java.util.Set {
    +     method public boolean add(K);
    +     method public boolean addAll(java.util.Collection<? extends K>);
    +     method public boolean contains(java.lang.Object);
    +@@ -59637,7 +59646,7 @@ package java.util.concurrent {
    +     method public java.util.Spliterator<K> spliterator();
    +   }
    + 
    +-  public class ConcurrentLinkedDeque extends java.util.AbstractCollection implements java.util.Deque java.io.Serializable {
    ++  public class ConcurrentLinkedDeque<E> extends java.util.AbstractCollection implements java.util.Deque java.io.Serializable {
    +     ctor public ConcurrentLinkedDeque();
    +     ctor public ConcurrentLinkedDeque(java.util.Collection<? extends E>);
    +     method public void addFirst(E);
    +@@ -59667,7 +59676,7 @@ package java.util.concurrent {
    +     method public java.util.Spliterator<E> spliterator();
    +   }
    + 
    +-  public class ConcurrentLinkedQueue extends java.util.AbstractQueue implements java.util.Queue java.io.Serializable {
    ++  public class ConcurrentLinkedQueue<E> extends java.util.AbstractQueue implements java.util.Queue java.io.Serializable {
    +     ctor public ConcurrentLinkedQueue();
    +     ctor public ConcurrentLinkedQueue(java.util.Collection<? extends E>);
    +     method public java.util.Iterator<E> iterator();
    +@@ -59678,14 +59687,14 @@ package java.util.concurrent {
    +     method public java.util.Spliterator<E> spliterator();
    +   }
    + 
    +-  public abstract interface ConcurrentMap implements java.util.Map {
    ++  public abstract interface ConcurrentMap<K, V> implements java.util.Map {
    +     method public abstract V putIfAbsent(K, V);
    +     method public abstract boolean remove(java.lang.Object, java.lang.Object);
    +     method public abstract boolean replace(K, V, V);
    +     method public abstract V replace(K, V);
    +   }
    + 
    +-  public abstract interface ConcurrentNavigableMap implements java.util.concurrent.ConcurrentMap java.util.NavigableMap {
    ++  public abstract interface ConcurrentNavigableMap<K, V> implements java.util.concurrent.ConcurrentMap java.util.NavigableMap {
    +     method public abstract java.util.NavigableSet<K> descendingKeySet();
    +     method public abstract java.util.concurrent.ConcurrentNavigableMap<K, V> descendingMap();
    +     method public abstract java.util.concurrent.ConcurrentNavigableMap<K, V> headMap(K, boolean);
    +@@ -59698,7 +59707,7 @@ package java.util.concurrent {
    +     method public abstract java.util.concurrent.ConcurrentNavigableMap<K, V> tailMap(K);
    +   }
    + 
    +-  public class ConcurrentSkipListMap extends java.util.AbstractMap implements java.lang.Cloneable java.util.concurrent.ConcurrentNavigableMap java.io.Serializable {
    ++  public class ConcurrentSkipListMap<K, V> extends java.util.AbstractMap implements java.lang.Cloneable java.util.concurrent.ConcurrentNavigableMap java.io.Serializable {
    +     ctor public ConcurrentSkipListMap();
    +     ctor public ConcurrentSkipListMap(java.util.Comparator<? super K>);
    +     ctor public ConcurrentSkipListMap(java.util.Map<? extends K, ? extends V>);
    +@@ -59742,7 +59751,7 @@ package java.util.concurrent {
    +     method public java.util.concurrent.ConcurrentNavigableMap<K, V> tailMap(K);
    +   }
    + 
    +-  public class ConcurrentSkipListSet extends java.util.AbstractSet implements java.lang.Cloneable java.util.NavigableSet java.io.Serializable {
    ++  public class ConcurrentSkipListSet<E> extends java.util.AbstractSet implements java.lang.Cloneable java.util.NavigableSet java.io.Serializable {
    +     ctor public ConcurrentSkipListSet();
    +     ctor public ConcurrentSkipListSet(java.util.Comparator<? super E>);
    +     ctor public ConcurrentSkipListSet(java.util.Collection<? extends E>);
    +@@ -59770,7 +59779,7 @@ package java.util.concurrent {
    +     method public java.util.NavigableSet<E> tailSet(E);
    +   }
    + 
    +-  public class CopyOnWriteArrayList implements java.lang.Cloneable java.util.List java.util.RandomAccess java.io.Serializable {
    ++  public class CopyOnWriteArrayList<E> implements java.lang.Cloneable java.util.List java.util.RandomAccess java.io.Serializable {
    +     ctor public CopyOnWriteArrayList();
    +     ctor public CopyOnWriteArrayList(java.util.Collection<? extends E>);
    +     ctor public CopyOnWriteArrayList(E[]);
    +@@ -59802,10 +59811,10 @@ package java.util.concurrent {
    +     method public int size();
    +     method public java.util.List<E> subList(int, int);
    +     method public java.lang.Object[] toArray();
    +-    method public T[] toArray(T[]);
    ++    method public <T> T[] toArray(T[]);
    +   }
    + 
    +-  public class CopyOnWriteArraySet extends java.util.AbstractSet implements java.io.Serializable {
    ++  public class CopyOnWriteArraySet<E> extends java.util.AbstractSet implements java.io.Serializable {
    +     ctor public CopyOnWriteArraySet();
    +     ctor public CopyOnWriteArraySet(java.util.Collection<? extends E>);
    +     method public void forEach(java.util.function.Consumer<? super E>);
    +@@ -59823,7 +59832,7 @@ package java.util.concurrent {
    +     method public long getCount();
    +   }
    + 
    +-  public abstract class CountedCompleter extends java.util.concurrent.ForkJoinTask {
    ++  public abstract class CountedCompleter<T> extends java.util.concurrent.ForkJoinTask {
    +     ctor protected CountedCompleter(java.util.concurrent.CountedCompleter<?>, int);
    +     ctor protected CountedCompleter(java.util.concurrent.CountedCompleter<?>);
    +     ctor protected CountedCompleter();
    +@@ -59860,7 +59869,7 @@ package java.util.concurrent {
    +     method public void reset();
    +   }
    + 
    +-  public class DelayQueue extends java.util.AbstractQueue implements java.util.concurrent.BlockingQueue {
    ++  public class DelayQueue<E extends java.util.concurrent.Delayed> extends java.util.AbstractQueue implements java.util.concurrent.BlockingQueue {
    +     ctor public DelayQueue();
    +     ctor public DelayQueue(java.util.Collection<? extends E>);
    +     method public int drainTo(java.util.Collection<? super E>);
    +@@ -59881,7 +59890,7 @@ package java.util.concurrent {
    +     method public abstract long getDelay(java.util.concurrent.TimeUnit);
    +   }
    + 
    +-  public class Exchanger {
    ++  public class Exchanger<V> {
    +     ctor public Exchanger();
    +     method public V exchange(V) throws java.lang.InterruptedException;
    +     method public V exchange(V, long, java.util.concurrent.TimeUnit) throws java.lang.InterruptedException, java.util.concurrent.TimeoutException;
    +@@ -59898,7 +59907,7 @@ package java.util.concurrent {
    +     method public abstract void execute(java.lang.Runnable);
    +   }
    + 
    +-  public class ExecutorCompletionService implements java.util.concurrent.CompletionService {
    ++  public class ExecutorCompletionService<V> implements java.util.concurrent.CompletionService {
    +     ctor public ExecutorCompletionService(java.util.concurrent.Executor);
    +     ctor public ExecutorCompletionService(java.util.concurrent.Executor, java.util.concurrent.BlockingQueue<java.util.concurrent.Future<V>>);
    +     method public java.util.concurrent.Future<V> poll();
    +@@ -59910,21 +59919,21 @@ package java.util.concurrent {
    + 
    +   public abstract interface ExecutorService implements java.util.concurrent.Executor {
    +     method public abstract boolean awaitTermination(long, java.util.concurrent.TimeUnit) throws java.lang.InterruptedException;
    +-    method public abstract java.util.List<java.util.concurrent.Future<T>> invokeAll(java.util.Collection<? extends java.util.concurrent.Callable<T>>) throws java.lang.InterruptedException;
    +-    method public abstract java.util.List<java.util.concurrent.Future<T>> invokeAll(java.util.Collection<? extends java.util.concurrent.Callable<T>>, long, java.util.concurrent.TimeUnit) throws java.lang.InterruptedException;
    +-    method public abstract T invokeAny(java.util.Collection<? extends java.util.concurrent.Callable<T>>) throws java.util.concurrent.ExecutionException, java.lang.InterruptedException;
    +-    method public abstract T invokeAny(java.util.Collection<? extends java.util.concurrent.Callable<T>>, long, java.util.concurrent.TimeUnit) throws java.util.concurrent.ExecutionException, java.lang.InterruptedException, java.util.concurrent.TimeoutException;
    ++    method public abstract <T> java.util.List<java.util.concurrent.Future<T>> invokeAll(java.util.Collection<? extends java.util.concurrent.Callable<T>>) throws java.lang.InterruptedException;
    ++    method public abstract <T> java.util.List<java.util.concurrent.Future<T>> invokeAll(java.util.Collection<? extends java.util.concurrent.Callable<T>>, long, java.util.concurrent.TimeUnit) throws java.lang.InterruptedException;
    ++    method public abstract <T> T invokeAny(java.util.Collection<? extends java.util.concurrent.Callable<T>>) throws java.util.concurrent.ExecutionException, java.lang.InterruptedException;
    ++    method public abstract <T> T invokeAny(java.util.Collection<? extends java.util.concurrent.Callable<T>>, long, java.util.concurrent.TimeUnit) throws java.util.concurrent.ExecutionException, java.lang.InterruptedException, java.util.concurrent.TimeoutException;
    +     method public abstract boolean isShutdown();
    +     method public abstract boolean isTerminated();
    +     method public abstract void shutdown();
    +     method public abstract java.util.List<java.lang.Runnable> shutdownNow();
    +-    method public abstract java.util.concurrent.Future<T> submit(java.util.concurrent.Callable<T>);
    +-    method public abstract java.util.concurrent.Future<T> submit(java.lang.Runnable, T);
    ++    method public abstract <T> java.util.concurrent.Future<T> submit(java.util.concurrent.Callable<T>);
    ++    method public abstract <T> java.util.concurrent.Future<T> submit(java.lang.Runnable, T);
    +     method public abstract java.util.concurrent.Future<?> submit(java.lang.Runnable);
    +   }
    + 
    +   public class Executors {
    +-    method public static java.util.concurrent.Callable<T> callable(java.lang.Runnable, T);
    ++    method public static <T> java.util.concurrent.Callable<T> callable(java.lang.Runnable, T);
    +     method public static java.util.concurrent.Callable<java.lang.Object> callable(java.lang.Runnable);
    +     method public static java.util.concurrent.Callable<java.lang.Object> callable(java.security.PrivilegedAction<?>);
    +     method public static java.util.concurrent.Callable<java.lang.Object> callable(java.security.PrivilegedExceptionAction<?>);
    +@@ -59941,8 +59950,8 @@ package java.util.concurrent {
    +     method public static java.util.concurrent.ScheduledExecutorService newSingleThreadScheduledExecutor(java.util.concurrent.ThreadFactory);
    +     method public static java.util.concurrent.ExecutorService newWorkStealingPool(int);
    +     method public static java.util.concurrent.ExecutorService newWorkStealingPool();
    +-    method public static java.util.concurrent.Callable<T> privilegedCallable(java.util.concurrent.Callable<T>);
    +-    method public static java.util.concurrent.Callable<T> privilegedCallableUsingCurrentClassLoader(java.util.concurrent.Callable<T>);
    ++    method public static <T> java.util.concurrent.Callable<T> privilegedCallable(java.util.concurrent.Callable<T>);
    ++    method public static <T> java.util.concurrent.Callable<T> privilegedCallableUsingCurrentClassLoader(java.util.concurrent.Callable<T>);
    +     method public static java.util.concurrent.ThreadFactory privilegedThreadFactory();
    +     method public static java.util.concurrent.ExecutorService unconfigurableExecutorService(java.util.concurrent.ExecutorService);
    +     method public static java.util.concurrent.ScheduledExecutorService unconfigurableScheduledExecutorService(java.util.concurrent.ScheduledExecutorService);
    +@@ -59970,7 +59979,7 @@ package java.util.concurrent {
    +     method public long getStealCount();
    +     method public java.lang.Thread.UncaughtExceptionHandler getUncaughtExceptionHandler();
    +     method public boolean hasQueuedSubmissions();
    +-    method public T invoke(java.util.concurrent.ForkJoinTask<T>);
    ++    method public <T> T invoke(java.util.concurrent.ForkJoinTask<T>);
    +     method public boolean isQuiescent();
    +     method public boolean isShutdown();
    +     method public boolean isTerminated();
    +@@ -59979,7 +59988,7 @@ package java.util.concurrent {
    +     method protected java.util.concurrent.ForkJoinTask<?> pollSubmission();
    +     method public void shutdown();
    +     method public java.util.List<java.lang.Runnable> shutdownNow();
    +-    method public java.util.concurrent.ForkJoinTask<T> submit(java.util.concurrent.ForkJoinTask<T>);
    ++    method public <T> java.util.concurrent.ForkJoinTask<T> submit(java.util.concurrent.ForkJoinTask<T>);
    +     field public static final java.util.concurrent.ForkJoinPool.ForkJoinWorkerThreadFactory defaultForkJoinWorkerThreadFactory;
    +   }
    + 
    +@@ -59992,11 +60001,11 @@ package java.util.concurrent {
    +     method public abstract boolean isReleasable();
    +   }
    + 
    +-  public abstract class ForkJoinTask implements java.util.concurrent.Future java.io.Serializable {
    ++  public abstract class ForkJoinTask<V> implements java.util.concurrent.Future java.io.Serializable {
    +     ctor public ForkJoinTask();
    +     method public static java.util.concurrent.ForkJoinTask<?> adapt(java.lang.Runnable);
    +-    method public static java.util.concurrent.ForkJoinTask<T> adapt(java.lang.Runnable, T);
    +-    method public static java.util.concurrent.ForkJoinTask<T> adapt(java.util.concurrent.Callable<? extends T>);
    ++    method public static <T> java.util.concurrent.ForkJoinTask<T> adapt(java.lang.Runnable, T);
    ++    method public static <T> java.util.concurrent.ForkJoinTask<T> adapt(java.util.concurrent.Callable<? extends T>);
    +     method public boolean cancel(boolean);
    +     method public final boolean compareAndSetForkJoinTaskTag(short, short);
    +     method public void complete(V);
    +@@ -60016,7 +60025,7 @@ package java.util.concurrent {
    +     method public final V invoke();
    +     method public static void invokeAll(java.util.concurrent.ForkJoinTask<?>, java.util.concurrent.ForkJoinTask<?>);
    +     method public static void invokeAll(java.util.concurrent.ForkJoinTask<?>...);
    +-    method public static java.util.Collection<T> invokeAll(java.util.Collection<T>);
    ++    method public static <T extends java.util.concurrent.ForkJoinTask<?>> java.util.Collection<T> invokeAll(java.util.Collection<T>);
    +     method public final boolean isCancelled();
    +     method public final boolean isCompletedAbnormally();
    +     method public final boolean isCompletedNormally();
    +@@ -60042,7 +60051,7 @@ package java.util.concurrent {
    +     method protected void onTermination(java.lang.Throwable);
    +   }
    + 
    +-  public abstract interface Future {
    ++  public abstract interface Future<V> {
    +     method public abstract boolean cancel(boolean);
    +     method public abstract V get() throws java.util.concurrent.ExecutionException, java.lang.InterruptedException;
    +     method public abstract V get(long, java.util.concurrent.TimeUnit) throws java.util.concurrent.ExecutionException, java.lang.InterruptedException, java.util.concurrent.TimeoutException;
    +@@ -60050,7 +60059,7 @@ package java.util.concurrent {
    +     method public abstract boolean isDone();
    +   }
    + 
    +-  public class FutureTask implements java.util.concurrent.RunnableFuture {
    ++  public class FutureTask<V> implements java.util.concurrent.RunnableFuture {
    +     ctor public FutureTask(java.util.concurrent.Callable<V>);
    +     ctor public FutureTask(java.lang.Runnable, V);
    +     method public boolean cancel(boolean);
    +@@ -60065,7 +60074,7 @@ package java.util.concurrent {
    +     method protected void setException(java.lang.Throwable);
    +   }
    + 
    +-  public class LinkedBlockingDeque extends java.util.AbstractQueue implements java.util.concurrent.BlockingDeque java.io.Serializable {
    ++  public class LinkedBlockingDeque<E> extends java.util.AbstractQueue implements java.util.concurrent.BlockingDeque java.io.Serializable {
    +     ctor public LinkedBlockingDeque();
    +     ctor public LinkedBlockingDeque(int);
    +     ctor public LinkedBlockingDeque(java.util.Collection<? extends E>);
    +@@ -60109,7 +60118,7 @@ package java.util.concurrent {
    +     method public E takeLast() throws java.lang.InterruptedException;
    +   }
    + 
    +-  public class LinkedBlockingQueue extends java.util.AbstractQueue implements java.util.concurrent.BlockingQueue java.io.Serializable {
    ++  public class LinkedBlockingQueue<E> extends java.util.AbstractQueue implements java.util.concurrent.BlockingQueue java.io.Serializable {
    +     ctor public LinkedBlockingQueue();
    +     ctor public LinkedBlockingQueue(int);
    +     ctor public LinkedBlockingQueue(java.util.Collection<? extends E>);
    +@@ -60128,7 +60137,7 @@ package java.util.concurrent {
    +     method public E take() throws java.lang.InterruptedException;
    +   }
    + 
    +-  public class LinkedTransferQueue extends java.util.AbstractQueue implements java.io.Serializable java.util.concurrent.TransferQueue {
    ++  public class LinkedTransferQueue<E> extends java.util.AbstractQueue implements java.io.Serializable java.util.concurrent.TransferQueue {
    +     ctor public LinkedTransferQueue();
    +     ctor public LinkedTransferQueue(java.util.Collection<? extends E>);
    +     method public int drainTo(java.util.Collection<? super E>);
    +@@ -60175,7 +60184,7 @@ package java.util.concurrent {
    +     method public int register();
    +   }
    + 
    +-  public class PriorityBlockingQueue extends java.util.AbstractQueue implements java.util.concurrent.BlockingQueue java.io.Serializable {
    ++  public class PriorityBlockingQueue<E> extends java.util.AbstractQueue implements java.util.concurrent.BlockingQueue java.io.Serializable {
    +     ctor public PriorityBlockingQueue();
    +     ctor public PriorityBlockingQueue(int);
    +     ctor public PriorityBlockingQueue(int, java.util.Comparator<? super E>);
    +@@ -60204,7 +60213,7 @@ package java.util.concurrent {
    +     method protected final void setRawResult(java.lang.Void);
    +   }
    + 
    +-  public abstract class RecursiveTask extends java.util.concurrent.ForkJoinTask {
    ++  public abstract class RecursiveTask<V> extends java.util.concurrent.ForkJoinTask {
    +     ctor public RecursiveTask();
    +     method protected abstract V compute();
    +     method protected final boolean exec();
    +@@ -60223,22 +60232,22 @@ package java.util.concurrent {
    +     method public abstract void rejectedExecution(java.lang.Runnable, java.util.concurrent.ThreadPoolExecutor);
    +   }
    + 
    +-  public abstract interface RunnableFuture implements java.util.concurrent.Future java.lang.Runnable {
    ++  public abstract interface RunnableFuture<V> implements java.util.concurrent.Future java.lang.Runnable {
    +     method public abstract void run();
    +   }
    + 
    +-  public abstract interface RunnableScheduledFuture implements java.util.concurrent.RunnableFuture java.util.concurrent.ScheduledFuture {
    ++  public abstract interface RunnableScheduledFuture<V> implements java.util.concurrent.RunnableFuture java.util.concurrent.ScheduledFuture {
    +     method public abstract boolean isPeriodic();
    +   }
    + 
    +   public abstract interface ScheduledExecutorService implements java.util.concurrent.ExecutorService {
    +     method public abstract java.util.concurrent.ScheduledFuture<?> schedule(java.lang.Runnable, long, java.util.concurrent.TimeUnit);
    +-    method public abstract java.util.concurrent.ScheduledFuture<V> schedule(java.util.concurrent.Callable<V>, long, java.util.concurrent.TimeUnit);
    ++    method public abstract <V> java.util.concurrent.ScheduledFuture<V> schedule(java.util.concurrent.Callable<V>, long, java.util.concurrent.TimeUnit);
    +     method public abstract java.util.concurrent.ScheduledFuture<?> scheduleAtFixedRate(java.lang.Runnable, long, long, java.util.concurrent.TimeUnit);
    +     method public abstract java.util.concurrent.ScheduledFuture<?> scheduleWithFixedDelay(java.lang.Runnable, long, long, java.util.concurrent.TimeUnit);
    +   }
    + 
    +-  public abstract interface ScheduledFuture implements java.util.concurrent.Delayed java.util.concurrent.Future {
    ++  public abstract interface ScheduledFuture<V> implements java.util.concurrent.Delayed java.util.concurrent.Future {
    +   }
    + 
    +   public class ScheduledThreadPoolExecutor extends java.util.concurrent.ThreadPoolExecutor implements java.util.concurrent.ScheduledExecutorService {
    +@@ -60246,13 +60255,13 @@ package java.util.concurrent {
    +     ctor public ScheduledThreadPoolExecutor(int, java.util.concurrent.ThreadFactory);
    +     ctor public ScheduledThreadPoolExecutor(int, java.util.concurrent.RejectedExecutionHandler);
    +     ctor public ScheduledThreadPoolExecutor(int, java.util.concurrent.ThreadFactory, java.util.concurrent.RejectedExecutionHandler);
    +-    method protected java.util.concurrent.RunnableScheduledFuture<V> decorateTask(java.lang.Runnable, java.util.concurrent.RunnableScheduledFuture<V>);
    +-    method protected java.util.concurrent.RunnableScheduledFuture<V> decorateTask(java.util.concurrent.Callable<V>, java.util.concurrent.RunnableScheduledFuture<V>);
    ++    method protected <V> java.util.concurrent.RunnableScheduledFuture<V> decorateTask(java.lang.Runnable, java.util.concurrent.RunnableScheduledFuture<V>);
    ++    method protected <V> java.util.concurrent.RunnableScheduledFuture<V> decorateTask(java.util.concurrent.Callable<V>, java.util.concurrent.RunnableScheduledFuture<V>);
    +     method public boolean getContinueExistingPeriodicTasksAfterShutdownPolicy();
    +     method public boolean getExecuteExistingDelayedTasksAfterShutdownPolicy();
    +     method public boolean getRemoveOnCancelPolicy();
    +     method public java.util.concurrent.ScheduledFuture<?> schedule(java.lang.Runnable, long, java.util.concurrent.TimeUnit);
    +-    method public java.util.concurrent.ScheduledFuture<V> schedule(java.util.concurrent.Callable<V>, long, java.util.concurrent.TimeUnit);
    ++    method public <V> java.util.concurrent.ScheduledFuture<V> schedule(java.util.concurrent.Callable<V>, long, java.util.concurrent.TimeUnit);
    +     method public java.util.concurrent.ScheduledFuture<?> scheduleAtFixedRate(java.lang.Runnable, long, long, java.util.concurrent.TimeUnit);
    +     method public java.util.concurrent.ScheduledFuture<?> scheduleWithFixedDelay(java.lang.Runnable, long, long, java.util.concurrent.TimeUnit);
    +     method public void setContinueExistingPeriodicTasksAfterShutdownPolicy(boolean);
    +@@ -60282,7 +60291,7 @@ package java.util.concurrent {
    +     method public boolean tryAcquire(int, long, java.util.concurrent.TimeUnit) throws java.lang.InterruptedException;
    +   }
    + 
    +-  public class SynchronousQueue extends java.util.AbstractQueue implements java.util.concurrent.BlockingQueue java.io.Serializable {
    ++  public class SynchronousQueue<E> extends java.util.AbstractQueue implements java.util.concurrent.BlockingQueue java.io.Serializable {
    +     ctor public SynchronousQueue();
    +     ctor public SynchronousQueue(boolean);
    +     method public int drainTo(java.util.Collection<? super E>);
    +@@ -60400,7 +60409,7 @@ package java.util.concurrent {
    +     ctor public TimeoutException(java.lang.String);
    +   }
    + 
    +-  public abstract interface TransferQueue implements java.util.concurrent.BlockingQueue {
    ++  public abstract interface TransferQueue<E> implements java.util.concurrent.BlockingQueue {
    +     method public abstract int getWaitingConsumerCount();
    +     method public abstract boolean hasWaitingConsumer();
    +     method public abstract void transfer(E) throws java.lang.InterruptedException;
    +@@ -60470,7 +60479,7 @@ package java.util.concurrent.atomic {
    +     method public final boolean weakCompareAndSet(int, int, int);
    +   }
    + 
    +-  public abstract class AtomicIntegerFieldUpdater {
    ++  public abstract class AtomicIntegerFieldUpdater<T> {
    +     ctor protected AtomicIntegerFieldUpdater();
    +     method public final int accumulateAndGet(T, int, java.util.function.IntBinaryOperator);
    +     method public int addAndGet(T, int);
    +@@ -60485,7 +60494,7 @@ package java.util.concurrent.atomic {
    +     method public final int getAndUpdate(T, java.util.function.IntUnaryOperator);
    +     method public int incrementAndGet(T);
    +     method public abstract void lazySet(T, int);
    +-    method public static java.util.concurrent.atomic.AtomicIntegerFieldUpdater<U> newUpdater(java.lang.Class<U>, java.lang.String);
    ++    method public static <U> java.util.concurrent.atomic.AtomicIntegerFieldUpdater<U> newUpdater(java.lang.Class<U>, java.lang.String);
    +     method public abstract void set(T, int);
    +     method public final int updateAndGet(T, java.util.function.IntUnaryOperator);
    +     method public abstract boolean weakCompareAndSet(T, int, int);
    +@@ -60538,7 +60547,7 @@ package java.util.concurrent.atomic {
    +     method public final boolean weakCompareAndSet(int, long, long);
    +   }
    + 
    +-  public abstract class AtomicLongFieldUpdater {
    ++  public abstract class AtomicLongFieldUpdater<T> {
    +     ctor protected AtomicLongFieldUpdater();
    +     method public final long accumulateAndGet(T, long, java.util.function.LongBinaryOperator);
    +     method public long addAndGet(T, long);
    +@@ -60553,13 +60562,13 @@ package java.util.concurrent.atomic {
    +     method public final long getAndUpdate(T, java.util.function.LongUnaryOperator);
    +     method public long incrementAndGet(T);
    +     method public abstract void lazySet(T, long);
    +-    method public static java.util.concurrent.atomic.AtomicLongFieldUpdater<U> newUpdater(java.lang.Class<U>, java.lang.String);
    ++    method public static <U> java.util.concurrent.atomic.AtomicLongFieldUpdater<U> newUpdater(java.lang.Class<U>, java.lang.String);
    +     method public abstract void set(T, long);
    +     method public final long updateAndGet(T, java.util.function.LongUnaryOperator);
    +     method public abstract boolean weakCompareAndSet(T, long, long);
    +   }
    + 
    +-  public class AtomicMarkableReference {
    ++  public class AtomicMarkableReference<V> {
    +     ctor public AtomicMarkableReference(V, boolean);
    +     method public boolean attemptMark(V, boolean);
    +     method public boolean compareAndSet(V, V, boolean, boolean);
    +@@ -60570,7 +60579,7 @@ package java.util.concurrent.atomic {
    +     method public boolean weakCompareAndSet(V, V, boolean, boolean);
    +   }
    + 
    +-  public class AtomicReference implements java.io.Serializable {
    ++  public class AtomicReference<V> implements java.io.Serializable {
    +     ctor public AtomicReference(V);
    +     ctor public AtomicReference();
    +     method public final V accumulateAndGet(V, java.util.function.BinaryOperator<V>);
    +@@ -60585,7 +60594,7 @@ package java.util.concurrent.atomic {
    +     method public final boolean weakCompareAndSet(V, V);
    +   }
    + 
    +-  public class AtomicReferenceArray implements java.io.Serializable {
    ++  public class AtomicReferenceArray<E> implements java.io.Serializable {
    +     ctor public AtomicReferenceArray(int);
    +     ctor public AtomicReferenceArray(E[]);
    +     method public final E accumulateAndGet(int, E, java.util.function.BinaryOperator<E>);
    +@@ -60601,7 +60610,7 @@ package java.util.concurrent.atomic {
    +     method public final boolean weakCompareAndSet(int, E, E);
    +   }
    + 
    +-  public abstract class AtomicReferenceFieldUpdater {
    ++  public abstract class AtomicReferenceFieldUpdater<T, V> {
    +     ctor protected AtomicReferenceFieldUpdater();
    +     method public final V accumulateAndGet(T, V, java.util.function.BinaryOperator<V>);
    +     method public abstract boolean compareAndSet(T, V, V);
    +@@ -60610,13 +60619,13 @@ package java.util.concurrent.atomic {
    +     method public V getAndSet(T, V);
    +     method public final V getAndUpdate(T, java.util.function.UnaryOperator<V>);
    +     method public abstract void lazySet(T, V);
    +-    method public static java.util.concurrent.atomic.AtomicReferenceFieldUpdater<U, W> newUpdater(java.lang.Class<U>, java.lang.Class<W>, java.lang.String);
    ++    method public static <U, W> java.util.concurrent.atomic.AtomicReferenceFieldUpdater<U, W> newUpdater(java.lang.Class<U>, java.lang.Class<W>, java.lang.String);
    +     method public abstract void set(T, V);
    +     method public final V updateAndGet(T, java.util.function.UnaryOperator<V>);
    +     method public abstract boolean weakCompareAndSet(T, V, V);
    +   }
    + 
    +-  public class AtomicStampedReference {
    ++  public class AtomicStampedReference<V> {
    +     ctor public AtomicStampedReference(V, int);
    +     method public boolean attemptStamp(V, int);
    +     method public boolean compareAndSet(V, V, int, int);
    +@@ -60919,33 +60928,33 @@ package java.util.concurrent.locks {
    + 
    + package java.util.function {
    + 
    +-  public abstract interface BiConsumer {
    ++  public abstract interface BiConsumer<T, U> {
    +     method public abstract void accept(T, U);
    +     method public default java.util.function.BiConsumer<T, U> andThen(java.util.function.BiConsumer<? super T, ? super U>);
    +   }
    + 
    +-  public abstract interface BiFunction {
    +-    method public default java.util.function.BiFunction<T, U, V> andThen(java.util.function.Function<? super R, ? extends V>);
    ++  public abstract interface BiFunction<T, U, R> {
    ++    method public default <V> java.util.function.BiFunction<T, U, V> andThen(java.util.function.Function<? super R, ? extends V>);
    +     method public abstract R apply(T, U);
    +   }
    + 
    +-  public abstract interface BiPredicate {
    ++  public abstract interface BiPredicate<T, U> {
    +     method public default java.util.function.BiPredicate<T, U> and(java.util.function.BiPredicate<? super T, ? super U>);
    +     method public default java.util.function.BiPredicate<T, U> negate();
    +     method public default java.util.function.BiPredicate<T, U> or(java.util.function.BiPredicate<? super T, ? super U>);
    +     method public abstract boolean test(T, U);
    +   }
    + 
    +-  public abstract interface BinaryOperator implements java.util.function.BiFunction {
    +-    method public static java.util.function.BinaryOperator<T> maxBy(java.util.Comparator<? super T>);
    +-    method public static java.util.function.BinaryOperator<T> minBy(java.util.Comparator<? super T>);
    ++  public abstract interface BinaryOperator<T> implements java.util.function.BiFunction {
    ++    method public static <T> java.util.function.BinaryOperator<T> maxBy(java.util.Comparator<? super T>);
    ++    method public static <T> java.util.function.BinaryOperator<T> minBy(java.util.Comparator<? super T>);
    +   }
    + 
    +   public abstract interface BooleanSupplier {
    +     method public abstract boolean getAsBoolean();
    +   }
    + 
    +-  public abstract interface Consumer {
    ++  public abstract interface Consumer<T> {
    +     method public abstract void accept(T);
    +     method public default java.util.function.Consumer<T> andThen(java.util.function.Consumer<? super T>);
    +   }
    +@@ -60959,7 +60968,7 @@ package java.util.function {
    +     method public default java.util.function.DoubleConsumer andThen(java.util.function.DoubleConsumer);
    +   }
    + 
    +-  public abstract interface DoubleFunction {
    ++  public abstract interface DoubleFunction<R> {
    +     method public abstract R apply(double);
    +   }
    + 
    +@@ -60989,11 +60998,11 @@ package java.util.function {
    +     method public static java.util.function.DoubleUnaryOperator identity();
    +   }
    + 
    +-  public abstract interface Function {
    +-    method public default java.util.function.Function<T, V> andThen(java.util.function.Function<? super R, ? extends V>);
    ++  public abstract interface Function<T, R> {
    ++    method public default <V> java.util.function.Function<T, V> andThen(java.util.function.Function<? super R, ? extends V>);
    +     method public abstract R apply(T);
    +-    method public default java.util.function.Function<V, R> compose(java.util.function.Function<? super V, ? extends T>);
    +-    method public static java.util.function.Function<T, T> identity();
    ++    method public default <V> java.util.function.Function<V, R> compose(java.util.function.Function<? super V, ? extends T>);
    ++    method public static <T> java.util.function.Function<T, T> identity();
    +   }
    + 
    +   public abstract interface IntBinaryOperator {
    +@@ -61005,7 +61014,7 @@ package java.util.function {
    +     method public default java.util.function.IntConsumer andThen(java.util.function.IntConsumer);
    +   }
    + 
    +-  public abstract interface IntFunction {
    ++  public abstract interface IntFunction<R> {
    +     method public abstract R apply(int);
    +   }
    + 
    +@@ -61044,7 +61053,7 @@ package java.util.function {
    +     method public default java.util.function.LongConsumer andThen(java.util.function.LongConsumer);
    +   }
    + 
    +-  public abstract interface LongFunction {
    ++  public abstract interface LongFunction<R> {
    +     method public abstract R apply(long);
    +   }
    + 
    +@@ -61074,56 +61083,56 @@ package java.util.function {
    +     method public static java.util.function.LongUnaryOperator identity();
    +   }
    + 
    +-  public abstract interface ObjDoubleConsumer {
    ++  public abstract interface ObjDoubleConsumer<T> {
    +     method public abstract void accept(T, double);
    +   }
    + 
    +-  public abstract interface ObjIntConsumer {
    ++  public abstract interface ObjIntConsumer<T> {
    +     method public abstract void accept(T, int);
    +   }
    + 
    +-  public abstract interface ObjLongConsumer {
    ++  public abstract interface ObjLongConsumer<T> {
    +     method public abstract void accept(T, long);
    +   }
    + 
    +-  public abstract interface Predicate {
    ++  public abstract interface Predicate<T> {
    +     method public default java.util.function.Predicate<T> and(java.util.function.Predicate<? super T>);
    +-    method public static java.util.function.Predicate<T> isEqual(java.lang.Object);
    ++    method public static <T> java.util.function.Predicate<T> isEqual(java.lang.Object);
    +     method public default java.util.function.Predicate<T> negate();
    +     method public default java.util.function.Predicate<T> or(java.util.function.Predicate<? super T>);
    +     method public abstract boolean test(T);
    +   }
    + 
    +-  public abstract interface Supplier {
    ++  public abstract interface Supplier<T> {
    +     method public abstract T get();
    +   }
    + 
    +-  public abstract interface ToDoubleBiFunction {
    ++  public abstract interface ToDoubleBiFunction<T, U> {
    +     method public abstract double applyAsDouble(T, U);
    +   }
    + 
    +-  public abstract interface ToDoubleFunction {
    ++  public abstract interface ToDoubleFunction<T> {
    +     method public abstract double applyAsDouble(T);
    +   }
    + 
    +-  public abstract interface ToIntBiFunction {
    ++  public abstract interface ToIntBiFunction<T, U> {
    +     method public abstract int applyAsInt(T, U);
    +   }
    + 
    +-  public abstract interface ToIntFunction {
    ++  public abstract interface ToIntFunction<T> {
    +     method public abstract int applyAsInt(T);
    +   }
    + 
    +-  public abstract interface ToLongBiFunction {
    ++  public abstract interface ToLongBiFunction<T, U> {
    +     method public abstract long applyAsLong(T, U);
    +   }
    + 
    +-  public abstract interface ToLongFunction {
    ++  public abstract interface ToLongFunction<T> {
    +     method public abstract long applyAsLong(T);
    +   }
    + 
    +-  public abstract interface UnaryOperator implements java.util.function.Function {
    +-    method public static java.util.function.UnaryOperator<T> identity();
    ++  public abstract interface UnaryOperator<T> implements java.util.function.Function {
    ++    method public static <T> java.util.function.UnaryOperator<T> identity();
    +   }
    + 
    + }
    +@@ -61711,7 +61720,7 @@ package java.util.regex {
    + 
    + package java.util.stream {
    + 
    +-  public abstract interface BaseStream implements java.lang.AutoCloseable {
    ++  public abstract interface BaseStream<T, S extends java.util.stream.BaseStream<T, S>> implements java.lang.AutoCloseable {
    +     method public abstract void close();
    +     method public abstract boolean isParallel();
    +     method public abstract java.util.Iterator<T> iterator();
    +@@ -61722,13 +61731,13 @@ package java.util.stream {
    +     method public abstract S unordered();
    +   }
    + 
    +-  public abstract interface Collector {
    ++  public abstract interface Collector<T, A, R> {
    +     method public abstract java.util.function.BiConsumer<A, T> accumulator();
    +     method public abstract java.util.Set<java.util.stream.Collector.Characteristics> characteristics();
    +     method public abstract java.util.function.BinaryOperator<A> combiner();
    +     method public abstract java.util.function.Function<A, R> finisher();
    +-    method public static java.util.stream.Collector<T, R, R> of(java.util.function.Supplier<R>, java.util.function.BiConsumer<R, T>, java.util.function.BinaryOperator<R>, java.util.stream.Collector.Characteristics...);
    +-    method public static java.util.stream.Collector<T, A, R> of(java.util.function.Supplier<A>, java.util.function.BiConsumer<A, T>, java.util.function.BinaryOperator<A>, java.util.function.Function<A, R>, java.util.stream.Collector.Characteristics...);
    ++    method public static <T, R> java.util.stream.Collector<T, R, R> of(java.util.function.Supplier<R>, java.util.function.BiConsumer<R, T>, java.util.function.BinaryOperator<R>, java.util.stream.Collector.Characteristics...);
    ++    method public static <T, A, R> java.util.stream.Collector<T, A, R> of(java.util.function.Supplier<A>, java.util.function.BiConsumer<A, T>, java.util.function.BinaryOperator<A>, java.util.function.Function<A, R>, java.util.stream.Collector.Characteristics...);
    +     method public abstract java.util.function.Supplier<A> supplier();
    +   }
    + 
    +@@ -61741,43 +61750,43 @@ package java.util.stream {
    +   }
    + 
    +   public final class Collectors {
    +-    method public static java.util.stream.Collector<T, ?, java.lang.Double> averagingDouble(java.util.function.ToDoubleFunction<? super T>);
    +-    method public static java.util.stream.Collector<T, ?, java.lang.Double> averagingInt(java.util.function.ToIntFunction<? super T>);
    +-    method public static java.util.stream.Collector<T, ?, java.lang.Double> averagingLong(java.util.function.ToLongFunction<? super T>);
    +-    method public static java.util.stream.Collector<T, A, RR> collectingAndThen(java.util.stream.Collector<T, A, R>, java.util.function.Function<R, RR>);
    +-    method public static java.util.stream.Collector<T, ?, java.lang.Long> counting();
    +-    method public static java.util.stream.Collector<T, ?, java.util.Map<K, java.util.List<T>>> groupingBy(java.util.function.Function<? super T, ? extends K>);
    +-    method public static java.util.stream.Collector<T, ?, java.util.Map<K, D>> groupingBy(java.util.function.Function<? super T, ? extends K>, java.util.stream.Collector<? super T, A, D>);
    +-    method public static java.util.stream.Collector<T, ?, M> groupingBy(java.util.function.Function<? super T, ? extends K>, java.util.function.Supplier<M>, java.util.stream.Collector<? super T, A, D>);
    +-    method public static java.util.stream.Collector<T, ?, java.util.concurrent.ConcurrentMap<K, java.util.List<T>>> groupingByConcurrent(java.util.function.Function<? super T, ? extends K>);
    +-    method public static java.util.stream.Collector<T, ?, java.util.concurrent.ConcurrentMap<K, D>> groupingByConcurrent(java.util.function.Function<? super T, ? extends K>, java.util.stream.Collector<? super T, A, D>);
    +-    method public static java.util.stream.Collector<T, ?, M> groupingByConcurrent(java.util.function.Function<? super T, ? extends K>, java.util.function.Supplier<M>, java.util.stream.Collector<? super T, A, D>);
    ++    method public static <T> java.util.stream.Collector<T, ?, java.lang.Double> averagingDouble(java.util.function.ToDoubleFunction<? super T>);
    ++    method public static <T> java.util.stream.Collector<T, ?, java.lang.Double> averagingInt(java.util.function.ToIntFunction<? super T>);
    ++    method public static <T> java.util.stream.Collector<T, ?, java.lang.Double> averagingLong(java.util.function.ToLongFunction<? super T>);
    ++    method public static <T, A, R, RR> java.util.stream.Collector<T, A, RR> collectingAndThen(java.util.stream.Collector<T, A, R>, java.util.function.Function<R, RR>);
    ++    method public static <T> java.util.stream.Collector<T, ?, java.lang.Long> counting();
    ++    method public static <T, K> java.util.stream.Collector<T, ?, java.util.Map<K, java.util.List<T>>> groupingBy(java.util.function.Function<? super T, ? extends K>);
    ++    method public static <T, K, A, D> java.util.stream.Collector<T, ?, java.util.Map<K, D>> groupingBy(java.util.function.Function<? super T, ? extends K>, java.util.stream.Collector<? super T, A, D>);
    ++    method public static <T, K, D, A, M extends java.util.Map<K, D>> java.util.stream.Collector<T, ?, M> groupingBy(java.util.function.Function<? super T, ? extends K>, java.util.function.Supplier<M>, java.util.stream.Collector<? super T, A, D>);
    ++    method public static <T, K> java.util.stream.Collector<T, ?, java.util.concurrent.ConcurrentMap<K, java.util.List<T>>> groupingByConcurrent(java.util.function.Function<? super T, ? extends K>);
    ++    method public static <T, K, A, D> java.util.stream.Collector<T, ?, java.util.concurrent.ConcurrentMap<K, D>> groupingByConcurrent(java.util.function.Function<? super T, ? extends K>, java.util.stream.Collector<? super T, A, D>);
    ++    method public static <T, K, A, D, M extends java.util.concurrent.ConcurrentMap<K, D>> java.util.stream.Collector<T, ?, M> groupingByConcurrent(java.util.function.Function<? super T, ? extends K>, java.util.function.Supplier<M>, java.util.stream.Collector<? super T, A, D>);
    +     method public static java.util.stream.Collector<java.lang.CharSequence, ?, java.lang.String> joining();
    +     method public static java.util.stream.Collector<java.lang.CharSequence, ?, java.lang.String> joining(java.lang.CharSequence);
    +     method public static java.util.stream.Collector<java.lang.CharSequence, ?, java.lang.String> joining(java.lang.CharSequence, java.lang.CharSequence, java.lang.CharSequence);
    +-    method public static java.util.stream.Collector<T, ?, R> mapping(java.util.function.Function<? super T, ? extends U>, java.util.stream.Collector<? super U, A, R>);
    +-    method public static java.util.stream.Collector<T, ?, java.util.Optional<T>> maxBy(java.util.Comparator<? super T>);
    +-    method public static java.util.stream.Collector<T, ?, java.util.Optional<T>> minBy(java.util.Comparator<? super T>);
    +-    method public static java.util.stream.Collector<T, ?, java.util.Map<java.lang.Boolean, java.util.List<T>>> partitioningBy(java.util.function.Predicate<? super T>);
    +-    method public static java.util.stream.Collector<T, ?, java.util.Map<java.lang.Boolean, D>> partitioningBy(java.util.function.Predicate<? super T>, java.util.stream.Collector<? super T, A, D>);
    +-    method public static java.util.stream.Collector<T, ?, T> reducing(T, java.util.function.BinaryOperator<T>);
    +-    method public static java.util.stream.Collector<T, ?, java.util.Optional<T>> reducing(java.util.function.BinaryOperator<T>);
    +-    method public static java.util.stream.Collector<T, ?, U> reducing(U, java.util.function.Function<? super T, ? extends U>, java.util.function.BinaryOperator<U>);
    +-    method public static java.util.stream.Collector<T, ?, java.util.DoubleSummaryStatistics> summarizingDouble(java.util.function.ToDoubleFunction<? super T>);
    +-    method public static java.util.stream.Collector<T, ?, java.util.IntSummaryStatistics> summarizingInt(java.util.function.ToIntFunction<? super T>);
    +-    method public static java.util.stream.Collector<T, ?, java.util.LongSummaryStatistics> summarizingLong(java.util.function.ToLongFunction<? super T>);
    +-    method public static java.util.stream.Collector<T, ?, java.lang.Double> summingDouble(java.util.function.ToDoubleFunction<? super T>);
    +-    method public static java.util.stream.Collector<T, ?, java.lang.Integer> summingInt(java.util.function.ToIntFunction<? super T>);
    +-    method public static java.util.stream.Collector<T, ?, java.lang.Long> summingLong(java.util.function.ToLongFunction<? super T>);
    +-    method public static java.util.stream.Collector<T, ?, C> toCollection(java.util.function.Supplier<C>);
    +-    method public static java.util.stream.Collector<T, ?, java.util.concurrent.ConcurrentMap<K, U>> toConcurrentMap(java.util.function.Function<? super T, ? extends K>, java.util.function.Function<? super T, ? extends U>);
    +-    method public static java.util.stream.Collector<T, ?, java.util.concurrent.ConcurrentMap<K, U>> toConcurrentMap(java.util.function.Function<? super T, ? extends K>, java.util.function.Function<? super T, ? extends U>, java.util.function.BinaryOperator<U>);
    +-    method public static java.util.stream.Collector<T, ?, M> toConcurrentMap(java.util.function.Function<? super T, ? extends K>, java.util.function.Function<? super T, ? extends U>, java.util.function.BinaryOperator<U>, java.util.function.Supplier<M>);
    +-    method public static java.util.stream.Collector<T, ?, java.util.List<T>> toList();
    +-    method public static java.util.stream.Collector<T, ?, java.util.Map<K, U>> toMap(java.util.function.Function<? super T, ? extends K>, java.util.function.Function<? super T, ? extends U>);
    +-    method public static java.util.stream.Collector<T, ?, java.util.Map<K, U>> toMap(java.util.function.Function<? super T, ? extends K>, java.util.function.Function<? super T, ? extends U>, java.util.function.BinaryOperator<U>);
    +-    method public static java.util.stream.Collector<T, ?, M> toMap(java.util.function.Function<? super T, ? extends K>, java.util.function.Function<? super T, ? extends U>, java.util.function.BinaryOperator<U>, java.util.function.Supplier<M>);
    +-    method public static java.util.stream.Collector<T, ?, java.util.Set<T>> toSet();
    ++    method public static <T, U, A, R> java.util.stream.Collector<T, ?, R> mapping(java.util.function.Function<? super T, ? extends U>, java.util.stream.Collector<? super U, A, R>);
    ++    method public static <T> java.util.stream.Collector<T, ?, java.util.Optional<T>> maxBy(java.util.Comparator<? super T>);
    ++    method public static <T> java.util.stream.Collector<T, ?, java.util.Optional<T>> minBy(java.util.Comparator<? super T>);
    ++    method public static <T> java.util.stream.Collector<T, ?, java.util.Map<java.lang.Boolean, java.util.List<T>>> partitioningBy(java.util.function.Predicate<? super T>);
    ++    method public static <T, D, A> java.util.stream.Collector<T, ?, java.util.Map<java.lang.Boolean, D>> partitioningBy(java.util.function.Predicate<? super T>, java.util.stream.Collector<? super T, A, D>);
    ++    method public static <T> java.util.stream.Collector<T, ?, T> reducing(T, java.util.function.BinaryOperator<T>);
    ++    method public static <T> java.util.stream.Collector<T, ?, java.util.Optional<T>> reducing(java.util.function.BinaryOperator<T>);
    ++    method public static <T, U> java.util.stream.Collector<T, ?, U> reducing(U, java.util.function.Function<? super T, ? extends U>, java.util.function.BinaryOperator<U>);
    ++    method public static <T> java.util.stream.Collector<T, ?, java.util.DoubleSummaryStatistics> summarizingDouble(java.util.function.ToDoubleFunction<? super T>);
    ++    method public static <T> java.util.stream.Collector<T, ?, java.util.IntSummaryStatistics> summarizingInt(java.util.function.ToIntFunction<? super T>);
    ++    method public static <T> java.util.stream.Collector<T, ?, java.util.LongSummaryStatistics> summarizingLong(java.util.function.ToLongFunction<? super T>);
    ++    method public static <T> java.util.stream.Collector<T, ?, java.lang.Double> summingDouble(java.util.function.ToDoubleFunction<? super T>);
    ++    method public static <T> java.util.stream.Collector<T, ?, java.lang.Integer> summingInt(java.util.function.ToIntFunction<? super T>);
    ++    method public static <T> java.util.stream.Collector<T, ?, java.lang.Long> summingLong(java.util.function.ToLongFunction<? super T>);
    ++    method public static <T, C extends java.util.Collection<T>> java.util.stream.Collector<T, ?, C> toCollection(java.util.function.Supplier<C>);
    ++    method public static <T, K, U> java.util.stream.Collector<T, ?, java.util.concurrent.ConcurrentMap<K, U>> toConcurrentMap(java.util.function.Function<? super T, ? extends K>, java.util.function.Function<? super T, ? extends U>);
    ++    method public static <T, K, U> java.util.stream.Collector<T, ?, java.util.concurrent.ConcurrentMap<K, U>> toConcurrentMap(java.util.function.Function<? super T, ? extends K>, java.util.function.Function<? super T, ? extends U>, java.util.function.BinaryOperator<U>);
    ++    method public static <T, K, U, M extends java.util.concurrent.ConcurrentMap<K, U>> java.util.stream.Collector<T, ?, M> toConcurrentMap(java.util.function.Function<? super T, ? extends K>, java.util.function.Function<? super T, ? extends U>, java.util.function.BinaryOperator<U>, java.util.function.Supplier<M>);
    ++    method public static <T> java.util.stream.Collector<T, ?, java.util.List<T>> toList();
    ++    method public static <T, K, U> java.util.stream.Collector<T, ?, java.util.Map<K, U>> toMap(java.util.function.Function<? super T, ? extends K>, java.util.function.Function<? super T, ? extends U>);
    ++    method public static <T, K, U> java.util.stream.Collector<T, ?, java.util.Map<K, U>> toMap(java.util.function.Function<? super T, ? extends K>, java.util.function.Function<? super T, ? extends U>, java.util.function.BinaryOperator<U>);
    ++    method public static <T, K, U, M extends java.util.Map<K, U>> java.util.stream.Collector<T, ?, M> toMap(java.util.function.Function<? super T, ? extends K>, java.util.function.Function<? super T, ? extends U>, java.util.function.BinaryOperator<U>, java.util.function.Supplier<M>);
    ++    method public static <T> java.util.stream.Collector<T, ?, java.util.Set<T>> toSet();
    +   }
    + 
    +   public abstract interface DoubleStream implements java.util.stream.BaseStream {
    +@@ -61786,7 +61795,7 @@ package java.util.stream {
    +     method public abstract java.util.OptionalDouble average();
    +     method public abstract java.util.stream.Stream<java.lang.Double> boxed();
    +     method public static java.util.stream.DoubleStream.Builder builder();
    +-    method public abstract R collect(java.util.function.Supplier<R>, java.util.function.ObjDoubleConsumer<R>, java.util.function.BiConsumer<R, R>);
    ++    method public abstract <R> R collect(java.util.function.Supplier<R>, java.util.function.ObjDoubleConsumer<R>, java.util.function.BiConsumer<R, R>);
    +     method public static java.util.stream.DoubleStream concat(java.util.stream.DoubleStream, java.util.stream.DoubleStream);
    +     method public abstract long count();
    +     method public abstract java.util.stream.DoubleStream distinct();
    +@@ -61804,7 +61813,7 @@ package java.util.stream {
    +     method public abstract java.util.stream.DoubleStream map(java.util.function.DoubleUnaryOperator);
    +     method public abstract java.util.stream.IntStream mapToInt(java.util.function.DoubleToIntFunction);
    +     method public abstract java.util.stream.LongStream mapToLong(java.util.function.DoubleToLongFunction);
    +-    method public abstract java.util.stream.Stream<U> mapToObj(java.util.function.DoubleFunction<? extends U>);
    ++    method public abstract <U> java.util.stream.Stream<U> mapToObj(java.util.function.DoubleFunction<? extends U>);
    +     method public abstract java.util.OptionalDouble max();
    +     method public abstract java.util.OptionalDouble min();
    +     method public abstract boolean noneMatch(java.util.function.DoublePredicate);
    +@@ -61837,7 +61846,7 @@ package java.util.stream {
    +     method public abstract java.util.OptionalDouble average();
    +     method public abstract java.util.stream.Stream<java.lang.Integer> boxed();
    +     method public static java.util.stream.IntStream.Builder builder();
    +-    method public abstract R collect(java.util.function.Supplier<R>, java.util.function.ObjIntConsumer<R>, java.util.function.BiConsumer<R, R>);
    ++    method public abstract <R> R collect(java.util.function.Supplier<R>, java.util.function.ObjIntConsumer<R>, java.util.function.BiConsumer<R, R>);
    +     method public static java.util.stream.IntStream concat(java.util.stream.IntStream, java.util.stream.IntStream);
    +     method public abstract long count();
    +     method public abstract java.util.stream.IntStream distinct();
    +@@ -61855,7 +61864,7 @@ package java.util.stream {
    +     method public abstract java.util.stream.IntStream map(java.util.function.IntUnaryOperator);
    +     method public abstract java.util.stream.DoubleStream mapToDouble(java.util.function.IntToDoubleFunction);
    +     method public abstract java.util.stream.LongStream mapToLong(java.util.function.IntToLongFunction);
    +-    method public abstract java.util.stream.Stream<U> mapToObj(java.util.function.IntFunction<? extends U>);
    ++    method public abstract <U> java.util.stream.Stream<U> mapToObj(java.util.function.IntFunction<? extends U>);
    +     method public abstract java.util.OptionalInt max();
    +     method public abstract java.util.OptionalInt min();
    +     method public abstract boolean noneMatch(java.util.function.IntPredicate);
    +@@ -61889,7 +61898,7 @@ package java.util.stream {
    +     method public abstract java.util.OptionalDouble average();
    +     method public abstract java.util.stream.Stream<java.lang.Long> boxed();
    +     method public static java.util.stream.LongStream.Builder builder();
    +-    method public abstract R collect(java.util.function.Supplier<R>, java.util.function.ObjLongConsumer<R>, java.util.function.BiConsumer<R, R>);
    ++    method public abstract <R> R collect(java.util.function.Supplier<R>, java.util.function.ObjLongConsumer<R>, java.util.function.BiConsumer<R, R>);
    +     method public static java.util.stream.LongStream concat(java.util.stream.LongStream, java.util.stream.LongStream);
    +     method public abstract long count();
    +     method public abstract java.util.stream.LongStream distinct();
    +@@ -61907,7 +61916,7 @@ package java.util.stream {
    +     method public abstract java.util.stream.LongStream map(java.util.function.LongUnaryOperator);
    +     method public abstract java.util.stream.DoubleStream mapToDouble(java.util.function.LongToDoubleFunction);
    +     method public abstract java.util.stream.IntStream mapToInt(java.util.function.LongToIntFunction);
    +-    method public abstract java.util.stream.Stream<U> mapToObj(java.util.function.LongFunction<? extends U>);
    ++    method public abstract <U> java.util.stream.Stream<U> mapToObj(java.util.function.LongFunction<? extends U>);
    +     method public abstract java.util.OptionalLong max();
    +     method public abstract java.util.OptionalLong min();
    +     method public abstract boolean noneMatch(java.util.function.LongPredicate);
    +@@ -61934,49 +61943,49 @@ package java.util.stream {
    +     method public abstract java.util.stream.LongStream build();
    +   }
    + 
    +-  public abstract interface Stream implements java.util.stream.BaseStream {
    ++  public abstract interface Stream<T> implements java.util.stream.BaseStream {
    +     method public abstract boolean allMatch(java.util.function.Predicate<? super T>);
    +     method public abstract boolean anyMatch(java.util.function.Predicate<? super T>);
    +-    method public static java.util.stream.Stream.Builder<T> builder();
    +-    method public abstract R collect(java.util.function.Supplier<R>, java.util.function.BiConsumer<R, ? super T>, java.util.function.BiConsumer<R, R>);
    +-    method public abstract R collect(java.util.stream.Collector<? super T, A, R>);
    +-    method public static java.util.stream.Stream<T> concat(java.util.stream.Stream<? extends T>, java.util.stream.Stream<? extends T>);
    ++    method public static <T> java.util.stream.Stream.Builder<T> builder();
    ++    method public abstract <R> R collect(java.util.function.Supplier<R>, java.util.function.BiConsumer<R, ? super T>, java.util.function.BiConsumer<R, R>);
    ++    method public abstract <R, A> R collect(java.util.stream.Collector<? super T, A, R>);
    ++    method public static <T> java.util.stream.Stream<T> concat(java.util.stream.Stream<? extends T>, java.util.stream.Stream<? extends T>);
    +     method public abstract long count();
    +     method public abstract java.util.stream.Stream<T> distinct();
    +-    method public static java.util.stream.Stream<T> empty();
    ++    method public static <T> java.util.stream.Stream<T> empty();
    +     method public abstract java.util.stream.Stream<T> filter(java.util.function.Predicate<? super T>);
    +     method public abstract java.util.Optional<T> findAny();
    +     method public abstract java.util.Optional<T> findFirst();
    +-    method public abstract java.util.stream.Stream<R> flatMap(java.util.function.Function<? super T, ? extends java.util.stream.Stream<? extends R>>);
    ++    method public abstract <R> java.util.stream.Stream<R> flatMap(java.util.function.Function<? super T, ? extends java.util.stream.Stream<? extends R>>);
    +     method public abstract java.util.stream.DoubleStream flatMapToDouble(java.util.function.Function<? super T, ? extends java.util.stream.DoubleStream>);
    +     method public abstract java.util.stream.IntStream flatMapToInt(java.util.function.Function<? super T, ? extends java.util.stream.IntStream>);
    +     method public abstract java.util.stream.LongStream flatMapToLong(java.util.function.Function<? super T, ? extends java.util.stream.LongStream>);
    +     method public abstract void forEach(java.util.function.Consumer<? super T>);
    +     method public abstract void forEachOrdered(java.util.function.Consumer<? super T>);
    +-    method public static java.util.stream.Stream<T> generate(java.util.function.Supplier<T>);
    +-    method public static java.util.stream.Stream<T> iterate(T, java.util.function.UnaryOperator<T>);
    ++    method public static <T> java.util.stream.Stream<T> generate(java.util.function.Supplier<T>);
    ++    method public static <T> java.util.stream.Stream<T> iterate(T, java.util.function.UnaryOperator<T>);
    +     method public abstract java.util.stream.Stream<T> limit(long);
    +-    method public abstract java.util.stream.Stream<R> map(java.util.function.Function<? super T, ? extends R>);
    ++    method public abstract <R> java.util.stream.Stream<R> map(java.util.function.Function<? super T, ? extends R>);
    +     method public abstract java.util.stream.DoubleStream mapToDouble(java.util.function.ToDoubleFunction<? super T>);
    +     method public abstract java.util.stream.IntStream mapToInt(java.util.function.ToIntFunction<? super T>);
    +     method public abstract java.util.stream.LongStream mapToLong(java.util.function.ToLongFunction<? super T>);
    +     method public abstract java.util.Optional<T> max(java.util.Comparator<? super T>);
    +     method public abstract java.util.Optional<T> min(java.util.Comparator<? super T>);
    +     method public abstract boolean noneMatch(java.util.function.Predicate<? super T>);
    +-    method public static java.util.stream.Stream<T> of(T);
    +-    method public static java.util.stream.Stream<T> of(T...);
    ++    method public static <T> java.util.stream.Stream<T> of(T);
    ++    method public static <T> java.util.stream.Stream<T> of(T...);
    +     method public abstract java.util.stream.Stream<T> peek(java.util.function.Consumer<? super T>);
    +     method public abstract T reduce(T, java.util.function.BinaryOperator<T>);
    +     method public abstract java.util.Optional<T> reduce(java.util.function.BinaryOperator<T>);
    +-    method public abstract U reduce(U, java.util.function.BiFunction<U, ? super T, U>, java.util.function.BinaryOperator<U>);
    ++    method public abstract <U> U reduce(U, java.util.function.BiFunction<U, ? super T, U>, java.util.function.BinaryOperator<U>);
    +     method public abstract java.util.stream.Stream<T> skip(long);
    +     method public abstract java.util.stream.Stream<T> sorted();
    +     method public abstract java.util.stream.Stream<T> sorted(java.util.Comparator<? super T>);
    +     method public abstract java.lang.Object[] toArray();
    +-    method public abstract A[] toArray(java.util.function.IntFunction<A[]>);
    ++    method public abstract <A> A[] toArray(java.util.function.IntFunction<A[]>);
    +   }
    + 
    +-  public static abstract interface Stream.Builder implements java.util.function.Consumer {
    ++  public static abstract interface Stream.Builder<T> implements java.util.function.Consumer {
    +     method public abstract void accept(T);
    +     method public default java.util.stream.Stream.Builder<T> add(T);
    +     method public abstract java.util.stream.Stream<T> build();
    +@@ -61989,8 +61998,8 @@ package java.util.stream {
    +     method public static java.util.stream.IntStream intStream(java.util.function.Supplier<? extends java.util.Spliterator.OfInt>, int, boolean);
    +     method public static java.util.stream.LongStream longStream(java.util.Spliterator.OfLong, boolean);
    +     method public static java.util.stream.LongStream longStream(java.util.function.Supplier<? extends java.util.Spliterator.OfLong>, int, boolean);
    +-    method public static java.util.stream.Stream<T> stream(java.util.Spliterator<T>, boolean);
    +-    method public static java.util.stream.Stream<T> stream(java.util.function.Supplier<? extends java.util.Spliterator<T>>, int, boolean);
    ++    method public static <T> java.util.stream.Stream<T> stream(java.util.Spliterator<T>, boolean);
    ++    method public static <T> java.util.stream.Stream<T> stream(java.util.function.Supplier<? extends java.util.Spliterator<T>>, int, boolean);
    +   }
    + 
    + }
    +@@ -64161,16 +64170,16 @@ package javax.security.auth {
    +   public final class Subject implements java.io.Serializable {
    +     ctor public Subject();
    +     ctor public Subject(boolean, java.util.Set<? extends java.security.Principal>, java.util.Set<?>, java.util.Set<?>);
    +-    method public static T doAs(javax.security.auth.Subject, java.security.PrivilegedAction<T>);
    +-    method public static T doAs(javax.security.auth.Subject, java.security.PrivilegedExceptionAction<T>) throws java.security.PrivilegedActionException;
    +-    method public static T doAsPrivileged(javax.security.auth.Subject, java.security.PrivilegedAction<T>, java.security.AccessControlContext);
    +-    method public static T doAsPrivileged(javax.security.auth.Subject, java.security.PrivilegedExceptionAction<T>, java.security.AccessControlContext) throws java.security.PrivilegedActionException;
    ++    method public static <T> T doAs(javax.security.auth.Subject, java.security.PrivilegedAction<T>);
    ++    method public static <T> T doAs(javax.security.auth.Subject, java.security.PrivilegedExceptionAction<T>) throws java.security.PrivilegedActionException;
    ++    method public static <T> T doAsPrivileged(javax.security.auth.Subject, java.security.PrivilegedAction<T>, java.security.AccessControlContext);
    ++    method public static <T> T doAsPrivileged(javax.security.auth.Subject, java.security.PrivilegedExceptionAction<T>, java.security.AccessControlContext) throws java.security.PrivilegedActionException;
    +     method public java.util.Set<java.security.Principal> getPrincipals();
    +-    method public java.util.Set<T> getPrincipals(java.lang.Class<T>);
    ++    method public <T extends java.security.Principal> java.util.Set<T> getPrincipals(java.lang.Class<T>);
    +     method public java.util.Set<java.lang.Object> getPrivateCredentials();
    +-    method public java.util.Set<T> getPrivateCredentials(java.lang.Class<T>);
    ++    method public <T> java.util.Set<T> getPrivateCredentials(java.lang.Class<T>);
    +     method public java.util.Set<java.lang.Object> getPublicCredentials();
    +-    method public java.util.Set<T> getPublicCredentials(java.lang.Class<T>);
    ++    method public <T> java.util.Set<T> getPublicCredentials(java.lang.Class<T>);
    +     method public static javax.security.auth.Subject getSubject(java.security.AccessControlContext);
    +     method public boolean isReadOnly();
    +     method public void setReadOnly();
    +diff --git a/cmds/bootanimation/audioplay.cpp b/cmds/bootanimation/audioplay.cpp
    +index 4983b9a..c546072 100644
    +--- a/cmds/bootanimation/audioplay.cpp
    ++++ b/cmds/bootanimation/audioplay.cpp
    +@@ -141,13 +141,27 @@ bool createBufferQueueAudioPlayer(const ChunkFormat* chunkFormat) {
    +     // configure audio source
    +     SLDataLocator_AndroidSimpleBufferQueue loc_bufq = {SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE, 1};
    + 
    ++    // Determine channelMask from num_channels
    ++    SLuint32 channelMask;
    ++    switch (chunkFormat->num_channels) {
    ++        case 1:
    ++            channelMask = SL_SPEAKER_FRONT_CENTER;
    ++            break;
    ++        case 2:
    ++            channelMask = SL_SPEAKER_FRONT_LEFT | SL_SPEAKER_FRONT_RIGHT;
    ++            break;
    ++        default:
    ++            // Default of 0 will derive mask from num_channels and log a warning.
    ++            channelMask = 0;
    ++    }
    ++
    +     SLDataFormat_PCM format_pcm = {
    +         SL_DATAFORMAT_PCM,
    +         chunkFormat->num_channels,
    +         chunkFormat->sample_rate * 1000,  // convert to milliHz
    +         chunkFormat->bits_per_sample,
    +         16,
    +-        SL_SPEAKER_FRONT_CENTER,
    ++        channelMask,
    +         SL_BYTEORDER_LITTLEENDIAN
    +     };
    +     SLDataSource audioSrc = {&loc_bufq, &format_pcm};
    +diff --git a/cmds/idmap/scan.cpp b/cmds/idmap/scan.cpp
    +index 6d30f0d..ab6adfb 100644
    +--- a/cmds/idmap/scan.cpp
    ++++ b/cmds/idmap/scan.cpp
    +@@ -1,5 +1,6 @@
    + #include <dirent.h>
    + #include <inttypes.h>
    ++#include <sys/file.h>
    + #include <sys/stat.h>
    + 
    + #include "idmap.h"
    +@@ -35,16 +36,31 @@ namespace {
    + 
    +     bool writePackagesList(const char *filename, const SortedVector<Overlay>& overlayVector)
    +     {
    +-        FILE* fout = fopen(filename, "w");
    ++        // the file is opened for appending so that it doesn't get truncated
    ++        // before we can guarantee mutual exclusion via the flock
    ++        FILE* fout = fopen(filename, "a");
    +         if (fout == NULL) {
    +             return false;
    +         }
    + 
    ++        if (TEMP_FAILURE_RETRY(flock(fileno(fout), LOCK_EX)) != 0) {
    ++            fclose(fout);
    ++            return false;
    ++        }
    ++
    ++        if (TEMP_FAILURE_RETRY(ftruncate(fileno(fout), 0)) != 0) {
    ++            TEMP_FAILURE_RETRY(flock(fileno(fout), LOCK_UN));
    ++            fclose(fout);
    ++            return false;
    ++        }
    ++
    +         for (size_t i = 0; i < overlayVector.size(); ++i) {
    +             const Overlay& overlay = overlayVector[i];
    +             fprintf(fout, "%s %s\n", overlay.apk_path.string(), overlay.idmap_path.string());
    +         }
    + 
    ++        TEMP_FAILURE_RETRY(fflush(fout));
    ++        TEMP_FAILURE_RETRY(flock(fileno(fout), LOCK_UN));
    +         fclose(fout);
    + 
    +         // Make file world readable since Zygote (running as root) will read
    +@@ -171,9 +187,6 @@ int idmap_scan(const char *target_package_name, const char *target_apk_path,
    + {
    +     String8 filename = String8(idmap_dir);
    +     filename.appendPath("overlays.list");
    +-    if (unlink(filename.string()) != 0 && errno != ENOENT) {
    +-        return EXIT_FAILURE;
    +-    }
    + 
    +     SortedVector<Overlay> overlayVector;
    +     const size_t N = overlay_dirs->size();
    +diff --git a/cmds/pm/src/com/android/commands/pm/Pm.java b/cmds/pm/src/com/android/commands/pm/Pm.java
    +index 32a8088..1b4eda8 100644
    +--- a/cmds/pm/src/com/android/commands/pm/Pm.java
    ++++ b/cmds/pm/src/com/android/commands/pm/Pm.java
    +@@ -41,6 +41,10 @@ import android.content.pm.PackageInstaller;
    + import android.content.pm.PackageInstaller.SessionInfo;
    + import android.content.pm.PackageInstaller.SessionParams;
    + import android.content.pm.PackageManager;
    ++import android.content.pm.PackageParser;
    ++import android.content.pm.PackageParser.ApkLite;
    ++import android.content.pm.PackageParser.PackageLite;
    ++import android.content.pm.PackageParser.PackageParserException;
    + import android.content.pm.UserInfo;
    + import android.net.Uri;
    + import android.os.Binder;
    +@@ -362,11 +366,33 @@ public final class Pm {
    +      */
    +     private int runInstall() throws RemoteException {
    +         final InstallParams params = makeInstallParams();
    ++        final String inPath = nextArg();
    ++        boolean installExternal =
    ++                (params.sessionParams.installFlags & PackageManager.INSTALL_EXTERNAL) != 0;
    ++        if (params.sessionParams.sizeBytes < 0 && inPath != null) {
    ++            File file = new File(inPath);
    ++            if (file.isFile()) {
    ++                if (installExternal) {
    ++                    try {
    ++                        ApkLite baseApk = PackageParser.parseApkLite(file, 0);
    ++                        PackageLite pkgLite = new PackageLite(null, baseApk, null, null, null);
    ++                        params.sessionParams.setSize(
    ++                                PackageHelper.calculateInstalledSize(pkgLite, false,
    ++                                        params.sessionParams.abiOverride));
    ++                    } catch (PackageParserException | IOException e) {
    ++                        System.err.println("Error: Failed to parse APK file : " + e);
    ++                        return 1;
    ++                    }
    ++                } else {
    ++                    params.sessionParams.setSize(file.length());
    ++                }
    ++            }
    ++        }
    ++
    +         final int sessionId = doCreateSession(params.sessionParams,
    +                 params.installerPackageName, params.userId);
    + 
    +         try {
    +-            final String inPath = nextArg();
    +             if (inPath == null && params.sessionParams.sizeBytes == 0) {
    +                 System.err.println("Error: must either specify a package size or an APK file");
    +                 return 1;
    +diff --git a/cmds/wm/src/com/android/commands/wm/Wm.java b/cmds/wm/src/com/android/commands/wm/Wm.java
    +index f7f7c88..383cd01 100644
    +--- a/cmds/wm/src/com/android/commands/wm/Wm.java
    ++++ b/cmds/wm/src/com/android/commands/wm/Wm.java
    +@@ -23,6 +23,7 @@ import android.graphics.Point;
    + import android.graphics.Rect;
    + import android.os.RemoteException;
    + import android.os.ServiceManager;
    ++import android.os.UserHandle;
    + import android.util.AndroidException;
    + import android.util.DisplayMetrics;
    + import android.view.Display;
    +@@ -201,9 +202,11 @@ public class Wm extends BaseCommand {
    +         try {
    +             if (density > 0) {
    +                 // TODO(multidisplay): For now Configuration only applies to main screen.
    +-                mWm.setForcedDisplayDensity(Display.DEFAULT_DISPLAY, density);
    ++                mWm.setForcedDisplayDensityForUser(Display.DEFAULT_DISPLAY, density,
    ++                        UserHandle.USER_CURRENT);
    +             } else {
    +-                mWm.clearForcedDisplayDensity(Display.DEFAULT_DISPLAY);
    ++                mWm.clearForcedDisplayDensityForUser(Display.DEFAULT_DISPLAY,
    ++                        UserHandle.USER_CURRENT);
    +             }
    +         } catch (RemoteException e) {
    +         }
    +diff --git a/core/java/android/accessibilityservice/AccessibilityService.java b/core/java/android/accessibilityservice/AccessibilityService.java
    +index c4eaccc..163e7d2 100644
    +--- a/core/java/android/accessibilityservice/AccessibilityService.java
    ++++ b/core/java/android/accessibilityservice/AccessibilityService.java
    +@@ -53,7 +53,7 @@ import java.lang.annotation.RetentionPolicy;
    + import java.util.List;
    + 
    + /**
    +- * Accessibility services are intended to assist users with disabilities in using
    ++ * Accessibility services should only be used to assist users with disabilities in using
    +  * Android devices and apps. They run in the background and receive callbacks by the system
    +  * when {@link AccessibilityEvent}s are fired. Such events denote some state transition
    +  * in the user interface, for example, the focus has changed, a button has been clicked,
    +diff --git a/core/java/android/accounts/Account.java b/core/java/android/accounts/Account.java
    +index 7b83a30..b6e85f1 100644
    +--- a/core/java/android/accounts/Account.java
    ++++ b/core/java/android/accounts/Account.java
    +@@ -16,9 +16,19 @@
    + 
    + package android.accounts;
    + 
    ++import android.annotation.NonNull;
    ++import android.annotation.Nullable;
    ++import android.content.Context;
    + import android.os.Parcelable;
    + import android.os.Parcel;
    ++import android.os.RemoteException;
    ++import android.os.ServiceManager;
    + import android.text.TextUtils;
    ++import android.util.ArraySet;
    ++import android.util.Log;
    ++import com.android.internal.annotations.GuardedBy;
    ++
    ++import java.util.Set;
    + 
    + /**
    +  * Value type that represents an Account in the {@link AccountManager}. This object is
    +@@ -26,8 +36,14 @@ import android.text.TextUtils;
    +  * suitable for use as the key of a {@link java.util.Map}
    +  */
    + public class Account implements Parcelable {
    ++    private static final String TAG = "Account";
    ++
    ++    @GuardedBy("sAccessedAccounts")
    ++    private static final Set<Account> sAccessedAccounts = new ArraySet<>();
    ++
    +     public final String name;
    +     public final String type;
    ++    private final @Nullable String accessId;
    + 
    +     public boolean equals(Object o) {
    +         if (o == this) return true;
    +@@ -44,6 +60,20 @@ public class Account implements Parcelable {
    +     }
    + 
    +     public Account(String name, String type) {
    ++        this(name, type, null);
    ++    }
    ++
    ++    /**
    ++     * @hide
    ++     */
    ++    public Account(@NonNull Account other, @NonNull String accessId) {
    ++        this(other.name, other.type, accessId);
    ++    }
    ++
    ++    /**
    ++     * @hide
    ++     */
    ++    public Account(String name, String type, String accessId) {
    +         if (TextUtils.isEmpty(name)) {
    +             throw new IllegalArgumentException("the name must not be empty: " + name);
    +         }
    +@@ -52,11 +82,31 @@ public class Account implements Parcelable {
    +         }
    +         this.name = name;
    +         this.type = type;
    ++        this.accessId = accessId;
    +     }
    + 
    +     public Account(Parcel in) {
    +         this.name = in.readString();
    +         this.type = in.readString();
    ++        this.accessId = in.readString();
    ++        if (accessId != null) {
    ++            synchronized (sAccessedAccounts) {
    ++                if (sAccessedAccounts.add(this)) {
    ++                    try {
    ++                        IAccountManager accountManager = IAccountManager.Stub.asInterface(
    ++                                ServiceManager.getService(Context.ACCOUNT_SERVICE));
    ++                        accountManager.onAccountAccessed(accessId);
    ++                    } catch (RemoteException e) {
    ++                        Log.e(TAG, "Error noting account access", e);
    ++                    }
    ++                }
    ++            }
    ++        }
    ++    }
    ++
    ++    /** @hide */
    ++    public String getAccessId() {
    ++        return accessId;
    +     }
    + 
    +     public int describeContents() {
    +@@ -66,6 +116,7 @@ public class Account implements Parcelable {
    +     public void writeToParcel(Parcel dest, int flags) {
    +         dest.writeString(name);
    +         dest.writeString(type);
    ++        dest.writeString(accessId);
    +     }
    + 
    +     public static final Creator<Account> CREATOR = new Creator<Account>() {
    +diff --git a/core/java/android/accounts/AccountManager.java b/core/java/android/accounts/AccountManager.java
    +index d3551b7..72707b7 100644
    +--- a/core/java/android/accounts/AccountManager.java
    ++++ b/core/java/android/accounts/AccountManager.java
    +@@ -28,6 +28,7 @@ import android.content.ComponentName;
    + import android.content.Context;
    + import android.content.Intent;
    + import android.content.IntentFilter;
    ++import android.content.IntentSender;
    + import android.content.res.Resources;
    + import android.database.SQLException;
    + import android.os.Build;
    +@@ -178,6 +179,14 @@ public class AccountManager {
    +     public static final String KEY_ACCOUNT_TYPE = "accountType";
    + 
    +     /**
    ++     * Bundle key used for the account access id used for noting the
    ++     * account was accessed when unmarshalled from a parcel.
    ++     *
    ++     * @hide
    ++     */
    ++    public static final String KEY_ACCOUNT_ACCESS_ID = "accountAccessId";
    ++
    ++    /**
    +      * Bundle key used for the auth token value in results
    +      * from {@link #getAuthToken} and friends.
    +      */
    +@@ -265,6 +274,15 @@ public class AccountManager {
    +             "android.accounts.AccountAuthenticator";
    +     public static final String AUTHENTICATOR_ATTRIBUTES_NAME = "account-authenticator";
    + 
    ++    /**
    ++     * Token type for the special case where a UID has access only to an account
    ++     * but no authenticator specific auth token types.
    ++     *
    ++     * @hide
    ++     */
    ++    public static final String ACCOUNT_ACCESS_TOKEN_TYPE =
    ++            "com.android.AccountManager.ACCOUNT_ACCESS_TOKEN_TYPE";
    ++
    +     private final Context mContext;
    +     private final IAccountManager mService;
    +     private final Handler mMainHandler;
    +@@ -803,7 +821,8 @@ public class AccountManager {
    +             public Account bundleToResult(Bundle bundle) throws AuthenticatorException {
    +                 String name = bundle.getString(KEY_ACCOUNT_NAME);
    +                 String type = bundle.getString(KEY_ACCOUNT_TYPE);
    +-                return new Account(name, type);
    ++                String accessId = bundle.getString(KEY_ACCOUNT_ACCESS_ID);
    ++                return new Account(name, type, accessId);
    +             }
    +         }.start();
    +     }
    +@@ -2259,6 +2278,7 @@ public class AccountManager {
    +                                     result.putString(KEY_ACCOUNT_NAME, null);
    +                                     result.putString(KEY_ACCOUNT_TYPE, null);
    +                                     result.putString(KEY_AUTHTOKEN, null);
    ++                                    result.putBinder(KEY_ACCOUNT_ACCESS_ID, null);
    +                                     try {
    +                                         mResponse.onResult(result);
    +                                     } catch (RemoteException e) {
    +@@ -2284,9 +2304,11 @@ public class AccountManager {
    +                                         public void onResult(Bundle value) throws RemoteException {
    +                                             Account account = new Account(
    +                                                     value.getString(KEY_ACCOUNT_NAME),
    +-                                                    value.getString(KEY_ACCOUNT_TYPE));
    +-                                            mFuture = getAuthToken(account, mAuthTokenType, mLoginOptions,
    +-                                                    mActivity, mMyCallback, mHandler);
    ++                                                    value.getString(KEY_ACCOUNT_TYPE),
    ++                                                    value.getString(KEY_ACCOUNT_ACCESS_ID));
    ++                                            mFuture = getAuthToken(account, mAuthTokenType,
    ++                                                    mLoginOptions,  mActivity, mMyCallback,
    ++                                                    mHandler);
    +                                         }
    + 
    +                                         @Override
    +@@ -2333,7 +2355,8 @@ public class AccountManager {
    +                         setException(new AuthenticatorException("account not in result"));
    +                         return;
    +                     }
    +-                    final Account account = new Account(accountName, accountType);
    ++                    final String accessId = result.getString(KEY_ACCOUNT_ACCESS_ID);
    ++                    final Account account = new Account(accountName, accountType, accessId);
    +                     mNumAccounts = 1;
    +                     getAuthToken(account, mAuthTokenType, null /* options */, mActivity,
    +                             mMyCallback, mHandler);
    +@@ -2956,4 +2979,49 @@ public class AccountManager {
    +             }
    +         }.start();
    +     }
    ++
    ++    /**
    ++     * Gets whether a given package under a user has access to an account.
    ++     * Can be called only from the system UID.
    ++     *
    ++     * @param account The account for which to check.
    ++     * @param packageName The package for which to check.
    ++     * @param userHandle The user for which to check.
    ++     * @return True if the package can access the account.
    ++     *
    ++     * @hide
    ++     */
    ++    public boolean hasAccountAccess(@NonNull Account account, @NonNull String packageName,
    ++            @NonNull UserHandle userHandle) {
    ++        try {
    ++            return mService.hasAccountAccess(account, packageName, userHandle);
    ++        } catch (RemoteException e) {
    ++            throw e.rethrowFromSystemServer();
    ++        }
    ++    }
    ++
    ++    /**
    ++     * Creates an intent to request access to a given account for a UID.
    ++     * The returned intent should be stated for a result where {@link
    ++     * Activity#RESULT_OK} result means access was granted whereas {@link
    ++     * Activity#RESULT_CANCELED} result means access wasn't granted. Can
    ++     * be called only from the system UID.
    ++     *
    ++     * @param account The account for which to request.
    ++     * @param packageName The package name which to request.
    ++     * @param userHandle The user for which to request.
    ++     * @return The intent to request account access or null if the package
    ++     *     doesn't exist.
    ++     *
    ++     * @hide
    ++     */
    ++    public IntentSender createRequestAccountAccessIntentSenderAsUser(@NonNull Account account,
    ++            @NonNull String packageName, @NonNull UserHandle userHandle) {
    ++        try {
    ++            return mService.createRequestAccountAccessIntentSenderAsUser(account, packageName,
    ++                    userHandle);
    ++        } catch (RemoteException e) {
    ++            throw e.rethrowFromSystemServer();
    ++        }
    ++    }
    + }
    +diff --git a/core/java/android/accounts/AccountManagerInternal.java b/core/java/android/accounts/AccountManagerInternal.java
    +new file mode 100644
    +index 0000000..68c17c3
    +--- /dev/null
    ++++ b/core/java/android/accounts/AccountManagerInternal.java
    +@@ -0,0 +1,90 @@
    ++/*
    ++ * Copyright (C) 2016 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 android.accounts;
    ++
    ++import android.annotation.IntRange;
    ++import android.annotation.NonNull;
    ++import android.os.RemoteCallback;
    ++
    ++/**
    ++ * Account manager local system service interface.
    ++ *
    ++ * @hide Only for use within the system server.
    ++ */
    ++public abstract class AccountManagerInternal {
    ++
    ++    /**
    ++     * Listener for explicit UID account access grant changes.
    ++     */
    ++    public interface OnAppPermissionChangeListener {
    ++
    ++        /**
    ++         * Called when the explicit grant state for a given UID to
    ++         * access an account changes.
    ++         *
    ++         * @param account The account
    ++         * @param uid The UID for which the grant changed
    ++         */
    ++        public void onAppPermissionChanged(Account account, int uid);
    ++    }
    ++
    ++    /**
    ++     * Requests that a given package is given access to an account.
    ++     * The provided callback will be invoked with a {@link android.os.Bundle}
    ++     * containing the result which will be a boolean value mapped to the
    ++     * {@link AccountManager#KEY_BOOLEAN_RESULT} key.
    ++     *
    ++     * @param account The account for which to request.
    ++     * @param packageName The package name for which to request.
    ++     * @param userId Concrete user id for which to request.
    ++     * @param callback A callback for receiving the result.
    ++     */
    ++    public abstract void requestAccountAccess(@NonNull Account account,
    ++            @NonNull String packageName, @IntRange(from = 0) int userId,
    ++            @NonNull RemoteCallback callback);
    ++
    ++    /**
    ++     * Check whether the given UID has access to the account.
    ++     *
    ++     * @param account The account
    ++     * @param uid The UID
    ++     * @return Whether the UID can access the account
    ++     */
    ++    public abstract boolean hasAccountAccess(@NonNull Account account, @IntRange(from = 0) int uid);
    ++
    ++    /**
    ++     * Adds a listener for explicit UID account access grant changes.
    ++     *
    ++     * @param listener The listener
    ++     */
    ++    public abstract void addOnAppPermissionChangeListener(
    ++            @NonNull OnAppPermissionChangeListener listener);
    ++
    ++    /**
    ++     * Backups the account access permissions.
    ++     * @param userId The user for which to backup.
    ++     * @return The backup data.
    ++     */
    ++    public abstract byte[] backupAccountAccessPermissions(int userId);
    ++
    ++    /**
    ++     * Restores the account access permissions.
    ++     * @param data The restore data.
    ++     * @param userId The user for which to restore.
    ++     */
    ++    public abstract void restoreAccountAccessPermissions(byte[] data, int userId);
    ++}
     diff --git a/core/java/android/accounts/ChooseTypeAndAccountActivity.java b/core/java/android/accounts/ChooseTypeAndAccountActivity.java
    -index 133df2b..fd52616 100644
    +index 133df2b..bf96926 100644
     --- a/core/java/android/accounts/ChooseTypeAndAccountActivity.java
     +++ b/core/java/android/accounts/ChooseTypeAndAccountActivity.java
     @@ -250,6 +250,10 @@ public class ChooseTypeAndAccountActivity extends Activity
                  outState.putParcelableArray(KEY_INSTANCE_STATE_EXISTING_ACCOUNTS, mExistingAccounts);
              }
    -         if (mSelectedItemIndex != SELECTED_ITEM_NONE) {
    -+            if (mAccounts == null) {
    -+                final AccountManager accountManager = AccountManager.get(this);
    -+                mAccounts = getAcceptableAccountChoices(accountManager);
    +         if (mSelectedItemIndex != SELECTED_ITEM_NONE) {
    ++            if (mAccounts == null) {
    ++                final AccountManager accountManager = AccountManager.get(this);
    ++                mAccounts = getAcceptableAccountChoices(accountManager);
    ++            }
    +             if (mSelectedItemIndex == mAccounts.size()) {
    +                 outState.putBoolean(KEY_INSTANCE_STATE_SELECTED_ADD_ACCOUNT, true);
    +             } else {
    +@@ -291,6 +295,10 @@ public class ChooseTypeAndAccountActivity extends Activity
    +         mPendingRequest = REQUEST_NULL;
    + 
    +         if (resultCode == RESULT_CANCELED) {
    ++            if (mAccounts == null) {
    ++                final AccountManager accountManager = AccountManager.get(this);
    ++                mAccounts = getAcceptableAccountChoices(accountManager);
    ++            }
    +             // if canceling out of addAccount and the original state caused us to skip this,
    +             // finish this activity
    +             if (mAccounts.isEmpty()) {
    +@@ -399,7 +407,7 @@ public class ChooseTypeAndAccountActivity extends Activity
    +      * useless.
    +      */
    +     private void setNonLabelThemeAndCallSuperCreate(Bundle savedInstanceState) {
    +-        setTheme(R.style.Theme_Material_Light_Dialog_NoActionBar);
    ++        setTheme(R.style.Theme_DeviceDefault_Light_Dialog_NoActionBar);
    +         super.onCreate(savedInstanceState);
    +     }
    + 
    +diff --git a/core/java/android/accounts/GrantCredentialsPermissionActivity.java b/core/java/android/accounts/GrantCredentialsPermissionActivity.java
    +index 12b2b9c..38eab29 100644
    +--- a/core/java/android/accounts/GrantCredentialsPermissionActivity.java
    ++++ b/core/java/android/accounts/GrantCredentialsPermissionActivity.java
    +@@ -35,12 +35,10 @@ import java.io.IOException;
    +  */
    + public class GrantCredentialsPermissionActivity extends Activity implements View.OnClickListener {
    +     public static final String EXTRAS_ACCOUNT = "account";
    +-    public static final String EXTRAS_AUTH_TOKEN_LABEL = "authTokenLabel";
    +     public static final String EXTRAS_AUTH_TOKEN_TYPE = "authTokenType";
    +     public static final String EXTRAS_RESPONSE = "response";
    +-    public static final String EXTRAS_ACCOUNT_TYPE_LABEL = "accountTypeLabel";
    +-    public static final String EXTRAS_PACKAGES = "application";
    +     public static final String EXTRAS_REQUESTING_UID = "uid";
    ++
    +     private Account mAccount;
    +     private String mAuthTokenType;
    +     private int mUid;
    +@@ -109,7 +107,11 @@ public class GrantCredentialsPermissionActivity extends Activity implements View
    +                 }
    +             }
    +         };
    +-        AccountManager.get(this).getAuthTokenLabel(mAccount.type, mAuthTokenType, callback, null);
    ++
    ++        if (!AccountManager.ACCOUNT_ACCESS_TOKEN_TYPE.equals(mAuthTokenType)) {
    ++            AccountManager.get(this).getAuthTokenLabel(mAccount.type,
    ++                    mAuthTokenType, callback, null);
    ++        }
    + 
    +         findViewById(R.id.allow_button).setOnClickListener(this);
    +         findViewById(R.id.deny_button).setOnClickListener(this);
    +diff --git a/core/java/android/accounts/IAccountManager.aidl b/core/java/android/accounts/IAccountManager.aidl
    +index 7199288..c271e7e 100644
    +--- a/core/java/android/accounts/IAccountManager.aidl
    ++++ b/core/java/android/accounts/IAccountManager.aidl
    +@@ -19,8 +19,10 @@ package android.accounts;
    + import android.accounts.IAccountManagerResponse;
    + import android.accounts.Account;
    + import android.accounts.AuthenticatorDescription;
    ++import android.content.IntentSender;
    + import android.os.Bundle;
    +-
    ++import android.os.RemoteCallback;
    ++import android.os.UserHandle;
    + 
    + /**
    +  * Central application service that provides account management.
    +@@ -102,4 +104,12 @@ interface IAccountManager {
    +     /* Check if credentials update is suggested */
    +     void isCredentialsUpdateSuggested(in IAccountManagerResponse response, in Account account,
    +         String statusToken);
    ++
    ++    /* Check if the package in a user can access an account */
    ++    boolean hasAccountAccess(in Account account, String packageName, in UserHandle userHandle);
    ++    /* Crate an intent to request account access for package and a given user id */
    ++    IntentSender createRequestAccountAccessIntentSenderAsUser(in Account account,
    ++        String packageName, in UserHandle userHandle);
    ++
    ++    void onAccountAccessed(String token);
    + }
    +diff --git a/core/java/android/animation/LayoutTransition.java b/core/java/android/animation/LayoutTransition.java
    +index cdd72be..5a23fdd 100644
    +--- a/core/java/android/animation/LayoutTransition.java
    ++++ b/core/java/android/animation/LayoutTransition.java
    +@@ -62,7 +62,11 @@ import java.util.Map;
    +  * layout will run (closing the gap created in the layout when the item was removed). If this
    +  * default choreography behavior is not desired, the {@link #setDuration(int, long)} and
    +  * {@link #setStartDelay(int, long)} of any or all of the animations can be changed as
    +- * appropriate.</p>
    ++ * appropriate. Keep in mind, however, that if you start an APPEARING animation before a
    ++ * DISAPPEARING animation is completed, the DISAPPEARING animation stops, and any effects from
    ++ * the DISAPPEARING animation are reverted. If you instead start a DISAPPEARING animation
    ++ * before an APPEARING animation is completed, a similar set of effects occurs for the
    ++ * APPEARING animation.</p>
    +  *
    +  * <p>The animations specified for the transition, both the defaults and any custom animations
    +  * set on the transition object, are templates only. That is, these animations exist to hold the
    +diff --git a/core/java/android/animation/ObjectAnimator.java b/core/java/android/animation/ObjectAnimator.java
    +index 9a2aa30..0c21c4f 100644
    +--- a/core/java/android/animation/ObjectAnimator.java
    ++++ b/core/java/android/animation/ObjectAnimator.java
    +@@ -977,8 +977,9 @@ public final class ObjectAnimator extends ValueAnimator {
    +     @Override
    +     void animateValue(float fraction) {
    +         final Object target = getTarget();
    +-        if (target == null) {
    +-            // We lost the target reference, cancel and clean up.
    ++        if (mTarget != null && target == null) {
    ++            // We lost the target reference, cancel and clean up. Note: we allow null target if the
    ++            /// target has never been set.
    +             cancel();
    +             return;
    +         }
    +diff --git a/core/java/android/animation/ValueAnimator.java b/core/java/android/animation/ValueAnimator.java
    +index e3f8fa4..7e16e3e 100644
    +--- a/core/java/android/animation/ValueAnimator.java
    ++++ b/core/java/android/animation/ValueAnimator.java
    +@@ -18,6 +18,7 @@ package android.animation;
    + 
    + import android.annotation.CallSuper;
    + import android.annotation.IntDef;
    ++import android.annotation.TestApi;
    + import android.os.Looper;
    + import android.os.Trace;
    + import android.util.AndroidRuntimeException;
    +@@ -261,6 +262,7 @@ public class ValueAnimator extends Animator implements AnimationHandler.Animatio
    +     /**
    +      * @hide
    +      */
    ++    @TestApi
    +     public static void setDurationScale(float durationScale) {
    +         sDurationScale = durationScale;
    +     }
    +@@ -268,6 +270,7 @@ public class ValueAnimator extends Animator implements AnimationHandler.Animatio
    +     /**
    +      * @hide
    +      */
    ++    @TestApi
    +     public static float getDurationScale() {
    +         return sDurationScale;
    +     }
    +diff --git a/core/java/android/app/ActivityManagerNative.java b/core/java/android/app/ActivityManagerNative.java
    +index aacd5da..50479c8 100644
    +--- a/core/java/android/app/ActivityManagerNative.java
    ++++ b/core/java/android/app/ActivityManagerNative.java
    +@@ -3017,6 +3017,14 @@ public abstract class ActivityManagerNative extends Binder implements IActivityM
    +             reply.writeNoException();
    +             return true;
    +         }
    ++        case CAN_BYPASS_WORK_CHALLENGE: {
    ++            data.enforceInterface(IActivityManager.descriptor);
    ++            final PendingIntent intent = PendingIntent.CREATOR.createFromParcel(data);
    ++            final boolean result = canBypassWorkChallenge(intent);
    ++            reply.writeNoException();
    ++            reply.writeInt(result ? 1 : 0);
    ++            return true;
    ++        }
    +         }
    + 
    +         return super.onTransact(code, data, reply, flags);
    +@@ -7091,6 +7099,20 @@ class ActivityManagerProxy implements IActivityManager
    +         reply.recycle();
    +         return;
    +     }
    ++    @Override
    ++    public boolean canBypassWorkChallenge(PendingIntent intent)
    ++            throws RemoteException {
    ++        Parcel data = Parcel.obtain();
    ++        Parcel reply = Parcel.obtain();
    ++        data.writeInterfaceToken(IActivityManager.descriptor);
    ++        intent.writeToParcel(data, 0);
    ++        mRemote.transact(CAN_BYPASS_WORK_CHALLENGE, data, reply, 0);
    ++        reply.readException();
    ++        final int result = reply.readInt();
    ++        data.recycle();
    ++        reply.recycle();
    ++        return result != 0;
    ++    }
    + 
    +     private IBinder mRemote;
    + }
    +diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
    +index 2c5f881..6a2b9aa 100644
    +--- a/core/java/android/app/ActivityThread.java
    ++++ b/core/java/android/app/ActivityThread.java
    +@@ -108,6 +108,7 @@ import android.renderscript.RenderScriptCacheDir;
    + import android.system.Os;
    + import android.system.OsConstants;
    + import android.system.ErrnoException;
    ++import android.webkit.WebView;
    + 
    + import com.android.internal.annotations.GuardedBy;
    + import com.android.internal.app.IVoiceInteractor;
    +@@ -433,8 +434,10 @@ public final class ActivityThread {
    +     static final class NewIntentData {
    +         List<ReferrerIntent> intents;
    +         IBinder token;
    ++        boolean andPause;
    +         public String toString() {
    +-            return "NewIntentData{intents=" + intents + " token=" + token + "}";
    ++            return "NewIntentData{intents=" + intents + " token=" + token
    ++                    + " andPause=" + andPause +"}";
    +         }
    +     }
    + 
    +@@ -751,10 +754,12 @@ public final class ActivityThread {
    +                     configChanges, notResumed, config, overrideConfig, true, preserveWindow);
    +         }
    + 
    +-        public final void scheduleNewIntent(List<ReferrerIntent> intents, IBinder token) {
    ++        public final void scheduleNewIntent(
    ++                List<ReferrerIntent> intents, IBinder token, boolean andPause) {
    +             NewIntentData data = new NewIntentData();
    +             data.intents = intents;
    +             data.token = token;
    ++            data.andPause = andPause;
    + 
    +             sendMessage(H.NEW_INTENT, data);
    +         }
    +@@ -1037,10 +1042,21 @@ public final class ActivityThread {
    +             long dalvikMax = runtime.totalMemory() / 1024;
    +             long dalvikFree = runtime.freeMemory() / 1024;
    +             long dalvikAllocated = dalvikMax - dalvikFree;
    ++
    ++            Class[] classesToCount = new Class[] {
    ++                    ContextImpl.class,
    ++                    Activity.class,
    ++                    WebView.class,
    ++                    OpenSSLSocketImpl.class
    ++            };
    ++            long[] instanceCounts = VMDebug.countInstancesOfClasses(classesToCount, true);
    ++            long appContextInstanceCount = instanceCounts[0];
    ++            long activityInstanceCount = instanceCounts[1];
    ++            long webviewInstanceCount = instanceCounts[2];
    ++            long openSslSocketCount = instanceCounts[3];
    ++
    +             long viewInstanceCount = ViewDebug.getViewInstanceCount();
    +             long viewRootInstanceCount = ViewDebug.getViewRootImplCount();
    +-            long appContextInstanceCount = Debug.countInstancesOfClass(ContextImpl.class);
    +-            long activityInstanceCount = Debug.countInstancesOfClass(Activity.class);
    +             int globalAssetCount = AssetManager.getGlobalAssetCount();
    +             int globalAssetManagerCount = AssetManager.getGlobalAssetManagerCount();
    +             int binderLocalObjectCount = Debug.getBinderLocalObjectCount();
    +@@ -1048,7 +1064,6 @@ public final class ActivityThread {
    +             int binderDeathObjectCount = Debug.getBinderDeathObjectCount();
    +             long parcelSize = Parcel.getGlobalAllocSize();
    +             long parcelCount = Parcel.getGlobalAllocCount();
    +-            long openSslSocketCount = Debug.countInstancesOfClass(OpenSSLSocketImpl.class);
    +             SQLiteDebug.PagerStats stats = SQLiteDebug.getDatabaseInfo();
    + 
    +             dumpMemInfoTable(pw, memInfo, checkin, dumpFullInfo, dumpDalvik, dumpSummaryOnly,
    +@@ -1111,6 +1126,7 @@ public final class ActivityThread {
    +                     "Parcel count:", parcelCount);
    +             printRow(pw, TWO_COUNT_COLUMNS, "Death Recipients:", binderDeathObjectCount,
    +                     "OpenSSL Sockets:", openSslSocketCount);
    ++            printRow(pw, ONE_COUNT_COLUMN, "WebViews:", webviewInstanceCount);
    + 
    +             // SQLite mem info
    +             pw.println(" ");
    +@@ -2787,24 +2803,34 @@ public final class ActivityThread {
    +         }
    +     }
    + 
    +-    public final void performNewIntents(IBinder token, List<ReferrerIntent> intents) {
    +-        ActivityClientRecord r = mActivities.get(token);
    +-        if (r != null) {
    +-            final boolean resumed = !r.paused;
    +-            if (resumed) {
    +-                r.activity.mTemporaryPause = true;
    +-                mInstrumentation.callActivityOnPause(r.activity);
    +-            }
    +-            deliverNewIntents(r, intents);
    +-            if (resumed) {
    +-                r.activity.performResume();
    +-                r.activity.mTemporaryPause = false;
    +-            }
    ++    void performNewIntents(IBinder token, List<ReferrerIntent> intents, boolean andPause) {
    ++        final ActivityClientRecord r = mActivities.get(token);
    ++        if (r == null) {
    ++            return;
    ++        }
    ++
    ++        final boolean resumed = !r.paused;
    ++        if (resumed) {
    ++            r.activity.mTemporaryPause = true;
    ++            mInstrumentation.callActivityOnPause(r.activity);
    ++        }
    ++        deliverNewIntents(r, intents);
    ++        if (resumed) {
    ++            r.activity.performResume();
    ++            r.activity.mTemporaryPause = false;
    ++        }
    ++
    ++        if (r.paused && andPause) {
    ++            // In this case the activity was in the paused state when we delivered the intent,
    ++            // to guarantee onResume gets called after onNewIntent we temporarily resume the
    ++            // activity and pause again as the caller wanted.
    ++            performResumeActivity(token, false, "performNewIntents");
    ++            performPauseActivityIfNeeded(r, "performNewIntents");
    +         }
    +     }
    + 
    +     private void handleNewIntent(NewIntentData data) {
    +-        performNewIntents(data.token, data.intents);
    ++        performNewIntents(data.token, data.intents, data.andPause);
    +     }
    + 
    +     public void handleRequestAssistContextExtras(RequestAssistContextExtras cmd) {
    +@@ -3785,7 +3811,7 @@ public final class ActivityThread {
    +      * than our client -- for the server, stop means to save state and give
    +      * it the result when it is done, but the window may still be visible.
    +      * For the client, we want to call onStop()/onStart() to indicate when
    +-     * the activity's UI visibillity changes.
    ++     * the activity's UI visibility changes.
    +      */
    +     private void performStopActivityInner(ActivityClientRecord r,
    +             StopInfo info, boolean keepShown, boolean saveState, String reason) {
    +@@ -3959,6 +3985,9 @@ public final class ActivityThread {
    +         mSomeActivitiesChanged = true;
    +     }
    + 
    ++    // TODO: This method should be changed to use {@link #performStopActivityInner} to perform to
    ++    // stop operation on the activity to reduce code duplication and the chance of fixing a bug in
    ++    // one place and missing the other.
    +     private void handleSleeping(IBinder token, boolean sleeping) {
    +         ActivityClientRecord r = mActivities.get(token);
    + 
    +@@ -3969,6 +3998,10 @@ public final class ActivityThread {
    + 
    +         if (sleeping) {
    +             if (!r.stopped && !r.isPreHoneycomb()) {
    ++                if (!r.activity.mFinished && r.state == null) {
    ++                    callCallActivityOnSaveInstanceState(r);
    ++                }
    ++
    +                 try {
    +                     // Now we are idle.
    +                     r.activity.performStop(false /*preserveWindow*/);
    +@@ -4989,9 +5022,7 @@ public final class ActivityThread {
    +             int uid = Process.myUid();
    +             String[] packages = getPackageManager().getPackagesForUid(uid);
    + 
    +-            // If there are several packages in this application we won't
    +-            // initialize the graphics disk caches
    +-            if (packages != null && packages.length == 1) {
    ++            if (packages != null) {
    +                 ThreadedRenderer.setupDiskCache(cacheDir);
    +                 RenderScriptCacheDir.setupDiskCache(cacheDir);
    +             }
    +diff --git a/core/java/android/app/ApplicationThreadNative.java b/core/java/android/app/ApplicationThreadNative.java
    +index d6da3f4..05d9d7e 100644
    +--- a/core/java/android/app/ApplicationThreadNative.java
    ++++ b/core/java/android/app/ApplicationThreadNative.java
    +@@ -190,7 +190,8 @@ public abstract class ApplicationThreadNative extends Binder
    +             data.enforceInterface(IApplicationThread.descriptor);
    +             List<ReferrerIntent> pi = data.createTypedArrayList(ReferrerIntent.CREATOR);
    +             IBinder b = data.readStrongBinder();
    +-            scheduleNewIntent(pi, b);
    ++            final boolean andPause = data.readInt() == 1;
    ++            scheduleNewIntent(pi, b, andPause);
    +             return true;
    +         }
    + 
    +@@ -909,12 +910,13 @@ class ApplicationThreadProxy implements IApplicationThread {
    +         data.recycle();
    +     }
    + 
    +-    public void scheduleNewIntent(List<ReferrerIntent> intents, IBinder token)
    ++    public void scheduleNewIntent(List<ReferrerIntent> intents, IBinder token, boolean andPause)
    +             throws RemoteException {
    +         Parcel data = Parcel.obtain();
    +         data.writeInterfaceToken(IApplicationThread.descriptor);
    +         data.writeTypedList(intents);
    +         data.writeStrongBinder(token);
    ++        data.writeInt(andPause ? 1 : 0);
    +         mRemote.transact(SCHEDULE_NEW_INTENT_TRANSACTION, data, null,
    +                 IBinder.FLAG_ONEWAY);
    +         data.recycle();
    +diff --git a/core/java/android/app/Dialog.java b/core/java/android/app/Dialog.java
    +index 85a0403..6e2c464 100644
    +--- a/core/java/android/app/Dialog.java
    ++++ b/core/java/android/app/Dialog.java
    +@@ -32,6 +32,7 @@ import android.content.ComponentName;
    + import android.content.Context;
    + import android.content.ContextWrapper;
    + import android.content.DialogInterface;
    ++import android.content.res.Configuration;
    + import android.content.pm.ApplicationInfo;
    + import android.graphics.drawable.Drawable;
    + import android.net.Uri;
    +@@ -288,9 +289,14 @@ public class Dialog implements DialogInterface, Window.Callback,
    +         }
    + 
    +         mCanceled = false;
    +-        
    ++
    +         if (!mCreated) {
    +             dispatchOnCreate(null);
    ++        } else {
    ++            // Fill the DecorView in on any configuration changes that
    ++            // may have occured while it was removed from the WindowManager.
    ++            final Configuration config = mContext.getResources().getConfiguration();
    ++            mWindow.getDecorView().dispatchConfigurationChanged(config);
    +         }
    + 
    +         onStart();
    +diff --git a/core/java/android/app/DownloadManager.java b/core/java/android/app/DownloadManager.java
    +index 66234da..6e38347 100644
    +--- a/core/java/android/app/DownloadManager.java
    ++++ b/core/java/android/app/DownloadManager.java
    +@@ -1089,7 +1089,7 @@ public class DownloadManager {
    +             if (cursor.moveToFirst()) {
    +                 int status = cursor.getInt(cursor.getColumnIndexOrThrow(COLUMN_STATUS));
    +                 if (DownloadManager.STATUS_SUCCESSFUL == status) {
    +-                   return ContentUris.withAppendedId(Downloads.Impl.ALL_DOWNLOADS_CONTENT_URI, id);
    ++                    return ContentUris.withAppendedId(Downloads.Impl.ALL_DOWNLOADS_CONTENT_URI, id);
    +                 }
    +             }
    +         } finally {
    +diff --git a/core/java/android/app/Fragment.java b/core/java/android/app/Fragment.java
    +index 8afca78..5dead28 100644
    +--- a/core/java/android/app/Fragment.java
    ++++ b/core/java/android/app/Fragment.java
    +@@ -194,7 +194,7 @@ final class FragmentState implements Parcelable {
    +  * <div class="special reference">
    +  * <h3>Developer Guides</h3>
    +  * <p>For more information about using fragments, read the
    +- * <a href="{@docRoot}guide/topics/fundamentals/fragments.html">Fragments</a> developer guide.</p>
    ++ * <a href="{@docRoot}guide/components/fragments.html">Fragments</a> developer guide.</p>
    +  * </div>
    +  *
    +  * <a name="OlderPlatforms"></a>
    +diff --git a/core/java/android/app/FragmentHostCallback.java b/core/java/android/app/FragmentHostCallback.java
    +index e1d7136..d869168 100644
    +--- a/core/java/android/app/FragmentHostCallback.java
    ++++ b/core/java/android/app/FragmentHostCallback.java
    +@@ -340,6 +340,11 @@ public abstract class FragmentHostCallback<E> extends FragmentContainer {
    +     }
    + 
    +     void restoreLoaderNonConfig(ArrayMap<String, LoaderManager> loaderManagers) {
    ++        if (loaderManagers != null) {
    ++            for (int i = 0, N = loaderManagers.size(); i < N; i++) {
    ++                ((LoaderManagerImpl) loaderManagers.valueAt(i)).updateHostController(this);
    ++            }
    ++        }
    +         mAllLoaderManagers = loaderManagers;
    +     }
    + 
    +diff --git a/core/java/android/app/FragmentManager.java b/core/java/android/app/FragmentManager.java
    +index cd7665c..bfaf332 100644
    +--- a/core/java/android/app/FragmentManager.java
    ++++ b/core/java/android/app/FragmentManager.java
    +@@ -59,7 +59,7 @@ import java.util.List;
    +  * <div class="special reference">
    +  * <h3>Developer Guides</h3>
    +  * <p>For more information about using fragments, read the
    +- * <a href="{@docRoot}guide/topics/fundamentals/fragments.html">Fragments</a> developer guide.</p>
    ++ * <a href="{@docRoot}guide/components/fragments.html">Fragments</a> developer guide.</p>
    +  * </div>
    +  *
    +  * While the FragmentManager API was introduced in
    +diff --git a/core/java/android/app/IActivityManager.java b/core/java/android/app/IActivityManager.java
    +index e411e03..5a4470b 100644
    +--- a/core/java/android/app/IActivityManager.java
    ++++ b/core/java/android/app/IActivityManager.java
    +@@ -671,6 +671,18 @@ public interface IActivityManager extends IInterface {
    +      */
    +     public void setHasTopUi(boolean hasTopUi) throws RemoteException;
    + 
    ++    /**
    ++     * Returns if the target of the PendingIntent can be fired directly, without triggering
    ++     * a work profile challenge. This can happen if the PendingIntent is to start direct-boot
    ++     * aware activities, and the target user is in RUNNING_LOCKED state, i.e. we should allow
    ++     * direct-boot aware activity to bypass work challenge when the user hasn't unlocked yet.
    ++     * @param intent the {@link  PendingIntent} to be tested.
    ++     * @return {@code true} if the intent should not trigger a work challenge, {@code false}
    ++     *     otherwise.
    ++     * @throws RemoteException
    ++     */
    ++    public boolean canBypassWorkChallenge(PendingIntent intent) throws RemoteException;
    ++
    +     /*
    +      * Private non-Binder interfaces
    +      */
    +@@ -1062,4 +1074,5 @@ public interface IActivityManager extends IInterface {
    +     int SET_VR_THREAD_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION + 377;
    +     int SET_RENDER_THREAD_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION + 378;
    +     int SET_HAS_TOP_UI = IBinder.FIRST_CALL_TRANSACTION + 379;
    ++    int CAN_BYPASS_WORK_CHALLENGE = IBinder.FIRST_CALL_TRANSACTION + 380;
    + }
    +diff --git a/core/java/android/app/IApplicationThread.java b/core/java/android/app/IApplicationThread.java
    +index 559f69f..3fa88ae 100644
    +--- a/core/java/android/app/IApplicationThread.java
    ++++ b/core/java/android/app/IApplicationThread.java
    +@@ -67,7 +67,8 @@ public interface IApplicationThread extends IInterface {
    +             List<ReferrerIntent> pendingNewIntents, int configChanges, boolean notResumed,
    +             Configuration config, Configuration overrideConfig, boolean preserveWindow)
    +             throws RemoteException;
    +-    void scheduleNewIntent(List<ReferrerIntent> intent, IBinder token) throws RemoteException;
    ++    void scheduleNewIntent(
    ++            List<ReferrerIntent> intent, IBinder token, boolean andPause) throws RemoteException;
    +     void scheduleDestroyActivity(IBinder token, boolean finished,
    +             int configChanges) throws RemoteException;
    +     void scheduleReceiver(Intent intent, ActivityInfo info, CompatibilityInfo compatInfo,
    +diff --git a/core/java/android/app/ITransientNotification.aidl b/core/java/android/app/ITransientNotification.aidl
    +index 35b53a4..d5b3ed0 100644
    +--- a/core/java/android/app/ITransientNotification.aidl
    ++++ b/core/java/android/app/ITransientNotification.aidl
    +@@ -19,7 +19,7 @@ package android.app;
    + 
    + /** @hide */
    + oneway interface ITransientNotification {
    +-    void show();
    ++    void show(IBinder windowToken);
    +     void hide();
    + }
    + 
    +diff --git a/core/java/android/app/IntentService.java b/core/java/android/app/IntentService.java
    +index f33af39..e4a22c4 100644
    +--- a/core/java/android/app/IntentService.java
    ++++ b/core/java/android/app/IntentService.java
    +@@ -46,7 +46,8 @@ import android.os.Message;
    +  * <div class="special reference">
    +  * <h3>Developer Guides</h3>
    +  * <p>For a detailed discussion about how to create services, read the
    +- * <a href="{@docRoot}guide/topics/fundamentals/services.html">Services</a> developer guide.</p>
    ++ * <a href="{@docRoot}guide/components/services.html">Services</a> developer
    ++ * guide.</p>
    +  * </div>
    +  *
    +  * @see android.os.AsyncTask
    +diff --git a/core/java/android/app/LoaderManager.java b/core/java/android/app/LoaderManager.java
    +index c14dec9..bedf31a 100644
    +--- a/core/java/android/app/LoaderManager.java
    ++++ b/core/java/android/app/LoaderManager.java
    +@@ -195,6 +195,9 @@ public abstract class LoaderManager {
    +     public static void enableDebugLogging(boolean enabled) {
    +         LoaderManagerImpl.DEBUG = enabled;
    +     }
    ++
    ++    /** @hide for internal testing only */
    ++    public FragmentHostCallback getFragmentHostCallback() { return null; }
    + }
    + 
    + class LoaderManagerImpl extends LoaderManager {
    +@@ -542,6 +545,10 @@ class LoaderManagerImpl extends LoaderManager {
    +     void updateHostController(FragmentHostCallback host) {
    +         mHost = host;
    +     }
    ++
    ++    public FragmentHostCallback getFragmentHostCallback() {
    ++        return mHost;
    ++    }
    +     
    +     private LoaderInfo createLoader(int id, Bundle args,
    +             LoaderManager.LoaderCallbacks<Object> callback) {
    +diff --git a/core/java/android/app/LocalActivityManager.java b/core/java/android/app/LocalActivityManager.java
    +index 2a1e3c2..3b273bc 100644
    +--- a/core/java/android/app/LocalActivityManager.java
    ++++ b/core/java/android/app/LocalActivityManager.java
    +@@ -314,7 +314,7 @@ public class LocalActivityManager {
    +                     ArrayList<ReferrerIntent> intents = new ArrayList<>(1);
    +                     intents.add(new ReferrerIntent(intent, mParent.getPackageName()));
    +                     if (localLOGV) Log.v(TAG, r.id + ": new intent");
    +-                    mActivityThread.performNewIntents(r, intents);
    ++                    mActivityThread.performNewIntents(r, intents, false /* andPause */);
    +                     r.intent = intent;
    +                     moveToState(r, mCurState);
    +                     if (mSingleMode) {
    +diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java
    +index 29ed97e..0dd9c63 100644
    +--- a/core/java/android/app/Notification.java
    ++++ b/core/java/android/app/Notification.java
    +@@ -19,6 +19,7 @@ package android.app;
    + import android.annotation.ColorInt;
    + import android.annotation.DrawableRes;
    + import android.annotation.IntDef;
    ++import android.annotation.NonNull;
    + import android.annotation.SdkConstant;
    + import android.annotation.SdkConstant.SdkConstantType;
    + import android.annotation.SystemApi;
    +@@ -1048,6 +1049,7 @@ public class Notification implements Parcelable
    +             this(Icon.createWithResource("", icon), title, intent, new Bundle(), null, false);
    +         }
    + 
    ++        /** Keep in sync with {@link Notification.Action.Builder#Builder(Action)}! */
    +         private Action(Icon icon, CharSequence title, PendingIntent intent, Bundle extras,
    +                 RemoteInput[] remoteInputs, boolean allowGeneratedReplies) {
    +             this.mIcon = icon;
    +@@ -1114,7 +1116,7 @@ public class Notification implements Parcelable
    +              */
    +             @Deprecated
    +             public Builder(int icon, CharSequence title, PendingIntent intent) {
    +-                this(Icon.createWithResource("", icon), title, intent, new Bundle(), null);
    ++                this(Icon.createWithResource("", icon), title, intent);
    +             }
    + 
    +             /**
    +@@ -1124,7 +1126,7 @@ public class Notification implements Parcelable
    +              * @param intent the {@link PendingIntent} to fire when users trigger this action
    +              */
    +             public Builder(Icon icon, CharSequence title, PendingIntent intent) {
    +-                this(icon, title, intent, new Bundle(), null);
    ++                this(icon, title, intent, new Bundle(), null, false);
    +             }
    + 
    +             /**
    +@@ -1133,12 +1135,13 @@ public class Notification implements Parcelable
    +              * @param action the action to read fields from.
    +              */
    +             public Builder(Action action) {
    +-                this(action.getIcon(), action.title, action.actionIntent, new Bundle(action.mExtras),
    +-                        action.getRemoteInputs());
    ++                this(action.getIcon(), action.title, action.actionIntent,
    ++                        new Bundle(action.mExtras), action.getRemoteInputs(),
    ++                        action.getAllowGeneratedReplies());
    +             }
    + 
    +             private Builder(Icon icon, CharSequence title, PendingIntent intent, Bundle extras,
    +-                    RemoteInput[] remoteInputs) {
    ++                    RemoteInput[] remoteInputs, boolean allowGeneratedReplies) {
    +                 mIcon = icon;
    +                 mTitle = title;
    +                 mIntent = intent;
    +@@ -1147,6 +1150,7 @@ public class Notification implements Parcelable
    +                     mRemoteInputs = new ArrayList<RemoteInput>(remoteInputs.length);
    +                     Collections.addAll(mRemoteInputs, remoteInputs);
    +                 }
    ++                mAllowGeneratedReplies = allowGeneratedReplies;
    +             }
    + 
    +             /**
    +@@ -1229,7 +1233,7 @@ public class Notification implements Parcelable
    +                     getIcon(),
    +                     title,
    +                     actionIntent, // safe to alias
    +-                    new Bundle(mExtras),
    ++                    mExtras == null ? new Bundle() : new Bundle(mExtras),
    +                     getRemoteInputs(),
    +                     getAllowGeneratedReplies());
    +         }
    +@@ -4649,12 +4653,12 @@ public class Notification implements Parcelable
    +         }
    + 
    +         /**
    +-         * @param userDisplayName the name to be displayed for any replies sent by the user before the
    +-         * posting app reposts the notification with those messages after they've been actually
    +-         * sent and in previous messages sent by the user added in
    ++         * @param userDisplayName Required - the name to be displayed for any replies sent by the
    ++         * user before the posting app reposts the notification with those messages after they've
    ++         * been actually sent and in previous messages sent by the user added in
    +          * {@link #addMessage(Notification.MessagingStyle.Message)}
    +          */
    +-        public MessagingStyle(CharSequence userDisplayName) {
    ++        public MessagingStyle(@NonNull CharSequence userDisplayName) {
    +             mUserDisplayName = userDisplayName;
    +         }
    + 
    +diff --git a/core/java/android/app/ResourcesManager.java b/core/java/android/app/ResourcesManager.java
    +index d2e0327..5cc064e 100644
    +--- a/core/java/android/app/ResourcesManager.java
    ++++ b/core/java/android/app/ResourcesManager.java
    +@@ -839,19 +839,22 @@ public class ResourcesManager {
    +                             tmpConfig = new Configuration();
    +                         }
    +                         tmpConfig.setTo(config);
    ++
    ++                        // Get new DisplayMetrics based on the DisplayAdjustments given
    ++                        // to the ResourcesImpl. Update a copy if the CompatibilityInfo
    ++                        // changed, because the ResourcesImpl object will handle the
    ++                        // update internally.
    ++                        DisplayAdjustments daj = r.getDisplayAdjustments();
    ++                        if (compat != null) {
    ++                            daj = new DisplayAdjustments(daj);
    ++                            daj.setCompatibilityInfo(compat);
    ++                        }
    ++                        dm = getDisplayMetrics(displayId, daj);
    ++
    +                         if (!isDefaultDisplay) {
    +-                            // Get new DisplayMetrics based on the DisplayAdjustments given
    +-                            // to the ResourcesImpl. Udate a copy if the CompatibilityInfo
    +-                            // changed, because the ResourcesImpl object will handle the
    +-                            // update internally.
    +-                            DisplayAdjustments daj = r.getDisplayAdjustments();
    +-                            if (compat != null) {
    +-                                daj = new DisplayAdjustments(daj);
    +-                                daj.setCompatibilityInfo(compat);
    +-                            }
    +-                            dm = getDisplayMetrics(displayId, daj);
    +                             applyNonDefaultDisplayMetricsToConfiguration(dm, tmpConfig);
    +                         }
    ++
    +                         if (hasOverrideConfiguration) {
    +                             tmpConfig.updateFrom(key.mOverrideConfiguration);
    +                         }
    +diff --git a/core/java/android/app/TimePickerDialog.java b/core/java/android/app/TimePickerDialog.java
    +index aca0763..3f467a0 100644
    +--- a/core/java/android/app/TimePickerDialog.java
    ++++ b/core/java/android/app/TimePickerDialog.java
    +@@ -16,6 +16,7 @@
    + 
    + package android.app;
    + 
    ++import android.annotation.TestApi;
    + import android.content.Context;
    + import android.content.DialogInterface;
    + import android.content.DialogInterface.OnClickListener;
    +@@ -91,6 +92,12 @@ public class TimePickerDialog extends AlertDialog implements OnClickListener,
    + 
    +     /**
    +      * Creates a new time picker dialog with the specified theme.
    ++     * <p>
    ++     * The theme is overlaid on top of the theme of the parent {@code context}.
    ++     * If {@code themeResId} is 0, the dialog will be inflated using the theme
    ++     * specified by the
    ++     * {@link android.R.attr#timePickerDialogTheme android:timePickerDialogTheme}
    ++     * attribute on the parent {@code context}'s theme.
    +      *
    +      * @param context the parent context
    +      * @param themeResId the resource ID of the theme to apply to this dialog
    +@@ -109,11 +116,6 @@ public class TimePickerDialog extends AlertDialog implements OnClickListener,
    +         mIs24HourView = is24HourView;
    + 
    +         final Context themeContext = getContext();
    +-
    +-
    +-        final TypedValue outValue = new TypedValue();
    +-        context.getTheme().resolveAttribute(R.attr.timePickerDialogTheme, outValue, true);
    +-
    +         final LayoutInflater inflater = LayoutInflater.from(themeContext);
    +         final View view = inflater.inflate(R.layout.time_picker_dialog, null);
    +         setView(view);
    +@@ -128,6 +130,15 @@ public class TimePickerDialog extends AlertDialog implements OnClickListener,
    +         mTimePicker.setOnTimeChangedListener(this);
    +     }
    + 
    ++    /**
    ++     * @return the time picker displayed in the dialog
    ++     * @hide For testing only.
    ++     */
    ++    @TestApi
    ++    public TimePicker getTimePicker() {
    ++        return mTimePicker;
    ++    }
    ++
    +     @Override
    +     public void onTimeChanged(TimePicker view, int hourOfDay, int minute) {
    +         /* do nothing */
    +diff --git a/core/java/android/app/WallpaperManager.java b/core/java/android/app/WallpaperManager.java
    +index 219afea..aa0eaae 100644
    +--- a/core/java/android/app/WallpaperManager.java
    ++++ b/core/java/android/app/WallpaperManager.java
    +@@ -910,7 +910,7 @@ public class WallpaperManager {
    +      * wallpaper.
    +      */
    +     public void setResource(@RawRes int resid) throws IOException {
    +-        setResource(resid, FLAG_SYSTEM);
    ++        setResource(resid, FLAG_SYSTEM | FLAG_LOCK);
    +     }
    + 
    +     /**
    +@@ -1016,7 +1016,7 @@ public class WallpaperManager {
    +      */
    +     public int setBitmap(Bitmap fullImage, Rect visibleCropHint, boolean allowBackup)
    +             throws IOException {
    +-        return setBitmap(fullImage, visibleCropHint, allowBackup, FLAG_SYSTEM);
    ++        return setBitmap(fullImage, visibleCropHint, allowBackup, FLAG_SYSTEM | FLAG_LOCK);
    +     }
    + 
    +     /**
    +@@ -1154,7 +1154,7 @@ public class WallpaperManager {
    +      */
    +     public int setStream(InputStream bitmapData, Rect visibleCropHint, boolean allowBackup)
    +             throws IOException {
    +-        return setStream(bitmapData, visibleCropHint, allowBackup, FLAG_SYSTEM);
    ++        return setStream(bitmapData, visibleCropHint, allowBackup, FLAG_SYSTEM | FLAG_LOCK);
    +     }
    + 
    +     /**
    +@@ -1393,6 +1393,7 @@ public class WallpaperManager {
    +      */
    +     @SystemApi
    +     public void clearWallpaper() {
    ++        clearWallpaper(FLAG_LOCK, mContext.getUserId());
    +         clearWallpaper(FLAG_SYSTEM, mContext.getUserId());
    +     }
    + 
    +diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
    +index 2a12ac8..a2f9bdd 100644
    +--- a/core/java/android/app/admin/DevicePolicyManager.java
    ++++ b/core/java/android/app/admin/DevicePolicyManager.java
    +@@ -417,6 +417,14 @@ public class DevicePolicyManager {
    +     public static final int NOTIFICATION_BUGREPORT_FINISHED_NOT_ACCEPTED = 3;
    + 
    +     /**
    ++     * Default and maximum timeout in milliseconds after which unlocking with weak auth times out,
    ++     * i.e. the user has to use a strong authentication method like password, PIN or pattern.
    ++     *
    ++     * @hide
    ++     */
    ++    public static final long DEFAULT_STRONG_AUTH_TIMEOUT_MS = 72 * 60 * 60 * 1000; // 72h
    ++
    ++    /**
    +      * A {@link android.os.Parcelable} extra of type {@link android.os.PersistableBundle} that
    +      * allows a mobile device management application or NFC programmer application which starts
    +      * managed provisioning to pass data to the management application instance after provisioning.
    +@@ -1276,6 +1284,33 @@ public class DevicePolicyManager {
    +     public static final int PASSWORD_QUALITY_MANAGED = 0x80000;
    + 
    +     /**
    ++     * @hide
    ++     *
    ++     * adb shell dpm set-{device,profile}-owner will normally not allow installing an owner to
    ++     * a user with accounts.  {@link #ACCOUNT_FEATURE_DEVICE_OR_PROFILE_OWNER_ALLOWED}
    ++     * and {@link #ACCOUNT_FEATURE_DEVICE_OR_PROFILE_OWNER_DISALLOWED} are the account features
    ++     * used by authenticator to exempt their accounts from this:
    ++     *
    ++     * <ul>
    ++     *     <li>Non-test-only DO/PO still can't be installed when there are accounts.
    ++     *     <p>In order to make an apk test-only, add android:testOnly="true" to the
    ++     *     &lt;application&gt; tag in the manifest.
    ++     *
    ++     *     <li>Test-only DO/PO can be installed even when there are accounts, as long as all the
    ++     *     accounts have the {@link #ACCOUNT_FEATURE_DEVICE_OR_PROFILE_OWNER_ALLOWED} feature.
    ++     *     Some authenticators claim to have any features, so to detect it, we also check
    ++     *     {@link #ACCOUNT_FEATURE_DEVICE_OR_PROFILE_OWNER_DISALLOWED} and disallow installing
    ++     *     if any of the accounts have it.
    ++     * </ul>
    ++     */
    ++    public static final String ACCOUNT_FEATURE_DEVICE_OR_PROFILE_OWNER_ALLOWED =
    ++            "android.account.DEVICE_OR_PROFILE_OWNER_ALLOWED";
    ++
    ++    /** @hide See {@link #ACCOUNT_FEATURE_DEVICE_OR_PROFILE_OWNER_ALLOWED} */
    ++    public static final String ACCOUNT_FEATURE_DEVICE_OR_PROFILE_OWNER_DISALLOWED =
    ++            "android.account.DEVICE_OR_PROFILE_OWNER_DISALLOWED";
    ++
    ++    /**
    +      * Called by an application that is administering the device to set the password restrictions it
    +      * is imposing. After setting this, the user will not be able to enter a new password that is
    +      * not at least as restrictive as what has been set. Note that the current password will remain
    +@@ -2219,6 +2254,7 @@ public class DevicePolicyManager {
    +      * @throws SecurityException if the calling application does not own an active administrator
    +      *             that uses {@link DeviceAdminInfo#USES_POLICY_RESET_PASSWORD}
    +      * @throws IllegalStateException if the calling user is locked or has a managed profile.
    ++     * @throws IllegalArgumentException if the password does not meet system requirements.
    +      */
    +     public boolean resetPassword(String password, int flags) {
    +         throwIfParentInstance("resetPassword");
    +@@ -2308,6 +2344,83 @@ public class DevicePolicyManager {
    +     }
    + 
    +     /**
    ++     * Called by a device/profile owner to set the timeout after which unlocking with secondary, non
    ++     * strong auth (e.g. fingerprint, trust agents) times out, i.e. the user has to use a strong
    ++     * authentication method like password, pin or pattern.
    ++     *
    ++     * <p>This timeout is used internally to reset the timer to require strong auth again after
    ++     * specified timeout each time it has been successfully used.
    ++     *
    ++     * <p>Fingerprint can also be disabled altogether using {@link #KEYGUARD_DISABLE_FINGERPRINT}.
    ++     *
    ++     * <p>Trust agents can also be disabled altogether using {@link #KEYGUARD_DISABLE_TRUST_AGENTS}.
    ++     *
    ++     * <p>The calling device admin must be a device or profile owner. If it is not,
    ++     * a {@link SecurityException} will be thrown.
    ++     *
    ++     * <p>The calling device admin can verify the value it has set by calling
    ++     * {@link #getRequiredStrongAuthTimeout(ComponentName)} and passing in its instance.
    ++     *
    ++     * <p>This method can be called on the {@link DevicePolicyManager} instance returned by
    ++     * {@link #getParentProfileInstance(ComponentName)} in order to set restrictions on the parent
    ++     * profile.
    ++     *
    ++     * @param admin Which {@link DeviceAdminReceiver} this request is associated with.
    ++     * @param timeoutMs The new timeout, after which the user will have to unlock with strong
    ++     *         authentication method. A value of 0 means the admin is not participating in
    ++     *         controlling the timeout.
    ++     *         The minimum and maximum timeouts are platform-defined and are typically 1 hour and
    ++     *         72 hours, respectively. Though discouraged, the admin may choose to require strong
    ++     *         auth at all times using {@link #KEYGUARD_DISABLE_FINGERPRINT} and/or
    ++     *         {@link #KEYGUARD_DISABLE_TRUST_AGENTS}.
    ++     *
    ++     * @throws SecurityException if {@code admin} is not a device or profile owner.
    ++     *
    ++     * @hide
    ++     */
    ++    public void setRequiredStrongAuthTimeout(@NonNull ComponentName admin,
    ++            long timeoutMs) {
    ++        if (mService != null) {
    ++            try {
    ++                mService.setRequiredStrongAuthTimeout(admin, timeoutMs, mParentInstance);
    ++            } catch (RemoteException e) {
    ++                throw e.rethrowFromSystemServer();
    ++            }
    ++        }
    ++    }
    ++
    ++    /**
    ++     * Determine for how long the user will be able to use secondary, non strong auth for
    ++     * authentication, since last strong method authentication (password, pin or pattern) was used.
    ++     * After the returned timeout the user is required to use strong authentication method.
    ++     *
    ++     * <p>This method can be called on the {@link DevicePolicyManager} instance
    ++     * returned by {@link #getParentProfileInstance(ComponentName)} in order to retrieve
    ++     * restrictions on the parent profile.
    ++     *
    ++     * @param admin The name of the admin component to check, or {@code null} to aggregate
    ++     *         accross all participating admins.
    ++     * @return The timeout or 0 if not configured for the provided admin.
    ++     *
    ++     * @hide
    ++     */
    ++    public long getRequiredStrongAuthTimeout(@Nullable ComponentName admin) {
    ++        return getRequiredStrongAuthTimeout(admin, myUserId());
    ++    }
    ++
    ++    /** @hide per-user version */
    ++    public long getRequiredStrongAuthTimeout(@Nullable ComponentName admin, @UserIdInt int userId) {
    ++        if (mService != null) {
    ++            try {
    ++                return mService.getRequiredStrongAuthTimeout(admin, userId, mParentInstance);
    ++            } catch (RemoteException e) {
    ++                throw e.rethrowFromSystemServer();
    ++            }
    ++        }
    ++        return DEFAULT_STRONG_AUTH_TIMEOUT_MS;
    ++    }
    ++
    ++    /**
    +      * Make the device lock immediately, as if the lock screen timeout has expired at the point of
    +      * this call.
    +      * <p>
    +@@ -6465,4 +6578,35 @@ public class DevicePolicyManager {
    +             throw new SecurityException(functionName + " cannot be called on the parent instance");
    +         }
    +     }
    ++
    ++    /**
    ++     * @hide
    ++     * Enable backup service.
    ++     * <p>This includes all backup and restore mechanisms.
    ++     * Setting this to {@code false} will make backup service no-op or return empty results.
    ++     *
    ++     * <p>There must be only one user on the device, managed by the device owner.
    ++     * Otherwise a {@link SecurityException} will be thrown.
    ++     *
    ++     * <p>Backup service is off by default when device owner is present.
    ++     */
    ++    public void setBackupServiceEnabled(@NonNull ComponentName admin, boolean enabled) {
    ++        try {
    ++            mService.setBackupServiceEnabled(admin, enabled);
    ++        } catch (RemoteException re) {
    ++            throw re.rethrowFromSystemServer();
    ++        }
    ++    }
    ++
    ++    /**
    ++     * @hide
    ++     * @return {@code true} if backup service is enabled, {@code false} otherwise.
    ++     */
    ++    public boolean isBackupServiceEnabled(@NonNull ComponentName admin) {
    ++        try {
    ++            return mService.isBackupServiceEnabled(admin);
    ++        } catch (RemoteException re) {
    ++            throw re.rethrowFromSystemServer();
    ++        }
    ++    }
    + }
    +diff --git a/core/java/android/app/admin/IDevicePolicyManager.aidl b/core/java/android/app/admin/IDevicePolicyManager.aidl
    +index 1036f04..f39cb5a 100644
    +--- a/core/java/android/app/admin/IDevicePolicyManager.aidl
    ++++ b/core/java/android/app/admin/IDevicePolicyManager.aidl
    +@@ -82,6 +82,9 @@ interface IDevicePolicyManager {
    +     long getMaximumTimeToLock(in ComponentName who, int userHandle, boolean parent);
    +     long getMaximumTimeToLockForUserAndProfiles(int userHandle);
    + 
    ++    void setRequiredStrongAuthTimeout(in ComponentName who, long timeMs, boolean parent);
    ++    long getRequiredStrongAuthTimeout(in ComponentName who, int userId, boolean parent);
    ++
    +     void lockNow(boolean parent);
    + 
    +     void wipeData(int flags);
    +@@ -305,4 +308,7 @@ interface IDevicePolicyManager {
    +     boolean isDeviceProvisioned();
    +     boolean isDeviceProvisioningConfigApplied();
    +     void setDeviceProvisioningConfigApplied();
    ++
    ++    void setBackupServiceEnabled(in ComponentName admin, boolean enabled);
    ++    boolean isBackupServiceEnabled(in ComponentName admin);
    + }
    +diff --git a/core/java/android/app/backup/BackupAgent.java b/core/java/android/app/backup/BackupAgent.java
    +index bc82806..bad6325 100644
    +--- a/core/java/android/app/backup/BackupAgent.java
    ++++ b/core/java/android/app/backup/BackupAgent.java
    +@@ -35,6 +35,8 @@ import android.system.StructStat;
    + import android.util.ArraySet;
    + import android.util.Log;
    + 
    ++import libcore.io.IoUtils;
    ++
    + import org.xmlpull.v1.XmlPullParserException;
    + 
    + import java.io.File;
    +@@ -647,10 +649,11 @@ public abstract class BackupAgent extends ContextWrapper {
    +                 File file = scanQueue.remove(0);
    +                 String filePath;
    +                 try {
    +-                    // Ignore symlinks outright
    ++                    // Ignore things that aren't "real" files or dirs
    +                     StructStat stat = Os.lstat(file.getPath());
    +-                    if (OsConstants.S_ISLNK(stat.st_mode)) {
    +-                        if (DEBUG) Log.i(TAG, "Symlink (skipping)!: " + file);
    ++                    if (!OsConstants.S_ISREG(stat.st_mode)
    ++                            && !OsConstants.S_ISDIR(stat.st_mode)) {
    ++                        if (DEBUG) Log.i(TAG, "Not a file/dir (skipping)!: " + file);
    +                         continue;
    +                     }
    + 
    +@@ -921,6 +924,13 @@ public abstract class BackupAgent extends ContextWrapper {
    +                 } catch (RemoteException e) {
    +                     // we'll time out anyway, so we're safe
    +                 }
    ++
    ++                // Don't close the fd out from under the system service if this was local
    ++                if (Binder.getCallingPid() != Process.myPid()) {
    ++                    IoUtils.closeQuietly(oldState);
    ++                    IoUtils.closeQuietly(data);
    ++                    IoUtils.closeQuietly(newState);
    ++                }
    +             }
    +         }
    + 
    +@@ -951,6 +961,11 @@ public abstract class BackupAgent extends ContextWrapper {
    +                 } catch (RemoteException e) {
    +                     // we'll time out anyway, so we're safe
    +                 }
    ++
    ++                if (Binder.getCallingPid() != Process.myPid()) {
    ++                    IoUtils.closeQuietly(data);
    ++                    IoUtils.closeQuietly(newState);
    ++                }
    +             }
    +         }
    + 
    +@@ -994,6 +1009,10 @@ public abstract class BackupAgent extends ContextWrapper {
    +                 } catch (RemoteException e) {
    +                     // we'll time out anyway, so we're safe
    +                 }
    ++
    ++                if (Binder.getCallingPid() != Process.myPid()) {
    ++                    IoUtils.closeQuietly(data);
    ++                }
    +             }
    +         }
    + 
    +@@ -1041,6 +1060,10 @@ public abstract class BackupAgent extends ContextWrapper {
    +                 } catch (RemoteException e) {
    +                     // we'll time out anyway, so we're safe
    +                 }
    ++
    ++                if (Binder.getCallingPid() != Process.myPid()) {
    ++                    IoUtils.closeQuietly(data);
    ++                }
    +             }
    +         }
    + 
    +diff --git a/core/java/android/app/backup/BackupManager.java b/core/java/android/app/backup/BackupManager.java
    +index 7fcca09..80bc136 100644
    +--- a/core/java/android/app/backup/BackupManager.java
    ++++ b/core/java/android/app/backup/BackupManager.java
    +@@ -128,6 +128,14 @@ public class BackupManager {
    +     @SystemApi
    +     public static final int ERROR_AGENT_FAILURE = BackupTransport.AGENT_ERROR;
    + 
    ++    /**
    ++     * Intent extra when any subsidiary backup-related UI is launched from Settings:  does
    ++     * device policy or configuration permit backup operations to run at all?
    ++     *
    ++     * @hide
    ++     */
    ++    public static final String EXTRA_BACKUP_SERVICES_AVAILABLE = "backup_services_available";
    ++
    +     private Context mContext;
    +     private static IBackupManager sService;
    + 
    +diff --git a/core/java/android/app/package.html b/core/java/android/app/package.html
    +index f37f1dc..b259cad 100644
    +--- a/core/java/android/app/package.html
    ++++ b/core/java/android/app/package.html
    +@@ -34,7 +34,7 @@ action bar.</p>
    + <p>For information about using some the classes in this package, see the following
    + documents: <a href="{@docRoot}guide/topics/fundamentals/activities.html">Activities</a>, <a
    + href="{@docRoot}guide/topics/fundamentals/services.html">Services</a>, <a
    +-href="{@docRoot}guide/topics/fundamentals/fragments.html">Fragments</a>, <a
    ++href="{@docRoot}guide/components/fragments.html">Fragments</a>, <a
    + href="{@docRoot}guide/topics/ui/actionbar.html">Using the Action Bar</a>, <a
    + href="{@docRoot}guide/topics/ui/dialogs.html">Creating Dialogs</a>, and <a
    + href="{@docRoot}guide/topics/ui/notifiers/index.html">Notifying the User</a>.</p>
    +diff --git a/core/java/android/bluetooth/BluetoothAdapter.java b/core/java/android/bluetooth/BluetoothAdapter.java
    +index 246a752..50c8e27 100644
    +--- a/core/java/android/bluetooth/BluetoothAdapter.java
    ++++ b/core/java/android/bluetooth/BluetoothAdapter.java
    +@@ -765,19 +765,13 @@ public final class BluetoothAdapter {
    +     public boolean enableBLE() {
    +         if (!isBleScanAlwaysAvailable()) return false;
    + 
    +-        if (isLeEnabled() == true) {
    +-            if (DBG) Log.d(TAG, "enableBLE(): BT is already enabled..!");
    +-            try {
    +-                mManagerService.updateBleAppCount(mToken, true);
    +-            } catch (RemoteException e) {
    +-                Log.e(TAG, "", e);
    +-            }
    +-            return true;
    +-        }
    +-
    +         try {
    +-            if (DBG) Log.d(TAG, "Calling enableBLE");
    +             mManagerService.updateBleAppCount(mToken, true);
    ++            if (isLeEnabled()) {
    ++                if (DBG) Log.d(TAG, "enableBLE(): Bluetooth already enabled");
    ++                return true;
    ++            }
    ++            if (DBG) Log.d(TAG, "enableBLE(): Calling enable");
    +             return mManagerService.enable();
    +         } catch (RemoteException e) {
    +             Log.e(TAG, "", e);
    +@@ -2006,7 +2000,7 @@ public final class BluetoothAdapter {
    +     final private IBluetoothManagerCallback mManagerCallback =
    +         new IBluetoothManagerCallback.Stub() {
    +             public void onBluetoothServiceUp(IBluetooth bluetoothService) {
    +-                if (VDBG) Log.d(TAG, "onBluetoothServiceUp: " + bluetoothService);
    ++                if (DBG) Log.d(TAG, "onBluetoothServiceUp: " + bluetoothService);
    + 
    +                 mServiceLock.writeLock().lock();
    +                 mService = bluetoothService;
    +@@ -2028,7 +2022,7 @@ public final class BluetoothAdapter {
    +             }
    + 
    +             public void onBluetoothServiceDown() {
    +-                if (VDBG) Log.d(TAG, "onBluetoothServiceDown: " + mService);
    ++                if (DBG) Log.d(TAG, "onBluetoothServiceDown: " + mService);
    + 
    +                 try {
    +                     mServiceLock.writeLock().lock();
    +@@ -2056,7 +2050,7 @@ public final class BluetoothAdapter {
    +             }
    + 
    +             public void onBrEdrDown() {
    +-                if (VDBG) Log.i(TAG, "on QBrEdrDown: ");
    ++                if (DBG) Log.i(TAG, "onBrEdrDown:");
    +             }
    +     };
    + 
    +diff --git a/core/java/android/bluetooth/BluetoothDevice.java b/core/java/android/bluetooth/BluetoothDevice.java
    +index 6d6dfeb..cd5eff2 100644
    +--- a/core/java/android/bluetooth/BluetoothDevice.java
    ++++ b/core/java/android/bluetooth/BluetoothDevice.java
    +@@ -1596,7 +1596,7 @@ public final class BluetoothDevice implements Parcelable {
    +                 // BLE is not supported
    +                 return null;
    +             }
    +-            BluetoothGatt gatt = new BluetoothGatt(context, iGatt, this, transport);
    ++            BluetoothGatt gatt = new BluetoothGatt(iGatt, this, transport);
    +             gatt.connect(autoConnect, callback);
    +             return gatt;
    +         } catch (RemoteException e) {Log.e(TAG, "", e);}
    +diff --git a/core/java/android/bluetooth/BluetoothGatt.java b/core/java/android/bluetooth/BluetoothGatt.java
    +index 800dd43..552c8d3 100644
    +--- a/core/java/android/bluetooth/BluetoothGatt.java
    ++++ b/core/java/android/bluetooth/BluetoothGatt.java
    +@@ -41,7 +41,6 @@ public final class BluetoothGatt implements BluetoothProfile {
    +     private static final boolean DBG = true;
    +     private static final boolean VDBG = false;
    + 
    +-    private final Context mContext;
    +     private IBluetoothGatt mService;
    +     private BluetoothGattCallback mCallback;
    +     private int mClientIf;
    +@@ -496,9 +495,8 @@ public final class BluetoothGatt implements BluetoothProfile {
    +             }
    +         };
    + 
    +-    /*package*/ BluetoothGatt(Context context, IBluetoothGatt iGatt, BluetoothDevice device,
    ++    /*package*/ BluetoothGatt(IBluetoothGatt iGatt, BluetoothDevice device,
    +                                 int transport) {
    +-        mContext = context;
    +         mService = iGatt;
    +         mDevice = device;
    +         mTransport = transport;
    +diff --git a/core/java/android/bluetooth/BluetoothGattServer.java b/core/java/android/bluetooth/BluetoothGattServer.java
    +index f451340..9f8d1a7 100644
    +--- a/core/java/android/bluetooth/BluetoothGattServer.java
    ++++ b/core/java/android/bluetooth/BluetoothGattServer.java
    +@@ -44,7 +44,6 @@ public final class BluetoothGattServer implements BluetoothProfile {
    +     private static final boolean DBG = true;
    +     private static final boolean VDBG = false;
    + 
    +-    private final Context mContext;
    +     private BluetoothAdapter mAdapter;
    +     private IBluetoothGatt mService;
    +     private BluetoothGattServerCallback mCallback;
    +@@ -307,8 +306,7 @@ public final class BluetoothGattServer implements BluetoothProfile {
    +     /**
    +      * Create a BluetoothGattServer proxy object.
    +      */
    +-    /*package*/ BluetoothGattServer(Context context, IBluetoothGatt iGatt, int transport) {
    +-        mContext = context;
    ++    /*package*/ BluetoothGattServer(IBluetoothGatt iGatt, int transport) {
    +         mService = iGatt;
    +         mAdapter = BluetoothAdapter.getDefaultAdapter();
    +         mCallback = null;
    +diff --git a/core/java/android/bluetooth/BluetoothHealthAppConfiguration.java b/core/java/android/bluetooth/BluetoothHealthAppConfiguration.java
    +index 15a9101..1717a1e 100644
    +--- a/core/java/android/bluetooth/BluetoothHealthAppConfiguration.java
    ++++ b/core/java/android/bluetooth/BluetoothHealthAppConfiguration.java
    +@@ -68,7 +68,9 @@ public final class BluetoothHealthAppConfiguration implements Parcelable {
    +     public boolean equals(Object o) {
    +         if (o instanceof BluetoothHealthAppConfiguration) {
    +             BluetoothHealthAppConfiguration config = (BluetoothHealthAppConfiguration) o;
    +-            // config.getName() can never be NULL
    ++
    ++            if (mName == null) return false;
    ++
    +             return mName.equals(config.getName()) &&
    +                     mDataType == config.getDataType() &&
    +                     mRole == config.getRole() &&
    +diff --git a/core/java/android/bluetooth/BluetoothManager.java b/core/java/android/bluetooth/BluetoothManager.java
    +index 00058a9..29283e7 100644
    +--- a/core/java/android/bluetooth/BluetoothManager.java
    ++++ b/core/java/android/bluetooth/BluetoothManager.java
    +@@ -236,7 +236,7 @@ public final class BluetoothManager {
    +                 Log.e(TAG, "Fail to get GATT Server connection");
    +                 return null;
    +             }
    +-            BluetoothGattServer mGattServer = new BluetoothGattServer(context, iGatt,transport);
    ++            BluetoothGattServer mGattServer = new BluetoothGattServer(iGatt,transport);
    +             Boolean regStatus = mGattServer.registerCallback(callback);
    +             return regStatus? mGattServer : null;
    +         } catch (RemoteException e) {
    +diff --git a/core/java/android/content/ContentResolver.java b/core/java/android/content/ContentResolver.java
    +index b3320d6..daa1b93 100644
    +--- a/core/java/android/content/ContentResolver.java
    ++++ b/core/java/android/content/ContentResolver.java
    +@@ -1877,6 +1877,7 @@ public abstract class ContentResolver {
    +         if (extras != null) {
    +             String accountName = extras.getString(SYNC_EXTRAS_ACCOUNT);
    +             if (!TextUtils.isEmpty(accountName)) {
    ++                // TODO: No references to Google in AOSP
    +                 account = new Account(accountName, "com.google");
    +             }
    +             extras.remove(SYNC_EXTRAS_ACCOUNT);
    +diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
    +index 3f18ea9..3a2f471 100644
    +--- a/core/java/android/content/Context.java
    ++++ b/core/java/android/content/Context.java
    +@@ -1130,7 +1130,9 @@ public abstract class Context {
    +      * <strong>Note: you should not <em>rely</em> on the system deleting these
    +      * files for you; you should always have a reasonable maximum, such as 1 MB,
    +      * for the amount of space you consume with cache files, and prune those
    +-     * files when exceeding that space.</strong>
    ++     * files when exceeding that space.</strong> If your app requires a larger
    ++     * cache (larger than 1 MB), you should use {@link #getExternalCacheDir()}
    ++     * instead.
    +      * <p>
    +      * The returned path may change over time if the calling app is moved to an
    +      * adopted storage device, so only relative paths should be persisted.
    +@@ -1142,6 +1144,7 @@ public abstract class Context {
    +      * @see #openFileOutput
    +      * @see #getFileStreamPath
    +      * @see #getDir
    ++     * @see #getExternalCacheDir
    +      */
    +     public abstract File getCacheDir();
    + 
    +@@ -1190,7 +1193,7 @@ public abstract class Context {
    +      * </ul>
    +      * <p>
    +      * If a shared storage device is emulated (as determined by
    +-     * {@link Environment#isExternalStorageEmulated(File)}), it's contents are
    ++     * {@link Environment#isExternalStorageEmulated(File)}), its contents are
    +      * backed by a private user data partition, which means there is little
    +      * benefit to storing data here instead of the private directory returned by
    +      * {@link #getCacheDir()}.
    +@@ -2761,8 +2764,10 @@ public abstract class Context {
    +      *  <dd> A {@link android.net.ConnectivityManager ConnectivityManager} for
    +      *  handling management of network connections.
    +      *  <dt> {@link #WIFI_SERVICE} ("wifi")
    +-     *  <dd> A {@link android.net.wifi.WifiManager WifiManager} for management of
    +-     * Wi-Fi connectivity.
    ++     *  <dd> A {@link android.net.wifi.WifiManager WifiManager} for management of Wi-Fi
    ++     *  connectivity.  On releases before NYC, it should only be obtained from an application
    ++     *  context, and not from any other derived context to avoid memory leaks within the calling
    ++     *  process.
    +      *  <dt> {@link #WIFI_P2P_SERVICE} ("wifip2p")
    +      *  <dd> A {@link android.net.wifi.p2p.WifiP2pManager WifiP2pManager} for management of
    +      * Wi-Fi Direct connectivity.
    +diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java
    +index 4d9db98..c6aaa48 100644
    +--- a/core/java/android/content/Intent.java
    ++++ b/core/java/android/content/Intent.java
    +@@ -128,7 +128,7 @@ import static android.content.ContentProvider.maybeAddUserId;
    +  *     a list of people, which the user can browse through.  This example is a
    +  *     typical top-level entry into the Contacts application, showing you the
    +  *     list of people. Selecting a particular person to view would result in a
    +- *     new intent { <b>{@link #ACTION_VIEW} <i>content://contacts/N</i></b> }
    ++ *     new intent { <b>{@link #ACTION_VIEW} <i>content://contacts/people/N</i></b> }
    +  *     being used to start an activity to display that person.</p>
    +  *   </li>
    +  * </ul>
    +@@ -4314,6 +4314,14 @@ public class Intent implements Parcelable, Cloneable {
    +     public static final int FLAG_DEBUG_TRIAGED_MISSING = 0x00000100;
    + 
    +     /**
    ++     * Internal flag used to indicate ephemeral applications should not be
    ++     * considered when resolving the intent.
    ++     *
    ++     * @hide
    ++     */
    ++    public static final int FLAG_IGNORE_EPHEMERAL = 0x00000200;
    ++
    ++    /**
    +      * If set, the new activity is not kept in the history stack.  As soon as
    +      * the user navigates away from it, the activity is finished.  This may also
    +      * be set with the {@link android.R.styleable#AndroidManifestActivity_noHistory
    +@@ -6565,7 +6573,7 @@ public class Intent implements Parcelable, Cloneable {
    +      */
    +     public void removeUnsafeExtras() {
    +         if (mExtras != null) {
    +-            mExtras.filterValues();
    ++            mExtras = mExtras.filterValues();
    +         }
    +     }
    + 
    +diff --git a/core/java/android/content/IntentFilter.java b/core/java/android/content/IntentFilter.java
    +index 22ab43b..f5a79c8 100644
    +--- a/core/java/android/content/IntentFilter.java
    ++++ b/core/java/android/content/IntentFilter.java
    +@@ -124,7 +124,7 @@ import java.util.Set;
    +  * <em>Note that authority matching here is <b>case sensitive</b>, unlike
    +  * formal RFC host names!</em>  You should thus always use lower case letters
    +  * for your authority.
    +- * 
    ++ *
    +  * <p><strong>Data Path</strong> matches if any of the given values match the
    +  * Intent's data path <em>and</em> both a scheme and authority in the filter
    +  * has matched against the Intent, <em>or</em> no paths were supplied in the
    +@@ -265,6 +265,7 @@ public class IntentFilter implements Parcelable {
    +     public static final String SCHEME_HTTPS = "https";
    + 
    +     private int mPriority;
    ++    private int mOrder;
    +     private final ArrayList<String> mActions;
    +     private ArrayList<String> mCategories = null;
    +     private ArrayList<String> mDataSchemes = null;
    +@@ -358,8 +359,8 @@ public class IntentFilter implements Parcelable {
    +      * the {@link MalformedMimeTypeException} exception that the constructor
    +      * can call and turns it into a runtime exception.
    +      *
    +-     * @param action The action to match, i.e. Intent.ACTION_VIEW.
    +-     * @param dataType The type to match, i.e. "vnd.android.cursor.dir/person".
    ++     * @param action The action to match, such as Intent.ACTION_VIEW.
    ++     * @param dataType The type to match, such as "vnd.android.cursor.dir/person".
    +      *
    +      * @return A new IntentFilter for the given action and type.
    +      *
    +@@ -386,7 +387,7 @@ public class IntentFilter implements Parcelable {
    +      * no data characteristics are subsequently specified, then the
    +      * filter will only match intents that contain no data.
    +      *
    +-     * @param action The action to match, i.e. Intent.ACTION_MAIN.
    ++     * @param action The action to match, such as Intent.ACTION_MAIN.
    +      */
    +     public IntentFilter(String action) {
    +         mPriority = 0;
    +@@ -406,8 +407,8 @@ public class IntentFilter implements Parcelable {
    +      * <p>Throws {@link MalformedMimeTypeException} if the given MIME type is
    +      * not syntactically correct.
    +      *
    +-     * @param action The action to match, i.e. Intent.ACTION_VIEW.
    +-     * @param dataType The type to match, i.e. "vnd.android.cursor.dir/person".
    ++     * @param action The action to match, such as Intent.ACTION_VIEW.
    ++     * @param dataType The type to match, such as "vnd.android.cursor.dir/person".
    +      *
    +      */
    +     public IntentFilter(String action, String dataType)
    +@@ -425,6 +426,7 @@ public class IntentFilter implements Parcelable {
    +      */
    +     public IntentFilter(IntentFilter o) {
    +         mPriority = o.mPriority;
    ++        mOrder = o.mOrder;
    +         mActions = new ArrayList<String>(o.mActions);
    +         if (o.mCategories != null) {
    +             mCategories = new ArrayList<String>(o.mCategories);
    +@@ -477,6 +479,16 @@ public class IntentFilter implements Parcelable {
    +         return mPriority;
    +     }
    + 
    ++    /** @hide */
    ++    public final void setOrder(int order) {
    ++        mOrder = order;
    ++    }
    ++
    ++    /** @hide */
    ++    public final int getOrder() {
    ++        return mOrder;
    ++    }
    ++
    +     /**
    +      * Set whether this filter will needs to be automatically verified against its data URIs or not.
    +      * The default is false.
    +@@ -640,7 +652,7 @@ public class IntentFilter implements Parcelable {
    +      * in the filter, then an Intent's action must be one of those values for
    +      * it to match.  If no actions are included, the Intent action is ignored.
    +      *
    +-     * @param action Name of the action to match, i.e. Intent.ACTION_VIEW.
    ++     * @param action Name of the action to match, such as Intent.ACTION_VIEW.
    +      */
    +     public final void addAction(String action) {
    +         if (!mActions.contains(action)) {
    +@@ -709,7 +721,7 @@ public class IntentFilter implements Parcelable {
    +      * <p>Throws {@link MalformedMimeTypeException} if the given MIME type is
    +      * not syntactically correct.
    +      *
    +-     * @param type Name of the data type to match, i.e. "vnd.android.cursor.dir/person".
    ++     * @param type Name of the data type to match, such as "vnd.android.cursor.dir/person".
    +      *
    +      * @see #matchData
    +      */
    +@@ -786,7 +798,7 @@ public class IntentFilter implements Parcelable {
    +      * and any schemes you receive from outside of Android should be
    +      * converted to lower case before supplying them here.</em></p>
    +      *
    +-     * @param scheme Name of the scheme to match, i.e. "http".
    ++     * @param scheme Name of the scheme to match, such as "http".
    +      *
    +      * @see #matchData
    +      */
    +@@ -897,7 +909,7 @@ public class IntentFilter implements Parcelable {
    +          * Determine whether this AuthorityEntry matches the given data Uri.
    +          * <em>Note that this comparison is case-sensitive, unlike formal
    +          * RFC host names.  You thus should always normalize to lower-case.</em>
    +-         * 
    ++         *
    +          * @param data The Uri to match.
    +          * @return Returns either {@link IntentFilter#NO_MATCH_DATA},
    +          * {@link IntentFilter#MATCH_CATEGORY_PORT}, or
    +@@ -1352,7 +1364,7 @@ public class IntentFilter implements Parcelable {
    +      * filter has no impact on matching unless that category is specified in
    +      * the intent.
    +      *
    +-     * @param category Name of category to match, i.e. Intent.CATEGORY_EMBED.
    ++     * @param category Name of category to match, such as Intent.CATEGORY_EMBED.
    +      */
    +     public final void addCategory(String category) {
    +         if (mCategories == null) mCategories = new ArrayList<String>();
    +diff --git a/core/java/android/content/SyncAdapterType.java b/core/java/android/content/SyncAdapterType.java
    +index 8a16ac9..6ef7fd2 100644
    +--- a/core/java/android/content/SyncAdapterType.java
    ++++ b/core/java/android/content/SyncAdapterType.java
    +@@ -16,6 +16,7 @@
    + 
    + package android.content;
    + 
    ++import android.annotation.Nullable;
    + import android.text.TextUtils;
    + import android.os.Parcelable;
    + import android.os.Parcel;
    +@@ -33,6 +34,7 @@ public class SyncAdapterType implements Parcelable {
    +     private final boolean isAlwaysSyncable;
    +     private final boolean allowParallelSyncs;
    +     private final String settingsActivity;
    ++    private final String packageName;
    + 
    +     public SyncAdapterType(String authority, String accountType, boolean userVisible,
    +             boolean supportsUploading) {
    +@@ -50,6 +52,7 @@ public class SyncAdapterType implements Parcelable {
    +         this.allowParallelSyncs = false;
    +         this.settingsActivity = null;
    +         this.isKey = false;
    ++        this.packageName = null;
    +     }
    + 
    +     /** @hide */
    +@@ -57,7 +60,8 @@ public class SyncAdapterType implements Parcelable {
    +             boolean supportsUploading,
    +             boolean isAlwaysSyncable,
    +             boolean allowParallelSyncs,
    +-            String settingsActivity) {
    ++            String settingsActivity,
    ++            String packageName) {
    +         if (TextUtils.isEmpty(authority)) {
    +             throw new IllegalArgumentException("the authority must not be empty: " + authority);
    +         }
    +@@ -72,6 +76,7 @@ public class SyncAdapterType implements Parcelable {
    +         this.allowParallelSyncs = allowParallelSyncs;
    +         this.settingsActivity = settingsActivity;
    +         this.isKey = false;
    ++        this.packageName = packageName;
    +     }
    + 
    +     private SyncAdapterType(String authority, String accountType) {
    +@@ -89,6 +94,7 @@ public class SyncAdapterType implements Parcelable {
    +         this.allowParallelSyncs = false;
    +         this.settingsActivity = null;
    +         this.isKey = true;
    ++        this.packageName = null;
    +     }
    + 
    +     public boolean supportsUploading() {
    +@@ -148,6 +154,16 @@ public class SyncAdapterType implements Parcelable {
    +         return settingsActivity;
    +     }
    + 
    ++    /**
    ++     * The package hosting the sync adapter.
    ++     * @return The package name.
    ++     *
    ++     * @hide
    ++     */
    ++    public @Nullable String getPackageName() {
    ++        return packageName;
    ++    }
    ++
    +     public static SyncAdapterType newKey(String authority, String accountType) {
    +         return new SyncAdapterType(authority, accountType);
    +     }
    +@@ -181,6 +197,7 @@ public class SyncAdapterType implements Parcelable {
    +                     + ", isAlwaysSyncable=" + isAlwaysSyncable
    +                     + ", allowParallelSyncs=" + allowParallelSyncs
    +                     + ", settingsActivity=" + settingsActivity
    ++                    + ", packageName=" + packageName
    +                     + "}";
    +         }
    +     }
    +@@ -201,6 +218,7 @@ public class SyncAdapterType implements Parcelable {
    +         dest.writeInt(isAlwaysSyncable ? 1 : 0);
    +         dest.writeInt(allowParallelSyncs ? 1 : 0);
    +         dest.writeString(settingsActivity);
    ++        dest.writeString(packageName);
    +     }
    + 
    +     public SyncAdapterType(Parcel source) {
    +@@ -211,6 +229,7 @@ public class SyncAdapterType implements Parcelable {
    +                 source.readInt() != 0,
    +                 source.readInt() != 0,
    +                 source.readInt() != 0,
    ++                source.readString(),
    +                 source.readString());
    +     }
    + 
    +diff --git a/core/java/android/content/SyncAdaptersCache.java b/core/java/android/content/SyncAdaptersCache.java
    +index 6704b75..ddbdb8a 100644
    +--- a/core/java/android/content/SyncAdaptersCache.java
    ++++ b/core/java/android/content/SyncAdaptersCache.java
    +@@ -81,7 +81,7 @@ public class SyncAdaptersCache extends RegisteredServicesCache<SyncAdapterType>
    +                     sa.getString(com.android.internal.R.styleable
    +                             .SyncAdapter_settingsActivity);
    +             return new SyncAdapterType(authority, accountType, userVisible, supportsUploading,
    +-                    isAlwaysSyncable, allowParallelSyncs, settingsActivity);
    ++                    isAlwaysSyncable, allowParallelSyncs, settingsActivity, packageName);
    +         } finally {
    +             sa.recycle();
    +         }
    +diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
    +index 281d6f6..a75f111 100644
    +--- a/core/java/android/content/pm/PackageManager.java
    ++++ b/core/java/android/content/pm/PackageManager.java
    +@@ -5431,7 +5431,7 @@ public abstract class PackageManager {
    +      * {@link #COMPONENT_ENABLED_STATE_DISABLED}, or
    +      * {@link #COMPONENT_ENABLED_STATE_DEFAULT}.  The last one means the
    +      * application's enabled state is based on the original information in
    +-     * the manifest as found in {@link ComponentInfo}.
    ++     * the manifest as found in {@link ApplicationInfo}.
    +      * @throws IllegalArgumentException if the named package does not exist.
    +      */
    +     public abstract int getApplicationEnabledSetting(String packageName);
    +diff --git a/core/java/android/content/pm/PackageManagerInternal.java b/core/java/android/content/pm/PackageManagerInternal.java
    +index d208fe7..f5bcf64 100644
    +--- a/core/java/android/content/pm/PackageManagerInternal.java
    ++++ b/core/java/android/content/pm/PackageManagerInternal.java
    +@@ -160,4 +160,12 @@ public abstract class PackageManagerInternal {
    +      * Returns {@code true} if a given package can't be wiped. Otherwise, returns {@code false}.
    +      */
    +     public abstract boolean isPackageDataProtected(int userId, String packageName);
    ++
    ++    /**
    ++     * Gets whether the package was ever launched.
    ++     * @param packageName The package name.
    ++     * @param userId The user for which to check.
    ++     * @return Whether was launched.
    ++     */
    ++    public abstract boolean wasPackageEverLaunched(String packageName, int userId);
    + }
    +diff --git a/core/java/android/content/pm/ResolveInfo.java b/core/java/android/content/pm/ResolveInfo.java
    +index c9be6ed..b5df4d7 100644
    +--- a/core/java/android/content/pm/ResolveInfo.java
    ++++ b/core/java/android/content/pm/ResolveInfo.java
    +@@ -68,12 +68,6 @@ public class ResolveInfo implements Parcelable {
    +     public EphemeralResolveInfo ephemeralResolveInfo;
    + 
    +     /**
    +-     * A ResolveInfo that points at the ephemeral installer.
    +-     * @hide
    +-     */
    +-    public ResolveInfo ephemeralInstaller;
    +-
    +-    /**
    +      * The IntentFilter that was matched for this ResolveInfo.
    +      */
    +     public IntentFilter filter;
    +diff --git a/core/java/android/content/pm/ShortcutInfo.java b/core/java/android/content/pm/ShortcutInfo.java
    +index ed0ac53..a854b89 100644
    +--- a/core/java/android/content/pm/ShortcutInfo.java
    ++++ b/core/java/android/content/pm/ShortcutInfo.java
    +@@ -46,7 +46,7 @@ import java.util.List;
    + import java.util.Set;
    + 
    + /**
    +- * Represents a "launcher shortcut" that can be published via {@link ShortcutManager}.
    ++ * Represents a shortcut that can be published via {@link ShortcutManager}.
    +  *
    +  * @see ShortcutManager
    +  */
    +@@ -776,17 +776,17 @@ public final class ShortcutInfo implements Parcelable {
    +          * activity is published using
    +          * {@link ShortcutManager#addDynamicShortcuts(List)} or
    +          * {@link ShortcutManager#setDynamicShortcuts(List)},
    +-         * the first main activity defined in the application's <code>AndroidManifest.xml</code>
    ++         * the first main activity defined in the app's <code>AndroidManifest.xml</code>
    +          * file is used.
    +          *
    +          * <li>Only "main" activities&mdash;ones that define the {@link Intent#ACTION_MAIN}
    +          * and {@link Intent#CATEGORY_LAUNCHER} intent filters&mdash;can be target
    +          * activities.
    +          *
    +-         * <li>By default, the first main activity defined in the application manifest is
    ++         * <li>By default, the first main activity defined in the app's manifest is
    +          * the target activity.
    +          *
    +-         * <li>A target activity must belong to the publisher application.
    ++         * <li>A target activity must belong to the publisher app.
    +          * </ul>
    +          *
    +          * @see ShortcutInfo#getActivity()
    +@@ -802,7 +802,7 @@ public final class ShortcutInfo implements Parcelable {
    +          *
    +          * <p>Icons are not available on {@link ShortcutInfo} instances
    +          * returned by {@link ShortcutManager} or {@link LauncherApps}.  The default launcher
    +-         * application can use {@link LauncherApps#getShortcutIconDrawable(ShortcutInfo, int)}
    ++         * app can use {@link LauncherApps#getShortcutIconDrawable(ShortcutInfo, int)}
    +          * or {@link LauncherApps#getShortcutBadgedIconDrawable(ShortcutInfo, int)} to fetch
    +          * shortcut icons.
    +          *
    +@@ -933,8 +933,8 @@ public final class ShortcutInfo implements Parcelable {
    +         }
    + 
    +         /**
    +-         * Sets categories for a shortcut.  Launcher applications may use this information to
    +-         * categorise shortcuts.
    ++         * Sets categories for a shortcut.  Launcher apps may use this information to
    ++         * categorize shortcuts.
    +          *
    +          * @see #SHORTCUT_CATEGORY_CONVERSATION
    +          * @see ShortcutInfo#getCategories()
    +@@ -953,9 +953,9 @@ public final class ShortcutInfo implements Parcelable {
    +          * {@link ShortcutManager#addDynamicShortcuts(List)} or
    +          * {@link ShortcutManager#setDynamicShortcuts(List)}.
    +          *
    +-         * <p>A shortcut can launch any intent that the publisher application has permission to
    ++         * <p>A shortcut can launch any intent that the publisher app has permission to
    +          * launch.  For example, a shortcut can launch an unexported activity within the publisher
    +-         * application.  A shortcut intent doesn't have to point at the target activity.
    ++         * app.  A shortcut intent doesn't have to point at the target activity.
    +          *
    +          * <p>The given {@code intent} can contain extras, but these extras must contain values
    +          * of primitive types in order for the system to persist these values.
    +@@ -970,7 +970,9 @@ public final class ShortcutInfo implements Parcelable {
    + 
    +         /**
    +          * Sets multiple intents instead of a single intent, in order to launch an activity with
    +-         * other activities in back stack.  Use {@link TaskStackBuilder} to build intents.
    ++         * other activities in back stack.  Use {@link TaskStackBuilder} to build intents. The
    ++         * last element in the list represents the only intent that doesn't place an activity on
    ++         * the back stack.
    +          * See the {@link ShortcutManager} javadoc for details.
    +          *
    +          * @see Builder#setIntent(Intent)
    +@@ -1006,9 +1008,9 @@ public final class ShortcutInfo implements Parcelable {
    +         }
    + 
    +         /**
    +-         * Extras that application can set for any purpose.
    ++         * Extras that the app can set for any purpose.
    +          *
    +-         * <p>Applications can store arbitrary shortcut metadata in extras and retrieve the
    ++         * <p>Apps can store arbitrary shortcut metadata in extras and retrieve the
    +          * metadata later using {@link ShortcutInfo#getExtras()}.
    +          */
    +         @NonNull
    +@@ -1029,7 +1031,7 @@ public final class ShortcutInfo implements Parcelable {
    +     /**
    +      * Returns the ID of a shortcut.
    +      *
    +-     * <p>Shortcut IDs are unique within each publisher application and must be stable across
    ++     * <p>Shortcut IDs are unique within each publisher app and must be stable across
    +      * devices so that shortcuts will still be valid when restored on a different device.
    +      * See {@link ShortcutManager} for details.
    +      */
    +@@ -1039,7 +1041,7 @@ public final class ShortcutInfo implements Parcelable {
    +     }
    + 
    +     /**
    +-     * Return the package name of the publisher application.
    ++     * Return the package name of the publisher app.
    +      */
    +     @NonNull
    +     public String getPackage() {
    +@@ -1050,7 +1052,7 @@ public final class ShortcutInfo implements Parcelable {
    +      * Return the target activity.
    +      *
    +      * <p>This has nothing to do with the activity that this shortcut will launch.
    +-     * Launcher applications should show the launcher icon for the returned activity alongside
    ++     * Launcher apps should show the launcher icon for the returned activity alongside
    +      * this shortcut.
    +      *
    +      * @see Builder#setActivity
    +@@ -1102,7 +1104,7 @@ public final class ShortcutInfo implements Parcelable {
    +     }
    + 
    +     /**
    +-     * Return the shorter description of a shortcut.
    ++     * Return the short description of a shortcut.
    +      *
    +      * @see Builder#setShortLabel(CharSequence)
    +      */
    +@@ -1117,7 +1119,7 @@ public final class ShortcutInfo implements Parcelable {
    +     }
    + 
    +     /**
    +-     * Return the longer description of a shortcut.
    ++     * Return the long description of a shortcut.
    +      *
    +      * @see Builder#setLongLabel(CharSequence)
    +      */
    +@@ -1161,7 +1163,7 @@ public final class ShortcutInfo implements Parcelable {
    +      * Returns the intent that is executed when the user selects this shortcut.
    +      * If setIntents() was used, then return the last intent in the array.
    +      *
    +-     * <p>Launcher applications <b>cannot</b> see the intent.  If a {@link ShortcutInfo} is
    ++     * <p>Launcher apps <b>cannot</b> see the intent.  If a {@link ShortcutInfo} is
    +      * obtained via {@link LauncherApps}, then this method will always return null.
    +      * Launchers can only start a shortcut intent with {@link LauncherApps#startShortcut}.
    +      *
    +@@ -1180,7 +1182,7 @@ public final class ShortcutInfo implements Parcelable {
    +     /**
    +      * Return the intent set with {@link Builder#setIntents(Intent[])}.
    +      *
    +-     * <p>Launcher applications <b>cannot</b> see the intents.  If a {@link ShortcutInfo} is
    ++     * <p>Launcher apps <b>cannot</b> see the intents.  If a {@link ShortcutInfo} is
    +      * obtained via {@link LauncherApps}, then this method will always return null.
    +      * Launchers can only start a shortcut intent with {@link LauncherApps#startShortcut}.
    +      *
    +@@ -1219,15 +1221,15 @@ public final class ShortcutInfo implements Parcelable {
    + 
    +     /**
    +      * "Rank" of a shortcut, which is a non-negative, sequential value that's unique for each
    +-     * {@link #getActivity} for each of the two kinds, dynamic shortcuts and manifest shortcuts.
    ++     * {@link #getActivity} for each of the two types of shortcuts (static and dynamic).
    +      *
    +-     * <p>Because manifest shortcuts and dynamic shortcuts have overlapping ranks,
    +-     * when a launcher application shows shortcuts for an activity, it should first show
    +-     * the manifest shortcuts followed by the dynamic shortcuts.  Within each of those categories,
    ++     * <p>Because static shortcuts and dynamic shortcuts have overlapping ranks,
    ++     * when a launcher app shows shortcuts for an activity, it should first show
    ++     * the static shortcuts, followed by the dynamic shortcuts.  Within each of those categories,
    +      * shortcuts should be sorted by rank in ascending order.
    +      *
    +-     * <p>"Floating" shortcuts (i.e. shortcuts that are neither dynamic nor manifest) will all
    +-     * have rank 0, because there's no sorting for them.
    ++     * <p><em>Floating shortcuts</em>, or shortcuts that are neither static nor dynamic, will all
    ++     * have rank 0, because they aren't sorted.
    +      *
    +      * See the {@link ShortcutManager}'s class javadoc for details.
    +      *
    +@@ -1274,7 +1276,7 @@ public final class ShortcutInfo implements Parcelable {
    +     }
    + 
    +     /**
    +-     * Extras that application can set to any purposes.
    ++     * Extras that the app can set for any purpose.
    +      *
    +      * @see Builder#setExtras(PersistableBundle)
    +      */
    +@@ -1339,12 +1341,13 @@ public final class ShortcutInfo implements Parcelable {
    +     }
    + 
    +     /**
    +-     * Return whether a shortcut is published from AndroidManifest.xml or not.  If {@code true},
    +-     * it's also {@link #isImmutable()}.
    ++     * Return whether a shortcut is static; that is, whether a shortcut is
    ++     * published from AndroidManifest.xml.  If {@code true}, the shortcut is
    ++     * also {@link #isImmutable()}.
    +      *
    +      * <p>When an app is upgraded and a shortcut is no longer published from AndroidManifest.xml,
    +-     * this will be set to {@code false}.  If the shortcut is not pinned, then it'll just disappear.
    +-     * However, if it's pinned, it will still be alive, and {@link #isEnabled()} will be
    ++     * this will be set to {@code false}.  If the shortcut is not pinned, then it'll disappear.
    ++     * However, if it's pinned, it will still be visible, {@link #isEnabled()} will be
    +      * {@code false} and {@link #isImmutable()} will be {@code true}.
    +      */
    +     public boolean isDeclaredInManifest() {
    +@@ -1358,7 +1361,7 @@ public final class ShortcutInfo implements Parcelable {
    +     }
    + 
    +     /**
    +-     * @return true if pinned but neither dynamic nor manifest.
    ++     * @return true if pinned but neither static nor dynamic.
    +      * @hide
    +      */
    +     public boolean isFloating() {
    +@@ -1374,9 +1377,10 @@ public final class ShortcutInfo implements Parcelable {
    +      * Return if a shortcut is immutable, in which case it cannot be modified with any of
    +      * {@link ShortcutManager} APIs.
    +      *
    +-     * <p>All manifest shortcuts are immutable.  When a manifest shortcut is pinned and then
    +-     * disabled because the app is upgraded and its AndroidManifest.xml no longer publishes it,
    +-     * {@link #isDeclaredInManifest()} returns {@code false}, but it is still immutable.
    ++     * <p>All static shortcuts are immutable.  When a static shortcut is pinned and is then
    ++     * disabled because it doesn't appear in AndroidManifest.xml for a newer version of the
    ++     * app, {@link #isDeclaredInManifest()} returns {@code false}, but the shortcut
    ++     * is still immutable.
    +      *
    +      * <p>All shortcuts originally published via the {@link ShortcutManager} APIs
    +      * are all mutable.
    +@@ -1561,7 +1565,7 @@ public final class ShortcutInfo implements Parcelable {
    +     }
    + 
    +     /**
    +-     * Replaces the intent
    ++     * Replaces the intent.
    +      *
    +      * @throws IllegalArgumentException when extra is not compatible with {@link PersistableBundle}.
    +      *
    +diff --git a/core/java/android/content/pm/ShortcutManager.java b/core/java/android/content/pm/ShortcutManager.java
    +index cd248ea..a93870e 100644
    +--- a/core/java/android/content/pm/ShortcutManager.java
    ++++ b/core/java/android/content/pm/ShortcutManager.java
    +@@ -31,87 +31,90 @@ import com.android.internal.annotations.VisibleForTesting;
    + import java.util.List;
    + 
    + /**
    +- * The ShortcutManager manages "launcher shortcuts" (or simply "shortcuts").  Shortcuts provide
    +- * users
    +- * with quick access to activities other than an application's main activity in the currently-active
    ++ * The ShortcutManager manages an app's <em>shortcuts</em>. Shortcuts provide users
    ++ * with quick access to activities other than an app's main activity in the currently-active
    +  * launcher.  For example,
    +- * an email application may publish the "compose new email" action, which will directly open the
    ++ * an email app may publish the "compose new email" action, which will directly open the
    +  * compose activity.  The {@link ShortcutInfo} class contains information about each of the
    +  * shortcuts themselves.
    +  *
    +- * <h3>Dynamic Shortcuts and Manifest Shortcuts</h3>
    ++ * <h3>Static Shortcuts and Dynamic Shortcuts</h3>
    +  *
    +- * There are two ways to publish shortcuts: manifest shortcuts and dynamic shortcuts.
    ++ * <p>
    ++ * There are two ways to publish shortcuts: static shortcuts and dynamic shortcuts.
    +  *
    +  * <ul>
    +- * <li>Manifest shortcuts are declared in a resource
    +- * XML, which is referenced in the publisher application's <code>AndroidManifest.xml</code> file.
    +- * Manifest shortcuts are published when an application is installed,
    +- * and the details of these shortcuts change when an application is upgraded with an updated XML
    ++ * <li>Static shortcuts are declared in a resource
    ++ * XML file, which is referenced in the publisher app's <code>AndroidManifest.xml</code> file.
    ++ * Static shortcuts are published when an app is installed,
    ++ * and the details of these shortcuts change when an app is upgraded with an updated XML
    +  * file.
    +- * Manifest shortcuts are immutable, and their
    ++ * Static shortcuts are immutable, and their
    +  * definitions, such as icons and labels, cannot be changed dynamically without upgrading the
    +- * publisher application.
    ++ * publisher app.
    +  *
    +- * <li>Dynamic shortcuts are published at runtime using the {@link ShortcutManager} APIs.
    +- * Applications can publish, update, and remove dynamic shortcuts at runtime.
    ++ * <li>Dynamic shortcuts are published at runtime using this class's APIs.
    ++ * Apps can publish, update, and remove dynamic shortcuts at runtime.
    +  * </ul>
    +  *
    +- * <p>Only "main" activities&mdash;activities that handle the {@code MAIN} action and the
    ++ * <p>Only main activities&mdash;activities that handle the {@code MAIN} action and the
    +  * {@code LAUNCHER} category&mdash;can have shortcuts.
    +- * If an application has multiple main activities, these activities will have different sets
    ++ * If an app has multiple main activities, these activities have different sets
    +  * of shortcuts.
    +  *
    +- * <p>Dynamic shortcuts and manifest shortcuts are shown in the currently active launcher when
    +- * the user long-presses on an application launcher icon.  The actual gesture may be different
    +- * depending on the launcher application.
    ++ * <p>Static shortcuts and dynamic shortcuts are shown in the currently active launcher when
    ++ * the user long-presses on an app's launcher icon.
    ++ *
    ++ * <p class="note"><strong>Note: </strong>The actual gesture may be different
    ++ * depending on the launcher app.
    +  *
    +  * <p>Each launcher icon can have at most {@link #getMaxShortcutCountPerActivity()} number of
    +- * dynamic and manifest shortcuts combined.
    ++ * static and dynamic shortcuts combined.
    +  *
    +  *
    +  * <h3>Pinning Shortcuts</h3>
    +  *
    +- * Launcher applications allow users to "pin" shortcuts so they're easier to access.  Both manifest
    ++ * <p>
    ++ * Launcher apps allow users to <em>pin</em> shortcuts so they're easier to access.  Both static
    +  * and dynamic shortcuts can be pinned.
    +  * Pinned shortcuts <b>cannot</b> be removed by publisher
    +- * applications; they're removed only when the user removes them,
    +- * when the publisher application is uninstalled, or when the
    +- * user performs the "clear data" action on the publisher application from the device's Settings
    +- * application.
    ++ * apps; they're removed only when the user removes them,
    ++ * when the publisher app is uninstalled, or when the
    ++ * user performs the <strong>clear data</strong> action on the publisher app from the device's Settings
    ++ * app.
    +  *
    +- * <p>However, the publisher application can <em>disable</em> pinned shortcuts so they cannot be
    ++ * <p>However, the publisher app can <em>disable</em> pinned shortcuts so they cannot be
    +  * started.  See the following sections for details.
    +  *
    +  *
    +  * <h3>Updating and Disabling Shortcuts</h3>
    +  *
    +  * <p>When a dynamic shortcut is pinned, even when the publisher removes it as a dynamic shortcut,
    +- * the pinned shortcut will still be visible and launchable.  This allows an application to have
    ++ * the pinned shortcut will still be visible and launchable.  This allows an app to have
    +  * more than {@link #getMaxShortcutCountPerActivity()} number of shortcuts.
    +  *
    +  * <p>For example, suppose {@link #getMaxShortcutCountPerActivity()} is 5:
    +- * <ul>
    +- *     <li>A chat application publishes 5 dynamic shortcuts for the 5 most recent
    +- *     conversations, "c1" - "c5".
    ++ * <ol>
    ++ *     <li>A chat app publishes 5 dynamic shortcuts for the 5 most recent
    ++ *     conversations (c1, c2, ..., c5).
    +  *
    +  *     <li>The user pins all 5 of the shortcuts.
    +  *
    +- *     <li>Later, the user has started 3 additional conversations ("c6", "c7", and "c8"),
    +- *     so the publisher application
    ++ *     <li>Later, the user has started 3 additional conversations (c6, c7, and c8),
    ++ *     so the publisher app
    +  *     re-publishes its dynamic shortcuts.  The new dynamic shortcut list is:
    +- *     "c4", "c5", "c6", "c7", and "c8".
    +- *     The publisher application has to remove "c1", "c2", and "c3" because it can't have more than
    ++ *     c4, c5, ..., c8.
    ++ *     The publisher app has to remove c1, c2, and c3 because it can't have more than
    +  *     5 dynamic shortcuts.
    +  *
    +- *     <li>However, even though "c1", "c2" and "c3" are no longer dynamic shortcuts, the pinned
    ++ *     <li>However, even though c1, c2, and c3 are no longer dynamic shortcuts, the pinned
    +  *     shortcuts for these conversations are still available and launchable.
    +  *
    +  *     <li>At this point, the user can access a total of 8 shortcuts that link to activities in
    +- *     the publisher application, including the 3 pinned
    +- *     shortcuts, even though it's allowed to have at most 5 dynamic shortcuts.
    ++ *     the publisher app, including the 3 pinned
    ++ *     shortcuts, even though an app can have at most 5 dynamic shortcuts.
    +  *
    +- *     <li>The application can use {@link #updateShortcuts(List)} to update any of the existing
    ++ *     <li>The app can use {@link #updateShortcuts(List)} to update <em>any</em> of the existing
    +  *     8 shortcuts, when, for example, the chat peers' icons have changed.
    +  * </ul>
    +  * The {@link #addDynamicShortcuts(List)} and {@link #setDynamicShortcuts(List)} methods
    +@@ -121,104 +124,108 @@ import java.util.List;
    +  * lists of shortcuts to dynamic shortcuts.
    +  *
    +  *
    +- * <h4>Disabling Manifest Shortcuts</h4>
    +- * When an application is upgraded and the new version
    +- * no longer uses a manifest shortcut that appeared in the previous version, this deprecated
    +- * shortcut will no longer be published as a manifest shortcut.
    ++ * <h4>Disabling Static Shortcuts</h4>
    ++ * When an app is upgraded and the new version
    ++ * no longer uses a static shortcut that appeared in the previous version, this deprecated
    ++ * shortcut will no longer be published as a static shortcut.
    +  *
    +  * <p>If the deprecated shortcut is pinned, then the pinned shortcut will remain on the launcher,
    +  * but it will be disabled automatically.
    +- * Note that, in this case, the pinned shortcut is no longer a manifest shortcut, but it's
    +- * still <b>immutable</b> and cannot be updated using the {@link ShortcutManager} APIs.
    ++ * Note that, in this case, the pinned shortcut is no longer a static shortcut, but it's
    ++ * still <b>immutable</b>. Therefore, it cannot be updated using this class's APIs.
    +  *
    +  *
    +  * <h4>Disabling Dynamic Shortcuts</h4>
    +  * Sometimes pinned shortcuts become obsolete and may not be usable.  For example, a pinned shortcut
    +- * to a group chat will be unusable when the associated group chat is deleted.  In cases like this,
    +- * applications should use {@link #disableShortcuts(List)}, which will remove the specified dynamic
    +- * shortcuts and also make any specified pinned shortcuts un-launchable.
    ++ * to a group chat becomes unusable when the associated group chat is deleted.  In cases like this,
    ++ * apps should use {@link #disableShortcuts(List)}, which removes the specified dynamic
    ++ * shortcuts and also makes any specified pinned shortcuts un-launchable.
    +  * The {@link #disableShortcuts(List, CharSequence)} method can also be used to disabled shortcuts
    +  * and show users a custom error message when they attempt to launch the disabled shortcuts.
    +  *
    +  *
    +- * <h3>Publishing Manifest Shortcuts</h3>
    ++ * <h3>Publishing Static Shortcuts</h3>
    +  *
    +- * In order to add manifest shortcuts to your application, first add
    ++ * <p>
    ++ * In order to add static shortcuts to your app, first add
    +  * {@code <meta-data android:name="android.app.shortcuts" />} to your main activity in
    +  * AndroidManifest.xml:
    +  * <pre>
    +- * &lt;manifest xmlns:android=&quot;http://schemas.android.com/apk/res/android&quot;
    +- *   package=&quot;com.example.myapplication&quot;&gt;
    +- *   &lt;application . . .&gt;
    +- *     &lt;activity android:name=&quot;Main&quot;&gt;
    +- *       &lt;intent-filter&gt;
    +- *         &lt;action android:name=&quot;android.intent.action.MAIN&quot; /&gt;
    +- *         &lt;category android:name=&quot;android.intent.category.LAUNCHER&quot; /&gt;
    +- *       &lt;/intent-filter&gt;
    +- *       <b>&lt;meta-data android:name=&quot;android.app.shortcuts&quot; android:resource=&quot;@xml/shortcuts&quot;/&gt;</b>
    +- *     &lt;/activity&gt;
    +- *   &lt;/application&gt;
    +- * &lt;/manifest&gt;
    ++ *&lt;manifest xmlns:android="http://schemas.android.com/apk/res/android"
    ++ *             package="com.example.myapplication"&gt;
    ++ *  &lt;application ... &gt;
    ++ *    &lt;activity android:name="Main"&gt;
    ++ *      &lt;intent-filter&gt;
    ++ *        &lt;action android:name="android.intent.action.MAIN" /&gt;
    ++ *        &lt;category android:name="android.intent.category.LAUNCHER" /&gt;
    ++ *      &lt;/intent-filter&gt;
    ++ *      <strong>&lt;meta-data android:name="android.app.shortcuts"
    ++ *                 android:resource="@xml/shortcuts" /&gt;</strong>
    ++ *    &lt;/activity&gt;
    ++ *  &lt;/application&gt;
    ++ *&lt;/manifest&gt;
    +  * </pre>
    +  *
    +- * Then, define your application's manifest shortcuts in the <code>res/xml/shortcuts.xml</code>
    ++ * Then, define your app's static shortcuts in the <code>res/xml/shortcuts.xml</code>
    +  * file:
    +  * <pre>
    +- * &lt;shortcuts xmlns:android=&quot;http://schemas.android.com/apk/res/android&quot; &gt;
    +- *   &lt;shortcut
    +- *     android:shortcutId=&quot;compose&quot;
    +- *     android:enabled=&quot;true&quot;
    +- *     android:icon=&quot;@drawable/compose_icon&quot;
    +- *     android:shortcutShortLabel=&quot;@string/compose_shortcut_short_label1&quot;
    +- *     android:shortcutLongLabel=&quot;@string/compose_shortcut_long_label1&quot;
    +- *     android:shortcutDisabledMessage=&quot;@string/compose_disabled_message1&quot;
    +- *     &gt;
    +- *     &lt;intent
    +- *       android:action=&quot;android.intent.action.VIEW&quot;
    +- *       android:targetPackage=&quot;com.example.myapplication&quot;
    +- *       android:targetClass=&quot;com.example.myapplication.ComposeActivity&quot; /&gt;
    +- *     &lt;!-- more intents can go here; see below --&gt;
    +- *     &lt;categories android:name=&quot;android.shortcut.conversation&quot; /&gt;
    +- *   &lt;/shortcut&gt;
    +- *   &lt;!-- more shortcuts can go here --&gt;
    +- * &lt;/shortcuts&gt;
    ++ *&lt;shortcuts xmlns:android="http://schemas.android.com/apk/res/android"&gt;
    ++ *  &lt;shortcut
    ++ *    android:shortcutId="compose"
    ++ *    android:enabled="true"
    ++ *    android:icon="@drawable/compose_icon"
    ++ *    android:shortcutShortLabel="@string/compose_shortcut_short_label1"
    ++ *    android:shortcutLongLabel="@string/compose_shortcut_long_label1"
    ++ *    android:shortcutDisabledMessage="@string/compose_disabled_message1"&gt;
    ++ *    &lt;intent
    ++ *      android:action="android.intent.action.VIEW"
    ++ *      android:targetPackage="com.example.myapplication"
    ++ *      android:targetClass="com.example.myapplication.ComposeActivity" /&gt;
    ++ *    &lt;!-- If your shortcut is associated with multiple intents, include them
    ++ *         here. The last intent in the list is what the user sees when they
    ++ *         launch this shortcut. --&gt;
    ++ *    &lt;categories android:name="android.shortcut.conversation" /&gt;
    ++ *  &lt;/shortcut&gt;
    ++ *  &lt;!-- Specify more shortcuts here. --&gt;
    ++ *&lt;/shortcuts&gt;
    +  * </pre>
    +  *
    +- * The following list includes descriptions for the different attributes within a manifest shortcut:
    ++ * The following list includes descriptions for the different attributes within a static shortcut:
    +  * <dl>
    +- *   <dt>android:shortcutId</dt>
    ++ *   <dt>{@code android:shortcutId}</dt>
    +  *   <dd>Mandatory shortcut ID</dd>
    +  *
    +- *   <dt>android:enabled</dt>
    ++ *   <dt>{@code android:enabled}</dt>
    +  *   <dd>Default is {@code true}.  Can be set to {@code false} in order
    +- *   to disable a manifest shortcut that was published in a previous version and and set a custom
    +- *   disabled message.  If a custom disabled message is not needed, then a manifest shortcut can
    ++ *   to disable a static shortcut that was published in a previous version and set a custom
    ++ *   disabled message.  If a custom disabled message is not needed, then a static shortcut can
    +  *   be simply removed from the XML file rather than keeping it with {@code enabled="false"}.</dd>
    +  *
    +- *   <dt>android:icon</dt>
    ++ *   <dt>{@code android:icon}</dt>
    +  *   <dd>Shortcut icon.</dd>
    +  *
    +- *   <dt>android:shortcutShortLabel</dt>
    ++ *   <dt>{@code android:shortcutShortLabel}</dt>
    +  *   <dd>Mandatory shortcut short label.
    +  *   See {@link ShortcutInfo.Builder#setShortLabel(CharSequence)}.</dd>
    +  *
    +- *   <dt>android:shortcutLongLabel</dt>
    ++ *   <dt>{@code android:shortcutLongLabel}</dt>
    +  *   <dd>Shortcut long label.
    +  *   See {@link ShortcutInfo.Builder#setLongLabel(CharSequence)}.</dd>
    +  *
    +- *   <dt>android:shortcutDisabledMessage</dt>
    ++ *   <dt>{@code android:shortcutDisabledMessage}</dt>
    +  *   <dd>When {@code android:enabled} is set to
    +  *   {@code false}, this attribute is used to display a custom disabled message.</dd>
    +  *
    +- *   <dt>intent</dt>
    ++ *   <dt>{@code intent}</dt>
    +  *   <dd>Intent to launch when the user selects the shortcut.
    +  *   {@code android:action} is mandatory.
    +  *   See <a href="{@docRoot}guide/topics/ui/settings.html#Intents">Using intents</a> for the
    +  *   other supported tags.
    +- *   You can provide multiple intents for a single shortcut so that an activity is launched
    +- *   with other activities in the back stack. See {@link android.app.TaskStackBuilder} for details.
    ++ *   You can provide multiple intents for a single shortcut so that the last defined activity is launched
    ++ *   with the other activities in the <a href="/guide/components/tasks-and-back-stack.html">back stack</a>.
    ++ *   See {@link android.app.TaskStackBuilder} for details.
    +  *   </dd>
    +- *   <dt>categories</dt>
    ++ *   <dt>{@code categories}</dt>
    +  *   <dd>Specify shortcut categories.  Currently only
    +  *   {@link ShortcutInfo#SHORTCUT_CATEGORY_CONVERSATION} is defined in the framework.
    +  *   </dd>
    +@@ -226,64 +233,68 @@ import java.util.List;
    +  *
    +  * <h3>Publishing Dynamic Shortcuts</h3>
    +  *
    +- * Applications can publish dynamic shortcuts with {@link #setDynamicShortcuts(List)}
    ++ * <p>
    ++ * Apps can publish dynamic shortcuts with {@link #setDynamicShortcuts(List)}
    +  * or {@link #addDynamicShortcuts(List)}.  The {@link #updateShortcuts(List)} method can also be
    +  * used to update existing, mutable shortcuts.
    +  * Use {@link #removeDynamicShortcuts(List)} or {@link #removeAllDynamicShortcuts()} to remove
    +  * dynamic shortcuts.
    +  *
    +- * <p>Example:
    ++ * <p>The following code snippet shows how to create a single dynamic shortcut:
    +  * <pre>
    +- * ShortcutManager shortcutManager = getSystemService(ShortcutManager.class);
    ++ *ShortcutManager shortcutManager = getSystemService(ShortcutManager.class);
    +  *
    +- * ShortcutInfo shortcut = new ShortcutInfo.Builder(this, "id1")
    +- *     .setIntent(new Intent(Intent.ACTION_VIEW, Uri.parse("http://www.mysite.com/")))
    +- *     .setShortLabel("Web site")
    +- *     .setLongLabel("Open the web site")
    +- *     .setIcon(Icon.createWithResource(context, R.drawable.icon_website))
    +- *     .build();
    ++ *ShortcutInfo shortcut = new ShortcutInfo.Builder(this, "id1")
    ++ *    .setShortLabel("Web site")
    ++ *    .setLongLabel("Open the web site")
    ++ *    .setIcon(Icon.createWithResource(context, R.drawable.icon_website))
    ++ *    .setIntent(new Intent(Intent.ACTION_VIEW,
    ++ *                   Uri.parse("https://www.mysite.example.com/")))
    ++ *    .build();
    +  *
    +- * shortcutManager.setDynamicShortcuts(Arrays.asList(shortcut));
    ++ *shortcutManager.setDynamicShortcuts(Arrays.asList(shortcut));
    +  * </pre>
    +  *
    +  *
    +  * <h3>Shortcut Intents</h3>
    ++ * <p>
    +  * Dynamic shortcuts can be published with any set of {@link Intent#addFlags Intent} flags.
    +  * Typically, {@link Intent#FLAG_ACTIVITY_CLEAR_TASK} is specified, possibly along with other
    +- * flags; otherwise, if the application is already running, the application is simply brought to
    ++ * flags; otherwise, if the app is already running, the app is simply brought to
    +  * the foreground, and the target activity may not appear.
    +  *
    +  * <p>The {@link ShortcutInfo.Builder#setIntents(Intent[])} method can be used instead of
    +  * {@link ShortcutInfo.Builder#setIntent(Intent)} with {@link android.app.TaskStackBuilder}
    +  * in order to launch an activity with other activities in the back stack.
    +  * When the user selects a shortcut to load an activity with a back stack,
    +- * then presses the back key, a "parent" activity will be shown instead of the user being
    +- * navigated back to the launcher.
    ++ * then presses the back key, a parent activity from the same app will be shown
    ++ * instead of the user being navigated back to the launcher.
    +  *
    +- * <p>Manifest shortcuts can also have multiple intents to achieve the same effect.
    ++ * <p>Static shortcuts can also have multiple intents to achieve the same effect.
    +  * In order to associate multiple {@link Intent} objects with a shortcut, simply list multiple
    +  * <code>&lt;intent&gt;</code> elements within a single <code>&lt;shortcut&gt;</code> element.
    +- * The last intent specifies what the user will see when they launch a shortcut.
    ++ * The last intent specifies what the user sees when they launch a shortcut.
    +  *
    +- * <p>Manifest shortcuts <b>cannot</b> have custom intent flags.
    +- * The first intent of a manifest shortcut will always have {@link Intent#FLAG_ACTIVITY_NEW_TASK}
    ++ * <p>Static shortcuts <b>cannot</b> have custom intent flags.
    ++ * The first intent of a static shortcut will always have {@link Intent#FLAG_ACTIVITY_NEW_TASK}
    +  * and {@link Intent#FLAG_ACTIVITY_CLEAR_TASK} set.
    +- * This means, when the application is already running, all the existing activities will be
    +- * destroyed when a manifest shortcut is launched.
    ++ * This means, when the app is already running, all the existing activities will be
    ++ * destroyed when a static shortcut is launched.
    +  * If this behavior is not desirable, you can use a <em>trampoline activity</em>,
    +  * or an invisible activity that starts another activity in {@link Activity#onCreate},
    +  * then calls {@link Activity#finish()}.
    +  * The first activity should include an attribute setting
    +- * of {@code android:taskAffinity=""} in the application's <code>AndroidManifest.xml</code>
    +- * file, and the intent within the manifest shortcut should point at this first activity.
    ++ * of {@code android:taskAffinity=""} in the app's <code>AndroidManifest.xml</code>
    ++ * file, and the intent within the static shortcut should point at this first activity.
    +  *
    +  *
    +  * <h3>Showing New Information in a Shortcut</h3>
    ++ * <p>
    +  * In order to avoid confusion, you should not use {@link #updateShortcuts(List)} to update
    +  * a shortcut so that it contains conceptually different information.
    +  *
    +- * <p>For example, a phone application may publish the most frequently called contact as a dynamic
    +- * shortcut.  Over time, this contact may change; when it does, the application should
    ++ * <p>For example, a phone app may publish the most frequently called contact as a dynamic
    ++ * shortcut.  Over time, this contact may change. When it does, the app should
    +  * represent the changed contact with a new shortcut that contains a different ID, using either
    +  * {@link #setDynamicShortcuts(List)} or {@link #addDynamicShortcuts(List)}, rather than updating
    +  * the existing shortcut with {@link #updateShortcuts(List)}.
    +@@ -291,7 +302,7 @@ import java.util.List;
    +  * it to reference a different contact will likely confuse the user.
    +  *
    +  * <p>On the other hand, when the
    +- * contact's information has changed, such as the name or picture, the application should
    ++ * contact's information has changed, such as the name or picture, the app should
    +  * use {@link #updateShortcuts(List)} so that the pinned shortcut is updated too.
    +  *
    +  *
    +@@ -299,21 +310,21 @@ import java.util.List;
    +  * When the launcher displays the shortcuts that are associated with a particular launcher icon,
    +  * the shortcuts should appear in the following order:
    +  * <ul>
    +- *   <li>First show manifest shortcuts
    ++ *   <li>First show static shortcuts
    +  *   (if {@link ShortcutInfo#isDeclaredInManifest()} is {@code true}),
    +  *   and then show dynamic shortcuts (if {@link ShortcutInfo#isDynamic()} is {@code true}).
    +- *   <li>Within each category of shortcuts (manifest and dynamic), sort the shortcuts in order
    ++ *   <li>Within each category of shortcuts (static and dynamic), sort the shortcuts in order
    +  *   of increasing rank according to {@link ShortcutInfo#getRank()}.
    +  * </ul>
    +- * <p>Shortcut ranks are non-negative sequential integers
    ++ * <p>Shortcut ranks are non-negative, sequential integers
    +  * that determine the order in which shortcuts appear, assuming that the shortcuts are all in
    +  * the same category.
    +  * Ranks of existing shortcuts can be updated with
    +- * {@link #updateShortcuts(List)}; you can use {@link #addDynamicShortcuts(List)} and
    +- * {@link #setDynamicShortcuts(List)}, too.
    ++ * {@link #updateShortcuts(List)}. You can also use {@link #addDynamicShortcuts(List)} and
    ++ * {@link #setDynamicShortcuts(List)}.
    +  *
    +  * <p>Ranks are auto-adjusted so that they're unique for each target activity in each category
    +- * (dynamic or manifest).  For example, if there are 3 dynamic shortcuts with ranks 0, 1 and 2,
    ++ * (static or dynamic).  For example, if there are 3 dynamic shortcuts with ranks 0, 1 and 2,
    +  * adding another dynamic shortcut with a rank of 1 represents a request to place this shortcut at
    +  * the second position.
    +  * In response, the third and fourth shortcuts move closer to the bottom of the shortcut list,
    +@@ -321,119 +332,120 @@ import java.util.List;
    +  *
    +  * <h3>Rate Limiting</h3>
    +  *
    ++ * <p>
    +  * Calls to {@link #setDynamicShortcuts(List)}, {@link #addDynamicShortcuts(List)}, and
    +- * {@link #updateShortcuts(List)} may be rate-limited when called by background applications, or
    +- * applications with no foreground activity or service.  When you attempt to call these methods
    +- * from a background application after exceeding the rate limit, these APIs return {@code false}.
    ++ * {@link #updateShortcuts(List)} may be rate-limited when called by <em>background apps</em>, or
    ++ * apps with no foreground activity or service.  When you attempt to call these methods
    ++ * from a background app after exceeding the rate limit, these APIs return {@code false}.
    +  *
    +- * <p>Applications with a foreground activity or service are not rate-limited.
    ++ * <p>Apps with a foreground activity or service are not rate-limited.
    +  *
    +- * <p>Rate-limiting will be reset upon certain events, so that even background applications
    +- * can call these APIs again until they are rate limit is reached again.
    ++ * <p>Rate-limiting is reset upon certain events, so that even background apps
    ++ * can call these APIs until the rate limit is reached again.
    +  * These events include the following:
    +  * <ul>
    +- *   <li>When an application comes to the foreground.
    +- *   <li>When the system locale changes.
    +- *   <li>When the user performs an "inline reply" action on a notification.
    ++ *   <li>An app comes to the foreground.
    ++ *   <li>The system locale changes.
    ++ *   <li>The user performs the <strong>inline reply</strong> action on a notification.
    +  * </ul>
    +  *
    +  * <p>When rate-limiting is active, {@link #isRateLimitingActive()} returns {@code true}.
    +  *
    +  * <h4>Resetting rate-limiting for testing</h4>
    +  *
    +- * If your application is rate-limited during development or testing, you can use the
    +- * "Reset ShortcutManager rate-limiting" development option or the following adb command to reset
    +- * it:
    +- * <pre>
    +- * adb shell cmd shortcut reset-throttling [ --user USER-ID ]
    ++ * <p>
    ++ * If your app is rate-limited during development or testing, you can use the
    ++ * <strong>Reset ShortcutManager rate-limiting</strong> development option or
    ++ * the following {@code adb} command to reset it:
    ++ * <pre class="no-pretty-print">
    ++ *$ adb shell cmd shortcut reset-throttling [ --user USER-ID ]
    +  * </pre>
    +  *
    +  * <h3>Handling System Locale Changes</h3>
    +  *
    +- * Applications should update dynamic and pinned shortcuts when the system locale changes
    ++ * <p>
    ++ * Apps should update dynamic and pinned shortcuts when the system locale changes
    +  * using the {@link Intent#ACTION_LOCALE_CHANGED} broadcast.
    +  *
    +- * <p>When the system locale changes, rate-limiting is reset, so even background applications
    +- * can set dynamic shortcuts, add dynamic shortcuts, and update shortcuts until the rate limit
    +- * is reached again.
    ++ * <p>When the system locale changes, rate-limiting is reset, so even background apps
    ++ * can add and update dynamic shortcuts until the rate limit is reached again.
    +  *
    +  *
    +  * <h3>Backup and Restore</h3>
    +  *
    +- * When an application has the {@code android:allowBackup="true"} attribute assignment included
    ++ * <p>
    ++ * When an app has the {@code android:allowBackup="true"} attribute assignment included
    +  * in its <code>AndroidManifest.xml</code> file, pinned shortcuts are
    +  * backed up automatically and are restored when the user sets up a new device.
    +  *
    +- * <h4>Categories of Shortcuts that are Backed Up</h4>
    ++ * <h4>Categories of shortcuts that are backed up</h4>
    +  *
    +  * <ul>
    +  *  <li>Pinned shortcuts are backed up.  Bitmap icons are not backed up by the system,
    +- *  but launcher applications should back them up and restore them so that the user still sees icons
    +- *  for pinned shortcuts on the launcher.  Applications can always use
    ++ *  so launcher apps should back them up and restore them so that the user still sees icons
    ++ *  for pinned shortcuts on the launcher.  Apps can always use
    +  *  {@link #updateShortcuts(List)} to re-publish icons.
    +  *
    +- *  <li>Manifest shortcuts are not backed up, but when an application is re-installed on a new
    +- *  device, they are re-published from the <code>AndroidManifest.xml</code> file, anyway.
    ++ *  <li>Static shortcuts aren't backed up, but when an app is re-installed on a new
    ++ *  device, they are re-published from the <code>AndroidManifest.xml</code> file.
    +  *
    +- *  <li>Dynamic shortcuts are <b>not</b> backed up.
    ++ *  <li>Dynamic shortcuts <b>aren't</b> backed up.
    +  * </ul>
    +  *
    +- * <p>Because dynamic shortcuts are not restored, it is recommended that applications check
    ++ * <p>Because dynamic shortcuts are not restored, it is recommended that apps check
    +  * currently-published dynamic shortcuts using {@link #getDynamicShortcuts()}
    +  * each time they are launched, and they should re-publish
    +  * dynamic shortcuts when necessary.
    +  *
    +  * <pre>
    +- * public class MainActivity extends Activity {
    +- *     public void onCreate(Bundle savedInstanceState) {
    +- *         super.onCreate(savedInstanceState);
    +- *
    +- *         ShortcutManager shortcutManager = getSystemService(ShortcutManager.class);
    +- *
    +- *         if (shortcutManager.getDynamicShortcuts().size() == 0) {
    +- *             // Application restored; re-publish dynamic shortcuts.
    +- *
    +- *             if (shortcutManager.getPinnedShortcuts().size() > 0) {
    +- *                 // Pinned shortcuts have been restored.  Use updateShortcuts() to make sure
    +- *                 // they have up-to-date information.
    +- *             }
    +- *         }
    +- *     }
    +- *     :
    +- *
    +- * }
    ++ *public class MainActivity extends Activity {
    ++ *    public void onCreate(Bundle savedInstanceState) {
    ++ *        super.onCreate(savedInstanceState);
    ++ *        ShortcutManager shortcutManager =
    ++ *                getSystemService(ShortcutManager.class);
    ++ *
    ++ *        if (shortcutManager.getDynamicShortcuts().size() == 0) {
    ++ *            // Application restored. Need to re-publish dynamic shortcuts.
    ++ *            if (shortcutManager.getPinnedShortcuts().size() > 0) {
    ++ *                // Pinned shortcuts have been restored. Use
    ++ *                // updateShortcuts() to make sure they contain
    ++ *                // up-to-date information.
    ++ *            }
    ++ *        }
    ++ *    }
    ++ *    // ...
    ++ *}
    +  * </pre>
    +  *
    +  *
    +  * <h4>Backup/restore and shortcut IDs</h4>
    +- *
    +- * Because pinned shortcuts are backed up and restored on new devices, shortcut IDs should be
    +- * meaningful across devices; that is, IDs should contain either stable, constant strings
    +- * or server-side identifiers,
    ++ * <p>
    ++ * Because pinned shortcuts are backed up and restored on new devices, shortcut IDs
    ++ * should contain either stable, constant strings or server-side identifiers,
    +  * rather than identifiers generated locally that might not make sense on other devices.
    +  *
    +  *
    +  * <h3>Report Shortcut Usage and Prediction</h3>
    +- *
    +- * Launcher applications may be capable of predicting which shortcuts will most likely be
    ++ * <p>
    ++ * Launcher apps may be capable of predicting which shortcuts will most likely be
    +  * used at a given time by examining the shortcut usage history data.
    +  *
    +- * <p>In order to provide launchers with such data, publisher applications should
    ++ * <p>In order to provide launchers with such data, publisher apps should
    +  * report the shortcuts that are used with {@link #reportShortcutUsed(String)}
    +  * when a shortcut is selected,
    +  * <b>or when an action equivalent to a shortcut is taken by the user even if it wasn't started
    +  * with the shortcut</b>.
    +  *
    +- * <p>For example, suppose a GPS navigation application supports "navigate to work" as a shortcut.
    ++ * <p>For example, suppose a navigation app supports "navigate to work" as a shortcut.
    +  * It should then report when the user selects this shortcut <b>and</b> when the user chooses
    +- * to navigate to work within the application itself.
    +- * This helps the launcher application
    ++ * to navigate to work within the app itself.
    ++ * This helps the launcher app
    +  * learn that the user wants to navigate to work at a certain time every
    +  * weekday, and it can then show this shortcut in a suggestion list at the right time.
    +  *
    +  * <h3>Launcher API</h3>
    +  *
    +- * The {@link LauncherApps} class provides APIs for launcher applications to access shortcuts.
    ++ * The {@link LauncherApps} class provides APIs for launcher apps to access shortcuts.
    +  *
    +  *
    +  * <h3>Direct Boot and Shortcuts</h3>
    +@@ -465,7 +477,7 @@ public class ShortcutManager {
    +     }
    + 
    +     /**
    +-     * Publish the list of shortcuts.  All existing dynamic shortcuts from the caller application
    ++     * Publish the list of shortcuts.  All existing dynamic shortcuts from the caller app
    +      * will be replaced.  If there are already pinned shortcuts with the same IDs,
    +      * the mutable pinned shortcuts are updated.
    +      *
    +@@ -488,7 +500,7 @@ public class ShortcutManager {
    +     }
    + 
    +     /**
    +-     * Return all dynamic shortcuts from the caller application.
    ++     * Return all dynamic shortcuts from the caller app.
    +      *
    +      * @throws IllegalStateException when the user is locked.
    +      */
    +@@ -503,7 +515,7 @@ public class ShortcutManager {
    +     }
    + 
    +     /**
    +-     * Return all manifest shortcuts from the caller application.
    ++     * Return all static (manifest) shortcuts from the caller app.
    +      *
    +      * @throws IllegalStateException when the user is locked.
    +      */
    +@@ -554,7 +566,7 @@ public class ShortcutManager {
    +     }
    + 
    +     /**
    +-     * Delete all dynamic shortcuts from the caller application.
    ++     * Delete all dynamic shortcuts from the caller app.
    +      *
    +      * @throws IllegalStateException when the user is locked.
    +      */
    +@@ -567,7 +579,7 @@ public class ShortcutManager {
    +     }
    + 
    +     /**
    +-     * Return all pinned shortcuts from the caller application.
    ++     * Return all pinned shortcuts from the caller app.
    +      *
    +      * @throws IllegalStateException when the user is locked.
    +      */
    +@@ -661,7 +673,7 @@ public class ShortcutManager {
    + 
    +     /**
    +      * Re-enable pinned shortcuts that were previously disabled.  If the target shortcuts
    +-     * already enabled, this method does nothing.
    ++     * are already enabled, this method does nothing.
    +      *
    +      * @throws IllegalArgumentException If trying to enable immutable shortcuts.
    +      *
    +@@ -684,7 +696,7 @@ public class ShortcutManager {
    +     }
    + 
    +     /**
    +-     * Return the maximum number of dynamic and manifest shortcuts that each launcher icon
    ++     * Return the maximum number of static and dynamic shortcuts that each launcher icon
    +      * can have at a time.
    +      */
    +     public int getMaxShortcutCountPerActivity() {
    +@@ -697,7 +709,7 @@ public class ShortcutManager {
    +     }
    + 
    +     /**
    +-     * Return the number of times the caller application can call the rate-limited APIs
    ++     * Return the number of times the caller app can call the rate-limited APIs
    +      * before the rate limit counter is reset.
    +      *
    +      * @see #getRateLimitResetTime()
    +@@ -729,7 +741,7 @@ public class ShortcutManager {
    +     }
    + 
    +     /**
    +-     * Return {@code true} when rate-limiting is active for the caller application.
    ++     * Return {@code true} when rate-limiting is active for the caller app.
    +      *
    +      * <p>See the class level javadoc for details.
    +      *
    +@@ -769,13 +781,13 @@ public class ShortcutManager {
    +     }
    + 
    +     /**
    +-     * Applications that publish shortcuts should call this method
    +-     * whenever the user selects the shortcut containing the given ID or when the user completes
    +-     * an action in the application that is equivalent to selecting the shortcut.
    ++     * Apps that publish shortcuts should call this method whenever the user
    ++     * selects the shortcut containing the given ID or when the user completes
    ++     * an action in the app that is equivalent to selecting the shortcut.
    +      * For more details, see the Javadoc for the {@link ShortcutManager} class
    +      *
    +      * <p>The information is accessible via {@link UsageStatsManager#queryEvents}
    +-     * Typically, launcher applications use this information to build a prediction model
    ++     * Typically, launcher apps use this information to build a prediction model
    +      * so that they can promote the shortcuts that are likely to be used at the moment.
    +      *
    +      * @throws IllegalStateException when the user is locked.
    +@@ -790,9 +802,9 @@ public class ShortcutManager {
    +     }
    + 
    +     /**
    +-     * Called internally when an application is considered to have come to foreground
    ++     * Called internally when an app is considered to have come to the foreground
    +      * even when technically it's not.  This method resets the throttling for this package.
    +-     * For example, when the user sends an "inline reply" on an notification, the system UI will
    ++     * For example, when the user sends an "inline reply" on a notification, the system UI will
    +      * call it.
    +      *
    +      * @hide
    +diff --git a/core/java/android/database/CursorJoiner.java b/core/java/android/database/CursorJoiner.java
    +index e3c2988..a95263b 100644
    +--- a/core/java/android/database/CursorJoiner.java
    ++++ b/core/java/android/database/CursorJoiner.java
    +@@ -27,7 +27,7 @@ import java.util.Iterator;
    +  *
    +  * <pre>
    +  * CursorJoiner joiner = new CursorJoiner(cursorA, keyColumnsofA, cursorB, keyColumnsofB);
    +- * for (CursorJointer.Result joinerResult : joiner) {
    ++ * for (CursorJoiner.Result joinerResult : joiner) {
    +  *     switch (joinerResult) {
    +  *         case LEFT:
    +  *             // handle case where a row in cursorA is unique
    +diff --git a/core/java/android/database/sqlite/SQLiteDatabase.java b/core/java/android/database/sqlite/SQLiteDatabase.java
    +index 0f64b92..8e17832 100644
    +--- a/core/java/android/database/sqlite/SQLiteDatabase.java
    ++++ b/core/java/android/database/sqlite/SQLiteDatabase.java
    +@@ -1371,6 +1371,7 @@ public final class SQLiteDatabase extends SQLiteClosable {
    + 
    +     /**
    +      * Convenience method for replacing a row in the database.
    ++     * Inserts a new row if a row does not already exist.
    +      *
    +      * @param table the table in which to replace the row
    +      * @param nullColumnHack optional; may be <code>null</code>.
    +@@ -1381,7 +1382,7 @@ public final class SQLiteDatabase extends SQLiteClosable {
    +      *            provides the name of nullable column name to explicitly insert a NULL into
    +      *            in the case where your <code>initialValues</code> is empty.
    +      * @param initialValues this map contains the initial column values for
    +-     *   the row.
    ++     *   the row. The keys should be the column names and the values the column values.
    +      * @return the row ID of the newly inserted row, or -1 if an error occurred
    +      */
    +     public long replace(String table, String nullColumnHack, ContentValues initialValues) {
    +@@ -1396,6 +1397,7 @@ public final class SQLiteDatabase extends SQLiteClosable {
    + 
    +     /**
    +      * Convenience method for replacing a row in the database.
    ++     * Inserts a new row if a row does not already exist.
    +      *
    +      * @param table the table in which to replace the row
    +      * @param nullColumnHack optional; may be <code>null</code>.
    +@@ -1406,7 +1408,7 @@ public final class SQLiteDatabase extends SQLiteClosable {
    +      *            provides the name of nullable column name to explicitly insert a NULL into
    +      *            in the case where your <code>initialValues</code> is empty.
    +      * @param initialValues this map contains the initial column values for
    +-     *   the row. The key
    ++     *   the row. The keys should be the column names and the values the column values.
    +      * @throws SQLException
    +      * @return the row ID of the newly inserted row, or -1 if an error occurred
    +      */
    +@@ -1740,7 +1742,7 @@ public final class SQLiteDatabase extends SQLiteClosable {
    +      * Returns true if the new version code is greater than the current database version.
    +      *
    +      * @param newVersion The new version code.
    +-     * @return True if the new version code is greater than the current database version. 
    ++     * @return True if the new version code is greater than the current database version.
    +      */
    +     public boolean needUpgrade(int newVersion) {
    +         return newVersion > getVersion();
    +diff --git a/core/java/android/database/sqlite/package.html b/core/java/android/database/sqlite/package.html
    +index ceed171..864a9bb 100644
    +--- a/core/java/android/database/sqlite/package.html
    ++++ b/core/java/android/database/sqlite/package.html
    +@@ -6,15 +6,44 @@ classes that an application would use to manage its own private database.
    + Applications use these classes to manage private databases. If creating a
    + content provider, you will probably have to use these classes to create and
    + manage your own database to store content. See <a
    +-href="{@docRoot}guide/topics/providers/content-providers.html">Content Providers</a> to learn
    +-the conventions for implementing a content provider. See the
    +-NotePadProvider class in the NotePad sample application in the SDK for an
    +-example of a content provider. Android ships with SQLite version 3.4.0
    +-<p>If you are working with data sent to you by a provider, you will not use
    +-these SQLite classes, but instead use the generic {@link android.database}
    +-classes.
    +-<p>Android ships with the sqlite3 database tool in the <code>tools/</code>
    +-folder. You can use this tool to browse or run SQL commands on the device. Run by
    +-typing <code>sqlite3</code> in a shell window.
    ++href="{@docRoot}guide/topics/providers/content-providers.html">Content Providers</a>
    ++to learn the conventions for implementing a content provider. If you are working
    ++with data sent to you by a provider, you do not use these SQLite classes, but
    ++instead use the generic {@link android.database} classes.
    ++
    ++<p>The Android SDK and Android emulators both include the
    ++<a href="{@docRoot}studio/command-line/sqlite3.html">sqlite3</a> command-line
    ++database tool. On your development machine, run the tool from the
    ++<code>platform-tools/</code> folder of your SDK. On the emulator, run the tool
    ++with adb shell, for example, <code>adb -e shell sqlite3</code>.
    ++
    ++<p>The version of SQLite depends on the version of Android. See the following table:
    ++<table style="width:auto;">
    ++  <tr><th>Android API</th><th>SQLite Version</th></tr>
    ++  <tr><td>API 24</td><td>3.9</td></tr>
    ++  <tr><td>API 21</td><td>3.8</td></tr>
    ++  <tr><td>API 11</td><td>3.7</td></tr>
    ++  <tr><td>API 8</td><td>3.6</td></tr>
    ++  <tr><td>API 3</td><td>3.5</td></tr>
    ++  <tr><td>API 1</td><td>3.4</td></tr>
    ++</table>
    ++
    ++<p>Some device manufacturers include different versions of SQLite on their devices.
    ++  There are two ways to programmatically determine the version number.
    ++
    ++<ul>
    ++  <li>If available, use the sqlite3 tool, for example:
    ++    <code>adb -e shell sqlite3 --version</code>.</li>
    ++  <li>Create and query an in-memory database as shown in the following code sample:
    ++    <pre>
    ++    String query = "select sqlite_version() AS sqlite_version";
    ++    SQLiteDatabase db = SQLiteDatabase.openOrCreateDatabase(":memory:", null);
    ++    Cursor cursor = db.rawQuery(query, null);
    ++    String sqliteVersion = "";
    ++    if (cursor.moveToNext()) {
    ++        sqliteVersion = cursor.getString(0);
    ++    }</pre>
    ++  </li>
    ++</ul>
    + </BODY>
    + </HTML>
    +diff --git a/core/java/android/hardware/camera2/DngCreator.java b/core/java/android/hardware/camera2/DngCreator.java
    +index 9478dc0..1a51acd 100644
    +--- a/core/java/android/hardware/camera2/DngCreator.java
    ++++ b/core/java/android/hardware/camera2/DngCreator.java
    +@@ -27,6 +27,7 @@ import android.location.Location;
    + import android.media.ExifInterface;
    + import android.media.Image;
    + import android.os.SystemClock;
    ++import android.util.Log;
    + import android.util.Size;
    + 
    + import java.io.IOException;
    +@@ -89,21 +90,43 @@ public final class DngCreator implements AutoCloseable {
    +             throw new IllegalArgumentException("Null argument to DngCreator constructor");
    +         }
    + 
    +-        // Find current time
    ++        // Find current time in milliseconds since 1970
    +         long currentTime = System.currentTimeMillis();
    +-
    +-        // Find boot time
    +-        long bootTimeMillis = currentTime - SystemClock.elapsedRealtime();
    ++        // Assume that sensor timestamp has that timebase to start
    ++        long timeOffset = 0;
    ++
    ++        int timestampSource = characteristics.get(
    ++                CameraCharacteristics.SENSOR_INFO_TIMESTAMP_SOURCE);
    ++
    ++        if (timestampSource == CameraCharacteristics.SENSOR_INFO_TIMESTAMP_SOURCE_REALTIME) {
    ++            // This means the same timebase as SystemClock.elapsedRealtime(),
    ++            // which is CLOCK_BOOTTIME
    ++            timeOffset = currentTime - SystemClock.elapsedRealtime();
    ++        } else if (timestampSource == CameraCharacteristics.SENSOR_INFO_TIMESTAMP_SOURCE_UNKNOWN) {
    ++            // This means the same timebase as System.currentTimeMillis(),
    ++            // which is CLOCK_MONOTONIC
    ++            timeOffset = currentTime - SystemClock.uptimeMillis();
    ++        } else {
    ++            // Unexpected time source - treat as CLOCK_MONOTONIC
    ++            Log.w(TAG, "Sensor timestamp source is unexpected: " + timestampSource);
    ++            timeOffset = currentTime - SystemClock.uptimeMillis();
    ++        }
    + 
    +         // Find capture time (nanos since boot)
    +         Long timestamp = metadata.get(CaptureResult.SENSOR_TIMESTAMP);
    +         long captureTime = currentTime;
    +         if (timestamp != null) {
    +-            captureTime = timestamp / 1000000 + bootTimeMillis;
    ++            captureTime = timestamp / 1000000 + timeOffset;
    +         }
    + 
    ++        // Create this fresh each time since the time zone may change while a long-running application
    ++        // is active.
    ++        final DateFormat dateTimeStampFormat =
    ++            new SimpleDateFormat(TIFF_DATETIME_FORMAT);
    ++        dateTimeStampFormat.setTimeZone(TimeZone.getDefault());
    ++
    +         // Format for metadata
    +-        String formattedCaptureTime = sDateTimeStampFormat.format(captureTime);
    ++        String formattedCaptureTime = dateTimeStampFormat.format(captureTime);
    + 
    +         nativeInit(characteristics.getNativeCopy(), metadata.getNativeCopy(),
    +                 formattedCaptureTime);
    +@@ -450,13 +473,10 @@ public final class DngCreator implements AutoCloseable {
    +     private static final String GPS_DATE_FORMAT_STR = "yyyy:MM:dd";
    +     private static final String TIFF_DATETIME_FORMAT = "yyyy:MM:dd HH:mm:ss";
    +     private static final DateFormat sExifGPSDateStamp = new SimpleDateFormat(GPS_DATE_FORMAT_STR);
    +-    private static final DateFormat sDateTimeStampFormat =
    +-            new SimpleDateFormat(TIFF_DATETIME_FORMAT);
    +     private final Calendar mGPSTimeStampCalendar = Calendar
    +             .getInstance(TimeZone.getTimeZone("UTC"));
    + 
    +     static {
    +-        sDateTimeStampFormat.setTimeZone(TimeZone.getDefault());
    +         sExifGPSDateStamp.setTimeZone(TimeZone.getTimeZone("UTC"));
    +     }
    + 
    +diff --git a/core/java/android/hardware/camera2/utils/TaskDrainer.java b/core/java/android/hardware/camera2/utils/TaskDrainer.java
    +index 7c46e50..ed30ff3 100644
    +--- a/core/java/android/hardware/camera2/utils/TaskDrainer.java
    ++++ b/core/java/android/hardware/camera2/utils/TaskDrainer.java
    +@@ -29,8 +29,9 @@ import static com.android.internal.util.Preconditions.*;
    +  * (and new ones won't begin).
    +  *
    +  * <p>The initial state is to allow all tasks to be started and finished. A task may only be started
    +- * once, after which it must be finished before starting again. Likewise, finishing a task
    +- * that hasn't been started is also not allowed.</p>
    ++ * once, after which it must be finished before starting again. Likewise, a task may only be
    ++ * finished once, after which it must be started before finishing again. It is okay to finish a
    ++ * task before starting it due to different threads handling starting and finishing.</p>
    +  *
    +  * <p>When draining begins, no more new tasks can be started. This guarantees that at some
    +  * point when all the tasks are finished there will be no more collective new tasks,
    +@@ -60,6 +61,11 @@ public class TaskDrainer<T> {
    + 
    +     /** Set of tasks which have been started but not yet finished with #taskFinished */
    +     private final Set<T> mTaskSet = new HashSet<T>();
    ++    /**
    ++     * Set of tasks which have been finished but not yet started with #taskStarted. This may happen
    ++     * if taskStarted and taskFinished are called from two different threads.
    ++     */
    ++    private final Set<T> mEarlyFinishedTaskSet = new HashSet<T>();
    +     private final Object mLock = new Object();
    + 
    +     private boolean mDraining = false;
    +@@ -118,8 +124,12 @@ public class TaskDrainer<T> {
    +                 throw new IllegalStateException("Can't start more tasks after draining has begun");
    +             }
    + 
    +-            if (!mTaskSet.add(task)) {
    +-                throw new IllegalStateException("Task " + task + " was already started");
    ++            // Try to remove the task from the early finished set.
    ++            if (!mEarlyFinishedTaskSet.remove(task)) {
    ++                // The task is not finished early. Add it to the started set.
    ++                if (!mTaskSet.add(task)) {
    ++                    throw new IllegalStateException("Task " + task + " was already started");
    ++                }
    +             }
    +         }
    +     }
    +@@ -128,8 +138,7 @@ public class TaskDrainer<T> {
    +     /**
    +      * Mark an asynchronous task as having finished.
    +      *
    +-     * <p>A task cannot be finished if it hasn't started. Once finished, a task
    +-     * cannot be finished again (unless it's started again).</p>
    ++     * <p>A task cannot be finished more than once without first having started.</p>
    +      *
    +      * @param task a key to identify a task
    +      *
    +@@ -137,7 +146,7 @@ public class TaskDrainer<T> {
    +      * @see #beginDrain
    +      *
    +      * @throws IllegalStateException
    +-     *          If attempting to start a task which is already finished (and not re-started),
    ++     *          If attempting to finish a task which is already finished (and not started),
    +      */
    +     public void taskFinished(T task) {
    +         synchronized (mLock) {
    +@@ -145,8 +154,12 @@ public class TaskDrainer<T> {
    +                 Log.v(TAG + "[" + mName + "]", "taskFinished " + task);
    +             }
    + 
    ++            // Try to remove the task from started set.
    +             if (!mTaskSet.remove(task)) {
    +-                throw new IllegalStateException("Task " + task + " was already finished");
    ++                // Task is not started yet. Add it to the early finished set.
    ++                if (!mEarlyFinishedTaskSet.add(task)) {
    ++                    throw new IllegalStateException("Task " + task + " was already finished");
    ++                }
    +             }
    + 
    +             // If this is the last finished task and draining has already begun, fire #onDrained
    +diff --git a/core/java/android/hardware/location/ContextHubManager.java b/core/java/android/hardware/location/ContextHubManager.java
    +index 0c3d4b3..d4dcacc 100644
    +--- a/core/java/android/hardware/location/ContextHubManager.java
    ++++ b/core/java/android/hardware/location/ContextHubManager.java
    +@@ -123,10 +123,18 @@ public final class ContextHubManager {
    +     /**
    +      * Load a nano app on a specified context hub.
    +      *
    ++     * Note that loading is asynchronous.  When we return from this method,
    ++     * the nano app (probably) hasn't loaded yet.  Assuming a return of 0
    ++     * from this method, then the final success/failure for the load, along
    ++     * with the "handle" for the nanoapp, is all delivered in a byte
    ++     * string via a call to Callback.onMessageReceipt.
    ++     *
    ++     * TODO(b/30784270): Provide a better success/failure and "handle" delivery.
    ++     *
    +      * @param hubHandle handle of context hub to load the app on.
    +      * @param app the nanoApp to load on the hub
    +      *
    +-     * @return int nanoAppInstance of the loaded nanoApp on success,
    ++     * @return 0 if the command for loading was sent to the context hub;
    +      *         -1 otherwise
    +      *
    +      * @see NanoApp
    +@@ -150,9 +158,17 @@ public final class ContextHubManager {
    +     /**
    +      * Unload a specified nanoApp
    +      *
    +-     * @param nanoAppHandle handle of the nanoApp to load
    ++     * Note that unloading is asynchronous.  When we return from this method,
    ++     * the nano app (probably) hasn't unloaded yet.  Assuming a return of 0
    ++     * from this method, then the final success/failure for the unload is
    ++     * delivered in a byte string via a call to Callback.onMessageReceipt.
    ++     *
    ++     * TODO(b/30784270): Provide a better success/failure delivery.
    +      *
    +-     * @return int  0 on success, -1 otherwise
    ++     * @param nanoAppHandle handle of the nanoApp to unload
    ++     *
    ++     * @return 0 if the command for unloading was sent to the context hub;
    ++     *         -1 otherwise
    +      */
    +     public int unloadNanoApp(int nanoAppHandle) {
    +         int retVal = -1;
    +@@ -169,6 +185,24 @@ public final class ContextHubManager {
    +     /**
    +      * get information about the nano app instance
    +      *
    ++     * NOTE: The returned NanoAppInstanceInfo does _not_ contain correct
    ++     * information for several fields, specifically:
    ++     * - getName()
    ++     * - getPublisher()
    ++     * - getNeededExecMemBytes()
    ++     * - getNeededReadMemBytes()
    ++     * - getNeededWriteMemBytes()
    ++     *
    ++     * For example, say you call loadNanoApp() with a NanoApp that has
    ++     * getName() returning "My Name".  Later, if you call getNanoAppInstanceInfo
    ++     * for that nanoapp, the returned NanoAppInstanceInfo's getName()
    ++     * method will claim "Preloaded app, unknown", even though you would
    ++     * have expected "My Name".  For now, as the user, you'll need to
    ++     * separately track the above fields if they are of interest to you.
    ++     *
    ++     * TODO(b/30943489): Have the returned NanoAppInstanceInfo contain the
    ++     *     correct information.
    ++     *
    +      * @param nanoAppHandle handle of the nanoAppInstance
    +      * @return NanoAppInstanceInfo Information about the nano app instance.
    +      *
    +@@ -209,6 +243,14 @@ public final class ContextHubManager {
    +     /**
    +      * Send a message to a specific nano app instance on a context hub.
    +      *
    ++     * Note that the return value of this method only speaks of success
    ++     * up to the point of sending this to the Context Hub.  It is not
    ++     * an assurance that the Context Hub successfully sent this message
    ++     * on to the nanoapp.  If assurance is desired, a protocol should be
    ++     * established between your code and the nanoapp, with the nanoapp
    ++     * sending a confirmation message (which will be reported via
    ++     * Callback.onMessageReceipt).
    ++     *
    +      * @param hubHandle handle of the hub to send the message to
    +      * @param nanoAppHandle  handle of the nano app to send to
    +      * @param message Message to be sent
    +diff --git a/core/java/android/hardware/location/ContextHubService.java b/core/java/android/hardware/location/ContextHubService.java
    +index 062c958..06af461 100644
    +--- a/core/java/android/hardware/location/ContextHubService.java
    ++++ b/core/java/android/hardware/location/ContextHubService.java
    +@@ -18,6 +18,8 @@ package android.hardware.location;
    + 
    + import java.io.FileDescriptor;
    + import java.io.PrintWriter;
    ++import java.nio.ByteBuffer;
    ++import java.nio.ByteOrder;
    + import java.util.ArrayList;
    + import java.util.HashMap;
    + 
    +@@ -146,6 +148,36 @@ public class ContextHubService extends IContextHubService.Stub {
    +         return mContextHubInfo[contextHubHandle];
    +     }
    + 
    ++    // TODO(b/30808791): Remove this when NanoApp's API is correctly treating
    ++    // app IDs as 64-bits.
    ++    private static long parseAppId(NanoApp app) {
    ++        // NOTE: If this shifting seems odd (since it's actually "ONAN"), note
    ++        //     that it matches how this is defined in context_hub.h.
    ++        final int HEADER_MAGIC =
    ++            (((int)'N' <<  0) |
    ++             ((int)'A' <<  8) |
    ++             ((int)'N' << 16) |
    ++             ((int)'O' << 24));
    ++        final int HEADER_MAGIC_OFFSET = 4;
    ++        final int HEADER_APP_ID_OFFSET = 8;
    ++
    ++        ByteBuffer header = ByteBuffer.wrap(app.getAppBinary())
    ++            .order(ByteOrder.LITTLE_ENDIAN);
    ++
    ++        try {
    ++            if (header.getInt(HEADER_MAGIC_OFFSET) == HEADER_MAGIC) {
    ++                // This is a legitimate nanoapp header.  Let's grab the app ID.
    ++                return header.getLong(HEADER_APP_ID_OFFSET);
    ++            }
    ++        } catch (IndexOutOfBoundsException e) {
    ++            // The header is undersized.  We'll fall through to our code
    ++            // path below, which handles being unable to parse the header.
    ++        }
    ++        // We failed to parse the header.  Even through it's probably wrong,
    ++        // let's give NanoApp's idea of our ID.  This is at least consistent.
    ++        return app.getAppId();
    ++    }
    ++
    +     @Override
    +     public int loadNanoApp(int contextHubHandle, NanoApp app) throws RemoteException {
    +         checkPermissions();
    +@@ -162,6 +194,15 @@ public class ContextHubService extends IContextHubService.Stub {
    +         msgHeader[HEADER_FIELD_MSG_TYPE] = MSG_LOAD_NANO_APP;
    + 
    +         long appId = app.getAppId();
    ++        // TODO(b/30808791): Remove this hack when the NanoApp API is fixed,
    ++        //     and getAppId() returns a 'long' instead of an 'int'.
    ++        if ((appId >> 32) != 0) {
    ++            // We're unlikely to notice this warning, but at least
    ++            // we can avoid running our hack logic.
    ++            Log.w(TAG, "Code has not been updated since API fix.");
    ++        } else {
    ++            appId = parseAppId(app);
    ++        }
    + 
    +         msgHeader[HEADER_FIELD_LOAD_APP_ID_LO] = (int)(appId & 0xFFFFFFFF);
    +         msgHeader[HEADER_FIELD_LOAD_APP_ID_HI] = (int)((appId >> 32) & 0xFFFFFFFF);
    +@@ -322,9 +363,16 @@ public class ContextHubService extends IContextHubService.Stub {
    +         appInfo.setNeededReadMemBytes(PRE_LOADED_APP_MEM_REQ);
    +         appInfo.setNeededWriteMemBytes(PRE_LOADED_APP_MEM_REQ);
    + 
    ++        String action;
    ++        if (mNanoAppHash.containsKey(appInstanceHandle)) {
    ++            action = "Updated";
    ++        } else {
    ++            action = "Added";
    ++        }
    ++
    +         mNanoAppHash.put(appInstanceHandle, appInfo);
    +-        Log.d(TAG, "Added app instance " + appInstanceHandle + " with id " + appId
    +-              + " version " + appVersion);
    ++        Log.d(TAG, action + " app instance " + appInstanceHandle + " with id "
    ++              + appId + " version " + appVersion);
    + 
    +         return 0;
    +     }
    +diff --git a/core/java/android/hardware/location/NanoAppFilter.java b/core/java/android/hardware/location/NanoAppFilter.java
    +index 8db70e9..bf35a3d 100644
    +--- a/core/java/android/hardware/location/NanoAppFilter.java
    ++++ b/core/java/android/hardware/location/NanoAppFilter.java
    +@@ -43,7 +43,8 @@ public class NanoAppFilter {
    +     private long mAppIdVendorMask;
    + 
    +     // Id of the context hub this instance is expected on
    +-    private int mContextHubId;
    ++    // TODO: Provide an API which will let us change this HubId.
    ++    private int mContextHubId = HUB_ANY;
    + 
    +     /**
    +      * Flag indicating any version. With this flag set, all versions shall match provided version.
    +diff --git a/core/java/android/hardware/location/NanoAppInstanceInfo.java b/core/java/android/hardware/location/NanoAppInstanceInfo.java
    +index 71a5a88..ac6d83f 100644
    +--- a/core/java/android/hardware/location/NanoAppInstanceInfo.java
    ++++ b/core/java/android/hardware/location/NanoAppInstanceInfo.java
    +@@ -113,7 +113,12 @@ public class NanoAppInstanceInfo {
    +     }
    + 
    +     /**
    +-     * Set the application version
    ++     * Get the application version
    ++     *
    ++     * NOTE: There is a race condition where shortly after loading, this
    ++     * may return -1 instead of the correct version.
    ++     *
    ++     * TODO(b/30970527): Fix this race condition.
    +      *
    +      * @return int - version of the app
    +      */
    +diff --git a/core/java/android/hardware/usb/UsbDeviceConnection.java b/core/java/android/hardware/usb/UsbDeviceConnection.java
    +index c062b3a..893b954 100644
    +--- a/core/java/android/hardware/usb/UsbDeviceConnection.java
    ++++ b/core/java/android/hardware/usb/UsbDeviceConnection.java
    +@@ -16,8 +16,10 @@
    + 
    + package android.hardware.usb;
    + 
    ++import android.annotation.NonNull;
    ++import android.annotation.Nullable;
    ++import android.content.Context;
    + import android.os.ParcelFileDescriptor;
    +-
    + import java.io.FileDescriptor;
    + 
    + 
    +@@ -31,6 +33,8 @@ public class UsbDeviceConnection {
    + 
    +     private final UsbDevice mDevice;
    + 
    ++    private Context mContext;
    ++
    +     // used by the JNI code
    +     private long mNativeContext;
    + 
    +@@ -42,11 +46,22 @@ public class UsbDeviceConnection {
    +         mDevice = device;
    +     }
    + 
    +-    /* package */ boolean open(String name, ParcelFileDescriptor pfd) {
    ++    /* package */ boolean open(String name, ParcelFileDescriptor pfd,  @NonNull Context context) {
    ++        mContext = context.getApplicationContext();
    ++
    +         return native_open(name, pfd.getFileDescriptor());
    +     }
    + 
    +     /**
    ++     * @return The application context the connection was created for.
    ++     *
    ++     * @hide
    ++     */
    ++    public @Nullable Context getContext() {
    ++        return mContext;
    ++    }
    ++
    ++    /**
    +      * Releases all system resources related to the device.
    +      * Once the object is closed it cannot be used again.
    +      * The client must call {@link UsbManager#openDevice} again
    +diff --git a/core/java/android/hardware/usb/UsbManager.java b/core/java/android/hardware/usb/UsbManager.java
    +index 629db06..cb2720a 100644
    +--- a/core/java/android/hardware/usb/UsbManager.java
    ++++ b/core/java/android/hardware/usb/UsbManager.java
    +@@ -330,7 +330,7 @@ public class UsbManager {
    +             ParcelFileDescriptor pfd = mService.openDevice(deviceName);
    +             if (pfd != null) {
    +                 UsbDeviceConnection connection = new UsbDeviceConnection(device);
    +-                boolean result = connection.open(deviceName, pfd);
    ++                boolean result = connection.open(deviceName, pfd, mContext);
    +                 pfd.close();
    +                 if (result) {
    +                     return connection;
    +diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java
    +index b9e9b28..0afb546 100644
    +--- a/core/java/android/net/ConnectivityManager.java
    ++++ b/core/java/android/net/ConnectivityManager.java
    +@@ -1825,6 +1825,16 @@ public class ConnectivityManager {
    +         return (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
    +     }
    + 
    ++    /* TODO: These permissions checks don't belong in client-side code. Move them to
    ++     * services.jar, possibly in com.android.server.net. */
    ++
    ++    /** {@hide} */
    ++    public static final boolean checkChangePermission(Context context) {
    ++        int uid = Binder.getCallingUid();
    ++        return Settings.checkAndNoteChangeNetworkStateOperation(context, uid, Settings
    ++                .getPackageNameForUid(context, uid), false /* throwException */);
    ++    }
    ++
    +     /** {@hide} */
    +     public static final void enforceChangePermission(Context context) {
    +         int uid = Binder.getCallingUid();
    +diff --git a/core/java/android/net/IIpConnectivityMetrics.aidl b/core/java/android/net/IIpConnectivityMetrics.aidl
    +new file mode 100644
    +index 0000000..8f634bb
    +--- /dev/null
    ++++ b/core/java/android/net/IIpConnectivityMetrics.aidl
    +@@ -0,0 +1,29 @@
    ++/*
    ++ * Copyright (C) 2016 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 android.net;
    ++
    ++import android.os.Parcelable;
    ++import android.net.ConnectivityMetricsEvent;
    ++
    ++/** {@hide} */
    ++interface IIpConnectivityMetrics {
    ++
    ++    /**
    ++     * @return number of remaining available slots in buffer.
    ++     */
    ++    int logEvent(in ConnectivityMetricsEvent event);
    ++}
    +diff --git a/core/java/android/net/LocalSocketImpl.java b/core/java/android/net/LocalSocketImpl.java
    +index b83fb26..0f0e9c4 100644
    +--- a/core/java/android/net/LocalSocketImpl.java
    ++++ b/core/java/android/net/LocalSocketImpl.java
    +@@ -516,13 +516,11 @@ class LocalSocketImpl
    +                     Os.setsockoptLinger(fd, OsConstants.SOL_SOCKET, OsConstants.SO_LINGER, linger);
    +                     break;
    +                 case SocketOptions.SO_TIMEOUT:
    +-                    /*
    +-                     * SO_TIMEOUT from the core library gets converted to
    +-                     * SO_SNDTIMEO, but the option is supposed to set both
    +-                     * send and receive timeouts. Note: The incoming timeout
    +-                     * value is in milliseconds.
    +-                     */
    ++                    // The option must set both send and receive timeouts.
    ++                    // Note: The incoming timeout value is in milliseconds.
    +                     StructTimeval timeval = StructTimeval.fromMillis(intValue);
    ++                    Os.setsockoptTimeval(fd, OsConstants.SOL_SOCKET, OsConstants.SO_RCVTIMEO,
    ++                            timeval);
    +                     Os.setsockoptTimeval(fd, OsConstants.SOL_SOCKET, OsConstants.SO_SNDTIMEO,
    +                             timeval);
    +                     break;
    +diff --git a/core/java/android/net/NetworkCapabilities.java b/core/java/android/net/NetworkCapabilities.java
    +index 6243f46..56eba4f 100644
    +--- a/core/java/android/net/NetworkCapabilities.java
    ++++ b/core/java/android/net/NetworkCapabilities.java
    +@@ -182,8 +182,15 @@ public final class NetworkCapabilities implements Parcelable {
    +      */
    +     public static final int NET_CAPABILITY_CAPTIVE_PORTAL = 17;
    + 
    ++    /**
    ++     * Indicates that this network is available for use by apps, and not a network that is being
    ++     * kept up in the background to facilitate fast network switching.
    ++     * @hide
    ++     */
    ++    public static final int NET_CAPABILITY_FOREGROUND = 18;
    ++
    +     private static final int MIN_NET_CAPABILITY = NET_CAPABILITY_MMS;
    +-    private static final int MAX_NET_CAPABILITY = NET_CAPABILITY_CAPTIVE_PORTAL;
    ++    private static final int MAX_NET_CAPABILITY = NET_CAPABILITY_FOREGROUND;
    + 
    +     /**
    +      * Network capabilities that are expected to be mutable, i.e., can change while a particular
    +@@ -194,7 +201,8 @@ public final class NetworkCapabilities implements Parcelable {
    +             // http://b/18206275
    +             (1 << NET_CAPABILITY_TRUSTED) |
    +             (1 << NET_CAPABILITY_VALIDATED) |
    +-            (1 << NET_CAPABILITY_CAPTIVE_PORTAL);
    ++            (1 << NET_CAPABILITY_CAPTIVE_PORTAL) |
    ++            (1 << NET_CAPABILITY_FOREGROUND);
    + 
    +     /**
    +      * Network specifier for factories which want to match any network specifier
    +@@ -217,8 +225,7 @@ public final class NetworkCapabilities implements Parcelable {
    +      * get immediately torn down because they do not have the requested capability.
    +      */
    +     private static final long NON_REQUESTABLE_CAPABILITIES =
    +-            (1 << NET_CAPABILITY_VALIDATED) |
    +-            (1 << NET_CAPABILITY_CAPTIVE_PORTAL);
    ++            MUTABLE_CAPABILITIES & ~(1 << NET_CAPABILITY_TRUSTED);
    + 
    +     /**
    +      * Capabilities that are set by default when the object is constructed.
    +@@ -325,6 +332,7 @@ public final class NetworkCapabilities implements Parcelable {
    +     public String describeFirstNonRequestableCapability() {
    +         if (hasCapability(NET_CAPABILITY_VALIDATED)) return "NET_CAPABILITY_VALIDATED";
    +         if (hasCapability(NET_CAPABILITY_CAPTIVE_PORTAL)) return "NET_CAPABILITY_CAPTIVE_PORTAL";
    ++        if (hasCapability(NET_CAPABILITY_FOREGROUND)) return "NET_CAPABILITY_FOREGROUND";
    +         // This cannot happen unless the preceding checks are incomplete.
    +         if ((mNetworkCapabilities & NON_REQUESTABLE_CAPABILITIES) != 0) {
    +             return "unknown non-requestable capabilities " + Long.toHexString(mNetworkCapabilities);
    +@@ -352,6 +360,11 @@ public final class NetworkCapabilities implements Parcelable {
    +                 (that.mNetworkCapabilities & ~MUTABLE_CAPABILITIES));
    +     }
    + 
    ++    private boolean equalsNetCapabilitiesRequestable(NetworkCapabilities that) {
    ++        return ((this.mNetworkCapabilities & ~NON_REQUESTABLE_CAPABILITIES) ==
    ++                (that.mNetworkCapabilities & ~NON_REQUESTABLE_CAPABILITIES));
    ++    }
    ++
    +     /**
    +      * Removes the NET_CAPABILITY_NOT_RESTRICTED capability if all the capabilities it provides are
    +      * typically provided by restricted networks.
    +@@ -749,6 +762,19 @@ public final class NetworkCapabilities implements Parcelable {
    +                 equalsSpecifier(nc));
    +     }
    + 
    ++    /**
    ++     * Checks that our requestable capabilities are the same as those of the given
    ++     * {@code NetworkCapabilities}.
    ++     *
    ++     * @hide
    ++     */
    ++    public boolean equalRequestableCapabilities(NetworkCapabilities nc) {
    ++        if (nc == null) return false;
    ++        return (equalsNetCapabilitiesRequestable(nc) &&
    ++                equalsTransportTypes(nc) &&
    ++                equalsSpecifier(nc));
    ++    }
    ++
    +     @Override
    +     public boolean equals(Object obj) {
    +         if (obj == null || (obj instanceof NetworkCapabilities == false)) return false;
    +@@ -833,6 +859,7 @@ public final class NetworkCapabilities implements Parcelable {
    +                 case NET_CAPABILITY_NOT_VPN:        capabilities += "NOT_VPN"; break;
    +                 case NET_CAPABILITY_VALIDATED:      capabilities += "VALIDATED"; break;
    +                 case NET_CAPABILITY_CAPTIVE_PORTAL: capabilities += "CAPTIVE_PORTAL"; break;
    ++                case NET_CAPABILITY_FOREGROUND:     capabilities += "FOREGROUND"; break;
    +             }
    +             if (++i < types.length) capabilities += "&";
    +         }
    +diff --git a/core/java/android/net/NetworkIdentity.java b/core/java/android/net/NetworkIdentity.java
    +index 9cd563e..d570e66 100644
    +--- a/core/java/android/net/NetworkIdentity.java
    ++++ b/core/java/android/net/NetworkIdentity.java
    +@@ -175,7 +175,11 @@ public class NetworkIdentity implements Comparable<NetworkIdentity> {
    + 
    +         if (isNetworkTypeMobile(type)) {
    +             if (state.subscriberId == null) {
    +-                Slog.w(TAG, "Active mobile network without subscriber!");
    ++                if (state.networkInfo.getState() != NetworkInfo.State.DISCONNECTED &&
    ++                        state.networkInfo.getState() != NetworkInfo.State.UNKNOWN) {
    ++                    Slog.w(TAG, "Active mobile network without subscriber! ni = "
    ++                            + state.networkInfo);
    ++                }
    +             }
    + 
    +             subscriberId = state.subscriberId;
    +diff --git a/core/java/android/net/NetworkRequest.java b/core/java/android/net/NetworkRequest.java
    +index 4501f7b..ae72470 100644
    +--- a/core/java/android/net/NetworkRequest.java
    ++++ b/core/java/android/net/NetworkRequest.java
    +@@ -49,7 +49,7 @@ public class NetworkRequest implements Parcelable {
    +     public final int legacyType;
    + 
    +     /**
    +-     * A NetworkRequest as used by the system can be one of three types:
    ++     * A NetworkRequest as used by the system can be one of the following types:
    +      *
    +      *     - LISTEN, for which the framework will issue callbacks about any
    +      *       and all networks that match the specified NetworkCapabilities,
    +@@ -64,7 +64,20 @@ public class NetworkRequest implements Parcelable {
    +      *       current network (if any) that matches the capabilities of the
    +      *       default Internet request (mDefaultRequest), but which cannot cause
    +      *       the framework to either create or retain the existence of any
    +-     *       specific network.
    ++     *       specific network. Note that from the point of view of the request
    ++     *       matching code, TRACK_DEFAULT is identical to REQUEST: its special
    ++     *       behaviour is not due to different semantics, but to the fact that
    ++     *       the system will only ever create a TRACK_DEFAULT with capabilities
    ++     *       that are identical to the default request's capabilities, thus
    ++     *       causing it to share fate in every way with the default request.
    ++     *
    ++     *     - BACKGROUND_REQUEST, like REQUEST but does not cause any networks
    ++     *       to retain the NET_CAPABILITY_FOREGROUND capability. A network with
    ++     *       no foreground requests is in the background. A network that has
    ++     *       one or more background requests and loses its last foreground
    ++     *       request to a higher-scoring network will not go into the
    ++     *       background immediately, but will linger and go into the background
    ++     *       after the linger timeout.
    +      *
    +      *     - The value NONE is used only by applications. When an application
    +      *       creates a NetworkRequest, it does not have a type; the type is set
    +@@ -77,7 +90,8 @@ public class NetworkRequest implements Parcelable {
    +         NONE,
    +         LISTEN,
    +         TRACK_DEFAULT,
    +-        REQUEST
    ++        REQUEST,
    ++        BACKGROUND_REQUEST,
    +     };
    + 
    +     /**
    +@@ -140,7 +154,7 @@ public class NetworkRequest implements Parcelable {
    +          * Add the given capability requirement to this builder.  These represent
    +          * the requested network's required capabilities.  Note that when searching
    +          * for a network to satisfy a request, all capabilities requested must be
    +-         * satisfied.  See {@link NetworkCapabilities} for {@code NET_CAPABILITIY_*}
    ++         * satisfied.  See {@link NetworkCapabilities} for {@code NET_CAPABILITY_*}
    +          * definitions.
    +          *
    +          * @param capability The {@code NetworkCapabilities.NET_CAPABILITY_*} to add.
    +@@ -284,7 +298,7 @@ public class NetworkRequest implements Parcelable {
    +         };
    + 
    +     /**
    +-     * Returns true iff. the contained NetworkRequest is of type LISTEN.
    ++     * Returns true iff. this NetworkRequest is of type LISTEN.
    +      *
    +      * @hide
    +      */
    +@@ -298,8 +312,9 @@ public class NetworkRequest implements Parcelable {
    +      *     - should be associated with at most one satisfying network
    +      *       at a time;
    +      *
    +-     *     - should cause a network to be kept up if it is the best network
    +-     *       which can satisfy the NetworkRequest.
    ++     *     - should cause a network to be kept up, but not necessarily in
    ++     *       the foreground, if it is the best network which can satisfy the
    ++     *       NetworkRequest.
    +      *
    +      * For full detail of how isRequest() is used for pairing Networks with
    +      * NetworkRequests read rematchNetworkAndRequests().
    +@@ -307,9 +322,36 @@ public class NetworkRequest implements Parcelable {
    +      * @hide
    +      */
    +     public boolean isRequest() {
    ++        return isForegroundRequest() || isBackgroundRequest();
    ++    }
    ++
    ++    /**
    ++     * Returns true iff. the contained NetworkRequest is one that:
    ++     *
    ++     *     - should be associated with at most one satisfying network
    ++     *       at a time;
    ++     *
    ++     *     - should cause a network to be kept up and in the foreground if
    ++     *       it is the best network which can satisfy the NetworkRequest.
    ++     *
    ++     * For full detail of how isRequest() is used for pairing Networks with
    ++     * NetworkRequests read rematchNetworkAndRequests().
    ++     *
    ++     * @hide
    ++     */
    ++    public boolean isForegroundRequest() {
    +         return type == Type.TRACK_DEFAULT || type == Type.REQUEST;
    +     }
    + 
    ++    /**
    ++     * Returns true iff. this NetworkRequest is of type BACKGROUND_REQUEST.
    ++     *
    ++     * @hide
    ++     */
    ++    public boolean isBackgroundRequest() {
    ++        return type == Type.BACKGROUND_REQUEST;
    ++    }
    ++
    +     public String toString() {
    +         return "NetworkRequest [ " + type + " id=" + requestId +
    +                 (legacyType != ConnectivityManager.TYPE_NONE ? ", legacyType=" + legacyType : "") +
    +diff --git a/core/java/android/net/NetworkStats.java b/core/java/android/net/NetworkStats.java
    +index 25806fa..f65a50f 100644
    +--- a/core/java/android/net/NetworkStats.java
    ++++ b/core/java/android/net/NetworkStats.java
    +@@ -904,7 +904,8 @@ public class NetworkStats implements Parcelable {
    +         if (pool.isEmpty()) {
    +             return true;
    +         }
    +-        Entry moved = addTrafficToApplications(tunIface,  underlyingIface, tunIfaceTotal, pool);
    ++        Entry moved =
    ++                addTrafficToApplications(tunUid, tunIface, underlyingIface, tunIfaceTotal, pool);
    +         deductTrafficFromVpnApp(tunUid, underlyingIface, moved);
    + 
    +         if (!moved.isEmpty()) {
    +@@ -919,9 +920,9 @@ public class NetworkStats implements Parcelable {
    +      * Initializes the data used by the migrateTun() method.
    +      *
    +      * This is the first pass iteration which does the following work:
    +-     * (1) Adds up all the traffic through tun0.
    +-     * (2) Adds up all the traffic through the tunUid's underlyingIface
    ++     * (1) Adds up all the traffic through the tunUid's underlyingIface
    +      *     (both foreground and background).
    ++     * (2) Adds up all the traffic through tun0 excluding traffic from the vpn app itself.
    +      */
    +     private void tunAdjustmentInit(int tunUid, String tunIface, String underlyingIface,
    +             Entry tunIfaceTotal, Entry underlyingIfaceTotal) {
    +@@ -941,8 +942,9 @@ public class NetworkStats implements Parcelable {
    +                 underlyingIfaceTotal.add(recycle);
    +             }
    + 
    +-            if (recycle.tag == TAG_NONE && Objects.equals(tunIface, recycle.iface)) {
    +-                // Add up all tunIface traffic.
    ++            if (recycle.uid != tunUid && recycle.tag == TAG_NONE
    ++                    && Objects.equals(tunIface, recycle.iface)) {
    ++                // Add up all tunIface traffic excluding traffic from the vpn app itself.
    +                 tunIfaceTotal.add(recycle);
    +             }
    +         }
    +@@ -958,13 +960,15 @@ public class NetworkStats implements Parcelable {
    +         return pool;
    +     }
    + 
    +-    private Entry addTrafficToApplications(String tunIface, String underlyingIface,
    ++    private Entry addTrafficToApplications(int tunUid, String tunIface, String underlyingIface,
    +             Entry tunIfaceTotal, Entry pool) {
    +         Entry moved = new Entry();
    +         Entry tmpEntry = new Entry();
    +         tmpEntry.iface = underlyingIface;
    +         for (int i = 0; i < size; i++) {
    +-            if (Objects.equals(iface[i], tunIface)) {
    ++            // the vpn app is excluded from the redistribution but all moved traffic will be
    ++            // deducted from the vpn app (see deductTrafficFromVpnApp below).
    ++            if (Objects.equals(iface[i], tunIface) && uid[i] != tunUid) {
    +                 if (tunIfaceTotal.rxBytes > 0) {
    +                     tmpEntry.rxBytes = pool.rxBytes * rxBytes[i] / tunIfaceTotal.rxBytes;
    +                 } else {
    +diff --git a/core/java/android/net/metrics/DhcpErrorEvent.java b/core/java/android/net/metrics/DhcpErrorEvent.java
    +index 59c5fb6..c3abcf7 100644
    +--- a/core/java/android/net/metrics/DhcpErrorEvent.java
    ++++ b/core/java/android/net/metrics/DhcpErrorEvent.java
    +@@ -50,9 +50,13 @@ public final class DhcpErrorEvent implements Parcelable {
    +     public static final int DHCP_INVALID_OPTION_LENGTH = makeErrorCode(DHCP_ERROR, 3);
    +     public static final int DHCP_NO_MSG_TYPE           = makeErrorCode(DHCP_ERROR, 4);
    +     public static final int DHCP_UNKNOWN_MSG_TYPE      = makeErrorCode(DHCP_ERROR, 5);
    ++    /** {@hide} */
    ++    public static final int DHCP_NO_COOKIE             = makeErrorCode(DHCP_ERROR, 6);
    + 
    +     public static final int BUFFER_UNDERFLOW           = makeErrorCode(MISC_ERROR, 1);
    +     public static final int RECEIVE_ERROR              = makeErrorCode(MISC_ERROR, 2);
    ++    /** {@hide} */
    ++    public static final int PARSING_ERROR              = makeErrorCode(MISC_ERROR, 3);
    + 
    +     public final String ifName;
    +     // error code byte format (MSB to LSB):
    +@@ -115,8 +119,9 @@ public final class DhcpErrorEvent implements Parcelable {
    +     }
    + 
    +     final static class Decoder {
    +-        static final SparseArray<String> constants =
    +-                MessageUtils.findMessageNames(new Class[]{DhcpErrorEvent.class},
    +-                new String[]{"L2_", "L3_", "L4_", "BOOTP_", "DHCP_", "BUFFER_", "RECEIVE_"});
    ++        static final SparseArray<String> constants = MessageUtils.findMessageNames(
    ++                new Class[]{DhcpErrorEvent.class},
    ++                new String[]{"L2_", "L3_", "L4_", "BOOTP_", "DHCP_", "BUFFER_", "RECEIVE_",
    ++                "PARSING_"});
    +     }
    + }
    +diff --git a/core/java/android/net/metrics/IpConnectivityLog.java b/core/java/android/net/metrics/IpConnectivityLog.java
    +index dd7bd1b..173e5fd 100644
    +--- a/core/java/android/net/metrics/IpConnectivityLog.java
    ++++ b/core/java/android/net/metrics/IpConnectivityLog.java
    +@@ -17,63 +17,65 @@
    + package android.net.metrics;
    + 
    + import android.net.ConnectivityMetricsEvent;
    +-import android.net.ConnectivityMetricsLogger;
    +-import android.net.IConnectivityMetricsLogger;
    ++import android.net.IIpConnectivityMetrics;
    + import android.os.Parcelable;
    + import android.os.RemoteException;
    ++import android.os.ServiceManager;
    + import android.util.Log;
    +-
    + import com.android.internal.annotations.VisibleForTesting;
    + 
    + /**
    +- * Specialization of the ConnectivityMetricsLogger class for recording IP connectivity events.
    ++ * Class for logging IpConnectvity events with IpConnectivityMetrics
    +  * {@hide}
    +  */
    +-public class IpConnectivityLog extends ConnectivityMetricsLogger {
    +-    private static String TAG = "IpConnectivityMetricsLogger";
    +-    private static final boolean DBG = true;
    ++public class IpConnectivityLog {
    ++    private static final String TAG = IpConnectivityLog.class.getSimpleName();
    ++    private static final boolean DBG = false;
    ++
    ++    public static final String SERVICE_NAME = "connmetrics";
    ++
    ++    private IIpConnectivityMetrics mService;
    + 
    +     public IpConnectivityLog() {
    +-        // mService initialized in super constructor.
    +     }
    + 
    +     @VisibleForTesting
    +-    public IpConnectivityLog(IConnectivityMetricsLogger service) {
    +-        super(service);
    ++    public IpConnectivityLog(IIpConnectivityMetrics service) {
    ++        mService = service;
    ++    }
    ++
    ++    private boolean checkLoggerService() {
    ++        if (mService != null) {
    ++            return true;
    ++        }
    ++        final IIpConnectivityMetrics service =
    ++                IIpConnectivityMetrics.Stub.asInterface(ServiceManager.getService(SERVICE_NAME));
    ++        if (service == null) {
    ++            return false;
    ++        }
    ++        // Two threads racing here will write the same pointer because getService
    ++        // is idempotent once MetricsLoggerService is initialized.
    ++        mService = service;
    ++        return true;
    +     }
    + 
    +     /**
    +-     * Log an IpConnectivity event. Contrary to logEvent(), this method does not
    +-     * keep track of skipped events and is thread-safe for callers.
    +-     *
    ++     * Log an IpConnectivity event.
    +      * @param timestamp is the epoch timestamp of the event in ms.
    +      * @param data is a Parcelable instance representing the event.
    +-     *
    +      * @return true if the event was successfully logged.
    +      */
    +     public boolean log(long timestamp, Parcelable data) {
    +         if (!checkLoggerService()) {
    +             if (DBG) {
    +-                Log.d(TAG, CONNECTIVITY_METRICS_LOGGER_SERVICE + " service was not ready");
    +-            }
    +-            return false;
    +-        }
    +-
    +-        if (System.currentTimeMillis() < mServiceUnblockedTimestampMillis) {
    +-            if (DBG) {
    +-                Log.d(TAG, "skipping logging due to throttling for IpConnectivity component");
    ++                Log.d(TAG, SERVICE_NAME + " service was not ready");
    +             }
    +             return false;
    +         }
    + 
    +         try {
    +-            final ConnectivityMetricsEvent event =
    +-                new ConnectivityMetricsEvent(timestamp, COMPONENT_TAG_CONNECTIVITY, 0, data);
    +-            final long result = mService.logEvent(event);
    +-            if (result >= 0) {
    +-                mServiceUnblockedTimestampMillis = result;
    +-            }
    +-            return (result == 0);
    ++            int left = mService.logEvent(new ConnectivityMetricsEvent(timestamp, 0, 0, data));
    ++            return left >= 0;
    +         } catch (RemoteException e) {
    +             Log.e(TAG, "Error logging event", e);
    +             return false;
    +diff --git a/core/java/android/net/metrics/ValidationProbeEvent.java b/core/java/android/net/metrics/ValidationProbeEvent.java
    +index 331cf0c..1a31b56 100644
    +--- a/core/java/android/net/metrics/ValidationProbeEvent.java
    ++++ b/core/java/android/net/metrics/ValidationProbeEvent.java
    +@@ -34,10 +34,12 @@ import java.lang.annotation.RetentionPolicy;
    + @SystemApi
    + public final class ValidationProbeEvent implements Parcelable {
    + 
    +-    public static final int PROBE_DNS   = 0;
    +-    public static final int PROBE_HTTP  = 1;
    +-    public static final int PROBE_HTTPS = 2;
    +-    public static final int PROBE_PAC   = 3;
    ++    public static final int PROBE_DNS       = 0;
    ++    public static final int PROBE_HTTP      = 1;
    ++    public static final int PROBE_HTTPS     = 2;
    ++    public static final int PROBE_PAC       = 3;
    ++    /** {@hide} */
    ++    public static final int PROBE_FALLBACK  = 4;
    + 
    +     public static final int DNS_FAILURE = 0;
    +     public static final int DNS_SUCCESS = 1;
    +@@ -57,7 +59,7 @@ public final class ValidationProbeEvent implements Parcelable {
    +     public final @ProbeType int probeType;
    +     public final @ReturnCode int returnCode;
    + 
    +-    /** @hide */
    ++    /** {@hide} */
    +     public ValidationProbeEvent(
    +             int netId, long durationMs, @ProbeType int probeType, @ReturnCode int returnCode) {
    +         this.netId = netId;
    +diff --git a/core/java/android/os/AsyncTask.java b/core/java/android/os/AsyncTask.java
    +index 4f4e722..fea64ec 100644
    +--- a/core/java/android/os/AsyncTask.java
    ++++ b/core/java/android/os/AsyncTask.java
    +@@ -298,12 +298,19 @@ public abstract class AsyncTask<Params, Progress, Result> {
    +         mWorker = new WorkerRunnable<Params, Result>() {
    +             public Result call() throws Exception {
    +                 mTaskInvoked.set(true);
    +-
    +-                Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
    +-                //noinspection unchecked
    +-                Result result = doInBackground(mParams);
    +-                Binder.flushPendingCommands();
    +-                return postResult(result);
    ++                Result result = null;
    ++                try {
    ++                    Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
    ++                    //noinspection unchecked
    ++                    result = doInBackground(mParams);
    ++                    Binder.flushPendingCommands();
    ++                } catch (Throwable tr) {
    ++                    mCancelled.set(true);
    ++                    throw tr;
    ++                } finally {
    ++                    postResult(result);
    ++                }
    ++                return result;
    +             }
    +         };
    + 
    +diff --git a/core/java/android/os/Build.java b/core/java/android/os/Build.java
    +index 3d3dc9c..151239b 100644
    +--- a/core/java/android/os/Build.java
    ++++ b/core/java/android/os/Build.java
    +@@ -709,6 +709,14 @@ public class Build {
    +          * {@link android.widget.LinearLayout.LayoutParams LinearLayout.LayoutParams} to
    +          * {@link android.widget.RelativeLayout.LayoutParams RelativeLayout.LayoutParams}).</li>
    +          * <li>Your application processes will not be killed when the device density changes.</li>
    ++         * <li>Drag and drop. After a view receives the
    ++         * {@link android.view.DragEvent#ACTION_DRAG_ENTERED} event, when the drag shadow moves into
    ++         * a descendant view that can accept the data, the view receives the
    ++         * {@link android.view.DragEvent#ACTION_DRAG_EXITED} event and won’t receive
    ++         * {@link android.view.DragEvent#ACTION_DRAG_LOCATION} and
    ++         * {@link android.view.DragEvent#ACTION_DROP} events while the drag shadow is within that
    ++         * descendant view, even if the descendant view returns <code>false</code> from its handler
    ++         * for these events.</li>
    +          * </ul>
    +          */
    +         public static final int N = 24;
    +diff --git a/core/java/android/os/Bundle.java b/core/java/android/os/Bundle.java
    +index ca64a96..62fa772 100644
    +--- a/core/java/android/os/Bundle.java
    ++++ b/core/java/android/os/Bundle.java
    +@@ -309,25 +309,49 @@ public final class Bundle extends BaseBundle implements Cloneable, Parcelable {
    +      * Filter values in Bundle to only basic types.
    +      * @hide
    +      */
    +-    public void filterValues() {
    ++    public Bundle filterValues() {
    +         unparcel();
    ++        Bundle bundle = this;
    +         if (mMap != null) {
    +-            for (int i = mMap.size() - 1; i >= 0; i--) {
    +-                Object value = mMap.valueAt(i);
    ++            ArrayMap<String, Object> map = mMap;
    ++            for (int i = map.size() - 1; i >= 0; i--) {
    ++                Object value = map.valueAt(i);
    +                 if (PersistableBundle.isValidType(value)) {
    +                     continue;
    +                 }
    +                 if (value instanceof Bundle) {
    +-                    ((Bundle)value).filterValues();
    ++                    Bundle newBundle = ((Bundle)value).filterValues();
    ++                    if (newBundle != value) {
    ++                        if (map == mMap) {
    ++                            // The filter had to generate a new bundle, but we have not yet
    ++                            // created a new one here.  Do that now.
    ++                            bundle = new Bundle(this);
    ++                            // Note the ArrayMap<> constructor is guaranteed to generate
    ++                            // a new object with items in the same order as the original.
    ++                            map = bundle.mMap;
    ++                        }
    ++                        // Replace this current entry with the new child bundle.
    ++                        map.setValueAt(i, newBundle);
    ++                    }
    ++                    continue;
    +                 }
    +                 if (value.getClass().getName().startsWith("android.")) {
    +                     continue;
    +                 }
    +-                mMap.removeAt(i);
    ++                if (map == mMap) {
    ++                    // This is the first time we have had to remove something, that means we
    ++                    // need to switch to a new Bundle.
    ++                    bundle = new Bundle(this);
    ++                    // Note the ArrayMap<> constructor is guaranteed to generate
    ++                    // a new object with items in the same order as the original.
    ++                    map = bundle.mMap;
    ++                }
    ++                map.removeAt(i);
    +             }
    +         }
    +         mFlags |= FLAG_HAS_FDS_KNOWN;
    +         mFlags &= ~FLAG_HAS_FDS;
    ++        return bundle;
    +     }
    + 
    +     /**
    +diff --git a/core/java/android/os/FileObserver.java b/core/java/android/os/FileObserver.java
    +index 4e705e0..dd85e15 100644
    +--- a/core/java/android/os/FileObserver.java
    ++++ b/core/java/android/os/FileObserver.java
    +@@ -16,6 +16,7 @@
    + 
    + package android.os;
    + 
    ++import android.annotation.Nullable;
    + import android.util.Log;
    + 
    + import java.lang.ref.WeakReference;
    +@@ -204,7 +205,8 @@ public abstract class FileObserver {
    +      *
    +      * @param event The type of event which happened
    +      * @param path The path, relative to the main monitored file or directory,
    +-     *     of the file or directory which triggered the event
    ++     *     of the file or directory which triggered the event.  This value can
    ++     *     be {@code null} for certain events, such as {@link #MOVE_SELF}.
    +      */
    +-    public abstract void onEvent(int event, String path);
    ++    public abstract void onEvent(int event, @Nullable String path);
    + }
    +diff --git a/core/java/android/os/FileUtils.java b/core/java/android/os/FileUtils.java
    +index fa32848..8e24caf 100644
    +--- a/core/java/android/os/FileUtils.java
    ++++ b/core/java/android/os/FileUtils.java
    +@@ -605,6 +605,22 @@ public class FileUtils {
    +         return null;
    +     }
    + 
    ++    private static File buildUniqueFileWithExtension(File parent, String name, String ext)
    ++            throws FileNotFoundException {
    ++        File file = buildFile(parent, name, ext);
    ++
    ++        // If conflicting file, try adding counter suffix
    ++        int n = 0;
    ++        while (file.exists()) {
    ++            if (n++ >= 32) {
    ++                throw new FileNotFoundException("Failed to create unique file");
    ++            }
    ++            file = buildFile(parent, name + " (" + n + ")", ext);
    ++        }
    ++
    ++        return file;
    ++    }
    ++
    +     /**
    +      * Generates a unique file name under the given parent directory. If the display name doesn't
    +      * have an extension that matches the requested MIME type, the default extension for that MIME
    +@@ -619,20 +635,29 @@ public class FileUtils {
    +     public static File buildUniqueFile(File parent, String mimeType, String displayName)
    +             throws FileNotFoundException {
    +         final String[] parts = splitFileName(mimeType, displayName);
    +-        final String name = parts[0];
    +-        final String ext = parts[1];
    +-        File file = buildFile(parent, name, ext);
    ++        return buildUniqueFileWithExtension(parent, parts[0], parts[1]);
    ++    }
    + 
    +-        // If conflicting file, try adding counter suffix
    +-        int n = 0;
    +-        while (file.exists()) {
    +-            if (n++ >= 32) {
    +-                throw new FileNotFoundException("Failed to create unique file");
    +-            }
    +-            file = buildFile(parent, name + " (" + n + ")", ext);
    ++    /**
    ++     * Generates a unique file name under the given parent directory, keeping
    ++     * any extension intact.
    ++     */
    ++    public static File buildUniqueFile(File parent, String displayName)
    ++            throws FileNotFoundException {
    ++        final String name;
    ++        final String ext;
    ++
    ++        // Extract requested extension from display name
    ++        final int lastDot = displayName.lastIndexOf('.');
    ++        if (lastDot >= 0) {
    ++            name = displayName.substring(0, lastDot);
    ++            ext = displayName.substring(lastDot + 1);
    ++        } else {
    ++            name = displayName;
    ++            ext = null;
    +         }
    + 
    +-        return file;
    ++        return buildUniqueFileWithExtension(parent, name, ext);
    +     }
    + 
    +     /**
    +diff --git a/core/java/android/os/IRecoverySystem.aidl b/core/java/android/os/IRecoverySystem.aidl
    +index 12830a4..c5ceecd 100644
    +--- a/core/java/android/os/IRecoverySystem.aidl
    ++++ b/core/java/android/os/IRecoverySystem.aidl
    +@@ -25,4 +25,5 @@ interface IRecoverySystem {
    +     boolean uncrypt(in String packageFile, IRecoverySystemProgressListener listener);
    +     boolean setupBcb(in String command);
    +     boolean clearBcb();
    ++    void rebootRecoveryWithCommand(in String command);
    + }
    +diff --git a/core/java/android/os/PatternMatcher.java b/core/java/android/os/PatternMatcher.java
    +index 56dc837..3890fbf 100644
    +--- a/core/java/android/os/PatternMatcher.java
    ++++ b/core/java/android/os/PatternMatcher.java
    +@@ -16,6 +16,10 @@
    + 
    + package android.os;
    + 
    ++import android.util.Log;
    ++
    ++import java.util.Arrays;
    ++
    + /**
    +  * A simple pattern matcher, which is safe to use on untrusted data: it does
    +  * not provide full reg-exp support, only simple globbing that can not be
    +@@ -44,13 +48,59 @@ public class PatternMatcher implements Parcelable {
    +      * wildcard part of a normal regexp. 
    +      */
    +     public static final int PATTERN_SIMPLE_GLOB = 2;
    +-    
    ++
    ++    /**
    ++     * Pattern type: the given pattern is interpreted with a regular
    ++     * expression-like syntax for matching against the string it is tested
    ++     * against. Supported tokens include dot ({@code .}) and sets ({@code [...]})
    ++     * with full support for character ranges and the not ({@code ^}) modifier.
    ++     * Supported modifiers include star ({@code *}) for zero-or-more, plus ({@code +})
    ++     * for one-or-more and full range ({@code {...}}) support. This is a simple
    ++     * evaulation implementation in which matching is done against the pattern in
    ++     * realtime with no backtracking support.
    ++     *
    ++     * {@hide} Pending approval for public API
    ++     */
    ++    public static final int PATTERN_ADVANCED_GLOB = 3;
    ++
    ++    // token types for advanced matching
    ++    private static final int TOKEN_TYPE_LITERAL = 0;
    ++    private static final int TOKEN_TYPE_ANY = 1;
    ++    private static final int TOKEN_TYPE_SET = 2;
    ++    private static final int TOKEN_TYPE_INVERSE_SET = 3;
    ++
    ++    // Return for no match
    ++    private static final int NO_MATCH = -1;
    ++
    ++    private static final String TAG = "PatternMatcher";
    ++
    ++    // Parsed placeholders for advanced patterns
    ++    private static final int PARSED_TOKEN_CHAR_SET_START = -1;
    ++    private static final int PARSED_TOKEN_CHAR_SET_INVERSE_START = -2;
    ++    private static final int PARSED_TOKEN_CHAR_SET_STOP = -3;
    ++    private static final int PARSED_TOKEN_CHAR_ANY = -4;
    ++    private static final int PARSED_MODIFIER_RANGE_START = -5;
    ++    private static final int PARSED_MODIFIER_RANGE_STOP = -6;
    ++    private static final int PARSED_MODIFIER_ZERO_OR_MORE = -7;
    ++    private static final int PARSED_MODIFIER_ONE_OR_MORE = -8;
    ++
    +     private final String mPattern;
    +     private final int mType;
    +-    
    ++    private final int[] mParsedPattern;
    ++
    ++
    ++    private static final int MAX_PATTERN_STORAGE = 2048;
    ++    // workspace to use for building a parsed advanced pattern;
    ++    private static final int[] sParsedPatternScratch = new int[MAX_PATTERN_STORAGE];
    ++
    +     public PatternMatcher(String pattern, int type) {
    +         mPattern = pattern;
    +         mType = type;
    ++        if (mType == PATTERN_ADVANCED_GLOB) {
    ++            mParsedPattern = parseAndVerifyAdvancedPattern(pattern);
    ++        } else {
    ++            mParsedPattern = null;
    ++        }
    +     }
    + 
    +     public final String getPath() {
    +@@ -62,7 +112,7 @@ public class PatternMatcher implements Parcelable {
    +     }
    +     
    +     public boolean match(String str) {
    +-        return matchPattern(mPattern, str, mType);
    ++        return matchPattern(str, mPattern, mParsedPattern, mType);
    +     }
    + 
    +     public String toString() {
    +@@ -77,6 +127,9 @@ public class PatternMatcher implements Parcelable {
    +             case PATTERN_SIMPLE_GLOB:
    +                 type = "GLOB: ";
    +                 break;
    ++            case PATTERN_ADVANCED_GLOB:
    ++                type = "ADVANCED: ";
    ++                break;
    +         }
    +         return "PatternMatcher{" + type + mPattern + "}";
    +     }
    +@@ -88,11 +141,13 @@ public class PatternMatcher implements Parcelable {
    +     public void writeToParcel(Parcel dest, int flags) {
    +         dest.writeString(mPattern);
    +         dest.writeInt(mType);
    ++        dest.writeIntArray(mParsedPattern);
    +     }
    +     
    +     public PatternMatcher(Parcel src) {
    +         mPattern = src.readString();
    +         mType = src.readInt();
    ++        mParsedPattern = src.createIntArray();
    +     }
    +     
    +     public static final Parcelable.Creator<PatternMatcher> CREATOR
    +@@ -106,16 +161,21 @@ public class PatternMatcher implements Parcelable {
    +         }
    +     };
    +     
    +-    static boolean matchPattern(String pattern, String match, int type) {
    ++    static boolean matchPattern(String match, String pattern, int[] parsedPattern, int type) {
    +         if (match == null) return false;
    +         if (type == PATTERN_LITERAL) {
    +             return pattern.equals(match);
    +         } if (type == PATTERN_PREFIX) {
    +             return match.startsWith(pattern);
    +-        } else if (type != PATTERN_SIMPLE_GLOB) {
    +-            return false;
    ++        } else if (type == PATTERN_SIMPLE_GLOB) {
    ++            return matchGlobPattern(pattern, match);
    ++        } else if (type == PATTERN_ADVANCED_GLOB) {
    ++            return matchAdvancedPattern(parsedPattern, match);
    +         }
    +-        
    ++        return false;
    ++    }
    ++
    ++    static boolean matchGlobPattern(String pattern, String match) {
    +         final int NP = pattern.length();
    +         if (NP <= 0) {
    +             return match.length() <= 0;
    +@@ -194,4 +254,310 @@ public class PatternMatcher implements Parcelable {
    +         
    +         return false;
    +     }
    +-}
    ++
    ++    /**
    ++     * Parses the advanced pattern and returns an integer array representation of it. The integer
    ++     * array treats each field as a character if positive and a unique token placeholder if
    ++     * negative. This method will throw on any pattern structure violations.
    ++     */
    ++    synchronized static int[] parseAndVerifyAdvancedPattern(String pattern) {
    ++        int ip = 0;
    ++        final int LP = pattern.length();
    ++
    ++        int it = 0;
    ++
    ++        boolean inSet = false;
    ++        boolean inRange = false;
    ++        boolean inCharClass = false;
    ++
    ++        boolean addToParsedPattern;
    ++
    ++        while (ip < LP) {
    ++            if (it > MAX_PATTERN_STORAGE - 3) {
    ++                throw new IllegalArgumentException("Pattern is too large!");
    ++            }
    ++
    ++            char c = pattern.charAt(ip);
    ++            addToParsedPattern = false;
    ++
    ++            switch (c) {
    ++                case '[':
    ++                    if (inSet) {
    ++                        addToParsedPattern = true; // treat as literal or char class in set
    ++                    } else {
    ++                        if (pattern.charAt(ip + 1) == '^') {
    ++                            sParsedPatternScratch[it++] = PARSED_TOKEN_CHAR_SET_INVERSE_START;
    ++                            ip++; // skip over the '^'
    ++                        } else {
    ++                            sParsedPatternScratch[it++] = PARSED_TOKEN_CHAR_SET_START;
    ++                        }
    ++                        ip++; // move to the next pattern char
    ++                        inSet = true;
    ++                        continue;
    ++                    }
    ++                    break;
    ++                case ']':
    ++                    if (!inSet) {
    ++                        addToParsedPattern = true; // treat as literal outside of set
    ++                    } else {
    ++                        int parsedToken = sParsedPatternScratch[it - 1];
    ++                        if (parsedToken == PARSED_TOKEN_CHAR_SET_START ||
    ++                            parsedToken == PARSED_TOKEN_CHAR_SET_INVERSE_START) {
    ++                            throw new IllegalArgumentException(
    ++                                    "You must define characters in a set.");
    ++                        }
    ++                        sParsedPatternScratch[it++] = PARSED_TOKEN_CHAR_SET_STOP;
    ++                        inSet = false;
    ++                        inCharClass = false;
    ++                    }
    ++                    break;
    ++                case '{':
    ++                    if (!inSet) {
    ++                        if (it == 0 || isParsedModifier(sParsedPatternScratch[it - 1])) {
    ++                            throw new IllegalArgumentException("Modifier must follow a token.");
    ++                        }
    ++                        sParsedPatternScratch[it++] = PARSED_MODIFIER_RANGE_START;
    ++                        ip++;
    ++                        inRange = true;
    ++                    }
    ++                    break;
    ++                case '}':
    ++                    if (inRange) { // only terminate the range if we're currently in one
    ++                        sParsedPatternScratch[it++] = PARSED_MODIFIER_RANGE_STOP;
    ++                        inRange = false;
    ++                    }
    ++                    break;
    ++                case '*':
    ++                    if (!inSet) {
    ++                        if (it == 0 || isParsedModifier(sParsedPatternScratch[it - 1])) {
    ++                            throw new IllegalArgumentException("Modifier must follow a token.");
    ++                        }
    ++                        sParsedPatternScratch[it++] = PARSED_MODIFIER_ZERO_OR_MORE;
    ++                    }
    ++                    break;
    ++                case '+':
    ++                    if (!inSet) {
    ++                        if (it == 0 || isParsedModifier(sParsedPatternScratch[it - 1])) {
    ++                            throw new IllegalArgumentException("Modifier must follow a token.");
    ++                        }
    ++                        sParsedPatternScratch[it++] = PARSED_MODIFIER_ONE_OR_MORE;
    ++                    }
    ++                    break;
    ++                case '.':
    ++                    if (!inSet) {
    ++                        sParsedPatternScratch[it++] = PARSED_TOKEN_CHAR_ANY;
    ++                    }
    ++                    break;
    ++                case '\\': // escape
    ++                    if (ip + 1 >= LP) {
    ++                        throw new IllegalArgumentException("Escape found at end of pattern!");
    ++                    }
    ++                    c = pattern.charAt(++ip);
    ++                    addToParsedPattern = true;
    ++                    break;
    ++                default:
    ++                    addToParsedPattern = true;
    ++                    break;
    ++            }
    ++            if (inSet) {
    ++                if (inCharClass) {
    ++                    sParsedPatternScratch[it++] = c;
    ++                    inCharClass = false;
    ++                } else {
    ++                    // look forward for character class
    ++                    if (ip + 2 < LP
    ++                            && pattern.charAt(ip + 1) == '-'
    ++                            && pattern.charAt(ip + 2) != ']') {
    ++                        inCharClass = true;
    ++                        sParsedPatternScratch[it++] = c; // set first token as lower end of range
    ++                        ip++; // advance past dash
    ++                    } else { // literal
    ++                        sParsedPatternScratch[it++] = c; // set first token as literal
    ++                        sParsedPatternScratch[it++] = c; // set second set as literal
    ++                    }
    ++                }
    ++            } else if (inRange) {
    ++                int endOfSet = pattern.indexOf('}', ip);
    ++                if (endOfSet < 0) {
    ++                    throw new IllegalArgumentException("Range not ended with '}'");
    ++                }
    ++                String rangeString = pattern.substring(ip, endOfSet);
    ++                int commaIndex = rangeString.indexOf(',');
    ++                try {
    ++                    final int rangeMin;
    ++                    final int rangeMax;
    ++                    if (commaIndex < 0) {
    ++                        int parsedRange = Integer.parseInt(rangeString);
    ++                        rangeMin = rangeMax = parsedRange;
    ++                    } else {
    ++                        rangeMin = Integer.parseInt(rangeString.substring(0, commaIndex));
    ++                        if (commaIndex == rangeString.length() - 1) { // e.g. {n,} (n or more)
    ++                            rangeMax = Integer.MAX_VALUE;
    ++                        } else {
    ++                            rangeMax = Integer.parseInt(rangeString.substring(commaIndex + 1));
    ++                        }
    ++                    }
    ++                    if (rangeMin > rangeMax) {
    ++                        throw new IllegalArgumentException(
    ++                            "Range quantifier minimum is greater than maximum");
    ++                    }
    ++                    sParsedPatternScratch[it++] = rangeMin;
    ++                    sParsedPatternScratch[it++] = rangeMax;
    ++                } catch (NumberFormatException e) {
    ++                    throw new IllegalArgumentException("Range number format incorrect", e);
    ++                }
    ++                ip = endOfSet;
    ++                continue; // don't increment ip
    ++            } else if (addToParsedPattern) {
    ++                sParsedPatternScratch[it++] = c;
    ++            }
    ++            ip++;
    ++        }
    ++        if (inSet) {
    ++            throw new IllegalArgumentException("Set was not terminated!");
    ++        }
    ++        return Arrays.copyOf(sParsedPatternScratch, it);
    ++    }
    ++
    ++    private static boolean isParsedModifier(int parsedChar) {
    ++        return parsedChar == PARSED_MODIFIER_ONE_OR_MORE ||
    ++                parsedChar == PARSED_MODIFIER_ZERO_OR_MORE ||
    ++                parsedChar == PARSED_MODIFIER_RANGE_STOP ||
    ++                parsedChar == PARSED_MODIFIER_RANGE_START;
    ++    }
    ++
    ++    static boolean matchAdvancedPattern(int[] parsedPattern, String match) {
    ++
    ++        // create indexes
    ++        int ip = 0, im = 0;
    ++
    ++        // one-time length check
    ++        final int LP = parsedPattern.length, LM = match.length();
    ++
    ++        // The current character being analyzed in the pattern
    ++        int patternChar;
    ++
    ++        int tokenType;
    ++
    ++        int charSetStart = 0, charSetEnd = 0;
    ++
    ++        while (ip < LP) { // we still have content in the pattern
    ++
    ++            patternChar = parsedPattern[ip];
    ++            // get the match type of the next verb
    ++
    ++            switch (patternChar) {
    ++                case PARSED_TOKEN_CHAR_ANY:
    ++                    tokenType = TOKEN_TYPE_ANY;
    ++                    ip++;
    ++                    break;
    ++                case PARSED_TOKEN_CHAR_SET_START:
    ++                case PARSED_TOKEN_CHAR_SET_INVERSE_START:
    ++                    tokenType = patternChar == PARSED_TOKEN_CHAR_SET_START
    ++                            ? TOKEN_TYPE_SET
    ++                            : TOKEN_TYPE_INVERSE_SET;
    ++                    charSetStart = ip + 1; // start from the char after the set start
    ++                    while (++ip < LP && parsedPattern[ip] != PARSED_TOKEN_CHAR_SET_STOP);
    ++                    charSetEnd = ip - 1; // we're on the set stop, end is the previous
    ++                    ip++; // move the pointer to the next pattern entry
    ++                    break;
    ++                default:
    ++                    charSetStart = ip;
    ++                    tokenType = TOKEN_TYPE_LITERAL;
    ++                    ip++;
    ++                    break;
    ++            }
    ++
    ++            final int minRepetition;
    ++            final int maxRepetition;
    ++
    ++            // look for a match length modifier
    ++            if (ip >= LP) {
    ++                minRepetition = maxRepetition = 1;
    ++            } else {
    ++                patternChar = parsedPattern[ip];
    ++                switch (patternChar) {
    ++                    case PARSED_MODIFIER_ZERO_OR_MORE:
    ++                        minRepetition = 0;
    ++                        maxRepetition = Integer.MAX_VALUE;
    ++                        ip++;
    ++                        break;
    ++                    case PARSED_MODIFIER_ONE_OR_MORE:
    ++                        minRepetition = 1;
    ++                        maxRepetition = Integer.MAX_VALUE;
    ++                        ip++;
    ++                        break;
    ++                    case PARSED_MODIFIER_RANGE_START:
    ++                        minRepetition = parsedPattern[++ip];
    ++                        maxRepetition = parsedPattern[++ip];
    ++                        ip += 2; // step over PARSED_MODIFIER_RANGE_STOP and on to the next token
    ++                        break;
    ++                    default:
    ++                        minRepetition = maxRepetition = 1; // implied literal
    ++                        break;
    ++                }
    ++            }
    ++            if (minRepetition > maxRepetition) {
    ++                return false;
    ++            }
    ++
    ++            // attempt to match as many characters as possible
    ++            int matched = matchChars(match, im, LM, tokenType, minRepetition, maxRepetition,
    ++                    parsedPattern, charSetStart, charSetEnd);
    ++
    ++            // if we found a conflict, return false immediately
    ++            if (matched == NO_MATCH) {
    ++                return false;
    ++            }
    ++
    ++            // move the match pointer the number of characters matched
    ++            im += matched;
    ++        }
    ++        return ip >= LP && im >= LM; // have parsed entire string and regex
    ++    }
    ++
    ++    private static int matchChars(String match, int im, final int lm, int tokenType,
    ++            int minRepetition, int maxRepetition, int[] parsedPattern,
    ++            int tokenStart, int tokenEnd) {
    ++        int matched = 0;
    ++
    ++        while(matched < maxRepetition
    ++                && matchChar(match, im + matched, lm, tokenType, parsedPattern, tokenStart,
    ++                    tokenEnd)) {
    ++            matched++;
    ++        }
    ++
    ++        return matched < minRepetition ? NO_MATCH : matched;
    ++    }
    ++
    ++    private static boolean matchChar(String match, int im, final int lm, int tokenType,
    ++            int[] parsedPattern, int tokenStart, int tokenEnd) {
    ++        if (im >= lm) { // we've overrun the string, no match
    ++            return false;
    ++        }
    ++        switch (tokenType) {
    ++            case TOKEN_TYPE_ANY:
    ++                return true;
    ++            case TOKEN_TYPE_SET:
    ++                for (int i = tokenStart; i < tokenEnd; i += 2) {
    ++                    char matchChar = match.charAt(im);
    ++                    if (matchChar >= parsedPattern[i] && matchChar <= parsedPattern[i + 1]) {
    ++                        return true;
    ++                    }
    ++                }
    ++                return false;
    ++            case TOKEN_TYPE_INVERSE_SET:
    ++                for (int i = tokenStart; i < tokenEnd; i += 2) {
    ++                    char matchChar = match.charAt(im);
    ++                    if (matchChar >= parsedPattern[i] && matchChar <= parsedPattern[i + 1]) {
    ++                        return false;
    ++                    }
    ++                }
    ++                return true;
    ++            case TOKEN_TYPE_LITERAL:
    ++                return match.charAt(im) == parsedPattern[tokenStart];
    ++            default:
    ++                return false;
    ++        }
    ++    }
    ++}
    +\ No newline at end of file
    +diff --git a/core/java/android/os/PowerManager.java b/core/java/android/os/PowerManager.java
    +index ce7a124..8d4d0a5 100644
    +--- a/core/java/android/os/PowerManager.java
    ++++ b/core/java/android/os/PowerManager.java
    +@@ -1340,6 +1340,11 @@ public final class PowerManager {
    +         }
    + 
    +         /** @hide */
    ++        public String getTag() {
    ++            return mTag;
    ++        }
    ++
    ++        /** @hide */
    +         public void setHistoryTag(String tag) {
    +             mHistoryTag = tag;
    +         }
    +@@ -1358,5 +1363,34 @@ public final class PowerManager {
    +                     + " held=" + mHeld + ", refCount=" + mCount + "}";
    +             }
    +         }
    ++
    ++        /**
    ++         * Wraps a Runnable such that this method immediately acquires the wake lock and then
    ++         * once the Runnable is done the wake lock is released.
    ++         *
    ++         * <p>Example:
    ++         *
    ++         * <pre>
    ++         * mHandler.post(mWakeLock.wrap(() -> {
    ++         *     // do things on handler, lock is held while we're waiting for this
    ++         *     // to get scheduled and until the runnable is done executing.
    ++         * });
    ++         * </pre>
    ++         *
    ++         * <p>Note: you must make sure that the Runnable eventually gets executed, otherwise you'll
    ++         *    leak the wakelock!
    ++         *
    ++         * @hide
    ++         */
    ++        public Runnable wrap(Runnable r) {
    ++            acquire();
    ++            return () -> {
    ++                try {
    ++                    r.run();
    ++                } finally {
    ++                    release();
    ++                }
    ++            };
    ++        }
    +     }
    + }
    +diff --git a/core/java/android/os/RecoverySystem.java b/core/java/android/os/RecoverySystem.java
    +index 507379b..d48431a 100644
    +--- a/core/java/android/os/RecoverySystem.java
    ++++ b/core/java/android/os/RecoverySystem.java
    +@@ -93,6 +93,14 @@ public class RecoverySystem {
    +      */
    +     public static final File UNCRYPT_PACKAGE_FILE = new File(RECOVERY_DIR, "uncrypt_file");
    + 
    ++    /**
    ++     * UNCRYPT_STATUS_FILE stores the time cost (and error code in the case of a failure)
    ++     * of uncrypt.
    ++     *
    ++     * @hide
    ++     */
    ++    public static final File UNCRYPT_STATUS_FILE = new File(RECOVERY_DIR, "uncrypt_status");
    ++
    +     // Length limits for reading files.
    +     private static final int LOG_FILE_MAX_LENGTH = 64 * 1024;
    + 
    +@@ -692,28 +700,22 @@ public class RecoverySystem {
    +      * @throws IOException if something goes wrong.
    +      */
    +     private static void bootCommand(Context context, String... args) throws IOException {
    +-        synchronized (sRequestLock) {
    +-            LOG_FILE.delete();
    ++        LOG_FILE.delete();
    + 
    +-            StringBuilder command = new StringBuilder();
    +-            for (String arg : args) {
    +-                if (!TextUtils.isEmpty(arg)) {
    +-                    command.append(arg);
    +-                    command.append("\n");
    +-                }
    ++        StringBuilder command = new StringBuilder();
    ++        for (String arg : args) {
    ++            if (!TextUtils.isEmpty(arg)) {
    ++                command.append(arg);
    ++                command.append("\n");
    +             }
    ++        }
    + 
    +-            // Write the command into BCB (bootloader control block).
    +-            RecoverySystem rs = (RecoverySystem) context.getSystemService(
    +-                    Context.RECOVERY_SERVICE);
    +-            rs.setupBcb(command.toString());
    +-
    +-            // Having set up the BCB, go ahead and reboot.
    +-            PowerManager pm = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
    +-            pm.reboot(PowerManager.REBOOT_RECOVERY);
    ++        // Write the command into BCB (bootloader control block) and boot from
    ++        // there. Will not return unless failed.
    ++        RecoverySystem rs = (RecoverySystem) context.getSystemService(Context.RECOVERY_SERVICE);
    ++        rs.rebootRecoveryWithCommand(command.toString());
    + 
    +-            throw new IOException("Reboot failed (no permissions?)");
    +-        }
    ++        throw new IOException("Reboot failed (no permissions?)");
    +     }
    + 
    +     // Read last_install; then report time (in seconds) and I/O (in MiB) for
    +@@ -724,6 +726,7 @@ public class RecoverySystem {
    +             String line = null;
    +             int bytesWrittenInMiB = -1, bytesStashedInMiB = -1;
    +             int timeTotal = -1;
    ++            int uncryptTime = -1;
    +             int sourceVersion = -1;
    +             while ((line = in.readLine()) != null) {
    +                 // Here is an example of lines in last_install:
    +@@ -759,6 +762,8 @@ public class RecoverySystem {
    + 
    +                 if (line.startsWith("time")) {
    +                     timeTotal = scaled;
    ++                } else if (line.startsWith("uncrypt_time")) {
    ++                    uncryptTime = scaled;
    +                 } else if (line.startsWith("source_build")) {
    +                     sourceVersion = scaled;
    +                 } else if (line.startsWith("bytes_written")) {
    +@@ -774,6 +779,9 @@ public class RecoverySystem {
    +             if (timeTotal != -1) {
    +                 MetricsLogger.histogram(context, "ota_time_total", timeTotal);
    +             }
    ++            if (uncryptTime != -1) {
    ++                MetricsLogger.histogram(context, "ota_uncrypt_time", uncryptTime);
    ++            }
    +             if (sourceVersion != -1) {
    +                 MetricsLogger.histogram(context, "ota_source_version", sourceVersion);
    +             }
    +@@ -902,6 +910,17 @@ public class RecoverySystem {
    +     }
    + 
    +     /**
    ++     * Talks to RecoverySystemService via Binder to set up the BCB command and
    ++     * reboot into recovery accordingly.
    ++     */
    ++    private void rebootRecoveryWithCommand(String command) {
    ++        try {
    ++            mService.rebootRecoveryWithCommand(command);
    ++        } catch (RemoteException ignored) {
    ++        }
    ++    }
    ++
    ++    /**
    +      * Internally, recovery treats each line of the command file as a separate
    +      * argv, so we only need to protect against newlines and nulls.
    +      */
    +diff --git a/core/java/android/os/RemoteCallbackList.java b/core/java/android/os/RemoteCallbackList.java
    +index 5849350..3546e17 100644
    +--- a/core/java/android/os/RemoteCallbackList.java
    ++++ b/core/java/android/os/RemoteCallbackList.java
    +@@ -288,20 +288,22 @@ public class RemoteCallbackList<E extends IInterface> {
    +      * @see #beginBroadcast
    +      */
    +     public void finishBroadcast() {
    +-        if (mBroadcastCount < 0) {
    +-            throw new IllegalStateException(
    +-                    "finishBroadcast() called outside of a broadcast");
    +-        }
    +-        
    +-        Object[] active = mActiveBroadcast;
    +-        if (active != null) {
    +-            final int N = mBroadcastCount;
    +-            for (int i=0; i<N; i++) {
    +-                active[i] = null;
    ++        synchronized (mCallbacks) {
    ++            if (mBroadcastCount < 0) {
    ++                throw new IllegalStateException(
    ++                        "finishBroadcast() called outside of a broadcast");
    +             }
    ++
    ++            Object[] active = mActiveBroadcast;
    ++            if (active != null) {
    ++                final int N = mBroadcastCount;
    ++                for (int i=0; i<N; i++) {
    ++                    active[i] = null;
    ++                }
    ++            }
    ++
    ++            mBroadcastCount = -1;
    +         }
    +-        
    +-        mBroadcastCount = -1;
    +     }
    + 
    +     /**
    +diff --git a/core/java/android/os/Trace.java b/core/java/android/os/Trace.java
    +index 9e8103a..3ae28fd 100644
    +--- a/core/java/android/os/Trace.java
    ++++ b/core/java/android/os/Trace.java
    +@@ -81,6 +81,8 @@ public final class Trace {
    +     public static final long TRACE_TAG_SYSTEM_SERVER = 1L << 19;
    +     /** @hide */
    +     public static final long TRACE_TAG_DATABASE = 1L << 20;
    ++    /** @hide */
    ++    public static final long TRACE_TAG_NETWORK = 1L << 21;
    + 
    +     private static final long TRACE_TAG_NOT_READY = 1L << 63;
    +     private static final int MAX_SECTION_NAME_LEN = 127;
    +diff --git a/core/java/android/os/storage/VolumeInfo.java b/core/java/android/os/storage/VolumeInfo.java
    +index 5a98482..19210b5 100644
    +--- a/core/java/android/os/storage/VolumeInfo.java
    ++++ b/core/java/android/os/storage/VolumeInfo.java
    +@@ -437,7 +437,7 @@ public class VolumeInfo implements Parcelable {
    + 
    +         final Intent intent = new Intent(DocumentsContract.ACTION_BROWSE);
    +         intent.addCategory(Intent.CATEGORY_DEFAULT);
    +-        intent.setData(uri);
    ++        intent.setDataAndType(uri, DocumentsContract.Root.MIME_TYPE_ITEM);
    + 
    +         // note that docsui treats this as *force* show advanced. So sending
    +         // false permits advanced to be shown based on user preferences.
    +diff --git a/core/java/android/provider/CallLog.java b/core/java/android/provider/CallLog.java
    +index fbd61cf..c7c6ceb 100644
    +--- a/core/java/android/provider/CallLog.java
    ++++ b/core/java/android/provider/CallLog.java
    +@@ -284,8 +284,10 @@ public class CallLog {
    + 
    +         /**
    +          * The cached name associated with the phone number, if it exists.
    +-         * This value is not guaranteed to be current, if the contact information
    +-         * associated with this number has changed.
    ++         *
    ++         * <p>This value is typically filled in by the dialer app for the caching purpose,
    ++         * so it's not guaranteed to be present, and may not be current if the contact
    ++         * information associated with this number has changed.
    +          * <P>Type: TEXT</P>
    +          */
    +         public static final String CACHED_NAME = "name";
    +@@ -293,8 +295,10 @@ public class CallLog {
    +         /**
    +          * The cached number type (Home, Work, etc) associated with the
    +          * phone number, if it exists.
    +-         * This value is not guaranteed to be current, if the contact information
    +-         * associated with this number has changed.
    ++         *
    ++         * <p>This value is typically filled in by the dialer app for the caching purpose,
    ++         * so it's not guaranteed to be present, and may not be current if the contact
    ++         * information associated with this number has changed.
    +          * <P>Type: INTEGER</P>
    +          */
    +         public static final String CACHED_NUMBER_TYPE = "numbertype";
    +@@ -302,8 +306,10 @@ public class CallLog {
    +         /**
    +          * The cached number label, for a custom number type, associated with the
    +          * phone number, if it exists.
    +-         * This value is not guaranteed to be current, if the contact information
    +-         * associated with this number has changed.
    ++         *
    ++         * <p>This value is typically filled in by the dialer app for the caching purpose,
    ++         * so it's not guaranteed to be present, and may not be current if the contact
    ++         * information associated with this number has changed.
    +          * <P>Type: TEXT</P>
    +          */
    +         public static final String CACHED_NUMBER_LABEL = "numberlabel";
    +@@ -339,40 +345,50 @@ public class CallLog {
    + 
    +         /**
    +          * The cached URI to look up the contact associated with the phone number, if it exists.
    +-         * This value may not be current if the contact information associated with this number
    +-         * has changed.
    ++         *
    ++         * <p>This value is typically filled in by the dialer app for the caching purpose,
    ++         * so it's not guaranteed to be present, and may not be current if the contact
    ++         * information associated with this number has changed.
    +          * <P>Type: TEXT</P>
    +          */
    +         public static final String CACHED_LOOKUP_URI = "lookup_uri";
    + 
    +         /**
    +          * The cached phone number of the contact which matches this entry, if it exists.
    +-         * This value may not be current if the contact information associated with this number
    +-         * has changed.
    ++         *
    ++         * <p>This value is typically filled in by the dialer app for the caching purpose,
    ++         * so it's not guaranteed to be present, and may not be current if the contact
    ++         * information associated with this number has changed.
    +          * <P>Type: TEXT</P>
    +          */
    +         public static final String CACHED_MATCHED_NUMBER = "matched_number";
    + 
    +         /**
    +          * The cached normalized(E164) version of the phone number, if it exists.
    +-         * This value may not be current if the contact information associated with this number
    +-         * has changed.
    ++         *
    ++         * <p>This value is typically filled in by the dialer app for the caching purpose,
    ++         * so it's not guaranteed to be present, and may not be current if the contact
    ++         * information associated with this number has changed.
    +          * <P>Type: TEXT</P>
    +          */
    +         public static final String CACHED_NORMALIZED_NUMBER = "normalized_number";
    + 
    +         /**
    +          * The cached photo id of the picture associated with the phone number, if it exists.
    +-         * This value may not be current if the contact information associated with this number
    +-         * has changed.
    ++         *
    ++         * <p>This value is typically filled in by the dialer app for the caching purpose,
    ++         * so it's not guaranteed to be present, and may not be current if the contact
    ++         * information associated with this number has changed.
    +          * <P>Type: INTEGER (long)</P>
    +          */
    +         public static final String CACHED_PHOTO_ID = "photo_id";
    + 
    +         /**
    +          * The cached photo URI of the picture associated with the phone number, if it exists.
    +-         * This value may not be current if the contact information associated with this number
    +-         * has changed.
    ++         *
    ++         * <p>This value is typically filled in by the dialer app for the caching purpose,
    ++         * so it's not guaranteed to be present, and may not be current if the contact
    ++         * information associated with this number has changed.
    +          * <P>Type: TEXT (URI)</P>
    +          */
    +         public static final String CACHED_PHOTO_URI = "photo_uri";
    +@@ -380,9 +396,10 @@ public class CallLog {
    +         /**
    +          * The cached phone number, formatted with formatting rules based on the country the
    +          * user was in when the call was made or received.
    +-         * This value is not guaranteed to be present, and may not be current if the contact
    +-         * information associated with this number
    +-         * has changed.
    ++         *
    ++         * <p>This value is typically filled in by the dialer app for the caching purpose,
    ++         * so it's not guaranteed to be present, and may not be current if the contact
    ++         * information associated with this number has changed.
    +          * <P>Type: TEXT</P>
    +          */
    +         public static final String CACHED_FORMATTED_NUMBER = "formatted_number";
    +diff --git a/core/java/android/provider/ContactsContract.java b/core/java/android/provider/ContactsContract.java
    +index c70304e..c495e6c 100644
    +--- a/core/java/android/provider/ContactsContract.java
    ++++ b/core/java/android/provider/ContactsContract.java
    +@@ -35,6 +35,7 @@ import android.content.Intent;
    + import android.content.res.AssetFileDescriptor;
    + import android.content.res.Resources;
    + import android.database.Cursor;
    ++import android.database.CursorWrapper;
    + import android.database.DatabaseUtils;
    + import android.graphics.Rect;
    + import android.net.Uri;
    +@@ -138,8 +139,20 @@ public final class ContactsContract {
    +     public static final String DIRECTORY_PARAM_KEY = "directory";
    + 
    +     /**
    +-     * A query parameter that limits the number of results returned. The
    ++     * A query parameter that limits the number of results returned for supported URIs. The
    +      * parameter value should be an integer.
    ++     *
    ++     * <p>This parameter is not supported by all URIs.  Supported URIs include, but not limited to,
    ++     * {@link Contacts#CONTENT_URI},
    ++     * {@link RawContacts#CONTENT_URI},
    ++     * {@link Data#CONTENT_URI},
    ++     * {@link CommonDataKinds.Phone#CONTENT_URI},
    ++     * {@link CommonDataKinds.Callable#CONTENT_URI},
    ++     * {@link CommonDataKinds.Email#CONTENT_URI},
    ++     * {@link CommonDataKinds.Contactables#CONTENT_URI},
    ++     *
    ++     * <p>In order to limit the number of rows returned by a non-supported URI, you can implement a
    ++     * {@link CursorWrapper} and override the {@link CursorWrapper#getCount()} methods.
    +      */
    +     public static final String LIMIT_PARAM_KEY = "limit";
    + 
    +@@ -437,6 +450,9 @@ public final class ContactsContract {
    + 
    +         /**
    +          * _ID of the default directory, which represents locally stored contacts.
    ++         * <b>This is only supported by {@link ContactsContract.Contacts#CONTENT_URI} and
    ++         * {@link ContactsContract.Contacts#CONTENT_FILTER_URI}.
    ++         * Other URLs do not support the concept of "visible" or "invisible" contacts.
    +          */
    +         public static final long DEFAULT = 0;
    + 
    +diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
    +index ce6fcdd..8bb6942 100755
    +--- a/core/java/android/provider/Settings.java
    ++++ b/core/java/android/provider/Settings.java
    +@@ -44,7 +44,6 @@ import android.net.ConnectivityManager;
    + import android.net.Uri;
    + import android.net.wifi.WifiManager;
    + import android.os.BatteryManager;
    +-import android.os.Binder;
    + import android.os.Bundle;
    + import android.os.DropBoxManager;
    + import android.os.IBinder;
    +@@ -1284,6 +1283,19 @@ public final class Settings {
    +             = "android.settings.VR_LISTENER_SETTINGS";
    + 
    +     /**
    ++     * Activity Action: Show Storage Manager settings.
    ++     * <p>
    ++     * Input: Nothing.
    ++     * <p>
    ++     * Output: Nothing.
    ++     *
    ++     * @hide
    ++     */
    ++    @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
    ++    public static final String ACTION_STORAGE_MANAGER_SETTINGS
    ++            = "android.settings.STORAGE_MANAGER_SETTINGS";
    ++
    ++    /**
    +      * Activity Action: Allows user to select current webview implementation.
    +      * <p>
    +      * Input: Nothing.
    +@@ -1838,7 +1850,6 @@ public final class Settings {
    +             MOVED_TO_GLOBAL.add(Settings.Global.CALL_AUTO_RETRY);
    +             MOVED_TO_GLOBAL.add(Settings.Global.DEBUG_APP);
    +             MOVED_TO_GLOBAL.add(Settings.Global.WAIT_FOR_DEBUGGER);
    +-            MOVED_TO_GLOBAL.add(Settings.Global.SHOW_PROCESSES);
    +             MOVED_TO_GLOBAL.add(Settings.Global.ALWAYS_FINISH_ACTIVITIES);
    +             MOVED_TO_GLOBAL.add(Settings.Global.TZINFO_UPDATE_CONTENT_URL);
    +             MOVED_TO_GLOBAL.add(Settings.Global.TZINFO_UPDATE_METADATA_URL);
    +@@ -2775,7 +2786,8 @@ public final class Settings {
    +         /**
    +          * Control whether the process CPU usage meter should be shown.
    +          *
    +-         * @deprecated Use {@link Global#SHOW_PROCESSES} instead
    ++         * @deprecated This functionality is no longer available as of
    ++         * {@link android.os.Build.VERSION_CODES#N_MR1}.
    +          */
    +         @Deprecated
    +         public static final String SHOW_PROCESSES = Global.SHOW_PROCESSES;
    +@@ -5839,6 +5851,8 @@ public final class Settings {
    +         /**
    +          * If nonzero, ANRs in invisible background processes bring up a dialog.
    +          * Otherwise, the process will be silently killed.
    ++         *
    ++         * Also prevents ANRs and crash dialogs from being suppressed.
    +          * @hide
    +          */
    +         public static final String ANR_SHOW_BACKGROUND = "anr_show_background";
    +@@ -5927,6 +5941,18 @@ public final class Settings {
    +         public static final String DOZE_ENABLED = "doze_enabled";
    + 
    +         /**
    ++         * Whether the device should pulse on pick up gesture.
    ++         * @hide
    ++         */
    ++        public static final String DOZE_PULSE_ON_PICK_UP = "doze_pulse_on_pick_up";
    ++
    ++        /**
    ++         * Whether the device should pulse on double tap gesture.
    ++         * @hide
    ++         */
    ++        public static final String DOZE_PULSE_ON_DOUBLE_TAP = "doze_pulse_on_double_tap";
    ++
    ++        /**
    +          * The current night mode that has been selected by the user.  Owned
    +          * and controlled by UiModeManagerService.  Constants are as per
    +          * UiModeManager.
    +@@ -6324,6 +6350,13 @@ public final class Settings {
    +                 = "demo_user_setup_complete";
    + 
    +         /**
    ++         * Specifies whether the web action API is enabled.
    ++         *
    ++         * @hide
    ++         */
    ++        public static final String WEB_ACTION_ENABLED = "web_action_enabled";
    ++
    ++        /**
    +          * This are the settings to be backed up.
    +          *
    +          * NOTE: Settings are backed up and restored in the order they appear
    +@@ -6404,6 +6437,9 @@ public final class Settings {
    +             CAMERA_DOUBLE_TAP_POWER_GESTURE_DISABLED,
    +             SYSTEM_NAVIGATION_KEYS_ENABLED,
    +             QS_TILES,
    ++            DOZE_ENABLED,
    ++            DOZE_PULSE_ON_PICK_UP,
    ++            DOZE_PULSE_ON_DOUBLE_TAP
    +         };
    + 
    +         /**
    +@@ -7924,12 +7960,37 @@ public final class Settings {
    +         /**
    +          * The server used for captive portal detection upon a new conection. A
    +          * 204 response code from the server is used for validation.
    ++         * TODO: remove this deprecated symbol.
    +          *
    +          * @hide
    +          */
    +         public static final String CAPTIVE_PORTAL_SERVER = "captive_portal_server";
    + 
    +         /**
    ++         * The URL used for HTTPS captive portal detection upon a new connection.
    ++         * A 204 response code from the server is used for validation.
    ++         *
    ++         * @hide
    ++         */
    ++        public static final String CAPTIVE_PORTAL_HTTPS_URL = "captive_portal_https_url";
    ++
    ++        /**
    ++         * The URL used for HTTP captive portal detection upon a new connection.
    ++         * A 204 response code from the server is used for validation.
    ++         *
    ++         * @hide
    ++         */
    ++        public static final String CAPTIVE_PORTAL_HTTP_URL = "captive_portal_http_url";
    ++
    ++        /**
    ++         * The URL used for fallback HTTP captive portal detection when previous HTTP
    ++         * and HTTPS captive portal detection attemps did not return a conclusive answer.
    ++         *
    ++         * @hide
    ++         */
    ++        public static final String CAPTIVE_PORTAL_FALLBACK_URL = "captive_portal_fallback_url";
    ++
    ++        /**
    +          * Whether to use HTTPS for network validation. This is enabled by default and the setting
    +          * needs to be set to 0 to disable it. This setting is a misnomer because captive portals
    +          * don't actually use HTTPS, but it's consistent with the other settings.
    +@@ -7939,6 +8000,14 @@ public final class Settings {
    +         public static final String CAPTIVE_PORTAL_USE_HTTPS = "captive_portal_use_https";
    + 
    +         /**
    ++         * Which User-Agent string to use in the header of the captive portal detection probes.
    ++         * The User-Agent field is unset when this setting has no value (HttpUrlConnection default).
    ++         *
    ++         * @hide
    ++         */
    ++        public static final String CAPTIVE_PORTAL_USER_AGENT = "captive_portal_user_agent";
    ++
    ++        /**
    +          * Whether network service discovery is enabled.
    +          *
    +          * @hide
    +@@ -8311,6 +8380,13 @@ public final class Settings {
    +         public static final String CALL_AUTO_RETRY = "call_auto_retry";
    + 
    +         /**
    ++         * A setting that can be read whether the emergency affordance is currently needed.
    ++         * The value is a boolean (1 or 0).
    ++         * @hide
    ++         */
    ++        public static final String EMERGENCY_AFFORDANCE_NEEDED = "emergency_affordance_needed";
    ++
    ++        /**
    +          * See RIL_PreferredNetworkType in ril.h
    +          * @hide
    +          */
    +@@ -8330,7 +8406,11 @@ public final class Settings {
    + 
    +         /**
    +          * Control whether the process CPU usage meter should be shown.
    ++         *
    ++         * @deprecated This functionality is no longer available as of
    ++         * {@link android.os.Build.VERSION_CODES#N_MR1}.
    +          */
    ++        @Deprecated
    +         public static final String SHOW_PROCESSES = "show_processes";
    + 
    +         /**
    +@@ -8642,7 +8722,7 @@ public final class Settings {
    +         public static final String WFC_IMS_ENABLED = "wfc_ims_enabled";
    + 
    +         /**
    +-         * WFC Mode.
    ++         * WFC mode on home/non-roaming network.
    +          * <p>
    +          * Type: int - 2=Wi-Fi preferred, 1=Cellular preferred, 0=Wi-Fi only
    +          *
    +@@ -8651,6 +8731,15 @@ public final class Settings {
    +         public static final String WFC_IMS_MODE = "wfc_ims_mode";
    + 
    +         /**
    ++         * WFC mode on roaming network.
    ++         * <p>
    ++         * Type: int - see {@link WFC_IMS_MODE} for values
    ++         *
    ++         * @hide
    ++         */
    ++        public static final String WFC_IMS_ROAMING_MODE = "wfc_ims_roaming_mode";
    ++
    ++        /**
    +          * Whether WFC roaming is enabled
    +          * <p>
    +          * Type: int (0 for false, 1 for true)
    +@@ -8678,6 +8767,16 @@ public final class Settings {
    +                 "ephemeral_cookie_max_size_bytes";
    + 
    +         /**
    ++         * Toggle to enable/disable the entire ephemeral feature. By default, ephemeral is
    ++         * enabled. Set to zero to disable.
    ++         * <p>
    ++         * Type: int (0 for false, 1 for true)
    ++         *
    ++         * @hide
    ++         */
    ++        public static final String ENABLE_EPHEMERAL_FEATURE = "enable_ephemeral_feature";
    ++
    ++        /**
    +          * A mask applied to the ephemeral hash to generate the hash prefix.
    +          * <p>
    +          * Type: int
    +@@ -8756,6 +8855,16 @@ public final class Settings {
    +         public static final String RETAIL_DEMO_MODE_CONSTANTS = "retail_demo_mode_constants";
    + 
    +         /**
    ++         * The reason for the settings database being downgraded. This is only for
    ++         * troubleshooting purposes and its value should not be interpreted in any way.
    ++         *
    ++         * Type: string
    ++         *
    ++         * @hide
    ++         */
    ++        public static final String DATABASE_DOWNGRADE_REASON = "database_downgrade_reason";
    ++
    ++        /**
    +          * Settings to backup. This is here so that it's in the same place as the settings
    +          * keys and easy to update.
    +          *
    +diff --git a/core/java/android/security/net/config/DirectoryCertificateSource.java b/core/java/android/security/net/config/DirectoryCertificateSource.java
    +index e3c9d65..119f5d0 100644
    +--- a/core/java/android/security/net/config/DirectoryCertificateSource.java
    ++++ b/core/java/android/security/net/config/DirectoryCertificateSource.java
    +@@ -19,6 +19,7 @@ package android.security.net.config;
    + import android.os.Environment;
    + import android.os.UserHandle;
    + import android.util.ArraySet;
    ++import android.util.Log;
    + import android.util.Pair;
    + import java.io.BufferedInputStream;
    + import java.io.File;
    +@@ -44,6 +45,7 @@ import javax.security.auth.x500.X500Principal;
    +  * @hide
    +  */
    + abstract class DirectoryCertificateSource implements CertificateSource {
    ++    private static final String LOG_TAG = "DirectoryCertificateSrc";
    +     private final File mDir;
    +     private final Object mLock = new Object();
    +     private final CertificateFactory mCertFactory;
    +@@ -149,6 +151,9 @@ abstract class DirectoryCertificateSource implements CertificateSource {
    +                 continue;
    +             }
    +             X509Certificate cert = readCertificate(fileName);
    ++            if (cert == null) {
    ++                continue;
    ++            }
    +             if (!subj.equals(cert.getSubjectX500Principal())) {
    +                 continue;
    +             }
    +@@ -173,6 +178,9 @@ abstract class DirectoryCertificateSource implements CertificateSource {
    +                 continue;
    +             }
    +             X509Certificate cert = readCertificate(fileName);
    ++            if (cert == null) {
    ++                continue;
    ++            }
    +             if (!subj.equals(cert.getSubjectX500Principal())) {
    +                 continue;
    +             }
    +@@ -194,6 +202,7 @@ abstract class DirectoryCertificateSource implements CertificateSource {
    +             is = new BufferedInputStream(new FileInputStream(new File(mDir, file)));
    +             return (X509Certificate) mCertFactory.generateCertificate(is);
    +         } catch (CertificateException | IOException e) {
    ++            Log.e(LOG_TAG, "Failed to read certificate from " + file, e);
    +             return null;
    +         } finally {
    +             IoUtils.closeQuietly(is);
    +diff --git a/core/java/android/service/dreams/DreamService.java b/core/java/android/service/dreams/DreamService.java
    +index 0557d13..94505d3 100644
    +--- a/core/java/android/service/dreams/DreamService.java
    ++++ b/core/java/android/service/dreams/DreamService.java
    +@@ -27,6 +27,7 @@ import android.graphics.PixelFormat;
    + import android.graphics.drawable.ColorDrawable;
    + import android.os.Handler;
    + import android.os.IBinder;
    ++import android.os.IRemoteCallback;
    + import android.os.PowerManager;
    + import android.os.RemoteException;
    + import android.os.ServiceManager;
    +@@ -942,8 +943,9 @@ public class DreamService extends Service implements Window.Callback {
    +      * Must run on mHandler.
    +      *
    +      * @param windowToken A window token that will allow a window to be created in the correct layer.
    ++     * @param started A callback that will be invoked once onDreamingStarted has completed.
    +      */
    +-    private final void attach(IBinder windowToken, boolean canDoze) {
    ++    private final void attach(IBinder windowToken, boolean canDoze, IRemoteCallback started) {
    +         if (mWindowToken != null) {
    +             Slog.e(TAG, "attach() called when already attached with token=" + mWindowToken);
    +             return;
    +@@ -1017,7 +1019,15 @@ public class DreamService extends Service implements Window.Callback {
    +                 if (mWindow != null || mWindowless) {
    +                     if (mDebug) Slog.v(TAG, "Calling onDreamingStarted()");
    +                     mStarted = true;
    +-                    onDreamingStarted();
    ++                    try {
    ++                        onDreamingStarted();
    ++                    } finally {
    ++                        try {
    ++                            started.sendResult(null);
    ++                        } catch (RemoteException e) {
    ++                            throw e.rethrowFromSystemServer();
    ++                        }
    ++                    }
    +                 }
    +             }
    +         });
    +@@ -1092,11 +1102,12 @@ public class DreamService extends Service implements Window.Callback {
    + 
    +     private final class DreamServiceWrapper extends IDreamService.Stub {
    +         @Override
    +-        public void attach(final IBinder windowToken, final boolean canDoze) {
    ++        public void attach(final IBinder windowToken, final boolean canDoze,
    ++                IRemoteCallback started) {
    +             mHandler.post(new Runnable() {
    +                 @Override
    +                 public void run() {
    +-                    DreamService.this.attach(windowToken, canDoze);
    ++                    DreamService.this.attach(windowToken, canDoze, started);
    +                 }
    +             });
    +         }
    +diff --git a/core/java/android/service/dreams/IDreamService.aidl b/core/java/android/service/dreams/IDreamService.aidl
    +index 9bb1804..ce04354 100644
    +--- a/core/java/android/service/dreams/IDreamService.aidl
    ++++ b/core/java/android/service/dreams/IDreamService.aidl
    +@@ -16,11 +16,13 @@
    + 
    + package android.service.dreams;
    + 
    ++import android.os.IRemoteCallback;
    ++
    + /**
    +  * @hide
    +  */
    + oneway interface IDreamService {
    +-    void attach(IBinder windowToken, boolean canDoze);
    ++    void attach(IBinder windowToken, boolean canDoze, IRemoteCallback started);
    +     void detach();
    +     void wakeUp();
    + }
    +diff --git a/core/java/android/util/DisplayMetrics.java b/core/java/android/util/DisplayMetrics.java
    +index f4db4d6..b7099b6 100644
    +--- a/core/java/android/util/DisplayMetrics.java
    ++++ b/core/java/android/util/DisplayMetrics.java
    +@@ -268,6 +268,10 @@ public class DisplayMetrics {
    +     }
    +     
    +     public void setTo(DisplayMetrics o) {
    ++        if (this == o) {
    ++            return;
    ++        }
    ++
    +         widthPixels = o.widthPixels;
    +         heightPixels = o.heightPixels;
    +         density = o.density;
    +diff --git a/core/java/android/util/PackageUtils.java b/core/java/android/util/PackageUtils.java
    +new file mode 100644
    +index 0000000..6531aef
    +--- /dev/null
    ++++ b/core/java/android/util/PackageUtils.java
    +@@ -0,0 +1,96 @@
    ++/*
    ++ * Copyright (C) 2016 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 android.util;
    ++
    ++import android.annotation.NonNull;
    ++import android.annotation.Nullable;
    ++import android.content.pm.PackageInfo;
    ++import android.content.pm.PackageManager;
    ++import android.content.pm.Signature;
    ++
    ++import java.security.MessageDigest;
    ++import java.security.NoSuchAlgorithmException;
    ++
    ++/**
    ++ * Helper functions applicable to packages.
    ++ * @hide
    ++ */
    ++public final class PackageUtils {
    ++    private final static char[] HEX_ARRAY = "0123456789ABCDEF".toCharArray();
    ++
    ++    private PackageUtils() {
    ++        /* hide constructor */
    ++    }
    ++
    ++    /**
    ++     * Computes the SHA256 digest of the signing cert for a package.
    ++     * @param packageManager The package manager.
    ++     * @param packageName The package for which to generate the digest.
    ++     * @param userId The user for which to generate the digest.
    ++     * @return The digest or null if the package does not exist for this user.
    ++     */
    ++    public static @Nullable String computePackageCertSha256Digest(
    ++            @NonNull PackageManager packageManager,
    ++            @NonNull String packageName, int userId) {
    ++        final PackageInfo packageInfo;
    ++        try {
    ++            packageInfo = packageManager.getPackageInfoAsUser(packageName,
    ++                    PackageManager.GET_SIGNATURES, userId);
    ++        } catch (PackageManager.NameNotFoundException e) {
    ++            return null;
    ++        }
    ++        return computeCertSha256Digest(packageInfo.signatures[0]);
    ++    }
    ++
    ++    /**
    ++     * Computes the SHA256 digest of a cert.
    ++     * @param signature The signature.
    ++     * @return The digest or null if an error occurs.
    ++     */
    ++    public static @Nullable String computeCertSha256Digest(@NonNull Signature signature) {
    ++        return computeSha256Digest(signature.toByteArray());
    ++    }
    ++
    ++    /**
    ++     * Computes the SHA256 digest of some data.
    ++     * @param data The data.
    ++     * @return The digest or null if an error occurs.
    ++     */
    ++    public static @Nullable String computeSha256Digest(@NonNull byte[] data) {
    ++        MessageDigest messageDigest;
    ++        try {
    ++            messageDigest = MessageDigest.getInstance("SHA256");
    ++        } catch (NoSuchAlgorithmException e) {
    ++            /* can't happen */
    ++            return null;
    ++        }
    ++
    ++        messageDigest.update(data);
    ++
    ++        final byte[] digest = messageDigest.digest();
    ++        final int digestLength = digest.length;
    ++        final int charCount = 2 * digestLength;
    ++
    ++        final char[] chars = new char[charCount];
    ++        for (int i = 0; i < digestLength; i++) {
    ++            final int byteHex = digest[i] & 0xFF;
    ++            chars[i * 2] = HEX_ARRAY[byteHex >>> 4];
    ++            chars[i * 2 + 1] = HEX_ARRAY[byteHex & 0x0F];
    ++        }
    ++        return new String(chars);
    ++    }
    ++}
    +diff --git a/core/java/android/view/DragEvent.java b/core/java/android/view/DragEvent.java
    +index b0f15b5..2baa0b4 100644
    +--- a/core/java/android/view/DragEvent.java
    ++++ b/core/java/android/view/DragEvent.java
    +@@ -134,6 +134,7 @@ public class DragEvent implements Parcelable {
    + 
    +     Object mLocalState;
    +     boolean mDragResult;
    ++    boolean mEventHandlerWasCalled;
    + 
    +     private DragEvent mNext;
    +     private RuntimeException mRecycledLocation;
    +@@ -152,12 +153,16 @@ public class DragEvent implements Parcelable {
    +      * if it can accept a drop. The onDragEvent() or onDrag() methods usually inspect the metadata
    +      * from {@link #getClipDescription()} to determine if they can accept the data contained in
    +      * this drag. For an operation that doesn't represent data transfer, these methods may
    +-     * perform other actions to determine whether or not the View should accept the drag.
    ++     * perform other actions to determine whether or not the View should accept the data.
    +      * If the View wants to indicate that it is a valid drop target, it can also react by
    +      * changing its appearance.
    +      * <p>
    +-     * A View only receives further drag events if it returns {@code true} in response to
    +-     * ACTION_DRAG_STARTED.
    ++     *  Views added or becoming visible for the first time during a drag operation receive this
    ++     *  event when they are added or becoming visible.
    ++     * </p>
    ++     * <p>
    ++     *  A View only receives further drag events if it returns {@code true} in response to
    ++     *  ACTION_DRAG_STARTED.
    +      * </p>
    +      * @see #ACTION_DRAG_ENDED
    +      * @see #getX()
    +@@ -176,9 +181,10 @@ public class DragEvent implements Parcelable {
    +      * </p>
    +      * <p>
    +      * The system stops sending ACTION_DRAG_LOCATION events to a View once the user moves the
    +-     * drag shadow out of the View object's bounding box. If the user moves the drag shadow back
    +-     * into the View object's bounding box, the View receives an ACTION_DRAG_ENTERED again before
    +-     * receiving any more ACTION_DRAG_LOCATION events.
    ++     * drag shadow out of the View object's bounding box or into a descendant view that can accept
    ++     * the data. If the user moves the drag shadow back into the View object's bounding box or out
    ++     * of a descendant view that can accept the data, the View receives an ACTION_DRAG_ENTERED again
    ++     * before receiving any more ACTION_DRAG_LOCATION events.
    +      * </p>
    +      * @see #ACTION_DRAG_ENTERED
    +      * @see #getX()
    +@@ -188,7 +194,8 @@ public class DragEvent implements Parcelable {
    + 
    +     /**
    +      * Action constant returned by {@link #getAction()}: Signals to a View that the user
    +-     * has released the drag shadow, and the drag point is within the bounding box of the View.
    ++     * has released the drag shadow, and the drag point is within the bounding box of the View and
    ++     * not within a descendant view that can accept the data.
    +      * The View should retrieve the data from the DragEvent by calling {@link #getClipData()}.
    +      * The methods {@link #getX()} and {@link #getY()} return the X and Y position of the drop point
    +      * within the View object's bounding box.
    +@@ -211,8 +218,10 @@ public class DragEvent implements Parcelable {
    +      * operation has concluded.  A View that changed its appearance during the operation should
    +      * return to its usual drawing state in response to this event.
    +      * <p>
    +-     * All views that received an ACTION_DRAG_STARTED event will receive the
    +-     * ACTION_DRAG_ENDED event even if they are not currently visible when the drag ends.
    ++     *  All views with listeners that returned boolean <code>true</code> for the ACTION_DRAG_STARTED
    ++     *  event will receive the ACTION_DRAG_ENDED event even if they are not currently visible when
    ++     *  the drag ends. Views removed during the drag operation won't receive the ACTION_DRAG_ENDED
    ++     *  event.
    +      * </p>
    +      * <p>
    +      *  The View object can call {@link #getResult()} to see the result of the operation.
    +@@ -233,9 +242,10 @@ public class DragEvent implements Parcelable {
    +      *  drop target.
    +      * </p>
    +      * The system stops sending ACTION_DRAG_LOCATION events to a View once the user moves the
    +-     * drag shadow out of the View object's bounding box. If the user moves the drag shadow back
    +-     * into the View object's bounding box, the View receives an ACTION_DRAG_ENTERED again before
    +-     * receiving any more ACTION_DRAG_LOCATION events.
    ++     * drag shadow out of the View object's bounding box or into a descendant view that can accept
    ++     * the data. If the user moves the drag shadow back into the View object's bounding box or out
    ++     * of a descendant view that can accept the data, the View receives an ACTION_DRAG_ENTERED again
    ++     * before receiving any more ACTION_DRAG_LOCATION events.
    +      * </p>
    +      * @see #ACTION_DRAG_ENTERED
    +      * @see #ACTION_DRAG_LOCATION
    +@@ -244,7 +254,8 @@ public class DragEvent implements Parcelable {
    + 
    +     /**
    +      * Action constant returned by {@link #getAction()}: Signals that the user has moved the
    +-     * drag shadow outside the bounding box of the View.
    ++     * drag shadow out of the bounding box of the View or into a descendant view that can accept
    ++     * the data.
    +      * The View can react by changing its appearance in a way that tells the user that
    +      * View is no longer the immediate drop target.
    +      * <p>
    +@@ -377,6 +388,10 @@ public class DragEvent implements Parcelable {
    +      * The object is intended to provide local information about the drag and drop operation. For
    +      * example, it can indicate whether the drag and drop operation is a copy or a move.
    +      * <p>
    ++     * The local state is available only to views in the activity which has started the drag
    ++     * operation. In all other activities this method will return null
    ++     * </p>
    ++     * <p>
    +      *  This method returns valid data for all event actions except for {@link #ACTION_DRAG_ENDED}.
    +      * </p>
    +      * @return The local state object sent to the system by startDrag().
    +@@ -435,6 +450,7 @@ public class DragEvent implements Parcelable {
    +         mClipData = null;
    +         mClipDescription = null;
    +         mLocalState = null;
    ++        mEventHandlerWasCalled = false;
    + 
    +         synchronized (gRecyclerLock) {
    +             if (gRecyclerUsed < MAX_RECYCLED) {
    +diff --git a/core/java/android/view/IWindowManager.aidl b/core/java/android/view/IWindowManager.aidl
    +index 81469c8..855b1bc 100644
    +--- a/core/java/android/view/IWindowManager.aidl
    ++++ b/core/java/android/view/IWindowManager.aidl
    +@@ -73,8 +73,8 @@ interface IWindowManager
    +     void clearForcedDisplaySize(int displayId);
    +     int getInitialDisplayDensity(int displayId);
    +     int getBaseDisplayDensity(int displayId);
    +-    void setForcedDisplayDensity(int displayId, int density);
    +-    void clearForcedDisplayDensity(int displayId);
    ++    void setForcedDisplayDensityForUser(int displayId, int density, int userId);
    ++    void clearForcedDisplayDensityForUser(int displayId, int userId);
    +     void setForcedDisplayScalingMode(int displayId, int mode); // 0 = auto, 1 = disable
    + 
    +     void setOverscan(int displayId, int left, int top, int right, int bottom);
    +@@ -331,6 +331,16 @@ interface IWindowManager
    +     oneway void statusBarVisibilityChanged(int visibility);
    + 
    +     /**
    ++     * Called by System UI to notify of changes to the visibility of Recents.
    ++     */
    ++    oneway void setRecentsVisibility(boolean visible);
    ++
    ++    /**
    ++     * Called by System UI to notify of changes to the visibility of PIP.
    ++     */
    ++    oneway void setTvPipVisibility(boolean visible);
    ++
    ++    /**
    +      * Device has a software navigation bar (separate from the status bar).
    +      */
    +     boolean hasNavigationBar();
    +diff --git a/core/java/android/view/KeyEvent.java b/core/java/android/view/KeyEvent.java
    +index 990d553..b73acda 100644
    +--- a/core/java/android/view/KeyEvent.java
    ++++ b/core/java/android/view/KeyEvent.java
    +@@ -1289,8 +1289,9 @@ public class KeyEvent extends InputEvent implements Parcelable {
    +         boolean onKeyUp(int keyCode, KeyEvent event);
    + 
    +         /**
    +-         * Called when multiple down/up pairs of the same key have occurred
    +-         * in a row.
    ++         * Called when a user's interaction with an analog control, such as
    ++         * flinging a trackball, generates simulated down/up events for the same
    ++         * key multiple times in quick succession.
    +          *
    +          * @param keyCode The value in event.getKeyCode().
    +          * @param count Number of pairs as returned by event.getRepeatCount().
    +diff --git a/core/java/android/view/Surface.java b/core/java/android/view/Surface.java
    +index 286e097..22e68a3 100644
    +--- a/core/java/android/view/Surface.java
    ++++ b/core/java/android/view/Surface.java
    +@@ -33,6 +33,18 @@ import dalvik.system.CloseGuard;
    + 
    + /**
    +  * Handle onto a raw buffer that is being managed by the screen compositor.
    ++ *
    ++ * <p>A Surface is generally created by or from a consumer of image buffers (such as a
    ++ * {@link android.graphics.SurfaceTexture}, {@link android.media.MediaRecorder}, or
    ++ * {@link android.renderscript.Allocation}), and is handed to some kind of producer (such as
    ++ * {@link android.opengl.EGL14#eglCreateWindowSurface(android.opengl.EGLDisplay,android.opengl.EGLConfig,java.lang.Object,int[],int) OpenGL},
    ++ * {@link android.media.MediaPlayer#setSurface MediaPlayer}, or
    ++ * {@link android.hardware.camera2.CameraDevice#createCaptureSession CameraDevice}) to draw
    ++ * into.</p>
    ++ *
    ++ * <p><strong>Note:</strong> A Surface acts like a
    ++ * {@link java.lang.ref.WeakReference weak reference} to the consumer it is associated with. By
    ++ * itself it will not keep its parent consumer from being reclaimed.</p>
    +  */
    + public class Surface implements Parcelable {
    +     private static final String TAG = "Surface";
    +@@ -59,6 +71,7 @@ public class Surface implements Parcelable {
    +     private static native long nativeGetNextFrameNumber(long nativeObject);
    +     private static native int nativeSetScalingMode(long nativeObject, int scalingMode);
    +     private static native void nativeSetBuffersTransform(long nativeObject, long transform);
    ++    private static native int nativeForceScopedDisconnect(long nativeObject);
    + 
    +     public static final Parcelable.Creator<Surface> CREATOR =
    +             new Parcelable.Creator<Surface>() {
    +@@ -96,6 +109,8 @@ public class Surface implements Parcelable {
    + 
    +     private HwuiContext mHwuiContext;
    + 
    ++    private boolean mIsSingleBuffered;
    ++
    +     /** @hide */
    +     @Retention(RetentionPolicy.SOURCE)
    +     @IntDef({SCALING_MODE_FREEZE, SCALING_MODE_SCALE_TO_WINDOW,
    +@@ -158,7 +173,7 @@ public class Surface implements Parcelable {
    +         if (surfaceTexture == null) {
    +             throw new IllegalArgumentException("surfaceTexture must not be null");
    +         }
    +-
    ++        mIsSingleBuffered = surfaceTexture.isSingleBuffered();
    +         synchronized (mLock) {
    +             mName = surfaceTexture.toString();
    +             setNativeObjectLocked(nativeCreateFromSurfaceTexture(surfaceTexture));
    +@@ -457,7 +472,10 @@ public class Surface implements Parcelable {
    +             // create a new native Surface and return it after reducing
    +             // the reference count on mNativeObject.  Either way, it is
    +             // not necessary to call nativeRelease() here.
    ++            // NOTE: This must be kept synchronized with the native parceling code
    ++            // in frameworks/native/libs/Surface.cpp
    +             mName = source.readString();
    ++            mIsSingleBuffered = source.readInt() != 0;
    +             setNativeObjectLocked(nativeReadFromParcel(mNativeObject, source));
    +         }
    +     }
    +@@ -468,7 +486,10 @@ public class Surface implements Parcelable {
    +             throw new IllegalArgumentException("dest must not be null");
    +         }
    +         synchronized (mLock) {
    ++            // NOTE: This must be kept synchronized with the native parceling code
    ++            // in frameworks/native/libs/Surface.cpp
    +             dest.writeString(mName);
    ++            dest.writeInt(mIsSingleBuffered ? 1 : 0);
    +             nativeWriteToParcel(mNativeObject, dest);
    +         }
    +         if ((flags & Parcelable.PARCELABLE_WRITE_RETURN_VALUE) != 0) {
    +@@ -530,6 +551,24 @@ public class Surface implements Parcelable {
    +         }
    +     }
    + 
    ++    void forceScopedDisconnect() {
    ++        synchronized (mLock) {
    ++            checkNotReleasedLocked();
    ++            int err = nativeForceScopedDisconnect(mNativeObject);
    ++            if (err != 0) {
    ++                throw new RuntimeException("Failed to disconnect Surface instance (bad object?)");
    ++            }
    ++        }
    ++    }
    ++
    ++    /**
    ++     * Returns whether or not this Surface is backed by a single-buffered SurfaceTexture
    ++     * @hide
    ++     */
    ++    public boolean isSingleBuffered() {
    ++        return mIsSingleBuffered;
    ++    }
    ++
    +     /**
    +      * Exception thrown when a Canvas couldn't be locked with {@link Surface#lockCanvas}, or
    +      * when a SurfaceTexture could not successfully be allocated.
    +diff --git a/core/java/android/view/SurfaceView.java b/core/java/android/view/SurfaceView.java
    +index 4818910..4b9a570 100644
    +--- a/core/java/android/view/SurfaceView.java
    ++++ b/core/java/android/view/SurfaceView.java
    +@@ -115,6 +115,7 @@ public class SurfaceView extends View {
    +     final Rect mStableInsets = new Rect();
    +     final Rect mOutsets = new Rect();
    +     final Rect mBackdropFrame = new Rect();
    ++    final Rect mTmpRect = new Rect();
    +     final Configuration mConfiguration = new Configuration();
    + 
    +     static final int KEEP_SCREEN_ON_MSG = 1;
    +@@ -193,26 +194,20 @@ public class SurfaceView extends View {
    +     private boolean mGlobalListenersAdded;
    + 
    +     public SurfaceView(Context context) {
    +-        super(context);
    +-        init();
    ++        this(context, null);
    +     }
    + 
    +     public SurfaceView(Context context, AttributeSet attrs) {
    +-        super(context, attrs);
    +-        init();
    ++        this(context, attrs, 0);
    +     }
    + 
    +     public SurfaceView(Context context, AttributeSet attrs, int defStyleAttr) {
    +-        super(context, attrs, defStyleAttr);
    +-        init();
    ++        this(context, attrs, defStyleAttr, 0);
    +     }
    + 
    +     public SurfaceView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
    +         super(context, attrs, defStyleAttr, defStyleRes);
    +-        init();
    +-    }
    + 
    +-    private void init() {
    +         setWillNotDraw(true);
    +     }
    + 
    +@@ -233,6 +228,7 @@ public class SurfaceView extends View {
    +         mSession = getWindowSession();
    +         mLayout.token = getWindowToken();
    +         mLayout.setTitle("SurfaceView - " + getViewRootImpl().getTitle());
    ++        mLayout.packageName = mContext.getOpPackageName();
    +         mViewVisibility = getVisibility() == VISIBLE;
    + 
    +         if (!mGlobalListenersAdded) {
    +@@ -591,6 +587,20 @@ public class SurfaceView extends View {
    +                             for (SurfaceHolder.Callback c : callbacks) {
    +                                 c.surfaceDestroyed(mSurfaceHolder);
    +                             }
    ++                            // Since Android N the same surface may be reused and given to us
    ++                            // again by the system server at a later point. However
    ++                            // as we didn't do this in previous releases, clients weren't
    ++                            // necessarily required to clean up properly in
    ++                            // surfaceDestroyed. This leads to problems for example when
    ++                            // clients don't destroy their EGL context, and try
    ++                            // and create a new one on the same surface following reuse.
    ++                            // Since there is no valid use of the surface in-between
    ++                            // surfaceDestroyed and surfaceCreated, we force a disconnect,
    ++                            // so the next connect will always work if we end up reusing
    ++                            // the surface.
    ++                            if (mSurface.isValid()) {
    ++                                mSurface.forceScopedDisconnect();
    ++                            }
    +                         }
    +                     }
    + 
    +@@ -666,21 +676,21 @@ public class SurfaceView extends View {
    + 
    +                 transformFromViewToWindowSpace(mLocation);
    + 
    +-                mWinFrame.set(mWindowSpaceLeft, mWindowSpaceTop,
    ++                mTmpRect.set(mWindowSpaceLeft, mWindowSpaceTop,
    +                         mLocation[0], mLocation[1]);
    + 
    +                 if (mTranslator != null) {
    +-                    mTranslator.translateRectInAppWindowToScreen(mWinFrame);
    ++                    mTranslator.translateRectInAppWindowToScreen(mTmpRect);
    +                 }
    + 
    +                 if (!isHardwareAccelerated() || !mRtHandlingPositionUpdates) {
    +                     try {
    +                         if (DEBUG) Log.d(TAG, String.format("%d updateWindowPosition UI, " +
    +                                 "postion = [%d, %d, %d, %d]", System.identityHashCode(this),
    +-                                mWinFrame.left, mWinFrame.top,
    +-                                mWinFrame.right, mWinFrame.bottom));
    +-                        mSession.repositionChild(mWindow, mWinFrame.left, mWinFrame.top,
    +-                                mWinFrame.right, mWinFrame.bottom, -1, mWinFrame);
    ++                                mTmpRect.left, mTmpRect.top,
    ++                                mTmpRect.right, mTmpRect.bottom));
    ++                        mSession.repositionChild(mWindow, mTmpRect.left, mTmpRect.top,
    ++                                mTmpRect.right, mTmpRect.bottom, -1, mTmpRect);
    +                     } catch (RemoteException ex) {
    +                         Log.e(TAG, "Exception from relayout", ex);
    +                     }
    +@@ -692,10 +702,10 @@ public class SurfaceView extends View {
    +     private Rect mRTLastReportedPosition = new Rect();
    + 
    +     /**
    +-     * Called by native on RenderThread to update the window position
    ++     * Called by native by a Rendering Worker thread to update the window position
    +      * @hide
    +      */
    +-    public final void updateWindowPositionRT(long frameNumber,
    ++    public final void updateWindowPosition_renderWorker(long frameNumber,
    +             int left, int top, int right, int bottom) {
    +         IWindowSession session = mSession;
    +         MyWindow window = mWindow;
    +@@ -720,7 +730,7 @@ public class SurfaceView extends View {
    +         }
    +         try {
    +             if (DEBUG) {
    +-                Log.d(TAG, String.format("%d updateWindowPosition RT, frameNr = %d, " +
    ++                Log.d(TAG, String.format("%d updateWindowPosition RenderWorker, frameNr = %d, " +
    +                         "postion = [%d, %d, %d, %d]", System.identityHashCode(this),
    +                         frameNumber, left, top, right, bottom));
    +             }
    +@@ -737,12 +747,12 @@ public class SurfaceView extends View {
    + 
    +     /**
    +      * Called by native on RenderThread to notify that the window is no longer in the
    +-     * draw tree
    ++     * draw tree. UI thread is blocked at this point.
    +      * @hide
    +      */
    +-    public final void windowPositionLostRT(long frameNumber) {
    ++    public final void windowPositionLost_uiRtSync(long frameNumber) {
    +         if (DEBUG) {
    +-            Log.d(TAG, String.format("%d windowPositionLostRT RT, frameNr = %d",
    ++            Log.d(TAG, String.format("%d windowPositionLost, frameNr = %d",
    +                     System.identityHashCode(this), frameNumber));
    +         }
    +         IWindowSession session = mSession;
    +@@ -757,14 +767,18 @@ public class SurfaceView extends View {
    +             // safely access other member variables at this time.
    +             // So do what the UI thread would have done if RT wasn't handling position
    +             // updates.
    +-            if (!mWinFrame.isEmpty() && !mWinFrame.equals(mRTLastReportedPosition)) {
    ++            mTmpRect.set(mLayout.x, mLayout.y,
    ++                    mLayout.x + mLayout.width,
    ++                    mLayout.y + mLayout.height);
    ++
    ++            if (!mTmpRect.isEmpty() && !mTmpRect.equals(mRTLastReportedPosition)) {
    +                 try {
    +                     if (DEBUG) Log.d(TAG, String.format("%d updateWindowPosition, " +
    +                             "postion = [%d, %d, %d, %d]", System.identityHashCode(this),
    +-                            mWinFrame.left, mWinFrame.top,
    +-                            mWinFrame.right, mWinFrame.bottom));
    +-                    session.repositionChild(window, mWinFrame.left, mWinFrame.top,
    +-                            mWinFrame.right, mWinFrame.bottom, frameNumber, mWinFrame);
    ++                            mTmpRect.left, mTmpRect.top,
    ++                            mTmpRect.right, mTmpRect.bottom));
    ++                    session.repositionChild(window, mTmpRect.left, mTmpRect.top,
    ++                            mTmpRect.right, mTmpRect.bottom, frameNumber, mWinFrame);
    +                 } catch (RemoteException ex) {
    +                     Log.e(TAG, "Exception from relayout", ex);
    +                 }
    +diff --git a/core/java/android/view/TextureView.java b/core/java/android/view/TextureView.java
    +index c7eca44..645ab5c 100644
    +--- a/core/java/android/view/TextureView.java
    ++++ b/core/java/android/view/TextureView.java
    +@@ -228,6 +228,7 @@ public class TextureView extends View {
    +      */
    +     @Override
    +     protected void destroyHardwareResources() {
    ++        super.destroyHardwareResources();
    +         destroyHardwareLayer();
    +     }
    + 
    +@@ -719,7 +720,7 @@ public class TextureView extends View {
    +     /**
    +      * Set the {@link SurfaceTexture} for this view to use. If a {@link
    +      * SurfaceTexture} is already being used by this view, it is immediately
    +-     * released and not be usable any more.  The {@link
    ++     * released and not usable any more.  The {@link
    +      * SurfaceTextureListener#onSurfaceTextureDestroyed} callback is <b>not</b>
    +      * called for the previous {@link SurfaceTexture}.  Similarly, the {@link
    +      * SurfaceTextureListener#onSurfaceTextureAvailable} callback is <b>not</b>
    +diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
    +index c42ad2e..9722083 100644
    +--- a/core/java/android/view/View.java
    ++++ b/core/java/android/view/View.java
    +@@ -40,7 +40,6 @@ import android.content.res.Resources;
    + import android.content.res.TypedArray;
    + import android.graphics.Bitmap;
    + import android.graphics.Canvas;
    +-import android.graphics.Color;
    + import android.graphics.Insets;
    + import android.graphics.Interpolator;
    + import android.graphics.LinearGradient;
    +@@ -831,6 +830,17 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
    +     protected static boolean sPreserveMarginParamsInLayoutParamConversion;
    + 
    +     /**
    ++     * Prior to N, when drag enters into child of a view that has already received an
    ++     * ACTION_DRAG_ENTERED event, the parent doesn't get a ACTION_DRAG_EXITED event.
    ++     * ACTION_DRAG_LOCATION and ACTION_DROP were delivered to the parent of a view that returned
    ++     * false from its event handler for these events.
    ++     * Starting from N, the parent will get ACTION_DRAG_EXITED event before the child gets its
    ++     * ACTION_DRAG_ENTERED. ACTION_DRAG_LOCATION and ACTION_DROP are never propagated to the parent.
    ++     * sCascadedDragDrop is true for pre-N apps for backwards compatibility implementation.
    ++     */
    ++    static boolean sCascadedDragDrop;
    ++
    ++    /**
    +      * This view does not want keystrokes. Use with TAKES_FOCUS_MASK when
    +      * calling setFlags.
    +      */
    +@@ -3086,20 +3096,6 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
    +     /**
    +      * @hide
    +      *
    +-     * Whether Recents is visible or not.
    +-     */
    +-    public static final int RECENT_APPS_VISIBLE = 0x00004000;
    +-
    +-    /**
    +-     * @hide
    +-     *
    +-     * Whether the TV's picture-in-picture is visible or not.
    +-     */
    +-    public static final int TV_PICTURE_IN_PICTURE_VISIBLE = 0x00010000;
    +-
    +-    /**
    +-     * @hide
    +-     *
    +      * Makes navigation bar transparent (but not the status bar).
    +      */
    +     public static final int NAVIGATION_BAR_TRANSPARENT = 0x00008000;
    +@@ -4066,6 +4062,8 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
    +             // in apps so we target check it to avoid breaking existing apps.
    +             sPreserveMarginParamsInLayoutParamConversion = targetSdkVersion >= N;
    + 
    ++            sCascadedDragDrop = targetSdkVersion < N;
    ++
    +             sCompatibilityDone = true;
    +         }
    +     }
    +@@ -8061,7 +8059,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
    +     }
    + 
    +     /**
    +-     * Set the enabled state of this view.
    ++     * Set the visibility state of this view.
    +      *
    +      * @param visibility One of {@link #VISIBLE}, {@link #INVISIBLE}, or {@link #GONE}.
    +      * @attr ref android.R.styleable#View_visibility
    +@@ -20280,8 +20278,14 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
    +                 // remove it from the transparent region.
    +                 final int[] location = attachInfo.mTransparentLocation;
    +                 getLocationInWindow(location);
    +-                region.op(location[0], location[1], location[0] + mRight - mLeft,
    +-                        location[1] + mBottom - mTop, Region.Op.DIFFERENCE);
    ++                // When a view has Z value, then it will be better to leave some area below the view
    ++                // for drawing shadow. The shadow outset is proportional to the Z value. Note that
    ++                // the bottom part needs more offset than the left, top and right parts due to the
    ++                // spot light effects.
    ++                int shadowOffset = getZ() > 0 ? (int) getZ() : 0;
    ++                region.op(location[0] - shadowOffset, location[1] - shadowOffset,
    ++                        location[0] + mRight - mLeft + shadowOffset,
    ++                        location[1] + mBottom - mTop + (shadowOffset * 3), Region.Op.DIFFERENCE);
    +             } else {
    +                 if (mBackground != null && mBackground.getOpacity() != PixelFormat.TRANSPARENT) {
    +                     // The SKIP_DRAW flag IS set and the background drawable exists, we remove
    +@@ -20649,8 +20653,10 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
    +      * @param shadowBuilder A {@link android.view.View.DragShadowBuilder} object for building the
    +      * drag shadow.
    +      * @param myLocalState An {@link java.lang.Object} containing local data about the drag and
    +-     * drop operation. This Object is put into every DragEvent object sent by the system during the
    +-     * current drag.
    ++     * drop operation. When dispatching drag events to views in the same activity this object
    ++     * will be available through {@link android.view.DragEvent#getLocalState()}. Views in other
    ++     * activities will not have access to this data ({@link android.view.DragEvent#getLocalState()}
    ++     * will return null).
    +      * <p>
    +      * myLocalState is a lightweight mechanism for the sending information from the dragged View
    +      * to the target Views. For example, it can contain flags that differentiate between a
    +@@ -20851,6 +20857,11 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
    +         return false;
    +     }
    + 
    ++    // Dispatches ACTION_DRAG_ENTERED and ACTION_DRAG_EXITED events for pre-Nougat apps.
    ++    boolean dispatchDragEnterExitInPreN(DragEvent event) {
    ++        return callDragEventHandler(event);
    ++    }
    ++
    +     /**
    +      * Detects if this View is enabled and has a drag event listener.
    +      * If both are true, then it calls the drag event listener with the
    +@@ -20868,13 +20879,44 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
    +      * </p>
    +      */
    +     public boolean dispatchDragEvent(DragEvent event) {
    ++        event.mEventHandlerWasCalled = true;
    ++        if (event.mAction == DragEvent.ACTION_DRAG_LOCATION ||
    ++            event.mAction == DragEvent.ACTION_DROP) {
    ++            // About to deliver an event with coordinates to this view. Notify that now this view
    ++            // has drag focus. This will send exit/enter events as needed.
    ++            getViewRootImpl().setDragFocus(this, event);
    ++        }
    ++        return callDragEventHandler(event);
    ++    }
    ++
    ++    final boolean callDragEventHandler(DragEvent event) {
    ++        final boolean result;
    ++
    +         ListenerInfo li = mListenerInfo;
    +         //noinspection SimplifiableIfStatement
    +         if (li != null && li.mOnDragListener != null && (mViewFlags & ENABLED_MASK) == ENABLED
    +                 && li.mOnDragListener.onDrag(this, event)) {
    +-            return true;
    ++            result = true;
    ++        } else {
    ++            result = onDragEvent(event);
    +         }
    +-        return onDragEvent(event);
    ++
    ++        switch (event.mAction) {
    ++            case DragEvent.ACTION_DRAG_ENTERED: {
    ++                mPrivateFlags2 |= View.PFLAG2_DRAG_HOVERED;
    ++                refreshDrawableState();
    ++            } break;
    ++            case DragEvent.ACTION_DRAG_EXITED: {
    ++                mPrivateFlags2 &= ~View.PFLAG2_DRAG_HOVERED;
    ++                refreshDrawableState();
    ++            } break;
    ++            case DragEvent.ACTION_DRAG_ENDED: {
    ++                mPrivateFlags2 &= ~View.DRAG_MASK;
    ++                refreshDrawableState();
    ++            } break;
    ++        }
    ++
    ++        return result;
    +     }
    + 
    +     boolean canAcceptDrag() {
    +diff --git a/core/java/android/view/ViewGroup.java b/core/java/android/view/ViewGroup.java
    +index 3ff8d4f..d4b7d3b 100644
    +--- a/core/java/android/view/ViewGroup.java
    ++++ b/core/java/android/view/ViewGroup.java
    +@@ -153,8 +153,9 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager
    +      */
    +     Transformation mInvalidationTransformation;
    + 
    +-    // View currently under an ongoing drag. Can be null, a child or this window.
    +-    private View mCurrentDragView;
    ++    // Current frontmost child that can accept drag and lies under the drag location.
    ++    // Used only to generate ENTER/EXIT events for pre-Nougat aps.
    ++    private View mCurrentDragChild;
    + 
    +     // Metadata about the ongoing drag
    +     private DragEvent mCurrentDragStartEvent;
    +@@ -1355,6 +1356,20 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager
    +         return mLocalPoint;
    +     }
    + 
    ++    @Override
    ++    boolean dispatchDragEnterExitInPreN(DragEvent event) {
    ++        if (event.mAction == DragEvent.ACTION_DRAG_EXITED && mCurrentDragChild != null) {
    ++            // The drag exited a sub-tree of views; notify of the exit all descendants that are in
    ++            // entered state.
    ++            // We don't need this recursive delivery for ENTERED events because they get generated
    ++            // from the recursive delivery of LOCATION/DROP events, and hence, don't need their own
    ++            // recursion.
    ++            mCurrentDragChild.dispatchDragEnterExitInPreN(event);
    ++            mCurrentDragChild = null;
    ++        }
    ++        return mIsInterestedInDrag && super.dispatchDragEnterExitInPreN(event);
    ++    }
    ++
    +     // TODO: Write real docs
    +     @Override
    +     public boolean dispatchDragEvent(DragEvent event) {
    +@@ -1362,15 +1377,13 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager
    +         final float tx = event.mX;
    +         final float ty = event.mY;
    + 
    +-        ViewRootImpl root = getViewRootImpl();
    +-
    +         // Dispatch down the view hierarchy
    +         final PointF localPoint = getLocalPoint();
    + 
    +         switch (event.mAction) {
    +         case DragEvent.ACTION_DRAG_STARTED: {
    +-            // clear state to recalculate which views we drag over
    +-            mCurrentDragView = null;
    ++            // Clear the state to recalculate which views we drag over.
    ++            mCurrentDragChild = null;
    + 
    +             // Set up our tracking of drag-started notifications
    +             mCurrentDragStartEvent = DragEvent.obtain(event);
    +@@ -1416,8 +1429,6 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager
    +                     if (child.dispatchDragEvent(event)) {
    +                         retval = true;
    +                     }
    +-                    child.mPrivateFlags2 &= ~View.DRAG_MASK;
    +-                    child.refreshDrawableState();
    +                 }
    +                 childrenInterestedInDrag.clear();
    +             }
    +@@ -1434,60 +1445,45 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager
    +             }
    +         } break;
    + 
    +-        case DragEvent.ACTION_DRAG_LOCATION: {
    ++        case DragEvent.ACTION_DRAG_LOCATION:
    ++        case DragEvent.ACTION_DROP: {
    +             // Find the [possibly new] drag target
    +             View target = findFrontmostDroppableChildAt(event.mX, event.mY, localPoint);
    +-            if (target == null && mIsInterestedInDrag) {
    +-                target = this;
    +-            }
    + 
    +-            // If we've changed apparent drag target, tell the view root which view
    +-            // we're over now [for purposes of the eventual drag-recipient-changed
    +-            // notifications to the framework] and tell the new target that the drag
    +-            // has entered its bounds.  The root will see setDragFocus() calls all
    +-            // the way down to the final leaf view that is handling the LOCATION event
    +-            // before reporting the new potential recipient to the framework.
    +-            if (mCurrentDragView != target) {
    +-                root.setDragFocus(target);
    +-
    +-                final int action = event.mAction;
    +-                // Position should not be available for ACTION_DRAG_ENTERED and ACTION_DRAG_EXITED.
    +-                event.mX = 0;
    +-                event.mY = 0;
    +-
    +-                // If we've dragged off of a child view or this window, send it the EXITED message
    +-                if (mCurrentDragView != null) {
    +-                    final View view = mCurrentDragView;
    +-                    event.mAction = DragEvent.ACTION_DRAG_EXITED;
    +-                    if (view != this) {
    +-                        view.dispatchDragEvent(event);
    +-                        view.mPrivateFlags2 &= ~View.PFLAG2_DRAG_HOVERED;
    +-                        view.refreshDrawableState();
    +-                    } else {
    +-                        super.dispatchDragEvent(event);
    ++            if (target != mCurrentDragChild) {
    ++                if (sCascadedDragDrop) {
    ++                    // For pre-Nougat apps, make sure that the whole hierarchy of views that contain
    ++                    // the drag location is kept in the state between ENTERED and EXITED events.
    ++                    // (Starting with N, only the innermost view will be in that state).
    ++
    ++                    final int action = event.mAction;
    ++                    // Position should not be available for ACTION_DRAG_ENTERED and
    ++                    // ACTION_DRAG_EXITED.
    ++                    event.mX = 0;
    ++                    event.mY = 0;
    ++
    ++                    if (mCurrentDragChild != null) {
    ++                        event.mAction = DragEvent.ACTION_DRAG_EXITED;
    ++                        mCurrentDragChild.dispatchDragEnterExitInPreN(event);
    +                     }
    +-                }
    + 
    +-                mCurrentDragView = target;
    +-
    +-                // If we've dragged over a new child view, send it the ENTERED message, otherwise
    +-                // send it to this window.
    +-                if (target != null) {
    +-                    event.mAction = DragEvent.ACTION_DRAG_ENTERED;
    +-                    if (target != this) {
    +-                        target.dispatchDragEvent(event);
    +-                        target.mPrivateFlags2 |= View.PFLAG2_DRAG_HOVERED;
    +-                        target.refreshDrawableState();
    +-                    } else {
    +-                        super.dispatchDragEvent(event);
    ++                    if (target != null) {
    ++                        event.mAction = DragEvent.ACTION_DRAG_ENTERED;
    ++                        target.dispatchDragEnterExitInPreN(event);
    +                     }
    ++
    ++                    event.mAction = action;
    ++                    event.mX = tx;
    ++                    event.mY = ty;
    +                 }
    +-                event.mAction = action;  // restore the event's original state
    +-                event.mX = tx;
    +-                event.mY = ty;
    ++                mCurrentDragChild = target;
    +             }
    + 
    +-            // Dispatch the actual drag location notice, localized into its coordinates
    ++            if (target == null && mIsInterestedInDrag) {
    ++                target = this;
    ++            }
    ++
    ++            // Dispatch the actual drag notice, localized into the target coordinates.
    +             if (target != null) {
    +                 if (target != this) {
    +                     event.mX = localPoint.x;
    +@@ -1497,55 +1493,21 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager
    + 
    +                     event.mX = tx;
    +                     event.mY = ty;
    +-                } else {
    +-                    retval = super.dispatchDragEvent(event);
    +-                }
    +-            }
    +-        } break;
    + 
    +-        /* Entered / exited dispatch
    +-         *
    +-         * DRAG_ENTERED is not dispatched downwards from ViewGroup.  The reason for this is
    +-         * that we're about to get the corresponding LOCATION event, which we will use to
    +-         * determine which of our children is the new target; at that point we will
    +-         * push a DRAG_ENTERED down to the new target child [which may itself be a ViewGroup].
    +-         * If no suitable child is detected, dispatch to this window.
    +-         *
    +-         * DRAG_EXITED *is* dispatched all the way down immediately: once we know the
    +-         * drag has left this ViewGroup, we know by definition that every contained subview
    +-         * is also no longer under the drag point.
    +-         */
    ++                    if (mIsInterestedInDrag) {
    ++                        final boolean eventWasConsumed;
    ++                        if (sCascadedDragDrop) {
    ++                            eventWasConsumed = retval;
    ++                        } else {
    ++                            eventWasConsumed = event.mEventHandlerWasCalled;
    ++                        }
    + 
    +-        case DragEvent.ACTION_DRAG_EXITED: {
    +-            if (mCurrentDragView != null) {
    +-                final View view = mCurrentDragView;
    +-                if (view != this) {
    +-                    view.dispatchDragEvent(event);
    +-                    view.mPrivateFlags2 &= ~View.PFLAG2_DRAG_HOVERED;
    +-                    view.refreshDrawableState();
    ++                        if (!eventWasConsumed) {
    ++                            retval = super.dispatchDragEvent(event);
    ++                        }
    ++                    }
    +                 } else {
    +-                    super.dispatchDragEvent(event);
    +-                }
    +-
    +-                mCurrentDragView = null;
    +-            }
    +-        } break;
    +-
    +-        case DragEvent.ACTION_DROP: {
    +-            if (ViewDebug.DEBUG_DRAG) Log.d(View.VIEW_LOG_TAG, "Drop event: " + event);
    +-            View target = findFrontmostDroppableChildAt(event.mX, event.mY, localPoint);
    +-            if (target != null) {
    +-                if (ViewDebug.DEBUG_DRAG) Log.d(View.VIEW_LOG_TAG, "   dispatch drop to " + target);
    +-                event.mX = localPoint.x;
    +-                event.mY = localPoint.y;
    +-                retval = target.dispatchDragEvent(event);
    +-                event.mX = tx;
    +-                event.mY = ty;
    +-            } else if (mIsInterestedInDrag) {
    +-                retval = super.dispatchDragEvent(event);
    +-            } else {
    +-                if (ViewDebug.DEBUG_DRAG) {
    +-                    Log.d(View.VIEW_LOG_TAG, "   not dropped on an accepting view");
    ++                    retval = super.dispatchDragEvent(event);
    +                 }
    +             }
    +         } break;
    +@@ -1592,6 +1554,7 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager
    +         final boolean canAccept = child.dispatchDragEvent(mCurrentDragStartEvent);
    +         mCurrentDragStartEvent.mX = tx;
    +         mCurrentDragStartEvent.mY = ty;
    ++        mCurrentDragStartEvent.mEventHandlerWasCalled = false;
    +         if (canAccept) {
    +             mChildrenInterestedInDrag.add(child);
    +             if (!child.canAcceptDrag()) {
    +@@ -6406,16 +6369,28 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager
    +             return true;
    +         }
    +         super.gatherTransparentRegion(region);
    +-        final View[] children = mChildren;
    +-        final int count = mChildrenCount;
    ++        // Instead of naively traversing the view tree, we have to traverse according to the Z
    ++        // order here. We need to go with the same order as dispatchDraw().
    ++        // One example is that after surfaceView punch a hole, we will still allow other views drawn
    ++        // on top of that hole. In this case, those other views should be able to cut the
    ++        // transparent region into smaller area.
    ++        final int childrenCount = mChildrenCount;
    +         boolean noneOfTheChildrenAreTransparent = true;
    +-        for (int i = 0; i < count; i++) {
    +-            final View child = children[i];
    +-            if ((child.mViewFlags & VISIBILITY_MASK) == VISIBLE || child.getAnimation() != null) {
    +-                if (!child.gatherTransparentRegion(region)) {
    +-                    noneOfTheChildrenAreTransparent = false;
    ++        if (childrenCount > 0) {
    ++            final ArrayList<View> preorderedList = buildOrderedChildList();
    ++            final boolean customOrder = preorderedList == null
    ++                    && isChildrenDrawingOrderEnabled();
    ++            final View[] children = mChildren;
    ++            for (int i = 0; i < childrenCount; i++) {
    ++                final int childIndex = getAndVerifyPreorderedIndex(childrenCount, i, customOrder);
    ++                final View child = getAndVerifyPreorderedView(preorderedList, children, childIndex);
    ++                if ((child.mViewFlags & VISIBILITY_MASK) == VISIBLE || child.getAnimation() != null) {
    ++                    if (!child.gatherTransparentRegion(region)) {
    ++                        noneOfTheChildrenAreTransparent = false;
    ++                    }
    +                 }
    +             }
    ++            if (preorderedList != null) preorderedList.clear();
    +         }
    +         return meOpaque || noneOfTheChildrenAreTransparent;
    +     }
    +diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
    +index 1bb4c08..e95fa5e 100644
    +--- a/core/java/android/view/ViewRootImpl.java
    ++++ b/core/java/android/view/ViewRootImpl.java
    +@@ -2167,7 +2167,12 @@ public final class ViewRootImpl implements ViewParent,
    +         }
    + 
    +         if (changedVisibility || regainedFocus) {
    +-            host.sendAccessibilityEvent(AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED);
    ++            // Toasts are presented as notifications - don't present them as windows as well
    ++            boolean isToast = (mWindowAttributes == null) ? false
    ++                    : (mWindowAttributes.type == WindowManager.LayoutParams.TYPE_TOAST);
    ++            if (!isToast) {
    ++                host.sendAccessibilityEvent(AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED);
    ++            }
    +         }
    + 
    +         mFirst = false;
    +@@ -5518,9 +5523,11 @@ public final class ViewRootImpl implements ViewParent,
    +             if (what == DragEvent.ACTION_DRAG_EXITED) {
    +                 // A direct EXITED event means that the window manager knows we've just crossed
    +                 // a window boundary, so the current drag target within this one must have
    +-                // just been exited.  Send it the usual notifications and then we're done
    +-                // for now.
    +-                mView.dispatchDragEvent(event);
    ++                // just been exited. Send the EXITED notification to the current drag view, if any.
    ++                if (View.sCascadedDragDrop) {
    ++                    mView.dispatchDragEnterExitInPreN(event);
    ++                }
    ++                setDragFocus(null, event);
    +             } else {
    +                 // For events with a [screen] location, translate into window coordinates
    +                 if ((what == DragEvent.ACTION_DRAG_LOCATION) || (what == DragEvent.ACTION_DROP)) {
    +@@ -5543,6 +5550,12 @@ public final class ViewRootImpl implements ViewParent,
    +                 // Now dispatch the drag/drop event
    +                 boolean result = mView.dispatchDragEvent(event);
    + 
    ++                if (what == DragEvent.ACTION_DRAG_LOCATION && !event.mEventHandlerWasCalled) {
    ++                    // If the LOCATION event wasn't delivered to any handler, no view now has a drag
    ++                    // focus.
    ++                    setDragFocus(null, event);
    ++                }
    ++
    +                 // If we changed apparent drag target, tell the OS about it
    +                 if (prevDragView != mCurrentDragView) {
    +                     try {
    +@@ -5570,6 +5583,7 @@ public final class ViewRootImpl implements ViewParent,
    + 
    +                 // When the drag operation ends, reset drag-related state
    +                 if (what == DragEvent.ACTION_DRAG_ENDED) {
    ++                    mCurrentDragView = null;
    +                     setLocalDragState(null);
    +                     mAttachInfo.mDragToken = null;
    +                     if (mAttachInfo.mDragSurface != null) {
    +@@ -5629,10 +5643,33 @@ public final class ViewRootImpl implements ViewParent,
    +         return mLastTouchSource;
    +     }
    + 
    +-    public void setDragFocus(View newDragTarget) {
    +-        if (mCurrentDragView != newDragTarget) {
    +-            mCurrentDragView = newDragTarget;
    ++    public void setDragFocus(View newDragTarget, DragEvent event) {
    ++        if (mCurrentDragView != newDragTarget && !View.sCascadedDragDrop) {
    ++            // Send EXITED and ENTERED notifications to the old and new drag focus views.
    ++
    ++            final float tx = event.mX;
    ++            final float ty = event.mY;
    ++            final int action = event.mAction;
    ++            // Position should not be available for ACTION_DRAG_ENTERED and ACTION_DRAG_EXITED.
    ++            event.mX = 0;
    ++            event.mY = 0;
    ++
    ++            if (mCurrentDragView != null) {
    ++                event.mAction = DragEvent.ACTION_DRAG_EXITED;
    ++                mCurrentDragView.callDragEventHandler(event);
    ++            }
    ++
    ++            if (newDragTarget != null) {
    ++                event.mAction = DragEvent.ACTION_DRAG_ENTERED;
    ++                newDragTarget.callDragEventHandler(event);
    ++            }
    ++
    ++            event.mAction = action;
    ++            event.mX = tx;
    ++            event.mY = ty;
    +         }
    ++
    ++        mCurrentDragView = newDragTarget;
    +     }
    + 
    +     private AudioManager getAudioManager() {
    +diff --git a/core/java/android/view/WindowManager.java b/core/java/android/view/WindowManager.java
    +index 0dbf00d..395f738 100644
    +--- a/core/java/android/view/WindowManager.java
    ++++ b/core/java/android/view/WindowManager.java
    +@@ -1752,14 +1752,18 @@ public interface WindowManager extends ViewManager {
    +         public CharSequence accessibilityTitle;
    + 
    +         /**
    +-         * Sets a timeout in milliseconds before which the window will be removed
    ++         * Sets a timeout in milliseconds before which the window will be hidden
    +          * by the window manager. Useful for transient notifications like toasts
    +          * so we don't have to rely on client cooperation to ensure the window
    +-         * is removed. Must be specified at window creation time.
    ++         * is hidden. Must be specified at window creation time. Note that apps
    ++         * are not prepared to handle their windows being removed without their
    ++         * explicit request and may try to interact with the removed window
    ++         * resulting in undefined behavior and crashes. Therefore, we do hide
    ++         * such windows to prevent them from overlaying other apps.
    +          *
    +          * @hide
    +          */
    +-        public long removeTimeoutMilliseconds = -1;
    ++        public long hideTimeoutMilliseconds = -1;
    + 
    +         public LayoutParams() {
    +             super(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);
    +@@ -1895,7 +1899,7 @@ public interface WindowManager extends ViewManager {
    +             out.writeInt(needsMenuKey);
    +             out.writeInt(accessibilityIdOfAnchor);
    +             TextUtils.writeToParcel(accessibilityTitle, out, parcelableFlags);
    +-            out.writeLong(removeTimeoutMilliseconds);
    ++            out.writeLong(hideTimeoutMilliseconds);
    +         }
    + 
    +         public static final Parcelable.Creator<LayoutParams> CREATOR
    +@@ -1949,7 +1953,7 @@ public interface WindowManager extends ViewManager {
    +             needsMenuKey = in.readInt();
    +             accessibilityIdOfAnchor = in.readInt();
    +             accessibilityTitle = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(in);
    +-            removeTimeoutMilliseconds = in.readLong();
    ++            hideTimeoutMilliseconds = in.readLong();
    +         }
    + 
    +         @SuppressWarnings({"PointlessBitwiseExpression"})
    +@@ -2171,7 +2175,7 @@ public interface WindowManager extends ViewManager {
    +             }
    + 
    +             // This can't change, it's only set at window creation time.
    +-            removeTimeoutMilliseconds = o.removeTimeoutMilliseconds;
    ++            hideTimeoutMilliseconds = o.hideTimeoutMilliseconds;
    + 
    +             return changes;
    +         }
    +diff --git a/core/java/android/view/WindowManagerPolicy.java b/core/java/android/view/WindowManagerPolicy.java
    +index b52e4b0..46a0194 100644
    +--- a/core/java/android/view/WindowManagerPolicy.java
    ++++ b/core/java/android/view/WindowManagerPolicy.java
    +@@ -507,6 +507,11 @@ public interface WindowManagerPolicy {
    +          * Retrieves the {@param outBounds} from the stack with id {@param stackId}.
    +          */
    +         void getStackBounds(int stackId, Rect outBounds);
    ++
    ++        /**
    ++         * Overrides all currently playing app animations with {@param a}.
    ++         */
    ++        void overridePlayingAppAnimationsLw(Animation a);
    +     }
    + 
    +     public interface PointerEventListener {
    +@@ -1301,6 +1306,16 @@ public interface WindowManagerPolicy {
    +     public int adjustSystemUiVisibilityLw(int visibility);
    + 
    +     /**
    ++     * Called by System UI to notify of changes to the visibility of Recents.
    ++     */
    ++    public void setRecentsVisibilityLw(boolean visible);
    ++
    ++    /**
    ++     * Called by System UI to notify of changes to the visibility of PIP.
    ++     */
    ++    public void setTvPipVisibilityLw(boolean visible);
    ++
    ++    /**
    +      * Specifies whether there is an on-screen navigation bar separate from the status bar.
    +      */
    +     public boolean hasNavigationBar();
    +diff --git a/core/java/android/view/inputmethod/InputConnection.java b/core/java/android/view/inputmethod/InputConnection.java
    +index 07910b6..71c1d62 100644
    +--- a/core/java/android/view/inputmethod/InputConnection.java
    ++++ b/core/java/android/view/inputmethod/InputConnection.java
    +@@ -43,12 +43,14 @@ import android.view.KeyEvent;
    +  *     in {@link android.os.Build.VERSION_CODES#HONEYCOMB}.</li>
    +  *     <li>{@link #requestCursorUpdates(int)}, which was introduced in
    +  *     {@link android.os.Build.VERSION_CODES#LOLLIPOP}.</li>
    +- *     <li>{@link #deleteSurroundingTextInCodePoints(int, int)}}, which
    ++ *     <li>{@link #deleteSurroundingTextInCodePoints(int, int)}, which
    +  *     was introduced in {@link android.os.Build.VERSION_CODES#N}.</li>
    +- *     <li>{@link #getHandler()}}, which was introduced in
    ++ *     <li>{@link #getHandler()}, which was introduced in
    +  *     {@link android.os.Build.VERSION_CODES#N}.</li>
    +- *     <li>{@link #closeConnection()}}, which was introduced in
    ++ *     <li>{@link #closeConnection()}, which was introduced in
    +  *     {@link android.os.Build.VERSION_CODES#N}.</li>
    ++ *     <li>{@link #commitContent(InputContentInfo, int, Bundle)}, which was
    ++ *     introduced in {@link android.os.Build.VERSION_CODES#N_MR1}.</li>
    +  * </ul>
    +  *
    +  * <h3>Implementing an IME or an editor</h3>
    +@@ -858,32 +860,35 @@ public interface InputConnection {
    +             android.content.Intent.FLAG_GRANT_READ_URI_PERMISSION;  // 0x00000001
    + 
    +     /**
    +-     * Called by the input method to commit a content such as PNG image to the editor.
    ++     * Called by the input method to commit content such as a PNG image to the editor.
    +      *
    +-     * <p>In order to avoid variety of compatibility issues, this focuses on a simple use case,
    +-     * where we expect editors and IMEs work cooperatively as follows:</p>
    ++     * <p>In order to avoid a variety of compatibility issues, this focuses on a simple use case,
    ++     * where editors and IMEs are expected to work cooperatively as follows:</p>
    +      * <ul>
    +-     *     <li>Editor must keep {@link EditorInfo#contentMimeTypes} to be {@code null} if it does
    ++     *     <li>Editor must keep {@link EditorInfo#contentMimeTypes} equal to {@code null} if it does
    +      *     not support this method at all.</li>
    +      *     <li>Editor can ignore this request when the MIME type specified in
    +-     *     {@code inputContentInfo} does not match to any of {@link EditorInfo#contentMimeTypes}.
    ++     *     {@code inputContentInfo} does not match any of {@link EditorInfo#contentMimeTypes}.
    +      *     </li>
    +-     *     <li>Editor can ignore the cursor position when inserting the provided context.</li>
    ++     *     <li>Editor can ignore the cursor position when inserting the provided content.</li>
    +      *     <li>Editor can return {@code true} asynchronously, even before it starts loading the
    +      *     content.</li>
    +-     *     <li>Editor should provide a way to delete the content inserted by this method, or revert
    +-     *     the effect caused by this method.</li>
    ++     *     <li>Editor should provide a way to delete the content inserted by this method or to
    ++     *     revert the effect caused by this method.</li>
    +      *     <li>IME should not call this method when there is any composing text, in case calling
    +-     *     this method causes focus change.</li>
    ++     *     this method causes a focus change.</li>
    +      *     <li>IME should grant a permission for the editor to read the content. See
    +      *     {@link EditorInfo#packageName} about how to obtain the package name of the editor.</li>
    +      * </ul>
    +      *
    +      * @param inputContentInfo Content to be inserted.
    +-     * @param flags {@code 0} or {@link #INPUT_CONTENT_GRANT_READ_URI_PERMISSION}.
    ++     * @param flags {@link #INPUT_CONTENT_GRANT_READ_URI_PERMISSION} if the content provider
    ++     * allows {@link android.R.styleable#AndroidManifestProvider_grantUriPermissions
    ++     * grantUriPermissions} or {@code 0} if the application does not need to call
    ++     * {@link InputContentInfo#requestPermission()}.
    +      * @param opts optional bundle data. This can be {@code null}.
    +-     * @return {@code true} if this request is accepted by the application, no matter if the request
    +-     * is already handled or still being handled in background.
    ++     * @return {@code true} if this request is accepted by the application, whether the request
    ++     * is already handled or still being handled in background, {@code false} otherwise.
    +      */
    +     public boolean commitContent(@NonNull InputContentInfo inputContentInfo, int flags,
    +             @Nullable Bundle opts);
    +diff --git a/core/java/android/view/inputmethod/InputMethodManager.java b/core/java/android/view/inputmethod/InputMethodManager.java
    +index c0c8e64..2e9cbf2 100644
    +--- a/core/java/android/view/inputmethod/InputMethodManager.java
    ++++ b/core/java/android/view/inputmethod/InputMethodManager.java
    +@@ -2056,12 +2056,10 @@ public final class InputMethodManager {
    +      * have any input method subtype.
    +      */
    +     public InputMethodSubtype getCurrentInputMethodSubtype() {
    +-        synchronized (mH) {
    +-            try {
    +-                return mService.getCurrentInputMethodSubtype();
    +-            } catch (RemoteException e) {
    +-                throw e.rethrowFromSystemServer();
    +-            }
    ++        try {
    ++            return mService.getCurrentInputMethodSubtype();
    ++        } catch (RemoteException e) {
    ++            throw e.rethrowFromSystemServer();
    +         }
    +     }
    + 
    +diff --git a/core/java/android/widget/DatePicker.java b/core/java/android/widget/DatePicker.java
    +index 8613f99..54818a1 100644
    +--- a/core/java/android/widget/DatePicker.java
    ++++ b/core/java/android/widget/DatePicker.java
    +@@ -18,7 +18,9 @@ package android.widget;
    + 
    + import com.android.internal.R;
    + 
    ++import android.annotation.IntDef;
    + import android.annotation.Nullable;
    ++import android.annotation.TestApi;
    + import android.annotation.Widget;
    + import android.content.Context;
    + import android.content.res.Configuration;
    +@@ -32,6 +34,8 @@ import android.util.SparseArray;
    + import android.view.View;
    + import android.view.accessibility.AccessibilityEvent;
    + 
    ++import java.lang.annotation.Retention;
    ++import java.lang.annotation.RetentionPolicy;
    + import java.util.Locale;
    + 
    + /**
    +@@ -75,11 +79,36 @@ import java.util.Locale;
    +  */
    + @Widget
    + public class DatePicker extends FrameLayout {
    +-    private static final int MODE_SPINNER = 1;
    +-    private static final int MODE_CALENDAR = 2;
    ++    /**
    ++     * Presentation mode for the Holo-style date picker that uses a set of
    ++     * {@link android.widget.NumberPicker}s.
    ++     *
    ++     * @see #getMode()
    ++     * @hide Visible for testing only.
    ++     */
    ++    @TestApi
    ++    public static final int MODE_SPINNER = 1;
    ++
    ++    /**
    ++     * Presentation mode for the Material-style date picker that uses a
    ++     * calendar.
    ++     *
    ++     * @see #getMode()
    ++     * @hide Visible for testing only.
    ++     */
    ++    @TestApi
    ++    public static final int MODE_CALENDAR = 2;
    ++
    ++    /** @hide */
    ++    @IntDef({MODE_SPINNER, MODE_CALENDAR})
    ++    @Retention(RetentionPolicy.SOURCE)
    ++    public @interface DatePickerMode {}
    + 
    +     private final DatePickerDelegate mDelegate;
    + 
    ++    @DatePickerMode
    ++    private final int mMode;
    ++
    +     /**
    +      * The callback used to indicate the user changed the date.
    +      */
    +@@ -114,11 +143,20 @@ public class DatePicker extends FrameLayout {
    + 
    +         final TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.DatePicker,
    +                 defStyleAttr, defStyleRes);
    +-        final int mode = a.getInt(R.styleable.DatePicker_datePickerMode, MODE_SPINNER);
    ++        final boolean isDialogMode = a.getBoolean(R.styleable.DatePicker_dialogMode, false);
    ++        final int requestedMode = a.getInt(R.styleable.DatePicker_datePickerMode, MODE_SPINNER);
    +         final int firstDayOfWeek = a.getInt(R.styleable.DatePicker_firstDayOfWeek, 0);
    +         a.recycle();
    + 
    +-        switch (mode) {
    ++        if (requestedMode == MODE_CALENDAR && isDialogMode) {
    ++            // You want MODE_CALENDAR? YOU CAN'T HANDLE MODE_CALENDAR! Well,
    ++            // maybe you can depending on your screen size. Let's check...
    ++            mMode = context.getResources().getInteger(R.integer.date_picker_mode);
    ++        } else {
    ++            mMode = requestedMode;
    ++        }
    ++
    ++        switch (mMode) {
    +             case MODE_CALENDAR:
    +                 mDelegate = createCalendarUIDelegate(context, attrs, defStyleAttr, defStyleRes);
    +                 break;
    +@@ -145,6 +183,18 @@ public class DatePicker extends FrameLayout {
    +     }
    + 
    +     /**
    ++     * @return the picker's presentation mode, one of {@link #MODE_CALENDAR} or
    ++     *         {@link #MODE_SPINNER}
    ++     * @attr ref android.R.styleable#DatePicker_datePickerMode
    ++     * @hide Visible for testing only.
    ++     */
    ++    @DatePickerMode
    ++    @TestApi
    ++    public int getMode() {
    ++        return mMode;
    ++    }
    ++
    ++    /**
    +      * Initialize the state. If the provided values designate an inconsistent
    +      * date the values are normalized before updating the spinners.
    +      *
    +diff --git a/core/java/android/widget/ImageView.java b/core/java/android/widget/ImageView.java
    +index aa67c82..4d405c5 100644
    +--- a/core/java/android/widget/ImageView.java
    ++++ b/core/java/android/widget/ImageView.java
    +@@ -467,6 +467,14 @@ public class ImageView extends View {
    +      * {@link #setImageBitmap(android.graphics.Bitmap)} and
    +      * {@link android.graphics.BitmapFactory} instead.</p>
    +      *
    ++     * <p class="note">On devices running SDK < 24, this method will fail to
    ++     * apply correct density scaling to images loaded from
    ++     * {@link ContentResolver#SCHEME_CONTENT content} and
    ++     * {@link ContentResolver#SCHEME_FILE file} schemes. Applications running
    ++     * on devices with SDK >= 24 <strong>MUST</strong> specify the
    ++     * {@code targetSdkVersion} in their manifest as 24 or above for density
    ++     * scaling to be applied to images loaded from these schemes.</p>
    ++     *
    +      * @param uri the Uri of an image, or {@code null} to clear the content
    +      */
    +     @android.view.RemotableViewMethod(asyncImpl="setImageURIAsync")
    +@@ -1441,7 +1449,9 @@ public class ImageView extends View {
    +     /**
    +      * Returns the alpha that will be applied to the drawable of this ImageView.
    +      *
    +-     * @return the alpha that will be applied to the drawable of this ImageView
    ++     * @return the alpha value that will be applied to the drawable of this
    ++     * ImageView (between 0 and 255 inclusive, with 0 being transparent and
    ++     * 255 being opaque)
    +      *
    +      * @see #setImageAlpha(int)
    +      */
    +@@ -1452,7 +1462,8 @@ public class ImageView extends View {
    +     /**
    +      * Sets the alpha value that should be applied to the image.
    +      *
    +-     * @param alpha the alpha value that should be applied to the image
    ++     * @param alpha the alpha value that should be applied to the image (between
    ++     * 0 and 255 inclusive, with 0 being transparent and 255 being opaque)
    +      *
    +      * @see #getImageAlpha()
    +      */
    +diff --git a/core/java/android/widget/NumberPicker.java b/core/java/android/widget/NumberPicker.java
    +index c3ddec7..25580fd 100644
    +--- a/core/java/android/widget/NumberPicker.java
    ++++ b/core/java/android/widget/NumberPicker.java
    +@@ -16,6 +16,8 @@
    + 
    + package android.widget;
    + 
    ++import com.android.internal.R;
    ++
    + import android.annotation.CallSuper;
    + import android.annotation.IntDef;
    + import android.annotation.Widget;
    +@@ -29,10 +31,12 @@ import android.graphics.Paint.Align;
    + import android.graphics.Rect;
    + import android.graphics.drawable.Drawable;
    + import android.os.Bundle;
    ++import android.text.Editable;
    + import android.text.InputFilter;
    + import android.text.InputType;
    + import android.text.Spanned;
    + import android.text.TextUtils;
    ++import android.text.TextWatcher;
    + import android.text.method.NumberKeyListener;
    + import android.util.AttributeSet;
    + import android.util.SparseArray;
    +@@ -52,9 +56,6 @@ import android.view.animation.DecelerateInterpolator;
    + import android.view.inputmethod.EditorInfo;
    + import android.view.inputmethod.InputMethodManager;
    + 
    +-import com.android.internal.R;
    +-import libcore.icu.LocaleData;
    +-
    + import java.lang.annotation.Retention;
    + import java.lang.annotation.RetentionPolicy;
    + import java.util.ArrayList;
    +@@ -62,6 +63,8 @@ import java.util.Collections;
    + import java.util.List;
    + import java.util.Locale;
    + 
    ++import libcore.icu.LocaleData;
    ++
    + /**
    +  * A widget that enables the user to select a number from a predefined range.
    +  * There are two flavors of this widget and which one is presented to the user
    +@@ -1991,7 +1994,7 @@ public class NumberPicker extends LinearLayout {
    +             removeCallbacks(mChangeCurrentByOneFromLongPressCommand);
    +         }
    +         if (mSetSelectionCommand != null) {
    +-            removeCallbacks(mSetSelectionCommand);
    ++            mSetSelectionCommand.cancel();
    +         }
    +         if (mBeginSoftInputOnLongPressCommand != null) {
    +             removeCallbacks(mBeginSoftInputOnLongPressCommand);
    +@@ -2033,18 +2036,14 @@ public class NumberPicker extends LinearLayout {
    +     }
    + 
    +     /**
    +-     * Posts an {@link SetSelectionCommand} from the given <code>selectionStart
    +-     * </code> to <code>selectionEnd</code>.
    ++     * Posts a {@link SetSelectionCommand} from the given
    ++     * {@code selectionStart} to {@code selectionEnd}.
    +      */
    +     private void postSetSelectionCommand(int selectionStart, int selectionEnd) {
    +         if (mSetSelectionCommand == null) {
    +-            mSetSelectionCommand = new SetSelectionCommand();
    +-        } else {
    +-            removeCallbacks(mSetSelectionCommand);
    ++            mSetSelectionCommand = new SetSelectionCommand(mInputText);
    +         }
    +-        mSetSelectionCommand.mSelectionStart = selectionStart;
    +-        mSetSelectionCommand.mSelectionEnd = selectionEnd;
    +-        post(mSetSelectionCommand);
    ++        mSetSelectionCommand.post(selectionStart, selectionEnd);
    +     }
    + 
    +     /**
    +@@ -2090,6 +2089,12 @@ public class NumberPicker extends LinearLayout {
    +         @Override
    +         public CharSequence filter(
    +                 CharSequence source, int start, int end, Spanned dest, int dstart, int dend) {
    ++            // We don't know what the output will be, so always cancel any
    ++            // pending set selection command.
    ++            if (mSetSelectionCommand != null) {
    ++                mSetSelectionCommand.cancel();
    ++            }
    ++
    +             if (mDisplayedValues == null) {
    +                 CharSequence filtered = super.filter(source, start, end, dest, dstart, dend);
    +                 if (filtered == null) {
    +@@ -2237,12 +2242,39 @@ public class NumberPicker extends LinearLayout {
    +     /**
    +      * Command for setting the input text selection.
    +      */
    +-    class SetSelectionCommand implements Runnable {
    +-        private int mSelectionStart;
    ++    private static class SetSelectionCommand implements Runnable {
    ++        private final EditText mInputText;
    + 
    ++        private int mSelectionStart;
    +         private int mSelectionEnd;
    + 
    ++        /** Whether this runnable is currently posted. */
    ++        private boolean mPosted;
    ++
    ++        public SetSelectionCommand(EditText inputText) {
    ++            mInputText = inputText;
    ++        }
    ++
    ++        public void post(int selectionStart, int selectionEnd) {
    ++            mSelectionStart = selectionStart;
    ++            mSelectionEnd = selectionEnd;
    ++
    ++            if (!mPosted) {
    ++                mInputText.post(this);
    ++                mPosted = true;
    ++            }
    ++        }
    ++
    ++        public void cancel() {
    ++            if (mPosted) {
    ++                mInputText.removeCallbacks(this);
    ++                mPosted = false;
    ++            }
    ++        }
    ++
    ++        @Override
    +         public void run() {
    ++            mPosted = false;
    +             mInputText.setSelection(mSelectionStart, mSelectionEnd);
    +         }
    +     }
    +diff --git a/core/java/android/widget/PopupWindow.java b/core/java/android/widget/PopupWindow.java
    +index 6432f70..9b89491 100644
    +--- a/core/java/android/widget/PopupWindow.java
    ++++ b/core/java/android/widget/PopupWindow.java
    +@@ -193,6 +193,8 @@ public class PopupWindow {
    + 
    +     private int mAnimationStyle = ANIMATION_STYLE_DEFAULT;
    + 
    ++    private int mGravity = Gravity.NO_GRAVITY;
    ++
    +     private static final int[] ABOVE_ANCHOR_STATE_SET = new int[] {
    +         com.android.internal.R.attr.state_above_anchor
    +     };
    +@@ -1141,15 +1143,11 @@ public class PopupWindow {
    + 
    +         mIsShowing = true;
    +         mIsDropdown = false;
    ++        mGravity = gravity;
    + 
    +         final WindowManager.LayoutParams p = createPopupLayoutParams(token);
    +         preparePopup(p);
    + 
    +-        // Only override the default if some gravity was specified.
    +-        if (gravity != Gravity.NO_GRAVITY) {
    +-            p.gravity = gravity;
    +-        }
    +-
    +         p.x = x;
    +         p.y = y;
    + 
    +@@ -1394,8 +1392,8 @@ public class PopupWindow {
    +     }
    + 
    +     private int computeGravity() {
    +-        int gravity = Gravity.START | Gravity.TOP;
    +-        if (mClipToScreen || mClippingEnabled) {
    ++        int gravity = mGravity == Gravity.NO_GRAVITY ?  Gravity.START | Gravity.TOP : mGravity;
    ++        if (mIsDropdown && (mClipToScreen || mClippingEnabled)) {
    +             gravity |= Gravity.DISPLAY_CLIP_VERTICAL;
    +         }
    +         return gravity;
    +@@ -1547,7 +1545,7 @@ public class PopupWindow {
    +         }
    + 
    +         // Let the window manager know to align the top to y.
    +-        outParams.gravity = Gravity.LEFT | Gravity.TOP;
    ++        outParams.gravity = computeGravity();
    +         outParams.width = width;
    +         outParams.height = height;
    + 
    +@@ -1760,11 +1758,22 @@ public class PopupWindow {
    +      */
    +     public int getMaxAvailableHeight(
    +             @NonNull View anchor, int yOffset, boolean ignoreBottomDecorations) {
    +-        final Rect displayFrame = new Rect();
    ++        Rect displayFrame = null;
    ++        final Rect visibleDisplayFrame = new Rect();
    ++
    ++        anchor.getWindowVisibleDisplayFrame(visibleDisplayFrame);
    +         if (ignoreBottomDecorations) {
    ++            // In the ignore bottom decorations case we want to
    ++            // still respect all other decorations so we use the inset visible
    ++            // frame on the top right and left and take the bottom
    ++            // value from the full frame.
    ++            displayFrame = new Rect();
    +             anchor.getWindowDisplayFrame(displayFrame);
    ++            displayFrame.top = visibleDisplayFrame.top;
    ++            displayFrame.right = visibleDisplayFrame.right;
    ++            displayFrame.left = visibleDisplayFrame.left;
    +         } else {
    +-            anchor.getWindowVisibleDisplayFrame(displayFrame);
    ++            displayFrame = visibleDisplayFrame;
    +         }
    + 
    +         final int[] anchorPos = mTmpDrawingLocation;
    +diff --git a/core/java/android/widget/ProgressBar.java b/core/java/android/widget/ProgressBar.java
    +index 3c967ac..1f379c9 100644
    +--- a/core/java/android/widget/ProgressBar.java
    ++++ b/core/java/android/widget/ProgressBar.java
    +@@ -22,6 +22,7 @@ import android.annotation.NonNull;
    + import android.annotation.Nullable;
    + import android.content.Context;
    + import android.content.res.ColorStateList;
    ++import android.content.res.Resources;
    + import android.content.res.TypedArray;
    + import android.graphics.Bitmap;
    + import android.graphics.Canvas;
    +@@ -230,7 +231,7 @@ public class ProgressBar extends View {
    +     private Drawable mCurrentDrawable;
    +     private ProgressTintInfo mProgressTintInfo;
    + 
    +-    Bitmap mSampleTile;
    ++    int mSampleWidth = 0;
    +     private boolean mNoInvalidate;
    +     private Interpolator mInterpolator;
    +     private RefreshProgressRunnable mRefreshProgressRunnable;
    +@@ -505,15 +506,14 @@ public class ProgressBar extends View {
    +         }
    + 
    +         if (drawable instanceof BitmapDrawable) {
    +-            final BitmapDrawable bitmap = (BitmapDrawable) drawable;
    +-            final Bitmap tileBitmap = bitmap.getBitmap();
    +-            if (mSampleTile == null) {
    +-                mSampleTile = tileBitmap;
    +-            }
    +-
    +-            final BitmapDrawable clone = (BitmapDrawable) bitmap.getConstantState().newDrawable();
    ++            final Drawable.ConstantState cs = drawable.getConstantState();
    ++            final BitmapDrawable clone = (BitmapDrawable) cs.newDrawable(getResources());
    +             clone.setTileModeXY(Shader.TileMode.REPEAT, Shader.TileMode.CLAMP);
    + 
    ++            if (mSampleWidth <= 0) {
    ++                mSampleWidth = clone.getIntrinsicWidth();
    ++            }
    ++
    +             if (clip) {
    +                 return new ClipDrawable(clone, Gravity.LEFT, ClipDrawable.HORIZONTAL);
    +             } else {
    +diff --git a/core/java/android/widget/RatingBar.java b/core/java/android/widget/RatingBar.java
    +index 3ad05b5..62dd90f 100644
    +--- a/core/java/android/widget/RatingBar.java
    ++++ b/core/java/android/widget/RatingBar.java
    +@@ -281,10 +281,8 @@ public class RatingBar extends AbsSeekBar {
    +     protected synchronized void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
    +         super.onMeasure(widthMeasureSpec, heightMeasureSpec);
    + 
    +-        if (mSampleTile != null) {
    +-            // TODO: Once ProgressBar's TODOs are gone, this can be done more
    +-            // cleanly than mSampleTile
    +-            final int width = mSampleTile.getWidth() * mNumStars;
    ++        if (mSampleWidth > 0) {
    ++            final int width = mSampleWidth * mNumStars;
    +             setMeasuredDimension(resolveSizeAndState(width, widthMeasureSpec, 0),
    +                     getMeasuredHeight());
    +         }
    +diff --git a/core/java/android/widget/SearchView.java b/core/java/android/widget/SearchView.java
    +index 5878cad..9139361 100644
    +--- a/core/java/android/widget/SearchView.java
    ++++ b/core/java/android/widget/SearchView.java
    +@@ -816,9 +816,11 @@ public class SearchView extends LinearLayout implements CollapsibleActionView {
    + 
    +         switch (heightMode) {
    +             case MeasureSpec.AT_MOST:
    +-            case MeasureSpec.UNSPECIFIED:
    +                 height = Math.min(getPreferredHeight(), height);
    +                 break;
    ++            case MeasureSpec.UNSPECIFIED:
    ++                height = getPreferredHeight();
    ++                break;
    +         }
    +         heightMode = MeasureSpec.EXACTLY;
    + 
    +diff --git a/core/java/android/widget/Switch.java b/core/java/android/widget/Switch.java
    +index c4a1771..a01d65a 100644
    +--- a/core/java/android/widget/Switch.java
    ++++ b/core/java/android/widget/Switch.java
    +@@ -65,6 +65,9 @@ import com.android.internal.R;
    +  * {@link #setSwitchTextAppearance(android.content.Context, int) switchTextAppearance} and
    +  * the related setSwitchTypeface() methods control that of the thumb.
    +  *
    ++ * <p>{@link android.support.v7.widget.SwitchCompat} is a version of
    ++ * the Switch widget which runs on devices back to API 7.</p>
    ++ *
    +  * <p>See the <a href="{@docRoot}guide/topics/ui/controls/togglebutton.html">Toggle Buttons</a>
    +  * guide.</p>
    +  *
    +diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
    +index d3cb742..f8daa88 100644
    +--- a/core/java/android/widget/TextView.java
    ++++ b/core/java/android/widget/TextView.java
    +@@ -3234,6 +3234,10 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
    +      * Sets the text color for all the states (normal, selected,
    +      * focused) to be this color.
    +      *
    ++     * @param color A color value in the form 0xAARRGGBB.
    ++     * Do not pass a resource ID. To get a color value from a resource ID, call
    ++     * {@link android.support.v4.content.ContextCompat#getColor(Context, int) getColor}.
    ++     *
    +      * @see #setTextColor(ColorStateList)
    +      * @see #getTextColors()
    +      *
    +diff --git a/core/java/android/widget/TimePicker.java b/core/java/android/widget/TimePicker.java
    +index f2fc617..a1c854b 100644
    +--- a/core/java/android/widget/TimePicker.java
    ++++ b/core/java/android/widget/TimePicker.java
    +@@ -16,20 +16,24 @@
    + 
    + package android.widget;
    + 
    ++import com.android.internal.R;
    ++
    ++import android.annotation.IntDef;
    ++import android.annotation.IntRange;
    + import android.annotation.NonNull;
    +-import android.annotation.Nullable;
    ++import android.annotation.TestApi;
    + import android.annotation.Widget;
    + import android.content.Context;
    +-import android.content.res.Configuration;
    + import android.content.res.TypedArray;
    + import android.os.Parcel;
    + import android.os.Parcelable;
    +-import android.os.Parcelable.Creator;
    + import android.util.AttributeSet;
    ++import android.util.MathUtils;
    + import android.view.View;
    + import android.view.accessibility.AccessibilityEvent;
    +-import com.android.internal.R;
    + 
    ++import java.lang.annotation.Retention;
    ++import java.lang.annotation.RetentionPolicy;
    + import java.util.Locale;
    + 
    + import libcore.icu.LocaleData;
    +@@ -45,11 +49,36 @@ import libcore.icu.LocaleData;
    +  */
    + @Widget
    + public class TimePicker extends FrameLayout {
    +-    private static final int MODE_SPINNER = 1;
    +-    private static final int MODE_CLOCK = 2;
    ++    /**
    ++     * Presentation mode for the Holo-style time picker that uses a set of
    ++     * {@link android.widget.NumberPicker}s.
    ++     *
    ++     * @see #getMode()
    ++     * @hide Visible for testing only.
    ++     */
    ++    @TestApi
    ++    public static final int MODE_SPINNER = 1;
    ++
    ++    /**
    ++     * Presentation mode for the Material-style time picker that uses a clock
    ++     * face.
    ++     *
    ++     * @see #getMode()
    ++     * @hide Visible for testing only.
    ++     */
    ++    @TestApi
    ++    public static final int MODE_CLOCK = 2;
    ++
    ++    /** @hide */
    ++    @IntDef({MODE_SPINNER, MODE_CLOCK})
    ++    @Retention(RetentionPolicy.SOURCE)
    ++    public @interface TimePickerMode {}
    + 
    +     private final TimePickerDelegate mDelegate;
    + 
    ++    @TimePickerMode
    ++    private final int mMode;
    ++
    +     /**
    +      * The callback interface used to indicate the time has been adjusted.
    +      */
    +@@ -80,10 +109,19 @@ public class TimePicker extends FrameLayout {
    + 
    +         final TypedArray a = context.obtainStyledAttributes(
    +                 attrs, R.styleable.TimePicker, defStyleAttr, defStyleRes);
    +-        final int mode = a.getInt(R.styleable.TimePicker_timePickerMode, MODE_SPINNER);
    ++        final boolean isDialogMode = a.getBoolean(R.styleable.TimePicker_dialogMode, false);
    ++        final int requestedMode = a.getInt(R.styleable.TimePicker_timePickerMode, MODE_SPINNER);
    +         a.recycle();
    + 
    +-        switch (mode) {
    ++        if (requestedMode == MODE_CLOCK && isDialogMode) {
    ++            // You want MODE_CLOCK? YOU CAN'T HANDLE MODE_CLOCK! Well, maybe
    ++            // you can depending on your screen size. Let's check...
    ++            mMode = context.getResources().getInteger(R.integer.time_picker_mode);
    ++        } else {
    ++            mMode = requestedMode;
    ++        }
    ++
    ++        switch (mMode) {
    +             case MODE_CLOCK:
    +                 mDelegate = new TimePickerClockDelegate(
    +                         this, context, attrs, defStyleAttr, defStyleRes);
    +@@ -97,13 +135,25 @@ public class TimePicker extends FrameLayout {
    +     }
    + 
    +     /**
    ++     * @return the picker's presentation mode, one of {@link #MODE_CLOCK} or
    ++     *         {@link #MODE_SPINNER}
    ++     * @attr ref android.R.styleable#TimePicker_timePickerMode
    ++     * @hide Visible for testing only.
    ++     */
    ++    @TimePickerMode
    ++    @TestApi
    ++    public int getMode() {
    ++        return mMode;
    ++    }
    ++
    ++    /**
    +      * Sets the currently selected hour using 24-hour time.
    +      *
    +      * @param hour the hour to set, in the range (0-23)
    +      * @see #getHour()
    +      */
    +-    public void setHour(int hour) {
    +-        mDelegate.setHour(hour);
    ++    public void setHour(@IntRange(from = 0, to = 23) int hour) {
    ++        mDelegate.setHour(MathUtils.constrain(hour, 0, 23));
    +     }
    + 
    +     /**
    +@@ -117,13 +167,13 @@ public class TimePicker extends FrameLayout {
    +     }
    + 
    +     /**
    +-     * Sets the currently selected minute..
    ++     * Sets the currently selected minute.
    +      *
    +      * @param minute the minute to set, in the range (0-59)
    +      * @see #getMinute()
    +      */
    +-    public void setMinute(int minute) {
    +-        mDelegate.setMinute(minute);
    ++    public void setMinute(@IntRange(from = 0, to = 59) int minute) {
    ++        mDelegate.setMinute(MathUtils.constrain(minute, 0, 59));
    +     }
    + 
    +     /**
    +@@ -137,8 +187,9 @@ public class TimePicker extends FrameLayout {
    +     }
    + 
    +     /**
    +-     * Sets the current hour.
    ++     * Sets the currently selected hour using 24-hour time.
    +      *
    ++     * @param currentHour the hour to set, in the range (0-23)
    +      * @deprecated Use {@link #setHour(int)}
    +      */
    +     @Deprecated
    +@@ -147,33 +198,34 @@ public class TimePicker extends FrameLayout {
    +     }
    + 
    +     /**
    +-     * @return the current hour in the range (0-23)
    ++     * @return the currently selected hour, in the range (0-23)
    +      * @deprecated Use {@link #getHour()}
    +      */
    +     @NonNull
    +     @Deprecated
    +     public Integer getCurrentHour() {
    +-        return mDelegate.getHour();
    ++        return getHour();
    +     }
    + 
    +     /**
    +-     * Set the current minute (0-59).
    ++     * Sets the currently selected minute.
    +      *
    ++     * @param currentMinute the minute to set, in the range (0-59)
    +      * @deprecated Use {@link #setMinute(int)}
    +      */
    +     @Deprecated
    +     public void setCurrentMinute(@NonNull Integer currentMinute) {
    +-        mDelegate.setMinute(currentMinute);
    ++        setMinute(currentMinute);
    +     }
    + 
    +     /**
    +-     * @return the current minute
    ++     * @return the currently selected minute, in the range (0-59)
    +      * @deprecated Use {@link #getMinute()}
    +      */
    +     @NonNull
    +     @Deprecated
    +     public Integer getCurrentMinute() {
    +-        return mDelegate.getMinute();
    ++        return getMinute();
    +     }
    + 
    +     /**
    +@@ -256,10 +308,10 @@ public class TimePicker extends FrameLayout {
    +      * for the real behavior.
    +      */
    +     interface TimePickerDelegate {
    +-        void setHour(int hour);
    ++        void setHour(@IntRange(from = 0, to = 23) int hour);
    +         int getHour();
    + 
    +-        void setMinute(int minute);
    ++        void setMinute(@IntRange(from = 0, to = 59) int minute);
    +         int getMinute();
    + 
    +         void setIs24Hour(boolean is24Hour);
    +diff --git a/core/java/android/widget/Toast.java b/core/java/android/widget/Toast.java
    +index 7762675..a400d90 100644
    +--- a/core/java/android/widget/Toast.java
    ++++ b/core/java/android/widget/Toast.java
    +@@ -25,6 +25,8 @@ import android.content.res.Configuration;
    + import android.content.res.Resources;
    + import android.graphics.PixelFormat;
    + import android.os.Handler;
    ++import android.os.IBinder;
    ++import android.os.Message;
    + import android.os.RemoteException;
    + import android.os.ServiceManager;
    + import android.util.Log;
    +@@ -326,13 +328,6 @@ public class Toast {
    +     }
    + 
    +     private static class TN extends ITransientNotification.Stub {
    +-        final Runnable mShow = new Runnable() {
    +-            @Override
    +-            public void run() {
    +-                handleShow();
    +-            }
    +-        };
    +-
    +         final Runnable mHide = new Runnable() {
    +             @Override
    +             public void run() {
    +@@ -343,7 +338,13 @@ public class Toast {
    +         };
    + 
    +         private final WindowManager.LayoutParams mParams = new WindowManager.LayoutParams();
    +-        final Handler mHandler = new Handler();
    ++        final Handler mHandler = new Handler() {
    ++            @Override
    ++            public void handleMessage(Message msg) {
    ++                IBinder token = (IBinder) msg.obj;
    ++                handleShow(token);
    ++            }
    ++        };
    + 
    +         int mGravity;
    +         int mX, mY;
    +@@ -379,9 +380,9 @@ public class Toast {
    +          * schedule handleShow into the right thread
    +          */
    +         @Override
    +-        public void show() {
    ++        public void show(IBinder windowToken) {
    +             if (localLOGV) Log.v(TAG, "SHOW: " + this);
    +-            mHandler.post(mShow);
    ++            mHandler.obtainMessage(0, windowToken).sendToTarget();
    +         }
    + 
    +         /**
    +@@ -393,7 +394,7 @@ public class Toast {
    +             mHandler.post(mHide);
    +         }
    + 
    +-        public void handleShow() {
    ++        public void handleShow(IBinder windowToken) {
    +             if (localLOGV) Log.v(TAG, "HANDLE SHOW: " + this + " mView=" + mView
    +                     + " mNextView=" + mNextView);
    +             if (mView != mNextView) {
    +@@ -422,8 +423,9 @@ public class Toast {
    +                 mParams.verticalMargin = mVerticalMargin;
    +                 mParams.horizontalMargin = mHorizontalMargin;
    +                 mParams.packageName = packageName;
    +-                mParams.removeTimeoutMilliseconds = mDuration ==
    ++                mParams.hideTimeoutMilliseconds = mDuration ==
    +                     Toast.LENGTH_LONG ? LONG_DURATION_TIMEOUT : SHORT_DURATION_TIMEOUT;
    ++                mParams.token = windowToken;
    +                 if (mView.getParent() != null) {
    +                     if (localLOGV) Log.v(TAG, "REMOVE! " + mView + " in " + this);
    +                     mWM.removeView(mView);
    +@@ -458,7 +460,7 @@ public class Toast {
    +                 // the view isn't yet added, so let's try not to crash.
    +                 if (mView.getParent() != null) {
    +                     if (localLOGV) Log.v(TAG, "REMOVE! " + mView + " in " + this);
    +-                    mWM.removeView(mView);
    ++                    mWM.removeViewImmediate(mView);
    +                 }
    + 
    +                 mView = null;
    +diff --git a/core/java/android/widget/VideoView.java b/core/java/android/widget/VideoView.java
    +index f084db2..b973324 100644
    +--- a/core/java/android/widget/VideoView.java
    ++++ b/core/java/android/widget/VideoView.java
    +@@ -70,46 +70,49 @@ import java.util.Vector;
    +  */
    + public class VideoView extends SurfaceView
    +         implements MediaPlayerControl, SubtitleController.Anchor {
    +-    private String TAG = "VideoView";
    +-    // settable by the client
    +-    private Uri         mUri;
    +-    private Map<String, String> mHeaders;
    ++    private static final String TAG = "VideoView";
    + 
    +     // all possible internal states
    +-    private static final int STATE_ERROR              = -1;
    +-    private static final int STATE_IDLE               = 0;
    +-    private static final int STATE_PREPARING          = 1;
    +-    private static final int STATE_PREPARED           = 2;
    +-    private static final int STATE_PLAYING            = 3;
    +-    private static final int STATE_PAUSED             = 4;
    ++    private static final int STATE_ERROR = -1;
    ++    private static final int STATE_IDLE = 0;
    ++    private static final int STATE_PREPARING = 1;
    ++    private static final int STATE_PREPARED = 2;
    ++    private static final int STATE_PLAYING = 3;
    ++    private static final int STATE_PAUSED = 4;
    +     private static final int STATE_PLAYBACK_COMPLETED = 5;
    + 
    ++    private final Vector<Pair<InputStream, MediaFormat>> mPendingSubtitleTracks = new Vector<>();
    ++
    ++    // settable by the client
    ++    private Uri mUri;
    ++    private Map<String, String> mHeaders;
    ++
    +     // mCurrentState is a VideoView object's current state.
    +     // mTargetState is the state that a method caller intends to reach.
    +     // For instance, regardless the VideoView object's current state,
    +     // calling pause() intends to bring the object to a target state
    +     // of STATE_PAUSED.
    +     private int mCurrentState = STATE_IDLE;
    +-    private int mTargetState  = STATE_IDLE;
    ++    private int mTargetState = STATE_IDLE;
    + 
    +     // All the stuff we need for playing and showing a video
    +     private SurfaceHolder mSurfaceHolder = null;
    +     private MediaPlayer mMediaPlayer = null;
    +-    private int         mAudioSession;
    +-    private int         mVideoWidth;
    +-    private int         mVideoHeight;
    +-    private int         mSurfaceWidth;
    +-    private int         mSurfaceHeight;
    ++    private int mAudioSession;
    ++    private int mVideoWidth;
    ++    private int mVideoHeight;
    ++    private int mSurfaceWidth;
    ++    private int mSurfaceHeight;
    +     private MediaController mMediaController;
    +     private OnCompletionListener mOnCompletionListener;
    +     private MediaPlayer.OnPreparedListener mOnPreparedListener;
    +-    private int         mCurrentBufferPercentage;
    ++    private int mCurrentBufferPercentage;
    +     private OnErrorListener mOnErrorListener;
    +-    private OnInfoListener  mOnInfoListener;
    +-    private int         mSeekWhenPrepared;  // recording the seek position while preparing
    +-    private boolean     mCanPause;
    +-    private boolean     mCanSeekBack;
    +-    private boolean     mCanSeekForward;
    ++    private OnInfoListener mOnInfoListener;
    ++    private int mSeekWhenPrepared;  // recording the seek position while preparing
    ++    private boolean mCanPause;
    ++    private boolean mCanSeekBack;
    ++    private boolean mCanSeekForward;
    + 
    +     /** Subtitle rendering widget overlaid on top of the video. */
    +     private RenderingWidget mSubtitleWidget;
    +@@ -118,13 +121,11 @@ public class VideoView extends SurfaceView
    +     private RenderingWidget.OnChangedListener mSubtitlesChangedListener;
    + 
    +     public VideoView(Context context) {
    +-        super(context);
    +-        initVideoView();
    ++        this(context, null);
    +     }
    + 
    +     public VideoView(Context context, AttributeSet attrs) {
    +         this(context, attrs, 0);
    +-        initVideoView();
    +     }
    + 
    +     public VideoView(Context context, AttributeSet attrs, int defStyleAttr) {
    +@@ -133,7 +134,19 @@ public class VideoView extends SurfaceView
    + 
    +     public VideoView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
    +         super(context, attrs, defStyleAttr, defStyleRes);
    +-        initVideoView();
    ++
    ++        mVideoWidth = 0;
    ++        mVideoHeight = 0;
    ++
    ++        getHolder().addCallback(mSHCallback);
    ++        getHolder().setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
    ++
    ++        setFocusable(true);
    ++        setFocusableInTouchMode(true);
    ++        requestFocus();
    ++
    ++        mCurrentState = STATE_IDLE;
    ++        mTargetState = STATE_IDLE;
    +     }
    + 
    +     @Override
    +@@ -209,19 +222,6 @@ public class VideoView extends SurfaceView
    +         return getDefaultSize(desiredSize, measureSpec);
    +     }
    + 
    +-    private void initVideoView() {
    +-        mVideoWidth = 0;
    +-        mVideoHeight = 0;
    +-        getHolder().addCallback(mSHCallback);
    +-        getHolder().setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
    +-        setFocusable(true);
    +-        setFocusableInTouchMode(true);
    +-        requestFocus();
    +-        mPendingSubtitleTracks = new Vector<Pair<InputStream, MediaFormat>>();
    +-        mCurrentState = STATE_IDLE;
    +-        mTargetState  = STATE_IDLE;
    +-    }
    +-
    +     /**
    +      * Sets video path.
    +      *
    +@@ -294,8 +294,6 @@ public class VideoView extends SurfaceView
    +         }
    +     }
    + 
    +-    private Vector<Pair<InputStream, MediaFormat>> mPendingSubtitleTracks;
    +-
    +     public void stopPlayback() {
    +         if (mMediaPlayer != null) {
    +             mMediaPlayer.stop();
    +diff --git a/core/java/com/android/internal/app/ResolverActivity.java b/core/java/com/android/internal/app/ResolverActivity.java
    +index 0a4ac0d..1e26c92 100644
    +--- a/core/java/com/android/internal/app/ResolverActivity.java
    ++++ b/core/java/com/android/internal/app/ResolverActivity.java
    +@@ -1469,7 +1469,7 @@ public class ResolverActivity extends Activity {
    +                 boolean found = false;
    +                 // Only loop to the end of into as it was before we started; no dupes in from.
    +                 for (int j = 0; j < intoCount; j++) {
    +-                    final ResolvedComponentInfo rci = into.get(i);
    ++                    final ResolvedComponentInfo rci = into.get(j);
    +                     if (isSameResolvedComponent(newInfo, rci)) {
    +                         found = true;
    +                         rci.add(intent, newInfo);
    +diff --git a/core/java/com/android/internal/app/ResolverComparator.java b/core/java/com/android/internal/app/ResolverComparator.java
    +index 03a3a38..4d4c7ce 100644
    +--- a/core/java/com/android/internal/app/ResolverComparator.java
    ++++ b/core/java/com/android/internal/app/ResolverComparator.java
    +@@ -157,7 +157,10 @@ class ResolverComparator implements Comparator<ResolvedComponentInfo> {
    + 
    +         // We want to put the one targeted to another user at the end of the dialog.
    +         if (lhs.targetUserId != UserHandle.USER_CURRENT) {
    +-            return 1;
    ++            return rhs.targetUserId != UserHandle.USER_CURRENT ? 0 : 1;
    ++        }
    ++        if (rhs.targetUserId != UserHandle.USER_CURRENT) {
    ++            return -1;
    +         }
    + 
    +         if (mHttp) {
    +diff --git a/core/java/com/android/internal/app/SuggestedLocaleAdapter.java b/core/java/com/android/internal/app/SuggestedLocaleAdapter.java
    +index a4b5a8e..cb2b019 100644
    +--- a/core/java/com/android/internal/app/SuggestedLocaleAdapter.java
    ++++ b/core/java/com/android/internal/app/SuggestedLocaleAdapter.java
    +@@ -145,7 +145,11 @@ public class SuggestedLocaleAdapter extends BaseAdapter implements Filterable {
    +                 if (itemType == TYPE_HEADER_SUGGESTED) {
    +                     textView.setText(R.string.language_picker_section_suggested);
    +                 } else {
    +-                    textView.setText(R.string.language_picker_section_all);
    ++                    if (mCountryMode) {
    ++                        textView.setText(R.string.region_picker_section_all);
    ++                    } else {
    ++                        textView.setText(R.string.language_picker_section_all);
    ++                    }
    +                 }
    +                 textView.setTextLocale(Locale.getDefault());
    +                 break;
    +diff --git a/core/java/com/android/internal/graphics/drawable/AnimationScaleListDrawable.java b/core/java/com/android/internal/graphics/drawable/AnimationScaleListDrawable.java
    +new file mode 100644
    +index 0000000..62f18ea
    +--- /dev/null
    ++++ b/core/java/com/android/internal/graphics/drawable/AnimationScaleListDrawable.java
    +@@ -0,0 +1,254 @@
    ++/*
    ++ * Copyright (C) 2016 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 com.android.internal.graphics.drawable;
    ++
    ++import android.animation.ValueAnimator;
    ++import android.annotation.NonNull;
    ++import android.annotation.Nullable;
    ++import android.content.res.Resources;
    ++import android.content.res.Resources.Theme;
    ++import android.content.res.TypedArray;
    ++import android.graphics.drawable.Animatable;
    ++import android.graphics.drawable.Drawable;
    ++import android.graphics.drawable.DrawableContainer;
    ++import android.util.AttributeSet;
    ++
    ++import com.android.internal.R;
    ++
    ++import org.xmlpull.v1.XmlPullParser;
    ++import org.xmlpull.v1.XmlPullParserException;
    ++
    ++import java.io.IOException;
    ++
    ++/**
    ++ * An internal DrawableContainer class, used to draw different things depending on animation scale.
    ++ * i.e: animation scale can be 0 in battery saver mode.
    ++ * This class contains 2 drawable, one is animatable, the other is static. When animation scale is
    ++ * not 0, the animatable drawable will the drawn. Otherwise, the static drawable will be drawn.
    ++ * <p>This class implements Animatable since ProgressBar can pick this up similarly as an
    ++ * AnimatedVectorDrawable.
    ++ * <p>It can be defined in an XML file with the {@code <AnimationScaleListDrawable>}
    ++ * element.
    ++ */
    ++public class AnimationScaleListDrawable extends DrawableContainer implements Animatable {
    ++    private static final String TAG = "AnimationScaleListDrawable";
    ++    private AnimationScaleListState mAnimationScaleListState;
    ++    private boolean mMutated;
    ++
    ++    public AnimationScaleListDrawable() {
    ++        this(null, null);
    ++    }
    ++
    ++    private AnimationScaleListDrawable(@Nullable AnimationScaleListState state,
    ++            @Nullable Resources res) {
    ++        // Every scale list drawable has its own constant state.
    ++        final AnimationScaleListState newState = new AnimationScaleListState(state, this, res);
    ++        setConstantState(newState);
    ++        onStateChange(getState());
    ++    }
    ++
    ++    /**
    ++     * Set the current drawable according to the animation scale. If scale is 0, then pick the
    ++     * static drawable, otherwise, pick the animatable drawable.
    ++     */
    ++    @Override
    ++    protected boolean onStateChange(int[] stateSet) {
    ++        final boolean changed = super.onStateChange(stateSet);
    ++        int idx = mAnimationScaleListState.getCurrentDrawableIndexBasedOnScale();
    ++        return selectDrawable(idx) || changed;
    ++    }
    ++
    ++
    ++    @Override
    ++    public void inflate(@NonNull Resources r, @NonNull XmlPullParser parser,
    ++            @NonNull AttributeSet attrs, @Nullable Theme theme)
    ++            throws XmlPullParserException, IOException {
    ++        final TypedArray a = obtainAttributes(r, theme, attrs,
    ++                R.styleable.AnimationScaleListDrawable);
    ++        updateDensity(r);
    ++        a.recycle();
    ++
    ++        inflateChildElements(r, parser, attrs, theme);
    ++
    ++        onStateChange(getState());
    ++    }
    ++
    ++    /**
    ++     * Inflates child elements from XML.
    ++     */
    ++    private void inflateChildElements(@NonNull Resources r, @NonNull XmlPullParser parser,
    ++            @NonNull AttributeSet attrs, @Nullable Theme theme)
    ++            throws XmlPullParserException, IOException {
    ++        final AnimationScaleListState state = mAnimationScaleListState;
    ++        final int innerDepth = parser.getDepth() + 1;
    ++        int type;
    ++        int depth;
    ++        while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
    ++                && ((depth = parser.getDepth()) >= innerDepth
    ++                || type != XmlPullParser.END_TAG)) {
    ++            if (type != XmlPullParser.START_TAG) {
    ++                continue;
    ++            }
    ++
    ++            if (depth > innerDepth || !parser.getName().equals("item")) {
    ++                continue;
    ++            }
    ++
    ++            // Either pick up the android:drawable attribute.
    ++            final TypedArray a = obtainAttributes(r, theme, attrs,
    ++                    R.styleable.AnimationScaleListDrawableItem);
    ++            Drawable dr = a.getDrawable(R.styleable.AnimationScaleListDrawableItem_drawable);
    ++            a.recycle();
    ++
    ++            // Or parse the child element under <item>.
    ++            if (dr == null) {
    ++                while ((type = parser.next()) == XmlPullParser.TEXT) {
    ++                }
    ++                if (type != XmlPullParser.START_TAG) {
    ++                    throw new XmlPullParserException(
    ++                            parser.getPositionDescription()
    ++                                    + ": <item> tag requires a 'drawable' attribute or "
    ++                                    + "child tag defining a drawable");
    ++                }
    ++                dr = Drawable.createFromXmlInner(r, parser, attrs, theme);
    ++            }
    ++
    ++            state.addDrawable(dr);
    ++        }
    ++    }
    ++
    ++    @Override
    ++    public Drawable mutate() {
    ++        if (!mMutated && super.mutate() == this) {
    ++            mAnimationScaleListState.mutate();
    ++            mMutated = true;
    ++        }
    ++        return this;
    ++    }
    ++
    ++    @Override
    ++    public void clearMutated() {
    ++        super.clearMutated();
    ++        mMutated = false;
    ++    }
    ++
    ++    @Override
    ++    public void start() {
    ++        Drawable dr = getCurrent();
    ++        if (dr != null && dr instanceof Animatable) {
    ++            ((Animatable) dr).start();
    ++        }
    ++    }
    ++
    ++    @Override
    ++    public void stop() {
    ++        Drawable dr = getCurrent();
    ++        if (dr != null && dr instanceof Animatable) {
    ++            ((Animatable) dr).stop();
    ++        }
    ++    }
    ++
    ++    @Override
    ++    public boolean isRunning() {
    ++        boolean result = false;
    ++        Drawable dr = getCurrent();
    ++        if (dr != null && dr instanceof Animatable) {
    ++            result = ((Animatable) dr).isRunning();
    ++        }
    ++        return result;
    ++    }
    ++
    ++    static class AnimationScaleListState extends DrawableContainerState {
    ++        int[] mThemeAttrs = null;
    ++        // The index of the last static drawable.
    ++        int mStaticDrawableIndex = -1;
    ++        // The index of the last animatable drawable.
    ++        int mAnimatableDrawableIndex = -1;
    ++
    ++        AnimationScaleListState(AnimationScaleListState orig, AnimationScaleListDrawable owner,
    ++                Resources res) {
    ++            super(orig, owner, res);
    ++
    ++            if (orig != null) {
    ++                // Perform a shallow copy and rely on mutate() to deep-copy.
    ++                mThemeAttrs = orig.mThemeAttrs;
    ++
    ++                mStaticDrawableIndex = orig.mStaticDrawableIndex;
    ++                mAnimatableDrawableIndex = orig.mAnimatableDrawableIndex;
    ++            }
    ++
    ++        }
    ++
    ++        void mutate() {
    ++            mThemeAttrs = mThemeAttrs != null ? mThemeAttrs.clone() : null;
    ++        }
    ++
    ++        /**
    ++         * Add the drawable into the container.
    ++         * This class only keep track one animatable drawable, and one static. If there are multiple
    ++         * defined in the XML, then pick the last one.
    ++         */
    ++        int addDrawable(Drawable drawable) {
    ++            final int pos = addChild(drawable);
    ++            if (drawable instanceof Animatable) {
    ++                mAnimatableDrawableIndex = pos;
    ++            } else {
    ++                mStaticDrawableIndex = pos;
    ++            }
    ++            return pos;
    ++        }
    ++
    ++        @Override
    ++        public Drawable newDrawable() {
    ++            return new AnimationScaleListDrawable(this, null);
    ++        }
    ++
    ++        @Override
    ++        public Drawable newDrawable(Resources res) {
    ++            return new AnimationScaleListDrawable(this, res);
    ++        }
    ++
    ++        @Override
    ++        public boolean canApplyTheme() {
    ++            return mThemeAttrs != null || super.canApplyTheme();
    ++        }
    ++
    ++        public int getCurrentDrawableIndexBasedOnScale() {
    ++            if (ValueAnimator.getDurationScale() == 0) {
    ++                return mStaticDrawableIndex;
    ++            }
    ++            return mAnimatableDrawableIndex;
    ++        }
    ++    }
    ++
    ++    @Override
    ++    public void applyTheme(@NonNull Theme theme) {
    ++        super.applyTheme(theme);
    ++
    ++        onStateChange(getState());
    ++    }
    ++
    ++    @Override
    ++    protected void setConstantState(@NonNull DrawableContainerState state) {
    ++        super.setConstantState(state);
    ++
    ++        if (state instanceof AnimationScaleListState) {
    ++            mAnimationScaleListState = (AnimationScaleListState) state;
    ++        }
    ++    }
    ++}
    ++
    +diff --git a/core/java/com/android/internal/hardware/AmbientDisplayConfiguration.java b/core/java/com/android/internal/hardware/AmbientDisplayConfiguration.java
    +new file mode 100644
    +index 0000000..cf1bf62
    +--- /dev/null
    ++++ b/core/java/com/android/internal/hardware/AmbientDisplayConfiguration.java
    +@@ -0,0 +1,87 @@
    ++/*
    ++ * Copyright (C) 2016 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 com.android.internal.hardware;
    ++
    ++import com.android.internal.R;
    ++
    ++import android.content.Context;
    ++import android.provider.Settings;
    ++import android.text.TextUtils;
    ++
    ++public class AmbientDisplayConfiguration {
    ++
    ++    private final Context mContext;
    ++
    ++    public AmbientDisplayConfiguration(Context context) {
    ++        mContext = context;
    ++    }
    ++    
    ++    public boolean enabled(int user) {
    ++        return pulseOnNotificationEnabled(user)
    ++                || pulseOnPickupEnabled(user)
    ++                || pulseOnDoubleTapEnabled(user);
    ++    }
    ++    
    ++    public boolean available() {
    ++        return pulseOnNotificationAvailable() || pulseOnPickupAvailable()
    ++                || pulseOnDoubleTapAvailable();
    ++    }
    ++    
    ++    public boolean pulseOnNotificationEnabled(int user) {
    ++        return boolSetting(Settings.Secure.DOZE_ENABLED, user) && pulseOnNotificationAvailable();
    ++    }
    ++
    ++    public boolean pulseOnNotificationAvailable() {
    ++        return ambientDisplayAvailable();
    ++    }
    ++
    ++    public boolean pulseOnPickupEnabled(int user) {
    ++        return boolSetting(Settings.Secure.DOZE_PULSE_ON_PICK_UP, user)
    ++                && pulseOnPickupAvailable();
    ++    }
    ++    
    ++    public boolean pulseOnPickupAvailable() {
    ++        return mContext.getResources().getBoolean(R.bool.config_dozePulsePickup)
    ++                && ambientDisplayAvailable();
    ++    }
    ++    
    ++    public boolean pulseOnDoubleTapEnabled(int user) {
    ++        return boolSetting(Settings.Secure.DOZE_PULSE_ON_DOUBLE_TAP, user)
    ++                && pulseOnDoubleTapAvailable();
    ++    }
    ++
    ++    public boolean pulseOnDoubleTapAvailable() {
    ++        return !TextUtils.isEmpty(doubleTapSensorType()) && ambientDisplayAvailable();
    ++    }
    ++
    ++    public String doubleTapSensorType() {
    ++        return mContext.getResources().getString(R.string.config_dozeDoubleTapSensorType);
    ++    }
    ++
    ++    public String ambientDisplayComponent() {
    ++        return mContext.getResources().getString(R.string.config_dozeComponent);
    ++    }
    ++
    ++    private boolean ambientDisplayAvailable() {
    ++        return !TextUtils.isEmpty(ambientDisplayComponent());
    ++    }
    ++
    ++    private boolean boolSetting(String name, int user) {
    ++        return Settings.Secure.getIntForUser(mContext.getContentResolver(), name, 1, user) != 0;
    ++    }
    ++
    ++}
    +diff --git a/core/java/com/android/internal/os/BatteryStatsImpl.java b/core/java/com/android/internal/os/BatteryStatsImpl.java
    +index 2538d60..3b3344e 100644
    +--- a/core/java/com/android/internal/os/BatteryStatsImpl.java
    ++++ b/core/java/com/android/internal/os/BatteryStatsImpl.java
    +@@ -10727,7 +10727,7 @@ public class BatteryStatsImpl extends BatteryStats {
    +             }
    + 
    +             int NW = in.readInt();
    +-            if (NW > 100) {
    ++            if (NW > (MAX_WAKELOCKS_PER_UID+1)) {
    +                 throw new ParcelFormatException("File corrupt: too many wake locks " + NW);
    +             }
    +             for (int iw = 0; iw < NW; iw++) {
    +@@ -10736,7 +10736,7 @@ public class BatteryStatsImpl extends BatteryStats {
    +             }
    + 
    +             int NS = in.readInt();
    +-            if (NS > 100) {
    ++            if (NS > (MAX_WAKELOCKS_PER_UID+1)) {
    +                 throw new ParcelFormatException("File corrupt: too many syncs " + NS);
    +             }
    +             for (int is = 0; is < NS; is++) {
    +@@ -10745,7 +10745,7 @@ public class BatteryStatsImpl extends BatteryStats {
    +             }
    + 
    +             int NJ = in.readInt();
    +-            if (NJ > 100) {
    ++            if (NJ > (MAX_WAKELOCKS_PER_UID+1)) {
    +                 throw new ParcelFormatException("File corrupt: too many job timers " + NJ);
    +             }
    +             for (int ij = 0; ij < NJ; ij++) {
    +diff --git a/core/java/com/android/internal/os/ProcessCpuTracker.java b/core/java/com/android/internal/os/ProcessCpuTracker.java
    +index b7e5718..e46dfc4 100644
    +--- a/core/java/com/android/internal/os/ProcessCpuTracker.java
    ++++ b/core/java/com/android/internal/os/ProcessCpuTracker.java
    +@@ -39,6 +39,7 @@ import java.util.ArrayList;
    + import java.util.Collections;
    + import java.util.Comparator;
    + import java.util.Date;
    ++import java.util.List;
    + import java.util.StringTokenizer;
    + 
    + public class ProcessCpuTracker {
    +@@ -177,6 +178,11 @@ public class ProcessCpuTracker {
    + 
    +     private byte[] mBuffer = new byte[4096];
    + 
    ++    public interface FilterStats {
    ++        /** Which stats to pick when filtering */
    ++        boolean needed(Stats stats);
    ++    }
    ++
    +     public static class Stats {
    +         public final int pid;
    +         public final int uid;
    +@@ -695,6 +701,18 @@ public class ProcessCpuTracker {
    +         return mProcStats.get(index);
    +     }
    + 
    ++    final public List<Stats> getStats(FilterStats filter) {
    ++        final ArrayList<Stats> statses = new ArrayList<>(mProcStats.size());
    ++        final int N = mProcStats.size();
    ++        for (int p = 0; p < N; p++) {
    ++            Stats stats = mProcStats.get(p);
    ++            if (filter.needed(stats)) {
    ++                statses.add(stats);
    ++            }
    ++        }
    ++        return statses;
    ++    }
    ++
    +     final public int countWorkingStats() {
    +         buildWorkingProcs();
    +         return mWorkingProcs.size();
    +diff --git a/core/java/com/android/internal/policy/BackdropFrameRenderer.java b/core/java/com/android/internal/policy/BackdropFrameRenderer.java
    +index 619303f..1abb59b 100644
    +--- a/core/java/com/android/internal/policy/BackdropFrameRenderer.java
    ++++ b/core/java/com/android/internal/policy/BackdropFrameRenderer.java
    +@@ -110,12 +110,15 @@ public class BackdropFrameRenderer extends Thread implements Choreographer.Frame
    +             int statusBarColor, int navigationBarColor) {
    +         mDecorView = decorView;
    +         mResizingBackgroundDrawable = resizingBackgroundDrawable != null
    ++                        && resizingBackgroundDrawable.getConstantState() != null
    +                 ? resizingBackgroundDrawable.getConstantState().newDrawable()
    +                 : null;
    +         mCaptionBackgroundDrawable = captionBackgroundDrawableDrawable != null
    ++                        && captionBackgroundDrawableDrawable.getConstantState() != null
    +                 ? captionBackgroundDrawableDrawable.getConstantState().newDrawable()
    +                 : null;
    +         mUserCaptionBackgroundDrawable = userCaptionBackgroundDrawable != null
    ++                        && userCaptionBackgroundDrawable.getConstantState() != null
    +                 ? userCaptionBackgroundDrawable.getConstantState().newDrawable()
    +                 : null;
    +         if (mCaptionBackgroundDrawable == null) {
    +diff --git a/core/java/com/android/internal/policy/EmergencyAffordanceManager.java b/core/java/com/android/internal/policy/EmergencyAffordanceManager.java
    +new file mode 100644
    +index 0000000..eb75bd4
    +--- /dev/null
    ++++ b/core/java/com/android/internal/policy/EmergencyAffordanceManager.java
    +@@ -0,0 +1,102 @@
    ++/*
    ++ * Copyright (C) 2016 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 com.android.internal.policy;
    ++
    ++import android.content.Context;
    ++import android.content.Intent;
    ++import android.net.Uri;
    ++import android.os.Build;
    ++import android.os.UserHandle;
    ++import android.provider.Settings;
    ++
    ++/**
    ++ * A class that manages emergency affordances and enables immediate calling to emergency services
    ++ */
    ++public class EmergencyAffordanceManager {
    ++
    ++    public static final boolean ENABLED = true;
    ++
    ++    /**
    ++     * Global setting override with the number to call with the emergency affordance.
    ++     * @hide
    ++     */
    ++    private static final String EMERGENCY_CALL_NUMBER_SETTING = "emergency_affordance_number";
    ++
    ++    /**
    ++     * Global setting, whether the emergency affordance should be shown regardless of device state.
    ++     * The value is a boolean (1 or 0).
    ++     * @hide
    ++     */
    ++    private static final String FORCE_EMERGENCY_AFFORDANCE_SETTING = "force_emergency_affordance";
    ++
    ++    private final Context mContext;
    ++
    ++    public EmergencyAffordanceManager(Context context) {
    ++        mContext = context;
    ++    }
    ++
    ++    /**
    ++     * perform an emergency call.
    ++     */
    ++    public final void performEmergencyCall() {
    ++        performEmergencyCall(mContext);
    ++    }
    ++
    ++    private static Uri getPhoneUri(Context context) {
    ++        String number = context.getResources().getString(
    ++                com.android.internal.R.string.config_emergency_call_number);
    ++        if (Build.IS_DEBUGGABLE) {
    ++            String override = Settings.Global.getString(
    ++                    context.getContentResolver(), EMERGENCY_CALL_NUMBER_SETTING);
    ++            if (override != null) {
    ++                number = override;
    ++            }
    ++        }
    ++        return Uri.fromParts("tel", number, null);
    ++    }
    ++
    ++    private static void performEmergencyCall(Context context) {
    ++        Intent intent = new Intent(Intent.ACTION_CALL_EMERGENCY);
    ++        intent.setData(getPhoneUri(context));
    ++        intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
    ++        context.startActivityAsUser(intent, UserHandle.CURRENT);
    ++    }
    ++
    ++    /**
    ++     * @return whether emergency affordance should be active.
    ++     */
    ++    public boolean needsEmergencyAffordance() {
    ++        if (!ENABLED) {
    ++            return false;
    ++        }
    ++        if (forceShowing()) {
    ++            return true;
    ++        }
    ++        return isEmergencyAffordanceNeeded();
    ++    }
    ++
    ++    private boolean isEmergencyAffordanceNeeded() {
    ++        return Settings.Global.getInt(mContext.getContentResolver(),
    ++                Settings.Global.EMERGENCY_AFFORDANCE_NEEDED, 0) != 0;
    ++    }
    ++
    ++
    ++    private boolean forceShowing() {
    ++        return Settings.Global.getInt(mContext.getContentResolver(),
    ++                FORCE_EMERGENCY_AFFORDANCE_SETTING, 0) != 0;
    ++    }
    ++}
    +diff --git a/core/java/com/android/internal/policy/IKeyguardService.aidl b/core/java/com/android/internal/policy/IKeyguardService.aidl
    +index 83d75fb..e51ad3f 100644
    +--- a/core/java/com/android/internal/policy/IKeyguardService.aidl
    ++++ b/core/java/com/android/internal/policy/IKeyguardService.aidl
    +@@ -28,8 +28,9 @@ oneway interface IKeyguardService {
    +      * FLAG_SHOW_ON_LOCK_SCREEN.
    +      *
    +      * @param isOccluded Whether the Keyguard is occluded by another window.
    ++     * @param animate Whether to play an animation for the state change.
    +      */
    +-    void setOccluded(boolean isOccluded);
    ++    void setOccluded(boolean isOccluded, boolean animate);
    + 
    +     void addStateMonitorCallback(IKeyguardStateCallback callback);
    +     void verifyUnlock(IKeyguardExitCallback callback);
    +diff --git a/core/java/com/android/internal/policy/PhoneFallbackEventHandler.java b/core/java/com/android/internal/policy/PhoneFallbackEventHandler.java
    +index 2cb9c25..fb0edea 100644
    +--- a/core/java/com/android/internal/policy/PhoneFallbackEventHandler.java
    ++++ b/core/java/com/android/internal/policy/PhoneFallbackEventHandler.java
    +@@ -150,6 +150,7 @@ public class PhoneFallbackEventHandler implements FallbackEventHandler {
    +                         sendCloseSystemWindows();
    +                         // Broadcast an intent that the Camera button was longpressed
    +                         Intent intent = new Intent(Intent.ACTION_CAMERA_BUTTON, null);
    ++                        intent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
    +                         intent.putExtra(Intent.EXTRA_KEY_EVENT, event);
    +                         mContext.sendOrderedBroadcastAsUser(intent, UserHandle.CURRENT_OR_SELF,
    +                                 null, null, null, 0, null, null);
    +diff --git a/core/java/com/android/internal/util/WakeupMessage.java b/core/java/com/android/internal/util/WakeupMessage.java
    +index 7d222c7..46098c5 100644
    +--- a/core/java/com/android/internal/util/WakeupMessage.java
    ++++ b/core/java/com/android/internal/util/WakeupMessage.java
    +@@ -108,7 +108,7 @@ public class WakeupMessage implements AlarmManager.OnAlarmListener {
    +         }
    +         if (stillScheduled) {
    +             Message msg = mHandler.obtainMessage(mCmd, mArg1, mArg2, mObj);
    +-            mHandler.handleMessage(msg);
    ++            mHandler.dispatchMessage(msg);
    +             msg.recycle();
    +         }
    +     }
    +diff --git a/core/java/com/android/internal/view/IInputConnectionWrapper.java b/core/java/com/android/internal/view/IInputConnectionWrapper.java
    +index 644c7e9..4f7b106 100644
    +--- a/core/java/com/android/internal/view/IInputConnectionWrapper.java
    ++++ b/core/java/com/android/internal/view/IInputConnectionWrapper.java
    +@@ -580,7 +580,13 @@ public abstract class IInputConnectionWrapper extends IInputContext.Stub {
    +                         return;
    +                     }
    +                     if (grantUriPermission) {
    +-                        inputContentInfo.requestPermission();
    ++                        try {
    ++                            inputContentInfo.requestPermission();
    ++                        } catch (Exception e) {
    ++                            Log.e(TAG, "InputConnectionInfo.requestPermission() failed", e);
    ++                            args.callback.setCommitContentResult(false, args.seq);
    ++                            return;
    ++                        }
    +                     }
    +                     final boolean result =
    +                             ic.commitContent(inputContentInfo, flags, (Bundle) args.arg2);
    +diff --git a/core/java/com/android/internal/widget/AlertDialogLayout.java b/core/java/com/android/internal/widget/AlertDialogLayout.java
    +index 891c920..9bf0948 100644
    +--- a/core/java/com/android/internal/widget/AlertDialogLayout.java
    ++++ b/core/java/com/android/internal/widget/AlertDialogLayout.java
    +@@ -20,7 +20,9 @@ import android.annotation.AttrRes;
    + import android.annotation.Nullable;
    + import android.annotation.StyleRes;
    + import android.content.Context;
    ++import android.graphics.drawable.Drawable;
    + import android.util.AttributeSet;
    ++import android.view.Gravity;
    + import android.view.View;
    + import android.view.ViewGroup;
    + import android.widget.LinearLayout;
    +@@ -265,4 +267,92 @@ public class AlertDialogLayout extends LinearLayout {
    + 
    +         return 0;
    +     }
    ++
    ++    @Override
    ++    protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
    ++        final int paddingLeft = mPaddingLeft;
    ++
    ++        // Where right end of child should go
    ++        final int width = right - left;
    ++        final int childRight = width - mPaddingRight;
    ++
    ++        // Space available for child
    ++        final int childSpace = width - paddingLeft - mPaddingRight;
    ++
    ++        final int totalLength = getMeasuredHeight();
    ++        final int count = getChildCount();
    ++        final int gravity = getGravity();
    ++        final int majorGravity = gravity & Gravity.VERTICAL_GRAVITY_MASK;
    ++        final int minorGravity = gravity & Gravity.RELATIVE_HORIZONTAL_GRAVITY_MASK;
    ++
    ++        int childTop;
    ++        switch (majorGravity) {
    ++            case Gravity.BOTTOM:
    ++                // totalLength contains the padding already
    ++                childTop = mPaddingTop + bottom - top - totalLength;
    ++                break;
    ++
    ++            // totalLength contains the padding already
    ++            case Gravity.CENTER_VERTICAL:
    ++                childTop = mPaddingTop + (bottom - top - totalLength) / 2;
    ++                break;
    ++
    ++            case Gravity.TOP:
    ++            default:
    ++                childTop = mPaddingTop;
    ++                break;
    ++        }
    ++
    ++        final Drawable dividerDrawable = getDividerDrawable();
    ++        final int dividerHeight = dividerDrawable == null ?
    ++                0 : dividerDrawable.getIntrinsicHeight();
    ++
    ++        for (int i = 0; i < count; i++) {
    ++            final View child = getChildAt(i);
    ++            if (child != null && child.getVisibility() != GONE) {
    ++                final int childWidth = child.getMeasuredWidth();
    ++                final int childHeight = child.getMeasuredHeight();
    ++
    ++                final LinearLayout.LayoutParams lp =
    ++                        (LinearLayout.LayoutParams) child.getLayoutParams();
    ++
    ++                int layoutGravity = lp.gravity;
    ++                if (layoutGravity < 0) {
    ++                    layoutGravity = minorGravity;
    ++                }
    ++                final int layoutDirection = getLayoutDirection();
    ++                final int absoluteGravity = Gravity.getAbsoluteGravity(
    ++                        layoutGravity, layoutDirection);
    ++
    ++                final int childLeft;
    ++                switch (absoluteGravity & Gravity.HORIZONTAL_GRAVITY_MASK) {
    ++                    case Gravity.CENTER_HORIZONTAL:
    ++                        childLeft = paddingLeft + ((childSpace - childWidth) / 2)
    ++                                + lp.leftMargin - lp.rightMargin;
    ++                        break;
    ++
    ++                    case Gravity.RIGHT:
    ++                        childLeft = childRight - childWidth - lp.rightMargin;
    ++                        break;
    ++
    ++                    case Gravity.LEFT:
    ++                    default:
    ++                        childLeft = paddingLeft + lp.leftMargin;
    ++                        break;
    ++                }
    ++
    ++                if (hasDividerBeforeChildAt(i)) {
    ++                    childTop += dividerHeight;
    ++                }
    ++
    ++                childTop += lp.topMargin;
    ++                setChildFrame(child, childLeft, childTop, childWidth, childHeight);
    ++                childTop += childHeight + lp.bottomMargin;
    ++            }
    ++        }
    ++    }
    ++
    ++    private void setChildFrame(View child, int left, int top, int width, int height) {
    ++        child.layout(left, top, left + width, top + height);
    ++    }
    + }
    +diff --git a/core/java/com/android/internal/widget/ImageFloatingTextView.java b/core/java/com/android/internal/widget/ImageFloatingTextView.java
    +index 926ebd1..358be60 100644
    +--- a/core/java/com/android/internal/widget/ImageFloatingTextView.java
    ++++ b/core/java/com/android/internal/widget/ImageFloatingTextView.java
    +@@ -40,6 +40,9 @@ public class ImageFloatingTextView extends TextView {
    +     /** Number of lines from the top to indent */
    +     private int mIndentLines;
    + 
    ++    /** Resolved layout direction */
    ++    private int mResolvedDirection = LAYOUT_DIRECTION_UNDEFINED;
    ++
    +     public ImageFloatingTextView(Context context) {
    +         this(context, null);
    +     }
    +@@ -82,7 +85,7 @@ public class ImageFloatingTextView extends TextView {
    +                 margins[i] = endMargin;
    +             }
    +         }
    +-        if (getLayoutDirection() == LAYOUT_DIRECTION_RTL) {
    ++        if (mResolvedDirection == LAYOUT_DIRECTION_RTL) {
    +             builder.setIndents(margins, null);
    +         } else {
    +             builder.setIndents(null, margins);
    +@@ -91,6 +94,19 @@ public class ImageFloatingTextView extends TextView {
    +         return builder.build();
    +     }
    + 
    ++    @Override
    ++    public void onRtlPropertiesChanged(int layoutDirection) {
    ++        super.onRtlPropertiesChanged(layoutDirection);
    ++
    ++        if (layoutDirection != mResolvedDirection && isLayoutDirectionResolved()) {
    ++            mResolvedDirection = layoutDirection;
    ++            if (mIndentLines > 0) {
    ++                // Invalidate layout.
    ++                setHint(getHint());
    ++            }
    ++        }
    ++    }
    ++
    +     @RemotableViewMethod
    +     public void setHasImage(boolean hasImage) {
    +         setNumIndentLines(hasImage ? 2 : 0);
    +diff --git a/core/java/com/android/server/BootReceiver.java b/core/java/com/android/server/BootReceiver.java
    +index fbc51cd..5a50fbf 100644
    +--- a/core/java/com/android/server/BootReceiver.java
    ++++ b/core/java/com/android/server/BootReceiver.java
    +@@ -79,6 +79,9 @@ public class BootReceiver extends BroadcastReceiver {
    +     private static final String LOG_FILES_FILE = "log-files.xml";
    +     private static final AtomicFile sFile = new AtomicFile(new File(
    +             Environment.getDataSystemDirectory(), LOG_FILES_FILE));
    ++    private static final String LAST_HEADER_FILE = "last-header.txt";
    ++    private static final File lastHeaderFile = new File(
    ++            Environment.getDataSystemDirectory(), LAST_HEADER_FILE);
    + 
    +     @Override
    +     public void onReceive(final Context context, Intent intent) {
    +@@ -113,9 +116,17 @@ public class BootReceiver extends BroadcastReceiver {
    +         Downloads.removeAllDownloadsByPackage(context, OLD_UPDATER_PACKAGE, OLD_UPDATER_CLASS);
    +     }
    + 
    +-    private void logBootEvents(Context ctx) throws IOException {
    +-        final DropBoxManager db = (DropBoxManager) ctx.getSystemService(Context.DROPBOX_SERVICE);
    +-        final String headers = new StringBuilder(512)
    ++    private String getPreviousBootHeaders() {
    ++        try {
    ++            return FileUtils.readTextFile(lastHeaderFile, 0, null);
    ++        } catch (IOException e) {
    ++            Slog.e(TAG, "Error reading " + lastHeaderFile, e);
    ++            return null;
    ++        }
    ++    }
    ++
    ++    private String getCurrentBootHeaders() throws IOException {
    ++        return new StringBuilder(512)
    +             .append("Build: ").append(Build.FINGERPRINT).append("\n")
    +             .append("Hardware: ").append(Build.BOARD).append("\n")
    +             .append("Revision: ")
    +@@ -125,6 +136,31 @@ public class BootReceiver extends BroadcastReceiver {
    +             .append("Kernel: ")
    +             .append(FileUtils.readTextFile(new File("/proc/version"), 1024, "...\n"))
    +             .append("\n").toString();
    ++    }
    ++
    ++
    ++    private String getBootHeadersToLogAndUpdate() throws IOException {
    ++        final String oldHeaders = getPreviousBootHeaders();
    ++        final String newHeaders = getCurrentBootHeaders();
    ++
    ++        try {
    ++            FileUtils.stringToFile(lastHeaderFile, newHeaders);
    ++        } catch (IOException e) {
    ++            Slog.e(TAG, "Error writing " + lastHeaderFile, e);
    ++        }
    ++
    ++        if (oldHeaders == null) {
    ++            // If we failed to read the old headers, use the current headers
    ++            // but note this in the headers so we know
    ++            return "isPrevious: false\n" + newHeaders;
    ++        }
    ++
    ++        return "isPrevious: true\n" + oldHeaders;
    ++    }
    ++
    ++    private void logBootEvents(Context ctx) throws IOException {
    ++        final DropBoxManager db = (DropBoxManager) ctx.getSystemService(Context.DROPBOX_SERVICE);
    ++        final String headers = getBootHeadersToLogAndUpdate();
    +         final String bootReason = SystemProperties.get("ro.boot.bootreason", null);
    + 
    +         String recovery = RecoverySystem.handleAftermath(ctx);
    +diff --git a/core/java/com/android/server/backup/AccountManagerBackupHelper.java b/core/java/com/android/server/backup/AccountManagerBackupHelper.java
    +new file mode 100644
    +index 0000000..39b18c0
    +--- /dev/null
    ++++ b/core/java/com/android/server/backup/AccountManagerBackupHelper.java
    +@@ -0,0 +1,85 @@
    ++/*
    ++ * Copyright (C) 2016 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 com.android.server.backup;
    ++
    ++import android.accounts.AccountManagerInternal;
    ++import android.app.backup.BlobBackupHelper;
    ++import android.os.UserHandle;
    ++import android.util.Slog;
    ++import com.android.server.LocalServices;
    ++
    ++/**
    ++ * Helper for handling backup of account manager specific state.
    ++ */
    ++public class AccountManagerBackupHelper extends BlobBackupHelper {
    ++    private static final String TAG = "AccountsBackup";
    ++    private static final boolean DEBUG = false;
    ++
    ++    // current schema of the backup state blob
    ++    private static final int STATE_VERSION = 1;
    ++
    ++    // key under which the account access grant state blob is committed to backup
    ++    private static final String KEY_ACCOUNT_ACCESS_GRANTS = "account_access_grants";
    ++
    ++    public AccountManagerBackupHelper() {
    ++        super(STATE_VERSION, KEY_ACCOUNT_ACCESS_GRANTS);
    ++    }
    ++
    ++    @Override
    ++    protected byte[] getBackupPayload(String key) {
    ++        AccountManagerInternal am = LocalServices.getService(AccountManagerInternal.class);
    ++        if (DEBUG) {
    ++            Slog.d(TAG, "Handling backup of " + key);
    ++        }
    ++        try {
    ++            switch (key) {
    ++                case KEY_ACCOUNT_ACCESS_GRANTS: {
    ++                    return am.backupAccountAccessPermissions(UserHandle.USER_SYSTEM);
    ++                }
    ++
    ++                default: {
    ++                    Slog.w(TAG, "Unexpected backup key " + key);
    ++                }
    ++            }
    ++        } catch (Exception e) {
    ++            Slog.e(TAG, "Unable to store payload " + key);
    ++        }
    ++
    ++        return new byte[0];
    ++    }
    ++
    ++    @Override
    ++    protected void applyRestoredPayload(String key, byte[] payload) {
    ++        AccountManagerInternal am = LocalServices.getService(AccountManagerInternal.class);
    ++        if (DEBUG) {
    ++            Slog.d(TAG, "Handling restore of " + key);
    ++        }
    ++        try {
    ++            switch (key) {
    ++                case KEY_ACCOUNT_ACCESS_GRANTS: {
    ++                    am.restoreAccountAccessPermissions(payload, UserHandle.USER_SYSTEM);
    ++                } break;
    ++
    ++                default: {
    ++                    Slog.w(TAG, "Unexpected restore key " + key);
    ++                }
    ++            }
    ++        } catch (Exception e) {
    ++            Slog.w(TAG, "Unable to restore key " + key);
    ++        }
    ++    }
    ++}
    +diff --git a/core/java/com/android/server/backup/SystemBackupAgent.java b/core/java/com/android/server/backup/SystemBackupAgent.java
    +index 9d296fa..5375651 100644
    +--- a/core/java/com/android/server/backup/SystemBackupAgent.java
    ++++ b/core/java/com/android/server/backup/SystemBackupAgent.java
    +@@ -49,6 +49,7 @@ public class SystemBackupAgent extends BackupAgentHelper {
    +     private static final String PERMISSION_HELPER = "permissions";
    +     private static final String USAGE_STATS_HELPER = "usage_stats";
    +     private static final String SHORTCUT_MANAGER_HELPER = "shortcut_manager";
    ++    private static final String ACCOUNT_MANAGER_HELPER = "account_manager";
    + 
    +     // These paths must match what the WallpaperManagerService uses.  The leaf *_FILENAME
    +     // are also used in the full-backup file format, so must not change unless steps are
    +@@ -82,6 +83,7 @@ public class SystemBackupAgent extends BackupAgentHelper {
    +         addHelper(PERMISSION_HELPER, new PermissionBackupHelper());
    +         addHelper(USAGE_STATS_HELPER, new UsageStatsBackupHelper(this));
    +         addHelper(SHORTCUT_MANAGER_HELPER, new ShortcutBackupHelper());
    ++        addHelper(ACCOUNT_MANAGER_HELPER, new AccountManagerBackupHelper());
    +         super.onBackup(oldState, data, newState);
    +     }
    + 
    +@@ -111,6 +113,7 @@ public class SystemBackupAgent extends BackupAgentHelper {
    +         addHelper(PERMISSION_HELPER, new PermissionBackupHelper());
    +         addHelper(USAGE_STATS_HELPER, new UsageStatsBackupHelper(this));
    +         addHelper(SHORTCUT_MANAGER_HELPER, new ShortcutBackupHelper());
    ++        addHelper(ACCOUNT_MANAGER_HELPER, new AccountManagerBackupHelper());
    + 
    +         try {
    +             super.onRestore(data, appVersionCode, newState);
    +diff --git a/core/jni/android/graphics/pdf/PdfEditor.cpp b/core/jni/android/graphics/pdf/PdfEditor.cpp
    +index d2d39cd..0468b64 100644
    +--- a/core/jni/android/graphics/pdf/PdfEditor.cpp
    ++++ b/core/jni/android/graphics/pdf/PdfEditor.cpp
    +@@ -52,11 +52,9 @@ static struct {
    + } gRectClassInfo;
    + 
    + // Also used in PdfRenderer.cpp
    +-Mutex sPdfiumLock;
    + int sUnmatchedPdfiumInitRequestCount = 0;
    + 
    + static void initializeLibraryIfNeeded() {
    +-    Mutex::Autolock _l(sPdfiumLock);
    +     if (sUnmatchedPdfiumInitRequestCount == 0) {
    +         FPDF_InitLibrary();
    +     }
    +@@ -64,7 +62,6 @@ static void initializeLibraryIfNeeded() {
    + }
    + 
    + static void destroyLibraryIfNeeded() {
    +-    Mutex::Autolock _l(sPdfiumLock);
    +     sUnmatchedPdfiumInitRequestCount--;
    +     if (sUnmatchedPdfiumInitRequestCount == 0) {
    +        FPDF_DestroyLibrary();
    +diff --git a/core/jni/android/graphics/pdf/PdfRenderer.cpp b/core/jni/android/graphics/pdf/PdfRenderer.cpp
    +index 71bec78..43550ac 100644
    +--- a/core/jni/android/graphics/pdf/PdfRenderer.cpp
    ++++ b/core/jni/android/graphics/pdf/PdfRenderer.cpp
    +@@ -44,11 +44,9 @@ static struct {
    + } gPointClassInfo;
    + 
    + // See PdfEditor.cpp
    +-extern Mutex sPdfiumLock;
    + extern int sUnmatchedPdfiumInitRequestCount;
    + 
    + static void initializeLibraryIfNeeded() {
    +-    Mutex::Autolock _l(sPdfiumLock);
    +     if (sUnmatchedPdfiumInitRequestCount == 0) {
    +         FPDF_InitLibrary();
    +     }
    +@@ -56,7 +54,6 @@ static void initializeLibraryIfNeeded() {
    + }
    + 
    + static void destroyLibraryIfNeeded() {
    +-    Mutex::Autolock _l(sPdfiumLock);
    +     sUnmatchedPdfiumInitRequestCount--;
    +     if (sUnmatchedPdfiumInitRequestCount == 0) {
    +        FPDF_DestroyLibrary();
    +diff --git a/core/jni/android_database_CursorWindow.cpp b/core/jni/android_database_CursorWindow.cpp
    +index bb09d00..e96613b 100644
    +--- a/core/jni/android_database_CursorWindow.cpp
    ++++ b/core/jni/android_database_CursorWindow.cpp
    +@@ -16,6 +16,7 @@
    + 
    + #undef LOG_TAG
    + #define LOG_TAG "CursorWindow"
    ++#define LOG_NDEBUG 0
    + 
    + #include <inttypes.h>
    + #include <jni.h>
    +@@ -30,6 +31,11 @@
    + #include <stdio.h>
    + #include <string.h>
    + #include <unistd.h>
    ++#include <sys/types.h>
    ++#include <dirent.h>
    ++
    ++#undef LOG_NDEBUG
    ++#define LOG_NDEBUG 1
    + 
    + #include <androidfw/CursorWindow.h>
    + #include "android_os_Parcel.h"
    +@@ -61,6 +67,22 @@ static void throwUnknownTypeException(JNIEnv * env, jint type) {
    +     jniThrowException(env, "java/lang/IllegalStateException", msg.string());
    + }
    + 
    ++static int getFdCount() {
    ++    char fdpath[PATH_MAX];
    ++    int count = 0;
    ++    snprintf(fdpath, PATH_MAX, "/proc/%d/fd", getpid());
    ++    DIR *dir = opendir(fdpath);
    ++    if (dir != NULL) {
    ++        struct dirent *dirent;
    ++        while ((dirent = readdir(dir))) {
    ++            count++;
    ++        }
    ++        count -= 2; // discount "." and ".."
    ++        closedir(dir);
    ++    }
    ++    return count;
    ++}
    ++
    + static jlong nativeCreate(JNIEnv* env, jclass clazz, jstring nameObj, jint cursorWindowSize) {
    +     String8 name;
    +     const char* nameStr = env->GetStringUTFChars(nameObj, NULL);
    +@@ -85,7 +107,8 @@ static jlong nativeCreateFromParcel(JNIEnv* env, jclass clazz, jobject parcelObj
    +     CursorWindow* window;
    +     status_t status = CursorWindow::createFromParcel(parcel, &window);
    +     if (status || !window) {
    +-        ALOGE("Could not create CursorWindow from Parcel due to error %d.", status);
    ++        ALOGE("Could not create CursorWindow from Parcel due to error %d, process fd count=%d",
    ++                status, getFdCount());
    +         return 0;
    +     }
    + 
    +diff --git a/core/jni/android_hardware_Camera.cpp b/core/jni/android_hardware_Camera.cpp
    +index 9459257..b926270 100644
    +--- a/core/jni/android_hardware_Camera.cpp
    ++++ b/core/jni/android_hardware_Camera.cpp
    +@@ -350,9 +350,16 @@ void JNICameraContext::postDataTimestamp(nsecs_t timestamp, int32_t msgType, con
    +     postData(msgType, dataPtr, NULL);
    + }
    + 
    +-void JNICameraContext::postRecordingFrameHandleTimestamp(nsecs_t, native_handle_t*) {
    +-    // This is not needed at app layer. This should not be called because JNICameraContext cannot
    +-    // start video recording.
    ++void JNICameraContext::postRecordingFrameHandleTimestamp(nsecs_t, native_handle_t* handle) {
    ++    // Video buffers are not needed at app layer so just return the video buffers here.
    ++    // This may be called when stagefright just releases camera but there are still outstanding
    ++    // video buffers.
    ++    if (mCamera != nullptr) {
    ++        mCamera->releaseRecordingFrameHandle(handle);
    ++    } else {
    ++        native_handle_close(handle);
    ++        native_handle_delete(handle);
    ++    }
    + }
    + 
    + void JNICameraContext::postMetadata(JNIEnv *env, int32_t msgType, camera_frame_metadata_t *metadata)
    +diff --git a/core/jni/android_hardware_location_ContextHubService.cpp b/core/jni/android_hardware_location_ContextHubService.cpp
    +index 9515a0e..8eb39e1 100644
    +--- a/core/jni/android_hardware_location_ContextHubService.cpp
    ++++ b/core/jni/android_hardware_location_ContextHubService.cpp
    +@@ -26,6 +26,10 @@
    + #include <stdint.h>
    + #include <stdio.h>
    + #include <stdlib.h>
    ++
    ++// TOOD: On master, alphabetize these and move <mutex> into this
    ++//     grouping.
    ++#include <chrono>
    + #include <unordered_map>
    + #include <queue>
    + 
    +@@ -34,11 +38,12 @@
    + #include "JNIHelp.h"
    + #include "core_jni_helpers.h"
    + 
    +-static constexpr int OS_APP_ID = -1;
    ++static constexpr jint OS_APP_ID = -1;
    ++static constexpr jint INVALID_APP_ID = -2;
    + static constexpr uint64_t ALL_APPS = UINT64_C(0xFFFFFFFFFFFFFFFF);
    + 
    +-static constexpr int MIN_APP_ID = 1;
    +-static constexpr int MAX_APP_ID = 128;
    ++static constexpr jint MIN_APP_ID = 1;
    ++static constexpr jint MAX_APP_ID = 128;
    + 
    + static constexpr size_t MSG_HEADER_SIZE = 4;
    + static constexpr size_t HEADER_FIELD_MSG_TYPE = 0;
    +@@ -50,6 +55,10 @@ static constexpr size_t HEADER_FIELD_LOAD_APP_ID_LO = MSG_HEADER_SIZE;
    + static constexpr size_t HEADER_FIELD_LOAD_APP_ID_HI = MSG_HEADER_SIZE + 1;
    + static constexpr size_t MSG_HEADER_SIZE_LOAD_APP = MSG_HEADER_SIZE + 2;
    + 
    ++// Monotonically increasing clock we use to determine if we can cancel
    ++// a transaction.
    ++using std::chrono::steady_clock;
    ++
    + namespace android {
    + 
    + namespace {
    +@@ -102,10 +111,21 @@ struct context_hub_info_s {
    + struct app_instance_info_s {
    +     uint64_t truncName;          // Possibly truncated name for logging
    +     uint32_t hubHandle;          // Id of the hub this app is on
    +-    int instanceId;              // system wide unique instance id - assigned
    ++    jint instanceId;             // system wide unique instance id - assigned
    +     struct hub_app_info appInfo; // returned from the HAL
    + };
    + 
    ++
    ++// If a transaction takes longer than this, we'll allow it to be
    ++// canceled by a new transaction.  Note we do _not_ automatically
    ++// cancel a transaction after this much time.  We can have a
    ++// legal transaction which takes longer than this amount of time,
    ++// as long as no other new transactions are attempted after this
    ++// time has expired.
    ++// TODO(b/31105001): Establish a clean timing approach for all
    ++// of our HAL interactions.
    ++constexpr auto kMinTransactionCancelTime = std::chrono::seconds(29);
    ++
    + /*
    +  * TODO(ashutoshj): From original code review:
    +  *
    +@@ -147,14 +167,15 @@ struct txnManager_s {
    +     std::mutex m;                 // mutex for manager
    +     hub_messages_e txnIdentifier; // What are we doing
    +     void *txnData;                // Details
    ++    steady_clock::time_point firstTimeTxnCanBeCanceled;
    + };
    + 
    + struct contextHubServiceDb_s {
    +     int initialized;
    +     context_hub_info_s hubInfo;
    +     jniInfo_s jniInfo;
    +-    std::queue<int> freeIds;
    +-    std::unordered_map<int, app_instance_info_s> appInstances;
    ++    std::queue<jint> freeIds;
    ++    std::unordered_map<jint, app_instance_info_s> appInstances;
    +     txnManager_s txnManager;
    + };
    + 
    +@@ -176,25 +197,40 @@ static int addTxn(hub_messages_e txnIdentifier, void *txnData) {
    +     std::lock_guard<std::mutex>lock(mgr->m);
    + 
    +     mgr->txnPending = true;
    ++    mgr->firstTimeTxnCanBeCanceled = steady_clock::now() +
    ++        kMinTransactionCancelTime;
    +     mgr->txnData = txnData;
    +     mgr->txnIdentifier = txnIdentifier;
    + 
    +     return 0;
    + }
    + 
    +-static int closeTxn() {
    ++// Only call this if you hold the db.txnManager.m lock.
    ++static void closeTxnUnlocked() {
    +     txnManager_s *mgr = &db.txnManager;
    +-    std::lock_guard<std::mutex>lock(mgr->m);
    +     mgr->txnPending = false;
    +     free(mgr->txnData);
    +     mgr->txnData = nullptr;
    ++}
    + 
    ++static int closeTxn() {
    ++    std::lock_guard<std::mutex>lock(db.txnManager.m);
    ++    closeTxnUnlocked();
    +     return 0;
    + }
    + 
    ++// If a transaction has been pending for longer than
    ++// kMinTransactionCancelTime, this call will "cancel" that
    ++// transaction and return that there are none pending.
    + static bool isTxnPending() {
    +     txnManager_s *mgr = &db.txnManager;
    +     std::lock_guard<std::mutex>lock(mgr->m);
    ++    if (mgr->txnPending) {
    ++        if (steady_clock::now() >= mgr->firstTimeTxnCanBeCanceled) {
    ++            ALOGW("Transaction canceled");
    ++            closeTxnUnlocked();
    ++        }
    ++    }
    +     return mgr->txnPending;
    + }
    + 
    +@@ -259,16 +295,17 @@ static int get_hub_id_for_hub_handle(int hubHandle) {
    +     }
    + }
    + 
    +-static int get_hub_handle_for_app_instance(int id) {
    ++static int get_hub_handle_for_app_instance(jint id) {
    +     if (!db.appInstances.count(id)) {
    +-        ALOGD("%s: Cannot find app for app instance %d", __FUNCTION__, id);
    ++        ALOGD("%s: Cannot find app for app instance %" PRId32,
    ++              __FUNCTION__, id);
    +         return -1;
    +     }
    + 
    +     return db.appInstances[id].hubHandle;
    + }
    + 
    +-static int get_hub_id_for_app_instance(int id) {
    ++static int get_hub_id_for_app_instance(jint id) {
    +     int hubHandle = get_hub_handle_for_app_instance(id);
    + 
    +     if (hubHandle < 0) {
    +@@ -278,7 +315,7 @@ static int get_hub_id_for_app_instance(int id) {
    +     return db.hubInfo.hubs[hubHandle].hub_id;
    + }
    + 
    +-static int get_app_instance_for_app_id(uint64_t app_id) {
    ++static jint get_app_instance_for_app_id(uint64_t app_id) {
    +     auto end = db.appInstances.end();
    +     for (auto current = db.appInstances.begin(); current != end; ++current) {
    +         if (current->second.appInfo.app_name.id == app_id) {
    +@@ -289,9 +326,10 @@ static int get_app_instance_for_app_id(uint64_t app_id) {
    +     return -1;
    + }
    + 
    +-static int set_dest_app(hub_message_t *msg, int id) {
    ++static int set_dest_app(hub_message_t *msg, jint id) {
    +     if (!db.appInstances.count(id)) {
    +-        ALOGD("%s: Cannot find app for app instance %d", __FUNCTION__, id);
    ++        ALOGD("%s: Cannot find app for app instance %" PRId32,
    ++              __FUNCTION__, id);
    +         return -1;
    +     }
    + 
    +@@ -299,11 +337,15 @@ static int set_dest_app(hub_message_t *msg, int id) {
    +     return 0;
    + }
    + 
    +-static void query_hub_for_apps(uint64_t appId, uint32_t hubHandle) {
    ++static void query_hub_for_apps(uint32_t hubHandle) {
    +     hub_message_t msg;
    +     query_apps_request_t queryMsg;
    + 
    +-    queryMsg.app_name.id = NANOAPP_VENDOR_ALL_APPS;
    ++    // TODO(b/30835598): When we're able to tell which request our
    ++    //     response matches, then we should allow this to be more
    ++    //     targetted, instead of always being every app in the
    ++    //     system.
    ++    queryMsg.app_name.id = ALL_APPS;
    + 
    +     msg.message_type = CONTEXT_HUB_QUERY_APPS;
    +     msg.message_len  = sizeof(queryMsg);
    +@@ -316,13 +358,13 @@ static void query_hub_for_apps(uint64_t appId, uint32_t hubHandle) {
    +     }
    + }
    + 
    +-static void sendQueryForApps(uint64_t appId) {
    ++static void sendQueryForApps() {
    +     for (int i = 0; i < db.hubInfo.numHubs; i++ ) {
    +-        query_hub_for_apps(appId, i);
    ++        query_hub_for_apps(i);
    +     }
    + }
    + 
    +-static int return_id(int id) {
    ++static int return_id(jint id) {
    +     // Note : This method is not thread safe.
    +     // id returned is guaranteed to be in use
    +     if (id >= 0) {
    +@@ -333,9 +375,9 @@ static int return_id(int id) {
    +     return -1;
    + }
    + 
    +-static int generate_id() {
    ++static jint generate_id() {
    +     // Note : This method is not thread safe.
    +-    int retVal = -1;
    ++    jint retVal = -1;
    + 
    +     if (!db.freeIds.empty()) {
    +         retVal = db.freeIds.front();
    +@@ -346,23 +388,14 @@ static int generate_id() {
    + }
    + 
    + 
    +-static int add_app_instance(const hub_app_info *appInfo, uint32_t hubHandle,
    +-        int appInstanceHandle, JNIEnv *env) {
    +-
    +-    ALOGI("Loading App");
    +-
    ++static jint add_app_instance(const hub_app_info *appInfo, uint32_t hubHandle,
    ++        jint appInstanceHandle, JNIEnv *env) {
    +     // Not checking if the apps are indeed distinct
    +     app_instance_info_s entry;
    +     assert(appInfo);
    + 
    +-    if (db.appInstances.count(appInstanceHandle) == 0) {
    +-        appInstanceHandle = generate_id();
    +-        if (appInstanceHandle < 0) {
    +-            ALOGE("Cannot find resources to add app instance %d",
    +-                  appInstanceHandle);
    +-            return -1;
    +-        }
    +-    }
    ++    const char *action =
    ++        (db.appInstances.count(appInstanceHandle) == 0) ? "Added" : "Updated";
    + 
    +     entry.appInfo = *appInfo;
    + 
    +@@ -372,42 +405,49 @@ static int add_app_instance(const hub_app_info *appInfo, uint32_t hubHandle,
    + 
    +     db.appInstances[appInstanceHandle] = entry;
    + 
    +-    // Finally - let the service know of this app instance
    ++    // Finally - let the service know of this app instance, to populate
    ++    // the Java cache.
    +     env->CallIntMethod(db.jniInfo.jContextHubService,
    +                        db.jniInfo.contextHubServiceAddAppInstance,
    +                        hubHandle, entry.instanceId, entry.truncName,
    +                        entry.appInfo.version);
    + 
    +-    ALOGW("Added App 0x%" PRIx64 " on hub Handle %" PRId32
    +-          " as appInstance %d", entry.truncName,
    ++    ALOGI("%s App 0x%" PRIx64 " on hub Handle %" PRId32
    ++          " as appInstance %" PRId32, action, entry.truncName,
    +           entry.hubHandle, appInstanceHandle);
    + 
    +     return appInstanceHandle;
    + }
    + 
    +-int delete_app_instance(int id, JNIEnv *env) {
    +-    if (!db.appInstances.count(id)) {
    +-        ALOGW("Cannot find App id : %d", id);
    +-        return -1;
    +-    }
    ++int delete_app_instance(jint id, JNIEnv *env) {
    ++    bool fullyDeleted = true;
    + 
    ++    if (db.appInstances.count(id)) {
    ++        db.appInstances.erase(id);
    ++    } else {
    ++        ALOGW("Cannot delete App id (%" PRId32 ") from the JNI C++ cache", id);
    ++        fullyDeleted = false;
    ++    }
    +     return_id(id);
    +-    db.appInstances.erase(id);
    +-    if (env->CallIntMethod(db.jniInfo.jContextHubService,
    ++
    ++    if ((env == nullptr) ||
    ++        (env->CallIntMethod(db.jniInfo.jContextHubService,
    +                        db.jniInfo.contextHubServiceDeleteAppInstance,
    +-                       id) != 0) {
    +-        ALOGW("Could not delete App id : %d", id);
    +-        return -1;
    ++                       id) != 0)) {
    ++        ALOGW("Cannot delete App id (%" PRId32 ") from Java cache", id);
    ++        fullyDeleted = false;
    +     }
    + 
    +-    ALOGI("Deleted App id : %d", id);
    +-
    +-    return 0;
    ++    if (fullyDeleted) {
    ++        ALOGI("Deleted App id : %" PRId32, id);
    ++        return 0;
    ++    }
    ++    return -1;
    + }
    + 
    + static int startLoadAppTxn(uint64_t appId, int hubHandle) {
    +     app_instance_info_s *txnInfo = (app_instance_info_s *)malloc(sizeof(app_instance_info_s));
    +-    int instanceId = generate_id();
    ++    jint instanceId = generate_id();
    + 
    +     if (!txnInfo || instanceId < 0) {
    +         return_id(instanceId);
    +@@ -432,8 +472,8 @@ static int startLoadAppTxn(uint64_t appId, int hubHandle) {
    +     return 0;
    + }
    + 
    +-static int startUnloadAppTxn(uint32_t appInstanceHandle) {
    +-    uint32_t *txnData = (uint32_t *) malloc(sizeof(uint32_t));
    ++static int startUnloadAppTxn(jint appInstanceHandle) {
    ++    jint *txnData = (jint *) malloc(sizeof(jint));
    +     if (!txnData) {
    +         ALOGW("Cannot allocate memory to start unload transaction");
    +         return -1;
    +@@ -454,7 +494,6 @@ static void initContextHubService() {
    +     int err = 0;
    +     db.hubInfo.hubs = nullptr;
    +     db.hubInfo.numHubs = 0;
    +-    int i;
    + 
    +     err = hw_get_module(CONTEXT_HUB_MODULE_ID,
    +                         (hw_module_t const**)(&db.hubInfo.contextHubModule));
    +@@ -465,7 +504,7 @@ static void initContextHubService() {
    +     }
    + 
    +     // Prep for storing app info
    +-    for(i = MIN_APP_ID; i <= MAX_APP_ID; i++) {
    ++    for (jint i = MIN_APP_ID; i <= MAX_APP_ID; i++) {
    +         db.freeIds.push(i);
    +     }
    + 
    +@@ -485,7 +524,7 @@ static void initContextHubService() {
    +                 return;
    +             }
    + 
    +-            for (i = 0; i < db.hubInfo.numHubs; i++) {
    ++            for (int i = 0; i < db.hubInfo.numHubs; i++) {
    +                 db.hubInfo.cookies[i] = db.hubInfo.hubs[i].hub_id;
    +                 ALOGI("Subscribing to hubHandle %d with OS App name %" PRIu64, i, db.hubInfo.hubs[i].os_app_name.id);
    +                 if (db.hubInfo.contextHubModule->subscribe_messages(db.hubInfo.hubs[i].hub_id,
    +@@ -495,7 +534,7 @@ static void initContextHubService() {
    +             }
    +         }
    + 
    +-        sendQueryForApps(ALL_APPS);
    ++        sendQueryForApps();
    +     } else {
    +         ALOGW("No Context Hub Module present");
    +     }
    +@@ -539,21 +578,70 @@ int handle_query_apps_response(const uint8_t *msg, int msgLen,
    +             return -1;
    +     }
    + 
    +-    int numApps = msgLen/sizeof(hub_app_info);
    +-    hub_app_info info;
    ++    int numApps = msgLen / sizeof(hub_app_info);
    +     const hub_app_info *unalignedInfoAddr = (const hub_app_info*)msg;
    + 
    +-    for (int i = 0; i < numApps; i++, unalignedInfoAddr++) {
    +-        memcpy(&info, unalignedInfoAddr, sizeof(info));
    ++    // We use this information to sync our JNI and Java caches of nanoapp info.
    ++    // We want to accomplish two things here:
    ++    // 1) Remove entries from our caches which are stale, and pertained to
    ++    //    apps no longer running on Context Hub.
    ++    // 2) Populate our caches with the latest information of all these apps.
    ++
    ++    // We make a couple of assumptions here:
    ++    // A) The JNI and Java caches are in sync with each other (this isn't
    ++    //    necessarily true; any failure of a single call into Java land to
    ++    //    update its cache will leave that cache in a bad state.  For NYC,
    ++    //    we're willing to tolerate this for now).
    ++    // B) The total number of apps is relatively small, so horribly inefficent
    ++    //    algorithms aren't too painful.
    ++    // C) We're going to call this relatively infrequently, so its inefficency
    ++    //    isn't a big impact.
    ++
    ++
    ++    // (1).  Looking for stale cache entries.  Yes, this is O(N^2).  See
    ++    // assumption (B).  Per assumption (A), it is sufficient to iterate
    ++    // over just the JNI cache.
    ++    auto end = db.appInstances.end();
    ++    for (auto current = db.appInstances.begin(); current != end; ) {
    ++        app_instance_info_s cache_entry = current->second;
    ++        // We perform our iteration here because if we call
    ++        // delete_app_instance() below, it will erase() this entry.
    ++        current++;
    ++        bool entryIsStale = true;
    ++        for (int i = 0; i < numApps; i++) {
    ++            // We use memcmp since this could be unaligned.
    ++            if (memcmp(&unalignedInfoAddr[i].app_name.id,
    ++                       &cache_entry.appInfo.app_name.id,
    ++                       sizeof(cache_entry.appInfo.app_name.id)) == 0) {
    ++                // We found a match; this entry is current.
    ++                entryIsStale = false;
    ++                break;
    ++            }
    ++        }
    ++        if (entryIsStale) {
    ++            delete_app_instance(cache_entry.instanceId, env);
    ++        }
    ++    }
    ++
    ++    // (2).  Update our caches with the latest.
    ++    for (int i = 0; i < numApps; i++) {
    ++        hub_app_info query_info;
    ++        memcpy(&query_info, &unalignedInfoAddr[i], sizeof(query_info));
    +         // We will only have one instance of the app
    +         // TODO : Change this logic once we support multiple instances of the same app
    +-        int appInstance = get_app_instance_for_app_id(info.app_name.id);
    +-        add_app_instance(&info, hubHandle, appInstance, env);
    ++        jint appInstance = get_app_instance_for_app_id(query_info.app_name.id);
    ++        if (appInstance == -1) {
    ++            // This is a previously unknown app, let's allocate an "id" for it.
    ++            appInstance = generate_id();
    ++        }
    ++        add_app_instance(&query_info, hubHandle, appInstance, env);
    +     }
    + 
    +     return 0;
    + }
    + 
    ++// TODO(b/30807327): Do not use raw bytes for additional data.  Use the
    ++//     JNI interfaces for the appropriate types.
    + static void passOnOsResponse(uint32_t hubHandle, uint32_t msgType,
    +                              status_response_t *rsp, int8_t *additionalData,
    +                              size_t additionalDataLen) {
    +@@ -584,7 +672,32 @@ static void passOnOsResponse(uint32_t hubHandle, uint32_t msgType,
    +     header[HEADER_FIELD_HUB_HANDLE] = hubHandle;
    +     header[HEADER_FIELD_APP_INSTANCE] = OS_APP_ID;
    + 
    +-    msg[0] = rsp->result;
    ++    // Due to API constraints, at the moment we can't change the fact that
    ++    // we're changing our 4-byte response to a 1-byte value.  But we can prevent
    ++    // the possible change in sign (and thus meaning) that would happen from
    ++    // a naive cast.  Further, we can log when we're losing part of the value.
    ++    // TODO(b/30918279): Don't truncate this result.
    ++    int8_t truncatedResult;
    ++    bool neededToTruncate;
    ++    if (rsp->result < INT8_MIN) {
    ++        neededToTruncate = true;
    ++        truncatedResult = INT8_MIN;
    ++    } else if (rsp->result > INT8_MAX) {
    ++        neededToTruncate = true;
    ++        truncatedResult = INT8_MAX;
    ++    } else {
    ++        neededToTruncate = false;
    ++        // Since this value fits within an int8_t, this is a safe cast which
    ++        // won't change the value or sign.
    ++        truncatedResult = static_cast<int8_t>(rsp->result);
    ++    }
    ++    if (neededToTruncate) {
    ++        ALOGW("Response from Context Hub truncated.  Value was %" PRId32
    ++              ", but giving Java layer %" PRId8,
    ++              rsp->result, (int)truncatedResult);
    ++    }
    ++
    ++    msg[0] = truncatedResult;
    + 
    +     if (additionalData) {
    +         memcpy(&msg[1], additionalData, additionalDataLen);
    +@@ -603,6 +716,8 @@ static void passOnOsResponse(uint32_t hubHandle, uint32_t msgType,
    +     env->CallIntMethod(db.jniInfo.jContextHubService,
    +                        db.jniInfo.contextHubServiceMsgReceiptCallback,
    +                        jheader, jmsg);
    ++    env->DeleteLocalRef(jmsg);
    ++    env->DeleteLocalRef(jheader);
    + 
    +     delete[] msg;
    + }
    +@@ -613,7 +728,13 @@ void closeUnloadTxn(bool success) {
    + 
    +     if (success && fetchTxnData(&txnId, &txnData) == 0 &&
    +         txnId == CONTEXT_HUB_UNLOAD_APP) {
    +-        db.appInstances.erase(*(uint32_t *)txnData);
    ++        JNIEnv *env;
    ++        if ((db.jniInfo.vm)->AttachCurrentThread(&env, nullptr) != JNI_OK) {
    ++            ALOGW("Could not attach to JVM !");
    ++            env = nullptr;
    ++        }
    ++        jint handle = *reinterpret_cast<jint *>(txnData);
    ++        delete_app_instance(handle, env);
    +     } else {
    +         ALOGW("Could not unload the app successfully ! success %d, txnData %p", success, txnData);
    +     }
    +@@ -621,7 +742,7 @@ void closeUnloadTxn(bool success) {
    +     closeTxn();
    + }
    + 
    +-void closeLoadTxn(bool success, int *appInstanceHandle) {
    ++static bool closeLoadTxn(bool success, jint *appInstanceHandle) {
    +     void *txnData;
    +     hub_messages_e txnId;
    + 
    +@@ -635,13 +756,22 @@ void closeLoadTxn(bool success, int *appInstanceHandle) {
    +             add_app_instance(&info->appInfo, info->hubHandle, info->instanceId, env);
    +         } else {
    +             ALOGW("Could not attach to JVM !");
    ++            success = false;
    +         }
    +-        sendQueryForApps(info->appInfo.app_name.id);
    ++        // While we just called add_app_instance above, our info->appInfo was
    ++        // incomplete (for example, the 'version' is hardcoded to -1).  So we
    ++        // trigger an additional query to the CHRE, so we'll be able to get
    ++        // all the app "info", and have our JNI and Java caches with the
    ++        // full information.
    ++        sendQueryForApps();
    +     } else {
    +         ALOGW("Could not load the app successfully ! Unexpected failure");
    ++        *appInstanceHandle = INVALID_APP_ID;
    ++        success = false;
    +     }
    + 
    +     closeTxn();
    ++    return success;
    + }
    + 
    + static bool isValidOsStatus(const uint8_t *msg, size_t msgLen,
    +@@ -663,23 +793,6 @@ static bool isValidOsStatus(const uint8_t *msg, size_t msgLen,
    +     return true;
    + }
    + 
    +-static void invalidateNanoApps(uint32_t hubHandle) {
    +-    JNIEnv *env;
    +-
    +-    if ((db.jniInfo.vm)->AttachCurrentThread(&env, nullptr) != JNI_OK) {
    +-        ALOGW("Could not attach to JVM !");
    +-    }
    +-
    +-    auto end = db.appInstances.end();
    +-    for (auto current = db.appInstances.begin(); current != end; ) {
    +-        app_instance_info_s info = current->second;
    +-        current++;
    +-        if (info.hubHandle == hubHandle) {
    +-             delete_app_instance(info.instanceId, env);
    +-        }
    +-    }
    +-}
    +-
    + static int handle_os_message(uint32_t msgType, uint32_t hubHandle,
    +                              const uint8_t *msg, int msgLen) {
    +     int retVal = -1;
    +@@ -697,8 +810,27 @@ static int handle_os_message(uint32_t msgType, uint32_t hubHandle,
    +       case CONTEXT_HUB_UNLOAD_APP:
    +           if (isValidOsStatus(msg, msgLen, &rsp)) {
    +               if (msgType == CONTEXT_HUB_LOAD_APP) {
    +-                  int appInstanceHandle;
    +-                  closeLoadTxn(rsp.result == 0, &appInstanceHandle);
    ++                  jint appInstanceHandle = INVALID_APP_ID;
    ++                  bool appRunningOnHub = (rsp.result == 0);
    ++                  if (!(closeLoadTxn(appRunningOnHub, &appInstanceHandle))) {
    ++                      if (appRunningOnHub) {
    ++                          // Now we're in an odd situation.  Our nanoapp
    ++                          // is up and running on the Context Hub.  However,
    ++                          // something went wrong in our Service code so that
    ++                          // we're not able to properly track this nanoapp
    ++                          // in our Service code.  If we tell the Java layer
    ++                          // things are good, it's a lie because the handle
    ++                          // we give them will fail when used with the Service.
    ++                          // If we tell the Java layer this failed, it's kind
    ++                          // of a lie as well, since this nanoapp is running.
    ++                          //
    ++                          // We leave a more robust fix for later, and for
    ++                          // now just tell the user things have failed.
    ++                          //
    ++                          // TODO(b/30835981): Make this situation better.
    ++                          rsp.result = -1;
    ++                      }
    ++                  }
    +                   passOnOsResponse(hubHandle, msgType, &rsp, (int8_t *)(&appInstanceHandle),
    +                                    sizeof(appInstanceHandle));
    +               } else if (msgType == CONTEXT_HUB_UNLOAD_APP) {
    +@@ -728,8 +860,7 @@ static int handle_os_message(uint32_t msgType, uint32_t hubHandle,
    +               ALOGW("Context Hub handle %d restarted", hubHandle);
    +               closeTxn();
    +               passOnOsResponse(hubHandle, msgType, &rsp, nullptr, 0);
    +-              invalidateNanoApps(hubHandle);
    +-              query_hub_for_apps(ALL_APPS, hubHandle);
    ++              query_hub_for_apps(hubHandle);
    +               retVal = 0;
    +           }
    +           break;
    +@@ -778,7 +909,7 @@ int context_hub_callback(uint32_t hubId,
    +     if (messageType < CONTEXT_HUB_TYPE_PRIVATE_MSG_BASE) {
    +         handle_os_message(messageType, hubHandle, (uint8_t*) msg->message, msg->message_len);
    +     } else {
    +-        int appHandle = get_app_instance_for_app_id(msg->app_name.id);
    ++        jint appHandle = get_app_instance_for_app_id(msg->app_name.id);
    +         if (appHandle < 0) {
    +             ALOGE("Filtering out message due to invalid App Instance.");
    +         } else {
    +@@ -1051,7 +1182,8 @@ static jint nativeSendMessage(JNIEnv *env, jobject instance, jintArray header_,
    +         ALOGD("Asking HAL to remove app");
    +         retVal = db.hubInfo.contextHubModule->send_message(hubId, &msg);
    +     } else {
    +-      ALOGD("Could not find app instance %d on hubHandle %d, setAddress %d",
    ++      ALOGD("Could not find app instance %" PRId32 " on hubHandle %" PRId32
    ++            ", setAddress %d",
    +             header[HEADER_FIELD_APP_INSTANCE],
    +             header[HEADER_FIELD_HUB_HANDLE],
    +             (int)setAddressSuccess);
    +@@ -1060,7 +1192,8 @@ static jint nativeSendMessage(JNIEnv *env, jobject instance, jintArray header_,
    +     if (retVal != 0) {
    +         ALOGD("Send Message failure - %d", retVal);
    +         if (msgType == CONTEXT_HUB_LOAD_APP) {
    +-            closeLoadTxn(false, nullptr);
    ++            jint ignored;
    ++            closeLoadTxn(false, &ignored);
    +         } else if (msgType == CONTEXT_HUB_UNLOAD_APP) {
    +             closeUnloadTxn(false);
    +         }
    +diff --git a/core/jni/android_view_RenderNode.cpp b/core/jni/android_view_RenderNode.cpp
    +index b0028e1..1bad5f8 100644
    +--- a/core/jni/android_view_RenderNode.cpp
    ++++ b/core/jni/android_view_RenderNode.cpp
    +@@ -721,9 +721,9 @@ static const JNINativeMethod gMethods[] = {
    + int register_android_view_RenderNode(JNIEnv* env) {
    +     jclass clazz = FindClassOrDie(env, "android/view/SurfaceView");
    +     gSurfaceViewPositionUpdateMethod = GetMethodIDOrDie(env, clazz,
    +-            "updateWindowPositionRT", "(JIIII)V");
    ++            "updateWindowPosition_renderWorker", "(JIIII)V");
    +     gSurfaceViewPositionLostMethod = GetMethodIDOrDie(env, clazz,
    +-            "windowPositionLostRT", "(J)V");
    ++            "windowPositionLost_uiRtSync", "(J)V");
    +     clazz = FindClassOrDie(env, "android/view/RenderNode");
    +     gOnRenderNodeDetached = GetMethodIDOrDie(env, clazz,
    +             "onRenderNodeDetached", "()V");
    +diff --git a/core/jni/android_view_Surface.cpp b/core/jni/android_view_Surface.cpp
    +index 21e4d2f..a0c62c3 100644
    +--- a/core/jni/android_view_Surface.cpp
    ++++ b/core/jni/android_view_Surface.cpp
    +@@ -487,6 +487,11 @@ static jint nativeSetScalingMode(JNIEnv *env, jclass clazz, jlong nativeObject,
    +     return surface->setScalingMode(scalingMode);
    + }
    + 
    ++static jint nativeForceScopedDisconnect(JNIEnv *env, jclass clazz, jlong nativeObject) {
    ++    Surface* surface = reinterpret_cast<Surface*>(nativeObject);
    ++    return surface->disconnect(-1, IGraphicBufferProducer::DisconnectMode::AllLocal);
    ++}
    ++
    + namespace uirenderer {
    + 
    + using namespace android::uirenderer::renderthread;
    +@@ -564,6 +569,7 @@ static const JNINativeMethod gSurfaceMethods[] = {
    +     {"nativeGetHeight", "(J)I", (void*)nativeGetHeight },
    +     {"nativeGetNextFrameNumber", "(J)J", (void*)nativeGetNextFrameNumber },
    +     {"nativeSetScalingMode", "(JI)I", (void*)nativeSetScalingMode },
    ++    {"nativeForceScopedDisconnect", "(J)I", (void*)nativeForceScopedDisconnect},
    + 
    +     // HWUI context
    +     {"nHwuiCreate", "(JJ)J", (void*) hwui::create },
    +diff --git a/core/jni/android_view_SurfaceControl.cpp b/core/jni/android_view_SurfaceControl.cpp
    +index 0d8a95c..73b3f52 100644
    +--- a/core/jni/android_view_SurfaceControl.cpp
    ++++ b/core/jni/android_view_SurfaceControl.cpp
    +@@ -371,7 +371,12 @@ static void nativeSetDisplaySurface(JNIEnv* env, jclass clazz,
    +     if (sur != NULL) {
    +         bufferProducer = sur->getIGraphicBufferProducer();
    +     }
    +-    SurfaceComposerClient::setDisplaySurface(token, bufferProducer);
    ++    status_t err = SurfaceComposerClient::setDisplaySurface(token,
    ++            bufferProducer);
    ++    if (err != NO_ERROR) {
    ++        doThrowIAE(env, "Illegal Surface, could not enable async mode. Was this"
    ++                " Surface created with singleBufferMode?");
    ++    }
    + }
    + 
    + static void nativeSetDisplayLayerStack(JNIEnv* env, jclass clazz,
    +diff --git a/core/jni/fd_utils-inl.h b/core/jni/fd_utils-inl.h
    +index db56c32..c67662b 100644
    +--- a/core/jni/fd_utils-inl.h
    ++++ b/core/jni/fd_utils-inl.h
    +@@ -50,7 +50,6 @@ static const char* kPathWhitelist[] = {
    +   "/dev/null",
    +   "/dev/socket/zygote",
    +   "/dev/socket/zygote_secondary",
    +-  "/system/etc/event-log-tags",
    +   "/sys/kernel/debug/tracing/trace_marker",
    +   "/system/framework/framework-res.apk",
    +   "/dev/urandom",
    +diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
    +index ed71fc2..430c6b6 100644
    +--- a/core/res/AndroidManifest.xml
    ++++ b/core/res/AndroidManifest.xml
    +@@ -149,6 +149,8 @@
    +     <protected-broadcast
    +         android:name="android.bluetooth.headset.action.VENDOR_SPECIFIC_HEADSET_EVENT" />
    +     <protected-broadcast
    ++        android:name="android.bluetooth.headset.action.HF_INDICATORS_VALUE_CHANGED" />
    ++    <protected-broadcast
    +         android:name="android.bluetooth.headsetclient.profile.action.CONNECTION_STATE_CHANGED" />
    +     <protected-broadcast
    +         android:name="android.bluetooth.headsetclient.profile.action.AUDIO_STATE_CHANGED" />
    +@@ -183,6 +185,7 @@
    +     <protected-broadcast
    +         android:name="android.bluetooth.pan.profile.action.CONNECTION_STATE_CHANGED" />
    +     <protected-broadcast android:name="android.bluetooth.pbap.intent.action.PBAP_STATE_CHANGED" />
    ++    <protected-broadcast android:name="android.bluetooth.sap.profile.action.CONNECTION_STATE_CHANGED" />
    +     <protected-broadcast android:name="android.btopp.intent.action.INCOMING_FILE_NOTIFICATION" />
    +     <protected-broadcast android:name="android.btopp.intent.action.USER_CONFIRMATION_TIMEOUT" />
    +     <protected-broadcast android:name="android.btopp.intent.action.LIST" />
    +@@ -199,6 +202,8 @@
    +     <protected-broadcast android:name="com.android.bluetooth.pbap.userconfirmtimeout" />
    +     <protected-broadcast android:name="com.android.bluetooth.pbap.authresponse" />
    +     <protected-broadcast android:name="com.android.bluetooth.pbap.authcancelled" />
    ++    <protected-broadcast android:name="com.android.bluetooth.sap.USER_CONFIRM_TIMEOUT" />
    ++    <protected-broadcast android:name="com.android.bluetooth.sap.action.DISCONNECT_ACTION" />
    + 
    +     <protected-broadcast android:name="android.hardware.display.action.WIFI_DISPLAY_STATUS_CHANGED" />
    + 
    +@@ -394,6 +399,8 @@
    + 
    +     <protected-broadcast android:name="android.bluetooth.adapter.action.BLE_STATE_CHANGED" />
    +     <protected-broadcast android:name="com.android.bluetooth.map.USER_CONFIRM_TIMEOUT" />
    ++    <protected-broadcast android:name="com.android.bluetooth.BluetoothMapContentObserver.action.MESSAGE_SENT" />
    ++    <protected-broadcast android:name="com.android.bluetooth.BluetoothMapContentObserver.action.MESSAGE_DELIVERY" />
    +     <protected-broadcast android:name="android.content.jobscheduler.JOB_DELAY_EXPIRED" />
    +     <protected-broadcast android:name="android.content.syncmanager.SYNC_ALARM" />
    +     <protected-broadcast android:name="android.media.INTERNAL_RINGER_MODE_CHANGED_ACTION" />
    +@@ -1308,6 +1315,7 @@
    +         android:protectionLevel="dangerous"
    +         android:description="@string/permdesc_getAccounts"
    +         android:label="@string/permlab_getAccounts" />
    ++    <uses-permission android:name="android.permission.GET_ACCOUNTS"/>
    + 
    +     <!-- @SystemApi Allows applications to call into AccountAuthenticators.
    +     <p>Not for use by third-party applications. -->
    +@@ -1628,7 +1636,7 @@
    + 
    +     <!-- @hide Allows an application to create, remove users and get the list of
    +          users on the device. Applications holding this permission can only create restricted,
    +-         guest, managed, and ephemeral users. For creating other kind of users,
    ++         guest, managed, demo, and ephemeral users. For creating other kind of users,
    +          {@link android.Manifest.permission#MANAGE_USERS} is needed.
    +          This permission is not available to third party applications. -->
    +     <permission android:name="android.permission.CREATE_USERS"
    +@@ -3024,7 +3032,7 @@
    +     <!-- @SystemApi Allows access to MAC addresses of WiFi and Bluetooth peer devices.
    +         @hide -->
    +     <permission android:name="android.permission.PEERS_MAC_ADDRESS"
    +-                android:protectionLevel="signature" />
    ++                android:protectionLevel="signature|setup" />
    + 
    +     <!-- Allows the Nfc stack to dispatch Nfc messages to applications. Applications
    +         can use this permission to ensure incoming Nfc messages are from the Nfc stack
    +@@ -3111,7 +3119,7 @@
    +                  android:killAfterRestore="false"
    +                  android:icon="@drawable/ic_launcher_android"
    +                  android:supportsRtl="true"
    +-                 android:theme="@style/Theme.Material.Light.DarkActionBar"
    ++                 android:theme="@style/Theme.DeviceDefault.Light.DarkActionBar"
    +                  android:defaultToDeviceProtectedStorage="true"
    +                  android:directBootAware="true">
    +         <activity android:name="com.android.internal.app.ChooserActivity"
    +@@ -3148,7 +3156,7 @@
    +                 android:label="@string/managed_profile_label">
    +         </activity-alias>
    +         <activity android:name="com.android.internal.app.HeavyWeightSwitcherActivity"
    +-                android:theme="@style/Theme.Material.Light.Dialog"
    ++                android:theme="@style/Theme.DeviceDefault.Light.Dialog"
    +                 android:label="@string/heavy_weight_switcher_title"
    +                 android:finishOnCloseSystemDialogs="true"
    +                 android:excludeFromRecents="true"
    +@@ -3181,7 +3189,7 @@
    +         <activity android:name="android.accounts.ChooseAccountActivity"
    +                 android:excludeFromRecents="true"
    +                 android:exported="true"
    +-                android:theme="@style/Theme.Material.Light.Dialog"
    ++                android:theme="@style/Theme.DeviceDefault.Light.Dialog"
    +                 android:label="@string/choose_account_label"
    +                 android:process=":ui">
    +         </activity>
    +@@ -3189,14 +3197,14 @@
    +         <activity android:name="android.accounts.ChooseTypeAndAccountActivity"
    +                 android:excludeFromRecents="true"
    +                 android:exported="true"
    +-                android:theme="@style/Theme.Material.Light.Dialog"
    ++                android:theme="@style/Theme.DeviceDefault.Light.Dialog"
    +                 android:label="@string/choose_account_label"
    +                 android:process=":ui">
    +         </activity>
    + 
    +         <activity android:name="android.accounts.ChooseAccountTypeActivity"
    +                 android:excludeFromRecents="true"
    +-                android:theme="@style/Theme.Material.Light.Dialog"
    ++                android:theme="@style/Theme.DeviceDefault.Light.Dialog"
    +                 android:label="@string/choose_account_label"
    +                 android:process=":ui">
    +         </activity>
    +@@ -3204,19 +3212,19 @@
    +         <activity android:name="android.accounts.CantAddAccountActivity"
    +                 android:excludeFromRecents="true"
    +                 android:exported="true"
    +-                android:theme="@style/Theme.Material.Light.Dialog.NoActionBar"
    ++                android:theme="@style/Theme.DeviceDefault.Light.Dialog.NoActionBar"
    +                 android:process=":ui">
    +         </activity>
    + 
    +         <activity android:name="android.accounts.GrantCredentialsPermissionActivity"
    +                 android:excludeFromRecents="true"
    +                 android:exported="true"
    +-                android:theme="@style/Theme.Material.Light.DialogWhenLarge"
    ++                android:theme="@style/Theme.DeviceDefault.Light.DialogWhenLarge"
    +                 android:process=":ui">
    +         </activity>
    + 
    +         <activity android:name="android.content.SyncActivityTooManyDeletes"
    +-               android:theme="@style/Theme.Material.Light.Dialog"
    ++               android:theme="@style/Theme.DeviceDefault.Light.Dialog"
    +                android:label="@string/sync_too_many_deletes"
    +                android:process=":ui">
    +         </activity>
    +@@ -3236,7 +3244,7 @@
    +         </activity>
    + 
    +         <activity android:name="com.android.internal.app.NetInitiatedActivity"
    +-                android:theme="@style/Theme.Material.Light.Dialog.Alert"
    ++                android:theme="@style/Theme.DeviceDefault.Light.Dialog.Alert"
    +                 android:excludeFromRecents="true"
    +                 android:process=":ui">
    +         </activity>
    +@@ -3257,7 +3265,7 @@
    +         <activity android:name="com.android.internal.app.ConfirmUserCreationActivity"
    +                 android:excludeFromRecents="true"
    +                 android:process=":ui"
    +-                android:theme="@style/Theme.Material.Light.Dialog.Alert">
    ++                android:theme="@style/Theme.DeviceDefault.Light.Dialog.Alert">
    +             <intent-filter android:priority="1000">
    +                 <action android:name="android.os.action.CREATE_USER" />
    +                 <category android:name="android.intent.category.DEFAULT" />
    +@@ -3265,7 +3273,7 @@
    +         </activity>
    + 
    +         <activity android:name="com.android.internal.app.UnlaunchableAppActivity"
    +-                android:theme="@style/Theme.Material.Light.Dialog.Alert"
    ++                android:theme="@style/Theme.DeviceDefault.Light.Dialog.Alert"
    +                 android:excludeFromRecents="true"
    +                 android:process=":ui">
    +         </activity>
    +diff --git a/core/res/res/anim/dock_bottom_exit_keyguard.xml b/core/res/res/anim/dock_bottom_exit_keyguard.xml
    +new file mode 100644
    +index 0000000..4de3ce5
    +--- /dev/null
    ++++ b/core/res/res/anim/dock_bottom_exit_keyguard.xml
    +@@ -0,0 +1,22 @@
    ++<!--
    ++  ~ Copyright (C) 2016 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
    ++  -->
    ++
    ++<!-- Animation for when a dock window at the bottom of the screen is exiting while on Keyguard -->
    ++<set xmlns:android="http://schemas.android.com/apk/res/android"
    ++    android:interpolator="@android:interpolator/fast_out_linear_in">
    ++    <translate android:fromYDelta="0" android:toYDelta="100%"
    ++        android:duration="200"/>
    ++</set>
    +\ No newline at end of file
    +diff --git a/core/res/res/color/hint_foreground_material_dark.xml b/core/res/res/color/hint_foreground_material_dark.xml
    +index 77883d9..5cc9559 100644
    +--- a/core/res/res/color/hint_foreground_material_dark.xml
    ++++ b/core/res/res/color/hint_foreground_material_dark.xml
    +@@ -15,6 +15,10 @@
    + -->
    + 
    + <selector xmlns:android="http://schemas.android.com/apk/res/android">
    ++    <item android:state_enabled="true"
    ++          android:state_pressed="true"
    ++          android:alpha="@dimen/hint_pressed_alpha_material_dark"
    ++          android:color="@color/foreground_material_dark" />
    +     <item android:alpha="@dimen/hint_alpha_material_dark"
    +           android:color="@color/foreground_material_dark" />
    + </selector>
    +diff --git a/core/res/res/color/hint_foreground_material_light.xml b/core/res/res/color/hint_foreground_material_light.xml
    +index 99168fd..f7465e0 100644
    +--- a/core/res/res/color/hint_foreground_material_light.xml
    ++++ b/core/res/res/color/hint_foreground_material_light.xml
    +@@ -15,6 +15,10 @@
    + -->
    + 
    + <selector xmlns:android="http://schemas.android.com/apk/res/android">
    ++    <item android:state_enabled="true"
    ++          android:state_pressed="true"
    ++          android:alpha="@dimen/hint_pressed_alpha_material_light"
    ++          android:color="@color/foreground_material_light" />
    +     <item android:alpha="@dimen/hint_alpha_material_light"
    +           android:color="@color/foreground_material_light" />
    + </selector>
    +diff --git a/core/res/res/drawable-hdpi/vpn_connected.png b/core/res/res/drawable-hdpi/vpn_connected.png
    +index c3547e8..e05e76f 100644
    +Binary files a/core/res/res/drawable-hdpi/vpn_connected.png and b/core/res/res/drawable-hdpi/vpn_connected.png differ
    +diff --git a/core/res/res/drawable-hdpi/vpn_disconnected.png b/core/res/res/drawable-hdpi/vpn_disconnected.png
    +index 10a9065..3508984 100644
    +Binary files a/core/res/res/drawable-hdpi/vpn_disconnected.png and b/core/res/res/drawable-hdpi/vpn_disconnected.png differ
    +diff --git a/core/res/res/drawable-mdpi/vpn_connected.png b/core/res/res/drawable-mdpi/vpn_connected.png
    +index 7e167f8..f7ac2a1 100644
    +Binary files a/core/res/res/drawable-mdpi/vpn_connected.png and b/core/res/res/drawable-mdpi/vpn_connected.png differ
    +diff --git a/core/res/res/drawable-mdpi/vpn_disconnected.png b/core/res/res/drawable-mdpi/vpn_disconnected.png
    +index a08c42a..9db4199 100644
    +Binary files a/core/res/res/drawable-mdpi/vpn_disconnected.png and b/core/res/res/drawable-mdpi/vpn_disconnected.png differ
    +diff --git a/core/res/res/drawable-nodpi/vpn_connected.xml b/core/res/res/drawable-nodpi/vpn_connected.xml
    +new file mode 100644
    +index 0000000..22a4a6c
    +--- /dev/null
    ++++ b/core/res/res/drawable-nodpi/vpn_connected.xml
    +@@ -0,0 +1,24 @@
    ++<!--
    ++Copyright (C) 2016 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.
    ++-->
    ++<vector xmlns:android="http://schemas.android.com/apk/res/android"
    ++        android:width="48dp"
    ++        android:height="48dp"
    ++        android:viewportWidth="48.0"
    ++        android:viewportHeight="48.0">
    ++    <path
    ++        android:fillColor="#FF000000"
    ++        android:pathData="M25.3,20c-1.65,-4.66 -6.08,-8 -11.3,-8 -6.63,0 -12,5.37 -12,12s5.37,12 12,12c5.22,0 9.65,-3.34 11.3,-8H34v8h8v-8h4v-8H25.3zM14,28c-2.21,0 -4,-1.79 -4,-4s1.79,-4 4,-4 4,1.79 4,4 -1.79,4 -4,4z"/>
    ++</vector>
    +diff --git a/core/res/res/drawable-nodpi/vpn_disconnected.xml b/core/res/res/drawable-nodpi/vpn_disconnected.xml
    +new file mode 100644
    +index 0000000..22a4a6c
    +--- /dev/null
    ++++ b/core/res/res/drawable-nodpi/vpn_disconnected.xml
    +@@ -0,0 +1,24 @@
    ++<!--
    ++Copyright (C) 2016 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.
    ++-->
    ++<vector xmlns:android="http://schemas.android.com/apk/res/android"
    ++        android:width="48dp"
    ++        android:height="48dp"
    ++        android:viewportWidth="48.0"
    ++        android:viewportHeight="48.0">
    ++    <path
    ++        android:fillColor="#FF000000"
    ++        android:pathData="M25.3,20c-1.65,-4.66 -6.08,-8 -11.3,-8 -6.63,0 -12,5.37 -12,12s5.37,12 12,12c5.22,0 9.65,-3.34 11.3,-8H34v8h8v-8h4v-8H25.3zM14,28c-2.21,0 -4,-1.79 -4,-4s1.79,-4 4,-4 4,1.79 4,4 -1.79,4 -4,4z"/>
    ++</vector>
    +diff --git a/core/res/res/drawable-xhdpi/vpn_connected.png b/core/res/res/drawable-xhdpi/vpn_connected.png
    +index 1f46be2..a8761c9 100644
    +Binary files a/core/res/res/drawable-xhdpi/vpn_connected.png and b/core/res/res/drawable-xhdpi/vpn_connected.png differ
    +diff --git a/core/res/res/drawable-xhdpi/vpn_disconnected.png b/core/res/res/drawable-xhdpi/vpn_disconnected.png
    +index 847d3f5..7118918 100644
    +Binary files a/core/res/res/drawable-xhdpi/vpn_disconnected.png and b/core/res/res/drawable-xhdpi/vpn_disconnected.png differ
    +diff --git a/core/res/res/drawable-xxhdpi/vpn_connected.png b/core/res/res/drawable-xxhdpi/vpn_connected.png
    +index ea4930c..16b1e4e 100644
    +Binary files a/core/res/res/drawable-xxhdpi/vpn_connected.png and b/core/res/res/drawable-xxhdpi/vpn_connected.png differ
    +diff --git a/core/res/res/drawable-xxhdpi/vpn_disconnected.png b/core/res/res/drawable-xxhdpi/vpn_disconnected.png
    +index 4cd0dd4..a025818 100644
    +Binary files a/core/res/res/drawable-xxhdpi/vpn_disconnected.png and b/core/res/res/drawable-xxhdpi/vpn_disconnected.png differ
    +diff --git a/core/res/res/drawable/emergency_icon.xml b/core/res/res/drawable/emergency_icon.xml
    +new file mode 100644
    +index 0000000..b2ffa2b
    +--- /dev/null
    ++++ b/core/res/res/drawable/emergency_icon.xml
    +@@ -0,0 +1,40 @@
    ++<!--
    ++Copyright (C) 2014 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.
    ++-->
    ++<vector xmlns:android="http://schemas.android.com/apk/res/android"
    ++        android:width="24.0dp"
    ++        android:height="24.0dp"
    ++        android:viewportWidth="24.0"
    ++        android:viewportHeight="24.0"
    ++        android:tint="?attr/colorControlNormal">
    ++    <path
    ++        android:fillColor="#FF000000"
    ++        android:pathData="M6.8,17.3C5.3,15.9 4.5,14.0 4.5,12.0c0.0,-2.0 0.8,-3.8 2.1,-5.2l1.4,1.4c-1.0,1.0 -1.6,2.4 -1.6,3.8c0.0,1.5 0.6,2.9 1.6,3.9L6.8,17.3z"/>
    ++    <path
    ++        android:fillColor="#FF000000"
    ++        android:pathData="M3.3,20.2C1.2,18.0 0.0,15.1 0.0,12.0c0.0,-3.1 1.2,-6.0 3.3,-8.2l1.4,1.4C3.0,7.0 2.0,9.4 2.0,12.0s1.0,5.0 2.7,6.9L3.3,20.2z"/>
    ++    <path
    ++        android:fillColor="#FF000000"
    ++        android:pathData="M17.2,17.3l-1.4,-1.4c1.1,-1.0 1.6,-2.4 1.6,-3.9c0.0,-1.4 -0.6,-2.8 -1.6,-3.8l1.4,-1.4c1.4,1.4 2.1,3.3 2.1,5.2C19.5,14.0 18.7,15.9 17.2,17.3z"/>
    ++    <path
    ++        android:fillColor="#FF000000"
    ++        android:pathData="M20.7,20.2l-1.4,-1.4C21.0,17.0 22.0,14.6 22.0,12.0c0.0,-2.6 -1.0,-5.0 -2.7,-6.9l1.4,-1.4C22.8,6.0 24.0,8.9 24.0,12.0C24.0,15.1 22.8,18.0 20.7,20.2z"/>
    ++    <path
    ++        android:fillColor="#FF000000"
    ++        android:pathData="M11.0,15.0l2.0,0.0l0.0,2.0l-2.0,0.0z"/>
    ++    <path
    ++        android:fillColor="#FF000000"
    ++        android:pathData="M11.0,7.0l2.0,0.0l0.0,6.0l-2.0,0.0z"/>
    ++</vector>
    +diff --git a/core/res/res/drawable/ic_check_circle_24px.xml b/core/res/res/drawable/ic_check_circle_24px.xml
    +index 066a8a7..e9af9e4 100644
    +--- a/core/res/res/drawable/ic_check_circle_24px.xml
    ++++ b/core/res/res/drawable/ic_check_circle_24px.xml
    +@@ -19,9 +19,6 @@ Copyright (C) 2015 The Android Open Source Project
    +         android:viewportWidth="24.0"
    +         android:viewportHeight="24.0">
    +     <path
    +-        android:pathData="M0 0h24v24H0z"
    +-        android:fillColor="#00000000"/>
    +-    <path
    +         android:fillColor="#FF000000"
    +         android:pathData="M12.0,2.0C6.48,2.0 2.0,6.48 2.0,12.0s4.48,10.0 10.0,10.0 10.0,-4.48 10.0,-10.0S17.52,2.0 12.0,2.0zm-2.0,15.0l-5.0,-5.0 1.41,-1.41L10.0,14.17l7.59,-7.59L19.0,8.0l-9.0,9.0z"/>
    + </vector>
    +diff --git a/core/res/res/drawable/ic_collapse_notification.xml b/core/res/res/drawable/ic_collapse_notification.xml
    +index 603c159..124e99e 100644
    +--- a/core/res/res/drawable/ic_collapse_notification.xml
    ++++ b/core/res/res/drawable/ic_collapse_notification.xml
    +@@ -22,7 +22,4 @@ Copyright (C) 2015 The Android Open Source Project
    +     <path
    +         android:fillColor="#FF000000"
    +         android:pathData="M12.0,8.0l-6.0,6.0l1.4,1.4l4.6,-4.6l4.6,4.6L18.0,14.0L12.0,8.0z"/>
    +-    <path
    +-        android:pathData="M0,0h24v24H0V0z"
    +-        android:fillColor="#00000000"/>
    + </vector>
    +diff --git a/core/res/res/drawable/ic_expand_more_48dp.xml b/core/res/res/drawable/ic_expand_more_48dp.xml
    +index 11323e3..5a71669 100644
    +--- a/core/res/res/drawable/ic_expand_more_48dp.xml
    ++++ b/core/res/res/drawable/ic_expand_more_48dp.xml
    +@@ -21,7 +21,4 @@ Copyright (C) 2015 The Android Open Source Project
    +     <path
    +         android:fillColor="#FF000000"
    +         android:pathData="M33.17,17.17L24.0,26.34l-9.17,-9.17L12.0,20.0l12.0,12.0 12.0,-12.0z"/>
    +-    <path
    +-        android:pathData="M0 0h48v48H0z"
    +-        android:fillColor="#00000000"/>
    + </vector>
    +diff --git a/core/res/res/drawable/ic_expand_notification.xml b/core/res/res/drawable/ic_expand_notification.xml
    +index db7d3eb..847e326 100644
    +--- a/core/res/res/drawable/ic_expand_notification.xml
    ++++ b/core/res/res/drawable/ic_expand_notification.xml
    +@@ -22,7 +22,4 @@ Copyright (C) 2015 The Android Open Source Project
    +     <path
    +         android:fillColor="#FF000000"
    +         android:pathData="M16.6,8.6L12.0,13.2L7.4,8.6L6.0,10.0l6.0,6.0l6.0,-6.0L16.6,8.6z"/>
    +-    <path
    +-        android:pathData="M0,0h24v24H0V0z"
    +-        android:fillColor="#00000000"/>
    + </vector>
    +diff --git a/core/res/res/drawable/ic_feedback.xml b/core/res/res/drawable/ic_feedback.xml
    +index b2d1cb8..365863d 100644
    +--- a/core/res/res/drawable/ic_feedback.xml
    ++++ b/core/res/res/drawable/ic_feedback.xml
    +@@ -19,9 +19,6 @@ Copyright (C) 2016 The Android Open Source Project
    +         android:viewportWidth="24.0"
    +         android:viewportHeight="24.0">
    +     <path
    +-        android:pathData="M0 0h24v24H0z"
    +-        android:fillColor="#00000000"/>
    +-    <path
    +         android:fillColor="#FF000000"
    +         android:pathData="M20.0,2.0L4.0,2.0c-1.1,0.0 -1.9,0.9 -1.99,2.0L2.0,22.0l4.0,-4.0l14.0,0.0c1.1,0.0 2.0,-0.9 2.0,-2.0L22.0,4.0c0.0,-1.1 -0.9,-2.0 -2.0,-2.0zm-7.0,12.0l-2.0,0.0l0.0,-2.0l2.0,0.0l0.0,2.0zm0.0,-4.0l-2.0,0.0L11.0,6.0l2.0,0.0l0.0,4.0z"/>
    + </vector>
    +diff --git a/core/res/res/drawable/ic_more_items.xml b/core/res/res/drawable/ic_more_items.xml
    +index 5fdcdce..0ec754c 100644
    +--- a/core/res/res/drawable/ic_more_items.xml
    ++++ b/core/res/res/drawable/ic_more_items.xml
    +@@ -24,6 +24,5 @@
    +         android:fillColor="#000000"
    +         android:pathData="M3 13h2v-2H3v2zm0 4h2v-2H3v2zm0-8h2V7H3v2zm4 4h14v-2H7v2zm0 4h14v-2H7v2zM7
    + 7v2h14V7H7z" />
    +-    <path
    +-        android:pathData="M0 0h24v24H0z" />
    ++
    + </vector>
    +\ No newline at end of file
    +diff --git a/core/res/res/drawable/ic_refresh.xml b/core/res/res/drawable/ic_refresh.xml
    +index 1f67168..1297407 100644
    +--- a/core/res/res/drawable/ic_refresh.xml
    ++++ b/core/res/res/drawable/ic_refresh.xml
    +@@ -21,7 +21,4 @@ Copyright (C) 2016 The Android Open Source Project
    +     <path
    +         android:fillColor="#FF000000"
    +         android:pathData="M17.65,6.35C16.2,4.9 14.21,4.0 12.0,4.0c-4.42,0.0 -7.99,3.58 -7.99,8.0s3.57,8.0 7.99,8.0c3.73,0.0 6.84,-2.55 7.73,-6.0l-2.08,0.0c-0.82,2.33 -3.04,4.0 -5.65,4.0 -3.31,0.0 -6.0,-2.69 -6.0,-6.0s2.69,-6.0 6.0,-6.0c1.66,0.0 3.1,0.69 4.22,1.78L13.0,11.0l7.0,0.0L20.0,4.0l-2.35,2.35z"/>
    +-    <path
    +-        android:pathData="M0 0h24v24H0z"
    +-        android:fillColor="#00000000"/>
    + </vector>
    +diff --git a/core/res/res/drawable/ic_schedule.xml b/core/res/res/drawable/ic_schedule.xml
    +index 899dc82..55d54b1 100644
    +--- a/core/res/res/drawable/ic_schedule.xml
    ++++ b/core/res/res/drawable/ic_schedule.xml
    +@@ -22,9 +22,6 @@ Copyright (C) 2016 The Android Open Source Project
    +         android:fillColor="#FF000000"
    +         android:pathData="M11.99,2.0C6.47,2.0 2.0,6.48 2.0,12.0s4.47,10.0 9.99,10.0C17.52,22.0 22.0,17.52 22.0,12.0S17.52,2.0 11.99,2.0zM12.0,20.0c-4.42,0.0 -8.0,-3.58 -8.0,-8.0s3.58,-8.0 8.0,-8.0 8.0,3.58 8.0,8.0 -3.58,8.0 -8.0,8.0z"/>
    +     <path
    +-        android:pathData="M0 0h24v24H0z"
    +-        android:fillColor="#00000000"/>
    +-    <path
    +         android:fillColor="#FF000000"
    +         android:pathData="M12.5,7.0L11.0,7.0l0.0,6.0l5.25,3.1 0.75,-1.23 -4.5,-2.67z"/>
    + </vector>
    +diff --git a/core/res/res/drawable/perm_group_calendar.xml b/core/res/res/drawable/perm_group_calendar.xml
    +index 4dc7b37..85a783e 100644
    +--- a/core/res/res/drawable/perm_group_calendar.xml
    ++++ b/core/res/res/drawable/perm_group_calendar.xml
    +@@ -24,6 +24,5 @@
    +         android:fillColor="#000000"
    +         android:pathData="M17 12h-5v5h5v-5zM16 1v2H8V1H6v2H5c-1.11 0-1.99 .9 -1.99 2L3 19c0 1.1 .89 2 2
    + 2h14c1.1 0 2-.9 2-2V5c0-1.1-.9-2-2-2h-1V1h-2zm3 18H5V8h14v11z" />
    +-    <path
    +-        android:pathData="M0 0h24v24H0z" />
    ++
    + </vector>
    +\ No newline at end of file
    +diff --git a/core/res/res/drawable/perm_group_camera.xml b/core/res/res/drawable/perm_group_camera.xml
    +index 741a40e..61903a5 100644
    +--- a/core/res/res/drawable/perm_group_camera.xml
    ++++ b/core/res/res/drawable/perm_group_camera.xml
    +@@ -28,6 +28,4 @@
    +         android:pathData="M9 2L7.17 4H4c-1.1 0-2 .9-2 2v12c0 1.1 .9 2 2 2h16c1.1 0 2-.9
    + 2-2V6c0-1.1-.9-2-2-2h-3.17L15 2H9zm3 15c-2.76 0-5-2.24-5-5s2.24-5 5-5 5 2.24 5
    + 5-2.24 5-5 5z" />
    +-    <path
    +-        android:pathData="M0 0h24v24H0z" />
    + </vector>
    +\ No newline at end of file
    +diff --git a/core/res/res/drawable/perm_group_contacts.xml b/core/res/res/drawable/perm_group_contacts.xml
    +index d698fd1..8f9dc3e 100644
    +--- a/core/res/res/drawable/perm_group_contacts.xml
    ++++ b/core/res/res/drawable/perm_group_contacts.xml
    +@@ -21,8 +21,6 @@
    +     android:viewportHeight="24">
    + 
    +     <path
    +-        android:pathData="M0 0h24v24H0zm0 0h24v24H0zm0 0h24v24H0z" />
    +-    <path
    +         android:fillColor="#000000"
    +         android:pathData="M20 0H4v2h16V0zM4 24h16v-2H4v2zM20 4H4c-1.1 0-2 .9-2 2v12c0 1.1 .9 2 2 2h16c1.1
    + 0 2-.9 2-2V6c0-1.1-.9-2-2-2zm-8 2.75c1.24 0 2.25 1.01 2.25 2.25s-1.01 2.25-2.25
    +diff --git a/core/res/res/drawable/perm_group_location.xml b/core/res/res/drawable/perm_group_location.xml
    +index fbc6066..cc1ec90 100644
    +--- a/core/res/res/drawable/perm_group_location.xml
    ++++ b/core/res/res/drawable/perm_group_location.xml
    +@@ -24,6 +24,4 @@
    +         android:fillColor="#000000"
    +         android:pathData="M12 2C8.13 2 5 5.13 5 9c0 5.25 7 13 7 13s7-7.75 7-13c0-3.87-3.13-7-7-7zm0
    + 9.5c-1.38 0-2.5-1.12-2.5-2.5s1.12-2.5 2.5-2.5 2.5 1.12 2.5 2.5-1.12 2.5-2.5 2.5z" />
    +-    <path
    +-        android:pathData="M0 0h24v24H0z" />
    + </vector>
    +\ No newline at end of file
    +diff --git a/core/res/res/drawable/perm_group_microphone.xml b/core/res/res/drawable/perm_group_microphone.xml
    +index c565d20..d494e67 100644
    +--- a/core/res/res/drawable/perm_group_microphone.xml
    ++++ b/core/res/res/drawable/perm_group_microphone.xml
    +@@ -25,6 +25,4 @@
    +         android:pathData="M12 14c1.66 0 2.99-1.34 2.99-3L15 5c0-1.66-1.34-3-3-3S9 3.34 9 5v6c0 1.66 1.34 3
    + 3 3zm5.3-3c0 3-2.54 5.1-5.3 5.1S6.7 14 6.7 11H5c0 3.41 2.72 6.23 6
    + 6.72V21h2v-3.28c3.28-.48 6-3.3 6-6.72h-1.7z" />
    +-    <path
    +-        android:pathData="M0 0h24v24H0z" />
    + </vector>
    +\ No newline at end of file
    +diff --git a/core/res/res/drawable/perm_group_phone_calls.xml b/core/res/res/drawable/perm_group_phone_calls.xml
    +index a647894..324d864 100644
    +--- a/core/res/res/drawable/perm_group_phone_calls.xml
    ++++ b/core/res/res/drawable/perm_group_phone_calls.xml
    +@@ -19,9 +19,6 @@
    +     android:height="24dp"
    +     android:viewportWidth="24"
    +     android:viewportHeight="24">
    +-
    +-    <path
    +-        android:pathData="M0 0h24v24H0z" />
    +     <path
    +         android:fillColor="#000000"
    +         android:pathData="M6.62 10.79c1.44 2.83 3.76 5.14 6.59 6.59l2.2-2.2c.27-.27 .67 -.36 1.02-.24 1.12
    +diff --git a/core/res/res/drawable/perm_group_sms.xml b/core/res/res/drawable/perm_group_sms.xml
    +index 9b32c601..47bca19 100644
    +--- a/core/res/res/drawable/perm_group_sms.xml
    ++++ b/core/res/res/drawable/perm_group_sms.xml
    +@@ -24,6 +24,4 @@
    +         android:fillColor="#000000"
    +         android:pathData="M20 2H4c-1.1 0-1.99 .9 -1.99 2L2 22l4-4h14c1.1 0 2-.9 2-2V4c0-1.1-.9-2-2-2zM9
    + 11H7V9h2v2zm4 0h-2V9h2v2zm4 0h-2V9h2v2z" />
    +-    <path
    +-        android:pathData="M0 0h24v24H0z" />
    + </vector>
    +\ No newline at end of file
    +diff --git a/core/res/res/drawable/perm_group_storage.xml b/core/res/res/drawable/perm_group_storage.xml
    +index 477270d..1ff1693 100644
    +--- a/core/res/res/drawable/perm_group_storage.xml
    ++++ b/core/res/res/drawable/perm_group_storage.xml
    +@@ -24,6 +24,4 @@
    +         android:fillColor="#000000"
    +         android:pathData="M10 4H4c-1.1 0-1.99 .9 -1.99 2L2 18c0 1.1 .9 2 2 2h16c1.1 0 2-.9
    + 2-2V8c0-1.1-.9-2-2-2h-8l-2-2z" />
    +-    <path
    +-        android:pathData="M0 0h24v24H0z" />
    + </vector>
    +\ No newline at end of file
    +diff --git a/core/res/res/drawable/progress_indeterminate_anim_large_material.xml b/core/res/res/drawable/progress_indeterminate_anim_large_material.xml
    +new file mode 100644
    +index 0000000..560ec5a
    +--- /dev/null
    ++++ b/core/res/res/drawable/progress_indeterminate_anim_large_material.xml
    +@@ -0,0 +1,26 @@
    ++<?xml version="1.0" encoding="utf-8"?>
    ++<!-- Copyright (C) 2016 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.
    ++-->
    ++<animated-vector xmlns:android="http://schemas.android.com/apk/res/android"
    ++                 android:drawable="@drawable/vector_drawable_progress_bar_large" >
    ++    <target
    ++            android:name="progressBar"
    ++            android:animation="@anim/progress_indeterminate_material" />
    ++
    ++    <target
    ++            android:name="root"
    ++            android:animation="@anim/progress_indeterminate_rotation_material" />
    ++</animated-vector>
    ++
    +diff --git a/core/res/res/drawable/progress_indeterminate_anim_medium_material.xml b/core/res/res/drawable/progress_indeterminate_anim_medium_material.xml
    +new file mode 100644
    +index 0000000..fbea22f
    +--- /dev/null
    ++++ b/core/res/res/drawable/progress_indeterminate_anim_medium_material.xml
    +@@ -0,0 +1,27 @@
    ++<?xml version="1.0" encoding="utf-8"?>
    ++<!-- Copyright (C) 2016 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.
    ++-->
    ++<animated-vector xmlns:android="http://schemas.android.com/apk/res/android"
    ++    android:drawable="@drawable/vector_drawable_progress_bar_medium" >
    ++
    ++    <target
    ++        android:name="progressBar"
    ++        android:animation="@anim/progress_indeterminate_material" />
    ++
    ++    <target
    ++        android:name="root"
    ++        android:animation="@anim/progress_indeterminate_rotation_material" />
    ++
    ++</animated-vector>
    +\ No newline at end of file
    +diff --git a/core/res/res/drawable/progress_large_material.xml b/core/res/res/drawable/progress_large_material.xml
    +index 526f914..ee82e35 100644
    +--- a/core/res/res/drawable/progress_large_material.xml
    ++++ b/core/res/res/drawable/progress_large_material.xml
    +@@ -13,16 +13,8 @@
    +      See the License for the specific language governing permissions and
    +      limitations under the License.
    + -->
    +-
    +-<animated-vector xmlns:android="http://schemas.android.com/apk/res/android"
    +-    android:drawable="@drawable/vector_drawable_progress_bar_large" >
    +-
    +-    <target
    +-        android:name="progressBar"
    +-        android:animation="@anim/progress_indeterminate_material" />
    +-
    +-    <target
    +-        android:name="root"
    +-        android:animation="@anim/progress_indeterminate_rotation_material" />
    +-
    +-</animated-vector>
    ++<com.android.internal.graphics.drawable.AnimationScaleListDrawable
    ++        xmlns:android="http://schemas.android.com/apk/res/android">
    ++    <item android:drawable="@drawable/progress_static_material" />
    ++    <item android:drawable="@drawable/progress_indeterminate_anim_large_material" />
    ++</com.android.internal.graphics.drawable.AnimationScaleListDrawable>
    +diff --git a/core/res/res/drawable/progress_medium_material.xml b/core/res/res/drawable/progress_medium_material.xml
    +index cc35816..5c92600 100644
    +--- a/core/res/res/drawable/progress_medium_material.xml
    ++++ b/core/res/res/drawable/progress_medium_material.xml
    +@@ -13,15 +13,8 @@
    +      See the License for the specific language governing permissions and
    +      limitations under the License.
    + -->
    +-<animated-vector xmlns:android="http://schemas.android.com/apk/res/android"
    +-    android:drawable="@drawable/vector_drawable_progress_bar_medium" >
    +-
    +-    <target
    +-        android:name="progressBar"
    +-        android:animation="@anim/progress_indeterminate_material" />
    +-
    +-    <target
    +-        android:name="root"
    +-        android:animation="@anim/progress_indeterminate_rotation_material" />
    +-
    +-</animated-vector>
    +\ No newline at end of file
    ++<com.android.internal.graphics.drawable.AnimationScaleListDrawable
    ++        xmlns:android="http://schemas.android.com/apk/res/android">
    ++    <item android:drawable="@drawable/progress_static_material" />
    ++    <item android:drawable="@drawable/progress_indeterminate_anim_medium_material" />
    ++</com.android.internal.graphics.drawable.AnimationScaleListDrawable>
    +diff --git a/core/res/res/drawable/progress_small_material.xml b/core/res/res/drawable/progress_small_material.xml
    +index c6e4380..cec9d95 100644
    +--- a/core/res/res/drawable/progress_small_material.xml
    ++++ b/core/res/res/drawable/progress_small_material.xml
    +@@ -13,16 +13,17 @@
    +      See the License for the specific language governing permissions and
    +      limitations under the License.
    + -->
    +-
    +-<animated-vector xmlns:android="http://schemas.android.com/apk/res/android"
    +-    android:drawable="@drawable/vector_drawable_progress_bar_small" >
    +-
    +-    <target
    +-        android:name="progressBar"
    +-        android:animation="@anim/progress_indeterminate_material" />
    +-
    +-    <target
    +-        android:name="root"
    +-        android:animation="@anim/progress_indeterminate_rotation_material" />
    +-
    +-</animated-vector>
    ++<com.android.internal.graphics.drawable.AnimationScaleListDrawable
    ++        xmlns:android="http://schemas.android.com/apk/res/android">
    ++    <item android:drawable="@drawable/progress_static_material" />
    ++    <item>
    ++        <animated-vector android:drawable="@drawable/vector_drawable_progress_bar_small" >
    ++            <target
    ++                    android:name="progressBar"
    ++                    android:animation="@anim/progress_indeterminate_material" />
    ++            <target
    ++                    android:name="root"
    ++                    android:animation="@anim/progress_indeterminate_rotation_material" />
    ++        </animated-vector>
    ++    </item>
    ++</com.android.internal.graphics.drawable.AnimationScaleListDrawable>
    +diff --git a/core/res/res/drawable/progress_static_material.xml b/core/res/res/drawable/progress_static_material.xml
    +new file mode 100644
    +index 0000000..b078fa9
    +--- /dev/null
    ++++ b/core/res/res/drawable/progress_static_material.xml
    +@@ -0,0 +1,25 @@
    ++<!--
    ++Copyright (C) 2016 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.
    ++-->
    ++<vector xmlns:android="http://schemas.android.com/apk/res/android"
    ++        android:width="24.0dp"
    ++        android:height="24.0dp"
    ++        android:viewportWidth="24.0"
    ++        android:viewportHeight="24.0"
    ++        >
    ++    <path
    ++        android:fillColor="?attr/colorControlActivated"
    ++        android:pathData="M17.65,6.35C16.2,4.9 14.21,4.0 12.0,4.0c-4.42,0.0 -7.99,3.58 -7.99,8.0s3.57,8.0 7.99,8.0c3.73,0.0 6.84,-2.55 7.73,-6.0l-2.08,0.0c-0.82,2.33 -3.04,4.0 -5.65,4.0 -3.31,0.0 -6.0,-2.69 -6.0,-6.0s2.69,-6.0 6.0,-6.0c1.66,0.0 3.1,0.69 4.22,1.78L13.0,11.0l7.0,0.0L20.0,4.0l-2.35,2.35z"/>
    ++</vector>
    +diff --git a/core/res/res/layout-sw600dp/date_picker_dialog.xml b/core/res/res/layout-sw600dp/date_picker_dialog.xml
    +index 5e3ca14..cd6af46 100644
    +--- a/core/res/res/layout-sw600dp/date_picker_dialog.xml
    ++++ b/core/res/res/layout-sw600dp/date_picker_dialog.xml
    +@@ -22,4 +22,4 @@
    +     android:layout_height="wrap_content"
    +     android:spinnersShown="true"
    +     android:calendarViewShown="true"
    +-    android:datePickerMode="@integer/date_picker_mode" />
    ++    android:dialogMode="true" />
    +diff --git a/core/res/res/layout/date_picker_dialog.xml b/core/res/res/layout/date_picker_dialog.xml
    +index 8f36e95..32a7360 100644
    +--- a/core/res/res/layout/date_picker_dialog.xml
    ++++ b/core/res/res/layout/date_picker_dialog.xml
    +@@ -22,4 +22,4 @@
    +     android:layout_height="wrap_content"
    +     android:spinnersShown="true"
    +     android:calendarViewShown="false"
    +-    android:datePickerMode="@integer/date_picker_mode" />
    ++    android:dialogMode="true" />
    +diff --git a/core/res/res/layout/time_picker_dialog.xml b/core/res/res/layout/time_picker_dialog.xml
    +index d1f3902..ada18d1 100644
    +--- a/core/res/res/layout/time_picker_dialog.xml
    ++++ b/core/res/res/layout/time_picker_dialog.xml
    +@@ -22,4 +22,4 @@
    +     android:layout_gravity="center_horizontal"
    +     android:layout_width="wrap_content"
    +     android:layout_height="wrap_content"
    +-    android:timePickerMode="@integer/time_picker_mode" />
    ++    android:dialogMode="true" />
    +diff --git a/core/res/res/values-af/strings.xml b/core/res/res/values-af/strings.xml
    +index bd92ab6..4b59f21 100644
    +--- a/core/res/res/values-af/strings.xml
    ++++ b/core/res/res/values-af/strings.xml
    +@@ -214,6 +214,7 @@
    +     <string name="global_actions" product="default" msgid="2406416831541615258">"Foonopsies"</string>
    +     <string name="global_action_lock" msgid="2844945191792119712">"Skermslot"</string>
    +     <string name="global_action_power_off" msgid="4471879440839879722">"Sit af"</string>
    ++    <string name="global_action_emergency" msgid="7112311161137421166">"Noodgeval"</string>
    +     <string name="global_action_bug_report" msgid="7934010578922304799">"Foutverslag"</string>
    +     <string name="bugreport_title" msgid="2667494803742548533">"Neem foutverslag"</string>
    +     <string name="bugreport_message" msgid="398447048750350456">"Dit sal inligting oor die huidige toestand van jou toestel insamel om as \'n e-posboodskap te stuur. Dit sal \'n tydjie neem vandat die foutverslag begin is totdat dit reg is om gestuur te word; wees asseblief geduldig."</string>
    +@@ -1076,6 +1077,17 @@
    +     <skip />
    +     <string name="wifi_no_internet" msgid="8451173622563841546">"Wi-Fi het geen internettoegang nie"</string>
    +     <string name="wifi_no_internet_detailed" msgid="8083079241212301741">"Tik vir opsies"</string>
    ++    <string name="network_switch_metered" msgid="4671730921726992671">"Het oorgeskakel na <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
    ++    <string name="network_switch_metered_detail" msgid="5325661434777870353">"Toestel gebruik <xliff:g id="NEW_NETWORK">%1$s</xliff:g> wanneer <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> geen internetverbinding het nie. Heffings kan geld."</string>
    ++    <string name="network_switch_metered_toast" msgid="5779283181685974304">"Het oorgeskakel van <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> na <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
    ++  <string-array name="network_switch_type_name">
    ++    <item msgid="2952042958050315394">"sellulêre data"</item>
    ++    <item msgid="75483255295529161">"Wi-Fi"</item>
    ++    <item msgid="6862614801537202646">"Bluetooth"</item>
    ++    <item msgid="5447331121797802871">"Ethernet"</item>
    ++    <item msgid="8257233890381651999">"VPN"</item>
    ++  </string-array>
    ++    <string name="network_switch_type_name_unknown" msgid="4552612897806660656">"\'n onbekende netwerktipe"</string>
    +     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Kon nie aan Wi-Fikoppel nie"</string>
    +     <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" het \'n swak internetverbinding."</string>
    +     <string name="wifi_connect_alert_title" msgid="8455846016001810172">"Laat verbinding toe?"</string>
    +@@ -1153,7 +1165,6 @@
    +     <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"Tik om taal en uitleg te kies"</string>
    +     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
    +     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
    +-    <string name="candidates_style" msgid="4333913089637062257"><u>"kandidate"</u></string>
    +     <string name="ext_media_checking_notification_title" msgid="5734005953288045806">"Berei tans <xliff:g id="NAME">%s</xliff:g> voor"</string>
    +     <string name="ext_media_checking_notification_message" msgid="4747432538578886744">"Kyk tans vir foute"</string>
    +     <string name="ext_media_new_notification_message" msgid="7589986898808506239">"Nuwe <xliff:g id="NAME">%s</xliff:g> bespeur"</string>
    +@@ -1232,8 +1243,9 @@
    +     <string name="vpn_text_long" msgid="4907843483284977618">"Gekoppel aan <xliff:g id="SESSION">%s</xliff:g>. Tik om die netwerk te bestuur."</string>
    +     <string name="vpn_lockdown_connecting" msgid="6443438964440960745">"Altydaan-VPN koppel tans..."</string>
    +     <string name="vpn_lockdown_connected" msgid="8202679674819213931">"Altydaan-VPN gekoppel"</string>
    ++    <string name="vpn_lockdown_disconnected" msgid="4532298952570796327">"Altydaan-VPN is ontkoppel"</string>
    +     <string name="vpn_lockdown_error" msgid="6009249814034708175">"Altydaan-VPN-fout"</string>
    +-    <string name="vpn_lockdown_config" msgid="4655589351146766608">"Tik om op te stel"</string>
    ++    <string name="vpn_lockdown_config" msgid="5099330695245008680">"Tik om op te stel"</string>
    +     <string name="upload_file" msgid="2897957172366730416">"Kies lêer"</string>
    +     <string name="no_file_chosen" msgid="6363648562170759465">"Geen lêer gekies nie"</string>
    +     <string name="reset" msgid="2448168080964209908">"Stel terug"</string>
    +@@ -1317,7 +1329,7 @@
    +     <string name="storage_usb_drive_label" msgid="4501418548927759953">"<xliff:g id="MANUFACTURER">%s</xliff:g>-USB-datastokkie"</string>
    +     <string name="storage_usb" msgid="3017954059538517278">"USB-berging"</string>
    +     <string name="extract_edit_menu_button" msgid="8940478730496610137">"Redigeer"</string>
    +-    <string name="data_usage_warning_title" msgid="1955638862122232342">"Dataverbruik-waarskuwing"</string>
    ++    <string name="data_usage_warning_title" msgid="3620440638180218181">"Datagebruik-opletberig"</string>
    +     <string name="data_usage_warning_body" msgid="6660692274311972007">"Tik om gebruik en instellings te bekyk."</string>
    +     <string name="data_usage_3g_limit_title" msgid="4361523876818447683">"2G-3G-datalimiet bereik"</string>
    +     <string name="data_usage_4g_limit_title" msgid="4609566827219442376">"4G-datalimiet bereik"</string>
    +@@ -1636,6 +1648,7 @@
    +     <string name="search_language_hint" msgid="7042102592055108574">"Voer taalnaam in"</string>
    +     <string name="language_picker_section_suggested" msgid="8414489646861640885">"Voorgestel"</string>
    +     <string name="language_picker_section_all" msgid="3097279199511617537">"Alle tale"</string>
    ++    <string name="region_picker_section_all" msgid="8966316787153001779">"Allle streke"</string>
    +     <string name="locale_search_menu" msgid="2560710726687249178">"Soek"</string>
    +     <string name="work_mode_off_title" msgid="8954725060677558855">"Werkmodus is AF"</string>
    +     <string name="work_mode_off_message" msgid="3286169091278094476">"Stel werkprofiel in staat om te werk, insluitend programme, agtergrondsinkronisering en verwante kenmerke."</string>
    +diff --git a/core/res/res/values-am/strings.xml b/core/res/res/values-am/strings.xml
    +index 98fcebb..54bddc7 100644
    +--- a/core/res/res/values-am/strings.xml
    ++++ b/core/res/res/values-am/strings.xml
    +@@ -214,6 +214,7 @@
    +     <string name="global_actions" product="default" msgid="2406416831541615258">"የስልክ አማራጮች"</string>
    +     <string name="global_action_lock" msgid="2844945191792119712">"ማያ ቆልፍ"</string>
    +     <string name="global_action_power_off" msgid="4471879440839879722">"ኃይል አጥፋ"</string>
    ++    <string name="global_action_emergency" msgid="7112311161137421166">"ድንገተኛ አደጋ"</string>
    +     <string name="global_action_bug_report" msgid="7934010578922304799">"የሳንካ ሪፖርት"</string>
    +     <string name="bugreport_title" msgid="2667494803742548533">"የሳንካ ሪፖርት ውሰድ"</string>
    +     <string name="bugreport_message" msgid="398447048750350456">"ይሄ እንደ የኢሜይል መልዕክት አድርጎ የሚልከውን ስለመሣሪያዎ የአሁኑ ሁኔታ መረጃ ይሰበስባል። የሳንካ ሪፖርቱን ከመጀመር ጀምሮ እስኪላክ ድረስ ትንሽ ጊዜ ይወስዳል፤ እባክዎ ይታገሱ።"</string>
    +@@ -1076,6 +1077,17 @@
    +     <skip />
    +     <string name="wifi_no_internet" msgid="8451173622563841546">"Wi-Fi በይነመረብ መዳረሻ የለውም"</string>
    +     <string name="wifi_no_internet_detailed" msgid="8083079241212301741">"ለአማራጮች መታ ያድርጉ"</string>
    ++    <string name="network_switch_metered" msgid="4671730921726992671">"ወደ <xliff:g id="NETWORK_TYPE">%1$s</xliff:g> ተቀይሯል"</string>
    ++    <string name="network_switch_metered_detail" msgid="5325661434777870353">"<xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> ምንም ዓይነት የበይነመረብ ግንኙነት በማይኖረው ጊዜ መሣሪያዎች <xliff:g id="NEW_NETWORK">%1$s</xliff:g>ን ይጠቀማሉ። ክፍያዎች ተፈጻሚ ሊሆኑ ይችላሉ።"</string>
    ++    <string name="network_switch_metered_toast" msgid="5779283181685974304">"ከ<xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> ወደ <xliff:g id="NEW_NETWORK">%2$s</xliff:g> ተቀይሯል"</string>
    ++  <string-array name="network_switch_type_name">
    ++    <item msgid="2952042958050315394">"የተንቀሳቃሽ ስልክ ውሂብ"</item>
    ++    <item msgid="75483255295529161">"Wi-Fi"</item>
    ++    <item msgid="6862614801537202646">"ብሉቱዝ"</item>
    ++    <item msgid="5447331121797802871">"ኤተርኔት"</item>
    ++    <item msgid="8257233890381651999">"VPN"</item>
    ++  </string-array>
    ++    <string name="network_switch_type_name_unknown" msgid="4552612897806660656">"አንድ ያልታወቀ አውታረ መረብ ዓይነት"</string>
    +     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"ወደ Wi-Fi ለማያያዝ አልተቻለም"</string>
    +     <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" ደካማ የበይነመረብ ግንኙነት ኣለው።"</string>
    +     <string name="wifi_connect_alert_title" msgid="8455846016001810172">"ግንኙነት ይፈቀድ?"</string>
    +@@ -1153,7 +1165,6 @@
    +     <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"ቋንቋ እና አቀማመጥን ለመምረጥ መታ ያድርጉ"</string>
    +     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
    +     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
    +-    <string name="candidates_style" msgid="4333913089637062257"><u>"ዕጩዎች"</u></string>
    +     <string name="ext_media_checking_notification_title" msgid="5734005953288045806">"<xliff:g id="NAME">%s</xliff:g>ን በማዘጋጀት ላይ"</string>
    +     <string name="ext_media_checking_notification_message" msgid="4747432538578886744">"ስህተቶች ካሉ በመፈተሽ ላይ"</string>
    +     <string name="ext_media_new_notification_message" msgid="7589986898808506239">"አዲስ <xliff:g id="NAME">%s</xliff:g> ተገኝቷል"</string>
    +@@ -1232,8 +1243,9 @@
    +     <string name="vpn_text_long" msgid="4907843483284977618">"ለ<xliff:g id="SESSION">%s</xliff:g> የተገናኘ። አውታረመረቡን ለማደራጀት ሁለቴ ንካ።"</string>
    +     <string name="vpn_lockdown_connecting" msgid="6443438964440960745">"ሁልጊዜ የበራ VPN በመገናኘት ላይ…"</string>
    +     <string name="vpn_lockdown_connected" msgid="8202679674819213931">"ሁልጊዜ የበራ VPN ተገናኝቷል"</string>
    ++    <string name="vpn_lockdown_disconnected" msgid="4532298952570796327">"ሁልጊዜ የበራ የVPN ግንኙነት ተቋርጧል"</string>
    +     <string name="vpn_lockdown_error" msgid="6009249814034708175">"ሁልጊዜ የበራ VPN ስህተት"</string>
    +-    <string name="vpn_lockdown_config" msgid="4655589351146766608">"ለማዋቀር መታ ያድርጉ"</string>
    ++    <string name="vpn_lockdown_config" msgid="5099330695245008680">"ለማዋቀር መታ ያድርጉ"</string>
    +     <string name="upload_file" msgid="2897957172366730416">"ፋይል ምረጥ"</string>
    +     <string name="no_file_chosen" msgid="6363648562170759465">"ምንም ፋይል አልተመረጠም"</string>
    +     <string name="reset" msgid="2448168080964209908">"ዳግም አስጀምር"</string>
    +@@ -1317,7 +1329,7 @@
    +     <string name="storage_usb_drive_label" msgid="4501418548927759953">"የ<xliff:g id="MANUFACTURER">%s</xliff:g> ዩኤስቢ አንጻፊ"</string>
    +     <string name="storage_usb" msgid="3017954059538517278">"የUSB  ማከማቻ"</string>
    +     <string name="extract_edit_menu_button" msgid="8940478730496610137">"አርትዕ"</string>
    +-    <string name="data_usage_warning_title" msgid="1955638862122232342">"የውሂብ አጠቃቀም ማስጠንቀቂየ"</string>
    ++    <string name="data_usage_warning_title" msgid="3620440638180218181">"የውሂብ አጠቃቀም ማንቂያ"</string>
    +     <string name="data_usage_warning_body" msgid="6660692274311972007">"አጠቃቀምን እና ቅንብሮችን ለማየት መታ ያድርጉ።"</string>
    +     <string name="data_usage_3g_limit_title" msgid="4361523876818447683">"የ2ጂ-3ጂ ውሂብ ገደብ ላይ ተደርሷል"</string>
    +     <string name="data_usage_4g_limit_title" msgid="4609566827219442376">"የ4ጂ ውሂብ ገደብ ላይ ተደርሷል"</string>
    +@@ -1636,6 +1648,7 @@
    +     <string name="search_language_hint" msgid="7042102592055108574">"የቋንቋ ስም ይተይቡ"</string>
    +     <string name="language_picker_section_suggested" msgid="8414489646861640885">"የተጠቆሙ"</string>
    +     <string name="language_picker_section_all" msgid="3097279199511617537">"ሁሉም ቋንቋዎች"</string>
    ++    <string name="region_picker_section_all" msgid="8966316787153001779">"ሁሉም ክልሎች"</string>
    +     <string name="locale_search_menu" msgid="2560710726687249178">"ፈልግ"</string>
    +     <string name="work_mode_off_title" msgid="8954725060677558855">"የሥራ ሁነታ ጠፍቷል"</string>
    +     <string name="work_mode_off_message" msgid="3286169091278094476">"መተግበሪያዎችን፣ የበስተጀርባ ሥምረት እና ተዛማጅ ባሕሪዎችን ጨምሮ የሥራ መገለጫ እንዲሰራ ይፍቀዱ።"</string>
    +diff --git a/core/res/res/values-ar/strings.xml b/core/res/res/values-ar/strings.xml
    +index 32df247..493170b 100644
    +--- a/core/res/res/values-ar/strings.xml
    ++++ b/core/res/res/values-ar/strings.xml
    +@@ -222,6 +222,7 @@
    +     <string name="global_actions" product="default" msgid="2406416831541615258">"خيارات الهاتف"</string>
    +     <string name="global_action_lock" msgid="2844945191792119712">"تأمين الشاشة"</string>
    +     <string name="global_action_power_off" msgid="4471879440839879722">"إيقاف التشغيل"</string>
    ++    <string name="global_action_emergency" msgid="7112311161137421166">"الطوارئ"</string>
    +     <string name="global_action_bug_report" msgid="7934010578922304799">"تقرير الأخطاء"</string>
    +     <string name="bugreport_title" msgid="2667494803742548533">"إعداد تقرير بالأخطاء"</string>
    +     <string name="bugreport_message" msgid="398447048750350456">"سيجمع هذا معلومات حول حالة جهازك الحالي لإرسالها كرسالة إلكترونية، ولكنه سيستغرق وقتًا قليلاً من بدء عرض تقرير بالأخطاء. وحتى يكون جاهزًا للإرسال، الرجاء الانتظار."</string>
    +@@ -1045,7 +1046,7 @@
    +     <string name="editTextMenuTitle" msgid="4909135564941815494">"إجراءات النص"</string>
    +     <string name="low_internal_storage_view_title" msgid="5576272496365684834">"مساحة التخزين منخفضة"</string>
    +     <string name="low_internal_storage_view_text" msgid="6640505817617414371">"قد لا تعمل بعض وظائف النظام"</string>
    +-    <string name="low_internal_storage_view_text_no_boot" msgid="6935190099204693424">"ليست هناك سعة تخزينية كافية للنظام. تأكد من أنه لديك مساحة خالية تبلغ ۲۵۰ ميغابايت وأعد التشغيل."</string>
    ++    <string name="low_internal_storage_view_text_no_boot" msgid="6935190099204693424">"ليست هناك سعة تخزينية كافية للنظام. تأكد من أنه لديك مساحة خالية تبلغ ٢٥٠ ميغابايت وأعد التشغيل."</string>
    +     <string name="app_running_notification_title" msgid="8718335121060787914">"<xliff:g id="APP_NAME">%1$s</xliff:g> قيد التشغيل"</string>
    +     <string name="app_running_notification_text" msgid="1197581823314971177">"انقر للحصول على مزيد من المعلومات أو لإيقاف التطبيق."</string>
    +     <string name="ok" msgid="5970060430562524910">"موافق"</string>
    +@@ -1176,6 +1177,17 @@
    +     <skip />
    +     <string name="wifi_no_internet" msgid="8451173622563841546">"‏شبكة Wi-Fi غير متصلة بالإنترنت"</string>
    +     <string name="wifi_no_internet_detailed" msgid="8083079241212301741">"انقر للحصول على الخيارات."</string>
    ++    <string name="network_switch_metered" msgid="4671730921726992671">"تم التبديل إلى <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
    ++    <string name="network_switch_metered_detail" msgid="5325661434777870353">"يستخدم الجهاز <xliff:g id="NEW_NETWORK">%1$s</xliff:g> عندما لا يتوفر اتصال بالإنترنت في شبكة <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g>، ويمكن أن يتم فرض رسوم مقابل ذلك."</string>
    ++    <string name="network_switch_metered_toast" msgid="5779283181685974304">"تم التبديل من <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> إلى <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
    ++  <string-array name="network_switch_type_name">
    ++    <item msgid="2952042958050315394">"بيانات شبكة الجوّال"</item>
    ++    <item msgid="75483255295529161">"Wi-Fi"</item>
    ++    <item msgid="6862614801537202646">"بلوتوث"</item>
    ++    <item msgid="5447331121797802871">"إيثرنت"</item>
    ++    <item msgid="8257233890381651999">"‏شبكة ظاهرية خاصة (VPN)"</item>
    ++  </string-array>
    ++    <string name="network_switch_type_name_unknown" msgid="4552612897806660656">"نوع شبكة غير معروف"</string>
    +     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"‏تعذر الاتصال بـ Wi-Fi"</string>
    +     <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" لديها اتصال إنترنت رديء."</string>
    +     <string name="wifi_connect_alert_title" msgid="8455846016001810172">"هل تريد السماح بالاتصال؟"</string>
    +@@ -1253,7 +1265,6 @@
    +     <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"انقر لاختيار لغة وتنسيق"</string>
    +     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" أ ب ت ث ج ح خ د ذ ر ز س ش ص ض ط ظ ع غ ف ق ك ل م ن ه و ي"</string>
    +     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789 أ ب ت ث ج ح خ د ذ ر ز س ش ص ض ط ظ ع غ ف ق ك ل م ن ه و ي"</string>
    +-    <string name="candidates_style" msgid="4333913089637062257"><u>"العناصر المرشحة"</u></string>
    +     <string name="ext_media_checking_notification_title" msgid="5734005953288045806">"جارٍ تحضير <xliff:g id="NAME">%s</xliff:g>"</string>
    +     <string name="ext_media_checking_notification_message" msgid="4747432538578886744">"جارٍ التحقق من الأخطاء"</string>
    +     <string name="ext_media_new_notification_message" msgid="7589986898808506239">"تم اكتشاف <xliff:g id="NAME">%s</xliff:g> جديدة"</string>
    +@@ -1332,8 +1343,9 @@
    +     <string name="vpn_text_long" msgid="4907843483284977618">"تم الاتصال بـ <xliff:g id="SESSION">%s</xliff:g>. انقر لإدارة الشبكة."</string>
    +     <string name="vpn_lockdown_connecting" msgid="6443438964440960745">"‏جارٍ الاتصال بشبكة ظاهرية خاصة (VPN) دائمة التشغيل..."</string>
    +     <string name="vpn_lockdown_connected" msgid="8202679674819213931">"‏تم الاتصال بشبكة ظاهرية خاصة (VPN) دائمة التشغيل"</string>
    ++    <string name="vpn_lockdown_disconnected" msgid="4532298952570796327">"‏تم فصل الشبكة الظاهرية الخاصة (VPN) دائمة التشغيل"</string>
    +     <string name="vpn_lockdown_error" msgid="6009249814034708175">"‏خطأ بشبكة ظاهرية خاصة (VPN) دائمة التشغيل"</string>
    +-    <string name="vpn_lockdown_config" msgid="4655589351146766608">"انقر للتهيئة."</string>
    ++    <string name="vpn_lockdown_config" msgid="5099330695245008680">"انقر للإعداد."</string>
    +     <string name="upload_file" msgid="2897957172366730416">"اختيار ملف"</string>
    +     <string name="no_file_chosen" msgid="6363648562170759465">"لم يتم اختيار أي ملف"</string>
    +     <string name="reset" msgid="2448168080964209908">"إعادة تعيين"</string>
    +@@ -1421,7 +1433,7 @@
    +     <string name="storage_usb_drive_label" msgid="4501418548927759953">"‏محرك أقراص USB من <xliff:g id="MANUFACTURER">%s</xliff:g>"</string>
    +     <string name="storage_usb" msgid="3017954059538517278">"‏وحدة تخزين USB"</string>
    +     <string name="extract_edit_menu_button" msgid="8940478730496610137">"تعديل"</string>
    +-    <string name="data_usage_warning_title" msgid="1955638862122232342">"تحذير استخدام البيانات"</string>
    ++    <string name="data_usage_warning_title" msgid="3620440638180218181">"تنبيه استخدام البيانات"</string>
    +     <string name="data_usage_warning_body" msgid="6660692274311972007">"انقر لعرض الاستخدام والإعدادات."</string>
    +     <string name="data_usage_3g_limit_title" msgid="4361523876818447683">"‏تم بلوغ حد بيانات اتصال 2G-3G"</string>
    +     <string name="data_usage_4g_limit_title" msgid="4609566827219442376">"‏تم بلوغ حد بيانات اتصال 4G"</string>
    +@@ -1780,6 +1792,7 @@
    +     <string name="search_language_hint" msgid="7042102592055108574">"اكتب اسم اللغة"</string>
    +     <string name="language_picker_section_suggested" msgid="8414489646861640885">"المقترحة"</string>
    +     <string name="language_picker_section_all" msgid="3097279199511617537">"جميع اللغات"</string>
    ++    <string name="region_picker_section_all" msgid="8966316787153001779">"كل المناطق"</string>
    +     <string name="locale_search_menu" msgid="2560710726687249178">"البحث"</string>
    +     <string name="work_mode_off_title" msgid="8954725060677558855">"وضع العمل معطَّل"</string>
    +     <string name="work_mode_off_message" msgid="3286169091278094476">"السماح باستخدام الملف الشخصي للعمل، بما في ذلك التطبيقات ومزامنة الخلفية والميزات ذات الصلة."</string>
    +diff --git a/core/res/res/values-az-rAZ/strings.xml b/core/res/res/values-az-rAZ/strings.xml
    +index b1ed7dd..7c3f2a4 100644
    +--- a/core/res/res/values-az-rAZ/strings.xml
    ++++ b/core/res/res/values-az-rAZ/strings.xml
    +@@ -214,6 +214,7 @@
    +     <string name="global_actions" product="default" msgid="2406416831541615258">"Telefon seçimləri"</string>
    +     <string name="global_action_lock" msgid="2844945191792119712">"Ekran kilidi"</string>
    +     <string name="global_action_power_off" msgid="4471879440839879722">"Söndür"</string>
    ++    <string name="global_action_emergency" msgid="7112311161137421166">"Təcili"</string>
    +     <string name="global_action_bug_report" msgid="7934010578922304799">"Baq hesabatı"</string>
    +     <string name="bugreport_title" msgid="2667494803742548533">"Baqı xəbər verin"</string>
    +     <string name="bugreport_message" msgid="398447048750350456">"Bu, sizin hazırkı cihaz durumu haqqında məlumat toplayacaq ki, elektron məktub şəklində göndərsin. Baq raportuna başlamaq üçün bir az vaxt lazım ola bilər, bir az səbr edin."</string>
    +@@ -1076,6 +1077,17 @@
    +     <skip />
    +     <string name="wifi_no_internet" msgid="8451173622563841546">"Wi-Fi-ın İnternetə girişi yoxdur"</string>
    +     <string name="wifi_no_internet_detailed" msgid="8083079241212301741">"Seçimlər üçün tıklayın"</string>
    ++    <string name="network_switch_metered" msgid="4671730921726992671">"<xliff:g id="NETWORK_TYPE">%1$s</xliff:g> şəbəkə növünə keçirildi"</string>
    ++    <string name="network_switch_metered_detail" msgid="5325661434777870353">"<xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> şəbəkəsinin İnternetə çıxışı olmadıqda, cihaz <xliff:g id="NEW_NETWORK">%1$s</xliff:g> şəbəkəsini istifadə edir. Ödəniş tətbiq oluna bilər."</string>
    ++    <string name="network_switch_metered_toast" msgid="5779283181685974304">"<xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> şəbəkəsindən <xliff:g id="NEW_NETWORK">%2$s</xliff:g> şəbəkəsinə keçirildi"</string>
    ++  <string-array name="network_switch_type_name">
    ++    <item msgid="2952042958050315394">"mobil data"</item>
    ++    <item msgid="75483255295529161">"Wi-Fi"</item>
    ++    <item msgid="6862614801537202646">"Bluetooth"</item>
    ++    <item msgid="5447331121797802871">"Ethernet"</item>
    ++    <item msgid="8257233890381651999">"VPN"</item>
    ++  </string-array>
    ++    <string name="network_switch_type_name_unknown" msgid="4552612897806660656">"naməlum şəbəkə növü"</string>
    +     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Wi-Fi\'a qoşulmaq alınmadı"</string>
    +     <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" internet bağlantısı keyfiyyətsizdir."</string>
    +     <string name="wifi_connect_alert_title" msgid="8455846016001810172">"Bağlantıya icazə verilsin?"</string>
    +@@ -1153,7 +1165,6 @@
    +     <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"Dil və tərtibatı seçmək üçün tıklayın"</string>
    +     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCÇDEƏFGĞHXIİJKQLMNOÖPRSŞTUÜVYZ"</string>
    +     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCÇDEƏFGĞHİIJKLMNOÖPQRSŞTUÜVWXYZ"</string>
    +-    <string name="candidates_style" msgid="4333913089637062257"><u>"namizədlər"</u></string>
    +     <string name="ext_media_checking_notification_title" msgid="5734005953288045806">"<xliff:g id="NAME">%s</xliff:g> hazırlanır"</string>
    +     <string name="ext_media_checking_notification_message" msgid="4747432538578886744">"Səhvlər yoxlanılır"</string>
    +     <string name="ext_media_new_notification_message" msgid="7589986898808506239">"Yeni <xliff:g id="NAME">%s</xliff:g> aşkarlandı"</string>
    +@@ -1232,8 +1243,9 @@
    +     <string name="vpn_text_long" msgid="4907843483284977618">"<xliff:g id="SESSION">%s</xliff:g> sessiyaya qoşulun. Şəbəkəni idarə etmək üçün tıklayın."</string>
    +     <string name="vpn_lockdown_connecting" msgid="6443438964440960745">"Həmişə aktiv VPN bağlanır..."</string>
    +     <string name="vpn_lockdown_connected" msgid="8202679674819213931">"VPN bağlantısı həmişə aktiv"</string>
    ++    <string name="vpn_lockdown_disconnected" msgid="4532298952570796327">"Həmişə aktiv VPN bağlantısı kəsildi"</string>
    +     <string name="vpn_lockdown_error" msgid="6009249814034708175">"Həmişə aktiv VPN xətası"</string>
    +-    <string name="vpn_lockdown_config" msgid="4655589351146766608">"Konfiqurasiya üçün tıklayın"</string>
    ++    <string name="vpn_lockdown_config" msgid="5099330695245008680">"Quraşdırmaq üçün tıklayın"</string>
    +     <string name="upload_file" msgid="2897957172366730416">"Fayl seçin"</string>
    +     <string name="no_file_chosen" msgid="6363648562170759465">"Heç bir fayl seçilməyib"</string>
    +     <string name="reset" msgid="2448168080964209908">"Sıfırlayın"</string>
    +@@ -1317,7 +1329,7 @@
    +     <string name="storage_usb_drive_label" msgid="4501418548927759953">"<xliff:g id="MANUFACTURER">%s</xliff:g> USB drayv"</string>
    +     <string name="storage_usb" msgid="3017954059538517278">"USB yaddaş"</string>
    +     <string name="extract_edit_menu_button" msgid="8940478730496610137">"Düzəliş edin"</string>
    +-    <string name="data_usage_warning_title" msgid="1955638862122232342">"Data istifadə xəbərdarlığı"</string>
    ++    <string name="data_usage_warning_title" msgid="3620440638180218181">"Data istifadə siqnalı"</string>
    +     <string name="data_usage_warning_body" msgid="6660692274311972007">"İstifadə və ayarları görmək üçün tıklayın."</string>
    +     <string name="data_usage_3g_limit_title" msgid="4361523876818447683">"2G-3G data limitinə çatdı"</string>
    +     <string name="data_usage_4g_limit_title" msgid="4609566827219442376">"4G data limitinə çatdı"</string>
    +@@ -1636,6 +1648,7 @@
    +     <string name="search_language_hint" msgid="7042102592055108574">"Dil adını daxil edin"</string>
    +     <string name="language_picker_section_suggested" msgid="8414489646861640885">"Təklif edilmiş"</string>
    +     <string name="language_picker_section_all" msgid="3097279199511617537">"Bütün dillər"</string>
    ++    <string name="region_picker_section_all" msgid="8966316787153001779">"Bütün bölgələr"</string>
    +     <string name="locale_search_menu" msgid="2560710726687249178">"Axtarın"</string>
    +     <string name="work_mode_off_title" msgid="8954725060677558855">"İş rejimi DEAKTİVDİR"</string>
    +     <string name="work_mode_off_message" msgid="3286169091278094476">"Tətbiq, arxa fon sinxronizasiyası və digər əlaqədar xüsusiyyətlər daxil olmaqla iş profilinin fəaliyyətinə icazə verin."</string>
    +diff --git a/core/res/res/values-b+sr+Latn/strings.xml b/core/res/res/values-b+sr+Latn/strings.xml
    +index ad74e2e..50e1327 100644
    +--- a/core/res/res/values-b+sr+Latn/strings.xml
    ++++ b/core/res/res/values-b+sr+Latn/strings.xml
    +@@ -152,7 +152,7 @@
    +     <string name="httpErrorAuth" msgid="1435065629438044534">"Nije moguće potvrditi autentičnost."</string>
    +     <string name="httpErrorProxyAuth" msgid="1788207010559081331">"Potvrda identiteta preko proksi servera nije uspela."</string>
    +     <string name="httpErrorConnect" msgid="8714273236364640549">"Nije moguće povezati se sa serverom."</string>
    +-    <string name="httpErrorIO" msgid="2340558197489302188">"Nije moguće komunicirati sa serverom. Pokušajte ponovo kasnije."</string>
    ++    <string name="httpErrorIO" msgid="2340558197489302188">"Nije moguće komunicirati sa serverom. Probajte ponovo kasnije."</string>
    +     <string name="httpErrorTimeout" msgid="4743403703762883954">"Veza sa serverom je istekla."</string>
    +     <string name="httpErrorRedirectLoop" msgid="8679596090392779516">"Stranica sadrži previše veza za preusmeravanje sa servera."</string>
    +     <string name="httpErrorUnsupportedScheme" msgid="5015730812906192208">"Protokol nije podržan."</string>
    +@@ -160,7 +160,7 @@
    +     <string name="httpErrorBadUrl" msgid="3636929722728881972">"Stranicu nije moguće otvoriti zato što je URL adresa nevažeća."</string>
    +     <string name="httpErrorFile" msgid="2170788515052558676">"Nije moguće pristupiti datoteci."</string>
    +     <string name="httpErrorFileNotFound" msgid="6203856612042655084">"Nije moguće pronaći traženu datoteku."</string>
    +-    <string name="httpErrorTooManyRequests" msgid="1235396927087188253">"Previše zahteva se obrađuje. Pokušajte ponovo kasnije."</string>
    ++    <string name="httpErrorTooManyRequests" msgid="1235396927087188253">"Previše zahteva se obrađuje. Probajte ponovo kasnije."</string>
    +     <string name="notification_title" msgid="8967710025036163822">"Greška pri prijavljivanju za <xliff:g id="ACCOUNT">%1$s</xliff:g>"</string>
    +     <string name="contentServiceSync" msgid="8353523060269335667">"Sinhronizacija"</string>
    +     <string name="contentServiceSyncNotificationTitle" msgid="397743349191901458">"Sinhronizacija"</string>
    +@@ -216,6 +216,7 @@
    +     <string name="global_actions" product="default" msgid="2406416831541615258">"Opcije telefona"</string>
    +     <string name="global_action_lock" msgid="2844945191792119712">"Zaključaj ekran"</string>
    +     <string name="global_action_power_off" msgid="4471879440839879722">"Isključi"</string>
    ++    <string name="global_action_emergency" msgid="7112311161137421166">"Hitni poziv"</string>
    +     <string name="global_action_bug_report" msgid="7934010578922304799">"Izveštaj o grešci"</string>
    +     <string name="bugreport_title" msgid="2667494803742548533">"Napravi izveštaj o grešci"</string>
    +     <string name="bugreport_message" msgid="398447048750350456">"Ovim će se prikupiti informacije o trenutnom stanju uređaja kako bi bile poslate u poruci e-pošte. Od započinjanja izveštaja o grešci do trenutka za njegovo slanje proći će neko vreme; budite strpljivi."</string>
    +@@ -256,9 +257,9 @@
    +     <string name="permgrouplab_storage" msgid="1971118770546336966">"Skladište"</string>
    +     <string name="permgroupdesc_storage" msgid="637758554581589203">"pristupa slikama, medijima i datotekama na uređaju"</string>
    +     <string name="permgrouplab_microphone" msgid="171539900250043464">"Mikrofon"</string>
    +-    <string name="permgroupdesc_microphone" msgid="4988812113943554584">"snima audio snimke"</string>
    ++    <string name="permgroupdesc_microphone" msgid="4988812113943554584">"snima audio"</string>
    +     <string name="permgrouplab_camera" msgid="4820372495894586615">"Kamera"</string>
    +-    <string name="permgroupdesc_camera" msgid="3250611594678347720">"snima slike i video snimke"</string>
    ++    <string name="permgroupdesc_camera" msgid="3250611594678347720">"snima slike i video"</string>
    +     <string name="permgrouplab_phone" msgid="5229115638567440675">"Telefon"</string>
    +     <string name="permgroupdesc_phone" msgid="6234224354060641055">"upućuje telefonske pozive i upravlja njima"</string>
    +     <string name="permgrouplab_sensors" msgid="416037179223226722">"Senzori za telo"</string>
    +@@ -439,19 +440,19 @@
    +     <string name="permdesc_manageFingerprint" msgid="178208705828055464">"Dozvoljava aplikaciji da aktivira metode za dodavanje i brisanje šablona otisaka prstiju koji će se koristiti."</string>
    +     <string name="permlab_useFingerprint" msgid="3150478619915124905">"koristi hardver za otiske prstiju"</string>
    +     <string name="permdesc_useFingerprint" msgid="9165097460730684114">"Dozvoljava aplikaciji da koristi hardver za otiske prstiju radi potvrde autentičnosti"</string>
    +-    <string name="fingerprint_acquired_partial" msgid="735082772341716043">"Otkriven je delimični otisak prsta. Pokušajte ponovo."</string>
    +-    <string name="fingerprint_acquired_insufficient" msgid="4596546021310923214">"Nije uspela obrada otiska prsta. Pokušajte ponovo."</string>
    ++    <string name="fingerprint_acquired_partial" msgid="735082772341716043">"Otkriven je delimični otisak prsta. Probajte ponovo."</string>
    ++    <string name="fingerprint_acquired_insufficient" msgid="4596546021310923214">"Nije uspela obrada otiska prsta. Probajte ponovo."</string>
    +     <string name="fingerprint_acquired_imager_dirty" msgid="1087209702421076105">"Senzor za otiske prstiju je prljav. Očistite ga i pokušajte ponovo."</string>
    +-    <string name="fingerprint_acquired_too_fast" msgid="6470642383109155969">"Prebrzo ste pomerili prst. Pokušajte ponovo."</string>
    +-    <string name="fingerprint_acquired_too_slow" msgid="59250885689661653">"Previše sporo ste pomerili prst. Pokušajte ponovo."</string>
    ++    <string name="fingerprint_acquired_too_fast" msgid="6470642383109155969">"Prebrzo ste pomerili prst. Probajte ponovo."</string>
    ++    <string name="fingerprint_acquired_too_slow" msgid="59250885689661653">"Previše sporo ste pomerili prst. Probajte ponovo."</string>
    +   <string-array name="fingerprint_acquired_vendor">
    +   </string-array>
    +     <string name="fingerprint_error_hw_not_available" msgid="7955921658939936596">"Hardver za otiske prstiju nije dostupan."</string>
    +     <string name="fingerprint_error_no_space" msgid="1055819001126053318">"Nije moguće sačuvati otisak prsta. Uklonite neki od postojećih otisaka prstiju."</string>
    +-    <string name="fingerprint_error_timeout" msgid="3927186043737732875">"Vremensko ograničenje za otisak prsta je isteklo. Pokušajte ponovo."</string>
    ++    <string name="fingerprint_error_timeout" msgid="3927186043737732875">"Vremensko ograničenje za otisak prsta je isteklo. Probajte ponovo."</string>
    +     <string name="fingerprint_error_canceled" msgid="4402024612660774395">"Radnja sa otiskom prsta je otkazana."</string>
    +-    <string name="fingerprint_error_lockout" msgid="5536934748136933450">"Previše pokušaja. Pokušajte ponovo kasnije."</string>
    +-    <string name="fingerprint_error_unable_to_process" msgid="6107816084103552441">"Pokušajte ponovo."</string>
    ++    <string name="fingerprint_error_lockout" msgid="5536934748136933450">"Previše pokušaja. Probajte ponovo kasnije."</string>
    ++    <string name="fingerprint_error_unable_to_process" msgid="6107816084103552441">"Probajte ponovo."</string>
    +     <string name="fingerprint_name_template" msgid="5870957565512716938">"Prst <xliff:g id="FINGERID">%d</xliff:g>"</string>
    +   <string-array name="fingerprint_error_vendor">
    +   </string-array>
    +@@ -679,8 +680,8 @@
    +     <string name="lockscreen_emergency_call" msgid="5298642613417801888">"Hitne službe"</string>
    +     <string name="lockscreen_return_to_call" msgid="5244259785500040021">"Nazad na poziv"</string>
    +     <string name="lockscreen_pattern_correct" msgid="9039008650362261237">"Tačno!"</string>
    +-    <string name="lockscreen_pattern_wrong" msgid="4317955014948108794">"Pokušajte ponovo"</string>
    +-    <string name="lockscreen_password_wrong" msgid="5737815393253165301">"Pokušajte ponovo"</string>
    ++    <string name="lockscreen_pattern_wrong" msgid="4317955014948108794">"Probajte ponovo"</string>
    ++    <string name="lockscreen_password_wrong" msgid="5737815393253165301">"Probajte ponovo"</string>
    +     <string name="lockscreen_storage_locked" msgid="9167551160010625200">"Otključaj za sve funkcije i podatke"</string>
    +     <string name="faceunlock_multiple_failures" msgid="754137583022792429">"Premašen je najveći dozvoljeni broj pokušaja Otključavanja licem"</string>
    +     <string name="lockscreen_missing_sim_message_short" msgid="5099439277819215399">"Nema SIM kartice"</string>
    +@@ -704,19 +705,19 @@
    +     <string name="lockscreen_sim_puk_locked_instructions" msgid="8127916255245181063">"Pogledajte Korisnički vodič ili kontaktirajte Korisničku podršku."</string>
    +     <string name="lockscreen_sim_locked_message" msgid="8066660129206001039">"SIM kartica je zaključana."</string>
    +     <string name="lockscreen_sim_unlock_progress_dialog_message" msgid="595323214052881264">"Otključavanje SIM kartice…"</string>
    +-    <string name="lockscreen_too_many_failed_attempts_dialog_message" msgid="6481623830344107222">"<xliff:g id="NUMBER_0">%1$d</xliff:g> puta ste nepravilno nacrtali šablon za otključavanje. \n\nPokušajte ponovo za <xliff:g id="NUMBER_1">%2$d</xliff:g> sekunde(i)."</string>
    +-    <string name="lockscreen_too_many_failed_password_attempts_dialog_message" msgid="2725973286239344555">"<xliff:g id="NUMBER_0">%1$d</xliff:g> puta ste pogrešno uneli lozinku. \n\nPokušajte ponovo za <xliff:g id="NUMBER_1">%2$d</xliff:g> sekunde(i)."</string>
    +-    <string name="lockscreen_too_many_failed_pin_attempts_dialog_message" msgid="6216672706545696955">"<xliff:g id="NUMBER_0">%1$d</xliff:g> puta ste pogrešno uneli PIN. \n\nPokušajte ponovo za <xliff:g id="NUMBER_1">%2$d</xliff:g> sekunde(i)."</string>
    +-    <string name="lockscreen_failed_attempts_almost_glogin" product="tablet" msgid="9191611984625460820">"<xliff:g id="NUMBER_0">%1$d</xliff:g> puta ste netačno uneli šablon za otključavanje. Nakon još <xliff:g id="NUMBER_1">%2$d</xliff:g> nesupešna(ih) pokušaja, od vas će biti zatraženo da otključate tablet pomoću podataka za prijavljivanje na Google.\n\n Pokušajte ponovo za <xliff:g id="NUMBER_2">%3$d</xliff:g> sekunde(i)."</string>
    +-    <string name="lockscreen_failed_attempts_almost_glogin" product="tv" msgid="5316664559603394684">"Neispravno ste nacrtali šablon za otključavanje <xliff:g id="NUMBER_0">%1$d</xliff:g> puta. Posle još <xliff:g id="NUMBER_1">%2$d</xliff:g> neuspešna(ih) pokušaja od vas će biti zatraženo da otključate TV pomoću podataka za prijavljivanje na Google.\n\n Pokušajte ponovo za <xliff:g id="NUMBER_2">%3$d</xliff:g> sek."</string>
    +-    <string name="lockscreen_failed_attempts_almost_glogin" product="default" msgid="2590227559763762751">"<xliff:g id="NUMBER_0">%1$d</xliff:g> puta ste netačno uneli šablon za otključavanje. Nakon još <xliff:g id="NUMBER_1">%2$d</xliff:g> nesupešna(ih) pokušaja, od vas će biti zatraženo da otključate telefon pomoću podataka za prijavljivanje na Google.\n\n Pokušajte ponovo za <xliff:g id="NUMBER_2">%3$d</xliff:g> sekunde(i)."</string>
    ++    <string name="lockscreen_too_many_failed_attempts_dialog_message" msgid="6481623830344107222">"<xliff:g id="NUMBER_0">%1$d</xliff:g> puta ste nepravilno nacrtali šablon za otključavanje. \n\nProbajte ponovo za <xliff:g id="NUMBER_1">%2$d</xliff:g> sekunde(i)."</string>
    ++    <string name="lockscreen_too_many_failed_password_attempts_dialog_message" msgid="2725973286239344555">"<xliff:g id="NUMBER_0">%1$d</xliff:g> puta ste pogrešno uneli lozinku. \n\nProbajte ponovo za <xliff:g id="NUMBER_1">%2$d</xliff:g> sekunde(i)."</string>
    ++    <string name="lockscreen_too_many_failed_pin_attempts_dialog_message" msgid="6216672706545696955">"<xliff:g id="NUMBER_0">%1$d</xliff:g> puta ste pogrešno uneli PIN. \n\nProbajte ponovo za <xliff:g id="NUMBER_1">%2$d</xliff:g> sekunde(i)."</string>
    ++    <string name="lockscreen_failed_attempts_almost_glogin" product="tablet" msgid="9191611984625460820">"<xliff:g id="NUMBER_0">%1$d</xliff:g> puta ste netačno uneli šablon za otključavanje. Nakon još <xliff:g id="NUMBER_1">%2$d</xliff:g> nesupešna(ih) pokušaja, od vas će biti zatraženo da otključate tablet pomoću podataka za prijavljivanje na Google.\n\n Probajte ponovo za <xliff:g id="NUMBER_2">%3$d</xliff:g> sekunde(i)."</string>
    ++    <string name="lockscreen_failed_attempts_almost_glogin" product="tv" msgid="5316664559603394684">"Neispravno ste nacrtali šablon za otključavanje <xliff:g id="NUMBER_0">%1$d</xliff:g> puta. Posle još <xliff:g id="NUMBER_1">%2$d</xliff:g> neuspešna(ih) pokušaja od vas će biti zatraženo da otključate TV pomoću podataka za prijavljivanje na Google.\n\n Probajte ponovo za <xliff:g id="NUMBER_2">%3$d</xliff:g> sek."</string>
    ++    <string name="lockscreen_failed_attempts_almost_glogin" product="default" msgid="2590227559763762751">"<xliff:g id="NUMBER_0">%1$d</xliff:g> puta ste netačno uneli šablon za otključavanje. Nakon još <xliff:g id="NUMBER_1">%2$d</xliff:g> nesupešna(ih) pokušaja, od vas će biti zatraženo da otključate telefon pomoću podataka za prijavljivanje na Google.\n\n Probajte ponovo za <xliff:g id="NUMBER_2">%3$d</xliff:g> sekunde(i)."</string>
    +     <string name="lockscreen_failed_attempts_almost_at_wipe" product="tablet" msgid="6128106399745755604">"Nepravilno ste pokušali da otključate tablet <xliff:g id="NUMBER_0">%1$d</xliff:g> puta. Nakon još neuspešnih pokušaja (<xliff:g id="NUMBER_1">%2$d</xliff:g>) tablet će biti resetovan na fabrička podešavanja i svi korisnički podaci će biti izgubljeni."</string>
    +     <string name="lockscreen_failed_attempts_almost_at_wipe" product="tv" msgid="950408382418270260">"Pokušali ste da otključate TV netačno <xliff:g id="NUMBER_0">%1$d</xliff:g> puta. Posle još <xliff:g id="NUMBER_1">%2$d</xliff:g> neuspešna(ih) pokušaja TV će biti resetovan na podrazumevana fabrička podešavanja i svi korisnički podaci će biti izgubljeni."</string>
    +     <string name="lockscreen_failed_attempts_almost_at_wipe" product="default" msgid="8603565142156826565">"Neispravno ste pokušali da otključate telefon <xliff:g id="NUMBER_0">%1$d</xliff:g> puta. Nakon još neuspešnih pokušaja (<xliff:g id="NUMBER_1">%2$d</xliff:g>) telefon će biti resetovan na fabrička podešavanja i svi korisnički podaci će biti izgubljeni."</string>
    +     <string name="lockscreen_failed_attempts_now_wiping" product="tablet" msgid="280873516493934365">"Neispravno ste pokušali da otključate tablet <xliff:g id="NUMBER">%d</xliff:g> puta. Tablet će sada biti vraćen na podrazumevana fabrička podešavanja."</string>
    +     <string name="lockscreen_failed_attempts_now_wiping" product="tv" msgid="3195755534096192191">"Pokušali ste da otključate TV netačno <xliff:g id="NUMBER">%d</xliff:g> puta. TV će sada biti resetovan na podrazumevana fabrička podešavanja."</string>
    +     <string name="lockscreen_failed_attempts_now_wiping" product="default" msgid="3025504721764922246">"Neispravno ste pokušali da otključate telefon <xliff:g id="NUMBER">%d</xliff:g> puta. Telefon će sada biti vraćen na podrazumevana fabrička podešavanja."</string>
    +-    <string name="lockscreen_too_many_failed_attempts_countdown" msgid="6251480343394389665">"Pokušajte ponovo za <xliff:g id="NUMBER">%d</xliff:g> sekunde(i)."</string>
    ++    <string name="lockscreen_too_many_failed_attempts_countdown" msgid="6251480343394389665">"Probajte ponovo za <xliff:g id="NUMBER">%d</xliff:g> sekunde(i)."</string>
    +     <string name="lockscreen_forgot_pattern_button_text" msgid="2626999449610695930">"Zaboravili ste šablon?"</string>
    +     <string name="lockscreen_glogin_forgot_pattern" msgid="2588521501166032747">"Otključavanje naloga"</string>
    +     <string name="lockscreen_glogin_too_many_attempts" msgid="2751368605287288808">"Previše pokušaja unosa šablona"</string>
    +@@ -1101,6 +1102,17 @@
    +     <skip />
    +     <string name="wifi_no_internet" msgid="8451173622563841546">"Wi-Fi nema pristup internetu"</string>
    +     <string name="wifi_no_internet_detailed" msgid="8083079241212301741">"Dodirnite za opcije"</string>
    ++    <string name="network_switch_metered" msgid="4671730921726992671">"Prešli ste na tip mreže <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
    ++    <string name="network_switch_metered_detail" msgid="5325661434777870353">"Uređaj koristi tip mreže <xliff:g id="NEW_NETWORK">%1$s</xliff:g> kada tip mreže <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> nema pristup internetu. Možda će se naplaćivati troškovi."</string>
    ++    <string name="network_switch_metered_toast" msgid="5779283181685974304">"Prešli ste sa tipa mreže <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> na tip mreže <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
    ++  <string-array name="network_switch_type_name">
    ++    <item msgid="2952042958050315394">"mobilni podaci"</item>
    ++    <item msgid="75483255295529161">"Wi-Fi"</item>
    ++    <item msgid="6862614801537202646">"Bluetooth"</item>
    ++    <item msgid="5447331121797802871">"Eternet"</item>
    ++    <item msgid="8257233890381651999">"VPN"</item>
    ++  </string-array>
    ++    <string name="network_switch_type_name_unknown" msgid="4552612897806660656">"nepoznat tip mreže"</string>
    +     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Nije moguće povezati sa Wi-Fi mrežom"</string>
    +     <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" ima lošu internet vezu."</string>
    +     <string name="wifi_connect_alert_title" msgid="8455846016001810172">"Želite li da dozvolite povezivanje?"</string>
    +@@ -1172,13 +1184,12 @@
    +     <string name="share_remote_bugreport_action" msgid="6249476773913384948">"DELI"</string>
    +     <string name="decline_remote_bugreport_action" msgid="6230987241608770062">"ODBIJ"</string>
    +     <string name="select_input_method" msgid="8547250819326693584">"Promenite tastaturu"</string>
    +-    <string name="show_ime" msgid="2506087537466597099">"Zadrži ga na ekranu dok je fizička tastatura aktivna"</string>
    ++    <string name="show_ime" msgid="2506087537466597099">"Zadrži je na ekranu dok je fizička tastatura aktivna"</string>
    +     <string name="hardware" msgid="194658061510127999">"Prikaži virtuelnu tastaturu"</string>
    +     <string name="select_keyboard_layout_notification_title" msgid="597189518763083494">"Konfigurišite fizičku tastaturu"</string>
    +     <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"Dodirnite da biste izabrali jezik i raspored"</string>
    +     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
    +     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
    +-    <string name="candidates_style" msgid="4333913089637062257"><u>"kandidati"</u></string>
    +     <string name="ext_media_checking_notification_title" msgid="5734005953288045806">"<xliff:g id="NAME">%s</xliff:g> se priprema"</string>
    +     <string name="ext_media_checking_notification_message" msgid="4747432538578886744">"Proverava se da li postoje greške"</string>
    +     <string name="ext_media_new_notification_message" msgid="7589986898808506239">"Novi uređaj <xliff:g id="NAME">%s</xliff:g> je otkriven"</string>
    +@@ -1257,8 +1268,9 @@
    +     <string name="vpn_text_long" msgid="4907843483284977618">"Povezano sa sesijom <xliff:g id="SESSION">%s</xliff:g>. Dodirnite da biste upravljali mrežom."</string>
    +     <string name="vpn_lockdown_connecting" msgid="6443438964440960745">"Povezivanje stalno uključenog VPN-a..."</string>
    +     <string name="vpn_lockdown_connected" msgid="8202679674819213931">"Stalno uključeni VPN je povezan"</string>
    ++    <string name="vpn_lockdown_disconnected" msgid="4532298952570796327">"Veza sa stalno uključenim VPN-om je prekinuta"</string>
    +     <string name="vpn_lockdown_error" msgid="6009249814034708175">"Greška stalno uključenog VPN-a"</string>
    +-    <string name="vpn_lockdown_config" msgid="4655589351146766608">"Dodirnite da biste konfigurisali"</string>
    ++    <string name="vpn_lockdown_config" msgid="5099330695245008680">"Dodirnite da biste podesili"</string>
    +     <string name="upload_file" msgid="2897957172366730416">"Odaberi datoteku"</string>
    +     <string name="no_file_chosen" msgid="6363648562170759465">"Nije izabrana nijedna datoteka"</string>
    +     <string name="reset" msgid="2448168080964209908">"Ponovo postavi"</string>
    +@@ -1343,7 +1355,7 @@
    +     <string name="storage_usb_drive_label" msgid="4501418548927759953">"<xliff:g id="MANUFACTURER">%s</xliff:g> USB disk"</string>
    +     <string name="storage_usb" msgid="3017954059538517278">"USB memorija"</string>
    +     <string name="extract_edit_menu_button" msgid="8940478730496610137">"Izmeni"</string>
    +-    <string name="data_usage_warning_title" msgid="1955638862122232342">"Upozorenje o potrošnji podataka"</string>
    ++    <string name="data_usage_warning_title" msgid="3620440638180218181">"Obaveštenje o potrošnji podataka"</string>
    +     <string name="data_usage_warning_body" msgid="6660692274311972007">"Dodirnite za potrošnju i podešavanja."</string>
    +     <string name="data_usage_3g_limit_title" msgid="4361523876818447683">"Nema više 2G-3G podataka"</string>
    +     <string name="data_usage_4g_limit_title" msgid="4609566827219442376">"Nema više 4G podataka"</string>
    +@@ -1409,7 +1421,7 @@
    +     <string name="kg_wrong_pattern" msgid="1850806070801358830">"Pogrešan šablon"</string>
    +     <string name="kg_wrong_password" msgid="2333281762128113157">"Pogrešna lozinka"</string>
    +     <string name="kg_wrong_pin" msgid="1131306510833563801">"Pogrešan PIN"</string>
    +-    <string name="kg_too_many_failed_attempts_countdown" msgid="6358110221603297548">"Pokušajte ponovo za <xliff:g id="NUMBER">%1$d</xliff:g> sekunde(i)."</string>
    ++    <string name="kg_too_many_failed_attempts_countdown" msgid="6358110221603297548">"Probajte ponovo za <xliff:g id="NUMBER">%1$d</xliff:g> sekunde(i)."</string>
    +     <string name="kg_pattern_instructions" msgid="398978611683075868">"Nacrtajte šablon"</string>
    +     <string name="kg_sim_pin_instructions" msgid="2319508550934557331">"Unesite PIN SIM kartice"</string>
    +     <string name="kg_pin_instructions" msgid="2377242233495111557">"Unesite PIN"</string>
    +@@ -1431,18 +1443,18 @@
    +     <string name="kg_login_invalid_input" msgid="5754664119319872197">"Nevažeće korisničko ime ili lozinka."</string>
    +     <string name="kg_login_account_recovery_hint" msgid="5690709132841752974">"Zaboravili ste korisničko ime ili lozinku?\nPosetite adresu "<b>"google.com/accounts/recovery"</b>"."</string>
    +     <string name="kg_login_checking_password" msgid="1052685197710252395">"Provera naloga…"</string>
    +-    <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"Uneli ste netačni PIN <xliff:g id="NUMBER_0">%1$d</xliff:g> puta. \n\nPokušajte ponovo za <xliff:g id="NUMBER_1">%2$d</xliff:g> sekunde(i)."</string>
    +-    <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"Uneli ste netačnu lozinku <xliff:g id="NUMBER_0">%1$d</xliff:g> puta. \n\nPokušajte ponovo za <xliff:g id="NUMBER_1">%2$d</xliff:g> sekunde(i)."</string>
    +-    <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"Nacrtali ste šablon za otključavanje netačno <xliff:g id="NUMBER_0">%1$d</xliff:g> puta. \n\nPokušajte ponovo za <xliff:g id="NUMBER_1">%2$d</xliff:g> sekunde(i)."</string>
    ++    <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"Uneli ste netačni PIN <xliff:g id="NUMBER_0">%1$d</xliff:g> puta. \n\nProbajte ponovo za <xliff:g id="NUMBER_1">%2$d</xliff:g> sekunde(i)."</string>
    ++    <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"Uneli ste netačnu lozinku <xliff:g id="NUMBER_0">%1$d</xliff:g> puta. \n\nProbajte ponovo za <xliff:g id="NUMBER_1">%2$d</xliff:g> sekunde(i)."</string>
    ++    <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"Nacrtali ste šablon za otključavanje netačno <xliff:g id="NUMBER_0">%1$d</xliff:g> puta. \n\nProbajte ponovo za <xliff:g id="NUMBER_1">%2$d</xliff:g> sekunde(i)."</string>
    +     <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="1575557200627128949">"Pokušali ste da otključate tablet netačno <xliff:g id="NUMBER_0">%1$d</xliff:g> puta. Nakon još <xliff:g id="NUMBER_1">%2$d</xliff:g> neuspešna(ih) pokušaja tablet će biti resetovan na fabrička podešavanja i svi korisnički podaci će biti izgubljeni."</string>
    +     <string name="kg_failed_attempts_almost_at_wipe" product="tv" msgid="5621231220154419413">"Pokušali ste da otključate TV netačno <xliff:g id="NUMBER_0">%1$d</xliff:g> puta. Posle još <xliff:g id="NUMBER_1">%2$d</xliff:g> neuspešna(ih) pokušaja TV će biti resetovan na podrazumevana fabrička podešavanja i svi korisnički podaci će biti izgubljeni."</string>
    +     <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4051015943038199910">"Pokušali ste da otključate telefon netačno <xliff:g id="NUMBER_0">%1$d</xliff:g> puta. Posle još <xliff:g id="NUMBER_1">%2$d</xliff:g> neuspešna(ih) pokušaja telefon će biti resetovan na fabrička podešavanja i svi korisnički podaci će biti izgubljeni."</string>
    +     <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="2072996269148483637">"Pokušali ste da otključate tablet netačno <xliff:g id="NUMBER">%d</xliff:g> puta. Tablet će sada biti vraćen na podrazumevana fabrička podešavanja."</string>
    +     <string name="kg_failed_attempts_now_wiping" product="tv" msgid="4987878286750741463">"Pokušali ste da otključate TV netačno <xliff:g id="NUMBER">%d</xliff:g> puta. TV će sada biti resetovan na podrazumevana fabrička podešavanja."</string>
    +     <string name="kg_failed_attempts_now_wiping" product="default" msgid="4817627474419471518">"Pokušali ste da otključate telefon netačno <xliff:g id="NUMBER">%d</xliff:g> puta. Telefon će sada biti vraćen na podrazumevana fabrička podešavanja."</string>
    +-    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"Nacrtali ste šablon za otključavanje netačno <xliff:g id="NUMBER_0">%1$d</xliff:g> puta. Posle još <xliff:g id="NUMBER_1">%2$d</xliff:g> neuspešna(ih) pokušaja, od vas će biti zatraženo da otključate tablet pomoću naloga e-pošte.\n\nPokušajte ponovo za <xliff:g id="NUMBER_2">%3$d</xliff:g> sekunde(i)."</string>
    +-    <string name="kg_failed_attempts_almost_at_login" product="tv" msgid="4224651132862313471">"Neispravno ste nacrtali šablon za otključavanje <xliff:g id="NUMBER_0">%1$d</xliff:g> puta. Posle još <xliff:g id="NUMBER_1">%2$d</xliff:g> neuspešna(ih) pokušaja, od vas će biti zatraženo da otključate TV pomoću naloga e-pošte.\n\n Pokušajte ponovo za <xliff:g id="NUMBER_2">%3$d</xliff:g> sek."</string>
    +-    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Nacrtali ste šablon za otključavanje netačno <xliff:g id="NUMBER_0">%1$d</xliff:g> puta. Posle još <xliff:g id="NUMBER_1">%2$d</xliff:g> neuspešna(ih) pokušaja, od vas će biti zatraženo da otključate telefon pomoću naloga e-pošte.\n\nPokušajte ponovo za <xliff:g id="NUMBER_2">%3$d</xliff:g> sekunde(i)."</string>
    ++    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"Nacrtali ste šablon za otključavanje netačno <xliff:g id="NUMBER_0">%1$d</xliff:g> puta. Posle još <xliff:g id="NUMBER_1">%2$d</xliff:g> neuspešna(ih) pokušaja, od vas će biti zatraženo da otključate tablet pomoću naloga e-pošte.\n\nProbajte ponovo za <xliff:g id="NUMBER_2">%3$d</xliff:g> sekunde(i)."</string>
    ++    <string name="kg_failed_attempts_almost_at_login" product="tv" msgid="4224651132862313471">"Neispravno ste nacrtali šablon za otključavanje <xliff:g id="NUMBER_0">%1$d</xliff:g> puta. Posle još <xliff:g id="NUMBER_1">%2$d</xliff:g> neuspešna(ih) pokušaja, od vas će biti zatraženo da otključate TV pomoću naloga e-pošte.\n\n Probajte ponovo za <xliff:g id="NUMBER_2">%3$d</xliff:g> sek."</string>
    ++    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Nacrtali ste šablon za otključavanje netačno <xliff:g id="NUMBER_0">%1$d</xliff:g> puta. Posle još <xliff:g id="NUMBER_1">%2$d</xliff:g> neuspešna(ih) pokušaja, od vas će biti zatraženo da otključate telefon pomoću naloga e-pošte.\n\nProbajte ponovo za <xliff:g id="NUMBER_2">%3$d</xliff:g> sekunde(i)."</string>
    +     <string name="kg_text_message_separator" product="default" msgid="4160700433287233771">" – "</string>
    +     <string name="kg_reordering_delete_drop_target_text" msgid="7899202978204438708">"Ukloni"</string>
    +     <string name="safe_media_volume_warning" product="default" msgid="2276318909314492312">"Želite da pojačate zvuk iznad preporučenog nivoa?\n\nSlušanje glasne muzike duže vreme može da vam ošteti sluh."</string>
    +@@ -1553,14 +1565,14 @@
    +     <string name="restr_pin_enter_new_pin" msgid="5959606691619959184">"Novi PIN"</string>
    +     <string name="restr_pin_confirm_pin" msgid="8501523829633146239">"Potvrdite novi PIN"</string>
    +     <string name="restr_pin_create_pin" msgid="8017600000263450337">"Napravite PIN za izmenu ograničenja"</string>
    +-    <string name="restr_pin_error_doesnt_match" msgid="2224214190906994548">"PIN-ovi se ne podudaraju. Pokušajte ponovo."</string>
    ++    <string name="restr_pin_error_doesnt_match" msgid="2224214190906994548">"PIN-ovi se ne podudaraju. Probajte ponovo."</string>
    +     <string name="restr_pin_error_too_short" msgid="8173982756265777792">"PIN je prekratak. Mora da sadrži najmanje 4 cifre."</string>
    +     <plurals name="restr_pin_countdown" formatted="false" msgid="9061246974881224688">
    +-      <item quantity="one">Pokušajte ponovo za <xliff:g id="COUNT">%d</xliff:g> sekundu</item>
    +-      <item quantity="few">Pokušajte ponovo za <xliff:g id="COUNT">%d</xliff:g> sekunde</item>
    +-      <item quantity="other">Pokušajte ponovo za <xliff:g id="COUNT">%d</xliff:g> sekundi</item>
    ++      <item quantity="one">Probajte ponovo za <xliff:g id="COUNT">%d</xliff:g> sekundu</item>
    ++      <item quantity="few">Probajte ponovo za <xliff:g id="COUNT">%d</xliff:g> sekunde</item>
    ++      <item quantity="other">Probajte ponovo za <xliff:g id="COUNT">%d</xliff:g> sekundi</item>
    +     </plurals>
    +-    <string name="restr_pin_try_later" msgid="973144472490532377">"Pokušajte ponovo kasnije"</string>
    ++    <string name="restr_pin_try_later" msgid="973144472490532377">"Probajte ponovo kasnije"</string>
    +     <string name="immersive_cling_title" msgid="8394201622932303336">"Prikazuje se ceo ekran"</string>
    +     <string name="immersive_cling_description" msgid="3482371193207536040">"Da biste izašli, prevucite nadole odozgo."</string>
    +     <string name="immersive_cling_positive" msgid="5016839404568297683">"Važi"</string>
    +@@ -1672,6 +1684,7 @@
    +     <string name="search_language_hint" msgid="7042102592055108574">"Unesite naziv jezika"</string>
    +     <string name="language_picker_section_suggested" msgid="8414489646861640885">"Predloženi"</string>
    +     <string name="language_picker_section_all" msgid="3097279199511617537">"Svi jezici"</string>
    ++    <string name="region_picker_section_all" msgid="8966316787153001779">"Svi regioni"</string>
    +     <string name="locale_search_menu" msgid="2560710726687249178">"Pretraži"</string>
    +     <string name="work_mode_off_title" msgid="8954725060677558855">"Režim za Work je ISKLJUČEN"</string>
    +     <string name="work_mode_off_message" msgid="3286169091278094476">"Dozvoljava profilu za Work da funkcioniše, uključujući aplikacije, sinhronizaciju u pozadini i srodne funkcije."</string>
    +diff --git a/core/res/res/values-be-rBY/strings.xml b/core/res/res/values-be-rBY/strings.xml
    +index 237820c..cadc0bc 100644
    +--- a/core/res/res/values-be-rBY/strings.xml
    ++++ b/core/res/res/values-be-rBY/strings.xml
    +@@ -218,6 +218,7 @@
    +     <string name="global_actions" product="default" msgid="2406416831541615258">"Параметры тэлефона"</string>
    +     <string name="global_action_lock" msgid="2844945191792119712">"Блакіроўка экрана"</string>
    +     <string name="global_action_power_off" msgid="4471879440839879722">"Выключыць"</string>
    ++    <string name="global_action_emergency" msgid="7112311161137421166">"SOS-выклік"</string>
    +     <string name="global_action_bug_report" msgid="7934010578922304799">"Справаздача пра памылкі"</string>
    +     <string name="bugreport_title" msgid="2667494803742548533">"Справаздача пра памылку"</string>
    +     <string name="bugreport_message" msgid="398447048750350456">"Будзе збiрацца iнфармацыя пра бягучы стан прылады, якая будзе адпраўляцца на электронную пошту. Стварэнне справаздачы пра памылкi зойме некаторы час."</string>
    +@@ -1126,6 +1127,17 @@
    +     <skip />
    +     <string name="wifi_no_internet" msgid="8451173622563841546">"У Wi-Fi няма доступу да Інтэрнэту"</string>
    +     <string name="wifi_no_internet_detailed" msgid="8083079241212301741">"Дакраніцеся, каб убачыць параметры"</string>
    ++    <string name="network_switch_metered" msgid="4671730921726992671">"Выкананы пераход да <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
    ++    <string name="network_switch_metered_detail" msgid="5325661434777870353">"Прылада выкарыстоўвае <xliff:g id="NEW_NETWORK">%1$s</xliff:g>, калі ў <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> няма доступу да інтэрнэту. Можа спаганяцца дадатковая плата."</string>
    ++    <string name="network_switch_metered_toast" msgid="5779283181685974304">"Выкананы пераход з <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> да <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
    ++  <string-array name="network_switch_type_name">
    ++    <item msgid="2952042958050315394">"сотавая перадача даных"</item>
    ++    <item msgid="75483255295529161">"Wi-Fi"</item>
    ++    <item msgid="6862614801537202646">"Bluetooth"</item>
    ++    <item msgid="5447331121797802871">"Ethernet"</item>
    ++    <item msgid="8257233890381651999">"VPN"</item>
    ++  </string-array>
    ++    <string name="network_switch_type_name_unknown" msgid="4552612897806660656">"невядомы тып сеткі"</string>
    +     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Немагчыма падключыцца да Wi-Fi"</string>
    +     <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" дрэннае падключэнне да Інтэрнэту."</string>
    +     <string name="wifi_connect_alert_title" msgid="8455846016001810172">"Дазволіць падключэнне?"</string>
    +@@ -1203,7 +1215,6 @@
    +     <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"Дакраніцеся, каб выбраць мову і раскладку"</string>
    +     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" АБВГДЕЁЖЗІЙКЛМНОПРСТУЎФХЦЧШ\'ЫЬЭЮЯ"</string>
    +     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
    +-    <string name="candidates_style" msgid="4333913089637062257"><u>"кандыдат."</u></string>
    +     <string name="ext_media_checking_notification_title" msgid="5734005953288045806">"Падрыхтоўка <xliff:g id="NAME">%s</xliff:g>"</string>
    +     <string name="ext_media_checking_notification_message" msgid="4747432538578886744">"Праверка на наяўнасць памылак"</string>
    +     <string name="ext_media_new_notification_message" msgid="7589986898808506239">"Выяўлены новы носьбіт <xliff:g id="NAME">%s</xliff:g>"</string>
    +@@ -1282,8 +1293,9 @@
    +     <string name="vpn_text_long" msgid="4907843483284977618">"Падлучаны да <xliff:g id="SESSION">%s</xliff:g>. Націсніце, каб кiраваць сеткай."</string>
    +     <string name="vpn_lockdown_connecting" msgid="6443438964440960745">"Падключэнне заўсёды ўключанага VPN..."</string>
    +     <string name="vpn_lockdown_connected" msgid="8202679674819213931">"Заўсёды ўключаны i падключаны VPN"</string>
    ++    <string name="vpn_lockdown_disconnected" msgid="4532298952570796327">"Заўсёды ўключаны VPN адключаны"</string>
    +     <string name="vpn_lockdown_error" msgid="6009249814034708175">"Памылка заўсёды ўключанага VPN"</string>
    +-    <string name="vpn_lockdown_config" msgid="4655589351146766608">"Дакраніцеся, каб сканфігураваць"</string>
    ++    <string name="vpn_lockdown_config" msgid="5099330695245008680">"Дакраніцеся, каб наладзіць"</string>
    +     <string name="upload_file" msgid="2897957172366730416">"Выберыце файл"</string>
    +     <string name="no_file_chosen" msgid="6363648562170759465">"Файл не выбраны"</string>
    +     <string name="reset" msgid="2448168080964209908">"Скінуць"</string>
    +@@ -1369,7 +1381,7 @@
    +     <string name="storage_usb_drive_label" msgid="4501418548927759953">"USB-дыск <xliff:g id="MANUFACTURER">%s</xliff:g>"</string>
    +     <string name="storage_usb" msgid="3017954059538517278">"USB-назапашвальнік"</string>
    +     <string name="extract_edit_menu_button" msgid="8940478730496610137">"Рэдагаваць"</string>
    +-    <string name="data_usage_warning_title" msgid="1955638862122232342">"Папярэджанне выкарыстання дадзеных"</string>
    ++    <string name="data_usage_warning_title" msgid="3620440638180218181">"Абвестка аб выкарыстанні трафіка"</string>
    +     <string name="data_usage_warning_body" msgid="6660692274311972007">"Прагляд выкарыстання і налад."</string>
    +     <string name="data_usage_3g_limit_title" msgid="4361523876818447683">"Дасягнуты ліміт трафіку 2G-3G"</string>
    +     <string name="data_usage_4g_limit_title" msgid="4609566827219442376">"Дасягнуты ліміт трафіку 4G"</string>
    +@@ -1708,6 +1720,7 @@
    +     <string name="search_language_hint" msgid="7042102592055108574">"Увядзіце назву мовы"</string>
    +     <string name="language_picker_section_suggested" msgid="8414489646861640885">"Прапанаваныя"</string>
    +     <string name="language_picker_section_all" msgid="3097279199511617537">"Усе мовы"</string>
    ++    <string name="region_picker_section_all" msgid="8966316787153001779">"Усе рэгіёны"</string>
    +     <string name="locale_search_menu" msgid="2560710726687249178">"Шукаць"</string>
    +     <string name="work_mode_off_title" msgid="8954725060677558855">"Рэжым працы АДКЛЮЧАНЫ"</string>
    +     <string name="work_mode_off_message" msgid="3286169091278094476">"Дазволіць функцыянаванне працоўнага профілю, у тым ліку праграм, фонавай сінхранізацыі і звязаных з імі функцый."</string>
    +diff --git a/core/res/res/values-bg/strings.xml b/core/res/res/values-bg/strings.xml
    +index 098a1a5..4d8915b 100644
    +--- a/core/res/res/values-bg/strings.xml
    ++++ b/core/res/res/values-bg/strings.xml
    +@@ -214,6 +214,7 @@
    +     <string name="global_actions" product="default" msgid="2406416831541615258">"Опции на телефона"</string>
    +     <string name="global_action_lock" msgid="2844945191792119712">"Заключване на екрана"</string>
    +     <string name="global_action_power_off" msgid="4471879440839879722">"Изключване"</string>
    ++    <string name="global_action_emergency" msgid="7112311161137421166">"Спешно обаждане"</string>
    +     <string name="global_action_bug_report" msgid="7934010578922304799">"Сигнал за програмна грешка"</string>
    +     <string name="bugreport_title" msgid="2667494803742548533">"Сигнал за програмна грешка"</string>
    +     <string name="bugreport_message" msgid="398447048750350456">"По този начин ще се събере информация за текущото състояние на устройството ви, която да се изпрати като имейл съобщение. След стартирането на процеса ще мине известно време, докато сигналът за програмна грешка бъде готов за подаване. Моля, имайте търпение."</string>
    +@@ -1076,6 +1077,17 @@
    +     <skip />
    +     <string name="wifi_no_internet" msgid="8451173622563841546">"Wi-Fi мрежата няма достъп до интернет"</string>
    +     <string name="wifi_no_internet_detailed" msgid="8083079241212301741">"Докоснете за опции"</string>
    ++    <string name="network_switch_metered" msgid="4671730921726992671">"Превключи се към <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
    ++    <string name="network_switch_metered_detail" msgid="5325661434777870353">"Устройството използва <xliff:g id="NEW_NETWORK">%1$s</xliff:g>, когато <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> няма достъп до интернет. Възможно е да бъдете таксувани."</string>
    ++    <string name="network_switch_metered_toast" msgid="5779283181685974304">"Превключи се от <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> към <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
    ++  <string-array name="network_switch_type_name">
    ++    <item msgid="2952042958050315394">"мобилни данни"</item>
    ++    <item msgid="75483255295529161">"Wi-Fi"</item>
    ++    <item msgid="6862614801537202646">"Bluetooth"</item>
    ++    <item msgid="5447331121797802871">"Ethernet"</item>
    ++    <item msgid="8257233890381651999">"виртуална частна мрежа (VPN)"</item>
    ++  </string-array>
    ++    <string name="network_switch_type_name_unknown" msgid="4552612897806660656">"неизвестен тип мрежа"</string>
    +     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Не можа да се свърже с Wi-Fi"</string>
    +     <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" има лоша връзка с интернет."</string>
    +     <string name="wifi_connect_alert_title" msgid="8455846016001810172">"Да се разреши ли връзката?"</string>
    +@@ -1153,7 +1165,6 @@
    +     <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"Докоснете, за да изберете език и подредба"</string>
    +     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
    +     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
    +-    <string name="candidates_style" msgid="4333913089637062257"><u>"кандидати"</u></string>
    +     <string name="ext_media_checking_notification_title" msgid="5734005953288045806">"<xliff:g id="NAME">%s</xliff:g>: Подготвя се"</string>
    +     <string name="ext_media_checking_notification_message" msgid="4747432538578886744">"Проверява се за грешки"</string>
    +     <string name="ext_media_new_notification_message" msgid="7589986898808506239">"Открито е ново хранилище (<xliff:g id="NAME">%s</xliff:g>)"</string>
    +@@ -1232,8 +1243,9 @@
    +     <string name="vpn_text_long" msgid="4907843483284977618">"Свързана с/ъс <xliff:g id="SESSION">%s</xliff:g>. Докоснете, за да управлявате мрежата."</string>
    +     <string name="vpn_lockdown_connecting" msgid="6443438964440960745">"Установява се връзка с винаги включената виртуална частна мрежа (VPN)…"</string>
    +     <string name="vpn_lockdown_connected" msgid="8202679674819213931">"Установена е връзка с винаги включената виртуална частна мрежа (VPN)"</string>
    ++    <string name="vpn_lockdown_disconnected" msgid="4532298952570796327">"Няма връзка с винаги включената виртуална частна мрежа (VPN)"</string>
    +     <string name="vpn_lockdown_error" msgid="6009249814034708175">"Грешка във винаги включената виртуална частна мрежа (VPN)"</string>
    +-    <string name="vpn_lockdown_config" msgid="4655589351146766608">"Докоснете, за да конфигурирате"</string>
    ++    <string name="vpn_lockdown_config" msgid="5099330695245008680">"Докоснете, за да настроите"</string>
    +     <string name="upload_file" msgid="2897957172366730416">"Избор на файл"</string>
    +     <string name="no_file_chosen" msgid="6363648562170759465">"Няма избран файл"</string>
    +     <string name="reset" msgid="2448168080964209908">"Повторно задаване"</string>
    +@@ -1317,7 +1329,7 @@
    +     <string name="storage_usb_drive_label" msgid="4501418548927759953">"USB устройство от <xliff:g id="MANUFACTURER">%s</xliff:g>"</string>
    +     <string name="storage_usb" msgid="3017954059538517278">"USB хранилище"</string>
    +     <string name="extract_edit_menu_button" msgid="8940478730496610137">"Редактиране"</string>
    +-    <string name="data_usage_warning_title" msgid="1955638862122232342">"Предупрежд. за ползване на данни"</string>
    ++    <string name="data_usage_warning_title" msgid="3620440638180218181">"Сигнал за преноса на данни"</string>
    +     <string name="data_usage_warning_body" msgid="6660692274311972007">"Пренос и настройки: Докоснете за преглед."</string>
    +     <string name="data_usage_3g_limit_title" msgid="4361523876818447683">"Достигнат лимит за 2G/3G данните"</string>
    +     <string name="data_usage_4g_limit_title" msgid="4609566827219442376">"Достигнат лимит за 4G данните"</string>
    +@@ -1636,6 +1648,7 @@
    +     <string name="search_language_hint" msgid="7042102592055108574">"Въведете име на език"</string>
    +     <string name="language_picker_section_suggested" msgid="8414489646861640885">"Предложени"</string>
    +     <string name="language_picker_section_all" msgid="3097279199511617537">"Всички езици"</string>
    ++    <string name="region_picker_section_all" msgid="8966316787153001779">"Всички региони"</string>
    +     <string name="locale_search_menu" msgid="2560710726687249178">"Търсене"</string>
    +     <string name="work_mode_off_title" msgid="8954725060677558855">"Работният режим е ИЗКЛЮЧЕН"</string>
    +     <string name="work_mode_off_message" msgid="3286169091278094476">"Разрешаване на функционирането на служебния потребителски профил, включително приложенията, синхронизирането на заден план и свързаните функции."</string>
    +diff --git a/core/res/res/values-bn-rBD/strings.xml b/core/res/res/values-bn-rBD/strings.xml
    +index c9e921a..8d893e5 100644
    +--- a/core/res/res/values-bn-rBD/strings.xml
    ++++ b/core/res/res/values-bn-rBD/strings.xml
    +@@ -214,8 +214,9 @@
    +     <string name="global_actions" product="default" msgid="2406416831541615258">"ফোন বিকল্পগুলি"</string>
    +     <string name="global_action_lock" msgid="2844945191792119712">"স্ক্রীণ লক"</string>
    +     <string name="global_action_power_off" msgid="4471879440839879722">"পাওয়ার বন্ধ করুন"</string>
    ++    <string name="global_action_emergency" msgid="7112311161137421166">"জরুরী"</string>
    +     <string name="global_action_bug_report" msgid="7934010578922304799">"ত্রুটির প্রতিবেদন"</string>
    +-    <string name="bugreport_title" msgid="2667494803742548533">"ত্রুটির প্রতিবেদন করুন"</string>
    ++    <string name="bugreport_title" msgid="2667494803742548533">"ত্রুটির অভিযোগ করুন"</string>
    +     <string name="bugreport_message" msgid="398447048750350456">"এটি একটি ই-মেল বার্তা পাঠানোর জন্য আপনার ডিভাইসের বর্তমান অবস্থা সম্পর্কে তথ্য সংগ্রহ করবে৷ ত্রুটির প্রতিবেদন শুরুর সময় থেকে এটি পাঠানোর জন্য প্রস্তুত হতে কিছুটা সময় নেবে; দয়া করে ধৈর্য রাখুন৷"</string>
    +     <string name="bugreport_option_interactive_title" msgid="8635056131768862479">"ইন্টারেক্টিভ প্রতিবেদন"</string>
    +     <string name="bugreport_option_interactive_summary" msgid="229299488536107968">"বেশিরভাগ পরিস্থিতিতে এটিকে ব্যবহার করুন৷ এটি আপনাকে প্রতিবেদনের কাজ কতটা হয়েছে তার উপর নজর রাখতে দেয়, সমস্যাটির সম্পর্কে আরো অনেক কিছু লিখতে দেয় এবং স্ক্রীনশটগুলি নিতে দেয়৷ এটি হয়ত প্রতিবেদন করতে খুব বেশি সময় নেয় এমনকি কম-ব্যবহৃত বিভাগগুলি সরিয়ে দিতে পারে৷"</string>
    +@@ -1007,7 +1008,7 @@
    +     <string name="anr_application_process" msgid="6417199034861140083">"<xliff:g id="APPLICATION">%1$s</xliff:g> সাড়া দিচ্ছে না"</string>
    +     <string name="anr_process" msgid="6156880875555921105">"<xliff:g id="PROCESS">%1$s</xliff:g> প্রক্রিয়া সাড়া দিচ্ছে না"</string>
    +     <string name="force_close" msgid="8346072094521265605">"ঠিক আছে"</string>
    +-    <string name="report" msgid="4060218260984795706">"প্রতিবেদন করুন"</string>
    ++    <string name="report" msgid="4060218260984795706">"অভিযোগ করুন"</string>
    +     <string name="wait" msgid="7147118217226317732">"অপেক্ষা করুন"</string>
    +     <string name="webpage_unresponsive" msgid="3272758351138122503">"পৃষ্ঠাটি কোনো পতিক্রিয়া করছে না৷\n\nআপনি কি এটিকে বন্ধ করতে চান?"</string>
    +     <string name="launch_warning_title" msgid="1547997780506713581">"অ্যাপ্লিকেশানকে পুনঃনির্দেশিত করা হয়েছে"</string>
    +@@ -1076,6 +1077,17 @@
    +     <skip />
    +     <string name="wifi_no_internet" msgid="8451173622563841546">"ওয়াই-ফাই -তে কোনো ইন্টারনেট অ্যাক্সেস নেই"</string>
    +     <string name="wifi_no_internet_detailed" msgid="8083079241212301741">"বিকল্পগুলির জন্য আলতো চাপুন"</string>
    ++    <string name="network_switch_metered" msgid="4671730921726992671">"<xliff:g id="NETWORK_TYPE">%1$s</xliff:g> এ পাল্টানো হয়েছে"</string>
    ++    <string name="network_switch_metered_detail" msgid="5325661434777870353">"যখন <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> এর কোনো ইন্টারনেট অ্যাক্সেস থাকে না তখন ডিভাইস <xliff:g id="NEW_NETWORK">%1$s</xliff:g> ব্যবহার করে৷ চার্জ লাগতে পারে৷"</string>
    ++    <string name="network_switch_metered_toast" msgid="5779283181685974304">"<xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> থেকে <xliff:g id="NEW_NETWORK">%2$s</xliff:g> এ পাল্টানো হয়েছে"</string>
    ++  <string-array name="network_switch_type_name">
    ++    <item msgid="2952042958050315394">"সেলুলার ডেটা"</item>
    ++    <item msgid="75483255295529161">"Wi-Fi"</item>
    ++    <item msgid="6862614801537202646">"Bluetooth"</item>
    ++    <item msgid="5447331121797802871">"ইথারনেট"</item>
    ++    <item msgid="8257233890381651999">"VPN"</item>
    ++  </string-array>
    ++    <string name="network_switch_type_name_unknown" msgid="4552612897806660656">"এই নেটওয়ার্কের প্রকার অজানা"</string>
    +     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"ওয়াই-ফাই এর সাথে সংযোগ করা যায়নি"</string>
    +     <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" একটি দুর্বল ইন্টারনেট সংযোগ রয়েছে৷"</string>
    +     <string name="wifi_connect_alert_title" msgid="8455846016001810172">"সংযোগের অনুমতি দেবেন?"</string>
    +@@ -1153,7 +1165,6 @@
    +     <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"ভাষা এবং লেআউট নির্বাচন করুন আলতো চাপ দিন"</string>
    +     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
    +     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
    +-    <string name="candidates_style" msgid="4333913089637062257"><u>"প্রার্থীরা"</u></string>
    +     <string name="ext_media_checking_notification_title" msgid="5734005953288045806">"<xliff:g id="NAME">%s</xliff:g> প্রস্তুত করা হচ্ছে"</string>
    +     <string name="ext_media_checking_notification_message" msgid="4747432538578886744">"ত্রুটি রয়েছে কিনা পরীক্ষা করা হচ্ছে"</string>
    +     <string name="ext_media_new_notification_message" msgid="7589986898808506239">"নতুন <xliff:g id="NAME">%s</xliff:g> সনাক্ত করা হয়েছে"</string>
    +@@ -1232,8 +1243,9 @@
    +     <string name="vpn_text_long" msgid="4907843483284977618">"<xliff:g id="SESSION">%s</xliff:g> তে সংযুক্ত হয়েছে৷ নেটওয়ার্ক পরিচালনা করতে আলতো চাপুন৷"</string>
    +     <string name="vpn_lockdown_connecting" msgid="6443438964440960745">"সর্বদা-চালু VPN সংযুক্ত হচ্ছে..."</string>
    +     <string name="vpn_lockdown_connected" msgid="8202679674819213931">"সর্বদা-চালু VPN সংযুক্ত হয়েছে"</string>
    ++    <string name="vpn_lockdown_disconnected" msgid="4532298952570796327">"সর্বদা-চালু VPN এর সংযোগ বিচ্ছিন্ন হয়েছে"</string>
    +     <string name="vpn_lockdown_error" msgid="6009249814034708175">"সর্বদা-চালু VPN ত্রুটি"</string>
    +-    <string name="vpn_lockdown_config" msgid="4655589351146766608">"কনফিগার করতে আলতো চাপুন"</string>
    ++    <string name="vpn_lockdown_config" msgid="5099330695245008680">"সেট আপ করতে আলতো চাপুন"</string>
    +     <string name="upload_file" msgid="2897957172366730416">"ফাইল বেছে নিন"</string>
    +     <string name="no_file_chosen" msgid="6363648562170759465">"কোনো ফাইল নির্বাচন করা হয়নি"</string>
    +     <string name="reset" msgid="2448168080964209908">"পুনরায় সেট করুন"</string>
    +@@ -1317,7 +1329,7 @@
    +     <string name="storage_usb_drive_label" msgid="4501418548927759953">"<xliff:g id="MANUFACTURER">%s</xliff:g> USB ড্রাইভ"</string>
    +     <string name="storage_usb" msgid="3017954059538517278">"USB সঞ্চয়স্থান"</string>
    +     <string name="extract_edit_menu_button" msgid="8940478730496610137">"সম্পাদনা করুন"</string>
    +-    <string name="data_usage_warning_title" msgid="1955638862122232342">"ডেটা ব্যবহারের সতর্কতা"</string>
    ++    <string name="data_usage_warning_title" msgid="3620440638180218181">"ডেটা ব্যবহারের সতর্কতা"</string>
    +     <string name="data_usage_warning_body" msgid="6660692274311972007">"ব্যবহার এবং সেটিংস দেখতে আলতো চাপুন৷"</string>
    +     <string name="data_usage_3g_limit_title" msgid="4361523876818447683">"2G-3G ডেটা সীমা ছাড়িয়েছে"</string>
    +     <string name="data_usage_4g_limit_title" msgid="4609566827219442376">"4G ডেটা সীমা ছাড়িয়েছে"</string>
    +@@ -1636,6 +1648,7 @@
    +     <string name="search_language_hint" msgid="7042102592055108574">"ভাষার নাম লিখুন"</string>
    +     <string name="language_picker_section_suggested" msgid="8414489646861640885">"প্রস্তাবিত"</string>
    +     <string name="language_picker_section_all" msgid="3097279199511617537">"সকল ভাষা"</string>
    ++    <string name="region_picker_section_all" msgid="8966316787153001779">"সমস্ত অঞ্চল"</string>
    +     <string name="locale_search_menu" msgid="2560710726687249178">"অনুসন্ধান করুন"</string>
    +     <string name="work_mode_off_title" msgid="8954725060677558855">"কাজের মোড বন্ধ আছে"</string>
    +     <string name="work_mode_off_message" msgid="3286169091278094476">"অ্যাপ্লিকেশান, পটভূমি সিঙ্ক এবং সম্পর্কিত বৈশিষ্ট্যগুলি সহ কর্মস্থলের প্রোফাইলটিকে কাজ করার অনুমতি দিন।"</string>
    +diff --git a/core/res/res/values-bs-rBA/strings.xml b/core/res/res/values-bs-rBA/strings.xml
    +index 20104a6..e8a3c02 100644
    +--- a/core/res/res/values-bs-rBA/strings.xml
    ++++ b/core/res/res/values-bs-rBA/strings.xml
    +@@ -216,6 +216,7 @@
    +     <string name="global_actions" product="default" msgid="2406416831541615258">"Opcije telefona"</string>
    +     <string name="global_action_lock" msgid="2844945191792119712">"Zaključavanje ekrana"</string>
    +     <string name="global_action_power_off" msgid="4471879440839879722">"Isključi telefon"</string>
    ++    <string name="global_action_emergency" msgid="7112311161137421166">"Hitni slučaj"</string>
    +     <string name="global_action_bug_report" msgid="7934010578922304799">"Izvještaj o greškama"</string>
    +     <string name="bugreport_title" msgid="2667494803742548533">"Kreirajte izvještaj o greškama"</string>
    +     <string name="bugreport_message" msgid="398447048750350456">"Ovim će se prikupljati informacije o trenutnom stanju uređaja, koji će biti poslani kao poruka e-pošte. Može malo potrajati dok se izvještaj o greškama ne kreira i bude spreman za slanje. Budite strpljivi."</string>
    +@@ -1103,6 +1104,17 @@
    +     <skip />
    +     <string name="wifi_no_internet" msgid="8451173622563841546">"Wi-Fi nema pristup Internetu"</string>
    +     <string name="wifi_no_internet_detailed" msgid="8083079241212301741">"Dodirnite za opcije"</string>
    ++    <string name="network_switch_metered" msgid="4671730921726992671">"Prebačeno na: <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
    ++    <string name="network_switch_metered_detail" msgid="5325661434777870353">"Kada na uređaju <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> nema pristup internetu, koristi se <xliff:g id="NEW_NETWORK">%1$s</xliff:g>. Moguća je naplata usluge."</string>
    ++    <string name="network_switch_metered_toast" msgid="5779283181685974304">"Prebačeno iz mreže <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> u <xliff:g id="NEW_NETWORK">%2$s</xliff:g> mrežu"</string>
    ++  <string-array name="network_switch_type_name">
    ++    <item msgid="2952042958050315394">"mobilni podaci"</item>
    ++    <item msgid="75483255295529161">"Wi-Fi"</item>
    ++    <item msgid="6862614801537202646">"Bluetooth"</item>
    ++    <item msgid="5447331121797802871">"Ethernet"</item>
    ++    <item msgid="8257233890381651999">"VPN"</item>
    ++  </string-array>
    ++    <string name="network_switch_type_name_unknown" msgid="4552612897806660656">"nepoznata vrsta mreže"</string>
    +     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Problem prilikom spajanja na Wi-Fi mrežu"</string>
    +     <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" ima lošu internet vezu."</string>
    +     <string name="wifi_connect_alert_title" msgid="8455846016001810172">"Želite li dozvoliti povezivanje?"</string>
    +@@ -1180,7 +1192,6 @@
    +     <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"Dodirnite za odabir jezika i rasporeda"</string>
    +     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
    +     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
    +-    <string name="candidates_style" msgid="4333913089637062257"><u>"kandidati"</u></string>
    +     <string name="ext_media_checking_notification_title" msgid="5734005953288045806">"Priprema se <xliff:g id="NAME">%s</xliff:g>"</string>
    +     <string name="ext_media_checking_notification_message" msgid="4747432538578886744">"Provjera grešaka"</string>
    +     <string name="ext_media_new_notification_message" msgid="7589986898808506239">"Novi uređaj <xliff:g id="NAME">%s</xliff:g> je otkriven"</string>
    +@@ -1259,8 +1270,9 @@
    +     <string name="vpn_text_long" msgid="4907843483284977618">"Povezano sa sesijom <xliff:g id="SESSION">%s</xliff:g>. Dodirnite da upravljate mrežom."</string>
    +     <string name="vpn_lockdown_connecting" msgid="6443438964440960745">"Povezivanje na uvijek aktivni VPN…"</string>
    +     <string name="vpn_lockdown_connected" msgid="8202679674819213931">"Povezan na uvijek aktivni VPN"</string>
    ++    <string name="vpn_lockdown_disconnected" msgid="4532298952570796327">"Uvijek aktivni VPN nije povezan"</string>
    +     <string name="vpn_lockdown_error" msgid="6009249814034708175">"Greška u povezivanju na uvijek aktivni VPN"</string>
    +-    <string name="vpn_lockdown_config" msgid="4655589351146766608">"Dodirnite za konfiguriranje"</string>
    ++    <string name="vpn_lockdown_config" msgid="5099330695245008680">"Dodirnite za postavke"</string>
    +     <string name="upload_file" msgid="2897957172366730416">"Odabir fajla"</string>
    +     <string name="no_file_chosen" msgid="6363648562170759465">"Nije izabran nijedan fajl"</string>
    +     <string name="reset" msgid="2448168080964209908">"Ponovno pokretanje"</string>
    +@@ -1345,7 +1357,7 @@
    +     <string name="storage_usb_drive_label" msgid="4501418548927759953">"<xliff:g id="MANUFACTURER">%s</xliff:g> USB disk"</string>
    +     <string name="storage_usb" msgid="3017954059538517278">"USB pohrana"</string>
    +     <string name="extract_edit_menu_button" msgid="8940478730496610137">"Uredi"</string>
    +-    <string name="data_usage_warning_title" msgid="1955638862122232342">"Upozorenje za prijenos podataka"</string>
    ++    <string name="data_usage_warning_title" msgid="3620440638180218181">"Upozorenje o prijenosu podataka"</string>
    +     <string name="data_usage_warning_body" msgid="6660692274311972007">"Dodirnite za prikaz upotrebe i postavki."</string>
    +     <string name="data_usage_3g_limit_title" msgid="4361523876818447683">"Dostignut limit za 2G-3G podatke"</string>
    +     <string name="data_usage_4g_limit_title" msgid="4609566827219442376">"Dostignut limit za 4G podatke"</string>
    +@@ -1586,7 +1598,7 @@
    +     <string name="package_updated_device_owner" msgid="8856631322440187071">"Ažurirao administrator"</string>
    +     <string name="package_deleted_device_owner" msgid="7650577387493101353">"Izbrisao administrator"</string>
    +     <string name="battery_saver_description" msgid="1960431123816253034">"Da bi se trajanje baterije produžilo, opcija za štednju baterije minimizira rad uređaja i ograničava vibriranje, usluge lokacije i većinu prijenosa podataka u pozadini. E-pošta, poruke i druge aplikacije koje se oslanjaju na sinhronizaciju ne mogu biti ažurirane dok ih ne otvorite.\n\nŠtednja baterije se automatski isključi prilikom punjenja uređaja."</string>
    +-    <string name="data_saver_description" msgid="6015391409098303235">"Da bi se smanjilo korištenje podataka, usluga Ušteda podataka sprečava da neke aplikacije šalju ili primaju podatke u pozadini. Aplikacija koju trenutno koristite može pristupiti podacima, ali se to može desiti rjeđe. To može značiti, naprimjer, da se slike ne prikazuju sve dok ih ne dodirnete."</string>
    ++    <string name="data_saver_description" msgid="6015391409098303235">"Da bi se smanjio prijenos podataka, usluga Ušteda podataka sprečava da neke aplikacije šalju ili primaju podatke u pozadini. Aplikacija koju trenutno koristite može pristupiti podacima, ali se to može desiti rjeđe. To može značiti, naprimjer, da se slike ne prikazuju sve dok ih ne dodirnete."</string>
    +     <string name="data_saver_enable_title" msgid="4674073932722787417">"Uključiti Uštedu podataka?"</string>
    +     <string name="data_saver_enable_button" msgid="7147735965247211818">"Uključi"</string>
    +     <plurals name="zen_mode_duration_minutes_summary" formatted="false" msgid="4367877408072000848">
    +@@ -1674,6 +1686,7 @@
    +     <string name="search_language_hint" msgid="7042102592055108574">"Ukucajte naziv jezika"</string>
    +     <string name="language_picker_section_suggested" msgid="8414489646861640885">"Predloženo"</string>
    +     <string name="language_picker_section_all" msgid="3097279199511617537">"Svi jezici"</string>
    ++    <string name="region_picker_section_all" msgid="8966316787153001779">"Sve regije"</string>
    +     <string name="locale_search_menu" msgid="2560710726687249178">"Pretraga"</string>
    +     <string name="work_mode_off_title" msgid="8954725060677558855">"Radni način rada je ISKLJUČEN"</string>
    +     <string name="work_mode_off_message" msgid="3286169091278094476">"Omogući radnom profilu da funkcionira, uključujući aplikacije, sinhronizaciju u pozadini i povezane funkcije."</string>
    +diff --git a/core/res/res/values-ca/strings.xml b/core/res/res/values-ca/strings.xml
    +index eeed892..137d924 100644
    +--- a/core/res/res/values-ca/strings.xml
    ++++ b/core/res/res/values-ca/strings.xml
    +@@ -214,6 +214,7 @@
    +     <string name="global_actions" product="default" msgid="2406416831541615258">"Opcions del telèfon"</string>
    +     <string name="global_action_lock" msgid="2844945191792119712">"Bloqueig de pantalla"</string>
    +     <string name="global_action_power_off" msgid="4471879440839879722">"Apaga"</string>
    ++    <string name="global_action_emergency" msgid="7112311161137421166">"Emergències"</string>
    +     <string name="global_action_bug_report" msgid="7934010578922304799">"Informe d\'error"</string>
    +     <string name="bugreport_title" msgid="2667494803742548533">"Crea informe d\'errors"</string>
    +     <string name="bugreport_message" msgid="398447048750350456">"Es recopilarà informació sobre l\'estat actual del dispositiu i se t\'enviarà per correu electrònic. Passaran uns quants minuts des de l\'inici de l\'informe d\'errors fins al seu enviament, per la qual cosa et recomanem que tinguis paciència."</string>
    +@@ -1076,6 +1077,17 @@
    +     <skip />
    +     <string name="wifi_no_internet" msgid="8451173622563841546">"La Wi-Fi no té accés a Internet"</string>
    +     <string name="wifi_no_internet_detailed" msgid="8083079241212301741">"Toca per veure les opcions"</string>
    ++    <string name="network_switch_metered" msgid="4671730921726992671">"Actualment en ús: <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
    ++    <string name="network_switch_metered_detail" msgid="5325661434777870353">"El dispositiu utilitza <xliff:g id="NEW_NETWORK">%1$s</xliff:g> en cas que <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> no tingui accés a Internet. És possible que s\'apliquin càrrecs."</string>
    ++    <string name="network_switch_metered_toast" msgid="5779283181685974304">"Abans es feia servir la xarxa <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g>; ara s\'utilitza <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
    ++  <string-array name="network_switch_type_name">
    ++    <item msgid="2952042958050315394">"dades mòbils"</item>
    ++    <item msgid="75483255295529161">"Wi-Fi"</item>
    ++    <item msgid="6862614801537202646">"Bluetooth"</item>
    ++    <item msgid="5447331121797802871">"Ethernet"</item>
    ++    <item msgid="8257233890381651999">"VPN"</item>
    ++  </string-array>
    ++    <string name="network_switch_type_name_unknown" msgid="4552612897806660656">"una tipus de xarxa desconegut"</string>
    +     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"No s\'ha pogut connectar a la Wi-Fi"</string>
    +     <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" té una mala connexió a Internet."</string>
    +     <string name="wifi_connect_alert_title" msgid="8455846016001810172">"Vols permetre la connexió?"</string>
    +@@ -1153,7 +1165,6 @@
    +     <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"Toca per seleccionar l\'idioma i el disseny"</string>
    +     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
    +     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
    +-    <string name="candidates_style" msgid="4333913089637062257"><u>"candidats"</u></string>
    +     <string name="ext_media_checking_notification_title" msgid="5734005953288045806">"S\'està preparant <xliff:g id="NAME">%s</xliff:g>"</string>
    +     <string name="ext_media_checking_notification_message" msgid="4747432538578886744">"S\'està comprovant si hi ha errors"</string>
    +     <string name="ext_media_new_notification_message" msgid="7589986898808506239">"S\'ha detectat <xliff:g id="NAME">%s</xliff:g>"</string>
    +@@ -1232,8 +1243,9 @@
    +     <string name="vpn_text_long" msgid="4907843483284977618">"Connectat a <xliff:g id="SESSION">%s</xliff:g>. Pica per gestionar la xarxa."</string>
    +     <string name="vpn_lockdown_connecting" msgid="6443438964440960745">"T\'estàs connectant a la VPN sempre activada…"</string>
    +     <string name="vpn_lockdown_connected" msgid="8202679674819213931">"Estàs connectat a la VPN sempre activada"</string>
    ++    <string name="vpn_lockdown_disconnected" msgid="4532298952570796327">"La VPN sempre activada està desconnectada"</string>
    +     <string name="vpn_lockdown_error" msgid="6009249814034708175">"Error de la VPN sempre activada"</string>
    +-    <string name="vpn_lockdown_config" msgid="4655589351146766608">"Toca per configurar"</string>
    ++    <string name="vpn_lockdown_config" msgid="5099330695245008680">"Toca per configurar"</string>
    +     <string name="upload_file" msgid="2897957172366730416">"Trieu un fitxer"</string>
    +     <string name="no_file_chosen" msgid="6363648562170759465">"No s\'ha escollit cap fitxer"</string>
    +     <string name="reset" msgid="2448168080964209908">"Restableix"</string>
    +@@ -1317,7 +1329,7 @@
    +     <string name="storage_usb_drive_label" msgid="4501418548927759953">"Unitat USB de: <xliff:g id="MANUFACTURER">%s</xliff:g>"</string>
    +     <string name="storage_usb" msgid="3017954059538517278">"Emmagatzematge USB"</string>
    +     <string name="extract_edit_menu_button" msgid="8940478730496610137">"Edita"</string>
    +-    <string name="data_usage_warning_title" msgid="1955638862122232342">"Advertiment d\'ús de dades"</string>
    ++    <string name="data_usage_warning_title" msgid="3620440638180218181">"Alerta d\'ús de dades"</string>
    +     <string name="data_usage_warning_body" msgid="6660692274311972007">"Toca per veure l\'ús i la configuració."</string>
    +     <string name="data_usage_3g_limit_title" msgid="4361523876818447683">"Límit de dades 2G-3G assolit"</string>
    +     <string name="data_usage_4g_limit_title" msgid="4609566827219442376">"Límit de dades 4G assolit"</string>
    +@@ -1636,6 +1648,7 @@
    +     <string name="search_language_hint" msgid="7042102592055108574">"Nom de l\'idioma"</string>
    +     <string name="language_picker_section_suggested" msgid="8414489646861640885">"Suggerits"</string>
    +     <string name="language_picker_section_all" msgid="3097279199511617537">"Tots els idiomes"</string>
    ++    <string name="region_picker_section_all" msgid="8966316787153001779">"Totes les regions"</string>
    +     <string name="locale_search_menu" msgid="2560710726687249178">"Cerca"</string>
    +     <string name="work_mode_off_title" msgid="8954725060677558855">"Mode de feina desactivat"</string>
    +     <string name="work_mode_off_message" msgid="3286169091278094476">"Permet que el perfil professional funcioni, incloses les aplicacions, la sincronització en segon pla i les funcions relacionades."</string>
    +diff --git a/core/res/res/values-cs/strings.xml b/core/res/res/values-cs/strings.xml
    +index df8bffd..8037681 100644
    +--- a/core/res/res/values-cs/strings.xml
    ++++ b/core/res/res/values-cs/strings.xml
    +@@ -218,6 +218,7 @@
    +     <string name="global_actions" product="default" msgid="2406416831541615258">"Možnosti telefonu"</string>
    +     <string name="global_action_lock" msgid="2844945191792119712">"Zámek obrazovky"</string>
    +     <string name="global_action_power_off" msgid="4471879440839879722">"Vypnout"</string>
    ++    <string name="global_action_emergency" msgid="7112311161137421166">"Stav nouze"</string>
    +     <string name="global_action_bug_report" msgid="7934010578922304799">"Hlášení chyb"</string>
    +     <string name="bugreport_title" msgid="2667494803742548533">"Vytvořit chybové hlášení"</string>
    +     <string name="bugreport_message" msgid="398447048750350456">"Shromažďuje informace o aktuálním stavu zařízení. Tyto informace je následně možné poslat v e-mailové zprávě, chvíli však potrvá, než bude hlášení o chybě připraveno k odeslání. Buďte prosím trpěliví."</string>
    +@@ -692,7 +693,7 @@
    +     <string name="lockscreen_missing_sim_message" product="default" msgid="2186920585695169078">"V telefonu není žádná SIM karta."</string>
    +     <string name="lockscreen_missing_sim_instructions" msgid="5372787138023272615">"Vložte SIM kartu."</string>
    +     <string name="lockscreen_missing_sim_instructions_long" msgid="3526573099019319472">"SIM karta chybí nebo je nečitelná. Vložte SIM kartu."</string>
    +-    <string name="lockscreen_permanent_disabled_sim_message_short" msgid="5096149665138916184">"Nepoužitelná karta SIM."</string>
    ++    <string name="lockscreen_permanent_disabled_sim_message_short" msgid="5096149665138916184">"Nepoužitelná SIM karta."</string>
    +     <string name="lockscreen_permanent_disabled_sim_instructions" msgid="910904643433151371">"Vaše SIM karta byla natrvalo zablokována.\n Požádejte svého poskytovatele bezdrátových služeb o další SIM kartu."</string>
    +     <string name="lockscreen_transport_prev_description" msgid="6300840251218161534">"Předchozí skladba"</string>
    +     <string name="lockscreen_transport_next_description" msgid="573285210424377338">"Další skladba"</string>
    +@@ -1126,6 +1127,17 @@
    +     <skip />
    +     <string name="wifi_no_internet" msgid="8451173622563841546">"Wi-Fi nemá přístup k internetu"</string>
    +     <string name="wifi_no_internet_detailed" msgid="8083079241212301741">"Klepnutím zobrazíte možnosti"</string>
    ++    <string name="network_switch_metered" msgid="4671730921726992671">"Přechod na síť <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
    ++    <string name="network_switch_metered_detail" msgid="5325661434777870353">"Když síť <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> nebude mít přístup k internetu, zařízení použije síť <xliff:g id="NEW_NETWORK">%1$s</xliff:g>. Mohou být účtovány poplatky."</string>
    ++    <string name="network_switch_metered_toast" msgid="5779283181685974304">"Přechod ze sítě <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> na síť <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
    ++  <string-array name="network_switch_type_name">
    ++    <item msgid="2952042958050315394">"mobilní data"</item>
    ++    <item msgid="75483255295529161">"Wi-Fi"</item>
    ++    <item msgid="6862614801537202646">"Bluetooth"</item>
    ++    <item msgid="5447331121797802871">"Ethernet"</item>
    ++    <item msgid="8257233890381651999">"VPN"</item>
    ++  </string-array>
    ++    <string name="network_switch_type_name_unknown" msgid="4552612897806660656">"neznámý typ sítě"</string>
    +     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Připojení k síti Wi-Fi se nezdařilo"</string>
    +     <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" má pomalé připojení k internetu."</string>
    +     <string name="wifi_connect_alert_title" msgid="8455846016001810172">"Povolit připojení?"</string>
    +@@ -1203,7 +1215,6 @@
    +     <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"Klepnutím vyberte jazyk a rozvržení"</string>
    +     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" AÁBCČDĎEÉĚFGHCHIÍJKLMNŇOÓPQRŘSŠTŤUÚVWXYÝZŽ"</string>
    +     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789AÁBCČDĎEÉĚFGHCHIÍJKLMNŇOÓPQRŘSŠTŤUÚVWXYÝZŽ"</string>
    +-    <string name="candidates_style" msgid="4333913089637062257"><u>"kandidáti"</u></string>
    +     <string name="ext_media_checking_notification_title" msgid="5734005953288045806">"Probíhá příprava úložiště <xliff:g id="NAME">%s</xliff:g>"</string>
    +     <string name="ext_media_checking_notification_message" msgid="4747432538578886744">"Kontrola chyb"</string>
    +     <string name="ext_media_new_notification_message" msgid="7589986898808506239">"Zjištěno nové úložiště <xliff:g id="NAME">%s</xliff:g>"</string>
    +@@ -1282,8 +1293,9 @@
    +     <string name="vpn_text_long" msgid="4907843483284977618">"Připojeno k relaci <xliff:g id="SESSION">%s</xliff:g>. Klepnutím můžete síť spravovat."</string>
    +     <string name="vpn_lockdown_connecting" msgid="6443438964440960745">"Připojování k trvalé síti VPN…"</string>
    +     <string name="vpn_lockdown_connected" msgid="8202679674819213931">"Je připojena trvalá síť VPN"</string>
    ++    <string name="vpn_lockdown_disconnected" msgid="4532298952570796327">"Trvalá síť VPN je odpojena"</string>
    +     <string name="vpn_lockdown_error" msgid="6009249814034708175">"Chyba trvalé sítě VPN"</string>
    +-    <string name="vpn_lockdown_config" msgid="4655589351146766608">"Klepnutím zahájíte konfiguraci"</string>
    ++    <string name="vpn_lockdown_config" msgid="5099330695245008680">"Klepnutím přejděte do Nastavení"</string>
    +     <string name="upload_file" msgid="2897957172366730416">"Zvolit soubor"</string>
    +     <string name="no_file_chosen" msgid="6363648562170759465">"Není vybrán žádný soubor"</string>
    +     <string name="reset" msgid="2448168080964209908">"Resetovat"</string>
    +@@ -1369,7 +1381,7 @@
    +     <string name="storage_usb_drive_label" msgid="4501418548927759953">"Jednotka USB <xliff:g id="MANUFACTURER">%s</xliff:g>"</string>
    +     <string name="storage_usb" msgid="3017954059538517278">"Úložiště USB"</string>
    +     <string name="extract_edit_menu_button" msgid="8940478730496610137">"Upravit"</string>
    +-    <string name="data_usage_warning_title" msgid="1955638862122232342">"Upozornění na využití dat"</string>
    ++    <string name="data_usage_warning_title" msgid="3620440638180218181">"Upozornění na používání dat"</string>
    +     <string name="data_usage_warning_body" msgid="6660692274311972007">"Klepnutím zobrazíte nastavení."</string>
    +     <string name="data_usage_3g_limit_title" msgid="4361523876818447683">"Dosáhli jste limitu dat 2G–3G"</string>
    +     <string name="data_usage_4g_limit_title" msgid="4609566827219442376">"Dosáhli jste limitu dat 4G"</string>
    +@@ -1708,6 +1720,7 @@
    +     <string name="search_language_hint" msgid="7042102592055108574">"Zadejte název jazyka"</string>
    +     <string name="language_picker_section_suggested" msgid="8414489646861640885">"Navrhované"</string>
    +     <string name="language_picker_section_all" msgid="3097279199511617537">"Všechny jazyky"</string>
    ++    <string name="region_picker_section_all" msgid="8966316787153001779">"Všechny oblasti"</string>
    +     <string name="locale_search_menu" msgid="2560710726687249178">"Vyhledávání"</string>
    +     <string name="work_mode_off_title" msgid="8954725060677558855">"Pracovní režim je VYPNUTÝ"</string>
    +     <string name="work_mode_off_message" msgid="3286169091278094476">"Povolí fungování pracovního profilu, včetně aplikací, synchronizace na pozadí a souvisejících funkcí."</string>
    +diff --git a/core/res/res/values-da/strings.xml b/core/res/res/values-da/strings.xml
    +index 731c847..eb4d255 100644
    +--- a/core/res/res/values-da/strings.xml
    ++++ b/core/res/res/values-da/strings.xml
    +@@ -214,6 +214,7 @@
    +     <string name="global_actions" product="default" msgid="2406416831541615258">"Indstillinger for telefon"</string>
    +     <string name="global_action_lock" msgid="2844945191792119712">"Skærmlås"</string>
    +     <string name="global_action_power_off" msgid="4471879440839879722">"Sluk"</string>
    ++    <string name="global_action_emergency" msgid="7112311161137421166">"Nødopkald"</string>
    +     <string name="global_action_bug_report" msgid="7934010578922304799">"Fejlrapport"</string>
    +     <string name="bugreport_title" msgid="2667494803742548533">"Lav fejlrapport"</string>
    +     <string name="bugreport_message" msgid="398447048750350456">"Der indsamles oplysninger om din enheds aktuelle status, der efterfølgende sendes i en e-mail. Der går lidt tid, fra fejlrapporten påbegyndes, til den er klar til at blive sendt. Tak for tålmodigheden."</string>
    +@@ -1076,6 +1077,17 @@
    +     <skip />
    +     <string name="wifi_no_internet" msgid="8451173622563841546">"Wi-Fi har ingen internetadgang"</string>
    +     <string name="wifi_no_internet_detailed" msgid="8083079241212301741">"Tryk for at se valgmuligheder"</string>
    ++    <string name="network_switch_metered" msgid="4671730921726992671">"Der blev skiftet til <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
    ++    <string name="network_switch_metered_detail" msgid="5325661434777870353">"Enheden benytter <xliff:g id="NEW_NETWORK">%1$s</xliff:g>, når <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> ikke har adgang til internettet. Der opkræves muligvis gebyr."</string>
    ++    <string name="network_switch_metered_toast" msgid="5779283181685974304">"Der blev skiftet fra <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> til <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
    ++  <string-array name="network_switch_type_name">
    ++    <item msgid="2952042958050315394">"mobildata"</item>
    ++    <item msgid="75483255295529161">"Wi-Fi"</item>
    ++    <item msgid="6862614801537202646">"Bluetooth"</item>
    ++    <item msgid="5447331121797802871">"Ethernet"</item>
    ++    <item msgid="8257233890381651999">"VPN"</item>
    ++  </string-array>
    ++    <string name="network_switch_type_name_unknown" msgid="4552612897806660656">"en ukendt netværkstype"</string>
    +     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Kunne ikke oprette forbindelse til Wi-Fi"</string>
    +     <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" har en dårlig internetforbindelse."</string>
    +     <string name="wifi_connect_alert_title" msgid="8455846016001810172">"Vil du tillade denne forbindelse?"</string>
    +@@ -1153,7 +1165,6 @@
    +     <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"Tryk for at vælge sprog og layout"</string>
    +     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
    +     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
    +-    <string name="candidates_style" msgid="4333913089637062257"><u>"kandidater"</u></string>
    +     <string name="ext_media_checking_notification_title" msgid="5734005953288045806">"Forbereder <xliff:g id="NAME">%s</xliff:g>"</string>
    +     <string name="ext_media_checking_notification_message" msgid="4747432538578886744">"Kontrollerer for fejl"</string>
    +     <string name="ext_media_new_notification_message" msgid="7589986898808506239">"Der blev registreret et nyt <xliff:g id="NAME">%s</xliff:g>"</string>
    +@@ -1232,8 +1243,9 @@
    +     <string name="vpn_text_long" msgid="4907843483284977618">"Forbundet til <xliff:g id="SESSION">%s</xliff:g>. Tryk for at administrere netværket."</string>
    +     <string name="vpn_lockdown_connecting" msgid="6443438964440960745">"Opretter forbindelse til altid aktiveret VPN…"</string>
    +     <string name="vpn_lockdown_connected" msgid="8202679674819213931">"Always-on VPN er forbundet"</string>
    ++    <string name="vpn_lockdown_disconnected" msgid="4532298952570796327">"Forbindelsen til altid aktiveret VPN er afbrudt"</string>
    +     <string name="vpn_lockdown_error" msgid="6009249814034708175">"Fejl i altid aktiveret VPN"</string>
    +-    <string name="vpn_lockdown_config" msgid="4655589351146766608">"Tryk for at konfigurere"</string>
    ++    <string name="vpn_lockdown_config" msgid="5099330695245008680">"Tryk for at konfigurere"</string>
    +     <string name="upload_file" msgid="2897957172366730416">"Vælg fil"</string>
    +     <string name="no_file_chosen" msgid="6363648562170759465">"Ingen fil er valgt"</string>
    +     <string name="reset" msgid="2448168080964209908">"Nulstil"</string>
    +@@ -1317,7 +1329,7 @@
    +     <string name="storage_usb_drive_label" msgid="4501418548927759953">"USB-drev fra <xliff:g id="MANUFACTURER">%s</xliff:g>"</string>
    +     <string name="storage_usb" msgid="3017954059538517278">"USB-lager"</string>
    +     <string name="extract_edit_menu_button" msgid="8940478730496610137">"Rediger"</string>
    +-    <string name="data_usage_warning_title" msgid="1955638862122232342">"Advarsel om dataforbrug"</string>
    ++    <string name="data_usage_warning_title" msgid="3620440638180218181">"Underretning om dataforbrug"</string>
    +     <string name="data_usage_warning_body" msgid="6660692274311972007">"Tryk for at se forbrug og indstillinger."</string>
    +     <string name="data_usage_3g_limit_title" msgid="4361523876818447683">"Grænsen for 2G-3G-data er nået"</string>
    +     <string name="data_usage_4g_limit_title" msgid="4609566827219442376">"Grænsen for 4G-data er nået"</string>
    +@@ -1636,6 +1648,7 @@
    +     <string name="search_language_hint" msgid="7042102592055108574">"Angiv sprogets navn"</string>
    +     <string name="language_picker_section_suggested" msgid="8414489646861640885">"Foreslået"</string>
    +     <string name="language_picker_section_all" msgid="3097279199511617537">"Alle sprog"</string>
    ++    <string name="region_picker_section_all" msgid="8966316787153001779">"Alle områder"</string>
    +     <string name="locale_search_menu" msgid="2560710726687249178">"Søg"</string>
    +     <string name="work_mode_off_title" msgid="8954725060677558855">"Arbejdstilstand er slået FRA"</string>
    +     <string name="work_mode_off_message" msgid="3286169091278094476">"Tillad, at arbejdsprofilen aktiveres, bl.a. i forbindelse med apps, baggrundssynkronisering og relaterede funktioner."</string>
    +diff --git a/core/res/res/values-de/strings.xml b/core/res/res/values-de/strings.xml
    +index c478607..a6fad85 100644
    +--- a/core/res/res/values-de/strings.xml
    ++++ b/core/res/res/values-de/strings.xml
    +@@ -214,6 +214,7 @@
    +     <string name="global_actions" product="default" msgid="2406416831541615258">"Telefonoptionen"</string>
    +     <string name="global_action_lock" msgid="2844945191792119712">"Displaysperre"</string>
    +     <string name="global_action_power_off" msgid="4471879440839879722">"Ausschalten"</string>
    ++    <string name="global_action_emergency" msgid="7112311161137421166">"Notfall"</string>
    +     <string name="global_action_bug_report" msgid="7934010578922304799">"Fehlerbericht"</string>
    +     <string name="bugreport_title" msgid="2667494803742548533">"Fehlerbericht abrufen"</string>
    +     <string name="bugreport_message" msgid="398447048750350456">"Bei diesem Fehlerbericht werden Daten zum aktuellen Status deines Geräts erfasst und als E-Mail versandt. Vom Start des Berichts bis zu seinem Versand kann es eine Weile dauern. Bitte habe etwas Geduld."</string>
    +@@ -416,7 +417,7 @@
    +     <string name="permdesc_changeWifiMulticastState" product="default" msgid="6851949706025349926">"Ermöglicht der App, Pakete zu empfangen, die mithilfe von Multicast-Adressen an sämtliche Geräte in einem WLAN versendet wurden, nicht nur an dein Telefon. Dies nimmt mehr Leistung in Anspruch als der Nicht-Multicast-Modus."</string>
    +     <string name="permlab_bluetoothAdmin" msgid="6006967373935926659">"Auf Bluetooth-Einstellungen zugreifen"</string>
    +     <string name="permdesc_bluetoothAdmin" product="tablet" msgid="6921177471748882137">"Ermöglicht der App, das lokale Bluetooth-Tablet zu konfigurieren, Remote-Geräte zu erkennen und eine Verbindung zu diesen herzustellen"</string>
    +-    <string name="permdesc_bluetoothAdmin" product="tv" msgid="3373125682645601429">"Ermöglicht der App, den lokalen Bluetooth-Fernseher zu konfigurieren, Remote-Geräte zu erkennen und ein Pairing mit diesen durchzuführen"</string>
    ++    <string name="permdesc_bluetoothAdmin" product="tv" msgid="3373125682645601429">"Ermöglicht der App, den lokalen Bluetooth-Fernseher zu konfigurieren, Remote-Geräte zu erkennen und eine Kopplung mit ihnen durchzuführen"</string>
    +     <string name="permdesc_bluetoothAdmin" product="default" msgid="8931682159331542137">"Ermöglicht der App, das lokale Bluetooth-Telefon zu konfigurieren, Remote-Geräte zu erkennen und eine Verbindung zu diesen herzustellen"</string>
    +     <string name="permlab_accessWimaxState" msgid="4195907010610205703">"WiMAX-Verbindungen herstellen und trennen"</string>
    +     <string name="permdesc_accessWimaxState" msgid="6360102877261978887">"Ermöglicht der App festzustellen, ob WiMAX aktiviert ist. Zudem kann sie Informationen zu verbundenen WiMAX-Netzwerken abrufen."</string>
    +@@ -424,9 +425,9 @@
    +     <string name="permdesc_changeWimaxState" product="tablet" msgid="3156456504084201805">"Ermöglicht der App, eine Verbindung zwischen dem Tablet und WiMAX-Netzwerken herzustellen und solche zu trennen."</string>
    +     <string name="permdesc_changeWimaxState" product="tv" msgid="6022307083934827718">"Ermöglicht der App, eine Verbindung zwischen dem Fernseher und WiMAX-Netzwerken herzustellen und diese zu trennen"</string>
    +     <string name="permdesc_changeWimaxState" product="default" msgid="697025043004923798">"Ermöglicht der App, eine Verbindung zwischen dem Telefon und WiMAX-Netzwerken herzustellen und solche zu trennen."</string>
    +-    <string name="permlab_bluetooth" msgid="6127769336339276828">"Pairing mit Bluetooth-Geräten durchführen"</string>
    ++    <string name="permlab_bluetooth" msgid="6127769336339276828">"Kopplung mit Bluetooth-Geräten durchführen"</string>
    +     <string name="permdesc_bluetooth" product="tablet" msgid="3480722181852438628">"Ermöglicht der App, die Bluetooth-Konfiguration eines Tablets einzusehen und Verbindungen zu gekoppelten Geräten herzustellen und zu akzeptieren."</string>
    +-    <string name="permdesc_bluetooth" product="tv" msgid="3974124940101104206">"Ermöglicht der App, die Bluetooth-Konfiguration des Fernsehers einzusehen und Verbindungen zu Pairing-Geräten herzustellen und zu akzeptieren"</string>
    ++    <string name="permdesc_bluetooth" product="tv" msgid="3974124940101104206">"Ermöglicht der App, die Bluetooth-Konfiguration des Fernsehers abzurufen und Verbindungen zu gekoppelten Geräten herzustellen und zu akzeptieren"</string>
    +     <string name="permdesc_bluetooth" product="default" msgid="3207106324452312739">"Ermöglicht der App, die Bluetooth-Konfiguration des Telefons einzusehen und Verbindungen mit gekoppelten Geräten herzustellen und zu akzeptieren."</string>
    +     <string name="permlab_nfc" msgid="4423351274757876953">"Nahfeldkommunikation steuern"</string>
    +     <string name="permdesc_nfc" msgid="7120611819401789907">"Ermöglicht der App die Kommunikation mit Tags für die Nahfeldkommunikation, Karten und Readern"</string>
    +@@ -1076,6 +1077,17 @@
    +     <skip />
    +     <string name="wifi_no_internet" msgid="8451173622563841546">"WLAN hat keinen Internetzugriff"</string>
    +     <string name="wifi_no_internet_detailed" msgid="8083079241212301741">"Für Optionen tippen"</string>
    ++    <string name="network_switch_metered" msgid="4671730921726992671">"Zu <xliff:g id="NETWORK_TYPE">%1$s</xliff:g> gewechselt"</string>
    ++    <string name="network_switch_metered_detail" msgid="5325661434777870353">"Auf dem Gerät wird \"<xliff:g id="NEW_NETWORK">%1$s</xliff:g>\" verwendet, wenn über \"<xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g>\" kein Internet verfügbar ist. Eventuell fallen Gebühren an."</string>
    ++    <string name="network_switch_metered_toast" msgid="5779283181685974304">"Von \"<xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g>\" zu \"<xliff:g id="NEW_NETWORK">%2$s</xliff:g>\" gewechselt"</string>
    ++  <string-array name="network_switch_type_name">
    ++    <item msgid="2952042958050315394">"mobile Datennutzung"</item>
    ++    <item msgid="75483255295529161">"WLAN"</item>
    ++    <item msgid="6862614801537202646">"Bluetooth"</item>
    ++    <item msgid="5447331121797802871">"Ethernet"</item>
    ++    <item msgid="8257233890381651999">"VPN"</item>
    ++  </string-array>
    ++    <string name="network_switch_type_name_unknown" msgid="4552612897806660656">"ein unbekannter Netzwerktyp"</string>
    +     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Es konnte keine WLAN-Verbindung hergestellt werden."</string>
    +     <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" hat eine schlechte Internetverbindung."</string>
    +     <string name="wifi_connect_alert_title" msgid="8455846016001810172">"Verbindung zulassen?"</string>
    +@@ -1153,7 +1165,6 @@
    +     <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"Zum Auswählen von Sprache und Layout tippen"</string>
    +     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
    +     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
    +-    <string name="candidates_style" msgid="4333913089637062257"><u>"Kandidaten"</u></string>
    +     <string name="ext_media_checking_notification_title" msgid="5734005953288045806">"<xliff:g id="NAME">%s</xliff:g> wird vorbereitet"</string>
    +     <string name="ext_media_checking_notification_message" msgid="4747432538578886744">"Nach Fehlern wird gesucht"</string>
    +     <string name="ext_media_new_notification_message" msgid="7589986898808506239">"Neue <xliff:g id="NAME">%s</xliff:g> entdeckt"</string>
    +@@ -1232,8 +1243,9 @@
    +     <string name="vpn_text_long" msgid="4907843483284977618">"Verbunden mit <xliff:g id="SESSION">%s</xliff:g>. Zum Verwalten des Netzwerks tippen"</string>
    +     <string name="vpn_lockdown_connecting" msgid="6443438964440960745">"Verbindung zu durchgehend aktivem VPN wird hergestellt…"</string>
    +     <string name="vpn_lockdown_connected" msgid="8202679674819213931">"Mit durchgehend aktivem VPN verbunden"</string>
    ++    <string name="vpn_lockdown_disconnected" msgid="4532298952570796327">"Verbindung zu durchgehend aktivem VPN getrennt"</string>
    +     <string name="vpn_lockdown_error" msgid="6009249814034708175">"Durchgehend aktives VPN – Verbindungsfehler"</string>
    +-    <string name="vpn_lockdown_config" msgid="4655589351146766608">"Zum Konfigurieren tippen"</string>
    ++    <string name="vpn_lockdown_config" msgid="5099330695245008680">"Zum Einrichten tippen"</string>
    +     <string name="upload_file" msgid="2897957172366730416">"Datei auswählen"</string>
    +     <string name="no_file_chosen" msgid="6363648562170759465">"Keine ausgewählt"</string>
    +     <string name="reset" msgid="2448168080964209908">"Zurücksetzen"</string>
    +@@ -1317,7 +1329,7 @@
    +     <string name="storage_usb_drive_label" msgid="4501418548927759953">"USB-Speichergerät von <xliff:g id="MANUFACTURER">%s</xliff:g>"</string>
    +     <string name="storage_usb" msgid="3017954059538517278">"USB-Speicher"</string>
    +     <string name="extract_edit_menu_button" msgid="8940478730496610137">"Bearbeiten"</string>
    +-    <string name="data_usage_warning_title" msgid="1955638862122232342">"Warnung zum Datenverbrauch"</string>
    ++    <string name="data_usage_warning_title" msgid="3620440638180218181">"Warnung zur Datennutzung"</string>
    +     <string name="data_usage_warning_body" msgid="6660692274311972007">"Für Nutzung und Einstellungen tippen."</string>
    +     <string name="data_usage_3g_limit_title" msgid="4361523876818447683">"2G-/3G-Datenlimit erreicht"</string>
    +     <string name="data_usage_4g_limit_title" msgid="4609566827219442376">"4G-Datenlimit erreicht"</string>
    +@@ -1636,6 +1648,7 @@
    +     <string name="search_language_hint" msgid="7042102592055108574">"Sprache eingeben"</string>
    +     <string name="language_picker_section_suggested" msgid="8414489646861640885">"Vorschläge"</string>
    +     <string name="language_picker_section_all" msgid="3097279199511617537">"Alle Sprachen"</string>
    ++    <string name="region_picker_section_all" msgid="8966316787153001779">"Alle Regionen"</string>
    +     <string name="locale_search_menu" msgid="2560710726687249178">"Suche"</string>
    +     <string name="work_mode_off_title" msgid="8954725060677558855">"Arbeitsmodus ist AUS"</string>
    +     <string name="work_mode_off_message" msgid="3286169091278094476">"Arbeitsprofil aktivieren, einschließlich Apps, Synchronisierung im Hintergrund und verknüpfter Funktionen."</string>
    +diff --git a/core/res/res/values-el/strings.xml b/core/res/res/values-el/strings.xml
    +index 3c6e832..9e41023 100644
    +--- a/core/res/res/values-el/strings.xml
    ++++ b/core/res/res/values-el/strings.xml
    +@@ -214,6 +214,7 @@
    +     <string name="global_actions" product="default" msgid="2406416831541615258">"Επιλογές τηλεφώνου"</string>
    +     <string name="global_action_lock" msgid="2844945191792119712">"Κλείδωμα οθόνης"</string>
    +     <string name="global_action_power_off" msgid="4471879440839879722">"Απενεργοποίηση"</string>
    ++    <string name="global_action_emergency" msgid="7112311161137421166">"Κλήση έκτακτης ανάγκης"</string>
    +     <string name="global_action_bug_report" msgid="7934010578922304799">"Αναφορά σφαλμάτων"</string>
    +     <string name="bugreport_title" msgid="2667494803742548533">"Λήψη αναφοράς σφάλματος"</string>
    +     <string name="bugreport_message" msgid="398447048750350456">"Θα συλλέξει πληροφορίες σχετικά με την τρέχουσα κατάσταση της συσκευής σας και θα τις στείλει μέσω μηνύματος ηλεκτρονικού ταχυδρομείου. Απαιτείται λίγος χρόνος για τη σύνταξη της αναφοράς σφάλματος και την αποστολή της. Κάντε λίγη υπομονή."</string>
    +@@ -249,7 +250,7 @@
    +     <string name="permgrouplab_calendar" msgid="5863508437783683902">"Ημερολόγιο"</string>
    +     <string name="permgroupdesc_calendar" msgid="3889615280211184106">"έχει πρόσβαση στο ημερολόγιό σας"</string>
    +     <string name="permgrouplab_sms" msgid="228308803364967808">"SMS"</string>
    +-    <string name="permgroupdesc_sms" msgid="4656988620100940350">"αποστολή και προβολή μηνυμάτων SMS"</string>
    ++    <string name="permgroupdesc_sms" msgid="4656988620100940350">"στέλνει και να διαβάζει μηνύματα SMS"</string>
    +     <string name="permgrouplab_storage" msgid="1971118770546336966">"Αποθηκευτικός χώρος"</string>
    +     <string name="permgroupdesc_storage" msgid="637758554581589203">"έχει πρόσβαση στις φωτογραφίες/πολυμέσα/αρχεία στη συσκευή σας"</string>
    +     <string name="permgrouplab_microphone" msgid="171539900250043464">"Μικρόφωνο"</string>
    +@@ -272,149 +273,149 @@
    +     <string name="capability_desc_canControlMagnification" msgid="4791858203568383773">"Ελέγξτε το επίπεδο ζουμ και τη θέση της οθόνης."</string>
    +     <string name="capability_title_canPerformGestures" msgid="7418984730362576862">"Εκτέλεση κινήσεων"</string>
    +     <string name="capability_desc_canPerformGestures" msgid="8296373021636981249">"Επιτρέπει το πάτημα, την ολίσθηση, το πλησίασμα και άλλες κινήσεις."</string>
    +-    <string name="permlab_statusBar" msgid="7417192629601890791">"απενεργοποίηση ή τροποποίηση γραμμής κατάστασης"</string>
    ++    <string name="permlab_statusBar" msgid="7417192629601890791">"απενεργοποιεί ή να τροποποιεί την γραμμή κατάστασης"</string>
    +     <string name="permdesc_statusBar" msgid="8434669549504290975">"Επιτρέπει στην εφαρμογή να απενεργοποιεί τη γραμμή κατάστασης ή να προσθέτει και να αφαιρεί εικονίδια συστήματος."</string>
    +-    <string name="permlab_statusBarService" msgid="4826835508226139688">"ορισμός ως γραμμής κατάστασης"</string>
    ++    <string name="permlab_statusBarService" msgid="4826835508226139688">"ορίζεται ως γραμμή κατάστασης"</string>
    +     <string name="permdesc_statusBarService" msgid="716113660795976060">"Επιτρέπει στην εφαρμογή να αποτελεί τη γραμμή κατάστασης."</string>
    +-    <string name="permlab_expandStatusBar" msgid="1148198785937489264">"ανάπτυξη/σύμπτυξη γραμμής κατάστασης"</string>
    ++    <string name="permlab_expandStatusBar" msgid="1148198785937489264">"αναπτύσσει/συμπτύσσει τη γραμμή κατάστασης"</string>
    +     <string name="permdesc_expandStatusBar" msgid="6917549437129401132">"Επιτρέπει στην εφαρμογή να αναπτύξει ή να συμπτύξει τη γραμμή κατάστασης."</string>
    +-    <string name="permlab_install_shortcut" msgid="4279070216371564234">"εγκατάσταση συντομεύσεων"</string>
    ++    <string name="permlab_install_shortcut" msgid="4279070216371564234">"εγκαθιστά συντομεύσεις"</string>
    +     <string name="permdesc_install_shortcut" msgid="8341295916286736996">"Επιτρέπει σε μια εφαρμογή την προσθήκη συντομεύσεων στην Αρχική οθόνη χωρίς την παρέμβαση του χρήστη."</string>
    +-    <string name="permlab_uninstall_shortcut" msgid="4729634524044003699">"κατάργηση εγκατάστασης συντομεύσεων"</string>
    ++    <string name="permlab_uninstall_shortcut" msgid="4729634524044003699">"καταργεί την εγκατάσταση συντομεύσεων"</string>
    +     <string name="permdesc_uninstall_shortcut" msgid="6745743474265057975">"Επιτρέπει στην εφαρμογή την κατάργηση συντομεύσεων από την Αρχική οθόνη χωρίς την παρέμβαση του χρήστη."</string>
    +-    <string name="permlab_processOutgoingCalls" msgid="3906007831192990946">"αναδρομολόγηση εξερχόμενων κλήσεων"</string>
    ++    <string name="permlab_processOutgoingCalls" msgid="3906007831192990946">"αναδρομολογεί τις εξερχόμενες κλήσεις"</string>
    +     <string name="permdesc_processOutgoingCalls" msgid="5156385005547315876">"Επιτρέπει στην εφαρμογή να βλέπει τον αριθμό που καλέσατε κατά τη διάρκεια μιας εξερχόμενης κλήσης με επιλογή ανακατεύθυνσης της κλήσης σε έναν διαφορετικό αριθμό ή διακοπής της κλήσης."</string>
    +-    <string name="permlab_receiveSms" msgid="8673471768947895082">"λήψη μηνυμάτων κειμένου (SMS)"</string>
    ++    <string name="permlab_receiveSms" msgid="8673471768947895082">"λαμβάνει μηνύματα κειμένου (SMS)"</string>
    +     <string name="permdesc_receiveSms" msgid="6424387754228766939">"Επιτρέπει στην εφαρμογή τη λήψη και την επεξεργασία μηνυμάτων SMS. Αυτό σημαίνει ότι η εφαρμογή θα μπορούσε να παρακολουθήσει ή να διαγράψει τα μηνύματα που αποστέλλονται στη συσκευή σας χωρίς αυτά να εμφανιστούν σε εσάς."</string>
    +-    <string name="permlab_receiveMms" msgid="1821317344668257098">"λήψη μηνυμάτων κειμένου (MMS)"</string>
    ++    <string name="permlab_receiveMms" msgid="1821317344668257098">"λαμβάνει μηνύματα κειμένου (MMS)"</string>
    +     <string name="permdesc_receiveMms" msgid="533019437263212260">"Επιτρέπει στην εφαρμογή τη λήψη και την επεξεργασία μηνυμάτων MMS. Αυτό σημαίνει ότι η εφαρμογή θα μπορούσε να παρακολουθήσει ή να διαγράψει τα μηνύματα που αποστέλλονται στη συσκευή σας χωρίς αυτά να εμφανιστούν σε εσάς."</string>
    +-    <string name="permlab_readCellBroadcasts" msgid="1598328843619646166">"ανάγνωση μηνυμάτων που έχουν μεταδοθεί μέσω κινητού τηλεφώνου"</string>
    ++    <string name="permlab_readCellBroadcasts" msgid="1598328843619646166">"διαβάζει μηνύματα που έχουν μεταδοθεί μέσω κινητού τηλεφώνου"</string>
    +     <string name="permdesc_readCellBroadcasts" msgid="6361972776080458979">"Επιτρέπει στην εφαρμογή την ανάγνωση μηνυμάτων που έχουν μεταδοθεί μέσω κινητού τηλεφώνου και έχουν ληφθεί από τη συσκευή σας. Ειδοποιήσεις που μεταδίδονται μέσω κινητού παραδίδονται σε ορισμένες τοποθεσίες για να σας προειδοποιήσουν για καταστάσεις έκτακτης ανάγκης. Κακόβουλες εφαρμογές ενδέχεται να παρεμποδίσουν την απόδοση ή τη λειτουργία της συσκευής σας κατά τη λήψη μετάδοσης μέσω κινητού σχετικά με μια επείγουσα κατάσταση."</string>
    +-    <string name="permlab_subscribedFeedsRead" msgid="4756609637053353318">"ανάγνωση ροών δεδομένων στις οποίες έχετε εγγραφεί"</string>
    ++    <string name="permlab_subscribedFeedsRead" msgid="4756609637053353318">"διαβάζει ροές δεδομένων στις οποίες έχετε εγγραφεί"</string>
    +     <string name="permdesc_subscribedFeedsRead" msgid="5557058907906144505">"Επιτρέπει στην εφαρμογή τη λήψη λεπτομερειών σχετικά με τις τρέχουσες συγχρονισμένες ροές δεδομένων."</string>
    +-    <string name="permlab_sendSms" msgid="7544599214260982981">"πραγματοποιεί αποστολή και προβολή μηνυμάτων SMS"</string>
    ++    <string name="permlab_sendSms" msgid="7544599214260982981">"στέλνει και να διαβάζει μηνύματα SMS"</string>
    +     <string name="permdesc_sendSms" msgid="7094729298204937667">"Επιτρέπει στην εφαρμογή των αποστολή μηνυμάτων SMS. Αυτό μπορεί να προκαλέσει μη αναμενόμενες χρεώσεις. Οι κακόβουλες εφαρμογές ενδέχεται να σας κοστίσουν χρήματα, αποστέλλοντας μηνύματα χωρίς την έγκρισή σας."</string>
    +-    <string name="permlab_readSms" msgid="8745086572213270480">"ανάγνωση των μηνυμάτων κειμένου σας (SMS ή MMS)"</string>
    ++    <string name="permlab_readSms" msgid="8745086572213270480">"διαβάζει τα μηνύματα κειμένου (SMS ή MMS)"</string>
    +     <string name="permdesc_readSms" product="tablet" msgid="2467981548684735522">"Επιτρέπει στην εφαρμογή την ανάγνωση μηνυμάτων SMS που είναι αποθηκευμένα στο tablet σας ή στην κάρτα σας SIM. Αυτό δίνει τη δυνατότητα στην εφαρμογή να διαβάζει όλα τα μηνύματα SMS, ανεξάρτητα από το περιεχόμενο ή το επίπεδο εμπιστευτικότητάς τους."</string>
    +     <string name="permdesc_readSms" product="tv" msgid="5102425513647038535">"Επιτρέπει στην εφαρμογή να διαβάζει μηνύματα SMS που έχουν αποθηκευτεί στην τηλεόραση ή στην κάρτα SIM. Έτσι, η εφαρμογή μπορεί να διαβάζει όλα τα μηνύματα SMS, ανεξαρτήτως περιεχομένου ή εμπιστευτικότητας."</string>
    +     <string name="permdesc_readSms" product="default" msgid="3695967533457240550">"Επιτρέπει στην εφαρμογή την ανάγνωση μηνυμάτων SMS που είναι αποθηκευμένα στο τηλέφωνό σας ή στην κάρτα σας SIM. Αυτό δίνει τη δυνατότητα στην εφαρμογή να διαβάζει όλα τα μηνύματα SMS, ανεξάρτητα από το περιεχόμενο ή το επίπεδο εμπιστευτικότητάς τους."</string>
    +-    <string name="permlab_receiveWapPush" msgid="5991398711936590410">"λήψη μηνυμάτων κειμένου (WAP)"</string>
    ++    <string name="permlab_receiveWapPush" msgid="5991398711936590410">"λαμβάνει μηνύματα κειμένου (WAP)"</string>
    +     <string name="permdesc_receiveWapPush" msgid="748232190220583385">"Επιτρέπει στην εφαρμογή τη λήψη και την επεξεργασία μηνυμάτων WAP. Αυτό σημαίνει ότι η εφαρμογή θα μπορούσε να παρακολουθήσει ή να διαγράψει τα μηνύματα που αποστέλλονται στη συσκευή σας χωρίς αυτά να εμφανιστούν σε εσάς."</string>
    +-    <string name="permlab_getTasks" msgid="6466095396623933906">"ανάκτηση εκτελούμενων εφαρμογών"</string>
    ++    <string name="permlab_getTasks" msgid="6466095396623933906">"ανακτά εκτελούμενες εφαρμογές"</string>
    +     <string name="permdesc_getTasks" msgid="7454215995847658102">"Επιτρέπει στην εφαρμογή την ανάκτηση πληροφοριών σχετικά με τρέχουσες και πρόσφατα εκτελούμενες εργασίες. Αυτό μπορεί να δίνει τη δυνατότητα στην εφαρμογή να ανακαλύπτει πληροφορίες σχετικά με το ποιες εφαρμογές χρησιμοποιούνται στη συσκευή."</string>
    +-    <string name="permlab_manageProfileAndDeviceOwners" msgid="7918181259098220004">"διαχείριση προφίλ και κατόχων συσκευής"</string>
    ++    <string name="permlab_manageProfileAndDeviceOwners" msgid="7918181259098220004">"διαχειρίζεται το προφίλ και τους κατόχους συσκευής"</string>
    +     <string name="permdesc_manageProfileAndDeviceOwners" msgid="106894851498657169">"Επιτρέπει σε εφαρμογές να ορίζουν τους κατόχους προφίλ και τον κάτοχο της συσκευής."</string>
    +-    <string name="permlab_reorderTasks" msgid="2018575526934422779">"αναδιάταξη εκτελούμενων εφαρμογών"</string>
    ++    <string name="permlab_reorderTasks" msgid="2018575526934422779">"αναδιατάσσει τις εκτελούμενες εφαρμογές"</string>
    +     <string name="permdesc_reorderTasks" msgid="7734217754877439351">"Επιτρέπει στην εφαρμογή τη μετακίνηση εργασιών στο προσκήνιο και το παρασκήνιο. Η εφαρμογή μπορεί να το κάνει αυτό χωρίς να καταχωρίσετε δεδομένα εισόδου."</string>
    +-    <string name="permlab_enableCarMode" msgid="5684504058192921098">"ενεργοποίηση λειτουργίας αυτοκινήτου"</string>
    ++    <string name="permlab_enableCarMode" msgid="5684504058192921098">"ενεργοποιεί την λειτουργία αυτοκινήτου"</string>
    +     <string name="permdesc_enableCarMode" msgid="4853187425751419467">"Επιτρέπει στην εφαρμογή την ενεργοποίηση της λειτουργίας αυτοκινήτου."</string>
    +-    <string name="permlab_killBackgroundProcesses" msgid="3914026687420177202">"κλείσιμο των άλλων εφαρμογών"</string>
    ++    <string name="permlab_killBackgroundProcesses" msgid="3914026687420177202">"κλείνει άλλες εφαρμογές"</string>
    +     <string name="permdesc_killBackgroundProcesses" msgid="4593353235959733119">"Επιτρέπει στην εφαρμογή τον τερματισμό των διεργασιών παρασκηνίου άλλων εφαρμογών. Αυτό μπορεί να προκαλεί τη διακοπή λειτουργίας άλλων εφαρμογών."</string>
    +-    <string name="permlab_systemAlertWindow" msgid="3543347980839518613">"σχεδίαση πάνω σε άλλες εφαρμογές"</string>
    ++    <string name="permlab_systemAlertWindow" msgid="3543347980839518613">"σχεδιάζει πάνω από άλλες εφαρμογές"</string>
    +     <string name="permdesc_systemAlertWindow" msgid="8584678381972820118">"Επιτρέπει στην εφαρμογή το σχεδιασμό πάνω σε άλλες εφαρμογές ή τμήματα του περιβάλλοντος χρήστη. Ενδέχεται να παρεμβαίνουν στη χρήση του περιβάλλοντος σε άλλες εφαρμογές ή να αλλάζουν τα στοιχεία που βλέπετε σε άλλες εφαρμογές."</string>
    +-    <string name="permlab_persistentActivity" msgid="8841113627955563938">"να εκτελείται συνεχώς η εφαρμογή"</string>
    ++    <string name="permlab_persistentActivity" msgid="8841113627955563938">"επιτρέπει στην εφαρμογή να εκτελείται συνεχώς"</string>
    +     <string name="permdesc_persistentActivity" product="tablet" msgid="8525189272329086137">"Επιτρέπει στην εφαρμογή να δημιουργεί μόνιμα τμήματα του εαυτού της στη μνήμη. Αυτό μπορεί να περιορίζει τη μνήμη που διατίθεται σε άλλες εφαρμογές, καθυστερώντας τη λειτουργία του tablet."</string>
    +     <string name="permdesc_persistentActivity" product="tv" msgid="5086862529499103587">"Επιτρέπει στην εφαρμογή να καθιστά τμήματά της μόνιμα στη μνήμη. Αυτό μπορεί να περιορίσει τη μνήμη που διατίθεται σε άλλες εφαρμογές, επιβραδύνοντας τη λειτουργία της τηλεόρασης."</string>
    +     <string name="permdesc_persistentActivity" product="default" msgid="4384760047508278272">"Επιτρέπει στην εφαρμογή να δημιουργεί μόνιμα τμήματα του εαυτού της στη μνήμη. Αυτό μπορεί να περιορίζει τη μνήμη που διατίθεται σε άλλες εφαρμογές, καθυστερώντας τη λειτουργία του τηλεφώνου."</string>
    +-    <string name="permlab_getPackageSize" msgid="7472921768357981986">"μέτρηση αποθηκευτικού χώρου εφαρμογής"</string>
    ++    <string name="permlab_getPackageSize" msgid="7472921768357981986">"υπολογίζει τον αποθηκευτικό χώρο εφαρμογής"</string>
    +     <string name="permdesc_getPackageSize" msgid="3921068154420738296">"Επιτρέπει στην εφαρμογή να ανακτήσει τα μεγέθη κώδικα, δεδομένων και προσωρινής μνήμης"</string>
    +     <string name="permlab_writeSettings" msgid="2226195290955224730">"τροποποίηση ρυθμίσεων συστήματος"</string>
    +     <string name="permdesc_writeSettings" msgid="7775723441558907181">"Επιτρέπει στην εφαρμογή την τροποποίηση των δεδομένων των ρυθμίσεων του συστήματος. Τυχόν κακόβουλες εφαρμογές ενδέχεται να καταστρέψουν τη διαμόρφωση του συστήματός σας."</string>
    +-    <string name="permlab_receiveBootCompleted" msgid="5312965565987800025">"εκτέλεση κατά την έναρξη"</string>
    ++    <string name="permlab_receiveBootCompleted" msgid="5312965565987800025">"εκτελείται κατά την έναρξη"</string>
    +     <string name="permdesc_receiveBootCompleted" product="tablet" msgid="7390304664116880704">"Επιτρέπει στην εφαρμογή να εκκινηθεί αμέσως μόλις ολοκληρωθεί η εκκίνηση του συστήματος. Αυτό ενδέχεται να καθυστερήσει την εκκίνηση του tablet και να προκαλέσει γενική μείωση της ταχύτητας λειτουργίας του tablet, καθώς η εφαρμογή θα εκτελείται συνεχώς."</string>
    +     <string name="permdesc_receiveBootCompleted" product="tv" msgid="4525890122209673621">"Επιτρέπει στην εφαρμογή να ξεκινάει μόλις ολοκληρώνεται η εκκίνηση του συστήματος. Αυτό μπορεί να καθυστερεί την εκκίνηση της τηλεόρασης και επιτρέπει στην εφαρμογή να επιβραδύνει τη συνολική λειτουργία του tablet, λόγω της συνεχούς προβολής."</string>
    +     <string name="permdesc_receiveBootCompleted" product="default" msgid="513950589102617504">"Επιτρέπει στην εφαρμογή να εκκινηθεί αμέσως μόλις ολοκληρωθεί η εκκίνηση του συστήματος. Αυτό ενδέχεται να καθυστερήσει την εκκίνηση του τηλεφώνου και να προκαλέσει γενική μείωση της ταχύτητας λειτουργίας του τηλεφώνου, καθώς η εφαρμογή θα εκτελείται συνεχώς."</string>
    +-    <string name="permlab_broadcastSticky" msgid="7919126372606881614">"αποστολή εκπομπής sticky"</string>
    ++    <string name="permlab_broadcastSticky" msgid="7919126372606881614">"στέλνει εκπομπή sticky"</string>
    +     <string name="permdesc_broadcastSticky" product="tablet" msgid="7749760494399915651">"Επιτρέπει στην εφαρμογή την αποστολή εκπομπών sticky, οι οποίες παραμένουν μετά το τέλος της εκπομπής. Η υπερβολική χρήση ενδέχεται να καταστήσει τη λειτουργία του tablet αργή ή ασταθή, προκαλώντας τη χρήση μεγάλου τμήματος της μνήμης."</string>
    +     <string name="permdesc_broadcastSticky" product="tv" msgid="6839285697565389467">"Επιτρέπει στην εφαρμογή να στέλνει εκπομπές που παραμένουν μετά το τέλος της μετάδοσης. Η υπερβολική χρήση μπορεί να καταστήσει αργή ή ασταθή τη λειτουργία της τηλεόρασης, προκαλώντας τη χρήση υπερβολικά μεγάλου μέρους της μνήμης."</string>
    +     <string name="permdesc_broadcastSticky" product="default" msgid="2825803764232445091">"Επιτρέπει στην εφαρμογή την αποστολή εκπομπών sticky, οι οποίες παραμένουν μετά το τέλος της εκπομπής. Η υπερβολική χρήση ενδέχεται να καταστήσει τη λειτουργία του τηλεφώνου αργή ή ασταθή, προκαλώντας τη χρήση μεγάλου τμήματος της μνήμης."</string>
    +-    <string name="permlab_readContacts" msgid="8348481131899886131">"ανάγνωση των επαφών σας"</string>
    ++    <string name="permlab_readContacts" msgid="8348481131899886131">"διαβάζει τις επαφές σας"</string>
    +     <string name="permdesc_readContacts" product="tablet" msgid="5294866856941149639">"Επιτρέπει στην εφαρμογή την ανάγνωση δεδομένων σχετικά με τις επαφές σας που είναι αποθηκευμένες στο tablet σας, συμπεριλαμβανομένης της συχνότητας με την οποία έχετε καλέσει συγκεκριμένα άτομα ή έχετε επικοινωνήσει μαζί τους μέσω ηλεκτρονικού ταχυδρομείου ή άλλου τρόπου. Αυτή η άδεια δίνει τη δυνατότητα σε εφαρμογές να αποθηκεύουν τα δεδομένα των επαφών σας και οι κακόβουλες εφαρμογές ενδέχεται να μοιράζονται δεδομένα επαφών χωρίς να το γνωρίζετε."</string>
    +     <string name="permdesc_readContacts" product="tv" msgid="1839238344654834087">"Επιτρέπει στην εφαρμογή να διαβάζει δεδομένα σχετικά με τις επαφές σας που είναι αποθηκευμένες στην τηλεόρασή σας, συμπεριλαμβανομένης της συχνότητας με την οποία έχετε καλέσει συγκεκριμένα άτομα ή έχετε επικοινωνήσει μαζί τους μέσω ηλεκτρονικού ταχυδρομείου ή άλλου τρόπου. Αυτό το δικαίωμα επιτρέπει στις εφαρμογές να αποθηκεύουν τα δεδομένα των επαφών σας. Επίσης, κακόβουλες εφαρμογές μπορεί να μοιραστούν δεδομένα επαφών χωρίς να το γνωρίζετε."</string>
    +     <string name="permdesc_readContacts" product="default" msgid="8440654152457300662">"Επιτρέπει στην εφαρμογή την ανάγνωση δεδομένων σχετικά με τις επαφές σας που είναι αποθηκευμένες στο τηλέφωνό σας, συμπεριλαμβανομένης της συχνότητας με την οποία έχετε καλέσει συγκεκριμένα άτομα ή έχετε επικοινωνήσει μαζί τους μέσω ηλεκτρονικού ταχυδρομείου ή άλλου τρόπου. Αυτή η άδεια δίνει τη δυνατότητα σε εφαρμογές να αποθηκεύουν τα δεδομένα των επαφών σας και οι κακόβουλες εφαρμογές ενδέχεται να μοιράζονται δεδομένα επαφών χωρίς να το γνωρίζετε."</string>
    +-    <string name="permlab_writeContacts" msgid="5107492086416793544">"τροποποίηση των επαφών σας"</string>
    ++    <string name="permlab_writeContacts" msgid="5107492086416793544">"τροποποιεί τις επαφές σας"</string>
    +     <string name="permdesc_writeContacts" product="tablet" msgid="897243932521953602">"Επιτρέπει στην εφαρμογή την τροποποίηση των δεδομένων σχετικά με τις επαφές σας που είναι αποθηκευμένες στο tablet σας, συμπεριλαμβανομένης της συχνότητας με την οποία έχετε καλέσει συγκεκριμένες επαφές ή έχετε επικοινωνήσει μαζί τους μέσω ηλεκτρονικού ταχυδρομείου ή άλλου τρόπου. Αυτή η άδεια δίνει τη δυνατότητα σε εφαρμογές να διαγράφουν δεδομένα επαφών."</string>
    +     <string name="permdesc_writeContacts" product="tv" msgid="5438230957000018959">"Επιτρέπει στην εφαρμογή να τροποποιεί τα δεδομένα σχετικά με τις επαφές που είναι αποθηκευμένες στην τηλεόρασή σας, συμπεριλαμβανομένης της συχνότητας με την οποία έχετε καλέσει συγκεκριμένες επαφές ή έχετε επικοινωνήσει μαζί τους μέσω ηλεκτρονικού ταχυδρομείου ή άλλου τρόπου. Αυτό το δικαίωμα δίνει τη δυνατότητα σε εφαρμογές να διαγράφουν δεδομένα επαφών."</string>
    +     <string name="permdesc_writeContacts" product="default" msgid="589869224625163558">"Επιτρέπει στην εφαρμογή την τροποποίηση των δεδομένων σχετικά με τις επαφές σας που είναι αποθηκευμένες στο τηλέφωνό σας, συμπεριλαμβανομένης της συχνότητας με την οποία έχετε καλέσει συγκεκριμένες επαφές ή έχετε επικοινωνήσει μαζί τους μέσω ηλεκτρονικού ταχυδρομείου ή άλλου τρόπου. Αυτή η άδεια δίνει τη δυνατότητα σε εφαρμογές να διαγράφουν δεδομένα επαφών."</string>
    +-    <string name="permlab_readCallLog" msgid="3478133184624102739">"ανάγνωση αρχείου καταγραφής κλήσεων"</string>
    ++    <string name="permlab_readCallLog" msgid="3478133184624102739">"διαβάζει το αρχείο καταγραφής κλήσεων"</string>
    +     <string name="permdesc_readCallLog" product="tablet" msgid="3700645184870760285">"Επιτρέπει στην εφαρμογή την ανάγνωση του αρχείου καταγραφής κλήσεων του tablet σας, συμπεριλαμβανομένων των δεδομένων σχετικά με τις εισερχόμενες και τις εξερχόμενες κλήσεις. Αυτή η άδεια δίνει τη δυνατότητα στις εφαρμογές να αποθηκεύει τα δεδομένα του αρχείου καταγραφής κλήσεων και οι κακόβουλες εφαρμογές ενδέχεται να μοιράζονται δεδομένα του αρχείου καταγραφής κλήσεων χωρίς να το γνωρίζετε."</string>
    +     <string name="permdesc_readCallLog" product="tv" msgid="5611770887047387926">"Επιτρέπει στην εφαρμογή να διαβάζει το αρχείο καταγραφής κλήσεων της τηλεόρασής σας, συμπεριλαμβανομένων δεδομένων σχετικά με τις εισερχόμενες και τις εξερχόμενες κλήσεις. Αυτό το δικαίωμα επιτρέπει στις εφαρμογές να αποθηκεύουν τα δεδομένα του αρχείου καταγραφής κλήσεων. Επίσης, κακόβουλες εφαρμογές μπορεί να μοιραστούν δεδομένα αρχείου καταγραφής κλήσεων χωρίς να το γνωρίζετε."</string>
    +     <string name="permdesc_readCallLog" product="default" msgid="5777725796813217244">"Επιτρέπει στην εφαρμογή την ανάγνωση του αρχείου καταγραφής κλήσεων του τηλεφώνου σας, συμπεριλαμβανομένων των δεδομένων σχετικά με τις εισερχόμενες και τις εξερχόμενες κλήσεις. Αυτή η άδεια δίνει τη δυνατότητα στις εφαρμογές να αποθηκεύει τα δεδομένα του αρχείου καταγραφής κλήσεων και οι κακόβουλες εφαρμογές ενδέχεται να μοιράζονται δεδομένα του αρχείου καταγραφής κλήσεων χωρίς να το γνωρίζετε."</string>
    +-    <string name="permlab_writeCallLog" msgid="8552045664743499354">"εγγραφή αρχείου καταγραφής κλήσεων"</string>
    ++    <string name="permlab_writeCallLog" msgid="8552045664743499354">"εγγράφει αρχείο καταγραφής κλήσεων"</string>
    +     <string name="permdesc_writeCallLog" product="tablet" msgid="6661806062274119245">"Επιτρέπει στην εφαρμογή να τροποποιεί το αρχείο καταγραφής κλήσεων του tablet σας, συμπεριλαμβανομένων των δεδομένων σχετικά με τις εισερχόμενες και τις εξερχόμενες κλήσεις. Οι κακόβουλες εφαρμογές μπορεί να το χρησιμοποιήσουν για να διαγράψουν ή να τροποποιήσουν το αρχείο καταγραφής κλήσεων."</string>
    +     <string name="permdesc_writeCallLog" product="tv" msgid="4225034892248398019">"Επιτρέπει στην εφαρμογή να τροποποιεί το αρχείο καταγραφής κλήσεων της τηλεόρασής σας, συμπεριλαμβανομένων των δεδομένων σχετικά με τις εισερχόμενες και τις εξερχόμενες κλήσεις. Κακόβουλες εφαρμογές μπορεί να χρησιμοποιήσουν αυτήν τη δυνατότητα, για να διαγράψουν ή να τροποποιήσουν το αρχείο καταγραφής κλήσεων."</string>
    +     <string name="permdesc_writeCallLog" product="default" msgid="683941736352787842">"Επιτρέπει στην εφαρμογή να τροποποιεί το αρχείο καταγραφής κλήσεων του τηλεφώνου σας, συμπεριλαμβανομένων των δεδομένων σχετικά με τις εισερχόμενες και τις εξερχόμενες κλήσεις. Οι κακόβουλες εφαρμογές μπορεί να το χρησιμοποιήσουν για να διαγράψουν ή να τροποποιήσουν το αρχείο καταγραφής κλήσεων."</string>
    +     <string name="permlab_bodySensors" msgid="4683341291818520277">"πρόσβαση στους αισθητήρες λειτουργιών (π.χ. παρακολούθηση καρδιακού παλμού)"</string>
    +     <string name="permdesc_bodySensors" product="default" msgid="4380015021754180431">"Επιτρέπει στην εφαρμογή να αποκτήσει πρόσβαση στα δεδομένα των αισθητήρων που παρακολουθούν τη φυσική σας κατάσταση, όπως τον καρδιακό ρυθμό σας."</string>
    +-    <string name="permlab_readCalendar" msgid="5972727560257612398">"ανάγνωση συμβάντων ημερολογίου και εμπιστευτικών πληροφοριών"</string>
    ++    <string name="permlab_readCalendar" msgid="5972727560257612398">"διαβάζει συμβάντα ημερολογίου και εμπιστευτικές πληροφορίες"</string>
    +     <string name="permdesc_readCalendar" product="tablet" msgid="4216462049057658723">"Επιτρέπει στην εφαρμογή την ανάγνωση όλων των συμβάντων ημερολογίου που είναι αποθηκευμένα στο tablet σας, συμπεριλαμβανομένων εκείνων των φίλων ή των συναδέλφων σας. Αυτό μπορεί να δίνει τη δυνατότητα στην εφαρμογή να μοιράζεται ή να αποθηκεύει τα δεδομένα του ημερολογίου σας, ανεξάρτητα από το βαθμό εμπιστευτικότητας ή ευαισθησίας τους."</string>
    +     <string name="permdesc_readCalendar" product="tv" msgid="3191352452242394196">"Επιτρέπει στην εφαρμογή να διαβάζει όλα τα συμβάντα ημερολογίου που είναι αποθηκευμένα στην τηλεόρασή σας, συμπεριλαμβανομένων εκείνων από τους φίλους ή τους συναδέλφους σας. Αυτό μπορεί να επιτρέψει στην εφαρμογή να μοιράζεται ή να αποθηκεύει τα δεδομένα ημερολογίου, ανεξαρτήτως εμπιστευτικότητας ή ευαισθησίας."</string>
    +     <string name="permdesc_readCalendar" product="default" msgid="7434548682470851583">"Επιτρέπει στην εφαρμογή την ανάγνωση όλων των συμβάντων ημερολογίου που είναι αποθηκευμένα στο τηλέφωνό σας, συμπεριλαμβανομένων εκείνων των φίλων ή των συναδέλφων σας. Αυτό μπορεί να δίνει τη δυνατότητα στην εφαρμογή να μοιράζεται ή να αποθηκεύει τα δεδομένα του ημερολογίου σας, ανεξάρτητα από το βαθμό εμπιστευτικότητας ή ευαισθησίας τους."</string>
    +-    <string name="permlab_writeCalendar" msgid="8438874755193825647">"προσθήκη ή τροποποίηση συμβάντων ημερολογίου και αποστολή μηνυμάτων ηλεκτρονικού ταχυδρομείου σε προσκεκλημένους χωρίς να το γνωρίζουν οι κάτοχοι"</string>
    ++    <string name="permlab_writeCalendar" msgid="8438874755193825647">"προσθέτει ή τροποποιεί συμβάντα ημερολογίου και να στέλνει μηνύματα ηλ. ταχυδρομείου σε προσκεκλημένους χωρίς να το γνωρίζουν οι κάτοχοι"</string>
    +     <string name="permdesc_writeCalendar" product="tablet" msgid="6679035520113668528">"Επιτρέπει στην εφαρμογή την προσθήκη, την κατάργηση και την αλλαγή συμβάντων που μπορείτε να τροποποιήσετε στο tablet σας, συμπεριλαμβανομένων εκείνων των φίλων ή των συναδέλφων σας. Αυτό μπορεί να επιτρέπει στην εφαρμογή να αποστέλλει μηνύματα που φαίνεται ότι προέρχονται από κατόχους ημερολογίων ή να τροποποιεί συμβάντα χωρίς να το γνωρίζουν οι κάτοχοι."</string>
    +     <string name="permdesc_writeCalendar" product="tv" msgid="1273290605500902507">"Επιτρέπει στην εφαρμογή να προσθέτει, να καταργεί και να αλλάζει συμβάντα που μπορείτε να τροποποιείτε στην τηλεόρασή σας, συμπεριλαμβανομένων όσων ανήκουν σε φίλους ή συναδέλφους. Αυτό ενδέχεται να επιτρέπει στην εφαρμογή να αποστέλλει μηνύματα τα οποία φαίνεται ότι προέρχονται από κατόχους ημερολογίου ή να τροποποιεί συμβάντα χωρίς να το γνωρίζουν οι κάτοχοί τους."</string>
    +     <string name="permdesc_writeCalendar" product="default" msgid="2324469496327249376">"Επιτρέπει στην εφαρμογή την προσθήκη, την κατάργηση και την αλλαγή συμβάντων που μπορείτε να τροποποιήσετε στο τηλέφωνό σας, συμπεριλαμβανομένων εκείνων των φίλων ή των συναδέλφων σας. Αυτό μπορεί να επιτρέπει στην εφαρμογή να αποστέλλει μηνύματα που φαίνεται ότι προέρχονται από κατόχους ημερολογίων ή να τροποποιεί συμβάντα χωρίς να το γνωρίζουν οι κάτοχοι."</string>
    +-    <string name="permlab_accessLocationExtraCommands" msgid="2836308076720553837">"πρόσβαση σε επιπλέον εντολές παρόχου τοποθεσίας"</string>
    ++    <string name="permlab_accessLocationExtraCommands" msgid="2836308076720553837">"έχει πρόσβαση σε επιπλέον εντολές παρόχου τοποθεσίας"</string>
    +     <string name="permdesc_accessLocationExtraCommands" msgid="6078307221056649927">"Επιτρέπει στην εφαρμογή την πρόσβαση σε επιπλέον εντολές παρόχου τοποθεσίας. Αυτό μπορεί να δώσει τη δυνατότητα στην εφαρμογή να παρέμβει στη λειτουργία του GPS ή άλλων πηγών τοποθεσίας."</string>
    +-    <string name="permlab_accessFineLocation" msgid="251034415460950944">"πρόσβαση στην ακριβή τοποθεσία (με βάση το GPS και το δίκτυο)"</string>
    ++    <string name="permlab_accessFineLocation" msgid="251034415460950944">"έχει πρόσβαση στην ακριβή τοποθεσία (με βάση το GPS και το δίκτυο)"</string>
    +     <string name="permdesc_accessFineLocation" msgid="5295047563564981250">"Επιτρέπει στην εφαρμογή να λαμβάνει την ακριβή θέση σας με τη χρήση του Παγκόσμιου Συστήματος Εντοπισμού (GPS) ή πηγών τοποθεσίας δικτύου, όπως κεραίες κινητής τηλεφωνίας και Wi-Fi. Αυτές οι υπηρεσίες τοποθεσίας πρέπει να είναι ενεργοποιημένες και διαθέσιμες στην συσκευή σας, ώστε να μπορούν να χρησιμοποιηθούν από την εφαρμογή. Οι εφαρμογές ενδέχεται να τις χρησιμοποιήσουν για να προσδιορίσουν τη θέση σας και ενδέχεται να καταναλώσουν επιπλέον ισχύ μπαταρίας."</string>
    +-    <string name="permlab_accessCoarseLocation" msgid="7715277613928539434">"πρόσβαση στην τοποθεσία κατά προσέγγιση (με βάση το δίκτυο)"</string>
    ++    <string name="permlab_accessCoarseLocation" msgid="7715277613928539434">"έχει πρόσβαση στην τοποθεσία κατά προσέγγιση (με βάση το δίκτυο)"</string>
    +     <string name="permdesc_accessCoarseLocation" msgid="2538200184373302295">"Επιτρέπει στην εφαρμογή τη λήψη της κατά προσέγγιση τοποθεσίας σας. Αυτή η τοποθεσία προκύπτει από τις υπηρεσίες τοποθεσίας με τη χρήση πηγών τοποθεσίας δικτύου, όπως κεραίες κινητής τηλεφωνίας και Wi-Fi. Αυτές οι υπηρεσίες τοποθεσίας πρέπει να είναι ενεργοποιημένες και διαθέσιμες στην συσκευή σας, ώστε να μπορούν να χρησιμοποιηθούν από την εφαρμογή. Οι εφαρμογές ενδέχεται να τις χρησιμοποιήσουν για να προσδιορίσουν κατά προσέγγιση τη θέση σας."</string>
    +-    <string name="permlab_modifyAudioSettings" msgid="6095859937069146086">"αλλαγή των ρυθμίσεων ήχου"</string>
    ++    <string name="permlab_modifyAudioSettings" msgid="6095859937069146086">"αλλάζει τις ρυθμίσεις ήχου"</string>
    +     <string name="permdesc_modifyAudioSettings" msgid="3522565366806248517">"Επιτρέπει στην εφαρμογή την τροποποίηση καθολικών ρυθμίσεων ήχου, όπως η ένταση και ποιο ηχείο χρησιμοποιείται για έξοδο."</string>
    +-    <string name="permlab_recordAudio" msgid="3876049771427466323">"εγγραφή ήχου"</string>
    ++    <string name="permlab_recordAudio" msgid="3876049771427466323">"εγγράφει ήχο"</string>
    +     <string name="permdesc_recordAudio" msgid="4906839301087980680">"Επιτρέπει στην εφαρμογή την εγγραφή ήχου με το μικρόφωνο. Αυτή η άδεια δίνει τη δυνατότητα στην εφαρμογή να εγγράφει ήχο ανά πάσα στιγμή χωρίς την έγκρισή σας."</string>
    +     <string name="permlab_sim_communication" msgid="2935852302216852065">"στέλνει εντολές στην κάρτα SIM"</string>
    +     <string name="permdesc_sim_communication" msgid="5725159654279639498">"Επιτρέπει στην εφαρμογή την αποστολή εντολών στην κάρτα SIM. Αυτό είναι εξαιρετικά επικίνδυνο."</string>
    +-    <string name="permlab_camera" msgid="3616391919559751192">"λήψη φωτογραφιών και βίντεο"</string>
    ++    <string name="permlab_camera" msgid="3616391919559751192">"κάνει λήψη φωτογραφιών και βίντεο"</string>
    +     <string name="permdesc_camera" msgid="8497216524735535009">"Επιτρέπει στην εφαρμογή τη λήψη φωτογραφιών και βίντεο με τη φωτογραφική μηχανή. Αυτή η άδεια δίνει τη δυνατότητα στην εφαρμογή να χρησιμοποιεί τη φωτογραφική μηχανή ανά πάσα στιγμή χωρίς την έγκρισή σας."</string>
    +-    <string name="permlab_vibrate" msgid="7696427026057705834">"έλεγχος δόνησης"</string>
    ++    <string name="permlab_vibrate" msgid="7696427026057705834">"ελέγχει τη δόνηση"</string>
    +     <string name="permdesc_vibrate" msgid="6284989245902300945">"Επιτρέπει στην εφαρμογή τον έλεγχο της δόνησης."</string>
    +-    <string name="permlab_callPhone" msgid="3925836347681847954">"απευθείας κλήση τηλεφωνικών αριθμών"</string>
    ++    <string name="permlab_callPhone" msgid="3925836347681847954">"πραγματοποιεί απευθείας κλήση τηλεφωνικών αριθμών"</string>
    +     <string name="permdesc_callPhone" msgid="3740797576113760827">"Επιτρέπει στην εφαρμογή την κλήση αριθμών τηλεφώνου χωρίς δική σας παρέμβαση. Αυτό μπορεί να προκαλέσει μη αναμενόμενες χρεώσεις ή κλήσεις. Έχετε υπόψη ότι δεν επιτρέπεται στην εφαρμογή η κλήση αριθμών έκτακτης ανάγκης. Οι κακόβουλες εφαρμογές ενδέχεται να σας κοστίσουν χρήματα, πραγματοποιώντας κλήσεις χωρίς την έγκρισή σας."</string>
    +-    <string name="permlab_accessImsCallService" msgid="3574943847181793918">"πρόσβαση στην υπηρεσία κλήσεων της IMS"</string>
    ++    <string name="permlab_accessImsCallService" msgid="3574943847181793918">"έχει πρόσβαση στην υπηρεσία κλήσεων της IMS"</string>
    +     <string name="permdesc_accessImsCallService" msgid="8992884015198298775">"Επιτρέπει στην εφαρμογή τη χρήση της υπηρεσίας IMS για την πραγματοποίηση κλήσεων χωρίς τη δική σας παρέμβαση."</string>
    +-    <string name="permlab_readPhoneState" msgid="9178228524507610486">"ανάγνωση κατάστασης και ταυτότητας τηλεφώνου"</string>
    ++    <string name="permlab_readPhoneState" msgid="9178228524507610486">"διαβάζει την κατάσταση και ταυτότητα τηλεφώνου"</string>
    +     <string name="permdesc_readPhoneState" msgid="1639212771826125528">"Επιτρέπει στην εφαρμογή την πρόσβαση στις λειτουργίες τηλεφώνου της συσκευής. Αυτή η άδεια δίνει τη δυνατότητα στην εφαρμογή να καθορίζει τον αριθμό τηλεφώνου και τα αναγνωριστικά συσκευών, εάν μια κλήση είναι ενεργή, καθώς και τον απομακρυσμένο αριθμό που συνδέεται από μια κλήση."</string>
    +-    <string name="permlab_wakeLock" product="tablet" msgid="1531731435011495015">"παρεμπόδιση μετάβασης του tablet σε κατάσταση αδράνειας"</string>
    +-    <string name="permlab_wakeLock" product="tv" msgid="2601193288949154131">"αποτροπή μετάβασης της τηλεόρασης στην κατάσταση αδράνειας"</string>
    +-    <string name="permlab_wakeLock" product="default" msgid="573480187941496130">"παρεμπόδιση μετάβασης του τηλεφώνου σε κατάσταση αδράνειας"</string>
    ++    <string name="permlab_wakeLock" product="tablet" msgid="1531731435011495015">"αποτρέπει την μετάβαση του tablet σε κατάσταση αδράνειας"</string>
    ++    <string name="permlab_wakeLock" product="tv" msgid="2601193288949154131">"αποτρέπει την μετάβαση της τηλεόρασης σε κατάσταση αδράνειας"</string>
    ++    <string name="permlab_wakeLock" product="default" msgid="573480187941496130">"αποτρέπει το τηλεφώνο να μεταβεί σε κατάσταση αδράνειας"</string>
    +     <string name="permdesc_wakeLock" product="tablet" msgid="7311319824400447868">"Επιτρέπει στην εφαρμογή την παρεμπόδιση της μετάβασης του tablet σε κατάσταση αδράνειας."</string>
    +     <string name="permdesc_wakeLock" product="tv" msgid="3208534859208996974">"Επιτρέπει στην εφαρμογή να εμποδίζει τη μετάβαση της τηλεόρασης στην κατάσταση αδράνειας."</string>
    +     <string name="permdesc_wakeLock" product="default" msgid="8559100677372928754">"Επιτρέπει στην εφαρμογή την παρεμπόδιση της μετάβασης του τηλεφώνου σε κατάσταση αδράνειας."</string>
    +-    <string name="permlab_transmitIr" msgid="7545858504238530105">"μετάδοση υπερύθρων"</string>
    ++    <string name="permlab_transmitIr" msgid="7545858504238530105">"μεταδίδει με υπερύθρες"</string>
    +     <string name="permdesc_transmitIr" product="tablet" msgid="5358308854306529170">"Επιτρέπει στην εφαρμογή να χρησιμοποιεί τον πομπό υπερύθρων του tablet."</string>
    +     <string name="permdesc_transmitIr" product="tv" msgid="3926790828514867101">"Επιτρέπει στην εφαρμογή να χρησιμοποιεί τον πομπό υπερύθρων της τηλεόρασης."</string>
    +     <string name="permdesc_transmitIr" product="default" msgid="7957763745020300725">"Επιτρέπει στην εφαρμογή να χρησιμοποιεί τον πομπό υπερύθρων του τηλεφώνου."</string>
    +-    <string name="permlab_setWallpaper" msgid="6627192333373465143">"ορισμός ταπετσαρίας"</string>
    ++    <string name="permlab_setWallpaper" msgid="6627192333373465143">"ορίζει ταπετσαρία"</string>
    +     <string name="permdesc_setWallpaper" msgid="7373447920977624745">"Επιτρέπει στην εφαρμογή τον ορισμό της ταπετσαρίας συστήματος."</string>
    +-    <string name="permlab_setWallpaperHints" msgid="3278608165977736538">"ρύθμιση του μεγέθους της ταπετσαρίας σας"</string>
    ++    <string name="permlab_setWallpaperHints" msgid="3278608165977736538">"ρυθμίζει το μέγεθος της ταπετσαρίας"</string>
    +     <string name="permdesc_setWallpaperHints" msgid="8235784384223730091">"Επιτρέπει στην εφαρμογή τον ορισμό συμβουλών μεγέθους ταπετσαρίας συστήματος."</string>
    +-    <string name="permlab_setTimeZone" msgid="2945079801013077340">"ορισμός ζώνης ώρας"</string>
    ++    <string name="permlab_setTimeZone" msgid="2945079801013077340">"ορίζει τη ζώνης ώρας"</string>
    +     <string name="permdesc_setTimeZone" product="tablet" msgid="1676983712315827645">"Επιτρέπει στην εφαρμογή την αλλαγή της ζώνης ώρας του tablet."</string>
    +     <string name="permdesc_setTimeZone" product="tv" msgid="888864653946175955">"Επιτρέπει στην εφαρμογή να αλλάζει τη ζώνη ώρας της τηλεόρασης."</string>
    +     <string name="permdesc_setTimeZone" product="default" msgid="4499943488436633398">"Επιτρέπει στην εφαρμογή την αλλαγή της ζώνης ώρας του τηλεφώνου."</string>
    +-    <string name="permlab_getAccounts" msgid="1086795467760122114">"εύρεση λογαριασμών στη συσκευή"</string>
    ++    <string name="permlab_getAccounts" msgid="1086795467760122114">"βρίσκει λογαριασμούς στη συσκευή"</string>
    +     <string name="permdesc_getAccounts" product="tablet" msgid="2741496534769660027">"Επιτρέπει στην εφαρμογή τη λήψη της λίστας λογαριασμών που υπάρχουν στο tablet. Μπορεί να περιλαμβάνονται τυχόν λογαριασμοί που δημιουργήθηκαν από εφαρμογές που έχετε εγκαταστήσει."</string>
    +     <string name="permdesc_getAccounts" product="tv" msgid="4190633395633907543">"Επιτρέπει στην εφαρμογή να λαμβάνει τη λίστα λογαριασμών που γνωρίζει η τηλεόραση. Αυτό μπορεί να περιλαμβάνει λογαριασμούς που δημιουργούνται από λογαριασμούς που έχετε εγκαταστήσει."</string>
    +     <string name="permdesc_getAccounts" product="default" msgid="3448316822451807382">"Επιτρέπει στην εφαρμογή τη λήψη της λίστας λογαριασμών που υπάρχουν στο τηλέφωνο. Μπορεί να περιλαμβάνονται τυχόν λογαριασμοί που δημιουργήθηκαν από εφαρμογές που έχετε εγκαταστήσει."</string>
    +-    <string name="permlab_accessNetworkState" msgid="4951027964348974773">"προβολή συνδέσεων δικτύου"</string>
    ++    <string name="permlab_accessNetworkState" msgid="4951027964348974773">"βλέπει τις συνδέσεις δικτύου"</string>
    +     <string name="permdesc_accessNetworkState" msgid="8318964424675960975">"Επιτρέπει στην εφαρμογή την προβολή πληροφοριών σχετικά με συνδέσεις δικτύου, όπως ποια δίκτυα υπάρχουν και είναι συνδεδεμένα."</string>
    +-    <string name="permlab_createNetworkSockets" msgid="7934516631384168107">"πλήρης πρόσβαση στο δίκτυο"</string>
    ++    <string name="permlab_createNetworkSockets" msgid="7934516631384168107">"έχει πλήρη πρόσβαση στο δίκτυο"</string>
    +     <string name="permdesc_createNetworkSockets" msgid="3403062187779724185">"Επιτρέπει στην εφαρμογή τη δημιουργία θέσεων δικτύου και τη χρήση προσαρμοσμένων πρωτοκόλλων δικτύου. Το πρόγραμμα περιήγησης και άλλες εφαρμογές παρέχουν μέσα για την αποστολή δεδομένων στο διαδίκτυο, επομένως η συγκεκριμένη άδεια δεν είναι απαραίτητη για την αποστολή δεδομένων στο διαδίκτυο."</string>
    +-    <string name="permlab_changeNetworkState" msgid="958884291454327309">"αλλαγή συνδεσιμότητας δικτύου"</string>
    ++    <string name="permlab_changeNetworkState" msgid="958884291454327309">"αλλάζει την συνδεσιμότητα δικτύου"</string>
    +     <string name="permdesc_changeNetworkState" msgid="6789123912476416214">"Επιτρέπει στην εφαρμογή την αλλαγή της κατάστασης συνδεσιμότητας δικτύου."</string>
    +-    <string name="permlab_changeTetherState" msgid="5952584964373017960">"αλλαγή συνδεσιμότητας μέσω σύνδεσης με κινητή συσκευή"</string>
    ++    <string name="permlab_changeTetherState" msgid="5952584964373017960">"αλλάζει συνδεσιμότητα μέσω σύνδεσης με κινητή συσκευή"</string>
    +     <string name="permdesc_changeTetherState" msgid="1524441344412319780">"Επιτρέπει στην εφαρμογή την αλλαγή της κατάστασης συνδεσιμότητας δικτύου."</string>
    +-    <string name="permlab_accessWifiState" msgid="5202012949247040011">"προβολή συνδέσεων Wi-Fi"</string>
    ++    <string name="permlab_accessWifiState" msgid="5202012949247040011">"βλέπει τις συνδέσεις Wi-Fi"</string>
    +     <string name="permdesc_accessWifiState" msgid="5002798077387803726">"Επιτρέπει στην εφαρμογή την προβολή πληροφοριών σχετικά με τη δικτύωση Wi-Fi, όπως εάν το Wi-Fi είναι ενεργοποιημένο και τα ονόματα των συνδεδεμένων συσκευών Wi-Fi."</string>
    +-    <string name="permlab_changeWifiState" msgid="6550641188749128035">"σύνδεση και αποσύνδεση από το Wi-Fi"</string>
    ++    <string name="permlab_changeWifiState" msgid="6550641188749128035">"συνδέεται/αποσυνδέεται από το Wi-Fi"</string>
    +     <string name="permdesc_changeWifiState" msgid="7137950297386127533">"Επιτρέπει στην εφαρμογή τη σύνδεση σε σημεία πρόσβασης Wi-Fi και την αποσύνδεση από αυτά, καθώς και την πραγματοποίηση αλλαγών σε διαμόρφωση συσκευών για δίκτυα Wi-Fi."</string>
    +-    <string name="permlab_changeWifiMulticastState" msgid="1368253871483254784">"να επιτρέπεται η λήψη πολλαπλής διανομής Wi-Fi"</string>
    ++    <string name="permlab_changeWifiMulticastState" msgid="1368253871483254784">"επιτρέπει την λήψη πολλαπλής διανομής Wi-Fi"</string>
    +     <string name="permdesc_changeWifiMulticastState" product="tablet" msgid="7969774021256336548">"Επιτρέπει στην εφαρμογή τη λήψη πακέτων που αποστέλλονται σε όλες τις συσκευές σε ένα δίκτυο Wi-Fi, με χρήση διευθύνσεων πολλαπλής διανομής και όχι απλώς στο tablet σας. Χρησιμοποιεί περισσότερη ενέργεια σε σχέση με τη λειτουργία χωρίς πολλαπλή διανομή."</string>
    +     <string name="permdesc_changeWifiMulticastState" product="tv" msgid="9031975661145014160">"Επιτρέπει στην εφαρμογή να λαμβάνει πακέτα που αποστέλλονται σε όλες τις συσκευές σε ένα δίκτυο Wi-Fi, χρησιμοποιώντας διευθύνσεις multicast και όχι μόνο την τηλεόρασή σας. Χρησιμοποιεί περισσότερη ενέργεια από τη λειτουργία χωρίς multicast."</string>
    +     <string name="permdesc_changeWifiMulticastState" product="default" msgid="6851949706025349926">"Επιτρέπει στην εφαρμογή τη λήψη πακέτων που αποστέλλονται σε όλες τις συσκευές σε ένα δίκτυο Wi-Fi, με χρήση διευθύνσεων πολλαπλής διανομής και όχι απλώς στο τηλέφωνό σας. Χρησιμοποιεί περισσότερη ενέργεια σε σχέση με τη λειτουργία χωρίς πολλαπλή διανομή."</string>
    +-    <string name="permlab_bluetoothAdmin" msgid="6006967373935926659">"πρόσβαση στις ρυθμίσεις Bluetooth"</string>
    ++    <string name="permlab_bluetoothAdmin" msgid="6006967373935926659">"διαβάζει τις ρυθμίσεις Bluetooth"</string>
    +     <string name="permdesc_bluetoothAdmin" product="tablet" msgid="6921177471748882137">"Επιτρέπει στην εφαρμογή τη διαμόρφωση του τοπικού tablet Bluetooth, τον εντοπισμό και τη σύζευξη με απομακρυσμένες συσκευές."</string>
    +     <string name="permdesc_bluetoothAdmin" product="tv" msgid="3373125682645601429">"Επιτρέπει στην εφαρμογή να διαμορφώνει το τοπικό Bluetooth στην τηλεόραση, καθώς και να ανακαλύπτει απομακρυσμένες συσκευές και να συνδέεται μαζί τους."</string>
    +     <string name="permdesc_bluetoothAdmin" product="default" msgid="8931682159331542137">"Επιτρέπει στην εφαρμογή τη διαμόρφωση του τοπικού tablet Bluetooth, τον εντοπισμό και τη σύζευξη με απομακρυσμένες συσκευές."</string>
    +@@ -424,17 +425,17 @@
    +     <string name="permdesc_changeWimaxState" product="tablet" msgid="3156456504084201805">"Επιτρέπει στην εφαρμογή τη σύνδεση στο tablet και την αποσύνδεση από αυτό, από δίκτυα WiMAX."</string>
    +     <string name="permdesc_changeWimaxState" product="tv" msgid="6022307083934827718">"Επιτρέπει στην εφαρμογή να συνδέει και να αποσυνδέει την τηλεόραση από δίκτυα WiMAX."</string>
    +     <string name="permdesc_changeWimaxState" product="default" msgid="697025043004923798">"Επιτρέπει στην εφαρμογή τη σύνδεση στο τηλέφωνο και την αποσύνδεση από αυτό, από δίκτυα WiMAX."</string>
    +-    <string name="permlab_bluetooth" msgid="6127769336339276828">"σύζευξη με συσκευές Bluetooth"</string>
    ++    <string name="permlab_bluetooth" msgid="6127769336339276828">"πραγματοποιεί σύζευξη με συσκευές Bluetooth"</string>
    +     <string name="permdesc_bluetooth" product="tablet" msgid="3480722181852438628">"Επιτρέπει στην εφαρμογή να προβάλλει τη διαμόρφωση του Bluetooth στο tablet, καθώς και να πραγματοποιεί και να αποδέχεται συνδέσεις με συνδεδεμένες συσκευές."</string>
    +     <string name="permdesc_bluetooth" product="tv" msgid="3974124940101104206">"Επιτρέπει στην εφαρμογή να προβάλλει τη διαμόρφωση του Bluetooth στην τηλεόραση, καθώς και να δημιουργεί και να αποδέχεται συνδέσεις με συσκευές σε σύζευξη."</string>
    +     <string name="permdesc_bluetooth" product="default" msgid="3207106324452312739">"Επιτρέπει στην εφαρμογή να προβάλλει τη διαμόρφωση του Bluetooth στο τηλέφωνο, καθώς και να πραγματοποιεί και να αποδέχεται συνδέσεις με συνδεδεμένες συσκευές."</string>
    +-    <string name="permlab_nfc" msgid="4423351274757876953">"έλεγχος Επικοινωνίας κοντινού πεδίου (Near Field Communication)"</string>
    ++    <string name="permlab_nfc" msgid="4423351274757876953">"ελέγχει την Επικοινωνία κοντινού πεδίου (FNC)"</string>
    +     <string name="permdesc_nfc" msgid="7120611819401789907">"Επιτρέπει στην εφαρμογή την επικοινωνία με ετικέτες, κάρτες και αναγνώστες της Επικοινωνίας κοντινού πεδίου (NFC)."</string>
    +-    <string name="permlab_disableKeyguard" msgid="3598496301486439258">"απενεργοποίηση κλειδώματος οθόνης"</string>
    ++    <string name="permlab_disableKeyguard" msgid="3598496301486439258">"απενεργοποιεί το κλείδωμα οθόνης"</string>
    +     <string name="permdesc_disableKeyguard" msgid="6034203065077122992">"Επιτρέπει στην εφαρμογή την απενεργοποίηση του κλειδώματος πληκτρολογίου και άλλης σχετικής ασφάλειας με κωδικό πρόσβασης. Για παράδειγμα, το κλείδωμα πληκτρολογίου στο τηλέφωνο απενεργοποιείται όταν λαμβάνεται εισερχόμενη τηλεφωνική κλήση και ενεργοποιείται ξανά όταν η κλήση τερματιστεί."</string>
    +-    <string name="permlab_manageFingerprint" msgid="5640858826254575638">"διαχείριση εξοπλισμού μοναδικού χαρακτηριστικού"</string>
    ++    <string name="permlab_manageFingerprint" msgid="5640858826254575638">"διαχειρίζεται τον εξοπλισμό δακτυλικού αποτυπώματος"</string>
    +     <string name="permdesc_manageFingerprint" msgid="178208705828055464">"Επιτρέπει στην εφαρμογή να επικαλείται μεθόδους για την προσθήκη και τη διαγραφή προτύπων μοναδικού χαρακτηριστικού για χρήση."</string>
    +-    <string name="permlab_useFingerprint" msgid="3150478619915124905">"χρήση εξοπλισμού μοναδικού χαρακτηριστικού"</string>
    ++    <string name="permlab_useFingerprint" msgid="3150478619915124905">"χρησιμοποιεί τον εξοπλισμό δακτυλικού αποτυπώματος"</string>
    +     <string name="permdesc_useFingerprint" msgid="9165097460730684114">"Επιτρέπει στην εφαρμογή να χρησιμοποιεί εξοπλισμό μοναδικού χαρακτηριστικού για έλεγχο ταυτότητας"</string>
    +     <string name="fingerprint_acquired_partial" msgid="735082772341716043">"Εντοπίστηκε μερικό μοναδικό χαρακτηριστικό. Δοκιμάστε ξανά."</string>
    +     <string name="fingerprint_acquired_insufficient" msgid="4596546021310923214">"Δεν ήταν δυνατή η επεξεργασία του μοναδικού χαρακτηριστικού. Δοκιμάστε ξανά."</string>
    +@@ -453,65 +454,65 @@
    +   <string-array name="fingerprint_error_vendor">
    +   </string-array>
    +     <string name="fingerprint_icon_content_description" msgid="2340202869968465936">"Εικονίδιο δακτυλικών αποτυπωμάτων"</string>
    +-    <string name="permlab_readSyncSettings" msgid="6201810008230503052">"ανάγνωση ρυθμίσεων συγχρονισμού"</string>
    ++    <string name="permlab_readSyncSettings" msgid="6201810008230503052">"διαβάζει τις ρυθμίσεις συγχρονισμού"</string>
    +     <string name="permdesc_readSyncSettings" msgid="2706745674569678644">"Επιτρέπει στην εφαρμογή την ανάγνωση των ρυθμίσεων συγχρονισμού για έναν λογαριασμό. Για παράδειγμα, αυτό μπορεί να καθορίσει εάν η εφαρμογή \"Άτομα\" είναι συγχρονισμένη με έναν λογαριασμό."</string>
    +-    <string name="permlab_writeSyncSettings" msgid="5408694875793945314">"εναλλαγή ενεργοποίησης και απενεργοποίησης συγχρονισμού"</string>
    ++    <string name="permlab_writeSyncSettings" msgid="5408694875793945314">"ενεργοποιεί/απενεργοποιεί τον συγχρονισμό"</string>
    +     <string name="permdesc_writeSyncSettings" msgid="8956262591306369868">"Επιτρέπει σε μια εφαρμογή την τροποποίηση των ρυθμίσεων συγχρονισμού για έναν λογαριασμό. Για παράδειγμα, αυτό μπορεί να χρησιμοποιηθεί για να ενεργοποιηθεί ο συγχρονισμός της εφαρμογής \"Άτομα\" με έναν λογαριασμό."</string>
    +-    <string name="permlab_readSyncStats" msgid="7396577451360202448">"ανάγνωση στατιστικών συγχρονισμού"</string>
    ++    <string name="permlab_readSyncStats" msgid="7396577451360202448">"διαβάζει στατιστικά στοιχεία συγχρονισμού"</string>
    +     <string name="permdesc_readSyncStats" msgid="1510143761757606156">"Επιτρέπει σε μια εφαρμογή την ανάγνωση των στατιστικών στοιχείων συγχρονισμού για έναν λογαριασμό, συμπεριλαμβανομένων του ιστορικού των συμβάντων συγχρονισμού και του όγκου των δεδομένων που συγχρονίζονται."</string>
    +     <string name="permlab_sdcardRead" product="nosdcard" msgid="367275095159405468">"ανάγν. περιεχ. αποθηκ. χώρ.USB"</string>
    +-    <string name="permlab_sdcardRead" product="default" msgid="2188156462934977940">"ανάγνωση του περιεχομένου της κάρτας SD"</string>
    ++    <string name="permlab_sdcardRead" product="default" msgid="2188156462934977940">"διαβάζει το περιεχομένο της κάρτας SD"</string>
    +     <string name="permdesc_sdcardRead" product="nosdcard" msgid="3446988712598386079">"Επιτρέπει στην εφαρμογή την ανάγνωση του περιεχομένου του αποθηκευτικού σας χώρου USB."</string>
    +     <string name="permdesc_sdcardRead" product="default" msgid="2607362473654975411">"Επιτρέπει στην εφαρμογή την ανάγνωση του περιεχομένου της κάρτας SD."</string>
    +-    <string name="permlab_sdcardWrite" product="nosdcard" msgid="8485979062254666748">"τροποποίηση ή διαγραφή του USB"</string>
    +-    <string name="permlab_sdcardWrite" product="default" msgid="8805693630050458763">"τροποποίηση ή διαγραφή των περιεχομένων της κάρτας SD"</string>
    ++    <string name="permlab_sdcardWrite" product="nosdcard" msgid="8485979062254666748">"τροποποιεί/διαγράφει το USB"</string>
    ++    <string name="permlab_sdcardWrite" product="default" msgid="8805693630050458763">"τροποποιεί ή διαγράφει τα περιεχόμενα της κάρτας SD"</string>
    +     <string name="permdesc_sdcardWrite" product="nosdcard" msgid="6175406299445710888">"Επιτρέπει στην εφαρμογή την εγγραφή στον αποθηκευτικό χώρο USB."</string>
    +     <string name="permdesc_sdcardWrite" product="default" msgid="4337417790936632090">"Επιτρέπει στην εφαρμογή την εγγραφή στην κάρτα SD."</string>
    +-    <string name="permlab_use_sip" msgid="2052499390128979920">"πραγματοποίηση/λήψη κλήσεων SIP"</string>
    ++    <string name="permlab_use_sip" msgid="2052499390128979920">"πραγματοποιεί/λαμβάνει κλήσεις SIP"</string>
    +     <string name="permdesc_use_sip" msgid="2297804849860225257">"Επιτρέπει στην εφαρμογή να πραγματοποιεί και να λαμβάνει κλήσεις SIP."</string>
    +-    <string name="permlab_register_sim_subscription" msgid="3166535485877549177">"εγγραφή νέων συνδέσεων SIM τηλεπικοινωνιών"</string>
    ++    <string name="permlab_register_sim_subscription" msgid="3166535485877549177">"πραγματοποιεί εγγραφή νέων συνδέσεων SIM τηλεπικοινωνιών"</string>
    +     <string name="permdesc_register_sim_subscription" msgid="2138909035926222911">"Επιτρέπει στην εφαρμογή την εγγραφή νέων συνδέσεων SIM τηλεπικοινωνιών."</string>
    +-    <string name="permlab_register_call_provider" msgid="108102120289029841">"εγγραφή νέων συνδέσεων τηλεπικοινωνιών"</string>
    ++    <string name="permlab_register_call_provider" msgid="108102120289029841">"πραγματοποιεί εγγραφή των νέων συνδέσεων τηλεπικοινωνιών"</string>
    +     <string name="permdesc_register_call_provider" msgid="7034310263521081388">"Επιτρέπει στην εφαρμογή την εγγραφή νέων συνδέσεων τηλεπικοινωνιών."</string>
    +-    <string name="permlab_connection_manager" msgid="1116193254522105375">"διαχείριση των συνδέσεων τηλεπικοινωνιών"</string>
    ++    <string name="permlab_connection_manager" msgid="1116193254522105375">"διαχειρίζεται τις συνδέσεις τηλεπικοινωνιών"</string>
    +     <string name="permdesc_connection_manager" msgid="5925480810356483565">"Επιτρέπει στην εφαρμογή να διαχειρίζεται τις συνδέσεις τηλεπικοινωνιών."</string>
    +-    <string name="permlab_bind_incall_service" msgid="6773648341975287125">"αλληλεπίδραση με την οθόνη κατά τη διάρκεια κλήσης"</string>
    ++    <string name="permlab_bind_incall_service" msgid="6773648341975287125">"αλληλεπιδρά με την οθόνη κατά τη διάρκεια κλήσης"</string>
    +     <string name="permdesc_bind_incall_service" msgid="8343471381323215005">"Επιτρέπει στην εφαρμογή να ελέγχει πότε και πώς βλέπει ο χρήστης την οθόνη κατά τη διάρκεια κλήσης."</string>
    +-    <string name="permlab_bind_connection_service" msgid="3557341439297014940">"αλληλεπίδραση με υπηρεσίες τηλεφωνίας"</string>
    ++    <string name="permlab_bind_connection_service" msgid="3557341439297014940">"αλληλεπιδρά με υπηρεσίες τηλεφωνίας"</string>
    +     <string name="permdesc_bind_connection_service" msgid="4008754499822478114">"Επιτρέπει στην εφαρμογή να αλληλεπιδρά με υπηρεσίες τηλεφωνίας για την πραγματοποίηση/λήψη κλήσεων."</string>
    +-    <string name="permlab_control_incall_experience" msgid="9061024437607777619">"παροχή εμπειρίας χρήστη κατά τη διάρκεια κλήσης"</string>
    ++    <string name="permlab_control_incall_experience" msgid="9061024437607777619">"παρέχει εμπειρία χρήστη κατά τη διάρκεια κλήσης"</string>
    +     <string name="permdesc_control_incall_experience" msgid="915159066039828124">"Επιτρέπει στην εφαρμογή να παρέχει μια εμπειρία στο χρήστη κατά τη διάρκεια κλήσης."</string>
    +-    <string name="permlab_readNetworkUsageHistory" msgid="7862593283611493232">"ανάγνωση ιστορικών δεδομένων χρήσης δικτύου"</string>
    ++    <string name="permlab_readNetworkUsageHistory" msgid="7862593283611493232">"διαβάζει ιστορικά στοιχεία δεδομένων χρήσης δικτύου"</string>
    +     <string name="permdesc_readNetworkUsageHistory" msgid="7689060749819126472">"Επιτρέπει στην εφαρμογή την ανάγνωση ιστορικών στοιχείων χρήσης δικτύου για συγκεκριμένα δίκτυα και εφαρμογές."</string>
    +-    <string name="permlab_manageNetworkPolicy" msgid="2562053592339859990">"διαχείριση πολιτικής δικτύου"</string>
    ++    <string name="permlab_manageNetworkPolicy" msgid="2562053592339859990">"διαχειρίζεται την πολιτική δικτύου"</string>
    +     <string name="permdesc_manageNetworkPolicy" msgid="7537586771559370668">"Επιτρέπει στην εφαρμογή τη διαχείριση των πολιτικών δικτύου και τον ορισμό κανόνων για ορισμένες εφαρμογές."</string>
    +-    <string name="permlab_modifyNetworkAccounting" msgid="5088217309088729650">"τροποποίηση υπολογισμού χρήσης δικτύου"</string>
    ++    <string name="permlab_modifyNetworkAccounting" msgid="5088217309088729650">"τροποποιεί τον υπολογισμό χρήσης δικτύου"</string>
    +     <string name="permdesc_modifyNetworkAccounting" msgid="5443412866746198123">"Επιτρέπει στην εφαρμογή την τροποποίηση του τρόπου υπολογισμού της χρήσης δικτύου έναντι των εφαρμογών. Δεν προορίζεται για χρήση από συνήθεις εφαρμογές."</string>
    +-    <string name="permlab_accessNotifications" msgid="7673416487873432268">"πρόσβαση στις ειδοποιήσεις"</string>
    ++    <string name="permlab_accessNotifications" msgid="7673416487873432268">"έχει πρόσβαση στις ειδοποιήσεις"</string>
    +     <string name="permdesc_accessNotifications" msgid="458457742683431387">"Επιτρέπει στην εφαρμογή να ανακτά, να εξετάζει και να απαλείφει ειδοποιήσεις, συμπεριλαμβανομένων εκείνων που δημοσιεύονται από άλλες εφαρμογές."</string>
    +-    <string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"δέσμευση σε υπηρεσία ακρόασης ειδοποίησης"</string>
    ++    <string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"συνδέεται σε υπηρεσία ακρόασης ειδοποίησης"</string>
    +     <string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"Επιτρέπει στον κάτοχο τη δέσμευση στη διεπαφή ανωτάτου επιπέδου μιας υπηρεσίας ακρόασης ειδοποιήσεων. Δεν απαιτείται σε κανονικές εφαρμογές."</string>
    +-    <string name="permlab_bindConditionProviderService" msgid="1180107672332704641">"σύνδεση σε μια υπηρεσία παρόχου συνθηκών"</string>
    ++    <string name="permlab_bindConditionProviderService" msgid="1180107672332704641">"δεσμεύεται σε μια υπηρεσία παρόχου συνθηκών"</string>
    +     <string name="permdesc_bindConditionProviderService" msgid="1680513931165058425">"Επιτρέπει στον κάτοχο τη σύνδεση στη διεπαφή ανωτάτου επιπέδου ενός παρόχου συνθηκών. Δεν απαιτείται για κανονικές εφαρμογές."</string>
    +-    <string name="permlab_bindDreamService" msgid="4153646965978563462">"δέσμευση σε υπηρεσία dream"</string>
    ++    <string name="permlab_bindDreamService" msgid="4153646965978563462">"δεσμεύεται σε υπηρεσία dream"</string>
    +     <string name="permdesc_bindDreamService" msgid="7325825272223347863">"Επιτρέπει στον κάτοχο τη δέσμευση στη διεπαφή ανωτάτου επιπέδου μιας υπηρεσίας dream. Δεν απαιτείται σε κανονικές εφαρμογές."</string>
    +-    <string name="permlab_invokeCarrierSetup" msgid="3699600833975117478">"κλήση της εφαρμογής διαμόρφωσης που παρέχεται από την εταιρεία κινητής τηλεφωνίας"</string>
    ++    <string name="permlab_invokeCarrierSetup" msgid="3699600833975117478">"καλέι την εφαρμογή διαμόρφωσης του παρόχου κινητής τηλεφωνίας"</string>
    +     <string name="permdesc_invokeCarrierSetup" msgid="4159549152529111920">"Επιτρέπει στον κάτοχο την κλήση της εφαρμογής διαμόρφωσης που παρέχεται από την εταιρεία κινητής τηλεφωνίας. Δεν απαιτείται για κανονικές εφαρμογές."</string>
    +-    <string name="permlab_accessNetworkConditions" msgid="8206077447838909516">"λήψη παρατηρήσεων σχετικά με την κατάσταση δικτύου"</string>
    ++    <string name="permlab_accessNetworkConditions" msgid="8206077447838909516">"ανιχνεύει παρατηρήσεις σχετικά με την κατάσταση δικτύου"</string>
    +     <string name="permdesc_accessNetworkConditions" msgid="6899102075825272211">"Επιτρέπει σε μια εφαρμογή να λαμβάνει παρατηρήσεις σχετικά με την κατάσταση δικτύου. Δεν θα πρέπει να απαιτείται ποτέ για κανονικές εφαρμογές."</string>
    +     <string name="permlab_setInputCalibration" msgid="4902620118878467615">"αλλαγή βαθμονόμησης της συσκευής εισόδου"</string>
    +     <string name="permdesc_setInputCalibration" msgid="4527511047549456929">"Επιτρέπει στην εφαρμογή να τροποποιεί τις παραμέτρους βαθμονόμησης της οθόνης αφής. Δεν απαιτείται για τις κανονικές εφαρμογές."</string>
    +-    <string name="permlab_accessDrmCertificates" msgid="7436886640723203615">"πρόσβαση σε πιστοποιητικά DRM"</string>
    ++    <string name="permlab_accessDrmCertificates" msgid="7436886640723203615">"έχει πρόσβαση σε πιστοποιητικά DRM"</string>
    +     <string name="permdesc_accessDrmCertificates" msgid="8073288354426159089">"Επιτρέπει σε μια εφαρμογή να παρέχει και να χρησιμοποιεί πιστοποιητικά DRM. Δεν θα χρειαστεί ποτέ για κανονικές εφαρμογές."</string>
    +     <string name="permlab_handoverStatus" msgid="7820353257219300883">"λήψη κατάστασης μεταφοράς Android Beam"</string>
    +     <string name="permdesc_handoverStatus" msgid="4788144087245714948">"Επιτρέπει σε αυτήν την εφαρμογή να λαμβάνει πληροφορίες σχετικά με τις τρέχουσες μεταφορές Android Beam"</string>
    +-    <string name="permlab_removeDrmCertificates" msgid="7044888287209892751">"κατάργηση πιστοποιητικών DRM"</string>
    ++    <string name="permlab_removeDrmCertificates" msgid="7044888287209892751">"καταργεί πιστοποιητικά DRM"</string>
    +     <string name="permdesc_removeDrmCertificates" msgid="7272999075113400993">"Επιτρέπει σε μια εφαρμογή την κατάργηση πιστοποιητικών DRM. Δεν χρειάζεται ποτέ για κανονικές εφαρμογές."</string>
    +-    <string name="permlab_bindCarrierMessagingService" msgid="1490229371796969158">"δέσμευση σε υπηρεσία ανταλλαγής μηνυμάτων εταιρείας κινητής τηλεφωνίας"</string>
    ++    <string name="permlab_bindCarrierMessagingService" msgid="1490229371796969158">"δεσμεύεται σε υπηρεσία ανταλλαγής μηνυμάτων παρόχου κινητής τηλεφωνίας"</string>
    +     <string name="permdesc_bindCarrierMessagingService" msgid="2762882888502113944">"Επιτρέπει στον κάτοχο τη δέσμευση στη διεπαφή ανωτάτου επιπέδου μιας υπηρεσίας ανταλλαγής μηνυμάτων εταιρείας κινητής τηλεφωνίας. Δεν απαιτείται για συνήθεις εφαρμογές."</string>
    +-    <string name="permlab_bindCarrierServices" msgid="3233108656245526783">"δέσμευση σε υπηρεσίες εταιρείας κινητής τηλεφωνίας"</string>
    ++    <string name="permlab_bindCarrierServices" msgid="3233108656245526783">"δεσμεύεται σε υπηρεσίες του παρόχου κινητής τηλεφωνίας"</string>
    +     <string name="permdesc_bindCarrierServices" msgid="1391552602551084192">"Δίνει στον κάτοχο τη δυνατότητα δέσμευσης σε υπηρεσίες εταιρείας κινητής τηλεφωνίας. Δεν απαιτείται ποτέ για κανονικές εφαρμογές."</string>
    +-    <string name="permlab_access_notification_policy" msgid="4247510821662059671">"πρόσβαση στη λειτουργία \"Μην ενοχλείτε\""</string>
    ++    <string name="permlab_access_notification_policy" msgid="4247510821662059671">"έχει πρόσβαση στη λειτουργία \"Μην ενοχλείτε\""</string>
    +     <string name="permdesc_access_notification_policy" msgid="3296832375218749580">"Επιτρέπει στην εφαρμογή την εγγραφή και τη σύνταξη διαμόρφωσης για τη λειτουργία \"Μην ενοχλείτε\"."</string>
    +     <string name="policylab_limitPassword" msgid="4497420728857585791">"Ορισμός κανόνων κωδικού πρόσβασης"</string>
    +     <string name="policydesc_limitPassword" msgid="2502021457917874968">"Ελέγξτε την έκταση και τους επιτρεπόμενους χαρακτήρες σε κωδικούς πρόσβασης κλειδώματος οθόνης και PIN."</string>
    +@@ -791,17 +792,17 @@
    +     <string name="autofill_parish" msgid="8202206105468820057">"Ενορία"</string>
    +     <string name="autofill_area" msgid="3547409050889952423">"Περιοχή"</string>
    +     <string name="autofill_emirate" msgid="2893880978835698818">"Εμιράτο"</string>
    +-    <string name="permlab_readHistoryBookmarks" msgid="3775265775405106983">"ανάγνωση των σελιδοδεικτών και του ιστορικού ιστού σας"</string>
    ++    <string name="permlab_readHistoryBookmarks" msgid="3775265775405106983">"διαβάζει τους σελιδοδείκτες και το ιστορικού ιστού"</string>
    +     <string name="permdesc_readHistoryBookmarks" msgid="8462378226600439658">"Επιτρέπει στην εφαρμογή την ανάγνωση του ιστορικού όλων των διευθύνσεων URL που έχει επισκεφτεί το πρόγραμμα περιήγησης, καθώς και όλων των σελιδοδεικτών του προγράμματος περιήγησης. Σημείωση: αυτή η άδεια ίσως να μην μπορεί να εφαρμοστεί από τρίτα προγράμματα περιήγησης ή άλλες εφαρμογές με δυνατότητες περιήγησης ιστού."</string>
    +-    <string name="permlab_writeHistoryBookmarks" msgid="3714785165273314490">"εγγραφή σελιδοδεικτών και ιστορικού ιστού"</string>
    ++    <string name="permlab_writeHistoryBookmarks" msgid="3714785165273314490">"εγγράφει σελιδοδείκτες και ιστορικό ιστού"</string>
    +     <string name="permdesc_writeHistoryBookmarks" product="tablet" msgid="6825527469145760922">"Επιτρέπει στην εφαρμογή την τροποποίηση του ιστορικού του προγράμματος περιήγησης ή των σελιδοδεικτών που έχουν αποθηκευτεί στο tablet σας. Αυτό μπορεί να δίνει τη δυνατότητα στην εφαρμογή να διαγράφει ή να τροποποιεί δεδομένα του προγράμματος περιήγησης. Σημείωση: αυτή η άδεια ίσως να μην μπορεί να εφαρμοστεί από τρίτα προγράμματα περιήγησης ή άλλες εφαρμογές με δυνατότητες περιήγησης ιστού."</string>
    +     <string name="permdesc_writeHistoryBookmarks" product="tv" msgid="7007393823197766548">"Επιτρέπει στην εφαρμογή να τροποποιεί το ιστορικό του προγράμματος περιήγησης ή τους σελιδοδείκτες που είναι αποθηκευμένοι στην τηλεόρασή σας. Σημείωση: Αυτό το δικαίωμα δεν πρέπει να εφαρμόζεται από τρίτα προγράμματα περιήγησης ή άλλες εφαρμογές με δυνατότητες περιήγησης στον ιστό."</string>
    +     <string name="permdesc_writeHistoryBookmarks" product="default" msgid="8497389531014185509">"Επιτρέπει στην εφαρμογή την τροποποίηση του ιστορικού του προγράμματος περιήγησης ή των σελιδοδεικτών που έχουν αποθηκευτεί στο τηλέφωνό σας. Αυτό μπορεί να δίνει τη δυνατότητα στην εφαρμογή να διαγράφει ή να τροποποιεί δεδομένα του προγράμματος περιήγησης. Σημείωση: αυτή η άδεια ίσως να μην μπορεί να εφαρμοστεί από τρίτα προγράμματα περιήγησης ή άλλες εφαρμογές με δυνατότητες περιήγησης ιστού."</string>
    +-    <string name="permlab_setAlarm" msgid="1379294556362091814">"ρύθμιση ξυπνητηριού"</string>
    ++    <string name="permlab_setAlarm" msgid="1379294556362091814">"ρυθμίζει το ξυπνητήρι"</string>
    +     <string name="permdesc_setAlarm" msgid="316392039157473848">"Επιτρέπει στην εφαρμογή τη ρύθμιση μιας ειδοποίησης σε μια εγκατεστημένη εφαρμογή ξυπνητηριού. Ορισμένες εφαρμογές ξυπνητηριού ενδέχεται να μην μπορούν να ενσωματώσουν αυτήν τη λειτουργία."</string>
    +-    <string name="permlab_addVoicemail" msgid="5525660026090959044">"προσθήκη τηλεφωνητή"</string>
    ++    <string name="permlab_addVoicemail" msgid="5525660026090959044">"προσθέτει τηλεφωνητή"</string>
    +     <string name="permdesc_addVoicemail" msgid="6604508651428252437">"Επιτρέπει στην εφαρμογή να προσθέτει μηνύματα στα εισερχόμενα του αυτόματου τηλεφωνητή σας."</string>
    +-    <string name="permlab_writeGeolocationPermissions" msgid="5962224158955273932">"τροποποίηση δικαιωμάτων γεωγραφικής θέσης του Προγράμματος περιήγησης"</string>
    ++    <string name="permlab_writeGeolocationPermissions" msgid="5962224158955273932">"τροποποιεί δικαιώματα γεωγραφικής θέσης του Προγράμματος περιήγησης"</string>
    +     <string name="permdesc_writeGeolocationPermissions" msgid="1083743234522638747">"Επιτρέπει στην εφαρμογή την τροποποίηση των αδειών γεωτοποθεσίας του Προγράμματος περιήγησης. Τυχόν κακόβουλες εφαρμογές ενδέχεται να το χρησιμοποιήσουν για να επιτρέψουν την αποστολή πληροφοριών τοποθεσίας σε αυθαίρετους ιστότοπους."</string>
    +     <string name="save_password_message" msgid="767344687139195790">"Θέλετε το πρόγραμμα περιήγησης να διατηρήσει αυτόν τον κωδικό πρόσβασης;"</string>
    +     <string name="save_password_notnow" msgid="6389675316706699758">"Να μην γίνει τώρα"</string>
    +@@ -1076,6 +1077,17 @@
    +     <skip />
    +     <string name="wifi_no_internet" msgid="8451173622563841546">"Το δίκτυο Wi-Fi δεν έχει πρόσβαση στο διαδίκτυο"</string>
    +     <string name="wifi_no_internet_detailed" msgid="8083079241212301741">"Πατήστε για να δείτε τις επιλογές"</string>
    ++    <string name="network_switch_metered" msgid="4671730921726992671">"Μετάβαση σε δίκτυο <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
    ++    <string name="network_switch_metered_detail" msgid="5325661434777870353">"Η συσκευή χρησιμοποιεί το δίκτυο <xliff:g id="NEW_NETWORK">%1$s</xliff:g> όταν το δίκτυο <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> δεν έχει πρόσβαση στο διαδίκτυο. Ενδέχεται να ισχύουν χρεώσεις."</string>
    ++    <string name="network_switch_metered_toast" msgid="5779283181685974304">"Μετάβαση από το δίκτυο <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> στο δίκτυο <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
    ++  <string-array name="network_switch_type_name">
    ++    <item msgid="2952042958050315394">"δεδομένα κινητής τηλεφωνίας"</item>
    ++    <item msgid="75483255295529161">"Wi-Fi"</item>
    ++    <item msgid="6862614801537202646">"Bluetooth"</item>
    ++    <item msgid="5447331121797802871">"Ethernet"</item>
    ++    <item msgid="8257233890381651999">"VPN"</item>
    ++  </string-array>
    ++    <string name="network_switch_type_name_unknown" msgid="4552612897806660656">"άγνωστος τύπος δικτύου"</string>
    +     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Δεν είναι δυνατή η σύνδεση στο Wi-Fi"</string>
    +     <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" έχει κακή σύνδεση στο Διαδίκτυο."</string>
    +     <string name="wifi_connect_alert_title" msgid="8455846016001810172">"Να επιτρέπεται η σύνδεση;"</string>
    +@@ -1153,7 +1165,6 @@
    +     <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"Πατήστε για να επιλέξετε γλώσσα και διάταξη"</string>
    +     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
    +     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
    +-    <string name="candidates_style" msgid="4333913089637062257"><u>"υποψήφιοι"</u></string>
    +     <string name="ext_media_checking_notification_title" msgid="5734005953288045806">"Προετοιμασία <xliff:g id="NAME">%s</xliff:g>"</string>
    +     <string name="ext_media_checking_notification_message" msgid="4747432538578886744">"Έλεγχος για σφάλματα"</string>
    +     <string name="ext_media_new_notification_message" msgid="7589986898808506239">"Εντοπίστηκε νέο μέσο αποθήκευσης <xliff:g id="NAME">%s</xliff:g>"</string>
    +@@ -1191,11 +1202,11 @@
    +     <string name="ext_media_status_formatting" msgid="1085079556538644861">"Διαμόρφωση…"</string>
    +     <string name="ext_media_status_missing" msgid="5638633895221670766">"Δεν έχει εισαχθεί"</string>
    +     <string name="activity_list_empty" msgid="1675388330786841066">"Δεν βρέθηκαν δραστηριότητες που να συμφωνούν με τα κριτήρια."</string>
    +-    <string name="permlab_route_media_output" msgid="6243022988998972085">"δρομολόγηση εξόδου μέσων"</string>
    ++    <string name="permlab_route_media_output" msgid="6243022988998972085">"δρομολογεί την έξοδο μέσων"</string>
    +     <string name="permdesc_route_media_output" msgid="4932818749547244346">"Επιτρέπει σε μια εφαρμογή τη διαγραφή διαδρομής δεδομένων εξόδου μέσων σε άλλες εξωτερικές συσκευές."</string>
    +-    <string name="permlab_readInstallSessions" msgid="3713753067455750349">"ανάγνωση περιόδων σύνδεσης εγκατάστασης"</string>
    ++    <string name="permlab_readInstallSessions" msgid="3713753067455750349">"διαβάζει τις περιόδους σύνδεσης εγκατάστασης"</string>
    +     <string name="permdesc_readInstallSessions" msgid="2049771699626019849">"Επιτρέπει σε μια εφαρμογή την ανάγνωση των περιόδων σύνδεσης εγκατάστασης. Αυτό της επιτρέπει να βλέπει λεπτομέρειες σχετικά με τις εγκαταστάσεις του ενεργού πακέτου."</string>
    +-    <string name="permlab_requestInstallPackages" msgid="5782013576218172577">"αίτημα εγκατάστασης πακέτων"</string>
    ++    <string name="permlab_requestInstallPackages" msgid="5782013576218172577">"ζητά πακέτα εγκατάστασης"</string>
    +     <string name="permdesc_requestInstallPackages" msgid="5740101072486783082">"Επιτρέπει σε μια εφαρμογή να ζητά εγκατάσταση πακέτων."</string>
    +     <string name="tutorial_double_tap_to_zoom_message_short" msgid="1311810005957319690">"Πατήστε δύο φορές για έλεγχο εστίασης"</string>
    +     <string name="gadget_host_error_inflating" msgid="4882004314906466162">"Δεν ήταν δυνατή η προσθήκη του γραφικού στοιχείου."</string>
    +@@ -1232,8 +1243,9 @@
    +     <string name="vpn_text_long" msgid="4907843483284977618">"Συνδέθηκε με <xliff:g id="SESSION">%s</xliff:g>. Πατήστε για να διαχειριστείτε το δίκτυο."</string>
    +     <string name="vpn_lockdown_connecting" msgid="6443438964440960745">"Σύνδεση πάντα ενεργοποιημένου VPN…"</string>
    +     <string name="vpn_lockdown_connected" msgid="8202679674819213931">"Έχει συνδεθεί πάντα ενεργοποιημένο VPN"</string>
    ++    <string name="vpn_lockdown_disconnected" msgid="4532298952570796327">"Το πάντα ενεργοποιημένο VPN αποσυνδέθηκε"</string>
    +     <string name="vpn_lockdown_error" msgid="6009249814034708175">"Σφάλμα πάντα ενεργοποιημένου VPN"</string>
    +-    <string name="vpn_lockdown_config" msgid="4655589351146766608">"Πατήστε για διαμόρφωση"</string>
    ++    <string name="vpn_lockdown_config" msgid="5099330695245008680">"Πατήστε για ρύθμιση"</string>
    +     <string name="upload_file" msgid="2897957172366730416">"Επιλογή αρχείου"</string>
    +     <string name="no_file_chosen" msgid="6363648562170759465">"Δεν επιλέχθηκε κανένα αρχείο."</string>
    +     <string name="reset" msgid="2448168080964209908">"Επαναφορά"</string>
    +@@ -1317,7 +1329,7 @@
    +     <string name="storage_usb_drive_label" msgid="4501418548927759953">"Μονάδα USB <xliff:g id="MANUFACTURER">%s</xliff:g>"</string>
    +     <string name="storage_usb" msgid="3017954059538517278">"Αποθηκευτικός χώρος USB"</string>
    +     <string name="extract_edit_menu_button" msgid="8940478730496610137">"Επεξεργασία"</string>
    +-    <string name="data_usage_warning_title" msgid="1955638862122232342">"Προειδοποίηση χρήσης δεδομένων"</string>
    ++    <string name="data_usage_warning_title" msgid="3620440638180218181">"Ειδοποίηση χρήσης δεδομένων"</string>
    +     <string name="data_usage_warning_body" msgid="6660692274311972007">"Πατήστε για προβολή χρήσης/ρυθμ."</string>
    +     <string name="data_usage_3g_limit_title" msgid="4361523876818447683">"Συμπλ. το όριο δεδομένων 2G-3G"</string>
    +     <string name="data_usage_4g_limit_title" msgid="4609566827219442376">"Συμπλ. το όριο δεδομένων 4G"</string>
    +@@ -1636,6 +1648,7 @@
    +     <string name="search_language_hint" msgid="7042102592055108574">"Εισαγ. όνομα γλώσσας"</string>
    +     <string name="language_picker_section_suggested" msgid="8414489646861640885">"Προτεινόμενες"</string>
    +     <string name="language_picker_section_all" msgid="3097279199511617537">"Όλες οι γλώσσες"</string>
    ++    <string name="region_picker_section_all" msgid="8966316787153001779">"Όλες οι περιοχές"</string>
    +     <string name="locale_search_menu" msgid="2560710726687249178">"Αναζήτηση"</string>
    +     <string name="work_mode_off_title" msgid="8954725060677558855">"Λειτουργία εργασίας ΑΠΕΝΕΡΓ/ΝΗ"</string>
    +     <string name="work_mode_off_message" msgid="3286169091278094476">"Να επιτρέπεται η λειτουργία του προφίλ εργασίας σας, συμπεριλαμβανομένων των εφαρμογών, του συγχρονισμού στο παρασκήνιο και των σχετικών λειτουργιών."</string>
    +diff --git a/core/res/res/values-en-rAU/strings.xml b/core/res/res/values-en-rAU/strings.xml
    +index 12b7aa5..c6e04d7 100644
    +--- a/core/res/res/values-en-rAU/strings.xml
    ++++ b/core/res/res/values-en-rAU/strings.xml
    +@@ -214,6 +214,7 @@
    +     <string name="global_actions" product="default" msgid="2406416831541615258">"Phone options"</string>
    +     <string name="global_action_lock" msgid="2844945191792119712">"Screen lock"</string>
    +     <string name="global_action_power_off" msgid="4471879440839879722">"Power off"</string>
    ++    <string name="global_action_emergency" msgid="7112311161137421166">"Emergency"</string>
    +     <string name="global_action_bug_report" msgid="7934010578922304799">"Bug report"</string>
    +     <string name="bugreport_title" msgid="2667494803742548533">"Take bug report"</string>
    +     <string name="bugreport_message" msgid="398447048750350456">"This will collect information about your current device state, to send as an email message. It will take a little time from starting the bug report until it is ready to be sent. Please be patient."</string>
    +@@ -1076,6 +1077,17 @@
    +     <skip />
    +     <string name="wifi_no_internet" msgid="8451173622563841546">"Wi-Fi has no Internet access"</string>
    +     <string name="wifi_no_internet_detailed" msgid="8083079241212301741">"Tap for options"</string>
    ++    <string name="network_switch_metered" msgid="4671730921726992671">"Switched to <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
    ++    <string name="network_switch_metered_detail" msgid="5325661434777870353">"Device uses <xliff:g id="NEW_NETWORK">%1$s</xliff:g> when <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> has no Internet access. Charges may apply."</string>
    ++    <string name="network_switch_metered_toast" msgid="5779283181685974304">"Switched from <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> to <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
    ++  <string-array name="network_switch_type_name">
    ++    <item msgid="2952042958050315394">"mobile data"</item>
    ++    <item msgid="75483255295529161">"Wi-Fi"</item>
    ++    <item msgid="6862614801537202646">"Bluetooth"</item>
    ++    <item msgid="5447331121797802871">"Ethernet"</item>
    ++    <item msgid="8257233890381651999">"VPN"</item>
    ++  </string-array>
    ++    <string name="network_switch_type_name_unknown" msgid="4552612897806660656">"an unknown network type"</string>
    +     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Couldn\'t connect to Wi-Fi"</string>
    +     <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" has a poor Internet connection."</string>
    +     <string name="wifi_connect_alert_title" msgid="8455846016001810172">"Allow connection?"</string>
    +@@ -1153,7 +1165,6 @@
    +     <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"Tap to select language and layout"</string>
    +     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
    +     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
    +-    <string name="candidates_style" msgid="4333913089637062257"><u>"candidates"</u></string>
    +     <string name="ext_media_checking_notification_title" msgid="5734005953288045806">"Preparing <xliff:g id="NAME">%s</xliff:g>"</string>
    +     <string name="ext_media_checking_notification_message" msgid="4747432538578886744">"Checking for errors"</string>
    +     <string name="ext_media_new_notification_message" msgid="7589986898808506239">"New <xliff:g id="NAME">%s</xliff:g> detected"</string>
    +@@ -1232,8 +1243,9 @@
    +     <string name="vpn_text_long" msgid="4907843483284977618">"Connected to <xliff:g id="SESSION">%s</xliff:g>. Tap to manage the network."</string>
    +     <string name="vpn_lockdown_connecting" msgid="6443438964440960745">"Always-on VPN connecting…"</string>
    +     <string name="vpn_lockdown_connected" msgid="8202679674819213931">"Always-on VPN connected"</string>
    ++    <string name="vpn_lockdown_disconnected" msgid="4532298952570796327">"Always-on VPN disconnected"</string>
    +     <string name="vpn_lockdown_error" msgid="6009249814034708175">"Always-on VPN error"</string>
    +-    <string name="vpn_lockdown_config" msgid="4655589351146766608">"Tap to configure"</string>
    ++    <string name="vpn_lockdown_config" msgid="5099330695245008680">"Tap to set up"</string>
    +     <string name="upload_file" msgid="2897957172366730416">"Choose file"</string>
    +     <string name="no_file_chosen" msgid="6363648562170759465">"No file chosen"</string>
    +     <string name="reset" msgid="2448168080964209908">"Reset"</string>
    +@@ -1317,7 +1329,7 @@
    +     <string name="storage_usb_drive_label" msgid="4501418548927759953">"<xliff:g id="MANUFACTURER">%s</xliff:g> USB drive"</string>
    +     <string name="storage_usb" msgid="3017954059538517278">"USB storage"</string>
    +     <string name="extract_edit_menu_button" msgid="8940478730496610137">"Edit"</string>
    +-    <string name="data_usage_warning_title" msgid="1955638862122232342">"Data usage warning"</string>
    ++    <string name="data_usage_warning_title" msgid="3620440638180218181">"Data usage alert"</string>
    +     <string name="data_usage_warning_body" msgid="6660692274311972007">"Tap to view usage and settings."</string>
    +     <string name="data_usage_3g_limit_title" msgid="4361523876818447683">"2G-3G data limit reached"</string>
    +     <string name="data_usage_4g_limit_title" msgid="4609566827219442376">"4G data limit reached"</string>
    +@@ -1636,6 +1648,7 @@
    +     <string name="search_language_hint" msgid="7042102592055108574">"Type language name"</string>
    +     <string name="language_picker_section_suggested" msgid="8414489646861640885">"Suggested"</string>
    +     <string name="language_picker_section_all" msgid="3097279199511617537">"All languages"</string>
    ++    <string name="region_picker_section_all" msgid="8966316787153001779">"All regions"</string>
    +     <string name="locale_search_menu" msgid="2560710726687249178">"Search"</string>
    +     <string name="work_mode_off_title" msgid="8954725060677558855">"Work mode is OFF"</string>
    +     <string name="work_mode_off_message" msgid="3286169091278094476">"Allow work profile to function, including apps, background sync and related features."</string>
    +diff --git a/core/res/res/values-en-rGB/strings.xml b/core/res/res/values-en-rGB/strings.xml
    +index 12b7aa5..c6e04d7 100644
    +--- a/core/res/res/values-en-rGB/strings.xml
    ++++ b/core/res/res/values-en-rGB/strings.xml
    +@@ -214,6 +214,7 @@
    +     <string name="global_actions" product="default" msgid="2406416831541615258">"Phone options"</string>
    +     <string name="global_action_lock" msgid="2844945191792119712">"Screen lock"</string>
    +     <string name="global_action_power_off" msgid="4471879440839879722">"Power off"</string>
    ++    <string name="global_action_emergency" msgid="7112311161137421166">"Emergency"</string>
    +     <string name="global_action_bug_report" msgid="7934010578922304799">"Bug report"</string>
    +     <string name="bugreport_title" msgid="2667494803742548533">"Take bug report"</string>
    +     <string name="bugreport_message" msgid="398447048750350456">"This will collect information about your current device state, to send as an email message. It will take a little time from starting the bug report until it is ready to be sent. Please be patient."</string>
    +@@ -1076,6 +1077,17 @@
    +     <skip />
    +     <string name="wifi_no_internet" msgid="8451173622563841546">"Wi-Fi has no Internet access"</string>
    +     <string name="wifi_no_internet_detailed" msgid="8083079241212301741">"Tap for options"</string>
    ++    <string name="network_switch_metered" msgid="4671730921726992671">"Switched to <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
    ++    <string name="network_switch_metered_detail" msgid="5325661434777870353">"Device uses <xliff:g id="NEW_NETWORK">%1$s</xliff:g> when <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> has no Internet access. Charges may apply."</string>
    ++    <string name="network_switch_metered_toast" msgid="5779283181685974304">"Switched from <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> to <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
    ++  <string-array name="network_switch_type_name">
    ++    <item msgid="2952042958050315394">"mobile data"</item>
    ++    <item msgid="75483255295529161">"Wi-Fi"</item>
    ++    <item msgid="6862614801537202646">"Bluetooth"</item>
    ++    <item msgid="5447331121797802871">"Ethernet"</item>
    ++    <item msgid="8257233890381651999">"VPN"</item>
    ++  </string-array>
    ++    <string name="network_switch_type_name_unknown" msgid="4552612897806660656">"an unknown network type"</string>
    +     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Couldn\'t connect to Wi-Fi"</string>
    +     <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" has a poor Internet connection."</string>
    +     <string name="wifi_connect_alert_title" msgid="8455846016001810172">"Allow connection?"</string>
    +@@ -1153,7 +1165,6 @@
    +     <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"Tap to select language and layout"</string>
    +     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
    +     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
    +-    <string name="candidates_style" msgid="4333913089637062257"><u>"candidates"</u></string>
    +     <string name="ext_media_checking_notification_title" msgid="5734005953288045806">"Preparing <xliff:g id="NAME">%s</xliff:g>"</string>
    +     <string name="ext_media_checking_notification_message" msgid="4747432538578886744">"Checking for errors"</string>
    +     <string name="ext_media_new_notification_message" msgid="7589986898808506239">"New <xliff:g id="NAME">%s</xliff:g> detected"</string>
    +@@ -1232,8 +1243,9 @@
    +     <string name="vpn_text_long" msgid="4907843483284977618">"Connected to <xliff:g id="SESSION">%s</xliff:g>. Tap to manage the network."</string>
    +     <string name="vpn_lockdown_connecting" msgid="6443438964440960745">"Always-on VPN connecting…"</string>
    +     <string name="vpn_lockdown_connected" msgid="8202679674819213931">"Always-on VPN connected"</string>
    ++    <string name="vpn_lockdown_disconnected" msgid="4532298952570796327">"Always-on VPN disconnected"</string>
    +     <string name="vpn_lockdown_error" msgid="6009249814034708175">"Always-on VPN error"</string>
    +-    <string name="vpn_lockdown_config" msgid="4655589351146766608">"Tap to configure"</string>
    ++    <string name="vpn_lockdown_config" msgid="5099330695245008680">"Tap to set up"</string>
    +     <string name="upload_file" msgid="2897957172366730416">"Choose file"</string>
    +     <string name="no_file_chosen" msgid="6363648562170759465">"No file chosen"</string>
    +     <string name="reset" msgid="2448168080964209908">"Reset"</string>
    +@@ -1317,7 +1329,7 @@
    +     <string name="storage_usb_drive_label" msgid="4501418548927759953">"<xliff:g id="MANUFACTURER">%s</xliff:g> USB drive"</string>
    +     <string name="storage_usb" msgid="3017954059538517278">"USB storage"</string>
    +     <string name="extract_edit_menu_button" msgid="8940478730496610137">"Edit"</string>
    +-    <string name="data_usage_warning_title" msgid="1955638862122232342">"Data usage warning"</string>
    ++    <string name="data_usage_warning_title" msgid="3620440638180218181">"Data usage alert"</string>
    +     <string name="data_usage_warning_body" msgid="6660692274311972007">"Tap to view usage and settings."</string>
    +     <string name="data_usage_3g_limit_title" msgid="4361523876818447683">"2G-3G data limit reached"</string>
    +     <string name="data_usage_4g_limit_title" msgid="4609566827219442376">"4G data limit reached"</string>
    +@@ -1636,6 +1648,7 @@
    +     <string name="search_language_hint" msgid="7042102592055108574">"Type language name"</string>
    +     <string name="language_picker_section_suggested" msgid="8414489646861640885">"Suggested"</string>
    +     <string name="language_picker_section_all" msgid="3097279199511617537">"All languages"</string>
    ++    <string name="region_picker_section_all" msgid="8966316787153001779">"All regions"</string>
    +     <string name="locale_search_menu" msgid="2560710726687249178">"Search"</string>
    +     <string name="work_mode_off_title" msgid="8954725060677558855">"Work mode is OFF"</string>
    +     <string name="work_mode_off_message" msgid="3286169091278094476">"Allow work profile to function, including apps, background sync and related features."</string>
    +diff --git a/core/res/res/values-en-rIN/strings.xml b/core/res/res/values-en-rIN/strings.xml
    +index 12b7aa5..c6e04d7 100644
    +--- a/core/res/res/values-en-rIN/strings.xml
    ++++ b/core/res/res/values-en-rIN/strings.xml
    +@@ -214,6 +214,7 @@
    +     <string name="global_actions" product="default" msgid="2406416831541615258">"Phone options"</string>
    +     <string name="global_action_lock" msgid="2844945191792119712">"Screen lock"</string>
    +     <string name="global_action_power_off" msgid="4471879440839879722">"Power off"</string>
    ++    <string name="global_action_emergency" msgid="7112311161137421166">"Emergency"</string>
    +     <string name="global_action_bug_report" msgid="7934010578922304799">"Bug report"</string>
    +     <string name="bugreport_title" msgid="2667494803742548533">"Take bug report"</string>
    +     <string name="bugreport_message" msgid="398447048750350456">"This will collect information about your current device state, to send as an email message. It will take a little time from starting the bug report until it is ready to be sent. Please be patient."</string>
    +@@ -1076,6 +1077,17 @@
    +     <skip />
    +     <string name="wifi_no_internet" msgid="8451173622563841546">"Wi-Fi has no Internet access"</string>
    +     <string name="wifi_no_internet_detailed" msgid="8083079241212301741">"Tap for options"</string>
    ++    <string name="network_switch_metered" msgid="4671730921726992671">"Switched to <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
    ++    <string name="network_switch_metered_detail" msgid="5325661434777870353">"Device uses <xliff:g id="NEW_NETWORK">%1$s</xliff:g> when <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> has no Internet access. Charges may apply."</string>
    ++    <string name="network_switch_metered_toast" msgid="5779283181685974304">"Switched from <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> to <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
    ++  <string-array name="network_switch_type_name">
    ++    <item msgid="2952042958050315394">"mobile data"</item>
    ++    <item msgid="75483255295529161">"Wi-Fi"</item>
    ++    <item msgid="6862614801537202646">"Bluetooth"</item>
    ++    <item msgid="5447331121797802871">"Ethernet"</item>
    ++    <item msgid="8257233890381651999">"VPN"</item>
    ++  </string-array>
    ++    <string name="network_switch_type_name_unknown" msgid="4552612897806660656">"an unknown network type"</string>
    +     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Couldn\'t connect to Wi-Fi"</string>
    +     <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" has a poor Internet connection."</string>
    +     <string name="wifi_connect_alert_title" msgid="8455846016001810172">"Allow connection?"</string>
    +@@ -1153,7 +1165,6 @@
    +     <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"Tap to select language and layout"</string>
    +     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
    +     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
    +-    <string name="candidates_style" msgid="4333913089637062257"><u>"candidates"</u></string>
    +     <string name="ext_media_checking_notification_title" msgid="5734005953288045806">"Preparing <xliff:g id="NAME">%s</xliff:g>"</string>
    +     <string name="ext_media_checking_notification_message" msgid="4747432538578886744">"Checking for errors"</string>
    +     <string name="ext_media_new_notification_message" msgid="7589986898808506239">"New <xliff:g id="NAME">%s</xliff:g> detected"</string>
    +@@ -1232,8 +1243,9 @@
    +     <string name="vpn_text_long" msgid="4907843483284977618">"Connected to <xliff:g id="SESSION">%s</xliff:g>. Tap to manage the network."</string>
    +     <string name="vpn_lockdown_connecting" msgid="6443438964440960745">"Always-on VPN connecting…"</string>
    +     <string name="vpn_lockdown_connected" msgid="8202679674819213931">"Always-on VPN connected"</string>
    ++    <string name="vpn_lockdown_disconnected" msgid="4532298952570796327">"Always-on VPN disconnected"</string>
    +     <string name="vpn_lockdown_error" msgid="6009249814034708175">"Always-on VPN error"</string>
    +-    <string name="vpn_lockdown_config" msgid="4655589351146766608">"Tap to configure"</string>
    ++    <string name="vpn_lockdown_config" msgid="5099330695245008680">"Tap to set up"</string>
    +     <string name="upload_file" msgid="2897957172366730416">"Choose file"</string>
    +     <string name="no_file_chosen" msgid="6363648562170759465">"No file chosen"</string>
    +     <string name="reset" msgid="2448168080964209908">"Reset"</string>
    +@@ -1317,7 +1329,7 @@
    +     <string name="storage_usb_drive_label" msgid="4501418548927759953">"<xliff:g id="MANUFACTURER">%s</xliff:g> USB drive"</string>
    +     <string name="storage_usb" msgid="3017954059538517278">"USB storage"</string>
    +     <string name="extract_edit_menu_button" msgid="8940478730496610137">"Edit"</string>
    +-    <string name="data_usage_warning_title" msgid="1955638862122232342">"Data usage warning"</string>
    ++    <string name="data_usage_warning_title" msgid="3620440638180218181">"Data usage alert"</string>
    +     <string name="data_usage_warning_body" msgid="6660692274311972007">"Tap to view usage and settings."</string>
    +     <string name="data_usage_3g_limit_title" msgid="4361523876818447683">"2G-3G data limit reached"</string>
    +     <string name="data_usage_4g_limit_title" msgid="4609566827219442376">"4G data limit reached"</string>
    +@@ -1636,6 +1648,7 @@
    +     <string name="search_language_hint" msgid="7042102592055108574">"Type language name"</string>
    +     <string name="language_picker_section_suggested" msgid="8414489646861640885">"Suggested"</string>
    +     <string name="language_picker_section_all" msgid="3097279199511617537">"All languages"</string>
    ++    <string name="region_picker_section_all" msgid="8966316787153001779">"All regions"</string>
    +     <string name="locale_search_menu" msgid="2560710726687249178">"Search"</string>
    +     <string name="work_mode_off_title" msgid="8954725060677558855">"Work mode is OFF"</string>
    +     <string name="work_mode_off_message" msgid="3286169091278094476">"Allow work profile to function, including apps, background sync and related features."</string>
    +diff --git a/core/res/res/values-es-rUS/strings.xml b/core/res/res/values-es-rUS/strings.xml
    +index 136902b..ea1c1a5 100644
    +--- a/core/res/res/values-es-rUS/strings.xml
    ++++ b/core/res/res/values-es-rUS/strings.xml
    +@@ -214,6 +214,7 @@
    +     <string name="global_actions" product="default" msgid="2406416831541615258">"Opciones de dispositivo"</string>
    +     <string name="global_action_lock" msgid="2844945191792119712">"Bloqueo de pantalla"</string>
    +     <string name="global_action_power_off" msgid="4471879440839879722">"Apagar"</string>
    ++    <string name="global_action_emergency" msgid="7112311161137421166">"Emergencias"</string>
    +     <string name="global_action_bug_report" msgid="7934010578922304799">"Informe de errores"</string>
    +     <string name="bugreport_title" msgid="2667494803742548533">"Iniciar informe de errores"</string>
    +     <string name="bugreport_message" msgid="398447048750350456">"Se recopilará información sobre el estado actual de tu dispositivo, que se enviará por correo. Pasarán unos minutos desde que se inicie el informe de errores hasta que se envíe, por lo que te recomendamos que tengas paciencia."</string>
    +@@ -1076,6 +1077,17 @@
    +     <skip />
    +     <string name="wifi_no_internet" msgid="8451173622563841546">"La red Wi-Fi no tiene acceso a Internet"</string>
    +     <string name="wifi_no_internet_detailed" msgid="8083079241212301741">"Presiona para ver opciones"</string>
    ++    <string name="network_switch_metered" msgid="4671730921726992671">"Se cambió a <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
    ++    <string name="network_switch_metered_detail" msgid="5325661434777870353">"El dispositivo usa <xliff:g id="NEW_NETWORK">%1$s</xliff:g> cuando <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> no tiene acceso a Internet. Es posible que se apliquen cargos."</string>
    ++    <string name="network_switch_metered_toast" msgid="5779283181685974304">"Se cambió de <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> a <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
    ++  <string-array name="network_switch_type_name">
    ++    <item msgid="2952042958050315394">"datos móviles"</item>
    ++    <item msgid="75483255295529161">"Wi-Fi"</item>
    ++    <item msgid="6862614801537202646">"Bluetooth"</item>
    ++    <item msgid="5447331121797802871">"Ethernet"</item>
    ++    <item msgid="8257233890381651999">"VPN"</item>
    ++  </string-array>
    ++    <string name="network_switch_type_name_unknown" msgid="4552612897806660656">"un tipo de red desconocido"</string>
    +     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"No se pudo conectar a la red Wi-Fi."</string>
    +     <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" tiene una mala conexión a Internet."</string>
    +     <string name="wifi_connect_alert_title" msgid="8455846016001810172">"¿Permitir la conexión?"</string>
    +@@ -1153,7 +1165,6 @@
    +     <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"Presiona para seleccionar el idioma y el diseño"</string>
    +     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
    +     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
    +-    <string name="candidates_style" msgid="4333913089637062257"><u>"candidatos"</u></string>
    +     <string name="ext_media_checking_notification_title" msgid="5734005953288045806">"Preparando el medio <xliff:g id="NAME">%s</xliff:g>"</string>
    +     <string name="ext_media_checking_notification_message" msgid="4747432538578886744">"Verificando errores"</string>
    +     <string name="ext_media_new_notification_message" msgid="7589986898808506239">"Se detectó un nuevo medio (<xliff:g id="NAME">%s</xliff:g>)."</string>
    +@@ -1232,8 +1243,9 @@
    +     <string name="vpn_text_long" msgid="4907843483284977618">"Conectado a <xliff:g id="SESSION">%s</xliff:g>. Pulsa para gestionar la red."</string>
    +     <string name="vpn_lockdown_connecting" msgid="6443438964440960745">"Estableciendo conexión con la VPN siempre activada..."</string>
    +     <string name="vpn_lockdown_connected" msgid="8202679674819213931">"Se estableció conexión con la VPN siempre activada."</string>
    ++    <string name="vpn_lockdown_disconnected" msgid="4532298952570796327">"Se desconectó la VPN siempre activada"</string>
    +     <string name="vpn_lockdown_error" msgid="6009249814034708175">"Se produjo un error al establecer conexión con la VPN siempre activada."</string>
    +-    <string name="vpn_lockdown_config" msgid="4655589351146766608">"Presiona para configurar"</string>
    ++    <string name="vpn_lockdown_config" msgid="5099330695245008680">"Presiona para configurar"</string>
    +     <string name="upload_file" msgid="2897957172366730416">"Elegir archivo"</string>
    +     <string name="no_file_chosen" msgid="6363648562170759465">"No se seleccionó un archivo."</string>
    +     <string name="reset" msgid="2448168080964209908">"Restablecer"</string>
    +@@ -1317,7 +1329,7 @@
    +     <string name="storage_usb_drive_label" msgid="4501418548927759953">"Unidad USB de <xliff:g id="MANUFACTURER">%s</xliff:g>"</string>
    +     <string name="storage_usb" msgid="3017954059538517278">"Almacenamiento USB"</string>
    +     <string name="extract_edit_menu_button" msgid="8940478730496610137">"Editar"</string>
    +-    <string name="data_usage_warning_title" msgid="1955638862122232342">"Advertencia de uso de datos"</string>
    ++    <string name="data_usage_warning_title" msgid="3620440638180218181">"Alerta por el uso de datos"</string>
    +     <string name="data_usage_warning_body" msgid="6660692274311972007">"Presiona para uso y opciones."</string>
    +     <string name="data_usage_3g_limit_title" msgid="4361523876818447683">"Límite de datos 2G-3G alcanzado"</string>
    +     <string name="data_usage_4g_limit_title" msgid="4609566827219442376">"Límite de datos 4G alcanzado"</string>
    +@@ -1636,6 +1648,7 @@
    +     <string name="search_language_hint" msgid="7042102592055108574">"Nombre del idioma"</string>
    +     <string name="language_picker_section_suggested" msgid="8414489646861640885">"Sugeridos"</string>
    +     <string name="language_picker_section_all" msgid="3097279199511617537">"Todos los idiomas"</string>
    ++    <string name="region_picker_section_all" msgid="8966316787153001779">"Todas las regiones"</string>
    +     <string name="locale_search_menu" msgid="2560710726687249178">"Búsqueda"</string>
    +     <string name="work_mode_off_title" msgid="8954725060677558855">"Modo de trabajo DESACTIVADO"</string>
    +     <string name="work_mode_off_message" msgid="3286169091278094476">"Permite que se active el perfil de trabajo, incluidas las apps, la sincronización en segundo plano y las funciones relacionadas."</string>
    +diff --git a/core/res/res/values-es/strings.xml b/core/res/res/values-es/strings.xml
    +index c4ebb02..c6d6663 100644
    +--- a/core/res/res/values-es/strings.xml
    ++++ b/core/res/res/values-es/strings.xml
    +@@ -214,6 +214,7 @@
    +     <string name="global_actions" product="default" msgid="2406416831541615258">"Opciones del teléfono"</string>
    +     <string name="global_action_lock" msgid="2844945191792119712">"Bloqueo de pantalla"</string>
    +     <string name="global_action_power_off" msgid="4471879440839879722">"Apagar"</string>
    ++    <string name="global_action_emergency" msgid="7112311161137421166">"Emergencia"</string>
    +     <string name="global_action_bug_report" msgid="7934010578922304799">"Informe de error"</string>
    +     <string name="bugreport_title" msgid="2667494803742548533">"Crear informe de errores"</string>
    +     <string name="bugreport_message" msgid="398447048750350456">"Se recopilará información sobre el estado actual de tu dispositivo y se enviará por correo electrónico. Pasarán unos minutos desde que empiece a generarse el informe de errores hasta que se envíe."</string>
    +@@ -1076,6 +1077,17 @@
    +     <skip />
    +     <string name="wifi_no_internet" msgid="8451173622563841546">"Wi-Fi sin acceso a Internet"</string>
    +     <string name="wifi_no_internet_detailed" msgid="8083079241212301741">"Toca para ver opciones"</string>
    ++    <string name="network_switch_metered" msgid="4671730921726992671">"Se ha cambiado a <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
    ++    <string name="network_switch_metered_detail" msgid="5325661434777870353">"El dispositivo utiliza <xliff:g id="NEW_NETWORK">%1$s</xliff:g> cuando <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> no tiene acceso a Internet. Es posible que se apliquen cargos."</string>
    ++    <string name="network_switch_metered_toast" msgid="5779283181685974304">"Se ha cambiado de <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> a <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
    ++  <string-array name="network_switch_type_name">
    ++    <item msgid="2952042958050315394">"datos móviles"</item>
    ++    <item msgid="75483255295529161">"Wi-Fi"</item>
    ++    <item msgid="6862614801537202646">"Bluetooth"</item>
    ++    <item msgid="5447331121797802871">"Ethernet"</item>
    ++    <item msgid="8257233890381651999">"VPN"</item>
    ++  </string-array>
    ++    <string name="network_switch_type_name_unknown" msgid="4552612897806660656">"tipo de red desconocido"</string>
    +     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"No se ha podido establecer conexión con la red Wi-Fi."</string>
    +     <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" tiene una conexión inestable a Internet."</string>
    +     <string name="wifi_connect_alert_title" msgid="8455846016001810172">"¿Permitir la conexión?"</string>
    +@@ -1153,7 +1165,6 @@
    +     <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"Toca para seleccionar el idioma y el diseño"</string>
    +     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
    +     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
    +-    <string name="candidates_style" msgid="4333913089637062257"><u>"candidatos"</u></string>
    +     <string name="ext_media_checking_notification_title" msgid="5734005953288045806">"Preparando <xliff:g id="NAME">%s</xliff:g>"</string>
    +     <string name="ext_media_checking_notification_message" msgid="4747432538578886744">"Comprobando errores"</string>
    +     <string name="ext_media_new_notification_message" msgid="7589986898808506239">"Nueva <xliff:g id="NAME">%s</xliff:g> detectada"</string>
    +@@ -1232,8 +1243,9 @@
    +     <string name="vpn_text_long" msgid="4907843483284977618">"Conectado a <xliff:g id="SESSION">%s</xliff:g>. Toca para administrar la red."</string>
    +     <string name="vpn_lockdown_connecting" msgid="6443438964440960745">"Conectando VPN siempre activada…"</string>
    +     <string name="vpn_lockdown_connected" msgid="8202679674819213931">"VPN siempre activada conectada"</string>
    ++    <string name="vpn_lockdown_disconnected" msgid="4532298952570796327">"VPN siempre activada desconectada"</string>
    +     <string name="vpn_lockdown_error" msgid="6009249814034708175">"Error de VPN siempre activada"</string>
    +-    <string name="vpn_lockdown_config" msgid="4655589351146766608">"Toca para configurar"</string>
    ++    <string name="vpn_lockdown_config" msgid="5099330695245008680">"Toca para configurar"</string>
    +     <string name="upload_file" msgid="2897957172366730416">"Seleccionar archivo"</string>
    +     <string name="no_file_chosen" msgid="6363648562170759465">"Archivo no seleccionado"</string>
    +     <string name="reset" msgid="2448168080964209908">"Restablecer"</string>
    +@@ -1317,7 +1329,7 @@
    +     <string name="storage_usb_drive_label" msgid="4501418548927759953">"Unidad USB <xliff:g id="MANUFACTURER">%s</xliff:g>"</string>
    +     <string name="storage_usb" msgid="3017954059538517278">"Almacenamiento USB"</string>
    +     <string name="extract_edit_menu_button" msgid="8940478730496610137">"Editar"</string>
    +-    <string name="data_usage_warning_title" msgid="1955638862122232342">"Advertencia de uso de datos"</string>
    ++    <string name="data_usage_warning_title" msgid="3620440638180218181">"Alerta sobre el uso de datos"</string>
    +     <string name="data_usage_warning_body" msgid="6660692274311972007">"Toca para ver uso y ajustes."</string>
    +     <string name="data_usage_3g_limit_title" msgid="4361523876818447683">"Límite de datos 2G-3G alcanzado"</string>
    +     <string name="data_usage_4g_limit_title" msgid="4609566827219442376">"Límite de datos 4G alcanzado"</string>
    +@@ -1557,7 +1569,7 @@
    +     <string name="package_updated_device_owner" msgid="8856631322440187071">"Actualizado por tu administrador"</string>
    +     <string name="package_deleted_device_owner" msgid="7650577387493101353">"Eliminado por tu administrador"</string>
    +     <string name="battery_saver_description" msgid="1960431123816253034">"Para ayudar a mejorar la duración de la batería, la función de ahorro de energía reduce el rendimiento del dispositivo y limita la vibración, los servicios de ubicación y la mayor parte de la transmisión de datos en segundo plano. Es posible que las aplicaciones que se sincronizan, como las de correo y mensajes, no se actualicen a menos que las abras.\n\nLa función de ahorro de energía se desactiva automáticamente cuando el dispositivo se está cargando."</string>
    +-    <string name="data_saver_description" msgid="6015391409098303235">"El Economizador de Datos evita que algunas aplicaciones envíen o reciban datos en segundo plano, lo que permite reducir el uso de datos. Una aplicación activa podrá acceder a los datos, aunque con menos frecuencia. Esto significa que, por ejemplo, algunas imágenes no se muestren hasta que no las toques."</string>
    ++    <string name="data_saver_description" msgid="6015391409098303235">"El ahorro de datos evita que algunas aplicaciones envíen o reciban datos en segundo plano, lo que permite reducir el uso de datos. Una aplicación activa podrá acceder a los datos, aunque con menos frecuencia. Esto significa que, por ejemplo, algunas imágenes no se muestren hasta que no las toques."</string>
    +     <string name="data_saver_enable_title" msgid="4674073932722787417">"¿Activar ahorro de datos?"</string>
    +     <string name="data_saver_enable_button" msgid="7147735965247211818">"Activar"</string>
    +     <plurals name="zen_mode_duration_minutes_summary" formatted="false" msgid="4367877408072000848">
    +@@ -1636,6 +1648,7 @@
    +     <string name="search_language_hint" msgid="7042102592055108574">"Nombre de idioma"</string>
    +     <string name="language_picker_section_suggested" msgid="8414489646861640885">"Sugeridos"</string>
    +     <string name="language_picker_section_all" msgid="3097279199511617537">"Todos los idiomas"</string>
    ++    <string name="region_picker_section_all" msgid="8966316787153001779">"Todas las regiones"</string>
    +     <string name="locale_search_menu" msgid="2560710726687249178">"Buscar"</string>
    +     <string name="work_mode_off_title" msgid="8954725060677558855">"Modo de trabajo desactivado"</string>
    +     <string name="work_mode_off_message" msgid="3286169091278094476">"Permite que se utilice el perfil de trabajo, incluidas las aplicaciones, la sincronización en segundo plano y las funciones relacionadas."</string>
    +diff --git a/core/res/res/values-et-rEE/strings.xml b/core/res/res/values-et-rEE/strings.xml
    +index 8922379..9263b59 100644
    +--- a/core/res/res/values-et-rEE/strings.xml
    ++++ b/core/res/res/values-et-rEE/strings.xml
    +@@ -214,6 +214,7 @@
    +     <string name="global_actions" product="default" msgid="2406416831541615258">"Telefonivalikud"</string>
    +     <string name="global_action_lock" msgid="2844945191792119712">"Ekraanilukk"</string>
    +     <string name="global_action_power_off" msgid="4471879440839879722">"Lülita välja"</string>
    ++    <string name="global_action_emergency" msgid="7112311161137421166">"Hädaabi"</string>
    +     <string name="global_action_bug_report" msgid="7934010578922304799">"Veaaruanne"</string>
    +     <string name="bugreport_title" msgid="2667494803742548533">"Veaaruande võtmine"</string>
    +     <string name="bugreport_message" msgid="398447048750350456">"Nii kogutakse teavet teie seadme praeguse oleku kohta, et saata see meilisõnumina. Enne kui saate veaaruande ära saata, võtab selle loomine natuke aega; varuge kannatust."</string>
    +@@ -251,7 +252,7 @@
    +     <string name="permgrouplab_sms" msgid="228308803364967808">"SMS"</string>
    +     <string name="permgroupdesc_sms" msgid="4656988620100940350">"saata ja vaadata SMS-sõnumeid"</string>
    +     <string name="permgrouplab_storage" msgid="1971118770546336966">"Mäluruum"</string>
    +-    <string name="permgroupdesc_storage" msgid="637758554581589203">"juurde pääseda seadmesse salvestatud fotodele, meediale ja failidele"</string>
    ++    <string name="permgroupdesc_storage" msgid="637758554581589203">"juurde pääseda seadmesse salvestatud fotodele, meediasisule ja failidele"</string>
    +     <string name="permgrouplab_microphone" msgid="171539900250043464">"Mikrofon"</string>
    +     <string name="permgroupdesc_microphone" msgid="4988812113943554584">"heli salvestamine"</string>
    +     <string name="permgrouplab_camera" msgid="4820372495894586615">"Kaamera"</string>
    +@@ -1076,6 +1077,17 @@
    +     <skip />
    +     <string name="wifi_no_internet" msgid="8451173622563841546">"WiFi-l pole juurdepääsu Internetile"</string>
    +     <string name="wifi_no_internet_detailed" msgid="8083079241212301741">"Puudutage valikute nägemiseks"</string>
    ++    <string name="network_switch_metered" msgid="4671730921726992671">"Lülitati võrgule <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
    ++    <string name="network_switch_metered_detail" msgid="5325661434777870353">"Seade kasutab võrku <xliff:g id="NEW_NETWORK">%1$s</xliff:g>, kui võrgul <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> puudub Interneti-ühendus. Rakenduda võivad tasud."</string>
    ++    <string name="network_switch_metered_toast" msgid="5779283181685974304">"Lülitati võrgult <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> võrgule <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
    ++  <string-array name="network_switch_type_name">
    ++    <item msgid="2952042958050315394">"mobiilne andmeside"</item>
    ++    <item msgid="75483255295529161">"WiFi"</item>
    ++    <item msgid="6862614801537202646">"Bluetooth"</item>
    ++    <item msgid="5447331121797802871">"Ethernet"</item>
    ++    <item msgid="8257233890381651999">"VPN"</item>
    ++  </string-array>
    ++    <string name="network_switch_type_name_unknown" msgid="4552612897806660656">"tundmatu võrgutüüp"</string>
    +     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Ei saanud WiFi-ga ühendust"</string>
    +     <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" on halb Interneti-ühendus."</string>
    +     <string name="wifi_connect_alert_title" msgid="8455846016001810172">"Kas lubada ühendus?"</string>
    +@@ -1153,7 +1165,6 @@
    +     <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"Puudutage keele ja paigutuse valimiseks"</string>
    +     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSŠZŽTUVWÕÄÖÜXY"</string>
    +     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSŠZŽTUVWÕÄÖÜXY"</string>
    +-    <string name="candidates_style" msgid="4333913089637062257"><u>"kandidaadid"</u></string>
    +     <string name="ext_media_checking_notification_title" msgid="5734005953288045806">"Üksuse <xliff:g id="NAME">%s</xliff:g> ettevalmistamine"</string>
    +     <string name="ext_media_checking_notification_message" msgid="4747432538578886744">"Vigade kontrollimine"</string>
    +     <string name="ext_media_new_notification_message" msgid="7589986898808506239">"Tuvastati uus üksus <xliff:g id="NAME">%s</xliff:g>"</string>
    +@@ -1232,8 +1243,9 @@
    +     <string name="vpn_text_long" msgid="4907843483284977618">"Ühendatud seansiga <xliff:g id="SESSION">%s</xliff:g>. Koputage võrgu haldamiseks"</string>
    +     <string name="vpn_lockdown_connecting" msgid="6443438964440960745">"Ühendamine alati sees VPN-iga …"</string>
    +     <string name="vpn_lockdown_connected" msgid="8202679674819213931">"Ühendatud alati sees VPN-iga"</string>
    ++    <string name="vpn_lockdown_disconnected" msgid="4532298952570796327">"Alati sees VPN pole ühendatud"</string>
    +     <string name="vpn_lockdown_error" msgid="6009249814034708175">"Alati sees VPN-i viga"</string>
    +-    <string name="vpn_lockdown_config" msgid="4655589351146766608">"Puudutage seadistamiseks"</string>
    ++    <string name="vpn_lockdown_config" msgid="5099330695245008680">"Puudutage seadistamiseks"</string>
    +     <string name="upload_file" msgid="2897957172366730416">"Valige fail"</string>
    +     <string name="no_file_chosen" msgid="6363648562170759465">"Ühtegi faili pole valitud"</string>
    +     <string name="reset" msgid="2448168080964209908">"Lähtesta"</string>
    +@@ -1317,7 +1329,7 @@
    +     <string name="storage_usb_drive_label" msgid="4501418548927759953">"Tootja <xliff:g id="MANUFACTURER">%s</xliff:g> USB-ketas"</string>
    +     <string name="storage_usb" msgid="3017954059538517278">"USB-mäluseade"</string>
    +     <string name="extract_edit_menu_button" msgid="8940478730496610137">"Muuda"</string>
    +-    <string name="data_usage_warning_title" msgid="1955638862122232342">"Andmete kasutamise hoiatus"</string>
    ++    <string name="data_usage_warning_title" msgid="3620440638180218181">"Andmekasutuse hoiatus"</string>
    +     <string name="data_usage_warning_body" msgid="6660692274311972007">"Puudutage kasutuse/seadete vaat."</string>
    +     <string name="data_usage_3g_limit_title" msgid="4361523876818447683">"2G-, 3G-andmeside limiit on täis"</string>
    +     <string name="data_usage_4g_limit_title" msgid="4609566827219442376">"4G-andmeside limiit on täis"</string>
    +@@ -1636,6 +1648,7 @@
    +     <string name="search_language_hint" msgid="7042102592055108574">"Sisestage keele nimi"</string>
    +     <string name="language_picker_section_suggested" msgid="8414489646861640885">"Soovitatud"</string>
    +     <string name="language_picker_section_all" msgid="3097279199511617537">"Kõik keeled"</string>
    ++    <string name="region_picker_section_all" msgid="8966316787153001779">"Kõik piirkonnad"</string>
    +     <string name="locale_search_menu" msgid="2560710726687249178">"Otsing"</string>
    +     <string name="work_mode_off_title" msgid="8954725060677558855">"Töörežiim on VÄLJA LÜLITATUD"</string>
    +     <string name="work_mode_off_message" msgid="3286169091278094476">"Lubatakse tööprofiili toimingud, sh rakendused, taustal sünkroonimine ja seotud funktsioonid."</string>
    +diff --git a/core/res/res/values-eu-rES/strings.xml b/core/res/res/values-eu-rES/strings.xml
    +index 7dc0877..97628fc 100644
    +--- a/core/res/res/values-eu-rES/strings.xml
    ++++ b/core/res/res/values-eu-rES/strings.xml
    +@@ -214,6 +214,7 @@
    +     <string name="global_actions" product="default" msgid="2406416831541615258">"Telefonoaren aukerak"</string>
    +     <string name="global_action_lock" msgid="2844945191792119712">"Pantailaren blokeoa"</string>
    +     <string name="global_action_power_off" msgid="4471879440839879722">"Itzali"</string>
    ++    <string name="global_action_emergency" msgid="7112311161137421166">"Larrialdiak"</string>
    +     <string name="global_action_bug_report" msgid="7934010578922304799">"Akatsen txostena"</string>
    +     <string name="bugreport_title" msgid="2667494803742548533">"Sortu akatsen txostena"</string>
    +     <string name="bugreport_message" msgid="398447048750350456">"Gailuaren uneko egoerari buruzko informazioa bilduko da, mezu elektroniko gisa bidaltzeko. Minutu batzuk igaroko dira akatsen txostena sortzen hasten denetik bidaltzeko prest egon arte. Itxaron, mesedez."</string>
    +@@ -742,7 +743,7 @@
    +     <string name="keyguard_accessibility_user_selector" msgid="1226798370913698896">"Erabiltzaile-hautatzailea"</string>
    +     <string name="keyguard_accessibility_status" msgid="8008264603935930611">"Egoera"</string>
    +     <string name="keyguard_accessibility_camera" msgid="8904231194181114603">"Kamera"</string>
    +-    <string name="keygaurd_accessibility_media_controls" msgid="262209654292161806">"Multimedia-kontrolak"</string>
    ++    <string name="keygaurd_accessibility_media_controls" msgid="262209654292161806">"Multimedia kontrolatzeko aukerak"</string>
    +     <string name="keyguard_accessibility_widget_reorder_start" msgid="8736853615588828197">"Widgetak berrantolatzen hasi da."</string>
    +     <string name="keyguard_accessibility_widget_reorder_end" msgid="7170190950870468320">"Widgetak berrantolatu dira."</string>
    +     <string name="keyguard_accessibility_widget_deleted" msgid="4426204263929224434">"<xliff:g id="WIDGET_INDEX">%1$s</xliff:g> widgeta ezabatu da."</string>
    +@@ -1074,8 +1075,19 @@
    +     <string name="network_available_sign_in" msgid="1848877297365446605">"Hasi saioa sarean"</string>
    +     <!-- no translation found for network_available_sign_in_detailed (8000081941447976118) -->
    +     <skip />
    +-    <string name="wifi_no_internet" msgid="8451173622563841546">"Wi-Fi konexioa ezin da Internetera konektatu"</string>
    ++    <string name="wifi_no_internet" msgid="8451173622563841546">"Wi-Fi eginbidea ezin da Internetera konektatu"</string>
    +     <string name="wifi_no_internet_detailed" msgid="8083079241212301741">"Sakatu aukerak ikusteko"</string>
    ++    <string name="network_switch_metered" msgid="4671730921726992671">"<xliff:g id="NETWORK_TYPE">%1$s</xliff:g> erabiltzen ari zara orain"</string>
    ++    <string name="network_switch_metered_detail" msgid="5325661434777870353">"<xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> Internetera konektatzeko gauza ez denean, <xliff:g id="NEW_NETWORK">%1$s</xliff:g> erabiltzen du gailuak. Agian kostuak ordaindu beharko dituzu."</string>
    ++    <string name="network_switch_metered_toast" msgid="5779283181685974304">"<xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> erabiltzen ari zinen, baina <xliff:g id="NEW_NETWORK">%2$s</xliff:g> erabiltzen ari zara orain"</string>
    ++  <string-array name="network_switch_type_name">
    ++    <item msgid="2952042958050315394">"datu-konexioa"</item>
    ++    <item msgid="75483255295529161">"Wi-Fi"</item>
    ++    <item msgid="6862614801537202646">"Bluetooth"</item>
    ++    <item msgid="5447331121797802871">"Ethernet"</item>
    ++    <item msgid="8257233890381651999">"VPN"</item>
    ++  </string-array>
    ++    <string name="network_switch_type_name_unknown" msgid="4552612897806660656">"sare mota ezezaguna"</string>
    +     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Ezin izan da Wi-Fi sarera konektatu"</string>
    +     <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" Interneteko konexio txarra du."</string>
    +     <string name="wifi_connect_alert_title" msgid="8455846016001810172">"Konektatzea baimendu nahi diozu?"</string>
    +@@ -1153,7 +1165,6 @@
    +     <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"Hizkuntza eta diseinua hautatzeko, sakatu hau"</string>
    +     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
    +     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
    +-    <string name="candidates_style" msgid="4333913089637062257"><u>"hautagaiak"</u></string>
    +     <string name="ext_media_checking_notification_title" msgid="5734005953288045806">"<xliff:g id="NAME">%s</xliff:g> prestatzen"</string>
    +     <string name="ext_media_checking_notification_message" msgid="4747432538578886744">"Errorerik dagoen egiaztatzen"</string>
    +     <string name="ext_media_new_notification_message" msgid="7589986898808506239">"<xliff:g id="NAME">%s</xliff:g> berria hauteman da"</string>
    +@@ -1232,8 +1243,9 @@
    +     <string name="vpn_text_long" msgid="4907843483284977618">"<xliff:g id="SESSION">%s</xliff:g> saiora konektatuta. Sakatu sarea kudeatzeko."</string>
    +     <string name="vpn_lockdown_connecting" msgid="6443438964440960745">"Beti aktibatuta dagoen VPNa konektatzen…"</string>
    +     <string name="vpn_lockdown_connected" msgid="8202679674819213931">"Beti aktibatuta dagoen VPNa konektatu da"</string>
    ++    <string name="vpn_lockdown_disconnected" msgid="4532298952570796327">"Deskonektatu egin da beti aktibatuta dagoen VPN konexioa"</string>
    +     <string name="vpn_lockdown_error" msgid="6009249814034708175">"Beti aktibatuta dagoen VPN errorea"</string>
    +-    <string name="vpn_lockdown_config" msgid="4655589351146766608">"Sakatu konfiguratzeko"</string>
    ++    <string name="vpn_lockdown_config" msgid="5099330695245008680">"Konfiguratzeko, sakatu hau"</string>
    +     <string name="upload_file" msgid="2897957172366730416">"Aukeratu fitxategia"</string>
    +     <string name="no_file_chosen" msgid="6363648562170759465">"Ez da fitxategirik aukeratu"</string>
    +     <string name="reset" msgid="2448168080964209908">"Berrezarri"</string>
    +@@ -1317,7 +1329,7 @@
    +     <string name="storage_usb_drive_label" msgid="4501418548927759953">"<xliff:g id="MANUFACTURER">%s</xliff:g> USB unitatea"</string>
    +     <string name="storage_usb" msgid="3017954059538517278">"USB memoria"</string>
    +     <string name="extract_edit_menu_button" msgid="8940478730496610137">"Editatu"</string>
    +-    <string name="data_usage_warning_title" msgid="1955638862122232342">"Datuen erabilerari buruzko abisua"</string>
    ++    <string name="data_usage_warning_title" msgid="3620440638180218181">"Datu-erabilerari buruzko abisua"</string>
    +     <string name="data_usage_warning_body" msgid="6660692274311972007">"Sakatu erabilera eta ezarpenak ikusteko."</string>
    +     <string name="data_usage_3g_limit_title" msgid="4361523876818447683">"2-3 GB-ko mugara iritsi zara"</string>
    +     <string name="data_usage_4g_limit_title" msgid="4609566827219442376">"4 GB-ko mugara iritsi zara"</string>
    +@@ -1636,6 +1648,7 @@
    +     <string name="search_language_hint" msgid="7042102592055108574">"Adierazi hizkuntza"</string>
    +     <string name="language_picker_section_suggested" msgid="8414489646861640885">"Iradokitakoak"</string>
    +     <string name="language_picker_section_all" msgid="3097279199511617537">"Hizkuntza guztiak"</string>
    ++    <string name="region_picker_section_all" msgid="8966316787153001779">"Lurralde guztiak"</string>
    +     <string name="locale_search_menu" msgid="2560710726687249178">"Bilaketa"</string>
    +     <string name="work_mode_off_title" msgid="8954725060677558855">"Desaktibatuta dago laneko modua"</string>
    +     <string name="work_mode_off_message" msgid="3286169091278094476">"Baimendu laneko profilak funtzionatzea, besteak beste, aplikazioak, atzeko planoko sinkronizazioa eta erlazionatutako eginbideak."</string>
    +diff --git a/core/res/res/values-fa/strings.xml b/core/res/res/values-fa/strings.xml
    +index 5976ad1..128a66f 100644
    +--- a/core/res/res/values-fa/strings.xml
    ++++ b/core/res/res/values-fa/strings.xml
    +@@ -214,6 +214,7 @@
    +     <string name="global_actions" product="default" msgid="2406416831541615258">"گزینه‌های تلفن"</string>
    +     <string name="global_action_lock" msgid="2844945191792119712">"قفل صفحه"</string>
    +     <string name="global_action_power_off" msgid="4471879440839879722">"خاموش کردن"</string>
    ++    <string name="global_action_emergency" msgid="7112311161137421166">"اضطراری"</string>
    +     <string name="global_action_bug_report" msgid="7934010578922304799">"گزارش اشکال"</string>
    +     <string name="bugreport_title" msgid="2667494803742548533">"گرفتن گزارش اشکال"</string>
    +     <string name="bugreport_message" msgid="398447048750350456">"این گزارش اطلاعات مربوط به وضعیت دستگاه کنونی شما را جمع‌آوری می‌کند تا به صورت یک پیام رایانامه ارسال شود. از زمان شروع گزارش اشکال تا آماده شدن برای ارسال اندکی زمان می‌برد؛ لطفاً شکیبا باشید."</string>
    +@@ -924,9 +925,9 @@
    +       <item quantity="one">در <xliff:g id="COUNT_1">%d</xliff:g> سال</item>
    +       <item quantity="other">در <xliff:g id="COUNT_1">%d</xliff:g> سال</item>
    +     </plurals>
    +-    <string name="VideoView_error_title" msgid="3534509135438353077">"مشکل در ویدیو"</string>
    +-    <string name="VideoView_error_text_invalid_progressive_playback" msgid="3186670335938670444">"متأسفیم، این ویدیو برای پخش جریانی با این دستگاه معتبر نیست."</string>
    +-    <string name="VideoView_error_text_unknown" msgid="3450439155187810085">"پخش این ویدیو ممکن نیست."</string>
    ++    <string name="VideoView_error_title" msgid="3534509135438353077">"مشکل در ویدئو"</string>
    ++    <string name="VideoView_error_text_invalid_progressive_playback" msgid="3186670335938670444">"متأسفیم، این ویدئو برای پخش جریانی با این دستگاه معتبر نیست."</string>
    ++    <string name="VideoView_error_text_unknown" msgid="3450439155187810085">"پخش این ویدئو ممکن نیست."</string>
    +     <string name="VideoView_error_button" msgid="2822238215100679592">"تأیید"</string>
    +     <string name="relative_time" msgid="1818557177829411417">"<xliff:g id="DATE">%1$s</xliff:g>، <xliff:g id="TIME">%2$s</xliff:g>"</string>
    +     <string name="noon" msgid="7245353528818587908">"ظهر"</string>
    +@@ -1076,6 +1077,17 @@
    +     <skip />
    +     <string name="wifi_no_internet" msgid="8451173622563841546">"‏Wi-Fi به اینترنت دسترسی ندارد"</string>
    +     <string name="wifi_no_internet_detailed" msgid="8083079241212301741">"برای گزینه‌ها ضربه بزنید"</string>
    ++    <string name="network_switch_metered" msgid="4671730921726992671">"به <xliff:g id="NETWORK_TYPE">%1$s</xliff:g> تغییر کرد"</string>
    ++    <string name="network_switch_metered_detail" msgid="5325661434777870353">"وقتی <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> دسترسی به اینترنت نداشته باشد، دستگاه از <xliff:g id="NEW_NETWORK">%1$s</xliff:g> استفاده می‌کند. ممکن است هزینه‌هایی اعمال شود."</string>
    ++    <string name="network_switch_metered_toast" msgid="5779283181685974304">"از <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> به <xliff:g id="NEW_NETWORK">%2$s</xliff:g> تغییر کرد"</string>
    ++  <string-array name="network_switch_type_name">
    ++    <item msgid="2952042958050315394">"داده شبکه تلفن همراه"</item>
    ++    <item msgid="75483255295529161">"Wi-Fi"</item>
    ++    <item msgid="6862614801537202646">"بلوتوث"</item>
    ++    <item msgid="5447331121797802871">"اترنت"</item>
    ++    <item msgid="8257233890381651999">"VPN"</item>
    ++  </string-array>
    ++    <string name="network_switch_type_name_unknown" msgid="4552612897806660656">"نوع شبکه نامشخص"</string>
    +     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"‏اتصال به Wi-Fi ممکن نیست"</string>
    +     <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" اتصال اینترنتی ضعیفی دارد."</string>
    +     <string name="wifi_connect_alert_title" msgid="8455846016001810172">"اتصال مجاز است؟"</string>
    +@@ -1153,7 +1165,6 @@
    +     <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"برای انتخاب زبان و چیدمان ضربه بزنید"</string>
    +     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
    +     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
    +-    <string name="candidates_style" msgid="4333913089637062257"><u>"داوطلبین"</u></string>
    +     <string name="ext_media_checking_notification_title" msgid="5734005953288045806">"در حال آماده‌سازی <xliff:g id="NAME">%s</xliff:g>"</string>
    +     <string name="ext_media_checking_notification_message" msgid="4747432538578886744">"در حال بررسی برای خطاها"</string>
    +     <string name="ext_media_new_notification_message" msgid="7589986898808506239">"<xliff:g id="NAME">%s</xliff:g> جدید شناسایی شد"</string>
    +@@ -1232,8 +1243,9 @@
    +     <string name="vpn_text_long" msgid="4907843483284977618">"به <xliff:g id="SESSION">%s</xliff:g> متصل شد. برای مدیریت شبکه ضربه بزنید."</string>
    +     <string name="vpn_lockdown_connecting" msgid="6443438964440960745">"‏در حال اتصال VPN همیشه فعال…"</string>
    +     <string name="vpn_lockdown_connected" msgid="8202679674819213931">"‏VPN همیشه فعال متصل شد"</string>
    ++    <string name="vpn_lockdown_disconnected" msgid="4532298952570796327">"‏ارتباط VPN همیشه روشن قطع شد"</string>
    +     <string name="vpn_lockdown_error" msgid="6009249814034708175">"‏خطای VPN همیشه فعال"</string>
    +-    <string name="vpn_lockdown_config" msgid="4655589351146766608">"جهت پیکربندی ضربه بزنید"</string>
    ++    <string name="vpn_lockdown_config" msgid="5099330695245008680">"برای راه‌اندازی ضربه بزنید"</string>
    +     <string name="upload_file" msgid="2897957172366730416">"انتخاب فایل"</string>
    +     <string name="no_file_chosen" msgid="6363648562170759465">"هیچ فایلی انتخاب نشد"</string>
    +     <string name="reset" msgid="2448168080964209908">"بازنشانی"</string>
    +@@ -1317,7 +1329,7 @@
    +     <string name="storage_usb_drive_label" msgid="4501418548927759953">"‏درایو USB ‏<xliff:g id="MANUFACTURER">%s</xliff:g>"</string>
    +     <string name="storage_usb" msgid="3017954059538517278">"‏حافظهٔ USB"</string>
    +     <string name="extract_edit_menu_button" msgid="8940478730496610137">"ویرایش"</string>
    +-    <string name="data_usage_warning_title" msgid="1955638862122232342">"هشدار میزان استفاده از داده"</string>
    ++    <string name="data_usage_warning_title" msgid="3620440638180218181">"هشدار مصرف داده"</string>
    +     <string name="data_usage_warning_body" msgid="6660692274311972007">"برای مشاهده مصرف و تنظیمات ضربه بزنید."</string>
    +     <string name="data_usage_3g_limit_title" msgid="4361523876818447683">"‏به حد مجاز مصرف داده 2G-3G رسید"</string>
    +     <string name="data_usage_4g_limit_title" msgid="4609566827219442376">"‏به حد مجاز مصرف داده 4G رسید"</string>
    +@@ -1512,8 +1524,8 @@
    +     <string name="mediasize_japanese_kahu" msgid="6872696027560065173">"Kahu"</string>
    +     <string name="mediasize_japanese_kaku2" msgid="2359077233775455405">"Kaku2"</string>
    +     <string name="mediasize_japanese_you4" msgid="2091777168747058008">"You4"</string>
    +-    <string name="mediasize_unknown_portrait" msgid="3088043641616409762">"عمودی ناشناس"</string>
    +-    <string name="mediasize_unknown_landscape" msgid="4876995327029361552">"افقی ناشناس"</string>
    ++    <string name="mediasize_unknown_portrait" msgid="3088043641616409762">"عمودی نامشخص"</string>
    ++    <string name="mediasize_unknown_landscape" msgid="4876995327029361552">"افقی نامشخص"</string>
    +     <string name="write_fail_reason_cancelled" msgid="7091258378121627624">"لغو شد"</string>
    +     <string name="write_fail_reason_cannot_write" msgid="8132505417935337724">"خطا هنگام نوشتن محتوا"</string>
    +     <string name="reason_unknown" msgid="6048913880184628119">"نامعلوم"</string>
    +@@ -1636,6 +1648,7 @@
    +     <string name="search_language_hint" msgid="7042102592055108574">"نام زبان را تایپ کنید"</string>
    +     <string name="language_picker_section_suggested" msgid="8414489646861640885">"پیشنهادشده"</string>
    +     <string name="language_picker_section_all" msgid="3097279199511617537">"همه زبان‌ها"</string>
    ++    <string name="region_picker_section_all" msgid="8966316787153001779">"همه منطقه‌ها"</string>
    +     <string name="locale_search_menu" msgid="2560710726687249178">"جستجو"</string>
    +     <string name="work_mode_off_title" msgid="8954725060677558855">"حالت کاری خاموش است"</string>
    +     <string name="work_mode_off_message" msgid="3286169091278094476">"به نمایه کاری اجازه فعالیت ( شامل استفاده از برنامه‌ها، همگام‌سازی در پس‌زمینه و قابلیت‌های مرتبط) داده شود."</string>
    +diff --git a/core/res/res/values-fi/strings.xml b/core/res/res/values-fi/strings.xml
    +index b221750..c4c223b 100644
    +--- a/core/res/res/values-fi/strings.xml
    ++++ b/core/res/res/values-fi/strings.xml
    +@@ -214,6 +214,7 @@
    +     <string name="global_actions" product="default" msgid="2406416831541615258">"Puhelimen asetukset"</string>
    +     <string name="global_action_lock" msgid="2844945191792119712">"Näytön lukitus"</string>
    +     <string name="global_action_power_off" msgid="4471879440839879722">"Katkaise virta"</string>
    ++    <string name="global_action_emergency" msgid="7112311161137421166">"Hätäpuhelu"</string>
    +     <string name="global_action_bug_report" msgid="7934010578922304799">"Virheraportti"</string>
    +     <string name="bugreport_title" msgid="2667494803742548533">"Luo virheraportti"</string>
    +     <string name="bugreport_message" msgid="398447048750350456">"Toiminto kerää tietoja laitteen tilasta ja lähettää ne sähköpostitse. Virheraportti on valmis lähetettäväksi hetken kuluttua - kiitos kärsivällisyydestäsi."</string>
    +@@ -1076,6 +1077,17 @@
    +     <skip />
    +     <string name="wifi_no_internet" msgid="8451173622563841546">"Wi-Fi ei ole yhteydessä internetiin."</string>
    +     <string name="wifi_no_internet_detailed" msgid="8083079241212301741">"Näytä vaihtoehdot napauttamalla."</string>
    ++    <string name="network_switch_metered" msgid="4671730921726992671">"<xliff:g id="NETWORK_TYPE">%1$s</xliff:g> otettiin käyttöön"</string>
    ++    <string name="network_switch_metered_detail" msgid="5325661434777870353">"<xliff:g id="NEW_NETWORK">%1$s</xliff:g> otetaan käyttöön, kun <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> ei voi muodostaa yhteyttä internetiin. Veloitukset ovat mahdollisia."</string>
    ++    <string name="network_switch_metered_toast" msgid="5779283181685974304">"<xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> poistettiin käytöstä ja <xliff:g id="NEW_NETWORK">%2$s</xliff:g> otettiin käyttöön."</string>
    ++  <string-array name="network_switch_type_name">
    ++    <item msgid="2952042958050315394">"mobiilidata"</item>
    ++    <item msgid="75483255295529161">"Wi-Fi"</item>
    ++    <item msgid="6862614801537202646">"Bluetooth"</item>
    ++    <item msgid="5447331121797802871">"Ethernet"</item>
    ++    <item msgid="8257233890381651999">"VPN"</item>
    ++  </string-array>
    ++    <string name="network_switch_type_name_unknown" msgid="4552612897806660656">"tuntematon verkon tyyppi"</string>
    +     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Wi-Fi-yhteyden muodostaminen epäonnistui"</string>
    +     <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" : huono internetyhteys."</string>
    +     <string name="wifi_connect_alert_title" msgid="8455846016001810172">"Sallitaanko yhteys?"</string>
    +@@ -1153,7 +1165,6 @@
    +     <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"Valitse kieli ja asettelu koskettamalla."</string>
    +     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZÅÄÖ"</string>
    +     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
    +-    <string name="candidates_style" msgid="4333913089637062257"><u>"kandidaatit"</u></string>
    +     <string name="ext_media_checking_notification_title" msgid="5734005953288045806">"Valmistellaan kohdetta <xliff:g id="NAME">%s</xliff:g>"</string>
    +     <string name="ext_media_checking_notification_message" msgid="4747432538578886744">"Tarkistetaan virheiden varalta."</string>
    +     <string name="ext_media_new_notification_message" msgid="7589986898808506239">"Uusi <xliff:g id="NAME">%s</xliff:g> on havaittu."</string>
    +@@ -1232,8 +1243,9 @@
    +     <string name="vpn_text_long" msgid="4907843483284977618">"Yhdistetty: <xliff:g id="SESSION">%s</xliff:g>. Hallinnoi verkkoa napauttamalla."</string>
    +     <string name="vpn_lockdown_connecting" msgid="6443438964440960745">"Yhdistetään aina käytössä olevaan VPN-verkkoon..."</string>
    +     <string name="vpn_lockdown_connected" msgid="8202679674819213931">"Yhdistetty aina käytössä olevaan VPN-verkkoon"</string>
    ++    <string name="vpn_lockdown_disconnected" msgid="4532298952570796327">"Aina käytössä olevan VPN:n yhteys on katkaistu"</string>
    +     <string name="vpn_lockdown_error" msgid="6009249814034708175">"Aina käytössä oleva VPN: virhe"</string>
    +-    <string name="vpn_lockdown_config" msgid="4655589351146766608">"Määritä napauttamalla."</string>
    ++    <string name="vpn_lockdown_config" msgid="5099330695245008680">"Määritä koskettamalla."</string>
    +     <string name="upload_file" msgid="2897957172366730416">"Valitse tiedosto"</string>
    +     <string name="no_file_chosen" msgid="6363648562170759465">"Ei valittua tiedostoa"</string>
    +     <string name="reset" msgid="2448168080964209908">"Palauta"</string>
    +@@ -1317,7 +1329,7 @@
    +     <string name="storage_usb_drive_label" msgid="4501418548927759953">"USB-asema: <xliff:g id="MANUFACTURER">%s</xliff:g>"</string>
    +     <string name="storage_usb" msgid="3017954059538517278">"USB-tallennustila"</string>
    +     <string name="extract_edit_menu_button" msgid="8940478730496610137">"Muokkaa"</string>
    +-    <string name="data_usage_warning_title" msgid="1955638862122232342">"Tiedonsiirtovaroitus"</string>
    ++    <string name="data_usage_warning_title" msgid="3620440638180218181">"Datankäyttövaroitus"</string>
    +     <string name="data_usage_warning_body" msgid="6660692274311972007">"Käyttö &amp; asetukset napauttamalla"</string>
    +     <string name="data_usage_3g_limit_title" msgid="4361523876818447683">"2G-3G-tietojen raja saavutettu"</string>
    +     <string name="data_usage_4g_limit_title" msgid="4609566827219442376">"4G-tietojen raja saavutettu"</string>
    +@@ -1636,6 +1648,7 @@
    +     <string name="search_language_hint" msgid="7042102592055108574">"Anna kielen nimi"</string>
    +     <string name="language_picker_section_suggested" msgid="8414489646861640885">"Ehdotukset"</string>
    +     <string name="language_picker_section_all" msgid="3097279199511617537">"Kaikki kielet"</string>
    ++    <string name="region_picker_section_all" msgid="8966316787153001779">"Kaikki alueet"</string>
    +     <string name="locale_search_menu" msgid="2560710726687249178">"Haku"</string>
    +     <string name="work_mode_off_title" msgid="8954725060677558855">"Työtila on pois käytöstä"</string>
    +     <string name="work_mode_off_message" msgid="3286169091278094476">"Sallii työprofiiliin toiminnan, esimerkiksi sovellukset ja taustasynkronoinnin."</string>
    +diff --git a/core/res/res/values-fr-rCA/strings.xml b/core/res/res/values-fr-rCA/strings.xml
    +index d9fbceb..e52eeda 100644
    +--- a/core/res/res/values-fr-rCA/strings.xml
    ++++ b/core/res/res/values-fr-rCA/strings.xml
    +@@ -214,6 +214,7 @@
    +     <string name="global_actions" product="default" msgid="2406416831541615258">"Options du téléphone"</string>
    +     <string name="global_action_lock" msgid="2844945191792119712">"Verrouillage de l\'écran"</string>
    +     <string name="global_action_power_off" msgid="4471879440839879722">"Éteindre"</string>
    ++    <string name="global_action_emergency" msgid="7112311161137421166">"Urgence"</string>
    +     <string name="global_action_bug_report" msgid="7934010578922304799">"Rapport de bogue"</string>
    +     <string name="bugreport_title" msgid="2667494803742548533">"Créer un rapport de bogue"</string>
    +     <string name="bugreport_message" msgid="398447048750350456">"Cela permet de recueillir des informations concernant l\'état actuel de votre appareil. Ces informations sont ensuite envoyées sous forme de courriel. Merci de patienter pendant la préparation du rapport de bogue. Cette opération peut prendre quelques instants."</string>
    +@@ -1076,6 +1077,17 @@
    +     <skip />
    +     <string name="wifi_no_internet" msgid="8451173622563841546">"Le réseau Wi-Fi ne dispose d\'aucun accès à Internet"</string>
    +     <string name="wifi_no_internet_detailed" msgid="8083079241212301741">"Touchez pour afficher les options"</string>
    ++    <string name="network_switch_metered" msgid="4671730921726992671">"Passé au réseau <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
    ++    <string name="network_switch_metered_detail" msgid="5325661434777870353">"L\'appareil utilise <xliff:g id="NEW_NETWORK">%1$s</xliff:g> quand <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> n\'a pas d\'accès à Internet. Des frais peuvent s\'appliquer."</string>
    ++    <string name="network_switch_metered_toast" msgid="5779283181685974304">"Passé du réseau <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> au <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
    ++  <string-array name="network_switch_type_name">
    ++    <item msgid="2952042958050315394">"données cellulaires"</item>
    ++    <item msgid="75483255295529161">"Wi-Fi"</item>
    ++    <item msgid="6862614801537202646">"Bluetooth"</item>
    ++    <item msgid="5447331121797802871">"Ethernet"</item>
    ++    <item msgid="8257233890381651999">"RPV"</item>
    ++  </string-array>
    ++    <string name="network_switch_type_name_unknown" msgid="4552612897806660656">"un type de réseau inconnu"</string>
    +     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Impossible de se connecter au Wi-Fi."</string>
    +     <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" dispose d\'une mauvaise connexion Internet."</string>
    +     <string name="wifi_connect_alert_title" msgid="8455846016001810172">"Autoriser la connexion?"</string>
    +@@ -1153,7 +1165,6 @@
    +     <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"Touchez pour sélectionner la langue et la configuration du clavier"</string>
    +     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
    +     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
    +-    <string name="candidates_style" msgid="4333913089637062257"><u>"candidats"</u></string>
    +     <string name="ext_media_checking_notification_title" msgid="5734005953288045806">"Préparation de « <xliff:g id="NAME">%s</xliff:g> » en cours"</string>
    +     <string name="ext_media_checking_notification_message" msgid="4747432538578886744">"Recherche d\'erreurs en cours..."</string>
    +     <string name="ext_media_new_notification_message" msgid="7589986898808506239">"Une nouvelle mémoire « <xliff:g id="NAME">%s</xliff:g> » a été détectée"</string>
    +@@ -1232,8 +1243,9 @@
    +     <string name="vpn_text_long" msgid="4907843483284977618">"Connecté à <xliff:g id="SESSION">%s</xliff:g>. Appuyez ici pour gérer le réseau."</string>
    +     <string name="vpn_lockdown_connecting" msgid="6443438964440960745">"VPN permanent en cours de connexion…"</string>
    +     <string name="vpn_lockdown_connected" msgid="8202679674819213931">"VPN permanent connecté"</string>
    ++    <string name="vpn_lockdown_disconnected" msgid="4532298952570796327">"RPV permanent déconnecté"</string>
    +     <string name="vpn_lockdown_error" msgid="6009249814034708175">"Erreur du VPN permanent"</string>
    +-    <string name="vpn_lockdown_config" msgid="4655589351146766608">"Touchez pour configurer"</string>
    ++    <string name="vpn_lockdown_config" msgid="5099330695245008680">"Touchez pour configurer"</string>
    +     <string name="upload_file" msgid="2897957172366730416">"Choisir un fichier"</string>
    +     <string name="no_file_chosen" msgid="6363648562170759465">"Aucun fichier sélectionné"</string>
    +     <string name="reset" msgid="2448168080964209908">"Réinitialiser"</string>
    +@@ -1317,7 +1329,7 @@
    +     <string name="storage_usb_drive_label" msgid="4501418548927759953">"Clé USB <xliff:g id="MANUFACTURER">%s</xliff:g>"</string>
    +     <string name="storage_usb" msgid="3017954059538517278">"Mémoire de stockage USB"</string>
    +     <string name="extract_edit_menu_button" msgid="8940478730496610137">"Modifier"</string>
    +-    <string name="data_usage_warning_title" msgid="1955638862122232342">"Avertissement utilisation données"</string>
    ++    <string name="data_usage_warning_title" msgid="3620440638180218181">"Alerte d\'utilisation des données"</string>
    +     <string name="data_usage_warning_body" msgid="6660692274311972007">"Touch. pour aff. util. et param."</string>
    +     <string name="data_usage_3g_limit_title" msgid="4361523876818447683">"Limite de données 2G-3G atteinte"</string>
    +     <string name="data_usage_4g_limit_title" msgid="4609566827219442376">"Limite de données 4G atteinte"</string>
    +@@ -1636,6 +1648,7 @@
    +     <string name="search_language_hint" msgid="7042102592055108574">"Entrez la langue"</string>
    +     <string name="language_picker_section_suggested" msgid="8414489646861640885">"Suggestions"</string>
    +     <string name="language_picker_section_all" msgid="3097279199511617537">"Toutes les langues"</string>
    ++    <string name="region_picker_section_all" msgid="8966316787153001779">"Toutes les régions"</string>
    +     <string name="locale_search_menu" msgid="2560710726687249178">"Rechercher"</string>
    +     <string name="work_mode_off_title" msgid="8954725060677558855">"Le mode Travail est désactivé"</string>
    +     <string name="work_mode_off_message" msgid="3286169091278094476">"Autoriser le fonctionnement du profil professionnel, y compris les applications, la synchronisation en arrière-plan et les fonctionnalités associées."</string>
    +diff --git a/core/res/res/values-fr/strings.xml b/core/res/res/values-fr/strings.xml
    +index 6600f09..9da228e 100644
    +--- a/core/res/res/values-fr/strings.xml
    ++++ b/core/res/res/values-fr/strings.xml
    +@@ -214,6 +214,7 @@
    +     <string name="global_actions" product="default" msgid="2406416831541615258">"Options du téléphone"</string>
    +     <string name="global_action_lock" msgid="2844945191792119712">"Verrouillage de l\'écran"</string>
    +     <string name="global_action_power_off" msgid="4471879440839879722">"Éteindre"</string>
    ++    <string name="global_action_emergency" msgid="7112311161137421166">"Urgences"</string>
    +     <string name="global_action_bug_report" msgid="7934010578922304799">"Rapport de bug"</string>
    +     <string name="bugreport_title" msgid="2667494803742548533">"Créer un rapport de bug"</string>
    +     <string name="bugreport_message" msgid="398447048750350456">"Cela permet de recueillir des informations concernant l\'état actuel de votre appareil. Ces informations sont ensuite envoyées sous forme d\'e-mail. Merci de patienter pendant la préparation du rapport de bug. Cette opération peut prendre quelques instants."</string>
    +@@ -993,7 +994,7 @@
    +     <string name="noApplications" msgid="2991814273936504689">"Aucune application ne peut effectuer cette action."</string>
    +     <string name="aerr_application" msgid="250320989337856518">"<xliff:g id="APPLICATION">%1$s</xliff:g> a cessé de fonctionner."</string>
    +     <string name="aerr_process" msgid="6201597323218674729">"Le processus <xliff:g id="PROCESS">%1$s</xliff:g> a cessé de fonctionner."</string>
    +-    <string name="aerr_application_repeated" msgid="3146328699537439573">"<xliff:g id="APPLICATION">%1$s</xliff:g> ne cesse de s\'arrêter."</string>
    ++    <string name="aerr_application_repeated" msgid="3146328699537439573">"<xliff:g id="APPLICATION">%1$s</xliff:g> s\'arrête systématiquement"</string>
    +     <string name="aerr_process_repeated" msgid="6235302956890402259">"Le processus \"<xliff:g id="PROCESS">%1$s</xliff:g>\" ne cesse de s\'arrêter."</string>
    +     <string name="aerr_restart" msgid="7581308074153624475">"Rouvrir l\'application"</string>
    +     <string name="aerr_report" msgid="5371800241488400617">"Envoyer des commentaires"</string>
    +@@ -1076,6 +1077,17 @@
    +     <skip />
    +     <string name="wifi_no_internet" msgid="8451173622563841546">"Le réseau Wi-Fi ne dispose d\'aucun accès à Internet."</string>
    +     <string name="wifi_no_internet_detailed" msgid="8083079241212301741">"Appuyez ici pour afficher des options."</string>
    ++    <string name="network_switch_metered" msgid="4671730921726992671">"Nouveau réseau : <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
    ++    <string name="network_switch_metered_detail" msgid="5325661434777870353">"L\'appareil utilise <xliff:g id="NEW_NETWORK">%1$s</xliff:g> lorsque <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> n\'a pas de connexion Internet. Des frais supplémentaires peuvent s\'appliquer."</string>
    ++    <string name="network_switch_metered_toast" msgid="5779283181685974304">"Ancien réseau : <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g>. Nouveau réseau : <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
    ++  <string-array name="network_switch_type_name">
    ++    <item msgid="2952042958050315394">"données mobiles"</item>
    ++    <item msgid="75483255295529161">"Wi-Fi"</item>
    ++    <item msgid="6862614801537202646">"Bluetooth"</item>
    ++    <item msgid="5447331121797802871">"Ethernet"</item>
    ++    <item msgid="8257233890381651999">"VPN"</item>
    ++  </string-array>
    ++    <string name="network_switch_type_name_unknown" msgid="4552612897806660656">"type de réseau inconnu"</string>
    +     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Impossible de se connecter au Wi-Fi."</string>
    +     <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" dispose d\'une mauvaise connexion Internet."</string>
    +     <string name="wifi_connect_alert_title" msgid="8455846016001810172">"Autoriser la connexion ?"</string>
    +@@ -1153,7 +1165,6 @@
    +     <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"Appuyer pour sélectionner la langue et la disposition"</string>
    +     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
    +     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
    +-    <string name="candidates_style" msgid="4333913089637062257"><u>"candidats"</u></string>
    +     <string name="ext_media_checking_notification_title" msgid="5734005953288045806">"Préparation mémoire \"<xliff:g id="NAME">%s</xliff:g>\" en cours"</string>
    +     <string name="ext_media_checking_notification_message" msgid="4747432538578886744">"Recherche d\'erreurs"</string>
    +     <string name="ext_media_new_notification_message" msgid="7589986898808506239">"Une nouvelle mémoire de stockage \"<xliff:g id="NAME">%s</xliff:g>\" a été détectée."</string>
    +@@ -1232,8 +1243,9 @@
    +     <string name="vpn_text_long" msgid="4907843483284977618">"Connecté à <xliff:g id="SESSION">%s</xliff:g>. Appuyez ici pour gérer le réseau."</string>
    +     <string name="vpn_lockdown_connecting" msgid="6443438964440960745">"VPN permanent en cours de connexion…"</string>
    +     <string name="vpn_lockdown_connected" msgid="8202679674819213931">"VPN permanent connecté"</string>
    ++    <string name="vpn_lockdown_disconnected" msgid="4532298952570796327">"VPN permanent déconnecté"</string>
    +     <string name="vpn_lockdown_error" msgid="6009249814034708175">"Erreur du VPN permanent"</string>
    +-    <string name="vpn_lockdown_config" msgid="4655589351146766608">"Appuyez ici pour configurer."</string>
    ++    <string name="vpn_lockdown_config" msgid="5099330695245008680">"Appuyer pour configurer"</string>
    +     <string name="upload_file" msgid="2897957172366730416">"Sélectionner un fichier"</string>
    +     <string name="no_file_chosen" msgid="6363648562170759465">"Aucun fichier sélectionné"</string>
    +     <string name="reset" msgid="2448168080964209908">"Réinitialiser"</string>
    +@@ -1317,7 +1329,7 @@
    +     <string name="storage_usb_drive_label" msgid="4501418548927759953">"Clé USB <xliff:g id="MANUFACTURER">%s</xliff:g>"</string>
    +     <string name="storage_usb" msgid="3017954059538517278">"Mémoire de stockage USB"</string>
    +     <string name="extract_edit_menu_button" msgid="8940478730496610137">"Modifier"</string>
    +-    <string name="data_usage_warning_title" msgid="1955638862122232342">"Avertissement utilisation données"</string>
    ++    <string name="data_usage_warning_title" msgid="3620440638180218181">"Alerte de consommation des données"</string>
    +     <string name="data_usage_warning_body" msgid="6660692274311972007">"Appuyez pour conso/paramètres."</string>
    +     <string name="data_usage_3g_limit_title" msgid="4361523876818447683">"Limite de données 2G-3G atteinte"</string>
    +     <string name="data_usage_4g_limit_title" msgid="4609566827219442376">"Limite de données 4G atteinte"</string>
    +@@ -1558,7 +1570,7 @@
    +     <string name="package_deleted_device_owner" msgid="7650577387493101353">"Supprimé par votre administrateur"</string>
    +     <string name="battery_saver_description" msgid="1960431123816253034">"Pour améliorer l\'autonomie de la batterie, l\'économiseur de batterie réduit les performances et désactive le vibreur, les services de localisation et la plupart des données en arrière-plan. Les messageries électroniques ou autres applications utilisant la synchronisation pourraient ne pas se mettre à jour, sauf si vous les ouvrez.\n\nL\'économiseur de batterie s\'éteint automatiquement lorsque l\'appareil est en charge."</string>
    +     <string name="data_saver_description" msgid="6015391409098303235">"Pour réduire la consommation des données, l\'économiseur de données empêche certaines applications d\'envoyer ou de recevoir des données en arrière-plan. Ainsi, une application que vous utilisez actuellement peut accéder à des données, mais moins souvent. Par exemple, il se peut que les images ne s\'affichent pas tant que vous n\'appuyez pas dessus."</string>
    +-    <string name="data_saver_enable_title" msgid="4674073932722787417">"Activer sauvegarde données ?"</string>
    ++    <string name="data_saver_enable_title" msgid="4674073932722787417">"Activer l\'économiseur de données ?"</string>
    +     <string name="data_saver_enable_button" msgid="7147735965247211818">"Activer"</string>
    +     <plurals name="zen_mode_duration_minutes_summary" formatted="false" msgid="4367877408072000848">
    +       <item quantity="one">Pendant %1$d minute (jusqu\'à <xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g>)</item>
    +@@ -1636,6 +1648,7 @@
    +     <string name="search_language_hint" msgid="7042102592055108574">"Saisissez la langue"</string>
    +     <string name="language_picker_section_suggested" msgid="8414489646861640885">"Recommandations"</string>
    +     <string name="language_picker_section_all" msgid="3097279199511617537">"Toutes les langues"</string>
    ++    <string name="region_picker_section_all" msgid="8966316787153001779">"Toutes les régions"</string>
    +     <string name="locale_search_menu" msgid="2560710726687249178">"Rechercher"</string>
    +     <string name="work_mode_off_title" msgid="8954725060677558855">"Mode professionnel DÉSACTIVÉ"</string>
    +     <string name="work_mode_off_message" msgid="3286169091278094476">"Autoriser le fonctionnement du profil professionnel, y compris les applications, la synchronisation en arrière-plan et les fonctionnalités associées."</string>
    +diff --git a/core/res/res/values-gl-rES/strings.xml b/core/res/res/values-gl-rES/strings.xml
    +index 8023edf..72757a6 100644
    +--- a/core/res/res/values-gl-rES/strings.xml
    ++++ b/core/res/res/values-gl-rES/strings.xml
    +@@ -214,6 +214,7 @@
    +     <string name="global_actions" product="default" msgid="2406416831541615258">"Opcións de teléfono"</string>
    +     <string name="global_action_lock" msgid="2844945191792119712">"Bloqueo da pantalla"</string>
    +     <string name="global_action_power_off" msgid="4471879440839879722">"Apagar"</string>
    ++    <string name="global_action_emergency" msgid="7112311161137421166">"Emerxencias"</string>
    +     <string name="global_action_bug_report" msgid="7934010578922304799">"Informe de erros"</string>
    +     <string name="bugreport_title" msgid="2667494803742548533">"Crear informe de erros"</string>
    +     <string name="bugreport_message" msgid="398447048750350456">"Este informe recompilará información acerca do estado actual do teu dispositivo para enviala en forma de mensaxe de correo electrónico. O informe de erros tardará un pouco en completarse desde o seu inicio ata que estea preparado para enviarse, polo que che recomendamos que teñas paciencia."</string>
    +@@ -598,7 +599,7 @@
    +     <string name="phoneTypeCallback" msgid="2712175203065678206">"Devolver chamada"</string>
    +     <string name="phoneTypeCar" msgid="8738360689616716982">"Coche"</string>
    +     <string name="phoneTypeCompanyMain" msgid="540434356461478916">"Empresa (ppal.)"</string>
    +-    <string name="phoneTypeIsdn" msgid="8022453193171370337">"ISDN"</string>
    ++    <string name="phoneTypeIsdn" msgid="8022453193171370337">"RDSI"</string>
    +     <string name="phoneTypeMain" msgid="6766137010628326916">"Principal"</string>
    +     <string name="phoneTypeOtherFax" msgid="8587657145072446565">"Outro fax"</string>
    +     <string name="phoneTypeRadio" msgid="4093738079908667513">"Radio"</string>
    +@@ -1076,6 +1077,17 @@
    +     <skip />
    +     <string name="wifi_no_internet" msgid="8451173622563841546">"A wifi non ten acceso a Internet"</string>
    +     <string name="wifi_no_internet_detailed" msgid="8083079241212301741">"Toca para ver opcións."</string>
    ++    <string name="network_switch_metered" msgid="4671730921726992671">"Cambiouse a: <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
    ++    <string name="network_switch_metered_detail" msgid="5325661434777870353">"O dispositivo utiliza <xliff:g id="NEW_NETWORK">%1$s</xliff:g> cando <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> non ten acceso a Internet. Pódense aplicar cargos."</string>
    ++    <string name="network_switch_metered_toast" msgid="5779283181685974304">"Cambiouse de <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> a <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
    ++  <string-array name="network_switch_type_name">
    ++    <item msgid="2952042958050315394">"datos móbiles"</item>
    ++    <item msgid="75483255295529161">"wifi"</item>
    ++    <item msgid="6862614801537202646">"Bluetooth"</item>
    ++    <item msgid="5447331121797802871">"Ethernet"</item>
    ++    <item msgid="8257233890381651999">"VPN"</item>
    ++  </string-array>
    ++    <string name="network_switch_type_name_unknown" msgid="4552612897806660656">"un tipo de rede descoñecido"</string>
    +     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Non se puido conectar coa rede Wi-Fi"</string>
    +     <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" ten unha conexión a Internet deficiente."</string>
    +     <string name="wifi_connect_alert_title" msgid="8455846016001810172">"Queres permitir a conexión?"</string>
    +@@ -1153,7 +1165,6 @@
    +     <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"Toca para seleccionar o idioma e o deseño"</string>
    +     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNÑOPQRSTUVWXYZ"</string>
    +     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNÑOPQRSTUVWXYZ"</string>
    +-    <string name="candidates_style" msgid="4333913089637062257"><u>"candidatos"</u></string>
    +     <string name="ext_media_checking_notification_title" msgid="5734005953288045806">"Preparando a <xliff:g id="NAME">%s</xliff:g>"</string>
    +     <string name="ext_media_checking_notification_message" msgid="4747432538578886744">"Comprobando se hai erros"</string>
    +     <string name="ext_media_new_notification_message" msgid="7589986898808506239">"Detectouse unha <xliff:g id="NAME">%s</xliff:g> nova"</string>
    +@@ -1232,8 +1243,9 @@
    +     <string name="vpn_text_long" msgid="4907843483284977618">"Conectado a <xliff:g id="SESSION">%s</xliff:g>. Toca aquí para xestionar a rede."</string>
    +     <string name="vpn_lockdown_connecting" msgid="6443438964440960745">"VPN sempre activada conectándose..."</string>
    +     <string name="vpn_lockdown_connected" msgid="8202679674819213931">"VPN sempre activada conectada"</string>
    ++    <string name="vpn_lockdown_disconnected" msgid="4532298952570796327">"Desconectouse a VPN sempre activada"</string>
    +     <string name="vpn_lockdown_error" msgid="6009249814034708175">"Erro na VPN sempre activada"</string>
    +-    <string name="vpn_lockdown_config" msgid="4655589351146766608">"Toca para configurar"</string>
    ++    <string name="vpn_lockdown_config" msgid="5099330695245008680">"Tocar para configurar"</string>
    +     <string name="upload_file" msgid="2897957172366730416">"Escoller un ficheiro"</string>
    +     <string name="no_file_chosen" msgid="6363648562170759465">"Non se seleccionou ningún ficheiro"</string>
    +     <string name="reset" msgid="2448168080964209908">"Restablecer"</string>
    +@@ -1317,7 +1329,7 @@
    +     <string name="storage_usb_drive_label" msgid="4501418548927759953">"Unidade USB de <xliff:g id="MANUFACTURER">%s</xliff:g>"</string>
    +     <string name="storage_usb" msgid="3017954059538517278">"almacenamento USB"</string>
    +     <string name="extract_edit_menu_button" msgid="8940478730496610137">"Editar"</string>
    +-    <string name="data_usage_warning_title" msgid="1955638862122232342">"Aviso de uso de datos"</string>
    ++    <string name="data_usage_warning_title" msgid="3620440638180218181">"Alerta de uso de datos"</string>
    +     <string name="data_usage_warning_body" msgid="6660692274311972007">"Toca para uso e configuración."</string>
    +     <string name="data_usage_3g_limit_title" msgid="4361523876818447683">"Límite de datos de 2G-3G acadado"</string>
    +     <string name="data_usage_4g_limit_title" msgid="4609566827219442376">"Límite de datos de 4G acadado"</string>
    +@@ -1636,6 +1648,7 @@
    +     <string name="search_language_hint" msgid="7042102592055108574">"Nome do idioma"</string>
    +     <string name="language_picker_section_suggested" msgid="8414489646861640885">"Suxeridos"</string>
    +     <string name="language_picker_section_all" msgid="3097279199511617537">"Todos os idiomas"</string>
    ++    <string name="region_picker_section_all" msgid="8966316787153001779">"Todas as rexións"</string>
    +     <string name="locale_search_menu" msgid="2560710726687249178">"Buscar"</string>
    +     <string name="work_mode_off_title" msgid="8954725060677558855">"Modo de traballo DESACTIVADO"</string>
    +     <string name="work_mode_off_message" msgid="3286169091278094476">"Permite que funcione o perfil de traballo, incluídas as aplicacións, a sincronización en segundo plano e as funcións relacionadas."</string>
    +diff --git a/core/res/res/values-gu-rIN/strings.xml b/core/res/res/values-gu-rIN/strings.xml
    +index 5c3bf93..a233361 100644
    +--- a/core/res/res/values-gu-rIN/strings.xml
    ++++ b/core/res/res/values-gu-rIN/strings.xml
    +@@ -214,6 +214,7 @@
    +     <string name="global_actions" product="default" msgid="2406416831541615258">"ફોન વિકલ્પો"</string>
    +     <string name="global_action_lock" msgid="2844945191792119712">"સ્ક્રીન લૉક"</string>
    +     <string name="global_action_power_off" msgid="4471879440839879722">"પાવર બંધ"</string>
    ++    <string name="global_action_emergency" msgid="7112311161137421166">"કટોકટી"</string>
    +     <string name="global_action_bug_report" msgid="7934010578922304799">"બગ રિપોર્ટ"</string>
    +     <string name="bugreport_title" msgid="2667494803742548533">"બગ રિપોર્ટ લો"</string>
    +     <string name="bugreport_message" msgid="398447048750350456">"આ, એક ઇ-મેઇલ સંદેશ તરીકે મોકલવા માટે, તમારા વર્તમાન ઉપકરણ સ્થિતિ વિશેની માહિતી એકત્રિત કરશે. એક બગ રિપોર્ટ પ્રારંભ કરીને તે મોકલવા માટે તૈયાર ન થઈ જાય ત્યાં સુધી તેમાં થોડો સમય લાગશે; કૃપા કરીને ધીરજ રાખો."</string>
    +@@ -1076,6 +1077,17 @@
    +     <skip />
    +     <string name="wifi_no_internet" msgid="8451173622563841546">"Wi-Fi ને કોઈ ઇન્ટરનેટ ઍક્સેસ નથી"</string>
    +     <string name="wifi_no_internet_detailed" msgid="8083079241212301741">"વિકલ્પો માટે ટૅપ કરો"</string>
    ++    <string name="network_switch_metered" msgid="4671730921726992671">"<xliff:g id="NETWORK_TYPE">%1$s</xliff:g> પર સ્વિચ કર્યું"</string>
    ++    <string name="network_switch_metered_detail" msgid="5325661434777870353">"જ્યારે <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> પાસે કોઈ ઇન્ટરનેટ ઍક્સેસ ન હોય ત્યારે ઉપકરણ <xliff:g id="NEW_NETWORK">%1$s</xliff:g> નો ઉપયોગ કરે છે. શુલ્ક લાગુ થઈ શકે છે."</string>
    ++    <string name="network_switch_metered_toast" msgid="5779283181685974304">"<xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> પરથી <xliff:g id="NEW_NETWORK">%2$s</xliff:g> પર સ્વિચ કર્યું"</string>
    ++  <string-array name="network_switch_type_name">
    ++    <item msgid="2952042958050315394">"સેલ્યુલર ડેટા"</item>
    ++    <item msgid="75483255295529161">"Wi-Fi"</item>
    ++    <item msgid="6862614801537202646">"Bluetooth"</item>
    ++    <item msgid="5447331121797802871">"ઇથરનેટ"</item>
    ++    <item msgid="8257233890381651999">"VPN"</item>
    ++  </string-array>
    ++    <string name="network_switch_type_name_unknown" msgid="4552612897806660656">"અજાણ્યો નેટવર્ક પ્રકાર"</string>
    +     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Wi-Fi સાથે કનેક્ટ કરી શકાયું નથી"</string>
    +     <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" નબળું ઇન્ટરનેટ કનેક્શન ધરાવે છે."</string>
    +     <string name="wifi_connect_alert_title" msgid="8455846016001810172">"કનેક્શનની મંજૂરી આપીએ?"</string>
    +@@ -1153,7 +1165,6 @@
    +     <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"ભાષા અને લેઆઉટ પસંદ કરવા માટે ટૅપ કરો"</string>
    +     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
    +     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
    +-    <string name="candidates_style" msgid="4333913089637062257"><u>"ઉમેદવારો"</u></string>
    +     <string name="ext_media_checking_notification_title" msgid="5734005953288045806">"<xliff:g id="NAME">%s</xliff:g> ને તૈયાર કરી રહ્યું છે"</string>
    +     <string name="ext_media_checking_notification_message" msgid="4747432538578886744">"ભૂલો માટે તપાસી રહ્યું છે"</string>
    +     <string name="ext_media_new_notification_message" msgid="7589986898808506239">"નવું <xliff:g id="NAME">%s</xliff:g> મળ્યું"</string>
    +@@ -1232,8 +1243,9 @@
    +     <string name="vpn_text_long" msgid="4907843483284977618">"<xliff:g id="SESSION">%s</xliff:g> થી કનેક્ટ થયાં. નેટવર્કને સંચાલિત કરવા માટે ટૅપ કરો."</string>
    +     <string name="vpn_lockdown_connecting" msgid="6443438964440960745">"હંમેશા-ચાલુ VPN કનેક્ટ થઈ રહ્યું છે…"</string>
    +     <string name="vpn_lockdown_connected" msgid="8202679674819213931">"હંમેશા-ચાલુ VPN કનેક્ટ થયું"</string>
    ++    <string name="vpn_lockdown_disconnected" msgid="4532298952570796327">"હંમેશાં-ચાલુ VPN ડિસ્કનેક્ટ થયું"</string>
    +     <string name="vpn_lockdown_error" msgid="6009249814034708175">"હંમેશાં ચાલુ VPN ભૂલ"</string>
    +-    <string name="vpn_lockdown_config" msgid="4655589351146766608">"ગોઠવવા માટે ટૅપ કરો"</string>
    ++    <string name="vpn_lockdown_config" msgid="5099330695245008680">"સેટ કરવા માટે ટૅપ કરો"</string>
    +     <string name="upload_file" msgid="2897957172366730416">"ફાઇલ પસંદ કરો"</string>
    +     <string name="no_file_chosen" msgid="6363648562170759465">"કોઈ ફાઇલ પસંદ કરેલી નથી"</string>
    +     <string name="reset" msgid="2448168080964209908">"ફરીથી સેટ કરો"</string>
    +@@ -1317,7 +1329,7 @@
    +     <string name="storage_usb_drive_label" msgid="4501418548927759953">"<xliff:g id="MANUFACTURER">%s</xliff:g> USB ડ્રાઇવ"</string>
    +     <string name="storage_usb" msgid="3017954059538517278">"USB સંગ્રહ"</string>
    +     <string name="extract_edit_menu_button" msgid="8940478730496610137">"સંપાદિત કરો"</string>
    +-    <string name="data_usage_warning_title" msgid="1955638862122232342">"ડેટા વપરાશ ચેતવણી"</string>
    ++    <string name="data_usage_warning_title" msgid="3620440638180218181">"ડેટા વપરાશ ચેતવણી"</string>
    +     <string name="data_usage_warning_body" msgid="6660692274311972007">"વપરાશ અને સેટિંગ્સ જોવા ટૅપ કરો."</string>
    +     <string name="data_usage_3g_limit_title" msgid="4361523876818447683">"2G-3G ડેટા મર્યાદા પર પહોંચ્યાં"</string>
    +     <string name="data_usage_4g_limit_title" msgid="4609566827219442376">"4G ડેટા મર્યાદા સુધી પહોંચ્યાં"</string>
    +@@ -1636,6 +1648,7 @@
    +     <string name="search_language_hint" msgid="7042102592055108574">"ભાષાનું નામ ટાઇપ કરો"</string>
    +     <string name="language_picker_section_suggested" msgid="8414489646861640885">"સૂચવેલા"</string>
    +     <string name="language_picker_section_all" msgid="3097279199511617537">"બધી ભાષાઓ"</string>
    ++    <string name="region_picker_section_all" msgid="8966316787153001779">"તમામ પ્રદેશ"</string>
    +     <string name="locale_search_menu" msgid="2560710726687249178">"શોધ"</string>
    +     <string name="work_mode_off_title" msgid="8954725060677558855">"કાર્ય મોડ બંધ છે"</string>
    +     <string name="work_mode_off_message" msgid="3286169091278094476">"કાર્ય પ્રોફાઇલને ઍપ્લિકેશનો, પૃષ્ઠભૂમિ સમન્વયન અને સંબંધિત સુવિધાઓ સહિતનું કાર્ય કરવાની મંજૂરી આપો."</string>
    +diff --git a/core/res/res/values-hi/strings.xml b/core/res/res/values-hi/strings.xml
    +index bea243b..ea45c1a 100644
    +--- a/core/res/res/values-hi/strings.xml
    ++++ b/core/res/res/values-hi/strings.xml
    +@@ -214,6 +214,7 @@
    +     <string name="global_actions" product="default" msgid="2406416831541615258">"फ़ोन विकल्‍प"</string>
    +     <string name="global_action_lock" msgid="2844945191792119712">"स्‍क्रीन लॉक"</string>
    +     <string name="global_action_power_off" msgid="4471879440839879722">"पावर बंद"</string>
    ++    <string name="global_action_emergency" msgid="7112311161137421166">"आपातकाल"</string>
    +     <string name="global_action_bug_report" msgid="7934010578922304799">"बग रिपोर्ट"</string>
    +     <string name="bugreport_title" msgid="2667494803742548533">"बग रिपोर्ट प्राप्त करें"</string>
    +     <string name="bugreport_message" msgid="398447048750350456">"ईमेल संदेश के रूप में भेजने के लिए, इसके द्वारा आपके डिवाइस की वर्तमान स्थिति के बारे में जानकारी एकत्र की जाएगी. बग रिपोर्ट प्रारंभ करने से लेकर भेजने के लिए तैयार होने तक कुछ समय लगेगा; कृपया धैर्य रखें."</string>
    +@@ -295,9 +296,9 @@
    +     <string name="permlab_sendSms" msgid="7544599214260982981">"SMS संदेश भेजें और देखें"</string>
    +     <string name="permdesc_sendSms" msgid="7094729298204937667">"ऐप्स  को SMS संदेशों को भेजने देता है. इसके परिणामस्वरूप अप्रत्‍याशित शुल्‍क लागू हो सकते हैं. दुर्भावनापूर्ण ऐप्स  आपकी पुष्टि के बिना संदेश भेजकर आपका धन व्‍यय कर सकते हैं."</string>
    +     <string name="permlab_readSms" msgid="8745086572213270480">"अपने लेख संदेश (SMS या MMS) पढ़ें"</string>
    +-    <string name="permdesc_readSms" product="tablet" msgid="2467981548684735522">"ऐप्स  को आपके टेबलेट या सिम कार्ड में संग्रहीत SMS संदेश पढ़ने देता है. इससे सामग्री या गोपनीयता पर ध्यान दिए बिना, ऐप्स  सभी SMS संदेश पढ़ सकता है."</string>
    +-    <string name="permdesc_readSms" product="tv" msgid="5102425513647038535">"ऐप को आपके टीवी या सिम कार्ड पर संग्रहीत SMS संदेशों को पढ़ने की अनुमति देती है. इससे ऐप को सामग्री या गोपनीयता पर ध्‍यान दिए बिना, सभी SMS संदेशों को पढ़ने की अनुमति मिल जाती है."</string>
    +-    <string name="permdesc_readSms" product="default" msgid="3695967533457240550">"ऐप्स  को आपके फ़ोन या सिम कार्ड में संग्रहीत SMS संदेश पढ़ने देता है. इससे सामग्री या गोपनीयता पर ध्यान दिए बिना, ऐप्स  सभी SMS संदेश पढ़ सकता है."</string>
    ++    <string name="permdesc_readSms" product="tablet" msgid="2467981548684735522">"ऐप्स  को आपके टेबलेट या सिम कार्ड में संग्रहीत SMS संदेश पढ़ने देता है. इससे सामग्री या निजता पर ध्यान दिए बिना, ऐप्स  सभी SMS संदेश पढ़ सकता है."</string>
    ++    <string name="permdesc_readSms" product="tv" msgid="5102425513647038535">"ऐप को आपके टीवी या सिम कार्ड पर संग्रहीत SMS संदेशों को पढ़ने की अनुमति देती है. इससे ऐप को सामग्री या निजता पर ध्‍यान दिए बिना, सभी SMS संदेशों को पढ़ने की अनुमति मिल जाती है."</string>
    ++    <string name="permdesc_readSms" product="default" msgid="3695967533457240550">"ऐप्स  को आपके फ़ोन या सिम कार्ड में संग्रहीत SMS संदेश पढ़ने देता है. इससे सामग्री या निजता पर ध्यान दिए बिना, ऐप्स  सभी SMS संदेश पढ़ सकता है."</string>
    +     <string name="permlab_receiveWapPush" msgid="5991398711936590410">"लेख संदेश (WAP) प्राप्त करें"</string>
    +     <string name="permdesc_receiveWapPush" msgid="748232190220583385">"ऐप्स  को WAP संदेशों को प्राप्‍त और संसाधित करने देता है. इस अनुमति में आपको भेजे गए संदेशों की निगरानी आपको दिखाए बिना करने और हटाने की क्षमता शामिल है."</string>
    +     <string name="permlab_getTasks" msgid="6466095396623933906">"चल रहे ऐप्स पुनर्प्राप्त करें"</string>
    +@@ -347,9 +348,9 @@
    +     <string name="permlab_bodySensors" msgid="4683341291818520277">"शरीर संवेदक एक्सेस करें (जैसे हृदय गति मॉनीटर)"</string>
    +     <string name="permdesc_bodySensors" product="default" msgid="4380015021754180431">"ऐप को आपकी शारीरिक स्‍थिति, जैसे आपकी हृदय गति पर नज़र रखने वाले संवेदकों का डेटा एक्‍सेस करने देती है."</string>
    +     <string name="permlab_readCalendar" msgid="5972727560257612398">"केलैंडर ईवेंट के साथ-साथ गोपनीय जानकारी पढ़ें"</string>
    +-    <string name="permdesc_readCalendar" product="tablet" msgid="4216462049057658723">"ऐप्स  को मित्रों या सहकर्मियों के कैलेंडर इवेंट सहित, आपके टेबलेट पर संग्रहीत कैलेंडर इवेंट पढ़ने देता है. इससे गोपनीयता या संवेदनशीलता पर ध्यान दिए बिना, ऐप्स  आपके कैलेंडर डेटा को साझा कर सकता है या सहेज सकता है."</string>
    +-    <string name="permdesc_readCalendar" product="tv" msgid="3191352452242394196">"ऐप को, मित्रों और सहकर्मियों के कैलेंडर ईवेंट सहित, आपके टीवी पर संग्रहीत सभी कैलेंडर ईवेंट पढ़ने देती है. इससे ऐप को गोपनीयता या संवेदनशीलता पर ध्‍यान दिए बिना, आपका कैलेडर डेटा साझा करने या सहेजने की अनुमति मिल जाती है."</string>
    +-    <string name="permdesc_readCalendar" product="default" msgid="7434548682470851583">"ऐप्स  को मित्रों या सहकर्मियों के कैलेंडर इवेंट सहित, आपके फ़ोन पर संग्रहीत कैलेंडर इवेंट पढ़ने देता है. इससे गोपनीयता या संवेदनशीलता पर ध्यान दिए बिना, ऐप्स  आपके कैलेंडर डेटा को साझा कर सकता है या सहेज सकता है."</string>
    ++    <string name="permdesc_readCalendar" product="tablet" msgid="4216462049057658723">"ऐप्स  को मित्रों या सहकर्मियों के कैलेंडर इवेंट सहित, आपके टेबलेट पर संग्रहीत कैलेंडर इवेंट पढ़ने देता है. इससे निजता या संवेदनशीलता पर ध्यान दिए बिना, ऐप्स  आपके कैलेंडर डेटा को साझा कर सकता है या सहेज सकता है."</string>
    ++    <string name="permdesc_readCalendar" product="tv" msgid="3191352452242394196">"ऐप को, मित्रों और सहकर्मियों के कैलेंडर ईवेंट सहित, आपके टीवी पर संग्रहीत सभी कैलेंडर ईवेंट पढ़ने देती है. इससे ऐप को निजता या संवेदनशीलता पर ध्‍यान दिए बिना, आपका कैलेडर डेटा साझा करने या सहेजने की अनुमति मिल जाती है."</string>
    ++    <string name="permdesc_readCalendar" product="default" msgid="7434548682470851583">"ऐप्स  को मित्रों या सहकर्मियों के कैलेंडर इवेंट सहित, आपके फ़ोन पर संग्रहीत कैलेंडर इवेंट पढ़ने देता है. इससे निजता या संवेदनशीलता पर ध्यान दिए बिना, ऐप्स  आपके कैलेंडर डेटा को साझा कर सकता है या सहेज सकता है."</string>
    +     <string name="permlab_writeCalendar" msgid="8438874755193825647">"अपनी जानकारी के बि‍ना कैलेंडर ईवेंट जोड़ें या संशोधि‍त करें और अति‍थि‍यों को ईमेल भेजें"</string>
    +     <string name="permdesc_writeCalendar" product="tablet" msgid="6679035520113668528">"ऐप्स  को मित्रों या सहकर्मियों के ईवेंट के साथ ही वे ईवेंट जोड़ने, निकालने, बदलने देता है जिन्हें आप अपने टेबलेट पर संशोधित कर सकते हैं. इससे ऐप्स ,अपनी जानकारी के बिना उन संदेशों को भेज सकता है जो कैलेंडर स्वामियों की ओर से आते दिखाई देते हैं, या ईवेंट संशोधित कर सकता है."</string>
    +     <string name="permdesc_writeCalendar" product="tv" msgid="1273290605500902507">"ऐप को ऐसे ईवेंट जोड़ने, निकालने, बदलने देती है जिन्हें आप अपने डिवाइस पर बदल सकते हैं, जिनमें मित्रों या सहकर्मियों के ईवेंट शामिल हैं. इससे ऐप ऐसे संदेश भेज सकता है जो कैलेंडर स्वामी से आते हुए प्रतीत होते हैं या ऐप स्वामी की जानकारी के बिना ईवेंट बदल सकता है."</string>
    +@@ -1076,6 +1077,17 @@
    +     <skip />
    +     <string name="wifi_no_internet" msgid="8451173622563841546">"वाई-फ़ाई में कोई इंटरनेट ऐक्‍सेस नहीं है"</string>
    +     <string name="wifi_no_internet_detailed" msgid="8083079241212301741">"विकल्पों के लिए टैप करें"</string>
    ++    <string name="network_switch_metered" msgid="4671730921726992671">"<xliff:g id="NETWORK_TYPE">%1$s</xliff:g> पर ले जाया गया"</string>
    ++    <string name="network_switch_metered_detail" msgid="5325661434777870353">"<xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> में कोई इंटरनेट एक्‍सेस नहीं होने पर डिवाइस <xliff:g id="NEW_NETWORK">%1$s</xliff:g> का उपयोग करता है. शुल्क लिया जा सकता है."</string>
    ++    <string name="network_switch_metered_toast" msgid="5779283181685974304">"<xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> से <xliff:g id="NEW_NETWORK">%2$s</xliff:g> पर ले जाया गया"</string>
    ++  <string-array name="network_switch_type_name">
    ++    <item msgid="2952042958050315394">"सेल्युलर डेटा"</item>
    ++    <item msgid="75483255295529161">"वाई-फ़ाई"</item>
    ++    <item msgid="6862614801537202646">"ब्लूटूथ"</item>
    ++    <item msgid="5447331121797802871">"ईथरनेट"</item>
    ++    <item msgid="8257233890381651999">"VPN"</item>
    ++  </string-array>
    ++    <string name="network_switch_type_name_unknown" msgid="4552612897806660656">"अज्ञात नेटवर्क प्रकार"</string>
    +     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"वाई-फ़ाई  से कनेक्‍ट नहीं हो सका"</string>
    +     <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" के पास एक कमज़ोर इंटरनेट कनेक्‍शन है."</string>
    +     <string name="wifi_connect_alert_title" msgid="8455846016001810172">"कनेक्शन की अनुमति दें?"</string>
    +@@ -1153,7 +1165,6 @@
    +     <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"भाषा और लेआउट चुनने के लिए टैप करें"</string>
    +     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
    +     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
    +-    <string name="candidates_style" msgid="4333913089637062257"><u>"उम्‍मीदवार"</u></string>
    +     <string name="ext_media_checking_notification_title" msgid="5734005953288045806">"<xliff:g id="NAME">%s</xliff:g> को तैयार किया जा रहा है"</string>
    +     <string name="ext_media_checking_notification_message" msgid="4747432538578886744">"त्रुटियों की जांच कर रहा है"</string>
    +     <string name="ext_media_new_notification_message" msgid="7589986898808506239">"नए <xliff:g id="NAME">%s</xliff:g> का पता लगा"</string>
    +@@ -1232,8 +1243,9 @@
    +     <string name="vpn_text_long" msgid="4907843483284977618">"<xliff:g id="SESSION">%s</xliff:g> से कनेक्‍ट किया गया. नेटवर्क प्रबंधित करने के लिए टैप करें."</string>
    +     <string name="vpn_lockdown_connecting" msgid="6443438964440960745">"हमेशा-चालू VPN कनेक्ट हो रहा है…"</string>
    +     <string name="vpn_lockdown_connected" msgid="8202679674819213931">"हमेशा-चालू VPN कनेक्ट है"</string>
    ++    <string name="vpn_lockdown_disconnected" msgid="4532298952570796327">"हमेशा-चालू VPN डिस्‍कनेक्‍ट है"</string>
    +     <string name="vpn_lockdown_error" msgid="6009249814034708175">"हमेशा-चालू VPN त्रुटि"</string>
    +-    <string name="vpn_lockdown_config" msgid="4655589351146766608">"कॉन्फ़िगर करने के लिए टैप करें"</string>
    ++    <string name="vpn_lockdown_config" msgid="5099330695245008680">"सेट करने के लिए टैप करें"</string>
    +     <string name="upload_file" msgid="2897957172366730416">"फ़ाइल चुनें"</string>
    +     <string name="no_file_chosen" msgid="6363648562170759465">"कोई फ़ाइल चुनी नहीं गई"</string>
    +     <string name="reset" msgid="2448168080964209908">"रीसेट करें"</string>
    +@@ -1317,7 +1329,7 @@
    +     <string name="storage_usb_drive_label" msgid="4501418548927759953">"<xliff:g id="MANUFACTURER">%s</xliff:g> USB डिस्‍क"</string>
    +     <string name="storage_usb" msgid="3017954059538517278">"USB मेमोरी"</string>
    +     <string name="extract_edit_menu_button" msgid="8940478730496610137">"संपादित करें"</string>
    +-    <string name="data_usage_warning_title" msgid="1955638862122232342">"डेटा उपयोग की चेतावनी"</string>
    ++    <string name="data_usage_warning_title" msgid="3620440638180218181">"डेटा उपयोग की सूचना"</string>
    +     <string name="data_usage_warning_body" msgid="6660692274311972007">"उपयोग व सेटिंग देखने हेतु टैप करें."</string>
    +     <string name="data_usage_3g_limit_title" msgid="4361523876818447683">"2G-3G डेटा सीमा पूर्ण हो गई"</string>
    +     <string name="data_usage_4g_limit_title" msgid="4609566827219442376">"4G डेटा सीमा पूर्ण हो गई"</string>
    +@@ -1636,6 +1648,7 @@
    +     <string name="search_language_hint" msgid="7042102592055108574">"भाषा का नाम लिखें"</string>
    +     <string name="language_picker_section_suggested" msgid="8414489646861640885">"सुझाए गए"</string>
    +     <string name="language_picker_section_all" msgid="3097279199511617537">"सभी भाषाएं"</string>
    ++    <string name="region_picker_section_all" msgid="8966316787153001779">"सभी क्षेत्र"</string>
    +     <string name="locale_search_menu" msgid="2560710726687249178">"खोजें"</string>
    +     <string name="work_mode_off_title" msgid="8954725060677558855">"कार्य मोड बंद है"</string>
    +     <string name="work_mode_off_message" msgid="3286169091278094476">"ऐप्स, पृष्ठभूमि समन्वयन और संबंधित सुविधाओं सहित कार्य प्रोफ़ाइल को काम करने की अनुमति दें"</string>
    +diff --git a/core/res/res/values-hr/strings.xml b/core/res/res/values-hr/strings.xml
    +index b181f6d..5f2d3d6 100644
    +--- a/core/res/res/values-hr/strings.xml
    ++++ b/core/res/res/values-hr/strings.xml
    +@@ -216,6 +216,7 @@
    +     <string name="global_actions" product="default" msgid="2406416831541615258">"Opcije telefona"</string>
    +     <string name="global_action_lock" msgid="2844945191792119712">"Zaključavanje zaslona"</string>
    +     <string name="global_action_power_off" msgid="4471879440839879722">"Isključi"</string>
    ++    <string name="global_action_emergency" msgid="7112311161137421166">"Hitno"</string>
    +     <string name="global_action_bug_report" msgid="7934010578922304799">"Izvješće o bugovima"</string>
    +     <string name="bugreport_title" msgid="2667494803742548533">"Izvješće o programskoj pogrešci"</string>
    +     <string name="bugreport_message" msgid="398447048750350456">"Time će se prikupiti podaci o trenutačnom stanju vašeg uređaja koje ćete nam poslati u e-poruci. Za pripremu izvješća o programskoj pogrešci potrebno je nešto vremena pa vas molimo za strpljenje."</string>
    +@@ -1101,6 +1102,17 @@
    +     <skip />
    +     <string name="wifi_no_internet" msgid="8451173622563841546">"Wi-Fi nema pristup internetu"</string>
    +     <string name="wifi_no_internet_detailed" msgid="8083079241212301741">"Dodirnite za opcije"</string>
    ++    <string name="network_switch_metered" msgid="4671730921726992671">"Prelazak na drugu mrežu: <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
    ++    <string name="network_switch_metered_detail" msgid="5325661434777870353">"Kada <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> nema pristup internetu, na uređaju se upotrebljava <xliff:g id="NEW_NETWORK">%1$s</xliff:g>. Moguća je naplata naknade."</string>
    ++    <string name="network_switch_metered_toast" msgid="5779283181685974304">"Mreža je promijenjena: <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> &gt; <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
    ++  <string-array name="network_switch_type_name">
    ++    <item msgid="2952042958050315394">"mobilni podaci"</item>
    ++    <item msgid="75483255295529161">"Wi-Fi"</item>
    ++    <item msgid="6862614801537202646">"Bluetooth"</item>
    ++    <item msgid="5447331121797802871">"Ethernet"</item>
    ++    <item msgid="8257233890381651999">"VPN"</item>
    ++  </string-array>
    ++    <string name="network_switch_type_name_unknown" msgid="4552612897806660656">"nepoznata vrsta mreže"</string>
    +     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Ne može se spojiti na Wi-Fi"</string>
    +     <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" ima lošu internetsku vezu."</string>
    +     <string name="wifi_connect_alert_title" msgid="8455846016001810172">"Dopustiti povezivanje?"</string>
    +@@ -1178,7 +1190,6 @@
    +     <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"Dodirnite da biste odabrali jezik i raspored"</string>
    +     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
    +     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
    +-    <string name="candidates_style" msgid="4333913089637062257"><u>"kandidati"</u></string>
    +     <string name="ext_media_checking_notification_title" msgid="5734005953288045806">"Priprema uređaja <xliff:g id="NAME">%s</xliff:g>"</string>
    +     <string name="ext_media_checking_notification_message" msgid="4747432538578886744">"Traženje pogrešaka"</string>
    +     <string name="ext_media_new_notification_message" msgid="7589986898808506239">"Otkriven je novi uređaj <xliff:g id="NAME">%s</xliff:g>"</string>
    +@@ -1257,8 +1268,9 @@
    +     <string name="vpn_text_long" msgid="4907843483284977618">"Povezan sa sesijom <xliff:g id="SESSION">%s</xliff:g>. Dotaknite za upravljanje mrežom."</string>
    +     <string name="vpn_lockdown_connecting" msgid="6443438964440960745">"Povezivanje s uvijek uključenom VPN mrežom…"</string>
    +     <string name="vpn_lockdown_connected" msgid="8202679674819213931">"Povezan s uvijek uključenom VPN mrežom"</string>
    ++    <string name="vpn_lockdown_disconnected" msgid="4532298952570796327">"Prekinuta je veza s uvijek uključenom VPN mrežom"</string>
    +     <string name="vpn_lockdown_error" msgid="6009249814034708175">"Pogreška uvijek uključene VPN mreže"</string>
    +-    <string name="vpn_lockdown_config" msgid="4655589351146766608">"Dodirnite da biste konfigurirali"</string>
    ++    <string name="vpn_lockdown_config" msgid="5099330695245008680">"Dodirnite za postavljanje"</string>
    +     <string name="upload_file" msgid="2897957172366730416">"Odaberite datoteku"</string>
    +     <string name="no_file_chosen" msgid="6363648562170759465">"Nema odabranih datoteka"</string>
    +     <string name="reset" msgid="2448168080964209908">"Ponovo postavi"</string>
    +@@ -1343,7 +1355,7 @@
    +     <string name="storage_usb_drive_label" msgid="4501418548927759953">"<xliff:g id="MANUFACTURER">%s</xliff:g> USB pogon"</string>
    +     <string name="storage_usb" msgid="3017954059538517278">"USB pohrana"</string>
    +     <string name="extract_edit_menu_button" msgid="8940478730496610137">"Uredi"</string>
    +-    <string name="data_usage_warning_title" msgid="1955638862122232342">"Upozorenje o upotrebi podataka"</string>
    ++    <string name="data_usage_warning_title" msgid="3620440638180218181">"Upozorenje o upotrebi podataka"</string>
    +     <string name="data_usage_warning_body" msgid="6660692274311972007">"Dodirnite za upotrebu i postavke"</string>
    +     <string name="data_usage_3g_limit_title" msgid="4361523876818447683">"Dost. ogr. 2G–3G prijenosa pod."</string>
    +     <string name="data_usage_4g_limit_title" msgid="4609566827219442376">"Dost. ogr. 4G prijenosa podataka"</string>
    +@@ -1672,6 +1684,7 @@
    +     <string name="search_language_hint" msgid="7042102592055108574">"Unesite naziv jezika"</string>
    +     <string name="language_picker_section_suggested" msgid="8414489646861640885">"Predloženo"</string>
    +     <string name="language_picker_section_all" msgid="3097279199511617537">"Svi jezici"</string>
    ++    <string name="region_picker_section_all" msgid="8966316787153001779">"Sve regije"</string>
    +     <string name="locale_search_menu" msgid="2560710726687249178">"Pretraži"</string>
    +     <string name="work_mode_off_title" msgid="8954725060677558855">"Radni je način ISKLJUČEN"</string>
    +     <string name="work_mode_off_message" msgid="3286169091278094476">"Omogućuje radnom profilu da funkcionira, uključujući aplikacije, sinkronizaciju u pozadini i povezane značajke."</string>
    +diff --git a/core/res/res/values-hu/strings.xml b/core/res/res/values-hu/strings.xml
    +index aea12a6..cd3659a 100644
    +--- a/core/res/res/values-hu/strings.xml
    ++++ b/core/res/res/values-hu/strings.xml
    +@@ -214,6 +214,7 @@
    +     <string name="global_actions" product="default" msgid="2406416831541615258">"Telefonbeállítások"</string>
    +     <string name="global_action_lock" msgid="2844945191792119712">"Képernyő lezárása"</string>
    +     <string name="global_action_power_off" msgid="4471879440839879722">"Kikapcsolás"</string>
    ++    <string name="global_action_emergency" msgid="7112311161137421166">"Vészhívás"</string>
    +     <string name="global_action_bug_report" msgid="7934010578922304799">"Programhiba bejelentése"</string>
    +     <string name="bugreport_title" msgid="2667494803742548533">"Hibajelentés készítése"</string>
    +     <string name="bugreport_message" msgid="398447048750350456">"Ezzel információt fog gyűjteni az eszköz jelenlegi állapotáról, amelyet a rendszer e-mailben fog elküldeni. Kérjük, legyen türelemmel, amíg a hibajelentés elkészül, és küldhető állapotba kerül."</string>
    +@@ -1076,6 +1077,17 @@
    +     <skip />
    +     <string name="wifi_no_internet" msgid="8451173622563841546">"A Wi-Fi-hálózaton nincs internetkapcsolat"</string>
    +     <string name="wifi_no_internet_detailed" msgid="8083079241212301741">"Koppintson a beállítások megjelenítéséhez"</string>
    ++    <string name="network_switch_metered" msgid="4671730921726992671">"Átváltva erre: <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
    ++    <string name="network_switch_metered_detail" msgid="5325661434777870353">"<xliff:g id="NEW_NETWORK">%1$s</xliff:g> használata, ha nincs internetkapcsolat <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g>-kapcsolaton keresztül. A szolgáltató díjat számíthat fel."</string>
    ++    <string name="network_switch_metered_toast" msgid="5779283181685974304">"Átváltva <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g>-hálózatról erre: <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
    ++  <string-array name="network_switch_type_name">
    ++    <item msgid="2952042958050315394">"mobiladat"</item>
    ++    <item msgid="75483255295529161">"Wi-Fi"</item>
    ++    <item msgid="6862614801537202646">"Bluetooth"</item>
    ++    <item msgid="5447331121797802871">"Ethernet"</item>
    ++    <item msgid="8257233890381651999">"VPN"</item>
    ++  </string-array>
    ++    <string name="network_switch_type_name_unknown" msgid="4552612897806660656">"ismeretlen hálózati típus"</string>
    +     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Nem sikerült csatlakozni a Wi-Fi hálózathoz"</string>
    +     <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" rossz internetkapcsolattal rendelkezik."</string>
    +     <string name="wifi_connect_alert_title" msgid="8455846016001810172">"Engedélyezi a csatlakozást?"</string>
    +@@ -1153,7 +1165,6 @@
    +     <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"Koppintson a nyelv és a billentyűzetkiosztás kiválasztásához"</string>
    +     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
    +     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
    +-    <string name="candidates_style" msgid="4333913089637062257"><u>"jelöltek"</u></string>
    +     <string name="ext_media_checking_notification_title" msgid="5734005953288045806">"<xliff:g id="NAME">%s</xliff:g> előkészítése"</string>
    +     <string name="ext_media_checking_notification_message" msgid="4747432538578886744">"Hibák keresése"</string>
    +     <string name="ext_media_new_notification_message" msgid="7589986898808506239">"Új <xliff:g id="NAME">%s</xliff:g> észlelve"</string>
    +@@ -1232,8 +1243,9 @@
    +     <string name="vpn_text_long" msgid="4907843483284977618">"Csatlakozva ide: <xliff:g id="SESSION">%s</xliff:g>. Érintse meg a hálózat kezeléséhez."</string>
    +     <string name="vpn_lockdown_connecting" msgid="6443438964440960745">"Csatlakozás a mindig bekapcsolt VPN-hez..."</string>
    +     <string name="vpn_lockdown_connected" msgid="8202679674819213931">"Csatlakozva a mindig bekapcsolt VPN-hez"</string>
    ++    <string name="vpn_lockdown_disconnected" msgid="4532298952570796327">"Kapcsolat bontva a mindig bekapcsolt VPN-nel"</string>
    +     <string name="vpn_lockdown_error" msgid="6009249814034708175">"Hiba a mindig bekapcsolt VPN-nel"</string>
    +-    <string name="vpn_lockdown_config" msgid="4655589351146766608">"Koppintson a konfiguráláshoz"</string>
    ++    <string name="vpn_lockdown_config" msgid="5099330695245008680">"Koppintson ide a beállításhoz"</string>
    +     <string name="upload_file" msgid="2897957172366730416">"Fájl kiválasztása"</string>
    +     <string name="no_file_chosen" msgid="6363648562170759465">"Nincs fájl kiválasztva"</string>
    +     <string name="reset" msgid="2448168080964209908">"Alaphelyzet"</string>
    +@@ -1317,7 +1329,7 @@
    +     <string name="storage_usb_drive_label" msgid="4501418548927759953">"<xliff:g id="MANUFACTURER">%s</xliff:g> USB-meghajtó"</string>
    +     <string name="storage_usb" msgid="3017954059538517278">"USB-tár"</string>
    +     <string name="extract_edit_menu_button" msgid="8940478730496610137">"Szerkesztés"</string>
    +-    <string name="data_usage_warning_title" msgid="1955638862122232342">"Adathasználati figyelmeztetés"</string>
    ++    <string name="data_usage_warning_title" msgid="3620440638180218181">"Adathasználati értesítés"</string>
    +     <string name="data_usage_warning_body" msgid="6660692274311972007">"Koppintson az adatokért."</string>
    +     <string name="data_usage_3g_limit_title" msgid="4361523876818447683">"2G-/3G-adatkorlát elérve"</string>
    +     <string name="data_usage_4g_limit_title" msgid="4609566827219442376">"4G-adatkorlát elérve"</string>
    +@@ -1636,6 +1648,7 @@
    +     <string name="search_language_hint" msgid="7042102592055108574">"Adja meg a nyelvet"</string>
    +     <string name="language_picker_section_suggested" msgid="8414489646861640885">"Javasolt"</string>
    +     <string name="language_picker_section_all" msgid="3097279199511617537">"Minden nyelv"</string>
    ++    <string name="region_picker_section_all" msgid="8966316787153001779">"Minden régió"</string>
    +     <string name="locale_search_menu" msgid="2560710726687249178">"Keresés"</string>
    +     <string name="work_mode_off_title" msgid="8954725060677558855">"A munka mód KI van kapcsolva"</string>
    +     <string name="work_mode_off_message" msgid="3286169091278094476">"Munkaprofil használatának engedélyezése, beleértve az alkalmazásokat, a háttérben való szinkronizálást és a kapcsolódó funkciókat."</string>
    +diff --git a/core/res/res/values-hy-rAM/strings.xml b/core/res/res/values-hy-rAM/strings.xml
    +index ba97468..160efff 100644
    +--- a/core/res/res/values-hy-rAM/strings.xml
    ++++ b/core/res/res/values-hy-rAM/strings.xml
    +@@ -214,6 +214,7 @@
    +     <string name="global_actions" product="default" msgid="2406416831541615258">"Հեռախոսի ընտրանքներ"</string>
    +     <string name="global_action_lock" msgid="2844945191792119712">"Էկրանի փական"</string>
    +     <string name="global_action_power_off" msgid="4471879440839879722">"Անջատել"</string>
    ++    <string name="global_action_emergency" msgid="7112311161137421166">"Շտապ կանչ"</string>
    +     <string name="global_action_bug_report" msgid="7934010578922304799">"Վրիպակի զեկույց"</string>
    +     <string name="bugreport_title" msgid="2667494803742548533">"Գրել սխալի զեկույց"</string>
    +     <string name="bugreport_message" msgid="398447048750350456">"Սա տեղեկություններ կհավաքագրի ձեր սարքի առկա կարգավիճակի մասին և կուղարկի այն էլեկտրոնային նամակով: Որոշակի ժամանակ կպահանջվի վրիպակի մասին զեկուցելու պահից սկսած մինչ ուղարկելը: Խնդրում ենք փոքր-ինչ համբերատար լինել:"</string>
    +@@ -249,17 +250,17 @@
    +     <string name="permgrouplab_calendar" msgid="5863508437783683902">"Օրացույց"</string>
    +     <string name="permgroupdesc_calendar" msgid="3889615280211184106">"օգտագործել օրացույցը"</string>
    +     <string name="permgrouplab_sms" msgid="228308803364967808">"Կարճ հաղորդագրություն"</string>
    +-    <string name="permgroupdesc_sms" msgid="4656988620100940350">"ուղարկել և դիտել SMS հաղորդագրությունները"</string>
    ++    <string name="permgroupdesc_sms" msgid="4656988620100940350">"ուղարկել և դիտել SMS-ները"</string>
    +     <string name="permgrouplab_storage" msgid="1971118770546336966">"Պահոց"</string>
    +-    <string name="permgroupdesc_storage" msgid="637758554581589203">"օգտագործել լուսանկարները, մեդիա ֆայլերը և ձեր սարքում պահվող այլ ֆայլերը"</string>
    ++    <string name="permgroupdesc_storage" msgid="637758554581589203">"օգտագործել լուսանկարները, մեդիա ֆայլերը և ձեր սարքում պահվող մյուս ֆայլերը"</string>
    +     <string name="permgrouplab_microphone" msgid="171539900250043464">"Բարձրախոս"</string>
    +-    <string name="permgroupdesc_microphone" msgid="4988812113943554584">"ձայնագրում"</string>
    ++    <string name="permgroupdesc_microphone" msgid="4988812113943554584">"ձայնագրել"</string>
    +     <string name="permgrouplab_camera" msgid="4820372495894586615">"Ֆոտոխցիկ"</string>
    +-    <string name="permgroupdesc_camera" msgid="3250611594678347720">"լուսանկարում և տեսագրում"</string>
    ++    <string name="permgroupdesc_camera" msgid="3250611594678347720">"լուսանկարել և տեսագրել"</string>
    +     <string name="permgrouplab_phone" msgid="5229115638567440675">"Հեռախոս"</string>
    +-    <string name="permgroupdesc_phone" msgid="6234224354060641055">"հեռախոսազանգերի կատարում և կառավարում"</string>
    ++    <string name="permgroupdesc_phone" msgid="6234224354060641055">"կատարել զանգեր և կառավարել զանգերը"</string>
    +     <string name="permgrouplab_sensors" msgid="416037179223226722">"Մարմնի սենսորներ"</string>
    +-    <string name="permgroupdesc_sensors" msgid="7147968539346634043">"օգտագործել ձեր հիմնական ֆիզիոլոգիական ցուցանիշների վերաբերյալ սենսորի տվյալները"</string>
    ++    <string name="permgroupdesc_sensors" msgid="7147968539346634043">"օգտագործել սենսորների տվյալները ձեր օրգանիզմի վիճակի մասին"</string>
    +     <string name="capability_title_canRetrieveWindowContent" msgid="3901717936930170320">"Առբերել պատուհանի բովանդակությունը"</string>
    +     <string name="capability_desc_canRetrieveWindowContent" msgid="3772225008605310672">"Ստուգեք պատուհանի բովանդակությունը, որի հետ փոխգործակցում եք:"</string>
    +     <string name="capability_title_canRequestTouchExploration" msgid="3108723364676667320">"Միացնել Հպման միջոցով հետազոտումը"</string>
    +@@ -673,7 +674,7 @@
    +     <string name="lockscreen_instructions_when_pattern_enabled" msgid="46154051614126049">"Ապակողպելու կամ շտապ կանչ անելու համար սեղմեք «Ընտրացանկ»"</string>
    +     <string name="lockscreen_instructions_when_pattern_disabled" msgid="686260028797158364">"Ապակողպելու համար սեղմեք Ցանկը:"</string>
    +     <string name="lockscreen_pattern_instructions" msgid="7478703254964810302">"Հավաքեք սխեման` ապակողպելու համար"</string>
    +-    <string name="lockscreen_emergency_call" msgid="5298642613417801888">"Արտակարգ իրավիճակ"</string>
    ++    <string name="lockscreen_emergency_call" msgid="5298642613417801888">"Շտապ կանչ"</string>
    +     <string name="lockscreen_return_to_call" msgid="5244259785500040021">"Վերադառնալ զանգին"</string>
    +     <string name="lockscreen_pattern_correct" msgid="9039008650362261237">"Ճիշտ է:"</string>
    +     <string name="lockscreen_pattern_wrong" msgid="4317955014948108794">"Կրկին փորձեք"</string>
    +@@ -1057,8 +1058,8 @@
    +     <string name="volume_icon_description_incall" msgid="8890073218154543397">"Զանգի ձայնի բարձրություն"</string>
    +     <string name="volume_icon_description_media" msgid="4217311719665194215">"Մեդիա ձայնի բարձրություն"</string>
    +     <string name="volume_icon_description_notification" msgid="7044986546477282274">"Ծանուցումների ձայնի ուժգնությունը"</string>
    +-    <string name="ringtone_default" msgid="3789758980357696936">"Լռելյայն զանգերանգ"</string>
    +-    <string name="ringtone_default_with_actual" msgid="8129563480895990372">"Լռելյայն զանգերանգ (<xliff:g id="ACTUAL_RINGTONE">%1$s</xliff:g>)"</string>
    ++    <string name="ringtone_default" msgid="3789758980357696936">"Կանխադրված զանգերանգ"</string>
    ++    <string name="ringtone_default_with_actual" msgid="8129563480895990372">"Կանխադրված զանգերանգ (<xliff:g id="ACTUAL_RINGTONE">%1$s</xliff:g>)"</string>
    +     <string name="ringtone_silent" msgid="7937634392408977062">"Ոչ մեկը"</string>
    +     <string name="ringtone_picker_title" msgid="3515143939175119094">"Զանգերանգներ"</string>
    +     <string name="ringtone_unknown" msgid="5477919988701784788">"Անհայտ զանգերանգ"</string>
    +@@ -1076,6 +1077,17 @@
    +     <skip />
    +     <string name="wifi_no_internet" msgid="8451173622563841546">"Wi-Fi ցանցը համացանցի միացում չունի"</string>
    +     <string name="wifi_no_internet_detailed" msgid="8083079241212301741">"Հպեք՝ ընտրանքները տեսնելու համար"</string>
    ++    <string name="network_switch_metered" msgid="4671730921726992671">"Անցել է <xliff:g id="NETWORK_TYPE">%1$s</xliff:g> ցանցի"</string>
    ++    <string name="network_switch_metered_detail" msgid="5325661434777870353">"Եթե <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> ցանցն ինտերնետ կապ չունի, սարքն անցնում է <xliff:g id="NEW_NETWORK">%1$s</xliff:g> ցանցի: Կարող են վճարներ գանձվել:"</string>
    ++    <string name="network_switch_metered_toast" msgid="5779283181685974304">"<xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> ցանցից անցել է <xliff:g id="NEW_NETWORK">%2$s</xliff:g> ցանցի"</string>
    ++  <string-array name="network_switch_type_name">
    ++    <item msgid="2952042958050315394">"բջջային տվյալներ"</item>
    ++    <item msgid="75483255295529161">"Wi-Fi"</item>
    ++    <item msgid="6862614801537202646">"Bluetooth"</item>
    ++    <item msgid="5447331121797802871">"Ethernet"</item>
    ++    <item msgid="8257233890381651999">"VPN"</item>
    ++  </string-array>
    ++    <string name="network_switch_type_name_unknown" msgid="4552612897806660656">"ցանցի անհայտ տեսակ"</string>
    +     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Չհաջողվեց միանալ Wi-Fi-ին"</string>
    +     <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" ունի թույլ ինտերնետ կապ:"</string>
    +     <string name="wifi_connect_alert_title" msgid="8455846016001810172">"Թույլատրե՞լ կապը:"</string>
    +@@ -1153,7 +1165,6 @@
    +     <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"Հպեք՝ լեզուն և դասավորությունն ընտրելու համար"</string>
    +     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ԱԲԳԴԵԶԷԸԹԺԻԼԽԾԿՀՁՂՃՄՅՆՇՈՉՊՋՌՍՎՏՐՑՈՒՓՔԵւՕՖ"</string>
    +     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
    +-    <string name="candidates_style" msgid="4333913089637062257"><u>"թեկնածուները"</u></string>
    +     <string name="ext_media_checking_notification_title" msgid="5734005953288045806">"<xliff:g id="NAME">%s</xliff:g>-ի նախապատրաստում"</string>
    +     <string name="ext_media_checking_notification_message" msgid="4747432538578886744">"Սխալների ստուգում"</string>
    +     <string name="ext_media_new_notification_message" msgid="7589986898808506239">"Հայտնաբերվել է նոր <xliff:g id="NAME">%s</xliff:g>"</string>
    +@@ -1232,8 +1243,9 @@
    +     <string name="vpn_text_long" msgid="4907843483284977618">"Կապակացված է <xliff:g id="SESSION">%s</xliff:g>-ին: Սեղմեք` ցանցը կառավարելու համար:"</string>
    +     <string name="vpn_lockdown_connecting" msgid="6443438964440960745">"Միշտ-միացված VPN-ը կապվում է..."</string>
    +     <string name="vpn_lockdown_connected" msgid="8202679674819213931">"Միշտ-առցանց VPN-ը կապակցված է"</string>
    ++    <string name="vpn_lockdown_disconnected" msgid="4532298952570796327">"«Միշտ միացված VPN»-ն անջատված է"</string>
    +     <string name="vpn_lockdown_error" msgid="6009249814034708175">"VPN սխալը միշտ միացված"</string>
    +-    <string name="vpn_lockdown_config" msgid="4655589351146766608">"Հպեք՝ կազմաձևելու համար"</string>
    ++    <string name="vpn_lockdown_config" msgid="5099330695245008680">"Հպեք՝ կարգավորելու համար"</string>
    +     <string name="upload_file" msgid="2897957172366730416">"Ընտրել ֆայլը"</string>
    +     <string name="no_file_chosen" msgid="6363648562170759465">"Ոչ մի ֆայլ չի ընտրված"</string>
    +     <string name="reset" msgid="2448168080964209908">"Վերակայել"</string>
    +@@ -1317,7 +1329,7 @@
    +     <string name="storage_usb_drive_label" msgid="4501418548927759953">"USB սարքավար <xliff:g id="MANUFACTURER">%s</xliff:g>-ից"</string>
    +     <string name="storage_usb" msgid="3017954059538517278">"USB կրիչ"</string>
    +     <string name="extract_edit_menu_button" msgid="8940478730496610137">"Խմբագրել"</string>
    +-    <string name="data_usage_warning_title" msgid="1955638862122232342">"Տվյալների օգտագործման նախազգուշացում"</string>
    ++    <string name="data_usage_warning_title" msgid="3620440638180218181">"Տվյալների օգտագործման զգուշացում"</string>
    +     <string name="data_usage_warning_body" msgid="6660692274311972007">"Հպեք և տեսեք օգտագործումը և կարգավորումները:"</string>
    +     <string name="data_usage_3g_limit_title" msgid="4361523876818447683">"2G-3G տվյալների սահմանաչափը սպառվել է"</string>
    +     <string name="data_usage_4g_limit_title" msgid="4609566827219442376">"4G տվյալների սահմանաչափը սպառվել է"</string>
    +@@ -1636,6 +1648,7 @@
    +     <string name="search_language_hint" msgid="7042102592055108574">"Մուտքագրեք լեզուն"</string>
    +     <string name="language_picker_section_suggested" msgid="8414489646861640885">"Առաջարկներ"</string>
    +     <string name="language_picker_section_all" msgid="3097279199511617537">"Բոլոր լեզուները"</string>
    ++    <string name="region_picker_section_all" msgid="8966316787153001779">"Բոլոր տարածաշրջանները"</string>
    +     <string name="locale_search_menu" msgid="2560710726687249178">"Որոնում"</string>
    +     <string name="work_mode_off_title" msgid="8954725060677558855">"Աշխատանքային ռեժիմն ԱՆՋԱՏՎԱԾ Է"</string>
    +     <string name="work_mode_off_message" msgid="3286169091278094476">"Միացնել աշխատանքային պրոֆիլը՝ հավելվածները, ֆոնային համաժամեցումը և առնչվող գործառույթները"</string>
    +diff --git a/core/res/res/values-in/strings.xml b/core/res/res/values-in/strings.xml
    +index 132789b..fefca0c 100644
    +--- a/core/res/res/values-in/strings.xml
    ++++ b/core/res/res/values-in/strings.xml
    +@@ -116,7 +116,7 @@
    +     <string name="roamingText5" msgid="7604063252850354350">"Roaming - Sistem Yang Dipilih"</string>
    +     <string name="roamingText6" msgid="2059440825782871513">"Roaming - Sistem Tersedia"</string>
    +     <string name="roamingText7" msgid="7112078724097233605">"Mitra Roaming - Alliance"</string>
    +-    <string name="roamingText8" msgid="5989569778604089291">"Roaming - Mitra Premium"</string>
    ++    <string name="roamingText8" msgid="5989569778604089291">"Roaming - Partner Premium"</string>
    +     <string name="roamingText9" msgid="7969296811355152491">"Fungsionalitas Layanan Roaming - Penuh"</string>
    +     <string name="roamingText10" msgid="3992906999815316417">"Fungsionalitas Layanan Roaming - Sebagian"</string>
    +     <string name="roamingText11" msgid="4154476854426920970">"Spanduk Roaming Hidup"</string>
    +@@ -214,6 +214,7 @@
    +     <string name="global_actions" product="default" msgid="2406416831541615258">"Opsi telepon"</string>
    +     <string name="global_action_lock" msgid="2844945191792119712">"Kunci layar"</string>
    +     <string name="global_action_power_off" msgid="4471879440839879722">"Matikan daya"</string>
    ++    <string name="global_action_emergency" msgid="7112311161137421166">"Darurat"</string>
    +     <string name="global_action_bug_report" msgid="7934010578922304799">"Laporan bug"</string>
    +     <string name="bugreport_title" msgid="2667494803742548533">"Ambil laporan bug"</string>
    +     <string name="bugreport_message" msgid="398447048750350456">"Ini akan mengumpulkan informasi status perangkat Anda saat ini, untuk dikirimkan sebagai pesan email. Harap bersabar, mungkin perlu waktu untuk memulai laporan bug hingga siap dikirim."</string>
    +@@ -253,7 +254,7 @@
    +     <string name="permgrouplab_storage" msgid="1971118770546336966">"Penyimpanan"</string>
    +     <string name="permgroupdesc_storage" msgid="637758554581589203">"mengakses foto, media, dan file di perangkat"</string>
    +     <string name="permgrouplab_microphone" msgid="171539900250043464">"Mikrofon"</string>
    +-    <string name="permgroupdesc_microphone" msgid="4988812113943554584">"rekam audio"</string>
    ++    <string name="permgroupdesc_microphone" msgid="4988812113943554584">"merekam audio"</string>
    +     <string name="permgrouplab_camera" msgid="4820372495894586615">"Kamera"</string>
    +     <string name="permgroupdesc_camera" msgid="3250611594678347720">"mengambil gambar dan merekam video"</string>
    +     <string name="permgrouplab_phone" msgid="5229115638567440675">"Telepon"</string>
    +@@ -1076,6 +1077,17 @@
    +     <skip />
    +     <string name="wifi_no_internet" msgid="8451173622563841546">"Wi-Fi tidak memiliki akses internet"</string>
    +     <string name="wifi_no_internet_detailed" msgid="8083079241212301741">"Ketuk untuk melihat opsi"</string>
    ++    <string name="network_switch_metered" msgid="4671730921726992671">"Dialihkan ke <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
    ++    <string name="network_switch_metered_detail" msgid="5325661434777870353">"Perangkat menggunakan <xliff:g id="NEW_NETWORK">%1$s</xliff:g> jika <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> tidak memiliki akses internet. Tarif mungkin berlaku."</string>
    ++    <string name="network_switch_metered_toast" msgid="5779283181685974304">"Dialihkan dari <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> ke <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
    ++  <string-array name="network_switch_type_name">
    ++    <item msgid="2952042958050315394">"data seluler"</item>
    ++    <item msgid="75483255295529161">"Wi-Fi"</item>
    ++    <item msgid="6862614801537202646">"Bluetooth"</item>
    ++    <item msgid="5447331121797802871">"Ethernet"</item>
    ++    <item msgid="8257233890381651999">"VPN"</item>
    ++  </string-array>
    ++    <string name="network_switch_type_name_unknown" msgid="4552612897806660656">"jenis jaringan yang tidak dikenal"</string>
    +     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Tidak dapat tersambung ke Wi-Fi"</string>
    +     <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" memiliki sambungan internet yang buruk."</string>
    +     <string name="wifi_connect_alert_title" msgid="8455846016001810172">"Izinkan hubungan?"</string>
    +@@ -1153,7 +1165,6 @@
    +     <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"Ketuk untuk memilih bahasa dan tata letak"</string>
    +     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
    +     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
    +-    <string name="candidates_style" msgid="4333913089637062257"><u>"calon"</u></string>
    +     <string name="ext_media_checking_notification_title" msgid="5734005953288045806">"Menyiapkan <xliff:g id="NAME">%s</xliff:g>"</string>
    +     <string name="ext_media_checking_notification_message" msgid="4747432538578886744">"Memeriksa kesalahan"</string>
    +     <string name="ext_media_new_notification_message" msgid="7589986898808506239">"<xliff:g id="NAME">%s</xliff:g> baru terdeteksi"</string>
    +@@ -1232,8 +1243,9 @@
    +     <string name="vpn_text_long" msgid="4907843483284977618">"Tersambung ke <xliff:g id="SESSION">%s</xliff:g>. Ketuk untuk mengelola jaringan."</string>
    +     <string name="vpn_lockdown_connecting" msgid="6443438964440960745">"Menyambungkan VPN selalu aktif..."</string>
    +     <string name="vpn_lockdown_connected" msgid="8202679674819213931">"VPN selalu aktif tersambung"</string>
    ++    <string name="vpn_lockdown_disconnected" msgid="4532298952570796327">"VPN selalu aktif terputus"</string>
    +     <string name="vpn_lockdown_error" msgid="6009249814034708175">"Kesalahan VPN selalu aktif"</string>
    +-    <string name="vpn_lockdown_config" msgid="4655589351146766608">"Ketuk untuk mengonfigurasi"</string>
    ++    <string name="vpn_lockdown_config" msgid="5099330695245008680">"Ketuk untuk menyiapkan"</string>
    +     <string name="upload_file" msgid="2897957172366730416">"Pilih file"</string>
    +     <string name="no_file_chosen" msgid="6363648562170759465">"Tidak ada file yang dipilih"</string>
    +     <string name="reset" msgid="2448168080964209908">"Setel ulang"</string>
    +@@ -1317,7 +1329,7 @@
    +     <string name="storage_usb_drive_label" msgid="4501418548927759953">"Drive USB <xliff:g id="MANUFACTURER">%s</xliff:g>"</string>
    +     <string name="storage_usb" msgid="3017954059538517278">"Penyimpanan USB"</string>
    +     <string name="extract_edit_menu_button" msgid="8940478730496610137">"Edit"</string>
    +-    <string name="data_usage_warning_title" msgid="1955638862122232342">"Peringatan penggunaan data"</string>
    ++    <string name="data_usage_warning_title" msgid="3620440638180218181">"Lansiran penggunaan data"</string>
    +     <string name="data_usage_warning_body" msgid="6660692274311972007">"Ketuk untuk lihat penggunaan &amp; setelan."</string>
    +     <string name="data_usage_3g_limit_title" msgid="4361523876818447683">"Batas data 2G-3G terlampaui"</string>
    +     <string name="data_usage_4g_limit_title" msgid="4609566827219442376">"Batas data 4G terlampaui"</string>
    +@@ -1636,6 +1648,7 @@
    +     <string name="search_language_hint" msgid="7042102592055108574">"Ketik nama bahasa"</string>
    +     <string name="language_picker_section_suggested" msgid="8414489646861640885">"Disarankan"</string>
    +     <string name="language_picker_section_all" msgid="3097279199511617537">"Semua bahasa"</string>
    ++    <string name="region_picker_section_all" msgid="8966316787153001779">"Semua wilayah"</string>
    +     <string name="locale_search_menu" msgid="2560710726687249178">"Telusuri"</string>
    +     <string name="work_mode_off_title" msgid="8954725060677558855">"Mode kerja NONAKTIF"</string>
    +     <string name="work_mode_off_message" msgid="3286169091278094476">"Izinkan profil kerja berfungsi, termasuk aplikasi, sinkronisasi latar belakang, dan fitur terkait."</string>
    +diff --git a/core/res/res/values-is-rIS/strings.xml b/core/res/res/values-is-rIS/strings.xml
    +index a897ba8..cdc6d42 100644
    +--- a/core/res/res/values-is-rIS/strings.xml
    ++++ b/core/res/res/values-is-rIS/strings.xml
    +@@ -214,6 +214,7 @@
    +     <string name="global_actions" product="default" msgid="2406416831541615258">"Valkostir síma"</string>
    +     <string name="global_action_lock" msgid="2844945191792119712">"Skjálás"</string>
    +     <string name="global_action_power_off" msgid="4471879440839879722">"Slökkva"</string>
    ++    <string name="global_action_emergency" msgid="7112311161137421166">"Neyðarsímtal"</string>
    +     <string name="global_action_bug_report" msgid="7934010578922304799">"Villutilkynning"</string>
    +     <string name="bugreport_title" msgid="2667494803742548533">"Útbúa villutilkynningu"</string>
    +     <string name="bugreport_message" msgid="398447048750350456">"Þetta safnar upplýsingum um núverandi stöðu tækisins til að senda með tölvupósti. Það tekur smástund frá því villutilkynningin er ræst og þar til hún er tilbúin til sendingar – sýndu biðlund."</string>
    +@@ -1076,6 +1077,17 @@
    +     <skip />
    +     <string name="wifi_no_internet" msgid="8451173622563841546">"Wi-Fi netið er ekki með tengingu við internetið"</string>
    +     <string name="wifi_no_internet_detailed" msgid="8083079241212301741">"Ýttu til að sjá valkosti"</string>
    ++    <string name="network_switch_metered" msgid="4671730921726992671">"Skipt yfir á <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
    ++    <string name="network_switch_metered_detail" msgid="5325661434777870353">"Tækið notar <xliff:g id="NEW_NETWORK">%1$s</xliff:g> þegar <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> er ekki með internetaðgang. Gjöld geta átt við."</string>
    ++    <string name="network_switch_metered_toast" msgid="5779283181685974304">"Skipt úr <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> yfir í <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
    ++  <string-array name="network_switch_type_name">
    ++    <item msgid="2952042958050315394">"farsímagögn"</item>
    ++    <item msgid="75483255295529161">"Wi-Fi"</item>
    ++    <item msgid="6862614801537202646">"Bluetooth"</item>
    ++    <item msgid="5447331121797802871">"Ethernet"</item>
    ++    <item msgid="8257233890381651999">"VPN"</item>
    ++  </string-array>
    ++    <string name="network_switch_type_name_unknown" msgid="4552612897806660656">"óþekkt tegund netkerfis"</string>
    +     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Ekki var hægt að tengjast Wi-Fi"</string>
    +     <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" er með lélegt netsamband."</string>
    +     <string name="wifi_connect_alert_title" msgid="8455846016001810172">"Leyfa tengingu?"</string>
    +@@ -1153,7 +1165,6 @@
    +     <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"Ýttu til að velja tungumál og útlit"</string>
    +     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" AÁBCDÐEÉFGHIÍJKLMNOÓPQRSTUÚVWXYÝZÞÆÖ"</string>
    +     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789AÁBCDÐEÉFGHIÍJKLMNOÓPQRSTUÚVWXYÝZÞÆÖ"</string>
    +-    <string name="candidates_style" msgid="4333913089637062257"><u>"möguleikar"</u></string>
    +     <string name="ext_media_checking_notification_title" msgid="5734005953288045806">"Undirbýr <xliff:g id="NAME">%s</xliff:g>"</string>
    +     <string name="ext_media_checking_notification_message" msgid="4747432538578886744">"Leitar að villum"</string>
    +     <string name="ext_media_new_notification_message" msgid="7589986898808506239">"Nýtt <xliff:g id="NAME">%s</xliff:g> fannst"</string>
    +@@ -1232,8 +1243,9 @@
    +     <string name="vpn_text_long" msgid="4907843483284977618">"Tengt við <xliff:g id="SESSION">%s</xliff:g>. Ýttu til að hafa umsjón með netinu."</string>
    +     <string name="vpn_lockdown_connecting" msgid="6443438964440960745">"Sívirkt VPN tengist…"</string>
    +     <string name="vpn_lockdown_connected" msgid="8202679674819213931">"Sívirkt VPN tengt"</string>
    ++    <string name="vpn_lockdown_disconnected" msgid="4532298952570796327">"Sívirkt VPN aftengt"</string>
    +     <string name="vpn_lockdown_error" msgid="6009249814034708175">"Villa í sívirku VPN"</string>
    +-    <string name="vpn_lockdown_config" msgid="4655589351146766608">"Ýttu til að stilla"</string>
    ++    <string name="vpn_lockdown_config" msgid="5099330695245008680">"Ýttu til að setja upp"</string>
    +     <string name="upload_file" msgid="2897957172366730416">"Velja skrá"</string>
    +     <string name="no_file_chosen" msgid="6363648562170759465">"Engin skrá valin"</string>
    +     <string name="reset" msgid="2448168080964209908">"Endurstilla"</string>
    +@@ -1317,7 +1329,7 @@
    +     <string name="storage_usb_drive_label" msgid="4501418548927759953">"USB-drif frá <xliff:g id="MANUFACTURER">%s</xliff:g>"</string>
    +     <string name="storage_usb" msgid="3017954059538517278">"USB-geymsla"</string>
    +     <string name="extract_edit_menu_button" msgid="8940478730496610137">"Breyta"</string>
    +-    <string name="data_usage_warning_title" msgid="1955638862122232342">"Viðvörun vegna gagnanotkunar"</string>
    ++    <string name="data_usage_warning_title" msgid="3620440638180218181">"Viðvörun um gagnanotkun"</string>
    +     <string name="data_usage_warning_body" msgid="6660692274311972007">"Ýttu fyrir uppl. og stillingar"</string>
    +     <string name="data_usage_3g_limit_title" msgid="4361523876818447683">"Gagnahámarki 2G og 3G náð"</string>
    +     <string name="data_usage_4g_limit_title" msgid="4609566827219442376">"Gagnahámarki 4G náð"</string>
    +@@ -1636,6 +1648,7 @@
    +     <string name="search_language_hint" msgid="7042102592055108574">"Sláðu inn heiti tungumáls"</string>
    +     <string name="language_picker_section_suggested" msgid="8414489646861640885">"Tillögur"</string>
    +     <string name="language_picker_section_all" msgid="3097279199511617537">"Öll tungumál"</string>
    ++    <string name="region_picker_section_all" msgid="8966316787153001779">"Öll svæði"</string>
    +     <string name="locale_search_menu" msgid="2560710726687249178">"Leita"</string>
    +     <string name="work_mode_off_title" msgid="8954725060677558855">"Slökkt á vinnusniði"</string>
    +     <string name="work_mode_off_message" msgid="3286169091278094476">"Leyfa virkni vinnusniðs, m.a. forrita, samstillingar í bakgrunni og tengdra eiginleika."</string>
    +diff --git a/core/res/res/values-it/strings.xml b/core/res/res/values-it/strings.xml
    +index 9cd74dc..b82470f 100644
    +--- a/core/res/res/values-it/strings.xml
    ++++ b/core/res/res/values-it/strings.xml
    +@@ -214,6 +214,7 @@
    +     <string name="global_actions" product="default" msgid="2406416831541615258">"Opzioni telefono"</string>
    +     <string name="global_action_lock" msgid="2844945191792119712">"Blocco schermo"</string>
    +     <string name="global_action_power_off" msgid="4471879440839879722">"Spegni"</string>
    ++    <string name="global_action_emergency" msgid="7112311161137421166">"Emergenza"</string>
    +     <string name="global_action_bug_report" msgid="7934010578922304799">"Segnalazione di bug"</string>
    +     <string name="bugreport_title" msgid="2667494803742548533">"Apri segnalazione bug"</string>
    +     <string name="bugreport_message" msgid="398447048750350456">"Verranno raccolte informazioni sullo stato corrente del dispositivo che saranno inviate sotto forma di messaggio email. Passerà un po\' di tempo prima che la segnalazione di bug aperta sia pronta per essere inviata; ti preghiamo di avere pazienza."</string>
    +@@ -1076,6 +1077,17 @@
    +     <skip />
    +     <string name="wifi_no_internet" msgid="8451173622563841546">"Connessione Wi-Fi priva di accesso Internet"</string>
    +     <string name="wifi_no_internet_detailed" msgid="8083079241212301741">"Tocca per le opzioni"</string>
    ++    <string name="network_switch_metered" msgid="4671730921726992671">"Passato a <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
    ++    <string name="network_switch_metered_detail" msgid="5325661434777870353">"Il dispositivo utilizza <xliff:g id="NEW_NETWORK">%1$s</xliff:g> quando <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> non ha accesso a Internet. Potrebbero essere applicati costi."</string>
    ++    <string name="network_switch_metered_toast" msgid="5779283181685974304">"Passato da <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> a <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
    ++  <string-array name="network_switch_type_name">
    ++    <item msgid="2952042958050315394">"rete dati"</item>
    ++    <item msgid="75483255295529161">"Wi-Fi"</item>
    ++    <item msgid="6862614801537202646">"Bluetooth"</item>
    ++    <item msgid="5447331121797802871">"Ethernet"</item>
    ++    <item msgid="8257233890381651999">"VPN"</item>
    ++  </string-array>
    ++    <string name="network_switch_type_name_unknown" msgid="4552612897806660656">"tipo di rete sconosciuto"</string>
    +     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Impossibile connettersi alla rete Wi-Fi"</string>
    +     <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" ha una connessione Internet debole."</string>
    +     <string name="wifi_connect_alert_title" msgid="8455846016001810172">"Consentire la connessione?"</string>
    +@@ -1153,7 +1165,6 @@
    +     <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"Tocca per selezionare la lingua e il layout"</string>
    +     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
    +     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
    +-    <string name="candidates_style" msgid="4333913089637062257"><u>"candidati"</u></string>
    +     <string name="ext_media_checking_notification_title" msgid="5734005953288045806">"Preparazione della <xliff:g id="NAME">%s</xliff:g>"</string>
    +     <string name="ext_media_checking_notification_message" msgid="4747432538578886744">"Ricerca errori"</string>
    +     <string name="ext_media_new_notification_message" msgid="7589986898808506239">"Nuova <xliff:g id="NAME">%s</xliff:g> rilevata"</string>
    +@@ -1232,8 +1243,9 @@
    +     <string name="vpn_text_long" msgid="4907843483284977618">"Collegata a <xliff:g id="SESSION">%s</xliff:g>. Tocca per gestire la rete."</string>
    +     <string name="vpn_lockdown_connecting" msgid="6443438964440960745">"Connessione a VPN sempre attiva…"</string>
    +     <string name="vpn_lockdown_connected" msgid="8202679674819213931">"VPN sempre attiva connessa"</string>
    ++    <string name="vpn_lockdown_disconnected" msgid="4532298952570796327">"VPN sempre attiva disconnessa"</string>
    +     <string name="vpn_lockdown_error" msgid="6009249814034708175">"Errore VPN sempre attiva"</string>
    +-    <string name="vpn_lockdown_config" msgid="4655589351146766608">"Tocca per configurare"</string>
    ++    <string name="vpn_lockdown_config" msgid="5099330695245008680">"Tocca per configurare"</string>
    +     <string name="upload_file" msgid="2897957172366730416">"Scegli file"</string>
    +     <string name="no_file_chosen" msgid="6363648562170759465">"Nessun file è stato scelto"</string>
    +     <string name="reset" msgid="2448168080964209908">"Reimposta"</string>
    +@@ -1317,7 +1329,7 @@
    +     <string name="storage_usb_drive_label" msgid="4501418548927759953">"Unità USB <xliff:g id="MANUFACTURER">%s</xliff:g>"</string>
    +     <string name="storage_usb" msgid="3017954059538517278">"Archivio USB"</string>
    +     <string name="extract_edit_menu_button" msgid="8940478730496610137">"Modifica"</string>
    +-    <string name="data_usage_warning_title" msgid="1955638862122232342">"Avviso sull\'utilizzo dei dati"</string>
    ++    <string name="data_usage_warning_title" msgid="3620440638180218181">"Avviso sull\'utilizzo dei dati"</string>
    +     <string name="data_usage_warning_body" msgid="6660692274311972007">"Tocca per uso e impostazioni."</string>
    +     <string name="data_usage_3g_limit_title" msgid="4361523876818447683">"Limite di dati 2G-3G raggiunto"</string>
    +     <string name="data_usage_4g_limit_title" msgid="4609566827219442376">"Limite di dati 4G raggiunto"</string>
    +@@ -1636,6 +1648,7 @@
    +     <string name="search_language_hint" msgid="7042102592055108574">"Digita nome lingua"</string>
    +     <string name="language_picker_section_suggested" msgid="8414489646861640885">"Suggerite"</string>
    +     <string name="language_picker_section_all" msgid="3097279199511617537">"Tutte le lingue"</string>
    ++    <string name="region_picker_section_all" msgid="8966316787153001779">"Tutte le aree geografiche"</string>
    +     <string name="locale_search_menu" msgid="2560710726687249178">"Cerca"</string>
    +     <string name="work_mode_off_title" msgid="8954725060677558855">"Modalità Lavoro DISATTIVATA"</string>
    +     <string name="work_mode_off_message" msgid="3286169091278094476">"Attiva il profilo di lavoro, incluse app, sincronizzazione in background e funzioni correlate."</string>
    +diff --git a/core/res/res/values-iw/strings.xml b/core/res/res/values-iw/strings.xml
    +index bebe027..36c5205 100644
    +--- a/core/res/res/values-iw/strings.xml
    ++++ b/core/res/res/values-iw/strings.xml
    +@@ -218,6 +218,7 @@
    +     <string name="global_actions" product="default" msgid="2406416831541615258">"אפשרויות טלפון"</string>
    +     <string name="global_action_lock" msgid="2844945191792119712">"נעילת מסך"</string>
    +     <string name="global_action_power_off" msgid="4471879440839879722">"כיבוי"</string>
    ++    <string name="global_action_emergency" msgid="7112311161137421166">"חירום"</string>
    +     <string name="global_action_bug_report" msgid="7934010578922304799">"דיווח על באג"</string>
    +     <string name="bugreport_title" msgid="2667494803742548533">"שלח דיווח על באג"</string>
    +     <string name="bugreport_message" msgid="398447048750350456">"פעולה זו תאסוף מידע על מצב המכשיר הנוכחי שלך על מנת לשלוח אותו כהודעת אימייל. היא תימשך זמן קצר מרגע פתיחת דיווח הבאג ועד לשליחת ההודעה בפועל. אנא המתן בסבלנות."</string>
    +@@ -1126,6 +1127,17 @@
    +     <skip />
    +     <string name="wifi_no_internet" msgid="8451173622563841546">"‏אין ל-Wi-Fi גישה לאינטרנט"</string>
    +     <string name="wifi_no_internet_detailed" msgid="8083079241212301741">"הקש לקבלת אפשרויות"</string>
    ++    <string name="network_switch_metered" msgid="4671730921726992671">"מעבר אל <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
    ++    <string name="network_switch_metered_detail" msgid="5325661434777870353">"המכשיר משתמש ברשת <xliff:g id="NEW_NETWORK">%1$s</xliff:g> כשלרשת <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> אין גישה לאינטרנט. עשויים לחול חיובים."</string>
    ++    <string name="network_switch_metered_toast" msgid="5779283181685974304">"עבר מרשת <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> לרשת <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
    ++  <string-array name="network_switch_type_name">
    ++    <item msgid="2952042958050315394">"נתונים סלולריים"</item>
    ++    <item msgid="75483255295529161">"Wi-Fi"</item>
    ++    <item msgid="6862614801537202646">"Bluetooth"</item>
    ++    <item msgid="5447331121797802871">"Ethernet"</item>
    ++    <item msgid="8257233890381651999">"VPN"</item>
    ++  </string-array>
    ++    <string name="network_switch_type_name_unknown" msgid="4552612897806660656">"סוג רשת לא מזוהה"</string>
    +     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"‏אין אפשרות להתחבר ל-Wi-Fi"</string>
    +     <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" אינו מחובר היטב לאינטרנט."</string>
    +     <string name="wifi_connect_alert_title" msgid="8455846016001810172">"האם להתיר את החיבור?"</string>
    +@@ -1203,7 +1215,6 @@
    +     <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"הקש כדי לבחור שפה ופריסה"</string>
    +     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
    +     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
    +-    <string name="candidates_style" msgid="4333913089637062257"><u>"מועמדים"</u></string>
    +     <string name="ext_media_checking_notification_title" msgid="5734005953288045806">"הכנת <xliff:g id="NAME">%s</xliff:g>"</string>
    +     <string name="ext_media_checking_notification_message" msgid="4747432538578886744">"בודק אם יש שגיאות"</string>
    +     <string name="ext_media_new_notification_message" msgid="7589986898808506239">"זוהה <xliff:g id="NAME">%s</xliff:g> חדש"</string>
    +@@ -1282,8 +1293,9 @@
    +     <string name="vpn_text_long" msgid="4907843483284977618">"מחובר אל <xliff:g id="SESSION">%s</xliff:g>. הקש כדי לנהל את הרשת."</string>
    +     <string name="vpn_lockdown_connecting" msgid="6443438964440960745">"‏ה-VPN שמופעל תמיד, מתחבר..."</string>
    +     <string name="vpn_lockdown_connected" msgid="8202679674819213931">"‏ה-VPN שפועל תמיד, מחובר"</string>
    ++    <string name="vpn_lockdown_disconnected" msgid="4532298952570796327">"‏חיבור תמידי ל-VPN מנותק"</string>
    +     <string name="vpn_lockdown_error" msgid="6009249814034708175">"‏שגיאת VPN שמופעל תמיד"</string>
    +-    <string name="vpn_lockdown_config" msgid="4655589351146766608">"הקש כדי להגדיר"</string>
    ++    <string name="vpn_lockdown_config" msgid="5099330695245008680">"הקש כדי להגדיר"</string>
    +     <string name="upload_file" msgid="2897957172366730416">"בחר קובץ"</string>
    +     <string name="no_file_chosen" msgid="6363648562170759465">"לא נבחר קובץ"</string>
    +     <string name="reset" msgid="2448168080964209908">"איפוס"</string>
    +@@ -1362,14 +1374,14 @@
    +     <string name="action_menu_overflow_description" msgid="2295659037509008453">"אפשרויות נוספות"</string>
    +     <string name="action_bar_home_description_format" msgid="7965984360903693903">"‏%1$s‏, %2$s"</string>
    +     <string name="action_bar_home_subtitle_description_format" msgid="6985546530471780727">"‏%1$s‏, %2$s‏, %3$s"</string>
    +-    <string name="storage_internal" msgid="3570990907910199483">"אחסון משותף פנימי"</string>
    ++    <string name="storage_internal" msgid="3570990907910199483">"אחסון שיתוף פנימי"</string>
    +     <string name="storage_sd_card" msgid="3282948861378286745">"‏כרטיס SD"</string>
    +     <string name="storage_sd_card_label" msgid="6347111320774379257">"‏כרטיס SD של <xliff:g id="MANUFACTURER">%s</xliff:g>"</string>
    +     <string name="storage_usb_drive" msgid="6261899683292244209">"‏כונן USB"</string>
    +     <string name="storage_usb_drive_label" msgid="4501418548927759953">"‏כונן USB של <xliff:g id="MANUFACTURER">%s</xliff:g>"</string>
    +     <string name="storage_usb" msgid="3017954059538517278">"‏אחסון USB"</string>
    +     <string name="extract_edit_menu_button" msgid="8940478730496610137">"ערוך"</string>
    +-    <string name="data_usage_warning_title" msgid="1955638862122232342">"אזהרת שימוש בנתונים"</string>
    ++    <string name="data_usage_warning_title" msgid="3620440638180218181">"התראה לשימוש בנתונים"</string>
    +     <string name="data_usage_warning_body" msgid="6660692274311972007">"הקש כדי להציג נתוני שימוש והגדרות."</string>
    +     <string name="data_usage_3g_limit_title" msgid="4361523876818447683">"‏הגעת למגבלת הנתונים של 2G-3G"</string>
    +     <string name="data_usage_4g_limit_title" msgid="4609566827219442376">"‏הגעת למגבלת הנתונים של 4G"</string>
    +@@ -1708,6 +1720,7 @@
    +     <string name="search_language_hint" msgid="7042102592055108574">"הקלד שם שפה"</string>
    +     <string name="language_picker_section_suggested" msgid="8414489646861640885">"הצעות"</string>
    +     <string name="language_picker_section_all" msgid="3097279199511617537">"כל השפות"</string>
    ++    <string name="region_picker_section_all" msgid="8966316787153001779">"כל האזורים"</string>
    +     <string name="locale_search_menu" msgid="2560710726687249178">"חיפוש"</string>
    +     <string name="work_mode_off_title" msgid="8954725060677558855">"מצב העבודה כבוי"</string>
    +     <string name="work_mode_off_message" msgid="3286169091278094476">"אפשר לפרופיל העבודה לפעול, כולל אפליקציות, סנכרון ברקע ותכונות קשורות."</string>
    +diff --git a/core/res/res/values-ja/strings.xml b/core/res/res/values-ja/strings.xml
    +index b2a7bd2..5550900 100644
    +--- a/core/res/res/values-ja/strings.xml
    ++++ b/core/res/res/values-ja/strings.xml
    +@@ -214,6 +214,7 @@
    +     <string name="global_actions" product="default" msgid="2406416831541615258">"携帯電話オプション"</string>
    +     <string name="global_action_lock" msgid="2844945191792119712">"画面ロック"</string>
    +     <string name="global_action_power_off" msgid="4471879440839879722">"電源を切る"</string>
    ++    <string name="global_action_emergency" msgid="7112311161137421166">"緊急通報"</string>
    +     <string name="global_action_bug_report" msgid="7934010578922304799">"バグレポート"</string>
    +     <string name="bugreport_title" msgid="2667494803742548533">"バグレポートを取得"</string>
    +     <string name="bugreport_message" msgid="398447048750350456">"現在の端末の状態に関する情報が収集され、その内容がメールで送信されます。バグレポートが開始してから送信可能な状態となるまでには多少の時間がかかりますのでご了承ください。"</string>
    +@@ -374,7 +375,7 @@
    +     <string name="permdesc_callPhone" msgid="3740797576113760827">"電話番号への自動発信をアプリに許可します。これにより、予期せぬ発信や料金が発生する可能性があります。なお、緊急通報番号への発信は許可されません。悪意のあるアプリが確認なしで発信し、料金が発生する恐れがあります。"</string>
    +     <string name="permlab_accessImsCallService" msgid="3574943847181793918">"IMS通話サービスへのアクセス"</string>
    +     <string name="permdesc_accessImsCallService" msgid="8992884015198298775">"IMSサービスがユーザー操作なしで電話をかけることをアプリに許可します。"</string>
    +-    <string name="permlab_readPhoneState" msgid="9178228524507610486">"端末のステータスとIDの読み取り"</string>
    ++    <string name="permlab_readPhoneState" msgid="9178228524507610486">"端末情報と ID の読み取り"</string>
    +     <string name="permdesc_readPhoneState" msgid="1639212771826125528">"端末の電話機能へのアクセスをアプリに許可します。これにより、電話番号、端末ID、通話中かどうか、通話相手の電話番号をアプリから特定できるようになります。"</string>
    +     <string name="permlab_wakeLock" product="tablet" msgid="1531731435011495015">"タブレットのスリープを無効化"</string>
    +     <string name="permlab_wakeLock" product="tv" msgid="2601193288949154131">"テレビのスリープを無効化"</string>
    +@@ -511,8 +512,8 @@
    +     <string name="permdesc_bindCarrierMessagingService" msgid="2762882888502113944">"携帯通信会社のSMSサービスのトップレベルインターフェースにバインドすることを所有者に許可します。通常のアプリでは不要です。"</string>
    +     <string name="permlab_bindCarrierServices" msgid="3233108656245526783">"携帯通信会社のサービスへのバインド"</string>
    +     <string name="permdesc_bindCarrierServices" msgid="1391552602551084192">"携帯通信会社のサービスにバインドすることを所有者に許可します。通常のアプリでは不要です。"</string>
    +-    <string name="permlab_access_notification_policy" msgid="4247510821662059671">"[通知を非表示]へのアクセス"</string>
    +-    <string name="permdesc_access_notification_policy" msgid="3296832375218749580">"[通知を非表示]の設定の読み取りと書き込みをアプリに許可します。"</string>
    ++    <string name="permlab_access_notification_policy" msgid="4247510821662059671">"マナーモードへのアクセス"</string>
    ++    <string name="permdesc_access_notification_policy" msgid="3296832375218749580">"マナーモード設定の読み取りと書き込みをアプリに許可します。"</string>
    +     <string name="policylab_limitPassword" msgid="4497420728857585791">"パスワードルールの設定"</string>
    +     <string name="policydesc_limitPassword" msgid="2502021457917874968">"画面ロックのパスワードとPINの長さと使用できる文字を制御します。"</string>
    +     <string name="policylab_watchLogin" msgid="914130646942199503">"画面ロック解除試行の監視"</string>
    +@@ -1076,6 +1077,17 @@
    +     <skip />
    +     <string name="wifi_no_internet" msgid="8451173622563841546">"Wi-Fiはインターネットに接続していません"</string>
    +     <string name="wifi_no_internet_detailed" msgid="8083079241212301741">"タップしてその他のオプションを表示"</string>
    ++    <string name="network_switch_metered" msgid="4671730921726992671">"「<xliff:g id="NETWORK_TYPE">%1$s</xliff:g>」に切り替えました"</string>
    ++    <string name="network_switch_metered_detail" msgid="5325661434777870353">"端末で「<xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g>」によるインターネット接続ができない場合に「<xliff:g id="NEW_NETWORK">%1$s</xliff:g>」を使用します。通信料が発生することがあります。"</string>
    ++    <string name="network_switch_metered_toast" msgid="5779283181685974304">"「<xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g>」から「<xliff:g id="NEW_NETWORK">%2$s</xliff:g>」に切り替えました"</string>
    ++  <string-array name="network_switch_type_name">
    ++    <item msgid="2952042958050315394">"モバイルデータ"</item>
    ++    <item msgid="75483255295529161">"Wi-Fi"</item>
    ++    <item msgid="6862614801537202646">"Bluetooth"</item>
    ++    <item msgid="5447331121797802871">"イーサネット"</item>
    ++    <item msgid="8257233890381651999">"VPN"</item>
    ++  </string-array>
    ++    <string name="network_switch_type_name_unknown" msgid="4552612897806660656">"不明なネットワーク タイプ"</string>
    +     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Wi-Fiに接続できませんでした"</string>
    +     <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" はインターネット接続に問題があります。"</string>
    +     <string name="wifi_connect_alert_title" msgid="8455846016001810172">"接続を許可しますか?"</string>
    +@@ -1153,7 +1165,6 @@
    +     <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"タップして言語とレイアウトを選択してください"</string>
    +     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
    +     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
    +-    <string name="candidates_style" msgid="4333913089637062257"><u>"候補"</u></string>
    +     <string name="ext_media_checking_notification_title" msgid="5734005953288045806">"<xliff:g id="NAME">%s</xliff:g>を準備中"</string>
    +     <string name="ext_media_checking_notification_message" msgid="4747432538578886744">"エラーを確認中"</string>
    +     <string name="ext_media_new_notification_message" msgid="7589986898808506239">"新しい<xliff:g id="NAME">%s</xliff:g>が検出されました"</string>
    +@@ -1232,8 +1243,9 @@
    +     <string name="vpn_text_long" msgid="4907843483284977618">"<xliff:g id="SESSION">%s</xliff:g>に接続しました。ネットワークを管理するにはタップしてください。"</string>
    +     <string name="vpn_lockdown_connecting" msgid="6443438964440960745">"VPNに常時接続しています…"</string>
    +     <string name="vpn_lockdown_connected" msgid="8202679674819213931">"VPNに常時接続しました"</string>
    ++    <string name="vpn_lockdown_disconnected" msgid="4532298952570796327">"常時接続 VPN の接続を解除しました"</string>
    +     <string name="vpn_lockdown_error" msgid="6009249814034708175">"常時接続VPNのエラー"</string>
    +-    <string name="vpn_lockdown_config" msgid="4655589351146766608">"タップして設定"</string>
    ++    <string name="vpn_lockdown_config" msgid="5099330695245008680">"設定するにはタップします"</string>
    +     <string name="upload_file" msgid="2897957172366730416">"ファイルを選択"</string>
    +     <string name="no_file_chosen" msgid="6363648562170759465">"ファイルが選択されていません"</string>
    +     <string name="reset" msgid="2448168080964209908">"リセット"</string>
    +@@ -1317,7 +1329,7 @@
    +     <string name="storage_usb_drive_label" msgid="4501418548927759953">"<xliff:g id="MANUFACTURER">%s</xliff:g>製USBドライブ"</string>
    +     <string name="storage_usb" msgid="3017954059538517278">"USBストレージ"</string>
    +     <string name="extract_edit_menu_button" msgid="8940478730496610137">"編集"</string>
    +-    <string name="data_usage_warning_title" msgid="1955638862122232342">"データ使用の警告"</string>
    ++    <string name="data_usage_warning_title" msgid="3620440638180218181">"データ使用量に関する通知"</string>
    +     <string name="data_usage_warning_body" msgid="6660692274311972007">"タップして使用状況と設定を表示します。"</string>
    +     <string name="data_usage_3g_limit_title" msgid="4361523876818447683">"2G~3Gデータの上限に達しました"</string>
    +     <string name="data_usage_4g_limit_title" msgid="4609566827219442376">"4Gデータの上限に達しました"</string>
    +@@ -1595,10 +1607,10 @@
    +     <string name="zen_mode_until" msgid="7336308492289875088">"<xliff:g id="FORMATTEDTIME">%1$s</xliff:g>まで"</string>
    +     <string name="zen_mode_alarm" msgid="9128205721301330797">"<xliff:g id="FORMATTEDTIME">%1$s</xliff:g>(次のアラーム)まで"</string>
    +     <string name="zen_mode_forever" msgid="7420011936770086993">"ユーザーがOFFにするまで"</string>
    +-    <string name="zen_mode_forever_dnd" msgid="3792132696572189081">"[通知を非表示]をOFFにするまで"</string>
    ++    <string name="zen_mode_forever_dnd" msgid="3792132696572189081">"マナーモードを OFF にするまで"</string>
    +     <string name="zen_mode_rule_name_combination" msgid="191109939968076477">"<xliff:g id="FIRST">%1$s</xliff:g>/<xliff:g id="REST">%2$s</xliff:g>"</string>
    +     <string name="toolbar_collapse_description" msgid="2821479483960330739">"折りたたむ"</string>
    +-    <string name="zen_mode_feature_name" msgid="5254089399895895004">"通知を非表示"</string>
    ++    <string name="zen_mode_feature_name" msgid="5254089399895895004">"マナーモード"</string>
    +     <string name="zen_mode_downtime_feature_name" msgid="2626974636779860146">"ダウンタイム"</string>
    +     <string name="zen_mode_default_weeknights_name" msgid="3081318299464998143">"平日の夜"</string>
    +     <string name="zen_mode_default_weekends_name" msgid="2786495801019345244">"週末"</string>
    +@@ -1636,6 +1648,7 @@
    +     <string name="search_language_hint" msgid="7042102592055108574">"言語名を入力"</string>
    +     <string name="language_picker_section_suggested" msgid="8414489646861640885">"言語の候補"</string>
    +     <string name="language_picker_section_all" msgid="3097279199511617537">"すべての言語"</string>
    ++    <string name="region_picker_section_all" msgid="8966316787153001779">"すべての地域"</string>
    +     <string name="locale_search_menu" msgid="2560710726687249178">"検索"</string>
    +     <string name="work_mode_off_title" msgid="8954725060677558855">"Work モード OFF"</string>
    +     <string name="work_mode_off_message" msgid="3286169091278094476">"仕事用プロファイルで、アプリ、バックグラウンド同期などの関連機能の使用を許可します。"</string>
    +diff --git a/core/res/res/values-ka-rGE/strings.xml b/core/res/res/values-ka-rGE/strings.xml
    +index 0295ea5..a8fed8b 100644
    +--- a/core/res/res/values-ka-rGE/strings.xml
    ++++ b/core/res/res/values-ka-rGE/strings.xml
    +@@ -214,6 +214,7 @@
    +     <string name="global_actions" product="default" msgid="2406416831541615258">"ტელეფონის პარამეტრები"</string>
    +     <string name="global_action_lock" msgid="2844945191792119712">"ეკრანის დაბლოკვა"</string>
    +     <string name="global_action_power_off" msgid="4471879440839879722">"კვების გამორთვა"</string>
    ++    <string name="global_action_emergency" msgid="7112311161137421166">"საგანგებო სამსახურები"</string>
    +     <string name="global_action_bug_report" msgid="7934010578922304799">"ხარვეზის შესახებ ანგარიში"</string>
    +     <string name="bugreport_title" msgid="2667494803742548533">"შექმენით შეცდომის ანგარიში"</string>
    +     <string name="bugreport_message" msgid="398447048750350456">"იგი შეაგროვებს ინფორმაციას თქვენი მოწყობილობის ამჟამინდელი მდგომარეობის შესახებ, რათა ის ელფოსტის შეტყობინების სახით გააგზავნოს. ხარვეზის ანგარიშის მომზადებასა და შეტყობინების გაგზავნას გარკვეული დრო სჭირდება. გთხოვთ, მოითმინოთ."</string>
    +@@ -1076,6 +1077,17 @@
    +     <skip />
    +     <string name="wifi_no_internet" msgid="8451173622563841546">"Wi-Fi-ს არ აქვს ინტერნეტზე წვდომა"</string>
    +     <string name="wifi_no_internet_detailed" msgid="8083079241212301741">"შეეხეთ ვარიანტების სანახავად"</string>
    ++    <string name="network_switch_metered" msgid="4671730921726992671">"ახლა გამოიყენება <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
    ++    <string name="network_switch_metered_detail" msgid="5325661434777870353">"თუ <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> ინტერნეტთან კავშირს დაკარგავს, მოწყობილობის მიერ <xliff:g id="NEW_NETWORK">%1$s</xliff:g> იქნება გამოყენებული, რამაც შეიძლება დამატებითი ხარჯები გამოიწვიოს"</string>
    ++    <string name="network_switch_metered_toast" msgid="5779283181685974304">"ახლა გამოიყენება <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> (გამოიყენებოდა <xliff:g id="NEW_NETWORK">%2$s</xliff:g>)"</string>
    ++  <string-array name="network_switch_type_name">
    ++    <item msgid="2952042958050315394">"მობილური ინტერნეტი"</item>
    ++    <item msgid="75483255295529161">"Wi-Fi"</item>
    ++    <item msgid="6862614801537202646">"Bluetooth"</item>
    ++    <item msgid="5447331121797802871">"Ethernet"</item>
    ++    <item msgid="8257233890381651999">"VPN"</item>
    ++  </string-array>
    ++    <string name="network_switch_type_name_unknown" msgid="4552612897806660656">"უცნობი ტიპის ქსელი"</string>
    +     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Wi-Fi-თან დაკავშირება ვერ მოხერხდა"</string>
    +     <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" აქვს ცუდი ინტერნეტ კავშირი."</string>
    +     <string name="wifi_connect_alert_title" msgid="8455846016001810172">"გსურთ კავშირის დაშვება?"</string>
    +@@ -1153,7 +1165,6 @@
    +     <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"შეეხეთ ენისა და განლაგების ასარჩევად"</string>
    +     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
    +     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
    +-    <string name="candidates_style" msgid="4333913089637062257"><u>"კანდიდატები"</u></string>
    +     <string name="ext_media_checking_notification_title" msgid="5734005953288045806">"<xliff:g id="NAME">%s</xliff:g>-ის მომზადება"</string>
    +     <string name="ext_media_checking_notification_message" msgid="4747432538578886744">"შეცდომების შემოწმება"</string>
    +     <string name="ext_media_new_notification_message" msgid="7589986898808506239">"აღმოჩენილია ახალი <xliff:g id="NAME">%s</xliff:g>"</string>
    +@@ -1232,8 +1243,9 @@
    +     <string name="vpn_text_long" msgid="4907843483284977618">"მიერთებულია <xliff:g id="SESSION">%s</xliff:g>-ზე. შეეხეთ ქსელის სამართავად."</string>
    +     <string name="vpn_lockdown_connecting" msgid="6443438964440960745">"მიმდინარეობს მუდმივად ჩართული VPN-ის მიერთება…"</string>
    +     <string name="vpn_lockdown_connected" msgid="8202679674819213931">"მუდმივად ჩართული VPN-ის მიერთებულია"</string>
    ++    <string name="vpn_lockdown_disconnected" msgid="4532298952570796327">"მუდმივად ჩართული VPN გათიშულია"</string>
    +     <string name="vpn_lockdown_error" msgid="6009249814034708175">"შეცდომა მუდამ VPN-ზე"</string>
    +-    <string name="vpn_lockdown_config" msgid="4655589351146766608">"შეეხეთ პარამეტრების კონფიგურაციისთვის"</string>
    ++    <string name="vpn_lockdown_config" msgid="5099330695245008680">"შეეხეთ დასაყენებლად"</string>
    +     <string name="upload_file" msgid="2897957172366730416">"ფაილის არჩევა"</string>
    +     <string name="no_file_chosen" msgid="6363648562170759465">"ფაილი არჩეული არ არის"</string>
    +     <string name="reset" msgid="2448168080964209908">"საწყისზე დაბრუნება"</string>
    +@@ -1317,7 +1329,7 @@
    +     <string name="storage_usb_drive_label" msgid="4501418548927759953">"<xliff:g id="MANUFACTURER">%s</xliff:g> USB დისკი"</string>
    +     <string name="storage_usb" msgid="3017954059538517278">"USB მეხსიერება"</string>
    +     <string name="extract_edit_menu_button" msgid="8940478730496610137">"რედაქტირება"</string>
    +-    <string name="data_usage_warning_title" msgid="1955638862122232342">"ინტერნეტის გამოყენების გაფრთხილება"</string>
    ++    <string name="data_usage_warning_title" msgid="3620440638180218181">"მონაცემთა მოხმარების გაფრთხილება"</string>
    +     <string name="data_usage_warning_body" msgid="6660692274311972007">"შეეხეთ მოხმარებისა და პარამეტრების სანახავად."</string>
    +     <string name="data_usage_3g_limit_title" msgid="4361523876818447683">"2G-3G მონაცემთა ლიმიტი ამოიწურა"</string>
    +     <string name="data_usage_4g_limit_title" msgid="4609566827219442376">"4G მონაცემთა ლიმიტი ამოიწურა"</string>
    +@@ -1636,6 +1648,7 @@
    +     <string name="search_language_hint" msgid="7042102592055108574">"აკრიფეთ ენის სახელი"</string>
    +     <string name="language_picker_section_suggested" msgid="8414489646861640885">"რეკომენდებული"</string>
    +     <string name="language_picker_section_all" msgid="3097279199511617537">"ყველა ენა"</string>
    ++    <string name="region_picker_section_all" msgid="8966316787153001779">"ყველა რეგიონი"</string>
    +     <string name="locale_search_menu" msgid="2560710726687249178">"ძიება"</string>
    +     <string name="work_mode_off_title" msgid="8954725060677558855">"სამსახურის რეჟიმი გამორთულია"</string>
    +     <string name="work_mode_off_message" msgid="3286169091278094476">"სამსახურის პროფილის მუშაობის დაშვება, მათ შორის, აპების, ფონური სინქრონიზაციის და დაკავშირებული ფუნქციების."</string>
    +diff --git a/core/res/res/values-kk-rKZ/strings.xml b/core/res/res/values-kk-rKZ/strings.xml
    +index b5931c1..00264ad 100644
    +--- a/core/res/res/values-kk-rKZ/strings.xml
    ++++ b/core/res/res/values-kk-rKZ/strings.xml
    +@@ -214,6 +214,7 @@
    +     <string name="global_actions" product="default" msgid="2406416831541615258">"Телефон опциялары"</string>
    +     <string name="global_action_lock" msgid="2844945191792119712">"Экранды құлыптау"</string>
    +     <string name="global_action_power_off" msgid="4471879440839879722">"Өшіру"</string>
    ++    <string name="global_action_emergency" msgid="7112311161137421166">"Төтенше жағдай"</string>
    +     <string name="global_action_bug_report" msgid="7934010578922304799">"Вирус туралы хабарлау"</string>
    +     <string name="bugreport_title" msgid="2667494803742548533">"Қате туралы есеп құру"</string>
    +     <string name="bugreport_message" msgid="398447048750350456">"Құрылғының қазіргі күйі туралы ақпаратты жинап, электрондық хабармен жібереді. Есеп әзір болғанша біраз уақыт кетеді, шыдай тұрыңыз."</string>
    +@@ -1076,6 +1077,17 @@
    +     <skip />
    +     <string name="wifi_no_internet" msgid="8451173622563841546">"Wi-Fi желісінде интернет байланысы жоқ"</string>
    +     <string name="wifi_no_internet_detailed" msgid="8083079241212301741">"Опциялар үшін түртіңіз"</string>
    ++    <string name="network_switch_metered" msgid="4671730921726992671">"<xliff:g id="NETWORK_TYPE">%1$s</xliff:g> желісіне ауысты"</string>
    ++    <string name="network_switch_metered_detail" msgid="5325661434777870353">"Құрылғы <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> желісінде интернетпен байланыс жоғалған жағдайда <xliff:g id="NEW_NETWORK">%1$s</xliff:g> желісін пайдаланады. Деректер ақысы алынуы мүмкін."</string>
    ++    <string name="network_switch_metered_toast" msgid="5779283181685974304">"<xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> желісінен <xliff:g id="NEW_NETWORK">%2$s</xliff:g> желісіне ауысты"</string>
    ++  <string-array name="network_switch_type_name">
    ++    <item msgid="2952042958050315394">"ұялы дерек"</item>
    ++    <item msgid="75483255295529161">"Wi-Fi"</item>
    ++    <item msgid="6862614801537202646">"Bluetooth"</item>
    ++    <item msgid="5447331121797802871">"Ethernet"</item>
    ++    <item msgid="8257233890381651999">"VPN"</item>
    ++  </string-array>
    ++    <string name="network_switch_type_name_unknown" msgid="4552612897806660656">"желі түрі белгісіз"</string>
    +     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Wi-Fi желісіне қосыла алмады"</string>
    +     <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" Интернет байланысы нашар."</string>
    +     <string name="wifi_connect_alert_title" msgid="8455846016001810172">"Қосылуға рұқсат ету керек пе?"</string>
    +@@ -1153,7 +1165,6 @@
    +     <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"Тіл мен пернетақта схемасын таңдау үшін түртіңіз"</string>
    +     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
    +     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
    +-    <string name="candidates_style" msgid="4333913089637062257"><u>"үміткерлер"</u></string>
    +     <string name="ext_media_checking_notification_title" msgid="5734005953288045806">"<xliff:g id="NAME">%s</xliff:g> дайындалуда"</string>
    +     <string name="ext_media_checking_notification_message" msgid="4747432538578886744">"Қателер тексерілуде"</string>
    +     <string name="ext_media_new_notification_message" msgid="7589986898808506239">"Жаңа <xliff:g id="NAME">%s</xliff:g> анықталды"</string>
    +@@ -1232,8 +1243,9 @@
    +     <string name="vpn_text_long" msgid="4907843483284977618">"<xliff:g id="SESSION">%s</xliff:g> жүйесіне жалғанған. Желіні басқару үшін түріңіз."</string>
    +     <string name="vpn_lockdown_connecting" msgid="6443438964440960745">"Әрқашан қосылған ВЖЖ жалғануда…"</string>
    +     <string name="vpn_lockdown_connected" msgid="8202679674819213931">"Әрқашан қосылған ВЖЖ жалғанған"</string>
    ++    <string name="vpn_lockdown_disconnected" msgid="4532298952570796327">"Әрқашан қосулы VPN желісі ажыратылды"</string>
    +     <string name="vpn_lockdown_error" msgid="6009249814034708175">"Әрқашан қосылған ВЖЖ қателігі"</string>
    +-    <string name="vpn_lockdown_config" msgid="4655589351146766608">"Конфигурациялау үшін түртіңіз"</string>
    ++    <string name="vpn_lockdown_config" msgid="5099330695245008680">"Реттеу үшін түртіңіз"</string>
    +     <string name="upload_file" msgid="2897957172366730416">"Файлды таңдау"</string>
    +     <string name="no_file_chosen" msgid="6363648562170759465">"Ешқандай файл таңдалмаған"</string>
    +     <string name="reset" msgid="2448168080964209908">"Қайта реттеу"</string>
    +@@ -1317,7 +1329,7 @@
    +     <string name="storage_usb_drive_label" msgid="4501418548927759953">"<xliff:g id="MANUFACTURER">%s</xliff:g> USB дискі"</string>
    +     <string name="storage_usb" msgid="3017954059538517278">"USB жады"</string>
    +     <string name="extract_edit_menu_button" msgid="8940478730496610137">"Өзгерту"</string>
    +-    <string name="data_usage_warning_title" msgid="1955638862122232342">"Дерекқор қолдануға қатысты ескерту"</string>
    ++    <string name="data_usage_warning_title" msgid="3620440638180218181">"Деректер трафигі туралы ескерту"</string>
    +     <string name="data_usage_warning_body" msgid="6660692274311972007">"Трафик пен параметрлерді көру үшін түртіңіз."</string>
    +     <string name="data_usage_3g_limit_title" msgid="4361523876818447683">"2G-3G деректер шегіне жеттіңіз"</string>
    +     <string name="data_usage_4g_limit_title" msgid="4609566827219442376">"4G деректер шегіне жеттіңіз"</string>
    +@@ -1636,6 +1648,7 @@
    +     <string name="search_language_hint" msgid="7042102592055108574">"Тіл атауын теріңіз"</string>
    +     <string name="language_picker_section_suggested" msgid="8414489646861640885">"Ұсынылған"</string>
    +     <string name="language_picker_section_all" msgid="3097279199511617537">"Барлық тілдер"</string>
    ++    <string name="region_picker_section_all" msgid="8966316787153001779">"Барлық аймақтар"</string>
    +     <string name="locale_search_menu" msgid="2560710726687249178">"Іздеу"</string>
    +     <string name="work_mode_off_title" msgid="8954725060677558855">"Жұмыс режимі ӨШІРУЛІ"</string>
    +     <string name="work_mode_off_message" msgid="3286169091278094476">"Жұмыс профиліне, соның ішінде, қолданбаларға, фондық синхрондауға және қатысты мүмкіндіктерге жұмыс істеуге рұқсат ету."</string>
    +diff --git a/core/res/res/values-km-rKH/strings.xml b/core/res/res/values-km-rKH/strings.xml
    +index 71f8cba..feaef82 100644
    +--- a/core/res/res/values-km-rKH/strings.xml
    ++++ b/core/res/res/values-km-rKH/strings.xml
    +@@ -214,6 +214,7 @@
    +     <string name="global_actions" product="default" msgid="2406416831541615258">"ជម្រើស​ទូរស័ព្ទ"</string>
    +     <string name="global_action_lock" msgid="2844945191792119712">"ចាក់​សោ​អេក្រង់"</string>
    +     <string name="global_action_power_off" msgid="4471879440839879722">"បិទ"</string>
    ++    <string name="global_action_emergency" msgid="7112311161137421166">"អាសន្ន"</string>
    +     <string name="global_action_bug_report" msgid="7934010578922304799">"របាយការណ៍​កំហុស"</string>
    +     <string name="bugreport_title" msgid="2667494803742548533">"យក​របាយការណ៍​កំហុស"</string>
    +     <string name="bugreport_message" msgid="398447048750350456">"វា​នឹង​​ប្រមូល​ព័ត៌មាន​អំពី​ស្ថានភាព​ឧបករណ៍​របស់​អ្នក ដើម្បី​ផ្ញើ​ជា​សារ​អ៊ីមែល។ វា​នឹង​ចំណាយ​ពេល​តិច​ពី​ពេល​ចាប់ផ្ដើម​របាយការណ៍​រហូត​ដល់​ពេល​វា​រួចរាល់​ដើម្បី​ផ្ញើ សូម​អត់ធ្មត់។"</string>
    +@@ -1078,6 +1079,17 @@
    +     <skip />
    +     <string name="wifi_no_internet" msgid="8451173622563841546">"Wi-Fi មិនមានអ៊ិនធឺណិតនោះទេ"</string>
    +     <string name="wifi_no_internet_detailed" msgid="8083079241212301741">"ប៉ះសម្រាប់ជម្រើស"</string>
    ++    <string name="network_switch_metered" msgid="4671730921726992671">"បានប្តូរទៅ <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
    ++    <string name="network_switch_metered_detail" msgid="5325661434777870353">"ឧបករណ៍ប្រើ <xliff:g id="NEW_NETWORK">%1$s</xliff:g> នៅពេលដែល <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> គ្មានការតភ្ជាប់អ៊ីនធឺណិត។ អាចគិតប្រាក់លើការប្រើប្រាស់ទិន្នន័យ។"</string>
    ++    <string name="network_switch_metered_toast" msgid="5779283181685974304">"បានប្តូរពី <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> ទៅ <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
    ++  <string-array name="network_switch_type_name">
    ++    <item msgid="2952042958050315394">"ទិន្នន័យចល័ត"</item>
    ++    <item msgid="75483255295529161">"Wi-Fi"</item>
    ++    <item msgid="6862614801537202646">"ប៊្លូធូស"</item>
    ++    <item msgid="5447331121797802871">"អ៊ីសឺរណិត"</item>
    ++    <item msgid="8257233890381651999">"VPN"</item>
    ++  </string-array>
    ++    <string name="network_switch_type_name_unknown" msgid="4552612897806660656">"ប្រភេទបណ្តាញមិនស្គាល់"</string>
    +     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"មិន​​អាច​តភ្ជាប់​វ៉ាយហ្វាយ"</string>
    +     <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" មាន​ការ​តភ្ជាប់​អ៊ីនធឺណិត​មិន​ល្អ។"</string>
    +     <string name="wifi_connect_alert_title" msgid="8455846016001810172">"អនុញ្ញាត​ភ្ជាប់?"</string>
    +@@ -1155,7 +1167,6 @@
    +     <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"ប៉ះដើម្បីជ្រើសភាសា និងប្លង់"</string>
    +     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
    +     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
    +-    <string name="candidates_style" msgid="4333913089637062257"><u>"បេក្ខជន"</u></string>
    +     <string name="ext_media_checking_notification_title" msgid="5734005953288045806">"កំពុងរៀបចំ <xliff:g id="NAME">%s</xliff:g>"</string>
    +     <string name="ext_media_checking_notification_message" msgid="4747432538578886744">"កំពុងពិនិត្យរកកំហុស"</string>
    +     <string name="ext_media_new_notification_message" msgid="7589986898808506239">"បានរកឃើញ <xliff:g id="NAME">%s</xliff:g> ថ្មី"</string>
    +@@ -1234,8 +1245,9 @@
    +     <string name="vpn_text_long" msgid="4907843483284977618">"បាន​ភ្ជាប់​ទៅ <xliff:g id="SESSION">%s</xliff:g> ។ ប៉ះ ដើម្បី​គ្រប់គ្រង​បណ្ដាញ។"</string>
    +     <string name="vpn_lockdown_connecting" msgid="6443438964440960745">"បើក​ការ​តភ្ជាប់ VPN ជា​និច្ច..។"</string>
    +     <string name="vpn_lockdown_connected" msgid="8202679674819213931">"ភ្ជាប់ VPN ជា​និច្ច"</string>
    ++    <string name="vpn_lockdown_disconnected" msgid="4532298952570796327">"បានផ្តាច់ VPN ដែលបើកជានិច្ច"</string>
    +     <string name="vpn_lockdown_error" msgid="6009249814034708175">"បើក​កំហុស VPN ជា​និច្ច"</string>
    +-    <string name="vpn_lockdown_config" msgid="4655589351146766608">"ប៉ះដើម្បីកំណត់រចនាសម្ព័ន្ធ"</string>
    ++    <string name="vpn_lockdown_config" msgid="5099330695245008680">"ប៉ះដើម្បីដំឡើង"</string>
    +     <string name="upload_file" msgid="2897957172366730416">"ជ្រើស​​ឯកសារ"</string>
    +     <string name="no_file_chosen" msgid="6363648562170759465">"គ្មាន​ឯកសារ​បាន​ជ្រើស"</string>
    +     <string name="reset" msgid="2448168080964209908">"កំណត់​ឡើងវិញ"</string>
    +@@ -1319,7 +1331,7 @@
    +     <string name="storage_usb_drive_label" msgid="4501418548927759953">"ឧបករណ៍ផ្ទុក USB <xliff:g id="MANUFACTURER">%s</xliff:g>"</string>
    +     <string name="storage_usb" msgid="3017954059538517278">"ឧបករណ៍​ផ្ទុក​យូអេសប៊ី"</string>
    +     <string name="extract_edit_menu_button" msgid="8940478730496610137">"កែសម្រួល​"</string>
    +-    <string name="data_usage_warning_title" msgid="1955638862122232342">"ការព្រមាន​ប្រើ​ទិន្នន័យ"</string>
    ++    <string name="data_usage_warning_title" msgid="3620440638180218181">"ការព្រមានអំពីការប្រើទិន្នន័យ"</string>
    +     <string name="data_usage_warning_body" msgid="6660692274311972007">"ប៉ះដើម្បីមើលការប្រើប្រាស់ និងការកំណត់"</string>
    +     <string name="data_usage_3g_limit_title" msgid="4361523876818447683">"បាន​ដល់​ដែន​កំណត់​ទិន្នន័យ 2G-3G"</string>
    +     <string name="data_usage_4g_limit_title" msgid="4609566827219442376">"បាន​ដល់​ដែន​កំណត់​ទិន្នន័យ 4G"</string>
    +@@ -1638,6 +1650,7 @@
    +     <string name="search_language_hint" msgid="7042102592055108574">"វាយបញ្ចូលឈ្មោះភាសា"</string>
    +     <string name="language_picker_section_suggested" msgid="8414489646861640885">"បាន​ស្នើ"</string>
    +     <string name="language_picker_section_all" msgid="3097279199511617537">"ភាសាទាំងអស់"</string>
    ++    <string name="region_picker_section_all" msgid="8966316787153001779">"តំបន់ទាំងអស់"</string>
    +     <string name="locale_search_menu" msgid="2560710726687249178">"ស្វែងរក"</string>
    +     <string name="work_mode_off_title" msgid="8954725060677558855">"របៀបការងារបានបិទ"</string>
    +     <string name="work_mode_off_message" msgid="3286169091278094476">"អនុញ្ញាតឲ្យប្រវត្តិរូបការងារដំណើរការ ដោយរាប់បញ្ចូលទាំងកម្មវិធី ការធ្វើសមកាលកម្មផ្ទៃខាងក្រោយ និងលក្ខណៈពិសេសដែលពាក់ព័ន្ធ។"</string>
    +diff --git a/core/res/res/values-kn-rIN/strings.xml b/core/res/res/values-kn-rIN/strings.xml
    +index 770af19..7cb97a7 100644
    +--- a/core/res/res/values-kn-rIN/strings.xml
    ++++ b/core/res/res/values-kn-rIN/strings.xml
    +@@ -172,7 +172,7 @@
    +       <item quantity="one">ಪ್ರಮಾಣಪತ್ರ ಅಂಗೀಕಾರಗಳನ್ನು ಸ್ಥಾಪಿಸಲಾಗಿದೆ</item>
    +       <item quantity="other">ಪ್ರಮಾಣಪತ್ರ ಅಂಗೀಕಾರಗಳನ್ನು ಸ್ಥಾಪಿಸಲಾಗಿದೆ</item>
    +     </plurals>
    +-    <string name="ssl_ca_cert_noti_by_unknown" msgid="4475437862189850602">"ಅಜ್ಞಾತ ಥರ್ಡ್ ಪಾರ್ಟಿಯ ಪ್ರಕಾರ"</string>
    ++    <string name="ssl_ca_cert_noti_by_unknown" msgid="4475437862189850602">"ಅಪರಿಚಿತ ಥರ್ಡ್ ಪಾರ್ಟಿಯ ಪ್ರಕಾರ"</string>
    +     <string name="ssl_ca_cert_noti_by_administrator" msgid="550758088185764312">"ನಿಮ್ಮ ಕೆಲಸದ ಪ್ರೊಫೈಲ್ ನಿರ್ವಾಹಕರಿಂದ"</string>
    +     <string name="ssl_ca_cert_noti_managed" msgid="4030263497686867141">"<xliff:g id="MANAGING_DOMAIN">%s</xliff:g> ಪ್ರಕಾರ"</string>
    +     <string name="work_profile_deleted" msgid="5005572078641980632">"ಕೆಲಸದ ಪ್ರೊಫೈಲ್ ಅನ್ನು ಅಳಿಸಲಾಗಿದೆ"</string>
    +@@ -214,6 +214,7 @@
    +     <string name="global_actions" product="default" msgid="2406416831541615258">"ಫೋನ್ ಆಯ್ಕೆಗಳು"</string>
    +     <string name="global_action_lock" msgid="2844945191792119712">"ಸ್ಕ್ರೀನ್ ಲಾಕ್"</string>
    +     <string name="global_action_power_off" msgid="4471879440839879722">"ಪವರ್ ಆಫ್ ಮಾಡು"</string>
    ++    <string name="global_action_emergency" msgid="7112311161137421166">"ತುರ್ತು"</string>
    +     <string name="global_action_bug_report" msgid="7934010578922304799">"ದೋಷದ ವರದಿ"</string>
    +     <string name="bugreport_title" msgid="2667494803742548533">"ದೋಷ ವರದಿ ರಚಿಸಿ"</string>
    +     <string name="bugreport_message" msgid="398447048750350456">"ನಿಮ್ಮ ಸಾಧನದ ಪ್ರಸ್ತುತ ಸ್ಥಿತಿಯ ಕುರಿತು ಮಾಹಿತಿಯನ್ನು ಸಂಗ್ರಹಿಸಿಕೊಳ್ಳುವುದರ ಜೊತೆ ಇ-ಮೇಲ್ ರೂಪದಲ್ಲಿ ನಿಮಗೆ ರವಾನಿಸುತ್ತದೆ. ಇದು ದೋಷ ವರದಿಯನ್ನು ಪ್ರಾರಂಭಿಸಿದ ಸಮಯದಿಂದ ಅದನ್ನು ಕಳುಹಿಸುವವರೆಗೆ ಸ್ವಲ್ಪ ಸಮಯವನ್ನು ತೆಗೆದುಕೊಳ್ಳುತ್ತದೆ; ದಯವಿಟ್ಟು ತಾಳ್ಮೆಯಿಂದಿರಿ."</string>
    +@@ -814,9 +815,9 @@
    +     <string name="menu_space_shortcut_label" msgid="2410328639272162537">"space"</string>
    +     <string name="menu_enter_shortcut_label" msgid="2743362785111309668">"enter"</string>
    +     <string name="menu_delete_shortcut_label" msgid="3658178007202748164">"ಅಳಿಸು"</string>
    +-    <string name="search_go" msgid="8298016669822141719">"ಹುಡುಕು"</string>
    ++    <string name="search_go" msgid="8298016669822141719">"ಹುಡುಕಿ"</string>
    +     <string name="search_hint" msgid="1733947260773056054">"ಹುಡುಕಿ…"</string>
    +-    <string name="searchview_description_search" msgid="6749826639098512120">"ಹುಡುಕು"</string>
    ++    <string name="searchview_description_search" msgid="6749826639098512120">"ಹುಡುಕಿ"</string>
    +     <string name="searchview_description_query" msgid="5911778593125355124">"ಪ್ರಶ್ನೆಯನ್ನು ಹುಡುಕಿ"</string>
    +     <string name="searchview_description_clear" msgid="1330281990951833033">"ಪ್ರಶ್ನೆಯನ್ನು ತೆರವುಗೊಳಿಸು"</string>
    +     <string name="searchview_description_submit" msgid="2688450133297983542">"ಪ್ರಶ್ನೆಯನ್ನು ಸಲ್ಲಿಸು"</string>
    +@@ -979,8 +980,8 @@
    +     <string name="whichSendToApplication" msgid="8272422260066642057">"ಇದನ್ನು ಬಳಸಿಕೊಂಡು ಕಳುಹಿಸಿ"</string>
    +     <string name="whichSendToApplicationNamed" msgid="7768387871529295325">"%1$s ಬಳಸಿಕೊಂಡು ಕಳುಹಿಸಿ"</string>
    +     <string name="whichSendToApplicationLabel" msgid="8878962419005813500">"ಕಳುಹಿಸು"</string>
    +-    <string name="whichHomeApplication" msgid="4307587691506919691">"ಹೋಮ್‌ ಅಪ್ಲಿಕೇಶನ್‌  ಆಯ್ಕೆಮಾಡಿ"</string>
    +-    <string name="whichHomeApplicationNamed" msgid="4493438593214760979">"ಹೋಮ್‌ ಎಂಬಂತೆ %1$s ಅನ್ನು ಬಳಸಿ"</string>
    ++    <string name="whichHomeApplication" msgid="4307587691506919691">"ಮುಖಪುಟ‌ ಅಪ್ಲಿಕೇಶನ್‌  ಆಯ್ಕೆಮಾಡಿ"</string>
    ++    <string name="whichHomeApplicationNamed" msgid="4493438593214760979">"ಮುಖಪುಟ‌ ಎಂಬಂತೆ %1$s ಅನ್ನು ಬಳಸಿ"</string>
    +     <string name="whichHomeApplicationLabel" msgid="809529747002918649">"ಚಿತ್ರ ಕ್ಯಾಪ್ಚರ್ ಮಾಡಿ"</string>
    +     <string name="whichImageCaptureApplication" msgid="3680261417470652882">"ಇದರ ಜೊತೆಗೆ ಚಿತ್ರ ಕ್ಯಾಪ್ಚರ್ ಮಾಡಿ"</string>
    +     <string name="whichImageCaptureApplicationNamed" msgid="8619384150737825003">"%1$s ಜೊತೆ ಚಿತ್ರ ಕ್ಯಾಪ್ಚರ್ ಮಾಡಿ"</string>
    +@@ -1061,7 +1062,7 @@
    +     <string name="ringtone_default_with_actual" msgid="8129563480895990372">"ಡಿಫಾಲ್ಟ್ ರಿಂಗ್‌ಟೋನ್ (<xliff:g id="ACTUAL_RINGTONE">%1$s</xliff:g>)"</string>
    +     <string name="ringtone_silent" msgid="7937634392408977062">"ಯಾವುದೂ ಇಲ್ಲ"</string>
    +     <string name="ringtone_picker_title" msgid="3515143939175119094">"ರಿಂಗ್‌ಟೋನ್‌ಗಳು"</string>
    +-    <string name="ringtone_unknown" msgid="5477919988701784788">"ಅಜ್ಞಾತ ರಿಂಗ್‌ಟೋನ್"</string>
    ++    <string name="ringtone_unknown" msgid="5477919988701784788">"ಅಪರಿಚಿತ ರಿಂಗ್‌ಟೋನ್"</string>
    +     <plurals name="wifi_available" formatted="false" msgid="7900333017752027322">
    +       <item quantity="one">ವೈ-ಫೈ ನೆಟ್‌ವರ್ಕ್‌ಗಳು ಲಭ್ಯವಿವೆ</item>
    +       <item quantity="other">ವೈ-ಫೈ ನೆಟ್‌ವರ್ಕ್‌ಗಳು ಲಭ್ಯವಿವೆ</item>
    +@@ -1076,6 +1077,17 @@
    +     <skip />
    +     <string name="wifi_no_internet" msgid="8451173622563841546">"ವೈ-ಫೈ ಯಾವುದೇ ಇಂಟರ್ನೆಟ್ ಪ್ರವೇಶವನ್ನು ಹೊಂದಿಲ್ಲ"</string>
    +     <string name="wifi_no_internet_detailed" msgid="8083079241212301741">"ಆಯ್ಕೆಗಳಿಗೆ ಟ್ಯಾಪ್ ಮಾಡಿ"</string>
    ++    <string name="network_switch_metered" msgid="4671730921726992671">"<xliff:g id="NETWORK_TYPE">%1$s</xliff:g> ಗೆ ಬದಲಾಯಿಸಲಾಗಿದೆ"</string>
    ++    <string name="network_switch_metered_detail" msgid="5325661434777870353">"<xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> ಇಂಟರ್ನೆಟ್ ಪ್ರವೇಶ ಹೊಂದಿಲ್ಲದಿರುವಾಗ, ಸಾಧನವು <xliff:g id="NEW_NETWORK">%1$s</xliff:g> ಬಳಸುತ್ತದೆ. ಶುಲ್ಕಗಳು ಅನ್ವಯವಾಗಬಹುದು."</string>
    ++    <string name="network_switch_metered_toast" msgid="5779283181685974304">"<xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> ರಿಂದ <xliff:g id="NEW_NETWORK">%2$s</xliff:g> ಗೆ ಬದಲಾಯಿಸಲಾಗಿದೆ"</string>
    ++  <string-array name="network_switch_type_name">
    ++    <item msgid="2952042958050315394">"ಸೆಲ್ಯುಲರ್ ಡೇಟಾ"</item>
    ++    <item msgid="75483255295529161">"ವೈ-ಫೈ"</item>
    ++    <item msgid="6862614801537202646">"ಬ್ಲೂಟೂತ್‌"</item>
    ++    <item msgid="5447331121797802871">"ಇಥರ್ನೆಟ್"</item>
    ++    <item msgid="8257233890381651999">"VPN"</item>
    ++  </string-array>
    ++    <string name="network_switch_type_name_unknown" msgid="4552612897806660656">"ಅಪರಿಚಿತ ನೆಟ್‌ವರ್ಕ್ ಪ್ರಕಾರ"</string>
    +     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"ವೈ-ಫೈ ಗೆ ಸಂಪರ್ಕಿಸಲು ಸಾಧ್ಯವಾಗುತ್ತಿಲ್ಲ"</string>
    +     <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" ಕಳಪೆ ಇಂಟರ್ನೆಟ್ ಸಂಪರ್ಕವನ್ನು ಹೊಂದಿದೆ."</string>
    +     <string name="wifi_connect_alert_title" msgid="8455846016001810172">"ಸಂಪರ್ಕವನ್ನು ಅನುಮತಿಸುವುದೇ?"</string>
    +@@ -1153,7 +1165,6 @@
    +     <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"ಭಾಷೆ ಮತ್ತು ವಿನ್ಯಾಸವನ್ನು ಆಯ್ಕೆ ಮಾಡಲು ಟ್ಯಾಪ್ ಮಾಡಿ"</string>
    +     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
    +     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
    +-    <string name="candidates_style" msgid="4333913089637062257"><u>"ಅಭ್ಯರ್ಥಿಗಳು"</u></string>
    +     <string name="ext_media_checking_notification_title" msgid="5734005953288045806">"<xliff:g id="NAME">%s</xliff:g> ಅನ್ನು ಸಿದ್ಧಪಡಿಸಲಾಗುತ್ತಿದೆ"</string>
    +     <string name="ext_media_checking_notification_message" msgid="4747432538578886744">"ದೋಷಗಳನ್ನು ಪರಿಶೀಲಿಸಲಾಗುತ್ತಿದೆ"</string>
    +     <string name="ext_media_new_notification_message" msgid="7589986898808506239">"ಹೊಸ <xliff:g id="NAME">%s</xliff:g> ಪತ್ತೆಯಾಗಿದೆ"</string>
    +@@ -1200,7 +1211,7 @@
    +     <string name="tutorial_double_tap_to_zoom_message_short" msgid="1311810005957319690">"ಝೂಮ್‌ ನಿಯಂತ್ರಿಸಲು ಎರಡು ಬಾರಿ ಟ್ಯಾಪ್ ಮಾಡಿ"</string>
    +     <string name="gadget_host_error_inflating" msgid="4882004314906466162">"ವಿಜೆಟ್ ಸೇರಿಸಲು ಸಾಧ್ಯವಾಗುತ್ತಿಲ್ಲ."</string>
    +     <string name="ime_action_go" msgid="8320845651737369027">"ಹೋಗು"</string>
    +-    <string name="ime_action_search" msgid="658110271822807811">"ಹುಡುಕು"</string>
    ++    <string name="ime_action_search" msgid="658110271822807811">"ಹುಡುಕಿ"</string>
    +     <string name="ime_action_send" msgid="2316166556349314424">"ಕಳುಹಿಸು"</string>
    +     <string name="ime_action_next" msgid="3138843904009813834">"ಮುಂದೆ"</string>
    +     <string name="ime_action_done" msgid="8971516117910934605">"ಮುಗಿದಿದೆ"</string>
    +@@ -1232,8 +1243,9 @@
    +     <string name="vpn_text_long" msgid="4907843483284977618">"<xliff:g id="SESSION">%s</xliff:g> ಗೆ ಸಂಪರ್ಕಗೊಂಡಿದೆ. ನೆಟ್‍ವರ್ಕ್ ನಿರ್ವಹಿಸಲು ಟ್ಯಾಪ್ ಮಾಡಿ."</string>
    +     <string name="vpn_lockdown_connecting" msgid="6443438964440960745">"ಯಾವಾಗಲೂ-ಆನ್ VPN ಸಂಪರ್ಕಗೊಳ್ಳುತ್ತಿದೆ…"</string>
    +     <string name="vpn_lockdown_connected" msgid="8202679674819213931">"ಯಾವಾಗಲೂ-ಆನ್ VPN ಸಂಪರ್ಕಗೊಂಡಿದೆ"</string>
    ++    <string name="vpn_lockdown_disconnected" msgid="4532298952570796327">"ಯಾವಾಗಲೂ-ಆನ್ VPN ಸಂಪರ್ಕ ಕಡಿತಗೊಳಿಸಲಾಗಿದೆ"</string>
    +     <string name="vpn_lockdown_error" msgid="6009249814034708175">"ಯಾವಾಗಲೂ-ಆನ್ VPN ದೋಷ"</string>
    +-    <string name="vpn_lockdown_config" msgid="4655589351146766608">"ಕಾನ್ಫಿಗರ್ ಮಾಡಲು ಟ್ಯಾಪ್‌ ಮಾಡಿ"</string>
    ++    <string name="vpn_lockdown_config" msgid="5099330695245008680">"ಹೊಂದಿಸಲು ಟ್ಯಾಪ್ ಮಾಡಿ"</string>
    +     <string name="upload_file" msgid="2897957172366730416">"ಫೈಲ್ ಆಯ್ಕೆಮಾಡು"</string>
    +     <string name="no_file_chosen" msgid="6363648562170759465">"ಯಾವುದೇ ಫೈಲ್ ಆಯ್ಕೆ ಮಾಡಿಲ್ಲ"</string>
    +     <string name="reset" msgid="2448168080964209908">"ಮರುಹೊಂದಿಸು"</string>
    +@@ -1257,8 +1269,8 @@
    +     <string name="share" msgid="1778686618230011964">"ಹಂಚು"</string>
    +     <string name="find" msgid="4808270900322985960">"ಹುಡುಕಿ"</string>
    +     <string name="websearch" msgid="4337157977400211589">"ವೆಬ್ ಹುಡುಕಾಟ"</string>
    +-    <string name="find_next" msgid="5742124618942193978">"ಮುಂದಿನದನ್ನು ಹುಡುಕು"</string>
    +-    <string name="find_previous" msgid="2196723669388360506">"ಹಿಂದಿನದನ್ನು ಹುಡುಕು"</string>
    ++    <string name="find_next" msgid="5742124618942193978">"ಮುಂದಿನದನ್ನು ಹುಡುಕಿ"</string>
    ++    <string name="find_previous" msgid="2196723669388360506">"ಹಿಂದಿನದನ್ನು ಹುಡುಕಿ"</string>
    +     <string name="gpsNotifTicker" msgid="5622683912616496172">"<xliff:g id="NAME">%s</xliff:g> ಅವರಿಂದ ಸ್ಥಾನ ವಿನಂತಿ"</string>
    +     <string name="gpsNotifTitle" msgid="5446858717157416839">"ಸ್ಥಾನ ವಿನಂತಿ"</string>
    +     <string name="gpsNotifMessage" msgid="1374718023224000702">"<xliff:g id="NAME">%1$s</xliff:g> (<xliff:g id="SERVICE">%2$s</xliff:g>) ಅವರಿಂದ ವಿನಂತಿಸಲಾಗಿದೆ"</string>
    +@@ -1317,7 +1329,7 @@
    +     <string name="storage_usb_drive_label" msgid="4501418548927759953">"<xliff:g id="MANUFACTURER">%s</xliff:g> USB ಡ್ರೈವ್"</string>
    +     <string name="storage_usb" msgid="3017954059538517278">"USB ಸಂಗ್ರಹಣೆ"</string>
    +     <string name="extract_edit_menu_button" msgid="8940478730496610137">"ಎಡಿಟ್"</string>
    +-    <string name="data_usage_warning_title" msgid="1955638862122232342">"ಡೇಟಾ ಬಳಕೆಯ ಎಚ್ಚರಿಕೆ"</string>
    ++    <string name="data_usage_warning_title" msgid="3620440638180218181">"ಡೇಟಾ ಬಳಕೆ ಎಚ್ಚರಿಕೆ"</string>
    +     <string name="data_usage_warning_body" msgid="6660692274311972007">"ಬಳಕೆ ಮತ್ತು ಸೆಟ್ಟಿಂಗ್‍ಗಳನ್ನು ವೀಕ್ಷಿಸಲು ಟ್ಯಾಪ್ ಮಾಡಿ."</string>
    +     <string name="data_usage_3g_limit_title" msgid="4361523876818447683">"2G-3G ಡೇಟಾ ಮೀತಿಯನ್ನು ತಲುಪಿದೆ"</string>
    +     <string name="data_usage_4g_limit_title" msgid="4609566827219442376">"4G ಡೇಟಾ ಮೀತಿಯನ್ನು ತಲುಪಿದೆ"</string>
    +@@ -1512,11 +1524,11 @@
    +     <string name="mediasize_japanese_kahu" msgid="6872696027560065173">"Kahu"</string>
    +     <string name="mediasize_japanese_kaku2" msgid="2359077233775455405">"Kaku2"</string>
    +     <string name="mediasize_japanese_you4" msgid="2091777168747058008">"You4"</string>
    +-    <string name="mediasize_unknown_portrait" msgid="3088043641616409762">"ಅಜ್ಞಾತ ಪೋಟ್ರೇಟ್"</string>
    +-    <string name="mediasize_unknown_landscape" msgid="4876995327029361552">"ಅಜ್ಞಾತ ಲ್ಯಾಂಡ್‌ಸ್ಕೇಪ್"</string>
    ++    <string name="mediasize_unknown_portrait" msgid="3088043641616409762">"ಅಪರಿಚಿತ ಪೋಟ್ರೇಟ್"</string>
    ++    <string name="mediasize_unknown_landscape" msgid="4876995327029361552">"ಅಪರಿಚಿತ ಲ್ಯಾಂಡ್‌ಸ್ಕೇಪ್"</string>
    +     <string name="write_fail_reason_cancelled" msgid="7091258378121627624">"ರದ್ದುಮಾಡಲಾಗಿದೆ"</string>
    +     <string name="write_fail_reason_cannot_write" msgid="8132505417935337724">"ವಿಷಯವನ್ನು ಬರೆಯುವಲ್ಲಿ ದೋಷ ಎದುರಾಗಿದೆ"</string>
    +-    <string name="reason_unknown" msgid="6048913880184628119">"ಅಜ್ಞಾತ"</string>
    ++    <string name="reason_unknown" msgid="6048913880184628119">"ಅಪರಿಚಿತ"</string>
    +     <string name="reason_service_unavailable" msgid="7824008732243903268">"ಮುದ್ರಣ ಸೇವೆ ಸಕ್ರಿಯಗೊಂಡಿಲ್ಲ"</string>
    +     <string name="print_service_installed_title" msgid="2246317169444081628">"<xliff:g id="NAME">%s</xliff:g> ಸೇವೆಯನ್ನು ಸ್ಥಾಪಿಸಲಾಗಿದೆ"</string>
    +     <string name="print_service_installed_message" msgid="5897362931070459152">"ಸಕ್ರಿಯಗೊಳಿಸಲು ಟ್ಯಾಪ್ ಮಾಡಿ"</string>
    +@@ -1636,7 +1648,8 @@
    +     <string name="search_language_hint" msgid="7042102592055108574">"ಭಾಷೆ ಹೆಸರನ್ನು ಟೈಪ್ ಮಾಡಿ"</string>
    +     <string name="language_picker_section_suggested" msgid="8414489646861640885">"ಸೂಚಿತ ಭಾಷೆ"</string>
    +     <string name="language_picker_section_all" msgid="3097279199511617537">"ಎಲ್ಲಾ ಭಾಷೆಗಳು"</string>
    +-    <string name="locale_search_menu" msgid="2560710726687249178">"ಹುಡುಕು"</string>
    ++    <string name="region_picker_section_all" msgid="8966316787153001779">"ಎಲ್ಲಾ ಪ್ರದೇಶಗಳು"</string>
    ++    <string name="locale_search_menu" msgid="2560710726687249178">"ಹುಡುಕಿ"</string>
    +     <string name="work_mode_off_title" msgid="8954725060677558855">"ಕೆಲಸದ ಮೋಡ್ ಆಫ್ ಆಗಿದೆ"</string>
    +     <string name="work_mode_off_message" msgid="3286169091278094476">"ಅಪ್ಲಿಕೇಶನ್‌ಗಳು, ಹಿನ್ನೆಲೆ ಸಿಂಕ್ ಮತ್ತು ಇತರ ಸಂಬಂಧಿತ ವೈಶಿಷ್ಟ್ಯಗಳು ಸೇರಿದಂತೆ ನಿಮ್ಮ ಕೆಲಸದ ಪ್ರೊಫೈಲ್‌‌ ಕಾರ್ಯನಿರ್ವಹಿಸಲು ಅನುಮತಿಸಿ."</string>
    +     <string name="work_mode_turn_on" msgid="2062544985670564875">"ಆನ್ ಮಾಡು"</string>
    +diff --git a/core/res/res/values-ko/strings.xml b/core/res/res/values-ko/strings.xml
    +index 5b446b4..b23a966 100644
    +--- a/core/res/res/values-ko/strings.xml
    ++++ b/core/res/res/values-ko/strings.xml
    +@@ -214,6 +214,7 @@
    +     <string name="global_actions" product="default" msgid="2406416831541615258">"휴대전화 옵션"</string>
    +     <string name="global_action_lock" msgid="2844945191792119712">"화면 잠금"</string>
    +     <string name="global_action_power_off" msgid="4471879440839879722">"종료"</string>
    ++    <string name="global_action_emergency" msgid="7112311161137421166">"긴급 전화"</string>
    +     <string name="global_action_bug_report" msgid="7934010578922304799">"버그 신고"</string>
    +     <string name="bugreport_title" msgid="2667494803742548533">"버그 신고"</string>
    +     <string name="bugreport_message" msgid="398447048750350456">"현재 기기 상태에 대한 정보를 수집하여 이메일 메시지로 전송합니다. 버그 신고를 시작하여 전송할 준비가 되려면 약간 시간이 걸립니다."</string>
    +@@ -243,7 +244,7 @@
    +     <string name="user_owner_label" msgid="1119010402169916617">"개인으로 전환"</string>
    +     <string name="managed_profile_label" msgid="5289992269827577857">"직장으로 전환"</string>
    +     <string name="permgrouplab_contacts" msgid="3657758145679177612">"주소록"</string>
    +-    <string name="permgroupdesc_contacts" msgid="6951499528303668046">"주소록에 접근할 수 있도록"</string>
    ++    <string name="permgroupdesc_contacts" msgid="6951499528303668046">"주소록에 액세스"</string>
    +     <string name="permgrouplab_location" msgid="7275582855722310164">"위치"</string>
    +     <string name="permgroupdesc_location" msgid="1346617465127855033">"이 기기의 위치정보에 액세스"</string>
    +     <string name="permgrouplab_calendar" msgid="5863508437783683902">"캘린더"</string>
    +@@ -259,7 +260,7 @@
    +     <string name="permgrouplab_phone" msgid="5229115638567440675">"전화"</string>
    +     <string name="permgroupdesc_phone" msgid="6234224354060641055">"통화 상태를 관리하거나 전화를 걸 수 있도록"</string>
    +     <string name="permgrouplab_sensors" msgid="416037179223226722">"신체 센서"</string>
    +-    <string name="permgroupdesc_sensors" msgid="7147968539346634043">"생체 신호에 관한 센서 데이터에 접근할 수 있도록"</string>
    ++    <string name="permgroupdesc_sensors" msgid="7147968539346634043">"생체 신호에 관한 센서 데이터에 액세스"</string>
    +     <string name="capability_title_canRetrieveWindowContent" msgid="3901717936930170320">"창 콘텐츠 가져오기"</string>
    +     <string name="capability_desc_canRetrieveWindowContent" msgid="3772225008605310672">"상호작용 중인 창의 콘텐츠를 검사합니다."</string>
    +     <string name="capability_title_canRequestTouchExploration" msgid="3108723364676667320">"터치하여 탐색 사용"</string>
    +@@ -1076,6 +1077,17 @@
    +     <skip />
    +     <string name="wifi_no_internet" msgid="8451173622563841546">"Wi-Fi가 인터넷에 연결되어 있지 않습니다."</string>
    +     <string name="wifi_no_internet_detailed" msgid="8083079241212301741">"탭하여 옵션 보기"</string>
    ++    <string name="network_switch_metered" msgid="4671730921726992671">"<xliff:g id="NETWORK_TYPE">%1$s</xliff:g>(으)로 전환"</string>
    ++    <string name="network_switch_metered_detail" msgid="5325661434777870353">"<xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g>이(가) 인터넷에 연결되지 않는 경우 기기에서 <xliff:g id="NEW_NETWORK">%1$s</xliff:g>을(를) 사용합니다. 요금이 부과될 수 있습니다."</string>
    ++    <string name="network_switch_metered_toast" msgid="5779283181685974304">"<xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g>에서 <xliff:g id="NEW_NETWORK">%2$s</xliff:g>(으)로 전환"</string>
    ++  <string-array name="network_switch_type_name">
    ++    <item msgid="2952042958050315394">"모바일 데이터"</item>
    ++    <item msgid="75483255295529161">"Wi-Fi"</item>
    ++    <item msgid="6862614801537202646">"블루투스"</item>
    ++    <item msgid="5447331121797802871">"이더넷"</item>
    ++    <item msgid="8257233890381651999">"VPN"</item>
    ++  </string-array>
    ++    <string name="network_switch_type_name_unknown" msgid="4552612897806660656">"알 수 없는 네트워크 유형"</string>
    +     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Wi-Fi에 연결할 수 없습니다"</string>
    +     <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" 인터넷 연결 상태가 좋지 않습니다."</string>
    +     <string name="wifi_connect_alert_title" msgid="8455846016001810172">"연결을 허용하시겠습니까?"</string>
    +@@ -1153,7 +1165,6 @@
    +     <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"탭하여 언어와 레이아웃을 선택하세요."</string>
    +     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
    +     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
    +-    <string name="candidates_style" msgid="4333913089637062257"><u>"가능한 원인"</u></string>
    +     <string name="ext_media_checking_notification_title" msgid="5734005953288045806">"<xliff:g id="NAME">%s</xliff:g> 준비 중"</string>
    +     <string name="ext_media_checking_notification_message" msgid="4747432538578886744">"오류 확인 중"</string>
    +     <string name="ext_media_new_notification_message" msgid="7589986898808506239">"새로운 <xliff:g id="NAME">%s</xliff:g> 감지됨"</string>
    +@@ -1232,8 +1243,9 @@
    +     <string name="vpn_text_long" msgid="4907843483284977618">"<xliff:g id="SESSION">%s</xliff:g>에 연결되어 있습니다. 네트워크를 관리하려면 누르세요."</string>
    +     <string name="vpn_lockdown_connecting" msgid="6443438964440960745">"연결 유지 VPN에 연결하는 중…"</string>
    +     <string name="vpn_lockdown_connected" msgid="8202679674819213931">"연결 유지 VPN에 연결됨"</string>
    ++    <string name="vpn_lockdown_disconnected" msgid="4532298952570796327">"연결 유지 VPN 연결 해제됨"</string>
    +     <string name="vpn_lockdown_error" msgid="6009249814034708175">"연결 유지 VPN 오류"</string>
    +-    <string name="vpn_lockdown_config" msgid="4655589351146766608">"설정하려면 탭하세요."</string>
    ++    <string name="vpn_lockdown_config" msgid="5099330695245008680">"탭하여 설정"</string>
    +     <string name="upload_file" msgid="2897957172366730416">"파일 선택"</string>
    +     <string name="no_file_chosen" msgid="6363648562170759465">"파일을 선택하지 않았습니다."</string>
    +     <string name="reset" msgid="2448168080964209908">"초기화"</string>
    +@@ -1310,14 +1322,14 @@
    +     <string name="action_menu_overflow_description" msgid="2295659037509008453">"옵션 더보기"</string>
    +     <string name="action_bar_home_description_format" msgid="7965984360903693903">"%1$s, %2$s"</string>
    +     <string name="action_bar_home_subtitle_description_format" msgid="6985546530471780727">"%1$s, %2$s, %3$s"</string>
    +-    <string name="storage_internal" msgid="3570990907910199483">"내부 공유 저장공간"</string>
    ++    <string name="storage_internal" msgid="3570990907910199483">"내부 공유 저장용량"</string>
    +     <string name="storage_sd_card" msgid="3282948861378286745">"SD 카드"</string>
    +     <string name="storage_sd_card_label" msgid="6347111320774379257">"<xliff:g id="MANUFACTURER">%s</xliff:g> SD 카드"</string>
    +     <string name="storage_usb_drive" msgid="6261899683292244209">"USB 드라이브"</string>
    +     <string name="storage_usb_drive_label" msgid="4501418548927759953">"<xliff:g id="MANUFACTURER">%s</xliff:g> USB 드라이브"</string>
    +     <string name="storage_usb" msgid="3017954059538517278">"USB 저장소"</string>
    +     <string name="extract_edit_menu_button" msgid="8940478730496610137">"수정"</string>
    +-    <string name="data_usage_warning_title" msgid="1955638862122232342">"데이터 사용 경고"</string>
    ++    <string name="data_usage_warning_title" msgid="3620440638180218181">"데이터 사용 알림"</string>
    +     <string name="data_usage_warning_body" msgid="6660692274311972007">"사용량 및 설정을 보려면 탭하세요."</string>
    +     <string name="data_usage_3g_limit_title" msgid="4361523876818447683">"2G-3G 데이터 한도에 도달함"</string>
    +     <string name="data_usage_4g_limit_title" msgid="4609566827219442376">"4G 데이터 한도에 도달함"</string>
    +@@ -1636,6 +1648,7 @@
    +     <string name="search_language_hint" msgid="7042102592055108574">"언어 이름 입력"</string>
    +     <string name="language_picker_section_suggested" msgid="8414489646861640885">"추천"</string>
    +     <string name="language_picker_section_all" msgid="3097279199511617537">"모든 언어"</string>
    ++    <string name="region_picker_section_all" msgid="8966316787153001779">"모든 지역"</string>
    +     <string name="locale_search_menu" msgid="2560710726687249178">"검색"</string>
    +     <string name="work_mode_off_title" msgid="8954725060677558855">"직장 모드가 사용 중지됨"</string>
    +     <string name="work_mode_off_message" msgid="3286169091278094476">"앱, 백그라운드 동기화 및 관련 기능을 포함한 직장 프로필이 작동하도록 허용"</string>
    +diff --git a/core/res/res/values-ky-rKG/strings.xml b/core/res/res/values-ky-rKG/strings.xml
    +index 0f82dcb..4f48a94 100644
    +--- a/core/res/res/values-ky-rKG/strings.xml
    ++++ b/core/res/res/values-ky-rKG/strings.xml
    +@@ -214,6 +214,7 @@
    +     <string name="global_actions" product="default" msgid="2406416831541615258">"Телефон мүмкүнчүлүктөрү"</string>
    +     <string name="global_action_lock" msgid="2844945191792119712">"Экран кулпусу"</string>
    +     <string name="global_action_power_off" msgid="4471879440839879722">"Кубатын өчүрүү"</string>
    ++    <string name="global_action_emergency" msgid="7112311161137421166">"Тез жардам"</string>
    +     <string name="global_action_bug_report" msgid="7934010578922304799">"Ката тууралуу билдирүү"</string>
    +     <string name="bugreport_title" msgid="2667494803742548533">"Ката тууралуу билдирүү түзүү"</string>
    +     <string name="bugreport_message" msgid="398447048750350456">"Бул сиздин түзмөгүңүздүн учурдагы абалын эмейл билдирүүсү катары жөнөтүш максатында маалымат чогултат. Ката тууралуу билдирүү түзүлүп башталып, жөнөтүлгөнгө чейин бир аз убакыт керек болот; сураныч, бир аз күтө туруңуз."</string>
    +@@ -1076,6 +1077,17 @@
    +     <skip />
    +     <string name="wifi_no_internet" msgid="8451173622563841546">"Wi-Fi тармагы Интернетке туташпай турат"</string>
    +     <string name="wifi_no_internet_detailed" msgid="8083079241212301741">"Параметрлерди ачуу үчүн таптап коюңуз"</string>
    ++    <string name="network_switch_metered" msgid="4671730921726992671">"<xliff:g id="NETWORK_TYPE">%1$s</xliff:g> тармагына которуштурулду"</string>
    ++    <string name="network_switch_metered_detail" msgid="5325661434777870353">"<xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> тармагы Интернетке туташпай турганда, түзмөгүңүз <xliff:g id="NEW_NETWORK">%1$s</xliff:g> тармагын колдонот. Акы алынышы мүмкүн."</string>
    ++    <string name="network_switch_metered_toast" msgid="5779283181685974304">"<xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> дегенден <xliff:g id="NEW_NETWORK">%2$s</xliff:g> тармагына которуштурулду"</string>
    ++  <string-array name="network_switch_type_name">
    ++    <item msgid="2952042958050315394">"мобилдик дайындар"</item>
    ++    <item msgid="75483255295529161">"Wi-Fi"</item>
    ++    <item msgid="6862614801537202646">"Bluetooth"</item>
    ++    <item msgid="5447331121797802871">"Ethernet"</item>
    ++    <item msgid="8257233890381651999">"VPN"</item>
    ++  </string-array>
    ++    <string name="network_switch_type_name_unknown" msgid="4552612897806660656">"белгисиз тармак түрү"</string>
    +     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Wi-Fi менен туташуу түзүлбөдү"</string>
    +     <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" хотспотунун интернет байланышы начар."</string>
    +     <string name="wifi_connect_alert_title" msgid="8455846016001810172">"Туташууга уруксатпы?"</string>
    +@@ -1153,7 +1165,6 @@
    +     <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"Тил жана калып тандоо үчүн таптап коюңуз"</string>
    +     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
    +     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
    +-    <string name="candidates_style" msgid="4333913089637062257"><u>"талапкерлер"</u></string>
    +     <string name="ext_media_checking_notification_title" msgid="5734005953288045806">"<xliff:g id="NAME">%s</xliff:g> даярдалууда"</string>
    +     <string name="ext_media_checking_notification_message" msgid="4747432538578886744">"Каталар текшерилүүдө"</string>
    +     <string name="ext_media_new_notification_message" msgid="7589986898808506239">"Жаңы <xliff:g id="NAME">%s</xliff:g> аныкталды"</string>
    +@@ -1197,8 +1208,7 @@
    +     <string name="permdesc_readInstallSessions" msgid="2049771699626019849">"Колдонмого орнотуу сеанстарын окуу мүмкүнчүлүгүн берет. Ушуну менен, ал жигердүү топтом орнотууларынын чоо-жайын көрө алат."</string>
    +     <string name="permlab_requestInstallPackages" msgid="5782013576218172577">"орнотуу топтомдорун суроо"</string>
    +     <string name="permdesc_requestInstallPackages" msgid="5740101072486783082">"Колдонмо топтомдорду орнотууга уруксат сурай алат."</string>
    +-    <!-- no translation found for tutorial_double_tap_to_zoom_message_short (1311810005957319690) -->
    +-    <skip />
    ++    <string name="tutorial_double_tap_to_zoom_message_short" msgid="1311810005957319690">"Масштабдын параметрлерин өзгөртүү үчүн бул жерди эки жолу басыңыз."</string>
    +     <string name="gadget_host_error_inflating" msgid="4882004314906466162">"Виджетти кошуу мүмкүн болбоду."</string>
    +     <string name="ime_action_go" msgid="8320845651737369027">"Өтүү"</string>
    +     <string name="ime_action_search" msgid="658110271822807811">"Издөө"</string>
    +@@ -1229,14 +1239,13 @@
    +     <string name="notification_ranker_binding_label" msgid="774540592299064747">"Эскертмелердин маанилүүлүгүн баалоо кызматы"</string>
    +     <string name="vpn_title" msgid="19615213552042827">"VPN иштетилди"</string>
    +     <string name="vpn_title_long" msgid="6400714798049252294">"VPN <xliff:g id="APP">%s</xliff:g> аркылуу жандырылды"</string>
    +-    <!-- no translation found for vpn_text (1610714069627824309) -->
    +-    <skip />
    +-    <!-- no translation found for vpn_text_long (4907843483284977618) -->
    +-    <skip />
    ++    <string name="vpn_text" msgid="1610714069627824309">"Тармактын параметрлерин өзгөртүү үчүн бул жерди басыңыз."</string>
    ++    <string name="vpn_text_long" msgid="4907843483284977618">"<xliff:g id="SESSION">%s</xliff:g> сеансына туташуу ишке ашты. Желенин параметрлерин өзгөртүү үчүн бул жерди басыңыз."</string>
    +     <string name="vpn_lockdown_connecting" msgid="6443438964440960745">"Дайым иштеген VPN туташууда…"</string>
    +     <string name="vpn_lockdown_connected" msgid="8202679674819213931">"Дайым иштеген VPN туташтырылды"</string>
    ++    <string name="vpn_lockdown_disconnected" msgid="4532298952570796327">"Дайым иштеген VPN ажыратылды"</string>
    +     <string name="vpn_lockdown_error" msgid="6009249814034708175">"Дайым иштеген VPN\'де ката кетти"</string>
    +-    <string name="vpn_lockdown_config" msgid="4655589351146766608">"Конфигурациялоо үчүн таптап коюңуз"</string>
    ++    <string name="vpn_lockdown_config" msgid="5099330695245008680">"Жөндөө үчүн таптаңыз"</string>
    +     <string name="upload_file" msgid="2897957172366730416">"Файл тандоо"</string>
    +     <string name="no_file_chosen" msgid="6363648562170759465">"Эч файл тандалган жок"</string>
    +     <string name="reset" msgid="2448168080964209908">"Баштапкы абалга келтирүү"</string>
    +@@ -1320,7 +1329,7 @@
    +     <string name="storage_usb_drive_label" msgid="4501418548927759953">"<xliff:g id="MANUFACTURER">%s</xliff:g> USB түзмөгү"</string>
    +     <string name="storage_usb" msgid="3017954059538517278">"USB эстутуму"</string>
    +     <string name="extract_edit_menu_button" msgid="8940478730496610137">"Өзгөртүү"</string>
    +-    <string name="data_usage_warning_title" msgid="1955638862122232342">"Дайындарды колдонуу боюнча эскрт"</string>
    ++    <string name="data_usage_warning_title" msgid="3620440638180218181">"Дайындарды колдонууну чектөө"</string>
    +     <string name="data_usage_warning_body" msgid="6660692274311972007">"Колдонулушун жана жөндөөлөрүн көрүү үчүн таптаңыз."</string>
    +     <string name="data_usage_3g_limit_title" msgid="4361523876818447683">"2G-3G дайындар чегине жетти"</string>
    +     <string name="data_usage_4g_limit_title" msgid="4609566827219442376">"4G дайындар чегине жетти"</string>
    +@@ -1639,6 +1648,7 @@
    +     <string name="search_language_hint" msgid="7042102592055108574">"Тилди киргизиңиз"</string>
    +     <string name="language_picker_section_suggested" msgid="8414489646861640885">"Сунушталган"</string>
    +     <string name="language_picker_section_all" msgid="3097279199511617537">"Бардык тилдер"</string>
    ++    <string name="region_picker_section_all" msgid="8966316787153001779">"Бардык аймактар"</string>
    +     <string name="locale_search_menu" msgid="2560710726687249178">"Издөө"</string>
    +     <string name="work_mode_off_title" msgid="8954725060677558855">"Жумуш режими ӨЧҮРҮЛГӨН"</string>
    +     <string name="work_mode_off_message" msgid="3286169091278094476">"Жумуш профилин, ошондой эле колдонмолорду, фондо шайкештирүү жана ага байланыштуу функцияларды иштетиңиз."</string>
    +diff --git a/core/res/res/values-lo-rLA/strings.xml b/core/res/res/values-lo-rLA/strings.xml
    +index e2720c7..18f285f 100644
    +--- a/core/res/res/values-lo-rLA/strings.xml
    ++++ b/core/res/res/values-lo-rLA/strings.xml
    +@@ -214,6 +214,7 @@
    +     <string name="global_actions" product="default" msgid="2406416831541615258">"ໂຕເລືອກໂທລະສັບ"</string>
    +     <string name="global_action_lock" msgid="2844945191792119712">"ລັອກໜ້າຈໍ"</string>
    +     <string name="global_action_power_off" msgid="4471879440839879722">"ປິດ"</string>
    ++    <string name="global_action_emergency" msgid="7112311161137421166">"ສຸກເສີນ"</string>
    +     <string name="global_action_bug_report" msgid="7934010578922304799">"ລາຍງານຂໍ້ຜິດພາດ"</string>
    +     <string name="bugreport_title" msgid="2667494803742548533">"ໃຊ້ລາຍງານຂໍ້ບົກພ່ອງ"</string>
    +     <string name="bugreport_message" msgid="398447048750350456">"ນີ້ຈະເປັນການເກັບກຳຂໍ້ມູນກ່ຽວກັບ ສະຖານະປັດຈຸບັນຂອງອຸປະກອນທ່ານ ເພື່ອສົ່ງເປັນຂໍ້ຄວາມທາງອີເມວ. ມັນຈະໃຊ້ເວລາໜ້ອຍນຶ່ງ ໃນການເລີ່ມຕົ້ນການລາຍງານຂໍ້ຜິດພາດ ຈົນກວ່າຈະພ້ອມທີ່ຈະສົ່ງໄດ້, ກະລຸນາລໍຖ້າ."</string>
    +@@ -1076,6 +1077,17 @@
    +     <skip />
    +     <string name="wifi_no_internet" msgid="8451173622563841546">"Wi-Fi ບໍ່ມີການເຂົ້າເຖິງອິນເຕີເນັດ"</string>
    +     <string name="wifi_no_internet_detailed" msgid="8083079241212301741">"ແຕະເພື່ອເບິ່ງຕົວເລືອກ"</string>
    ++    <string name="network_switch_metered" msgid="4671730921726992671">"ສະຫຼັບໄປໃຊ້ <xliff:g id="NETWORK_TYPE">%1$s</xliff:g> ແລ້ວ"</string>
    ++    <string name="network_switch_metered_detail" msgid="5325661434777870353">"ອຸປະກອນຈະໃຊ້ <xliff:g id="NEW_NETWORK">%1$s</xliff:g> ເມື່ອ <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> ບໍ່ມີການເຊື່ອມຕໍ່ອິນເຕີເນັດ. ອາດມີການຮຽກເກັບຄ່າບໍລິການ."</string>
    ++    <string name="network_switch_metered_toast" msgid="5779283181685974304">"ສະຫຼັບຈາກ <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> ໄປໃຊ້ <xliff:g id="NEW_NETWORK">%2$s</xliff:g> ແລ້ວ"</string>
    ++  <string-array name="network_switch_type_name">
    ++    <item msgid="2952042958050315394">"ຂໍ້ມູນອິນເຕີເນັດມືຖື"</item>
    ++    <item msgid="75483255295529161">"Wi-Fi"</item>
    ++    <item msgid="6862614801537202646">"Bluetooth"</item>
    ++    <item msgid="5447331121797802871">"ອີເທີເນັດ"</item>
    ++    <item msgid="8257233890381651999">"VPN"</item>
    ++  </string-array>
    ++    <string name="network_switch_type_name_unknown" msgid="4552612897806660656">"ບໍ່ຮູ້ຈັກປະເພດເຄືອຂ່າຍ"</string>
    +     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"ບໍ່ສາມາດເຊື່ອມຕໍ່ Wi-Fi ໄດ້"</string>
    +     <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" ມີສັນຍານອິນເຕີເນັດທີ່ບໍ່ດີ."</string>
    +     <string name="wifi_connect_alert_title" msgid="8455846016001810172">"​ອະ​ນຸ​ຍາດ​ການ​ເຊື່ອມ​ຕໍ່ຫຼື​ບໍ່?"</string>
    +@@ -1153,7 +1165,6 @@
    +     <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"ແຕະເພື່ອເລືອກພາສາ ແລະ ໂຄງແປ້ນພິມ"</string>
    +     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
    +     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
    +-    <string name="candidates_style" msgid="4333913089637062257"><u>"ຕົວເລືອກ"</u></string>
    +     <string name="ext_media_checking_notification_title" msgid="5734005953288045806">"ກຳ​ລັງ​ກຽມ <xliff:g id="NAME">%s</xliff:g>"</string>
    +     <string name="ext_media_checking_notification_message" msgid="4747432538578886744">"ກຳລັງກວດຫາຂໍ້ຜິດພາດ"</string>
    +     <string name="ext_media_new_notification_message" msgid="7589986898808506239">"ກວດ​ພົບ <xliff:g id="NAME">%s</xliff:g> ໃໝ່​ແລ້ວ"</string>
    +@@ -1232,8 +1243,9 @@
    +     <string name="vpn_text_long" msgid="4907843483284977618">"ເຊື່ອມຕໍ່ກັບ <xliff:g id="SESSION">%s</xliff:g> ແລ້ວ. ແຕະເພື່ອຈັດການເຄືອຂ່າຍ."</string>
    +     <string name="vpn_lockdown_connecting" msgid="6443438964440960745">"ກຳລັງເຊື່ອມຕໍ່ Always-on VPN…"</string>
    +     <string name="vpn_lockdown_connected" msgid="8202679674819213931">"ເຊື່ອມຕໍ່ VPN ແບບເປີດຕະຫຼອດເວລາແລ້ວ"</string>
    ++    <string name="vpn_lockdown_disconnected" msgid="4532298952570796327">"ຕັດການເຊື່ອມຕໍ່ VPN ແບບເປີດໃຊ້ຕະຫຼອດເວລາແລ້ວ"</string>
    +     <string name="vpn_lockdown_error" msgid="6009249814034708175">"VPN ແບບເປີດຕະຫຼອດເກີດຄວາມຜິດພາດ"</string>
    +-    <string name="vpn_lockdown_config" msgid="4655589351146766608">"ແຕະເພື່ອຕັ້ງຄ່າ"</string>
    ++    <string name="vpn_lockdown_config" msgid="5099330695245008680">"ແຕະເພື່ອຕັ້ງຄ່າ"</string>
    +     <string name="upload_file" msgid="2897957172366730416">"ເລືອກໄຟລ໌"</string>
    +     <string name="no_file_chosen" msgid="6363648562170759465">"ບໍ່ໄດ້ເລືອກໄຟລ໌ເທື່ອ"</string>
    +     <string name="reset" msgid="2448168080964209908">"ຣີເຊັດ"</string>
    +@@ -1317,7 +1329,7 @@
    +     <string name="storage_usb_drive_label" msgid="4501418548927759953">"<xliff:g id="MANUFACTURER">%s</xliff:g> USB ດ​ຣ້າຍ"</string>
    +     <string name="storage_usb" msgid="3017954059538517278">"ບ່ອນຈັດເກັບຂໍ້ມູນ USB"</string>
    +     <string name="extract_edit_menu_button" msgid="8940478730496610137">"ແກ້ໄຂ"</string>
    +-    <string name="data_usage_warning_title" msgid="1955638862122232342">"ເຕືອນກ່ຽວກັບການນຳໃຊ້ຂໍ້ມູນ"</string>
    ++    <string name="data_usage_warning_title" msgid="3620440638180218181">"ແຈ້ງເຕືອນການໃຊ້ອິນເຕີເນັດ"</string>
    +     <string name="data_usage_warning_body" msgid="6660692274311972007">"ແຕະເພື່ອເບິ່ງການນຳໃຊ້ ແລະ ການຕັ້ງຄ່າ."</string>
    +     <string name="data_usage_3g_limit_title" msgid="4361523876818447683">"ໃຊ້​ຂໍ້​ມູນ 2G-3G ຮອດ​ຈຳ​ນວນ​ທີ່​ຈຳ​ກັດ​ແລ້ວ"</string>
    +     <string name="data_usage_4g_limit_title" msgid="4609566827219442376">"ໃຊ້​ຂໍ້​ມູນ 4G ຮອດ​ຈຳ​ນວນ​ທີ່​ຈຳ​ກັດ​ແລ້ວ"</string>
    +@@ -1636,6 +1648,7 @@
    +     <string name="search_language_hint" msgid="7042102592055108574">"ພິມຊື່ພາສາ"</string>
    +     <string name="language_picker_section_suggested" msgid="8414489646861640885">"ແນະນຳ"</string>
    +     <string name="language_picker_section_all" msgid="3097279199511617537">"ທຸກພາ​ສາ​"</string>
    ++    <string name="region_picker_section_all" msgid="8966316787153001779">"ທຸກຂົງເຂດ"</string>
    +     <string name="locale_search_menu" msgid="2560710726687249178">"ຄົ້ນຫາ"</string>
    +     <string name="work_mode_off_title" msgid="8954725060677558855">"ໂໝດບ່ອນເຮັດວຽກປິດຢູ່"</string>
    +     <string name="work_mode_off_message" msgid="3286169091278094476">"ອະນຸຍາດໃຫ້ໂປຣໄຟລ໌ບ່ອນເຮັດວຽກສາມາດນຳໃຊ້ໄດ້ ເຊິ່ງຮວມທັງແອັບ, ການຊິ້ງຂໍ້ມູນໃນພື້ນຫຼັງ ແລະ ຄຸນສົມບັດທີ່ກ່ຽວຂ້ອງ."</string>
    +diff --git a/core/res/res/values-lt/strings.xml b/core/res/res/values-lt/strings.xml
    +index ab38c0c..9952a7c 100644
    +--- a/core/res/res/values-lt/strings.xml
    ++++ b/core/res/res/values-lt/strings.xml
    +@@ -218,6 +218,7 @@
    +     <string name="global_actions" product="default" msgid="2406416831541615258">"Telefono parinktys"</string>
    +     <string name="global_action_lock" msgid="2844945191792119712">"Ekrano užraktas"</string>
    +     <string name="global_action_power_off" msgid="4471879440839879722">"Išjungiamas maitinimas"</string>
    ++    <string name="global_action_emergency" msgid="7112311161137421166">"Skambutis pagalbos numeriu"</string>
    +     <string name="global_action_bug_report" msgid="7934010578922304799">"Pranešimas apie riktą"</string>
    +     <string name="bugreport_title" msgid="2667494803742548533">"Pranešti apie riktą"</string>
    +     <string name="bugreport_message" msgid="398447048750350456">"Bus surinkta informacija apie dabartinę įrenginio būseną ir išsiųsta el. pašto pranešimu. Šiek tiek užtruks, kol pranešimas apie riktą bus paruoštas siųsti; būkite kantrūs."</string>
    +@@ -1104,7 +1105,7 @@
    +     <string name="volume_icon_description_media" msgid="4217311719665194215">"Medijos garsumas"</string>
    +     <string name="volume_icon_description_notification" msgid="7044986546477282274">"Pranešimo apimtis"</string>
    +     <string name="ringtone_default" msgid="3789758980357696936">"Numatytasis skambėjimo tonas"</string>
    +-    <string name="ringtone_default_with_actual" msgid="8129563480895990372">"Numatytasis skambėjimo tonas (<xliff:g id="ACTUAL_RINGTONE">%1$s</xliff:g>)"</string>
    ++    <string name="ringtone_default_with_actual" msgid="8129563480895990372">"Numatytasis skambėjimo tonas („<xliff:g id="ACTUAL_RINGTONE">%1$s</xliff:g>“)"</string>
    +     <string name="ringtone_silent" msgid="7937634392408977062">"Nėra"</string>
    +     <string name="ringtone_picker_title" msgid="3515143939175119094">"Skambėjimo tonai"</string>
    +     <string name="ringtone_unknown" msgid="5477919988701784788">"Nežinomas skambėjimo tonas"</string>
    +@@ -1126,6 +1127,17 @@
    +     <skip />
    +     <string name="wifi_no_internet" msgid="8451173622563841546">"„Wi-Fi“ tinkle nėra interneto ryšio"</string>
    +     <string name="wifi_no_internet_detailed" msgid="8083079241212301741">"Palieskite, kad būtų rodomos parinktys."</string>
    ++    <string name="network_switch_metered" msgid="4671730921726992671">"Perjungta į tinklą <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
    ++    <string name="network_switch_metered_detail" msgid="5325661434777870353">"Įrenginys naudoja tinklą <xliff:g id="NEW_NETWORK">%1$s</xliff:g> kai tinkle <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> nėra interneto ryšio. Gali būti taikomi mokesčiai."</string>
    ++    <string name="network_switch_metered_toast" msgid="5779283181685974304">"Perjungta iš tinklo <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> į tinklą <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
    ++  <string-array name="network_switch_type_name">
    ++    <item msgid="2952042958050315394">"mobiliojo ryšio duomenys"</item>
    ++    <item msgid="75483255295529161">"Wi-Fi"</item>
    ++    <item msgid="6862614801537202646">"Bluetooth"</item>
    ++    <item msgid="5447331121797802871">"Eternetas"</item>
    ++    <item msgid="8257233890381651999">"VPN"</item>
    ++  </string-array>
    ++    <string name="network_switch_type_name_unknown" msgid="4552612897806660656">"nežinomas tinklo tipas"</string>
    +     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Nepavyko prisijungti prie „Wi-Fi“"</string>
    +     <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" turi prastą interneto ryšį."</string>
    +     <string name="wifi_connect_alert_title" msgid="8455846016001810172">"Leisti prisijungti?"</string>
    +@@ -1203,7 +1215,6 @@
    +     <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"Palieskite, kad pasirinktumėte kalbą ir išdėstymą"</string>
    +     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" AĄBCČDEĘĖFGHIĮYJKLMNOPRSŠTUŲŪVZŽ"</string>
    +     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789AĄBCČDEĘĖFGHIĮYJKLMNOPRSŠTUŲŪVZŽ"</string>
    +-    <string name="candidates_style" msgid="4333913089637062257"><u>"kandidatai"</u></string>
    +     <string name="ext_media_checking_notification_title" msgid="5734005953288045806">"Ruošiama <xliff:g id="NAME">%s</xliff:g>"</string>
    +     <string name="ext_media_checking_notification_message" msgid="4747432538578886744">"Tikrinama, ar nėra klaidų"</string>
    +     <string name="ext_media_new_notification_message" msgid="7589986898808506239">"Aptikta nauja <xliff:g id="NAME">%s</xliff:g>"</string>
    +@@ -1282,8 +1293,9 @@
    +     <string name="vpn_text_long" msgid="4907843483284977618">"Prisijungta prie <xliff:g id="SESSION">%s</xliff:g>. Jei norite valdyti tinklą, palieskite."</string>
    +     <string name="vpn_lockdown_connecting" msgid="6443438964440960745">"Prisijungiama prie visada įjungto VPN…"</string>
    +     <string name="vpn_lockdown_connected" msgid="8202679674819213931">"Prisijungta prie visada įjungto VPN"</string>
    ++    <string name="vpn_lockdown_disconnected" msgid="4532298952570796327">"Visada įjungtas VPN atjungtas"</string>
    +     <string name="vpn_lockdown_error" msgid="6009249814034708175">"Visada įjungto VPN klaida"</string>
    +-    <string name="vpn_lockdown_config" msgid="4655589351146766608">"Palieskite, kad konfigūruotumėte"</string>
    ++    <string name="vpn_lockdown_config" msgid="5099330695245008680">"Palieskite, kad nustatytumėte"</string>
    +     <string name="upload_file" msgid="2897957172366730416">"Pasirinkti failą"</string>
    +     <string name="no_file_chosen" msgid="6363648562170759465">"Nepasirinktas joks failas"</string>
    +     <string name="reset" msgid="2448168080964209908">"Atstatyti"</string>
    +@@ -1369,7 +1381,7 @@
    +     <string name="storage_usb_drive_label" msgid="4501418548927759953">"„<xliff:g id="MANUFACTURER">%s</xliff:g>“ atmintukas"</string>
    +     <string name="storage_usb" msgid="3017954059538517278">"USB atmintis"</string>
    +     <string name="extract_edit_menu_button" msgid="8940478730496610137">"Redaguoti"</string>
    +-    <string name="data_usage_warning_title" msgid="1955638862122232342">"Įspėjimas dėl duomenų naudojimo"</string>
    ++    <string name="data_usage_warning_title" msgid="3620440638180218181">"Duomenų naudojimo įspėjimas"</string>
    +     <string name="data_usage_warning_body" msgid="6660692274311972007">"Pal. ir perž. naud. i. bei nust."</string>
    +     <string name="data_usage_3g_limit_title" msgid="4361523876818447683">"Pasiektas 2G–3G duomenų apribojimas"</string>
    +     <string name="data_usage_4g_limit_title" msgid="4609566827219442376">"Pasiektas 4G duomenų apribojimas"</string>
    +@@ -1708,6 +1720,7 @@
    +     <string name="search_language_hint" msgid="7042102592055108574">"Įveskite kalbos pav."</string>
    +     <string name="language_picker_section_suggested" msgid="8414489646861640885">"Siūloma"</string>
    +     <string name="language_picker_section_all" msgid="3097279199511617537">"Visos kalbos"</string>
    ++    <string name="region_picker_section_all" msgid="8966316787153001779">"Visi regionai"</string>
    +     <string name="locale_search_menu" msgid="2560710726687249178">"Paieška"</string>
    +     <string name="work_mode_off_title" msgid="8954725060677558855">"Darbo režimas išjungtas"</string>
    +     <string name="work_mode_off_message" msgid="3286169091278094476">"Leisti veikti darbo profiliui, įskaitant programas, sinchronizavimą fone ir susijusias funkcijas."</string>
    +diff --git a/core/res/res/values-lv/strings.xml b/core/res/res/values-lv/strings.xml
    +index 35b699f..ff2e974 100644
    +--- a/core/res/res/values-lv/strings.xml
    ++++ b/core/res/res/values-lv/strings.xml
    +@@ -216,6 +216,7 @@
    +     <string name="global_actions" product="default" msgid="2406416831541615258">"Tālruņa opcijas"</string>
    +     <string name="global_action_lock" msgid="2844945191792119712">"Ekrāna bloķētājs"</string>
    +     <string name="global_action_power_off" msgid="4471879440839879722">"Strāvas padeve ir izslēgta."</string>
    ++    <string name="global_action_emergency" msgid="7112311161137421166">"Ārkārtas"</string>
    +     <string name="global_action_bug_report" msgid="7934010578922304799">"Kļūdu ziņojums"</string>
    +     <string name="bugreport_title" msgid="2667494803742548533">"Kļūdu ziņojuma sagatavošana"</string>
    +     <string name="bugreport_message" msgid="398447048750350456">"Veicot šo darbību, tiks apkopota informācija par jūsu ierīces pašreizējo stāvokli un nosūtīta e-pasta ziņojuma veidā. Kļūdu ziņojuma pabeigšanai un nosūtīšanai var būt nepieciešams laiks. Lūdzu, esiet pacietīgs."</string>
    +@@ -1101,6 +1102,17 @@
    +     <skip />
    +     <string name="wifi_no_internet" msgid="8451173622563841546">"Wi-Fi tīklā nav piekļuves internetam."</string>
    +     <string name="wifi_no_internet_detailed" msgid="8083079241212301741">"Pieskarieties, lai skatītu iespējas."</string>
    ++    <string name="network_switch_metered" msgid="4671730921726992671">"Pārslēdzās uz tīklu <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
    ++    <string name="network_switch_metered_detail" msgid="5325661434777870353">"Kad tīklā <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> nav piekļuves internetam, ierīcē tiek izmantots tīkls <xliff:g id="NEW_NETWORK">%1$s</xliff:g>. Var tikt piemērota maksa."</string>
    ++    <string name="network_switch_metered_toast" msgid="5779283181685974304">"Pārslēdzās no tīkla <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> uz tīklu <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
    ++  <string-array name="network_switch_type_name">
    ++    <item msgid="2952042958050315394">"mobilie dati"</item>
    ++    <item msgid="75483255295529161">"Wi-Fi"</item>
    ++    <item msgid="6862614801537202646">"Bluetooth"</item>
    ++    <item msgid="5447331121797802871">"Ethernet"</item>
    ++    <item msgid="8257233890381651999">"VPN"</item>
    ++  </string-array>
    ++    <string name="network_switch_type_name_unknown" msgid="4552612897806660656">"nezināms tīkla veids"</string>
    +     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Nevarēja izveidot savienojumu ar Wi-Fi."</string>
    +     <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" ir slikts interneta savienojums."</string>
    +     <string name="wifi_connect_alert_title" msgid="8455846016001810172">"Vai atļaut savienojumu?"</string>
    +@@ -1178,7 +1190,6 @@
    +     <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"Pieskarieties, lai atlasītu valodu un izkārtojumu"</string>
    +     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" AĀBCČDEĒFGĢHIĪJKĶLĻMNŅOPRSŠTUŪVZŽ"</string>
    +     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789AĀBCČDEĒFGĢHIĪJKĶLĻMNŅOPRSŠTUŪVZŽ"</string>
    +-    <string name="candidates_style" msgid="4333913089637062257"><u>"kandidāti"</u></string>
    +     <string name="ext_media_checking_notification_title" msgid="5734005953288045806">"Notiek <xliff:g id="NAME">%s</xliff:g> sagatavošana"</string>
    +     <string name="ext_media_checking_notification_message" msgid="4747432538578886744">"Tiek meklētas kļūdas"</string>
    +     <string name="ext_media_new_notification_message" msgid="7589986898808506239">"Tika atrasta jauna <xliff:g id="NAME">%s</xliff:g>."</string>
    +@@ -1257,8 +1268,9 @@
    +     <string name="vpn_text_long" msgid="4907843483284977618">"Ir izveidots savienojums ar: <xliff:g id="SESSION">%s</xliff:g>. Pieskarieties, lai pārvaldītu tīklu."</string>
    +     <string name="vpn_lockdown_connecting" msgid="6443438964440960745">"Notiek savienojuma izveide ar vienmēr ieslēgtu VPN…"</string>
    +     <string name="vpn_lockdown_connected" msgid="8202679674819213931">"Izveidots savienojums ar vienmēr ieslēgtu VPN."</string>
    ++    <string name="vpn_lockdown_disconnected" msgid="4532298952570796327">"Vienmēr ieslēgts VPN ir atvienots"</string>
    +     <string name="vpn_lockdown_error" msgid="6009249814034708175">"Kļūda saistībā ar vienmēr ieslēgtu VPN"</string>
    +-    <string name="vpn_lockdown_config" msgid="4655589351146766608">"Pieskarieties, lai konfigurētu."</string>
    ++    <string name="vpn_lockdown_config" msgid="5099330695245008680">"Pieskarieties, lai iestatītu."</string>
    +     <string name="upload_file" msgid="2897957172366730416">"Izvēlēties failu"</string>
    +     <string name="no_file_chosen" msgid="6363648562170759465">"Neviens fails nav izvēlēts"</string>
    +     <string name="reset" msgid="2448168080964209908">"Atiestatīt"</string>
    +@@ -1343,7 +1355,7 @@
    +     <string name="storage_usb_drive_label" msgid="4501418548927759953">"<xliff:g id="MANUFACTURER">%s</xliff:g> USB disks"</string>
    +     <string name="storage_usb" msgid="3017954059538517278">"USB atmiņa"</string>
    +     <string name="extract_edit_menu_button" msgid="8940478730496610137">"Rediģēt"</string>
    +-    <string name="data_usage_warning_title" msgid="1955638862122232342">"Datu izmantošanas brīdinājums"</string>
    ++    <string name="data_usage_warning_title" msgid="3620440638180218181">"Brīdinājums par datu lietojumu"</string>
    +     <string name="data_usage_warning_body" msgid="6660692274311972007">"Piesk., lai sk. lietoj. un iest."</string>
    +     <string name="data_usage_3g_limit_title" msgid="4361523876818447683">"Sasniegts 2G-3G datu ierobež."</string>
    +     <string name="data_usage_4g_limit_title" msgid="4609566827219442376">"Sasniegts 4G datu ierobežojums"</string>
    +@@ -1672,6 +1684,7 @@
    +     <string name="search_language_hint" msgid="7042102592055108574">"Ierakstiet valodas nosaukumu"</string>
    +     <string name="language_picker_section_suggested" msgid="8414489646861640885">"Ieteiktās"</string>
    +     <string name="language_picker_section_all" msgid="3097279199511617537">"Visas valodas"</string>
    ++    <string name="region_picker_section_all" msgid="8966316787153001779">"Visi reģioni"</string>
    +     <string name="locale_search_menu" msgid="2560710726687249178">"Meklēt"</string>
    +     <string name="work_mode_off_title" msgid="8954725060677558855">"Darba režīms IZSLĒGTS"</string>
    +     <string name="work_mode_off_message" msgid="3286169091278094476">"Atļaujiet darboties darba profilam, tostarp lietotnēm, sinhronizācijai fonā un saistītajām funkcijām."</string>
    +diff --git a/core/res/res/values-mcc001/config.xml b/core/res/res/values-mcc001/config.xml
    +new file mode 100644
    +index 0000000..93cde03
    +--- /dev/null
    ++++ b/core/res/res/values-mcc001/config.xml
    +@@ -0,0 +1,21 @@
    ++<?xml version="1.0" encoding="utf-8"?>
    ++<!--
    ++/*
    ++** Copyright 2016, 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.
    ++*/
    ++-->
    ++<resources>
    ++    <bool name="config_use_sim_language_file">true</bool>
    ++</resources>
    +diff --git a/core/res/res/values-mcc222-mnc10/config.xml b/core/res/res/values-mcc222-mnc10/config.xml
    +index cd6e8c6..c819de2 100644
    +--- a/core/res/res/values-mcc222-mnc10/config.xml
    ++++ b/core/res/res/values-mcc222-mnc10/config.xml
    +@@ -28,29 +28,4 @@
    +     <string-array translatable="false" name="config_tether_apndata">
    +       <item>Tethering Internet,web.omnitel.it,,,,,,,,,222,10,,DUN</item>
    +     </string-array>
    +-
    +-    <string-array translatable="false" name="config_operatorConsideredNonRoaming">
    +-        <item>21401</item>
    +-        <item>21402</item>
    +-        <item>21403</item>
    +-        <item>21404</item>
    +-        <item>21405</item>
    +-        <item>21406</item>
    +-        <item>21407</item>
    +-        <item>21408</item>
    +-        <item>21409</item>
    +-        <item>21410</item>
    +-        <item>21411</item>
    +-        <item>21412</item>
    +-        <item>21413</item>
    +-        <item>21414</item>
    +-        <item>21415</item>
    +-        <item>21416</item>
    +-        <item>21417</item>
    +-        <item>21418</item>
    +-        <item>21419</item>
    +-        <item>21420</item>
    +-        <item>21421</item>
    +-    </string-array>
    +-
    + </resources>
    +diff --git a/core/res/res/values-mcc232-mnc10/config.xml b/core/res/res/values-mcc232-mnc10/config.xml
    +new file mode 100644
    +index 0000000..bdf83016
    +--- /dev/null
    ++++ b/core/res/res/values-mcc232-mnc10/config.xml
    +@@ -0,0 +1,26 @@
    ++<?xml version="1.0" encoding="utf-8"?>
    ++<!--
    ++/*
    ++ ** Copyright 2016, 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.
    ++ */
    ++-->
    ++
    ++<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
    ++    <!-- Don't use roaming icon for considered operators -->
    ++    <string-array translatable="false" name="config_operatorConsideredNonRoaming">
    ++        <item>23203</item>
    ++        <item>23205</item>
    ++    </string-array>
    ++</resources>
    +diff --git a/core/res/res/values-mcc232-mnc13/config.xml b/core/res/res/values-mcc232-mnc13/config.xml
    +new file mode 100644
    +index 0000000..2c14f87
    +--- /dev/null
    ++++ b/core/res/res/values-mcc232-mnc13/config.xml
    +@@ -0,0 +1,25 @@
    ++<?xml version="1.0" encoding="utf-8"?>
    ++<!--
    ++/*
    ++ ** Copyright 2016, 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.
    ++ */
    ++-->
    ++
    ++<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
    ++    <!-- Don't use roaming icon for considered operators -->
    ++    <string-array translatable="false" name="config_operatorConsideredNonRoaming">
    ++        <item>23203</item>
    ++    </string-array>
    ++</resources>
    +diff --git a/core/res/res/values-mcc302-mnc220/config.xml b/core/res/res/values-mcc302-mnc220/config.xml
    +index d638b89..422f7c9 100644
    +--- a/core/res/res/values-mcc302-mnc220/config.xml
    ++++ b/core/res/res/values-mcc302-mnc220/config.xml
    +@@ -21,14 +21,6 @@
    +      for different hardware and product builds. -->
    + <resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
    + 
    +-    <string-array translatable="false" name="config_operatorConsideredNonRoaming">
    +-        <item>302370</item>
    +-        <item>302610</item>
    +-        <item>302660</item>
    +-        <item>302720</item>
    +-        <item>302780</item>
    +-    </string-array>
    +-
    +     <integer name="config_mobile_mtu">1410</integer>
    + 
    +     <!-- String containing the apn value for tethering.  May be overriden by secure settings
    +diff --git a/core/res/res/values-mcc302-mnc500/config.xml b/core/res/res/values-mcc302-mnc500/config.xml
    +new file mode 100644
    +index 0000000..77f6419
    +--- /dev/null
    ++++ b/core/res/res/values-mcc302-mnc500/config.xml
    +@@ -0,0 +1,25 @@
    ++<?xml version="1.0" encoding="utf-8"?>
    ++<!--
    ++/*
    ++ ** Copyright 2016, 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.
    ++ */
    ++-->
    ++
    ++<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
    ++    <!-- Don't use roaming icon for considered operators -->
    ++    <string-array translatable="false" name="config_operatorConsideredNonRoaming">
    ++        <item>302</item>
    ++    </string-array>
    ++</resources>
    +diff --git a/core/res/res/values-mcc302-mnc510/config.xml b/core/res/res/values-mcc302-mnc510/config.xml
    +new file mode 100644
    +index 0000000..77f6419
    +--- /dev/null
    ++++ b/core/res/res/values-mcc302-mnc510/config.xml
    +@@ -0,0 +1,25 @@
    ++<?xml version="1.0" encoding="utf-8"?>
    ++<!--
    ++/*
    ++ ** Copyright 2016, 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.
    ++ */
    ++-->
    ++
    ++<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
    ++    <!-- Don't use roaming icon for considered operators -->
    ++    <string-array translatable="false" name="config_operatorConsideredNonRoaming">
    ++        <item>302</item>
    ++    </string-array>
    ++</resources>
    +diff --git a/core/res/res/values-mcc722-mnc36/config.xml b/core/res/res/values-mcc722-mnc36/config.xml
    +new file mode 100644
    +index 0000000..daf5373
    +--- /dev/null
    ++++ b/core/res/res/values-mcc722-mnc36/config.xml
    +@@ -0,0 +1,25 @@
    ++<?xml version="1.0" encoding="utf-8"?>
    ++<!--
    ++/*
    ++** Copyright 2016, 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 my 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.
    ++*/
    ++-->
    ++
    ++<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
    ++    <!-- Don't use roaming icon for considered operators -->
    ++    <string-array translatable="false" name="config_operatorConsideredNonRoaming">
    ++        <item>72234</item>
    ++    </string-array>
    ++</resources>
    +diff --git a/core/res/res/values-mk-rMK/strings.xml b/core/res/res/values-mk-rMK/strings.xml
    +index e0ec16a..eb86a77 100644
    +--- a/core/res/res/values-mk-rMK/strings.xml
    ++++ b/core/res/res/values-mk-rMK/strings.xml
    +@@ -214,6 +214,7 @@
    +     <string name="global_actions" product="default" msgid="2406416831541615258">"Опции на телефон"</string>
    +     <string name="global_action_lock" msgid="2844945191792119712">"Заклучи екран"</string>
    +     <string name="global_action_power_off" msgid="4471879440839879722">"Исклучи"</string>
    ++    <string name="global_action_emergency" msgid="7112311161137421166">"Итен случај"</string>
    +     <string name="global_action_bug_report" msgid="7934010578922304799">"Извештај за грешка"</string>
    +     <string name="bugreport_title" msgid="2667494803742548533">"Земи извештај за грешки"</string>
    +     <string name="bugreport_message" msgid="398447048750350456">"Ова ќе собира информации за моменталната состојба на вашиот уред, за да ги испрати како порака по е-пошта. Тоа ќе одземе малку време почнувајќи од извештајот за грешки додека не се подготви за праќање; бидете трпеливи."</string>
    +@@ -1076,6 +1077,17 @@
    +     <skip />
    +     <string name="wifi_no_internet" msgid="8451173622563841546">"Wi-Fi нема пристап на интернет"</string>
    +     <string name="wifi_no_internet_detailed" msgid="8083079241212301741">"Допрете за опции"</string>
    ++    <string name="network_switch_metered" msgid="4671730921726992671">"Префрлено на <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
    ++    <string name="network_switch_metered_detail" msgid="5325661434777870353">"Уредот користи <xliff:g id="NEW_NETWORK">%1$s</xliff:g> кога <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> нема пристап до интернет. Може да се наплатат трошоци."</string>
    ++    <string name="network_switch_metered_toast" msgid="5779283181685974304">"Префрлено од <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> на <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
    ++  <string-array name="network_switch_type_name">
    ++    <item msgid="2952042958050315394">"мобилен интернет"</item>
    ++    <item msgid="75483255295529161">"Wi-Fi"</item>
    ++    <item msgid="6862614801537202646">"Bluetooth"</item>
    ++    <item msgid="5447331121797802871">"Етернет"</item>
    ++    <item msgid="8257233890381651999">"VPN"</item>
    ++  </string-array>
    ++    <string name="network_switch_type_name_unknown" msgid="4552612897806660656">"непознат тип мрежа"</string>
    +     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Не можеше да се поврзе со Wi-Fi"</string>
    +     <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" има слаба конекција на интернет."</string>
    +     <string name="wifi_connect_alert_title" msgid="8455846016001810172">"Дозволете поврзување?"</string>
    +@@ -1153,7 +1165,6 @@
    +     <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"Допрете за избирање јазик и распоред"</string>
    +     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
    +     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
    +-    <string name="candidates_style" msgid="4333913089637062257"><u>"кандидати"</u></string>
    +     <string name="ext_media_checking_notification_title" msgid="5734005953288045806">"Се подготвува <xliff:g id="NAME">%s</xliff:g>"</string>
    +     <string name="ext_media_checking_notification_message" msgid="4747432538578886744">"Се проверува за грешки"</string>
    +     <string name="ext_media_new_notification_message" msgid="7589986898808506239">"Откриена е нова <xliff:g id="NAME">%s</xliff:g>"</string>
    +@@ -1232,8 +1243,9 @@
    +     <string name="vpn_text_long" msgid="4907843483284977618">"Поврзани сте на <xliff:g id="SESSION">%s</xliff:g>. Допрете за да управувате со мрежата."</string>
    +     <string name="vpn_lockdown_connecting" msgid="6443438964440960745">"Поврзување со секогаш вклучена VPN..."</string>
    +     <string name="vpn_lockdown_connected" msgid="8202679674819213931">"Поврзани со секогаш вклучена VPN"</string>
    ++    <string name="vpn_lockdown_disconnected" msgid="4532298952570796327">"Секогаш вклучената VPN е неповрзана"</string>
    +     <string name="vpn_lockdown_error" msgid="6009249814034708175">"Грешка на секогаш вклучена VPN"</string>
    +-    <string name="vpn_lockdown_config" msgid="4655589351146766608">"Допрете за конфигурирање"</string>
    ++    <string name="vpn_lockdown_config" msgid="5099330695245008680">"Допрете за да поставите"</string>
    +     <string name="upload_file" msgid="2897957172366730416">"Избери датотека"</string>
    +     <string name="no_file_chosen" msgid="6363648562170759465">"Не е избрана датотека"</string>
    +     <string name="reset" msgid="2448168080964209908">"Ресетирај"</string>
    +@@ -1319,7 +1331,7 @@
    +     <string name="storage_usb_drive_label" msgid="4501418548927759953">"<xliff:g id="MANUFACTURER">%s</xliff:g> УСБ-меморија"</string>
    +     <string name="storage_usb" msgid="3017954059538517278">"УСБ меморија"</string>
    +     <string name="extract_edit_menu_button" msgid="8940478730496610137">"Уреди"</string>
    +-    <string name="data_usage_warning_title" msgid="1955638862122232342">"Опомена за потрошен интернет"</string>
    ++    <string name="data_usage_warning_title" msgid="3620440638180218181">"Известување за потрошен сообраќај"</string>
    +     <string name="data_usage_warning_body" msgid="6660692274311972007">"Допрете за употреба и поставки."</string>
    +     <string name="data_usage_3g_limit_title" msgid="4361523876818447683">"Постигна лимит за 2G-3G податоци"</string>
    +     <string name="data_usage_4g_limit_title" msgid="4609566827219442376">"Постигнат лимит за 4G податоци"</string>
    +@@ -1638,6 +1650,7 @@
    +     <string name="search_language_hint" msgid="7042102592055108574">"Внеси име на јазик"</string>
    +     <string name="language_picker_section_suggested" msgid="8414489646861640885">"Предложени"</string>
    +     <string name="language_picker_section_all" msgid="3097279199511617537">"Сите јазици"</string>
    ++    <string name="region_picker_section_all" msgid="8966316787153001779">"Сите региони"</string>
    +     <string name="locale_search_menu" msgid="2560710726687249178">"Пребарај"</string>
    +     <string name="work_mode_off_title" msgid="8954725060677558855">"Режимот на работа е ИСКЛУЧЕН"</string>
    +     <string name="work_mode_off_message" msgid="3286169091278094476">"Дозволете работниот профил да функционира, вклучувајќи ги апликациите, синхронизирањето во заднина и други поврзани функции."</string>
    +diff --git a/core/res/res/values-ml-rIN/strings.xml b/core/res/res/values-ml-rIN/strings.xml
    +index 39d493a..423db1d 100644
    +--- a/core/res/res/values-ml-rIN/strings.xml
    ++++ b/core/res/res/values-ml-rIN/strings.xml
    +@@ -214,6 +214,7 @@
    +     <string name="global_actions" product="default" msgid="2406416831541615258">"ഫോൺ ഓപ്‌ഷനുകൾ"</string>
    +     <string name="global_action_lock" msgid="2844945191792119712">"സ്‌ക്രീൻ ലോക്ക്"</string>
    +     <string name="global_action_power_off" msgid="4471879440839879722">"പവർ ഓഫാക്കുക"</string>
    ++    <string name="global_action_emergency" msgid="7112311161137421166">"അടിയന്തിരാവശ്യം"</string>
    +     <string name="global_action_bug_report" msgid="7934010578922304799">"ബഗ് റിപ്പോർട്ട്"</string>
    +     <string name="bugreport_title" msgid="2667494803742548533">"ബഗ് റിപ്പോർട്ട് എടുക്കുക"</string>
    +     <string name="bugreport_message" msgid="398447048750350456">"ഒരു ഇമെയിൽ സന്ദേശമായി അയയ്‌ക്കുന്നതിന്, ഇത് നിങ്ങളുടെ നിലവിലെ ഉപകരണ നിലയെക്കുറിച്ചുള്ള വിവരങ്ങൾ ശേഖരിക്കും. ബഗ് റിപ്പോർട്ട് ആരംഭിക്കുന്നതിൽ നിന്ന് ഇത് അയയ്‌ക്കാനായി തയ്യാറാകുന്നതുവരെ അൽപ്പസമയമെടുക്കും; ക്ഷമയോടെ കാത്തിരിക്കുക."</string>
    +@@ -1076,6 +1077,17 @@
    +     <skip />
    +     <string name="wifi_no_internet" msgid="8451173622563841546">"Wi-Fi-യിൽ ഇന്റർനെറ്റ് ആക്‌സസ് ഇല്ല."</string>
    +     <string name="wifi_no_internet_detailed" msgid="8083079241212301741">"ഓപ്ഷനുകൾക്ക് ടാപ്പുചെയ്യുക"</string>
    ++    <string name="network_switch_metered" msgid="4671730921726992671">"<xliff:g id="NETWORK_TYPE">%1$s</xliff:g> എന്നതിലേക്ക് മാറി"</string>
    ++    <string name="network_switch_metered_detail" msgid="5325661434777870353">"<xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> നെറ്റ്‌വർക്കിന് ഇന്റർനെറ്റ് ആക്സസ്സ് ഇല്ലാത്തപ്പോൾ ഉപകരണം <xliff:g id="NEW_NETWORK">%1$s</xliff:g> ഉപയോഗിക്കുന്നു. നിരക്കുകൾ ബാധകമായേക്കാം."</string>
    ++    <string name="network_switch_metered_toast" msgid="5779283181685974304">"<xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> നെറ്റ്‌വർക്കിൽ നിന്ന് <xliff:g id="NEW_NETWORK">%2$s</xliff:g> നെറ്റ്‌വർക്കിലേക്ക് മാറി"</string>
    ++  <string-array name="network_switch_type_name">
    ++    <item msgid="2952042958050315394">"സെല്ലുലാർ ഡാറ്റ"</item>
    ++    <item msgid="75483255295529161">"വൈഫൈ"</item>
    ++    <item msgid="6862614801537202646">"Bluetooth"</item>
    ++    <item msgid="5447331121797802871">"ഇതര്‍നെറ്റ്"</item>
    ++    <item msgid="8257233890381651999">"VPN"</item>
    ++  </string-array>
    ++    <string name="network_switch_type_name_unknown" msgid="4552612897806660656">"തിരിച്ചറിയാനാകാത്ത ഒരു നെറ്റ്‌വർക്ക് തരം"</string>
    +     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Wi-Fi-ലേക്ക് കണക്‌റ്റുചെയ്യാൻ കഴിഞ്ഞില്ല"</string>
    +     <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" മോശം ഇന്റർനെറ്റ് കണക്ഷനാണുള്ളത്."</string>
    +     <string name="wifi_connect_alert_title" msgid="8455846016001810172">"കണക്ഷൻ അനുവദിക്കണോ?"</string>
    +@@ -1153,7 +1165,6 @@
    +     <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"ഭാഷയും ലേഔട്ടും തിരഞ്ഞെടുക്കുന്നതിന് ടാപ്പുചെയ്യുക"</string>
    +     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
    +     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
    +-    <string name="candidates_style" msgid="4333913089637062257"><u>"കാൻഡിഡേറ്റുകൾ"</u></string>
    +     <string name="ext_media_checking_notification_title" msgid="5734005953288045806">"<xliff:g id="NAME">%s</xliff:g> തയ്യാറാകുന്നു"</string>
    +     <string name="ext_media_checking_notification_message" msgid="4747432538578886744">"പിശകുകളുണ്ടോയെന്നു പരിശോധിക്കുന്നു"</string>
    +     <string name="ext_media_new_notification_message" msgid="7589986898808506239">"പുതിയ <xliff:g id="NAME">%s</xliff:g> എന്നതിനെ തിരിച്ചറിഞ്ഞു"</string>
    +@@ -1232,8 +1243,9 @@
    +     <string name="vpn_text_long" msgid="4907843483284977618">"<xliff:g id="SESSION">%s</xliff:g> എന്ന സെഷനിലേക്ക് കണക്റ്റുചെയ്തു. നെറ്റ്‌വർക്ക് മാനേജുചെയ്യാൻ ടാപ്പുചെയ്യുക."</string>
    +     <string name="vpn_lockdown_connecting" msgid="6443438964440960745">"എല്ലായ്‌പ്പോഴും ഓണായിരിക്കുന്ന VPN കണക്റ്റുചെയ്യുന്നു…"</string>
    +     <string name="vpn_lockdown_connected" msgid="8202679674819213931">"എല്ലായ്‌പ്പോഴും ഓണായിരിക്കുന്ന VPN കണക്റ്റുചെയ്‌തു"</string>
    ++    <string name="vpn_lockdown_disconnected" msgid="4532298952570796327">"\'എല്ലായ്‌പ്പോഴും ഓണായിരിക്കുന്ന VPN\' വിച്ഛേദിച്ചു"</string>
    +     <string name="vpn_lockdown_error" msgid="6009249814034708175">"എല്ലായ്‌പ്പോഴും ഓണായിരിക്കുന്ന VPN പിശക്"</string>
    +-    <string name="vpn_lockdown_config" msgid="4655589351146766608">"കോൺഫിഗർ ചെയ്യുന്നതിന് ടാപ്പുചെയ്യുക"</string>
    ++    <string name="vpn_lockdown_config" msgid="5099330695245008680">"സജ്ജമാക്കാൻ ടാപ്പുചെയ്യുക"</string>
    +     <string name="upload_file" msgid="2897957172366730416">"ഫയല്‍‌ തിരഞ്ഞെടുക്കുക"</string>
    +     <string name="no_file_chosen" msgid="6363648562170759465">"ഫയലൊന്നും തിരഞ്ഞെടുത്തില്ല"</string>
    +     <string name="reset" msgid="2448168080964209908">"പുനഃസജ്ജമാക്കുക"</string>
    +@@ -1317,7 +1329,7 @@
    +     <string name="storage_usb_drive_label" msgid="4501418548927759953">"<xliff:g id="MANUFACTURER">%s</xliff:g> USB ഡ്രൈവ്"</string>
    +     <string name="storage_usb" msgid="3017954059538517278">"USB സ്റ്റോറേജ്"</string>
    +     <string name="extract_edit_menu_button" msgid="8940478730496610137">"എഡിറ്റുചെയ്യുക"</string>
    +-    <string name="data_usage_warning_title" msgid="1955638862122232342">"ഡാറ്റ ഉപയോഗ മുന്നറിയിപ്പ്"</string>
    ++    <string name="data_usage_warning_title" msgid="3620440638180218181">"ഡാറ്റാ ഉപയോഗ മുന്നറിയിപ്പ്"</string>
    +     <string name="data_usage_warning_body" msgid="6660692274311972007">"ഉപയോഗവും ക്രമീകരണവും കാണാൻ ടാപ്പുചെയ്യുക."</string>
    +     <string name="data_usage_3g_limit_title" msgid="4361523876818447683">"2G-3G ഡാറ്റ പരിധിയിലെത്തി"</string>
    +     <string name="data_usage_4g_limit_title" msgid="4609566827219442376">"4G ഡാറ്റ പരിധിയിലെത്തി"</string>
    +@@ -1636,6 +1648,7 @@
    +     <string name="search_language_hint" msgid="7042102592055108574">"ഭാഷയുടെ പേര് ടൈപ്പുചെയ്യുക"</string>
    +     <string name="language_picker_section_suggested" msgid="8414489646861640885">"നിര്‍‌ദ്ദേശിച്ചത്"</string>
    +     <string name="language_picker_section_all" msgid="3097279199511617537">"എല്ലാ ഭാഷകളും"</string>
    ++    <string name="region_picker_section_all" msgid="8966316787153001779">"എല്ലാ പ്രദേശങ്ങളും"</string>
    +     <string name="locale_search_menu" msgid="2560710726687249178">"തിരയുക"</string>
    +     <string name="work_mode_off_title" msgid="8954725060677558855">"ഔദ്യോഗിക മോഡ് ഓഫാണ്"</string>
    +     <string name="work_mode_off_message" msgid="3286169091278094476">"ആപ്സും, പശ്ചാത്തല സമന്വയവും ബന്ധപ്പെട്ട ഫീച്ചറുകളും ഉൾപ്പെടെ, ഔദ്യോഗിക പ്രൊഫൈലിനെ പ്രവർത്തിക്കാൻ അനുവദിക്കുക."</string>
    +diff --git a/core/res/res/values-mn-rMN/strings.xml b/core/res/res/values-mn-rMN/strings.xml
    +index 5f384a1..f936b85 100644
    +--- a/core/res/res/values-mn-rMN/strings.xml
    ++++ b/core/res/res/values-mn-rMN/strings.xml
    +@@ -214,6 +214,7 @@
    +     <string name="global_actions" product="default" msgid="2406416831541615258">"Утасны сонголтууд"</string>
    +     <string name="global_action_lock" msgid="2844945191792119712">"Дэлгэцний түгжээ"</string>
    +     <string name="global_action_power_off" msgid="4471879440839879722">"Унтраах"</string>
    ++    <string name="global_action_emergency" msgid="7112311161137421166">"Яаралтай тусламж"</string>
    +     <string name="global_action_bug_report" msgid="7934010578922304799">"Алдаа мэдээллэх"</string>
    +     <string name="bugreport_title" msgid="2667494803742548533">"Согог репорт авах"</string>
    +     <string name="bugreport_message" msgid="398447048750350456">"Энэ таны төхөөрөмжийн одоогийн статусын талаарх мэдээллийг цуглуулах ба имэйл мессеж болгон илгээнэ. Алдааны мэдэгдлээс эхэлж илгээхэд бэлэн болоход хэсэг хугацаа зарцуулагдана тэвчээртэй байна уу."</string>
    +@@ -1076,6 +1077,17 @@
    +     <skip />
    +     <string name="wifi_no_internet" msgid="8451173622563841546">"Wi-Fi-д интернет холболт байхгүй байна"</string>
    +     <string name="wifi_no_internet_detailed" msgid="8083079241212301741">"Сонголт хийхийн тулд товшино уу"</string>
    ++    <string name="network_switch_metered" msgid="4671730921726992671">"<xliff:g id="NETWORK_TYPE">%1$s</xliff:g> руу шилжүүлсэн"</string>
    ++    <string name="network_switch_metered_detail" msgid="5325661434777870353">"<xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> интернэт холболтгүй үед төхөөрөмж <xliff:g id="NEW_NETWORK">%1$s</xliff:g>-г ашигладаг. Төлбөр гарч болзошгүй."</string>
    ++    <string name="network_switch_metered_toast" msgid="5779283181685974304">"<xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g>-с <xliff:g id="NEW_NETWORK">%2$s</xliff:g> руу шилжүүлсэн"</string>
    ++  <string-array name="network_switch_type_name">
    ++    <item msgid="2952042958050315394">"мобайл дата"</item>
    ++    <item msgid="75483255295529161">"Wi-Fi"</item>
    ++    <item msgid="6862614801537202646">"Bluetooth"</item>
    ++    <item msgid="5447331121797802871">"Этернэт"</item>
    ++    <item msgid="8257233890381651999">"VPN"</item>
    ++  </string-array>
    ++    <string name="network_switch_type_name_unknown" msgid="4552612897806660656">"сүлжээний тодорхойгүй төрөл"</string>
    +     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Wi-Fi-д холбогдож чадсангүй"</string>
    +     <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" Интернет холболт муу байна."</string>
    +     <string name="wifi_connect_alert_title" msgid="8455846016001810172">"Холболтыг зөвшөөрөх үү?"</string>
    +@@ -1153,7 +1165,6 @@
    +     <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"Хэл болон бүдүүвчийг сонгохын тулд дарна уу"</string>
    +     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
    +     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
    +-    <string name="candidates_style" msgid="4333913089637062257"><u>"нэр дэвшигч"</u></string>
    +     <string name="ext_media_checking_notification_title" msgid="5734005953288045806">"<xliff:g id="NAME">%s</xliff:g>-ыг бэлдэж байна"</string>
    +     <string name="ext_media_checking_notification_message" msgid="4747432538578886744">"Алдааг шалгаж байна"</string>
    +     <string name="ext_media_new_notification_message" msgid="7589986898808506239">"Шинэ <xliff:g id="NAME">%s</xliff:g> илэрлээ"</string>
    +@@ -1232,8 +1243,9 @@
    +     <string name="vpn_text_long" msgid="4907843483284977618">"<xliff:g id="SESSION">%s</xliff:g>-д холбогдов. Сүлжээг удирдах бол товшино уу."</string>
    +     <string name="vpn_lockdown_connecting" msgid="6443438964440960745">"Байнгын VPN-д холбогдож байна..."</string>
    +     <string name="vpn_lockdown_connected" msgid="8202679674819213931">"Байнга VPN холбоотой"</string>
    ++    <string name="vpn_lockdown_disconnected" msgid="4532298952570796327">"Тогтмол асаалттай VPN салсан"</string>
    +     <string name="vpn_lockdown_error" msgid="6009249814034708175">"Байнгын VPN алдаа"</string>
    +-    <string name="vpn_lockdown_config" msgid="4655589351146766608">"Тохируулахын тулд товшино уу"</string>
    ++    <string name="vpn_lockdown_config" msgid="5099330695245008680">"Тохируулахын тулд товшино уу"</string>
    +     <string name="upload_file" msgid="2897957172366730416">"Файл сонгох"</string>
    +     <string name="no_file_chosen" msgid="6363648562170759465">"Сонгосон файл байхгүй"</string>
    +     <string name="reset" msgid="2448168080964209908">"Бүгдийг цэвэрлэх"</string>
    +@@ -1317,7 +1329,7 @@
    +     <string name="storage_usb_drive_label" msgid="4501418548927759953">"<xliff:g id="MANUFACTURER">%s</xliff:g> USB диск"</string>
    +     <string name="storage_usb" msgid="3017954059538517278">"USB сан"</string>
    +     <string name="extract_edit_menu_button" msgid="8940478730496610137">"Засах"</string>
    +-    <string name="data_usage_warning_title" msgid="1955638862122232342">"Дата хэрэглээний анхааруулга"</string>
    ++    <string name="data_usage_warning_title" msgid="3620440638180218181">"Дата ашиглалтын сануулга"</string>
    +     <string name="data_usage_warning_body" msgid="6660692274311972007">"Хэрэглээ, тохиргоог харах бол товш."</string>
    +     <string name="data_usage_3g_limit_title" msgid="4361523876818447683">"2G-3G дата хязгаарт хүрсэн"</string>
    +     <string name="data_usage_4g_limit_title" msgid="4609566827219442376">"4G дата хязгаарт хүрсэн"</string>
    +@@ -1634,6 +1646,7 @@
    +     <string name="search_language_hint" msgid="7042102592055108574">"Улсын хэлийг бичнэ үү"</string>
    +     <string name="language_picker_section_suggested" msgid="8414489646861640885">"Санал болгосон"</string>
    +     <string name="language_picker_section_all" msgid="3097279199511617537">"Бүх хэл"</string>
    ++    <string name="region_picker_section_all" msgid="8966316787153001779">"Бүх бүс нутаг"</string>
    +     <string name="locale_search_menu" msgid="2560710726687249178">"Хайх"</string>
    +     <string name="work_mode_off_title" msgid="8954725060677558855">"Ажлын горимыг УНТРААСАН байна"</string>
    +     <string name="work_mode_off_message" msgid="3286169091278094476">"Ажлын профайлд апп, дэвсгэр синхрончлол болон бусад холбоотой тохиргоог ажиллахыг зөвшөөрнө үү."</string>
    +diff --git a/core/res/res/values-mr-rIN/strings.xml b/core/res/res/values-mr-rIN/strings.xml
    +index 36d6f6a..8951643 100644
    +--- a/core/res/res/values-mr-rIN/strings.xml
    ++++ b/core/res/res/values-mr-rIN/strings.xml
    +@@ -214,6 +214,7 @@
    +     <string name="global_actions" product="default" msgid="2406416831541615258">"फोन पर्याय"</string>
    +     <string name="global_action_lock" msgid="2844945191792119712">"स्क्रीन लॉक"</string>
    +     <string name="global_action_power_off" msgid="4471879440839879722">"बंद"</string>
    ++    <string name="global_action_emergency" msgid="7112311161137421166">"आणीबाणी"</string>
    +     <string name="global_action_bug_report" msgid="7934010578922304799">"दोष अहवाल"</string>
    +     <string name="bugreport_title" msgid="2667494803742548533">"दोष अहवाल घ्या"</string>
    +     <string name="bugreport_message" msgid="398447048750350456">"ई-मेल संदेश म्हणून पाठविण्यासाठी, हे आपल्या वर्तमान डिव्हाइस स्थितीविषयी माहिती संकलित करेल. दोष अहवाल प्रारंभ करण्यापासून तो पाठविण्यापर्यंत थोडा वेळ लागेल; कृपया धीर धरा."</string>
    +@@ -1074,8 +1075,19 @@
    +     <string name="network_available_sign_in" msgid="1848877297365446605">"नेटवर्कवर साइन इन करा"</string>
    +     <!-- no translation found for network_available_sign_in_detailed (8000081941447976118) -->
    +     <skip />
    +-    <string name="wifi_no_internet" msgid="8451173622563841546">"वाय-फाय मध्‍ये इंटरनेट प्रवेश नाही"</string>
    ++    <string name="wifi_no_internet" msgid="8451173622563841546">"वाय-फायवरून इंटरनेटवर प्रवेश नाही"</string>
    +     <string name="wifi_no_internet_detailed" msgid="8083079241212301741">"पर्यायांसाठी टॅप करा"</string>
    ++    <string name="network_switch_metered" msgid="4671730921726992671">"<xliff:g id="NETWORK_TYPE">%1$s</xliff:g> वर स्विच केले"</string>
    ++    <string name="network_switch_metered_detail" msgid="5325661434777870353">"<xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> कडे इंटरनेट प्रवेश नसताना डिव्हाइस <xliff:g id="NEW_NETWORK">%1$s</xliff:g> वापरतो. शुल्क लागू शकतील."</string>
    ++    <string name="network_switch_metered_toast" msgid="5779283181685974304">"<xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> वरून <xliff:g id="NEW_NETWORK">%2$s</xliff:g> वर स्विच केले"</string>
    ++  <string-array name="network_switch_type_name">
    ++    <item msgid="2952042958050315394">"मोबाइल डेटा"</item>
    ++    <item msgid="75483255295529161">"वाय-फाय"</item>
    ++    <item msgid="6862614801537202646">"ब्लूटुथ"</item>
    ++    <item msgid="5447331121797802871">"इथरनेट"</item>
    ++    <item msgid="8257233890381651999">"VPN"</item>
    ++  </string-array>
    ++    <string name="network_switch_type_name_unknown" msgid="4552612897806660656">"अज्ञात नेटवर्क प्रकार"</string>
    +     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"वाय-फाय ला कनेक्ट करू शकलो नाही"</string>
    +     <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" खराब इंटरनेट कनेक्शन आहे."</string>
    +     <string name="wifi_connect_alert_title" msgid="8455846016001810172">"कनेक्शनला अनुमती द्यायची?"</string>
    +@@ -1153,7 +1165,6 @@
    +     <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"भाषा आणि लेआउट निवडण्यासाठी टॅप करा"</string>
    +     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
    +     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
    +-    <string name="candidates_style" msgid="4333913089637062257"><u>"उमेदवार"</u></string>
    +     <string name="ext_media_checking_notification_title" msgid="5734005953288045806">"<xliff:g id="NAME">%s</xliff:g> तयार करीत आहे"</string>
    +     <string name="ext_media_checking_notification_message" msgid="4747432538578886744">"त्रुटींसाठी तपासत आहे"</string>
    +     <string name="ext_media_new_notification_message" msgid="7589986898808506239">"नवीन <xliff:g id="NAME">%s</xliff:g> आढळले"</string>
    +@@ -1232,8 +1243,9 @@
    +     <string name="vpn_text_long" msgid="4907843483284977618">"<xliff:g id="SESSION">%s</xliff:g> शी कनेक्ट केले. नेटवर्क व्यवस्थापित करण्यासाठी टॅप करा."</string>
    +     <string name="vpn_lockdown_connecting" msgid="6443438964440960745">"VPN कनेक्ट करणे नेहमी-चालू…"</string>
    +     <string name="vpn_lockdown_connected" msgid="8202679674819213931">"VPN कनेक्ट केलेले नेहमी-चालू"</string>
    ++    <string name="vpn_lockdown_disconnected" msgid="4532298952570796327">"नेहमी-चालू असलेले VPN डिस्कनेक्ट केले"</string>
    +     <string name="vpn_lockdown_error" msgid="6009249814034708175">"VPN त्रुटी नेहमी-चालू"</string>
    +-    <string name="vpn_lockdown_config" msgid="4655589351146766608">"कॉन्फिगर करण्यासाठी टॅप करा"</string>
    ++    <string name="vpn_lockdown_config" msgid="5099330695245008680">"सेट करण्यासाठी टॅप करा"</string>
    +     <string name="upload_file" msgid="2897957172366730416">"फाईल निवडा"</string>
    +     <string name="no_file_chosen" msgid="6363648562170759465">"फाईल निवडली नाही"</string>
    +     <string name="reset" msgid="2448168080964209908">"रीसेट करा"</string>
    +@@ -1317,7 +1329,7 @@
    +     <string name="storage_usb_drive_label" msgid="4501418548927759953">"<xliff:g id="MANUFACTURER">%s</xliff:g> USB ड्राइव्‍ह"</string>
    +     <string name="storage_usb" msgid="3017954059538517278">"USB संचयन"</string>
    +     <string name="extract_edit_menu_button" msgid="8940478730496610137">"संपादित करा"</string>
    +-    <string name="data_usage_warning_title" msgid="1955638862122232342">"डेटा वापर चेतावणी"</string>
    ++    <string name="data_usage_warning_title" msgid="3620440638180218181">"डेटा वापर सूचना"</string>
    +     <string name="data_usage_warning_body" msgid="6660692274311972007">"वापर आणि सेटिंग्ज पाहण्यासाठी टॅप करा."</string>
    +     <string name="data_usage_3g_limit_title" msgid="4361523876818447683">"2G-3G डेटा मर्यादा गाठली"</string>
    +     <string name="data_usage_4g_limit_title" msgid="4609566827219442376">"4G डेटा मर्यादा गाठली"</string>
    +@@ -1636,6 +1648,7 @@
    +     <string name="search_language_hint" msgid="7042102592055108574">"भाषा नाव टाइप करा"</string>
    +     <string name="language_picker_section_suggested" msgid="8414489646861640885">"सूचित केलेले"</string>
    +     <string name="language_picker_section_all" msgid="3097279199511617537">"सर्व भाषा"</string>
    ++    <string name="region_picker_section_all" msgid="8966316787153001779">"सर्व प्रदेश"</string>
    +     <string name="locale_search_menu" msgid="2560710726687249178">"शोध"</string>
    +     <string name="work_mode_off_title" msgid="8954725060677558855">"कार्य मोड बंद आहे"</string>
    +     <string name="work_mode_off_message" msgid="3286169091278094476">"कार्य प्रोफाइलला अॅप्स, पार्श्वभूमी संकालन आणि संबंधित वैशिष्ट्यांच्या समावेशासह कार्य करण्याची परवानगी द्या."</string>
    +diff --git a/core/res/res/values-ms-rMY/strings.xml b/core/res/res/values-ms-rMY/strings.xml
    +index 7db5c74..e096aec 100644
    +--- a/core/res/res/values-ms-rMY/strings.xml
    ++++ b/core/res/res/values-ms-rMY/strings.xml
    +@@ -214,6 +214,7 @@
    +     <string name="global_actions" product="default" msgid="2406416831541615258">"Pilihan telefon"</string>
    +     <string name="global_action_lock" msgid="2844945191792119712">"Kunci skrin"</string>
    +     <string name="global_action_power_off" msgid="4471879440839879722">"Matikan kuasa"</string>
    ++    <string name="global_action_emergency" msgid="7112311161137421166">"Kecemasan"</string>
    +     <string name="global_action_bug_report" msgid="7934010578922304799">"Laporan pepijat"</string>
    +     <string name="bugreport_title" msgid="2667494803742548533">"Ambil laporan pepijat"</string>
    +     <string name="bugreport_message" msgid="398447048750350456">"Ini akan mengumpul maklumat tentang keadaan peranti semasa anda untuk dihantarkan sebagai mesej e-mel. Harap bersabar, mungkin perlu sedikit masa untuk memulakan laporan sehingga siap untuk dihantar."</string>
    +@@ -1076,6 +1077,17 @@
    +     <skip />
    +     <string name="wifi_no_internet" msgid="8451173622563841546">"Wi-Fi tiada akses Internet"</string>
    +     <string name="wifi_no_internet_detailed" msgid="8083079241212301741">"Ketik untuk mendapatkan pilihan"</string>
    ++    <string name="network_switch_metered" msgid="4671730921726992671">"Beralih kepada <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
    ++    <string name="network_switch_metered_detail" msgid="5325661434777870353">"Peranti menggunakan <xliff:g id="NEW_NETWORK">%1$s</xliff:g> apabila <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> tiada akses Internet. Bayaran mungkin dikenakan."</string>
    ++    <string name="network_switch_metered_toast" msgid="5779283181685974304">"Beralih daripada <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> kepada <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
    ++  <string-array name="network_switch_type_name">
    ++    <item msgid="2952042958050315394">"data selular"</item>
    ++    <item msgid="75483255295529161">"Wi-Fi"</item>
    ++    <item msgid="6862614801537202646">"Bluetooth"</item>
    ++    <item msgid="5447331121797802871">"Ethernet"</item>
    ++    <item msgid="8257233890381651999">"VPN"</item>
    ++  </string-array>
    ++    <string name="network_switch_type_name_unknown" msgid="4552612897806660656">"jenis rangkaian tidak diketahui"</string>
    +     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Tidak boleh menyambung kepada Wi-Fi"</string>
    +     <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" mempunyai sambungan internet yang kurang baik."</string>
    +     <string name="wifi_connect_alert_title" msgid="8455846016001810172">"Benarkan sambungan?"</string>
    +@@ -1153,7 +1165,6 @@
    +     <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"Ketik untuk memilih bahasa dan susun atur"</string>
    +     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
    +     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
    +-    <string name="candidates_style" msgid="4333913089637062257"><u>"calon"</u></string>
    +     <string name="ext_media_checking_notification_title" msgid="5734005953288045806">"Menyediakan <xliff:g id="NAME">%s</xliff:g>"</string>
    +     <string name="ext_media_checking_notification_message" msgid="4747432538578886744">"Menyemak untuk mengesan ralat"</string>
    +     <string name="ext_media_new_notification_message" msgid="7589986898808506239">"<xliff:g id="NAME">%s</xliff:g> baharu dikesan"</string>
    +@@ -1232,8 +1243,9 @@
    +     <string name="vpn_text_long" msgid="4907843483284977618">"Bersambung kepada <xliff:g id="SESSION">%s</xliff:g>. Ketik untuk mengurus rangkaian."</string>
    +     <string name="vpn_lockdown_connecting" msgid="6443438964440960745">"VPN sentiasa hidup sedang disambungkan..."</string>
    +     <string name="vpn_lockdown_connected" msgid="8202679674819213931">"VPN sentiasa hidup telah disambungkan"</string>
    ++    <string name="vpn_lockdown_disconnected" msgid="4532298952570796327">"VPN sentiasa hidup diputuskan sambungannya"</string>
    +     <string name="vpn_lockdown_error" msgid="6009249814034708175">"Ralat VPN sentiasa hidup"</string>
    +-    <string name="vpn_lockdown_config" msgid="4655589351146766608">"Ketik untuk membuat konfigurasi"</string>
    ++    <string name="vpn_lockdown_config" msgid="5099330695245008680">"Ketik untuk menyediakan"</string>
    +     <string name="upload_file" msgid="2897957172366730416">"Pilih fail"</string>
    +     <string name="no_file_chosen" msgid="6363648562170759465">"Tiada fail dipilih"</string>
    +     <string name="reset" msgid="2448168080964209908">"Tetapkan semula"</string>
    +@@ -1317,7 +1329,7 @@
    +     <string name="storage_usb_drive_label" msgid="4501418548927759953">"Pemacu USB <xliff:g id="MANUFACTURER">%s</xliff:g>"</string>
    +     <string name="storage_usb" msgid="3017954059538517278">"Storan USB"</string>
    +     <string name="extract_edit_menu_button" msgid="8940478730496610137">"Edit"</string>
    +-    <string name="data_usage_warning_title" msgid="1955638862122232342">"Amaran penggunaan data"</string>
    ++    <string name="data_usage_warning_title" msgid="3620440638180218181">"Makluman penggunaan data"</string>
    +     <string name="data_usage_warning_body" msgid="6660692274311972007">"Ketik utk lihat p\'gunaan &amp; ttpn."</string>
    +     <string name="data_usage_3g_limit_title" msgid="4361523876818447683">"Mencapai had data 2G-3G"</string>
    +     <string name="data_usage_4g_limit_title" msgid="4609566827219442376">"Mencapai had data 4G"</string>
    +@@ -1636,6 +1648,7 @@
    +     <string name="search_language_hint" msgid="7042102592055108574">"Taipkan nama bahasa"</string>
    +     <string name="language_picker_section_suggested" msgid="8414489646861640885">"Dicadangkan"</string>
    +     <string name="language_picker_section_all" msgid="3097279199511617537">"Semua bahasa"</string>
    ++    <string name="region_picker_section_all" msgid="8966316787153001779">"Semua rantau"</string>
    +     <string name="locale_search_menu" msgid="2560710726687249178">"Cari"</string>
    +     <string name="work_mode_off_title" msgid="8954725060677558855">"Mod kerja DIMATIKAN"</string>
    +     <string name="work_mode_off_message" msgid="3286169091278094476">"Benarkan profil kerja berfungsi, termasuk apl, penyegerakan latar belakang dan ciri yang berkaitan."</string>
    +diff --git a/core/res/res/values-my-rMM/strings.xml b/core/res/res/values-my-rMM/strings.xml
    +index 077b889..80d331d 100644
    +--- a/core/res/res/values-my-rMM/strings.xml
    ++++ b/core/res/res/values-my-rMM/strings.xml
    +@@ -214,6 +214,7 @@
    +     <string name="global_actions" product="default" msgid="2406416831541615258">"ဖုန်းဆိုင်ရာရွေးချယ်မှုများ"</string>
    +     <string name="global_action_lock" msgid="2844945191792119712">"ဖုန်းမျက်နှာပြင်အား သော့ချရန်"</string>
    +     <string name="global_action_power_off" msgid="4471879440839879722">"ပါဝါပိတ်ရန်"</string>
    ++    <string name="global_action_emergency" msgid="7112311161137421166">"အရေးပေါ်"</string>
    +     <string name="global_action_bug_report" msgid="7934010578922304799">"အမှားရှာဖွေပြင်ဆင်မှုမှတ်တမ်း"</string>
    +     <string name="bugreport_title" msgid="2667494803742548533">"အမှားရှာဖွေပြင်ဆင်မှုမှတ်တမ်းအား ယူရန်"</string>
    +     <string name="bugreport_message" msgid="398447048750350456">"သင့်ရဲ့ လက်ရှိ စက်အခြေအနေ အချက်အလက်များကို အီးမေးလ် အနေဖြင့် ပေးပို့ရန် စုဆောင်းပါမည်။ အမှားရှာဖွေပြင်ဆင်မှုမှတ်တမ်းမှ ပေးပို့ရန် အသင့်ဖြစ်သည်အထိ အချိန် အနည်းငယ်ကြာမြင့်မှာ ဖြစ်သဖြင့် သည်းခံပြီး စောင့်ပါရန်"</string>
    +@@ -1076,6 +1077,17 @@
    +     <skip />
    +     <string name="wifi_no_internet" msgid="8451173622563841546">"ဝိုင်-ဖို်ငတွင် အင်တာနက် ဝင်ရောက်သုံးခွင့် မရှိပါ"</string>
    +     <string name="wifi_no_internet_detailed" msgid="8083079241212301741">"အခြားရွေးချယ်စရာများကိုကြည့်ရန် တို့ပါ"</string>
    ++    <string name="network_switch_metered" msgid="4671730921726992671">"<xliff:g id="NETWORK_TYPE">%1$s</xliff:g> သို့ ပြောင်းလိုက်ပြီ"</string>
    ++    <string name="network_switch_metered_detail" msgid="5325661434777870353">"စက်ပစ္စည်းသည် <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> ဖြင့် အင်တာနက် အသုံးမပြုနိုင်သည့်အချိန်တွင် <xliff:g id="NEW_NETWORK">%1$s</xliff:g> ကို သုံးပါသည်။ ဒေတာသုံးစွဲခ ကျသင့်နိုင်ပါသည်။"</string>
    ++    <string name="network_switch_metered_toast" msgid="5779283181685974304">"<xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> မှ <xliff:g id="NEW_NETWORK">%2$s</xliff:g> သို့ ပြောင်းလိုက်ပြီ"</string>
    ++  <string-array name="network_switch_type_name">
    ++    <item msgid="2952042958050315394">"ဆယ်လူလာဒေတာ"</item>
    ++    <item msgid="75483255295529161">"Wi-Fi"</item>
    ++    <item msgid="6862614801537202646">"ဘလူးတုသ်"</item>
    ++    <item msgid="5447331121797802871">"အီသာနက်"</item>
    ++    <item msgid="8257233890381651999">"VPN"</item>
    ++  </string-array>
    ++    <string name="network_switch_type_name_unknown" msgid="4552612897806660656">"အမည်မသိကွန်ရက်အမျိုးအစား"</string>
    +     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"ဝိုင်ဖိုင်ကိုချိတ်ဆက်မရပါ"</string>
    +     <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" အင်တာနက် ဆက်သွယ်မှု ကောင်းကောင်းမရှိပါ"</string>
    +     <string name="wifi_connect_alert_title" msgid="8455846016001810172">"ချိတ်ဆက်မှုကို ခွင့်ပြုမလား?"</string>
    +@@ -1153,7 +1165,6 @@
    +     <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"ဘာသာစကားနှင့် အသွင်အပြင်ရွေးချယ်ရန် တို့ပါ"</string>
    +     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
    +     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
    +-    <string name="candidates_style" msgid="4333913089637062257"><u>"ရွေးချယ်ခံမည့်သူ"</u></string>
    +     <string name="ext_media_checking_notification_title" msgid="5734005953288045806">"<xliff:g id="NAME">%s</xliff:g> ပြင်ဆင်နေသည်"</string>
    +     <string name="ext_media_checking_notification_message" msgid="4747432538578886744">"အမှားအယွင်းများ စစ်ဆေးနေသည်"</string>
    +     <string name="ext_media_new_notification_message" msgid="7589986898808506239">"<xliff:g id="NAME">%s</xliff:g> အသစ်တွေ့ရှိပါသည်"</string>
    +@@ -1232,8 +1243,9 @@
    +     <string name="vpn_text_long" msgid="4907843483284977618">"<xliff:g id="SESSION">%s</xliff:g> သို့ ချိတ်ဆက်ထားသည်။ ကွန်ရက်ကို စီမံခန့်ခွဲရန် တို့ပါ။"</string>
    +     <string name="vpn_lockdown_connecting" msgid="6443438964440960745">"အမြဲတမ်းဖွင့်ထား VPN ဆက်သွယ်နေစဉ်…"</string>
    +     <string name="vpn_lockdown_connected" msgid="8202679674819213931">"အမြဲတမ်းဖွင့်ထား VPN ဆက်သွယ်မှုရှိ"</string>
    ++    <string name="vpn_lockdown_disconnected" msgid="4532298952570796327">"အမြဲတမ်းဖွင့်ထားရသော VPN ပြတ်တောက်နေသည်"</string>
    +     <string name="vpn_lockdown_error" msgid="6009249814034708175">"အမြဲတမ်းဖွင့်ထား VPN အမှား"</string>
    +-    <string name="vpn_lockdown_config" msgid="4655589351146766608">"ပြင်ဆင်သတ်မှတ်ရန် တို့ပါ"</string>
    ++    <string name="vpn_lockdown_config" msgid="5099330695245008680">"ပြင်ဆင်သတ်မှတ်ရန် တို့ပါ"</string>
    +     <string name="upload_file" msgid="2897957172366730416">"ဖိုင်ရွေးချယ်ရန်"</string>
    +     <string name="no_file_chosen" msgid="6363648562170759465">"မည်သည့်ဖိုင်ကိုမှမရွေးပါ"</string>
    +     <string name="reset" msgid="2448168080964209908">"ပြန်လည်သတ်မှတ်ရန်"</string>
    +@@ -1317,7 +1329,7 @@
    +     <string name="storage_usb_drive_label" msgid="4501418548927759953">"<xliff:g id="MANUFACTURER">%s</xliff:g> USB ဒရိုက်ဗ်"</string>
    +     <string name="storage_usb" msgid="3017954059538517278">"USBဖြင့် သိမ်းဆည်း"</string>
    +     <string name="extract_edit_menu_button" msgid="8940478730496610137">"ပြင်ဆင်ရန်"</string>
    +-    <string name="data_usage_warning_title" msgid="1955638862122232342">"ဒေတာအသုံးပြုမှုသတိပေးချက်"</string>
    ++    <string name="data_usage_warning_title" msgid="3620440638180218181">"ဒေတာအသုံးပြုမှုသတိပေးချက်"</string>
    +     <string name="data_usage_warning_body" msgid="6660692274311972007">"အသုံးပြုမှုနှင့် ဆက်တင်များကိုကြည့်ရန် တို့ပါ။"</string>
    +     <string name="data_usage_3g_limit_title" msgid="4361523876818447683">"2G-3G ဒေတာ ကန့်သတ်ချက် ပြည့်မီသွားပြီ"</string>
    +     <string name="data_usage_4g_limit_title" msgid="4609566827219442376">"4G ဒေတာ ကန့်သတ်ချက် ပြည့်မီသွားပြီ"</string>
    +@@ -1636,6 +1648,7 @@
    +     <string name="search_language_hint" msgid="7042102592055108574">"ဘာသာစကားအမည် ထည့်ပါ"</string>
    +     <string name="language_picker_section_suggested" msgid="8414489646861640885">"အကြံပြုထားသော"</string>
    +     <string name="language_picker_section_all" msgid="3097279199511617537">"ဘာသာစကားများအားလုံး"</string>
    ++    <string name="region_picker_section_all" msgid="8966316787153001779">"ဒေသအားလုံး"</string>
    +     <string name="locale_search_menu" msgid="2560710726687249178">"ရှာဖွေရန်"</string>
    +     <string name="work_mode_off_title" msgid="8954725060677558855">"အလုပ်မုဒ် ပိတ်ထားသည်"</string>
    +     <string name="work_mode_off_message" msgid="3286169091278094476">"အက်ပ်များ၊ နောက်ခံစင့်ခ်လုပ်ခြင်း၊ နှင့်သက်ဆိုင်သည့်အင်္ဂါရပ်များကို ဆောင်ရွက်ရန် အလုပ်ပရိုဖိုင်ကိုခွင့်ပြုပါ။"</string>
    +diff --git a/core/res/res/values-nb/strings.xml b/core/res/res/values-nb/strings.xml
    +index c9b275c..691da31 100644
    +--- a/core/res/res/values-nb/strings.xml
    ++++ b/core/res/res/values-nb/strings.xml
    +@@ -214,6 +214,7 @@
    +     <string name="global_actions" product="default" msgid="2406416831541615258">"Telefoninnstillinger"</string>
    +     <string name="global_action_lock" msgid="2844945191792119712">"Lås skjermen"</string>
    +     <string name="global_action_power_off" msgid="4471879440839879722">"Slå av"</string>
    ++    <string name="global_action_emergency" msgid="7112311161137421166">"Nødssituasjon"</string>
    +     <string name="global_action_bug_report" msgid="7934010578922304799">"Feilrapport"</string>
    +     <string name="bugreport_title" msgid="2667494803742548533">"Utfør feilrapport"</string>
    +     <string name="bugreport_message" msgid="398447048750350456">"Informasjon om tilstanden til enheten din samles inn og sendes som en e-post. Det tar litt tid fra du starter feilrapporten til e-posten er klar, så vær tålmodig."</string>
    +@@ -1076,6 +1077,17 @@
    +     <skip />
    +     <string name="wifi_no_internet" msgid="8451173622563841546">"Wi-Fi har ikke Internett-tilgang"</string>
    +     <string name="wifi_no_internet_detailed" msgid="8083079241212301741">"Trykk for å få alternativer"</string>
    ++    <string name="network_switch_metered" msgid="4671730921726992671">"Byttet til <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
    ++    <string name="network_switch_metered_detail" msgid="5325661434777870353">"Enheten bruker <xliff:g id="NEW_NETWORK">%1$s</xliff:g> når <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> ikke har Internett-tilgang. Avgifter kan påløpe."</string>
    ++    <string name="network_switch_metered_toast" msgid="5779283181685974304">"Byttet fra <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> til <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
    ++  <string-array name="network_switch_type_name">
    ++    <item msgid="2952042958050315394">"mobildata"</item>
    ++    <item msgid="75483255295529161">"Wi-Fi"</item>
    ++    <item msgid="6862614801537202646">"Bluetooth"</item>
    ++    <item msgid="5447331121797802871">"Ethernet"</item>
    ++    <item msgid="8257233890381651999">"VPN"</item>
    ++  </string-array>
    ++    <string name="network_switch_type_name_unknown" msgid="4552612897806660656">"en ukjent nettverkstype"</string>
    +     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Kan ikke koble til Wi-Fi"</string>
    +     <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" har en dårlig Internett-tilkobling."</string>
    +     <string name="wifi_connect_alert_title" msgid="8455846016001810172">"Vil du tillat tilkoblingen?"</string>
    +@@ -1153,7 +1165,6 @@
    +     <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"Trykk for å velge språk og layout"</string>
    +     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZÆØÅ"</string>
    +     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZÆØÅ"</string>
    +-    <string name="candidates_style" msgid="4333913089637062257">"TAG_FONT"<u>"kandidater"</u>"CLOSE_FONT"</string>
    +     <string name="ext_media_checking_notification_title" msgid="5734005953288045806">"Forbereder <xliff:g id="NAME">%s</xliff:g>"</string>
    +     <string name="ext_media_checking_notification_message" msgid="4747432538578886744">"Sjekker for feil"</string>
    +     <string name="ext_media_new_notification_message" msgid="7589986898808506239">"<xliff:g id="NAME">%s</xliff:g> ble oppdaget"</string>
    +@@ -1232,8 +1243,9 @@
    +     <string name="vpn_text_long" msgid="4907843483284977618">"Koblet til <xliff:g id="SESSION">%s</xliff:g>. Trykk for å administrere nettverket."</string>
    +     <string name="vpn_lockdown_connecting" msgid="6443438964440960745">"Alltid-på VPN kobler til ..."</string>
    +     <string name="vpn_lockdown_connected" msgid="8202679674819213931">"Alltid-på VPN er tilkoblet"</string>
    ++    <string name="vpn_lockdown_disconnected" msgid="4532298952570796327">"Alltid på-VPN er frakoblet"</string>
    +     <string name="vpn_lockdown_error" msgid="6009249814034708175">"Alltid-på VPN-feil"</string>
    +-    <string name="vpn_lockdown_config" msgid="4655589351146766608">"Trykk for å konfigurere"</string>
    ++    <string name="vpn_lockdown_config" msgid="5099330695245008680">"Trykk for å konfigurere"</string>
    +     <string name="upload_file" msgid="2897957172366730416">"Velg fil"</string>
    +     <string name="no_file_chosen" msgid="6363648562170759465">"Ingen fil er valgt"</string>
    +     <string name="reset" msgid="2448168080964209908">"Tilbakestill"</string>
    +@@ -1317,7 +1329,7 @@
    +     <string name="storage_usb_drive_label" msgid="4501418548927759953">"<xliff:g id="MANUFACTURER">%s</xliff:g> USB-stasjon"</string>
    +     <string name="storage_usb" msgid="3017954059538517278">"USB-lagring"</string>
    +     <string name="extract_edit_menu_button" msgid="8940478730496610137">"Rediger"</string>
    +-    <string name="data_usage_warning_title" msgid="1955638862122232342">"Advarsel for høyt dataforbruk"</string>
    ++    <string name="data_usage_warning_title" msgid="3620440638180218181">"Varsel om databruk"</string>
    +     <string name="data_usage_warning_body" msgid="6660692274311972007">"Trykk for å se bruken og innstillingene."</string>
    +     <string name="data_usage_3g_limit_title" msgid="4361523876818447683">"Datagrensen for 2G-3G er nådd"</string>
    +     <string name="data_usage_4g_limit_title" msgid="4609566827219442376">"Datagrensen for 4G er nådd"</string>
    +@@ -1636,6 +1648,7 @@
    +     <string name="search_language_hint" msgid="7042102592055108574">"Skriv inn språknavn"</string>
    +     <string name="language_picker_section_suggested" msgid="8414489646861640885">"Foreslått"</string>
    +     <string name="language_picker_section_all" msgid="3097279199511617537">"Alle språk"</string>
    ++    <string name="region_picker_section_all" msgid="8966316787153001779">"Alle områder"</string>
    +     <string name="locale_search_menu" msgid="2560710726687249178">"Søk"</string>
    +     <string name="work_mode_off_title" msgid="8954725060677558855">"Jobbmodus er AV"</string>
    +     <string name="work_mode_off_message" msgid="3286169091278094476">"Slå på jobbprofilen, inkludert apper, synkronisering i bakgrunnen og relaterte funksjoner."</string>
    +diff --git a/core/res/res/values-ne-rNP/strings.xml b/core/res/res/values-ne-rNP/strings.xml
    +index a0dcfeb..3d5cfed 100644
    +--- a/core/res/res/values-ne-rNP/strings.xml
    ++++ b/core/res/res/values-ne-rNP/strings.xml
    +@@ -214,6 +214,7 @@
    +     <string name="global_actions" product="default" msgid="2406416831541615258">"फोन विकल्पहरू"</string>
    +     <string name="global_action_lock" msgid="2844945191792119712">"स्क्रिन बन्द"</string>
    +     <string name="global_action_power_off" msgid="4471879440839879722">"बन्द गर्नुहोस्"</string>
    ++    <string name="global_action_emergency" msgid="7112311161137421166">"आपतकालीन"</string>
    +     <string name="global_action_bug_report" msgid="7934010578922304799">"बग रिपोर्ट"</string>
    +     <string name="bugreport_title" msgid="2667494803742548533">"बग रिपोर्ट लिनुहोस्"</string>
    +     <string name="bugreport_message" msgid="398447048750350456">"एउटा इमेल सन्देशको रूपमा पठाउनलाई यसले तपाईँको हालैको उपकरणको अवस्थाको बारेमा सूचना जम्मा गर्ने छ। बग रिपोर्ट सुरु गरेदेखि पठाउन तयार नभएसम्म यसले केही समय लिन्छ; कृपया धैर्य गर्नुहोस्।"</string>
    +@@ -255,7 +256,7 @@
    +     <string name="permgrouplab_microphone" msgid="171539900250043464">"माइक्रोफोन"</string>
    +     <string name="permgroupdesc_microphone" msgid="4988812113943554584">"अडियो रेकर्ड गर्नुहोस्"</string>
    +     <string name="permgrouplab_camera" msgid="4820372495894586615">"क्यामेरा"</string>
    +-    <string name="permgroupdesc_camera" msgid="3250611594678347720">"तस्बिर खिच्नुहोस् तथा भिडियो रेकर्ड गर्नुहोस्"</string>
    ++    <string name="permgroupdesc_camera" msgid="3250611594678347720">"तस्बिर खिच्नुका साथै भिडियो रेकर्ड गर्नुहोस्"</string>
    +     <string name="permgrouplab_phone" msgid="5229115638567440675">"फोन"</string>
    +     <string name="permgroupdesc_phone" msgid="6234224354060641055">"फोन कलहरू गर्नुहोस् र व्यवस्थापन गर्नुहोस्"</string>
    +     <string name="permgrouplab_sensors" msgid="416037179223226722">"शारीरिक सेन्सर"</string>
    +@@ -1082,6 +1083,17 @@
    +     <skip />
    +     <string name="wifi_no_internet" msgid="8451173622563841546">"Wi-Fi मा इन्टरनेट पहुँच छैन"</string>
    +     <string name="wifi_no_internet_detailed" msgid="8083079241212301741">"विकल्पहरूका लागि ट्याप गर्नुहोस्"</string>
    ++    <string name="network_switch_metered" msgid="4671730921726992671">"<xliff:g id="NETWORK_TYPE">%1$s</xliff:g> मा बदल्नुहोस्"</string>
    ++    <string name="network_switch_metered_detail" msgid="5325661434777870353">"<xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> मा इन्टरनेट माथिको पहुँच नहुँदा यन्त्रले <xliff:g id="NEW_NETWORK">%1$s</xliff:g> को प्रयोग गर्दछ। शुल्कहरू लागू हुन सक्छन्।"</string>
    ++    <string name="network_switch_metered_toast" msgid="5779283181685974304">"<xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> बाट <xliff:g id="NEW_NETWORK">%2$s</xliff:g> मा परिवर्तन गरियो"</string>
    ++  <string-array name="network_switch_type_name">
    ++    <item msgid="2952042958050315394">"सेलुलर डेटा"</item>
    ++    <item msgid="75483255295529161">"Wi-Fi"</item>
    ++    <item msgid="6862614801537202646">"ब्लुटुथ"</item>
    ++    <item msgid="5447331121797802871">"इथरनेट"</item>
    ++    <item msgid="8257233890381651999">"VPN"</item>
    ++  </string-array>
    ++    <string name="network_switch_type_name_unknown" msgid="4552612897806660656">"नेटवर्कको कुनै अज्ञात प्रकार"</string>
    +     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"वाइ-फाइसँग जडान गर्न सकेन"</string>
    +     <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" कमजोर इन्टरनेट जडान छ।"</string>
    +     <string name="wifi_connect_alert_title" msgid="8455846016001810172">"जडान अनुमति दिने हो?"</string>
    +@@ -1159,7 +1171,6 @@
    +     <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"भाषा र लेआउट चयन गर्न ट्याप गर्नुहोस्"</string>
    +     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
    +     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
    +-    <string name="candidates_style" msgid="4333913089637062257"><u>"उम्मेदवार"</u></string>
    +     <string name="ext_media_checking_notification_title" msgid="5734005953288045806">"तयारी गर्दै <xliff:g id="NAME">%s</xliff:g>"</string>
    +     <string name="ext_media_checking_notification_message" msgid="4747432538578886744">"त्रुटिहरूको लागि जाँच गर्दै"</string>
    +     <string name="ext_media_new_notification_message" msgid="7589986898808506239">"नयाँ <xliff:g id="NAME">%s</xliff:g> भेटियो"</string>
    +@@ -1238,8 +1249,9 @@
    +     <string name="vpn_text_long" msgid="4907843483284977618">"<xliff:g id="SESSION">%s</xliff:g>सँग जोडिएको। नेटवर्क प्रबन्ध गर्न हान्नुहोस्।"</string>
    +     <string name="vpn_lockdown_connecting" msgid="6443438964440960745">"VPN जडान सधै जोड्दै…"</string>
    +     <string name="vpn_lockdown_connected" msgid="8202679674819213931">"सधैँ खुल्ला हुने VPN जोडिएको"</string>
    ++    <string name="vpn_lockdown_disconnected" msgid="4532298952570796327">"सधैँ-सक्रिय VPN लाई विच्छेद गरियो"</string>
    +     <string name="vpn_lockdown_error" msgid="6009249814034708175">"सधैँ भरि VPN त्रुटिमा"</string>
    +-    <string name="vpn_lockdown_config" msgid="4655589351146766608">"कन्फिगर गर्न ट्याप गर्नुहोस्"</string>
    ++    <string name="vpn_lockdown_config" msgid="5099330695245008680">"सेट अप गर्न ट्याप गर्नुहोस्"</string>
    +     <string name="upload_file" msgid="2897957172366730416">"फाइल छान्नुहोस्"</string>
    +     <string name="no_file_chosen" msgid="6363648562170759465">"कुनै फाइल छानिएको छैन"</string>
    +     <string name="reset" msgid="2448168080964209908">"पुनःसेट गर्नु"</string>
    +@@ -1323,7 +1335,7 @@
    +     <string name="storage_usb_drive_label" msgid="4501418548927759953">"<xliff:g id="MANUFACTURER">%s</xliff:g> USB ड्राइभ"</string>
    +     <string name="storage_usb" msgid="3017954059538517278">"USB भण्डारण"</string>
    +     <string name="extract_edit_menu_button" msgid="8940478730496610137">"सम्पादन गर्नुहोस्"</string>
    +-    <string name="data_usage_warning_title" msgid="1955638862122232342">"डेटाको प्रयोग चेतावनी"</string>
    ++    <string name="data_usage_warning_title" msgid="3620440638180218181">"डेटा प्रयोग बारे सतर्कता"</string>
    +     <string name="data_usage_warning_body" msgid="6660692274311972007">"प्रयोग र सेटिङहरू हेर्न ट्याप गर्नुहोस्।"</string>
    +     <string name="data_usage_3g_limit_title" msgid="4361523876818447683">"2G-3G डेटा सीमा पुग्यो"</string>
    +     <string name="data_usage_4g_limit_title" msgid="4609566827219442376">"4G डेटा सीमा पुग्यो"</string>
    +@@ -1642,6 +1654,7 @@
    +     <string name="search_language_hint" msgid="7042102592055108574">"भाषाको नाम टाइप गर्नुहोस्"</string>
    +     <string name="language_picker_section_suggested" msgid="8414489646861640885">"सुझाव दिइयो"</string>
    +     <string name="language_picker_section_all" msgid="3097279199511617537">"सम्पूर्ण भाषाहरू"</string>
    ++    <string name="region_picker_section_all" msgid="8966316787153001779">"सबै क्षेत्रहरू"</string>
    +     <string name="locale_search_menu" msgid="2560710726687249178">"खोज"</string>
    +     <string name="work_mode_off_title" msgid="8954725060677558855">"कार्य मोड बन्द छ"</string>
    +     <string name="work_mode_off_message" msgid="3286169091278094476">"अनुप्रयोग, पृष्ठभूमि सिंक र सम्बन्धित विशेषताहरू सहित, कार्य प्रोफाइललाई कार्य गर्न अनुमति दिनुहोस्।"</string>
    +diff --git a/core/res/res/values-nl/strings.xml b/core/res/res/values-nl/strings.xml
    +index d7f10d3..1f53e8d 100644
    +--- a/core/res/res/values-nl/strings.xml
    ++++ b/core/res/res/values-nl/strings.xml
    +@@ -214,6 +214,7 @@
    +     <string name="global_actions" product="default" msgid="2406416831541615258">"Telefoonopties"</string>
    +     <string name="global_action_lock" msgid="2844945191792119712">"Schermvergrendeling"</string>
    +     <string name="global_action_power_off" msgid="4471879440839879722">"Uitschakelen"</string>
    ++    <string name="global_action_emergency" msgid="7112311161137421166">"Noodgeval"</string>
    +     <string name="global_action_bug_report" msgid="7934010578922304799">"Foutenrapport"</string>
    +     <string name="bugreport_title" msgid="2667494803742548533">"Foutenrapport genereren"</string>
    +     <string name="bugreport_message" msgid="398447048750350456">"Hiermee worden gegevens over de huidige status van je apparaat verzameld en als e-mail verzonden. Wanneer u een foutenrapport start, duurt het even voordat het kan worden verzonden. Even geduld alstublieft."</string>
    +@@ -236,7 +237,7 @@
    +     <string name="global_action_voice_assist" msgid="7751191495200504480">"Spraakassistent"</string>
    +     <string name="global_action_lockdown" msgid="8751542514724332873">"Nu vergrendelen"</string>
    +     <string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999 +"</string>
    +-    <string name="notification_hidden_text" msgid="1135169301897151909">"Inhoud verborgen"</string>
    ++    <string name="notification_hidden_text" msgid="1135169301897151909">"Content verborgen"</string>
    +     <string name="notification_hidden_by_policy_text" msgid="9004631276932584600">"Content verborgen op basis van beleid"</string>
    +     <string name="safeMode" msgid="2788228061547930246">"Veilige modus"</string>
    +     <string name="android_system_label" msgid="6577375335728551336">"Android-systeem"</string>
    +@@ -260,12 +261,12 @@
    +     <string name="permgroupdesc_phone" msgid="6234224354060641055">"bellen en telefoontjes beheren"</string>
    +     <string name="permgrouplab_sensors" msgid="416037179223226722">"Lichaamssensoren"</string>
    +     <string name="permgroupdesc_sensors" msgid="7147968539346634043">"toegang krijgen tot sensorgegevens over je vitale functies"</string>
    +-    <string name="capability_title_canRetrieveWindowContent" msgid="3901717936930170320">"Inhoud van vensters ophalen"</string>
    +-    <string name="capability_desc_canRetrieveWindowContent" msgid="3772225008605310672">"De inhoud inspecteren van een venster waarmee je interactie hebt."</string>
    ++    <string name="capability_title_canRetrieveWindowContent" msgid="3901717936930170320">"Content van vensters ophalen"</string>
    ++    <string name="capability_desc_canRetrieveWindowContent" msgid="3772225008605310672">"De content inspecteren van een venster waarmee je interactie hebt."</string>
    +     <string name="capability_title_canRequestTouchExploration" msgid="3108723364676667320">"\'Verkennen via aanraking\' inschakelen"</string>
    +     <string name="capability_desc_canRequestTouchExploration" msgid="7543249041581408313">"Aangetikte items worden hardop benoemd en het scherm kan worden verkend door middel van gebaren."</string>
    +     <string name="capability_title_canRequestEnhancedWebAccessibility" msgid="1739881766522594073">"Verbeterde internettoegankelijkheid inschakelen"</string>
    +-    <string name="capability_desc_canRequestEnhancedWebAccessibility" msgid="7881063961507511765">"Er kunnen scripts worden geïnstalleerd om app-inhoud toegankelijker te maken."</string>
    ++    <string name="capability_desc_canRequestEnhancedWebAccessibility" msgid="7881063961507511765">"Er kunnen scripts worden geïnstalleerd om app-content toegankelijker te maken."</string>
    +     <string name="capability_title_canRequestFilterKeyEvents" msgid="2103440391902412174">"Tekst observeren die u typt"</string>
    +     <string name="capability_desc_canRequestFilterKeyEvents" msgid="7463135292204152818">"Omvat persoonlijke gegevens zoals creditcardnummers en wachtwoorden."</string>
    +     <string name="capability_title_canControlMagnification" msgid="3593493281059424855">"Schermvergroting bedienen"</string>
    +@@ -295,9 +296,9 @@
    +     <string name="permlab_sendSms" msgid="7544599214260982981">"sms\'jes verzenden en bekijken"</string>
    +     <string name="permdesc_sendSms" msgid="7094729298204937667">"Hiermee kan de app sms-berichten verzenden. Dit kan tot onverwachte kosten leiden. Schadelijke apps kunnen u geld kosten doordat ze zonder je bevestiging berichten kunnen verzenden."</string>
    +     <string name="permlab_readSms" msgid="8745086572213270480">"je tekstberichten (SMS of MMS) lezen"</string>
    +-    <string name="permdesc_readSms" product="tablet" msgid="2467981548684735522">"Hiermee kan de app sms-berichten lezen die zijn opgeslagen op je tablet of simkaart. De app kan alle sms-berichten lezen, ongeacht inhoud of vertrouwelijkheid."</string>
    +-    <string name="permdesc_readSms" product="tv" msgid="5102425513647038535">"Hiermee kan de app sms-berichten lezen die zijn opgeslagen op je tv of simkaart. De app kan alle sms-berichten lezen, ongeacht inhoud of vertrouwelijkheid."</string>
    +-    <string name="permdesc_readSms" product="default" msgid="3695967533457240550">"Hiermee kan de app sms-berichten lezen die zijn opgeslagen op je telefoon of simkaart. De app kan alle sms-berichten lezen, ongeacht inhoud of vertrouwelijkheid."</string>
    ++    <string name="permdesc_readSms" product="tablet" msgid="2467981548684735522">"Hiermee kan de app sms-berichten lezen die zijn opgeslagen op je tablet of simkaart. De app kan alle sms-berichten lezen, ongeacht content of vertrouwelijkheid."</string>
    ++    <string name="permdesc_readSms" product="tv" msgid="5102425513647038535">"Hiermee kan de app sms-berichten lezen die zijn opgeslagen op je tv of simkaart. De app kan alle sms-berichten lezen, ongeacht content of vertrouwelijkheid."</string>
    ++    <string name="permdesc_readSms" product="default" msgid="3695967533457240550">"Hiermee kan de app sms-berichten lezen die zijn opgeslagen op je telefoon of simkaart. De app kan alle sms-berichten lezen, ongeacht content of vertrouwelijkheid."</string>
    +     <string name="permlab_receiveWapPush" msgid="5991398711936590410">"tekstberichten (WAP) ontvangen"</string>
    +     <string name="permdesc_receiveWapPush" msgid="748232190220583385">"Hiermee kan de app WAP-berichten ontvangen en verwerken. Dit betekent dat de app berichten die naar je apparaat zijn verzonden, kan bijhouden of verwijderen zonder deze aan u weer te geven."</string>
    +     <string name="permlab_getTasks" msgid="6466095396623933906">"actieve apps ophalen"</string>
    +@@ -459,12 +460,12 @@
    +     <string name="permdesc_writeSyncSettings" msgid="8956262591306369868">"Hiermee kan een app de synchronisatie-instellingen aanpassen voor een account. Deze toestemming kan bijvoorbeeld worden gebruikt om synchronisatie van de app Personen in te schakelen voor een account."</string>
    +     <string name="permlab_readSyncStats" msgid="7396577451360202448">"synchronisatiestatistieken lezen"</string>
    +     <string name="permdesc_readSyncStats" msgid="1510143761757606156">"Hiermee kan een app de synchronisatiestatistieken voor een account lezen, inclusief de geschiedenis van synchronisatie-activiteiten en hoeveel gegevens zijn gesynchroniseerd."</string>
    +-    <string name="permlab_sdcardRead" product="nosdcard" msgid="367275095159405468">"de inhoud van je USB-opslag lezen"</string>
    +-    <string name="permlab_sdcardRead" product="default" msgid="2188156462934977940">"de inhoud van je SD-kaart lezen"</string>
    +-    <string name="permdesc_sdcardRead" product="nosdcard" msgid="3446988712598386079">"De app toestaan de inhoud van je USB-opslag te lezen."</string>
    +-    <string name="permdesc_sdcardRead" product="default" msgid="2607362473654975411">"De app toestaan de inhoud van je SD-kaart te lezen."</string>
    +-    <string name="permlab_sdcardWrite" product="nosdcard" msgid="8485979062254666748">"de inhoud van je USB-opslag aanpassen of verwijderen"</string>
    +-    <string name="permlab_sdcardWrite" product="default" msgid="8805693630050458763">"de inhoud van je SD-kaart aanpassen of verwijderen"</string>
    ++    <string name="permlab_sdcardRead" product="nosdcard" msgid="367275095159405468">"de content van je USB-opslag lezen"</string>
    ++    <string name="permlab_sdcardRead" product="default" msgid="2188156462934977940">"de content van je SD-kaart lezen"</string>
    ++    <string name="permdesc_sdcardRead" product="nosdcard" msgid="3446988712598386079">"De app toestaan de content van je USB-opslag te lezen."</string>
    ++    <string name="permdesc_sdcardRead" product="default" msgid="2607362473654975411">"De app toestaan de content van je SD-kaart te lezen."</string>
    ++    <string name="permlab_sdcardWrite" product="nosdcard" msgid="8485979062254666748">"de content van je USB-opslag aanpassen of verwijderen"</string>
    ++    <string name="permlab_sdcardWrite" product="default" msgid="8805693630050458763">"de content van je SD-kaart aanpassen of verwijderen"</string>
    +     <string name="permdesc_sdcardWrite" product="nosdcard" msgid="6175406299445710888">"Hiermee kan de app schrijven naar de USB-opslag."</string>
    +     <string name="permdesc_sdcardWrite" product="default" msgid="4337417790936632090">"Hiermee kan de app schrijven naar de SD-kaart."</string>
    +     <string name="permlab_use_sip" msgid="2052499390128979920">"SIP-oproepen plaatsen/ontvangen"</string>
    +@@ -1076,6 +1077,17 @@
    +     <skip />
    +     <string name="wifi_no_internet" msgid="8451173622563841546">"Wifi-netwerk heeft geen internettoegang"</string>
    +     <string name="wifi_no_internet_detailed" msgid="8083079241212301741">"Tik voor opties"</string>
    ++    <string name="network_switch_metered" msgid="4671730921726992671">"Overgeschakeld naar <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
    ++    <string name="network_switch_metered_detail" msgid="5325661434777870353">"Apparaat gebruikt <xliff:g id="NEW_NETWORK">%1$s</xliff:g> wanneer <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> geen internetverbinding heeft. Er kunnen kosten in rekening worden gebracht."</string>
    ++    <string name="network_switch_metered_toast" msgid="5779283181685974304">"Overgeschakeld van <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> naar <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
    ++  <string-array name="network_switch_type_name">
    ++    <item msgid="2952042958050315394">"mobiele data"</item>
    ++    <item msgid="75483255295529161">"Wifi"</item>
    ++    <item msgid="6862614801537202646">"Bluetooth"</item>
    ++    <item msgid="5447331121797802871">"Ethernet"</item>
    ++    <item msgid="8257233890381651999">"VPN"</item>
    ++  </string-array>
    ++    <string name="network_switch_type_name_unknown" msgid="4552612897806660656">"een onbekend netwerktype"</string>
    +     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Kan geen verbinding maken met wifi"</string>
    +     <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" heeft een slechte internetverbinding."</string>
    +     <string name="wifi_connect_alert_title" msgid="8455846016001810172">"Verbinding toestaan?"</string>
    +@@ -1153,7 +1165,6 @@
    +     <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"Tik om een taal en indeling te selecteren"</string>
    +     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
    +     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
    +-    <string name="candidates_style" msgid="4333913089637062257"><u>"kandidaten"</u></string>
    +     <string name="ext_media_checking_notification_title" msgid="5734005953288045806">"<xliff:g id="NAME">%s</xliff:g> voorbereiden"</string>
    +     <string name="ext_media_checking_notification_message" msgid="4747432538578886744">"Controleren op fouten"</string>
    +     <string name="ext_media_new_notification_message" msgid="7589986898808506239">"Nieuwe <xliff:g id="NAME">%s</xliff:g> gedetecteerd"</string>
    +@@ -1232,8 +1243,9 @@
    +     <string name="vpn_text_long" msgid="4907843483284977618">"Verbonden met <xliff:g id="SESSION">%s</xliff:g>. Tik om het netwerk te beheren."</string>
    +     <string name="vpn_lockdown_connecting" msgid="6443438964440960745">"Always-on VPN-verbinding maken…"</string>
    +     <string name="vpn_lockdown_connected" msgid="8202679674819213931">"Always-on VPN-verbinding"</string>
    ++    <string name="vpn_lockdown_disconnected" msgid="4532298952570796327">"Always-on VPN-verbinding ontkoppeld"</string>
    +     <string name="vpn_lockdown_error" msgid="6009249814034708175">"Fout met Always-on VPN"</string>
    +-    <string name="vpn_lockdown_config" msgid="4655589351146766608">"Tik om te configureren"</string>
    ++    <string name="vpn_lockdown_config" msgid="5099330695245008680">"Tik om in te stellen"</string>
    +     <string name="upload_file" msgid="2897957172366730416">"Bestand kiezen"</string>
    +     <string name="no_file_chosen" msgid="6363648562170759465">"Geen bestand geselecteerd"</string>
    +     <string name="reset" msgid="2448168080964209908">"Resetten"</string>
    +@@ -1317,7 +1329,7 @@
    +     <string name="storage_usb_drive_label" msgid="4501418548927759953">"<xliff:g id="MANUFACTURER">%s</xliff:g> USB-drive"</string>
    +     <string name="storage_usb" msgid="3017954059538517278">"USB-opslag"</string>
    +     <string name="extract_edit_menu_button" msgid="8940478730496610137">"Bewerken"</string>
    +-    <string name="data_usage_warning_title" msgid="1955638862122232342">"Waarschuwing v. gegevensgebruik"</string>
    ++    <string name="data_usage_warning_title" msgid="3620440638180218181">"Melding voor datagebruik"</string>
    +     <string name="data_usage_warning_body" msgid="6660692274311972007">"Tik voor gebruik en instellingen"</string>
    +     <string name="data_usage_3g_limit_title" msgid="4361523876818447683">"Gegevenslimiet van 2G-3G bereikt"</string>
    +     <string name="data_usage_4g_limit_title" msgid="4609566827219442376">"Gegevenslimiet van 4G bereikt"</string>
    +@@ -1515,7 +1527,7 @@
    +     <string name="mediasize_unknown_portrait" msgid="3088043641616409762">"Onbekend portret"</string>
    +     <string name="mediasize_unknown_landscape" msgid="4876995327029361552">"Onbekend landschap"</string>
    +     <string name="write_fail_reason_cancelled" msgid="7091258378121627624">"Geannuleerd"</string>
    +-    <string name="write_fail_reason_cannot_write" msgid="8132505417935337724">"Fout bij schrijven van inhoud"</string>
    ++    <string name="write_fail_reason_cannot_write" msgid="8132505417935337724">"Fout bij schrijven van content"</string>
    +     <string name="reason_unknown" msgid="6048913880184628119">"onbekend"</string>
    +     <string name="reason_service_unavailable" msgid="7824008732243903268">"Afdrukservice niet ingeschakeld"</string>
    +     <string name="print_service_installed_title" msgid="2246317169444081628">"<xliff:g id="NAME">%s</xliff:g>-service geïnstalleerd"</string>
    +@@ -1636,6 +1648,7 @@
    +     <string name="search_language_hint" msgid="7042102592055108574">"Typ een taalnaam"</string>
    +     <string name="language_picker_section_suggested" msgid="8414489646861640885">"Voorgesteld"</string>
    +     <string name="language_picker_section_all" msgid="3097279199511617537">"Alle talen"</string>
    ++    <string name="region_picker_section_all" msgid="8966316787153001779">"Alle regio\'s"</string>
    +     <string name="locale_search_menu" msgid="2560710726687249178">"Zoeken"</string>
    +     <string name="work_mode_off_title" msgid="8954725060677558855">"Werkmodus is UIT"</string>
    +     <string name="work_mode_off_message" msgid="3286169091278094476">"Functioneren van werkprofiel toestaan, waaronder apps, synchronisatie op de achtergrond en gerelateerde functies."</string>
    +diff --git a/core/res/res/values-pa-rIN/strings.xml b/core/res/res/values-pa-rIN/strings.xml
    +index e717e69..9658e1e 100644
    +--- a/core/res/res/values-pa-rIN/strings.xml
    ++++ b/core/res/res/values-pa-rIN/strings.xml
    +@@ -214,6 +214,7 @@
    +     <string name="global_actions" product="default" msgid="2406416831541615258">"ਫੋਨ ਚੋਣਾਂ"</string>
    +     <string name="global_action_lock" msgid="2844945191792119712">"ਸਕ੍ਰੀਨ ਲੌਕ"</string>
    +     <string name="global_action_power_off" msgid="4471879440839879722">"ਪਾਵਰ ਬੰਦ"</string>
    ++    <string name="global_action_emergency" msgid="7112311161137421166">"ਸੰਕਟਕਾਲ"</string>
    +     <string name="global_action_bug_report" msgid="7934010578922304799">"ਬਗ ਰਿਪੋਰਟ"</string>
    +     <string name="bugreport_title" msgid="2667494803742548533">"ਬਗ ਰਿਪੋਰਟ ਲਓ"</string>
    +     <string name="bugreport_message" msgid="398447048750350456">"ਇਹ ਇੱਕ ਈ-ਮੇਲ ਸੁਨੇਹਾ ਭੇਜਣ ਲਈ, ਤੁਹਾਡੀ ਵਰਤਮਾਨ ਡੀਵਾਈਸ ਬਾਰੇ ਜਾਣਕਾਰੀ ਇਕੱਤਰ ਕਰੇਗਾ। ਬਗ ਰਿਪੋਰਟ ਸ਼ੁਰੂ ਕਰਨ ਵਿੱਚ ਥੋੜ੍ਹਾ ਸਮਾਂ ਲੱਗੇਗਾ ਜਦੋਂ ਤੱਕ ਇਹ ਭੇਜੇ ਜਾਣ ਲਈ ਤਿਆਰ ਨਾ ਹੋਵੇ, ਕਿਰਪਾ ਕਰਕੇ ਧੀਰਜ ਰੱਖੋ।"</string>
    +@@ -362,7 +363,7 @@
    +     <string name="permdesc_accessCoarseLocation" msgid="2538200184373302295">"ਐਪ ਨੂੰ ਤੁਹਾਡਾ ਅਨੁਮਾਨਿਤ ਨਿਰਧਾਰਿਤ ਸਥਾਨ ਪ੍ਰਾਪਤ ਕਰਨ ਦੀ ਆਗਿਆ ਦਿੰਦਾ ਹੈ। ਇਹ ਨਿਰਧਾਰਿਤ ਸਥਾਨ ਨੈੱਟਵਰਕ ਨਿਰਧਾਰਿਤ ਸਥਾਨ ਸਰੋਤ ਵਰਤਦੇ ਹੋਏ ਨਿਰਧਾਰਿਤ ਸਥਾਨ ਸੇਵਾਵਾਂ ਰਾਹੀਂ ਪ੍ਰਾਪਤ ਕੀਤਾ ਜਾਂਦਾ ਹੈ ਜਿਵੇਂ ਸੈਲ ਟਾਵਰ ਅਤੇ Wi-Fi. ਇਹ ਨਿਰਧਾਰਿਤ ਸਥਾਨ ਸੇਵਾਵਾਂ ਚਾਲੂ ਅਤੇ ਐਪ ਨੂੰ ਉਹਨਾਂ ਨੂੰ ਵਰਤਣ ਲਈ ਤੁਹਾਡੀ ਡੀਵਾਈਸ ਤੇ ਹੋਣੀਆਂ ਚਾਹੀਦੀਆਂ ਹਨ। ਐਪਸ ਇਸਦੀ ਵਰਤੋਂ ਇਹ ਅਨੁਮਾਨ ਲਗਾਉਣ ਲਈ ਕਰ ਸਕਦੇ ਹਨ ਕਿ ਤੁਸੀਂ ਕਿੱਥੇ ਹੋ।"</string>
    +     <string name="permlab_modifyAudioSettings" msgid="6095859937069146086">"ਆਪਣੀਆਂ ਔਡੀਓ ਸੈਟਿੰਗਾਂ ਬਦਲੋ"</string>
    +     <string name="permdesc_modifyAudioSettings" msgid="3522565366806248517">"ਔਪ ਨੂੰ ਗਲੋਬਲ ਔਡੀਓ ਸੈਟਿੰਗਾਂ ਸੰਸ਼ੋਧਿਤ ਕਰਨ ਦੀ ਆਗਿਆ ਦਿੰਦਾ ਹੈ ਜਿਵੇਂ ਵੌਲਿਊਮ ਅਤੇ ਆਊਟਪੁਟ ਲਈ ਕਿਹੜਾ ਸਪੀਕਰ ਵਰਤਿਆ ਜਾਂਦਾ ਹੈ।"</string>
    +-    <string name="permlab_recordAudio" msgid="3876049771427466323">"ਔਡੀਓ ਰਿਕਾਰਡ ਕਰੋ"</string>
    ++    <string name="permlab_recordAudio" msgid="3876049771427466323">"ਔਡੀਓ ਰਿਕਾਰਡ ਕਰਨ"</string>
    +     <string name="permdesc_recordAudio" msgid="4906839301087980680">"ਐਪ ਨੂੰ ਮਾਈਕ੍ਰੋਫੋਨ ਨਾਲ ਔਡੀਓ ਰਿਕਾਰਡ ਕਰਨ ਦੀ ਆਗਿਆ ਦਿੰਦਾ ਹੈ। ਇਹ ਅਨੁਮਤੀ ਐਪ ਨੂੰ ਤੁਹਾਡੀ ਪੁਸ਼ਟੀ ਤੋਂ ਬਿਨਾਂ ਕਿਸੇ ਵੀ ਸਮੇਂ ਔਡੀਓ ਰਿਕਾਰਡ ਕਰਨ ਦੀ ਆਗਿਆ ਦਿੰਦੀ ਹੈ।"</string>
    +     <string name="permlab_sim_communication" msgid="2935852302216852065">"SIM ਨੂੰ ਕਮਾਂਡਾਂ ਭੇਜੋ"</string>
    +     <string name="permdesc_sim_communication" msgid="5725159654279639498">"ਐਪ ਨੂੰ SIM ਨੂੰ ਕਮਾਂਡਾਂ ਭੇਜਣ ਦੀ ਆਗਿਆ ਦਿੰਦਾ ਹੈ। ਇਹ ਬਹੁਤ ਘਾਤਕ ਹੈ।"</string>
    +@@ -1076,6 +1077,17 @@
    +     <skip />
    +     <string name="wifi_no_internet" msgid="8451173622563841546">"Wi-Fi ਦੀ ਕੋਈ ਇੰਟਰਨੈਟ ਪਹੁੰਚ ਨਹੀਂ ਹੈ"</string>
    +     <string name="wifi_no_internet_detailed" msgid="8083079241212301741">"ਵਿਕਲਪਾਂ ਲਈ ਟੈਪ ਕਰੋ"</string>
    ++    <string name="network_switch_metered" msgid="4671730921726992671">"ਬਦਲਕੇ <xliff:g id="NETWORK_TYPE">%1$s</xliff:g> ਲਿਆਂਦਾ ਗਿਆ"</string>
    ++    <string name="network_switch_metered_detail" msgid="5325661434777870353">"<xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> ਦੀ ਇੰਟਰਨੈੱਟ \'ਤੇ ਪਹੁੰਚ ਨਾ ਹੋਣ \'ਤੇ ਡੀਵਾਈਸ <xliff:g id="NEW_NETWORK">%1$s</xliff:g> ਦੀ ਵਰਤੋਂ ਕਰਦੀ ਹੈ। ਖਰਚੇ ਲਾਗੂ ਹੋ ਸਕਦੇ ਹਨ।"</string>
    ++    <string name="network_switch_metered_toast" msgid="5779283181685974304">"<xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> ਤੋਂ ਬਦਲਕੇ <xliff:g id="NEW_NETWORK">%2$s</xliff:g> \'ਤੇ ਕੀਤਾ ਗਿਆ"</string>
    ++  <string-array name="network_switch_type_name">
    ++    <item msgid="2952042958050315394">"ਸੈਲਿਊਲਰ ਡੈਟਾ"</item>
    ++    <item msgid="75483255295529161">"Wi-Fi"</item>
    ++    <item msgid="6862614801537202646">"ਬਲੂਟੁੱਥ"</item>
    ++    <item msgid="5447331121797802871">"ਈਥਰਨੈੱਟ"</item>
    ++    <item msgid="8257233890381651999">"VPN"</item>
    ++  </string-array>
    ++    <string name="network_switch_type_name_unknown" msgid="4552612897806660656">"ਇੱਕ ਅਗਿਆਤ ਨੈੱਟਵਰਕ ਕਿਸਮ"</string>
    +     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Wi-Fi ਨਾਲ ਕਨੈਕਟ ਨਹੀਂ ਕਰ ਸਕਿਆ"</string>
    +     <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" ਇਸਦਾ ਇੱਕ ਖ਼ਰਾਬ ਇੰਟਰਨੈਟ ਕਨੈਕਸ਼ਨ ਹੈ।"</string>
    +     <string name="wifi_connect_alert_title" msgid="8455846016001810172">"ਕੀ ਕਨੈਕਸ਼ਨ ਦੀ ਆਗਿਆ ਦੇਣੀ ਹੈ?"</string>
    +@@ -1153,7 +1165,6 @@
    +     <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"ਭਾਸ਼ਾ ਅਤੇ ਖਾਕਾ ਚੁਣਨ ਲਈ ਟੈਪ ਕਰੋ"</string>
    +     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
    +     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
    +-    <string name="candidates_style" msgid="4333913089637062257"><u>"ਉਮੀਦਵਾਰ"</u></string>
    +     <string name="ext_media_checking_notification_title" msgid="5734005953288045806">"<xliff:g id="NAME">%s</xliff:g> ਤਿਆਰ ਹੋ ਰਿਹਾ ਹੈ"</string>
    +     <string name="ext_media_checking_notification_message" msgid="4747432538578886744">"ਤਰੁੱਟੀਆਂ ਦੀ ਜਾਂਚ ਕਰ ਰਿਹਾ ਹੈ"</string>
    +     <string name="ext_media_new_notification_message" msgid="7589986898808506239">"ਨਵੇਂ <xliff:g id="NAME">%s</xliff:g> ਦਾ ਪਤਾ ਲਗਾਇਆ ਗਿਆ"</string>
    +@@ -1232,8 +1243,9 @@
    +     <string name="vpn_text_long" msgid="4907843483284977618">"<xliff:g id="SESSION">%s</xliff:g> ਨਾਲ ਕਨੈਕਟ ਕੀਤਾ ਗਿਆ। ਨੈੱਟਵਰਕ ਦੇ ਪ੍ਰਬੰਧਨ ਲਈ ਟੈਪ ਕਰੋ।"</string>
    +     <string name="vpn_lockdown_connecting" msgid="6443438964440960745">"ਹਮੇਸ਼ਾਂ-ਚਾਲੂ VPN ਕਨੈਕਟ ਕਰ ਰਿਹਾ ਹੈ..."</string>
    +     <string name="vpn_lockdown_connected" msgid="8202679674819213931">"ਹਮੇਸ਼ਾਂ-ਚਾਲੂ VPN ਕਨੈਕਟ ਕੀਤਾ"</string>
    ++    <string name="vpn_lockdown_disconnected" msgid="4532298952570796327">"ਹਮੇਸ਼ਾ-ਚਾਲੂ VPN ਡਿਸਕਨੈਕਟ ਕੀਤਾ ਗਿਆ"</string>
    +     <string name="vpn_lockdown_error" msgid="6009249814034708175">"ਹਮੇਸ਼ਾਂ-ਚਾਲੂ VPN ਅਸ਼ੁੱਧੀ"</string>
    +-    <string name="vpn_lockdown_config" msgid="4655589351146766608">"ਸੰਰੂਪਣ ਲਈ ਟੈਪ ਕਰੋ"</string>
    ++    <string name="vpn_lockdown_config" msgid="5099330695245008680">"ਸਥਾਪਤ ਕਰਨ ਲਈ ਟੈਪ ਕਰੋ"</string>
    +     <string name="upload_file" msgid="2897957172366730416">"ਫਾਈਲ ਚੁਣੋ"</string>
    +     <string name="no_file_chosen" msgid="6363648562170759465">"ਕੋਈ ਫਾਈਲ ਨਹੀਂ ਚੁਣੀ ਗਈ"</string>
    +     <string name="reset" msgid="2448168080964209908">"ਰੀਸੈੱਟ ਕਰੋ"</string>
    +@@ -1317,7 +1329,7 @@
    +     <string name="storage_usb_drive_label" msgid="4501418548927759953">"<xliff:g id="MANUFACTURER">%s</xliff:g> USB ਡ੍ਰਾਇਵ"</string>
    +     <string name="storage_usb" msgid="3017954059538517278">"USB ਸਟੋਰੇਜ"</string>
    +     <string name="extract_edit_menu_button" msgid="8940478730496610137">"ਸੰਪਾਦਿਤ ਕਰੋ"</string>
    +-    <string name="data_usage_warning_title" msgid="1955638862122232342">"ਡੈਟਾ ਉਪਯੋਗ ਚਿਤਾਵਨੀ"</string>
    ++    <string name="data_usage_warning_title" msgid="3620440638180218181">"ਡੈਟਾ ਵਰਤੋਂ ਚੇਤਾਵਨੀ"</string>
    +     <string name="data_usage_warning_body" msgid="6660692274311972007">"ਵਰਤੋਂ ਅਤੇ ਸੈਟਿੰਗਾਂ ਨੂੰ ਵੇਖਣ ਲਈ ਟੈਪ ਕਰੋ।"</string>
    +     <string name="data_usage_3g_limit_title" msgid="4361523876818447683">"2G-3G ਡੈਟਾ ਸੀਮਾ ਪੂਰੀ ਹੋ ਗਈ"</string>
    +     <string name="data_usage_4g_limit_title" msgid="4609566827219442376">"4G ਡੈਟਾ ਸੀਮਾ ਪੂਰੀ ਹੋਈ"</string>
    +@@ -1636,6 +1648,7 @@
    +     <string name="search_language_hint" msgid="7042102592055108574">"ਭਾਸ਼ਾ ਨਾਮ ਟਾਈਪ ਕਰੋ"</string>
    +     <string name="language_picker_section_suggested" msgid="8414489646861640885">"ਸੁਝਾਈਆਂ ਗਈਆਂ"</string>
    +     <string name="language_picker_section_all" msgid="3097279199511617537">"ਸਾਰੀਆਂ ਭਾਸ਼ਾਵਾਂ"</string>
    ++    <string name="region_picker_section_all" msgid="8966316787153001779">"ਸਾਰੇ ਖੇਤਰ"</string>
    +     <string name="locale_search_menu" msgid="2560710726687249178">"ਖੋਜ"</string>
    +     <string name="work_mode_off_title" msgid="8954725060677558855">"ਕੰਮ ਮੋਡ ਬੰਦ ਹੈ"</string>
    +     <string name="work_mode_off_message" msgid="3286169091278094476">"ਐਪਾਂ, ਬੈਕਗ੍ਰਾਊਂਡ ਸਮਕਾਲੀਕਰਨ, ਅਤੇ ਸਬੰਧਿਤ ਵਿਸ਼ੇਸ਼ਤਾਵਾਂ ਸ਼ਾਮਲ ਕਰਦੇ ਹੋਏ ਕੰਮ ਪ੍ਰੋਫਾਈਲ ਨੂੰ ਕੰਮ ਕਰਨ ਦੀ ਮਨਜ਼ੂਰੀ ਦਿਓ।"</string>
    +diff --git a/core/res/res/values-pl/strings.xml b/core/res/res/values-pl/strings.xml
    +index d9e63a6..dbe29ee 100644
    +--- a/core/res/res/values-pl/strings.xml
    ++++ b/core/res/res/values-pl/strings.xml
    +@@ -218,6 +218,7 @@
    +     <string name="global_actions" product="default" msgid="2406416831541615258">"Opcje telefonu"</string>
    +     <string name="global_action_lock" msgid="2844945191792119712">"Blokada ekranu"</string>
    +     <string name="global_action_power_off" msgid="4471879440839879722">"Wyłącz"</string>
    ++    <string name="global_action_emergency" msgid="7112311161137421166">"Alarmowy"</string>
    +     <string name="global_action_bug_report" msgid="7934010578922304799">"Zgłoszenie błędu"</string>
    +     <string name="bugreport_title" msgid="2667494803742548533">"Zgłoś błąd"</string>
    +     <string name="bugreport_message" msgid="398447048750350456">"Informacje o bieżącym stanie urządzenia zostaną zebrane i wysłane e-mailem. Przygotowanie zgłoszenia błędu do wysłania chwilę potrwa, więc zachowaj cierpliwość."</string>
    +@@ -1126,6 +1127,17 @@
    +     <skip />
    +     <string name="wifi_no_internet" msgid="8451173622563841546">"Sieć Wi-Fi nie ma dostępu do internetu"</string>
    +     <string name="wifi_no_internet_detailed" msgid="8083079241212301741">"Kliknij, by wyświetlić opcje"</string>
    ++    <string name="network_switch_metered" msgid="4671730921726992671">"Zmieniono na połączenie typu <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
    ++    <string name="network_switch_metered_detail" msgid="5325661434777870353">"Urządzenie korzysta z połączenia typu <xliff:g id="NEW_NETWORK">%1$s</xliff:g>, gdy <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> nie dostępu do internetu. Mogą zostać naliczone opłaty."</string>
    ++    <string name="network_switch_metered_toast" msgid="5779283181685974304">"Przełączono z połączenia typu <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> na <xliff:g id="NEW_NETWORK">%2$s</xliff:g>."</string>
    ++  <string-array name="network_switch_type_name">
    ++    <item msgid="2952042958050315394">"komórkowa transmisja danych"</item>
    ++    <item msgid="75483255295529161">"Wi-Fi"</item>
    ++    <item msgid="6862614801537202646">"Bluetooth"</item>
    ++    <item msgid="5447331121797802871">"Ethernet"</item>
    ++    <item msgid="8257233890381651999">"VPN"</item>
    ++  </string-array>
    ++    <string name="network_switch_type_name_unknown" msgid="4552612897806660656">"nieznany typ sieci"</string>
    +     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Nie można połączyć się z siecią Wi-Fi."</string>
    +     <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" ma powolne połączenie internetowe."</string>
    +     <string name="wifi_connect_alert_title" msgid="8455846016001810172">"Zezwolić na połączenie?"</string>
    +@@ -1203,7 +1215,6 @@
    +     <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"Kliknij, by wybrać język i układ"</string>
    +     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" AĄBCĆDEĘFGHIJKLŁMNŃOÓPQRSŚTUVWXYZŹŻ"</string>
    +     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
    +-    <string name="candidates_style" msgid="4333913089637062257"><u>"kandydaci"</u></string>
    +     <string name="ext_media_checking_notification_title" msgid="5734005953288045806">"Przygotowuję: <xliff:g id="NAME">%s</xliff:g>"</string>
    +     <string name="ext_media_checking_notification_message" msgid="4747432538578886744">"Sprawdzanie w poszukiwaniu błędów"</string>
    +     <string name="ext_media_new_notification_message" msgid="7589986898808506239">"Wykryto nowy nośnik: <xliff:g id="NAME">%s</xliff:g>"</string>
    +@@ -1282,8 +1293,9 @@
    +     <string name="vpn_text_long" msgid="4907843483284977618">"Nawiązano połączenie: <xliff:g id="SESSION">%s</xliff:g>. Dotknij, aby zarządzać siecią."</string>
    +     <string name="vpn_lockdown_connecting" msgid="6443438964440960745">"Łączę ze stałą siecią VPN…"</string>
    +     <string name="vpn_lockdown_connected" msgid="8202679674819213931">"Połączono ze stałą siecią VPN"</string>
    ++    <string name="vpn_lockdown_disconnected" msgid="4532298952570796327">"Rozłączono ze stałą siecią VPN"</string>
    +     <string name="vpn_lockdown_error" msgid="6009249814034708175">"Błąd stałej sieci VPN"</string>
    +-    <string name="vpn_lockdown_config" msgid="4655589351146766608">"Kliknij, by skonfigurować"</string>
    ++    <string name="vpn_lockdown_config" msgid="5099330695245008680">"Kliknij, by skonfigurować"</string>
    +     <string name="upload_file" msgid="2897957172366730416">"Wybierz plik"</string>
    +     <string name="no_file_chosen" msgid="6363648562170759465">"Nie wybrano pliku"</string>
    +     <string name="reset" msgid="2448168080964209908">"Resetuj"</string>
    +@@ -1369,7 +1381,7 @@
    +     <string name="storage_usb_drive_label" msgid="4501418548927759953">"Dysk USB (<xliff:g id="MANUFACTURER">%s</xliff:g>)"</string>
    +     <string name="storage_usb" msgid="3017954059538517278">"Nośnik USB"</string>
    +     <string name="extract_edit_menu_button" msgid="8940478730496610137">"Edytuj"</string>
    +-    <string name="data_usage_warning_title" msgid="1955638862122232342">"Ostrzeżenie o transmisji danych"</string>
    ++    <string name="data_usage_warning_title" msgid="3620440638180218181">"Alert transmisji danych"</string>
    +     <string name="data_usage_warning_body" msgid="6660692274311972007">"Kliknij, by wyświetlić użycie i ustawienia."</string>
    +     <string name="data_usage_3g_limit_title" msgid="4361523876818447683">"Osiągnięto limit danych 2G/3G"</string>
    +     <string name="data_usage_4g_limit_title" msgid="4609566827219442376">"Osiągnięto limit danych 4G"</string>
    +@@ -1708,6 +1720,7 @@
    +     <string name="search_language_hint" msgid="7042102592055108574">"Wpisz nazwę języka"</string>
    +     <string name="language_picker_section_suggested" msgid="8414489646861640885">"Sugerowane"</string>
    +     <string name="language_picker_section_all" msgid="3097279199511617537">"Wszystkie języki"</string>
    ++    <string name="region_picker_section_all" msgid="8966316787153001779">"Wszystkie kraje"</string>
    +     <string name="locale_search_menu" msgid="2560710726687249178">"Szukaj"</string>
    +     <string name="work_mode_off_title" msgid="8954725060677558855">"Tryb pracy jest WYŁĄCZONY"</string>
    +     <string name="work_mode_off_message" msgid="3286169091278094476">"Włącz profil do pracy, w tym aplikacje, synchronizację w tle i inne funkcje."</string>
    +diff --git a/core/res/res/values-pt-rBR/strings.xml b/core/res/res/values-pt-rBR/strings.xml
    +index eaaad25..4f3b09f 100644
    +--- a/core/res/res/values-pt-rBR/strings.xml
    ++++ b/core/res/res/values-pt-rBR/strings.xml
    +@@ -214,6 +214,7 @@
    +     <string name="global_actions" product="default" msgid="2406416831541615258">"Opções do telefone"</string>
    +     <string name="global_action_lock" msgid="2844945191792119712">"Bloquear tela"</string>
    +     <string name="global_action_power_off" msgid="4471879440839879722">"Desligar"</string>
    ++    <string name="global_action_emergency" msgid="7112311161137421166">"Emergência"</string>
    +     <string name="global_action_bug_report" msgid="7934010578922304799">"Relatório de bugs"</string>
    +     <string name="bugreport_title" msgid="2667494803742548533">"Obter relatório de bugs"</string>
    +     <string name="bugreport_message" msgid="398447048750350456">"Isto coletará informações sobre o estado atual do dispositivo para enviá-las em uma mensagem de e-mail. Após iniciar o relatório de bugs, será necessário aguardar algum tempo até que esteja pronto para ser enviado."</string>
    +@@ -1076,6 +1077,17 @@
    +     <skip />
    +     <string name="wifi_no_internet" msgid="8451173622563841546">"O Wi-Fi não tem acesso à Internet"</string>
    +     <string name="wifi_no_internet_detailed" msgid="8083079241212301741">"Toque para ver opções"</string>
    ++    <string name="network_switch_metered" msgid="4671730921726992671">"Alternado para <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
    ++    <string name="network_switch_metered_detail" msgid="5325661434777870353">"O dispositivo usa <xliff:g id="NEW_NETWORK">%1$s</xliff:g> quando <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> não tem acesso à Internet. Cobranças podem ser aplicadas."</string>
    ++    <string name="network_switch_metered_toast" msgid="5779283181685974304">"Alternado de <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> para <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
    ++  <string-array name="network_switch_type_name">
    ++    <item msgid="2952042958050315394">"dados da rede celular"</item>
    ++    <item msgid="75483255295529161">"Wi-Fi"</item>
    ++    <item msgid="6862614801537202646">"Bluetooth"</item>
    ++    <item msgid="5447331121797802871">"Ethernet"</item>
    ++    <item msgid="8257233890381651999">"VPN"</item>
    ++  </string-array>
    ++    <string name="network_switch_type_name_unknown" msgid="4552612897806660656">"um tipo de rede desconhecido"</string>
    +     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Não foi possível se conectar a redes Wi-Fi"</string>
    +     <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" tem uma conexão de baixa qualidade com a Internet."</string>
    +     <string name="wifi_connect_alert_title" msgid="8455846016001810172">"Permitir conexão?"</string>
    +@@ -1153,7 +1165,6 @@
    +     <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"Toque para selecionar o idioma e o layout"</string>
    +     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
    +     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
    +-    <string name="candidates_style" msgid="4333913089637062257"><u>"candidatos"</u></string>
    +     <string name="ext_media_checking_notification_title" msgid="5734005953288045806">"Preparando <xliff:g id="NAME">%s</xliff:g>"</string>
    +     <string name="ext_media_checking_notification_message" msgid="4747432538578886744">"Procurando erros"</string>
    +     <string name="ext_media_new_notification_message" msgid="7589986898808506239">"Novo <xliff:g id="NAME">%s</xliff:g> detectado"</string>
    +@@ -1232,8 +1243,9 @@
    +     <string name="vpn_text_long" msgid="4907843483284977618">"Conectado a <xliff:g id="SESSION">%s</xliff:g>. Toque para gerenciar a rede."</string>
    +     <string name="vpn_lockdown_connecting" msgid="6443438964440960745">"VPN sempre ativa conectando..."</string>
    +     <string name="vpn_lockdown_connected" msgid="8202679674819213931">"VPN sempre ativa conectada"</string>
    ++    <string name="vpn_lockdown_disconnected" msgid="4532298952570796327">"VPN sempre ativa desconectada"</string>
    +     <string name="vpn_lockdown_error" msgid="6009249814034708175">"Erro na VPN sempre ativa"</string>
    +-    <string name="vpn_lockdown_config" msgid="4655589351146766608">"Toque para configurar"</string>
    ++    <string name="vpn_lockdown_config" msgid="5099330695245008680">"Toque para configurar"</string>
    +     <string name="upload_file" msgid="2897957172366730416">"Escolher arquivo"</string>
    +     <string name="no_file_chosen" msgid="6363648562170759465">"Nenhum arquivo escolhido"</string>
    +     <string name="reset" msgid="2448168080964209908">"Redefinir"</string>
    +@@ -1317,7 +1329,7 @@
    +     <string name="storage_usb_drive_label" msgid="4501418548927759953">"Drive USB <xliff:g id="MANUFACTURER">%s</xliff:g>"</string>
    +     <string name="storage_usb" msgid="3017954059538517278">"Armazenamento USB"</string>
    +     <string name="extract_edit_menu_button" msgid="8940478730496610137">"Editar"</string>
    +-    <string name="data_usage_warning_title" msgid="1955638862122232342">"Aviso sobre uso de dados"</string>
    ++    <string name="data_usage_warning_title" msgid="3620440638180218181">"Alerta de uso de dados"</string>
    +     <string name="data_usage_warning_body" msgid="6660692274311972007">"Toque para ver uso e config."</string>
    +     <string name="data_usage_3g_limit_title" msgid="4361523876818447683">"Limite de dados 2G-3G atingido"</string>
    +     <string name="data_usage_4g_limit_title" msgid="4609566827219442376">"Limite de dados 4G atingido"</string>
    +@@ -1636,6 +1648,7 @@
    +     <string name="search_language_hint" msgid="7042102592055108574">"Digitar nome do idioma"</string>
    +     <string name="language_picker_section_suggested" msgid="8414489646861640885">"Sugeridos"</string>
    +     <string name="language_picker_section_all" msgid="3097279199511617537">"Todos os idiomas"</string>
    ++    <string name="region_picker_section_all" msgid="8966316787153001779">"Todas as regiões"</string>
    +     <string name="locale_search_menu" msgid="2560710726687249178">"Pesquisa"</string>
    +     <string name="work_mode_off_title" msgid="8954725060677558855">"Modo de trabalho DESATIVADO"</string>
    +     <string name="work_mode_off_message" msgid="3286169091278094476">"Permitir que o perfil de trabalho funcione, incluindo apps, sincronização em segundo plano e recursos relacionados"</string>
    +diff --git a/core/res/res/values-pt-rPT/strings.xml b/core/res/res/values-pt-rPT/strings.xml
    +index ae115d8..64db1c2 100644
    +--- a/core/res/res/values-pt-rPT/strings.xml
    ++++ b/core/res/res/values-pt-rPT/strings.xml
    +@@ -214,6 +214,7 @@
    +     <string name="global_actions" product="default" msgid="2406416831541615258">"Opções do telefone"</string>
    +     <string name="global_action_lock" msgid="2844945191792119712">"Bloqueio de ecrã"</string>
    +     <string name="global_action_power_off" msgid="4471879440839879722">"Desligar"</string>
    ++    <string name="global_action_emergency" msgid="7112311161137421166">"Emergência"</string>
    +     <string name="global_action_bug_report" msgid="7934010578922304799">"Relatório de erros"</string>
    +     <string name="bugreport_title" msgid="2667494803742548533">"Criar relatório de erros"</string>
    +     <string name="bugreport_message" msgid="398447048750350456">"Será recolhida informação sobre o estado atual do seu dispositivo a enviar através de uma mensagem de email. Demorará algum tempo até que o relatório de erro esteja pronto para ser enviado. Aguarde um pouco."</string>
    +@@ -1076,6 +1077,17 @@
    +     <skip />
    +     <string name="wifi_no_internet" msgid="8451173622563841546">"O Wi-Fi não tem acesso à Internet"</string>
    +     <string name="wifi_no_internet_detailed" msgid="8083079241212301741">"Toque para obter mais opções"</string>
    ++    <string name="network_switch_metered" msgid="4671730921726992671">"Mudou para <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
    ++    <string name="network_switch_metered_detail" msgid="5325661434777870353">"O dispositivo utiliza <xliff:g id="NEW_NETWORK">%1$s</xliff:g> quando <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> não tem acesso à Internet. Podem ser aplicados custos."</string>
    ++    <string name="network_switch_metered_toast" msgid="5779283181685974304">"Mudou de <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> para <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
    ++  <string-array name="network_switch_type_name">
    ++    <item msgid="2952042958050315394">"dados móveis"</item>
    ++    <item msgid="75483255295529161">"Wi-Fi"</item>
    ++    <item msgid="6862614801537202646">"Bluetooth"</item>
    ++    <item msgid="5447331121797802871">"Ethernet"</item>
    ++    <item msgid="8257233890381651999">"VPN"</item>
    ++  </string-array>
    ++    <string name="network_switch_type_name_unknown" msgid="4552612897806660656">"um tipo de rede desconhecido"</string>
    +     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Não foi possível ligar a Wi-Fi"</string>
    +     <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" tem uma ligação à internet fraca."</string>
    +     <string name="wifi_connect_alert_title" msgid="8455846016001810172">"Permitir ligação?"</string>
    +@@ -1153,7 +1165,6 @@
    +     <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"Toque para selecionar o idioma e o esquema"</string>
    +     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
    +     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
    +-    <string name="candidates_style" msgid="4333913089637062257"><u>"candidatos"</u></string>
    +     <string name="ext_media_checking_notification_title" msgid="5734005953288045806">"A preparar o <xliff:g id="NAME">%s</xliff:g>"</string>
    +     <string name="ext_media_checking_notification_message" msgid="4747432538578886744">"A verificar a presença de erros"</string>
    +     <string name="ext_media_new_notification_message" msgid="7589986898808506239">"Novo <xliff:g id="NAME">%s</xliff:g> detetado"</string>
    +@@ -1232,8 +1243,9 @@
    +     <string name="vpn_text_long" msgid="4907843483284977618">"Ligado a <xliff:g id="SESSION">%s</xliff:g>. Toque para gerir a rede."</string>
    +     <string name="vpn_lockdown_connecting" msgid="6443438964440960745">"A ligar VPN sempre ativa..."</string>
    +     <string name="vpn_lockdown_connected" msgid="8202679674819213931">"VPN sempre ativa ligada"</string>
    ++    <string name="vpn_lockdown_disconnected" msgid="4532298952570796327">"VPN sempre ativa desligada"</string>
    +     <string name="vpn_lockdown_error" msgid="6009249814034708175">"Erro da VPN sempre ativa"</string>
    +-    <string name="vpn_lockdown_config" msgid="4655589351146766608">"Toque para configurar"</string>
    ++    <string name="vpn_lockdown_config" msgid="5099330695245008680">"Tocar para configurar"</string>
    +     <string name="upload_file" msgid="2897957172366730416">"Escolher ficheiro"</string>
    +     <string name="no_file_chosen" msgid="6363648562170759465">"Não foi selecionado nenhum ficheiro"</string>
    +     <string name="reset" msgid="2448168080964209908">"Repor"</string>
    +@@ -1310,14 +1322,14 @@
    +     <string name="action_menu_overflow_description" msgid="2295659037509008453">"Mais opções"</string>
    +     <string name="action_bar_home_description_format" msgid="7965984360903693903">"%1$s, %2$s"</string>
    +     <string name="action_bar_home_subtitle_description_format" msgid="6985546530471780727">"%1$s, %2$s, %3$s"</string>
    +-    <string name="storage_internal" msgid="3570990907910199483">"Armazenamento interno partilhado"</string>
    ++    <string name="storage_internal" msgid="3570990907910199483">"Armazen. interno partilhado"</string>
    +     <string name="storage_sd_card" msgid="3282948861378286745">"Cartão SD"</string>
    +     <string name="storage_sd_card_label" msgid="6347111320774379257">"Cartão SD <xliff:g id="MANUFACTURER">%s</xliff:g>"</string>
    +     <string name="storage_usb_drive" msgid="6261899683292244209">"Unidade USB"</string>
    +     <string name="storage_usb_drive_label" msgid="4501418548927759953">"Unidade USB <xliff:g id="MANUFACTURER">%s</xliff:g>"</string>
    +     <string name="storage_usb" msgid="3017954059538517278">"Armazenamento USB"</string>
    +     <string name="extract_edit_menu_button" msgid="8940478730496610137">"Editar"</string>
    +-    <string name="data_usage_warning_title" msgid="1955638862122232342">"Aviso de utilização de dados"</string>
    ++    <string name="data_usage_warning_title" msgid="3620440638180218181">"Alerta de utilização de dados"</string>
    +     <string name="data_usage_warning_body" msgid="6660692274311972007">"Toque para ver a utilização e definições"</string>
    +     <string name="data_usage_3g_limit_title" msgid="4361523876818447683">"Limite de dados 2G/3G atingido"</string>
    +     <string name="data_usage_4g_limit_title" msgid="4609566827219442376">"Limite de dados 4G atingido"</string>
    +@@ -1636,6 +1648,7 @@
    +     <string name="search_language_hint" msgid="7042102592055108574">"Intr. nome do idioma"</string>
    +     <string name="language_picker_section_suggested" msgid="8414489646861640885">"Sugeridos"</string>
    +     <string name="language_picker_section_all" msgid="3097279199511617537">"Todos os idiomas"</string>
    ++    <string name="region_picker_section_all" msgid="8966316787153001779">"Todas as regiões"</string>
    +     <string name="locale_search_menu" msgid="2560710726687249178">"Pesquisa"</string>
    +     <string name="work_mode_off_title" msgid="8954725060677558855">"Modo de trabalho DESATIVADO"</string>
    +     <string name="work_mode_off_message" msgid="3286169091278094476">"Permitir o funcionamento do perfil de trabalho, incluindo as aplicações, a sincronização em segundo plano e as funcionalidades relacionadas."</string>
    +diff --git a/core/res/res/values-pt/strings.xml b/core/res/res/values-pt/strings.xml
    +index eaaad25..4f3b09f 100644
    +--- a/core/res/res/values-pt/strings.xml
    ++++ b/core/res/res/values-pt/strings.xml
    +@@ -214,6 +214,7 @@
    +     <string name="global_actions" product="default" msgid="2406416831541615258">"Opções do telefone"</string>
    +     <string name="global_action_lock" msgid="2844945191792119712">"Bloquear tela"</string>
    +     <string name="global_action_power_off" msgid="4471879440839879722">"Desligar"</string>
    ++    <string name="global_action_emergency" msgid="7112311161137421166">"Emergência"</string>
    +     <string name="global_action_bug_report" msgid="7934010578922304799">"Relatório de bugs"</string>
    +     <string name="bugreport_title" msgid="2667494803742548533">"Obter relatório de bugs"</string>
    +     <string name="bugreport_message" msgid="398447048750350456">"Isto coletará informações sobre o estado atual do dispositivo para enviá-las em uma mensagem de e-mail. Após iniciar o relatório de bugs, será necessário aguardar algum tempo até que esteja pronto para ser enviado."</string>
    +@@ -1076,6 +1077,17 @@
    +     <skip />
    +     <string name="wifi_no_internet" msgid="8451173622563841546">"O Wi-Fi não tem acesso à Internet"</string>
    +     <string name="wifi_no_internet_detailed" msgid="8083079241212301741">"Toque para ver opções"</string>
    ++    <string name="network_switch_metered" msgid="4671730921726992671">"Alternado para <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
    ++    <string name="network_switch_metered_detail" msgid="5325661434777870353">"O dispositivo usa <xliff:g id="NEW_NETWORK">%1$s</xliff:g> quando <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> não tem acesso à Internet. Cobranças podem ser aplicadas."</string>
    ++    <string name="network_switch_metered_toast" msgid="5779283181685974304">"Alternado de <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> para <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
    ++  <string-array name="network_switch_type_name">
    ++    <item msgid="2952042958050315394">"dados da rede celular"</item>
    ++    <item msgid="75483255295529161">"Wi-Fi"</item>
    ++    <item msgid="6862614801537202646">"Bluetooth"</item>
    ++    <item msgid="5447331121797802871">"Ethernet"</item>
    ++    <item msgid="8257233890381651999">"VPN"</item>
    ++  </string-array>
    ++    <string name="network_switch_type_name_unknown" msgid="4552612897806660656">"um tipo de rede desconhecido"</string>
    +     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Não foi possível se conectar a redes Wi-Fi"</string>
    +     <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" tem uma conexão de baixa qualidade com a Internet."</string>
    +     <string name="wifi_connect_alert_title" msgid="8455846016001810172">"Permitir conexão?"</string>
    +@@ -1153,7 +1165,6 @@
    +     <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"Toque para selecionar o idioma e o layout"</string>
    +     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
    +     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
    +-    <string name="candidates_style" msgid="4333913089637062257"><u>"candidatos"</u></string>
    +     <string name="ext_media_checking_notification_title" msgid="5734005953288045806">"Preparando <xliff:g id="NAME">%s</xliff:g>"</string>
    +     <string name="ext_media_checking_notification_message" msgid="4747432538578886744">"Procurando erros"</string>
    +     <string name="ext_media_new_notification_message" msgid="7589986898808506239">"Novo <xliff:g id="NAME">%s</xliff:g> detectado"</string>
    +@@ -1232,8 +1243,9 @@
    +     <string name="vpn_text_long" msgid="4907843483284977618">"Conectado a <xliff:g id="SESSION">%s</xliff:g>. Toque para gerenciar a rede."</string>
    +     <string name="vpn_lockdown_connecting" msgid="6443438964440960745">"VPN sempre ativa conectando..."</string>
    +     <string name="vpn_lockdown_connected" msgid="8202679674819213931">"VPN sempre ativa conectada"</string>
    ++    <string name="vpn_lockdown_disconnected" msgid="4532298952570796327">"VPN sempre ativa desconectada"</string>
    +     <string name="vpn_lockdown_error" msgid="6009249814034708175">"Erro na VPN sempre ativa"</string>
    +-    <string name="vpn_lockdown_config" msgid="4655589351146766608">"Toque para configurar"</string>
    ++    <string name="vpn_lockdown_config" msgid="5099330695245008680">"Toque para configurar"</string>
    +     <string name="upload_file" msgid="2897957172366730416">"Escolher arquivo"</string>
    +     <string name="no_file_chosen" msgid="6363648562170759465">"Nenhum arquivo escolhido"</string>
    +     <string name="reset" msgid="2448168080964209908">"Redefinir"</string>
    +@@ -1317,7 +1329,7 @@
    +     <string name="storage_usb_drive_label" msgid="4501418548927759953">"Drive USB <xliff:g id="MANUFACTURER">%s</xliff:g>"</string>
    +     <string name="storage_usb" msgid="3017954059538517278">"Armazenamento USB"</string>
    +     <string name="extract_edit_menu_button" msgid="8940478730496610137">"Editar"</string>
    +-    <string name="data_usage_warning_title" msgid="1955638862122232342">"Aviso sobre uso de dados"</string>
    ++    <string name="data_usage_warning_title" msgid="3620440638180218181">"Alerta de uso de dados"</string>
    +     <string name="data_usage_warning_body" msgid="6660692274311972007">"Toque para ver uso e config."</string>
    +     <string name="data_usage_3g_limit_title" msgid="4361523876818447683">"Limite de dados 2G-3G atingido"</string>
    +     <string name="data_usage_4g_limit_title" msgid="4609566827219442376">"Limite de dados 4G atingido"</string>
    +@@ -1636,6 +1648,7 @@
    +     <string name="search_language_hint" msgid="7042102592055108574">"Digitar nome do idioma"</string>
    +     <string name="language_picker_section_suggested" msgid="8414489646861640885">"Sugeridos"</string>
    +     <string name="language_picker_section_all" msgid="3097279199511617537">"Todos os idiomas"</string>
    ++    <string name="region_picker_section_all" msgid="8966316787153001779">"Todas as regiões"</string>
    +     <string name="locale_search_menu" msgid="2560710726687249178">"Pesquisa"</string>
    +     <string name="work_mode_off_title" msgid="8954725060677558855">"Modo de trabalho DESATIVADO"</string>
    +     <string name="work_mode_off_message" msgid="3286169091278094476">"Permitir que o perfil de trabalho funcione, incluindo apps, sincronização em segundo plano e recursos relacionados"</string>
    +diff --git a/core/res/res/values-ro/strings.xml b/core/res/res/values-ro/strings.xml
    +index 6198f12..192d9c1 100644
    +--- a/core/res/res/values-ro/strings.xml
    ++++ b/core/res/res/values-ro/strings.xml
    +@@ -216,6 +216,7 @@
    +     <string name="global_actions" product="default" msgid="2406416831541615258">"Opțiuni telefon"</string>
    +     <string name="global_action_lock" msgid="2844945191792119712">"Blocați ecranul"</string>
    +     <string name="global_action_power_off" msgid="4471879440839879722">"Opriți alimentarea"</string>
    ++    <string name="global_action_emergency" msgid="7112311161137421166">"Urgență"</string>
    +     <string name="global_action_bug_report" msgid="7934010578922304799">"Raport despre erori"</string>
    +     <string name="bugreport_title" msgid="2667494803742548533">"Executați un raport despre erori"</string>
    +     <string name="bugreport_message" msgid="398447048750350456">"Acest raport va colecta informații despre starea actuală a dispozitivului, pentru a le trimite într-un e-mail. Aveți răbdare după pornirea raportului despre erori până când va fi gata de trimis."</string>
    +@@ -1101,6 +1102,17 @@
    +     <skip />
    +     <string name="wifi_no_internet" msgid="8451173622563841546">"Rețeaua Wi-Fi nu are acces la internet"</string>
    +     <string name="wifi_no_internet_detailed" msgid="8083079241212301741">"Atingeți pentru opțiuni"</string>
    ++    <string name="network_switch_metered" msgid="4671730921726992671">"S-a comutat la <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
    ++    <string name="network_switch_metered_detail" msgid="5325661434777870353">"Dispozitivul folosește <xliff:g id="NEW_NETWORK">%1$s</xliff:g> când <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> nu are acces la internet. Se pot aplica taxe."</string>
    ++    <string name="network_switch_metered_toast" msgid="5779283181685974304">"S-a comutat de la <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> la <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
    ++  <string-array name="network_switch_type_name">
    ++    <item msgid="2952042958050315394">"date mobile"</item>
    ++    <item msgid="75483255295529161">"Wi-Fi"</item>
    ++    <item msgid="6862614801537202646">"Bluetooth"</item>
    ++    <item msgid="5447331121797802871">"Ethernet"</item>
    ++    <item msgid="8257233890381651999">"VPN"</item>
    ++  </string-array>
    ++    <string name="network_switch_type_name_unknown" msgid="4552612897806660656">"un tip de rețea necunoscut"</string>
    +     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Nu se poate conecta la Wi-Fi"</string>
    +     <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" are o conexiune la internet slabă."</string>
    +     <string name="wifi_connect_alert_title" msgid="8455846016001810172">"Permiteți conectarea?"</string>
    +@@ -1178,7 +1190,6 @@
    +     <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"Atingeți pentru a selecta limba și aspectul"</string>
    +     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
    +     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
    +-    <string name="candidates_style" msgid="4333913089637062257"><u>"candidați"</u></string>
    +     <string name="ext_media_checking_notification_title" msgid="5734005953288045806">"Se pregătește <xliff:g id="NAME">%s</xliff:g>"</string>
    +     <string name="ext_media_checking_notification_message" msgid="4747432538578886744">"Se verifică dacă există erori"</string>
    +     <string name="ext_media_new_notification_message" msgid="7589986898808506239">"A fost detectat un nou <xliff:g id="NAME">%s</xliff:g>"</string>
    +@@ -1257,8 +1268,9 @@
    +     <string name="vpn_text_long" msgid="4907843483284977618">"Conectat la <xliff:g id="SESSION">%s</xliff:g>. Apăsați pentru a gestiona rețeaua."</string>
    +     <string name="vpn_lockdown_connecting" msgid="6443438964440960745">"Se efectuează conectarea la rețeaua VPN activată permanent…"</string>
    +     <string name="vpn_lockdown_connected" msgid="8202679674819213931">"Conectat(ă) la rețeaua VPN activată permanent"</string>
    ++    <string name="vpn_lockdown_disconnected" msgid="4532298952570796327">"Rețeaua VPN activată permanent a fost deconectată"</string>
    +     <string name="vpn_lockdown_error" msgid="6009249814034708175">"Eroare de rețea VPN activată permanent"</string>
    +-    <string name="vpn_lockdown_config" msgid="4655589351146766608">"Atingeți ca să configurați"</string>
    ++    <string name="vpn_lockdown_config" msgid="5099330695245008680">"Atingeți pentru a configura"</string>
    +     <string name="upload_file" msgid="2897957172366730416">"Alegeți un fișier"</string>
    +     <string name="no_file_chosen" msgid="6363648562170759465">"Nu au fost găsite fișiere"</string>
    +     <string name="reset" msgid="2448168080964209908">"Resetați"</string>
    +@@ -1343,7 +1355,7 @@
    +     <string name="storage_usb_drive_label" msgid="4501418548927759953">"Unitate USB <xliff:g id="MANUFACTURER">%s</xliff:g>"</string>
    +     <string name="storage_usb" msgid="3017954059538517278">"Dsipozitiv de stocare USB"</string>
    +     <string name="extract_edit_menu_button" msgid="8940478730496610137">"Editați"</string>
    +-    <string name="data_usage_warning_title" msgid="1955638862122232342">"Avertisment de utiliz. a datelor"</string>
    ++    <string name="data_usage_warning_title" msgid="3620440638180218181">"Alertă pentru utilizarea datelor"</string>
    +     <string name="data_usage_warning_body" msgid="6660692274311972007">"Atingeți ca să vedeți utilizarea/setările."</string>
    +     <string name="data_usage_3g_limit_title" msgid="4361523876818447683">"Ați atins limita de date 2G-3G"</string>
    +     <string name="data_usage_4g_limit_title" msgid="4609566827219442376">"Ați atins limita de date 4G"</string>
    +@@ -1672,6 +1684,7 @@
    +     <string name="search_language_hint" msgid="7042102592055108574">"Numele limbii"</string>
    +     <string name="language_picker_section_suggested" msgid="8414489646861640885">"Sugerate"</string>
    +     <string name="language_picker_section_all" msgid="3097279199511617537">"Toate limbile"</string>
    ++    <string name="region_picker_section_all" msgid="8966316787153001779">"Toate regiunile"</string>
    +     <string name="locale_search_menu" msgid="2560710726687249178">"Căutați"</string>
    +     <string name="work_mode_off_title" msgid="8954725060677558855">"Modul de serviciu e DEZACTIVAT"</string>
    +     <string name="work_mode_off_message" msgid="3286169091278094476">"Permiteți profilului de serviciu să funcționeze, inclusiv aplicațiile, sincronizarea în fundal și funcțiile asociate."</string>
    +diff --git a/core/res/res/values-ru/strings.xml b/core/res/res/values-ru/strings.xml
    +index 0ef96af..b1b14f9 100644
    +--- a/core/res/res/values-ru/strings.xml
    ++++ b/core/res/res/values-ru/strings.xml
    +@@ -218,6 +218,7 @@
    +     <string name="global_actions" product="default" msgid="2406416831541615258">"Параметры телефона"</string>
    +     <string name="global_action_lock" msgid="2844945191792119712">"Блокировка экрана"</string>
    +     <string name="global_action_power_off" msgid="4471879440839879722">"Отключить питание"</string>
    ++    <string name="global_action_emergency" msgid="7112311161137421166">"Экстренный вызов"</string>
    +     <string name="global_action_bug_report" msgid="7934010578922304799">"Отчет об ошибке"</string>
    +     <string name="bugreport_title" msgid="2667494803742548533">"Отчет об ошибке"</string>
    +     <string name="bugreport_message" msgid="398447048750350456">"Информация о текущем состоянии вашего устройства будет собрана и отправлена по электронной почте. Подготовка отчета займет некоторое время."</string>
    +@@ -1126,6 +1127,17 @@
    +     <skip />
    +     <string name="wifi_no_internet" msgid="8451173622563841546">"Сеть Wi-Fi не подключена к Интернету"</string>
    +     <string name="wifi_no_internet_detailed" msgid="8083079241212301741">"Нажмите, чтобы показать варианты."</string>
    ++    <string name="network_switch_metered" msgid="4671730921726992671">"Новое подключение: <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
    ++    <string name="network_switch_metered_detail" msgid="5325661434777870353">"Устройство использует <xliff:g id="NEW_NETWORK">%1$s</xliff:g>, если подключение к сети <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> недоступно. Может взиматься плата за передачу данных."</string>
    ++    <string name="network_switch_metered_toast" msgid="5779283181685974304">"Устройство отключено от сети <xliff:g id="NEW_NETWORK">%2$s</xliff:g> и теперь использует <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g>"</string>
    ++  <string-array name="network_switch_type_name">
    ++    <item msgid="2952042958050315394">"мобильные данные"</item>
    ++    <item msgid="75483255295529161">"Wi-Fi"</item>
    ++    <item msgid="6862614801537202646">"Bluetooth"</item>
    ++    <item msgid="5447331121797802871">"Ethernet"</item>
    ++    <item msgid="8257233890381651999">"VPN"</item>
    ++  </string-array>
    ++    <string name="network_switch_type_name_unknown" msgid="4552612897806660656">"неизвестный тип сети"</string>
    +     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Не удалось подключиться к сети Wi-Fi"</string>
    +     <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" – плохое интернет-соединение."</string>
    +     <string name="wifi_connect_alert_title" msgid="8455846016001810172">"Разрешить подключение?"</string>
    +@@ -1203,7 +1215,6 @@
    +     <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"Нажмите, чтобы выбрать язык и раскладку"</string>
    +     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
    +     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
    +-    <string name="candidates_style" msgid="4333913089637062257"><u>"варианты"</u></string>
    +     <string name="ext_media_checking_notification_title" msgid="5734005953288045806">"Подготовка карты \"<xliff:g id="NAME">%s</xliff:g>\"…"</string>
    +     <string name="ext_media_checking_notification_message" msgid="4747432538578886744">"Поиск ошибок"</string>
    +     <string name="ext_media_new_notification_message" msgid="7589986898808506239">"Обнаружена новая карта \"<xliff:g id="NAME">%s</xliff:g>\""</string>
    +@@ -1282,8 +1293,9 @@
    +     <string name="vpn_text_long" msgid="4907843483284977618">"Подключено: \"<xliff:g id="SESSION">%s</xliff:g>\". Нажмите здесь, чтобы изменить настройки сети."</string>
    +     <string name="vpn_lockdown_connecting" msgid="6443438964440960745">"Подключение…"</string>
    +     <string name="vpn_lockdown_connected" msgid="8202679674819213931">"Подключено"</string>
    ++    <string name="vpn_lockdown_disconnected" msgid="4532298952570796327">"Отключено"</string>
    +     <string name="vpn_lockdown_error" msgid="6009249814034708175">"Ошибка"</string>
    +-    <string name="vpn_lockdown_config" msgid="4655589351146766608">"Нажмите, чтобы настроить."</string>
    ++    <string name="vpn_lockdown_config" msgid="5099330695245008680">"Нажмите, чтобы настроить"</string>
    +     <string name="upload_file" msgid="2897957172366730416">"Выбрать файл"</string>
    +     <string name="no_file_chosen" msgid="6363648562170759465">"Не выбран файл"</string>
    +     <string name="reset" msgid="2448168080964209908">"Сбросить"</string>
    +@@ -1369,7 +1381,7 @@
    +     <string name="storage_usb_drive_label" msgid="4501418548927759953">"USB-накопитель <xliff:g id="MANUFACTURER">%s</xliff:g>"</string>
    +     <string name="storage_usb" msgid="3017954059538517278">"USB-накопитель"</string>
    +     <string name="extract_edit_menu_button" msgid="8940478730496610137">"Изменить"</string>
    +-    <string name="data_usage_warning_title" msgid="1955638862122232342">"Осталось мало трафика"</string>
    ++    <string name="data_usage_warning_title" msgid="3620440638180218181">"Лимит на передачу данных"</string>
    +     <string name="data_usage_warning_body" msgid="6660692274311972007">"Нажмите, чтобы проверить трафик и настройки."</string>
    +     <string name="data_usage_3g_limit_title" msgid="4361523876818447683">"Достигнут лимит трафика 2G/3G"</string>
    +     <string name="data_usage_4g_limit_title" msgid="4609566827219442376">"Достигнут лимит трафика 4G"</string>
    +@@ -1708,6 +1720,7 @@
    +     <string name="search_language_hint" msgid="7042102592055108574">"Введите язык"</string>
    +     <string name="language_picker_section_suggested" msgid="8414489646861640885">"Рекомендуемые"</string>
    +     <string name="language_picker_section_all" msgid="3097279199511617537">"Все языки"</string>
    ++    <string name="region_picker_section_all" msgid="8966316787153001779">"Все регионы"</string>
    +     <string name="locale_search_menu" msgid="2560710726687249178">"Поиск"</string>
    +     <string name="work_mode_off_title" msgid="8954725060677558855">"Рабочий режим отключен"</string>
    +     <string name="work_mode_off_message" msgid="3286169091278094476">"Включить рабочий профиль: приложения, фоновую синхронизацию и связанные функции."</string>
    +diff --git a/core/res/res/values-si-rLK/strings.xml b/core/res/res/values-si-rLK/strings.xml
    +index 4f90b57..f3c8e7b 100644
    +--- a/core/res/res/values-si-rLK/strings.xml
    ++++ b/core/res/res/values-si-rLK/strings.xml
    +@@ -214,6 +214,7 @@
    +     <string name="global_actions" product="default" msgid="2406416831541615258">"දුරකථන විකල්ප"</string>
    +     <string name="global_action_lock" msgid="2844945191792119712">"තිර අගුල"</string>
    +     <string name="global_action_power_off" msgid="4471879440839879722">"බලය අක්‍රිය කරන්න"</string>
    ++    <string name="global_action_emergency" msgid="7112311161137421166">"හදිසි"</string>
    +     <string name="global_action_bug_report" msgid="7934010578922304799">"දෝෂ වර්තාව"</string>
    +     <string name="bugreport_title" msgid="2667494803742548533">"දෝෂ වාර්තාවක් ගන්න"</string>
    +     <string name="bugreport_message" msgid="398447048750350456">"ඊ-තැපැල් පණිවිඩයක් ලෙස යැවීමට මෙය ඔබගේ වත්මන් උපාංග තත්වය ගැන තොරතුරු එකතු කරනු ඇත. දෝෂ වාර්තාව ආරම්භ කර එය යැවීමට සූදානම් කරන තෙක් එයට කිසියම් කාලයක් ගතවනු ඇත; කරුණාකර ඉවසන්න."</string>
    +@@ -1078,6 +1079,17 @@
    +     <skip />
    +     <string name="wifi_no_internet" msgid="8451173622563841546">"Wi-Fi හට අන්තර්ජාල ප්‍රවේශය නැත"</string>
    +     <string name="wifi_no_internet_detailed" msgid="8083079241212301741">"විකල්ප සඳහා තට්ටු කරන්න"</string>
    ++    <string name="network_switch_metered" msgid="4671730921726992671">"<xliff:g id="NETWORK_TYPE">%1$s</xliff:g> වෙත මාරු විය"</string>
    ++    <string name="network_switch_metered_detail" msgid="5325661434777870353">"උපාංගය <xliff:g id="NEW_NETWORK">%1$s</xliff:g> <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> සඳහා අන්තර්ජාල ප්‍රවේශය නැති විට භාවිත කරයි. ගාස්තු අදාළ විය හැකිය."</string>
    ++    <string name="network_switch_metered_toast" msgid="5779283181685974304">"<xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> සිට <xliff:g id="NEW_NETWORK">%2$s</xliff:g> වෙත මාරු විය"</string>
    ++  <string-array name="network_switch_type_name">
    ++    <item msgid="2952042958050315394">"සෙලියුලර් දත්ත"</item>
    ++    <item msgid="75483255295529161">"Wi-Fi"</item>
    ++    <item msgid="6862614801537202646">"බ්ලූටූත්"</item>
    ++    <item msgid="5447331121797802871">"ඊතර්නෙට්"</item>
    ++    <item msgid="8257233890381651999">"VPN"</item>
    ++  </string-array>
    ++    <string name="network_switch_type_name_unknown" msgid="4552612897806660656">"නොදන්නා ජාල වර්ගයකි"</string>
    +     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Wi-Fi වෙත සම්බන්ධ විය නොහැක"</string>
    +     <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" දුබල අන්තර්ජාල සම්බන්ධතාවයක් ඇත."</string>
    +     <string name="wifi_connect_alert_title" msgid="8455846016001810172">"සම්බන්ධතාවයට ඉඩ දෙන්නද?"</string>
    +@@ -1155,7 +1167,6 @@
    +     <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"භාෂාව හා පිරිසැලසුම තේරීමට තට්ටු කරන්න"</string>
    +     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
    +     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
    +-    <string name="candidates_style" msgid="4333913089637062257"><u>"අපේක්ෂකයන්"</u></string>
    +     <string name="ext_media_checking_notification_title" msgid="5734005953288045806">"<xliff:g id="NAME">%s</xliff:g> සූදානම් කරමින්"</string>
    +     <string name="ext_media_checking_notification_message" msgid="4747432538578886744">"වැරදි සඳහා පරීක්ෂා කරමින්"</string>
    +     <string name="ext_media_new_notification_message" msgid="7589986898808506239">"නව <xliff:g id="NAME">%s</xliff:g> අනාවරණය කරන ලදි"</string>
    +@@ -1234,8 +1245,9 @@
    +     <string name="vpn_text_long" msgid="4907843483284977618">"<xliff:g id="SESSION">%s</xliff:g> වෙත සම්බන්ධිතයි. ජාලය කළමනාකරණය කිරීමට තට්ටු කරන්න."</string>
    +     <string name="vpn_lockdown_connecting" msgid="6443438964440960745">"සැමවිටම VPN සම්බන්ධ වෙමින්…"</string>
    +     <string name="vpn_lockdown_connected" msgid="8202679674819213931">"නිරතුරුවම VPN සම්බන්ධ කර ඇත"</string>
    ++    <string name="vpn_lockdown_disconnected" msgid="4532298952570796327">"සැමවිට ක්‍රියාත්මක VPN විසන්ධි කරන ලදී"</string>
    +     <string name="vpn_lockdown_error" msgid="6009249814034708175">"සැමවිට සක්‍රිය VPN දෝෂය"</string>
    +-    <string name="vpn_lockdown_config" msgid="4655589351146766608">"වින්‍යාස කිරීමට තට්ටු කරන්න"</string>
    ++    <string name="vpn_lockdown_config" msgid="5099330695245008680">"පිහිටුවීමට තට්ටු කරන්න"</string>
    +     <string name="upload_file" msgid="2897957172366730416">"ගොනුව තෝරන්න"</string>
    +     <string name="no_file_chosen" msgid="6363648562170759465">"ගොනුවක් තෝරාගෙන නැත"</string>
    +     <string name="reset" msgid="2448168080964209908">"යළි පිහිටුවන්න"</string>
    +@@ -1319,7 +1331,7 @@
    +     <string name="storage_usb_drive_label" msgid="4501418548927759953">"<xliff:g id="MANUFACTURER">%s</xliff:g> USB ධාවකය"</string>
    +     <string name="storage_usb" msgid="3017954059538517278">"USB ආචයනය"</string>
    +     <string name="extract_edit_menu_button" msgid="8940478730496610137">"සංස්කරණය කරන්න"</string>
    +-    <string name="data_usage_warning_title" msgid="1955638862122232342">"දත්ත භාවිතා අවවාදය"</string>
    ++    <string name="data_usage_warning_title" msgid="3620440638180218181">"දත්ත භාවිතය ගැන ඇඟවීම"</string>
    +     <string name="data_usage_warning_body" msgid="6660692274311972007">"භාවිතය සහ සැකසීම් බැලීමට තට්ටු කරන්න."</string>
    +     <string name="data_usage_3g_limit_title" msgid="4361523876818447683">"2G-3G දත්ත සීමාවට ළඟාවී ඇත"</string>
    +     <string name="data_usage_4g_limit_title" msgid="4609566827219442376">"4G දත්ත සීමාවට ළඟාවී ඇත"</string>
    +@@ -1638,6 +1650,7 @@
    +     <string name="search_language_hint" msgid="7042102592055108574">"භාෂා නම ටයිප් කරන්න"</string>
    +     <string name="language_picker_section_suggested" msgid="8414489646861640885">"යෝජිත"</string>
    +     <string name="language_picker_section_all" msgid="3097279199511617537">"සියලු භාෂා"</string>
    ++    <string name="region_picker_section_all" msgid="8966316787153001779">"සියලු ප්‍රදේශ"</string>
    +     <string name="locale_search_menu" msgid="2560710726687249178">"සෙවීම"</string>
    +     <string name="work_mode_off_title" msgid="8954725060677558855">"වැඩ ප්‍රකාරය ක්‍රියාවිරහිතයි"</string>
    +     <string name="work_mode_off_message" msgid="3286169091278094476">"යෙදුම්, පසුබිම සමමුහුර්ත කිරීම, සහ සම්බන්ධිත විශේෂාංග ඇතුළුව, ක්‍රියා කිරීමට කාර්යාල පැතිකඩට ඉඩ දෙන්න"</string>
    +diff --git a/core/res/res/values-sk/strings.xml b/core/res/res/values-sk/strings.xml
    +index 0a48693..a94c3b4 100644
    +--- a/core/res/res/values-sk/strings.xml
    ++++ b/core/res/res/values-sk/strings.xml
    +@@ -218,6 +218,7 @@
    +     <string name="global_actions" product="default" msgid="2406416831541615258">"Možnosti telefónu"</string>
    +     <string name="global_action_lock" msgid="2844945191792119712">"Zámka obrazovky"</string>
    +     <string name="global_action_power_off" msgid="4471879440839879722">"Vypnúť"</string>
    ++    <string name="global_action_emergency" msgid="7112311161137421166">"Tiesňové volanie"</string>
    +     <string name="global_action_bug_report" msgid="7934010578922304799">"Hlásenie o chybách"</string>
    +     <string name="bugreport_title" msgid="2667494803742548533">"Vytvoriť hlásenie chyby"</string>
    +     <string name="bugreport_message" msgid="398447048750350456">"Týmto zhromaždíte informácie o aktuálnom stave zariadenia. Informácie je potom možné odoslať e-mailom, chvíľu však potrvá, kým bude hlásenie chyby pripravené na odoslanie. Prosíme vás preto o trpezlivosť."</string>
    +@@ -1126,6 +1127,17 @@
    +     <skip />
    +     <string name="wifi_no_internet" msgid="8451173622563841546">"Sieť Wi-Fi nemá prístup k internetu"</string>
    +     <string name="wifi_no_internet_detailed" msgid="8083079241212301741">"Klepnutím získate možnosti"</string>
    ++    <string name="network_switch_metered" msgid="4671730921726992671">"Prepnuté na sieť: <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
    ++    <string name="network_switch_metered_detail" msgid="5325661434777870353">"Keď sieť <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> nemá prístup k internetu, zariadenie používa sieť <xliff:g id="NEW_NETWORK">%1$s</xliff:g>. Môžu sa účtovať poplatky."</string>
    ++    <string name="network_switch_metered_toast" msgid="5779283181685974304">"Prepnuté zo siete <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> na sieť <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
    ++  <string-array name="network_switch_type_name">
    ++    <item msgid="2952042958050315394">"mobilné dáta"</item>
    ++    <item msgid="75483255295529161">"Wi-Fi"</item>
    ++    <item msgid="6862614801537202646">"Bluetooth"</item>
    ++    <item msgid="5447331121797802871">"Ethernet"</item>
    ++    <item msgid="8257233890381651999">"VPN"</item>
    ++  </string-array>
    ++    <string name="network_switch_type_name_unknown" msgid="4552612897806660656">"neznámy typ siete"</string>
    +     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Nepodarilo sa pripojiť k sieti Wi-Fi"</string>
    +     <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" má nekvalitné internetové pripojenie."</string>
    +     <string name="wifi_connect_alert_title" msgid="8455846016001810172">"Povoliť pripojenie?"</string>
    +@@ -1203,7 +1215,6 @@
    +     <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"Klepnutím vyberte jazyk a rozloženie"</string>
    +     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" AÁÄBCČDĎDZDŽEÉFGHCHIÍJKLĽMNŇOÓÔPRŔSŠTŤUÚVWXYÝZŽ"</string>
    +     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
    +-    <string name="candidates_style" msgid="4333913089637062257"><u>"kandidáti"</u></string>
    +     <string name="ext_media_checking_notification_title" msgid="5734005953288045806">"Pripravuje sa úložisko <xliff:g id="NAME">%s</xliff:g>"</string>
    +     <string name="ext_media_checking_notification_message" msgid="4747432538578886744">"Prebieha kontrola chýb"</string>
    +     <string name="ext_media_new_notification_message" msgid="7589986898808506239">"Bolo zistené nové úložisko <xliff:g id="NAME">%s</xliff:g>"</string>
    +@@ -1282,8 +1293,9 @@
    +     <string name="vpn_text_long" msgid="4907843483284977618">"Pripojené k relácii <xliff:g id="SESSION">%s</xliff:g>. Po klepnutí môžete sieť spravovať."</string>
    +     <string name="vpn_lockdown_connecting" msgid="6443438964440960745">"Pripájanie k vždy zapnutej sieti VPN…"</string>
    +     <string name="vpn_lockdown_connected" msgid="8202679674819213931">"Pripojenie k vždy zapnutej sieti VPN"</string>
    ++    <string name="vpn_lockdown_disconnected" msgid="4532298952570796327">"Vždy zapnutá sieť VPN bola odpojená"</string>
    +     <string name="vpn_lockdown_error" msgid="6009249814034708175">"Chyba vždy zapnutej siete VPN"</string>
    +-    <string name="vpn_lockdown_config" msgid="4655589351146766608">"Klepnutím spustíte konfiguráciu"</string>
    ++    <string name="vpn_lockdown_config" msgid="5099330695245008680">"Klepnutím prejdete do Nastavení"</string>
    +     <string name="upload_file" msgid="2897957172366730416">"Zvoliť súbor"</string>
    +     <string name="no_file_chosen" msgid="6363648562170759465">"Nie je vybratý žiadny súbor"</string>
    +     <string name="reset" msgid="2448168080964209908">"Obnoviť"</string>
    +@@ -1369,7 +1381,7 @@
    +     <string name="storage_usb_drive_label" msgid="4501418548927759953">"Disk USB <xliff:g id="MANUFACTURER">%s</xliff:g>"</string>
    +     <string name="storage_usb" msgid="3017954059538517278">"Ukladací priestor USB"</string>
    +     <string name="extract_edit_menu_button" msgid="8940478730496610137">"Upraviť"</string>
    +-    <string name="data_usage_warning_title" msgid="1955638862122232342">"Upozornenie o využití dát"</string>
    ++    <string name="data_usage_warning_title" msgid="3620440638180218181">"Upozornenie na spotrebu dát"</string>
    +     <string name="data_usage_warning_body" msgid="6660692274311972007">"Klepnutím zobrazíte využitie a nastavenia."</string>
    +     <string name="data_usage_3g_limit_title" msgid="4361523876818447683">"Bol dosiahnutý limit 2G–3G"</string>
    +     <string name="data_usage_4g_limit_title" msgid="4609566827219442376">"Bol dosiahnutý limit 4G"</string>
    +@@ -1664,7 +1676,7 @@
    +     </plurals>
    +     <string name="zen_mode_until" msgid="7336308492289875088">"Do <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
    +     <string name="zen_mode_alarm" msgid="9128205721301330797">"Do <xliff:g id="FORMATTEDTIME">%1$s</xliff:g> (ďalší budík)"</string>
    +-    <string name="zen_mode_forever" msgid="7420011936770086993">"Dokým túto funkciu nevypnete"</string>
    ++    <string name="zen_mode_forever" msgid="7420011936770086993">"Kým túto funkciu nevypnete"</string>
    +     <string name="zen_mode_forever_dnd" msgid="3792132696572189081">"Dokým nevypnete stav Nerušiť"</string>
    +     <string name="zen_mode_rule_name_combination" msgid="191109939968076477">"<xliff:g id="FIRST">%1$s</xliff:g> / <xliff:g id="REST">%2$s</xliff:g>"</string>
    +     <string name="toolbar_collapse_description" msgid="2821479483960330739">"Zbaliť"</string>
    +@@ -1708,6 +1720,7 @@
    +     <string name="search_language_hint" msgid="7042102592055108574">"Zadajte názov jazyka"</string>
    +     <string name="language_picker_section_suggested" msgid="8414489646861640885">"Navrhované"</string>
    +     <string name="language_picker_section_all" msgid="3097279199511617537">"Všetky jazyky"</string>
    ++    <string name="region_picker_section_all" msgid="8966316787153001779">"Všetky regióny"</string>
    +     <string name="locale_search_menu" msgid="2560710726687249178">"Vyhľadávanie"</string>
    +     <string name="work_mode_off_title" msgid="8954725060677558855">"Pracovný režim je VYPNUTÝ"</string>
    +     <string name="work_mode_off_message" msgid="3286169091278094476">"Povoľte fungovanie pracovného profilu vrátane aplikácií, synchronizácie na pozadí a súvisiacich funkcií."</string>
    +diff --git a/core/res/res/values-sl/strings.xml b/core/res/res/values-sl/strings.xml
    +index 7b8a03a..a19643b 100644
    +--- a/core/res/res/values-sl/strings.xml
    ++++ b/core/res/res/values-sl/strings.xml
    +@@ -218,6 +218,7 @@
    +     <string name="global_actions" product="default" msgid="2406416831541615258">"Možnosti telefona"</string>
    +     <string name="global_action_lock" msgid="2844945191792119712">"Zaklep zaslona"</string>
    +     <string name="global_action_power_off" msgid="4471879440839879722">"Izklopi"</string>
    ++    <string name="global_action_emergency" msgid="7112311161137421166">"Klic v sili"</string>
    +     <string name="global_action_bug_report" msgid="7934010578922304799">"Poročilo o napakah"</string>
    +     <string name="bugreport_title" msgid="2667494803742548533">"Ustvari poročilo o napakah"</string>
    +     <string name="bugreport_message" msgid="398447048750350456">"S tem bodo zbrani podatki o trenutnem stanju naprave, ki bodo poslani v e-poštnem sporočilu. Izvedba poročila o napakah in priprava trajata nekaj časa, zato bodite potrpežljivi."</string>
    +@@ -1126,6 +1127,17 @@
    +     <skip />
    +     <string name="wifi_no_internet" msgid="8451173622563841546">"Omrežje Wi-Fi nima dostopa do interneta"</string>
    +     <string name="wifi_no_internet_detailed" msgid="8083079241212301741">"Dotaknite se za možnosti"</string>
    ++    <string name="network_switch_metered" msgid="4671730921726992671">"Preklopljeno na omrežje vrste <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
    ++    <string name="network_switch_metered_detail" msgid="5325661434777870353">"Naprava uporabi omrežje vrste <xliff:g id="NEW_NETWORK">%1$s</xliff:g>, ko omrežje vrste <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> nima dostopa do interneta. Prenos podatkov se lahko zaračuna posebej."</string>
    ++    <string name="network_switch_metered_toast" msgid="5779283181685974304">"Preklopljeno z omrežja vrste <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> na omrežje vrste <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
    ++  <string-array name="network_switch_type_name">
    ++    <item msgid="2952042958050315394">"prenos podatkov v mobilnih omrežjih"</item>
    ++    <item msgid="75483255295529161">"Wi-Fi"</item>
    ++    <item msgid="6862614801537202646">"Bluetooth"</item>
    ++    <item msgid="5447331121797802871">"Ethernet"</item>
    ++    <item msgid="8257233890381651999">"VPN"</item>
    ++  </string-array>
    ++    <string name="network_switch_type_name_unknown" msgid="4552612897806660656">"neznana vrsta omrežja"</string>
    +     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Z omrežjem Wi-Fi se ni mogoče povezati"</string>
    +     <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" ima slabo internetno povezavo."</string>
    +     <string name="wifi_connect_alert_title" msgid="8455846016001810172">"Ali dovolite vzpostavitev povezave?"</string>
    +@@ -1203,7 +1215,6 @@
    +     <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"Dotaknite se, če želite izbrati jezik in postavitev."</string>
    +     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
    +     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
    +-    <string name="candidates_style" msgid="4333913089637062257"><u>"kandidati"</u></string>
    +     <string name="ext_media_checking_notification_title" msgid="5734005953288045806">"Pripravljanje shrambe <xliff:g id="NAME">%s</xliff:g>"</string>
    +     <string name="ext_media_checking_notification_message" msgid="4747432538578886744">"Iskanje napak"</string>
    +     <string name="ext_media_new_notification_message" msgid="7589986898808506239">"Zaznana je bila nova shramba <xliff:g id="NAME">%s</xliff:g>"</string>
    +@@ -1282,8 +1293,9 @@
    +     <string name="vpn_text_long" msgid="4907843483284977618">"Povezan z mestom <xliff:g id="SESSION">%s</xliff:g>. Tapnite za upravljanje omrežja."</string>
    +     <string name="vpn_lockdown_connecting" msgid="6443438964440960745">"Povezovanje v stalno vklopljeno navidezno zasebno omrežje ..."</string>
    +     <string name="vpn_lockdown_connected" msgid="8202679674819213931">"Vzpostavljena povezava v stalno vklopljeno navidezno zasebno omrežje"</string>
    ++    <string name="vpn_lockdown_disconnected" msgid="4532298952570796327">"Povezava s stalno vklopljenim VPN-jem je prekinjena"</string>
    +     <string name="vpn_lockdown_error" msgid="6009249814034708175">"Napaka stalno vklopljenega navideznega zasebnega omrežja"</string>
    +-    <string name="vpn_lockdown_config" msgid="4655589351146766608">"Dotanite se, če želite konfigurirati"</string>
    ++    <string name="vpn_lockdown_config" msgid="5099330695245008680">"Dotaknite se, če želite nastaviti"</string>
    +     <string name="upload_file" msgid="2897957172366730416">"Izberi datoteko"</string>
    +     <string name="no_file_chosen" msgid="6363648562170759465">"Nobena datoteka ni izbrana"</string>
    +     <string name="reset" msgid="2448168080964209908">"Ponastavi"</string>
    +@@ -1369,7 +1381,7 @@
    +     <string name="storage_usb_drive_label" msgid="4501418548927759953">"Pogon USB <xliff:g id="MANUFACTURER">%s</xliff:g>"</string>
    +     <string name="storage_usb" msgid="3017954059538517278">"Pomnilnik USB"</string>
    +     <string name="extract_edit_menu_button" msgid="8940478730496610137">"Uredi"</string>
    +-    <string name="data_usage_warning_title" msgid="1955638862122232342">"Opozorilo o uporabi podatkov"</string>
    ++    <string name="data_usage_warning_title" msgid="3620440638180218181">"Opozorilo o preneseni količini podatkov"</string>
    +     <string name="data_usage_warning_body" msgid="6660692274311972007">"Dot. se za ogled upor. in nast."</string>
    +     <string name="data_usage_3g_limit_title" msgid="4361523876818447683">"Dosežena pod. omejitev za 2G/3G"</string>
    +     <string name="data_usage_4g_limit_title" msgid="4609566827219442376">"Dosežena pod. omejitev za 4G"</string>
    +@@ -1708,6 +1720,7 @@
    +     <string name="search_language_hint" msgid="7042102592055108574">"Vnesite ime jezika"</string>
    +     <string name="language_picker_section_suggested" msgid="8414489646861640885">"Predlagano"</string>
    +     <string name="language_picker_section_all" msgid="3097279199511617537">"Vsi jeziki"</string>
    ++    <string name="region_picker_section_all" msgid="8966316787153001779">"Vse regije"</string>
    +     <string name="locale_search_menu" msgid="2560710726687249178">"Išči"</string>
    +     <string name="work_mode_off_title" msgid="8954725060677558855">"Delovni način IZKLOPLJEN"</string>
    +     <string name="work_mode_off_message" msgid="3286169091278094476">"Dovoljeno delovanje delovnega profila, vključno z aplikacijami, sinhronizacijo v ozadju in povezanimi funkcijami."</string>
    +diff --git a/core/res/res/values-sq-rAL/strings.xml b/core/res/res/values-sq-rAL/strings.xml
    +index 05f0e59..624b004 100644
    +--- a/core/res/res/values-sq-rAL/strings.xml
    ++++ b/core/res/res/values-sq-rAL/strings.xml
    +@@ -214,6 +214,7 @@
    +     <string name="global_actions" product="default" msgid="2406416831541615258">"Opsionet e telefonit"</string>
    +     <string name="global_action_lock" msgid="2844945191792119712">"Kyçja e ekranit"</string>
    +     <string name="global_action_power_off" msgid="4471879440839879722">"Fik"</string>
    ++    <string name="global_action_emergency" msgid="7112311161137421166">"Urgjenca"</string>
    +     <string name="global_action_bug_report" msgid="7934010578922304799">"Raporti i defekteve në kod"</string>
    +     <string name="bugreport_title" msgid="2667494803742548533">"Merr raportin e defekteve në kod"</string>
    +     <string name="bugreport_message" msgid="398447048750350456">"Ky funksion mundëson mbledhjen e informacioneve mbi gjendjen aktuale të pajisjes për ta dërguar si mesazh mail-i. Do të duhet pak kohë nga nisja e raportit të defekteve në kod. Faleminderit për durimin."</string>
    +@@ -1076,6 +1077,17 @@
    +     <skip />
    +     <string name="wifi_no_internet" msgid="8451173622563841546">"Wi-Fi nuk ka qasje në internet"</string>
    +     <string name="wifi_no_internet_detailed" msgid="8083079241212301741">"Trokit për opsionet"</string>
    ++    <string name="network_switch_metered" msgid="4671730921726992671">"Kaloi te <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
    ++    <string name="network_switch_metered_detail" msgid="5325661434777870353">"Pajisja përdor <xliff:g id="NEW_NETWORK">%1$s</xliff:g> kur <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> nuk ka qasje në internet. Mund të zbatohen tarifa."</string>
    ++    <string name="network_switch_metered_toast" msgid="5779283181685974304">"Kaloi nga <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> te <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
    ++  <string-array name="network_switch_type_name">
    ++    <item msgid="2952042958050315394">"të dhënat celulare"</item>
    ++    <item msgid="75483255295529161">"Wi-Fi"</item>
    ++    <item msgid="6862614801537202646">"Bluetooth"</item>
    ++    <item msgid="5447331121797802871">"Eternet"</item>
    ++    <item msgid="8257233890381651999">"VPN"</item>
    ++  </string-array>
    ++    <string name="network_switch_type_name_unknown" msgid="4552612897806660656">"një lloj rrjeti i panjohur"</string>
    +     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Nuk mund të lidhej me Wi-Fi"</string>
    +     <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" ka një lidhje të dobët interneti."</string>
    +     <string name="wifi_connect_alert_title" msgid="8455846016001810172">"Të lejohet lidhja?"</string>
    +@@ -1153,7 +1165,6 @@
    +     <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"Trokit për të zgjedhur gjuhën dhe strukturën"</string>
    +     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
    +     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
    +-    <string name="candidates_style" msgid="4333913089637062257"><u>"kandidatë"</u></string>
    +     <string name="ext_media_checking_notification_title" msgid="5734005953288045806">"Po përgatit <xliff:g id="NAME">%s</xliff:g>"</string>
    +     <string name="ext_media_checking_notification_message" msgid="4747432538578886744">"Po kontrollon për gabime"</string>
    +     <string name="ext_media_new_notification_message" msgid="7589986898808506239">"U zbulua karta e re <xliff:g id="NAME">%s</xliff:g>"</string>
    +@@ -1232,8 +1243,9 @@
    +     <string name="vpn_text_long" msgid="4907843483284977618">"Lidhur me <xliff:g id="SESSION">%s</xliff:g>. Trokit për të menaxhuar rrjetin."</string>
    +     <string name="vpn_lockdown_connecting" msgid="6443438964440960745">"Po lidh VPN-në për aktivizim të përhershëm…"</string>
    +     <string name="vpn_lockdown_connected" msgid="8202679674819213931">"VPN e lidhur në mënyrë të përhershme"</string>
    ++    <string name="vpn_lockdown_disconnected" msgid="4532298952570796327">"Rrjeti VPN gjithmonë aktiv u shkëput"</string>
    +     <string name="vpn_lockdown_error" msgid="6009249814034708175">"Gabimi VPN-je për aktivizimin e përhershëm"</string>
    +-    <string name="vpn_lockdown_config" msgid="4655589351146766608">"Trokit për të konfiguruar"</string>
    ++    <string name="vpn_lockdown_config" msgid="5099330695245008680">"Trokit për ta konfiguruar"</string>
    +     <string name="upload_file" msgid="2897957172366730416">"Zgjidh skedarin"</string>
    +     <string name="no_file_chosen" msgid="6363648562170759465">"Nuk u zgjodh asnjë skedar"</string>
    +     <string name="reset" msgid="2448168080964209908">"Rivendos"</string>
    +@@ -1317,7 +1329,7 @@
    +     <string name="storage_usb_drive_label" msgid="4501418548927759953">"USB-ja nga <xliff:g id="MANUFACTURER">%s</xliff:g>"</string>
    +     <string name="storage_usb" msgid="3017954059538517278">"Hapësira ruajtëse e USB-së"</string>
    +     <string name="extract_edit_menu_button" msgid="8940478730496610137">"Redakto"</string>
    +-    <string name="data_usage_warning_title" msgid="1955638862122232342">"Paralajmërim për përdorimin e të dhënave"</string>
    ++    <string name="data_usage_warning_title" msgid="3620440638180218181">"Sinjalizimi i të dhënave"</string>
    +     <string name="data_usage_warning_body" msgid="6660692274311972007">"Trokit për të parë përdorimin dhe cilësimet."</string>
    +     <string name="data_usage_3g_limit_title" msgid="4361523876818447683">"Kufiri i të dhënave 2G-3G u arrit"</string>
    +     <string name="data_usage_4g_limit_title" msgid="4609566827219442376">"Kufiri i të dhënave 4G u arrit"</string>
    +@@ -1636,6 +1648,7 @@
    +     <string name="search_language_hint" msgid="7042102592055108574">"Shkruaj emrin e gjuhës"</string>
    +     <string name="language_picker_section_suggested" msgid="8414489646861640885">"Sugjeruar"</string>
    +     <string name="language_picker_section_all" msgid="3097279199511617537">"Të gjitha gjuhët"</string>
    ++    <string name="region_picker_section_all" msgid="8966316787153001779">"Të gjitha rajonet"</string>
    +     <string name="locale_search_menu" msgid="2560710726687249178">"Kërko"</string>
    +     <string name="work_mode_off_title" msgid="8954725060677558855">"Modaliteti i punës është JOAKTIV"</string>
    +     <string name="work_mode_off_message" msgid="3286169091278094476">"Lejoje profilin e punës të funksionojë, duke përfshirë aplikacionet, sinkronizimin në sfond dhe funksionet e lidhura."</string>
    +diff --git a/core/res/res/values-sr/strings.xml b/core/res/res/values-sr/strings.xml
    +index 517d777..395b049 100644
    +--- a/core/res/res/values-sr/strings.xml
    ++++ b/core/res/res/values-sr/strings.xml
    +@@ -152,7 +152,7 @@
    +     <string name="httpErrorAuth" msgid="1435065629438044534">"Није могуће потврдити аутентичност."</string>
    +     <string name="httpErrorProxyAuth" msgid="1788207010559081331">"Потврда идентитета преко прокси сервера није успела."</string>
    +     <string name="httpErrorConnect" msgid="8714273236364640549">"Није могуће повезати се са сервером."</string>
    +-    <string name="httpErrorIO" msgid="2340558197489302188">"Није могуће комуницирати са сервером. Покушајте поново касније."</string>
    ++    <string name="httpErrorIO" msgid="2340558197489302188">"Није могуће комуницирати са сервером. Пробајте поново касније."</string>
    +     <string name="httpErrorTimeout" msgid="4743403703762883954">"Веза са сервером је истекла."</string>
    +     <string name="httpErrorRedirectLoop" msgid="8679596090392779516">"Страница садржи превише веза за преусмеравање са сервера."</string>
    +     <string name="httpErrorUnsupportedScheme" msgid="5015730812906192208">"Протокол није подржан."</string>
    +@@ -160,7 +160,7 @@
    +     <string name="httpErrorBadUrl" msgid="3636929722728881972">"Страницу није могуће отворити зато што је URL адреса неважећа."</string>
    +     <string name="httpErrorFile" msgid="2170788515052558676">"Није могуће приступити датотеци."</string>
    +     <string name="httpErrorFileNotFound" msgid="6203856612042655084">"Није могуће пронаћи тражену датотеку."</string>
    +-    <string name="httpErrorTooManyRequests" msgid="1235396927087188253">"Превише захтева се обрађује. Покушајте поново касније."</string>
    ++    <string name="httpErrorTooManyRequests" msgid="1235396927087188253">"Превише захтева се обрађује. Пробајте поново касније."</string>
    +     <string name="notification_title" msgid="8967710025036163822">"Грешка при пријављивању за <xliff:g id="ACCOUNT">%1$s</xliff:g>"</string>
    +     <string name="contentServiceSync" msgid="8353523060269335667">"Синхронизација"</string>
    +     <string name="contentServiceSyncNotificationTitle" msgid="397743349191901458">"Синхронизација"</string>
    +@@ -216,6 +216,7 @@
    +     <string name="global_actions" product="default" msgid="2406416831541615258">"Опције телефона"</string>
    +     <string name="global_action_lock" msgid="2844945191792119712">"Закључај екран"</string>
    +     <string name="global_action_power_off" msgid="4471879440839879722">"Искључи"</string>
    ++    <string name="global_action_emergency" msgid="7112311161137421166">"Хитни позив"</string>
    +     <string name="global_action_bug_report" msgid="7934010578922304799">"Извештај о грешци"</string>
    +     <string name="bugreport_title" msgid="2667494803742548533">"Направи извештај о грешци"</string>
    +     <string name="bugreport_message" msgid="398447048750350456">"Овим ће се прикупити информације о тренутном стању уређаја како би биле послате у поруци е-поште. Од започињања извештаја о грешци до тренутка за његово слање проћи ће неко време; будите стрпљиви."</string>
    +@@ -256,9 +257,9 @@
    +     <string name="permgrouplab_storage" msgid="1971118770546336966">"Складиште"</string>
    +     <string name="permgroupdesc_storage" msgid="637758554581589203">"приступа сликама, медијима и датотекама на уређају"</string>
    +     <string name="permgrouplab_microphone" msgid="171539900250043464">"Микрофон"</string>
    +-    <string name="permgroupdesc_microphone" msgid="4988812113943554584">"снима аудио снимке"</string>
    ++    <string name="permgroupdesc_microphone" msgid="4988812113943554584">"снима аудио"</string>
    +     <string name="permgrouplab_camera" msgid="4820372495894586615">"Камера"</string>
    +-    <string name="permgroupdesc_camera" msgid="3250611594678347720">"снима слике и видео снимке"</string>
    ++    <string name="permgroupdesc_camera" msgid="3250611594678347720">"снима слике и видео"</string>
    +     <string name="permgrouplab_phone" msgid="5229115638567440675">"Телефон"</string>
    +     <string name="permgroupdesc_phone" msgid="6234224354060641055">"упућује телефонске позиве и управља њима"</string>
    +     <string name="permgrouplab_sensors" msgid="416037179223226722">"Сензори за тело"</string>
    +@@ -439,19 +440,19 @@
    +     <string name="permdesc_manageFingerprint" msgid="178208705828055464">"Дозвољава апликацији да активира методе за додавање и брисање шаблона отисака прстију који ће се користити."</string>
    +     <string name="permlab_useFingerprint" msgid="3150478619915124905">"користи хардвер за отиске прстију"</string>
    +     <string name="permdesc_useFingerprint" msgid="9165097460730684114">"Дозвољава апликацији да користи хардвер за отиске прстију ради потврде аутентичности"</string>
    +-    <string name="fingerprint_acquired_partial" msgid="735082772341716043">"Откривен је делимични отисак прста. Покушајте поново."</string>
    +-    <string name="fingerprint_acquired_insufficient" msgid="4596546021310923214">"Није успела обрада отиска прста. Покушајте поново."</string>
    ++    <string name="fingerprint_acquired_partial" msgid="735082772341716043">"Откривен је делимични отисак прста. Пробајте поново."</string>
    ++    <string name="fingerprint_acquired_insufficient" msgid="4596546021310923214">"Није успела обрада отиска прста. Пробајте поново."</string>
    +     <string name="fingerprint_acquired_imager_dirty" msgid="1087209702421076105">"Сензор за отиске прстију је прљав. Очистите га и покушајте поново."</string>
    +-    <string name="fingerprint_acquired_too_fast" msgid="6470642383109155969">"Пребрзо сте померили прст. Покушајте поново."</string>
    +-    <string name="fingerprint_acquired_too_slow" msgid="59250885689661653">"Превише споро сте померили прст. Покушајте поново."</string>
    ++    <string name="fingerprint_acquired_too_fast" msgid="6470642383109155969">"Пребрзо сте померили прст. Пробајте поново."</string>
    ++    <string name="fingerprint_acquired_too_slow" msgid="59250885689661653">"Превише споро сте померили прст. Пробајте поново."</string>
    +   <string-array name="fingerprint_acquired_vendor">
    +   </string-array>
    +     <string name="fingerprint_error_hw_not_available" msgid="7955921658939936596">"Хардвер за отиске прстију није доступан."</string>
    +     <string name="fingerprint_error_no_space" msgid="1055819001126053318">"Није могуће сачувати отисак прста. Уклоните неки од постојећих отисака прстију."</string>
    +-    <string name="fingerprint_error_timeout" msgid="3927186043737732875">"Временско ограничење за отисак прста је истекло. Покушајте поново."</string>
    ++    <string name="fingerprint_error_timeout" msgid="3927186043737732875">"Временско ограничење за отисак прста је истекло. Пробајте поново."</string>
    +     <string name="fingerprint_error_canceled" msgid="4402024612660774395">"Радња са отиском прста је отказана."</string>
    +-    <string name="fingerprint_error_lockout" msgid="5536934748136933450">"Превише покушаја. Покушајте поново касније."</string>
    +-    <string name="fingerprint_error_unable_to_process" msgid="6107816084103552441">"Покушајте поново."</string>
    ++    <string name="fingerprint_error_lockout" msgid="5536934748136933450">"Превише покушаја. Пробајте поново касније."</string>
    ++    <string name="fingerprint_error_unable_to_process" msgid="6107816084103552441">"Пробајте поново."</string>
    +     <string name="fingerprint_name_template" msgid="5870957565512716938">"Прст <xliff:g id="FINGERID">%d</xliff:g>"</string>
    +   <string-array name="fingerprint_error_vendor">
    +   </string-array>
    +@@ -679,8 +680,8 @@
    +     <string name="lockscreen_emergency_call" msgid="5298642613417801888">"Хитне службе"</string>
    +     <string name="lockscreen_return_to_call" msgid="5244259785500040021">"Назад на позив"</string>
    +     <string name="lockscreen_pattern_correct" msgid="9039008650362261237">"Тачно!"</string>
    +-    <string name="lockscreen_pattern_wrong" msgid="4317955014948108794">"Покушајте поново"</string>
    +-    <string name="lockscreen_password_wrong" msgid="5737815393253165301">"Покушајте поново"</string>
    ++    <string name="lockscreen_pattern_wrong" msgid="4317955014948108794">"Пробајте поново"</string>
    ++    <string name="lockscreen_password_wrong" msgid="5737815393253165301">"Пробајте поново"</string>
    +     <string name="lockscreen_storage_locked" msgid="9167551160010625200">"Откључај за све функције и податке"</string>
    +     <string name="faceunlock_multiple_failures" msgid="754137583022792429">"Премашен је највећи дозвољени број покушаја Откључавања лицем"</string>
    +     <string name="lockscreen_missing_sim_message_short" msgid="5099439277819215399">"Нема SIM картице"</string>
    +@@ -704,19 +705,19 @@
    +     <string name="lockscreen_sim_puk_locked_instructions" msgid="8127916255245181063">"Погледајте Кориснички водич или контактирајте Корисничку подршку."</string>
    +     <string name="lockscreen_sim_locked_message" msgid="8066660129206001039">"SIM картица је закључана."</string>
    +     <string name="lockscreen_sim_unlock_progress_dialog_message" msgid="595323214052881264">"Откључавање SIM картице…"</string>
    +-    <string name="lockscreen_too_many_failed_attempts_dialog_message" msgid="6481623830344107222">"<xliff:g id="NUMBER_0">%1$d</xliff:g> пута сте неправилно нацртали шаблон за откључавање. \n\nПокушајте поново за <xliff:g id="NUMBER_1">%2$d</xliff:g> секунде(и)."</string>
    +-    <string name="lockscreen_too_many_failed_password_attempts_dialog_message" msgid="2725973286239344555">"<xliff:g id="NUMBER_0">%1$d</xliff:g> пута сте погрешно унели лозинку. \n\nПокушајте поново за <xliff:g id="NUMBER_1">%2$d</xliff:g> секунде(и)."</string>
    +-    <string name="lockscreen_too_many_failed_pin_attempts_dialog_message" msgid="6216672706545696955">"<xliff:g id="NUMBER_0">%1$d</xliff:g> пута сте погрешно унели PIN. \n\nПокушајте поново за <xliff:g id="NUMBER_1">%2$d</xliff:g> секунде(и)."</string>
    +-    <string name="lockscreen_failed_attempts_almost_glogin" product="tablet" msgid="9191611984625460820">"<xliff:g id="NUMBER_0">%1$d</xliff:g> пута сте нетачно унели шаблон за откључавање. Након још <xliff:g id="NUMBER_1">%2$d</xliff:g> несупешна(их) покушаја, од вас ће бити затражено да откључате таблет помоћу података за пријављивање на Google.\n\n Покушајте поново за <xliff:g id="NUMBER_2">%3$d</xliff:g> секунде(и)."</string>
    +-    <string name="lockscreen_failed_attempts_almost_glogin" product="tv" msgid="5316664559603394684">"Неисправно сте нацртали шаблон за откључавање <xliff:g id="NUMBER_0">%1$d</xliff:g> пута. После још <xliff:g id="NUMBER_1">%2$d</xliff:g> неуспешна(их) покушаја од вас ће бити затражено да откључате ТВ помоћу података за пријављивање на Google.\n\n Покушајте поново за <xliff:g id="NUMBER_2">%3$d</xliff:g> сек."</string>
    +-    <string name="lockscreen_failed_attempts_almost_glogin" product="default" msgid="2590227559763762751">"<xliff:g id="NUMBER_0">%1$d</xliff:g> пута сте нетачно унели шаблон за откључавање. Након још <xliff:g id="NUMBER_1">%2$d</xliff:g> несупешна(их) покушаја, од вас ће бити затражено да откључате телефон помоћу података за пријављивање на Google.\n\n Покушајте поново за <xliff:g id="NUMBER_2">%3$d</xliff:g> секунде(и)."</string>
    ++    <string name="lockscreen_too_many_failed_attempts_dialog_message" msgid="6481623830344107222">"<xliff:g id="NUMBER_0">%1$d</xliff:g> пута сте неправилно нацртали шаблон за откључавање. \n\nПробајте поново за <xliff:g id="NUMBER_1">%2$d</xliff:g> секунде(и)."</string>
    ++    <string name="lockscreen_too_many_failed_password_attempts_dialog_message" msgid="2725973286239344555">"<xliff:g id="NUMBER_0">%1$d</xliff:g> пута сте погрешно унели лозинку. \n\nПробајте поново за <xliff:g id="NUMBER_1">%2$d</xliff:g> секунде(и)."</string>
    ++    <string name="lockscreen_too_many_failed_pin_attempts_dialog_message" msgid="6216672706545696955">"<xliff:g id="NUMBER_0">%1$d</xliff:g> пута сте погрешно унели PIN. \n\nПробајте поново за <xliff:g id="NUMBER_1">%2$d</xliff:g> секунде(и)."</string>
    ++    <string name="lockscreen_failed_attempts_almost_glogin" product="tablet" msgid="9191611984625460820">"<xliff:g id="NUMBER_0">%1$d</xliff:g> пута сте нетачно унели шаблон за откључавање. Након још <xliff:g id="NUMBER_1">%2$d</xliff:g> несупешна(их) покушаја, од вас ће бити затражено да откључате таблет помоћу података за пријављивање на Google.\n\n Пробајте поново за <xliff:g id="NUMBER_2">%3$d</xliff:g> секунде(и)."</string>
    ++    <string name="lockscreen_failed_attempts_almost_glogin" product="tv" msgid="5316664559603394684">"Неисправно сте нацртали шаблон за откључавање <xliff:g id="NUMBER_0">%1$d</xliff:g> пута. После још <xliff:g id="NUMBER_1">%2$d</xliff:g> неуспешна(их) покушаја од вас ће бити затражено да откључате ТВ помоћу података за пријављивање на Google.\n\n Пробајте поново за <xliff:g id="NUMBER_2">%3$d</xliff:g> сек."</string>
    ++    <string name="lockscreen_failed_attempts_almost_glogin" product="default" msgid="2590227559763762751">"<xliff:g id="NUMBER_0">%1$d</xliff:g> пута сте нетачно унели шаблон за откључавање. Након још <xliff:g id="NUMBER_1">%2$d</xliff:g> несупешна(их) покушаја, од вас ће бити затражено да откључате телефон помоћу података за пријављивање на Google.\n\n Пробајте поново за <xliff:g id="NUMBER_2">%3$d</xliff:g> секунде(и)."</string>
    +     <string name="lockscreen_failed_attempts_almost_at_wipe" product="tablet" msgid="6128106399745755604">"Неправилно сте покушали да откључате таблет <xliff:g id="NUMBER_0">%1$d</xliff:g> пута. Након још неуспешних покушаја (<xliff:g id="NUMBER_1">%2$d</xliff:g>) таблет ће бити ресетован на фабричка подешавања и сви кориснички подаци ће бити изгубљени."</string>
    +     <string name="lockscreen_failed_attempts_almost_at_wipe" product="tv" msgid="950408382418270260">"Покушали сте да откључате ТВ нетачно <xliff:g id="NUMBER_0">%1$d</xliff:g> пута. После још <xliff:g id="NUMBER_1">%2$d</xliff:g> неуспешна(их) покушаја ТВ ће бити ресетован на подразумевана фабричка подешавања и сви кориснички подаци ће бити изгубљени."</string>
    +     <string name="lockscreen_failed_attempts_almost_at_wipe" product="default" msgid="8603565142156826565">"Неисправно сте покушали да откључате телефон <xliff:g id="NUMBER_0">%1$d</xliff:g> пута. Након још неуспешних покушаја (<xliff:g id="NUMBER_1">%2$d</xliff:g>) телефон ће бити ресетован на фабричка подешавања и сви кориснички подаци ће бити изгубљени."</string>
    +     <string name="lockscreen_failed_attempts_now_wiping" product="tablet" msgid="280873516493934365">"Неисправно сте покушали да откључате таблет <xliff:g id="NUMBER">%d</xliff:g> пута. Таблет ће сада бити враћен на подразумевана фабричка подешавања."</string>
    +     <string name="lockscreen_failed_attempts_now_wiping" product="tv" msgid="3195755534096192191">"Покушали сте да откључате ТВ нетачно <xliff:g id="NUMBER">%d</xliff:g> пута. ТВ ће сада бити ресетован на подразумевана фабричка подешавања."</string>
    +     <string name="lockscreen_failed_attempts_now_wiping" product="default" msgid="3025504721764922246">"Неисправно сте покушали да откључате телефон <xliff:g id="NUMBER">%d</xliff:g> пута. Телефон ће сада бити враћен на подразумевана фабричка подешавања."</string>
    +-    <string name="lockscreen_too_many_failed_attempts_countdown" msgid="6251480343394389665">"Покушајте поново за <xliff:g id="NUMBER">%d</xliff:g> секунде(и)."</string>
    ++    <string name="lockscreen_too_many_failed_attempts_countdown" msgid="6251480343394389665">"Пробајте поново за <xliff:g id="NUMBER">%d</xliff:g> секунде(и)."</string>
    +     <string name="lockscreen_forgot_pattern_button_text" msgid="2626999449610695930">"Заборавили сте шаблон?"</string>
    +     <string name="lockscreen_glogin_forgot_pattern" msgid="2588521501166032747">"Откључавање налога"</string>
    +     <string name="lockscreen_glogin_too_many_attempts" msgid="2751368605287288808">"Превише покушаја уноса шаблона"</string>
    +@@ -1101,6 +1102,17 @@
    +     <skip />
    +     <string name="wifi_no_internet" msgid="8451173622563841546">"Wi-Fi нема приступ интернету"</string>
    +     <string name="wifi_no_internet_detailed" msgid="8083079241212301741">"Додирните за опције"</string>
    ++    <string name="network_switch_metered" msgid="4671730921726992671">"Прешли сте на тип мреже <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
    ++    <string name="network_switch_metered_detail" msgid="5325661434777870353">"Уређај користи тип мреже <xliff:g id="NEW_NETWORK">%1$s</xliff:g> када тип мреже <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> нема приступ интернету. Можда ће се наплаћивати трошкови."</string>
    ++    <string name="network_switch_metered_toast" msgid="5779283181685974304">"Прешли сте са типа мреже <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> на тип мреже <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
    ++  <string-array name="network_switch_type_name">
    ++    <item msgid="2952042958050315394">"мобилни подаци"</item>
    ++    <item msgid="75483255295529161">"Wi-Fi"</item>
    ++    <item msgid="6862614801537202646">"Bluetooth"</item>
    ++    <item msgid="5447331121797802871">"Етернет"</item>
    ++    <item msgid="8257233890381651999">"VPN"</item>
    ++  </string-array>
    ++    <string name="network_switch_type_name_unknown" msgid="4552612897806660656">"непознат тип мреже"</string>
    +     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Није могуће повезати са Wi-Fi мрежом"</string>
    +     <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" има лошу интернет везу."</string>
    +     <string name="wifi_connect_alert_title" msgid="8455846016001810172">"Желите ли да дозволите повезивање?"</string>
    +@@ -1172,13 +1184,12 @@
    +     <string name="share_remote_bugreport_action" msgid="6249476773913384948">"ДЕЛИ"</string>
    +     <string name="decline_remote_bugreport_action" msgid="6230987241608770062">"ОДБИЈ"</string>
    +     <string name="select_input_method" msgid="8547250819326693584">"Промените тастатуру"</string>
    +-    <string name="show_ime" msgid="2506087537466597099">"Задржи га на екрану док је физичка тастатура активна"</string>
    ++    <string name="show_ime" msgid="2506087537466597099">"Задржи је на екрану док је физичка тастатура активна"</string>
    +     <string name="hardware" msgid="194658061510127999">"Прикажи виртуелну тастатуру"</string>
    +     <string name="select_keyboard_layout_notification_title" msgid="597189518763083494">"Конфигуришите физичку тастатуру"</string>
    +     <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"Додирните да бисте изабрали језик и распоред"</string>
    +     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
    +     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
    +-    <string name="candidates_style" msgid="4333913089637062257"><u>"кандидати"</u></string>
    +     <string name="ext_media_checking_notification_title" msgid="5734005953288045806">"<xliff:g id="NAME">%s</xliff:g> се припрема"</string>
    +     <string name="ext_media_checking_notification_message" msgid="4747432538578886744">"Проверава се да ли постоје грешке"</string>
    +     <string name="ext_media_new_notification_message" msgid="7589986898808506239">"Нови уређај <xliff:g id="NAME">%s</xliff:g> је откривен"</string>
    +@@ -1257,8 +1268,9 @@
    +     <string name="vpn_text_long" msgid="4907843483284977618">"Повезано са сесијом <xliff:g id="SESSION">%s</xliff:g>. Додирните да бисте управљали мрежом."</string>
    +     <string name="vpn_lockdown_connecting" msgid="6443438964440960745">"Повезивање стално укљученог VPN-а..."</string>
    +     <string name="vpn_lockdown_connected" msgid="8202679674819213931">"Стално укључени VPN је повезан"</string>
    ++    <string name="vpn_lockdown_disconnected" msgid="4532298952570796327">"Веза са стално укљученим VPN-ом је прекинута"</string>
    +     <string name="vpn_lockdown_error" msgid="6009249814034708175">"Грешка стално укљученог VPN-а"</string>
    +-    <string name="vpn_lockdown_config" msgid="4655589351146766608">"Додирните да бисте конфигурисали"</string>
    ++    <string name="vpn_lockdown_config" msgid="5099330695245008680">"Додирните да бисте подесили"</string>
    +     <string name="upload_file" msgid="2897957172366730416">"Одабери датотеку"</string>
    +     <string name="no_file_chosen" msgid="6363648562170759465">"Није изабрана ниједна датотека"</string>
    +     <string name="reset" msgid="2448168080964209908">"Поново постави"</string>
    +@@ -1343,7 +1355,7 @@
    +     <string name="storage_usb_drive_label" msgid="4501418548927759953">"<xliff:g id="MANUFACTURER">%s</xliff:g> USB диск"</string>
    +     <string name="storage_usb" msgid="3017954059538517278">"USB меморија"</string>
    +     <string name="extract_edit_menu_button" msgid="8940478730496610137">"Измени"</string>
    +-    <string name="data_usage_warning_title" msgid="1955638862122232342">"Упозорење о потрошњи података"</string>
    ++    <string name="data_usage_warning_title" msgid="3620440638180218181">"Обавештење о потрошњи података"</string>
    +     <string name="data_usage_warning_body" msgid="6660692274311972007">"Додирните за потрошњу и подешавања."</string>
    +     <string name="data_usage_3g_limit_title" msgid="4361523876818447683">"Нема више 2G-3G података"</string>
    +     <string name="data_usage_4g_limit_title" msgid="4609566827219442376">"Нема више 4G података"</string>
    +@@ -1409,7 +1421,7 @@
    +     <string name="kg_wrong_pattern" msgid="1850806070801358830">"Погрешан шаблон"</string>
    +     <string name="kg_wrong_password" msgid="2333281762128113157">"Погрешна лозинка"</string>
    +     <string name="kg_wrong_pin" msgid="1131306510833563801">"Погрешан PIN"</string>
    +-    <string name="kg_too_many_failed_attempts_countdown" msgid="6358110221603297548">"Покушајте поново за <xliff:g id="NUMBER">%1$d</xliff:g> секунде(и)."</string>
    ++    <string name="kg_too_many_failed_attempts_countdown" msgid="6358110221603297548">"Пробајте поново за <xliff:g id="NUMBER">%1$d</xliff:g> секунде(и)."</string>
    +     <string name="kg_pattern_instructions" msgid="398978611683075868">"Нацртајте шаблон"</string>
    +     <string name="kg_sim_pin_instructions" msgid="2319508550934557331">"Унесите PIN SIM картице"</string>
    +     <string name="kg_pin_instructions" msgid="2377242233495111557">"Унесите PIN"</string>
    +@@ -1431,18 +1443,18 @@
    +     <string name="kg_login_invalid_input" msgid="5754664119319872197">"Неважеће корисничко име или лозинка."</string>
    +     <string name="kg_login_account_recovery_hint" msgid="5690709132841752974">"Заборавили сте корисничко име или лозинку?\nПосетите адресу "<b>"google.com/accounts/recovery"</b>"."</string>
    +     <string name="kg_login_checking_password" msgid="1052685197710252395">"Провера налога…"</string>
    +-    <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"Унели сте нетачни PIN <xliff:g id="NUMBER_0">%1$d</xliff:g> пута. \n\nПокушајте поново за <xliff:g id="NUMBER_1">%2$d</xliff:g> секунде(и)."</string>
    +-    <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"Унели сте нетачну лозинку <xliff:g id="NUMBER_0">%1$d</xliff:g> пута. \n\nПокушајте поново за <xliff:g id="NUMBER_1">%2$d</xliff:g> секунде(и)."</string>
    +-    <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"Нацртали сте шаблон за откључавање нетачно <xliff:g id="NUMBER_0">%1$d</xliff:g> пута. \n\nПокушајте поново за <xliff:g id="NUMBER_1">%2$d</xliff:g> секунде(и)."</string>
    ++    <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"Унели сте нетачни PIN <xliff:g id="NUMBER_0">%1$d</xliff:g> пута. \n\nПробајте поново за <xliff:g id="NUMBER_1">%2$d</xliff:g> секунде(и)."</string>
    ++    <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"Унели сте нетачну лозинку <xliff:g id="NUMBER_0">%1$d</xliff:g> пута. \n\nПробајте поново за <xliff:g id="NUMBER_1">%2$d</xliff:g> секунде(и)."</string>
    ++    <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"Нацртали сте шаблон за откључавање нетачно <xliff:g id="NUMBER_0">%1$d</xliff:g> пута. \n\nПробајте поново за <xliff:g id="NUMBER_1">%2$d</xliff:g> секунде(и)."</string>
    +     <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="1575557200627128949">"Покушали сте да откључате таблет нетачно <xliff:g id="NUMBER_0">%1$d</xliff:g> пута. Након још <xliff:g id="NUMBER_1">%2$d</xliff:g> неуспешна(их) покушаја таблет ће бити ресетован на фабричка подешавања и сви кориснички подаци ће бити изгубљени."</string>
    +     <string name="kg_failed_attempts_almost_at_wipe" product="tv" msgid="5621231220154419413">"Покушали сте да откључате ТВ нетачно <xliff:g id="NUMBER_0">%1$d</xliff:g> пута. После још <xliff:g id="NUMBER_1">%2$d</xliff:g> неуспешна(их) покушаја ТВ ће бити ресетован на подразумевана фабричка подешавања и сви кориснички подаци ће бити изгубљени."</string>
    +     <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4051015943038199910">"Покушали сте да откључате телефон нетачно <xliff:g id="NUMBER_0">%1$d</xliff:g> пута. После још <xliff:g id="NUMBER_1">%2$d</xliff:g> неуспешна(их) покушаја телефон ће бити ресетован на фабричка подешавања и сви кориснички подаци ће бити изгубљени."</string>
    +     <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="2072996269148483637">"Покушали сте да откључате таблет нетачно <xliff:g id="NUMBER">%d</xliff:g> пута. Таблет ће сада бити враћен на подразумевана фабричка подешавања."</string>
    +     <string name="kg_failed_attempts_now_wiping" product="tv" msgid="4987878286750741463">"Покушали сте да откључате ТВ нетачно <xliff:g id="NUMBER">%d</xliff:g> пута. ТВ ће сада бити ресетован на подразумевана фабричка подешавања."</string>
    +     <string name="kg_failed_attempts_now_wiping" product="default" msgid="4817627474419471518">"Покушали сте да откључате телефон нетачно <xliff:g id="NUMBER">%d</xliff:g> пута. Телефон ће сада бити враћен на подразумевана фабричка подешавања."</string>
    +-    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"Нацртали сте шаблон за откључавање нетачно <xliff:g id="NUMBER_0">%1$d</xliff:g> пута. После још <xliff:g id="NUMBER_1">%2$d</xliff:g> неуспешна(их) покушаја, од вас ће бити затражено да откључате таблет помоћу налога е-поште.\n\nПокушајте поново за <xliff:g id="NUMBER_2">%3$d</xliff:g> секунде(и)."</string>
    +-    <string name="kg_failed_attempts_almost_at_login" product="tv" msgid="4224651132862313471">"Неисправно сте нацртали шаблон за откључавање <xliff:g id="NUMBER_0">%1$d</xliff:g> пута. После још <xliff:g id="NUMBER_1">%2$d</xliff:g> неуспешна(их) покушаја, од вас ће бити затражено да откључате ТВ помоћу налога е-поште.\n\n Покушајте поново за <xliff:g id="NUMBER_2">%3$d</xliff:g> сек."</string>
    +-    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Нацртали сте шаблон за откључавање нетачно <xliff:g id="NUMBER_0">%1$d</xliff:g> пута. После још <xliff:g id="NUMBER_1">%2$d</xliff:g> неуспешна(их) покушаја, од вас ће бити затражено да откључате телефон помоћу налога е-поште.\n\nПокушајте поново за <xliff:g id="NUMBER_2">%3$d</xliff:g> секунде(и)."</string>
    ++    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"Нацртали сте шаблон за откључавање нетачно <xliff:g id="NUMBER_0">%1$d</xliff:g> пута. После још <xliff:g id="NUMBER_1">%2$d</xliff:g> неуспешна(их) покушаја, од вас ће бити затражено да откључате таблет помоћу налога е-поште.\n\nПробајте поново за <xliff:g id="NUMBER_2">%3$d</xliff:g> секунде(и)."</string>
    ++    <string name="kg_failed_attempts_almost_at_login" product="tv" msgid="4224651132862313471">"Неисправно сте нацртали шаблон за откључавање <xliff:g id="NUMBER_0">%1$d</xliff:g> пута. После још <xliff:g id="NUMBER_1">%2$d</xliff:g> неуспешна(их) покушаја, од вас ће бити затражено да откључате ТВ помоћу налога е-поште.\n\n Пробајте поново за <xliff:g id="NUMBER_2">%3$d</xliff:g> сек."</string>
    ++    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Нацртали сте шаблон за откључавање нетачно <xliff:g id="NUMBER_0">%1$d</xliff:g> пута. После још <xliff:g id="NUMBER_1">%2$d</xliff:g> неуспешна(их) покушаја, од вас ће бити затражено да откључате телефон помоћу налога е-поште.\n\nПробајте поново за <xliff:g id="NUMBER_2">%3$d</xliff:g> секунде(и)."</string>
    +     <string name="kg_text_message_separator" product="default" msgid="4160700433287233771">" – "</string>
    +     <string name="kg_reordering_delete_drop_target_text" msgid="7899202978204438708">"Уклони"</string>
    +     <string name="safe_media_volume_warning" product="default" msgid="2276318909314492312">"Желите да појачате звук изнад препорученог нивоа?\n\nСлушање гласне музике дуже време може да вам оштети слух."</string>
    +@@ -1553,14 +1565,14 @@
    +     <string name="restr_pin_enter_new_pin" msgid="5959606691619959184">"Нови PIN"</string>
    +     <string name="restr_pin_confirm_pin" msgid="8501523829633146239">"Потврдите нови PIN"</string>
    +     <string name="restr_pin_create_pin" msgid="8017600000263450337">"Направите PIN за измену ограничења"</string>
    +-    <string name="restr_pin_error_doesnt_match" msgid="2224214190906994548">"PIN-ови се не подударају. Покушајте поново."</string>
    ++    <string name="restr_pin_error_doesnt_match" msgid="2224214190906994548">"PIN-ови се не подударају. Пробајте поново."</string>
    +     <string name="restr_pin_error_too_short" msgid="8173982756265777792">"PIN је прекратак. Мора да садржи најмање 4 цифре."</string>
    +     <plurals name="restr_pin_countdown" formatted="false" msgid="9061246974881224688">
    +-      <item quantity="one">Покушајте поново за <xliff:g id="COUNT">%d</xliff:g> секунду</item>
    +-      <item quantity="few">Покушајте поново за <xliff:g id="COUNT">%d</xliff:g> секунде</item>
    +-      <item quantity="other">Покушајте поново за <xliff:g id="COUNT">%d</xliff:g> секунди</item>
    ++      <item quantity="one">Пробајте поново за <xliff:g id="COUNT">%d</xliff:g> секунду</item>
    ++      <item quantity="few">Пробајте поново за <xliff:g id="COUNT">%d</xliff:g> секунде</item>
    ++      <item quantity="other">Пробајте поново за <xliff:g id="COUNT">%d</xliff:g> секунди</item>
    +     </plurals>
    +-    <string name="restr_pin_try_later" msgid="973144472490532377">"Покушајте поново касније"</string>
    ++    <string name="restr_pin_try_later" msgid="973144472490532377">"Пробајте поново касније"</string>
    +     <string name="immersive_cling_title" msgid="8394201622932303336">"Приказује се цео екран"</string>
    +     <string name="immersive_cling_description" msgid="3482371193207536040">"Да бисте изашли, превуците надоле одозго."</string>
    +     <string name="immersive_cling_positive" msgid="5016839404568297683">"Важи"</string>
    +@@ -1672,6 +1684,7 @@
    +     <string name="search_language_hint" msgid="7042102592055108574">"Унесите назив језика"</string>
    +     <string name="language_picker_section_suggested" msgid="8414489646861640885">"Предложени"</string>
    +     <string name="language_picker_section_all" msgid="3097279199511617537">"Сви језици"</string>
    ++    <string name="region_picker_section_all" msgid="8966316787153001779">"Сви региони"</string>
    +     <string name="locale_search_menu" msgid="2560710726687249178">"Претражи"</string>
    +     <string name="work_mode_off_title" msgid="8954725060677558855">"Режим за Work је ИСКЉУЧЕН"</string>
    +     <string name="work_mode_off_message" msgid="3286169091278094476">"Дозвољава профилу за Work да функционише, укључујући апликације, синхронизацију у позадини и сродне функције."</string>
    +diff --git a/core/res/res/values-sv/strings.xml b/core/res/res/values-sv/strings.xml
    +index cf1b19c..d43282d 100644
    +--- a/core/res/res/values-sv/strings.xml
    ++++ b/core/res/res/values-sv/strings.xml
    +@@ -214,6 +214,7 @@
    +     <string name="global_actions" product="default" msgid="2406416831541615258">"Telefonalternativ"</string>
    +     <string name="global_action_lock" msgid="2844945191792119712">"Skärmlås"</string>
    +     <string name="global_action_power_off" msgid="4471879440839879722">"Stäng av"</string>
    ++    <string name="global_action_emergency" msgid="7112311161137421166">"Nödsituation"</string>
    +     <string name="global_action_bug_report" msgid="7934010578922304799">"Felrapport"</string>
    +     <string name="bugreport_title" msgid="2667494803742548533">"Skapa felrapport"</string>
    +     <string name="bugreport_message" msgid="398447048750350456">"Nu hämtas information om aktuell status för enheten, som sedan skickas i ett e-postmeddelade. Det tar en liten stund innan felrapporten är färdig och kan skickas, så vi ber dig ha tålamod."</string>
    +@@ -671,7 +672,7 @@
    +     <string name="lockscreen_carrier_default" msgid="6169005837238288522">"Ingen tjänst"</string>
    +     <string name="lockscreen_screen_locked" msgid="7288443074806832904">"Skärmen har låsts."</string>
    +     <string name="lockscreen_instructions_when_pattern_enabled" msgid="46154051614126049">"Tryck på Menu om du vill låsa upp eller ringa nödsamtal."</string>
    +-    <string name="lockscreen_instructions_when_pattern_disabled" msgid="686260028797158364">"Tryck på Menu om du vill låsa upp."</string>
    ++    <string name="lockscreen_instructions_when_pattern_disabled" msgid="686260028797158364">"Tryck på Menu för att låsa upp."</string>
    +     <string name="lockscreen_pattern_instructions" msgid="7478703254964810302">"Rita grafiskt lösenord för att låsa upp"</string>
    +     <string name="lockscreen_emergency_call" msgid="5298642613417801888">"Nödsamtal"</string>
    +     <string name="lockscreen_return_to_call" msgid="5244259785500040021">"Tillbaka till samtal"</string>
    +@@ -1076,6 +1077,17 @@
    +     <skip />
    +     <string name="wifi_no_internet" msgid="8451173622563841546">"Wi-Fi-nätverket är inte anslutet till internet"</string>
    +     <string name="wifi_no_internet_detailed" msgid="8083079241212301741">"Tryck för alternativ"</string>
    ++    <string name="network_switch_metered" msgid="4671730921726992671">"Byte av nätverk till <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
    ++    <string name="network_switch_metered_detail" msgid="5325661434777870353">"<xliff:g id="NEW_NETWORK">%1$s</xliff:g> används på enheten när det inte finns internetåtkomst via <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g>. Avgifter kan tillkomma."</string>
    ++    <string name="network_switch_metered_toast" msgid="5779283181685974304">"Byte av nätverk från <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> till <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
    ++  <string-array name="network_switch_type_name">
    ++    <item msgid="2952042958050315394">"mobildata"</item>
    ++    <item msgid="75483255295529161">"Wi-Fi"</item>
    ++    <item msgid="6862614801537202646">"Bluetooth"</item>
    ++    <item msgid="5447331121797802871">"Ethernet"</item>
    ++    <item msgid="8257233890381651999">"VPN"</item>
    ++  </string-array>
    ++    <string name="network_switch_type_name_unknown" msgid="4552612897806660656">"en okänd nätverkstyp"</string>
    +     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Det gick inte att ansluta till Wi-Fi"</string>
    +     <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" har en dålig Internetanslutning."</string>
    +     <string name="wifi_connect_alert_title" msgid="8455846016001810172">"Tillåt anslutning?"</string>
    +@@ -1153,7 +1165,6 @@
    +     <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"Tryck om du vill välja språk och layout"</string>
    +     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
    +     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
    +-    <string name="candidates_style" msgid="4333913089637062257"><u>"kandidater"</u></string>
    +     <string name="ext_media_checking_notification_title" msgid="5734005953288045806">"Förbereder ditt <xliff:g id="NAME">%s</xliff:g>"</string>
    +     <string name="ext_media_checking_notification_message" msgid="4747432538578886744">"Söker efter fel"</string>
    +     <string name="ext_media_new_notification_message" msgid="7589986898808506239">"Nytt <xliff:g id="NAME">%s</xliff:g> har hittats"</string>
    +@@ -1232,8 +1243,9 @@
    +     <string name="vpn_text_long" msgid="4907843483284977618">"Ansluten till <xliff:g id="SESSION">%s</xliff:g>. Knacka lätt för att hantera nätverket."</string>
    +     <string name="vpn_lockdown_connecting" msgid="6443438964440960745">"Ansluter till Always-on VPN ..."</string>
    +     <string name="vpn_lockdown_connected" msgid="8202679674819213931">"Ansluten till Always-on VPN"</string>
    ++    <string name="vpn_lockdown_disconnected" msgid="4532298952570796327">"Always-on VPN har kopplats från"</string>
    +     <string name="vpn_lockdown_error" msgid="6009249814034708175">"Fel på Always-on VPN"</string>
    +-    <string name="vpn_lockdown_config" msgid="4655589351146766608">"Tryck om du vill konfigurera"</string>
    ++    <string name="vpn_lockdown_config" msgid="5099330695245008680">"Tryck för att konfigurera"</string>
    +     <string name="upload_file" msgid="2897957172366730416">"Välj fil"</string>
    +     <string name="no_file_chosen" msgid="6363648562170759465">"Ingen fil har valts"</string>
    +     <string name="reset" msgid="2448168080964209908">"Återställ"</string>
    +@@ -1317,7 +1329,7 @@
    +     <string name="storage_usb_drive_label" msgid="4501418548927759953">"USB-enhet (<xliff:g id="MANUFACTURER">%s</xliff:g>)"</string>
    +     <string name="storage_usb" msgid="3017954059538517278">"USB-lagring"</string>
    +     <string name="extract_edit_menu_button" msgid="8940478730496610137">"Redigera"</string>
    +-    <string name="data_usage_warning_title" msgid="1955638862122232342">"Varning angående dataanvändning"</string>
    ++    <string name="data_usage_warning_title" msgid="3620440638180218181">"Varning – dataanvändning"</string>
    +     <string name="data_usage_warning_body" msgid="6660692274311972007">"Visa användning och inställning."</string>
    +     <string name="data_usage_3g_limit_title" msgid="4361523876818447683">"Datagränsen för 2G-3G har uppnåtts"</string>
    +     <string name="data_usage_4g_limit_title" msgid="4609566827219442376">"Datagränsen för 4G har uppnåtts"</string>
    +@@ -1636,6 +1648,7 @@
    +     <string name="search_language_hint" msgid="7042102592055108574">"Ange språket"</string>
    +     <string name="language_picker_section_suggested" msgid="8414489646861640885">"Förslag"</string>
    +     <string name="language_picker_section_all" msgid="3097279199511617537">"Alla språk"</string>
    ++    <string name="region_picker_section_all" msgid="8966316787153001779">"Alla regioner"</string>
    +     <string name="locale_search_menu" msgid="2560710726687249178">"Söka"</string>
    +     <string name="work_mode_off_title" msgid="8954725060677558855">"Arbetsläget är inaktiverat"</string>
    +     <string name="work_mode_off_message" msgid="3286169091278094476">"Tillåt att jobbprofilen är aktiv, inklusive appar, bakgrundssynkronisering och andra tillhörande funktioner."</string>
    +@@ -1643,7 +1656,7 @@
    +     <string name="new_sms_notification_title" msgid="8442817549127555977">"Du har nya meddelanden"</string>
    +     <string name="new_sms_notification_content" msgid="7002938807812083463">"Öppna sms-appen och visa meddelandet"</string>
    +     <string name="user_encrypted_title" msgid="9054897468831672082">"Vissa funktioner är begränsade"</string>
    +-    <string name="user_encrypted_message" msgid="4923292604515744267">"Tryck om du vill låsa upp"</string>
    ++    <string name="user_encrypted_message" msgid="4923292604515744267">"Tryck för att låsa upp"</string>
    +     <string name="user_encrypted_detail" msgid="5708447464349420392">"Användaruppgifterna är låsta"</string>
    +     <string name="profile_encrypted_detail" msgid="3700965619978314974">"Jobbprofilen är låst"</string>
    +     <string name="profile_encrypted_message" msgid="6964994232310195874">"Tryck och lås upp jobbprofilen"</string>
    +diff --git a/core/res/res/values-sw/strings.xml b/core/res/res/values-sw/strings.xml
    +index 3daaf93..cc750d6 100644
    +--- a/core/res/res/values-sw/strings.xml
    ++++ b/core/res/res/values-sw/strings.xml
    +@@ -212,6 +212,7 @@
    +     <string name="global_actions" product="default" msgid="2406416831541615258">"Chaguo za simu"</string>
    +     <string name="global_action_lock" msgid="2844945191792119712">"Funga skrini"</string>
    +     <string name="global_action_power_off" msgid="4471879440839879722">"Zima"</string>
    ++    <string name="global_action_emergency" msgid="7112311161137421166">"Dharura"</string>
    +     <string name="global_action_bug_report" msgid="7934010578922304799">"Ripoti ya hitilafu"</string>
    +     <string name="bugreport_title" msgid="2667494803742548533">"Chukua ripoti ya hitilafu"</string>
    +     <string name="bugreport_message" msgid="398447048750350456">"Hii itakusanya maelezo kuhusu hali ya kifaa chako kwa sasa, na itume kama barua pepe. Itachukua muda mfupi tangu ripoti ya hitilafu ianze kuzalishwa hadi iwe tayari kutumwa; vumilia."</string>
    +@@ -1074,6 +1075,17 @@
    +     <skip />
    +     <string name="wifi_no_internet" msgid="8451173622563841546">"Wi-Fi haina muunganisho wa intaneti"</string>
    +     <string name="wifi_no_internet_detailed" msgid="8083079241212301741">"Gonga ili upate chaguo"</string>
    ++    <string name="network_switch_metered" msgid="4671730921726992671">"Sasa inatumia <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
    ++    <string name="network_switch_metered_detail" msgid="5325661434777870353">"Kifaa hutumia <xliff:g id="NEW_NETWORK">%1$s</xliff:g> wakati <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> haina Intaneti. Huenda ukalipishwa."</string>
    ++    <string name="network_switch_metered_toast" msgid="5779283181685974304">"Imebadilisha mtandao kutoka <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> na sasa inatumia <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
    ++  <string-array name="network_switch_type_name">
    ++    <item msgid="2952042958050315394">"data ya simu za mkononi"</item>
    ++    <item msgid="75483255295529161">"Wi-Fi"</item>
    ++    <item msgid="6862614801537202646">"Bluetooth"</item>
    ++    <item msgid="5447331121797802871">"Ethaneti"</item>
    ++    <item msgid="8257233890381651999">"VPN"</item>
    ++  </string-array>
    ++    <string name="network_switch_type_name_unknown" msgid="4552612897806660656">"aina ya mtandao isiyojulikana"</string>
    +     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Haikuweza kuunganisha kwa Mtandao-Hewa"</string>
    +     <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" ina muunganisho duni wa Mtandao."</string>
    +     <string name="wifi_connect_alert_title" msgid="8455846016001810172">"Ungepenga kuruhusu muunganisho?"</string>
    +@@ -1151,7 +1163,6 @@
    +     <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"Gonga ili uchague lugha na muundo"</string>
    +     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
    +     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
    +-    <string name="candidates_style" msgid="4333913089637062257"><u>"wagombeaji"</u></string>
    +     <string name="ext_media_checking_notification_title" msgid="5734005953288045806">"Inaandaa <xliff:g id="NAME">%s</xliff:g>"</string>
    +     <string name="ext_media_checking_notification_message" msgid="4747432538578886744">"Inakagua hitilafu"</string>
    +     <string name="ext_media_new_notification_message" msgid="7589986898808506239">"<xliff:g id="NAME">%s</xliff:g> mpya imegunduliwa"</string>
    +@@ -1230,8 +1241,9 @@
    +     <string name="vpn_text_long" msgid="4907843483284977618">"Imeunganishwa kwa <xliff:g id="SESSION">%s</xliff:g>. Gonga ili kudhibiti mtandao"</string>
    +     <string name="vpn_lockdown_connecting" msgid="6443438964440960745">"Kila mara VPN iliyowashwa inaunganishwa…"</string>
    +     <string name="vpn_lockdown_connected" msgid="8202679674819213931">"Kila mara VPN iliyowashwa imeunganishwa"</string>
    ++    <string name="vpn_lockdown_disconnected" msgid="4532298952570796327">"Iwe imeondoa VPN kila wakati"</string>
    +     <string name="vpn_lockdown_error" msgid="6009249814034708175">"Kila mara kuna hitilafu ya VPN iliyowashwa"</string>
    +-    <string name="vpn_lockdown_config" msgid="4655589351146766608">"Gonga ili uweke mipangilio"</string>
    ++    <string name="vpn_lockdown_config" msgid="5099330695245008680">"Gonga ili uweke mipangilio"</string>
    +     <string name="upload_file" msgid="2897957172366730416">"Chagua faili"</string>
    +     <string name="no_file_chosen" msgid="6363648562170759465">"Hakuna faili iliyochaguliwa"</string>
    +     <string name="reset" msgid="2448168080964209908">"Weka upya"</string>
    +@@ -1315,7 +1327,7 @@
    +     <string name="storage_usb_drive_label" msgid="4501418548927759953">"Hifadhi ya USB iliyotengenezwa na <xliff:g id="MANUFACTURER">%s</xliff:g>"</string>
    +     <string name="storage_usb" msgid="3017954059538517278">"Hifadhi ya USB"</string>
    +     <string name="extract_edit_menu_button" msgid="8940478730496610137">"Badilisha"</string>
    +-    <string name="data_usage_warning_title" msgid="1955638862122232342">"Onyo la matumizi ya data"</string>
    ++    <string name="data_usage_warning_title" msgid="3620440638180218181">"Tahadhari ya matumizi ya data"</string>
    +     <string name="data_usage_warning_body" msgid="6660692274311972007">"Gonga ili uangalie matumizi na mipangilio."</string>
    +     <string name="data_usage_3g_limit_title" msgid="4361523876818447683">"Kikomo data ya 2G-3G kimefikiwa"</string>
    +     <string name="data_usage_4g_limit_title" msgid="4609566827219442376">"Kikomo cha data ya 4G kimefikiwa"</string>
    +@@ -1634,6 +1646,7 @@
    +     <string name="search_language_hint" msgid="7042102592055108574">"Weka jina la lugha"</string>
    +     <string name="language_picker_section_suggested" msgid="8414489646861640885">"Inayopendekezwa"</string>
    +     <string name="language_picker_section_all" msgid="3097279199511617537">"Lugha zote"</string>
    ++    <string name="region_picker_section_all" msgid="8966316787153001779">"Maeneo yote"</string>
    +     <string name="locale_search_menu" msgid="2560710726687249178">"Tafuta"</string>
    +     <string name="work_mode_off_title" msgid="8954725060677558855">"Hali ya kazi IMEZIMWA"</string>
    +     <string name="work_mode_off_message" msgid="3286169091278094476">"Ruhusu wasifu wa kazini utumike, ikiwa ni pamoja na programu, usawazishaji wa chini chini na vipengele vinavyohusiana."</string>
    +diff --git a/core/res/res/values-ta-rIN/strings.xml b/core/res/res/values-ta-rIN/strings.xml
    +index e851399..20226e9 100644
    +--- a/core/res/res/values-ta-rIN/strings.xml
    ++++ b/core/res/res/values-ta-rIN/strings.xml
    +@@ -214,6 +214,7 @@
    +     <string name="global_actions" product="default" msgid="2406416831541615258">"தொலைபேசி விருப்பங்கள்"</string>
    +     <string name="global_action_lock" msgid="2844945191792119712">"திரைப் பூட்டு"</string>
    +     <string name="global_action_power_off" msgid="4471879440839879722">"முடக்கு"</string>
    ++    <string name="global_action_emergency" msgid="7112311161137421166">"அவசர அழைப்பு"</string>
    +     <string name="global_action_bug_report" msgid="7934010578922304799">"பிழை அறிக்கை"</string>
    +     <string name="bugreport_title" msgid="2667494803742548533">"பிழை அறிக்கையை எடு"</string>
    +     <string name="bugreport_message" msgid="398447048750350456">"உங்கள் நடப்புச் சாதன நிலையை மின்னஞ்சல் செய்தியாக அனுப்ப, அது குறித்த தகவலை இது சேகரிக்கும். பிழை அறிக்கையைத் தொடங்குவதில் இருந்து, அது அனுப்புவதற்குத் தயாராகும் வரை, இதற்குச் சிறிது நேரம் ஆகும்; பொறுமையாகக் காத்திருக்கவும்."</string>
    +@@ -1076,6 +1077,17 @@
    +     <skip />
    +     <string name="wifi_no_internet" msgid="8451173622563841546">"வைஃபை இணைய அணுகல் கொண்டிருக்கவில்லை"</string>
    +     <string name="wifi_no_internet_detailed" msgid="8083079241212301741">"விருப்பங்களுக்கு, தட்டவும்"</string>
    ++    <string name="network_switch_metered" msgid="4671730921726992671">"<xliff:g id="NETWORK_TYPE">%1$s</xliff:g>க்கு மாற்றப்பட்டது"</string>
    ++    <string name="network_switch_metered_detail" msgid="5325661434777870353">"<xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> இல் இணைய அணுகல் இல்லாததால், சாதனமானது <xliff:g id="NEW_NETWORK">%1$s</xliff:g>ஐப் பயன்படுத்துகிறது. கட்டணங்கள் விதிக்கப்படலாம்."</string>
    ++    <string name="network_switch_metered_toast" msgid="5779283181685974304">"<xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> இலிருந்து <xliff:g id="NEW_NETWORK">%2$s</xliff:g>க்கு மாற்றப்பட்டது"</string>
    ++  <string-array name="network_switch_type_name">
    ++    <item msgid="2952042958050315394">"செல்லுலார் தரவு"</item>
    ++    <item msgid="75483255295529161">"வைஃபை"</item>
    ++    <item msgid="6862614801537202646">"புளூடூத்"</item>
    ++    <item msgid="5447331121797802871">"ஈத்தர்நெட்"</item>
    ++    <item msgid="8257233890381651999">"VPN"</item>
    ++  </string-array>
    ++    <string name="network_switch_type_name_unknown" msgid="4552612897806660656">"தெரியாத நெட்வொர்க் வகை"</string>
    +     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"வைஃபை உடன் இணைக்க முடியவில்லை"</string>
    +     <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" இணைய இணைப்பு மோசமாக உள்ளது."</string>
    +     <string name="wifi_connect_alert_title" msgid="8455846016001810172">"இணைப்பை அனுமதிக்கவா?"</string>
    +@@ -1153,7 +1165,6 @@
    +     <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"மொழியையும் தளவமைப்பையும் தேர்ந்தெடுக்க, தட்டவும்"</string>
    +     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
    +     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
    +-    <string name="candidates_style" msgid="4333913089637062257"><u>"கேன்டிடேட்ஸ்"</u></string>
    +     <string name="ext_media_checking_notification_title" msgid="5734005953288045806">"<xliff:g id="NAME">%s</xliff:g> தயாராகிறது"</string>
    +     <string name="ext_media_checking_notification_message" msgid="4747432538578886744">"பிழைகள் உள்ளதா எனப் பார்க்கிறது"</string>
    +     <string name="ext_media_new_notification_message" msgid="7589986898808506239">"புதிய <xliff:g id="NAME">%s</xliff:g> கண்டறியப்பட்டது"</string>
    +@@ -1232,8 +1243,9 @@
    +     <string name="vpn_text_long" msgid="4907843483284977618">"<xliff:g id="SESSION">%s</xliff:g> உடன் இணைக்கப்பட்டது. நெட்வொர்க்கை நிர்வகிக்க, தட்டவும்."</string>
    +     <string name="vpn_lockdown_connecting" msgid="6443438964440960745">"எப்போதும் இயங்கும் VPN உடன் இணைக்கிறது…"</string>
    +     <string name="vpn_lockdown_connected" msgid="8202679674819213931">"எப்போதும் இயங்கும் VPN இணைக்கப்பட்டது"</string>
    ++    <string name="vpn_lockdown_disconnected" msgid="4532298952570796327">"எப்போதும் இயங்கும் VPN துண்டிக்கப்பட்டது"</string>
    +     <string name="vpn_lockdown_error" msgid="6009249814034708175">"எப்போதும் இயங்கும் VPN பிழை"</string>
    +-    <string name="vpn_lockdown_config" msgid="4655589351146766608">"உள்ளமைக்க, தட்டவும்"</string>
    ++    <string name="vpn_lockdown_config" msgid="5099330695245008680">"அமைக்க, தட்டவும்"</string>
    +     <string name="upload_file" msgid="2897957172366730416">"கோப்பைத் தேர்வுசெய்"</string>
    +     <string name="no_file_chosen" msgid="6363648562170759465">"எந்தக் கோப்பும் தேர்வுசெய்யப்படவில்லை"</string>
    +     <string name="reset" msgid="2448168080964209908">"மீட்டமை"</string>
    +@@ -1317,7 +1329,7 @@
    +     <string name="storage_usb_drive_label" msgid="4501418548927759953">"<xliff:g id="MANUFACTURER">%s</xliff:g> USB டிரைவ்"</string>
    +     <string name="storage_usb" msgid="3017954059538517278">"USB சேமிப்பிடம்"</string>
    +     <string name="extract_edit_menu_button" msgid="8940478730496610137">"திருத்து"</string>
    +-    <string name="data_usage_warning_title" msgid="1955638862122232342">"தரவு பயன்பாட்டு எச்சரிக்கை"</string>
    ++    <string name="data_usage_warning_title" msgid="3620440638180218181">"தரவுப் பயன்பாடு குறித்த எச்சரிக்கை"</string>
    +     <string name="data_usage_warning_body" msgid="6660692274311972007">"தரவு உபயோகம், அமைப்புகளைப் பார்க்க, தட்டவும்."</string>
    +     <string name="data_usage_3g_limit_title" msgid="4361523876818447683">"2G-3G தரவு வரம்பைக் கடந்தது"</string>
    +     <string name="data_usage_4g_limit_title" msgid="4609566827219442376">"4G தரவு வரம்பைக் கடந்தது"</string>
    +@@ -1636,6 +1648,7 @@
    +     <string name="search_language_hint" msgid="7042102592055108574">"மொழி பெயரை உள்ளிடுக"</string>
    +     <string name="language_picker_section_suggested" msgid="8414489646861640885">"பரிந்துரைகள்"</string>
    +     <string name="language_picker_section_all" msgid="3097279199511617537">"எல்லா மொழிகளும்"</string>
    ++    <string name="region_picker_section_all" msgid="8966316787153001779">"எல்லா மண்டலங்களும்"</string>
    +     <string name="locale_search_menu" msgid="2560710726687249178">"தேடு"</string>
    +     <string name="work_mode_off_title" msgid="8954725060677558855">"பணிப் பயன்முறை முடக்கப்பட்டது"</string>
    +     <string name="work_mode_off_message" msgid="3286169091278094476">"செயல்பட, பணி சுயவிவரத்தை அனுமதி. இதில் பயன்பாடுகள், பின்னணி ஒத்திசைவு மற்றும் தொடர்புடைய அம்சங்கள் அடங்கும்."</string>
    +diff --git a/core/res/res/values-te-rIN/strings.xml b/core/res/res/values-te-rIN/strings.xml
    +index 7c48c8c..072b69b 100644
    +--- a/core/res/res/values-te-rIN/strings.xml
    ++++ b/core/res/res/values-te-rIN/strings.xml
    +@@ -214,6 +214,7 @@
    +     <string name="global_actions" product="default" msgid="2406416831541615258">"ఫోన్ ఎంపికలు"</string>
    +     <string name="global_action_lock" msgid="2844945191792119712">"స్క్రీన్ లాక్"</string>
    +     <string name="global_action_power_off" msgid="4471879440839879722">"పవర్ ఆఫ్ చేయి"</string>
    ++    <string name="global_action_emergency" msgid="7112311161137421166">"అత్యవసరం"</string>
    +     <string name="global_action_bug_report" msgid="7934010578922304799">"బగ్ నివేదిక"</string>
    +     <string name="bugreport_title" msgid="2667494803742548533">"బగ్ నివేదికను సిద్ధం చేయి"</string>
    +     <string name="bugreport_message" msgid="398447048750350456">"ఇది ఇ-మెయిల్ సందేశం రూపంలో పంపడానికి మీ ప్రస్తుత పరికర స్థితి గురించి సమాచారాన్ని సేకరిస్తుంది. బగ్ నివేదికను ప్రారంభించడం మొదలుకొని పంపడానికి సిద్ధం చేసే వరకు ఇందుకు కొంత సమయం పడుతుంది; దయచేసి ఓపిక పట్టండి."</string>
    +@@ -1076,6 +1077,17 @@
    +     <skip />
    +     <string name="wifi_no_internet" msgid="8451173622563841546">"Wi-Fiకి ఇంటర్నెట్ ప్రాప్యత లేదు"</string>
    +     <string name="wifi_no_internet_detailed" msgid="8083079241212301741">"ఎంపికల కోసం నొక్కండి"</string>
    ++    <string name="network_switch_metered" msgid="4671730921726992671">"<xliff:g id="NETWORK_TYPE">%1$s</xliff:g>కి మార్చబడింది"</string>
    ++    <string name="network_switch_metered_detail" msgid="5325661434777870353">"పరికరం <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g>కి ఇంటర్నెట్ ప్రాప్యత లేనప్పుడు <xliff:g id="NEW_NETWORK">%1$s</xliff:g>ని ఉపయోగిస్తుంది. ఛార్జీలు వర్తించవచ్చు."</string>
    ++    <string name="network_switch_metered_toast" msgid="5779283181685974304">"<xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> నుండి <xliff:g id="NEW_NETWORK">%2$s</xliff:g>కి మార్చబడింది"</string>
    ++  <string-array name="network_switch_type_name">
    ++    <item msgid="2952042958050315394">"సెల్యులార్ డేటా"</item>
    ++    <item msgid="75483255295529161">"Wi-Fi"</item>
    ++    <item msgid="6862614801537202646">"బ్లూటూత్"</item>
    ++    <item msgid="5447331121797802871">"ఈథర్‌నెట్"</item>
    ++    <item msgid="8257233890381651999">"VPN"</item>
    ++  </string-array>
    ++    <string name="network_switch_type_name_unknown" msgid="4552612897806660656">"తెలియని నెట్‌వర్క్ రకం"</string>
    +     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Wi-Fiకి కనెక్ట్ చేయడం సాధ్యపడలేదు"</string>
    +     <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" బలహీన ఇంటర్నెట్ కనెక్షన్‌ను కలిగి ఉంది."</string>
    +     <string name="wifi_connect_alert_title" msgid="8455846016001810172">"కనెక్షన్‌ని అనుమతించాలా?"</string>
    +@@ -1153,7 +1165,6 @@
    +     <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"భాష మరియు లేఅవుట్‌ను ఎంచుకోవడానికి నొక్కండి"</string>
    +     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
    +     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
    +-    <string name="candidates_style" msgid="4333913089637062257"><u>"క్యాండిడేట్‌లు"</u></string>
    +     <string name="ext_media_checking_notification_title" msgid="5734005953288045806">"<xliff:g id="NAME">%s</xliff:g>ని సిద్ధం చేస్తోంది"</string>
    +     <string name="ext_media_checking_notification_message" msgid="4747432538578886744">"లోపాల కోసం తనిఖీ చేస్తోంది"</string>
    +     <string name="ext_media_new_notification_message" msgid="7589986898808506239">"కొత్త <xliff:g id="NAME">%s</xliff:g> గుర్తించబడింది"</string>
    +@@ -1232,8 +1243,9 @@
    +     <string name="vpn_text_long" msgid="4907843483284977618">"<xliff:g id="SESSION">%s</xliff:g>కు కనెక్ట్ చేయబడింది. నెట్‌వర్క్‌ను నిర్వహించడానికి నొక్కండి."</string>
    +     <string name="vpn_lockdown_connecting" msgid="6443438964440960745">"ఎల్లప్పుడూ-ఆన్‌లో ఉండే VPN కనెక్ట్ చేయబడుతోంది…"</string>
    +     <string name="vpn_lockdown_connected" msgid="8202679674819213931">"ఎల్లప్పుడూ-ఆన్‌లో ఉండే VPN కనెక్ట్ చేయబడింది"</string>
    ++    <string name="vpn_lockdown_disconnected" msgid="4532298952570796327">"ఎల్లప్పుడూ ఆన్‌లో ఉండే VPN డిస్‌కనెక్ట్ చేయబడింది"</string>
    +     <string name="vpn_lockdown_error" msgid="6009249814034708175">"ఎల్లప్పుడూ-ఆన్‌లో ఉండే VPN లోపం"</string>
    +-    <string name="vpn_lockdown_config" msgid="4655589351146766608">"కాన్ఫిగర్ చేయడానికి నొక్కండి"</string>
    ++    <string name="vpn_lockdown_config" msgid="5099330695245008680">"సెటప్ చేయడానికి నొక్కండి"</string>
    +     <string name="upload_file" msgid="2897957172366730416">"ఫైల్‌ను ఎంచుకోండి"</string>
    +     <string name="no_file_chosen" msgid="6363648562170759465">"ఫైల్ ఎంచుకోబడలేదు"</string>
    +     <string name="reset" msgid="2448168080964209908">"రీసెట్ చేయి"</string>
    +@@ -1317,7 +1329,7 @@
    +     <string name="storage_usb_drive_label" msgid="4501418548927759953">"<xliff:g id="MANUFACTURER">%s</xliff:g> USB డ్రైవ్"</string>
    +     <string name="storage_usb" msgid="3017954059538517278">"USB నిల్వ"</string>
    +     <string name="extract_edit_menu_button" msgid="8940478730496610137">"సవరించు"</string>
    +-    <string name="data_usage_warning_title" msgid="1955638862122232342">"డేటా వినియోగం హెచ్చరిక"</string>
    ++    <string name="data_usage_warning_title" msgid="3620440638180218181">"డేటా వినియోగ హెచ్చరిక"</string>
    +     <string name="data_usage_warning_body" msgid="6660692274311972007">"వినియోగం,సెట్టింగ్‌ల కోసం నొక్కండి"</string>
    +     <string name="data_usage_3g_limit_title" msgid="4361523876818447683">"2G-3G డేటా పరిమితిని చేరుకుంది"</string>
    +     <string name="data_usage_4g_limit_title" msgid="4609566827219442376">"4G డేటా పరిమితిని చేరుకుంది"</string>
    +@@ -1636,6 +1648,7 @@
    +     <string name="search_language_hint" msgid="7042102592055108574">"భాష పేరును టైప్ చేయండి"</string>
    +     <string name="language_picker_section_suggested" msgid="8414489646861640885">"సూచించినవి"</string>
    +     <string name="language_picker_section_all" msgid="3097279199511617537">"అన్ని భాషలు"</string>
    ++    <string name="region_picker_section_all" msgid="8966316787153001779">"అన్ని ప్రాంతాలు"</string>
    +     <string name="locale_search_menu" msgid="2560710726687249178">"శోధించు"</string>
    +     <string name="work_mode_off_title" msgid="8954725060677558855">"కార్యాలయ మోడ్ ఆఫ్ చేయబడింది"</string>
    +     <string name="work_mode_off_message" msgid="3286169091278094476">"అనువర్తనాలు, నేపథ్య సమకాలీకరణ మరియు సంబంధిత లక్షణాలతో సహా కార్యాలయ ప్రొఫైల్‌ను పని చేయడానికి అనుమతించండి."</string>
    +diff --git a/core/res/res/values-th/strings.xml b/core/res/res/values-th/strings.xml
    +index 90d9f9b..c251590 100644
    +--- a/core/res/res/values-th/strings.xml
    ++++ b/core/res/res/values-th/strings.xml
    +@@ -214,6 +214,7 @@
    +     <string name="global_actions" product="default" msgid="2406416831541615258">"ตัวเลือกโทรศัพท์"</string>
    +     <string name="global_action_lock" msgid="2844945191792119712">"ล็อกหน้าจอ"</string>
    +     <string name="global_action_power_off" msgid="4471879440839879722">"ปิดเครื่อง"</string>
    ++    <string name="global_action_emergency" msgid="7112311161137421166">"เหตุฉุกเฉิน"</string>
    +     <string name="global_action_bug_report" msgid="7934010578922304799">"รายงานข้อบกพร่อง"</string>
    +     <string name="bugreport_title" msgid="2667494803742548533">"ใช้รายงานข้อบกพร่อง"</string>
    +     <string name="bugreport_message" msgid="398447048750350456">"การดำเนินการนี้จะรวบรวมข้อมูลเกี่ยวกับสถานะปัจจุบันของอุปกรณ์ของคุณ โดยจะส่งไปในรูปแบบข้อความอีเมล อาจใช้เวลาสักครู่ตั้งแต่เริ่มการสร้างรายงานข้อบกพร่องจนกระทั่งเสร็จสมบูรณ์ โปรดอดทนรอ"</string>
    +@@ -1076,6 +1077,17 @@
    +     <skip />
    +     <string name="wifi_no_internet" msgid="8451173622563841546">"Wi-Fi ไม่สามารถเข้าถึงอินเทอร์เน็ต"</string>
    +     <string name="wifi_no_internet_detailed" msgid="8083079241212301741">"แตะเพื่อดูตัวเลือก"</string>
    ++    <string name="network_switch_metered" msgid="4671730921726992671">"เปลี่ยนเป็น <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
    ++    <string name="network_switch_metered_detail" msgid="5325661434777870353">"อุปกรณ์จะใช้ <xliff:g id="NEW_NETWORK">%1$s</xliff:g> เมื่อ <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> ไม่สามารถเข้าถึงอินเทอร์เน็ต อาจมีค่าบริการ"</string>
    ++    <string name="network_switch_metered_toast" msgid="5779283181685974304">"เปลี่ยนจาก <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> เป็น <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
    ++  <string-array name="network_switch_type_name">
    ++    <item msgid="2952042958050315394">"เน็ตมือถือ"</item>
    ++    <item msgid="75483255295529161">"Wi-Fi"</item>
    ++    <item msgid="6862614801537202646">"บลูทูธ"</item>
    ++    <item msgid="5447331121797802871">"อีเทอร์เน็ต"</item>
    ++    <item msgid="8257233890381651999">"VPN"</item>
    ++  </string-array>
    ++    <string name="network_switch_type_name_unknown" msgid="4552612897806660656">"ประเภทเครือข่ายที่ไม่รู้จัก"</string>
    +     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"ไม่สามารถเชื่อมต่อ WiFi"</string>
    +     <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" มีสัญญาณอินเทอร์เน็ตไม่ดี"</string>
    +     <string name="wifi_connect_alert_title" msgid="8455846016001810172">"อนุญาตการเชื่อมต่อใช่ไหม"</string>
    +@@ -1153,7 +1165,6 @@
    +     <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"แตะเพื่อเลือกภาษาและรูปแบบ"</string>
    +     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" กขฃคฅฆงจฉชซฌญฎฏฐฑฒณดตถทธนบปผฝพฟภมยรลวศษสหฬอฮ"</string>
    +     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" กขฃคฅฆงจฉชซฌญฎฏฐฑฒณดตถทธนบปผฝพฟภมยรลวศษสหฬอฮ"</string>
    +-    <string name="candidates_style" msgid="4333913089637062257"><u>"ตัวเลือก"</u></string>
    +     <string name="ext_media_checking_notification_title" msgid="5734005953288045806">"กำลังเตรียม <xliff:g id="NAME">%s</xliff:g>"</string>
    +     <string name="ext_media_checking_notification_message" msgid="4747432538578886744">"กำลังตรวจหาข้อผิดพลาด"</string>
    +     <string name="ext_media_new_notification_message" msgid="7589986898808506239">"ตรวจพบ <xliff:g id="NAME">%s</xliff:g> ใหม่"</string>
    +@@ -1232,8 +1243,9 @@
    +     <string name="vpn_text_long" msgid="4907843483284977618">"เชื่อมต่อกับ <xliff:g id="SESSION">%s</xliff:g> แตะเพื่อจัดการเครือข่าย"</string>
    +     <string name="vpn_lockdown_connecting" msgid="6443438964440960745">"กำลังเชื่อมต่อ VPN แบบเปิดตลอดเวลา…"</string>
    +     <string name="vpn_lockdown_connected" msgid="8202679674819213931">"เชื่อมต่อ VPN แบบเปิดตลอดเวลาแล้ว"</string>
    ++    <string name="vpn_lockdown_disconnected" msgid="4532298952570796327">"ยกเลิกการเชื่อมต่อ VPN แบบเปิดตลอดเวลาแล้ว"</string>
    +     <string name="vpn_lockdown_error" msgid="6009249814034708175">"ข้อผิดพลาดของ VPN แบบเปิดตลอดเวลา"</string>
    +-    <string name="vpn_lockdown_config" msgid="4655589351146766608">"แตะเพื่อกำหนดค่า"</string>
    ++    <string name="vpn_lockdown_config" msgid="5099330695245008680">"แตะเพื่อตั้งค่า"</string>
    +     <string name="upload_file" msgid="2897957172366730416">"เลือกไฟล์"</string>
    +     <string name="no_file_chosen" msgid="6363648562170759465">"ไม่ได้เลือกไฟล์ไว้"</string>
    +     <string name="reset" msgid="2448168080964209908">"รีเซ็ต"</string>
    +@@ -1317,7 +1329,7 @@
    +     <string name="storage_usb_drive_label" msgid="4501418548927759953">"ไดรฟ์ USB ของ <xliff:g id="MANUFACTURER">%s</xliff:g>"</string>
    +     <string name="storage_usb" msgid="3017954059538517278">"ที่เก็บข้อมูล USB"</string>
    +     <string name="extract_edit_menu_button" msgid="8940478730496610137">"แก้ไข"</string>
    +-    <string name="data_usage_warning_title" msgid="1955638862122232342">"คำเตือนการใช้ข้อมูล"</string>
    ++    <string name="data_usage_warning_title" msgid="3620440638180218181">"การแจ้งเตือนการใช้อินเทอร์เน็ต"</string>
    +     <string name="data_usage_warning_body" msgid="6660692274311972007">"แตะเพื่อดูการใช้งานและการตั้งค่า"</string>
    +     <string name="data_usage_3g_limit_title" msgid="4361523876818447683">"ถึงขีดจำกัดข้อมูล 2G-3G แล้ว"</string>
    +     <string name="data_usage_4g_limit_title" msgid="4609566827219442376">"ถึงขีดจำกัดข้อมูล 4G แล้ว"</string>
    +@@ -1636,6 +1648,7 @@
    +     <string name="search_language_hint" msgid="7042102592055108574">"พิมพ์ชื่อภาษา"</string>
    +     <string name="language_picker_section_suggested" msgid="8414489646861640885">"แนะนำ"</string>
    +     <string name="language_picker_section_all" msgid="3097279199511617537">"ทุกภาษา"</string>
    ++    <string name="region_picker_section_all" msgid="8966316787153001779">"ภูมิภาคทั้งหมด"</string>
    +     <string name="locale_search_menu" msgid="2560710726687249178">"ค้นหา"</string>
    +     <string name="work_mode_off_title" msgid="8954725060677558855">"โหมดทำงานปิดอยู่"</string>
    +     <string name="work_mode_off_message" msgid="3286169091278094476">"อนุญาตให้โปรไฟล์งานทำงานได้ ซึ่งรวมถึงแอป การซิงค์ในพื้นหลัง และคุณลักษณะอื่นที่เกี่ยวข้อง"</string>
    +diff --git a/core/res/res/values-tl/strings.xml b/core/res/res/values-tl/strings.xml
    +index efb319f..b0d84ea 100644
    +--- a/core/res/res/values-tl/strings.xml
    ++++ b/core/res/res/values-tl/strings.xml
    +@@ -214,6 +214,7 @@
    +     <string name="global_actions" product="default" msgid="2406416831541615258">"Pagpipilian sa telepono"</string>
    +     <string name="global_action_lock" msgid="2844945191792119712">"Pag-lock sa screen"</string>
    +     <string name="global_action_power_off" msgid="4471879440839879722">"I-off"</string>
    ++    <string name="global_action_emergency" msgid="7112311161137421166">"Emergency"</string>
    +     <string name="global_action_bug_report" msgid="7934010578922304799">"Ulat sa bug"</string>
    +     <string name="bugreport_title" msgid="2667494803742548533">"Kunin ang ulat sa bug"</string>
    +     <string name="bugreport_message" msgid="398447048750350456">"Mangongolekta ito ng impormasyon tungkol sa kasalukuyang katayuan ng iyong device, na ipapadala bilang mensaheng e-mail. Gugugol ito ng kaunting oras mula sa pagsisimula ng ulat sa bug hanggang sa handa na itong maipadala; mangyaring magpasensya."</string>
    +@@ -1076,6 +1077,17 @@
    +     <skip />
    +     <string name="wifi_no_internet" msgid="8451173622563841546">"Walang access sa Internet ang Wi-Fi"</string>
    +     <string name="wifi_no_internet_detailed" msgid="8083079241212301741">"I-tap para sa mga opsyon"</string>
    ++    <string name="network_switch_metered" msgid="4671730921726992671">"Lumipat sa <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
    ++    <string name="network_switch_metered_detail" msgid="5325661434777870353">"Ginagamit ng device ang <xliff:g id="NEW_NETWORK">%1$s</xliff:g> kapag walang access sa Internet ang <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g>. Maaaring may mga malapat na singilin."</string>
    ++    <string name="network_switch_metered_toast" msgid="5779283181685974304">"Lumipat sa <xliff:g id="NEW_NETWORK">%2$s</xliff:g> mula sa <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g>"</string>
    ++  <string-array name="network_switch_type_name">
    ++    <item msgid="2952042958050315394">"cellular data"</item>
    ++    <item msgid="75483255295529161">"Wi-Fi"</item>
    ++    <item msgid="6862614801537202646">"Bluetooth"</item>
    ++    <item msgid="5447331121797802871">"Ethernet"</item>
    ++    <item msgid="8257233890381651999">"VPN"</item>
    ++  </string-array>
    ++    <string name="network_switch_type_name_unknown" msgid="4552612897806660656">"isang hindi kilalang uri ng network"</string>
    +     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Hindi makakonekta sa Wi-Fi"</string>
    +     <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" ay mayroong mahinang koneksyon sa Internet."</string>
    +     <string name="wifi_connect_alert_title" msgid="8455846016001810172">"Payagan ang kuneksyon?"</string>
    +@@ -1139,7 +1151,7 @@
    +     <string name="usb_accessory_notification_title" msgid="7848236974087653666">"Nakakonekta sa isang accessory ng USB"</string>
    +     <string name="usb_notification_message" msgid="3370903770828407960">"I-tap para sa higit pang mga opsyon."</string>
    +     <string name="adb_active_notification_title" msgid="6729044778949189918">"Konektado ang debugging ng USB"</string>
    +-    <string name="adb_active_notification_message" msgid="4948470599328424059">"I-tap upang i-disable ang pagde-debug ng USB."</string>
    ++    <string name="adb_active_notification_message" msgid="4948470599328424059">"I-tap upang i-disable ang pag-debug ng USB."</string>
    +     <string name="taking_remote_bugreport_notification_title" msgid="6742483073875060934">"Kinukuha ang ulat ng bug…"</string>
    +     <string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"Gusto mo bang ibahagi ang ulat ng bug?"</string>
    +     <string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"Ibinabahagi ang ulat ng bug…"</string>
    +@@ -1153,7 +1165,6 @@
    +     <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"I-tap upang pumili ng wika at layout"</string>
    +     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
    +     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
    +-    <string name="candidates_style" msgid="4333913089637062257"><u>"mga kandidato"</u></string>
    +     <string name="ext_media_checking_notification_title" msgid="5734005953288045806">"Inihahanda ang <xliff:g id="NAME">%s</xliff:g>"</string>
    +     <string name="ext_media_checking_notification_message" msgid="4747432538578886744">"Sinusuri para sa mga error"</string>
    +     <string name="ext_media_new_notification_message" msgid="7589986898808506239">"Na-detect ang bagong <xliff:g id="NAME">%s</xliff:g>"</string>
    +@@ -1232,8 +1243,9 @@
    +     <string name="vpn_text_long" msgid="4907843483284977618">"Nakakonekta sa <xliff:g id="SESSION">%s</xliff:g>. Tapikin upang pamahalaan ang network."</string>
    +     <string name="vpn_lockdown_connecting" msgid="6443438964440960745">"Kumukonekta ang Always-on VPN…"</string>
    +     <string name="vpn_lockdown_connected" msgid="8202679674819213931">"Nakakonekta ang Always-on VPN"</string>
    ++    <string name="vpn_lockdown_disconnected" msgid="4532298952570796327">"Hindi nakakonekta ang palaging naka-on na VPN"</string>
    +     <string name="vpn_lockdown_error" msgid="6009249814034708175">"Error sa Always-on VPN"</string>
    +-    <string name="vpn_lockdown_config" msgid="4655589351146766608">"I-tap upang i-configure"</string>
    ++    <string name="vpn_lockdown_config" msgid="5099330695245008680">"I-tap upang i-set up"</string>
    +     <string name="upload_file" msgid="2897957172366730416">"Pumili ng file"</string>
    +     <string name="no_file_chosen" msgid="6363648562170759465">"Walang napiling file"</string>
    +     <string name="reset" msgid="2448168080964209908">"I-reset"</string>
    +@@ -1317,7 +1329,7 @@
    +     <string name="storage_usb_drive_label" msgid="4501418548927759953">"<xliff:g id="MANUFACTURER">%s</xliff:g> USB drive"</string>
    +     <string name="storage_usb" msgid="3017954059538517278">"USB storage"</string>
    +     <string name="extract_edit_menu_button" msgid="8940478730496610137">"I-edit"</string>
    +-    <string name="data_usage_warning_title" msgid="1955638862122232342">"Babala sa paggamit ng data"</string>
    ++    <string name="data_usage_warning_title" msgid="3620440638180218181">"Alerto sa paggamit ng data"</string>
    +     <string name="data_usage_warning_body" msgid="6660692274311972007">"I-tap tingnan paggamit/setting."</string>
    +     <string name="data_usage_3g_limit_title" msgid="4361523876818447683">"Naabot na ang limitasyon sa 2G-3G data"</string>
    +     <string name="data_usage_4g_limit_title" msgid="4609566827219442376">"Naabot na ang limitasyon sa 4G data"</string>
    +@@ -1636,6 +1648,7 @@
    +     <string name="search_language_hint" msgid="7042102592055108574">"I-type ang wika"</string>
    +     <string name="language_picker_section_suggested" msgid="8414489646861640885">"Iminumungkahi"</string>
    +     <string name="language_picker_section_all" msgid="3097279199511617537">"Lahat ng wika"</string>
    ++    <string name="region_picker_section_all" msgid="8966316787153001779">"Lahat ng rehiyon"</string>
    +     <string name="locale_search_menu" msgid="2560710726687249178">"Maghanap"</string>
    +     <string name="work_mode_off_title" msgid="8954725060677558855">"NAKA-OFF ang work mode"</string>
    +     <string name="work_mode_off_message" msgid="3286169091278094476">"Payagang gumana ang profile sa trabaho, kasama na ang mga app, pag-sync sa background at mga may kaugnayang feature."</string>
    +diff --git a/core/res/res/values-tr/strings.xml b/core/res/res/values-tr/strings.xml
    +index 5a0776a..a089fd4 100644
    +--- a/core/res/res/values-tr/strings.xml
    ++++ b/core/res/res/values-tr/strings.xml
    +@@ -214,6 +214,7 @@
    +     <string name="global_actions" product="default" msgid="2406416831541615258">"Telefon seçenekleri"</string>
    +     <string name="global_action_lock" msgid="2844945191792119712">"Ekran kilidi"</string>
    +     <string name="global_action_power_off" msgid="4471879440839879722">"Kapat"</string>
    ++    <string name="global_action_emergency" msgid="7112311161137421166">"Acil durum"</string>
    +     <string name="global_action_bug_report" msgid="7934010578922304799">"Hata raporu"</string>
    +     <string name="bugreport_title" msgid="2667494803742548533">"Hata raporu al"</string>
    +     <string name="bugreport_message" msgid="398447048750350456">"Bu rapor, e-posta iletisi olarak göndermek üzere cihazınızın şu anki durumuyla ilgili bilgi toplar. Hata raporu başlatıldıktan sonra hazır olması biraz zaman alabilir, lütfen sabırlı olun."</string>
    +@@ -1076,6 +1077,17 @@
    +     <skip />
    +     <string name="wifi_no_internet" msgid="8451173622563841546">"Kablosuz bağlantıda İnternet erişimi yok"</string>
    +     <string name="wifi_no_internet_detailed" msgid="8083079241212301741">"Seçenekler için dokunun"</string>
    ++    <string name="network_switch_metered" msgid="4671730921726992671">"<xliff:g id="NETWORK_TYPE">%1$s</xliff:g> ağına geçildi"</string>
    ++    <string name="network_switch_metered_detail" msgid="5325661434777870353">"<xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> ağının İnternet erişimi olmadığında cihaz <xliff:g id="NEW_NETWORK">%1$s</xliff:g> ağını kullanır. Bunun için ödeme alınabilir."</string>
    ++    <string name="network_switch_metered_toast" msgid="5779283181685974304">"<xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> ağından <xliff:g id="NEW_NETWORK">%2$s</xliff:g> ağına geçildi"</string>
    ++  <string-array name="network_switch_type_name">
    ++    <item msgid="2952042958050315394">"hücresel veri"</item>
    ++    <item msgid="75483255295529161">"Kablosuz"</item>
    ++    <item msgid="6862614801537202646">"Bluetooth"</item>
    ++    <item msgid="5447331121797802871">"Ethernet"</item>
    ++    <item msgid="8257233890381651999">"VPN"</item>
    ++  </string-array>
    ++    <string name="network_switch_type_name_unknown" msgid="4552612897806660656">"bilinmeyen ağ türü"</string>
    +     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Kablosuz bağlantısı kurulamadı"</string>
    +     <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" İnternet bağlantısı zayıf."</string>
    +     <string name="wifi_connect_alert_title" msgid="8455846016001810172">"Bağlantıya izin verilsin mi?"</string>
    +@@ -1153,7 +1165,6 @@
    +     <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"Dili ve düzeni seçmek için hafifçe dokunun"</string>
    +     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
    +     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
    +-    <string name="candidates_style" msgid="4333913089637062257"><u>"adaylar"</u></string>
    +     <string name="ext_media_checking_notification_title" msgid="5734005953288045806">"<xliff:g id="NAME">%s</xliff:g> hazırlanıyor"</string>
    +     <string name="ext_media_checking_notification_message" msgid="4747432538578886744">"Hatalar denetleniyor"</string>
    +     <string name="ext_media_new_notification_message" msgid="7589986898808506239">"Yeni <xliff:g id="NAME">%s</xliff:g> algılandı"</string>
    +@@ -1232,8 +1243,9 @@
    +     <string name="vpn_text_long" msgid="4907843483284977618">"<xliff:g id="SESSION">%s</xliff:g> oturumuna bağlı. Ağı yönetmek için hafifçe vurun."</string>
    +     <string name="vpn_lockdown_connecting" msgid="6443438964440960745">"Her zaman açık VPN\'ye bağlanılıyor…"</string>
    +     <string name="vpn_lockdown_connected" msgid="8202679674819213931">"Her zaman açık VPN\'ye bağlanıldı"</string>
    ++    <string name="vpn_lockdown_disconnected" msgid="4532298952570796327">"Her zaman açık VPN bağlantısı kesildi"</string>
    +     <string name="vpn_lockdown_error" msgid="6009249814034708175">"Her zaman açık VPN hatası"</string>
    +-    <string name="vpn_lockdown_config" msgid="4655589351146766608">"Yapılandırmak için dokunun"</string>
    ++    <string name="vpn_lockdown_config" msgid="5099330695245008680">"Ayarlamak için dokunun"</string>
    +     <string name="upload_file" msgid="2897957172366730416">"Dosya seç"</string>
    +     <string name="no_file_chosen" msgid="6363648562170759465">"Seçili dosya yok"</string>
    +     <string name="reset" msgid="2448168080964209908">"Sıfırla"</string>
    +@@ -1317,7 +1329,7 @@
    +     <string name="storage_usb_drive_label" msgid="4501418548927759953">"<xliff:g id="MANUFACTURER">%s</xliff:g> USB sürücüsü"</string>
    +     <string name="storage_usb" msgid="3017954059538517278">"USB bellek"</string>
    +     <string name="extract_edit_menu_button" msgid="8940478730496610137">"Düzenle"</string>
    +-    <string name="data_usage_warning_title" msgid="1955638862122232342">"Veri kullanım uyarısı"</string>
    ++    <string name="data_usage_warning_title" msgid="3620440638180218181">"Veri kullanımı uyarısı"</string>
    +     <string name="data_usage_warning_body" msgid="6660692274311972007">"Kul. ve ayar. gör. için dokunun."</string>
    +     <string name="data_usage_3g_limit_title" msgid="4361523876818447683">"2G-3G veri sınırına ulaşıldı"</string>
    +     <string name="data_usage_4g_limit_title" msgid="4609566827219442376">"4G veri sınırına ulaşıldı"</string>
    +@@ -1636,6 +1648,7 @@
    +     <string name="search_language_hint" msgid="7042102592055108574">"Dil adını yazın"</string>
    +     <string name="language_picker_section_suggested" msgid="8414489646861640885">"Önerilen"</string>
    +     <string name="language_picker_section_all" msgid="3097279199511617537">"Tüm diller"</string>
    ++    <string name="region_picker_section_all" msgid="8966316787153001779">"Tüm bölgeler"</string>
    +     <string name="locale_search_menu" msgid="2560710726687249178">"Ara"</string>
    +     <string name="work_mode_off_title" msgid="8954725060677558855">"İş modu KAPALI"</string>
    +     <string name="work_mode_off_message" msgid="3286169091278094476">"Uygulamalar, arka planda senkronizasyon ve ilgili özellikler dahil olmak üzere iş profilinin çalışmasına izin ver."</string>
    +diff --git a/core/res/res/values-uk/strings.xml b/core/res/res/values-uk/strings.xml
    +index 4810e37..704ade8 100644
    +--- a/core/res/res/values-uk/strings.xml
    ++++ b/core/res/res/values-uk/strings.xml
    +@@ -218,6 +218,7 @@
    +     <string name="global_actions" product="default" msgid="2406416831541615258">"Параметри телеф."</string>
    +     <string name="global_action_lock" msgid="2844945191792119712">"Заблок. екран"</string>
    +     <string name="global_action_power_off" msgid="4471879440839879722">"Вимкнути"</string>
    ++    <string name="global_action_emergency" msgid="7112311161137421166">"Екстрений виклик"</string>
    +     <string name="global_action_bug_report" msgid="7934010578922304799">"Звіт про помилки"</string>
    +     <string name="bugreport_title" msgid="2667494803742548533">"Звіт про помилку"</string>
    +     <string name="bugreport_message" msgid="398447048750350456">"Інформація про поточний стан вашого пристрою буде зібрана й надіслана електронною поштою. Підготовка звіту триватиме певний час."</string>
    +@@ -1103,8 +1104,8 @@
    +     <string name="volume_icon_description_incall" msgid="8890073218154543397">"Гучність сигналу виклику"</string>
    +     <string name="volume_icon_description_media" msgid="4217311719665194215">"Гучність медіа"</string>
    +     <string name="volume_icon_description_notification" msgid="7044986546477282274">"Гучність сповіщення"</string>
    +-    <string name="ringtone_default" msgid="3789758980357696936">"Мелодія за умовч."</string>
    +-    <string name="ringtone_default_with_actual" msgid="8129563480895990372">"Мелодія за умовч. (<xliff:g id="ACTUAL_RINGTONE">%1$s</xliff:g>)"</string>
    ++    <string name="ringtone_default" msgid="3789758980357696936">"Мелодія за умовчанням"</string>
    ++    <string name="ringtone_default_with_actual" msgid="8129563480895990372">"Мелодія за умовчанням (<xliff:g id="ACTUAL_RINGTONE">%1$s</xliff:g>)"</string>
    +     <string name="ringtone_silent" msgid="7937634392408977062">"Немає"</string>
    +     <string name="ringtone_picker_title" msgid="3515143939175119094">"Мелодії"</string>
    +     <string name="ringtone_unknown" msgid="5477919988701784788">"Невідома мелодія"</string>
    +@@ -1126,6 +1127,17 @@
    +     <skip />
    +     <string name="wifi_no_internet" msgid="8451173622563841546">"Мережа Wi-Fi не має доступу до Інтернету"</string>
    +     <string name="wifi_no_internet_detailed" msgid="8083079241212301741">"Торкніться, щоб відкрити опції"</string>
    ++    <string name="network_switch_metered" msgid="4671730921726992671">"Пристрій перейшов на мережу <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
    ++    <string name="network_switch_metered_detail" msgid="5325661434777870353">"Пристрій використовує мережу <xliff:g id="NEW_NETWORK">%1$s</xliff:g>, коли мережа <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> не має доступу до Інтернету. Може стягуватися плата."</string>
    ++    <string name="network_switch_metered_toast" msgid="5779283181685974304">"Пристрій перейшов з мережі <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> на мережу <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
    ++  <string-array name="network_switch_type_name">
    ++    <item msgid="2952042958050315394">"мобільний трафік"</item>
    ++    <item msgid="75483255295529161">"Wi-Fi"</item>
    ++    <item msgid="6862614801537202646">"Bluetooth"</item>
    ++    <item msgid="5447331121797802871">"Ethernet"</item>
    ++    <item msgid="8257233890381651999">"Мережа VPN"</item>
    ++  </string-array>
    ++    <string name="network_switch_type_name_unknown" msgid="4552612897806660656">"невідомий тип мережі"</string>
    +     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Не вдалося під’єднатися до мережі Wi-Fi"</string>
    +     <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" має погане з’єднання з Інтернетом."</string>
    +     <string name="wifi_connect_alert_title" msgid="8455846016001810172">"Дозволити з’єднання?"</string>
    +@@ -1203,7 +1215,6 @@
    +     <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"Торкніться, щоб вибрати мову та розкладку"</string>
    +     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" АБВГҐДЕЄЖЗИІЇЙКЛМНОПРСТУФХЦЧШЩЬЮЯ"</string>
    +     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789АБВГҐДЕЄЖЗИІЇЙКЛМНОПРСТУФХЦЧШЩЬЮЯ"</string>
    +-    <string name="candidates_style" msgid="4333913089637062257"><u>"кандидати"</u></string>
    +     <string name="ext_media_checking_notification_title" msgid="5734005953288045806">"Підготовка пристрою пам’яті <xliff:g id="NAME">%s</xliff:g>"</string>
    +     <string name="ext_media_checking_notification_message" msgid="4747432538578886744">"Виявлення помилок"</string>
    +     <string name="ext_media_new_notification_message" msgid="7589986898808506239">"Виявлено новий пристрій пам’яті (<xliff:g id="NAME">%s</xliff:g>)"</string>
    +@@ -1282,8 +1293,9 @@
    +     <string name="vpn_text_long" msgid="4907843483284977618">"Під’єднано до <xliff:g id="SESSION">%s</xliff:g>. Торкніться, щоб керувати мережею."</string>
    +     <string name="vpn_lockdown_connecting" msgid="6443438964440960745">"Під’єднання до постійної мережі VPN…"</string>
    +     <string name="vpn_lockdown_connected" msgid="8202679674819213931">"Під’єднано до постійної мережі VPN"</string>
    ++    <string name="vpn_lockdown_disconnected" msgid="4532298952570796327">"Постійну мережу VPN від’єднано"</string>
    +     <string name="vpn_lockdown_error" msgid="6009249814034708175">"Помилка постійної мережі VPN"</string>
    +-    <string name="vpn_lockdown_config" msgid="4655589351146766608">"Торкніться, щоб налаштувати"</string>
    ++    <string name="vpn_lockdown_config" msgid="5099330695245008680">"Торкніться, щоб налаштувати"</string>
    +     <string name="upload_file" msgid="2897957172366730416">"Виберіть файл"</string>
    +     <string name="no_file_chosen" msgid="6363648562170759465">"Не вибрано файл"</string>
    +     <string name="reset" msgid="2448168080964209908">"Віднов."</string>
    +@@ -1369,7 +1381,7 @@
    +     <string name="storage_usb_drive_label" msgid="4501418548927759953">"Носій USB (<xliff:g id="MANUFACTURER">%s</xliff:g>)"</string>
    +     <string name="storage_usb" msgid="3017954059538517278">"Носій USB"</string>
    +     <string name="extract_edit_menu_button" msgid="8940478730496610137">"Редагувати"</string>
    +-    <string name="data_usage_warning_title" msgid="1955638862122232342">"Застереження про використ. даних"</string>
    ++    <string name="data_usage_warning_title" msgid="3620440638180218181">"Сповіщення про використ. трафіку"</string>
    +     <string name="data_usage_warning_body" msgid="6660692274311972007">"Переглянути дані та параметри."</string>
    +     <string name="data_usage_3g_limit_title" msgid="4361523876818447683">"Досягнуто ліміту даних 2G–3G"</string>
    +     <string name="data_usage_4g_limit_title" msgid="4609566827219442376">"Досягнуто ліміту даних 4G"</string>
    +@@ -1708,6 +1720,7 @@
    +     <string name="search_language_hint" msgid="7042102592055108574">"Введіть назву мови"</string>
    +     <string name="language_picker_section_suggested" msgid="8414489646861640885">"Пропоновані"</string>
    +     <string name="language_picker_section_all" msgid="3097279199511617537">"Усі мови"</string>
    ++    <string name="region_picker_section_all" msgid="8966316787153001779">"Усі регіони"</string>
    +     <string name="locale_search_menu" msgid="2560710726687249178">"Пошук"</string>
    +     <string name="work_mode_off_title" msgid="8954725060677558855">"Робочий профіль ВИМКНЕНО"</string>
    +     <string name="work_mode_off_message" msgid="3286169091278094476">"Увімкнути робочий профіль, зокрема додатки, фонову синхронізацію та пов’язані функції."</string>
    +diff --git a/core/res/res/values-ur-rPK/strings.xml b/core/res/res/values-ur-rPK/strings.xml
    +index f677132..24a03b2 100644
    +--- a/core/res/res/values-ur-rPK/strings.xml
    ++++ b/core/res/res/values-ur-rPK/strings.xml
    +@@ -214,6 +214,7 @@
    +     <string name="global_actions" product="default" msgid="2406416831541615258">"فون کے اختیارات"</string>
    +     <string name="global_action_lock" msgid="2844945191792119712">"اسکرین لاک"</string>
    +     <string name="global_action_power_off" msgid="4471879440839879722">"پاور آف"</string>
    ++    <string name="global_action_emergency" msgid="7112311161137421166">"ایمرجنسی"</string>
    +     <string name="global_action_bug_report" msgid="7934010578922304799">"بگ کی اطلاع"</string>
    +     <string name="bugreport_title" msgid="2667494803742548533">"بگ کی اطلاع لیں"</string>
    +     <string name="bugreport_message" msgid="398447048750350456">"ایک ای میل پیغام کے بطور بھیجنے کیلئے، یہ آپ کے موجودہ آلہ کی حالت کے بارے میں معلومات جمع کرے گا۔ بگ کی اطلاع شروع کرنے سے لے کر بھیجنے کیلئے تیار ہونے تک اس میں تھوڑا وقت لگے گا؛ براہ کرم تحمل سے کام لیں۔"</string>
    +@@ -1076,6 +1077,17 @@
    +     <skip />
    +     <string name="wifi_no_internet" msgid="8451173622563841546">"‏Wi-Fi کی انٹرنیٹ تک رسائی نہیں ہے"</string>
    +     <string name="wifi_no_internet_detailed" msgid="8083079241212301741">"اختیارات کیلئے تھپتھپائیں"</string>
    ++    <string name="network_switch_metered" msgid="4671730921726992671">"<xliff:g id="NETWORK_TYPE">%1$s</xliff:g> پر سوئچ ہو گیا"</string>
    ++    <string name="network_switch_metered_detail" msgid="5325661434777870353">"جب <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> کے پاس انٹرنیٹ تک رسائی نہ ہو تو آلہ <xliff:g id="NEW_NETWORK">%1$s</xliff:g> کو استعمال کرتا ہے۔ چارجز کا اطلاق ہو سکتا ہے۔"</string>
    ++    <string name="network_switch_metered_toast" msgid="5779283181685974304">"<xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> سے <xliff:g id="NEW_NETWORK">%2$s</xliff:g> پر سوئچ ہو گیا"</string>
    ++  <string-array name="network_switch_type_name">
    ++    <item msgid="2952042958050315394">"سیلولر ڈیٹا"</item>
    ++    <item msgid="75483255295529161">"Wi-Fi"</item>
    ++    <item msgid="6862614801537202646">"بلوٹوتھ"</item>
    ++    <item msgid="5447331121797802871">"ایتھرنیٹ"</item>
    ++    <item msgid="8257233890381651999">"VPN"</item>
    ++  </string-array>
    ++    <string name="network_switch_type_name_unknown" msgid="4552612897806660656">"نیٹ ورک کی نامعلوم قسم"</string>
    +     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"‏Wi-Fi سے مربوط نہیں ہو سکا"</string>
    +     <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" اس میں ایک کمزور انٹرنیٹ کنکشن ہے۔"</string>
    +     <string name="wifi_connect_alert_title" msgid="8455846016001810172">"کنکشن کی اجازت دیں؟"</string>
    +@@ -1153,7 +1165,6 @@
    +     <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"زبان اور لے آؤٹ منتخب کرنے کیلئے تھپتھپائیں"</string>
    +     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
    +     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
    +-    <string name="candidates_style" msgid="4333913089637062257"><u>"امیدواران"</u></string>
    +     <string name="ext_media_checking_notification_title" msgid="5734005953288045806">"<xliff:g id="NAME">%s</xliff:g> تیار کیا جا رہا ہے"</string>
    +     <string name="ext_media_checking_notification_message" msgid="4747432538578886744">"خرابیوں کیلئے چیک کیا جا رہا ہے"</string>
    +     <string name="ext_media_new_notification_message" msgid="7589986898808506239">"نئے <xliff:g id="NAME">%s</xliff:g> کا پتا چلا"</string>
    +@@ -1232,8 +1243,9 @@
    +     <string name="vpn_text_long" msgid="4907843483284977618">"<xliff:g id="SESSION">%s</xliff:g> سے منسلک ہے۔ نیٹ ورک کا نظم کرنے کیلئے تھپتھپائیں۔"</string>
    +     <string name="vpn_lockdown_connecting" msgid="6443438964440960745">"‏ہمیشہ آن VPN مربوط ہو رہا ہے…"</string>
    +     <string name="vpn_lockdown_connected" msgid="8202679674819213931">"‏ہمیشہ آن VPN مربوط ہوگیا"</string>
    ++    <string name="vpn_lockdown_disconnected" msgid="4532298952570796327">"‏ہمیشہ آن VPN غیر منسلک ہو گیا"</string>
    +     <string name="vpn_lockdown_error" msgid="6009249814034708175">"‏ہمیشہ آن VPN کی خرابی"</string>
    +-    <string name="vpn_lockdown_config" msgid="4655589351146766608">"کنفیگر کرنے کیلئے تھپتھپائیں"</string>
    ++    <string name="vpn_lockdown_config" msgid="5099330695245008680">"سیٹ اپ کرنے کیلئے تھپتھپائیں"</string>
    +     <string name="upload_file" msgid="2897957172366730416">"فائل منتخب کریں"</string>
    +     <string name="no_file_chosen" msgid="6363648562170759465">"کوئی فائل منتخب نہیں کی گئی"</string>
    +     <string name="reset" msgid="2448168080964209908">"دوبارہ ترتیب دیں"</string>
    +@@ -1317,7 +1329,7 @@
    +     <string name="storage_usb_drive_label" msgid="4501418548927759953">"‏<xliff:g id="MANUFACTURER">%s</xliff:g> USB ڈرائیو"</string>
    +     <string name="storage_usb" msgid="3017954059538517278">"‏USB اسٹوریج"</string>
    +     <string name="extract_edit_menu_button" msgid="8940478730496610137">"ترمیم کریں"</string>
    +-    <string name="data_usage_warning_title" msgid="1955638862122232342">"ڈیٹا کے استعمال کی وارننگ"</string>
    ++    <string name="data_usage_warning_title" msgid="3620440638180218181">"ڈیٹا کے استعمال کا الرٹ"</string>
    +     <string name="data_usage_warning_body" msgid="6660692274311972007">"استعمال اور ترتیبات دیکھنے کیلئے تھپتھپائیں۔"</string>
    +     <string name="data_usage_3g_limit_title" msgid="4361523876818447683">"‏2G-3G ڈیٹا کی حد کو پہنچ گیا"</string>
    +     <string name="data_usage_4g_limit_title" msgid="4609566827219442376">"‏4G ڈیٹا کی حد کو پہنچ گیا"</string>
    +@@ -1636,6 +1648,7 @@
    +     <string name="search_language_hint" msgid="7042102592055108574">"زبان کا نام ٹائپ کریں"</string>
    +     <string name="language_picker_section_suggested" msgid="8414489646861640885">"تجویز کردہ"</string>
    +     <string name="language_picker_section_all" msgid="3097279199511617537">"سبھی زبانیں"</string>
    ++    <string name="region_picker_section_all" msgid="8966316787153001779">"تمام علاقے"</string>
    +     <string name="locale_search_menu" msgid="2560710726687249178">"تلاش"</string>
    +     <string name="work_mode_off_title" msgid="8954725060677558855">"کام موڈ آف ہے"</string>
    +     <string name="work_mode_off_message" msgid="3286169091278094476">"دفتری پروفائل کو کام کرنے دیں، بشمول ایپس، پس منظر کی مطابقت پذیری اور متعلقہ خصوصیات۔"</string>
    +diff --git a/core/res/res/values-uz-rUZ/strings.xml b/core/res/res/values-uz-rUZ/strings.xml
    +index 8fc6428..e5a2889 100644
    +--- a/core/res/res/values-uz-rUZ/strings.xml
    ++++ b/core/res/res/values-uz-rUZ/strings.xml
    +@@ -214,6 +214,7 @@
    +     <string name="global_actions" product="default" msgid="2406416831541615258">"Telefon sozlamalari"</string>
    +     <string name="global_action_lock" msgid="2844945191792119712">"Ekran qulfi"</string>
    +     <string name="global_action_power_off" msgid="4471879440839879722">"O‘chirish"</string>
    ++    <string name="global_action_emergency" msgid="7112311161137421166">"Favqulodda chaqiruv"</string>
    +     <string name="global_action_bug_report" msgid="7934010578922304799">"Nosozlik haqida ma’lumot berish"</string>
    +     <string name="bugreport_title" msgid="2667494803742548533">"Xatoliklar hisoboti"</string>
    +     <string name="bugreport_message" msgid="398447048750350456">"Qurilmangiz holati haqidagi ma’lumotlar to‘planib, e-pochta orqali yuboriladi. Hisobotni tayyorlash biroz vaqt olishi mumkin."</string>
    +@@ -1076,6 +1077,17 @@
    +     <skip />
    +     <string name="wifi_no_internet" msgid="8451173622563841546">"Wi-Fi tarmog‘ida internet aloqasi yo‘q"</string>
    +     <string name="wifi_no_internet_detailed" msgid="8083079241212301741">"Variantlarni ko‘rsatish uchun bosing"</string>
    ++    <string name="network_switch_metered" msgid="4671730921726992671">"<xliff:g id="NETWORK_TYPE">%1$s</xliff:g> tarmog‘iga ulanildi"</string>
    ++    <string name="network_switch_metered_detail" msgid="5325661434777870353">"Qurilma <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> tarmog‘ida internet o‘chganda, <xliff:g id="NEW_NETWORK">%1$s</xliff:g> tarmog‘iga ulaniladi. To‘lov olinishi mumkin."</string>
    ++    <string name="network_switch_metered_toast" msgid="5779283181685974304">"<xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> tarmog‘idan <xliff:g id="NEW_NETWORK">%2$s</xliff:g> tarmog‘iga o‘tildi"</string>
    ++  <string-array name="network_switch_type_name">
    ++    <item msgid="2952042958050315394">"mobil internet"</item>
    ++    <item msgid="75483255295529161">"Wi-Fi"</item>
    ++    <item msgid="6862614801537202646">"Bluetooth"</item>
    ++    <item msgid="5447331121797802871">"Ethernet"</item>
    ++    <item msgid="8257233890381651999">"VPN"</item>
    ++  </string-array>
    ++    <string name="network_switch_type_name_unknown" msgid="4552612897806660656">"noma’lum tarmoq turi"</string>
    +     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Wi-Fi’ga ulana olmadi"</string>
    +     <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" tezligi past Internetga ulangan."</string>
    +     <string name="wifi_connect_alert_title" msgid="8455846016001810172">"Ulanishga ruxsat berilsinmi?"</string>
    +@@ -1087,7 +1099,7 @@
    +     <string name="wifi_p2p_enabled_notification_title" msgid="2068321881673734886">"Wi-Fi Direct yoniq"</string>
    +     <string name="wifi_p2p_enabled_notification_message" msgid="8064677407830620023">"Sozlamalarni ochish uchun bosing"</string>
    +     <string name="accept" msgid="1645267259272829559">"Qabul qilish"</string>
    +-    <string name="decline" msgid="2112225451706137894">"Rad qilish"</string>
    ++    <string name="decline" msgid="2112225451706137894">"Rad etish"</string>
    +     <string name="wifi_p2p_invitation_sent_title" msgid="1318975185112070734">"taklif jo‘natildi"</string>
    +     <string name="wifi_p2p_invitation_to_connect_title" msgid="4958803948658533637">"ulanish taklifi"</string>
    +     <string name="wifi_p2p_from_message" msgid="570389174731951769">"Kimdan:"</string>
    +@@ -1101,7 +1113,7 @@
    +     <string name="sms_control_title" msgid="7296612781128917719">"SMS xabarlar yuborilmoqda"</string>
    +     <string name="sms_control_message" msgid="3867899169651496433">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; katta miqdordagi SMS xabarlarini jo‘natmoqda. Ushbu ilovaga xabarlar jo‘natishni davom ettirishga ruxsat berasizmi?"</string>
    +     <string name="sms_control_yes" msgid="3663725993855816807">"Ruxsat berish"</string>
    +-    <string name="sms_control_no" msgid="625438561395534982">"Rad qilish"</string>
    ++    <string name="sms_control_no" msgid="625438561395534982">"Rad etish"</string>
    +     <string name="sms_short_code_confirm_message" msgid="1645436466285310855">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; &lt;b&gt;<xliff:g id="DEST_ADDRESS">%2$s</xliff:g>&lt;/b&gt;ga xabar jo‘natishni xohlaydi."</string>
    +     <string name="sms_short_code_details" msgid="5873295990846059400">"Bunda, mobil hisobingizdan "<b>"to‘lov olinishi mumkin"</b>"."</string>
    +     <string name="sms_premium_short_code_details" msgid="7869234868023975"><b>"Bunda, mobil hisobingizdan to‘lov olinishi mumkin."</b></string>
    +@@ -1153,7 +1165,6 @@
    +     <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"Til va sxemani belgilash uchun bosing"</string>
    +     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
    +     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
    +-    <string name="candidates_style" msgid="4333913089637062257"><u>"nomzodlar"</u></string>
    +     <string name="ext_media_checking_notification_title" msgid="5734005953288045806">"<xliff:g id="NAME">%s</xliff:g> tayyorlanmoqda"</string>
    +     <string name="ext_media_checking_notification_message" msgid="4747432538578886744">"Xatolar qidirilmoqda"</string>
    +     <string name="ext_media_new_notification_message" msgid="7589986898808506239">"Yangi <xliff:g id="NAME">%s</xliff:g> kartasi aniqlandi"</string>
    +@@ -1212,7 +1223,7 @@
    +     <string name="grant_credentials_permission_message_footer" msgid="3125211343379376561">"Ushbu so‘rovga ruxsat berishni xohlaysizmi?"</string>
    +     <string name="grant_permissions_header_text" msgid="6874497408201826708">"Ruxsat so‘rovi"</string>
    +     <string name="allow" msgid="7225948811296386551">"Ruxsat berish"</string>
    +-    <string name="deny" msgid="2081879885755434506">"Rad qilish"</string>
    ++    <string name="deny" msgid="2081879885755434506">"Rad etish"</string>
    +     <string name="permission_request_notification_title" msgid="6486759795926237907">"Ruxsat so‘raldi"</string>
    +     <string name="permission_request_notification_with_subtitle" msgid="8530393139639560189">"<xliff:g id="ACCOUNT">%s</xliff:g> hisobi uchun\nruxsat so‘raldi"</string>
    +     <string name="forward_intent_to_owner" msgid="1207197447013960896">"Siz ushbu ilovadan ishchi profilingizdan tashqarida foydalanmoqdasiz"</string>
    +@@ -1232,8 +1243,9 @@
    +     <string name="vpn_text_long" msgid="4907843483284977618">"<xliff:g id="SESSION">%s</xliff:g> ulandi. Tarmoq sozlamalarini o‘zgartirish uchun bu yerni bosing."</string>
    +     <string name="vpn_lockdown_connecting" msgid="6443438964440960745">"Ulanmoqda…"</string>
    +     <string name="vpn_lockdown_connected" msgid="8202679674819213931">"Ulandi"</string>
    ++    <string name="vpn_lockdown_disconnected" msgid="4532298952570796327">"Doimiy VPN o‘chirildi"</string>
    +     <string name="vpn_lockdown_error" msgid="6009249814034708175">"Xato"</string>
    +-    <string name="vpn_lockdown_config" msgid="4655589351146766608">"Sozlash uchun bosing"</string>
    ++    <string name="vpn_lockdown_config" msgid="5099330695245008680">"Sozlash uchun bosing"</string>
    +     <string name="upload_file" msgid="2897957172366730416">"Faylni tanlash"</string>
    +     <string name="no_file_chosen" msgid="6363648562170759465">"Hech qanday fayl tanlanmadi"</string>
    +     <string name="reset" msgid="2448168080964209908">"Asliga qaytarish"</string>
    +@@ -1317,7 +1329,7 @@
    +     <string name="storage_usb_drive_label" msgid="4501418548927759953">"<xliff:g id="MANUFACTURER">%s</xliff:g> USB xotira qurilmasi"</string>
    +     <string name="storage_usb" msgid="3017954059538517278">"USB xotira"</string>
    +     <string name="extract_edit_menu_button" msgid="8940478730496610137">"Tahrirlash"</string>
    +-    <string name="data_usage_warning_title" msgid="1955638862122232342">"Trafik kam qoldi"</string>
    ++    <string name="data_usage_warning_title" msgid="3620440638180218181">"Trafik sarfi bo‘yicha ogohlantirish"</string>
    +     <string name="data_usage_warning_body" msgid="6660692274311972007">"Trafik sarfi va sozlamalarni ko‘rish uchun bosing."</string>
    +     <string name="data_usage_3g_limit_title" msgid="4361523876818447683">"2G-3G trafik chekloviga yetdi"</string>
    +     <string name="data_usage_4g_limit_title" msgid="4609566827219442376">"4G trafik chekloviga yetdi"</string>
    +@@ -1636,6 +1648,7 @@
    +     <string name="search_language_hint" msgid="7042102592055108574">"Til nomini kiriting"</string>
    +     <string name="language_picker_section_suggested" msgid="8414489646861640885">"Taklif etiladi"</string>
    +     <string name="language_picker_section_all" msgid="3097279199511617537">"Barcha tillar"</string>
    ++    <string name="region_picker_section_all" msgid="8966316787153001779">"Barcha hududlar"</string>
    +     <string name="locale_search_menu" msgid="2560710726687249178">"Qidiruv"</string>
    +     <string name="work_mode_off_title" msgid="8954725060677558855">"Ish rejimi O‘CHIQ"</string>
    +     <string name="work_mode_off_message" msgid="3286169091278094476">"Ishchi profilini yoqish: ilovalar, fonda sinxronlash va bog‘liq funksiyalar."</string>
    +diff --git a/core/res/res/values-vi/strings.xml b/core/res/res/values-vi/strings.xml
    +index a537b8f..0bbfe3b 100644
    +--- a/core/res/res/values-vi/strings.xml
    ++++ b/core/res/res/values-vi/strings.xml
    +@@ -214,6 +214,7 @@
    +     <string name="global_actions" product="default" msgid="2406416831541615258">"Tùy chọn điện thoại"</string>
    +     <string name="global_action_lock" msgid="2844945191792119712">"Khoá màn hình"</string>
    +     <string name="global_action_power_off" msgid="4471879440839879722">"Tắt nguồn"</string>
    ++    <string name="global_action_emergency" msgid="7112311161137421166">"Khẩn cấp"</string>
    +     <string name="global_action_bug_report" msgid="7934010578922304799">"Báo cáo lỗi"</string>
    +     <string name="bugreport_title" msgid="2667494803742548533">"Nhận báo cáo lỗi"</string>
    +     <string name="bugreport_message" msgid="398447048750350456">"Báo cáo này sẽ thu thập thông tin về tình trạng thiết bị hiện tại của bạn, để gửi dưới dạng thông báo qua email. Sẽ mất một chút thời gian kể từ khi bắt đầu báo cáo lỗi cho tới khi báo cáo sẵn sàng để gửi; xin vui lòng kiên nhẫn."</string>
    +@@ -1076,6 +1077,17 @@
    +     <skip />
    +     <string name="wifi_no_internet" msgid="8451173622563841546">"Wi-Fi không có quyền truy cập Internet"</string>
    +     <string name="wifi_no_internet_detailed" msgid="8083079241212301741">"Nhấn để biết tùy chọn"</string>
    ++    <string name="network_switch_metered" msgid="4671730921726992671">"Đã chuyển sang <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
    ++    <string name="network_switch_metered_detail" msgid="5325661434777870353">"Thiết bị sử dụng <xliff:g id="NEW_NETWORK">%1$s</xliff:g> khi <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> không có quyền truy cập Internet. Bạn có thể phải trả phí."</string>
    ++    <string name="network_switch_metered_toast" msgid="5779283181685974304">"Đã chuyển từ <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> sang <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
    ++  <string-array name="network_switch_type_name">
    ++    <item msgid="2952042958050315394">"dữ liệu di động"</item>
    ++    <item msgid="75483255295529161">"Wi-Fi"</item>
    ++    <item msgid="6862614801537202646">"Bluetooth"</item>
    ++    <item msgid="5447331121797802871">"Ethernet"</item>
    ++    <item msgid="8257233890381651999">"VPN"</item>
    ++  </string-array>
    ++    <string name="network_switch_type_name_unknown" msgid="4552612897806660656">"loại mạng không xác định"</string>
    +     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Không thể kết nối với Wi-Fi"</string>
    +     <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" có kết nối Internet không tốt."</string>
    +     <string name="wifi_connect_alert_title" msgid="8455846016001810172">"Cho phép kết nối?"</string>
    +@@ -1153,7 +1165,6 @@
    +     <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"Nhấn để chọn ngôn ngữ và bố cục"</string>
    +     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
    +     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
    +-    <string name="candidates_style" msgid="4333913089637062257"><u>"ứng viên"</u></string>
    +     <string name="ext_media_checking_notification_title" msgid="5734005953288045806">"Đang chuẩn bị <xliff:g id="NAME">%s</xliff:g>"</string>
    +     <string name="ext_media_checking_notification_message" msgid="4747432538578886744">"Đang kiểm tra lỗi"</string>
    +     <string name="ext_media_new_notification_message" msgid="7589986898808506239">"Đã phát hiện <xliff:g id="NAME">%s</xliff:g> mới"</string>
    +@@ -1232,8 +1243,9 @@
    +     <string name="vpn_text_long" msgid="4907843483284977618">"Đã kết nối với <xliff:g id="SESSION">%s</xliff:g>. Chạm để quản lý mạng."</string>
    +     <string name="vpn_lockdown_connecting" msgid="6443438964440960745">"Đang kết nối VPN luôn bật…"</string>
    +     <string name="vpn_lockdown_connected" msgid="8202679674819213931">"Đã kết nối VPN luôn bật"</string>
    ++    <string name="vpn_lockdown_disconnected" msgid="4532298952570796327">"Đã ngắt kết nối VPN luôn bật"</string>
    +     <string name="vpn_lockdown_error" msgid="6009249814034708175">"Lỗi VPN luôn bật"</string>
    +-    <string name="vpn_lockdown_config" msgid="4655589351146766608">"Nhấn để định cấu hình"</string>
    ++    <string name="vpn_lockdown_config" msgid="5099330695245008680">"Nhấn để thiết lập"</string>
    +     <string name="upload_file" msgid="2897957172366730416">"Chọn tệp"</string>
    +     <string name="no_file_chosen" msgid="6363648562170759465">"Không có tệp nào được chọn"</string>
    +     <string name="reset" msgid="2448168080964209908">"Đặt lại"</string>
    +@@ -1317,7 +1329,7 @@
    +     <string name="storage_usb_drive_label" msgid="4501418548927759953">"Ổ USB <xliff:g id="MANUFACTURER">%s</xliff:g>"</string>
    +     <string name="storage_usb" msgid="3017954059538517278">"Bộ lưu trữ USB"</string>
    +     <string name="extract_edit_menu_button" msgid="8940478730496610137">"Chỉnh sửa"</string>
    +-    <string name="data_usage_warning_title" msgid="1955638862122232342">"Cảnh báo sử dụng dữ liệu"</string>
    ++    <string name="data_usage_warning_title" msgid="3620440638180218181">"Thông báo về sử dụng dữ liệu"</string>
    +     <string name="data_usage_warning_body" msgid="6660692274311972007">"Nhấn để xem sử dụng và cài đặt."</string>
    +     <string name="data_usage_3g_limit_title" msgid="4361523876818447683">"Đã đạt tới giới hạn dữ liệu 2G-3G"</string>
    +     <string name="data_usage_4g_limit_title" msgid="4609566827219442376">"Đã đạt tới giới hạn dữ liệu 4G"</string>
    +@@ -1636,6 +1648,7 @@
    +     <string name="search_language_hint" msgid="7042102592055108574">"Nhập tên ngôn ngữ"</string>
    +     <string name="language_picker_section_suggested" msgid="8414489646861640885">"Ðược đề xuất"</string>
    +     <string name="language_picker_section_all" msgid="3097279199511617537">"Tất cả ngôn ngữ"</string>
    ++    <string name="region_picker_section_all" msgid="8966316787153001779">"Tất cả khu vực"</string>
    +     <string name="locale_search_menu" msgid="2560710726687249178">"Tìm kiếm"</string>
    +     <string name="work_mode_off_title" msgid="8954725060677558855">"Chế độ làm việc đang TẮT"</string>
    +     <string name="work_mode_off_message" msgid="3286169091278094476">"Cho phép hồ sơ công việc hoạt động, bao gồm ứng dụng, đồng bộ hóa trong nền và các tính năng liên quan."</string>
    +diff --git a/core/res/res/values-watch/donottranslate.xml b/core/res/res/values-watch/donottranslate.xml
    +new file mode 100644
    +index 0000000..d247ff6
    +--- /dev/null
    ++++ b/core/res/res/values-watch/donottranslate.xml
    +@@ -0,0 +1,22 @@
    ++<?xml version="1.0" encoding="utf-8"?>
    ++<!-- Copyright (C) 2016 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.
    ++-->
    ++
    ++<resources>
    ++    <!-- DO NOT TRANSLATE Spans within this text are applied to style composing regions
    ++    within an EditText widget. The text content is ignored and not used.
    ++    Note: This is @color/material_deep_teal_200, cannot use @color references here. -->
    ++    <string name="candidates_style" translatable="false"><font color="#80cbc4">candidates</font></string>
    ++ </resources>
    +diff --git a/core/res/res/values-watch/styles_material.xml b/core/res/res/values-watch/styles_material.xml
    +index f5735e6..a9f6e22 100644
    +--- a/core/res/res/values-watch/styles_material.xml
    ++++ b/core/res/res/values-watch/styles_material.xml
    +@@ -88,9 +88,4 @@ please see styles_device_defaults.xml.
    +         <item name="virtualButtonPressedDrawable">?selectableItemBackground</item>
    +         <item name="descendantFocusability">blocksDescendants</item>
    +     </style>
    +-
    +-    <!-- DO NOTE TRANSLATE Spans within this text are applied to style composing regions
    +-    within an EditText widget. The text content is ignored and not used.
    +-    Note: This is @color/material_deep_teal_200, cannot use @color references here. -->
    +-    <string name="candidates_style"><font color="#80cbc4">candidates</font></string>
    + </resources>
    +diff --git a/core/res/res/values-zh-rCN/strings.xml b/core/res/res/values-zh-rCN/strings.xml
    +index 8116ec0..98ae54c 100644
    +--- a/core/res/res/values-zh-rCN/strings.xml
    ++++ b/core/res/res/values-zh-rCN/strings.xml
    +@@ -195,7 +195,7 @@
    +     <string name="silent_mode_ring" msgid="8592241816194074353">"振铃器开启"</string>
    +     <string name="reboot_to_update_title" msgid="6212636802536823850">"Android 系统更新"</string>
    +     <string name="reboot_to_update_prepare" msgid="6305853831955310890">"正在准备更新…"</string>
    +-    <string name="reboot_to_update_package" msgid="3871302324500927291">"正在处理更新文件包…"</string>
    ++    <string name="reboot_to_update_package" msgid="3871302324500927291">"正在处理更新软件包…"</string>
    +     <string name="reboot_to_update_reboot" msgid="6428441000951565185">"正在重新启动…"</string>
    +     <string name="reboot_to_reset_title" msgid="4142355915340627490">"恢复出厂设置"</string>
    +     <string name="reboot_to_reset_message" msgid="2432077491101416345">"正在重新启动…"</string>
    +@@ -214,6 +214,7 @@
    +     <string name="global_actions" product="default" msgid="2406416831541615258">"手机选项"</string>
    +     <string name="global_action_lock" msgid="2844945191792119712">"屏幕锁定"</string>
    +     <string name="global_action_power_off" msgid="4471879440839879722">"关机"</string>
    ++    <string name="global_action_emergency" msgid="7112311161137421166">"紧急呼救"</string>
    +     <string name="global_action_bug_report" msgid="7934010578922304799">"错误报告"</string>
    +     <string name="bugreport_title" msgid="2667494803742548533">"提交错误报告"</string>
    +     <string name="bugreport_message" msgid="398447048750350456">"这会收集有关当前设备状态的信息,并以电子邮件的形式进行发送。从开始生成错误报告到准备好发送需要一点时间,请耐心等待。"</string>
    +@@ -1076,6 +1077,17 @@
    +     <skip />
    +     <string name="wifi_no_internet" msgid="8451173622563841546">"此 WLAN 网络无法访问互联网"</string>
    +     <string name="wifi_no_internet_detailed" msgid="8083079241212301741">"点按即可查看相关选项"</string>
    ++    <string name="network_switch_metered" msgid="4671730921726992671">"已切换至<xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
    ++    <string name="network_switch_metered_detail" msgid="5325661434777870353">"设备会在无法连接到<xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g>时使用<xliff:g id="NEW_NETWORK">%1$s</xliff:g>(可能需要支付相应的费用)。"</string>
    ++    <string name="network_switch_metered_toast" msgid="5779283181685974304">"已从<xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g>切换至<xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
    ++  <string-array name="network_switch_type_name">
    ++    <item msgid="2952042958050315394">"移动数据网络"</item>
    ++    <item msgid="75483255295529161">"WLAN"</item>
    ++    <item msgid="6862614801537202646">"蓝牙"</item>
    ++    <item msgid="5447331121797802871">"以太网"</item>
    ++    <item msgid="8257233890381651999">"VPN"</item>
    ++  </string-array>
    ++    <string name="network_switch_type_name_unknown" msgid="4552612897806660656">"未知网络类型"</string>
    +     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"无法连接到WLAN"</string>
    +     <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" 互联网连接状况不佳。"</string>
    +     <string name="wifi_connect_alert_title" msgid="8455846016001810172">"要允许连接吗?"</string>
    +@@ -1153,7 +1165,6 @@
    +     <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"点按即可选择语言和布局"</string>
    +     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
    +     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
    +-    <string name="candidates_style" msgid="4333913089637062257"><u>"候选"</u></string>
    +     <string name="ext_media_checking_notification_title" msgid="5734005953288045806">"正在准备<xliff:g id="NAME">%s</xliff:g>"</string>
    +     <string name="ext_media_checking_notification_message" msgid="4747432538578886744">"检查是否有错误"</string>
    +     <string name="ext_media_new_notification_message" msgid="7589986898808506239">"检测到新的<xliff:g id="NAME">%s</xliff:g>"</string>
    +@@ -1232,8 +1243,9 @@
    +     <string name="vpn_text_long" msgid="4907843483284977618">"已连接到<xliff:g id="SESSION">%s</xliff:g>。点按即可管理网络。"</string>
    +     <string name="vpn_lockdown_connecting" msgid="6443438964440960745">"正在连接到始终开启的 VPN…"</string>
    +     <string name="vpn_lockdown_connected" msgid="8202679674819213931">"已连接到始终开启的 VPN"</string>
    ++    <string name="vpn_lockdown_disconnected" msgid="4532298952570796327">"始终开启的 VPN 已断开连接"</string>
    +     <string name="vpn_lockdown_error" msgid="6009249814034708175">"始终开启的 VPN 出现错误"</string>
    +-    <string name="vpn_lockdown_config" msgid="4655589351146766608">"点按即可进行配置"</string>
    ++    <string name="vpn_lockdown_config" msgid="5099330695245008680">"点按即可进行设置"</string>
    +     <string name="upload_file" msgid="2897957172366730416">"选择文件"</string>
    +     <string name="no_file_chosen" msgid="6363648562170759465">"未选定任何文件"</string>
    +     <string name="reset" msgid="2448168080964209908">"重置"</string>
    +@@ -1317,7 +1329,7 @@
    +     <string name="storage_usb_drive_label" msgid="4501418548927759953">"<xliff:g id="MANUFACTURER">%s</xliff:g> U 盘"</string>
    +     <string name="storage_usb" msgid="3017954059538517278">"USB存储器"</string>
    +     <string name="extract_edit_menu_button" msgid="8940478730496610137">"修改"</string>
    +-    <string name="data_usage_warning_title" msgid="1955638862122232342">"流量警告"</string>
    ++    <string name="data_usage_warning_title" msgid="3620440638180218181">"流量消耗提醒"</string>
    +     <string name="data_usage_warning_body" msgid="6660692274311972007">"点按即可查看使用情况和设置。"</string>
    +     <string name="data_usage_3g_limit_title" msgid="4361523876818447683">"已达到2G-3G流量上限"</string>
    +     <string name="data_usage_4g_limit_title" msgid="4609566827219442376">"已达到4G流量上限"</string>
    +@@ -1636,6 +1648,7 @@
    +     <string name="search_language_hint" msgid="7042102592055108574">"输入语言名称"</string>
    +     <string name="language_picker_section_suggested" msgid="8414489646861640885">"建议语言"</string>
    +     <string name="language_picker_section_all" msgid="3097279199511617537">"所有语言"</string>
    ++    <string name="region_picker_section_all" msgid="8966316787153001779">"所有国家/地区"</string>
    +     <string name="locale_search_menu" msgid="2560710726687249178">"搜索"</string>
    +     <string name="work_mode_off_title" msgid="8954725060677558855">"工作模式已关闭"</string>
    +     <string name="work_mode_off_message" msgid="3286169091278094476">"启用工作资料,包括应用、后台同步和相关功能。"</string>
    +diff --git a/core/res/res/values-zh-rHK/strings.xml b/core/res/res/values-zh-rHK/strings.xml
    +index ef12eea..8e034a7 100644
    +--- a/core/res/res/values-zh-rHK/strings.xml
    ++++ b/core/res/res/values-zh-rHK/strings.xml
    +@@ -214,6 +214,7 @@
    +     <string name="global_actions" product="default" msgid="2406416831541615258">"手機選項"</string>
    +     <string name="global_action_lock" msgid="2844945191792119712">"螢幕鎖定"</string>
    +     <string name="global_action_power_off" msgid="4471879440839879722">"關閉"</string>
    ++    <string name="global_action_emergency" msgid="7112311161137421166">"緊急"</string>
    +     <string name="global_action_bug_report" msgid="7934010578922304799">"錯誤報告"</string>
    +     <string name="bugreport_title" msgid="2667494803742548533">"取得錯誤報告"</string>
    +     <string name="bugreport_message" msgid="398447048750350456">"這會收集您目前裝置狀態的相關資訊,並以電郵傳送給您。從開始建立錯誤報告到準備傳送需要一段時間,請耐心等候。"</string>
    +@@ -1076,6 +1077,17 @@
    +     <skip />
    +     <string name="wifi_no_internet" msgid="8451173622563841546">"Wi-Fi 並未連接互聯網"</string>
    +     <string name="wifi_no_internet_detailed" msgid="8083079241212301741">"輕按即可查看選項"</string>
    ++    <string name="network_switch_metered" msgid="4671730921726992671">"已切換至<xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
    ++    <string name="network_switch_metered_detail" msgid="5325661434777870353">"當<xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g>無法連線至互聯網時,裝置便會切換至<xliff:g id="NEW_NETWORK">%1$s</xliff:g>。可能需要支付額外費用。"</string>
    ++    <string name="network_switch_metered_toast" msgid="5779283181685974304">"已從<xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g>切換至<xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
    ++  <string-array name="network_switch_type_name">
    ++    <item msgid="2952042958050315394">"流動數據"</item>
    ++    <item msgid="75483255295529161">"Wi-Fi"</item>
    ++    <item msgid="6862614801537202646">"藍牙"</item>
    ++    <item msgid="5447331121797802871">"以太網"</item>
    ++    <item msgid="8257233890381651999">"VPN"</item>
    ++  </string-array>
    ++    <string name="network_switch_type_name_unknown" msgid="4552612897806660656">"不明網絡類型"</string>
    +     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"無法連線至 Wi-Fi"</string>
    +     <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" 互聯網連線欠佳。"</string>
    +     <string name="wifi_connect_alert_title" msgid="8455846016001810172">"允許連線?"</string>
    +@@ -1153,7 +1165,6 @@
    +     <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"輕按即可選取語言和鍵盤配置"</string>
    +     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
    +     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
    +-    <string name="candidates_style" msgid="4333913089637062257"><u>"待選項目"</u></string>
    +     <string name="ext_media_checking_notification_title" msgid="5734005953288045806">"正在準備<xliff:g id="NAME">%s</xliff:g>"</string>
    +     <string name="ext_media_checking_notification_message" msgid="4747432538578886744">"正在檢查錯誤"</string>
    +     <string name="ext_media_new_notification_message" msgid="7589986898808506239">"已偵測到新<xliff:g id="NAME">%s</xliff:g>"</string>
    +@@ -1232,8 +1243,9 @@
    +     <string name="vpn_text_long" msgid="4907843483284977618">"已連線至 <xliff:g id="SESSION">%s</xliff:g>,輕按一下即可管理網絡。"</string>
    +     <string name="vpn_lockdown_connecting" msgid="6443438964440960745">"正在連線至永久連線的 VPN…"</string>
    +     <string name="vpn_lockdown_connected" msgid="8202679674819213931">"已連線至永久連線的 VPN"</string>
    ++    <string name="vpn_lockdown_disconnected" msgid="4532298952570796327">"永久連線的 VPN 已中斷"</string>
    +     <string name="vpn_lockdown_error" msgid="6009249814034708175">"永久連線的 VPN 發生錯誤"</string>
    +-    <string name="vpn_lockdown_config" msgid="4655589351146766608">"輕觸即可設定"</string>
    ++    <string name="vpn_lockdown_config" msgid="5099330695245008680">"輕按即可設定"</string>
    +     <string name="upload_file" msgid="2897957172366730416">"選擇檔案"</string>
    +     <string name="no_file_chosen" msgid="6363648562170759465">"未選擇檔案"</string>
    +     <string name="reset" msgid="2448168080964209908">"重設"</string>
    +@@ -1317,7 +1329,7 @@
    +     <string name="storage_usb_drive_label" msgid="4501418548927759953">"<xliff:g id="MANUFACTURER">%s</xliff:g> USB 驅動器"</string>
    +     <string name="storage_usb" msgid="3017954059538517278">"USB 儲存裝置"</string>
    +     <string name="extract_edit_menu_button" msgid="8940478730496610137">"編輯"</string>
    +-    <string name="data_usage_warning_title" msgid="1955638862122232342">"資料用量警告"</string>
    ++    <string name="data_usage_warning_title" msgid="3620440638180218181">"數據用量警告"</string>
    +     <string name="data_usage_warning_body" msgid="6660692274311972007">"輕按即可查看用量和設定。"</string>
    +     <string name="data_usage_3g_limit_title" msgid="4361523876818447683">"已達到 2G-3G 數據流量上限"</string>
    +     <string name="data_usage_4g_limit_title" msgid="4609566827219442376">"已達到 4G 數據流量上限"</string>
    +@@ -1636,6 +1648,7 @@
    +     <string name="search_language_hint" msgid="7042102592055108574">"輸入語言名稱"</string>
    +     <string name="language_picker_section_suggested" msgid="8414489646861640885">"建議"</string>
    +     <string name="language_picker_section_all" msgid="3097279199511617537">"所有語言"</string>
    ++    <string name="region_picker_section_all" msgid="8966316787153001779">"所有國家/地區"</string>
    +     <string name="locale_search_menu" msgid="2560710726687249178">"搜尋"</string>
    +     <string name="work_mode_off_title" msgid="8954725060677558855">"工作模式已關閉"</string>
    +     <string name="work_mode_off_message" msgid="3286169091278094476">"允許使用應用程式、背景同步及相關功能的工作設定檔。"</string>
    +diff --git a/core/res/res/values-zh-rTW/strings.xml b/core/res/res/values-zh-rTW/strings.xml
    +index 84e2c2c..82b4f6d 100644
    +--- a/core/res/res/values-zh-rTW/strings.xml
    ++++ b/core/res/res/values-zh-rTW/strings.xml
    +@@ -214,6 +214,7 @@
    +     <string name="global_actions" product="default" msgid="2406416831541615258">"電話選項"</string>
    +     <string name="global_action_lock" msgid="2844945191792119712">"螢幕鎖定"</string>
    +     <string name="global_action_power_off" msgid="4471879440839879722">"關機"</string>
    ++    <string name="global_action_emergency" msgid="7112311161137421166">"緊急電話"</string>
    +     <string name="global_action_bug_report" msgid="7934010578922304799">"錯誤報告"</string>
    +     <string name="bugreport_title" msgid="2667494803742548533">"取得錯誤報告"</string>
    +     <string name="bugreport_message" msgid="398447048750350456">"這會收集您目前裝置狀態的相關資訊,以便透過電子郵件傳送。從錯誤報告開始建立到準備傳送的這段過程可能需要一點時間,敬請耐心等候。"</string>
    +@@ -1076,6 +1077,17 @@
    +     <skip />
    +     <string name="wifi_no_internet" msgid="8451173622563841546">"Wi-Fi 網路沒有網際網路連線"</string>
    +     <string name="wifi_no_internet_detailed" msgid="8083079241212301741">"輕觸即可查看選項"</string>
    ++    <string name="network_switch_metered" msgid="4671730921726992671">"已切換至<xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
    ++    <string name="network_switch_metered_detail" msgid="5325661434777870353">"裝置會在無法連上 <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> 時切換至<xliff:g id="NEW_NETWORK">%1$s</xliff:g> (可能需要支付相關費用)。"</string>
    ++    <string name="network_switch_metered_toast" msgid="5779283181685974304">"已從 <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> 切換至<xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
    ++  <string-array name="network_switch_type_name">
    ++    <item msgid="2952042958050315394">"行動數據"</item>
    ++    <item msgid="75483255295529161">"Wi-Fi"</item>
    ++    <item msgid="6862614801537202646">"藍牙"</item>
    ++    <item msgid="5447331121797802871">"乙太網路"</item>
    ++    <item msgid="8257233890381651999">"VPN"</item>
    ++  </string-array>
    ++    <string name="network_switch_type_name_unknown" msgid="4552612897806660656">"不明的網路類型"</string>
    +     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"無法連線至 Wi-Fi"</string>
    +     <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" 的網際網路連線狀況不佳。"</string>
    +     <string name="wifi_connect_alert_title" msgid="8455846016001810172">"允許連線?"</string>
    +@@ -1153,7 +1165,6 @@
    +     <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"輕觸即可選取語言和版面配置"</string>
    +     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
    +     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
    +-    <string name="candidates_style" msgid="4333913089637062257"><u>"待選項目"</u></string>
    +     <string name="ext_media_checking_notification_title" msgid="5734005953288045806">"正在準備「<xliff:g id="NAME">%s</xliff:g>」"</string>
    +     <string name="ext_media_checking_notification_message" msgid="4747432538578886744">"正在檢查錯誤"</string>
    +     <string name="ext_media_new_notification_message" msgid="7589986898808506239">"偵測到新的「<xliff:g id="NAME">%s</xliff:g>」"</string>
    +@@ -1232,8 +1243,9 @@
    +     <string name="vpn_text_long" msgid="4907843483284977618">"已連線至 <xliff:g id="SESSION">%s</xliff:g>,輕觸一下即可管理網路。"</string>
    +     <string name="vpn_lockdown_connecting" msgid="6443438964440960745">"正在連線至永久連線的 VPN…"</string>
    +     <string name="vpn_lockdown_connected" msgid="8202679674819213931">"已連線至永久連線的 VPN"</string>
    ++    <string name="vpn_lockdown_disconnected" msgid="4532298952570796327">"永久連線的 VPN 已中斷連線"</string>
    +     <string name="vpn_lockdown_error" msgid="6009249814034708175">"永久連線的 VPN 發生錯誤"</string>
    +-    <string name="vpn_lockdown_config" msgid="4655589351146766608">"輕觸即可進行設定"</string>
    ++    <string name="vpn_lockdown_config" msgid="5099330695245008680">"輕觸即可進行設定"</string>
    +     <string name="upload_file" msgid="2897957172366730416">"選擇檔案"</string>
    +     <string name="no_file_chosen" msgid="6363648562170759465">"未選擇任何檔案"</string>
    +     <string name="reset" msgid="2448168080964209908">"重設"</string>
    +@@ -1317,7 +1329,7 @@
    +     <string name="storage_usb_drive_label" msgid="4501418548927759953">"<xliff:g id="MANUFACTURER">%s</xliff:g> USB 隨身碟"</string>
    +     <string name="storage_usb" msgid="3017954059538517278">"USB 儲存裝置"</string>
    +     <string name="extract_edit_menu_button" msgid="8940478730496610137">"編輯"</string>
    +-    <string name="data_usage_warning_title" msgid="1955638862122232342">"數據用量警告"</string>
    ++    <string name="data_usage_warning_title" msgid="3620440638180218181">"數據用量警告"</string>
    +     <string name="data_usage_warning_body" msgid="6660692274311972007">"輕觸即可查看用量和設定。"</string>
    +     <string name="data_usage_3g_limit_title" msgid="4361523876818447683">"已達到 2G-3G 數據流量上限"</string>
    +     <string name="data_usage_4g_limit_title" msgid="4609566827219442376">"已達到 4G 數據流量上限"</string>
    +@@ -1636,6 +1648,7 @@
    +     <string name="search_language_hint" msgid="7042102592055108574">"請輸入語言名稱"</string>
    +     <string name="language_picker_section_suggested" msgid="8414489646861640885">"建議語言"</string>
    +     <string name="language_picker_section_all" msgid="3097279199511617537">"所有語言"</string>
    ++    <string name="region_picker_section_all" msgid="8966316787153001779">"所有地區"</string>
    +     <string name="locale_search_menu" msgid="2560710726687249178">"搜尋"</string>
    +     <string name="work_mode_off_title" msgid="8954725060677558855">"Work 模式已關閉"</string>
    +     <string name="work_mode_off_message" msgid="3286169091278094476">"啟用 Work 設定檔,包括應用程式、背景同步處理和相關功能。"</string>
    +diff --git a/core/res/res/values-zu/strings.xml b/core/res/res/values-zu/strings.xml
    +index 0c7af8d..20dfcc0 100644
    +--- a/core/res/res/values-zu/strings.xml
    ++++ b/core/res/res/values-zu/strings.xml
    +@@ -214,6 +214,7 @@
    +     <string name="global_actions" product="default" msgid="2406416831541615258">"Okukhethwa kukho kwefoni"</string>
    +     <string name="global_action_lock" msgid="2844945191792119712">"Ukuvala isikrini"</string>
    +     <string name="global_action_power_off" msgid="4471879440839879722">"Vala amandla"</string>
    ++    <string name="global_action_emergency" msgid="7112311161137421166">"Isimo esiphuthumayo"</string>
    +     <string name="global_action_bug_report" msgid="7934010578922304799">"Umbiko wephutha"</string>
    +     <string name="bugreport_title" msgid="2667494803742548533">"Thatha umbiko wesiphazamiso"</string>
    +     <string name="bugreport_message" msgid="398447048750350456">"Lokhu kuzoqoqa ulwazi mayelana nesimo samanje sedivayisi yakho, ukuthumela imilayezo ye-imeyili. Kuzothatha isikhathi esincane kusuka ekuqaleni umbiko wesiphazamiso uze ulungele ukuthunyelwa; sicela ubekezele."</string>
    +@@ -1076,6 +1077,17 @@
    +     <skip />
    +     <string name="wifi_no_internet" msgid="8451173622563841546">"I-Wi-Fi ayinakho ukufinyelela kwe-inthanethi"</string>
    +     <string name="wifi_no_internet_detailed" msgid="8083079241212301741">"Thepha ukuze uthole izinketho"</string>
    ++    <string name="network_switch_metered" msgid="4671730921726992671">"Kushintshelwe ku-<xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
    ++    <string name="network_switch_metered_detail" msgid="5325661434777870353">"Idivayisi isebenzisa i-<xliff:g id="NEW_NETWORK">%1$s</xliff:g> uma i-<xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> ingenakho ukufinyelela kwe-inthanethi. Izindleko zingasebenza."</string>
    ++    <string name="network_switch_metered_toast" msgid="5779283181685974304">"Kushintshelewe kusuka ku-<xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> kuya ku-<xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
    ++  <string-array name="network_switch_type_name">
    ++    <item msgid="2952042958050315394">"idatha yeselula"</item>
    ++    <item msgid="75483255295529161">"I-Wi-Fi"</item>
    ++    <item msgid="6862614801537202646">"I-Bluetooth"</item>
    ++    <item msgid="5447331121797802871">"I-Ethernet"</item>
    ++    <item msgid="8257233890381651999">"I-VPN"</item>
    ++  </string-array>
    ++    <string name="network_switch_type_name_unknown" msgid="4552612897806660656">"uhlobo olungaziwa lwenethiwekhi"</string>
    +     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Ayikwazanga ukuxhuma kwi-Wi-Fi"</string>
    +     <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" inoxhumano oluphansi lwe-inthanethi."</string>
    +     <string name="wifi_connect_alert_title" msgid="8455846016001810172">"Vumela ukuxhumeka?"</string>
    +@@ -1153,7 +1165,6 @@
    +     <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"Thepha ukuze ukhethe ulimi nesakhiwo"</string>
    +     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
    +     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
    +-    <string name="candidates_style" msgid="4333913089637062257"><u>"abahlanganyeli"</u></string>
    +     <string name="ext_media_checking_notification_title" msgid="5734005953288045806">"Ilungiselela i-<xliff:g id="NAME">%s</xliff:g>"</string>
    +     <string name="ext_media_checking_notification_message" msgid="4747432538578886744">"Ihlolela amaphutha"</string>
    +     <string name="ext_media_new_notification_message" msgid="7589986898808506239">"I-<xliff:g id="NAME">%s</xliff:g> entsha itholiwe"</string>
    +@@ -1232,8 +1243,9 @@
    +     <string name="vpn_text_long" msgid="4907843483284977618">"Ixhume ku-<xliff:g id="SESSION">%s</xliff:g>. Thepha ukuphatha inethiwekhi."</string>
    +     <string name="vpn_lockdown_connecting" msgid="6443438964440960745">"I-VPN ehlala ikhanya iyaxhuma…"</string>
    +     <string name="vpn_lockdown_connected" msgid="8202679674819213931">"I-VPN ehlala ikhanya ixhunyiwe"</string>
    ++    <string name="vpn_lockdown_disconnected" msgid="4532298952570796327">"Njalo kuvuliwe i-VPN kunqamukile"</string>
    +     <string name="vpn_lockdown_error" msgid="6009249814034708175">"Iphutha le-VPN ehlala ikhanya"</string>
    +-    <string name="vpn_lockdown_config" msgid="4655589351146766608">"Thinta ukuze umise"</string>
    ++    <string name="vpn_lockdown_config" msgid="5099330695245008680">"Thepha ukuze usethe"</string>
    +     <string name="upload_file" msgid="2897957172366730416">"Khetha ifayela"</string>
    +     <string name="no_file_chosen" msgid="6363648562170759465">"Ayikho ifayela ekhethiwe"</string>
    +     <string name="reset" msgid="2448168080964209908">"Setha kabusha"</string>
    +@@ -1317,7 +1329,7 @@
    +     <string name="storage_usb_drive_label" msgid="4501418548927759953">"<xliff:g id="MANUFACTURER">%s</xliff:g> idrayivu ye-USB"</string>
    +     <string name="storage_usb" msgid="3017954059538517278">"Isitoreji se-USB"</string>
    +     <string name="extract_edit_menu_button" msgid="8940478730496610137">"Hlela"</string>
    +-    <string name="data_usage_warning_title" msgid="1955638862122232342">"Isexwayiso sokusetshenziswa kwedatha"</string>
    ++    <string name="data_usage_warning_title" msgid="3620440638180218181">"Izexwayiso zokusetshenziswa kwedatha"</string>
    +     <string name="data_usage_warning_body" msgid="6660692274311972007">"Thepha ukuze ubuke ukusetshenziswa nezilungiselelo."</string>
    +     <string name="data_usage_3g_limit_title" msgid="4361523876818447683">"2G-3G umkhawulo wedatha ufinyelelwe"</string>
    +     <string name="data_usage_4g_limit_title" msgid="4609566827219442376">"4G umkhawulo wedatha ufinyelelwe"</string>
    +@@ -1636,6 +1648,7 @@
    +     <string name="search_language_hint" msgid="7042102592055108574">"Thayipha igama lolimi"</string>
    +     <string name="language_picker_section_suggested" msgid="8414489646861640885">"Okuphakanyisiwe"</string>
    +     <string name="language_picker_section_all" msgid="3097279199511617537">"Zonke izilimi"</string>
    ++    <string name="region_picker_section_all" msgid="8966316787153001779">"Zonke izifunda"</string>
    +     <string name="locale_search_menu" msgid="2560710726687249178">"Sesha"</string>
    +     <string name="work_mode_off_title" msgid="8954725060677558855">"Imodi yomsebenzi IVALIWE"</string>
    +     <string name="work_mode_off_message" msgid="3286169091278094476">"Vumela iphrofayela yomsebenzi ukuze isebenze, efaka izinhlelo zokusebenza, ukuvumelanisa kwangemuva, nezici ezisondelene."</string>
    +diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
    +index 48e4201..30a1a28 100644
    +--- a/core/res/res/values/attrs.xml
    ++++ b/core/res/res/values/attrs.xml
    +@@ -4839,6 +4839,11 @@ i
    +         <!-- The list year's selected circle color in the list.
    +              {@deprecated No longer displayed.} -->
    +         <attr name="yearListSelectorColor" format="color" />
    ++
    ++        <!-- @hide Whether this time picker is being displayed within a dialog,
    ++             in which case it may ignore the requested time picker mode due to
    ++             space considerations. -->
    ++        <attr name="dialogMode" format="boolean" />
    +     </declare-styleable>
    + 
    +     <declare-styleable name="TwoLineListItem">
    +@@ -5167,6 +5172,11 @@ i
    +         <!-- The background color state list for the AM/PM selectors.
    +              {@deprecated Use headerBackground instead.}-->
    +         <attr name="amPmBackgroundColor" format="color" />
    ++
    ++        <!-- @hide Whether this time picker is being displayed within a dialog,
    ++             in which case it may ignore the requested time picker mode due to
    ++             space considerations. -->
    ++        <attr name="dialogMode" />
    +     </declare-styleable>
    + 
    +     <!-- ========================= -->
    +@@ -5313,6 +5323,21 @@ i
    +         <attr name="alpha" />
    +     </declare-styleable>
    + 
    ++    <!-- Drawable used to render according to the animation scale. Esp. when it is 0 due to battery
    ++         saver mode. It should contain one animatable drawable and one static drawable.
    ++         @hide -->
    ++    <declare-styleable name="AnimationScaleListDrawable">
    ++    </declare-styleable>
    ++
    ++    <!-- Attributes that can be assigned to a AnimationScaleListDrawable item.
    ++         @hide -->
    ++    <declare-styleable name="AnimationScaleListDrawableItem">
    ++        <!-- Reference to a drawable resource to use for the state. If not
    ++             given, the drawable must be defined by the first child tag. -->
    ++        <attr name="drawable" />
    ++    </declare-styleable>
    ++
    ++
    +     <!-- Drawable used to render a geometric shape, with a gradient or a solid color. -->
    +     <declare-styleable name="GradientDrawable">
    +         <!-- Indicates whether the drawable should intially be visible. -->
    +@@ -5342,7 +5367,10 @@ i
    +         <attr name="innerRadius" format="dimension" />
    +         <!-- Thickness of the ring. When defined, thicknessRatio is ignored. -->
    +         <attr name="thickness" format="dimension" />
    +-        <!-- Indicates whether the drawable's level affects the way the gradient is drawn. -->
    ++        <!-- Whether the drawable level value (see
    ++             {@link android.graphics.drawable.Drawable#getLevel()}) is used to scale the shape.
    ++             Scaling behavior depends on the shape type. For "ring", the angle is scaled from 0 to
    ++             360. For all other types, there is no effect. The default value is true. -->
    +         <attr name="useLevel" />
    +         <!-- If set, specifies the color to apply to the drawable as a tint. By default,
    +              no tint is applied. May be a color state list. -->
    +@@ -5376,28 +5404,37 @@ i
    +     <declare-styleable name="GradientDrawableGradient">
    +         <!-- Start color of the gradient. -->
    +         <attr name="startColor" format="color" />
    +-        <!-- Optional center color. For linear gradients, use centerX or centerY
    +-             to place the center color. -->
    ++        <!-- Optional center color. For linear gradients, use centerX or centerY to place the center
    ++             color. -->
    +         <attr name="centerColor" format="color" />
    +         <!-- End color of the gradient. -->
    +         <attr name="endColor" format="color" />
    ++        <!-- Whether the drawable level value (see
    ++             {@link android.graphics.drawable.Drawable#getLevel()}) is used to scale the gradient.
    ++             Scaling behavior varies based on gradient type. For "linear", adjusts the ending
    ++             position along the gradient's axis of orientation. For "radial", adjusts the outer
    ++             radius. For "sweep", adjusts the ending angle. The default value is false. -->
    +         <attr name="useLevel" format="boolean" />
    +-        <!-- Angle of the gradient. -->
    ++        <!-- Angle of the gradient, used only with linear gradient. Must be a multiple of 45 in the
    ++             range [0, 315]. -->
    +         <attr name="angle" format="float" />
    +         <!-- Type of gradient. The default type is linear. -->
    +         <attr name="type">
    +-            <!-- Linear gradient. -->
    ++            <!-- Linear gradient extending across the center point. -->
    +             <enum name="linear" value="0" />
    +-            <!-- Radial, or circular, gradient. -->
    ++            <!-- Radial gradient extending from the center point outward. -->
    +             <enum name="radial" value="1" />
    +-            <!-- Sweep, or angled or diamond, gradient. -->
    ++            <!-- Sweep (or angular) gradient sweeping counter-clockwise around the center point. -->
    +             <enum name="sweep"  value="2" />
    +         </attr>
    +-        <!-- X coordinate of the origin of the gradient within the shape. -->
    ++        <!-- X-position of the center point of the gradient within the shape as a fraction of the
    ++             width. The default value is 0.5. -->
    +         <attr name="centerX" format="float|fraction" />
    +-        <!-- Y coordinate of the origin of the gradient within the shape. -->
    ++        <!-- Y-position of the center point of the gradient within the shape as a fraction of the
    ++             height. The default value is 0.5. -->
    +         <attr name="centerY" format="float|fraction" />
    +-        <!-- Radius of the gradient, used only with radial gradient. -->
    ++        <!-- Radius of the gradient, used only with radial gradient. May be an explicit dimension
    ++             or a fractional value relative to the shape's minimum dimension. -->
    +         <attr name="gradientRadius" format="float|fraction|dimension" />
    +     </declare-styleable>
    + 
    +diff --git a/core/res/res/values/colors_material.xml b/core/res/res/values/colors_material.xml
    +index a864cf3..92426c6 100644
    +--- a/core/res/res/values/colors_material.xml
    ++++ b/core/res/res/values/colors_material.xml
    +@@ -61,7 +61,10 @@
    +     <color name="secondary_text_default_material_dark">#b3ffffff</color>
    + 
    +     <item name="hint_alpha_material_dark" format="float" type="dimen">0.50</item>
    +-    <item name="hint_alpha_material_light" format="float" type="dimen">0.54</item>
    ++    <item name="hint_alpha_material_light" format="float" type="dimen">0.38</item>
    ++
    ++    <item name="hint_pressed_alpha_material_dark" format="float" type="dimen">0.70</item>
    ++    <item name="hint_pressed_alpha_material_light" format="float" type="dimen">0.54</item>
    + 
    +     <item name="disabled_alpha_material_light" format="float" type="dimen">0.26</item>
    +     <item name="disabled_alpha_material_dark" format="float" type="dimen">0.30</item>
    +diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
    +index 3dbcdaf..ae8edab 100644
    +--- a/core/res/res/values/config.xml
    ++++ b/core/res/res/values/config.xml
    +@@ -1661,6 +1661,12 @@
    +          turned off and the screen off animation has been performed. -->
    +     <bool name="config_dozeAfterScreenOff">false</bool>
    + 
    ++    <!-- Doze: should the TYPE_PICK_UP_GESTURE sensor be used as a pulse signal. -->
    ++    <bool name="config_dozePulsePickup">false</bool>
    ++
    ++    <!-- Type of the double tap sensor. Empty if double tap is not supported. -->
    ++    <string name="config_dozeDoubleTapSensorType" translatable="false"></string>
    ++
    +     <!-- Power Management: Specifies whether to decouple the auto-suspend state of the
    +          device from the display on/off state.
    + 
    +@@ -2158,6 +2164,11 @@
    +     <!-- Flag specifying whether VT is available on device -->
    +     <bool name="config_device_vt_available">false</bool>
    + 
    ++    <!-- Flag specifying whether the device will use the "allow_hold_in_ims_call" carrier config
    ++         option.  When false, the device will support holding of IMS calls, regardless of the
    ++         carrier config setting. -->
    ++    <bool name="config_device_respects_hold_carrier_config">true</bool>
    ++
    +     <!-- Flag specifying whether VT should be available for carrier: independent of
    +          carrier provisioning. If false: hard disabled. If true: then depends on carrier
    +          provisioning, availability etc -->
    +@@ -2300,8 +2311,8 @@
    +     <!-- An array of CDMA roaming indicators which means international roaming -->
    +     <integer-array translatable="false" name="config_cdma_international_roaming_indicators" />
    + 
    +-    <!-- set the system language as value of EF LI/EF PL -->
    +-    <bool name="config_use_sim_language_file">true</bool>
    ++    <!-- flag to indicate if EF LI/EF PL should be used for system language -->
    ++    <bool name="config_use_sim_language_file">false</bool>
    + 
    +     <!-- Use ERI text for network name on CDMA LTE -->
    +     <bool name="config_LTE_eri_for_network_name">true</bool>
    +@@ -2521,6 +2532,16 @@
    +     <!-- True if the device supports system navigation keys. -->
    +     <bool name="config_supportSystemNavigationKeys">false</bool>
    + 
    ++    <!-- emergency call number for the emergency affordance -->
    ++    <string name="config_emergency_call_number" translatable="false">112</string>
    ++
    ++    <!-- Do not translate. Mcc codes whose existence trigger the presence of emergency
    ++         affordances-->
    ++    <integer-array name="config_emergency_mcc_codes" translatable="false">
    ++        <item>404</item>
    ++        <item>405</item>
    ++    </integer-array>
    ++
    +     <!-- Package name for the device provisioning package. -->
    +     <string name="config_deviceProvisioningPackage"></string>
    + 
    +@@ -2540,4 +2561,15 @@
    +         <!-- Verizon requires any SMS that starts with //VZWVVM to be treated as a VVM SMS-->
    +         <item>310004,310010,310012,310013,310590,310890,310910,311110,311270,311271,311272,311273,311274,311275,311276,311277,311278,311279,311280,311281,311282,311283,311284,311285,311286,311287,311288,311289,311390,311480,311481,311482,311483,311484,311485,311486,311487,311488,311489;^//VZWVVM.*</item>
    +     </string-array>
    ++    <!-- This config is holding calling number conversion map - expected to convert to emergency
    ++         number. Formats for this config as below:
    ++         <item>[dialstring1],[dialstring2],[dialstring3]:[replacement]</item>
    ++
    ++         E.g. for Taiwan Type Approval, 110 and 119 should be converted to 112.
    ++         <item>110,119:112</item>
    ++    -->
    ++    <string-array translatable="false" name="config_convert_to_emergency_number_map" />
    ++
    ++    <!-- An array of packages for which notifications cannot be blocked. -->
    ++    <string-array translatable="false" name="config_nonBlockableNotificationPackages" />
    + </resources>
    +diff --git a/core/res/res/values/donottranslate.xml b/core/res/res/values/donottranslate.xml
    +index a139529..3a1679c 100644
    +--- a/core/res/res/values/donottranslate.xml
    ++++ b/core/res/res/values/donottranslate.xml
    +@@ -26,4 +26,7 @@
    +     <string name="icu_abbrev_wday_month_day_no_year">eeeMMMMd</string>
    +     <!-- @hide DO NOT TRANSLATE. date formatting pattern for system ui.-->
    +     <string name="system_ui_date_pattern">@string/icu_abbrev_wday_month_day_no_year</string>
    ++    <!-- @hide DO NOT TRANSLATE Spans within this text are applied to style composing regions
    ++    within an EditText widget. The text content is ignored and not used. -->
    ++    <string name="candidates_style" translatable="false"><u>candidates</u></string>
    + </resources>
    +diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
    +index 9002ed4..f42c9ed 100644
    +--- a/core/res/res/values/strings.xml
    ++++ b/core/res/res/values/strings.xml
    +@@ -486,6 +486,9 @@
    +     <!-- TODO: promote to separate string-->
    +     <string name="global_action_restart" translatable="false">@string/sim_restart_button</string>
    + 
    ++    <!-- label for item that starts emergency call -->
    ++    <string name="global_action_emergency">Emergency</string>
    ++
    +     <!-- label for item that generates a bug report in the phone options dialog -->
    +     <string name="global_action_bug_report">Bug report</string>
    + 
    +@@ -3122,8 +3125,6 @@
    +     <string name="fast_scroll_alphabet">\u0020ABCDEFGHIJKLMNOPQRSTUVWXYZ</string>
    +     <string name="fast_scroll_numeric_alphabet">\u00200123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ</string>
    + 
    +-    <string name="candidates_style"><u>candidates</u></string>
    +-
    +     <!-- External media notification strings -->
    +     <skip />
    + 
    +@@ -3326,10 +3327,12 @@
    +     <string name="vpn_lockdown_connecting">Always-on VPN connecting\u2026</string>
    +     <!-- Notification title when connected to lockdown VPN. -->
    +     <string name="vpn_lockdown_connected">Always-on VPN connected</string>
    ++    <!-- Notification title when not connected to lockdown VPN. -->
    ++    <string name="vpn_lockdown_disconnected">Always-on VPN disconnected</string>
    +     <!-- Notification title when error connecting to lockdown VPN. -->
    +     <string name="vpn_lockdown_error">Always-on VPN error</string>
    +     <!-- Notification body that indicates user can touch to configure lockdown VPN connection. -->
    +-    <string name="vpn_lockdown_config">Tap to configure</string>
    ++    <string name="vpn_lockdown_config">Tap to set up</string>
    + 
    +     <!-- Localized strings for WebView -->
    +     <!-- Label for button in a WebView that will open a chooser to choose a file to upload -->
    +@@ -3550,8 +3553,8 @@
    +     <!-- Button text for the edit menu in input method extract mode. [CHAR LIMIT=16] -->
    +     <string name="extract_edit_menu_button">Edit</string>
    + 
    +-    <!-- Notification title when data usage has exceeded warning threshold. [CHAR LIMIT=32] -->
    +-    <string name="data_usage_warning_title">Data usage warning</string>
    ++    <!-- Notification title when data usage has exceeded warning threshold. [CHAR LIMIT=50] -->
    ++    <string name="data_usage_warning_title">Data usage alert</string>
    +     <!-- Notification body when data usage has exceeded warning threshold. [CHAR LIMIT=32] -->
    +     <string name="data_usage_warning_body">Tap to view usage and settings.</string>
    + 
    +@@ -4357,6 +4360,9 @@
    +     <string name="language_picker_section_suggested">Suggested</string>
    +     <!-- List section subheader for the language picker, containing a list of all languages available [CHAR LIMIT=30] -->
    +     <string name="language_picker_section_all">All languages</string>
    ++    <!-- List section subheader for the region picker, containing a list of all regions supported for the selected language.
    ++    Warning: this is a more 'neutral' term for 'country', not for the sub-divisions of a country. [CHAR LIMIT=30] -->
    ++    <string name="region_picker_section_all">All regions</string>
    + 
    +     <!-- Menu item in the locale menu  [CHAR LIMIT=30] -->
    +     <string name="locale_search_menu">Search</string>
    +diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
    +index def40db..826161e 100644
    +--- a/core/res/res/values/symbols.xml
    ++++ b/core/res/res/values/symbols.xml
    +@@ -1459,6 +1459,7 @@
    +   <java-symbol type="anim" name="dock_top_exit" />
    +   <java-symbol type="anim" name="dock_bottom_enter" />
    +   <java-symbol type="anim" name="dock_bottom_exit" />
    ++  <java-symbol type="anim" name="dock_bottom_exit_keyguard" />
    +   <java-symbol type="anim" name="dock_left_enter" />
    +   <java-symbol type="anim" name="dock_left_exit" />
    +   <java-symbol type="anim" name="dock_right_enter" />
    +@@ -1869,6 +1870,7 @@
    +   <java-symbol type="string" name="vpn_title_long" />
    +   <java-symbol type="string" name="vpn_lockdown_connecting" />
    +   <java-symbol type="string" name="vpn_lockdown_connected" />
    ++  <java-symbol type="string" name="vpn_lockdown_disconnected" />
    +   <java-symbol type="string" name="vpn_lockdown_error" />
    +   <java-symbol type="string" name="vpn_lockdown_config" />
    +   <java-symbol type="string" name="wallpaper_binding_label" />
    +@@ -1943,6 +1945,7 @@
    +   <java-symbol type="anim" name="lock_screen_behind_enter_fade_in" />
    +   <java-symbol type="anim" name="lock_screen_wallpaper_exit" />
    +   <java-symbol type="anim" name="launch_task_behind_source" />
    ++  <java-symbol type="anim" name="wallpaper_open_exit" />
    + 
    +   <java-symbol type="bool" name="config_alwaysUseCdmaRssi" />
    +   <java-symbol type="dimen" name="status_bar_icon_size" />
    +@@ -2212,6 +2215,7 @@
    +   <java-symbol type="bool" name="config_carrier_volte_provisioned" />
    +   <java-symbol type="bool" name="config_carrier_volte_tty_supported" />
    +   <java-symbol type="bool" name="config_device_vt_available" />
    ++  <java-symbol type="bool" name="config_device_respects_hold_carrier_config" />
    +   <java-symbol type="bool" name="config_carrier_vt_available" />
    +   <java-symbol type="bool" name="config_device_wfc_ims_available" />
    +   <java-symbol type="bool" name="config_carrier_wfc_ims_available" />
    +@@ -2505,6 +2509,7 @@
    +   <java-symbol type="menu" name="language_selection_list" />
    +   <java-symbol type="string" name="country_selection_title" />
    +   <java-symbol type="string" name="language_picker_section_all" />
    ++  <java-symbol type="string" name="region_picker_section_all" />
    +   <java-symbol type="string" name="language_picker_section_suggested" />
    +   <java-symbol type="string" name="language_selection_title" />
    +   <java-symbol type="string" name="search_language_hint" />
    +@@ -2659,6 +2664,13 @@
    + 
    +   <java-symbol type="string" name="lockscreen_storage_locked" />
    + 
    ++  <java-symbol type="string" name="global_action_emergency" />
    ++  <java-symbol type="string" name="config_emergency_call_number" />
    ++  <java-symbol type="array" name="config_emergency_mcc_codes" />
    ++
    ++  <java-symbol type="string" name="config_dozeDoubleTapSensorType" />
    ++  <java-symbol type="bool" name="config_dozePulsePickup" />
    ++
    +   <!-- Used for MimeIconUtils. -->
    +   <java-symbol type="drawable" name="ic_doc_apk" />
    +   <java-symbol type="drawable" name="ic_doc_audio" />
    +@@ -2695,4 +2707,13 @@
    + 
    +   <java-symbol type="drawable" name="ic_restart" />
    + 
    ++  <java-symbol type="drawable" name="emergency_icon" />
    ++
    ++  <java-symbol type="array" name="config_convert_to_emergency_number_map" />
    ++
    ++  <java-symbol type="array" name="config_nonBlockableNotificationPackages" />
    ++
    ++  <!-- Screen-size-dependent modes for picker dialogs. -->
    ++  <java-symbol type="integer" name="time_picker_mode" />
    ++  <java-symbol type="integer" name="date_picker_mode" />
    + </resources>
    +diff --git a/core/tests/coretests/AndroidManifest.xml b/core/tests/coretests/AndroidManifest.xml
    +index 2452cfd..4416402 100644
    +--- a/core/tests/coretests/AndroidManifest.xml
    ++++ b/core/tests/coretests/AndroidManifest.xml
    +@@ -1147,6 +1147,8 @@
    +         </activity>
    +         <activity android:name="com.android.internal.policy.PhoneWindowActionModeTestActivity">
    +         </activity>
    ++        <activity android:name="android.app.EmptyActivity">
    ++        </activity>
    + 
    +         <receiver android:name="android.app.activity.AbortReceiver">
    +             <intent-filter android:priority="1">
    +diff --git a/core/tests/coretests/src/android/app/EmptyActivity.java b/core/tests/coretests/src/android/app/EmptyActivity.java
    +new file mode 100644
    +index 0000000..fefd7b7
    +--- /dev/null
    ++++ b/core/tests/coretests/src/android/app/EmptyActivity.java
    +@@ -0,0 +1,21 @@
    ++/*
    ++ * Copyright (C) 2016 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 android.app;
    ++
    ++public class EmptyActivity extends Activity {
    ++}
    +diff --git a/core/tests/coretests/src/android/app/LoaderLifecycleTest.java b/core/tests/coretests/src/android/app/LoaderLifecycleTest.java
    +new file mode 100644
    +index 0000000..1850d57
    +--- /dev/null
    ++++ b/core/tests/coretests/src/android/app/LoaderLifecycleTest.java
    +@@ -0,0 +1,228 @@
    ++/*
    ++ * Copyright (C) 2016 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 android.app;
    ++
    ++import android.content.Context;
    ++import android.os.Handler;
    ++import android.os.Parcelable;
    ++import android.support.test.filters.MediumTest;
    ++import android.support.test.rule.ActivityTestRule;
    ++import android.support.test.runner.AndroidJUnit4;
    ++import android.util.ArrayMap;
    ++import org.junit.Rule;
    ++import org.junit.Test;
    ++import org.junit.runner.RunWith;
    ++
    ++import static junit.framework.TestCase.assertNotNull;
    ++import static junit.framework.TestCase.assertNotSame;
    ++import static junit.framework.TestCase.assertSame;
    ++
    ++@RunWith(AndroidJUnit4.class)
    ++public class LoaderLifecycleTest {
    ++    @Rule
    ++    public ActivityTestRule<EmptyActivity> mActivityRule =
    ++            new ActivityTestRule<>(EmptyActivity.class);
    ++    @Test
    ++    @MediumTest
    ++    public void loaderIdentityTest() throws Throwable{
    ++        mActivityRule.runOnUiThread(() -> {
    ++            final Handler h = new Handler();
    ++            final FragmentController fc1 = FragmentController.createController(
    ++                    new TestFragmentHostCallback(mActivityRule.getActivity(), h, 0));
    ++
    ++            fc1.attachHost(null);
    ++            fc1.dispatchCreate();
    ++
    ++            final FragmentManager fm1 = fc1.getFragmentManager();
    ++
    ++            final Fragment f1 = new Fragment();
    ++            fm1.beginTransaction().add(f1, "one").commitNow();
    ++
    ++            // Removing and re-adding a fragment completely will destroy its LoaderManager.
    ++            // Keep the first one here to confirm this later.
    ++            final LoaderManager lm1 = f1.getLoaderManager();
    ++
    ++            // Remove the fragment, add a second one, and re-add the first to
    ++            // force its internal index to change. The tests below should still remain consistent.
    ++            final Fragment f2 = new Fragment();
    ++            fm1.beginTransaction().remove(f1).commitNow();
    ++            fm1.beginTransaction().add(f2, "two").commitNow();
    ++            fm1.beginTransaction().add(f1, "one").commitNow();
    ++
    ++            // We'll check this to see if we get the same instance back later
    ++            // as passed through NonConfigurationInstance. If the keys stay consistent
    ++            // across fragment remove/re-add, this will be consistent.
    ++            final LoaderManager lm12 = f1.getLoaderManager();
    ++
    ++            assertNotSame("fully removed and re-added fragment got same LoaderManager", lm1, lm12);
    ++
    ++            fc1.dispatchActivityCreated();
    ++            fc1.noteStateNotSaved();
    ++            fc1.execPendingActions();
    ++            fc1.doLoaderStart();
    ++            fc1.dispatchStart();
    ++            fc1.reportLoaderStart();
    ++            fc1.dispatchResume();
    ++            fc1.execPendingActions();
    ++
    ++            // Bring the state back down to destroyed, simulating an activity restart
    ++            fc1.dispatchPause();
    ++            final Parcelable savedState = fc1.saveAllState();
    ++            fc1.doLoaderStop(true);
    ++            fc1.dispatchStop();
    ++            final FragmentManagerNonConfig nonconf = fc1.retainNestedNonConfig();
    ++
    ++            final ArrayMap<String, LoaderManager> loaderNonConfig = fc1.retainLoaderNonConfig();
    ++            assertNotNull("loaderNonConfig was null", loaderNonConfig);
    ++
    ++            fc1.dispatchDestroy();
    ++
    ++            // Create the new controller and restore state
    ++            final FragmentController fc2 = FragmentController.createController(
    ++                    new TestFragmentHostCallback(mActivityRule.getActivity(), h, 0));
    ++
    ++            final FragmentManager fm2 = fc2.getFragmentManager();
    ++
    ++            fc2.attachHost(null);
    ++            // Make sure nothing blows up on a null here
    ++            fc2.restoreLoaderNonConfig(null);
    ++            // for real this time
    ++            fc2.restoreLoaderNonConfig(loaderNonConfig);
    ++            fc2.restoreAllState(savedState, nonconf);
    ++            fc2.dispatchCreate();
    ++
    ++
    ++            fc2.dispatchActivityCreated();
    ++            fc2.noteStateNotSaved();
    ++            fc2.execPendingActions();
    ++            fc2.doLoaderStart();
    ++            fc2.dispatchStart();
    ++            fc2.reportLoaderStart();
    ++            fc2.dispatchResume();
    ++            fc2.execPendingActions();
    ++
    ++            // Test that the fragments are in the configuration we expect
    ++            final Fragment restoredOne = fm2.findFragmentByTag("one");
    ++            final LoaderManager lm2 = restoredOne.getLoaderManager();
    ++
    ++            assertSame("didn't get same LoaderManager instance back", lm2, lm12);
    ++
    ++            // Bring the state back down to destroyed before we finish the test
    ++            fc2.dispatchPause();
    ++            fc2.saveAllState();
    ++            fc2.dispatchStop();
    ++            fc2.dispatchDestroy();
    ++        });
    ++    }
    ++
    ++    @Test
    ++    @MediumTest
    ++    public void backStackLoaderIdentityTest() throws Throwable{
    ++        mActivityRule.runOnUiThread(() -> {
    ++            final Handler h = new Handler();
    ++            final FragmentHostCallback host1 =
    ++                    new TestFragmentHostCallback(mActivityRule.getActivity(), h, 0);
    ++            final FragmentController fc1 = FragmentController.createController(host1);
    ++
    ++            fc1.attachHost(null);
    ++            fc1.dispatchCreate();
    ++
    ++            final FragmentManager fm1 = fc1.getFragmentManager();
    ++
    ++            final Fragment f1 = new Fragment();
    ++            fm1.beginTransaction().add(f1, "one").commitNow();
    ++
    ++            final LoaderManager lm1 = f1.getLoaderManager();
    ++
    ++            // Put the fragment on the back stack.
    ++            fm1.beginTransaction().remove(f1).addToBackStack("backentry").commit();
    ++            fm1.executePendingTransactions();
    ++
    ++            fc1.dispatchActivityCreated();
    ++            fc1.noteStateNotSaved();
    ++            fc1.execPendingActions();
    ++            fc1.doLoaderStart();
    ++            fc1.dispatchStart();
    ++            fc1.reportLoaderStart();
    ++            fc1.dispatchResume();
    ++            fc1.execPendingActions();
    ++
    ++            // Bring the state back down to destroyed, simulating an activity restart
    ++            fc1.dispatchPause();
    ++            final Parcelable savedState = fc1.saveAllState();
    ++            fc1.doLoaderStop(true);
    ++            fc1.dispatchStop();
    ++            final FragmentManagerNonConfig nonconf = fc1.retainNestedNonConfig();
    ++
    ++            final ArrayMap<String, LoaderManager> loaderNonConfig = fc1.retainLoaderNonConfig();
    ++            assertNotNull("loaderNonConfig was null", loaderNonConfig);
    ++
    ++            fc1.dispatchDestroy();
    ++
    ++            // Create the new controller and restore state
    ++            final FragmentHostCallback host2 =
    ++                    new TestFragmentHostCallback(mActivityRule.getActivity(), h, 0);
    ++            final FragmentController fc2 = FragmentController.createController(host2);
    ++
    ++            final FragmentManager fm2 = fc2.getFragmentManager();
    ++
    ++            fc2.attachHost(null);
    ++            fc2.restoreLoaderNonConfig(loaderNonConfig);
    ++            fc2.restoreAllState(savedState, nonconf);
    ++            fc2.dispatchCreate();
    ++
    ++
    ++            fc2.dispatchActivityCreated();
    ++            fc2.noteStateNotSaved();
    ++            fc2.execPendingActions();
    ++            fc2.doLoaderStart();
    ++            fc2.dispatchStart();
    ++            fc2.reportLoaderStart();
    ++            fc2.dispatchResume();
    ++            fc2.execPendingActions();
    ++
    ++            assertNotSame("LoaderManager kept reference to old FragmentHostCallback",
    ++                    host1, lm1.getFragmentHostCallback());
    ++            assertSame("LoaderManager did not refrence new FragmentHostCallback",
    ++                    host2, lm1.getFragmentHostCallback());
    ++
    ++            // Test that the fragments are in the configuration we expect
    ++            final Fragment restoredOne = fm2.findFragmentByTag("one");
    ++            final LoaderManager lm2 = restoredOne.getLoaderManager();
    ++
    ++            assertSame("didn't get same LoaderManager instance back", lm2, lm1);
    ++
    ++            // Bring the state back down to destroyed before we finish the test
    ++            fc2.dispatchPause();
    ++            fc2.saveAllState();
    ++            fc2.dispatchStop();
    ++            fc2.dispatchDestroy();
    ++        });
    ++    }
    ++
    ++    public class TestFragmentHostCallback extends FragmentHostCallback<LoaderLifecycleTest> {
    ++        public TestFragmentHostCallback(Context context, Handler handler, int windowAnimations) {
    ++            super(context, handler, windowAnimations);
    ++        }
    ++
    ++        @Override
    ++        public LoaderLifecycleTest onGetHost() {
    ++            return LoaderLifecycleTest.this;
    ++        }
    ++    }
    ++}
    +diff --git a/core/tests/coretests/src/android/net/NetworkStatsTest.java b/core/tests/coretests/src/android/net/NetworkStatsTest.java
    +index 9074f8a..d48a67a 100644
    +--- a/core/tests/coretests/src/android/net/NetworkStatsTest.java
    ++++ b/core/tests/coretests/src/android/net/NetworkStatsTest.java
    +@@ -454,7 +454,7 @@ public class NetworkStatsTest extends TestCase {
    +             .addValues(underlyingIface, tunUid, SET_FOREGROUND, TAG_NONE, 0L, 0L, 0L, 0L, 0L);
    + 
    +         assertTrue(delta.migrateTun(tunUid, tunIface, underlyingIface));
    +-        assertEquals(21, delta.size());
    ++        assertEquals(20, delta.size());
    + 
    +         // tunIface and TEST_IFACE entries are not changed.
    +         assertValues(delta, 0, tunIface, 10100, SET_DEFAULT, TAG_NONE, ROAMING_NO,
    +@@ -478,38 +478,89 @@ public class NetworkStatsTest extends TestCase {
    + 
    +         // Existing underlying Iface entries are updated
    +         assertValues(delta, 9, underlyingIface, 10100, SET_DEFAULT, TAG_NONE, ROAMING_NO,
    +-                44783L, 54L, 13829L, 60L, 0L);
    ++                44783L, 54L, 14178L, 62L, 0L);
    +         assertValues(delta, 10, underlyingIface, 10100, SET_FOREGROUND, TAG_NONE, ROAMING_NO,
    +                 0L, 0L, 0L, 0L, 0L);
    + 
    +         // VPN underlying Iface entries are updated
    +         assertValues(delta, 11, underlyingIface, tunUid, SET_DEFAULT, TAG_NONE, ROAMING_NO,
    +-                28304L, 27L, 1719L, 12L, 0L);
    ++                28304L, 27L, 1L, 2L, 0L);
    +         assertValues(delta, 12, underlyingIface, tunUid, SET_FOREGROUND, TAG_NONE, ROAMING_NO,
    +                 0L, 0L, 0L, 0L, 0L);
    + 
    +         // New entries are added for new application's underlying Iface traffic
    +         assertContains(delta, underlyingIface, 10120, SET_DEFAULT, TAG_NONE, ROAMING_NO,
    +-                72667L, 197L, 41872L, 219L, 0L);
    ++                72667L, 197L, 43123L, 227L, 0L);
    +         assertContains(delta, underlyingIface, 10120, SET_FOREGROUND, TAG_NONE, ROAMING_NO,
    +-                9297L, 17L, 3936, 19L, 0L);
    ++                9297L, 17L, 4054, 19L, 0L);
    +         assertContains(delta, underlyingIface, 10120, SET_DEFAULT, testTag1, ROAMING_NO,
    +-                21691L, 41L, 13179L, 46L, 0L);
    ++                21691L, 41L, 13572L, 48L, 0L);
    +         assertContains(delta, underlyingIface, 10120, SET_FOREGROUND, testTag1, ROAMING_NO,
    +-                1281L, 2L, 634L, 1L, 0L);
    ++                1281L, 2L, 653L, 1L, 0L);
    + 
    +         // New entries are added for debug purpose
    +         assertContains(delta, underlyingIface, 10100, SET_DBG_VPN_IN, TAG_NONE, ROAMING_NO,
    +-                39605L, 46L, 11690, 49, 0);
    ++                39605L, 46L, 12039, 51, 0);
    +         assertContains(delta, underlyingIface, 10120, SET_DBG_VPN_IN, TAG_NONE, ROAMING_NO,
    +-                81964, 214, 45808, 238, 0);
    +-        assertContains(delta, underlyingIface, tunUid, SET_DBG_VPN_IN, TAG_NONE, ROAMING_NO,
    +-                4983, 10, 1717, 10, 0);
    ++                81964, 214, 47177, 246, 0);
    +         assertContains(delta, underlyingIface, tunUid, SET_DBG_VPN_OUT, TAG_NONE, ROAMING_ALL,
    +-                126552, 270, 59215, 297, 0);
    ++                121569, 260, 59216, 297, 0);
    + 
    +     }
    + 
    ++    // Tests a case where all of the data received by the tun0 interface is echo back into the tun0
    ++    // interface by the vpn app before it's sent out of the underlying interface. The VPN app should
    ++    // not be charged for the echoed data but it should still be charged for any extra data it sends
    ++    // via the underlying interface.
    ++    public void testMigrateTun_VpnAsLoopback() {
    ++        final int tunUid = 10030;
    ++        final String tunIface = "tun0";
    ++        final String underlyingIface = "wlan0";
    ++        NetworkStats delta = new NetworkStats(TEST_START, 9)
    ++            // 2 different apps sent/receive data via tun0.
    ++            .addValues(tunIface, 10100, SET_DEFAULT, TAG_NONE, 50000L, 25L, 100000L, 50L, 0L)
    ++            .addValues(tunIface, 20100, SET_DEFAULT, TAG_NONE, 500L, 2L, 200L, 5L, 0L)
    ++            // VPN package resends data through the tunnel (with exaggerated overhead)
    ++            .addValues(tunIface, tunUid, SET_DEFAULT, TAG_NONE, 240000, 100L, 120000L, 60L, 0L)
    ++            // 1 app already has some traffic on the underlying interface, the other doesn't yet
    ++            .addValues(underlyingIface, 10100, SET_DEFAULT, TAG_NONE, 1000L, 10L, 2000L, 20L, 0L)
    ++            // Traffic through the underlying interface via the vpn app.
    ++            // This test should redistribute this data correctly.
    ++            .addValues(underlyingIface, tunUid, SET_DEFAULT, TAG_NONE,
    ++                    75500L, 37L, 130000L, 70L, 0L);
    ++
    ++        assertTrue(delta.migrateTun(tunUid, tunIface, underlyingIface));
    ++        assertEquals(9, delta.size());
    ++
    ++        // tunIface entries should not be changed.
    ++        assertValues(delta, 0, tunIface, 10100, SET_DEFAULT, TAG_NONE, ROAMING_NO,
    ++                50000L, 25L, 100000L, 50L, 0L);
    ++        assertValues(delta, 1, tunIface, 20100, SET_DEFAULT, TAG_NONE, ROAMING_NO,
    ++                500L, 2L, 200L, 5L, 0L);
    ++        assertValues(delta, 2, tunIface, tunUid, SET_DEFAULT, TAG_NONE, ROAMING_NO,
    ++                240000L, 100L, 120000L, 60L, 0L);
    ++
    ++        // Existing underlying Iface entries are updated
    ++        assertValues(delta, 3, underlyingIface, 10100, SET_DEFAULT, TAG_NONE, ROAMING_NO,
    ++                51000L, 35L, 102000L, 70L, 0L);
    ++
    ++        // VPN underlying Iface entries are updated
    ++        assertValues(delta, 4, underlyingIface, tunUid, SET_DEFAULT, TAG_NONE, ROAMING_NO,
    ++                25000L, 10L, 29800L, 15L, 0L);
    ++
    ++        // New entries are added for new application's underlying Iface traffic
    ++        assertContains(delta, underlyingIface, 20100, SET_DEFAULT, TAG_NONE, ROAMING_NO,
    ++                500L, 2L, 200L, 5L, 0L);
    ++
    ++        // New entries are added for debug purpose
    ++        assertContains(delta, underlyingIface, 10100, SET_DBG_VPN_IN, TAG_NONE, ROAMING_NO,
    ++                50000L, 25L, 100000L, 50L, 0L);
    ++        assertContains(delta, underlyingIface, 20100, SET_DBG_VPN_IN, TAG_NONE, ROAMING_NO,
    ++                500, 2L, 200L, 5L, 0L);
    ++        assertContains(delta, underlyingIface, tunUid, SET_DBG_VPN_OUT, TAG_NONE, ROAMING_ALL,
    ++                50500L, 27L, 100200L, 55, 0);
    ++    }
    ++
    +     private static void assertContains(NetworkStats stats,  String iface, int uid, int set,
    +             int tag, int roaming, long rxBytes, long rxPackets, long txBytes, long txPackets,
    +             long operations) {
    +diff --git a/core/tests/coretests/src/android/os/FileUtilsTest.java b/core/tests/coretests/src/android/os/FileUtilsTest.java
    +index ac5abad..bd90079 100644
    +--- a/core/tests/coretests/src/android/os/FileUtilsTest.java
    ++++ b/core/tests/coretests/src/android/os/FileUtilsTest.java
    +@@ -297,6 +297,20 @@ public class FileUtilsTest extends AndroidTestCase {
    +                 FileUtils.buildUniqueFile(mTarget, "image/jpeg", "test.jpg"));
    +     }
    + 
    ++    public void testBuildUniqueFile_mimeless() throws Exception {
    ++        assertNameEquals("test.jpg", FileUtils.buildUniqueFile(mTarget, "test.jpg"));
    ++        new File(mTarget, "test.jpg").createNewFile();
    ++        assertNameEquals("test (1).jpg", FileUtils.buildUniqueFile(mTarget, "test.jpg"));
    ++
    ++        assertNameEquals("test", FileUtils.buildUniqueFile(mTarget, "test"));
    ++        new File(mTarget, "test").createNewFile();
    ++        assertNameEquals("test (1)", FileUtils.buildUniqueFile(mTarget, "test"));
    ++
    ++        assertNameEquals("test.foo.bar", FileUtils.buildUniqueFile(mTarget, "test.foo.bar"));
    ++        new File(mTarget, "test.foo.bar").createNewFile();
    ++        assertNameEquals("test.foo (1).bar", FileUtils.buildUniqueFile(mTarget, "test.foo.bar"));
    ++    }
    ++
    +     private static void assertNameEquals(String expected, File actual) {
    +         assertEquals(expected, actual.getName());
    +     }
    +diff --git a/core/tests/coretests/src/android/os/OsTests.java b/core/tests/coretests/src/android/os/OsTests.java
    +index 582bf1a..985fa4f 100644
    +--- a/core/tests/coretests/src/android/os/OsTests.java
    ++++ b/core/tests/coretests/src/android/os/OsTests.java
    +@@ -32,6 +32,7 @@ public class OsTests {
    +         suite.addTestSuite(IdleHandlerTest.class);
    +         suite.addTestSuite(MessageQueueTest.class);
    +         suite.addTestSuite(MessengerTest.class);
    ++        suite.addTestSuite(PatternMatcherTest.class);
    +         suite.addTestSuite(SystemPropertiesTest.class);
    + 
    +         return suite;
    +diff --git a/core/tests/coretests/src/android/os/PatternMatcherTest.java b/core/tests/coretests/src/android/os/PatternMatcherTest.java
    +new file mode 100644
    +index 0000000..9645ccc
    +--- /dev/null
    ++++ b/core/tests/coretests/src/android/os/PatternMatcherTest.java
    +@@ -0,0 +1,234 @@
    ++package android.os;
    ++
    ++import android.test.suitebuilder.annotation.SmallTest;
    ++import junit.framework.TestCase;
    ++import org.junit.runner.RunWith;
    ++import org.junit.Test;
    ++import org.junit.runners.JUnit4;
    ++
    ++@RunWith(JUnit4.class)
    ++@SmallTest
    ++public class PatternMatcherTest extends TestCase{
    ++
    ++    @Test
    ++    public void testAdvancedPatternMatchesAnyToken() {
    ++        PatternMatcher matcher = new PatternMatcher(".", PatternMatcher.PATTERN_ADVANCED_GLOB);
    ++        assertMatches("a", matcher);
    ++        assertMatches("b", matcher);
    ++        assertNotMatches("", matcher);
    ++    }
    ++
    ++    @Test
    ++    public void testAdvancedPatternMatchesSetToken() {
    ++        PatternMatcher matcher = new PatternMatcher("[a]", PatternMatcher.PATTERN_ADVANCED_GLOB);
    ++        assertMatches("a", matcher);
    ++        assertNotMatches("b", matcher);
    ++
    ++        matcher = new PatternMatcher("[.*+{}\\]\\\\[]", PatternMatcher.PATTERN_ADVANCED_GLOB);
    ++        assertMatches(".", matcher);
    ++        assertMatches("*", matcher);
    ++        assertMatches("+", matcher);
    ++        assertMatches("{", matcher);
    ++        assertMatches("}", matcher);
    ++        assertMatches("]", matcher);
    ++        assertMatches("\\", matcher);
    ++        assertMatches("[", matcher);
    ++    }
    ++
    ++    @Test
    ++    public void testAdvancedPatternMatchesSetCharacterClassToken() {
    ++        PatternMatcher matcher = new PatternMatcher("[a-z]", PatternMatcher.PATTERN_ADVANCED_GLOB);
    ++        assertMatches("a", matcher);
    ++        assertMatches("b", matcher);
    ++        assertNotMatches("A", matcher);
    ++        assertNotMatches("1", matcher);
    ++
    ++        matcher = new PatternMatcher("[a-z][0-9]", PatternMatcher.PATTERN_ADVANCED_GLOB);
    ++        assertMatches("a1", matcher);
    ++        assertNotMatches("1a", matcher);
    ++        assertNotMatches("aa", matcher);
    ++
    ++        matcher = new PatternMatcher("[z-a]", PatternMatcher.PATTERN_ADVANCED_GLOB);
    ++        assertNotMatches("a", matcher);
    ++        assertNotMatches("z", matcher);
    ++        assertNotMatches("A", matcher);
    ++
    ++        matcher = new PatternMatcher("[^0-9]", PatternMatcher.PATTERN_ADVANCED_GLOB);
    ++        assertMatches("a", matcher);
    ++        assertMatches("z", matcher);
    ++        assertMatches("A", matcher);
    ++        assertNotMatches("9", matcher);
    ++        assertNotMatches("5", matcher);
    ++        assertNotMatches("0", matcher);
    ++
    ++        assertPoorlyFormattedPattern("[]a]");
    ++        matcher = new PatternMatcher("[\\[a]", PatternMatcher.PATTERN_ADVANCED_GLOB);
    ++        assertMatches("a", matcher);
    ++        assertMatches("[", matcher);
    ++    }
    ++
    ++    @Test
    ++    public void testAdvancedPatternMatchesEscapedCharacters() {
    ++        PatternMatcher matcher = new PatternMatcher("\\.", PatternMatcher.PATTERN_ADVANCED_GLOB);
    ++        assertMatches(".", matcher);
    ++        assertNotMatches("a", matcher);
    ++        assertNotMatches("1", matcher);
    ++
    ++        matcher = new PatternMatcher("a\\+", PatternMatcher.PATTERN_ADVANCED_GLOB);
    ++        assertMatches("a+", matcher);
    ++        assertNotMatches("a", matcher);
    ++        assertNotMatches("aaaaa", matcher);
    ++
    ++        matcher = new PatternMatcher("[\\a-\\z]", PatternMatcher.PATTERN_ADVANCED_GLOB);
    ++        assertMatches("a", matcher);
    ++        assertMatches("z", matcher);
    ++        assertNotMatches("A", matcher);
    ++    }
    ++
    ++    @Test
    ++    public void testAdvancedPatternMatchesLiteralTokens() {
    ++        PatternMatcher matcher = new PatternMatcher("a", PatternMatcher.PATTERN_ADVANCED_GLOB);
    ++        assertNotMatches("", matcher);
    ++        assertMatches("a", matcher);
    ++        assertNotMatches("z", matcher);
    ++
    ++        matcher = new PatternMatcher("az", PatternMatcher.PATTERN_ADVANCED_GLOB);
    ++        assertNotMatches("", matcher);
    ++        assertMatches("az", matcher);
    ++        assertNotMatches("za", matcher);
    ++    }
    ++
    ++    @Test
    ++    public void testAdvancedPatternMatchesSetZeroOrMore() {
    ++        PatternMatcher matcher = new PatternMatcher("[a-z]*", PatternMatcher.PATTERN_ADVANCED_GLOB);
    ++
    ++        assertMatches("", matcher);
    ++        assertMatches("a", matcher);
    ++        assertMatches("abcdefg", matcher);
    ++        assertNotMatches("abc1", matcher);
    ++        assertNotMatches("1abc", matcher);
    ++    }
    ++
    ++    @Test
    ++    public void testAdvancedPatternMatchesSetOneOrMore() {
    ++        PatternMatcher matcher = new PatternMatcher("[a-z]+", PatternMatcher.PATTERN_ADVANCED_GLOB);
    ++
    ++        assertNotMatches("", matcher);
    ++        assertMatches("a", matcher);
    ++        assertMatches("abcdefg", matcher);
    ++        assertNotMatches("abc1", matcher);
    ++        assertNotMatches("1abc", matcher);
    ++    }
    ++
    ++
    ++    @Test
    ++    public void testAdvancedPatternMatchesSingleRange() {
    ++        PatternMatcher matcher = new PatternMatcher("[a-z]{1}",
    ++                PatternMatcher.PATTERN_ADVANCED_GLOB);
    ++
    ++        assertNotMatches("", matcher);
    ++        assertMatches("a", matcher);
    ++        assertMatches("z", matcher);
    ++        assertNotMatches("1", matcher);
    ++        assertNotMatches("aa", matcher);
    ++    }
    ++
    ++    @Test
    ++    public void testAdvancedPatternMatchesFullRange() {
    ++        PatternMatcher matcher = new PatternMatcher("[a-z]{1,5}",
    ++                PatternMatcher.PATTERN_ADVANCED_GLOB);
    ++
    ++        assertNotMatches("", matcher);
    ++        assertMatches("a", matcher);
    ++        assertMatches("zazaz", matcher);
    ++        assertNotMatches("azazaz", matcher);
    ++        assertNotMatches("11111", matcher);
    ++    }
    ++
    ++    @Test
    ++    public void testAdvancedPatternMatchesPartialRange() {
    ++        PatternMatcher matcher = new PatternMatcher("[a-z]{3,}",
    ++                PatternMatcher.PATTERN_ADVANCED_GLOB);
    ++
    ++        assertNotMatches("", matcher);
    ++        assertMatches("aza", matcher);
    ++        assertMatches("zazaz", matcher);
    ++        assertMatches("azazazazazaz", matcher);
    ++        assertNotMatches("aa", matcher);
    ++    }
    ++
    ++    @Test
    ++    public void testAdvancedPatternMatchesComplexPatterns() {
    ++        PatternMatcher matcher = new PatternMatcher(
    ++                "/[0-9]{4}/[0-9]{2}/[0-9]{2}/[a-zA-Z0-9_]+\\.html",
    ++                PatternMatcher.PATTERN_ADVANCED_GLOB);
    ++
    ++        assertNotMatches("", matcher);
    ++        assertMatches("/2016/09/07/got_this_working.html", matcher);
    ++        assertMatches("/2016/09/07/got_this_working2.html", matcher);
    ++        assertNotMatches("/2016/09/07/got_this_working2dothtml", matcher);
    ++        assertNotMatches("/2016/9/7/got_this_working.html", matcher);
    ++
    ++        matcher = new PatternMatcher(
    ++                "/b*a*bar.*",
    ++                PatternMatcher.PATTERN_ADVANCED_GLOB);
    ++
    ++        assertMatches("/babar", matcher);
    ++        assertMatches("/babarfff", matcher);
    ++        assertMatches("/bbaabarfff", matcher);
    ++        assertMatches("/babar?blah", matcher);
    ++        assertMatches("/baaaabar?blah", matcher);
    ++        assertNotMatches("?bar", matcher);
    ++        assertNotMatches("/bar", matcher);
    ++        assertNotMatches("/baz", matcher);
    ++        assertNotMatches("/ba/bar", matcher);
    ++        assertNotMatches("/barf", matcher);
    ++        assertNotMatches("/", matcher);
    ++        assertNotMatches("?blah", matcher);
    ++    }
    ++
    ++    @Test
    ++    public void testAdvancedPatternPoorFormatThrowsIllegalArgumentException() {
    ++        assertPoorlyFormattedPattern("[a-z");
    ++        assertPoorlyFormattedPattern("a{,4}");
    ++        assertPoorlyFormattedPattern("a{0,a}");
    ++        assertPoorlyFormattedPattern("a{\\1, 2}");
    ++        assertPoorlyFormattedPattern("[]");
    ++        assertPoorlyFormattedPattern("a{}");
    ++        assertPoorlyFormattedPattern("{3,4}");
    ++        assertPoorlyFormattedPattern("a+{3,4}");
    ++        assertPoorlyFormattedPattern("*.");
    ++        assertPoorlyFormattedPattern(".+*");
    ++        assertPoorlyFormattedPattern("a{3,4");
    ++        assertPoorlyFormattedPattern("[a");
    ++        assertPoorlyFormattedPattern("abc\\");
    ++        assertPoorlyFormattedPattern("+.");
    ++
    ++        StringBuilder charSet = new StringBuilder("[");
    ++        for (int i = 0; i < 1024; i++) {
    ++            charSet.append('a' + (i % 26));
    ++        }
    ++        charSet.append("]");
    ++        assertPoorlyFormattedPattern(charSet.toString());
    ++    }
    ++
    ++    private void assertMatches(String string, PatternMatcher matcher) {
    ++        assertTrue("'" + string + "' should match '" + matcher.toString() + "'",
    ++                matcher.match(string));
    ++    }
    ++
    ++    private void assertNotMatches(String string, PatternMatcher matcher) {
    ++        assertTrue("'" + string + "' should not match '" + matcher.toString() + "'",
    ++                !matcher.match(string));
    ++    }
    ++
    ++    private void assertPoorlyFormattedPattern(String format) {
    ++        try {
    ++            new PatternMatcher(format, PatternMatcher.PATTERN_ADVANCED_GLOB);
    ++        } catch (IllegalArgumentException e) {
    ++            return;// expected
    ++        }
    ++
    ++        fail("'" + format + "' was erroneously created");
    ++    }
    ++}
    +diff --git a/docs/html-intl/intl/es/about/versions/nougat/index.jd b/docs/html-intl/intl/es/about/versions/nougat/index.jd
    +index b30cc88..59afd81 100644
    +--- a/docs/html-intl/intl/es/about/versions/nougat/index.jd
    ++++ b/docs/html-intl/intl/es/about/versions/nougat/index.jd
    +@@ -7,16 +7,6 @@ header.hide=1
    + footer.hide=1
    + @jd:body
    + 
    +-<script>
    +-  $(document).ready(function() {
    +-    if (useUpdatedTemplates) {
    +-      $("#useUpdatedTemplates").css("display","block");
    +-    } else {
    +-      $("#useOldTemplates").css("display","block");
    +-    }
    +-  })
    +-</script>
    +-
    + <section class="dac-expand dac-hero dac-light">
    +   <div class="wrap" style="max-width:1100px;margin-top:0">
    +   <a href="{@docRoot}about/versions/nougat/android-7.0.html">
    +@@ -54,7 +44,7 @@ footer.hide=1
    +   </div>
    + </section>
    + 
    +-<div id="useUpdatedTemplates" style="display:none" class="dac-section dac-slim dac-gray dac-expand">
    ++<div class="dac-section dac-slim dac-gray dac-expand">
    +   <div class="wrap dac-offset-parent">
    +     <a class="dac-fab dac-scroll-button" data-scroll-button href="#latest">
    +       <i class="dac-sprite dac-arrow-down-gray"></i>
    +@@ -76,26 +66,6 @@ footer.hide=1
    +   </div><!-- end .wrap -->
    + </div><!-- end .dac-actions -->
    + 
    +-<div id="useOldTemplates" style="display:none;color:black" class="actions-bar dac-expand dac-invert">
    +-  <div class="wrap dac-offset-parent">
    +-
    +-    <div class="actions">
    +-      <div><a href="https://developer.android.com/preview/bug">
    +-        <span class="dac-sprite dac-auto-chevron-large"></span>
    +-        Informar un problema
    +-      </a></div>
    +-      <div><a href="{@docRoot}preview/support.html">
    +-        <span class="dac-sprite dac-auto-chevron-large"></span>
    +-        Consulta las notas de la versión
    +-      </a></div>
    +-      <div><a href="{@docRoot}preview/dev-community">
    +-        <span class="dac-sprite dac-auto-chevron-large"></span>
    +-        Únete a la comunidad de desarrolladores
    +-        </a></div>
    +-    </div><!-- end .actions -->
    +-  </div><!-- end .wrap -->
    +-</div>
    +-
    + <section class="dac-section dac-light dac-small" id="latest"><div class="wrap">
    +   <h2 class="norule">Lo último</h2>
    +   <div class="resource-widget resource-flow-layout col-16"
    +diff --git a/docs/html-intl/intl/es/index.jd b/docs/html-intl/intl/es/index.jd
    +index e0d80c1..1ecf47c 100644
    +--- a/docs/html-intl/intl/es/index.jd
    ++++ b/docs/html-intl/intl/es/index.jd
    +@@ -5,16 +5,6 @@ page.customHeadTag=<meta name="google-site-verification" content="sa-bIAI6GKvct3
    + 
    + @jd:body
    + 
    +-<script>
    +-  $(document).ready(function() {
    +-    if (useUpdatedTemplates) {
    +-      $("#useUpdatedTemplates").css("display","block");
    +-    } else {
    +-      $("#useOldTemplates").css("display","block");
    +-    }
    +-  })
    +-</script>
    +-
    + <section class="dac-expand dac-hero" style="background-color:#b2dfdb;">
    +   <div class="wrap" style="max-width:1000px;margin-top:0">
    +     <div class="col-7of16 col-push-8of16">
    +@@ -44,7 +34,7 @@ page.customHeadTag=<meta name="google-site-verification" content="sa-bIAI6GKvct3
    +   </div>
    + </section>
    + 
    +-<div id="useUpdatedTemplates" style="display:none" class="dac-section dac-slim dac-gray dac-expand">
    ++<div class="dac-section dac-slim dac-gray dac-expand">
    +   <div class="wrap dac-offset-parent">
    +     <a class="dac-fab dac-scroll-button" data-scroll-button href="#build-apps">
    +       <i class="dac-sprite dac-arrow-down-gray"></i>
    +@@ -72,28 +62,6 @@ page.customHeadTag=<meta name="google-site-verification" content="sa-bIAI6GKvct3
    +   </div><!-- end .wrap -->
    + </div><!-- end .dac-actions -->
    + 
    +-<div id="useOldTemplates" style="display:none" class="actions-bar dac-expand dac-invert">
    +-  <div class="wrap dac-offset-parent">
    +-    <a class="dac-fab dac-scroll-button" data-scroll-button="" href="#build-apps">
    +-      <i class="dac-sprite dac-arrow-down-gray"></i>
    +-    </a>
    +-    <div class="actions">
    +-      <div><a href="{@docRoot}sdk/index.html">
    +-        <span class="dac-sprite dac-auto-chevron-large"></span>
    +-        Get the SDK
    +-      </a></div>
    +-      <div><a href="{@docRoot}samples/index.html">
    +-        <span class="dac-sprite dac-auto-chevron-large"></span>
    +-        Browse Samples
    +-      </a></div>
    +-      <div><a href="{@docRoot}distribute/stories/index.html">
    +-        <span class="dac-sprite dac-auto-chevron-large"></span>
    +-        Watch Stories
    +-      </a></div>
    +-    </div><!-- end .actions -->
    +-  </div><!-- end .wrap -->
    +-</div>
    +-
    + <section class="dac-section dac-light" id="build-apps"><div class="wrap">
    +   <h1 class="dac-section-title">Build Beautiful Apps</h1>
    +   <div class="dac-section-subtitle">
    +diff --git a/docs/html-intl/intl/id/about/versions/marshmallow/android-6.0-testing.jd b/docs/html-intl/intl/id/about/versions/marshmallow/android-6.0-testing.jd
    +new file mode 100644
    +index 0000000..94bc74c
    +--- /dev/null
    ++++ b/docs/html-intl/intl/id/about/versions/marshmallow/android-6.0-testing.jd
    +@@ -0,0 +1,190 @@
    ++page.title=Panduan Pengujian
    ++page.image=images/cards/card-n-guide_2x.png
    ++meta.tags="preview", "testing"
    ++page.tags="preview", "developer preview"
    ++
    ++@jd:body
    ++
    ++<div id="tb-wrapper">
    ++  <div id="tb">
    ++    <h2>Dalam dokumen ini</h2>
    ++      <ol>
    ++        <li><a href="#runtime-permissions">Izin Pengujian</a></li>
    ++        <li><a href="#doze-standby">Menguji Istirahatkan dan Aplikasi Siaga</a></li>
    ++        <li><a href="#ids">Pencadangan Otomatis dan Identifier Perangkat</a></li>
    ++      </ol>
    ++  </div>
    ++</div>
    ++
    ++<p>
    ++  Android N memberi Anda kesempatan untuk memastikan aplikasi bekerja pada
    ++  platform versi berikutnya. Pratinjau ini berisi beberapa API dan perubahan perilaku yang bisa
    ++  memengaruhi aplikasi Anda, sebagaimana dijelaskan dalam <a href="{@docRoot}preview/api-overview.html">Ringkasan
    ++  API</a> dan <a href="{@docRoot}preview/behavior-changes.html">Perubahan Perilaku</a>. Dalam menguji
    ++  aplikasi dengan pratinjau, ada beberapa perubahan sistem spesifik yang harus Anda fokuskan untuk
    ++  memastikan pengguna mendapatkan pengalaman yang bagus.
    ++</p>
    ++
    ++<p>
    ++  Panduan ini menjelaskan apa dan bagaimana menguji fitur pratinjau dengan aplikasi Anda. Anda harus
    ++  mengutamakan pengujian fitur pratinjau spesifik ini, dikarenakan pengaruhnya yang besar pada
    ++  perilaku aplikasi Anda:
    ++</p>
    ++
    ++<ul>
    ++  <li><a href="#runtime-permissions">Izin</a>
    ++  </li>
    ++  <li><a href="#doze-standby">Istirahatkan dan Aplikasi Siaga</a>
    ++  </li>
    ++  <li><a href="#ids">Pencadangan Otomatis dan Identifier Perangkat</a></li>
    ++</ul>
    ++
    ++<p>
    ++  Untuk informasi selengkapnya tentang cara menyiapkan perangkat atau perangkat maya dengan citra sistem pratinjau
    ++  untuk pengujian, lihat <a href="{@docRoot}preview/setup-sdk.html">Menyiapkan
    ++Android N SDK</a>.
    ++</p>
    ++
    ++
    ++<h2 id="runtime-permissions">Izin Pengujian</h2>
    ++
    ++<p>
    ++  Model <a href="{@docRoot}preview/features/runtime-permissions.html">Izin</a> yang baru
    ++  mengubah cara alokasi izin untuk aplikasi Anda oleh pengguna. Sebagai ganti memberi semua
    ++  izin selama prosedur pemasangan, aplikasi Anda harus meminta izin kepada pengguna secara individual
    ++ pada waktu proses. Bagi pengguna, perilaku ini memberi kontrol yang lebih detail atas setiap aktivitas aplikasi, dan
    ++  juga konteks yang lebih untuk memahami sebab aplikasi meminta izin tertentu. Pengguna
    ++  bisa memberi atau mencabut izin yang diberikan pada suatu aplikasi secara individual kapan saja. Fitur
    ++  pratinjau ini kemungkinan besar memengaruhi perilaku aplikasi Anda dan mungkin menghambat fungsi beberapa
    ++  fitur aplikasi Anda, atau mengurangi kualitas kerjanya.
    ++</p>
    ++
    ++<p class="caution">
    ++  Perubahan ini memengaruhi semua aplikasi yang berjalan di platform baru, bahkan aplikasi yang tidak menargetkan versi
    ++  platform baru. Platform ini memberikan perilaku kompatibilitas terbatas untuk aplikasi lawas, namun Anda
    ++  harus mulai merencanakan migrasi aplikasi ke model izin baru sekarang juga, dengan tujuan
    ++  mempublikasikan versi terbaru aplikasi Anda saat peluncuran platform secara resmi.
    ++</p>
    ++
    ++
    ++<h3 id="permission-test-tips">Tip pengujian</h3>
    ++
    ++<p>
    ++  Gunakan tip berikut untuk membantu Anda merencanakan dan menjalankan pengujian aplikasi dengan
    ++  perilaku izin yang baru.
    ++</p>
    ++
    ++<ul>
    ++  <li>Identifikasi izin aplikasi Anda saat ini dan jalur kode terkait.</li>
    ++  <li>Uji alur pengguna pada semua layanan dan data yang dilindungi izin.</li>
    ++  <li>Uji dengan berbagai kombinasi izin yang diberikan/dicabut.</li>
    ++  <li>Gunakan alat bantu {@code adb} untuk mengelola izin dari baris perintah:
    ++    <ul>
    ++      <li>Cantumkan daftar izin dan status berdasarkan kelompok:
    ++        <pre>adb shell pm list permissions -d -g</pre>
    ++      </li>
    ++      <li>Beri atau cabut satu atau beberapa izin menggunakan sintaks berikut:<br>
    ++        <pre>adb shell pm [grant|revoke] &lt;permission.name&gt; ...</pre>
    ++      </li>
    ++    </ul>
    ++  </li>
    ++  <li>Analisis aplikasi Anda untuk layanan yang menggunakan izin.</li>
    ++</ul>
    ++
    ++<h3 id="permission-test-strategy">Strategi pengujian</h3>
    ++
    ++<p>
    ++  Perubahan izin memengaruhi struktur dan desain aplikasi Anda, begitu juga
    ++  pengalaman pengguna dan alur yang Anda sediakan untuk pengguna. Anda harus menilai penggunaan izin
    ++  aplikasi saat ini dan mulai merencanakan alur baru yang ingin ditawarkan. Rilis platform
    ++  resmi menyediakan perilaku kompatibilitas, namun Anda harus merencanakan pembaruan aplikasi dan tidak
    ++  bergantung pada perilaku ini.
    ++</p>
    ++
    ++<p>
    ++  Identifikasi izin yang sebenarnya diperlukan dan digunakan aplikasi Anda, kemudian temukan berbagai
    ++  jalur kode yang menggunakan layanan yang dilindungi izin. Anda bisa melakukan ini melalui kombinasi
    ++  pengujian pada platform baru dan analisis kode. Dalam pengujian, Anda harus fokus pada pemilihan
    ++ izin waktu proses dengan mengubah {@code targetSdkVersion} aplikasi ke versi pratinjau. Untuk
    ++  informasi selengkapnya, lihat <a href="{@docRoot}preview/setup-sdk.html#">Menyiapkan
    ++Android N SDK</a>.
    ++</p>
    ++
    ++<p>
    ++  Uji dengan berbagai kombinasi izin yang dicabut dan ditambahkan, untuk menyoroti alur pengguna yang
    ++  bergantung pada izin. Jika dependensi tidak jelas atau logis, Anda harus mempertimbangkan
    ++optimalisasi atau kompartementalisasi alur tersebut untuk mengeliminasi dependensi atau menjelaskan alasan
    ++  diperlukannya izin.
    ++</p>
    ++
    ++<p>
    ++  Untuk informasi selengkapnya tentang perilaku izin waktu proses, pengujian, dan praktik terbaik, lihat
    ++  halaman pratinjau <a href="{@docRoot}preview/features/runtime-permissions.html">Izin</a>
    ++  pengembang.
    ++</p>
    ++
    ++
    ++<h2 id="doze-standby">Menguji Istirahatkan dan Aplikasi Siaga</h2>
    ++
    ++<p>
    ++  Fitur penghematan daya Istirahatkan dan Aplikasi Siaga membatasi jumlah pemrosesan latar belakang yang
    ++  bisa dikerjakan aplikasi Anda saat perangkat dalam keadaan diam atau saat aplikasi Anda sedang tidak fokus. Pembatasan
    ++  yang dapat diberlakukan oleh sistem pada aplikasi termasuk akses jaringan terbatas atau tidak ada,
    ++  tugas latar belakang yang ditangguhkan, Pemberitahuan yang ditangguhkan, permintaan membangunkan yang diabaikan, serta alarm. Untuk memastikan
    ++  aplikasi Anda berperilaku dengan benar pada optimalisasi penghematan daya ini, Anda harus menguji aplikasi dengan
    ++ menyimulasikan keadaan baterai yang sedang tinggal sedikit ini.
    ++</p>
    ++
    ++<h4 id="doze">Menguji aplikasi Anda dengan Istirahatkan</h4>
    ++
    ++<p>Untuk menguji Istirahatkan dengan aplikasi Anda:</p>
    ++
    ++<ol>
    ++<li>Konfigurasikan perangkat keras atau perangkat maya dengan citra sistem Android N.</li>
    ++<li>Hubungkan perangkat dengan mesin pengembangan dan pasang aplikasi Anda.</li>
    ++<li>Jalankan aplikasi Anda dan biarkan aktif.</li>
    ++<li>Simulasikan perangkat yang sedang masuk ke dalam mode Istirahatkan dengan menjalankan perintah berikut:
    ++
    ++<pre>
    ++$ adb shell dumpsys battery unplug
    ++$ adb shell dumpsys deviceidle step
    ++$ adb shell dumpsys deviceidle -h
    ++</pre>
    ++
    ++  </li>
    ++  <li>Amati perilaku aplikasi Anda saat perangkat diaktifkan kembali. Pastikan aplikasi
    ++    pulih dengan baik saat perangkat keluar dari Istirahatkan.</li>
    ++</ol>
    ++
    ++
    ++<h4 id="standby">Menguji aplikasi dengan Aplikasi Siaga</h4>
    ++
    ++<p>Untuk menguji mode Aplikasi Siaga dengan aplikasi Anda:</p>
    ++
    ++<ol>
    ++  <li>Konfigurasikan perangkat keras atau perangkat maya dengan citra sistem Android N.</li>
    ++  <li>Hubungkan perangkat dengan mesin pengembangan dan pasang aplikasi Anda.</li>
    ++  <li>Jalankan aplikasi Anda dan biarkan aktif.</li>
    ++  <li>Simulasikan aplikasi yang sedang masuk ke dalam mode siaga dengan menjalankan perintah berikut:
    ++
    ++<pre>
    ++$ adb shell am broadcast -a android.os.action.DISCHARGING
    ++$ adb shell am set-idle &lt;packageName&gt; true
    ++</pre>
    ++
    ++  </li>
    ++  <li>Simulasikan membangunkan aplikasi Anda menggunakan perintah berikut:
    ++    <pre>$ adb shell am set-idle &lt;packageName&gt; false</pre>
    ++  </li>
    ++  <li>Amati perilaku aplikasi Anda saat dibangunkan. Pastikan aplikasi pulih dengan baik
    ++   dari mode siaga. Secara khusus, Anda harus memeriksa apakah Pemberitahuan aplikasi dan pekerjaan latar belakang
    ++   tetap berjalan sebagaimana yang diharapkan.</li>
    ++</ol>
    ++
    ++<h2 id="ids">Auto Backup for Apps dan Identifier Perangkat Spesifik</h2>
    ++
    ++<p>Jika aplikasi Anda mempertahankan identifier perangkat spesifik, seperti ID pendaftaran Google
    ++Cloud Messaging, dalam penyimpanan internal,
    ++pastikan Anda mengikuti praktik terbaik untuk mengecualikan lokasi
    ++penyimpanan dari pencadangan otomatis, seperti dijelaskan dalam <a href="{@docRoot}preview/backup/index.html">Auto
    ++Backup for Apps</a>. </p>
    +diff --git a/docs/html-intl/intl/id/about/versions/nougat/android-7.0-changes.jd b/docs/html-intl/intl/id/about/versions/nougat/android-7.0-changes.jd
    +new file mode 100644
    +index 0000000..af01cd2
    +--- /dev/null
    ++++ b/docs/html-intl/intl/id/about/versions/nougat/android-7.0-changes.jd
    +@@ -0,0 +1,610 @@
    ++page.title=Perubahan Perilaku
    ++page.keywords=pratinjau,sdk,kompatibilitas
    ++meta.tags="preview", "compatibility"
    ++page.tags="preview", "developer preview"
    ++page.image=images/cards/card-n-changes_2x.png
    ++@jd:body
    ++
    ++
    ++<div id="tb-wrapper">
    ++<div id="tb">
    ++
    ++<h2>Dalam dokumen ini</h2>
    ++
    ++<ol>
    ++  <li><a href="#perf">Peningkatan Kinerja</a>
    ++    <ol>
    ++      <li><a href="#doze">Istirahatkan</a></li>
    ++      <li><a href="#bg-opt">Optimalisasi Latar Belakang</a></li>
    ++    </ol>
    ++  </li>
    ++  <li><a href="#perm">Perubahan Izin</a>
    ++  </li>
    ++  <li><a href="#sharing-files">Berbagi File Antar Aplikasi</a></li>
    ++  <li><a href="#accessibility">Peningkatan Aksesibilitas</a>
    ++    <ol>
    ++      <li><a href="#screen-zoom">Perbesaran Layar</a></li>
    ++      <li><a href="#vision-settings">Vision Settings di Setup Wizard</a></li>
    ++    </ol>
    ++  </li>
    ++  <li><a href="#ndk">Penautan Aplikasi NDK ke Pustaka Platform</a></li>
    ++  <li><a href="#afw">Android for Work</a></li>
    ++  <li><a href="#annotations">Retensi Anotasi</a></li>
    ++  <li><a href="#other">Poin Penting Lainnya</a></li>
    ++</ol>
    ++
    ++<h2>Lihat Juga</h2>
    ++<ol>
    ++  <li><a href="{@docRoot}preview/api-overview.html">
    ++    Ringkasan Android N API</a></li>
    ++</ol>
    ++
    ++</div>
    ++</div>
    ++
    ++
    ++<p>
    ++  Bersama fitur dan kemampuan baru, Android N
    ++  menyertakan berbagai macam perubahan sistem dan perubahan perilaku API. Dokumen ini
    ++  menyoroti beberapa perubahan utama yang harus dipahami dan diperhitungkan
    ++  dalam aplikasi Anda.
    ++</p>
    ++
    ++<p>
    ++  Jika Anda sebelumnya telah mempublikasikan aplikasi untuk Android, ketahuilah bahwa aplikasi Anda
    ++  mungkin dipengaruhi oleh perubahan dalam platform.
    ++</p>
    ++
    ++
    ++<h2 id="perf">Baterai dan Memori</h2>
    ++
    ++<p>
    ++Android N menyertakan perubahan perilaku sistem yang bertujuan untuk meningkatkan daya tahan baterai
    ++perangkat dan mengurangi penggunaan RAM. Perubahan ini bisa memengaruhi akses aplikasi Anda ke
    ++sumber daya sistem, termasuk cara aplikasi Anda berinteraksi dengan aplikasi lain melalui
    ++intent implisit tertentu.
    ++</p>
    ++
    ++<h3 id="doze">Istirahatkan</h3>
    ++
    ++<p>
    ++  Diperkenalkan dalam Android 6.0 (API level 23), Istirahatkan meningkatkan daya tahan baterai dengan
    ++  menangguhkan aktivitas CPU dan jaringan bila pengguna tidak mencabut perangkat,
    ++  tidak bergerak, dan layar dinonaktifkan. Android N lebih
    ++  menyempurnakan Istirahatkan dengan menerapkan subset CPU dan pembatasan jaringan
    ++  bila perangkat dicabut dan layar dinonaktifkan, namun tidak harus
    ++  diam, misalnya, bila handset dibawa bepergian di saku pengguna.
    ++</p>
    ++
    ++
    ++<img src="{@docRoot}images/android-7.0/doze-diagram-1.png" alt="" height="251px" id="figure1" />
    ++<p class="img-caption">
    ++  <strong>Gambar 1.</strong> Ilustrasi tentang cara Istirahatkan menerapkan pembatasan
    ++  aktivitas sistem level pertama untuk meningkatkan daya tahan baterai.
    ++</p>
    ++
    ++<p>
    ++  Bila perangkat sedang menggunakan daya baterai, dan layar telah nonaktif selama jangka waktu
    ++  tertentu, perangkat akan memasuki Istirahatkan dan menerapkan subset pembatasan pertama: Perangkat
    ++  akan menutup akses jaringan aplikasi, serta menangguhkan pekerjaan dan sinkronisasi. Jika perangkat sedang
    ++  diam selama jangka waktu tertentu setelah memasuki Istirahatkan, sistem akan menerapkan
    ++  pembatasan Istirahatkan selebihnya terhadap alarm {@link android.os.PowerManager.WakeLock},
    ++  {@link android.app.AlarmManager}, GPS, dan pemindaian Wi-Fi. Tidak peduli
    ++  apakah sebagian atau semua pembatasan Istirahatkan diterapkan, sistem akan membangunkan
    ++  perangkat selama jeda pemeliharaan singkat, dan selama itu aplikasi diizinkan
    ++  mengakses jaringan dan bisa mengeksekusi semua pekerjaan/sinkronisasi yang telah ditangguhkan.
    ++</p>
    ++
    ++
    ++<img src="{@docRoot}images/android-7.0/doze-diagram-2.png" alt="" id="figure2" />
    ++<p class="img-caption">
    ++  <strong>Gambar 2.</strong> Ilustrasi tentang cara Istirahatkan menerapkan pembatasan
    ++  aktivitas sistem level kedua setelah perangkat diam selama jangka waktu tertentu.
    ++</p>
    ++
    ++<p>
    ++  Perhatikan, mengaktifkan layar atau mencolokkan steker perangkat akan mengeluarkan dari Istirahatkan
    ++  dan membuang pembatasan pemrosesan ini. Perilaku tambahan ini tidak
    ++  memengaruhi rekomendasi dan praktik terbaik dalam menyesuaikan aplikasi Anda dengan versi
    ++  Istirahatkan sebelumnya yang diperkenalkan dalam Android 6.0 (API level 23), seperti yang dibahas di
    ++  <a href="{@docRoot}training/monitoring-device-state/doze-standby.html">
    ++  Mengoptimalkan untuk Istirahatkan dan Aplikasi Siaga</a>. Anda tetap harus
    ++   mengikuti rekomendasi itu, seperti menggunakan Google Cloud Messaging (GCM) untuk
    ++  mengirim dan menerima pesan, serta mulai merencanakan pembaruan
    ++  untuk mengakomodasi perilaku Istirahatkan tambahan.
    ++</p>
    ++
    ++
    ++<h3 id="bg-opt">Project Svelte: Optimalisasi Latar Belakang</h3>
    ++
    ++<p>
    ++  Android N membuang tiga siaran implisit untuk membantu mengoptimalkan
    ++  penggunaan memori dan konsumsi daya. Perubahan ini penting karena siaran
    ++  implisit sering memulai aplikasi yang telah didaftarkan untuk mendengarkannya di
    ++  latar belakang. Membuang siaran ini bisa sangat menguntungkan
    ++  kinerja perangkat dan pengalaman pengguna.
    ++</p>
    ++
    ++<p>
    ++  Perangkat seluler seringkali mengalami perubahan konektivitas, seperti saat berpindah
    ++  antara Wi-Fi dan data seluler. Saat ini, aplikasi bisa memantau perubahan dalam
    ++  konektivitas dengan mendaftarkan suatu penerima untuk siaran implisit {@link
    ++  android.net.ConnectivityManager#CONNECTIVITY_ACTION} dalam manifes
    ++  mereka. Karena banyak aplikasi yang didaftarkan untuk menerima siaran ini, switch  jaringan tunggal
    ++  bisa menyebabkan semuanya aktif dan memproses siaran tersebut
    ++  secara bersamaan.
    ++</p>
    ++
    ++<p>
    ++  Demikian pula, dalam Android versi sebelumnya, aplikasi bisa mendaftar untuk menerima siaran implisit {@link
    ++  android.hardware.Camera#ACTION_NEW_PICTURE} dan {@link
    ++  android.hardware.Camera#ACTION_NEW_VIDEO} dari aplikasi lain, seperti
    ++  Kamera. Bila pengguna mengambil gambar dengan aplikasi Kamera, semua aplikasi ini akan aktif
    ++  untuk memproses siaran.
    ++</p>
    ++
    ++<p>
    ++  Untuk meminimalkan masalah ini, Android N menerapkan optimalisasi
    ++  berikut:
    ++</p>
    ++
    ++<ul>
    ++  <li>Aplikasi yang menargetkan Android N tidak menerima siaran {@link
    ++  android.net.ConnectivityManager#CONNECTIVITY_ACTION}, sekalipun
    ++  memiliki entri manifes untuk meminta pemberitahuan mengenai kejadian ini. Aplikasi
    ++  yang berjalan tetap bisa mendengarkan {@code CONNECTIVITY_CHANGE} pada thread utama
    ++  jika mereka meminta pemberitahuan dengan {@link android.content.BroadcastReceiver}.
    ++  </li>
    ++
    ++  <li>Aplikasi tidak bisa mengirim atau menerima siaran {@link
    ++  android.hardware.Camera#ACTION_NEW_PICTURE} atau {@link
    ++  android.hardware.Camera#ACTION_NEW_VIDEO}. Optimalisasi ini
    ++  memengaruhi semua aplikasi, bukan hanya aplikasi yang menargetkan Android N.
    ++  </li>
    ++</ul>
    ++
    ++<p>Jika aplikasi Anda menggunakan intent ini, Anda harus membuang dependensi padanya
    ++  secepat mungkin agar Anda bisa menargetkan perangkat Android N dengan benar.
    ++  Kerangka kerja Android menyediakan beberapa solusi untuk mengurangi kebutuhan akan
    ++  siaran implisit ini. Misalnya, {@link
    ++  android.app.job.JobScheduler} API menyediakan mekanisme yang tangguh untuk menjadwalkan
    ++  operasi jaringan bila kondisi yang ditetapkan, seperti koneksi ke jaringan
    ++  berbiaya tetap, terpenuhi. Anda juga dapat menggunakan {@link
    ++  android.app.job.JobScheduler} untuk bereaksi terhadap perubahan pada penyedia materi.
    ++</p>
    ++
    ++<p>
    ++  Untuk informasi selengkapnya tentang optimalisasi latar belakang di N dan cara menyesuaikan aplikasi Anda,
    ++  lihat <a href="{@docRoot}preview/features/background-optimization.html">Optimalisasi
    ++  Latar Belakang</a>.
    ++</p>
    ++
    ++<h2 id="perm">Perubahan Izin</h2>
    ++
    ++<p>
    ++  Android N menyertakan perubahan pada izin yang bisa memengaruhi aplikasi Anda.
    ++</p>
    ++
    ++<h3 id="permfilesys">Perubahan izin sistem file</h3>
    ++
    ++<p>
    ++  Guna meningkatkan keamanan file privat, direktori privat
    ++  aplikasi yang menargetkan Android N atau yang lebih tinggi memiliki akses terbatas (<code>0700</code>).
    ++  Pengaturan ini mencegah kebocoran metadata dari file privat, seperti ukuran
    ++  atau eksistensi. Perubahan izin ini memiliki beberapa efek samping:
    ++</p>
    ++
    ++<ul>
    ++  <li>
    ++    Izin file privat tidak boleh dianggap remeh oleh pemilik,
    ++    dan usaha untuk melakukannya menggunakan
    ++    {@link android.content.Context#MODE_WORLD_READABLE} dan/atau
    ++    {@link android.content.Context#MODE_WORLD_WRITEABLE}, akan memicu sebuah
    ++    {@link java.lang.SecurityException}.
    ++    <p class="note">
    ++      <strong>Catatan:</strong> Seperti sebelumnya, pembatasan ini tidak sepenuhnya diterapkan.
    ++      Aplikasi mungkin masih memodifikasi izin ke direktori privat mereka menggunakan
    ++      API asal atau {@link java.io.File File} API. Akan tetapi, kami sangat
    ++      tidak menyarankan Anda meremehkan izin direktori privat.
    ++    </p>
    ++  </li>
    ++  <li>
    ++    Meneruskan URI <code>file://</code> di luar domain paket dapat meninggalkan
    ++    penerima dengan jalur yang tidak bisa di akses. Karena itu, upaya untuk meneruskan URI
    ++    <code>file://</code> akan memicu
    ++    <code>FileUriExposedException</code>. Cara yang disarankan adalah
    ++    materi file privat menggunakan {@link
    ++    android.support.v4.content.FileProvider}.
    ++  </li>
    ++  <li>
    ++    {@link android.app.DownloadManager} tidak bisa lagi berbagi
    ++    file yang tersimpan secara privat berdasarkan nama file. Aplikasi lawas dapat mengakibatkan
    ++    jalur yang tidak dapat diakses saat mengakses {@link
    ++    android.app.DownloadManager#COLUMN_LOCAL_FILENAME}. Aplikasi yang menargetkan
    ++    Android N atau yang lebih tinggi akan memicu {@link java.lang.SecurityException} saat
    ++    berupaya mengakses
    ++    {@link android.app.DownloadManager#COLUMN_LOCAL_FILENAME}.
    ++    Aplikasi lawas yang menyetel lokasi unduhan ke lokasi publik dengan
    ++    menggunakan
    ++    {@link
    ++    android.app.DownloadManager.Request#setDestinationInExternalFilesDir
    ++    DownloadManager.Request.setDestinationInExternalFilesDir()} atau
    ++    {@link
    ++    android.app.DownloadManager.Request#setDestinationInExternalPublicDir
    ++    DownloadManager.Request.setDestinationInExternalPublicDir()}
    ++    tetap bisa mengakses jalur tersebut di
    ++    {@link android.app.DownloadManager#COLUMN_LOCAL_FILENAME}, akan tetapi,
    ++     metode ini sangat tidak disarankan. Cara yang disarankan untuk mengakses file
    ++    yang diekspos oleh {@link android.app.DownloadManager} adalah menggunakan
    ++    {@link android.content.ContentResolver#openFileDescriptor
    ++    ContentResolver.openFileDescriptor()}.
    ++  </li>
    ++</ul>
    ++
    ++<h2 id="sharing-files">Berbagi File Antar Aplikasi</h2>
    ++
    ++<p>
    ++Untuk aplikasi yang menargetkan Android N, kerangka kerja Android menerapkan
    ++kebijakan {@link android.os.StrictMode} API yang melarang mengekspos URI {@code file://}
    ++di luar aplikasi Anda. Jika sebuah intent berisi URI file meninggalkan aplikasi Anda, aplikasi tersebut akan gagal
    ++dengan pengecualian {@code FileUriExposedException}.
    ++</p>
    ++
    ++<p>
    ++Untuk berbagi file antar aplikasi, Anda harus mengirim URI {@code content://}
    ++dan memberikan izin akses sementara pada URI. Cara termudah untuk memberikan izin ini adalah dengan
    ++menggunakan kelas {@link android.support.v4.content.FileProvider}. Untuk informasi selengkapnya
    ++mengenai izin dan berbagi file,
    ++lihat <a href="{@docRoot}training/secure-file-sharing/index.html">Berbagi File</a>.
    ++</p>
    ++
    ++<h2 id="accessibility">Peningkatan Aksesibilitas</h2>
    ++
    ++<p>
    ++  Android N menyertakan perubahan yang bertujuan meningkatkan kegunaan
    ++  platform untuk pengguna dengan penglihatan yang rendah atau lemah. Perubahan ini umumnya tidak
    ++  memerlukan perubahan kode dalam aplikasi Anda, akan tetapi Anda harus memeriksa
    ++  fitur ini dan mengujinya dengan aplikasi untuk menilai kemungkinan dampaknya terhadap pengalaman
    ++  pengguna.
    ++</p>
    ++
    ++
    ++<h3 id="screen-zoom">Perbesaran Layar</h3>
    ++
    ++<p>
    ++  Android N memungkinkan pengguna menyetel <strong>Display size</strong> yang akan memperbesar
    ++  atau memperkecil semua elemen pada layar, sehingga meningkatkan aksesibilitas perangkat
    ++  bagi pengguna yang kurang melihat. Pengguna tidak bisa memperbesar layar melewati lebar layar
    ++  minimum <a href="http://developer.android.com/guide/topics/resources/providing-resources.html">
    ++  sw320dp</a>, yang merupakan lebar Nexus 4, yakni ponsel ukuran sedang pada umumnya.
    ++</p>
    ++
    ++<div class="cols">
    ++
    ++<div class="col-6">
    ++  <img src="{@docRoot}images/android-7.0/screen-zoom-1.png" alt="" height="XXX" id="figure1" />
    ++</div>
    ++<div class="col-6">
    ++  <img src="{@docRoot}images/android-7.0/screen-zoom-2.png" alt="" height="XXX" id="figure1" />
    ++</div>
    ++
    ++</div> <!-- end cols -->
    ++<p class="img-caption">
    ++  <strong>Gambar 3.</strong> Layar di sebelah kanan menampilkan efek
    ++ penambahan Display size perangkat yang menjalankan citra sistem Android N.
    ++</p>
    ++
    ++
    ++<p>
    ++  Bila kepadatan perangkat berubah, sistem akan memberi tahu aplikasi yang sedang berjalan dengan
    ++  cara berikut:
    ++</p>
    ++
    ++<ul>
    ++  <li>Jika aplikasi menargetkan API level 23 atau yang lebih rendah, sistem secara otomatis akan mematikan
    ++  semua proses latar belakang. Artinya, jika pengguna beralih dari
    ++  aplikasi tersebut untuk membuka layar <em>Settings</em> dan mengubah
    ++  setelan <strong>Display size</strong>, maka sistem akan mematikan aplikasi tersebut dengan cara yang
    ++  sama dengan saat memori tinggal sedikit. Jika aplikasi memiliki beberapa proses
    ++  latar depan, sistem akan memberi tahu proses tersebut mengenai perubahan konfigurasi seperti
    ++ dijelaskan dalam <a href="{@docRoot}guide/topics/resources/runtime-changes.html">Menangani Perubahan
    ++  Waktu Proses</a>, seolah-olah orientasi perangkat telah berubah.
    ++  </li>
    ++
    ++  <li>Jika sebuah aplikasi menargetkan Android N, semua prosesnya
    ++  (latar depan dan latar belakang) akan diberi tahu mengenai perubahan konfigurasi seperti
    ++  dijelaskan dalam <a href="{@docRoot}guide/topics/resources/runtime-changes.html">Menangani Perubahan
    ++  Waktu Proses</a>.
    ++  </li>
    ++</ul>
    ++
    ++<p>
    ++  Sebagian besar aplikasi tidak perlu melakukan perubahan untuk mendukung fitur ini, asalkan
    ++  aplikasi tersebut mengikuti praktik terbaik Android. Hal-hal tertentu yang harus diperiksa:
    ++</p>
    ++
    ++<ul>
    ++  <li>Uji aplikasi Anda pada perangkat dengan lebar layar <code><a href=
    ++  "{@docRoot}guide/topics/resources/providing-resources.html">sw320dp</a></code>
    ++  dan pastikan aplikasi berjalan dengan semestinya.
    ++  </li>
    ++
    ++  <li>Bila konfigurasi perangkat berubah, perbarui informasi cache
    ++  yang bergantung pada kepadatan, seperti bitmap di cache atau sumber daya yang dimuat dari
    ++  jaringan. Periksa perubahan konfigurasi bila aplikasi melanjutkan dari status dihentikan
    ++  sementara.
    ++    <p class="note">
    ++      <strong>Catatan:</strong> Catatan: Jika Anda meng-cache data yang bergantung pada konfigurasi, ada
    ++      baiknya untuk menyertakan metadata yang relevan seperti ukuran layar
    ++      atau kepadatan piksel yang sesuai untuk data tersebut. Menyimpan metadata ini memungkinkan Anda untuk
    ++      memutuskan apakah Anda perlu segarkan data cache setelah perubahan
    ++      konfigurasi.
    ++    </p>
    ++  </li>
    ++
    ++  <li>Hindari menetapkan dimensi dengan satuan px, karena satuan ini tidak diskalakan dengan
    ++  kepadatan layar. Sebagai gantinya, tetapkan dimensi dengan satuan <a href="{@docRoot}guide/practices/screens_support.html">piksel yang tidak bergantung kepadatan
    ++  </a> (<code>dp</code>).
    ++  </li>
    ++</ul>
    ++
    ++<h3 id="vision-settings">Vision Settings di Setup Wizard</h3>
    ++
    ++<p>
    ++  Android N menyertakan Vision Settings di layar Sambutan, di mana pengguna bisa
    ++  menyiapkan setelan aksesibilitas berikut pada perangkat baru:
    ++  <strong>Magnification gesture</strong>, <strong>Font size</strong>,
    ++  <strong>Display size</strong> dan <strong>TalkBack</strong>. Perubahan ini
    ++  meningkatkan visibilitas bug terkait dengan setelan layar yang berbeda. Untuk
    ++  mengurangi dampak fitur ini, Anda harus menguji aplikasi dengan setelan ini
    ++  diaktifkan. Anda bisa menemukannya pada <strong>Settings &gt;
    ++  Accessibility</strong>.
    ++</p>
    ++
    ++<h2 id="ndk">Penautan Aplikasi NDK ke Pustaka Platform</h2>
    ++
    ++<p>
    ++  Android N menyertakan perubahan ruang nama untuk mencegah pemuatan API non-publik.
    ++  Jika menggunakan NDK, Anda hanya boleh menggunakan API publik dari platform
    ++  Android. Menggunakan API non-publik dalam rilis Android resmi berikutnya
    ++  bisa menyebabkan aplikasi mogok.
    ++</p>
    ++
    ++<p>
    ++  Untuk memberi tahu Anda agar menggunakan API non-publik, aplikasi yang berjalan pada perangkat
    ++  Android N akan menghasilkan kesalahan dalam keluaran logcat bila aplikasi memanggil API non-publik.
    ++  Kesalahan ini juga ditampilkan di layar perangkat berupa pesan untuk membantu
    ++  meningkatkan kepedulian terhadap situasi ini. Anda harus memeriksa kode aplikasi untuk
    ++  membuang penggunaan API platform non-publik dan secara saksama menguji aplikasi Anda menggunakan
    ++  perangkat pratinjau atau emulator.
    ++</p>
    ++
    ++<p>
    ++  Jika aplikasi Anda bergantung pada pustaka platform, lihat dokumentasi NDK untuk
    ++  perbaikan tipikal guna menggantikan API privat umum dengan padanan API publik.
    ++  Anda mungkin juga menautkan ke pustaka platform tanpa menyadarinya,
    ++  terutama jika aplikasi Anda menggunakan pustaka yang merupakan bagian dari platform ini (seperti
    ++  <code>libpng</code>), namun bukan bagian dari NDK. Dalam hal itu, pastikan
    ++  APK Anda berisi semua file .so yang ingin ditautkan.
    ++</p>
    ++
    ++<p class="caution">
    ++  <strong>Perhatian:</strong> Beberapa pustaka pihak ketiga mungkin menautkan ke API
    ++  non-publik. Jika menggunakan pustaka ini, aplikasi Anda bisa mogok saat dijalankan
    ++  pada rilis resmi Android berikutnya.
    ++</p>
    ++
    ++<p>
    ++  Aplikasi tidak boleh bergantung pada atau menggunakan pustaka bawaan yang tidak disertakan dalam
    ++  NDK, karena bisa mengalami perubahan, atau dipindahkan dari satu rilis Android ke
    ++  rilis lainnya. Peralihan dari OpenSSL ke BoringSSL merupakan satu contoh dari perubahan semacam ini.
    ++  Selain itu, perangkat yang berbeda bisa menawarkan tingkat kompatibilitas yang berbeda, karena
    ++   tidak ada persyaratan kompatibilitas untuk pustaka platform yang tidak disertakan
    ++  dalam NDK. Jika Anda harus mengakses pustaka non-NDK pada perangkat yang lebih lama, jadikan
    ++  pemuatan bergantung pada level Android API.
    ++</p>
    ++
    ++<p>
    ++  Untuk membantu Anda mendiagnosis tipe masalah ini ada beberapa contoh kesalahan Java dan NDK
    ++  yang mungkin Anda temui saat berusaha membangun aplikasi dengan Android N:
    ++</p>
    ++
    ++<p>Contoh kesalahan Java:</p>
    ++<pre class="no-pretty-print">
    ++java.lang.UnsatisfiedLinkError: dlopen failed: library "/system/lib/libcutils.so"
    ++    is not accessible for the namespace "classloader-namespace"
    ++</pre>
    ++
    ++<p>Contoh kesalahan NDK:</p>
    ++<pre class="no-pretty-print">
    ++dlopen failed: cannot locate symbol "__system_property_get" referenced by ...
    ++</pre>
    ++
    ++
    ++<p>
    ++  Inilah beberapa perbaikan tipikal untuk aplikasi yang mengalami tipe kesalahan ini:
    ++</p>
    ++
    ++<ul>
    ++  <li>Penggunaan getJavaVM dan getJNIEnv dari libandroid_runtime.so bisa diganti
    ++  dengan fungsi JNI standar:
    ++<pre class="no-pretty-print">
    ++AndroidRuntime::getJavaVM -&gt; GetJavaVM from &lt;jni.h&gt;
    ++AndroidRuntime::getJNIEnv -&gt; JavaVM::GetEnv or
    ++JavaVM::AttachCurrentThread from &lt;jni.h&gt;.
    ++</pre>
    ++  </li>
    ++
    ++  <li>Penggunaan simbol {@code property_get} dari {@code libcutils.so} bisa
    ++    diganti dengan {@code alternative __system_property_get} publik.
    ++   Caranya, gunakan {@code __system_property_get} dengan menyertakan yang berikut:
    ++<pre>
    ++#include &lt;sys/system_properties.h&gt;
    ++</pre>
    ++  </li>
    ++
    ++  <li>Penggunaan simbol {@code SSL_ctrl} dari {@code libcrypto.so} harus
    ++    diganti dengan aplikasi versi lokal. Misalnya, Anda harus menautkan
    ++  {@code libcyrpto.a} secara statis dalam file {@code .so} atau menyertakan
    ++  {@code libcrypto.so} Anda sendiri secara dinamis dari BoringSSL atau OpenSSL dalam aplikasi Anda.
    ++  </li>
    ++</ul>
    ++
    ++<h2 id="afw">Android for Work</h2>
    ++<p>
    ++  Android N berisi perubahan untuk aplikasi yang menargetkan Android for Work, termasuk
    ++  perubahan pada pemasangan sertifikat, penyetelan ulang sandi, manajemen pengguna
    ++  tambahan, dan akses ke identifier perangkat. Jika Anda membangun aplikasi untuk
    ++  lingkungan Android for Work, Anda harus meninjau perubahan ini dan memodifikasi
    ++  aplikasi sebagaimana mestinya.
    ++</p>
    ++
    ++<ul>
    ++  <li>Anda harus pasang pemasang sertifikat yang didelegasikan sebelum DPC bisa
    ++  menyetelnya. Untuk aplikasi profil dan aplikasi pemilik perangkat yang menargetkan N SDK, Anda harus
    ++  pasang pemasang sertifikat yang didelegasikan sebelum pengontrol kebijakan
    ++  perangkat (DPC) memanggil
    ++  <code>DevicePolicyManager.setCertInstallerPackage()</code>. Jika pemasang
    ++  belum dipasang, sistem akan melontarkan
    ++  <code>IllegalArgumentException</code>.
    ++  </li>
    ++
    ++  <li>Pembatasan sandi penyetelan ulang untuk admin perangkat sekarang diterapkan ke pemilik
    ++  profil. Admin perangkat tidak bisa lagi menggunakan
    ++  {@code DevicePolicyManager.resetPassword()} untuk menghapus sandi atau mengubah
    ++  sandi yang sudah disetel. Admin perangkat tetap bisa menyetel sandi, namun hanya
    ++  bila perangkat belum memiliki sandi, PIN, atau pola.
    ++  </li>
    ++
    ++  <li>Pemilik perangkat dan profil bisa mengelola akun meskipun pembatasan
    ++  telah disetel. Pemilik perangkat dan pemilik profil bisa memanggil Account Management API
    ++  sekalipun pembatasan pengguna <code>DISALLOW_MODIFY_ACCOUNTS</code> diberlakukan.
    ++  </li>
    ++
    ++  <li>Pemilik perangkat bisa mengelola pengguna tambahan lebih mudah. Bila perangkat
    ++  berjalan dalam mode pemilik perangkat, maka pembatasan <code>DISALLOW_ADD_USER</code>
    ++  secara otomatis akan ditetapkan. Ini mencegah pengguna membuat pengguna tambahan yang
    ++  tidak terkelola. Selain itu, <code>CreateUser()</code> dan
    ++  <code>createAndInitializeUser()</code> metode tidak digunakan lagi; metode
    ++  <code>DevicePolicyManager.createAndManageUser()</code> telah menggantikannya.
    ++  </li>
    ++
    ++  <li>Pemilik perangkat bisa mengakses identifier perangkat. Pemilik perangkat bisa mengakses
    ++  alamat MAC Wi-Fi dari perangkat, menggunakan
    ++  <code>DevicePolicyManagewr.getWifiMacAddress()</code>. Jika Wi-Fi belum pernah
    ++  diaktifkan pada perangkat tersebut, metode ini akan mengembalikan nilai {@code null}.
    ++  </li>
    ++
    ++  <li>Setelan Mode Kerja mengontrol akses ke aplikasi kerja. Bila mode kerja tidak aktif, peluncur sistem
    ++  akan menunjukkan aplikasi kerja tidak tersedia dengan membuat warnanya jadi abu-abu. Mengaktifkan kembali
    ++ mode kerja akan memulihkan perilaku normal.
    ++</ul>
    ++
    ++<p>
    ++  Untuk informasi selengkapnya tentang perubahan Android for Work di Android N, lihat
    ++  <a href="{@docRoot}preview/features/afw.html">Pembaruan Android for Work</a>.
    ++</p>
    ++
    ++<h2 id="annotations">Retensi Anotasi</h2>
    ++
    ++<p>
    ++Android N memperbaiki bug dengan visibilitas anotasi diabaikan.
    ++Masalah ini mengaktifkan waktu proses untuk mengakses anotasi yang seharusnya tidak bisa
    ++dilakukan. Anotasi ini termasuk:
    ++</p>
    ++
    ++<ul>
    ++   <li>{@code VISIBILITY_BUILD}: Dimaksudkan agar hanya bisa terlihat pada waktu pembuatan.</li>
    ++   <li>{@code VISIBILITY_SYSTEM}: Dimaksud agar bisa terlihat pada waktu proses, namun hanya pada
    ++ sistem yang mendasarinya.</li>
    ++</ul>
    ++
    ++<p>
    ++Jika aplikasi Anda mengandalkan perilaku ini, tambahkan kebijakan retensi untuk anotasi yang harus
    ++tersedia di waktu proses. Caranya dengan menggunakan {@code @Retention(RetentionPolicy.RUNTIME)}.
    ++</p>
    ++
    ++<h2 id="other">Poin Penting Lainnya</h2>
    ++
    ++<ul>
    ++<li>Bila aplikasi berjalan pada Android N, namun menargetkan level API yang lebih rendah,
    ++dan pengguna mengubah ukuran tampilan, proses aplikasi akan dimatikan. Aplikasi
    ++harus dapat menangani skenario ini dengan lancar. Jika tidak, maka akan mogok
    ++bila pengguna memulihkannya dari Recents.
    ++
    ++<p>
    ++Anda harus menguji aplikasi untuk memastikan
    ++perilaku ini tidak terjadi.
    ++Anda bisa melakukannya dengan menyebabkan suatu mogok yang identik
    ++saat mematikan aplikasi secara manual melalui DDMS.
    ++</p>
    ++
    ++<p>
    ++Aplikasi yang menargetkan N dan yang di atasnya tidak secara otomatis dimatikan saat perubahan kepadatan;
    ++akan tetapi, aplikasi tersebut mungkin tetap merespons perubahan konfigurasi dengan buruk.
    ++</p>
    ++</li>
    ++
    ++<li>
    ++Aplikasi pada Android N harus mampu menangani perubahan konfigurasi dengan lancar,
    ++dan tidak boleh mengalami mogok pada start selanjutnya. Anda bisa memverifikasi perilaku aplikasi
    ++dengan mengubah ukuran font (<strong>Setting</strong> &gt;
    ++<strong>Display</strong> &gt; <strong>Font size</strong>), kemudian memulihkan
    ++aplikasi dari Recents.
    ++</li>
    ++
    ++<li>
    ++Dikarenakan adanya bug di versi Android sebelumnya, sistem tidak menandai penulisan
    ++  ke soket TCP di thread utama sebagai pelanggaran mode-ketat. Android N memperbaiki bug ini.
    ++Aplikasi yang menunjukkan perilaku ini kini melontarkan sebuah {@code android.os.NetworkOnMainThreadException}.
    ++Secara umum, melakukan operasi jaringan di thread utama tidak baik karena operasi ini
    ++biasanya memiliki latensi tinggi yang menyebabkan ANR dan jank.
    ++</li>
    ++
    ++<li>
    ++Kelompok metode {@code Debug.startMethodTracing()} kini default ke
    ++keluaran penyimpanan di direktori paket tertentu di penyimpanan bersama,
    ++sebagai ganti di level teratas
    ++kartu SD.  Berarti aplikasi tidak perlu lagi meminta izin {@code WRITE_EXTERNAL_STORAGE} untuk menggunakan API ini.
    ++</li>
    ++
    ++<li>
    ++Banyak platform API yang kini mulai memeriksa beban besar yang dikirim
    ++ke seluruh transaksi {@link android.os.Binder}, dan sistem
    ++kini melontarkan kembali {@code TransactionTooLargeExceptions}
    ++sebagai {@code RuntimeExceptions}, sebagai ganti logging secara diam-diam atau menyembunyikannya.  Satu contoh
    ++umum adalah menyimpan terlalu banyak data di
    ++{@link android.app.Activity#onSaveInstanceState Activity.onSaveInstanceState()},
    ++yang menyebabkan {@code ActivityThread.StopInfo} melontarkan
    ++{@code RuntimeException} bila aplikasi Anda menargetkan Android N.
    ++</li>
    ++
    ++<li>
    ++Jika sebuah aplikasi mengeposkan tugas {@link java.lang.Runnable} ke{@link android.view.View}, dan
    ++{@link android.view.View}
    ++tidak terpasang ke jendela, sistem
    ++akan mengantrekan tugas {@link java.lang.Runnable} dengan {@link android.view.View};
    ++tugas {@link java.lang.Runnable} tidak akan dieksekusi hingga
    ++{@link android.view.View} terpasang
    ++ke jendela. Perilaku ini mengatasi bug berikut:
    ++<ul>
    ++   <li>Jika sebuah aplikasi mengeposkan ke {@link android.view.View} dari thread selain thread UI jendela yang dimaksud,
    ++    maka {@link java.lang.Runnable} mungkin akan menjalankan thread yang salah.
    ++   </li>
    ++   <li>Jika tugas {@link java.lang.Runnable} diposkan dari thread selain
    ++   looper-thread, aplikasi bisa mengekspos tugas {@link java.lang.Runnable}.</li>
    ++</ul>
    ++</li>
    ++
    ++<li>
    ++Jika sebuah aplikasi di Android N dengan
    ++izin{@link android.Manifest.permission#DELETE_PACKAGES DELETE_PACKAGES}
    ++mencoba menghapus sebuah paket, namun sebuah aplikasi berbeda telah memasang paket itu,
    ++sistem akan memerlukan konfirmasi pengguna. Dalam skenario ini, aplikasi harus mengharapkan
    ++{@link android.content.pm.PackageInstaller#STATUS_PENDING_USER_ACTION STATUS_PENDING_USER_ACTION}
    ++sebagai status kembalian bila memanggil
    ++{@link android.content.pm.PackageInstaller#uninstall PackageInstaller.uninstall()}.
    ++</li>
    ++
    ++</ul>
    ++
    +diff --git a/docs/html-intl/intl/id/about/versions/nougat/android-7.0-samples.jd b/docs/html-intl/intl/id/about/versions/nougat/android-7.0-samples.jd
    +new file mode 100644
    +index 0000000..d31c0c0
    +--- /dev/null
    ++++ b/docs/html-intl/intl/id/about/versions/nougat/android-7.0-samples.jd
    +@@ -0,0 +1,85 @@
    ++page.title=Contoh
    ++page.tags="preview", "samples", "android"
    ++page.image=images/cards/card-n-samples_2x.png
    ++@jd:body
    ++
    ++<p>
    ++  Contoh kode berikut disediakan untuk Android N. Untuk
    ++  mengunduh contoh di Android Studio, pilih opsi menu <b>File &gt; Import
    ++  Samples</b>.
    ++</p>
    ++
    ++<p class="note">
    ++  <strong>Catatan:</strong> Proyek yang bisa diunduh ini didesain
    ++   untuk digunakan bersama Gradle dan Android Studio.
    ++</p>
    ++
    ++
    ++<h3 id="mw">Playground Multi-Jendela</h3>
    ++<img src="{@docRoot}images/android-7.0/sample-multiwindow.png" style="float: left; padding-right: 0.5em" height="250" width="156" />
    ++<p>
    ++  Contoh ini memperagakan cara memanfaatkan antarmuka pengguna
    ++  multi-jendela bersama aplikasi Anda.
    ++</p>
    ++<p>
    ++  <a href="https://github.com/googlesamples/android-MultiWindowPlayground">
    ++  Dapatkan di GitHub</a>
    ++</p>
    ++
    ++<div style="clear: both;"></div>
    ++<h3 id="an">Pemberitahuan Aktif</h3>
    ++<img src="{@docRoot}images/android-7.0/sample-activenotifications.png" style="float: left; padding-right: 0.5em" height="250" width="141" />
    ++<p>
    ++  Ini adalah contoh yang sudah ada sebelumnya, menampilkan layanan sederhana yang mengirimkan
    ++   pemberitahuan menggunakan NotificationCompat. Setiap percakapan yang belum dibaca dari pengguna
    ++  dikirimkan sebagai pemberitahuan berbeda.
    ++</p>
    ++<p>
    ++  Contoh ini telah diperbarui untuk memanfaatkan fitur pemberitahuan baru
    ++  yang tersedia di Android N.
    ++</p>
    ++<p>
    ++  <a href="https://github.com/googlesamples/android-ActiveNotifications">
    ++  Dapatkan di GitHub</a>
    ++</p>
    ++
    ++<div style="clear: both;"></div>
    ++<h3 id="ms">Layanan Perpesanan</h3>
    ++<img src="{@docRoot}images/android-7.0/sample-messagingservice.png" style="float: left; padding-right: 0.5em" height="250" width="150" />
    ++<p>
    ++  Ini adalah contoh yang telah ada sebelumnya yang memperagakan cara menggunakan
    ++  NotificationManager untuk memberi tahu jumlah pemberitahuan yang saat ini ditampilkan
    ++  oleh aplikasi.
    ++</p>
    ++<p>
    ++  Contoh ini telah diperbarui untuk memanfaatkan fitur pemberitahuan baru
    ++  yang tersedia di Android N.
    ++</p>
    ++<p>
    ++  <a href="https://github.com/googlesamples/android-MessagingService">
    ++  Dapatkan di GitHub</a>
    ++</p>
    ++
    ++<div style="clear: both;"></div>
    ++<h3 id="fbe">Direct Boot</h3>
    ++<img src="{@docRoot}images/android-7.0/sample-directboot.png" style="float: left; padding-right: 0.5em" height="250" width="141" />
    ++<p>
    ++  Contoh ini memperagakan cara menyimpan dan mengakses data dalam penyimpanan yang dienkripsi
    ++  dengan perangkat yang selalu tersedia saat perangkat booting.
    ++</p>
    ++<p>
    ++  <a href="https://github.com/googlesamples/android-DirectBoot">
    ++  Dapatkan di GitHub</a>
    ++</p>
    ++
    ++<div style="clear: both;"></div>
    ++<h3 id="sda">Scoped Directory Access</h3>
    ++<img src="{@docRoot}images/android-7.0/sample-scopeddirectoryaccess.png" style="float: left; padding-right: 0.5em" height="250" width="141" />
    ++<p>
    ++  Contoh ini memperagakan cara membaca dan menulis data dari direktori
    ++  spesifik, sekaligus meminta izin lebih sedikit.
    ++</p>
    ++<p>
    ++  <a href="https://github.com/googlesamples/android-ScopedDirectoryAccess">
    ++  Dapatkan di GitHub</a>
    ++</p>
    +diff --git a/docs/html-intl/intl/id/about/versions/nougat/android-7.0.jd b/docs/html-intl/intl/id/about/versions/nougat/android-7.0.jd
    +new file mode 100644
    +index 0000000..ff8af12
    +--- /dev/null
    ++++ b/docs/html-intl/intl/id/about/versions/nougat/android-7.0.jd
    +@@ -0,0 +1,1039 @@
    ++page.title=Android N for Developers
    ++meta.tags="preview", "androidn"
    ++page.tags="preview", "developer preview"
    ++page.image=images/cards/card-n-apis_2x.png
    ++@jd:body
    ++
    ++
    ++
    ++
    ++<div id="tb-wrapper">
    ++<div id="tb">
    ++  <h2>Fitur-fitur Utama bagi Pengembang</h2>
    ++  <ol>
    ++      <ul style="list-style-type:none;">
    ++        <li><a href="#multi-window_support">Dukungan Multi-Jendela</a></li>
    ++        <li><a href="#notification_enhancements">Pemberitahuan</a></li>
    ++        <li><a href="#jit_aot">Kompilasi JIT/AOT</a></li>
    ++        <li><a href="#quick_path_to_app_install">Jalur Cepat untuk Pasang Aplikasi</a></li>
    ++        <li><a href="#doze_on_the_go">Istirahatkan Kapan Saja</a></li>
    ++        <li><a href="#background_optimizations">Optimalisasi Latar Belakang</a></li>
    ++        <li><a href="#data_saver">Data Saver</a></li>
    ++        <li><a href="#vulkan">Vulkan API</a></li>
    ++        <li><a href="#tile_api">Quick Settings Tile API</a></li>
    ++        <li><a href="#number-blocking">Pemblokiran Nomor</a></li>
    ++        <li><a href="#call_screening">Penyaringan Panggilan</a></li>
    ++        <li><a href="#multi-locale_languages">Lokal dan Bahasa</a></li>
    ++        <li><a href="#emoji">Emoji Baru</a></li>
    ++        <li><a href="#icu4">ICU4J API di Android</a></li>
    ++        <li><a href="#gles_32">OpenGL ES 3.2 API</a></li>
    ++        <li><a href="#android_tv_recording">Perekaman Android TV</a></li>
    ++        <li><a href="#android_for_work">Android for Work</a></li>
    ++        <li><a href="#accessibility_enhancements">Aksesibilitas</a></li>
    ++        <li><a href="#direct_boot">Direct Boot</a></li>
    ++        <li><a href="#key_attestation">Key Attestation</a></li>
    ++        <li><a href="#network_security_config">Network Security Config</a></li>
    ++        <li><a href="#default_trusted_ca">CA Tepercaya Default</a></li>
    ++        <li><a href="#apk_signature_v2">APK Signature Scheme V2</a></li>
    ++        <li><a href="#scoped_directory_access">Scoped Directory Access</a></li>
    ++        <li><a href="#keyboard_shortcuts_helper">Keyboard Shortcuts Helper</a></li>
    ++        <li><a href="#sustained_performance_api">Sustained Performance API</a></li>
    ++        <li><a href="#vr">Dukungan VR</a></li>
    ++        <li><a href="#print_svc">Penyempurnaan Layanan Cetak</a></li>
    ++        <li><a href="#virtual_files">File Maya</a></li>
    ++        <li><a href="#framemetrics_api">FrameMetricsListener API</a></li>
    ++      </ol>
    ++</div>
    ++</div>
    ++
    ++
    ++
    ++<p>Android N masih dalam pengembangan aktif, namun Anda bisa mencobanya
    ++sekarang sebagai bagian dari N Developer Preview. Bagian-bagian di bawah ini akan menyoroti sebagian dari
    ++fitur baru untuk pengembang. </p>
    ++
    ++<p>
    ++  Pastikan memeriksa <a href="{@docRoot}preview/behavior-changes.html">Perubahan Perilaku</a> untuk mengetahui selengkapnya tentang
    ++  bagian-bagian perubahan platform yang bisa memengaruhi aplikasi Anda, lihatlah
    ++  panduan pengembang untuk mengetahui selengkapnya tentang fitur-fitur utama, dan unduh <a href="{@docRoot}preview/setup-sdk.html#docs-dl">Referensi API</a> untuk mengetahui detail tentang
    ++  API baru.
    ++</p>
    ++
    ++<h2 id="multi-window_support">Dukungan Multi-Jendela</h2>
    ++
    ++
    ++<p>Di Android N, kami memperkenalkan fitur multitasking baru dan yang banyak diminta
    ++ke dalam platform &mdash; dukungan multi-jendela. </p>
    ++
    ++  <p>Pengguna sekarang bisa membuka dua aplikasi sekaligus di layar. </p>
    ++  <ul>
    ++  <li>Pada ponsel dan tablet
    ++yang menjalankan Android N, pengguna bisa menjalankan dua aplikasi secara berdampingan atau
    ++satu aplikasi di atas yang lain dalam mode layar terbagi. Pengguna bisa mengubah ukuran aplikasi dengan menyeret
    ++pembagi di antara keduanya. </li>
    ++
    ++<li>Pada perangkat Android TV, aplikasi bisa menempatkan dirinya sendiri dalam <a href="{@docRoot}preview/features/picture-in-picture.html">mode
    ++gambar-dalam-gambar</a>, sehingga aplikasi bisa terus menampilkan materi sementara pengguna menjelajahi atau
    ++berinteraksi dengan aplikasi lain.</li>
    ++  </ul>
    ++
    ++<div class="col-4of10">
    ++<img src="{@docRoot}images/android-7.0/mw-portrait.png" alt="" style="height:460px;padding-left:1em;" id="img-split-screen" />
    ++<p class="img-caption">
    ++  <strong>Gambar 1.</strong> Aplikasi yang berjalan dalam mode layar terbagi.
    ++</p>
    ++
    ++  </div>
    ++
    ++<p>Khususnya pada tablet dan perangkat yang berlayar lebih besar lainnya, dukungan multi-jendela
    ++memberi Anda cara baru untuk memikat pengguna. Anda bahkan bisa mengaktifkan fitur seret-dan-lepas di
    ++aplikasi untuk memudahkan pengguna menyeret materi ke dan dari aplikasi &mdash; cara bagus
    ++untuk menyempurnakan pengalaman pengguna Anda. </p>
    ++
    ++<p>Tidak sulit menambahkan dukungan multi-jendela ke aplikasi Anda dan mengonfigurasi cara
    ++menangani tampilan multi-jendela. Misalnya, Anda bisa menetapkan dimensi
    ++minimum yang diizinkan aktivitas, sehingga mencegah pengguna mengubah ukuran aktivitas di bawah
    ++ukuran itu. Anda juga bisa menonaktifkan tampilan multi-jendela untuk aplikasi Anda, yang
    ++  akan memastikan sistem hanya menampilkan aplikasi dalam mode layar penuh.</p>
    ++
    ++<p>
    ++  Untuk informasi selengkapnya, lihat dokumentasi pengembang <a href="{@docRoot}preview/features/multi-window.html">Dukungan Multi-Jendela</a>.
    ++
    ++</p>
    ++
    ++<h2 id="notification_enhancements">Penyempurnaan Pemberitahuan</h2>
    ++
    ++<p>Di Android N kami telah mengubah desain pemberitahuan agar lebih mudah dan lebih cepat
    ++digunakan. Beberapa perubahan tersebut antara lain:</p>
    ++
    ++<ul>
    ++  <li>
    ++    <strong>Pembaruan template</strong>: Kami telah memperbarui template pemberitahuan untuk
    ++    lebih menekankan citra pahlawan dan avatar. Pengembang akan dapat
    ++   memanfaatkan template baru dengan penyesuaian kode yang minimal.
    ++  </li>
    ++
    ++  <li>
    ++    <strong>Penyesuaian gaya pesan</strong>: Anda bisa menyesuaikan lebih banyak
    ++    label antarmuka pengguna yang berkaitan dengan pemberitahuan Anda menggunakan kelas
    ++    <code>MessageStyle</code>. Anda bisa mengonfigurasi pesan, judul percakapan,
    ++    dan tampilan materi.
    ++  </li>
    ++
    ++  <li>
    ++    <strong>Bundel pemberitahuan</strong>: Sistem bisa mengelompokkan pesan,
    ++    misalnya menurut topik pesan, dan menampilkan kelompok pesan tersebut. Seorang pengguna bisa
    ++   bertindak, misalnya Tutup atau Arsipkan, atas pesan yang ditampilkan. Jika Anda sudah
    ++    mengimplementasikan pemberitahuan untuk Android Wear, Anda akan terbiasa dengan
    ++    model ini.
    ++  </li>
    ++
    ++  <li>
    ++    <strong>Balasan Langsung</strong>: Untuk aplikasi komunikasi real-time, sistem
    ++    Android mendukung balasan inline sehingga pengguna bisa dengan cepat membalas
    ++    SMS atau pesan teks secara langsung dari dalam antarmuka pemberitahuan.
    ++  </li>
    ++
    ++  <li>
    ++    <strong>Tampilan khusus</strong>: Dua API baru memungkinkan Anda memanfaatkan dekorasi sistem,
    ++    misalnya header pemberitahuan dan tindakan, saat menggunakan tampilan
    ++    khusus dalam pemberitahuan.
    ++  </li>
    ++</ul>
    ++
    ++<div class="col-4of12">
    ++  <img src="{@docRoot}images/android-7.0/notifications-1.png" alt="" style="padding:.5em;max-width:226px">
    ++</div>
    ++
    ++<div class="col-4of12">
    ++  <img src="{@docRoot}images/android-7.0/notifications-3.png" alt="" style="padding:.5em;max-width:226px">
    ++</div>
    ++
    ++<div class="col-4of12">
    ++  <img src="{@docRoot}images/android-7.0/notifications-2.png" alt="" style="padding:.5em;max-width:226px">
    ++</div>
    ++
    ++
    ++<p class="img-caption">
    ++  <strong>Gambar 2.</strong> Bundel pemberitahuan dan balasan langsung.
    ++</p>
    ++
    ++<p>Untuk mengetahui cara mengimplementasikan fitur-fitur
    ++  baru ini, lihat panduan <a href="{@docRoot}preview/features/notification-updates.html">Pemberitahuan</a>.
    ++</p>
    ++
    ++
    ++
    ++<h2 id="jit_aot">Kompilasi JIT/AOT yang dipandu profil</h2>
    ++
    ++<p>Di Android N, kami telah menambahkan compiler Just in Time (JIT) dengan pembuatan profil kode ke
    ++ART, yang memungkinkannya terus meningkatkan kinerja aplikasi Android saat
    ++dijalankan. Compiler JIT melengkapi compiler Ahead of Time (AOT) pada ART
    ++dan membantu memperbaiki kinerja waktu proses, menghemat ruang penyimpanan, dan mempercepat
    ++pembaruan aplikasi serta pembaruan sistem.</p>
    ++
    ++<p>Kompilasi yang dipandu profil memungkinkan ART mengelola kompilasi AOT/JIT untuk setiap aplikasi
    ++sesuai dengan penggunaan sebenarnya, serta kondisi pada perangkat. Misalnya
    ++,ART menyimpan profil setiap metode terbaik aplikasi dan bisa melakukan kompilasi lebih awal
    ++serta menyimpan sementara metode-metode tersebut di cache untuk mendapatkan kinerja terbaik. Hal ini membuat bagian lain dari aplikasi
    ++dibiarkan tidak dikompilasi hingga benar-benar digunakan.</p>
    ++
    ++<p>Di samping meningkatkan kinerja bagian-bagian penting aplikasi, kompilasi yang dipandu profil
    ++membantu mengurangi footprint RAM keseluruhan aplikasi, termasuk biner
    ++terkait. Fitur ini terutama penting pada perangkat dengan memori minim.</p>
    ++
    ++<p>ART mengelola kompilasi yang dipandu profil dengan cara yang meminimalkan dampak terhadap
    ++baterai perangkat. ART melakukan prakompilasi hanya bila perangkat sedang diam dan
    ++mengisi daya, sehingga menghemat waktu dan baterai dengan melakukan pekerjaan tersebut di awal.</p>
    ++
    ++<h2 id="quick_path_to_app_install">Jalur Cepat untuk Pasang Aplikasi</h2>
    ++
    ++<p>Salah satu manfaat paling nyata dari compiler JIT pada ART adalah kecepatan
    ++pemasnagan aplikasi dan pembaruan sistem. Bahkan aplikasi besar yang membutuhkan beberapa menit untuk
    ++dioptimalkan dan dipasang di Android 6.0 sekarang bisa dipasang hanya dalam hitungan
    ++detik. Pembaruan sistem juga lebih cepat, karena tidak ada lagi langkah optimalisasi. </p>
    ++
    ++<h2 id="doze_on_the_go">Istirahatkan Kapan Saja...</h2>
    ++
    ++<p>Android 6.0 memperkenalkan Istirahatkan, yaitu mode sistem yang menghemat baterai dengan menangguhkan
    ++aktivitas CPU dan jaringan di aplikasi bila perangkat sedang diam, misalnya saat
    ++diletakkan di atas meja atau dalam laci. </p>
    ++
    ++<p>Sekarang di Android N, Istirahatkan selangkah lebih maju dalam menghemat baterai kapan saja.
    ++Setiap kali layar mati dalam jangka waktu tertentu dan perangkat tidak terhubung ke sumber daya,
    ++Istirahatkan akan menerapkan subset pembatasan umum CPU dan jaringan pada aplikasi.
    ++Artinya pengguna bisa menghemat daya baterai meskipun perangkat dibawa di dalam
    ++tasnya.</p>
    ++
    ++
    ++<img src="/preview/images/doze-diagram-1.png" alt="" id="figure1" />
    ++<p class="img-caption">
    ++  <strong>Gambar 3.</strong> Istirahatkan sekarang menerapkan
    ++  pembatasan untuk meningkatkan daya tahan baterai bahkan saat perangkat sedang tidak diam.
    ++</p>
    ++
    ++
    ++<p>Tidak lama setelah layar dimatikan saat perangkat menggunakan daya baterai, Istirahatkan
    ++akan membatasi akses jaringan serta menangguhkan pekerjaan dan sinkronisasi. Selama jeda
    ++pemeliharaan, aplikasi diizinkan mengakses jaringan dan menjalankan semua
    ++pekerjaan/sinkronisasi yang ditangguhkan. Menyalakan layar atau mencolokkan perangkat akan mengeluarkan
    ++perangkat dari Istirahatkan.</p>
    ++
    ++<p>Bila perangkat dalam kondisi diam lagi, dengan layar mati dan menggunakan daya baterai selama
    ++jangka waktu tertentu, Istirahatkan akan menerapkan pembatasan CPU dan jaringan pada {@link
    ++android.os.PowerManager.WakeLock}, alarm {@link android.app.AlarmManager}, dan
    ++pemindaian GPS/Wi-Fi.</p>
    ++
    ++<p>Praktik terbaik untuk menyesuaikan aplikasi Anda dengan Istirahatkan adalah sama, baik
    ++perangkat sedang bergerak maupun diam, jadi jika Anda sudah memperbarui aplikasi untuk
    ++menjalankan Istirahatkan dengan lancar, berarti Anda sudah siap. Jika belum, mulailah <a href="{@docRoot}training/monitoring-device-state/doze-standby.html#assessing_your_app">menyesuaikan
    ++aplikasi Anda dengan Istirahatkan</a> sekarang juga.</p>
    ++
    ++<h2 id="background_optimizations">Project Svelte: Optimalisasi Latar Belakang</h2>
    ++
    ++<p>Project Svelte merupakan upaya berkelanjutan untuk meminimalkan penggunaan RAM oleh sistem dan aplikasi
    ++di semua jenis perangkat Android dalam ekosistem. Di Android N, Project
    ++Svelte berfokus pada optimalisasi cara aplikasi berjalan di latar belakang. </p>
    ++
    ++<p>Proses latar belakang merupakan bagian terpenting dari sebagian besar aplikasi. Bila ditangani dengan benar, proses
    ++ini bisa memberikan pengalaman pengguna yang mengagumkan &mdash; segera, cepat, dan sesuai konteks.
    ++Bila tidak ditangani dengan benar, proses latar belakang bisa menguras RAM (dan
    ++baterai) yang sebenarnya tidak perlu serta memengaruhi kinerja sistem untuk aplikasi lain. </p>
    ++
    ++<p>Sejak Android 5.0, {@link android.app.job.JobScheduler} telah menjadi
    ++cara yang disukai untuk melakukan pekerjaan latar belakang dengan cara yang baik
    ++bagi pengguna. Aplikasi bisa menjadwalkan pekerjaan sekaligus memungkinkan sistem mengoptimalkan berdasarkan
    ++kondisi memori, daya, dan konektivitas. JobScheduler menawarkan kontrol serta
    ++kemudahan, dan kami ingin semua aplikasi menggunakannya. </p>
    ++
    ++<p>
    ++  Opsi baik lainnya adalah <a href="https://developers.google.com/android/reference/com/google/android/gms/gcm/GcmNetworkManager">
    ++  <code>GCMNetworkManager</code></a>, bagian dari Google Play Services, yang
    ++  menawarkan penjadwalan pekerjaan serupa dengan kompatibilitas pada semua versi lawas
    ++  Android.
    ++</p>
    ++
    ++<p>Kami terus memperluas <code>JobScheduler</code> dan
    ++<code>GCMNetworkManager</code> untuk memenuhi lebih banyak
    ++kasus penggunaan Anda &mdash; misalnya, di Android N Anda sekarang bisa menjadwalkan pekerjaan
    ++latar belakang berdasarkan perubahan di Content Providers. Pada saat yang sama kami mulai
    ++menghilangkan beberapa pola lama yang bisa mengurangi kinerja sistem,
    ++terutama pada perangkat yang minim memori.</p>
    ++
    ++<p>Di Android N kami membuang tiga siaran implisit yang umum digunakan &mdash;
    ++ {@link android.net.ConnectivityManager#CONNECTIVITY_ACTION}, {@link
    ++  android.hardware.Camera#ACTION_NEW_PICTURE}, dan {@link
    ++  android.hardware.Camera#ACTION_NEW_VIDEO} &mdash; karena ketiganya bisa mengaktifkan
    ++proses latar belakang pada beberapa aplikasi sekaligus serta menguras memori dan baterai. Jika
    ++aplikasi Anda menerimanya, manfaatkan N Developer Preview untuk
    ++  beralih ke <code>JobScheduler</code> dan API terkait sebagai gantinya. </p>
    ++
    ++<p>
    ++  Lihat dokumentasi <a href="{@docRoot}preview/features/background-optimization.html">Optimalisasi
    ++  Latar Belakang</a> untuk mengetahui detailnya.
    ++</p>
    ++
    ++
    ++<h2 id="data_saver">Data Saver</h2>
    ++
    ++<div class="col-5of12" style="margin-right:1.5em;">
    ++<img src="{@docRoot}images/android-7.0/datasaver.png" style="border:2px solid #ddd">
    ++
    ++<p class="img-caption" style="padding-right:2em;">
    ++  <strong>Gambar 4.</strong> Data Saver di Settings.
    ++</p>
    ++  </div>
    ++
    ++<p>Selama penggunaan perangkat seluler, biaya paket data seluler biasanya
    ++  melebihi harga perangkat itu sendiri. Bagi banyak pengguna, data seluler adalah sumber daya
    ++mahal yang ingin mereka hemat. </p>
    ++
    ++<p>Android N memperkenalkan mode Data Saver, layanan sistem baru yang mengurangi
    ++penggunaan data seluler oleh aplikasi, baik saat roaming, mendekati akhir siklus tagihan,
    ++atau saat menggunakan paket data prabayar yang kecil. Data Saver memberi pengguna kemampuan mengontrol cara aplikasi
    ++menggunakan data seluler dan memungkinkan pengembang memberikan layanan yang lebih efisien bila Data
    ++Saver aktif. </p>
    ++
    ++<p>Bila pengguna mengaktifkan Data Saver di <strong>Settings</strong> dan perangkat
    ++dalam jaringan berkuota, sistem akan memblokir penggunaan data latar belakang dan memberi tahu aplikasi
    ++untuk menghemat penggunaan data latar depan &mdash; misalnya dengan membatasi
    ++kecepatan bit untuk streaming, mengurangi kualitas gambar, menangguhkan precaching optimistik,
    ++dan seterusnya. Pengguna bisa memasukkan aplikasi tertentu ke daftar putih untuk memungkinkan penggunaan data berkuota
    ++bila Data Saver diaktifkan.</p>
    ++
    ++<p>Android N memperluas {@link android.net.ConnectivityManager} untuk menyediakan cara pada aplikasi
    ++untuk <a href="{@docRoot}preview/features/data-saver.html#status">mengambil
    ++preferensi Data Saver pengguna</a> dan <a href="{@docRoot}preview/features/data-saver.html#monitor-changes">memantau
    ++perubahan preferensi</a>. Semua aplikasi harus memeriksa apakah pengguna telah mengaktifkan Data
    ++Saver dan berusaha membatasi penggunaan data latar belakang dan latar depan.</p>
    ++
    ++
    ++<h2 id="vulkan">Vulkan API</h2>
    ++
    ++<p>
    ++  Android N mengintegrasikan <a href="http://www.khronos.org/vulkan" class="external-link">Vulkan™</a>, sebuah API rendering 3D baru, ke dalam platform. Seperti
    ++  <a href="https://www.khronos.org/opengles/" class="external-link">OpenGL™
    ++  ES</a>, Vulkan merupakan standar terbuka untuk grafik 3D dan rendering yang dikelola
    ++  oleh Khronos Group.
    ++</p>
    ++
    ++<p>
    ++  Vulkan didesain dari nol untuk meminimalkan overhead CPU dalam driver,
    ++  dan memungkinkan aplikasi Anda mengontrol operasi GPU lebih langsung. Vulkan
    ++  juga memungkinkan paralelisasi yang lebih baik dengan mengizinkan beberapa thread menjalankan
    ++  pekerjaan seperti pembuatan buffer perintah sekaligus.
    ++</p>
    ++
    ++<p>
    ++  Pustaka dan alat pengembangan Vulkan telah dimasukkan ke dalam Android NDK. Ini
    ++  berisi:
    ++</p>
    ++
    ++<ul>
    ++  <li>Header
    ++  </li>
    ++
    ++  <li>Layer validasi (pustaka debug)
    ++  </li>
    ++
    ++  <li>SPIR-V shader compiler
    ++  </li>
    ++
    ++  <li>Pustaka kompilasi shader waktu proses SPIR-V
    ++  </li>
    ++</ul>
    ++
    ++<p>
    ++  Vulkan hanya tersedia untuk aplikasi pada perangkat dengan perangkat keras yang mendukung Vulkan,
    ++  seperti Nexus 5X, Nexus 6P, dan Nexus Player. Kami bekerja sama erat dengan mitra
    ++  agar secepatnya makin banyak perangkat yang dilengkapi Vulkan.
    ++</p>
    ++
    ++<p>
    ++  Untuk informasi selengkapnya, lihat <a href="{@docRoot}ndk/guides/graphics/index.html">dokumentasi API</a>.
    ++</p>
    ++
    ++<h2 id="tile_api">Quick Settings Tile API</h2>
    ++
    ++
    ++<div style="float:right;max-width:320px">
    ++<img src="{@docRoot}images/android-7.0/quicksettings.png" style="padding-left:1.5em;">
    ++
    ++<p class="img-caption" style="padding-left:2em;">
    ++  <strong>Gambar 5.</strong> Quick Settings Tile dalam bayangan pemberitahuan.
    ++</p>
    ++
    ++
    ++  </div><p>Quick Settings adalah cara populer dan mudah untuk mengekspos setelan dan tindakan utama,
    ++langsung dari bayangan pemberitahuan. Di Android N, kami telah memperluas lingkup
    ++Quick Settings untuk membuatnya lebih berguna dan praktis lagi. </p>
    ++
    ++<p>Kami telah menambahkan ruang lebih banyak untuk petak Quick Settings tambahan, yang bisa
    ++diakses pengguna di semua bagian area tampilan halaman bernomor dengan mengusap ke kiri atau kanan. Kami juga memberi pengguna
    ++kontrol untuk mengatur letak dan petak Quick Settings apa yang akan
    ++ditampilkan &mdash; pengguna bisa menambahkan atau memindahkan petak dengan menyeret dan melepasnya. </p>
    ++
    ++<p>Bagi pengembang, Android N juga menambahkan API baru yang memungkinkan Anda mendefinisikan
    ++  petak Quick Settings untuk memberi akses mudah kepada pengguna ke berbagai kontrol dan tindakan utama dalam aplikasi Anda.</p>
    ++
    ++<p>
    ++  Petak Quick Settings dicadangkan untuk kontrol atau tindakan yang
    ++  mendesak atau sering digunakan, dan tidak boleh digunakan sebagai pintasan untuk
    ++ membuka aplikasi.
    ++</p>
    ++
    ++<p>
    ++  Setelah mendefinisikan petak, Anda bisa menyediakannya kepada pengguna, yang bisa mereka tambahkan
    ++  ke Quick Settings cukup dengan seret dan lepas.
    ++</p>
    ++
    ++<p>
    ++  Untuk informasi tentang pembuatan petak aplikasi, lihat dokumentasi untuk
    ++  <code>android.service.quicksettings.Tile</code> dalam <a href="{@docRoot}preview/setup-sdk.html#docs-dl">Referensi API</a> yang bisa diunduh.
    ++</p>
    ++
    ++
    ++
    ++<h2 id="number-blocking">Pemblokiran Nomor</h2>
    ++
    ++<p>Android N sekarang mendukung pemblokiran nomor di platform dan menyediakan
    ++API kerangka kerja agar penyedia layanan bisa mengelola daftar nomor blokir. Aplikasi SMS
    ++default, aplikasi telepon default, dan aplikasi operator bisa membaca dari dan
    ++menulis ke daftar nomor blokir. Daftar ini tidak dapat diakses oleh aplikasi lain.</p>
    ++
    ++<p>Dengan membuat pemblokiran nomor sebagai fitur standar pada platformnya, Android menyediakan
    ++cara konsisten bagi aplikasi untuk mendukung pemblokiran nomor di berbagai
    ++perangkat. Manfaat lain yang bisa diperoleh aplikasi antara lain:</p>
    ++
    ++<ul>
    ++  <li> Nomor yang diblokir untuk panggilan juga akan diblokir untuk SMS
    ++  <li> Nomor yang diblokir tetap disimpan saat pengaturan ulang dan pada berbagai perangkat melalui fitur Backup &amp;
    ++Restore.
    ++  <li> Beberapa aplikasi sekaligus bisa menggunakan daftar nomor blokir yang sama.
    ++</ul>
    ++
    ++<p>Selain itu, dengan integrasi aplikasi operator melalui Android berarti operator bisa
    ++membaca daftar nomor blokir pada perangkat dan melakukan pemblokiran di sisi layanan
    ++bagi pengguna tersebut untuk menghentikan panggilan dan SMS yang tidak diinginkan
    ++agar tidak sampai ke pengguna lewat media apa pun, misalnya VOIP-endpoint atau meneruskan panggilan telepon.</p>
    ++
    ++<p>
    ++  Untuk informasi selengkapnya, lihat <code>android.provider.BlockedNumberContract</code>
    ++  dalam <a href="{@docRoot}preview/setup-sdk.html#docs-dl">Referensi
    ++  API</a> yang bisa diunduh.
    ++</p>
    ++
    ++<h2 id="call_screening">Penyaringan Panggilan</h2>
    ++
    ++<p>
    ++  Android N memungkinkan aplikasi telepon default untuk menyaring panggilan masuk. Aplikasi
    ++  telepon melakukannya dengan mengimplementasikan <code>CallScreeningService</code> baru,
    ++  yang memungkinkan aplikasi telepon untuk melakukan sejumlah tindakan berdasarkan
    ++  {@link android.telecom.Call.Details Call.Details} panggilan masuk, misalnya:
    ++</p>
    ++
    ++<ul>
    ++  <li> Menolak panggilan masuk
    ++  <li> Tidak mengizinkan panggilan tersebut disimpan ke log panggilan
    ++  <li> Tidak menampilkan pemberitahuan untuk panggilan tersebut kepada pengguna
    ++</ul>
    ++
    ++<p>
    ++  Untuk informasi selengkapnya, lihat <code>android.telecom.CallScreeningService</code>
    ++  dalam <a href="{@docRoot}preview/setup-sdk.html#docs-dl">Referensi
    ++  API</a> yang bisa diunduh.
    ++</p>
    ++
    ++
    ++<h2 id="multi-locale_languages">Dukungan Multilokal, Lebih Banyak Bahasa yang Didukung</h2>
    ++
    ++
    ++<p>Android N kini memungkinkan pengguna memilih <strong>banyak lokal</strong> di Settings,
    ++untuk mendukung kasus penggunaan dwibahasa dengan lebih baik. Aplikasi bisa menggunakan
    ++API baru untuk mendapatkan lokal pilihan pengguna kemudian menawarkan pengalaman pengguna
    ++yang lebih canggih untuk pengguna multilokal &mdash; seperti menampilkan hasil telusur dalam
    ++banyak bahasa dan tidak menawarkan untuk menerjemahkan halaman web dalam bahasa
    ++yang sudah diketahui pengguna.</p>
    ++
    ++<p>Bersama dukungan multilokal, Android N juga memperluas ragam bahasa
    ++yang tersedia untuk pengguna. Masing-masing ditawarkan lebih dari 25 varian untuk bahasa yang umum
    ++digunakan seperti Inggris, Spanyol, Prancis, dan Arab. Juga ditambahkan dukungan
    ++parsial untuk lebih dari 100 bahasa baru.</p>
    ++
    ++<p>Aplikasi bisa mendapatkan daftar lokal yang disetel oleh pengguna dengan memanggil
    ++<code>LocaleList.GetDefault()</code>.  Untuk mendukung jumlah lokal yang diperluas, Android N sedang
    ++ mengubah cara mengatasi masalah sumber daya. Pastikan Anda menguji dan memverifikasi bahwa aplikasi Anda
    ++berfungsi seperti yang diharapkan dengan logika resolusi sumber daya baru.</p>
    ++
    ++<p>Untuk mengetahui tentang perilaku resolusi sumber daya baru dan praktik terbaik yang
    ++harus Anda ikuti, lihat <a href="{@docRoot}preview/features/multilingual-support.html">Dukungan Multibahasa</a>.</p>
    ++
    ++
    ++<h2 id="emoji">Emoji Baru</h2>
    ++
    ++<p>
    ++  Android N memperkenalkan emoji tambahan dan fitur terkait emoji termasuk
    ++  emoji warna kulit dan dukungan untuk pemilih
    ++  variasi. Jika aplikasi Anda mendukung emoji,
    ++  ikuti panduan berikut untuk memanfaatkan fitur terkait emoji ini.
    ++</p>
    ++
    ++<ul>
    ++  <li>
    ++    <strong>Periksa apakah perangkat berisi emoji sebelum memasukannya.</strong>
    ++    Untuk memeriksa emoji mana yang terdapat di
    ++    font sistem, gunakan metode {@link android.graphics.Paint#hasGlyph(String)}.
    ++  </li>
    ++  <li>
    ++    <strong>Periksa apakah emoji mendukung pemilih variasi.</strong>
    ++    Pemilih variasi memungkinkan Anda
    ++    menampilkan emoji tertentu berwarna atau hitam-putih.
    ++    Pada perangkat seluler, aplikasi akan menghadirkan emoji berwarna daripada hitam-putih. Akan tetapi,
    ++    jika aplikasi Anda menampilkan emoji sebaris dengan teks, maka harus menggunakan variasi hitam-putih.
    ++    Untuk menentukan apakah sebuah emoji memiliki variasi, gunakan pemilih variasi.
    ++    Untuk daftar lengkap dari karakter dengan variasinya, tinjaulah bagian
    ++    <em>rangkaian variasi emoji</em> pada
    ++    <a class="external-link" href="http://www.unicode.org/Public/9.0.0/ucd/StandardizedVariants-9.0.0d1.txt">
    ++      dokumentasi Unicode mengenai variasi</a>.
    ++  </li>
    ++  <li>
    ++    <strong>Periksa apakah emoji mendukung warna kulit.</strong> Android N memungkinkan pengguna memodifikasi
    ++    warna kulit emoji yang dirender sesuai dengan preferensi mereka. Aplikasi keyboard harus menyediakan indikasi
    ++    visual untuk emoji yang memiliki beberapa warna kulit dan harus memungkinkan pengguna
    ++    memilih warna kulit yang mereka sukai. Untuk menentukan apakah emoji sistem memiliki
    ++    modifier warna kulit, gunakan metode {@link android.graphics.Paint#hasGlyph(String)}.
    ++ Anda bisa menentukan emoji mana yang menggunakan warna kulit dengan membaca
    ++    <a class="external-link" href="http://unicode.org/emoji/charts/full-emoji-list.html">
    ++     dokumentasi Unicode</a>.
    ++  </li>
    ++</ul>
    ++
    ++
    ++<h2 id="icu4">ICU4J API di Android</h2>
    ++
    ++<p>
    ++  Android N kini menawarkan subset <a href="http://site.icu-project.org/">ICU4J</a> API dalam kerangka kerja Android pada paket
    ++  <code>android.icu</code>. Migrasi mudah, dan biasanya hanya perlu
    ++  mengubah dari ruang nama <code>com.java.icu</code> ke
    ++  <code>android.icu</code>. Jika Anda sudah menggunakan bundel ICU4J dalam aplikasi,
    ++  maka beralih ke <code>android.icu</code> API yang disediakan dalam kerangka kerja
    ++  Android bisa menghasilkan penghematan besar dalam ukuran APK.
    ++</p>
    ++
    ++<p>
    ++  Untuk mengetahui selengkapnya tentang Android ICU4J API, lihat <a href="{@docRoot}preview/features/icu4j-framework.html">Dukungan ICU4J</a>.
    ++</p>
    ++
    ++
    ++
    ++<h2 id="gles_32">OpenGL&trade; ES 3.2 API</h2>
    ++
    ++<p>Android N menambahkan antarmuka kerangka kerja dan dukungan platform untuk OpenGL ES 3.2, termasuk:</p>
    ++
    ++<ul>
    ++  <li> Semua ekstensi dari <a class="external-link" href="https://www.khronos.org/registry/gles/extensions/ANDROID/ANDROID_extension_pack_es31a.txt">
    ++Android Extension Pack</a></a> (AEP) kecuali untuk <code>EXT_texture_sRGB_decode</code>.
    ++  <li> Floating-point framebuffer untuk HDR dan shading yang ditangguhkan.
    ++  <li> Panggilan draw BaseVertex agar batching dan streaming jadi lebih baik.
    ++  <li> Kontrol akses buffer yang tangguh untuk mengurangi overhead WebGL.
    ++</ul>
    ++
    ++<p>API kerangka kerja untuk OpenGL ES 3.2 di Android N dilengkapi dengan kelas
    ++  <code>GLES32</code>. Saat menggunakan OpenGL ES 3.2, pastikan
    ++mendeklarasikan persyaratan dalam file manifes Anda, dengan tag <code>&lt;uses-feature&gt;</code> dan
    ++atribut <code>android:glEsVersion</code>. </p>
    ++
    ++<p>Untuk informasi tentang menggunakan OpenGL ES, termasuk cara memeriksa versi
    ++OpenGL ES yang didukung perangkat saat waktu proses, lihat <a href="{@docRoot}guide/topics/graphics/opengl.html">Panduan OpenGL ES API</a>.</p>
    ++
    ++
    ++<h2 id="android_tv_recording">Perekaman Android TV</h2>
    ++
    ++<p>Android N menambahkan kemampuan untuk merekam dan memutar kembali materi dari layanan masukan
    ++Android TV melalui API perekaman baru.  Karena dibangun dengan API perekaman yang sudah
    ++ada, layanan masukan TV bisa mengontrol data saluran apa yang bisa direkam, cara menyimpan
    ++sesi rekaman, dan mengelola interaksi pengguna dengan materi rekaman. </p>
    ++
    ++<p>Untuk informasi selengkapnya, lihat <a href="{@docRoot}preview/features/tv-recording-api.html">API Perekaman Android TV</a>.</p>
    ++
    ++
    ++<h2 id="android_for_work">Android for Work</h2>
    ++
    ++<p>Android for Work menambahkan berbagai fitur dan API baru untuk perangkat yang menjalankan Android N.
    ++Beberapa fitur unggulannya ada di bawah ini &mdash; untuk mengetahui daftar lengkap perubahannya, lihat
    ++<a href="{@docRoot}preview/features/afw.html">Pembaruan Android for Work</a>.</p>
    ++
    ++<h3 id="work_profile_security_challenge">Pertanyaan Keamanan Profil Kerja </h3>
    ++
    ++<p>
    ++  Pemilik profil yang menargetkan N SDK
    ++  bisa menetapkan pertanyaan keamanan terpisah untuk aplikasi yang berjalan di
    ++  profil kerja. Pertanyaan kerja ditampilkan bila pengguna mencoba membuka
    ++  aplikasi kerja apa pun. Jawaban pertanyaan keamanan yang benar akan membuka
    ++  profil kerja dan mendekripsinya jika diperlukan. Untuk pemilik profil,
    ++  <code>ACTION_SET_NEW_PASSWORD</code> akan meminta pengguna untuk menetapkan pertanyaan
    ++  kerja, dan <code>ACTION_SET_NEW_PARENT_PROFILE_PASSWORD</code> meminta
    ++  pengguna menyetel kunci perangkat.
    ++</p>
    ++
    ++<p>
    ++  Pemilik profil bisa menyetel kebijakan kode sandi untuk pertanyaan kerja
    ++  (seperti berapa lama seharusnya PIN, atau apakah sidik jari bisa digunakan
    ++  untuk membuka kunci profil) menggunakan <code>setPasswordQuality()</code>,
    ++  <code>setPasswordMinimumLength()</code> dan metode terkait. Pemilik profil
    ++  juga bisa menyetel kunci perangkat, menggunakan instance <code>DevicePolicyManager</code>
    ++  yang dikembalikan oleh metode <code>getParentProfileInstance()</code>  baru.
    ++  Selain itu, pemilik profil bisa menyesuaikan layar kredensial untuk
    ++ pertanyaan kerja menggunakan metode baru <code>setOrganizationColor()</code> dan
    ++  <code>setOrganizationName()</code>.
    ++</p>
    ++<h3 id="turn_off_work">Menonaktifkan pekerjaan </h3>
    ++
    ++<p>Pada perangkat dengan profil kerja, pengguna bisa beralih mode kerja. Bila mode
    ++kerja dinonaktifkan, profil yang dikelola akan dinonaktifkan untuk sementara, yang akan menonaktifkan aplikasi
    ++profil kerja, sinkronisasi latar belakang, dan pemberitahuan. Termasuk aplikasi pemilik
    ++profil. Bila profil kerja dinonaktifkan, sistem akan menampilkan ikon status
    ++tetap untuk mengingatkan pengguna bahwa mereka tidak bisa meluncurkan aplikasi kerja. Peluncur
    ++menunjukkan bahwa aplikasi kerja dan widget tidak bisa diakses. </p>
    ++
    ++<h3 id="always_on_vpn">Always-On VPN </h3>
    ++
    ++<p>Pemilik perangkat dan pemilik profil bisa memastikan bahwa aplikasi kerja selalu menghubungkan
    ++melalui VPN yang ditetapkan. Sistem secara otomatis akan memulai VPN itu setelah booting
    ++perangkat.</p>
    ++
    ++<p>
    ++  Metode <code>DevicePolicyManager</code> baru adalah
    ++  <code>setAlwaysOnVpnPackage()</code> dan
    ++  <code>getAlwaysOnVpnPackage()</code>.
    ++</p>
    ++
    ++<p>Karena layanan VPN bisa diikat langsung oleh sistem tanpa interaksi
    ++aplikasi, klien VPN perlu menangani titik masuk baru untuk Always-On VPN. Seperti
    ++sebelumnya, layanan ditunjukkan ke sistem melalui
    ++tindakan pencocokan filter intent <code>android.net.VpnService</code>. </p>
    ++
    ++<p>
    ++  Pengguna bisa secara manual menyetel klien Always-On VPN yang mengimplementasikan
    ++  metode <code>VPNService</code> dalam pengguna utama dengan menggunakan
    ++  <strong>Settings&gt;More&gt;Vpn</strong>.
    ++</p>
    ++
    ++<h3 id="custom_provisioning">Penyediaan yang disesuaikan</h3>
    ++
    ++<p>
    ++  Aplikasi bisa menyesuaikan alur penyediaan pemilik profil dan pemilik perangkat
    ++  dengan warna dan logo perusahaan.
    ++  <code>DevicePolicyManager.EXTRA_PROVISIONING_MAIN_COLOR</code> menyesuaikan
    ++  warna alur. <code>DevicePolicyManager.EXTRA_PROVISIONING_LOGO_URI</code>
    ++  menyesuaikan alur dengan logo perusahaan.
    ++</p>
    ++
    ++<h2 id="accessibility_enhancements">Penyempurnaan Aksesibilitas</h2>
    ++
    ++<p>Android N saat ini menawarkan Vision Settings langsung di layar Sambutan untuk
    ++persiapan perangkat baru. Ini sangat memudahkan pengguna untuk menemukan dan mengonfigurasi
    ++fitur aksesibilitas pada perangkat mereka, termasuk isyarat perbesaran, ukuran
    ++font, ukuran layar, dan TalkBack. </p>
    ++
    ++<p>Dengan fitur aksesibilitas yang penempatannya semakin jelas, pengguna Anda
    ++kemungkinan besar akan mencoba aplikasi dengan fitur-fitur yang diaktifkan itu. Pastikan Anda menguji aplikasi
    ++lebih dini dengan mengaktifkan dahulu setelan ini. Anda bisa mengaktifkannya dari Settings &gt;
    ++Accessibility.</p>
    ++
    ++<p>Di Android N, layanan aksesibilitas sekarang bisa membantu pengguna yang mengalami gangguan
    ++motorik untuk menyentuh layar. API baru memungkinkan membangun layanan dengan
    ++fitur-fitur seperti pelacakan wajah, pelacakan mata, pemindaian titik, dan seterusnya, untuk
    ++memenuhi kebutuhan para pengguna tersebut.</p>
    ++
    ++<p>Untuk informasi selengkapnya, lihat <code>android.accessibilityservice.GestureDescription</code>
    ++ dalam <a href="{@docRoot}preview/setup-sdk.html#docs-dl">Referensi  API</a> yang bisa diunduh.</p>
    ++
    ++
    ++<h2 id="direct_boot">Direct Boot</h2>
    ++
    ++<p>Direct Boot memperbaiki waktu startup perangkat dan memungkinkan aplikasi
    ++yang telah didaftarkan memiliki fungsionalitas terbatas bahkan setelah boot ulang tak terduga.
    ++Misalnya, jika perangkat yang dienkripsi melakukan boot ulang selagi pengguna tidur,
    ++alarm terdaftar, pesan dan panggilan masuk sekarang bisa terus memberi tahu
    ++pengguna seperti biasa. Ini juga berarti layanan aksesibilitas bisa
    ++  segera tersedia setelah restart.</p>
    ++
    ++<p>Direct Boot memanfaatkan enkripsi berbasis file di Android N
    ++untuk mengaktifkan kebijakan enkripsi yang telah disesuaikan bagi sistem dan data aplikasi.
    ++Sistem akan menggunakan penyimpanan yang dienkripsi dengan perangkat untuk data sistem terpilih dan data
    ++aplikasi yang terdaftar secara eksplisit. Secara default, penyimpanan yang dienkripsi dengan kredensial digunakan untuk semua
    ++  data sistem lainnya, data pengguna, aplikasi, dan data aplikasi. </p>
    ++
    ++<p>Saat booting, sistem dimulai dalam mode terbatas dengan akses
    ++ke data yang dienkripsi dengan perangkat saja, dan tanpa akses umum ke aplikasi atau data.
    ++Jika Anda memiliki komponen yang ingin Anda jalankan dalam mode ini, Anda bisa mendaftarkannya
    ++dengan menyetel flag dalam manifes. Setelah restart, sistem akan mengaktifkan
    ++komponen terdaftar dengan menyiarkan intent <code>LOCKED_BOOT_COMPLETED</code>.
    ++ Sistem akan memastikan data aplikasi yang dienkripsi dengan perangkat tersedia
    ++sebelum membuka kunci. Semua data lainnya tidak tersedia sebelum Pengguna mengonfirmasi
    ++  kredensial layar kunci mereka untuk mendekripsinya. </p>
    ++
    ++Untuk informasi selengkapnya, lihat <a href="{@docRoot}preview/features/direct-boot.html">Direct Boot</a>.</p>
    ++</p>
    ++
    ++
    ++<h2 id="key_attestation">Key Attestation</h2>
    ++
    ++<p>Keystore yang didukung perangkat keras menyediakan metode yang jauh lebih aman untuk membuat, menyimpan,
    ++dan menggunakan kunci kriptografi pada perangkat Android. Keystore itu melindungi kunci dari
    ++kernel Linux, potensi kerentanan Android, dan ekstraksi
    ++dari perangkat yang di-root.</p>
    ++
    ++<p>Agar lebih mudah dan lebih aman dalam menggunakan keystore yang didukung perangkat keras,
    ++Android N memperkenalkan Key Attestation. Aplikasi dan perangkat-nonaktif bisa menggunakan Key
    ++Attestation untuk menentukan apakah penyandingan kunci RSA atau EC
    ++didukung perangkat keras, apa properti dari penyandingan kunci, dan batasan
    ++  apa yang diterapkan terhadap penggunaan dan validitasnya. </p>
    ++
    ++<p>Aplikasi dan layanan perangkat-nonaktif bisa meminta informasi tentang penyandingan kunci
    ++melalui sertifikat pengesahan X.509 yang harus ditandatangani dengan kunci
    ++pengesahan yang valid. Kunci pengesahan adalah kunci penandatanganan ECDSA yang
    ++telah diinjeksikan ke dalam keystore yang didukung perangkat keras pada perangkat saat di pabriknya.
    ++Karena itu, sertifikat pengesahan yang ditandatangani oleh kunci pengesahan yang
    ++valid akan mengonfirmasi keberadaan keystore yang didukung perangkat keras, bersama
    ++  detail pasangan kunci dalam keystore itu.</p>
    ++
    ++<p>Untuk memastikan perangkat ini menggunakan citra Android resmi yang
    ++aman dari pabrik, Key Attestation mengharuskan <a class="external-link" href="https://source.android.com/security/verifiedboot/verified-boot.html#bootloader_requirements">bootloader</a> perangkat
    ++menyediakan informasi berikut pada <a class="external-link" href="https://source.android.com/security/trusty/index.html">Trusted
    ++Execution Environment (TEE)</a>:</p>
    ++
    ++<ul>
    ++<li>Versi OS dan level patch yang dipasang pada perangkat</li>
    ++<li>Kunci publik <a href="https://source.android.com/security/verifiedboot/index.html" class="external-link">Verified Boot</a> dan status kunci</li>
    ++  </ul>
    ++
    ++<p>Untuk informasi selengkapnya tentang fitur keystore yang didukung perangkat keras,
    ++lihat panduan untuk <a href="https://source.android.com/security/keystore/" class="external-link">Keystore yang Didukung Perangkat Keras</a>.</p>
    ++
    ++<p>Selain Key Attestation, Android N juga memperkenalkan
    ++  kunci yang terikat sidik jari yang tidak dipanggil saat pendaftaran sidik jari.</p>
    ++
    ++<h2 id="network_security_config">Network Security Config</h2>
    ++
    ++<p>Di Android N, aplikasi bisa menyesuaikan perilaku koneksi aman mereka
    ++(HTTPS, TLS) secara aman, tanpa modifikasi kode, dengan menggunakan
    ++<em>Network Security Config</em> deklaratif sebagai ganti menggunakan API programatik
    ++konvensional yang rawan kesalahan (mis. X509TrustManager).</p>
    ++
    ++  <p>Fitur yang didukung:</p>
    ++<ul>
    ++<li><b>Trust-anchor khusus.</b> Memungkinkan aplikasi menyesuaikan
    ++Certificate Authorities (CA) mana yang dipercaya untuk koneksi amannya. Misalnya,
    ++mempercayai sertifikat tertentu yang ditandatangani sendiri atau set CA publik yang dibatasi.
    ++</li>
    ++<li><b>Penggantian hanya-debug.</b> Memungkinkan pengembang aplikasi dengan aman men-debug
    ++koneksi aman aplikasi mereka tanpa menambah risiko pada basis yang sudah
    ++dipasang.
    ++</li>
    ++<li><b>Berhenti dari lalu lintas cleartext.</b> Memungkinkan aplikasi melindungi dirinya sendiri dari
    ++penggunaan lalu lintas cleartext yang tidak disengaja.</li>
    ++<li><b>Penyematan sertifikat.</b> Sebuah fitur canggih yang memungkinkan aplikasi
    ++  membatasi kunci server mana yang dipercaya untuk koneksi aman.</li>
    ++</ul>
    ++
    ++<p>Untuk informasi selengkapnya, lihat <a href="{@docRoot}preview/features/security-config.html">Network Security
    ++Config</a>.</p>
    ++
    ++<h2 id="default_trusted_ca">Certificate Authority Tepercaya Default</h2>
    ++
    ++<p>Secara default, aplikasi yang menargetkan Android N hanya mempercayai sertifikat yang disediakan sistem
    ++dan tidak lagi mempercayai Certificate Authorities (CA) yang ditambahkan pengguna. Aplikasi yang menargetkan Android
    ++N dan ingin mempercayai CA yang ditambahkan pengguna harus menggunakan
    ++<a href="{@docRoot}preview/features/security-config.html">Network Security Config</a> untuk
    ++menetapkan cara mempercayai CA pengguna.</p>
    ++
    ++<h2 id="apk_signature_v2">APK Signature Scheme v2</h2>
    ++
    ++<p>
    ++  Android N memperkenalkan APK Signature Scheme v2, sebuah skema penandatanganan aplikasi baru yang
    ++  menawarkan waktu pasang aplikasi lebih cepat dan lebih banyak perlindungan terhadap perubahan
    ++ tidak sah pada file APK. Secara default, Android Studio 2.2 dan Android
    ++  Plugin untuk Gradle 2.2 menandatangani aplikasi Anda menggunakan APK Signature Scheme v2 dan
    ++  skema penandatanganan tradisional, yang menggunakan penandatanganan JAR.
    ++</p>
    ++
    ++<p>
    ++  Meskipun kami menyarankan untuk menerapkan APK Signature Scheme v2 pada aplikasi Anda, skema
    ++  baru ini tidak wajib. Jika aplikasi Anda tidak dibangun dengan benar saat menggunakan APK
    ++  Signature Scheme v2, Anda bisa menonaktifkan skema baru ini. Proses penonaktifan
    ++  menyebabkan Android Studio 2.2 dan Android Plugin untuk Gradle 2.2 menandatangani aplikasi Anda
    ++  menggunakan skema penandatanganan tradisional saja. Untuk menandatangani dengan
    ++ skema tradisional saja, buka file <code>build.gradle</code> level-modul, kemudian
    ++  tambahkan baris <code>v2SigningEnabled false</code> ke konfigurasi
    ++  penandatanganan rilis Anda:
    ++</p>
    ++
    ++<pre>
    ++  android {
    ++    ...
    ++    defaultConfig { ... }
    ++    signingConfigs {
    ++      release {
    ++        storeFile file("myreleasekey.keystore")
    ++        storePassword "password"
    ++        keyAlias "MyReleaseKey"
    ++        keyPassword "password"
    ++        <strong>v2SigningEnabled false</strong>
    ++      }
    ++    }
    ++  }
    ++</pre>
    ++
    ++<p class="caution"><strong>Perhatian: </strong> Jika Anda menandatangani aplikasi menggunakan APK
    ++  Signature Scheme v2 dan membuat perubahan lebih jauh pada aplikasi, tanda tangan aplikasi
    ++  menjadi tidak valid. Untuk alasan ini, gunakan alat seperti <code>zipalign</code>
    ++  sebelum menandatangani aplikasi Anda menggunakan APK Signature Scheme v2, bukan setelahnya.
    ++</p>
    ++
    ++<p>
    ++  Untuk informasi selengkapnya, baca dokumen Android Studio yang menjelaskan cara
    ++  <a href="{@docRoot}studio/publish/app-signing.html#release-mode">
    ++  menandatangani aplikasi</a> di Android Studio dan cara<a href="{@docRoot}studio/build/build-variants.html#signing"> mengonfigurasi
    ++  file build untuk menandatangani aplikasi</a> menggunakan Android Plugin untuk Gradle.
    ++</p>
    ++
    ++<h2 id="scoped_directory_access">Scoped Directory Access</h2>
    ++
    ++<p>Di Android N, aplikasi bisa menggunakan API baru untuk meminta akses ke direktori <a href="{@docRoot}guide/topics/data/data-storage.html#filesExternal">penyimpanan
    ++eksternal</a> tertentu, termasuk direktori di media lepas-pasang seperti kartu
    ++SD. API baru ini sangat menyederhanakan cara aplikasi Anda mengakses direktori
    ++penyimpanan eksternal standar, seperti direktori <code>Pictures</code>. Aplikasi
    ++seperti aplikasi foto bisa menggunakan API ini sebagai ganti menggunakan
    ++<code>READ_EXTERNAL_STORAGE</code>, yang memberikan akses ke semua direktori
    ++penyimpanan, atau Storage Access Framework, yang membuat pengguna mengarah ke
    ++direktori tersebut.</p>
    ++
    ++<p>Selain itu, API baru ini menyederhanakan langkah-langkah yang diambil pengguna untuk memberikan akses
    ++penyimpanan eksternal ke aplikasi Anda. Bila Anda menggunakan API baru, sistem akan menggunakan UI izin
    ++sederhana yang memperinci dengan jelas direktori apa yang aksesnya diminta
    ++oleh aplikasi.</p>
    ++
    ++<p>Untuk informasi selengkapnya, lihat dokumentasi pengembang
    ++<a href="{@docRoot}preview/features/scoped-folder-access.html">Scoped
    ++Directory Access</a>.</p>
    ++
    ++<h2 id="keyboard_shortcuts_helper">Keyboard Shortcuts Helper</h2>
    ++
    ++<p>
    ++Di Android N, pengguna bisa menekan "Alt + /" untuk memunculkan layar <em>Keyboard Shortcuts</em>
    ++yang menampilkan semua pintasan yang tersedia baik dari sistem maupun dari
    ++aplikasi yang sedang mendapatkan fokus. Ini diambil secara otomatis dari menu aplikasi
    ++jika tersedia, namun pengembang bisa menyediakan daftar pintasan yang telah disesuaikan
    ++untuk layar. Anda bisa melakukannya dengan mengganti metode
    ++<code>Activity.onProvideKeyboardShortcuts()</code> baru, yang dijelaskan dalam
    ++<a href="{@docRoot}preview/setup-sdk.html#docs-dl">Referensi API</a> yang bisa diunduh.
    ++</p>
    ++
    ++<p>
    ++Untuk memunculkan Keyboard Shortcuts Helper dari mana saja di aplikasi Anda,
    ++panggil {@code Activity.requestKeyboardShortcutsHelper()} untuk aktivitas terkait.
    ++</p>
    ++
    ++<h2 id="sustained_performance_api">Sustained Performance API</h2>
    ++
    ++<p>
    ++Kinerja bisa berfluktuasi secara dramatis untuk aplikasi yang berjalan lama, karena
    ++sistem melakukan throttle pada mesin sistem-di-chip saat komponen perangkat mencapai
    ++batas suhunya. Fluktuasi ini memberikan target bergerak bagi pengembang
    ++aplikasi yang sedang membuat aplikasi berkinerja tinggi dan berjalan lama.
    ++</p>
    ++
    ++<p>
    ++Untuk menangani batasan ini, Android N menyertakan dukungan untuk
    ++<em>mode kinerja kontinu</em>, yang memungkinkan OEM memberikan petunjuk mengenai kemampuan kinerja
    ++perangkat untuk aplikasi yang berjalan lama. Pengembang aplikasi
    ++bisa menggunakan petunjuk ini untuk menyesuaikan aplikasi agar kinerja perangkat bisa diprediksi
    ++dan pada level yang konsisten dalam jangka waktu lama.
    ++</p>
    ++
    ++<p>
    ++Pengembang aplikasi bisa mencoba API baru ini dalam N Developer Preview pada
    ++perangkat Nexus 6P saja. Untuk menggunakan fitur ini,
    ++setel flag jendela kinerja kontinu
    ++yang ingin Anda jalankan dalam mode kinerja kontinu. Setel flag ini menggunakan metode
    ++{@code Window.setSustainedPerformanceMode()}. Sistem secara otomatis
    ++akan menonaktifkan mode ini bila jendela tidak lagi mendapatkan fokus.
    ++</p>
    ++
    ++<h2 id="vr">Dukungan VR</h2>
    ++
    ++<p>
    ++Android N menambahkan dukungan platform dan optimalisasi untuk VR Mode baru yang memungkinkan
    ++pengembang membuat pengalaman VR berkualitas tinggi di seluler bagi para pengguna. Ada banyak perbaikan
    ++kinerja, termasuk akses ke inti CPU yang eksklusif untuk aplikasi VR.
    ++Di dalam aplikasi, Anda bisa memanfaatkan pelacakan kepala yang cerdas,
    ++dan pemberitahuan stereo yang bekerja untuk VR. Hal terpenting adalah Android N menyediakan
    ++grafis dengan latensi sangat rendah. Untuk informasi selengkapnya tentang membangun aplikasi VR untuk Android N,
    ++lihat <a href="https://developers.google.com/vr/android/">Google VR SDK untuk Android</a>.
    ++</p>
    ++
    ++
    ++<h2 id="print_svc">Penyempurnaan Layanan Cetak</h2>
    ++
    ++<p>
    ++  Di Android N, pengembang layanan cetak kini bisa menampilkan informasi tambahan
    ++  tentang masing-masing printer dan pekerjaan cetak.
    ++</p>
    ++
    ++<p>
    ++  Saat mendaftarkan masing-masing printer, layanan cetak kini bisa menyetel
    ++  ikon per printer dalam dua cara:
    ++</p>
    ++
    ++<ul>
    ++  <li>Anda bisa menyetel ikon dari ID sumber daya dengan memanggil
    ++  <code>PrinterInfo.Builder.setResourceIconId()</code>
    ++  </li>
    ++
    ++  <li>Anda bisa menampilkan ikon dari jaringan dengan memanggil
    ++  <code>PrinterInfo.Builder.setHasCustomPrinterIcon()</code>, dan menyetel sebuah
    ++ callback bila ikon diminta menggunakan
    ++  <code>android.printservice.PrinterDiscoverySession.onRequestCustomPrinterIcon()</code>
    ++  </li>
    ++</ul>
    ++
    ++<p>
    ++  Selain itu, Anda bisa menyediakan aktivitas per printer untuk menampilkan informasi
    ++  tambahan dengan memanggil <code>PrinterInfo.Builder.setInfoIntent()</code>.
    ++</p>
    ++
    ++<p>
    ++  Anda bisa menunjukkan kemajuan dan status pekerjaan cetak di
    ++  pemberitahuan pekerjaan cetak dengan memanggil masing-masing
    ++  <code>android.printservice.PrintJob.setProgress()</code> dan
    ++  <code>android.printservice.PrintJob.setStatus()</code>.
    ++</p>
    ++
    ++<p>
    ++  Untuk informasi selengkapnya tentang metode ini,lihat  dalam <a href="{@docRoot}preview/setup-sdk.html#docs-dl">Referensi  API</a> yang bisa diunduh.
    ++</p>
    ++
    ++<h2 id="framemetrics_api">FrameMetricsListener API</h2>
    ++
    ++<p>
    ++FrameMetricsListener API memungkinkan aplikasi untuk memantau
    ++kinerja rendering UI. API tersebut menyediakan kemampuan ini dengan mengekspos Pub/Sub API streaming
    ++untuk mentransfer info frame-timing untuk jendela aplikasi saat ini. Data yang dikembalikan
    ++setara dengan yang ditampilkan <code><a href="{@docRoot}tools/help/shell.html#shellcommands">adb shell</a>
    ++dumpsys gfxinfo framestats</code>, namun tidak dibatasi pada 120 bingkai.
    ++</p>
    ++
    ++<p>
    ++Anda bisa menggunakan FrameMetricsListener untuk mengukur kinerja UI
    ++level interaksi di produksi, tanpa koneksi USB. API
    ++ini memungkinkan pengumpulan data dengan granularitas lebih tinggi daripada
    ++{@code adb shell dumpsys gfxinfo}. Granularitas lebih tinggi ini dimungkinkan karena
    ++sistem bisa mengumpulkan data untuk interaksi tertentu di aplikasi; sistem
    ++tidak perlu merekam ringkasan global untuk keseluruhan kinerja
    ++aplikasi, atau mengosongkan status global yang ada. Anda bisa menggunakan kemampuan ini
    ++untuk mengumpulkan data kinerja dan menangkap regresi di kinerja UI
    ++untuk kasus penggunaan sungguhan di dalam aplikasi.
    ++</p>
    ++
    ++<p>
    ++Untuk memantau sebuah jendela, implementasikan metode callback <code>FrameMetricsListener.onMetricsAvailable()</code>
    ++dan daftarkan di jendela itu. Untuk informasi selengkapnya, lihat
    ++dokumentasi kelas {@code FrameMetricsListener} di
    ++<a href="{@docRoot}preview/setup-sdk.html#docs-dl">Referensi API</a> yang bisa diunduh.
    ++</p>
    ++
    ++<p>
    ++API menyediakan objek {@code FrameMetrics}, yang berisi data timing yang
    ++dilaporkan subsistem rendering untuk berbagai tahap pencapaian dalam daur hidup bingkai.
    ++Metrik yang didukung adalah: {@code UNKNOWN_DELAY_DURATION},
    ++{@code INPUT_HANDLING_DURATION}, {@code ANIMATION_DURATION},
    ++{@code LAYOUT_MEASURE_DURATION}, {@code DRAW_DURATION}, {@code SYNC_DURATION},
    ++{@code COMMAND_ISSUE_DURATION}, {@code SWAP_BUFFERS_DURATION},
    ++{@code TOTAL_DURATION}, dan {@code FIRST_DRAW_FRAME}.
    ++</p>
    ++
    ++
    ++<h2 id="virtual_files">File Maya</h2>
    ++
    ++<p>
    ++  Di versi Android sebelumnya, aplikasi Anda bisa menggunakan Storage Access
    ++  Framework untuk memungkinkan pengguna memilih file dari akun penyimpanan awan mereka,
    ++  seperti Google Drive. Akan tetapi, tidak ada cara untuk merepresentasikan file yang
    ++  tidak memiliki representasi bytecode langsung; setiap file diharuskan menyediakan
    ++  aliran masukan.
    ++</p>
    ++
    ++<p>
    ++  Android N menambahkan konsep <em>file maya</em> pada Storage Access
    ++  Framework. Fitur file maya memungkinkan
    ++  {@link android.provider.DocumentsProvider} Anda mengembalikan URI dokumen yang bisa
    ++  digunakan bersama intent {@link android.content.Intent#ACTION_VIEW} sekalipun
    ++  tidak memiliki representasi bytecode langsung. Android N juga memungkinkan Anda untuk
    ++  menyediakan format alternatif untuk file pengguna, maya atau dengan cara lain.
    ++</p>
    ++
    ++<p>
    ++  Untuk mendapatkan URI sebuah dokumen maya di aplikasi Anda, terlebih dahulu Anda membuat
    ++  {@link android.content.Intent} untuk membuka UI pemilih file. Karena aplikasi
    ++  tidak bisa membuka file maya secara langsung dengan menggunakan metode
    ++  {@link android.content.ContentResolver#openInputStream(Uri) openInputStream()},
    ++   aplikasi Anda tidak akan menerima file maya jika Anda memasukkan kategori
    ++  {@link android.content.Intent#CATEGORY_OPENABLE}.
    ++</p>
    ++
    ++<p>
    ++  Setelah pengguna menentukan pilihan, sistem akan memanggil metode
    ++  {@link android.app.Activity#onActivityResult onActivityResult()}.
    ++  Aplikasi Anda bisa mengambil URI file maya dan mendapatkan aliran masukan, seperti yang
    ++  diperagakan dalam cuplikan kode di bawah.
    ++</p>
    ++
    ++<pre>
    ++  // Other Activity code ...
    ++
    ++  final static private int REQUEST_CODE = 64;
    ++
    ++  // We listen to the OnActivityResult event to respond to the user's selection.
    ++  &#64;Override
    ++  public void onActivityResult(int requestCode, int resultCode,
    ++    Intent resultData) {
    ++      try {
    ++        if (requestCode == REQUEST_CODE &amp;&amp;
    ++            resultCode == Activity.RESULT_OK) {
    ++
    ++            Uri uri = null;
    ++
    ++            if (resultData != null) {
    ++                uri = resultData.getData();
    ++
    ++                ContentResolver resolver = getContentResolver();
    ++
    ++                // Before attempting to coerce a file into a MIME type,
    ++                // check to see what alternative MIME types are available to
    ++                // coerce this file into.
    ++                String[] streamTypes =
    ++                  resolver.getStreamTypes(uri, "*/*");
    ++
    ++                AssetFileDescriptor descriptor =
    ++                    resolver.openTypedAssetFileDescriptor(
    ++                        uri,
    ++                        streamTypes[0],
    ++                        null);
    ++
    ++                // Retrieve a stream to the virtual file.
    ++                InputStream inputStream = descriptor.createInputStream();
    ++            }
    ++        }
    ++      } catch (Exception ex) {
    ++        Log.e("EXCEPTION", "ERROR: ", ex);
    ++      }
    ++  }
    ++</pre>
    ++
    ++<p>
    ++  Untuk informasi selengkapnya tentang mengakses file pengguna, lihat
    ++  <a href="{@docRoot}guide/topics/providers/document-provider.html">Panduan Storage
    ++  Access Frameworks</a>.
    ++</p>
    +diff --git a/docs/html-intl/intl/id/about/versions/nougat/index.jd b/docs/html-intl/intl/id/about/versions/nougat/index.jd
    +new file mode 100644
    +index 0000000..212870a
    +--- /dev/null
    ++++ b/docs/html-intl/intl/id/about/versions/nougat/index.jd
    +@@ -0,0 +1,110 @@
    ++page.title=Android 7.0 Nougat
    ++page.tags="androidn","versions"
    ++meta.tags="android n", "nougat", "android 7.0"
    ++fullpage=true
    ++forcelocalnav=true
    ++header.hide=1
    ++footer.hide=1
    ++@jd:body
    ++
    ++<section class="dac-expand dac-hero dac-light">
    ++  <div class="wrap" style="max-width:1100px;margin-top:0">
    ++  <a href="{@docRoot}about/versions/nougat/android-7.0.html">
    ++    <div class="cols dac-hero-content" style="padding-bottom:1em;">
    ++
    ++      <div class="col-7of16 col-push-8of16" style="padding-left:2em">
    ++        <h1 class="dac-hero-title">Android 7.0 Nougat</h1>
    ++        <p class="dac-hero-description">
    ++          Bersiaplah menyambut Android Nougat!
    ++          <strong>Uji aplikasi Anda</strong> pada perangkat Nexus dan perangkat lainnya. Dukung perilaku sistem
    ++          baru untuk <strong>menghemat daya dan memori</strong>.
    ++          Tambah aplikasi Anda dengan <strong>UI multi-jendela</strong>,
    ++          <strong>pemberitahuan balasan langsung</strong> dan lainnya.
    ++        </p>
    ++
    ++        <a class="dac-hero-cta" href="{@docRoot}about/versions/nougat/android-7.0.html">
    ++          <span class="dac-sprite dac-auto-chevron"></span>
    ++          Mulai
    ++        </a>
    ++      </div>
    ++      <div class="col-7of16 col-pull-6of16 dac-hero-figure" style="margin-top:1.5em;padding-right:1.5em;">
    ++        <a  href="{@docRoot}about/versions/nougat/android-7.0.html">
    ++        <img class="dac-hero-image" src="{@docRoot}images/home/n-preview-hero.png"
    ++             srcset="{@docRoot}images/home/n-preview-hero.png 1x,
    ++             {@docRoot}images/home/n-preview-hero_2x.png 2x" />
    ++           </a>
    ++      </div>
    ++    </div></a>
    ++    <div class="dac-section dac-small">
    ++      <div class="resource-widget resource-flow-layout col-16"
    ++           data-query="collection:nougat/landing/resources"
    ++           data-cardSizes="6x2"
    ++           data-maxResults="3"></div>
    ++         </div>
    ++  </div>
    ++</section>
    ++
    ++
    ++<div class="dac-section dac-slim dac-gray dac-expand">
    ++  <div class="wrap dac-offset-parent">
    ++    <a class="dac-fab dac-scroll-button" data-scroll-button href="#latest">
    ++      <i class="dac-sprite dac-arrow-down-gray"></i>
    ++    </a>
    ++    <ul class="dac-actions">
    ++      <li class="dac-action">
    ++        <a class="dac-action-link" href="https://source.android.com/source/report-bugs.html">
    ++          <i class="dac-action-sprite dac-sprite dac-auto-chevron-large"></i>
    ++          Laporkan masalah
    ++        </a>
    ++      </li>
    ++      <li class="dac-action">
    ++        <a class="dac-action-link" href="{@docRoot}preview/dev-community">
    ++          <i class="dac-action-sprite dac-sprite dac-auto-chevron-large"></i>
    ++          Bergabunglah dengan komunitas pengembang
    ++        </a>
    ++      </li>
    ++    </ul>
    ++  </div><!-- end .wrap -->
    ++</div><!-- end .dac-actions -->
    ++
    ++<section class="dac-section dac-light dac-small" id="latest"><div class="wrap">
    ++  <h2 class="norule">Terbaru</h2>
    ++  <div class="resource-widget resource-flow-layout col-16"
    ++    data-query="type:blog+tag:androidn+tag:featured, type:youtube+tag:androidn+tag:featured"
    ++    data-sortOrder="-timestamp"
    ++    data-cardSizes="6x6"
    ++    data-items-per-page="6"
    ++    data-maxResults="15"
    ++    data-initial-results="3"></div>
    ++</div></section>
    ++
    ++<section class="dac-section dac-gray" id="videos"><div class="wrap">
    ++  <h1 class="dac-section-title">Videos</h1>
    ++  <div class="dac-section-subtitle">
    ++    New Android capabilities and the right way to use them in your apps.
    ++  </div>
    ++
    ++  <div class="resource-widget resource-flow-layout col-16"
    ++    data-query="collection:nougat/landing/videos/first,type:youtube+tag:androidn"
    ++    data-sortOrder="-timestamp"
    ++    data-cardSizes="6x6"
    ++    data-items-per-page="6"
    ++    data-maxResults="15"
    ++    data-initial-results="3">
    ++  </div>
    ++</div></section>
    ++
    ++<section class="dac-section dac-light" id="resources"><div class="wrap">
    ++  <h1 class="dac-section-title">Sumber Daya</h1>
    ++  <div class="dac-section-subtitle">
    ++    Informasi penting guna membantu mempersiapkan aplikasi untuk Android Nougat.
    ++  </div>
    ++
    ++  <div class="resource-widget resource-flow-layout col-16"
    ++       data-query="collection:nougat/landing/more"
    ++       data-cardSizes="6x6"
    ++       data-items-per-page="6"
    ++       data-maxResults="15"
    ++       data-initial-results="6"></div>
    ++  </div>
    ++</section>
    +\ No newline at end of file
    +diff --git a/docs/html-intl/intl/id/design/get-started/principles.jd b/docs/html-intl/intl/id/design/get-started/principles.jd
    +new file mode 100644
    +index 0000000..2a1d194
    +--- /dev/null
    ++++ b/docs/html-intl/intl/id/design/get-started/principles.jd
    +@@ -0,0 +1,307 @@
    ++page.title=Prinsip Desain Android
    ++@jd:body
    ++
    ++<p>Prinsip desain ini dikembangkan oleh dan untuk Tim Pengalaman Pengguna
    ++ Android agar selalu mempertimbangkan kepentingan pengguna.
    ++Untuk pengembang dan desainer Android, mereka terus
    ++meletakkan dasar pedoman desain yang lebih detail untuk beragam tipe
    ++perangkat.</p>
    ++
    ++<p>
    ++Perhatikan prinsip-prinsip ini saat Anda menerapkan
    ++kreativitas dan pemikiran desain sendiri. Menyimpang dengan sengaja.
    ++</p>
    ++
    ++<h2 id="enchant-me">Pikat Saya</h2>
    ++
    ++<div class="cols">
    ++  <div class="col-7">
    ++
    ++<h4 id="delight-me">Senangkan saya dengan cara yang mengejutkan</h4>
    ++<p>Permukaan yang cantik, animasi yang ditempatkan dengan hati-hati, atau efek suara di saat yang tepat sungguh menyenangkan untuk
    ++dinikmati. Efek yang lembut menimbulkan perasaan serba mudah dan kesadaran bahwa kekuatan yang
    ++bisa diandalkan ada dalam genggaman.</p>
    ++
    ++  </div>
    ++  <div class="col-6">
    ++
    ++    <img src="{@docRoot}design/media/principles_delight.png">
    ++
    ++  </div>
    ++</div>
    ++
    ++<div class="vspace size-2">&nbsp;</div>
    ++
    ++<div class="cols">
    ++  <div class="col-7">
    ++
    ++<h4 id="real-objects-more-fun">Objek sungguhan lebih menyenangkan daripada tombol dan menu</h4>
    ++<p>Biarkan orang langsung menyentuh dan memanipulasi objek dalam aplikasi Anda. Ini mengurangi upaya kognitif
    ++yang diperlukan untuk menjalankan tugas sekaligus membuatnya lebih memuaskan secara emosional.</p>
    ++
    ++  </div>
    ++  <div class="col-6">
    ++
    ++    <img src="{@docRoot}design/media/principles_real_objects.png">
    ++
    ++  </div>
    ++</div>
    ++
    ++<div class="vspace size-2">&nbsp;</div>
    ++
    ++<div class="cols">
    ++  <div class="col-7">
    ++
    ++<h4 id="make-it-mine">Biarkan saya memilikinya</h4>
    ++<p>Orang suka menambahkan sentuhan pribadi karena membantu mereka merasa betah dan memegang kendali. Memberikan
    ++default yang pantas dan indah, tetapi juga mempertimbangkan penyesuaian opsional yang menyenangkan, yang tidak mengganggu
    ++tugas utama.</p>
    ++
    ++  </div>
    ++  <div class="col-6">
    ++
    ++    <img src="{@docRoot}design/media/principles_make_it_mine.png">
    ++
    ++  </div>
    ++</div>
    ++
    ++<div class="vspace size-2">&nbsp;</div>
    ++
    ++<div class="cols">
    ++  <div class="col-7">
    ++
    ++<h4 id="get-to-know-me">Kenali saya</h4>
    ++<p>Pelajari preferensi orang dari waktu ke waktu. Daripada meminta mereka untuk membuat pilihan yang sama
    ++berulang-ulang, tempatkan pilihan sebelumnya agar mudah dijangkau.</p>
    ++
    ++  </div>
    ++  <div class="col-6">
    ++
    ++    <img src="{@docRoot}design/media/principles_get_to_know_me.png">
    ++
    ++  </div>
    ++</div>
    ++
    ++<h2 id="simplify-my-life">Sederhanakan Hidup Saya</h2>
    ++
    ++<div class="cols">
    ++  <div class="col-7">
    ++
    ++<h4 id="keep-it-brief">Persingkat</h4>
    ++<p>Gunakan frasa pendek dengan kata-kata sederhana. Orang cenderung melewatkan kalimat-kalimat panjang.</p>
    ++
    ++  </div>
    ++  <div class="col-6">
    ++
    ++    <img src="{@docRoot}design/media/principles_keep_it_brief.png">
    ++
    ++  </div>
    ++</div>
    ++
    ++<div class="vspace size-2">&nbsp;</div>
    ++
    ++<div class="cols">
    ++  <div class="col-7">
    ++
    ++<h4 id="pictures-faster-than-words">Gambar lebih cepat dibanding kata-kata</h4>
    ++<p>Pertimbangkan menggunakan gambar untuk menjelaskan gagasan. Gambar menarik perhatian orang dan bisa jauh lebih efisien
    ++dibanding kata-kata.</p>
    ++
    ++  </div>
    ++  <div class="col-6">
    ++
    ++    <img src="{@docRoot}design/media/principles_pictures.png">
    ++
    ++  </div>
    ++</div>
    ++
    ++<div class="vspace size-2">&nbsp;</div>
    ++
    ++<div class="cols">
    ++  <div class="col-7">
    ++
    ++<h4 id="decide-for-me">Putuskan untuk saya tetapi biarkan saya yang menentukan</h4>
    ++<p>Gunakan tebakan terbaik Anda dan bertindaklah daripada meminta terlebih dahulu. Terlalu banyak pilihan dan keputusan membuat orang
    ++tidak suka. Untuk berjaga-jaga jika Anda salah, izinkan 'pembatalan'.</p>
    ++
    ++  </div>
    ++  <div class="col-6">
    ++
    ++    <img src="{@docRoot}design/media/principles_decide_for_me.png">
    ++
    ++  </div>
    ++</div>
    ++
    ++<div class="vspace size-2">&nbsp;</div>
    ++
    ++<div class="cols">
    ++  <div class="col-7">
    ++
    ++<h4 id="only-show-when-i-need-it">Cukup tunjukkan yang saya perlukan ketika saya memerlukannya</h4>
    ++<p>Orang merasa kewalahan ketika melihat terlalu banyak hal sekaligus. Uraikan tugas dan informasi menjadi potongan-potongan
    ++kecil yang mudah dicerna. Sembunyikan opsi yang tidak perlu pada saat ini, dan ajari orang sambil jalan.</p>
    ++
    ++  </div>
    ++  <div class="col-6">
    ++
    ++    <img src="{@docRoot}design/media/principles_information_when_need_it.png">
    ++
    ++  </div>
    ++</div>
    ++
    ++<div class="vspace size-2">&nbsp;</div>
    ++
    ++<div class="cols">
    ++  <div class="col-7">
    ++
    ++<h4 id="always-know-where-i-am">Saya harus selalu tahu di mana saya berada</h4>
    ++<p>Beri orang kepercayaan diri bahwa mereka tahu di mana berada. Buat agar tempat-tempat dalam aplikasi Anda terlihat berbeda dan
    ++gunakan transisi untuk menunjukkan hubungan antar layar. Berikan umpan balik tentang tugas yang sedang berlangsung.</p>
    ++
    ++  </div>
    ++  <div class="col-6">
    ++
    ++    <img src="{@docRoot}design/media/principles_navigation.png">
    ++
    ++  </div>
    ++</div>
    ++
    ++<div class="vspace size-2">&nbsp;</div>
    ++
    ++<div class="cols">
    ++  <div class="col-7">
    ++
    ++<h4 id="never-lose-my-stuff">Jangan sekali-kali menghilangkan milik saya</h4>
    ++<p>Simpan apa yang telah susah-payah dibuat orang dan biarkan mereka mengaksesnya dari mana saja. Ingat pengaturan,
    ++sentuhan pribadi, dan kreasi lintas ponsel, tablet, dan komputer. Itu membuat pemutakhiran menjadi
    ++hal termudah di dunia.</p>
    ++
    ++  </div>
    ++  <div class="col-6">
    ++
    ++    <img src="{@docRoot}design/media/principles_never_lose_stuff.png">
    ++
    ++  </div>
    ++</div>
    ++
    ++<div class="vspace size-2">&nbsp;</div>
    ++
    ++<div class="cols">
    ++  <div class="col-7">
    ++
    ++<h4 id="looks-same-should-act-same">Jika terlihat sama, seharusnya fungsinya sama</h4>
    ++<p>Bantu orang merasakan perbedaan fungsional dengan membuat mereka terlihat berbeda daripada mirip.
    ++Hindari mode, yaitu tempat yang terlihat mirip tetapi berbeda fungsinya pada input yang sama.</p>
    ++
    ++  </div>
    ++  <div class="col-6">
    ++
    ++    <img src="{@docRoot}design/media/principles_looks_same.png">
    ++
    ++  </div>
    ++</div>
    ++
    ++<div class="vspace size-2">&nbsp;</div>
    ++
    ++<div class="cols">
    ++  <div class="col-7">
    ++
    ++<h4 id="interrupt-only-if-important">Sela saya jika penting saja</h4>
    ++<p>Layaknya asisten pribadi yang baik, lindungi orang dari detail yang tidak penting. Orang ingin tetap
    ++fokus, dan kecuali jika memang penting dan sensitif waktu, interupsi bisa melelahkan dan menjengkelkan.</p>
    ++
    ++  </div>
    ++  <div class="col-6">
    ++
    ++    <img src="{@docRoot}design/media/principles_important_interruption.png">
    ++
    ++  </div>
    ++</div>
    ++
    ++<h2 id="make-me-amazing">Buat Saya Terpesona</h2>
    ++
    ++<div class="cols">
    ++  <div class="col-7">
    ++
    ++<h4 id="give-me-tricks">Beri saya trik yang efektif di mana saja</h4>
    ++<p>Orang merasa senang ketika mereka memahami sendiri sesuatu. Jadikan aplikasi Anda lebih mudah dipelajari dengan
    ++memanfaatkan pola visual dan memori otot dari aplikasi Android lainnya. Misalnya, gerakan menggeser
    ++dapat menjadi pintasan navigasi yang bagus.</p>
    ++
    ++  </div>
    ++  <div class="col-6">
    ++
    ++    <img src="{@docRoot}design/media/principles_tricks.png">
    ++
    ++  </div>
    ++</div>
    ++
    ++<div class="vspace size-2">&nbsp;</div>
    ++
    ++<div class="cols">
    ++  <div class="col-7">
    ++
    ++<h4 id="its-not-my-fault">Bukan salah saya</h4>
    ++<p>Bersikap ramahlah dalam meminta orang untuk melakukan koreksi. Mereka ingin merasa pintar ketika menggunakan
    ++aplikasi Anda. Jika terjadi kesalahan, berikan petunjuk perbaikan yang jelas tetapi lepaskan mereka dari detail teknis.
    ++Jika Anda dapat memperbaikinya secara diam-diam, tentu lebih baik.</p>
    ++
    ++  </div>
    ++  <div class="col-6">
    ++
    ++    <img src="{@docRoot}design/media/principles_error.png">
    ++
    ++  </div>
    ++</div>
    ++
    ++<div class="vspace size-2">&nbsp;</div>
    ++
    ++<div class="cols">
    ++  <div class="col-7">
    ++
    ++<h4 id="sprinkle-encouragement">Berikan dorongan</h4>
    ++<p>Uraikan tugas-tugas rumit menjadi langkah-langkah kecil yang dapat dilakukan dengan mudah. Beri umpan balik tentang tindakan,
    ++meskipun hanya sesuatu yang sederhana.</p>
    ++
    ++  </div>
    ++  <div class="col-6">
    ++
    ++    <img src="{@docRoot}design/media/principles_sprinkle_encouragement.png">
    ++
    ++  </div>
    ++</div>
    ++
    ++<div class="vspace size-2">&nbsp;</div>
    ++
    ++<div class="cols">
    ++  <div class="col-7">
    ++
    ++<h4 id="do-heavy-lifting-for-me">Lakukan pekerjaan yang sulit untuk saya</h4>
    ++<p>Buatlah pemula merasa seperti ahli dengan memungkinkan mereka untuk melakukan hal-hal yang mereka pikir tidak akan bisa.
    ++Misalnya, pintasan yang menggabungkan beberapa efek foto dapat membuat foto amatir terlihat mengagumkan hanya
    ++dalam beberapa langkah.</p>
    ++
    ++  </div>
    ++  <div class="col-6">
    ++
    ++    <img src="{@docRoot}design/media/principles_heavy_lifting.png">
    ++
    ++  </div>
    ++</div>
    ++
    ++<div class="vspace size-2">&nbsp;</div>
    ++
    ++<div class="cols">
    ++  <div class="col-7">
    ++
    ++<h4 id="make-important-things-fast">Percepat hal penting</h4>
    ++<p>Tidak semua tindakan itu sama. Putuskan apa yang terpenting dalam aplikasi Anda dan permudah untuk menemukannya serta
    ++cepat untuk digunakan, seperti tombol rana pada kamera, atau tombol jeda pada pemutar musik.</p>
    ++
    ++  </div>
    ++  <div class="col-6">
    ++
    ++    <img src="{@docRoot}design/media/principles_make_important_fast.png">
    ++
    ++  </div>
    ++</div>
    +diff --git a/docs/html-intl/intl/id/design/material/index.jd b/docs/html-intl/intl/id/design/material/index.jd
    +new file mode 100644
    +index 0000000..0cb4dbc
    +--- /dev/null
    ++++ b/docs/html-intl/intl/id/design/material/index.jd
    +@@ -0,0 +1,186 @@
    ++page.title=Material Design for Android
    ++page.tags=Material,design
    ++page.type=design
    ++page.image=images/cards/design-material-for-android_2x.jpg
    ++
    ++@jd:body
    ++
    ++<!-- developer docs box -->
    ++<a class="notice-developers right" href="{@docRoot}training/material/index.html">
    ++  <div>
    ++    <h3>Dokumen Pengembang</h3>
    ++    <p>Membuat Aplikasi dengan Desain Bahan</p>
    ++  </div>
    ++</a>
    ++
    ++<!-- video box -->
    ++<a class="notice-developers-video" href="https://www.youtube.com/watch?v=p4gmvHyuZzw">
    ++<div>
    ++    <h3>Video</h3>
    ++    <p>Pengantar Desain Bahan</p>
    ++</div>
    ++</a>
    ++
    ++<!-- video box -->
    ++<a class="notice-developers-video" href="https://www.youtube.com/watch?v=YaG_ljfzeUw">
    ++<div>
    ++    <h3>Video</h3>
    ++    <p>Kertas dan Tinta: Bahan Penting</p>
    ++</div>
    ++</a>
    ++
    ++<!-- video box -->
    ++<a class="notice-developers-video" href="https://www.youtube.com/watch?v=XOcCOBe8PTc">
    ++<div>
    ++    <h3>Video</h3>
    ++    <p>Desain Bahan di Aplikasi Google I/O</p>
    ++</div>
    ++</a>
    ++
    ++
    ++
    ++<p itemprop="description">Desain bahan adalah panduan komprehensif untuk desain visual, gerak, dan
    ++interaksi lintas platform dan perangkat. Android kini menyertakan dukungan untuk
    ++aplikasi desain bahan. Untuk menggunakan desain bahan di aplikasi Android, ikuti panduan yang didefinisikan
    ++dalam <a href="http://www.google.com/design/spec">spesifikasi desain bahan</a> dan gunakan
    ++komponen dan fungsionalitas baru yang tersedia di Android 5.0 (API level 21) ke atas.</p>
    ++
    ++<p>Android menyediakan elemen berikut untuk membangun aplikasi desain bahan:</p>
    ++
    ++<ul>
    ++  <li>Tema baru</li>
    ++  <li>Widget baru untuk tampilan yang kompleks</li>
    ++  <li>API baru untuk animasi dan bayangan custom</li>
    ++</ul>
    ++
    ++<p>Untuk informasi selengkapnya tentang mengimplementasikan desain bahan pada Android, lihat
    ++<a href="{@docRoot}training/material/index.html">Membuat Aplikasi dengan Desain Bahan</a>.</p>
    ++
    ++
    ++<h3>Tema Bahan</h3>
    ++
    ++<p>Tema bahan menyediakan gaya baru untuk aplikasi Anda, widget sistem yang memungkinkan Anda mengatur
    ++palet warnanya, dan animasi default untuk umpan balik sentuh dan transisi aktivitas.</p>
    ++
    ++<!-- two columns -->
    ++<div style="width:700px;margin-top:25px;margin-bottom:20px">
    ++<div style="float:left;width:250px;margin-left:40px;margin-right:60px;">
    ++  <img src="{@docRoot}design/material/images/MaterialDark.png" width="500" height="238" />
    ++  <div style="width:140px;margin:0 auto">
    ++  <p style="margin-top:8px">Tema bahan gelap</p>
    ++  </div>
    ++</div>
    ++<div style="float:left;width:250px;margin-right:0px;">
    ++  <img src="{@docRoot}design/material/images/MaterialLight.png" width="500" height="238" />
    ++  <div style="width:140px;margin:0 auto">
    ++  <p style="margin-top:8px">Tema bahan terang</p>
    ++  </div>
    ++</div>
    ++<br style="clear:left"/>
    ++</div>
    ++
    ++<p>Untuk informasi selengkapnya, lihat <a href="{@docRoot}training/material/theme.html">Menggunakan Tema
    ++Bahan</a>.</p>
    ++
    ++
    ++<h3>Daftar dan Kartu</h3>
    ++
    ++<p>Android menyediakan dua widget baru untuk menampilkan kartu dan daftar dengan gaya desain bahan
    ++dan animasi:</p>
    ++
    ++<!-- two columns -->
    ++<div style="width:700px;margin-top:25px;margin-bottom:20px">
    ++<div style="float:left;width:250px;margin-left:40px;margin-right:60px;">
    ++  <img src="{@docRoot}design/material/images/list_mail.png" width="500" height="426" />
    ++  <p>Widget <code>RecyclerView</code> baru adalah versi <code>ListView</code>
    ++ yang lebih mudah dimasukkan dan mendukung beragam tipe layout serta memberikan peningkatan kinerja.</p>
    ++</div>
    ++<div style="float:left;width:250px;margin-right:0px;">
    ++  <img src="{@docRoot}design/material/images/card_travel.png" width="500" height="426" />
    ++  <p>Widget <code>CardView</code> baru memungkinkan Anda menampilkan potongan informasi penting dalam
    ++  kartu yang memiliki tampilan dan cara kerja yang konsisten.</p>
    ++</div>
    ++<br style="clear:left"/>
    ++</div>
    ++
    ++<p>Untuk informasi selengkapnya, lihat <a href="{@docRoot}training/material/lists-cards.html">Membuat Daftar
    ++dan Kartu</a>.</p>
    ++
    ++
    ++<h3>Bayangan Tampilan</h3>
    ++
    ++<p>Selain properti X dan Y, tampilan di Android kini memiliki
    ++properti Z. Properti baru ini mewakili ketinggian tampilan, yang menentukan:</p>
    ++
    ++<ul>
    ++<li>Ukuran bayangan: tampilan dengan nilai Z lebih tinggi menghasilkan bayangan lebih besar.</li>
    ++<li>Urutan penggambaran: tampilan dengan nilai Z lebih tinggi muncul di atas tampilan lainnya.</li>
    ++</ul>
    ++
    ++<div style="width:290px;margin-left:35px;float:right">
    ++  <div class="framed-nexus5-port-span-5">
    ++  <video class="play-on-hover" autoplay>
    ++    <source src="{@docRoot}design/material/videos/ContactsAnim.mp4"/>
    ++    <source src="{@docRoot}design/videos/ContactsAnim.webm"/>
    ++    <source src="{@docRoot}design/videos/ContactsAnim.ogv"/>
    ++  </video>
    ++  </div>
    ++  <div style="font-size:10pt;margin-left:20px;margin-bottom:30px">
    ++    <em>Untuk memutar ulang film, klik layar perangkat</em>
    ++  </div>
    ++</div>
    ++
    ++<p>Untuk informasi selengkapnya, lihat <a href="{@docRoot}training/material/shadows-clipping.html">Mendefinisikan
    ++Bayangan dan Memangkas Tampilan</a>.</p>
    ++
    ++
    ++<h3>Animasi</h3>
    ++
    ++<p>API animasi baru memungkinkan Anda membuat animasi custom untuk umpan balik sentuh dalam kontrol UI,
    ++perubahan status tampilan, dan transisi aktivitas.</p>
    ++
    ++<p>API ini memungkinkan Anda:</p>
    ++
    ++<ul>
    ++<li style="margin-bottom:15px">
    ++Merespons kejadian sentuh dalam tampilan Anda dengan animasi <strong>umpan balik sentuh</strong>.
    ++</li>
    ++<li style="margin-bottom:15px">
    ++Menyembunyikan dan memperlihatkan tampilan dengan animasi <strong>membuka melingkar</strong>.
    ++</li>
    ++<li style="margin-bottom:15px">
    ++Peralihan antar aktivitas dengan animasi <strong>transisi aktivitas</strong> custom.
    ++</li>
    ++<li style="margin-bottom:15px">
    ++Membuat animasi yang lebih alami dengan <strong>gerak melengkung</strong>.
    ++</li>
    ++<li style="margin-bottom:15px">
    ++Menganimasikan perubahan dalam satu atau beberapa properti tampilan dengan animasi <strong>perubahan status tampilan</strong>.
    ++</li>
    ++<li style="margin-bottom:15px">
    ++Menampilkan animasi di <strong>drawable daftar status</strong> di antara perubahan status tampilan.
    ++</li>
    ++</ul>
    ++
    ++<p>Animasi umpan balik sentuh dimasukkan ke dalam beberapa tampilan standar, misalnya tombol. API baru
    ++ini memungkinkan Anda menyesuaikan animasi ini dan menambahkannya ke tampilan custom Anda.</p>
    ++
    ++<p>Untuk informasi selengkapnya, lihat <a href="{@docRoot}training/material/animations.html">Mendefinisikan Animasi
    ++Custom</a>.</p>
    ++
    ++
    ++<h3>Drawable</h3>
    ++
    ++<p>Kemampuan baru untuk drawable ini membantu Anda mengimplementasikan aplikasi desain bahan:</p>
    ++
    ++<ul>
    ++<li><strong>Drawable vektor</strong> bisa diubah skalanya tanpa kehilangan definisi dan cocok
    ++untuk ikon satu-warna dalam-aplikasi.</li>
    ++<li><strong>Pewarnaan drawable</strong> memungkinkan Anda mendefinisikan bitmap sebagai alpha-mask dan mewarnainya
    ++saat runtime.</li>
    ++<li><strong>Ekstraksi warna</strong> memungkinkan Anda mengekstrak warna mencolok secara otomatis dari
    ++gambar bitmap.</li>
    ++</ul>
    ++
    ++<p>Untuk informasi selengkapnya, lihat <a href="{@docRoot}training/material/drawables.html">Bekerja dengan
    ++Drawable</a>.</p>
    +diff --git a/docs/html-intl/intl/id/design/patterns/compatibility.jd b/docs/html-intl/intl/id/design/patterns/compatibility.jd
    +new file mode 100644
    +index 0000000..cafaac4
    +--- /dev/null
    ++++ b/docs/html-intl/intl/id/design/patterns/compatibility.jd
    +@@ -0,0 +1,70 @@
    ++page.title=Kompatibilitas Mundur
    ++page.tags="support"
    ++page.metaDescription=Catatan tentang bagaimana Android 4.x menyesuaikan UI yang didesain untuk perangkat keras dan versi OS yang lebih lama.
    ++@jd:body
    ++
    ++<a class="notice-developers" href="{@docRoot}training/basics/supporting-devices/index.html">
    ++  <div>
    ++    <h3>Dokumen Pengembang</h3>
    ++    <p>Mendukung Perangkat Berbeda</p>
    ++  </div>
    ++</a>
    ++
    ++<p>Perubahan signifikan dalam Android 3.0 meliputi:</p>
    ++<ul>
    ++<li>Dihilangkannya tombol perangkat keras navigasi (Back, Menu, Search, Home) untuk membantu menangani navigasi
    ++  melalui kontrol maya (Back, Home, Recents).</li>
    ++<li>Pola yang tangguh untuk penggunaan menu pada action-bar.</li>
    ++</ul>
    ++<p>Android 4.0 membawa perubahan ini untuk tablet dengan platform ponsel.</p>
    ++
    ++<h2 id="older-hardware">Menyesuaikan Android 4.0 dengan Perangkat Keras dan Aplikasi yang Lebih Lama</h2>
    ++
    ++<div class="cols">
    ++  <div class="col-6">
    ++
    ++<h4>Ponsel dengan kontrol navigasi virtual</h4>
    ++<p>Aplikasi Android yang ditulis untuk Android 3.0 dan yang lebih baru menampilkan tindakan dalam action-bar. Tindakan yang tidak
    ++muat dalam action-bar atau tidak cukup penting untuk ditampilkan di tingkat atas akan muncul dalam
    ++action-overflow.</p>
    ++<p>Pengguna mengakses action-overflow dengan menyentuhnya dalam action-bar.</p>
    ++
    ++  </div>
    ++  <div class="col-7">
    ++
    ++    <img src="{@docRoot}design/media/compatibility_virtual_nav.png">
    ++
    ++  </div>
    ++</div>
    ++
    ++<div class="cols">
    ++  <div class="col-6">
    ++
    ++<h4>Ponsel dengan tombol navigasi fisik</h4>
    ++<p>Ponsel Android dengan tombol perangkat keras navigasi biasa tidak menampilkan baris navigasi virtual di
    ++bagian bawah layar. Sebagai gantinya, action-overflow tersedia dari tombol perangkat keras menu. Popup
    ++tindakan yang dihasilkan memiliki gaya yang sama dengan contoh sebelumnya, tetapi ditampilkan di bagian bawah layar.</p>
    ++
    ++  </div>
    ++  <div class="col-7">
    ++
    ++    <img src="{@docRoot}design/media/compatibility_physical_buttons.png">
    ++
    ++  </div>
    ++</div>
    ++
    ++<div class="cols">
    ++  <div class="col-6">
    ++
    ++<h4>Aplikasi lama pada ponsel dengan kontrol navigasi virtual</h4>
    ++<p>Bila Anda menjalankan aplikasi yang dibuat untuk Android 2.3 atau yang lebih lama pada ponsel
    ++dengan kontrol navigasi virtual, sebuah kontrol action-overflow akan muncul di sebelah kanan baris navigasi virtual. Anda
    ++dapat menyentuh kontrol itu untuk menampilkan tindakan aplikasi dalam gaya menu Android biasa.</p>
    ++
    ++  </div>
    ++  <div class="col-7">
    ++
    ++    <img src="{@docRoot}design/media/compatibility_legacy_apps.png">
    ++
    ++  </div>
    ++</div>
    +diff --git a/docs/html-intl/intl/id/design/patterns/confirming-acknowledging.jd b/docs/html-intl/intl/id/design/patterns/confirming-acknowledging.jd
    +new file mode 100644
    +index 0000000..d22e924
    +--- /dev/null
    ++++ b/docs/html-intl/intl/id/design/patterns/confirming-acknowledging.jd
    +@@ -0,0 +1,70 @@
    ++page.title=Mengonfirmasi &amp; Mengakui
    ++page.tags=dialog,toast,notification
    ++@jd:body
    ++
    ++<p>Dalam beberapa situasi, bila pengguna memanggil suatu tindakan dalam aplikasi Anda, ada baiknya <em>mengonfirmasi</em> atau <em>mengakui</em> tindakan itu melalui teks.</p>
    ++
    ++<div class="cols">
    ++  <div class="col-6">
    ++    <img src="{@docRoot}design/media/confirm_ack_confirming.png">
    ++    <p><strong>Mengonfirmasi</strong> adalah meminta pengguna untuk memverifikasi bahwa mereka benar-benar ingin melanjutkan tindakan yang baru saja mereka panggil. Dalam beberapa kasus, konfirmasi ditampilkan bersama-sama dengan peringatan atau informasi penting yang terkait dengan tindakan yang perlu mereka pertimbangkan.</p>
    ++  </div>
    ++  <div class="col-6">
    ++    <img src="{@docRoot}design/media/confirm_ack_acknowledge.png">
    ++    <p><strong>Mengakui</strong> adalah menampilkan teks untuk memberi tahu pengguna bahwa tindakan yang baru mereka panggil sudah dilakukan. Ini menghilangkan ketidakpastian tentang operasi implisit yang dilakukan sistem. Dalam beberapa kasus, pengakuan ditampilkan bersama dengan opsi untuk membatalkan tindakan.</p>
    ++  </div>
    ++</div>
    ++
    ++<p>Berkomunikasi pada pengguna dengan cara ini bisa membantu mengurangi ketidakpastian tentang hal-hal yang sudah atau akan terjadi. Mengonfirmasi atau mengakui juga dapat mencegah pengguna melakukan kesalahan yang akan mereka sesali.</p>
    ++
    ++<h2>Kapan Harus Mengonfirmasi atau Mengakui Tindakan Pengguna</h2>
    ++<p>Tidak semua tindakan memerlukan konfirmasi atau pengakuan. Gunakan bagan alur ini untuk memandu keputusan desain Anda.</p>
    ++<img src="{@docRoot}design/media/confirm_ack_flowchart.png">
    ++
    ++<h2>Mengonfirmasi</h2>
    ++<div class="cols">
    ++  <div class="col-6">
    ++    <h4>Contoh: Google Play Books</h4>
    ++    <img src="{@docRoot}design/media/confirm_ack_ex_books.png">
    ++    <p>Dalam contoh ini, pengguna telah meminta untuk menghapus sebuah buku dari perpustakaan Google Play mereka. Sebuah <a href="{@docRoot}design/building-blocks/dialogs.html#alerts">peringatan</a> muncul untuk mengonfirmasi tindakan ini karena perlu dipahami bahwa buku tersebut tidak akan tersedia lagi dari perangkat apa pun.</p>
    ++    <p>Saat membuat dialog konfirmasi, buat judul bermakna dengan mencerminkan tindakan yang diminta.</p>
    ++  </div>
    ++  <div class="col-7">
    ++    <h4>Contoh: Android Beam</h4>
    ++    <img src="{@docRoot}design/media/confirm_ack_ex_beam.png">
    ++    <p>Konfirmasi tidak harus ditampilkan dalam peringatan dengan dua tombol. Setelah menjalankan Android Beam, pengguna diminta untuk menyentuh konten yang akan dibagikan (dalam contoh ini, sebuah foto). Jika mereka memutuskan untuk tidak melanjutkan, mereka tinggal memindahkan ponsel.</p>
    ++  </div>
    ++</div>
    ++
    ++<h2>Mengakui</h2>
    ++<div class="cols">
    ++  <div class="col-6">
    ++    <h4>Contoh: Draf Gmail batal yang disimpan</h4>
    ++    <img src="{@docRoot}design/media/confirm_ack_ex_draftsave.png">
    ++    <p>Dalam contoh ini, jika pengguna menyusuri ke belakang atau ke atas dari layar pembuatan email di Gmail, sesuatu yang tak diharapkan bisa terjadi: draf saat itu akan disimpan secara otomatis. Pengakuan dalam bentuk pemberitahuan akan lebih jelas. Ini menghilang setelah beberapa detik.</p>
    ++    <p>Pembatalan tidak cocok di sini karena penyimpanan dilakukan oleh aplikasi, bukan pengguna. Cepat dan mudah untuk melanjutkan penulisan pesan dengan menyusuri daftar draf.</p>
    ++
    ++  </div>
    ++  <div class="col-6">
    ++    <h4>Contoh: Percakapan Gmail dihapus</h4>
    ++    <img src="{@docRoot}design/media/confirm_ack_draft_deleted.png">
    ++    <p>Setelah pengguna menghapus percakapan dari daftar dalam Gmail, sebuah pengakuan muncul tanpa opsi pembatalan. Pengakuan tetap ada sampai pengguna melakukan tindakan yang tidak berkaitan, seperti menggulir daftar.</p>
    ++  </div>
    ++</div>
    ++
    ++<h2>Tidak ada Konfirmasi atau Pengakuan</h2>
    ++<div class="cols">
    ++  <div class="col-6">
    ++    <h4>Contoh: memberikan +1</h4>
    ++    <img style="padding: 33px 0 30px;" src="{@docRoot}design/media/confirm_ack_ex_plus1.png">
    ++    <p><strong>Konfirmasi tidak diperlukan</strong>. Jika pengguna telah memberikan +1 secara tidak sengaja, tidak masalah. Mereka cukup menyentuh kembali tombol itu untuk membatalkan tindakan.</p>
    ++    <p><strong>Pengakuan tidak diperlukan</strong>. Pengguna akan melihat tombol +1 memantul dan berubah merah. Itu tanda yang sangat jelas.</p>
    ++  </div>
    ++  <div class="col-7">
    ++    <h4>Contoh: Menghapus aplikasi dari Layar Beranda</h4>
    ++    <img src="{@docRoot}design/media/confirm_ack_ex_removeapp.png">
    ++    <p><strong>Konfirmasi tidak diperlukan</strong>. Ini adalah tindakan yang disengaja: pengguna harus menyeret dan meletakkan sebuah item di atas target yang relatif besar dan terpisah. Karena itu, kecil kemungkinan terjadi ketidaksengajaan. Tetapi jika pengguna menyesali keputusan itu, maka hanya perlu beberapa detik untuk mengembalikannya lagi.</p>
    ++    <p><strong>Pengakuan tidak diperlukan</strong>. Pengguna akan mengetahui bahwa aplikasi itu tidak ada di Layar Beranda karena mereka menghilangkannya dengan cara menyeretnya.</p>
    ++
    ++  </div>
    ++</div>
    +diff --git a/docs/html-intl/intl/id/design/patterns/navigation.jd b/docs/html-intl/intl/id/design/patterns/navigation.jd
    +new file mode 100644
    +index 0000000..4915700
    +--- /dev/null
    ++++ b/docs/html-intl/intl/id/design/patterns/navigation.jd
    +@@ -0,0 +1,213 @@
    ++page.title=Navigasi dengan Back dan Up
    ++page.tags="navigation","activity","task","up navigation","back navigation"
    ++page.image=/design/media/navigation_between_siblings_gmail.png
    ++@jd:body
    ++
    ++<a class="notice-developers" href="{@docRoot}training/implementing-navigation/index.html">
    ++  <div>
    ++    <h3>Dokumen Pengembang</h3>
    ++    <p>Mengimplementasikan Navigasi yang Efektif</p>
    ++  </div>
    ++</a>
    ++
    ++<p itemprop="description">Navigasi yang konsisten merupakan komponen penting dari keseluruhan pengalaman pengguna. Hampir tidak ada yang lebih membingungkan
    ++pengguna selain navigasi dasar yang perilakunya tidak konsisten dan tidak sesuai harapan. Android 3.0
    ++memperkenalkan perubahan besar dalam perilaku navigasi global. Mengikuti dengan saksama
    ++panduan untuk Back dan Up akan membuat navigasi aplikasi Anda dapat diprediksi dan dapat diandalkan pengguna.</p>
    ++<p>Android 2.3 dan versi sebelumnya mengandalkan tombol <em>Back</em> sistem untuk mendukung navigasi dalam
    ++aplikasi. Dengan diperkenalkannya action-bar dalam Android 3.0, mekanisme navigasi kedua muncul:
    ++tombol <em>Up</em>, yang terdiri dari ikon aplikasi dan tanda panah yang menunjuk ke kiri.</p>
    ++
    ++<img src="{@docRoot}design/media/navigation_with_back_and_up.png">
    ++
    ++<h2 id="up-vs-back">Up vs. Back</h2>
    ++
    ++<p>Tombol Up digunakan untuk berpindah dalam aplikasi berdasarkan hubungan hierarki
    ++antar layar. Misalnya, jika layar A menampilkan daftar item, dan memilih sebuah item akan membuka
    ++layar B (yang menampilkan item tersebut secara lebih detail), maka layar B akan menawarkan tombol Up untuk
    ++kembali ke layar A.</p>
    ++<p>Jika suatu layar merupakan yang teratas dalam aplikasi (yaitu layar Home aplikasi), maka tidak perlu menampilkan tombol
    ++Up.</p>
    ++
    ++<p>Tombol Back sistem digunakan untuk berpindah, dalam urutan kronologis terbalik, melalui riwayat
    ++layar yang baru dibuka oleh pengguna. Biasanya ini berdasarkan hubungan sementara
    ++antar layar, dan bukan hierarki aplikasi.</p>
    ++
    ++<p>Bila layar yang dilihat sebelumnya juga merupakan induk hierarki dari layar yang sekarang, menekan tombol
    ++Back akan sama hasilnya dengan menekan tombol Up&mdash;ini adalah kejadian
    ++biasa. Akan tetapi, berbeda dengan tombol Up, yang memastikan pengguna tetap berada dalam aplikasi Anda, tombol Back
    ++dapat mengembalikan pengguna ke layar Home, atau bahkan ke aplikasi lain.</p>
    ++
    ++<img src="{@docRoot}design/media/navigation_up_vs_back_gmail.png">
    ++
    ++<p>Tombol Back juga mendukung beberapa perilaku yang tidak terkait langsung dengan navigasi antar layar:
    ++</p>
    ++<ul>
    ++<li>Menghilangkan jendela mengambang (dialog, popup)</li>
    ++<li>Menghilangkan action-bar kontekstual, dan menghapus sorotan dari item yang dipilih</li>
    ++<li>Menyembunyikan keyboard di layar (IME)</li>
    ++</ul>
    ++<h2 id="within-app">Navigasi Dalam Aplikasi Anda</h2>
    ++
    ++<h4>Berpindah ke layar yang memiliki beberapa titik masuk</h4>
    ++<p>Kadang-kadang layar tidak memiliki posisi pasti dalam hierarki aplikasi, dan bisa dimasuki
    ++dari berbagai titik masuk&mdash;seperti layar pengaturan yang dapat dibuka dari layar lain
    ++dalam aplikasi Anda. Dalam hal ini, tombol Up akan memilih untuk kembali ke layar pengarah, yang cara kerjanya
    ++sama dengan tombol Back.</p>
    ++<h4>Mengubah tampilan dalam layar</h4>
    ++<p>Mengubah opsi tampilan untuk layar tidak mengubah perilaku Up atau Back: layar tetap
    ++berada di tempat yang sama dalam hierarki aplikasi, dan tidak dibuat riwayat navigasi yang baru.</p>
    ++<p>Contoh perubahan tampilan tersebut adalah:</p>
    ++<ul>
    ++<li>Mengganti tampilan menggunakan tab dan/atau geser kiri dan kanan</li>
    ++<li>Mengubah tampilan menggunakan tarik-turun (alias tab turun)</li>
    ++<li>Memfilter daftar</li>
    ++<li>Menyortir daftar</li>
    ++<li>Mengubah karakteristik tampilan (seperti zoom)</li>
    ++</ul>
    ++<h4>Berpindah antar layar yang seinduk</h4>
    ++<p>Bila aplikasi Anda mendukung navigasi dari daftar item ke tampilan detail salah satu item tersebut, aplikasi
    ++juga sering diharapkan mendukung navigasi langsung dari item itu ke item sebelumnya atau
    ++sesudahnya dalam daftar. Misalnya, dalam Gmail, begitu mudah untuk bergeser ke kiri atau kanan dari sebuah percakapan
    ++untuk melihat percakapan yang lebih baru atau lebih lama dalam Inbox yang sama. Sama seperti saat mengubah tampilan dalam layar, navigasi
    ++ini tidak mengubah perilaku Up atau Back.</p>
    ++
    ++<img src="{@docRoot}design/media/navigation_between_siblings_gmail.png">
    ++
    ++<p>Akan tetapi, pengecualian khusus terhadap hal ini terjadi saat menjelajah di antara tampilan detail terkait yang tidak disatukan
    ++oleh daftar yang merujuknya&mdash;misalnya, saat menjelajahi Play Store di antara aplikasi dari
    ++pengembang yang sama, atau album dari artis yang sama. Dalam hal ini, mengikuti setiap tautan akan membuat
    ++riwayat, sehingga tombol Back akan menyusuri setiap layar yang dilihat sebelumnya. Tombol Up akan terus
    ++melewatkan semua layar terkait ini dan berpindah ke layar kontainer yang terakhir dilihat.</p>
    ++
    ++<img src="{@docRoot}design/media/navigation_between_siblings_market1.png">
    ++
    ++<p>Anda dapat menjadikan perilaku tombol Up lebih cerdas lagi berdasarkan pengetahuan Anda tentang tampilan
    ++detail. Dengan memperluas contoh Play Store dari atas, bayangkan pengguna yang telah berpindah dari Buku
    ++terakhir yang dilihat ke detail untuk adaptasi Film. Dalam hal itu, tombol Up dapat kembali ke kontainer
    ++(Movies) yang sebelumnya belum dilalui pengguna.</p>
    ++
    ++<img src="{@docRoot}design/media/navigation_between_siblings_market2.png">
    ++
    ++<h2 id="into-your-app">Navigasi ke Aplikasi Anda melalui Widget dan Pemberitahuan Layar Home</h2>
    ++
    ++<p>Anda bisa menggunakan widget atau pemberitahuan layar Home untuk membantu pengguna berpindah langsung ke layar
    ++jauh dalam hierarki aplikasi Anda. Misalnya, widget Inbox dan pemberitahuan pesan baru di Gmail dapat
    ++melewatkan layar Inbox, dan membawa pengguna langsung ke tampilan percakapan.</p>
    ++
    ++<p>Untuk kedua kasus ini, tangani tombol Up sebagai berikut:</p>
    ++
    ++<ul>
    ++<li><em>Jika layar tujuan biasanya dicapai dari satu layar tertentu dalam aplikasi
    ++Anda</em>, tombol Up akan mengarahkannya ke layar itu.</li>
    ++<li><em>Jika tidak</em>, tombol Up akan mengarahkan ke layar teratas ("Home") dari aplikasi Anda.</li>
    ++</ul>
    ++
    ++<p>Dalam hal tombol Back, Anda harus membuat navigasi lebih bisa diprediksi dengan menyisipkan ke dalam
    ++back-stack tugas path navigasi naik lengkap menuju layar teratas aplikasi. Ini memungkinkan pengguna
    ++yang lupa cara masuk ke aplikasi Anda untuk berpindah ke layar teratas aplikasi sebelum
    ++keluar.</p>
    ++
    ++<p>Sebagai contoh, widget layar Home di Gmail memiliki tombol untuk menuju langsung ke layar
    ++Compose. Tombol Up atau Back dari layar Compose akan membawa pengguna ke Inbox, dan dari sana tombol
    ++Back berlanjut ke Home.</p>
    ++
    ++<img src="{@docRoot}design/media/navigation_from_outside_back.png">
    ++
    ++<h4>Pemberitahuan tidak langsung</h4>
    ++
    ++<p>Jika aplikasi Anda perlu menampilkan informasi tentang beberapa kejadian sekaligus, aplikasi dapat menggunakan
    ++pemberitahuan tunggal yang mengarahkan pengguna ke layar antara. Layar ini merangkum semua
    ++kejadian tersebut, dan menyediakan path bagi pengguna untuk menjelajah ke dalam aplikasi. Pemberitahuan dengan gaya seperti ini
    ++disebut <em>pemberitahuan tidak langsung</em>.</p>
    ++
    ++<p>Berbeda dengan pemberitahuan standar (langsung), menekan tombol Back dari
    ++layar antara pada pemberitahuan tidak langsung akan mengembalikan pengguna ke titik pemicu pemberitahuan tersebut&mdash;tidak ada
    ++layar tambahan yang disisipkan ke dalam back-stack. Setelah pengguna melanjutkan ke dalam aplikasi dari
    ++layar antara, tombol Up dan Back akan berperilaku seperti pada pemberitahuan standar, sebagaimana dijelaskan di atas:
    ++menyusuri ke dalam aplikasi dan bukan kembali ke layar antara.</p>
    ++
    ++<p>Misalnya, anggaplah seorang pengguna di Gmail menerima pemberitahuan tidak langsung dari Kalender. Menyentuh
    ++pemberitahuan ini akan membuka layar antara, yang menampilkan pengingat beberapa macam
    ++kejadian. Menyentuh Back dari layar antara akan mengembalikan pengguna ke Gmail. Menyentuh kejadian
    ++tertentu akan membawa pengguna dari layar antara ke aplikasi Kalender lengkap untuk menampilkan detail
    ++kejadian. Dari detail kejadian, tombol Up dan Back akan mengarahkan ke tampilan Kalender tingkat atas.</p>
    ++
    ++<img src="{@docRoot}design/media/navigation_indirect_notification.png">
    ++
    ++<h4>Pemberitahuan pop-up</h4>
    ++
    ++<p><em>Pemberitahuan pop-up</em> akan melewatkan laci pemberitahuan, bukan muncul secara langsung di
    ++hadapan pengguna. Ini jarang digunakan, dan <strong>harus dicadangkan untuk peristiwa yang memerlukan respons tepat waktu
    ++dan diperlukan interupsi dari konteks pengguna</strong>. Misalnya,
    ++Talk menggunakan gaya ini untuk memberi tahu pengguna tentang ajakan dari teman untuk bergabung dalam chatting video, karena
    ++ajakan ini akan kedaluwarsa secara otomatis setelah beberapa detik.</p>
    ++
    ++<p>Dalam hal perilaku navigasi, pemberitahuan pop-up sangat mirip perilaku pemberitahuan
    ++tidak langsung pada layar antara. Tombol Back akan menghilangkan pemberitahuan pop-up. Jika pengguna berpindah
    ++dari pop-up ke aplikasi yang memberi tahu, tombol Up dan Back akan mengikuti aturan pemberitahuan standar,
    ++berpindah dalam aplikasi.</p>
    ++
    ++<img src="{@docRoot}design/media/navigation_popup_notification.png">
    ++
    ++<h2 id="between-apps">Navigasi Antar Aplikasi</h2>
    ++
    ++<p>Salah satu kekuatan dasar sistem Android adalah kemampuan aplikasi untuk saling
    ++mengaktifkan, sehingga pengguna dapat berpindah langsung dari satu aplikasi ke aplikasi lainnya. Misalnya, sebuah
    ++aplikasi yang perlu mengambil foto dapat mengaktifkan aplikasi Kamera, yang akan mengembalikan foto
    ++ke aplikasi perujuk. Ini sangat menguntungkan pengembang, yang bisa dengan mudah memanfaatkan
    ++kode dari aplikasi lain, maupun pengguna, yang menikmati pengalaman konsisten untuk tindakan yang biasa
    ++dilakukan.</p>
    ++
    ++<p>Untuk memahami navigasi antar aplikasi, maka perlu memahami perilaku kerangka kerja Android
    ++yang akan dibahas di bawah ini.</p>
    ++
    ++<h4>Aktivitas, tugas, dan intent</h4>
    ++
    ++<p>Dalam Android, <strong>aktivitas</strong> adalah komponen aplikasi yang mendefinisikan layar
    ++informasi dan semua tindakan terkait yang dapat dilakukan pengguna. Aplikasi Anda adalah kumpulan
    ++aktivitas, yang terdiri dari aktivitas yang Anda buat dan aktivitas yang Anda gunakan ulang dari aplikasi lain.</p>
    ++
    ++<p><strong>Tugas</strong> adalah urutan aktivitas yang diikuti pengguna untuk mencapai tujuan.
    ++Tugas tunggal dapat memanfaatkan aktivitas dari satu aplikasi saja, atau dapat memanfaatkan aktivitas dari sejumlah
    ++aplikasi berbeda.</p>
    ++
    ++<p><strong>Intent</strong> adalah mekanisme bagi satu aplikasi untuk memberi isyarat minta bantuan
    ++aplikasi lain dalam menjalankan suatu tindakan. Aktivitas aplikasi dapat menunjukkan intent
    ++ apa saja yang dapat diresponsnya. Untuk intent umum seperti "Share", pengguna mungkin telah menginstal beberapa aplikasi
    ++yang dapat memenuhi permintaan itu.</p>
    ++
    ++<h4>Contoh: berpindah antar aplikasi untuk mendukung berbagi</h4>
    ++
    ++<p>Untuk memahami cara kerja sama aktivitas, tugas, dan intent, perhatikan bagaimana sebuah aplikasi memungkinkan pengguna
    ++untuk berbagi konten dengan menggunakan aplikasi lain. Misalnya, membuka aplikasi Play Store dari Home akan memulai
    ++Task A baru (lihat gambar di bawah). Setelah menyusuri Play Store dan menyentuh buku yang dipromosikan
    ++untuk melihat detailnya, pengguna tetap berada dalam tugas yang sama, memperluasnya dengan menambahkan aktivitas. Memicu
    ++tindakan Share akan memberi tahu pengguna dengan dialog berisi daftar aktivitas (dari aplikasi berbeda)
    ++yang telah terdaftar untuk menangani intent Share.</p>
    ++
    ++<img src="{@docRoot}design/media/navigation_between_apps_inward.png">
    ++
    ++<p>Bila pengguna memilih untuk berbagi melalui Gmail, aktivitas penulisan di Gmail akan ditambahkan sebagai kelanjutan dari
    ++Task A&mdash;tidak ada tugas baru yang dibuat. Jika Gmail sedang menjalankan tugasnya di latar belakang, maka
    ++tidak akan terpengaruh.</p>
    ++
    ++<p>Dari aktivitas penulisan, mengirim pesan atau menyentuh tombol Back akan mengembalikan pengguna ke
    ++aktivitas detail buku tersebut. Penyentuhan tombol Back berikutnya akan terus mengarahkan kembali melalui Play
    ++Store, sampai akhirnya tiba di Home.</p>
    ++
    ++<img src="{@docRoot}design/media/navigation_between_apps_back.png">
    ++
    ++<p>Akan tetapi, dengan menyentuh tombol Up dari aktivitas penulisan, pengguna menunjukkan keinginan untuk tetap berada di
    ++Gmail. Aktivitas daftar percakapan Gmail muncul, Task B yang baru akan dibuat untuk itu. Tugas baru
    ++selalu terkait ke Home, maka menyentuh tombol Back dari daftar percakapan akan mengembalikan ke sana.</p>
    ++
    ++<img src="{@docRoot}design/media/navigation_between_apps_up.png">
    ++
    ++<p>Task A tetap berjalan di latar belakang, dan pengguna nanti dapat kembali ke sana (misalnya, melalui layar
    ++Recents). Jika Gmail sedang menjalankan tugasnya di latar belakang, maka itu akan digantikan
    ++dengan Task B&mdash;konteks sebelumnya akan diabaikan demi tujuan baru pengguna.</p>
    ++
    ++<p>Jika register aplikasi Anda menangani intent dengan aktivitas yang jauh di dalam hierarki aplikasi,
    ++lihat <a href="#into-your-app">Navigasi Aplikasi Anda melalui Widget Layar Home dan
    ++Pemberitahuan</a> untuk panduan mengenai cara menetapkan navigasi Up.</p>
    +diff --git a/docs/html-intl/intl/id/guide/components/activities.jd b/docs/html-intl/intl/id/guide/components/activities.jd
    +new file mode 100644
    +index 0000000..bbc061c
    +--- /dev/null
    ++++ b/docs/html-intl/intl/id/guide/components/activities.jd
    +@@ -0,0 +1,756 @@
    ++page.title=Aktivitas
    ++page.tags=aktivitas,intent
    ++@jd:body
    ++
    ++<div id="qv-wrapper">
    ++<div id="qv">
    ++<h2>Dalam dokumen ini</h2>
    ++<ol>
    ++  <li><a href="#Creating">Membuat Aktivitas</a>
    ++    <ol>
    ++      <li><a href="#UI">Mengimplementasikan antarmuka pengguna</a></li>
    ++      <li><a href="#Declaring">Mendeklarasikan aktivitas dalam manifes</a></li>
    ++    </ol>
    ++  </li>
    ++  <li><a href="#StartingAnActivity">Memulai Aktivitas</a>
    ++    <ol>
    ++      <li><a href="#StartingAnActivityForResult">Memulai aktivitas agar berhasil</a></li>
    ++    </ol>
    ++  </li>
    ++  <li><a href="#ShuttingDown">Mematikan Aktivitas</a></li>
    ++  <li><a href="#Lifecycle">Mengelola Daur Hidup Aktivitas</a>
    ++    <ol>
    ++      <li><a href="#ImplementingLifecycleCallbacks">Mengimplementasikan callback daur hidup</a></li>
    ++      <li><a href="#SavingActivityState">Menyimpan status aktivitas</a></li>
    ++      <li><a href="#ConfigurationChanges">Menangani perubahan konfigurasi</a></li>
    ++      <li><a href="#CoordinatingActivities">Mengoordinasikan aktivitas</a></li>
    ++    </ol>
    ++  </li>
    ++</ol>
    ++
    ++<h2>Kelas-kelas utama</h2>
    ++<ol>
    ++  <li>{@link android.app.Activity}</li>
    ++</ol>
    ++
    ++<h2>Lihat juga</h2>
    ++<ol>
    ++  <li><a href="{@docRoot}guide/components/tasks-and-back-stack.html">Tugas dan
    ++Back-Stack</a></li>
    ++</ol>
    ++
    ++</div>
    ++</div>
    ++
    ++
    ++
    ++<p>{@link android.app.Activity} adalah sebuah komponen aplikasi yang menyediakan layar yang digunakan
    ++pengguna untuk berinteraksi guna melakukan sesuatu, misalnya memilih nomor telepon, mengambil foto, mengirim email, atau
    ++menampilkan peta. Tiap aktivitas diberi sebuah jendela untuk menggambar antarmuka penggunanya. Jendela ini
    ++biasanya mengisi layar, namun mungkin lebih kecil daripada layar dan mengambang di atas
    ++jendela lain.</p>
    ++
    ++<p> Sebuah aplikasi biasanya terdiri atas beberapa aktivitas yang terikat secara longgar
    ++satu sama lain. Biasanya, satu aktivitas dalam aplikasi ditetapkan sebagai aktivitas "utama", yang
    ++ditampilkan kepada pengguna saat membuka aplikasi untuk pertama kali. Tiap
    ++aktivitas kemudian bisa memulai aktivitas lain untuk melakukan berbagai tindakan. Tiap kali
    ++aktivitas baru dimulai, aktivitas sebelumnya akan dihentikan, namun sistem mempertahankan aktivitas
    ++dalam sebuah tumpukan ("back-stack"). Bila sebuah aktivitas baru dimulai, aktivitas itu akan didorong ke atas back-stack dan
    ++mengambil fokus pengguna. Back-stack mematuhi mekanisme dasar tumpukan "masuk terakhir, keluar pertama",
    ++jadi, bila pengguna selesai dengan aktivitas saat ini dan menekan tombol <em>Back</em>, aktivitas
    ++akan dikeluarkan dari tumpukan (dan dimusnahkan) dan aktivitas sebelumnya akan dilanjutkan. (Back-stack
    ++dibahas selengkapnya dalam dokumen <a href="{@docRoot}guide/components/tasks-and-back-stack.html">Tugas
    ++dan Back-Stack</a>.)</p>
    ++
    ++<p>Bila aktivitas dihentikan karena ada aktivitas baru yang dimulai, aktivitas lama akan diberi tahu tentang perubahan status ini
    ++melalui metode callback daur hidupnya.
    ++Ada beberapa metode callback yang mungkin diterima aktivitas, karena sebuah perubahan dalam
    ++statusnya&mdash;apakah sistem sedang membuatnya, menghentikannya, melanjutkannya, atau menghapuskannya&mdash;dan
    ++masing-masing callback memberi Anda kesempatan melakukan pekerjaan tertentu yang
    ++sesuai untuk perubahan status itu. Misalnya, bila dihentikan, aktivitas Anda harus melepas
    ++objek besar, seperti koneksi jaringan atau database. Bila aktivitas dilanjutkan, Anda bisa
    ++memperoleh kembali sumber daya yang diperlukan dan melanjutkan tindakan yang terputus. Transisi status ini
    ++semuanya bagian dari daur hidup aktivitas.</p>
    ++
    ++<p>Bagian selebihnya dari dokumen ini membahas dasar-dasar cara membuat dan menggunakan aktivitas,
    ++yang meliputi satu pembahasan lengkap tentang cara kerja daur hidup aktivitas, sehingga Anda bisa dengan benar mengelola
    ++transisi di antara berbagai status aktivitas.</p>
    ++
    ++
    ++
    ++<h2 id="Creating">Membuat Aktivitas</h2>
    ++
    ++<p>Untuk membuat sebuah aktivitas, Anda harus membuat subkelas {@link android.app.Activity} (atau
    ++subkelasnya yang ada). Dalam subkelas itu, Anda perlu mengimplementasikan metode-metode callback yang
    ++dipanggil sistem saat aktivitas bertransisi di antara berbagai status daur hidupnya, misalnya saat
    ++aktivitas sedang dibuat, dihentikan, dilanjutkan, atau dimusnahkan. Dua metode callback
    ++terpenting adalah:</p>
    ++
    ++<dl>
    ++  <dt>{@link android.app.Activity#onCreate onCreate()}</dt>
    ++  <dd>Anda harus mengimplementasikan metode ini. Sistem memanggilnya saat membuat
    ++    aktivitas Anda. Dalam implementasi, Anda harus menginisialisasi komponen-komponen esensial
    ++aktivitas.
    ++    Yang terpenting, inilah tempat Anda harus memanggil {@link android.app.Activity#setContentView
    ++    setContentView()} untuk mendefinisikan layout untuk antarmuka pengguna aktivitas.</dd>
    ++  <dt>{@link android.app.Activity#onPause onPause()}</dt>
    ++  <dd>Sistem memanggil metode ini sebagai pertanda pertama bahwa pengguna sedang meninggalkan
    ++aktivitas Anda (walau itu tidak selalu berarti aktivitas sedang dimusnahkan). Inilah biasanya tempat Anda
    ++harus mengikat setiap perubahan yang harus dipertahankan selepas sesi pengguna saat ini (karena
    ++pengguna mungkin tidak kembali).</dd>
    ++</dl>
    ++
    ++<p>Ada beberapa metode callback daur hidup lainnya yang harus Anda gunakan untuk memberikan
    ++pengalaman pengguna yang mengalir di antara aktivitas dan menangani interupsi tidak terduga yang menyebabkan aktivitas Anda
    ++dihentikan dan bahkan dimusnahkan. Semua metode callback daur hidup akan dibahas nanti, di
    ++bagian tentang <a href="#Lifecycle">Mengelola Daur Hidup Aktivitas</a>.</p>
    ++
    ++
    ++
    ++<h3 id="UI">Mengimplementasikan antarmuka pengguna</h3>
    ++
    ++<p> Antarmuka pengguna aktivitas disediakan oleh hierarki objek&mdash;tampilan yang diturunkan
    ++dari kelas {@link android.view.View}.  Tiap tampilan mengontrol sebuah ruang persegi panjang tertentu
    ++dalam jendela aktivitas dan bisa merespons interaksi pengguna. Misalnya, sebuah tampilan mungkin berupa sebuah
    ++tombol yang mengawali suatu tindakan bila pengguna menyentuhnya.</p>
    ++
    ++<p>Android menyediakan sejumlah tampilan siap-dibuat yang bisa Anda gunakan untuk mendesain dan mengatur
    ++layout. "Widget" adalah tampilan yang menyediakan elemen-elemen visual (dan interaktif) untuk layar,
    ++misalnya tombol, bidang teks, kotak cek, atau sekadar sebuah gambar. "Layout" adalah tampilan yang diturunkan dari {@link
    ++android.view.ViewGroup} yang memberikan sebuah model layout unik untuk tampilan anaknya, misalnya
    ++layout linier, layout grid, atau layout relatif. Anda juga bisa mensubkelaskan kelas-kelas {@link android.view.View} dan
    ++{@link android.view.ViewGroup} (atau subkelas yang ada) untuk membuat widget dan
    ++layout Anda sendiri dan menerapkannya ke layout aktivitas Anda.</p>
    ++
    ++<p>Cara paling umum untuk mendefinisikan layout dengan menggunakan tampilan adalah dengan file layout XML yang disimpan dalam
    ++sumber daya aplikasi Anda. Dengan cara ini, Anda bisa memelihara desain antarmuka pengguna Anda secara terpisah dari
    ++kode yang mendefinisikan perilaku aktivitas. Anda bisa mengatur layout sebagai UI
    ++aktivitas Anda dengan {@link android.app.Activity#setContentView(int) setContentView()}, dengan meneruskan
    ++ID sumber daya untuk layout itu. Akan tetapi, Anda juga bisa membuat {@link android.view.View} baru dalam
    ++kode aktivitas dan membuat hierarki tampilan dengan menyisipkan {@link
    ++android.view.View} baru ke dalam {@link android.view.ViewGroup}, kemudian menggunakan layout itu dengan meneruskan akar
    ++{@link android.view.ViewGroup} ke {@link android.app.Activity#setContentView(View)
    ++setContentView()}.</p>
    ++
    ++<p>Untuk informasi tentang cara membuat antarmuka pengguna, lihat dokumentasi <a href="{@docRoot}guide/topics/ui/index.html">Antarmuka Pengguna</a>.</p>
    ++
    ++
    ++
    ++<h3 id="Declaring">Mendeklarasikan aktivitas dalam manifes</h3>
    ++
    ++<p>Anda harus mendeklarasikan aktivitas dalam file manifes agar file itu
    ++bisa diakses oleh sistem. Untuk mendeklarasikan aktivitas, bukalah file manifes Anda dan tambahkan sebuah elemen <a href="{@docRoot}guide/topics/manifest/activity-element.html">{@code &lt;activity&gt;}</a>
    ++sebagai anak elemen <a href="{@docRoot}guide/topics/manifest/application-element.html">{@code &lt;application&gt;}</a>
    ++. Misalnya:</p>
    ++
    ++<pre>
    ++&lt;manifest ... &gt;
    ++  &lt;application ... &gt;
    ++      &lt;activity android:name=".ExampleActivity" /&gt;
    ++      ...
    ++  &lt;/application ... &gt;
    ++  ...
    ++&lt;/manifest &gt;
    ++</pre>
    ++
    ++<p>Ada beberapa atribut lain yang bisa Anda sertakan dalam elemen ini, untuk mendefinisikan properti
    ++misalnya label untuk aktivitas, ikon untuk aktivitas, atau tema untuk memberi gaya ke
    ++UI aktivitas. Atribut <a href="{@docRoot}guide/topics/manifest/activity-element.html#nm">{@code android:name}</a>
    ++ adalah satu-satunya atribut yang diperlukan&mdash;atribut ini menetapkan nama kelas aktivitas. Setelah
    ++Anda mempublikasikan aplikasi, Anda tidak boleh mengubah nama ini, karena jika melakukannya, Anda bisa merusak
    ++sebagian fungsionalitas, misalnya pintasan aplikasi (bacalah posting blog berjudul <a href="http://android-developers.blogspot.com/2011/06/things-that-cannot-change.html">Things
    ++That Cannot Change</a>).</p>
    ++
    ++<p>Lihat acuan elemen <a href="{@docRoot}guide/topics/manifest/activity-element.html">{@code &lt;activity&gt;}</a>
    ++untuk informasi selengkapnya tentang cara mendeklarasikan aktivitas Anda dalam manifes.</p>
    ++
    ++
    ++<h4>Menggunakan filter intent</h4>
    ++
    ++<p>Elemen <a href="{@docRoot}guide/topics/manifest/activity-element.html">{@code
    ++&lt;activity&gt;}</a> juga bisa menetapkan berbagai filter intent&mdash;dengan menggunakan elemen <a href="{@docRoot}guide/topics/manifest/intent-filter-element.html">{@code
    ++&lt;intent-filter&gt;}</a> &mdash;untuk mendeklarasikan cara komponen aplikasi lain
    ++mengaktifkannya.</p>
    ++
    ++<p>Bila Anda membuat aplikasi baru dengan Android SDK Tools, aktivitas stub
    ++yang dibuat untuk Anda secara otomatis menyertakan filter intent yang mendeklarasikan respons
    ++aktivitas pada tindakan "main" (utama) dan harus diletakkan dalam kategori "launcher"). Filter intent
    ++terlihat seperti ini:</p>
    ++
    ++<pre>
    ++&lt;activity android:name=".ExampleActivity" android:icon="@drawable/app_icon"&gt;
    ++    &lt;intent-filter&gt;
    ++        &lt;action android:name="android.intent.action.MAIN" /&gt;
    ++        &lt;category android:name="android.intent.category.LAUNCHER" /&gt;
    ++    &lt;/intent-filter&gt;
    ++&lt;/activity&gt;
    ++</pre>
    ++
    ++<p>Elemen <a href="{@docRoot}guide/topics/manifest/action-element.html">{@code
    ++&lt;action&gt;}</a> menetapkan bahwa ini adalah titik masuk "main" ke aplikasi. Elemen <a href="{@docRoot}guide/topics/manifest/category-element.html">{@code
    ++&lt;category&gt;}</a> menetapkan bahwa aktivitas ini harus tercantum dalam launcher aplikasi
    ++sistem (untuk memungkinkan pengguna meluncurkan aktivitas ini).</p>
    ++
    ++<p>Jika Anda bermaksud agar aplikasi dimuat dengan sendirinya dan tidak memperbolehkan aplikasi lain
    ++mengaktifkan aktivitasnya, maka Anda tidak memerlukan filter intent lain. Hanya satu aktivitas yang boleh
    ++memiliki tindakan "main" dan kategori "launcher", seperti dalam contoh sebelumnya. Aktivitas yang
    ++tidak ingin Anda sediakan untuk aplikasi lain tidak boleh memiliki filter intent dan Anda bisa
    ++memulai sendiri aktivitas dengan menggunakan intent secara eksplisit (seperti dibahas di bagian berikut).</p>
    ++
    ++<p>Akan tetapi, jika ingin aktivitas Anda merespons intent implisit yang dikirim dari
    ++aplikasi lain (dan aplikasi Anda sendiri), maka Anda harus mendefinisikan filter intent tambahan untuk
    ++aktivitas. Untuk masing-masing tipe intent yang ingin direspons, Anda harus menyertakan sebuah <a href="{@docRoot}guide/topics/manifest/intent-filter-element.html">{@code
    ++&lt;intent-filter&gt;}</a> yang menyertakan elemen
    ++<a href="{@docRoot}guide/topics/manifest/action-element.html">{@code
    ++&lt;action&gt;}</a> dan, opsional, sebuah elemen <a href="{@docRoot}guide/topics/manifest/category-element.html">{@code
    ++&lt;category&gt;}</a> dan/atau elemen <a href="{@docRoot}guide/topics/manifest/data-element.html">{@code
    ++&lt;data&gt;}</a>. Elemen-elemen ini menetapkan tipe intent yang bisa
    ++direspons oleh aktivitas Anda.</p>
    ++
    ++<p>Untuk informasi selengkapnya tentang cara aktivitas Anda merespons intent, lihat dokumen <a href="{@docRoot}guide/components/intents-filters.html">Intent dan Filter Intent</a>.
    ++</p>
    ++
    ++
    ++
    ++<h2 id="StartingAnActivity">Memulai Aktivitas</h2>
    ++
    ++<p>Anda bisa memulai aktivitas lain dengan memanggil {@link android.app.Activity#startActivity
    ++  startActivity()}, dengan meneruskan sebuah {@link android.content.Intent} yang menjelaskan aktivitas
    ++  yang ingin Anda mulai. Intent menetapkan aktivitas persis yang ingin Anda mulai atau menjelaskan
    ++  tipe tindakan yang ingin Anda lakukan (dan sistem akan memilih aktivitas yang sesuai untuk Anda,
    ++yang bahkan
    ++  bisa berasal dari aplikasi berbeda). Intent juga bisa membawa sejumlah kecil data untuk
    ++  digunakan oleh aktivitas yang dimulai.</p>
    ++
    ++<p>Saat bekerja dalam aplikasi sendiri, Anda nanti akan sering meluncurkan aktivitas yang dikenal saja.
    ++ Anda bisa melakukannya dengan membuat intent yang mendefinisikan secara eksplisit aktivitas yang ingin Anda mulai,
    ++dengan menggunakan nama kelas. Misalnya, beginilah cara satu aktivitas memulai aktivitas lain bernama {@code
    ++SignInActivity}:</p>
    ++
    ++<pre>
    ++Intent intent = new Intent(this, SignInActivity.class);
    ++startActivity(intent);
    ++</pre>
    ++
    ++<p>Akan tetapi, aplikasi Anda mungkin juga perlu melakukan beberapa tindakan, misalnya mengirim email,
    ++  pesan teks, atau pembaruan status, dengan menggunakan data dari aktivitas Anda. Dalam hal ini, aplikasi Anda mungkin
    ++ tidak memiliki aktivitasnya sendiri untuk melakukan tindakan tersebut, sehingga Anda bisa memanfaatkan aktivitas
    ++  yang disediakan oleh aplikasi lain pada perangkat, yang bisa melakukan tindakan itu untuk Anda. Inilah saatnya
    ++intent benar-benar berharga&mdash;Anda bisa membuat intent yang menjelaskan tindakan yang ingin
    ++dilakukan dan sistem
    ++  akan meluncurkan aktivitas yang tepat dari aplikasi lain. Jika ada
    ++  beberapa aktivitas yang bisa menangani intent itu, pengguna bisa memilih aktivitas yang akan digunakan. Misalnya,
    ++  jika Anda ingin memperbolehkan pengguna mengirim pesan email, Anda bisa membuat
    ++  intent berikut:</p>
    ++
    ++<pre>
    ++Intent intent = new Intent(Intent.ACTION_SEND);
    ++intent.putExtra(Intent.EXTRA_EMAIL, recipientArray);
    ++startActivity(intent);
    ++</pre>
    ++
    ++<p>Ekstra {@link android.content.Intent#EXTRA_EMAIL} yang ditambahkan ke intent adalah sebuah larik string
    ++  alamat email yang menjadi tujuan pengiriman email. Bila aplikasi email merespons intent ini,
    ++ aplikasi itu akan membaca larik string yang disediakan dalam ekstra dan meletakkannya dalam bidang "to"
    ++  pada formulir penulisan email. Dalam situasi ini, aktivitas aplikasi email dimulai dan bila
    ++  pengguna selesai, aktivitas Anda akan dilanjutkan.</p>
    ++
    ++
    ++
    ++
    ++<h3 id="StartingAnActivityForResult">Memulai aktivitas agar berhasil</h3>
    ++
    ++<p>Kadang-kadang, Anda mungkin ingin menerima hasil dari aktivitas yang Anda mulai. Dalam hal itu,
    ++  mulailah aktivitas dengan memanggil {@link android.app.Activity#startActivityForResult
    ++  startActivityForResult()} (sebagai ganti {@link android.app.Activity#startActivity
    ++  startActivity()}). Untuk menerima hasil dari
    ++aktivitas selanjutnya nanti, implementasikan metode callback {@link android.app.Activity#onActivityResult onActivityResult()}
    ++. Bila aktivitas selanjutnya selesai, aktivitas akan mengembalikan hasil dalam {@link
    ++android.content.Intent} kepada metode {@link android.app.Activity#onActivityResult onActivityResult()}
    ++Anda.</p>
    ++
    ++<p>Misalnya, mungkin Anda ingin pengguna mengambil salah satu kontaknya, sehingga aktivitas Anda bisa
    ++melakukan sesuatu dengan informasi dalam kontak itu. Begini caranya membuat intent tersebut dan
    ++menangani hasilnya:</p>
    ++
    ++<pre>
    ++private void pickContact() {
    ++    // Create an intent to "pick" a contact, as defined by the content provider URI
    ++    Intent intent = new Intent(Intent.ACTION_PICK, Contacts.CONTENT_URI);
    ++    startActivityForResult(intent, PICK_CONTACT_REQUEST);
    ++}
    ++
    ++&#64;Override
    ++protected void onActivityResult(int requestCode, int resultCode, Intent data) {
    ++    // If the request went well (OK) and the request was PICK_CONTACT_REQUEST
    ++    if (resultCode == Activity.RESULT_OK &amp;&amp; requestCode == PICK_CONTACT_REQUEST) {
    ++        // Perform a query to the contact's content provider for the contact's name
    ++        Cursor cursor = getContentResolver().query(data.getData(),
    ++        new String[] {Contacts.DISPLAY_NAME}, null, null, null);
    ++        if (cursor.moveToFirst()) { // True if the cursor is not empty
    ++            int columnIndex = cursor.getColumnIndex(Contacts.DISPLAY_NAME);
    ++            String name = cursor.getString(columnIndex);
    ++            // Do something with the selected contact's name...
    ++        }
    ++    }
    ++}
    ++</pre>
    ++
    ++<p>Contoh ini menunjukkan logika dasar yang harus Anda gunakan dalam metode {@link
    ++android.app.Activity#onActivityResult onActivityResult()} Anda untuk menangani
    ++hasil aktivitas. Syarat pertama memeriksa apakah permintaan berhasil&mdash;jika ya, maka
    ++ {@code resultCode} akan berupa {@link android.app.Activity#RESULT_OK}&mdash;dan apakah permintaan
    ++yang direspons hasil ini dikenal&mdash;dalam hal ini, {@code requestCode} cocok dengan
    ++parameter kedua yang dikirim dengan {@link android.app.Activity#startActivityForResult
    ++startActivityForResult()}. Dari sana, kode akan menangani hasil aktivitas dengan membuat query
    ++data yang dihasilkan dalam{@link android.content.Intent} (parameter {@code data}).</p>
    ++
    ++<p>Yang terjadi adalah {@link
    ++android.content.ContentResolver} melakukan query terhadap penyedia konten, yang menghasilkan
    ++{@link android.database.Cursor} yang memperbolehkan data query dibaca. Untuk informasi selengkapnya, lihat dokumen
    ++<a href="{@docRoot}guide/topics/providers/content-providers.html">Penyedia Konten</a>.</p>
    ++
    ++<p>Untuk informasi selengkapnya tentang menggunakan intent, lihat dokumen <a href="{@docRoot}guide/components/intents-filters.html">Intent dan Filter
    ++Intent</a>.</p>
    ++
    ++
    ++<h2 id="ShuttingDown">Mematikan Aktivitas</h2>
    ++
    ++<p>Anda bisa mematikan aktivitas dengan memanggil metode {@link android.app.Activity#finish
    ++finish()}-nya. Anda juga bisa mematikan aktivitas terpisah yang sebelumnya Anda mulai dengan memanggil
    ++{@link android.app.Activity#finishActivity finishActivity()}.</p>
    ++
    ++<p class="note"><strong>Catatan:</strong> Pada umumnya, Anda tidak boleh secara eksplisit mengakhiri aktivitas
    ++dengan menggunakan metode-metode ini. Seperti yang dibahas di bagian berikut tentang daur hidup aktivitas,
    ++sistem Android mengelola hidup aktivitas untuk Anda, sehingga Anda tidak perlu menyelesaikan sendiri
    ++aktivitas tersebut. Memanggil metode-metode ini bisa berpengaruh negatif pada pengalaman
    ++pengguna yang diharapkan dan hanya boleh digunakan bila Anda benar-benar tidak ingin pengguna kembali ke
    ++instance aktivitas ini.</p>
    ++
    ++
    ++<h2 id="Lifecycle">Mengelola Daur Hidup Aktivitas</h2>
    ++
    ++<p>Mengelola daur hidup aktivitas dengan mengimplementasikan metode-metode callback sangat
    ++penting untuk mengembangkan
    ++aplikasi yang kuat dan fleksibel. Daur hidup aktivitas dipengaruhi langsung oleh kaitannya dengan
    ++aktivitas lain, tugasnya, serta back-stack.</p>
    ++
    ++<p>Pada dasarnya, sebuah aktivitas bisa berada dalam tiga status:</p>
    ++
    ++<dl>
    ++  <dt><i>Dilanjutkan</i></dt>
    ++    <dd>Aktivitas berada di latar depan layar dan mendapatkan fokus pengguna. (Status ini
    ++kadang-kadang disebut juga dengan "running" (berjalan).)</dd>
    ++
    ++  <dt><i>Dihentikan sementara</i></dt>
    ++    <dd>Aktivitas lain berada di latar depan dan mendapat fokus, namun aktivitas ini masih terlihat. Yakni,
    ++aktivitas lain terlihat di atas aplikasi ini dan aktivitas itu setengah transparan atau tidak
    ++menuutpi seluruh layar. Aktivitas yang dihentikan sementara adalah benar-benar hidup (objek {@link android.app.Activity}
    ++dipertahankan dalam memori, objek itu memelihara semua informasi status dan anggota, dan tetap dikaitkan dengan
    ++window manager), namun bisa dimatikan oleh sistem dalam situasi memori sangat rendah.</dd>
    ++
    ++  <dt><i>Dihentikan</i></dt>
    ++    <dd>Aktivitas ditutupi sepenuhnya oleh aktivitas lain (aktivitas sekarang berada di
    ++"latar belakang"). Aktivitas yang dihentikan juga masih hidup (objek {@link android.app.Activity}
    ++dipertahankan dalam memori, objek itu menjaga semua informasi status dan anggota, namun <em>tidak</em>
    ++dikaitkan dengan window manager). Akan tetapi, aktivitas tidak lagi terlihat bagi pengguna dan
    ++bisa dimatikan oleh sistem bila memori diperlukan di lain.</dd>
    ++</dl>
    ++
    ++<p>Jika aktivitas dihentikan sementara atau dihentikan, sistem bisa mengeluarkannya dari memori baik dengan memintanya agar
    ++diakhiri (memanggil metode {@link android.app.Activity#finish finish()}-nya), atau sekadar mematikan
    ++prosesnya.  Bila dibuka lagi (setelah diakhiri atau dimatikan), aktivitas harus dibuat dari
    ++awal.</p>
    ++
    ++
    ++
    ++<h3 id="ImplementingLifecycleCallbacks">Mengimplementasikan callback daur hidup</h3>
    ++
    ++<p>Saat bertransisi ke dalam dan ke luar berbagai status yang dijelaskan di atas, aktivitas diberi tahu
    ++melalui berbagai metode callback. Semua metode callback adalah sangkutan yang
    ++bisa Anda kesampingkan untuk melakukan pekerjaan yang sesuai saat status aktivitas Anda berubah. Aktivitas skeleton
    ++berikut menyertakan setiap metode daur hidup mendasar:</p>
    ++
    ++
    ++<pre>
    ++public class ExampleActivity extends Activity {
    ++    &#64;Override
    ++    public void {@link android.app.Activity#onCreate onCreate}(Bundle savedInstanceState) {
    ++        super.onCreate(savedInstanceState);
    ++        // The activity is being created.
    ++    }
    ++    &#64;Override
    ++    protected void {@link android.app.Activity#onStart onStart()} {
    ++        super.onStart();
    ++        // The activity is about to become visible.
    ++    }
    ++    &#64;Override
    ++    protected void {@link android.app.Activity#onResume onResume()} {
    ++        super.onResume();
    ++        // The activity has become visible (it is now "resumed").
    ++    }
    ++    &#64;Override
    ++    protected void {@link android.app.Activity#onPause onPause()} {
    ++        super.onPause();
    ++        // Another activity is taking focus (this activity is about to be "paused").
    ++    }
    ++    &#64;Override
    ++    protected void {@link android.app.Activity#onStop onStop()} {
    ++        super.onStop();
    ++        // The activity is no longer visible (it is now "stopped")
    ++    }
    ++    &#64;Override
    ++    protected void {@link android.app.Activity#onDestroy onDestroy()} {
    ++        super.onDestroy();
    ++        // The activity is about to be destroyed.
    ++    }
    ++}
    ++</pre>
    ++
    ++<p class="note"><strong>Catatan:</strong> Implementasi Anda terhadap metode-metode daur hidup ini harus
    ++selalu memanggil implementasi superkelas sebelum melakukan pekerjaan apa pun, seperti yang ditampilkan dalam contoh-contoh di atas.</p>
    ++
    ++<p>Bersama-sama, semua metode ini mendefinisikan seluruh daur hidup sebuah aktivitas. Dengan mengimplementasikan
    ++metode-metode ini, Anda bisa memantau tiga loop tersarang (nested loop) dalam daur hidup aktivitas: </p>
    ++
    ++<ul>
    ++<li><b>Seluruh masa hidup</b> aktivitas berlangsung antara panggilan ke {@link
    ++android.app.Activity#onCreate onCreate()} dan panggilan ke {@link
    ++android.app.Activity#onDestroy}. Aktivitas Anda harus melakukan penyiapan
    ++status "global" (misalnya mendefinisikan layout) dalam {@link android.app.Activity#onCreate onCreate()}, dan
    ++melepas semua sisa sumber daya dalam {@link android.app.Activity#onDestroy}. Misalnya, jika
    ++aktivitas Anda memiliki sebuah thread yang berjalan di latar belakang untuk mengunduh data dari jaringan, aktivitas itu bisa membuat
    ++thread itu dalam {@link android.app.Activity#onCreate onCreate()} kemudian menghentikan thread dalam {@link
    ++android.app.Activity#onDestroy}.</li>
    ++
    ++<li><p><b>Masa pakai terlihat</b> (visible lifetime) aktivitas berlangsung antara panggilan ke {@link
    ++android.app.Activity#onStart onStart()} dan panggilan ke {@link
    ++android.app.Activity#onStop onStop()}. Selama ini, pengguna bisa melihat aktivitas
    ++pada layar dan berinteraksi dengannya. Misalnya, {@link android.app.Activity#onStop onStop()} dipanggil
    ++bila sebuah aktivitas baru dimulai dan aktivitas ini tidak lagi terlihat. Di antara dua metode ini, Anda bisa
    ++memelihara sumber daya yang diperlukan untuk menampilkan aktivitas kepada pengguna. Misalnya, Anda bisa mendaftarkan sebuah
    ++{@link android.content.BroadcastReceiver} dalam {@link
    ++android.app.Activity#onStart onStart()} untuk memantau perubahan yang berdampak pada UI Anda, dan mencabut pendaftarannya
    ++dalam {@link android.app.Activity#onStop onStop()} bila pengguna tidak bisa lagi melihat apa yang sedang Anda
    ++tampilkan. Sistem bisa memanggil {@link android.app.Activity#onStart onStart()} dan {@link
    ++android.app.Activity#onStop onStop()} beberapa kali selama masa pakai aktivitas, sambil
    ++aktivitas berganti-ganti antara terlihat dan tersembunyi bagi pengguna.</p></li>
    ++
    ++<li><p><b>Masa pakai latar depan</b> aktivitas berlangsung antara panggilan ke {@link
    ++android.app.Activity#onResume onResume()} dan panggilan ke {@link android.app.Activity#onPause
    ++onPause()}. Selama waktu ini, aktivitas berada di depan semua aktivitas lain pada layar dan mendapatkan
    ++fokus input pengguna.  Aktivitas bisa sering bertransisi ke dalam dan ke luar latar depan&mdash;misalnya,
    ++ {@link android.app.Activity#onPause onPause()} dipanggil bila perangkat masuk ke mode tidur atau
    ++bila dialog muncul. Karena status ini bisa sering bertransisi, kode dalam dua metode ini harus
    ++cukup ringan untuk menghindari transisi lamban yang membuat pengguna menunggu.</p></li>
    ++</ul>
    ++
    ++<p>Gambar 1 mengilustrasikan loop dan path yang mungkin diambil sebuah aktivitas di antara status-status.
    ++Persegi panjang mewakili metode callback yang bisa Anda implementasikan untuk melakukan operasi saat
    ++aktivitas bertransisi di antara status. <p>
    ++
    ++<img src="{@docRoot}images/activity_lifecycle.png" alt="" />
    ++<p class="img-caption"><strong>Gambar 1.</strong> Daur hidup aktivitas.</p>
    ++
    ++<p>Metode-metode callback daur hidup yang sama tercantum dalam tabel 1, yang menjelaskan setiap metode callback
    ++secara lebih detail dan menentukan lokasinya masing-masing dalam
    ++daur hidup aktivitas keseluruhan, termasuk apakah sistem bisa mematikan aktivitas setelah
    ++metode callback selesai.</p>
    ++
    ++<p class="table-caption"><strong>Tabel 1.</strong> Rangkuman metode callback
    ++daur hidup aktivitas.</p>
    ++
    ++<table border="2" width="85%" frame="hsides" rules="rows">
    ++<colgroup align="left" span="3"></colgroup>
    ++<colgroup align="left"></colgroup>
    ++<colgroup align="center"></colgroup>
    ++<colgroup align="center"></colgroup>
    ++
    ++<thead>
    ++<tr><th colspan="3">Metode</th> <th>Keterangan</th> <th>Bisa dimatikan setelahnya?</th> <th>Berikutnya</th></tr>
    ++</thead>
    ++
    ++<tbody>
    ++<tr>
    ++  <td colspan="3" align="left"><code>{@link android.app.Activity#onCreate onCreate()}</code></td>
    ++  <td>Dipanggil saat aktivitas pertama kali dibuat.
    ++      Di sinilah Anda harus melakukan semua persiapan statis normal &mdash;
    ++      membuat tampilan, mengikat data ke daftar, dan sebagainya.  Metode ini diberi
    ++      sebuah objek Bundle yang berisi status aktivitas sebelumnya, jika
    ++      status itu tertangkap (lihat <a href="#actstate">Menyimpan Status Aktivitas</a>,
    ++      nanti).
    ++      <p>Selalu diikuti oleh {@code onStart()}.</p></td>
    ++  <td align="center">Tidak</td>
    ++      <td align="center">{@code onStart()}</td>
    ++</tr>
    ++
    ++<tr>
    ++   <td rowspan="5" style="border-left: none; border-right: none;">&nbsp;&nbsp;&nbsp;&nbsp;</td>
    ++   <td colspan="2" align="left"><code>{@link android.app.Activity#onRestart
    ++onRestart()}</code></td>
    ++   <td>Dipanggil setelah aktivitas dihentikan, tepat sebelum
    ++       dimulai lagi.
    ++       <p>Selalu diikuti oleh {@code onStart()}</p></td>
    ++   <td align="center">Tidak</td>
    ++   <td align="center">{@code onStart()}</td>
    ++</tr>
    ++
    ++<tr>
    ++   <td colspan="2" align="left"><code>{@link android.app.Activity#onStart onStart()}</code></td>
    ++   <td>Dipanggil tepat sebelum aktivitas menjadi terlihat bagi pengguna.
    ++       <p>Diikuti oleh {@code onResume()} jika aktivitas maju
    ++       ke latar depan, atau {@code onStop()} jika menjadi tersembunyi.</p></td>
    ++    <td align="center">Tidak</td>
    ++    <td align="center">{@code onResume()} <br/>atau<br/> {@code onStop()}</td>
    ++</tr>
    ++
    ++<tr>
    ++   <td rowspan="2" style="border-left: none;">&nbsp;&nbsp;&nbsp;&nbsp;</td>
    ++   <td align="left"><code>{@link android.app.Activity#onResume onResume()}</code></td>
    ++   <td>Dipanggil tepat sebelum aktivitas mulai
    ++       berinteraksi dengan pengguna.  Pada titik ini, aktivitas berada di
    ++       puncak tumpukan aktivitas, dengan input pengguna menuju kepadanya.
    ++       <p>Selalu diikuti oleh {@code onPause()}.</p></td>
    ++   <td align="center">Tidak</td>
    ++   <td align="center">{@code onPause()}</td>
    ++</tr>
    ++
    ++<tr>
    ++   <td align="left"><code>{@link android.app.Activity#onPause onPause()}</code></td>
    ++   <td>Dipanggil bila sistem akan memulai pelanjutan
    ++       aktivitas lain.  Metode ini biasanya digunakan untuk menerapkan (commit) perubahan yang tidak tersimpan pada
    ++       data persisten, menghentikan animasi dan hal-hal lain yang mungkin menghabiskan
    ++       CPU, dan sebagainya.  Metode ini harus melakukan apa saja yang dilakukannya dengan sangat cepat, karena
    ++       aktivitas berikutnya tidak akan dilanjutkan hingga aktivitas ini kembali.
    ++       <p>Diikuti oleh {@code onResume()} jika aktivitas
    ++       kembali ke depan, atau oleh {@code onStop()} jika menjadi
    ++       tidak terlihat bagi pengguna.</td>
    ++   <td align="center"><strong style="color:#800000">Ya</strong></td>
    ++   <td align="center">{@code onResume()} <br/>atau<br/> {@code onStop()}</td>
    ++</tr>
    ++
    ++<tr>
    ++   <td colspan="2" align="left"><code>{@link android.app.Activity#onStop onStop()}</code></td>
    ++   <td>Dipanggil bila aktivitas tidak lagi terlihat bagi pengguna.  Hal ini
    ++       bisa terjadi karena aktivitas sedang dimusnahkan, atau karena aktivitas lain
    ++       (aktivitas yang ada atau yang baru) telah dilanjutkan dan sedang menutupinya.
    ++       <p>Diikuti oleh {@code onRestart()} jika
    ++       aktivitas kembali untuk berinteraksi dengan pengguna, atau oleh
    ++       {@code onDestroy()} jika aktivitas ini akan menghilang.</p></td>
    ++   <td align="center"><strong style="color:#800000">Ya</strong></td>
    ++   <td align="center">{@code onRestart()} <br/>atau<br/> {@code onDestroy()}</td>
    ++</tr>
    ++
    ++<tr>
    ++   <td colspan="3" align="left"><code>{@link android.app.Activity#onDestroy
    ++onDestroy()}</code></td>
    ++   <td>Dipanggil sebelum aktivitas dimusnahkan.  Inilah panggilan terakhir
    ++       yang akan diterima aktivitas.  Metode ini bisa dipanggil karena
    ++       aktivitas selesai (seseorang memanggil <code>{@link android.app.Activity#finish
    ++       finish()}</code> padanya), atau karena sistem memusnahkan sementara
    ++       instance aktivitas ini untuk menghemat tempat.  Anda bisa membedakan
    ++       kedua skenario ini dengan metode <code>{@link
    ++       android.app.Activity#isFinishing isFinishing()}</code>.</td>
    ++   <td align="center"><strong style="color:#800000">Ya</strong></td>
    ++   <td align="center"><em>tidak ada</em></td>
    ++</tr>
    ++</tbody>
    ++</table>
    ++
    ++<p>Kolom berlabel "Bisa dimatikan setelahnya?" menunjukkan apakah sistem bisa
    ++atau tidak mematikan proses yang menjadi host aktivitas kapan saja <em>setelah metode kembali</em>, tanpa
    ++menjalankan baris lain pada kode aktivitas.  Tiga metode ini ditandai "ya": ({@link
    ++android.app.Activity#onPause
    ++onPause()}, {@link android.app.Activity#onStop onStop()}, dan {@link android.app.Activity#onDestroy
    ++onDestroy()}). Karena {@link android.app.Activity#onPause onPause()} adalah yang pertama
    ++dari tiga, begitu aktivitas dibuat, {@link android.app.Activity#onPause onPause()} adalah
    ++metode terakhir yang dipastikan akan dipanggil sebelum proses <em>bisa</em> dimatikan&mdash;jika
    ++sistem harus memulihkan memori dalam keadaan darurat, maka {@link
    ++android.app.Activity#onStop onStop()} dan {@link android.app.Activity#onDestroy onDestroy()} mungkin
    ++tidak dipanggil. Karena itu, Anda harus menggunakan {@link android.app.Activity#onPause onPause()} untuk menulis
    ++data persisten yang penting (misalnya hasil edit pengguna) ke penyimpanan. Akan tetapi, Anda harus selektif dalam hal
    ++informasi yang harus dipertahankan selama {@link android.app.Activity#onPause onPause()}, karena setiap
    ++prosedur pemblokiran dalam metode ini akan memblokir transisi ke aktivitas berikutnya dan memperlambat
    ++pengalaman pengguna.</p>
    ++
    ++<p> Metode-metode yang ditandai "Tidak" dalam kolom <b>Bisa dimatikan</b> melindungi proses yang menjadi host
    ++aktivitas dari dimatikan sejak saat metode dipanggil.  Jadi, aktivitas bisa dimatikan
    ++sejak {@link android.app.Activity#onPause onPause()} kembali hingga waktu
    ++{@link android.app.Activity#onResume onResume()} dipanggil. Aktivitas tidak akan lagi bisa dimatikan hingga
    ++{@link android.app.Activity#onPause onPause()} dipanggil lagi dan kembali. </p>
    ++
    ++<p class="note"><strong>Catatan:</strong> Aktivitas yang tidak "bisa dimatikan" secara teknis oleh
    ++definisi dalam tabel 1 masih bisa dimatikan oleh sistem&mdash;namun itu hany terjadi dalam
    ++situasi ekstrem bila tidak ada jalan lain. Kapan aktivitas bisa dimatikan
    ++akan dibahas selengkapnya dalam dokumen <a href="{@docRoot}guide/components/processes-and-threads.html">Proses dan
    ++Threading</a>.</p>
    ++
    ++
    ++<h3 id="SavingActivityState">Menyimpan status aktivitas</h3>
    ++
    ++<p>Pengantar untuk <a href="#Lifecycle">Mengelola Daur Hidup Aktivitas</a> secara ringkas menyebutkan
    ++bahwa
    ++bila aktivitas dihentikan sementara atau dihentikan, status aktivitas akan dipertahankan. Hal itu terjadi karena
    ++objek {@link android.app.Activity} masih ditahan dalam memori saat aktivitas dihentikan sementara atau
    ++dihentikan&mdash;semua informasi tentang anggota dan statusnya saat ini masih hidup. Jadi, setiap perubahan
    ++yang dibuat pengguna dalam aktivitas akan dipertahankan sehingga bila aktivitas kembali ke
    ++latar depan (bila "dilanjutkan"), perubahan itu masih ada.</p>
    ++
    ++<p>Akan tetapi, bila sistem memusnahkan aktivitas untuk memulihkan memori, objek {@link
    ++android.app.Activity} akan dimusnahkan, sehingga sistem tidak bisa sekadar melanjutkan aktivitas dengan status
    ++tidak berubah. Sebagai gantinya, sistem harus membuat ulang objek {@link android.app.Activity} jika pengguna
    ++menyusuri kembali ke aktivitas tersebut. Namun, pengguna tidak menyadari
    ++bahwa sistem memusnahkan aktivitas dan membuatnya kembali dan, karena itu, mungkin
    ++mengharapkan aktivitas untuk sama persis dengan sebelumnya. Dalam situasi ini, Anda bisa memastikan bahwa
    ++informasi penting tentang status aktivitas tetap terjaga dengan mengimplementasikan
    ++metode callback tambahan yang memungkinkan Anda menyimpan informasi tentang status aktivitas: {@link
    ++android.app.Activity#onSaveInstanceState onSaveInstanceState()}.</p>
    ++
    ++<p>Sistem memanggil {@link android.app.Activity#onSaveInstanceState onSaveInstanceState()}
    ++sebelum membuat aktivitas rawan terhadap pemusnahan. Sistem meneruskan ke metode ini
    ++sebuah {@link android.os.Bundle} tempat Anda bisa menyimpan
    ++informasi status tentang aktivitas sebagai pasangan nama-nilai, dengan menggunakan metode-metode misalnya {@link
    ++android.os.Bundle#putString putString()} dan {@link
    ++android.os.Bundle#putInt putInt()}. Kemudian, jika sistem mematikan proses aplikasi Anda
    ++dan pengguna menyusuri kembali ke aktivitas tersebut, sistem akan membuat kembali aktivitas dan meneruskan
    ++{@link android.os.Bundle} ke {@link android.app.Activity#onCreate onCreate()} maupun {@link
    ++android.app.Activity#onRestoreInstanceState onRestoreInstanceState()}. Dengan menggunakan salah satu
    ++metode ini, Anda bisa mengekstrak status tersimpan dari {@link android.os.Bundle} dan memulihkan
    ++status aktivitas. Jika tidak ada informasi status untuk dipulihkan, maka {@link
    ++android.os.Bundle} yang diteruskan kepada adalah Anda null (yang akan terjadi bila aktivitas dibuat untuk
    ++pertama kali).</p>
    ++
    ++<img src="{@docRoot}images/fundamentals/restore_instance.png" alt="" />
    ++<p class="img-caption"><strong>Gambar 2.</strong> Ada dua cara yang bisa digunakan aktivitas untuk kembali ke fokus pengguna
    ++dengan status tetap: aktivitas dimusnahkan, kemudian dibuat kembali, dan aktivitas harus memulihkan
    ++status yang disimpan sebelumnya, atau aktivitas dihentikan, kemudian dilanjutkan dengan status aktivitas
    ++tetap.</p>
    ++
    ++<p class="note"><strong>Catatan:</strong> Tidak ada jaminan bahwa {@link
    ++android.app.Activity#onSaveInstanceState onSaveInstanceState()} akan dipanggil sebelum
    ++aktivitas Anda dimusnahkan, karena bisa saja terjadi aktivitas tidak perlu menyimpan status
    ++(misalnya saat pengguna meninggalkan aktivitas Anda dengan menggunakan tombol <em>Back</em>, karena pengguna menutup aktivitas
    ++secara eksplisit
    ++). Jika sistem memanggil {@link android.app.Activity#onSaveInstanceState
    ++onSaveInstanceState()}, ini akan dilakukan sebelum {@link
    ++android.app.Activity#onStop onStop()} dan mungkin sebelum {@link android.app.Activity#onPause
    ++onPause()}.</p>
    ++
    ++<p>Akan tetapi, sekalipun Anda tidak melakukan apa-apa dan tidak mengimplementasikan {@link
    ++android.app.Activity#onSaveInstanceState onSaveInstanceState()}, beberapa status aktivitas
    ++akan dipulihkan oleh implementasi default {@link
    ++android.app.Activity#onSaveInstanceState onSaveInstanceState()} dalam kelas {@link android.app.Activity}. Khususnya,
    ++implementasi default akan memanggil metode {@link
    ++android.view.View#onSaveInstanceState onSaveInstanceState()} yang sesuai untuk setiap {@link
    ++android.view.View} dalam layout, yang memungkinkan setiap tampilan untuk memberi informasi tentang dirinya
    ++yang harus disimpan. Hampir setiap widget dalam kerangka kerja Android mengimplementasikan metode ini
    ++sebagaimana mestinya, sehingga setiap perubahan yang terlihat pada UI akan disimpan dan dipulihkan secara otomatis bila
    ++aktivitas Anda dibuat kembali. Misalnya, widget {@link android.widget.EditText} menyimpan teks apa saja
    ++yang dimasukkan oleh pengguna dan widget {@link android.widget.CheckBox} menyimpan baik teks itu diperiksa maupun
    ++tidak. Satu-satunya pekerjaan yang Anda perlukan adalah memberikan ID unik (dengan atribut <a href="{@docRoot}guide/topics/resources/layout-resource.html#idvalue">{@code android:id}</a>
    ++) untuk masing-masing widget yang ingin disimpan statusnya. Jika widget tidak memiliki ID, maka sistem
    ++tidak bisa menyimpan statusnya.</p>
    ++
    ++<div class="sidebox-wrapper">
    ++<div class="sidebox">
    ++<p>Anda juga bisa menghentikan secara eksplisit sebuah tampilan dalam layout Anda agar tidak menyimpan statusnya dengan mengatur atribut
    ++{@link android.R.attr#saveEnabled android:saveEnabled} ke {@code "false"} atau dengan memanggil
    ++metode {@link android.view.View#setSaveEnabled setSaveEnabled()}. Biasanya, Anda tidak boleh
    ++menonaktifkannya, namun Anda boleh melakukannya jika ingin memulihkan status UI aktivitas secara berbeda.</p>
    ++</div>
    ++</div>
    ++
    ++<p>Walaupun implementasi default {@link
    ++android.app.Activity#onSaveInstanceState onSaveInstanceState()} menyimpan informasi yang berguna tentang
    ++UI aktivitas, Anda mungkin masih perlu mengesampingkannya untuk menyimpan informasi tambahan.
    ++Misalnya, Anda mungkin perlu menyimpan nilai-nilai anggota yang berubah selama masa pakai aktivitas (yang
    ++mungkin berkorelasi dengan nilai-nilai yang dipulihkan dalam UI, namun anggota-anggota yang menyimpan nilai-nilai UI itu tidak
    ++dipulihkan, secara default).</p>
    ++
    ++<p>Karena implementasi default {@link
    ++android.app.Activity#onSaveInstanceState onSaveInstanceState()} membantu menyimpan status UI, jika
    ++Anda mengesampingkan metode ini untuk menyimpan informasi tambahan status, Anda harus selalu memanggil
    ++implementasi superkelas {@link android.app.Activity#onSaveInstanceState onSaveInstanceState()}
    ++sebelum melakukan pekerjaan apa pun. Demikian pula, Anda juga harus memanggil implementasi superkelas {@link
    ++android.app.Activity#onRestoreInstanceState onRestoreInstanceState()} jika Anda mengesampingkannya, sehingga
    ++implementasi default bisa memulihkan status tampilan.</p>
    ++
    ++<p class="note"><strong>Catatan:</strong> Karena {@link android.app.Activity#onSaveInstanceState
    ++onSaveInstanceState()} tidak dijamin
    ++akan dipanggil, Anda harus menggunakannya hanya untuk mencatat status aktivitas sementara (transient) (status
    ++UI)&mdash;Anda tidak boleh menggunakannya untuk menyimpan data persisten.  Sebagai gantinya, Anda harus menggunakan {@link
    ++android.app.Activity#onPause onPause()} untuk menyimpan data persisten (misalnya data yang harus disimpan
    ++ke database) saat pengguna meninggalkan aktivitas.</p>
    ++
    ++<p>Salah satu cara yang baik untuk menguji kemampuan aplikasi dalam memulihkan statusnya adalah cukup dengan memutar
    ++perangkat sehingga orientasi layarnya berubah. Bila orientasi layar berubah, sistem
    ++akan memusnahkan dan membuat kembali aktivitas untuk menerapkan sumber daya alternatif yang mungkin tersedia
    ++untuk konfigurasi layar baru. Karena alasan ini saja, sangat penting bahwa aktivitas Anda
    ++memulihkan statusnya secara lengkap saat dibuat kembali, karena pengguna memutar layar secara rutin saat
    ++menggunakan aplikasi.</p>
    ++
    ++
    ++<h3 id="ConfigurationChanges">Menangani perubahan konfigurasi</h3>
    ++
    ++<p>Sebagian konfigurasi perangkat bisa berubah saat runtime (misalnya orientasi layar, ketersediaan keyboard
    ++, dan bahasa). Bila terjadi perubahan demikian, Android akan membuat kembali aktivitas yang berjalan
    ++(sistem akan memanggil {@link android.app.Activity#onDestroy}, kemudian segera memanggil {@link
    ++android.app.Activity#onCreate onCreate()}). Perilaku ini
    ++didesain untuk membantu aplikasi Anda menyesuaikan diri dengan konfigurasi baru dengan cara memuat ulang
    ++aplikasi Anda secara otomatis dengan sumber daya alternatif yang telah Anda sediakan (misalnya layout yang berbeda untuk
    ++layar orientasi dan ukuran yang berbeda).</p>
    ++
    ++<p>Jika Anda mendesain aktivitas dengan benar untuk menangani restart karena perubahan orientasi layar dan
    ++memulihkan status aktivitas seperti yang dijelaskan di atas, aplikasi Anda akan lebih tahan terhadap
    ++kejadian tidak terduga lainnya dalam daur hidup aktivitas.</p>
    ++
    ++<p>Cara terbaik menangani restart tersebut adalah
    ++  menyimpan dan memulihkan status aktivitas Anda dengan menggunakan {@link
    ++  android.app.Activity#onSaveInstanceState onSaveInstanceState()} dan {@link
    ++android.app.Activity#onRestoreInstanceState onRestoreInstanceState()} (atau {@link
    ++android.app.Activity#onCreate onCreate()}), seperti yang dibahas di bagian sebelumnya.</p>
    ++
    ++<p>Untuk informasi selengkapnya tentang konfigurasi perubahan yang terjadi saat program berjalan dan cara menanganinya
    ++, bacalah panduan untuk <a href="{@docRoot}guide/topics/resources/runtime-changes.html">Menangani
    ++Perubahan Runtime</a>.</p>
    ++
    ++
    ++
    ++<h3 id="CoordinatingActivities">Mengoordinasikan aktivitas</h3>
    ++
    ++ <p>Bila suatu aktivitas memulai aktivitas lain, keduanya akan mengalami transisi daur hidup. Aktivitas pertama
    ++akan berhenti sementara dan berhenti sama sekali (walau tidak akan berhenti jika masih terlihat di latar belakang), saat
    ++aktivitas lain dibuat. Jika aktivitas-aktivitas ini berbagi data yang disimpan ke disk atau di tempat lain, Anda perlu
    ++memahami bahwa aktivitas pertama tidak dihentikan sepenuhnya sebelum aktivitas kedua dibuat.
    ++Sebagai gantinya, proses akan memulai aktivitas kedua secara tumpang tindih dengan proses penghentian
    ++aktivitas pertama.</p>
    ++
    ++<p>Urutan callback daur hidup didefinisikan dengan baik, khususnya bila kedua aktivitas berada dalam
    ++proses yang sama dan salah satunya memulai yang lain. Berikut ini adalah urutan operasi yang terjadi bila Aktivitas
    ++A memulai Aktivitas B: </p>
    ++
    ++<ol>
    ++<li>Metode {@link android.app.Activity#onPause onPause()} Aktivitas A berjalan.</li>
    ++
    ++<li>Metode-metode {@link android.app.Activity#onCreate onCreate()}, {@link
    ++android.app.Activity#onStart onStart()}, dan {@link android.app.Activity#onResume onResume()}
    ++Aktivitas B berjalan secara berurutan. (Aktivitas B sekarang mendapatkan fokus pengguna.)</li>
    ++
    ++<li>Kemudian, jika Aktivitas A tidak lagi terlihat di layar, metode {@link
    ++android.app.Activity#onStop onStop()}-nya akan dijalankan.</li>
    ++</ol>
    ++
    ++ <p>Urutan callback daur hidup yang bisa diramalkan ini memungkinkan Anda mengelola transisi
    ++informasi dari satu aktivitas ke aktivitas lainnya. Misalnya, jika Anda harus menulis ke database saat
    ++aktivitas pertama berhenti agar aktivitas berikutnya bisa membacanya, maka Anda harus menulis ke
    ++database selama {@link android.app.Activity#onPause onPause()} sebagai ganti selama {@link
    ++android.app.Activity#onStop onStop()}.</p>
    ++
    ++<!--
    ++<h2>Beginner's Path</h2>
    ++
    ++<p>For more information about how Android maintains a history of activities and
    ++enables user multitasking, continue with the <b><a
    ++href="{@docRoot}guide/components/tasks-and-back-stack.html">Tasks and Back
    ++Stack</a></b> document.</p>
    ++-->
    +diff --git a/docs/html-intl/intl/id/guide/components/bound-services.jd b/docs/html-intl/intl/id/guide/components/bound-services.jd
    +new file mode 100644
    +index 0000000..6e5e65a
    +--- /dev/null
    ++++ b/docs/html-intl/intl/id/guide/components/bound-services.jd
    +@@ -0,0 +1,658 @@
    ++page.title=Layanan Terikat
    ++parent.title=Layanan
    ++parent.link=services.html
    ++@jd:body
    ++
    ++
    ++<div id="qv-wrapper">
    ++<ol id="qv">
    ++<h2>Dalam dokumen ini</h2>
    ++<ol>
    ++  <li><a href="#Basics">Dasar-Dasar</a></li>
    ++  <li><a href="#Creating">Membuat Layanan Terikat</a>
    ++    <ol>
    ++      <li><a href="#Binder">Memperluas kelas Binder</a></li>
    ++      <li><a href="#Messenger">Menggunakan Messenger</a></li>
    ++    </ol>
    ++  </li>
    ++  <li><a href="#Binding">Mengikat ke Layanan</a></li>
    ++  <li><a href="#Lifecycle">Mengelola Daur Hidup Layanan Terikat</a></li>
    ++</ol>
    ++
    ++<h2>Kelas-kelas utama</h2>
    ++<ol>
    ++  <li>{@link android.app.Service}</li>
    ++  <li>{@link android.content.ServiceConnection}</li>
    ++  <li>{@link android.os.IBinder}</li>
    ++</ol>
    ++
    ++<h2>Contoh</h2>
    ++<ol>
    ++  <li><a href="{@docRoot}resources/samples/ApiDemos/src/com/example/android/apis/app/RemoteService.html">{@code
    ++      RemoteService}</a></li>
    ++  <li><a href="{@docRoot}resources/samples/ApiDemos/src/com/example/android/apis/app/LocalService.html">{@code
    ++      LocalService}</a></li>
    ++</ol>
    ++
    ++<h2>Lihat juga</h2>
    ++<ol>
    ++  <li><a href="{@docRoot}guide/components/services.html">Layanan</a></li>
    ++</ol>
    ++</div>
    ++
    ++
    ++<p>Layanan terikat adalah server di antarmuka klien-server. Layanan terikat memungkinkan komponen-komponen
    ++(seperti aktivitas) untuk diikat ke layanan, mengirim permintaan, menerima respons, dan bahkan melakukan
    ++komunikasi antarproses (IPC). Layanan terikat biasanya hidup hanya saat melayani
    ++komponen aplikasi lain dan tidak berjalan di latar belakang terus-menerus.</p>
    ++
    ++<p>Dokumen ini menampilkan cara membuat layanan terikat, termasuk cara mengikat
    ++ke layanan dari komponen aplikasi lain. Akan tetapi, Anda juga harus mengacu dokumen <a href="{@docRoot}guide/components/services.html">Layanan</a> untuk
    ++informasi tambahan tentang layanan secara umum, seperti cara menyampaikan pemberitahuan dari layanan, mengatur
    ++layanan agar berjalan di latar depan, dan lain-lain.</p>
    ++
    ++
    ++<h2 id="Basics">Dasar-Dasar</h2>
    ++
    ++<p>Layanan terikat adalah implementasi kelas {@link android.app.Service} yang memungkinkan
    ++aplikasi lain diikat padanya dan berinteraksi dengannya. Untuk menyediakan pengikatan bagi sebuah
    ++layanan, Anda harus mengimplementasikan metode callback {@link android.app.Service#onBind onBind()}. Metode ini
    ++menghasilkan objek {@link android.os.IBinder} yang mendefinisikan antarmuka pemprograman yang
    ++bisa digunakan klien untuk berinteraksi dengan layanan.</p>
    ++
    ++<div class="sidebox-wrapper">
    ++<div class="sidebox">
    ++  <h3>Mengikat ke Layanan yang Sudah Dimulai</h3>
    ++
    ++<p>Seperti dibahas dalam dokumen <a href="{@docRoot}guide/components/services.html">Layanan</a>
    ++, Anda bisa membuat layanan yang dimulai sekaligus diikat. Yakni, layanan bisa
    ++dimulai dengan memanggil {@link android.content.Context#startService startService()}, yang memungkinkan
    ++layanan berjalan terus-menerus, dan juga membolehkan klien untuk mengikat ke layanan dengan memanggil {@link
    ++android.content.Context#bindService bindService()}.
    ++  <p>Jika Anda mengizinkan layanan dimulai dan diikat, lalu ketika layanan telah
    ++dimulai, sistem <em>tidak</em> menghapus layanan ketika semua klien melepas ikatan. Sebagai gantinya, Anda harus
    ++menghentikan layanan secara eksplisit, dengan memanggil {@link android.app.Service#stopSelf stopSelf()} atau {@link
    ++android.content.Context#stopService stopService()}.</p>
    ++
    ++<p>Walaupun Anda biasanya harus mengimplementasikan {@link android.app.Service#onBind onBind()}
    ++<em>atau</em> {@link android.app.Service#onStartCommand onStartCommand()}, kadang-kadang perlu
    ++mengimplementasikan keduanya. Misalnya, sebuah pemutar musik bisa merasakan manfaatnya karena layanannya boleh berjalan
    ++terus-menerus dan juga menyediakan pengikatan. Dengan cara ini, sebuah aktivitas bisa memulai layanan untuk memutar beberapa
    ++lagu dan musik terus dimainkan sekalipun pengguna meninggalkan aplikasi. Lalu, bila pengguna
    ++kembali ke aplikasi, aktivitas bisa mengikat ke layanan untuk mendapatkan kembali kontrol atas pemutaran.</p>
    ++
    ++<p>Pastikan membaca bagian tentang <a href="#Lifecycle">Mengelola Daur Hidup Layanan
    ++Terikat</a>, untuk informasi selengkapnya tentang daur hidup layanan saat menambahkan pengikatan ke
    ++layanan yang sudah dimulai.</p>
    ++</div>
    ++</div>
    ++
    ++<p>Klien bisa mengikat ke layanan dengan memanggil {@link android.content.Context#bindService
    ++bindService()}. Bila itu dilakukan, klien harus menyediakan implementasi {@link
    ++android.content.ServiceConnection}, yang memantau koneksi dengan layanan. Metode {@link
    ++android.content.Context#bindService bindService()} kembali dengan serta-merta tanpa sebuah nilai, namun
    ++bila sistem Android membuat koneksi antara klien
    ++dan layanan, sistem akan memanggil {@link
    ++android.content.ServiceConnection#onServiceConnected onServiceConnected()} pada {@link
    ++android.content.ServiceConnection} untuk mengirim {@link android.os.IBinder} yang
    ++bisa digunakan klien untuk berkomunikasi dengan layanan.</p>
    ++
    ++<p>Beberapa klien bisa terhubung ke layanan dengan serentak. Akan tetapi, sistem akan memanggil metode
    ++{@link android.app.Service#onBind onBind()} layanan Anda untuk mengambil {@link android.os.IBinder} hanya
    ++bila klien pertama mengikat. Sistem lalu memberikan {@link android.os.IBinder} yang sama ke setiap
    ++klien tambahan yang mengikat, tanpa memanggil {@link android.app.Service#onBind onBind()} lagi.</p>
    ++
    ++<p>Bila klien terakhir melepas ikatan dari layanan, sistem akan menghapus layanan (kecuali jika
    ++layanan juga dimulai oleh {@link android.content.Context#startService startService()}).</p>
    ++
    ++<p>Bila Anda mengimplementasikan layanan terikat, yang terpenting adalah mendefinisikan antarmuka
    ++yang dihasilkan metode callback {@link android.app.Service#onBind onBind()} Anda. Ada sedikit
    ++cara mendefinisikan antarmuka {@link android.os.IBinder} layanan Anda dan bagian berikut
    ++akan membahas masing-masing teknik.</p>
    ++
    ++
    ++
    ++<h2 id="Creating">Membuat Layanan Terikat</h2>
    ++
    ++<p>Saat membuat layanan yang menyediakan pengikatan, Anda harus menyediakan {@link android.os.IBinder}
    ++yang menyediakan antarmuka pemrograman yang bisa digunakan klien untuk berinteraksi dengan layanan. Ada
    ++tiga cara untuk mendefinisikan antarmuka:</p>
    ++
    ++<dl>
    ++  <dt><a href="#Binder">Memperluas kelas Binder</a></dt>
    ++  <dd>Jika layanan Anda bersifat privat untuk aplikasi Anda sendiri dan berjalan dalam proses yang sama dengan klien
    ++(biasanya), Anda harus membuat antarmuka dengan memperluas kelas {@link android.os.Binder}
    ++dan menghasilkan instance dari
    ++{@link android.app.Service#onBind onBind()}. Klien akan menerima {@link android.os.Binder} dan
    ++bisa menggunakannya untuk mengakses langsung metode publik yang tersedia dalam implementasi {@link android.os.Binder}
    ++atau bahkan {@link android.app.Service}.
    ++  <p>Inilah teknik yang lebih disukai bila layanan Anda sekadar pekerja latar belakang untuk aplikasi Anda
    ++sendiri. Satu-satunya alasan tidak membuat antarmuka dengan cara ini adalah karena
    ++layanan Anda akan digunakan oleh aplikasi lain atau pada proses-proses terpisah.</dd>
    ++
    ++  <dt><a href="#Messenger">Menggunakan Messenger</a></dt>
    ++  <dd>Jika antarmuka Anda perlu bekerja lintas proses, Anda bisa membuat
    ++antarmuka untuk layanan dengan {@link android.os.Messenger}. Dengan cara ini, layanan
    ++mendefinisikan {@link android.os.Handler} yang akan merespons aneka tipe objek {@link
    ++android.os.Message}. {@link android.os.Handler}
    ++ini adalah dasar bagi {@link android.os.Messenger} yang nanti bisa berbagi {@link android.os.IBinder}
    ++dengan klien, sehingga memungkinkan klien mengirim perintah ke layanan dengan menggunakan objek {@link
    ++android.os.Message}. Selain itu, klien bisa mendefinisikan sendiri {@link android.os.Messenger}
    ++sehingga layanan bisa mengirim balik pesan.
    ++  <p>Inilah cara termudah melakukan komunikasi antarproses (IPC), karena {@link
    ++android.os.Messenger} akan mengantre semua permintaan ke dalam satu thread sehingga Anda tidak perlu mendesain
    ++layanan agar thread-safe.</p>
    ++  </dd>
    ++
    ++  <dt>Menggunakan AIDL</dt>
    ++  <dd>AIDL (Android Interface Definition Language) melakukan semua pekerjaan untuk mengurai objek menjadi
    ++primitif yang bisa dipahami dan diarahkan oleh sistem operasi ke berbagai proses untuk melakukan
    ++IPC. Teknik sebelumnya, dengan menggunakan {@link android.os.Messenger}, sebenarnya berdasarkan AIDL sebagai
    ++struktur yang mendasarinya. Seperti disebutkan di atas, {@link android.os.Messenger} membuat antrean
    ++semua permintaan klien dalam satu thread, sehingga layanan akan menerima permintaan satu per satu. Akan tetapi,
    ++jika ingin layanan Anda menangani beberapa permintaan sekaligus, Anda bisa menggunakan AIDL
    ++secara langsung. Dalam hal ini, layanan Anda harus mampu multi-thread dan dibuat thread-safe.
    ++  <p>Untuk menggunakan AIDL secara langsung, Anda harus
    ++membuat file {@code .aidl} yang mendefinisikan antarmuka pemrograman. Alat Android SDK menggunakan
    ++file ini untuk menghasilkan kelas abstrak yang mengimplementasikan antarmuka dan menangani IPC, yang nanti
    ++bisa Anda perluas dalam layanan.</p>
    ++  </dd>
    ++</dl>
    ++
    ++  <p class="note"><strong>Catatan:</strong> Umumnya aplikasi <strong>tidak boleh</strong> menggunakan AIDL untuk
    ++membuat layanan terikat, karena hal itu mungkin memerlukan kemampuan multi-thread dan
    ++bisa mengakibatkan implementasi yang lebih rumit. Dengan demikian, AIDL tidak cocok untuk sebagian besar aplikasi
    ++dan dokumen ini tidak membahas cara menggunakannya untuk layanan Anda. Jika Anda yakin perlu
    ++menggunakan AIDL secara langsung, lihat dokumen <a href="{@docRoot}guide/components/aidl.html">AIDL</a>
    ++.</p>
    ++
    ++
    ++
    ++
    ++<h3 id="Binder">Memperluas kelas Binder</h3>
    ++
    ++<p>Jika layanan Anda hanya digunakan oleh aplikasi lokal dan tidak perlu bekerja lintas proses,
    ++maka Anda bisa mengimplementasikan kelas {@link android.os.Binder} Anda sendiri yang memberi klien Anda
    ++akses langsung ke metode publik dalam layanan.</p>
    ++
    ++<p class="note"><strong>Catatan:</strong> Hal ini hanya berhasil jika klien dan layanan berada dalam
    ++aplikasi dan proses yang sama, suatu kondisi yang paling umum. Misalnya, cara ini sangat cocok untuk sebuah aplikasi musik
    ++yang perlu mengikat aktivitas ke layanannya sendiri, yakni memutar musik di
    ++latar belakang.</p>
    ++
    ++<p>Berikut cara menyiapkannya:</p>
    ++<ol>
    ++  <li>Dalam layanan Anda, buat sebuah instance {@link android.os.Binder} yang:
    ++    <ul>
    ++      <li>berisi metode publik yang bisa dipanggil klien</li>
    ++      <li>menghasilkan instance {@link android.app.Service} saat ini, yang memiliki metode publik yang
    ++bisa dipanggil klien</li>
    ++      <li>atau, menghasilkan instance kelas lain yang host-nya di layanan dengan metode publik yang
    ++bisa dipanggil klien</li>
    ++    </ul>
    ++  <li>Hasilkan instance {@link android.os.Binder} ini dari metode callback {@link
    ++android.app.Service#onBind onBind()}.</li>
    ++  <li>Di klien, terima {@link android.os.Binder} dari metode callback {@link
    ++android.content.ServiceConnection#onServiceConnected onServiceConnected()} dan
    ++buat panggilan ke layanan terikat dengan menggunakan metode yang disediakan.</li>
    ++</ol>
    ++
    ++<p class="note"><strong>Catatan:</strong> Alasan layanan dan klien harus berada dalam aplikasi yang sama
    ++adalah agar klien bisa mengkonversi objek yang dihasilkan dan memanggil API-nya dengan benar. Layanan
    ++dan klien juga harus berada dalam proses yang sama, karena teknik ini tidak melakukan
    ++pengarahan (marshalling) apa pun untuk lintas proses.</p>
    ++
    ++<p>Misalnya, berikut ini adalah layanan yang memberi klien akses ke metode-metode dalam layanan melalui
    ++implementasi {@link android.os.Binder}:</p>
    ++
    ++<pre>
    ++public class LocalService extends Service {
    ++    // Binder given to clients
    ++    private final IBinder mBinder = new LocalBinder();
    ++    // Random number generator
    ++    private final Random mGenerator = new Random();
    ++
    ++    /**
    ++     * Class used for the client Binder.  Because we know this service always
    ++     * runs in the same process as its clients, we don't need to deal with IPC.
    ++     */
    ++    public class LocalBinder extends Binder {
    ++        LocalService getService() {
    ++            // Return this instance of LocalService so clients can call public methods
    ++            return LocalService.this;
    ++        }
    ++    }
    ++
    ++    &#64;Override
    ++    public IBinder onBind(Intent intent) {
    ++        return mBinder;
    ++    }
    ++
    ++    /** method for clients */
    ++    public int getRandomNumber() {
    ++      return mGenerator.nextInt(100);
    ++    }
    ++}
    ++</pre>
    ++
    ++<p>{@code LocalBinder} menyediakan {@code getService()} metode bagi klien untuk mengambil
    ++instance {@code LocalService} saat ini. Cara ini memungkinkan klien memanggil metode publik dalam
    ++layanan. Misalnya, klien bisa memanggil {@code getRandomNumber()} dari layanan.</p>
    ++
    ++<p>Berikut ini adalah aktivitas yang mengikat ke {@code LocalService} dan memanggil {@code getRandomNumber()}
    ++bila tombol diklik:</p>
    ++
    ++<pre>
    ++public class BindingActivity extends Activity {
    ++    LocalService mService;
    ++    boolean mBound = false;
    ++
    ++    &#64;Override
    ++    protected void onCreate(Bundle savedInstanceState) {
    ++        super.onCreate(savedInstanceState);
    ++        setContentView(R.layout.main);
    ++    }
    ++
    ++    &#64;Override
    ++    protected void onStart() {
    ++        super.onStart();
    ++        // Bind to LocalService
    ++        Intent intent = new Intent(this, LocalService.class);
    ++        bindService(intent, mConnection, Context.BIND_AUTO_CREATE);
    ++    }
    ++
    ++    &#64;Override
    ++    protected void onStop() {
    ++        super.onStop();
    ++        // Unbind from the service
    ++        if (mBound) {
    ++            unbindService(mConnection);
    ++            mBound = false;
    ++        }
    ++    }
    ++
    ++    /** Called when a button is clicked (the button in the layout file attaches to
    ++      * this method with the android:onClick attribute) */
    ++    public void onButtonClick(View v) {
    ++        if (mBound) {
    ++            // Call a method from the LocalService.
    ++            // However, if this call were something that might hang, then this request should
    ++            // occur in a separate thread to avoid slowing down the activity performance.
    ++            int num = mService.getRandomNumber();
    ++            Toast.makeText(this, "number: " + num, Toast.LENGTH_SHORT).show();
    ++        }
    ++    }
    ++
    ++    /** Defines callbacks for service binding, passed to bindService() */
    ++    private ServiceConnection mConnection = new ServiceConnection() {
    ++
    ++        &#64;Override
    ++        public void onServiceConnected(ComponentName className,
    ++                IBinder service) {
    ++            // We've bound to LocalService, cast the IBinder and get LocalService instance
    ++            LocalBinder binder = (LocalBinder) service;
    ++            mService = binder.getService();
    ++            mBound = true;
    ++        }
    ++
    ++        &#64;Override
    ++        public void onServiceDisconnected(ComponentName arg0) {
    ++            mBound = false;
    ++        }
    ++    };
    ++}
    ++</pre>
    ++
    ++<p>Contoh di atas menampilkan cara klien mengikat ke layanan dengan menggunakan implementasi
    ++{@link android.content.ServiceConnection} dan callback {@link
    ++android.content.ServiceConnection#onServiceConnected onServiceConnected()}. Bagian
    ++berikut menyediakan informasi selengkapnya tentang proses pengikatan ke layanan.</p>
    ++
    ++<p class="note"><strong>Catatan:</strong> Contoh di atas tidak secara eksplisit melepas ikatan dari layanan,
    ++namun semua klien harus melepas ikatan pada waktu yang tepat (seperti saat aktivitas sedang jeda).</p>
    ++
    ++<p>Untuk contoh kode selengkapnya, lihat kelas <a href="{@docRoot}resources/samples/ApiDemos/src/com/example/android/apis/app/LocalService.html">{@code
    ++LocalService.java}</a> dan kelas <a href="{@docRoot}resources/samples/ApiDemos/src/com/example/android/apis/app/LocalServiceActivities.html">{@code
    ++LocalServiceActivities.java}</a> dalam <a href="{@docRoot}resources/samples/ApiDemos/index.html">ApiDemos</a>.</p>
    ++
    ++
    ++
    ++
    ++
    ++<h3 id="Messenger">Menggunakan Messenger</h3>
    ++
    ++<div class="sidebox-wrapper">
    ++<div class="sidebox">
    ++  <h4>Dibandingkan dengan AIDL</h4>
    ++  <p>Bila Anda perlu melakukan IPC, menggunakan {@link android.os.Messenger} untuk antarmuka
    ++lebih sederhana daripada mengimplementasikannya dengan AIDL, karena {@link android.os.Messenger} mengantre
    ++semua panggilan ke layanan, sementara antarmuka AIDL murni mengirim permintaan serentak ke
    ++layanan, yang nanti harus menangani multi-threading.</p>
    ++  <p>Untuk sebagian besar aplikasi, layanan tidak perlu melakukan multi-threading, jadi dengan menggunakan {@link
    ++android.os.Messenger} memungkinkan layanan menangani panggilan satu per satu. Jika
    ++layanan harus multi-thread, Anda harus menggunakan <a href="{@docRoot}guide/components/aidl.html">AIDL</a> untuk mendefinisikan antarmuka.</p>
    ++</div>
    ++</div>
    ++
    ++<p>Jika layanan perlu berkomunikasi dengan proses jauh, Anda bisa menggunakan
    ++{@link android.os.Messenger} untuk menyediakan antarmuka bagi layanan Anda. Teknik ini memungkinkan
    ++Anda melakukan komunikasi antarproses (IPC) tanpa harus menggunakan AIDL.</p>
    ++
    ++<p>Berikut ini rangkuman cara menggunakan {@link android.os.Messenger}:</p>
    ++
    ++<ul>
    ++  <li>Layanan mengimplementasikan {@link android.os.Handler} yang menerima callback untuk tiap
    ++panggilan dari klien.</li>
    ++  <li>{@link android.os.Handler} digunakan untuk membuat objek {@link android.os.Messenger}
    ++(yang merupakan acuan ke {@link android.os.Handler}).</li>
    ++  <li>{@link android.os.Messenger} membuat {@link android.os.IBinder} yang
    ++dikembalikan layanan ke klien dari {@link android.app.Service#onBind onBind()}.</li>
    ++  <li>Klien menggunakan {@link android.os.IBinder} untuk membuat instance {@link android.os.Messenger}
    ++(yang mengacu {@link android.os.Handler} layanan), yang digunakan klien untuk mengirim
    ++objek {@link android.os.Message} ke layanan.</li>
    ++  <li>Layanan menerima setiap {@link android.os.Message} dalam {@link
    ++android.os.Handler}&mdash;secara spesifik, dalam metode {@link android.os.Handler#handleMessage
    ++handleMessage()}.</li>
    ++</ul>
    ++
    ++
    ++<p>Dengan cara ini, tidak ada "metode" untuk dipanggil klien pada layanan. Sebagai gantinya,
    ++klien mengirim "pesan" (objek-objek {@link android.os.Message}) yang diterima layanan dalam
    ++{@link android.os.Handler}-nya.</p>
    ++
    ++<p>Berikut ini contoh layanan sederhana yang menggunakan antarmuka {@link android.os.Messenger}:</p>
    ++
    ++<pre>
    ++public class MessengerService extends Service {
    ++    /** Command to the service to display a message */
    ++    static final int MSG_SAY_HELLO = 1;
    ++
    ++    /**
    ++     * Handler of incoming messages from clients.
    ++     */
    ++    class IncomingHandler extends Handler {
    ++        &#64;Override
    ++        public void handleMessage(Message msg) {
    ++            switch (msg.what) {
    ++                case MSG_SAY_HELLO:
    ++                    Toast.makeText(getApplicationContext(), "hello!", Toast.LENGTH_SHORT).show();
    ++                    break;
    ++                default:
    ++                    super.handleMessage(msg);
    ++            }
    ++        }
    ++    }
    ++
    ++    /**
    ++     * Target we publish for clients to send messages to IncomingHandler.
    ++     */
    ++    final Messenger mMessenger = new Messenger(new IncomingHandler());
    ++
    ++    /**
    ++     * When binding to the service, we return an interface to our messenger
    ++     * for sending messages to the service.
    ++     */
    ++    &#64;Override
    ++    public IBinder onBind(Intent intent) {
    ++        Toast.makeText(getApplicationContext(), "binding", Toast.LENGTH_SHORT).show();
    ++        return mMessenger.getBinder();
    ++    }
    ++}
    ++</pre>
    ++
    ++<p>Perhatikan bahwa metode {@link android.os.Handler#handleMessage handleMessage()} dalam
    ++{@link android.os.Handler} adalah tempat layanan menerima {@link android.os.Message}
    ++yang masuk dan memutuskan aksi yang harus dilakukan, berdasarkan anggota {@link android.os.Message#what}.</p>
    ++
    ++<p>Klien tinggal membuat {@link android.os.Messenger} berdasarkan {@link
    ++android.os.IBinder} yang dihasilkan layanan dan mengirim pesan menggunakan {@link
    ++android.os.Messenger#send send()}. Misalnya, berikut ini adalah aktivitas sederhana yang mengikat ke
    ++layanan dan mengirim pesan {@code MSG_SAY_HELLO} ke layanan:</p>
    ++
    ++<pre>
    ++public class ActivityMessenger extends Activity {
    ++    /** Messenger for communicating with the service. */
    ++    Messenger mService = null;
    ++
    ++    /** Flag indicating whether we have called bind on the service. */
    ++    boolean mBound;
    ++
    ++    /**
    ++     * Class for interacting with the main interface of the service.
    ++     */
    ++    private ServiceConnection mConnection = new ServiceConnection() {
    ++        public void onServiceConnected(ComponentName className, IBinder service) {
    ++            // This is called when the connection with the service has been
    ++            // established, giving us the object we can use to
    ++            // interact with the service.  We are communicating with the
    ++            // service using a Messenger, so here we get a client-side
    ++            // representation of that from the raw IBinder object.
    ++            mService = new Messenger(service);
    ++            mBound = true;
    ++        }
    ++
    ++        public void onServiceDisconnected(ComponentName className) {
    ++            // This is called when the connection with the service has been
    ++            // unexpectedly disconnected -- that is, its process crashed.
    ++            mService = null;
    ++            mBound = false;
    ++        }
    ++    };
    ++
    ++    public void sayHello(View v) {
    ++        if (!mBound) return;
    ++        // Create and send a message to the service, using a supported 'what' value
    ++        Message msg = Message.obtain(null, MessengerService.MSG_SAY_HELLO, 0, 0);
    ++        try {
    ++            mService.send(msg);
    ++        } catch (RemoteException e) {
    ++            e.printStackTrace();
    ++        }
    ++    }
    ++
    ++    &#64;Override
    ++    protected void onCreate(Bundle savedInstanceState) {
    ++        super.onCreate(savedInstanceState);
    ++        setContentView(R.layout.main);
    ++    }
    ++
    ++    &#64;Override
    ++    protected void onStart() {
    ++        super.onStart();
    ++        // Bind to the service
    ++        bindService(new Intent(this, MessengerService.class), mConnection,
    ++            Context.BIND_AUTO_CREATE);
    ++    }
    ++
    ++    &#64;Override
    ++    protected void onStop() {
    ++        super.onStop();
    ++        // Unbind from the service
    ++        if (mBound) {
    ++            unbindService(mConnection);
    ++            mBound = false;
    ++        }
    ++    }
    ++}
    ++</pre>
    ++
    ++<p>Perhatikan bahwa contoh ini tidak menampilkan cara layanan merespons klien. Jika ingin
    ++layanan merespons, Anda juga perlu membuat {@link android.os.Messenger} di klien. Lalu
    ++saat menerima callback {@link android.content.ServiceConnection#onServiceConnected
    ++onServiceConnected()}, klien akan mengirim {@link android.os.Message} ke layanan yang berisi
    ++{@link android.os.Messenger} klien dalam parameter {@link android.os.Message#replyTo}
    ++metode {@link android.os.Messenger#send send()}.</p>
    ++
    ++<p>Anda bisa melihat contoh cara menyediakan pertukaran pesan dua arah dalam contoh <a href="{@docRoot}resources/samples/ApiDemos/src/com/example/android/apis/app/MessengerService.html">{@code
    ++MessengerService.java}</a> (layanan) dan <a href="{@docRoot}resources/samples/ApiDemos/src/com/example/android/apis/app/MessengerServiceActivities.html">{@code
    ++MessengerServiceActivities.java}</a> (klien).</p>
    ++
    ++
    ++
    ++
    ++
    ++<h2 id="Binding">Mengikat ke Layanan</h2>
    ++
    ++<p>Komponen-komponen aplikasi (klien) bisa mengikat ke layanan dengan memanggil
    ++{@link android.content.Context#bindService bindService()}. Sistem Android
    ++lalu memanggil metode {@link android.app.Service#onBind
    ++onBind()} layanan, yang menghasilkan {@link android.os.IBinder} untuk berinteraksi dengan layanan.</p>
    ++
    ++<p>Pengikatan ini bersifat asinkron. {@link android.content.Context#bindService
    ++bindService()} segera kembali dan <em>tidak</em> mengembalikan {@link android.os.IBinder} ke
    ++klien. Untuk menerima {@link android.os.IBinder}, klien harus membuat instance {@link
    ++android.content.ServiceConnection} dan meneruskannya ke {@link android.content.Context#bindService
    ++bindService()}. {@link android.content.ServiceConnection} berisi metode callback yang
    ++dipanggil sistem untuk mengirim {@link android.os.IBinder}.</p>
    ++
    ++<p class="note"><strong>Catatan:</strong> Hanya aktivitas, layanan, dan penyedia konten yang bisa mengikat
    ++ke layanan yang&mdash;Anda <strong>tidak bisa</strong> ikat ke layanan dari penerima siaran.</p>
    ++
    ++<p>Jadi, untuk mengikat ke layanan dari klien, Anda harus: </p>
    ++<ol>
    ++  <li>Mengimplementasikan {@link android.content.ServiceConnection}.
    ++    <p>Implementasi Anda harus mengesampingkan dua metode callback:</p>
    ++    <dl>
    ++      <dt>{@link android.content.ServiceConnection#onServiceConnected onServiceConnected()}</dt>
    ++        <dd>Sistem memanggil ini untuk mengirim {@link android.os.IBinder} yang dihasilkan oleh
    ++metode {@link android.app.Service#onBind onBind()} layanan.</dd>
    ++      <dt>{@link android.content.ServiceConnection#onServiceDisconnected
    ++onServiceDisconnected()}</dt>
    ++        <dd>Sistem Android memanggil ini bila koneksi ke layanan putus
    ++tanpa terduga, seperti ketika layanan mengalami crash atau dimatikan. Ini <em>tidak</em> dipanggil ketika
    ++klien melepas ikatan.</dd>
    ++    </dl>
    ++  </li>
    ++  <li>Panggil {@link
    ++android.content.Context#bindService bindService()}, dengan meneruskan implementasi {@link
    ++android.content.ServiceConnection}. </li>
    ++  <li>Bila sistem memanggil metode callback {@link android.content.ServiceConnection#onServiceConnected
    ++onServiceConnected()}, Anda bisa mulai membuat panggilan ke layanan, dengan menggunakan
    ++metode yang didefinisikan oleh antarmuka.</li>
    ++  <li>Untuk memutus koneksi dari layanan, panggil {@link
    ++android.content.Context#unbindService unbindService()}.
    ++    <p>Bila telah dimusnahkan (destroyed), klien Anda akan melepas ikatan dari layanan, namun Anda harus selalu melepas ikatan
    ++bila sudah selesai berinteraksi dengan layanan atau bila aktivitas Anda sedang jeda sehingga layanan bisa
    ++dimatikan saat tidak sedang digunakan. (Waktu yang tepat untuk mengikat dan melepas ikatan dibahas
    ++selengkapnya di bawah ini.)</p>
    ++  </li>
    ++</ol>
    ++
    ++<p>Misalnya, cuplikan berikut menghubungkan klien ke layanan yang dibuat di atas dengan
    ++<a href="#Binder">memperluas kelas Binder</a>, sehingga tinggal mengkonversi
    ++{@link android.os.IBinder} yang dihasilkan ke kelas {@code LocalService} dan meminta instance {@code
    ++LocalService}:</p>
    ++
    ++<pre>
    ++LocalService mService;
    ++private ServiceConnection mConnection = new ServiceConnection() {
    ++    // Called when the connection with the service is established
    ++    public void onServiceConnected(ComponentName className, IBinder service) {
    ++        // Because we have bound to an explicit
    ++        // service that is running in our own process, we can
    ++        // cast its IBinder to a concrete class and directly access it.
    ++        LocalBinder binder = (LocalBinder) service;
    ++        mService = binder.getService();
    ++        mBound = true;
    ++    }
    ++
    ++    // Called when the connection with the service disconnects unexpectedly
    ++    public void onServiceDisconnected(ComponentName className) {
    ++        Log.e(TAG, "onServiceDisconnected");
    ++        mBound = false;
    ++    }
    ++};
    ++</pre>
    ++
    ++<p>Dengan {@link android.content.ServiceConnection} ini, klien bisa mengikat ke layanan dengan meneruskannya
    ++ke {@link android.content.Context#bindService bindService()}. Misalnya:</p>
    ++
    ++<pre>
    ++Intent intent = new Intent(this, LocalService.class);
    ++bindService(intent, mConnection, Context.BIND_AUTO_CREATE);
    ++</pre>
    ++
    ++<ul>
    ++  <li>Parameter pertama {@link android.content.Context#bindService bindService()} adalah sebuah
    ++{@link android.content.Intent} yang secara eksplisit menyebutkan layanan yang akan diikat (walaupun intent
    ++boleh implisit).</li>
    ++<li>Parameter kedua adalah objek {@link android.content.ServiceConnection}.</li>
    ++<li>Parameter ketiga adalah tanda (flag) yang menunjukkan opsi pengikatan. Tanda ini biasanya harus {@link
    ++android.content.Context#BIND_AUTO_CREATE} agar dapat membuat layanan jika belum hidup.
    ++Nilai-nilai lain yang memungkinkan adalah {@link android.content.Context#BIND_DEBUG_UNBIND}
    ++dan {@link android.content.Context#BIND_NOT_FOREGROUND}, atau {@code 0} untuk tidak satu pun.</li>
    ++</ul>
    ++
    ++
    ++<h3>Catatan tambahan</h3>
    ++
    ++<p>Berikut ini beberapa catatan penting tentang mengikat ke layanan:</p>
    ++<ul>
    ++  <li>Anda harus selalu menjebak eksepsi {@link android.os.DeadObjectException}, yang dilontarkan
    ++bila koneksi terputus. Inilah satu-satunya eksepsi yang dilontarkan oleh metode jauh.</li>
    ++  <li>Objek adalah acuan yang dihitung lintas proses. </li>
    ++  <li>Anda biasanya harus memasangkan pengikatan dan pelepasan ikatan selama
    ++memasangkan momen membuat dan menghapus daur hidup klien. Misalnya:
    ++    <ul>
    ++      <li>Jika Anda hanya perlu berinteraksi dengan layanan saat aktivitas terlihat, Anda
    ++harus mengikat selama {@link android.app.Activity#onStart onStart()} dan melepas ikatan selama {@link
    ++android.app.Activity#onStop onStop()}.</li>
    ++      <li>Jika Anda ingin aktivitas menerima tanggapan bahkan saat dihentikan di
    ++latar belakang, Anda bisa mengikat selama {@link android.app.Activity#onCreate onCreate()} dan melepas ikatan
    ++selama {@link android.app.Activity#onDestroy onDestroy()}. Berhati-hatilah karena hal ini menyiratkan aktivitas
    ++Anda perlu menggunakan layanan selama dijalankan (sekalipun di latar belakang), jadi jika
    ++layanan berada dalam proses lain, Anda meningkatkan bobot proses dan semakin besar
    ++kemungkinan sistem akan mematikannya.</li>
    ++    </ul>
    ++    <p class="note"><strong>Catatan:</strong> Anda biasanya <strong>tidak</strong> boleh mengikat dan melepas ikatan
    ++selama {@link android.app.Activity#onResume onResume()} aktivitas Anda dan {@link
    ++android.app.Activity#onPause onPause()}, karena callback ini terjadi pada setiap transisi daur hidup
    ++dan Anda harus menjaga pemrosesan yang terjadi pada transisi ini tetap minim. Juga, jika
    ++banyak aktivitas dalam aplikasi Anda mengikat ke layanan yang sama dan ada transisi antara
    ++dua aktivitas, layanan bisa dimusnahkan dan dibuat lagi sambil aktivitas saat ini melepas ikatan
    ++(selama jeda) sebelum aktivitas berikutnya mengikat (selama lanjutkan). (Transisi aktivitas ini untuk cara
    ++aktivitas mengoordinasikan daur hidupnya dijelaskan dalam dokumen <a href="{@docRoot}guide/components/activities.html#CoordinatingActivities">Aktivitas</a>
    ++.)</p>
    ++</ul>
    ++
    ++<p>Untuk contoh kode selengkapnya, yang menampilkan cara mengikat ke layanan, lihat kelas <a href="{@docRoot}resources/samples/ApiDemos/src/com/example/android/apis/app/RemoteService.html">{@code
    ++RemoteService.java}</a> dalam <a href="{@docRoot}resources/samples/ApiDemos/index.html">ApiDemos</a>.</p>
    ++
    ++
    ++
    ++
    ++
    ++<h2 id="Lifecycle">Mengelola Daur Hidup Layanan Terikat</h2>
    ++
    ++<p>Bila layanan dilepas ikatannya dari semua klien, sistem Android akan menghapusnya (kecuali jika layanan juga
    ++dimulai dengan {@link android.app.Service#onStartCommand onStartCommand()}). Dengan demikian, Anda tidak harus
    ++mengelola daur hidup layanan jika layanan itu murni sebuah layanan
    ++terikat&mdash;yang dikelola sistem Android untuk Anda berdasarkan apakah layanan terikat ke klien atau tidak.</p>
    ++
    ++<p>Akan tetapi, Jika Anda memilih untuk mengimplementasikan metode callback {@link android.app.Service#onStartCommand
    ++onStartCommand()}, maka Anda harus menghentikan layanan secara eksplisit, karena layanan
    ++sekarang dianggap telah <em>dimulai</em>. Dalam hal ini, layanan akan berjalan hingga layanan
    ++menghentikan dirinya sendiri dengan {@link android.app.Service#stopSelf()} atau panggilan komponen lain {@link
    ++android.content.Context#stopService stopService()}, terlepas dari apakah layanan terikat ke
    ++klien atau tidak.</p>
    ++
    ++<p>Selain itu, jika layanan Anda telah dimulai dan menerima pengikatan, maka saat sistem memanggil
    ++metode {@link android.app.Service#onUnbind onUnbind()}, Anda bisa memilih untuk mengembalikan
    ++{@code true} jika ingin menerima panggilan ke {@link android.app.Service#onRebind
    ++onRebind()} bila nanti klien mengikat ke layanan (sebagai ganti menerima panggilan ke {@link
    ++android.app.Service#onBind onBind()}). {@link android.app.Service#onRebind
    ++onRebind()} akan menghasilkan void, namun klien tetap menerima {@link android.os.IBinder} dalam callback
    ++{@link android.content.ServiceConnection#onServiceConnected onServiceConnected()}.
    ++Di bawah ini adalah gambar 1 yang mengilustrasikan logika untuk jenis daur hidup ini.</p>
    ++
    ++
    ++<img src="{@docRoot}images/fundamentals/service_binding_tree_lifecycle.png" alt="" />
    ++<p class="img-caption"><strong>Gambar 1.</strong> Daur hidup untuk layanan yang dimulai
    ++dan juga memungkinkan pengikatan.</p>
    ++
    ++
    ++<p>Untuk informasi selengkapnya tentang daur hidup layanan yang telah dimulai, lihat dokumen <a href="{@docRoot}guide/components/services.html#Lifecycle">Layanan</a>.</p>
    ++
    ++
    ++
    ++
    +diff --git a/docs/html-intl/intl/id/guide/components/fragments.jd b/docs/html-intl/intl/id/guide/components/fragments.jd
    +new file mode 100644
    +index 0000000..9f7199c
    +--- /dev/null
    ++++ b/docs/html-intl/intl/id/guide/components/fragments.jd
    +@@ -0,0 +1,812 @@
    ++page.title=Fragmen
    ++parent.title=Aktivitas
    ++parent.link=activities.html
    ++@jd:body
    ++
    ++<div id="qv-wrapper">
    ++<div id="qv">
    ++  <h2>Dalam dokumen ini</h2>
    ++  <ol>
    ++    <li><a href="#Design">Filosofi Desain</a></li>
    ++    <li><a href="#Creating">Membuat Fragmen</a>
    ++      <ol>
    ++        <li><a href="#UI">Menambahkan antarmuka pengguna</a></li>
    ++        <li><a href="#Adding">Menambahkan fragmen ke aktivitas</a></li>
    ++      </ol>
    ++    </li>
    ++    <li><a href="#Managing">Mengelola Fragmen</a></li>
    ++    <li><a href="#Transactions">Melakukan Transaksi Fragmen</a></li>
    ++    <li><a href="#CommunicatingWithActivity">Berkomunikasi dengan Aktivitas</a>
    ++      <ol>
    ++        <li><a href="#EventCallbacks">Membuat callback kejadian pada aktivitas</a></li>
    ++        <li><a href="#ActionBar">Menambahkan item ke Action-Bar</a></li>
    ++      </ol>
    ++    </li>
    ++    <li><a href="#Lifecycle">Menangani Daur Hidup Fragmen</a>
    ++      <ol>
    ++        <li><a href="#CoordinatingWithActivity">Mengoordinasi dengan daur hidup aktivitas</a></li>
    ++      </ol>
    ++    </li>
    ++    <li><a href="#Example">Contoh</a></li>
    ++  </ol>
    ++
    ++  <h2>Kelas-kelas utama</h2>
    ++  <ol>
    ++    <li>{@link android.app.Fragment}</li>
    ++    <li>{@link android.app.FragmentManager}</li>
    ++    <li>{@link android.app.FragmentTransaction}</li>
    ++  </ol>
    ++
    ++  <h2>Lihat juga</h2>
    ++  <ol>
    ++    <li><a href="{@docRoot}training/basics/fragments/index.html">Membangun UI Dinamis dengan Fragmen</a></li>
    ++    <li><a href="{@docRoot}guide/practices/tablets-and-handsets.html">Mendukung Tablet
    ++dan Handset</a></li>
    ++  </ol>
    ++</div>
    ++</div>
    ++
    ++<p>{@link android.app.Fragment} mewakili perilaku atau bagian dari antarmuka pengguna dalam
    ++{@link android.app.Activity}. Anda bisa mengombinasikan beberapa fragmen dalam satu aktivitas untuk membangun UI
    ++multipanel dan menggunakan kembali sebuah fragmen dalam beberapa aktivitas. Anda bisa menganggap fragmen sebagai bagian
    ++modular dari aktivitas, yang memiliki daur hidup sendiri, menerima kejadian input sendiri, dan
    ++yang bisa Anda tambahkan atau hapus saat aktivitas berjalan (semacam "sub aktivitas" yang
    ++bisa digunakan kembali dalam aktivitas berbeda).</p>
    ++
    ++<p>Fragmen harus selalu tertanam dalam aktivitas dan daur hidup fragmen secara langsung
    ++dipengaruhi oleh daur hidup aktivitas host-nya. Misalnya, saat aktivitas dihentikan sementara,
    ++semua fragmen di dalamnya juga dihentikan sementara, dan bila aktivitas dimusnahkan, semua fragmen juga demikian. Akan tetapi, saat
    ++aktivitas berjalan (dalam <a href="{@docRoot}guide/components/activities.html#Lifecycle">status daur hidup</a> <em>dilanjutkan</em>, Anda bisa
    ++memanipulasi setiap fragmen secara terpisah, seperti menambah atau menghapusnya. Saat melakukan transaksi
    ++fragmen, Anda juga bisa menambahkannya ke back-stack yang dikelola oleh aktivitas
    ++&mdash;setiap entri back-stack merupakan record transaksi fragmen yang
    ++terjadi. Dengan back-stack pengguna dapat membalikkan transaksi fragmen (mengarah mundur),
    ++dengan menekan tombol <em>Back</em>.</p>
    ++
    ++<p>Bila Anda menambahkan fragmen sebagai bagian dari layout aktivitas, fragmen itu berada dalam {@link
    ++android.view.ViewGroup} di hierarki tampilan aktivitas tersebut dan fragmen mendefinisikan
    ++layout
    ++tampilannya sendiri. Anda bisa menyisipkan fragmen ke dalam layout aktivitas dengan mendeklarasikan fragmen dalam file layout aktivitas
    ++, sebagai elemen {@code &lt;fragment&gt;}, atau dari kode aplikasi dengan menambahkannya ke
    ++ {@link android.view.ViewGroup} yang ada. Akan tetapi, fragmen tidak harus menjadi bagian dari
    ++layout aktivitas; Anda juga bisa menggunakan fragmen tanpa UI-nya sendiri sebagai pekerja tak terlihat untuk
    ++aktivitas tersebut.</p>
    ++
    ++<p>Dokumen ini menjelaskan cara membangun aplikasi menggunakan fragmen, termasuk
    ++cara fragmen mempertahankan statusnya bila ditambahkan ke back-stack aktivitas, berbagi
    ++kejadian dengan aktivitas, dan fragmen lain dalam aktivitas, berkontribusi pada action-bar
    ++aktivitas, dan lainnya.</p>
    ++
    ++
    ++<h2 id="Design">Filosofi Desain</h2>
    ++
    ++<p>Android memperkenalkan fragmen di Android 3.0 (API level 11), terutama untuk mendukung desain UI yang lebih
    ++dinamis dan fleksibel pada layar besar, seperti tablet. Karena
    ++layar tablet jauh lebih besar daripada layar handset, maka lebih banyak ruang untuk mengombinasikan dan
    ++bertukar komponen UI. Fragmen memungkinkan desain seperti itu tanpa perlu mengelola perubahan
    ++kompleks pada hierarki tampilan. Dengan membagi layout aktivitas menjadi beberapa fragmen, Anda bisa
    ++mengubah penampilan aktivitas saat runtime dan mempertahankan perubahan itu di back-stack
    ++yang dikelola oleh aktivitas.</p>
    ++
    ++<p>Misalnya, aplikasi berita bisa menggunakan satu fragmen untuk menampilkan daftar artikel di
    ++sebelah kiri dan fragmen lainnya untuk menampilkan artikel di sebelah kanan&mdash;kedua fragmen ini muncul di satu
    ++aktivitas, berdampingan, dan masing-masing fragmen memiliki serangkaian metode callback daur hidup dan menangani kejadian input
    ++penggunanya sendiri. Sehingga, sebagai ganti menggunakan satu aktivitas untuk memilih
    ++artikel dan aktivitas lainnya untuk membaca artikel, pengguna bisa memilih artikel dan membaca semuanya dalam
    ++aktivitas yang sama, sebagaimana diilustrasikan dalam layout tablet pada gambar 1.</p>
    ++
    ++<p>Anda harus mendesain masing-masing fragmen sebagai komponen aktivitas modular dan bisa digunakan kembali. Yakni, karena
    ++setiap fragmen mendefinisikan layoutnya dan perilakunya dengan callback daur hidupnya sendiri, Anda bisa memasukkan
    ++satu fragmen dalam banyak aktivitas, sehingga Anda harus mendesainnya untuk digunakan kembali dan mencegah
    ++memanipulasi satu fragmen dari fragmen lain secara langsung. Ini terutama penting karena dengan
    ++fragmen modular Anda bisa mengubah kombinasi fragmen untuk ukuran layar berbeda. Saat mendesain aplikasi
    ++untuk mendukung tablet maupun handset, Anda bisa menggunakan kembali fragmen dalam
    ++konfigurasi layout berbeda untuk mengoptimalkan pengalaman pengguna berdasarkan ruang layar yang tersedia. Misalnya
    ++, pada handset, fragmen mungkin perlu dipisahkan untuk menyediakan UI panel tunggal
    ++bila lebih dari satu yang tidak cocok dalam aktivitas yang sama.</p>
    ++
    ++<img src="{@docRoot}images/fundamentals/fragments.png" alt="" />
    ++<p class="img-caption"><strong>Gambar 1.</strong> Contoh cara dua modul UI yang didefinisikan oleh
    ++ fragmen bisa digabungkan ke dalam satu aktivitas untuk desain tablet, namun dipisahkan untuk
    ++desain handset.</p>
    ++
    ++<p>Misalnya&mdash;untuk melanjutkan contoh aplikasi berita&mdash; aplikasi bisa menanamkan
    ++dua fragmen dalam <em>Aktivitas A</em>, saat berjalan pada perangkat berukuran tablet. Akan tetapi, pada
    ++layar berukuran handset, ruang untuk kedua fragmen tidak cukup, sehingga <em>Aktivitas A</em> hanya
    ++menyertakan fragmen untuk daftar artikel, dan saat pengguna memilih artikel,
    ++<em>Aktivitas B</em> akan dimulai, termasuk fragmen kedua untuk membaca artikel. Sehingga, aplikasi mendukung
    ++tablet dan handset dengan menggunakan kembali fragmen dalam kombinasi berbeda, seperti diilustrasikan dalam
    ++gambar 1.</p>
    ++
    ++<p>Untuk informasi selengkapnya tentang mendesain aplikasi menggunakan kombinasi fragmen berbeda
    ++untuk konfigurasi layar berbeda, lihat panduan untuk <a href="{@docRoot}guide/practices/tablets-and-handsets.html">Mendukung Tablet dan Handset</a>.</p>
    ++
    ++
    ++
    ++<h2 id="Creating">Membuat Fragmen</h2>
    ++
    ++<div class="figure" style="width:327px">
    ++<img src="{@docRoot}images/fragment_lifecycle.png" alt="" />
    ++<p class="img-caption"><strong>Gambar 2.</strong> Daur hidup fragmen (saat
    ++ aktivitasnya berjalan).</p>
    ++</div>
    ++
    ++<p>Untuk membuat fragmen, Anda harus membuat subkelas {@link android.app.Fragment} (atau
    ++subkelasnya yang ada). Kelas {@link android.app.Fragment} memiliki kode yang mirip seperti
    ++{@link android.app.Activity}. Kelas ini memiliki metode callback yang serupa dengan aktivitas, seperti
    ++ {@link android.app.Fragment#onCreate onCreate()}, {@link android.app.Fragment#onStart onStart()},
    ++{@link android.app.Fragment#onPause onPause()}, dan {@link android.app.Fragment#onStop onStop()}. Sebenarnya
    ++, jika Anda mengkonversi aplikasi Android saat ini untuk menggunakan fragmen, Anda mungkin cukup memindahkan
    ++kode dari metode callback aktivitas ke masing-masing metode callback
    ++fragmen.</p>
    ++
    ++<p>Biasanya, Anda harus mengimplementasikan setidaknya metode daur hidup berikut ini:</p>
    ++
    ++<dl>
    ++  <dt>{@link android.app.Fragment#onCreate onCreate()}</dt>
    ++  <dd>Sistem akan memanggilnya saat membuat fragmen. Dalam implementasi, Anda harus
    ++menginisialisasi komponen penting dari fragmen yang ingin dipertahankan saat fragmen
    ++dihentikan sementara atau dihentikan, kemudian dilanjutkan.</dd>
    ++  <dt>{@link android.app.Fragment#onCreateView onCreateView()}</dt>
    ++  <dd>Sistem akan memanggilnya saat fragmen menggambar antarmuka penggunanya
    ++untuk yang pertama kali. Untuk menggambar UI fragmen, Anda harus mengembalikan {@link android.view.View} dari metode
    ++ini yang menjadi akar layout fragmen. Hasil yang dikembalikan bisa berupa null jika
    ++fragmen tidak menyediakan UI.</dd>
    ++  <dt>{@link android.app.Activity#onPause onPause()}</dt>
    ++  <dd>Sistem akan memanggil metode ini sebagai indikasi pertama bahwa pengguna sedang meninggalkan
    ++fragmen Anda (walau itu tidak selalu berarti fragmen sedang dimusnahkan). Inilah biasanya tempat Anda
    ++harus mengikat setiap perubahan yang harus dipertahankan selepas sesi pengguna saat ini (karena
    ++pengguna mungkin tidak kembali).</dd>
    ++</dl>
    ++
    ++<p>Kebanyakan aplikasi harus mengimplementasikan setidaknya tiga metode ini untuk setiap fragmen, namun ada
    ++beberapa metode callback lain yang juga harus Anda gunakan untuk menangani berbagai tahap
    ++daur hidup fragmen. Semua metode callback daur hidup akan dibahas secara lebih detail, di bagian
    ++tentang <a href="#Lifecycle">Menangani Daur Hidup Fragmen</a>.</p>
    ++
    ++
    ++<p>Ada juga beberapa subkelas yang mungkin ingin diperpanjang, sebagai ganti kelas basis {@link
    ++android.app.Fragment}:</p>
    ++
    ++<dl>
    ++  <dt>{@link android.app.DialogFragment}</dt>
    ++  <dd>Menampilkan dialog mengambang. Penggunaan kelas ini untuk membuat dialog merupakan alternatif yang baik dari
    ++penggunaan metode helper dialog di kelas {@link android.app.Activity}, karena Anda bisa
    ++menyatukan dialog fragmen ke dalam back-stack fragmen yang dikelola oleh aktivitas,
    ++sehingga pengguna bisa kembali ke fragmen yang ditinggalkan.</dd>
    ++
    ++  <dt>{@link android.app.ListFragment}</dt>
    ++  <dd>Menampilkan daftar item yang dikelola oleh adaptor (seperti {@link
    ++android.widget.SimpleCursorAdapter}), serupa dengan {@link android.app.ListActivity}. Menampilkan
    ++beberapa metode pengelolaan daftar tampilan seperti callback {@link
    ++android.app.ListFragment#onListItemClick(ListView,View,int,long) onListItemClick()} untuk
    ++menangani kejadian klik.</dd>
    ++
    ++  <dt>{@link android.preference.PreferenceFragment}</dt>
    ++  <dd>Menampilkan hierarki objek {@link android.preference.Preference} sebagai daftar, serupa dengan
    ++{@link android.preference.PreferenceActivity}. Hal ini berguna saat membuat aktivitas
    ++"pengaturan" untuk aplikasi Anda.</dd>
    ++</dl>
    ++
    ++
    ++<h3 id="UI">Menambahkan antarmuka pengguna</h3>
    ++
    ++<p>Fragmen biasanya digunakan sebagai bagian dari antarmuka pengguna aktivitas dan menyumbangkan
    ++layoutnya sendiri ke aktivitas.</p>
    ++
    ++<p>Untuk menyediakan layout fragmen, Anda harus mengimplementasikan metode callback {@link
    ++android.app.Fragment#onCreateView onCreateView()}, yang dipanggil sistem Android
    ++bila tiba saatnya fragmen menggambar layoutnya. Implementasi Anda atas metode ini harus mengembalikan
    ++{@link android.view.View} yang menjadi akar layout fragmen.</p>
    ++
    ++<p class="note"><strong>Catatan:</strong> Jika fragmen adalah subkelas {@link
    ++android.app.ListFragment}, implementasi default akan mengembalikan {@link android.widget.ListView} dari
    ++{@link android.app.Fragment#onCreateView onCreateView()}, sehingga Anda tidak perlu mengimplementasikannya.</p>
    ++
    ++<p>Untuk mengembalikan layout dari {@link
    ++android.app.Fragment#onCreateView onCreateView()}, Anda bisa memekarkannya dari <a href="{@docRoot}guide/topics/resources/layout-resource.html">sumber daya layout</a> yang didefinisikan di XML. Untuk
    ++membantu melakukannya, {@link android.app.Fragment#onCreateView onCreateView()} menyediakan objek
    ++{@link android.view.LayoutInflater}.</p>
    ++
    ++<p>Misalnya, ini adalah subkelas {@link android.app.Fragment} yang memuat layout dari file
    ++{@code example_fragment.xml}:</p>
    ++
    ++<pre>
    ++public static class ExampleFragment extends Fragment {
    ++    &#64;Override
    ++    public View onCreateView(LayoutInflater inflater, ViewGroup container,
    ++                             Bundle savedInstanceState) {
    ++        // Inflate the layout for this fragment
    ++        return inflater.inflate(R.layout.example_fragment, container, false);
    ++    }
    ++}
    ++</pre>
    ++
    ++<div class="sidebox-wrapper">
    ++<div class="sidebox">
    ++  <h3>Membuat layout</h3>
    ++  <p>Dalam contoh di atas, {@code R.layout.example_fragment} merupakan acuan ke sumber daya layout
    ++bernama {@code example_fragment.xml} yang tersimpan dalam sumber daya aplikasi. Untuk informasi tentang cara
    ++membuat layout di XML, lihat dokumentasi
    ++<a href="{@docRoot}guide/topics/ui/index.html">Antarmuka Pengguna</a>.</p>
    ++</div>
    ++</div>
    ++
    ++<p>Parameter {@code container} yang diteruskan ke {@link android.app.Fragment#onCreateView
    ++onCreateView()} adalah induk {@link android.view.ViewGroup} (dari layout aktivitas) tempat
    ++layout fragmen
    ++akan disisipkan. Parameter {@code savedInstanceState} adalah {@link android.os.Bundle} yang
    ++menyediakan data tentang instance fragmen sebelumnya, jika fragmen dilanjutkan
    ++(status pemulihan dibahas selengkapnya di bagian tentang <a href="#Lifecycle">Menangani
    ++Daur Hidup Fragmen</a>).</p>
    ++
    ++<p>Metode {@link android.view.LayoutInflater#inflate(int,ViewGroup,boolean) inflate()} membutuhkan
    ++tiga argumen:</p>
    ++<ul>
    ++  <li>ID sumber daya layout yang ingin dimekarkan.</li>
    ++  <li>{@link android.view.ViewGroup} akan menjadi induk dari layout yang dimekarkan. {@code
    ++container} perlu diteruskan agar sistem menerapkan parameter layout ke tampilan akar layout
    ++yang dimekarkan, yang ditetapkan dalam tampilan induk yang akan dituju.</li>
    ++  <li>Boolean yang menunjukkan apakah layout akan dimekarkan harus ditempelkan pada {@link
    ++android.view.ViewGroup} (parameter kedua) selama pemekaran. (Dalam hal ini, ini
    ++salah karena sistem sudah memasukkan layout yang dimekarkan ke dalam {@code
    ++container}&mdash;meneruskan benar akan membuat tampilan grup yang berlebihan dalam layout akhir.)</li>
    ++</ul>
    ++
    ++<p>Anda kini telah melihat cara membuat fragmen yang menyediakan layout. Berikutnya, Anda perlu menambahkan
    ++fragmen ke aktivitas.</p>
    ++
    ++
    ++
    ++<h3 id="Adding">Menambahkan fragmen ke aktivitas</h3>
    ++
    ++<p>Biasanya, fragmen berkontribusi pada sebagian UI ke aktivitas host, yang ditanamkan sebagai
    ++bagian dari hierarki tampilan keseluruhan aktivitas. Ada dua cara untuk menambahkan fragmen ke layout
    ++aktivitas:</p>
    ++
    ++<ul>
    ++  <li><b>Deklarasikan fragmen dalam file layout aktivitas.</b>
    ++<p>Dalam hal ini, Anda bisa
    ++menetapkan properti layout fragmen seakan-akan sebuah tampilan. Misalnya, berikut ini adalah file
    ++layout untuk aktivitas dengan dua fragmen:</p>
    ++<pre>
    ++&lt;?xml version="1.0" encoding="utf-8"?&gt;
    ++&lt;LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    ++    android:orientation="horizontal"
    ++    android:layout_width="match_parent"
    ++    android:layout_height="match_parent"&gt;
    ++    &lt;fragment android:name="com.example.news.ArticleListFragment"
    ++            android:id="@+id/list"
    ++            android:layout_weight="1"
    ++            android:layout_width="0dp"
    ++            android:layout_height="match_parent" /&gt;
    ++    &lt;fragment android:name="com.example.news.ArticleReaderFragment"
    ++            android:id="@+id/viewer"
    ++            android:layout_weight="2"
    ++            android:layout_width="0dp"
    ++            android:layout_height="match_parent" /&gt;
    ++&lt;/LinearLayout&gt;
    ++</pre>
    ++  <p>Atribut {@code android:name} dalam {@code &lt;fragment&gt;} menetapkan kelas {@link
    ++android.app.Fragment} untuk dibuat instance-nya dalam layout.</p>
    ++
    ++<p>Saat sistem membuat layout aktivitas, sistem membuat instance setiap fragmen sebagaimana yang ditetapkan dalam layout
    ++dan memanggil metode {@link android.app.Fragment#onCreateView onCreateView()} masing-masing,
    ++untuk mengambil setiap fragmen. Sistem akan menyisipkan {@link android.view.View} yang dikembalikan langsung oleh fragmen,
    ++ menggantikan elemen {@code &lt;fragment&gt;}.</p>
    ++
    ++<div class="note">
    ++  <p><strong>Catatan:</strong> Setiap fragmen memerlukan identifier
    ++unik yang bisa digunakan sistem untuk memulihkan fragmen jika aktivitas dimulai kembali (dan identifier yang bisa digunakan menangkap
    ++fragmen untuk melakukan transaksi, seperti menghapusnya). Ada tiga cara untuk memberikan
    ++ID bagi fragmen:</p>
    ++  <ul>
    ++    <li>Memberikan atribut {@code android:id} bersama ID unik.</li>
    ++    <li>Memberikan atribut {@code android:tag} bersama string unik.</li>
    ++    <li>Jika Anda tidak memberikan dua hal tersebut, sistem akan menggunakan ID
    ++tampilan kontainer.</li>
    ++  </ul>
    ++</div>
    ++  </li>
    ++
    ++  <li><b>Atau, secara programatis tambahkan fragmen ke {@link android.view.ViewGroup} yang ada.</b>
    ++<p>Kapan saja saat aktivitas berjalan, Anda bisa menambahkan fragmen ke layout aktivitas. Anda
    ++cukup menetapkan {@link
    ++android.view.ViewGroup} di tempat memasukkan fragmen.</p>
    ++  <p>Untuk membuat transaksi fragmen dalam aktivitas (seperti menambah, menghapus, atau mengganti
    ++fragmen), Anda harus menggunakan API dari {@link android.app.FragmentTransaction}. Anda bisa mengambil instance
    ++ {@link android.app.FragmentTransaction} dari {@link android.app.Activity} seperti ini:</p>
    ++
    ++<pre>
    ++FragmentManager fragmentManager = {@link android.app.Activity#getFragmentManager()}
    ++FragmentTransaction fragmentTransaction = fragmentManager.{@link android.app.FragmentManager#beginTransaction()};
    ++</pre>
    ++
    ++<p>Selanjutnya Anda bisa menambahkan fragmen menggunakan metode {@link
    ++android.app.FragmentTransaction#add(int,Fragment) add()}, dengan menetapkan fragmen yang akan ditambahkan dan
    ++tampilan tempat menyisipkannya. Misalnya:</p>
    ++
    ++<pre>
    ++ExampleFragment fragment = new ExampleFragment();
    ++fragmentTransaction.add(R.id.fragment_container, fragment);
    ++fragmentTransaction.commit();
    ++</pre>
    ++
    ++  <p>Argumen pertama yang diteruskan ke {@link android.app.FragmentTransaction#add(int,Fragment) add()}
    ++ adalah {@link android.view.ViewGroup} tempat fragmen harus dimasukkan, yang ditetapkan oleh
    ++ID sumber daya, dan parameter kedua merupakan fragmen yang akan ditambahkan.</p>
    ++  <p>Setelah membuat perubahan dengan
    ++{@link android.app.FragmentTransaction}, Anda harus
    ++ memanggil {@link android.app.FragmentTransaction#commit} untuk menerapkan perubahan.</p>
    ++  </li>
    ++</ul>
    ++
    ++
    ++<h4 id="AddingWithoutUI">Menambahkan fragmen tanpa UI</h4>
    ++
    ++<p>Contoh di atas menampilkan cara menambahkan fragmen ke aktivitas untuk menyediakan UI. Akan tetapi,
    ++Anda juga bisa menggunakan fragmen untuk menyediakan perilaku latar belakang bagi aktivitas tanpa menampilkan UI
    ++tambahan.</p>
    ++
    ++<p>Untuk menambahkan fragmen tanpa UI, tambahkan fragmen dari aktivitas menggunakan {@link
    ++android.app.FragmentTransaction#add(Fragment,String)} (dengan menyediakan string unik "tag" untuk fragmen
    ++, bukan ID tampilan). Ini akan menambahkan fragmen, namun, karena tidak dikaitkan dengan tampilan
    ++dalam layout aktivitas, ini tidak akan menerima panggilan ke {@link
    ++android.app.Fragment#onCreateView onCreateView()}. Jadi Anda tidak perlu mengimplementasikan metode itu.</p>
    ++
    ++<p>Menyediakan tag string untuk fragmen tidak hanya untuk fragmen non-UI&mdash;Anda juga bisa
    ++menyediakan tag string untuk fragmen yang memiliki UI&mdash;namun jika fragmen tidak memiliki UI
    ++, maka tag string adalah satu-satunya cara untuk mengidentifikasinya. Jika Anda ingin mendapatkan fragmen dari
    ++aktivitas nantinya, Anda perlu menggunakan {@link android.app.FragmentManager#findFragmentByTag
    ++findFragmentByTag()}.</p>
    ++
    ++<p>Untuk contoh aktivitas yang menggunakan fragmen sebagai pekerja latar belakang, tanpa UI, lihat sampel {@code
    ++FragmentRetainInstance.java}, yang disertakan dalam sampel SDK (tersedia melalui
    ++Android SDK Manager) dan terletak di sistem Anda sebagai
    ++<code>&lt;sdk_root&gt;/APIDemos/app/src/main/java/com/example/android/apis/app/FragmentRetainInstance.java</code>.</p>
    ++
    ++
    ++
    ++<h2 id="Managing">Mengelola Fragmen</h2>
    ++
    ++<p>Untuk mengelola fragmen dalam aktivitas, Anda perlu menggunakan {@link android.app.FragmentManager}. Untuk
    ++mendapatkannya, panggil {@link android.app.Activity#getFragmentManager()} dari aktivitas Anda.</p>
    ++
    ++<p>Beberapa hal yang dapat Anda lakukan dengan {@link android.app.FragmentManager} antara lain:</p>
    ++
    ++<ul>
    ++  <li>Dapatkan fragmen yang ada di aktivitas dengan {@link
    ++android.app.FragmentManager#findFragmentById findFragmentById()} (untuk fragmen yang menyediakan UI dalam
    ++layout aktivitas) atau {@link android.app.FragmentManager#findFragmentByTag
    ++findFragmentByTag()} (untuk fragmen yang menyediakan atau tidak menyediakan UI).</li>
    ++  <li>Tarik fragmen dari back-stack, dengan {@link
    ++android.app.FragmentManager#popBackStack()} (mensimulasikan perintah <em>Back</em> oleh pengguna).</li>
    ++  <li>Daftarkan listener untuk perubahan pada back-stack, dengan {@link
    ++android.app.FragmentManager#addOnBackStackChangedListener addOnBackStackChangedListener()}.</li>
    ++</ul>
    ++
    ++<p>Untuk informasi selengkapnya tentang metode ini dan hal lainnya, lihat dokumentasi kelas {@link
    ++android.app.FragmentManager}.</p>
    ++
    ++<p>Seperti yang ditunjukkan di bagian sebelumnya, Anda juga bisa menggunakan {@link android.app.FragmentManager}
    ++untuk membuka {@link android.app.FragmentTransaction}, sehingga Anda bisa melakukan transaksi, seperti
    ++menambah dan menghapus fragmen.</p>
    ++
    ++
    ++<h2 id="Transactions">Melakukan Transaksi Fragmen</h2>
    ++
    ++<p>Fitur menarik terkait penggunaan fragmen di aktivitas adalah kemampuan menambah, menghapus, mengganti,
    ++dan melakukan tindakan lain dengannya, sebagai respons atas interaksi pengguna. Setiap set perubahan
    ++yang Anda lakukan untuk aktivitas disebut transaksi dan Anda bisa melakukan transaksi menggunakan API di {@link
    ++android.app.FragmentTransaction}. Anda juga bisa menyimpan setiap transaksi ke back-stack yang dikelola
    ++aktivitas, sehingga pengguna bisa mengarah mundur melalui perubahan fragmen (mirip mengarah
    ++mundur melalui aktivitas).</p>
    ++
    ++<p>Anda bisa mengambil instance {@link android.app.FragmentTransaction} dari {@link
    ++android.app.FragmentManager} seperti ini:</p>
    ++
    ++<pre>
    ++FragmentManager fragmentManager = {@link android.app.Activity#getFragmentManager()};
    ++FragmentTransaction fragmentTransaction = fragmentManager.{@link android.app.FragmentManager#beginTransaction()};
    ++</pre>
    ++
    ++<p>Setiap transaksi merupakan serangkaian perubahan yang ingin dilakukan pada waktu yang sama. Anda bisa
    ++mengatur semua perubahan yang ingin dilakukan untuk transaksi mana saja menggunakan metode seperti {@link
    ++android.app.FragmentTransaction#add add()}, {@link android.app.FragmentTransaction#remove remove()},
    ++dan {@link android.app.FragmentTransaction#replace replace()}. Kemudian, untuk menerapkan transaksi
    ++pada aktivitas, Anda harus memanggil {@link android.app.FragmentTransaction#commit()}.</p>
    ++</dl>
    ++
    ++<p>Akan tetapi, sebelum memanggil {@link
    ++android.app.FragmentTransaction#commit()}, Anda mungkin perlu memanggil {@link
    ++android.app.FragmentTransaction#addToBackStack addToBackStack()}, untuk menambahkan transaksi
    ++ke back-stack dari transaksi fragmen. Back-stack ini dikelola oleh aktivitas dan memungkinkan
    ++pengguna kembali ke status fragmen sebelumnya, dengan menekan tombol <em>Back</em>.</p>
    ++
    ++<p>Misalnya, berikut ini cara mengganti satu fragmen dengan yang fragmen yang lain, dan mempertahankan
    ++status sebelumnya di back-stack:</p>
    ++
    ++<pre>
    ++// Create new fragment and transaction
    ++Fragment newFragment = new ExampleFragment();
    ++FragmentTransaction transaction = getFragmentManager().beginTransaction();
    ++
    ++// Replace whatever is in the fragment_container view with this fragment,
    ++// and add the transaction to the back stack
    ++transaction.replace(R.id.fragment_container, newFragment);
    ++transaction.addToBackStack(null);
    ++
    ++// Commit the transaction
    ++transaction.commit();
    ++</pre>
    ++
    ++<p>Dalam contoh ini, {@code newFragment} menggantikan fragmen apa saja (jika ada) yang saat ini berada dalam
    ++kontainer layout yang diidentifikasi oleh ID {@code R.id.fragment_container}. Dengan memanggil @link
    ++android.app.FragmentTransaction#addToBackStack addToBackStack()}, transaksi yang diganti
    ++disimpan ke back-stack sehingga pengguna bisa membalikkan transaksi dan mengembalikan fragmen
    ++sebelumnya dengan menekan tombol <em>Back</em>.</p>
    ++
    ++<p>Jika Anda menambahkan beberapa perubahan pada transaksi (seperti {@link
    ++android.app.FragmentTransaction#add add()} atau {@link android.app.FragmentTransaction#remove
    ++remove()}) dan panggil {@link
    ++android.app.FragmentTransaction#addToBackStack addToBackStack()}, maka semua perubahan akan diterapkan
    ++sebelum Anda memanggil {@link android.app.FragmentTransaction#commit commit()} akan ditambahkan ke
    ++back-stack sebagai satu transaksi dan tombol <em>Back</em> akan membalikannya semua.</p>
    ++
    ++<p>Urutan menambahkan perubahan pada {@link android.app.FragmentTransaction} tidak berpengaruh,
    ++kecuali:</p>
    ++<ul>
    ++  <li>Anda harus memanggil {@link android.app.FragmentTransaction#commit()} paling akhir</li>
    ++  <li>Jika Anda menambahkan beberapa fragmen ke kontainer yang sama, maka
    ++urutan penambahannya akan menentukan urutan munculnya dalam hierarki tampilan</li>
    ++</ul>
    ++
    ++<p>Jika Anda tidak memanggil {@link android.app.FragmentTransaction#addToBackStack(String)
    ++addToBackStack()} saat melakukan transaksi yang menghapus fragmen, maka fragmen itu
    ++akan dimusnahkan bila transaksi diikat dan pengguna tidak bisa mengarah kembali ke sana. Sedangkan, jika
    ++Anda memanggil {@link android.app.FragmentTransaction#addToBackStack(String) addToBackStack()} saat
    ++menghapus fragmen, maka fragmen itu akan <em>dihentikan</em> dan akan dilanjutkan jika pengguna mengarah
    ++kembali.</p>
    ++
    ++<p class="note"><strong>Tip:</strong> Untuk setiap transaksi fragmen, Anda bisa menerapkan animasi
    ++transisi, dengan memanggil {@link android.app.FragmentTransaction#setTransition setTransition()} sebelum
    ++mengikatnya.</p>
    ++
    ++<p>Memanggil {@link android.app.FragmentTransaction#commit()} tidak akan langsung menjalankan
    ++transaksi. Namun sebuah jadwal akan dibuat untuk dijalankan pada thread UI aktivitas (thread "utama")
    ++begitu thread bisa melakukannya. Akan tetapi, jika perlu Anda bisa memanggil {@link
    ++android.app.FragmentManager#executePendingTransactions()} dari thread UI untuk segera
    ++mengeksekusi transaksi yang diserahkan oleh {@link android.app.FragmentTransaction#commit()}. Hal itu
    ++biasanya tidak perlu kecuali jika transaksi merupakan dependensi bagi pekerjaan dalam thread lain.</p>
    ++
    ++<p class="caution"><strong>Perhatian:</strong> Anda bisa mengikat transaksi menggunakan {@link
    ++android.app.FragmentTransaction#commit commit()} hanya sebelum aktivitas <a href="{@docRoot}guide/components/activities.html#SavingActivityState">menyimpan
    ++statusnya</a> (saat pengguna meninggalkan aktivitas). Jika Anda mencoba mengikatnya setelah itu,
    ++eksepsi akan dilontarkan. Ini karena status setelah pengikatan bisa hilang jika aktivitas
    ++perlu dipulihkan. Untuk situasi yang memperbolehkan Anda meniadakan pengikatan (commit), gunakan {@link
    ++android.app.FragmentTransaction#commitAllowingStateLoss()}.</p>
    ++
    ++
    ++
    ++
    ++<h2 id="CommunicatingWithActivity">Berkomunikasi dengan Aktivitas</h2>
    ++
    ++<p>Meskipun {@link android.app.Fragment} diimplementasikan sebagai objek yang tidak bergantung pada
    ++{@link android.app.Activity} dan bisa digunakan dalam banyak aktivitas, instance tertentu
    ++dari fragmen secara langsung terkait dengan aktivitas yang dimuatnya.</p>
    ++
    ++<p>Khususnya, fragmen bisa mengakses instance {@link android.app.Activity} dengan {@link
    ++android.app.Fragment#getActivity()} dan dengan mudah melakukan tugas-tugas seperti mencari tampilan dalam
    ++ layout aktivitas:</p>
    ++
    ++<pre>
    ++View listView = {@link android.app.Fragment#getActivity()}.{@link android.app.Activity#findViewById findViewById}(R.id.list);
    ++</pre>
    ++
    ++<p>Demikian pula, aktivitas Anda bisa memanggil metode di fragmen dengan meminta acuan ke
    ++{@link android.app.Fragment} dari {@link android.app.FragmentManager}, menggunakan {@link
    ++android.app.FragmentManager#findFragmentById findFragmentById()} atau {@link
    ++android.app.FragmentManager#findFragmentByTag findFragmentByTag()}. Misalnya:</p>
    ++
    ++<pre>
    ++ExampleFragment fragment = (ExampleFragment) getFragmentManager().findFragmentById(R.id.example_fragment);
    ++</pre>
    ++
    ++
    ++<h3 id="EventCallbacks">Membuat callback kejadian pada aktivitas</h3>
    ++
    ++<p>Dalam beberapa kasus, Anda mungkin perlu fragmen untuk berbagi kejadian dengan aktivitas. Cara yang baik untuk melakukannya
    ++adalah mendefinisikan antarmuka callback di dalam fragmen dan mengharuskan aktivitas host
    ++mengimplementasikannya. Saat aktivitas menerima callback melalui antarmuka, aktivitas akan bisa berbagi informasi itu
    ++dengan fragmen lain dalam layout jika perlu.</p>
    ++
    ++<p>Misalnya, jika sebuah aplikasi berita memiliki dua fragmen dalam aktivitas&mdash;satu untuk menampilkan daftar
    ++artikel (fragmen A) dan satu lagi untuk menampilkan artikel (fragmen B)&mdash;maka fragmen A harus
    ++memberi tahu aktivitas bila item daftar dipilih sehingga aktivitas bisa memberi tahu fragmen B untuk menampilkan artikel. Dalam
    ++hal ini, antarmuka {@code OnArticleSelectedListener} dideklarasikan di dalam fragmen A:</p>
    ++
    ++<pre>
    ++public static class FragmentA extends ListFragment {
    ++    ...
    ++    // Container Activity must implement this interface
    ++    public interface OnArticleSelectedListener {
    ++        public void onArticleSelected(Uri articleUri);
    ++    }
    ++    ...
    ++}
    ++</pre>
    ++
    ++<p>Selanjutnya aktivitas yang menjadi host fragmen akan mengimplementasikan antarmuka {@code OnArticleSelectedListener}
    ++ dan
    ++mengesampingkan {@code onArticleSelected()} untuk memberi tahu fragmen B mengenai kejadian dari fragmen A. Untuk memastikan
    ++bahwa aktivitas host mengimplementasikan antarmuka ini, metode callback fragmen A {@link
    ++android.app.Fragment#onAttach onAttach()} (yang dipanggil sistem saat menambahkan
    ++fragmen ke aktivitas) membuat instance {@code OnArticleSelectedListener} dengan
    ++membuat {@link android.app.Activity} yang diteruskan ke {@link android.app.Fragment#onAttach
    ++onAttach()}:</p>
    ++
    ++<pre>
    ++public static class FragmentA extends ListFragment {
    ++    OnArticleSelectedListener mListener;
    ++    ...
    ++    &#64;Override
    ++    public void onAttach(Activity activity) {
    ++        super.onAttach(activity);
    ++        try {
    ++            mListener = (OnArticleSelectedListener) activity;
    ++        } catch (ClassCastException e) {
    ++            throw new ClassCastException(activity.toString() + " must implement OnArticleSelectedListener");
    ++        }
    ++    }
    ++    ...
    ++}
    ++</pre>
    ++
    ++<p>Jika aktivitas belum mengimplementasikan antarmuka, maka fragmen akan melontarkan
    ++{@link java.lang.ClassCastException}.
    ++Jika berhasil, anggota {@code mListener} yang menyimpan acuan ke implementasi aktivitas
    ++{@code OnArticleSelectedListener}, sehingga fragmen A bisa berbagi kejadian dengan aktivitas, dengan memanggil metode
    ++yang didefinisikan oleh antarmuka {@code OnArticleSelectedListener}. Misalnya, jika fragmen A adalah
    ++ekstensi dari {@link android.app.ListFragment}, maka setiap kali
    ++pengguna mengklik item daftar, sistem akan memanggil {@link android.app.ListFragment#onListItemClick
    ++onListItemClick()} di fragmen, yang selanjutnya memanggil {@code onArticleSelected()} untuk berbagi
    ++kejadian dengan aktivitas:</p>
    ++
    ++<pre>
    ++public static class FragmentA extends ListFragment {
    ++    OnArticleSelectedListener mListener;
    ++    ...
    ++    &#64;Override
    ++    public void onListItemClick(ListView l, View v, int position, long id) {
    ++        // Append the clicked item's row ID with the content provider Uri
    ++        Uri noteUri = ContentUris.{@link android.content.ContentUris#withAppendedId withAppendedId}(ArticleColumns.CONTENT_URI, id);
    ++        // Send the event and Uri to the host activity
    ++        mListener.onArticleSelected(noteUri);
    ++    }
    ++    ...
    ++}
    ++</pre>
    ++
    ++<p>Parameter {@code id} yang diteruskan ke {@link
    ++android.app.ListFragment#onListItemClick onListItemClick()} merupakan ID baris dari item yang diklik,
    ++yang digunakan aktivitas (atau fragmen lain) untuk mengambil artikel dari {@link
    ++android.content.ContentProvider} aplikasi.</p>
    ++
    ++<p><!--To see a complete implementation of this kind of callback interface, see the <a
    ++href="{@docRoot}resources/samples/NotePad/index.html">NotePad sample</a>. -->Informasi selengkapnya tentang
    ++menggunakan penyedia konten tersedia dalam dokumen <a href="{@docRoot}guide/topics/providers/content-providers.html">Penyedia Konten</a>.</p>
    ++
    ++
    ++
    ++<h3 id="ActionBar">Menambahkan item ke Action-Bar</h3>
    ++
    ++<p>Fragmen Anda bisa menyumbangkan item menu ke <a href="{@docRoot}guide/topics/ui/menus.html#options-menu">Menu Opsi</a> aktivitas (dan, konsekuensinya, <a href="{@docRoot}guide/topics/ui/actionbar.html">Action-Bar</a>) dengan mengimplementasikan
    ++{@link android.app.Fragment#onCreateOptionsMenu(Menu,MenuInflater) onCreateOptionsMenu()}. Agar
    ++metode ini bisa menerima panggilan, Anda harus memanggil {@link
    ++android.app.Fragment#setHasOptionsMenu(boolean) setHasOptionsMenu()} selama {@link
    ++android.app.Fragment#onCreate(Bundle) onCreate()}, untuk menunjukkan bahwa fragmen
    ++ingin menambahkan item ke Menu Opsi (jika tidak, fragmen tidak akan menerima panggilan ke
    ++{@link android.app.Fragment#onCreateOptionsMenu onCreateOptionsMenu()}).</p>
    ++
    ++<p>Setiap item yang selanjutnya Anda tambahkan ke Menu Opsi dari fragmen akan ditambahkan ke item menu
    ++yang ada. Fragmen juga menerima callback ke {@link
    ++android.app.Fragment#onOptionsItemSelected(MenuItem) onOptionsItemSelected()} bila item menu
    ++dipilih.</p>
    ++
    ++<p>Anda juga bisa mendaftarkan tampilan dalam layout fragmen untuk menyediakan menu konteks dengan memanggil {@link
    ++android.app.Fragment#registerForContextMenu(View) registerForContextMenu()}. Bila pengguna
    ++membuka menu konteks, fragmen akan menerima panggilan ke {@link
    ++android.app.Fragment#onCreateContextMenu(ContextMenu,View,ContextMenu.ContextMenuInfo)
    ++onCreateContextMenu()}. Bila pengguna memilih item, fragmen akan menerima panggilan ke @link
    ++android.app.Fragment#onContextItemSelected(MenuItem) onContextItemSelected()}.</p>
    ++
    ++<p class="note"><strong>Catatan:</strong> Walaupun fragmen menerima callback pada item yang dipilih
    ++untuk setiap item menu yang ditambahkannya, aktivitaslah yang pertama kali menerima masing-masing callback saat pengguna
    ++memilih item menu. Jika implementasi aktivitas dari callback bila-item-dipilih,
    ++tidak menangani item yang dipilih, maka kejadian akan diteruskan ke callback fragmen. Ini berlaku
    ++untuk Menu Opsi dan menu konteks.</p>
    ++
    ++<p>Untuk informasi selengkapnya tentang menu, lihat panduan pengembang <a href="{@docRoot}guide/topics/ui/menus.html">Menu</a> dan <a href="{@docRoot}guide/topics/ui/actionbar.html">Action-Bar</a>.</p>
    ++
    ++
    ++
    ++
    ++<h2 id="Lifecycle">Menangani Daur Hidup Fragmen</h2>
    ++
    ++<div class="figure" style="width:350px">
    ++<img src="{@docRoot}images/activity_fragment_lifecycle.png" alt="" />
    ++<p class="img-caption"><strong>Gambar 3.</strong> Efek daur hidup aktivitas pada daur hidup
    ++fragmen.</p>
    ++</div>
    ++
    ++<p>Mengelola daur hidup fragmen mirip sekali dengan mengelola daur hidup aktivitas. Seperti
    ++aktivitas, fragmen bisa berada dalam tiga status:</p>
    ++
    ++<dl>
    ++  <dt><i>Dilanjutkan</i></dt>
    ++    <dd>Fragmen terlihat dalam aktivitas yang berjalan.</dd>
    ++
    ++  <dt><i>Dihentikan sementara</i></dt>
    ++    <dd>Aktivitas lain berada di latar depan dan memiliki fokus, namun aktivitas tempat fragmen berada
    ++masih terlihat (aktivitas latar depan sebagian terlihat atau tidak menutupi
    ++seluruh layar).</dd>
    ++
    ++  <dt><i>Dihentikan</i></dt>
    ++    <dd>Fragmen tidak terlihat. Aktivitas host telah dihentikan atau
    ++fragmen telah dihapus dari aktivitas namun ditambahkan ke back-stack. Fragmen yang dihentikan
    ++masih hidup (semua status dan informasi anggota masih disimpan oleh sistem). Akan tetapi, fragmen
    ++tidak terlihat lagi oleh pengguna dan akan dimatikan jika aktivitas dimatikan.</dd>
    ++</dl>
    ++
    ++<p>Seperti halnya aktivitas, Anda bisa mempertahankan status fragmen menggunakan {@link
    ++android.os.Bundle}, jika proses aktivitas dimatikan dan Anda harus memulihkan status
    ++fragmen bila aktivitas dibuat kembali. Anda bisa menyimpan status selama callback {@link
    ++android.app.Fragment#onSaveInstanceState onSaveInstanceState()} fragmen dan memulihkannya selama
    ++{@link android.app.Fragment#onCreate onCreate()}, {@link
    ++android.app.Fragment#onCreateView onCreateView()}, atau {@link
    ++android.app.Fragment#onActivityCreated onActivityCreated()}. Untuk informasi selengkapnya tentang menyimpan
    ++status, lihat dokumen <a href="{@docRoot}guide/components/activities.html#SavingActivityState">Aktivitas</a>
    ++.</p>
    ++
    ++<p>Perbedaan paling signifikan dalam daur hidup antara aktivitas dan fragmen ada
    ++pada cara penyimpanannya dalam back-stack masing-masing. Aktivitas ditempatkan ke back-stack aktivitas
    ++yang dikelola oleh sistem saat dihentikan, secara default (sehingga pengguna bisa mengarah kembali
    ++ke aktivitas dengan tombol <em>Back</em>, seperti yang dibahas dalam <a href="{@docRoot}guide/components/tasks-and-back-stack.html">Tugas dan Back-Stack</a>).
    ++Akan tetapi, fragmen yang ditempatkan ke back-stack dikelola oleh aktivitas host hanya saat
    ++Anda secara eksplisit meminta agar instance disimpan dengan memanggil {@link
    ++android.app.FragmentTransaction#addToBackStack(String) addToBackStack()} selama transaksi yang
    ++menghapus fragmen.</p>
    ++
    ++<p>Jika tidak, pengelolaan daur hidup fragmen mirip sekali dengan mengelola daur hidup
    ++aktivitas. Jadi, praktik yang sama untuk <a href="{@docRoot}guide/components/activities.html#Lifecycle">mengelola daur hidup
    ++aktivitas</a> juga berlaku untuk fragmen. Namun yang perlu juga Anda pahami adalah bagaimana hidup
    ++aktivitas memengaruhi hidup fragmen.</p>
    ++
    ++<p class="caution"><strong>Perhatian:</strong> Jika Anda memerlukan objek {@link android.content.Context}
    ++ dalam {@link android.app.Fragment}, Anda bisa memanggil {@link android.app.Fragment#getActivity()}.
    ++Akan tetapi, berhati-hatilah memanggil {@link android.app.Fragment#getActivity()} hanya bila fragmen
    ++terkait dengan aktivitas. Bila fragmen belum terkait, atau terlepas selama akhir daur
    ++hidupnya, {@link android.app.Fragment#getActivity()} akan kembali nol.</p>
    ++
    ++
    ++<h3 id="CoordinatingWithActivity">Mengoordinasi dengan daur hidup aktivitas</h3>
    ++
    ++<p>Daur hidup aktivitas tempat fragmen berada akan memengaruhi langsung siklus hidup
    ++fragmen sedemikian rupa sehingga setiap callback daur hidup aktivitas menghasilkan callback yang sama untuk masing-masing
    ++fragmen. Misalnya, bila aktivitas menerima {@link android.app.Activity#onPause}, masing-masing
    ++fragmen dalam aktivitas akan menerima {@link android.app.Fragment#onPause}.</p>
    ++
    ++<p>Namun fragmen memiliki beberapa callback daur hidup ekstra, yang menangani interaksi
    ++unik dengan aktivitas untuk melakukan tindakan seperti membangun dan memusnahkan UI fragmen. Metode callback
    ++tambahan ini adalah:</p>
    ++
    ++<dl>
    ++  <dt>{@link android.app.Fragment#onAttach onAttach()}</dt>
    ++    <dd>Dipanggil bila fragmen telah dikaitkan dengan aktivitas ({@link
    ++android.app.Activity} diteruskan di sini).</dd>
    ++  <dt>{@link android.app.Fragment#onCreateView onCreateView()}</dt>
    ++    <dd>Dipanggil untuk membuat hierarki tampilan yang dikaitkan dengan fragmen.</dd>
    ++  <dt>{@link android.app.Fragment#onActivityCreated onActivityCreated()}</dt>
    ++    <dd>Dipanggil bila metode {@link android.app.Activity#onCreate
    ++onCreate()} aktivitas telah dikembalikan.</dd>
    ++  <dt>{@link android.app.Fragment#onDestroyView onDestroyView()}</dt>
    ++    <dd>Dipanggil bila hierarki tampilan yang terkait dengan fragmen dihapus.</dd>
    ++  <dt>{@link android.app.Fragment#onDetach onDetach()}</dt>
    ++    <dd>Dipanggil bila fragmen diputuskan dari aktivitas.</dd>
    ++</dl>
    ++
    ++<p>Aliran daur hidup fragmen, karena dipengaruhi oleh aktivitas host-nya, diilustrasikan oleh
    ++gambar 3. Dalam gambar ini, Anda bisa melihat bagaimana setiap status aktivitas menentukan
    ++metode callback mana yang mungkin diterima fragmen. Misalnya, saat aktivitas menerima call back {@link
    ++android.app.Activity#onCreate onCreate()}, fragmen dalam aktivitas akan menerima tidak lebih
    ++dari callback {@link android.app.Fragment#onActivityCreated onActivityCreated()}.</p>
    ++
    ++<p>Setelah status aktivitas diteruskan kembali, Anda bisa bebas menambah dan menghapus fragmen untuk
    ++aktivitas tersebut. Sehingga, hanya saat aktivitas berada dalam status dilanjutkan, daur hidup fragmen bisa
    ++berubah secara independen.</p>
    ++
    ++<p>Akan tetapi, saat aktivitas meninggalkan status dilanjutkan, fragmen akan kembali didorong
    ++melalui daur hidupnya oleh aktivitas.</p>
    ++
    ++
    ++
    ++
    ++<h2 id="Example">Contoh</h2>
    ++
    ++<p>Untuk merangkum semua yang telah dibahas dalam dokumen ini, berikut ini contoh aktivitas
    ++yang menggunakan dua fragmen untuk membuat layout dua panel. Aktivitas di bawah ini menyertakan satu fragmen untuk
    ++menampilkan daftar putar Shakespeare dan fragmen lainnya menampilkan rangkuman pemutaran bila dipilih dari
    ++daftar. Aktivitas ini juga menunjukkan cara menyediakan konfigurasi fragmen berbeda,
    ++berdasarkan konfigurasi layar.</p>
    ++
    ++<p class="note"><strong>Catatan:</strong> Kode sumber lengkap untuk aktivitas ini tersedia di
    ++<a href="{@docRoot}resources/samples/ApiDemos/src/com/example/android/apis/app/FragmentLayout.html">{@code
    ++FragmentLayout.java}</a>.</p>
    ++
    ++<p>Aktivitas utama akan menerapkan layout seperti biasa, selama {@link
    ++android.app.Activity#onCreate onCreate()}:</p>
    ++
    ++{@sample development/samples/ApiDemos/src/com/example/android/apis/app/FragmentLayout.java main}
    ++
    ++<p>Layout yang diterapkan adalah {@code fragment_layout.xml}:</p>
    ++
    ++{@sample development/samples/ApiDemos/res/layout-land/fragment_layout.xml layout}
    ++
    ++<p>Dengan layout ini, sistem akan membuat instance {@code TitlesFragment} (yang mencantumkan
    ++judul) segera setelah aktivitas memuat layout, sementara {@link android.widget.FrameLayout}
    ++ (lokasi penempatan fragmen untuk menampilkan rangkuman pemutaran) menempati ruang di sisi kanan
    ++layar, namun pada awalnya masih kosong. Seperti yang akan Anda lihat di bawah ini, sampai pengguna memilih item
    ++dari daftar maka fragmen baru akan ditempatkan ke dalam {@link android.widget.FrameLayout}.</p>
    ++
    ++<p>Akan tetapi, tidak semua konfigurasi layar cukup lebar untuk menampilkan
    ++daftar putar dan rangkuman secara berdampingan. Sehingga, layout di atas hanya digunakan untuk konfigurasi
    ++layar mendatar, dengan menyimpannya di {@code res/layout-land/fragment_layout.xml}.</p>
    ++
    ++<p>Sehingga, bila layar berada dalam orientasi tegak, sistem akan menerapkan layout berikut, yang
    ++tersimpan di {@code res/layout/fragment_layout.xml}:</p>
    ++
    ++{@sample development/samples/ApiDemos/res/layout/fragment_layout.xml layout}
    ++
    ++<p>Layout ini hanya menyertakan {@code TitlesFragment}. Ini artinya saat perangkat berada dalam
    ++orientasi tegak, hanya judul daftar putar yang terlihat. Jadi, saat pengguna mengklik item
    ++daftar dalam konfigurasi ini, aplikasi akan memulai aktivitas baru untuk menampilkan rangkuman,
    ++sebagai ganti pemuatan fragmen kedua.</p>
    ++
    ++<p>Berikutnya, Anda bisa melihat bagaimana hal ini dilakukan dalam kelas fragmen. Pertama adalah {@code
    ++TitlesFragment}, yang menampilkan judul daftar putar Shakespeare. Fragmen ini membuat ekstensi {@link
    ++android.app.ListFragment} dan mengandalkannya itu untuk menangani sebagian besar pekerjaan tampilan daftar.</p>
    ++
    ++<p>Saat Anda memeriksa kode ini, perhatikan bahwa ada dua kemungkinan perilaku saat pengguna mengklik
    ++item daftar: bergantung pada layout mana yang aktif, bisa membuat dan menampilkan fragmen
    ++baru untuk menampilkan detail dalam aktivitas yang sama (menambahkan fragmen ke {@link
    ++android.widget.FrameLayout}), atau memulai aktivitas baru (tempat fragmen ditampilkan).</p>
    ++
    ++{@sample development/samples/ApiDemos/src/com/example/android/apis/app/FragmentLayout.java titles}
    ++
    ++<p>Fragmen kedua, {@code DetailsFragment} menampilkan rangkuman pemutaran untuk item yang dipilih dari
    ++daftar dari {@code TitlesFragment}:</p>
    ++
    ++{@sample development/samples/ApiDemos/src/com/example/android/apis/app/FragmentLayout.java details}
    ++
    ++<p>Ingatlah dari kelas {@code TitlesFragment}, bahwa, jika pengguna mengklik item daftar dan
    ++layout saat ini <em>tidak</em> menyertakan tampilan {@code R.id.details} (yaitu tempat
    ++{@code DetailsFragment} berada), maka aplikasi memulai aktivitas {@code DetailsActivity}
    ++untuk menampilkan konten item.</p>
    ++
    ++<p>Berikut ini adalah {@code DetailsActivity}, yang hanya menanamkan {@code DetailsFragment} untuk menampilkan rangkuman pemutaran
    ++yang dipilih saat layar dalam orientasi tegak:</p>
    ++
    ++{@sample development/samples/ApiDemos/src/com/example/android/apis/app/FragmentLayout.java
    ++details_activity}
    ++
    ++<p>Perhatikan bahwa aktivitas ini selesai sendiri jika konfigurasi mendatar, sehingga aktivitas utama
    ++bisa mengambil alih dan menampilkan {@code DetailsFragment} bersama {@code TitlesFragment}.
    ++Ini bisa terjadi jika pengguna memulai {@code DetailsActivity} saat dalam orientasi tegak, namun kemudian
    ++memutarnya menjadi mendatar (yang akan memulai lagi aktivitas saat ini).</p>
    ++
    ++
    ++<p>Untuk contoh lainnya mengenai penggunaan fragmen (dan file sumber lengkap untuk contoh ini),
    ++lihat aplikasi contoh Demo API yang tersedia di <a href="{@docRoot}resources/samples/ApiDemos/src/com/example/android/apis/app/index.html#Fragment">
    ++ApiDemos</a> (bisa diunduh dari <a href="{@docRoot}resources/samples/get.html">Komponen contoh SDK</a>).</p>
    ++
    ++
    +diff --git a/docs/html-intl/intl/id/guide/components/fundamentals.jd b/docs/html-intl/intl/id/guide/components/fundamentals.jd
    +new file mode 100644
    +index 0000000..2c925e9
    +--- /dev/null
    ++++ b/docs/html-intl/intl/id/guide/components/fundamentals.jd
    +@@ -0,0 +1,480 @@
    ++page.title=Dasar-Dasar Aplikasi
    ++@jd:body
    ++
    ++<div id="qv-wrapper">
    ++<div id="qv">
    ++
    ++<h2>Dalam dokumen ini</h2>
    ++<ol>
    ++<li><a href="#Components">Komponen Aplikasi</a>
    ++  <ol>
    ++    <li><a href="#ActivatingComponents">Mengaktifkan komponen</a></li>
    ++  </ol>
    ++</li>
    ++<li><a href="#Manifest">File Manifes</a>
    ++  <ol>
    ++    <li><a href="#DeclaringComponents">Mendeklarasikan komponen</a></li>
    ++    <li><a href="#DeclaringRequirements">Mendeklarasikan kebutuhan aplikasi</a></li>
    ++  </ol>
    ++</li>
    ++<li><a href="#Resources">Sumber Daya Aplikasi</a></li>
    ++</ol>
    ++</div>
    ++</div>
    ++
    ++<p>Aplikasi Android ditulis dalam bahasa pemrograman Java. Android SDK Tools mengkompilasi
    ++kode Anda&mdash;bersama data dan file sumber daya &mdash;ke dalam APK: <i>Paket Android</i>,
    ++yaitu file arsip berekstensi {@code .apk}. Satu file APK berisi semua konten
    ++aplikasi Android dan merupakan file yang digunakan perangkat berbasis Android untuk menginstal aplikasi.</p>
    ++
    ++<p>Setelah diinstal di perangkat, setiap aplikasi Android tinggal di sandbox keamanannya sendiri: </p>
    ++
    ++<ul>
    ++ <li>Sistem operasi Android merupakan sistem Linux multi-pengguna yang di dalamnya setiap
    ++aplikasi adalah pengguna berbeda.</li>
    ++
    ++<li>Secara default, sistem menetapkan ID pengguna Linux unik kepada setiap aplikasi (ID ini hanya
    ++ digunakan oleh sistem dan tidak diketahui aplikasi). Sistem menetapkan izin
    ++bagi semua file dalam aplikasi sehingga hanya ID pengguna yang diizinkan yang bisa mengaksesnya. </li>
    ++
    ++<li>Setiap proses memiliki mesin virtual (VM) sendiri, sehingga kode aplikasi yang berjalan secara terisolasi dari
    ++aplikasi lainnya.</li>
    ++
    ++<li>Secara default, setiap aplikasi berjalan dalam proses Linux-nya sendiri. Android memulai proses
    ++bila ada komponen aplikasi yang perlu dijalankan, kemudian mematikan proses bila tidak lagi diperlukan
    ++atau bila sistem harus memulihkan memori untuk digunakan aplikasi lain.</li>
    ++</ul>
    ++
    ++<p>Dengan cara ini, sistem Android mengimplementasikan <em>prinsip privilese minim</em>. Ini berarti,
    ++secara default aplikasi hanya memiliki akses ke komponen yang diperlukannya untuk melakukan pekerjaannya dan
    ++tidak lebih dari itu. Hal ini menghasilkan lingkungan yang sangat aman sehingga aplikasi tidak bisa mengakses bagian
    ++sistem bila tidak diberi izin.</p>
    ++
    ++<p>Akan tetapi, ada beberapa cara bagi aplikasi untuk berbagi data dengan aplikasi lain dan bagi aplikasi
    ++untuk mengakses layanan sistem:</p>
    ++
    ++<ul>
    ++  <li>Dua aplikasi bisa diatur untuk menggunakan ID pengguna Linux yang sama,
    ++dalam hal ini keduanya bisa saling mengakses file masing-masing.  Untuk menghemat sumber daya sistem, aplikasi dengan ID
    ++pengguna yang sama juga bisa diatur agar berjalan dalam proses Linux yang sama dan menggunakan VM yang sama (
    ++aplikasi juga harus ditandatangani dengan sertifikat yang sama).</li>
    ++  <li>Aplikasi bisa meminta izin akses ke data perangkat seperti kontak
    ++pengguna, pesan SMS, penyimpanan lepas-pasang (kartu SD), kamera, Bluetooth, dan lainnya. Semua
    ++izin aplikasi harus diberikan oleh pengguna saat menginstal.</li>
    ++</ul>
    ++
    ++<p>Hal tersebut mencakup dasar-dasar tentang cara aplikasi Android berada di dalam sistem. Bagian dokumen
    ++selanjutnya memperkenalkan Anda pada:</p>
    ++<ul>
    ++  <li>Komponen kerangka kerja inti yang mendefinisikan aplikasi.</li>
    ++  <li>File manifes tempat Anda mendeklarasikan komponen dan fitur yang diperlukan perangkat
    ++untuk aplikasi.</li>
    ++  <li>Sumber daya yang terpisah dari kode aplikasi dan memungkinkan
    ++aplikasi mengoptimalkan perilakunya untuk beragam konfigurasi perangkat.</li>
    ++</ul>
    ++
    ++
    ++
    ++<h2 id="Components">Komponen Aplikasi</h2>
    ++
    ++<p>Komponen aplikasi adalah blok pembangun penting dari aplikasi Android.
    ++Setiap komponen merupakan titik berbeda yang digunakan sistem untuk memasuki aplikasi. Tidak semua komponen
    ++merupakan titik masuk sebenarnya bagi pengguna dan sebagian saling bergantung, namun masing-masing komponen tersedia
    ++sebagai kesatuan sendiri dan memainkan peran tertentu&mdash;masing-masing merupakan
    ++blok pembangun unik yang mendefinisikan perilaku aplikasi secara keseluruhan.</p>
    ++
    ++<p>Ada empat macam tipe komponen aplikasi. Setiap tipe memiliki kegunaan tersendiri
    ++dan daur hidupnya sendiri yang mendefinisikan cara komponen dibuat dan dimusnahkan.</p>
    ++
    ++<p>Berikut ini empat tipe komponen aplikasi:</p>
    ++
    ++<dl>
    ++
    ++<dt><b>Aktivitas</b></dt>
    ++
    ++<dd>Sebuah <i>aktivitas</i> mewakili satu layar dengan antarmuka pengguna. Misalnya,
    ++aplikasi email mungkin memiliki satu aktivitas yang menampilkan daftar email
    ++baru, aktivitas lain untuk menulis email, dan aktivitas satunya lagi untuk membaca email. Walaupun
    ++semua aktivitas bekerja sama untuk membentuk pengalaman pengguna yang kohesif dalam aplikasi email,
    ++masing-masing tidak saling bergantung. Karenanya, aplikasi berbeda bisa memulai
    ++salah satu aktivitas ini (jika aplikasi email mengizinkannya). Misalnya, aplikasi kamera bisa memulai
    ++aktivitas dalam aplikasi email yang membuat email baru agar pengguna bisa berbagi gambar.
    ++
    ++<p>Aktivitas diimplementasikan sebagai subkelas {@link android.app.Activity} dan Anda bisa mengetahui selengkapnya
    ++tentang hal ini dalam panduan pengembang <a href="{@docRoot}guide/components/activities.html">Aktivitas</a>
    ++.</p>
    ++</dd>
    ++
    ++
    ++<dt><b>Layanan</b></dt>
    ++
    ++<dd>Sebuah <i>layanan</i> adalah komponen yang berjalan di latar belakang untuk melakukan
    ++operasi yang berjalan lama atau untuk melakukan pekerjaan bagi proses jarak jauh. Layanan
    ++tidak menyediakan antarmuka pengguna. Misalnya, sebuah layanan bisa memutar musik di latar belakang sementara
    ++pengguna berada dalam aplikasi lain, atau layanan bisa menarik data lewat jaringan tanpa
    ++memblokir interaksi pengguna dengan aktivitas. Komponen lain, seperti aktivitas, bisa memulai
    ++layanan dan membiarkannya berjalan atau mengikat layanan untuk berinteraksi dengannya.
    ++
    ++<p>Layanan diimplementasikan sebagai subkelas {@link android.app.Service} dan Anda bisa mengetahui selengkapnya
    ++tentang hal ini dalam panduan
    ++pengembang <a href="{@docRoot}guide/components/services.html">Layanan</a>.</p>
    ++</dd>
    ++
    ++
    ++<dt><b>Penyedia konten</b></dt>
    ++
    ++<dd>Sebuah <i>penyedia konten</i> mengelola seperangkat data-bersama aplikasi. Anda bisa menyimpan data
    ++dalam sistem file, database SQLite, di web, atau lokasi penyimpanan permanen lainnya
    ++yang bisa diakses aplikasi. Melalui penyedia konten, aplikasi lain bisa melakukan query atau bahkan
    ++memodifikasi data (jika penyedia konten mengizinkannya). Misalnya, sistem Android menyediakan penyedia
    ++konten yang mengelola informasi kontak pengguna. Karenanya, setiap aplikasi
    ++dengan izin yang sesuai bisa melakukan query mengenai bagian dari penyedia konten (seperti {@link
    ++android.provider.ContactsContract.Data}) untuk membaca dan menulis informasi tentang orang tertentu.
    ++
    ++<p>Penyedia konten juga berguna untuk membaca dan menulis data privat ke aplikasi Anda
    ++dan tidak dibagikan. Misalnya, aplikasi contoh <a href="{@docRoot}resources/samples/NotePad/index.html">Note Pad</a> menggunakan
    ++penyedia konten untuk menyimpan catatan.</p>
    ++
    ++<p>Penyedia konten diimplementasikan sebagai subkelas {@link android.content.ContentProvider}
    ++dan harus mengimplementasikan seperangkat standar API yang memungkinkan aplikasi
    ++lain melakukan transaksi. Untuk informasi selengkapnya, lihat panduan pengembang
    ++<a href="{@docRoot}guide/topics/providers/content-providers.html">Penyedia Konten</a>.</p>
    ++</dd>
    ++
    ++
    ++<dt><b>Penerima siaran</b></dt>
    ++
    ++<dd>Sebuah <i>penerima siaran</i> adalah komponen yang merespons pengumuman siaran dalam lingkup
    ++sistem.  Banyak siaran yang berasal dari sistem&mdash;misalnya, siaran yang mengumumkan bahwa
    ++layar telah dimatikan, baterai lemah, atau gambar telah direkam.
    ++Aplikasi juga bisa memulai siaran&mdash;misalnya untuk menginformasikan ke
    ++aplikasi lain bahwa sebagian data telah diunduh ke perangkat dan bisa digunakan aplikasi lain tersebut. Walaupun penerima
    ++siaran tidak menampilkan antarmuka pengguna, penerima bisa <a href="{@docRoot}guide/topics/ui/notifiers/notifications.html">membuat pemberitahuan baris status</a>
    ++untuk memberi tahu pengguna kapan kejadian siaran dilakukan. Meskipun penerima siaran umumnya cuma menjadi
    ++"gerbang" untuk komponen lain dan dimaksudkan untuk melakukan pekerjaan dalam jumlah sangat minim. Misalnya
    ++, penerima siaran bisa menjalankan layanan untuk melakukan beberapa pekerjaan berdasarkan kejadian.
    ++
    ++<p>Penerima siaran diimplementasikan sebagai subkelas {@link android.content.BroadcastReceiver}
    ++dan setiap siaran dikirim sebagai objek {@link android.content.Intent}. Untuk informasi selengkapnya,
    ++lihat kelas {@link android.content.BroadcastReceiver}.</p>
    ++</dd>
    ++
    ++</dl>
    ++
    ++
    ++
    ++<p>Aspek unik dari desain sistem Android adalah aplikasi mana pun bisa memulai
    ++komponen aplikasi lain. Misalnya, jika Anda menginginkan pengguna mengambil
    ++foto dengan kamera perangkat, bisa saja aplikasi lain yang melakukannya dan aplikasi
    ++Anda bisa menggunakannya, sebagai ganti mengembangkan aktivitas sendiri untuk mengambil foto. Anda tidak
    ++harus menyatukan atau bahkan menautkan ke kode dari aplikasi kamera.
    ++Sebagai gantinya, Anda tinggal memulai aktivitas di aplikasi kamera yang akan mengambil
    ++foto. Bila selesai, foto akan dikembalikan ke aplikasi sehingga Anda bisa menggunakannya. Bagi pengguna,
    ++kamera seakan menjadi bagian dari aplikasi Anda.</p>
    ++
    ++<p>Saat sistem memulai komponen, sistem akan memulai proses untuk aplikasi itu (jika
    ++belum berjalan) dan membuat instance kelas yang diperlukan untuk komponen. Misalnya, jika aplikasi Anda
    ++memulai aktivitas dalam aplikasi kamera yang mengambil foto, aktivitas itu akan
    ++berjalan dalam proses yang dimiliki oleh aplikasi kamera, bukan dalam proses aplikasi Anda.
    ++Karenanya, tidak seperti aplikasi di sebagian besar sistem lain, aplikasi Android tidak memiliki titik
    ++masuk tunggal (misalnya tidak ada fungsi {@code main()}).</p>
    ++
    ++<p>Karena sistem menjalankan setiap aplikasi dalam proses terpisah dengan izin file yang
    ++membatasi akses ke aplikasi lain, aplikasi Anda tidak bisa langsung mengaktifkan komponen dari aplikasi lain. Akan tetapi, sistem
    ++Android bisa melakukannya. Jadi, untuk mengaktifkan
    ++komponen dalam aplikasi lain, Anda harus mengirim pesan ke sistem yang menetapkan <em>intent</em> Anda untuk memulai
    ++komponen tertentu. Selanjutnya sistem akan mengaktifkan komponen untuk Anda.</p>
    ++
    ++
    ++<h3 id="ActivatingComponents">Mengaktifkan Komponen</h3>
    ++
    ++<p>Tiga dari empat tipe komponen&mdash;aktivitas, layanan, dan
    ++penerima siaran&mdash;diaktifkan oleh pesan asinkron yang disebut <em>intent</em>.
    ++Intent saling mengikat setiap komponen saat runtime (Anda bisa menganggapnya
    ++sebagai pembawa pesan yang meminta tindakan dari komponen lain), baik komponen itu milik aplikasi Anda
    ++atau milik aplikasi lain.</p>
    ++
    ++<p>Intent dibuat dengan objek {@link android.content.Intent}, yang mendefinisikan pesan untuk
    ++mengaktifkan komponen tertentu atau komponen <em>tipe</em> komponen tertentu&mdash;masing-masing intent
    ++bisa eksplisit atau implisit.</p>
    ++
    ++<p>Untuk aktivitas dan layanan, intent mendefinisikan tindakan yang akan dilakukan (misalnya, untuk "melihat" atau
    ++"mengirim" sesuatu) dan mungkin menetapkan URI data untuk ditindaklanjuti (salah satu hal yang mungkin perlu diketahui
    ++oleh komponen yang akan dimulai). Misalnya, intent mungkin menyampaikan permintaan suatu
    ++aktivitas untuk menampilkan gambar atau membuka halaman web. Dalam beberapa kasus, Anda bisa memulai
    ++aktivitas untuk menerima hasil, dalam hal ini, aktivitas juga akan mengembalikan hasil
    ++dalam {@link android.content.Intent} (misalnya Anda bisa mengeluarkan intent agar
    ++pengguna bisa memilih kontak pribadi dan memintanya dikembalikan kepada Anda&mdash;intent yang dikembalikan menyertakan URI yang
    ++menunjuk ke kontak yang dipilih).</p>
    ++
    ++<p>Untuk penerima siaran, intent hanya mendefinisikan
    ++pengumuman yang sedang disiarkan (misalnya, siaran untuk menunjukkan baterai perangkat hampir habis
    ++hanya menyertakan string tindakan yang menunjukkan "baterai hampir habis").</p>
    ++
    ++<p>Tipe komponen lainnya dan penyedia konten, tidak diaktifkan oleh intent. Melainkan
    ++diaktifkan saat ditargetkan oleh permintaan dari {@link android.content.ContentResolver}. Resolver
    ++konten menangani semua transaksi langsung dengan penyedia konten sehingga komponen yang melakukan
    ++transaksi dengan penyedia tidak perlu dan sebagai gantinya memanggil metode pada objek {@link
    ++android.content.ContentResolver}. Ini membuat lapisan abstraksi antara penyedia
    ++konten dan komponen yang meminta informasi (demi keamanan).</p>
    ++
    ++<p>Ada beberapa metode terpisah untuk mengaktifkan masing-masing tipe komponen:</p>
    ++<ul>
    ++  <li>Anda bisa memulai aktivitas (atau memberinya pekerjaan baru) dengan
    ++meneruskan {@link android.content.Intent} ke {@link android.content.Context#startActivity
    ++startActivity()} atau {@link android.app.Activity#startActivityForResult startActivityForResult()}
    ++(bila Anda ingin aktivitas mengembalikan hasil).</li>
    ++  <li>Anda bisa memulai layanan (atau memberikan instruksi baru ke layanan yang sedang berlangsung) dengan
    ++meneruskan {@link android.content.Intent} ke {@link android.content.Context#startService
    ++startService()}. Atau Anda bisa mengikat ke layanan dengan meneruskan {@link android.content.Intent} ke
    ++{@link android.content.Context#bindService bindService()}.</li>
    ++  <li>Anda bisa memulai siaran dengan meneruskan {@link android.content.Intent} ke metode seperti
    ++{@link android.content.Context#sendBroadcast(Intent) sendBroadcast()}, {@link
    ++android.content.Context#sendOrderedBroadcast(Intent, String) sendOrderedBroadcast()}, atau {@link
    ++android.content.Context#sendStickyBroadcast sendStickyBroadcast()}.</li>
    ++  <li>Anda bisa melakukan query ke penyedia konten dengan memanggil {@link
    ++android.content.ContentProvider#query query()} pada {@link android.content.ContentResolver}.</li>
    ++</ul>
    ++
    ++<p>Untuk informasi selengkapnya tentang menggunakan intent, lihat dokumen <a href="{@docRoot}guide/components/intents-filters.html">Intent dan Filter
    ++ Intent</a>. Informasi selengkapnya tentang mengaktifkan komponen
    ++tertentu juga tersedia dalam dokumen berikut: <a href="{@docRoot}guide/components/activities.html">Aktivitas</a>, <a href="{@docRoot}guide/components/services.html">Layanan</a>, {@link
    ++android.content.BroadcastReceiver} dan <a href="{@docRoot}guide/topics/providers/content-providers.html">Penyedia Konten</a>.</p>
    ++
    ++
    ++<h2 id="Manifest">File Manifes</h2>
    ++
    ++<p>Sebelum sistem Android bisa memulai komponen aplikasi, sistem harus mengetahui
    ++keberadaan komponen dengan membaca file {@code AndroidManifest.xml} aplikasi (file
    ++"manifes"). Aplikasi Anda harus mendeklarasikan semua komponennya dalam file ini, yang harus menjadi akar
    ++dari direktori proyek aplikasi.</p>
    ++
    ++<p>Manifes melakukan banyak hal selain mendeklarasikan komponen aplikasi,
    ++seperti:</p>
    ++<ul>
    ++  <li>Mengidentifikasi izin pengguna yang diperlukan aplikasi, seperti akses Internet atau
    ++akses-baca ke kontak pengguna.</li>
    ++  <li>Mendeklarasikan <a href="{@docRoot}guide/topics/manifest/uses-sdk-element.html#ApiLevels">API Level</a>
    ++ minimum yang diperlukan aplikasi, berdasarkan API yang digunakan aplikasi.</li>
    ++  <li>Mendeklarasikan fitur perangkat keras dan perangkat lunak yang diperlukan aplikasi, seperti kamera,
    ++layanan Bluetooth, atau layar multisentuh.</li>
    ++  <li>Pustaka API aplikasi perlu ditautkan (selain
    ++API kerangka kerja Android), seperti pustaka
    ++<a href="http://code.google.com/android/add-ons/google-apis/maps-overview.html">Google Maps.</a></li>
    ++  <li>Dan lainnya</li>
    ++</ul>
    ++
    ++
    ++<h3 id="DeclaringComponents">Mendeklarasikan komponen</h3>
    ++
    ++<p>Tugas utama manifes adalah menginformasikan komponen aplikasi pada sistem. Misalnya,
    ++file manifes bisa mendeklarasikan aktivitas sebagai berikut: </p>
    ++
    ++<pre>
    ++&lt;?xml version="1.0" encoding="utf-8"?&gt;
    ++&lt;manifest ... &gt;
    ++    &lt;application android:icon="@drawable/app_icon.png" ... &gt;
    ++        &lt;activity android:name="com.example.project.ExampleActivity"
    ++                  android:label="@string/example_label" ... &gt;
    ++        &lt;/activity&gt;
    ++        ...
    ++    &lt;/application&gt;
    ++&lt;/manifest&gt;</pre>
    ++
    ++<p>Dalam elemen <code><a
    ++href="{@docRoot}guide/topics/manifest/application-element.html">&lt;application&gt;</a></code>
    ++, atribut {@code android:icon} menunjuk ke sumber daya untuk ikon yang mengidentifikasi
    ++aplikasi.</p>
    ++
    ++<p>Dalam elemen <code><a
    ++href="{@docRoot}guide/topics/manifest/activity-element.html">&lt;activity&gt;</a></code>,
    ++atribut {@code android:name} menetapkan nama kelas yang sepenuhnya memenuhi syarat subkelas {@link
    ++android.app.Activity} dan atribut {@code android:label} menetapkan string yang akan
    ++digunakan sebagai label yang terlihat oleh pengguna untuk aktivitas tersebut.</p>
    ++
    ++<p>Anda harus mendeklarasikan semua komponen aplikasi dengan cara ini:</p>
    ++<ul>
    ++  <li>Elemen <code><a
    ++href="{@docRoot}guide/topics/manifest/activity-element.html">&lt;activity&gt;</a></code> untuk
    ++aktivitas</li>
    ++  <li>Elemen <code><a
    ++href="{@docRoot}guide/topics/manifest/service-element.html">&lt;service&gt;</a></code> untuk
    ++layanan</li>
    ++  <li>Elemen <code><a
    ++href="{@docRoot}guide/topics/manifest/receiver-element.html">&lt;receiver&gt;</a></code> untuk
    ++penerima siaran</li>
    ++  <li>Elemen <code><a
    ++href="{@docRoot}guide/topics/manifest/provider-element.html">&lt;provider&gt;</a></code> untuk
    ++penyedia konten</li>
    ++</ul>
    ++
    ++<p>Aktivitas, layanan, dan penyedia konten yang Anda sertakan dalam kode sumber, namun tidak
    ++dideklarasikan dalam manifes, tidak akan terlihat pada sistem dan, akibatnya, tidak pernah bisa berjalan.  Akan tetapi,
    ++penerima siaran
    ++bisa dideklarasikan dalam manifes atau dibuat secara dinamis dalam kode (sebagai objek
    ++{@link android.content.BroadcastReceiver}) dan didaftarkan pada sistem dengan memanggil
    ++{@link android.content.Context#registerReceiver registerReceiver()}.</p>
    ++
    ++<p>Untuk informasi selengkapnya tentang cara menstrukturkan file manifes untuk aplikasi Anda,
    ++lihat dokumentasi <a href="{@docRoot}guide/topics/manifest/manifest-intro.html">File AndroidManifest.xml</a>. </p>
    ++
    ++
    ++
    ++<h3 id="DeclaringComponentCapabilities">Mendeklarasikan kemampuan komponen</h3>
    ++
    ++<p>Seperti telah dibahas di atas, dalam <a href="#ActivatingComponents">Mengaktifkan Komponen</a>, Anda bisa menggunakan
    ++{@link android.content.Intent} untuk memulai aktivitas, layanan, dan penerima siaran. Anda bisa
    ++melakukannya dengan menamai komponen sasaran secara eksplisit (menggunakan nama kelas komponen) dalam intent. Akan tetapi,
    ++kemampuan intent sebenarnya ada pada konsep <em>intent implisit</em>. Intent implisit
    ++cuma menjelaskan tipe tindakan yang akan dilakukan (dan, secara opsional, data tempat Anda ingin
    ++melakukan tindakan) dan memungkinkan sistem untuk menemukan komponen pada perangkat yang bisa melakukan
    ++tindakan tersebut dan memulainya. Jika ada banyak komponen yang bisa melakukan tindakan yang dijelaskan oleh intent,
    ++maka pengguna bisa memilih komponen yang akan digunakan.</p>
    ++
    ++<p>Cara sistem mengidentifikasi komponen yang bisa merespons intent adalah dengan membandingkan
    ++intent yang diterima dengan <i>filter intent</i> yang disediakan dalam file manifes aplikasi lainnya pada
    ++perangkat.</p>
    ++
    ++<p>Bila mendeklarasikan aktivitas dalam manifes aplikasi, secara opsional Anda bisa menyertakan
    ++filter intent yang mendeklarasikan kemampuan aktivitas agar bisa merespons intent dari
    ++aplikasi lain. Anda bisa mendeklarasikan filter intent untuk komponen dengan
    ++menambahkan elemen <a href="{@docRoot}guide/topics/manifest/intent-filter-element.html">{@code
    ++&lt;intent-filter&gt;}</a> sebagai anak elemen deklarasi komponen.</p>
    ++
    ++<p>Misalnya, jika Anda telah membangun aplikasi email dengan aktivitas untuk menulis email baru, Anda bisa
    ++mendeklarasikan filter intent untuk merespons intent "kirim" (untuk mengirim email baru) seperti ini:</p>
    ++<pre>
    ++&lt;manifest ... >
    ++    ...
    ++    &lt;application ... &gt;
    ++        &lt;activity android:name="com.example.project.ComposeEmailActivity">
    ++            &lt;intent-filter>
    ++                &lt;action android:name="android.intent.action.SEND" />
    ++                &lt;data android:type="*/*" />
    ++                &lt;category android:name="android.intent.category.DEFAULT" />
    ++            &lt;/intent-filter>
    ++        &lt;/activity>
    ++    &lt;/application&gt;
    ++&lt;/manifest>
    ++</pre>
    ++
    ++<p>Kemudian, jika aplikasi lain membuat intent dengan tindakan {@link
    ++android.content.Intent#ACTION_SEND} dan meneruskannya ke {@link android.app.Activity#startActivity
    ++startActivity()}, sistem bisa memulai aktivitas Anda agar pengguna bisa menulis draf dan mengirim
    ++email.</p>
    ++
    ++<p>Untuk informasi selengkapnya tentang membuat filter intent, lihat dokumen <a href="{@docRoot}guide/components/intents-filters.html">Intent dan Filter Intent</a>.
    ++</p>
    ++
    ++
    ++
    ++<h3 id="DeclaringRequirements">Mendeklarasikan kebutuhan aplikasi</h3>
    ++
    ++<p>Ada berbagai macam perangkat yang didukung oleh Android dan tidak
    ++semuanya menyediakan fitur dan kemampuan yang sama. Agar aplikasi Anda tidak dihapus pada perangkat yang tidak memiliki
    ++fitur yang diperlukan aplikasi, Anda harus jelas mendefinisikan profil mengenai
    ++tipe perangkat yang didukung aplikasi dengan mendeklarasikan kebutuhan perangkat dan perangkat lunak dalam file
    ++manifes. Kebanyakan deklarasi ini hanya bersifat informasi dan sistem tidak
    ++membacanya, namun layanan eksternal seperti Google Play akan membacanya untuk menyediakan
    ++penyaringan bagi pengguna saat mereka mencari aplikasi dari perangkat.</p>
    ++
    ++<p>Misalnya, jika aplikasi memerlukan kamera dan menggunakan API yang disediakan dalam Android 2.1 (<a href="{@docRoot}guide/topics/manifest/uses-sdk-element.html#ApiLevels">API Level</a> 7)
    ++, Anda harus mendeklarasikannya sebagai kebutuhan dalam file manifes seperti ini:</p>
    ++
    ++<pre>
    ++&lt;manifest ... >
    ++    &lt;uses-feature android:name="android.hardware.camera.any"
    ++                  android:required="true" />
    ++    &lt;uses-sdk android:minSdkVersion="7" android:targetSdkVersion="19" />
    ++    ...
    ++&lt;/manifest>
    ++</pre>
    ++
    ++<p>Sekarang, perangkat yang <em>tidak</em> memiliki kamera dan menggunakan
    ++Android versi <em>lebih rendah</em> dari 2.1 tidak bisa menginstal aplikasi Anda dari Google Play.</p>
    ++
    ++<p>Akan tetapi, bisa juga mendeklarasikan bahwa aplikasi Anda menggunakan kamera, namun tidak
    ++<em>mengharuskannya</em>. Dalam hal itu, aplikasi Anda harus mengatur atribut <a href="{@docRoot}guide/topics/manifest/uses-feature-element.html#required">{@code required}</a>
    ++ ke {@code "false"} dan memeriksa saat runtime apakah
    ++perangkat memiliki kamera dan menonaktifkan setiap fitur kamera yang sesuai.</p>
    ++
    ++<p>Informasi selengkapnya tentang cara mengelola kompatibilitas aplikasi dengan
    ++perangkat yang berbeda disediakan dalam dokumen
    ++<a href="{@docRoot}guide/practices/compatibility.html">Kompatibilitas Perangkat</a>.</p>
    ++
    ++
    ++
    ++<h2 id="Resources">Sumber Daya Aplikasi</h2>
    ++
    ++<p>Aplikasi Android tidak hanya terdiri dari kode&mdash;Aplikasi memerlukan sumber daya yang
    ++terpisah dari kode sumber, seperti gambar, file audio, dan apa saja yang berkaitan dengan
    ++presentasi visual dari aplikasi. Misalnya, Anda harus mendefinisikan animasi, menu, gaya, warna,
    ++dan layout antarmuka pengguna aktivitas dengan file XML. Penggunaan sumber daya aplikasi
    ++mempermudah pembaruan berbagai karakteristik aplikasi Anda tanpa memodifikasi kode dan&mdash;dengan menyediakan
    ++seperangkat sumber daya alternatif&mdash;memungkinkan Anda mengoptimalkan aplikasi untuk berbagai konfigurasi
    ++perangkat berbeda (seperti bahasa dan ukuran layar yang berbeda).</p>
    ++
    ++<p>Untuk setiap sumber daya yang Anda sertakan dalam proyek Android, alat bawaan SDK akan mendefinisikan ID integer
    ++unik, yang bisa Anda gunakan untuk mengacu sumber daya dari kode aplikasi atau dari sumber daya lainnya yang
    ++didefinisikan dalam XML. Misalnya, jika aplikasi berisi file gambar bernama {@code
    ++logo.png} (disimpan dalam direktori {@code res/drawable/}), alat SDK akan menghasilkan ID sumber daya
    ++bernama {@code R.drawable.logo}, yang bisa Anda gunakan untuk mengacu gambar dan memasukkannya dalam
    ++antarmuka pengguna.</p>
    ++
    ++<p>Salah satu aspek paling penting dari penyediaan sumber daya yang terpisah dari
    ++kode sumber adalah kemampuan Anda menyediakan sumber daya alternatif untuk konfigurasi perangkat
    ++yang berbeda. Misalnya, dengan mendefinisikan string UI dalam XML, Anda bisa menerjemahkan string ke dalam
    ++bahasa lain dan menyimpan string itu dalam file terpisah. Kemudian, berdasarkan <em>qualifier</em>
    ++bahasa yang ditambahkan ke nama direktori sumber daya (seperti {@code res/values-fr/} untuk nilai
    ++string Prancis) dan pengaturan bahasa pengguna, sistem Android akan menerapkan string bahasa yang sesuai
    ++untuk UI Anda.</p>
    ++
    ++<p>Android mendukung banyak <em>qualifier</em> berbeda untuk sumber daya alternatif Anda. Qualifier
    ++adalah string pendek yang Anda sertakan dalam nama direktori sumber
    ++daya untuk mendefinisikan konfigurasi perangkat yang harus digunakan sumber daya tersebut. Contoh lainnya,
    ++Anda harus sering membuat layout berbeda untuk aktivitas, bergantung pada
    ++orientasi layar dan ukuran perangkat. Misalnya, saat layar perangkat dalam orientasi
    ++tegak, Anda mungkin ingin layout tombolnya vertikal, tetapi saat layar dalam orientasi
    ++mendatar, tombolnya harus sejajar horizontal. Untuk mengubah layout
    ++sesuai orientasi, Anda bisa mendefinisikan dua layout berbeda dan menerapkan qualifier yang
    ++tepat untuk setiap nama direktori layout. Kemudian, sistem secara otomatis menerapkan
    ++layout yang tepat sesuai dengan orientasi perangkat saat ini.</p>
    ++
    ++<p>Untuk informasi selengkapnya tentang berbagai jenis sumber daya yang bisa disertakan dalam aplikasi dan cara
    ++membuat sumber daya alternatif untuk konfigurasi perangkat berbeda, bacalah <a href="{@docRoot}guide/topics/resources/providing-resources.html">Menyediakan Sumber Daya</a>.</p>
    ++
    ++
    ++
    ++<div class="next-docs">
    ++<div class="col-6">
    ++  <h2 class="norule">Teruskan membaca tentang:</h2>
    ++  <dl>
    ++    <dt><a href="{@docRoot}guide/components/intents-filters.html">Intent dan Filter Intent</a>
    ++    </dt>
    ++    <dd>Informasi tentang cara menggunakan API {@link android.content.Intent} untuk
    ++ mengaktifkan komponen aplikasi, seperti aktivitas dan layanan, dan cara menyediakan komponen aplikasi
    ++ untuk digunakan oleh aplikasi lain.</dd>
    ++    <dt><a href="{@docRoot}guide/components/activities.html">Aktivitas</a></dt>
    ++    <dd>Informasi tentang cara membuat instance kelas {@link android.app.Activity},
    ++yang menyediakan layar tersendiri dalam aplikasi bersama antarmuka pengguna.</dd>
    ++    <dt><a href="{@docRoot}guide/topics/resources/providing-resources.html">Menyediakan Sumber Daya</a></dt>
    ++    <dd>Informasi tentang cara aplikasi Android disusun untuk memisahkan sumber daya aplikasi dari
    ++kode aplikasi, termasuk cara Anda bisa menyediakan sumber daya alternatif untuk
    ++konfigurasi perangkat tertentu.
    ++    </dd>
    ++  </dl>
    ++</div>
    ++<div class="col-6">
    ++  <h2 class="norule">Anda juga mungkin tertarik dengan:</h2>
    ++  <dl>
    ++    <dt><a href="{@docRoot}guide/practices/compatibility.html">Kompatibilitas Perangkat</a></dt>
    ++    <dd>Informasi tentang cara kerja Android pada berbagai tipe perangkat dan
    ++pengenalan mengenai cara mengoptimalkan aplikasi untuk setiap perangkat atau membatasi ketersediaan aplikasi Anda untuk
    ++perangkat berbeda.</dd>
    ++    <dt><a href="{@docRoot}guide/topics/security/permissions.html">Izin Sistem</a></dt>
    ++    <dd>Informasi tentang cara Android membatasi akses aplikasi pada API tertentu dengan sistem izin
    ++yang mengharuskan persetujuan pengguna agar aplikasi dapat menggunakan API tersebut.</dd>
    ++  </dl>
    ++</div>
    ++</div>
    ++
    +diff --git a/docs/html-intl/intl/id/guide/components/index.jd b/docs/html-intl/intl/id/guide/components/index.jd
    +new file mode 100644
    +index 0000000..de40b22
    +--- /dev/null
    ++++ b/docs/html-intl/intl/id/guide/components/index.jd
    +@@ -0,0 +1,57 @@
    ++page.title=Komponen Aplikasi
    ++page.landing=true
    ++page.landing.intro=Kerangka kerja aplikasi Android memungkinkan Anda membuat aplikasi yang kaya dan inovatif menggunakan seperangkat komponen yang dapat digunakan kembali. Bagian ini menjelaskan cara membangun komponen yang mendefinisikan blok pembangun aplikasi Anda dan cara menghubungkannya bersama menggunakan intent.
    ++page.metaDescription=Kerangka kerja aplikasi Android memungkinkan Anda membuat aplikasi yang kaya dan inovatif menggunakan seperangkat komponen yang dapat digunakan kembali. Bagian ini menjelaskan cara membangun komponen yang mendefinisikan blok pembangun aplikasi Anda dan cara menghubungkannya bersama menggunakan intent.
    ++page.landing.image=images/develop/app_components.png
    ++page.image=images/develop/app_components.png
    ++
    ++@jd:body
    ++
    ++<div class="landing-docs">
    ++
    ++  <div class="col-6">
    ++    <h3>Artikel Blog</h3>
    ++
    ++    <a href="http://android-developers.blogspot.com/2012/05/using-dialogfragments.html">
    ++      <h4>Menggunakan DialogFragments</h4>
    ++      <p>Dalam posting ini, saya akan menunjukkan cara menggunakan DialogFragments dengan pustaka dukungan v4 (untuk kompatibilitas mundur pada perangkat sebelum Honeycomb) untuk menunjukkan dialog edit sederhana dan mengembalikan hasil ke Aktivitas pemanggil menggunakan antarmuka.</p>
    ++    </a>
    ++
    ++    <a href="http://android-developers.blogspot.com/2011/03/fragments-for-all.html">
    ++      <h4>Fragmen Untuk Semua</h4>
    ++      <p>Hari ini kami telah merilis pustaka statis yang memperlihatkan API Fragment yang sama (serta LoaderManager baru dan beberapa kelas lain) agar aplikasi yang kompatibel dengan Android 1.6 atau yang lebih baru bisa menggunakan fragmen untuk membuat antarmuka pengguna yang kompatibel dengan tablet. </p>
    ++    </a>
    ++
    ++    <a href="http://android-developers.blogspot.com/2010/07/multithreading-for-performance.html">
    ++      <h4>Multithreading untuk Kinerja</h4>
    ++      <p>Praktik yang baik dalam membuat aplikasi yang responsif adalah memastikan thread UI utama Anda
    ++melakukan pekerjaan minimum. Setiap tugas yang berpotensi lama dan dapat membuat aplikasi mogok harus
    ++ditangani di thread berbeda.</p>
    ++    </a>
    ++  </div>
    ++
    ++  <div class="col-6">
    ++    <h3>Pelatihan</h3>
    ++
    ++    <a href="http://developer.android.com/training/basics/activity-lifecycle/index.html">
    ++      <h4>Mengelola Daur Hidup Aktivitas</h4>
    ++      <p>Bagian ini menjelaskan pentingnya metode callback daur hidup yang diterima setiap instance Aktivitas
    ++dan cara menggunakannya sehingga aktivitas Anda melakukan yang diharapkan pengguna dan tidak menghabiskan sumber daya sistem
    ++saat aktivitas tidak membutuhkannya.</p>
    ++    </a>
    ++
    ++    <a href="http://developer.android.com/training/basics/fragments/index.html">
    ++      <h4>Membangun UI Dinamis dengan Fragmen</h4>
    ++      <p>Bagian ini menunjukkan kepada Anda cara membuat pengalaman pengguna yang dinamis dengan fragmen dan mengoptimalkan
    ++pengalaman pengguna aplikasi Anda dengan berbagai ukuran layar, sekaligus terus mendukung
    ++perangkat yang menjalankan versi sebelumnya, sesudah versi Android 1.6.</p>
    ++    </a>
    ++
    ++    <a href="http://developer.android.com/training/sharing/index.html">
    ++      <h4>Berbagi Konten</h4>
    ++      <p>Bagian ini membahas beberapa cara umum untuk mengirim dan menerima konten antar
    ++aplikasi menggunakan API Intent dan objek ActionProvider.</p>
    ++    </a>
    ++  </div>
    ++
    ++</div>
    +diff --git a/docs/html-intl/intl/id/guide/components/intents-filters.jd b/docs/html-intl/intl/id/guide/components/intents-filters.jd
    +new file mode 100644
    +index 0000000..8e89b5d
    +--- /dev/null
    ++++ b/docs/html-intl/intl/id/guide/components/intents-filters.jd
    +@@ -0,0 +1,899 @@
    ++page.title=Intent dan Filter Intent
    ++page.tags="IntentFilter"
    ++@jd:body
    ++
    ++<div id="qv-wrapper">
    ++<div id="qv">
    ++
    ++<h2>Dalam dokumen ini</h2>
    ++<ol>
    ++  <li><a href="#Types">Tipe Intent</a></li>
    ++  <li><a href="#Building">Membangun Intent</a>
    ++    <ol>
    ++      <li><a href="#ExampleExplicit">Contoh intent eksplisit</a></li>
    ++      <li><a href="#ExampleSend">Contoh intent implisit</a></li>
    ++      <li><a href="#ForceChooser">Memaksakan pemilih aplikasi</a></li>
    ++    </ol>
    ++  </li>
    ++  <li><a href="#Receiving">Menerima Intent Implisit</a>
    ++    <ol>
    ++      <li><a href="#ExampleFilters">Contoh filter</a></li>
    ++    </ol>
    ++  </li>
    ++  <li><a href="#PendingIntent">Menggunakan Intent Tertunda</a></li>
    ++  <li><a href="#Resolution">Resolusi Intent</a>
    ++    <ol>
    ++      <li><a href="#ActionTest">Pengujian tindakan</a></li>
    ++      <li><a href="#CategoryTest">Pengujian kategori</a></li>
    ++      <li><a href="#DataTest">Pengujian data</a></li>
    ++      <li><a href="#imatch">Pencocokan intent</a></li>
    ++    </ol>
    ++  </li>
    ++</ol>
    ++
    ++<h2>Lihat juga</h2>
    ++<ol>
    ++<li><a href="{@docRoot}training/basics/intents/index.html">Berinteraksi dengan Aplikasi Lain</a></li>
    ++<li><a href="{@docRoot}training/sharing/index.html">Berbagi Konten</a></li>
    ++</ol>
    ++
    ++</div>
    ++</div>
    ++
    ++
    ++
    ++
    ++<p>{@link android.content.Intent} merupakan objek pertukaran pesan yang bisa Anda gunakan untuk meminta tindakan
    ++dari <a href="{@docRoot}guide/components/fundamentals.html#Components">komponen aplikasi</a> lain.
    ++Walaupun intent memudahkan komunikasi antarkomponen dalam beberapa cara, ada tiga
    ++kasus-penggunaan dasar:</p>
    ++
    ++<ul>
    ++<li><b>Untuk memulai aktivitas:</b>
    ++<p>{@link android.app.Activity} menyatakan satu layar dalam aplikasi. Anda bisa memulai instance
    ++baru {@link android.app.Activity} dengan meneruskan {@link android.content.Intent}
    ++ke {@link android.content.Context#startActivity startActivity()}. {@link android.content.Intent}
    ++menjelaskan aktivitas yang akan dimulai dan membawa data yang diperlukan.</p>
    ++
    ++<p>Jika Anda ingin menerima hasil dari aktivitas bila selesai,
    ++panggil {@link android.app.Activity#startActivityForResult
    ++startActivityForResult()}. Aktivitas Anda menerima hasil
    ++sebagai objek {@link android.content.Intent} terpisah dalam callback {@link
    ++android.app.Activity#onActivityResult onActivityResult()} aktivitas Anda.
    ++Untuk informasi selengkapnya, lihat panduan <a href="{@docRoot}guide/components/activities.html">Aktivitas</a>.</p></li>
    ++
    ++<li><b>Untuk memulai layanan:</b>
    ++<p>{@link android.app.Service} adalah komponen yang melakukan operasi di latar belakang
    ++tanpa antarmuka pengguna. Anda bisa memulai layanan untuk melakukan operasi satu-kali
    ++(misalnya mengunduh file) dengan meneruskan {@link android.content.Intent}
    ++ke {@link android.content.Context#startService startService()}. {@link android.content.Intent}
    ++menjelaskan layanan yang akan dimulai dan membawa data yang diperlukan.</p>
    ++
    ++<p>Jika layanan didesain dengan antarmuka pengguna klien-server, Anda bisa mengikat ke layanan
    ++dari komponen lain dengan meneruskan {@link android.content.Intent} ke {@link
    ++android.content.Context#bindService bindService()}</code>. Untuk informasi selengkapnya, lihat panduan <a href="{@docRoot}guide/components/services.html">Layanan</a>.</p></li>
    ++
    ++<li><b>Untuk mengirim siaran:</b>
    ++<p>Siaran adalah pesan yang bisa diterima aplikasi apa saja. Sistem menyampaikan beragam siaran
    ++untuk kejadian sistem, misalnya saat sistem booting atau saat perangkat mulai mengisi daya.
    ++Anda bisa mengirim siaran ke aplikasi lain dengan meneruskan {@link android.content.Intent}
    ++ke {@link android.content.Context#sendBroadcast(Intent) sendBroadcast()},
    ++{@link android.content.Context#sendOrderedBroadcast(Intent, String)
    ++sendOrderedBroadcast()}, atau {@link
    ++android.content.Context#sendStickyBroadcast sendStickyBroadcast()}.</p>
    ++</li>
    ++</ul>
    ++
    ++
    ++
    ++
    ++<h2 id="Types">Tipe Intent</h2>
    ++
    ++<p>Ada dua tipe intent:</p>
    ++
    ++<ul>
    ++<li><b>Intent eksplisit</b> menetapkan komponen untuk memulai dengan nama (
    ++nama kelas yang sepenuhnya memenuhi syarat). Anda biasanya akan menggunakan intent eksplisit untuk memulai sebuah komponen
    ++dalam aplikasi sendiri, karena Anda mengetahui nama kelas dari aktivitas atau layanan yang ingin dimulai.
    ++Misalnya, mulai aktivitas baru sebagai respons terhadap tindakan pengguna atau mulai layanan untuk mengunduh
    ++file di latar belakang.</li>
    ++
    ++<li><b>Intent implisit</b> tidak menetapkan komponen tertentu, melainkan mendeklarasikan tindakan umum
    ++yang dilakukan, yang memungkinkan komponen aplikasi lain untuk menanganinya. Misalnya, jika Anda ingin
    ++menampilkan sebuah lokasi di peta pada pengguna, Anda bisa menggunakan intent implisit untuk meminta aplikasi lain
    ++yang mampu untuk menunjukkan lokasi yang telah ditetapkan di peta tersebut.</li>
    ++</ul>
    ++
    ++<p>Saat Anda membuat intent eksplisit untuk memulai aktivitas atau layanan, sistem akan segera
    ++memulai komponen aplikasi yang telah ditetapkan dalam objek {@link android.content.Intent}.</p>
    ++
    ++<div class="figure" style="width:446px">
    ++<img src="{@docRoot}images/components/intent-filters@2x.png" width="446" alt="" />
    ++<p class="img-caption"><strong>Gambar 1.</strong> Ilustrasi yang menggambarkan cara intent implisit
    ++disampaikan melalui sistem untuk memulai aktivitas lain: <b>[1]</b> <em>Aktivitas A</em> membuat sebuah
    ++{@link android.content.Intent} dengan keterangan tindakan dan meneruskannya ke {@link
    ++android.content.Context#startActivity startActivity()}. <b>[2]</b> Sistem Android akan mencari semua
    ++aplikasi untuk filter intent yang cocok dengan intent tersebut. Bila cocok, <b>[3]</b> sistem akan
    ++memulai aktivitas mencocokkan (<em>Aktivitas B</em>) dengan memanggil metode {@link
    ++android.app.Activity#onCreate onCreate()} dan meneruskannya ke {@link android.content.Intent}.
    ++</p>
    ++</div>
    ++
    ++<p>Bila Anda membuat intent implisit, sistem Android akan menemukan komponen yang sesuai untuk memulai
    ++dengan membandingkan konten intent dengan <em>filter intent</em> yang dideklarasikan dalam <a href="{@docRoot}guide/topics/manifest/manifest-intro.html">file manifes</a> aplikasi lain di
    ++perangkat. Jika intent cocok dengan filter intent, sistem akan memulai komponen tersebut dan mengiriminya
    ++objek {@link android.content.Intent}. Jika banyak filter intent yang kompatibel, sistem
    ++menampilkan dialog sehingga pengguna bisa memilih aplikasi yang akan digunakan.</p>
    ++
    ++<p>Filter intent adalah ekspresi dalam file manifes aplikasi yang
    ++menetapkan tipe intent yang akan diterima
    ++komponen. Misalnya, dengan mendeklarasikan intent filter untuk aktivitas,
    ++Anda akan memungkinkan aplikasi lain untuk langsung memulai aktivitas Anda dengan intent tertentu.
    ++Demikian pula, jika Anda <em>tidak</em> mendeklarasikan filter intent untuk suatu aktivitas, maka aktivitas tersebut hanya bisa dimulai
    ++dengan intent eksplisit.</p>
    ++
    ++<p class="caution"><strong>Perhatian:</strong> Untuk memastikan aplikasi Anda aman, selalu gunakan intent
    ++eksplisit saat memulai {@link android.app.Service} dan jangan
    ++mendeklarasikan filter intent untuk layanan. Menggunakan intent implisit untuk memulai layanan akan menimbulkan
    ++bahaya keamanan karena Anda tidak bisa memastikan layanan apa yang akan merespons intent,
    ++dan pengguna tidak bisa melihat layanan mana yang dimulai. Mulai dari Android 5.0 (API level 21), sistem
    ++melontarkan eksepsi jika Anda memanggil {@link android.content.Context#bindService bindService()}
    ++dengan intent implisit.</p>
    ++
    ++
    ++
    ++
    ++
    ++<h2 id="Building">Membangun Intent</h2>
    ++
    ++<p>Objek {@link android.content.Intent} membawa informasi yang digunakan sistem Android
    ++untuk menentukan komponen mana yang akan dimulai (misalnya nama persis dari suatu komponen atau kategori
    ++komponen yang seharusnya menerima intent), ditambah informasi yang digunakan komponen penerima untuk
    ++melakukan tindakan dengan benar (misalnya tindakan yang harus dilakukan dan data yang harus diolah).</p>
    ++
    ++
    ++<p>Informasi utama yang dimuat dalam {@link android.content.Intent} adalah sebagai berikut:</p>
    ++
    ++<dl>
    ++
    ++<dt><b>Nama komponen</b></dt>
    ++<dd>Nama komponen yang akan dimulai.
    ++
    ++<p>Ini opsional, namun merupakan bagian informasi penting yang membuat intent
    ++menjadi <b>eksplisit</b>, yaitu intent harus dikirim hanya ke komponen aplikasi
    ++yang didefinisikan oleh nama komponen. Tanpa nama komponen, intent menjadi <b>implisit</b> dan
    ++sistem akan memutuskan komponen mana yang harus menerima intent berdasarkan informasi intent lain
    ++(misalnya tindakan, data, dan kategori&mdash;yang dijelaskan di bawah ini). Jadi jika Anda ingin memulai komponen
    ++tertentu dalam aplikasi, Anda harus menetapkan nama komponen tersebut.</p>
    ++
    ++<p class="note"><strong>Catatan:</strong> Saat memulai {@link android.app.Service}, Anda harus
    ++<strong>selalu menetapkan nama komponen</strong>. Jika tidak, maka Anda tidak bisa memastikan layanan apa
    ++yang akan merespons intent tersebut, dan pengguna tidak bisa melihat layanan mana yang dimulai.</p>
    ++
    ++<p>Bidang {@link android.content.Intent} ini adalah objek
    ++{@link android.content.ComponentName}, yang bisa Anda tetapkan menggunakan
    ++nama kelas yang sepenuhnya memenuhi syarat dari komponen target, termasuk nama paket aplikasi. Misalnya,
    ++{@code com.example.ExampleActivity}. Anda bisa mengatur nama komponen dengan {@link
    ++android.content.Intent#setComponent setComponent()}, {@link android.content.Intent#setClass
    ++setClass()}, {@link android.content.Intent#setClassName(String, String) setClassName()}, atau dengan konstruktor
    ++{@link android.content.Intent}.</p>
    ++
    ++</dd>
    ++
    ++<p><dt><b>Tindakan</b></dt>
    ++<dd>String yang menetapkan tindakan generik untuk dilakukan (misalnya <em>lihat</em> atau <em>pilih</em>).
    ++
    ++<p>Dalam hal intent siaran, ini adalah tindakan yang terjadi dan dilaporkan.
    ++Tindakan ini sangat menentukan bagaimana keseluruhan intent disusun&mdash;terutama
    ++apa yang dimuat dalam data dan ekstra.
    ++
    ++<p>Anda bisa menetapkan tindakan sendiri yang akan digunakan oleh intent dalam aplikasi Anda (atau digunakan oleh aplikasi
    ++lain untuk memanggil komponen dalam aplikasi Anda), namun Anda harus menggunakan konstanta tindakan
    ++yang didefinisikan oleh kelas {@link android.content.Intent} atau kelas kerangka kerja lain. Berikut ini adalah beberapa
    ++tindakan umum untuk memulai sebuah aktivitas:</p>
    ++
    ++<dl>
    ++<dt>{@link android.content.Intent#ACTION_VIEW}</dt>
    ++   <dd>Gunakan tindakan ini dalam intent dengan {@link
    ++   android.content.Context#startActivity startActivity()} saat Anda memiliki beberapa informasi yang
    ++ bisa ditampilkan aktivitas kepada pengguna, misalnya foto yang bisa dilihat dalam aplikasi galeri, atau alamat
    ++ yang bisa dilihat dalam aplikasi peta.</dd>
    ++
    ++<dt>{@link android.content.Intent#ACTION_SEND}</dt>
    ++   <dd>Juga dikenal dengan intent "berbagi", Anda harus menggunakannya dalam intent dengan {@link
    ++   android.content.Context#startActivity startActivity()} bila Anda memiliki data yang bisa digunakan pengguna untuk
    ++ berbagi melalui aplikasi lain, misalnya aplikasi email atau aplikasi jaringan sosial.</dd>
    ++</dl>
    ++
    ++<p>Lihat referensi kelas {@link android.content.Intent} untuk konstanta
    ++selengkapnya yang mendefinisikan tindakan generik.  Tindakan lain yang didefinisikan
    ++di tempat lain dalam kerangka kerja Android, misalnya dalam {@link android.provider.Settings} untuk tindakan
    ++yang membuka layar tertentu dalam aplikasi Settings di sistem.</p>
    ++
    ++<p>Anda bisa menetapkan tindakan untuk sebuah intent dengan {@link android.content.Intent#setAction
    ++setAction()} atau dengan konstruktor {@link android.content.Intent}.</p>
    ++
    ++<p>Jika mendefinisikan tindakan Anda sendiri, pastikan untuk memasukkan nama paket aplikasi Anda
    ++sebagai awalan. Misalnya:</p>
    ++<pre>static final String ACTION_TIMETRAVEL = "com.example.action.TIMETRAVEL";</pre>
    ++</dd>
    ++
    ++<dt><b>Data</b></dt>
    ++<dd>URI (objek {@link android.net.Uri}) yang mengacu data untuk diolah dan/atau
    ++tipe MIME dari data tersebut. Tipe data yang disediakan umumnya didikte oleh tindakan intent.
    ++Misalnya, jika tindakan merupakan {@link android.content.Intent#ACTION_EDIT}, data harus berisi
    ++URI dari dokumen untuk diedit.
    ++
    ++<p>Saat membuat intent,
    ++seringkali tipe data (tipe MIME-nya) selain URI perlu ditetapkan.
    ++Misalnya, aktivitas yang mampu menampilkan gambar mungkin tidak mampu
    ++memutar file audio, walaupun format URI mungkin serupa.
    ++Jadi menetapkan tipe MIME data Anda akan membantu sistem
    ++Android menemukan komponen terbaik untuk diterima intent.
    ++Akan tetapi, tipe MIME seringkali bisa diambil dari URI&mdash;terutama saat datanya merupakan URI
    ++{@code content:}, yang menunjukkan data tersebut berada di perangkat dan dikontrol oleh
    ++{@link android.content.ContentProvider}, yang membuat data tipe MIME terlihat di sistem.</p>
    ++
    ++<p>Untuk mengatur data URI saja, panggil {@link android.content.Intent#setData setData()}.
    ++Untuk mengatur tipe MIME saja, panggil {@link android.content.Intent#setType setType()}. Jika perlu, Anda
    ++bisa mengatur keduanya secara eksplisit dengan {@link
    ++android.content.Intent#setDataAndType setDataAndType()}.</p>
    ++
    ++<p class="caution"><strong>Perhatian:</strong> Jika ingin mengatur tipe URI dan MIME,
    ++<strong>jangan</strong> panggil {@link android.content.Intent#setData setData()} dan
    ++{@link android.content.Intent#setType setType()} karena mereka saling menghapuskan nilai satu sama lain.
    ++Selalu gunakan {@link android.content.Intent#setDataAndType setDataAndType()} untuk mengatur
    ++tipe URI maupun MIME.</p>
    ++</dd>
    ++
    ++<p><dt><b>Kategori</b></dt>
    ++<dd>String yang berisi informasi tambahan tentang jenis komponen
    ++yang harus menangani intent.  Keterangan kategori dalam jumlah berapa pun bisa
    ++dimasukkan dalam intent, namun sebagian besar intent tidak memerlukan kategori.
    ++Berikut ini adalah beberapa kategori umum:
    ++
    ++<dl>
    ++<dt>{@link android.content.Intent#CATEGORY_BROWSABLE}</dt>
    ++  <dd>Aktivitas target memungkinkannya dimulai oleh browser web untuk menampilkan data
    ++yang diacu oleh tautan&mdash;misalnya gambar atau pesan e-mail.
    ++  </dd>
    ++<dt>{@link android.content.Intent#CATEGORY_LAUNCHER}</dt>
    ++  <dd>Aktivitas tersebut adalah aktivitas awal dari sebuah tugas dan dicantumkan dalam
    ++       launcher aplikasi sistem.
    ++  </dd>
    ++</dl>
    ++
    ++<p>Lihat keterangan kelas {@link android.content.Intent} untuk mengetahui daftar lengkap
    ++kategori.</p>
    ++
    ++<p>Anda bisa menetapkan kategori dengan {@link android.content.Intent#addCategory addCategory()}.</p>
    ++</dd>
    ++</dl>
    ++
    ++
    ++<p>Properti yang tercantum di atas (nama komponen, tindakan, data, dan kategori) menyatakan
    ++karakteristik yang mendefinisikan intent. Dengan membaca properti ini, sistem Android
    ++mampu memutuskan komponen aplikasi yang harus dimulainya.</p>
    ++
    ++<p>Akan tetapi, intent bisa membawa informasi tambahan yang tidak memengaruhi
    ++cara intent ditetapkan pada komponen aplikasi. Intent juga bisa menyediakan:</p>
    ++
    ++<dl>
    ++<dt><b>Ekstra</b></dt>
    ++<dd>Pasangan nilai-kunci yang membawa informasi yang diperlukan untuk menghasilkan tindakan yang diminta.
    ++Seperti halnya beberapa tindakan menggunakan jenis tertentu URI data, beberapa tindakan juga menggunakan ekstra tertentu.
    ++
    ++<p>Anda bisa menambahkan data ekstra dengan beragam metode {@link android.content.Intent#putExtra putExtra()},
    ++masing-masing menerima dua parameter: nama kunci dan nilainya.
    ++Anda juga bisa membuat objek {@link android.os.Bundle} dengan semua data ekstra, kemudian memasukkan
    ++{@link android.os.Bundle} dalam {@link android.content.Intent} dengan {@link
    ++android.content.Intent#putExtras putExtras()}.</p>
    ++
    ++<p>Misalnya, saat membuat intent yang akan dikirimkan bersama email
    ++{@link android.content.Intent#ACTION_SEND}, Anda bisa menetapkan penerima "kepada" dengan kunci
    ++{@link android.content.Intent#EXTRA_EMAIL}, dan menetapkan "subjek" dengan kunci
    ++{@link android.content.Intent#EXTRA_SUBJECT}.</p>
    ++
    ++<p>Kelas {@link android.content.Intent} menetapkan beberapa konstanta {@code EXTRA_*}
    ++untuk tipe data standar. Jika Anda ingin mendeklarasikan kunci ekstra sendiri (untuk intent yang
    ++diterima aplikasi Anda), pastikan untuk memasukkan nama paket aplikasi
    ++sebagai awalan. Misalnya:</p>
    ++<pre>static final String EXTRA_GIGAWATTS = "com.example.EXTRA_GIGAWATTS";</pre>
    ++</dd>
    ++
    ++<dt><b>Flag</b></dt>
    ++<dd>Flag didefinisikan dalam kelas {@link android.content.Intent} yang berfungsi sebagai metadata untuk
    ++intent. Flag menginstruksikan cara meluncurkan aktivitas (misalnya,
    ++<a href="{@docRoot}guide/components/tasks-and-back-stack.html">tugas</a> mana yang harus dimiliki suatu aktivitas
    ++) dan cara memperlakukannya setelah diluncurkan (misalnya, apakah aktivitas tersebut masuk ke dalam daftar aktivitas
    ++terbaru) pada sistem Android.
    ++
    ++<p>Untuk informasi selengkapnya, lihat metode {@link android.content.Intent#setFlags setFlags()} .</p>
    ++</dd>
    ++
    ++</dl>
    ++
    ++
    ++
    ++
    ++<h3 id="ExampleExplicit">Contoh intent eksplisit</h3>
    ++
    ++<p>Intent eksplisit adalah intent yang Anda gunakan untuk meluncurkan komponen aplikasi tertentu, seperti
    ++aktivitas tertentu atau layanan dalam aplikasi Anda. Untuk membuat intent eksplisit, definisikan
    ++nama komponen untuk objek {@link android.content.Intent} &mdash;semua
    ++properti intent lain bersifat opsional.</p>
    ++
    ++<p>Misalnya, jika Anda ingin membangun layanan dalam aplikasi Anda, bernama {@code DownloadService},
    ++yang didesain untuk mengunduh file dari web, Anda bisa memulainya dengan kode berikut ini:</p>
    ++
    ++<pre>
    ++// Executed in an Activity, so 'this' is the {@link android.content.Context}
    ++// The fileUrl is a string URL, such as "http://www.example.com/image.png"
    ++Intent downloadIntent = new Intent(this, DownloadService.class);
    ++downloadIntent.setData({@link android.net.Uri#parse Uri.parse}(fileUrl));
    ++startService(downloadIntent);
    ++</pre>
    ++
    ++<p>Konstruktor {@link android.content.Intent#Intent(Context,Class)}
    ++ menyediakan {@link android.content.Context} aplikasi dan
    ++objek {@link java.lang.Class} pada komponen. Dengan demikian,
    ++intent ini memulai secara eksplisit kelas {@code DownloadService} dalam aplikasi.</p>
    ++
    ++<p>Untuk informasi selengkapnya tentang membangun dan memulai layanan, lihat panduan
    ++<a href="{@docRoot}guide/components/services.html">Layanan</a>.</p>
    ++
    ++
    ++
    ++
    ++<h3 id="ExampleSend">Contoh intent implisit</h3>
    ++
    ++<p>Intent implisit menetapkan tindakan yang bisa memanggil aplikasi pada perangkat yang mampu
    ++melakukan tindakan. Menggunakan intent implisit berguna bila aplikasi Anda tidak bisa melakukan
    ++tindakan, namun aplikasi lain mungkin bisa melakukannya dan Anda ingin pengguna untuk memilih aplikasi mana yang ingin digunakan.</p>
    ++
    ++<p>Misalnya, jika memiliki konten yang Anda ingin agar pengguna berbagi konten itu dengan orang lain, buatlah intent
    ++dengan tindakan {@link android.content.Intent#ACTION_SEND}
    ++dan tambahkan ekstra yang menetapkan konten yang akan dibagikan. Bila Anda memanggil
    ++{@link android.content.Context#startActivity startActivity()} dengan intent tersebut, pengguna bisa
    ++memilih aplikasi yang akan digunakan untuk berbagi konten.</p>
    ++
    ++<p class="caution"><strong>Perhatian:</strong> Ada kemungkinan pengguna tidak memiliki <em>suatu</em>
    ++aplikasi yang menangani intent implisit yang Anda kirimkan ke {@link android.content.Context#startActivity
    ++startActivity()}. Jika itu terjadi, panggilan akan gagal dan aplikasi Anda akan crash. Untuk memeriksa
    ++apakah aktivitas bisa menerima intent, panggil {@link android.content.Intent#resolveActivity
    ++resolveActivity()} pada objek {@link android.content.Intent} Anda. Jika hasilnya bukan nol,
    ++berarti setidaknya ada satu aplikasi yang bisa menangani intent tersebut dan aman untuk memanggil
    ++{@link android.content.Context#startActivity startActivity()}. Jika hasilnya nol,
    ++Anda tidak boleh menggunakan intent tersebut dan, jika memungkinkan, Anda harus menonaktifkan fitur yang mengeluarkan
    ++intent tersebut.</p>
    ++
    ++
    ++<pre>
    ++// Create the text message with a string
    ++Intent sendIntent = new Intent();
    ++sendIntent.setAction(Intent.ACTION_SEND);
    ++sendIntent.putExtra(Intent.EXTRA_TEXT, textMessage);
    ++sendIntent.setType("text/plain");
    ++
    ++// Verify that the intent will resolve to an activity
    ++if (sendIntent.resolveActivity(getPackageManager()) != null) {
    ++    startActivity(sendIntent);
    ++}
    ++</pre>
    ++
    ++<p class="note"><strong>Catatan:</strong> Dalam hal ini, URI tidak digunakan, namun tipe data intent
    ++dideklarasikan untuk menetapkan konten yang dibawa oleh ekstra.</p>
    ++
    ++
    ++<p>Saat {@link android.content.Context#startActivity startActivity()} dipanggil, sistem akan
    ++memeriksa semua aplikasi yang terinstal untuk menentukan aplikasi mana yang bisa menangani intent jenis ini (
    ++intent dengan tindakan {@link android.content.Intent#ACTION_SEND} dan yang membawa data
    ++"teks/polos"). Jika hanya ada satu aplikasi yang bisa menanganinya, aplikasi tersebut akan langsung terbuka dan diberi
    ++intent tersebut. Jika banyak aktivitas menerima intent, sistem akan
    ++menampilkan dialog sehingga pengguna bisa memilih aplikasi mana yang digunakan.</p>
    ++
    ++
    ++<div class="figure" style="width:200px">
    ++  <img src="{@docRoot}images/training/basics/intent-chooser.png" alt="">
    ++  <p class="img-caption"><strong>Gambar 2.</strong> Dialog pemilih.</p>
    ++</div>
    ++
    ++<h3 id="ForceChooser">Memaksakan pemilih aplikasi</h3>
    ++
    ++<p>Bila ada lebih dari satu aplikasi yang merespons intent implisit Anda,
    ++pengguna bisa memilih aplikasi mana yang digunakan dan membuat aplikasi tersebut pilihan default untuk
    ++tindakan tersebut. Ini sangat membantu saat melakukan tindakan di mana pengguna
    ++mungkin ingin menggunakan aplikasi yang sama untuk seterusnya, seperti saat membuka halaman web (pengguna
    ++biasanya memilih hanya satu browser web).</p>
    ++
    ++<p>Akan tetapi, jika ada banyak aplikasi yang bisa merespons intent tersebut dan pengguna mungkin ingin menggunakan aplikasi
    ++yang berbeda untuk setiap kalinya, Anda harus menampilkan dialog pemilih secara eksplisit. Dialog pemilih akan meminta
    ++pengguna memilih aplikasi yang akan digunakan untuk tindakan tertentu setiap kali (pengguna tidak bisa memilih aplikasi default untuk
    ++tindakan tersebut). Misalnya, saat aplikasi Anda melakukan "berbagi" dengan tindakan {@link
    ++android.content.Intent#ACTION_SEND}, pengguna mungkin ingin berbagi menggunakan aplikasi berbeda sesuai
    ++dengan situasi mereka saat itu, jadi Anda harus selalu menggunakan dialog pemilih, seperti yang ditampilkan dalam gambar 2.</p>
    ++
    ++
    ++
    ++
    ++<p>Untuk menampilkan pemilih, buatlah {@link android.content.Intent} menggunakan {@link
    ++android.content.Intent#createChooser createChooser()} dan teruskan ke {@link
    ++android.app.Activity#startActivity startActivity()}. Misalnya:</p>
    ++
    ++<pre>
    ++Intent sendIntent = new Intent(Intent.ACTION_SEND);
    ++...
    ++
    ++// Always use string resources for UI text.
    ++// This says something like "Share this photo with"
    ++String title = getResources().getString(R.string.chooser_title);
    ++// Create intent to show the chooser dialog
    ++Intent chooser = Intent.createChooser(sendIntent, title);
    ++
    ++// Verify the original intent will resolve to at least one activity
    ++if (sendIntent.resolveActivity(getPackageManager()) != null) {
    ++    startActivity(chooser);
    ++}
    ++</pre>
    ++
    ++<p>Ini menampilkan dialog dengan daftar aplikasi yang merespons intent yang diteruskan ke metode {@link
    ++android.content.Intent#createChooser createChooser()} dan menggunakan teks yang disediakan sebagai
    ++judul dialog.</p>
    ++
    ++
    ++
    ++
    ++
    ++
    ++
    ++
    ++
    ++<h2 id="Receiving">Menerima Intent Implisit</h2>
    ++
    ++<p>Untuk mengiklankan intent implisit yang bisa diterima aplikasi Anda, deklarasikan satu atau beberapa filter intent untuk
    ++tiap komponen aplikasi dengan elemen <a href="{@docRoot}guide/topics/manifest/intent-filter-element.html">{@code &lt;intent-filter&gt;}</a>
    ++dalam <a href="{@docRoot}guide/topics/manifest/manifest-intro.html">file manifes</a> Anda.
    ++Tiap filter intent menetapkan tipe intent yang diterimanya berdasarkan tindakan intent,
    ++data, dan kategori. Sistem akan mengirim intent implisit ke komponen aplikasi Anda hanya jika
    ++intent tersebut bisa diteruskan melalui salah satu filter intent.</p>
    ++
    ++<p class="note"><strong>Catatan:</strong> Intent eksplisit selalu dikirimkan ke targetnya,
    ++apa pun filter intent yang dideklarasikan komponen.</p>
    ++
    ++<p>Komponen aplikasi harus mendeklarasikan filter terpisah untuk setiap pekerjaan unik yang bisa dilakukannya.
    ++Misalnya, satu aktivitas dalam aplikasi galeri gambar bisa memiliki dua filter: satu filter
    ++untuk melihat gambar, dan filter lainnya untuk mengedit gambar. Bila aktivitas dimulai,
    ++aktivitas akan memeriksa {@link android.content.Intent} dan menentukan cara berperilaku berdasarkan informasi
    ++dalam {@link android.content.Intent} (misalnya menampilkan kontrol editor atau tidak).</p>
    ++
    ++<p>Tiap filter intent didefinisikan oleh elemen <a href="{@docRoot}guide/topics/manifest/intent-filter-element.html">{@code &lt;intent-filter&gt;}</a>
    ++dalam file manifes aplikasi, yang tersarang dalam komponen aplikasi terkait (seperti
    ++elemen <a href="{@docRoot}guide/topics/manifest/activity-element.html">{@code &lt;activity&gt;}</a>
    ++). Di dalam <a href="{@docRoot}guide/topics/manifest/intent-filter-element.html">{@code &lt;intent-filter&gt;}</a>,
    ++Anda bisa menetapkan tipe intent yang akan diterima dengan menggunakan salah satu atau beberapa
    ++dari tiga elemen ini:</p>
    ++
    ++<dl>
    ++<dt><a href="{@docRoot}guide/topics/manifest/action-element.html">{@code &lt;action&gt;}</a></dt>
    ++  <dd>Mendeklarasikan tindakan intent yang diterima, dalam atribut {@code name}. Nilai
    ++  haruslah nilai string literal dari tindakan, bukan konstanta kelas.</dd>
    ++<dt><a href="{@docRoot}guide/topics/manifest/data-element.html">{@code &lt;data&gt;}</a></dt>
    ++  <dd>Mendeklarasikan tipe data yang diterima, menggunakan salah satu atau beberapa atribut yang menetapkan beragam
    ++  aspek URI data (<code>scheme</code>, <code>host</code>, <code>port</code>,
    ++  <code>path</code>, dll.) dan tipe MIME.</dd>
    ++<dt><a href="{@docRoot}guide/topics/manifest/category-element.html">{@code &lt;category&gt;}</a></dt>
    ++  <dd>Mendeklarasikan kategori intent yang diterima, dalam atribut {@code name}. Nilai
    ++  haruslah nilai string literal dari tindakan, bukan konstanta kelas.
    ++
    ++  <p class="note"><strong>Catatan:</strong> Untuk menerima intent implisit, Anda
    ++  <strong>harus menyertakan</strong> kategori
    ++{@link android.content.Intent#CATEGORY_DEFAULT} dalam filter intent. Metode
    ++  {@link android.app.Activity#startActivity startActivity()}dan
    ++  {@link android.app.Activity#startActivityForResult startActivityForResult()} memperlakukan semua intent
    ++  seolah-olah mendeklarasikan kategori {@link android.content.Intent#CATEGORY_DEFAULT}.
    ++  Jika tidak mendeklarasikan kategori ini dalam filter intent Anda, tidak ada intent implisit yang ditetapkan untuk
    ++ aktivitas Anda.</p>
    ++  </dd>
    ++</dl>
    ++
    ++<p>Misalnya, ini adalah deklarasi aktivitas dengan filter intent yang diterima intent
    ++{@link android.content.Intent#ACTION_SEND} bila tipe data berupa teks:</p>
    ++
    ++<pre>
    ++&lt;activity android:name="ShareActivity">
    ++    &lt;intent-filter>
    ++        &lt;action android:name="android.intent.action.SEND"/>
    ++        &lt;category android:name="android.intent.category.DEFAULT"/>
    ++        &lt;data android:mimeType="text/plain"/>
    ++    &lt;/intent-filter>
    ++&lt;/activity>
    ++</pre>
    ++
    ++<p>Anda bisa membuat filter yang menyertakan lebih dari satu instance
    ++<a href="{@docRoot}guide/topics/manifest/action-element.html">{@code &lt;action&gt;}</a>,
    ++<a href="{@docRoot}guide/topics/manifest/data-element.html">{@code &lt;data&gt;}</a>, atau
    ++<a href="{@docRoot}guide/topics/manifest/category-element.html">{@code &lt;category&gt;}</a>.
    ++Jika Anda melakukannya, Anda hanya perlu memastikan bahwa komponen bisa menangani semua kombinasi
    ++elemen filter tersebut.</p>
    ++
    ++<p>Bila ingin menangani beragam jenis intent, namun hanya dalam kombinasi
    ++tindakan, data, dan tipe kategori tertentu, maka Anda harus membuat banyak filter intent.</p>
    ++
    ++
    ++<div class="sidebox-wrapper">
    ++<div class="sidebox">
    ++<h2>Membatasi akses ke komponen</h2>
    ++<p>Menggunakan filter intent bukanlah cara yang aman untuk mencegah aplikasi lain memulai
    ++komponen Anda. Walaupun filter intent membatasi komponen agar hanya merespons
    ++jenis intent implisit tertentu, aplikasi lain bisa saja memulai komponen aplikasi Anda
    ++dengan menggunakan intent eksplisit jika pengembangnya menentukan nama komponen Anda.
    ++Jika perlu <em>hanya aplikasi Anda sendiri</em> yang mampu memulai salah satu komponen,
    ++atur atribut <a href="{@docRoot}guide/topics/manifest/activity-element.html#exported">{@code
    ++exported}</a> ke {@code "false"} untuk komponen itu.
    ++</p>
    ++</div>
    ++</div>
    ++
    ++<p>Intent implisit diuji terhadap filter dengan membandingkan intent dengan masing-masing
    ++dari ketiga elemen. Agar dikirim ke komponen, intent harus lolos ketiga pengujian tersebut.
    ++Jika intent gagal dalam salah satu pengujian, sistem Android tidak akan mengirim intent ke
    ++komponen.  Akan tetapi, karena sebuah komponen dapat memiliki beberapa filter intent, intent yang tidak
    ++lolos melalui salah satu filter komponen mungkin akan lolos di filter lain.
    ++Informasi selengkapnya tentang cara sistem menetapkan intent disediakan dalam bagian di bawah ini
    ++tentang <a href="#Resolution">Resolusi Intent</a>.</p>
    ++
    ++<p class="caution"><strong>Perhatian:</strong> Untuk menghindari menjalankan
    ++{@link android.app.Service} aplikasi yang berbeda secara tidak sengaja, selalu gunakan intent eksplisit untuk memulai layanan Anda sendiri dan jangan
    ++deklarasikan filter intent untuk layanan Anda.</p>
    ++
    ++<p class="note"><strong>Catatan:</strong>
    ++Untuk semua aktivitas, Anda harus mendeklarasikan filter intent dalam file manifes.
    ++Akan tetapi, filter untuk penerima siaran bisa didaftarkan secara dinamis dengan memanggil
    ++{@link android.content.Context#registerReceiver(BroadcastReceiver, IntentFilter, String,
    ++Handler) registerReceiver()}. Anda nanti bisa mencabut pendaftaran penerima dengan {@link
    ++android.content.Context#unregisterReceiver unregisterReceiver()}. Dengan begitu aplikasi Anda
    ++bisa mendengarkan siaran tertentu hanya selama periode waktu yang telah ditetapkan saat aplikasi Anda
    ++berjalan.</p>
    ++
    ++
    ++
    ++
    ++
    ++
    ++
    ++<h3 id="ExampleFilters">Contoh filter</h3>
    ++
    ++<p>Untuk lebih memahami beberapa perilaku filter intent, lihatlah cuplikan berikut
    ++dari file manifes aplikasi berbagi di jaringan sosial.</p>
    ++
    ++<pre>
    ++&lt;activity android:name="MainActivity">
    ++    &lt;!-- This activity is the main entry, should appear in app launcher -->
    ++    &lt;intent-filter>
    ++        &lt;action android:name="android.intent.action.MAIN" />
    ++        &lt;category android:name="android.intent.category.LAUNCHER" />
    ++    &lt;/intent-filter>
    ++&lt;/activity>
    ++
    ++&lt;activity android:name="ShareActivity">
    ++    &lt;!-- This activity handles "SEND" actions with text data -->
    ++    &lt;intent-filter&gt;
    ++        &lt;action android:name="android.intent.action.SEND"/>
    ++        &lt;category android:name="android.intent.category.DEFAULT"/>
    ++        &lt;data android:mimeType="text/plain"/>
    ++    &lt;/intent-filter&gt;
    ++    &lt;!-- This activity also handles "SEND" and "SEND_MULTIPLE" with media data -->
    ++    &lt;intent-filter&gt;
    ++        &lt;action android:name="android.intent.action.SEND"/>
    ++        &lt;action android:name="android.intent.action.SEND_MULTIPLE"/>
    ++        &lt;category android:name="android.intent.category.DEFAULT"/>
    ++        &lt;data android:mimeType="application/vnd.google.panorama360+jpg"/>
    ++        &lt;data android:mimeType="image/*"/>
    ++        &lt;data android:mimeType="video/*"/>
    ++    &lt;/intent-filter&gt;
    ++&lt;/activity&gt;
    ++</pre>
    ++
    ++<p>Aktivitas pertama, {@code MainActivity}, merupakan titik masuk utama aplikasi&mdash;aplikasi yang
    ++terbuka saat pengguna meluncurkan aplikasi dengan ikon launcher:</p>
    ++<ul>
    ++  <li>Tindakan {@link android.content.Intent#ACTION_MAIN}
    ++  menunjukkan ini adalah titik masuk utama dan tidak mengharapkan data intent apa pun.</li>
    ++  <li>Kategori {@link android.content.Intent#CATEGORY_LAUNCHER} menunjukjkan bahwa ikon
    ++  aktivitas ini harus ditempatkan dalam launcher aplikasi sistem. Jika elemen <a href="{@docRoot}guide/topics/manifest/activity-element.html">{@code &lt;activity&gt;}</a>
    ++  tidak menetapkan ikon dengan{@code icon}, maka sistem akan menggunakan ikon dari elemen
    ++<a href="{@docRoot}guide/topics/manifest/application-element.html">{@code &lt;application&gt;}</a>.</li>
    ++</ul>
    ++<p>Keduanya harus dipasangkan bersama agar aktivitas muncul dalam launcher aplikasi.</p>
    ++
    ++<p>Aktivitas kedua, {@code ShareActivity}, dimaksudkan untuk memudahkan berbagi teks dan konten
    ++media. Walaupun pengguna mungkin memasuki aktivitas ini dengan mengarah ke aktivitas dari {@code MainActivity},
    ++pengguna juga bisa memasukkan {@code ShareActivity} secara langsung dari aplikasi lain yang mengeluarkan intent
    ++implisit yang cocok dengan salah satu dari kedua filter intent.</p>
    ++
    ++<p class="note"><strong>Catatan:</strong> Tipe MIME,
    ++<a href="https://developers.google.com/panorama/android/">{@code
    ++application/vnd.google.panorama360+jpg}</a>, merupakan tipe data khusus yang menetapkan
    ++foto panorama, yang bisa Anda tangani dengan API <a href="{@docRoot}reference/com/google/android/gms/panorama/package-summary.html">panorama
    ++Google</a>.</p>
    ++
    ++
    ++
    ++
    ++
    ++
    ++
    ++
    ++
    ++
    ++
    ++
    ++
    ++<h2 id="PendingIntent">Menggunakan Intent Tertunda</h2>
    ++
    ++<p>Objek {@link android.app.PendingIntent} merupakan pembungkus objek {@link
    ++android.content.Intent}. Tujuan utama {@link android.app.PendingIntent}
    ++adalah memberikan izin pada aplikasi asing
    ++untuk menggunakan {@link android.content.Intent} yang termuat seolah-olah dieksekusi dari
    ++proses aplikasi Anda sendiri.</p>
    ++
    ++<p>Kasus penggunaan utama untuk intent tertunda antara lain:</p>
    ++<ul>
    ++  <li>Mendeklarasikan intent untuk dieksekusi saat pengguna melakukan tindakan dengan <a href="{@docRoot}guide/topics/ui/notifiers/notifications.html">Pemberitahuan</a>
    ++  ({@link android.app.NotificationManager}
    ++  sistem Android akan mengeksekusi {@link android.content.Intent}) Anda.
    ++  <li>Mendeklarasikan intent untuk dieksekusi saat pengguna melakukan tindakan dengan
    ++<a href="{@docRoot}guide/topics/appwidgets/index.html">App Widget</a>
    ++  (aplikasi layar Home mengeksekusi {@link android.content.Intent}).
    ++  <li>Mendeklarasikan intent untuk dieksekusi di waktu yang telah ditetapkan di masa mendatang
    ++({@link android.app.AlarmManager}  sistem Android akan mengeksekusi {@link android.content.Intent}).
    ++</ul>
    ++
    ++<p>Karena setiap objek {@link android.content.Intent} didesain untuk ditangani oleh tipe
    ++tertentu dari komponen aplikasi (baik {@link android.app.Activity}, {@link android.app.Service}, maupun
    ++ {@link android.content.BroadcastReceiver}), jadi {@link android.app.PendingIntent} harus
    ++dibuat dengan pertimbangan yang sama. Saat menggunakan intent tertunda, aplikasi Anda tidak akan
    ++mengeksekusi intent dengan panggilan seperti {@link android.content.Context#startActivity
    ++startActivity()}. Anda harus mendeklarasikan tipe komponen yang dimaksud saat membuat
    ++{@link android.app.PendingIntent} dengan memanggil metode kreator masing-masing:</p>
    ++
    ++<ul>
    ++  <li>{@link android.app.PendingIntent#getActivity PendingIntent.getActivity()} untuk
    ++  {@link android.content.Intent} yang memulai {@link android.app.Activity}.</li>
    ++  <li>{@link android.app.PendingIntent#getService PendingIntent.getService()} untuk
    ++  {@link android.content.Intent} yang memulai {@link android.app.Service}.</li>
    ++  <li>{@link android.app.PendingIntent#getBroadcast PendingIntent.getBroadcast()} untuk
    ++  {@link android.content.Intent} yang memulai {@link android.content.BroadcastReceiver}.</li>
    ++</ul>
    ++
    ++<p>Kecuali jika aplikasi Anda <em>menerima</em> intent tertunda dari aplikasi lain,
    ++metode di atas untuk membuat {@link android.app.PendingIntent} menjadi satu-satunya metode
    ++{@link android.app.PendingIntent} yang mungkin Anda butuhkan.</p>
    ++
    ++<p>Tiap metode mengambil {@link android.content.Context} aplikasi saat itu,
    ++{@link android.content.Intent} yang ingin Anda bungkus, dan satu atau beberapa flag yang menetapkan
    ++cara penggunaan intent (misalnya apakah intent bisa digunakan lebih dari sekali).</p>
    ++
    ++<p>Informasi selengkapnya tentang intent tertunda disediakan pada dokumentasi untuk setiap
    ++kasus penggunaan yang bersangkutan, seperti dalam panduan API <a href="{@docRoot}guide/topics/ui/notifiers/notifications.html">Notifications</a>
    ++dan <a href="{@docRoot}guide/topics/appwidgets/index.html">App Widgets</a>.</p>
    ++
    ++
    ++
    ++
    ++
    ++
    ++
    ++<h2 id="Resolution">Resolusi Intent</h2>
    ++
    ++
    ++<p>Saat sistem menerima intent implisit yang memulai suatu aktivitas, sistem tersebut akan mencari
    ++aktivitas terbaik untuk intent dengan membandingkan intent dengan filter intent berdasarkan tiga aspek:</p>
    ++
    ++<ul>
    ++  <li>Tindakan intent
    ++  <li>Data intent (baik URI maupun tipe data)
    ++  <li>Kategori intent
    ++</ul>
    ++
    ++<p>Bagian berikut menjelaskan cara pencocokan intent dengan komponen yang sesuai
    ++sehubungan dengan cara pendeklarasian filter intent dalam file manifes aplikasi.</p>
    ++
    ++
    ++<h3 id="ActionTest">Pengujian tindakan</h3>
    ++
    ++<p>Untuk menetapkan tindakan intent yang diterima, filter intent bisa mendeklarasikan nol atau beberapa elemen
    ++<a href="{@docRoot}guide/topics/manifest/action-element.html">{@code
    ++&lt;action&gt;}</a>.  Misalnya:</p>
    ++
    ++<pre>
    ++&lt;intent-filter&gt;
    ++    &lt;action android:name="android.intent.action.EDIT" /&gt;
    ++    &lt;action android:name="android.intent.action.VIEW" /&gt;
    ++    ...
    ++&lt;/intent-filter&gt;
    ++</pre>
    ++
    ++<p>Untuk melewati filter ini, tindakan yang ditetapkan dalam {@link android.content.Intent}
    ++harus sesuai dengan salah satu tindakan yang tercantum dalam filter.</p>
    ++
    ++<p>Jika filter tidak mencantumkan tindakan apa pun, maka tidak ada intent
    ++yang dicocokkan, jadi semua intent gagal dalam pengujian. Akan tetapi, jika sebuah {@link android.content.Intent}
    ++tidak menetapkan suatu tindakan, maka akan lolos pengujian (asalkan filter
    ++berisi setidaknya satu tindakan).</p>
    ++
    ++
    ++
    ++<h3 id="CategoryTest">Pengujian kategori</h3>
    ++
    ++<p>Untuk menetapkan kategori intent yang diterima, filter intent bisa mendeklarasikan nol atau beberapa elemen
    ++<a href="{@docRoot}guide/topics/manifest/category-element.html">{@code
    ++&lt;category&gt;}</a>.  Misalnya:</p>
    ++
    ++<pre>
    ++&lt;intent-filter&gt;
    ++    &lt;category android:name="android.intent.category.DEFAULT" /&gt;
    ++    &lt;category android:name="android.intent.category.BROWSABLE" /&gt;
    ++    ...
    ++&lt;/intent-filter&gt;
    ++</pre>
    ++
    ++<p>Agar intent bisa lolos pengujian kategori, setiap kategori dalam {@link android.content.Intent}
    ++harus sesuai dengan kategori dalam filter. Kebalikannya tidak diperlukan&mdash;filter intent bisa
    ++mendeklarasikan kategori lebih banyak daripada yang ditetapkan dalam {@link android.content.Intent} dan
    ++{@link android.content.Intent} tetap akan lolos. Oleh karena itu, intent tanpa kategori harus
    ++selalu lolos pengujian ini, kategori apa pun yang dideklarasikan dalam filter.</p>
    ++
    ++<p class="note"><strong>Catatan:</strong>
    ++Android secara otomatis menerapkan kategori {@link android.content.Intent#CATEGORY_DEFAULT}
    ++untuk semua intent implisit yang diteruskan ke {@link
    ++android.content.Context#startActivity startActivity()} dan {@link
    ++android.app.Activity#startActivityForResult startActivityForResult()}.
    ++Jadi jika ingin aktivitas Anda menerima intent implisit, aktivitas tersebut harus
    ++menyertakan kategori untuk{@code "android.intent.category.DEFAULT"} dalam filter intent (seperti
    ++yang ditampilkan dalam contoh{@code &lt;intent-filter&gt;} sebelumnya.</p>
    ++
    ++
    ++
    ++<h3 id="DataTest">Pengujian data</h3>
    ++
    ++<p>Untuk menetapkan data intent yang diterima, filter intent bisa mendeklarasikan nol atau beberapa elemen
    ++<a href="{@docRoot}guide/topics/manifest/data-element.html">{@code
    ++&lt;data&gt;}</a>.  Misalnya:</p>
    ++
    ++<pre>
    ++&lt;intent-filter&gt;
    ++    &lt;data android:mimeType="video/mpeg" android:scheme="http" ... /&gt;
    ++    &lt;data android:mimeType="audio/mpeg" android:scheme="http" ... /&gt;
    ++    ...
    ++&lt;/intent-filter&gt;
    ++</pre>
    ++
    ++<p>Tiap elemen <code><a href="{@docRoot}guide/topics/manifest/data-element.html">&lt;data&gt;</a></code>
    ++bisa menetapkan struktur URI dan tipe data (tipe media MIME).  Ada atribut
    ++terpisah &mdash; {@code scheme}, {@code host}, {@code port},
    ++dan {@code path} &mdash; untuk setiap bagian URI:
    ++</p>
    ++
    ++<p style="margin-left: 2em">{@code &lt;scheme&gt;://&lt;host&gt;:&lt;port&gt;/&lt;path&gt;}</p>
    ++
    ++<p>
    ++Misalnya:
    ++</p>
    ++
    ++<p style="margin-left: 2em">{@code content://com.example.project:200/folder/subfolder/etc}</p>
    ++
    ++<p>Dalam URI ini, skemanya adalah {@code content}, host-nya adalah {@code com.example.project},
    ++port-nya adalah {@code 200}, dan path-nya adalah {@code folder/subfolder/etc}.
    ++</p>
    ++
    ++<p>Tiap atribut bersifat opsional dalam elemen <a href="{@docRoot}guide/topics/manifest/data-element.html">{@code &lt;data&gt;}</a>,
    ++namun ada dependensi linear:</p>
    ++<ul>
    ++  <li>Jika skema tidak ditetapkan, host akan diabaikan.</li>
    ++  <li>Jika host tidak ditetapkan, port akan diabaikan.</li>
    ++  <li>Jika skema dan host tidak ditetapkan, path akan diabaikan.</li>
    ++</ul>
    ++
    ++<p>Bila URI dalam intent dibandingkan dengan spesifikasi URI dalam filter,
    ++pembandingannya hanya dengan bagian URI yang disertakan dalam filter. Misalnya:</p>
    ++<ul>
    ++  <li>Jika sebuah filter menetapkan hanya satu skema, semua URI dengan skema tersebut akan cocok
    ++dengan filter.</li>
    ++  <li>Jika sebuah filter menetapkan satu skema dan satu otoritas namun tanpa path, semua URI
    ++dengan skema dan otoritas yang sama akan lolos dari filter, apa pun path-nya.</li>
    ++  <li>Jika sebuah filter menetapkan satu skema, otoritas dan path, hanya URI dengan skema,
    ++otoritas, dan path sama yang bisa lolos dari filter.</li>
    ++</ul>
    ++
    ++<p class="note"><strong>Catatan:</strong> Spesifikasi path bisa berisi
    ++wildcard bintang (*) untuk hanya mencocokkan nama path secara parsial.</p>
    ++
    ++<p>Pengujian data membandingkan URI maupun tipe MIME dalam intent dengan URI
    ++dan tipe MIME yang ditetapkan dalam filter.  Aturannya adalah sebagai berikut:
    ++</p>
    ++
    ++<ol type="a">
    ++<li>Intent yang tidak berisi URI maupun tipe MIME hanya akan lolos
    ++pengujian jika filter tersebut tidak menetapkan URI atau tipe MIME apa pun.</li>
    ++
    ++<li>Intent yang berisi URI namun tidak berisi tipe MIME (baik secara eksplisit maupun tidak langsung dari
    ++URI) hanya akan lolos pengujian jika URI-nya cocok dengan format URI filter
    ++dan filternya juga tidak menetapkan tipe MIME.</li>
    ++
    ++<li>Intent yang berisi tipe MIME namun tidak berisi URI hanya akan lolos pengujian
    ++jika filter mencantumkan tipe MIME yang sama dan tidak menetapkan format URI.</li>
    ++
    ++<li>Intent yang berisi URI maupun tipe MIME (baik secara eksplisit maupun tidak langsung dari
    ++URI) hanya akan lolos pengujian bagian tipe MIME jika
    ++tipe tersebut cocok dengan tipe yang dicantumkan dalam filter.  Ini akan lolos pengujian bagian URI
    ++jika URI-nya cocok dengan URI dalam filter atau memiliki {@code content:}
    ++atau URI {@code file:} dan filter tidak menetapkan URI. Dengan kata lain,
    ++komponen dianggap mendukung data {@code content:} dan {@code file:} jika
    ++filternya <em>hanya</em> mencantumkan tipe MIME.</p></li>
    ++</ol>
    ++
    ++<p>
    ++Aturan terakhir ini, aturan (d), mencerminkan harapan
    ++bahwa komponen mampu mendapatkan data lokal dari file atau penyedia konten.
    ++Oleh karena itu, filter mereka mencatumkan tipe data saja dan tidak secara eksplisit
    ++harus menamai skema {@code content:} dan {@code file:}.
    ++Ini adalah kasus umum.  Elemen <a href="{@docRoot}guide/topics/manifest/data-element.html">{@code &lt;data&gt;}</a>
    ++seperti berikut ini, misalnya, memberi tahu Android bahwa komponen bisa mengambil data gambar dari penyedia
    ++konten dan menampilkannya:
    ++</p>
    ++
    ++<pre>
    ++&lt;intent-filter&gt;
    ++    &lt;data android:mimeType="image/*" /&gt;
    ++    ...
    ++&lt;/intent-filter&gt;</pre>
    ++
    ++<p>
    ++Karena sebagian besar data yang tersedia dikeluarkan oleh penyedia konten, filter yang
    ++menetapkan tipe data namun bukan URI mungkin adalah yang paling umum.
    ++</p>
    ++
    ++<p>
    ++Konfigurasi umum yang lain adalah filter dengan skema dan tipe data.  Misalnya
    ++, elemen <a href="{@docRoot}guide/topics/manifest/data-element.html">{@code &lt;data&gt;}</a>
    ++ seperti berikut ini akan memberi tahu Android bahwa
    ++komponen bisa mengambil data video dari jaringan untuk melakukan tindakan:
    ++</p>
    ++
    ++<pre>
    ++&lt;intent-filter&gt;
    ++    &lt;data android:scheme="http" android:type="video/*" /&gt;
    ++    ...
    ++&lt;/intent-filter&gt;</pre>
    ++
    ++
    ++
    ++<h3 id="imatch">Pencocokan intent</h3>
    ++
    ++<p>Intent dicocokkan dengan filter intent selain untuk menemukan komponen
    ++target yang akan diaktifkan, juga untuk menemukan sesuatu tentang rangkaian
    ++komponen pada perangkat.  Misalnya, aplikasi Home akan menempatkan launcher aplikasi
    ++dengan mencari semua aktivitas dengan filter intent yang menetapkan tindakan
    ++{@link android.content.Intent#ACTION_MAIN} dan
    ++kategori {@link android.content.Intent#CATEGORY_LAUNCHER}.</p>
    ++
    ++<p>Aplikasi Anda bisa menggunakan pencocokan intent dengan cara serupa.
    ++{@link android.content.pm.PackageManager} memiliki seperangkat metode {@code query...()}
    ++yang mengembalikan semua komponen yang bisa menerima intent tertentu, dan
    ++serangkaian metode{@code resolve...()} serupa yang menentukan komponen
    ++terbaik untuk merespons intent.  Misalnya,
    ++{@link android.content.pm.PackageManager#queryIntentActivities
    ++queryIntentActivities()} akan mengembalikan daftar semua aktivitas yang bisa melakukan
    ++intent yang diteruskan sebagai argumen, dan {@link
    ++android.content.pm.PackageManager#queryIntentServices
    ++queryIntentServices()} akan mengembalikan daftar layanan serupa.
    ++Tidak ada metode yang akan mengaktifkan komponen; mereka hanya mencantumkan komponen yang
    ++bisa merespons.  Ada metode serupa,
    ++{@link android.content.pm.PackageManager#queryBroadcastReceivers
    ++queryBroadcastReceivers()}, untuk penerima siaran.
    ++</p>
    ++
    ++
    ++
    ++
    +diff --git a/docs/html-intl/intl/id/guide/components/loaders.jd b/docs/html-intl/intl/id/guide/components/loaders.jd
    +new file mode 100644
    +index 0000000..88093cc
    +--- /dev/null
    ++++ b/docs/html-intl/intl/id/guide/components/loaders.jd
    +@@ -0,0 +1,494 @@
    ++page.title=Aktivitas
    ++parent.title=Loader
    ++parent.link=activities.html
    ++@jd:body
    ++<div id="qv-wrapper">
    ++<div id="qv">
    ++    <h2>Dalam dokumen ini</h2>
    ++    <ol>
    ++    <li><a href="#summary">Rangkuman Loader API</a></li>
    ++    <li><a href="#app">Menggunakan Loader dalam Aplikasi</a>
    ++      <ol>
    ++        <li><a href="#requirements"></a></li>
    ++        <li><a href="#starting">Memulai Loader</a></li>
    ++        <li><a href="#restarting">Me-restart Loader</a></li>
    ++        <li><a href="#callback">Menggunakan Callback LoaderManager</a></li>
    ++      </ol>
    ++    </li>
    ++    <li><a href="#example">Contoh</a>
    ++       <ol>
    ++         <li><a href="#more_examples">Contoh Selengkapnya</a></li>
    ++        </ol>
    ++    </li>
    ++  </ol>
    ++
    ++  <h2>Kelas-kelas utama</h2>
    ++    <ol>
    ++      <li>{@link android.app.LoaderManager}</li>
    ++      <li>{@link android.content.Loader}</li>
    ++
    ++    </ol>
    ++
    ++    <h2>Contoh-contoh terkait</h2>
    ++   <ol>
    ++     <li> <a href="{@docRoot}resources/samples/ApiDemos/src/com/example/android/apis/app/LoaderCursor.html">
    ++LoaderCursor</a></li>
    ++     <li> <a href="{@docRoot}resources/samples/ApiDemos/src/com/example/android/apis/app/LoaderThrottle.html">
    ++LoaderThrottle</a></li>
    ++   </ol>
    ++  </div>
    ++</div>
    ++
    ++<p>Diperkenalkan di Android 3.0, loader memudahkan pemuatan data asinkron
    ++dalam aktivitas atau fragmen. Loader memiliki karakteristik ini:</p>
    ++  <ul>
    ++    <li>Loader tersedia untuk setiap {@link android.app.Activity} dan {@link
    ++android.app.Fragment}.</li>
    ++    <li>Loader menyediakan pemuatan data asinkron.</li>
    ++    <li>Loader memantau sumber data mereka dan memberikan hasil baru bila
    ++konten berubah.</li>
    ++    <li>Loader secara otomatis menghubungkan kembali ke kursor loader lalu saat
    ++dibuat kembali setelah perubahan konfigurasi. Karena itu, loader tidak perlu melakukan query ulang
    ++datanya.</li>
    ++  </ul>
    ++
    ++<h2 id="summary">Rangkuman Loader API</h2>
    ++
    ++<p>Ada beberapa kelas dan antarmuka yang mungkin dilibatkan dalam menggunakan
    ++loader pada aplikasi. Semuanya dirangkum dalam tabel ini:</p>
    ++
    ++<table>
    ++  <tr>
    ++    <th>Kelas/Antarmuka</th>
    ++    <th>Keterangan</th>
    ++  </tr>
    ++  <tr>
    ++    <td>{@link android.app.LoaderManager}</td>
    ++    <td>Kelas abstrak yang dikaitkan dengan {@link android.app.Activity} atau
    ++{@link android.app.Fragment} untuk mengelola satu atau beberapa instance {@link
    ++android.content.Loader}. Ini membantu aplikasi mengelola
    ++operasi berjalan lebih lama bersamaan dengan daur hidup {@link android.app.Activity}
    ++atau {@link android.app.Fragment}; penggunaan paling umumnya adalah dengan
    ++{@link android.content.CursorLoader}, akan tetapi aplikasi bebas menulis loader-nya
    ++ sendiri untuk memuat tipe data lainnya.
    ++    <br />
    ++    <br />
    ++    Hanya ada satu {@link android.app.LoaderManager} per aktivitas atau fragmen. Namun {@link android.app.LoaderManager} bisa memiliki
    ++beberapa loader.</td>
    ++  </tr>
    ++  <tr>
    ++    <td>{@link android.app.LoaderManager.LoaderCallbacks}</td>
    ++    <td>Antarmuka callback untuk klien berinteraksi dengan {@link
    ++android.app.LoaderManager}. Misalnya, Anda menggunakan metode callback {@link
    ++android.app.LoaderManager.LoaderCallbacks#onCreateLoader onCreateLoader()}
    ++untuk membuat loader baru.</td>
    ++  </tr>
    ++  <tr>
    ++    <td>{@link android.content.Loader}</td>
    ++    <td>Kelas abstrak yang melakukan pemuatan data asinkron. Ini
    ++adalah kelas dasar untuk loader. Biasanya Anda akan menggunakan {@link
    ++android.content.CursorLoader}, namun Anda bisa menerapkan subkelas sendiri. Selagi
    ++loader aktif, loader harus memantau sumber datanya dan memberikan hasil
    ++baru bila konten berubah. </td>
    ++  </tr>
    ++  <tr>
    ++    <td>{@link android.content.AsyncTaskLoader}</td>
    ++    <td>Loader abstrak yang menyediakan {@link android.os.AsyncTask} untuk melakukan pekerjaan.</td>
    ++  </tr>
    ++  <tr>
    ++    <td>{@link android.content.CursorLoader}</td>
    ++    <td>Subkelas {@link android.content.AsyncTaskLoader} yang meng-query
    ++{@link android.content.ContentResolver} dan mengembalikan {@link
    ++android.database.Cursor}. Kelas ini mengimplementasikan protokol {@link
    ++android.content.Loader} dengan cara standar untuk query kursor,
    ++yang dibuat berdasarkan {@link android.content.AsyncTaskLoader} untuk melakukan query kursor
    ++pada thread latar belakang agar tidak memblokir UI aplikasi. Menggunakan loader
    ++ini merupakan cara terbaik untuk memuat data secara asinkron dari {@link
    ++android.content.ContentProvider}, sebagai ganti melakukan query terkelola melalui
    ++fragmen atau API aktivitas.</td>
    ++  </tr>
    ++</table>
    ++
    ++<p>Kelas dan antarmuka dalam tabel di atas merupakan komponen
    ++esensial yang akan Anda gunakan untuk mengimplementasikan loader dalam aplikasi Anda. Anda tidak memerlukan semuanya
    ++untuk setiap loader yang dibuat, namun Anda akan selalu memerlukan acuan ke {@link
    ++android.app.LoaderManager} untuk memulai loader dan implementasi
    ++kelas {@link android.content.Loader} seperti {@link
    ++android.content.CursorLoader}. Bagian berikut ini menunjukkan kepada Anda cara menggunakan
    ++kelas dan antarmuka ini dalam aplikasi.</p>
    ++
    ++<h2 id ="app">Menggunakan Loader dalam Aplikasi</h2>
    ++<p>Bagian ini menjelaskan cara menggunakan loader dalam aplikasi Android. Aplikasi
    ++yang menggunakan loader biasanya berisi yang berikut ini:</p>
    ++<ul>
    ++  <li>{@link android.app.Activity} atau {@link android.app.Fragment}.</li>
    ++  <li>Instance {@link android.app.LoaderManager}.</li>
    ++  <li>{@link android.content.CursorLoader} akan memuat data yang didukung oleh {@link
    ++android.content.ContentProvider}. Atau, Anda dapat mengimplementasikan subkelas sendiri
    ++ dari {@link android.content.Loader} atau {@link android.content.AsyncTaskLoader} untuk
    ++memuat data dari beberapa sumber lain.</li>
    ++  <li>Implementasi untuk {@link android.app.LoaderManager.LoaderCallbacks}.
    ++Di sinilah Anda membuat loader baru dan mengelola acuan bagi loader
    ++yang ada.</li>
    ++<li>Cara menampilkan data loader, seperti {@link
    ++android.widget.SimpleCursorAdapter}.</li>
    ++  <li>Sumber data, seperti {@link android.content.ContentProvider}, saat menggunakan
    ++{@link android.content.CursorLoader}.</li>
    ++</ul>
    ++<h3 id="starting">Memulai Loader</h3>
    ++
    ++<p>{@link android.app.LoaderManager} mengelola satu atau beberapa instance {@link
    ++android.content.Loader} dalam {@link android.app.Activity} atau
    ++{@link android.app.Fragment}. Hanya ada satu {@link
    ++android.app.LoaderManager} per aktivitas atau fragmen.</p>
    ++
    ++<p>Anda biasanya
    ++memulai {@link android.content.Loader} dalam metode {@link
    ++android.app.Activity#onCreate onCreate()} aktivitas, atau dalam metode
    ++{@link android.app.Fragment#onActivityCreated onActivityCreated()} fragmen. Anda
    ++melakukannya dengan cara berikut ini:</p>
    ++
    ++<pre>// Prepare the loader.  Either re-connect with an existing one,
    ++// or start a new one.
    ++getLoaderManager().initLoader(0, null, this);</pre>
    ++
    ++<p>Metode {@link android.app.LoaderManager#initLoader initLoader()} mengambil
    ++parameter berikut:</p>
    ++<ul>
    ++  <li>ID unik yang mengidentifikasi loader. Dalam contoh ini, ID-nya adalah 0.</li>
    ++<li>Argumen opsional untuk dipasok ke loader
    ++pada saat pembuatan (dalam contoh ini <code>null</code>).</li>
    ++
    ++<li>Implementasi {@link android.app.LoaderManager.LoaderCallbacks}, yang
    ++akan dipanggil {@link android.app.LoaderManager} untuk melaporkan kejadian loader. Dalam contoh
    ++ini, kelas lokal mengimplementasikan antarmuka {@link
    ++android.app.LoaderManager.LoaderCallbacks}, sehingga meneruskan acuan
    ++ke dirinya sendiri, {@code this}.</li>
    ++</ul>
    ++<p>Panggilan {@link android.app.LoaderManager#initLoader initLoader()} memastikan bahwa loader
    ++telah dimulai dan aktif. Ia memiliki dua kemungkinan hasil:</p>
    ++<ul>
    ++  <li>Jika loader yang disebutkan oleh ID sudah ada, loader yang dibuat terakhir akan digunakan
    ++kembali.</li>
    ++  <li>Jika loader yang disebutkan oleh ID <em>tidak</em> ada,
    ++{@link android.app.LoaderManager#initLoader initLoader()} akan memicu metode
    ++{@link android.app.LoaderManager.LoaderCallbacks} {@link android.app.LoaderManager.LoaderCallbacks#onCreateLoader onCreateLoader()}.
    ++Di sinilah Anda mengimplementasikan kode untuk membuat instance dan mengembalikan loader baru.
    ++Untuk diskusi selengkapnya, lihat bagian <a href="#onCreateLoader">onCreateLoader</a>.</li>
    ++</ul>
    ++<p>Dalam hal ini, implementasi {@link android.app.LoaderManager.LoaderCallbacks}
    ++yang ditentukan akan dikaitkan dengan loader, dan akan dipanggil bila
    ++status loader berubah.  Jika saat panggilan ini status pemanggil sudah
    ++dimulai, dan loader yang diminta sudah ada dan telah menghasilkan
    ++datanya, maka sistem segera memanggil {@link
    ++android.app.LoaderManager.LoaderCallbacks#onLoadFinished onLoadFinished()}
    ++(selama {@link android.app.LoaderManager#initLoader initLoader()}),
    ++sehingga Anda harus siap bila hal ini terjadi. Lihat <a href="#onLoadFinished">
    ++onLoadFinished</a> untuk diskusi selengkapnya mengenai callback ini</p>
    ++
    ++<p>Perhatikan bahwa metode {@link android.app.LoaderManager#initLoader initLoader()}
    ++mengembalikan {@link android.content.Loader} yang dibuat, namun Anda tidak
    ++perlu menangkap acuan ke sana. {@link android.app.LoaderManager} mengelola
    ++masa hidup loader secara otomatis. {@link android.app.LoaderManager}
    ++memulai dan menghentikan pemuatan jika perlu, dan menjaga status loader
    ++dan konten terkaitnya. Seperti yang tersirat di sini, Anda akan jarang berinteraksi dengan loader
    ++secara langsung (meskipun misalnya menggunakan metode loader untuk menyempurnakan perilaku
    ++loader, lihat contoh <a href="{@docRoot}resources/samples/ApiDemos/src/com/example/android/apis/app/LoaderThrottle.html"> LoaderThrottle</a>).
    ++Anda paling sering akan menggunakan metode {@link
    ++android.app.LoaderManager.LoaderCallbacks} untuk mengintervensi proses
    ++pemuatan saat terjadi kejadian tertentu. Untuk diskusi selengkapnya mengenai topik ini, lihat <a href="#callback">Menggunakan Callback LoaderManager</a>.</p>
    ++
    ++<h3 id="restarting">Me-restart Loader</h3>
    ++
    ++<p>Bila Anda menggunakan {@link android.app.LoaderManager#initLoader initLoader()}, seperti
    ++ditampilkan di atas, loader yang ada akan digunakan dengan ID yang ditetapkan jika ada.
    ++Jika tidak ada, ID akan dibuat. Namun kadang-kadang Anda perlu membuang data lama
    ++dan mulai dari awal.</p>
    ++
    ++<p>Untuk membuang data lama, gunakan {@link
    ++android.app.LoaderManager#restartLoader restartLoader()}. Misalnya, implementasi
    ++{@link android.widget.SearchView.OnQueryTextListener} ini akan me-restart
    ++bila query pengguna berubah. Loader perlu di-restart
    ++agar dapat menggunakan filter pencarian yang telah direvisi untuk melakukan query baru:</p>
    ++
    ++<pre>
    ++public boolean onQueryTextChanged(String newText) {
    ++    // Called when the action bar search text has changed.  Update
    ++    // the search filter, and restart the loader to do a new query
    ++    // with this filter.
    ++    mCurFilter = !TextUtils.isEmpty(newText) ? newText : null;
    ++    getLoaderManager().restartLoader(0, null, this);
    ++    return true;
    ++}</pre>
    ++
    ++<h3 id="callback">Menggunakan Callback LoaderManager</h3>
    ++
    ++<p>{@link android.app.LoaderManager.LoaderCallbacks} adalah antarmuka callback
    ++yang memungkinkan klien berinteraksi dengan {@link android.app.LoaderManager}. </p>
    ++<p>Loader, khususnya {@link android.content.CursorLoader}, diharapkan
    ++mempertahankan datanya setelah dihentikan. Ini memungkinkan aplikasi mempertahankan
    ++datanya di aktivitas atau metode {@link android.app.Activity#onStop
    ++onStop()} fragmen dan {@link android.app.Activity#onStart onStart()}, sehingga
    ++bila pengguna kembali ke aplikasi, mereka tidak harus menunggu data
    ++dimuat kembali. Anda menggunakan metode {@link android.app.LoaderManager.LoaderCallbacks}
    ++untuk mengetahui waktu membuat loader baru, dan memberi tahu aplikasi kapan
    ++berhenti menggunakan data loader.</p>
    ++
    ++<p>{@link android.app.LoaderManager.LoaderCallbacks} berisi metode
    ++ini:</p>
    ++<ul>
    ++  <li>{@link android.app.LoaderManager.LoaderCallbacks#onCreateLoader onCreateLoader()} —
    ++Membuat instance dan mengembalikan {@link android.content.Loader} baru untuk ID yang diberikan.
    ++</li></ul>
    ++<ul>
    ++  <li> {@link android.app.LoaderManager.LoaderCallbacks#onLoadFinished onLoadFinished()}
    ++— Dipanggil bila loader yang dibuat sebelumnya selesai dimuat.
    ++</li></ul>
    ++<ul>
    ++  <li>{@link android.app.LoaderManager.LoaderCallbacks#onLoaderReset onLoaderReset()}
    ++    — Dipanggil bila loader yang dibuat sebelumnya sedang di-reset, sehingga datanya
    ++tidak tersedia.
    ++</li>
    ++</ul>
    ++<p>Metode ini dijelaskan lebih detail dalam bagian berikutnya.</p>
    ++
    ++<h4 id ="onCreateLoader">onCreateLoader</h4>
    ++
    ++<p>Saat Anda mencoba mengakses loader (misalnya, melalui {@link
    ++android.app.LoaderManager#initLoader initLoader()}), ia akan memeriksa untuk mengetahui adanya
    ++loader yang ditetapkan oleh ID. Jika tidak ada, ia akan memicu metode {@link
    ++android.app.LoaderManager.LoaderCallbacks} {@link
    ++android.app.LoaderManager.LoaderCallbacks#onCreateLoader onCreateLoader()}. Di
    ++sinilah Anda membuat loader baru. Biasanya ini adalah {@link
    ++android.content.CursorLoader}, namun Anda bisa mengimplementasikan sendiri subkelas {@link
    ++android.content.Loader}. </p>
    ++
    ++<p>Dalam contoh ini, metode callback {@link
    ++android.app.LoaderManager.LoaderCallbacks#onCreateLoader onCreateLoader()}
    ++ akan membuat {@link android.content.CursorLoader}. Anda harus membuat
    ++{@link android.content.CursorLoader} menggunakan metode konstruktornya, yang
    ++memerlukan set informasi lengkap untuk melakukan query ke {@link
    ++android.content.ContentProvider}. Secara khusus, ia memerlukan:</p>
    ++<ul>
    ++  <li><em>uri</em> — URI untuk konten yang akan diambil. </li>
    ++  <li><em>projection</em> — Daftar berisi kolom yang akan dikembalikan. Meneruskan
    ++<code>null</code> akan mengembalikan semua kolom, jadi tidak efisien. </li>
    ++  <li><em>selection</em> — Filter yang mendeklarasikan baris yang akan dikembalikan,
    ++diformat sebagai klausa SQL WHERE (tidak termasuk WHERE itu sendiri). Meneruskan
    ++<code>null</code> akan mengembalikan semua baris untuk URI yang diberikan. </li>
    ++  <li><em>selectionArgs</em> — Anda dapat menyertakan ?s dalam pilihan, yang akan
    ++digantikan dengan nilai dari <em>selectionArgs</em>, agar muncul dalam
    ++pilihan. Nilai-nilai akan diikat sebagai String. </li>
    ++  <li><em>sortOrder</em> — Cara menyusun baris, diformat sebagai klausa SQL
    ++ORDER BY (tidak termasuk ORDER BY itu sendiri). Meneruskan <code>null</code> akan
    ++menggunakan urutan sortir default, yang mungkin tidak berurutan.</li>
    ++</ul>
    ++<p>Misalnya:</p>
    ++<pre>
    ++ // If non-null, this is the current filter the user has provided.
    ++String mCurFilter;
    ++...
    ++public Loader&lt;Cursor&gt; onCreateLoader(int id, Bundle args) {
    ++    // This is called when a new Loader needs to be created.  This
    ++    // sample only has one Loader, so we don't care about the ID.
    ++    // First, pick the base URI to use depending on whether we are
    ++    // currently filtering.
    ++    Uri baseUri;
    ++    if (mCurFilter != null) {
    ++        baseUri = Uri.withAppendedPath(Contacts.CONTENT_FILTER_URI,
    ++                  Uri.encode(mCurFilter));
    ++    } else {
    ++        baseUri = Contacts.CONTENT_URI;
    ++    }
    ++
    ++    // Now create and return a CursorLoader that will take care of
    ++    // creating a Cursor for the data being displayed.
    ++    String select = &quot;((&quot; + Contacts.DISPLAY_NAME + &quot; NOTNULL) AND (&quot;
    ++            + Contacts.HAS_PHONE_NUMBER + &quot;=1) AND (&quot;
    ++            + Contacts.DISPLAY_NAME + &quot; != '' ))&quot;;
    ++    return new CursorLoader(getActivity(), baseUri,
    ++            CONTACTS_SUMMARY_PROJECTION, select, null,
    ++            Contacts.DISPLAY_NAME + &quot; COLLATE LOCALIZED ASC&quot;);
    ++}</pre>
    ++<h4 id="onLoadFinished">onLoadFinished</h4>
    ++
    ++<p>Metode ini dipanggil bila loader yang dibuat sebelumnya selesai dimuat.
    ++Metode ini dijamin dipanggil sebelum pelepasan data terakhir
    ++yang disediakan untuk loader ini.  Di titik ini Anda harus menyingkirkan semua penggunaan
    ++data lama (karena akan segera dilepas), namun jangan melepas sendiri
    ++data tersebut karena loader memilikinya dan akan menanganinya.</p>
    ++
    ++
    ++<p>Loader akan melepas data setelah mengetahui bahwa aplikasi tidak
    ++lagi menggunakannya.  Misalnya, jika data adalah kursor dari {@link
    ++android.content.CursorLoader}, Anda tidak boleh memanggil {@link
    ++android.database.Cursor#close close()} sendiri. Jika kursor ditempatkan
    ++dalam {@link android.widget.CursorAdapter}, Anda harus menggunakan metode {@link
    ++android.widget.SimpleCursorAdapter#swapCursor swapCursor()} agar
    ++{@link android.database.Cursor} lama tidak ditutup. Misalnya:</p>
    ++
    ++<pre>
    ++// This is the Adapter being used to display the list's data.<br
    ++/>SimpleCursorAdapter mAdapter;
    ++...
    ++
    ++public void onLoadFinished(Loader&lt;Cursor&gt; loader, Cursor data) {
    ++    // Swap the new cursor in.  (The framework will take care of closing the
    ++    // old cursor once we return.)
    ++    mAdapter.swapCursor(data);
    ++}</pre>
    ++
    ++<h4 id="onLoaderReset">onLoaderReset</h4>
    ++
    ++<p>Metode ini dipanggil bila loader yang dibuat sebelumnya sedang di-reset, sehingga datanya
    ++tidak tersedia. Callback ini memungkinkan Anda mengetahui
    ++kapan data akan dilepas sehingga dapat menghapus acuannya ke callback.  </p>
    ++<p>Implementasi ini memanggil
    ++{@link android.widget.SimpleCursorAdapter#swapCursor swapCursor()}
    ++dengan nilai <code>null</code>:</p>
    ++
    ++<pre>
    ++// This is the Adapter being used to display the list's data.
    ++SimpleCursorAdapter mAdapter;
    ++...
    ++
    ++public void onLoaderReset(Loader&lt;Cursor&gt; loader) {
    ++    // This is called when the last Cursor provided to onLoadFinished()
    ++    // above is about to be closed.  We need to make sure we are no
    ++    // longer using it.
    ++    mAdapter.swapCursor(null);
    ++}</pre>
    ++
    ++
    ++<h2 id="example">Contoh</h2>
    ++
    ++<p>Sebagai contoh, berikut ini adalah implementasi penuh {@link
    ++android.app.Fragment} yang menampilkan {@link android.widget.ListView} berisi
    ++hasil query terhadap penyedia konten kontak. Ia menggunakan {@link
    ++android.content.CursorLoader} untuk mengelola query pada penyedia.</p>
    ++
    ++<p>Agar aplikasi dapat mengakses kontak pengguna, seperti yang ditampilkan dalam contoh ini,
    ++manifesnya harus menyertakan izin
    ++{@link android.Manifest.permission#READ_CONTACTS READ_CONTACTS}.</p>
    ++
    ++<pre>
    ++public static class CursorLoaderListFragment extends ListFragment
    ++        implements OnQueryTextListener, LoaderManager.LoaderCallbacks&lt;Cursor&gt; {
    ++
    ++    // This is the Adapter being used to display the list's data.
    ++    SimpleCursorAdapter mAdapter;
    ++
    ++    // If non-null, this is the current filter the user has provided.
    ++    String mCurFilter;
    ++
    ++    @Override public void onActivityCreated(Bundle savedInstanceState) {
    ++        super.onActivityCreated(savedInstanceState);
    ++
    ++        // Give some text to display if there is no data.  In a real
    ++        // application this would come from a resource.
    ++        setEmptyText(&quot;No phone numbers&quot;);
    ++
    ++        // We have a menu item to show in action bar.
    ++        setHasOptionsMenu(true);
    ++
    ++        // Create an empty adapter we will use to display the loaded data.
    ++        mAdapter = new SimpleCursorAdapter(getActivity(),
    ++                android.R.layout.simple_list_item_2, null,
    ++                new String[] { Contacts.DISPLAY_NAME, Contacts.CONTACT_STATUS },
    ++                new int[] { android.R.id.text1, android.R.id.text2 }, 0);
    ++        setListAdapter(mAdapter);
    ++
    ++        // Prepare the loader.  Either re-connect with an existing one,
    ++        // or start a new one.
    ++        getLoaderManager().initLoader(0, null, this);
    ++    }
    ++
    ++    @Override public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
    ++        // Place an action bar item for searching.
    ++        MenuItem item = menu.add(&quot;Search&quot;);
    ++        item.setIcon(android.R.drawable.ic_menu_search);
    ++        item.setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM);
    ++        SearchView sv = new SearchView(getActivity());
    ++        sv.setOnQueryTextListener(this);
    ++        item.setActionView(sv);
    ++    }
    ++
    ++    public boolean onQueryTextChange(String newText) {
    ++        // Called when the action bar search text has changed.  Update
    ++        // the search filter, and restart the loader to do a new query
    ++        // with this filter.
    ++        mCurFilter = !TextUtils.isEmpty(newText) ? newText : null;
    ++        getLoaderManager().restartLoader(0, null, this);
    ++        return true;
    ++    }
    ++
    ++    @Override public boolean onQueryTextSubmit(String query) {
    ++        // Don't care about this.
    ++        return true;
    ++    }
    ++
    ++    @Override public void onListItemClick(ListView l, View v, int position, long id) {
    ++        // Insert desired behavior here.
    ++        Log.i(&quot;FragmentComplexList&quot;, &quot;Item clicked: &quot; + id);
    ++    }
    ++
    ++    // These are the Contacts rows that we will retrieve.
    ++    static final String[] CONTACTS_SUMMARY_PROJECTION = new String[] {
    ++        Contacts._ID,
    ++        Contacts.DISPLAY_NAME,
    ++        Contacts.CONTACT_STATUS,
    ++        Contacts.CONTACT_PRESENCE,
    ++        Contacts.PHOTO_ID,
    ++        Contacts.LOOKUP_KEY,
    ++    };
    ++    public Loader&lt;Cursor&gt; onCreateLoader(int id, Bundle args) {
    ++        // This is called when a new Loader needs to be created.  This
    ++        // sample only has one Loader, so we don't care about the ID.
    ++        // First, pick the base URI to use depending on whether we are
    ++        // currently filtering.
    ++        Uri baseUri;
    ++        if (mCurFilter != null) {
    ++            baseUri = Uri.withAppendedPath(Contacts.CONTENT_FILTER_URI,
    ++                    Uri.encode(mCurFilter));
    ++        } else {
    ++            baseUri = Contacts.CONTENT_URI;
    ++        }
    ++
    ++        // Now create and return a CursorLoader that will take care of
    ++        // creating a Cursor for the data being displayed.
    ++        String select = &quot;((&quot; + Contacts.DISPLAY_NAME + &quot; NOTNULL) AND (&quot;
    ++                + Contacts.HAS_PHONE_NUMBER + &quot;=1) AND (&quot;
    ++                + Contacts.DISPLAY_NAME + &quot; != '' ))&quot;;
    ++        return new CursorLoader(getActivity(), baseUri,
    ++                CONTACTS_SUMMARY_PROJECTION, select, null,
    ++                Contacts.DISPLAY_NAME + &quot; COLLATE LOCALIZED ASC&quot;);
    ++    }
    ++
    ++    public void onLoadFinished(Loader&lt;Cursor&gt; loader, Cursor data) {
    ++        // Swap the new cursor in.  (The framework will take care of closing the
    ++        // old cursor once we return.)
    ++        mAdapter.swapCursor(data);
    ++    }
    ++
    ++    public void onLoaderReset(Loader&lt;Cursor&gt; loader) {
    ++        // This is called when the last Cursor provided to onLoadFinished()
    ++        // above is about to be closed.  We need to make sure we are no
    ++        // longer using it.
    ++        mAdapter.swapCursor(null);
    ++    }
    ++}</pre>
    ++<h3 id="more_examples">Contoh Selengkapnya</h3>
    ++
    ++<p>Ada beberapa contoh berbeda dalam <strong>ApiDemos</strong> yang
    ++mengilustrasikan cara menggunakan loader:</p>
    ++<ul>
    ++  <li><a href="{@docRoot}resources/samples/ApiDemos/src/com/example/android/apis/app/LoaderCursor.html">
    ++LoaderCursor</a> — Versi lengkap dari
    ++cuplikan yang ditampilkan di atas.</li>
    ++  <li><a href="{@docRoot}resources/samples/ApiDemos/src/com/example/android/apis/app/LoaderThrottle.html"> LoaderThrottle</a> — Contoh cara penggunaan throttling untuk
    ++mengurangi jumlah query dari penyedia konten saat datanya berubah.</li>
    ++</ul>
    ++
    ++<p>Untuk informasi tentang mengunduh dan menginstal contoh SDK, lihat <a href="http://developer.android.com/resources/samples/get.html"> Mendapatkan
    ++Contoh</a>. </p>
    ++
    +diff --git a/docs/html-intl/intl/id/guide/components/processes-and-threads.jd b/docs/html-intl/intl/id/guide/components/processes-and-threads.jd
    +new file mode 100644
    +index 0000000..cdab715
    +--- /dev/null
    ++++ b/docs/html-intl/intl/id/guide/components/processes-and-threads.jd
    +@@ -0,0 +1,411 @@
    ++page.title=Proses dan Thread
    ++page.tags=daur hidup,latar belakang
    ++
    ++@jd:body
    ++
    ++<div id="qv-wrapper">
    ++<div id="qv">
    ++
    ++<h2>Dalam dokumen ini</h2>
    ++<ol>
    ++<li><a href="#Processes">Proses</a>
    ++  <ol>
    ++    <li><a href="#Lifecycle">Daur hidup proses</a></li>
    ++  </ol>
    ++</li>
    ++<li><a href="#Threads">Thread</a>
    ++  <ol>
    ++    <li><a href="#WorkerThreads">Thread pekerja</a></li>
    ++    <li><a href="#ThreadSafe">Metode thread-safe</a></li>
    ++  </ol>
    ++</li>
    ++<li><a href="#IPC">Komunikasi antarproses</a></li>
    ++</ol>
    ++
    ++</div>
    ++</div>
    ++
    ++<p>Bila komponen aplikasi dimulai dan tidak ada komponen aplikasi lain yang
    ++berjalan, sistem Android akan memulai proses Linux baru untuk aplikasi dengan satu thread
    ++eksekusi. Secara default, semua komponen aplikasi yang sama berjalan dalam proses dan
    ++thread yang sama (disebut thread "utama"). Jika komponen aplikasi dimulai dan sudah ada
    ++proses untuk aplikasi itu (karena komponen lain dari aplikasi itu sudah ada), maka komponen
    ++akan dimulai dalam proses itu dan menggunakan thread eksekusi yang sama. Akan tetapi, Anda bisa
    ++mengatur komponen berbeda di aplikasi agar berjalan di proses terpisah, dan Anda bisa membuat thread tambahan untuk
    ++setiap proses.</p>
    ++
    ++<p>Dokumen ini membahas cara kerja proses dan thread di aplikasi Android.</p>
    ++
    ++
    ++<h2 id="Processes">Proses</h2>
    ++
    ++<p>Secara default, semua komponen aplikasi yang sama berjalan dalam proses yang sama dan kebanyakan
    ++aplikasi tidak boleh mengubah ini. Akan tetapi, jika Anda merasa perlu mengontrol proses milik
    ++komponen tertentu, Anda dapat melakukannya dalam file manifes.</p>
    ++
    ++<p>Entri manifes untuk setiap tipe elemen komponen&mdash;<a href="{@docRoot}guide/topics/manifest/activity-element.html">{@code
    ++&lt;activity&gt;}</a>, <a href="{@docRoot}guide/topics/manifest/service-element.html">{@code
    ++&lt;service&gt;}</a>, <a href="{@docRoot}guide/topics/manifest/receiver-element.html">{@code
    ++&lt;receiver&gt;}</a>, dan <a href="{@docRoot}guide/topics/manifest/provider-element.html">{@code
    ++&lt;provider&gt;}</a>&mdash;mendukung atribut {@code android:process} yang bisa menetapkan
    ++dalam proses mana komponen harus dijalankan. Anda bisa mengatur atribut ini agar setiap komponen
    ++berjalan dalam prosesnya sendiri atau agar beberapa komponen menggunakan proses yang sama sementara yang lainnya tidak.  Anda juga bisa mengatur
    ++{@code android:process} agar komponen aplikasi yang berbeda berjalan dalam proses yang sama
    ++&mdash;sepanjang aplikasi menggunakan ID Linux yang sama dan ditandatangani
    ++dengan sertifikat yang sama.</p>
    ++
    ++<p>Elemen <a href="{@docRoot}guide/topics/manifest/application-element.html">{@code
    ++&lt;application&gt;}</a> juga mendukung atribut {@code android:process}, untuk mengatur
    ++nilai default yang berlaku bagi semua komponen.</p>
    ++
    ++<p>Android bisa memutuskan untuk mematikan proses pada waktu tertentu, bila memori tinggal sedikit dan diperlukan oleh
    ++proses lain yang lebih mendesak untuk melayani pengguna. Komponen
    ++aplikasi yang berjalan dalam proses yang dimatikan maka sebagai konsekuensinya juga akan dimusnahkan.  Proses dimulai
    ++kembali untuk komponen itu bila ada lagi pekerjaan untuk mereka lakukan.</p>
    ++
    ++<p>Saat memutuskan proses yang akan dimatikan, sistem Android akan mempertimbangkan kepentingan relatifnya bagi
    ++pengguna.  Misalnya, sistem lebih mudah menghentikan proses yang menjadi host aktivitas yang tidak
    ++ lagi terlihat di layar, dibandingkan dengan proses yang menjadi host aktivitas yang terlihat. Karena itu, keputusan
    ++untuk menghentikan proses bergantung pada keadaan komponen yang berjalan dalam proses tersebut. Aturan
    ++yang digunakan untuk menentukan proses yang akan dihentikan dibahas di bawah ini. </p>
    ++
    ++
    ++<h3 id="Lifecycle">Daur hidup proses</h3>
    ++
    ++<p>Sistem Android mencoba mempertahankan proses aplikasi selama mungkin, namun
    ++pada akhirnya perlu menghapus proses lama untuk mengambil kembali memori bagi proses baru atau yang lebih penting.  Untuk
    ++menentukan proses yang akan
    ++dipertahankan dan yang harus dimatikan, sistem menempatkan setiap proses ke dalam "hierarki prioritas" berdasarkan
    ++komponen yang berjalan dalam proses dan status komponen tersebut.  Proses yang memiliki
    ++prioritas terendah akan dimatikan terlebih dahulu, kemudian yang terendah berikutnya, dan seterusnya, jika perlu
    ++untuk memulihkan sumber daya sistem.</p>
    ++
    ++<p>Ada lima tingkatan dalam hierarki prioritas. Daftar berikut berisi beberapa
    ++tipe proses berdasarkan urutan prioritas (proses pertama adalah yang <em>terpenting</em> dan
    ++<em>dimatikan terakhir</em>):</p>
    ++
    ++<ol>
    ++  <li><b>Proses latar depan</b>
    ++    <p>Proses yang diperlukan untuk aktivitas yang sedang dilakukan pengguna.  Proses
    ++dianggap berada di latar depan jika salah satu kondisi berikut terpenuhi:</p>
    ++
    ++      <ul>
    ++        <li>Proses menjadi host {@link android.app.Activity} yang berinteraksi dengan pengguna dengan metode ({@link
    ++android.app.Activity}{@link android.app.Activity#onResume onResume()} telah
    ++dipanggil).</li>
    ++
    ++        <li>Proses menjadi host {@link android.app.Service} yang terikat dengan aktivitas yang sedang berinteraksi dengan
    ++pengguna.</li>
    ++
    ++        <li>Proses menjadi host {@link android.app.Service} yang berjalan "di latar depan"&mdash;
    ++layanan telah memanggil{@link android.app.Service#startForeground startForeground()}.
    ++
    ++        <li>Proses menjadi host {@link android.app.Service} yang menjalankan salah satu callback
    ++daur hidupnya ({@link android.app.Service#onCreate onCreate()}, {@link android.app.Service#onStart
    ++onStart()}, atau {@link android.app.Service#onDestroy onDestroy()}).</li>
    ++
    ++        <li>Proses menjadi host {@link android.content.BroadcastReceiver} yang menjalankan metode {@link
    ++        android.content.BroadcastReceiver#onReceive onReceive()}-nya.</li>
    ++    </ul>
    ++
    ++    <p>Secara umum, hanya ada beberapa proses latar depan pada waktu yang diberikan.  Proses dimatikan hanya sebagai
    ++upaya terakhir&mdash; jika memori hampir habis sehingga semuanya tidak bisa terus berjalan.  Pada umumnya, pada
    ++titik itu, perangkat dalam keadaan memory paging, sehingga menghentikan beberapa proses latar depan
    ++diperlukan agar antarmuka pengguna tetap responsif.</p></li>
    ++
    ++  <li><b>Proses yang terlihat</b>
    ++    <p>Proses yang tidak memiliki komponen latar depan, namun masih bisa
    ++memengaruhi apa yang dilihat pengguna di layar. Proses dianggap terlihat jika salah satu kondisi
    ++berikut terpenuhi:</p>
    ++
    ++      <ul>
    ++        <li>Proses ini menjadi host {@link android.app.Activity} yang tidak berada di latar depan, namun masih
    ++terlihat oleh penggunanya (metode {@link android.app.Activity#onPause onPause()} telah dipanggil).
    ++Ini bisa terjadi, misalnya, jika aktivitas latar depan memulai dialog, sehingga
    ++aktivitas sebelumnya terlihat berada di belakangnya.</li>
    ++
    ++        <li>Proses menjadi host {@link android.app.Service} yang terikat dengan aktivitas yang terlihat (atau latar
    ++depan)</li>
    ++      </ul>
    ++
    ++      <p>Proses yang terlihat dianggap sangat penting dan tidak akan dimatikan kecuali jika hal itu
    ++diperlukan agar semua proses latar depan tetap berjalan. </p>
    ++    </li>
    ++
    ++  <li><b>Proses layanan</b>
    ++    <p>Proses yang menjalankan layanan yang telah dimulai dengan metode {@link
    ++android.content.Context#startService startService()} dan tidak termasuk dalam salah satu dari dua kategori
    ++yang lebih tinggi. Walaupun proses pelayanan tidak langsung terkait dengan semua yang dilihat oleh pengguna, proses ini
    ++umumnya melakukan hal-hal yang dipedulikan pengguna (seperti memutar musik di latar belakang
    ++atau mengunduh data di jaringan), jadi sistem membuat proses tetap berjalan kecuali memori tidak cukup untuk
    ++mempertahankannya bersama semua proses latar depan dan proses yang terlihat. </p>
    ++  </li>
    ++
    ++  <li><b>Proses latar belakang</b>
    ++    <p>Proses yang menampung aktivitas yang saat ini tidak terlihat oleh pengguna (metode
    ++{@link android.app.Activity#onStop onStop()} aktivitas telah dipanggil). Proses ini tidak memiliki dampak
    ++langsung pada pengalaman pengguna, dan sistem bisa menghentikannya kapan saja untuk memperoleh kembali memori bagi
    ++proses latar depan, proses yang terlihat,
    ++atau proses layanan. Biasanya ada banyak proses latar belakang yang berjalan, sehingga disimpan
    ++dalam daftar LRU (least recently used atau paling sedikit digunakan) untuk memastikan bahwa proses dengan aktivitas yang paling baru
    ++terlihat oleh pengguna sebagai yang terakhir untuk dimatikan. Jika aktivitas mengimplementasikan metode
    ++ daur hidupnya dengan benar, dan menyimpan statusnya saat ini, menghentikan prosesnya tidak akan memiliki efek
    ++yang terlihat pada pengalaman pengguna, karena ketika pengguna kembali ke aktivitas, aktivitas itu memulihkan
    ++semua statusnya yang terlihat. Lihat dokumen <a href="{@docRoot}guide/components/activities.html#SavingActivityState">Aktivitas</a>
    ++ untuk mendapatkan informasi tentang menyimpan dan memulihkan status.</p>
    ++  </li>
    ++
    ++  <li><b>Proses kosong</b>
    ++    <p>Sebuah proses yang tidak berisi komponen aplikasi aktif apa pun.  Alasan satu-satunya mempertahankan proses
    ++seperti ini tetap hidup adalah untuk keperluan caching, meningkatkan waktu mulai (startup) bila
    ++nanti komponen perlu dijalankan di dalamnya.  Sistem sering menghentikan proses ini untuk menyeimbangkan sumber
    ++daya sistem secara keseluruhan antara proses cache dan cache kernel yang mendasarinya.</p>
    ++  </li>
    ++</ol>
    ++
    ++
    ++  <p>Android sebisa mungkin memeringkat proses setinggi
    ++mungkin, berdasarkan prioritas komponen yang sedang aktif dalam proses.  Misalnya, jika suatu proses menjadi host sebuah layanan dan
    ++aktivitas yang terlihat, proses akan diperingkat sebagai proses yang terlihat, bukan sebagai proses layanan.</p>
    ++
    ++  <p>Selain itu, peringkat proses dapat meningkat karena adanya proses lain yang bergantung padanya
    ++&mdash;proses yang melayani proses lain tidak bisa diperingkat lebih rendah daripada proses yang
    ++sedang dilayaninya. Misalnya, jika penyedia konten dalam proses A melayani klien dalam proses B, atau
    ++jika layanan dalam proses A terikat dengan komponen dalam proses B, proses A selalu dipertimbangkan sebagai paling rendah
    ++prioritasnya dibandingkan dengan proses B.</p>
    ++
    ++  <p>Karena proses yang menjalankan layanan diperingkat lebih tinggi daripada aktivitas latar belakang,
    ++aktivitas yang memulai operasi yang berjalan lama mungkin lebih baik memulai <a href="{@docRoot}guide/components/services.html">layanan</a> untuk operasi itu, daripada hanya
    ++membuat thread pekerja&mdash;khususnya jika operasi mungkin akan berlangsung lebih lama daripada aktivitas.
    ++ Misalnya, aktivitas yang mengunggah gambar ke situs web harus memulai layanan
    ++untuk mengunggah sehingga unggahan bisa terus berjalan di latar belakang meskipun pengguna meninggalkan aktivitas tersebut.
    ++Menggunakan layanan akan memastikan operasi paling tidak memiliki prioritas "proses layanan",
    ++apa pun yang terjadi pada aktivitas. Ini menjadi alasan yang sama yang membuat penerima siaran harus
    ++menjalankan layanan daripada hanya menempatkan operasi yang menghabiskan waktu di thread.</p>
    ++
    ++
    ++
    ++
    ++<h2 id="Threads">Thread</h2>
    ++
    ++<p>Bila aplikasi diluncurkan, sistem akan membuat thread eksekusi untuk aplikasi tersebut, yang diberi nama,
    ++"main". Thread ini sangat penting karena bertugas mengirim kejadian ke widget
    ++antarmuka pengguna yang sesuai, termasuk kejadian menggambar. Ini juga merupakan thread yang
    ++membuat aplikasi berinteraksi dengan komponen dari Android UI toolkit (komponen dari paket {@link
    ++android.widget} dan {@link android.view}). Karena itu, thread 'main' juga terkadang
    ++disebut thread UI.</p>
    ++
    ++<p>Sistem ini <em>tidak</em> membuat thread terpisah untuk setiap instance komponen. Semua
    ++komponen yang berjalan di proses yang sama akan dibuat instance-nya dalam thread UI, dan sistem akan memanggil
    ++setiap komponen yang dikirim dari thread itu. Akibatnya, metode yang merespons callback sistem
    ++ (seperti {@link android.view.View#onKeyDown onKeyDown()} untuk melaporkan tindakan pengguna atau metode callback daur hidup)
    ++ selalu berjalan di thread UI proses.</p>
    ++
    ++<p>Misalnya saat pengguna menyentuh tombol pada layar, thread UI aplikasi akan mengirim kejadian
    ++sentuh ke widget, yang selanjutnya menetapkan status ditekan dan mengirim permintaan yang tidak divalidasi ke
    ++antrean kejadian. Thread UI akan menghapus antrean permintaan dan memberi tahu widget bahwa widget harus menggambar
    ++dirinya sendiri.</p>
    ++
    ++<p>Saat aplikasi melakukan pekerjaan intensif sebagai respons terhadap interaksi pengguna, model
    ++thread tunggal ini bisa menghasilkan kinerja yang buruk kecuali jika Anda mengimplementasikan aplikasi dengan benar. Khususnya jika
    ++ semua terjadi di thread UI, melakukan operasi yang panjang seperti akses ke jaringan atau query
    ++database akan memblokir seluruh UI. Bila thread diblokir, tidak ada kejadian yang bisa dikirim,
    ++termasuk kejadian menggambar. Dari sudut pandang pengguna, aplikasi
    ++tampak mogok (hang). Lebih buruk lagi, jika thread UI diblokir selama lebih dari beberapa detik
    ++(saat ini sekitar 5 detik) pengguna akan ditampilkan dialog "<a href="http://developer.android.com/guide/practices/responsiveness.html">aplikasi tidak
    ++merespons</a>" (ANR) yang populer karena reputasi buruknya. Pengguna nanti bisa memutuskan untuk keluar dari aplikasi dan menghapus aplikasi
    ++jika mereka tidak suka.</p>
    ++
    ++<p>Selain itu, toolkit Android UI <em>bukan</em> thread-safe. Jadi, Anda tidak harus memanipulasi
    ++UI dari thread pekerja&mdash;Anda harus melakukan semua manipulasi pada antarmuka pengguna dari thread
    ++UI. Sehingga hanya ada dua aturan untuk model thread tunggal Android:</p>
    ++
    ++<ol>
    ++<li>Jangan memblokir thread UI
    ++<li>Jangan mengakses toolkit Android UI dari luar thread UI
    ++</ol>
    ++
    ++<h3 id="WorkerThreads">Thread pekerja</h3>
    ++
    ++<p>Karena model thread tunggal yang dijelaskan di atas, Anda dilarang memblokir thread
    ++UI demi daya respons UI aplikasi. Jika memiliki operasi untuk dijalankan
    ++yang tidak seketika, Anda harus memastikan untuk melakukannya di thread terpisah (thread "latar belakang" atau
    ++thread "pekerja").</p>
    ++
    ++<p>Misalnya, berikut ini beberapa kode untuk listener klik yang mengunduh gambar dari
    ++thread terpisah dan menampilkannya dalam {@link android.widget.ImageView}:</p>
    ++
    ++<pre>
    ++public void onClick(View v) {
    ++    new Thread(new Runnable() {
    ++        public void run() {
    ++            Bitmap b = loadImageFromNetwork("http://example.com/image.png");
    ++            mImageView.setImageBitmap(b);
    ++        }
    ++    }).start();
    ++}
    ++</pre>
    ++
    ++<p>Awalnya hal ini tampak bekerja dengan baik, karena menciptakan thread baru untuk menangani
    ++operasi jaringan. Akan tetapi, hal tersebut melanggar aturan kedua model thread tunggal: <em>jangan mengakses
    ++ toolkit Android UI dari luar thread UI</em>&mdash;sampel ini memodifikasi {@link
    ++android.widget.ImageView} dari thread pekerja sebagai ganti thread UI. Ini bisa
    ++mengakibatkan perilaku yang tidak terdefinisi dan tidak diharapkan, yang bisa menyulitkan dan menghabiskan waktu untuk melacaknya.</p>
    ++
    ++<p>Untuk memperbaiki masalah ini, Android menawarkan beberapa cara untuk mengakses thread UI dari
    ++thread lainnya. Berikut ini daftar metode yang bisa membantu:</p>
    ++
    ++<ul>
    ++<li>{@link android.app.Activity#runOnUiThread(java.lang.Runnable)
    ++Activity.runOnUiThread(Runnable)}</li>
    ++<li>{@link android.view.View#post(java.lang.Runnable) View.post(Runnable)}</li>
    ++<li>{@link android.view.View#postDelayed(java.lang.Runnable, long) View.postDelayed(Runnable,
    ++long)}</li>
    ++</ul>
    ++
    ++<p>Misalnya, Anda bisa memperbaiki kode di atas dengan menggunakan metode {@link
    ++android.view.View#post(java.lang.Runnable) View.post(Runnable)}:</p>
    ++
    ++<pre>
    ++public void onClick(View v) {
    ++    new Thread(new Runnable() {
    ++        public void run() {
    ++            final Bitmap bitmap = loadImageFromNetwork("http://example.com/image.png");
    ++            mImageView.post(new Runnable() {
    ++                public void run() {
    ++                    mImageView.setImageBitmap(bitmap);
    ++                }
    ++            });
    ++        }
    ++    }).start();
    ++}
    ++</pre>
    ++
    ++<p>Kini implementasi ini thread-safe: operasi jaringan dilakukan terpisah dari thread
    ++ sementara {@link android.widget.ImageView} dimanipulasi dari thread UI.</p>
    ++
    ++<p>Akan tetapi, karena operasi semakin kompleks, jenis kode seperti ini bisa semakin rumit
    ++dan sulit dipertahankan. Untuk menangani interaksi yang lebih kompleks dengan thread pekerja, Anda bisa mempertimbangkan
    ++ penggunaan {@link android.os.Handler}di thread pekerja, untuk memproses pesan yang dikirim dari
    ++ thread UI. Mungkin solusi terbaiknya adalah memperpanjang kelas {@link android.os.AsyncTask},
    ++yang akan menyederhanakan eksekusi tugas-tugas thread pekerja yang perlu berinteraksi dengan UI.</p>
    ++
    ++
    ++<h4 id="AsyncTask">Menggunakan AsyncTask</h4>
    ++
    ++<p>Dengan {@link android.os.AsyncTask}, Anda bisa melakukan pekerjaan asinkron pada antarmuka
    ++pengguna. AsyncTask memblokir operasi di thread pekerja kemudian mempublikasikan hasilnya
    ++di thread UI, tanpa mengharuskan Anda untuk menangani sendiri thread dan/atau handler sendiri.</p>
    ++
    ++<p>Untuk menggunakannya, Anda harus menempatkan {@link android.os.AsyncTask} sebagai subkelas dan mengimplementasikan metode callback {@link
    ++android.os.AsyncTask#doInBackground doInBackground()} yang berjalan di kumpulan
    ++thread latar belakang. Untuk memperbarui UI, Anda harus mengimplementasikan {@link
    ++android.os.AsyncTask#onPostExecute onPostExecute()}, yang memberikan hasil dari {@link
    ++android.os.AsyncTask#doInBackground doInBackground()} dan berjalan di thread UI, jadi Anda bisa
    ++memperbarui UI dengan aman. Selanjutnya Anda bisa menjalankan tugas dengan memanggil {@link android.os.AsyncTask#execute execute()}
    ++dari thread UI.</p>
    ++
    ++<p>Misalnya, Anda bisa mengimplementasikan contoh sebelumnya menggunakan {@link android.os.AsyncTask} dengan cara
    ++ini:</p>
    ++
    ++<pre>
    ++public void onClick(View v) {
    ++    new DownloadImageTask().execute("http://example.com/image.png");
    ++}
    ++
    ++private class DownloadImageTask extends AsyncTask&lt;String, Void, Bitmap&gt; {
    ++    /** The system calls this to perform work in a worker thread and
    ++      * delivers it the parameters given to AsyncTask.execute() */
    ++    protected Bitmap doInBackground(String... urls) {
    ++        return loadImageFromNetwork(urls[0]);
    ++    }
    ++
    ++    /** The system calls this to perform work in the UI thread and delivers
    ++      * the result from doInBackground() */
    ++    protected void onPostExecute(Bitmap result) {
    ++        mImageView.setImageBitmap(result);
    ++    }
    ++}
    ++</pre>
    ++
    ++<p>Kini UI aman dan kode jadi lebih sederhana, karena memisahkan pekerjaan ke
    ++dalam bagian-bagian yang harus dilakukan pada thread pekerja dan thread UI.</p>
    ++
    ++<p>Anda harus membaca acuan {@link android.os.AsyncTask} untuk memahami sepenuhnya
    ++cara menggunakan kelas ini, namun berikut ini ikhtisar singkat cara kerjanya:</p>
    ++
    ++<ul>
    ++<li>Anda bisa menetapkan tipe parameter, nilai kemajuan, dan nilai
    ++ akhir tugas, dengan menggunakan generik</li>
    ++<li>Metode {@link android.os.AsyncTask#doInBackground doInBackground()} berjalan secara otomatis pada
    ++thread pekerja</li>
    ++<li>{@link android.os.AsyncTask#onPreExecute onPreExecute()}, {@link
    ++android.os.AsyncTask#onPostExecute onPostExecute()}, dan {@link
    ++android.os.AsyncTask#onProgressUpdate onProgressUpdate()} semuanya dipanggil pada thread UI</li>
    ++<li>Nilai yang dikembalikan oleh {@link android.os.AsyncTask#doInBackground doInBackground()} akan dikirim ke
    ++{@link android.os.AsyncTask#onPostExecute onPostExecute()}</li>
    ++<li>Anda bisa memangil {@link android.os.AsyncTask#publishProgress publishProgress()} setiap saat di {@link
    ++android.os.AsyncTask#doInBackground doInBackground()} untuk mengeksekusi {@link
    ++android.os.AsyncTask#onProgressUpdate onProgressUpdate()} pada thread UI</li>
    ++<li>Anda bisa membatalkan tugas ini kapan saja, dari thread mana saja</li>
    ++</ul>
    ++
    ++<p class="caution"><strong>Perhatian:</strong> Masalah lain yang mungkin Anda temui saat menggunakan
    ++thread pekerja adalah restart tak terduga dalam aktivitas karena <a href="{@docRoot}guide/topics/resources/runtime-changes.html">perubahan konfigurasi runtime</a>
    ++ (seperti saat pengguna mengubah orientasi layar), yang bisa memusnahkan thread pekerja. Untuk
    ++melihat cara mempertahankan tugas selama restart ini dan cara membatalkan
    ++tugas dengan benar saat aktivitas dimusnahkan, lihat kode sumber untuk aplikasi sampel <a href="http://code.google.com/p/shelves/">Shelves</a>.</p>
    ++
    ++
    ++<h3 id="ThreadSafe">Metode thread-safe</h3>
    ++
    ++<p> Dalam beberapa situasi, metode yang Anda implementasikan bisa dipanggil dari lebih dari satu thread,
    ++dan karena itu harus ditulis agar menjadi thread-safe. </p>
    ++
    ++<p>Ini terutama terjadi untuk metode yang bisa dipanggil dari jauh &mdash;seperti metode dalam <a href="{@docRoot}guide/components/bound-services.html">layanan terikat</a>. Bila sebuah panggilan pada
    ++metode yang dijalankan dalam {@link android.os.IBinder} berasal dari proses yang sama di mana
    ++{@link android.os.IBinder IBinder} berjalan, metode ini akan dieksekusi di thread pemanggil.
    ++Akan tetapi, bila panggilan berasal proses lain, metode akan dieksekusi dalam thread yang dipilih dari
    ++ kumpulan (pool) thread yang dipertahankan sistem dalam proses yang sama seperti{@link android.os.IBinder
    ++IBinder} (tidak dieksekusi dalam thread UI proses).  Misalnya, karena metode
    ++{@link android.app.Service#onBind onBind()} layanan akan dipanggil dari thread UI
    ++proses layanan, metode yang diimplementasikan dalam objek yang dikembalikan {@link android.app.Service#onBind
    ++onBind()} (misalnya, subkelas yang mengimplementasikan metode RPC) akan dipanggil dari thread
    ++di pool. Karena layanan bisa memiliki lebih dari satu klien, maka lebih dari satu pool thread bisa melibatkan
    ++ metode {@link android.os.IBinder IBinder} yang sama sekaligus. Metode {@link android.os.IBinder
    ++IBinder} karenanya harus diimplementasikan sebagai thread-safe.</p>
    ++
    ++<p> Penyedia konten juga bisa menerima permintaan data yang berasal dalam proses lain.
    ++Meskipun kelas {@link android.content.ContentResolver} dan {@link android.content.ContentProvider}
    ++ menyembunyikan detail cara komunikasi antarproses dikelola, metode {@link
    ++android.content.ContentProvider} yang merespons permintaan itu&mdash;metode {@link
    ++android.content.ContentProvider#query query()}, {@link android.content.ContentProvider#insert
    ++insert()}, {@link android.content.ContentProvider#delete delete()}, {@link
    ++android.content.ContentProvider#update update()}, dan {@link android.content.ContentProvider#getType
    ++getType()}&mdash; dipanggil dari pool thread pada proses penyedia konten, bukan thread UI
    ++untuk proses tersebut.  Mengingat metode ini bisa dipanggil dari thread mana pun
    ++sekaligus, metode-metode ini juga harus diimplementasikan sebagai thread-safe. </p>
    ++
    ++
    ++<h2 id="IPC">Komunikasi Antarproses</h2>
    ++
    ++<p>Android menawarkan mekanisme komunikasi antarproses (IPC) menggunakan panggilan prosedur jauh
    ++ (RPC), yang mana metode ini dipanggil oleh aktivitas atau komponen aplikasi lain, namun dieksekusi dari
    ++jauh (di proses lain), bersama hasil yang dikembalikan ke
    ++pemanggil. Ini mengharuskan penguraian panggilan metode dan datanya ke tingkat yang bisa
    ++dipahami sistem operasi, mentransmisikannya dari proses lokal dan ruang alamat untuk proses jauh
    ++dan ruang proses, kemudian merakit kembali dan menetapkannya kembali di sana.  Nilai-nilai yang dikembalikan
    ++akan ditransmisikan dalam arah berlawanan.  Android menyediakan semua kode untuk melakukan transaksi IPC
    ++ ini, sehingga Anda bisa fokus pada pendefinisian dan implementasi antarmuka pemrograman RPC. </p>
    ++
    ++<p>Untuk melakukan IPC, aplikasi Anda harus diikat ke layanan, dengan menggunakan {@link
    ++android.content.Context#bindService bindService()}. Untuk informasi selengkapnya, lihat panduan pengembang <a href="{@docRoot}guide/components/services.html">Layanan</a>.</p>
    ++
    ++
    ++<!--
    ++<h2>Beginner's Path</h2>
    ++
    ++<p>For information about how to perform work in the background for an indefinite period of time
    ++(without a user interface), continue with the <b><a
    ++href="{@docRoot}guide/components/services.html">Services</a></b> document.</p>
    ++-->
    +diff --git a/docs/html-intl/intl/id/guide/components/recents.jd b/docs/html-intl/intl/id/guide/components/recents.jd
    +new file mode 100644
    +index 0000000..286fdc1
    +--- /dev/null
    ++++ b/docs/html-intl/intl/id/guide/components/recents.jd
    +@@ -0,0 +1,256 @@
    ++page.title=Layar Ikhtisar
    ++page.tags="recents","overview"
    ++
    ++@jd:body
    ++
    ++<div id="qv-wrapper">
    ++<div id="qv">
    ++
    ++  <h2>Dalam dokumen ini</h2>
    ++  <ol>
    ++    <li><a href="#adding">Menambahkan Tugas ke Layar Ikhtisar</a>
    ++      <ol>
    ++        <li><a href="#flag-new-doc">Menggunakan flag Intent untuk menambahkan tugas</a></li>
    ++        <li><a href="#attr-doclaunch">Menggunakan atribut Aktivitas untuk menambahkan tugas</a></li>
    ++      </ol>
    ++    </li>
    ++    <li><a href="#removing">Menghapus Tugas</a>
    ++      <ol>
    ++        <li><a href="#apptask-remove">Menggunakan kelas AppTask untuk menghapus tugas</a></li>
    ++        <li><a href="#retain-finished">Mempertahankan tugas yang telah selesai</a></li>
    ++      </ol>
    ++    </li>
    ++  </ol>
    ++
    ++  <h2>Kelas-kelas utama</h2>
    ++  <ol>
    ++    <li>{@link android.app.ActivityManager.AppTask}</li>
    ++    <li>{@link android.content.Intent}</li>
    ++  </ol>
    ++
    ++  <h2>Kode contoh</h2>
    ++  <ol>
    ++    <li><a href="{@docRoot}samples/DocumentCentricApps/index.html">Aplikasi yang berorientasi dokumen</a></li>
    ++  </ol>
    ++
    ++</div>
    ++</div>
    ++
    ++<p>Layar ikhtisar (juga disebut sebagai layar terbaru, daftar tugas terbaru, atau aplikasi terbaru)
    ++UI tingkat sistem yang mencantumkan <a href="{@docRoot}guide/components/activities.html">
    ++aktivitas</a> dan <a href="{@docRoot}guide/components/tasks-and-back-stack.html">tugas</a> yang baru saja diakses. Pengguna
    ++bisa menyusuri daftar ini dan memilih satu tugas untuk dilanjutkan, atau pengguna bisa menghapus tugas dari
    ++daftar dengan gerakan mengusap. Dengan dirilisnya Android 5.0 (API level 21), beberapa instance aktivitas yang
    ++sama yang berisi dokumen berbeda dapat muncul sebagai tugas di layar ikhtisar. Misalnya,
    ++Google Drive mungkin memiliki satu tugas untuk setiap beberapa dokumen Google. Setiap dokumen muncul sebagai
    ++tugas dalam layar ikhtisar.</p>
    ++
    ++<img src="{@docRoot}images/components/recents.png" alt="" width="284" />
    ++<p class="img-caption"><strong>Gambar 1.</strong> Layar ikhtisar menampilkan tiga dokumen
    ++Google Drive, masing-masing dinyatakan sebagai tugas terpisah.</p>
    ++
    ++<p>Biasanya Anda harus mengizinkan sistem mendefinisikan cara menyatakan tugas dan
    ++aktivitas di layar ikhtisar, dan Anda tidak perlu memodifikasi perilaku ini.
    ++Akan tetapi, aplikasi Anda dapat menentukan cara dan waktu munculnya aktivitas di layar ikhtisar. Kelas
    ++{@link android.app.ActivityManager.AppTask} memungkinkan Anda mengelola tugas, dan flag
    ++ aktivitas kelas {@link android.content.Intent} memungkinkan Anda menentukan kapan aktivitas ditambahkan atau dihapus dari
    ++layar ikhtisar. Selain itu, atribut <code><a href="{@docRoot}guide/topics/manifest/activity-element.html">
    ++&lt;activity&gt;</a></code> memungkinkan Anda menetapkan perilaku di manifes.</p>
    ++
    ++<h2 id="adding">Menambahkan Tugas ke Layar Ikhtisar</h2>
    ++
    ++<p>Penggunaan flag kelas {@link android.content.Intent} untuk menambahkan tugas memberi kontrol lebih besar
    ++atas waktu dan cara dokumen dibuka atau dibuka kembali di layar ikhtisar. Bila menggunakan atribut
    ++<code><a href="{@docRoot}guide/topics/manifest/activity-element.html">&lt;activity&gt;</a></code>
    ++, Anda dapat memilih antara selalu membuka dokumen dalam tugas baru atau menggunakan kembali tugas
    ++yang ada untuk dokumen tersebut.</p>
    ++
    ++<h3 id="flag-new-doc">Menggunakan flag Intent untuk menambahkan tugas</h3>
    ++
    ++<p>Bila membuat dokumen baru untuk aktivitas, Anda memanggil metode
    ++{@link android.app.ActivityManager.AppTask#startActivity(android.content.Context, android.content.Intent, android.os.Bundle) startActivity()}
    ++ dari kelas {@link android.app.ActivityManager.AppTask}, dengan meneruskannya ke intent yang
    ++menjalankan aktivitas tersebut. Untuk menyisipkan jeda logis agar sistem memperlakukan aktivitas Anda sebagai tugas
    ++baru di layar ikhtisar, teruskan flag {@link android.content.Intent#FLAG_ACTIVITY_NEW_DOCUMENT}
    ++dalam metode {@link android.content.Intent#addFlags(int) addFlags()} dari {@link android.content.Intent}
    ++yang memulai aktivitas itu.</p>
    ++
    ++<p class="note"><strong>Catatan:</strong> Flag {@link android.content.Intent#FLAG_ACTIVITY_NEW_DOCUMENT}
    ++menggantikan flag {@link android.content.Intent#FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET},
    ++yang tidak digunakan lagi pada Android 5.0 (API level 21).</p>
    ++
    ++<p>Jika Anda menetapkan flag {@link android.content.Intent#FLAG_ACTIVITY_MULTIPLE_TASK} saat membuat
    ++dokumen baru, sistem akan selalu membuat tugas baru dengan aktivitas target sebagai akar.
    ++Dengan pengaturan ini, dokumen yang sama dapat dibuka di lebih dari satu tugas. Kode berikut memperagakan
    ++cara aktivitas utama melakukannya:</p>
    ++
    ++<p class="code-caption"><a href="{@docRoot}samples/DocumentCentricApps/index.html">
    ++DocumentCentricActivity.java</a></p>
    ++<pre>
    ++public void createNewDocument(View view) {
    ++      final Intent newDocumentIntent = newDocumentIntent();
    ++      if (useMultipleTasks) {
    ++          newDocumentIntent.addFlags(Intent.FLAG_ACTIVITY_MULTIPLE_TASK);
    ++      }
    ++      startActivity(newDocumentIntent);
    ++  }
    ++
    ++  private Intent newDocumentIntent() {
    ++      boolean useMultipleTasks = mCheckbox.isChecked();
    ++      final Intent newDocumentIntent = new Intent(this, NewDocumentActivity.class);
    ++      newDocumentIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_DOCUMENT);
    ++      newDocumentIntent.putExtra(KEY_EXTRA_NEW_DOCUMENT_COUNTER, incrementAndGet());
    ++      return newDocumentIntent;
    ++  }
    ++
    ++  private static int incrementAndGet() {
    ++      Log.d(TAG, "incrementAndGet(): " + mDocumentCounter);
    ++      return mDocumentCounter++;
    ++  }
    ++}
    ++</pre>
    ++
    ++<p class="note"><strong>Catatan:</strong> Aktivitas yang dimulai dengan flag {@code FLAG_ACTIVITY_NEW_DOCUMENT}
    ++ harus telah menetapkan nilai atribut {@code android:launchMode="standard"} (default) dalam
    ++manifes.</p>
    ++
    ++<p>Bila aktivitas utama memulai aktivitas baru, sistem akan mencari tugas yang intent
    ++-nya cocok dengan nama komponen intent dalam tugas-tugas yang sudah ada dan mencari aktivitas dalam data Intent. Jika tugas
    ++tidak ditemukan, atau intent ada dalam flag {@link android.content.Intent#FLAG_ACTIVITY_MULTIPLE_TASK}
    ++, tugas baru akan dibuat dengan aktivitas tersebut sebagai akarnya. Jika ditemukan, sistem akan
    ++mengedepankan tugas itu dan meneruskan intent baru ke {@link android.app.Activity#onNewIntent onNewIntent()}.
    ++Aktivitas baru akan mendapatkan intent dan membuat dokumen baru di layar ikhtisar, seperti dalam
    ++contoh berikut:</p>
    ++
    ++<p class="code-caption"><a href="{@docRoot}samples/DocumentCentricApps/index.html">
    ++NewDocumentActivity.java</a></p>
    ++<pre>
    ++&#64;Override
    ++protected void onCreate(Bundle savedInstanceState) {
    ++    super.onCreate(savedInstanceState);
    ++    setContentView(R.layout.activity_new_document);
    ++    mDocumentCount = getIntent()
    ++            .getIntExtra(DocumentCentricActivity.KEY_EXTRA_NEW_DOCUMENT_COUNTER, 0);
    ++    mDocumentCounterTextView = (TextView) findViewById(
    ++            R.id.hello_new_document_text_view);
    ++    setDocumentCounterText(R.string.hello_new_document_counter);
    ++}
    ++
    ++&#64;Override
    ++protected void onNewIntent(Intent intent) {
    ++    super.onNewIntent(intent);
    ++    /* If FLAG_ACTIVITY_MULTIPLE_TASK has not been used, this activity
    ++    is reused to create a new document.
    ++     */
    ++    setDocumentCounterText(R.string.reusing_document_counter);
    ++}
    ++</pre>
    ++
    ++
    ++<h3 id="#attr-doclaunch">Menggunakan atribut Aktivitas untuk menambahkan tugas</h3>
    ++
    ++<p>Aktivitas juga dapat menetapkan dalam manifesnya agar selalu dimulai ke dalam tugas baru dengan menggunakan
    ++atribut <code><a href="{@docRoot}guide/topics/manifest/activity-element.html">&lt;activity&gt;</a></code>
    ++, <a href="{@docRoot}guide/topics/manifest/activity-element.html#dlmode">
    ++{@code android:documentLaunchMode}</a>. Atribut ini memiliki empat nilai yang menghasilkan efek berikut
    ++bila pengguna membuka dokumen dengan aplikasi:</p>
    ++
    ++<dl>
    ++  <dt>"{@code intoExisting}"</dt>
    ++  <dd>Aktivitas menggunakan kembali tugas yang ada untuk dokumen tersebut. Ini sama dengan mengatur flag
    ++ {@link android.content.Intent#FLAG_ACTIVITY_NEW_DOCUMENT} <em>tanpa</em> mengatur flag
    ++ {@link android.content.Intent#FLAG_ACTIVITY_MULTIPLE_TASK}, seperti dijelaskan dalam
    ++ <a href="#flag-new-doc">Menggunakan flag Intent untuk menambahkan tugas</a>, di atas.</dd>
    ++
    ++  <dt>"{@code always}"</dt>
    ++  <dd>Aktivitas ini membuat tugas baru untuk dokumen, meski dokumen sudah dibuka. Menggunakan
    ++ nilai ini sama dengan menetapkan flag {@link android.content.Intent#FLAG_ACTIVITY_NEW_DOCUMENT}
    ++ maupun {@link android.content.Intent#FLAG_ACTIVITY_MULTIPLE_TASK}.</dd>
    ++
    ++  <dt>"{@code none”}"</dt>
    ++  <dd>Aktivitas ini tidak membuat tugas baru untuk dokumen. Layar ikhtisar memperlakukan
    ++ aktivitas seperti itu secara default: satu tugas ditampilkan untuk aplikasi, yang
    ++dilanjutkan dari aktivitas apa pun yang terakhir dipanggil pengguna.</dd>
    ++
    ++  <dt>"{@code never}"</dt>
    ++  <dd>Aktivitas ini tidak membuat tugas baru untuk dokumen. Mengatur nilai ini akan mengesampingkan
    ++ perilaku flag {@link android.content.Intent#FLAG_ACTIVITY_NEW_DOCUMENT}
    ++ dan {@link android.content.Intent#FLAG_ACTIVITY_MULTIPLE_TASK}, jika salah satunya ditetapkan di
    ++intent, dan layar ikhtisar menampilkan satu tugas untuk aplikasi, yang dilanjutkan dari
    ++ aktivitas apa pun yang terakhir dipanggil pengguna.</dd>
    ++</dl>
    ++
    ++<p class="note"><strong>Catatan:</strong> Untuk nilai selain {@code none} dan {@code never},
    ++aktivitas harus didefinisikan dengan {@code launchMode="standard"}. Jika atribut ini tidak ditetapkan, maka
    ++{@code documentLaunchMode="none"} akan digunakan.</p>
    ++
    ++<h2 id="removing">Menghapus Tugas</h2>
    ++
    ++<p>Secara default, tugas dokumen secara otomatis dihapus dari layar ikhtisar bila aktivitasnya
    ++selesai. Anda bisa mengesampingkan perilaku ini dengan kelas {@link android.app.ActivityManager.AppTask},
    ++dengan flag {@link android.content.Intent} atau atribut <code><a href="{@docRoot}guide/topics/manifest/activity-element.html">
    ++&lt;activity&gt;</a></code>.</p>
    ++
    ++<p>Kapan saja Anda bisa mengecualikan tugas dari layar ikhtisar secara keseluruhan dengan menetapkan atribut
    ++<code><a href="{@docRoot}guide/topics/manifest/activity-element.html">&lt;activity&gt;</a></code>
    ++, <a href="{@docRoot}guide/topics/manifest/activity-element.html#exclude">
    ++{@code android:excludeFromRecents}</a> hingga {@code true}.</p>
    ++
    ++<p>Anda bisa menetapkan jumlah maksimum tugas yang dapat disertakan aplikasi Anda dalam layar ikhtisar dengan menetapkan
    ++atribut <code><a href="{@docRoot}guide/topics/manifest/activity-element.html">&lt;activity&gt;</a></code>
    ++ <a href="{@docRoot}guide/topics/manifest/activity-element.html#maxrecents">{@code android:maxRecents}
    ++</a> ke satu nilai integer. Nilai default-nya adalah 16. Bila telah mencapai jumlah maksimum, tugas yang terakhir
    ++digunakan akan dihapus dari layar ikhtisar. Nilai maksimum {@code android:maxRecents}
    ++ adalah 50 (25 pada perangkat dengan memori sedikit); nilai yang kurang dari 1 tidak berlaku.</p>
    ++
    ++<h3 id="#apptask-remove">Menggunakan kelas AppTask untuk menghapus tugas</h3>
    ++
    ++<p>Dalam aktivitas yang membuat tugas baru di layar ikhtisar, Anda bisa
    ++menetapkan kapan menghapus tugas dan menyelesaikan semua aktivitas yang terkait dengannya
    ++dengan memanggil metode {@link android.app.ActivityManager.AppTask#finishAndRemoveTask() finishAndRemoveTask()}.</p>
    ++
    ++<p class="code-caption"><a href="{@docRoot}samples/DocumentCentricApps/index.html">
    ++NewDocumentActivity.java</a></p>
    ++<pre>
    ++public void onRemoveFromRecents(View view) {
    ++    // The document is no longer needed; remove its task.
    ++    finishAndRemoveTask();
    ++}
    ++</pre>
    ++
    ++<p class="note"><strong>Catatan:</strong> Penggunaan metode
    ++{@link android.app.ActivityManager.AppTask#finishAndRemoveTask() finishAndRemoveTask()}
    ++akan mengesampingkan penggunaan tag {@link android.content.Intent#FLAG_ACTIVITY_RETAIN_IN_RECENTS}, seperti
    ++dibahas di bawah ini.</p>
    ++
    ++<h3 id="#retain-finished">Mempertahankan tugas yang telah selesai</h3>
    ++
    ++<p>Jika Anda ingin mempertahankan tugas di layar ikhtisar, sekalipun aktivitas sudah selesai, teruskan
    ++flag {@link android.content.Intent#FLAG_ACTIVITY_RETAIN_IN_RECENTS} dalam metode
    ++{@link android.content.Intent#addFlags(int) addFlags()} dari Intent yang memulai aktivitas itu.</p>
    ++
    ++<p class="code-caption"><a href="{@docRoot}samples/DocumentCentricApps/index.html">
    ++DocumentCentricActivity.java</a></p>
    ++<pre>
    ++private Intent newDocumentIntent() {
    ++    final Intent newDocumentIntent = new Intent(this, NewDocumentActivity.class);
    ++    newDocumentIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_DOCUMENT |
    ++      android.content.Intent.FLAG_ACTIVITY_RETAIN_IN_RECENTS);
    ++    newDocumentIntent.putExtra(KEY_EXTRA_NEW_DOCUMENT_COUNTER, incrementAndGet());
    ++    return newDocumentIntent;
    ++}
    ++</pre>
    ++
    ++<p>Untuk memperoleh efek yang sama, tetapkan atribut
    ++<code><a href="{@docRoot}guide/topics/manifest/activity-element.html">&lt;activity&gt;</a></code>
    ++ <a href="{@docRoot}guide/topics/manifest/activity-element.html#autoremrecents">
    ++{@code android:autoRemoveFromRecents}</a> hingga {@code false}. Nilai default-nya adalah {@code true}
    ++untuk aktivitas dokumen, dan {@code false} untuk aktivitas biasa. Penggunaan atribut ini akan mengesampingkan flag
    ++{@link android.content.Intent#FLAG_ACTIVITY_RETAIN_IN_RECENTS}, yang telah dibahas sebelumnya.</p>
    ++
    ++
    ++
    ++
    ++
    ++
    ++
    +diff --git a/docs/html-intl/intl/id/guide/components/services.jd b/docs/html-intl/intl/id/guide/components/services.jd
    +new file mode 100644
    +index 0000000..b36e565
    +--- /dev/null
    ++++ b/docs/html-intl/intl/id/guide/components/services.jd
    +@@ -0,0 +1,813 @@
    ++page.title=Layanan
    ++@jd:body
    ++
    ++<div id="qv-wrapper">
    ++<ol id="qv">
    ++<h2>Dalam dokumen ini</h2>
    ++<ol>
    ++<li><a href="#Basics">Dasar-Dasar</a></li>
    ++<ol>
    ++  <li><a href="#Declaring">Mendeklarasikan layanan dalam manifes</a></li>
    ++</ol>
    ++<li><a href="#CreatingAService">Membuat Layanan yang Sudah Dimulai</a>
    ++  <ol>
    ++    <li><a href="#ExtendingIntentService">Memperluas kelas IntentService</a></li>
    ++    <li><a href="#ExtendingService">Memperluas kelas Layanan</a></li>
    ++    <li><a href="#StartingAService">Memulai layanan</a></li>
    ++    <li><a href="#Stopping">Menghentikan layanan</a></li>
    ++  </ol>
    ++</li>
    ++<li><a href="#CreatingBoundService">Membuat Layanan Terikat</a></li>
    ++<li><a href="#Notifications">Mengirim Pemberitahuan ke Pengguna</a></li>
    ++<li><a href="#Foreground">Menjalankan Layanan di Latar Depan</a></li>
    ++<li><a href="#Lifecycle">Mengelola Daur Hidup Layanan</a>
    ++<ol>
    ++  <li><a href="#LifecycleCallbacks">Mengimplementasikan callback daur hidup</a></li>
    ++</ol>
    ++</li>
    ++</ol>
    ++
    ++<h2>Kelas-kelas utama</h2>
    ++<ol>
    ++  <li>{@link android.app.Service}</li>
    ++  <li>{@link android.app.IntentService}</li>
    ++</ol>
    ++
    ++<h2>Contoh</h2>
    ++<ol>
    ++  <li><a href="{@docRoot}resources/samples/ApiDemos/src/com/example/android/apis/app/ServiceStartArguments.html">{@code
    ++      ServiceStartArguments}</a></li>
    ++  <li><a href="{@docRoot}resources/samples/ApiDemos/src/com/example/android/apis/app/LocalService.html">{@code
    ++      LocalService}</a></li>
    ++</ol>
    ++
    ++<h2>Lihat juga</h2>
    ++<ol>
    ++<li><a href="{@docRoot}guide/components/bound-services.html">Layanan Terikat</a></li>
    ++</ol>
    ++
    ++</div>
    ++
    ++
    ++<p>{@link android.app.Service} adalah sebuah komponen aplikasi yang bisa melakukan
    ++operasi yang berjalan lama di latar belakang dan tidak menyediakan antarmuka pengguna. Komponen
    ++aplikasi lain bisa memulai layanan dan komponen aplikasi tersebut akan terus berjalan
    ++di latar belakang walaupun pengguna beralih ke aplikasi lain. Selain itu, komponen bisa mengikat ke layanan
    ++untuk berinteraksi dengannya dan bahkan melakukan komunikasi antarproses (IPC). Misalnya, layanan mungkin
    ++menangani transaksi jaringan, memutar musik, melakukan file I/O, atau berinteraksi dengan penyedia konten
    ++dari latar belakang.</p>
    ++
    ++<p>Ada dua bentuk dasar layanan:</p>
    ++
    ++<dl>
    ++  <dt>Sudah Dimulai</dt>
    ++  <dd>Layanan "sudah dimulai" bila komponen aplikasi (misalnya aktivitas) memulainya dengan
    ++memanggil {@link android.content.Context#startService startService()}. Sesudah dimulai, layanan
    ++bisa berjalan terus-menerus di latar belakang walaupun komponen yang memulainya telah dimusnahkan. Biasanya,
    ++layanan yang sudah dimulai akan melakukan operasi tunggal dan tidak mengembalikan hasil ke pemanggilnya.
    ++Misalnya, layanan bisa mengunduh atau mengunggah file melalui jaringan. Bila operasi selesai,
    ++layanan seharusnya berhenti sendiri.</dd>
    ++  <dt>Terikat</dt>
    ++  <dd>Layanan "terikat" bila komponen aplikasi mengikat kepadanya dengan memanggil {@link
    ++android.content.Context#bindService bindService()}. Layanan terikat menawarkan antarmuka
    ++klien-server yang memungkinkan komponen berinteraksi dengan layanan tersebut, mengirim permintaan, mendapatkan hasil dan bahkan
    ++melakukannya pada sejumlah proses dengan komunikasi antarproses (IPC). Layanan terikat hanya berjalan selama
    ++ada komponen aplikasi lain yang terikat padanya. Sejumlah komponen bisa terikat pada layanan secara bersamaan,
    ++namun bila semuanya melepas ikatan, layanan tersebut akan dimusnahkan.</dd>
    ++</dl>
    ++
    ++<p>Walaupun dokumentasi ini secara umum membahas kedua jenis layanan secara terpisah, layanan
    ++Anda bisa menggunakan keduanya&mdash;layanan bisa dimulai (untuk berjalan terus-menerus) sekaligus memungkinkan pengikatan.
    ++Cukup mengimplementasikan dua metode callback: {@link
    ++android.app.Service#onStartCommand onStartCommand()} untuk memungkinkan komponen memulainya dan {@link
    ++android.app.Service#onBind onBind()} untuk memungkinkan pengikatan.</p>
    ++
    ++<p>Apakah aplikasi Anda sudah dimulai, terikat, atau keduanya, semua komponen aplikasi
    ++bisa menggunakan layanan (bahkan dari aplikasi terpisah), demikian pula semua komponen bisa menggunakan
    ++suatu aktivitas&mdash;dengan memulainya dengan {@link android.content.Intent}. Akan tetapi, Anda bisa mendeklarasikan
    ++layanan sebagai privat, pada file manifes, dan memblokir akses dari aplikasi lain. Hal ini
    ++dibahas selengkapnya di bagian tentang <a href="#Declaring">Mendeklarasikan layanan dalam
    ++manifes</a>.</p>
    ++
    ++<p class="caution"><strong>Perhatian:</strong> Layanan berjalan di
    ++thread utama proses yang menjadi host-nya&mdash;layanan <strong>tidak</strong> membuat thread-nya sendiri
    ++dan <strong>tidak</strong> berjalan pada proses terpisah (kecuali bila Anda tentukan demikian). Artinya,
    ++jika layanan Anda akan melakukan pekerjaan yang membutuhkan tenaga CPU besar atau operasi yang memblokir (seperti
    ++pemutaran MP3 atau jaringan), Anda perlu membuat thread baru dalam layanan untuk melakukan pekerjaan tersebut. Dengan menggunakan
    ++thread terpisah, Anda mengurangi risiko terjadinya kesalahan Aplikasi Tidak Merespons (Application Not Responding/ANR) dan
    ++thread utama aplikasi bisa tetap dikhususkan pada interaksi pengguna dengan aktivitas Anda.</p>
    ++
    ++
    ++<h2 id="Basics">Dasar-Dasar</h2>
    ++
    ++<div class="sidebox-wrapper">
    ++<div class="sidebox">
    ++  <h3>Haruskah menggunakan layanan atau thread?</h3>
    ++  <p>Layanan sekadar komponen yang bisa berjalan di latar belakang walaupun pengguna sedang tidak
    ++berinteraksi dengan aplikasi Anda. Sehingga, Anda harus membuat layanan bila memang itu
    ++yang dibutuhkan.</p>
    ++  <p>Bila Anda perlu melakukan pekerjaan di luar thread utama, namun hanya bila pengguna sedang berinteraksi
    ++dengan aplikasi, maka Anda harus membuat thread baru sebagai ganti layanan baru. Misalnya,
    ++bila Anda ingin memutar musik, namun hanya saat aktivitas Anda berjalan, Anda bisa membuat
    ++thread dalam {@link android.app.Activity#onCreate onCreate()}, mulai menjalankannya di {@link
    ++android.app.Activity#onStart onStart()}, kemudian menghentikannya di {@link android.app.Activity#onStop
    ++onStop()}. Pertimbangkan juga untuk menggunakan {@link android.os.AsyncTask} atau {@link android.os.HandlerThread},
    ++sebagai ganti kelas {@link java.lang.Thread} yang lazim digunakan. Lihat dokumen <a href="{@docRoot}guide/components/processes-and-threads.html#Threads">Proses dan
    ++Threading</a> untuk informasi selengkapnya tentang thread.</p>
    ++  <p>Ingatlah jika menggunakan layanan, layanan tersebut tetap berjalan di thread utama aplikasi Anda secara
    ++default, jadi Anda harus tetap membuat thread baru dalam layanan bila layanan tersebut melakukan operasi yang intensif
    ++atau operasi yang memblokir.</p>
    ++</div>
    ++</div>
    ++
    ++<p>Untuk membuat layanan, Anda harus membuat subkelas {@link android.app.Service} (atau
    ++salah satu dari subkelasnya yang ada). Dalam implementasi, Anda perlu mengesampingkan sebagian metode callback yang
    ++menangani aspek utama daur hidup layanan dan memberikan mekanisme bagi komponen untuk mengikat
    ++pada layanan, bila dibutuhkan. Metode callback terpenting yang perlu Anda kesampingkan adalah:</p>
    ++
    ++<dl>
    ++  <dt>{@link android.app.Service#onStartCommand onStartCommand()}</dt>
    ++    <dd>Sistem akan memanggil metode ini bila komponen lain, misalnya aktivitas,
    ++meminta dimulainya layanan, dengan memanggil {@link android.content.Context#startService
    ++startService()}. Setelah metode ini dieksekusi, layanan akan dimulai dan bisa berjalan di
    ++latar belakang terus-menerus. Jika mengimplementasikan ini, Anda bertanggung jawab menghentikan layanan bila
    ++bila pekerjaannya selesai, dengan memanggil {@link android.app.Service#stopSelf stopSelf()} atau {@link
    ++android.content.Context#stopService stopService()}. (Jika hanya ingin menyediakan pengikatan, Anda tidak
    ++perlu mengimplementasikan metode ini.)</dd>
    ++  <dt>{@link android.app.Service#onBind onBind()}</dt>
    ++    <dd>Sistem akan memanggil metode ini bila komponen lain ingin mengikat pada
    ++layanan (misalnya untuk melakukan RPC), dengan memanggil {@link android.content.Context#bindService
    ++bindService()}. Dalam mengimplementasikan metode ini, Anda harus menyediakan antarmuka yang digunakan
    ++klien untuk berkomunikasi dengan layanan, dengan mengembalikan {@link android.os.IBinder}. Anda harus selalu
    ++mengimplementasikan metode ini, namun jika tidak ingin mengizinkan pengikatan, Anda perlu mengembalikan null.</dd>
    ++  <dt>{@link android.app.Service#onCreate()}</dt>
    ++    <dd>Sistem memanggil metode ini bila layanan dibuat untuk pertama kalinya, untuk melakukan prosedur
    ++penyiapan satu kali (sebelum memanggil {@link android.app.Service#onStartCommand onStartCommand()} atau
    ++{@link android.app.Service#onBind onBind()}). Bila layanan sudah berjalan, metode ini tidak
    ++dipanggil.</dd>
    ++  <dt>{@link android.app.Service#onDestroy()}</dt>
    ++    <dd>Sistem memanggil metode ini bila layanan tidak lagi digunakan dan sedang dimusnahkan.
    ++Layanan Anda perlu mengimplementasikannya untuk membersihkan sumber daya seperti thread, listener
    ++terdaftar, penerima, dll. Ini adalah panggilan terakhir yang diterima layanan.</dd>
    ++</dl>
    ++
    ++<p>Bila komponen memulai layanan dengan memanggil {@link
    ++android.content.Context#startService startService()} (yang menyebabkan panggilan ke {@link
    ++android.app.Service#onStartCommand onStartCommand()}), maka layanan
    ++terus berjalan hingga terhenti sendiri dengan {@link android.app.Service#stopSelf()} atau bila komponen
    ++lain menghentikannya dengan memanggil {@link android.content.Context#stopService stopService()}.</p>
    ++
    ++<p>Bila komponen memanggil
    ++{@link android.content.Context#bindService bindService()} untuk membuat layanan (dan {@link
    ++android.app.Service#onStartCommand onStartCommand()} <em>tidak</em> dipanggil), maka layanan hanya berjalan
    ++selama komponen terikat kepadanya. Setelah layanan dilepas ikatannya dari semua klien,
    ++sistem akan menghancurkannya.</p>
    ++
    ++<p>Sistem Android akan menghentikan paksa layanan hanya bila memori tinggal sedikit dan sistem harus memulihkan
    ++sumber daya sistem untuk aktivitas yang mendapatkan fokus pengguna. Jika layanan terikat pada suatu aktivitas yang mendapatkan
    ++fokus pengguna, layanan tersebut lebih kecil kemungkinannya untuk dimatikan, dan jika layanan dideklarasikan untuk <a href="#Foreground">berjalan di latar depan</a> (akan dibahas kemudian), maka sudah hampir pasti ia tidak akan dimatikan.
    ++Sebaliknya, bila layanan sudah dimulai dan berjalan lama, maka sistem akan menurunkan posisinya
    ++dalam daftar tugas latar belakang seiring waktu dan layanan akan sangat rentan untuk
    ++dimatikan&mdash;bila layanan Anda dimulai, maka Anda harus mendesainnya agar bisa menangani restart
    ++oleh sistem dengan baik. Jika sistem mematikan layanan Anda, layanan akan dimulai kembali begitu sumber daya
    ++kembali tersedia (tetapi ini juga bergantung pada nilai yang Anda kembalikan dari {@link
    ++android.app.Service#onStartCommand onStartCommand()}, sebagaimana akan dibahas nanti). Untuk informasi selengkapnya
    ++tentang kapan sistem mungkin akan memusnahkan layanan, lihat dokumen
    ++<a href="{@docRoot}guide/components/processes-and-threads.html">Proses dan Threading</a>.</p>
    ++
    ++<p>Dalam bagian selanjutnya, Anda akan melihat bagaimana membuat masing-masing tipe layanan dan cara menggunakannya
    ++dari komponen aplikasi lain.</p>
    ++
    ++
    ++
    ++<h3 id="Declaring">Mendeklarasikan layanan dalam manifes</h3>
    ++
    ++<p>Sebagaimana aktivitas (dan komponen lainnya), Anda harus mendeklarasikan semua layanan dalam file manifes
    ++aplikasi Anda.</p>
    ++
    ++<p>Untuk mendeklarasikan layanan Anda, tambahkan sebuah elemen <a href="{@docRoot}guide/topics/manifest/service-element.html">{@code &lt;service&gt;}</a>
    ++sebagai anak
    ++elemen <a href="{@docRoot}guide/topics/manifest/application-element.html">{@code &lt;application&gt;}</a>. Misalnya:</p>
    ++
    ++<pre>
    ++&lt;manifest ... &gt;
    ++  ...
    ++  &lt;application ... &gt;
    ++      &lt;service android:name=".ExampleService" /&gt;
    ++      ...
    ++  &lt;/application&gt;
    ++&lt;/manifest&gt;
    ++</pre>
    ++
    ++<p>Lihat acuan elemen <a href="{@docRoot}guide/topics/manifest/service-element.html">{@code &lt;service&gt;}</a>
    ++untuk informasi selengkapnya tentang cara mendeklarasikan layanan Anda dalam manifes.</p>
    ++
    ++<p>Ada atribut lain yang bisa Anda sertakan dalam elemen <a href="{@docRoot}guide/topics/manifest/service-element.html">{@code &lt;service&gt;}</a> untuk
    ++mendefinisikan properti seperti izin yang dibutuhkan untuk memulai layanan dan proses
    ++tempat berjalannya layanan. <a href="{@docRoot}guide/topics/manifest/service-element.html#nm">{@code android:name}</a> adalah satu-satunya atribut yang diperlukan
    ++&mdash;atribut tersebut menetapkan nama kelas layanan. Setelah
    ++mempublikasikan aplikasi, Anda tidak boleh mengubah nama ini, karena jika melakukannya, Anda bisa merusak
    ++kode karena dependensi terhadap intent eksplisit untuk memulai atau mengikat layanan (bacalah posting blog berjudul <a href="http://android-developers.blogspot.com/2011/06/things-that-cannot-change.html">Things
    ++That Cannot Change</a>).
    ++
    ++<p>Untuk memastikan aplikasi Anda aman, <strong>selalu gunakan intent eksplisit saat memulai atau mengikat
    ++{@link android.app.Service} Anda</strong> dan jangan mendeklarasikan filter intent untuk layanan. Jika
    ++Anda perlu membiarkan adanya ambiguitas tentang layanan mana yang dimulai, Anda bisa
    ++menyediakan filter intent bagi layanan dan tidak memasukkan nama komponen pada {@link
    ++android.content.Intent}, namun Anda juga harus menyesuaikan paket bagi intent tersebut dengan {@link
    ++android.content.Intent#setPackage setPackage()}, yang memberikan klarifikasi memadai bagi
    ++target layanan.</p>
    ++
    ++<p>Anda juga bisa memastikan layanan tersedia hanya bagi aplikasi Anda dengan
    ++menyertakan atribut <a href="{@docRoot}guide/topics/manifest/service-element.html#exported">{@code android:exported}</a>
    ++dan mengaturnya ke {@code "false"}. Hal ini efektif menghentikan aplikasi lain agar tidak memulai
    ++layanan Anda, bahkan saat menggunakan intent eksplisit.</p>
    ++
    ++
    ++
    ++
    ++<h2 id="CreatingStartedService">Membuat Layanan yang Sudah Dimulai</h2>
    ++
    ++<p>Layanan yang sudah dimulai adalah layanan yang dimulai komponen lain dengan memanggil {@link
    ++android.content.Context#startService startService()}, yang menyebabkan panggilan ke metode
    ++{@link android.app.Service#onStartCommand onStartCommand()} layanan.</p>
    ++
    ++<p>Bila layanan sudah dimulai, layanan tersebut memiliki daur hidup yang tidak bergantung pada
    ++komponen yang memulainya dan bisa berjalan terus-menerus di latar belakang walaupun
    ++komponen yang memulainya dimusnahkan. Dengan sendirinya, layanan akan berhenti sendiri bila pekerjaannya
    ++selesai dengan memanggil {@link android.app.Service#stopSelf stopSelf()}, atau komponen lain bisa menghentikannya
    ++dengan memanggil {@link android.content.Context#stopService stopService()}.</p>
    ++
    ++<p>Komponen aplikasi seperti aktivitas bisa memulai layanan dengan memanggil {@link
    ++android.content.Context#startService startService()} dan meneruskan {@link android.content.Intent}
    ++yang menetapkan layanan dan menyertakan data untuk digunakan layanan. Layanan menerima
    ++{@link android.content.Intent} ini dalam metode {@link android.app.Service#onStartCommand
    ++onStartCommand()}.</p>
    ++
    ++<p>Sebagai contoh, anggaplah aktivitas perlu menyimpan data ke database online. Aktivitas tersebut bisa
    ++memulai layanan pendamping dan mengiriminya data untuk disimpan dengan meneruskan intent ke {@link
    ++android.content.Context#startService startService()}. Layanan akan menerima intent dalam {@link
    ++android.app.Service#onStartCommand onStartCommand()}, menghubungkan ke Internet dan melakukan
    ++transaksi database. Bila transaksi selesai, layanan akan berhenti sendiri dan
    ++dimusnahkan.</p>
    ++
    ++<p class="caution"><strong>Perhatian:</strong> Layanan berjalan dalam proses yang sama dengan aplikasi
    ++tempatnya dideklarasikan dan dalam thread utama aplikasi tersebut, secara default. Jadi, bila layanan Anda
    ++melakukan operasi yang intensif atau operasi pemblokiran saat pengguna berinteraksi dengan aktivitas dari
    ++aplikasi yang sama, layanan akan memperlambat kinerja aktivitas. Agar tidak memengaruhi
    ++kinerja aplikasi, Anda harus memulai thread baru di dalam layanan.</p>
    ++
    ++<p>Biasanya, ada dua kelas yang bisa Anda perluas untuk membuat layanan yang sudah dimulai:</p>
    ++<dl>
    ++  <dt>{@link android.app.Service}</dt>
    ++  <dd>Ini adalah kelas dasar untuk semua layanan. Bila memperluas kelas ini, Anda perlu
    ++membuat thread baru sebagai tempat melaksanakan semua pekerjaan layanan tersebut, karena layanan
    ++menggunakan thread utama aplikasi Anda secara default, dan hal ini bisa memperlambat
    ++kinerja aktivitas yang dijalankan aplikasi Anda.</dd>
    ++  <dt>{@link android.app.IntentService}</dt>
    ++  <dd>Ini adalah subkelas {@link android.app.Service} yang menggunakan thread pekerja untuk menangani
    ++semua permintaan memulai, satu per satu. Ini adalah pilihan terbaik jika Anda tidak mengharuskan layanan
    ++menangani beberapa permintaan sekaligus. Anda cukup mengimplementasikan {@link
    ++android.app.IntentService#onHandleIntent onHandleIntent()}, yang menerima intent untuk setiap
    ++permintaan memulai agar bisa melakukan pekerjaan latar belakang.</dd>
    ++</dl>
    ++
    ++<p>Bagian selanjutnya membahas cara mengimplementasikan layanan Anda menggunakan
    ++salah satu dari kelas-kelas ini.</p>
    ++
    ++
    ++<h3 id="ExtendingIntentService">Memperluas kelas IntentService</h3>
    ++
    ++<p>Mengingat kebanyakan layanan yang sudah dimulai tidak perlu menangani beberapa permintaan
    ++sekaligus (yang bisa berupa skenario multi-threading berbahaya), mungkin Anda sebaiknya mengimplementasikan
    ++layanan menggunakan kelas {@link android.app.IntentService}.</p>
    ++
    ++<p>Berikut ini yang dilakukan {@link android.app.IntentService}:</p>
    ++
    ++<ul>
    ++  <li>Membuat thread pekerja default yang menjalankan semua intent yang disampaikan ke {@link
    ++android.app.Service#onStartCommand onStartCommand()} terpisah dari thread utama aplikasi
    ++Anda.</li>
    ++  <li>Membuat antrean pekerjaan yang meneruskan intent satu per satu ke implementasi {@link
    ++android.app.IntentService#onHandleIntent onHandleIntent()}, sehingga Anda tidak perlu
    ++mengkhawatirkan multi-threading.</li>
    ++  <li>Menghentikan layanan setelah semua permintaan memulai telah ditangani, jadi Anda tidak perlu memanggil
    ++{@link android.app.Service#stopSelf}.</li>
    ++  <li>Menyediakan implementasi default {@link android.app.IntentService#onBind onBind()} yang
    ++mengembalikan null.</li>
    ++  <li>Menyediakan implementasi default {@link android.app.IntentService#onStartCommand
    ++onStartCommand()} yang mengirimkan intent ke antrean pekerjaan kemudian ke implementasi {@link
    ++android.app.IntentService#onHandleIntent onHandleIntent()} Anda.</li>
    ++</ul>
    ++
    ++<p>Oleh karena itu, Anda hanya perlu mengimplementasikan {@link
    ++android.app.IntentService#onHandleIntent onHandleIntent()} untuk melakukan pekerjaan yang diberikan oleh
    ++klien. (Akan tetapi, Anda juga perlu menyediakan konstruktor kecil bagi layanan.)</p>
    ++
    ++<p>Berikut ini contoh implementasi {@link android.app.IntentService}:</p>
    ++
    ++<pre>
    ++public class HelloIntentService extends IntentService {
    ++
    ++  /**
    ++   * A constructor is required, and must call the super {@link android.app.IntentService#IntentService}
    ++   * constructor with a name for the worker thread.
    ++   */
    ++  public HelloIntentService() {
    ++      super("HelloIntentService");
    ++  }
    ++
    ++  /**
    ++   * The IntentService calls this method from the default worker thread with
    ++   * the intent that started the service. When this method returns, IntentService
    ++   * stops the service, as appropriate.
    ++   */
    ++  &#64;Override
    ++  protected void onHandleIntent(Intent intent) {
    ++      // Normally we would do some work here, like download a file.
    ++      // For our sample, we just sleep for 5 seconds.
    ++      long endTime = System.currentTimeMillis() + 5*1000;
    ++      while (System.currentTimeMillis() &lt; endTime) {
    ++          synchronized (this) {
    ++              try {
    ++                  wait(endTime - System.currentTimeMillis());
    ++              } catch (Exception e) {
    ++              }
    ++          }
    ++      }
    ++  }
    ++}
    ++</pre>
    ++
    ++<p>Anda hanya memerlukan: konstruktor dan implementasi {@link
    ++android.app.IntentService#onHandleIntent onHandleIntent()}.</p>
    ++
    ++<p>Jika Anda memutuskan untuk juga mengesampingkan metode callback lain, seperti {@link
    ++android.app.IntentService#onCreate onCreate()}, {@link
    ++android.app.IntentService#onStartCommand onStartCommand()}, atau {@link
    ++android.app.IntentService#onDestroy onDestroy()}, pastikan memanggil implementasi super, sehingga
    ++{@link android.app.IntentService} bisa menangani hidup thread pekerja dengan baik.</p>
    ++
    ++<p>Misalnya, {@link android.app.IntentService#onStartCommand onStartCommand()} harus mengembalikan
    ++implementasi default (yang merupakan cara penyampaian intent ke {@link
    ++android.app.IntentService#onHandleIntent onHandleIntent()}):</p>
    ++
    ++<pre>
    ++&#64;Override
    ++public int onStartCommand(Intent intent, int flags, int startId) {
    ++    Toast.makeText(this, "service starting", Toast.LENGTH_SHORT).show();
    ++    return super.onStartCommand(intent,flags,startId);
    ++}
    ++</pre>
    ++
    ++<p>Selain {@link android.app.IntentService#onHandleIntent onHandleIntent()}, satu-satunya metode lain
    ++yang tidak mengharuskan Anda memanggil super kelas adalah {@link android.app.IntentService#onBind
    ++onBind()} (namun Anda hanya perlu mengimplementasikannya bila layanan mengizinkan pengikatan).</p>
    ++
    ++<p>Dalam bagian berikutnya, Anda akan melihat bagaimana layanan serupa diimplementasikan saat
    ++memperluas kelas {@link android.app.Service} basis, yang membutuhkan kode lebih banyak lagi, namun mungkin
    ++cocok jika Anda perlu menangani beberapa permintaan memulai sekaligus.</p>
    ++
    ++
    ++<h3 id="ExtendingService">Memperluas kelas Layanan</h3>
    ++
    ++<p>Seperti telah Anda lihat di bagian sebelumnya, menggunakan {@link android.app.IntentService} membuat
    ++implementasi layanan yang sudah dimulai jadi sangat sederhana. Namun, bila Anda mengharuskan layanan untuk
    ++melakukan multi-threading (sebagai ganti memproses permintaan memulai melalui antrean pekerjaan), maka Anda
    ++bisa memperluas kelas {@link android.app.Service} untuk menangani masing-masing intent.</p>
    ++
    ++<p>Sebagai perbandingan, contoh kode berikut ini adalah implementasi kelas {@link
    ++android.app.Service} yang melakukan pekerjaan yang persis sama dengan contoh di atas menggunakan {@link
    ++android.app.IntentService}. Artinya, untuk setiap permintaan memulai, kode tersebut akan menggunakan thread pekerja
    ++untuk melakukan pekerjaan dan memproses permintaan satu per satu.</p>
    ++
    ++<pre>
    ++public class HelloService extends Service {
    ++  private Looper mServiceLooper;
    ++  private ServiceHandler mServiceHandler;
    ++
    ++  // Handler that receives messages from the thread
    ++  private final class ServiceHandler extends Handler {
    ++      public ServiceHandler(Looper looper) {
    ++          super(looper);
    ++      }
    ++      &#64;Override
    ++      public void handleMessage(Message msg) {
    ++          // Normally we would do some work here, like download a file.
    ++          // For our sample, we just sleep for 5 seconds.
    ++          long endTime = System.currentTimeMillis() + 5*1000;
    ++          while (System.currentTimeMillis() &lt; endTime) {
    ++              synchronized (this) {
    ++                  try {
    ++                      wait(endTime - System.currentTimeMillis());
    ++                  } catch (Exception e) {
    ++                  }
    ++              }
    ++          }
    ++          // Stop the service using the startId, so that we don't stop
    ++          // the service in the middle of handling another job
    ++          stopSelf(msg.arg1);
    ++      }
    ++  }
    ++
    ++  &#64;Override
    ++  public void onCreate() {
    ++    // Start up the thread running the service.  Note that we create a
    ++    // separate thread because the service normally runs in the process's
    ++    // main thread, which we don't want to block.  We also make it
    ++    // background priority so CPU-intensive work will not disrupt our UI.
    ++    HandlerThread thread = new HandlerThread("ServiceStartArguments",
    ++            Process.THREAD_PRIORITY_BACKGROUND);
    ++    thread.start();
    ++
    ++    // Get the HandlerThread's Looper and use it for our Handler
    ++    mServiceLooper = thread.getLooper();
    ++    mServiceHandler = new ServiceHandler(mServiceLooper);
    ++  }
    ++
    ++  &#64;Override
    ++  public int onStartCommand(Intent intent, int flags, int startId) {
    ++      Toast.makeText(this, "service starting", Toast.LENGTH_SHORT).show();
    ++
    ++      // For each start request, send a message to start a job and deliver the
    ++      // start ID so we know which request we're stopping when we finish the job
    ++      Message msg = mServiceHandler.obtainMessage();
    ++      msg.arg1 = startId;
    ++      mServiceHandler.sendMessage(msg);
    ++
    ++      // If we get killed, after returning from here, restart
    ++      return START_STICKY;
    ++  }
    ++
    ++  &#64;Override
    ++  public IBinder onBind(Intent intent) {
    ++      // We don't provide binding, so return null
    ++      return null;
    ++  }
    ++
    ++  &#64;Override
    ++  public void onDestroy() {
    ++    Toast.makeText(this, "service done", Toast.LENGTH_SHORT).show();
    ++  }
    ++}
    ++</pre>
    ++
    ++<p>Seperti yang bisa Anda lihat, ini membutuhkan lebih banyak pekerjaan daripada menggunakan {@link android.app.IntentService}.</p>
    ++
    ++<p>Akan tetapi, karena Anda menangani sendiri setiap panggilan ke {@link android.app.Service#onStartCommand
    ++onStartCommand()}, Anda bisa melakukan beberapa permintaan sekaligus. Itu bukan yang
    ++dilakukan contoh ini, namun jika itu yang diinginkan, Anda bisa membuat thread baru untuk setiap
    ++permintaan dan langsung menjalankannya (sebagai ganti menunggu permintaan sebelumnya selesai).</p>
    ++
    ++<p>Perhatikan bahwa metode {@link android.app.Service#onStartCommand onStartCommand()} harus mengembalikan
    ++integer. Integer tersebut merupakan nilai yang menjelaskan cara sistem melanjutkan layanan dalam
    ++kejadian yang dimatikan oleh sistem (sebagaimana dibahas di atas, implementasi default {@link
    ++android.app.IntentService} menangani hal ini untuk Anda, walaupun Anda bisa memodifikasinya). Nilai yang dikembalikan
    ++dari {@link android.app.Service#onStartCommand onStartCommand()} harus berupa salah satu
    ++konstanta berikut ini:</p>
    ++
    ++<dl>
    ++  <dt>{@link android.app.Service#START_NOT_STICKY}</dt>
    ++    <dd>Jika sistem mematikan layanan setelah {@link android.app.Service#onStartCommand
    ++onStartCommand()} dikembalikan, <em>jangan</em> membuat lagi layanan tersebut, kecuali jika ada intent
    ++tertunda yang akan disampaikan. Inilah pilihan teraman untuk menghindari menjalankan layanan Anda
    ++bila tidak diperlukan dan bila aplikasi Anda bisa me-restart pekerjaan yang belum selesai.</dd>
    ++  <dt>{@link android.app.Service#START_STICKY}</dt>
    ++    <dd>Jika sistem mematikan layanan setelah {@link android.app.Service#onStartCommand
    ++onStartCommand()} dikembalikan, buat kembali layanan dan panggil {@link
    ++android.app.Service#onStartCommand onStartCommand()}, namun <em>jangan</em> menyampaikan ulang intent terakhir.
    ++Sebagai gantinya, sistem akan memanggil {@link android.app.Service#onStartCommand onStartCommand()} dengan
    ++intent null, kecuali jika ada intent tertunda untuk memulai layanan, dan dalam hal ini,
    ++intent tersebut disampaikan. Ini cocok bagi pemutar media (atau layanan serupa) yang tidak
    ++mengeksekusi perintah, namun berjalan terus-menerus dan menunggu pekerjaan.</dd>
    ++  <dt>{@link android.app.Service#START_REDELIVER_INTENT}</dt>
    ++    <dd>Jika sistem mematikan layanan setelah {@link android.app.Service#onStartCommand
    ++onStartCommand()} kembali, buat kembali layanan dan panggil {@link
    ++android.app.Service#onStartCommand onStartCommand()} dengan intent terakhir yang disampaikan ke
    ++layanan. Intent yang tertunda akan disampaikan pada gilirannya. Ini cocok bagi layanan yang
    ++aktif melakukan pekerjaan yang harus segera dilanjutkan, misalnya mengunduh file.</dd>
    ++</dl>
    ++<p>Untuk detail selengkapnya tentang nilai pengembalian ini, lihat dokumentasi acuan untuk setiap
    ++konstanta.</p>
    ++
    ++
    ++
    ++<h3 id="StartingAService">Memulai Layanan</h3>
    ++
    ++<p>Anda bisa memulai layanan dari aktivitas atau komponen aplikasi lain dengan meneruskan
    ++{@link android.content.Intent} (yang menetapkan layanan yang akan dimulai) ke {@link
    ++android.content.Context#startService startService()}. Sistem Android akan memanggil metode {@link
    ++android.app.Service#onStartCommand onStartCommand()} layanan dan meneruskan {@link
    ++android.content.Intent} padanya. (Jangan sekali-kali memanggil {@link android.app.Service#onStartCommand
    ++onStartCommand()} secara langsung.)</p>
    ++
    ++<p>Misalnya, aktivitas bisa memulai contoh layanan di bagian sebelumnya ({@code
    ++HelloSevice}) menggunakan intent eksplisit dengan {@link android.content.Context#startService
    ++startService()}:</p>
    ++
    ++<pre>
    ++Intent intent = new Intent(this, HelloService.class);
    ++startService(intent);
    ++</pre>
    ++
    ++<p>Metode {@link android.content.Context#startService startService()} segera kembali dan
    ++sistem Android akan memanggil metode {@link android.app.Service#onStartCommand
    ++onStartCommand()} layanan. Jika layanan belum berjalan, sistem mula-mula memanggil {@link
    ++android.app.Service#onCreate onCreate()}, kemudian memanggil {@link android.app.Service#onStartCommand
    ++onStartCommand()}.</p>
    ++
    ++<p>Jika layanan juga tidak menyediakan pengikatan, intent yang disampaikan dengan {@link
    ++android.content.Context#startService startService()} adalah satu-satunya mode komunikasi antara
    ++komponen aplikasi dan layanan. Akan tetapi, jika Anda ingin agar layanan mengirimkan hasilnya kembali, maka
    ++klien yang memulai layanan bisa membuat {@link android.app.PendingIntent} untuk siaran
    ++(dengan {@link android.app.PendingIntent#getBroadcast getBroadcast()}) dan menyampaikannya ke layanan
    ++dalam {@link android.content.Intent} yang memulai layanan. Layanan kemudian bisa menggunakan
    ++siaran untuk menyampaikan hasil.</p>
    ++
    ++<p>Beberapa permintaan untuk memulai layanan menghasilkan beberapa panggilan pula ke
    ++{@link android.app.Service#onStartCommand onStartCommand()} layanan. Akan tetapi, hanya satu permintaan untuk menghentikan
    ++layanan (dengan {@link android.app.Service#stopSelf stopSelf()} atau {@link
    ++android.content.Context#stopService stopService()}) dibutuhkan untuk menghentikannya.</p>
    ++
    ++
    ++<h3 id="Stopping">Menghentikan layanan</h3>
    ++
    ++<p>Layanan yang sudah dimulai harus mengelola daur hidupnya sendiri. Artinya, sistem tidak menghentikan atau
    ++memusnahkan layanan kecuali jika harus memulihkan memori sistem dan layanan
    ++terus berjalan setelah {@link android.app.Service#onStartCommand onStartCommand()} kembali. Jadi,
    ++layanan tersebut harus berhenti sendiri dengan memanggil {@link android.app.Service#stopSelf stopSelf()} atau
    ++komponen lain bisa menghentikannya dengan memanggil {@link android.content.Context#stopService stopService()}.</p>
    ++
    ++<p>Setelah diminta untuk berhenti dengan {@link android.app.Service#stopSelf stopSelf()} atau {@link
    ++android.content.Context#stopService stopService()}, sistem akan menghapus layanan
    ++secepatnya.</p>
    ++
    ++<p>Akan tetapi, bila layanan Anda menangani beberapa permintaan ke {@link
    ++android.app.Service#onStartCommand onStartCommand()} sekaligus, Anda tidak boleh menghentikan
    ++layanan bila Anda baru selesai memproses permintaan memulai, karena setelah itu mungkin Anda sudah menerima permintaan memulai
    ++yang baru (berhenti pada permintaan pertama akan menghentikan permintaan kedua). Untuk menghindari
    ++masalah ini, Anda bisa menggunakan {@link android.app.Service#stopSelf(int)} untuk memastikan bahwa permintaan
    ++Anda untuk menghentikan layanan selalu berdasarkan pada permintaan memulai terbaru. Artinya, bila Anda memanggil {@link
    ++android.app.Service#stopSelf(int)}, Anda akan meneruskan ID permintaan memulai (<code>startId</code>
    ++yang disampaikan ke {@link android.app.Service#onStartCommand onStartCommand()}) yang terkait dengan permintaan berhenti
    ++Anda. Kemudian jika layanan menerima permintaan memulai baru sebelum Anda bisa memanggil {@link
    ++android.app.Service#stopSelf(int)}, maka ID tidak akan sesuai dan layanan tidak akan berhenti.</p>
    ++
    ++<p class="caution"><strong>Perhatian:</strong> Aplikasi Anda perlu menghentikan layanannya
    ++bila selesai bekerja untuk menghindari pemborosan sumber daya sistem dan tenaga baterai. Jika perlu,
    ++komponen lain bisa menghentikan layanan secara eksplisit dengan memanggil {@link
    ++android.content.Context#stopService stopService()}. Bahkan jika Anda mengaktifkan pengikatan bagi layanan,
    ++Anda harus selalu menghentikan layanan sendiri jika layanan tersebut menerima panggilan ke {@link
    ++android.app.Service#onStartCommand onStartCommand()}.</p>
    ++
    ++<p>Untuk informasi selengkapnya tentang daur hidup layanan, lihat bagian di bawah ini tentang <a href="#Lifecycle">Mengelola Daur Hidup Layanan</a>.</p>
    ++
    ++
    ++
    ++<h2 id="CreatingBoundService">Membuat Layanan Terikat</h2>
    ++
    ++<p>Layanan terikat adalah layanan yang memungkinkan komponen aplikasi untuk mengikatnya dengan memanggil {@link
    ++android.content.Context#bindService bindService()} guna membuat koneksi yang berlangsung lama
    ++(dan umumnya tidak mengizinkan komponen untuk <em>memulainya</em> dengan memanggil {@link
    ++android.content.Context#startService startService()}).</p>
    ++
    ++<p>Anda sebaiknya membuat layanan terikat bila ingin berinteraksi dengan layanan dari aktivitas
    ++dan komponen lain dalam aplikasi Anda atau mengeskpos sebagian fungsionalitas aplikasi Anda ke
    ++ke aplikasi lain, melalui komunikasi antarproses (IPC).</p>
    ++
    ++<p>Untuk membuat layanan terikat, Anda harus mengimplementasikan metode callback {@link
    ++android.app.Service#onBind onBind()} untuk mengembalikan {@link android.os.IBinder} yang
    ++mendefinisikan antarmuka bagi komunikasi dengan layanan. Komponen aplikasi lain kemudian bisa memanggil
    ++{@link android.content.Context#bindService bindService()} untuk mengambil antarmuka dan
    ++mulai memanggil metode pada layanan. Layanan hanya hidup untuk melayani komponen aplikasi yang
    ++terikat padanya, jadi bila tidak ada komponen yang terikat pada layanan, sistem akan memusnahkannya
    ++(Anda <em>tidak</em> perlu menghentikan layanan terikat seperti halnya bila layanan dimulai
    ++melalui {@link android.app.Service#onStartCommand onStartCommand()}).</p>
    ++
    ++<p>Untuk membuat layanan terikat, hal yang perlu dilakukan pertama kali adalah mendefinisikan antarmuka yang menetapkan
    ++cara klien berkomunikasi dengan layanan. Antarmuka antara layanan
    ++dan klien ini harus berupa implementasi {@link android.os.IBinder} dan yang harus dikembalikan
    ++layanan Anda dari metode callback {@link android.app.Service#onBind
    ++onBind()}. Setelah menerima {@link android.os.IBinder}, klien bisa mulai
    ++berinteraksi dengan layanan melalui antarmuka tersebut.</p>
    ++
    ++<p>Beberapa klien bisa mengikat ke layanan sekaligus. Bila klien selesai berinteraksi dengan
    ++layanan, klien akan memanggil {@link android.content.Context#unbindService unbindService()} untuk melepas ikatan. Bila
    ++tidak ada klien yang terikat pada layanan, sistem akan menghapus layanan tersebut.</p>
    ++
    ++<p>Ada beberapa cara untuk mengimplementasikan layanan terikat dan implementasinya lebih
    ++rumit daripada layanan yang sudah dimulai, jadi layanan terikat dibahas dalam dokumen
    ++terpisah tentang <a href="{@docRoot}guide/components/bound-services.html">Layanan Terikat</a>.</p>
    ++
    ++
    ++
    ++<h2 id="Notifications">Mengirim Pemberitahuan ke Pengguna</h2>
    ++
    ++<p>Setelah berjalan, layanan bisa memberi tahu pengguna tentang suatu kejadian menggunakan <a href="{@docRoot}guide/topics/ui/notifiers/toasts.html">Pemberitahuan Toast</a> atau <a href="{@docRoot}guide/topics/ui/notifiers/notifications.html">Pemberitahuan Baris Status</a>.</p>
    ++
    ++<p>Pemberitahuan Toast adalah pesan yang muncul sebentar pada permukaan jendela saat ini
    ++kemudian menghilang, sementara pemberitahuan baris status memberikan ikon di baris status dengan
    ++pesan yang bisa dipilih oleh pengguna untuk melakukan suatu tindakan (misalnya memulai suatu aktivitas).</p>
    ++
    ++<p>Biasanya, pemberitahuan baris status adalah teknik terbaik bila ada pekerjaan latar belakang yang sudah selesai
    ++(misalnya file selesai
    ++diunduh) dan pengguna kini bisa menggunakannya. Bila pengguna memilih pemberitahuan dari
    ++tampilan diperluas, pemberitahuan akan bisa memulai aktivitas (misalnya menampilkan file yang baru diunduh).</p>
    ++
    ++<p>Lihat panduan pengembang <a href="{@docRoot}guide/topics/ui/notifiers/toasts.html">Pemberitahuan Toast</a> atau <a href="{@docRoot}guide/topics/ui/notifiers/notifications.html">Pemberitahuan Baris Status</a>
    ++untuk informasi selengkapnya.</p>
    ++
    ++
    ++
    ++<h2 id="Foreground">Menjalankan Layanan di Latar Depan</h2>
    ++
    ++<p>Layanan latar depan adalah layanan yang dianggap sebagai sesuatu yang
    ++diketahui secara aktif oleh pengguna, jadi bukan sesuatu yang akan dihapus oleh sistem bila memori menipis. Sebuah
    ++layanan latar depan harus memberikan pemberitahuan bagi baris status, yang ditempatkan pada
    ++heading "Ongoing" yang artinya pemberitahuan tersebut tidak bisa diabaikan kecuali jika layanan
    ++dihentikan atau dihapus dari latar depan.</p>
    ++
    ++<p>Misalnya, pemutar musik yang memutar musik dari suatu layanan harus diatur untuk berjalan di
    ++latar depan, karena pengguna mengetahui operasi tersebut
    ++secara eksplisit. Pemberitahuan di baris status bisa menunjukkan lagu saat ini dan memungkinkan
    ++pengguna untuk menjalankan suatu aktivitas untuk berinteraksi dengan pemutar musik.</p>
    ++
    ++<p>Untuk meminta agar layanan Anda berjalan di latar depan, panggil {@link
    ++android.app.Service#startForeground startForeground()}. Metode ini memerlukan dua parameter: sebuah integer
    ++yang mengidentifikasi pemberitahuan secara unik dan {@link
    ++android.app.Notification} untuk baris status. Misalnya:</p>
    ++
    ++<pre>
    ++Notification notification = new Notification(R.drawable.icon, getText(R.string.ticker_text),
    ++        System.currentTimeMillis());
    ++Intent notificationIntent = new Intent(this, ExampleActivity.class);
    ++PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, notificationIntent, 0);
    ++notification.setLatestEventInfo(this, getText(R.string.notification_title),
    ++        getText(R.string.notification_message), pendingIntent);
    ++startForeground(ONGOING_NOTIFICATION_ID, notification);
    ++</pre>
    ++
    ++<p class="caution"><strong>Perhatian:</strong> ID integer yang Anda berikan ke {@link
    ++android.app.Service#startForeground startForeground()} tidak boleh 0.</p>
    ++
    ++
    ++<p>Untuk menghapus layanan dari latar depan, panggil {@link
    ++android.app.Service#stopForeground stopForeground()}. Metode ini memerlukan boolean, yang menunjukkan
    ++apakah pemberitahuan baris status juga akan dihapus. Metode ini <em>tidak</em> menghentikan
    ++layanan. Akan tetapi, jika Anda menghentikan layanan saat masih berjalan di latar depan
    ++maka pemberitahuan juga akan dihapus.</p>
    ++
    ++<p>Untuk informasi selengkapnya tentang pemberitahuan, lihat <a href="{@docRoot}guide/topics/ui/notifiers/notifications.html">Membuat Pemberitahuan
    ++Baris Status</a>.</p>
    ++
    ++
    ++
    ++<h2 id="Lifecycle">Mengelola Daur Hidup Layanan</h2>
    ++
    ++<p>Daur hidup layanan jauh lebih sederhana daripada daur hidup aktivitas. Akan tetapi, lebih penting lagi adalah
    ++memerhatikan dengan cermat bagaimana layanan Anda dibuat dan dimusnahkan, karena suatu layanan
    ++bisa berjalan di latar belakang tanpa disadari oleh pengguna.</p>
    ++
    ++<p>Daur hidup layanan&mdash;dari saat dibuat hingga dimusnahkan&mdash;bisa mengikuti
    ++dua path berbeda:</p>
    ++
    ++<ul>
    ++<li>Layanan yang sudah dimulai
    ++  <p>Layanan dibuat bila komponen lain memanggil {@link
    ++android.content.Context#startService startService()}. Layanan kemudian berjalan terus-menerus dan harus
    ++berhenti sendiri dengan memanggil {@link
    ++android.app.Service#stopSelf() stopSelf()}. Komponen lain juga bisa menghentikan
    ++layanan dengan memanggil {@link android.content.Context#stopService
    ++stopService()}. Bila layanan dihentikan, sistem akan menghancurkannya.</p></li>
    ++
    ++<li>Layanan terikat
    ++  <p>Layanan dibuat bila komponen lain (klien) memanggil {@link
    ++android.content.Context#bindService bindService()}. Klien kemudian berkomunikasi dengan layanan
    ++melalui antarmuka {@link android.os.IBinder}. Klien bisa menutup koneksi dengan memanggil
    ++{@link android.content.Context#unbindService unbindService()}. Sejumlah klien bisa mengikat pada
    ++layanan yang sama dan bila semuanya melepas ikatan, sistem akan memusnahkan layanan tersebut. (Layanan
    ++<em>tidak</em> perlu berhenti sendiri.)</p></li>
    ++</ul>
    ++
    ++<p>Kedua path tersebut tidak benar-benar terpisah. Artinya, Anda bisa mengikat ke layanan yang sudah
    ++dimulai dengan {@link android.content.Context#startService startService()}. Misalnya, layanan
    ++musik latar belakang bisa dimulai dengan memanggil {@link android.content.Context#startService
    ++startService()} dengan {@link android.content.Intent} yang mengidentifikasi musik yang akan diputar. Kemudian,
    ++mungkin saat pengguna ingin mengontrol pemutar musik atau mendapatkan informasi
    ++tentang lagu yang diputar, aktivitas bisa mengikat ke layanan dengan memanggil {@link
    ++android.content.Context#bindService bindService()}. Dalam kasus seperti ini, {@link
    ++android.content.Context#stopService stopService()} atau {@link android.app.Service#stopSelf
    ++stopSelf()} tidak menghentikan layanan sampai semua klien melepas ikatan. </p>
    ++
    ++
    ++<h3 id="LifecycleCallbacks">Mengimplementasikan callback daur hidup</h3>
    ++
    ++<p>Seperti halnya aktivitas, layanan memiliki metode callback daur hidup yang bisa Anda implementasikan
    ++untuk memantau perubahan status layanan dan melakukan pekerjaan pada waktu yang tepat. Layanan skeleton
    ++berikut memperagakan setiap metode daur hidup:</p>
    ++
    ++<pre>
    ++public class ExampleService extends Service {
    ++    int mStartMode;       // indicates how to behave if the service is killed
    ++    IBinder mBinder;      // interface for clients that bind
    ++    boolean mAllowRebind; // indicates whether onRebind should be used
    ++
    ++    &#64;Override
    ++    public void {@link android.app.Service#onCreate onCreate}() {
    ++        // The service is being created
    ++    }
    ++    &#64;Override
    ++    public int {@link android.app.Service#onStartCommand onStartCommand}(Intent intent, int flags, int startId) {
    ++        // The service is starting, due to a call to {@link android.content.Context#startService startService()}
    ++        return <em>mStartMode</em>;
    ++    }
    ++    &#64;Override
    ++    public IBinder {@link android.app.Service#onBind onBind}(Intent intent) {
    ++        // A client is binding to the service with {@link android.content.Context#bindService bindService()}
    ++        return <em>mBinder</em>;
    ++    }
    ++    &#64;Override
    ++    public boolean {@link android.app.Service#onUnbind onUnbind}(Intent intent) {
    ++        // All clients have unbound with {@link android.content.Context#unbindService unbindService()}
    ++        return <em>mAllowRebind</em>;
    ++    }
    ++    &#64;Override
    ++    public void {@link android.app.Service#onRebind onRebind}(Intent intent) {
    ++        // A client is binding to the service with {@link android.content.Context#bindService bindService()},
    ++        // after onUnbind() has already been called
    ++    }
    ++    &#64;Override
    ++    public void {@link android.app.Service#onDestroy onDestroy}() {
    ++        // The service is no longer used and is being destroyed
    ++    }
    ++}
    ++</pre>
    ++
    ++<p class="note"><strong>Catatan:</strong> Tidak seperti metode callback daur hidup aktivitas, Anda
    ++<em>tidak</em> perlu memanggil implementasi superkelas metode callback tersebut.</p>
    ++
    ++<img src="{@docRoot}images/service_lifecycle.png" alt="" />
    ++<p class="img-caption"><strong>Gambar 2.</strong> Daur hidup layanan. Diagram di sebelah kiri
    ++menampilkan daur hidup bila layanan dibuat dengan {@link android.content.Context#startService
    ++startService()} dan diagram di sebelah kanan menampilkan daur hidup bila layanan dibuat
    ++dengan {@link android.content.Context#bindService bindService()}.</p>
    ++
    ++<p>Dengan mengimplementasikan metode-metode ini, Anda bisa memantau dua loop tersarang (nested loop) daur hidup layanan: </p>
    ++
    ++<ul>
    ++<li><strong>Seluruh masa pakai</strong> layanan terjadi antara saat {@link
    ++android.app.Service#onCreate onCreate()} dipanggil dan saat {@link
    ++android.app.Service#onDestroy} kembali. Seperti halnya aktivitas, layanan melakukan penyiapan awal di
    ++{@link android.app.Service#onCreate onCreate()} dan melepaskan semua sisa sumber daya yang ada di {@link
    ++android.app.Service#onDestroy onDestroy()}.  Misalnya,
    ++layanan pemutar musik bisa membuat thread tempat musik akan diputar dalam {@link
    ++android.app.Service#onCreate onCreate()}, kemudian menghentikan thread tersebut dalam {@link
    ++android.app.Service#onDestroy onDestroy()}.
    ++
    ++<p>Metode {@link android.app.Service#onCreate onCreate()} dan {@link android.app.Service#onDestroy
    ++onDestroy()} diperlukan semua layanan, baik yang
    ++dibuat oleh {@link android.content.Context#startService startService()} maupun {@link
    ++android.content.Context#bindService bindService()}.</p></li>
    ++
    ++<li><strong>Masa pakai aktif</strong> layanan dimulai dengan panggilan ke {@link
    ++android.app.Service#onStartCommand onStartCommand()} atau {@link android.app.Service#onBind onBind()}.
    ++Masing-masing metode diberikan {@link
    ++android.content.Intent} yang diteruskan ke {@link android.content.Context#startService
    ++startService()} atau {@link android.content.Context#bindService bindService()}.
    ++<p>Jika layanan telah dimulai, masa pakai aktif akan berakhir pada saat yang sama dengan
    ++berakhirnya seluruh masa pakai (layanan masih aktif bahkan setelah {@link android.app.Service#onStartCommand
    ++onStartCommand()} kembali). Jika layanan tersebut terikat, masa pakai aktifnya akan berakhir bila {@link
    ++android.app.Service#onUnbind onUnbind()} kembali.</p>
    ++</li>
    ++</ul>
    ++
    ++<p class="note"><strong>Catatan:</strong> Meskipun layanan yang sudah dimulai dihentikan dengan panggilan ke
    ++{@link android.app.Service#stopSelf stopSelf()} atau {@link
    ++android.content.Context#stopService stopService()}, tidak ada callback tersendiri bagi
    ++layanan tersebut (tidak ada callback {@code onStop()}). Jadi, kecuali jika layanan terikat ke klien,
    ++sistem akan memusnahkannya bila layanan dihentikan&mdash;{@link
    ++android.app.Service#onDestroy onDestroy()} adalah satu-satunya callback yang diterima.</p>
    ++
    ++<p>Gambar 2 mengilustrasikan metode callback yang lazim bagi suatu layanan. Walaupun gambar tersebut memisahkan
    ++layanan yang dibuat oleh {@link android.content.Context#startService startService()} dari layanan
    ++yang dibuat oleh {@link android.content.Context#bindService bindService()}, ingatlah
    ++bahwa suatu layanan, bagaimana pun dimulainya, bisa memungkinkan klien mengikat padanya.
    ++Jadi, suatu layanan yang awalnya dimulai dengan {@link android.app.Service#onStartCommand
    ++onStartCommand()} (oleh klien yang memanggil {@link android.content.Context#startService startService()})
    ++masih bisa menerima panggilan ke {@link android.app.Service#onBind onBind()} (bila klien memanggil
    ++{@link android.content.Context#bindService bindService()}).</p>
    ++
    ++<p>Untuk informasi selengkapnya tentang membuat layanan yang menyediakan pengikatan, lihat dokumen <a href="{@docRoot}guide/components/bound-services.html">Layanan Terikat</a>,
    ++yang menyertakan informasi selengkapnya tentang metode callback {@link android.app.Service#onRebind onRebind()}
    ++di bagian tentang <a href="{@docRoot}guide/components/bound-services.html#Lifecycle">Mengelola Daur Hidup
    ++Layanan Terikat</a>.</p>
    ++
    ++
    ++<!--
    ++<h2>Beginner's Path</h2>
    ++
    ++<p>To learn how to query data from the system or other applications (such as contacts or media
    ++stored on the device), continue with the <b><a
    ++href="{@docRoot}guide/topics/providers/content-providers.html">Content Providers</a></b>
    ++document.</p>
    ++-->
    +diff --git a/docs/html-intl/intl/id/guide/components/tasks-and-back-stack.jd b/docs/html-intl/intl/id/guide/components/tasks-and-back-stack.jd
    +new file mode 100644
    +index 0000000..4c344ae
    +--- /dev/null
    ++++ b/docs/html-intl/intl/id/guide/components/tasks-and-back-stack.jd
    +@@ -0,0 +1,578 @@
    ++page.title=Tugas dan Back-Stack
    ++parent.title=Aktivitas
    ++parent.link=activities.html
    ++@jd:body
    ++
    ++<div id="qv-wrapper">
    ++<div id="qv">
    ++
    ++<h2>Dalam dokumen ini</h2>
    ++<ol>
    ++<li><a href="#ActivityState">Menyimpan Status Aktivitas</a></li></li>
    ++<li><a href="#ManagingTasks">Mengelola Tugas</a>
    ++  <ol>
    ++    <li><a href="#TaskLaunchModes">Mendefinisikan mode peluncuran</a></li>
    ++    <li><a href="#Affinities">Menangani afinitas</a></li>
    ++    <li><a href="#Clearing">Menghapus back-stack</a></li>
    ++    <li><a href="#Starting">Memulai tugas</a></li>
    ++  </ol>
    ++</li>
    ++</ol>
    ++
    ++<h2>Artikel</h2>
    ++<ol>
    ++  <li><a href="http://android-developers.blogspot.com/2010/04/multitasking-android-way.html">
    ++  Multitasking Ala Android</a></li>
    ++</ol>
    ++
    ++<h2>Lihat juga</h2>
    ++<ol>
    ++  <li><a href="{@docRoot}design/patterns/navigation.html">Desain Android:
    ++Navigasi</a></li>
    ++  <li><a href="{@docRoot}guide/topics/manifest/activity-element.html">Elemen manifes
    ++{@code &lt;activity&gt;}</a></li>
    ++  <li><a href="{@docRoot}guide/components/recents.html">Layar Ikhtisar</a></li>
    ++</ol>
    ++</div>
    ++</div>
    ++
    ++
    ++<p>Sebuah aplikasi biasanya berisi beberapa <a href="{@docRoot}guide/components/activities.html">aktivitas</a>. Setiap aktivitas
    ++harus didesain dengan jenis tindakan tertentu yang bisa dilakukan pengguna dan bisa memulai aktivitas
    ++lain. Misalnya, aplikasi email mungkin memiliki satu aktivitas untuk menampilkan daftar pesan baru.
    ++Bila pengguna memilih sebuah pesan, aktivitas baru akan terbuka untuk melihat pesan tersebut.</p>
    ++
    ++<p>Aktivitas bahkan bisa memulai aktivitas yang ada dalam aplikasi lain di perangkat. Misalnya
    ++, jika aplikasi Anda ingin mengirim pesan email, Anda bisa mendefinisikan intent untuk melakukan tindakan
    ++"kirim" dan menyertakan sejumlah data, seperti alamat email dan pesan. Aktivitas dari aplikasi
    ++lain yang mendeklarasikan dirinya untuk menangani jenis intent ini akan terbuka. Dalam hal ini, intent
    ++tersebut untuk mengirim email, sehingga aktivitas "menulis" pada aplikasi email akan dimulai (jika beberapa aktivitas
    ++mendukung intent yang sama, maka sistem akan memungkinkan pengguna memilih mana yang akan digunakan). Bila email telah
    ++dikirim, aktivitas Anda akan dilanjutkan dan seolah-olah aktivitas email adalah bagian dari aplikasi Anda. Meskipun
    ++aktivitas mungkin dari aplikasi yang berbeda, Android akan tetap mempertahankan pengalaman pengguna yang mulus
    ++dengan menjalankan kedua aktivitas dalam <em>tugas</em> yang sama.</p>
    ++
    ++<p>Tugas adalah kumpulan aktivitas yang berinteraksi dengan pengguna
    ++saat melakukan pekerjaan tertentu. Aktivitas tersebut diatur dalam tumpukan (<em>back-stack</em>), dalam
    ++urutan membuka setiap aktivitas.</p>
    ++
    ++<!-- SAVE FOR WHEN THE FRAGMENT DOC IS ADDED
    ++<div class="sidebox-wrapper">
    ++<div class="sidebox">
    ++<h3>Adding fragments to a task's back stack</h3>
    ++
    ++<p>Your activity can also include {@link android.app.Fragment}s to the back stack. For example,
    ++suppose you have a two-pane layout using fragments, one of which is a list view (fragment A) and the
    ++other being a layout to display an item from the list (fragment B). When the user selects an item
    ++from the list, fragment B is replaced by a new fragment (fragment C). In this case, it might be
    ++desireable for the user to navigate back to reveal fragment B, using the <em>Back</em> button.</p>
    ++<p>In order to add fragment B to the back stack so that this is possible, you must call {@link
    ++android.app.FragmentTransaction#addToBackStack addToBackStack()} before you {@link
    ++android.app.FragmentTransaction#commit()} the transaction that replaces fragment B with fragment
    ++C.</p>
    ++<p>For more information about using fragments and adding them to the back stack, see the {@link
    ++android.app.Fragment} class documentation.</p>
    ++
    ++</div>
    ++</div>
    ++-->
    ++
    ++<p>Layar Home perangkat adalah tempat memulai hampir semua tugas. Bila pengguna menyentuh ikon di launcher
    ++aplikasi
    ++(atau pintasan pada layar Home), tugas aplikasi tersebut akan muncul pada latar depan. Jika tidak ada
    ++tugas untuk aplikasi (aplikasi tidak digunakan baru-baru ini), maka tugas baru
    ++akan dibuat dan aktivitas "utama" untuk aplikasi tersebut akan terbuka sebagai aktivitas akar dalam back-stack.</p>
    ++
    ++<p>Bila aktivitas saat ini dimulai lagi, aktivitas baru akan didorong ke atas back-stack dan
    ++mengambil fokus. Aktivitas sebelumnya tetap dalam back-stack, namun dihentikan. Bila aktivitas
    ++dihentikan, sistem akan mempertahankan status antarmuka penggunanya saat ini. Bila pengguna menekan tombol
    ++<em>Back</em>
    ++, aktivitas saat ini akan dikeluarkan dari atas back-stack (aktivitas dimusnahkan) dan
    ++ aktivitas sebelumnya dilanjutkan (status UI sebelumnya dipulihkan). Aktivitas dalam back-stack
    ++tidak pernah disusun ulang, hanya didorong dan dikeluarkan dari back-stack&mdash;yang didorong ke back-stack saat dimulai oleh
    ++aktivitas saat ini dan dikeluarkan bila pengguna meninggalkannya menggunakan tombol <em>Back</em>. Dengan demikian,
    ++back-stack
    ++beroperasi sebagai struktur objek "masuk terakhir, keluar pertama". Gambar 1 melukiskan perilaku
    ++ini dengan jangka waktu yang menunjukkan kemajuan antar aktivitas beserta
    ++back-stack pada setiap waktu.</p>
    ++
    ++<img src="{@docRoot}images/fundamentals/diagram_backstack.png" alt="" />
    ++<p class="img-caption"><strong>Gambar 1.</strong> Representasi tentang cara setiap aktivitas baru dalam
    ++tugas menambahkan item ke back-stack. Bila pengguna menekan tombol <em>Back</em>, aktivitas
    ++saat ini
    ++akan dimusnahkan dan aktivitas sebelumnya dilanjutkan.</p>
    ++
    ++
    ++<p>Jika pengguna terus menekan <em>Back</em>, maka setiap aktivitas dalam back-stack akan dikeluarkan untuk
    ++menampilkan
    ++yang sebelumnya, sampai pengguna kembali ke layar Home (atau aktivitas mana pun yang sedang dijalankan saat tugas
    ++dimulai. Bila semua aktivitas telah dihapus dari back-stack, maka tugas tidak akan ada lagi.</p>
    ++
    ++<div class="figure" style="width:287px">
    ++<img src="{@docRoot}images/fundamentals/diagram_multitasking.png" alt="" /> <p
    ++class="img-caption"><strong>Gambar 2.</strong> Dua tugas: Tugas B menerima interaksi pengguna
    ++di latar depan, sedangkan Tugas A di latar belakang, menunggu untuk dilanjutkan.</p>
    ++</div>
    ++<div class="figure" style="width:215px">
    ++  <img src="{@docRoot}images/fundamentals/diagram_multiple_instances.png" alt="" /> <p
    ++class="img-caption"><strong>Gambar 3.</strong> Satu aktivitas dibuat instance-nya beberapa kali.</p>
    ++</div>
    ++
    ++<p>Tugas adalah unit kohesif yang bisa dipindahkan ke "latar belakang" bila pengguna memulai tugas baru atau masuk ke
    ++layar Home, melalui tombol<em>Home</em>. Sementara di latar belakang, semua aktivitas dalam
    ++tugas
    ++dihentikan, namun back-stack untuk tugas tidak berubah&mdash;tugas kehilangan fokus saat
    ++tugas lain berlangsung, seperti yang ditampilkan dalam gambar 2. Kemudian, tugas bisa kembali ke "latar depan" agar pengguna
    ++bisa melanjutkan tugas di tempat menghentikannya. Anggaplah, misalnya, tugas saat ini (Tugas A) memiliki tiga
    ++aktivitas dalam back-stack&mdash;dua pada aktivitas saat ini. Pengguna menekan tombol <em>Home</em>
    ++, kemudian
    ++memulai aplikasi baru dari launcher aplikasi. Bila muncul layar Home, Tugas A akan beralih
    ++ke latar belakang. Bila aplikasi baru dimulai, sistem akan memulai tugas untuk aplikasi tersebut
    ++(Tugas B) dengan back-stack aktivitas sendiri. Setelah berinteraksi dengan aplikasi
    ++tersebut, pengguna akan kembali ke Home lagi dan memilih aplikasi yang semula
    ++memulai Tugas A. Sekarang, Tugas A muncul di
    ++latar depan&mdash;ketiga aktivitas dalam back-stack tidak berubah dan aktivitas di atas
    ++back-stack akan dilanjutkan. Pada
    ++titik ini pengguna juga bisa beralih kembali ke Tugas B dengan masuk ke Home dan memilih ikon aplikasi
    ++yang memulai tugas tersebut (atau dengan memilih tugas aplikasi dari
    ++<a href="{@docRoot}guide/components/recents.html">layar ikhtisar</a>).
    ++Ini adalah contoh dari melakukan multitasking di Android.</p>
    ++
    ++<p class="note"><strong>Catatan:</strong> Beberapa tugas bisa berlangsung di latar belakang secara bersamaan.
    ++Akan tetapi, jika pengguna menjalankan banyak tugas di latar belakang sekaligus, sistem mungkin mulai
    ++menghapus aktivitas latar belakang untuk memulihkan memori, yang akan menyebabkan status aktivitas hilang.
    ++Lihat bagian berikut tentang <a href="#ActivityState">Status aktivitas</a>.</p>
    ++
    ++<p>Karena aktivitas di back-stack tidak pernah diatur ulang, jika aplikasi Anda memungkinkan
    ++pengguna untuk memulai aktivitas tertentu dari lebih dari satu aktivitas, instance baru
    ++aktivitas tersebut akan dibuat dan didorong ke back-stack (bukannya memunculkan instance sebelumnya dari
    ++aktivitas ke atas). Dengan demikian, satu aktivitas pada aplikasi Anda mungkin dibuat beberapa
    ++kali (bahkan dari beberapa tugas), seperti yang ditampilkan dalam gambar 3. Dengan demikian, jika pengguna mengarahkan mundur
    ++menggunakan tombol <em>Back</em>, setiap instance aktivitas ini akan ditampilkan dalam urutan saat
    ++dibuka (masing-masing
    ++dengan status UI sendiri). Akan tetapi, Anda bisa memodifikasi perilaku ini jika tidak ingin aktivitas
    ++dibuat instance-nya lebih dari sekali. Caranya dibahas di bagian selanjutnya tentang <a href="#ManagingTasks">Mengelola Tugas</a>.</p>
    ++
    ++
    ++<p>Untuk meringkas perilaku default aktivitas dan tugas:</p>
    ++
    ++<ul>
    ++  <li>Bila Aktivitas A memulai Aktivitas B, Aktivitas A dihentikan, namun sistem mempertahankan statusnya
    ++(seperti posisi gulir dan teks yang dimasukkan ke dalam formulir).
    ++Jika pengguna menekan tombol <em>Back</em> saat dalam Aktivitas B, Aktivitas A akan dilanjutkan dengan status
    ++yang dipulihkan.</li>
    ++  <li>Bila pengguna meninggalkan tugas dengan menekan tombol <em>Home</em> aktivitas saat ini akan
    ++dihentikan dan
    ++tugas beralih ke latar belakang. Sistem akan mempertahankan status setiap aktivitas dalam tugas. Jika
    ++nanti pengguna melanjutkan tugas dengan memilih ikon launcher yang memulai tugas, tugas tersebut akan
    ++beralih ke latar depan dan melanjutkan aktivitas di atas back-stack.</li>
    ++  <li>Jika pengguna menekan tombol <em>Back</em>, aktivitas saat ini akan dikeluarkan dari back-stack
    ++dan
    ++dimusnahkan. Aktivitas sebelumnya dalam back-stack akan dilanjutkan. Bila suatu aktivitas dimusnahkan, sistem
    ++<em>tidak akan</em>mempertahankan status aktivitas.</li>
    ++  <li>Aktivitas bisa dibuat instance-nya beberapa kali, bahkan dari tugas-tugas lainnya.</li>
    ++</ul>
    ++
    ++
    ++<div class="note design">
    ++<p><strong>Desain Navigasi</strong></p>
    ++  <p>Untuk mengetahui selengkapnya tentang cara kerja navigasi aplikasi di Android, baca panduan <a href="{@docRoot}design/patterns/navigation.html">Navigasi</a> Desain Android.</p>
    ++</div>
    ++
    ++
    ++<h2 id="ActivityState">Menyimpan Status Aktivitas</h2>
    ++
    ++<p>Seperti dibahas di atas, perilaku default sistem akan mempertahankan status aktivitas bila
    ++dihentikan. Dengan cara ini, bila pengguna mengarah kembali ke aktivitas sebelumnya, antarmuka pengguna akan muncul
    ++seperti saat ditinggalkan. Akan tetapi, Anda bisa&mdash;dan <strong>harus</strong>&mdash;secara proaktif mempertahankan
    ++status aktivitas menggunakan metode callback, jika aktivitas ini dimusnahkan dan harus
    ++dibuat kembali.</p>
    ++
    ++<p>Bila sistem menghentikan salah satu aktivitas (seperti saat aktivitas baru dimulai atau tugas
    ++dipindah ke latar belakang), sistem mungkin memusnahkan aktivitas sepenuhnya jika perlu memulihkan
    ++memori sistem. Bila hal ini terjadi, informasi tentang status aktivitas akan hilang. Jika hal ini terjadi, sistem
    ++masih
    ++mengetahui bahwa aktivitas memiliki tempat di back-stack, namun saat aktivitas tersebut dibawa ke bagian teratas
    ++back-stack, sistem harus membuatnya kembali (bukan melanjutkannya). Untuk
    ++menghindari hilangnya pekerjaan pengguna, Anda harus secara proaktif mempertahankannya dengan menerapkan metode callback
    ++{@link android.app.Activity#onSaveInstanceState onSaveInstanceState()}
    ++dalam aktivitas.</p>
    ++
    ++<p>Untuk informasi selengkapnya tentang cara menyimpan status aktivitas Anda, lihat dokumen
    ++<a href="{@docRoot}guide/components/activities.html#SavingActivityState">Aktivitas</a>.</p>
    ++
    ++
    ++
    ++<h2 id="ManagingTasks">Mengelola Tugas</h2>
    ++
    ++<p>Cara Android mengelola tugas dan back-stack, seperti yang dijelaskan di atas&mdash;dengan menempatkan semua
    ++aktivitas yang dimulai secara berurutan dalam tugas yang sama dan dalam back-stack "masuk terakhir, keluar pertama"&mdash;berfungsi
    ++dengan baik untuk kebanyakan aplikasi dan Anda tidak perlu khawatir tentang cara mengaitkan aktivitas
    ++dengan tugas atau cara penempatannya di back-stack. Akan tetapi, Anda bisa memutuskan apakah ingin menyela
    ++perilaku normal. Mungkin Anda ingin agar suatu aktivitas dalam aplikasi untuk memulai tugas baru bila telah
    ++dimulai (sebagai ganti menempatkannya dalam tugas saat ini); atau, bila memulai aktivitas, Anda ingin
    ++memajukan instance yang ada (sebagai ganti membuat instance
    ++baru pada bagian teratas back-stack); atau, Anda ingin back-stack dihapus dari semua
    ++aktivitas selain untuk aktivitas akar bila pengguna meninggalkan tugas.</p>
    ++
    ++<p>Anda bisa melakukan semua ini dan lainnya, dengan atribut dalam elemen manifes
    ++<a href="{@docRoot}guide/topics/manifest/activity-element.html">{@code &lt;activity&gt;}</a>
    ++dan dengan flag pada intent yang Anda teruskan ke
    ++{@link android.app.Activity#startActivity startActivity()}.</p>
    ++
    ++<p>Dalam hal ini, atribut<a href="{@docRoot}guide/topics/manifest/activity-element.html">
    ++{@code &lt;activity&gt;}</a> utama yang bisa Anda gunakan adalah:</p>
    ++
    ++<ul class="nolist">
    ++  <li><a href="{@docRoot}guide/topics/manifest/activity-element.html#aff">
    ++  {@code taskAffinity}</a></li>
    ++  <li><a href="{@docRoot}guide/topics/manifest/activity-element.html#lmode">
    ++  {@code launchMode}</a></li>
    ++  <li><a href="{@docRoot}guide/topics/manifest/activity-element.html#reparent">
    ++  {@code allowTaskReparenting}</a></li>
    ++  <li><a href="{@docRoot}guide/topics/manifest/activity-element.html#clear">
    ++  {@code clearTaskOnLaunch}</a></li>
    ++  <li><a href="{@docRoot}guide/topics/manifest/activity-element.html#always">
    ++  {@code alwaysRetainTaskState}</a></li>
    ++  <li><a href="{@docRoot}guide/topics/manifest/activity-element.html#finish">
    ++  {@code finishOnTaskLaunch}</a></li>
    ++</ul>
    ++
    ++<p>Dan flag intent utama yang bisa Anda gunakan adalah:</p>
    ++
    ++<ul class="nolist">
    ++  <li>{@link android.content.Intent#FLAG_ACTIVITY_NEW_TASK}</li>
    ++  <li>{@link android.content.Intent#FLAG_ACTIVITY_CLEAR_TOP}</li>
    ++  <li>{@link android.content.Intent#FLAG_ACTIVITY_SINGLE_TOP}</li>
    ++</ul>
    ++
    ++<p>Dalam bagian berikut, Anda akan melihat cara menggunakan beberapa atribut manifes ini dan flag
    ++intent untuk mendefinisikan cara mengaitkan aktivitas dengan tugas dan cara perilakunya di back-stack.</p>
    ++
    ++<p>Juga, pertimbangan cara menyatakan dan mengelola tugas dan aktivitas
    ++dibahas secara terpisah di layar ikhtisar. Lihat <a href="{@docRoot}guide/components/recents.html">Layar Ikhtisar</a>
    ++untuk informasi selengkapnya. Biasanya Anda harus mengizinkan sistem mendefinisikan cara menyatakan tugas dan
    ++aktivitas di layar ikhtisar, dan Anda tidak perlu memodifikasi perilaku ini.</p>
    ++
    ++<p class="caution"><strong>Perhatian:</strong> Kebanyakan aplikasi tidak harus menyela perilaku
    ++default untuk aktivitas dan tugas. Jika merasa bahwa aktivitas Anda perlu memodifikasi
    ++perilaku default, lakukan dengan hati-hati dan pastikan menguji kegunaan aktivitas selama
    ++dijalankan dan saat mengarahkan kembali ke sana dari aktivitas dan tugas lain dengan tombol <em>Back</em>.
    ++Pastikan menguji perilaku navigasi yang mungkin bertentangan dengan perilaku yang diharapkan pengguna.</p>
    ++
    ++
    ++<h3 id="TaskLaunchModes">Mendefinisikan mode peluncuran</h3>
    ++
    ++<p>Mode peluncuran memungkinkan Anda mendefinisikan cara mengaitkan instance baru dari suatu aktivitas dengan
    ++tugas saat ini. Anda bisa mendefinisikan beragam mode peluncuran dalam dua cara:</p>
    ++<ul class="nolist">
    ++  <li><a href="#ManifestForTasks">Menggunakan file manifes</a>
    ++    <p>Bila Anda mendeklarasikan aktivitas dalam file manifes, Anda bisa menetapkan cara mengaitkan aktivitas
    ++dengan tugas-tugas saat mulai.</li>
    ++  <li><a href="#IntentFlagsForTasks">Menggunakan flag intent</a>
    ++    <p>Saat memanggil{@link android.app.Activity#startActivity startActivity()},
    ++Anda bisa menyertakan flag dalam {@link android.content.Intent} yang menyatakan cara (atau
    ++apakah) aktivitas baru tersebut harus dikaitkan dengan tugas saat ini.</p></li>
    ++</ul>
    ++
    ++<p>Dengan demikian, jika Aktivitas A memulai Aktivitas B, Aktivitas B bisa mendefinisikan dalam manifesnya cara
    ++mengaitkan dengan tugas saat ini (jika sama sekali) dan Aktivitas A juga bisa meminta cara mengaitkan Aktivitas B
    ++dengan tugas saat ini. Jika kedua aktivitas mendefinisikan cara mengaitkan Aktivitas B
    ++dengan tugas, maka permintaan Aktivitas A (sebagaimana didefinisikan dalam intent) lebih dihargai daripada
    ++permintaan Aktivitas B (sebagaimana didefinisikan dalam manifesnya).</p>
    ++
    ++<p class="note"><strong>Catatan:</strong> Beberapa mode peluncuran yang tersedia untuk file manifes
    ++tidak tersedia sebagai flag untuk intent dan, juga, beberapa mode peluncuran yang tersedia sebagai flag
    ++untuk intent tidak bisa didefinisikan dalam manifest.</p>
    ++
    ++
    ++<h4 id="ManifestForTasks">Menggunakan file manifes</h4>
    ++
    ++<p>Saat mendeklarasikan aktivitas dalam file manifes, Anda bisa menetapkan cara mengaitkan aktivitas
    ++dengan tugas menggunakan <a href="{@docRoot}guide/topics/manifest/activity-element.html">{@code &lt;activity&gt;}</a>
    ++melalui atribut <a href="{@docRoot}guide/topics/manifest/activity-element.html#lmode">{@code
    ++launchMode}</a> elemen.</p>
    ++
    ++<p>Atribut <a href="{@docRoot}guide/topics/manifest/activity-element.html#lmode">{@code
    ++launchMode}</a> menetapkan instruksi tentang cara meluncurkan aktivitas
    ++ke dalam tugas. Ada empat macam mode peluncuran yang bisa Anda tetapkan ke atribut
    ++<code><a href="{@docRoot}guide/topics/manifest/activity-element.html#lmode">launchMode</a></code>
    ++:</p>
    ++
    ++<dl>
    ++<dt>{@code "standard"} (mode default)</dt>
    ++  <dd>Default. Sistem membuat instance baru aktivitas dalam tugas yang
    ++akan menjadi tempat memulainya dan mengarahkan intent ke sana. Aktivitas ini bisa dibuat instance-nya beberapa kali,
    ++masing-masing instance bisa dimiliki oleh tugas berbeda, dan satu tugas bisa memiliki beberapa instance.</dd>
    ++<dt>{@code "singleTop"}</dt>
    ++  <dd>Jika instance aktivitas sudah ada di bagian teratas tugas saat ini, sistem
    ++akan mengarahkan intent ke instance tersebut melalui panggilan ke metode {@link
    ++android.app.Activity#onNewIntent onNewIntent()}, bukan membuat instance baru dari
    ++aktivitas tersebut. Aktivitas bisa dibuat instance-nya beberapa kali, masing-masing instance bisa dimiliki
    ++oleh tugas berbeda, dan satu tugas bisa memiliki beberapa instance (namun hanya jika
    ++aktivitas di bagian teratas back-stack <em>bukan</em> instance yang ada dari aktivitas tersebut).
    ++  <p>Misalnya, anggaplah back-stack tugas terdiri dari aktivitas A akar dengan aktivitas B, C,
    ++dan D di bagian teratas (back-stack adalah A-B-C-D; D yang teratas). Intent masuk untuk aktivitas tipe D.
    ++Jika D memiliki mode peluncuran {@code "standard"} default, instance baru dari kelas ini akan diluncurkan dan
    ++back-stack menjadi A-B-C-D-D. Namun, jika mode peluncuran D adalah {@code "singleTop"}, instance
    ++yang ada dari D akan menerima intent melalui {@link
    ++android.app.Activity#onNewIntent onNewIntent()}, karena ada di bagian teratas back-stack&mdash;
    ++back-stack tetap A-B-C-D. Akan tetapi, jika intent masuk untuk aktivitas tipe B, maka
    ++instance B baru akan ditambahkan ke back-stack, sekalipun mode peluncuran adalah{@code "singleTop"}.</p>
    ++  <p class="note"><strong>Catatan:</strong> Bila instance dari aktivitas baru telah dibuat,
    ++pengguna bisa menekan tombol <em>Back</em> untuk kembali ke aktivitas sebelumnya. Namun bila instance
    ++yang ada dari
    ++aktivitas menangani intent baru, pengguna tidak bisa menekan tombol <em>Back</em> untuk kembali ke
    ++status
    ++aktivitas sebelum intent baru masuk di {@link android.app.Activity#onNewIntent
    ++onNewIntent()}.</p>
    ++</dd>
    ++
    ++<dt>{@code "singleTask"}</dt>
    ++  <dd>Sistem membuat tugas baru dan membuat instance aktivitas di akar tugas baru.
    ++Akan tetapi, jika instance aktivitas sudah ada dalam tugas terpisah, sistem akan mengarahkan
    ++intent ke instance yang ada melalui panggilan ke metode {@link
    ++android.app.Activity#onNewIntent onNewIntent()}, bukan membuat instance baru. Hanya
    ++boleh ada satu instance aktivitas untuk setiap kalinya.
    ++  <p class="note"><strong>Catatan:</strong> Meskipun aktivitas dimulai di tugas baru, tombol
    ++<em>Back</em> tetap akan mengembalikan pengguna ke aktivitas sebelumnya.</p></dd>
    ++<dt>{@code "singleInstance"}.</dt>
    ++  <dd>Sama seperti {@code "singleTask"}, namun sistem tidak meluncurkan aktivitas lain ke
    ++tugas yang menyimpan instance. Aktivitas selalu satu dan satu-satunya anggota dari tugasnya;
    ++aktivitas apa pun yang dimulai dengan ini akan dibuka di tugas yang terpisah.</dd>
    ++</dl>
    ++
    ++
    ++<p>Sebagai contoh lainnya, aplikasi Browser Android mendeklarasikan bahwa aktivitas browser web harus
    ++selalu dibuka dalam tugasnya sendiri&mdash;dengan menetapkan mode pembuka {@code singleTask} dalam elemen<a href="{@docRoot}guide/topics/manifest/activity-element.html">{@code &lt;activity&gt;}</a>.
    ++Ini berarti bahwa jika aplikasi Anda mengeluarkan
    ++intent untuk membuka Browser Android, aktivitasnya <em>tidak</em> akan ditempatkan dalam tugas
    ++yang sama seperti aplikasi Anda. Sebagai gantinya, tugas baru akan dimulai untuk Browser atau, jika Browser
    ++sudah memiliki tugas yang berjalan di latar belakang, tugas tersebut akan dimajukan untuk menangani intent
    ++baru.</p>
    ++
    ++<p>Baik aktivitas dimulai dalam tugas baru atau maupun dalam tugas yang sama seperti aktivitas yang memulainya, tombol
    ++<em>Back</em> selalu membawa pengguna ke aktivitas sebelumnya. Akan tetapi, jika
    ++Anda memulai aktivitas yang menetapkan mode pembuka {@code singleTask}, maka jika instance
    ++aktivitas tersebut ada dalam tugas latar belakang, seluruh tugas tersebut akan dibawa ke latar depan. Pada titik
    ++ini, back-stack sekarang menyertakan semua aktivitas dari tugas yang dimajukan, di atas
    ++back-stack. Gambar 4 mengilustrasikan tipe skenario ini.</p>
    ++
    ++<img src="{@docRoot}images/fundamentals/diagram_backstack_singletask_multiactivity.png" alt="" />
    ++<p class="img-caption"><strong>Gambar 4.</strong> Representasi tentang cara aktivitas dengan
    ++mode pembuka "singleTask" ditambahkan ke back-stack. Jika aktivitas tersebut sudah menjadi bagian dari
    ++tugas latar belakang dengan back-stack sendiri, maka seluruh back-stack juga
    ++dimajukan, di atas tugas saat ini.</p>
    ++
    ++<p>Untuk informasi selengkapnya tentang menggunakan mode pembuka dalam file manifes, lihat dokumentasi elemen
    ++<code><a href="{@docRoot}guide/topics/manifest/activity-element.html">&lt;activity&gt;</a></code>
    ++, di mana atribut {@code launchMode} dan nilai-nilai yang diterima
    ++akan dibahas selengkapnya.</p>
    ++
    ++<p class="note"><strong>Catatan:</strong> Perilaku yang Anda tentukan untuk aktivitas dengan atribut <a href="{@docRoot}guide/topics/manifest/activity-element.html#lmode">{@code launchMode}</a>
    ++bisa dikesampingkan dengan flag yang disertakan bersama intent yang memulai aktivitas Anda, seperti dibahas dalam
    ++bagian berikutnya.</p>
    ++
    ++
    ++
    ++<h4 id="#IntentFlagsForTasks">Menggunakan flag Intent</h4>
    ++
    ++<p>Saat memulai aktivitas, Anda bisa memodifikasi asosiasi default aktivitas pada tugasnya
    ++ dengan menyertakan flag dalam intent yang Anda kirimkan ke {@link
    ++android.app.Activity#startActivity startActivity()}. Flag yang bisa Anda gunakan untuk memodifikasi perilaku default
    ++adalah:</p>
    ++
    ++<p>
    ++  <dt>{@link android.content.Intent#FLAG_ACTIVITY_NEW_TASK}</dt>
    ++    <dd>Memulai aktivitas dalam tugas baru. Jika tugas sudah dijalankan untuk aktivitas yang sekarang
    ++Anda mulai, tugas tersebut akan dibawa ke latar depan dengan status terakhir yang dipulihkan dan aktivitas
    ++akan menerima intent baru dalam {@link android.app.Activity#onNewIntent onNewIntent()}.
    ++    <p>Ini menghasilkan perilaku yang sama dengan nilai {@code "singleTask"} <a href="{@docRoot}guide/topics/manifest/activity-element.html#lmode">{@code launchMode}</a>
    ++yang dibahas di bagian sebelumnya.</p></dd>
    ++  <dt>{@link android.content.Intent#FLAG_ACTIVITY_SINGLE_TOP}</dt>
    ++    <dd>Jika aktivitas yang dimulai adalah aktivitas saat ini (di bagian teratas back-stack), maka
    ++instance yang ada akan menerima panggilan ke {@link android.app.Activity#onNewIntent onNewIntent()}
    ++sebagai ganti membuat instance baru aktivitas.
    ++    <p>Ini menghasilkan perilaku yang sama dengan nilai {@code "singleTop"} <a href="{@docRoot}guide/topics/manifest/activity-element.html#lmode">{@code launchMode}</a>
    ++yang dibahas di bagian sebelumnya.</p></dd>
    ++  <dt>{@link android.content.Intent#FLAG_ACTIVITY_CLEAR_TOP}</dt>
    ++    <dd>Jika aktivitas yang dimulai sudah berjalan dalam tugas saat ini, maka sebagai
    ++ganti meluncurkan instance baru aktivitas tersebut, semua kegiatan lain di atasnya akan
    ++dimusnahkan dan intent ini akan disampaikan ke instance aktivitas yang dilanjutkan (sekarang di atas),
    ++melalui {@link android.app.Activity#onNewIntent onNewIntent()}).
    ++    <p>Tidak ada nilai untuk atribut <a href="{@docRoot}guide/topics/manifest/activity-element.html#lmode">{@code launchMode}</a>
    ++ yang menghasilkan perilaku ini.</p>
    ++    <p>{@code FLAG_ACTIVITY_CLEAR_TOP} paling sering digunakan bersama dengan
    ++    {@code FLAG_ACTIVITY_NEW_TASK}.
    ++Bila digunakan bersama-sama, flag ini adalah cara penempatan aktivitas yang ada
    ++dalam tugas lain dan meletakkannya dalam posisi yang memungkinkannya merespons intent. </p>
    ++    <p class="note"><strong>Catatan:</strong> Jika mode pembuka aktivitas yang didesain adalah
    ++{@code "standard"},
    ++ini juga akan dihapus dari back-stack dan instance baru akan diluncurkan di tempatnya untuk menangani
    ++intent yang masuk.  Itu karena instance baru selalu dibuat untuk intent baru bila
    ++mode peluncuran adalah {@code "standard"}. </p>
    ++</dd>
    ++</dl>
    ++
    ++
    ++
    ++
    ++
    ++<h3 id="Affinities">Menangani afinitas</h3>
    ++
    ++<p><em>Afinitas</em> menunjukkan tugas mana yang disukai aktivitas untuk dimiliki. Secara default, semua
    ++aktivitas aplikasi yang sama memiliki afinitas untuk satu sama lain. Jadi, secara default, semua
    ++aktivitas dalam aplikasi yang sama lebih menyukai berada dalam tugas yang sama. Akan tetapi, Anda bisa memodifikasi
    ++afinitas default untuk suatu aktivitas. Aktivitas yang didefinisikan dalam
    ++aplikasi yang berbeda bisa berbagi afinitas, atau aktivitas yang didefinisikan dalam aplikasi yang sama bisa
    ++diberi afinitas tugas yang berbeda.</p>
    ++
    ++<p>Anda bisa memodifikasi afinitas untuk setiap yang diberikan
    ++dengan atribut <a href="{@docRoot}guide/topics/manifest/activity-element.html#aff">{@code taskAffinity}</a>
    ++elemen <a href="{@docRoot}guide/topics/manifest/activity-element.html">{@code &lt;activity&gt;}</a>.</p>
    ++
    ++<p>Atribut <a href="{@docRoot}guide/topics/manifest/activity-element.html#aff">{@code taskAffinity}</a>
    ++mengambil nilai string, yang harus unik dari nama paket default
    ++yang dideklarasikan dalam elemen <a href="{@docRoot}guide/topics/manifest/manifest-element.html">
    ++{@code &lt;manifest&gt;}
    ++</a>, karena sistem menggunakan nama untuk mengidentifikasi afinitas
    ++tugas default untuk aplikasi.</p>
    ++
    ++<p>Afinitas berperan dalam dua keadaan:</p>
    ++<ul>
    ++  <li>Bila intent yang meluncurkan aktivitas berisi flag
    ++  {@link android.content.Intent#FLAG_ACTIVITY_NEW_TASK}
    ++.
    ++
    ++<p>Aktivitas baru, secara default, diluncurkan ke dalam tugas aktivitas
    ++yang disebut {@link android.app.Activity#startActivity startActivity()}. Ini didorong ke back-stack
    ++yang sama seperti caller.  Akan tetapi, jika intent yang diteruskan ke
    ++{@link android.app.Activity#startActivity startActivity()}
    ++berisi flag {@link android.content.Intent#FLAG_ACTIVITY_NEW_TASK}
    ++, maka sistem akan mencari tugas yang berbeda untuk menampung aktivitas baru. Sering kali, itu adalah tugas baru.
    ++Akan tetapi, tidak harus demikian.  Jika sudah ada tugas lama dengan afinitas yang sama seperti
    ++aktivitas baru, aktivitas ini akan diluncurkan ke dalam tugas tersebut.  Jika tidak, tugas baru akan dimulai.</p>
    ++
    ++<p>Jika flag ini menyebabkan aktivitas memulai tugas baru dan pengguna menekan tombol <em>Home</em>
    ++untuk meninggalkannya,
    ++harus ada cara bagi pengguna untuk mengarahkan kembali ke tugas. Beberapa entitas (seperti
    ++notification manager) selalu memulai aktivitas dalam tugas eksternal, tidak pernah sebagai bagian dari miliknya sendiri, jadi
    ++selalu menempatkan {@code FLAG_ACTIVITY_NEW_TASK} dalam intent yang diteruskan ke
    ++{@link android.app.Activity#startActivity startActivity()}.
    ++Jika Anda memiliki aktivitas yang bisa dipanggil melalui
    ++entitas eksternal yang mungkin menggunakan flag ini, hati-hatilah karena pengguna memiliki cara independen untuk kembali
    ++ke tugas yang telah dimulai, seperti dengan ikon launcher (aktivitas akar dari tugas
    ++memiliki filter intent {@link android.content.Intent#CATEGORY_LAUNCHER}; lihat bagian <a href="#Starting">Memulai tugas</a> di bawah ini).</p>
    ++</li>
    ++
    ++  <li>Bila aktivitas memiliki atribut <a href="{@docRoot}guide/topics/manifest/activity-element.html#reparent">
    ++{@code allowTaskReparenting}</a> sendiri yang diatur ke {@code "true"}.
    ++  <p>Dalam hal ini, aktivitas bisa berpindah dari tugas yang dimulainya ke tugas yang afinitasnya
    ++dimilikinya, bila tugas tersebut di bawa ke latar depan.</p>
    ++  <p>Misalnya, anggaplah sebuah aktivitas melaporkan kondisi cuaca di sejumlah kota terpilih
    ++yang didefinisikan sebagai bagian dari aplikasi perjalanan.  Aktivitas memiliki afinitas yang sama dengan aktivitas lain dalam aplikasi
    ++yang sama (afinitas aplikasi default) dan aktivitas ini memungkinkan re-parenting dengan atribut ini.
    ++Bila salah satu aktivitas Anda memulai aktivitas laporan cuaca, awalnya aktivitas ini dimiliki oleh tugas
    ++yang sama dengan aktivitas Anda. Akan tetapi, bila tugas aplikasi perjalanan di bawa ke latar depan,
    ++aktivitas laporan cuaca akan ditetapkan kembali ke tugas itu dan ditampilkan di dalamnya.</p>
    ++</li>
    ++</ul>
    ++
    ++<p class="note"><strong>Tip:</strong> Jika file {@code .apk} berisi lebih dari satu "aplikasi"
    ++dari sudut pandang pengguna, Anda mungkin perlu menggunakan atribut <a href="{@docRoot}guide/topics/manifest/activity-element.html#aff">{@code taskAffinity}</a>
    ++ untuk menetapkan afinitas berbeda pada aktivitas yang terkait dengan setiap "aplikasi".</p>
    ++
    ++
    ++
    ++<h3 id="Clearing">Menghapus back-stack</h3>
    ++
    ++<p>Jika pengguna meninggalkan tugas dalam waktu yang lama, sistem akan menghapus tugas semua aktivitas kecuali
    ++aktivitas akar.  Bila pengguna kembali ke tugas itu lagi, hanya aktivitas akar yang akan dipulihkan.
    ++Sistem berperilaku seperti ini, karena, setelah sekian waktu, pengguna mungkin telah mengabaikan
    ++apa yang mereka kerjakan sebelum dan kembali ke tugas itu untuk memulai sesuatu yang baru. </p>
    ++
    ++<p>Ada beberapa atribut aktivitas yang bisa Anda gunakan untuk memodifikasi perilaku ini: </p>
    ++
    ++<dl>
    ++<dt><code><a
    ++href="{@docRoot}guide/topics/manifest/activity-element.html#always">alwaysRetainTaskState</a></code>
    ++</dt>
    ++<dd>Jika atribut ini ditetapkan ke {@code "true"} dalam aktivitas akar tugas,
    ++perilaku default yang baru dijelaskan tidak akan terjadi.
    ++ Tugas akan mempertahankan semua aktivitas dalam back-stack bahkan setelah sekian lama.</dd>
    ++
    ++<dt><code><a
    ++href="{@docRoot}guide/topics/manifest/activity-element.html#clear">clearTaskOnLaunch</a></code></dt>
    ++<dd>Jika atribut ini diatur ke {@code "true"} dalam aktivitas akar tugas, back-
    ++stack akan dihapus hingga aktivitas akar bila pengguna meninggalkan tugas
    ++dan kembali lagi.  Dengan kata lain, ini adalah lawan dari
    ++<a href="{@docRoot}guide/topics/manifest/activity-element.html#always">
    ++{@code alwaysRetainTaskState}</a>. Pengguna selalu kembali ke tugas dengan
    ++status awalnya, walaupun hanya sebentar meninggalkan tugas.</dd>
    ++
    ++<dt><code><a
    ++href="{@docRoot}guide/topics/manifest/activity-element.html#finish">finishOnTaskLaunch</a></code>
    ++</dt>
    ++<dd>Atribut ini seperti <a href="{@docRoot}guide/topics/manifest/activity-element.html#clear">{@code clearTaskOnLaunch}</a>,
    ++namun beroperasi pada
    ++satu aktivitas, bukan pada seluruh tugas.  Hal ini juga bisa menyebabkan aktivitas
    ++hilang, termasuk aktivitas akar.  Bila ini diatur ke {@code "true"},
    ++aktivitas akan tetap menjadi bagian dari tugas hanya untuk sesi saat ini.  Jika pengguna
    ++keluar dan kemudian kembali ke tugas tersebut, tugas tidak akan ada lagi.</dd>
    ++</dl>
    ++
    ++
    ++
    ++
    ++<h3 id="Starting">Memulai tugas</h3>
    ++
    ++<p>Anda bisa mengatur aktivitas sebagai titik masuk untuk tugas dengan memberikan filter intent dengan
    ++{@code "android.intent.action.MAIN"} sebagai tindakan yang ditetapkan dan
    ++{@code "android.intent.category.LAUNCHER"}
    ++sebagai kategori yang ditetapkan. Misalnya:</p>
    ++
    ++<pre>
    ++&lt;activity ... &gt;
    ++    &lt;intent-filter ... &gt;
    ++        &lt;action android:name="android.intent.action.MAIN" /&gt;
    ++        &lt;category android:name="android.intent.category.LAUNCHER" /&gt;
    ++    &lt;/intent-filter&gt;
    ++    ...
    ++&lt;/activity&gt;
    ++</pre>
    ++
    ++<p>Filter intent semacam ini akan menyebabkan ikon dan label untuk
    ++aktivitas ditampilkan dalam launcher aplikasi, yang akan memberi cara kepada pengguna untuk meluncurkan aktivitas dan
    ++kembali ke tugas yang dibuatnya kapan saja setelah ia telah diluncurkan.
    ++</p>
    ++
    ++<p>Kemampuan kedua ini penting: Pengguna harus bisa meninggalkan tugas dan kemudian kembali ke tugas tersebut
    ++nanti dengan menggunakan launcher aktivitas ini. Karena itu, kedua <a href="#LaunchModes">mode
    ++pembuka</a> yang menandai aktivitas selalu memulai tugas, {@code "singleTask"} dan
    ++{@code "singleInstance"}, hanya boleh digunakan bila aktivitas memiliki filter
    ++{@link android.content.Intent#ACTION_MAIN}
    ++dan {@link android.content.Intent#CATEGORY_LAUNCHER}. Bayangkan, misalnya, apa yang akan
    ++terjadi jika filter tidak ada: Intent meluncurkan aktivitas{@code "singleTask"}, memulai
    ++tugas yang baru, dan pengguna menghabiskan lebih banyak waktu mengerjakan tugas tersebut. Pengguna kemudian menekan tombol
    ++<em>Home</em>. Tugas kini dikirim ke latar belakang dan tidak terlihat. Sekarang pengguna tidak memiliki cara untuk kembali
    ++ke tugas tersebut, karena tidak dinyatakan dalam launcher aplikasi.</p>
    ++
    ++<p>Untuk kasus-kasus di mana Anda tidak ingin pengguna bisa kembali ke aktivitas, atur dalam
    ++<code><a href="{@docRoot}guide/topics/manifest/activity-element.html">&lt;activity&gt;</a></code>
    ++ pada
    ++<a href="{@docRoot}guide/topics/manifest/activity-element.html#finish">{@code finishOnTaskLaunch}</a>
    ++elemen ke {@code "true"} (lihat <a href="#Clearing">Menghapus back-stack</a>).</p>
    ++
    ++<p>Informasi lebih jauh tentang cara menyatakan dan mengelola tugas dan aktivitas dalam
    ++layar ikhtisar tersedia dalam<a href="{@docRoot}guide/components/recents.html">
    ++Layar Ikhtisar</a>.</p>
    ++
    ++<!--
    ++<h2>Beginner's Path</h2>
    ++
    ++<p>For more information about how to use intents to
    ++activate other application components and publish the intents to which your components
    ++respond, continue with the <b><a
    ++href="{@docRoot}guide/components/intents-filters.html">Intents and Intent
    ++Filters</a></b> document.</p>
    ++-->
    +diff --git a/docs/html-intl/intl/id/guide/index.jd b/docs/html-intl/intl/id/guide/index.jd
    +new file mode 100644
    +index 0000000..f24fab6
    +--- /dev/null
    ++++ b/docs/html-intl/intl/id/guide/index.jd
    +@@ -0,0 +1,74 @@
    ++page.title=Pengantar Android
    ++
    ++@jd:body
    ++
    ++
    ++<div class="sidebox" style="width:220px"><!-- width to match col-4 below -->
    ++<p>Untuk mempelajari cara kerja aplikasi, mulailah dengan
    ++<a href="{@docRoot}guide/components/fundamentals.html">Dasar-Dasar Aplikasi</a>.</p>
    ++<p>Untuk langsung memulai pemrograman, bacalah <a href="{@docRoot}training/basics/firstapp/index.html">Membangun Aplikasi Pertama Anda.</a></p>
    ++</div>
    ++
    ++<p>Android menyediakan kerangka kerja aplikasi yang kaya dan memungkinkan Anda membangun aplikasi dan permainan
    ++inovatif untuk perangkat seluler di lingkungan bahasa pemrograman Java. Dokumen yang tercantum di navigasi
    ++sebelah kiri menyediakan detail tentang cara membangun aplikasi menggunakan berbagai API Android.</p>
    ++
    ++<p>Jika Anda masih baru dengan pengembangan Android, Anda perlu memahami
    ++konsep dasar berikut mengenai kerangka kerja aplikasi Android:</p>
    ++
    ++
    ++<div class="landing-banner">
    ++
    ++<div class="col-6">
    ++
    ++<h4>Aplikasi menyediakan beberapa titik masuk</h4>
    ++
    ++<p>Aplikasi Android dibangun sebagai kombinasi beragam komponen yang bisa dipanggil
    ++satu per satu. Misalnya, satu <em>aktivitas</em> individual menyediakan satu
    ++layar untuk antarmuka pengguna, dan <em>layanan</em> yang secara terpisah melakukan
    ++tugas di latar belakang.</p>
    ++
    ++<p>Dari satu komponen Anda dapat memulai komponen lainnya menggunakan <em>intent</em>. Anda bahkan dapat memulai
    ++satu komponen dalam aplikasi berbeda, seperti aktivitas dalam aplikasi peta untuk menampilkan alamat. Model ini
    ++menyediakan beberapa titik masuk untuk aplikasi tunggal dan memungkinkan setiap aplikasi untuk berfungsi sebagai "default"
    ++pengguna bagi tindakan yang dapat dipanggil aplikasi lain.</p>
    ++
    ++
    ++<p><b>Ketahui selengkapnya:</b></p>
    ++<ul class="nolist">
    ++<li><a href="{@docRoot}guide/components/fundamentals.html">Dasar-Dasar Aplikasi</a>
    ++<li><a href="{@docRoot}guide/components/intents-filters.html">Intent dan Filter Intent</a>
    ++<li><a href="{@docRoot}guide/components/activities.html">Aktivitas</a>
    ++</ul>
    ++
    ++</div>
    ++
    ++
    ++<div class="col-6">
    ++
    ++<h4>Aplikasi beradaptasi dengan perangkat berbeda</h4>
    ++
    ++<p>Android menyediakan kerangka kerja aplikasi adaptif yang memungkinkan Anda menyediakan sumber daya unik
    ++bagi konfigurasi perangkat yang berbeda-beda. Misalnya, Anda bisa membuat berbagai file layout
    ++XML untuk ukuran layar yang berbeda-beda dan sistem akan menentukan
    ++layout yang akan diterapkan berdasarkan ukuran layar perangkat yang ada saat ini.</p>
    ++
    ++<p>Anda dapat melakukan query ketersediaan fitur perangkat saat dijalankan (runtime) jika ada fitur aplikasi yang memerlukan
    ++perangkat keras spesifik seperti kamera. Jika diperlukan, Anda juga bisa mendeklarasikan fitur yang dibutuhkan aplikasi
    ++agar pasar aplikasi seperti Google Play Store tidak mengizinkan instalasi pada perangkat yang tidak
    ++mendukung fitur itu.</p>
    ++
    ++
    ++<p><b>Ketahui selengkapnya:</b></p>
    ++<ul class="nolist">
    ++<li><a href="{@docRoot}guide/practices/compatibility.html">Kompatibilitas Perangkat</a>
    ++<li><a href="{@docRoot}guide/topics/resources/overview.html">Ikhtisar Sumber Daya</a>
    ++<li><a href="{@docRoot}guide/topics/ui/overview.html">Ikhtisar Antarmuka Pengguna</a>
    ++</ul>
    ++
    ++</div>
    ++
    ++</div><!-- end landing-banner -->
    ++
    ++
    ++
    +diff --git a/docs/html-intl/intl/id/guide/platform/j8-jack.jd b/docs/html-intl/intl/id/guide/platform/j8-jack.jd
    +new file mode 100644
    +index 0000000..4389184
    +--- /dev/null
    ++++ b/docs/html-intl/intl/id/guide/platform/j8-jack.jd
    +@@ -0,0 +1,197 @@
    ++page.title=Fitur Bahasa Java 8
    ++page.keywords="android N", "Java 8", "Jack"
    ++@jd:body
    ++
    ++<div id="qv-wrapper">
    ++  <div id="qv">
    ++    <ol>
    ++      <li>
    ++        <a href="#supported-features">API dan Fitur Bahasa Java 8 yang didukung</a>
    ++      </li>
    ++      <li>
    ++        <a href="#configuration">Mengaktifkan Fitur Java 8 dan Jack Toolchain</a>
    ++      </li>
    ++    </ol>
    ++  </div>
    ++</div>
    ++
    ++<p>Android N memperkenalkan dukungan untuk fitur bahasa Java 8
    ++  yang bisa Anda gunakan saat mengembangkan aplikasi yang menargetkan Android N.
    ++  Halaman ini menjelaskan fitur bahasa baru yang didukung dalam Android N
    ++  Preview, cara menyiapkan proyek Anda dengan benar untuk menggunakannya, dan setiap masalah
    ++  yang diketahui yang mungkin Anda temui.
    ++</p>
    ++
    ++<p>Untuk mulai menggunakan fitur-fitur ini, Anda perlu mengunduh dan menyiapkan Android
    ++Studio 2.1 dan Android N Preview SDK, yang menyertakan
    ++Jack toolchain yang diperlukan dan Plugin Android untuk Gradle yang telah diperbarui. Jika Anda belum
    ++memasang Android N Preview SDK, lihat <a href="{@docRoot}preview/setup-sdk.html">Menyiapkan Pengembangan untuk Android N</a>.</p>
    ++
    ++
    ++
    ++<p class="note">
    ++  <strong>Catatan:</strong> Menggunakan fitur bahasa Java 8 yang baru bukanlah
    ++  persyaratan untuk mengembangkan aplikasi yang menargetkan platform Android N. Jika Anda
    ++  tidak ingin menulis kode dengan fitur bahasa Java 8, Anda bisa membiarkan nilai kompatibilitas
    ++  sumber dan target proyek disetel ke Java 7, namun Anda tetap harus
    ++  mengompilasi dengan JDK 8 untuk membangun pada platform Android N.
    ++</p>
    ++
    ++<h2 id="supported-features">
    ++  API dan Fitur Bahasa Java 8 yang Didukung
    ++</h2>
    ++
    ++<p>
    ++  Saat ini tidak semua fitur bahasa Java 8 didukung Android. Akan tetapi,
    ++  fitur berikut sekarang tersedia saat mengembangkan aplikasi yang menargetkan
    ++  Android N Preview:
    ++</p>
    ++
    ++<ul>
    ++  <li>
    ++    <a class="external-link" href="https://docs.oracle.com/javase/tutorial/java/IandI/defaultmethods.html">Metode
    ++    antarmuka default dan statis</a>
    ++  </li>
    ++
    ++  <li>
    ++    <a class="external-link" href="https://docs.oracle.com/javase/tutorial/java/javaOO/lambdaexpressions.html">
    ++    Ekspresi Lambda</a> (juga tersedia pada API level 23 dan yang lebih rendah)
    ++  </li>
    ++
    ++  <li>
    ++    <a class="external-link" href="https://docs.oracle.com/javase/tutorial/java/annotations/repeating.html">Anotasi
    ++    yang bisa diulang</a>
    ++  </li>
    ++
    ++  <li>
    ++    <a class="external-link" href="https://docs.oracle.com/javase/tutorial/java/javaOO/methodreferences.html">
    ++    Referensi Metode</a> (juga tersedia pada API level 23 dan yang lebih rendah)
    ++  </li>
    ++</ul>
    ++
    ++<p class="note">
    ++  <strong>Catatan:</strong> Untuk menguji ekspresi lambda dan referensi metode pada
    ++  Android versi sebelumnya, bukalah file {@code build.gradle}
    ++  Anda, serta setel {@code compileSdkVersion} dan {@code targetSdkVersion} ke 23 atau
    ++  yang lebih rendah. Anda tetap perlu <a href="#configuration">mengaktifkan Jack
    ++  toolchain</a> untuk menggunakan fitur Java 8 ini.
    ++</p>
    ++
    ++<p>
    ++  Selain itu, API fitur bahasa Java 8 berikut ini sekarang tersedia:
    ++</p>
    ++
    ++<ul>
    ++  <li>Reflection API dan API terkait bahasa:
    ++    <ul>
    ++      <li>
    ++        <a class="external-link" href="https://docs.oracle.com/javase/8/docs/api/java/lang/FunctionalInterface.html">
    ++        {@code java.lang.FunctionalInterface}</a>
    ++      </li>
    ++
    ++      <li>
    ++        <a class="external-link" href="https://docs.oracle.com/javase/8/docs/api/java/lang/annotation/Repeatable.html">
    ++        {@code java.lang.annotation.Repeatable}</a>
    ++      </li>
    ++
    ++      <li>
    ++        <a class="external-link" href="https://docs.oracle.com/javase/8/docs/api/java/lang/reflect/Method.html#isDefault--">
    ++        {@code java.lang.reflect.Method.isDefault()}</a>
    ++      </li>
    ++
    ++      <li>dan Reflection API yang terkait dengan anotasi yang bisa diulang, seperti
    ++     <a class="external-link" href="https://docs.oracle.com/javase/8/docs/api/java/lang/reflect/AnnotatedElement.html#getAnnotationsByType-java.lang.Class-">
    ++{@code AnnotatedElement.getAnnotationsByType(Class)}</a>
    ++      </li>
    ++    </ul>
    ++  </li>
    ++
    ++  <li>Utility API:
    ++    <ul>
    ++      <li>
    ++        <a class="external-link" href="https://docs.oracle.com/javase/8/docs/api/java/util/function/package-summary.html">
    ++        {@code java.util.function}</a>
    ++      </li>
    ++
    ++      <li>
    ++        <a class="external-link" href="https://docs.oracle.com/javase/8/docs/api/java/util/stream/package-summary.html">
    ++        {@code java.util.stream}</a>
    ++      </li>
    ++    </ul>
    ++  </li>
    ++</ul>
    ++
    ++<h2 id="configuration">
    ++  Mengaktifkan Fitur Java 8 dan Jack Toolchain
    ++</h2>
    ++
    ++<p>
    ++  Agar dapat menggunakan fitur bahasa Java 8 yang baru, Anda juga perlu menggunakan
    ++  <a class="external-link" href="https://source.android.com/source/jack.html">Jack toolchain</a> yang baru.  Toolchain Android
    ++ yang baru ini mengompilasi sumber bahasa Java menjadi dex
    ++  bytecode yang bisa dibaca Android, memiliki format  pustaka {@code .jack} sendiri, dan menyediakan sebagian besar fitur toolchain
    ++  sebagai bagian dari alat bantu tunggal: pengemasan ulang, penciutan, pengaburan, dan
    ++  multidex.
    ++</p>
    ++
    ++<p>Inilah perbandingan dua toolchain yang digunakan untuk membangun file Android DEX:</p>
    ++<ul>
    ++  <li>Toolchain javac lawas:<br>
    ++  <b>javac</b> ({@code .java} --&gt; {@code .class}) --&gt; <b>dx</b> ({@code
    ++ .class} --&gt; {@code .dex})
    ++  </li>
    ++
    ++  <li>Jack Toolchain baru:<br>
    ++  <b>Jack</b> ({@code .java} --&gt; {@code .jack} --&gt; {@code .dex})
    ++  </li>
    ++</ul>
    ++
    ++<h3>
    ++  Mengonfigurasi Gradle
    ++</h3>
    ++
    ++<p>
    ++  Untuk mengaktifkan fitur bahasa Java 8 dan Jack bagi proyek Anda, masukkan
    ++  yang berikut dalam file {@code build.gradle} level modul Anda:
    ++</p>
    ++
    ++<pre>
    ++android {
    ++  ...
    ++  defaultConfig {
    ++    ...
    ++    jackOptions {
    ++      enabled true
    ++    }
    ++  }
    ++  compileOptions {
    ++    sourceCompatibility JavaVersion.VERSION_1_8
    ++    targetCompatibility JavaVersion.VERSION_1_8
    ++  }
    ++}
    ++</pre>
    ++
    ++<h3 id="known-issues">
    ++  Masalah yang Diketahui
    ++</h3>
    ++
    ++<p>
    ++  <a href="{@docRoot}tools/building/building-studio.html#instant-run">Instant
    ++  Run</a> saat ini tidak berfungsi pada Jack dan akan dinonaktifkan saat menggunakan
    ++  toolchain baru.
    ++</p>
    ++
    ++<p>Karena Jack tidak menghasilkan file kelas antara saat mengompilasi sebuah
    ++aplikasi, alat yang bergantung pada file-file ini sekarang tidak berfungsi pada Jack. Beberapa
    ++contoh alat ini adalah:</p>
    ++
    ++<ul>
    ++  <li>Pendeteksi lint yang beroperasi pada file kelas
    ++  </li>
    ++
    ++  <li>Alat dan pustaka yang mewajibkan file kelas aplikasi (misalnya
    ++pengujian instrumentasi dengan JaCoCo)
    ++  </li>
    ++</ul>
    ++
    ++<p>Jika Anda menemukan masalah lain saat menggunakan Jack, <a href="http://tools.android.com/filing-bugs">laporkan bug</a>.</p>
    +\ No newline at end of file
    +diff --git a/docs/html-intl/intl/id/guide/topics/manifest/manifest-intro.jd b/docs/html-intl/intl/id/guide/topics/manifest/manifest-intro.jd
    +new file mode 100644
    +index 0000000..050abf4
    +--- /dev/null
    ++++ b/docs/html-intl/intl/id/guide/topics/manifest/manifest-intro.jd
    +@@ -0,0 +1,517 @@
    ++page.title=Manifes Aplikasi
    ++@jd:body
    ++
    ++<div id="qv-wrapper">
    ++<div id="qv">
    ++
    ++<h2>Dalam dokumen ini</h2>
    ++<ol>
    ++<li><a href="#filestruct">Struktur File Manifes</a></li>
    ++<li><a href="#filec">Konvensi File</a>
    ++<li><a href="#filef">Fitur File</a>
    ++	<ol>
    ++	<li><a href="#ifs">Filter Intent</a></li>
    ++	<li><a href="#iconlabel">Ikon dan Label</a></li>
    ++	<li><a href="#perms">Izin</a></li>
    ++	<li><a href="#libs">Pustaka</a></li>
    ++	</ol></li>
    ++</ol>
    ++</div>
    ++</div>
    ++
    ++<p>
    ++  Setiap aplikasi harus memiliki file AndroidManifest.xml (bernama persis seperti ini) di direktori akar.
    ++ <span itemprop="description">File manifes
    ++ menyediakan informasi penting tentang aplikasi ke sistem Android,
    ++ informasi yang harus dimiliki sistem agar bisa menjalankan setiap kode
    ++aplikasi.</span> Di antaranya, manifes melakukan hal berikut ini:
    ++</p>
    ++
    ++<ul>
    ++<li>Menamai paket Java untuk aplikasi.
    ++Nama paket berfungsi sebagai identifier unik untuk aplikasi.</li>
    ++
    ++<li>Menjelaskan berbagai komponen aplikasi&mdash;aktivitas,
    ++ layanan, penerima siaran, dan penyedia konten
    ++yang membentuk aplikasi.  Menamai kelas yang mengimplementasikan setiap komponen dan
    ++mempublikasikan kemampuannya (misalnya, pesan {@link android.content.Intent
    ++Intent} mana yang bisa ditanganinya).  Deklarasi ini memberi tahu sistem Android mengenai
    ++komponennya dan dalam kondisi apa bisa diluncurkan.</li>
    ++
    ++<li>Menentukan proses yang akan menjadi host komponen aplikasi.</li>
    ++
    ++<li>Mendeklarasikan izin aplikasi mana yang harus dimiliki untuk
    ++mengakses bagian yang dilindungi pada API dan berinteraksi dengan aplikasi lain.</li>
    ++
    ++<li>Juga mendeklarasikan izin lain yang harus dimiliki untuk
    ++untuk berinteraksi dengan komponen aplikasi.</li>
    ++
    ++<li>Mencantumkan daftar kelas {@link android.app.Instrumentation} yang memberikan
    ++profil dan informasi lain saat aplikasi berjalan.  Deklarasi ini
    ++hanya ada di manifes saat aplikasi dibuat dan diuji;
    ++ deklarasi dihapus sebelum aplikasi dipublikasikan.</li>
    ++
    ++<li>Mendeklarasikan tingkat minimum API Android yang diperlukan
    ++aplikasi.</li>
    ++
    ++<li>Mencantumkan daftar pustaka yang harus ditautkan aplikasi.</li>
    ++</ul>
    ++
    ++
    ++<h2 id="filestruct">Struktur File Manifes</h2>
    ++
    ++<p>
    ++Diagram di bawah ini menampilkan struktur umum file manifes dan setiap
    ++elemen yang bisa ditampungnya.  Setiap elemen, bersama
    ++atributnya, didokumentasikan secara lengkap dalam file terpisah.  Untuk melihat
    ++informasi terperinci tentang setiap elemen, klik nama elemen dalam diagram,
    ++dalam daftar abjad elemen yang mengikuti diagram, atau penyebutan nama
    ++elemen lainnya.
    ++</p>
    ++
    ++<pre>
    ++&lt;?xml version="1.0" encoding="utf-8"?&gt;
    ++
    ++<a href="{@docRoot}guide/topics/manifest/manifest-element.html">&lt;manifest&gt;</a>
    ++
    ++    <a href="{@docRoot}guide/topics/manifest/uses-permission-element.html">&lt;uses-permission /&gt;</a>
    ++    <a href="{@docRoot}guide/topics/manifest/permission-element.html">&lt;permission /&gt;</a>
    ++    <a href="{@docRoot}guide/topics/manifest/permission-tree-element.html">&lt;permission-tree /&gt;</a>
    ++    <a href="{@docRoot}guide/topics/manifest/permission-group-element.html">&lt;permission-group /&gt;</a>
    ++    <a href="{@docRoot}guide/topics/manifest/instrumentation-element.html">&lt;instrumentation /&gt;</a>
    ++    <a href="{@docRoot}guide/topics/manifest/uses-sdk-element.html">&lt;uses-sdk /&gt;</a>
    ++    <a href="{@docRoot}guide/topics/manifest/uses-configuration-element.html">&lt;uses-configuration /&gt;</a>  <!-- ##api level 3## -->
    ++    <a href="{@docRoot}guide/topics/manifest/uses-feature-element.html">&lt;uses-feature /&gt;</a>  <!-- ##api level 4## -->
    ++    <a href="{@docRoot}guide/topics/manifest/supports-screens-element.html">&lt;supports-screens /&gt;</a>  <!-- ##api level 4## -->
    ++    <a href="{@docRoot}guide/topics/manifest/compatible-screens-element.html">&lt;compatible-screens /&gt;</a>  <!-- ##api level 9## -->
    ++    <a href="{@docRoot}guide/topics/manifest/supports-gl-texture-element.html">&lt;supports-gl-texture /&gt;</a>  <!-- ##api level 11## -->
    ++
    ++    <a href="{@docRoot}guide/topics/manifest/application-element.html">&lt;application&gt;</a>
    ++
    ++        <a href="{@docRoot}guide/topics/manifest/activity-element.html">&lt;activity&gt;</a>
    ++            <a href="{@docRoot}guide/topics/manifest/intent-filter-element.html">&lt;intent-filter&gt;</a>
    ++                <a href="{@docRoot}guide/topics/manifest/action-element.html">&lt;action /&gt;</a>
    ++                <a href="{@docRoot}guide/topics/manifest/category-element.html">&lt;category /&gt;</a>
    ++                <a href="{@docRoot}guide/topics/manifest/data-element.html">&lt;data /&gt;</a>
    ++            <a href="{@docRoot}guide/topics/manifest/intent-filter-element.html">&lt;/intent-filter&gt;</a>
    ++            <a href="{@docRoot}guide/topics/manifest/meta-data-element.html">&lt;meta-data /&gt;</a>
    ++        <a href="{@docRoot}guide/topics/manifest/activity-element.html">&lt;/activity&gt;</a>
    ++
    ++        <a href="{@docRoot}guide/topics/manifest/activity-alias-element.html">&lt;activity-alias&gt;</a>
    ++            <a href="{@docRoot}guide/topics/manifest/intent-filter-element.html">&lt;intent-filter&gt;</a> . . . <a href="{@docRoot}guide/topics/manifest/intent-filter-element.html">&lt;/intent-filter&gt;</a>
    ++            <a href="{@docRoot}guide/topics/manifest/meta-data-element.html">&lt;meta-data /&gt;</a>
    ++        <a href="{@docRoot}guide/topics/manifest/activity-alias-element.html">&lt;/activity-alias&gt;</a>
    ++
    ++        <a href="{@docRoot}guide/topics/manifest/service-element.html">&lt;service&gt;</a>
    ++            <a href="{@docRoot}guide/topics/manifest/intent-filter-element.html">&lt;intent-filter&gt;</a> . . . <a href="{@docRoot}guide/topics/manifest/intent-filter-element.html">&lt;/intent-filter&gt;</a>
    ++            <a href="{@docRoot}guide/topics/manifest/meta-data-element.html">&lt;meta-data/&gt;</a>
    ++        <a href="{@docRoot}guide/topics/manifest/service-element.html">&lt;/service&gt;</a>
    ++
    ++        <a href="{@docRoot}guide/topics/manifest/receiver-element.html">&lt;receiver&gt;</a>
    ++            <a href="{@docRoot}guide/topics/manifest/intent-filter-element.html">&lt;intent-filter&gt;</a> . . . <a href="{@docRoot}guide/topics/manifest/intent-filter-element.html">&lt;/intent-filter&gt;</a>
    ++            <a href="{@docRoot}guide/topics/manifest/meta-data-element.html">&lt;meta-data /&gt;</a>
    ++        <a href="{@docRoot}guide/topics/manifest/receiver-element.html">&lt;/receiver&gt;</a>
    ++
    ++        <a href="{@docRoot}guide/topics/manifest/provider-element.html">&lt;provider&gt;</a>
    ++            <a href="{@docRoot}guide/topics/manifest/grant-uri-permission-element.html">&lt;grant-uri-permission /&gt;</a>
    ++            <a href="{@docRoot}guide/topics/manifest/meta-data-element.html">&lt;meta-data /&gt;</a>
    ++            <a href="{@docRoot}guide/topics/manifest/path-permission-element.html">&lt;path-permission /&gt;</a>
    ++        <a href="{@docRoot}guide/topics/manifest/provider-element.html">&lt;/provider&gt;</a>
    ++
    ++        <a href="{@docRoot}guide/topics/manifest/uses-library-element.html">&lt;uses-library /&gt;</a>
    ++
    ++    <a href="{@docRoot}guide/topics/manifest/application-element.html">&lt;/application&gt;</a>
    ++
    ++<a href="{@docRoot}guide/topics/manifest/manifest-element.html">&lt;/manifest&gt;</a>
    ++</pre>
    ++
    ++<p>
    ++Semua elemen yang bisa muncul dalam file manifes tercantum di bawah ini
    ++dalam urutan abjad.  Ini adalah satu-satunya elemen legal; Anda tidak bisa
    ++menambahkan elemen atau atribut sendiri.
    ++</p>
    ++
    ++<p style="margin-left: 2em">
    ++<code><a href="{@docRoot}guide/topics/manifest/action-element.html">&lt;action&gt;</a></code>
    ++<br/><code><a href="{@docRoot}guide/topics/manifest/activity-element.html">&lt;activity&gt;</a></code>
    ++<br/><code><a href="{@docRoot}guide/topics/manifest/activity-alias-element.html">&lt;activity-alias&gt;</a></code>
    ++<br/><code><a href="{@docRoot}guide/topics/manifest/application-element.html">&lt;application&gt;</a></code>
    ++<br/><code><a href="{@docRoot}guide/topics/manifest/category-element.html">&lt;category&gt;</a></code>
    ++<br/><code><a href="{@docRoot}guide/topics/manifest/data-element.html">&lt;data&gt;</a></code>
    ++<br/><code><a href="{@docRoot}guide/topics/manifest/grant-uri-permission-element.html">&lt;grant-uri-permission&gt;</a></code>
    ++<br/><code><a href="{@docRoot}guide/topics/manifest/instrumentation-element.html">&lt;instrumentation&gt;</a></code>
    ++<br/><code><a href="{@docRoot}guide/topics/manifest/intent-filter-element.html">&lt;intent-filter&gt;</a></code>
    ++<br/><code><a href="{@docRoot}guide/topics/manifest/manifest-element.html">&lt;manifest&gt;</a></code>
    ++<br/><code><a href="{@docRoot}guide/topics/manifest/meta-data-element.html">&lt;meta-data&gt;</a></code>
    ++<br/><code><a href="{@docRoot}guide/topics/manifest/permission-element.html">&lt;permission&gt;</a></code>
    ++<br/><code><a href="{@docRoot}guide/topics/manifest/permission-group-element.html">&lt;permission-group&gt;</a></code>
    ++<br/><code><a href="{@docRoot}guide/topics/manifest/permission-tree-element.html">&lt;permission-tree&gt;</a></code>
    ++<br/><code><a href="{@docRoot}guide/topics/manifest/provider-element.html">&lt;provider&gt;</a></code>
    ++<br/><code><a href="{@docRoot}guide/topics/manifest/receiver-element.html">&lt;receiver&gt;</a></code>
    ++<br/><code><a href="{@docRoot}guide/topics/manifest/service-element.html">&lt;service&gt;</a></code>
    ++<br/><code><a href="{@docRoot}guide/topics/manifest/supports-screens-element.html">&lt;supports-screens&gt;</a></code>  <!-- ##api level 4## -->
    ++<br/><code><a href="{@docRoot}guide/topics/manifest/uses-configuration-element.html">&lt;uses-configuration&gt;</a></code>  <!-- ##api level 3## -->
    ++<br/><code><a href="{@docRoot}guide/topics/manifest/uses-feature-element.html">&lt;uses-feature&gt;</a></code>  <!-- ##api level 4## -->
    ++<br/><code><a href="{@docRoot}guide/topics/manifest/uses-library-element.html">&lt;uses-library&gt;</a></code>
    ++<br/><code><a href="{@docRoot}guide/topics/manifest/uses-permission-element.html">&lt;uses-permission&gt;</a></code>
    ++<br/><code><a href="{@docRoot}guide/topics/manifest/uses-sdk-element.html">&lt;uses-sdk&gt;</a></code>
    ++</p>
    ++
    ++
    ++
    ++
    ++<h2 id="filec">Konvensi File</h2>
    ++
    ++<p>
    ++Sebagian konvensi dan aturan berlaku secara umum untuk semua elemen
    ++dan atribut di manifes:
    ++</p>
    ++
    ++<dl>
    ++<dt><b>Elemen</b></dt>
    ++<dd>Hanya elemen
    ++<code><a href="{@docRoot}guide/topics/manifest/manifest-element.html">&lt;manifest&gt;</a></code> dan
    ++<code><a href="{@docRoot}guide/topics/manifest/application-element.html">&lt;application&gt;</a></code>
    ++yang diwajibkan, masing-masing harus ada dan hanya boleh terjadi sekali.
    ++Umumnya elemen lain bisa terjadi berkali-kali atau sama sekali tidak terjadi &mdash; meskipun
    ++setidaknya sebagian dari elemen itu harus ada untuk agar manifes mencapai sesuatu yang
    ++berarti.
    ++
    ++<p>
    ++Jika elemen tidak berisi apa pun, berarti elemen itu berisi elemen lain.
    ++Semua nilai diatur melalui atribut, bukan sebagai data karakter dalam elemen.
    ++</p>
    ++
    ++<p>
    ++Elemen yang sama tingkatan umumnya tidak diurutkan.  Misalnya, elemen
    ++<code><a href="{@docRoot}guide/topics/manifest/activity-element.html">&lt;activity&gt;</a></code>,
    ++<code><a href="{@docRoot}guide/topics/manifest/provider-element.html">&lt;provider&gt;</a></code>, dan
    ++<code><a href="{@docRoot}guide/topics/manifest/service-element.html">&lt;service&gt;</a></code>
    ++bisa dicampur dalam urutan apa pun.  (Elemen
    ++<code><a href="{@docRoot}guide/topics/manifest/activity-alias-element.html">&lt;activity-alias&gt;</a></code>
    ++ merupakan eksepsi untuk aturan ini:  Elemen ini harus mengikuti
    ++<code><a href="{@docRoot}guide/topics/manifest/activity-element.html">&lt;activity&gt;</a></code>
    ++ini aliasnya.)
    ++</p></dd>
    ++
    ++<dt><b>Atribut</b></dt>
    ++<dd>Secara formal, semua atribut opsional.  Akan tetapi, ada sebagian
    ++yang harus ditetapkan agar elemen bisa mencapai tujuannya.  Gunakan
    ++dokumentasi sebagai panduan.  Bagi atribut yang benar-benar opsional, ini menyebutkan
    ++nilai default atau menyatakan apa yang terjadi jika tidak ada spesifikasi.
    ++
    ++<p>Selain untuk beberapa atribut elemen akar
    ++<code><a href="{@docRoot}guide/topics/manifest/manifest-element.html">&lt;manifest&gt;</a></code>,
    ++ semua nama atribut dimulai dengan awalan {@code android:} &mdash;
    ++misalnya, {@code android:alwaysRetainTaskState}.  Karena awalan ini universal, dokumentasi umumnya meniadakannya saat mengacu atribut
    ++dengan nama.
    ++</p></dd>
    ++
    ++<dt><b>Mendeklarasikan nama kelas</b></dt>
    ++<dd>Banyak elemen berhubungan dengan objek Java, termasuk elemen
    ++aplikasi itu sendiri (elemen
    ++<code><a href="{@docRoot}guide/topics/manifest/application-element.html">&lt;application&gt;</a></code>
    ++) dan aktivitas komponen &mdash; utamanya
    ++(<code><a href="{@docRoot}guide/topics/manifest/activity-element.html">&lt;activity&gt;</a></code>),
    ++layanan
    ++(<code><a href="{@docRoot}guide/topics/manifest/service-element.html">&lt;service&gt;</a></code>),
    ++penerima siaran
    ++(<code><a href="{@docRoot}guide/topics/manifest/receiver-element.html">&lt;receiver&gt;</a></code>),
    ++dan penyedia konten
    ++(<code><a href="{@docRoot}guide/topics/manifest/provider-element.html">&lt;provider&gt;</a></code>).
    ++
    ++<p>
    ++Jika mendefinisikan subkelas, seperti yang selalu Anda definisikan untuk kelas komponen
    ++({@link android.app.Activity}, {@link android.app.Service},
    ++{@link android.content.BroadcastReceiver}, dan {@link android.content.ContentProvider}),
    ++subkelas dideklarasikan melalui atribut {@code name}.  Nama harus menyertakan tujuan
    ++paket lengkap.
    ++Misalnya, subkelas {@link android.app.Service} mungkin dideklarasikan sebagai berikut:
    ++</p>
    ++
    ++<pre>&lt;manifest . . . &gt;
    ++    &lt;application . . . &gt;
    ++        &lt;service android:name="com.example.project.SecretService" . . . &gt;
    ++            . . .
    ++        &lt;/service&gt;
    ++        . . .
    ++    &lt;/application&gt;
    ++&lt;/manifest&gt;</pre>
    ++
    ++<p>
    ++Akan tetapi, sebagai shorthand, jika karakter pertama string adalah titik,
    ++string akan ditambahkan ke nama paket aplikasi (seperti yang ditetapkan dalam elemen
    ++<code><a href="{@docRoot}guide/topics/manifest/manifest-element.html">&lt;manifest&gt;</a></code>
    ++ melalui atribut
    ++<code><a href="{@docRoot}guide/topics/manifest/manifest-element.html#package">package</a></code>
    ++).  Penetapan berikut sama dengan di atas:
    ++</p>
    ++
    ++<pre>&lt;manifest package="com.example.project" . . . &gt;
    ++    &lt;application . . . &gt;
    ++        &lt;service android:name=".SecretService" . . . &gt;
    ++            . . .
    ++        &lt;/service&gt;
    ++        . . .
    ++    &lt;/application&gt;
    ++&lt;/manifest&gt;</pre>
    ++
    ++<p>
    ++Saat memulai komponen, Android akan membuat instance subkelas yang diberi nama.
    ++Jika subkelas tidak ditetapkan, maka akak dibuat instance kelas dasar.
    ++</p></dd>
    ++
    ++<dt><b>Banyak nilai</b></dt>
    ++<dd>Jika lebih dari satu nilai yang dapat ditetapkan, elemen ini hampir selalu
    ++diulangi, bukan menampilkan daftar banyak nilai dalam satu elemen.
    ++Misalnya, filter intent dapat mencantumkan beberapa tindakan:
    ++
    ++<pre>&lt;intent-filter . . . &gt;
    ++    &lt;action android:name="android.intent.action.EDIT" /&gt;
    ++    &lt;action android:name="android.intent.action.INSERT" /&gt;
    ++    &lt;action android:name="android.intent.action.DELETE" /&gt;
    ++    . . .
    ++&lt;/intent-filter&gt;</pre></dd>
    ++
    ++<dt><b>Nilai sumber daya</b></dt>
    ++<dd>Beberapa atribut memiliki nilai yang bisa ditampilkan kepada pengguna &mdash; misalnya
    ++, label dan ikon aktivitas.  Nilai atribut ini
    ++harus dilokalkan dan karenanya ditetapkan dari sumber daya atau tema.  Nilai sumber
    ++daya dinyatakan dalam format berikut,</p>
    ++
    ++<p style="margin-left: 2em">{@code @[<i>package</i>:]<i>type</i>:<i>name</i>}</p>
    ++
    ++<p>
    ++dalam hal ini nama <i>package</i> boleh dihilangkan jika sumber daya ada dalam paket yang sama dengan
    ++dengan aplikasi, <i>type</i> adalah tipe sumber daya &mdash; seperti "string" atau
    ++"drawable" &mdash; dan <i>name</i> adalah nama yang mengidentifikasi sumber daya tertentu.
    ++Misalnya:
    ++</p>
    ++
    ++<pre>&lt;activity android:icon="@drawable/smallPic" . . . &gt</pre>
    ++
    ++<p>
    ++Nilai tema diekspresikan dengan cara yang sama, namun dengan awal '{@code ?}'
    ++dan bukan '{@code @}':
    ++</p>
    ++
    ++<p style="margin-left: 2em">{@code ?[<i>package</i>:]<i>type</i>:<i>name</i>}
    ++</p></dd>
    ++
    ++<dt><b>Nilai-nilai string</b></dt>
    ++<dd>Bila nilai atribut adalah string, dua garis miring kiri ('{@code \\}')
    ++harus digunakan untuk meninggalkan karakter &mdash; misalnya, '{@code \\n}' untuk
    ++baris baru atau '{@code \\uxxxx}' untuk karakter Unicode.</dd>
    ++</dl>
    ++
    ++
    ++<h2 id="filef">Fitur File</h2>
    ++
    ++<p>
    ++Bagian berikut menjelaskan cara menerapkan sebagian fitur Android
    ++dalam file manifest.
    ++</p>
    ++
    ++
    ++<h3 id="ifs">Filter Intent</h3>
    ++
    ++<p>
    ++Komponen inti dari aplikasi (aktivitasnya, layanannya, dan penerima
    ++siaran) diaktifkan oleh <i>intent</i>.  Intent adalah
    ++sekumpulan informasi (objek {@link android.content.Intent}) yang menjelaskan
    ++tindakan yang diinginkan &mdash; termasuk data yang akan ditindaklanjuti, kategori
    ++komponen yang harus melakukan tindakan, dan petunjuk terkait lainnya.
    ++Android mencari komponen yang sesuai untuk merespons intent, meluncurkan
    ++instance komponen baru jika diperlukan, dan meneruskannya ke
    ++objek Intent.
    ++</p>
    ++
    ++<p>
    ++Komponen mengiklankan kemampuannya &mdash; jenis intent yang bisa diresponsnya
    ++ &mdash; melalui <i>filter intent</i>.  Karena sistem Android
    ++harus mempelajari intent yang dapat ditangani komponen sebelum meluncurkan komponen,
    ++filter intent ditetapkan dalam manifes sebagai elemen
    ++<code><a href="{@docRoot}guide/topics/manifest/intent-filter-element.html">&lt;intent-filter&gt;</a></code>
    ++.  Sebuah komponen dapat memiliki filter dalam jumlah berapa saja, masing-masing menjelaskan
    ++kemampuan yang berbeda.
    ++</p>
    ++
    ++<p>
    ++Intent yang secara eksplisit menamai komponen target akan mengaktifkan komponen itu;
    ++filter tidak berperan.  Namun intent yang tidak menetapkan target
    ++dengan nama dapat mengaktifkan komponen hanya jika dapat melewati salah satu filter
    ++komponen.
    ++</p>
    ++
    ++<p>
    ++Untuk informasi tentang cara objek Intent diuji terhadap filter intent,
    ++lihat dokumen terpisah,
    ++<a href="{@docRoot}guide/components/intents-filters.html">Intent
    ++dan Filter Intent</a>.
    ++</p>
    ++
    ++
    ++<h3 id="iconlabel">Ikon dan Label</h3>
    ++
    ++<p>
    ++Sejumlah elemen memiliki atribut {@code icon} dan {@code label} untuk
    ++ikon kecil dan label teks yang bisa ditampilkan kepada pengguna.  Sebagian ada juga yang memiliki atribut
    ++{@code description}untuk teks penjelasan yang lebih panjang yang juga bisa
    ++ditampilkan pada layar.  Misalnya, elemen
    ++<code><a href="{@docRoot}guide/topics/manifest/permission-element.html">&lt;permission&gt;</a></code>
    ++ memiliki ketiga atribut ini, jadi saat pengguna ditanya apakah akan
    ++memberi izin bagi aplikasi yang memintanya, ikon yang mewakili
    ++izin, nama izin, dan keterangan yang
    ++mengikutinya bisa ditampilkan kepada pengguna.
    ++</p>
    ++
    ++<p>
    ++Dalam setiap kasus, ikon dan label yang ditetapkan dalam elemen yang memuatnya menjadi
    ++{@code icon} default dan pengaturan {@code label} untuk semua subelemen kontainer ini.
    ++Karena itu, ikon dan label yang ditetapkan dalam elemen
    ++<code><a href="{@docRoot}guide/topics/manifest/application-element.html">&lt;application&gt;</a></code>
    ++adalah ikon dan label default untuk setiap komponen aplikasi.
    ++Demikian pula, ikon dan label yang ditetapkan untuk komponen &mdash; misalnya, elemen
    ++<code><a href="{@docRoot}guide/topics/manifest/activity-element.html">&lt;activity&gt;</a></code>
    ++&mdash; adalah pengaturan default untuk setiap elemen komponen
    ++<code><a href="{@docRoot}guide/topics/manifest/intent-filter-element.html">&lt;intent-filter&gt;</a></code>
    ++.  Jika elemen
    ++<code><a href="{@docRoot}guide/topics/manifest/application-element.html">&lt;application&gt;</a></code>
    ++menetapkan label, namun suatu aktivitas dan filter intent-nya tidak menetapkan label,
    ++maka label aplikasi akan dianggap sama-sama sebagai label aktvitas dan
    ++filter intent.
    ++</p>
    ++
    ++<p>
    ++Ikon dan label yang ditetapkan untuk filter intent digunakan untuk mewakili komponen
    ++kapan saja komponen ditampilkan kepada pengguna saat memenuhi fungsi yang
    ++diiklankan oleh filter.  Misalnya, filter dengan pengaturan
    ++"{@code android.intent.action.MAIN}" dan
    ++"{@code android.intent.category.LAUNCHER}" mengiklankan aktivitas
    ++sebagai aktivitas yang memulai aplikasi&mdash;, yaitu
    ++sebagai salah satu aktivitas yang harus ditampilkan dalam launcher aplikasi.  Ikon dan label yang
    ++diatur dalam filter karenanya adalah ikon dan label yang ditampilkan dalam launcher.
    ++</p>
    ++
    ++
    ++<h3 id="perms">Izin</h3>
    ++
    ++<p>
    ++Sebuah <i>izin</i> adalah pembatasan yang membatasi akses ke bagian
    ++kode atau ke data pada perangkat.   Pembatasan diberlakukan untuk melindungi data dan kode
    ++penting yang bisa disalahgunakan untuk mengganggu atau merusak pengalaman pengguna.
    ++</p>
    ++
    ++<p>
    ++Setiap izin diidentifikasi melalui label yang unik.  Sering kali, label menunjukkan
    ++tindakan yang dibatasi.  Misalnya, berikut ini adalah beberapa izin yang didefinisikan
    ++oleh Android:
    ++</p>
    ++
    ++<p style="margin-left: 2em">{@code android.permission.CALL_EMERGENCY_NUMBERS}
    ++<br/>{@code android.permission.READ_OWNER_DATA}
    ++<br/>{@code android.permission.SET_WALLPAPER}
    ++<br/>{@code android.permission.DEVICE_POWER}</p>
    ++
    ++<p>
    ++Sebuah fitur bisa dilindungi paling banyak oleh satu izin.
    ++</p>
    ++
    ++<p>
    ++Jika aplikasi memerlukan akses ke fitur yang dilindungi oleh izin,
    ++aplikasi harus mendeklarasikan bahwa aplikasi memerlukan izin itu dengan elemen
    ++<code><a href="{@docRoot}guide/topics/manifest/uses-permission-element.html">&lt;uses-permission&gt;</a></code>
    ++ dalam manifes.  Kemudian, bila aplikasi telah diinstal pada
    ++perangkat, installer akan menentukan apakah izin yang diminta akan diberikan atau tidak
    ++dengan memeriksa otoritas yang menandatangani
    ++sertifikat aplikasi dan, dalam beberapa kasus, bertanya pada pengguna.
    ++Jika izin diberikan, aplikasi tersebut bisa menggunakan
    ++fitur yang dilindungi.  Jika tidak, upaya aplikasi untuk mengakses fitur tersebut akan gagal
    ++tanpa ada pemberitahuan apa pun kepada pengguna.
    ++</p>
    ++
    ++<p>
    ++Aplikasi juga bisa melindungi komponennya sendiri (aktivitas, layanan,
    ++penerima siaran, dan penyedia konten) dengan izin.  Aplikasi bisa menerapkan
    ++izin mana pun yang didefinisikan oleh Android (tercantum dalam
    ++{@link android.Manifest.permission android.Manifest.permission}) atau dideklarasikan
    ++oleh aplikasi lain.  Atau aplikasi bisa mendefinisikannya sendiri.  Izin baru dideklarasikan
    ++dengan elemen
    ++<code><a href="{@docRoot}guide/topics/manifest/permission-element.html">&lt;permission&gt;</a></code>
    ++.  Misalnya, aktivitas dapat dilindungi sebagai berikut:
    ++</p>
    ++
    ++<pre>
    ++&lt;manifest . . . &gt;
    ++    &lt;permission android:name="com.example.project.DEBIT_ACCT" . . . /&gt;
    ++    &lt;uses-permission android:name="com.example.project.DEBIT_ACCT" /&gt;
    ++    . . .
    ++    &lt;application . . .&gt;
    ++        &lt;activity android:name="com.example.project.FreneticActivity"
    ++                  android:permission="com.example.project.DEBIT_ACCT"
    ++                  . . . &gt;
    ++            . . .
    ++        &lt;/activity&gt;
    ++    &lt;/application&gt;
    ++&lt;/manifest&gt;
    ++</pre>
    ++
    ++<p>
    ++Perhatikan, dalam contoh ini izin {@code DEBIT_ACCT} tidak hanya
    ++dideklarasikan dengan elemen
    ++<code><a href="{@docRoot}guide/topics/manifest/permission-element.html">&lt;permission&gt;</a></code>
    ++, penggunaannya juga diminta dengan elemen
    ++<code><a href="{@docRoot}guide/topics/manifest/uses-permission-element.html">&lt;uses-permission&gt;</a></code>
    ++.  Penggunaannya harus diminta agar komponen
    ++aplikasi lainnya bisa menjalankan aktivitas yang dilindungi, meskipun perlindungan itu
    ++diberlakukan oleh aplikasi itu sendiri.
    ++</p>
    ++
    ++<p>
    ++Dalam contoh yang sama, jika atribut {@code permission} ditetapkan
    ++untuk izin yang dideklarasikan di tempat lain
    ++lain (seperti {@code android.permission.CALL_EMERGENCY_NUMBERS}, maka atribut
    ++tidak perlu mendeklarasikannya lagi dengan elemen
    ++<code><a href="{@docRoot}guide/topics/manifest/permission-element.html">&lt;permission&gt;</a></code>
    ++.  Akan tetapi, penggunaannya masih perlu dengan
    ++<code><a href="{@docRoot}guide/topics/manifest/uses-permission-element.html">&lt;uses-permission&gt;</a></code>.
    ++</p>
    ++
    ++<p>
    ++Elemen
    ++<code><a href="{@docRoot}guide/topics/manifest/permission-tree-element.html">&lt;permission-tree&gt;</a></code>
    ++mendeklarasikan namespace untuk grup izin yang akan didefinisikan dalam
    ++kode.  Dan
    ++<code><a href="{@docRoot}guide/topics/manifest/permission-group-element.html">&lt;permission-group&gt;</a></code>
    ++mendefinisikan label untuk seperangkat izin (yang sama-sama dideklarasikan dalam manifes dengan elemen
    ++<code><a href="{@docRoot}guide/topics/manifest/permission-element.html">&lt;permission&gt;</a></code>
    ++dan yang dideklarasikan di tempat lain).  Ini hanya memengaruhi cara izin
    ++dikelompokkan saat ditampilkan kepada pengguna.  Elemen
    ++<code><a href="{@docRoot}guide/topics/manifest/permission-group-element.html">&lt;permission-group&gt;</a></code>
    ++ tidak menetapkan izin mana dimiliki grup;
    ++elemen hanya memberi nama grup.  Izin ditempatkan dalam grup
    ++dengan memberikan nama grup ke elemen
    ++<code><a href="{@docRoot}guide/topics/manifest/permission-element.html">&lt;permission&gt;</a></code>
    ++ melalui atribut
    ++<code><a href="{@docRoot}guide/topics/manifest/permission-element.html#pgroup">permissionGroup</a></code>
    ++.
    ++</p>
    ++
    ++
    ++<h3 id="libs">Pustaka</h3>
    ++
    ++<p>
    ++Setiap aplikasi ditautkan dengan pustaka default Android, yang
    ++menyertakan paket dasar untuk membangun aplikasi (dengan kelas umum
    ++seperti Activity, Service, Intent, View, Button, Application, ContentProvider,
    ++dan sebagainya).
    ++</p>
    ++
    ++<p>
    ++Akan tetapi, sebagian paket berada dalam pustakanya sendiri.  Jika aplikasi Anda
    ++menggunakan kode salah satu paket ini, aplikasi secara eksplisit meminta untuk ditautkan dengan
    ++paket tersebut.  Manifes harus berisi elemen
    ++<code><a href="{@docRoot}guide/topics/manifest/uses-library-element.html">&lt;uses-library&gt;</a></code> yang
    ++terpisah untuk menamai setiap pustaka.  (Nama pustaka bisa ditemukan
    ++dalam dokumentasi paket.)
    ++</p>
    +diff --git a/docs/html-intl/intl/id/guide/topics/providers/calendar-provider.jd b/docs/html-intl/intl/id/guide/topics/providers/calendar-provider.jd
    +new file mode 100644
    +index 0000000..3058815
    +--- /dev/null
    ++++ b/docs/html-intl/intl/id/guide/topics/providers/calendar-provider.jd
    +@@ -0,0 +1,1184 @@
    ++page.title=Penyedia Kalender
    ++@jd:body
    ++
    ++<div id="qv-wrapper">
    ++<div id="qv">
    ++    <h2>Dalam dokumen ini</h2>
    ++    <ol>
    ++  <li><a href="#overview">Dasar-Dasar</a></li>
    ++  <li><a href="#manifest">Izin Pengguna</a></li>
    ++  <li><a href="#calendar">Tabel kalender</a>
    ++<ol>
    ++      <li><a href="#query">Membuat query kalender</a></li>
    ++      <li><a href="#modify-calendar">Memodifikasi kalender</a></li>
    ++      <li><a href="#insert-calendar">Menyisipkan kalender</a></li>
    ++    </ol>
    ++  </li>
    ++  <li><a href="#events">Tabel Events</a>
    ++<ol>
    ++      <li><a href="#add-event">Menambahkan Kejadian</a></li>
    ++      <li><a href="#update-event">Memperbarui Kejadian</a></li>
    ++      <li><a href="#delete-event">Menghapus Kejadian</a></li>
    ++    </ol>
    ++  </li>
    ++  <li><a href="#attendees">Tabel peserta</a>
    ++<ol>
    ++      <li><a href="#add-attendees">Menambahkan Peserta</a></li>
    ++    </ol>
    ++  </li>
    ++  <li><a href="#reminders">Tabel pengingat</a>
    ++<ol>
    ++      <li><a href="#add-reminders">Menambahkan Pengingat</a></li>
    ++    </ol>
    ++  </li>
    ++  <li><a href="#instances">Tabel Instances</a>
    ++  <ol>
    ++      <li><a href="#query-instances">Membuat query tabel Instance</a></li>
    ++  </ol></li>
    ++  <li><a href="#intents">Intent Kalender</a>
    ++  <ol>
    ++      <li><a href="#intent-insert">Menggunakan intent untuk menyisipkan kejadian</a></li>
    ++      <li><a href="#intent-edit">Menggunakan intent untuk mengedit kejadian</a></li>
    ++      <li><a href="#intent-view">Menggunakan intent untuk menampilkan data kalender</a></li>
    ++    </ol>
    ++  </li>
    ++
    ++  <li><a href="#sync-adapter">Adaptor Sinkronisasi</a></li>
    ++</ol>
    ++
    ++    <h2>Kelas-kelas utama</h2>
    ++    <ol>
    ++      <li>{@link android.provider.CalendarContract.Calendars}</li>
    ++      <li>{@link android.provider.CalendarContract.Events}</li>
    ++      <li>{@link android.provider.CalendarContract.Attendees}</li>
    ++      <li>{@link android.provider.CalendarContract.Reminders}</li>
    ++    </ol>
    ++</div>
    ++</div>
    ++
    ++<p>Penyedia Kalender adalah repository untuk kejadian kalender seorang pengguna. API
    ++Penyedia Kalender memungkinkan Anda melakukan query, menyisipkan, memperbarui, dan menghapus
    ++pada kalender, kejadian, peserta, pengingat, dan seterusnya.</p>
    ++
    ++
    ++<p>API Penyedia Kalender bisa digunakan oleh aplikasi dan adaptor sinkronisasi. Aturannya
    ++bervariasi menurut tipe program yang membuat panggilan. Dokumen ini
    ++terutama berfokus pada penggunaan API Penyedia Kalender sebagai sebuah aplikasi. Untuk
    ++pembahasan ragam adaptor sinkronisasi, lihat
    ++<a href="#sync-adapter">Adaptor Sinkronisasi</a>.</p>
    ++
    ++
    ++<p>Biasanya, untuk membaca atau menulis data kalender, manifes aplikasi harus
    ++berisi izin yang sesuai, yang dijelaskan dalam <a href="#manifest">Izin
    ++Pengguna</a>. Untuk mempermudah dilakukannya operasi umum,
    ++Penyedia Kalender menyediakan satu set intent, seperti dijelaskan dalam <a href="#intents">Intent
    ++Kalender</a>. Semua intent ini membawa pengguna ke aplikasi Kalender untuk menyisipkan, menampilkan,
    ++dan mengedit kejadian. Pengguna berinteraksi dengan aplikasi Kalender kemudian
    ++kembali ke aplikasi semula. Jadi, aplikasi Anda tidak perlu meminta izin,
    ++juga tidak perlu menyediakan antarmuka pengguna untuk menampilkan atau membuat kejadian.</p>
    ++
    ++<h2 id="overview">Dasar-Dasar</h2>
    ++
    ++<p><a href="{@docRoot}guide/topics/providers/content-providers.html">Penyedia konten</a> menyimpan data dan menjadikannya bisa diakses oleh
    ++aplikasi. Penyedia konten yang ditawarkan oleh platform Android (termasuk Penyedia Kalender) biasanya mengekspos data sebagai satu set tabel berdasarkan
    ++model database relasional, dengan tiap baris berupa record dan tiap kolom berupa data
    ++yang memiliki tipe dan arti tertentu. Melalui API Penyedia Kalender, aplikasi
    ++dan adaptor sinkronisasi bisa mendapatkan akses baca/tulis ke tabel-tabel database yang menyimpan
    ++data kalender seorang pengguna.</p>
    ++
    ++<p>Setiap penyedia konten membuka sebuah URI publik (yang dibungkus sebagai objek
    ++{@link android.net.Uri}
    ++) yang mengidentifikasikan set datanya secara unik.  Penyedia konten yang mengontrol
    ++ beberapa set data (beberapa tabel) mengekspos URI terpisah untuk tiap set.  Semua
    ++URI untuk penyedia diawali dengan string "content://".  String ini
    ++mengidentifikasi data sebagai dikontrol oleh penyedia konten. Penyedia Kalender
    ++mendefinisikan konstanta untuk URI masing-masing kelas (tabel). URI ini
    ++memiliki format <code><em>&lt;class&gt;</em>.CONTENT_URI</code>. Misalnya,
    ++{@link android.provider.CalendarContract.Events#CONTENT_URI Events.CONTENT_URI}.</p>
    ++
    ++<p>Gambar 1 menampilkan representasi grafis model data Penyedia Kalender. Gambar ini menampilkan
    ++tabel dan bidang utama yang saling berkaitan.</p>
    ++
    ++<img src="{@docRoot}images/providers/datamodel.png" alt="Calendar Provider Data Model" />
    ++<p class="img-caption"><strong>Gambar 1.</strong> Model data Penyedia Kalender.</p>
    ++
    ++<p>Seorang pengguna bisa memiliki beberapa kalender, dan kalender yang berbeda bisa dikaitkan dengan tipe akun yang berbeda (Google Calendar, Exchange, dan seterusnya).</p>
    ++
    ++<p>{@link android.provider.CalendarContract} mendefinisikan model data dari informasi yang terkait dengan kalender dan kejadian. Data ini disimpan di sejumlah tabel, yang dicantumkan di bawah ini.</p>
    ++
    ++<table>
    ++  <tr>
    ++    <th>Tabel (Kelas)</th>
    ++    <th>Keterangan</th>
    ++  </tr>
    ++  <tr>
    ++    <td><p>{@link android.provider.CalendarContract.Calendars}</p></td>
    ++
    ++    <td>Tabel ini menyimpan
    ++informasi khusus kalender. Tiap baris dalam tabel ini berisi data untuk
    ++satu kalender, seperti nama, warna, informasi sinkronisasi, dan seterusnya.</td>
    ++  </tr>
    ++  <tr>
    ++    <td>{@link android.provider.CalendarContract.Events}</td>
    ++
    ++    <td>Tabel ini menyimpan
    ++informasi khusus kejadian. Tiap baris dalam tabel ini berisi informasi untuk satu
    ++kejadian&mdash;misalnya, judul kejadian, lokasi, waktu mulai, waktu
    ++selesai, dan seterusnya. Kejadian bisa terjadi satu kali atau bisa berulang beberapa kali. Peserta,
    ++pengingat, dan properti perluasan disimpan dalam tabel terpisah.
    ++Masing-masing memiliki sebuah {@link android.provider.CalendarContract.AttendeesColumns#EVENT_ID}
    ++yang mengacu {@link android.provider.BaseColumns#_ID} dalam tabel Events.</td>
    ++
    ++  </tr>
    ++  <tr>
    ++    <td>{@link android.provider.CalendarContract.Instances}</td>
    ++
    ++    <td>Tabel ini menyimpan
    ++waktu mulai dan waktu selesai setiap bentuk kejadian. Tiap baris dalam tabel ini
    ++mewakili satu bentuk kejadian. Untuk kejadian satu kali ada pemetaan 1:1
    ++antara instance dan kejadian. Untuk kejadian berulang, beberapa baris akan dibuat
    ++secara otomatis yang sesuai dengan beberapa kejadian itu.</td>
    ++  </tr>
    ++  <tr>
    ++    <td>{@link android.provider.CalendarContract.Attendees}</td>
    ++
    ++    <td>Tabel ini menyimpan
    ++informasi peserta (tamu) kejadian. Tiap baris mewakili satu tamu
    ++kejadian. Ini menetapkan tipe tamu dan respons kehadiran tamu
    ++untuk kejadian.</td>
    ++  </tr>
    ++  <tr>
    ++    <td>{@link android.provider.CalendarContract.Reminders}</td>
    ++
    ++    <td>Tabel ini menyimpan
    ++data peringatan/pemberitahuan. Tiap baris mewakili satu peringatan untuk sebuah kejadian. Sebuah
    ++kejadian bisa memiliki beberapa pengingat. Jumlah maksimum pengingat per kejadian
    ++ditetapkan dalam
    ++{@link android.provider.CalendarContract.CalendarColumns#MAX_REMINDERS},
    ++yang diatur oleh adaptor sinkronisasi yang
    ++memiliki kalender yang diberikan. Pengingat ditetapkan dalam menit sebelum kejadian
    ++dan memiliki metode yang menentukan cara pengguna akan diperingatkan.</td>
    ++  </tr>
    ++
    ++</table>
    ++
    ++<p>API Penyedia Kalender didesain agar luwes dan tangguh. Sementara itu
    ++, Anda perlu memberikan pengalaman pengguna akhir yang baik dan
    ++melindungi integritas kalender dan datanya. Untuk mencapainya, berikut ini adalah
    ++beberapa hal yang harus diingat saat menggunakan API ini:</p>
    ++
    ++<ul>
    ++
    ++<li><strong>Menyisipkan, memperbarui, dan menampilkan kejadian kalender.</strong> Untuk menyisipkan, mengubah, dan membaca kejadian secara langsung dari Penyedia Kalender, Anda memerlukan <a href="#manifest">izin</a> yang sesuai. Akan tetapi, jika Anda tidak sedang membuat aplikasi atau adaptor sinkronisasi kalender berfitur lengkap, maka tidak perlu meminta izin. Sebagai gantinya, Anda bisa menggunakan intent yang didukung oleh aplikasi Kalender Android untuk menyerahkan operasi baca dan tulis ke aplikasi itu. Bila menggunakan intent, aplikasi Anda akan mengirim pengguna ke aplikasi Kalender untuk melakukan operasi yang diinginkan
    ++dalam sebuah formulir yang sudah diisi. Setelah operasi selesai, formulir dikembalikan ke aplikasi Anda.
    ++Dengan mendesain aplikasi untuk melakukan operasi umum melalui Kalender,
    ++Anda akan memberi pengguna sebuah antarmuka pengguna yang konsisten dan tangguh. Inilah
    ++pendekatan yang disarankan. Untuk informasi selengkapnya, lihat <a href="#intents">Intent
    ++Kalender</a>.</p>
    ++
    ++
    ++<li><strong>Adaptor sinkronisasi.</strong> Adaptor sinkronisasi menyinkronkan data kalender
    ++pada perangkat pengguna dengan server atau sumber data lain. Dalam tabel
    ++{@link android.provider.CalendarContract.Calendars} dan
    ++{@link android.provider.CalendarContract.Events},
    ++ada kolom yang dicadangkan untuk digunakan adaptor sinkronisasi.
    ++Penyedia dan aplikasi tidak boleh memodifikasinya. Sebenarnya, tabel-tabel itu tidak
    ++terlihat kecuali jika diakses sebagai adaptor sinkronisasi. Untuk informasi selengkapnya tentang
    ++adaptor sinkronisasi, lihat <a href="#sync-adapter">Adaptor Sinkronisasi</a>.</li>
    ++
    ++</ul>
    ++
    ++
    ++<h2 id="manifest">Izin Pengguna</h2>
    ++
    ++<p>Untuk membaca data kalender, aplikasi harus menyertakan izin {@link
    ++android.Manifest.permission#READ_CALENDAR} dalam file manifesnya. File
    ++harus menyertakan izin {@link android.Manifest.permission#WRITE_CALENDAR}
    ++untuk menghapus, menyisipkan, atau memperbarui data kalender:</p>
    ++
    ++<pre>
    ++&lt;?xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot;?&gt;
    ++&lt;manifest xmlns:android=&quot;http://schemas.android.com/apk/res/android&quot;...&gt;
    ++    &lt;uses-sdk android:minSdkVersion=&quot;14&quot; /&gt;
    ++    &lt;uses-permission android:name=&quot;android.permission.READ_CALENDAR&quot; /&gt;
    ++    &lt;uses-permission android:name=&quot;android.permission.WRITE_CALENDAR&quot; /&gt;
    ++    ...
    ++&lt;/manifest&gt;
    ++</pre>
    ++
    ++
    ++<h2 id="calendar">Tabel Kalender</h2>
    ++
    ++<p>Tabel {@link android.provider.CalendarContract.Calendars} berisi data
    ++untuk tiap kalender. Kolom-kolom
    ++berikut ini bisa ditulisi oleh aplikasi maupun <a href="#sync-adapter">adaptor sinkronisasi</a>.
    ++Untuk mengetahui daftar lengkap bidang-bidang yang didukung, lihat
    ++acuan {@link android.provider.CalendarContract.Calendars}.</p>
    ++<table>
    ++  <tr>
    ++    <th>Konstanta</th>
    ++    <th>Keterangan</th>
    ++  </tr>
    ++  <tr>
    ++    <td>{@link android.provider.CalendarContract.Calendars#NAME}</td>
    ++    <td>Nama kalender.</td>
    ++  </tr>
    ++  <tr>
    ++    <td>{@link android.provider.CalendarContract.Calendars#CALENDAR_DISPLAY_NAME}</td>
    ++    <td>Nama kalender ini yang ditampilkan kepada pengguna.</td>
    ++  </tr>
    ++  <tr>
    ++    <td>{@link android.provider.CalendarContract.Calendars#VISIBLE}</td>
    ++
    ++    <td>Sebuah boolean yang menunjukkan apakah kalender dipilih untuk ditampilkan. Nilai
    ++0 menunjukkan bahwa kejadian yang terkait dengan kalender ini tidak boleh
    ++ditampilkan.  Nilai 1 menunjukkan bahwa kejadian yang terkait dengan kalender ini harus
    ++ditampilkan. Nilai ini memengaruhi pembuatan baris dalam tabel {@link
    ++android.provider.CalendarContract.Instances}.</td>
    ++
    ++
    ++  </tr>
    ++  <tr>
    ++    <td>{@link android.provider.CalendarContract.CalendarColumns#SYNC_EVENTS}</td>
    ++
    ++    <td>Sebuah boolean yang menunjukkan apakah kalender harus disinkronkan dan apakah
    ++kejadiannya harus disimpan pada perangkat. Nilai 0 berarti jangan menyinkronkan kalender ini atau
    ++simpan kejadiannya pada perangkat.  Nilai 1 berarti menyinkronkan kejadian untuk kalender ini
    ++dan simpan kejadiannya pada perangkat.</td>
    ++  </tr>
    ++</table>
    ++
    ++<h3 id="query">Membuat query kalender</h3>
    ++
    ++<p>Berikut ini adalah contoh yang menampilkan cara mendapatkan kalender yang dimiliki oleh
    ++pengguna tertentu. Untuk memudahkan, dalam contoh ini, operasi query ditampilkan dalam
    ++thread antarmuka pengguna ("thread utama"). Dalam praktiknya, hal ini harus dilakukan dalam
    ++thread asinkron, sebagai ganti pada thread utama. Untuk diskusi selengkapnya, lihat
    ++<a href="{@docRoot}guide/components/loaders.html">Loader</a>. Jika Anda tidak sekadar
    ++membaca data melainkan memodifikasinya, lihat {@link android.content.AsyncQueryHandler}.
    ++</p>
    ++
    ++
    ++<pre>
    ++// Projection array. Creating indices for this array instead of doing
    ++// dynamic lookups improves performance.
    ++public static final String[] EVENT_PROJECTION = new String[] {
    ++    Calendars._ID,                           // 0
    ++    Calendars.ACCOUNT_NAME,                  // 1
    ++    Calendars.CALENDAR_DISPLAY_NAME,         // 2
    ++    Calendars.OWNER_ACCOUNT                  // 3
    ++};
    ++
    ++// The indices for the projection array above.
    ++private static final int PROJECTION_ID_INDEX = 0;
    ++private static final int PROJECTION_ACCOUNT_NAME_INDEX = 1;
    ++private static final int PROJECTION_DISPLAY_NAME_INDEX = 2;
    ++private static final int PROJECTION_OWNER_ACCOUNT_INDEX = 3;</pre>
    ++
    ++
    ++<div class="sidebox-wrapper"> <div class="sidebox"> <h3>Mengapa Anda harus menyertakan
    ++ACCOUNT_TYPE?</h3> <p>Jika Anda membuat query pada {@link
    ++android.provider.CalendarContract.Calendars#ACCOUNT_NAME
    ++Calendars.ACCOUNT_NAME}, Anda juga harus menyertakan
    ++{@link android.provider.CalendarContract.Calendars#ACCOUNT_TYPE Calendars.ACCOUNT_TYPE}
    ++dalam pemilihan. Itu karena akun yang bersangkutan
    ++hanya dianggap unik mengingat <code>ACCOUNT_NAME</code> dan
    ++<code>ACCOUNT_TYPE</code>-nya. <code>ACCOUNT_TYPE</code> adalah string yang sesuai dengan
    ++autentikator akun yang digunakan bila akun didaftarkan dengan
    ++{@link android.accounts.AccountManager}. Ada juga sebuah tipe akun khusus yang disebut {@link
    ++android.provider.CalendarContract#ACCOUNT_TYPE_LOCAL} untuk kalender
    ++yang tidak terkait dengan akun perangkat. Akun {@link
    ++android.provider.CalendarContract#ACCOUNT_TYPE_LOCAL} tidak
    ++disinkronkan.</p> </div> </div>
    ++
    ++
    ++<p> Di bagian berikutnya pada contoh ini, Anda akan membuat query. Pemilihan
    ++akan menetapkan kriteria untuk query. Dalam contoh ini, query mencari
    ++kalender yang memiliki <code>ACCOUNT_NAME</code>
    ++"sampleuser@google.com", <code>ACCOUNT_TYPE</code>
    ++"com.google", dan <code>OWNER_ACCOUNT</code>
    ++"sampleuser@google.com". Jika Anda ingin melihat semua kalender yang
    ++telah ditampilkan pengguna, bukan hanya kalender yang dimiliki pengguna, hilangkan <code>OWNER_ACCOUNT</code>.
    ++Query tersebut akan menghasilkan objek {@link android.database.Cursor}
    ++yang bisa Anda gunakan untuk menyusuri set hasil yang dikembalikan oleh
    ++query database. Untuk diskusi selengkapnya tentang penggunaan query dalam penyedia konten,
    ++lihat <a href="{@docRoot}guide/topics/providers/content-providers.html">Penyedia Kalender</a>.</p>
    ++
    ++
    ++<pre>// Run query
    ++Cursor cur = null;
    ++ContentResolver cr = getContentResolver();
    ++Uri uri = Calendars.CONTENT_URI;
    ++String selection = "((" + Calendars.ACCOUNT_NAME + " = ?) AND ("
    ++                        + Calendars.ACCOUNT_TYPE + " = ?) AND ("
    ++                        + Calendars.OWNER_ACCOUNT + " = ?))";
    ++String[] selectionArgs = new String[] {"sampleuser@gmail.com", "com.google",
    ++        "sampleuser@gmail.com"};
    ++// Submit the query and get a Cursor object back.
    ++cur = cr.query(uri, EVENT_PROJECTION, selection, selectionArgs, null);</pre>
    ++
    ++<p>Bagian berikutnya ini menggunakan kursor untuk merunut set hasil. Bagian ini menggunakan
    ++konstanta yang disiapkan pada awal contoh ini untuk menghasilkan nilai-nilai
    ++bagi tiap bidang.</p>
    ++
    ++<pre>// Use the cursor to step through the returned records
    ++while (cur.moveToNext()) {
    ++    long calID = 0;
    ++    String displayName = null;
    ++    String accountName = null;
    ++    String ownerName = null;
    ++
    ++    // Get the field values
    ++    calID = cur.getLong(PROJECTION_ID_INDEX);
    ++    displayName = cur.getString(PROJECTION_DISPLAY_NAME_INDEX);
    ++    accountName = cur.getString(PROJECTION_ACCOUNT_NAME_INDEX);
    ++    ownerName = cur.getString(PROJECTION_OWNER_ACCOUNT_INDEX);
    ++
    ++    // Do something with the values...
    ++
    ++   ...
    ++}
    ++</pre>
    ++
    ++<h3 id="modify-calendar">Memodifikasi kalender</h3>
    ++
    ++<p>Untuk melakukan pembaruan kalender, Anda bisa menyediakan {@link
    ++android.provider.BaseColumns#_ID} kalender itu baik sebagai ID yang ditambahkan ke
    ++URI
    ++
    ++({@link android.content.ContentUris#withAppendedId(android.net.Uri,long) withAppendedId()})
    ++atau sebagai item pemilihan pertama. Pemilihan
    ++harus diawali dengan <code>&quot;_id=?&quot;</code>, dan
    ++<code>selectionArg</code> pertama harus berupa {@link
    ++android.provider.BaseColumns#_ID} kalender.
    ++Anda juga bisa melakukan pembaruan dengan menuliskan kode ID dalam URI. Contoh ini mengubah
    ++nama tampilan kalender dengan pendekatan
    ++({@link android.content.ContentUris#withAppendedId(android.net.Uri,long) withAppendedId()})
    ++:</p>
    ++
    ++<pre>private static final String DEBUG_TAG = "MyActivity";
    ++...
    ++long calID = 2;
    ++ContentValues values = new ContentValues();
    ++// The new display name for the calendar
    ++values.put(Calendars.CALENDAR_DISPLAY_NAME, &quot;Trevor's Calendar&quot;);
    ++Uri updateUri = ContentUris.withAppendedId(Calendars.CONTENT_URI, calID);
    ++int rows = getContentResolver().update(updateUri, values, null, null);
    ++Log.i(DEBUG_TAG, &quot;Rows updated: &quot; + rows);</pre>
    ++
    ++<h3 id="insert-calendar">Menyisipkan kalender</h2>
    ++
    ++<p>Kalender didesain untuk dikelola terutama oleh sebuah adaptor sinkronisasi, sehingga Anda
    ++hanya boleh menyisipkan kalender baru sebagai adaptor sinkronisasi. Biasanya,
    ++aplikasi hanya bisa membuat perubahan semu pada kalender, misalnya mengubah nama tampilan. Jika
    ++perlu membuat sebuah kalender lokal, aplikasi bisa melakukannya dengan melakukan
    ++penyisipan kalender sebagai adaptor sinkronisasi, menggunakan {@link
    ++android.provider.CalendarContract.SyncColumns#ACCOUNT_TYPE} dari {@link
    ++android.provider.CalendarContract#ACCOUNT_TYPE_LOCAL}.
    ++{@link android.provider.CalendarContract#ACCOUNT_TYPE_LOCAL}
    ++adalah sebuah tipe akun khusus untuk kalender yang tidak
    ++terkait dengan akun perangkat. Kalender tipe ini tidak disinkronkan dengan server. Untuk
    ++diskusi tentang adaptor sinkronisasi, lihat <a href="#sync-adapter">Adaptor Sinkronisasi</a>.</p>
    ++
    ++<h2 id="events">Tabel Events</h2>
    ++
    ++<p>Tabel {@link android.provider.CalendarContract.Events} berisi detail
    ++untuk tiap kejadian. Untuk menambah, memperbarui, atau menghapus kejadian, aplikasi harus
    ++menyertakan izin {@link android.Manifest.permission#WRITE_CALENDAR} dalam
    ++<a href="#manifest">file manifesnya</a>.</p>
    ++
    ++<p>Kolom-kolom Events berikut ini bisa ditulis oleh aplikasi maupun
    ++adaptor sinkronisasi. Untuk mengetahui daftar lengkap bidang-bidang yang didukung, lihat acuan {@link
    ++android.provider.CalendarContract.Events}.</p>
    ++
    ++<table>
    ++  <tr>
    ++    <th>Konstanta</th>
    ++    <th>Keterangan</th>
    ++  </tr>
    ++  <tr>
    ++    <td>{@link android.provider.CalendarContract.EventsColumns#CALENDAR_ID}</td>
    ++    <td>{@link android.provider.BaseColumns#_ID} kalender yang dimiliki kejadian.</td>
    ++  </tr>
    ++  <tr>
    ++    <td>{@link android.provider.CalendarContract.EventsColumns#ORGANIZER}</td>
    ++    <td>Email pengatur (pemilik) kejadian.</td>
    ++  </tr>
    ++  <tr>
    ++    <td>{@link android.provider.CalendarContract.EventsColumns#TITLE}</td>
    ++    <td>Judul kejadian.</td>
    ++  </tr>
    ++  <tr>
    ++    <td>{@link android.provider.CalendarContract.EventsColumns#EVENT_LOCATION}</td>
    ++    <td>Tempat kejadian. </td>
    ++  </tr>
    ++  <tr>
    ++    <td>{@link android.provider.CalendarContract.EventsColumns#DESCRIPTION}</td>
    ++    <td>Keterangan kejadian.</td>
    ++  </tr>
    ++  <tr>
    ++    <td>{@link android.provider.CalendarContract.EventsColumns#DTSTART}</td>
    ++    <td>Waktu mulai kejadian dalam milidetik UTC sejak waktu patokan. </td>
    ++  </tr>
    ++  <tr>
    ++    <td>{@link android.provider.CalendarContract.EventsColumns#DTEND}</td>
    ++    <td>Waktu selesai kejadian dalam milidetik UTC sejak waktu patokan. </td>
    ++  </tr>
    ++  <tr>
    ++    <td>{@link android.provider.CalendarContract.EventsColumns#EVENT_TIMEZONE}</td>
    ++    <td>Zona waktu kejadian.</td>
    ++  </tr>
    ++  <tr>
    ++    <td>{@link android.provider.CalendarContract.EventsColumns#EVENT_END_TIMEZONE}</td>
    ++    <td>Zona waktu untuk waktu selesai kejadian.</td>
    ++  </tr>
    ++  <tr>
    ++    <td>{@link android.provider.CalendarContract.EventsColumns#DURATION}</td>
    ++
    ++    <td>Durasi kejadian dalam format <a href="http://tools.ietf.org/html/rfc5545#section-3.8.2.5">RFC5545</a>.
    ++Misalnya, nilai <code>&quot;PT1H&quot;</code> menyatakan bahwa kejadian
    ++akan berlangsung satu jam, dan nilai <code>&quot;P2W&quot;</code> menunjukkan
    ++durasi 2 minggu. </td>
    ++
    ++
    ++  </tr>
    ++  <tr>
    ++    <td>{@link android.provider.CalendarContract.EventsColumns#ALL_DAY}</td>
    ++
    ++    <td>Nilai 1 menunjukkan kejadian ini memakan waktu sehari penuh, seperti yang didefinisikan oleh
    ++zona waktu lokal. Nilai 0 menunjukkan kejadian adalah kejadian biasa yang mungkin dimulai
    ++dan selesai pada sembarang waktu selama suatu hari.</td>
    ++
    ++
    ++  </tr>
    ++
    ++
    ++  <tr>
    ++    <td>{@link android.provider.CalendarContract.EventsColumns#RRULE}</td>
    ++
    ++    <td>Aturan perulangan untuk format kejadian. Misalnya,
    ++<code>&quot;FREQ=WEEKLY;COUNT=10;WKST=SU&quot;</code>. Anda bisa menemukan
    ++contoh selengkapnya <a href="http://tools.ietf.org/html/rfc5545#section-3.8.5.3">di sini</a>.</td>
    ++
    ++  </tr>
    ++
    ++  <tr>
    ++    <td>{@link android.provider.CalendarContract.EventsColumns#RDATE}</td>
    ++    <td>Tanggal perulangan kejadian.
    ++    Anda biasanya menggunakan {@link android.provider.CalendarContract.EventsColumns#RDATE}
    ++    bersama dengan {@link android.provider.CalendarContract.EventsColumns#RRULE}
    ++    untuk mendefinisikan satu set agregat
    ++kejadian berulang. Untuk diskusi selengkapnya, lihat <a href="http://tools.ietf.org/html/rfc5545#section-3.8.5.2">Spesifikasi RFC5545</a>.</td>
    ++</tr>
    ++
    ++  <tr>
    ++    <td>{@link android.provider.CalendarContract.EventsColumns#AVAILABILITY}</td>
    ++
    ++    <td>Jika kejadian ini dihitung sebagai waktu sibuk atau waktu bebas yang bisa
    ++dijadwalkan. </td>
    ++
    ++  </tr>
    ++  <tr>
    ++    <td>{@link android.provider.CalendarContract.EventsColumns#GUESTS_CAN_MODIFY}</td>
    ++    <td>Apakah tamu bisa memodifikasi kejadian atau tidak. </td>
    ++  </tr>
    ++  <tr>
    ++    <td>{@link android.provider.CalendarContract.EventsColumns#GUESTS_CAN_INVITE_OTHERS}</td>
    ++    <td>Apakah tamu bisa mengundang tamu lain atau tidak. </td>
    ++  </tr>
    ++  <tr>
    ++    <td>{@link android.provider.CalendarContract.EventsColumns#GUESTS_CAN_SEE_GUESTS}</td>
    ++    <td>Apakah tamu bisa membaca daftar peserta atau tidak.</td>
    ++  </tr>
    ++</table>
    ++
    ++<h3 id="add-event">Menambahkan Kejadian</h3>
    ++
    ++<p>Bila aplikasi Anda menyisipkan kejadian baru, sebaiknya Anda menggunakan
    ++Intent {@link android.content.Intent#ACTION_INSERT INSERT}, seperti dijelaskan dalam <a href="#intent-insert">Menggunakan intent untuk menyisipkan kejadian</a>. Akan tetapi, jika
    ++perlu, Anda bisa menyisipkan kejadian secara langsung. Bagian ini menjelaskan
    ++caranya.</p>
    ++
    ++
    ++<p>Berikut ini adalah aturan untuk menyisipkan kejadian baru: </p>
    ++<ul>
    ++
    ++  <li>Anda harus menyertakan {@link
    ++android.provider.CalendarContract.EventsColumns#CALENDAR_ID} dan {@link
    ++android.provider.CalendarContract.EventsColumns#DTSTART}.</li>
    ++
    ++<li>Anda harus menyertakan {@link
    ++android.provider.CalendarContract.EventsColumns#EVENT_TIMEZONE}. Untuk mendapatkan daftar
    ++ID zona waktu yang diinstal pada sistem, gunakan {@link
    ++java.util.TimeZone#getAvailableIDs()}. Perhatikan bahwa aturan ini tidak berlaku jika
    ++Anda menyisipkan kejadian melalui Intent {@link
    ++android.content.Intent#ACTION_INSERT INSERT}, yang dijelaskan dalam <a href="#intent-insert">Menggunakan intent untuk menyisipkan kejadian</a>&mdash;dalam
    ++skenario itu, sebuah zona waktu default akan diberikan.</li>
    ++
    ++  <li>Untuk kejadian tidak-berulang, Anda harus menyertakan {@link
    ++android.provider.CalendarContract.EventsColumns#DTEND}. </li>
    ++
    ++
    ++  <li>Untuk kejadian berulang, Anda harus menyertakan sebuah {@link
    ++android.provider.CalendarContract.EventsColumns#DURATION} selain {@link
    ++android.provider.CalendarContract.EventsColumns#RRULE} atau {@link
    ++android.provider.CalendarContract.EventsColumns#RDATE}. Perhatikan bahwa aturan ini tidak berlaku jika
    ++Anda menyisipkan kejadian melalui Intent {@link
    ++android.content.Intent#ACTION_INSERT INSERT}, yang dijelaskan dalam <a href="#intent-insert">Menggunakan intent untuk menyisipkan kejadian</a>&mdash;dalam
    ++skenario itu, Anda bisa menggunakan {@link
    ++android.provider.CalendarContract.EventsColumns#RRULE} bersama {@link android.provider.CalendarContract.EventsColumns#DTSTART} dan {@link android.provider.CalendarContract.EventsColumns#DTEND}, dan aplikasi Calendar
    ++akan mengubahnya menjadi durasi secara otomatis.</li>
    ++
    ++</ul>
    ++
    ++<p>Berikut ini adalah contoh penyisipan kejadian. Penyisipan ini dilakukan dalam thread UI
    ++demi kemudahan. Dalam praktiknya, penyisipan dan pembaruan harus dilakukan di
    ++thread asinkron untuk memindahkan tindakan ke dalam thread latar belakang. Untuk
    ++informasi selengkapnya, lihat {@link android.content.AsyncQueryHandler}.</p>
    ++
    ++
    ++<pre>
    ++long calID = 3;
    ++long startMillis = 0;
    ++long endMillis = 0;
    ++Calendar beginTime = Calendar.getInstance();
    ++beginTime.set(2012, 9, 14, 7, 30);
    ++startMillis = beginTime.getTimeInMillis();
    ++Calendar endTime = Calendar.getInstance();
    ++endTime.set(2012, 9, 14, 8, 45);
    ++endMillis = endTime.getTimeInMillis();
    ++...
    ++
    ++ContentResolver cr = getContentResolver();
    ++ContentValues values = new ContentValues();
    ++values.put(Events.DTSTART, startMillis);
    ++values.put(Events.DTEND, endMillis);
    ++values.put(Events.TITLE, &quot;Jazzercise&quot;);
    ++values.put(Events.DESCRIPTION, &quot;Group workout&quot;);
    ++values.put(Events.CALENDAR_ID, calID);
    ++values.put(Events.EVENT_TIMEZONE, "America/Los_Angeles");
    ++Uri uri = cr.insert(Events.CONTENT_URI, values);
    ++
    ++// get the event ID that is the last element in the Uri
    ++long eventID = Long.parseLong(uri.getLastPathSegment());
    ++//
    ++// ... do something with event ID
    ++//
    ++//</pre>
    ++
    ++<p class="note"><strong>Catatan:</strong> Perhatikan cara contoh ini menangkap ID kejadian
    ++setelah kejadian dibuat. Inilah cara termudah untuk mendapatkan ID kejadian. Anda akan sering
    ++memerlukan ID kejadian untuk melakukan operasi kalender lainnya&mdash;misalnya, untuk menambahkan
    ++peserta atau pengingat ke kejadian.</p>
    ++
    ++
    ++<h3 id="update-event">Memperbarui Kejadian</h3>
    ++
    ++<p>Bila aplikasi Anda ingin memperbolehkan pengguna mengedit kejadian, sebaiknya
    ++gunakan Intent {@link android.content.Intent#ACTION_EDIT EDIT}, seperti
    ++dijelaskan dalam <a href="#intent-edit">Menggunakan intent untuk mengedit kejadian</a>.
    ++Akan tetapi, jika perlu, Anda bisa mengedit kejadian secara langsung. Untuk melakukan pembaruan
    ++suatu kejadian, Anda bisa memberikan <code>_ID</code>
    ++kejadian itu sebagai ID yang ditambahkan ke URI ({@link
    ++android.content.ContentUris#withAppendedId(android.net.Uri,long) withAppendedId()})
    ++atau sebagai item pemilihan pertama.
    ++Pemilihan harus dimulai dengan <code>&quot;_id=?&quot;</code>, dan
    ++<code>selectionArg</code> yang pertama harus berupa <code>_ID</code> kejadian. Anda juga bisa
    ++melakukan pembaruan dengan menggunakan pemilihan tanpa ID. Berikut ini adalah contoh pembaruan
    ++kejadian. Contoh ini mengubah judul kejadian dengan pendekatan
    ++{@link android.content.ContentUris#withAppendedId(android.net.Uri,long) withAppendedId()}
    ++:</p>
    ++
    ++
    ++<pre>private static final String DEBUG_TAG = "MyActivity";
    ++...
    ++long eventID = 188;
    ++...
    ++ContentResolver cr = getContentResolver();
    ++ContentValues values = new ContentValues();
    ++Uri updateUri = null;
    ++// The new title for the event
    ++values.put(Events.TITLE, &quot;Kickboxing&quot;);
    ++updateUri = ContentUris.withAppendedId(Events.CONTENT_URI, eventID);
    ++int rows = getContentResolver().update(updateUri, values, null, null);
    ++Log.i(DEBUG_TAG, &quot;Rows updated: &quot; + rows);  </pre>
    ++
    ++<h3 id="delete-event">Menghapus Kejadian</h3>
    ++
    ++<p>Anda bisa menghapus kejadian dengan {@link
    ++android.provider.BaseColumns#_ID} sebagai ID yang ditambahkan pada URI, atau dengan
    ++pemilihan standar. Jika Anda menggunakan ID yang ditambahkan, Anda tidak bisa melakukan pemilihan.
    ++Ada dua versi penghapusan: sebagai aplikasi dan sebagai adaptor sinkronisasi. Penghapusan
    ++aplikasi mengatur kolom yang <em>dihapus</em> ke 1. Flag ini yang memberi tahu
    ++adaptor sinkronisasi bahwa baris telah dihapus dan bahwa penghapusan ini harus
    ++diberitahukan ke server. Penghapusan adaptor sinkronisasi menghapus kejadian dari
    ++database bersama semua data terkaitnya. Berikut ini adalah contoh aplikasi
    ++yang menghapus kejadian melalui {@link android.provider.BaseColumns#_ID}-nya:</p>
    ++
    ++
    ++<pre>private static final String DEBUG_TAG = "MyActivity";
    ++...
    ++long eventID = 201;
    ++...
    ++ContentResolver cr = getContentResolver();
    ++ContentValues values = new ContentValues();
    ++Uri deleteUri = null;
    ++deleteUri = ContentUris.withAppendedId(Events.CONTENT_URI, eventID);
    ++int rows = getContentResolver().delete(deleteUri, null, null);
    ++Log.i(DEBUG_TAG, &quot;Rows deleted: &quot; + rows);
    ++</pre>
    ++
    ++<h2 id="attendees">Tabel Peserta</h2>
    ++
    ++<p>Tiap baris tabel {@link android.provider.CalendarContract.Attendees}
    ++mewakili satu peserta atau tamu dari sebuah kejadian. Memanggil
    ++{@link android.provider.CalendarContract.Reminders#query(android.content.ContentResolver, long, java.lang.String[]) query()}
    ++akan menghasilkan daftar peserta untuk
    ++kejadian dengan {@link android.provider.CalendarContract.AttendeesColumns#EVENT_ID} yang diberikan.
    ++{@link android.provider.CalendarContract.AttendeesColumns#EVENT_ID} ini
    ++harus cocok dengan {@link
    ++android.provider.BaseColumns#_ID} kejadian tertentu.</p>
    ++
    ++<p>Tabel berikut mencantumkan
    ++bidang-bidang yang bisa ditulis. Saat menyisipkan peserta baru, Anda harus menyertakan semuanya
    ++kecuali <code>ATTENDEE_NAME</code>.
    ++</p>
    ++
    ++
    ++<table>
    ++  <tr>
    ++    <th>Konstanta</th>
    ++    <th>Keterangan</th>
    ++  </tr>
    ++  <tr>
    ++    <td>{@link android.provider.CalendarContract.AttendeesColumns#EVENT_ID}</td>
    ++    <td>ID kejadian.</td>
    ++  </tr>
    ++  <tr>
    ++    <td>{@link android.provider.CalendarContract.AttendeesColumns#ATTENDEE_NAME}</td>
    ++    <td>Nama peserta.</td>
    ++  </tr>
    ++  <tr>
    ++    <td>{@link android.provider.CalendarContract.AttendeesColumns#ATTENDEE_EMAIL}</td>
    ++    <td>Alamat email peserta.</td>
    ++  </tr>
    ++  <tr>
    ++    <td>{@link android.provider.CalendarContract.AttendeesColumns#ATTENDEE_RELATIONSHIP}</td>
    ++    <td><p>Hubungan peserta dengan kejadian. Salah satu dari:</p>
    ++      <ul>
    ++        <li>{@link android.provider.CalendarContract.AttendeesColumns#RELATIONSHIP_ATTENDEE}</li>
    ++        <li>{@link android.provider.CalendarContract.AttendeesColumns#RELATIONSHIP_NONE}</li>
    ++        <li>{@link android.provider.CalendarContract.AttendeesColumns#RELATIONSHIP_ORGANIZER}</li>
    ++        <li>{@link android.provider.CalendarContract.AttendeesColumns#RELATIONSHIP_PERFORMER}</li>
    ++        <li>{@link android.provider.CalendarContract.AttendeesColumns#RELATIONSHIP_SPEAKER}</li>
    ++    </ul>
    ++    </td>
    ++  </tr>
    ++  <tr>
    ++    <td>{@link android.provider.CalendarContract.AttendeesColumns#ATTENDEE_TYPE}</td>
    ++    <td><p>Tipe peserta. Salah satu dari: </p>
    ++      <ul>
    ++        <li>{@link android.provider.CalendarContract.AttendeesColumns#TYPE_REQUIRED}</li>
    ++        <li>{@link android.provider.CalendarContract.AttendeesColumns#TYPE_OPTIONAL}</li>
    ++    </ul></td>
    ++  </tr>
    ++  <tr>
    ++    <td>{@link android.provider.CalendarContract.AttendeesColumns#ATTENDEE_STATUS}</td>
    ++    <td><p>Status kehadiran peserta. Salah satu dari:</p>
    ++      <ul>
    ++        <li>{@link android.provider.CalendarContract.AttendeesColumns#ATTENDEE_STATUS_ACCEPTED}</li>
    ++        <li>{@link android.provider.CalendarContract.AttendeesColumns#ATTENDEE_STATUS_DECLINED}</li>
    ++        <li>{@link android.provider.CalendarContract.AttendeesColumns#ATTENDEE_STATUS_INVITED}</li>
    ++        <li>{@link android.provider.CalendarContract.AttendeesColumns#ATTENDEE_STATUS_NONE}</li>
    ++        <li>{@link android.provider.CalendarContract.AttendeesColumns#ATTENDEE_STATUS_TENTATIVE}</li>
    ++    </ul></td>
    ++  </tr>
    ++</table>
    ++
    ++<h3 id="add-attendees">Menambahkan Peserta</h3>
    ++
    ++<p>Berikut ini adalah contoh yang menambahkan satu peserta ke kejadian. Perhatikan bahwa
    ++{@link android.provider.CalendarContract.AttendeesColumns#EVENT_ID}
    ++diperlukan:</p>
    ++
    ++<pre>
    ++long eventID = 202;
    ++...
    ++ContentResolver cr = getContentResolver();
    ++ContentValues values = new ContentValues();
    ++values.put(Attendees.ATTENDEE_NAME, &quot;Trevor&quot;);
    ++values.put(Attendees.ATTENDEE_EMAIL, &quot;trevor@example.com&quot;);
    ++values.put(Attendees.ATTENDEE_RELATIONSHIP, Attendees.RELATIONSHIP_ATTENDEE);
    ++values.put(Attendees.ATTENDEE_TYPE, Attendees.TYPE_OPTIONAL);
    ++values.put(Attendees.ATTENDEE_STATUS, Attendees.ATTENDEE_STATUS_INVITED);
    ++values.put(Attendees.EVENT_ID, eventID);
    ++Uri uri = cr.insert(Attendees.CONTENT_URI, values);
    ++</pre>
    ++
    ++<h2 id="reminders">Tabel Pengingat</h2>
    ++
    ++<p>Tiap baris tabel {@link android.provider.CalendarContract.Reminders}
    ++mewakili satu pengingat untuk sebuah kejadian. Memanggil
    ++{@link android.provider.CalendarContract.Reminders#query(android.content.ContentResolver, long, java.lang.String[]) query()} akan menghasilkan daftar pengingat untuk
    ++kejadian dengan
    ++{@link android.provider.CalendarContract.AttendeesColumns#EVENT_ID} yang diberikan.</p>
    ++
    ++
    ++<p>Tabel berikut mencantumkan bidang-bidang yang bisa ditulis untuk pengingat. Semua bidang harus
    ++disertakan saat menyisipkan pengingat baru. Perhatikan bahwa adaptor sinkronisasi menetapkan
    ++tipe pengingat yang didukungnya dalam tabel {@link
    ++android.provider.CalendarContract.Calendars}. Lihat
    ++{@link android.provider.CalendarContract.CalendarColumns#ALLOWED_REMINDERS}
    ++untuk detailnya.</p>
    ++
    ++
    ++<table>
    ++  <tr>
    ++    <th>Konstanta</th>
    ++    <th>Keterangan</th>
    ++  </tr>
    ++  <tr>
    ++    <td>{@link android.provider.CalendarContract.RemindersColumns#EVENT_ID}</td>
    ++    <td>ID kejadian.</td>
    ++  </tr>
    ++  <tr>
    ++    <td>{@link android.provider.CalendarContract.RemindersColumns#MINUTES}</td>
    ++    <td>Menit yang ditunggu untuk memicu kejadian pengingat.</td>
    ++  </tr>
    ++  <tr>
    ++    <td>{@link android.provider.CalendarContract.RemindersColumns#METHOD}</td>
    ++    <td><p>Metode alarm, seperti yang diatur pada server. Salah satu dari:</p>
    ++      <ul>
    ++        <li>{@link android.provider.CalendarContract.RemindersColumns#METHOD_ALERT}</li>
    ++        <li>{@link android.provider.CalendarContract.RemindersColumns#METHOD_DEFAULT}</li>
    ++        <li>{@link android.provider.CalendarContract.RemindersColumns#METHOD_EMAIL}</li>
    ++        <li>{@link android.provider.CalendarContract.RemindersColumns#METHOD_SMS}</li>
    ++    </ul></td>
    ++  </tr>
    ++</table>
    ++
    ++<h3 id="add-reminders">Menambahkan Pengingat</h3>
    ++
    ++<p>Contoh ini menambahkan pengingat ke kejadian. Pengingat dipicu 15
    ++menit sebelum kejadian.</p>
    ++<pre>
    ++long eventID = 221;
    ++...
    ++ContentResolver cr = getContentResolver();
    ++ContentValues values = new ContentValues();
    ++values.put(Reminders.MINUTES, 15);
    ++values.put(Reminders.EVENT_ID, eventID);
    ++values.put(Reminders.METHOD, Reminders.METHOD_ALERT);
    ++Uri uri = cr.insert(Reminders.CONTENT_URI, values);</pre>
    ++
    ++<h2 id="instances">Tabel Instances</h2>
    ++
    ++<p>Tabel
    ++{@link android.provider.CalendarContract.Instances} menyimpan
    ++waktu mulai dan waktu selesai kejadian. Tiap baris dalam tabel ini
    ++mewakili satu bentuk kejadian. Tabel instance tidak bisa ditulis dan hanya
    ++menyediakan sebuah cara untuk membuat query kejadian. </p>
    ++
    ++<p>Tabel berikut mencantumkan beberapa bidang yang bisa Anda query untuk suatu instance. Perhatikan
    ++bahwa zona waktu didefinisikan oleh
    ++{@link android.provider.CalendarContract.CalendarCache#KEY_TIMEZONE_TYPE}
    ++dan
    ++{@link android.provider.CalendarContract.CalendarCache#KEY_TIMEZONE_INSTANCES}.</p>
    ++
    ++
    ++<table>
    ++  <tr>
    ++    <th>Konstanta</th>
    ++    <th>Keterangan</th>
    ++  </tr>
    ++  <tr>
    ++    <td>{@link android.provider.CalendarContract.Instances#BEGIN}</td>
    ++    <td>Waktu mulai instance, dalam milidetik UTC.</td>
    ++  </tr>
    ++  <tr>
    ++    <td>{@link android.provider.CalendarContract.Instances#END}</td>
    ++    <td>Waktu selesai instance, dalam milidetik UTC.</td>
    ++  </tr>
    ++  <tr>
    ++    <td>{@link android.provider.CalendarContract.Instances#END_DAY}</td>
    ++
    ++    <td>Hari selesai Julian dari instance, relatif terhadap
    ++zona waktu Kalender.
    ++
    ++</td>
    ++  </tr>
    ++  <tr>
    ++    <td>{@link android.provider.CalendarContract.Instances#END_MINUTE}</td>
    ++
    ++    <td>Menit selesai dari instance yang diukur dari tengah malam di zona waktu
    ++Kalender.</td>
    ++
    ++  </tr>
    ++  <tr>
    ++    <td>{@link android.provider.CalendarContract.Instances#EVENT_ID}</td>
    ++    <td>Kejadian <code>_ID</code> untuk instance ini.</td>
    ++  </tr>
    ++    <tr>
    ++    <td>{@link android.provider.CalendarContract.Instances#START_DAY}</td>
    ++    <td>Hari mulai Julian dari instance, relatif terhadap zona waktu Kalender.
    ++ </td>
    ++  </tr>
    ++  <tr>
    ++    <td>{@link android.provider.CalendarContract.Instances#START_MINUTE}</td>
    ++
    ++    <td>Menit mulai dari instance yang diukur dari tengah malam, relatif terhadap
    ++zona waktu Kalender.
    ++</td>
    ++
    ++  </tr>
    ++
    ++</table>
    ++
    ++<h3 id="query-instances">Membuat query tabel Instance</h3>
    ++
    ++<p>Untuk membuat query tabel Instances, Anda perlu menetapkan rentang waktu query
    ++dalam URI. Dalam contoh ini, {@link android.provider.CalendarContract.Instances}
    ++mendapatkan akses ke bidang {@link
    ++android.provider.CalendarContract.EventsColumns#TITLE} melalui
    ++implementasi antarmuka {@link android.provider.CalendarContract.EventsColumns}-nya.
    ++Dengan kata lain, {@link
    ++android.provider.CalendarContract.EventsColumns#TITLE} dihasilkan melalui
    ++tampilan database, bukan melalui query terhadap tabel {@link
    ++android.provider.CalendarContract.Instances} mentah.</p>
    ++
    ++<pre>
    ++private static final String DEBUG_TAG = "MyActivity";
    ++public static final String[] INSTANCE_PROJECTION = new String[] {
    ++    Instances.EVENT_ID,      // 0
    ++    Instances.BEGIN,         // 1
    ++    Instances.TITLE          // 2
    ++  };
    ++
    ++// The indices for the projection array above.
    ++private static final int PROJECTION_ID_INDEX = 0;
    ++private static final int PROJECTION_BEGIN_INDEX = 1;
    ++private static final int PROJECTION_TITLE_INDEX = 2;
    ++...
    ++
    ++// Specify the date range you want to search for recurring
    ++// event instances
    ++Calendar beginTime = Calendar.getInstance();
    ++beginTime.set(2011, 9, 23, 8, 0);
    ++long startMillis = beginTime.getTimeInMillis();
    ++Calendar endTime = Calendar.getInstance();
    ++endTime.set(2011, 10, 24, 8, 0);
    ++long endMillis = endTime.getTimeInMillis();
    ++
    ++Cursor cur = null;
    ++ContentResolver cr = getContentResolver();
    ++
    ++// The ID of the recurring event whose instances you are searching
    ++// for in the Instances table
    ++String selection = Instances.EVENT_ID + " = ?";
    ++String[] selectionArgs = new String[] {"207"};
    ++
    ++// Construct the query with the desired date range.
    ++Uri.Builder builder = Instances.CONTENT_URI.buildUpon();
    ++ContentUris.appendId(builder, startMillis);
    ++ContentUris.appendId(builder, endMillis);
    ++
    ++// Submit the query
    ++cur =  cr.query(builder.build(),
    ++    INSTANCE_PROJECTION,
    ++    selection,
    ++    selectionArgs,
    ++    null);
    ++
    ++while (cur.moveToNext()) {
    ++    String title = null;
    ++    long eventID = 0;
    ++    long beginVal = 0;
    ++
    ++    // Get the field values
    ++    eventID = cur.getLong(PROJECTION_ID_INDEX);
    ++    beginVal = cur.getLong(PROJECTION_BEGIN_INDEX);
    ++    title = cur.getString(PROJECTION_TITLE_INDEX);
    ++
    ++    // Do something with the values.
    ++    Log.i(DEBUG_TAG, "Event:  " + title);
    ++    Calendar calendar = Calendar.getInstance();
    ++    calendar.setTimeInMillis(beginVal);
    ++    DateFormat formatter = new SimpleDateFormat("MM/dd/yyyy");
    ++    Log.i(DEBUG_TAG, "Date: " + formatter.format(calendar.getTime()));
    ++    }
    ++ }</pre>
    ++
    ++<h2 id="intents">Intent Kalender</h2>
    ++<p>Aplikasi Anda tidak memerlukan <a href="#manifest">izin</a> untuk membaca dan menulis data kalender. Sebagai gantinya, aplikasi bisa menggunakan intent yang didukung oleh aplikasi Kalender Android untuk menyerahkan operasi baca dan tulis ke aplikasi itu. Tabel berikut mencantumkan intent yang didukung oleh Penyedia Kalender:</p>
    ++<table>
    ++  <tr>
    ++    <th>Tindakan</th>
    ++    <th>URI</th>
    ++
    ++    <th>Keterangan</th>
    ++    <th>Ekstra</th>
    ++  </tr>
    ++  <tr>
    ++    <td><br>
    ++    {@link android.content.Intent#ACTION_VIEW VIEW} <br></td>
    ++    <td><p><code>content://com.android.calendar/time/&lt;ms_since_epoch&gt;</code></p>
    ++    Anda juga bisa mengacu ke URI dengan
    ++{@link android.provider.CalendarContract#CONTENT_URI CalendarContract.CONTENT_URI}.
    ++Untuk contoh yang menggunakan intent ini, lihat <a href="{@docRoot}guide/topics/providers/calendar-provider.html#intent-view">Menggunakan intent untuk menampilkan data kalender</a>.
    ++
    ++    </td>
    ++    <td>Membuka kalender pada waktu yang ditetapkan oleh <code>&lt;ms_since_epoch&gt;</code>.</td>
    ++    <td>Tidak ada.</td>
    ++  </tr>
    ++  <tr>
    ++    <td><p>{@link android.content.Intent#ACTION_VIEW VIEW} </p>
    ++
    ++     </td>
    ++    <td><p><code>content://com.android.calendar/events/&lt;event_id&gt;</code></p>
    ++
    ++    Anda juga bisa mengacu ke URI dengan
    ++{@link android.provider.CalendarContract.Events#CONTENT_URI Events.CONTENT_URI}.
    ++Untuk contoh yang menggunakan intent ini, lihat <a href="{@docRoot}guide/topics/providers/calendar-provider.html#intent-view">Menggunakan intent untuk menampilkan data kalender</a>.
    ++
    ++    </td>
    ++    <td>Menampilkan kejadian yang ditetapkan oleh <code>&lt;event_id&gt;</code>.</td>
    ++
    ++    <td>{@link android.provider.CalendarContract#EXTRA_EVENT_BEGIN_TIME CalendarContract.EXTRA_EVENT_BEGIN_TIME}<br>
    ++      <br>
    ++      <br>
    ++    {@link android.provider.CalendarContract#EXTRA_EVENT_END_TIME CalendarContract.EXTRA_EVENT_END_TIME}</td>
    ++  </tr>
    ++
    ++  <tr>
    ++    <td>{@link android.content.Intent#ACTION_EDIT EDIT} </td>
    ++    <td><p><code>content://com.android.calendar/events/&lt;event_id&gt;</code></p>
    ++
    ++  Anda juga bisa mengacu ke URI dengan
    ++{@link android.provider.CalendarContract.Events#CONTENT_URI Events.CONTENT_URI}.
    ++Untuk contoh penggunaan intent ini, lihat <a href="{@docRoot}guide/topics/providers/calendar-provider.html#intent-edit">Menggunakan intent untuk mengedit kejadian</a>.
    ++
    ++
    ++    </td>
    ++    <td>Mengedit kejadian yang ditetapkan oleh <code>&lt;event_id&gt;</code>.</td>
    ++
    ++    <td>{@link android.provider.CalendarContract#EXTRA_EVENT_BEGIN_TIME CalendarContract.EXTRA_EVENT_BEGIN_TIME}<br>
    ++      <br>
    ++      <br>
    ++    {@link android.provider.CalendarContract#EXTRA_EVENT_END_TIME CalendarContract.EXTRA_EVENT_END_TIME}</td>
    ++  </tr>
    ++
    ++  <tr>
    ++    <td>{@link android.content.Intent#ACTION_EDIT EDIT} <br>
    ++    <br>
    ++    {@link android.content.Intent#ACTION_INSERT INSERT} </td>
    ++    <td><p><code>content://com.android.calendar/events</code></p>
    ++
    ++   Anda juga bisa mengacu ke URI dengan
    ++{@link android.provider.CalendarContract.Events#CONTENT_URI Events.CONTENT_URI}.
    ++Untuk contoh penggunaan intent ini, lihat <a href="{@docRoot}guide/topics/providers/calendar-provider.html#intent-insert">Menggunakan intent untuk menyisipkan kejadian</a>.
    ++
    ++    </td>
    ++
    ++    <td>Membuat sebuah kejadian.</td>
    ++    <td>Ekstra apa saja yang tercantum dalam tabel di bawah.</td>
    ++  </tr>
    ++</table>
    ++
    ++<p>Tabel berikut mencantumkan ekstra intent yang didukung oleh Penyedia Kalender:
    ++</p>
    ++<table>
    ++  <tr>
    ++    <th>Ekstra Intent</th>
    ++    <th>Keterangan</th>
    ++  </tr>
    ++  <tr>
    ++    <td>{@link android.provider.CalendarContract.EventsColumns#TITLE Events.TITLE}</td>
    ++    <td>Nama kejadian.</td>
    ++  </tr>
    ++  <tr>
    ++
    ++    <td>{@link android.provider.CalendarContract#EXTRA_EVENT_BEGIN_TIME
    ++CalendarContract.EXTRA_EVENT_BEGIN_TIME}</td>
    ++    <td>Waktu mulai kejadian dalam milidetik sejak waktu patokan.</td>
    ++  </tr>
    ++  <tr>
    ++    <td>{@link android.provider.CalendarContract#EXTRA_EVENT_END_TIME
    ++CalendarContract.EXTRA_EVENT_END_TIME}</td>
    ++
    ++    <td>Waktu selesai kejadian dalam milidetik sejak waktu patokan.</td>
    ++  </tr>
    ++  <tr>
    ++    <td>{@link android.provider.CalendarContract#EXTRA_EVENT_ALL_DAY
    ++CalendarContract.EXTRA_EVENT_ALL_DAY}</td>
    ++
    ++    <td>Sebuah boolean yang menunjukkan bahwa kejadian sehari penuh. Nilai bisa
    ++<code>true</code> atau <code>false</code>.</td> </tr>
    ++  <tr>
    ++    <td>{@link android.provider.CalendarContract.EventsColumns#EVENT_LOCATION
    ++Events.EVENT_LOCATION}</td>
    ++
    ++    <td>Lokasi kejadian.</td>
    ++  </tr>
    ++  <tr>
    ++    <td>{@link android.provider.CalendarContract.EventsColumns#DESCRIPTION
    ++Events.DESCRIPTION}</td>
    ++
    ++    <td>Keterangan kejadian.</td>
    ++  </tr>
    ++  <tr>
    ++    <td>
    ++    {@link android.content.Intent#EXTRA_EMAIL Intent.EXTRA_EMAIL}</td>
    ++    <td>Alamat email mereka yang harus diundang berupa daftar yang dipisahkan koma.</td>
    ++  </tr>
    ++  <tr>
    ++    <td>
    ++    {@link android.provider.CalendarContract.EventsColumns#RRULE Events.RRULE}</td>
    ++    <td>Aturan perulangan kejadian.</td>
    ++  </tr>
    ++  <tr>
    ++    <td>
    ++    {@link android.provider.CalendarContract.EventsColumns#ACCESS_LEVEL
    ++Events.ACCESS_LEVEL}</td>
    ++
    ++    <td>Apakah kejadian bersifat privat atau publik.</td>
    ++  </tr>
    ++  <tr>
    ++    <td>{@link android.provider.CalendarContract.EventsColumns#AVAILABILITY
    ++Events.AVAILABILITY}</td>
    ++
    ++    <td>Jika kejadian ini dihitung sebagai waktu sibuk atau waktu bebas yang bisa dijadwalkan.</td>
    ++
    ++</table>
    ++<p>Bagian berikut menjelaskan cara menggunakan semua intent ini.</p>
    ++
    ++
    ++<h3 id="intent-insert">Menggunakan intent untuk menyisipkan kejadian</h3>
    ++
    ++<p>Penggunaan Intent {@link android.content.Intent#ACTION_INSERT INSERT}
    ++akan memungkinkan aplikasi Anda menyerahkan tugas penyisipan kejadian ke Kalender itu sendiri.
    ++Dengan pendekatan ini, aplikasi Anda bahkan tidak perlu menyertakan izin {@link
    ++android.Manifest.permission#WRITE_CALENDAR} dalam <a href="#manifest">file manifesnya</a>.</p>
    ++
    ++
    ++<p>Bila pengguna menjalankan aplikasi yang menggunakan pendekatan ini, aplikasi akan mengirim
    ++izin ke Kalender untuk menyelesaikan penambahan kejadian. Intent {@link
    ++android.content.Intent#ACTION_INSERT INSERT} menggunakan bidang-bidang ekstra
    ++untuk mengisi formulir lebih dahulu dengan detail kejadian dalam Kalender. Pengguna nanti bisa
    ++membatalkan kejadian, mengedit formulir sebagaimana diperlukan, atau menyimpan kejadian ke
    ++kalender mereka.</p>
    ++
    ++
    ++
    ++<p>Berikut ini adalah cuplikan kode yang menjadwalkan kejadian pada tanggal 19 Januari 2012, yang berjalan
    ++dari 7:30 pagi hingga 8:30 pagi Perhatikan hal-hal berikut tentang cuplikan kode ini:</p>
    ++
    ++<ul>
    ++  <li>Cuplikan kode ini menetapkan {@link android.provider.CalendarContract.Events#CONTENT_URI Events.CONTENT_URI}
    ++  sebagai URI-nya.</li>
    ++
    ++  <li>Cuplikan kode ini menggunakan bidang-bidang ekstra {@link
    ++android.provider.CalendarContract#EXTRA_EVENT_BEGIN_TIME
    ++CalendarContract.EXTRA_EVENT_BEGIN_TIME} dan {@link
    ++android.provider.CalendarContract#EXTRA_EVENT_END_TIME
    ++CalendarContract.EXTRA_EVENT_END_TIME} untuk mengisi dahulu formulir
    ++dengan waktu kejadian. Nilai-nilai untuk waktu ini harus dalam milidetik UTC
    ++sejak waktu patokan.</li>
    ++
    ++  <li>Cuplikan kode ini menggunakan bidang ekstra {@link android.content.Intent#EXTRA_EMAIL Intent.EXTRA_EMAIL}
    ++untuk memberikan daftar undangan yang dipisah koma, yang ditetapkan melalui alamat email.</li>
    ++
    ++</ul>
    ++<pre>
    ++Calendar beginTime = Calendar.getInstance();
    ++beginTime.set(2012, 0, 19, 7, 30);
    ++Calendar endTime = Calendar.getInstance();
    ++endTime.set(2012, 0, 19, 8, 30);
    ++Intent intent = new Intent(Intent.ACTION_INSERT)
    ++        .setData(Events.CONTENT_URI)
    ++        .putExtra(CalendarContract.EXTRA_EVENT_BEGIN_TIME, beginTime.getTimeInMillis())
    ++        .putExtra(CalendarContract.EXTRA_EVENT_END_TIME, endTime.getTimeInMillis())
    ++        .putExtra(Events.TITLE, &quot;Yoga&quot;)
    ++        .putExtra(Events.DESCRIPTION, &quot;Group class&quot;)
    ++        .putExtra(Events.EVENT_LOCATION, &quot;The gym&quot;)
    ++        .putExtra(Events.AVAILABILITY, Events.AVAILABILITY_BUSY)
    ++        .putExtra(Intent.EXTRA_EMAIL, &quot;rowan@example.com,trevor@example.com&quot;);
    ++startActivity(intent);
    ++</pre>
    ++
    ++<h3 id="intent-edit">Menggunakan intent untuk mengedit kejadian</h3>
    ++
    ++<p>Anda bisa memperbarui kejadian secara langsung, seperti dijelaskan dalam <a href="#update-event">Memperbarui kejadian</a>. Namun penggunaan Intent {@link
    ++android.content.Intent#ACTION_EDIT EDIT} memungkinkan aplikasi yang
    ++tidak memiliki izin untuk menyerahkan pengeditan kejadian ke aplikasi Kalender.
    ++Bila pengguna selesai mengedit kejadian dalam Kalender, pengguna akan dikembalikan ke
    ++aplikasi semula.</p> <p>Berikut ini adalah contoh intent yang mengatur
    ++judul baru bagi kejadian yang ditetapkan dan memungkinkan pengguna mengedit kejadian dalam Kalender.</p>
    ++
    ++
    ++<pre>long eventID = 208;
    ++Uri uri = ContentUris.withAppendedId(Events.CONTENT_URI, eventID);
    ++Intent intent = new Intent(Intent.ACTION_EDIT)
    ++    .setData(uri)
    ++    .putExtra(Events.TITLE, &quot;My New Title&quot;);
    ++startActivity(intent);</pre>
    ++
    ++<h3 id="intent-view">Menggunakan intent untuk menampilkan data kalender</h3>
    ++<p>Penyedia Kalender menyediakan dua cara menggunakan Intent {@link android.content.Intent#ACTION_VIEW VIEW}:</p>
    ++<ul>
    ++  <li>Untuk membuka Kalender pada tanggal tertentu.</li>
    ++  <li>Untuk menampilkan sebuah kejadian.</li>
    ++
    ++</ul>
    ++<p>Berikut ini adalah contoh yang menampilkan cara membuka Kalender pada tanggal tertentu:</p>
    ++<pre>// A date-time specified in milliseconds since the epoch.
    ++long startMillis;
    ++...
    ++Uri.Builder builder = CalendarContract.CONTENT_URI.buildUpon();
    ++builder.appendPath(&quot;time&quot;);
    ++ContentUris.appendId(builder, startMillis);
    ++Intent intent = new Intent(Intent.ACTION_VIEW)
    ++    .setData(builder.build());
    ++startActivity(intent);</pre>
    ++
    ++<p>Berikut ini adalah contoh yang menampilkan cara membuka kejadian untuk menampilkan:</p>
    ++<pre>long eventID = 208;
    ++...
    ++Uri uri = ContentUris.withAppendedId(Events.CONTENT_URI, eventID);
    ++Intent intent = new Intent(Intent.ACTION_VIEW)
    ++   .setData(uri);
    ++startActivity(intent);
    ++</pre>
    ++
    ++
    ++<h2 id="sync-adapter">Adaptor Sinkronisasi</h2>
    ++
    ++
    ++<p>Hanya ada perbedaan kecil dalam cara aplikasi dan adaptor sinkronisasi
    ++mengakses Penyedia Kalender:</p>
    ++
    ++<ul>
    ++  <li>Adaptor sinkronisasi perlu menetapkan bahwa dirinya sebuah adaptor sinkronisasi dengan mengatur {@link android.provider.CalendarContract#CALLER_IS_SYNCADAPTER} ke <code>true</code>.</li>
    ++
    ++
    ++  <li>Adaptor sinkronisasi perlu memberikan {@link
    ++android.provider.CalendarContract.SyncColumns#ACCOUNT_NAME} dan {@link
    ++android.provider.CalendarContract.SyncColumns#ACCOUNT_TYPE} sebagai parameter query dalam URI. </li>
    ++
    ++  <li>Adaptor sinkronisasi memiliki akses tulis ke lebih banyak kolom daripada aplikasi atau widget.
    ++  Misalnya, aplikasi hanya bisa mengubah sedikit karakteristik kalender,
    ++  misalnya nama, nama tampilan, pengaturan visibilitas, dan apakah kalender
    ++  disinkronkan atau tidak. Sebagai perbandingan, adaptor sinkronisasi bisa mengakses bukan hanya kolom-kolom itu, namun banyak kolom lainnya,
    ++  misalnya warna kalender, zona waktu, tingkat akses, lokasi, dan seterusnya.
    ++Akan tetapi, adaptor sinkronisasi dibatasi pada <code>ACCOUNT_NAME</code> dan
    ++<code>ACCOUNT_TYPE</code> yang ditetapkannya.</li> </ul>
    ++
    ++<p>Berikut ini adalah metode pembantu yang bisa Anda gunakan untuk menghasilkan URI bagi penggunaan dengan adaptor sinkronisasi:</p>
    ++<pre> static Uri asSyncAdapter(Uri uri, String account, String accountType) {
    ++    return uri.buildUpon()
    ++        .appendQueryParameter(android.provider.CalendarContract.CALLER_IS_SYNCADAPTER,&quot;true&quot;)
    ++        .appendQueryParameter(Calendars.ACCOUNT_NAME, account)
    ++        .appendQueryParameter(Calendars.ACCOUNT_TYPE, accountType).build();
    ++ }
    ++</pre>
    ++<p>Untuk contoh implementasi adaptor sinkronisasi (yang tidak terkait secara khusus dengan Kalender), lihat
    ++<a href="{@docRoot}resources/samples/SampleSyncAdapter/index.html">SampleSyncAdapter</a>.
    +diff --git a/docs/html-intl/intl/id/guide/topics/providers/contacts-provider.jd b/docs/html-intl/intl/id/guide/topics/providers/contacts-provider.jd
    +new file mode 100644
    +index 0000000..994c56b
    +--- /dev/null
    ++++ b/docs/html-intl/intl/id/guide/topics/providers/contacts-provider.jd
    +@@ -0,0 +1,2356 @@
    ++page.title=Penyedia Kontak
    ++@jd:body
    ++<div id="qv-wrapper">
    ++<div id="qv">
    ++<h2>Tampilan Cepat</h2>
    ++<ul>
    ++    <li>Repository informasi Android tentang orang.</li>
    ++    <li>
    ++        Sinkronisasi dengan web.
    ++    </li>
    ++    <li>
    ++        Mengintegrasikan data aliran sosial.
    ++    </li>
    ++</ul>
    ++<h2>Dalam dokumen ini</h2>
    ++<ol>
    ++    <li>
    ++        <a href="#InformationTypes">Organisasi Penyedia Kontak</a>
    ++    </li>
    ++    <li>
    ++        <a href="#RawContactBasics">Kontak mentah</a>
    ++    </li>
    ++    <li>
    ++        <a href="#DataBasics">Data</a>
    ++    </li>
    ++    <li>
    ++        <a href="#ContactBasics">Kontak</a>
    ++    </li>
    ++    <li>
    ++        <a href="#Sources">Data Dari Adaptor Sinkronisasi</a>
    ++    </li>
    ++    <li>
    ++        <a href="#Permissions">Izin yang Diperlukan</a>
    ++    </li>
    ++    <li>
    ++        <a href="#UserProfile">Profil Pengguna</a>
    ++    </li>
    ++    <li>
    ++        <a href="#ContactsProviderMetadata">Metadata Penyedia Kontak</a>
    ++    </li>
    ++    <li>
    ++        <a href="#Access">Akses Penyedia Kontak</a>
    ++    <li>
    ++    </li>
    ++    <li>
    ++        <a href="#SyncAdapters">Adaptor Sinkronisasi Penyedia Kontak</a>
    ++    </li>
    ++    <li>
    ++        <a href="#SocialStream">Data Aliran Sosial</a>
    ++    </li>
    ++    <li>
    ++        <a href="#AdditionalFeatures">Fitur Tambahan Penyedia Kontak</a>
    ++    </li>
    ++</ol>
    ++<h2>Kelas-kelas utama</h2>
    ++<ol>
    ++    <li>{@link android.provider.ContactsContract.Contacts}</li>
    ++    <li>{@link android.provider.ContactsContract.RawContacts}</li>
    ++    <li>{@link android.provider.ContactsContract.Data}</li>
    ++    <li>{@code android.provider.ContactsContract.StreamItems}</li>
    ++</ol>
    ++<h2>Contoh-Contoh Terkait</h2>
    ++<ol>
    ++    <li>
    ++        <a href="{@docRoot}resources/samples/ContactManager/index.html">
    ++        Contact Manager
    ++        </a>
    ++    </li>
    ++    <li>
    ++        <a href="{@docRoot}resources/samples/SampleSyncAdapter/index.html">
    ++        Contoh Adaptor Sinkronisasi</a>
    ++    </li>
    ++</ol>
    ++<h2>Lihat Juga</h2>
    ++<ol>
    ++    <li>
    ++        <a href="{@docRoot}guide/topics/providers/content-provider-basics.html">
    ++        Dasar-Dasar Penyedia Konten
    ++        </a>
    ++    </li>
    ++</ol>
    ++</div>
    ++</div>
    ++<p>
    ++    Penyedia Kontak adalah komponen Android yang tangguh dan fleksibel dalam mengelola
    ++ repository data pusat tentang orang di perangkat. Penyedia Kontak adalah sumber data
    ++ yang Anda lihat dalam aplikasi kontak perangkat, dan Anda juga bisa mengakses datanya dalam aplikasi
    ++    Anda sendiri serta mentransfer data antara perangkat dan layanan online. Penyedia mengakomodasi
    ++    berbagai sumber data dan mencoba mengelola data sebanyak mungkin untuk setiap orang, sehingga
    ++   organisasinya menjadi kompleks. Karena itu, API penyedia menyertakan
    ++    satu set kelas kontrak dan antarmuka ekstensif yang membantu pengambilan dan
    ++    modifikasi data.
    ++</p>
    ++<p>
    ++    Panduan ini menjelaskan hal-hal berikut:
    ++</p>
    ++    <ul>
    ++        <li>
    ++            Struktur penyedia dasar.
    ++        </li>
    ++        <li>
    ++            Cara mengambil data dari penyedia.
    ++        </li>
    ++        <li>
    ++            Cara memodifikasi data di penyedia.
    ++        </li>
    ++        <li>
    ++            Cara menulis adaptor sinkronisasi untuk menyinkronkan data dari server Anda ke
    ++            Penyedia Kontak.
    ++        </li>
    ++    </ul>
    ++<p>
    ++    Panduan ini beranggapan bahwa Anda mengetahui dasar-dasar penyedia konten Android. Untuk mengetahui selengkapnya
    ++    tentang penyedia konten Android, bacalah
    ++    panduan<a href="{@docRoot}guide/topics/providers/content-provider-basics.html">
    ++    Dasar-Dasar Penyedia Konten</a>. Contoh aplikasi
    ++    <a href="{@docRoot}resources/samples/SampleSyncAdapter/index.html">Sample Sync Adapter</a>
    ++    adalah contoh penggunaan adaptor sinkronisasi untuk mentransfer data antara Penyedia Kontak
    ++    dan contoh aplikasi yang memiliki host di Google Web Services.
    ++</p>
    ++<h2 id="InformationTypes">Organisasi Penyedia Kontak</h2>
    ++<p>
    ++    Penyedia Kontak adalah komponen penyedia konten Android. Komponen ini memelihara tiga tipe
    ++    data tentang seseorang, masing-masing disesuaikan dengan tabel yang ditawarkan oleh penyedia, seperti
    ++    yang terlihat dalam gambar 1:
    ++</p>
    ++<img src="{@docRoot}images/providers/contacts_structure.png" alt="" height="364" id="figure1" />
    ++<p class="img-caption">
    ++  <strong>Gambar 1.</strong> Struktur tabel Penyedia Kontak.
    ++</p>
    ++<p>
    ++    Ketiga tabel disebut secara umum menurut nama kelas kontrak. Kelas
    ++    mendefinisikan konstanta untuk URI konten, nama kolom, dan nilai kolom yang digunakan oleh tabel-tabel:
    ++</p>
    ++<dl>
    ++    <dt>
    ++        Tabel {@link android.provider.ContactsContract.Contacts}
    ++    </dt>
    ++    <dd>
    ++        Baris mewakili orang yang berbeda, berdasarkan agregrasi baris kontak mentah.
    ++    </dd>
    ++    <dt>
    ++        Tabel {@link android.provider.ContactsContract.RawContacts}
    ++    </dt>
    ++    <dd>
    ++        Baris berisi rangkuman data seseorang, untuk tipe dan akun pengguna tertentu.
    ++    </dd>
    ++    <dt>
    ++        Tabel {@link android.provider.ContactsContract.Data}
    ++    </dt>
    ++    <dd>
    ++        Baris berisi data untuk kontak mentah, seperti alamat email atau nomor telepon.
    ++    </dd>
    ++</dl>
    ++<p>
    ++    Tabel lain yang diwakili oleh kelas kontrak dalam {@link android.provider.ContactsContract}
    ++    adalah tabel tambahan yang digunakan Penyedia Kontak untuk mengelola operasinya atau mendukung
    ++    fungsi tertentu dalam kontak atau aplikasi telepon perangkat.
    ++</p>
    ++<h2 id="RawContactBasics">Kontak mentah</h2>
    ++<p>
    ++    Kontak mentah mewakili data seseorang yang berasal dari satu tipe akun dan nama
    ++  akun. Karena Penyedia Kontak memungkinkan lebih dari satu layanan online sebagai sumber
    ++    data untuk satu orang, Penyedia Kontak memungkinkan multikontak mentah untuk orang yang sama.
    ++    Multikontak mentah juga memungkinkan seorang pengguna mengombinasikan data seseorang dari lebih dari satu akun
    ++    bertipe akun yang sama.
    ++</p>
    ++<p>
    ++    Sebagian besar data untuk kontak mentah tidak disimpan dalam
    ++    tabel {@link android.provider.ContactsContract.RawContacts}. Sebagai gantinya, data tersebut disimpan dalam satu atau beberapa baris
    ++    dalam tabel {@link android.provider.ContactsContract.Data}. Setiap baris data memiliki kolom
    ++    {@link android.provider.ContactsContract.DataColumns#RAW_CONTACT_ID Data.RAW_CONTACT_ID} yang
    ++    berisi nilai {@code android.provider.BaseColumns#_ID RawContacts._ID} dari
    ++    baris {@link android.provider.ContactsContract.RawContacts} induknya.
    ++</p>
    ++<h3 id="RawContactsColumns">Kolom-kolom kontak mentah yang penting</h3>
    ++<p>
    ++    Kolom-kolom penting dalam tabel {@link android.provider.ContactsContract.RawContacts}
    ++    tercantum pada tabel 1. Bacalah catatan yang diberikan setelah tabel:
    ++</p>
    ++<p class="table-caption" id="table1">
    ++    <strong>Tabel 1.</strong> Kolom-kolom kontak mentah yang penting.
    ++</p>
    ++<table>
    ++    <tr>
    ++        <th scope="col">Nama kolom</th>
    ++        <th scope="col">Kegunaan</th>
    ++        <th scope="col">Catatan</th>
    ++    </tr>
    ++    <tr>
    ++        <td>
    ++            {@link android.provider.ContactsContract.SyncColumns#ACCOUNT_NAME}
    ++        </td>
    ++        <td>
    ++            Nama akun untuk tipe akun yang merupakan sumber kontak mentah ini.
    ++            Misalnya, nama akun dari akun Google adalah salah satu alamat Gmail
    ++   pemilik perangkat. Lihat entri berikutnya untuk
    ++            {@link android.provider.ContactsContract.SyncColumns#ACCOUNT_TYPE} untuk informasi
    ++            selengkapnya.
    ++        </td>
    ++        <td>
    ++            Format nama ini khusus untuk tipe akun ini. Format ini tidak
    ++            harus alamat email.
    ++        </td>
    ++    </tr>
    ++    <tr>
    ++        <td>
    ++            {@link android.provider.ContactsContract.SyncColumns#ACCOUNT_TYPE}
    ++        </td>
    ++        <td>
    ++            Tipe akun yang merupakan sumber kontak mentah ini. Misalnya, tipe
    ++           akun dari akun Google adalah <code>com.google</code>. Selalu batasi tipe akun Anda
    ++            dengan identifier domain untuk domain yang Anda miliki atau kontrol. Hal ini akan memastikan bahwa tipe
    ++            akun Anda bersifat unik.
    ++        </td>
    ++        <td>
    ++            Tipe akun yang menawarkan data kontak biasanya memiliki adaptor sinkronisasi terkait yang
    ++            menyinkronkan dengan Penyedia Kontak.
    ++    </tr>
    ++    <tr>
    ++        <td>
    ++            {@link android.provider.ContactsContract.RawContactsColumns#DELETED}
    ++        </td>
    ++        <td>
    ++            Flag "deleted" untuk kontak mentah.
    ++        </td>
    ++        <td>
    ++            Flag ini memungkinkan Penyedia Kontak memelihara baris secara internal hingga adaptor
    ++            sinkronisasi bisa menghapus baris dari server mereka dan akhirnya menghapus baris
    ++            dari repository.
    ++        </td>
    ++    </tr>
    ++</table>
    ++<h4>Catatan</h4>
    ++<p>
    ++    Berikut ini adalah catatan penting tentang
    ++    tabel {@link android.provider.ContactsContract.RawContacts}:
    ++</p>
    ++<ul>
    ++    <li>
    ++        Nama kontak mentah tidak disimpan di barisnya dalam
    ++        {@link android.provider.ContactsContract.RawContacts}. Sebagai gantinya, nama tersebut disimpan dalam
    ++         tabel {@link android.provider.ContactsContract.Data}, pada
    ++        baris {@link android.provider.ContactsContract.CommonDataKinds.StructuredName}. Kontak mentah
    ++        hanya memiliki satu baris dari tipe ini dalam tabel {@link android.provider.ContactsContract.Data}.
    ++    </li>
    ++    <li>
    ++        <strong>Perhatian:</strong> Untuk menggunakan data akun sendiri dalam baris kontak mentah, akun harus
    ++        didaftarkan lebih dahulu dengan {@link android.accounts.AccountManager}. Caranya, mintalah
    ++        pengguna untuk menambahkan tipe akun dan nama akun ke dalam daftar akun. Jika Anda tidak
    ++        melakukannya, Penyedia Kontak secara otomatis akan menghapus baris kontak mentah Anda.
    ++        <p>
    ++            Misalnya, Anda menginginkan aplikasi memelihara data kontak untuk layanan berbasis web
    ++            dengan domain {@code com.example.dataservice}, dan akun pengguna untuk layanan Anda
    ++            adalah {@code becky.sharp@dataservice.example.com}, pengguna harus menambahkan lebih dahulu "type"
    ++            akun ({@code com.example.dataservice}) dan "name" akun
    ++            ({@code becky.smart@dataservice.example.com}) sebelum aplikasi Anda bisa menambahkan baris kontak mentah.
    ++            Anda bisa menjelaskan ketentuan ini kepada pengguna dalam dokumentasi, atau meminta
    ++            pengguna untuk menambahkan tipe dan nama, atau keduanya. Tipe akun dan nama akun
    ++            dijelaskan lebih detail di bagian berikutnya.
    ++    </li>
    ++</ul>
    ++<h3 id="RawContactsExample">Sumber data kontak mentah</h3>
    ++<p>
    ++    Untuk memahami cara kerja kontak mentah, perhatikan pengguna "Emily Dickinson" yang mendefinisikan
    ++    tiga akun pengguna berikut pada perangkatnya:
    ++</p>
    ++<ul>
    ++    <li><code>emily.dickinson@gmail.com</code></li>
    ++    <li><code>emilyd@gmail.com</code></li>
    ++    <li>Akun Twitter "belle_of_amherst"</li>
    ++</ul>
    ++<p>
    ++    Pengguna ini telah mengaktifkan <em>Sync Contacts</em> untuk ketiga akun dalam pengaturan
    ++    <em>Accounts</em>.
    ++</p>
    ++<p>
    ++    Anggaplah Emily Dickinson membuka jendela browser, masuk ke Gmail sebagai
    ++    <code>emily.dickinson@gmail.com</code>, membuka
    ++    Contacts, dan menambahkan "Thomas Higginson". Kemudian, ia masuk ke Gmail sebagai
    ++    <code>emilyd@gmail.com</code> dan mengirimkan email kepada "Thomas Higginson", yang
    ++    menambahkan Thomas secara otomatis sebagai kontak. Ia juga mengikuti "colonel_tom" (ID Twitter Thomas Higginson) di
    ++    Twitter.
    ++</p>
    ++<p>
    ++    Penyedia Kontak membuat tiga kontak mentah akibat pekerjaan ini:
    ++</p>
    ++<ol>
    ++    <li>
    ++        Kontak mentah untuk "Thomas Higginson" yang dikaitkan dengan <code>emily.dickinson@gmail.com</code>.
    ++        Tipe akun penggunanya adalah Google.
    ++    </li>
    ++    <li>
    ++        Kontak mentah kedua untuk "Thomas Higginson" yang dikaitkan dengan <code>emilyd@gmail.com</code>.
    ++        Tipe akun pengguna juga Google. Ada kontak mentah kedua
    ++       meskipun nama tersebut identik dengan nama sebelumnya karena orang bersangkutan ditambahkan untuk
    ++        akun pengguna yang berbeda.
    ++    </li>
    ++    <li>
    ++        Kontak mentah ketiga untuk "Thomas Higginson" yang dikaitkan dengan "belle_of_amherst". Tipe
    ++        akun penggunanya adalah Twitter.
    ++    </li>
    ++</ol>
    ++<h2 id="DataBasics">Data</h2>
    ++<p>
    ++    Seperti yang telah disebutkan, data untuk kontak mentah disimpan dalam
    ++    baris {@link android.provider.ContactsContract.Data} yang ditautkan dengan nilai
    ++    <code>_ID</code> kontak mentah. Cara ini memungkinkan satu kontak mentah memiliki beberapa instance tipe data
    ++    yang sama dengan alamat email atau nomor telepon. Misalnya, jika
    ++    "Thomas Higginson" untuk {@code emilyd@gmail.com} (baris kontak mentah untuk Thomas Higginson
    ++   yang dikaitkan dengan akun Google <code>emilyd@gmail.com</code>) memiliki alamat email rumah
    ++    <code>thigg@gmail.com</code> dan alamat email kerja
    ++    <code>thomas.higginson@gmail.com</code>, Penyedia Kontak akan menyimpan dua baris alamat
    ++    email dan menautkan keduanya ke kontak mentah.
    ++</p>
    ++<p>
    ++    Perhatikan bahwa tipe data yang berbeda disimpan dalam satu tabel ini. Baris-baris nama tampilan,
    ++    nomor telepon, email, alamat surat, foto, dan data situs web semuanya bisa ditemukan dalam
    ++    tabel {@link android.provider.ContactsContract.Data}. Untuk membantu mengelola ini,
    ++    tabel {@link android.provider.ContactsContract.Data} memiliki beberapa kolom dengan nama deskriptif,
    ++    dalam kolom lain dengan nama generik. Konten kolom bernama deskriptif memiliki arti yang sama
    ++    terlepas dari tipe data dalam barisnya, sedangkan konten kolom bernama generik memiliki
    ++    arti yang berbeda-beda sesuai dengan tipe data.
    ++</p>
    ++<h3 id="DescriptiveColumns">Nama kolom deskriptif</h3>
    ++<p>
    ++    Beberapa contoh nama kolom deskriptif adalah:
    ++</p>
    ++<dl>
    ++    <dt>
    ++        {@link android.provider.ContactsContract.Data#RAW_CONTACT_ID}
    ++    </dt>
    ++    <dd>
    ++        Nilai kolom <code>_ID</code> kontak mentah untuk data ini.
    ++    </dd>
    ++    <dt>
    ++        {@link android.provider.ContactsContract.Data#MIMETYPE}
    ++    </dt>
    ++    <dd>
    ++        Tipe data yang disimpan dalam baris ini, dinyatakan berupa tipe MIME custom. Penyedia Kontak
    ++        menggunakan tipe MIME yang didefinisikan dalam subkelas
    ++        {@link android.provider.ContactsContract.CommonDataKinds}. Tipe MIME ini adalah sumber terbuka,
    ++        dan bisa digunakan oleh setiap aplikasi atau adaptor sinkronisasi yang bisa digunakan bersama Penyedia Kontak.
    ++    </dd>
    ++    <dt>
    ++        {@link android.provider.ContactsContract.DataColumns#IS_PRIMARY}
    ++    </dt>
    ++    <dd>
    ++        Jika tipe baris data ini bisa terjadi lebih dari satu kali untuk suatu kontak mentah,
    ++        kolom {@link android.provider.ContactsContract.DataColumns#IS_PRIMARY}
    ++        menandai baris data yang berisi data utama untuk tipe itu. Misalnya, jika
    ++        pengguna menekan lama sebuah nomor telepon untuk kontak dan memilih <strong>Set default</strong>,
    ++       maka baris {@link android.provider.ContactsContract.Data} yang berisi angka itu
    ++        mengatur kolom {@link android.provider.ContactsContract.DataColumns#IS_PRIMARY}-nya ke suatu
    ++        nilai bukan nol.
    ++    </dd>
    ++</dl>
    ++<h3 id="GenericColumns">Nama kolom generik</h3>
    ++<p>
    ++    Ada 15 kolom generik bernama <code>DATA1</code> hingga
    ++    <code>DATA15</code> yang tersedia secara umum dan empat kolom generik
    ++    tambahan <code>SYNC1</code> hingga <code>SYNC4</code> yang harus digunakan hanya oleh adaptor
    ++    sinkronisasi. Konstanta nama kolom generik selalu berfungsi, terlepas dari tipe
    ++    data dalam baris .
    ++</p>
    ++<p>
    ++    Kolom <code>DATA1</code> diindeks.  Penyedia Kontak selalu menggunakan kolom ini untuk
    ++    data yang diharapkan penyedia akan menjadi target yang paling sering dari suatu query. Misalnya,
    ++    dalam baris email, kolom ini berisi alamat email sebenarnya.
    ++</p>
    ++<p>
    ++    Sesuai konvensi, kolom <code>DATA15</code> dicadangkan untuk menyimpan data Binary Large Object
    ++    (BLOB) seperti thumbnail foto.
    ++</p>
    ++<h3 id="TypeSpecificNames">Nama kolom bertipe spesifik</h3>
    ++<p>
    ++    Guna memudahkan pekerjaan dengan kolom untuk tipe baris tertentu, Penyedia Kontak
    ++    juga menyediakan konstanta nama kolom bertipe spesifik, yang didefinisikan dalam subkelas
    ++    {@link android.provider.ContactsContract.CommonDataKinds}. Konstanta cuma memberikan nama
    ++    konstanta yang berbeda ke nama kolom yang sama, yang membantu Anda mengakses data dalam baris
    ++    bertipe spesifik.
    ++</p>
    ++<p>
    ++    Misalnya, kelas {@link android.provider.ContactsContract.CommonDataKinds.Email} mendefinisikan
    ++    konstanta nama kolom bertipe spesifik untuk baris {@link android.provider.ContactsContract.Data}
    ++    yang memiliki tipe MIME
    ++    {@link android.provider.ContactsContract.CommonDataKinds.Email#CONTENT_ITEM_TYPE
    ++    Email.CONTENT_ITEM_TYPE}. Kelas ini berisi konstanta
    ++    {@link android.provider.ContactsContract.CommonDataKinds.Email#ADDRESS} untuk kolom
    ++    alamat email. Nilai sesungguhnya dari
    ++    {@link android.provider.ContactsContract.CommonDataKinds.Email#ADDRESS} adalah "data1", yang
    ++    sama dengan nama generik kolom.
    ++</p>
    ++<p class="caution">
    ++    <strong>Perhatian:</strong> Jangan tambahkan data custom Anda sendiri ke
    ++    tabel {@link android.provider.ContactsContract.Data} dengan menggunakan baris yang memiliki salah satu
    ++    tipe MIME yang telah didefinisikan penyedia. Jika melakukannya, Anda bisa kehilangan data atau menyebabkan penyedia
    ++    gagal berfungsi. Misalnya, Anda seharusnya tidak menambahkan baris bertipe MIME
    ++    {@link android.provider.ContactsContract.CommonDataKinds.Email#CONTENT_ITEM_TYPE
    ++    Email.CONTENT_ITEM_TYPE} yang berisi nama pengguna sebagai ganti alamat email dalam
    ++    kolom <code>DATA1</code>. Jika Anda menggunakan tipe MIME custom sendiri untuk baris bersangkutan, maka Anda bebas
    ++    untuk mendefinisikan nama kolom bertipe spesifik dan menggunakan kolom sekehendak Anda.
    ++</p>
    ++<p>
    ++    Gambar 2 menampilkan cara kolom deskriptif dan kolom data muncul dalam
    ++    baris {@link android.provider.ContactsContract.Data}, dan cara nama kolom bertipe spesifik "melapisi"
    ++    nama kolom generik
    ++</p>
    ++<img src="{@docRoot}images/providers/data_columns.png" alt="How type-specific column names map to generic column names" height="311" id="figure2" />
    ++<p class="img-caption">
    ++  <strong>Gambar 2.</strong> Nama kolom bertipe spesifik dan nama kolom generik.
    ++</p>
    ++<h3 id="ColumnMaps">Kelas nama kolom bertipe spesifik</h3>
    ++<p>
    ++    Tabel 2 berisi daftar kelas nama kolom bertipe spesifik yang paling umum digunakan:
    ++</p>
    ++<p class="table-caption" id="table2">
    ++  <strong>Tabel 2.</strong> Kelas nama kolom bertipe spesifik</p>
    ++<table>
    ++  <tr>
    ++    <th scope="col">Kelas pemetaan</th>
    ++    <th scope="col">Tipe data</th>
    ++    <th scope="col">Catatan</th>
    ++  </tr>
    ++  <tr>
    ++    <td>{@link android.provider.ContactsContract.CommonDataKinds.StructuredName}</td>
    ++    <td>Data nama untuk kontak mentah yang dikaitkan dengan baris data ini.</td>
    ++    <td>Kontak mentah hanya memiliki salah satu baris ini.</td>
    ++  </tr>
    ++  <tr>
    ++    <td>{@link android.provider.ContactsContract.CommonDataKinds.Photo}</td>
    ++    <td>Foto utama untuk kontak mentah yang dikaitkan dengan baris data ini.</td>
    ++    <td>Kontak mentah hanya memiliki salah satu baris ini.</td>
    ++  </tr>
    ++  <tr>
    ++    <td>{@link android.provider.ContactsContract.CommonDataKinds.Email}</td>
    ++    <td>Alamat email untuk kontak mentah yang dikaitkan dengan baris data ini.</td>
    ++    <td>Kontak mentah bisa memiliki beberapa alamat email.</td>
    ++  </tr>
    ++  <tr>
    ++    <td>{@link android.provider.ContactsContract.CommonDataKinds.StructuredPostal}</td>
    ++    <td>Alamat pos untuk kontak mentah yang dikaitkan dengan baris data ini.</td>
    ++    <td>Kontak mentah bisa memiliki beberapa alamat email.</td>
    ++  </tr>
    ++  <tr>
    ++    <td>{@link android.provider.ContactsContract.CommonDataKinds.GroupMembership}</td>
    ++    <td>Identifier yang menautkan kontak mentah ke salah satu grup dalam Penyedia Kontak.</td>
    ++    <td>
    ++        Grup adalah fitur opsional pada tipe akun dan nama akun. Grup dijelaskan
    ++       lebih detail di bagian <a href="#Groups">Grup kontak</a>.
    ++    </td>
    ++  </tr>
    ++</table>
    ++<h3 id="ContactBasics">Kontak</h3>
    ++<p>
    ++    Penyedia Kontak mengombinasikan baris kontak mentah di semua tipe akun dan nama akun
    ++    untuk membentuk <strong>kontak</strong>. Hal ini memudahkan menampilkan dan memodifikasi semua data
    ++    yang telah dikumpulkan pengguna untuk seseorang. Penyedia Kontak mengelola pembuatan baris
    ++    kontak baru, dan agregasi kontak mentah dengan baris kontak yang ada. Baik aplikasi maupun adaptor sinkronisasi
    ++    tidak boleh menambahkan kontak dan sebagian kolom dalam baris kontak yang bersifat hanya baca.
    ++</p>
    ++<p class="note">
    ++    <strong>Catatan:</strong> Jika Anda mencoba menambahkan kontak ke Penyedia Kontak dengan
    ++    {@link android.content.ContentResolver#insert(Uri,ContentValues) insert()}, Anda akan mendapatkan
    ++    eksepsi {@link java.lang.UnsupportedOperationException}. Jika Anda mencoba memperbarui sebuah kolom
    ++   yang tercantum sebagai "hanya-baca", pembaruan akan diabaikan.
    ++</p>
    ++<p>
    ++    Penyedia Kontak membuat kontak baru untuk merespons penambahan kontak mentah baru
    ++    yang tidak cocok dengan kontak yang ada. Penyedia juga melakukan ini jika data
    ++    kontak mentah yang ada berubah sehingga tidak lagi cocok dengan kontak yang
    ++    sebelumnya dihubungkan. Jika aplikasi atau adaptor sinkronisasi membuat kontak mentah baru yang
    ++    <em>memang</em> cocok dengan kontak yang ada, kontak mentah baru akan diagregasikan ke kontak
    ++    yang ada.
    ++</p>
    ++<p>
    ++    Penyedia Kontak menautkan baris kontak ke baris kontak mentahnya dengan kolom
    ++    <code>_ID</code> dari baris kontak dalam tabel {@link android.provider.ContactsContract.Contacts Contacts}.
    ++ Kolom <code>CONTACT_ID</code> tabel kontak mentah
    ++    {@link android.provider.ContactsContract.RawContacts} berisi nilai <code>_ID</code> untuk
    ++    baris kontak yang dikaitkan dengan tiap baris kontak mentah.
    ++</p>
    ++<p>
    ++    Tabel {@link android.provider.ContactsContract.Contacts} juga memiliki kolom
    ++    {@code android.provider.ContactsContract.ContactsColumns#LOOKUP_KEY} yang merupakan
    ++    tautan "permanen" ke baris kontak. Karena memelihara kontak
    ++    secara otomatis, Penyedia Kontak bisa mengubah nilai {@code android.provider.BaseColumns#_ID} baris kontak
    ++    untuk merespons agregasi atau sinkronisasi. Sekalipun ini terjadi, URI konten
    ++    {@link android.provider.ContactsContract.Contacts#CONTENT_LOOKUP_URI} yang dikombinasikan dengan
    ++    {@code android.provider.ContactsContract.ContactsColumns#LOOKUP_KEY} kontak akan tetap
    ++    menunjuk ke baris kontak itu, sehingga Anda bisa menggunakan
    ++    {@code android.provider.ContactsContract.ContactsColumns#LOOKUP_KEY}
    ++   untuk memelihara tautan ke kontak "favorit", dan seterusnya. Kolom ini memiliki formatnya sendiri, yang
    ++    tidak terkait dengan format kolom {@code android.provider.BaseColumns#_ID}.
    ++</p>
    ++<p>
    ++    Gambar 3 menampilkan cara ketiga tabel utama terkait satu sama lain.
    ++</p>
    ++<img src="{@docRoot}images/providers/contacts_tables.png" alt="Contacts provider main tables" height="514" id="figure4" />
    ++<p class="img-caption">
    ++  <strong>Gambar 3.</strong> Hubungan tabel Contacts, Raw Contacts, dan Details.
    ++</p>
    ++<h2 id="Sources">Data Dari Adaptor Sinkronisasi</h2>
    ++<p>
    ++    Pengguna memasukkan data kontak secara langsung ke dalam perangkat, namun data juga mengalir masuk ke Penyedia Kontak
    ++    dari layanan web melalui <strong>adaptor sinkronisasi</strong>, yang mengotomatiskan
    ++    transfer data antara perangkat dan layanan. Adaptor sinkronisasi berjalan di latar belakang
    ++    di bawah kontrol sistem, dan memanggil metode {@link android.content.ContentResolver}
    ++   untuk mengelola data.
    ++</p>
    ++<p>
    ++    Di Android, layanan web yang digunakan adaptor sinkronisasi diidentifikasi melalui tipe akun.
    ++    Setiap adaptor sinkronisasi bekerja dengan satu tipe akun, tetapi bisa mendukung beberapa nama akun untuk
    ++    tipe itu. Tipe akun dan nama akun dijelaskan secara singkat di bagian
    ++    <a href="#RawContactsExample">Sumber data kontak mentah</a>. Definisi berikut menyediakan
    ++    detail selengkapnya, dan menjelaskan cara tipe dan nama akun berkaitan dengan adaptor sinkronisasi dan layanan.
    ++</p>
    ++<dl>
    ++    <dt>
    ++        Tipe akun
    ++    </dt>
    ++    <dd>
    ++        Mengidentifikasi layanan tempat pengguna menyimpan data. Sering kali, pengguna harus
    ++        mengautentikasi diri dengan layanan. Misalnya, Google Contacts adalah tipe akun, yang diidentifikasi
    ++        dengan kode <code>google.com</code>. Nilai ini sesuai dengan tipe akun yang digunakan oleh
    ++        {@link android.accounts.AccountManager}.
    ++    </dd>
    ++    <dt>
    ++        Nama akun
    ++    </dt>
    ++    <dd>
    ++        Mengidentifikasi akun atau login tertentu untuk suatu tipe akun. Akun Google Contacts
    ++        sama dengan akun Google, yang memiliki alamat email sebagai nama akun.
    ++        Layanan lain mungkin menggunakan nama pengguna satu-kata atau identitas berupa angka.
    ++    </dd>
    ++</dl>
    ++<p>
    ++    Tipe akun tidak harus unik. Pengguna boleh mengonfigurasi beberapa akun Google Contacts
    ++    dan mengunduh data ke Penyedia Kontak; ini mungkin terjadi jika pengguna memiliki satu set
    ++    kontak pribadi untuk satu nama akun pribadi, dan satu set lagi untuk pekerjaan. Nama akun
    ++    biasanya unik. Bersama-sama, keduanya mengidentifikasi aliran data tertentu antara Penyedia Kontak dan
    ++    layanan eksternal.
    ++</p>
    ++<p>
    ++    Jika Anda ingin mentransfer data layanan ke Penyedia Kontak, Anda perlu menulis
    ++    adaptor sinkronisasi sendiri. Hal ini dijelaskan lebih detail di bagian
    ++    <a href="#SyncAdapters">Adaptor Sinkronisasi Penyedia Kontak</a>.
    ++</p>
    ++<p>
    ++    Gambar 4 menampilkan cara Penyedia Kontak dimasukkan ke dalam aliran data
    ++    tentang orang. Dalam kotak bertanda "sync adapters", setiap adaptor diberi label menurut tipe akunnya.
    ++</p>
    ++<img src="{@docRoot}images/providers/ContactsDataFlow.png" alt="Flow of data about people" height="252" id="figure5" />
    ++<p class="img-caption">
    ++  <strong>Gambar 4.</strong> Aliran data Penyedia Kontak.
    ++</p>
    ++<h2 id="Permissions">Izin yang Diperlukan</h2>
    ++<p>
    ++    Aplikasi yang ingin mengakses Penyedia Kontak harus meminta izin
    ++   berikut:
    ++</p>
    ++<dl>
    ++    <dt>Akses baca ke satu atau beberapa tabel</dt>
    ++    <dd>
    ++        {@link android.Manifest.permission#READ_CONTACTS}, yang ditetapkan dalam
    ++        <code>AndroidManifest.xml</code> dengan elemen
    ++        <code><a href="{@docRoot}guide/topics/manifest/uses-permission-element.html">
    ++        &lt;uses-permission&gt;</a></code> sebagai
    ++        <code>&lt;uses-permission android:name="android.permission.READ_CONTACTS"&gt;</code>.
    ++    </dd>
    ++    <dt>Akses tulis ke satu atau beberapa tabel</dt>
    ++    <dd>
    ++        {@link android.Manifest.permission#WRITE_CONTACTS}, yang ditetapkan dalam
    ++        <code>AndroidManifest.xml</code> dengan elemen
    ++        <code><a href="{@docRoot}guide/topics/manifest/uses-permission-element.html">
    ++        &lt;uses-permission&gt;</a></code> sebagai
    ++        <code>&lt;uses-permission android:name="android.permission.WRITE_CONTACTS"&gt;</code>.
    ++    </dd>
    ++</dl>
    ++<p>
    ++    Izin ini tidak diperluas ke data profil pengguna. Profil pengguna dan izin
    ++   yang diperlukan dibahas di bagian berikut,
    ++    <a href="#UserProfile">Profil Pengguna</a>.
    ++</p>
    ++<p>
    ++    Ingatlah bahwa data kontak pengguna bersifat pribadi dan sensitif. Pengguna mempersoalkan
    ++    privasinya, sehingga tidak ingin aplikasi mengumpulkan data tentang diri atau kontak mereka.
    ++    Jika alasan Anda memerlukan izin untuk mengakses data kontak tidak jelas, pengguna mungkin memberi
    ++    aplikasi Anda peringkat rendah atau langsung menolak menginstalnya.
    ++</p>
    ++<h2 id="UserProfile">Profil Pengguna</h2>
    ++<p>
    ++    Tabel {@link android.provider.ContactsContract.Contacts} berisi satu baris yang berisi
    ++    data profil untuk pengguna perangkat. Data ini menjelaskan data perangkat  <code>user</code> bukannya
    ++    salah satu kontak pengguna. Baris kontak profil ditautkan ke baris
    ++     kontak mentah untuk setiap sistem yang menggunakan profil.
    ++    Setiap baris kontak mentah profil bisa memiliki beberapa baris data. Konstanta untuk mengakses profil
    ++    pengguna tersedia dalam kelas {@link android.provider.ContactsContract.Profile}.
    ++</p>
    ++<p>
    ++    Akses ke profil pengguna memerlukan izin khusus. Selain itu, izin
    ++    {@link android.Manifest.permission#READ_CONTACTS} dan
    ++    {@link android.Manifest.permission#WRITE_CONTACTS} diperlukan untuk membaca dan menulis, akses
    ++    ke profil pengguna memerlukan masing-masing izin {@code android.Manifest.permission#READ_PROFILE} dan
    ++    {@code android.Manifest.permission#WRITE_PROFILE} untuk akses baca dan tulis.
    ++
    ++</p>
    ++<p>
    ++    Ingatlah bahwa Anda harus mempertimbangkan profil pengguna bersifat sensitif. Izin
    ++    {@code android.Manifest.permission#READ_PROFILE} memungkinkan Anda mengakses data yang mengidentifikasi secara pribadi
    ++    pengguna perangkat. Pastikan memberi tahu pengguna alasan
    ++    Anda memerlukan izin akses profil pengguna dalam keterangan aplikasi Anda.
    ++</p>
    ++<p>
    ++    Untuk mengambil baris kontak berisi profil pengguna,
    ++    panggil {@link android.content.ContentResolver#query(Uri,String[], String, String[], String)
    ++    ContentResolver.query()}. Atur URI konten ke
    ++    {@link android.provider.ContactsContract.Profile#CONTENT_URI} dan jangan sediakan
    ++    kriteria pemilihan apa pun. Anda juga bisa menggunakan URI konten ini sebagai URI dasar untuk mengambil kontak
    ++    mentah atau data untuk profil. Misalnya, cuplikan kode ini mengambil data untuk profil:
    ++</p>
    ++<pre>
    ++// Sets the columns to retrieve for the user profile
    ++mProjection = new String[]
    ++    {
    ++        Profile._ID,
    ++        Profile.DISPLAY_NAME_PRIMARY,
    ++        Profile.LOOKUP_KEY,
    ++        Profile.PHOTO_THUMBNAIL_URI
    ++    };
    ++
    ++// Retrieves the profile from the Contacts Provider
    ++mProfileCursor =
    ++        getContentResolver().query(
    ++                Profile.CONTENT_URI,
    ++                mProjection ,
    ++                null,
    ++                null,
    ++                null);
    ++</pre>
    ++<p class="note">
    ++    <strong>Catatan:</strong> Jika Anda mengambil beberapa baris kontak, dan ingin menentukan apakah salah satu baris
    ++    adalah profil pengguna, uji
    ++    kolom {@link android.provider.ContactsContract.ContactsColumns#IS_USER_PROFILE} pada baris tersebut. Kolom ini
    ++    diatur ke "1" jika kontak adalah profil pengguna.
    ++</p>
    ++<h2 id="ContactsProviderMetadata">Metadata Penyedia Kontak</h2>
    ++<p>
    ++    Penyedia Kontak mengelola data yang mencatat status data kontak dalam
    ++    repository. Metadata repository ini disimpan di berbagai tempat, termasuk baris-baris tabel
    ++    Raw Contacts, Data, dan Contacts,
    ++    tabel {@link android.provider.ContactsContract.Settings}, dan
    ++    tabel {@link android.provider.ContactsContract.SyncState}. Tabel berikut menampilkan
    ++    efek setiap potongan metadata ini:
    ++</p>
    ++<p class="table-caption" id="table3">
    ++  <strong>Tabel 3.</strong> Metadata di Penyedia Kontak</p>
    ++<table>
    ++    <tr>
    ++        <th scope="col">Tabel</th>
    ++        <th scope="col">Kolom</th>
    ++        <th scope="col">Nilai</th>
    ++        <th scope="col">Arti</th>
    ++    </tr>
    ++    <tr>
    ++        <td rowspan="2">{@link android.provider.ContactsContract.RawContacts}</td>
    ++        <td rowspan="2">{@link android.provider.ContactsContract.SyncColumns#DIRTY}</td>
    ++        <td>"0" - tidak berubah sejak sinkronisasi terakhir.</td>
    ++        <td rowspan="2">
    ++            Menandai kontak mentah yang berubah pada perangkat dan telah disinkronkan kembali ke
    ++           server. Nilai diatur secara otomatis oleh Penyedia Kontak bila aplikasi
    ++            Android memperbarui baris.
    ++            <p>
    ++                Adaptor sinkronisasi yang memodifikasi kontak mentah atau tabel data harus selalu menambahkan
    ++                string {@link android.provider.ContactsContract#CALLER_IS_SYNCADAPTER} ke
    ++                URI konten yang digunakannya. Ini mencegah penyedia menandai baris sebagai kotor.
    ++                Sebaliknya, modifikasi oleh adaptor sinkronisasi tampak seperti modifikasi lokal dan
    ++                dikirim ke server, meskipun server adalah sumber modifikasi.
    ++            </p>
    ++        </td>
    ++    </tr>
    ++    <tr>
    ++            <td>"1" - berubah sejak sinkronisasi terakhir, harus disinkronkan kembali ke server.</td>
    ++    </tr>
    ++    <tr>
    ++        <td>{@link android.provider.ContactsContract.RawContacts}</td>
    ++        <td>{@link android.provider.ContactsContract.SyncColumns#VERSION}</td>
    ++        <td>Nomor versi baris ini.</td>
    ++        <td>
    ++            Penyedia Kontak menambahkan nilai ini secara otomatis bila baris atau
    ++            data terkaitnya berubah.
    ++        </td>
    ++    </tr>
    ++    <tr>
    ++        <td>{@link android.provider.ContactsContract.Data}</td>
    ++        <td>{@link android.provider.ContactsContract.DataColumns#DATA_VERSION}</td>
    ++        <td>Nomor versi baris ini.</td>
    ++        <td>
    ++            Penyedia Kontak menambahkan nilai ini secara otomatis bila baris data
    ++            berubah.
    ++        </td>
    ++    </tr>
    ++    <tr>
    ++        <td>{@link android.provider.ContactsContract.RawContacts}</td>
    ++        <td>{@link android.provider.ContactsContract.SyncColumns#SOURCE_ID}</td>
    ++        <td>
    ++            Nilai string yang mengidentifikasi secara unik kontak mentah ini ke akun tempat
    ++            kontak dibuat.
    ++        </td>
    ++        <td>
    ++            Bila adaptor sinkronisasi membuat kontak mentah baru, kolom ini harus diatur ke
    ++            ID unik server untuk kontak mentah itu. Bila aplikasi Android membuat kontak mentah
    ++            baru, aplikasi harus membiarkan kolom ini kosong. Ini mengisyaratkan pada adaptor
    ++            sinkronisasi bahwa adaptor harus membuat kontak mentah baru pada server, dan mendapatkan
    ++            nilai untuk {@link android.provider.ContactsContract.SyncColumns#SOURCE_ID}.
    ++            <p>
    ++                Khususnya, id sumber harus <strong>unik</strong> untuk setiap tipe
    ++                akun dan stabil di semua sinkronisasi:
    ++            </p>
    ++                <ul>
    ++                    <li>
    ++                        Unik: Setiap kontak mentah untuk satu akun harus memiliki id sumbernya sendiri. Jika Anda
    ++                        tidak memberlakukan aturan ini, masalah akan timbul dalam aplikasi kontak.
    ++                        Perhatikan bahwa dua kontak mentah untuk tipe akun yang <em>sama</em> boleh memiliki
    ++                       id sumber yang sama. Misalnya, kontak mentah "Thomas Higginson" untuk
    ++                        akun {@code emily.dickinson@gmail.com} boleh memiliki id sumber
    ++                        yang sama dengan kontak mentah "Thomas Higginson" untuk akun
    ++                        {@code emilyd@gmail.com}.
    ++                    </li>
    ++                    <li>
    ++                        Stabil: Id sumber adalah bagian tetap dari data layanan online untuk
    ++                        kontak mentah. Misalnya, jika pengguna membersihkan Contacts Storage dari
    ++                        pengaturan aplikasi dan menyinkronkan ulang, kontak mentah yang dipulihkan akan memiliki id sumber
    ++                        yang sama dengan sebelumnya. Jika Anda tidak memberlakukan hal ini, pintasan akan berhenti
    ++                        berfungsi.
    ++                    </li>
    ++                </ul>
    ++        </td>
    ++    </tr>
    ++    <tr>
    ++        <td rowspan="2">{@link android.provider.ContactsContract.Groups}</td>
    ++        <td rowspan="2">{@link android.provider.ContactsContract.GroupsColumns#GROUP_VISIBLE}</td>
    ++        <td>"0" - Kontak dalam grup ini tidak boleh terlihat dalam UI aplikasi Android.</td>
    ++        <td>
    ++            Kolom ini digunakan untuk kompatibilitas dengan server yang memungkinkan pengguna menyembunyikan kontak dalam
    ++            grup tertentu.
    ++        </td>
    ++    </tr>
    ++    <tr>
    ++        <td>"1" - Kontak dalam grup ini boleh terlihat dalam UI aplikasi.</td>
    ++    </tr>
    ++    <tr>
    ++        <td rowspan="2">{@link android.provider.ContactsContract.Settings}</td>
    ++        <td rowspan="2">
    ++            {@link android.provider.ContactsContract.SettingsColumns#UNGROUPED_VISIBLE}</td>
    ++        <td>
    ++            "0" - Untuk akun dan tipe akun ini, kontak yang bukan milik grup
    ++            tidak akan terlihat pada UI aplikasi Android.
    ++        </td>
    ++        <td rowspan="2">
    ++            Secara default, kontak tidak terlihat jika tidak satu pun kontak mentahnya milik grup
    ++            (Keanggotaan grup untuk kontak mentah ditandai oleh satu atau beberapa baris
    ++            {@link android.provider.ContactsContract.CommonDataKinds.GroupMembership}
    ++            dalam tabel {@link android.provider.ContactsContract.Data}).
    ++            Dengan mengatur flag ini dalam baris tabel {@link android.provider.ContactsContract.Settings}
    ++            untuk tipe akun dan akun, Anda bisa memaksakan kontak tanpa grup agar terlihat.
    ++            Satu kegunaan flag ini adalah menampilkan kontak dari server yang tidak menggunakan grup.
    ++        </td>
    ++    </tr>
    ++    <tr>
    ++        <td>
    ++            "1" - Untuk akun dan tipe akun ini, kontak yang bukan milik grup
    ++            akan terlihat pada UI aplikasi.
    ++        </td>
    ++
    ++    </tr>
    ++    <tr>
    ++        <td>{@link android.provider.ContactsContract.SyncState}</td>
    ++        <td>(semua)</td>
    ++        <td>
    ++            Gunakan tabel ini untuk menyimpan metadata bagi adaptor sinkronisasi Anda.
    ++        </td>
    ++        <td>
    ++            Dengan tabel ini, Anda bisa menyimpan status sinkronisasi dan data lain yang terkait dengan sinkronisasi secara persisten pada
    ++            perangkat.
    ++        </td>
    ++    </tr>
    ++</table>
    ++<h2 id="Access">Akses Penyedia Kontak</h2>
    ++<p>
    ++    Bagian ini menjelaskan panduan untuk mengakses data dari Penyedia Kontak, yang berfokus pada
    ++    hal-hal berikut:
    ++</p>
    ++<ul>
    ++    <li>
    ++        Query entitas.
    ++    </li>
    ++    <li>
    ++        Modifikasi batch.
    ++    </li>
    ++    <li>
    ++        Pengambilan dan modifikasi dengan intent.
    ++    </li>
    ++    <li>
    ++        Integritas data.
    ++    </li>
    ++</ul>
    ++<p>
    ++    Membuat modifikasi dari adaptor sinkronisasi juga secara lebih detail di bagian
    ++    <a href="#SyncAdapters">Adaptor Sinkronisasi Penyedia Kontak</a>.
    ++</p>
    ++<h3 id="Entities">Membuat query entitas</h3>
    ++<p>
    ++    Karena disusun secara hierarki, tabel-tabel Penyedia Kontak sering kali berguna untuk
    ++    mengambil baris dan semua baris "anak" yang ditautkan dengannya. Misalnya, untuk menampilkan
    ++    semua informasi untuk satu orang, Anda mungkin ingin mengambil semua
    ++    baris {@link android.provider.ContactsContract.RawContacts} untuk satu baris
    ++    {@link android.provider.ContactsContract.Contacts}, atau semua
    ++    baris {@link android.provider.ContactsContract.CommonDataKinds.Email} untuk satu baris
    ++    {@link android.provider.ContactsContract.RawContacts}. Untuk memudahkan hal ini, Penyedia Kontak
    ++    menawarkan konstruksi <strong>entitas</strong>, yang berfungsi seperti gabungan database di antara
    ++    tabel-tabel.
    ++</p>
    ++<p>
    ++    Entitas adalah seperti tabel yang terdiri atas kolom-kolom terpilih dari tabel induk dan tabel anaknya.
    ++    Bila membuat query sebuah entitas, Anda memberikan proyeksi dan kriteria pencarian berdasarkan kolom-kolom
    ++    yang tersedia dari entitas itu. Hasilnya adalah sebuah {@link android.database.Cursor} yang
    ++    berisi satu baris untuk setiap baris tabel anak yang diambil. Misalnya, jika Anda membuat query
    ++    {@link android.provider.ContactsContract.Contacts.Entity} untuk satu nama kontak
    ++    dan semua baris {@link android.provider.ContactsContract.CommonDataKinds.Email} untuk semua
    ++    kontak mentah bagi nama itu, Anda akan mendapatkan kembali {@link android.database.Cursor} berisi satu baris
    ++    untuk setiap baris {@link android.provider.ContactsContract.CommonDataKinds.Email}.
    ++</p>
    ++<p>
    ++    Entitas menyederhanakan query. Dengan entitas, Anda bisa mengambil semua data kontak untuk satu
    ++    kontak atau kontak mentah sekaligus, sebagai ganti harus membuat query tabel induk terlebih dahulu untuk mendapatkan
    ++    ID, lalu harus membuat query tabel anak dengan ID itu. Selain itu, Penyedia Kontak akan memproses
    ++    query terhadap entitas dalam satu transaksi, yang memastikan bahwa data yang diambil
    ++    konsisten secara internal.
    ++</p>
    ++<p class="note">
    ++    <strong>Catatan:</strong> Entitas biasanya tidak berisi semua kolom tabel induk dan
    ++    anak. Jika Anda mencoba menggunakan nama kolom yang tidak ada dalam daftar konstanta
    ++    nama kolom untuk entitas, Anda akan mendapatkan {@link java.lang.Exception}.
    ++</p>
    ++<p>
    ++    Cuplikan berikut menampilkan cara mengambil semua baris kontak mentah untuk sebuah kontak. Cuplikan ini
    ++    adalah bagian dari aplikasi lebih besar yang memiliki dua aktivitas, "main" dan "detail". Aktivitas utama
    ++    menampilkan daftar baris kontak; bila pengguna memilih satu baris, aktivitas akan mengirimkan ID-nya ke aktivitas
    ++    detail. Aktivitas detail menggunakan{@link android.provider.ContactsContract.Contacts.Entity}
    ++    untuk menampilkan semua baris data dari semua kontak mentah yang dikaitkan dengan kontak
    ++    terpilih.
    ++</p>
    ++<p>
    ++    Cuplikan ini diambil dari aktivitas "detail":
    ++</p>
    ++<pre>
    ++...
    ++    /*
    ++     * Appends the entity path to the URI. In the case of the Contacts Provider, the
    ++     * expected URI is content://com.google.contacts/#/entity (# is the ID value).
    ++     */
    ++    mContactUri = Uri.withAppendedPath(
    ++            mContactUri,
    ++            ContactsContract.Contacts.Entity.CONTENT_DIRECTORY);
    ++
    ++    // Initializes the loader identified by LOADER_ID.
    ++    getLoaderManager().initLoader(
    ++            LOADER_ID,  // The identifier of the loader to initialize
    ++            null,       // Arguments for the loader (in this case, none)
    ++            this);      // The context of the activity
    ++
    ++    // Creates a new cursor adapter to attach to the list view
    ++    mCursorAdapter = new SimpleCursorAdapter(
    ++            this,                        // the context of the activity
    ++            R.layout.detail_list_item,   // the view item containing the detail widgets
    ++            mCursor,                     // the backing cursor
    ++            mFromColumns,                // the columns in the cursor that provide the data
    ++            mToViews,                    // the views in the view item that display the data
    ++            0);                          // flags
    ++
    ++    // Sets the ListView's backing adapter.
    ++    mRawContactList.setAdapter(mCursorAdapter);
    ++...
    ++&#64;Override
    ++public Loader&lt;Cursor&gt; onCreateLoader(int id, Bundle args) {
    ++
    ++    /*
    ++     * Sets the columns to retrieve.
    ++     * RAW_CONTACT_ID is included to identify the raw contact associated with the data row.
    ++     * DATA1 contains the first column in the data row (usually the most important one).
    ++     * MIMETYPE indicates the type of data in the data row.
    ++     */
    ++    String[] projection =
    ++        {
    ++            ContactsContract.Contacts.Entity.RAW_CONTACT_ID,
    ++            ContactsContract.Contacts.Entity.DATA1,
    ++            ContactsContract.Contacts.Entity.MIMETYPE
    ++        };
    ++
    ++    /*
    ++     * Sorts the retrieved cursor by raw contact id, to keep all data rows for a single raw
    ++     * contact collated together.
    ++     */
    ++    String sortOrder =
    ++            ContactsContract.Contacts.Entity.RAW_CONTACT_ID +
    ++            " ASC";
    ++
    ++    /*
    ++     * Returns a new CursorLoader. The arguments are similar to
    ++     * ContentResolver.query(), except for the Context argument, which supplies the location of
    ++     * the ContentResolver to use.
    ++     */
    ++    return new CursorLoader(
    ++            getApplicationContext(),  // The activity's context
    ++            mContactUri,              // The entity content URI for a single contact
    ++            projection,               // The columns to retrieve
    ++            null,                     // Retrieve all the raw contacts and their data rows.
    ++            null,                     //
    ++            sortOrder);               // Sort by the raw contact ID.
    ++}
    ++</pre>
    ++<p>
    ++    Bila selesai dimuat, {@link android.app.LoaderManager} akan memicu callback ke
    ++    {@link android.app.LoaderManager.LoaderCallbacks#onLoadFinished(Loader, D)
    ++    onLoadFinished()}. Salah satu argumen masuk pada metode ini adalah
    ++    {@link android.database.Cursor} bersama hasil query. Dalam aplikasi Anda sendiri, Anda bisa memperoleh
    ++    data dari {@link android.database.Cursor} ini untuk menampilkannya atau menggunakannya lebih jauh.
    ++</p>
    ++<h3 id="Transactions">Modifikasi batch</h3>
    ++<p>
    ++    Bila memungkinkan, Anda harus menyisipkan, memperbarui, dan menghapus data dalam Penyedia Kontak dengan
    ++    "batch mode", dengan membuat {@link java.util.ArrayList} dari
    ++    objek-objek {@link android.content.ContentProviderOperation} dan memanggil
    ++    {@link android.content.ContentResolver#applyBatch(String, ArrayList) applyBatch()}. Karena
    ++    Penyedia Kontak menjalankan semua operasi dalam satu
    ++    {@link android.content.ContentResolver#applyBatch(String, ArrayList) applyBatch()} transaksi,
    ++    modifikasi Anda tidak akan pernah meninggalkan repository kontak dalam keadaan
    ++    tidak konsisten. Modifikasi batch juga memudahkan penyisipan kontak mentah dan data detailnya
    ++    sekaligus.
    ++</p>
    ++<p class="note">
    ++    <strong>Catatan:</strong> Untuk memodifikasi <em>satu</em> kontak mentah, pertimbangkan untuk mengirim intent ke
    ++    aplikasi kontak perangkat daripada menangani modifikasi dalam aplikasi Anda.
    ++    Cara ini dijelaskan lebih detail di bagian
    ++    <a href="#Intents">Pengambilan dan modifikasi dengan intent</a>.
    ++</p>
    ++<h4>Yield point</h4>
    ++<p>
    ++    Modifikasi batch yang berisi operasi dalam jumlah besar bisa memblokir proses lain,
    ++    yang mengakibatkan pengalaman pengguna yang buruk secara keseluruhan. Untuk menata semua modifikasi yang ingin Anda
    ++    jalankan dalam sesedikit mungkin daftar terpisah, sambil mencegah modifikasi dari
    ++    memblokir sistem, Anda harus menetapkan <strong>yield point</strong> untuk satu atau beberapa operasi.
    ++    Yield point (titik hasil) adalah objek {@link android.content.ContentProviderOperation} yang mengatur
    ++    nilai {@link android.content.ContentProviderOperation#isYieldAllowed()}-nya ke
    ++    <code>true</code>. Bila menemui yield point, Penyedia Kontak akan menghentikan pekerjaannya untuk
    ++    membiarkan proses lain berjalan dan menutup transaksi saat ini. Bila dimulai lagi, penyedia akan
    ++    melanjutkan dengan operasi berikutnya di {@link java.util.ArrayList} dan memulai transaksi
    ++    baru.
    ++</p>
    ++<p>
    ++    Yield point memang menyebabkan lebih dari satu transaksi per panggilan ke
    ++    {@link android.content.ContentResolver#applyBatch(String, ArrayList) applyBatch()}. Karena
    ++    itu, Anda harus menetapkan yield point pada operasi terakhir untuk satu set baris terkait.
    ++    Misalnya, Anda harus menetapkan yield point pada operasi terakhir di satu set yang menambahkan
    ++    baris kontak mentah dan baris data terkait, atau operasi terakhir untuk satu set baris yang terkait
    ++    dengan satu kontak.
    ++</p>
    ++<p>
    ++    Yield point juga merupakan unit operasi atomis. Semua akses antara dua yield point bisa
    ++    saja berhasil atau gagal sebagai satu unit. Jika Anda mengatur yield point, operasi
    ++    atomis terkecil adalah seluruh batch operasi. Jika menggunakan yield point, Anda akan mencegah
    ++    operasi menurunkan kinerja sistem, sekaligus memastikan subset
    ++    operasi bersifat atomis.
    ++</p>
    ++<h4>Acuan balik modifikasi</h4>
    ++<p>
    ++    Saat Anda menyisipkan baris kontak mentah baru dan baris data terkaitnya sebagai satu set
    ++    objek {@link android.content.ContentProviderOperation}, Anda harus menautkan baris data ke
    ++    baris kontak mentah dengan memasukkan nilai
    ++    {@code android.provider.BaseColumns#_ID} kontak mentah sebagai
    ++    nilai {@link android.provider.ContactsContract.DataColumns#RAW_CONTACT_ID}. Akan tetapi, nilai
    ++    ini tidak tersedia saat Anda membuat {@link android.content.ContentProviderOperation}
    ++    untuk baris data, karena Anda belum menerapkan
    ++    {@link android.content.ContentProviderOperation} untuk baris kontak mentah. Solusinya,
    ++     kelas {@link android.content.ContentProviderOperation.Builder} memiliki metode
    ++    {@link android.content.ContentProviderOperation.Builder#withValueBackReference(String, int) withValueBackReference()}.
    ++    Metode ini memungkinkan Anda menyisipkan atau mengubah kolom dengan
    ++    hasil dari operasi sebelumnya.
    ++</p>
    ++<p>
    ++    Metode {@link android.content.ContentProviderOperation.Builder#withValueBackReference(String, int) withValueBackReference()}
    ++    memiliki dua argumen:
    ++</p>
    ++    <dl>
    ++        <dt>
    ++            <code>key</code>
    ++        </dt>
    ++        <dd>
    ++            Kunci dari pasangan kunci-nilai. Nilai argumen ini harus berupa nama kolom
    ++            dalam tabel yang Anda modifikasi.
    ++        </dd>
    ++        <dt>
    ++            <code>previousResult</code>
    ++        </dt>
    ++        <dd>
    ++            Indeks berbasis 0 dari nilai pada larik
    ++            objek {@link android.content.ContentProviderResult} dari
    ++            {@link android.content.ContentResolver#applyBatch(String, ArrayList) applyBatch()}. Saat
    ++            operasi batch diterapkan, hasil tiap operasi akan disimpan dalam
    ++            larik hasil antara. Nilai <code>previousResult</code> adalah indeks
    ++            dari salah satu hasil ini, yang diambil dan disimpan bersama nilai <code>key</code>.
    ++ Cara ini memungkinkan Anda menyisipkan record kontak mentah baru dan mendapatkan kembali nilai
    ++            {@code android.provider.BaseColumns#_ID}-nya, lalu membuat "acuan balik" ke
    ++            nilai itu saat Anda menambahkan baris {@link android.provider.ContactsContract.Data}.
    ++            <p>
    ++                Seluruh larik hasil dibuat saat Anda memanggil
    ++                {@link android.content.ContentResolver#applyBatch(String, ArrayList) applyBatch()} untuk pertama kali,
    ++                dengan ukuran setara dengan ukuran {@link java.util.ArrayList} dari
    ++                objek {@link android.content.ContentProviderOperation} yang Anda sediakan. Akan tetapi, semua
    ++                elemen dalam larik hasil diatur ke <code>null</code>, dan jika Anda mencoba
    ++                melakukan acuan balik ke hasil untuk operasi yang belum diterapkan,
    ++{@link android.content.ContentProviderOperation.Builder#withValueBackReference(String, int) withValueBackReference()}
    ++                akan mengeluarkan {@link java.lang.Exception}.
    ++
    ++            </p>
    ++        </dd>
    ++    </dl>
    ++<p>
    ++    Cuplikan kode berikut menampilkan cara menyisipkan kontak mentah baru dan data secara batch. Cuplikan kode ini
    ++    menyertakan kode yang menetapkan yield point dan menggunakan acuan balik. Cuplikan kode ini adalah
    ++    versi perluasan dari metode<code>createContacEntry()</code>, yang merupakan bagian dari kelas
    ++    <code>ContactAdder</code> dalam
    ++    aplikasi contoh <code><a href="{@docRoot}resources/samples/ContactManager/index.html">
    ++    Contact Manager</a></code>.
    ++</p>
    ++<p>
    ++    Cuplikan pertama mengambil data kontak dari UI. Pada saat ini, pengguna sudah
    ++    memilih akun tempat kontak mentah baru harus ditambahkan.
    ++</p>
    ++<pre>
    ++// Creates a contact entry from the current UI values, using the currently-selected account.
    ++protected void createContactEntry() {
    ++    /*
    ++     * Gets values from the UI
    ++     */
    ++    String name = mContactNameEditText.getText().toString();
    ++    String phone = mContactPhoneEditText.getText().toString();
    ++    String email = mContactEmailEditText.getText().toString();
    ++
    ++    int phoneType = mContactPhoneTypes.get(
    ++            mContactPhoneTypeSpinner.getSelectedItemPosition());
    ++
    ++    int emailType = mContactEmailTypes.get(
    ++            mContactEmailTypeSpinner.getSelectedItemPosition());
    ++</pre>
    ++<p>
    ++    Cuplikan berikutnya membuat operasi untuk menyisipkan baris kontak mentah ke dalam
    ++    tabel {@link android.provider.ContactsContract.RawContacts}:
    ++</p>
    ++<pre>
    ++    /*
    ++     * Prepares the batch operation for inserting a new raw contact and its data. Even if
    ++     * the Contacts Provider does not have any data for this person, you can't add a Contact,
    ++     * only a raw contact. The Contacts Provider will then add a Contact automatically.
    ++     */
    ++
    ++     // Creates a new array of ContentProviderOperation objects.
    ++    ArrayList&lt;ContentProviderOperation&gt; ops =
    ++            new ArrayList&lt;ContentProviderOperation&gt;();
    ++
    ++    /*
    ++     * Creates a new raw contact with its account type (server type) and account name
    ++     * (user's account). Remember that the display name is not stored in this row, but in a
    ++     * StructuredName data row. No other data is required.
    ++     */
    ++    ContentProviderOperation.Builder op =
    ++            ContentProviderOperation.newInsert(ContactsContract.RawContacts.CONTENT_URI)
    ++            .withValue(ContactsContract.RawContacts.ACCOUNT_TYPE, mSelectedAccount.getType())
    ++            .withValue(ContactsContract.RawContacts.ACCOUNT_NAME, mSelectedAccount.getName());
    ++
    ++    // Builds the operation and adds it to the array of operations
    ++    ops.add(op.build());
    ++</pre>
    ++<p>
    ++    Berikutnya, kode akan membuat baris data untuk baris-baris nama tampilan, telepon, dan email.
    ++</p>
    ++<p>
    ++    Setiap objek pembangun operasi menggunakan
    ++    {@link android.content.ContentProviderOperation.Builder#withValueBackReference(String, int) withValueBackReference()}
    ++    untuk mendapatkan
    ++    {@link android.provider.ContactsContract.DataColumns#RAW_CONTACT_ID}. Acuan menunjuk
    ++    balik ke objek {@link android.content.ContentProviderResult} dari operasi pertama,
    ++    yang menambahkan baris kontak mentah dan mengembalikan nilai {@code android.provider.BaseColumns#_ID}
    ++    barunya. Hasilnya, setiap data ditautkan secara otomatis oleh
    ++    {@link android.provider.ContactsContract.DataColumns#RAW_CONTACT_ID}-nya
    ++    ke baris {@link android.provider.ContactsContract.RawContacts} baru yang memilikinya.
    ++</p>
    ++<p>
    ++    Objek {@link android.content.ContentProviderOperation.Builder} yang menambahkan baris email
    ++    diberi flag {@link android.content.ContentProviderOperation.Builder#withYieldAllowed(boolean)
    ++    withYieldAllowed()}, yang mengatur yield point:
    ++</p>
    ++<pre>
    ++    // Creates the display name for the new raw contact, as a StructuredName data row.
    ++    op =
    ++            ContentProviderOperation.newInsert(ContactsContract.Data.CONTENT_URI)
    ++            /*
    ++             * withValueBackReference sets the value of the first argument to the value of
    ++             * the ContentProviderResult indexed by the second argument. In this particular
    ++             * call, the raw contact ID column of the StructuredName data row is set to the
    ++             * value of the result returned by the first operation, which is the one that
    ++             * actually adds the raw contact row.
    ++             */
    ++            .withValueBackReference(ContactsContract.Data.RAW_CONTACT_ID, 0)
    ++
    ++            // Sets the data row's MIME type to StructuredName
    ++            .withValue(ContactsContract.Data.MIMETYPE,
    ++                    ContactsContract.CommonDataKinds.StructuredName.CONTENT_ITEM_TYPE)
    ++
    ++            // Sets the data row's display name to the name in the UI.
    ++            .withValue(ContactsContract.CommonDataKinds.StructuredName.DISPLAY_NAME, name);
    ++
    ++    // Builds the operation and adds it to the array of operations
    ++    ops.add(op.build());
    ++
    ++    // Inserts the specified phone number and type as a Phone data row
    ++    op =
    ++            ContentProviderOperation.newInsert(ContactsContract.Data.CONTENT_URI)
    ++            /*
    ++             * Sets the value of the raw contact id column to the new raw contact ID returned
    ++             * by the first operation in the batch.
    ++             */
    ++            .withValueBackReference(ContactsContract.Data.RAW_CONTACT_ID, 0)
    ++
    ++            // Sets the data row's MIME type to Phone
    ++            .withValue(ContactsContract.Data.MIMETYPE,
    ++                    ContactsContract.CommonDataKinds.Phone.CONTENT_ITEM_TYPE)
    ++
    ++            // Sets the phone number and type
    ++            .withValue(ContactsContract.CommonDataKinds.Phone.NUMBER, phone)
    ++            .withValue(ContactsContract.CommonDataKinds.Phone.TYPE, phoneType);
    ++
    ++    // Builds the operation and adds it to the array of operations
    ++    ops.add(op.build());
    ++
    ++    // Inserts the specified email and type as a Phone data row
    ++    op =
    ++            ContentProviderOperation.newInsert(ContactsContract.Data.CONTENT_URI)
    ++            /*
    ++             * Sets the value of the raw contact id column to the new raw contact ID returned
    ++             * by the first operation in the batch.
    ++             */
    ++            .withValueBackReference(ContactsContract.Data.RAW_CONTACT_ID, 0)
    ++
    ++            // Sets the data row's MIME type to Email
    ++            .withValue(ContactsContract.Data.MIMETYPE,
    ++                    ContactsContract.CommonDataKinds.Email.CONTENT_ITEM_TYPE)
    ++
    ++            // Sets the email address and type
    ++            .withValue(ContactsContract.CommonDataKinds.Email.ADDRESS, email)
    ++            .withValue(ContactsContract.CommonDataKinds.Email.TYPE, emailType);
    ++
    ++    /*
    ++     * Demonstrates a yield point. At the end of this insert, the batch operation's thread
    ++     * will yield priority to other threads. Use after every set of operations that affect a
    ++     * single contact, to avoid degrading performance.
    ++     */
    ++    op.withYieldAllowed(true);
    ++
    ++    // Builds the operation and adds it to the array of operations
    ++    ops.add(op.build());
    ++</pre>
    ++<p>
    ++    Cuplikan terakhir menampilkan panggilan ke
    ++    {@link android.content.ContentResolver#applyBatch(String, ArrayList) applyBatch()} yang
    ++    menyisipkan baris-baris kontak mentah dan data baru.
    ++</p>
    ++<pre>
    ++    // Ask the Contacts Provider to create a new contact
    ++    Log.d(TAG,"Selected account: " + mSelectedAccount.getName() + " (" +
    ++            mSelectedAccount.getType() + ")");
    ++    Log.d(TAG,"Creating contact: " + name);
    ++
    ++    /*
    ++     * Applies the array of ContentProviderOperation objects in batch. The results are
    ++     * discarded.
    ++     */
    ++    try {
    ++
    ++            getContentResolver().applyBatch(ContactsContract.AUTHORITY, ops);
    ++    } catch (Exception e) {
    ++
    ++            // Display a warning
    ++            Context ctx = getApplicationContext();
    ++
    ++            CharSequence txt = getString(R.string.contactCreationFailure);
    ++            int duration = Toast.LENGTH_SHORT;
    ++            Toast toast = Toast.makeText(ctx, txt, duration);
    ++            toast.show();
    ++
    ++            // Log exception
    ++            Log.e(TAG, "Exception encountered while inserting contact: " + e);
    ++    }
    ++}
    ++</pre>
    ++<p>
    ++    Operasi batch juga memungkinkan Anda menerapkan <strong>kontrol konkurensi optimistis</strong>,
    ++    sebuah metode yang menerapkan transaksi modifikasi tanpa harus mengunci repository yang mendasari.
    ++    Untuk menggunakan metode ini, terapkan transaksi dan periksa modifikasi lain yang
    ++    mungkin telah dibuat bersamaan. Jika ternyata modifikasi tidak konsisten, Anda
    ++    mengembalikan transaksi ke kondisi semula dan mencobanya kembali.
    ++</p>
    ++<p>
    ++    Kontrol konkurensi optimistis berguna untuk perangkat seluler, apabila hanya ada satu pengguna setiap
    ++   kalinya, dan akses simultan ke repository data jarang terjadi. Karena penguncian tidak digunakan,
    ++    tidak ada waktu yang terbuang untuk memasang kunci atau menunggu transaksi lain untuk melepas kunci.
    ++</p>
    ++<p>
    ++    Untuk menggunakan kontrol konkurensi optimistis saat memperbarui satu baris
    ++    {@link android.provider.ContactsContract.RawContacts}, ikuti langkah-langkah ini:
    ++</p>
    ++<ol>
    ++    <li>
    ++        Ambil kolom {@link android.provider.ContactsContract.SyncColumns#VERSION}
    ++        kontak mentah bersama data lain yang Anda ambil.
    ++    </li>
    ++    <li>
    ++        Buat sebuah objek {@link android.content.ContentProviderOperation.Builder} yang cocok untuk
    ++        memberlakukan batasan, dengan menggunakan metode
    ++        {@link android.content.ContentProviderOperation#newAssertQuery(Uri)}. Untuk URI konten,
    ++        gunakan {@link android.provider.ContactsContract.RawContacts#CONTENT_URI
    ++        RawContacts.CONTENT_URI}
    ++        dengan {@code android.provider.BaseColumns#_ID} kontak mentah yang ditambahkan padanya.
    ++    </li>
    ++    <li>
    ++        Untuk objek {@link android.content.ContentProviderOperation.Builder}, panggil
    ++        {@link android.content.ContentProviderOperation.Builder#withValue(String, Object)
    ++        withValue()} untuk membandingkan kolom {@link android.provider.ContactsContract.SyncColumns#VERSION}
    ++        dengan nomor versi yang baru saja Anda ambil.
    ++    </li>
    ++    <li>
    ++        Untuk {@link android.content.ContentProviderOperation.Builder} yang sama, panggil
    ++        {@link android.content.ContentProviderOperation.Builder#withExpectedCount(int)
    ++        withExpectedCount()} untuk memastikan bahwa hanya satu baris yang diuji oleh pernyataan ini.
    ++    </li>
    ++    <li>
    ++        Panggil {@link android.content.ContentProviderOperation.Builder#build()} untuk membuat
    ++        objek {@link android.content.ContentProviderOperation}, kemudian tambahkan objek ini sebagai
    ++        objek pertama di {@link java.util.ArrayList} yang Anda teruskan ke
    ++        {@link android.content.ContentResolver#applyBatch(String, ArrayList) applyBatch()}.
    ++    </li>
    ++    <li>
    ++        Terapkan transaksi batch.
    ++    </li>
    ++</ol>
    ++<p>
    ++    Jika baris kontak mentah diperbarui oleh operasi lain antara waktu Anda membaca baris dan
    ++    waktu Anda mencoba memodifikasinya, "asert" {@link android.content.ContentProviderOperation}
    ++    akan gagal, dan seluruh batch operasi akan dibatalkan. Anda nanti bisa memilih untuk mencoba ulang
    ++    batch atau melakukan tindakan lain.
    ++</p>
    ++<p>
    ++    Cuplikan berikut memperagakan cara membuat "asert"
    ++    {@link android.content.ContentProviderOperation} setelah membuat query satu kontak mentah yang menggunakan
    ++     {@link android.content.CursorLoader}:
    ++</p>
    ++<pre>
    ++/*
    ++ * The application uses CursorLoader to query the raw contacts table. The system calls this method
    ++ * when the load is finished.
    ++ */
    ++public void onLoadFinished(Loader&lt;Cursor&gt; loader, Cursor cursor) {
    ++
    ++    // Gets the raw contact's _ID and VERSION values
    ++    mRawContactID = cursor.getLong(cursor.getColumnIndex(BaseColumns._ID));
    ++    mVersion = cursor.getInt(cursor.getColumnIndex(SyncColumns.VERSION));
    ++}
    ++
    ++...
    ++
    ++// Sets up a Uri for the assert operation
    ++Uri rawContactUri = ContentUris.withAppendedId(RawContacts.CONTENT_URI, mRawContactID);
    ++
    ++// Creates a builder for the assert operation
    ++ContentProviderOperation.Builder assertOp = ContentProviderOperation.netAssertQuery(rawContactUri);
    ++
    ++// Adds the assertions to the assert operation: checks the version and count of rows tested
    ++assertOp.withValue(SyncColumns.VERSION, mVersion);
    ++assertOp.withExpectedCount(1);
    ++
    ++// Creates an ArrayList to hold the ContentProviderOperation objects
    ++ArrayList ops = new ArrayList&lt;ContentProviderOperationg&gt;;
    ++
    ++ops.add(assertOp.build());
    ++
    ++// You would add the rest of your batch operations to "ops" here
    ++
    ++...
    ++
    ++// Applies the batch. If the assert fails, an Exception is thrown
    ++try
    ++    {
    ++        ContentProviderResult[] results =
    ++                getContentResolver().applyBatch(AUTHORITY, ops);
    ++
    ++    } catch (OperationApplicationException e) {
    ++
    ++        // Actions you want to take if the assert operation fails go here
    ++    }
    ++</pre>
    ++<h3 id="Intents">Pengambilan dan modifikasi dengan intent</h3>
    ++<p>
    ++    Mengirimkan intent ke aplikasi kontak perangkat memungkinkan Anda mengakses Penyedia Kontak
    ++    secara tidak langsung. Intent akan memulai UI aplikasi kontak perangkat, tempat pengguna bisa
    ++    melakukan pekerjaan yang terkait dengan kontak. Dengan tipe akses ini, pengguna bisa:
    ++    <ul>
    ++        <li>Memilih kontak dari daftar dan meneruskannya ke aplikasi untuk pekerjaan lebih jauh.</li>
    ++        <li>Mengedit data kontak yang ada.</li>
    ++        <li>Memasukkan kontak mentah baru untuk akun mereka.</li>
    ++        <li>Menghapus kontak atau data kontak.</li>
    ++    </ul>
    ++<p>
    ++    Jika pengguna menyisipkan atau memperbarui data, Anda bisa mengumpulkan data lebih dahulu dan mengirimkannya sebagai
    ++    bagian dari intent.
    ++</p>
    ++<p>
    ++    Bila Anda menggunakan intent untuk mengakses Penyedia Kontak melalui aplikasi kontak perangkat, Anda
    ++    tidak perlu menulis UI atau kode sendiri untuk mengakses penyedia. Anda juga tidak harus
    ++   meminta izin untuk membaca dari atau menulis ke penyedia. Aplikasi kontak perangkat bisa
    ++    mendelegasikan izin membaca untuk kontak kepada Anda, dan karena Anda membuat modifikasi pada
    ++    penyedia melalui aplikasi lain, Anda tidak perlu memiliki izin menulis.
    ++</p>
    ++<p>
    ++    Proses umum pengiriman intent untuk mengakses penyedia dijelaskan secara detail dalam panduan
    ++    <a href="{@docRoot}guide/topics/providers/content-provider-basics.html">
    ++    Dasar-Dasar Penyedia Konten</a> di bagian "Akses data melalui intent". Tindakan,
    ++    tipe MIME, dan nilai data yang Anda gunakan untuk tugas yang tersedia dirangkum dalam Tabel 4, sedangkan
    ++    nilai ekstra yang bisa Anda gunakan bersama
    ++    {@link android.content.Intent#putExtra(String, String) putExtra()} tercantum dalam
    ++    dokumentasi acuan untuk {@link android.provider.ContactsContract.Intents.Insert}:
    ++</p>
    ++<p class="table-caption" id="table4">
    ++  <strong>Tabel 4.</strong> Intent Penyedia Kontak.
    ++</p>
    ++<table style="width:75%">
    ++    <tr>
    ++        <th scope="col" style="width:10%">Tugas</th>
    ++        <th scope="col" style="width:5%">Tindakan</th>
    ++        <th scope="col" style="width:10%">Data</th>
    ++        <th scope="col" style="width:10%">Tipe MIME</th>
    ++        <th scope="col" style="width:25%">Catatan</th>
    ++    </tr>
    ++    <tr>
    ++        <td><strong>Memilih kontak dari daftar</strong></td>
    ++        <td>{@link android.content.Intent#ACTION_PICK}</td>
    ++        <td>
    ++            Salah satu dari:
    ++            <ul>
    ++                <li>
    ++{@link android.provider.ContactsContract.Contacts#CONTENT_URI Contacts.CONTENT_URI},
    ++                    yang menampilkan daftar kontak.
    ++                </li>
    ++                <li>
    ++{@link android.provider.ContactsContract.CommonDataKinds.Phone#CONTENT_URI Phone.CONTENT_URI},
    ++                    yang menampilkan daftar nomor telepon untuk kontak mentah.
    ++                </li>
    ++                <li>
    ++{@link android.provider.ContactsContract.CommonDataKinds.StructuredPostal#CONTENT_URI
    ++StructuredPostal.CONTENT_URI},
    ++                    yang menampilkan daftar alamat pos untuk kontak mentah.
    ++                </li>
    ++                <li>
    ++{@link android.provider.ContactsContract.CommonDataKinds.Email#CONTENT_URI Email.CONTENT_URI},
    ++                    yang menampilkan daftar alamat email untuk kontak baru.
    ++                </li>
    ++            </ul>
    ++        </td>
    ++        <td>
    ++            Tidak digunakan
    ++        </td>
    ++        <td>
    ++            Menampilkan daftar kontak mentah atau daftar data dari kontak mentah, sesuai dengan tipe
    ++            URI konten yang Anda sediakan.
    ++            <p>
    ++                Panggil
    ++         {@link android.app.Activity#startActivityForResult(Intent, int) startActivityForResult()},
    ++                yang menghasilkan URI konten dari baris terpilih. Bentuk URI adalah
    ++                URI konten tabel dengan <code>LOOKUP_ID</code> baris yang ditambahkan padanya.
    ++                Aplikasi kontak perangkat mendelegasikan izin membaca dan menulis untuk URI konten ini
    ++                selama masa pakai aktivitas Anda. Lihat panduan
    ++                <a href="{@docRoot}guide/topics/providers/content-provider-basics.html">
    ++                Dasar-Dasar Penyedia Konten</a> untuk detail selengkapnya.
    ++            </p>
    ++        </td>
    ++    </tr>
    ++    <tr>
    ++        <td><strong>Menyisipkan kontak mentah baru</strong></td>
    ++        <td>{@link android.provider.ContactsContract.Intents.Insert#ACTION Insert.ACTION}</td>
    ++        <td>N/A</td>
    ++        <td>
    ++            {@link android.provider.ContactsContract.RawContacts#CONTENT_TYPE
    ++            RawContacts.CONTENT_TYPE}, tipe MIME untuk satu set kontak mentah.
    ++        </td>
    ++        <td>
    ++            Menampilkan layar <strong>Add Contact</strong> aplikasi kontak perangkat. Nilai
    ++            ekstra yang Anda tambahkan ke intent akan ditampilkan. Jika dikirimkan bersama
    ++        {@link android.app.Activity#startActivityForResult(Intent, int) startActivityForResult()},
    ++            URI konten dari kontak mentah yang baru saja ditambahkan akan dikembalikan ke
    ++            {@link android.app.Activity#onActivityResult(int, int, Intent) onActivityResult()}
    ++           metode callback aktivitas Anda pada argumen {@link android.content.Intent}, di
    ++            bidang "data". Untuk mendapatkan nilainya, panggil {@link android.content.Intent#getData()}.
    ++        </td>
    ++    </tr>
    ++    <tr>
    ++        <td><strong>Mengedit kontak</strong></td>
    ++        <td>{@link android.content.Intent#ACTION_EDIT}</td>
    ++        <td>
    ++            {@link android.provider.ContactsContract.Contacts#CONTENT_LOOKUP_URI} untuk
    ++            kontak. Aktivitas editor memungkinkan pengguna mengedit setiap data yang dikaitkan
    ++            dengan kontak ini.
    ++        </td>
    ++        <td>
    ++            {@link android.provider.ContactsContract.Contacts#CONTENT_ITEM_TYPE
    ++            Contacts.CONTENT_ITEM_TYPE}, kontak tunggal.</td>
    ++        <td>
    ++            Menampilkan layar Edit Contact dalam aplikasi kontak. Nilai ekstra yang Anda tambahkan
    ++            ke intent akan ditampilkan. Bila pengguna mengklik <strong>Done</strong> untuk menyimpan
    ++            hasil edit, aktivitas Anda kembali ke latar depan.
    ++        </td>
    ++    </tr>
    ++    <tr>
    ++        <td><strong>Menampilkan picker yang juga bisa menambahkan data.</strong></td>
    ++        <td>{@link android.content.Intent#ACTION_INSERT_OR_EDIT}</td>
    ++        <td>
    ++            N/A
    ++        </td>
    ++        <td>
    ++            {@link android.provider.ContactsContract.Contacts#CONTENT_ITEM_TYPE}
    ++        </td>
    ++         <td>
    ++            Intent ini selalu menampilkan layar picker aplikasi kontak. Pengguna bisa memilih
    ++            kontak untuk diedit, atau menambahkan kontak baru. Layar edit atau layar tambah
    ++            akan muncul, sesuai dengan pilihan pengguna, dan data ekstra yang Anda kirimkan dalam intent
    ++            akan ditampilkan. Jika aplikasi Anda menampilkan data kontak seperti email atau nomor telepon, gunakan
    ++            intent ini untuk memungkinkan pengguna menambahkan data ke kontak yang ada.
    ++
    ++            <p class="note">
    ++                <strong>Catatan:</strong> Tidak perlu mengirimkan nilai nama dalam ekstra intent ini,
    ++                karena pengguna selalu mengambil nama yang ada atau menambahkan nama baru. Lebih-lebih,
    ++                jika Anda mengirimkan nama, dan pengguna memilih untuk melakukan edit, aplikasi kontak akan
    ++                menampilkan nama yang Anda kirimkan, yang menimpa nilai sebelumnya. Jika pengguna tidak
    ++                menyadari hal ini dan menyimpan hasil edit, nilai lama akan hilang.
    ++            </p>
    ++         </td>
    ++    </tr>
    ++</table>
    ++<p>
    ++    Aplikasi kontak perangkat tidak memperbolehkan Anda menghapus kontak mentah atau datanya dengan
    ++    intent. Sebagai gantinya, untuk menghapus kontak mentah, gunakan
    ++    {@link android.content.ContentResolver#delete(Uri, String, String[]) ContentResolver.delete()}
    ++    atau {@link android.content.ContentProviderOperation#newDelete(Uri)
    ++    ContentProviderOperation.newDelete()}.
    ++</p>
    ++<p>
    ++    Cuplikan berikut menampilkan cara menyusun dan mengirimkan intent yang menyisipkan kontak dan data
    ++    mentah baru:
    ++</p>
    ++<pre>
    ++// Gets values from the UI
    ++String name = mContactNameEditText.getText().toString();
    ++String phone = mContactPhoneEditText.getText().toString();
    ++String email = mContactEmailEditText.getText().toString();
    ++
    ++String company = mCompanyName.getText().toString();
    ++String jobtitle = mJobTitle.getText().toString();
    ++
    ++// Creates a new intent for sending to the device's contacts application
    ++Intent insertIntent = new Intent(ContactsContract.Intents.Insert.ACTION);
    ++
    ++// Sets the MIME type to the one expected by the insertion activity
    ++insertIntent.setType(ContactsContract.RawContacts.CONTENT_TYPE);
    ++
    ++// Sets the new contact name
    ++insertIntent.putExtra(ContactsContract.Intents.Insert.NAME, name);
    ++
    ++// Sets the new company and job title
    ++insertIntent.putExtra(ContactsContract.Intents.Insert.COMPANY, company);
    ++insertIntent.putExtra(ContactsContract.Intents.Insert.JOB_TITLE, jobtitle);
    ++
    ++/*
    ++ * Demonstrates adding data rows as an array list associated with the DATA key
    ++ */
    ++
    ++// Defines an array list to contain the ContentValues objects for each row
    ++ArrayList&lt;ContentValues&gt; contactData = new ArrayList&lt;ContentValues&gt;();
    ++
    ++
    ++/*
    ++ * Defines the raw contact row
    ++ */
    ++
    ++// Sets up the row as a ContentValues object
    ++ContentValues rawContactRow = new ContentValues();
    ++
    ++// Adds the account type and name to the row
    ++rawContactRow.put(ContactsContract.RawContacts.ACCOUNT_TYPE, mSelectedAccount.getType());
    ++rawContactRow.put(ContactsContract.RawContacts.ACCOUNT_NAME, mSelectedAccount.getName());
    ++
    ++// Adds the row to the array
    ++contactData.add(rawContactRow);
    ++
    ++/*
    ++ * Sets up the phone number data row
    ++ */
    ++
    ++// Sets up the row as a ContentValues object
    ++ContentValues phoneRow = new ContentValues();
    ++
    ++// Specifies the MIME type for this data row (all data rows must be marked by their type)
    ++phoneRow.put(
    ++        ContactsContract.Data.MIMETYPE,
    ++        ContactsContract.CommonDataKinds.Phone.CONTENT_ITEM_TYPE
    ++);
    ++
    ++// Adds the phone number and its type to the row
    ++phoneRow.put(ContactsContract.CommonDataKinds.Phone.NUMBER, phone);
    ++
    ++// Adds the row to the array
    ++contactData.add(phoneRow);
    ++
    ++/*
    ++ * Sets up the email data row
    ++ */
    ++
    ++// Sets up the row as a ContentValues object
    ++ContentValues emailRow = new ContentValues();
    ++
    ++// Specifies the MIME type for this data row (all data rows must be marked by their type)
    ++emailRow.put(
    ++        ContactsContract.Data.MIMETYPE,
    ++        ContactsContract.CommonDataKinds.Email.CONTENT_ITEM_TYPE
    ++);
    ++
    ++// Adds the email address and its type to the row
    ++emailRow.put(ContactsContract.CommonDataKinds.Email.ADDRESS, email);
    ++
    ++// Adds the row to the array
    ++contactData.add(emailRow);
    ++
    ++/*
    ++ * Adds the array to the intent's extras. It must be a parcelable object in order to
    ++ * travel between processes. The device's contacts app expects its key to be
    ++ * Intents.Insert.DATA
    ++ */
    ++insertIntent.putParcelableArrayListExtra(ContactsContract.Intents.Insert.DATA, contactData);
    ++
    ++// Send out the intent to start the device's contacts app in its add contact activity.
    ++startActivity(insertIntent);
    ++</pre>
    ++<h3 id="DataIntegrity">Integritas data</h3>
    ++<p>
    ++    Karena repository kontak berisi data penting dan sensitif yang diharapkan pengguna agar
    ++    benar dan terbaru. Penyedia Kontak memiliki aturan yang didefinisikan dengan baik demi integritas data. Anda
    ++    bertanggung jawab untuk mematuhi aturan ini saat memodifikasi data kontak. Aturan-aturan penting itu
    ++    dicantumkan di sini:
    ++</p>
    ++<dl>
    ++    <dt>
    ++        Selalu tambahkan baris {@link android.provider.ContactsContract.CommonDataKinds.StructuredName}
    ++        untuk setiap baris {@link android.provider.ContactsContract.RawContacts} yang Anda tambahkan.
    ++    </dt>
    ++    <dd>
    ++        Baris {@link android.provider.ContactsContract.RawContacts} tanpa
    ++        baris {@link android.provider.ContactsContract.CommonDataKinds.StructuredName} dalam
    ++        tabel {@link android.provider.ContactsContract.Data} bisa menyebabkan masalah selama
    ++       agregasi.
    ++    </dd>
    ++    <dt>
    ++        Selalu tautkan baris {@link android.provider.ContactsContract.Data} baru ke baris
    ++        {@link android.provider.ContactsContract.RawContacts} induknya.
    ++    </dt>
    ++    <dd>
    ++        Baris {@link android.provider.ContactsContract.Data} yang tidak ditautkan ke
    ++        {@link android.provider.ContactsContract.RawContacts} tidak akan terlihat dalam aplikasi kontak
    ++        perangkat, dan itu bisa menimbulkan masalah dengan adaptor sinkronisasi.
    ++    </dd>
    ++    <dt>
    ++        Ubah data hanya untuk kontak mentah yang Anda miliki.
    ++    </dt>
    ++    <dd>
    ++        Ingatlah bahwa Penyedia Kontak biasanya mengelola data dari berbagai
    ++        tipe akun/layanan online. Anda harus memastikan bahwa aplikasi Anda hanya memodifikasi
    ++        atau menghapus data untuk baris milik Anda, dan bahwa aplikasi hanya menyisipkan data dengan
    ++        tipe akun dan nama yang Anda kontrol.
    ++    </dd>
    ++    <dt>
    ++        Selalu gunakan konstanta yang didefinisikan dalam {@link android.provider.ContactsContract} dan
    ++        subkelasnya untuk otoritas, URI konten, URI path, nama kolom, tipe MIME, dan
    ++        nilai {@link android.provider.ContactsContract.CommonDataKinds.CommonColumns#TYPE}.
    ++    </dt>
    ++    <dd>
    ++        Menggunakan konstanta ini membantu Anda menghindari kesalahan. Anda juga akan diberi tahu dengan peringatan
    ++        compiler jika salah satu konstanta sudah usang.
    ++    </dd>
    ++</dl>
    ++<h3 id="CustomData">Baris data custom</h3>
    ++<p>
    ++    Dengan membuat dan menggunakan tipe MIME custom sendiri, Anda bisa menyisipkan, mengedit, menghapus, dan mengambil
    ++    baris data sendiri dalam tabel {@link android.provider.ContactsContract.Data}. Baris Anda
    ++    dibatasi untuk menggunakan kolom yang didefinisikan dalam
    ++    {@link android.provider.ContactsContract.DataColumns}, meskipun Anda bisa memetakan nama kolom
    ++    bertipe spesifik sendiri ke nama kolom default. Dalam aplikasi kontak perangkat,
    ++    data untuk baris Anda ditampilkan, tetapi tidak bisa diedit atau dihapus, dan pengguna tidak bisa menambahkan
    ++    data lain. Untuk memudahkan pengguna mengubah baris data custom Anda, Anda harus menyediakan aktivitas
    ++    editor dalam aplikasi Anda sendiri.
    ++</p>
    ++<p>
    ++    Untuk menampilkan data custom, sediakan file <code>contacts.xml</code> berisi elemen
    ++    <code>&lt;ContactsAccountType&gt;</code> dan satu atau beberapa elemen anak
    ++    <code>&lt;ContactsDataKind&gt;</code>. Hal ini dijelaskan lebih detail di
    ++    bagian <a href="#SocialStreamDataKind"><code>&lt;ContactsDataKind&gt; element</code></a>.
    ++</p>
    ++<p>
    ++    Untuk mengetahui selengkapnya tentang tipe MIME custom, bacalah panduan
    ++    <a href="{@docRoot}guide/topics/providers/content-provider-creating.html">
    ++    Membuat Penyedia Konten</a>.
    ++</p>
    ++<h2 id="SyncAdapters">Adaptor Sinkronisasi Penyedia Kontak</h2>
    ++<p>
    ++    Penyedia Kontak didesain khusus untuk menangani <strong>sinkronisasi</strong>
    ++    data kontak antara perangkat dan layanan online. Hal ini memungkinkan pengguna mengunduh
    ++    data yang ada dari perangkat baru dan mengunggah data yang ada ke akun baru.
    ++    Sinkronisasi juga memastikan bahwa pengguna memiliki data terbaru, apa pun
    ++    sumber penambahan dan perubahan itu. Keuntungan lain dari sinkronisasi adalah membuat
    ++    data kontak tersedia sekalipun perangkat tidak terhubung ke jaringan.
    ++</p>
    ++<p>
    ++    Walaupun Anda bisa menerapkan sinkronisasi dengan berbagai cara, sistem Android menyediakan
    ++    kerangka kerja sinkronisasi plug-in yang mengotomatiskan tugas-tugas berikut:
    ++    <ul>
    ++
    ++    <li>
    ++        Memeriksa ketersediaan jaringan.
    ++    </li>
    ++    <li>
    ++        Menjadwalkan dan menjalankan sinkronisasi, berdasarkan preferensi pengguna.
    ++    </li>
    ++    <li>
    ++        Memulai kembali sinkronisasi yang telah berhenti.
    ++    </li>
    ++    </ul>
    ++<p>
    ++    Untuk menggunakan kerangka kerja ini, Anda harus menyediakan plug-in adaptor sinkronisasi. Setiap adaptor sinkronisasi bersifat unik bagi
    ++    layanan dan penyedia konten, tetapi mampu menangani beberapa nama akun untuk layanan yang sama. Kerangka
    ++    kerja ini juga memungkinkan beberapa adaptor sinkronisasi untuk layanan dan penyedia yang sama.
    ++</p>
    ++<h3 id="SyncClassesFiles">Kelas dan file adaptor sinkronisasi</h3>
    ++<p>
    ++    Anda mengimplementasikan adaptor sinkronisasi sebagai subkelas
    ++    {@link android.content.AbstractThreadedSyncAdapter} dan menginstalnya sebagai bagian dari aplikasi
    ++    Android. Sistem akan mempelajari adaptor sinkronisasi dari elemen-elemen di manifes
    ++     aplikasi Anda dan dari file XML khusus yang ditunjuk oleh manifes. File XML mendefinisikan
    ++    tipe akun untuk layanan online dan otoritas untuk penyedia konten, yang bersama-sama
    ++    mengidentifikasi adaptor secara unik. Adaptor sinkronisasi tidak menjadi aktif hingga pengguna menambahkan
    ++    akun untuk tipe akun adaptor sinkronisasi dan memungkinkan sinkronisasi untuk penyedia
    ++    konten yang disinkronkan dengan adaptor sinkronisasi.  Pada saat itu, sistem mulai mengelola adaptor,
    ++    memanggilnya seperlunya untuk menyinkronkan antara penyedia konten dan server.
    ++</p>
    ++<p class="note">
    ++    <strong>Catatan:</strong> Menggunakan tipe akun sebagai bagian dari identifikasi adaptor sinkronisasi memungkinkan
    ++    sistem mendeteksi dan menghimpun adaptor-adaptor sinkronisasi yang mengakses berbagai layanan dari
    ++    organisasi yang sama. Misalnya, adaptor sinkronisasi untuk semua layanan online Google semuanya memiliki tipe akun
    ++    yang sama <code>com.google</code>. Bila pengguna menambahkan akun Google ke perangkatnya, semua
    ++    adaptor sinkronisasi yang terinstal untuk layanan Google akan dicantumkan bersama; setiap adaptor sinkronisasi
    ++    yang tercantum akan menyinkronkan diri dengan berbagai penyedia konten pada perangkat.
    ++</p>
    ++<p>
    ++    Karena sebagian besar layanan mengharuskan pengguna untuk memeriksa identitas sebelum mengakses
    ++    data, sistem Android menawarkan kerangka kerja autentikasi yang serupa dengan, dan sering kali
    ++    digunakan bersama, kerangka kerja adaptor sinkronisasi. Kerangka kerja autentikasi menggunakan
    ++    autentikator plug-in yang merupakan subkelas
    ++    {@link android.accounts.AbstractAccountAuthenticator}. Autentikator memeriksa
    ++    identitas pengguna dalam langkah-langkah berikut:
    ++    <ol>
    ++        <li>
    ++            Mengumpulkan nama pengguna, kata sandi, atau informasi serupa (
    ++            <strong>kredensial</strong> pengguna).
    ++        </li>
    ++        <li>
    ++            Mengirimkan kredensial ke layanan
    ++        </li>
    ++        <li>
    ++            Memeriksa balasan layanan.
    ++        </li>
    ++    </ol>
    ++<p>
    ++    Jika layanan menerima kredensial, autentikator bisa
    ++    menyimpan kredensial itu untuk digunakan nanti. Karena kerangka kerja autentikator plug-in,
    ++    {@link android.accounts.AccountManager} bisa menyediakan akses ke setiap token autentikasi yang didukung suatu autentikator
    ++    dan dipilihnya untuk diekspos, seperti token autentikasi OAuth2.
    ++</p>
    ++<p>
    ++    Meskipun autentikasi tidak diharuskan, sebagian besar layanan kontak menggunakannya.
    ++    Akan tetapi, Anda tidak wajib menggunakan kerangka kerja autentikasi Android untuk melakukan autentikasi.
    ++</p>
    ++<h3 id="SyncAdapterImplementing">Implementasi adaptor sinkronisasi</h3>
    ++<p>
    ++    Untuk mengimplementasikan adaptor sinkronisasi bagi Penyedia Kontak, perlu Anda memulai dengan membuat
    ++    aplikasi Android yang berisi elemen-elemen berikut:
    ++</p>
    ++    <dl>
    ++        <dt>
    ++            Komponen {@link android.app.Service} yang merespons permintaan sistem untuk
    ++            mengikat ke adaptor sinkronisasi.
    ++        </dt>
    ++        <dd>
    ++            Bila sistem ingin menjalankan sinkronisasi, sistem akan memanggil metode
    ++            {@link android.app.Service#onBind(Intent) onBind()} layanan untuk mendapatkan
    ++            {@link android.os.IBinder} bagi adaptor sinkronisasi. Hal ini memungkinkan sistem melakukan
    ++            panggilan lintas proses ke metode adaptor.
    ++            <p>
    ++                Dalam contoh aplikasi <a href="{@docRoot}resources/samples/SampleSyncAdapter/index.html">
    ++               Sample Sync Adapter</a>, nama kelas layanan ini adalah
    ++                <code>com.example.android.samplesync.syncadapter.SyncService</code>.
    ++            </p>
    ++        </dd>
    ++        <dt>
    ++            Adaptor sinkronisasi yang sesungguhnya, diimplementasikan sebagai subkelas konkret dari
    ++            {@link android.content.AbstractThreadedSyncAdapter}.
    ++        </dt>
    ++        <dd>
    ++            Kelas ini melakukan pekerjaan mengunduh data dari server, mengunggah data ke
    ++            perangkat, dan menyelesaikan konflik. Pekerjaan utama adaptor
    ++            diselesaikan dengan metode {@link android.content.AbstractThreadedSyncAdapter#onPerformSync(
    ++            Account, Bundle, String, ContentProviderClient, SyncResult)
    ++            onPerformSync()}. Instance kelas ini harus dibuat sebagai singleton.
    ++            <p>
    ++                Dalam contoh aplikasi <a href="{@docRoot}resources/samples/SampleSyncAdapter/index.html">
    ++               Sample Sync Adapter</a>, adaptor sinkronisasi didefinisikan dalam kelas
    ++                <code>com.example.android.samplesync.syncadapter.SyncAdapter</code>.
    ++            </p>
    ++        </dd>
    ++        <dt>
    ++            Subkelas {@link android.app.Application}.
    ++        </dt>
    ++        <dd>
    ++            Kelas ini berfungsi sebagai pabrik untuk singleton adaptor sinkronisasi. Gunakan
    ++            metode {@link android.app.Application#onCreate()} untuk membuat instance adaptor sinkronisasi , dan
    ++            menyediakan metode "getter" statis untuk mengembalikan singleton ke
    ++            metode {@link android.app.Service#onBind(Intent) onBind()} dari layanan
    ++            adaptor sinkronisasi.
    ++        </dd>
    ++        <dt>
    ++            <strong>Opsional:</strong> Komponen {@link android.app.Service} yang merespons
    ++            permintaan dari sistem untuk autentikasi pengguna.
    ++        </dt>
    ++        <dd>
    ++            {@link android.accounts.AccountManager} memulai layanan ini untuk memulai proses
    ++            autentikasi. Metode {@link android.app.Service#onCreate()} layanan membuat instance
    ++            objek autentikator. Bila sistem ingin mengautentikasi akun pengguna untuk
    ++            adaptor sinkronisasi aplikasi, sistem akan memanggil metode
    ++{@link android.app.Service#onBind(Intent) onBind()}            layanan guna mendapatkan
    ++            {@link android.os.IBinder} bagi autentikator. Hal ini memungkinkan sistem melakukan
    ++            panggilan lintas proses ke metode autentikator.
    ++            <p>
    ++                Dalam contoh aplikasi <a href="{@docRoot}resources/samples/SampleSyncAdapter/index.html">
    ++               Sample Sync Adapter</a>, nama kelas layanan ini adalah
    ++                <code>com.example.android.samplesync.authenticator.AuthenticationService</code>.
    ++            </p>
    ++        </dd>
    ++        <dt>
    ++            <strong>Opsional:</strong> Subkelas konkret
    ++            {@link android.accounts.AbstractAccountAuthenticator} yang menangani permintaan
    ++            autentikasi.
    ++        </dt>
    ++        <dd>
    ++            Kelas ini menyediakan metode yang dipicu {@link android.accounts.AccountManager}
    ++            untuk mengautentikasi kredensial pengguna dengan layanan. Detail
    ++            proses autentikasi sangat bervariasi, berdasarkan teknologi server yang digunakan. Anda harus
    ++            mengacu ke dokumentasi bagi perangkat lunak server untuk mengetahui selengkapnya tentang autentikasi.
    ++            <p>
    ++                Dalam contoh aplikasi <a href="{@docRoot}resources/samples/SampleSyncAdapter/index.html">
    ++               Sample Sync Adapter</a>, autentikator didefinisikan dalam kelas
    ++                <code>com.example.android.samplesync.authenticator.Authenticator</code>.
    ++            </p>
    ++        </dd>
    ++        <dt>
    ++            File XML yang mendefinisikan adaptor sinkronisasi dan autentikator bagi sistem.
    ++        </dt>
    ++        <dd>
    ++            Komponen-komponen layanan adaptor sinkronisasi dan autentikator
    ++            didefinisikan dalam elemen-elemen
    ++<code>&lt;<a href="{@docRoot}guide/topics/manifest/service-element.html">service</a>&gt;</code>
    ++            di manifes aplikasi. Elemen-elemen ini
    ++            berisi
    ++<code>&lt;<a href="{@docRoot}guide/topics/manifest/meta-data-element.html">meta-data</a>&gt;</code>
    ++elemen anak yang menyediakan data tertentu ke
    ++            sistem:
    ++            <ul>
    ++                <li>
    ++                    Elemen
    ++<code>&lt;<a href="{@docRoot}guide/topics/manifest/meta-data-element.html">meta-data</a>&gt;</code>
    ++                    untuk layanan adaptor sinkronisasi menunjuk ke
    ++                    file XML <code>res/xml/syncadapter.xml</code>. Pada gilirannya, file ini mendefinisikan
    ++                    URI untuk layanan web yang akan disinkronkan dengan Penyedia Kontak,
    ++                    dan tipe akun untuk layanan web.
    ++                </li>
    ++                <li>
    ++                    <strong>Opsional:</strong> Elemen
    ++<code>&lt;<a href="{@docRoot}guide/topics/manifest/meta-data-element.html">meta-data</a>&gt;</code>
    ++                   untuk autentikator menunjuk ke file XML
    ++                    <code>res/xml/authenticator.xml</code>. Pada gilirannya, file ini menetapkan
    ++                    tipe akun yang didukung autentikator, serta sumber daya UI yang
    ++                    muncul selama proses autentikasi. Tipe akun yang ditetapkan dalam elemen ini
    ++                    harus sama dengan tipe akun yang ditetapkan untuk adaptor
    ++                    sinkronisasi.
    ++                </li>
    ++            </ul>
    ++        </dd>
    ++    </dl>
    ++<h2 id="SocialStream">Data Aliran Sosial</h2>
    ++<p>
    ++    Tabel-tabel {@code android.provider.ContactsContract.StreamItems} dan
    ++    {@code android.provider.ContactsContract.StreamItemPhotos}
    ++    mengelola data yang masuk dari jaringan sosial. Anda bisa menulis adaptor sinkronisasi yang menambahkan data aliran
    ++    dari jaringan Anda sendiri ke tabel-tabel ini, atau Anda bisa membaca data aliran dari tabel-tabel ini dan
    ++    menampilkannya dalam aplikasi sendiri, atau keduanya. Dengan fitur-fitur ini, layanan dan aplikasi
    ++    jaringan sosial Anda bisa diintegrasikan ke dalam pengalaman jaringan sosial Android.
    ++</p>
    ++<h3 id="StreamText">Teks aliran sosial</h3>
    ++<p>
    ++    Item aliran selalu dikaitkan dengan kontak mentah.
    ++    {@code android.provider.ContactsContract.StreamItemsColumns#RAW_CONTACT_ID} menautkan ke
    ++    nilai <code>_ID</code> untuk kontak mentah. Tipe akun dan nama akun kontak
    ++    mentah juga disimpan dalam baris item aliran.
    ++</p>
    ++<p>
    ++    Simpanlah data dari aliran Anda dalam kolom-kolom berikut:
    ++</p>
    ++<dl>
    ++    <dt>
    ++        {@code android.provider.ContactsContract.StreamItemsColumns#ACCOUNT_TYPE}
    ++    </dt>
    ++    <dd>
    ++        <strong>Diperlukan.</strong> Tipe akun pengguna untuk kontak mentah yang dikaitkan dengan
    ++        item aliran ini. Ingatlah untuk mengatur nilai ini saat Anda menyisipkan item aliran.
    ++    </dd>
    ++    <dt>
    ++        {@code android.provider.ContactsContract.StreamItemsColumns#ACCOUNT_NAME}
    ++    </dt>
    ++    <dd>
    ++        <strong>Diperlukan.</strong> Nama akun pengguna untuk kontak mentah yang dikaitkan dengan
    ++        item aliran ini. Ingatlah untuk mengatur nilai ini saat Anda menyisipkan item aliran.
    ++    </dd>
    ++    <dt>
    ++        Kolom identifier
    ++    </dt>
    ++    <dd>
    ++        <strong>Diperlukan.</strong> Anda harus memasukkan kolom identifier berikut saat
    ++        menyisipkan item aliran:
    ++        <ul>
    ++            <li>
    ++                {@code android.provider.ContactsContract.StreamItemsColumns#CONTACT_ID}:
    ++                Nilai {@code android.provider.BaseColumns#_ID} kontak yang dikaitkan dengan item aliran
    ++                ini.
    ++            </li>
    ++            <li>
    ++                {@code android.provider.ContactsContract.StreamItemsColumns#CONTACT_LOOKUP_KEY}:
    ++                Nilai {@code android.provider.ContactsContract.ContactsColumns#LOOKUP_KEY}
    ++                kontak yang dikaitkan dengan item aliran ini.
    ++            </li>
    ++            <li>
    ++                {@code android.provider.ContactsContract.StreamItemsColumns#RAW_CONTACT_ID}:
    ++                Nilai {@code android.provider.BaseColumns#_ID} kontak mentah yang dikaitkan dengan item aliran
    ++                ini.
    ++            </li>
    ++        </ul>
    ++    </dd>
    ++    <dt>
    ++        {@code android.provider.ContactsContract.StreamItemsColumns#COMMENTS}
    ++    </dt>
    ++    <dd>
    ++        Opsional. Menyimpan informasi rangkuman yang bisa Anda tampilkan di awal item aliran.
    ++    </dd>
    ++    <dt>
    ++        {@code android.provider.ContactsContract.StreamItemsColumns#TEXT}
    ++    </dt>
    ++    <dd>
    ++        Teks item aliran, baik konten yang diposting oleh sumber item,
    ++        maupun keterangan beberapa tindakan yang menghasilkan item aliran. Kolom ini bisa berisi
    ++        sembarang gambar sumber daya pemformatan dan tertanam yang bisa dirender oleh
    ++        {@link android.text.Html#fromHtml(String) fromHtml()}. Penyedia bisa memotong atau
    ++        menghapus konten yang panjang, tetapi penyedia akan mencoba menghindari memutus tag.
    ++    </dd>
    ++    <dt>
    ++        {@code android.provider.ContactsContract.StreamItemsColumns#TIMESTAMP}
    ++    </dt>
    ++    <dd>
    ++        String teks berisi waktu item aliran yang disisipkan atau diperbarui, berupa
    ++        <em>milidetik</em> sejak waktu patokan. Aplikasi yang menyisipkan atau memperbarui item aliran
    ++        bertanggung jawab memelihara kolom ini; aplikasi tidak dipelihara secara otomatis oleh
    ++        Penyedia Kontak.
    ++    </dd>
    ++</dl>
    ++<p>
    ++    Untuk menampilkan informasi pengidentifikasi item aliran Anda, gunakan
    ++    {@code android.provider.ContactsContract.StreamItemsColumns#RES_ICON},
    ++    {@code android.provider.ContactsContract.StreamItemsColumns#RES_LABEL}, dan
    ++    {@code android.provider.ContactsContract.StreamItemsColumns#RES_PACKAGE} untuk menautkan ke sumber daya
    ++    dalam aplikasi Anda.
    ++</p>
    ++<p>
    ++    Tabel {@code android.provider.ContactsContract.StreamItems} juga berisi kolom-kolom
    ++    {@code android.provider.ContactsContract.StreamItemsColumns#SYNC1} hingga
    ++    {@code android.provider.ContactsContract.StreamItemsColumns#SYNC4} untuk penggunaan eksklusif oleh
    ++    adaptor sinkronisasi.
    ++</p>
    ++<h3 id="StreamPhotos">Foto aliran sosial</h3>
    ++<p>
    ++   Tabel {@code android.provider.ContactsContract.StreamItemPhotos} menyimpan foto-foto yang dikaitkan
    ++   dengan item aliran. Kolom
    ++{@code android.provider.ContactsContract.StreamItemPhotosColumns#STREAM_ITEM_ID}   tabel ini
    ++   menautkan ke nilai dalam kolom {@code android.provider.BaseColumns#_ID}
    ++   tabel {@code android.provider.ContactsContract.StreamItems}. Acuan foto disimpan dalam
    ++   tabel pada kolom-kolom ini:
    ++</p>
    ++<dl>
    ++    <dt>
    ++        Kolom {@code android.provider.ContactsContract.StreamItemPhotos#PHOTO} (BLOB).
    ++    </dt>
    ++    <dd>
    ++        Representasi biner foto, yang diubah ukurannya oleh penyedia untuk penyimpanan dan tampilan.
    ++        Kolom ini tersedia untuk kompatibilitas ke belakang dengan versi Penyedia Kontak
    ++        sebelumnya yang menggunakannya untuk menyimpan foto. Akan tetapi, pada versi saat ini
    ++        Anda tidak boleh menggunakan kolom ini untuk menyimpan foto. Sebagai gantinya, gunakan
    ++         {@code android.provider.ContactsContract.StreamItemPhotosColumns#PHOTO_FILE_ID} atau
    ++        {@code android.provider.ContactsContract.StreamItemPhotosColumns#PHOTO_URI} (keduanya
    ++        dijelaskan dalam poin-poin berikut) untuk menyimpan foto di file. Kolom ini sekarang
    ++        berisi thumbnail foto, yang tersedia untuk dibaca.
    ++    </dd>
    ++    <dt>
    ++        {@code android.provider.ContactsContract.StreamItemPhotosColumns#PHOTO_FILE_ID}
    ++    </dt>
    ++    <dd>
    ++        Identifier numerik foto untuk kontak mentah. Tambahkan nilai ini ke konstanta
    ++        {@link android.provider.ContactsContract.DisplayPhoto#CONTENT_URI DisplayPhoto.CONTENT_URI}
    ++        untuk mendapatkan URI konten yang menunjuk ke satu file foto, kemudian panggil
    ++        {@link android.content.ContentResolver#openAssetFileDescriptor(Uri, String)
    ++        openAssetFileDescriptor()} untuk mendapatkan handle ke file foto.
    ++    </dd>
    ++    <dt>
    ++        {@code android.provider.ContactsContract.StreamItemPhotosColumns#PHOTO_URI}
    ++    </dt>
    ++    <dd>
    ++        URI konten menunjuk langsung ke file foto untuk foto yang diwakili oleh baris ini.
    ++        Panggillah {@link android.content.ContentResolver#openAssetFileDescriptor(Uri, String)
    ++        openAssetFileDescriptor()} dengan URI ini untuk mendapatkan handle ke file foto.
    ++    </dd>
    ++</dl>
    ++<h3 id="SocialStreamTables">Menggunakan tabel aliran sosial</h3>
    ++<p>
    ++    Tabel-tabel ini sama fungsinya dengan tabel-tabel utama lainnya dalam Penyedia Kontak, kecuali:
    ++</p>
    ++    <ul>
    ++        <li>
    ++            Tabel-tabel ini memerlukan izin akses tambahan. Untuk membaca dari tabel, aplikasi Anda
    ++            harus memiliki izin {@code android.Manifest.permission#READ_SOCIAL_STREAM}. Untuk memodifikasi
    ++            tabel, aplikasi Anda harus memiliki izin
    ++            {@code android.Manifest.permission#WRITE_SOCIAL_STREAM}.
    ++        </li>
    ++        <li>
    ++            Untuk tabel {@code android.provider.ContactsContract.StreamItems}, jumlah baris
    ++            yang disimpan bagi setiap kontak mentah adalah terbatas. Setelah batasnya tercapai,
    ++            Penyedia Kontak akan membuat ruang untuk baris item aliran baru dengan menghapus secara otomatis
    ++            baris yang memiliki
    ++            {@code android.provider.ContactsContract.StreamItemsColumns#TIMESTAMP} terlama. Untuk mendapatkan
    ++            batas, keluarkan query ke URI konten
    ++            {@code android.provider.ContactsContract.StreamItems#CONTENT_LIMIT_URI}. Anda bisa membiarkan
    ++            semua argumen selain URI konten diatur ke <code>null</code>. Query
    ++            menghasilkan sebuah Kursor yang berisi baris tunggal, dengan kolom tunggal
    ++            {@code android.provider.ContactsContract.StreamItems#MAX_ITEMS}.
    ++        </li>
    ++    </ul>
    ++
    ++<p>
    ++    Kelas {@code android.provider.ContactsContract.StreamItems.StreamItemPhotos} mendefinisikan
    ++    subtabel {@code android.provider.ContactsContract.StreamItemPhotos} yang berisi
    ++    baris foto untuk satu item aliran.
    ++</p>
    ++<h3 id="SocialStreamInteraction">Interaksi aliran sosial</h3>
    ++<p>
    ++    Data aliran sosial yang dikelola oleh Penyedia Kontak, bersama aplikasi kontak
    ++    perangkat, menawarkan cara andal untuk menghubungkan sistem jaringan sosial Anda
    ++    dengan kontak yang ada. Tersedia fitur-fitur berikut:
    ++</p>
    ++    <ul>
    ++        <li>
    ++            Dengan menyinkronkan layanan jaringan sosial ke Penyedia Kontak dengan adaptor
    ++            sinkronisasi, Anda bisa mengambil aktivitas terbaru untuk kontak pengguna dan menyimpannya dalam tabel-tabel
    ++             {@code android.provider.ContactsContract.StreamItems} dan
    ++            {@code android.provider.ContactsContract.StreamItemPhotos} untuk digunakan nanti.
    ++        </li>
    ++        <li>
    ++            Selain sinkronisasi rutin, Anda bisa memicu adaptor sinkronisasi agar mengambil
    ++            data tambahan bila pengguna memilih sebuah kontak untuk ditampilkan. Hal ini memungkinkan adaptor sinkronisasi Anda
    ++            mengambil foto resolusi tinggi dan item aliran terbaru untuk kontak.
    ++        </li>
    ++        <li>
    ++            Dengan mendaftarkan pemberitahuan pada aplikasi kontak perangkat dan Penyedia Kontak,
    ++            Anda bisa <em>menerima</em> intent saat kontak ditampilkan, dan pada saat itu
    ++            memperbarui status kontak dari layanan Anda. Pendekatan ini mungkin lebih cepat dan menggunakan
    ++            bandwidth lebih sedikit daripada melakukan sinkronisasi penuh dengan adaptor sinkronisasi.
    ++        </li>
    ++        <li>
    ++            Pengguna bisa menambahkan kontak ke layanan jaringan sosial Anda sambil melihat kontak
    ++            dalam aplikasi kontak perangkat. Anda mengaktifkannya dengan fitur "invite contact",
    ++            yang Anda aktifkan dengan kombinasi aktivitas yang menambahkan kontak yang ada ke jaringan
    ++           Anda, dan file XML yang menyediakan aplikasi kontak perangkat dan
    ++            Penyedia Kontak dengan detail aplikasi Anda.
    ++        </li>
    ++    </ul>
    ++<p>
    ++    Sinkronisasi rutin item aliran dengan Penyedia Kontak sama dengan
    ++    sinkronisasi lainnya. Untuk mengetahui selengkapnya tentang sinkronisasi, lihat bagian
    ++    <a href="#SyncAdapters">Adaptor Sinkronisasi Penyedia Kontak</a>. Mendaftarkan pemberitahuan dan
    ++    mengundang kontak dibahas dalam dua bagian berikutnya.
    ++</p>
    ++<h4>Pendaftaran untuk menangani tampilan jaringan sosial</h4>
    ++<p>
    ++    Untuk mendaftarkan adaptor sinkronisasi agar menerima pemberitahuan saat pengguna menampilkan kontak
    ++    yang dikelola oleh adaptor sinkronisasi Anda:
    ++</p>
    ++<ol>
    ++    <li>
    ++        Buat file yang bernama <code>contacts.xml</code> dalam direktori <code>res/xml/</code>
    ++        proyek Anda. Jika sudah memiliki file ini, langkah ini boleh dilewati.
    ++    </li>
    ++    <li>
    ++        Dalam file ini, tambahkan elemen
    ++<code>&lt;ContactsAccountType xmlns:android="http://schemas.android.com/apk/res/android"&gt;</code>.
    ++        Jika elemen ini sudah ada, langkah ini boleh dilewati.
    ++    </li>
    ++    <li>
    ++        Untuk mendaftarkan layanan yang diberitahukan saat pengguna membuka halaman detail kontak dalam
    ++        aplikasi kontak perangkat, tambahkan atribut
    ++        <code>viewContactNotifyService="<em>serviceclass</em>"</code> ke elemen, dengan
    ++        <code><em>serviceclass</em></code> sebagai nama kelas mutlak (fully qualified) dari layanan
    ++        yang seharusnya menerima intent dari aplikasi kontak perangkat. Untuk layanan
    ++        notifier, gunakan kelas yang memperluas {@link android.app.IntentService}, guna memudahkan layanan
    ++        untuk menerima intent. Data dalam intent yang masuk berisi URI konten dari kontak
    ++        mentah yang diklik pengguna. Untuk layanan notifier, Anda bisa mengikatnya ke kemudian memanggil
    ++        adaptor sinkronisasi Anda untuk memperbarui data bagi kontak mentah.
    ++    </li>
    ++</ol>
    ++<p>
    ++    Untuk mendaftarkan aktivitas agar dipanggil saat pengguna mengklik item aliran atau foto atau keduanya:
    ++</p>
    ++<ol>
    ++    <li>
    ++        Buat file yang bernama <code>contacts.xml</code> dalam direktori <code>res/xml/</code>
    ++        proyek Anda. Jika sudah memiliki file ini, langkah ini boleh dilewati.
    ++    </li>
    ++    <li>
    ++        Dalam file ini, tambahkan elemen
    ++<code>&lt;ContactsAccountType xmlns:android="http://schemas.android.com/apk/res/android"&gt;</code>.
    ++        Jika elemen ini sudah ada, langkah ini boleh dilewati.
    ++    </li>
    ++    <li>
    ++        Untuk mendaftarkan salah satu aktivitas Anda guna menangani klik oleh pengguna pada item aliran dalam
    ++        aplikasi kontak perangkat, tambahkan atribut
    ++        <code>viewStreamItemActivity="<em>activityclass</em>"</code> ke elemen, dengan
    ++        <code><em>activityclass</em></code> sebagai nama kelas mutlak (fully-qualified) dari aktivitas
    ++        yang harus menerima intent dari aplikasi kontak perangkat.
    ++    </li>
    ++    <li>
    ++        Untuk mendaftarkan salah satu aktivitas Anda guna menangani klik oleh pengguna pada foto aliran dalam
    ++        aplikasi kontak perangkat, tambahkan atribut
    ++        <code>viewStreamItemPhotoActivity="<em>activityclass</em>"</code> ke elemen, dengan
    ++        <code><em>activityclass</em></code> adalah kelas nama mutlak aktivitas
    ++        yang harus menerima intent dari aplikasi kontak perangkat.
    ++    </li>
    ++</ol>
    ++<p>
    ++    Elemen <code>&lt;ContactsAccountType&gt;</code> dijelaskan lebih detail di
    ++    bagian <a href="#SocialStreamAcctType">Elemen &lt;ContactsAccountType&gt;</a>.
    ++</p>
    ++<p>
    ++    Intent yang masuk berisi URI konten dari materi atau foto yang diklik pengguna.
    ++    Untuk mendapatkan aktivitas terpisah bagi item teks dan foto, gunakan kedua atribut dalam file yang sama.
    ++</p>
    ++<h4>Berinteraksi dengan layanan jaringan sosial Anda</h4>
    ++<p>
    ++    Pengguna tidak harus meninggalkan aplikasi perangkat kontak untuk mengundang kontak ke situs
    ++    jaringan sosial Anda. Sebagai gantinya, Anda bisa meminta aplikasi kontak perangkat mengirimkan intent untuk mengundang
    ++    kontak ke salah satu aktivitas Anda. Untuk mempersiapkannya:
    ++</p>
    ++<ol>
    ++    <li>
    ++        Buat file yang bernama <code>contacts.xml</code> dalam direktori <code>res/xml/</code>
    ++        proyek Anda. Jika sudah memiliki file ini, langkah ini boleh dilewati.
    ++    </li>
    ++    <li>
    ++        Dalam file ini, tambahkan elemen
    ++<code>&lt;ContactsAccountType xmlns:android="http://schemas.android.com/apk/res/android"&gt;</code>.
    ++        Jika elemen ini sudah ada, langkah ini boleh dilewati.
    ++    </li>
    ++    <li>
    ++        Tambahkan atribut-atribut berikut:
    ++        <ul>
    ++            <li><code>inviteContactActivity="<em>activityclass</em>"</code></li>
    ++            <li>
    ++                <code>inviteContactActionLabel="&#64;string/<em>invite_action_label</em>"</code>
    ++            </li>
    ++        </ul>
    ++        Nilai <code><em>activityclass</em></code> adalah nama kelas mutlak
    ++        aktivitas yang harus menerima intent ini. Nilai <code><em>invite_action_label</em></code>
    ++        adalah string teks yang ditampilkan dalam menu <strong>Add Connection</strong> dalam
    ++        aplikasi kontak perangkat.
    ++    </li>
    ++</ol>
    ++<p class="note">
    ++    <strong>Catatan:</strong> <code>ContactsSource</code> adalah nama tag yang sudah usang untuk
    ++    <code>ContactsAccountType</code>.
    ++</p>
    ++<h3 id="ContactsFile">Acuan contacts.xml</h3>
    ++<p>
    ++    File <code>contacts.xml</code> berisi elemen XML yang mengontrol interaksi adaptor sinkronisasi
    ++    Anda dan aplikasi dengan aplikasi kontak dan Penyedia Kontak. Elemen-elemen ini
    ++    dijelaskan di bagian-bagian selanjutnya.
    ++</p>
    ++<h4 id="SocialStreamAcctType">Elemen &lt;ContactsAccountType&gt;</h4>
    ++<p>
    ++    Elemen <code>&lt;ContactsAccountType&gt;</code> mengontrol interaksi aplikasi
    ++    Anda dengan aplikasi kontak. Sintaksnya adalah sebagai berikut:
    ++</p>
    ++<pre>
    ++&lt;ContactsAccountType
    ++        xmlns:android="http://schemas.android.com/apk/res/android"
    ++        inviteContactActivity="<em>activity_name</em>"
    ++        inviteContactActionLabel="<em>invite_command_text</em>"
    ++        viewContactNotifyService="<em>view_notify_service</em>"
    ++        viewGroupActivity="<em>group_view_activity</em>"
    ++        viewGroupActionLabel="<em>group_action_text</em>"
    ++        viewStreamItemActivity="<em>viewstream_activity_name</em>"
    ++        viewStreamItemPhotoActivity="<em>viewphotostream_activity_name</em>"&gt;
    ++</pre>
    ++<p>
    ++    <strong>dimuat dalam:</strong>
    ++</p>
    ++<p>
    ++    <code>res/xml/contacts.xml</code>
    ++</p>
    ++<p>
    ++    <strong>bisa berisi:</strong>
    ++</p>
    ++<p>
    ++    <strong><code>&lt;ContactsDataKind&gt;</code></strong>
    ++</p>
    ++<p>
    ++    <strong>Keterangan:</strong>
    ++</p>
    ++<p>
    ++    Mendeklarasikan komponen Android dan label UI yang memungkinkan pengguna mengundang salah satu kontak ke
    ++    jaringan sosial, memberi tahu pengguna bila salah satu aliran jaringan sosial diperbarui, dan
    ++    seterusnya.
    ++</p>
    ++<p>
    ++    Perhatikan bahwa awalan atribut <code>android:</code> tidak perlu untuk atribut-atribut
    ++    <code>&lt;ContactsAccountType&gt;</code>.
    ++</p>
    ++<p>
    ++    <strong>Atribut:</strong>
    ++</p>
    ++<dl>
    ++    <dt>{@code inviteContactActivity}</dt>
    ++    <dd>
    ++        Nama kelas mutlak aktivitas dalam aplikasi yang Anda ingin
    ++        aktifkan bila pengguna memilih <strong>Add connection</strong> dari aplikasi kontak
    ++        perangkat.
    ++    </dd>
    ++    <dt>{@code inviteContactActionLabel}</dt>
    ++    <dd>
    ++        String teks yang ditampilkan untuk aktivitas yang ditetapkan dalam
    ++        {@code inviteContactActivity}, dalam menu <strong>Add connection</strong>.
    ++        Misalnya, Anda bisa menggunakan string "Ikuti di jaringan saya". Anda bisa menggunakan identifier sumber daya
    ++        string untuk tabel ini.
    ++    </dd>
    ++    <dt>{@code viewContactNotifyService}</dt>
    ++    <dd>
    ++        Nama kelas mutlak layanan dalam aplikasi Anda yang harus menerima
    ++        pemberitahuan saat pengguna menampilkan kontak. Pemberitahuan ini dikirimkan oleh aplikasi kontak
    ++        perangkat; hal ini memungkinkan aplikasi Anda menunda operasi yang banyak memproses data
    ++        hingga dibutuhkan. Misalnya, aplikasi Anda bisa merespons pemberitahuan ini
    ++        dengan membaca dalam dan menampilkan foto resolusi tinggi kontak dan item aliran sosial
    ++        terbaru. Fitur ini dijelaskan lebih detail di bagian
    ++        <a href="#SocialStreamInteraction">Interaksi aliran sosial</a>. Anda bisa melihat
    ++        contoh layanan pemberitahuan dalam file <code>NotifierService.java</code> dalam contoh aplikasi
    ++        <a href="{@docRoot}resources/samples/SampleSyncAdapter/index.html">Sample Sync Adapter</a>.
    ++
    ++    </dd>
    ++    <dt>{@code viewGroupActivity}</dt>
    ++    <dd>
    ++        Nama kelas mutlak aktivitas dalam aplikasi yang bisa menampilkan
    ++        informasi grup. Bila pengguna mengklik label grup dalam aplikasi
    ++        kontak perangkat, UI aktivitas ini akan ditampilkan.
    ++    </dd>
    ++    <dt>{@code viewGroupActionLabel}</dt>
    ++    <dd>
    ++        Label yang ditampilkan aplikasi kontak untuk kontrol UI yang memungkinkan
    ++        pengguna melihat grup dalam aplikasi Anda.
    ++        <p>
    ++            Misalnya, jika Anda menginstal aplikasi Google+ di perangkat dan menyinkronkan
    ++            Google+ dengan aplikasi kontak, Anda akan melihat lingkaran Google+ tercantum sebagai grup
    ++            dalam tab <strong>Groups</strong> aplikasi kontak Anda. Jika Anda mengklik
    ++            lingkaran Google+, Anda akan melihat orang-orang di lingkaran itu tercantum sebagai satu "grup". Di atas
    ++            tampilan, Anda akan melihat ikon Google+; jika mengklik ikon itu, kontrol akan beralih ke
    ++            aplikasi Google+. Aplikasi kontak melakukan ini dengan
    ++            {@code viewGroupActivity}, yang menggunakan ikon Google+ sebagai nilai
    ++            {@code viewGroupActionLabel}.
    ++        </p>
    ++        <p>
    ++            Identifier sumber daya string diperbolehkan untuk atribut ini.
    ++        </p>
    ++    </dd>
    ++    <dt>{@code viewStreamItemActivity}</dt>
    ++    <dd>
    ++        Nama kelas mutlak aktivitas dalam aplikasi Anda
    ++        yang diluncurkan aplikasi kontak perangkat bila pengguna mengklik item aliran untuk kontak mentah.
    ++    </dd>
    ++    <dt>{@code viewStreamItemPhotoActivity}</dt>
    ++    <dd>
    ++        Nama kelas mutlak aktivitas yang diluncurkan
    ++        aplikasi kontak perangkat bila pengguna mengklik foto dalam item aliran
    ++        untuk kontak mentah.
    ++    </dd>
    ++</dl>
    ++<h4 id="SocialStreamDataKind">Elemen &lt;ContactsDataKind&gt;</h4>
    ++<p>
    ++    Elemen <code>&lt;ContactsDataKind&gt;</code> mengontrol tampilan baris data custom
    ++    aplikasi Anda dalam UI aplikasi kontak. Sintaksnya adalah sebagai berikut:
    ++</p>
    ++<pre>
    ++&lt;ContactsDataKind
    ++        android:mimeType="<em>MIMEtype</em>"
    ++        android:icon="<em>icon_resources</em>"
    ++        android:summaryColumn="<em>column_name</em>"
    ++        android:detailColumn="<em>column_name</em>"&gt;
    ++</pre>
    ++<p>
    ++    <strong>dimuat dalam:</strong>
    ++</p>
    ++<code>&lt;ContactsAccountType&gt;</code>
    ++<p>
    ++    <strong>Keterangan:</strong>
    ++</p>
    ++<p>
    ++    Gunakan elemen ini untuk memerintahkan aplikasi kontak agar menampilkan konten baris data custom sebagai
    ++    bagian dari detail kontak mentah. Setiap elemen anak <code>&lt;ContactsDataKind&gt;</code>
    ++    <code>&lt;ContactsAccountType&gt;</code> mewakili tipe baris data custom yang
    ++    ditambahkan adaptor sinkronisasi Anda ke tabel {@link android.provider.ContactsContract.Data}. Tambahkan satu
    ++    elemen <code>&lt;ContactsDataKind&gt;</code> untuk setiap tipe MIME custom yang Anda gunakan. Anda tidak harus
    ++    menambahkan elemen jika Anda memiliki baris data custom yang datanya tidak ingin ditampilkan.
    ++</p>
    ++<p>
    ++    <strong>Atribut:</strong>
    ++</p>
    ++<dl>
    ++    <dt>{@code android:mimeType}</dt>
    ++    <dd>
    ++        Tipe MIME custom yang telah Anda definisikan untuk salah satu tipe baris data custom dalam
    ++        tabel {@link android.provider.ContactsContract.Data}. Misalnya, nilai
    ++        <code>vnd.android.cursor.item/vnd.example.locationstatus</code> bisa berupa tipe MIME
    ++       custom untuk baris data yang mencatat lokasi kontak yang terakhir diketahui.
    ++    </dd>
    ++    <dt>{@code android:icon}</dt>
    ++    <dd>
    ++
    ++        <a href="{@docRoot}guide/topics/resources/drawable-resource.html">Sumber daya drawable</a>
    ++        Android yang ditampilkan aplikasi kontak di samping data Anda. Gunakan ini untuk menunjukkan kepada
    ++        pengguna bahwa data berasal dari layanan Anda.
    ++    </dd>
    ++    <dt>{@code android:summaryColumn}</dt>
    ++    <dd>
    ++        Nama kolom untuk yang pertama dari dua nilai yang diambil dari baris data. Nilai
    ++        ditampilkan sebagai baris pertama entri untuk baris data ini. Baris pertama
    ++        dimaksudkan untuk digunakan sebagai rangkuman data, tetapi itu bersifat opsional. Lihat juga
    ++        <a href="#detailColumn">android:detailColumn</a>.
    ++    </dd>
    ++    <dt>{@code android:detailColumn}</dt>
    ++    <dd>
    ++        Nama kolom untuk yang kedua dari dua nilai yang diambil dari baris data. Nilai
    ++        ditampilkan sebagai baris kedua entri untuk baris data ini. Lihat juga
    ++        {@code android:summaryColumn}.
    ++    </dd>
    ++</dl>
    ++<h2 id="AdditionalFeatures">Fitur Tambahan Penyedia Kontak</h2>
    ++<p>
    ++    Di samping fitur-fitur utama yang dijelaskan di bagian sebelumnya, Penyedia Kontak menawarkan
    ++   fitur-fitur berguna ini untuk digunakan bersama data kontak:
    ++</p>
    ++    <ul>
    ++       <li>Grup kontak</li>
    ++       <li>Fitur foto</li>
    ++    </ul>
    ++<h3 id="Groups">Grup kontak</h3>
    ++<p>
    ++    Penyedia Kontak secara opsional bisa melabeli kumpulan kontak terkait dengan data
    ++    <strong>grup</strong>. Jika server yang dikaitkan dengan akun pengguna
    ++    ingin mempertahankan grup, adaptor sinkronisasi untuk tipe akun dari akun itu harus mentransfer
    ++    data grup antara Penyedia Kontak dan server. Bila pengguna menambahkan kontak baru ke
    ++    server, kemudian memasukkan kontak ini dalam grup baru, adaptor sinkronisasi harus menambahkan grup baru
    ++    ke tabel {@link android.provider.ContactsContract.Groups}. Grup atau grup-grup yang memiliki kontak
    ++    disimpan dalam tabel {@link android.provider.ContactsContract.Data}, dengan menggunakan
    ++    tipe MIME {@link android.provider.ContactsContract.CommonDataKinds.GroupMembership}.
    ++</p>
    ++<p>
    ++    Jika Anda mendesain adaptor sinkronisasi yang akan menambahkan data kontak mentah dari
    ++    server ke Penyedia Kontak, dan Anda tidak menggunakan grup, maka Anda harus memberi tahu
    ++    penyedia itu agar membuat data Anda terlihat. Dalam kode yang dijalankan bila pengguna menambahkan akun
    ++    ke perangkat, perbarui baris {@link android.provider.ContactsContract.Settings}
    ++    yang ditambahkan Penyedia Kontak untuk akunnya. Dalam baris ini, atur nilai kolom
    ++    {@link android.provider.ContactsContract.SettingsColumns#UNGROUPED_VISIBLE
    ++    Settings.UNGROUPED_VISIBLE} ke 1. Bila melakukannya, Penyedia Kontak akan selalu
    ++    membuat data kontak Anda terlihat, meskipun Anda tidak menggunakan grup.
    ++</p>
    ++<h3 id="Photos">Foto kontak</h3>
    ++<p>
    ++    Tabel {@link android.provider.ContactsContract.Data} menyimpan foto sebagai baris dengan tipe MIME
    ++    {@link android.provider.ContactsContract.CommonDataKinds.Photo#CONTENT_ITEM_TYPE
    ++    Photo.CONTENT_ITEM_TYPE}. Kolom
    ++    {@link android.provider.ContactsContract.RawContactsColumns#CONTACT_ID} baris yang ditautkan ke
    ++    kolom {@code android.provider.BaseColumns#_ID} kontak mentah yang memiliki kolom itu.
    ++    Kelas {@link android.provider.ContactsContract.Contacts.Photo} mendefinisikan subtabel
    ++    {@link android.provider.ContactsContract.Contacts} yang berisi informasi foto untuk foto
    ++    utama kontak, yang merupakan foto utama dari kontak mentah utama kontak itu. Demikian pula,
    ++    kelas {@link android.provider.ContactsContract.RawContacts.DisplayPhoto} mendefinisikan subtabel
    ++    {@link android.provider.ContactsContract.RawContacts} yang berisi informasi foto untuk
    ++    foto utama kontak mentah.
    ++</p>
    ++<p>
    ++    Dokumentasi acuan untuk {@link android.provider.ContactsContract.Contacts.Photo} dan
    ++    {@link android.provider.ContactsContract.RawContacts.DisplayPhoto} berisi contoh-contoh
    ++    pengambilan informasi foto. Tidak ada kelas praktis untuk mengambil
    ++    thumbnail utama kontak mentah, tetapi Anda bisa mengirim query ke
    ++    tabel {@link android.provider.ContactsContract.Data}, dengan memilih
    ++    {@code android.provider.BaseColumns#_ID} kontak mentah,
    ++    {@link android.provider.ContactsContract.CommonDataKinds.Photo#CONTENT_ITEM_TYPE
    ++    Photo.CONTENT_ITEM_TYPE}, dan kolom {@link android.provider.ContactsContract.Data#IS_PRIMARY}
    ++    untuk menemukan baris foto utama kontak mentah.
    ++</p>
    ++<p>
    ++    Data aliran sosial untuk seseorang bisa juga disertai foto. Data ini disimpan dalam
    ++    tabel {@code android.provider.ContactsContract.StreamItemPhotos}, yang dijelaskan lebih detail
    ++    di bagian <a href="#StreamPhotos">Foto aliran sosial</a>.
    ++</p>
    +diff --git a/docs/html-intl/intl/id/guide/topics/providers/content-provider-basics.jd b/docs/html-intl/intl/id/guide/topics/providers/content-provider-basics.jd
    +new file mode 100644
    +index 0000000..4af9277
    +--- /dev/null
    ++++ b/docs/html-intl/intl/id/guide/topics/providers/content-provider-basics.jd
    +@@ -0,0 +1,1196 @@
    ++page.title=Dasar-Dasar Penyedia Konten
    ++@jd:body
    ++<div id="qv-wrapper">
    ++<div id="qv">
    ++<!-- In this document -->
    ++<h2>Dalam dokumen ini</h2>
    ++<ol>
    ++    <li>
    ++        <a href="#Basics">Ikhtisar</a>
    ++        <ol>
    ++            <li>
    ++                <a href="#ClientProvider">Mengakses penyedia</a>
    ++            </li>
    ++            <li>
    ++                <a href="#ContentURIs">URI Konten</a>
    ++            </li>
    ++        </ol>
    ++    </li>
    ++    <li>
    ++        <a href="#SimpleQuery">Mengambil Data dari Penyedia</a>
    ++        <ol>
    ++            <li>
    ++                <a href="#RequestPermissions">Meminta izin akses baca</a>
    ++            </li>
    ++            <li>
    ++                <a href="#Query">Membuat query</a>
    ++            </li>
    ++            <li>
    ++                <a href="#DisplayResults">Menampilkan hasil query</a>
    ++            </li>
    ++            <li>
    ++                <a href="#GettingResults">Mendapatkan data dari hasil query</a>
    ++            </li>
    ++        </ol>
    ++    </li>
    ++    <li>
    ++        <a href="#Permissions">Izin Penyedia Konten</a>
    ++    </li>
    ++    <li>
    ++        <a href="#Modifications">Menyisipkan, Memperbarui, dan Menghapus Data</a>
    ++        <ol>
    ++            <li>
    ++                <a href="#Inserting">Menyisipkan data</a>
    ++            </li>
    ++            <li>
    ++                <a href="#Updating">Memperbarui data</a>
    ++            </li>
    ++            <li>
    ++                <a href="#Deleting">Menghapus data</a>
    ++            </li>
    ++        </ol>
    ++    </li>
    ++    <li>
    ++        <a href="#DataTypes">Tipe Data Penyedia</a>
    ++    </li>
    ++    <li>
    ++        <a href="#AltForms">Bentuk-Bentuk Alternatif Akses Penyedia</a>
    ++        <ol>
    ++            <li>
    ++                <a href="#Batch">Akses batch</a>
    ++            </li>
    ++            <li>
    ++                <a href="#Intents">Akses data melalui intent</a>
    ++            </li>
    ++        </ol>
    ++    </li>
    ++    <li>
    ++        <a href="#ContractClasses">Kelas-kelas Kontrak</a>
    ++    </li>
    ++    <li>
    ++        <a href="#MIMETypeReference">Acuan Tipe MIME</a>
    ++    </li>
    ++</ol>
    ++
    ++    <!-- Key Classes -->
    ++<h2>Kelas-kelas utama</h2>
    ++    <ol>
    ++        <li>
    ++            {@link android.content.ContentProvider}
    ++        </li>
    ++        <li>
    ++            {@link android.content.ContentResolver}
    ++        </li>
    ++        <li>
    ++            {@link android.database.Cursor}
    ++        </li>
    ++        <li>
    ++            {@link android.net.Uri}
    ++        </li>
    ++    </ol>
    ++
    ++    <!-- Related Samples -->
    ++<h2>Contoh-Contoh Terkait</h2>
    ++    <ol>
    ++        <li>
    ++        <a href="{@docRoot}resources/samples/ApiDemos/src/com/example/android/apis/view/List2.html">
    ++        Kursor (Orang)</a>
    ++        </li>
    ++        <li>
    ++        <a href="{@docRoot}resources/samples/ApiDemos/src/com/example/android/apis/view/List7.html">
    ++        Kursor (Telepon)</a>
    ++        </li>
    ++    </ol>
    ++
    ++    <!-- See also -->
    ++<h2>Lihat juga</h2>
    ++    <ol>
    ++        <li>
    ++            <a href="{@docRoot}guide/topics/providers/content-provider-creating.html">
    ++            Membuat Penyedia Konten</a>
    ++        </li>
    ++        <li>
    ++            <a href="{@docRoot}guide/topics/providers/calendar-provider.html">
    ++            Penyedia Kalender</a>
    ++        </li>
    ++    </ol>
    ++</div>
    ++</div>
    ++
    ++    <!-- Intro paragraphs -->
    ++<p>
    ++    Penyedia konten mengelola akses ke repository data pusat. Penyedia
    ++    adalah bagian dari aplikasi Android, yang sering menyediakan UI-nya sendiri untuk menggunakan
    ++    data. Akan tetapi, penyedia konten terutama dimaksudkan untuk digunakan oleh
    ++    aplikasi lain, yang mengakses penyedia itu melalui objek klien penyedia. Bersama-sama, penyedia
    ++    dan klien penyedia menawarkan antarmuka standar yang konsisten ke data yang juga menangani
    ++    komunikasi antar-proses dan akses data aman.
    ++</p>
    ++<p>
    ++    Topik ini menerangkan dasar-dasar dari hal-hal berikut:
    ++</p>
    ++    <ul>
    ++        <li>Cara kerja penyedia konten.</li>
    ++        <li>API yang Anda gunakan untuk mengambil data dari penyedia konten.</li>
    ++        <li>API yang Anda gunakan untuk menyisipkan, memperbarui, atau menghapus data dalam penyedia konten.</li>
    ++        <li>Fitur API lainnya yang memudahkan kita menggunakan penyedia.</li>
    ++    </ul>
    ++
    ++    <!-- Basics -->
    ++<h2 id="Basics">Ikhtisar</h2>
    ++<p>
    ++    Penyedia konten menyajikan data ke aplikasi eksternal sebagai satu atau beberapa tabel yang
    ++    serupa dengan tabel-tabel yang ditemukan dalam database relasional. Sebuah baris mewakili instance beberapa tipe
    ++    data yang dikumpulkan penyedia, dan tiap kolom dalam baris mewakili sepotong
    ++    data yang dikumpulkan untuk sebuah instance.
    ++</p>
    ++<p>
    ++    Misalnya, salah satu penyedia bawaan di platform Android adalah kamus pengguna, yang
    ++    menyimpan ejaan kata-kata tidak-standar yang ingin disimpan pengguna. Tabel 1 mengilustrasikan
    ++    wujud data yang mungkin ada dalam tabel penyedia ini:
    ++</p>
    ++<p class="table-caption">
    ++    <strong>Tabel 1:</strong> Contoh tabel kamus pengguna.
    ++</p>
    ++<table id="table1" style="width: 50%;">
    ++    <tr>
    ++        <th style="width:20%" align="center" scope="col">word</th>
    ++        <th style="width:20%" align="center" scope="col">app id</th>
    ++        <th style="width:20%" align="center" scope="col">frequency</th>
    ++        <th style="width:20%" align="center" scope="col">locale</th>
    ++        <th style="width:20%" align="center" scope="col">_ID</th>
    ++    </tr>
    ++    <tr>
    ++        <td align="center" scope="row">mapreduce</td>
    ++        <td align="center">user1</td>
    ++        <td align="center">100</td>
    ++        <td align="center">en_US</td>
    ++        <td align="center">1</td>
    ++    </tr>
    ++    <tr>
    ++        <td align="center" scope="row">precompiler</td>
    ++        <td align="center">user14</td>
    ++        <td align="center">200</td>
    ++        <td align="center">fr_FR</td>
    ++        <td align="center">2</td>
    ++    </tr>
    ++    <tr>
    ++        <td align="center" scope="row">applet</td>
    ++        <td align="center">user2</td>
    ++        <td align="center">225</td>
    ++        <td align="center">fr_CA</td>
    ++        <td align="center">3</td>
    ++    </tr>
    ++    <tr>
    ++        <td align="center" scope="row">const</td>
    ++        <td align="center">user1</td>
    ++        <td align="center">255</td>
    ++        <td align="center">pt_BR</td>
    ++        <td align="center">4</td>
    ++    </tr>
    ++    <tr>
    ++        <td align="center" scope="row">int</td>
    ++        <td align="center">user5</td>
    ++        <td align="center">100</td>
    ++        <td align="center">en_UK</td>
    ++        <td align="center">5</td>
    ++    </tr>
    ++</table>
    ++<p>
    ++    Dalam tabel 1, tiap baris mewakili instance sebuah kata yang mungkin tidak
    ++    ditemukan dalam kamus standar. Tiap kolom mewakili beberapa data untuk kata itu, misalnya
    ++    bahasa lokal tempat kata itu ditemukan kali pertama. Header kolom adalah nama kolom yang disimpan dalam
    ++    penyedia. Untuk mengacu ke bahasa lokal suatu baris, Anda mengacu ke kolom <code>locale</code>-nya. Untuk
    ++    penyedia ini, kolom <code>_ID</code> berfungsi sebagai "kunci utama" kolom yang
    ++    dipelihara oleh penyedia secara otomatis.
    ++</p>
    ++<p class="note">
    ++    <strong>Catatan:</strong> Penyedia tidak diharuskan memiliki kunci utama, dan tidak diharuskan
    ++    menggunakan <code>_ID</code> sebagai nama kolom kunci utama jika kunci itu ada. Akan tetapi,
    ++    jika Anda ingin mengikat data dari penyedia ke {@link android.widget.ListView}, salah satu
    ++    nama kolom harus <code>_ID</code>. Ketentuan ini dijelaskan secara lebih detail di bagian
    ++    <a href="#DisplayResults">Menampilkan hasil query</a>.
    ++</p>
    ++<h3 id="ClientProvider">Mengakses penyedia</h3>
    ++<p>
    ++    Aplikasi mengakses data dari penyedia konten dengan
    ++    sebuah objek klien {@link android.content.ContentResolver}. Objek ini memiliki metode yang memanggil
    ++    metode dengan nama identik dalam objek penyedia, instance salah satu
    ++    subkelas konkret dari {@link android.content.ContentProvider}. Metode-metode
    ++    {@link android.content.ContentResolver} menyediakan fungsi-fungsi dasar
    ++    "CRUD" (create, retrieve, update, dan delete) pada penyimpanan yang persisten.
    ++</p>
    ++<p>
    ++    Objek {@link android.content.ContentResolver} dalam
    ++    proses aplikasi klien dan objek {@link android.content.ContentProvider} dalam aplikasi yang memiliki
    ++    penyedia itu secara otomatis akan menangani komunikasi antar-proses.
    ++    {@link android.content.ContentProvider} juga berfungsi sebagai lapisan abstraksi antara
    ++    repository datanya dan penampilan eksternal data sebagai tabel.
    ++</p>
    ++<p class="note">
    ++    <strong>Catatan:</strong> Untuk mengakses penyedia, aplikasi Anda biasanya harus meminta
    ++    izin tertentu dalam file manifesnya. Hal ini dijelaskan lebih detail di bagian
    ++    <a href="#Permissions">Izin Penyedia Konten</a>
    ++</p>
    ++<p>
    ++    Misalnya, untuk mendapatkan daftar kata dan lokalnya dari Penyedia Kamus Pengguna,
    ++    Anda memanggil {@link android.content.ContentResolver#query ContentResolver.query()}.
    ++    Metode {@link android.content.ContentResolver#query query()} memanggil
    ++    metode {@link android.content.ContentProvider#query ContentProvider.query()} yang didefinisikan oleh
    ++    Penyedia Kamus Pengguna. Baris-baris kode berikut menunjukkan sebuah
    ++    panggilan {@link android.content.ContentResolver#query ContentResolver.query()}:
    ++<p>
    ++<pre>
    ++// Queries the user dictionary and returns results
    ++mCursor = getContentResolver().query(
    ++    UserDictionary.Words.CONTENT_URI,   // The content URI of the words table
    ++    mProjection,                        // The columns to return for each row
    ++    mSelectionClause                    // Selection criteria
    ++    mSelectionArgs,                     // Selection criteria
    ++    mSortOrder);                        // The sort order for the returned rows
    ++</pre>
    ++<p>
    ++    Tabel 2 menampilkan cara argumen untuk
    ++    {@link android.content.ContentResolver#query
    ++    query(Uri,projection,selection,selectionArgs,sortOrder)} cocok dengan sebuah pernyataan SELECT di SQL:
    ++</p>
    ++<p class="table-caption">
    ++    <strong>Tabel 2:</strong> Query() dibandingkan dengan query SQL.
    ++</p>
    ++<table id="table2" style="width: 75%;">
    ++    <tr>
    ++        <th style="width:25%" align="center" scope="col">Argumen query()</th>
    ++        <th style="width:25%" align="center" scope="col">Kata kunci/parameter SELECT</th>
    ++        <th style="width:50%" align="center" scope="col">Catatan</th>
    ++    </tr>
    ++    <tr>
    ++        <td align="center"><code>Uri</code></td>
    ++        <td align="center"><code>FROM <em>table_name</em></code></td>
    ++        <td><code>Uri</code> memetakan ke tabel dalam penyedia yang bernama <em>table_name</em>.</td>
    ++    </tr>
    ++    <tr>
    ++        <td align="center"><code>projection</code></td>
    ++        <td align="center"><code><em>col,col,col,...</em></code></td>
    ++        <td>
    ++            <code>projection</code> adalah satu larik kolom yang harus disertakan untuk tiap baris
    ++            yang diambil.
    ++        </td>
    ++    </tr>
    ++    <tr>
    ++        <td align="center"><code>selection</code></td>
    ++        <td align="center"><code>WHERE <em>col</em> = <em>value</em></code></td>
    ++        <td><code>selection</code> menetapkan kriteria untuk memilih baris.</td>
    ++    </tr>
    ++    <tr>
    ++        <td align="center"><code>selectionArgs</code></td>
    ++        <td align="center">
    ++            (Tidak ada padanan persis. Argumen pemilihan mengganti <code>?</code> placeholder dalam
    ++            klausa pemilihan.)
    ++        </td>
    ++    </tr>
    ++    <tr>
    ++        <td align="center"><code>sortOrder</code></td>
    ++        <td align="center"><code>ORDER BY <em>col,col,...</em></code></td>
    ++        <td>
    ++            <code>sortOrder</code> menetapkan urutan munculnya baris dalam
    ++            {@link android.database.Cursor} yang dihasilkan.
    ++        </td>
    ++    </tr>
    ++</table>
    ++<h3 id="ContentURIs">URI Konten</h3>
    ++<p>
    ++    <strong>URI konten</strong> adalah URI yang mengidentifikasi data dalam penyedia. URI Konten
    ++    menyertakan nama simbolis seluruh penyedia (<strong>otoritas</strong>nya) dan sebuah
    ++    nama yang menunjuk ke tabel (<strong>path</strong>). Bila Anda memanggil
    ++    metode klien untuk mengakses tabel dalam penyedia, URI konten untuk tabel itu adalah salah satu
    ++    argumennya.
    ++</p>
    ++<p>
    ++    Dalam baris kode sebelumnya, konstanta
    ++    {@link android.provider.UserDictionary.Words#CONTENT_URI} mengandung URI konten dari
    ++    tabel "words" kamus pengguna. Objek {@link android.content.ContentResolver}
    ++    akan mengurai otoritas URI, dan menggunakannya untuk "mengetahui" penyedia dengan
    ++    membandingkan otoritas tersebut dengan sebuah tabel sistem berisi penyedia yang dikenal.
    ++{@link android.content.ContentResolver}    kemudian bisa mengirim argumen query ke penyedia
    ++    yang benar.
    ++</p>
    ++<p>
    ++    {@link android.content.ContentProvider} menggunakan bagian path dari URI konten untuk memilih
    ++    tabel yang akan diakses. Penyedia biasanya memiliki <strong>path</strong> untuk tiap tabel yang dieksposnya.
    ++</p>
    ++<p>
    ++    Dalam baris kode sebelumnya, URI lengkap untuk tabel "words" adalah:
    ++</p>
    ++<pre>
    ++content://user_dictionary/words
    ++</pre>
    ++<p>
    ++    dalam hal ini string <code>user_dictionary</code> adalah otoritas penyedia, dan string
    ++    <code>words</code> adalah path tabel. String
    ++    <code>content://</code> (<strong>skema</strong>) selalu ada,
    ++    dan mengidentifikasinya sebagai URI konten.
    ++</p>
    ++<p>
    ++    Banyak penyedia yang memperbolehkan Anda mengakses satu baris dalam tabel dengan menambahkan sebuah ID nilai
    ++    ke akhir URI. Misalnya, untuk mengambil sebuah baris yang <code>_ID</code>-nya adalah
    ++    <code>4</code> dari kamus pengguna, Anda bisa menggunakan URI konten ini:
    ++</p>
    ++<pre>
    ++Uri singleUri = ContentUris.withAppendedId(UserDictionary.Words.CONTENT_URI,4);
    ++</pre>
    ++<p>
    ++    Anda akan sering menggunakan nilai-nilai ID bila telah mengambil satu set baris kemudian ingin memperbarui atau menghapus
    ++    salah satunya.
    ++</p>
    ++<p class="note">
    ++    <strong>Catatan:</strong> Kelas-kelas {@link android.net.Uri} dan {@link android.net.Uri.Builder}
    ++    berisi metode praktis untuk membangun objek dari string URI yang tersusun dengan baik.
    ++{@link android.content.ContentUris}    berisi metode praktis untuk menambahkan nilai ID ke
    ++    URI. Cuplikan kode sebelumnya menggunakan {@link android.content.ContentUris#withAppendedId
    ++    withAppendedId()} untuk menambahkan id ke URI konten User Dictionary.
    ++</p>
    ++
    ++
    ++    <!-- Retrieving Data from the Provider -->
    ++<h2 id="SimpleQuery">Mengambil Data dari Penyedia</h2>
    ++<p>
    ++    Bagian ini menerangkan cara mengambil data dari penyedia, dengan menggunakan Penyedia Kamus Pengguna
    ++    sebagai contoh.
    ++</p>
    ++<p class="note">
    ++    Demi kejelasan, cuplikan kode di bagian ini memanggil
    ++    {@link android.content.ContentResolver#query ContentResolver.query()} pada "UI thread"". Akan tetapi, dalam
    ++    kode sesungguhnya, Anda harus melakukan query secara asinkron pada sebuah thread terpisah. Satu cara melakukannya
    ++    adalah menggunakan kelas {@link android.content.CursorLoader}, yang dijelaskan
    ++    lebih detail dalam panduan <a href="{@docRoot}guide/components/loaders.html">
    ++    Loader</a>. Juga, baris-baris kode tersebut hanyalah cuplikan; tidak menunjukkan sebuah aplikasi
    ++     lengkap.
    ++</p>
    ++<p>
    ++    Untuk mengambil data dari penyedia, ikutilah langkah-langkah dasar ini:
    ++</p>
    ++<ol>
    ++   <li>
    ++        Minta izin akses baca untuk penyedia itu.
    ++   </li>
    ++   <li>
    ++        Definisikan kode yang mengirim query ke penyedia.
    ++   </li>
    ++</ol>
    ++<h3 id="RequestPermissions">Meminta izin akses baca</h3>
    ++<p>
    ++    Untuk mengambil data dari penyedia, aplikasi Anda memerlukan "izin akses baca" untuk
    ++    penyedia itu. Anda tidak bisa meminta izin ini saat runtime; sebagai gantinya, Anda harus menetapkan bahwa
    ++    Anda memerlukan izin ini dalam manifes, dengan menggunakan elemen
    ++<code><a href="{@docRoot}guide/topics/manifest/uses-permission-element.html">&lt;uses-permission&gt;</a></code>
    ++    dan nama persis izin yang didefinisikan oleh
    ++    penyedia itu. Bila menetapkan elemen ini dalam manifes, Anda secara efektif "meminta"
    ++    izin ini untuk aplikasi Anda. Bila pengguna menginstal aplikasi Anda, mereka secara implisit akan memberikan
    ++    permintaan ini.
    ++</p>
    ++<p>
    ++    Untuk menemukan nama persis dari izin akses baca untuk penyedia yang sedang Anda gunakan, serta
    ++    nama-nama izin akses lain yang digunakan oleh penyedia, lihatlah dalam
    ++    dokumentasi penyedia.
    ++</p>
    ++<p>
    ++    Peran izin dalam yang mengakses penyedia dijelaskan lebih detail di bagian
    ++    <a href="#Permissions">Izin Penyedia Konten</a>.
    ++</p>
    ++<p>
    ++    Penyedia Kamus Pengguna mendefinisikan izin
    ++    <code>android.permission.READ_USER_DICTIONARY</code> dalam file manifesnya, sehingga
    ++    aplikasi yang ingin membaca dari penyedia itu harus meminta izin ini.
    ++</p>
    ++<!-- Constructing the query -->
    ++<h3 id="Query">Membuat query</h3>
    ++<p>
    ++    Langkah berikutnya dalam mengambil data penyedia adalah membuat query. Cuplikan kode pertama ini
    ++    mendefinisikan beberapa variabel untuk mengakses Penyedia Kamus Pengguna:
    ++</p>
    ++<pre class="prettyprint">
    ++
    ++// A "projection" defines the columns that will be returned for each row
    ++String[] mProjection =
    ++{
    ++    UserDictionary.Words._ID,    // Contract class constant for the _ID column name
    ++    UserDictionary.Words.WORD,   // Contract class constant for the word column name
    ++    UserDictionary.Words.LOCALE  // Contract class constant for the locale column name
    ++};
    ++
    ++// Defines a string to contain the selection clause
    ++String mSelectionClause = null;
    ++
    ++// Initializes an array to contain selection arguments
    ++String[] mSelectionArgs = {""};
    ++
    ++</pre>
    ++<p>
    ++    Cuplikan berikutnya menampilkan cara menggunakan
    ++    {@link android.content.ContentResolver#query ContentResolver.query()}, dengan menggunakan Penyedia Kamus Pengguna
    ++    sebagai contoh. Query klien penyedia serupa dengan query SQL, dan berisi satu
    ++    set kolom yang akan dihasilkan, satu set kriteria pemilihan, dan urutan sortir.
    ++</p>
    ++<p>
    ++    Set kolom yang harus dikembalikan query disebut dengan <strong>proyeksi</strong>
    ++    (variabel <code>mProjection</code>).
    ++</p>
    ++<p>
    ++    Ekspresi yang menetapkan baris yang harus diambil dipecah menjadi klausa pemilihan dan
    ++    argumen pemilihan. Klausa pemilihan adalah kombinasi ekspresi logis dan boolean,
    ++    nama kolom, dan nilai (variabel <code>mSelectionClause</code>). Jika Anda menetapkan
    ++    parameter <code>?</code> yang bisa diganti, sebagai ganti nilai, metode query akan mengambil nilai
    ++    dari larik argumen pemilihan (variabel <code>mSelectionArgs</code>).
    ++</p>
    ++<p>
    ++    Dalam cuplikan berikutnya, jika pengguna tidak memasukkan sebuah kata, klausa pemilihan akan diatur ke
    ++    <code>null</code>, dan query menghasilkan semua kata dalam penyedia. Jika pengguna memasukkan
    ++    sebuah kata, klausa pemilihan akan diatur ke <code>UserDictionary.Words.WORD + " = ?"</code> dan
    ++    elemen pertama larik argumen pemilihan diatur ke kata yang dimasukkan pengguna.
    ++</p>
    ++<pre class="prettyprint">
    ++/*
    ++ * This defines a one-element String array to contain the selection argument.
    ++ */
    ++String[] mSelectionArgs = {""};
    ++
    ++// Gets a word from the UI
    ++mSearchString = mSearchWord.getText().toString();
    ++
    ++// Remember to insert code here to check for invalid or malicious input.
    ++
    ++// If the word is the empty string, gets everything
    ++if (TextUtils.isEmpty(mSearchString)) {
    ++    // Setting the selection clause to null will return all words
    ++    mSelectionClause = null;
    ++    mSelectionArgs[0] = "";
    ++
    ++} else {
    ++    // Constructs a selection clause that matches the word that the user entered.
    ++    mSelectionClause = UserDictionary.Words.WORD + " = ?";
    ++
    ++    // Moves the user's input string to the selection arguments.
    ++    mSelectionArgs[0] = mSearchString;
    ++
    ++}
    ++
    ++// Does a query against the table and returns a Cursor object
    ++mCursor = getContentResolver().query(
    ++    UserDictionary.Words.CONTENT_URI,  // The content URI of the words table
    ++    mProjection,                       // The columns to return for each row
    ++    mSelectionClause                   // Either null, or the word the user entered
    ++    mSelectionArgs,                    // Either empty, or the string the user entered
    ++    mSortOrder);                       // The sort order for the returned rows
    ++
    ++// Some providers return null if an error occurs, others throw an exception
    ++if (null == mCursor) {
    ++    /*
    ++     * Insert code here to handle the error. Be sure not to use the cursor! You may want to
    ++     * call android.util.Log.e() to log this error.
    ++     *
    ++     */
    ++// If the Cursor is empty, the provider found no matches
    ++} else if (mCursor.getCount() &lt; 1) {
    ++
    ++    /*
    ++     * Insert code here to notify the user that the search was unsuccessful. This isn't necessarily
    ++     * an error. You may want to offer the user the option to insert a new row, or re-type the
    ++     * search term.
    ++     */
    ++
    ++} else {
    ++    // Insert code here to do something with the results
    ++
    ++}
    ++</pre>
    ++<p>
    ++    Query ini analog dengan pernyataan SQL:
    ++</p>
    ++<pre>
    ++SELECT _ID, word, locale FROM words WHERE word = &lt;userinput&gt; ORDER BY word ASC;
    ++</pre>
    ++<p>
    ++    Dalam pernyataan SQL ini, nama kolom yang sesungguhnya digunakan sebagai ganti konstanta kelas kontrak.
    ++</p>
    ++<h4 id="Injection">Melindungi dari input merusak</h4>
    ++<p>
    ++    Jika data dikelola oleh penyedia konten berada dalam database SQL, memasukkan data tak dipercaya eksternal
    ++    ke dalam pernyataan SQL mentah bisa menyebabkan injeksi SQL.
    ++</p>
    ++<p>
    ++    Perhatikan klausa pemilihan ini:
    ++</p>
    ++<pre>
    ++// Constructs a selection clause by concatenating the user's input to the column name
    ++String mSelectionClause =  "var = " + mUserInput;
    ++</pre>
    ++<p>
    ++    Jika melakukannya, Anda akan membuat pengguna menyambungkan SQL merusak ke pernyataan SQL Anda.
    ++    Misalnya, pengguna bisa memasukkan "nothing; DROP TABLE *;"  untuk <code>mUserInput</code>, yang
    ++    akan menghasilkan klausa pemilihan <code>var = nothing; DROP TABLE *;</code>. Karena
    ++    klausa pemilihan diperlakukan sebagai pernyataan SQL, hal ini bisa menyebabkan penyedia itu menghapus semua
    ++    tabel dalam database SQLite yang mendasarinya (kecuali penyedia disiapkan untuk menangkap upaya
    ++    <a href="http://en.wikipedia.org/wiki/SQL_injection">injeksi SQL</a>).
    ++</p>
    ++<p>
    ++    Untuk menghindari masalah ini, gunakan klausa pemilihan yang menggunakan <code>?</code> sebagai
    ++    parameter yang bisa diganti dan larik argumen pemilihan yang terpisah. Bila Anda melakukannya, input pengguna
    ++    akan dibatasi secara langsung pada query agar tidak ditafsirkan sebagai bagian dari pernyataan SQL.
    ++    Karena tidak diperlakukan sebagai SQL, input pengguna tidak bisa menyuntikkan SQL merusak. Sebagai ganti menggunakan
    ++    penyambungan untuk menyertakan input pengguna, gunakan klausa pemilihan ini:
    ++</p>
    ++<pre>
    ++// Constructs a selection clause with a replaceable parameter
    ++String mSelectionClause =  "var = ?";
    ++</pre>
    ++<p>
    ++    Buat larik argumen pemilihan seperti ini:
    ++</p>
    ++<pre>
    ++// Defines an array to contain the selection arguments
    ++String[] selectionArgs = {""};
    ++</pre>
    ++<p>
    ++    Masukkan nilai dalam larik argumen pemilihan seperti ini:
    ++</p>
    ++<pre>
    ++// Sets the selection argument to the user's input
    ++selectionArgs[0] = mUserInput;
    ++</pre>
    ++<p>
    ++    Sebuah klausa pemilihan yang menggunakan <code>?</code> sebagai parameter yang bisa diganti dan sebuah larik
    ++    argumen pemilihan adalah cara yang lebih disukai untuk menyebutkan pemilihan, sekalipun penyedia tidak
    ++    dibuat berdasarkan database SQL.
    ++</p>
    ++<!-- Displaying the results -->
    ++<h3 id="DisplayResults">Menampilkan hasil query</h3>
    ++<p>
    ++    Metode klien {@link android.content.ContentResolver#query ContentResolver.query()} selalu
    ++    menghasilkan {@link android.database.Cursor} berisi kolom-kolom yang ditetapkan oleh
    ++    proyeksi query untuk baris yang cocok dengan kriteria pemilihan query. Objek
    ++    {@link android.database.Cursor} menyediakan akses baca acak ke baris dan kolom yang
    ++    dimuatnya. Dengan metode {@link android.database.Cursor}, Anda bisa mengulang baris-baris dalam
    ++    hasil, menentukan tipe data tiap kolom, mengambil data dari kolom, dan memeriksa
    ++    properti lain dari hasil. Beberapa implementasi {@link android.database.Cursor}
    ++    akan memperbarui objek secara otomatis bila data penyedia berubah, atau memicu metode dalam objek pengamat
    ++    bila {@link android.database.Cursor} berubah, atau keduanya.
    ++</p>
    ++<p class="note">
    ++    <strong>Catatan:</strong> Penyedia bisa membatasi akses ke kolom berdasarkan sifat
    ++    objek yang membuat query. Misalnya, Penyedia Kontak membatasi akses untuk beberapa kolom pada
    ++    adaptor sinkronisasi, sehingga tidak akan mengembalikannya ke aktivitas atau layanan.
    ++</p>
    ++<p>
    ++    Jika tidak ada baris yang cocok dengan kriteria pemilihan, penyedia
    ++    akan mengembalikan objek {@link android.database.Cursor} dengan
    ++    {@link android.database.Cursor#getCount Cursor.getCount()} adalah 0 (kursor kosong).
    ++</p>
    ++<p>
    ++    Jika terjadi kesalahan internal, hasil query akan bergantung pada penyedia tertentu. Penyedia bisa
    ++    memilih untuk menghasilkan <code>null</code>, atau melontarkan {@link java.lang.Exception}.
    ++</p>
    ++<p>
    ++    Karena {@link android.database.Cursor} adalah "daftar" baris, cara yang cocok untuk menampilkan
    ++    konten {@link android.database.Cursor} adalah mengaitkannya dengan {@link android.widget.ListView}
    ++    melalui {@link android.widget.SimpleCursorAdapter}.
    ++</p>
    ++<p>
    ++    Cuplikan berikut melanjutkan kode dari cuplikan sebelumnya. Cuplikan ini membuat
    ++    objek {@link android.widget.SimpleCursorAdapter} berisi {@link android.database.Cursor}
    ++    yang diambil oleh query, dan mengatur objek ini menjadi adaptor bagi
    ++    {@link android.widget.ListView}:
    ++</p>
    ++<pre class="prettyprint">
    ++// Defines a list of columns to retrieve from the Cursor and load into an output row
    ++String[] mWordListColumns =
    ++{
    ++    UserDictionary.Words.WORD,   // Contract class constant containing the word column name
    ++    UserDictionary.Words.LOCALE  // Contract class constant containing the locale column name
    ++};
    ++
    ++// Defines a list of View IDs that will receive the Cursor columns for each row
    ++int[] mWordListItems = { R.id.dictWord, R.id.locale};
    ++
    ++// Creates a new SimpleCursorAdapter
    ++mCursorAdapter = new SimpleCursorAdapter(
    ++    getApplicationContext(),               // The application's Context object
    ++    R.layout.wordlistrow,                  // A layout in XML for one row in the ListView
    ++    mCursor,                               // The result from the query
    ++    mWordListColumns,                      // A string array of column names in the cursor
    ++    mWordListItems,                        // An integer array of view IDs in the row layout
    ++    0);                                    // Flags (usually none are needed)
    ++
    ++// Sets the adapter for the ListView
    ++mWordList.setAdapter(mCursorAdapter);
    ++</pre>
    ++<p class="note">
    ++    <strong>Catatan:</strong> Untuk mendukung {@link android.widget.ListView} dengan
    ++    {@link android.database.Cursor}, kursor harus berisi kolom bernama <code>_ID</code>.
    ++    Karena itu, query yang ditampilkan sebelumnya mengambil kolom <code>_ID</code> untuk
    ++    tabel "words", walaupun {@link android.widget.ListView} tidak menampilkannya.
    ++    Pembatasan ini juga menjelaskan mengapa sebagian besar penyedia memiliki kolom <code>_ID</code> untuk masing-masing
    ++    tabelnya.
    ++</p>
    ++
    ++        <!-- Getting data from query results -->
    ++<h3 id="GettingResults">Mendapatkan data dari hasil query</h3>
    ++<p>
    ++    Daripada sekadar menampilkan hasil query, Anda bisa menggunakannya untuk tugas-tugas lain. Misalnya,
    ++    Anda bisa mengambil ejaan dari kamus pengguna kemudian mencarinya dalam
    ++    penyedia lain. Caranya, ulangi baris-baris dalam {@link android.database.Cursor}:
    ++</p>
    ++<pre class="prettyprint">
    ++
    ++// Determine the column index of the column named "word"
    ++int index = mCursor.getColumnIndex(UserDictionary.Words.WORD);
    ++
    ++/*
    ++ * Only executes if the cursor is valid. The User Dictionary Provider returns null if
    ++ * an internal error occurs. Other providers may throw an Exception instead of returning null.
    ++ */
    ++
    ++if (mCursor != null) {
    ++    /*
    ++     * Moves to the next row in the cursor. Before the first movement in the cursor, the
    ++     * "row pointer" is -1, and if you try to retrieve data at that position you will get an
    ++     * exception.
    ++     */
    ++    while (mCursor.moveToNext()) {
    ++
    ++        // Gets the value from the column.
    ++        newWord = mCursor.getString(index);
    ++
    ++        // Insert code here to process the retrieved word.
    ++
    ++        ...
    ++
    ++        // end of while loop
    ++    }
    ++} else {
    ++
    ++    // Insert code here to report an error if the cursor is null or the provider threw an exception.
    ++}
    ++</pre>
    ++<p>
    ++    Implementasi {@link android.database.Cursor} berisi beberapa metode "get" untuk
    ++    mengambil berbagai tipe data dari objek. Misalnya, cuplikan sebelumnya
    ++    menggunakan {@link android.database.Cursor#getString getString()}. Implementasi juga memiliki
    ++    metode {@link android.database.Cursor#getType getType()} yang menghasilkan nilai yang menunjukkan
    ++    tipe data kolom.
    ++</p>
    ++
    ++
    ++    <!-- Requesting permissions -->
    ++<h2 id="Permissions">Izin Penyedia Konten</h2>
    ++<p>
    ++    Aplikasi penyedia bisa menetapkan izin yang harus dimiliki aplikasi lain untuk
    ++    mengakses data penyedia. Izin ini akan memastikan bahwa pengguna mengetahui data
    ++    yang coba diakses oleh aplikasi. Berdasarkan ketentuan penyedia, aplikasi lain
    ++    meminta izin yang diperlukannya untuk mengakses penyedia. Pengguna akhir akan melihat
    ++    izin yang diminta saat menginstal aplikasi.
    ++</p>
    ++<p>
    ++    Jika aplikasi penyedia tidak menetapkan izin apa pun, maka aplikasi lain tidak memiliki
    ++    akses ke data penyedia. Akan tetapi, komponen-komponen dalam aplikasi penyedia selalu memiliki
    ++    akses penuh untuk baca dan tulis, izin apa pun yang ditetapkan.
    ++</p>
    ++<p>
    ++    Seperti disebutkan sebelumnya, Penyedia Kamus Pengguna mensyaratkan izin
    ++    <code>android.permission.READ_USER_DICTIONARY</code> untuk mengambil data darinya.
    ++    Penyedia memiliki izin <code>android.permission.WRITE_USER_DICTIONARY</code>
    ++    yang terpisah untuk menyisipkan, memperbarui, atau menghapus data.
    ++</p>
    ++<p>
    ++    Untuk mendapatkan izin yang diperlukan untuk mengakses penyedia, aplikasi memintanya dengan elemen
    ++<code><a href="{@docRoot}guide/topics/manifest/uses-permission-element.html">&lt;uses-permission&gt;</a></code>
    ++    dalam file manifesnya. Bila Android Package Manager memasang aplikasi, pengguna
    ++    harus menyetujui semua izin yang diminta aplikasi. Jika pengguna menyetujui semuanya,
    ++    Package Manager akan melanjutkan instalasi; jika pengguna tidak menyetujui, Package Manager
    ++    akan membatalkan instalasi.
    ++</p>
    ++<p>
    ++    Elemen
    ++<code><a href="{@docRoot}guide/topics/manifest/uses-permission-element.html">&lt;uses-permission&gt;</a></code>
    ++    berikut meminta akses baca ke Penyedia Kamus Pengguna:
    ++</p>
    ++<pre>
    ++    &lt;uses-permission android:name="android.permission.READ_USER_DICTIONARY"&gt;
    ++</pre>
    ++<p>
    ++    Dampak izin pada akses penyedia dijelaskan secara lebih detail dalam panduan
    ++    <a href="{@docRoot}guide/topics/security/security.html">Keamanan dan Izin</a>.
    ++</p>
    ++
    ++
    ++<!-- Inserting, Updating, and Deleting Data -->
    ++<h2 id="Modifications">Menyisipkan, Memperbarui, dan Menghapus Data</h2>
    ++<p>
    ++    Lewat cara yang sama dengan cara mengambil data dari penyedia, Anda juga menggunakan interaksi antara
    ++    klien penyedia dan {@link android.content.ContentProvider} penyedia untuk memodifikasi data.
    ++    Anda memanggil metode {@link android.content.ContentResolver} dengan argumen yang diteruskan ke
    ++    metode {@link android.content.ContentProvider} yang sesuai. Penyedia dan klien penyedia
    ++    menangani secara otomatis keamanan dan komunikasi antar-proses.
    ++</p>
    ++<h3 id="Inserting">Menyisipkan data</h3>
    ++<p>
    ++    Untuk menyisipkan data ke penyedia, Anda memanggil metode
    ++    {@link android.content.ContentResolver#insert ContentResolver.insert()}.
    ++ Metode ini menyisipkan sebuah baris baru ke penyedia itu dan menghasilkan URI konten untuk baris itu.
    ++    Cuplikan ini menampilkan cara menyisipkan sebuah kata baru ke Penyedia Kamus Pengguna:
    ++</p>
    ++<pre class="prettyprint">
    ++// Defines a new Uri object that receives the result of the insertion
    ++Uri mNewUri;
    ++
    ++...
    ++
    ++// Defines an object to contain the new values to insert
    ++ContentValues mNewValues = new ContentValues();
    ++
    ++/*
    ++ * Sets the values of each column and inserts the word. The arguments to the "put"
    ++ * method are "column name" and "value"
    ++ */
    ++mNewValues.put(UserDictionary.Words.APP_ID, "example.user");
    ++mNewValues.put(UserDictionary.Words.LOCALE, "en_US");
    ++mNewValues.put(UserDictionary.Words.WORD, "insert");
    ++mNewValues.put(UserDictionary.Words.FREQUENCY, "100");
    ++
    ++mNewUri = getContentResolver().insert(
    ++    UserDictionary.Word.CONTENT_URI,   // the user dictionary content URI
    ++    mNewValues                          // the values to insert
    ++);
    ++</pre>
    ++<p>
    ++    Data untuk baris baru masuk ke dalam satu objek {@link android.content.ContentValues}, yang
    ++    serupa bentuknya dengan kursor satu-baris. Kolom dalam objek ini tidak perlu memiliki
    ++    tipe data yang sama, dan jika Anda tidak ingin menetapkan nilai sama sekali, Anda bisa mengatur kolom
    ++    ke <code>null</code> dengan menggunakan {@link android.content.ContentValues#putNull ContentValues.putNull()}.
    ++</p>
    ++<p>
    ++    Cuplikan ini tidak menambahkan kolom <code>_ID</code>, karena kolom ini dipelihara
    ++    secara otomatis. Penyedia menetapkan sebuah nilai unik <code>_ID</code> ke setiap baris yang
    ++    ditambahkan. Penyedia biasanya menggunakan nilai ini sebagai kunci utama tabel.
    ++</p>
    ++<p>
    ++    URI konten yang dihasilkan dalam <code>newUri</code> akan mengidentifikasi baris yang baru ditambahkan, dengan
    ++    format berikut:
    ++</p>
    ++<pre>
    ++content://user_dictionary/words/&lt;id_value&gt;
    ++</pre>
    ++<p>
    ++    <code>&lt;id_value&gt;</code> adalah konten <code>_ID</code> untuk baris baru.
    ++    Kebanyakan penyedia bisa mendeteksi bentuk URI konten ini secara otomatis kemudian melakukan
    ++    operasi yang diminta pada baris tersebut.
    ++</p>
    ++<p>
    ++    Untuk mendapatkan nilai <code>_ID</code> dari {@link android.net.Uri} yang dihasilkan, panggil
    ++    {@link android.content.ContentUris#parseId ContentUris.parseId()}.
    ++</p>
    ++<h3 id="Updating">Memperbarui data</h3>
    ++<p>
    ++    Untuk memperbarui sebuah baris, gunakan objek {@link android.content.ContentValues} dengan
    ++    nilai-nilai yang diperbarui, persis seperti yang Anda lakukan pada penyisipan, dan kriteria pemilihan persis seperti yang Anda lakukan pada query.
    ++    Metode klien yang Anda gunakan adalah
    ++    {@link android.content.ContentResolver#update ContentResolver.update()}. Anda hanya perlu menambahkan
    ++    nilai-nilai ke objek {@link android.content.ContentValues} untuk kolom yang sedang Anda perbarui. Jika Anda
    ++    ingin membersihkan konten kolom, aturlah nilai ke <code>null</code>.
    ++</p>
    ++<p>
    ++    Cuplikan berikut mengubah semua baris yang kolom lokalnya memiliki bahasa "en" ke
    ++    lokal <code>null</code>. Nilai hasil adalah jumlah baris yang diperbarui:
    ++</p>
    ++<pre>
    ++// Defines an object to contain the updated values
    ++ContentValues mUpdateValues = new ContentValues();
    ++
    ++// Defines selection criteria for the rows you want to update
    ++String mSelectionClause = UserDictionary.Words.LOCALE +  "LIKE ?";
    ++String[] mSelectionArgs = {"en_%"};
    ++
    ++// Defines a variable to contain the number of updated rows
    ++int mRowsUpdated = 0;
    ++
    ++...
    ++
    ++/*
    ++ * Sets the updated value and updates the selected words.
    ++ */
    ++mUpdateValues.putNull(UserDictionary.Words.LOCALE);
    ++
    ++mRowsUpdated = getContentResolver().update(
    ++    UserDictionary.Words.CONTENT_URI,   // the user dictionary content URI
    ++    mUpdateValues                       // the columns to update
    ++    mSelectionClause                    // the column to select on
    ++    mSelectionArgs                      // the value to compare to
    ++);
    ++</pre>
    ++<p>
    ++    Anda juga harus membersihkan input pengguna bila memanggil
    ++    {@link android.content.ContentResolver#update ContentResolver.update()}. Untuk mengetahui selengkapnya tentang
    ++    hal ini, bacalah bagian <a href="#Injection">Melindungi dari input merusak</a>.
    ++</p>
    ++<h3 id="Deleting">Menghapus data</h3>
    ++<p>
    ++    Menghapus baris serupa dengan mengambil baris data: Anda menetapkan kriteria pemilihan untuk baris
    ++    yang ingin Anda hapus dan metode klien akan menghasilkan jumlah baris yang dihapus.
    ++    Cuplikan berikut menghapus baris yang appid-nya sama dengan "user". Metode menghasilkan
    ++    jumlah baris yang dihapus.
    ++</p>
    ++<pre>
    ++
    ++// Defines selection criteria for the rows you want to delete
    ++String mSelectionClause = UserDictionary.Words.APP_ID + " LIKE ?";
    ++String[] mSelectionArgs = {"user"};
    ++
    ++// Defines a variable to contain the number of rows deleted
    ++int mRowsDeleted = 0;
    ++
    ++...
    ++
    ++// Deletes the words that match the selection criteria
    ++mRowsDeleted = getContentResolver().delete(
    ++    UserDictionary.Words.CONTENT_URI,   // the user dictionary content URI
    ++    mSelectionClause                    // the column to select on
    ++    mSelectionArgs                      // the value to compare to
    ++);
    ++</pre>
    ++<p>
    ++    Anda juga harus membersihkan input pengguna bila memanggil
    ++    {@link android.content.ContentResolver#delete ContentResolver.delete()}. Untuk mengetahui selengkapnya tentang
    ++    hal ini, bacalah bagian <a href="#Injection">Melindungi dari input merusak</a>.
    ++</p>
    ++<!-- Provider Data Types -->
    ++<h2 id="DataTypes">Tipe Data Penyedia</h2>
    ++<p>
    ++    Penyedia konten bisa menawarkan berbagai tipe data. Penyedia Kamus Pengguna hanya menawarkan
    ++    teks, namun penyedia juga bisa menawarkan format berikut:
    ++</p>
    ++    <ul>
    ++        <li>
    ++            integer
    ++        </li>
    ++        <li>
    ++            long integer (long)
    ++        </li>
    ++        <li>
    ++            floating point
    ++        </li>
    ++        <li>
    ++            long floating point (double)
    ++        </li>
    ++    </ul>
    ++<p>
    ++    Tipe data lain yang sering digunakan penyedia adalah Binary Large OBject (BLOB) yang diimplementasikan sebagai
    ++    larik byte 64 KB. Anda bisa melihat tipe data yang tersedia dengan memperhatikan metode "get"
    ++    kelas {@link android.database.Cursor}.
    ++</p>
    ++<p>
    ++    Tipe data tiap kolom dalam penyedia biasanya tercantum dalam dokumentasinya.
    ++    Tipe data untuk Penyedia Kamus Pengguna tercantum dalam dokumentasi acuan
    ++    untuk kelas kontraknya {@link android.provider.UserDictionary.Words} (kelas kontrak
    ++    dijelaskan di bagian <a href="#ContractClasses">Kelas-kelas Kontrak</a>).
    ++    Anda juga bisa menentukan tipe data dengan memanggil {@link android.database.Cursor#getType
    ++    Cursor.getType()}.
    ++</p>
    ++<p>
    ++    Penyedia juga memelihara informasi tipe data MIME untuk tiap URI konten yang didefinisikannya. Anda bisa
    ++    menggunakan informasi tipe MIME untuk mengetahui apakah aplikasi Anda bisa menangani data yang
    ++    disediakan penyedia, atau memilih tipe penanganan berdasarkan tipe MIME. Anda biasanya memerlukan
    ++    tipe MIME saat menggunakan penyedia yang berisi
    ++    struktur atau file data yang kompleks. Misalnya, tabel {@link android.provider.ContactsContract.Data}
    ++    dalam Penyedia Kontak menggunakan tipe MIME untuk memberi label tipe data kontak yang disimpan di tiap
    ++    baris. Untuk mendapatkan tipe MIME yang sesuai dengan URI konten, panggil
    ++    {@link android.content.ContentResolver#getType ContentResolver.getType()}.
    ++</p>
    ++<p>
    ++    Bagian <a href="#MIMETypeReference">Acuan Tipe MIME</a> menerangkan
    ++    sintaks tipe MIME baik yang standar maupun custom.
    ++</p>
    ++
    ++
    ++<!-- Alternative Forms of Provider Access -->
    ++<h2 id="AltForms">Bentuk-Bentuk Alternatif Akses Penyedia</h2>
    ++<p>
    ++    Tiga bentuk alternatif akses penyedia adalah penting dalam pengembangan aplikasi:
    ++</p>
    ++<ul>
    ++    <li>
    ++        <a href="#Batch">Akses batch</a>: Anda bisa membuat sebuah batch panggilan akses dengan metode-metode dalam
    ++        kelas {@link android.content.ContentProviderOperation}, kemudian menerapkannya dengan
    ++        {@link android.content.ContentResolver#applyBatch ContentResolver.applyBatch()}.
    ++    </li>
    ++    <li>
    ++        Query asinkron: Anda harus melakukan query dalam thread terpisah. Satu cara melakukannya adalah
    ++        menggunakan objek {@link android.content.CursorLoader}. Contoh-contoh dalam panduan
    ++        <a href="{@docRoot}guide/components/loaders.html">Loader</a> memperagakan
    ++        cara melakukannya.
    ++    </li>
    ++    <li>
    ++        <a href="#Intents">Akses data melalui intent</a>: Walaupun tidak bisa mengirim intent
    ++        ke penyedia secara langsung, Anda bisa mengirim intent ke aplikasi penyedia, yang
    ++        biasanya paling lengkap dibekali untuk memodifikasi data penyedia.
    ++    </li>
    ++</ul>
    ++<p>
    ++    Akses batch dan modifikasi melalui intent dijelaskan dalam bagian-bagian berikut.
    ++</p>
    ++<h3 id="Batch">Akses batch</h3>
    ++<p>
    ++    Akses batch ke penyedia berguna untuk menyisipkan baris dalam jumlah besar, atau menyisipkan
    ++    baris ke dalam beberapa tabel dalam panggilan metode yang sama, atau biasanya melakukan satu set
    ++    operasi lintas batas proses sebagai transaksi (operasi atomik).
    ++</p>
    ++<p>
    ++    Untuk mengakses penyedia dalam "mode batch",
    ++    buat satu larik objek {@link android.content.ContentProviderOperation}, kemudian
    ++    kirim larik itu ke penyedia konten dengan
    ++    {@link android.content.ContentResolver#applyBatch ContentResolver.applyBatch()}. Anda meneruskan
    ++    <em>otoritas</em> penyedia konten ke metode ini, daripada URI konten tertentu.
    ++    Ini memungkinkan tiap objek {@link android.content.ContentProviderOperation} dalam larik untuk bekerja
    ++    terhadap tabel yang berbeda. Panggilan ke {@link android.content.ContentResolver#applyBatch
    ++    ContentResolver.applyBatch()} menghasilkan satu larik hasil.
    ++</p>
    ++<p>
    ++    Keterangan kelas kontrak {@link android.provider.ContactsContract.RawContacts}
    ++    menyertakan cuplikan kode yang memperagakan penyisipan batch. Contoh aplikasi
    ++    <a href="{@docRoot}resources/samples/ContactManager/index.html">Contacts Manager</a>
    ++    berisi contoh akses batch dalam file sumber <code>ContactAdder.java</code>-nya
    ++.
    ++</p>
    ++<div class="sidebox-wrapper">
    ++<div class="sidebox">
    ++<h2>Menampilkan data dengan aplikasi pembantu</h2>
    ++<p>
    ++    Jika aplikasi Anda <em>memang</em> memiliki izin akses, Anda masih mungkin perlu menggunakan
    ++    intent untuk menampilkan data dalam aplikasi lain. Misalnya, aplikasi Kalender menerima
    ++    intent {@link android.content.Intent#ACTION_VIEW}, yang menampilkan tanggal atau kejadian tertentu.
    ++    Hal ini memungkinkan Anda menampilkan informasi kalender tanpa harus membuat UI sendiri.
    ++    Untuk mengetahui selengkapnya tentang fitur ini, lihat panduan
    ++    <a href="{@docRoot}guide/topics/providers/calendar-provider.html">Penyedia Kalender</a>.
    ++</p>
    ++<p>
    ++    Aplikasi yang Anda kirimi intent tidak harus aplikasi
    ++    yang terkait dengan penyedia. Misalnya, Anda bisa mengambil satu kontak dari
    ++    Penyedia Kontak, kemudian mengirim intent {@link android.content.Intent#ACTION_VIEW}
    ++    berisi URI konten untuk gambar kontak itu ke penampil gambar.
    ++</p>
    ++</div>
    ++</div>
    ++<h3 id="Intents">Akses data melalui intent</h3>
    ++<p>
    ++    Intent bisa menyediakan akses tidak langsung ke penyedia konten. Anda memperbolehkan pengguna mengakses
    ++    data dalam penyedia sekalipun aplikasi Anda tidak memiliki izin akses, baik dengan
    ++    mendapatkan intent yang dihasilkan aplikasi yang memiliki izin, atau dengan mengaktifkan
    ++    aplikasi yang memiliki izin dan membiarkan pengguna melakukan pekerjaan di dalamnya.
    ++</p>
    ++<h4>Mendapatkan akses dengan izin sementara</h4>
    ++<p>
    ++    Anda bisa mengakses data dalam penyedia konten, sekalipun tidak memiliki
    ++    izin akses yang sesuai, dengan mengirimkan intent ke aplikasi yang memang memiliki izin dan
    ++    menerima hasil berupa intent berisi izin "URI".
    ++    Inilah izin untuk URI konten tertentu yang berlaku hingga aktivitas yang menerima
    ++    izin selesai. Aplikasi yang memiliki izin tetap akan memberikan
    ++    izin sementara dengan mengatur flag dalam intent yang dihasilkan:
    ++</p>
    ++<ul>
    ++    <li>
    ++        <strong>Izin baca:</strong>
    ++        {@link android.content.Intent#FLAG_GRANT_READ_URI_PERMISSION}
    ++    </li>
    ++    <li>
    ++        <strong>Izin tulis:</strong>
    ++        {@link android.content.Intent#FLAG_GRANT_WRITE_URI_PERMISSION}
    ++    </li>
    ++</ul>
    ++<p class="note">
    ++    <strong>Catatan:</strong> Flag ini tidak memberikan akses baca atau tulis umum ke penyedia
    ++    yang otoritasnya dimuat dalam URI konten. Aksesnya hanya untuk URI itu sendiri.
    ++</p>
    ++<p>
    ++    Penyedia mendefinisikan izin URI untuk URI konten dalam manifesnya, dengan menggunakan atribut
    ++<code><a href="{@docRoot}guide/topics/manifest/provider-element.html#gprmsn">android:grantUriPermission</a></code>
    ++    dari elemen
    ++<code><a href="{@docRoot}guide/topics/manifest/provider-element.html">&lt;provider&gt;</a></code>
    ++,   serta elemen anak
    ++<code><a href="{@docRoot}guide/topics/manifest/grant-uri-permission-element.html">&lt;grant-uri-permission&gt;</a></code>
    ++    dari elemen
    ++<code><a href="{@docRoot}guide/topics/manifest/provider-element.html">&lt;provider&gt;</a></code>.
    ++ Mekanisme izin URI dijelaskan secara lebih detail dalam panduan
    ++    <a href="{@docRoot}guide/topics/security/security.html">Keamanan dan Izin</a>,
    ++    di bagian "Izin URI".
    ++</p>
    ++<p>
    ++    Misalnya, Anda bisa mengambil data untuk satu kontak di Penyedia Kontak, sekalipun tidak
    ++    memiliki izin {@link android.Manifest.permission#READ_CONTACTS}. Anda mungkin ingin melakukan
    ++    ini dalam aplikasi yang mengirim kartu ucapan elektronik ke seorang kenalan pada hari ulang tahunnya. Sebagai ganti
    ++    meminta {@link android.Manifest.permission#READ_CONTACTS}, yang memberi Anda akses ke semua
    ++    kontak pengguna dan semua informasinya, Anda lebih baik membiarkan pengguna mengontrol
    ++    kontak-kontak yang akan digunakan oleh aplikasi Anda. Caranya, gunakan proses berikut:
    ++</p>
    ++<ol>
    ++    <li>
    ++        Aplikasi Anda akan mengirim intent berisi tindakan
    ++        {@link android.content.Intent#ACTION_PICK} dan tipe MIME "contacts"
    ++        {@link android.provider.ContactsContract.RawContacts#CONTENT_ITEM_TYPE}, dengan menggunakan
    ++        metode {@link android.app.Activity#startActivityForResult
    ++        startActivityForResult()}.
    ++    </li>
    ++    <li>
    ++        Karena intent ini cocok dengan filter intent untuk
    ++        aktivitas "pemilihan" aplikasi People, aktivitas akan muncul ke latar depan.
    ++    </li>
    ++    <li>
    ++        Dalam aktivitas pemilihan, pengguna memilih sebuah
    ++        kontak untuk diperbarui. Bila ini terjadi, aktivitas pemilihan akan memanggil
    ++        {@link android.app.Activity#setResult setResult(resultcode, intent)}
    ++        untuk membuat intent yang akan diberikan kembali ke aplikasi Anda. Intent itu berisi URI konten
    ++        kontak yang dipilih pengguna, dan flag "extras"
    ++        {@link android.content.Intent#FLAG_GRANT_READ_URI_PERMISSION}. Semua flag ini memberikan
    ++        izin URI ke aplikasi Anda untuk membaca data kontak yang ditunjuk oleh
    ++        URI konten. Aktivitas pemilihan kemudian memanggil {@link android.app.Activity#finish()} untuk
    ++        mengembalikan kontrol ke aplikasi Anda.
    ++    </li>
    ++    <li>
    ++        Aktivitas Anda akan kembali ke latar depan, dan sistem memanggil metode
    ++        {@link android.app.Activity#onActivityResult onActivityResult()}
    ++        aktivitas Anda. Metode ini menerima intent yang dihasilkan oleh aktivitas pemilihan dalam
    ++        aplikasi People.
    ++    </li>
    ++    <li>
    ++        Dengan URI konten dari intent yang dihasilkan, Anda bisa membaca data kontak
    ++        dari Penyedia Kontak, sekalipun Anda tidak meminta izin akses baca tetap
    ++        ke penyedia dalam manifes Anda. Anda kemudian bisa mendapatkan informasi hari ulang tahun si kontak
    ++        atau alamat emailnya, kemudian mengirim kartu ucapan elektronik.
    ++    </li>
    ++</ol>
    ++<h4>Menggunakan aplikasi lain</h4>
    ++<p>
    ++    Satu cara mudah agar pengguna bisa memodifikasi data yang izin aksesnya tidak Anda miliki adalah
    ++    mengaktifkan aplikasi yang memiliki izin dan membiarkan pengguna melakukan pekerjaannya di sana.
    ++</p>
    ++<p>
    ++    Misalnya, aplikasi Kalender menerima
    ++    intent {@link android.content.Intent#ACTION_INSERT}, yang memungkinkan Anda mengaktifkan
    ++    UI penyisipan aplikasi itu. Anda bisa meneruskan data "extras" dalam intent ini, yang
    ++    digunakan aplikasi untuk mengisi dahulu UI-nya. Karena kejadian berulang memiliki sintaks yang rumit,
    ++    cara yang lebih disukai untuk menyisipkan kejadian ke dalam Penyedia Kalender adalah mengaktifkan aplikasi Kalender dengan
    ++    {@link android.content.Intent#ACTION_INSERT}, kemudian membiarkan pengguna menyisipkan kejadian di sana.
    ++</p>
    ++<!-- Contract Classes -->
    ++<h2 id="ContractClasses">Kelas-kelas Kontrak</h2>
    ++<p>
    ++    Kelas kontrak mendefinisikan konstanta yang membantu aplikasi menggunakan URI konten, nama
    ++    kolom, tindakan intent, dan fitur lain pada penyedia konten. Kelas kontrak tidak
    ++    disertakan secara otomatis bersama penyedia; pengembang penyedia harus mendefinisikannya kemudian
    ++    membuatnya tersedia bagi pengembang lain. Banyak penyedia yang disertakan pada platform Android
    ++    memiliki kelas kontrak yang sesuai dalam {@link android.provider} paketnya.
    ++</p>
    ++<p>
    ++    Misalnya, Penyedia Kamus Pengguna memiliki kelas kontrak
    ++    {@link android.provider.UserDictionary} yang berisi URI konten dan konstanta nama kolom. URI
    ++    konten untuk tabel "words" didefinisikan dalam konstanta
    ++    {@link android.provider.UserDictionary.Words#CONTENT_URI UserDictionary.Words.CONTENT_URI}.
    ++    Kelas {@link android.provider.UserDictionary.Words} juga berisi konstanta nama kolom,
    ++    yang digunakan dalam cuplikan contoh pada panduan ini. Misalnya, sebuah proyeksi query bisa
    ++    didefinisikan sebagai:
    ++</p>
    ++<pre>
    ++String[] mProjection =
    ++{
    ++    UserDictionary.Words._ID,
    ++    UserDictionary.Words.WORD,
    ++    UserDictionary.Words.LOCALE
    ++};
    ++</pre>
    ++<p>
    ++    Kelas kontrak lain adalah {@link android.provider.ContactsContract} untuk Penyedia Kontak.
    ++    Dokumentasi acuan untuk kelas ini menyertakan contoh cuplikan kode. Salah satu
    ++    subkelasnya, {@link android.provider.ContactsContract.Intents.Insert}, adalah
    ++    kelas kontrak yang berisi konstanta untuk intent dan data intent.
    ++</p>
    ++
    ++
    ++<!-- MIME Type Reference -->
    ++<h2 id="MIMETypeReference">Acuan Tipe MIME</h2>
    ++<p>
    ++    Penyedia konten bisa menghasilkan tipe media MIME standar, atau string tipe MIME custom, atau keduanya.
    ++</p>
    ++<p>
    ++    Tipe MIME memiliki format
    ++</p>
    ++<pre>
    ++<em>type</em>/<em>subtype</em>
    ++</pre>
    ++<p>
    ++    Misalnya, tipe MIME <code>text/html</code> yang dikenal luas memiliki tipe <code>text</code> dan
    ++    subtipe <code>html</code>. Jika penyedia menghasilkan tipe ini untuk sebuah URI, artinya
    ++    query dengan URI itu akan menghasilkan teks berisi tag HTML.
    ++</p>
    ++<p>
    ++    String tipe MIME custom, yang juga disebut dengan tipe MIME "khusus vendor", memiliki nilai-nilai
    ++    <em>tipe</em> dan <em>subtipe</em> yang lebih kompleks. Nilai <em>tipe</em> selalu
    ++</p>
    ++<pre>
    ++vnd.android.cursor.<strong>dir</strong>
    ++</pre>
    ++<p>
    ++    untuk beberapa baris, atau
    ++</p>
    ++<pre>
    ++vnd.android.cursor.<strong>item</strong>
    ++</pre>
    ++<p>
    ++    untuk satu baris.
    ++</p>
    ++<p>
    ++    <em>Subtipe</em> adalah khusus penyedia. Penyedia bawaan Android biasanya memiliki subtipe
    ++    sederhana. Misalnya, bila aplikasi Contacts membuat satu baris untuk nomor telepon,
    ++    aplikasi akan mengatur tipe MIME berikut di baris itu:
    ++</p>
    ++<pre>
    ++vnd.android.cursor.item/phone_v2
    ++</pre>
    ++<p>
    ++    Perhatikan bahwa nilai subtipe adalah sekadar <code>phone_v2</code>.
    ++</p>
    ++<p>
    ++    Pengembang penyedia lain bisa membuat pola subtipe sendiri berdasarkan
    ++    otoritas dan nama-nama tabel penyedia. Misalnya, perhatikan penyedia yang berisi jadwal kereta api.
    ++    Otoritas penyedia adalah <code>com.example.trains</code>, dan berisi tabel-tabel
    ++    Line1, Line2, dan Line3. Untuk merespons URI konten
    ++</p>
    ++<p>
    ++<pre>
    ++content://com.example.trains/Line1
    ++</pre>
    ++<p>
    ++    untuk tabel Line1, penyedia menghasilkan tipe MIME
    ++</p>
    ++<pre>
    ++vnd.android.cursor.<strong>dir</strong>/vnd.example.line1
    ++</pre>
    ++<p>
    ++     Untuk merespons URI konten
    ++</p>
    ++<pre>
    ++content://com.example.trains/Line2/5
    ++</pre>
    ++<p>
    ++    untuk baris 5 di tabel Line2, penyedia menghasilkan tipe MIME
    ++</p>
    ++<pre>
    ++vnd.android.cursor.<strong>item</strong>/vnd.example.line2
    ++</pre>
    ++<p>
    ++    Kebanyakan penyedia konten mendefinisikan konstanta kelas kontrak untuk tipe MIME yang digunakannya. Kelas kontrak
    ++    {@link android.provider.ContactsContract.RawContacts} pada Penyedia Kontak
    ++    misalnya, mendefinisikan konstanta
    ++    {@link android.provider.ContactsContract.RawContacts#CONTENT_ITEM_TYPE} untuk tipe MIME
    ++    baris kontak mentah tunggal.
    ++</p>
    ++<p>
    ++    URI konten untuk baris-baris tunggal dijelaskan di bagian
    ++    <a href="#ContentURIs">URI Konten</a>.
    ++</p>
    +diff --git a/docs/html-intl/intl/id/guide/topics/providers/content-provider-creating.jd b/docs/html-intl/intl/id/guide/topics/providers/content-provider-creating.jd
    +new file mode 100644
    +index 0000000..7fbc613
    +--- /dev/null
    ++++ b/docs/html-intl/intl/id/guide/topics/providers/content-provider-creating.jd
    +@@ -0,0 +1,1214 @@
    ++page.title=Membuat Penyedia Konten
    ++@jd:body
    ++<div id="qv-wrapper">
    ++<div id="qv">
    ++
    ++
    ++<h2>Dalam dokumen ini</h2>
    ++<ol>
    ++    <li>
    ++        <a href="#DataStorage">Mendesain Penyimpanan Data</a>
    ++    </li>
    ++    <li>
    ++        <a href="#ContentURI">Mendesain URI Konten</a>
    ++    </li>
    ++    <li>
    ++        <a href="#ContentProvider">Mengimplementasikan Kelas ContentProvider</a>
    ++        <ol>
    ++            <li>
    ++                <a href="#RequiredAccess">Metode-Metode yang Diperlukan</a>
    ++            </li>
    ++            <li>
    ++                <a href="#Query">Mengimplementasikan metode query()</a>
    ++            </li>
    ++            <li>
    ++                <a href="#Insert">Mengimplementasikan metode insert()</a>
    ++            </li>
    ++            <li>
    ++                <a href="#Delete">Mengimplementasikan metode delete()</a>
    ++            </li>
    ++            <li>
    ++                <a href="#Update">Mengimplementasikan metode update()</a>
    ++            </li>
    ++            <li>
    ++                <a href="#OnCreate">Mengimplementasikan metode onCreate()</a>
    ++            </li>
    ++        </ol>
    ++    </li>
    ++    <li>
    ++        <a href="#MIMETypes">Mengimplementasikan Tipe MIME Penyedia Konten</a>
    ++        <ol>
    ++            <li>
    ++                <a href="#TableMIMETypes">Tipe MIME untuk tabel</a>
    ++            </li>
    ++            <li>
    ++                <a href="#FileMIMETypes">Tipe MIME untuk file</a>
    ++            </li>
    ++        </ol>
    ++    </li>
    ++    <li>
    ++        <a href="#ContractClass">Mengimplementasikan Kelas Kontrak</a>
    ++    </li>
    ++    <li>
    ++        <a href="#Permissions">Mengimplementasikan Izin Penyedia Konten</a>
    ++    </li>
    ++    <li>
    ++        <a href="#ProviderElement">Elemen &lt;provider&gt;</a>
    ++    </li>
    ++    <li>
    ++        <a href="#Intents">Intent dan Akses Data</a>
    ++    </li>
    ++</ol>
    ++<h2>Kelas-kelas utama</h2>
    ++    <ol>
    ++        <li>
    ++            {@link android.content.ContentProvider}
    ++        </li>
    ++        <li>
    ++            {@link android.database.Cursor}
    ++        </li>
    ++        <li>
    ++            {@link android.net.Uri}
    ++        </li>
    ++    </ol>
    ++<h2>Contoh-Contoh Terkait</h2>
    ++    <ol>
    ++        <li>
    ++            <a href="{@docRoot}resources/samples/NotePad/index.html">
    ++                Aplikasi contoh Note Pad
    ++            </a>
    ++        </li>
    ++    </ol>
    ++<h2>Lihat juga</h2>
    ++    <ol>
    ++        <li>
    ++            <a href="{@docRoot}guide/topics/providers/content-provider-basics.html">
    ++            Dasar-Dasar Penyedia Konten</a>
    ++        </li>
    ++        <li>
    ++            <a href="{@docRoot}guide/topics/providers/calendar-provider.html">
    ++            Penyedia Kalender</a>
    ++        </li>
    ++    </ol>
    ++</div>
    ++</div>
    ++
    ++
    ++<p>
    ++    Penyedia konten mengelola akses ke repository data pusat. Anda mengimplementasikan
    ++    penyedia sebagai satu atau beberapa kelas dalam aplikasi Android, bersama elemen-elemen dalam
    ++    file manifes. Salah satu kelas Anda mengimplementasikan subkelas
    ++    {@link android.content.ContentProvider}, yang merupakan antarmuka antara penyedia Anda dan
    ++    aplikasi lain. Walaupun penyedia konten dimaksudkan untuk menyediakan data bagi
    ++    aplikasi lain, Anda tentu saja bisa memiliki aktivitas dalam aplikasi yang memungkinkan pengguna
    ++    melakukan query dan memodifikasi data yang dikelola oleh penyedia Anda.
    ++</p>
    ++<p>
    ++    Bagian selebihnya dalam topik ini adalah daftar langkah-langkah dasar untuk membangun penyedia konten dan daftar
    ++    API yang akan digunakan.
    ++</p>
    ++
    ++
    ++<!-- Before You Start Building -->
    ++<h2 id="BeforeYouStart">Sebelum Anda Mulai Membangun</h2>
    ++<p>
    ++    Sebelum Anda mulai membangun penyedia, lakukanlah hal-hal berikut:
    ++</p>
    ++<ol>
    ++    <li>
    ++        <strong>Putuskan apakah Anda memerlukan penyedia konten</strong>. Anda perlu membangun sebuah
    ++        penyedia konten jika ingin menyediakan salah satu atau beberapa dari fitur berikut:
    ++        <ul>
    ++            <li>Anda ingin menawarkan data atau file yang kompleks ke aplikasi lain.</li>
    ++            <li>Anda ingin memungkinkan pengguna menyalin data yang kompleks dari aplikasi Anda ke dalam aplikasi lain.</li>
    ++            <li>Anda ingin menyediakan saran pencarian custom dengan menggunakan kerangka kerja pencarian.</li>
    ++        </ul>
    ++    <p>
    ++        Anda <em>tidak</em> mengharuskan penyedia untuk menggunakan database SQLite jika hanya digunakan dalam
    ++        aplikasi sendiri.
    ++    </p>
    ++    </li>
    ++    <li>
    ++        Jika Anda belum siap melakukannya, bacalah topik
    ++        <a href="{@docRoot}guide/topics/providers/content-provider-basics.html">
    ++        Dasar-Dasar Penyedia Konten</a> untuk mengetahui selengkapnya tentang penyedia.
    ++    </li>
    ++</ol>
    ++<p>
    ++    Berikutnya, ikuti langkah-langkah ini untuk membangun penyedia:
    ++</p>
    ++<ol>
    ++    <li>
    ++        Desain penyimpanan mentah untuk data Anda. Penyedia konten menawarkan data dengan dua cara:
    ++        <dl>
    ++            <dt>
    ++                Data file
    ++            </dt>
    ++            <dd>
    ++                Data yang biasanya masuk ke dalam file, misalnya
    ++                foto, audio, atau video. Simpan file dalam ruang privat
    ++                aplikasi Anda. Untuk merespons permintaan file dari aplikasi lain,
    ++                penyedia Anda bisa menawarkan handle ke file tersebut.
    ++            </dd>
    ++            <dt>
    ++                Data "terstruktur"
    ++            </dt>
    ++            <dd>
    ++                Data yang biasanya masuk ke dalam database, larik, atau struktur serupa.
    ++                Simpan data dalam bentuk yang kompatibel dengan tabel berisi baris dan kolom. Baris
    ++                mewakili entitas, misalnya satu orang atau satu barang inventori. Kolom mewakili
    ++                beberapa data untuk entitas itu, misalnya nama orang atau harga barang. Cara umum untuk
    ++                menyimpan tipe data ini adalah dalam database SQLite, namun Anda bisa menggunakan tipe
    ++                penyimpanan apa saja yang persisten. Untuk mengetahui selengkapnya tentang tipe penyimpanan yang tersedia di
    ++                sistem Android, lihat bagian <a href="#DataStorage">
    ++                Mendesain Penyimpanan Data</a>.
    ++            </dd>
    ++        </dl>
    ++    </li>
    ++    <li>
    ++        Definisikan sebuah implementasi konkret kelas {@link android.content.ContentProvider} dan
    ++        metode yang diperlukannya. Kelas ini adalah antarmuka antara data Anda dan bagian selebihnya pada
    ++        sistem Android. Untuk informasi selengkapnya tentang kelas ini, lihat bagian
    ++        <a href="#ContentProvider">Mengimplementasikan Kelas ContentProvider</a>.
    ++    </li>
    ++    <li>
    ++        Definisikan string otoritas, semua URI isinya, dan nama-nama kolom penyedia. Jika Anda ingin
    ++        penyedia aplikasi menangani intent, definisikan juga semua tindakan intent, data ekstra,
    ++        dan flag. Definisikan juga izin yang akan Anda syaratkan terhadap aplikasi yang ingin
    ++        mengakses data Anda. Anda harus mempertimbangkan pendefinisian semua nilai ini sebagai konstanta di
    ++        kelas kontrak terpisah; nantinya, Anda bisa mengekspos kelas ini kepada pengembang lain. Untuk
    ++        informasi selengkapnya tentang URI konten, lihat
    ++        bagian <a href="#ContentURI">Mendesain URI Konten</a>.
    ++        Untuk informasi selengkapnya tentang intent, lihat
    ++        bagian <a href="#Intents">Intent dan Akses Data</a>.
    ++    </li>
    ++    <li>
    ++        Tambahkan bagian opsional lainnya, seperti data contoh atau implementasi
    ++        {@link android.content.AbstractThreadedSyncAdapter} yang bisa menyinkronkan data antara
    ++        penyedia dan data berbasis cloud.
    ++    </li>
    ++</ol>
    ++
    ++
    ++<!-- Designing Data Storage -->
    ++<h2 id="DataStorage">Mendesain Penyimpanan Data</h2>
    ++<p>
    ++    Penyedia konten adalah antarmuka ke data yang disimpan dalam format terstruktur. Sebelum membuat
    ++    antarmuka, Anda harus memutuskan cara menyimpan data. Anda bisa menyimpan data dalam bentuk apa saja yang Anda
    ++    sukai, kemudian mendesain antarmuka untuk membaca dan menulis data yang diperlukan.
    ++</p>
    ++<p>
    ++    Berikut ini adalah beberapa teknologi penyimpanan data yang tersedia di Android:
    ++</p>
    ++<ul>
    ++    <li>
    ++        Sistem Android menyertakan API database SQLite yang digunakan penyedia Android sendiri
    ++        untuk menyimpan data berorientasi tabel. Kelas
    ++        {@link android.database.sqlite.SQLiteOpenHelper} membantu Anda membuat database, dan kelas
    ++        {@link android.database.sqlite.SQLiteDatabase} adalah kelas dasar untuk mengakses
    ++        database.
    ++        <p>
    ++            Ingatlah bahwa Anda tidak harus menggunakan database untuk mengimplementasikan repository. Penyedia
    ++            muncul secara eksternal sebagai satu set tabel, yang serupa dengan sebuah database relasional, namun ini
    ++            bukan persyaratan untuk implementasi internal penyedia.
    ++        </p>
    ++    </li>
    ++    <li>
    ++        Untuk menyimpan file data, Android memiliki beragam API berorientasi file.
    ++        Untuk mengetahui selengkapnya tentang penyimpanan file, bacalah topik
    ++        <a href="{@docRoot}guide/topics/data/data-storage.html">Penyimpanan Data</a>. Jika Anda sedang
    ++        mendesain penyedia yang menawarkan data yang terkait dengan media seperti musik atau video, Anda bisa
    ++        memiliki penyedia yang mengombinasikan data tabel dan file.
    ++    </li>
    ++    <li>
    ++        Untuk bekerja dengan data berbasis jaringan, gunakan kelas-kelas dalam {@link java.net} dan
    ++        {@link android.net}. Anda juga bisa menyinkronkan data berbasis jaringan dengan penyimpanan data lokal
    ++        seperti database, kemudian menawarkan data sebagai tabel atau file.
    ++        Aplikasi contoh <a href="{@docRoot}resources/samples/SampleSyncAdapter/index.html">
    ++        Sample Sync Adapter</a> memperagakan tipe sinkronisasi ini.
    ++    </li>
    ++</ul>
    ++<h3 id="DataDesign">
    ++    Pertimbangan desain data
    ++</h3>
    ++<p>
    ++    Berikut ini adalah beberapa tip untuk mendesain struktur data penyedia:
    ++</p>
    ++<ul>
    ++    <li>
    ++        Data tabel harus selalu memiliki kolom "kunci utama" yang dipelihara oleh penyedia
    ++        sebagai nilai numerik unik untuk setiap baris. Anda bisa menggunakan nilai ini untuk menautkan baris ke
    ++        baris yang terkait dalam tabel lain (dengan menggunakannya sebagai "kunci asing"). Walaupun Anda bisa menggunakan nama
    ++        apa saja untuk kolom ini, menggunakan {@link android.provider.BaseColumns#_ID BaseColumns._ID} adalah
    ++        pilihan terbaik, karena menautkan hasil query penyedia dengan
    ++        {@link android.widget.ListView} mensyaratkan bahwa salah satu kolom yang diambil memiliki nama
    ++        <code>_ID</code>.
    ++    </li>
    ++    <li>
    ++        Jika Anda ingin untuk menyediakan gambar bitmap atau potongan data berorientasi file lainnya yang berukuran sangat besar, simpanlah
    ++        data dalam sebuah file kemudian sediakan secara tidak langsung sebagai ganti menyimpannya secara langsung dalam
    ++        tabel. Jika melakukannya, Anda perlu memberi tahu pengguna penyedia Anda bahwa mereka perlu menggunakan metode file
    ++        {@link android.content.ContentResolver} untuk mengakses data.
    ++    </li>
    ++    <li>
    ++        Gunakan tipe data Binary Large OBject (BLOB) untuk menyimpan data yang bervariasi ukurannya atau memiliki
    ++        struktur yang beragam. Misalnya, Anda bisa menggunakan sebuah kolom BLOB untuk menyimpan
    ++        <a href="http://code.google.com/p/protobuf">buffer protokol</a> atau
    ++        <a href="http://www.json.org">struktur JSON</a>.
    ++        <p>
    ++            Anda juga bisa menggunakan BLOB untuk mengimplementasikan tabel yang <em>tidak bergantung skema</em>. Dalam
    ++            tipe tabel ini, Anda mendefinisikan kolom kunci utama, kolom tipe MIME, dan satu atau beberapa
    ++            kolom generik sebagai BLOB. Arti dari data dalam kolom-kolom BLOB ditunjukkan
    ++            oleh nilai dalam kolom tipe MIME. Cara ini memungkinkan Anda menyimpan berbagai tipe baris dalam
    ++            tabel yang sama. Tabel "data"
    ++            {@link android.provider.ContactsContract.Data} Penyedia Kontak adalah contoh tabel yang tidak bergantung skema
    ++            tersebut.
    ++        </p>
    ++    </li>
    ++</ul>
    ++<!-- Designing Content URIs -->
    ++<h2 id="ContentURI">Mendesain URI Konten</h2>
    ++<p>
    ++    <strong>URI konten</strong> adalah URI yang mengidentifikasi data dalam penyedia. URI Konten
    ++    berisi nama simbolis seluruh penyedia (<strong>otoritas</strong>nya) dan sebuah
    ++    nama yang menunjuk ke tabel atau file (<strong>path</strong>). Bagian id opsional menunjuk ke
    ++    satu baris dalam tabel. Setiap metode akses data
    ++    {@link android.content.ContentProvider} memiliki sebuah URI konten sebagai argumen; hal ini memungkinkan Anda
    ++    menentukan tabel, baris, atau file yang akan diakses.
    ++</p>
    ++<p>
    ++    Dasar-dasar URI konten dijelaskan dalam topik
    ++    <a href="{@docRoot}guide/topics/providers/content-provider-basics.html">
    ++    Dasar-Dasar Penyedia Konten</a>.
    ++</p>
    ++<h3>Mendesain otoritas</h3>
    ++<p>
    ++    Penyedia biasanya memiliki otoritas tunggal, yang berfungsi sebagai nama internal Android-nya. Untuk
    ++    menghindari konflik dengan penyedia lain, Anda harus menggunakan kepemilikan domain internet (secara terbalik)
    ++    sebagai basis otoritas penyedia Anda. Karena saran ini juga berlaku untuk
    ++    nama-nama paket Android, Anda bisa mendefinisikan otoritas penyedia sebagai perluasan dari nama
    ++    paket yang berisi penyedia. Misalnya, jika nama paket Android Anda adalah
    ++    <code>com.example.&lt;appname&gt;</code>, Anda harus memberikan penyedia Anda
    ++    otoritas <code>com.example.&lt;appname&gt;.provider</code>.
    ++</p>
    ++<h3>Mendesain struktur path</h3>
    ++<p>
    ++    Pengembang biasanya membuat URI konten dari otoritas dengan menambahkan path yang menunjuk ke
    ++    masing-masing tabel. Misalnya, jika Anda memiliki dua tabel <em>table1</em> dan
    ++    <em>table2</em>, Anda mengombinasikan otoritas dari contoh sebelumnya untuk menghasilkan
    ++    URI konten
    ++    <code>com.example.&lt;appname&gt;.provider/table1</code> dan
    ++    <code>com.example.&lt;appname&gt;.provider/table2</code>. Path tidak
    ++    dibatasi pada segmen tunggal, dan tidak harus berupa tabel untuk masing-masing tingkat path.
    ++</p>
    ++<h3>Menangani ID URI konten</h3>
    ++<p>
    ++    Berdasarkan standar, penyedia menawarkan akses ke satu baris dalam tabel dengan menerima URI konten
    ++    dengan sebuah nilai ID untuk baris itu di akhir URI. Juga berdasarkan standar, penyedia mencocokkan
    ++    nilai ID dengan kolom <code>_ID</code> tabel, dan melakukan akses yang diminta terhadap baris
    ++    yang cocok.
    ++</p>
    ++<p>
    ++    Standar ini memudahkan pola desain umum untuk aplikasi yang mengakses penyedia. Aplikasi
    ++    melakukan query terhadap penyedia dan menampilkan {@link android.database.Cursor} yang dihasilkan
    ++    dalam {@link android.widget.ListView} dengan menggunakan {@link android.widget.CursorAdapter}.
    ++    Definisi {@link android.widget.CursorAdapter} mengharuskan salah satu kolom dalam
    ++    {@link android.database.Cursor} berupa <code>_ID</code>
    ++</p>
    ++<p>
    ++    Pengguna kemudian mengambil salah satu baris yang ditampilkan dari UI untuk menemukan atau memodifikasi
    ++    data. Aplikasi mengambil baris yang sesuai dari {@link android.database.Cursor} yang mendukung
    ++    {@link android.widget.ListView}, mengambil nilai <code>_ID</code> untuk baris ini, menambahkannya ke
    ++    URI konten, dan mengirim permintaan akses ke penyedia. Penyedia nanti bisa melakukan
    ++    query atau modifikasi terhadap baris yang persis diambil pengguna.
    ++</p>
    ++<h3>Pola URI konten</h3>
    ++<p>
    ++    Untuk membantu Anda memilih tindakan yang diambil bagi URI konten yang masuk, API penyedia menyertakan
    ++    kelas praktis {@link android.content.UriMatcher}, yang memetakan "pola-pola" URI konten ke
    ++    nilai-nilai integer. Anda bisa menggunakan nilai-nilai integer dalam pernyataan <code>switch</code> yang
    ++    memilih tindakan yang diinginkan untuk URI konten atau URI yang cocok dengan pola tertentu.
    ++</p>
    ++<p>
    ++    Pola URI konten mencocokkan dengan URI konten menggunakan karakter wildcard:
    ++</p>
    ++    <ul>
    ++        <li>
    ++            <strong><code>*</code>:</strong> Mencocokkan string yang memiliki karakter yang sah dengan panjang berapa saja.
    ++        </li>
    ++        <li>
    ++            <strong><code>#</code>:</strong> Mencocokkan string karakter numerik dengan panjang berapa saja.
    ++        </li>
    ++    </ul>
    ++<p>
    ++    Sebagai contoh desain dan pemrograman penanganan URI konten, perhatikan penyedia dengan
    ++    otoritas <code>com.example.app.provider</code> yang mengenali URI konten berikut
    ++    yang menunjuk ke tabel-tabel:
    ++</p>
    ++<ul>
    ++    <li>
    ++        <code>content://com.example.app.provider/table1</code>: Tabel bernama <code>table1</code>.
    ++    </li>
    ++    <li>
    ++        <code>content://com.example.app.provider/table2/dataset1</code>: Tabel bernama
    ++        <code>dataset1</code>.
    ++    </li>
    ++    <li>
    ++        <code>content://com.example.app.provider/table2/dataset2</code>: Tabel bernama
    ++        <code>dataset2</code>.
    ++    </li>
    ++    <li>
    ++        <code>content://com.example.app.provider/table3</code>: Tabel bernama <code>table3</code>.
    ++    </li>
    ++</ul>
    ++<p>
    ++    Penyedia juga mengenali URI konten ini jika baris ID ditambahkan ke URI,
    ++    misalnya <code>content://com.example.app.provider/table3/1</code> untuk baris yang diidentifikasi oleh
    ++    <code>1</code> dalam <code>table3</code>.
    ++</p>
    ++<p>
    ++    Pola-pola URI konten berikut akan menjadi mungkin:
    ++</p>
    ++<dl>
    ++    <dt>
    ++        <code>content://com.example.app.provider/*</code>
    ++    </dt>
    ++    <dd>
    ++        Mencocokkan URI konten di penyedia.
    ++    </dd>
    ++    <dt>
    ++        <code>content://com.example.app.provider/table2/*</code>:
    ++    </dt>
    ++    <dd>
    ++        Mencocokkan URI konten untuk tabel-tabel <code>dataset1</code>
    ++        dan <code>dataset2</code>, namun tidak mencocokkan URI konten untuk <code>table1</code> atau
    ++        <code>table3</code>.
    ++    </dd>
    ++    <dt>
    ++        <code>content://com.example.app.provider/table3/#</code>: Mencocokkan URI konten
    ++        untuk satu baris di <code>table3</code>, misalnya
    ++        <code>content://com.example.app.provider/table3/6</code> untuk baris yang diidentifikasi oleh
    ++        <code>6</code>.
    ++    </dt>
    ++</dl>
    ++<p>
    ++    Cuplikan kode berikut menunjukkan cara kerja metode di {@link android.content.UriMatcher}.
    ++    Kode ini menangani URI seluruh tabel secara berbeda dengan URI untuk
    ++    satu baris, menggunakan pola URI konten
    ++    <code>content://&lt;authority&gt;/&lt;path&gt;</code> untuk tabel, dan
    ++    <code>content://&lt;authority&gt;/&lt;path&gt;/&lt;id&gt;</code> untuk satu baris.
    ++</p>
    ++<p>
    ++    Metode {@link android.content.UriMatcher#addURI(String, String, int) addURI()} memetakan
    ++    otoritas dan path ke nilai integer. Metode {@link android.content.UriMatcher#match(Uri)
    ++    match()} menghasilkan nilai integer URI. Pernyataan <code>switch</code>
    ++    memilih antara melakukan query seluruh tabel dan melakukan query satu record:
    ++</p>
    ++<pre class="prettyprint">
    ++public class ExampleProvider extends ContentProvider {
    ++...
    ++    // Creates a UriMatcher object.
    ++    private static final UriMatcher sUriMatcher;
    ++...
    ++    /*
    ++     * The calls to addURI() go here, for all of the content URI patterns that the provider
    ++     * should recognize. For this snippet, only the calls for table 3 are shown.
    ++     */
    ++...
    ++    /*
    ++     * Sets the integer value for multiple rows in table 3 to 1. Notice that no wildcard is used
    ++     * in the path
    ++     */
    ++    sUriMatcher.addURI("com.example.app.provider", "table3", 1);
    ++
    ++    /*
    ++     * Sets the code for a single row to 2. In this case, the "#" wildcard is
    ++     * used. "content://com.example.app.provider/table3/3" matches, but
    ++     * "content://com.example.app.provider/table3 doesn't.
    ++     */
    ++    sUriMatcher.addURI("com.example.app.provider", "table3/#", 2);
    ++...
    ++    // Implements ContentProvider.query()
    ++    public Cursor query(
    ++        Uri uri,
    ++        String[] projection,
    ++        String selection,
    ++        String[] selectionArgs,
    ++        String sortOrder) {
    ++...
    ++        /*
    ++         * Choose the table to query and a sort order based on the code returned for the incoming
    ++         * URI. Here, too, only the statements for table 3 are shown.
    ++         */
    ++        switch (sUriMatcher.match(uri)) {
    ++
    ++
    ++            // If the incoming URI was for all of table3
    ++            case 1:
    ++
    ++                if (TextUtils.isEmpty(sortOrder)) sortOrder = "_ID ASC";
    ++                break;
    ++
    ++            // If the incoming URI was for a single row
    ++            case 2:
    ++
    ++                /*
    ++                 * Because this URI was for a single row, the _ID value part is
    ++                 * present. Get the last path segment from the URI; this is the _ID value.
    ++                 * Then, append the value to the WHERE clause for the query
    ++                 */
    ++                selection = selection + "_ID = " uri.getLastPathSegment();
    ++                break;
    ++
    ++            default:
    ++            ...
    ++                // If the URI is not recognized, you should do some error handling here.
    ++        }
    ++        // call the code to actually do the query
    ++    }
    ++</pre>
    ++<p>
    ++    Kelas lainnya, {@link android.content.ContentUris}, menyediakan metode praktis untuk menggunakan
    ++    bagian <code>id</code> URI konten. Kelas-kelas {@link android.net.Uri} dan
    ++    {@link android.net.Uri.Builder} menyertakan metode praktis untuk mengurai
    ++    objek {@link android.net.Uri} yang ada dan membuat objek baru.
    ++</p>
    ++
    ++<!-- Implementing the ContentProvider class -->
    ++<h2 id="ContentProvider">Mengimplementasikan Kelas ContentProvider</h2>
    ++<p>
    ++    Instance {@link android.content.ContentProvider} mengelola akses
    ++    ke satu set data terstruktur dengan menangani permintaan dari aplikasi lain. Semua bentuk
    ++    akses pada akhirnya akan memanggil {@link android.content.ContentResolver}, yang kemudian memanggil
    ++    metode konkret {@link android.content.ContentProvider} untuk mendapatkan akses.
    ++</p>
    ++<h3 id="RequiredAccess">Metode-metode yang diperlukan</h3>
    ++<p>
    ++    Kelas abstrak {@link android.content.ContentProvider} mendefinisikan enam metode abstrak yang
    ++    harus Anda implementasikan sebagai bagian dari subkelas konkret Anda sendiri. Semua metode ini kecuali
    ++    {@link android.content.ContentProvider#onCreate() onCreate()} dipanggil oleh aplikasi klien
    ++    yang berupaya mengakses penyedia konten Anda:
    ++</p>
    ++<dl>
    ++    <dt>
    ++        {@link android.content.ContentProvider#query(Uri, String[], String, String[], String)
    ++        query()}
    ++    </dt>
    ++    <dd>
    ++        Mengambil data dari penyedia Anda. Menggunakan argumen untuk memilih tabel yang akan
    ++        di-query, baris dan kolom yang akan dihasilkan, dan urutan sortir hasilnya.
    ++        Menghasilkan data berupa objek {@link android.database.Cursor}.
    ++    </dd>
    ++    <dt>
    ++        {@link android.content.ContentProvider#insert(Uri, ContentValues) insert()}
    ++    </dt>
    ++    <dd>
    ++        Menyisipkan baris baru ke dalam penyedia Anda. Menggunakan argumen untuk memilih
    ++        tabel tujuan dan mendapatkan nilai-nilai kolom yang akan digunakan. Menghasilkan URI konten untuk
    ++        baris yang baru disisipkan.
    ++    </dd>
    ++    <dt>
    ++        {@link android.content.ContentProvider#update(Uri, ContentValues, String, String[])
    ++        update()}
    ++    </dt>
    ++    <dd>
    ++        Memperbarui baris yang ada di penyedia Anda. Menggunakan argumen untuk memilih tabel dan baris
    ++        yang akan diperbarui dan mendapatkan nilai-nilai kolom yang diperbarui. Menghasilkan jumlah baris yang diperbarui.
    ++    </dd>
    ++    <dt>
    ++        {@link android.content.ContentProvider#delete(Uri, String, String[]) delete()}
    ++    </dt>
    ++    <dd>
    ++        Menghapus baris dari penyedia Anda. Menggunakan argumen untuk memilih tabel dan baris yang akan
    ++        dihapus. Menghasilkan jumlah baris yang dihapus.
    ++    </dd>
    ++    <dt>
    ++        {@link android.content.ContentProvider#getType(Uri) getType()}
    ++    </dt>
    ++    <dd>
    ++        Menghasilkan tipe MIME yang sesuai dengan URI konten. Metode ini dijelaskan lebih detail
    ++        di bagian <a href="#MIMETypes">Mengimplementasikan Tipe MIME Penyedia Konten</a>.
    ++    </dd>
    ++    <dt>
    ++        {@link android.content.ContentProvider#onCreate() onCreate()}
    ++    </dt>
    ++    <dd>
    ++        Inisialisasi penyedia Anda. Sistem Android memanggil metode ini segera setelah
    ++        membuat penyedia Anda. Perhatikan bahwa penyedia Anda tidak dibuat hingga
    ++        objek {@link android.content.ContentResolver} mencoba mengaksesnya.
    ++    </dd>
    ++</dl>
    ++<p>
    ++    Perhatikan bahwa metode-metode ini memiliki signature yang sama dengan
    ++    metode-metode {@link android.content.ContentResolver} yang sama namanya.
    ++</p>
    ++<p>
    ++    Implementasi metode-metode ini harus memperhitungkan hal-hal berikut:
    ++</p>
    ++<ul>
    ++    <li>
    ++        Semua metode ini kecuali {@link android.content.ContentProvider#onCreate() onCreate()}
    ++        bisa dipanggil oleh beberapa thread sekaligus, jadi harus thread-safe (aman untuk thread). Untuk mengetahui
    ++        selengkapnya tentang multi-thread, lihat topik
    ++        <a href="{@docRoot}guide/components/processes-and-threads.html">
    ++        Proses dan Thread</a>.
    ++    </li>
    ++    <li>
    ++        Hindari melakukan operasi yang lama dalam {@link android.content.ContentProvider#onCreate()
    ++        onCreate()}. Tunda inisialisasi tugas hingga benar-benar diperlukan.
    ++        Bagian <a href="#OnCreate">Mengimplementasikan metode onCreate()</a>
    ++        membahas hal ini secara lebih detail.
    ++    </li>
    ++    <li>
    ++        Walaupun harus mengimplementasikan metode-metode ini, kode Anda tidak harus melakukan apa pun selain
    ++        tipe data yang diharapkan. Misalnya, Anda mungkin ingin mencegah aplikasi lain
    ++        menyisipkan data ke dalam beberapa tabel. Caranya, Anda bisa mengabaikan panggilan ke
    ++        {@link android.content.ContentProvider#insert(Uri, ContentValues) insert()} dan menghasilkan
    ++        0.
    ++    </li>
    ++</ul>
    ++<h3 id="Query">Mengimplementasikan metode query()</h3>
    ++<p>
    ++    Metode
    ++    {@link android.content.ContentProvider#query(Uri, String[], String, String[], String)
    ++    ContentProvider.query()} harus menghasilkan objek {@link android.database.Cursor}, atau jika
    ++    gagal, melontarkan {@link java.lang.Exception}. Jika menggunakan database SQLite sebagai
    ++    penyimpanan data, Anda bisa mengembalikan{@link android.database.Cursor} yang dikembalikan oleh salah satu metode
    ++    <code>query()</code> dari kelas {@link android.database.sqlite.SQLiteDatabase}.
    ++    Jika query tidak mencocokkan baris apa pun, Anda harus mengembalikan instance {@link android.database.Cursor}
    ++    yang metode {@link android.database.Cursor#getCount()}-nya mengembalikan 0.
    ++    Anda harus mengembalikan <code>null</code> hanya jika terjadi kesalahan internal selama proses query.
    ++</p>
    ++<p>
    ++    Jika Anda tidak menggunakan database SQLite sebagai penyimpanan data, gunakan salah satu subkelas konkret
    ++    {@link android.database.Cursor}. Misalnya, kelas {@link android.database.MatrixCursor}
    ++    mengimplementasikan kursor dengan masing-masing baris berupa larik {@link java.lang.Object}. Dengan kelas ini,
    ++    gunakan {@link android.database.MatrixCursor#addRow(Object[]) addRow()} untuk menambahkan baris baru.
    ++</p>
    ++<p>
    ++    Ingatlah bahwa sistem Android harus mampu mengomunikasikan {@link java.lang.Exception}
    ++    lintas batas proses. Android bisa melakukannya untuk eksepsi berikut yang mungkin berguna
    ++    dalam menangani kesalahan query:
    ++</p>
    ++<ul>
    ++    <li>
    ++        {@link java.lang.IllegalArgumentException} (Anda bisa saja melontarkannya jika penyedia Anda
    ++        menerima URI konten yang tidak sah)
    ++    </li>
    ++    <li>
    ++        {@link java.lang.NullPointerException}
    ++    </li>
    ++</ul>
    ++<h3 id="Insert">Mengimplementasikan metode insert()</h3>
    ++<p>
    ++    Metode {@link android.content.ContentProvider#insert(Uri, ContentValues) insert()} menambahkan satu
    ++    baris baru ke tabel yang sesuai, dengan menggunakan nilai-nilai dalam argumen {@link android.content.ContentValues}.
    ++ Jika kolom nama tidak ada dalam argumen {@link android.content.ContentValues}, Anda
    ++    mungkin perlu menyediakan nilai default untuknya, baik dalam kode penyedia atau dalam skema database
    ++    Anda.
    ++</p>
    ++<p>
    ++    Metode ini harus mengembalikan URI konten untuk baris baru. Untuk membuatnya, tambahkan nilai
    ++    <code>_ID</code> baris baru (atau kunci utama lainnya) ke tabel URI konten, dengan menggunakan
    ++    {@link android.content.ContentUris#withAppendedId(Uri, long) withAppendedId()}.
    ++</p>
    ++<h3 id="Delete">Mengimplementasikan metode delete()</h3>
    ++<p>
    ++    Metode {@link android.content.ContentProvider#delete(Uri, String, String[]) delete()}
    ++    tidak harus menghapus baris-baris dari penyimpanan data Anda secara fisik. Jika menggunakan adaptor sinkronisasi
    ++    bersama penyedia, Anda harus mempertimbangkan penandaan baris yang dihapus
    ++    dengan flag "delete"; bukan menghilangkan baris itu sepenuhnya. Adaptor sinkronisasi bisa
    ++    memeriksa baris yang dihapus dan menghilangkannya dari server sebelum menghapusnya dari penyedia.
    ++</p>
    ++<h3 id="Update">Mengimplementasikan metode update()</h3>
    ++<p>
    ++    Metode {@link android.content.ContentProvider#update(Uri, ContentValues, String, String[])
    ++    update()} mengambil argumen {@link android.content.ContentValues} yang sama dengan yang digunakan oleh
    ++    {@link android.content.ContentProvider#insert(Uri, ContentValues) insert()}, dan
    ++    argumen-argumen <code>selection</code> dan <code>selectionArgs</code> yang sama dengan yang digunakan oleh
    ++    {@link android.content.ContentProvider#delete(Uri, String, String[]) delete()} dan
    ++    {@link android.content.ContentProvider#query(Uri, String[], String, String[], String)
    ++    ContentProvider.query()}. Hal ini bisa memungkinkan Anda menggunakan kembali kode di antara metode-metode ini.
    ++</p>
    ++<h3 id="OnCreate">Mengimplementasikan metode onCreate()</h3>
    ++<p>
    ++    Sistem Android memanggil {@link android.content.ContentProvider#onCreate()
    ++    onCreate()} saat memulai penyedia. Anda harus melakukan tugas-tugas inisialisasi yang berjalan cepat saja
    ++    dalam metode ini, serta menunda pembuatan database dan pemuatan data hingga penyedia benar-benar
    ++    menerima permintaan terhadap data. Jika Anda melakukan tugas yang memakan waktu dalam
    ++    {@link android.content.ContentProvider#onCreate() onCreate()}, Anda akan memperlambat
    ++    startup penyedia. Pada gilirannya, hal ini akan memperlambat respons dari penyedia terhadap
    ++    aplikasi lain.
    ++</p>
    ++<p>
    ++    Misalnya, jika menggunakan database SQLite, Anda bisa membuat
    ++    sebuah objek {@link android.database.sqlite.SQLiteOpenHelper} baru di
    ++    {@link android.content.ContentProvider#onCreate() ContentProvider.onCreate()},
    ++    kemudian membuat tabel-tabel SQL saat pertama kali membuka database itu. Untuk memperlancar hal ini,
    ++    saat pertama Anda memanggil {@link android.database.sqlite.SQLiteOpenHelper#getWritableDatabase
    ++    getWritableDatabase()}, metode ini memanggil metode
    ++    {@link android.database.sqlite.SQLiteOpenHelper#onCreate(SQLiteDatabase)
    ++    SQLiteOpenHelper.onCreate()} secara otomatis.
    ++</p>
    ++<p>
    ++    Dua cuplikan berikut memperagakan interaksi antara
    ++    {@link android.content.ContentProvider#onCreate() ContentProvider.onCreate()} dan
    ++    {@link android.database.sqlite.SQLiteOpenHelper#onCreate(SQLiteDatabase)
    ++    SQLiteOpenHelper.onCreate()}. Cuplikan pertama adalah implementasi
    ++    {@link android.content.ContentProvider#onCreate() ContentProvider.onCreate()}:
    ++</p>
    ++<pre class="prettyprint">
    ++public class ExampleProvider extends ContentProvider
    ++
    ++    /*
    ++     * Defines a handle to the database helper object. The MainDatabaseHelper class is defined
    ++     * in a following snippet.
    ++     */
    ++    private MainDatabaseHelper mOpenHelper;
    ++
    ++    // Defines the database name
    ++    private static final String DBNAME = "mydb";
    ++
    ++    // Holds the database object
    ++    private SQLiteDatabase db;
    ++
    ++    public boolean onCreate() {
    ++
    ++        /*
    ++         * Creates a new helper object. This method always returns quickly.
    ++         * Notice that the database itself isn't created or opened
    ++         * until SQLiteOpenHelper.getWritableDatabase is called
    ++         */
    ++        mOpenHelper = new MainDatabaseHelper(
    ++            getContext(),        // the application context
    ++            DBNAME,              // the name of the database)
    ++            null,                // uses the default SQLite cursor
    ++            1                    // the version number
    ++        );
    ++
    ++        return true;
    ++    }
    ++
    ++    ...
    ++
    ++    // Implements the provider's insert method
    ++    public Cursor insert(Uri uri, ContentValues values) {
    ++        // Insert code here to determine which table to open, handle error-checking, and so forth
    ++
    ++        ...
    ++
    ++        /*
    ++         * Gets a writeable database. This will trigger its creation if it doesn't already exist.
    ++         *
    ++         */
    ++        db = mOpenHelper.getWritableDatabase();
    ++    }
    ++}
    ++</pre>
    ++<p>
    ++    Cuplikan berikutnya adalah implementasi
    ++    {@link android.database.sqlite.SQLiteOpenHelper#onCreate(SQLiteDatabase)
    ++    SQLiteOpenHelper.onCreate()}, yang menyertakan kelas helper:
    ++</p>
    ++<pre class="prettyprint">
    ++...
    ++// A string that defines the SQL statement for creating a table
    ++private static final String SQL_CREATE_MAIN = "CREATE TABLE " +
    ++    "main " +                       // Table's name
    ++    "(" +                           // The columns in the table
    ++    " _ID INTEGER PRIMARY KEY, " +
    ++    " WORD TEXT"
    ++    " FREQUENCY INTEGER " +
    ++    " LOCALE TEXT )";
    ++...
    ++/**
    ++ * Helper class that actually creates and manages the provider's underlying data repository.
    ++ */
    ++protected static final class MainDatabaseHelper extends SQLiteOpenHelper {
    ++
    ++    /*
    ++     * Instantiates an open helper for the provider's SQLite data repository
    ++     * Do not do database creation and upgrade here.
    ++     */
    ++    MainDatabaseHelper(Context context) {
    ++        super(context, DBNAME, null, 1);
    ++    }
    ++
    ++    /*
    ++     * Creates the data repository. This is called when the provider attempts to open the
    ++     * repository and SQLite reports that it doesn't exist.
    ++     */
    ++    public void onCreate(SQLiteDatabase db) {
    ++
    ++        // Creates the main table
    ++        db.execSQL(SQL_CREATE_MAIN);
    ++    }
    ++}
    ++</pre>
    ++
    ++
    ++<!-- Implementing ContentProvider MIME Types -->
    ++<h2 id="MIMETypes">Mengimplementasikan Tipe MIME Penyedia Konten</h2>
    ++<p>
    ++    Kelas {@link android.content.ContentProvider} memiliki dua metode untuk menghasilkan tipe-tipe MIME:
    ++</p>
    ++<dl>
    ++    <dt>
    ++        {@link android.content.ContentProvider#getType(Uri) getType()}
    ++    </dt>
    ++    <dd>
    ++        Salah satu metode wajib yang harus Anda implementasikan untuk setiap penyedia.
    ++    </dd>
    ++    <dt>
    ++        {@link android.content.ContentProvider#getStreamTypes(Uri, String) getStreamTypes()}
    ++    </dt>
    ++    <dd>
    ++        Sebuah metode yang diharapkan untuk Anda implementasikan jika penyedia Anda menawarkan file.
    ++    </dd>
    ++</dl>
    ++<h3 id="TableMIMETypes">Tipe MIME untuk tabel</h3>
    ++<p>
    ++    Metode {@link android.content.ContentProvider#getType(Uri) getType()} mengembalikan
    ++    {@link java.lang.String} dengan format MIME yang menjelaskan tipe data yang dikembalikan oleh
    ++    argumen URI konten. Argumen {@link android.net.Uri} bisa berupa pola, bukannya URI tertentu;
    ++    dalam hal ini, Anda harus mengembalikan tipe data terkait URI konten yang cocok dengan
    ++    polanya.
    ++</p>
    ++<p>
    ++    Untuk tipe data umum misalnya teks, HTML, atau JPEG,
    ++    {@link android.content.ContentProvider#getType(Uri) getType()} harus mengembalikan
    ++    tipe MIME standar untuk data itu. Daftar lengkap tipe standar ini tersedia di situs web
    ++    <a href="http://www.iana.org/assignments/media-types/index.htm">IANA MIME Media Types</a>.
    ++
    ++</p>
    ++<p>
    ++    Untuk URI konten yang menunjuk ke baris atau baris-baris data tabel,
    ++    {@link android.content.ContentProvider#getType(Uri) getType()} harus mengembalikan
    ++    tipe MIME dalam format MIME khusus vendor Android:
    ++</p>
    ++<ul>
    ++    <li>
    ++        Bagian tipe: <code>vnd</code>
    ++    </li>
    ++    <li>
    ++        Bagian subtipe:
    ++        <ul>
    ++            <li>
    ++    Jika pola URI adalah untuk satu baris: <code>android.cursor.<strong>item</strong>/</code>
    ++            </li>
    ++            <li>
    ++    Jika pola URI adalah untuk lebih dari satu baris: <code>android.cursor.<strong>dir</strong>/</code>
    ++            </li>
    ++        </ul>
    ++    </li>
    ++    <li>
    ++        Bagian khusus penyedia: <code>vnd.&lt;name&gt;</code>.<code>&lt;type&gt;</code>
    ++        <p>
    ++            Anda menyediakan <code>&lt;name&gt;</code> dan <code>&lt;type&gt;</code>.
    ++            Nilai <code>&lt;name&gt;</code> harus unik secara global,
    ++            dan nilai <code>&lt;type&gt;</code> harus unik bagi pola URI
    ++            yang sesuai. Pilihan tepat untuk <code>&lt;name&gt;</code> adalah nama perusahaan Anda atau
    ++            sebagian dari nama paket Android aplikasi Anda. Pilihan tepat untuk
    ++            <code>&lt;type&gt;</code> adalah string yang mengidentifikasi tabel yang terkait dengan
    ++            URI.
    ++        </p>
    ++
    ++    </li>
    ++</ul>
    ++<p>
    ++    Misalnya, jika otoritas penyedia adalah
    ++    <code>com.example.app.provider</code>, dan penyedia mengekspos tabel bernama
    ++    <code>table1</code>, tipe MIME untuk beberapa baris dalam <code>table1</code> adalah:
    ++</p>
    ++<pre>
    ++vnd.android.cursor.<strong>dir</strong>/vnd.com.example.provider.table1
    ++</pre>
    ++<p>
    ++    Untuk satu baris <code>table1</code>, tipe MIME adalah:
    ++</p>
    ++<pre>
    ++vnd.android.cursor.<strong>item</strong>/vnd.com.example.provider.table1
    ++</pre>
    ++<h3 id="FileMIMETypes">Tipe MIME untuk file</h3>
    ++<p>
    ++    Jika penyedia Anda menawarkan file, implementasikan
    ++    {@link android.content.ContentProvider#getStreamTypes(Uri, String) getStreamTypes()}.
    ++    Metode ini menghasilkan larik {@link java.lang.String} tipe MIME untuk file
    ++    yang bisa dikembalikan penyedia Anda untuk URI konten bersangkutan. Anda harus memfilter tipe MIME yang Anda tawarkan dengan argumen filter
    ++    tipe MIME, sehingga Anda hanya mengembalikan tipe MIME yang ingin ditangani klien.
    ++</p>
    ++<p>
    ++    Misalnya, perhatikan penyedia yang menawarkan gambar foto sebagai file dalam format <code>.jpg</code>,
    ++    <code>.png</code>, dan <code>.gif</code>.
    ++    Jika aplikasi memanggil {@link android.content.ContentResolver#getStreamTypes(Uri, String)
    ++    ContentResolver.getStreamTypes()} dengan string filter <code>image/*</code> (sesuatu yang
    ++    merupakan "gambar"),
    ++    maka metode {@link android.content.ContentProvider#getStreamTypes(Uri, String)
    ++    ContentProvider.getStreamTypes()} harus mengembalikan larik:
    ++</p>
    ++<pre>
    ++{ &quot;image/jpeg&quot;, &quot;image/png&quot;, &quot;image/gif&quot;}
    ++</pre>
    ++<p>
    ++    Jika aplikasi tertarik pada file <code>.jpg</code>, maka aplikasi bisa memanggil
    ++    {@link android.content.ContentResolver#getStreamTypes(Uri, String)
    ++    ContentResolver.getStreamTypes()} dengan string filter <code>*\/jpeg</code>, dan
    ++    {@link android.content.ContentProvider#getStreamTypes(Uri, String)
    ++    ContentProvider.getStreamTypes()} harus mengembalikan:
    ++<pre>
    ++{&quot;image/jpeg&quot;}
    ++</pre>
    ++<p>
    ++    Jika penyedia Anda tidak menawarkan tipe MIME apa pun yang diminta dalam string filter,
    ++    {@link android.content.ContentProvider#getStreamTypes(Uri, String) getStreamTypes()}
    ++    harus mengembalikan <code>null</code>.
    ++</p>
    ++
    ++
    ++<!--  Implementing a Contract Class -->
    ++<h2 id="ContractClass">Mengimplementasikan Kelas Kontrak</h2>
    ++<p>
    ++    Kelas kontrak adalah kelas <code>public final</code> yang berisi definisi konstanta untuk URI, nama kolom, tipe MIME, dan
    ++metadata lain yang melekat ke penyedia. Kelas
    ++    membentuk sebuah kontrak antara penyedia dan aplikasi lain dengan memastikan bahwa penyedia
    ++    bisa diakses dengan benar sekalipun ada perubahan pada nilai URI sesungguhnya, nama kolom,
    ++    dan seterusnya.
    ++</p>
    ++<p>
    ++    Kelas kontrak juga membantu pengembang karena kelas ini biasanya memiliki nama-nama simbolik untuk konstantanya,
    ++    sehingga memperkecil kemungkinan pengembang menggunakan nilai yang salah untuk nama kolom atau URI. Karena berupa
    ++    kelas, kelas ini bisa berisi dokumentasi Javadoc. Lingkungan pengembangan terpadu (IDE) seperti
    ++    Eclipse secara otomatis bisa melengkapi nama-nama konstanta dari kelas kontrak dan menampilkan Javadoc untuk
    ++    konstanta.
    ++</p>
    ++<p>
    ++    Pengembang tidak bisa mengakses file kelas milik kelas kontrak dari aplikasi Anda, namun bisa
    ++    mengompilasinya secara statis ke dalam aplikasi mereka dari file <code>.jar</code> yang Anda sediakan.
    ++</p>
    ++<p>
    ++    Kelas {@link android.provider.ContactsContract} dan kelas-kelas tersarangnya adalah contoh
    ++    kelas kontrak.
    ++</p>
    ++<h2 id="Permissions">Mengimplementasikan Izin Penyedia Konten</h2>
    ++<p>
    ++    Izin dan akses untuk semua aspek sistem Android dijelaskan secara detail dalam
    ++    topik <a href="{@docRoot}guide/topics/security/security.html">Keamanan dan Izin</a>.
    ++    Topik <a href="{@docRoot}guide/topics/data/data-storage.html">Penyimpanan Data</a> juga
    ++    menjelaskan keamanan dan izin terkait dengan berbagai tipe penyimpanan.
    ++    Singkatnya, poin-poin pentingnya adalah:
    ++</p>
    ++<ul>
    ++    <li>
    ++        Secara default, file data yang disimpan pada penyimpanan internal perangkat bersifat privat bagi
    ++        aplikasi dan penyedia Anda.
    ++    </li>
    ++    <li>
    ++        Database {@link android.database.sqlite.SQLiteDatabase} yang Anda buat bersifat privat bagi
    ++        aplikasi dan penyedia Anda.
    ++    </li>
    ++    <li>
    ++        Secara default, file data yang Anda simpan ke penyimpanan eksternal bersifat <em>publik</em> dan
    ++        <em>bisa dibaca secara global</em>. Anda tidak bisa menggunakan penyedia konten untuk membatasi akses ke file dalam
    ++        penyimpanan eksternal, karena aplikasi lain bisa menggunakan panggilan API untuk membaca dan menulis ke file tersebut.
    ++    </li>
    ++    <li>
    ++        Panggilan metode untuk membuka atau membuat file atau database SQLite pada
    ++        penyimpanan internal perangkat Anda berpotensi memberikan akses baca maupun tulis ke semua aplikasi lain. Jika Anda
    ++        menggunakan file atau database internal sebagai repository penyedia, dan Anda memberinya
    ++        akses "world-readable" (bisa dibaca secara global) atau "world-writeable" (bisa ditulis secara global), izin yang Anda atur untuk penyedia dalam
    ++        manifesnya tidak akan melindungi data Anda. Akses default untuk file dan database dalam
    ++        penyimpanan internal adalah "privat", dan untuk repository penyedia, tidak boleh Anda ubah.
    ++    </li>
    ++</ul>
    ++<p>
    ++    Jika Anda ingin menggunakan izin penyedia konten untuk mengontrol akses ke data Anda, maka Anda harus
    ++    menyimpan data Anda dalam file internal, database SQLite, atau "cloud" (misalnya,
    ++    di server jauh), dan Anda harus membuat file dan database tetap privat bagi aplikasi Anda.
    ++</p>
    ++<h3>Mengimplementasikan izin</h3>
    ++<p>
    ++    Semua aplikasi bisa membaca dari atau menulis ke penyedia Anda, sekalipun data yang mendasari adalah
    ++    privat, karena secara default penyedia Anda tidak mengatur izin. Untuk mengubahnya,
    ++    atur izin untuk penyedia dalam file manifes, dengan menggunakan atribut atau elemen anak
    ++    dari elemen <code><a href="{@docRoot}guide/topics/manifest/provider-element.html">
    ++    &lt;provider&gt;</a></code>. Anda bisa mengatur izin yang berlaku pada seluruh penyedia,
    ++    atau pada tabel tertentu, atau bahkan pada record tertentu, atau ketiganya.
    ++</p>
    ++<p>
    ++    Anda mendefinisikan izin untuk penyedia dengan satu atau beberapa elemen
    ++    <code><a href="{@docRoot}guide/topics/manifest/permission-element.html">
    ++    &lt;permission&gt;</a></code> dalam file manifes. Untuk membuat
    ++    izin unik bagi penyedia, gunakan scoping (pengaturan lingkup) bergaya Java untuk
    ++    atribut <code><a href="{@docRoot}guide/topics/manifest/permission-element.html#nm">
    ++    android:name</a></code>. Misalnya, beri nama izin membaca dengan
    ++    <code>com.example.app.provider.permission.READ_PROVIDER</code>.
    ++
    ++</p>
    ++<p>
    ++    Daftar berikut menjelaskan lingkup penyedia izin, mulai dengan
    ++    izin yang berlaku pada seluruh penyedia kemudian menjadi semakin sempit.
    ++    Izin yang lebih sempit akan didahulukan daripada izin yang berlingkup lebih luas:
    ++</p>
    ++<dl>
    ++    <dt>
    ++        Izin baca-tulis tunggal tingkat penyedia
    ++    </dt>
    ++    <dd>
    ++        Suatu izin yang mengontrol akses baca-tulis bagi seluruh penyedia, ditetapkan
    ++        dengan atribut <code><a href="{@docRoot}guide/topics/manifest/provider-element.html#prmsn">
    ++        android:permission</a></code> dari
    ++        elemen <code><a href="{@docRoot}guide/topics/manifest/provider-element.html">
    ++        &lt;provider&gt;</a></code>.
    ++    </dd>
    ++    <dt>
    ++        Izin baca-tulis terpisah tingkat penyedia
    ++    </dt>
    ++    <dd>
    ++        Satu izin baca dan satu izin tulis untuk seluruh penyedia. Anda menetapkan keduanya
    ++        dengan atribut <code><a href="{@docRoot}guide/topics/manifest/provider-element.html#rprmsn">
    ++        android:readPermission</a></code> dan
    ++        <code><a href="{@docRoot}guide/topics/manifest/provider-element.html#wprmsn">
    ++        android:writePermission</a></code> dari elemen
    ++        <code><a href="{@docRoot}guide/topics/manifest/provider-element.html">
    ++        &lt;provider&gt;</a></code>. Kedua izin akan didahulukan daripada izin yang diharuskan oleh
    ++        <code><a href="{@docRoot}guide/topics/manifest/provider-element.html#prmsn">
    ++        android:permission</a></code>.
    ++    </dd>
    ++    <dt>
    ++        Izin tingkat path
    ++    </dt>
    ++    <dd>
    ++        Izin baca, tulis, atau baca/tulis untuk URI konten dalam penyedia Anda. Anda menetapkan
    ++        tiap URI yang ingin dikontrol dengan elemen anak
    ++        <code><a href="{@docRoot}guide/topics/manifest/path-permission-element.html">
    ++        &lt;path-permission&gt;</a></code> dari
    ++        elemen <code><a href="{@docRoot}guide/topics/manifest/provider-element.html">
    ++        &lt;provider&gt;</a></code>. Untuk setiap URI konten yang ditetapkan, Anda bisa menetapkan
    ++        satu izin baca/tulis, satu izin baca, atau satu izin tulis, atau ketiganya. Izin baca dan
    ++        tulis akan didahulukan daripada izin baca/tulis. Juga,
    ++        izin tingkat path akan didahulukan daripada izin tingkat penyedia.
    ++    </dd>
    ++    <dt>
    ++        Izin sementara
    ++    </dt>
    ++    <dd>
    ++        Tingkat izin yang memberikan akses sementara ke aplikasi, sekalipun aplikasi itu
    ++        tidak memiliki izin yang biasanya diminta. Fitur akses
    ++         sementara mengurangi jumlah izin yang harus diminta aplikasi dalam
    ++        manifesnya. Bila Anda mengaktifkan izin sementara, satu-satunya aplikasi yang memerlukan
    ++        izin "permanen" untuk penyedia adalah aplikasi yang mengakses terus-menerus semua
    ++        data Anda.
    ++        <p>
    ++            Perhatikan izin yang Anda perlukan untuk mengimplementasikan penyedia dan aplikasi email, bila Anda
    ++            ingin memperbolehkan aplikasi penampil gambar dari luar menampilkan lampiran foto dari
    ++            penyedia Anda. Untuk memberikan akses yang diperlukan kepada penampil gambar tanpa mengharuskan izin,
    ++            siapkan izin sementara untuk URI konten bagi foto. Desainlah aplikasi email Anda agar
    ++            bila pengguna ingin menampilkan foto, aplikasi itu akan mengirim intent berisi
    ++            URI konten foto dan flag izin ke penampil gambar. Penampil gambar nanti bisa
    ++            melakukan query penyedia email untuk mengambil foto, sekalipun penampil itu tidak
    ++            memiliki izin baca normal untuk penyedia Anda.
    ++        </p>
    ++        <p>
    ++            Untuk mengaktifkan izin sementara, atur atribut
    ++            <code><a href="{@docRoot}guide/topics/manifest/provider-element.html#gprmsn">
    ++            android:grantUriPermissions</a></code> dari
    ++            elemen <code><a href="{@docRoot}guide/topics/manifest/provider-element.html">
    ++            &lt;provider&gt;</a></code>, atau tambahkan satu atau beberapa elemen anak
    ++            <code><a href="{@docRoot}guide/topics/manifest/grant-uri-permission-element.html">
    ++            &lt;grant-uri-permission&gt;</a></code> ke
    ++            elemen <code><a href="{@docRoot}guide/topics/manifest/provider-element.html">
    ++            &lt;provider&gt;</a></code> Anda. Jika menggunakan izin sementara, Anda harus memanggil
    ++            {@link android.content.Context#revokeUriPermission(Uri, int)
    ++            Context.revokeUriPermission()} kapan saja Anda menghilangkan dukungan untuk URI konten dari
    ++            penyedia, dan URI konten dikaitkan dengan izin sementara.
    ++        </p>
    ++        <p>
    ++            Nilai atribut menentukan seberapa banyak penyedia Anda yang dijadikan bisa diakses.
    ++            Jika atribut diatur ke <code>true</code>, maka sistem akan memberikan
    ++            izin sementara kepada seluruh penyedia, dengan mengesampingkan izin lain yang diharuskan
    ++            oleh izin tingkat penyedia atau tingkat path.
    ++        </p>
    ++        <p>
    ++            Jika flag ini diatur ke <code>false</code>, maka Anda harus menambahkan elemen-elemen anak
    ++            <code><a href="{@docRoot}guide/topics/manifest/grant-uri-permission-element.html">
    ++            &lt;grant-uri-permission&gt;</a></code> ke
    ++            elemen <code><a href="{@docRoot}guide/topics/manifest/provider-element.html">
    ++            &lt;provider&gt;</a></code> Anda. Tiap elemen anak menetapkan URI konten atau
    ++            URI yang telah diberi akses sementara.
    ++        </p>
    ++        <p>
    ++            Untuk mendelegasikan akses sementara ke sebuah aplikasi, intent harus berisi
    ++            {@link android.content.Intent#FLAG_GRANT_READ_URI_PERMISSION} atau flag
    ++            {@link android.content.Intent#FLAG_GRANT_WRITE_URI_PERMISSION}, atau keduanya. Keduanya
    ++            diatur dengan metode {@link android.content.Intent#setFlags(int) setFlags()}.
    ++        </p>
    ++        <p>
    ++            Jika atribut <code><a href="{@docRoot}guide/topics/manifest/provider-element.html#gprmsn">
    ++            android:grantUriPermissions</a></code> tidak ada, atribut ini diasumsikan sebagai
    ++            <code>false</code>.
    ++        </p>
    ++    </dd>
    ++</dl>
    ++
    ++
    ++
    ++<!-- The Provider Element -->
    ++<h2 id="ProviderElement">Elemen &lt;provider&gt;</h2>
    ++<p>
    ++    Seperti halnya komponen {@link android.app.Activity} dan {@link android.app.Service},
    ++    subkelas {@link android.content.ContentProvider}
    ++    harus didefinisikan dalam file manifes untuk aplikasinya, dengan menggunakan elemen
    ++    <code><a href="{@docRoot}guide/topics/manifest/provider-element.html">
    ++    &lt;provider&gt;</a></code>. Sistem Android mendapatkan informasi berikut dari
    ++    elemen:
    ++<dl>
    ++    <dt>
    ++        Otoritas
    ++        (<a href="{@docRoot}guide/topics/manifest/provider-element.html#auth">{@code
    ++        android:authorities}</a>)
    ++    </dt>
    ++    <dd>
    ++        Nama-nama simbolik yang mengidentifikasi seluruh penyedia dalam sistem. Atribut
    ++        ini dijelaskan lebih detail di bagian
    ++        <a href="#ContentURI">Mendesain URI Konten</a>.
    ++    </dd>
    ++    <dt>
    ++        Nama kelas penyedia
    ++        (<code>
    ++<a href="{@docRoot}guide/topics/manifest/provider-element.html#nm">android:name</a>
    ++        </code>)
    ++    </dt>
    ++    <dd>
    ++        Kelas yang mengimplementasikan {@link android.content.ContentProvider}. Kelas ini
    ++        dijelaskan lebih detail di bagian
    ++        <a href="#ContentProvider">Mengimplementasikan Kelas ContentProvider</a>.
    ++    </dd>
    ++    <dt>
    ++        Izin
    ++    </dt>
    ++    <dd>
    ++        Atribut-atribut yang menetapkan izin yang harus dimiliki aplikasi lain untuk mengakses
    ++        data penyedia:
    ++        <ul>
    ++            <li>
    ++                <code><a href="{@docRoot}guide/topics/manifest/provider-element.html#gprmsn">
    ++                android:grantUriPermssions</a></code>: Flag izin sementara.
    ++            </li>
    ++            <li>
    ++                <code><a href="{@docRoot}guide/topics/manifest/provider-element.html#prmsn">
    ++                android:permission</a></code>: Izin baca/tulis tunggal untuk tingkat penyedia.
    ++            </li>
    ++            <li>
    ++                <code><a href="{@docRoot}guide/topics/manifest/provider-element.html#rprmsn">
    ++                android:readPermission</a></code>: Izin baca untuk tingkat penyedia.
    ++            </li>
    ++            <li>
    ++                <code><a href="{@docRoot}guide/topics/manifest/provider-element.html#wprmsn">
    ++                android:writePermission</a></code>: Izin tulis untuk tingkat penyedia.
    ++            </li>
    ++        </ul>
    ++        <p>
    ++            Izin dan atribut-atribut yang sesuai dijelaskan lebih detail
    ++            di bagian
    ++            <a href="#Permissions">Mengimplementasikan Izin Penyedia Konten</a>.
    ++        </p>
    ++    </dd>
    ++    <dt>
    ++        Atribut-atribut startup dan kontrol
    ++    </dt>
    ++    <dd>
    ++        Atribut-atribut ini menentukan cara dan waktu sistem Android memulai penyedia,
    ++        karakteristik proses penyedia, dan pengaturan runtime lainnya:
    ++        <ul>
    ++            <li>
    ++                <code><a href="{@docRoot}guide/topics/manifest/provider-element.html#enabled">
    ++                android:enabled</a></code>: Flag yang memperbolehkan sistem untuk memulai penyedia.
    ++            </li>
    ++              <li>
    ++                <code><a href="{@docRoot}guide/topics/manifest/provider-element.html#exported">
    ++                android:exported</a></code>: Flag yang memperbolehkan aplikasi lain untuk menggunakan penyedia ini.
    ++            </li>
    ++            <li>
    ++                <code><a href="{@docRoot}guide/topics/manifest/provider-element.html#init">
    ++                android:initOrder</a></code>: Urutan yang digunakan untuk memulai penyedia ini,
    ++                relatif terhadap penyedia lain dalam proses yang sama.
    ++            </li>
    ++            <li>
    ++                <code><a href="{@docRoot}guide/topics/manifest/provider-element.html#multi">
    ++                android:multiProcess</a></code>: Flag yang memperbolehkan sistem untuk memulai penyedia
    ++                dalam proses yang sama dengan proses klien pemanggil.
    ++            </li>
    ++            <li>
    ++                <code><a href="{@docRoot}guide/topics/manifest/provider-element.html#proc">
    ++                android:process</a></code>: Nama proses tempat penyedia harus
    ++                berjalan.
    ++            </li>
    ++            <li>
    ++                <code><a href="{@docRoot}guide/topics/manifest/provider-element.html#sync">
    ++                android:syncable</a></code>: Flag yang menunjukkan bahwa data penyedia harus
    ++                disinkronkan dengan data di server.
    ++            </li>
    ++        </ul>
    ++        <p>
    ++            Atribut-atribut ini didokumentasikan dengan lengkap dalam topik panduan pengembang untuk elemen
    ++            <code><a href="{@docRoot}guide/topics/manifest/provider-element.html">
    ++            &lt;provider&gt;</a></code>.
    ++
    ++        </p>
    ++    </dd>
    ++    <dt>
    ++        Atribut-atribut informatif
    ++    </dt>
    ++    <dd>
    ++        Ikon dan label opsional untuk penyedia:
    ++        <ul>
    ++            <li>
    ++                <code><a href="{@docRoot}guide/topics/manifest/provider-element.html#icon">
    ++                android:icon</a></code>: Sumber daya drawable, berisi ikon untuk penyedia.
    ++                Ikon ini muncul di sebelah label penyedia dalam daftar aplikasi dalam menu
    ++                <em>Settings</em> &gt; <em>Apps</em> &gt; <em>All</em>.
    ++            </li>
    ++            <li>
    ++                <code><a href="{@docRoot}guide/topics/manifest/provider-element.html#label">
    ++                android:label</a></code>: Label informatif yang menjelaskan penyedia atau
    ++                datanya, atau keduanya. Label ini muncul dalam daftar aplikasi di
    ++                <em>Settings</em> &gt; <em>Apps</em> &gt; <em>All</em>.
    ++            </li>
    ++        </ul>
    ++        <p>
    ++            Atribut-atribut ini didokumentasikan dengan lengkap dalam topik panduan pengembang untuk elemen
    ++            <code><a href="{@docRoot}guide/topics/manifest/provider-element.html">
    ++            &lt;provider&gt;</a></code>.
    ++        </p>
    ++    </dd>
    ++</dl>
    ++
    ++<!-- Intent Access -->
    ++<h2 id="Intents">Intent dan Akses Data</h2>
    ++<p>
    ++    Aplikasi bisa mengakses penyedia konten secara tidak langsung dengan sebuah {@link android.content.Intent}.
    ++    Aplikasi tidak memanggil satu pun dari metode-metode {@link android.content.ContentResolver} atau
    ++    {@link android.content.ContentProvider}. Sebagai gantinya, aplikasi mengirim intent yang memulai aktivitas,
    ++    yang sering kali merupakan bagian dari aplikasi penyedia sendiri. Aktivitas tujuan bertugas
    ++    mengambil dan menampilkan data dalam UI-nya. Bergantung pada tindakan dalam intent,
    ++    aktivitas tujuan juga bisa meminta pengguna untuk membuat modifikasi pada data penyedia.
    ++    Intent juga bisa berisi data "ekstra" yang menampilkan aktivitas tujuan
    ++    dalam UI; pengguna nanti memiliki pilihan untuk mengubah data ini sebelum menggunakannya untuk mengubah
    ++    data di penyedia.
    ++</p>
    ++<p>
    ++
    ++</p>
    ++<p>
    ++    Anda mungkin perlu menggunakan akses intent guna membantu memastikan integritas data. Penyedia Anda mungkin bergantung
    ++    pada data yang disisipkan, diperbarui, dan dihapusnya sesuai dengan logika bisnis yang didefinisikan dengan ketat. Jika
    ++    demikian halnya, memperbolehkan aplikasi lain mengubah data Anda secara langsung bisa menyebabkan
    ++    data yang tidak sah. Jika Anda ingin pengembang menggunakan akses intent, pastikan untuk mendokumentasikannya secara saksama.
    ++    Jelaskan kepada mereka alasan akses intent yang menggunakan UI aplikasi Anda sendiri adalah lebih baik daripada mencoba
    ++    memodifikasi data dengan kode mereka.
    ++</p>
    ++<p>
    ++    Menangani sebuah intent masuk yang ingin memodifikasi data penyedia Anda tidak berbeda dengan
    ++    menangani intent lainnya. Anda bisa mengetahui selengkapnya tentang penggunaan intent dengan membaca topik
    ++    <a href="{@docRoot}guide/components/intents-filters.html">Intent dan Filter Intent</a>.
    ++</p>
    +diff --git a/docs/html-intl/intl/id/guide/topics/providers/content-providers.jd b/docs/html-intl/intl/id/guide/topics/providers/content-providers.jd
    +new file mode 100644
    +index 0000000..2dcd55e
    +--- /dev/null
    ++++ b/docs/html-intl/intl/id/guide/topics/providers/content-providers.jd
    +@@ -0,0 +1,108 @@
    ++page.title=Penyedia konten
    ++@jd:body
    ++<div id="qv-wrapper">
    ++<div id="qv">
    ++
    ++
    ++<!-- In this document -->
    ++<h2>Topik</h2>
    ++<ol>
    ++    <li>
    ++        <a href="{@docRoot}guide/topics/providers/content-provider-basics.html">
    ++        Dasar-Dasar Penyedia Konten</a>
    ++    </li>
    ++    <li>
    ++        <a href="{@docRoot}guide/topics/providers/content-provider-creating.html">
    ++        Membuat Penyedia Konten</a>
    ++    </li>
    ++    <li>
    ++        <a href="{@docRoot}guide/topics/providers/calendar-provider.html">Penyedia Kalender</a>
    ++    </li>
    ++    <li>
    ++        <a href="{@docRoot}guide/topics/providers/contacts-provider.html">Penyedia Kontak</a>
    ++    </li>
    ++</ol>
    ++
    ++    <!-- Related Samples -->
    ++<h2>Contoh-Contoh Terkait</h2>
    ++    <ol>
    ++        <li>
    ++            <a href="{@docRoot}resources/samples/ContactManager/index.html">
    ++            Aplikasi Contact Manager</a>
    ++        </li>
    ++        <li>
    ++        <a href="{@docRoot}resources/samples/ApiDemos/src/com/example/android/apis/view/List2.html">
    ++        "Kursor (Orang)"
    ++        </a>
    ++        </li>
    ++        <li>
    ++        <a href="{@docRoot}resources/samples/ApiDemos/src/com/example/android/apis/view/List7.html">
    ++        "Kursor (Telepon)"</a>
    ++        </li>
    ++        <li>
    ++            <a href="{@docRoot}resources/samples/SampleSyncAdapter/index.html">
    ++            Contoh Adaptor Sinkronisasi</a>
    ++        </li>
    ++    </ol>
    ++</div>
    ++</div>
    ++<p>
    ++    Penyedia konten mengelola akses ke set data terstruktur. Penyedia ini membungkus
    ++ data, dan menyediakan mekanisme untuk mendefinisikan keamanan data. Penyedia konten adalah antarmuka
    ++ standar yang menghubungkan data dalam satu proses dengan kode yang berjalan dalam proses lain.
    ++</p>
    ++<p>
    ++    Bila Anda ingin mengakses data di penyedia konten, Anda menggunakan
    ++ {@link android.content.ContentResolver} objek dalam
    ++ {@link android.content.Context} aplikasi untuk berkomunikasi dengan penyedia sebagai klien.
    ++    Objek {@link android.content.ContentResolver} berkomunikasi dengan objek penyedia, yakni
    ++ instance kelas yang mengimplementasikan {@link android.content.ContentProvider}. Objek penyedia
    ++ menerima permintaan data dari klien, melakukan tindakan yang diminta, dan
    ++ mengembalikan hasilnya.
    ++</p>
    ++<p>
    ++    Anda tidak perlu mengembangkan penyedia sendiri jika tidak bermaksud untuk berbagi data dengan
    ++ aplikasi lain. Akan tetapi, Anda memerlukan penyedia buatan sendiri untuk menyediakan saran pencarian custom
    ++ dalam aplikasi Anda sendiri. Anda juga memerlukan penyedia sendiri jika ingin menyalin dan
    ++menempelkan data atau file yang kompleks dari aplikasi Anda ke aplikasi lain.
    ++</p>
    ++<p>
    ++    Android sendiri berisi penyedia konten yang mengelola data seperti informasi audio, video, gambar, dan
    ++ kontak pribadi. Anda bisa melihat sebagian informasi ini tercantum dalam dokumentasi
    ++ acuan untuk paket
    ++ <code><a href="{@docRoot}reference/android/provider/package-summary.html">android.provider</a>
    ++    </code>. Dengan beberapa batasan, semua penyedia ini bisa diakses oleh aplikasi Android
    ++ apa saja.
    ++</p><p>
    ++    Topik-topik berikut menjelaskan penyedia konten secara lebih detail:
    ++</p>
    ++<dl>
    ++    <dt>
    ++        <strong><a href="{@docRoot}guide/topics/providers/content-provider-basics.html">
    ++        Dasar-Dasar Penyedia Konten</a></strong>
    ++    </dt>
    ++    <dd>
    ++        Cara mengakses data di penyedia konten bila data disusun dalam tabel.
    ++    </dd>
    ++    <dt>
    ++        <strong><a href="{@docRoot}guide/topics/providers/content-provider-creating.html">
    ++        Membuat Penyedia Konten</a></strong>
    ++    </dt>
    ++    <dd>
    ++        Cara membuat penyedia konten sendiri.
    ++    </dd>
    ++    <dt>
    ++        <strong><a href="{@docRoot}guide/topics/providers/calendar-provider.html">
    ++        Penyedia Kalender</a></strong>
    ++    </dt>
    ++    <dd>
    ++        Cara mengakses Penyedia Kalender yang merupakan bagian dari platform Android.
    ++    </dd>
    ++    <dt>
    ++        <strong><a href="{@docRoot}guide/topics/providers/contacts-provider.html">
    ++        Penyedia Kontak</a></strong>
    ++    </dt>
    ++    <dd>
    ++        Cara mengakses Penyedia Kontak yang merupakan bagian dari platform Android.
    ++    </dd>
    ++</dl>
    +diff --git a/docs/html-intl/intl/id/guide/topics/providers/document-provider.jd b/docs/html-intl/intl/id/guide/topics/providers/document-provider.jd
    +new file mode 100644
    +index 0000000..f857467
    +--- /dev/null
    ++++ b/docs/html-intl/intl/id/guide/topics/providers/document-provider.jd
    +@@ -0,0 +1,916 @@
    ++page.title=Storage Access Framework
    ++@jd:body
    ++<div id="qv-wrapper">
    ++<div id="qv">
    ++
    ++<h2>Dalam dokumen ini
    ++ <a href="#" onclick="hideNestedItems('#toc44',this);return false;" class="header-toggle">
    ++        <span class="more">tampilkan maksimal</span>
    ++        <span class="less" style="display:none">tampilkan minimal</span></a></h2>
    ++<ol id="toc44" class="hide-nested">
    ++    <li>
    ++        <a href="#overview">Ikhtisar</a>
    ++    </li>
    ++    <li>
    ++        <a href="#flow">Arus Kontrol</a>
    ++    </li>
    ++    <li>
    ++        <a href="#client">Menulis Aplikasi Klien</a>
    ++        <ol>
    ++        <li><a href="#search">Mencari dokumen</a></li>
    ++        <li><a href="#process">Memproses hasil</a></li>
    ++        <li><a href="#metadata">Memeriksa metadata dokumen</a></li>
    ++        <li><a href="#open">Membuka dokumen</a></li>
    ++        <li><a href="#create">Membuat dokumen baru</a></li>
    ++        <li><a href="#delete">Menghapus dokumen</a></li>
    ++        <li><a href="#edit">Mengedit dokumen</a></li>
    ++        <li><a href="#permissions">Mempertahankan izin</a></li>
    ++        </ol>
    ++    </li>
    ++    <li><a href="#custom">Menulis Penyedia Dokumen Custom</a>
    ++        <ol>
    ++        <li><a href="#manifest">Manifes</a></li>
    ++        <li><a href="#contract">Kontrak</a></li>
    ++        <li><a href="#subclass">Subkelas DocumentsProvider</a></li>
    ++        <li><a href="#security">Keamanan</a></li>
    ++        </ol>
    ++    </li>
    ++
    ++</ol>
    ++<h2>Kelas-kelas utama</h2>
    ++<ol>
    ++    <li>{@link android.provider.DocumentsProvider}</li>
    ++    <li>{@link android.provider.DocumentsContract}</li>
    ++</ol>
    ++
    ++<h2>Video</h2>
    ++
    ++<ol>
    ++    <li><a href="http://www.youtube.com/watch?v=zxHVeXbK1P4">
    ++DevBytes: Android 4.4 Storage Access Framework: Penyedia</a></li>
    ++     <li><a href="http://www.youtube.com/watch?v=UFj9AEz0DHQ">
    ++DevBytes: Android 4.4 Storage Access Framework: Klien</a></li>
    ++</ol>
    ++
    ++
    ++<h2>Contoh Kode</h2>
    ++
    ++<ol>
    ++    <li><a href="{@docRoot}samples/StorageProvider/index.html">
    ++Penyedia Penyimpanan</a></li>
    ++     <li><a href="{@docRoot}samples/StorageClient/index.html">
    ++Klien Penyimpanan</a></li>
    ++</ol>
    ++
    ++<h2>Lihat Juga</h2>
    ++<ol>
    ++    <li>
    ++        <a href="{@docRoot}guide/topics/providers/content-provider-basics.html">
    ++        Dasar-Dasar Penyedia Konten
    ++        </a>
    ++    </li>
    ++</ol>
    ++
    ++</div>
    ++</div>
    ++
    ++
    ++<p>Android 4.4 (API level 19) memperkenalkan Storage Access Framework (SAF, Kerangka Kerja Akses Penyimpanan). SAF
    ++ memudahkan pengguna menyusuri dan membuka dokumen, gambar, dan file lainnya
    ++di semua penyedia penyimpanan dokumen pilihannya. UI standar yang mudah digunakan
    ++memungkinkan pengguna menyusuri file dan mengakses yang terbaru dengan cara konsisten di antara berbagai aplikasi dan penyedia.</p>
    ++
    ++<p>Layanan penyimpanan cloud atau lokal bisa dilibatkan dalam ekosistem ini dengan mengimplementasikan sebuah
    ++{@link android.provider.DocumentsProvider} yang membungkus layanannya. Aplikasi klien
    ++yang memerlukan akses ke dokumen sebuah penyedia bisa berintegrasi dengan SAF cukup dengan beberapa
    ++baris kode.</p>
    ++
    ++<p>SAF terdiri dari berikut ini:</p>
    ++
    ++<ul>
    ++<li><strong>Penyedia dokumen</strong>&mdash;Penyedia konten yang memungkinkan
    ++layanan penyimpanan (seperti Google Drive) untuk menampilkan file yang dikelolanya. Penyedia dokumen
    ++diimplementasikan sebagai subkelas dari kelas {@link android.provider.DocumentsProvider}.
    ++Skema penyedia dokumen berdasarkan hierarki file biasa,
    ++walaupun cara penyedia dokumen Anda secara fisik menyimpan data adalah terserah Anda.
    ++Platform Android terdiri dari beberapa penyedia dokumen bawaan, seperti
    ++Downloads, Images, dan Videos.</li>
    ++
    ++<li><strong>Aplikasi klien</strong>&mdash;Aplikasi custom yang memanggil intent
    ++{@link android.content.Intent#ACTION_OPEN_DOCUMENT} dan/atau
    ++{@link android.content.Intent#ACTION_CREATE_DOCUMENT} dan menerima
    ++file yang dihasilkan penyedia dokumen.</li>
    ++
    ++<li><strong>Picker</strong>&mdash;UI sistem yang memungkinkan pengguna mengakses dokumen dari semua
    ++penyedia dokumen yang memenuhi kriteria pencarian aplikasi klien.</li>
    ++</ul>
    ++
    ++<p>Beberapa fitur yang disediakan oleh SAF adalah sebagai berikut:</p>
    ++<ul>
    ++<li>Memungkinkan pengguna menyusuri konten dari semua penyedia dokumen, bukan hanya satu aplikasi.</li>
    ++<li>Memungkinkan aplikasi Anda memiliki akses jangka panjang dan tetap ke
    ++ dokumen yang dimiliki oleh penyedia dokumen. Melalui akses ini pengguna bisa menambah, mengedit,
    ++ menyimpan, dan menghapus file pada penyedia.</li>
    ++<li>Mendukung banyak akun pengguna dan akar jangka pendek seperti penyedia penyimpanan
    ++USB, yang hanya muncul jika drive itu dipasang. </li>
    ++</ul>
    ++
    ++<h2 id ="overview">Ikhtisar</h2>
    ++
    ++<p>SAF berpusat di seputar penyedia konten yang merupakan
    ++subkelas dari kelas {@link android.provider.DocumentsProvider}. Dalam <em>penyedia dokumen</em>, data
    ++distrukturkan sebagai hierarki file biasa:</p>
    ++<p><img src="{@docRoot}images/providers/storage_datamodel.png" alt="data model" /></p>
    ++<p class="img-caption"><strong>Gambar 1.</strong> Model data penyedia dokumen. Root menunjuk ke satu Document,
    ++yang nanti memulai pemekaran seluruh pohon.</p>
    ++
    ++<p>Perhatikan yang berikut ini:</p>
    ++<ul>
    ++
    ++<li>Setiap penyedia dokumen melaporkan satu atau beberapa
    ++"akar" yang merupakan titik awal penyusuran pohon dokumen.
    ++Masing-masing akar memiliki sebuah {@link android.provider.DocumentsContract.Root#COLUMN_ROOT_ID} yang unik,
    ++dan menunjuk ke satu dokumen (satu direktori)
    ++yang mewakili konten di bawah akar itu.
    ++Akar sengaja dibuat dinamis untuk mendukung kasus penggunaan seperti multiakun,
    ++perangkat penyimpanan USB jangka pendek, atau masuk/keluar pengguna.</li>
    ++
    ++<li>Di bawah tiap akar terdapat satu dokumen. Dokumen itu menunjuk ke dokumen-dokumen 1-ke-<em>N</em>,
    ++yang nanti masing-masing bisa menunjuk ke dokumen 1-ke-<em>N</em>. </li>
    ++
    ++<li>Tiap backend penyimpanan memunculkan
    ++masing-masing file dan direktori dengan mengacunya lewat sebuah
    ++{@link android.provider.DocumentsContract.Document#COLUMN_DOCUMENT_ID} yang unik.
    ++ID dokumen harus unik dan tidak berubah setelah dibuat, karena ID ini digunakan untuk
    ++URI persisten yang diberikan pada saat reboot perangkat.</li>
    ++
    ++
    ++<li>Dokumen bisa berupa file yang bisa dibuka (dengan tipe MIME tertentu), atau
    ++direktori yang berisi dokumen tambahan (dengan tipe MIME
    ++{@link android.provider.DocumentsContract.Document#MIME_TYPE_DIR}).</li>
    ++
    ++<li>Tiap dokumen bisa mempunyai kemampuan berbeda, sebagaimana yang dijelaskan oleh
    ++{@link android.provider.DocumentsContract.Document#COLUMN_FLAGS COLUMN_FLAGS}.
    ++Misalnya, {@link android.provider.DocumentsContract.Document#FLAG_SUPPORTS_WRITE},
    ++{@link android.provider.DocumentsContract.Document#FLAG_SUPPORTS_DELETE}, dan
    ++{@link android.provider.DocumentsContract.Document#FLAG_SUPPORTS_THUMBNAIL}.
    ++{@link android.provider.DocumentsContract.Document#COLUMN_DOCUMENT_ID} yang sama bisa
    ++dimasukkan dalam beberapa direktori.</li>
    ++</ul>
    ++
    ++<h2 id="flow">Arus Kontrol</h2>
    ++<p>Seperti dinyatakan di atas, model data penyedia dokumen dibuat berdasarkan hierarki file
    ++biasa. Akan tetapi, Anda bisa menyimpan secara fisik data dengan cara apa pun yang disukai,
    ++selama data bisa diakses melalui API {@link android.provider.DocumentsProvider}. Misalnya, Anda
    ++bisa menggunakan penyimpanan cloud berbasis tag untuk data Anda.</p>
    ++
    ++<p>Gambar 2 menampilkan contoh cara aplikasi foto bisa menggunakan SAF
    ++untuk mengakses data tersimpan:</p>
    ++<p><img src="{@docRoot}images/providers/storage_dataflow.png" alt="app" /></p>
    ++
    ++<p class="img-caption"><strong>Gambar 2.</strong> Arus Storage Access Framework</p>
    ++
    ++<p>Perhatikan yang berikut ini:</p>
    ++<ul>
    ++
    ++<li>Di SAF, penyedia dan klien tidak berinteraksi
    ++secara langsung. Klien meminta izin untuk berinteraksi
    ++dengan file (yakni, membaca, mengedit, membuat, atau menghapus file).</li>
    ++
    ++<li>Interaksi dimulai bila sebuah aplikasi (dalam contoh ini adalah aplikasi foto) mengeluarkan intent
    ++{@link android.content.Intent#ACTION_OPEN_DOCUMENT} atau {@link android.content.Intent#ACTION_CREATE_DOCUMENT}. Intent bisa berisi filter
    ++untuk mempersempit kriteria&mdash;misalnya, "beri saya semua file yang bisa dibuka
    ++yang memiliki tipe MIME 'gambar'".</li>
    ++
    ++<li>Setelah intent dibuat, picker sistem akan pergi ke setiap penyedia yang terdaftar
    ++dan menunjukkan kepada pengguna akar konten yang cocok.</li>
    ++
    ++<li>Picker memberi pengguna antarmuka standar untuk mengakses dokumen,
    ++walaupun penyedia dokumen dasar bisa sangat berbeda. Misalnya, gambar 2
    ++menunjukkan penyedia Google Drive, penyedia USB, dan penyedia cloud.</li>
    ++</ul>
    ++
    ++<p>Gambar 3 menunjukkan picker yang di digunakan pengguna mencari gambar telah memilih
    ++akun Google Drive:</p>
    ++
    ++<p><img src="{@docRoot}images/providers/storage_picker.png" width="340" alt="picker" style="border:2px solid #ddd" /></p>
    ++
    ++<p class="img-caption"><strong>Gambar 3.</strong> Picker</p>
    ++
    ++<p>Bila pengguna memilih Google Drive, gambar-gambar akan ditampilkan, seperti yang ditampilkan dalam
    ++gambar 4. Dari titik itu, pengguna bisa berinteraksi dengan gambar dengan cara apa pun
    ++yang didukung oleh penyedia dan aplikasi klien.
    ++
    ++<p><img src="{@docRoot}images/providers/storage_photos.png" width="340" alt="picker" style="border:2px solid #ddd" /></p>
    ++
    ++<p class="img-caption"><strong>Gambar 4.</strong> Gambar</p>
    ++
    ++<h2 id="client">Menulis Aplikasi Klien</h2>
    ++
    ++<p>Pada Android 4.3 dan yang lebih rendah, jika Anda ingin aplikasi mengambil file dari
    ++aplikasi lain, aplikasi Anda harus memanggil intent seperti {@link android.content.Intent#ACTION_PICK}
    ++atau {@link android.content.Intent#ACTION_GET_CONTENT}. Pengguna nanti harus memilih
    ++satu aplikasi yang akan digunakan untuk mengambil file dan aplikasi yang dipilih harus menyediakan antarmuka pengguna
    ++bagi untuk menyusuri dan mengambil dari file yang tersedia. </p>
    ++
    ++<p>Pada Android 4.4 dan yang lebih tinggi, Anda mempunyai opsi tambahan dalam menggunakan intent
    ++{@link android.content.Intent#ACTION_OPEN_DOCUMENT},
    ++yang menampilkan UI picker yang dikontrol oleh sistem yang memungkinkan pengguna
    ++menyusuri semua file yang disediakan aplikasi lain. Dari satu UI ini, pengguna
    ++bisa mengambil file dari aplikasi apa saja yang didukung.</p>
    ++
    ++<p>{@link android.content.Intent#ACTION_OPEN_DOCUMENT}
    ++tidak dimaksudkan untuk menjadi pengganti {@link android.content.Intent#ACTION_GET_CONTENT}.
    ++Yang harus Anda gunakan bergantung pada kebutuhan aplikasi:</p>
    ++
    ++<ul>
    ++<li>Gunakan {@link android.content.Intent#ACTION_GET_CONTENT} jika Anda ingin aplikasi
    ++cuma membaca/mengimpor data. Dengan pendekatan ini, aplikasi akan mengimpor salinan data,
    ++misalnya file gambar.</li>
    ++
    ++<li>Gunakan {@link android.content.Intent#ACTION_OPEN_DOCUMENT} jika Anda ingin aplikasi
    ++memiliki akses jangka panjang dan jangka pendek ke dokumen yang dimiliki oleh penyedia
    ++dokumen. Contohnya adalah aplikasi pengeditan foto yang memungkinkan pengguna mengedit
    ++gambar yang tersimpan dalam penyedia dokumen. </li>
    ++
    ++</ul>
    ++
    ++
    ++<p>Bagian ini menjelaskan cara menulis aplikasi klien berdasarkan
    ++{@link android.content.Intent#ACTION_OPEN_DOCUMENT} dan
    ++intent {@link android.content.Intent#ACTION_CREATE_DOCUMENT}.</p>
    ++
    ++
    ++<h3 id="search">Mencari dokumen</h3>
    ++
    ++<p>
    ++Cuplikan berikut menggunakan {@link android.content.Intent#ACTION_OPEN_DOCUMENT}
    ++untuk mencari penyedia dokumen yang
    ++berisi file gambar:</p>
    ++
    ++<pre>private static final int READ_REQUEST_CODE = 42;
    ++...
    ++/**
    ++ * Fires an intent to spin up the &quot;file chooser&quot; UI and select an image.
    ++ */
    ++public void performFileSearch() {
    ++
    ++    // ACTION_OPEN_DOCUMENT is the intent to choose a file via the system's file
    ++    // browser.
    ++    Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT);
    ++
    ++    // Filter to only show results that can be &quot;opened&quot;, such as a
    ++    // file (as opposed to a list of contacts or timezones)
    ++    intent.addCategory(Intent.CATEGORY_OPENABLE);
    ++
    ++    // Filter to show only images, using the image MIME data type.
    ++    // If one wanted to search for ogg vorbis files, the type would be &quot;audio/ogg&quot;.
    ++    // To search for all documents available via installed storage providers,
    ++    // it would be &quot;*/*&quot;.
    ++    intent.setType(&quot;image/*&quot;);
    ++
    ++    startActivityForResult(intent, READ_REQUEST_CODE);
    ++}</pre>
    ++
    ++<p>Perhatikan yang berikut ini:</p>
    ++<ul>
    ++<li>Saat aplikasi mengeluarkan intent {@link android.content.Intent#ACTION_OPEN_DOCUMENT}
    ++, aplikasi akan menjalankan picker yang menampilkan semua penyedia dokumen yang cocok.</li>
    ++
    ++<li>Menambahkan kategori {@link android.content.Intent#CATEGORY_OPENABLE} ke
    ++intent akan menyaring hasil agar hanya menampilkan dokumen yang bisa dibuka, seperti file gambar.</li>
    ++
    ++<li>Pernyataan {@code intent.setType("image/*")} menyaring lebih jauh agar hanya
    ++menampilkan dokumen yang memiliki tipe data MIME gambar.</li>
    ++</ul>
    ++
    ++<h3 id="results">Memproses Hasil</h3>
    ++
    ++<p>Setelah pengguna memilih dokumen di picker,
    ++{@link android.app.Activity#onActivityResult onActivityResult()} akan dipanggil.
    ++URI yang menunjuk ke dokumen yang dipilih dimasukkan dalam parameter {@code resultData}
    ++. Ekstrak URI dengan {@link android.content.Intent#getData getData()}.
    ++Setelah mendapatkannya, Anda bisa menggunakannya untuk mengambil dokumen yang diinginkan pengguna. Misalnya
    ++:</p>
    ++
    ++<pre>&#64;Override
    ++public void onActivityResult(int requestCode, int resultCode,
    ++        Intent resultData) {
    ++
    ++    // The ACTION_OPEN_DOCUMENT intent was sent with the request code
    ++    // READ_REQUEST_CODE. If the request code seen here doesn't match, it's the
    ++    // response to some other intent, and the code below shouldn't run at all.
    ++
    ++    if (requestCode == READ_REQUEST_CODE && resultCode == Activity.RESULT_OK) {
    ++        // The document selected by the user won't be returned in the intent.
    ++        // Instead, a URI to that document will be contained in the return intent
    ++        // provided to this method as a parameter.
    ++        // Pull that URI using resultData.getData().
    ++        Uri uri = null;
    ++        if (resultData != null) {
    ++            uri = resultData.getData();
    ++            Log.i(TAG, "Uri: " + uri.toString());
    ++            showImage(uri);
    ++        }
    ++    }
    ++}
    ++</pre>
    ++
    ++<h3 id="metadata">Memeriksa metadata dokumen</h3>
    ++
    ++<p>Setelah Anda memiliki URI untuk dokumen, Anda akan mendapatkan akses ke metadatanya. Cuplikan
    ++ini memegang metadata sebuah dokumen yang disebutkan oleh URI, dan mencatatnya:</p>
    ++
    ++<pre>public void dumpImageMetaData(Uri uri) {
    ++
    ++    // The query, since it only applies to a single document, will only return
    ++    // one row. There's no need to filter, sort, or select fields, since we want
    ++    // all fields for one document.
    ++    Cursor cursor = getActivity().getContentResolver()
    ++            .query(uri, null, null, null, null, null);
    ++
    ++    try {
    ++    // moveToFirst() returns false if the cursor has 0 rows.  Very handy for
    ++    // &quot;if there's anything to look at, look at it&quot; conditionals.
    ++        if (cursor != null &amp;&amp; cursor.moveToFirst()) {
    ++
    ++            // Note it's called &quot;Display Name&quot;.  This is
    ++            // provider-specific, and might not necessarily be the file name.
    ++            String displayName = cursor.getString(
    ++                    cursor.getColumnIndex(OpenableColumns.DISPLAY_NAME));
    ++            Log.i(TAG, &quot;Display Name: &quot; + displayName);
    ++
    ++            int sizeIndex = cursor.getColumnIndex(OpenableColumns.SIZE);
    ++            // If the size is unknown, the value stored is null.  But since an
    ++            // int can't be null in Java, the behavior is implementation-specific,
    ++            // which is just a fancy term for &quot;unpredictable&quot;.  So as
    ++            // a rule, check if it's null before assigning to an int.  This will
    ++            // happen often:  The storage API allows for remote files, whose
    ++            // size might not be locally known.
    ++            String size = null;
    ++            if (!cursor.isNull(sizeIndex)) {
    ++                // Technically the column stores an int, but cursor.getString()
    ++                // will do the conversion automatically.
    ++                size = cursor.getString(sizeIndex);
    ++            } else {
    ++                size = &quot;Unknown&quot;;
    ++            }
    ++            Log.i(TAG, &quot;Size: &quot; + size);
    ++        }
    ++    } finally {
    ++        cursor.close();
    ++    }
    ++}
    ++</pre>
    ++
    ++<h3 id="open-client">Membuka dokumen</h3>
    ++
    ++<p>Setelah mendapatkan URI dokumen, Anda bisa membuka dokumen atau melakukan apa saja
    ++yang diinginkan padanya.</p>
    ++
    ++<h4>Bitmap</h4>
    ++
    ++<p>Berikut ini adalah contoh cara membuka {@link android.graphics.Bitmap}:</p>
    ++
    ++<pre>private Bitmap getBitmapFromUri(Uri uri) throws IOException {
    ++    ParcelFileDescriptor parcelFileDescriptor =
    ++            getContentResolver().openFileDescriptor(uri, "r");
    ++    FileDescriptor fileDescriptor = parcelFileDescriptor.getFileDescriptor();
    ++    Bitmap image = BitmapFactory.decodeFileDescriptor(fileDescriptor);
    ++    parcelFileDescriptor.close();
    ++    return image;
    ++}
    ++</pre>
    ++
    ++<p>Perhatikan bahwa Anda tidak boleh melakukan operasi ini pada thread UI. Lakukan hal ini di latar belakang
    ++, dengan menggunakan {@link android.os.AsyncTask}. Setelah membuka bitmap, Anda
    ++bisa menampilkannya dalam {@link android.widget.ImageView}.
    ++</p>
    ++
    ++<h4>Mendapatkan InputStream</h4>
    ++
    ++<p>Berikut ini adalah contoh cara mendapatkan {@link java.io.InputStream} dari URI. Dalam cuplikan ini
    ++, baris-baris file dibaca ke dalam sebuah string:</p>
    ++
    ++<pre>private String readTextFromUri(Uri uri) throws IOException {
    ++    InputStream inputStream = getContentResolver().openInputStream(uri);
    ++    BufferedReader reader = new BufferedReader(new InputStreamReader(
    ++            inputStream));
    ++    StringBuilder stringBuilder = new StringBuilder();
    ++    String line;
    ++    while ((line = reader.readLine()) != null) {
    ++        stringBuilder.append(line);
    ++    }
    ++    fileInputStream.close();
    ++    parcelFileDescriptor.close();
    ++    return stringBuilder.toString();
    ++}
    ++</pre>
    ++
    ++<h3 id="create">Membuat dokumen baru</h3>
    ++
    ++<p>Aplikasi Anda bisa membuat dokumen baru dalam penyedia dokumen dengan menggunakan intent
    ++{@link android.content.Intent#ACTION_CREATE_DOCUMENT}
    ++. Untuk membuat file, Anda memberikan satu tipe MIME dan satu nama file pada intent, dan
    ++menjalankannya dengan kode permintaan yang unik. Selebihnya akan diurus untuk Anda:</p>
    ++
    ++
    ++<pre>
    ++// Here are some examples of how you might call this method.
    ++// The first parameter is the MIME type, and the second parameter is the name
    ++// of the file you are creating:
    ++//
    ++// createFile("text/plain", "foobar.txt");
    ++// createFile("image/png", "mypicture.png");
    ++
    ++// Unique request code.
    ++private static final int WRITE_REQUEST_CODE = 43;
    ++...
    ++private void createFile(String mimeType, String fileName) {
    ++    Intent intent = new Intent(Intent.ACTION_CREATE_DOCUMENT);
    ++
    ++    // Filter to only show results that can be &quot;opened&quot;, such as
    ++    // a file (as opposed to a list of contacts or timezones).
    ++    intent.addCategory(Intent.CATEGORY_OPENABLE);
    ++
    ++    // Create a file with the requested MIME type.
    ++    intent.setType(mimeType);
    ++    intent.putExtra(Intent.EXTRA_TITLE, fileName);
    ++    startActivityForResult(intent, WRITE_REQUEST_CODE);
    ++}
    ++</pre>
    ++
    ++<p>Setelah membuat dokumen baru, Anda bisa mendapatkan URI-nya dalam
    ++{@link android.app.Activity#onActivityResult onActivityResult()}, sehingga Anda
    ++bisa terus menulis ke dokumen itu.</p>
    ++
    ++<h3 id="delete">Menghapus dokumen</h3>
    ++
    ++<p>Jika Anda memiliki URI dokumen dan
    ++{@link android.provider.DocumentsContract.Document#COLUMN_FLAGS Document.COLUMN_FLAGS}
    ++ dokumen berisi
    ++{@link android.provider.DocumentsContract.Document#FLAG_SUPPORTS_DELETE SUPPORTS_DELETE},
    ++Anda bisa menghapus dokumen tersebut. Misalnya:</p>
    ++
    ++<pre>
    ++DocumentsContract.deleteDocument(getContentResolver(), uri);
    ++</pre>
    ++
    ++<h3 id="edit">Mengedit dokumen</h3>
    ++
    ++<p>Anda bisa menggunakan SAF untuk mengedit dokumen teks langsung di tempatnya.
    ++Cuplikan ini memicu
    ++intent {@link android.content.Intent#ACTION_OPEN_DOCUMENT} dan menggunakan
    ++kategori {@link android.content.Intent#CATEGORY_OPENABLE} untuk menampilkan
    ++dokumen yang bisa dibuka saja. Ini akan menyaring lebih jauh untuk menampilkan file teks saja:</p>
    ++
    ++<pre>
    ++private static final int EDIT_REQUEST_CODE = 44;
    ++/**
    ++ * Open a file for writing and append some text to it.
    ++ */
    ++ private void editDocument() {
    ++    // ACTION_OPEN_DOCUMENT is the intent to choose a file via the system's
    ++    // file browser.
    ++    Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT);
    ++
    ++    // Filter to only show results that can be &quot;opened&quot;, such as a
    ++    // file (as opposed to a list of contacts or timezones).
    ++    intent.addCategory(Intent.CATEGORY_OPENABLE);
    ++
    ++    // Filter to show only text files.
    ++    intent.setType(&quot;text/plain&quot;);
    ++
    ++    startActivityForResult(intent, EDIT_REQUEST_CODE);
    ++}
    ++</pre>
    ++
    ++<p>Berikutnya, dari {@link android.app.Activity#onActivityResult onActivityResult()}
    ++(lihat <a href="#results">Memproses hasil</a>) Anda bisa memanggil kode untuk mengedit.
    ++Cuplikan berikut mendapatkan {@link java.io.FileOutputStream}
    ++dari {@link android.content.ContentResolver}. Secara default, snipet menggunakan mode “tulis”.
    ++Inilah praktik terbaik untuk meminta jumlah akses minimum yang Anda perlukan, jadi jangan meminta
    ++baca/tulis jika yang Anda perlukan hanyalah tulis:</p>
    ++
    ++<pre>private void alterDocument(Uri uri) {
    ++    try {
    ++        ParcelFileDescriptor pfd = getActivity().getContentResolver().
    ++                openFileDescriptor(uri, "w");
    ++        FileOutputStream fileOutputStream =
    ++                new FileOutputStream(pfd.getFileDescriptor());
    ++        fileOutputStream.write(("Overwritten by MyCloud at " +
    ++                System.currentTimeMillis() + "\n").getBytes());
    ++        // Let the document provider know you're done by closing the stream.
    ++        fileOutputStream.close();
    ++        pfd.close();
    ++    } catch (FileNotFoundException e) {
    ++        e.printStackTrace();
    ++    } catch (IOException e) {
    ++        e.printStackTrace();
    ++    }
    ++}</pre>
    ++
    ++<h3 id="permissions">Mempertahankan izin</h3>
    ++
    ++<p>Bila aplikasi Anda membuka file untuk membaca atau menulis, sistem akan memberi
    ++aplikasi Anda izin URI untuk file itu. Pemberian ini berlaku hingga perangkat pengguna di-restart.
    ++Namun anggaplah aplikasi Anda adalah aplikasi pengeditan gambar, dan Anda ingin pengguna bisa
    ++mengakses 5 gambar terakhir yang dieditnya, langsung dari aplikasi Anda. Jika perangkat pengguna telah
    ++di-restart, maka Anda harus mengirim pengguna kembali ke picker sistem untuk menemukan
    ++file, hal ini jelas tidak ideal.</p>
    ++
    ++<p>Untuk mencegah terjadinya hal ini, Anda bisa mempertahankan izin yang diberikan
    ++sistem ke aplikasi Anda. Secara efektif, aplikasi Anda akan "mengambil" pemberian izin URI yang bisa dipertahankan
    ++yang ditawarkan oleh sistem. Hal ini memberi pengguna akses kontinu ke file
    ++melalui aplikasi Anda, sekalipun perangkat telah di-restart:</p>
    ++
    ++
    ++<pre>final int takeFlags = intent.getFlags()
    ++            &amp; (Intent.FLAG_GRANT_READ_URI_PERMISSION
    ++            | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
    ++// Check for the freshest data.
    ++getContentResolver().takePersistableUriPermission(uri, takeFlags);</pre>
    ++
    ++<p>Ada satu langkah akhir. Anda mungkin telah menyimpan
    ++URI terbaru yang diakses aplikasi, namun URI itu mungkin tidak lagi valid,&mdash;aplikasi lain
    ++mungkin telah menghapus atau memodifikasi dokumen. Karena itu, Anda harus selalu memanggil
    ++{@code getContentResolver().takePersistableUriPermission()} untuk memeriksa
    ++data terbaru.</p>
    ++
    ++<h2 id="custom">Menulis Penyedia Dokumen Custom</h2>
    ++
    ++<p>
    ++Jika Anda sedang mengembangkan aplikasi yang menyediakan layanan penyimpanan untuk file (misalnya
    ++layanan penyimpanan cloud), Anda bisa menyediakan file melalui
    ++SAF dengan menulis penyedia dokumen custom.  Bagian ini menjelaskan
    ++caranya.</p>
    ++
    ++
    ++<h3 id="manifest">Manifes</h3>
    ++
    ++<p>Untuk mengimplementasikan penyedia dokumen custom, tambahkan yang berikut ini ke manifes aplikasi
    ++Anda:</p>
    ++<ul>
    ++
    ++<li>Target berupa API level 19 atau yang lebih tinggi.</li>
    ++
    ++<li>Elemen <code>&lt;provider&gt;</code> yang mendeklarasikan penyedia penyimpanan custom
    ++Anda. </li>
    ++
    ++<li>Nama penyedia Anda, yaitu nama kelasnya, termasuk nama paket.
    ++Misalnya: <code>com.example.android.storageprovider.MyCloudProvider</code>.</li>
    ++
    ++<li>Nama otoritas Anda, yaitu nama paket Anda (dalam contoh ini,
    ++<code>com.example.android.storageprovider</code>) plus tipe penyedia konten
    ++(<code>documents</code>). Misalnya, {@code com.example.android.storageprovider.documents}.</li>
    ++
    ++<li>Atribut <code>android:exported</code> yang diatur ke <code>&quot;true&quot;</code>.
    ++Anda harus mengekspor penyedia sehingga aplikasi lain bisa membacanya.</li>
    ++
    ++<li>Atribut <code>android:grantUriPermissions</code> yang diatur ke
    ++<code>&quot;true&quot;</code>. Pengaturan ini memungkinkan sistem memberi aplikasi lain akses
    ++ke konten dalam penyedia Anda. Untuk pembahasan cara mempertahankan pemberian bagi
    ++dokumen tertentu, lihat <a href="#permissions">Mempertahankan izin</a>.</li>
    ++
    ++<li>Izin {@code MANAGE_DOCUMENTS}. Secara default, penyedia tersedia
    ++bagi siapa saja. Menambahkan izin ini akan membatasi penyedia Anda pada sistem.
    ++Pembatasan ini penting untuk keamanan.</li>
    ++
    ++<li>Atribut {@code android:enabled} yang diatur ke nilai boolean didefinisikan dalam file
    ++sumber daya. Tujuan atribut ini adalah menonaktifkan penyedia pada perangkat yang menjalankan Android 4.3 atau yang lebih rendah.
    ++Misalnya, {@code android:enabled="@bool/atLeastKitKat"}. Selain
    ++memasukkan atribut ini dalam manifes, Anda perlu melakukan hal-hal berikut:
    ++<ul>
    ++<li>Dalam file sumber daya {@code bool.xml} Anda di bawah {@code res/values/}, tambahkan
    ++baris ini: <pre>&lt;bool name=&quot;atLeastKitKat&quot;&gt;false&lt;/bool&gt;</pre></li>
    ++
    ++<li>Dalam file sumber daya {@code bool.xml} Anda di bawah {@code res/values-v19/}, tambahkan
    ++baris ini: <pre>&lt;bool name=&quot;atLeastKitKat&quot;&gt;true&lt;/bool&gt;</pre></li>
    ++</ul></li>
    ++
    ++<li>Sebuah filter intent berisi tindakan
    ++{@code android.content.action.DOCUMENTS_PROVIDER}, agar penyedia Anda
    ++muncul dalam picker saat sistem mencari penyedia.</li>
    ++
    ++</ul>
    ++<p>Berikut ini adalah kutipan contoh manifes berisi penyedia yang:</p>
    ++
    ++<pre>&lt;manifest... &gt;
    ++    ...
    ++    &lt;uses-sdk
    ++        android:minSdkVersion=&quot;19&quot;
    ++        android:targetSdkVersion=&quot;19&quot; /&gt;
    ++        ....
    ++        &lt;provider
    ++            android:name=&quot;com.example.android.storageprovider.MyCloudProvider&quot;
    ++            android:authorities=&quot;com.example.android.storageprovider.documents&quot;
    ++            android:grantUriPermissions=&quot;true&quot;
    ++            android:exported=&quot;true&quot;
    ++            android:permission=&quot;android.permission.MANAGE_DOCUMENTS&quot;
    ++            android:enabled=&quot;&#64;bool/atLeastKitKat&quot;&gt;
    ++            &lt;intent-filter&gt;
    ++                &lt;action android:name=&quot;android.content.action.DOCUMENTS_PROVIDER&quot; /&gt;
    ++            &lt;/intent-filter&gt;
    ++        &lt;/provider&gt;
    ++    &lt;/application&gt;
    ++
    ++&lt;/manifest&gt;</pre>
    ++
    ++<h4 id="43">Mendukung perangkat yang menjalankan Android 4.3 dan yang lebih rendah</h4>
    ++
    ++<p>Intent
    ++{@link android.content.Intent#ACTION_OPEN_DOCUMENT} hanya tersedia
    ++pada perangkat yang menjalankan Android 4.4 dan yang lebih tinggi.
    ++Jika ingin aplikasi Anda mendukung {@link android.content.Intent#ACTION_GET_CONTENT}
    ++untuk mengakomodasi perangkat yang menjalankan Android 4.3 dan yang lebih rendah, Anda harus
    ++menonaktifkan filter inten {@link android.content.Intent#ACTION_GET_CONTENT} dalam
    ++manifes untuk perangkat yang menjalankan Android 4.4 atau yang lebih tinggi. Penyedia
    ++dokumen dan {@link android.content.Intent#ACTION_GET_CONTENT} harus dianggap
    ++saling eksklusif. Jika Anda mendukung keduanya sekaligus, aplikasi Anda akan
    ++muncul dua kali dalam UI picker sistem, yang menawarkan dua cara mengakses
    ++data tersimpan Anda. Hal ini akan membingungkan pengguna.</p>
    ++
    ++<p>Berikut ini adalah cara yang disarankan untuk menonaktifkan
    ++filter intent {@link android.content.Intent#ACTION_GET_CONTENT} untuk perangkat
    ++yang menjalankan Android versi 4.4 atau yang lebih tinggi:</p>
    ++
    ++<ol>
    ++<li>Dalam file sumber daya {@code bool.xml} Anda di bawah {@code res/values/}, tambahkan
    ++baris ini: <pre>&lt;bool name=&quot;atMostJellyBeanMR2&quot;&gt;true&lt;/bool&gt;</pre></li>
    ++
    ++<li>Dalam file sumber daya {@code bool.xml} Anda di bawah {@code res/values-v19/}, tambahkan
    ++baris ini: <pre>&lt;bool name=&quot;atMostJellyBeanMR2&quot;&gt;false&lt;/bool&gt;</pre></li>
    ++
    ++<li>Tambahkan
    ++<a href="{@docRoot}guide/topics/manifest/activity-alias-element.html">alias
    ++aktivitas</a> untuk menonaktifkan filter intent {@link android.content.Intent#ACTION_GET_CONTENT}
    ++bagi versi 4.4 (API level 19) dan yang lebih tinggi. Misalnya:
    ++
    ++<pre>
    ++&lt;!-- This activity alias is added so that GET_CONTENT intent-filter
    ++     can be disabled for builds on API level 19 and higher. --&gt;
    ++&lt;activity-alias android:name=&quot;com.android.example.app.MyPicker&quot;
    ++        android:targetActivity=&quot;com.android.example.app.MyActivity&quot;
    ++        ...
    ++        android:enabled=&quot;@bool/atMostJellyBeanMR2&quot;&gt;
    ++    &lt;intent-filter&gt;
    ++        &lt;action android:name=&quot;android.intent.action.GET_CONTENT&quot; /&gt;
    ++        &lt;category android:name=&quot;android.intent.category.OPENABLE&quot; /&gt;
    ++        &lt;category android:name=&quot;android.intent.category.DEFAULT&quot; /&gt;
    ++        &lt;data android:mimeType=&quot;image/*&quot; /&gt;
    ++        &lt;data android:mimeType=&quot;video/*&quot; /&gt;
    ++    &lt;/intent-filter&gt;
    ++&lt;/activity-alias&gt;
    ++</pre>
    ++</li>
    ++</ol>
    ++<h3 id="contract">Kontrak</h3>
    ++
    ++<p>Biasanya bila Anda menulis penyedia konten custom, salah satu tugas adalah
    ++mengimplementasikan kelas kontrak, seperti dijelaskan dalam panduan pengembang
    ++<a href="{@docRoot}guide/topics/providers/content-provider-creating.html#ContractClass">
    ++Penyedia Konten</a>. Kelas kontrak adalah kelas {@code public final}
    ++yang berisi definisi konstanta untuk URI, nama kolom, tipe MIME, dan
    ++metadata lain yang berkenaan dengan penyedia. SAF
    ++menyediakan kelas-kelas kontrak ini untuk Anda, jadi Anda tidak perlu menulisnya
    ++sendiri:</p>
    ++
    ++<ul>
    ++   <li>{@link android.provider.DocumentsContract.Document}</li>
    ++   <li>{@link android.provider.DocumentsContract.Root}</li>
    ++</ul>
    ++
    ++<p>Misalnya, berikut ini adalah kolom-kolom yang bisa Anda hasilkan di kursor bila
    ++penyedia dokumen Anda membuat query dokumen atau akar:</p>
    ++
    ++<pre>private static final String[] DEFAULT_ROOT_PROJECTION =
    ++        new String[]{Root.COLUMN_ROOT_ID, Root.COLUMN_MIME_TYPES,
    ++        Root.COLUMN_FLAGS, Root.COLUMN_ICON, Root.COLUMN_TITLE,
    ++        Root.COLUMN_SUMMARY, Root.COLUMN_DOCUMENT_ID,
    ++        Root.COLUMN_AVAILABLE_BYTES,};
    ++private static final String[] DEFAULT_DOCUMENT_PROJECTION = new
    ++        String[]{Document.COLUMN_DOCUMENT_ID, Document.COLUMN_MIME_TYPE,
    ++        Document.COLUMN_DISPLAY_NAME, Document.COLUMN_LAST_MODIFIED,
    ++        Document.COLUMN_FLAGS, Document.COLUMN_SIZE,};
    ++</pre>
    ++
    ++<h3 id="subclass">Subkelas DocumentsProvider</h3>
    ++
    ++<p>Langkah berikutnya dalam menulis penyedia dokumen custom adalah menjadikan
    ++kelas abstrak sebagai subkelas {@link android.provider.DocumentsProvider}. Setidaknya, Anda perlu
    ++ mengimplementasikan metode berikut:</p>
    ++
    ++<ul>
    ++<li>{@link android.provider.DocumentsProvider#queryRoots queryRoots()}</li>
    ++
    ++<li>{@link android.provider.DocumentsProvider#queryChildDocuments queryChildDocuments()}</li>
    ++
    ++<li>{@link android.provider.DocumentsProvider#queryDocument queryDocument()}</li>
    ++
    ++<li>{@link android.provider.DocumentsProvider#openDocument openDocument()}</li>
    ++</ul>
    ++
    ++<p>Hanya inilah metode yang diwajibkan kepada Anda secara ketat untuk diimplementasikan, namun ada
    ++banyak lagi yang mungkin Anda inginkan. Lihat {@link android.provider.DocumentsProvider}
    ++untuk detailnya.</p>
    ++
    ++<h4 id="queryRoots">Mengimplementasikan queryRoots</h4>
    ++
    ++<p>Implementasi {@link android.provider.DocumentsProvider#queryRoots
    ++queryRoots()} oleh Anda harus menghasilkan {@link android.database.Cursor} yang menunjuk ke semua
    ++direktori akar penyedia dokumen, dengan menggunakan kolom-kolom yang didefinisikan dalam
    ++{@link android.provider.DocumentsContract.Root}.</p>
    ++
    ++<p>Dalam cuplikan berikut, parameter {@code projection} mewakili bidang-bidang
    ++tertentu yang ingin didapatkan kembali oleh pemanggil. Cuplikan ini membuat kursor baru
    ++dan menambahkan satu baris ke satu akar&mdash; kursor, satu direktori level atas, seperti
    ++Downloads atau Images.  Kebanyakan penyedia hanya mempunyai satu akar. Anda bisa mempunyai lebih dari satu,
    ++misalnya, jika ada banyak akun pengguna. Dalam hal itu, cukup tambahkan sebuah
    ++baris kedua ke kursor.</p>
    ++
    ++<pre>
    ++&#64;Override
    ++public Cursor queryRoots(String[] projection) throws FileNotFoundException {
    ++
    ++    // Create a cursor with either the requested fields, or the default
    ++    // projection if "projection" is null.
    ++    final MatrixCursor result =
    ++            new MatrixCursor(resolveRootProjection(projection));
    ++
    ++    // If user is not logged in, return an empty root cursor.  This removes our
    ++    // provider from the list entirely.
    ++    if (!isUserLoggedIn()) {
    ++        return result;
    ++    }
    ++
    ++    // It's possible to have multiple roots (e.g. for multiple accounts in the
    ++    // same app) -- just add multiple cursor rows.
    ++    // Construct one row for a root called &quot;MyCloud&quot;.
    ++    final MatrixCursor.RowBuilder row = result.newRow();
    ++    row.add(Root.COLUMN_ROOT_ID, ROOT);
    ++    row.add(Root.COLUMN_SUMMARY, getContext().getString(R.string.root_summary));
    ++
    ++    // FLAG_SUPPORTS_CREATE means at least one directory under the root supports
    ++    // creating documents. FLAG_SUPPORTS_RECENTS means your application's most
    ++    // recently used documents will show up in the &quot;Recents&quot; category.
    ++    // FLAG_SUPPORTS_SEARCH allows users to search all documents the application
    ++    // shares.
    ++    row.add(Root.COLUMN_FLAGS, Root.FLAG_SUPPORTS_CREATE |
    ++            Root.FLAG_SUPPORTS_RECENTS |
    ++            Root.FLAG_SUPPORTS_SEARCH);
    ++
    ++    // COLUMN_TITLE is the root title (e.g. Gallery, Drive).
    ++    row.add(Root.COLUMN_TITLE, getContext().getString(R.string.title));
    ++
    ++    // This document id cannot change once it's shared.
    ++    row.add(Root.COLUMN_DOCUMENT_ID, getDocIdForFile(mBaseDir));
    ++
    ++    // The child MIME types are used to filter the roots and only present to the
    ++    //  user roots that contain the desired type somewhere in their file hierarchy.
    ++    row.add(Root.COLUMN_MIME_TYPES, getChildMimeTypes(mBaseDir));
    ++    row.add(Root.COLUMN_AVAILABLE_BYTES, mBaseDir.getFreeSpace());
    ++    row.add(Root.COLUMN_ICON, R.drawable.ic_launcher);
    ++
    ++    return result;
    ++}</pre>
    ++
    ++<h4 id="queryChildDocuments">Mengimplementasikan queryChildDocuments</h4>
    ++
    ++<p>Implementasi
    ++{@link android.provider.DocumentsProvider#queryChildDocuments queryChildDocuments()}
    ++oleh Anda harus menghasilkan {@link android.database.Cursor} yang menunjuk ke semua file dalam
    ++direktori yang ditentukan, dengan menggunakan kolom-kolom yang didefinisikan dalam
    ++{@link android.provider.DocumentsContract.Document}.</p>
    ++
    ++<p>Metode ini akan dipanggil bila Anda memilih akar aplikasi dalam picker UI.
    ++Metode mengambil dokumen anak dari direktori di bawah akar.  Metode ini bisa dipanggil pada level apa saja dalam
    ++hierarki file, bukan hanya akar. Cuplikan ini
    ++membuat kursor baru dengan kolom-kolom yang diminta, lalu menambahkan informasi tentang
    ++setiap anak langsung dalam direktori induk ke kursor.
    ++Satu anak bisa berupa gambar, direktori lain&mdash;file apa saja:</p>
    ++
    ++<pre>&#64;Override
    ++public Cursor queryChildDocuments(String parentDocumentId, String[] projection,
    ++                              String sortOrder) throws FileNotFoundException {
    ++
    ++    final MatrixCursor result = new
    ++            MatrixCursor(resolveDocumentProjection(projection));
    ++    final File parent = getFileForDocId(parentDocumentId);
    ++    for (File file : parent.listFiles()) {
    ++        // Adds the file's display name, MIME type, size, and so on.
    ++        includeFile(result, null, file);
    ++    }
    ++    return result;
    ++}
    ++</pre>
    ++
    ++<h4 id="queryDocument">Mengimplementasikan queryDocument</h4>
    ++
    ++<p>Implementasi
    ++{@link android.provider.DocumentsProvider#queryDocument queryDocument()}
    ++oleh Anda harus menghasilkan {@link android.database.Cursor} yang menunjuk ke file yang disebutkan,
    ++dengan menggunakan kolom-kolom yang didefinisikan dalam {@link android.provider.DocumentsContract.Document}.
    ++</p>
    ++
    ++<p>Metode {@link android.provider.DocumentsProvider#queryDocument queryDocument()}
    ++menghasilkan informasi yang sama yang diteruskan dalam
    ++{@link android.provider.DocumentsProvider#queryChildDocuments queryChildDocuments()},
    ++namun untuk file tertentu:</p>
    ++
    ++
    ++<pre>&#64;Override
    ++public Cursor queryDocument(String documentId, String[] projection) throws
    ++        FileNotFoundException {
    ++
    ++    // Create a cursor with the requested projection, or the default projection.
    ++    final MatrixCursor result = new
    ++            MatrixCursor(resolveDocumentProjection(projection));
    ++    includeFile(result, documentId, null);
    ++    return result;
    ++}
    ++</pre>
    ++
    ++<h4 id="openDocument">Mengimplementasikan openDocument</h4>
    ++
    ++<p>Anda harus mengimplementasikan {@link android.provider.DocumentsProvider#openDocument
    ++openDocument()} untuk menghasilkan {@link android.os.ParcelFileDescriptor} yang mewakili
    ++file yang disebutkan. Aplikasi lain bisa menggunakan {@link android.os.ParcelFileDescriptor}
    ++yang dihasilkan untuk mengalirkan data. Sistem memanggil metode ini setelah pengguna memilih file
    ++dan aplikasi klien meminta akses ke file itu dengan memanggil
    ++{@link android.content.ContentResolver#openFileDescriptor openFileDescriptor()}.
    ++Misalnya:</p>
    ++
    ++<pre>&#64;Override
    ++public ParcelFileDescriptor openDocument(final String documentId,
    ++                                         final String mode,
    ++                                         CancellationSignal signal) throws
    ++        FileNotFoundException {
    ++    Log.v(TAG, &quot;openDocument, mode: &quot; + mode);
    ++    // It's OK to do network operations in this method to download the document,
    ++    // as long as you periodically check the CancellationSignal. If you have an
    ++    // extremely large file to transfer from the network, a better solution may
    ++    // be pipes or sockets (see ParcelFileDescriptor for helper methods).
    ++
    ++    final File file = getFileForDocId(documentId);
    ++
    ++    final boolean isWrite = (mode.indexOf('w') != -1);
    ++    if(isWrite) {
    ++        // Attach a close listener if the document is opened in write mode.
    ++        try {
    ++            Handler handler = new Handler(getContext().getMainLooper());
    ++            return ParcelFileDescriptor.open(file, accessMode, handler,
    ++                        new ParcelFileDescriptor.OnCloseListener() {
    ++                &#64;Override
    ++                public void onClose(IOException e) {
    ++
    ++                    // Update the file with the cloud server. The client is done
    ++                    // writing.
    ++                    Log.i(TAG, &quot;A file with id &quot; +
    ++                    documentId + &quot; has been closed!
    ++                    Time to &quot; +
    ++                    &quot;update the server.&quot;);
    ++                }
    ++
    ++            });
    ++        } catch (IOException e) {
    ++            throw new FileNotFoundException(&quot;Failed to open document with id &quot;
    ++            + documentId + &quot; and mode &quot; + mode);
    ++        }
    ++    } else {
    ++        return ParcelFileDescriptor.open(file, accessMode);
    ++    }
    ++}
    ++</pre>
    ++
    ++<h3 id="security">Keamanan</h3>
    ++
    ++<p>Anggaplah penyedia dokumen Anda sebuah layanan penyimpanan cloud yang dilindungi kata sandi
    ++dan Anda ingin memastikan bahwa pengguna sudah login sebelum Anda mulai berbagi file mereka.
    ++Apakah yang harus dilakukan aplikasi Anda jika pengguna tidak login?  Solusinya adalah menghasilkan
    ++akar nol dalam implementasi {@link android.provider.DocumentsProvider#queryRoots
    ++queryRoots()} Anda. Yakni, sebuah kursor akar kosong:</p>
    ++
    ++<pre>
    ++public Cursor queryRoots(String[] projection) throws FileNotFoundException {
    ++...
    ++    // If user is not logged in, return an empty root cursor.  This removes our
    ++    // provider from the list entirely.
    ++    if (!isUserLoggedIn()) {
    ++        return result;
    ++}
    ++</pre>
    ++
    ++<p>Langkah lainnya adalah memanggil {@code getContentResolver().notifyChange()}.
    ++Ingat {@link android.provider.DocumentsContract}?  Kita menggunakannya untuk membuat
    ++URI ini. Cuplikan berikut memberi tahu sistem untuk membuat query akar penyedia dokumen Anda
    ++kapan saja status login pengguna berubah. Jika pengguna tidak
    ++login, panggilan ke {@link android.provider.DocumentsProvider#queryRoots queryRoots()} akan menghasilkan
    ++kursor kosong, seperti yang ditampilkan di atas. Cara ini akan memastikan bahwa dokumen penyedia hanya
    ++tersedia jika pengguna login ke penyedia itu.</p>
    ++
    ++<pre>private void onLoginButtonClick() {
    ++    loginOrLogout();
    ++    getContentResolver().notifyChange(DocumentsContract
    ++            .buildRootsUri(AUTHORITY), null);
    ++}
    ++</pre>
    +\ No newline at end of file
    +diff --git a/docs/html-intl/intl/id/guide/topics/resources/accessing-resources.jd b/docs/html-intl/intl/id/guide/topics/resources/accessing-resources.jd
    +new file mode 100644
    +index 0000000..6774557
    +--- /dev/null
    ++++ b/docs/html-intl/intl/id/guide/topics/resources/accessing-resources.jd
    +@@ -0,0 +1,337 @@
    ++page.title=Mengakses Sumber Daya
    ++parent.title=Sumber Daya Aplikasi
    ++parent.link=index.html
    ++@jd:body
    ++
    ++<div id="qv-wrapper">
    ++<div id="qv">
    ++  <h2>Tampilan Cepat</h2>
    ++  <ul>
    ++    <li>Sumber daya bisa diacu dari kode dengan menggunakan integer dari {@code R.java}, seperti
    ++{@code R.drawable.myimage}</li>
    ++    <li>Sumber daya bisa diacu dari sumber daya dengan menggunakan sintaks XML khusus, seperti {@code
    ++&#64;drawable/myimage}</li>
    ++    <li>Anda juga bisa mengakses sumber daya aplikasi Anda dengan berbagai metode di
    ++{@link android.content.res.Resources}</li>
    ++  </ul>
    ++
    ++  <h2>Kelas-Kelas Utama</h2>
    ++  <ol>
    ++    <li>{@link android.content.res.Resources}</li>
    ++  </ol>
    ++
    ++  <h2>Dalam dokumen ini</h2>
    ++  <ol>
    ++    <li><a href="#ResourcesFromCode">Mengakses Sumber Daya dari Kode</a></li>
    ++    <li><a href="#ResourcesFromXml">Mengakses Sumber Daya dari XML</a>
    ++      <ol>
    ++        <li><a href="#ReferencesToThemeAttributes">Mengacu atribut gaya</a></li>
    ++      </ol>
    ++    </li>
    ++    <li><a href="#PlatformResources">Mengakses Sumber Daya Platform</a></li>
    ++  </ol>
    ++
    ++  <h2>Lihat juga</h2>
    ++  <ol>
    ++    <li><a href="providing-resources.html">Menyediakan Sumber Daya</a></li>
    ++    <li><a href="available-resources.html">Tipe Sumber Daya</a></li>
    ++  </ol>
    ++</div>
    ++</div>
    ++
    ++
    ++
    ++
    ++<p>Setelah Anda menyediakan sumber daya dalam aplikasi Anda (yang dibicarakan di <a href="providing-resources.html">Menyediakan Sumber Daya</a>), Anda bisa menerapkannya dengan
    ++mengacu ID sumber dayanya. Semua ID sumber daya didefinisikan di kelas {@code R} proyek Anda, yang
    ++dihasilkan oleh alat {@code aapt} secara otomatis.</p>
    ++
    ++<p>Bila aplikasi Anda dikompilasi, {@code aapt} akan membuat kelas {@code R}, yang berisi
    ++ID sumber daya untuk semua sumber daya dalam direktori {@code
    ++res/} Anda. Untuk masing-masing tipe sumber daya, ada subkelas {@code R} (misalnya,
    ++{@code R.drawable} untuk semua sumber daya yang bisa ditarik), dan untuk masing-masing sumber daya dari tipe itu, ada satu integer statis
    ++ (misalnya, {@code R.drawable.icon}). Integer ini adalah ID sumber daya yang bisa Anda gunakan
    ++untuk mengambil sumber daya Anda.</p>
    ++
    ++<p>Walaupun kelas {@code R} adalah tempat menyebutkan ID sumber daya, Anda tidak perlu
    ++melihat ke sana untuk menemukan ID sumber daya. ID sumber daya selalu terdiri dari:</p>
    ++<ul>
    ++  <li><em>Tipe sumber daya</em>: Masing-masing sumber daya dikelompokkan menjadi "tipe", misalnya {@code
    ++string}, {@code drawable}, dan {@code layout}. Untuk mengetahui selengkapnya tentang berbagai tipe, lihat <a href="available-resources.html">Tipe Sumber Daya</a>.
    ++  </li>
    ++  <li><em>Nama sumber daya</em>, bisa berupa: nama file,
    ++tidak termasuk ekstensi; atau nilai dalam atribut {@code android:name} XML, jika
    ++sumber daya itu sebuah nilai sederhana (misalnya sebuah string).</li>
    ++</ul>
    ++
    ++<p>Ada dua cara untuk mengakses sumber daya:</p>
    ++<ul>
    ++  <li><strong>Dalam kode:</strong> Menggunakan integer statis dari subkelas dari kelas {@code R}
    ++, misalnya:
    ++    <pre class="classic no-pretty-print">R.string.hello</pre>
    ++    <p>{@code string} adalah tipe sumber daya dan {@code hello} adalah nama sumber daya. Ada banyak
    ++API Android yang bisa mengakses sumber daya Anda bila Anda menyediakan ID sumber daya dengan format ini. Lihat
    ++<a href="#ResourcesFromCode">Mengakses Sumber Daya dalam Kode</a>.</p>
    ++  </li>
    ++  <li><strong>Dalam XML:</strong> Menggunakan sebuah sintaks XML khusus yang juga berkaitan dengan
    ++ID sumber daya yang didefinisikan dalam kelas {@code R}, misalnya:
    ++    <pre class="classic no-pretty-print">&#64;string/hello</pre>
    ++    <p>{@code string} adalah tipe sumber daya dan {@code hello} adalah nama sumber daya. Anda bisa menggunakan
    ++sintaks ini dalam sumber daya XML di mana saja Anda ingin menyediakan sebuah nilai dalam sebuah sumber daya. Lihat <a href="#ResourcesFromXml">Mengakses Sumber Daya dari XML</a>.</p>
    ++  </li>
    ++</ul>
    ++
    ++
    ++
    ++<h2 id="ResourcesFromCode">Mengakses Sumber Daya dalam Kode </h2>
    ++
    ++<p>Anda bisa menggunakan sumber daya dalam kode dengan menyalurkan ID sumber daya sebagai sebuah parameter metode. Misalnya,
    ++ Anda bisa mengatur sebuah {@link android.widget.ImageView} agar menggunakan sumber daya{@code res/drawable/myimage.png}
    ++dengan menggunakan {@link android.widget.ImageView#setImageResource(int) setImageResource()}:</p>
    ++<pre>
    ++ImageView imageView = (ImageView) findViewById(R.id.myimageview);
    ++imageView.setImageResource(<strong>R.drawable.myimage</strong>);
    ++</pre>
    ++
    ++<p>Anda juga bisa mengambil tiap sumber daya dengan menggunakan berbagai metode di {@link
    ++android.content.res.Resources}, di mana Anda bisa mendapatkan instance
    ++ {@link android.content.Context#getResources()}.</p>
    ++
    ++<div class="sidebox-wrapper">
    ++<div class="sidebox">
    ++<h2>Akses ke File Asli</h2>
    ++
    ++<p>Walaupun tidak lazim, Anda mungkin perlu mengakses file dan direktori asli Anda. Jika demikian, maka
    ++menyimpan file Anda di {@code res/} tidak akan berhasil, karena satu-satunya cara untuk membaca sebuah sumber daya dari
    ++{@code res/} adalah dengan ID sumber daya. Sebagai gantinya, Anda bisa menyimpan sumber daya dalam direktori
    ++{@code assets/}.</p>
    ++<p>File yang tersimpan di direktori {@code assets/} <em>tidak</em> diberi ID
    ++sumber daya, sehingga Anda tidak bisa mengacunya melalui kelas {@code R} atau dari sumber daya XML. Sebagai gantinya, Anda bisa melakukan
    ++query file di direktori {@code assets/} seperti sebuah sistem file biasa dan membaca data mentah dengan menggunakan
    ++{@link android.content.res.AssetManager}.</p>
    ++<p>Akan tetapi, jika yang Anda butuhkan hanya kemampuan membaca data mentah (misalnya sebuah file video atau audio),
    ++maka simpanlah file itu di direktori {@code res/raw/} dan baca aliran byte dengan menggunakan {@link
    ++android.content.res.Resources#openRawResource(int) openRawResource()}.</p>
    ++
    ++</div>
    ++</div>
    ++
    ++
    ++<h3>Sintaks</h3>
    ++
    ++<p>Inilah sintaks untuk mengacu sumber daya dalam kode:</p>
    ++
    ++<pre class="classic no-pretty-print">
    ++[<em>&lt;package_name&gt;</em>.]R.<em>&lt;resource_type&gt;</em>.<em>&lt;resource_name&gt;</em>
    ++</pre>
    ++
    ++<ul>
    ++  <li><em> {@code &lt;package_name&gt;}</em>adalah nama paket yang di dalamnya terdapat sumber daya (tidak
    ++dibutuhkan bila mengacu sumber daya dari paket Anda sendiri).</li>
    ++  <li><em>{@code &lt;resource_type&gt;}</em> adalah subkelas {@code R} untuk tipe sumber daya.</li>
    ++  <li><em>{@code &lt;resource_name&gt;}</em> bisa berupa nama file sumber daya
    ++tanpa ekstensi atau nilai atribut {@code android:name} dalam elemen XML (untuk nilai
    ++sederhana).</li>
    ++</ul>
    ++<p>Lihat <a href="available-resources.html">Tipe Sumber Daya</a> untuk
    ++informasi selengkapnya tentang masing-masing tipe sumber daya dan cara mengacunya.</p>
    ++
    ++
    ++<h3>Kasus penggunaan</h3>
    ++
    ++<p>Ada banyak metode yang menerima parameter ID sumber daya dan Anda bisa mengambil sumber daya dengan menggunakan
    ++metode di {@link android.content.res.Resources}. Anda bisa mengambil instance {@link
    ++android.content.res.Resources} dengan {@link android.content.Context#getResources
    ++Context.getResources()}.</p>
    ++
    ++
    ++<p>Berikut adalah beberapa contoh cara mengakses sumber daya dalam kode:</p>
    ++
    ++<pre>
    ++// Load a background for the current screen from a drawable resource
    ++{@link android.app.Activity#getWindow()}.{@link
    ++android.view.Window#setBackgroundDrawableResource(int)
    ++setBackgroundDrawableResource}(<strong>R.drawable.my_background_image</strong>) ;
    ++
    ++// Set the Activity title by getting a string from the Resources object, because
    ++//  this method requires a CharSequence rather than a resource ID
    ++{@link android.app.Activity#getWindow()}.{@link android.view.Window#setTitle(CharSequence)
    ++setTitle}(getResources().{@link android.content.res.Resources#getText(int)
    ++getText}(<strong>R.string.main_title</strong>));
    ++
    ++// Load a custom layout for the current screen
    ++{@link android.app.Activity#setContentView(int)
    ++setContentView}(<strong>R.layout.main_screen</strong>);
    ++
    ++// Set a slide in animation by getting an Animation from the Resources object
    ++mFlipper.{@link android.widget.ViewAnimator#setInAnimation(Animation)
    ++setInAnimation}(AnimationUtils.loadAnimation(this,
    ++        <strong>R.anim.hyperspace_in</strong>));
    ++
    ++// Set the text on a TextView object using a resource ID
    ++TextView msgTextView = (TextView) findViewById(<strong>R.id.msg</strong>);
    ++msgTextView.{@link android.widget.TextView#setText(int)
    ++setText}(<strong>R.string.hello_message</strong>);
    ++</pre>
    ++
    ++
    ++<p class="caution"><strong>Perhatian:</strong> Anda tidak boleh memodifikasi file {@code
    ++R.java} secara manual&mdash;, ini dihasilkan oleh alat {@code aapt} bila proyek Anda telah
    ++dikompilasi. Perubahan apa pun akan ditimpa bila nanti Anda mengompilasi.</p>
    ++
    ++
    ++
    ++<h2 id="ResourcesFromXml">Mengakses Sumber Daya dari XML</h2>
    ++
    ++<p>Anda bisa mendefinisikan nilai untuk beberapa atribut dan elemen XML dengan menggunakan
    ++acuan ke sumber daya yang ada. Anda akan sering melakukannya saat membuat file layout, untuk
    ++memasok string dan gambar bagi widget Anda.</p>
    ++
    ++<p>Misalnya, jika Anda menambahkan sebuah {@link android.widget.Button} ke layout, Anda harus menggunakan
    ++sebuah <a href="string-resource.html">sumber daya string</a> bagi teks tombolnya:</p>
    ++
    ++<pre>
    ++&lt;Button
    ++    android:layout_width="fill_parent"
    ++    android:layout_height="wrap_content"
    ++    android:text="<strong>@string/submit</strong>" /&gt;
    ++</pre>
    ++
    ++
    ++<h3>Sintaks</h3>
    ++
    ++<p>Berikut adalah sintaks untuk mengacu sumber daya di sumber daya XML:</p>
    ++
    ++<pre class="classic no-pretty-print">
    ++&#64;[<em>&lt;package_name&gt;</em>:]<em>&lt;resource_type&gt;</em>/<em>&lt;resource_name&gt;</em>
    ++</pre>
    ++
    ++<ul>
    ++  <li>{@code &lt;package_name&gt;} adalah nama paket yang di dalamnya terdapat sumber daya (tidak
    ++dibutuhkan bila mengacu sumber daya dari paket yang sama)</li>
    ++  <li>{@code &lt;resource_type&gt;} adalah subkelas
    ++{@code R} untuk tipe sumber daya</li>
    ++  <li>{@code &lt;resource_name&gt;} bisa berupa nama file sumber daya
    ++tanpa ekstensi atau nilai atribut {@code android:name} dalam elemen XML (untuk nilai
    ++sederhana).</li>
    ++</ul>
    ++
    ++<p>Lihat <a href="available-resources.html">Tipe Sumber Daya</a> untuk
    ++informasi selengkapnya tentang masing-masing tipe sumber daya dan cara mengacunya.</p>
    ++
    ++
    ++<h3>Kasus penggunaan</h3>
    ++
    ++<p>Dalam beberapa kasus, Anda harus menggunakan sumber daya untuk suatu nilai dalam XML (misalnya, untuk menerapkan gambar yang bisa ditarik
    ++pada widget), namun Anda juga bisa menggunakan sumber daya di XML mana saja yang menerima nilai sederhana. Misalnya, jika
    ++Anda mempunyai file sumber daya berikut yang berisi <a href="more-resources.html#Color">sumber daya warna</a> dan <a href="string-resource.html">sumber daya string</a>:</p>
    ++
    ++<pre>
    ++&lt;?xml version="1.0" encoding="utf-8"?>
    ++&lt;resources>
    ++   &lt;color name="opaque_red">#f00&lt;/color>
    ++   &lt;string name="hello">Hello!&lt;/string>
    ++&lt;/resources>
    ++</pre>
    ++
    ++<p>Anda bisa menggunakan sumber daya ini dalam file layout berikut untuk mengatur warna teks dan
    ++string teks:</p>
    ++
    ++<pre>
    ++&lt;?xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot;?&gt;
    ++&lt;EditText xmlns:android=&quot;http://schemas.android.com/apk/res/android&quot;
    ++    android:layout_width=&quot;fill_parent&quot;
    ++    android:layout_height=&quot;fill_parent&quot;
    ++    android:textColor=&quot;<strong>&#64;color/opaque_red</strong>&quot;
    ++    android:text=&quot;<strong>&#64;string/hello</strong>&quot; /&gt;
    ++</pre>
    ++
    ++<p>Dalam hal ini, Anda tidak perlu menyebutkan nama paket dalam sumber daya acuan karena
    ++sumber daya berasal dari paket Anda sendiri. Untuk
    ++mengacu sumber daya sistem, Anda perlu memasukkan nama paketnya. Misalnya:</p>
    ++
    ++<pre>
    ++&lt;?xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot;?&gt;
    ++&lt;EditText xmlns:android=&quot;http://schemas.android.com/apk/res/android&quot;
    ++    android:layout_width=&quot;fill_parent&quot;
    ++    android:layout_height=&quot;fill_parent&quot;
    ++    android:textColor=&quot;<strong>&#64;android:color/secondary_text_dark</strong>&quot;
    ++    android:text=&quot;&#64;string/hello&quot; /&gt;
    ++</pre>
    ++
    ++<p class="note"><strong>Catatan:</strong> Anda harus menggunakan sumber daya string sepanjang
    ++waktu, sehingga aplikasi Anda bisa dilokalkan untuk bahasa lain.
    ++Untuk informasi tentang cara menciptakan
    ++sumber daya alternatif (seperti string lokal), lihat <a href="providing-resources.html#AlternativeResources">Menyediakan Sumber Daya Alternatif
    ++</a>. Untuk panduan lengkap melokalkan aplikasi Anda ke bahasa lain,
    ++lihat <a href="localization.html">Pelokalan</a>.</p>
    ++
    ++<p>Anda bahkan bisa menggunakan sumber daya dalam XML untuk membuat alias. Misalnya, Anda bisa membuat
    ++sumber daya yang bisa ditarik yang merupakan alias bagi sumber daya yang bisa ditarik lainnya:</p>
    ++
    ++<pre>
    ++&lt;?xml version="1.0" encoding="utf-8"?>
    ++&lt;bitmap xmlns:android="http://schemas.android.com/apk/res/android"
    ++    android:src="@drawable/other_drawable" />
    ++</pre>
    ++
    ++<p>Hal ini terdengar berlebihan, namun bisa sangat berguna saat menggunakan sumber daya alternatif. Baca selengkapnya tentang
    ++<a href="providing-resources.html#AliasResources">Membuat sumber daya alias</a>.</p>
    ++
    ++
    ++
    ++<h3 id="ReferencesToThemeAttributes">Mengacu atribut gaya</h3>
    ++
    ++<p>Sumber daya atribut gaya memungkinkan Anda mengacu nilai
    ++suatu atribut dalam tema yang diterapkan saat ini. Dengan mengacu sebuah atribut gaya memungkinkan Anda
    ++menyesuaikan tampilan elemen UI dengan mengatur gayanya agar cocok dengan beragam variasi standar yang dipasok oleh
    ++tema saat ini, sebagai ganti memasok nilai yang ditanamkan (hard-coded). Mengacu sebuah atribut gaya
    ++pada dasarnya adalah "gunakan gaya yang didefinisikan oleh atribut ini, dalam tema saat ini".</p>
    ++
    ++<p>Untuk mengacu sebuah atribut gaya, sintaks namanya hampir sama dengan format sumber daya normal
    ++, namun sebagai ganti simbol @ ({@code @}), gunakan sebuah tanda tanya ({@code ?}), dan
    ++porsi tipe sumber daya bersifat opsional. Sebagai contoh:</p>
    ++
    ++<pre class="classic">
    ++?[<em>&lt;package_name&gt;</em>:][<em>&lt;resource_type&gt;</em>/]<em>&lt;resource_name&gt;</em>
    ++</pre>
    ++
    ++<p>Misalnya, begini cara Anda mengacu suatu atribut untuk mengatur warna teks agar cocok dengan
    ++warna teks "utama" tema sistem:</p>
    ++
    ++<pre>
    ++&lt;EditText id=&quot;text&quot;
    ++    android:layout_width=&quot;fill_parent&quot;
    ++    android:layout_height=&quot;wrap_content&quot;
    ++    android:textColor=&quot;<strong>?android:textColorSecondary</strong>&quot;
    ++    android:text=&quot;&#64;string/hello_world&quot; /&gt;
    ++</pre>
    ++
    ++<p>Di sini, atribut {@code android:textColor} menyebutkan nama atribut gaya
    ++dalam tema saat ini. Android kini menggunakan nilai yang diterapkan pada atribut gaya {@code android:textColorSecondary}
    ++sebagai nilai untuk {@code android:textColor} dalam widget ini. Karena alat sumber daya
    ++mengetahui bahwa atribut sumber daya diharapkan dalam konteks ini,
    ++maka Anda tidak perlu menyatakan tipenyanya secara eksplisit (yang akan berupa
    ++<code>?android:attr/textColorSecondary</code>)&mdash;Anda bisa mengecualikan tipe {@code attr}.</p>
    ++
    ++
    ++
    ++
    ++<h2 id="PlatformResources">Mengakses Sumber Daya Platform</h2>
    ++
    ++<p>Android berisi sejumlah sumber daya standar, seperti gaya, tema, dan layout. Untuk
    ++mengakses semua sumber daya ini, tetapkan acuan sumber daya Anda dengan nama paket
    ++<code>android</code>. Misalnya, Android menyediakan sumber daya layout yang bisa Anda gunakan untuk
    ++item daftar dalam{@link android.widget.ListAdapter}:</p>
    ++
    ++<pre>
    ++{@link android.app.ListActivity#setListAdapter(ListAdapter)
    ++setListAdapter}(new {@link
    ++android.widget.ArrayAdapter}&lt;String&gt;(this, <strong>android.R.layout.simple_list_item_1</strong>, myarray));
    ++</pre>
    ++
    ++<p>Dalam contoh ini, {@link android.R.layout#simple_list_item_1} adalah sumber daya layout yang didefinisikan oleh
    ++platform untuk item di {@link android.widget.ListView}. Anda bisa menggunakannya sebagai ganti menciptakan
    ++layout sendiri untuk item daftar. Untuk informasi selengkapnya, lihat panduan pengembang
    ++<a href="{@docRoot}guide/topics/ui/layout/listview.html">List View</a>.</p>
    ++
    +diff --git a/docs/html-intl/intl/id/guide/topics/resources/overview.jd b/docs/html-intl/intl/id/guide/topics/resources/overview.jd
    +new file mode 100644
    +index 0000000..def4932
    +--- /dev/null
    ++++ b/docs/html-intl/intl/id/guide/topics/resources/overview.jd
    +@@ -0,0 +1,103 @@
    ++page.title=Ikhtisar Sumber Daya
    ++@jd:body
    ++
    ++<div id="qv-wrapper">
    ++<div id="qv">
    ++  <h2>Topik</h2>
    ++  <ol>
    ++    <li><a href="providing-resources.html">Menyediakan Sumber Daya</a></li>
    ++    <li><a href="accessing-resources.html">Mengakses Sumber Daya</a></li>
    ++    <li><a href="runtime-changes.html">Menangani Perubahan Runtime</a></li>
    ++    <li><a href="localization.html">Pelokalan</a></li>
    ++  </ol>
    ++
    ++  <h2>Acuan</h2>
    ++  <ol>
    ++    <li><a href="available-resources.html">Tipe Sumber Daya</a></li>
    ++  </ol>
    ++</div>
    ++</div>
    ++
    ++
    ++<p>Anda harus selalu mengeksternalkan sumber daya seperti gambar dan string dari kode
    ++aplikasi, agar Anda bisa memeliharanya secara independen. Mengeksternalkan
    ++sumber daya juga membuat Anda dapat menyediakan sumber daya alternatif yang mendukung konfigurasi
    ++perangkat tertentu seperti bahasa atau ukuran layar yang berbeda, yang semakin penting
    ++seiring semakin banyak tersedianya perangkat berbasis Android dengan konfigurasi berbeda. Untuk
    ++memberikan kompatibilitas dengan konfigurasi berbeda, Anda harus menata sumber daya dalam
    ++direktori {@code res/} proyek Anda, menggunakan berbagai subdirektori yang mengelompokkan sumber daya menurut tipe
    ++dan konfigurasinya.</p>
    ++
    ++<div class="figure" style="width:429px">
    ++<img src="{@docRoot}images/resources/resource_devices_diagram1.png" height="167" alt="" />
    ++<p class="img-caption">
    ++<strong>Gambar 1.</strong> Dua perangkat berbeda, masing-masing menggunakan layout default
    ++(aplikasi tidak menyediakan layout alternatif).</p>
    ++</div>
    ++
    ++<div class="figure" style="width:429px">
    ++<img src="{@docRoot}images/resources/resource_devices_diagram2.png" height="167" alt="" />
    ++<p class="img-caption">
    ++<strong>Gambar 2.</strong> Dua perangkat berbeda, masing-masing menggunakan layout berbeda yang tersedia untuk
    ++ukuran layar berbeda.</p>
    ++</div>
    ++
    ++<p>Bagi setiap tipe sumber daya, Anda bisa menetapkan sumber daya <em>default</em> dan sumber daya
    ++<em>alternatif</em> untuk aplikasi Anda:</p>
    ++<ul>
    ++  <li>Sumber daya default adalah sumber daya yang harus digunakan apa pun
    ++konfigurasi perangkatnya atau jika tidak ada sumber daya alternatif yang sesuai
    ++dengan konfigurasi saat ini.</li>
    ++  <li>Sumber daya alternatif adalah sumber daya yang Anda desain untuk digunakan dengan
    ++konfigurasi tertentu. Untuk menetapkan bahwa satu kelompok sumber daya ditujukan bagi konfigurasi tertentu,
    ++tambahkan qualifier konfigurasi yang sesuai ke nama direktori.</li>
    ++</ul>
    ++
    ++<p>Misalnya, walaupun layout
    ++UI default Anda disimpan dalam direktori {@code res/layout/}, Anda dapat menetapkan layout berbeda
    ++untuk digunakan saat layar dalam orientasi lanskap, dengan menyimpannya dalam direktori {@code res/layout-land/}
    ++. Android secara otomatis memberlakukan sumber daya yang sesuai dengan mencocokkan konfigurasi perangkat
    ++saat ini dengan nama direktori sumber daya.</p>
    ++
    ++<p>Gambar 1 mengilustrasikan cara sistem memberlakukan layout yang sama untuk
    ++dua perangkat berbeda saat sumber daya alternatif tidak tersedia. Gambar 2 menunjukkan
    ++aplikasi yang sama saat menambahkan sumber daya layout alternatif untuk layar yang lebih besar.</p>
    ++
    ++<p>Dokumen-dokumen berikut berisi panduan lengkap mengenai cara menata sumber daya aplikasi,
    ++menetapkan sumber daya alternatif, mengaksesnya dalam aplikasi, dan banyak lagi:</p>
    ++
    ++<dl>
    ++  <dt><strong><a href="providing-resources.html">Menyediakan Sumber Daya</a></strong></dt>
    ++  <dd>Jenis sumber daya yang dapat Anda sediakan dalam aplikasi, tempat menyimpannya, dan cara membuat sumber daya
    ++alternatif untuk konfigurasi perangkat tertentu.</dd>
    ++  <dt><strong><a href="accessing-resources.html">Mengakses Sumber Daya</a></strong></dt>
    ++  <dd>Cara menggunakan sumber daya yang telah Anda sediakan, baik dengan mengacunya dari kode
    ++aplikasi Anda atau dari sumber daya XML lainnya.</dd>
    ++  <dt><strong><a href="runtime-changes.html">Menangani Perubahan Runtime</a></strong></dt>
    ++  <dd>Cara mengelola perubahan konfigurasi yang terjadi saat Aktivitas Anda berjalan.</dd>
    ++  <dt><strong><a href="localization.html">Pelokalan</a></strong></dt>
    ++  <dd>Panduan dari pengalaman untuk melokalkan aplikasi menggunakan sumber daya alternatif. Walaupun ini
    ++hanya satu penggunaan tertentu dari sumber daya alternatif, hal ini sangat penting dalam meraih pengguna lebih
    ++banyak.</dd>
    ++  <dt><strong><a href="available-resources.html">Tipe Sumber Daya</a></strong></dt>
    ++  <dd>Acuan dari berbagai tipe sumber daya yang dapat Anda sediakan, menjelaskan elemen-elemen XML,
    ++atribut, dan sintaksnya. Misalnya, acuan ini menunjukkan kepada Anda cara membuat sumber daya untuk
    ++menu aplikasi, drawable, animasi, dan lainnya.</dd>
    ++</dl>
    ++
    ++<!--
    ++<h2>Raw Assets</h2>
    ++
    ++<p>An alternative to saving files in {@code res/} is to save files in the {@code
    ++assets/} directory. This should only be necessary if you need direct access to original files and
    ++directories by name. Files saved in the {@code assets/} directory will not be given a resource
    ++ID, so you can't reference them through the {@code R} class or from XML resources. Instead, you can
    ++query data in the {@code assets/} directory like an ordinary file system, search through the
    ++directory and
    ++read raw data using {@link android.content.res.AssetManager}. For example, this can be more useful
    ++when dealing with textures for a game. However, if you only need to read raw data from a file
    ++(such as a video or audio file), then you should save files into the {@code res/raw/} directory and
    ++then read a stream of bytes using {@link android.content.res.Resources#openRawResource(int)}. This
    ++is uncommon, but if you need direct access to original files in {@code assets/}, refer to the {@link
    ++android.content.res.AssetManager} documentation.</p>
    ++-->
    +diff --git a/docs/html-intl/intl/id/guide/topics/resources/providing-resources.jd b/docs/html-intl/intl/id/guide/topics/resources/providing-resources.jd
    +new file mode 100644
    +index 0000000..9bccd24
    +--- /dev/null
    ++++ b/docs/html-intl/intl/id/guide/topics/resources/providing-resources.jd
    +@@ -0,0 +1,1094 @@
    ++page.title=Menyediakan Sumber Daya
    ++parent.title=Sumber Daya Aplikasi
    ++parent.link=index.html
    ++@jd:body
    ++
    ++<div id="qv-wrapper">
    ++<div id="qv">
    ++  <h2>Tampilan Cepat</h2>
    ++  <ul>
    ++    <li>Berbagai tipe sumber daya termasuk dalam subdirektori {@code res/}</li>
    ++    <li>Sumber daya alternatif menyediakan file sumber daya dengan konfigurasi tertentu</li>
    ++    <li>Sertakan selalu sumber daya default agar aplikasi Anda tidak bergantung pada
    ++konfigurasi perangkat tertentu</li>
    ++  </ul>
    ++  <h2>Dalam dokumen ini</h2>
    ++  <ol>
    ++    <li><a href="#ResourceTypes">Mengelompokkan Tipe Sumber Daya</a></li>
    ++    <li><a href="#AlternativeResources">Menyediakan Sumber Daya Alternatif</a>
    ++      <ol>
    ++        <li><a href="#QualifierRules">Aturan penamaan qualifier</a></li>
    ++        <li><a href="#AliasResources">Membuat sumber daya alias</a></li>
    ++      </ol>
    ++    </li>
    ++    <li><a href="#Compatibility">Menyediakan Kompatibilitas Perangkat Terbaik dengan Sumber Daya</a></li>
    ++    <li><a href="#BestMatch">Cara Android Menemukan Sumber Daya yang Paling Cocok</a></li>
    ++  </ol>
    ++
    ++  <h2>Lihat juga</h2>
    ++  <ol>
    ++    <li><a href="accessing-resources.html">Mengakses Sumber Daya</a></li>
    ++    <li><a href="available-resources.html">Tipe Sumber Daya</a></li>
    ++    <li><a href="{@docRoot}guide/practices/screens_support.html">Mendukung Beberapa
    ++Layar</a></li>
    ++  </ol>
    ++</div>
    ++</div>
    ++
    ++<p>Anda harus selalu mengeksternalkan sumber daya aplikasi seperti gambar dan string dari kode
    ++, agar Anda bisa memeliharanya secara independen. Anda juga harus menyediakan sumber daya alternatif untuk
    ++konfigurasi perangkat tertentu, dengan mengelompokkannya dalam direktori sumber daya bernama khusus. Saat
    ++runtime, Android menggunakan sumber daya yang sesuai berdasarkan konfigurasi saat ini. Misalnya, Anda mungkin
    ++ingin menyediakan layout UI berbeda bergantung pada ukuran layar atau string berbeda bergantung pada
    ++pengaturan bahasa.</p>
    ++
    ++<p>Setelah mengeksternalkan sumber daya aplikasi, Anda dapat mengaksesnya menggunakan
    ++ID sumber daya yang dibuat dalam kelas {@code R} proyek Anda. Cara menggunakan
    ++sumber daya dalam aplikasi dibahas dalam <a href="accessing-resources.html">Mengakses
    ++Sumber Daya</a>. Dokumen ini menampilkan cara mengelompokkan sumber daya
    ++dalam proyek Android Anda dan menyediakan sumber daya alternatif untuk konfigurasi perangkat tertentu.</p>
    ++
    ++
    ++<h2 id="ResourceTypes">Mengelompokkan Tipe Sumber Daya</h2>
    ++
    ++<p>Anda harus menempatkan setiap tipe sumber daya dalam subdirektori spesifik pada direktori
    ++{@code res/} proyek. Misalnya, inilah hierarki file untuk proyek sederhana:</p>
    ++
    ++<pre class="classic no-pretty-print">
    ++MyProject/
    ++    src/  <span style="color:black">
    ++        MyActivity.java  </span>
    ++    res/
    ++        drawable/  <span style="color:black">
    ++            graphic.png  </span>
    ++        layout/  <span style="color:black">
    ++            main.xml
    ++            info.xml</span>
    ++        mipmap/  <span style="color:black">
    ++            icon.png </span>
    ++        values/  <span style="color:black">
    ++            strings.xml  </span>
    ++</pre>
    ++
    ++<p>Seperti yang Anda lihat dalam contoh ini, direktori {@code res/} berisi semua sumber daya (dalam
    ++subdirektori): sumber daya gambar, dua sumber daya layout, direktori {@code mipmap/} untuk ikon
    ++launcher, dan satu file sumber daya string. Nama direktori
    ++sumber daya penting dan dijelaskan dalam tabel 1.</p>
    ++
    ++<p class="note"><strong>Catatan:</strong> Untuk informasi selengkapnya tentang menggunakan folder mipmap, lihat
    ++<a href="{@docRoot}tools/projects/index.html#mipmap">Mengelola Ikhtisar Proyek</a>.</p>
    ++
    ++<p class="table-caption" id="table1"><strong>Tabel 1.</strong> Direktori sumber daya
    ++didukung dalam direktori proyek {@code res/}.</p>
    ++
    ++<table>
    ++  <tr>
    ++    <th scope="col">Direktori</th>
    ++    <th scope="col">Tipe Sumber Daya</th>
    ++  </tr>
    ++
    ++  <tr>
    ++    <td><code>animator/</code></td>
    ++    <td>File XML yang mendefinisikan <a href="{@docRoot}guide/topics/graphics/prop-animation.html">animasi
    ++properti</a>.</td>
    ++  </tr>
    ++
    ++  <tr>
    ++    <td><code>anim/</code></td>
    ++    <td>File XML yang mendefinisikan <a href="{@docRoot}guide/topics/graphics/view-animation.html#tween-animation">animasi
    ++tween</a>. (Animasi properti juga dapat disimpan dalam direktori ini, namun
    ++direktori {@code animator/} lebih disukai bagi animasi properti agar kedua tipe
    ++ini dapat dibedakan.)</td>
    ++  </tr>
    ++
    ++  <tr>
    ++    <td><code>color/</code></td>
    ++    <td>File XML yang mendefinisikan daftar status warna. Lihat <a href="color-list-resource.html">Sumber Daya
    ++Daftar Status Warna</a></td>
    ++  </tr>
    ++
    ++  <tr>
    ++    <td><code>drawable/</code></td>
    ++
    ++    <td><p>File bitmap ({@code .png}, {@code .9.png}, {@code .jpg}, {@code .gif}) atau file XML yang
    ++dikompilasi menjadi subtipe sumber daya drawable berikut:</p>
    ++      <ul>
    ++        <li>File bitmap</li>
    ++        <li>Nine-Patches (bitmap yang dapat diubah ukurannya)</li>
    ++        <li>Daftar status</li>
    ++        <li>Bentuk</li>
    ++        <li>Drawable animasi</li>
    ++        <li>Drawable lainnya</li>
    ++      </ul>
    ++      <p>Lihat <a href="drawable-resource.html">Sumber Daya Drawable</a>.</p>
    ++    </td>
    ++  </tr>
    ++
    ++  <tr>
    ++    <td><code>mipmap/</code></td>
    ++    <td>File drawable untuk densitas ikon launcher yang berbeda. Untuk informasi selengkapnya tentang
    ++ mengelola ikon launcher dengan folder {@code mipmap/}, lihat
    ++<a href="{@docRoot}tools/project/index.html#mipmap">Mengelola Ikhtisar Proyek</a>.</td>
    ++  </tr>
    ++
    ++  <tr>
    ++    <td><code>layout/</code></td>
    ++    <td>File XML yang mendefinisikan layout antarmuka pengguna.
    ++        Lihat <a href="layout-resource.html">Sumber Daya Layout</a>.</td>
    ++  </tr>
    ++
    ++  <tr>
    ++    <td><code>menu/</code></td>
    ++    <td>File XML yang mendefinisikan menu aplikasi, seperti Menu Opsi, Menu Konteks, atau Sub
    ++Menu. Lihat <a href="menu-resource.html">Sumber Daya Menu</a>.</td>
    ++  </tr>
    ++
    ++  <tr>
    ++    <td><code>raw/</code></td>
    ++    <td><p>File tak didukung yang akan disimpan dalam bentuk mentah. Untuk membuka sumber daya ini dengan
    ++{@link java.io.InputStream} mentah, panggil {@link android.content.res.Resources#openRawResource(int)
    ++Resources.openRawResource()} dengan ID sumber daya, yaitu {@code R.raw.<em>filename</em>}.</p>
    ++      <p>Akan tetapi, jika Anda butuh akses ke nama file asli dan hierarki file, Anda bisa mempertimbangkan
    ++untuk menyimpan beberapa sumber daya dalam direktori {@code
    ++assets/} (sebagai ganti {@code res/raw/}). File dalam {@code assets/} tidak diberi
    ++ID sumber daya, jadi Anda bisa membacanya hanya dengan menggunakan {@link android.content.res.AssetManager}.</p></td>
    ++  </tr>
    ++
    ++  <tr>
    ++    <td><code>values/</code></td>
    ++    <td><p>File XML yang berisi nilai-nilai sederhana, seperti string, integer, dan warna.</p>
    ++      <p>Walaupun file sumber daya XML dalam subdirektori {@code res/} lainnya mendefinisikan satu sumber daya
    ++berdasarkan nama file XML, file dalam direktori {@code values/} menggambarkan beberapa sumber daya.
    ++Untuk file dalam direktori ini, setiap anak elemen {@code &lt;resources&gt;} mendefinisikan satu sumber
    ++daya. Misalnya, elemen {@code &lt;string&gt;} membuat sumber daya
    ++{@code R.string} dan elemen {@code &lt;color&gt;} membuat sumber daya {@code R.color}
    ++.</p>
    ++      <p>Karena setiap sumber daya didefinisikan dengan elemen XML-nya sendiri, Anda bisa bebas menamai file
    ++ini dan menempatkan tipe sumber daya berbeda dalam satu file. Akan tetapi, agar jelas, Anda mungkin
    ++perlu menempatkan tipe sumber daya unik dalam file berbeda. Misalnya, berikut ini adalah beberapa ketentuan
    ++penamaan file untuk sumber daya yang dapat Anda buat dalam direktori ini:</p>
    ++      <ul>
    ++        <li>arrays.xml untuk larik sumber daya tipe (<a href="more-resources.html#TypedArray">larik bertipe</a>).</li>
    ++        <li>colors.xml untuk <a href="more-resources.html#Color">nilai warna</a></li>
    ++        <li>dimens.xml untuk <a href="more-resources.html#Dimension">nilai dimensi</a>.</li>
    ++        <li>strings.xml untuk <a href="string-resource.html">nilai
    ++string</a>.</li>
    ++        <li>styles.xml untuk <a href="style-resource.html">gaya</a>.</li>
    ++      </ul>
    ++      <p>Lihat <a href="string-resource.html">Sumber Daya String</a>,
    ++        <a href="style-resource.html">Sumber Daya Gaya</a>, dan
    ++        <a href="more-resources.html">Tipe Sumber Daya Lainnya</a>.</p>
    ++    </td>
    ++  </tr>
    ++
    ++  <tr>
    ++    <td><code>xml/</code></td>
    ++    <td>File XML tak didukung yang bisa dibaca saat runtime dengan memanggil {@link
    ++android.content.res.Resources#getXml(int) Resources.getXML()}. Berbagai file konfigurasi XML
    ++harus disimpan di sini, seperti <a href="{@docRoot}guide/topics/search/searchable-config.html">konfigurasi yang dapat dicari</a>.
    ++<!-- or preferences configuration. --></td>
    ++  </tr>
    ++</table>
    ++
    ++<p class="caution"><strong>Perhatian:</strong> Jangan menyimpan file sumber daya secara langsung dalam
    ++direktori {@code res/}&mdash; karena akan menyebabkan kesalahan compiler.</p>
    ++
    ++<p>Untuk informasi selengkapnya tentang tipe sumber daya tertentu, lihat dokumentasi <a href="available-resources.html">Tipe Sumber Daya</a>.</p>
    ++
    ++<p>Sumber daya yang disimpan dalam subdirektori yang didefinisikan dalam tabel 1 adalah sumber daya
    ++"default" Anda. Berarti sumber daya ini mendefinisikan desain default dan konten untuk aplikasi Anda.
    ++Akan tetapi, beberapa tipe perangkat berbasis Android mungkin memanggil tipe sumber daya yang berbeda.
    ++Misalnya, jika perangkat memiliki layar yang lebih besar daripada layar normal, maka Anda harus
    ++menyediakan sumber daya layout berbeda yang memanfaatkan ruang layar yang lebih besar. Atau, jika perangkat
    ++memiliki pengaturan bahasa berbeda, maka Anda harus menyediakan sumber daya string berbeda yang menerjemahkan teks dalam
    ++antarmuka pengguna Anda. Untuk menyediakan sumber daya berbeda ini bagi
    ++konfigurasi perangkat yang berbeda, Anda harus menyediakan sumber daya alternatif, selain sumber
    ++daya default.</p>
    ++
    ++
    ++<h2 id="AlternativeResources">Menyediakan Sumber Daya Alternatif</h2>
    ++
    ++
    ++<div class="figure" style="width:429px">
    ++<img src="{@docRoot}images/resources/resource_devices_diagram2.png" height="167" alt="" />
    ++<p class="img-caption">
    ++<strong>Gambar 1.</strong> Dua perangkat berbeda, masing-masing menggunakan sumber daya layout berbeda.</p>
    ++</div>
    ++
    ++<p>Hampir setiap aplikasi harus menyediakan sumber daya alternatif untuk mendukung konfigurasi
    ++perangkat tertentu. Misalnya, Anda harus menyertakan sumber daya drawable alternatif untuk densitas layar
    ++berbeda dan sumber daya string alternatif untuk bahasa yang berbeda. Saat runtime, Android
    ++akan mendeteksi konfigurasi perangkat aktif dan memuat
    ++sumber daya yang sesuai untuk aplikasi Anda.</p>
    ++
    ++<p>Untuk menyebutkan alternatif konfigurasi tertentu untuk satu set sumber daya:</p>
    ++<ol>
    ++  <li>Buat direktori baru dalam {@code res/} yang dinamai dalam bentuk {@code
    ++<em>&lt;resources_name&gt;</em>-<em>&lt;config_qualifier&gt;</em>}.
    ++    <ul>
    ++      <li><em>{@code &lt;resources_name&gt;}</em> adalah nama direktori dari sumber daya default
    ++terkait (didefinisikan dalam tabel 1).</li>
    ++      <li><em>{@code &lt;qualifier&gt;}</em> adalah nama yang menetapkan konfigurasi individu
    ++yang akan digunakan sumber daya ini (didefinisikan dalam tabel 2).</li>
    ++    </ul>
    ++    <p>Anda bisa menambahkan lebih dari satu <em>{@code &lt;qualifier&gt;}</em>. Pisahkan masing-masing
    ++dengan tanda hubung.</p>
    ++    <p class="caution"><strong>Perhatian:</strong> Saat menambahkan beberapa qualifier, Anda
    ++harus menempatkannya dalam urutan yang sama dengan yang tercantum dalam tabel 2. Jika urutan qualifier
    ++salah, sumber daya akan diabaikan.</p>
    ++  </li>
    ++  <li>Simpan masing-masing sumber daya alternatif dalam direktori baru ini. File sumber daya harus dinamai
    ++sama persis dengan file sumber daya default.</li>
    ++</ol>
    ++
    ++<p>Misalnya, berikut ini beberapa sumber daya default dan sumber daya alternatif:</p>
    ++
    ++<pre class="classic no-pretty-print">
    ++res/
    ++    drawable/   <span style="color:black">
    ++        icon.png
    ++        background.png    </span>
    ++    drawable-hdpi/  <span style="color:black">
    ++        icon.png
    ++        background.png  </span>
    ++</pre>
    ++
    ++<p>Qualifier {@code hdpi} menunjukkan bahwa sumber daya dalam direktori itu diperuntukkan bagi perangkat dengan
    ++layar densitas tinggi. Gambar di masing-masing direktori drawable memiliki ukuran untuk densitas layar
    ++tertentu, namun nama filenya persis
    ++sama. Dengan demikian, ID sumber daya yang Anda gunakan untuk mengacu gambar {@code icon.png} atau @code
    ++background.png} selalu sama, namun Android memilih
    ++versi masing-masing sumber daya yang paling cocok dengan perangkat saat ini, dengan membandingkan informasi konfigurasi
    ++perangkat dengan qualifier dalam nama direktori sumber daya.</p>
    ++
    ++<p>Android mendukung beberapa qualifier konfigurasi dan Anda dapat
    ++menambahkan beberapa qualifier ke satu nama direktori, dengan memisahkan setiap qualifier dengan tanda hubung. Tabel 2
    ++berisi daftar qualifier konfigurasi yang valid, dalam urutan prioritas&mdash;jika Anda menggunakan beberapa
    ++qualifier sebagai direktori sumber daya, Anda harus menambahkannya ke nama direktori sesuai urutan
    ++yang tercantum dalam tabel.</p>
    ++
    ++
    ++<p class="table-caption" id="table2"><strong>Tabel 2.</strong> Nama-nama
    ++qualifier konfigurasi.</p>
    ++<table>
    ++    <tr>
    ++        <th>Konfigurasi</th>
    ++        <th>Nilai-nilai Qualifier</th>
    ++        <th>Keterangan</th>
    ++    </tr>
    ++    <tr id="MccQualifier">
    ++      <td>MCC dan MNC</td>
    ++      <td>Contoh:<br/>
    ++        <code>mcc310</code><br/>
    ++        <code><nobr>mcc310-mnc004</nobr></code><br/>
    ++        <code>mcc208-mnc00</code><br/>
    ++        dll.
    ++      </td>
    ++      <td>
    ++        <p>Kode negara seluler (MCC), bisa diikuti dengan kode jaringan seluler (MNC)
    ++ dari kartu SIM dalam perangkat. Misalnya, <code>mcc310</code> adalah AS untuk operator mana saja,
    ++ <code>mcc310-mnc004</code> adalah AS untuk Verizon, dan <code>mcc208-mnc00</code> Prancis untuk
    ++Orange.</p>
    ++        <p>Jika perangkat menggunakan koneksi radio (ponsel GSM), nilai-nilai MCC dan MNC berasal
    ++dari kartu SIM.</p>
    ++        <p>Anda juga dapat menggunakan MNC saja (misalnya, untuk menyertakan sumber daya legal
    ++spesifik untuk negara itu di aplikasi Anda). Jika Anda perlu menetapkan hanya berdasarkan bahasa, maka gunakan qualifier
    ++<em>bahasa dan wilayah</em> sebagai gantinya (akan dibahas nanti). Jika Anda memutuskan untuk menggunakan qualifier MCC dan
    ++MNC, Anda harus melakukannya dengan hati-hati dan menguji apakah qualifier itu berjalan sesuai harapan.</p>
    ++        <p>Lihat juga bidang konfigurasi {@link
    ++android.content.res.Configuration#mcc}, dan {@link
    ++android.content.res.Configuration#mnc}, yang masing-masing menunjukkan kode negara seluler saat ini
    ++dan kode jaringan seluler.</p>
    ++      </td>
    ++    </tr>
    ++    <tr id="LocaleQualifier">
    ++      <td>Bahasa dan wilayah</td>
    ++      <td>Contoh:<br/>
    ++        <code>en</code><br/>
    ++        <code>fr</code><br/>
    ++        <code>en-rUS</code><br/>
    ++        <code>fr-rFR</code><br/>
    ++        <code>fr-rCA</code><br/>
    ++        dll.
    ++      </td>
    ++      <td><p>Bahasa didefinisikan oleh kode bahasa dua huruf <a href="http://www.loc.gov/standards/iso639-2/php/code_list.php">ISO
    ++639-1</a>, bisa juga diikuti dengan kode wilayah
    ++dua huruf <a href="http://www.iso.org/iso/en/prods-services/iso3166ma/02iso-3166-code-lists/list-en1.html">ISO
    ++3166-1-alpha-2</a> (diawali dengan huruf kecil "{@code r}").
    ++        </p><p>
    ++        Kode <em>tidak</em> membedakan huruf besar atau kecil; awalan {@code r} akan digunakan untuk
    ++membedakan bagian wilayah.
    ++        Anda tidak bisa menetapkan wilayah saja.</p>
    ++        <p>Ini bisa berubah selama masa pakai
    ++aplikasi Anda jika pengguna mengubah bahasanya dalam pengaturan sistem. Lihat <a href="runtime-changes.html">Menangani Perubahan Runtime</a> untuk informasi tentang
    ++bagaimana hal ini dapat memengaruhi aplikasi Anda selama runtime.</p>
    ++        <p>Lihat <a href="localization.html">Pelokalan</a> untuk panduan lengkap melokalkan
    ++aplikasi Anda ke bahasa lain.</p>
    ++        <p>Lihat juga bidang konfigurasi {@link android.content.res.Configuration#locale} yang menunjukkan
    ++bahasa setempat yang digunakan saat ini.</p>
    ++      </td>
    ++    </tr>
    ++    <tr id="LayoutDirectionQualifier">
    ++      <td>Arah Layout</td>
    ++      <td><code>ldrtl</code><br/>
    ++        <code>ldltr</code><br/>
    ++      </td>
    ++      <td><p>Arah layout aplikasi Anda. {@code ldrtl} berarti "arah layout dari kanan ke kiri".
    ++ {@code ldltr} berarti "arah layout dari kiri ke kanan" dan merupakan nilai implisit default.
    ++      </p>
    ++      <p>Ini bisa berlaku untuk sumber daya mana pun seperti layout, drawable, atau nilai-nilai.
    ++      </p>
    ++      <p>Misalnya, jika Anda ingin memberikan beberapa layout khusus untuk bahasa Arab dan beberapa
    ++layout umum untuk setiap bahasa lainnya yang menggunakan "kanan-ke-kiri" lainnya (seperti bahasa Persia atau Ibrani) maka Anda akan memiliki:
    ++      </p>
    ++<pre class="classic no-pretty-print">
    ++res/
    ++    layout/   <span style="color:black">
    ++        main.xml  </span>(Default layout)
    ++    layout-ar/  <span style="color:black">
    ++        main.xml  </span>(Specific layout for Arabic)
    ++    layout-ldrtl/  <span style="color:black">
    ++        main.xml  </span>(Any "right-to-left" language, except
    ++                  for Arabic, because the "ar" language qualifier
    ++                  has a higher precedence.)
    ++</pre>
    ++        <p class="note"><strong>Catatan:</strong> Untuk mengaktifkan fitur
    ++layout kanan-ke-kiri untuk aplikasi, Anda harus mengatur <a href="{@docRoot}guide/topics/manifest/application-element.html#supportsrtl">{@code
    ++        supportsRtl}</a> ke {@code "true"} dan mengatur <a href="{@docRoot}guide/topics/manifest/uses-sdk-element.html#target">{@code targetSdkVersion}</a> ke 17 atau yang lebih tinggi.</p>
    ++        <p><em>Ditambahkan dalam API level 17.</em></p>
    ++      </td>
    ++    </tr>
    ++    <tr id="SmallestScreenWidthQualifier">
    ++      <td>smallestWidth</td>
    ++      <td><code>sw&lt;N&gt;dp</code><br/><br/>
    ++        Contoh:<br/>
    ++        <code>sw320dp</code><br/>
    ++        <code>sw600dp</code><br/>
    ++        <code>sw720dp</code><br/>
    ++        dll.
    ++      </td>
    ++      <td>
    ++        <p>Ukuran dasar layar, sebagaimana yang ditunjukkan oleh dimensi terpendek dari area layar
    ++yang tersedia. Secara spesifik, smallestWidth perangkat adalah yang terpendek dari
    ++tinggi dan lebar layar yang tersedia (Anda dapat menganggapnya sebagai "lebar terkecil yang memungkinkan" untuk layar). Anda bisa
    ++menggunakan qualifier ini untuk memastikan bahwa, apa pun orientasi layar saat ini, aplikasi
    ++Anda memiliki paling tidak {@code &lt;N&gt;} dps dari lebar yang tersedia untuk UI-nya.</p>
    ++        <p>Misalnya, jika layout mengharuskan dimensi layar terkecilnya setiap saat paling tidak
    ++600 dp, maka Anda dapat menggunakan qualifer ini untuk membuat sumber daya layout, {@code
    ++res/layout-sw600dp/}. Sistem akan menggunakan sumber daya ini hanya bila dimensi layar terkecil yang
    ++tersedia paling tidak 600 dp, tanpa mempertimbangkan apakah sisi 600 dp adalah tinggi atau
    ++lebar yang dipersepsikan pengguna. SmallestWidth adalah karakteristik ukuran layar tetap dari perangkat; <strong>smallestWidth
    ++perangkat tidak berubah saat orientasi layar berubah</strong>.</p>
    ++        <p>SmallestWidth perangkat memperhitungkan dekorasi layar dan UI sistem. Misalnya
    ++, jika perangkat memiliki beberapa elemen UI persisten pada layar yang menghitung ruang di sepanjang
    ++sumbu smallestWidth, sistem akan mendeklarasikan smallestWidth lebih kecil daripada ukuran layar sebenarnya,
    ++karena itu adalah piksel layar yang tidak tersedia untuk UI Anda. Sehingga nilai yang Anda
    ++gunakan haruslah merupakan dimensi terkecil sebenarnya yang <em>dibutuhkan oleh layout Anda</em> (biasanya, nilai ini adalah
    ++"lebar terkecil" yang didukung layout Anda, apa pun orientasi layar saat ini).</p>
    ++        <p>Sebagian nilai yang mungkin Anda gunakan untuk ukuran layar umum:</p>
    ++        <ul>
    ++          <li>320, untuk perangkat berkonfigurasi layar seperti:
    ++            <ul>
    ++              <li>240x320 ldpi (handset QVGA)</li>
    ++              <li>320x480 mdpi (handset)</li>
    ++              <li>480x800 hdpi (handset densitas tinggi)</li>
    ++            </ul>
    ++          </li>
    ++          <li>480, untuk layar seperti 480x800 mdpi (tablet/handset).</li>
    ++          <li>600, untuk layar seperti 600x1024 mdpi (tablet 7").</li>
    ++          <li>720, untuk layar seperti 720x1280 mdpi (tablet 10").</li>
    ++        </ul>
    ++        <p>Bila aplikasi Anda menyediakan beberapa direktori sumber daya dengan nilai yang berbeda untuk
    ++qualifier smallestWidth terkecil, sistem akan menggunakan nilai terdekat dengan (tanpa melebihi)
    ++smallestWidth perangkat. </p>
    ++        <p><em>Ditambahkan dalam API level 13.</em></p>
    ++        <p>Lihat juga atribut <a href="{@docRoot}guide/topics/manifest/supports-screens-element.html#requiresSmallest">{@code
    ++android:requiresSmallestWidthDp}</a>, yang mendeklarasikan smallestWidth minimum yang
    ++kompatibel dengan aplikasi Anda, dan bidang konfigurasi {@link
    ++android.content.res.Configuration#smallestScreenWidthDp}, yang menyimpan nilai
    ++smallestWidth perangkat.</p>
    ++        <p>Untuk informasi selengkapnya tentang mendesain untuk layar berbeda dan menggunakan
    ++qualifier ini, lihat panduan pengembang <a href="{@docRoot}guide/practices/screens_support.html">Mendukung
    ++Multi Layar</a>.</p>
    ++      </td>
    ++    </tr>
    ++    <tr id="ScreenWidthQualifier">
    ++      <td>Lebar yang tersedia</td>
    ++      <td><code>w&lt;N&gt;dp</code><br/><br/>
    ++        Contoh:<br/>
    ++        <code>w720dp</code><br/>
    ++        <code>w1024dp</code><br/>
    ++        dll.
    ++      </td>
    ++      <td>
    ++        <p>Menetapkan lebar layar minimum yang tersedia, di unit {@code dp} yang
    ++menggunakan sumber daya&mdash;yang didefinisikan oleh nilai <code>&lt;N&gt;</code>.  Nilai konfigurasi ini
    ++ akan berubah bila orientasi
    ++berubah antara lanskap dan potret agar cocok dengan lebar sebenarnya saat ini.</p>
    ++        <p>Bila aplikasi Anda menyediakan beberapa direktori sumber daya dengan nilai yang berbeda
    ++ untuk konfigurasi ini, sistem akan menggunakan nilai terdekat dengan (tanpa melebihi)
    ++ lebar layar perangkat saat ini.  Nilai
    ++di sini memperhitungkan dekorasi layar akun, jadi jika perangkat memiliki beberapa
    ++elemen UI persisten di tepi kiri atau kanan, layar
    ++menggunakan nilai lebar yang lebih kecil daripada ukuran layar sebenarnya, yang memperhitungkan
    ++elemen UI ini dan mengurangi ruang aplikasi yang tersedia.</p>
    ++        <p><em>Ditambahkan dalam API level 13.</em></p>
    ++        <p>Lihat juga bidang konfigurasi {@link android.content.res.Configuration#screenWidthDp}
    ++ yang menyimpan lebar layar saat ini.</p>
    ++        <p>Untuk informasi selengkapnya tentang mendesain untuk layar berbeda dan menggunakan
    ++qualifier ini, lihat panduan pengembang <a href="{@docRoot}guide/practices/screens_support.html">Mendukung
    ++Multi Layar</a>.</p>
    ++      </td>
    ++    </tr>
    ++    <tr id="ScreenHeightQualifier">
    ++      <td>Tinggi yang tersedia</td>
    ++      <td><code>h&lt;N&gt;dp</code><br/><br/>
    ++        Contoh:<br/>
    ++        <code>h720dp</code><br/>
    ++        <code>h1024dp</code><br/>
    ++        dll.
    ++      </td>
    ++      <td>
    ++        <p>Menetapkan tinggi layar minimum yang tersedia, dalam satuan "dp" yang harus digunakan
    ++sumber daya &mdash;bersama nilai yang didefinisikan oleh <code>&lt;N&gt;</code>.  Nilai konfigurasi ini
    ++ akan berubah saat orientasi
    ++berubah antara lanskap dan potret agar cocok dengan tinggi sebenarnya saat ini.</p>
    ++        <p>Bila aplikasi menyediakan beberapa direktori sumber daya dengan nilai yang berbeda
    ++ untuk konfigurasi ini, sistem akan menggunakan nilai yang terdekat dengan (tanpa melebihi)
    ++ tinggi layar perangkat saat ini.  Nilai
    ++di sini memperhitungkan dekorasi layar akun, jadi jika perangkat memiliki beberapa
    ++elemen UI persisten di tepi atas atau bawah, layar akan
    ++menggunakan nilai tinggi yang lebih kecil daripada ukuran layar sebenarnya, memperhitungkan
    ++elemen UI ini dan mengurangi ruang aplikasi yang tersedia.  Dekorasi
    ++layar yang tidak tetap (misalnya baris status (status-bar) telepon yang bisa
    ++disembunyikan saat layar penuh) di sini <em>tidak</em> diperhitungkan, demikian pula
    ++dekorasi jendela seperti baris judul (title-bar)atau baris tindakan (action-bar), jadi aplikasi harus disiapkan
    ++untuk menangani ruang yang agak lebih kecil daripada yang ditetapkan.
    ++        <p><em>Ditambahkan dalam API level 13.</em></p>
    ++        <p>Lihat juga bidang konfigurasi {@link android.content.res.Configuration#screenHeightDp}
    ++ yang menyimpan lebar layar saat ini.</p>
    ++        <p>Untuk informasi selengkapnya tentang mendesain untuk layar berbeda dan menggunakan
    ++qualifier ini, lihat panduan pengembang <a href="{@docRoot}guide/practices/screens_support.html">Mendukung
    ++Multi Layar</a>.</p>
    ++      </td>
    ++    </tr>
    ++    <tr id="ScreenSizeQualifier">
    ++      <td>Ukuran layar</td>
    ++      <td>
    ++        <code>small</code><br/>
    ++        <code>normal</code><br/>
    ++        <code>large</code><br/>
    ++        <code>xlarge</code>
    ++      </td>
    ++      <td>
    ++        <ul class="nolist">
    ++        <li>{@code small}: Layar yang berukuran serupa dengan
    ++layar QVGA densitas rendah. Ukuran layout minimum untuk layar kecil
    ++adalah sekitar 320x426 satuan dp.  Misalnya QVGA densitas rendah
    ++dan VGA densitas tinggi.</li>
    ++        <li>{@code normal}: Layar yang berukuran serupa dengan
    ++layar HVGA densitas sedang. Ukuran layout minimum untuk
    ++layar normal adalah sekitar 320x470 satuan dp.  Contoh layar seperti itu adalah
    ++WQVGA densitas rendah, HVGA densitas sedang, WVGA
    ++     densitas tinggi.</li>
    ++        <li>{@code large}: Layar yang berukuran serupa dengan
    ++layar VGA densitas sedang.
    ++        Ukuran layout minimum untuk layar besar adalah sekitar 480x640 satuan dp.
    ++        Misalnya layar VGA dan WVGA densitas sedang.</li>
    ++        <li>{@code xlarge}: Layar yang jauh lebih besar dari layar HVGA
    ++densitas sedang tradisional. Ukuran layout minimum untuk
    ++layar ekstra besar adalah sekitar 720x960 satuan dp.  Perangkat dengan layar ekstra besar
    ++seringkali terlalu besar untuk dibawa dalam saku dan kemungkinan besar
    ++ berupa perangkat bergaya tablet. <em>Ditambahkan dalam API level 9.</em></li>
    ++        </ul>
    ++        <p class="note"><strong>Catatan:</strong> Menggunakan qualifier ukuran tidak berarti bahwa
    ++sumber daya <em>hanya</em> untuk layar ukuran itu saja. Jika Anda tidak menyediakan sumber
    ++daya alternatif dengan qualifier yang lebih cocok dengan konfigurasi perangkat saat ini, sistem dapat menggunakan sumber daya
    ++mana saja yang <a href="#BestMatch">paling cocok</a>.</p>
    ++        <p class="caution"><strong>Perhatian:</strong> Jika semua sumber daya Anda menggunakan
    ++qualifier yang berukuran <em>lebih besar</em> daripada layar saat ini, sistem <strong>tidak</strong> akan menggunakannya dan aplikasi
    ++Anda akan crash saat runtime (misalnya, jika semua sumber daya layout ditandai dengan qualifier {@code
    ++xlarge}, namun perangkat memiliki ukuran layar normal).</p>
    ++        <p><em>Ditambahkan dalam API level 4.</em></p>
    ++
    ++        <p>Lihat <a href="{@docRoot}guide/practices/screens_support.html">Mendukung Beberapa
    ++Layar</a> untuk informasi selengkapnya.</p>
    ++        <p>Lihat juga bidang konfigurasi {@link android.content.res.Configuration#screenLayout},
    ++ yang menunjukkan apakah layar berukuran kecil, normal, atau
    ++besar.</p>
    ++      </td>
    ++    </tr>
    ++    <tr id="ScreenAspectQualifier">
    ++      <td>Aspek layar</td>
    ++      <td>
    ++        <code>long</code><br/>
    ++        <code>notlong</code>
    ++      </td>
    ++      <td>
    ++        <ul class="nolist">
    ++          <li>{@code long}: Layar panjang, seperti WQVGA, WVGA, FWVGA</li>
    ++          <li>{@code notlong}: Layar tidak panjang, seperti QVGA, HVGA, dan VGA</li>
    ++        </ul>
    ++        <p><em>Ditambahkan dalam API level 4.</em></p>
    ++        <p>Ini berdasarkan sepenuhnya pada rasio aspek layar (layar "panjang" lebih lebar). Ini
    ++tidak ada kaitannya dengan orientasi layar.</p>
    ++        <p>Lihat juga bidang konfigurasi {@link android.content.res.Configuration#screenLayout},
    ++ yang menunjukkan apakah layar panjang.</p>
    ++      </td>
    ++    </tr>
    ++    <tr id="OrientationQualifier">
    ++      <td>Orientasi layar</td>
    ++      <td>
    ++        <code>port</code><br/>
    ++        <code>land</code>  <!-- <br/>
    ++        <code>square</code>  -->
    ++      </td>
    ++      <td>
    ++        <ul class="nolist">
    ++          <li>{@code port}: Perangkat dalam orientasi potret (vertikal)</li>
    ++          <li>{@code land}: Perangkat dalam orientasi lanskap (horizontal)</li>
    ++          <!-- Square mode is currently not used. -->
    ++        </ul>
    ++        <p>Ini bisa berubah selama masa pakai aplikasi Anda jika pengguna memutar
    ++layar. Lihat <a href="runtime-changes.html">Menangani Perubahan Runtime</a> untuk
    ++ informasi tentang bagaimana hal ini memengaruhi aplikasi Anda selama runtime.</p>
    ++        <p>Lihat juga bidang konfigurasi {@link android.content.res.Configuration#orientation},
    ++yang menunjukkan orientasi perangkat saat ini.</p>
    ++      </td>
    ++    </tr>
    ++    <tr id="UiModeQualifier">
    ++      <td>Mode UI</td>
    ++      <td>
    ++        <code>car</code><br/>
    ++        <code>desk</code><br/>
    ++        <code>television</code><br/>
    ++        <code>appliance</code>
    ++        <code>watch</code>
    ++      </td>
    ++      <td>
    ++        <ul class="nolist">
    ++          <li>{@code car}: Perangkat sedang menampilkan di dudukan perangkat di mobil</li>
    ++          <li>{@code desk}: Perangkat sedang menampilkan di dudukan perangkat di meja</li>
    ++          <li>{@code television}: Perangkat sedang menampilkan di televisi, yang menyediakan
    ++pengalaman "sepuluh kaki" dengan UI-nya pada layar besar yang berada jauh dari pengguna,
    ++terutama diorientasikan seputar DPAD atau
    ++interaksi non-pointer lainnya</li>
    ++          <li>{@code appliance}: Perangkat berlaku sebagai
    ++alat, tanpa tampilan</li>
    ++          <li>{@code watch}: Perangkat memiliki tampilan dan dikenakan di pergelangan tangan</li>
    ++        </ul>
    ++        <p><em>Ditambahkan dalam API level 8, televisi ditambahkan dalam API 13, jam ditambahkan dalam API 20.</em></p>
    ++        <p>Untuk informasi tentang cara aplikasi merespons saat perangkat dimasukkan
    ++ke dalam atau dilepaskan dari dudukannya, bacalah <a href="{@docRoot}training/monitoring-device-state/docking-monitoring.html">Menentukan
    ++dan Memantau Kondisi dan Tipe Dudukan</a>.</p>
    ++        <p>Ini bisa berubah selama masa pakai aplikasi jika pengguna menempatkan perangkat di
    ++dudukannya. Anda dapat mengaktifkan atau menonaktifkan sebagian mode ini menggunakan {@link
    ++android.app.UiModeManager}. Lihat <a href="runtime-changes.html">Menangani Perubahan Runtime</a> untuk
    ++informasi tentang bagaimana hal ini memengaruhi aplikasi Anda selama runtime.</p>
    ++      </td>
    ++    </tr>
    ++    <tr id="NightQualifier">
    ++      <td>Mode malam</td>
    ++      <td>
    ++        <code>night</code><br/>
    ++        <code>notnight</code>
    ++      </td>
    ++      <td>
    ++        <ul class="nolist">
    ++          <li>{@code night}: Waktu malam</li>
    ++          <li>{@code notnight}: Waktu siang</li>
    ++        </ul>
    ++        <p><em>Ditambahkan dalam API level 8.</em></p>
    ++        <p>Ini bisa berubah selama masa pakai aplikasi jika mode malam dibiarkan dalam
    ++mode otomatis (default), dalam hal ini perubahan mode berdasarkan pada waktu hari.  Anda dapat mengaktifkan
    ++atau menonaktifkan mode ini menggunakan {@link android.app.UiModeManager}. Lihat <a href="runtime-changes.html">Menangani Perubahan Runtime</a> untuk informasi tentang bagaimana hal ini memengaruhi
    ++aplikasi Anda selama runtime.</p>
    ++      </td>
    ++    </tr>
    ++    <tr id="DensityQualifier">
    ++      <td>Densitas piksel layar (dpi)</td>
    ++      <td>
    ++        <code>ldpi</code><br/>
    ++        <code>mdpi</code><br/>
    ++        <code>hdpi</code><br/>
    ++        <code>xhdpi</code><br/>
    ++        <code>xxhdpi</code><br/>
    ++        <code>xxxhdpi</code><br/>
    ++        <code>nodpi</code><br/>
    ++        <code>tvdpi</code>
    ++      </td>
    ++      <td>
    ++        <ul class="nolist">
    ++          <li>{@code ldpi}: Layar densitas rendah; sekitar 120 dpi.</li>
    ++          <li>{@code mdpi}: Layar densitas sedang (pada HVGA tradisional); sekitar 160 dpi.
    ++</li>
    ++          <li>{@code hdpi}: Layar densitas tinggi; sekitar 240 dpi.</li>
    ++          <li>{@code xhdpi}: Layar densitas ekstra tinggi; sekitar 320 dpi. <em>Ditambahkan dalam API
    ++Level 8.</em></li>
    ++          <li>{@code xxhdpi}: Layar densitas ekstra-ekstra-tinggi; sekitar 480 dpi. <em>Ditambahkan dalam API
    ++Level 16.</em></li>
    ++          <li>{@code xxxhdpi}: Densitas ekstra-ekstra-ekstra-tinggi (hanya ikon launcher,
    ++lihat <a href="{@docRoot}guide/practices/screens_support.html#xxxhdpi-note">catatan</a>
    ++ dalam <em>Mendukung Beberapa Layar</em>); sekitar 640 dpi. <em>Ditambahkan dalam API
    ++Level 18.</em></li>
    ++          <li>{@code nodpi}: Ini bisa digunakan untuk sumber daya bitmap yang tidak ingin Anda
    ++skalakan agar sama dengan densitas perangkat.</li>
    ++          <li>{@code tvdpi}: Layar antara mdpi dan hdpi; sekitar 213 dpi. Ini
    ++tidak dianggap sebagai kelompok densitas "utama". Sebagian besar ditujukan untuk televisi dan kebanyakan
    ++aplikasi tidak memerlukannya &mdash;asalkan sumber daya mdpi dan hdpi cukup untuk sebagian besar aplikasi dan
    ++sistem akan menskalakan sebagaimana mestinya. Qualifier ini diperkenalkan pada API level 13.</li>
    ++        </ul>
    ++        <p>Terdapat rasio skala 3:4:6:8:12:16 antara enam densitas utama (dengan mengabaikan densitas
    ++tvdpi). Jadi bitmap 9x9 di ldpi adalah 12x12 di mdpi, 18x18 di hdpi, 24x24 di xhdpi dan seterusnya.
    ++</p>
    ++        <p>Jika Anda memutuskan bahwa sumber daya gambar tidak terlihat cukup baik di televisi
    ++atau perangkat tertentu lainnya dan ingin mencoba sumber daya tvdpi, faktor skalanya adalah 1,33*mdpi. Misalnya,
    ++gambar 100px x 100px untuk layar mdpi harus 133px x 133px untuk tvdpi.</p>
    ++        <p class="note"><strong>Catatan:</strong> Menggunakan qualifier densitas tidak berarti bahwa
    ++sumber daya <em>hanya</em> untuk layar dengan ukuran itu saja. Jika Anda tidak menyediakan sumber
    ++daya alternatif dengan qualifier yang lebih cocok dengan konfigurasi perangkat saat ini, sistem dapat menggunakan sumber daya
    ++mana saja yang <a href="#BestMatch">paling cocok</a>.</p>
    ++        <p>Lihat <a href="{@docRoot}guide/practices/screens_support.html">Mendukung Beberapa
    ++Layar</a> untuk informasi selengkapnya tentang cara menangani densitas layar yang berbeda dan cara Android
    ++menurunkan skala bitmap Anda agar sesuai dengan densitas saat ini.</p>
    ++       </td>
    ++    </tr>
    ++    <tr id="TouchscreenQualifier">
    ++      <td>Tipe layar sentuh</td>
    ++      <td>
    ++        <code>notouch</code><br/>
    ++        <code>finger</code>
    ++      </td>
    ++      <td>
    ++        <ul class="nolist">
    ++          <li>{@code notouch}: Perangkat tidak memiliki layar sentuh.</li>
    ++          <li>{@code finger}: Perangkat memiliki layar sentuh yang dimaksudkan untuk
    ++digunakan melalui interaksi dengan jari pengguna.</li>
    ++        </ul>
    ++        <p>Lihat juga bidang konfigurasi {@link android.content.res.Configuration#touchscreen}, yang
    ++menunjukkan tipe layar sentuh pada perangkat.</p>
    ++      </td>
    ++    </tr>
    ++    <tr id="KeyboardAvailQualifier">
    ++      <td>Ketersediaan keyboard</td>
    ++      <td>
    ++        <code>keysexposed</code><br/>
    ++        <code>keyshidden</code><br/>
    ++        <code>keyssoft</code>
    ++      </td>
    ++      <td>
    ++        <ul class="nolist">
    ++          <li>{@code keysexposed}: Perangkat menyediakan keyboard. Jika perangkat mengaktifkan
    ++keyboard perangkat lunak (kemungkinan), ini dapat digunakan bahkan saat keyboard fisik
    ++<em>tidak</em> diekspos kepada pengguna, meskipun perangkat tidak memiliki keyboard fisik. Jika keyboard
    ++perangkat lunak tidak disediakan atau dinonaktifkan, maka ini hanya digunakan bila
    ++keyboard fisik diekspos.</li>
    ++          <li>{@code keyshidden}: Perangkat memiliki keyboard fisik yang tersedia
    ++tetapi tersembunyi <em>dan</em> perangkat <em>tidak</em> mengaktifkan keyboard perangkat lunak.</li>
    ++          <li>{@code keyssoft}: Perangkat mengaktifkan keyboard perangkat lunak,
    ++baik itu terlihat maupun tidak.</li>
    ++        </ul>
    ++        <p>Jika Anda menyediakan sumber daya <code>keysexposed</code>, namun bukan sumber daya <code>keyssoft</code>
    ++, sistem akan menggunakan sumber daya <code>keysexposed</code> baik keyboard
    ++terlihat atau tidak, asalkan sistem telah mengaktifkan keyboard perangkat lunak.</p>
    ++        <p>Ini bisa berubah selama masa pakai aplikasi jika pengguna membuka keyboard
    ++fisik. Lihat <a href="runtime-changes.html">Menangani Perubahan Runtime</a> untuk informasi tentang bagaimana
    ++hal ini memengaruhi aplikasi Anda selama runtime.</p>
    ++        <p>Lihat juga bidang konfigurasi {@link
    ++android.content.res.Configuration#hardKeyboardHidden} dan {@link
    ++android.content.res.Configuration#keyboardHidden}, yang menunjukkan visibilitas
    ++keyboard fisik dan visibilitas segala jenis keyboard (termasuk keyboard perangkat lunak), masing-masing.</p>
    ++      </td>
    ++    </tr>
    ++    <tr id="ImeQualifier">
    ++      <td>Metode input teks utama</td>
    ++      <td>
    ++        <code>nokeys</code><br/>
    ++        <code>qwerty</code><br/>
    ++        <code>12key</code>
    ++      </td>
    ++      <td>
    ++        <ul class="nolist">
    ++          <li>{@code nokeys}: Perangkat tidak memiliki tombol fisik untuk input teks.</li>
    ++          <li>{@code qwerty}: Perangkat memiliki keyboard fisik qwerty, baik terlihat maupun tidak pada
    ++pengguna
    ++.</li>
    ++          <li>{@code 12key}: Perangkat memiliki keyboard fisik 12 tombol, baik terlihat maupun tidak
    ++pada pengguna.</li>
    ++        </ul>
    ++        <p>Lihat juga bidang konfigurasi {@link android.content.res.Configuration#keyboard},
    ++yang menunjukkan metode utama input teks yang tersedia.</p>
    ++      </td>
    ++    </tr>
    ++    <tr id="NavAvailQualifier">
    ++      <td>Ketersediaan tombol navigasi</td>
    ++      <td>
    ++        <code>navexposed</code><br/>
    ++        <code>navhidden</code>
    ++      </td>
    ++      <td>
    ++        <ul class="nolist">
    ++          <li>{@code navexposed}: Tombol navigasi tersedia bagi pengguna.</li>
    ++          <li>{@code navhidden}: Tombol navigasi tidak tersedia (misalnya di balik penutup yang
    ++ditutup).</li>
    ++        </ul>
    ++        <p>Ini bisa berubah selama masa pakai aplikasi jika pengguna menyingkap tombol
    ++navigasi. Lihat <a href="runtime-changes.html">Menangani Perubahan Runtime</a> untuk
    ++informasi tentang bagaimana hal ini memengaruhi aplikasi Anda selama runtime.</p>
    ++        <p>Lihat juga bidang konfigurasi {@link android.content.res.Configuration#navigationHidden}, yang menunjukkan
    ++apakah tombol navigasi disembunyikan.</p>
    ++      </td>
    ++    </tr>
    ++    <tr id="NavigationQualifier">
    ++      <td>Metode navigasi non-sentuh utama</td>
    ++      <td>
    ++        <code>nonav</code><br/>
    ++        <code>dpad</code><br/>
    ++        <code>trackball</code><br/>
    ++        <code>wheel</code>
    ++      </td>
    ++      <td>
    ++        <ul class="nolist">
    ++          <li>{@code nonav}: Perangkat tidak memiliki fasilitas navigasi selain menggunakan
    ++layar sentuh.</li>
    ++          <li>{@code dpad}: Perangkat memiliki pad pengarah (directional pad / d-pad) untuk navigasi.</li>
    ++          <li>{@code trackball}: Perangkat memiliki trackball untuk navigasi.</li>
    ++          <li>{@code wheel}: Perangkat memiliki roda pengarah (directional wheel) untuk navigasi (tidak umum).</li>
    ++        </ul>
    ++        <p>Lihat juga bidang konfigurasi {@link android.content.res.Configuration#navigation},
    ++yang menunjukkan tipe metode navigasi yang tersedia.</p>
    ++      </td>
    ++    </tr>
    ++<!-- DEPRECATED
    ++    <tr>
    ++      <td>Screen dimensions</td>
    ++      <td>Examples:<br/>
    ++        <code>320x240</code><br/>
    ++        <code>640x480</code><br/>
    ++        etc.
    ++      </td>
    ++      <td>
    ++        <p>The larger dimension must be specified first. <strong>This configuration is deprecated
    ++and should not be used</strong>. Instead use "screen size," "wider/taller screens," and "screen
    ++orientation" described above.</p>
    ++      </td>
    ++    </tr>
    ++-->
    ++    <tr id="VersionQualifier">
    ++      <td>Versi Platform (level API)</td>
    ++      <td>Contoh:<br/>
    ++        <code>v3</code><br/>
    ++        <code>v4</code><br/>
    ++        <code>v7</code><br/>
    ++        dll.</td>
    ++      <td>
    ++        <p>Level API yang didukung perangkat. Misalnya, <code>v1</code> untuk API level
    ++1 (perangkat dengan Android 1.0 atau yang lebih tinggi) dan <code>v4</code> untuk API level 4 (perangkat dengan Android
    ++1.6 atau yang lebih tinggi). Lihat dokumen <a href="{@docRoot}guide/topics/manifest/uses-sdk-element.html#ApiLevels">Level API Android</a> untuk informasi selengkapnya
    ++tentang nilai-nilai ini.</p>
    ++      </td>
    ++    </tr>
    ++</table>
    ++
    ++
    ++<p class="note"><strong>Catatan:</strong> Sebagian qualifier konfigurasi telah ditambahkan sejak Android
    ++1.0, jadi tidak semua versi Android mendukung semua qualifier. Menggunakan qualifier baru secara implisit
    ++akan menambahkan qualifier versi platform sehingga perangkat yang lebih lama pasti mengabaikannya. Misalnya, menggunakan qualifier
    ++<code>w600dp</code> secara otomatis akan menyertakan qualifier <code>v13</code>, karena
    ++qualifier lebar yang tersedia baru di API level 13. Untuk menghindari masalah, selalu sertakan satu set
    ++sumber daya default (satu set sumber daya <em>tanpa qualifier</em>). Untuk informasi selengkapnya, lihat
    ++bagian tentang <a href="#Compatibility">Menyediakan Kompatibilitas Perangkat Terbaik dengan
    ++Sumber Daya</a>.</p>
    ++
    ++
    ++
    ++<h3 id="QualifierRules">Aturan penamaan qualifier</h3>
    ++
    ++<p>Inilah beberapa aturan tentang penggunaan nama qualifier konfigurasi:</p>
    ++
    ++<ul>
    ++    <li>Anda bisa menetapkan beberapa qualifier untuk satu set sumber daya, yang dipisahkan dengan tanda hubung. Misalnya,
    ++<code>drawable-en-rUS-land</code> berlaku untuk perangkat bahasa Inggris-AS dalam orientasi
    ++lanskap.</li>
    ++    <li>Qualifier harus dalam urutan seperti yang tercantum dalam <a href="#table2">tabel 2</a>.
    ++Misalnya:
    ++      <ul>
    ++        <li>Salah: <code>drawable-hdpi-port/</code></li>
    ++        <li>Benar: <code>drawable-port-hdpi/</code></li>
    ++      </ul>
    ++    </li>
    ++    <li>Direktori sumber daya alternatif tidak bisa digunakan. Misalnya, Anda tidak bisa memiliki
    ++<code>res/drawable/drawable-en/</code>.</li>
    ++    <li>Nilai tidak membedakan huruf besar maupun kecil.  Compiler sumber daya mengubah nama direktori
    ++menjadi huruf kecil sebelum pemrosesan untuk menghindari masalah pada sistem file yang membedakan
    ++huruf kecil dan besar. Setiap penggunaan huruf besar dalam nama hanyalah demi keterbacaan.</li>
    ++    <li>Hanya didukung satu nilai untuk setiap tipe qualifier. Misalnya, jika Anda ingin menggunakan
    ++file drawable yang sama untuk Spanyol dan Prancis, Anda <em>tidak bisa</em> memiliki direktori bernama
    ++<code>drawable-rES-rFR/</code>. Sebagai gantinya, Anda perlu dua direktori sumber daya, seperti
    ++<code>drawable-rES/</code> dan <code>drawable-rFR/</code>, berisi file yang sesuai.
    ++Akan tetapi, Anda tidak harus benar-benar menggandakan file yang sama di kedua lokasi. Sebagai gantinya, Anda
    ++bisa membuat alias ke satu sumber daya. Lihat <a href="#AliasResources">Membuat
    ++sumber daya alias</a> di bawah ini.</li>
    ++</ul>
    ++
    ++<p>Setelah Anda menyimpan sumber daya alternatif ke dalam direktori yang diberi nama dengan
    ++qualifier ini, Android secara otomatis menerapkan sumber daya dalam
    ++aplikasi Anda berdasarkan pada konfigurasi perangkat saat ini. Setiap kali sumber daya diminta, Android akan memeriksa direktori sumber daya
    ++alternatif berisi file sumber daya yang diminta, lalu <a href="#BestMatch">mencari sumber daya yang
    ++paling cocok</a>(dibahas di bawah). Jika tidak ada sumber daya alternatif yang cocok
    ++dengan konfigurasi perangkat tertentu, Android akan menggunakan sumber daya default terkait (set
    ++sumber daya untuk tipe sumber daya tertentu yang tidak termasuk qualifier
    ++konfigurasi).</p>
    ++
    ++
    ++
    ++<h3 id="AliasResources">Membuat sumber daya alias</h3>
    ++
    ++<p>Bila memiliki sumber daya yang ingin Anda gunakan untuk lebih dari satu konfigurasi
    ++perangkat (namun tidak ingin menyediakannya sebagai sumber daya default), Anda tidak perlu menempatkan sumber daya
    ++yang sama di lebih dari satu direktori sumber daya alternatif. Sebagai gantinya, (dalam beberapa kasus) Anda bisa membuat
    ++sumber daya alternatif
    ++yang berfungsi sebagai alias untuk sumber daya yang disimpan dalam direktori sumber daya default.</p>
    ++
    ++<p class="note"><strong>Catatan:</strong> Tidak semua sumber daya menawarkan mekanisme yang memungkinkan Anda
    ++membuat alias ke sumber daya lain. Khususnya, animasi, menu, raw, dan
    ++sumber daya lain yang tidak ditetapkan dalam direktori {@code xml/} tidak menawarkan fitur ini.</p>
    ++
    ++<p>Misalnya, bayangkan Anda memiliki ikon aplikasi {@code icon.png}, dan membutuhkan versi uniknya
    ++untuk lokal berbeda. Akan tetapi, dua lokal, bahasa Inggris-Kanada dan bahasa Prancis-Kanada, harus menggunakan
    ++versi yang sama. Anda mungkin berasumsi bahwa Anda perlu menyalin gambar
    ++yang sama ke dalam direktori sumber daya baik untuk bahasa Inggris-Kanada maupun bahasa Prancis-Kanada, namun
    ++bukan demikian. Sebagai gantinya, Anda bisa menyimpan gambar yang sama-sama digunakan sebagai {@code icon_ca.png} (nama
    ++apa saja selain {@code icon.png}) dan memasukkannya
    ++dalam direktori default {@code res/drawable/}. Lalu buat file {@code icon.xml} dalam {@code
    ++res/drawable-en-rCA/} dan {@code res/drawable-fr-rCA/} yang mengacu ke sumber daya {@code icon_ca.png}
    ++yang menggunakan elemen {@code &lt;bitmap&gt;}. Hal ini memungkinkan Anda menyimpan satu versi saja dari
    ++file PNG dan dua file XML kecil yang menunjuk ke sana. (Contoh file XML ditampilkan di bawah.)</p>
    ++
    ++
    ++<h4>Drawable</h4>
    ++
    ++<p>Untuk membuat alias ke drawable yang ada, gunakan elemen {@code &lt;bitmap&gt;}.
    ++Misalnya:</p>
    ++
    ++<pre>
    ++&lt;?xml version="1.0" encoding="utf-8"?>
    ++&lt;bitmap xmlns:android="http://schemas.android.com/apk/res/android"
    ++    android:src="@drawable/icon_ca" />
    ++</pre>
    ++
    ++<p>Jika Anda menyimpan file ini sebagai {@code icon.xml} (dalam direktori sumber daya alternatif, seperti
    ++{@code res/drawable-en-rCA/}), maka file akan dikompilasi menjadi sumber daya yang dapat Anda acu
    ++sebagai {@code R.drawable.icon}, namun sebenarnya merupakan alias untuk sumber daya {@code
    ++R.drawable.icon_ca} (yang disimpan dalam {@code res/drawable/}).</p>
    ++
    ++
    ++<h4>Layout</h4>
    ++
    ++<p>Untuk membuat alias ke layout yang ada, gunakan elemen {@code &lt;include&gt;},
    ++yang dibungkus dalam {@code &lt;merge&gt;}. Misalnya:</p>
    ++
    ++<pre>
    ++&lt;?xml version="1.0" encoding="utf-8"?>
    ++&lt;merge>
    ++    &lt;include layout="@layout/main_ltr"/>
    ++&lt;/merge>
    ++</pre>
    ++
    ++<p>Jika Anda menyimpan file ini sebagai {@code main.xml}, file akan dikompilasi menjadi sumber daya yang dapat Anda acu
    ++sebagai {@code R.layout.main}, namun sebenarnya merupakan alias untuk sumber daya {@code R.layout.main_ltr}
    ++.</p>
    ++
    ++
    ++<h4>String dan nilai-nilai sederhana lainnya</h4>
    ++
    ++<p>Untuk membuat alias ke string yang ada, cukup gunakan ID sumber daya
    ++dari string yang diinginkan sebagai nilai untuk string baru. Misalnya:</p>
    ++
    ++<pre>
    ++&lt;?xml version="1.0" encoding="utf-8"?>
    ++&lt;resources>
    ++    &lt;string name="hello">Hello&lt;/string>
    ++    &lt;string name="hi">@string/hello&lt;/string>
    ++&lt;/resources>
    ++</pre>
    ++
    ++<p>Sumber daya {@code R.string.hi} sekarang merupakan alias untuk {@code R.string.hello}.</p>
    ++
    ++<p> <a href="{@docRoot}guide/topics/resources/more-resources.html">Nilai sederhana lainnya</a> sama
    ++cara kerjanya. Misalnya, sebuah warna:</p>
    ++
    ++<pre>
    ++&lt;?xml version="1.0" encoding="utf-8"?>
    ++&lt;resources>
    ++    &lt;color name="yellow">#f00&lt;/color>
    ++    &lt;color name="highlight">@color/red&lt;/color>
    ++&lt;/resources>
    ++</pre>
    ++
    ++
    ++
    ++
    ++<h2 id="Compatibility">Menyediakan Kompatibilitas Perangkat Terbaik dengan Sumber Daya</h2>
    ++
    ++<p>Agar aplikasi Anda mendukung beberapa konfigurasi perangkat,
    ++Anda harus selalu menyediakan sumber daya default untuk setiap tipe sumber daya yang menggunakan aplikasi Anda.</p>
    ++
    ++<p>Misalnya, jika aplikasi Anda mendukung beberapa bahasa, sertakan selalu direktori {@code
    ++values/} (tempat string Anda disimpan) <em>tanpa</em> <a href="#LocaleQualifier">qualifier bahasa dan wilayah</a>. Jika sebaliknya Anda menempatkan semua file
    ++string dalam direktori yang memiliki qualifier bahasa dan wilayah, maka aplikasi Anda akan crash saat berjalan
    ++pada perangkat yang telah diatur ke bahasa yang tidak didukung string Anda. Namun asalkan Anda menyediakan sumber daya default
    ++{@code values/}, aplikasi akan berjalan lancar (meskipun pengguna
    ++tidak memahami bahasa itu&mdash;, ini lebih baik daripada crash).</p>
    ++
    ++<p>Demikian pula, jika Anda menyediakan sumber daya layout berbeda berdasarkan orientasi layar, Anda harus
    ++memilih satu orientasi sebagai default. Misalnya, sebagai ganti menyediakan sumber daya dalam {@code
    ++layout-land/} untuk lanskap dan {@code layout-port/} untuk potret, biarkan salah satu sebagai default, seperti
    ++{@code layout/} untuk lanskap dan {@code layout-port/} untuk potret.</p>
    ++
    ++<p>Sumber daya default perlu disediakan bukan hanya karena aplikasi mungkin berjalan pada
    ++konfigurasi yang belum Anda antisipasi, namun juga karena versi baru Android terkadang menambahkan
    ++qualifier konfigurasi yang tidak didukung oleh versi lama. Jika Anda menggunakan qualifier sumber daya baru,
    ++namun mempertahankan kompatibilitas kode dengan versi Android yang lebih lama, maka saat versi lama
    ++Android menjalankan aplikasi, aplikasi itu akan crash jika Anda tidak menyediakan sumber daya default, aplikasi
    ++tidak bisa menggunakan sumber daya yang dinamai dengan qualifier baru. Misalnya, jika <a href="{@docRoot}guide/topics/manifest/uses-sdk-element.html#min">{@code
    ++minSdkVersion}</a> Anda diatur ke 4, dan Anda memenuhi syarat semua sumber daya drawable dengan menggunakan <a href="#NightQualifier">mode malam</a> ({@code night} atau {@code notnight}, yang ditambahkan di API
    ++Level 8), maka perangkat API level 4 tidak bisa mengakses sumber daya drawable dan akan crash. Dalam hal
    ++ini, Anda mungkin ingin {@code notnight} menjadi sumber daya default, jadi Anda harus mengecualikan
    ++qualifier itu agar sumber daya drawable Anda ada dalam {@code drawable/} atau {@code drawable-night/}.</p>
    ++
    ++<p>Jadi, agar bisa menyediakan kompatibilitas perangkat terbaik, sediakan selalu sumber daya
    ++default untuk sumber daya yang diperlukan aplikasi Anda untuk berjalan dengan benar. Selanjutnya buatlah sumber daya
    ++alternatif untuk konfigurasi perangkat tertentu dengan menggunakan qualifier konfigurasi.</p>
    ++
    ++<p>Ada satu eksepsi untuk aturan ini: Jika <a href="{@docRoot}guide/topics/manifest/uses-sdk-element.html#min">{@code minSdkVersion}</a> aplikasi Anda adalah 4 atau
    ++lebih, Anda <em>tidak</em> memerlukan sumber daya drawable default saat menyediakan sumber daya
    ++drawable alternatif dengan qualifier <a href="#DensityQualifier">densitas layar</a>. Tanpa sumber daya
    ++drawable default sekali pun, Android bisa menemukan yang paling cocok di antara densitas layar alternatif dan menskalakan
    ++bitmap sesuai kebutuhan. Akan tetapi, demi pengalaman terbaik pada semua jenis perangkat, Anda harus
    ++menyediakan drawable alternatif untuk ketiga tipe densitas.</p>
    ++
    ++
    ++
    ++<h2 id="BestMatch">Cara Android Menemukan Sumber Daya yang Paling Cocok</h2>
    ++
    ++<p>Saat Anda meminta sumber daya yang Anda berikan alternatifnya, Android akan memilih
    ++sumber daya alternatif yang akan digunakan saat runtime, bergantung pada konfigurasi perangkat saat ini. Untuk
    ++mendemonstrasikan cara Android memilih sumber daya alternatif, anggaplah direktori drawable berikut
    ++masing-masing berisi versi berbeda dari gambar yang sama:</p>
    ++
    ++<pre class="classic no-pretty-print">
    ++drawable/
    ++drawable-en/
    ++drawable-fr-rCA/
    ++drawable-en-port/
    ++drawable-en-notouch-12key/
    ++drawable-port-ldpi/
    ++drawable-port-notouch-12key/
    ++</pre>
    ++
    ++<p>Dan anggaplah yang berikut ini merupakan konfigurasi perangkatnya:</p>
    ++
    ++<p style="margin-left:1em;">
    ++Lokal = <code>en-GB</code> <br/>
    ++Orientasi layar = <code>port</code> <br/>
    ++Densitas piksel layar = <code>hdpi</code> <br/>
    ++Tipe layar sentuh = <code>notouch</code> <br/>
    ++Metode input teks utama = <code>12key</code>
    ++</p>
    ++
    ++<p>Dengan membandingkan konfigurasi perangkat dengan sumber daya alternatif yang tersedia, Android akan memilih
    ++drawable dari {@code drawable-en-port}.</p>
    ++
    ++<p>Sistem akan menentukan keputusannya mengenai sumber daya yang akan digunakan dengan logika
    ++berikut:</p>
    ++
    ++
    ++<div class="figure" style="width:371px">
    ++<img src="{@docRoot}images/resources/res-selection-flowchart.png" alt="" height="471" />
    ++<p class="img-caption"><strong>Gambar 2.</strong> Bagan alur cara Android menemukan
    ++sumber daya yang paling cocok.</p>
    ++</div>
    ++
    ++
    ++<ol>
    ++  <li>Menghapus file sumber daya yang bertentangan dengan konfigurasi perangkat.
    ++    <p>Direktori <code>drawable-fr-rCA/</code> dihapus karena bertentangan
    ++dengan lokal <code>en-GB</code>.</p>
    ++<pre class="classic no-pretty-print">
    ++drawable/
    ++drawable-en/
    ++<strike>drawable-fr-rCA/</strike>
    ++drawable-en-port/
    ++drawable-en-notouch-12key/
    ++drawable-port-ldpi/
    ++drawable-port-notouch-12key/
    ++</pre>
    ++<p class="note"><strong>Eksepsi:</strong> Densitas piksel layar adalah satu qualifier yang
    ++tidak dihapus karena bertentangan. Meskipun densitas layar perangkat adalah hdpi,
    ++<code>drawable-port-ldpi/</code> tidak dihapus karena setiap densitas layar
    ++dianggap cocok untuk saat ini. Informasi selengkapnya tersedia dalam dokumen <a href="{@docRoot}guide/practices/screens_support.html">Mendukung Beberapa
    ++Layar</a>.</p></li>
    ++
    ++  <li>Pilih qualifier berkedudukan tertinggi (berikutnya) dalam daftar (<a href="#table2">tabel 2</a>).
    ++(Mulai dengan MCC, lalu pindah ke bawah.) </li>
    ++  <li>Apakah salah satu direktori sumber daya menyertakan qualifier ini?  </li>
    ++    <ul>
    ++      <li>Jika Tidak, kembali ke langkah 2 dan lihat qualifier berikutnya. (Dalam contoh,
    ++jawabannya adalah "tidak" hingga qualifier bahasa tercapai.)</li>
    ++      <li>Jika Ya, lanjutkan ke langkah 4.</li>
    ++    </ul>
    ++  </li>
    ++
    ++  <li>Hapus direktori sumber daya yang tidak menyertakan qualifier ini. Dalam contoh, sistem
    ++menghapus semua direktori yang tidak menyertakan qualifier bahasa:</li>
    ++<pre class="classic no-pretty-print">
    ++<strike>drawable/</strike>
    ++drawable-en/
    ++drawable-en-port/
    ++drawable-en-notouch-12key/
    ++<strike>drawable-port-ldpi/</strike>
    ++<strike>drawable-port-notouch-12key/</strike>
    ++</pre>
    ++<p class="note"><strong>Eksepsi:</strong> Jika qualifier yang dimaksud adalah densitas piksel layar,
    ++Android akan memilih opsi yang paling cocok dengan densitas layar perangkat.
    ++Secara umum, Android lebih suka menurunkan skala gambar asli yang lebih besar daripada menaikkan skala
    ++atas gambar asli yang lebih kecil. Lihat <a href="{@docRoot}guide/practices/screens_support.html">Mendukung Beberapa
    ++Layar</a>.</p>
    ++  </li>
    ++
    ++  <li>Kembali dan ulangi langkah 2, 3, dan 4 hingga tersisa satu direktori. Dalam contoh ini, orientasi
    ++layar adalah qualifier berikutnya yang memiliki kecocokan.
    ++Jadi, sumber daya yang tidak menetapkan orientasi layar akan dihapus:
    ++<pre class="classic no-pretty-print">
    ++<strike>drawable-en/</strike>
    ++drawable-en-port/
    ++<strike>drawable-en-notouch-12key/</strike>
    ++</pre>
    ++<p>Direktori yang tersisa adalah {@code drawable-en-port}.</p>
    ++  </li>
    ++</ol>
    ++
    ++<p>Meskipun prosedur dijalankan untuk setiap sumber daya yang diminta, sistem akan mengoptimalkan beberapa aspek
    ++lebih lanjut. Satu optimalisasi tersebut adalah bahwa setelah konfigurasi perangkat diketahui, sistem mungkin
    ++akan menghapus sumber daya alternatif yang sama sekali tidak cocok. Misalnya, jika bahasa konfigurasi
    ++adalah bahasa Inggris ("en"), maka setiap direktori sumber daya yang memiliki qualifier bahasa akan diatur ke
    ++selain bahasa Inggris tidak akan pernah disertakan dalam pool sumber daya yang diperiksa (meskipun
    ++direktori sumber daya <em>tanpa</em> qualifier bahasa masih disertakan).</p>
    ++
    ++<p>Saat memilih sumber daya berdasarkan qualifier ukuran layar, sistem akan menggunakan
    ++sumber daya yang didesain untuk layar yang lebih kecil daripada layar saat ini jika tidak ada sumber daya yang lebih cocok
    ++(misalnya, layar ukuran besar akan menggunakan sumber daya layar ukuran normal jika diperlukan). Akan tetapi,
    ++jika satu-satunya sumber daya yang tersedia <em>lebih besar</em> daripada layar saat ini, sistem
    ++<strong>tidak</strong> akan menggunakannya dan aplikasi Anda akan crash jika tidak ada sumber daya lain yang cocok dengan konfigurasi
    ++perangkat (misalnya, jika semua sumber daya layout ditandai dengan qualifier {@code xlarge},
    ++namun perangkat memiliki ukuran layar normal).</p>
    ++
    ++<p class="note"><strong>Catatan:</strong> <em>Kedudukan</em> qualifier (dalam <a href="#table2">tabel 2</a>) lebih penting
    ++daripada jumlah qualifier yang benar-benar pas dengan perangkat. Misalnya, dalam langkah 4 di atas, pilihan
    ++terakhir pada daftar berisi tiga qualifier yang bebar-benar cocok dengan perangkat (orientasi, tipe
    ++layar sentuh, dan metode input), sementara <code>drawable-en</code> hanya memiliki satu parameter yang cocok
    ++(bahasa). Akan tetapi, bahasa memiliki kedudukan lebih tinggi dari pada qualifier lainnya, sehingga
    ++<code>drawable-port-notouch-12key</code> tidak masuk.</p>
    ++
    ++<p>Untuk mengetahui selengkapnya tentang cara menggunakan sumber daya dalam aplikasi, lanjutkan ke <a href="accessing-resources.html">Mengakses Sumber Daya</a>.</p>
    +diff --git a/docs/html-intl/intl/id/guide/topics/resources/runtime-changes.jd b/docs/html-intl/intl/id/guide/topics/resources/runtime-changes.jd
    +new file mode 100644
    +index 0000000..09ad60c
    +--- /dev/null
    ++++ b/docs/html-intl/intl/id/guide/topics/resources/runtime-changes.jd
    +@@ -0,0 +1,281 @@
    ++page.title=Menangani Perubahan Runtime
    ++page.tags=aktivitas,daur hidup
    ++@jd:body
    ++
    ++<div id="qv-wrapper">
    ++<div id="qv">
    ++
    ++  <h2>Dalam dokumen ini</h2>
    ++  <ol>
    ++    <li><a href="#RetainingAnObject">Mempertahankan Objek Selama Perubahan Konfigurasi</a></li>
    ++    <li><a href="#HandlingTheChange">Menangani Sendiri Perubahan Konfigurasi</a>
    ++  </ol>
    ++
    ++  <h2>Lihat juga</h2>
    ++  <ol>
    ++    <li><a href="providing-resources.html">Menyediakan Sumber Daya</a></li>
    ++    <li><a href="accessing-resources.html">Mengakses Sumber Daya</a></li>
    ++    <li><a href="http://android-developers.blogspot.com/2009/02/faster-screen-orientation-change.html">Perubahan
    ++ Orientasi Layar yang Lebih Cepat</a></li>
    ++  </ol>
    ++</div>
    ++</div>
    ++
    ++<p>Sebagian konfigurasi perangkat bisa berubah selama runtime
    ++(seperti orientasi layar, ketersediaan keyboard, dan bahasa). Saat perubahan demikian terjadi,
    ++Android akan me-restart
    ++{@link android.app.Activity} yang berjalan ({@link android.app.Activity#onDestroy()} dipanggil, diikuti oleh {@link
    ++android.app.Activity#onCreate(Bundle) onCreate()}). Perilaku restart didesain untuk membantu
    ++aplikasi Anda beradaptasi dengan konfigurasi baru melalui pemuatan kembali aplikasi Anda secara otomatis dengan
    ++sumber daya alternatif sumber yang sesuai dengan konfigurasi perangkat baru.</p>
    ++
    ++<p>Untuk menangani restart dengan benar, aktivitas Anda harus mengembalikan
    ++statusnya seperti semula melalui <a href="{@docRoot}guide/components/activities.html#Lifecycle">Daur hidup
    ++aktivitas</a> normal, dalam hal ini Android akan memanggil
    ++{@link android.app.Activity#onSaveInstanceState(Bundle) onSaveInstanceState()} sebelum menghentikan
    ++aktivitas Anda sehingga Anda dapat menyimpan data mengenai status aplikasi. Selanjutnya Anda bisa mengembalikan status
    ++selama {@link android.app.Activity#onCreate(Bundle) onCreate()} atau {@link
    ++android.app.Activity#onRestoreInstanceState(Bundle) onRestoreInstanceState()}.</p>
    ++
    ++<p>Untuk menguji bahwa aplikasi me-restart sendiri dengan status tak berubah, Anda harus
    ++memanggil perubahan konfigurasi (seperti mengubah orientasi layar) saat melakukan berbagai
    ++tugas dalam aplikasi. Aplikasi Anda harus dapat me-restart setiap saat tanpa kehilangan
    ++data pengguna atau status untuk menangani kejadian seperti perubahan konfigurasi atau bila pengguna menerima panggilan telepon
    ++masuk lalu kembali ke aplikasi setelah proses
    ++aplikasi Anda dimusnahkan. Untuk mengetahui cara mengembalikan status aktivitas, bacalah tentang <a href="{@docRoot}guide/components/activities.html#Lifecycle">Daur hidup aktivitas</a>.</p>
    ++
    ++<p>Akan tetapi, Anda mungkin menemui situasi ketika me-restart aplikasi dan
    ++mengembalikan data dalam jumlah besar malah menjadi mahal dan menghasilkan pengalaman pengguna yang buruk. Dalam situasi
    ++demikian, Anda memiliki dua opsi lain:</p>
    ++
    ++<ol type="a">
    ++  <li><a href="#RetainingAnObject">Mempertahankan objek selama perubahan konfigurasi</a>
    ++  <p>Izinkan aktivitas Anda me-restart saat konfigurasi berubah, namun bawa objek
    ++berstatus (stateful) ke instance baru aktivitas Anda.</p>
    ++
    ++  </li>
    ++  <li><a href="#HandlingTheChange">Menangani sendiri perubahan konfigurasi</a>
    ++  <p>Cegah sistem me-restart aktivitas selama perubahan konfigurasi
    ++tertentu, namun terima callback saat konfigurasi benar-benar berubah, agar Anda bisa memperbarui
    ++aktivitas secara manual bila diperlukan.</p>
    ++  </li>
    ++</ol>
    ++
    ++
    ++<h2 id="RetainingAnObject">Mempertahankan Objek Selama Perubahan Konfigurasi</h2>
    ++
    ++<p>Jika me-restart aktivitas mengharuskan pemulihan seperangkat data dalam jumlah besar, menghubungkan kembali koneksi
    ++jaringan, atau melakukan operasi intensif lainnya, maka restart penuh karena perubahan konfigurasi mungkin
    ++menjadi pengalaman pengguna yang lambat. Selain itu, Anda mungkin tidak bisa sepenuhnya mengembalikan status
    ++aktivitas dengan {@link android.os.Bundle} yang disimpan sistem untuk Anda dengan callback {@link
    ++android.app.Activity#onSaveInstanceState(Bundle) onSaveInstanceState()}&mdash;itu tidaklah
    ++didesain untuk membawa objek besar (seperti bitmap) dan data di dalamnya harus diserialkan kemudian
    ++dinon-serialkan, yang bisa menghabiskan banyak memori dan membuat perubahan konfigurasi menjadi lambat. Dalam situasi
    ++demikian, Anda bisa meringankan beban memulai kembali aktivitas Anda dengan mempertahankan {@link
    ++android.app.Fragment} saat aktivitas Anda di-restart karena perubahan konfigurasi. Fragmen ini
    ++bisa berisi acuan ke objek stateful yang ingin Anda pertahankan.</p>
    ++
    ++<p>Bila sistem Android menghentikan aktivitas Anda karena perubahan konfigurasi, fragmen
    ++aktivitas yang telah ditandai untuk dipertahankan tidak akan dimusnahkan. Anda dapat menambahkan fragmen tersebut ke
    ++aktivitas untuk mempertahankan objek stateful.</p>
    ++
    ++<p>Untuk mempertahankan objek stateful dalam fragmen selama perubahan konfigurasi runtime:</p>
    ++
    ++<ol>
    ++  <li>Perluas kelas {@link android.app.Fragment} dan deklarasikan referensi ke objek stateful
    ++Anda.</li>
    ++  <li>Panggil {@link android.app.Fragment#setRetainInstance(boolean)} saat fragmen dibuat.
    ++      </li>
    ++  <li>Tambahkan fragmen ke aktivitas.</li>
    ++  <li>Gunakan {@link android.app.FragmentManager} untuk mengambil fragmen saat aktivitas
    ++di-restart.</li>
    ++</ol>
    ++
    ++<p>Misalnya, definisikan fragmen sebagai berikut:</p>
    ++
    ++<pre>
    ++public class RetainedFragment extends Fragment {
    ++
    ++    // data object we want to retain
    ++    private MyDataObject data;
    ++
    ++    // this method is only called once for this fragment
    ++    &#64;Override
    ++    public void onCreate(Bundle savedInstanceState) {
    ++        super.onCreate(savedInstanceState);
    ++        // retain this fragment
    ++        setRetainInstance(true);
    ++    }
    ++
    ++    public void setData(MyDataObject data) {
    ++        this.data = data;
    ++    }
    ++
    ++    public MyDataObject getData() {
    ++        return data;
    ++    }
    ++}
    ++</pre>
    ++
    ++<p class="caution"><strong>Perhatian:</strong> Meskipun bisa menyimpan objek apa saja, Anda
    ++sama sekali tidak boleh meneruskan objek yang terkait dengan {@link android.app.Activity}, seperti {@link
    ++android.graphics.drawable.Drawable}, {@link android.widget.Adapter}, {@link android.view.View}
    ++atau objek lainnya mana pun yang terkait dengan {@link android.content.Context}. Jika Anda melakukannya, hal tersebut akan
    ++membocorkan semua tampilan dan sumber daya instance aktivitas semula. (Sumber daya yang bocor
    ++berarti bahwa aplikasi Anda tetap menyimpannya dan tidak bisa dijadikan kumpulan sampah, sehingga bisa banyak
    ++memori yang hilang.)</p>
    ++
    ++<p>Selanjutnya gunakan {@link android.app.FragmentManager} untuk menambahkan fragmen ke aktivitas.
    ++Anda bisa memperoleh objek data dari fragmen saat aktivitas memulai kembali selama perubahan
    ++konfigurasi runtime. Misalnya, definisikan aktivitas Anda sebagai berikut:</p>
    ++
    ++<pre>
    ++public class MyActivity extends Activity {
    ++
    ++    private RetainedFragment dataFragment;
    ++
    ++    &#64;Override
    ++    public void onCreate(Bundle savedInstanceState) {
    ++        super.onCreate(savedInstanceState);
    ++        setContentView(R.layout.main);
    ++
    ++        // find the retained fragment on activity restarts
    ++        FragmentManager fm = getFragmentManager();
    ++        dataFragment = (DataFragment) fm.findFragmentByTag(“data”);
    ++
    ++        // create the fragment and data the first time
    ++        if (dataFragment == null) {
    ++            // add the fragment
    ++            dataFragment = new DataFragment();
    ++            fm.beginTransaction().add(dataFragment, “data”).commit();
    ++            // load the data from the web
    ++            dataFragment.setData(loadMyData());
    ++        }
    ++
    ++        // the data is available in dataFragment.getData()
    ++        ...
    ++    }
    ++
    ++    &#64;Override
    ++    public void onDestroy() {
    ++        super.onDestroy();
    ++        // store the data in the fragment
    ++        dataFragment.setData(collectMyLoadedData());
    ++    }
    ++}
    ++</pre>
    ++
    ++<p>Dalam contoh ini, {@link android.app.Activity#onCreate(Bundle) onCreate()} menambahkan fragmen
    ++atau mengembalikan referensinya. {@link android.app.Activity#onCreate(Bundle) onCreate()} juga
    ++menyimpan objek stateful dalam instance fragmen.
    ++{@link android.app.Activity#onDestroy() onDestroy()} akan memperbarui objek stateful dalam
    ++instance fragmen yang dipertahankan.</p>
    ++
    ++
    ++
    ++
    ++
    ++<h2 id="HandlingTheChange">Menangani Sendiri Perubahan Konfigurasi</h2>
    ++
    ++<p>Jika aplikasi Anda tidak memerlukan pembaruan sumber daya selama perubahan konfigurasi
    ++tertentu <em>dan</em> Anda memiliki keterbatasan kinerja yang mengharuskan Anda untuk
    ++menghindari restart aktivitas, maka Anda bisa mendeklarasikan agar aktivitas Anda menangani sendiri perubahan
    ++konfigurasinya, sehingga mencegah sistem me-restart aktivitas.</p>
    ++
    ++<p class="note"><strong>Catatan:</strong> Menangani sendiri perubahan konfigurasi bisa jauh lebih
    ++mempersulit penggunaan sumber daya alternatif, karena sistem tidak menerapkannya secara otomatis
    ++untuk Anda. Teknik ini harus dianggap sebagai usaha terakhir bila Anda harus menghindari restart
    ++karena perubahan konfigurasi dan tidak disarankan untuk sebagian besar aplikasi.</p>
    ++
    ++<p>Untuk mendeklarasikan agar aktivitas Anda menangani perubahan konfigurasi, edit elemen <a href="{@docRoot}guide/topics/manifest/activity-element.html">{@code &lt;activity&gt;}</a> yang sesuai
    ++dalam file manifes Anda agar menyertakan atribut <a href="{@docRoot}guide/topics/manifest/activity-element.html#config">{@code
    ++android:configChanges}</a> dengan nilai yang mewakili konfigurasi yang ingin
    ++ditangani. Nilai yang memungkinkan tercantum dalam dokumentasi untuk atribut <a href="{@docRoot}guide/topics/manifest/activity-element.html#config">{@code
    ++android:configChanges}</a> (nilai paling sering digunakan adalah {@code "orientation"} untuk
    ++mencegah restart saat orientasi layar berubah dan {@code "keyboardHidden"} untuk mencegah
    ++restart saat ketersediaan keyboard berubah).  Anda dapat mendeklarasikan beberapa nilai konfigurasi
    ++dalam atribut dengan memisahkannya menggunakan karakter pipa {@code |}.</p>
    ++
    ++<p>Misalnya, kode manifes berikut menyatakan aktivitas yang menangani
    ++perubahan orientasi layar maupun perubahan ketersediaan keyboard:</p>
    ++
    ++<pre>
    ++&lt;activity android:name=".MyActivity"
    ++          android:configChanges="orientation|keyboardHidden"
    ++          android:label="@string/app_name">
    ++</pre>
    ++
    ++<p>Sekarang, bila salah satu konfigurasi ini berubah, {@code MyActivity} tidak akan me-restart.
    ++Sebagai gantinya, {@code MyActivity} akan menerima panggilan ke {@link
    ++android.app.Activity#onConfigurationChanged(Configuration) onConfigurationChanged()}. Metode ini
    ++meneruskan objek {@link android.content.res.Configuration} yang menetapkan
    ++konfigurasi perangkat baru. Dengan membaca bidang-bidang dalam {@link android.content.res.Configuration},
    ++Anda dapat menentukan konfigurasi baru dan membuat perubahan yang sesuai dengan memperbarui
    ++sumber daya yang digunakan dalam antarmuka. Pada saat
    ++metode ini dipanggil, objek {@link android.content.res.Resources} aktivitas Anda akan diperbarui untuk
    ++mengembalikan sumber daya berdasarkan konfigurasi baru, jadi Anda bisa dengan mudah
    ++me-reset elemen UI tanpa membuat sistem me-restart aktivitas Anda.</p>
    ++
    ++<p class="caution"><strong>Perhatian:</strong> Mulai Android 3.2 (API level 13), <strong>
    ++"ukuran layar" juga berubah</strong> bila perangkat beralih orientasi antara potret
    ++dan lanskap. Jadi jika Anda tidak ingin runtime di-restart karena perubahan orientasi saat mengembangkan
    ++API level 13 atau yang lebih tinggi (sebagaimana dideklarasikan oleh atribut <a href="{@docRoot}guide/topics/manifest/uses-sdk-element.html#min">{@code minSdkVersion}</a> dan <a href="{@docRoot}guide/topics/manifest/uses-sdk-element.html#target">{@code targetSdkVersion}</a>
    ++), Anda harus menyertakan nilai {@code "screenSize"} selain nilai {@code
    ++"orientation"}. Yaitu Anda harus mendeklarasikan {@code
    ++android:configChanges="orientation|screenSize"}. Akan tetapi, jika aplikasi Anda menargetkan API level
    ++12 atau yang lebih rendah, maka aktivitas Anda akan selalu menangani sendiri perubahan konfigurasi ini (perubahan
    ++konfigurasi ini tidak me-restart aktivitas Anda, bahkan saat berjalan pada perangkat Android 3.2 atau yang lebih tinggi).</p>
    ++
    ++<p>Misalnya, implementasi {@link
    ++android.app.Activity#onConfigurationChanged(Configuration) onConfigurationChanged()} berikut akan
    ++memeriksa orientasi perangkat saat ini:</p>
    ++
    ++<pre>
    ++&#64;Override
    ++public void onConfigurationChanged(Configuration newConfig) {
    ++    super.onConfigurationChanged(newConfig);
    ++
    ++    // Checks the orientation of the screen
    ++    if (newConfig.orientation == Configuration.ORIENTATION_LANDSCAPE) {
    ++        Toast.makeText(this, "landscape", Toast.LENGTH_SHORT).show();
    ++    } else if (newConfig.orientation == Configuration.ORIENTATION_PORTRAIT){
    ++        Toast.makeText(this, "portrait", Toast.LENGTH_SHORT).show();
    ++    }
    ++}
    ++</pre>
    ++
    ++<p>Objek {@link android.content.res.Configuration} mewakili semua konfigurasi
    ++saat ini, tidak hanya konfigurasi yang telah berubah. Seringkali Anda tidak perlu memperhatikan dengan persis bagaimana
    ++konfigurasi berubah dan cukup menetapkan kembali semua sumber daya yang memberikan alternatif untuk
    ++konfigurasi sedang ditangani. Misalnya, karena objek {@link
    ++android.content.res.Resources} sekarang diperbarui, Anda dapat me-reset
    ++setiap {@link android.widget.ImageView} dengan {@link android.widget.ImageView#setImageResource(int)
    ++setImageResource()}
    ++dan sumber daya yang sesuai untuk konfigurasi baru yang digunakan (seperti dijelaskan dalam <a href="providing-resources.html#AlternateResources">Menyediakan Sumber Daya</a>).</p>
    ++
    ++<p>Perhatikan bahwa nilai-nilai dari bidang {@link
    ++android.content.res.Configuration} adalah integer yang sesuai dengan konstanta spesifik
    ++dari kelas {@link android.content.res.Configuration}. Untuk dokumentasi tentang konstanta
    ++yang harus digunakan di setiap bidang, lihat bidang yang sesuai dalam referensi {@link
    ++android.content.res.Configuration}.</p>
    ++
    ++<p class="note"><strong>Ingatlah:</strong> Saat mendeklarasikan aktivitas untuk menangani perubahan
    ++konfigurasi, Anda bertanggung jawab untuk me-reset setiap elemen yang alternatifnya Anda berikan. Jika Anda
    ++mendeklarasikan aktivitas untuk menangani perubahan orientasi dan memiliki gambar yang harus berubah
    ++antara lanskap dan potret, Anda harus menetapkan kembali setiap sumber daya elemen selama {@link
    ++android.app.Activity#onConfigurationChanged(Configuration) onConfigurationChanged()}.</p>
    ++
    ++<p>Jika Anda tidak perlu memperbarui aplikasi berdasarkan perubahan
    ++konfigurasi ini, sebagai gantinya Anda bisa saja <em>tidak</em> mengimplementasikan {@link
    ++android.app.Activity#onConfigurationChanged(Configuration) onConfigurationChanged()}. Dalam
    ++hal ini, semua sumber daya yang digunakan sebelum perubahan konfigurasi akan tetap digunakan
    ++dan Anda hanya menghindari restart aktivitas. Akan tetapi, aplikasi Anda harus selalu
    ++bisa dimatikan dan di-restart dengan status sebelumnya tetap utuh, sehingga Anda jangan menganggap teknik
    ++ini sebagai jalan keluar untuk mempertahankan status selama daur hidup aktivitas normal. Tidak hanya
    ++karena ada perubahan konfigurasi lainnya yang tidak bisa Anda cegah untuk me-restart aplikasi, namun
    ++juga karena Anda harus menangani kejadian seperti saat pengguna meninggalkan aplikasi dan
    ++dimusnahkan sebelum pengguna kembali ke aplikasi.</p>
    ++
    ++<p>Untuk informasi selengkapnya tentang perubahan konfigurasi yang bisa Anda tangani dalam aktivitas, lihat dokumentasi <a href="{@docRoot}guide/topics/manifest/activity-element.html#config">{@code
    ++android:configChanges}</a> dan kelas {@link android.content.res.Configuration}
    ++.</p>
    +diff --git a/docs/html-intl/intl/id/guide/topics/ui/controls.jd b/docs/html-intl/intl/id/guide/topics/ui/controls.jd
    +new file mode 100644
    +index 0000000..3ebf48b
    +--- /dev/null
    ++++ b/docs/html-intl/intl/id/guide/topics/ui/controls.jd
    +@@ -0,0 +1,90 @@
    ++page.title=Kontrol Input
    ++parent.title=Antarmuka Pengguna
    ++parent.link=index.html
    ++@jd:body
    ++
    ++<div class="figure" style="margin:0">
    ++  <img src="{@docRoot}images/ui/ui-controls.png" alt="" style="margin:0" />
    ++</div>
    ++
    ++<p>Kontrol input adalah komponen interaktif dalam antarmuka pengguna aplikasi Anda. Android menyediakan
    ++aneka ragam kontrol yang bisa Anda gunakan dalam UI, seperti tombol, bidang teks, bilah pencarian,
    ++kotak cek, tombol zoom, tombol toggle, dan masih banyak lagi.</p>
    ++
    ++<p>Menambahkan sebuah kontrol input ke UI adalah semudah menambahkan satu elemen XML ke <a href="{@docRoot}guide/topics/ui/declaring-layout.html">layout XML</a>. Misalnya, inilah sebuah
    ++layout dengan satu bidang teks dan satu tombol:</p>
    ++
    ++<pre style="clear:right">
    ++&lt;?xml version="1.0" encoding="utf-8"?>
    ++&lt;LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    ++    android:layout_width="fill_parent"
    ++    android:layout_height="fill_parent"
    ++    android:orientation="horizontal">
    ++    &lt;EditText android:id="@+id/edit_message"
    ++        android:layout_weight="1"
    ++        android:layout_width="0dp"
    ++        android:layout_height="wrap_content"
    ++        android:hint="@string/edit_message" />
    ++    &lt;Button android:id="@+id/button_send"
    ++        android:layout_width="wrap_content"
    ++        android:layout_height="wrap_content"
    ++        android:text="@string/button_send"
    ++        android:onClick="sendMessage" />
    ++&lt;/LinearLayout>
    ++</pre>
    ++
    ++<p>Tiap kontrol input mendukung satu set kejadian input sehingga Anda bisa menangani berbagai kejadian seperti saat
    ++pengguna memasukkan teks atau menyentuh tombol.</p>
    ++
    ++
    ++<h2 id="CommonControls">Kontrol Umum</h2>
    ++<p>Berikut adalah daftar beberapa kontrol umum yang bisa Anda gunakan dalam aplikasi. Ikuti tautan ini untuk mengetahui
    ++selengkapnya tentang penggunaannya masing-masing.</p>
    ++
    ++<p class="note"><strong>Catatan:</strong> Android menyediakan beberapa kontrol lain yang tidak tercantum
    ++di sini. Telusuri paket {@link android.widget} untuk mengetahui selengkapnya. Jika aplikasi Anda memerlukan
    ++semacam kontrol input tertentu, Anda bisa membangun <a href="{@docRoot}guide/topics/ui/custom-components.html">komponen custom</a> sendiri.</p>
    ++
    ++<table>
    ++    <tr>
    ++        <th scope="col">Tipe Kontrol</th>
    ++        <th scope="col">Keterangan</th>
    ++	<th scope="col">Kelas Terkait</th>
    ++    </tr>
    ++    <tr>
    ++        <td><a href="controls/button.html">Tombol</a></td>
    ++        <td>Tombol tekan yang bisa ditekan, atau diklik, oleh pengguna untuk melakukan suatu tindakan.</td>
    ++	<td>{@link android.widget.Button Button} </td>
    ++    </tr>
    ++    <tr>
    ++        <td><a href="controls/text.html">Bidang teks</a></td>
    ++        <td>Bidang teks yang bisa diedit. Anda bisa menggunakan widget <code>AutoCompleteTextView</code> untuk membuat widget entri teks yang menyediakan saran pelengkapan otomatis</td>
    ++	<td>{@link android.widget.EditText EditText}, {@link android.widget.AutoCompleteTextView}</td>
    ++    </tr>
    ++    <tr>
    ++        <td><a href="controls/checkbox.html">Kotak cek</a></td>
    ++        <td>Switch aktif/nonaktif yang bisa diubah oleh pengguna. Anda harus menggunakan kotak cek saat menampilkan sekumpulan opsi yang bisa dipilih pengguna dan bila keduanya mungkin terjadi bersamaan.</td>
    ++	<td>{@link android.widget.CheckBox CheckBox} </td>
    ++    </tr>
    ++    <tr>
    ++        <td><a href="controls/radiobutton.html">Tombol radio</a></td>
    ++        <td>Mirip dengan kotak cek, hanya saja cuma satu opsi yang bisa dipilih dalam kumpulan tersebut.</td>
    ++	<td>{@link android.widget.RadioGroup RadioGroup}
    ++	<br>{@link android.widget.RadioButton RadioButton} </td>
    ++    </tr>
    ++    <tr>
    ++        <td><a href="controls/togglebutton.html" style="white-space:nowrap">Tombol toggle</a></td>
    ++        <td>Tombol aktif/nonaktif dengan indikator cahaya.</td>
    ++	<td>{@link android.widget.ToggleButton ToggleButton} </td>
    ++    </tr>
    ++    <tr>
    ++        <td><a href="controls/spinner.html">Spinner</a></td>
    ++        <td>Daftar tarik-turun yang memungkinkan pengguna memilih salah satu dari serangkaian nilai.</td>
    ++	<td>{@link android.widget.Spinner Spinner} </td>
    ++    </tr>
    ++    <tr>
    ++        <td><a href="controls/pickers.html">Picker</a></td>
    ++        <td>Dialog bagi pengguna untuk memilih satu nilai dari satu kumpulan dengan menggunakan tombol naik/turun atau dengan gerakan mengusap. Gunakan widget <code>DatePicker</code>code&gt; untuk memasukkan nilai tanggal (bulan, hari, tahun) atau widget <code>TimePicker</code> untuk memasukkan nilai waktu (jam, menit, AM/PM), yang akan diformat secara otomatis untuk lokasi pengguna tersebut.</td>
    ++	<td>{@link android.widget.DatePicker}, {@link android.widget.TimePicker}</td>
    ++    </tr>
    ++</table>
    +diff --git a/docs/html-intl/intl/id/guide/topics/ui/declaring-layout.jd b/docs/html-intl/intl/id/guide/topics/ui/declaring-layout.jd
    +new file mode 100644
    +index 0000000..1c8a0d6
    +--- /dev/null
    ++++ b/docs/html-intl/intl/id/guide/topics/ui/declaring-layout.jd
    +@@ -0,0 +1,492 @@
    ++page.title=Layout
    ++page.tags=view,viewgroup
    ++@jd:body
    ++
    ++<div id="qv-wrapper">
    ++<div id="qv">
    ++  <h2>Dalam dokumen ini</h2>
    ++<ol>
    ++  <li><a href="#write">Tulis XML</a></li>
    ++  <li><a href="#load">Muat Sumber Daya XML</a></li>
    ++  <li><a href="#attributes">Atribut</a>
    ++    <ol>
    ++      <li><a href="#id">ID</a></li>
    ++      <li><a href="#layout-params">Parameter Layout</a></li>
    ++    </ol>
    ++  </li>
    ++  <li><a href="#Position">Posisi Layout</a></li>
    ++  <li><a href="#SizePaddingMargins">Ukuran, Pengisi, dan Margin</a></li>
    ++  <li><a href="#CommonLayouts">Layout Umum</a></li>
    ++  <li><a href="#AdapterViews">Membangun Layout dengan Adaptor</a>
    ++    <ol>
    ++      <li><a href="#FillingTheLayout">Mengisi tampilan adaptor dengan data</a></li>
    ++      <li><a href="#HandlingUserSelections">Menangani kejadian klik</a></li>
    ++    </ol>
    ++  </li>
    ++</ol>
    ++
    ++  <h2>Kelas-kelas utama</h2>
    ++  <ol>
    ++    <li>{@link android.view.View}</li>
    ++    <li>{@link android.view.ViewGroup}</li>
    ++    <li>{@link android.view.ViewGroup.LayoutParams}</li>
    ++  </ol>
    ++
    ++  <h2>Lihat juga</h2>
    ++  <ol>
    ++    <li><a href="{@docRoot}training/basics/firstapp/building-ui.html">Membangun Antarmuka Pengguna
    ++Sederhana</a></li> </div>
    ++</div>
    ++
    ++<p>Layout mendefinisikan struktur visual untuk antarmuka pengguna, seperti UI sebuah <a href="{@docRoot}guide/components/activities.html">aktivitas</a> atau <a href="{@docRoot}guide/topics/appwidgets/index.html">widget aplikasi</a>.
    ++Anda dapat mendeklarasikan layout dengan dua cara:</p>
    ++<ul>
    ++<li><strong>Deklarasikan elemen UI dalam XML</strong>. Android menyediakan sebuah kosakata XML
    ++sederhana yang sesuai dengan kelas dan subkelas View, seperti halnya untuk widget dan layout.</li>
    ++<li><strong>Buat instance elemen layout saat runtime</strong>. Aplikasi Anda
    ++bisa membuat objek View dan ViewGroup (dan memanipulasi propertinya) lewat program. </li>
    ++</ul>
    ++
    ++<p>Kerangka kerja Android memberi Anda fleksibilitas untuk menggunakan salah satu atau kedua metode ini guna mendeklarasikan dan mengelola UI aplikasi Anda. Misalnya, Anda bisa mendeklarasikan layout default aplikasi Anda dalam XML, termasuk elemen-elemen layar yang akan muncul di dalamnya dan di propertinya. Anda nanti bisa menambahkan kode dalam aplikasi yang akan memodifikasi status objek layar, termasuk yang dideklarasikan dalam XML, saat runtime. </p>
    ++
    ++<div class="sidebox-wrapper">
    ++<div class="sidebox">
    ++  <ul>
    ++  <li><a href="{@docRoot}tools/sdk/eclipse-adt.html">ADT
    ++  Plugin for Eclipse</a> menawarkan preview layout XML &mdash;
    ++ Anda dengan file XML yang dibuka, pilih tab <strong>Layout</strong>.</li>
    ++  <li>Anda juga harus mencoba alat
    ++  <a href="{@docRoot}tools/debugging/debugging-ui.html#hierarchyViewer">Hierarchy Viewer</a>,
    ++ untuk merunut layout &mdash; alat ini akan menampilkan nilai-nilai properti layout,
    ++  menggambar bentuk kerangka dengan indikator pengisi/margin, dan tampilan yang dirender penuh selagi
    ++  Anda merunut pada emulator atau perangkat.</li>
    ++  <li>Alat <a href="{@docRoot}tools/debugging/debugging-ui.html#layoutopt">layoutopt</a> memungkinkan
    ++  Anda menganalisis layout dan hierarki dengan untuk mengetahui ketidakefisienan atau masalah lainnya.</li>
    ++</div>
    ++</div>
    ++
    ++<p>Keuntungan mendeklarasikan UI dalam XML adalah karena hal ini memungkinkan Anda memisahkan penampilan aplikasi dari kode yang mengontrol perilakunya dengan lebih baik. Keterangan UI Anda bersifat eksternal bagi kode aplikasi Anda, yang berarti bahwa Anda bisa memodifikasi atau menyesuaikannya tanpa harus memodifikasi dan mengompilasi ulang kode sumber. Misalnya, Anda bisa membuat layout XML untuk berbagai orientasi layar, berbagai ukuran layar perangkat, dan berbagai bahasa. Selain itu, mendeklarasikan layout dalam XML akan mempermudah Anda memvisualisasikan struktur UI, sehingga lebih mudah merunut masalahnya. Karena itu, dokumen ini berfokus pada upaya mengajari Anda cara mendeklarasikan layout dalam XML. Jika Anda
    ++tertarik dalam membuat instance objek View saat runtime, lihat referensi kelas {@link android.view.ViewGroup} dan
    ++{@link android.view.View}.</p>
    ++
    ++<p>Secara umum, kosakata XML untuk mendeklarasikan elemen UI mengikuti dengan sangat mirip struktur serta penamaan kelas dan metode, dengan nama elemen dipadankan dengan nama kelas dan nama atribut dipadankan dengan metode. Sebenarnya, pemadanan ini kerap kali begitu jelas sehingga Anda bisa menebak atribut XML yang berpadanan dengan sebuah metode kelas, atau menebak kelas yang berpadanan dengan sebuah elemen XML. Akan tetapi, perhatikan bahwa tidak semua kosakata identik. Dalam beberapa kasus, ada sedikit perbedaan penamaan. Misalnya
    ++, elemen EditText memiliki atribut <code>text</code> yang berpadanan dengan
    ++<code>EditText.setText()</code>. </p>
    ++
    ++<p class="note"><strong>Tip:</strong> Ketahui selengkapnya berbagai tipe layout dalam <a href="{@docRoot}guide/topics/ui/layout-objects.html">Objek
    ++Layout Umum</a>. Ada juga sekumpulan tutorial tentang cara membangun berbagai layout dalam panduan tutorial
    ++<a href="{@docRoot}resources/tutorials/views/index.html">Hello Views</a>.</p>
    ++
    ++<h2 id="write">Tulis XML</h2>
    ++
    ++<p>Dengan menggunakan kosakata XML Android, Anda bisa mendesain secara cepat layout UI dan elemen layar yang dimuatnya, sama dengan cara membuat halaman web dalam HTML &mdash; dengan serangkaian elemen tersarang. </p>
    ++
    ++<p>Tiap file layout harus berisi persis satu elemen akar, yang harus berupa sebuah objek View atau ViewGroup. Setelah mendefinisikan elemen akar, Anda bisa menambahkan objek atau widget layout tambahan sebagai elemen anak untuk membangun hierarki View yang mendefinisikan layout Anda secara bertahap. Misalnya, inilah layout XML yang menggunakan {@link android.widget.LinearLayout}
    ++vertikal untuk menyimpan {@link android.widget.TextView} dan {@link android.widget.Button}:</p>
    ++<pre>
    ++&lt;?xml version="1.0" encoding="utf-8"?>
    ++&lt;LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    ++              android:layout_width="match_parent"
    ++              android:layout_height="match_parent"
    ++              android:orientation="vertical" >
    ++    &lt;TextView android:id="@+id/text"
    ++              android:layout_width="wrap_content"
    ++              android:layout_height="wrap_content"
    ++              android:text="Hello, I am a TextView" />
    ++    &lt;Button android:id="@+id/button"
    ++            android:layout_width="wrap_content"
    ++            android:layout_height="wrap_content"
    ++            android:text="Hello, I am a Button" />
    ++&lt;/LinearLayout>
    ++</pre>
    ++
    ++<p>Setelah Anda mendeklarasikan layout dalam XML, simpanlah file dengan ekstensi <code>.xml</code>,
    ++dalam direktori <code>res/layout/</code> proyek Android, sehingga nanti bisa dikompilasi dengan benar. </p>
    ++
    ++<p>Informasi selengkapnya tentang sintaks untuk file XML layout tersedia dalam dokumen <a href="{@docRoot}guide/topics/resources/layout-resource.html">Sumber Daya Layout</a>.</p>
    ++
    ++<h2 id="load">Muat Sumber Daya XML</h2>
    ++
    ++<p>Saat mengompilasi aplikasi, masing-masing file layout XML akan dikompilasi dalam sebuah sumber daya
    ++{@link android.view.View}. Anda harus memuat sumber daya layout dari kode aplikasi, dalam implementasi
    ++callback {@link android.app.Activity#onCreate(android.os.Bundle) Activity.onCreate()}.
    ++Lakukan dengan memanggil <code>{@link android.app.Activity#setContentView(int) setContentView()}</code>,
    ++dengan meneruskan acuan ke sumber daya layout berupa:
    ++<code>R.layout.<em>layout_file_name</em></code>.
    ++Misalnya, jika XML layout Anda disimpan sebagai <code>main_layout.xml</code>, Anda akan memuatnya
    ++untuk Activity seperti ini:</p>
    ++<pre>
    ++public void onCreate(Bundle savedInstanceState) {
    ++    super.onCreate(savedInstanceState);
    ++    setContentView(R.layout.main_layout);
    ++}
    ++</pre>
    ++
    ++<p>Metode callback <code>onCreate()</code> dalam Activity dipanggil oleh kerangka kerja Android saat
    ++Activity Anda dijalankan (lihat diskusi tentang daur hidup, dalam dokumen
    ++<a href="{@docRoot}guide/components/activities.html#Lifecycle">Aktivitas</a>
    ++).</p>
    ++
    ++
    ++<h2 id="attributes">Atribut</h2>
    ++
    ++<p>Setiap objek View dan ViewGroup mendukung variasi atribut XML-nya sendiri.
    ++Sebagian atribut bersifat spesifik untuk objek View (misalnya, TextView mendukung atribut <code>textSize</code>
    ++), namun atribut ini juga diwarisi oleh sembarang objek View yang dapat memperluas kelas ini.
    ++Sebagian atribut bersifat umum untuk semua objek View, karena diwarisi dari kelas View akar (seperti
    ++atribut <code>id</code>). Dan, atribut lain dianggap sebagai "parameter layout" yaitu
    ++atribut yang menjelaskan orientasi layout tertentu dari objek View, seperti yang didefinisikan oleh objek ViewGroup induk
    ++dari objek itu.</p>
    ++
    ++<h3 id="id">ID</h3>
    ++
    ++<p>Objek View apa saja dapat memiliki ID integer yang dikaitkan dengannya, untuk mengidentifikasi secara unik View dalam pohon.
    ++Bila aplikasi dikompilasi, ID ini akan diacu sebagai integer, namun ID biasanya
    ++ditetapkan dalam file XML layout sebagai string, dalam atribut <code>id</code>.
    ++Ini atribut XML yang umum untuk semua objek View
    ++(yang didefinisikan oleh kelas {@link android.view.View}) dan Anda akan sering sekali menggunakannya.
    ++Sintaks untuk ID dalam tag XML adalah:</p>
    ++<pre>android:id="&#64;+id/my_button"</pre>
    ++
    ++<p>Simbol "at" (@) pada awal string menunjukkan parser XML harus mengurai dan memperluas
    ++ID string selebihnya dan mengenalinya sebagai ID sumber daya. Simbol tanda tambah (+) berarti ini nama sumber daya baru yang harus
    ++dibuat dan ditambahkan ke sumber daya kita (dalam file <code>R.java</code>). Ada sejumlah sumber daya ID lain yang
    ++ditawarkan oleh kerangka kerja Android. Saat mengacu sebuah ID sumber daya Android, Anda tidak memerlukan simbol tanda tambah,
    ++namun harus menambahkan namespace paket <code>android</code>, sehingga:</p>
    ++<pre>android:id="&#64;android:id/empty"</pre>
    ++<p>Dengan namespace paket <code>android</code> yang tersedia, kita sekarang mengacu ID dari kelas sumber daya <code>android.R</code>
    ++, daripada kelas sumber daya lokal.</p>
    ++
    ++<p>Untuk membuat tampilan dan mengacunya dari aplikasi, pola yang umum adalah:</p>
    ++<ol>
    ++  <li>Mendefinisikan tampilan/widget dalam file layout dan memberinya ID unik:
    ++<pre>
    ++&lt;Button android:id="&#64;+id/my_button"
    ++        android:layout_width="wrap_content"
    ++        android:layout_height="wrap_content"
    ++        android:text="&#64;string/my_button_text"/>
    ++</pre>
    ++  </li>
    ++  <li>Kemudian buat instance objek tampilan dan tangkap instance itu dari layout
    ++(biasanya dalam metode <code>{@link android.app.Activity#onCreate(Bundle) onCreate()}</code>):
    ++<pre>
    ++Button myButton = (Button) findViewById(R.id.my_button);
    ++</pre>
    ++  </li>
    ++</ol>
    ++<p>Mendefinisikan ID untuk objek tampilan adalah penting saat membuat {@link android.widget.RelativeLayout}.
    ++Dalam layout relatif, tampilan saudara bisa mendefinisikan layout secara relatif terhadap tampilan saudara lainnya,
    ++yang diacu melalui ID unik.</p>
    ++<p>ID tidak perlu unik di seluruh pohon, namun harus
    ++unik di bagian pohon yang Anda cari (yang mungkin sering kali seluruh pohon, jadi lebih baik
    ++benar-benar unik bila memungkinkan).</p>
    ++
    ++
    ++<h3 id="layout-params">Parameter Layout</h3>
    ++
    ++<p>Atribut layout XML bernama <code>layout_<em>something</em></code> mendefinisikan
    ++parameter layout View yang cocok untuk ViewGroup tempatnya berada.</p>
    ++
    ++<p>Setiap kelas ViewGroup mengimplementasikan kelas tersarang yang memperluas {@link
    ++android.view.ViewGroup.LayoutParams}. Subkelas ini
    ++berisi tipe properti yang mendefinisikan ukuran dan posisi masing-masing tampilan anak, sebagaimana
    ++mestinya untuk grup tampilan. Seperti yang bisa Anda lihat dalam gambar 1,
    ++grup tampilan induk mendefinisikan parameter layout untuk masing-masing tampilan anak (termasuk grup tampilan anak).</p>
    ++
    ++<img src="{@docRoot}images/layoutparams.png" alt="" />
    ++<p class="img-caption"><strong>Gambar 1.</strong> Visualisasi hierarki tampilan dengan parameter layout
    ++yang dikaitkan dengan tiap tampilan.</p>
    ++
    ++<p>Perhatikan bahwa setiap subkelas LayoutParams memiliki sintaksnya sendiri untuk menetapkan
    ++nilai-nilai. Tiap elemen anak harus mendefinisikan LayoutParams yang semestinya bagi induknya,
    ++meskipun elemen itu bisa juga mendefinisikan LayoutParams untuk anak-anaknya sendiri. </p>
    ++
    ++<p>Semua grup tampilan berisi lebar dan tinggi (<code>layout_width</code> dan
    ++<code>layout_height</code>), dan masing-masing tampilan harus mendefinisikannya. Banyak
    ++LayoutParams yang juga menyertakan margin dan border opsional. <p>
    ++
    ++<p>Anda bisa menetapkan lebar dan tinggi dengan ukuran persis, meskipun Anda mungkin
    ++tidak ingin sering-sering melakukannya. Lebih sering, Anda akan menggunakan salah satu konstanta ini untuk
    ++mengatur lebar atau tinggi: </p>
    ++
    ++<ul>
    ++  <li><var>wrap_content</var> memberi tahu tampilan Anda agar menyesuaikan sendiri ukurannya dengan dimensi
    ++yang dibutuhkan oleh isinya.</li>
    ++  <li><var>match_parent</var> (bernama <var>fill_parent</var> sebelum API Level 8)
    ++memberi tahu tampilan Anda agar menjadi sebesar yang diperbolehkan oleh grup tampilan induknya.</li>
    ++</ul>
    ++
    ++<p>Secara umum, menetapkan lebar dan tinggi layout dengan satuan mutlak seperti
    ++piksel tidaklah disarankan. Melainkan dengan menggunakan ukuran relatif seperti
    ++satuan piksel yang tidak bergantung pada kerapatan (<var>dp</var>), <var>wrap_content</var>, atau
    ++<var>match_parent</var>, adalah sebuah pendekatan yang lebih baik, karena membantu memastikan bahwa
    ++aplikasi Anda akan ditampilkan dengan benar pada berbagai ukuran layar perangkat.
    ++Tipe ukuran yang diterima didefinisikan dalam dokumen
    ++<a href="{@docRoot}guide/topics/resources/available-resources.html#dimension">
    ++Sumber Daya yang Tersedia</a>.</p>
    ++
    ++
    ++<h2 id="Position">Posisi Layout</h2>
    ++   <p>
    ++   Geometri tampilan adalah persegi panjang. Sebuah tampilan memiliki lokasi,
    ++   yang dinyatakan berupa sepasang koordinat <em>kiri</em> dan <em>atas</em>, dan
    ++   dua dimensi, yang dinyatakan berupa lebar dan tinggi. Satuan untuk lokasi
    ++   dan dimensi adalah piksel.
    ++   </p>
    ++
    ++   <p>
    ++   Lokasi tampilan dapat diambil dengan memanggil metode
    ++   {@link android.view.View#getLeft()} dan {@link android.view.View#getTop()}. Metode terdahulu menghasilkan koordinat kiri, atau X,
    ++   persegi panjang yang mewakili tampilan. Metode selanjutnya menghasilkan koordinat
    ++   atas, atau Y, persegi panjang yang mewakili tampilan. Kedua metode ini
    ++   menghasilkan lokasi tampilan relatif terhadap induknya. Misalnya,
    ++   bila <code>getLeft()</code> menghasilkan 20, berarti tampilan berlokasi 20 piksel ke
    ++   kanan dari tepi kiri induk langsungnya.
    ++   </p>
    ++
    ++   <p>
    ++   Selain itu, beberapa metode praktis ditawarkan untuk menghindari komputasi yang tidak perlu,
    ++   yakni {@link android.view.View#getRight()} dan {@link android.view.View#getBottom()}.
    ++   Kedua metode ini menghasilkan koordinat tepi kanan dan bawah
    ++   persegi panjang yang mewakili tampilan. Misalnya, memanggil {@link android.view.View#getRight()}
    ++   serupa dengan komputasi berikut: <code>getLeft() + getWidth()</code>.
    ++   </p>
    ++
    ++
    ++<h2 id="SizePaddingMargins">Ukuran, Pengisi, dan Margin</h2>
    ++   <p>
    ++   Ukuran tampilan dinyatakan dengan lebar dan tinggi. Tampilan sebenarnya
    ++   memiliki dua pasang nilai lebar dan tinggi.
    ++   </p>
    ++
    ++   <p>
    ++   Sepasang pertama disebut <em>lebar terukur</em> dan
    ++   <em>tinggi terukur</em>. Dimensi ini mendefinisikan seberapa besar tampilan yang diinginkan
    ++   dalam induknya. Dimensi
    ++   terukur bisa diperoleh dengan memanggil {@link android.view.View#getMeasuredWidth()}
    ++   dan {@link android.view.View#getMeasuredHeight()}.
    ++   </p>
    ++
    ++   <p>
    ++   Sepasang kedua cukup disebut dengan <em>lebar</em> dan <em>tinggi</em>, atau
    ++   kadang-kadang <em>lebar penggambaran</em> dan <em>tinggi penggambaran</em>. Dimensi-dimensi ini
    ++   mendefinisikan ukuran tampilan sebenarnya pada layar, saat digambar dan
    ++   setelah layout. Nilai-nilai ini mungkin, namun tidak harus, berbeda dengan
    ++   lebar dan tinggi terukur. Lebar dan tinggi bisa diperoleh dengan memanggil
    ++   {@link android.view.View#getWidth()} dan {@link android.view.View#getHeight()}.
    ++   </p>
    ++
    ++   <p>
    ++   Untuk mengukur dimensinya, tampilan akan memperhitungkan pengisinya (padding). Pengisi
    ++   dinyatakan dalam piksel untuk bagian kiri, atas, kanan, dan bawah tampilan.
    ++   Pengisi bisa digunakan untuk meng-offset isi tampilan dengan
    ++   piksel dalam jumlah tertentu. Misalnya, pengisi kiri sebesar 2 akan mendorong isi tampilan sebanyak
    ++   2 piksel ke kanan dari tepi kiri. Pengisi bisa diatur menggunakan
    ++   metode {@link android.view.View#setPadding(int, int, int, int)} dan diketahui dengan memanggil
    ++   {@link android.view.View#getPaddingLeft()}, {@link android.view.View#getPaddingTop()},
    ++   {@link android.view.View#getPaddingRight()}, dan {@link android.view.View#getPaddingBottom()}.
    ++   </p>
    ++
    ++   <p>
    ++   Meskipun bisa mendefinisikan pengisi, tampilan tidak menyediakan dukungan untuk
    ++   margin. Akan tetapi, grup tampilan menyediakan dukungan tersebut. Lihat
    ++   {@link android.view.ViewGroup} dan
    ++   {@link android.view.ViewGroup.MarginLayoutParams} untuk informasi lebih jauh.
    ++   </p>
    ++
    ++   <p>Untuk informasi selengkapnya tentang dimensi, lihat
    ++   <a href="{@docRoot}guide/topics/resources/more-resources.html#Dimension">Nilai-Nilai Dimensi</a>.
    ++   </p>
    ++
    ++
    ++
    ++
    ++
    ++
    ++<style type="text/css">
    ++div.layout {
    ++  float:left;
    ++  width:200px;
    ++  margin:0 0 20px 20px;
    ++}
    ++div.layout.first {
    ++  margin-left:0;
    ++  clear:left;
    ++}
    ++</style>
    ++
    ++
    ++
    ++
    ++<h2 id="CommonLayouts">Layout Umum</h2>
    ++
    ++<p>Tiap subkelas dari kelas {@link android.view.ViewGroup} menyediakan cara unik untuk menampilkan
    ++tampilan yang Anda sarangkan di dalamnya. Di bawah ini adalah beberapa tipe layout lebih umum yang dibuat
    ++ke dalam platform Android.</p>
    ++
    ++<p class="note"><strong>Catatan:</strong> Walaupun Anda bisa menyarangkan satu atau beberapa layout dalam
    ++layout lain untuk mendapatkan desain UI, Anda harus berusaha menjaga hierarki layout sedangkal
    ++mungkin. Layout Anda akan digambar lebih cepat jika memiliki layout tersarang yang lebih sedikit (hierarki tampilan yang melebar
    ++lebih baik daripada hierarki tampilan yang dalam).</p>
    ++
    ++<!--
    ++<h2 id="framelayout">FrameLayout</h2>
    ++<p>{@link android.widget.FrameLayout FrameLayout} is the simplest type of layout
    ++object. It's basically a blank space on your screen that you can
    ++later fill with a single object &mdash; for example, a picture that you'll swap in and out.
    ++All child elements of the FrameLayout are pinned to the top left corner of the screen; you cannot
    ++specify a different location for a child view. Subsequent child views will simply be drawn over
    ++previous ones,
    ++partially or totally obscuring them (unless the newer object is transparent).
    ++</p>
    ++-->
    ++
    ++
    ++<div class="layout first">
    ++  <h4><a href="layout/linear.html">Layout Linier</a></h4>
    ++  <a href="layout/linear.html"><img src="{@docRoot}images/ui/linearlayout-small.png" alt="" /></a>
    ++  <p>Layout yang mengatur anak-anaknya menjadi satu baris horizontal atau vertikal. Layout ini
    ++  akan membuat scrollbar jika panjang jendela melebihi panjang layar.</p>
    ++</div>
    ++
    ++<div class="layout">
    ++  <h4><a href="layout/relative.html">Layout Relatif</a></h4>
    ++  <a href="layout/relative.html"><img src="{@docRoot}images/ui/relativelayout-small.png" alt="" /></a>
    ++  <p>Memungkinkan Anda menentukan lokasi objek anak relatif terhadap satu sama lain (anak A di
    ++kiri anak B) atau terhadap induk (disejajarkan dengan atas induknya).</p>
    ++</div>
    ++
    ++<div class="layout">
    ++  <h4><a href="{@docRoot}guide/webapps/webview.html">Tampilan Web</a></h4>
    ++  <a href="{@docRoot}guide/webapps/webview.html"><img src="{@docRoot}images/ui/webview-small.png" alt="" /></a>
    ++  <p>Menampilkan halaman web.</p>
    ++</div>
    ++
    ++
    ++
    ++
    ++<h2 id="AdapterViews" style="clear:left">Membangun Layout dengan Adaptor</h2>
    ++
    ++<p>Bila isi layout bersifat dinamis atau tidak dipastikan sebelumnya, Anda bisa menggunakan layout yang menjadi
    ++subkelas {@link android.widget.AdapterView} untuk mengisi layout dengan tampilan saat runtime.
    ++Subkelas dari kelas {@link android.widget.AdapterView} menggunakan {@link android.widget.Adapter} untuk
    ++mengikat data ke layoutnya. {@link android.widget.Adapter} berfungsi sebagai penghubung antara sumber data
    ++dan layout{@link android.widget.AdapterView}&mdash;{@link android.widget.Adapter}
    ++menarik data (dari suatu sumber seperti larik (array) atau query database) dan mengubah setiap entri
    ++menjadi tampilan yang bisa ditambahkan ke dalam layout {@link android.widget.AdapterView}.</p>
    ++
    ++<p>Layout umum yang didukung oleh adaptor meliputi:</p>
    ++
    ++<div class="layout first">
    ++  <h4><a href="layout/listview.html">Tampilan Daftar</a></h4>
    ++  <a href="layout/listview.html"><img src="{@docRoot}images/ui/listview-small.png" alt="" /></a>
    ++  <p>Menampilkan daftar kolom tunggal yang bergulir.</p>
    ++</div>
    ++
    ++<div class="layout">
    ++  <h4><a href="layout/gridview.html">Tampilan Petak</a></h4>
    ++  <a href="layout/gridview.html"><img src="{@docRoot}images/ui/gridview-small.png" alt="" /></a>
    ++  <p>Menampilkan petak bergulir yang terdiri atas kolom dan baris.</p>
    ++</div>
    ++
    ++
    ++
    ++<h3 id="FillingTheLayout" style="clear:left">Mengisi tampilan adaptor dengan data</h3>
    ++
    ++<p>Anda bisa mengisi {@link android.widget.AdapterView} seperti {@link android.widget.ListView} atau
    ++{@link android.widget.GridView} dengan mengikat instance {@link android.widget.AdapterView} ke
    ++{@link android.widget.Adapter}, yang akan mengambil data dari sumber eksternal dan membuat {@link
    ++android.view.View} yang mewakili tiap entri data.</p>
    ++
    ++<p>Android menyediakan beberapa subkelas {@link android.widget.Adapter} yang berguna untuk
    ++menarik berbagai jenis data dan membangun tampilan untuk {@link android.widget.AdapterView}. Dua
    ++ adaptor yang paling umum adalah:</p>
    ++
    ++<dl>
    ++  <dt>{@link android.widget.ArrayAdapter}</dt>
    ++    <dd>Gunakan adaptor ini bila sumber data Anda berupa larik. Secara default, {@link
    ++android.widget.ArrayAdapter} akan membuat tampilan untuk tiap elemen larik dengan memanggil {@link
    ++java.lang.Object#toString()} pada tiap elemen dan menempatkan isinya dalam {@link
    ++android.widget.TextView}.
    ++      <p>Misalnya, jika Anda memiliki satu larik string yang ingin ditampilkan dalam {@link
    ++android.widget.ListView}, buatlah {@link android.widget.ArrayAdapter} baru dengan konstruktor
    ++untuk menentukan layout setiap string dan larik string:</p>
    ++<pre>
    ++ArrayAdapter&lt;String> adapter = new ArrayAdapter&lt;String>(this,
    ++        android.R.layout.simple_list_item_1, myStringArray);
    ++</pre>
    ++<p>Argumen-argumen untuk konstruktor ini adalah:</p>
    ++<ul>
    ++  <li>{@link android.content.Context} aplikasi Anda</li>
    ++  <li>Layout yang berisi {@link android.widget.TextView} untuk tiap string dalam larik</li>
    ++  <li>Larik string</li>
    ++</ul>
    ++<p>Kemudian tinggal panggil
    ++{@link android.widget.ListView#setAdapter setAdapter()} pada {@link android.widget.ListView} Anda:</p>
    ++<pre>
    ++ListView listView = (ListView) findViewById(R.id.listview);
    ++listView.setAdapter(adapter);
    ++</pre>
    ++
    ++      <p>Untuk menyesuaikan penampilan setiap item, Anda bisa mengesampingkan metode {@link
    ++java.lang.Object#toString()} bagi objek dalam larik Anda. Atau, untuk membuat tampilan tiap
    ++elemen selain {@link android.widget.TextView} (misalnya, jika Anda menginginkan
    ++{@link android.widget.ImageView} bagi setiap item larik), perluas kelas {@link
    ++android.widget.ArrayAdapter} dan kesampingkan {@link android.widget.ArrayAdapter#getView
    ++getView()} agar memberikan tipe tampilan yang Anda inginkan bagi tiap item.</p>
    ++
    ++</dd>
    ++
    ++  <dt>{@link android.widget.SimpleCursorAdapter}</dt>
    ++    <dd>Gunakan adaptor ini bila data Anda berasal dari {@link android.database.Cursor}. Saat
    ++menggunakan {@link android.widget.SimpleCursorAdapter}, Anda harus menentukan layout yang akan digunakan untuk tiap
    ++baris dalam {@link android.database.Cursor} dan di kolom mana di {@link android.database.Cursor}
    ++harus memasukkan tampilan layout. Misalnya, jika Anda ingin untuk membuat daftar
    ++nama orang dan nomor telepon, Anda bisa melakukan query yang menghasilkan {@link
    ++android.database.Cursor} yang berisi satu baris untuk tiap orang dan kolom-kolom untuk nama dan
    ++nomor. Selanjutnya Anda membuat larik string yang menentukan kolom dari {@link
    ++android.database.Cursor} yang Anda inginkan dalam layout untuk setiap hasil dan larik integer yang menentukan
    ++tampilan yang sesuai untuk menempatkan masing-masing kolom:</p>
    ++<pre>
    ++String[] fromColumns = {ContactsContract.Data.DISPLAY_NAME,
    ++                        ContactsContract.CommonDataKinds.Phone.NUMBER};
    ++int[] toViews = {R.id.display_name, R.id.phone_number};
    ++</pre>
    ++<p>Bila Anda membuat instance {@link android.widget.SimpleCursorAdapter}, teruskan layout yang akan digunakan untuk
    ++setiap hasil, {@link android.database.Cursor} yang berisi hasil tersebut, dan dua larik ini:</p>
    ++<pre>
    ++SimpleCursorAdapter adapter = new SimpleCursorAdapter(this,
    ++        R.layout.person_name_and_number, cursor, fromColumns, toViews, 0);
    ++ListView listView = getListView();
    ++listView.setAdapter(adapter);
    ++</pre>
    ++<p>{@link android.widget.SimpleCursorAdapter} kemudian membuat tampilan untuk tiap baris dalam
    ++{@link android.database.Cursor} dengan layout yang disediakan dengan memasukkan setiap item {@code
    ++fromColumns} ke dalam tampilan {@code toViews} yang sesuai.</p></dd>
    ++</dl>
    ++
    ++
    ++<p>Jika, selama aplikasi berjalan, Anda mengubah data sumber yang dibaca oleh
    ++adaptor, maka Anda harus memanggil {@link android.widget.ArrayAdapter#notifyDataSetChanged()}. Hal ini akan
    ++memberi tahu tampilan yang bersangkutan bahwa data telah berubah dan tampilan harus memperbarui dirinya sendiri.</p>
    ++
    ++
    ++
    ++<h3 id="HandlingUserSelections">Menangani kejadian klik</h3>
    ++
    ++<p>Anda bisa merespons kejadian klik pada setiap item dalam {@link android.widget.AdapterView} dengan
    ++menerapkan antarmuka {@link android.widget.AdapterView.OnItemClickListener}. Misalnya:</p>
    ++
    ++<pre>
    ++// Create a message handling object as an anonymous class.
    ++private OnItemClickListener mMessageClickedHandler = new OnItemClickListener() {
    ++    public void onItemClick(AdapterView parent, View v, int position, long id) {
    ++        // Do something in response to the click
    ++    }
    ++};
    ++
    ++listView.setOnItemClickListener(mMessageClickedHandler);
    ++</pre>
    ++
    ++
    ++
    +diff --git a/docs/html-intl/intl/id/guide/topics/ui/dialogs.jd b/docs/html-intl/intl/id/guide/topics/ui/dialogs.jd
    +new file mode 100644
    +index 0000000..06a25ac
    +--- /dev/null
    ++++ b/docs/html-intl/intl/id/guide/topics/ui/dialogs.jd
    +@@ -0,0 +1,798 @@
    ++page.title=Dialog
    ++page.tags=alertdialog,dialogfragment
    ++
    ++@jd:body
    ++
    ++
    ++
    ++<div id="qv-wrapper">
    ++  <div id="qv">
    ++    <h2>Dalam dokumen ini</h2>
    ++<ol>
    ++  <li><a href="#DialogFragment">Membuat Fragmen Dialog</a></li>
    ++  <li><a href="#AlertDialog">Membuat Dialog Peringatan</a>
    ++    <ol>
    ++      <li><a href="#AddingButtons">Menambahkan tombol</a></li>
    ++      <li><a href="#AddingAList">Menambahkan daftar</a></li>
    ++      <li><a href="#CustomLayout">Membuat Layout Custom</a></li>
    ++    </ol>
    ++  </li>
    ++  <li><a href="#PassingEvents">Meneruskan Kejadian Kembali ke Host Dialog</a></li>
    ++  <li><a href="#ShowingADialog">Menampilkan Dialog</a></li>
    ++  <li><a href="#FullscreenDialog">Menampilkan Dialog sebagai Layar Penuh atau Fragmen Tertanam</a>
    ++    <ol>
    ++      <li><a href="#ActivityAsDialog">Menampilkan aktivitas sebagai dialog pada layar besar</a></li>
    ++    </ol>
    ++  </li>
    ++  <li><a href="#DismissingADialog">Menutup Dialog</a></li>
    ++</ol>
    ++
    ++    <h2>Kelas-kelas utama</h2>
    ++    <ol>
    ++      <li>{@link android.app.DialogFragment}</li>
    ++      <li>{@link android.app.AlertDialog}</li>
    ++    </ol>
    ++
    ++    <h2>Lihat juga</h2>
    ++    <ol>
    ++      <li><a href="{@docRoot}design/building-blocks/dialogs.html">Panduan desain dialog</a></li>
    ++      <li><a href="{@docRoot}guide/topics/ui/controls/pickers.html">Picker</a> (dialog Tanggal/Waktu)</li>
    ++    </ol>
    ++  </div>
    ++</div>
    ++
    ++<p>Dialog adalah jendela kecil yang meminta pengguna untuk
    ++membuat keputusan atau memasukkan informasi tambahan. Dialog tidak mengisi layar dan
    ++biasanya digunakan untuk kejadian modal yang mengharuskan pengguna untuk melakukan tindakan sebelum bisa melanjutkan.</p>
    ++
    ++<div class="note design">
    ++<p><strong>Desain Dialog</strong></p>
    ++  <p>Untuk informasi tentang cara mendesain dialog, termasuk saran
    ++  untuk bahasa, bacalah panduan Desain <a href="{@docRoot}design/building-blocks/dialogs.html">dialog</a>.</p>
    ++</div>
    ++
    ++<img src="{@docRoot}images/ui/dialogs.png" />
    ++
    ++<p>Kelas {@link android.app.Dialog} adalah kelas basis untuk dialog, namun Anda
    ++harus menghindari pembuatan instance {@link android.app.Dialog} secara langsung.
    ++Sebagai gantinya, gunakan salah satu subkelas berikut:</p>
    ++<dl>
    ++  <dt>{@link android.app.AlertDialog}</dt>
    ++  <dd>Dialog yang bisa menampilkan judul, hingga tiga tombol, daftar
    ++    item yang dapat dipilih, atau layout custom.</dd>
    ++  <dt>{@link android.app.DatePickerDialog} atau {@link android.app.TimePickerDialog}</dt>
    ++  <dd>Dialog berisi UI yang sudah didefinisikan dan memungkinkan pengguna memilih tanggal atau waktu.</dd>
    ++</dl>
    ++
    ++<div class="sidebox">
    ++<h2>Hindari ProgressDialog</h2>
    ++<p>Android menyertakan kelas dialog lain yang disebut
    ++{@link android.app.ProgressDialog} yang menampilkan dialog berisi progress-bar. Akan tetapi, jika Anda
    ++perlu menunjukkan kemajuan pemuatan ataupun kemajuan yang tidak pasti, maka Anda harus mengikuti
    ++panduan desain untuk <a href="{@docRoot}design/building-blocks/progress.html">Kemajuan &amp;
    ++Aktivitas</a> dan menggunakan {@link android.widget.ProgressBar} dalam layout Anda.</p>
    ++</div>
    ++
    ++<p>Kelas-kelas ini mendefinisikan gaya dan struktur dialog Anda, namun Anda harus
    ++menggunakan {@link android.support.v4.app.DialogFragment} sebagai kontainer dialog Anda.
    ++Kelas {@link android.support.v4.app.DialogFragment} menyediakan semua kontrol yang Anda
    ++perlukan untuk membuat dialog dan mengelola penampilannya, sebagai ganti memanggil metode
    ++pada objek {@link android.app.Dialog}.</p>
    ++
    ++<p>Menggunakan {@link android.support.v4.app.DialogFragment} untuk mengelola dialog
    ++akan memastikan bahwa kelas itu menangani kejadian daur hidup
    ++dengan benar seperti ketika pengguna menekan tombol <em>Back</em> atau memutar layar. Kelas {@link
    ++android.support.v4.app.DialogFragment} juga memungkinkan Anda menggunakan ulang dialog UI sebagai
    ++komponen yang bisa ditanamkan dalam UI yang lebih besar, persis seperti {@link
    ++android.support.v4.app.Fragment} tradisional (seperti saat Anda ingin dialog UI muncul berbeda
    ++pada layar besar dan kecil).</p>
    ++
    ++<p>Bagian-bagian berikutnya dalam panduan ini akan menjelaskan cara menggunakan {@link
    ++android.support.v4.app.DialogFragment} yang dikombinasikan dengan objek {@link android.app.AlertDialog}
    ++. Jika Anda ingin membuat picker tanggal atau waktu, Anda harus membaca panduan
    ++<a href="{@docRoot}guide/topics/ui/controls/pickers.html">Picker</a>.</p>
    ++
    ++<p class="note"><strong>Catatan:</strong>
    ++Karena kelas {@link android.app.DialogFragment} mulanya ditambahkan pada
    ++Android 3.0 (API level 11), dokumen ini menjelaskan cara menggunakan kelas {@link
    ++android.support.v4.app.DialogFragment} yang disediakan bersama <a href="{@docRoot}tools/support-library/index.html">Pustaka Dukungan</a>. Dengan menambahkan pustaka ini
    ++ke aplikasi, Anda bisa menggunakan {@link android.support.v4.app.DialogFragment} dan berbagai
    ++API lain pada perangkat yang menjalankan Android 1.6 atau yang lebih tinggi. Jika versi minimum yang didukung aplikasi Anda
    ++adalah API level 11 atau yang lebih tinggi, maka Anda bisa menggunakan versi kerangka kerja {@link
    ++android.app.DialogFragment}, namun ketahuilah bahwa tautan dalam dokumen ini adalah untuk API
    ++pustaka dukungan. Saat menggunakan pustaka dukungan,
    ++pastikan Anda mengimpor kelas <code>android.support.v4.app.DialogFragment</code>
    ++dan <em>bukan</em> <code>android.app.DialogFragment</code>.</p>
    ++
    ++
    ++<h2 id="DialogFragment">Membuat Fragmen Dialog</h2>
    ++
    ++<p>Anda bisa menghasilkan beragam rancangan dialog&mdash;termasuk
    ++layout custom dan desain yang dijelaskan dalam panduan desain <a href="{@docRoot}design/building-blocks/dialogs.html">Dialog</a>
    ++&mdash;dengan memperluas
    ++{@link android.support.v4.app.DialogFragment} dan membuat {@link android.app.AlertDialog}
    ++dalam metode callback {@link android.support.v4.app.DialogFragment#onCreateDialog
    ++onCreateDialog()}.</p>
    ++
    ++<p>Misalnya, berikut ini sebuah {@link android.app.AlertDialog} dasar yang dikelola dalam
    ++{@link android.support.v4.app.DialogFragment}:</p>
    ++
    ++<pre>
    ++public class FireMissilesDialogFragment extends DialogFragment {
    ++    &#64;Override
    ++    public Dialog onCreateDialog(Bundle savedInstanceState) {
    ++        // Use the Builder class for convenient dialog construction
    ++        AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
    ++        builder.setMessage(R.string.dialog_fire_missiles)
    ++               .setPositiveButton(R.string.fire, new DialogInterface.OnClickListener() {
    ++                   public void onClick(DialogInterface dialog, int id) {
    ++                       // FIRE ZE MISSILES!
    ++                   }
    ++               })
    ++               .setNegativeButton(R.string.cancel, new DialogInterface.OnClickListener() {
    ++                   public void onClick(DialogInterface dialog, int id) {
    ++                       // User cancelled the dialog
    ++                   }
    ++               });
    ++        // Create the AlertDialog object and return it
    ++        return builder.create();
    ++    }
    ++}
    ++</pre>
    ++
    ++<div class="figure" style="width:290px;margin:0 0 0 20px">
    ++<img src="{@docRoot}images/ui/dialog_buttons.png" alt="" />
    ++<p class="img-caption"><strong>Gambar 1.</strong>
    ++Dialog dengan satu pesan dan dua tombol tindakan.</p>
    ++</div>
    ++
    ++<p>Sekarang, bila Anda membuat instance kelas ini dan memanggil {@link
    ++android.support.v4.app.DialogFragment#show show()} pada objek itu, dialog akan muncul seperti
    ++yang ditampilkan dalam gambar 1.</p>
    ++
    ++<p>Bagian berikutnya menjelaskan lebih jauh tentang penggunaan API {@link android.app.AlertDialog.Builder}
    ++untuk membuat dialog.</p>
    ++
    ++<p>Bergantung pada seberapa rumit dialog tersebut, Anda bisa menerapkan berbagai metode callback lain
    ++dalam {@link android.support.v4.app.DialogFragment}, termasuk semua
    ++<a href="{@docRoot}guide/components/fragments.html#Lifecycle">metode daur hidup fragmen</a> dasar.
    ++
    ++
    ++
    ++
    ++
    ++<h2 id="AlertDialog">Membuat Dialog Peringatan</h2>
    ++
    ++
    ++<p>Kelas {@link android.app.AlertDialog} memungkinkan Anda membuat berbagai desain dialog dan
    ++seringkali satu-satunya kelas dialog yang akan Anda perlukan.
    ++Seperti yang ditampilkan dalam gambar 2, ada tiga area pada dialog peringatan:</p>
    ++
    ++<div class="figure" style="width:311px;margin-top:0">
    ++<img src="{@docRoot}images/ui/dialogs_regions.png" alt="" style="margin-bottom:0" />
    ++<p class="img-caption"><strong>Gambar 2.</strong> Layout dialog.</p>
    ++</div>
    ++
    ++<ol>
    ++<li><b>Judul</b>
    ++  <p>Area ini opsional dan hanya boleh digunakan bila area konten
    ++  ditempati oleh pesan terperinci, daftar, atau layout custom. Jika Anda perlu menyatakan
    ++  pesan atau pertanyaan sederhana (seperti dialog dalam gambar 1), Anda tidak memerlukan judul.</li>
    ++<li><b>Area konten</b>
    ++  <p>Area ini bisa menampilkan pesan, daftar, atau layout custom lainnya.</p></li>
    ++<li><b>Tombol tindakan</b>
    ++  <p>Tidak boleh ada lebih dari tiga tombol tindakan dalam sebuah dialog.</p></li>
    ++</ol>
    ++
    ++<p>Kelas {@link android.app.AlertDialog.Builder}
    ++ menyediakan API yang memungkinkan Anda membuat {@link android.app.AlertDialog}
    ++dengan jenis konten ini, termasuk layout custom.</p>
    ++
    ++<p>Untuk membuat {@link android.app.AlertDialog}:</p>
    ++
    ++<pre>
    ++<b>// 1. Instantiate an {@link android.app.AlertDialog.Builder} with its constructor</b>
    ++AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
    ++
    ++<b>// 2. Chain together various setter methods to set the dialog characteristics</b>
    ++builder.setMessage(R.string.dialog_message)
    ++       .setTitle(R.string.dialog_title);
    ++
    ++<b>// 3. Get the {@link android.app.AlertDialog} from {@link android.app.AlertDialog.Builder#create()}</b>
    ++AlertDialog dialog = builder.create();
    ++</pre>
    ++
    ++<p>Topik-topik selanjutnya menampilkan cara mendefinisikan berbagai atribut dialog dengan menggunakan
    ++kelas {@link android.app.AlertDialog.Builder}.</p>
    ++
    ++
    ++
    ++
    ++<h3 id="AddingButtons">Menambahkan tombol</h3>
    ++
    ++<p>Untuk menambahkan tombol tindakan seperti dalam gambar 2,
    ++panggil metode {@link android.app.AlertDialog.Builder#setPositiveButton setPositiveButton()} dan
    ++{@link android.app.AlertDialog.Builder#setNegativeButton setNegativeButton()}:</p>
    ++
    ++<pre style="clear:right">
    ++AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
    ++// Add the buttons
    ++builder.setPositiveButton(R.string.ok, new DialogInterface.OnClickListener() {
    ++           public void onClick(DialogInterface dialog, int id) {
    ++               // User clicked OK button
    ++           }
    ++       });
    ++builder.setNegativeButton(R.string.cancel, new DialogInterface.OnClickListener() {
    ++           public void onClick(DialogInterface dialog, int id) {
    ++               // User cancelled the dialog
    ++           }
    ++       });
    ++// Set other dialog properties
    ++...
    ++
    ++// Create the AlertDialog
    ++AlertDialog dialog = builder.create();
    ++</pre>
    ++
    ++<p>Metode <code>set...Button()</code> mengharuskan adanya judul bagi tombol (disediakan
    ++oleh suatu <a href="{@docRoot}guide/topics/resources/string-resource.html">sumber daya string</a>) dan
    ++{@link android.content.DialogInterface.OnClickListener} yang mendefinisikan tindakan yang diambil
    ++bila pengguna menekan tombol.</p>
    ++
    ++<p>Ada tiga macam tombol tindakan yang Anda bisa tambahkan:</p>
    ++<dl>
    ++  <dt>Positif</dt>
    ++  <dd>Anda harus menggunakan tipe ini untuk menerima dan melanjutkan tindakan (tindakan "OK").</dd>
    ++  <dt>Negatif</dt>
    ++  <dd>Anda harus menggunakan tipe ini untuk membatalkan tindakan.</dd>
    ++  <dt>Netral</dt>
    ++  <dd>Anda harus menggunakan tipe ini bila pengguna mungkin tidak ingin melanjutkan tindakan,
    ++  namun tidak ingin membatalkan. Tipe ini muncul antara tombol positif dan
    ++tombol negatif. Misalnya, tindakan bisa berupa "Ingatkan saya nanti".</dd>
    ++</dl>
    ++
    ++<p>Anda hanya bisa menambahkan salah satu tipe tombol ke {@link
    ++android.app.AlertDialog}. Artinya, Anda tidak bisa memiliki lebih dari satu tombol "positif".</p>
    ++
    ++
    ++
    ++<div class="figure" style="width:290px;margin:0 0 0 40px">
    ++<img src="{@docRoot}images/ui/dialog_list.png" alt="" />
    ++<p class="img-caption"><strong>Gambar 3.</strong>
    ++Dialog dengan satu judul dan daftar.</p>
    ++</div>
    ++
    ++<h3 id="AddingAList">Menambahkan daftar</h3>
    ++
    ++<p>Ada tiga macam daftar yang tersedia pada API {@link android.app.AlertDialog}:</p>
    ++<ul>
    ++<li>Daftar pilihan tunggal biasa</li>
    ++<li>Daftar pilihan tunggal persisten (tombol radio)</li>
    ++<li>Daftar pilihan ganda persisten (kotak cek)</li>
    ++</ul>
    ++
    ++<p>Untuk membuat daftar pilihan tunggal seperti dalam gambar 3,
    ++gunakan metode {@link android.app.AlertDialog.Builder#setItems setItems()}:</p>
    ++
    ++<pre style="clear:right">
    ++&#64;Override
    ++public Dialog onCreateDialog(Bundle savedInstanceState) {
    ++    AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
    ++    builder.setTitle(R.string.pick_color)
    ++           .setItems(R.array.colors_array, new DialogInterface.OnClickListener() {
    ++               public void onClick(DialogInterface dialog, int which) {
    ++               // The 'which' argument contains the index position
    ++               // of the selected item
    ++           }
    ++    });
    ++    return builder.create();
    ++}
    ++</pre>
    ++
    ++<p>Karena daftar muncul dalam area konten dialog,
    ++dialog tidak bisa menampilkan pesan dan daftar sekaligus dan Anda harus menetapkan judul untuk
    ++dialog dengan {@link android.app.AlertDialog.Builder#setTitle setTitle()}.
    ++Untuk menentukan item daftar, panggil {@link
    ++android.app.AlertDialog.Builder#setItems setItems()}, dengan meneruskan larik.
    ++Atau, Anda bisa menetapkan daftar menggunakan {@link
    ++android.app.AlertDialog.Builder#setAdapter setAdapter()}. Hal ini memungkinkan Anda mendukung daftar
    ++dengan data dinamis (seperti dari database) dengan menggunakan {@link android.widget.ListAdapter}.</p>
    ++
    ++<p>Jika Anda memilih untuk mendukung daftar dengan {@link android.widget.ListAdapter},
    ++selalu gunakan sebuah {@link android.support.v4.content.Loader} agar konten dimuat
    ++secara asinkron. Hal ini dijelaskan lebih jauh dalam panduan
    ++<a href="{@docRoot}guide/topics/ui/declaring-layout.html#AdapterViews">Membuat Layout
    ++dengan Adaptor</a> dan <a href="{@docRoot}guide/components/loaders.html">Loader</a>
    ++.</p>
    ++
    ++<p class="note"><strong>Catatan:</strong> Secara default, menyentuh sebuah item daftar akan menutup dialog,
    ++kecuali Anda menggunakan salah satu daftar pilihan persisten berikut ini.</p>
    ++
    ++<div class="figure" style="width:290px;margin:-30px 0 0 40px">
    ++<img src="{@docRoot}images/ui/dialog_checkboxes.png" />
    ++<p class="img-caption"><strong>Gambar 4.</strong>
    ++Daftar item pilihan ganda.</p>
    ++</div>
    ++
    ++
    ++<h4 id="Checkboxes">Menambahkan daftar pilihan ganda atau pilihan tunggal persisten</h4>
    ++
    ++<p>Untuk menambahkan daftar item pilihan ganda (kotak cek) atau
    ++item pilihan tunggal (tombol radio), gunakan masing-masing metode
    ++{@link android.app.AlertDialog.Builder#setMultiChoiceItems(Cursor,String,String,
    ++DialogInterface.OnMultiChoiceClickListener) setMultiChoiceItems()}, atau
    ++{@link android.app.AlertDialog.Builder#setSingleChoiceItems(int,int,DialogInterface.OnClickListener)
    ++setSingleChoiceItems()}.</p>
    ++
    ++<p>Misalnya, berikut ini cara membuat daftar pilihan ganda seperti
    ++yang ditampilkan dalam gambar 4 yang menyimpan item
    ++yang dipilih dalam {@link java.util.ArrayList}:</p>
    ++
    ++<pre style="clear:right">
    ++&#64;Override
    ++public Dialog onCreateDialog(Bundle savedInstanceState) {
    ++    mSelectedItems = new ArrayList();  // Where we track the selected items
    ++    AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
    ++    // Set the dialog title
    ++    builder.setTitle(R.string.pick_toppings)
    ++    // Specify the list array, the items to be selected by default (null for none),
    ++    // and the listener through which to receive callbacks when items are selected
    ++           .setMultiChoiceItems(R.array.toppings, null,
    ++                      new DialogInterface.OnMultiChoiceClickListener() {
    ++               &#64;Override
    ++               public void onClick(DialogInterface dialog, int which,
    ++                       boolean isChecked) {
    ++                   if (isChecked) {
    ++                       // If the user checked the item, add it to the selected items
    ++                       mSelectedItems.add(which);
    ++                   } else if (mSelectedItems.contains(which)) {
    ++                       // Else, if the item is already in the array, remove it
    ++                       mSelectedItems.remove(Integer.valueOf(which));
    ++                   }
    ++               }
    ++           })
    ++    // Set the action buttons
    ++           .setPositiveButton(R.string.ok, new DialogInterface.OnClickListener() {
    ++               &#64;Override
    ++               public void onClick(DialogInterface dialog, int id) {
    ++                   // User clicked OK, so save the mSelectedItems results somewhere
    ++                   // or return them to the component that opened the dialog
    ++                   ...
    ++               }
    ++           })
    ++           .setNegativeButton(R.string.cancel, new DialogInterface.OnClickListener() {
    ++               &#64;Override
    ++               public void onClick(DialogInterface dialog, int id) {
    ++                   ...
    ++               }
    ++           });
    ++
    ++    return builder.create();
    ++}
    ++</pre>
    ++
    ++<p>Walaupun daftar tradisional maupun daftar dengan tombol radio
    ++menyediakan tindakan "pilihan tunggal", Anda harus menggunakan {@link
    ++android.app.AlertDialog.Builder#setSingleChoiceItems(int,int,DialogInterface.OnClickListener)
    ++setSingleChoiceItems()} jika ingin mempertahankan pilihan pengguna.
    ++Yakni, jika nanti membuka dialog lagi untuk menunjukkan pilihan pengguna,
    ++maka Anda perlu membuat daftar dengan tombol radio.</p>
    ++
    ++
    ++
    ++
    ++
    ++<h3 id="CustomLayout">Membuat Layout Custom</h3>
    ++
    ++<div class="figure" style="width:290px;margin:-30px 0 0 40px">
    ++<img src="{@docRoot}images/ui/dialog_custom.png" alt="" />
    ++<p class="img-caption"><strong>Gambar 5.</strong> Layout dialog custom.</p>
    ++</div>
    ++
    ++<p>Jika Anda menginginkan layout custom dalam dialog, buatlah layout dan tambahkan ke
    ++{@link android.app.AlertDialog} dengan memanggil {@link
    ++android.app.AlertDialog.Builder#setView setView()} pada objek {@link
    ++android.app.AlertDialog.Builder} Anda.</p>
    ++
    ++<p>Secara default, layout custom akan mengisi jendela dialog, namun Anda masih bisa
    ++menggunakan metode {@link android.app.AlertDialog.Builder} untuk menambahkan tombol dan judul.</p>
    ++
    ++<p>Misalnya, berikut ini adalah file layout untuk dialog dalam Gambar 5:</p>
    ++
    ++<p style="clear:right" class="code-caption">res/layout/dialog_signin.xml</p>
    ++<pre>
    ++&lt;LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    ++    android:orientation="vertical"
    ++    android:layout_width="wrap_content"
    ++    android:layout_height="wrap_content">
    ++    &lt;ImageView
    ++        android:src="@drawable/header_logo"
    ++        android:layout_width="match_parent"
    ++        android:layout_height="64dp"
    ++        android:scaleType="center"
    ++        android:background="#FFFFBB33"
    ++        android:contentDescription="@string/app_name" />
    ++    &lt;EditText
    ++        android:id="@+id/username"
    ++        android:inputType="textEmailAddress"
    ++        android:layout_width="match_parent"
    ++        android:layout_height="wrap_content"
    ++        android:layout_marginTop="16dp"
    ++        android:layout_marginLeft="4dp"
    ++        android:layout_marginRight="4dp"
    ++        android:layout_marginBottom="4dp"
    ++        android:hint="@string/username" />
    ++    &lt;EditText
    ++        android:id="@+id/password"
    ++        android:inputType="textPassword"
    ++        android:layout_width="match_parent"
    ++        android:layout_height="wrap_content"
    ++        android:layout_marginTop="4dp"
    ++        android:layout_marginLeft="4dp"
    ++        android:layout_marginRight="4dp"
    ++        android:layout_marginBottom="16dp"
    ++        android:fontFamily="sans-serif"
    ++        android:hint="@string/password"/>
    ++&lt;/LinearLayout>
    ++</pre>
    ++
    ++<p class="note"><strong>Tip:</strong> Secara default, bila Anda telah mengatur sebuah elemen {@link android.widget.EditText}
    ++agar menggunakan tipe input {@code "textPassword"}, keluarga font akan diatur ke spasi tunggal, sehingga
    ++Anda harus mengubah keluarga font ke {@code "sans-serif"} sehingga kedua bidang teks menggunakan
    ++gaya font yang cocok.</p>
    ++
    ++<p>Untuk memekarkan layout dalam {@link android.support.v4.app.DialogFragment} Anda,
    ++ambillah {@link android.view.LayoutInflater} dengan
    ++{@link android.app.Activity#getLayoutInflater()} dan panggil
    ++{@link android.view.LayoutInflater#inflate inflate()}, dengan parameter pertama
    ++adalah ID sumber daya layout dan parameter kedua adalah tampilan induk untuk layout.
    ++Selanjutnya Anda bisa memanggil {@link android.app.AlertDialog#setView setView()}
    ++untuk menempatkan layout dalam dialog.</p>
    ++
    ++<pre>
    ++&#64;Override
    ++public Dialog onCreateDialog(Bundle savedInstanceState) {
    ++    AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
    ++    // Get the layout inflater
    ++    LayoutInflater inflater = getActivity().getLayoutInflater();
    ++
    ++    // Inflate and set the layout for the dialog
    ++    // Pass null as the parent view because its going in the dialog layout
    ++    builder.setView(inflater.inflate(R.layout.dialog_signin, null))
    ++    // Add action buttons
    ++           .setPositiveButton(R.string.signin, new DialogInterface.OnClickListener() {
    ++               &#64;Override
    ++               public void onClick(DialogInterface dialog, int id) {
    ++                   // sign in the user ...
    ++               }
    ++           })
    ++           .setNegativeButton(R.string.cancel, new DialogInterface.OnClickListener() {
    ++               public void onClick(DialogInterface dialog, int id) {
    ++                   LoginDialogFragment.this.getDialog().cancel();
    ++               }
    ++           });
    ++    return builder.create();
    ++}
    ++</pre>
    ++
    ++<div class="note">
    ++<p><strong>Tip:</strong> Jika Anda menginginkan dialog custom,
    ++Anda bisa menampilkan {@link android.app.Activity} sebagai dialog
    ++daripada menggunakan API {@link android.app.Dialog}. Cukup buat satu aktivitas dan mengatur temanya ke
    ++{@link android.R.style#Theme_Holo_Dialog Theme.Holo.Dialog}
    ++di elemen manifes <a href="{@docRoot}guide/topics/manifest/activity-element.html">{@code
    ++&lt;activity&gt;}</a>:</p>
    ++
    ++<pre>
    ++&lt;activity android:theme="&#64;android:style/Theme.Holo.Dialog" >
    ++</pre>
    ++<p>Demikian saja. Aktivitas sekarang ditampilkan dalam jendela dialog, sebagai ganti layar penuh.</p>
    ++</div>
    ++
    ++
    ++
    ++<h2 id="PassingEvents">Meneruskan Kejadian Kembali ke Host Dialog</h2>
    ++
    ++<p>Bila pengguna menyentuh salah satu tombol tindakan dialog atau memilih satu item dari daftarnya,
    ++{@link android.support.v4.app.DialogFragment} Anda bisa melakukan sendiri tindakan yang diperlukan
    ++, namun sering kali Anda perlu mengirim kejadian itu ke aktivitas atau fragmen yang
    ++membuka dialog. Caranya, definisikan antarmuka dengan sebuah metode untuk masing-masing tipe kejadian klik.
    ++Lalu implementasikan antarmuka itu dalam komponen host yang akan
    ++menerima kejadian tindakan dari dialog.</p>
    ++
    ++<p>Misalnya, berikut ini adalah {@link android.support.v4.app.DialogFragment} yang mendefinisikan
    ++antarmuka yang akan digunakan untuk mengirim kembali suatu kejadian ke aktivitas host:</p>
    ++
    ++<pre>
    ++public class NoticeDialogFragment extends DialogFragment {
    ++
    ++    /* The activity that creates an instance of this dialog fragment must
    ++     * implement this interface in order to receive event callbacks.
    ++     * Each method passes the DialogFragment in case the host needs to query it. */
    ++    public interface NoticeDialogListener {
    ++        public void onDialogPositiveClick(DialogFragment dialog);
    ++        public void onDialogNegativeClick(DialogFragment dialog);
    ++    }
    ++
    ++    // Use this instance of the interface to deliver action events
    ++    NoticeDialogListener mListener;
    ++
    ++    // Override the Fragment.onAttach() method to instantiate the NoticeDialogListener
    ++    &#64;Override
    ++    public void onAttach(Activity activity) {
    ++        super.onAttach(activity);
    ++        // Verify that the host activity implements the callback interface
    ++        try {
    ++            // Instantiate the NoticeDialogListener so we can send events to the host
    ++            mListener = (NoticeDialogListener) activity;
    ++        } catch (ClassCastException e) {
    ++            // The activity doesn't implement the interface, throw exception
    ++            throw new ClassCastException(activity.toString()
    ++                    + " must implement NoticeDialogListener");
    ++        }
    ++    }
    ++    ...
    ++}
    ++</pre>
    ++
    ++<p>Aktivitas yang menjadi host dialog tersebut akan membuat instance dialog
    ++dengan konstruktor fragmen dialog dan menerima kejadian dialog
    ++melalui implementasi antarmuka {@code NoticeDialogListener}:</p>
    ++
    ++<pre>
    ++public class MainActivity extends FragmentActivity
    ++                          implements NoticeDialogFragment.NoticeDialogListener{
    ++    ...
    ++
    ++    public void showNoticeDialog() {
    ++        // Create an instance of the dialog fragment and show it
    ++        DialogFragment dialog = new NoticeDialogFragment();
    ++        dialog.show(getSupportFragmentManager(), "NoticeDialogFragment");
    ++    }
    ++
    ++    // The dialog fragment receives a reference to this Activity through the
    ++    // Fragment.onAttach() callback, which it uses to call the following methods
    ++    // defined by the NoticeDialogFragment.NoticeDialogListener interface
    ++    &#64;Override
    ++    public void onDialogPositiveClick(DialogFragment dialog) {
    ++        // User touched the dialog's positive button
    ++        ...
    ++    }
    ++
    ++    &#64;Override
    ++    public void onDialogNegativeClick(DialogFragment dialog) {
    ++        // User touched the dialog's negative button
    ++        ...
    ++    }
    ++}
    ++</pre>
    ++
    ++<p>Karena aktivitas host mengimplementasikan {@code NoticeDialogListener}&mdash;yang
    ++diberlakukan oleh metode callback {@link android.support.v4.app.Fragment#onAttach onAttach()}
    ++di atas,&mdash;fragmen dialog bisa menggunakan
    ++metode callback antarmuka untuk mengirimkan kejadian klik ke aktivitas:</p>
    ++
    ++<pre>
    ++public class NoticeDialogFragment extends DialogFragment {
    ++    ...
    ++
    ++    &#64;Override
    ++    public Dialog onCreateDialog(Bundle savedInstanceState) {
    ++        // Build the dialog and set up the button click handlers
    ++        AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
    ++        builder.setMessage(R.string.dialog_fire_missiles)
    ++               .setPositiveButton(R.string.fire, new DialogInterface.OnClickListener() {
    ++                   public void onClick(DialogInterface dialog, int id) {
    ++                       // Send the positive button event back to the host activity
    ++                       mListener.onDialogPositiveClick(NoticeDialogFragment.this);
    ++                   }
    ++               })
    ++               .setNegativeButton(R.string.cancel, new DialogInterface.OnClickListener() {
    ++                   public void onClick(DialogInterface dialog, int id) {
    ++                       // Send the negative button event back to the host activity
    ++                       mListener.onDialogNegativeClick(NoticeDialogFragment.this);
    ++                   }
    ++               });
    ++        return builder.create();
    ++    }
    ++}
    ++</pre>
    ++
    ++
    ++
    ++<h2 id="ShowingADialog">Menampilkan Dialog</h2>
    ++
    ++<p>Bila Anda ingin menampilkan dialog, buatlah instance {@link
    ++android.support.v4.app.DialogFragment} dan panggil {@link android.support.v4.app.DialogFragment#show
    ++show()}, dengan meneruskan {@link android.support.v4.app.FragmentManager} dan nama tag
    ++untuk fragmen dialognya.</p>
    ++
    ++<p>Anda bisa mendapatkan {@link android.support.v4.app.FragmentManager} dengan memanggil
    ++{@link android.support.v4.app.FragmentActivity#getSupportFragmentManager()} dari
    ++ {@link android.support.v4.app.FragmentActivity} atau {@link
    ++android.support.v4.app.Fragment#getFragmentManager()} dari {@link
    ++android.support.v4.app.Fragment}. Misalnya:</p>
    ++
    ++<pre>
    ++public void confirmFireMissiles() {
    ++    DialogFragment newFragment = new FireMissilesDialogFragment();
    ++    newFragment.show(getSupportFragmentManager(), "missiles");
    ++}
    ++</pre>
    ++
    ++<p>Argumen kedua, {@code "missiles"}, adalah nama tag unik yang digunakan sistem untuk menyimpan
    ++dan memulihkan status fragmen bila diperlukan. Tag ini juga memungkinkan Anda mendapatkan handle ke
    ++fragmen dengan memanggil {@link android.support.v4.app.FragmentManager#findFragmentByTag
    ++findFragmentByTag()}.</p>
    ++
    ++
    ++
    ++
    ++<h2 id="FullscreenDialog">Menampilkan Dialog sebagai Layar Penuh atau Fragmen Tertanam</h2>
    ++
    ++<p>Anda mungkin memiliki desain UI yang di dalamnya Anda ingin UI muncul sebagai dialog dalam beberapa
    ++situasi, namun sebagai layar penuh atau fragmen tertanam dalam situasi lain (mungkin bergantung pada apakah
    ++perangkat memiliki layar besar atau layar kecil). Kelas {@link android.support.v4.app.DialogFragment}
    ++menawarkan fleksibilitas ini karena masih bisa berperilaku sebagai {@link
    ++android.support.v4.app.Fragment} yang bisa ditanamkan.</p>
    ++
    ++<p>Akan tetapi, dalam hal ini Anda tidak bisa menggunakan {@link android.app.AlertDialog.Builder AlertDialog.Builder}
    ++atau objek {@link android.app.Dialog} lain untuk membangun dialog. Jika
    ++Anda ingin {@link android.support.v4.app.DialogFragment}
    ++bisa ditanamkan, Anda harus mendefinisikan dialog UI dalam layout, lalu memuat layout itu dalam metode callback
    ++{@link android.support.v4.app.DialogFragment#onCreateView
    ++onCreateView()}.</p>
    ++
    ++<p>Berikut ini adalah contoh {@link android.support.v4.app.DialogFragment} yang bisa muncul sebagai
    ++dialog maupun fragmen yang bisa ditanamkan (menggunakan layout bernama <code>purchase_items.xml</code>):</p>
    ++
    ++<pre>
    ++public class CustomDialogFragment extends DialogFragment {
    ++    /** The system calls this to get the DialogFragment's layout, regardless
    ++        of whether it's being displayed as a dialog or an embedded fragment. */
    ++    &#64;Override
    ++    public View onCreateView(LayoutInflater inflater, ViewGroup container,
    ++            Bundle savedInstanceState) {
    ++        // Inflate the layout to use as dialog or embedded fragment
    ++        return inflater.inflate(R.layout.purchase_items, container, false);
    ++    }
    ++
    ++    /** The system calls this only when creating the layout in a dialog. */
    ++    &#64;Override
    ++    public Dialog onCreateDialog(Bundle savedInstanceState) {
    ++        // The only reason you might override this method when using onCreateView() is
    ++        // to modify any dialog characteristics. For example, the dialog includes a
    ++        // title by default, but your custom layout might not need it. So here you can
    ++        // remove the dialog title, but you must call the superclass to get the Dialog.
    ++        Dialog dialog = super.onCreateDialog(savedInstanceState);
    ++        dialog.requestWindowFeature(Window.FEATURE_NO_TITLE);
    ++        return dialog;
    ++    }
    ++}
    ++</pre>
    ++
    ++<p>Dan berikut ini adalah beberapa kode yang memutuskan apakah akan menampilkan fragmen sebagai dialog
    ++atau UI layar penuh, berdasarkan ukuran layar:</p>
    ++
    ++<pre>
    ++public void showDialog() {
    ++    FragmentManager fragmentManager = getSupportFragmentManager();
    ++    CustomDialogFragment newFragment = new CustomDialogFragment();
    ++
    ++    if (mIsLargeLayout) {
    ++        // The device is using a large layout, so show the fragment as a dialog
    ++        newFragment.show(fragmentManager, "dialog");
    ++    } else {
    ++        // The device is smaller, so show the fragment fullscreen
    ++        FragmentTransaction transaction = fragmentManager.beginTransaction();
    ++        // For a little polish, specify a transition animation
    ++        transaction.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN);
    ++        // To make it fullscreen, use the 'content' root view as the container
    ++        // for the fragment, which is always the root view for the activity
    ++        transaction.add(android.R.id.content, newFragment)
    ++                   .addToBackStack(null).commit();
    ++    }
    ++}
    ++</pre>
    ++
    ++<p>Untuk informasi selengkapnya tentang melakukan transaksi fragmen, lihat panduan
    ++<a href="{@docRoot}guide/components/fragments.html">Fragmen</a>.</p>
    ++
    ++<p>Dalam contoh ini, nilai boolean <code>mIsLargeLayout</code> menentukan apakah perangkat saat ini
    ++harus menggunakan desain layout besar aplikasi (dan dengan demikian menampilkan fragmen ini sebagai dialog, bukan
    ++layar penuh). Cara terbaik untuk mengatur jenis boolean ini adalah mendeklarasikan
    ++<a href="{@docRoot}guide/topics/resources/more-resources.html#Bool">nilai sumber daya boolean</a>
    ++dengan nilai <a href="{@docRoot}guide/topics/resources/providing-resources.html#AlternativeResources">sumber daya alternatif</a> untuk berbagai ukuran layar. Misalnya, berikut ini adalah dua
    ++versi sumber daya boolean untuk berbagai ukuran layar:</p>
    ++
    ++<p class="code-caption">res/values/bools.xml</p>
    ++<pre>
    ++&lt;!-- Default boolean values -->
    ++&lt;resources>
    ++    &lt;bool name="large_layout">false&lt;/bool>
    ++&lt;/resources>
    ++</pre>
    ++
    ++<p class="code-caption">res/values-large/bools.xml</p>
    ++<pre>
    ++&lt;!-- Large screen boolean values -->
    ++&lt;resources>
    ++    &lt;bool name="large_layout">true&lt;/bool>
    ++&lt;/resources>
    ++</pre>
    ++
    ++<p>Selanjutnya Anda bisa menetapkan nilai {@code mIsLargeLayout} selama
    ++metode {@link android.app.Activity#onCreate onCreate()} aktivitas:</p>
    ++
    ++<pre>
    ++boolean mIsLargeLayout;
    ++
    ++&#64;Override
    ++public void onCreate(Bundle savedInstanceState) {
    ++    super.onCreate(savedInstanceState);
    ++    setContentView(R.layout.activity_main);
    ++
    ++    mIsLargeLayout = getResources().getBoolean(R.bool.large_layout);
    ++}
    ++</pre>
    ++
    ++
    ++
    ++<h3 id="ActivityAsDialog">Menampilkan aktivitas sebagai dialog pada layar besar</h3>
    ++
    ++<p>Sebagai ganti menampilkan dialog berupa UI layar penuh saat di layar kecil, Anda bisa memperoleh
    ++hasil yang sama dengan menampilkan {@link android.app.Activity} sebagai dialog saat di
    ++layar besar. Pendekatan yang Anda pilih bergantung pada desain aplikasi, namun
    ++menampilkan aktivitas sebagai dialog sering kali berguna bila aplikasi Anda sudah didesain untuk
    ++layar kecil dan Anda ingin meningkatkan pengalaman pada tablet dengan menampilkan aktivitas berjangka pendek
    ++sebagai dialog.</p>
    ++
    ++<p>Untuk menampilkan aktivitas sebagai dialog hanya saat di layar besar,
    ++terapkan tema {@link android.R.style#Theme_Holo_DialogWhenLarge Theme.Holo.DialogWhenLarge}
    ++ pada elemen manifes <a href="{@docRoot}guide/topics/manifest/activity-element.html">{@code
    ++&lt;activity&gt;}</a>:</p>
    ++
    ++<pre>
    ++&lt;activity android:theme="&#64;android:style/Theme.Holo.DialogWhenLarge" >
    ++</pre>
    ++
    ++<p>Untuk informasi selengkapnya tentang mengatur gaya aktivitas Anda dengan tema, lihat panduan <a href="{@docRoot}guide/topics/ui/themes.html">Gaya dan Tema</a>.</p>
    ++
    ++
    ++
    ++<h2 id="DismissingADialog">Menutup Dialog</h2>
    ++
    ++<p>Bila pengguna menyentuh salah satu tombol tindakan yang dibuat dengan
    ++{@link android.app.AlertDialog.Builder}, sistem akan menutup dialog untuk Anda.</p>
    ++
    ++<p>Sistem juga menutup dialog bila pengguna menyentuh sebuah item dalam daftar dialog, kecuali
    ++bila daftar itu menggunakan tombol radio atau kotak cek. Jika tidak, Anda bisa menutup dialog secara manual
    ++dengan memanggil {@link android.support.v4.app.DialogFragment#dismiss()} pada {@link
    ++android.support.v4.app.DialogFragment} Anda.</p>
    ++
    ++<p>Jika Anda perlu melakukan
    ++tindakan tertentu saat dialog menghilang, Anda bisa menerapkan metode {@link
    ++android.support.v4.app.DialogFragment#onDismiss onDismiss()} dalam {@link
    ++android.support.v4.app.DialogFragment} Anda.</p>
    ++
    ++<p>Anda juga bisa <em>membatalkan</em> dialog. Ini merupakan kejadian khusus yang menunjukkan bahwa pengguna
    ++secara eksplisit meninggalkan dialog tanpa menyelesaikan tugas. Hal ini terjadi jika pengguna menekan tombol
    ++<em>Back</em>, menyentuh layar di luar area dialog,
    ++atau jika Anda secara eksplisit memanggil {@link android.app.Dialog#cancel()} pada {@link
    ++android.app.Dialog} (seperti saat merespons tombol "Cancel" dalam dialog).</p>
    ++
    ++<p>Seperti yang ditampilkan dalam contoh di atas, Anda bisa merespons kejadian batal dengan menerapkan
    ++{@link android.support.v4.app.DialogFragment#onCancel onCancel()} dalam kelas {@link
    ++android.support.v4.app.DialogFragment} Anda.</p>
    ++
    ++<p class="note"><strong>Catatan:</strong> Sistem akan memanggil
    ++{@link android.support.v4.app.DialogFragment#onDismiss onDismiss()} pada tiap kejadian yang
    ++memanggil callback {@link android.support.v4.app.DialogFragment#onCancel onCancel()}. Akan tetapi,
    ++jika Anda memanggil {@link android.app.Dialog#dismiss Dialog.dismiss()} atau {@link
    ++android.support.v4.app.DialogFragment#dismiss DialogFragment.dismiss()},
    ++sistem akan memanggil {@link android.support.v4.app.DialogFragment#onDismiss onDismiss()} <em>namun
    ++bukan</em> {@link android.support.v4.app.DialogFragment#onCancel onCancel()}. Jadi biasanya Anda harus
    ++memanggil {@link android.support.v4.app.DialogFragment#dismiss dismiss()} bila pengguna menekan tombol
    ++<em>positif</em> dalam dialog untuk menghilangkan tampilan dialog.</p>
    ++
    ++
    +diff --git a/docs/html-intl/intl/id/guide/topics/ui/menus.jd b/docs/html-intl/intl/id/guide/topics/ui/menus.jd
    +new file mode 100644
    +index 0000000..1ee0244
    +--- /dev/null
    ++++ b/docs/html-intl/intl/id/guide/topics/ui/menus.jd
    +@@ -0,0 +1,1031 @@
    ++page.title=Menu
    ++parent.title=Antarmuka Pengguna
    ++parent.link=index.html
    ++@jd:body
    ++
    ++<div id="qv-wrapper">
    ++<div id="qv">
    ++  <h2>Dalam dokumen ini</h2>
    ++<ol>
    ++  <li><a href="#xml">Mendefinisikan Menu dalam XML</a></li>
    ++  <li><a href="#options-menu">Membuat Menu Opsi</a>
    ++    <ol>
    ++      <li><a href="#RespondingOptionsMenu">Menangani kejadian klik</a></li>
    ++      <li><a href="#ChangingTheMenu">Mengubah item menu saat runtime</a></li>
    ++    </ol>
    ++  </li>
    ++  <li><a href="#context-menu">Membuat Menu Kontekstual</a>
    ++    <ol>
    ++      <li><a href="#FloatingContextMenu">Membuat menu konteks mengambang</a></li>
    ++      <li><a href="#CAB">Menggunakan mode tindakan kontekstual</a></li>
    ++    </ol>
    ++  </li>
    ++  <li><a href="#PopupMenu">Membuat Menu Popup</a>
    ++    <ol>
    ++      <li><a href="#PopupEvents">Menangani kejadian klik</a></li>
    ++    </ol>
    ++  </li>
    ++  <li><a href="#groups">Membuat Grup Menu</a>
    ++    <ol>
    ++      <li><a href="#checkable">Menggunakan item menu yang bisa diberi tanda cek</a></li>
    ++    </ol>
    ++  </li>
    ++  <li><a href="#intents">Menambahkan Item Menu Berdasarkan Intent</a>
    ++    <ol>
    ++      <li><a href="#AllowingToAdd">Memungkinkan aktivitas Anda ditambahkan ke menu lain</a></li>
    ++    </ol>
    ++  </li>
    ++</ol>
    ++
    ++  <h2>Kelas-kelas utama</h2>
    ++  <ol>
    ++    <li>{@link android.view.Menu}</li>
    ++    <li>{@link android.view.MenuItem}</li>
    ++    <li>{@link android.view.ContextMenu}</li>
    ++    <li>{@link android.view.ActionMode}</li>
    ++  </ol>
    ++
    ++  <h2>Lihat juga</h2>
    ++  <ol>
    ++    <li><a href="{@docRoot}guide/topics/ui/actionbar.html">Action-Bar</a></li>
    ++    <li><a href="{@docRoot}guide/topics/resources/menu-resource.html">Sumber Daya Menu</a></li>
    ++    <li><a href="http://android-developers.blogspot.com/2012/01/say-goodbye-to-menu-button.html">Ucapkan
    ++Selamat Tinggal pada Tombol Menu</a></li>
    ++  </ol>
    ++</div>
    ++</div>
    ++
    ++<p>Menu adalah komponen antarmuka pengguna yang lazim dalam banyak tipe aplikasi. Untuk menyediakan pengalaman pengguna yang sudah akrab
    ++dan konsisten, Anda harus menggunakan API {@link android.view.Menu} untuk menyajikan
    ++tindakan dan opsi lain dalam aktivitas kepada pengguna.</p>
    ++
    ++<p>Mulai dengan Android 3.0 (API level 11), perangkat berbasis Android tidak perlu lagi
    ++menyediakan tombol <em>Menu</em> tersendiri. Dengan perubahan ini, aplikasi Android harus bermigrasi dari
    ++dependensi pada panel menu 6 item biasa, dan sebagai ganti menyediakan action-bar untuk menyajikan
    ++berbagai tindakan pengguna yang lazim.</p>
    ++
    ++<p>Walaupun desain dan pengalaman pengguna untuk sebagian item menu telah berubah, semantik untuk mendefinisikan
    ++serangkaian tindakan dan opsi masih berdasarkan pada API {@link android.view.Menu}. Panduan ini
    ++menampilkan cara membuat tiga tipe dasar penyajian menu atau tindakan pada semua
    ++versi Android:</p>
    ++
    ++<dl>
    ++  <dt><strong>Menu opsi dan action-bar</strong></dt>
    ++    <dd><a href="#options-menu">Menu opsi</a> adalah kumpulan item menu utama untuk suatu
    ++aktivitas. Inilah tempat Anda harus menempatkan tindakan yang berdampak global pada aplikasi, seperti
    ++"Cari", "Tulis email", dan "Pengaturan".
    ++  <p>Jika Anda mengembangkan aplikasi untuk Android 2.3 atau yang lebih rendah, pengguna bisa
    ++menampilkan panel menu opsi dengan menekan tombol <em>Menu</em>.</p>
    ++  <p>Pada Android 3.0 dan yang lebih tinggi, item menu opsi disajikan melalui <a href="{@docRoot}guide/topics/ui/actionbar.html">action-bar</a> sebagai kombinasi item tindakan
    ++di layar dan opsi overflow. Mulai dengan Android 3.0, tombol <em>Menu</em> dihilangkan (sebagian
    ++perangkat
    ++tidak memilikinya), sehingga Anda harus bermigrasi ke penggunaan action-bar untuk menyediakan akses ke tindakan dan
    ++opsi lainnya.</p>
    ++  <p>Lihat bagian tentang <a href="#options-menu">Membuat Menu Opsi</a>.</p>
    ++    </dd>
    ++
    ++  <dt><strong>Menu konteks dan mode tindakan kontekstual</strong></dt>
    ++
    ++   <dd>Menu konteks adalah <a href="#FloatingContextMenu">menu mengambang</a> yang muncul saat
    ++pengguna mengklik lama pada suatu elemen. Menu ini menyediakan tindakan yang memengaruhi konten atau
    ++bingkai konteks yang dipilih.
    ++  <p>Saat mengembangkan aplikasi untuk Android 3.0 dan yang lebih tinggi, sebagai gantinya Anda harus menggunakan <a href="#CAB">mode tindakan kontekstual</a> untuk memungkinkan tindakan pada konten yang dipilih. Mode ini menampilkan
    ++item tindakan yang memengaruhi konten yang dipilih dalam baris di bagian atas layar dan memungkinkan pengguna
    ++memilih beberapa item sekaligus.</p>
    ++  <p>Lihat bagian tentang <a href="#context-menu">Membuat Menu Kontekstual</a>.</p>
    ++</dd>
    ++
    ++  <dt><strong>Menu popup</strong></dt>
    ++    <dd>Menu popup menampilkan daftar item secara vertikal yang dipasang pada tampilan yang
    ++memanggil menu. Ini cocok untuk menyediakan kelebihan tindakan yang terkait dengan konten tertentu atau
    ++untuk menyediakan opsi bagi bagian kedua dari suatu perintah. Tindakan di menu popup
    ++<strong>tidak</strong> boleh memengaruhi secara langsung konten yang bersangkutan&mdash;yang diperuntukkan bagi
    ++tindakan kontekstual. Melainkan, menu popup adalah untuk tindakan tambahan yang terkait dengan wilayah konten dalam
    ++aktivitas Anda.
    ++  <p>Lihat bagian tentang <a href="#PopupMenu">Membuat Menu Popup</a>.</p>
    ++</dd>
    ++</dl>
    ++
    ++
    ++
    ++<h2 id="xml">Mendefinisikan Menu dalam XML</h2>
    ++
    ++<p>Untuk semua tipe menu, Android menyediakan sebuah format XML standar untuk mendefinisikan item menu.
    ++Sebagai ganti membuat menu dalam kode aktivitas, Anda harus mendefinisikan menu dan semua itemnya dalam
    ++<a href="{@docRoot}guide/topics/resources/menu-resource.html">sumber daya menu</a> XML. Anda kemudian bisa
    ++memekarkan sumber daya menu (memuatnya sebagai objek {@link android.view.Menu}) dalam aktivitas atau
    ++fragmen.</p>
    ++
    ++<p>Menggunakan sumber daya menu adalah praktik yang baik karena beberapa alasan:</p>
    ++<ul>
    ++  <li>Memvisualisasikan struktur menu dalam XML menjadi lebih mudah.</li>
    ++  <li>Cara ini memisahkan konten untuk menu dari kode perilaku aplikasi Anda.</li>
    ++  <li>Cara ini memungkinkan Anda membuat konfigurasi menu alternatif untuk berbagai versi platform,
    ++ukuran layar, dan konfigurasi lainnya dengan memanfaatkan kerangka kerja <a href="{@docRoot}guide/topics/resources/index.html">sumber daya aplikasi</a>.</li>
    ++</ul>
    ++
    ++<p>Untuk mendefinisikan menu, buatlah sebuah file XML dalam direktori <code>res/menu/</code>
    ++proyek dan buat menu dengan elemen-elemen berikut:</p>
    ++<dl>
    ++  <dt><code>&lt;menu></code></dt>
    ++    <dd>Mendefinisikan {@link android.view.Menu}, yang merupakan sebuah kontainer untuk item menu. Elemen
    ++<code>&lt;menu></code> harus menjadi simpul akar untuk file dan bisa menampung salah satu atau beberapa dari elemen
    ++<code>&lt;item></code> dan <code>&lt;group></code>.</dd>
    ++
    ++  <dt><code>&lt;item></code></dt>
    ++    <dd>Membuat {@link android.view.MenuItem}, yang mewakili satu item menu. Elemen ini
    ++bisa berisi elemen <code>&lt;menu></code> tersarang guna untuk membuat submenu.</dd>
    ++
    ++  <dt><code>&lt;group></code></dt>
    ++    <dd>Kontainer opsional tak terlihat untuk elemen-elemen {@code &lt;item&gt;}. Kontainer ini memungkinkan Anda
    ++mengelompokkan item menu untuk berbagi properti seperti status aktif dan visibilitas. Untuk informasi
    ++selengkapnya, lihat bagian tentang <a href="#groups">Membuat Grup Menu</a>.</dd>
    ++</dl>
    ++
    ++
    ++<p>Berikut ini adalah contoh menu bernama <code>game_menu.xml</code>:</p>
    ++<pre>
    ++&lt;?xml version="1.0" encoding="utf-8"?&gt;
    ++&lt;menu xmlns:android="http://schemas.android.com/apk/res/android"&gt;
    ++    &lt;item android:id="@+id/new_game"
    ++          android:icon="@drawable/ic_new_game"
    ++          android:title="@string/new_game"
    ++          android:showAsAction="ifRoom"/&gt;
    ++    &lt;item android:id="@+id/help"
    ++          android:icon="@drawable/ic_help"
    ++          android:title="@string/help" /&gt;
    ++&lt;/menu&gt;
    ++</pre>
    ++
    ++<p>Elemen <code>&lt;item></code> mendukung beberapa atribut yang bisa Anda gunakan untuk mendefinisikan penampilan dan perilaku
    ++item. Item menu di atas mencakup atribut berikut:</p>
    ++
    ++<dl>
    ++  <dt>{@code android:id}</dt>
    ++    <dd>ID sumber daya unik bagi item, yang memungkinkan aplikasi mengenali item
    ++bila pengguna memilihnya.</dd>
    ++  <dt>{@code android:icon}</dt>
    ++    <dd>Acuan ke drawable untuk digunakan sebagai ikon item.</dd>
    ++  <dt>{@code android:title}</dt>
    ++    <dd>Acuan ke string untuk digunakan sebagai judul item.</dd>
    ++  <dt>{@code android:showAsAction}</dt>
    ++    <dd>Menetapkan waktu dan cara item ini muncul sebagai item tindakan di <a href="{@docRoot}guide/topics/ui/actionbar.html">action-bar</a>.</dd>
    ++</dl>
    ++
    ++<p>Ini adalah atribut-atribut terpenting yang harus Anda gunakan, namun banyak lagi yang tersedia.
    ++Untuk informasi tentang semua atribut yang didukung, lihat dokumen <a href="{@docRoot}guide/topics/resources/menu-resource.html">Sumber Daya Menu</a>.</p>
    ++
    ++<p>Anda bisa menambahkan submenu ke sebuah item di menu (kecuali submenu) apa saja dengan menambahkan elemen {@code &lt;menu&gt;}
    ++sebagai anak {@code &lt;item&gt;}. Submenu berguna saat aplikasi Anda memiliki banyak
    ++fungsi yang bisa ditata ke dalam topik-topik, seperti item dalam sebuah baris menu aplikasi PC (File,
    ++Edit, Lihat, dsb.). Misalnya:</p>
    ++
    ++<pre>
    ++&lt;?xml version="1.0" encoding="utf-8"?&gt;
    ++&lt;menu xmlns:android="http://schemas.android.com/apk/res/android"&gt;
    ++    &lt;item android:id="@+id/file"
    ++          android:title="@string/file" &gt;
    ++        &lt;!-- "file" submenu --&gt;
    ++        &lt;menu&gt;
    ++            &lt;item android:id="@+id/create_new"
    ++                  android:title="@string/create_new" /&gt;
    ++            &lt;item android:id="@+id/open"
    ++                  android:title="@string/open" /&gt;
    ++        &lt;/menu&gt;
    ++    &lt;/item&gt;
    ++&lt;/menu&gt;
    ++</pre>
    ++
    ++<p>Untuk menggunakan menu dalam aktivitas, Anda perlu memekarkan sumber daya menu (mengonversi sumber daya XML
    ++menjadi objek yang bisa diprogram) dengan menggunakan {@link android.view.MenuInflater#inflate(int,Menu)
    ++MenuInflater.inflate()}. Di bagian berikut, Anda akan melihat cara memekarkan menu untuk tiap
    ++tipe menu.</p>
    ++
    ++
    ++
    ++<h2 id="options-menu">Membuat Menu Opsi</h2>
    ++
    ++<div class="figure" style="width:200px;margin:0">
    ++  <img src="{@docRoot}images/options_menu.png" height="333" alt="" />
    ++  <p class="img-caption"><strong>Gambar 1.</strong> Menu opsi di
    ++Browser, pada Android 2.3.</p>
    ++</div>
    ++
    ++<p>Menu opsi adalah tempat Anda harus menyertakan tindakan dan opsi lain yang relevan dengan
    ++konteks aktivitas saat ini, seperti "Cari", "Tulis email", dan "Pengaturan".</p>
    ++
    ++<p>Tempat item dalam menu opsi muncul di layar bergantung pada versi aplikasi yang Anda
    ++kembangkan:</p>
    ++
    ++<ul>
    ++  <li>Jika Anda mengembangkan aplikasi untuk <strong>Android 2.3.x (API level 10) atau
    ++yang lebih rendah</strong>, konten menu opsi muncul pada bagian bawah layar bila pengguna
    ++menekan tombol <em>Menu</em>, seperti yang ditampilkan dalam gambar 1. Bila dibuka, bagian yang terlihat pertama adalah
    ++menu
    ++ikon, yang menampung hingga enam item menu. Jika menu Anda menyertakan lebih dari enam item, Android akan meletakkan
    ++item keenam dan sisanya ke dalam menu kelebihan, yang bisa dibuka pengguna dengan memilih
    ++<em>More</em>.</li>
    ++
    ++  <li>Jika Anda mengembangkan aplikasi untuk <strong>Android 3.0 (API level 11) dan
    ++yang lebih tinggi</strong>, item menu opsi tersedia dalam <a href="{@docRoot}guide/topics/ui/actionbar.html">action-bar</a>. Secara default, sistem
    ++meletakkan semua item dalam kelebihan tindakan, yang bisa ditampilkan pengguna dengan ikon kelebihan tindakan di
    ++sisi kanan action-bar (atau dengan menekan tombol <em>Menu</em> perangkat, jika tersedia). Untuk
    ++mengaktifkan
    ++akses cepat ke tindakan penting, Anda bisa mempromosikan beberapa item agar muncul pada action-bar dengan menambahkan
    ++{@code android:showAsAction="ifRoom"} ke elemen-elemen {@code &lt;item&gt;} yang bersangkutan (lihat gambar
    ++2). <p>Untuk informasi selengkapnya tentang item tindakan dan perilaku action-bar lainnya, lihat panduan <a href="{@docRoot}guide/topics/ui/actionbar.html">Action-Bar</a>. </p>
    ++<p class="note"><strong>Catatan:</strong> Sekalipun Anda <em>tidak</em> mengembangkan aplikasi untuk Android 3.0 atau
    ++yang lebih tinggi, Anda bisa membuat layout action-bar sendiri untuk mendapatkan efek serupa. Untuk contoh cara
    ++mendukung versi Android yang lebih lama dengan action-bar, lihat contoh <a href="{@docRoot}resources/samples/ActionBarCompat/index.html">Kompatibilitas Action-Bar</a>
    ++.</p>
    ++</li>
    ++</ul>
    ++
    ++<img src="{@docRoot}images/ui/actionbar.png" alt="" />
    ++<p class="img-caption"><strong>Gambar 2.</strong> Action-bar dari aplikasi <a href="{@docRoot}resources/samples/HoneycombGallery/index.html">Honeycomb Gallery</a>, yang menampilkan
    ++tab-tab navigasi dan item tindakan kamera (plus tombol kelebihan tindakan).</p>
    ++
    ++<p>Anda bisa mendeklarasikan item untuk menu opsi dari subkelas {@link android.app.Activity}
    ++atau subkelas {@link android.app.Fragment}. Jika aktivitas maupun fragmen Anda
    ++mendeklarasikan item menu opsi, keduanya akan dikombinasikan dalam UI. Item aktivitas akan muncul
    ++lebih dahulu, diikuti oleh item tiap fragmen sesuai dengan urutan penambahan fragmen ke
    ++aktivitas. Jika perlu, Anda bisa menyusun ulang item menu dengan atribut {@code android:orderInCategory}
    ++dalam setiap {@code &lt;item&gt;} yang perlu Anda pindahkan.</p>
    ++
    ++<p>Untuk menetapkan menu opsi suatu aktivitas, kesampingkan {@link
    ++android.app.Activity#onCreateOptionsMenu(Menu) onCreateOptionsMenu()} (fragmen-fragmen menyediakan
    ++callback {@link android.app.Fragment#onCreateOptionsMenu onCreateOptionsMenu()} sendiri). Dalam metode ini
    ++, Anda bisa memekarkan sumber daya menu (<a href="#xml">yang didefinisikan dalam XML</a>) menjadi {@link
    ++android.view.Menu} yang disediakan dalam callback. Misalnya:</p>
    ++
    ++<pre>
    ++&#64;Override
    ++public boolean onCreateOptionsMenu(Menu menu) {
    ++    MenuInflater inflater = {@link android.app.Activity#getMenuInflater()};
    ++    inflater.inflate(R.menu.game_menu, menu);
    ++    return true;
    ++}
    ++</pre>
    ++
    ++<p>Anda juga bisa menambahkan item menu dengan menggunakan {@link android.view.Menu#add(int,int,int,int)
    ++add()} dan mengambil item dengan {@link android.view.Menu#findItem findItem()} untuk merevisi propertinya
    ++dengan API {@link android.view.MenuItem}.</p>
    ++
    ++<p>Jika Anda mengembangkan aplikasi untuk Android 2.3.x dan yang lebih rendah, sistem akan memanggil {@link
    ++android.app.Activity#onCreateOptionsMenu(Menu) onCreateOptionsMenu()} untuk membuat menu opsi
    ++bila pengguna membuka menu untuk pertama kali. Jika Anda mengembangkan aplikasi untuk Android 3.0 dan yang lebih tinggi,
    ++sistem akan memanggil {@link android.app.Activity#onCreateOptionsMenu(Menu) onCreateOptionsMenu()} saat
    ++memulai aktivitas, untuk menampilkan item menu pada action-bar.</p>
    ++
    ++
    ++
    ++<h3 id="RespondingOptionsMenu">Menangani kejadian klik</h3>
    ++
    ++<p>Bila pengguna memilih item dari menu opsi (termasuk item tindakan dalam action-bar),
    ++sistem akan memanggil metode {@link android.app.Activity#onOptionsItemSelected(MenuItem)
    ++onOptionsItemSelected()} aktivitas Anda. Metode ini meneruskan {@link android.view.MenuItem} yang dipilih. Anda
    ++bisa mengidentifikasi item dengan memanggil {@link android.view.MenuItem#getItemId()}, yang menghasilkan
    ++ID unik untuk item menu itu (yang didefinisikan oleh atribut {@code android:id} dalam sumber daya menu atau dengan
    ++integer yang diberikan ke metode {@link android.view.Menu#add(int,int,int,int) add()}). Anda bisa mencocokkan
    ++ID ini dengan item menu yang diketahui untuk melakukan tindakan yang sesuai. Misalnya:</p>
    ++
    ++<pre>
    ++&#64;Override
    ++public boolean onOptionsItemSelected(MenuItem item) {
    ++    // Handle item selection
    ++    switch (item.getItemId()) {
    ++        case R.id.new_game:
    ++            newGame();
    ++            return true;
    ++        case R.id.help:
    ++            showHelp();
    ++            return true;
    ++        default:
    ++            return super.onOptionsItemSelected(item);
    ++    }
    ++}
    ++</pre>
    ++
    ++<p>Bila Anda berhasil menangani sebuah item menu, kembalikan {@code true}. Jika tidak menangani item menu
    ++, Anda harus memanggil implementasi superkelas {@link
    ++android.app.Activity#onOptionsItemSelected(MenuItem) onOptionsItemSelected()} (implementasi default
    ++menghasilkan false).</p>
    ++
    ++<p>Jika aktivitas Anda menyertakan fragmen, sistem akan memanggil lebih dahulu {@link
    ++android.app.Activity#onOptionsItemSelected(MenuItem) onOptionsItemSelected()} untuk aktivitas, kemudian
    ++untuk setiap fragmen (sesuai dengan urutan penambahan fragmen) hingga satu fragmen mengembalikan
    ++{@code true} atau semua fragmen telah dipanggil.</p>
    ++
    ++<p class="note"><strong>Tip:</strong> Android 3.0 menambahkan kemampuan mendefinisikan perilaku on-click
    ++untuk item menu dalam XML, dengan menggunakan atribut {@code android:onClick}. Nilai atribut
    ++harus berupa nama metode yang didefinisikan aktivitas dengan menggunakan menu. Metode
    ++harus bersifat publik dan menerima satu parameter {@link android.view.MenuItem}&mdash;bila sistem
    ++memanggilnya, metode ini akan meneruskan item menu yang dipilih. Untuk informasi selengkapnya dan contoh, lihat dokumen <a href="{@docRoot}guide/topics/resources/menu-resource.html">Sumber Daya Menu</a>.</p>
    ++
    ++<p class="note"><strong>Tip:</strong> Jika aplikasi Anda berisi banyak aktivitas dan
    ++sebagian menyediakan menu opsi yang sama, pertimbangkan untuk membuat
    ++aktivitas yang tidak mengimplementasikan apa-apa kecuali metode {@link android.app.Activity#onCreateOptionsMenu(Menu)
    ++onCreateOptionsMenu()} dan {@link android.app.Activity#onOptionsItemSelected(MenuItem)
    ++onOptionsItemSelected()}. Kemudian perluas kelas ini untuk setiap aktivitas yang harus menggunakan
    ++menu opsi yang sama. Dengan begini, Anda bisa mengelola satu set kode untuk menangani tindakan menu
    ++dan setiap kelas turunan mewarisi perilaku menu.
    ++Jika ingin menambahkan item menu ke salah satu aktivitas turunan,
    ++kesampingkan {@link android.app.Activity#onCreateOptionsMenu(Menu)
    ++onCreateOptionsMenu()} dalam aktivitas itu. Panggil {@code super.onCreateOptionsMenu(menu)} agar
    ++item menu asli dibuat, kemudian tambahkan item menu yang baru dengan {@link
    ++android.view.Menu#add(int,int,int,int) menu.add()}. Anda juga bisa mengesampingkan
    ++perilaku superkelas untuk setiap item menu.</p>
    ++
    ++
    ++<h3 id="ChangingTheMenu">Mengubah item menu saat runtime</h3>
    ++
    ++<p>Setelah sistem memanggil {@link android.app.Activity#onCreateOptionsMenu(Menu)
    ++onCreateOptionsMenu()}, sistem akan mempertahankan instance {@link android.view.Menu} yang Anda tempatkan dan
    ++tidak akan memanggil {@link android.app.Activity#onCreateOptionsMenu(Menu) onCreateOptionsMenu()}
    ++lagi kecuali menu diinvalidkan karena suatu alasan. Akan tetapi, Anda harus menggunakan {@link
    ++android.app.Activity#onCreateOptionsMenu(Menu) onCreateOptionsMenu()} hanya untuk membuat
    ++status menu awal dan tidak untuk membuat perubahan selama daur hidup aktivitas.</p>
    ++
    ++<p>Jika Anda ingin mengubah menu opsi berdasarkan
    ++kejadian yang terjadi selama daur hidup aktivitas, Anda bisa melakukannya dalam metode
    ++{@link android.app.Activity#onPrepareOptionsMenu(Menu) onPrepareOptionsMenu()}. Metode ini
    ++meneruskan objek {@link android.view.Menu} sebagaimana adanya saat ini sehingga Anda bisa mengubahnya,
    ++seperti menambah, menghapus, atau menonaktifkan item. (Fragmen juga menyediakan callback {@link
    ++android.app.Fragment#onPrepareOptionsMenu onPrepareOptionsMenu()}.)</p>
    ++
    ++<p>Pada Android 2.3.x dan yang lebih rendah, sistem akan memanggil {@link
    ++android.app.Activity#onPrepareOptionsMenu(Menu)
    ++onPrepareOptionsMenu()} setiap kali pengguna membuka menu opsi (menekan tombol <em>Menu</em>
    ++).</p>
    ++
    ++<p>Pada Android 3.0 dan yang lebih tinggi, menu opsi dianggap sebagai selalu terbuka saat item menu
    ++ditampilkan pada action-bar. Bila ada kejadian dan Anda ingin melakukan pembaruan menu, Anda harus
    ++memanggil {@link android.app.Activity#invalidateOptionsMenu invalidateOptionsMenu()} untuk meminta
    ++sistem memanggil {@link android.app.Activity#onPrepareOptionsMenu(Menu) onPrepareOptionsMenu()}.</p>
    ++
    ++<p class="note"><strong>Catatan:</strong>
    ++Anda tidak boleh mengubah item dalam menu opsi berdasarkan {@link android.view.View} yang saat ini
    ++difokus. Saat dalam mode sentuh (bila pengguna tidak sedang menggunakan trackball atau d-pad), tampilan
    ++tidak bisa mengambil fokus, sehingga Anda tidak boleh menggunakan fokus sebagai dasar untuk mengubah
    ++item dalam menu opsi. Jika Anda ingin menyediakan item menu yang peka konteks pada {@link
    ++android.view.View}, gunakan <a href="#context-menu">Menu Konteks</a>.</p>
    ++
    ++
    ++
    ++
    ++<h2 id="context-menu">Membuat Menu Kontekstual</h2>
    ++
    ++<div class="figure" style="width:420px;margin-top:-1em">
    ++  <img src="{@docRoot}images/ui/menu-context.png" alt="" />
    ++  <p class="img-caption"><strong>Gambar 3.</strong> Cuplikan layar menu konteks mengambang (kiri)
    ++dan action-bar kontekstual (kanan).</p>
    ++</div>
    ++
    ++<p>Menu kontekstual menawarkan tindakan yang memengaruhi item atau bingkai konteks tertentu dalam UI. Anda
    ++bisa menyediakan menu konteks untuk setiap tampilan, tetapi menu ini paling sering digunakan untuk item pada {@link
    ++android.widget.ListView}, {@link android.widget.GridView}, atau kumpulan tampilan lainnya yang bisa digunakan
    ++pengguna untuk melakukan tindakan langsung pada setiap item.</p>
    ++
    ++<p>Ada dua cara menyediakan tindakan kontekstual:</p>
    ++<ul>
    ++  <li>Dalam <a href="#FloatingContextMenu">menu konteks mengambang</a>. Menu muncul sebagai
    ++daftar item menu mengambang (serupa dengan dialog) bila pengguna mengklik lama (menekan dan
    ++menahan) pada tampilan yang mendeklarasikan dukungan bagi menu konteks. Pengguna bisa melakukan
    ++tindakan kontekstual pada satu item untuk setiap kalinya.</li>
    ++
    ++  <li>Dalam <a href="#CAB">mode tindakan kontekstual</a>. Mode ini adalah implementasi sistem
    ++{@link android.view.ActionMode} yang menampilkan <em>action-bar kontekstual</em> di bagian atas
    ++layar dengan item tindakan yang memengaruhi item(-item) yang dipilih. Bila mode ini aktif, pengguna
    ++bisa melakukan tindakan pada beberapa item sekaligus (jika aplikasi Anda mengizinkannya).</li>
    ++</ul>
    ++
    ++<p class="note"><strong>Catatan:</strong> Mode tindakan kontekstual tersedia pada Android 3.0 (API
    ++level 11) dan yang lebih tinggi dan merupakan teknik yang lebih disukai untuk menampilkan tindakan kontekstual bila
    ++tersedia. Jika aplikasi Anda mendukung versi yang lebih rendah daripada 3.0, maka Anda harus mundur ke
    ++menu konteks mengambang pada perangkat-perangkat itu.</p>
    ++
    ++
    ++<h3 id="FloatingContextMenu">Membuat menu konteks mengambang</h3>
    ++
    ++<p>Untuk menyediakan menu konteks mengambang:</p>
    ++<ol>
    ++  <li>Daftarkan {@link android.view.View} ke menu konteks yang harus dikaitkan dengan
    ++memanggil {@link android.app.Activity#registerForContextMenu(View) registerForContextMenu()} dan teruskan
    ++{@link android.view.View} ke menu itu.
    ++  <p>Jika aktivitas Anda menggunakan {@link android.widget.ListView} atau {@link android.widget.GridView} dan
    ++Anda ingin setiap item untuk menyediakan menu konteks yang sama, daftarkan semua item ke menu konteks dengan
    ++meneruskan {@link android.widget.ListView} atau {@link android.widget.GridView} ke {@link
    ++android.app.Activity#registerForContextMenu(View) registerForContextMenu()}.</p>
    ++</li>
    ++
    ++  <li>Implementasikan metode {@link
    ++android.view.View.OnCreateContextMenuListener#onCreateContextMenu onCreateContextMenu()}
    ++dalam {@link android.app.Activity} atau {@link android.app.Fragment} Anda.
    ++  <p>Bila tampilan yang terdaftar menerima kejadian klik-lama, sistem akan memanggil metode {@link
    ++android.view.View.OnCreateContextMenuListener#onCreateContextMenu onCreateContextMenu()}
    ++Anda. Inilah tempat Anda mendefinisikan item menu, biasanya dengan memekarkan sumber daya menu. Misalnya:
    ++</p>
    ++<pre>
    ++&#64;Override
    ++public void onCreateContextMenu(ContextMenu menu, View v,
    ++                                ContextMenuInfo menuInfo) {
    ++    super.onCreateContextMenu(menu, v, menuInfo);
    ++    MenuInflater inflater = getMenuInflater();
    ++    inflater.inflate(R.menu.context_menu, menu);
    ++}
    ++</pre>
    ++
    ++<p>{@link android.view.MenuInflater} memungkinkan Anda untuk memekarkan menu konteks <a href="{@docRoot}guide/topics/resources/menu-resource.html">sumber daya menu</a>. Parameter metode callback
    ++menyertakan {@link android.view.View}
    ++yang dipilih pengguna dan objek {@link android.view.ContextMenu.ContextMenuInfo} yang menyediakan
    ++informasi tambahan tentang item yang dipilih. Jika aktivitas Anda memiliki beberapa tampilan yang masing-masingnya menyediakan
    ++menu konteks berbeda, Anda bisa menggunakan parameter ini untuk menentukan menu konteks yang harus
    ++dimekarkan.</p>
    ++</li>
    ++
    ++<li>Implementasikan {@link android.app.Activity#onContextItemSelected(MenuItem)
    ++onContextItemSelected()}.
    ++  <p>Bila pengguna memilih item menu, sistem akan memanggil metode ini sehingga Anda bisa melakukan
    ++tindakan yang sesuai. Misalnya:</p>
    ++
    ++<pre>
    ++&#64;Override
    ++public boolean onContextItemSelected(MenuItem item) {
    ++    AdapterContextMenuInfo info = (AdapterContextMenuInfo) item.getMenuInfo();
    ++    switch (item.getItemId()) {
    ++        case R.id.edit:
    ++            editNote(info.id);
    ++            return true;
    ++        case R.id.delete:
    ++            deleteNote(info.id);
    ++            return true;
    ++        default:
    ++            return super.onContextItemSelected(item);
    ++    }
    ++}
    ++</pre>
    ++
    ++<p>Metode {@link android.view.MenuItem#getItemId()} melakukan query ID untuk
    ++item menu yang dipilih, yang harus Anda tetapkan ke setiap item menu dalam XML dengan menggunakan atribut {@code
    ++android:id}, seperti yang ditampilkan di bagian tentang <a href="#xml">Mendefinisikan Menu dalam
    ++XML</a>.</p>
    ++
    ++<p>Bila Anda berhasil menangani sebuah item menu, kembalikan {@code true}. Jika tidak menangani item menu,
    ++Anda harus meneruskan item menu ke implementasi superkelas. Jika aktivitas Anda menyertakan fragmen,
    ++aktivitas akan menerima callback ini lebih dahulu. Dengan memanggil superkelas bila tidak ditangani, sistem
    ++meneruskan kejadian ke metode callback di setiap fragmen, satu per satu (sesuai dengan urutan
    ++penambahan fragmen) hingga {@code true} atau {@code false} dikembalikan. (Implementasi default
    ++untuk {@link android.app.Activity} dan {@code android.app.Fragment} mengembalikan {@code
    ++false}, sehingga Anda harus selalu memanggil superkelas bila tidak ditangani.)</p>
    ++</li>
    ++</ol>
    ++
    ++
    ++<h3 id="CAB">Menggunakan mode tindakan kontekstual</h3>
    ++
    ++<p>Mode tindakan kontekstual adalah implementasi sistem {@link android.view.ActionMode} yang
    ++memfokuskan interaksi pengguna pada upaya melakukan tindakan kontekstual. Bila seorang
    ++pengguna mengaktifkan mode ini dengan memilih item, <em>action-bar kontekstual</em> akan muncul di bagian atas
    ++layar untuk menampilkan tindakan yang bisa dilakukan pengguna pada item yang dipilih saat ini. Selagi mode ini
    ++diaktifkan, pengguna bisa memilih beberapa item (jika Anda mengizinkan), membatalkan pilihan item, dan melanjutkan
    ++penelusuran dalam aktivitas (sebanyak yang ingin Anda izinkan). Mode tindakan dinonaktifkan
    ++dan action-bar kontekstual menghilang bila pengguna membatalkan pilihan semua item, menekan tombol BACK,
    ++atau memilih tindakan <em>Done</em> di sisi kiri action-bar.</p>
    ++
    ++<p class="note"><strong>Catatan:</strong> Action-bar kontekstual tidak harus
    ++terkait dengan <a href="{@docRoot}guide/topics/ui/actionbar.html">action-bar</a>. Action-bar ini beroperasi
    ++secara independen, walaupun action-bar kontekstual secara visual mengambil alih
    ++posisi action-bar.</p>
    ++
    ++<p>Jika Anda mengembangkan aplikasi untuk Android 3.0 (API level 11) atau yang lebih tinggi, Anda
    ++biasanya harus menggunakan mode tindakan kontekstual untuk menampilkan tindakan kontekstual, sebagai ganti <a href="#FloatingContextMenu">menu konteks mengambang</a>.</p>
    ++
    ++<p>Untuk tampilan yang menyediakan tindakan kontekstual, Anda biasanya harus memanggil mode tindakan kontekstual
    ++pada salah satu dari dua kejadian (atau keduanya):</p>
    ++<ul>
    ++  <li>Pengguna mengklik-lama pada tampilan.</li>
    ++  <li>Pengguna memilih kotak cek atau komponen UI yang serupa dalam tampilan.</li>
    ++</ul>
    ++
    ++<p>Cara aplikasi memanggil mode tindakan kontekstual dan mendefinisikan perilaku setiap
    ++tindakan bergantung pada desain Anda. Pada dasarnya ada dua desain:</p>
    ++<ul>
    ++  <li>Untuk tindakan kontekstual pada tampilan individual dan tak didukung.</li>
    ++  <li>Untuk tindakan kontekstual batch pada grup item dalam {@link
    ++android.widget.ListView} atau {@link android.widget.GridView} (memungkinkan pengguna memilih beberapa
    ++item dan melakukan tindakan pada semua item itu).</li>
    ++</ul>
    ++
    ++<p>Bagian berikut ini menjelaskan penyiapan yang diperlukan untuk setiap skenario.</p>
    ++
    ++
    ++<h4 id="CABforViews">Mengaktifkan mode tindakan kontekstual untuk tampilan individual</h4>
    ++
    ++<p>Jika Anda ingin memanggil mode tindakan kontekstual hanya bila pengguna memilih
    ++tampilan tertentu, Anda harus:</p>
    ++<ol>
    ++  <li>Mengimplementasikan antarmuka {@link android.view.ActionMode.Callback}. Dalam metode callback-nya, Anda
    ++bisa menetapkan tindakan untuk action-bar kontekstual, merespons kejadian klik pada item tindakan, dan
    ++menangani kejadian daur hidup lainnya untuk mode tindakan itu.</li>
    ++  <li>Memanggil {@link android.app.Activity#startActionMode startActionMode()} bila Anda ingin menampilkan
    ++action-bar (seperti saat pengguna mengklik-lama pada tampilan).</li>
    ++</ol>
    ++
    ++<p>Misalnya:</p>
    ++
    ++<ol>
    ++  <li>Implementasikan antarmuka {@link android.view.ActionMode.Callback ActionMode.Callback}:
    ++<pre>
    ++private ActionMode.Callback mActionModeCallback = new ActionMode.Callback() {
    ++
    ++    // Called when the action mode is created; startActionMode() was called
    ++    &#64;Override
    ++    public boolean onCreateActionMode(ActionMode mode, Menu menu) {
    ++        // Inflate a menu resource providing context menu items
    ++        MenuInflater inflater = mode.getMenuInflater();
    ++        inflater.inflate(R.menu.context_menu, menu);
    ++        return true;
    ++    }
    ++
    ++    // Called each time the action mode is shown. Always called after onCreateActionMode, but
    ++    // may be called multiple times if the mode is invalidated.
    ++    &#64;Override
    ++    public boolean onPrepareActionMode(ActionMode mode, Menu menu) {
    ++        return false; // Return false if nothing is done
    ++    }
    ++
    ++    // Called when the user selects a contextual menu item
    ++    &#64;Override
    ++    public boolean onActionItemClicked(ActionMode mode, MenuItem item) {
    ++        switch (item.getItemId()) {
    ++            case R.id.menu_share:
    ++                shareCurrentItem();
    ++                mode.finish(); // Action picked, so close the CAB
    ++                return true;
    ++            default:
    ++                return false;
    ++        }
    ++    }
    ++
    ++    // Called when the user exits the action mode
    ++    &#64;Override
    ++    public void onDestroyActionMode(ActionMode mode) {
    ++        mActionMode = null;
    ++    }
    ++};
    ++</pre>
    ++
    ++<p>Perhatikan bahwa kejadian callback ini hampir persis sama dengan callback untuk <a href="#options-menu">menu opsi</a>, hanya saja setiap callback ini juga meneruskan objek {@link
    ++android.view.ActionMode} yang terkait dengan kejadian. Anda bisa menggunakan API {@link
    ++android.view.ActionMode} untuk membuat berbagai perubahan pada CAB, seperti merevisi judul dan
    ++subjudul dengan {@link android.view.ActionMode#setTitle setTitle()} dan {@link
    ++android.view.ActionMode#setSubtitle setSubtitle()} (berguna untuk menunjukkan jumlah item
    ++yang dipilih).</p>
    ++
    ++<p>Juga perhatikan bahwa contoh di atas mengatur variabel {@code mActionMode} ke nol bila
    ++mode tindakan dimusnahkan. Dalam langkah berikutnya, Anda akan melihat cara variabel diinisialisasi dan kegunaan menyimpan
    ++variabel anggota dalam aktivitas atau fragmen.</p>
    ++</li>
    ++
    ++  <li>Panggil {@link android.app.Activity#startActionMode startActionMode()} untuk mengaktifkan
    ++mode tindakan kontekstual bila sesuai, seperti saat merespons klik-lama pada {@link
    ++android.view.View}:</p>
    ++
    ++<pre>
    ++someView.setOnLongClickListener(new View.OnLongClickListener() {
    ++    // Called when the user long-clicks on someView
    ++    public boolean onLongClick(View view) {
    ++        if (mActionMode != null) {
    ++            return false;
    ++        }
    ++
    ++        // Start the CAB using the ActionMode.Callback defined above
    ++        mActionMode = getActivity().startActionMode(mActionModeCallback);
    ++        view.setSelected(true);
    ++        return true;
    ++    }
    ++});
    ++</pre>
    ++
    ++<p>Bila Anda memanggil {@link android.app.Activity#startActionMode startActionMode()}, sistem akan mengembalikan
    ++{@link android.view.ActionMode} yang dibuat. Dengan menyimpannya dalam variabel anggota, Anda bisa
    ++membuat perubahan ke action-bar kontekstual sebagai respons terhadap kejadian lainnya. Dalam contoh di atas,
    ++{@link android.view.ActionMode} digunakan untuk memastikan bahwa instance {@link android.view.ActionMode}
    ++tidak dibuat kembali jika sudah aktif, dengan memeriksa apakah anggota bernilai nol sebelum memulai
    ++mode tindakan.</p>
    ++</li>
    ++</ol>
    ++
    ++
    ++
    ++<h4 id="CABforListView">Mengaktifkan tindakan kontekstual batch dalam ListView atau GridView</h4>
    ++
    ++<p>Jika Anda memiliki sekumpulan item dalam {@link android.widget.ListView} atau {@link
    ++android.widget.GridView} (atau ekstensi {@link android.widget.AbsListView} lainnya) dan ingin
    ++mengizinkan pengguna melakukan tindakan batch, Anda harus:</p>
    ++
    ++<ul>
    ++  <li>Mengimplementasikan antarmuka {@link android.widget.AbsListView.MultiChoiceModeListener} dan mengaturnya
    ++untuk grup tampilan dengan {@link android.widget.AbsListView#setMultiChoiceModeListener
    ++setMultiChoiceModeListener()}. Dalam metode callback listener, Anda bisa menetapkan tindakan
    ++untuk action-bar kontekstual, merespons kejadian klik pada item tindakan, dan menangani callback lainnya
    ++yang diwarisi dari antarmuka {@link android.view.ActionMode.Callback}.</li>
    ++
    ++  <li>Panggil {@link android.widget.AbsListView#setChoiceMode setChoiceMode()} dengan argumen {@link
    ++android.widget.AbsListView#CHOICE_MODE_MULTIPLE_MODAL}.</li>
    ++</ul>
    ++
    ++<p>Misalnya:</p>
    ++
    ++<pre>
    ++ListView listView = getListView();
    ++listView.setChoiceMode(ListView.CHOICE_MODE_MULTIPLE_MODAL);
    ++listView.setMultiChoiceModeListener(new MultiChoiceModeListener() {
    ++
    ++    &#64;Override
    ++    public void onItemCheckedStateChanged(ActionMode mode, int position,
    ++                                          long id, boolean checked) {
    ++        // Here you can do something when items are selected/de-selected,
    ++        // such as update the title in the CAB
    ++    }
    ++
    ++    &#64;Override
    ++    public boolean onActionItemClicked(ActionMode mode, MenuItem item) {
    ++        // Respond to clicks on the actions in the CAB
    ++        switch (item.getItemId()) {
    ++            case R.id.menu_delete:
    ++                deleteSelectedItems();
    ++                mode.finish(); // Action picked, so close the CAB
    ++                return true;
    ++            default:
    ++                return false;
    ++        }
    ++    }
    ++
    ++    &#64;Override
    ++    public boolean onCreateActionMode(ActionMode mode, Menu menu) {
    ++        // Inflate the menu for the CAB
    ++        MenuInflater inflater = mode.getMenuInflater();
    ++        inflater.inflate(R.menu.context, menu);
    ++        return true;
    ++    }
    ++
    ++    &#64;Override
    ++    public void onDestroyActionMode(ActionMode mode) {
    ++        // Here you can make any necessary updates to the activity when
    ++        // the CAB is removed. By default, selected items are deselected/unchecked.
    ++    }
    ++
    ++    &#64;Override
    ++    public boolean onPrepareActionMode(ActionMode mode, Menu menu) {
    ++        // Here you can perform updates to the CAB due to
    ++        // an {@link android.view.ActionMode#invalidate} request
    ++        return false;
    ++    }
    ++});
    ++</pre>
    ++
    ++<p>Demikian saja. Kini bila pengguna memilih item dengan klik-lama, sistem akan memanggil metode {@link
    ++android.widget.AbsListView.MultiChoiceModeListener#onCreateActionMode onCreateActionMode()}
    ++dan menampilkan action-bar kontekstual bersama tindakan yang ditetapkan. Saat
    ++action-bar kontekstual terlihat, pengguna bisa memilih item tambahan.</p>
    ++
    ++<p>Dalam beberapa kasus di mana tindakan kontekstual menyediakan item tindakan umum, Anda mungkin
    ++ingin menambahkan kotak cek atau elemen UI serupa yang memungkinkan pengguna memilih item, karena pengguna
    ++mungkin tidak menemukan perilaku klik-lama. Bila pengguna memilih kotak cek itu, Anda
    ++bisa memanggil mode tindakan kontekstual dengan mengatur item daftar yang bersangkutan ke
    ++status diberi tanda cek dengan {@link android.widget.AbsListView#setItemChecked setItemChecked()}.</p>
    ++
    ++
    ++
    ++
    ++<h2 id="PopupMenu">Membuat Menu Popup</h2>
    ++
    ++<div class="figure" style="width:220px">
    ++<img src="{@docRoot}images/ui/popupmenu.png" alt="" />
    ++<p><strong>Gambar 4.</strong> Menu popup dalam aplikasi Gmail, dikaitkan pada
    ++tombol kelebihan di sudut kanan atas.</p>
    ++</div>
    ++
    ++<p>{@link android.widget.PopupMenu} adalah menu modal yang dikaitkan pada {@link android.view.View}.
    ++Menu ini muncul di bawah tampilan jangkar jika ada ruang, atau di atas tampilan jika tidak ada. Menu ini berguna untuk:</p>
    ++<ul>
    ++  <li>Menyediakan menu bergaya kelebihan (overflow) untuk tindakan yang <em>berkaitan dengan</em> konten tertentu (seperti
    ++header email Gmail, yang ditampilkan dalam gambar 4).
    ++    <p class="note"><strong>Catatan:</strong> Ini tidak sama dengan menu konteks, yang umumnya
    ++untuk tindakan yang <em>memengaruhi</em> konten yang dipilih. Untuk tindakan yang memengaruhi
    ++konten yang dipilih, gunakan <a href="#CAB">mode tindakan kontekstual</a> atau <a href="#FloatingContextMenu">menu konteks mengambang</a>.</p></li>
    ++  <li>Menyediakan bagian kedua dari kalimat perintah (seperti tombol bertanda "Tambah"
    ++yang menghasilkan menu popup dengan berbagai opsi "Tambah").</li>
    ++  <li>Menyediakan daftar menurun yang serupa dengan {@link android.widget.Spinner} yang tidak mempertahankan
    ++pilihan persisten.</li>
    ++</ul>
    ++
    ++
    ++<p class="note"><strong>Catatan:</strong> {@link android.widget.PopupMenu} tersedia dengan API
    ++level 11 dan yang lebih tinggi.</p>
    ++
    ++<p>Jika Anda <a href="#xml">mendefinisikan menu dalam XML</a>, berikut ini adalah cara Anda menampilkan menu popup:</p>
    ++<ol>
    ++  <li>Buat instance {@link android.widget.PopupMenu} bersama konstruktornya, yang mengambil
    ++aplikasi saat ini {@link android.content.Context} dan {@link android.view.View} yang akan menjadi tempat mengaitkan
    ++menu.</li>
    ++  <li>Gunakan {@link android.view.MenuInflater} untuk memekarkan sumber daya menu Anda ke dalam objek {@link
    ++android.view.Menu} yang dikembalikan oleh {@link
    ++android.widget.PopupMenu#getMenu() PopupMenu.getMenu()}. Pada API level 14 ke atas, Anda bisa menggunakan
    ++{@link android.widget.PopupMenu#inflate PopupMenu.inflate()} sebagai gantinya.</li>
    ++  <li>Panggil {@link android.widget.PopupMenu#show() PopupMenu.show()}.</li>
    ++</ol>
    ++
    ++<p>Misalnya, berikut ini adalah tombol dengan atribut {@link android.R.attr#onClick android:onClick}
    ++yang menampilkan menu popup:</p>
    ++
    ++<pre>
    ++&lt;ImageButton
    ++    android:layout_width="wrap_content"
    ++    android:layout_height="wrap_content"
    ++    android:src="@drawable/ic_overflow_holo_dark"
    ++    android:contentDescription="@string/descr_overflow_button"
    ++    android:onClick="showPopup" />
    ++</pre>
    ++
    ++<p>Aktivitas nanti bisa menampilkan menu popup seperti ini:</p>
    ++
    ++<pre>
    ++public void showPopup(View v) {
    ++    PopupMenu popup = new PopupMenu(this, v);
    ++    MenuInflater inflater = popup.getMenuInflater();
    ++    inflater.inflate(R.menu.actions, popup.getMenu());
    ++    popup.show();
    ++}
    ++</pre>
    ++
    ++<p>Dalam API level 14 dan yang lebih tinggi, Anda bisa menggabungkan dua baris yang memekarkan menu dengan {@link
    ++android.widget.PopupMenu#inflate PopupMenu.inflate()}.</p>
    ++
    ++<p>Menu akan menghilang bila pengguna memilih item atau menyentuh di luar
    ++area menu. Anda bisa mendengarkan kejadian menghilangkan dengan menggunakan {@link
    ++android.widget.PopupMenu.OnDismissListener}.</p>
    ++
    ++<h3 id="PopupEvents">Menangani kejadian klik</h3>
    ++
    ++<p>Untuk melakukan suatu
    ++tindakan bila pengguna memilih item menu, Anda harus mengimplementasikan antarmuka {@link
    ++android.widget.PopupMenu.OnMenuItemClickListener} dan mendaftarkannya pada {@link
    ++android.widget.PopupMenu} dengan memanggil {@link android.widget.PopupMenu#setOnMenuItemClickListener
    ++setOnMenuItemclickListener()}. Bila pengguna memilih item, sistem akan memanggil callback {@link
    ++android.widget.PopupMenu.OnMenuItemClickListener#onMenuItemClick onMenuItemClick()} dalam
    ++antarmuka Anda.</p>
    ++
    ++<p>Misalnya:</p>
    ++
    ++<pre>
    ++public void showMenu(View v) {
    ++    PopupMenu popup = new PopupMenu(this, v);
    ++
    ++    // This activity implements OnMenuItemClickListener
    ++    popup.setOnMenuItemClickListener(this);
    ++    popup.inflate(R.menu.actions);
    ++    popup.show();
    ++}
    ++
    ++&#64;Override
    ++public boolean onMenuItemClick(MenuItem item) {
    ++    switch (item.getItemId()) {
    ++        case R.id.archive:
    ++            archive(item);
    ++            return true;
    ++        case R.id.delete:
    ++            delete(item);
    ++            return true;
    ++        default:
    ++            return false;
    ++    }
    ++}
    ++</pre>
    ++
    ++
    ++<h2 id="groups">Membuat Grup Menu</h2>
    ++
    ++<p>Grup menu adalah sekumpulan item menu yang sama-sama memiliki ciri (trait) tertentu. Dengan grup, Anda
    ++bisa:</p>
    ++<ul>
    ++  <li>Menampilkan atau menyembunyikan semua item dengan {@link android.view.Menu#setGroupVisible(int,boolean)
    ++setGroupVisible()}</li>
    ++  <li>Mengaktifkan atau mennonaktifkan semua item dengan {@link android.view.Menu#setGroupEnabled(int,boolean)
    ++setGroupEnabled()}</li>
    ++  <li>Menetapkan apakah semua item bisa diberi tanda cek dengan {@link
    ++android.view.Menu#setGroupCheckable(int,boolean,boolean) setGroupCheckable()}</li>
    ++</ul>
    ++
    ++<p>Anda bisa membuat grup dengan menyarangkan elemen-elemen {@code &lt;item&gt;} dalam elemen {@code &lt;group&gt;}
    ++dalam sumber daya menu atau dengan menetapkan ID grup dengan metode {@link
    ++android.view.Menu#add(int,int,int,int) add()}.</p>
    ++
    ++<p>Berikut ini adalah contoh sumber daya menu yang berisi sebuah grup:</p>
    ++
    ++<pre>
    ++&lt;?xml version="1.0" encoding="utf-8"?&gt;
    ++&lt;menu xmlns:android="http://schemas.android.com/apk/res/android"&gt;
    ++    &lt;item android:id="@+id/menu_save"
    ++          android:icon="@drawable/menu_save"
    ++          android:title="@string/menu_save" /&gt;
    ++    &lt;!-- menu group --&gt;
    ++    &lt;group android:id="@+id/group_delete"&gt;
    ++        &lt;item android:id="@+id/menu_archive"
    ++              android:title="@string/menu_archive" /&gt;
    ++        &lt;item android:id="@+id/menu_delete"
    ++              android:title="@string/menu_delete" /&gt;
    ++    &lt;/group&gt;
    ++&lt;/menu&gt;
    ++</pre>
    ++
    ++<p>Item yang berada dalam grup akan muncul pada level yang sama dengan item pertama&mdash;ketiga item
    ++dalam menu adalah bersaudara. Akan tetapi, Anda bisa memodifikasi ciri kedua
    ++item dalam grup dengan mengacu ID grup dan menggunakan metode yang tercantum di atas. Sistem
    ++juga tidak akan memisahkan item yang telah dikelompokkan. Misalnya, jika Anda mendeklarasikan {@code
    ++android:showAsAction="ifRoom"} untuk tiap item, item tersebut akan muncul dalam
    ++action-bar atau dalam kelebihan tindakan.</p>
    ++
    ++
    ++<h3 id="checkable">Menggunakan item menu yang bisa diberi tanda cek</h3>
    ++
    ++<div class="figure" style="width:200px">
    ++  <img src="{@docRoot}images/radio_buttons.png" height="333" alt="" />
    ++  <p class="img-caption"><strong>Gambar 5.</strong> Cuplikan layar submenu dengan
    ++item yang bisa diberi tanda cek.</p>
    ++</div>
    ++
    ++<p>Menu bisa digunakan sebagai antarmuka untuk mengaktifkan dan menonaktifkan opsi, menggunakan kotak cek untuk
    ++opsi mandiri, atau tombol radio untuk grup
    ++opsi yang saling eksklusif. Gambar 5 menampilkan submenu dengan item yang bisa diberi tanda cek dengan
    ++tombol radio.</p>
    ++
    ++<p class="note"><strong>Catatan:</strong> Item menu dalam Icon Menu (dari menu opsi) tidak bisa
    ++menampilkan kotak cek atau tombol radio. Jika Anda memilih untuk membuat item dalam Icon Menu yang bisa diberi tanda cek,
    ++Anda harus menandai status diberi tanda cek secara manual dengan menukar ikon dan/atau teks
    ++tiap kali statusnya berubah.</p>
    ++
    ++<p>Anda bisa mendefinisikan perilaku yang bisa diberi tanda cek untuk tiap item menu dengan menggunakan atribut {@code
    ++android:checkable} dalam elemen {@code &lt;item&gt;}, atau untuk seluruh grup dengan
    ++atribut {@code android:checkableBehavior} dalam elemen {@code &lt;group&gt;}. Misalnya
    ++, semua item dalam grup menu ini bisa diberi tanda cek dengan tombol radio:</p>
    ++
    ++<pre>
    ++&lt;?xml version="1.0" encoding="utf-8"?&gt;
    ++&lt;menu xmlns:android="http://schemas.android.com/apk/res/android"&gt;
    ++    &lt;group android:checkableBehavior="single"&gt;
    ++        &lt;item android:id="@+id/red"
    ++              android:title="@string/red" /&gt;
    ++        &lt;item android:id="@+id/blue"
    ++              android:title="@string/blue" /&gt;
    ++    &lt;/group&gt;
    ++&lt;/menu&gt;
    ++</pre>
    ++
    ++<p>Atribut {@code android:checkableBehavior} menerima:
    ++<dl>
    ++  <dt>{@code single}</dt>
    ++    <dd>Hanya satu item dari grup ini yang bisa diberi tanda cek (tombol radio)</dd>
    ++  <dt>{@code all}</dt>
    ++    <dd>Semua item bisa diberi tanda cek (kotak cek)</dd>
    ++  <dt>{@code none}</dt>
    ++    <dd>Tidak ada item yang bisa diberi tanda cek</dd>
    ++</dl>
    ++
    ++<p>Anda bisa menerapkan status diberi tanda cek default pada suatu item dengan menggunakan atribut {@code android:checked} dalam
    ++elemen {@code &lt;item&gt;} dan mengubahnya dalam kode dengan metode {@link
    ++android.view.MenuItem#setChecked(boolean) setChecked()}.</p>
    ++
    ++<p>Bila item yang bisa diberi tanda cek dipilih, sistem akan memanggil metode callback setiap item yang dipilih
    ++(seperti {@link android.app.Activity#onOptionsItemSelected(MenuItem) onOptionsItemSelected()}). Di sinilah
    ++Anda harus mengatur status kotak cek itu, karena kotak cek atau tombol radio tidak
    ++mengubah statusnya secara otomatis. Anda bisa melakukan query status saat ini suatu item (seperti sebelum
    ++pengguna memilihnya) dengan {@link android.view.MenuItem#isChecked()} kemudian mengatur status diberi tanda cek dengan
    ++{@link android.view.MenuItem#setChecked(boolean) setChecked()}. Misalnya:</p>
    ++
    ++<pre>
    ++&#64;Override
    ++public boolean onOptionsItemSelected(MenuItem item) {
    ++    switch (item.getItemId()) {
    ++        case R.id.vibrate:
    ++        case R.id.dont_vibrate:
    ++            if (item.isChecked()) item.setChecked(false);
    ++            else item.setChecked(true);
    ++            return true;
    ++        default:
    ++            return super.onOptionsItemSelected(item);
    ++    }
    ++}
    ++</pre>
    ++
    ++<p>Jika Anda tidak mengatur status diberi tanda cek dengan cara ini, maka status item (kotak cek atau
    ++tombol radio) yang terlihat tidak akan
    ++berubah bila pengguna memilihnya. Bila Anda telah mengatur status, aktivitas akan menjaga status diberi tanda cek
    ++suatu item sehingga bila nanti pengguna membuka menu, status diberi tanda cek yang Anda
    ++atur akan terlihat.</p>
    ++
    ++<p class="note"><strong>Catatan:</strong>
    ++Item menu yang bisa diberi tanda cek dimaksudkan untuk digunakan hanya atas dasar per sesi dan tidak disimpan setelah
    ++aplikasi dimusnahkan. Jika Anda memiliki pengaturan aplikasi yang ingin disimpan untuk pengguna,
    ++Anda harus menyimpan data dengan menggunakan <a href="{@docRoot}guide/topics/data/data-storage.html#pref">Shared Preferences</a>.</p>
    ++
    ++
    ++
    ++<h2 id="intents">Menambahkan Item Menu Berdasarkan Intent</h2>
    ++
    ++<p>Kadang-kadang Anda ingin supaya item menu menjalankan aktivitas dengan menggunakan {@link android.content.Intent}
    ++(baik aktivitas berada dalam aplikasi Anda maupun di aplikasi lain). Bila Anda mengetahui intent
    ++yang ingin digunakan dan memiliki item menu tertentu yang harus memulai intent, Anda bisa mengeksekusi
    ++intent dengan {@link android.app.Activity#startActivity(Intent) startActivity()} selama
    ++metode callback bila-item-dipilih yang sesuai (seperti callback {@link
    ++android.app.Activity#onOptionsItemSelected(MenuItem) onOptionsItemSelected()}).</p>
    ++
    ++<p>Akan tetapi, jika Anda tidak yakin apakah perangkat pengguna
    ++berisi aplikasi yang menangani intent, maka menambahkan item menu yang memanggilnya bisa mengakibatkan
    ++item menu tidak berfungsi, karena intent tidak bisa diterjemahkan menjadi
    ++aktivitas. Untuk mengatasi hal ini, Android memungkinkan Anda menambahkan item menu secara dinamis ke menu
    ++bila Android menemukan aktivitas pada perangkat yang menangani intent Anda.</p>
    ++
    ++<p>Untuk menambahkan item menu berdasarkan aktivitas tersedia yang menerima intent:</p>
    ++<ol>
    ++  <li>Definisikan
    ++intent dengan kategori {@link android.content.Intent#CATEGORY_ALTERNATIVE} dan/atau
    ++{@link android.content.Intent#CATEGORY_SELECTED_ALTERNATIVE}, plus kebutuhan lainnya.</li>
    ++  <li>Panggil {@link
    ++android.view.Menu#addIntentOptions(int,int,int,ComponentName,Intent[],Intent,int,MenuItem[])
    ++Menu.addIntentOptions()}. Android kemudian akan mencari setiap aplikasi yang bisa melakukan intent
    ++dan menambahkannya ke menu Anda.</li>
    ++</ol>
    ++
    ++<p>Jika tidak ada aplikasi terinstal
    ++yang memenuhi intent, maka tidak ada item menu yang ditambahkan.</p>
    ++
    ++<p class="note"><strong>Catatan:</strong>
    ++{@link android.content.Intent#CATEGORY_SELECTED_ALTERNATIVE} digunakan untuk menangani
    ++elemen yang saat ini dipilih pada layar. Jadi, metode hanya digunakan saat membuat Menu dalam {@link
    ++android.app.Activity#onCreateContextMenu(ContextMenu,View,ContextMenuInfo)
    ++onCreateContextMenu()}.</p>
    ++
    ++<p>Misalnya:</p>
    ++
    ++<pre>
    ++&#64;Override
    ++public boolean onCreateOptionsMenu(Menu menu){
    ++    super.onCreateOptionsMenu(menu);
    ++
    ++    // Create an Intent that describes the requirements to fulfill, to be included
    ++    // in our menu. The offering app must include a category value of Intent.CATEGORY_ALTERNATIVE.
    ++    Intent intent = new Intent(null, dataUri);
    ++    intent.addCategory(Intent.CATEGORY_ALTERNATIVE);
    ++
    ++    // Search and populate the menu with acceptable offering applications.
    ++    menu.addIntentOptions(
    ++         R.id.intent_group,  // Menu group to which new items will be added
    ++         0,      // Unique item ID (none)
    ++         0,      // Order for the items (none)
    ++         this.getComponentName(),   // The current activity name
    ++         null,   // Specific items to place first (none)
    ++         intent, // Intent created above that describes our requirements
    ++         0,      // Additional flags to control items (none)
    ++         null);  // Array of MenuItems that correlate to specific items (none)
    ++
    ++    return true;
    ++}</pre>
    ++
    ++<p>Untuk setiap aktivitas yang diketahui menyediakan filter intent yang cocok dengan intent yang didefinisikan, item menu
    ++akan ditambahkan, menggunakan nilai dalam filter intent <code>android:label</code> sebagai
    ++judul item menu dan ikon aplikasi sebagai ikon item menu. Metode
    ++{@link android.view.Menu#addIntentOptions(int,int,int,ComponentName,Intent[],Intent,int,MenuItem[])
    ++addIntentOptions()} mengembalikan jumlah item menu yang ditambahkan.</p>
    ++
    ++<p class="note"><strong>Catatan:</strong> Bila Anda memanggil {@link
    ++android.view.Menu#addIntentOptions(int,int,int,ComponentName,Intent[],Intent,int,MenuItem[])
    ++addIntentOptions()}, metode ini akan mengesampingkan setiap dan semua item menu menurut grup menu yang ditetapkan dalam argumen
    ++pertama.</p>
    ++
    ++
    ++<h3 id="AllowingToAdd">Memungkinkan aktivitas Anda ditambahkan ke menu lain</h3>
    ++
    ++<p>Anda juga bisa menawarkan layanan aktivitas Anda pada aplikasi lainnya, sehingga
    ++aplikasi Anda bisa disertakan dalam menu aplikasi lain (membalik peran yang dijelaskan di atas).</p>
    ++
    ++<p>Agar bisa dimasukkan dalam menu aplikasi lain, Anda perlu mendefinisikan
    ++filter intent seperti biasa, tetapi pastikan menyertakan nilai-nilai {@link android.content.Intent#CATEGORY_ALTERNATIVE}
    ++dan/atau {@link android.content.Intent#CATEGORY_SELECTED_ALTERNATIVE} untuk
    ++kategori filter intent. Misalnya:</p>
    ++<pre>
    ++&lt;intent-filter label="&#64;string/resize_image">
    ++    ...
    ++    &lt;category android:name="android.intent.category.ALTERNATIVE" />
    ++    &lt;category android:name="android.intent.category.SELECTED_ALTERNATIVE" />
    ++    ...
    ++&lt;/intent-filter>
    ++</pre>
    ++
    ++<p>Baca selengkapnya tentang penulisan filter intent dalam dokumen
    ++<a href="/guide/components/intents-filters.html">Intent dan Filter Intent</a>.</p>
    ++
    ++<p>Untuk contoh aplikasi yang menggunakan teknik ini, lihat contoh kode
    ++<a href="{@docRoot}resources/samples/NotePad/src/com/example/android/notepad/NoteEditor.html">Note
    ++Pad</a>.</p>
    +diff --git a/docs/html-intl/intl/id/guide/topics/ui/multi-window.jd b/docs/html-intl/intl/id/guide/topics/ui/multi-window.jd
    +new file mode 100644
    +index 0000000..5e7b3d9
    +--- /dev/null
    ++++ b/docs/html-intl/intl/id/guide/topics/ui/multi-window.jd
    +@@ -0,0 +1,589 @@
    ++page.title=Dukungan Multi-Jendela
    ++page.metaDescription=Dukungan baru di Android N untuk menampilkan lebih dari satu aplikasi sekaligus.
    ++page.keywords="multi-window", "android N", "split screen", "free-form"
    ++
    ++@jd:body
    ++
    ++<div id="tb-wrapper">
    ++  <div id="tb">
    ++    <h2>Dalam dokumen ini</h2>
    ++      <ol>
    ++        <li><a href="#overview">Ringkasan</a></li>
    ++        <li><a href="#lifecycle">Daur Hidup Multi-Jendela</a></li>
    ++        <li><a href="#configuring">Mengonfigurasi Aplikasi Anda untuk Mode
    ++              Multi-Jendela</a></li>
    ++        <li><a href="#running">Menjalankan Aplikasi Anda dalam Mode Multi-Jendela</a></li>
    ++        <li><a href="#testing">Menguji Dukungan Multi-Jendela Aplikasi Anda</a></li>
    ++      </ol>
    ++    <h2>Lihat Juga</h2>
    ++      <ol>
    ++        <li><a class="external-link" href="https://github.com/googlesamples/android-MultiWindowPlayground">Aplikasi contoh Playground
    ++          Multi-Jendela</a></li>
    ++        <li><a class="external-link" href="https://medium.com/google-developers/5-tips-for-preparing-for-multi-window-in-android-n-7bed803dda64">Lima Tip untuk Mempersiapkan Multi-Jendela di Android N</a></li>
    ++      </ol>
    ++  </div>
    ++</div>
    ++
    ++<p>
    ++  Android N menambahkan dukungan untuk menampilkan lebih dari satu aplikasi
    ++  sekaligus. Pada perangkat genggam, dua aplikasi bisa berjalan berdampingan atau
    ++  atas-bawah dalam mode <em>layar terbagi</em>. Pada perangkat TV, aplikasi bisa
    ++  menggunakan mode <em>gambar-dalam-gambar</em> untuk melanjutkan pemutaran video selagi pengguna
    ++  berinteraksi dengan aplikasi lain.
    ++</p>
    ++
    ++<p>
    ++  Jika Anda membangun aplikasi Anda dengan N Preview SDK, Anda bisa mengonfigurasi cara aplikasi
    ++  menangani tampilan multi-jendela. Misalnya, Anda bisa menetapkan dimensi
    ++  minimum yang diizinkan aktivitas Anda. Anda juga bisa menonaktifkan tampilan multi-jendela untuk
    ++   aplikasi, sehingga memastikan sistem hanya menampilkan aplikasi Anda dalam mode
    ++  layar penuh.
    ++</p>
    ++
    ++<h2 id="overview">Ringkasan</h2>
    ++
    ++<p>
    ++  Android N memungkinkan beberapa aplikasi berbagi layar sekaligus. Misalnya,
    ++  pengguna bisa membagi layar, melihat halaman web di sisi kiri
    ++  sambil menulis email di sisi kanan. Pengalaman pengguna bergantung pada
    ++  perangkat:
    ++</p>
    ++
    ++<ul>
    ++  <li>Perangkat genggam yang menjalankan Android N menawarkan mode
    ++  layar terbagi. Di mode ini, sistem mengisi layar dengan dua aplikasi, menampilkannya secara
    ++  berdampingan atau atas-bawah. Pengguna bisa menyeret garis pembagi
    ++   yang memisahkan keduanya untuk membuat satu aplikasi lebih besar dan yang lainnya lebih kecil.
    ++  </li>
    ++
    ++  <li>Pada Nexus Player yang menjalankan Android N, aplikasi bisa menempatkan diri
    ++  dalam <a href="picture-in-picture.html">mode gambar-dalam-gambar</a>, yang memungkinkannya
    ++  untuk terus menampilkan materi selagi pengguna menjelajahi atau berinteraksi dengan
    ++   aplikasi lain.
    ++  </li>
    ++
    ++  <li>Produsen perangkat berukuran lebih besar bisa memilih untuk mengaktifkan mode
    ++ bentuk bebas, di mana pengguna bisa bebas mengubah ukuran setiap aktivitas. Jika
    ++  produsen mengaktifkan fitur ini, perangkat akan menawarkan mode bentuk bebas sebagai tambahan
    ++  untuk mode layar terbagi.
    ++  </li>
    ++</ul>
    ++
    ++<img src="{@docRoot}images/android-7.0/mw-splitscreen.png" alt="" width="650" srcset="{@docRoot}images/android-7.0/mw-splitscreen.png 1x,
    ++    {@docRoot}images/android-7.0/mw-splitscreen_2x.png 2x," id="img-split-screen" />
    ++<p class="img-caption">
    ++  <strong>Gambar 1.</strong> Dua aplikasi berjalan berdampingan dalam mode layar terbagi.
    ++</p>
    ++
    ++<p>
    ++  Pengguna bisa beralih ke mode multi-jendela dengan cara berikut:
    ++</p>
    ++
    ++<ul>
    ++  <li>Jika pengguna membuka <a href="{@docRoot}guide/components/recents.html">layar
    ++  Ringkasan</a> dan menekan lama pada
    ++  judul aktivitas, mereka bisa menyeret aktivitas itu ke bagian yang disorot pada layar
    ++  untuk menempatkan aktivitas dalam mode multi-jendela.
    ++  </li>
    ++
    ++  <li>Jika pengguna menekan lama pada tombol Ringkasan, perangkat akan menempatkan
    ++   aktivitas saat ini dalam mode multi-jendela, dan membuka layar Ringkasan guna
    ++  memungkinkan pengguna memilih aktivitas lain untuk berbagi layar.
    ++  </li>
    ++</ul>
    ++
    ++<p>
    ++  Pengguna bisa <a href="{@docRoot}guide/topics/ui/drag-drop.html">seret dan
    ++  lepas</a> data dari aktivitas satu ke aktivitas lain sewaktu aktivitas berbagi
    ++  layar. (Sebelumnya, pengguna hanya bisa menyeret dan melepas data dalam aktivitas
    ++  tunggal.)
    ++</p>
    ++
    ++<h2 id="lifecycle">Daur Hidup Multi-Jendela</h2>
    ++
    ++<p>
    ++  Mode multi-jendela tidak mengubah <a href="{@docRoot}training/basics/activity-lifecycle/index.html">daur hidup
    ++  aktivitas</a>.
    ++</p>
    ++
    ++<p>
    ++  Dalam mode multi-jendela, hanya aktivitas yang paling sering digunakan pengguna
    ++  yang akan aktif pada waktu tertentu. Aktivitas ini dianggap <em>teratas</em>.
    ++  Semua aktivitas lainnya dalam keadaan berhenti sementara, sekalipun terlihat.
    ++  Akan tetapi, sistem memberikan aktivitas, yang berhenti-sementara-namun-terlihat ini, prioritas lebih tinggi
    ++   daripada aktivitas yang tidak terlihat. Jika pengguna berinteraksi dengan salah satu
    ++  aktivitas yang berhenti sementara, aktivitas tersebut akan dilanjutkan kembali, dan aktivitas
    ++  teratas sebelumnya akan dihentikan sementara.
    ++</p>
    ++
    ++<p class="note">
    ++  <strong>Catatan:</strong> Dalam mode multi-jendela, aplikasi bisa berada dalam keadaan berhenti sementara
    ++  dan masih terlihat oleh pengguna. Sebuah aplikasi mungkin perlu melanjutkan aktivitasnya
    ++   bahkan saat berhenti sementara. Misalnya, aplikasi pemutar video yang ada dalam
    ++   mode berhenti sementara namun terlihat harus tetap menampilkan videonya. Karena alasan
    ++  ini, kami menyarankan aktivitas yang memutar video <em>tidak</em> menghentikan sementara video
    ++   dalam handler {@link android.app.Activity#onPause onPause()} mereka.
    ++  Sebagai gantinya, aktivitas itu harus menghentikan sementara video di {@link android.app.Activity#onStop
    ++  onStop()}, dan melanjutkan pemutaran di {@link android.app.Activity#onStart
    ++  onStart()}.
    ++</p>
    ++
    ++<p>
    ++  Bila pengguna menempatkan aplikasi dalam mode multi-jendela, sistem akan memberi tahu
    ++   aktivitas tersebut mengenai perubahan konfigurasi, sebagaimana ditetapkan dalam <a href="{@docRoot}guide/topics/resources/runtime-changes.html">Menangani Perubahan
    ++  Waktu Proses</a>. Hal ini juga terjadi ketika pengguna mengubah skala aplikasi, atau menempatkan kembali aplikasi
    ++  ke mode layar penuh.
    ++  Pada dasarnya, perubahan ini memiliki implikasi daur hidup aktivitas yang sama
    ++  seperti saat sistem memberi tahu aplikasi bahwa perangkat telah beralih
    ++  dari mode potret ke mode lanskap, kecuali dimensi perangkat
    ++  telah berubah sebagai ganti bertukar posisi. Seperti yang dibahas di <a href="{@docRoot}guide/topics/resources/runtime-changes.html">Menangani Perubahan
    ++  Waktu Proses</a>, aktivitas Anda bisa menangani perubahan konfigurasi itu sendiri, atau
    ++   mengizinkan sistem memusnahkan aktivitas dan membuatnya kembali dengan dimensi
    ++  baru.
    ++</p>
    ++
    ++<p>
    ++  Jika pengguna mengubah ukuran jendela dan membuat dimensinya lebih besar, sistem
    ++   akan mengubah ukuran aktivitas untuk menyesuaikan dengan tindakan pengguna dan mengeluarkan <a href="{@docRoot}guide/topics/resources/runtime-changes.html">perubahan waktu proses</a>
    ++  bila diperlukan. Jika aplikasi tertinggal dibandingkan gambar di area yang baru diekspos,
    ++  sistem untuk sementara mengisi area tersebut dengan warna yang ditetapkan oleh atribut {@link
    ++  android.R.attr#windowBackground windowBackground} atau dengan atribut gaya
    ++  <code>windowBackgroundFallback</code> secara default.
    ++</p>
    ++
    ++<h2 id="configuring">Mengonfigurasi Aplikasi Anda untuk Mode Multi-Jendela</h2>
    ++
    ++<p>
    ++  Jika aplikasi Anda menargetkan Android N, Anda bisa mengonfigurasi bagaimana dan
    ++  apakah aktivitas aplikasi Anda mendukung tampilan multi-jendela. Anda bisa menyetel
    ++  atribut dalam manifes untuk mengontrol ukuran dan layoutnya.
    ++  Setelan atribut aktivitas root berlaku pada semua aktivitas
    ++   dalam tumpukan tugasnya. Misalnya, jika aktivitas root memiliki
    ++  <code>android:resizeableActivity</code> yang disetel ke true, maka semua aktivitas
    ++  dalam tumpukan tugas bisa diubah ukurannya.
    ++</p>
    ++
    ++<p class="note">
    ++  <strong>Catatan:</strong> Jika Anda membangun aplikasi multi-orientasi dengan versi
    ++  SDK lebih rendah dari Android N, dan pengguna menggunakan aplikasi
    ++   dalam mode multi-jendela, sistem akan mengubah ukuran aplikasi secara paksa. Sistem akan menampilkan kotak
    ++  dialog yang memperingatkan pengguna bahwa aplikasi mungkin berperilaku tidak terduga. Sistem
    ++   <em>tidak</em> mengubah ukuran aplikasi yang berorientasi tetap; jika
    ++  pengguna berusaha membuka  aplikasi berorientasi tetap saat mode multi-jendela,
    ++  aplikasi akan menggunakan seluruh layar.
    ++</p>
    ++
    ++<h4 id="resizeableActivity">android:resizeableActivity</h4>
    ++<p>
    ++  Setel atribut ini dalam manifes <code>&lt;activity&gt;</code> Anda atau simpul
    ++  <code>&lt;application&gt;</code> untuk mengaktifkan atau menonaktifkan tampilan
    ++   multi-jendela:
    ++</p>
    ++
    ++<pre>
    ++android:resizeableActivity=["true" | "false"]
    ++</pre>
    ++
    ++<p>
    ++  Jika atribut ini disetel ke true, aktivitas bisa dijalankan di
    ++  mode layar terbagi dan mode bentuk bebas. Jika atribut ini disetel ke false, aktivitas
    ++  tidak akan mendukung mode multi-jendela. Jika nilai ini false, dan pengguna
    ++  berusaha memulai aktivitas dalam mode multi-jendela, aktivitas akan menggunakan
    ++   layar penuh.
    ++</p>
    ++
    ++<p>
    ++  Jika aplikasi Anda menargetkan Android N, namun Anda tidak menetapkan nilai
    ++  untuk atribut ini, nilai atribut default adalah true.
    ++</p>
    ++
    ++<h4 id="supportsPictureInPicture">android:supportsPictureInPicture</h4>
    ++
    ++<p>
    ++  Setel atribut ini dalam simpul <code>&lt;activity&gt;</code> manifes Anda untuk
    ++  menunjukkan apakah aktivitas mendukung tampilan gambar-dalam-gambar. Atribut ini
    ++  diabaikan jika <code>android:resizeableActivity</code> bernilai false.
    ++</p>
    ++
    ++<pre>
    ++android:supportsPictureInPicture=["true" | "false"]
    ++</pre>
    ++
    ++<h3 id="layout">Atribut layout</h3>
    ++
    ++<p>
    ++  Dengan Android N, elemen manifes <code>&lt;layout&gt;</code>
    ++  mendukung beberapa atribut yang memengaruhi cara aktivitas berperilaku dalam
    ++  mode multi-jendela:
    ++</p>
    ++
    ++<dl>
    ++  <dt>
    ++    <code>android:defaultWidth</code>
    ++  </dt>
    ++
    ++  <dd>
    ++    Lebar default aktivitas saat dijalankan dalam mode bentuk bebas.
    ++  </dd>
    ++
    ++  <dt>
    ++    <code>android:defaultHeight</code>
    ++  </dt>
    ++
    ++  <dd>
    ++    Tinggi default aktivitas saat dijalankan dalam mode bentuk bebas.
    ++  </dd>
    ++
    ++  <dt>
    ++    <code>android:gravity</code>
    ++  </dt>
    ++
    ++  <dd>
    ++    Penempatan awal dari aktivitas saat dibuka dalam mode bentuk bebas. Lihat referensi
    ++    {@link android.view.Gravity} untuk mengetahui nilai yang cocok.
    ++  </dd>
    ++
    ++  <dt>
    ++    <code>android:minimalHeight</code>, <code>android:minimalWidth</code>
    ++  </dt>
    ++
    ++  <dd>
    ++    Tinggi dan lebar minimum untuk aktivitas dalam mode layar terbagi
    ++    dan mode bentuk bebas. Jika pengguna memindahkan pembagi dalam mode layar terbagi
    ++    untuk membuat aktivitas lebih kecil dari minimum yang ditetapkan, sistem akan memangkas
    ++   aktivitas sesuai dengan ukuran yang diminta pengguna.
    ++  </dd>
    ++</dl>
    ++
    ++<p>
    ++  Misalnya, kode berikut menampilkan cara menetapkan ukuran dan lokasi default
    ++  aktivitas, dan ukuran minimumnya, bila aktivitas ditampilkan dalam
    ++   mode bentuk bebas:
    ++</p>
    ++
    ++<pre>
    ++&lt;activity android:name=".MyActivity"&gt;
    ++    &lt;layout android:defaultHeight="500dp"
    ++          android:defaultWidth="600dp"
    ++          android:gravity="top|end"
    ++          android:minimalHeight="450dp"
    ++          android:minimalWidth="300dp" /&gt;
    ++&lt;/activity&gt;
    ++</pre>
    ++
    ++<h2 id="running">Menjalankan Aplikasi Anda dalam Mode Multi-Jendela</h2>
    ++
    ++<p>
    ++  Android N menawarkan fungsionalitas baru untuk mendukung aplikasi yang bisa berjalan
    ++  dalam mode multi-jendela.
    ++</p>
    ++
    ++<h3 id="disabled-features">Fitur yang dinonaktifkan dalam mode multi-jendela</h3>
    ++
    ++<p>
    ++  Fitur tertentu akan dinonaktifkan atau diabaikan bila perangkat berada dalam mode
    ++  multi-jendela, karena dianggap tidak logis bagi suatu aktivitas yang mungkin berbagi
    ++  layar perangkat dengan aktivitas atau aplikasi lainnya. Fitur tersebut meliputi:
    ++
    ++<ul>
    ++  <li>Beberapa opsi penyesuaian di <a href="{@docRoot}training/system-ui/index.html">System UI</a>
    ++  dinonaktifkan; misalnya, aplikasi tidak bisa menyembunyikan bilah status
    ++  jika tidak berjalan dalam mode layar penuh.
    ++  </li>
    ++
    ++  <li>Sistem akan mengabaikan perubahan pada atribut <code><a href=
    ++  "{@docRoot}guide/topics/manifest/activity-element.html#screen"
    ++  >android:screenOrientation</a></code>.
    ++  </li>
    ++</ul>
    ++
    ++<h3 id="change-notification">Pemberitahuan perubahan multi-jendela dan melakukan kueri</h3>
    ++
    ++<p>
    ++  Metode baru berikut telah ditambahkan ke kelas {@link android.app.Activity}
    ++  untuk mendukung tampilan multi-jendela. Untuk mengetahui detail tentang setiap
    ++  metode, lihat <a href="{@docRoot}preview/setup-sdk.html#docs-dl">Referensi N
    ++ Preview SDK</a>.
    ++</p>
    ++
    ++<dl>
    ++  <dt>
    ++    <code>Activity.isInMultiWindowMode()</code>
    ++  </dt>
    ++
    ++  <dd>
    ++    Panggil untuk mengetahui apakah aktivitas berada dalam mode multi-jendela.
    ++  </dd>
    ++
    ++  <dt>
    ++    <code>Activity.isInPictureInPictureMode()</code>
    ++  </dt>
    ++
    ++  <dd>
    ++    Panggil untuk mengetahui apakah aktivitas berada dalam mode gambar-dalam-gambar.
    ++
    ++    <p class="note">
    ++      <strong>Catatan:</strong> Mode gambar-dalam-gambar adalah kasus khusus pada
    ++      mode multi-jendela. Jika <code>myActivity.isInPictureInPictureMode()</code>
    ++     mengembalikan nilai true, maka <code>myActivity.isInMultiWindowMode()</code> juga
    ++      mengembalikan nilai true.
    ++    </p>
    ++  </dd>
    ++
    ++  <dt>
    ++    <code>Activity.onMultiWindowModeChanged()</code>
    ++  </dt>
    ++
    ++  <dd>
    ++    Sistem akan memanggil metode ini bila aktivitas masuk atau keluar dari
    ++    mode multi-jendela. Sistem akan meneruskan ke metode sebuah nilai true jika
    ++   aktivitas tersebut memasuki mode multi-jendela, dan nilai false jika aktivitas
    ++     tersebut meninggalkan mode multi-jendela.
    ++  </dd>
    ++
    ++  <dt>
    ++    <code>Activity.onPictureInPictureModeChanged()</code>
    ++  </dt>
    ++
    ++  <dd>
    ++    Sistem akan memanggil metode ini bila aktivitas masuk atau keluar dari
    ++    mode gambar-dalam-gambar. Sistem akan meneruskan ke metode sebuah nilai true jika
    ++   aktivitas tersebut memasuki mode gambar-dalam-gambar, dan nilai false jika aktivitas
    ++     tersebut meninggalkan mode gambar-dalam-gambar.
    ++  </dd>
    ++</dl>
    ++
    ++<p>
    ++  Ada juga versi {@link android.app.Fragment} untuk setiap
    ++  metode ini, misalnya <code>Fragment.isInMultiWindowMode()</code>.
    ++</p>
    ++
    ++<h3 id="entering-pip">Memasuki mode gambar-dalam-gambar</h3>
    ++
    ++<p>
    ++  Untuk menempatkan aktivitas dalam mode gambar-dalam-gambar, panggil metode baru
    ++  <code>Activity.enterPictureInPictureMode()</code>. Metode ini tidak berpengaruh jika
    ++   perangkat tidak mendukung mode gambar-dalam-gambar. Untuk informasi selengkapnya,
    ++   lihat dokumentasi <a href="picture-in-picture.html">Gambar-dalam-Gambar</a>.
    ++</p>
    ++
    ++<h3 id="launch">Meluncurkan Aktivitas Baru dalam Mode Multi-Jendela</h3>
    ++
    ++<p>
    ++  Bila meluncurkan aktivitas baru, Anda bisa memberi petunjuk pada sistem bahwa aktivitas
    ++  baru harus ditampilkan bersebelahan dengan aktivitas yang sedang aktif, jika memungkinkan. Caranya,
    ++  gunakan flag
    ++  <code>Intent.FLAG_ACTIVITY_LAUNCH_TO_ADJACENT</code>. Meneruskan
    ++  flag ini akan meminta perilaku berikut:
    ++</p>
    ++
    ++<ul>
    ++  <li>Jika perangkat berada dalam mode layar terbagi, sistem akan berupaya membuat
    ++  aktivitas baru di sebelah aktivitas yang meluncurkannya, sehingga kedua aktivitas tersebut
    ++  berbagi layar. Tidak ada jaminan sistem mampu melakukannya, namun sistem akan
    ++  membuat aktivitas bersebelahan jika memungkinkan.
    ++  </li>
    ++
    ++  <li>Jika perangkat tidak berada dalam mode layar terbagi, flag ini tidak akan berpengaruh.
    ++  </li>
    ++</ul>
    ++
    ++<p>
    ++  Jika perangkat dalam mode bentuk bebas dan Anda menjalankan aktivitas baru, Anda bisa
    ++  menetapkan dimensi aktivitas baru dan lokasi layar dengan memanggil
    ++  <code>ActivityOptions.setLaunchBounds()</code>. Metode ini tidak berpengaruh jika
    ++  perangkat tidak berada dalam mode multi-jendela.
    ++</p>
    ++
    ++<p class="note">
    ++  <strong>Catatan:</strong> Jika Anda meluncurkan aktivitas dalam tumpukan tugas, aktivitas
    ++  tersebut akan menggantikan aktivitas pada layar, dengan mewarisi semua
    ++   properti multi-jendelanya. Jika Anda ingin meluncurkan aktivitas baru sebagai jendela
    ++  terpisah dalam mode multi-jendela, Anda harus meluncurkannya dalam tumpukan tugas baru.
    ++</p>
    ++
    ++<h3 id="dnd">Mendukung seret dan lepas</h3>
    ++
    ++<p>
    ++  Pengguna bisa <a href="{@docRoot}guide/topics/ui/drag-drop.html">menyeret dan
    ++  melepas</a> data dari satu aktivitas ke aktivitas yang lain selagi kedua aktivitas
    ++  berbagi layar. (Sebelumnya, pengguna hanya bisa menyeret dan melepas data dalam
    ++   aktivitas tunggal.) Karena alasan ini, Anda mungkin perlu menambahkan fungsionalitas
    ++  seret dan lepas ke aplikasi jika aplikasi saat ini belum mendukungnya.
    ++</p>
    ++
    ++<p>
    ++  N Preview SDK menambahkan paket <a href="{@docRoot}reference/android/view/package-summary.html"><code>android.view</code></a>
    ++  untuk mendukung seret dan lepas lintas-aplikasi. Untuk mengetahui detail tentang kelas dan metode
    ++  berikut, lihat <a href="{@docRoot}preview/setup-sdk.html#docs-dl">Referensi N
    ++  Preview SDK</a>.
    ++</p>
    ++
    ++<dl>
    ++  <dt>
    ++    <code>android.view.DropPermissions</code>
    ++  </dt>
    ++
    ++  <dd>
    ++    Objek token bertanggung jawab menetapkan izin yang diberikan kepada aplikasi
    ++    yang menerima pelepasan tersebut.
    ++  </dd>
    ++
    ++  <dt>
    ++    <code>View.startDragAndDrop()</code>
    ++  </dt>
    ++
    ++  <dd>
    ++    Alias baru untuk {@link android.view.View#startDrag View.startDrag()}. Untuk
    ++    mengaktifkan seret dan lepas lintas-aktivitas, teruskan flag baru
    ++    <code>View.DRAG_FLAG_GLOBAL</code>. Jika Anda perlu memberikan izin URI ke
    ++    aktivitas penerima, teruskan flag baru,
    ++    <code>View.DRAG_FLAG_GLOBAL_URI_READ</code> atau
    ++    <code>View.DRAG_FLAG_GLOBAL_URI_WRITE</code>, sebagaimana mestinya.
    ++  </dd>
    ++
    ++  <dt>
    ++    <code>View.cancelDragAndDrop()</code>
    ++  </dt>
    ++
    ++  <dd>
    ++    Membatalkan operasi seret yang sedang berlangsung. Hanya bisa dipanggil oleh
    ++    aplikasi yang menghasilkan operasi seret.
    ++  </dd>
    ++
    ++  <dt>
    ++    <code>View.updateDragShadow()</code>
    ++  </dt>
    ++
    ++  <dd>
    ++    Menggantikan bayangan penyeretan untuk operasi seret yang sedang berlangsung. Hanya
    ++    bisa dipanggil oleh aplikasi yang menghasilkan operasi seret.
    ++  </dd>
    ++
    ++  <dt>
    ++    <code>Activity.requestDropPermissions()</code>
    ++  </dt>
    ++
    ++  <dd>
    ++    Meminta izin untuk URI materi yang diteruskan dengan {@link
    ++    android.content.ClipData} yang terdapat dalam {@link android.view.DragEvent}.
    ++  </dd>
    ++</dl>
    ++
    ++<h2 id="testing">Menguji Dukungan Multi-Jendela Aplikasi Anda</h2>
    ++
    ++<p>
    ++  Apakah Anda memperbarui aplikasi untuk Android N atau tidak, Anda harus
    ++  verifikasi bagaimana perilakunya di mode multi-jendela saat pengguna mencoba untuk menjalankannya
    ++  dalam mode multi-jendela pada perangkat yang menjalankan Android N.
    ++</p>
    ++
    ++<h3 id="configuring">Mengonfigurasi Perangkat Pengujian</h3>
    ++
    ++<p>
    ++  Jika Anda pasang Android N pada perangkat, mode
    ++  layar terbagi secara otomatis didukung.
    ++</p>
    ++
    ++<h3 id="test-non-n">Jika aplikasi Anda tidak dibangun dengan N Preview SDK</h3>
    ++
    ++<p>
    ++  Jika Anda tidak membangun aplikasi dengan N Preview SDK dan pengguna berupaya menggunakan
    ++  aplikasi dalam mode multi-jendela, sistem secara paksa akan mengubah ukuran aplikasi kecuali jika aplikasi
    ++  mendeklarasikan orientasi tetap.
    ++</p>
    ++
    ++<p>
    ++  Jika aplikasi Anda tidak mendeklarasikan orientasi tetap, Anda harus meluncurkan aplikasi
    ++  pada perangkat yang menjalankan Android N dan berupaya menempatkan aplikasi tersebut dalam
    ++  mode layar terbagi. Verifikasi pengalaman pengguna
    ++  bisa diterima bila aplikasi secara paksa diubah ukurannya.
    ++</p>
    ++
    ++<p>
    ++  Jika aplikasi mendeklarasikan orientasi tetap, Anda harus berupaya menempatkan aplikasi dalam
    ++  mode multi-jendela. Verifikasi apakah saat Anda melakukannya, aplikasi tetap berada dalam
    ++  mode layar penuh.
    ++</p>
    ++
    ++<h3 id="test-mw">Jika Anda mendukung mode multi-jendela</h3>
    ++
    ++<p>
    ++  Jika Anda membuat aplikasi Anda dengan N Preview SDK dan belum menonaktifkan
    ++  dukungan multi-jendela, verifikasi perilaku berikut dalam mode layar terbagi
    ++   dan mode bentuk bebas.
    ++</p>
    ++
    ++<ul>
    ++  <li>Luncurkan aplikasi dalam mode layar penuh, kemudian beralih ke mode multi-jendela dengan
    ++   menekan lama pada tombol Ringkasan. Verifikasi apakah aplikasi beralih dengan benar.
    ++  </li>
    ++
    ++  <li>Jalankan aplikasi secara langsung dalam mode multi-jendela, dan verifikasi aplikasi
    ++  diluncurkan dengan benar. Anda bisa meluncurkan aplikasi dalam mode multi-jendela dengan menekan
    ++  tombol Ringkasan, kemudian menekan lama baris judul pada aplikasi Anda dan menyeretnya
    ++  ke salah satu area yang disorot di layar.
    ++  </li>
    ++
    ++  <li>Ubah ukuran aplikasi Anda dalam mode layar terbagi dengan menyeret garis pembagi.
    ++  Verifikasi apakah aplikasi mengubah ukuran tanpa mogok, dan apakah elemen UI yang diperlukan
    ++  terlihat.
    ++  </li>
    ++
    ++  <li>Jika Anda telah menetapkan dimensi minimum aplikasi, cobalah untuk mengubah ukuran
    ++  aplikasi di bawah dimensi tersebut. Verifikasi apakah Anda tidak bisa mengubah ukuran aplikasi menjadi
    ++  lebih kecil dari minimum yang ditetapkan.
    ++  </li>
    ++
    ++  <li>Melalui semua pengujian, verifikasi apakah kinerja aplikasi Anda bisa diterima. Misalnya,
    ++  verifikasi apakah tidak ada jeda yang terlalu lama untuk memperbarui UI setelah
    ++  aplikasi diubah ukurannya.
    ++  </li>
    ++</ul>
    ++
    ++<h4 id="test-checklist">Daftar periksa pengujian</h4>
    ++
    ++<p>
    ++  Untuk verifikasi kinerja aplikasi Anda dalam mode multi-jendela, cobalah operasi
    ++  berikut. Anda harus mencoba semua operasi ini dalam mode layar terbagi dan
    ++   dan mode multi-jendela, kecuali jika dinyatakan berbeda.
    ++</p>
    ++
    ++<ul>
    ++  <li>Masuki dan tinggalkan mode multi-jendela.
    ++  </li>
    ++
    ++  <li>Beralih dari aplikasi Anda ke aplikasi lain, dan verifikasi apakah aplikasi berperilaku
    ++   sebagaimana mestinya saat terlihat namun tidak aktif. Misalnya, jika aplikasi Anda
    ++   sedang memutar video, verifikasi apakah video terus diputar selagi pengguna
    ++  berinteraksi dengan aplikasi lain.
    ++  </li>
    ++
    ++  <li>Dalam mode layar terbagi, cobalah menggeser garis pembagi untuk membuat aplikasi
    ++  Anda menjadi lebih besar dan lebih kecil. Coba operasi ini dalam konfigurasi berdampingan dan
    ++  atas-bawah. Verifikasi apakah aplikasi tidak mogok,
    ++  fungsionalitas penting bisa terlihat, dan operasi mengubah ukuran tidak memakan waktu terlalu
    ++  lama.
    ++  </li>
    ++
    ++  <li>Lakukan beberapa operasi ubah ukuran berturut-turut dalam waktu cepat. Verifikasi apakah
    ++  aplikasi Anda tidak mogok atau mengalami kebocoran memori. Untuk informasi tentang memeriksa penggunaan memori
    ++  aplikasi Anda, lihat <a href="{@docRoot}tools/debugging/debugging-memory.html">
    ++  Menyelidiki Penggunaan RAM Anda</a>.
    ++  </li>
    ++
    ++  <li>Gunakan aplikasi secara normal di sejumlah konfigurasi jendela yang berbeda, dan
    ++  verifikasi apakah aplikasi berperilaku sebagaimana mestinya. Verifikasi apakah teks terbaca, dan apakah
    ++  elemen UI tidak terlalu kecil untuk interaksi.
    ++  </li>
    ++</ul>
    ++
    ++<h3 id="test-disabled-mw">Jika Anda telah menonaktifkan dukungan multi-jendela</h3>
    ++
    ++<p>
    ++  Jika Anda menonaktifkan dukungan multi-jendela dengan menyetel
    ++  <code>android:resizableActivity="false"</code>, Anda harus menjalankan aplikasi pada
    ++  perangkat yang menjalankan Android N dan berusaha menempatkan aplikasi dalam
    ++  mode bentuk bebas dan mode layar terbagi. Verifikasi apakah saat Anda melakukannya, aplikasi tetap berada dalam
    ++  mode layar penuh.
    ++</p>
    +diff --git a/docs/html-intl/intl/id/guide/topics/ui/notifiers/notifications.jd b/docs/html-intl/intl/id/guide/topics/ui/notifiers/notifications.jd
    +new file mode 100644
    +index 0000000..bb48b80
    +--- /dev/null
    ++++ b/docs/html-intl/intl/id/guide/topics/ui/notifiers/notifications.jd
    +@@ -0,0 +1,979 @@
    ++page.title=Pemberitahuan
    ++@jd:body
    ++
    ++<div id="qv-wrapper">
    ++<div id="qv">
    ++<h2>Dalam dokumen ini</h2>
    ++<ol>
    ++  <li><a href="#Design">Pertimbangan Desain</a></li>
    ++  <li><a href="#CreateNotification">Membuat Pemberitahuan</a>
    ++    <ol>
    ++      <li><a href="#Required">Isi pemberitahuan yang diperlukan</a></li>
    ++      <li><a href="#Optional">Isi dan pengaturan pemberitahuan opsional</a></li>
    ++      <li><a href="#Actions">Tindakan pemberitahuan</a></li>
    ++      <li><a href="#Priority">Prioritas pemberitahuan</a></li>
    ++      <li><a href="#SimpleNotification">Membuat pemberitahuan sederhana</a></li>
    ++      <li><a href="#ApplyStyle">Menerapkan layout yang diperluas pada pemberitahuan</a></li>
    ++      <li><a href="#Compatibility">Menangani kompatibilitas</a></li>
    ++    </ol>
    ++  </li>
    ++  <li><a href="#Managing">Mengelola Pemberitahuan</a>
    ++    <ol>
    ++      <li><a href="#Updating">Memperbarui pemberitahuan</a></li>
    ++      <li><a href="#Removing">Menghapus pemberitahuan</a></li>
    ++    </ol>
    ++  </li>
    ++  <li><a href="#NotificationResponse">Mempertahankan Navigasi saat Memulai Aktivitas</a>
    ++    <ol>
    ++      <li><a href="#DirectEntry">Menyiapkan PendingIntent aktivitas biasa</a></li>
    ++      <li><a href="#ExtendedNotification">Menyiapkan PendingIntent aktivitas khusus</a></li>
    ++    </ol>
    ++  </li>
    ++  <li><a href="#Progress">Menampilkan Kemajuan dalam Pemberitahuan</a>
    ++    <ol>
    ++      <li><a href="#FixedProgress">Menampilkan indikator kemajuan berdurasi tetap</a></li>
    ++      <li><a href="#ActivityIndicator">Menampilkan indikator aktivitas berlanjut</a></li>
    ++    </ol>
    ++  </li>
    ++  <li><a href="#metadata">Metadata Pemberitahuan</a></li>
    ++  <li><a href="#Heads-up">Pemberitahuan Pendahuluan</a></li>
    ++  <li><a href="#lockscreenNotification">Pemberitahuan Layar Kunci</a></li>
    ++    <ol>
    ++      <li><a href="#visibility">Mengatur Visibilitas</a></li>
    ++      <li><a href="#controllingMedia">Mengontrol Pemutaran Media pada Layar Kunci</a></li>
    ++    </ol>
    ++  <li><a href="#CustomNotification">Layout Pemberitahuan Custom</a></li>
    ++</ol>
    ++
    ++    <h2>Kelas-kelas utama</h2>
    ++    <ol>
    ++        <li>{@link android.app.NotificationManager}</li>
    ++        <li>{@link android.support.v4.app.NotificationCompat}</li>
    ++    </ol>
    ++    <h2>Video</h2>
    ++    <ol>
    ++        <li>
    ++            <a href="http://www.youtube.com/watch?v=Yc8YrVc47TI&amp;feature=player_detailpage#t=1672s">
    ++            Pemberitahuan di 4.1</a>
    ++        </li>
    ++    </ol>
    ++<h2>Lihat juga</h2>
    ++<ol>
    ++    <li>
    ++        <a href="{@docRoot}design/patterns/notifications.html">Desain Android: Pemberitahuan</a>
    ++    </li>
    ++</ol>
    ++</div>
    ++</div>
    ++<p>
    ++    Pemberitahuan adalah pesan yang bisa Anda tampilkan kepada pengguna di luar
    ++    UI normal aplikasi. Bila Anda memberi tahu sistem untuk mengeluarkan pemberitahuan, pemberitahuan akan muncul lebih dahulu sebagai ikon dalam
    ++    <strong>area pemberitahuan</strong>. Untuk melihat detail pemberitahuan, pengguna membuka
    ++    <strong>laci pemberitahuan</strong>. Baik area pemberitahuan maupun laci pemberitahuan
    ++    adalah area-area yang dikontrol sistem yang bisa dilihat pengguna kapan saja.
    ++</p>
    ++<img id="figure1" src="{@docRoot}images/ui/notifications/notification_area.png" height="" alt="" />
    ++<p class="img-caption">
    ++    <strong>Gambar 1.</strong> Pemberitahuan di area pemberitahuan.
    ++</p>
    ++<img id="figure2" src="{@docRoot}images/ui/notifications/notification_drawer.png" width="280px" alt="" />
    ++<p class="img-caption">
    ++    <strong>Gambar 2.</strong> Pemberitahuan di laci pemberitahuan.
    ++</p>
    ++
    ++<p class="note"><strong>Catatan:</strong> Kecuali disebutkan, panduan ini mengacu pada
    ++kelas {@link android.support.v4.app.NotificationCompat.Builder NotificationCompat.Builder}
    ++dalam <a href="{@docRoot}tools/support-library/index.html">Support Library</a> versi 4.
    ++Kelas {@link android.app.Notification.Builder Notification.Builder} telah ditambahkan pada Android
    ++3.0 (API level 11).</p>
    ++
    ++<h2 id="Design">Pertimbangan Desain</h2>
    ++
    ++<p>Pemberitahuan, sebagai bagian penting dari antarmuka pengguna Android, memiliki panduan desainnya sendiri.
    ++Perubahan desain materi yang diperkenalkan dalam Android 5.0 (API level 21) adalah sangat
    ++penting, dan Anda harus meninjau pelatihan <a href="{@docRoot}training/material/index.html">Desain Bahan</a>
    ++untuk informasi selengkapnya. Untuk mengetahui cara mendesain pemberitahuan dan interaksinya, bacalah panduan desain
    ++<a href="{@docRoot}design/patterns/notifications.html">Pemberitahuan</a>.</p>
    ++
    ++<h2 id="CreateNotification">Membuat Pemberitahuan</h2>
    ++
    ++<p>Anda menetapkan informasi dan tindakan UI bagi pemberitahuan dalam
    ++objek {@link android.support.v4.app.NotificationCompat.Builder NotificationCompat.Builder}.
    ++Untuk membuat pemberitahuan itu sendiri, panggil
    ++{@link android.support.v4.app.NotificationCompat.Builder#build NotificationCompat.Builder.build()},
    ++yang akan mengembalikan objek {@link android.app.Notification} berisi spesifikasi Anda. Untuk mengeluarkan
    ++pemberitahuan, Anda meneruskan objek {@link android.app.Notification} ke sistem dengan memanggil
    ++{@link android.app.NotificationManager#notify NotificationManager.notify()}.</p>
    ++
    ++<h3 id="Required">Isi pemberitahuan yang diperlukan</h3>
    ++<p>
    ++    Objek {@link android.app.Notification} <em>harus</em> berisi yang berikut ini:
    ++</p>
    ++<ul>
    ++    <li>
    ++        Ikon kecil, yang diatur dengan
    ++        {@link android.support.v4.app.NotificationCompat.Builder#setSmallIcon setSmallIcon()}
    ++    </li>
    ++    <li>
    ++        Judul, yang diatur dengan
    ++        {@link android.support.v4.app.NotificationCompat.Builder#setContentTitle setContentTitle()}
    ++    </li>
    ++    <li>
    ++        Teks detail, yang diatur dengan
    ++        {@link android.support.v4.app.NotificationCompat.Builder#setContentText setContentText()}
    ++    </li>
    ++</ul>
    ++<h3 id="Optional">Isi dan pengaturan pemberitahuan opsional</h3>
    ++<p>
    ++    Semua isi dan pengaturan pemberitahuan lainnya bersifat opsional. Untuk mengetahui selengkapnya tentang semua itu,
    ++    lihat dokumentasi acuan untuk {@link android.support.v4.app.NotificationCompat.Builder}.
    ++</p>
    ++<!-- ------------------------------------------------------------------------------------------ -->
    ++<h3 id="Actions">Tindakan pemberitahuan</h3>
    ++<p>
    ++    Walaupun bersifat opsional, Anda harus menambahkan setidaknya satu tindakan pada pemberitahuan.
    ++    Tindakan memungkinkan pengguna beralih langsung dari pemberitahuan ke
    ++    {@link android.app.Activity} dalam aplikasi Anda, tempat pengguna bisa melihat satu atau beberapa kejadian
    ++    atau melakukan pekerjaan lebih jauh.
    ++</p>
    ++<p>
    ++    Pemberitahuan bisa menyediakan beberapa tindakan sekaligus. Anda harus selalu mendefinisikan tindakan yang
    ++    akan diaktifkan bila pengguna mengklik pemberitahuan; biasanya tindakan ini akan membuka
    ++    {@link android.app.Activity} dalam aplikasi Anda. Anda juga bisa menambahkan tombol pada pemberitahuan
    ++    yang melakukan tindakan tambahan seperti mendiamkan alarm atau segera merespons
    ++    pesan teks; fitur ini tersedia mulai Android 4.1. Jika menggunakan tombol tindakan tambahan, Anda
    ++    juga harus membuat fungsionalitasnya tersedia dalam {@link android.app.Activity} di aplikasi Anda; lihat
    ++    bagian <a href="#Compatibility">Menangani kompatibilitas</a> untuk detail selengkapnya.
    ++</p>
    ++<p>
    ++    Dalam {@link android.app.Notification}, tindakan itu sendiri didefinisikan oleh
    ++    {@link android.app.PendingIntent} berisi
    ++    {@link android.content.Intent} yang memulai
    ++    {@link android.app.Activity} dalam aplikasi Anda. Untuk mengaitkan
    ++    {@link android.app.PendingIntent} dengan gestur, panggil metode
    ++    {@link android.support.v4.app.NotificationCompat.Builder} yang sesuai. Misalnya, jika ingin memulai
    ++    {@link android.app.Activity} bila pengguna mengklik teks pemberitahuan pada
    ++    laci pemberitahuan, tambahkan {@link android.app.PendingIntent} dengan memanggil
    ++    {@link android.support.v4.app.NotificationCompat.Builder#setContentIntent setContentIntent()}.
    ++</p>
    ++<p>
    ++    Memulai {@link android.app.Activity} bila pengguna mengklik pemberitahuan adalah
    ++    skenario tindakan yang paling umum. Anda juga bisa memulai {@link android.app.Activity} bila pengguna
    ++    menghilangkan pemberitahuan. Dalam Android 4.1 dan yang lebih baru, Anda bisa memulai
    ++    {@link android.app.Activity} dari tombol tindakan. Untuk mengetahui selengkapnya, bacalah panduan acuan untuk
    ++    {@link android.support.v4.app.NotificationCompat.Builder}.
    ++</p>
    ++<!-- ------------------------------------------------------------------------------------------ -->
    ++<h3 id="Priority">Prioritas pemberitahuan</h3>
    ++<p>
    ++    Jika diinginkan, Anda bisa mengatur prioritas pemberitahuan. Prioritas berfungsi
    ++    sebagai petunjuk bagi UI perangkat tentang cara menampilkan pemberitahuan.
    ++    Untuk mengatur prioritas pemberitahuan, panggil {@link
    ++    android.support.v4.app.NotificationCompat.Builder#setPriority(int)
    ++    NotificationCompat.Builder.setPriority()} dan teruskan salah satu konstanta prioritas {@link
    ++    android.support.v4.app.NotificationCompat}. Ada
    ++    lima level prioritas, mulai dari {@link
    ++    android.support.v4.app.NotificationCompat#PRIORITY_MIN} (-2) hingga {@link
    ++    android.support.v4.app.NotificationCompat#PRIORITY_MAX} (2); jika tidak diatur,
    ++    prioritas default akan ditetapkan {@link
    ++    android.support.v4.app.NotificationCompat#PRIORITY_DEFAULT} (0).
    ++</p>
    ++<p> Untuk informasi tentang mengatur level prioritas, lihat "Mengatur
    ++    dan mengelola prioritas pemberitahuan dengan benar" dalam panduan
    ++Desain <a href="{@docRoot}design/patterns/notifications.html">Pemberitahuan</a>.
    ++</p>
    ++<!-- ------------------------------------------------------------------------------------------ -->
    ++<h3 id="SimpleNotification">Membuat pemberitahuan sederhana</h3>
    ++<p>
    ++    Cuplikan berikut mengilustrasikan pemberitahuan sederhana yang menetapkan aktivitas untuk dibuka bila
    ++    pengguna mengklik pemberitahuan. Perhatikan bahwa kode ini membuat
    ++    objek {@link android.support.v4.app.TaskStackBuilder} dan menggunakannya untuk membuat
    ++    {@link android.app.PendingIntent} untuk tindakan. Pola ini dijelaskan secara lebih detail
    ++    di bagian <a href="#NotificationResponse">
    ++    Mempertahankan Navigasi saat Memulai Aktivitas</a>:
    ++</p>
    ++<pre>
    ++NotificationCompat.Builder mBuilder =
    ++        new NotificationCompat.Builder(this)
    ++        .setSmallIcon(R.drawable.notification_icon)
    ++        .setContentTitle("My notification")
    ++        .setContentText("Hello World!");
    ++// Creates an explicit intent for an Activity in your app
    ++Intent resultIntent = new Intent(this, ResultActivity.class);
    ++
    ++// The stack builder object will contain an artificial back stack for the
    ++// started Activity.
    ++// This ensures that navigating backward from the Activity leads out of
    ++// your application to the Home screen.
    ++TaskStackBuilder stackBuilder = TaskStackBuilder.create(this);
    ++// Adds the back stack for the Intent (but not the Intent itself)
    ++stackBuilder.addParentStack(ResultActivity.class);
    ++// Adds the Intent that starts the Activity to the top of the stack
    ++stackBuilder.addNextIntent(resultIntent);
    ++PendingIntent resultPendingIntent =
    ++        stackBuilder.getPendingIntent(
    ++            0,
    ++            PendingIntent.FLAG_UPDATE_CURRENT
    ++        );
    ++mBuilder.setContentIntent(resultPendingIntent);
    ++NotificationManager mNotificationManager =
    ++    (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
    ++// mId allows you to update the notification later on.
    ++mNotificationManager.notify(mId, mBuilder.build());
    ++</pre>
    ++<p>Demikian saja. Pengguna Anda kini telah diberi tahu.</p>
    ++<!-- ------------------------------------------------------------------------------------------ -->
    ++<h3 id="ApplyStyle">Menerapkan layout yang diperluas pada pemberitahuan</h3>
    ++<p>
    ++    Agar pemberitahuan muncul dalam tampilan yang diperluas, buat dahulu
    ++    objek {@link android.support.v4.app.NotificationCompat.Builder} dengan opsi tampilan normal
    ++    yang Anda inginkan. Berikutnya, panggil {@link android.support.v4.app.NotificationCompat.Builder#setStyle
    ++    Builder.setStyle()}  dengan objek layout yang diperluas sebagai argumennya.
    ++</p>
    ++<p>
    ++    Ingatlah bahwa pemberitahuan yang diperluas tidak tersedia pada platform-platform sebelum Android 4.1. Untuk
    ++    mengetahui cara menangani pemberitahuan untuk Android 4.1 dan untuk platform-platform sebelumnya, bacalah
    ++    bagian <a href="#Compatibility">Menangani kompatibilitas</a>.
    ++</p>
    ++<p>
    ++    Misalnya, cuplikan kode berikut memperagakan cara mengubah pemberitahuan yang dibuat
    ++    dalam cuplikan sebelumnya untuk menggunakan layout yang diperluas:
    ++</p>
    ++<pre>
    ++NotificationCompat.Builder mBuilder = new NotificationCompat.Builder(this)
    ++    .setSmallIcon(R.drawable.notification_icon)
    ++    .setContentTitle("Event tracker")
    ++    .setContentText("Events received")
    ++NotificationCompat.InboxStyle inboxStyle =
    ++        new NotificationCompat.InboxStyle();
    ++String[] events = new String[6];
    ++// Sets a title for the Inbox in expanded layout
    ++inboxStyle.setBigContentTitle("Event tracker details:");
    ++...
    ++// Moves events into the expanded layout
    ++for (int i=0; i &lt; events.length; i++) {
    ++
    ++    inboxStyle.addLine(events[i]);
    ++}
    ++// Moves the expanded layout object into the notification object.
    ++mBuilder.setStyle(inBoxStyle);
    ++...
    ++// Issue the notification here.
    ++</pre>
    ++
    ++<h3 id="Compatibility">Menangani kompatibilitas</h3>
    ++
    ++<p>
    ++    Tidak semua fitur pemberitahuan tersedia untuk versi tertentu, walaupun
    ++    metode untuk mengaturnya ada dalam kelas pustaka dukungan
    ++    {@link android.support.v4.app.NotificationCompat.Builder NotificationCompat.Builder}.
    ++    Misalnya, tombol tindakan, yang bergantung pada pemberitahuan yang diperluas, hanya muncul pada Android
    ++    4.1 dan lebih tinggi, karena pemberitahuan yang diperluas itu sendiri hanya tersedia pada
    ++    Android 4.1 dan yang lebih tinggi.
    ++</p>
    ++<p>
    ++    Untuk memastikan kompatibilitas terbaik, buatlah pemberitahuan dengan
    ++    {@link android.support.v4.app.NotificationCompat NotificationCompat} dan subkelasnya,
    ++    khususnya {@link android.support.v4.app.NotificationCompat.Builder
    ++    NotificationCompat.Builder}. Selain itu, ikutilah proses ini bila Anda mengimplementasikan pemberitahuan:
    ++</p>
    ++<ol>
    ++    <li>
    ++        Sediakan semua fungsionalitas pemberitahuan kepada semua pengguna, terlepas dari versi
    ++        yang mereka gunakan. Caranya, pastikan semua fungsionalitas tersedia dari
    ++        {@link android.app.Activity} dalam aplikasi Anda. Anda mungkin perlu menambahkan sebuah
    ++        {@link android.app.Activity} baru untuk melakukannya.
    ++        <p>
    ++            Misalnya, jika Anda ingin menggunakan
    ++            {@link android.support.v4.app.NotificationCompat.Builder#addAction addAction()} untuk
    ++            menyediakan kontrol yang menghentikan dan memulai pemutaran media, implementasikan dahulu
    ++            kontrol ini pada {@link android.app.Activity} dalam aplikasi Anda.
    ++        </p>
    ++    </li>
    ++    <li>
    ++        Pastikan semua pengguna bisa memperoleh fungsionalitas dalam {@link android.app.Activity},
    ++        dengan memulainya bila pengguna mengklik pemberitahuan. Caranya,
    ++        buatlah {@link android.app.PendingIntent}
    ++        untuk {@link android.app.Activity}. Panggil
    ++        {@link android.support.v4.app.NotificationCompat.Builder#setContentIntent
    ++        setContentIntent()} untuk menambahkan {@link android.app.PendingIntent} pada pemberitahuan.
    ++    </li>
    ++    <li>
    ++        Kini tambahkan fitur pemberitahuan diperluas yang ingin Anda gunakan pada pemberitahuan. Ingatlah
    ++        bahwa setiap fungsionalitas yang Anda tambahkan juga harus tersedia dalam {@link android.app.Activity}
    ++        yang akan dimulai bila pengguna mengklik pemberitahuan.
    ++    </li>
    ++</ol>
    ++
    ++
    ++<!-- ------------------------------------------------------------------------------------------ -->
    ++<!-- ------------------------------------------------------------------------------------------ -->
    ++<h2 id="Managing">Mengelola Pemberitahuan</h2>
    ++<p>
    ++    Bila perlu mengeluarkan pemberitahuan beberapa kali untuk tipe kejadian yang sama,
    ++hindari membuat pemberitahuan yang sama sekali baru. Sebagai gantinya, Anda harus mempertimbangkan untuk memperbarui
    ++    pemberitahuan sebelumnya, baik dengan mengubah sebagian nilainya atau dengan menambahkan nilai, atau keduanya.
    ++</p>
    ++<p>
    ++    Misalnya, Gmail akan memberi tahu pengguna bila ada email baru dengan menambah hitungan
    ++    pesan tidak terbaca dan dengan menambahkan rangkuman tiap email ke pemberitahuan. Ini disebut dengan
    ++    "stacking" (menumpuk) pemberitahuan; hal ini dijelaskan lebih detail dalam panduan
    ++    Desain <a href="{@docRoot}design/patterns/notifications.html">Pemberitahuan</a>.
    ++</p>
    ++<p class="note">
    ++    <strong>Catatan:</strong> Fitur Gmail ini mensyaratkan layout "kotak masuk" diperluas, yang merupakan
    ++    bagian dari fitur pemberitahuan diperluas yang tersedia mulai Android 4.1.
    ++</p>
    ++<p>
    ++    Bagian berikut menjelaskan cara memperbarui pemberitahuan dan cara menghapusnya.
    ++</p>
    ++<h3 id="Updating">Memperbarui pemberitahuan</h3>
    ++<p>
    ++    Untuk menyiapkan pemberitahuan agar bisa diperbarui, keluarkan pemberitahuan bersama ID pemberitahuan dengan
    ++    memanggil {@link android.app.NotificationManager#notify(int, android.app.Notification) NotificationManager.notify()}.
    ++    Untuk memperbarui pemberitahuan ini setelah Anda
    ++    mengeluarkan, memperbarui, atau membuat objek {@link android.support.v4.app.NotificationCompat.Builder},
    ++    buat objek {@link android.app.Notification} darinya, dan keluarkan
    ++    {@link android.app.Notification} bersama ID yang sama dengan yang Anda gunakan sebelumnya. Jika
    ++    pemberitahuan sebelumnya tetap terlihat, sistem akan memperbaruinya dari konten
    ++    objek {@link android.app.Notification}. Jika pemberitahuan sebelumnya telah dihilangkan, sebuah
    ++    pemberitahuan baru akan dibuat.
    ++</p>
    ++<p>
    ++    Cuplikan berikut memperagakan pemberitahuan yang diperbarui untuk mencerminkan
    ++    jumlah kejadian yang telah terjadi. Cuplikan ini menumpuk pemberitahuan, yang menampilkan rangkuman:
    ++</p>
    ++<pre>
    ++mNotificationManager =
    ++        (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
    ++// Sets an ID for the notification, so it can be updated
    ++int notifyID = 1;
    ++mNotifyBuilder = new NotificationCompat.Builder(this)
    ++    .setContentTitle("New Message")
    ++    .setContentText("You've received new messages.")
    ++    .setSmallIcon(R.drawable.ic_notify_status)
    ++numMessages = 0;
    ++// Start of a loop that processes data and then notifies the user
    ++...
    ++    mNotifyBuilder.setContentText(currentText)
    ++        .setNumber(++numMessages);
    ++    // Because the ID remains unchanged, the existing notification is
    ++    // updated.
    ++    mNotificationManager.notify(
    ++            notifyID,
    ++            mNotifyBuilder.build());
    ++...
    ++</pre>
    ++
    ++<!-- ------------------------------------------------------------------------------------------ -->
    ++<h3 id="Removing">Menghapus pemberitahuan</h3>
    ++<p>
    ++    Pemberitahuan tetap terlihat hingga salah satu kejadian berikut terjadi:
    ++</p>
    ++<ul>
    ++    <li>
    ++        Pengguna menghilangkan pemberitahuan satu per satu atau dengan menggunakan "Clear All" (jika
    ++        pemberitahuan bisa dihapus).
    ++    </li>
    ++    <li>
    ++        Pengguna mengklik pemberitahuan, dan Anda memanggil
    ++        {@link android.support.v4.app.NotificationCompat.Builder#setAutoCancel setAutoCancel()} bila
    ++        Anda telah membuat pemberitahuan.
    ++    </li>
    ++    <li>
    ++        Anda memanggil {@link android.app.NotificationManager#cancel(int) cancel()} untuk
    ++        ID pemberitahuan tertentu. Metode ini juga menghapus pemberitahuan yang berjalan.
    ++    </li>
    ++    <li>
    ++        Anda memanggil {@link android.app.NotificationManager#cancelAll() cancelAll()}, yang menghapus
    ++        semua pemberitahuan yang dikeluarkan sebelumnya.
    ++    </li>
    ++</ul>
    ++<!-- ------------------------------------------------------------------------------------------ -->
    ++<!-- ------------------------------------------------------------------------------------------ -->
    ++<h2 id="NotificationResponse">Mempertahankan Navigasi saat Memulai Aktivitas</h2>
    ++<p>
    ++    Bila memulai {@link android.app.Activity} dari pemberitahuan, Anda harus mempertahankan
    ++    pengalaman navigasi yang diharapkan pengguna. Mengklik <i>Back</i> harus membawa pengguna kembali melalui
    ++    aliran pekerjaan normal aplikasi ke layar Home, dan mengklik <i>Recents</i> harus menampilkan
    ++    {@link android.app.Activity} sebagai tugas terpisah. Untuk mempertahankan pengalaman navigasi, Anda
    ++    harus memulai {@link android.app.Activity} dalam tugas baru. Cara menyiapkan
    ++    {@link android.app.PendingIntent} untuk memberi Anda tugas baru bergantung pada sifat
    ++    {@link android.app.Activity} yang Anda mulai. Ada dua situasi umum:
    ++</p>
    ++<dl>
    ++    <dt>
    ++        Aktivitas rutin
    ++    </dt>
    ++    <dd>
    ++        Anda memulai {@link android.app.Activity} yang merupakan bagian dari aliran pekerjaan normal
    ++        aplikasi. Dalam situasi ini, siapkan {@link android.app.PendingIntent} untuk
    ++        memulai tugas baru, dan sediakan {@link android.app.PendingIntent} bersama back-stack
    ++        yang meniru perilaku <i>Back</i> biasa.
    ++        <p>
    ++            Pemberitahuan dari aplikasi Gmail memperagakan hal ini. Bila Anda mengklik pemberitahuan untuk
    ++            satu pesan email, Anda akan melihat pesan itu sendiri. Menyentuh <b>Back</b> akan membawa Anda
    ++            kembali melalui Gmail ke layar Home, persis seperti jika memasuki Gmail dari
    ++            layar Home bukannya memasukinya dari pemberitahuan.
    ++        </p>
    ++        <p>
    ++            Hal ini terjadi terlepas dari aplikasi tempat Anda berada saat menyentuh
    ++            pemberitahuan. Misalnya, jika Anda dalam Gmail sedang menulis pesan, dan Anda mengklik
    ++            pemberitahuan untuk satu email, Anda akan segera dibawa ke email itu. Menyentuh <i>Back</i>
    ++            akan membawa Anda ke kotak masuk kemudian layar Home, bukannya membawa Anda ke
    ++            pesan yang sedang ditulis.
    ++        </p>
    ++    </dd>
    ++    <dt>
    ++        Aktivitas khusus
    ++    </dt>
    ++    <dd>
    ++        Pengguna hanya melihat {@link android.app.Activity} ini jika dimulai dari pemberitahuan.
    ++        Dalam beberapa hal, {@link android.app.Activity} akan memperluas pemberitahuan dengan menyediakan
    ++        informasi yang akan sulit untuk ditampilkan dalam pemberitahuan itu sendiri. Untuk situasi ini,
    ++        siapkan {@link android.app.PendingIntent} untuk dimulai dalam tugas baru. Tidak perlu
    ++        membuat back-stack, karena {@link android.app.Activity} yang dimulai bukan bagian dari
    ++        aliran aktivitas aplikasi. Mengklik <i>Back</i> tetap akan membawa pengguna ke
    ++        layar Home.
    ++    </dd>
    ++</dl>
    ++<!-- ------------------------------------------------------------------------------------------ -->
    ++<h3 id="DirectEntry">Menyiapkan PendingIntent aktivitas biasa</h3>
    ++<p>
    ++    Untuk menyiapkan {@link android.app.PendingIntent} yang memulai entri langsung
    ++    {@link android.app.Activity}, ikuti langkah-langkah ini:
    ++</p>
    ++<ol>
    ++    <li>
    ++        Definisikan hierarki {@link android.app.Activity} aplikasi Anda dalam manifes.
    ++        <ol style="list-style-type: lower-alpha;">
    ++            <li>
    ++                Tambahkan dukungan untuk Android 4.0.3 dan yang terdahulu. Caranya, tetapkan induk
    ++                {@link android.app.Activity} yang Anda mulai dengan menambahkan elemen
    ++<code><a href="{@docRoot}guide/topics/manifest/meta-data-element.html">&lt;meta-data&gt;</a></code>
    ++                sebagai anak
    ++<code><a href="{@docRoot}guide/topics/manifest/activity-element.html">&lt;activity&gt;</a></code>.
    ++                <p>
    ++                    Untuk elemen ini, atur
    ++<code><a href="{@docRoot}guide/topics/manifest/meta-data-element.html#nm">android:name</a>="android.support.PARENT_ACTIVITY"</code>.
    ++                    Atur
    ++<code><a href="{@docRoot}guide/topics/manifest/meta-data-element.html#val">android:value</a>="&lt;parent_activity_name&gt;"</code>
    ++                    dengan <code>&lt;parent_activity_name&gt;</code> sebagai nilai
    ++<code><a href="{@docRoot}guide/topics/manifest/meta-data-element.html#nm">android:name</a></code>
    ++                    untuk elemen induk
    ++<code><a href="{@docRoot}guide/topics/manifest/activity-element.html">&lt;activity&gt;</a></code>
    ++. Lihat XML berikut sebagai contoh.
    ++                </p>
    ++            </li>
    ++            <li>
    ++                Juga tambahkan dukungan untuk Android 4.1 dan yang lebih baru. Caranya, tambahkan atribut
    ++<code><a href="{@docRoot}guide/topics/manifest/activity-element.html#parent">android:parentActivityName</a></code>
    ++                 pada elemen
    ++<code><a href="{@docRoot}guide/topics/manifest/activity-element.html">&lt;activity&gt;</a></code>
    ++                dari {@link android.app.Activity} yang Anda mulai.
    ++            </li>
    ++        </ol>
    ++        <p>
    ++            XML akhir akan terlihat seperti ini:
    ++        </p>
    ++<pre>
    ++&lt;activity
    ++    android:name=".MainActivity"
    ++    android:label="&#64;string/app_name" &gt;
    ++    &lt;intent-filter&gt;
    ++        &lt;action android:name="android.intent.action.MAIN" /&gt;
    ++        &lt;category android:name="android.intent.category.LAUNCHER" /&gt;
    ++    &lt;/intent-filter&gt;
    ++&lt;/activity&gt;
    ++&lt;activity
    ++    android:name=".ResultActivity"
    ++    android:parentActivityName=".MainActivity"&gt;
    ++    &lt;meta-data
    ++        android:name="android.support.PARENT_ACTIVITY"
    ++        android:value=".MainActivity"/&gt;
    ++&lt;/activity&gt;
    ++</pre>
    ++    </li>
    ++    <li>
    ++        Buat back-stack berdasarkan {@link android.content.Intent} yang memulai
    ++        {@link android.app.Activity}:
    ++        <ol style="list-style-type: lower-alpha;">
    ++            <li>
    ++                Buat {@link android.content.Intent} untuk memulai {@link android.app.Activity}.
    ++            </li>
    ++            <li>
    ++                Buat stack-builder (pembangun tumpukan) dengan memanggil {@link android.app.TaskStackBuilder#create
    ++                TaskStackBuilder.create()}.
    ++            </li>
    ++            <li>
    ++                Tambahkan back-stack ke stack-builder dengan memanggil
    ++                {@link android.support.v4.app.TaskStackBuilder#addParentStack addParentStack()}.
    ++                Untuk setiap {@link android.app.Activity} dalam hierarki yang telah Anda definisikan dalam
    ++                manifes, back-stack berisi objek {@link android.content.Intent} yang
    ++                memulai {@link android.app.Activity}. Metode ini juga menambahkan flag yang memulai
    ++                back-stack dalam tugas baru.
    ++                <p class="note">
    ++                    <strong>Catatan:</strong> Walaupun argumen untuk
    ++                    {@link android.support.v4.app.TaskStackBuilder#addParentStack addParentStack()}
    ++                    adalah acuan ke {@link android.app.Activity} yang dimulai, panggilan metode
    ++                    tidak akan menambahkan {@link android.content.Intent} yang memulai
    ++                    {@link android.app.Activity}. Sebagai gantinya, hal itu ditangani dalam langkah berikutnya.
    ++                </p>
    ++            </li>
    ++            <li>
    ++                Tambahkan {@link android.content.Intent} yang memulai {@link android.app.Activity}
    ++                dari pemberitahuan, dengan memanggil
    ++                {@link android.support.v4.app.TaskStackBuilder#addNextIntent addNextIntent()}.
    ++                Teruskan {@link android.content.Intent} yang Anda buat dalam langkah pertama sebagai
    ++                argumen ke
    ++                {@link android.support.v4.app.TaskStackBuilder#addNextIntent addNextIntent()}.
    ++            </li>
    ++            <li>
    ++                Jika perlu, tambahkan argumen ke objek {@link android.content.Intent} pada
    ++                back-stack dengan memanggil {@link android.support.v4.app.TaskStackBuilder#editIntentAt
    ++                TaskStackBuilder.editIntentAt()}. Kadang-kadang perlu memastikan apakah
    ++                {@link android.app.Activity} target menampilkan data bermakna saat pengguna menelusurinya
    ++                dengan menggunakan <i>Back</i>.
    ++            </li>
    ++            <li>
    ++                Dapatkan {@link android.app.PendingIntent} untuk back-stack ini dengan memanggil
    ++                {@link android.support.v4.app.TaskStackBuilder#getPendingIntent getPendingIntent()}.
    ++                Anda nanti bisa menggunakan {@link android.app.PendingIntent} ini sebagai argumen untuk
    ++                {@link android.support.v4.app.NotificationCompat.Builder#setContentIntent
    ++                setContentIntent()}.
    ++            </li>
    ++        </ol>
    ++     </li>
    ++</ol>
    ++<p>
    ++    Cuplikan kode berikut memperagakan prosesnya:
    ++</p>
    ++<pre>
    ++...
    ++Intent resultIntent = new Intent(this, ResultActivity.class);
    ++TaskStackBuilder stackBuilder = TaskStackBuilder.create(this);
    ++// Adds the back stack
    ++stackBuilder.addParentStack(ResultActivity.class);
    ++// Adds the Intent to the top of the stack
    ++stackBuilder.addNextIntent(resultIntent);
    ++// Gets a PendingIntent containing the entire back stack
    ++PendingIntent resultPendingIntent =
    ++        stackBuilder.getPendingIntent(0, PendingIntent.FLAG_UPDATE_CURRENT);
    ++...
    ++NotificationCompat.Builder builder = new NotificationCompat.Builder(this);
    ++builder.setContentIntent(resultPendingIntent);
    ++NotificationManager mNotificationManager =
    ++    (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
    ++mNotificationManager.notify(id, builder.build());
    ++</pre>
    ++<!-- ------------------------------------------------------------------------------------------ -->
    ++<h3 id="ExtendedNotification">Menyiapkan PendingIntent aktivitas khusus</h3>
    ++<p>
    ++    Bagian berikut menjelaskan cara menyiapkan aktivitas khusus
    ++    {@link android.app.PendingIntent}.
    ++</p>
    ++<p>
    ++    {@link android.app.Activity} khusus tidak memerlukan back-stack, sehingga Anda tidak perlu
    ++    mendefinisikan hierarki {@link android.app.Activity}-nya dalam manifes, dan Anda tidak perlu
    ++    memanggil
    ++    {@link android.support.v4.app.TaskStackBuilder#addParentStack  addParentStack()} untuk membuat
    ++    back-stack. Sebagai gantinya, gunakan manifes untuk menyiapkan opsi tugas {@link android.app.Activity},
    ++    dan buat {@link android.app.PendingIntent} dengan memanggil
    ++    {@link android.app.PendingIntent#getActivity getActivity()}:
    ++</p>
    ++<ol>
    ++    <li>
    ++        Dalam manifes, tambahkan atribut berikut pada elemen
    ++<code><a href="{@docRoot}guide/topics/manifest/activity-element.html">&lt;activity&gt;</a></code>
    ++        untuk {@link android.app.Activity}
    ++        <dl>
    ++            <dt>
    ++<code><a href="{@docRoot}guide/topics/manifest/activity-element.html#nm">android:name</a>="<i>activityclass</i>"</code>
    ++            </dt>
    ++            <dd>
    ++                Nama kelas mutlak (fully qualified) aktivitas.
    ++            </dd>
    ++            <dt>
    ++<code><a href="{@docRoot}guide/topics/manifest/activity-element.html#aff">android:taskAffinity</a>=""</code>
    ++            </dt>
    ++            <dd>
    ++                Dikombinasikan dengan flag
    ++                {@link android.content.Intent#FLAG_ACTIVITY_NEW_TASK FLAG_ACTIVITY_NEW_TASK}
    ++                yang Anda atur dalam kode, ini memastikan bahwa {@link android.app.Activity} ini tidak
    ++                masuk ke dalam tugas default aplikasi. Setiap tugas yang ada yang memiliki
    ++                afinitas default aplikasi tidak terpengaruh.
    ++            </dd>
    ++            <dt>
    ++<code><a href="{@docRoot}guide/topics/manifest/activity-element.html#exclude">android:excludeFromRecents</a>="true"</code>
    ++            </dt>
    ++            <dd>
    ++                Mengecualikan tugas baru dari <i>Recents</i>, sehingga pengguna tidak bisa tanpa sengaja
    ++                mengarahkan kembali.
    ++            </dd>
    ++        </dl>
    ++        <p>
    ++            Cuplikan ini menampilkan elemen:
    ++        </p>
    ++<pre>
    ++&lt;activity
    ++    android:name=".ResultActivity"
    ++...
    ++    android:launchMode="singleTask"
    ++    android:taskAffinity=""
    ++    android:excludeFromRecents="true"&gt;
    ++&lt;/activity&gt;
    ++...
    ++</pre>
    ++    </li>
    ++    <li>
    ++        Buat dan keluarkan pemberitahuan:
    ++        <ol style="list-style-type: lower-alpha;">
    ++            <li>
    ++                Buat {@link android.content.Intent} yang memulai
    ++                {@link android.app.Activity}.
    ++            </li>
    ++            <li>
    ++                Atur {@link android.app.Activity} untuk dimulai dalam tugas kosong yang baru dengan memanggil
    ++                {@link android.content.Intent#setFlags setFlags()} dengan flag
    ++                {@link android.content.Intent#FLAG_ACTIVITY_NEW_TASK FLAG_ACTIVITY_NEW_TASK}
    ++                dan
    ++                {@link android.content.Intent#FLAG_ACTIVITY_CLEAR_TASK FLAG_ACTIVITY_CLEAR_TASK}.
    ++            </li>
    ++            <li>
    ++                Atur setiap opsi lain yang Anda perlukan untuk {@link android.content.Intent}.
    ++            </li>
    ++            <li>
    ++                Buat {@link android.app.PendingIntent} dari {@link android.content.Intent}
    ++                dengan memanggil {@link android.app.PendingIntent#getActivity getActivity()}.
    ++                Anda nanti bisa menggunakan {@link android.app.PendingIntent} ini sebagai argumen untuk
    ++                {@link android.support.v4.app.NotificationCompat.Builder#setContentIntent
    ++                setContentIntent()}.
    ++            </li>
    ++        </ol>
    ++    <p>
    ++        Cuplikan kode berikut memperagakan prosesnya:
    ++    </p>
    ++<pre>
    ++// Instantiate a Builder object.
    ++NotificationCompat.Builder builder = new NotificationCompat.Builder(this);
    ++// Creates an Intent for the Activity
    ++Intent notifyIntent =
    ++        new Intent(this, ResultActivity.class);
    ++// Sets the Activity to start in a new, empty task
    ++notifyIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
    ++                        | Intent.FLAG_ACTIVITY_CLEAR_TASK);
    ++// Creates the PendingIntent
    ++PendingIntent notifyPendingIntent =
    ++        PendingIntent.getActivity(
    ++        this,
    ++        0,
    ++        notifyIntent,
    ++        PendingIntent.FLAG_UPDATE_CURRENT
    ++);
    ++
    ++// Puts the PendingIntent into the notification builder
    ++builder.setContentIntent(notifyPendingIntent);
    ++// Notifications are issued by sending them to the
    ++// NotificationManager system service.
    ++NotificationManager mNotificationManager =
    ++    (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
    ++// Builds an anonymous Notification object from the builder, and
    ++// passes it to the NotificationManager
    ++mNotificationManager.notify(id, builder.build());
    ++</pre>
    ++    </li>
    ++</ol>
    ++<!-- ------------------------------------------------------------------------------------------ -->
    ++<!-- ------------------------------------------------------------------------------------------ -->
    ++<h2 id="Progress">Menampilkan Kemajuan dalam Pemberitahuan</h2>
    ++<p>
    ++    Pemberitahuan bisa menyertakan indikator kemajuan beranimasi yang menampilkan status
    ++operasi yang berjalan kepada pengguna. Jika Anda bisa memperkirakan lamanya operasi berlangsung dan berapa banyak
    ++    yang sudah selesai pada suatu waktu, gunakan bentuk indikator yang "pasti"
    ++    (baris kemajuan). Jika Anda tidak bisa memperkirakan lamanya operasi, gunakan
    ++    bentuk indikator "tidak pasti" (indikator aktivitas).
    ++</p>
    ++<p>
    ++    Indikator kemajuan ditampilkan bersama implementasi platform
    ++    kelas {@link android.widget.ProgressBar}.
    ++</p>
    ++<p>
    ++    Untuk menggunakan indikator kemajuan pada platform mulai dari Android 4.0, panggil
    ++    {@link android.support.v4.app.NotificationCompat.Builder#setProgress setProgress()}. Untuk
    ++    versi sebelumnya, Anda harus membuat layout pemberitahuan custom sendiri yang
    ++menyertakan tampilan {@link android.widget.ProgressBar}.
    ++</p>
    ++<p>
    ++    Bagian berikut ini menjelaskan cara menampilkan kemajuan dalam pemberitahuan dengan menggunakan
    ++    {@link android.support.v4.app.NotificationCompat.Builder#setProgress setProgress()}.
    ++</p>
    ++<!-- ------------------------------------------------------------------------------------------ -->
    ++<h3 id="FixedProgress">Menampilkan indikator kemajuan berdurasi tetap</h3>
    ++<p>
    ++    Untuk menampilkan baris kemajuan pasti, tambahkan baris itu ke pemberitahuan dengan memanggil
    ++    {@link android.support.v4.app.NotificationCompat.Builder#setProgress
    ++    setProgress(max, progress, false)}, kemudian keluarkan pemberitahuan. Selagi operasi berlangsung,
    ++    tambah <code>progress</code>, dan perbarui pemberitahuan. Di akhir operasi,
    ++    <code>progress</code> harus sama dengan <code>max</code>. Satu cara umum memanggil
    ++    {@link android.support.v4.app.NotificationCompat.Builder#setProgress setProgress()}
    ++    adalah mengatur <code>max</code> ke 100, kemudian tambah <code>progress</code> sebagai
    ++     nilai "persen selesai"untuk operasi itu.
    ++</p>
    ++<p>
    ++    Anda bisa membiarkan baris kemajuan ditampilkan saat operasi selesai, atau menghilangkannya. Dalam
    ++    hal apa pun, ingatlah memperbarui teks pemberitahuan untuk menampilkan bahwa operasi telah selesai.
    ++    Untuk menghapus baris kemajuan, panggil
    ++    {@link android.support.v4.app.NotificationCompat.Builder#setProgress
    ++    setProgress(0, 0, false)}. Misalnya:
    ++</p>
    ++<pre>
    ++...
    ++mNotifyManager =
    ++        (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
    ++mBuilder = new NotificationCompat.Builder(this);
    ++mBuilder.setContentTitle("Picture Download")
    ++    .setContentText("Download in progress")
    ++    .setSmallIcon(R.drawable.ic_notification);
    ++// Start a lengthy operation in a background thread
    ++new Thread(
    ++    new Runnable() {
    ++        &#64;Override
    ++        public void run() {
    ++            int incr;
    ++            // Do the "lengthy" operation 20 times
    ++            for (incr = 0; incr &lt;= 100; incr+=5) {
    ++                    // Sets the progress indicator to a max value, the
    ++                    // current completion percentage, and "determinate"
    ++                    // state
    ++                    mBuilder.setProgress(100, incr, false);
    ++                    // Displays the progress bar for the first time.
    ++                    mNotifyManager.notify(0, mBuilder.build());
    ++                        // Sleeps the thread, simulating an operation
    ++                        // that takes time
    ++                        try {
    ++                            // Sleep for 5 seconds
    ++                            Thread.sleep(5*1000);
    ++                        } catch (InterruptedException e) {
    ++                            Log.d(TAG, "sleep failure");
    ++                        }
    ++            }
    ++            // When the loop is finished, updates the notification
    ++            mBuilder.setContentText("Download complete")
    ++            // Removes the progress bar
    ++                    .setProgress(0,0,false);
    ++            mNotifyManager.notify(ID, mBuilder.build());
    ++        }
    ++    }
    ++// Starts the thread by calling the run() method in its Runnable
    ++).start();
    ++</pre>
    ++
    ++<!-- ------------------------------------------------------------------------------------------ -->
    ++<h3 id="ActivityIndicator">Menampilkan indikator aktivitas berlanjut</h3>
    ++<p>
    ++    Untuk menampilkan indikator aktivitas tidak pasti, tambahkan aktivitas ke pemberitahuan dengan
    ++    {@link android.support.v4.app.NotificationCompat.Builder#setProgress setProgress(0, 0, true)}
    ++    (dua argumen pertama akan diabaikan), dan keluarkan pemberitahuan. Hasilnya adalah indikator
    ++    yang memiliki gaya yang sama dengan baris kemajuan, hanya saja animasinya terus berjalan.
    ++</p>
    ++<p>
    ++    Keluarkan pemberitahuan di awal operasi. Animasi akan berjalan hingga Anda
    ++    memodifikasi pemberitahuan. Bila operasi selesai, panggil
    ++    {@link android.support.v4.app.NotificationCompat.Builder#setProgress setProgress(0, 0, false)}
    ++    kemudian perbarui pemberitahuan untuk menghapus indikator aktivitas.
    ++    Selalu lakukan ini; jika makan animasi akan terus berjalan sekalipun operasi telah selesai. Juga
    ++    ingatlah mengubah teks pemberitahuan untuk menunjukkan bahwa operasi telah selesai.
    ++</p>
    ++<p>
    ++    Untuk melihat cara kerja indikator aktivitas, lihat cuplikan terdahulu. Cari lokasi baris-baris berikut:
    ++</p>
    ++<pre>
    ++// Sets the progress indicator to a max value, the current completion
    ++// percentage, and "determinate" state
    ++mBuilder.setProgress(100, incr, false);
    ++// Issues the notification
    ++mNotifyManager.notify(0, mBuilder.build());
    ++</pre>
    ++<p>
    ++    Ganti baris yang telah Anda temukan dengan baris berikut:
    ++</p>
    ++<pre>
    ++ // Sets an activity indicator for an operation of indeterminate length
    ++mBuilder.setProgress(0, 0, true);
    ++// Issues the notification
    ++mNotifyManager.notify(0, mBuilder.build());
    ++</pre>
    ++
    ++<h2 id="metadata">Metadata Pemberitahuan</h2>
    ++
    ++<p>Pemberitahuan dapat disortir sesuai metadata yang Anda tetapkan dengan
    ++metode {@link android.support.v4.app.NotificationCompat.Builder} berikut:</p>
    ++
    ++<ul>
    ++    <li>{@link android.support.v4.app.NotificationCompat.Builder#setCategory(java.lang.String) setCategory()}
    ++    memberi tahu sistem cara menangani pemberitahuan aplikasi Anda bila perangkat berada dalam mode Priority
    ++    (misalnya, jika pemberitahuan menyatakan suatu panggilan masuk, pesan instan, atau alarm).</li>
    ++    <li>{@link android.support.v4.app.NotificationCompat.Builder#setPriority(int) setPriority()} menyebabkan
    ++    pemberitahuan dengan bidang prioritas diatur ke {@code PRIORITY_MAX} atau {@code PRIORITY_HIGH}
    ++    muncul dalam jendela kecil mengambang jika pemberitahuan juga memiliki suara atau getaran.</li>
    ++    <li>{@link android.support.v4.app.NotificationCompat.Builder#addPerson(java.lang.String) addPerson()}
    ++    memungkinkan Anda menambahkan daftar orang ke pemberitahuan. Aplikasi Anda bisa menggunakannya untuk memberi isyarat pada
    ++    sistem bahwa sistem harus mengelompokkan bersama pemberitahuan dari orang-orang yang ditetapkan, atau memberi peringkat lebih penting pada pemberitahuan
    ++    untuk orang-orang ini.</li>
    ++</ul>
    ++
    ++<div class="figure" style="width:230px">
    ++  <img src="{@docRoot}images/ui/notifications/heads-up.png" alt="" width="" height="" id="figure3" />
    ++  <p class="img-caption">
    ++    <strong>Gambar 3.</strong> Aktivitas layar penuh yang menampilkan pemberitahuan pendahuluan
    ++  </p>
    ++</div>
    ++
    ++<h2 id="Heads-up">Pemberitahuan Pendahuluan</h2>
    ++
    ++<p>Dengan Android 5.0 (API level 21), pemberitahuan bisa muncul dalam jendela kecil mengambang
    ++(yang disebut juga dengan <em>pemberitahuan pendahuluan</em>) saat perangkat aktif
    ++(yakni, perangkat dibuka kuncinya dan layarnya menyala). Pemberitahuan ini
    ++muncul seperti bentuk ringkas pemberitahuan Anda, hanya saja
    ++pemberitahuan pendahuluan juga menampilkan tombol tindakan. Pengguna bisa menindaklanjuti atau mengabaikan,
    ++pemberitahuan pendahuluan tanpa meninggalkan aplikasi saat ini.</p>
    ++
    ++<p>Contoh-contoh kondisi yang dapat memicu pemberitahuan pendahuluan antara lain:</p>
    ++
    ++<ul>
    ++  <li>Aktivitas pengguna berada dalam mode layar penuh (aplikasi menggunakan
    ++{@link android.app.Notification#fullScreenIntent}), atau</li>
    ++  <li>Pemberitahuan memiliki prioritas tinggi dan menggunakan nada dering atau
    ++    getaran</li>
    ++</ul>
    ++
    ++<h2 id="lockscreenNotification">Pemberitahuan Layar Kunci</h2>
    ++
    ++<p>Dengan rilis Android 5.0 (API level 21), pemberitahuan kini dapat muncul pada
    ++layar kunci. Aplikasi Anda bisa menggunakan fungsionalitas ini untuk menyediakan kontrol pemutaran media dan
    ++tindakan umum lainnya. Pengguna bisa memilih lewat Settings apakah akan menampilkan pemberitahuan pada layar kunci, dan
    ++Anda bisa mendesain apakah pemberitahuan aplikasi akan terlihat pada layar kunci.</p>
    ++
    ++<h3 id="visibility">Mengatur Visibilitas</h3>
    ++
    ++<p>Aplikasi Anda bisa mengatur level detail terlihat pada pemberitahuan yang ditampilkan di
    ++layar kunci aman. Anda memanggil {@link android.support.v4.app.NotificationCompat.Builder#setVisibility(int) setVisibility()}
    ++dan menetapkan salah satu nilai berikut:</p>
    ++
    ++<ul>
    ++    <li>{@link android.support.v4.app.NotificationCompat#VISIBILITY_PUBLIC} menampilkan isi lengkap
    ++    pemberitahuan.</li>
    ++    <li>{@link android.support.v4.app.NotificationCompat#VISIBILITY_SECRET} tidak menampilkan bagian apa pun dari
    ++    pemberitahuan ini pada layar kunci.</li>
    ++    <li>{@link android.support.v4.app.NotificationCompat#VISIBILITY_PRIVATE} menampilkan informasi dasar,
    ++    misalnya ikon dan judul isi pemberitahuan, namun menyembunyikan isi lengkap pemberitahuan.</li>
    ++</ul>
    ++
    ++<p>Bila {@link android.support.v4.app.NotificationCompat#VISIBILITY_PRIVATE} telah diatur, Anda juga bisa
    ++menyediakan versi alternatif isi pemberitahuan yang menyembunyikan detail tertentu. Misalnya,
    ++aplikasi SMS dapat menampilkan pemberitahuan yang menampilkan <em>Anda memiliki 3 pesan teks baru</em>, namun menyembunyikan
    ++isi dan pengirim pesan. Untuk menyediakan pemberitahuan alternatif ini, buat dahulu pemberitahuan
    ++pengganti menggunakan {@link android.support.v4.app.NotificationCompat.Builder}. Bila Anda membuat
    ++objek pemberitahuan privat, lampirkan pemberitahuan pengganti melalui metode
    ++{@link android.support.v4.app.NotificationCompat.Builder#setPublicVersion(android.app.Notification) setPublicVersion()}
    ++.</p>
    ++
    ++<h3 id="controllingMedia">Mengontrol Pemutaran Media pada Layar Kunci</h3>
    ++
    ++<p>Dalam Android 5.0 (API level 21) layar kunci tidak lagi menampilkan kontrol media
    ++berdasarkan {@link android.media.RemoteControlClient}, yang sekarang telah dihilangkan. Sebagai gantinya, gunakan
    ++template {@link android.app.Notification.MediaStyle} dengan metode
    ++{@link android.app.Notification.Builder#addAction(android.app.Notification.Action) addAction()}
    ++, yang mengubah tindakan menjadi ikon yang bisa diklik.</p>
    ++
    ++<p class="note"><strong>Catatan:</strong> Template dan metode {@link android.app.Notification.Builder#addAction(android.app.Notification.Action) addAction()}
    ++tidak disertakan dalam pustaka dukungan, sehingga fitur-fitur ini berjalan pada Android 5.0 dan yang lebih tinggi
    ++saja.</p>
    ++
    ++<p>Untuk menampilkan kontrol pemutaran media di layar kunci dalam Android 5.0, atur visibilitas
    ++ke {@link android.support.v4.app.NotificationCompat#VISIBILITY_PUBLIC}, seperti dijelaskan di atas. Kemudian tambahkan
    ++tindakan dan atur template {@link android.app.Notification.MediaStyle}, seperti dijelaskan dalam contoh kode
    ++berikut:</p>
    ++
    ++<pre>
    ++Notification notification = new Notification.Builder(context)
    ++    // Show controls on lock screen even when user hides sensitive content.
    ++    .setVisibility(Notification.VISIBILITY_PUBLIC)
    ++    .setSmallIcon(R.drawable.ic_stat_player)
    ++    // Add media control buttons that invoke intents in your media service
    ++    .addAction(R.drawable.ic_prev, "Previous", prevPendingIntent) // #0
    ++    .addAction(R.drawable.ic_pause, "Pause", pausePendingIntent)  // #1
    ++    .addAction(R.drawable.ic_next, "Next", nextPendingIntent)     // #2
    ++    // Apply the media style template
    ++    .setStyle(new Notification.MediaStyle()
    ++    .setShowActionsInCompactView(1 /* #1: pause button */)
    ++    .setMediaSession(mMediaSession.getSessionToken())
    ++    .setContentTitle("Wonderful music")
    ++    .setContentText("My Awesome Band")
    ++    .setLargeIcon(albumArtBitmap)
    ++    .build();
    ++</pre>
    ++
    ++<p class="note"><strong>Catatan:</strong> Dihilangkannya {@link android.media.RemoteControlClient}
    ++memiliki implikasi lebih jauh untuk mengontrol media. Lihat
    ++<a href="{@docRoot}about/versions/android-5.0.html#MediaPlaybackControl">Kontrol Pemutaran Media</a>
    ++untuk informasi selengkapnya tentang API baru untuk mengelola sesi media dan mengontrol pemutaran.</p>
    ++
    ++
    ++<!-- ------------------------------------------------------------------------------------------ -->
    ++<h2 id="CustomNotification">Layout Pemberitahuan Custom</h2>
    ++<p>
    ++    Kerangka kerja pemberitahuan memungkinkan Anda mendefinisikan layout pemberitahuan custom, yang
    ++    mendefinisikan penampilan pemberitahuan dalam objek {@link android.widget.RemoteViews}.
    ++    Pemberitahuan dengan layout custom serupa pemberitahuan normal, namun dibuat berdasarkan
    ++    {@link android.widget.RemoteViews} yang didefinisikan dalam file layout XML.
    ++</p>
    ++<p>
    ++    Tinggi yang tersedia untuk layout pemberitahuan custom bergantung pada tampilan pemberitahuan. Layout
    ++    tampilan normal dibatasi hingga 64 dp, dan layout tampilan yang diperluas dibatasi hingga 256 dp.
    ++</p>
    ++<p>
    ++    Untuk mendefinisikan layout pemberitahuan custom, mulailah dengan membuat instance
    ++    objek {@link android.widget.RemoteViews} yang memekarkan file layout XML. Kemudian,
    ++    sebagai ganti memanggil metode seperti
    ++    {@link android.support.v4.app.NotificationCompat.Builder#setContentTitle setContentTitle()},
    ++    panggil {@link android.support.v4.app.NotificationCompat.Builder#setContent setContent()}. Untuk mengatur
    ++    detail isi pemberitahuan custom, gunakan metode dalam
    ++    {@link android.widget.RemoteViews} untuk mengatur nilai anak tampilan:
    ++</p>
    ++<ol>
    ++    <li>
    ++        Buat layout XML untuk pemberitahuan di file terpisah. Anda bisa menggunakan nama file
    ++apa saja yang diinginkan, namun Anda harus menggunakan ekstensi <code>.xml</code>
    ++    </li>
    ++    <li>
    ++        Dalam aplikasi Anda, gunakan metode {@link android.widget.RemoteViews} untuk mendefinisikan
    ++        ikon dan teks pemberitahuan. Masukkan objek {@link android.widget.RemoteViews} ini ke dalam
    ++        {@link android.support.v4.app.NotificationCompat.Builder} Anda dengan memanggil
    ++        {@link android.support.v4.app.NotificationCompat.Builder#setContent setContent()}. Hindari
    ++        mengatur {@link android.graphics.drawable.Drawable} latar belakang pada
    ++        objek {@link android.widget.RemoteViews} Anda, karena warna teks bisa menjadi tidak terbaca.
    ++    </li>
    ++</ol>
    ++<p>
    ++    Kelas {@link android.widget.RemoteViews} juga menyertakan metode yang bisa Anda gunakan untuk
    ++    menambahkan {@link android.widget.Chronometer} atau {@link android.widget.ProgressBar}
    ++dengan mudah ke layout pemberitahuan Anda. Untuk informasi selengkapnya tentang cara membuat layout custom
    ++    pemberitahuan Anda, lihat dokumentasi acuan {@link android.widget.RemoteViews}.
    ++</p>
    ++<p class="caution">
    ++    <strong>Perhatian:</strong> Bila Anda menggunakan layout pemberitahuan custom, berhati-hatilah
    ++    untuk memastikan bahwa layout custom itu bekerja pada berbagai orientasi dan resolusi perangkat. Walaupun
    ++    berlaku bagi semua layout View, nasihat ini khususnya penting untuk pemberitahuan karena
    ++    ruang di laci pemberitahuan sangat terbatas. Jangan buat layout custom terlalu
    ++    kompleks, dan pastikan mengujinya di berbagai konfigurasi.
    ++</p>
    ++<!-- ------------------------------------------------------------------------------------------ -->
    ++<h4>Menggunakan sumber daya gaya untuk teks pemberitahuan custom</h4>
    ++<p>
    ++    Selalu gunakan sumber daya gaya untuk teks pemberitahuan custom. Warna latar belakang
    ++    pemberitahuan bisa bervariasi di berbagai perangkat dan versi, dan menggunakan sumber daya gaya
    ++    membantu Anda menangani hal ini. Mulai Android 2.3, sistem mendefinisikan sebuah gaya untuk
    ++    teks layout pemberitahuan standar. Jika Anda menggunakan gaya yang sama dalam aplikasi yang menargetkan Android
    ++    2.3 atau yang lebih tinggi, Anda akan memastikan bahwa teks terlihat pada latar belakang tampilan.
    ++</p>
    +diff --git a/docs/html-intl/intl/id/guide/topics/ui/overview.jd b/docs/html-intl/intl/id/guide/topics/ui/overview.jd
    +new file mode 100644
    +index 0000000..ca8b420
    +--- /dev/null
    ++++ b/docs/html-intl/intl/id/guide/topics/ui/overview.jd
    +@@ -0,0 +1,71 @@
    ++page.title=Ikhtisar UI
    ++@jd:body
    ++
    ++
    ++<p>Semua elemen antarmuka pengguna dalam aplikasi Android dibangun menggunakan objek {@link android.view.View} dan
    ++{@link android.view.ViewGroup}. {@link android.view.View} adalah objek yang menarik
    ++sesuatu di layar dan dapat berinteraksi dengan pengguna. {@link android.view.ViewGroup} merupakan sebuah
    ++objek yang menyimpan objek {@link android.view.View} lainnya (dan {@link android.view.ViewGroup}) untuk
    ++mendefinisikan layout antarmuka.</p>
    ++
    ++<p>Android menyediakan sekumpulan subkelas {@link android.view.View} dan {@link
    ++android.view.ViewGroup} yang menawarkan kontrol input umum (seperti tombol dan bidang
    ++teks) serta berbagai model layout (seperti layout linear atau relatif).</p>
    ++
    ++
    ++<h2 id="Layout">Layout Antarmuka Pengguna</h2>
    ++
    ++<p>Antarmuka pengguna untuk setiap komponen aplikasi Anda didefinisikan menggunakan hierarki objek {link
    ++android.view.View} dan {@link android.view.ViewGroup}, seperti yang ditampilkan dalam gambar 1. Setiap kelompok tampilan
    ++merupakan kontainer tak terlihat yang mengelola tampilan anak, sementara tampilan anak ini dapat menjadi kontrol
    ++input atau widget lain yang
    ++menarik sebagian dari UI. Pohon hierarki ini bisa sederhana atau bisa juga kompleks bergantung kebutuhan
    ++(namun yang sederhana paling baik untuk kinerja).</p>
    ++
    ++<img src="{@docRoot}images/viewgroup.png" alt="" />
    ++<p class="img-caption"><strong>Gambar 1.</strong> Ilustrasi dari hierarki tampilan, yang mendefinisikan layout
    ++UI.</p>
    ++
    ++<p>Untuk mendeklarasikan layout, Anda dapat menyediakan objek {@link android.view.View} dalam kode dan mulai
    ++membangun pohon, namun cara termudah dan terefektif untuk mendefinisikan layout adalah dengan file XML.
    ++XML menawarkan struktur layout yang dapat dibaca manusia, serupa dengan HTML.</p>
    ++
    ++<p>Nama elemen XML untuk tampilan sesuai dengan kelas Android yang diwakilinya. Dengan demikian elemen
    ++<code>&lt;TextView&gt;</code> membuat widget {@link android.widget.TextView} dalam UI Anda,
    ++dan elemen <code>&lt;LinearLayout&gt;</code> membuat kelompok tampilan {@link android.widget.LinearLayout}
    ++. </p>
    ++
    ++<p>Misalnya, layout vertikal sederhana dengan tampilan teks dan tombol akan tampak seperti ini:</p>
    ++<pre>
    ++&lt;?xml version="1.0" encoding="utf-8"?>
    ++&lt;LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    ++              android:layout_width="fill_parent"
    ++              android:layout_height="fill_parent"
    ++              android:orientation="vertical" >
    ++    &lt;TextView android:id="@+id/text"
    ++              android:layout_width="wrap_content"
    ++              android:layout_height="wrap_content"
    ++              android:text="I am a TextView" />
    ++    &lt;Button android:id="@+id/button"
    ++            android:layout_width="wrap_content"
    ++            android:layout_height="wrap_content"
    ++            android:text="I am a Button" />
    ++&lt;/LinearLayout>
    ++</pre>
    ++
    ++<p>Saat Anda memuat sumber daya layout di aplikasi, Android akan menginisialisasi setiap simpul layout menjadi
    ++objek runtime yang bisa Anda gunakan untuk mendefinisikan perilaku tambahan, query status objek, atau memodifikasi
    ++layout.</p>
    ++
    ++<p>Untuk mendapatkan panduan lengkap mengenai pembuatan layout UI, lihat <a href="declaring-layout.html">Layout
    ++XML</a>.
    ++
    ++
    ++<h2 id="UIComponents">Komponen Antarmuka Pengguna</h2>
    ++
    ++<p>Anda tidak harus membuat semua UI menggunakan objek {@link android.view.View} dan {link
    ++android.view.ViewGroup}. Android menyediakan beberapa komponen aplikasi yang menawarkan
    ++layout UI standar yang tinggal Anda definisikan kontennya. Komponen UI ini masing-masing
    ++memiliki set API unik yang dijelaskan dalam masing-masing dokumennya, seperti <a href="{@docRoot}guide/topics/ui/actionbar.html">Action-Bar</a>, <a href="{@docRoot}guide/topics/ui/dialogs.html">Dialog</a>, dan <a href="{@docRoot}guide/topics/ui/notifiers/notifications.html">Pemberitahuan Status</a>.</p>
    ++
    ++
    +diff --git a/docs/html-intl/intl/id/guide/topics/ui/settings.jd b/docs/html-intl/intl/id/guide/topics/ui/settings.jd
    +new file mode 100644
    +index 0000000..89be52f
    +--- /dev/null
    ++++ b/docs/html-intl/intl/id/guide/topics/ui/settings.jd
    +@@ -0,0 +1,1202 @@
    ++page.title=Pengaturan
    ++page.tags=preference,preferenceactivity,preferencefragment
    ++
    ++@jd:body
    ++
    ++
    ++<div id="qv-wrapper">
    ++<div id="qv">
    ++
    ++<h2>Dalam dokumen ini</h2>
    ++<ol>
    ++  <li><a href="#Overview">Ikhtisar</a>
    ++    <ol>
    ++      <li><a href="#SettingTypes">Preferensi</a></li>
    ++    </ol>
    ++  </li>
    ++  <li><a href="#DefiningPrefs">Mendefinisikan Preferensi dalam XML</a>
    ++    <ol>
    ++      <li><a href="#Groups">Membuat grup pengaturan</a></li>
    ++      <li><a href="#Intents">Menggunakan intent</a></li>
    ++    </ol>
    ++  </li>
    ++  <li><a href="#Activity">Membuat Aktivitas Preferensi</a></li>
    ++  <li><a href="#Fragment">Menggunakan Fragmen Preferensi</a></li>
    ++  <li><a href="#Defaults">Mengatur Nilai Default</a></li>
    ++  <li><a href="#PreferenceHeaders">Menggunakan Header Preferensi</a>
    ++    <ol>
    ++      <li><a href="#CreateHeaders">Membuat file header</a></li>
    ++      <li><a href="#DisplayHeaders">Menampilkan header</a></li>
    ++      <li><a href="#BackCompatHeaders">Mendukung versi yang lebih lama dengan header preferensi</a></li>
    ++    </ol>
    ++  </li>
    ++  <li><a href="#ReadingPrefs">Preferensi Membaca</a>
    ++    <ol>
    ++      <li><a href="#Listening">Mendengarkan perubahan preferensi</a></li>
    ++    </ol>
    ++  </li>
    ++  <li><a href="#NetworkUsage">Mengelola Penggunaan Jaringan</a></li>
    ++  <li><a href="#Custom">Membangun Preferensi Custom</a>
    ++    <ol>
    ++      <li><a href="#CustomSelected">Menetapkan antarmuka pengguna</a></li>
    ++      <li><a href="#CustomSave">Menyimpan nilai pengaturan</a></li>
    ++      <li><a href="#CustomInitialize">Menginisialisasi nilai saat ini</a></li>
    ++      <li><a href="#CustomDefault">Menyediakan nilai default</a></li>
    ++      <li><a href="#CustomSaveState">Menyimpan dan memulihkan status Preferensi</a></li>
    ++    </ol>
    ++  </li>
    ++</ol>
    ++
    ++<h2>Kelas-kelas utama</h2>
    ++<ol>
    ++  <li>{@link android.preference.Preference}</li>
    ++  <li>{@link android.preference.PreferenceActivity}</li>
    ++  <li>{@link android.preference.PreferenceFragment}</li>
    ++</ol>
    ++
    ++
    ++<h2>Lihat juga</h2>
    ++<ol>
    ++  <li><a href="{@docRoot}design/patterns/settings.html">Panduan desain pengaturan</a></li>
    ++</ol>
    ++</div>
    ++</div>
    ++
    ++
    ++
    ++
    ++<p>Aplikasi sering kali menyertakan pengaturan yang memungkinkan pengguna memodifikasi fitur dan perilaku aplikasi. Misalnya,
    ++beberapa aplikasi memungkinkan pengguna untuk menetapkan apakah pemberitahuan diaktifkan atau menetapkan seberapa sering
    ++aplikasi menyinkronkan data dengan cloud.</p>
    ++
    ++<p>Jika ingin menyediakan pengaturan untuk aplikasi, Anda harus menggunakan
    ++API Android {@link android.preference.Preference} untuk membangun antarmuka yang konsisten dengan
    ++pengalaman pengguna di aplikasi Android yang lain (termasuk pengaturan sistem). Dokumen ini menjelaskan
    ++cara membangun pengaturan aplikasi Anda menggunakan API {@link android.preference.Preference}.</p>
    ++
    ++<div class="note design">
    ++<p><strong>Desain Pengaturan</strong></p>
    ++  <p>Untuk informasi tentang cara mendesain pengaturan Anda, bacalah panduan desain <a href="{@docRoot}design/patterns/settings.html">Pengaturan</a>.</p>
    ++</div>
    ++
    ++
    ++<img src="{@docRoot}images/ui/settings/settings.png" alt="" width="435" />
    ++<p class="img-caption"><strong>Gambar 1.</strong> Cuplikan layar dari pengaturan
    ++aplikasi Messaging Android. Memilih item yang didefinisikan oleh {@link android.preference.Preference}
    ++akan membuka antarmuka untuk mengubah pengaturan.</p>
    ++
    ++
    ++
    ++
    ++<h2 id="Overview">Ikhtisar</h2>
    ++
    ++<p>Sebagai ganti menggunakan objek {@link android.view.View} untuk membangun antarmuka pengguna, pengaturan
    ++dibangun menggunakan berbagai subkelas dari kelas {@link android.preference.Preference} yang Anda
    ++deklarasikan dalam file XML.</p>
    ++
    ++<p>Objek {@link android.preference.Preference} adalah blok pembangun untuk pengaturan
    ++tunggal. Setiap {@link android.preference.Preference} muncul sebagai item dalam daftar dan menyediakan UI
    ++yang sesuai bagi pengguna untuk memodifikasi pengaturan. Misalnya, {@link
    ++android.preference.CheckBoxPreference} membuat item daftar yang menampilkan kotak cek, dan {@link
    ++android.preference.ListPreference} membuat item yang membuka dialog berisi daftar pilihan.</p>
    ++
    ++<p>Setiap {@link android.preference.Preference} yang Anda tambahkan memiliki pasangan nilai-kunci yang sesuai yang
    ++digunakan sistem untuk menyimpan pengaturan dalam file {@link android.content.SharedPreferences}
    ++default untuk pengaturan aplikasi Anda. Bila pengguna mengubah pengaturan, sistem akan memperbarui nilai
    ++yang bersangkutan dalam file {@link android.content.SharedPreferences} untuk Anda. Satu-satunya saat di mana Anda harus
    ++berinteraksi langsung dengan file {@link android.content.SharedPreferences} yang terkait adalah bila Anda
    ++perlu membaca nilai untuk menentukan perilaku aplikasi berdasarkan pengaturan pengguna.</p>
    ++
    ++<p>Nilai yang tersimpan di {@link android.content.SharedPreferences} untuk setiap pengaturan bisa berupa
    ++tipe data berikut:</p>
    ++
    ++<ul>
    ++  <li>Boolean</li>
    ++  <li>Float</li>
    ++  <li>Int</li>
    ++  <li>Long</li>
    ++  <li>String</li>
    ++  <li>String {@link java.util.Set}</li>
    ++</ul>
    ++
    ++<p>Oleh karena UI pengaturan aplikasi Anda dibangun menggunakan objek {@link android.preference.Preference}
    ++sebagai ganti
    ++objek {@link android.view.View}, Anda perlu menggunakan {@link android.app.Activity} khusus atau
    ++subkelas {@link android.app.Fragment} untuk menampilkan pengaturan daftar:</p>
    ++
    ++<ul>
    ++  <li>Jika aplikasi Anda mendukung versi Android yang lebih lama dari 3.0 (API level 10 dan yang lebih rendah), Anda harus
    ++membangun aktivitas sebagai ekstensi dari kelas {@link android.preference.PreferenceActivity}.</li>
    ++  <li>Pada Android 3.0 dan yang lebih baru, sebaiknya Anda menggunakan {@link android.app.Activity} biasa
    ++yang menjadi host {@link android.preference.PreferenceFragment} yang menampilkan pengaturan aplikasi Anda.
    ++Akan tetapi, Anda juga bisa menggunakan {@link android.preference.PreferenceActivity} untuk membuat layout dua panel
    ++bagi layar besar bila Anda memiliki beberapa grup pengaturan.</li>
    ++</ul>
    ++
    ++<p>Cara mengatur {@link android.preference.PreferenceActivity} Anda dan instance {@link
    ++android.preference.PreferenceFragment} dibahas di bagian tentang <a href="#Activity">Membuat Aktivitas Preferensi</a> dan <a href="#Fragment">Menggunakan
    ++Fragmen Preferensi</a>.</p>
    ++
    ++
    ++<h3 id="SettingTypes">Preferensi</h3>
    ++
    ++<p>Setiap pengaturan untuk aplikasi Anda diwakili oleh subkelas khusus dari kelas {@link
    ++android.preference.Preference}. Setiap subkelas menyertakan seperangkat properti utama yang memungkinkan Anda
    ++untuk menetapkan berbagai hal seperti judul pengaturan dan nilai default. Setiap subkelas juga menyediakan
    ++antarmuka pengguna dan properti khusus miliknya sendiri. Misalnya, gambar 1 menampilkan cuplikan layar dari
    ++ pengaturan aplikasi Messaging. Setiap item daftar dalam layar pengaturan didukung oleh objek {@link
    ++android.preference.Preference} berbeda.</p>
    ++
    ++<p>Beberapa preferensi yang paling umum adalah:</p>
    ++
    ++<dl>
    ++  <dt>{@link android.preference.CheckBoxPreference}</dt>
    ++  <dd>Menampilkan item dengan kotak cek untuk pengaturan yang diaktifkan atau dinonaktifkan. Nilai
    ++tersimpan adalah boolean (<code>true</code> jika diberi tanda cek).</dd>
    ++
    ++  <dt>{@link android.preference.ListPreference}</dt>
    ++  <dd>Membuka dialog berisi daftar tombol radio. Nilai
    ++tersimpan bisa berupa tipe nilai apa pun yang didukung (tercantum di atas).</dd>
    ++
    ++  <dt>{@link android.preference.EditTextPreference}</dt>
    ++  <dd>Membuka dialog berisi widget {@link android.widget.EditText}. Nilai tersimpan adalah {@link
    ++java.lang.String}.</dd>
    ++</dl>
    ++
    ++<p>Lihat kelas {@link android.preference.Preference} untuk mengetahui daftar subkelas lain dan
    ++propertinya.</p>
    ++
    ++<p>Tentu saja, kelas bawaan tidak mengakomodasi setiap kebutuhan dan aplikasi Anda mungkin memerlukan
    ++sesuatu yang lebih khusus. Misalnya, platform saat ini tidak menyediakan kelas {@link
    ++android.preference.Preference} untuk mengambil nomor atau tanggal. Anda mungkin perlu mendefinisikan
    ++subkelas {@link android.preference.Preference} sendiri. Untuk bantuan melakukannya, lihat bagian tentang <a href="#Custom">Membangun Preferensi Custom</a>.</p>
    ++
    ++
    ++
    ++<h2 id="DefiningPrefs">Mendefinisikan Preferensi dalam XML</h2>
    ++
    ++<p>Meskipun bisa membuat instance objek {@link android.preference.Preference} baru saat runtime, Anda
    ++harus mendefinisikan daftar pengaturan dalam XML dengan hierarki objek
    ++{@link android.preference.Preference}. Menggunakan file XML untuk mendefinisikan sekumpulan pengaturan lebih disukai karena file
    ++menyediakan struktur yang mudah dibaca dan diperbarui. Selain itu, pengaturan aplikasi Anda
    ++umumnya telah ditetapkan sebelumnya, meskipun Anda masih bisa memodifikasi kumpulan tersebut saat runtime.</p>
    ++
    ++<p>Setiap subkelas {@link android.preference.Preference} bisa dideklarasikan dengan elemen XML yang
    ++cocok dengan nama kelas, seperti {@code &lt;CheckBoxPreference&gt;}.</p>
    ++
    ++<p>Anda harus menyimpan file XML dalam direktori {@code res/xml/}. Meskipun bisa memberi nama file
    ++sesuka Anda, biasanya file diberi nama {@code preferences.xml}. Biasanya Anda hanya memerlukan satu file,
    ++karena cabang di hierarki (yang membuka daftar pengaturanny sendiri) dideklarasikan menggunakan instance
    ++tersarang {@link android.preference.PreferenceScreen}.</p>
    ++
    ++<p class="note"><strong>Catatan:</strong> Jika ingin membuat layout multipanel untuk
    ++pengaturan, Anda memerlukan file XML terpisah untuk setiap fragmen.</p>
    ++
    ++<p>Simpul akar untuk file XML harus merupakan elemen {@link android.preference.PreferenceScreen
    ++&lt;PreferenceScreen&gt;}. Dalam elemen inilah tempat Anda menambahkan setiap {@link
    ++android.preference.Preference}. Setiap anak yang Anda tambahkan dalam elemen
    ++{@link android.preference.PreferenceScreen &lt;PreferenceScreen&gt;} akan tampak sebagai item
    ++tunggal dalam daftar pengaturan.</p>
    ++
    ++<p>Misalnya:</p>
    ++
    ++<pre>
    ++&lt;?xml version="1.0" encoding="utf-8"?>
    ++&lt;PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android">
    ++    &lt;CheckBoxPreference
    ++        android:key="pref_sync"
    ++        android:title="@string/pref_sync"
    ++        android:summary="@string/pref_sync_summ"
    ++        android:defaultValue="true" />
    ++    &lt;ListPreference
    ++        android:dependency="pref_sync"
    ++        android:key="pref_syncConnectionType"
    ++        android:title="@string/pref_syncConnectionType"
    ++        android:dialogTitle="@string/pref_syncConnectionType"
    ++        android:entries="@array/pref_syncConnectionTypes_entries"
    ++        android:entryValues="@array/pref_syncConnectionTypes_values"
    ++        android:defaultValue="@string/pref_syncConnectionTypes_default" />
    ++&lt;/PreferenceScreen>
    ++</pre>
    ++
    ++<p>Dalam contoh ini, terdapat {@link android.preference.CheckBoxPreference} dan {@link
    ++android.preference.ListPreference}. Kedua item tersebut menyertakan tiga atribut berikut:</p>
    ++
    ++<dl>
    ++  <dt>{@code android:key}</dt>
    ++  <dd>Atribut ini diperlukan untuk preferensi yang mempertahankan nilai data. Ini menetapkan kunci
    ++unik (string) yang digunakan sistem saat menyimpan nilai pengaturan ini dalam {@link
    ++android.content.SharedPreferences}.
    ++  <p>Instance satu-satunya di mana atribut ini <em>tidak diperlukan</em> adalah bila preferensi berupa
    ++{@link android.preference.PreferenceCategory} atau {@link android.preference.PreferenceScreen}, atau
    ++preferensi menetapkan {@link android.content.Intent} untuk dipanggil (dengan elemen <a href="#Intents">{@code &lt;intent&gt;}</a>) atau {@link android.app.Fragment} untuk ditampilkan (dengan atribut <a href="{@docRoot}reference/android/preference/Preference.html#attr_android:fragment">{@code
    ++android:fragment}</a>).</p>
    ++  </dd>
    ++  <dt>{@code android:title}</dt>
    ++  <dd>Ini menyediakan nama pengaturan yang bisa dilihat oleh pengguna.</dd>
    ++  <dt>{@code android:defaultValue}</dt>
    ++  <dd>Ini menetapkan nilai awal yang harus diatur sistem dalam file {@link
    ++android.content.SharedPreferences}. Anda harus memberikan nilai default untuk semua
    ++pengaturan.</dd>
    ++</dl>
    ++
    ++<p>Untuk informasi tentang semua atribut lain yang didukung, lihat dokumentasi {@link
    ++android.preference.Preference} (dan subkelas masing-masing).</p>
    ++
    ++
    ++<div class="figure" style="width:300px">
    ++  <img src="{@docRoot}images/ui/settings/settings-titles.png" alt="" />
    ++  <p class="img-caption"><strong>Gambar 2.</strong> Mengatur kategori
    ++    dengan judul. <br/><b>1.</b> Kategori ditetapkan oleh elemen {@link
    ++android.preference.PreferenceCategory &lt;PreferenceCategory&gt;}. <br/><b>2.</b> Judul
    ++ditetapkan dengan atribut {@code android:title}.</p>
    ++</div>
    ++
    ++
    ++<p>Bila daftar pengaturan Anda melebihi sekitar 10 item, Anda mungkin perlu menambahkan judul untuk
    ++mendefinisikan grup pengaturan atau menampilkan grup tersebut di
    ++layar terpisah. Opsi ini dijelaskan di bagian berikut.</p>
    ++
    ++
    ++<h3 id="Groups">Membuat grup pengaturan</h3>
    ++
    ++<p>Jika Anda menampilkan daftar 10 pengaturan atau lebih, pengguna
    ++mungkin akan kesulitan dalam memindai, memahami dan memprosesnya. Anda bisa mengatasinya dengan
    ++membagi sebagian atau semua pengaturan ke dalam beberapa grup, yang secara efektif akan mengubah satu daftar panjang menjadi beberapa daftar
    ++yang lebih pendek. Suatu grup pengaturan terkait bisa ditampilkan dalam salah satu dari dua cara:</p>
    ++
    ++<ul>
    ++  <li><a href="#Titles">Menggunakan judul</a></li>
    ++  <li><a href="#Subscreens">Menggunakan sublayar</a></li>
    ++</ul>
    ++
    ++<p>Anda bisa menggunakan salah satu atau keduanya untuk mengelola pengaturan aplikasi Anda. Saat
    ++memutuskan mana yang akan digunakan dan cara membagi pengaturan, Anda harus mengikuti pedoman dalam
    ++Panduan <a href="{@docRoot}design/patterns/settings.html">Pengaturan</a> Desain Android.</p>
    ++
    ++
    ++<h4 id="Titles">Menggunakan judul</h4>
    ++
    ++<p>Jika ingin menyediakan divider dengan heading di antara grup pengaturan (seperti yang ditampilkan dalam gambar 2),
    ++tempatkan setiap grup objek {@link android.preference.Preference} di dalam {@link
    ++android.preference.PreferenceCategory}.</p>
    ++
    ++<p>Misalnya:</p>
    ++
    ++<pre>
    ++&lt;PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android">
    ++    &lt;PreferenceCategory
    ++        android:title="&#64;string/pref_sms_storage_title"
    ++        android:key="pref_key_storage_settings">
    ++        &lt;CheckBoxPreference
    ++            android:key="pref_key_auto_delete"
    ++            android:summary="&#64;string/pref_summary_auto_delete"
    ++            android:title="&#64;string/pref_title_auto_delete"
    ++            android:defaultValue="false"... />
    ++        &lt;Preference
    ++            android:key="pref_key_sms_delete_limit"
    ++            android:dependency="pref_key_auto_delete"
    ++            android:summary="&#64;string/pref_summary_delete_limit"
    ++            android:title="&#64;string/pref_title_sms_delete"... />
    ++        &lt;Preference
    ++            android:key="pref_key_mms_delete_limit"
    ++            android:dependency="pref_key_auto_delete"
    ++            android:summary="&#64;string/pref_summary_delete_limit"
    ++            android:title="&#64;string/pref_title_mms_delete" ... />
    ++    &lt;/PreferenceCategory>
    ++    ...
    ++&lt;/PreferenceScreen>
    ++</pre>
    ++
    ++
    ++<h4 id="Subscreens">Menggunakan sublayar</h4>
    ++
    ++<p>Jika ingin menempatkan grup pengaturan ke dalam sublayar (seperti yang ditampilkan dalam gambar 3), tempatkan grup
    ++objek {@link android.preference.Preference} di dalam {@link
    ++android.preference.PreferenceScreen}.</p>
    ++
    ++<img src="{@docRoot}images/ui/settings/settings-subscreen.png" alt="" />
    ++<p class="img-caption"><strong>Gambar 3.</strong> Mengatur sublayar. Elemen {@code
    ++&lt;PreferenceScreen&gt;}
    ++membuat item yang, bila dipilih, akan membuka daftar terpisah untuk menampilkan pengaturan tersarang.</p>
    ++
    ++<p>Misalnya:</p>
    ++
    ++<pre>
    ++&lt;PreferenceScreen  xmlns:android="http://schemas.android.com/apk/res/android">
    ++    &lt;!-- opens a subscreen of settings -->
    ++    &lt;PreferenceScreen
    ++        android:key="button_voicemail_category_key"
    ++        android:title="&#64;string/voicemail"
    ++        android:persistent="false">
    ++        &lt;ListPreference
    ++            android:key="button_voicemail_provider_key"
    ++            android:title="&#64;string/voicemail_provider" ... />
    ++        &lt;!-- opens another nested subscreen -->
    ++        &lt;PreferenceScreen
    ++            android:key="button_voicemail_setting_key"
    ++            android:title="&#64;string/voicemail_settings"
    ++            android:persistent="false">
    ++            ...
    ++        &lt;/PreferenceScreen>
    ++        &lt;RingtonePreference
    ++            android:key="button_voicemail_ringtone_key"
    ++            android:title="&#64;string/voicemail_ringtone_title"
    ++            android:ringtoneType="notification" ... />
    ++        ...
    ++    &lt;/PreferenceScreen>
    ++    ...
    ++&lt;/PreferenceScreen>
    ++</pre>
    ++
    ++
    ++<h3 id="Intents">Menggunakan intent</h3>
    ++
    ++<p>Dalam beberapa kasus, Anda mungkin ingin item preferensi untuk membuka beberapa aktivitas sebagai ganti
    ++layar pengaturan, seperti browser web untuk melihat halaman web. Untuk memanggil {@link
    ++android.content.Intent} saat pengguna memilih item preferensi, tambahkan elemen {@code &lt;intent&gt;}
    ++sebagai anak dari elemen {@code &lt;Preference&gt;} yang bersangkutan.</p>
    ++
    ++<p>Misalnya, berikut ini cara menggunakan item preferensi untuk membuka halaman web:</p>
    ++
    ++<pre>
    ++&lt;Preference android:title="@string/prefs_web_page" >
    ++    &lt;intent android:action="android.intent.action.VIEW"
    ++            android:data="http://www.example.com" />
    ++&lt;/Preference>
    ++</pre>
    ++
    ++<p>Anda bisa membuat intent implisit maupun eksplisit menggunakan atribut berikut:</p>
    ++
    ++<dl>
    ++  <dt>{@code android:action}</dt>
    ++    <dd>Tindakan yang akan ditetapkan, sesuai metode
    ++{@link android.content.Intent#setAction setAction()}.</dd>
    ++  <dt>{@code android:data}</dt>
    ++    <dd>Data yang akan ditetapkan, sesuai metode {@link android.content.Intent#setData setData()}.</dd>
    ++  <dt>{@code android:mimeType}</dt>
    ++    <dd>Tipe MIME yang akan ditetapkan, sesuai metode
    ++{@link android.content.Intent#setType setType()}.</dd>
    ++  <dt>{@code android:targetClass}</dt>
    ++    <dd>Bagian kelas dari nama komponen, sesuai metode {@link android.content.Intent#setComponent
    ++setComponent()}.</dd>
    ++  <dt>{@code android:targetPackage}</dt>
    ++    <dd>Bagian paket dari nama komponen, sesuai metode {@link
    ++android.content.Intent#setComponent setComponent()}.</dd>
    ++</dl>
    ++
    ++
    ++
    ++<h2 id="Activity">Membuat Aktivitas Preferensi</h2>
    ++
    ++<p>Untuk menampilkan pengaturan Anda dalam suatu aktivitas, perluas kelas {@link
    ++android.preference.PreferenceActivity}. Ini adalah ekstensi dari kelas {@link
    ++android.app.Activity} biasa yang menampilkan daftar pengaturan berdasarkan hierarki objek {@link
    ++android.preference.Preference}. {@link android.preference.PreferenceActivity}
    ++secara otomatis mempertahankan pengaturan yang dikaitkan dengan setiap {@link
    ++android.preference.Preference} bila pengguna membuat perubahan.</p>
    ++
    ++<p class="note"><strong>Catatan:</strong> Jika Anda mengembangkan aplikasi untuk Android 3.0 dan
    ++yang lebih tinggi, sebaiknya gunakan {@link android.preference.PreferenceFragment}. Pindah ke bagian
    ++berikutnya tentang <a href="#Fragment">Menggunakan Fragmen Preferensi</a>.</p>
    ++
    ++<p>Hal paling penting untuk diingat adalah jangan memuat layout tampilan selama callback {@link
    ++android.preference.PreferenceActivity#onCreate onCreate()}. Sebagai gantinya, panggil {@link
    ++android.preference.PreferenceActivity#addPreferencesFromResource addPreferencesFromResource()} untuk
    ++menambahkan preferensi yang telah Anda deklarasikan dalam file XML ke aktivitas. Misalnya, berikut ini adalah kode minimum
    ++polos yang diperlukan untuk {@link android.preference.PreferenceActivity} fungsional:</p>
    ++
    ++<pre>
    ++public class SettingsActivity extends PreferenceActivity {
    ++    &#64;Override
    ++    public void onCreate(Bundle savedInstanceState) {
    ++        super.onCreate(savedInstanceState);
    ++        addPreferencesFromResource(R.xml.preferences);
    ++    }
    ++}
    ++</pre>
    ++
    ++<p>Ini sebenarnya kode yang cukup untuk beberapa aplikasi, karena segera setelah pengguna memodifikasi preferensi,
    ++sistem akan menyimpan perubahan tersebut ke file {@link android.content.SharedPreferences} default yang
    ++bisa dibaca oleh komponen aplikasi Anda lainnya bila Anda perlu memeriksa pengaturan pengguna. Akan tetapi,
    ++banyak aplikasi, yang memerlukan kode lebih sedikit untuk mendengarkan perubahan yang terjadi pada preferensi.
    ++Untuk informasi tentang mendengarkan perubahan di file {@link android.content.SharedPreferences},
    ++lihat bagian tentang <a href="#ReadingPrefs">Preferensi Membaca</a>.</p>
    ++
    ++
    ++
    ++
    ++<h2 id="Fragment">Menggunakan Fragmen Preferensi</h2>
    ++
    ++<p>Jika Anda mengembangkan Android 3.0 (API level 11) dan yang lebih tinggi, Anda harus menggunakan {@link
    ++android.preference.PreferenceFragment} untuk menampilkan daftar objek {@link android.preference.Preference}
    ++Anda. Anda bisa menambahkan {@link android.preference.PreferenceFragment} ke aktivitas apa pun,&mdash;Anda tidak
    ++perlu menggunakan {@link android.preference.PreferenceActivity}.</p>
    ++
    ++<p><a href="{@docRoot}guide/components/fragments.html">Fragmen</a> menyediakan arsitektur yang lebih
    ++fleksibel untuk aplikasi Anda, dibandingkan hanya menggunakan aktivitas, apa pun jenis
    ++aktivitas yang Anda bangun. Dengan sendirinya, kami menyarankan Anda menggunakan {@link
    ++android.preference.PreferenceFragment} untuk mengontrol tampilan pengaturan Anda sebagai ganti {@link
    ++android.preference.PreferenceActivity} bila memungkinkan.</p>
    ++
    ++<p>Implementasi {@link android.preference.PreferenceFragment} Anda bisa semudah
    ++mendefinisikan metode {@link android.preference.PreferenceFragment#onCreate onCreate()} untuk memuat
    ++file preferensi dengan {@link android.preference.PreferenceFragment#addPreferencesFromResource
    ++addPreferencesFromResource()}. Misalnya:</p>
    ++
    ++<pre>
    ++public static class SettingsFragment extends PreferenceFragment {
    ++    &#64;Override
    ++    public void onCreate(Bundle savedInstanceState) {
    ++        super.onCreate(savedInstanceState);
    ++
    ++        // Load the preferences from an XML resource
    ++        addPreferencesFromResource(R.xml.preferences);
    ++    }
    ++    ...
    ++}
    ++</pre>
    ++
    ++<p>Anda nanti bisa menambahkan fragmen ini ke {@link android.app.Activity} seperti yang Anda lakukan untuk
    ++{@link android.app.Fragment} lainnya. Misalnya:</p>
    ++
    ++<pre>
    ++public class SettingsActivity extends Activity {
    ++    &#64;Override
    ++    protected void onCreate(Bundle savedInstanceState) {
    ++        super.onCreate(savedInstanceState);
    ++
    ++        // Display the fragment as the main content.
    ++        getFragmentManager().beginTransaction()
    ++                .replace(android.R.id.content, new SettingsFragment())
    ++                .commit();
    ++    }
    ++}
    ++</pre>
    ++
    ++<p class="note"><strong>Catatan:</strong> {@link android.preference.PreferenceFragment} tidak memiliki
    ++objek {@link android.content.Context} sendiri. Jika memerlukan objek {@link android.content.Context}
    ++, Anda bisa memanggil {@link android.app.Fragment#getActivity()}. Akan tetapi, berhati-hatilah untuk memanggil
    ++{@link android.app.Fragment#getActivity()} hanya bila fragmen telah dikaitkan dengan aktivitas. Bila
    ++fragmen belum dikaitkan, atau terlepas saat akhir daur hidupnya, {@link
    ++android.app.Fragment#getActivity()} akan mengembalikan nol.</p>
    ++
    ++
    ++<h2 id="Defaults">Mengatur Nilai Default</h2>
    ++
    ++<p>Preferensi yang Anda buat mungkin mendefinisikan beberapa perilaku penting untuk aplikasi, jadi Anda
    ++perlu menginisialisasi file {@link android.content.SharedPreferences} yang terkait dengan
    ++nilai default untuk setiap {@link android.preference.Preference} bila pengguna menggunakan aplikasi
    ++Anda untuk pertama kali.</p>
    ++
    ++<p>Hal pertama yang harus Anda lakukan adalah menetapkan nilai default untuk setiap objek {@link
    ++android.preference.Preference}
    ++di file XML Anda menggunakan atribut {@code android:defaultValue}. Nilainya bisa berupa tipe data
    ++apa saja yang sesuai untuk objek {@link android.preference.Preference} bersangkutan. Misalnya:
    ++</p>
    ++
    ++<pre>
    ++&lt;!-- default value is a boolean -->
    ++&lt;CheckBoxPreference
    ++    android:defaultValue="true"
    ++    ... />
    ++
    ++&lt;!-- default value is a string -->
    ++&lt;ListPreference
    ++    android:defaultValue="@string/pref_syncConnectionTypes_default"
    ++    ... />
    ++</pre>
    ++
    ++<p>Kemudian, dari metode {@link android.app.Activity#onCreate onCreate()} dalam aktivitas utama aplikasi
    ++Anda&mdash;dan dalam aktivitas lainnya yang digunakan pengguna untuk masuk ke aplikasi Anda untuk pertama kali
    ++&mdash;panggil {@link android.preference.PreferenceManager#setDefaultValues
    ++setDefaultValues()}:</p>
    ++
    ++<pre>
    ++PreferenceManager.setDefaultValues(this, R.xml.advanced_preferences, false);
    ++</pre>
    ++
    ++<p>Memanggil ini selama {@link android.app.Activity#onCreate onCreate()} akan memastikan aplikasi
    ++Anda diinisialisasi dengan pengaturan default, yang mungkin perlu
    ++dibaca oleh aplikasi Anda untuk menentukan beberapa perilaku (seperti apakah akan mengunduh data pada
    ++jaringan seluler).</p>
    ++
    ++<p>Metode ini membutuhkan tiga argumen:</p>
    ++<ul>
    ++  <li>{@link android.content.Context} aplikasi Anda.</li>
    ++  <li>ID sumber daya untuk file XML preferensi yang ingin Anda atur nilai defaultnya.</li>
    ++  <li>Boolean menunjukkan apakah nilai default harus diatur lebih dari satu kali.
    ++<p>Bila <code>false</code>, sistem akan mengatur nilai default hanya jika metode ini belum pernah
    ++dipanggil sebelumnya (atau {@link android.preference.PreferenceManager#KEY_HAS_SET_DEFAULT_VALUES}
    ++dalam file preferensi berbagi nilai default salah).</p></li>
    ++</ul>
    ++
    ++<p>Selama Anda mengatur argumen ketiga ke <code>false</code>, Anda bisa dengan aman memanggil metode ini
    ++setiap kali aktivitas Anda memulai tanpa mengesampingkan preferensi tersimpan pengguna dengan mengatur ulang preferensi tersebut ke
    ++default. Akan tetapi, jika mengatur ke <code>true</code>, Anda akan mengesampingkan nilai
    ++sebelumnya dengan default.</p>
    ++
    ++
    ++
    ++<h2 id="PreferenceHeaders">Menggunakan Header Preferensi</h2>
    ++
    ++<p>Dalam kasus yang jarang terjadi, Anda mungkin perlu mendesain pengaturan agar layar pertama
    ++hanya menampilkan daftar <a href="#Subscreens">sublayar</a> (seperti dalam aplikasi Setting pada sistem,
    ++seperti yang ditampilkan dalam gambar 4 dan 5). Bila mengembangkan desain seperti itu untuk Android 3.0 dan yang lebih tinggi, Anda
    ++harus menggunakan fitur "header" yang baru di Android 3.0, sebagai ganti membangun sublayar dengan elemen
    ++{@link android.preference.PreferenceScreen} tersarang.</p>
    ++
    ++<p>Untuk membangun pengaturan dengan header, Anda perlu:</p>
    ++<ol>
    ++  <li>Memisahkan setiap grup pengaturan ke dalam instance {@link
    ++android.preference.PreferenceFragment} terpisah. Ini berarti, setiap grup pengaturan memerlukan file XML
    ++terpisah.</li>
    ++  <li>Membuat file header XML yang mencantumkan daftar setiap grup pengaturan dan mendeklarasikan fragmen mana
    ++yang berisi daftar pengaturan yang sesuai.</li>
    ++  <li>Memperluas kelas {@link android.preference.PreferenceActivity} untuk menjadi host pengaturan Anda.</li>
    ++  <li>Mengimplementasikan callback {@link
    ++android.preference.PreferenceActivity#onBuildHeaders onBuildHeaders()} untuk menetapkan file
    ++header.</li>
    ++</ol>
    ++
    ++<p>Manfaat besar dalam menggunakan desain ini adalah karena {@link android.preference.PreferenceActivity}
    ++secara otomatis akan menampilkan layout dua panel yang ditampilkan dalam gambar 4 bila dijalankan pada layar besar.</p>
    ++
    ++<p>Bahkan jika aplikasi Anda mendukung versi Android yang lebih lama dari 3.0, Anda bisa membangun
    ++aplikasi untuk menggunakan {@link android.preference.PreferenceFragment} bagi presentasi dua panel pada perangkat
    ++yang lebih baru sementara tetap mendukung hierarki multilayar biasa pada perangkat
    ++yang lebih lama (lihat bagian tentang <a href="#BackCompatHeaders">Mendukung versi yang lebih lama dengan
    ++header preferensi</a>).</p>
    ++
    ++<img src="{@docRoot}images/ui/settings/settings-headers-tablet.png" alt="" />
    ++<p class="img-caption"><strong>Gambar 4.</strong> Layout dua panel dengan header. <br/><b>1.</b> Header
    ++didefinisikan dengan file header XML. <br/><b>2.</b> Setiap grup pengaturan didefinisikan dengan
    ++{@link android.preference.PreferenceFragment} yang ditetapkan oleh elemen {@code &lt;header&gt;} dalam
    ++file header.</p>
    ++
    ++<img src="{@docRoot}images/ui/settings/settings-headers-handset.png" alt="" />
    ++<p class="img-caption"><strong>Gambar 5.</strong> Perangkat handset dengan header pengaturan. Bila sebuah
    ++item dipilih, {@link android.preference.PreferenceFragment} terkait akan menggantikan
    ++header.</p>
    ++
    ++
    ++<h3 id="CreateHeaders" style="clear:left">Membuat file header</h3>
    ++
    ++<p>Setiap grup pengaturan dalam daftar header Anda akan ditetapkan oleh elemen {@code &lt;header&gt;}
    ++tunggal dalam elemen {@code &lt;preference-headers&gt;} akar. Misalnya:</p>
    ++
    ++<pre>
    ++&lt;?xml version="1.0" encoding="utf-8"?>
    ++&lt;preference-headers xmlns:android="http://schemas.android.com/apk/res/android">
    ++    &lt;header
    ++        android:fragment="com.example.prefs.SettingsActivity$SettingsFragmentOne"
    ++        android:title="@string/prefs_category_one"
    ++        android:summary="@string/prefs_summ_category_one" />
    ++    &lt;header
    ++        android:fragment="com.example.prefs.SettingsActivity$SettingsFragmentTwo"
    ++        android:title="@string/prefs_category_two"
    ++        android:summary="@string/prefs_summ_category_two" >
    ++        &lt;!-- key/value pairs can be included as arguments for the fragment. -->
    ++        &lt;extra android:name="someKey" android:value="someHeaderValue" />
    ++    &lt;/header>
    ++&lt;/preference-headers>
    ++</pre>
    ++
    ++<p>Dengan atribut {@code android:fragment}, setiap header mendeklarasikan instance {@link
    ++android.preference.PreferenceFragment} yang harus terbuka saat pengguna memilih header.</p>
    ++
    ++<p>Elemen {@code &lt;extras&gt;} memungkinkan Anda meneruskan pasangan nilai-kunci ke fragmen di {@link
    ++android.os.Bundle}. Fragmen bisa mengambil argumen dengan memanggil {@link
    ++android.app.Fragment#getArguments()}. Anda bisa meneruskan argumen ke fragmen dengan berbagai
    ++alasan, namun satu alasan yang baik adalah untuk menggunakan kembali subkelas yang sama dari {@link
    ++android.preference.PreferenceFragment} untuk setiap grup dan menggunakan argumen untuk menetapkan file
    ++XML preferensi mana yang harus dimuat fragmen.</p>
    ++
    ++<p>Misalnya, ada fragmen yang bisa digunakan ulang untuk berbagai grup pengaturan, bila setiap
    ++header mendefinisikan argumen {@code &lt;extra&gt;} dengan kunci {@code "settings"}:</p>
    ++
    ++<pre>
    ++public static class SettingsFragment extends PreferenceFragment {
    ++    &#64;Override
    ++    public void onCreate(Bundle savedInstanceState) {
    ++        super.onCreate(savedInstanceState);
    ++
    ++        String settings = getArguments().getString("settings");
    ++        if ("notifications".equals(settings)) {
    ++            addPreferencesFromResource(R.xml.settings_wifi);
    ++        } else if ("sync".equals(settings)) {
    ++            addPreferencesFromResource(R.xml.settings_sync);
    ++        }
    ++    }
    ++}
    ++</pre>
    ++
    ++
    ++
    ++<h3 id="DisplayHeaders">Menampilkan header</h3>
    ++
    ++<p>Untuk menampilkan header preferensi, Anda harus mengimplementasikan metode callback {@link
    ++android.preference.PreferenceActivity#onBuildHeaders onBuildHeaders()} dan memanggil
    ++{@link android.preference.PreferenceActivity#loadHeadersFromResource
    ++loadHeadersFromResource()}. Misalnya:</p>
    ++
    ++<pre>
    ++public class SettingsActivity extends PreferenceActivity {
    ++    &#64;Override
    ++    public void onBuildHeaders(List&lt;Header> target) {
    ++        loadHeadersFromResource(R.xml.preference_headers, target);
    ++    }
    ++}
    ++</pre>
    ++
    ++<p>Bila pengguna memilih item dari daftar header, sistem akan membuka {@link
    ++android.preference.PreferenceFragment} terkait.</p>
    ++
    ++<p class="note"><strong>Catatan:</strong> Saat menggunakan header preferensi, subkelas {@link
    ++android.preference.PreferenceActivity} Anda tidak perlu mengimplementasikan metode {@link
    ++android.preference.PreferenceActivity#onCreate onCreate()}, karena tugas
    ++yang diperlukan untuk aktivitas hanyalah memuat header.</p>
    ++
    ++
    ++<h3 id="BackCompatHeaders">Mendukung versi yang lebih lama dengan header preferensi</h3>
    ++
    ++<p>Jika aplikasi Anda mendukung versi Android yang lebih lama dari 3.0, Anda tetap bisa menggunakan header untuk
    ++menyediakan layout dua panel saat berjalan pada Android 3.0 dan yang lebih tinggi. Anda hanya perlu membuat
    ++file XML preferensi tambahan yang menggunakan elemen {@link android.preference.Preference
    ++&lt;Preference&gt;} dasar yang berperilaku seperti item header (untuk digunakan oleh Android
    ++versi yang lebih lama).</p>
    ++
    ++<p>Akan tetapi, sebagai ganti membuka {@link android.preference.PreferenceScreen} baru, setiap elemen {@link
    ++android.preference.Preference &lt;Preference&gt;} mengirimkan {@link android.content.Intent} ke
    ++{@link android.preference.PreferenceActivity} yang menetapkan file XML preferensi mana yang
    ++akan dimuat.</p>
    ++
    ++<p>Misalnya, ini adalah file XML untuk header preferensi yang menggunakan Android 3.0
    ++dan yang lebih tinggi ({@code res/xml/preference_headers.xml}):</p>
    ++
    ++<pre>
    ++&lt;preference-headers xmlns:android="http://schemas.android.com/apk/res/android">
    ++    &lt;header
    ++        android:fragment="com.example.prefs.SettingsFragmentOne"
    ++        android:title="@string/prefs_category_one"
    ++        android:summary="@string/prefs_summ_category_one" />
    ++    &lt;header
    ++        android:fragment="com.example.prefs.SettingsFragmentTwo"
    ++        android:title="@string/prefs_category_two"
    ++        android:summary="@string/prefs_summ_category_two" />
    ++&lt;/preference-headers>
    ++</pre>
    ++
    ++<p>Dan ini adalah file preferensi yang menyediakan header yang sama untuk versi yang lebih lama dari
    ++Android 3.0 ({@code res/xml/preference_headers_legacy.xml}):</p>
    ++
    ++<pre>
    ++&lt;PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android">
    ++    &lt;Preference
    ++        android:title="@string/prefs_category_one"
    ++        android:summary="@string/prefs_summ_category_one"  >
    ++        &lt;intent
    ++            android:targetPackage="com.example.prefs"
    ++            android:targetClass="com.example.prefs.SettingsActivity"
    ++            android:action="com.example.prefs.PREFS_ONE" />
    ++    &lt;/Preference>
    ++    &lt;Preference
    ++        android:title="@string/prefs_category_two"
    ++        android:summary="@string/prefs_summ_category_two" >
    ++        &lt;intent
    ++            android:targetPackage="com.example.prefs"
    ++            android:targetClass="com.example.prefs.SettingsActivity"
    ++            android:action="com.example.prefs.PREFS_TWO" />
    ++    &lt;/Preference>
    ++&lt;/PreferenceScreen>
    ++</pre>
    ++
    ++<p>Karena dukungan untuk {@code &lt;preference-headers&gt;} telah ditambahkan di Android 3.0, sistem akan memanggil
    ++{@link android.preference.PreferenceActivity#onBuildHeaders onBuildHeaders()} di {@link
    ++android.preference.PreferenceActivity} hanya saat berjalan pada Android 3.0 atau yang lebih tinggi. Untuk memuat
    ++file header "lama" ({@code preference_headers_legacy.xml}), Anda harus memeriksa versi Android
    ++dan, jika versi tersebut lebih lama dari Android 3.0 ({@link
    ++android.os.Build.VERSION_CODES#HONEYCOMB}), panggil {@link
    ++android.preference.PreferenceActivity#addPreferencesFromResource addPreferencesFromResource()} untuk
    ++memuat file header lama. Misalnya:</p>
    ++
    ++<pre>
    ++&#64;Override
    ++public void onCreate(Bundle savedInstanceState) {
    ++    super.onCreate(savedInstanceState);
    ++    ...
    ++
    ++    if (Build.VERSION.SDK_INT &lt; Build.VERSION_CODES.HONEYCOMB) {
    ++        // Load the legacy preferences headers
    ++        addPreferencesFromResource(R.xml.preference_headers_legacy);
    ++    }
    ++}
    ++
    ++// Called only on Honeycomb and later
    ++&#64;Override
    ++public void onBuildHeaders(List&lt;Header> target) {
    ++   loadHeadersFromResource(R.xml.preference_headers, target);
    ++}
    ++</pre>
    ++
    ++<p>Satu-satunya hal yang perlu dilakukan adalah menangani {@link android.content.Intent} yang diteruskan ke
    ++aktivitas untuk mengidentifikasi file preferensi yang akan dimuat. Jadi ambillah tindakan intent dan bandingkan dengan
    ++string tindakan yang diketahui yang telah Anda gunakan dalam tag {@code &lt;intent&gt;} XML preferensi:</p>
    ++
    ++<pre>
    ++final static String ACTION_PREFS_ONE = "com.example.prefs.PREFS_ONE";
    ++...
    ++
    ++&#64;Override
    ++public void onCreate(Bundle savedInstanceState) {
    ++    super.onCreate(savedInstanceState);
    ++
    ++    String action = getIntent().getAction();
    ++    if (action != null &amp;&amp; action.equals(ACTION_PREFS_ONE)) {
    ++        addPreferencesFromResource(R.xml.preferences);
    ++    }
    ++    ...
    ++
    ++    else if (Build.VERSION.SDK_INT &lt; Build.VERSION_CODES.HONEYCOMB) {
    ++        // Load the legacy preferences headers
    ++        addPreferencesFromResource(R.xml.preference_headers_legacy);
    ++    }
    ++}
    ++</pre>
    ++
    ++<p>Ketahuilah bahwa panggilan berturut-turut ke {@link
    ++android.preference.PreferenceActivity#addPreferencesFromResource addPreferencesFromResource()} akan
    ++menumpuk semua preferensi ke dalam satu daftar, jadi pastikan bahwa ini hanya dipanggil sekali dengan mengikatkan syarat
    ++ke pernyataan else-if.</p>
    ++
    ++
    ++
    ++
    ++
    ++<h2 id="ReadingPrefs">Preferensi Membaca</h2>
    ++
    ++<p>Secara default, semua preferensi aplikasi Anda disimpan ke file yang bisa diakses dari mana saja
    ++di dalam aplikasi dengan memanggil metode statis {@link
    ++android.preference.PreferenceManager#getDefaultSharedPreferences
    ++PreferenceManager.getDefaultSharedPreferences()}. Ini akan mengembalikan objek {@link
    ++android.content.SharedPreferences} berisi semua pasangan nilai-kunci yang terkait
    ++dengan objek {@link android.preference.Preference} yang digunakan di {@link
    ++android.preference.PreferenceActivity} Anda.</p>
    ++
    ++<p>Misalnya, inilah cara membaca salah satu nilai preferensi dari aktivitas lain dalam aplikasi
    ++Anda:</p>
    ++
    ++<pre>
    ++SharedPreferences sharedPref = PreferenceManager.getDefaultSharedPreferences(this);
    ++String syncConnPref = sharedPref.getString(SettingsActivity.KEY_PREF_SYNC_CONN, "");
    ++</pre>
    ++
    ++
    ++
    ++<h3 id="Listening">Mendengarkan perubahan preferensi</h3>
    ++
    ++<p>Ada beberapa alasan yang membuat Anda perlu mendapatkan pemberitahuan segera setelah pengguna mengubah salah satu
    ++preferensi. Untuk menerima callback saat perubahan terjadi pada salah satu preferensi,
    ++implementasikan antarmuka {@link android.content.SharedPreferences.OnSharedPreferenceChangeListener
    ++SharedPreference.OnSharedPreferenceChangeListener} dan daftarkan listener untuk objek
    ++{@link android.content.SharedPreferences} dengan memanggil {@link
    ++android.content.SharedPreferences#registerOnSharedPreferenceChangeListener
    ++registerOnSharedPreferenceChangeListener()}.</p>
    ++
    ++<p>Antarmuka hanya memiliki satu metode callback, {@link
    ++android.content.SharedPreferences.OnSharedPreferenceChangeListener#onSharedPreferenceChanged
    ++onSharedPreferenceChanged()}, dan mungkin lebih mudah mengimplementasikan antarmuka sebagai bagian dari
    ++aktivitas Anda. Misalnya:</p>
    ++
    ++<pre>
    ++public class SettingsActivity extends PreferenceActivity
    ++                              implements OnSharedPreferenceChangeListener {
    ++    public static final String KEY_PREF_SYNC_CONN = "pref_syncConnectionType";
    ++    ...
    ++
    ++    public void onSharedPreferenceChanged(SharedPreferences sharedPreferences,
    ++        String key) {
    ++        if (key.equals(KEY_PREF_SYNC_CONN)) {
    ++            Preference connectionPref = findPreference(key);
    ++            // Set summary to be the user-description for the selected value
    ++            connectionPref.setSummary(sharedPreferences.getString(key, ""));
    ++        }
    ++    }
    ++}
    ++</pre>
    ++
    ++<p>Dalam contoh ini, metode akan memeriksa apakah pengaturan yang diubah adalah untuk kunci preferensi yang diketahui. Ini akan
    ++memanggil {@link android.preference.PreferenceActivity#findPreference findPreference()} untuk mendapatkan objek
    ++{@link android.preference.Preference} yang diubah agar bisa memodifikasi rangkuman item
    ++menjadi keterangan pada pilihan pengguna. Ini berarti, bila pengaturan adalah {@link
    ++android.preference.ListPreference} atau pengaturan multipilihan, Anda harus memanggil {@link
    ++android.preference.Preference#setSummary setSummary()} bila pengaturan berubah ke tampilkan
    ++status saat ini (seperti pengaturan Sleep yang ditampilkan dalam gambar 5).</p>
    ++
    ++<p class="note"><strong>Catatan:</strong> Seperti dijelaskan dalam dokumen Desain Android tentang <a href="{@docRoot}design/patterns/settings.html">Pengaturan</a>, kami merekomendasikan Anda untuk memperbarui
    ++rangkuman {@link android.preference.ListPreference} setiap kali pengguna mengubah preferensi untuk
    ++menjelaskan pengaturan saat ini.</p>
    ++
    ++<p>Untuk manajemen daur hidup yang baik di aktivitas, kami merekomendasikan Anda untuk mendaftarkan dan mencabut pendaftaran
    ++{@link android.content.SharedPreferences.OnSharedPreferenceChangeListener} selama callback {@link
    ++android.app.Activity#onResume} dan {@link android.app.Activity#onPause}:</p>
    ++
    ++<pre>
    ++&#64;Override
    ++protected void onResume() {
    ++    super.onResume();
    ++    getPreferenceScreen().getSharedPreferences()
    ++            .registerOnSharedPreferenceChangeListener(this);
    ++}
    ++
    ++&#64;Override
    ++protected void onPause() {
    ++    super.onPause();
    ++    getPreferenceScreen().getSharedPreferences()
    ++            .unregisterOnSharedPreferenceChangeListener(this);
    ++}
    ++</pre>
    ++
    ++<p class="caution"><strong>Perhatian:</strong> Bila Anda memanggil {@link
    ++android.content.SharedPreferences#registerOnSharedPreferenceChangeListener
    ++registerOnSharedPreferenceChangeListener()}, pengelola preferensi saat ini tidak akan
    ++menyimpan referensi kuat ke listener. Anda harus menyimpan referensi
    ++kuat bagi listener, atau referensi akan rentan terhadap pengumpulan sampah. Kami
    ++merekomendasikan Anda untuk mempertahankan referensi bagi listener dalam data instance objek
    ++yang akan ada selama Anda memerlukan listener tersebut.</p>
    ++
    ++<p>Misalnya, dalam kode berikut, caller tidak menyimpan referensi ke
    ++listener. Akibatnya, listener akan dikenakan pengumpulan sampah,
    ++dan suatu saat nanti akan gagal:</p>
    ++
    ++<pre>
    ++prefs.registerOnSharedPreferenceChangeListener(
    ++  // Bad! The listener is subject to garbage collection!
    ++  new SharedPreferences.OnSharedPreferenceChangeListener() {
    ++  public void onSharedPreferenceChanged(SharedPreferences prefs, String key) {
    ++    // listener implementation
    ++  }
    ++});
    ++</pre>
    ++
    ++<p>Sebagai gantinya, simpan referensi ke listener dalam bidang data instance
    ++objek yang akan ada selama listener dibutuhkan:</p>
    ++
    ++<pre>
    ++SharedPreferences.OnSharedPreferenceChangeListener listener =
    ++    new SharedPreferences.OnSharedPreferenceChangeListener() {
    ++  public void onSharedPreferenceChanged(SharedPreferences prefs, String key) {
    ++    // listener implementation
    ++  }
    ++};
    ++prefs.registerOnSharedPreferenceChangeListener(listener);
    ++</pre>
    ++
    ++<h2 id="NetworkUsage">Mengelola Penggunaan Jaringan</h2>
    ++
    ++
    ++<p>Mulai Android 4.0, aplikasi Settings untuk sistem memungkinkan pengguna melihat seberapa besar
    ++data jaringan yang digunakan aplikasi mereka saat berada di latar depan dan latar belakang. Kemudian pengguna bisa
    ++menonaktifkan penggunaan data latar belakang untuk aplikasi individual. Agar pengguna tidak menonaktifkan akses
    ++aplikasi ke data dari latar belakang, Anda harus menggunakan koneksi data secara efisien dan mengizinkan
    ++pengguna untuk menyaring penggunaan data aplikasi melalui pengaturan aplikasi Anda.<p>
    ++
    ++<p>Misalnya, Anda bisa mengizinkan pengguna untuk mengontrol seberapa sering aplikasi menyinkronkan data, apakah aplikasi
    ++hanya melakukan pengunggahan/pengunduhan bila ada Wi-Fi, apakah aplikasi menggunakan data saat roaming, dll. Dengan
    ++tersedianya kontrol ini bagi pengguna, mereka kemungkinan besar tidak akan menonaktifkan akses aplikasi ke data
    ++saat mendekati batas yang mereka tetapkan dalam Settings pada sistem, karena mereka bisa mengontrol secara tepat
    ++seberapa besar data yang digunakan aplikasi Anda.</p>
    ++
    ++<p>Setelah menambahkan preferensi yang diperlukan dalam {@link android.preference.PreferenceActivity} Anda
    ++untuk mengontrol kebiasaan data aplikasi, Anda harus menambahkan filter intent untuk {@link
    ++android.content.Intent#ACTION_MANAGE_NETWORK_USAGE} dalam file manifes Anda. Misalnya:</p>
    ++
    ++<pre>
    ++&lt;activity android:name="SettingsActivity" ... >
    ++    &lt;intent-filter>
    ++       &lt;action android:name="android.intent.action.MANAGE_NETWORK_USAGE" />
    ++       &lt;category android:name="android.intent.category.DEFAULT" />
    ++    &lt;/intent-filter>
    ++&lt;/activity>
    ++</pre>
    ++
    ++<p>Filter intent ini menunjukkan pada sistem bahwa ini adalah aktivitas yang mengontrol penggunaan
    ++data aplikasi Anda. Jadi, saat pengguna memeriksa seberapa banyak data yang digunakan oleh aplikasi dari
    ++aplikasi Settings pada sistem, tombol <em>View application settings</em> akan tersedia dan menjalankan
    ++{@link android.preference.PreferenceActivity} sehingga pengguna bisa menyaring seberapa besar data yang digunakan
    ++aplikasi Anda.</p>
    ++
    ++
    ++
    ++
    ++
    ++
    ++
    ++<h2 id="Custom">Membangun Preferensi Custom</h2>
    ++
    ++<p>Kerangka kerja Android menyertakan berbagai subkelas {@link android.preference.Preference} yang
    ++memungkinkan Anda membangun UI untuk beberapa macam tipe pengaturan.
    ++Akan tetapi, Anda mungkin menemukan pengaturan yang diperlukan bila tidak ada solusi bawaan, seperti
    ++picker nomor atau picker tanggal. Dalam hal demikian, Anda akan perlu membuat preferensi custom dengan memperluas
    ++kelas {@link android.preference.Preference} atau salah satu subkelas lainnya.</p>
    ++
    ++<p>Bila memperluas kelas {@link android.preference.Preference}, ada beberapa hal
    ++penting yang perlu Anda lakukan:</p>
    ++
    ++<ul>
    ++  <li>Menetapkan antarmuka pengguna yang akan muncul saat pengguna memilih pengaturan.</li>
    ++  <li>Menyimpan nilai pengaturan bila perlu.</li>
    ++  <li>Menginisialisasi {@link android.preference.Preference} dengan nilai saat ini (atau default)
    ++bila muncul di tampilan.</li>
    ++  <li>Menyediakan nilai default bila diminta oleh sistem.</li>
    ++  <li>Jika {@link android.preference.Preference} menyediakan UI sendiri (seperti dialog), simpan
    ++dan pulihkan status untuk menangani perubahan daur hidup (seperti saat pengguna memutar layar).</li>
    ++</ul>
    ++
    ++<p>Bagian berikut menjelaskan cara melakukan setiap tugas ini.</p>
    ++
    ++
    ++
    ++<h3 id="CustomSelected">Menetapkan antarmuka pengguna</h3>
    ++
    ++  <p>Jika secara langsung memperluas kelas {@link android.preference.Preference}, Anda perlu mengimplementasikan
    ++{@link android.preference.Preference#onClick()} untuk mendefinisikan tindakan yang terjadi bila pengguna
    ++memilih item tersebut. Akan tetapi, sebagian besar pengaturan custom memperluas {@link android.preference.DialogPreference} untuk
    ++menampilkan dialog, sehingga menyederhanakan prosedur. Bila memperluas {@link
    ++android.preference.DialogPreference}, Anda harus memanggil {@link
    ++android.preference.DialogPreference#setDialogLayoutResource setDialogLayoutResourcs()} selama di
    ++konstruktor kelas untuk menetapkan layout dialog.</p>
    ++
    ++  <p>Misalnya, beri ini konstruktor untuk {@link
    ++android.preference.DialogPreference} custom yang mendeklarasikan layout dan menetapkan teks untuk tombol dialog
    ++negatif dan positif default:</p>
    ++
    ++<pre>
    ++public class NumberPickerPreference extends DialogPreference {
    ++    public NumberPickerPreference(Context context, AttributeSet attrs) {
    ++        super(context, attrs);
    ++
    ++        setDialogLayoutResource(R.layout.numberpicker_dialog);
    ++        setPositiveButtonText(android.R.string.ok);
    ++        setNegativeButtonText(android.R.string.cancel);
    ++
    ++        setDialogIcon(null);
    ++    }
    ++    ...
    ++}
    ++</pre>
    ++
    ++
    ++
    ++<h3 id="CustomSave">Menyimpan nilai pengaturan</h3>
    ++
    ++<p>Anda bisa menyimpan nilai pengaturan kapan saja dengan memanggil salah satu metode {@code persist*()} kelas {@link
    ++android.preference.Preference}, seperti {@link
    ++android.preference.Preference#persistInt persistInt()} jika nilai pengaturan adalah integer atau
    ++{@link android.preference.Preference#persistBoolean persistBoolean()} untuk menyimpan boolean.</p>
    ++
    ++<p class="note"><strong>Catatan:</strong> Setiap {@link android.preference.Preference} hanya bisa menyimpan satu
    ++tipe data, jadi Anda harus menggunakan metode {@code persist*()} yang tepat untuk tipe data yang digunakan
    ++oleh {@link android.preference.Preference} custom Anda.</p>
    ++
    ++<p>Bila Anda memilih untuk mempertahankannya, pengaturan bisa bergantung pada kelas {@link
    ++android.preference.Preference} yang Anda perluas. Jika Anda memperluas {@link
    ++android.preference.DialogPreference}, maka Anda harus mempertahankan nilai hanya jika dialog
    ++tertutup karena hasil positif (pengguna memilih tombol "OK").</p>
    ++
    ++<p>Bila {@link android.preference.DialogPreference} tertutup, sistem akan memanggil metode {@link
    ++android.preference.DialogPreference#onDialogClosed onDialogClosed()}. Metode mencakup argumen
    ++boolean yang menetapkan apakah hasil pengguna "positif"&mdash;jika nilainya
    ++<code>true</code>, maka pengguna memilih tombol positif dan Anda harus menyimpan nilai baru. Misalnya:
    ++</p>
    ++
    ++<pre>
    ++&#64;Override
    ++protected void onDialogClosed(boolean positiveResult) {
    ++    // When the user selects "OK", persist the new value
    ++    if (positiveResult) {
    ++        persistInt(mNewValue);
    ++    }
    ++}
    ++</pre>
    ++
    ++<p>Dalam contoh ini, <code>mNewValue</code> adalah anggota kelas yang menampung nilai
    ++pengaturan saat ini. Memanggil {@link android.preference.Preference#persistInt persistInt()} akan menyimpan nilai
    ++ke file {@link android.content.SharedPreferences} (secara otomatis menggunakan kunci yang
    ++ditetapkan dalam file XML untuk {@link android.preference.Preference} ini).</p>
    ++
    ++
    ++<h3 id="CustomInitialize">Menginisialisasi nilai saat ini</h3>
    ++
    ++<p>Bila sistem menambahkan {@link android.preference.Preference} Anda ke layar, ia
    ++akan memanggil {@link android.preference.Preference#onSetInitialValue onSetInitialValue()} untuk memberi tahu
    ++Anda apakah pengaturan memiliki nilai yang dipertahankan. Jika tidak ada nilai yang dipertahankan, panggilan ini
    ++akan menyediakan nilai default bagi Anda.</p>
    ++
    ++<p>Metode {@link android.preference.Preference#onSetInitialValue onSetInitialValue()} akan meneruskan
    ++boolean, <code>restorePersistedValue</code>, untuk menunjukkan apakah nilai dipertahankan
    ++untuk pengaturan. Jika <code>true</code>, maka Anda harus mengambil nilai yang dipertahankan dengan memanggil
    ++salah satu metode {@code getPersisted*()} kelas {@link
    ++android.preference.Preference}, seperti {@link
    ++android.preference.Preference#getPersistedInt getPersistedInt()} untuk nilai integer. Anda biasanya
    ++perlu mengambil nilai yang dipertahankan agar bisa memperbarui UI dengan benar untuk merefleksikan
    ++nilai yang tersimpan sebelumnya.</p>
    ++
    ++<p>Jika <code>restorePersistedValue</code> adalah <code>false</code>, maka Anda
    ++harus menggunakan nilai default yang diteruskan dalam argumen kedua.</p>
    ++
    ++<pre>
    ++&#64;Override
    ++protected void onSetInitialValue(boolean restorePersistedValue, Object defaultValue) {
    ++    if (restorePersistedValue) {
    ++        // Restore existing state
    ++        mCurrentValue = this.getPersistedInt(DEFAULT_VALUE);
    ++    } else {
    ++        // Set default state from the XML attribute
    ++        mCurrentValue = (Integer) defaultValue;
    ++        persistInt(mCurrentValue);
    ++    }
    ++}
    ++</pre>
    ++
    ++<p>Setiap metode {@code getPersisted*()} memerlukan argumen yang menetapkan
    ++nilai default untuk digunakan jika tidak ada nilai yang dipertahankan atau kunci tidak ada. Dalam contoh
    ++di atas, konstanta lokal yang digunakan untuk menetapkan nilai default dalam kasus {@link
    ++android.preference.Preference#getPersistedInt getPersistedInt()} tidak bisa mengembalikan nilai yang dipertahankan.</p>
    ++
    ++<p class="caution"><strong>Perhatian:</strong> Anda <strong>tidak bisa</strong> menggunakan
    ++<code>defaultValue</code> sebagai nilai default dalam metode {@code getPersisted*()}, karena
    ++nilainya selalu nol bila <code>restorePersistedValue</code> adalah <code>true</code>.</p>
    ++
    ++
    ++<h3 id="CustomDefault">Menyediakan nilai default</h3>
    ++
    ++<p>Jika instance kelas {@link android.preference.Preference} Anda menetapkan nilai default
    ++(dengan atribut {@code android:defaultValue}), maka
    ++sistem akan memanggil {@link android.preference.Preference#onGetDefaultValue
    ++onGetDefaultValue()} bila membuat instance objek untuk mengambil nilai. Anda harus mengimplementasikan
    ++metode ini agar sistem bisa menyimpan nilai default dalam {@link
    ++android.content.SharedPreferences}. Misalnya:</p>
    ++
    ++<pre>
    ++&#64;Override
    ++protected Object onGetDefaultValue(TypedArray a, int index) {
    ++    return a.getInteger(index, DEFAULT_VALUE);
    ++}
    ++</pre>
    ++
    ++<p>Argumen metode menyediakan semua hal yang Anda perlukan: larik atribut dan posisi
    ++indeks dari {@code android:defaultValue}, yang harus Anda ambil. Alasan Anda harus
    ++mengimplementasikan metode ini untuk mengekstrak nilai default dari atribut adalah karena Anda harus menetapkan
    ++nilai default lokal untuk atribut jika nilai tidak didefinisikan.</p>
    ++
    ++
    ++
    ++<h3 id="CustomSaveState">Menyimpan dan memulihkan status Preferensi</h3>
    ++
    ++<p>Seperti halnya {@link android.view.View} di layout, subkelas {@link android.preference.Preference}
    ++Anda bertanggung jawab menyimpan dan memulihkan statusnya jika aktivitas atau fragmen
    ++di-restart (seperti saat pengguna memutar layar). Untuk menyimpan
    ++dan memulihkan status kelas {@link android.preference.Preference} dengan benar, Anda harus mengimplementasikan
    ++metode callback daur hidup {@link android.preference.Preference#onSaveInstanceState
    ++onSaveInstanceState()} dan {@link
    ++android.preference.Preference#onRestoreInstanceState onRestoreInstanceState()}.</p>
    ++
    ++<p>Status {@link android.preference.Preference} Anda didefinisikan oleh objek yang mengimplementasikan
    ++antarmuka {@link android.os.Parcelable}. Kerangka kerja Android menyediakan objek seperti itu untuk Anda gunakan
    ++sebagai titik mulai untuk mendefinisikan objek status Anda: kelas {@link
    ++android.preference.Preference.BaseSavedState}.</p>
    ++
    ++<p>Untuk mendefinisikan cara kelas {@link android.preference.Preference} menyimpan statusnya, Anda harus
    ++memperluas kelas {@link android.preference.Preference.BaseSavedState}. Anda hanya perlu mengesampingkan
    ++ beberapa metode dan mendefinisikan objek {@link android.preference.Preference.BaseSavedState#CREATOR}
    ++.</p>
    ++
    ++<p>Untuk sebagian besar aplikasi, Anda bisa menyalin implementasi berikut dan cukup mengubah baris yang
    ++menangani {@code value} jika subkelas {@link android.preference.Preference} Anda menyimpan tipe
    ++data selain integer.</p>
    ++
    ++<pre>
    ++private static class SavedState extends BaseSavedState {
    ++    // Member that holds the setting's value
    ++    // Change this data type to match the type saved by your Preference
    ++    int value;
    ++
    ++    public SavedState(Parcelable superState) {
    ++        super(superState);
    ++    }
    ++
    ++    public SavedState(Parcel source) {
    ++        super(source);
    ++        // Get the current preference's value
    ++        value = source.readInt();  // Change this to read the appropriate data type
    ++    }
    ++
    ++    &#64;Override
    ++    public void writeToParcel(Parcel dest, int flags) {
    ++        super.writeToParcel(dest, flags);
    ++        // Write the preference's value
    ++        dest.writeInt(value);  // Change this to write the appropriate data type
    ++    }
    ++
    ++    // Standard creator object using an instance of this class
    ++    public static final Parcelable.Creator&lt;SavedState> CREATOR =
    ++            new Parcelable.Creator&lt;SavedState>() {
    ++
    ++        public SavedState createFromParcel(Parcel in) {
    ++            return new SavedState(in);
    ++        }
    ++
    ++        public SavedState[] newArray(int size) {
    ++            return new SavedState[size];
    ++        }
    ++    };
    ++}
    ++</pre>
    ++
    ++<p>Dengan implementasi {@link android.preference.Preference.BaseSavedState} di atas yang ditambahkan
    ++ke aplikasi Anda (biasanya sebagai subkelas dari subkelas {@link android.preference.Preference}), Anda
    ++nanti perlu mengimplementasikan metode {@link android.preference.Preference#onSaveInstanceState
    ++onSaveInstanceState()} dan {@link
    ++android.preference.Preference#onRestoreInstanceState onRestoreInstanceState()} untuk subkelas
    ++{@link android.preference.Preference} Anda.</p>
    ++
    ++<p>Misalnya:</p>
    ++
    ++<pre>
    ++&#64;Override
    ++protected Parcelable onSaveInstanceState() {
    ++    final Parcelable superState = super.onSaveInstanceState();
    ++    // Check whether this Preference is persistent (continually saved)
    ++    if (isPersistent()) {
    ++        // No need to save instance state since it's persistent,
    ++        // use superclass state
    ++        return superState;
    ++    }
    ++
    ++    // Create instance of custom BaseSavedState
    ++    final SavedState myState = new SavedState(superState);
    ++    // Set the state's value with the class member that holds current
    ++    // setting value
    ++    myState.value = mNewValue;
    ++    return myState;
    ++}
    ++
    ++&#64;Override
    ++protected void onRestoreInstanceState(Parcelable state) {
    ++    // Check whether we saved the state in onSaveInstanceState
    ++    if (state == null || !state.getClass().equals(SavedState.class)) {
    ++        // Didn't save the state, so call superclass
    ++        super.onRestoreInstanceState(state);
    ++        return;
    ++    }
    ++
    ++    // Cast state to custom BaseSavedState and pass to superclass
    ++    SavedState myState = (SavedState) state;
    ++    super.onRestoreInstanceState(myState.getSuperState());
    ++
    ++    // Set this Preference's widget to reflect the restored state
    ++    mNumberPicker.setValue(myState.value);
    ++}
    ++</pre>
    ++
    +diff --git a/docs/html-intl/intl/id/guide/topics/ui/ui-events.jd b/docs/html-intl/intl/id/guide/topics/ui/ui-events.jd
    +new file mode 100644
    +index 0000000..0307b34
    +--- /dev/null
    ++++ b/docs/html-intl/intl/id/guide/topics/ui/ui-events.jd
    +@@ -0,0 +1,291 @@
    ++page.title=Kejadian Input
    ++parent.title=Antarmuka Pengguna
    ++parent.link=index.html
    ++@jd:body
    ++
    ++<div id="qv-wrapper">
    ++<div id="qv">
    ++  <h2>Dalam dokumen ini</h2>
    ++  <ol>
    ++    <li><a href="#EventListeners">Event Listener</a></li>
    ++    <li><a href="#EventHandlers">Event Handler</a></li>
    ++    <li><a href="#TouchMode">Mode Sentuh</a></li>
    ++    <li><a href="#HandlingFocus">Menangani Fokus</a></li>
    ++  </ol>
    ++
    ++</div>
    ++</div>
    ++
    ++<p>Di Android, ada lebih dari satu cara untuk mencegat kejadian dari interaksi pengguna dengan aplikasi Anda.
    ++Saat mempertimbangkan kejadian dalam antarmuka pengguna Anda, pendekatannya adalah menangkap kejadian
    ++dari objek View tertentu yang digunakan pengguna untuk berinteraksi. Kelas View menyediakan sarana untuk melakukannya.</p>
    ++
    ++<p>Dalam berbagai kelas View yang akan digunakan untuk menyusun layout, Anda mungkin melihat beberapa metode callback
    ++publik yang tampak berguna untuk kejadian UI. Metode ini dipanggil oleh kerangka kerja Android ketika masing-masing
    ++tindakan terjadi pada objek itu. Misalnya, bila View (seperti Button/Tombol) disentuh,
    ++metode <code>onTouchEvent()</code> akan dipanggil pada objek itu. Akan tetapi, untuk mencegatnya, Anda harus memperluas
    ++kelas dan mengesampingkan metode itu. Akan tetapi, memperluas setiap objek View
    ++untuk menangani kejadian seperti itu tidaklah praktis. Karena itulah kelas View juga berisi
    ++sekumpulan antarmuka tersarang dengan callback yang jauh lebih mudah didefinisikan. Antarmuka ini,
    ++yang disebut <a href="#EventListeners">event listener</a>, merupakan tiket Anda untuk menangkap interaksi pengguna dengan UI.</p>
    ++
    ++<p>Walaupun Anda akan lebih sering menggunakan event listener ini untuk interaksi pengguna,
    ++mungkin ada saatnya Anda ingin memperluas kelas View, untuk membuat komponen custom.
    ++Mungkin Anda ingin memperluas kelas {@link android.widget.Button}
    ++untuk membuat sesuatu yang lebih menarik. Dalam hal ini, Anda akan dapat mendefinisikan perilaku kejadian default untuk kelas Anda dengan menggunakan
    ++kelas <a href="#EventHandlers">event handler</a>.</p>
    ++
    ++
    ++<h2 id="EventListeners">Event Listener</h2>
    ++
    ++<p>Event listener merupakan antarmuka di kelas {@link android.view.View} yang berisi metode
    ++callback tunggal. Metode ini akan dipanggil oleh kerangka kerja Android bila View yang
    ++telah didaftarkan dengan listener dipicu oleh interaksi pengguna dengan item dalam UI.</p>
    ++
    ++<p>Yang juga disertakan dalam antarmuka event listener adalah metode callback berikut ini:</p>
    ++
    ++<dl>
    ++  <dt><code>onClick()</code></dt>
    ++    <dd>Dari {@link android.view.View.OnClickListener}.
    ++    Ini dipanggil baik saat pengguna menyentuh item
    ++ (bila dalam mode sentuh), maupun memfokuskan pada item dengan tombol navigasi atau trackball dan
    ++menekan tombol "enter" yang sesuai atau menekan trackball.</dd>
    ++  <dt><code>onLongClick()</code></dt>
    ++    <dd>Dari {@link android.view.View.OnLongClickListener}.
    ++    Ini dipanggil baik saat pengguna menyentuh dan menahan item (bila dalam mode sentuh),
    ++maupun memfokuskan pada item dengan tombol navigasi atau trackball dan
    ++menekan serta menahan tombol "enter" yang sesuai atau menekan dan menahan trackball (selama satu detik).</dd>
    ++  <dt><code>onFocusChange()</code></dt>
    ++    <dd>Dari {@link android.view.View.OnFocusChangeListener}.
    ++    Ini dipanggil saat pengguna menyusuri ke atau dari item, dengan menggunakan tombol navigasi atau trackball.</dd>
    ++  <dt><code>onKey()</code></dt>
    ++    <dd>Dari {@link android.view.View.OnKeyListener}.
    ++    Ini dipanggil saat pengguna memfokuskan pada item dan menekan atau melepas tombol fisik pada perangkat.</dd>
    ++  <dt><code>onTouch()</code></dt>
    ++    <dd>Dari {@link android.view.View.OnTouchListener}.
    ++    Ini dipanggil saat pengguna melakukan tindakan yang digolongkan sebagai kejadian sentuh, termasuk penekanan, pelepasan,
    ++atau gerak perpindahan pada layar (dalam batasan item itu).</dd>
    ++  <dt><code>onCreateContextMenu()</code></dt>
    ++    <dd>Dari {@link android.view.View.OnCreateContextMenuListener}.
    ++    Ini dipanggil saat Menu Konteks sedang dibuat (akibat "klik lama" terus-menerus). Lihat diskusi
    ++tentang menu konteks di panduan pengembang <a href="{@docRoot}guide/topics/ui/menus.html#context-menu">Menu</a>.
    ++</dd>
    ++</dl>
    ++
    ++<p>Metode ini satu-satunya yang menempati antarmukanya masing-masing. Untuk mendefinisikan salah satu metode ini
    ++dan menangani kejadian Anda, implementasikan antarmuka tersarang dalam Aktivitas Anda atau definisikan sebagai kelas anonim.
    ++Kemudian, teruskan satu
    ++instance implementasi Anda pada masing-masing metode <code>View.set...Listener()</code>. (Misalnya, panggil
    ++<code>{@link android.view.View#setOnClickListener(View.OnClickListener) setOnClickListener()}</code>
    ++dan teruskan implementasi {@link android.view.View.OnClickListener OnClickListener} Anda.)</p>
    ++
    ++<p>Contoh di bawah menunjukkan cara mendaftarkan on-click listener untuk Button. </p>
    ++
    ++<pre>
    ++// Create an anonymous implementation of OnClickListener
    ++private OnClickListener mCorkyListener = new OnClickListener() {
    ++    public void onClick(View v) {
    ++      // do something when the button is clicked
    ++    }
    ++};
    ++
    ++protected void onCreate(Bundle savedValues) {
    ++    ...
    ++    // Capture our button from layout
    ++    Button button = (Button)findViewById(R.id.corky);
    ++    // Register the onClick listener with the implementation above
    ++    button.setOnClickListener(mCorkyListener);
    ++    ...
    ++}
    ++</pre>
    ++
    ++<p>Anda juga akan merasa lebih praktis mengimplementasikan OnClickListener sebagai bagian dari Aktivitas.
    ++Ini akan menghindari beban kelas ekstra dan alokasi objek. Misalnya:</p>
    ++<pre>
    ++public class ExampleActivity extends Activity implements OnClickListener {
    ++    protected void onCreate(Bundle savedValues) {
    ++        ...
    ++        Button button = (Button)findViewById(R.id.corky);
    ++        button.setOnClickListener(this);
    ++    }
    ++
    ++    // Implement the OnClickListener callback
    ++    public void onClick(View v) {
    ++      // do something when the button is clicked
    ++    }
    ++    ...
    ++}
    ++</pre>
    ++
    ++<p>Perhatikan bahwa callback <code>onClick()</code> dalam contoh di atas tidak memiliki
    ++nilai hasil, namun beberapa metode event listener lainnya harus mengembalikan boolean. Sebabnya
    ++bergantung pada kejadian. Untuk sebagian yang mengembalikan boolean, ini sebabnya:</p>
    ++<ul>
    ++  <li><code>{@link android.view.View.OnLongClickListener#onLongClick(View) onLongClick()}</code> -
    ++    Ini mengembalikan boolean untuk menunjukkan apakah Anda telah menggunakan kejadian dan tidak boleh dibawa lebih jauh.
    ++    Yaitu, mengembalikan <em>benar</em> untuk menunjukkan apakah Anda telah menangani kejadian dan semestinya berhenti di sini;
    ++    mengembalikan <em>salah</em> jika Anda tidak menanganinya dan/atau kejadian semestinya berlanjut ke
    ++    on-click listener lainnya.</li>
    ++  <li><code>{@link android.view.View.OnKeyListener#onKey(View,int,KeyEvent) onKey()}</code> -
    ++    Ini mengembalikan boolean untuk menunjukkan apakah Anda telah menggunakan kejadian dan tidak boleh dibawa lebih jauh.
    ++    Yaitu, mengembalikan <em>benar</em> untuk menunjukkan apakah Anda telah menangani kejadian dan semestinya berhenti di sini;
    ++    mengembalikan <em>salah</em> jika Anda tidak menanganinya dan/atau kejadian semestinya berlanjut ke
    ++    on-key listener lainnya.</li>
    ++  <li><code>{@link android.view.View.OnTouchListener#onTouch(View,MotionEvent) onTouch()}</code> -
    ++    Ini mengembalikan boolean untuk menunjukkan apakah listener Anda telah menggunakan kejadian ini. Yang penting adalah
    ++kejadian ini bisa memiliki beberapa tindakan yang saling mengikuti. Jadi, jika Anda mengembalikan <em>salah</em>saat
    ++kejadian tindakan turun diterima, itu menunjukkan bahwa Anda belum menggunakan kejadian itu dan juga
    ++tidak tertarik dengan tindakan berikutnya dari kejadian ini. Karena itu, Anda tidak akan diminta untuk melakukan tindakan
    ++ lainnya dalam kejadian, seperti gerakan jari, atau kejadian tindakan naik yang akan terjadi.</li>
    ++</ul>
    ++
    ++<p>Ingatlah bahwa kejadian tombol fisik selalu disampaikan ke View yang sedang difokus. Kejadian ini dikirim mulai dari atas
    ++hierarki View, kemudian turun hingga tujuan yang sesuai. Jika View Anda (atau anak View Anda)
    ++saat ini sedang fokus, maka Anda dapat melihat kejadian berpindah melalui metode.<code>{@link android.view.View#dispatchKeyEvent(KeyEvent)
    ++dispatchKeyEvent()}</code> Sebagai pengganti untuk menangkap kejadian penting melalui View, Anda juga dapat menerima
    ++semua kejadian dalam Aktivitas Anda dengan <code>{@link android.app.Activity#onKeyDown(int,KeyEvent) onKeyDown()}</code>
    ++dan <code>{@link android.app.Activity#onKeyUp(int,KeyEvent) onKeyUp()}</code>.</p>
    ++
    ++<p>Selain itu, saat memikirkan tentang input teks aplikasi Anda, ingatlah bahwa banyak perangkat yang hanya memiliki
    ++metode input perangkat lunak. Metode seperti itu tidak harus berbasis tombol; sebagian mungkin menggunakan input suara, tulisan tangan, dan seterusnya. Meskipun
    ++metode input menyajikan antarmuka seperti keyboard, itu umumnya <strong>tidak</strong> memicu keluarga kejadian
    ++<code>{@link android.app.Activity#onKeyDown(int,KeyEvent) onKeyDown()}</code>. Anda sama sekali tidak boleh
    ++membangun UI yang mengharuskan penekanan tombol tertentu dikontrol kecuali jika Anda ingin membatasi aplikasi Anda pada perangkat yang memiliki
    ++keyboard fisik. Khususnya, jangan mengandalkan metode ini untuk memvalidasi input saat pengguna menekan tombol
    ++enter; melainkan, gunakan tindakan seperti {@link android.view.inputmethod.EditorInfo#IME_ACTION_DONE} untuk menandai
    ++metode input mengenai reaksi yang diharapkan aplikasi Anda, sehingga bisa mengubah UI-nya secara signifikan. Hindari anggapan
    ++tentang bagaimana metode input perangkat lunak seharusnya bekerja dan percayalah bahwa metode akan menyediakan teks yang sudah diformat bagi aplikasi Anda.</p>
    ++
    ++<p class="note"><strong>Catatan:</strong> Android akan memanggil event handler terlebih dahulu kemudian handler
    ++default yang sesuai dari definisi kelas. Karena itu, mengembalikan <em>benar</em> dari event listener ini akan menghentikan
    ++penyebaran kejadian ke event listener lain dan juga akan memblokir callback ke
    ++event handler default di View. Pastikan bahwa Anda ingin mengakhiri kejadian saat mengembalikan <em>true</em>.</p>
    ++
    ++
    ++<h2 id="EventHandlers">Event Handler</h2>
    ++
    ++<p>Jika Anda membuat komponen custom dari View, maka Anda dapat mendefinisikan penggunaan beberapa
    ++metode callback sebagai event handler default.
    ++Dalam dokumen tentang <a href="{@docRoot}guide/topics/ui/custom-components.html">Komponen
    ++Custom</a>, Anda akan melihat penggunaan beberapa callback umum untuk penanganan kejadian,
    ++termasuk:</p>
    ++<ul>
    ++  <li><code>{@link  android.view.View#onKeyDown}</code> - Dipanggil bila terjadi kejadian tombol baru.</li>
    ++  <li><code>{@link  android.view.View#onKeyUp}</code> - Dipanggil bila terjadi kejadian tombol naik.</li>
    ++  <li><code>{@link  android.view.View#onTrackballEvent}</code> - Dipanggil bila terjadi kejadian gerakan trackball.</li>
    ++  <li><code>{@link  android.view.View#onTouchEvent}</code> - Dipanggil bila terjadi kejadian gerakan layar sentuh.</li>
    ++  <li><code>{@link  android.view.View#onFocusChanged}</code> - Dipanggil bila View memperoleh atau kehilangan fokus.</li>
    ++</ul>
    ++<p>Ada beberapa metode lain yang harus Anda ketahui, yang bukan bagian dari kelas View,
    ++namun bisa berdampak langsung pada kemampuan Anda menangani kejadian. Jadi, saat mengelola kejadian yang lebih kompleks dalam
    ++layout, pertimbangkanlah metode-metode lain ini:</p>
    ++<ul>
    ++  <li><code>{@link  android.app.Activity#dispatchTouchEvent(MotionEvent)
    ++    Activity.dispatchTouchEvent(MotionEvent)}</code> - Ini memungkinkan {@link
    ++    android.app.Activity} Anda mencegat semua kejadian sentuh sebelum dikirim ke jendela.</li>
    ++  <li><code>{@link  android.view.ViewGroup#onInterceptTouchEvent(MotionEvent)
    ++    ViewGroup.onInterceptTouchEvent(MotionEvent)}</code> - Ini memungkinkan {@link
    ++    android.view.ViewGroup} memantau kejadian saat dikirim ke View anak.</li>
    ++  <li><code>{@link  android.view.ViewParent#requestDisallowInterceptTouchEvent(boolean)
    ++    ViewParent.requestDisallowInterceptTouchEvent(boolean)}</code> - Panggil ini
    ++    pada View induk untuk menunjukan larangan mencegat kejadian sentuh dengan <code>{@link
    ++    android.view.ViewGroup#onInterceptTouchEvent(MotionEvent)}</code>.</li>
    ++</ul>
    ++
    ++<h2 id="TouchMode">Mode Sentuh</h2>
    ++<p>
    ++Saat pengguna menyusuri antarmuka pengguna dengan tombol pengarah atau trackball, Anda
    ++perlu memberikan fokus pada item tindakan (seperti tombol) agar pengguna bisa mengetahui apa
    ++yang akan menerima input.  Akan tetapi jika perangkat memiliki kemampuan sentuh, dan pengguna
    ++mulai berinteraksi dengan antarmuka dengan menyentuhnya, maka Anda tidak perlu lagi
    ++menyorot item, atau memfokuskan pada View tertentu.  Karena itu, ada mode
    ++untuk interaksi yang bernama "mode sentuh".
    ++</p>
    ++<p>
    ++Untuk perangkat berkemampuan sentuh, setelah pengguna menyentuh layar, perangkat
    ++akan masuk ke mode sentuh.  Dari sini dan selanjutnya, hanya View dengan
    ++{@link android.view.View#isFocusableInTouchMode} benar yang akan dapat difokus, seperti widget pengedit teks.
    ++View lain yang dapat disentuh, seperti tombol, tidak akan difokus bila disentuh; View ini akan
    ++langsung memicu on-click listener bila ditekan.
    ++</p>
    ++<p>
    ++Kapan saja pengguna menekan tombol pengarah atau menggulir dengan trackball, perangkat akan
    ++keluar dari mode sentuh, dan mencari tampilan untuk difokuskan. Kini pengguna bisa melanjutkan interaksi
    ++dengan antarmuka pengguna tanpa menyentuh layar.
    ++</p>
    ++<p>
    ++Status mode sentuh dipertahankan di seluruh sistem (semua jendela dan aktivitas).
    ++Untuk query status saat ini, Anda bisa memanggil
    ++{@link android.view.View#isInTouchMode} untuk mengetahui apakah perangkat saat ini sedang dalam mode sentuh.
    ++</p>
    ++
    ++
    ++<h2 id="HandlingFocus">Menangani Fokus</h2>
    ++
    ++<p>Kerangka kerja ini akan menangani gerakan fokus rutin sebagai respons input pengguna.
    ++Ini termasuk mengubah fokus saat View dihapus atau disembunyikan, atau saat tersedia View
    ++baru. View menunjukkan kesediaannya untuk mengambil fokus
    ++melalui metode <code>{@link android.view.View#isFocusable()}</code>. Untuk mengubah apakah View bisa mengambil
    ++fokus, panggil <code>{@link android.view.View#setFocusable(boolean) setFocusable()}</code>.  Saat dalam mode sentuh,
    ++Anda dapat me-query apakah View memungkinkan fokus dengan <code>{@link android.view.View#isFocusableInTouchMode()}</code>.
    ++Anda bisa mengubahnya dengan <code>{@link android.view.View#setFocusableInTouchMode(boolean) setFocusableInTouchMode()}</code>.
    ++</p>
    ++
    ++<p>Gerakan fokus berdasarkan pada algoritma yang mencari tetangga terdekat dalam
    ++arah yang diberikan. Dalam kasus yang jarang terjadi, algoritma default mungkin
    ++tidak cocok dengan perilaku yang diinginkan pengembang. Dalam situasi ini, Anda bisa memberikan
    ++pengesampingan eksplisit dengan mengikuti atribut XML berikut dalam file layout:
    ++<var>nextFocusDown</var>, <var>nextFocusLeft</var>, <var>nextFocusRight</var>, dan
    ++<var>nextFocusUp</var>. Tambahkan salah satu atribut ini ke View <em>dari</em> mana fokus
    ++meninggalkan. Definisikan nilai atribut untuk menjadi ID View
    ++<em>ke</em> mana fokus harus diberikan. Misalnya:</p>
    ++<pre>
    ++&lt;LinearLayout
    ++    android:orientation="vertical"
    ++    ... >
    ++  &lt;Button android:id="@+id/top"
    ++          android:nextFocusUp="@+id/bottom"
    ++          ... />
    ++  &lt;Button android:id="@+id/bottom"
    ++          android:nextFocusDown="@+id/top"
    ++          ... />
    ++&lt;/LinearLayout>
    ++</pre>
    ++
    ++<p>Biasanya, dalam layout vertikal ini, navigasi ke atas dari Button pertama tidak akan membawa ke
    ++mana pun, tidak pula akan menyusuri ke bawah dari Button kedua. Karena sekarang Button atas telah
    ++mendefinisikan Button bawah sebagai <var>nextFocusUp</var> (dan sebaliknya), fokus navigasi akan
    ++silih berganti dari atas ke bawah dan bawah ke atas.</p>
    ++
    ++<p>Jika Anda ingin mendeklarasikan View sebagai dapat difokus dalam UI (bila biasanya tidak dapat difokus),
    ++tambahkan atribut XML <code>android:focusable</code> ke View, dalam deklarasi layout Anda.
    ++Atur nilai <var>true</var>. Anda juga bisa mendeklarasikan View
    ++sebagai dapat difokus saat dalam Mode Sentuh dengan <code>android:focusableInTouchMode</code>.</p>
    ++<p>Untuk meminta View tertentu difokus, panggil <code>{@link android.view.View#requestFocus()}</code>.</p>
    ++<p>Untuk mendengarkan kejadian fokus (diberi tahu bila View menerima atau kehilangan fokus), gunakan
    ++<code>{@link android.view.View.OnFocusChangeListener#onFocusChange(View,boolean) onFocusChange()}</code>
    ++, seperti yang dibahas di bagian <a href="#EventListeners">Event Listener</a>, di atas.</p>
    ++
    ++
    ++
    ++<!--
    ++<h2 is="EventCycle">Event Cycle</h2>
    ++   <p>The basic cycle of a View is as follows:</p>
    ++   <ol>
    ++    <li>An event comes in and is dispatched to the appropriate View. The View
    ++    handles the event and notifies any listeners.</li>
    ++    <li>If, in the course of processing the event, the View's bounds may need
    ++    to be changed, the View will call {@link android.view.View#requestLayout()}.</li>
    ++    <li>Similarly, if in the course of processing the event the View's appearance
    ++    may need to be changed, the View will call {@link android.view.View#invalidate()}.</li>
    ++    <li>If either {@link android.view.View#requestLayout()} or {@link android.view.View#invalidate()} were called,
    ++    the framework will take care of measuring, laying out, and drawing the tree
    ++    as appropriate.</li>
    ++   </ol>
    ++
    ++   <p class="note"><strong>Note:</strong> The entire View tree is single threaded. You must always be on
    ++   the UI thread when calling any method on any View.
    ++   If you are doing work on other threads and want to update the state of a View
    ++   from that thread, you should use a {@link android.os.Handler}.
    ++   </p>
    ++-->
    +diff --git a/docs/html-intl/intl/id/training/articles/direct-boot.jd b/docs/html-intl/intl/id/training/articles/direct-boot.jd
    +new file mode 100644
    +index 0000000..a7e3cf3
    +--- /dev/null
    ++++ b/docs/html-intl/intl/id/training/articles/direct-boot.jd
    +@@ -0,0 +1,181 @@
    ++page.title=Direct Boot
    ++page.keywords=pratinjau,sdk,direct boot
    ++page.tags=androidn
    ++page.image=images/cards/card-nyc_2x.jpg
    ++
    ++@jd:body
    ++
    ++<div id="tb-wrapper">
    ++<div id="tb">
    ++  <h2>Dalam dokumen ini</h2>
    ++  <ol>
    ++    <li><a href="#run">Meminta Akses untuk Berjalan Selama Direct Boot</a></li>
    ++    <li><a href="#access">Mengakses Penyimpanan yang Dienkripsi dengan Perangkat</a></li>
    ++    <li><a href="#notification">Mendapatkan Pemberitahuan saat Pengguna Membuka Kunci</a></li>
    ++    <li><a href="#migrating">Migrasi Data yang Ada</a></li>
    ++    <li><a href="#testing">Menguji Aplikasi Peka Enkripsi Anda</a></li>
    ++  </ol>
    ++</div>
    ++</div>
    ++
    ++<p>Android N berjalan dalam mode <i>Direct Boot</i> yang aman
    ++bila perangkat telah dihidupkan namun pengguna tidak membuka
    ++kunci perangkat. Untuk mendukung hal ini, sistem menyediakan dua lokasi penyimpanan untuk data:</p>
    ++
    ++<ul>
    ++<li><i>Penyimpanan yang dienkripsi dengan kredensial</i>, yang merupakan lokasi penyimpanan default
    ++dan hanya tersedia setelah pengguna membuka kunci perangkat.</li>
    ++<li><i>Penyimpanan yang dienkripsi dengan perangkat</i>, yang merupakan lokasi penyimpanan yang tersedia
    ++selama mode Direct Boot dan setelah pengguna membuka kunci perangkat.</li>
    ++</ul>
    ++
    ++<p>Secara default, aplikasi tidak berjalan selama mode Direct Boot.
    ++Jika aplikasi Anda perlu melakukan tindakan selama mode Direct Boot, Anda bisa mendaftarkan
    ++komponen aplikasi yang harus dijalankan selama mode ini. Beberapa kasus penggunaan umum
    ++untuk aplikasi yang perlu dijalankan selama mode Direct Boot antara lain:</p>
    ++
    ++<ul>
    ++<li>Aplikasi yang telah menjadwalkan pemberitahuan, seperti aplikasi
    ++beker.</li>
    ++<li>Aplikasi yang menyediakan pemberitahuan pengguna yang penting, seperti aplikasi SMS.</li>
    ++<li>Aplikasi yang menyediakan layanan aksesibilitas, seperti TalkBack.</li>
    ++</ul>
    ++
    ++<p>Jika aplikasi Anda perlu mengakses data saat dijalankan dalam mode Direct Boot, gunakan
    ++penyimpanan yang dienkripsi dengan perangkat. Penyimpanan yang dienkripsi dengan perangkat berisi data
    ++yang dienkripsi dengan kunci yang hanya tersedia setelah perangkat melakukan
    ++booting yang berhasil diverifikasi.</p>
    ++
    ++<p>Untuk data yang harus dienkripsi dengan kunci yang dikaitkan dengan kredensial
    ++pengguna, seperti PIN atau kata sandi, gunakan penyimpanan yang dienkripsi dengan kredensial.
    ++Penyimpanan yang dienkripsi dengan kredensial hanya tersedia setelah pengguna berhasil
    ++membuka kunci perangkat, hingga saat pengguna menghidupkan ulang perangkat lagi. Jika
    ++pengguna mengaktifkan layar kunci setelah membuka kunci perangkat, hal ini tidak akan mengunci
    ++penyimpanan yang dienkripsi dengan kredensial.</p>
    ++
    ++<h2 id="run">Meminta Akses untuk Berjalan Selama Direct Boot</h2>
    ++
    ++<p>Aplikasi harus mendaftarkan komponennya pada sistem agar
    ++bisa berjalan selama mode Direct Boot atau mengakses
    ++penyimpanan yang dienkripsi dengan perangkat. Aplikasi mendaftar pada sistem dengan menandai komponen sebagai
    ++<i>peka enkripsi</i>. Untuk menandai komponen Anda sebagai peka enkripsi, setel atribut
    ++<code>android:directBootAware</code> ke true dalam manifes Anda.<p>
    ++
    ++<p>Komponen yang peka enkripsi bisa mendaftar untuk menerima pesan siaran
    ++<code>LOCKED_BOOT_COMPLETED</code> dari
    ++sistem bila perangkat telah dihidupkan ulang. Pada tahap ini
    ++penyimpanan yang dienkripsi dengan perangkat akan tersedia, dan komponen Anda bisa mengeksekusi tugas-tugas yang perlu
    ++dijalankan selama mode Direct Boot, seperti memicu alarm yang terjadwal.</p>
    ++
    ++<p>Cuplikan kode berikut adalah contoh cara mendaftarkan
    ++{@link android.content.BroadcastReceiver} sebagai peka enkripsi, dan menambahkan sebuah
    ++filter intent untuk <code>LOCKED_BOOT_COMPLETED</code>, dalam manifes aplikasi:</p>
    ++
    ++<pre>
    ++&lt;receiver
    ++  android:directBootAware="true" &gt;
    ++  ...
    ++  &lt;intent-filter&gt;
    ++    &lt;action android:name="android.intent.action.LOCKED_BOOT_COMPLETED" /&gt;
    ++  &lt;/intent-filter&gt;
    ++&lt;/receiver&gt;
    ++</pre>
    ++
    ++<p>Setelah pengguna membuka kunci perangkat, semua komponen bisa mengakses
    ++penyimpanan yang dienkripsi dengan perangkat serta penyimpanan yang dienkripsi dengan kredensial.</p>
    ++
    ++<h2 id="access">Mengakses Penyimpanan yang Dienkripsi dengan Perangkat</h2>
    ++
    ++<p>Untuk mengakses penyimpanan yang dienkripsi dengan perangkat, buat instance
    ++{@link android.content.Context} kedua dengan memanggil
    ++<code>Context.createDeviceProtectedStorageContext()</code>. Semua panggilan
    ++API penyimpanan yang dibuat menggunakan konteks ini mengakses penyimpanan yang dienkripsi dengan perangkat. Contoh
    ++berikut mengakses penyimpanan yang dienkripsi dengan perangkat dan membuka file data aplikasi
    ++yang ada:</p>
    ++
    ++<pre>
    ++Context directBootContext = appContext.createDeviceProtectedStorageContext();
    ++// Access appDataFilename that lives in device encrypted storage
    ++FileInputStream inStream = directBootContext.openFileInput(appDataFilename);
    ++// Use inStream to read content...
    ++</pre>
    ++
    ++<p>Gunakan penyimpanan yang dienkripsi dengan perangkat hanya untuk
    ++informasi yang harus bisa diakses selama mode Direct Boot.
    ++Jangan gunakan penyimpanan yang dienkripsi dengan perangkat sebagai penyimpanan terenkripsi serba guna.
    ++Untuk informasi pengguna yang bersifat pribadi, atau data terenkripsi yang tidak diperlukan selama
    ++mode Direct Boot, gunakan penyimpanan yang dienkripsi dengan kredensial.</p>
    ++
    ++<h2 id="notification">Mendapatkan Pemberitahuan saat Pengguna Membuka Kunci</h2>
    ++
    ++<p>Setelah pengguna membuka kunci perangkat setelah restart, aplikasi Anda bisa beralih untuk
    ++mengakses penyimpanan yang dienkripsi dengan kredensial dan menggunakan layanan sistem biasa yang
    ++bergantung pada kredensial pengguna.</p>
    ++
    ++<p>Agar diberi tahu bila pengguna membuka kunci perangkat setelah boot ulang,
    ++daftarkan {@link android.content.BroadcastReceiver} dari komponen yang berjalan
    ++untuk mendengarkan pesan <code>ACTION_USER_UNLOCKED</code>. Atau, Anda bisa
    ++menerima pesan {@link android.content.Intent#ACTION_BOOT_COMPLETED
    ++ACTION_BOOT_COMPLETED} yang ada, yang sekarang menunjukkan bahwa perangkat telah dihidupkan dan
    ++pengguna telah membuka kunci perangkat.</p>
    ++
    ++<p>Anda bisa langsung kueri apakah pengguna telah membuka kunci perangkat dengan memanggil
    ++<code>UserManager.isUserUnlocked()</code>.</p>
    ++
    ++<h2 id="migrating">Migrasi Data yang Ada</h2>
    ++
    ++<p>Jika pengguna memperbarui perangkat mereka untuk menggunakan mode Direct Boot,
    ++data Anda yang ada mungkin perlu dipindahkan ke penyimpanan yang dienkripsi dengan perangkat. Gunakan
    ++<code>Context.moveSharedPreferencesFrom()</code> dan
    ++<code>Context.moveDatabaseFrom()</code> untuk memindahkan data preferensi dan
    ++basis data antara penyimpanan yang dienkripsi dengan kredensial dan penyimpanan yang dienkripsi dengan perangkat.</p>
    ++
    ++<p>Pertimbangkan dengan baik saat memutuskan data apa yang akan dipindahkan dari
    ++penyimpanan yang dienkripsi dengan kredensial ke penyimpanan yang dienkripsi dengan perangkat. Anda sebaiknya tidak memindahkan
    ++informasi pengguna yang bersifat rahasia, seperti kata sandi atau token otorisasi, ke
    ++penyimpanan yang dienkripsi dengan perangkat. Dalam beberapa skenario, Anda mungkin perlu mengelola
    ++set data terpisah pada dua tempat penyimpanan yang dienkripsi.</p>
    ++
    ++<h2 id="testing">Menguji Aplikasi Peka Enkripsi Anda</h2>
    ++
    ++<p>Uji aplikasi peka enkripsi Anda menggunakan mode Direct Boot baru. Ada
    ++dua cara untuk mengaktifkan Direct Boot.</p>
    ++
    ++<p class="caution"><strong>Perhatian:</strong> Mengaktifkan Direct Boot
    ++akan menghapus semua data pengguna pada perangkat.</p>
    ++
    ++<p>Pada perangkat yang didukung dengan Android N terpasang, aktifkan
    ++Direct Boot dengan melakukan salah satu hal berikut:</p>
    ++
    ++<ul>
    ++<li>Pada perangkat, aktifkan <b>Developer options</b> jika Anda belum melakukannya dengan
    ++masuk ke <b>Settings &gt; About phone</b>, dan menyentuh <b>Build number</b>
    ++tujuh kali. Setelah layar Developer options terbuka, masuk ke
    ++<b>Settings &gt; Developer options</b> dan pilih
    ++<b>Convert to file encryption</b>.</li>
    ++<li>Gunakan perintah shell adb berikut untuk mengaktifkan mode Direct Boot:
    ++<pre class="no-pretty-print">
    ++$ adb reboot-bootloader
    ++$ fastboot --wipe-and-use-fbe
    ++</pre>
    ++</li>
    ++</ul>
    ++
    ++<p>Mode emulasi Direct Boot juga tersedia, jika Anda perlu mengganti
    ++mode pada perangkat pengujian. Mode emulasi sebaiknya hanya digunakan selama
    ++pengembangan dan bisa menyebabkan kehilangan data. Untuk mengaktifkan mode emulasi Direct Boot,
    ++setel pola kunci pada perangkat, pilih "No thanks" jika ditanya mengenai
    ++layar start-up aman saat menetapkan pola kunci, kemudian gunakan
    ++perintah shell adb berikut:</p>
    ++
    ++<pre class="no-pretty-print">
    ++$ adb shell sm set-emulate-fbe true
    ++</pre>
    ++
    ++<p>Untuk menonaktifkan mode emulasi Direct Boot, gunakan perintah berikut:</p>
    ++
    ++<pre class="no-pretty-print">
    ++$ adb shell sm set-emulate-fbe false
    ++</pre>
    ++
    ++<p>Menggunakan perintah ini akan menyebabkan perangkat melakukan boot ulang.</p>
    +diff --git a/docs/html-intl/intl/id/training/articles/scoped-directory-access.jd b/docs/html-intl/intl/id/training/articles/scoped-directory-access.jd
    +new file mode 100644
    +index 0000000..30aed6f
    +--- /dev/null
    ++++ b/docs/html-intl/intl/id/training/articles/scoped-directory-access.jd
    +@@ -0,0 +1,148 @@
    ++page.title=Scoped Directory Access
    ++page.keywords=pratinjau,sdk,scoped directory access
    ++page.tags=androidn
    ++
    ++@jd:body
    ++
    ++<div id="tb-wrapper">
    ++<div id="tb">
    ++  <h2>Dalam dokumen ini</h2>
    ++  <ol>
    ++    <li><a href="#accessing">Mengakses Direktori Penyimpanan Eksternal</a></li>
    ++    <li><a href="#removable">Mengakses Direktori pada Media Lepas-Pasang</a></li>
    ++    <li><a href="#best">Praktik Terbaik</a></li>
    ++  </ol>
    ++</div>
    ++</div>
    ++
    ++<p>Aplikasi seperti aplikasi foto biasanya hanya memerlukan akses ke direktori tertentu dalam
    ++penyimpanan eksternal, seperti direktori <code>Pictures</code>. Pendekatan
    ++yang ada dalam mengakses penyimpanan eksternal tidak didesain untuk memberi kemudahan
    ++akses direktori tertarget untuk tipe aplikasi ini. Misalnya:</p>
    ++
    ++<ul>
    ++<li>Meminta {@link android.Manifest.permission#READ_EXTERNAL_STORAGE}
    ++atau {@link android.Manifest.permission#WRITE_EXTERNAL_STORAGE} dalam manifes Anda
    ++akan memungkinkan akses ke semua direktori publik pada penyimpanan eksternal, yang mungkin
    ++lebih banyak akses dari yang dibutuhkan aplikasi Anda.</li>
    ++<li>Menggunakan
    ++<a href="{@docRoot}guide/topics/providers/document-provider.html">Storage
    ++Access Framework</a> biasanya membuat pengguna Anda memilih direktori
    ++melalui UI sistem, yang tidak diperlukan jika aplikasi Anda selalu mengakses
    ++direktori eksternal yang sama.</li>
    ++</ul>
    ++
    ++<p>Android N menyediakan API baru yang disederhanakan untuk mengakses
    ++direktori penyimpanan eksternal umum. </p>
    ++
    ++<h2 id="accessing">Mengakses Direktori Penyimpanan Eksternal</h2>
    ++
    ++<p>Gunakan kelas <code>StorageManager</code> untuk mendapatkan instance
    ++<code>StorageVolume</code> yang tepat. Kemudian, buat intent dengan memanggil metode
    ++<code>StorageVolume.createAccessIntent()</code> dari instance itu.
    ++Gunakan intent ini untuk mengakses direktori penyimpanan eksternal. Untuk mendapatkan daftar
    ++semua volume yang tersedia, termasuk volume media lepas-pasang, gunakan
    ++<code>StorageManager.getVolumesList()</code>.</p>
    ++
    ++<p>Jika Anda memiliki informasi tentang file spesifik, gunakan
    ++<code>StorageManager.getStorageVolume(File)</code> untuk mendapatkan
    ++<code>StorageVolume</code> yang berisi file tersebut. Panggil
    ++<code>createAccessIntent()</code> pada <code>StorageVolume</code> ini untuk mengakses
    ++direktori penyimpanan eksternal untuk file tersebut.</p>
    ++
    ++<p>
    ++Di volume kedua, seperti kartu SD eksternal, teruskan null saat memanggil
    ++<code>StorageVolume.createAccessIntent()</code> untuk meminta akses ke seluruh
    ++volume, sebagai ganti direktori spesifik.
    ++<code>StorageVolume.createAccessIntent()</code> akan mengembalikan null jika Anda meneruskan
    ++null ke volume utama, atau jika Anda meneruskan nama direktori yang tidak valid.
    ++</p>
    ++
    ++<p>Cuplikan kode berikut adalah contoh cara membuka direktori
    ++<code>Pictures</code> dalam penyimpanan bersama utama:</p>
    ++
    ++<pre>
    ++StorageManager sm = (StorageManager)getSystemService(Context.STORAGE_SERVICE);
    ++StorageVolume volume = sm.getPrimaryVolume();
    ++Intent intent = volume.createAccessIntent(Environment.DIRECTORY_PICTURES);
    ++startActivityForResult(intent, request_code);
    ++</pre>
    ++
    ++<p>Sistem ini mencoba untuk memberikan akses ke direktori eksternal, dan jika
    ++diperlukan mengonfirmasi akses dengan pengguna menggunakan UI yang disederhanakan:</p>
    ++
    ++<img src="{@docRoot}images/android-7.0/scoped-directory-access-framed.png" srcset="{@docRoot}images/android-7.0/scoped-directory-access-framed.png 1x,
    ++{@docRoot}images/android-7.0/scoped-directory-access-framed_2x.png 2x" />
    ++<p class="img-caption"><strong>Gambar 1.</strong> Sebuah aplikasi yang meminta
    ++akses ke direktori Pictures.</p>
    ++
    ++<p>Jika pengguna memberi akses, sistem akan memanggil penggantian
    ++<code>onActivityResult()</code> Anda dengan kode hasil
    ++<code>Activity.RESULT_OK</code>, dan data intent yang berisi URI. Gunakan
    ++URI yang disediakan untuk mengakses informasi direktori, serupa dengan menggunakan URI
    ++yang dikembalikan oleh
    ++<a href="{@docRoot}guide/topics/providers/document-provider.html">Storage
    ++Access Framework</a>.</p>
    ++
    ++<p>Jika pengguna tidak memberi akses, sistem akan memanggil penggantian
    ++<code>onActivityResult()</code> Anda dengan kode hasil
    ++<code>Activity.RESULT_CANCELED</code>, dan data intent nol.</p>
    ++
    ++<p class="note"><b>Catatan</b>: Mendapatkan akses ke direktori eksternal tertentu
    ++juga akan memperoleh akses ke subdirektori dalam direktori tersebut.</p>
    ++
    ++<h2 id="removable">Mengakses Direktori pada Media Lepas-Pasang</h2>
    ++
    ++<p>Untuk menggunakan Scoped Directory Access guna mengakses direktori pada media lepas-pasang,
    ++pertama tambahkan {@link android.content.BroadcastReceiver} yang akan mendengarkan pemberitahuan
    ++{@link android.os.Environment#MEDIA_MOUNTED}, misalnya:</p>
    ++
    ++<pre>
    ++&lt;receiver
    ++    android:name=".MediaMountedReceiver"
    ++    android:enabled="true"
    ++    android:exported="true" &gt;
    ++    &lt;intent-filter&gt;
    ++        &lt;action android:name="android.intent.action.MEDIA_MOUNTED" /&gt;
    ++        &lt;data android:scheme="file" /&gt;
    ++    &lt;/intent-filter&gt;
    ++&lt;/receiver&gt;
    ++</pre>
    ++
    ++<p>Bila pengguna memasang media lepas-pasang, seperti kartu SD, sistem akan mengirimkan pemberitahuan
    ++{@link android.os.Environment#MEDIA_MOUNTED}. Pemberitahuan ini
    ++memberikan sebuah objek <code>StorageVolume</code> dalam data intent yang bisa
    ++Anda gunakan untuk mengakses direktori pada media lepas-pasang. Contoh berikut
    ++mengakses direktori <code>Pictures</code> pada media lepas-pasang:</p>
    ++
    ++<pre>
    ++// BroadcastReceiver has already cached the MEDIA_MOUNTED
    ++// notification Intent in mediaMountedIntent
    ++StorageVolume volume = (StorageVolume)
    ++    mediaMountedIntent.getParcelableExtra(StorageVolume.EXTRA_STORAGE_VOLUME);
    ++volume.createAccessIntent(Environment.DIRECTORY_PICTURES);
    ++startActivityForResult(intent, request_code);
    ++</pre>
    ++
    ++<h2 id="best">Praktik Terbaik</h2>
    ++
    ++<p>Bila memungkinkan, pertahankan URI akses direktori eksternal sehingga Anda tidak perlu
    ++berulang kali meminta akses ke pengguna. Setelah pengguna memberikan akses, panggil
    ++<code>getContentResolver().takePersistableUriPermssion()</code> bersama
    ++URI akses direktori. Sistem akan mempertahankan URI dan permintaan
    ++akses berikutnya akan mengembalikan <code>RESULT_OK</code> dan tidak menampilkan UI konfirmasi kepada
    ++pengguna.</p>
    ++
    ++<p>Jika pengguna menolak akses ke direktori eksternal, jangan langsung
    ++meminta akses lagi. Berulang kali meminta akses akan menghasilkan pengalaman
    ++pengguna yang buruk. Jika permintaan ditolak oleh pengguna, dan aplikasi meminta akses
    ++lagi, UI akan menampilkan kotak centang <b>Don't ask again</b>:</p>
    ++
    ++<img src="{@docRoot}images/android-7.0/scoped-directory-access-dont-ask.png" srcset="{@docRoot}images/android-7.0/scoped-directory-access-dont-ask.png 1x,
    ++{@docRoot}images/android-7.0/scoped-directory-access-dont-ask_2x.png 2x" />
    ++<p class="img-caption"><strong>Gambar 1.</strong> Sebuah aplikasi membuat
    ++permintaan kedua untuk mengakses media lepas-pasang.</p>
    ++
    ++<p>Jika pengguna memilih <b>Don't ask again</b> dan menolak permintaan,
    ++semua permintaan berikutnya untuk direktori yang diberikan dari aplikasi
    ++Anda secara otomatis akan ditolak, dan tidak ada UI permintaan yang akan ditampilkan ke pengguna.</p>
    +\ No newline at end of file
    +diff --git a/docs/html-intl/intl/id/training/articles/security-config.jd b/docs/html-intl/intl/id/training/articles/security-config.jd
    +new file mode 100644
    +index 0000000..e13429d
    +--- /dev/null
    ++++ b/docs/html-intl/intl/id/training/articles/security-config.jd
    +@@ -0,0 +1,747 @@
    ++page.title=Konfigurasi Keamanan Jaringan
    ++page.keywords=androidn,keamanan,jaringan
    ++page.image=images/cards/card-nyc_2x.jpg
    ++
    ++@jd:body
    ++
    ++<div id="tb-wrapper">
    ++<div id="tb">
    ++
    ++<h2>Dalam dokumen ini</h2>
    ++<ol>
    ++  <li><a href="#manifest">Menambahkan File Konfigurasi Keamanan</a></li>
    ++  <li><a href="#CustomTrust">Menyesuaikan CA Tepercaya</a>
    ++      <ol>
    ++      <li><a href="#ConfigCustom">Mengonfigurasi CA Tepercaya Khusus</a></li>
    ++      <li><a href="#LimitingCas">Membatasi Set CA Tepercaya</a></li>
    ++      <li><a href="#TrustingAdditionalCas">Mempercayai CA Tambahan</a></li>
    ++      </ol>
    ++  </li>
    ++  <li><a href="#TrustingDebugCa">CA Debug Saja</a></li>
    ++  <li><a href="#UsesCleartextTraffic">Berhenti dari Lalu Lintas Cleartext</a></li>
    ++  <li><a href="#CertificatePinning">Menyematkan Sertifikat</a></li>
    ++  <li><a href="#ConfigInheritance">Perilaku Pewarisan Konfigurasi</a></li>
    ++  <li><a href="#FileFormat">Format File Konfigurasi</a></li>
    ++</ol>
    ++</div>
    ++</div>
    ++
    ++
    ++<p>
    ++  Android N menyertakan fitur
    ++  Network Security Configuration yang memungkinkan aplikasi menyesuaikan setelan keamanan jaringan mereka dalam
    ++  file konfigurasi deklaratif yang aman tanpa memodifikasi kode aplikasi. Setelan ini bisa
    ++  dikonfigurasi untuk domain dan aplikasi tertentu. Kemampuan
    ++  utama fitur ini adalah sebagai berikut:
    ++</p>
    ++
    ++<ul>
    ++  <li>
    ++    <b>Trust-anchor khusus:</b> Menyesuaikan Certificate Authorities (CA) mana
    ++    yang dipercaya untuk koneksi aman aplikasi. Misalnya,
    ++    mempercayai sertifikat tertentu yang ditandatangani sendiri atau membatasi
    ++    set CA umum yang dipercaya aplikasi.
    ++  </li>
    ++
    ++  <li>
    ++    <b>Penggantian hanya-debug:</b> Men-debug secara aman koneksi aman dalam aplikasi
    ++    tanpa menambahkan risiko pada basis yang telah dipasang.
    ++  </li>
    ++
    ++  <li>
    ++    <b>Berhenti dari lalu lintas cleartext:</b> Melindungi aplikasi dari
    ++    penggunaan lalu lintas cleartext secara tidak sengaja.
    ++  </li>
    ++
    ++  <li>
    ++    <b>Penyematan sertifikat:</b> Membatasi koneksi aman aplikasi ke
    ++    sertifikat tertentu.
    ++  </li>
    ++</ul>
    ++
    ++
    ++<h2 id="manifest">Menambahkan File Konfigurasi Keamanan</h2>
    ++
    ++<p>
    ++  Fitur Network Security Configuration menggunakan file XML tempat Anda menetapkan
    ++  setelan untuk aplikasi. Anda harus menyertakan sebuah entri dalam manifes aplikasi
    ++  untuk menunjuk ke file ini. Kutipan kode berikut dari sebuah manifes
    ++  yang memperagakan cara membuat entri ini:
    ++</p>
    ++
    ++<pre>
    ++&lt;?xml version="1.0" encoding="utf-8"?&gt;
    ++&lt;manifest ... &gt;
    ++  &lt;application ... &gt;
    ++    &lt;meta-data android:name="android.security.net.config"
    ++               android:resource="@xml/network_security_config" /&gt;
    ++    ...
    ++  &lt;/application&gt;
    ++&lt;/manifest&gt;
    ++</pre>
    ++
    ++<h2 id="CustomTrust">Menyesuaikan CA Tepercaya</h2>
    ++
    ++<p>
    ++  Aplikasi mungkin perlu mempercayai set CA khusus sebagai ganti default
    ++  platform. Alasannya yang paling umum adalah:
    ++</p>
    ++
    ++<ul>
    ++  <li>Menghubungkan ke host dengan otoritas sertifikat khusus (ditandatangani sendiri,
    ++  dikeluarkan oleh CA internal, dll).
    ++  </li>
    ++
    ++  <li>Membatasi set CA hanya untuk CA yang Anda percaya sebagai ganti setiap CA
    ++  yang sudah terpasang.
    ++  </li>
    ++
    ++  <li>Mempercayai CA tambahan yang tidak disertakan dalam sistem.
    ++  </li>
    ++</ul>
    ++
    ++<p>
    ++  Secara default koneksi (mis. TLS, HTTPS) aman dari semua aplikasi mempercayai
    ++  CA yang telah dipasang oleh sistem, dan aplikasi yang menargetkan API level 23
    ++  (Android M) ke bawah, juga mempercayai penyimpanan CA yang ditambahkan pengguna secara default. Aplikasi
    ++  bisa menyesuaikan koneksinya menggunakan {@code base-config} (untuk
    ++  penyesuaian lebar-aplikasi) atau {@code domain-config} (untuk penyesuaian
    ++  per-domain).
    ++</p>
    ++
    ++
    ++<h3 id="ConfigCustom">Mengonfigurasi CA Khusus</h3>
    ++
    ++<p>
    ++  Anggaplah Anda ingin menghubungkan ke host Anda yang menggunakan sertifikat
    ++  SSL yang ditandatangani sendiri atau ke host yang sertifikat SSL-nya dikeluarkan oleh CA non-publik
    ++  yang Anda percaya, seperti CA internal perusahaan Anda.
    ++</p>
    ++
    ++<p>
    ++  <code>res/xml/network_security_config.xml</code>:
    ++<pre>
    ++&lt;?xml version="1.0" encoding="utf-8"?&gt;
    ++&lt;network-security-config&gt;
    ++    &lt;domain-config&gt;
    ++        &lt;domain includeSubdomains="true"&gt;example.com&lt;/domain&gt;
    ++        &lt;trust-anchors&gt;
    ++            &lt;certificates src="@raw/my_ca"/&gt;
    ++        &lt;/trust-anchors&gt;
    ++    &lt;/domain-config&gt;
    ++&lt;/network-security-config&gt;
    ++</pre>
    ++</p>
    ++
    ++<p>
    ++  Menambahkan sertifikat CA yang ditandatangani sendiri atau sertifikat CA non-publik, dalam format PEM atau DER, ke
    ++  {@code res/raw/my_ca}.
    ++</p>
    ++
    ++
    ++<h3 id="LimitingCas">Membatasi Set CA Tepercaya</h3>
    ++
    ++<p>
    ++  Aplikasi yang tidak ingin mempercayai semua CA yang dipercaya oleh sistem
    ++  sebagai gantinya bisa menetapkan set CA sendiri yang telah dikurangi untuk dipercaya. Ini akan melindungi
    ++  aplikasi dari sertifikat palsu yang dikeluarkan oleh selain CA.
    ++</p>
    ++
    ++<p>
    ++  Konfigurasi untuk membatasi set CA tepercaya mirip dengan <a href="#TrustingACustomCa">mempercayai CA khusus</a> untuk domain tertentu selain
    ++  beberapa CA disediakan dalam sumber daya.
    ++</p>
    ++
    ++<p>
    ++<code>res/xml/network_security_config.xml</code>:
    ++<pre>
    ++&lt;?xml version="1.0" encoding="utf-8"?&gt;
    ++&lt;network-security-config&gt;
    ++    &lt;domain-config&gt;
    ++        &lt;domain includeSubdomains="true"&gt;secure.example.com&lt;/domain&gt;
    ++        &lt;domain includeSubdomains="true"&gt;cdn.example.com&lt;/domain&gt;
    ++        &lt;trust-anchors&gt;
    ++            &lt;certificates src="@raw/trusted_roots"/&gt;
    ++        &lt;/trust-anchors&gt;
    ++    &lt;/domain-config&gt;
    ++&lt;/network-security-config&gt;
    ++</pre>
    ++</p>
    ++
    ++<p>
    ++  Menambahkan CA tepercaya, dalam format PEM atau DER, ke {@code res/raw/trusted_roots}.
    ++  Perhatikan, jika menggunakan format PEM, file <em>hanya</em> boleh berisi data PEM
    ++  dan tidak ada teks tambahan. Anda juga bisa menyediakan beberapa elemen
    ++  <a href="#certificates"><code>&lt;certificates&gt;</code></a>
    ++sebagai ganti satu elemen.
    ++</p>
    ++
    ++
    ++<h3 id="TrustingAdditionalCas">
    ++  Mempercayai CA Tambahan
    ++</h3>
    ++
    ++<p>
    ++  Sebuah aplikasi mungkin perlu mempercayai CA tambahan yang tidak dipercaya oleh sistem,
    ++  hal ini bisa disebabkan karena sistem belum menyertakan CA atau CA tidak
    ++  memenuhi persyaratan untuk memasukkan ke dalam sistem Android. Aplikasi
    ++  bisa melakukannya dengan menetapkan beberapa sumber sertifikat untuk
    ++  konfigurasi.
    ++</p>
    ++<p>
    ++<code>res/xml/network_security_config.xml</code>:
    ++<pre>
    ++&lt;?xml version="1.0" encoding="utf-8"?&gt;
    ++&lt;network-security-config&gt;
    ++    &lt;base-config&gt;
    ++        &lt;trust-anchors&gt;
    ++            &lt;certificates src="@raw/extracas"/&gt;
    ++            &lt;certificates src="system"/&gt;
    ++        &lt;/trust-anchors&gt;
    ++    &lt;/base-config&gt;
    ++&lt;/network-security-config&gt;
    ++</pre>
    ++</p>
    ++
    ++
    ++<h2 id="TrustingDebugCa">Mengonfigurasi CA untuk Debug</h2>
    ++
    ++<p>
    ++  Saat men-debug aplikasi yang terhubung melalui HTTPS, Anda mungkin perlu
    ++  menghubungkan ke server pengembangan lokal, yang tidak memiliki sertifikat
    ++  SSL untuk server produksi Anda. Untuk mendukungnya tanpa
    ++  memodifikasi kode aplikasi, Anda bisa menetapkan CA hanya-debug
    ++  yang <i>hanya</i> dipercaya bila <a href="{@docRoot}guide/topics/manifest/application-element.html#debug">
    ++android:debuggable</a>
    ++  adalah {@code true} dengan menggunakan {@code debug-overrides}. Biasanya IDE dan alat
    ++  build menyetel flag ini secara otomatis untuk build non-rilis.
    ++</p>
    ++
    ++<p>
    ++  Ini lebih aman daripada kode kondisional biasa karena, sebagai tindakan
    ++  pencegahan keamanan, toko aplikasi tidak menerima aplikasi yang ditandai
    ++  bisa-di-debug.
    ++</p>
    ++
    ++<p>
    ++<code>res/xml/network_security_config.xml</code>:
    ++<pre>
    ++&lt;?xml version="1.0" encoding="utf-8"?&gt;
    ++&lt;network-security-config&gt;
    ++    &lt;debug-overrides&gt;
    ++        &lt;trust-anchors&gt;
    ++            &lt;certificates src="@raw/debug_cas"/&gt;
    ++        &lt;/trust-anchors&gt;
    ++    &lt;/debug-overrides&gt;
    ++&lt;/network-security-config&gt;
    ++</pre>
    ++</p>
    ++
    ++
    ++<h2 id="UsesCleartextTraffic">Berhenti dari Lalu Lintas Cleartext</h2>
    ++
    ++<p>
    ++  Aplikasi bermaksud menyambung ke tujuan hanya menggunakan koneksi
    ++ aman dapat memilih keluar dari dukungan cleartext (menggunakan protokol
    ++ HTTP yang tidak terenkripsi sebagai ganti HTTPS) ke tujuan tersebut. Opsi ini akan membantu mencegah
    ++  regresi tidak disengaja dalam aplikasi karena perubahan dalam URL yang disediakan oleh sumber-sumber
    ++  eksternal seperti server backend.
    ++  Lihat {@link android.security.NetworkSecurityPolicy#isCleartextTrafficPermitted
    ++  NetworkSecurityPolicy.isCleartextTrafficPermitted()} untuk detail selengkapnya.
    ++</p>
    ++
    ++<p>
    ++  Misalnya, aplikasi mungkin ingin memastikan semua koneksi ke {@code
    ++  secure.example.com} selalu dilakukan melalui HTTPS untuk melindungi lalu lintas sensitif
    ++  dari jaringan yang berbahaya.
    ++</p>
    ++
    ++<p>
    ++<code>res/xml/network_security_config.xml</code>:
    ++<pre>
    ++&lt;?xml version="1.0" encoding="utf-8"?&gt;
    ++&lt;network-security-config&gt;
    ++    &lt;domain-config usesCleartextTraffic="false"&gt;
    ++        &lt;domain includeSubdomains="true"&gt;secure.example.com&lt;/domain&gt;
    ++    &lt;/domain-config&gt;
    ++&lt;/network-security-config&gt;
    ++</pre>
    ++</p>
    ++
    ++
    ++<h2 id="CertificatePinning">Menyematkan Sertifikat</h2>
    ++
    ++<p>
    ++  Biasanya aplikasi mempercayai semua CA yang telah terpasang. Jika salah satu dari CA ini
    ++  mengeluarkan sertifikat palsu, aplikasi akan berisiko terkena serangan
    ++  MiTM. Beberapa aplikasi memilih untuk membatasi set sertifikat yang mereka terima
    ++  baik dengan membatasi set CA yang mereka percaya atau dengan menyematkan sertifikat.
    ++</p>
    ++
    ++<p>
    ++  Penyematan sertifikat dilakukan dengan memberikan seperangkat sertifikat dengan hash
    ++  kunci publik (SubjectPublicKeyInfo pada sertifikat X.509). Rantai
    ++  sertifikat nanti hanya berlaku jika rantai sertifikat berisi setidaknya salah satu
    ++  dari kunci publik yang disematkan.
    ++</p>
    ++
    ++<p>
    ++  Perhatikan, saat menggunakan penyematan sertifikat, Anda harus selalu menyertakan kunci
    ++  cadangan sehingga jika Anda terpaksa beralih ke kunci baru, atau mengubah CA (saat
    ++  menyematkan ke sertifikat CA atau perantara CA tersebut), konektivitas
    ++  aplikasi Anda tidak terpengaruh. Jika tidak, Anda harus mendorong
    ++  pembaruan ke aplikasi tersebut untuk memulihkan konektivitas.
    ++</p>
    ++
    ++<p>
    ++  Selain itu dimungkinkan juga menyetel waktu habis masa berlaku untuk pin setelah
    ++  penyematan tidak dilakukan. Hal ini membantu mencegah masalah konektivitas dalam
    ++  aplikasi yang belum diperbarui. Akan tetapi, menyetel waktu kedaluwarsa
    ++  pada pin mungkin akan membuat penyematan bisa diabaikan.
    ++</p>
    ++
    ++<p>
    ++<code>res/xml/network_security_config.xml</code>:
    ++<pre>
    ++&lt;?xml version="1.0" encoding="utf-8"?&gt;
    ++&lt;network-security-config&gt;
    ++    &lt;domain-config&gt;
    ++        &lt;domain includeSubdomains="true"&gt;example.com&lt;/domain&gt;
    ++        &lt;pin-set expiration="2018-01-01"&gt;
    ++            &lt;pin digest="SHA-256"&gt;7HIpactkIAq2Y49orFOOQKurWxmmSFZhBCoQYcRhJ3Y=&lt;/pin&gt;
    ++            &lt;!-- backup pin --&gt
    ++            &lt;pin digest="SHA-256"&gt;fwza0LRMXouZHRC8Ei+4PyuldPDcf3UKgO/04cDM1oE=&lt;/pin&gt;
    ++        &lt;/pin-set&gt;
    ++    &lt;/domain-config&gt;
    ++&lt;/network-security-config&gt;
    ++</pre>
    ++</p>
    ++
    ++
    ++<h2 id="ConfigInheritance">Perilaku Pewarisan Konfigurasi</h2>
    ++
    ++<p>
    ++  Nilai yang tidak disetel dalam konfigurasi tertentu akan diwariskan. Perilaku ini memungkinkan konfigurasi
    ++  yang lebih kompleks sambil menjaga file konfigurasi tetap terbaca.
    ++</p>
    ++
    ++<p>
    ++  Jika nilai tidak disetel dalam entri tertentu maka nilai dari entri berikutnya yang lebih
    ++  umum akan digunakan. Nilai yang tidak disetel dalam {@code domain-config} akan
    ++  diambil dari {@code domain-config} induk, jika tersarang, atau dari {@code
    ++  base-config} jika tidak. Nilai yang tidak disetel dalam {@code base-config} akan menggunakan
    ++  nilai default platform.
    ++</p>
    ++
    ++<p>
    ++  Misalnya pertimbangkan, bila semua koneksi ke subdomain {@code
    ++  example.com} harus menggunakan set CA khusus. Selain itu, lalu lintas cleartext ke
    ++  domain ini diizinkan <em>kecuali</em> saat menghubungkan ke {@code
    ++  secure.example.com}. Dengan menyarangkan konfigurasi untuk {@code
    ++  secure.example.com} dalam konfigurasi untuk {@code example.com},
    ++  {@code trust-anchors} tidak perlu digandakan.
    ++</p>
    ++
    ++<p>
    ++<code>res/xml/network_security_config.xml</code>:
    ++<pre>
    ++&lt;?xml version="1.0" encoding="utf-8"?&gt;
    ++&lt;network-security-config&gt;
    ++    &lt;domain-config&gt;
    ++        &lt;domain includeSubdomains="true"&gt;example.com&lt;/domain&gt;
    ++        &lt;trust-anchors&gt;
    ++            &lt;certificates src="@raw/my_ca"/&gt;
    ++        &lt;/trust-anchors&gt;
    ++        &lt;domain-config cleartextTrafficPermitted="false"&gt;
    ++            &lt;domain includeSubdomains="true"&gt;secure.example.com&lt;/domain&gt;
    ++        &lt;/domain-config&gt;
    ++    &lt;/domain-config&gt;
    ++&lt;/network-security-config&gt;
    ++</pre>
    ++</p>
    ++
    ++
    ++<h2 id="FileFormat">Format File Konfigurasi</h2>
    ++
    ++<p>
    ++  Fitur Network Security Configuration menggunakan format file XML.
    ++  Struktur keseluruhan file ditampilkan dalam contoh kode berikut:
    ++</p>
    ++
    ++<pre>
    ++&lt;?xml version="1.0" encoding="utf-8"?&gt;
    ++&lt;network-security-config&gt;
    ++    &lt;base-config&gt;
    ++        &lt;trust-anchors&gt;
    ++            &lt;certificates src="..."/&gt;
    ++            ...
    ++        &lt;/trust-anchors&gt;
    ++    &lt;/base-config&gt;
    ++
    ++    &lt;domain-config&gt;
    ++        &lt;domain&gt;android.com&lt;/domain&gt;
    ++        ...
    ++        &lt;trust-anchors&gt;
    ++            &lt;certificates src="..."/&gt;
    ++            ...
    ++        &lt;/trust-anchors&gt;
    ++        &lt;pin-set&gt;
    ++            &lt;pin digest="..."&gt;...&lt;/pin&gt;
    ++            ...
    ++        &lt;/pin-set&gt;
    ++    &lt;/domain-config&gt;
    ++    ...
    ++    &lt;debug-overrides&gt;
    ++        &lt;trust-anchors&gt;
    ++            &lt;certificates src="..."/&gt;
    ++            ...
    ++        &lt;/trust-anchors&gt;
    ++    &lt;/debug-overrides&gt;
    ++&lt;/network-security-config&gt;
    ++</pre>
    ++
    ++<p>
    ++  Bagian berikut menjelaskan sintaks dan detail lainnya dari format
    ++  file.
    ++</p>
    ++
    ++<h3 id="network-security-config">
    ++  &lt;network-security-config&gt;
    ++</h3>
    ++
    ++<dl class="xml">
    ++  <dt>
    ++    bisa berisi:
    ++  </dt>
    ++
    ++  <dd>
    ++    0 atau 1 <code><a href="#base-config">&lt;base-config&gt;</a></code><br>
    ++    Sejumlah <code><a href=
    ++    "#domain-config">&lt;domain-config&gt;</a></code><br>
    ++    0 atau 1 <code><a href="#debug-overrides">&lt;debug-overrides&gt;</a></code>
    ++  </dd>
    ++</dl>
    ++
    ++<h3 id="base-config">
    ++  &lt;base-config&gt;
    ++</h3>
    ++
    ++<dl class="xml">
    ++  <dt>
    ++    sintaks:
    ++  </dt>
    ++</dl>
    ++
    ++<pre class="stx">
    ++&lt;base-config <a href=
    ++"#usesCleartextTraffic">usesCleartextTraffic</a>=["true" | "false"]&gt;
    ++    ...
    ++&lt;/base-config&gt;
    ++</pre>
    ++<dl class="xml">
    ++  <dt>
    ++    bisa berisi:
    ++  </dt>
    ++
    ++  <dd>
    ++    <code><a href="#trust-anchors">&lt;trust-anchors&gt;</a></code>
    ++  </dd>
    ++
    ++  <dt>
    ++    keterangan:
    ++  </dt>
    ++
    ++  <dd>
    ++    Konfigurasi default yang digunakan oleh semua koneksi yang tujuannya tidak
    ++    tercakup oleh <a href="#domain-config"><code>domain-config</code></a>.
    ++
    ++<p>
    ++  Nilai yang tidak disetel akan menggunakan nilai default platform. Konfigurasi
    ++  default untuk aplikasi yang menargetkan API level 24 ke atas:
    ++</p>
    ++
    ++<pre>
    ++&lt;base-config usesCleartextTraffic="true"&gt;
    ++    &lt;trust-anchors&gt;
    ++        &lt;certificates src="system" /&gt;
    ++    &lt;/trust-anchors&gt;
    ++&lt;/base-config&gt;
    ++</pre>
    ++Konfigurasi default untuk aplikasi yang menargetkan API level 23 ke bawah:
    ++<pre>
    ++&lt;base-config usesCleartextTraffic="true"&gt;
    ++    &lt;trust-anchors&gt;
    ++        &lt;certificates src="system" /&gt;
    ++        &lt;certificates src="user" /&gt;
    ++    &lt;/trust-anchors&gt;
    ++&lt;/base-config&gt;
    ++</pre>
    ++
    ++  </dd>
    ++</dl>
    ++
    ++<h3 id="domain-config">&lt;domain-config&gt;</h3>
    ++<dl class="xml">
    ++<dt>sintaks:</dt>
    ++<dd>
    ++<pre class="stx">&lt;domain-config <a href="#usesCleartextTraffic">usesCleartextTraffic</a>=["true" | "false"]&gt;
    ++    ...
    ++&lt;/domain-config&gt;</pre>
    ++</dd>
    ++
    ++<dt>Bisa Berisi:</dt>
    ++
    ++<dd>
    ++1 atau beberapa <code><a href="#domain">&lt;domain&gt;</a></code>
    ++<br/>0 atau 1 <code><a href="#trust-anchors">&lt;trust-anchors&gt;</a></code>
    ++<br/>0 atau 1 <code><a href="#pin-set">&lt;pin-set&gt;</code></a>
    ++<br/>Sejumlah <code>&lt;domain-config&gt;</code> tersarang</dd>
    ++
    ++<dt>Keterangan</dt>
    ++<dd>Konfigurasi yang digunakan untuk koneksi ke tujuan tertentu seperti didefinisikan oleh elemen {@code domain}.
    ++
    ++<p>Perhatikan, jika beberapa elemen {@code domain-config} mencakup suatu tujuan, konfigurasi dengan aturan domain paling spesifik (terpanjang) yang cocok
    ++akan digunakan.</p></dd>
    ++</dl>
    ++
    ++
    ++<h3 id="domain">&lt;domain&gt;</h3>
    ++
    ++<dl class="xml">
    ++  <dt>
    ++    sintaks:
    ++  </dt>
    ++
    ++  <dd>
    ++    <pre class="stx">
    ++&lt;domain includeSubdomains=["true" | "false"]&gt;example.com&lt;/domain&gt;
    ++</pre>
    ++  </dd>
    ++
    ++  <dt>
    ++    Atribut:
    ++  </dt>
    ++
    ++  <dd>
    ++    <dl class="attr">
    ++      <dt>
    ++        {@code includeSubdomains}
    ++      </dt>
    ++
    ++      <dd>
    ++        Jika {@code "true"} maka aturan domain ini akan dicocokkan dengan domain dan semua
    ++        subdomain, termasuk subdomain dari subdomain, jika tidak peraturan hanya
    ++        diterapkan pada kecocokan yang persis tepat.
    ++      </dd>
    ++    </dl>
    ++  </dd>
    ++
    ++  <dt>
    ++    Keterangan:
    ++  </dt>
    ++</dl>
    ++
    ++<h3 id="debug-overrides">&lt;debug-overrides&gt;</h3>
    ++
    ++<dl class="xml">
    ++  <dt>
    ++    sintaks:
    ++  </dt>
    ++
    ++  <dd>
    ++    <pre class="stx">
    ++&lt;debug-overrides&gt;
    ++    ...
    ++&lt;/debug-overrides&gt;
    ++</pre>
    ++  </dd>
    ++
    ++  <dt>
    ++    Bisa Berisi:
    ++  </dt>
    ++
    ++  <dd>
    ++    0 atau 1 <code><a href="#trust-anchors">&lt;trust-anchors&gt;</a></code>
    ++  </dd>
    ++
    ++  <dt>
    ++    Keterangan:
    ++  </dt>
    ++
    ++  <dd>
    ++    Pengesampingan yang akan diterapkan bila <a href="{@docRoot}guide/topics/manifest/application-element.html#debug">android:debuggable</a>
    ++    adalah {@code "true"} yang biasanya terjadi untuk build non-rilis
    ++    yang dihasilkan oleh alat IDE dan build. Trust-anchor yang ditetapkan dalam {@code
    ++    debug-overrides} akan ditambahkan ke semua konfigurasi lainnya dan penyematan
    ++    sertifikat tidak dilakukan bila rantai sertifikat server menggunakan satu dari
    ++    trust-anchor hanya-debug ini. Jika <a href="{@docRoot}guide/topics/manifest/application-element.html#debug">android:debuggable</a>
    ++    adalah {@code "false"} maka bagian ini akan diabaikan sepenuhnya.
    ++  </dd>
    ++</dl>
    ++
    ++<h3 id="trust-anchors">&lt;trust-anchors&gt;</h3>
    ++<dl class="xml">
    ++  <dt>
    ++    sintaks:
    ++  </dt>
    ++
    ++  <dd>
    ++    <pre class="stx">
    ++&lt;trust-anchors&gt;
    ++...
    ++&lt;/trust-anchors&gt;
    ++</pre>
    ++  </dd>
    ++
    ++  <dt>
    ++    Bisa Berisi:
    ++  </dt>
    ++
    ++  <dd>
    ++    Sejumlah <code><a href="#certificates">&lt;certificates&gt;</a></code>
    ++  </dd>
    ++
    ++  <dt>
    ++    Keterangan:
    ++  </dt>
    ++
    ++  <dd>
    ++    Set trust-anchor untuk koneksi aman.
    ++  </dd>
    ++</dl>
    ++
    ++
    ++<h3 id="certificates">&lt;certificates&gt;</h3>
    ++<dl class="xml">
    ++<dt>sintaks:</dt>
    ++<dd><pre class="stx">&lt;certificates src=["system" | "user" | "<i>raw resource</i>"]
    ++              overridePins=["true" | "false"] /&gt;
    ++</pre></dd>
    ++<dt>keterangan:</dt>
    ++<dd>Set sertifikat X.509 untuk elemen {@code trust-anchors}.</dd>
    ++
    ++<dt>atribut:</dt>
    ++<dd><dl class="attr">
    ++<dt>{@code src}</dt>
    ++<dd>
    ++Sumber sertifikat CA, bisa salah satu dari
    ++<ul>
    ++  <li>ID sumber daya mentah yang menunjuk ke file berisi sertifikat X.509.
    ++  Sertifikat harus dikodekan dalam format DER atau PEM. Dalam hal sertifikat
    ++  PEM, file <em>tidak boleh</em> berisi data tambahan non-PEM seperti
    ++  komentar.
    ++  </li>
    ++
    ++  <li>{@code "system"} untuk sertifikat CA sistem yang telah terpasang.
    ++  </li>
    ++
    ++  <li>{@code "user"} untuk sertifikat CA yang ditambahkan pengguna.
    ++  </li>
    ++</ul>
    ++</dd>
    ++
    ++<dt>{@code overridePins}</dt>
    ++<dd>
    ++  <p>
    ++    Menetapkan apakah CA dari sumber akan mengabaikan penyematan sertifikat. Jika {@code
    ++    "true"} kemudian rangkaian sertifikat melalui salah satu CA dari
    ++    sumber ini maka tidak dilakukan penyematan. Hal ini bisa berguna untuk debug CA
    ++    atau untuk mendukung dengan memungkinkan pengguna melakukan MiTM atas lalu lintas aman aplikasi Anda.
    ++  </p>
    ++
    ++  <p>
    ++    Default-nya adalah {@code "false"} kecuali jika ditetapkan dalam elemen {@code debug-overrides},
    ++    dalam hal demikian default-nya adalah {@code "true"}.
    ++  </p>
    ++</dd>
    ++</dl>
    ++</dd>
    ++
    ++
    ++<h3 id="pin-set">&lt;pin-set&gt;</h3>
    ++
    ++<dl class="xml">
    ++  <dt>
    ++    sintaks:
    ++  </dt>
    ++
    ++  <dd>
    ++<pre class="stx">
    ++&lt;pin-set expiration="date"&gt;
    ++...
    ++&lt;/pin-set&gt;
    ++</pre>
    ++  </dd>
    ++
    ++  <dt>
    ++    Bisa Berisi:
    ++  </dt>
    ++
    ++  <dd>
    ++    Sejumlah <code><a href="#pin">&lt;pin&gt;</a></code>
    ++  </dd>
    ++
    ++  <dt>
    ++    Keterangan:
    ++  </dt>
    ++
    ++  <dd>
    ++    Satu set pin kunci publik. Agar koneksi aman bisa dipercaya, salah satu
    ++    kunci publik dalam rantai kepercayaan harus berada dalam set pin. Lihat
    ++    <code><a href="#pin">&lt;pin&gt;</a></code> untuk mengetahui format pin.
    ++  </dd>
    ++
    ++  <dt>
    ++    Atribut:
    ++  </dt>
    ++
    ++  <dd>
    ++    <dl class="attr">
    ++      <dt>
    ++        {@code expiration}
    ++      </dt>
    ++
    ++      <dd>
    ++        Tanggal, dalam format {@code yyyy-MM-dd}, pada saat dan setelah pin
    ++        kedaluwarsa, sehingga menonaktifkan penyematan. Jika atribut tidak disetel maka
    ++        pin tidak kedaluwarsa.
    ++        <p>
    ++          Tanggal kedaluwarsa membantu mencegah masalah konektivitas di aplikasi yang
    ++          tidak mengambil pembaruan untuk set pin mereka, misalnya karena pengguna
    ++          menonaktifkan pembaruan aplikasi.
    ++        </p>
    ++      </dd>
    ++    </dl>
    ++  </dd>
    ++</dl>
    ++
    ++<h3 id="pin">&lt;pin&gt;</h3>
    ++<dl class="xml">
    ++  <dt>
    ++    sintaks:
    ++  </dt>
    ++
    ++  <dd>
    ++<pre class="stx">
    ++&lt;pin digest=["SHA-256"]&gt;base64 encoded digest of X.509
    ++    SubjectPublicKeyInfo (SPKI)&lt;/pin&gt;
    ++</pre>
    ++  </dd>
    ++
    ++  <dt>
    ++    Atribut:
    ++  </dt>
    ++
    ++  <dd>
    ++    <dl class="attr">
    ++      <dt>
    ++        {@code digest}
    ++      </dt>
    ++
    ++      <dd>
    ++        Algoritme intisari yang digunakan untuk menghasilkan pin. Saat ini, hanya
    ++        {@code "SHA-256"} yang didukung.
    ++      </dd>
    ++    </dl>
    ++  </dd>
    ++</dl>
    +diff --git a/docs/html-intl/intl/id/training/basics/network-ops/data-saver.jd b/docs/html-intl/intl/id/training/basics/network-ops/data-saver.jd
    +new file mode 100644
    +index 0000000..abd4e43
    +--- /dev/null
    ++++ b/docs/html-intl/intl/id/training/basics/network-ops/data-saver.jd
    +@@ -0,0 +1,234 @@
    ++page.title=Data Saver
    ++metaDescription=Optimalisasi penggunaan data yang diaktifkan pengguna.
    ++page.keywords="android N", "data usage", "metered network"
    ++page.image=images/cards/card-nyc_2x.jpg
    ++@jd:body
    ++
    ++<div id="tb-wrapper">
    ++  <div id="tb">
    ++    <h2>
    ++      Dalam dokumen ini
    ++    </h2>
    ++
    ++    <ol>
    ++      <li>
    ++        <a href="#status">Memeriksa Preferensi Data Saver</a>
    ++        <ol>
    ++          <li>
    ++            <a href="#request-whitelist">Meminta izin daftar putih</a>
    ++          </li>
    ++        </ol>
    ++      </li>
    ++
    ++      <li>
    ++        <a href="#monitor-changes">Memantau Perubahan pada Preferensi
    ++        Data Saver</a>
    ++      </li>
    ++
    ++      <li>
    ++        <a href="#testing">Menguji dengan Perintah Android Debug Bridge</a>
    ++      </li>
    ++    </ol>
    ++  </div>
    ++</div>
    ++
    ++<p>
    ++  Selama penggunaan ponsel cerdas, biaya paket data seluler bisa saja
    ++  melebihi harga perangkat itu sendiri. Di N Developer Preview, pengguna bisa
    ++  mengaktifkan Data Saver berdasarkan lingkup perangkat untuk menghemat data, baik saat
    ++  roaming, mendekati akhir siklus penagihan, atau pada paket data prabayar kecil.
    ++</p>
    ++
    ++<p>
    ++  Bila pengguna mengaktifkan Data Saver di <strong>Settings</strong> dan perangkat
    ++  berada dalam jaringan berkuota, sistem akan memblokir penggunaan data latar belakang dan memberi tahu
    ++  aplikasi untuk menghemat penggunaan data latar depan bila memungkinkan. Pengguna bisa
    ++  memasukkan aplikasi tertentu ke daftar putih untuk memungkinkan penggunaan data berkuota bila Data
    ++  Saver diaktifkan.
    ++</p>
    ++
    ++<p>
    ++  N Developer Preview memperluas {@link android.net.ConnectivityManager}
    ++  API untuk menyediakan cara pada aplikasi untuk <a href="#status">menerima preferensi Data Saver
    ++  pengguna</a> dan <a href="#monitor-changes">memantau perubahan
    ++  preferensi</a>. Hal ini dianggap praktik terbaik bagi aplikasi untuk memeriksa apakah
    ++  pengguna telah mengaktifkan DataSaver dan berusaha membatasi penggunaan data latar depan dan
    ++  data latar belakang.
    ++</p>
    ++
    ++<h2 id="status">
    ++  Memeriksa Preferensi Data Saver
    ++</h2>
    ++
    ++<p>
    ++  Di N Developer Preview, aplikasi bisa menggunakan {@link
    ++  android.net.ConnectivityManager} API untuk menentukan pembatasan penggunaan data
    ++  apa yang sedang diterapkan. Metode {@code getRestrictBackgroundStatus()}
    ++  akan mengembalikan salah satu dari nilai berikut:
    ++</p>
    ++
    ++<dl>
    ++  <dt>
    ++    {@code RESTRICT_BACKGROUND_STATUS_DISABLED}
    ++  </dt>
    ++
    ++  <dd>
    ++    Data Saver dinonaktifkan.
    ++  </dd>
    ++
    ++  <dt>
    ++    {@code RESTRICT_BACKGROUND_STATUS_ENABLED}
    ++  </dt>
    ++
    ++  <dd>
    ++    Pengguna telah mengaktifkan Data Saver untuk aplikasi ini. Aplikasi harus berusaha membatasi
    ++    penggunaan data di latar depan dan dengan halus menangani pembatasan penggunaan
    ++    data latar belakang.
    ++  </dd>
    ++
    ++  <dt>
    ++    {@code RESTRICT_BACKGROUND_STATUS_WHITELISTED}
    ++  </dt>
    ++
    ++  <dd>
    ++    Pengguna telah mengaktifkan Data Saver namun aplikasi telah dimasukkan dalam daftar putih. Aplikasi harus
    ++    tetap berusaha membatasi penggunaan data latar belakang dan latar depan.
    ++  </dd>
    ++</dl>
    ++
    ++<p>
    ++  Hal ini dianggap praktik terbaik untuk membatasi penggunaan data bila perangkat
    ++  terhubung ke jaringan berkuota, meskipun Data Saver telah dinonaktifkan atau aplikasi
    ++  telah dimasukkan dalam daftar putih. Kode contoh berikut menggunakan {@link
    ++  android.net.ConnectivityManager#isActiveNetworkMetered
    ++  ConnectivityManager.isActiveNetworkMetered()} dan {@code
    ++  ConnectivityManager.getRestrictBackgroundStatus()} untuk menentukan berapa banyak data
    ++  yang harus digunakan aplikasi:
    ++</p>
    ++
    ++<pre>
    ++ConnectivityManager connMgr = (ConnectivityManager)
    ++        getSystemService(Context.CONNECTIVITY_SERVICE);
    ++// Checks if the device is on a metered network
    ++if (connMgr.isActiveNetworkMetered()) {
    ++  // Checks user’s Data Saver settings.
    ++  switch (connMgr.getRestrictBackgroundStatus()) {
    ++    case RESTRICT_BACKGROUND_STATUS_ENABLED:
    ++    // Background data usage is blocked for this app. Wherever possible,
    ++    // the app should also use less data in the foreground.
    ++
    ++    case RESTRICT_BACKGROUND_STATUS_WHITELISTED:
    ++    // The app is whitelisted. Wherever possible,
    ++    // the app should use less data in the foreground and background.
    ++
    ++    case RESTRICT_BACKGROUND_STATUS_DISABLED:
    ++    // Data Saver is disabled. Since the device is connected to a
    ++    // metered network, the app should use less data wherever possible.
    ++  }
    ++} else {
    ++  // The device is not on a metered network.
    ++  // Use data as required to perform syncs, downloads, and updates.
    ++}
    ++</pre>
    ++
    ++<h3 id="request-whitelist">
    ++  Meminta izin daftar putih
    ++</h3>
    ++
    ++<p>
    ++  Jika aplikasi Anda perlu menggunakan data di latar belakang, aplikasi bisa meminta izin
    ++  daftar putih dengan mengirim
    ++  <code>Settings.ACTION_IGNORE_BACKGROUND_DATA_RESTRICTIONS_SETTINGS</code>
    ++  yang mengandung URI dari nama paket aplikasi Anda: misalnya,
    ++  <code>package:MY_APP_ID</code>.
    ++</p>
    ++
    ++<p>
    ++  Mengirim intent dan URI akan membuka aplikasi <strong>Settings</strong> dan
    ++  menampilkan setelan penggunaan data untuk aplikasi Anda. Pengguna nanti bisa memutuskan apakah akan
    ++  mengaktifkan data latar belakang untuk aplikasi Anda. Sebelum Anda mengirim intent ini, sebaiknya
    ++  tanyakan kepada pengguna terlebih dahulu apakah mereka ingin membuka aplikasi
    ++  <strong>Settings</strong> untuk keperluan mengaktifkan penggunaan
    ++  data latar belakang.
    ++</p>
    ++
    ++<h2 id="monitor-changes">
    ++  Memantau Perubahan pada Preferensi Data Saver
    ++</h2>
    ++
    ++<p>
    ++  Aplikasi bisa memantau perubahan pada preferensi Data Saver dengan membuat {@link
    ++  android.content.BroadcastReceiver} untuk memantau {@code
    ++  ConnectivityManager.ACTION_RESTRICT_BACKGROUND_CHANGED} dan secara dinamis
    ++  mendaftarkan penerima pada {@link android.content.Context#registerReceiver
    ++  Context.registerReceiver()}. Bila menerima siaran ini, aplikasi harus
    ++  <a href="#status">memeriksa apakah preferensi Data Saver baru memengaruhi
    ++  izinnya</a> dengan memanggil {@code
    ++  ConnectivityManager.getRestrictBackgroundStatus()}.
    ++</p>
    ++
    ++<p class="note">
    ++  <strong>Catatan:</strong> Sistem hanya mengirim siaran ini ke aplikasi yang
    ++  secara dinamis mendaftar padanya dengan {@link
    ++  android.content.Context#registerReceiver Context.registerReceiver()}. Aplikasi
    ++  yang mendaftar untuk menerima siaran ini dalam manifes mereka
    ++  tidak akan menerimanya.
    ++</p>
    ++
    ++<h2 id="testing">
    ++  Menguji dengan Perintah Android Debug Bridge
    ++</h2>
    ++
    ++<a href="{@docRoot}tools/help/adb.html">Android Debug Bridge (ADB)</a>
    ++menyediakan beberapa perintah yang bisa Anda gunakan untuk memeriksa dan
    ++mengonfigurasi izin jaringan:
    ++
    ++<dl>
    ++  <dt>
    ++    <code>$ adb shell dumpsys netpolicy</code>
    ++  </dt>
    ++
    ++  <dd>
    ++    Menghasilkan laporan berisi setelan pembatasan jaringan latar belakang
    ++    global saat ini, UID paket saat ini di daftar putih, dan izin jaringan
    ++    untuk paket yang diketahui lainnya.
    ++  </dd>
    ++
    ++  <dt>
    ++    <code>$ adb shell cmd netpolicy</code>
    ++  </dt>
    ++
    ++  <dd>
    ++    Menampilkan daftar lengkap dari perintah Network Policy Manager (netpolicy).
    ++  </dd>
    ++
    ++  <dt>
    ++    <code>$ adb shell cmd netpolicy set restrict-background
    ++    &lt;boolean&gt;</code>
    ++  </dt>
    ++
    ++  <dd>
    ++    Mengaktifkan atau menonaktifkan mode Data Saver saat meneruskan <code>true</code> atau
    ++ <code>false</code>, masing-masing.
    ++  </dd>
    ++
    ++  <dt>
    ++    <code>$ adb shell cmd netpolicy add restrict-background-whitelist
    ++    &lt;UID&gt;</code>
    ++  </dt>
    ++
    ++  <dd>
    ++    Menambahkan UID paket tertentu ke daftar putih untuk mengizinkan penggunaan data berkuota
    ++  di latar belakang.
    ++  </dd>
    ++
    ++  <dt>
    ++    <code>$ adb shell cmd netpolicy remove restrict-background-whitelist
    ++    &lt;UID&gt;</code>
    ++  </dt>
    ++
    ++  <dd>
    ++    Membuang UID paket tertentu dari daftar putih untuk memblokir
    ++    penggunaan data berkuota di latar belakang saat Data Saver diaktifkan.
    ++  </dd>
    ++</dl>
    +diff --git a/docs/html-intl/intl/id/training/material/animations.jd b/docs/html-intl/intl/id/training/material/animations.jd
    +new file mode 100644
    +index 0000000..e57a03f
    +--- /dev/null
    ++++ b/docs/html-intl/intl/id/training/material/animations.jd
    +@@ -0,0 +1,550 @@
    ++page.title=Mendefinisikan Animasi Custom
    ++
    ++@jd:body
    ++
    ++<div id="tb-wrapper">
    ++<div id="tb">
    ++<h2>Pelajaran ini mengajarkan Anda cara</h2>
    ++<ol>
    ++  <li><a href="#Touch">Menyesuaikan Umpan Balik Sentuh</a></li>
    ++  <li><a href="#Reveal">Menggunakan Reveal Effect</a></li>
    ++  <li><a href="#Transitions">Menyesuaikan Transisi Aktivitas</a></li>
    ++  <li><a href="#ViewState">Menganimasikan Perubahan Status Tampilan</a></li>
    ++  <li><a href="#AnimVector">Menganimasikan Drawable Vektor</a></li>
    ++</ol>
    ++<h2>Anda juga harus membaca</h2>
    ++<ul>
    ++  <li><a href="http://www.google.com/design/spec">Spesifikasi desain bahan</a></li>
    ++  <li><a href="{@docRoot}design/material/index.html">Desain bahan di Android</a></li>
    ++</ul>
    ++</div>
    ++</div>
    ++
    ++
    ++<p>Animasi dalam desain bahan memberi pengguna umpan balik tentang tindakannya dan menyediakan
    ++kesinambungan visual saat pengguna berinteraksi dengan aplikasi Anda. Tema bahan menyediakan beberapa animasi default
    ++untuk tombol dan transisi aktivitas, dan Android 5.0 (API level 21) ke atas memungkinkan Anda menyesuaikan
    ++animasi ini dan membuat yang baru:</p>
    ++
    ++<ul>
    ++<li>Umpan balik sentuh</li>
    ++<li>Singkap Melingkar</li>
    ++<li>Transisi aktivitas</li>
    ++<li>Gerakan melengkung</li>
    ++<li>Perubahan status tampilan</li>
    ++</ul>
    ++
    ++
    ++<h2 id="Touch">Menyesuaikan Umpan Balik Sentuh</h2>
    ++
    ++<p>Umpan balik sentuh dalam desain bahan menyediakan konfirmasi visual seketika pada
    ++titik kontak bila pengguna berinteraksi dengan elemen UI. Animasi umpan balik sentuh default
    ++untuk tombol menggunakan kelas {@link android.graphics.drawable.RippleDrawable} baru, yang bertransisi
    ++di antara berbagai status dengan efek riak.</p>
    ++
    ++<p>Di sebagian besar kasus, Anda harus menerapkan fungsionalitas ini dalam XML tampilan dengan menetapkan
    ++latar belakang tampilan sebagai:</p>
    ++
    ++<ul>
    ++<li><code>?android:attr/selectableItemBackground</code> untuk riak berbatas.</li>
    ++<li><code>?android:attr/selectableItemBackgroundBorderless</code> untuk riak yang meluas ke luar
    ++tampilan. Latar belakang ini akan digambar di atas, dan dibatasi oleh, induk tampilan terdekat dengan
    ++latar belakang non-null.</li>
    ++</ul>
    ++
    ++<p class="note"><strong>Catatan:</strong> <code>selectableItemBackgroundBorderless</code> adalah
    ++atribut baru yang diperkenalkan di API level 21.</p>
    ++
    ++
    ++<p>Atau, Anda bisa mendefinisikan {@link android.graphics.drawable.RippleDrawable}
    ++sebagai sumber daya XML dengan menggunakan elemen <code>ripple</code>.</p>
    ++
    ++<p>Anda bisa menetapkan warna ke objek-objek {@link android.graphics.drawable.RippleDrawable}. Untuk mengubah
    ++warna default umpan balik sentuh, gunakan atribut <code>android:colorControlHighlight</code>
    ++tema.</p>
    ++
    ++<p>Untuk informasi selengkapnya, lihat referensi API bagi kelas {@link
    ++android.graphics.drawable.RippleDrawable}.</p>
    ++
    ++
    ++<h2 id="Reveal">Menggunakan Reveal Effect</h2>
    ++
    ++<p>Animasi singkap memberi pengguna kesinambungan visual saat menampilkan atau menyembunyikan sekelompok
    ++elemen UI. Metode {@link android.view.ViewAnimationUtils#createCircularReveal
    ++ViewAnimationUtils.createCircularReveal()} memungkinkan Anda menganimasikan lingkaran terpangkas
    ++untuk memperlihatkan atau menyembunyikan tampilan.</p>
    ++
    ++<p>Untuk memperlihatkan tampilan yang sebelumnya tidak terlihat dengan menggunakan efek ini:</p>
    ++
    ++<pre>
    ++// previously invisible view
    ++View myView = findViewById(R.id.my_view);
    ++
    ++// get the center for the clipping circle
    ++int cx = (myView.getLeft() + myView.getRight()) / 2;
    ++int cy = (myView.getTop() + myView.getBottom()) / 2;
    ++
    ++// get the final radius for the clipping circle
    ++int finalRadius = Math.max(myView.getWidth(), myView.getHeight());
    ++
    ++// create the animator for this view (the start radius is zero)
    ++Animator anim =
    ++    ViewAnimationUtils.createCircularReveal(myView, cx, cy, 0, finalRadius);
    ++
    ++// make the view visible and start the animation
    ++myView.setVisibility(View.VISIBLE);
    ++anim.start();
    ++</pre>
    ++
    ++<p>Untuk menyembunyikan sebuah tampilan yang sebelumnya terlihat dengan menggunakan efek ini:</p>
    ++
    ++<pre>
    ++// previously visible view
    ++final View myView = findViewById(R.id.my_view);
    ++
    ++// get the center for the clipping circle
    ++int cx = (myView.getLeft() + myView.getRight()) / 2;
    ++int cy = (myView.getTop() + myView.getBottom()) / 2;
    ++
    ++// get the initial radius for the clipping circle
    ++int initialRadius = myView.getWidth();
    ++
    ++// create the animation (the final radius is zero)
    ++Animator anim =
    ++    ViewAnimationUtils.createCircularReveal(myView, cx, cy, initialRadius, 0);
    ++
    ++// make the view invisible when the animation is done
    ++anim.addListener(new AnimatorListenerAdapter() {
    ++    &#64;Override
    ++    public void onAnimationEnd(Animator animation) {
    ++        super.onAnimationEnd(animation);
    ++        myView.setVisibility(View.INVISIBLE);
    ++    }
    ++});
    ++
    ++// start the animation
    ++anim.start();
    ++</pre>
    ++
    ++
    ++<h2 id="Transitions">Menyesuaikan Transisi Aktivitas</h2>
    ++
    ++<!-- shared transition video -->
    ++<div style="width:290px;margin-left:35px;float:right">
    ++  <div class="framed-nexus5-port-span-5">
    ++  <video class="play-on-hover" autoplay="">
    ++    <source src="{@docRoot}design/material/videos/ContactsAnim.mp4">
    ++    <source src="{@docRoot}design/material/videos/ContactsAnim.webm">
    ++    <source src="{@docRoot}design/material/videos/ContactsAnim.ogv">
    ++  </video>
    ++  </div>
    ++  <div style="font-size:10pt;margin-left:20px;margin-bottom:30px">
    ++    <p class="img-caption" style="margin-top:3px;margin-bottom:10px"><strong>Gambar 1</strong> - Transisi
    ++    dengan elemen bersama.</p>
    ++    <em>Untuk memutar ulang film, klik layar perangkat</em>
    ++  </div>
    ++</div>
    ++
    ++<p>Transisi aktivitas dalam aplikasi desain bahan memberikan koneksi visual antar berbagai status
    ++melalui gerakan dan transformasi di antara elemen umum. Anda bisa menetapkan animasi custom untuk
    ++masuk ke dan keluar dari transisi dan untuk transisi elemen bersama di antara aktivitas.</p>
    ++
    ++<ul>
    ++<li>Transisi <strong>masuk</strong> menentukan cara tampilan di aktivitas memasuki suatu babak.
    ++misalnya, dalam transisi masuk <em>explode</em>, tampilan memasuki babak dari sisi luar
    ++dan melayang masuk ke arah tengah layar.</li>
    ++
    ++<li>Transisi <strong>keluar</strong> menentukan cara tampilan di aktivitas keluar dari suatu babak. Misalnya
    ++, dalam transisi keluar <em>explode</em>, tampilan akan keluar dari babak dari bagian
    ++tengahnya.</li>
    ++
    ++<li>Transisi <strong>elemen bersama</strong> menentukan cara menggunakan bersama suatu tampilan
    ++oleh dua transisi aktivitas di antara aktivitas-aktivitas ini. Misalnya, jika dua aktivitas memiliki
    ++gambar yang sama dengan posisi dan ukuran berbeda, transisi elemen bersama <em>changeImageTransform</em>
    ++mentransformasikan dan menskalakan gambar secara mulus di antara aktivitas-aktivitas ini.</li>
    ++</ul>
    ++
    ++<p>Android 5.0 (API level 21) mendukung transisi masuk dan transisi keluar ini:</p>
    ++
    ++<ul>
    ++<li><em>explode</em> - Memindahkan tampilan masuk ke atau keluar dari tengah babak.</li>
    ++<li><em>slide</em> - Memindahkan tampilan masuk ke atau keluar dari salah satu tepi babak.</li>
    ++<li><em>fade</em> - Menambahkan atau menghapus tampilan dari babak dengan mengubah opasitasnya.</li>
    ++</ul>
    ++
    ++<p>Transisi apa pun yang memperluas kelas {@link android.transition.Visibility} didukung
    ++sebagai transisi masuk atau transisi keluar. Untuk informasi selengkapnya, lihat referensi API untuk kelas
    ++{@link android.transition.Transition}.</p>
    ++
    ++<p>Android 5.0 (API level 21) juga mendukung transisi elemen bersama ini:</p>
    ++
    ++<ul>
    ++<li><em>changeBounds</em> - Menganimasikan perubahan pada batas-batas layout tampilan target.</li>
    ++<li><em>changeClipBounds</em> - Menganimasikan perubahan pada batas-batas pemangkasan tampilan target.</li>
    ++<li><em>changeTransform</em> - Menganimasikan perubahan pada skala dan rotasi tampilan target.</li>
    ++<li><em>changeImageTransform</em> - Menganimasikan perubahan pada ukuran dan skala gambar target.</li>
    ++</ul>
    ++
    ++<p>Bila Anda mengaktifkan transisi aktivitas dalam aplikasi, transisi memudar-silang default akan
    ++diaktifkan di antara aktivitas masuk dan aktivitas keluar.</p>
    ++
    ++<img src="{@docRoot}training/material/images/SceneTransition.png" alt="" width="600" height="405" style="margin-top:20px" />
    ++<p class="img-caption">
    ++  <strong>Gambar 2</strong> - Transisi babak dengan satu elemen bersama.
    ++</p>
    ++
    ++<h3>Menetapkan transisi custom</h3>
    ++
    ++<p>Pertama, aktifkan transisi konten jendela dengan atribut <code>android:windowContentTransitions</code>
    ++bila Anda mendefinisikan gaya yang mewarisi tema bahan. Anda juga bisa menetapkan
    ++transisi-transisi masuk, keluar, dan elemen bersama dalam definisi gaya:</p>
    ++
    ++<pre>
    ++&lt;style name="BaseAppTheme" parent="android:Theme.Material">
    ++  &lt;!-- enable window content transitions -->
    ++  &lt;item name="android:windowContentTransitions">true&lt;/item>
    ++
    ++  &lt;!-- specify enter and exit transitions -->
    ++  &lt;item name="android:windowEnterTransition">@transition/explode&lt;/item>
    ++  &lt;item name="android:windowExitTransition">@transition/explode&lt;/item>
    ++
    ++  &lt;!-- specify shared element transitions -->
    ++  &lt;item name="android:windowSharedElementEnterTransition">
    ++    &#64;transition/change_image_transform&lt;/item>
    ++  &lt;item name="android:windowSharedElementExitTransition">
    ++    &#64;transition/change_image_transform&lt;/item>
    ++&lt;/style>
    ++</pre>
    ++
    ++<p>Transisi <code>change_image_transform</code> dalam contoh ini didefinisikan sebagai berikut:</p>
    ++
    ++<pre>
    ++&lt;!-- res/transition/change_image_transform.xml -->
    ++&lt;!-- (see also Shared Transitions below) -->
    ++&lt;transitionSet xmlns:android="http://schemas.android.com/apk/res/android">
    ++  &lt;changeImageTransform/>
    ++&lt;/transitionSet>
    ++</pre>
    ++
    ++<p>Elemen <code>changeImageTransform</code> menunjukkan
    ++kelas {@link android.transition.ChangeImageTransform}. Untuk informasi selengkapnya, lihat referensi
    ++API untuk {@link android.transition.Transition}.</p>
    ++
    ++<p>Sebaliknya, untuk mengaktifkan transisi konten jendela dalam kode Anda, panggil
    ++metode {@link android.view.Window#requestFeature Window.requestFeature()}:</p>
    ++
    ++<pre>
    ++// inside your activity (if you did not enable transitions in your theme)
    ++getWindow().requestFeature(Window.FEATURE_CONTENT_TRANSITIONS);
    ++
    ++// set an exit transition
    ++getWindow().setExitTransition(new Explode());
    ++</pre>
    ++
    ++<p>Untuk menetapkan transisi dalam kode Anda, panggil metode-metode ini dengan objek {@link
    ++android.transition.Transition}:</p>
    ++
    ++<ul>
    ++  <li>{@link android.view.Window#setEnterTransition Window.setEnterTransition()}</li>
    ++  <li>{@link android.view.Window#setExitTransition Window.setExitTransition()}</li>
    ++  <li>{@link android.view.Window#setSharedElementEnterTransition
    ++      Window.setSharedElementEnterTransition()}</li>
    ++  <li>{@link android.view.Window#setSharedElementExitTransition
    ++      Window.setSharedElementExitTransition()}</li>
    ++</ul>
    ++
    ++<p>Metode {@link android.view.Window#setExitTransition setExitTransition()} dan {@link
    ++android.view.Window#setSharedElementExitTransition setSharedElementExitTransition()} mendefinisikan
    ++transisi keluar untuk aktivitas yang memanggil. Metode {@link android.view.Window#setEnterTransition
    ++setEnterTransition()} dan {@link android.view.Window#setSharedElementEnterTransition
    ++setSharedElementEnterTransition()} mendefinisikan transisi masuk untuk aktivitas yang dipanggil.</p>
    ++
    ++<p>Untuk mendapatkan efek penuh sebuah transisi, Anda harus mengaktifkan transisi konten jendela pada
    ++aktivitas yang memanggil maupun aktivitas yang dipanggil. Jika tidak, aktivitas yang memanggil akan memulai transisi keluar,
    ++namun kemudian Anda akan melihat transisi jendela (seperti mengelupas atau memudar).</p>
    ++
    ++<p>Untuk memulai transisi masuk sesegera mungkin, gunakan metode
    ++{@link android.view.Window#setAllowEnterTransitionOverlap Window.setAllowEnterTransitionOverlap()}
    ++pada aktivitas yang dipanggil. Ini memungkinkan Anda mendapatkan transisi masuk yang lebih dramatis.</p>
    ++
    ++<h3>Memulai aktivitas dengan menggunakan transisi</h3>
    ++
    ++<p>Jika Anda mengaktifkan transisi dan mengatur transisi keluar untuk aktivitas, transisi itu akan diaktifkan
    ++bila Anda menjalankan aktivitas lain sebagai berikut:</p>
    ++
    ++<pre>
    ++startActivity(intent,
    ++              ActivityOptions.makeSceneTransitionAnimation(this).toBundle());
    ++</pre>
    ++
    ++<p>Jika Anda telah mengatur transisi masuk untuk aktivitas kedua, transisi juga akan diaktifkan
    ++bila aktivitas dimulai. Untuk menonaktifkan transisi bila Anda memulai aktivitas lain, sediakan
    ++bundel opsi <code>null</code>.</p>
    ++
    ++<h3>Memulai aktivitas dengan satu elemen bersama</h3>
    ++
    ++<p>Untuk membuat animasi transisi layar di antara dua aktivitas yang memiliki satu elemen bersama:</p>
    ++
    ++<ol>
    ++<li>Aktifkan transisi konten jendela dalam tema Anda.</li>
    ++<li>Tetapkan transisi elemen bersama dalam gaya Anda.</li>
    ++<li>Definisikan transisi Anda sebagai sumber daya XML.</li>
    ++<li>Tetapkan nama umum pada elemen bersama dalam kedua layout dengan
    ++    atribut <code>android:transitionName</code>.</li>
    ++<li>Gunakan metode {@link android.app.ActivityOptions#makeSceneTransitionAnimation
    ++ActivityOptions.makeSceneTransitionAnimation()}.</li>
    ++</ol>
    ++
    ++<pre>
    ++// get the element that receives the click event
    ++final View imgContainerView = findViewById(R.id.img_container);
    ++
    ++// get the common element for the transition in this activity
    ++final View androidRobotView = findViewById(R.id.image_small);
    ++
    ++// define a click listener
    ++imgContainerView.setOnClickListener(new View.OnClickListener() {
    ++    &#64;Override
    ++    public void onClick(View view) {
    ++        Intent intent = new Intent(this, Activity2.class);
    ++        // create the transition animation - the images in the layouts
    ++        // of both activities are defined with android:transitionName="robot"
    ++        ActivityOptions options = ActivityOptions
    ++            .makeSceneTransitionAnimation(this, androidRobotView, "robot");
    ++        // start the new activity
    ++        startActivity(intent, options.toBundle());
    ++    }
    ++});
    ++</pre>
    ++
    ++<p>Untuk tampilan dinamis bersama yang Anda hasilkan dalam kode, gunakan
    ++metode {@link android.view.View#setTransitionName View.setTransitionName()} untuk menetapkan
    ++nama elemen umum di kedua aktivitas.</p>
    ++
    ++<p>Untuk membalik animasi transisi babak bila Anda menyelesaikan aktivitas kedua, panggil metode
    ++{@link android.app.Activity#finishAfterTransition Activity.finishAfterTransition()}
    ++sebagai ganti {@link android.app.Activity#finish Activity.finish()}.</p>
    ++
    ++<h3>Memulai aktivitas dengan beberapa elemen bersama</h3>
    ++
    ++<p>Untuk membuat animasi transisi babak antara dua aktivitas yang memiliki lebih dari satu
    ++elemen bersama, definisikan elemen bersama di kedua layout dengan atribut <code>android:transitionName</code>
    ++ (atau gunakan metode {@link android.view.View#setTransitionName View.setTransitionName()}
    ++di kedua aktivitas), dan buat sebuah objek {@link android.app.ActivityOptions} sebagai berikut:</p>
    ++
    ++<pre>
    ++ActivityOptions options = ActivityOptions.makeSceneTransitionAnimation(this,
    ++        Pair.create(view1, "agreedName1"),
    ++        Pair.create(view2, "agreedName2"));
    ++</pre>
    ++
    ++
    ++<h2 id="CurvedMotion">Menggunakan Gerakan Melengkung</h2>
    ++
    ++<p>Animasi dalam desain bahan mengandalkan kurva untuk pola interpolasi waktu dan
    ++gerakan spasial. Dengan Android 5.0 (API level 21) ke atas, Anda bisa mendefinisikan kurva pewaktuan custom dan
    ++pola gerakan melengkung untuk animasi.</p>
    ++
    ++<p>Kelas {@link android.view.animation.PathInterpolator} adalah interpolator baru berdasarkan sebuah
    ++kurva Bézier atau objek {@link android.graphics.Path}. Interpolator ini menetapkan kurva gerakan
    ++dalam bujur sangkar 1x1, dengan titik-titik jangkar di (0,0) dan (1,1) dan titik-titik kontrol sebagaimana ditetapkan menggunakan
    ++argumen konstruktor. Anda juga bisa mendefinisikan interpolator path sebagai sumber daya XML:</p>
    ++
    ++<pre>
    ++&lt;pathInterpolator xmlns:android="http://schemas.android.com/apk/res/android"
    ++    android:controlX1="0.4"
    ++    android:controlY1="0"
    ++    android:controlX2="1"
    ++    android:controlY2="1"/>
    ++</pre>
    ++
    ++<p>Sistem menyediakan sumber daya XML untuk tiga kurva dasar dalam
    ++spesifikasi desain bahan:</p>
    ++
    ++<ul>
    ++  <li><code>&#64;interpolator/fast_out_linear_in.xml</code></li>
    ++  <li><code>&#64;interpolator/fast_out_slow_in.xml</code></li>
    ++  <li><code>&#64;interpolator/linear_out_slow_in.xml</code></li>
    ++</ul>
    ++
    ++<p>Anda bisa meneruskan objek {@link android.view.animation.PathInterpolator} ke metode {@link
    ++android.animation.Animator#setInterpolator Animator.setInterpolator()}.</p>
    ++
    ++<p>Kelas {@link android.animation.ObjectAnimator} memiliki konstruktor-konstruktor baru yang memungkinkan Anda menganimasikan
    ++koordinat bersama sebuah path dengan menggunakan dua atau beberapa properti sekaligus. Misalnya, animator berikut
    ++menggunakan objek {@link android.graphics.Path} untuk menganimasikan properti X dan Y sebuah tampilan:</p>
    ++
    ++<pre>
    ++ObjectAnimator mAnimator;
    ++mAnimator = ObjectAnimator.ofFloat(view, View.X, View.Y, path);
    ++...
    ++mAnimator.start();
    ++</pre>
    ++
    ++
    ++<h2 id="ViewState">Menganimasikan Perubahan Status Tampilan</h2>
    ++
    ++<p>Kelas {@link android.animation.StateListAnimator} memungkinkan Anda mendefinisikan animator yang berjalan bila
    ++status tampilan berubah. Contoh berikut menampilkan cara mendefinisikan {@link
    ++android.animation.StateListAnimator} sebagai sumber daya XML:</p>
    ++
    ++<pre>
    ++&lt;!-- animate the translationZ property of a view when pressed -->
    ++&lt;selector xmlns:android="http://schemas.android.com/apk/res/android">
    ++  &lt;item android:state_pressed="true">
    ++    &lt;set>
    ++      &lt;objectAnimator android:propertyName="translationZ"
    ++        android:duration="@android:integer/config_shortAnimTime"
    ++        android:valueTo="2dp"
    ++        android:valueType="floatType"/>
    ++        &lt;!-- you could have other objectAnimator elements
    ++             here for "x" and "y", or other properties -->
    ++    &lt;/set>
    ++  &lt;/item>
    ++  &lt;item android:state_enabled="true"
    ++    android:state_pressed="false"
    ++    android:state_focused="true">
    ++    &lt;set>
    ++      &lt;objectAnimator android:propertyName="translationZ"
    ++        android:duration="100"
    ++        android:valueTo="0"
    ++        android:valueType="floatType"/>
    ++    &lt;/set>
    ++  &lt;/item>
    ++&lt;/selector>
    ++</pre>
    ++
    ++<p>Untuk menyertakan animasi status tampilan custom ke tampilan, definisikan animator menggunakan
    ++elemen <code>selector</code> dalam sumber daya file XML sebagaimana dalam contoh ini, dan tetapkan ke
    ++tampilan Anda dengan atribut <code>android:stateListAnimator</code>. Untuk menetapkan animator daftar status
    ++ke sebuah tampilan dalam kode Anda, gunakan metode {@link android.animation.AnimatorInflater#loadStateListAnimator
    ++AnimationInflater.loadStateListAnimator()}, dan tetapkan animator ke tampilan dengan
    ++metode {@link android.view.View#setStateListAnimator View.setStateListAnimator()}.</p>
    ++
    ++<p>Bila tema Anda memperluas tema bahan, tombol-tombol akan memiliki animasi Z secara default. Untuk menghindari
    ++perilaku ini di tombol Anda, aturlah atribut <code>android:stateListAnimator</code> ke
    ++<code>@null</code>.</p>
    ++
    ++<p>Kelas {@link android.graphics.drawable.AnimatedStateListDrawable} memungkinkan Anda membuat drawable
    ++yang menampilkan animasi di antara perubahan status tampilan terkait. Sebagian widget sistem di
    ++Android 5.0 menggunakan animasi ini secara default. Contoh berikut menampilkan cara
    ++mendefinisikan {@link android.graphics.drawable.AnimatedStateListDrawable} sebagai sumber daya XML:</p>
    ++
    ++<pre>
    ++&lt;!-- res/drawable/myanimstatedrawable.xml -->
    ++&lt;animated-selector
    ++    xmlns:android="http://schemas.android.com/apk/res/android">
    ++
    ++    &lt;!-- provide a different drawable for each state-->
    ++    &lt;item android:id="@+id/pressed" android:drawable="@drawable/drawableP"
    ++        android:state_pressed="true"/>
    ++    &lt;item android:id="@+id/focused" android:drawable="@drawable/drawableF"
    ++        android:state_focused="true"/>
    ++    &lt;item android:id="@id/default"
    ++        android:drawable="@drawable/drawableD"/>
    ++
    ++    &lt;!-- specify a transition -->
    ++    &lt;transition android:fromId="@+id/default" android:toId="@+id/pressed">
    ++        &lt;animation-list>
    ++            &lt;item android:duration="15" android:drawable="@drawable/dt1"/>
    ++            &lt;item android:duration="15" android:drawable="@drawable/dt2"/>
    ++            ...
    ++        &lt;/animation-list>
    ++    &lt;/transition>
    ++    ...
    ++&lt;/animated-selector>
    ++</pre>
    ++
    ++
    ++<h2 id="AnimVector">Menganimasikan Drawable Vektor</h2>
    ++
    ++<p><a href="{@docRoot}training/material/drawables.html#VectorDrawables">Drawable Vektor </a>
    ++bisa diubah skalanya tanpa kehilangan definisi. Kelas {@link android.graphics.drawable.AnimatedVectorDrawable}
    ++memungkinkan Anda menganimasikan properti drawable vektor.</p>
    ++
    ++<p>Anda biasanya mendefinisikan drawable vektor yang dianimasikan dalam tiga file XML:</p>
    ++
    ++<ul>
    ++<li>Drawable vektor dengan elemen <code>&lt;vector&gt;</code> dalam
    ++<code>res/drawable/</code></li>
    ++<li>Drawable vektor animasi dengan elemen <code>&lt;animated-vector&gt;</code> dalam
    ++<code>res/drawable/</code></li>
    ++<li>Satu atau beberapa animator objek dengan elemen <code>&lt;objectAnimator&gt;</code> dalam
    ++<code>res/anim/</code></li>
    ++</ul>
    ++
    ++<p>Drawable vektor yang dianimasikan bisa menganimasikan atribut elemen <code>&lt;group&gt;</code> dan
    ++<code>&lt;path&gt;</code>. Elemen <code>&lt;group&gt;</code> mendefinisikan satu set
    ++path atau subgrup, dan elemen <code>&lt;path&gt;</code> mendefinisikan path yang harus digambar.</p>
    ++
    ++<p>Bila Anda mendefinisikan drawable vektor yang ingin dianimasikan, gunakan atribut <code>android:name</code>
    ++untuk menetapkan nama unik ke grup dan path, sehingga Anda bisa merujuknya dari
    ++definisi animator Anda. Misalnya:</p>
    ++
    ++<pre>
    ++&lt;!-- res/drawable/vectordrawable.xml -->
    ++&lt;vector xmlns:android="http://schemas.android.com/apk/res/android"
    ++    android:height="64dp"
    ++    android:width="64dp"
    ++    android:viewportHeight="600"
    ++    android:viewportWidth="600">
    ++    &lt;group
    ++        <strong>android:name="rotationGroup"</strong>
    ++        android:pivotX="300.0"
    ++        android:pivotY="300.0"
    ++        android:rotation="45.0" >
    ++        &lt;path
    ++            <strong>android:name="v"</strong>
    ++            android:fillColor="#000000"
    ++            android:pathData="M300,70 l 0,-70 70,70 0,0 -70,70z" />
    ++    &lt;/group>
    ++&lt;/vector>
    ++</pre>
    ++
    ++<p>Definisi drawable vektor yang dianimasikan merujuk pada grup dan path dalam drawable vektor
    ++berdasarkan namanya:</p>
    ++
    ++<pre>
    ++&lt;!-- res/drawable/animvectordrawable.xml -->
    ++&lt;animated-vector xmlns:android="http://schemas.android.com/apk/res/android"
    ++  android:drawable="@drawable/vectordrawable" >
    ++    &lt;target
    ++        android:name="rotationGroup"
    ++        android:animation="@anim/rotation" />
    ++    &lt;target
    ++        android:name="v"
    ++        android:animation="@anim/path_morph" />
    ++&lt;/animated-vector>
    ++</pre>
    ++
    ++<p>Definisi animasi menyatakan objek {@link android.animation.ObjectAnimator} atau {@link
    ++android.animation.AnimatorSet}. Animator pertama dalam contoh ini memutar
    ++grup target sebanyak 360 derajat:</p>
    ++
    ++<pre>
    ++&lt;!-- res/anim/rotation.xml -->
    ++&lt;objectAnimator
    ++    android:duration="6000"
    ++    android:propertyName="rotation"
    ++    android:valueFrom="0"
    ++    android:valueTo="360" />
    ++</pre>
    ++
    ++<p>Animator kedua dalam contoh ini perlahan-lahan mengubah bentuk path drawable vektor dari satu bentuk ke
    ++bentuk yang lain. Kedua path harus kompatibel untuk morphing: keduanya harus memiliki jumlah perintah yang sama
    ++dan jumlah parameter yang sama untuk setiap perintah.</p>
    ++
    ++<pre>
    ++&lt;!-- res/anim/path_morph.xml -->
    ++&lt;set xmlns:android="http://schemas.android.com/apk/res/android">
    ++    &lt;objectAnimator
    ++        android:duration="3000"
    ++        android:propertyName="pathData"
    ++        android:valueFrom="M300,70 l 0,-70 70,70 0,0   -70,70z"
    ++        android:valueTo="M300,70 l 0,-70 70,0  0,140 -70,0 z"
    ++        android:valueType="pathType" />
    ++&lt;/set>
    ++</pre>
    ++
    ++<p>Untuk informasi selengkapnya, lihat referensi API bagi {@link
    ++android.graphics.drawable.AnimatedVectorDrawable}.</p>
    +diff --git a/docs/html-intl/intl/id/training/material/compatibility.jd b/docs/html-intl/intl/id/training/material/compatibility.jd
    +new file mode 100644
    +index 0000000..ef444c3
    +--- /dev/null
    ++++ b/docs/html-intl/intl/id/training/material/compatibility.jd
    +@@ -0,0 +1,168 @@
    ++page.title=Mempertahankan Kompatibilitas
    ++
    ++@jd:body
    ++
    ++<div id="tb-wrapper">
    ++<div id="tb">
    ++<h2>Pelajaran ini mengajarkan Anda cara</h2>
    ++<ol>
    ++  <li><a href="#Theme">Mendefinisikan Gaya Alternatif</a></li>
    ++  <li><a href="#Layouts">Menyediakan Layout Alternatif</a></li>
    ++  <li><a href="#SupportLib">Menggunakan Support Library</a></li>
    ++  <li><a href="#CheckVersion">Memeriksa Versi Sistem</a></li>
    ++</ol>
    ++<h2>Anda juga harus membaca</h2>
    ++<ul>
    ++  <li><a href="http://www.google.com/design/spec">Spesifikasi desain bahan</a></li>
    ++  <li><a href="{@docRoot}design/material/index.html">Desain bahan di Android</a></li>
    ++</ul>
    ++</div>
    ++</div>
    ++
    ++
    ++<p>Sebagian fitur desain bahan seperti tema bahan dan transisi aktivitas custom
    ++hanya tersedia pada Android 5.0 (API level 21) ke atas. Akan tetapi, Anda bisa mendesain aplikasi untuk menggunakan
    ++fitur-fitur ini saat dijalankan pada perangkat yang mendukung desain bahan dan tetap kompatibel
    ++dengan perangkat yang menjalankan rilis Android sebelumnya.</p>
    ++
    ++
    ++<h2 id="Theme">Mendefinisikan Gaya Alternatif</h2>
    ++
    ++<p>Anda bisa mengonfigurasi aplikasi untuk menggunakan tema bahan pada perangkat yang mendukungnya dan mengembalikan
    ++ke tema lama pada perangkat yang menjalankan versi Android terdahulu:</p>
    ++
    ++<ol>
    ++<li>Definisikan tema yang mewarisi tema lama (seperti Holo) di
    ++    <code>res/values/styles.xml</code>.</li>
    ++<li>Definisikan tema bernama sama yang mewarisi tema bahan di
    ++    <code>res/values-v21/styles.xml</code>.</li>
    ++<li>Atur tema ini sebagai tema aplikasi Anda dalam file manifes.</li>
    ++</ol>
    ++
    ++<p class="note"><strong>Catatan:</strong>
    ++Jika aplikasi Anda menggunakan tema bahan namun tidak menyediakan tema alternatif dengan cara ini,
    ++aplikasi itu tidak akan berjalan pada versi Android sebelum 5.0.
    ++</p>
    ++
    ++
    ++<h2 id="Layouts">Menyediakan Layout Alternatif</h2>
    ++
    ++<p>Jika layout yang Anda desain sesuai dengan panduan desain bahan tidak menggunakan salah satu
    ++atribut XML baru yang diperkenalkan di Android 5.0 (API level 21), layout itu akan berfungsi pada
    ++versi Android sebelumnya. Jika tidak, Anda bisa menyediakan layout alternatif. Anda juga bisa menyediakan
    ++layout alternatif untuk menyesuaikan cara aplikasi ditampilkan pada versi Android terdahulu.</p>
    ++
    ++<p>Buatlah file layout untuk Android 5.0 (API level 21) dalam <code>res/layout-v21/</code> dan
    ++file layout alternatif untuk versi Android terdahulu dalam <code>res/layout/</code>.
    ++Misalnya, <code>res/layout/my_activity.xml</code> adalah layout alternatif untuk
    ++<code>res/layout-v21/my_activity.xml</code>.</p>
    ++
    ++<p>Untuk menghindari duplikasi kode, definisikan gaya dalam <code>res/values/</code>, modifikasi
    ++gaya di <code>res/values-v21/</code> untuk API baru, dan gunakan pewarisan gaya, dengan mendefinisikan
    ++gaya dasar di <code>res/values/</code> dan mewarisi gaya di <code>res/values-v21/</code>.</p>
    ++
    ++
    ++<h2 id="SupportLib">Menggunakan Support Library</h2>
    ++
    ++<p><a href="{@docRoot}tools/support-library/features.html#v7">v7 Support Library</a>
    ++r21 ke atas menyertakan fitur desain bahan berikut:</p>
    ++
    ++<ul>
    ++<li><a href="{@docRoot}training/material/theme.html">Gaya desain bahan</a> untuk beberapa widget sistem
    ++    bila Anda menerapkan salah satu tema <code>Theme.AppCompat</code>.</li>
    ++<li><a href="{@docRoot}training/material/theme.html#ColorPalette">Atribut tema palet warna</a>
    ++    dalam tema <code>Theme.AppCompat</code>.</li>
    ++<li>Widget {@link android.support.v7.widget.RecyclerView} untuk <a href="{@docRoot}training/material/lists-cards.html#RecyclerView">
    ++menampilkan kumpulan data.</a></li>
    ++<li>Widget {@link android.support.v7.widget.CardView} untuk <a href="{@docRoot}training/material/lists-cards.html#CardView">membuat kartu</a>.</li>
    ++<li>Kelas {@link android.support.v7.graphics.Palette} untuk <a href="{@docRoot}training/material/drawables.html#ColorExtract">mengekstrak warna mencolok dari
    ++    gambar</a>.</li>
    ++</ul>
    ++
    ++<h3>Widget sistem</h3>
    ++
    ++<p>Tema-tema <code>Theme.AppCompat</code> menyediakan gaya desain bahan untuk widget ini:</p>
    ++
    ++<ul>
    ++  <li>{@link android.widget.EditText}</li>
    ++  <li>{@link android.widget.Spinner}</li>
    ++  <li>{@link android.widget.CheckBox}</li>
    ++  <li>{@link android.widget.RadioButton}</li>
    ++  <li>{@link android.support.v7.widget.SwitchCompat}</li>
    ++  <li>{@link android.widget.CheckedTextView}</li>
    ++</ul>
    ++
    ++<h3>Palet Warna</h3>
    ++
    ++<p>Untuk memperoleh gaya desain bahan dan menyesuaikan palet warna dengan Android v7 Support
    ++Library, terapkan salah satu tema <code>Theme.AppCompat</code>:</p>
    ++
    ++<pre>
    ++&lt;!-- extend one of the Theme.AppCompat themes -->
    ++&lt;style name="Theme.MyTheme" parent="Theme.AppCompat.Light">
    ++    &lt;!-- customize the color palette -->
    ++    &lt;item name="colorPrimary">@color/material_blue_500&lt;/item>
    ++    &lt;item name="colorPrimaryDark">@color/material_blue_700&lt;/item>
    ++    &lt;item name="colorAccent">@color/material_green_A200&lt;/item>
    ++&lt;/style>
    ++</pre>
    ++
    ++<h3>Daftar dan Kartu</h3>
    ++
    ++<p>Widget {@link android.support.v7.widget.RecyclerView} dan {@link
    ++android.support.v7.widget.CardView} tersedia di versi Android terdahulu melalui
    ++Android v7 Support Library dengan pembatasan ini:</p>
    ++<ul>
    ++<li>{@link android.support.v7.widget.CardView} memundurkan ke implementasi bayangan terprogram
    ++    dengan menggunakan pengisi tambahan.</li>
    ++<li>{@link android.support.v7.widget.CardView} tidak memangkas tampilan anaknya yang berpotongan
    ++    dengan sudut melengkung.</li>
    ++</ul>
    ++
    ++
    ++<h3>Dependensi</h3>
    ++
    ++<p>Untuk menggunakan fitur-fitur ini di versi Android sebelum 5.0 (API level 21), sertakan
    ++Android v7 Support Library dalam proyek Anda sebagai <a href="{@docRoot}sdk/installing/studio-build.html#dependencies">dependensi Gradle</a>:</p>
    ++
    ++<pre>
    ++dependencies {
    ++    compile 'com.android.support:appcompat-v7:21.0.+'
    ++    compile 'com.android.support:cardview-v7:21.0.+'
    ++    compile 'com.android.support:recyclerview-v7:21.0.+'
    ++}
    ++</pre>
    ++
    ++
    ++<h2 id="CheckVersion">Memeriksa Versi Sistem</h2>
    ++
    ++<p>Fitur berikut hanya tersedia di Android 5.0 (API level 21) ke atas:</p>
    ++
    ++<ul>
    ++<li>Transisi aktivitas</li>
    ++<li>Umpan balik sentuh</li>
    ++<li>Animasi membuka</li>
    ++<li>Animasi berbasis path</li>
    ++<li>Drawable vektor</li>
    ++<li>Pewarnaan drawable</li>
    ++</ul>
    ++
    ++<p>Untuk menjaga kompatibilitas dengan versi Android terdahulu, periksa {@link
    ++android.os.Build.VERSION#SDK_INT version} sistem saat runtime sebelum Anda memanggil API untuk salah satu
    ++fitur ini:</p>
    ++
    ++<pre>
    ++// Check if we're running on Android 5.0 or higher
    ++if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
    ++    // Call some material design APIs here
    ++} else {
    ++    // Implement this feature without material design
    ++}
    ++</pre>
    ++
    ++<p class="note"><strong>Catatan:</strong> Untuk menetapkan versi Android yang didukung aplikasi Anda,
    ++gunakan atribut <code>android:minSdkVersion</code> dan <code>android:targetSdkVersion</code>
    ++dalam file manifes. Untuk menggunakan fitur desain bahan di Android 5.0, atur
    ++atribut <code>android:targetSdkVersion</code> ke <code>21</code>. Untuk informasi selengkapnya, lihat
    ++panduan <a href="{@docRoot}guide/topics/manifest/uses-sdk-element.html">API
    ++&lt;uses-sdk&gt;</a>.</p>
    +diff --git a/docs/html-intl/intl/id/training/material/drawables.jd b/docs/html-intl/intl/id/training/material/drawables.jd
    +new file mode 100644
    +index 0000000..493abd4
    +--- /dev/null
    ++++ b/docs/html-intl/intl/id/training/material/drawables.jd
    +@@ -0,0 +1,126 @@
    ++page.title=Bekerja dengan Drawable
    ++
    ++@jd:body
    ++
    ++<div id="tb-wrapper">
    ++<div id="tb">
    ++<h2>Pelajaran ini mengajarkan Anda cara</h2>
    ++<ol>
    ++  <li><a href="#DrawableTint">Mewarnai Sumber Daya Drawable</a></li>
    ++  <li><a href="#ColorExtract">Mengekstrak Warna Mencolok dari Gambar</a></li>
    ++  <li><a href="#VectorDrawables">Membuat Drawable Vektor</a></li>
    ++</ol>
    ++<h2>Anda juga harus membaca</h2>
    ++<ul>
    ++  <li><a href="http://www.google.com/design/spec">Spesifikasi desain bahan</a></li>
    ++  <li><a href="{@docRoot}design/material/index.html">Desain bahan di Android</a></li>
    ++</ul>
    ++</div>
    ++</div>
    ++
    ++<p>Kemampuan berikut untuk drawable membantu Anda mengimplementasikan desain bahan dalam aplikasi Anda:</p>
    ++
    ++<ul>
    ++<li>Pewarnaan drawable</li>
    ++<li>Ekstraksi warna mencolok</li>
    ++<li>Drawable vektor</li>
    ++</ul>
    ++
    ++<p>Pelajaran ini menampilkan cara menggunakan fitur-fitur ini dalam aplikasi Anda.</p>
    ++
    ++
    ++<h2 id="DrawableTint">Mewarnai Sumber Daya Drawable</h2>
    ++
    ++<p>Dengan Android 5.0 (API level 21) ke atas, Anda bisa mewarnai bitmap dan sembilan-tambalan yang didefinisikan sebagai
    ++alpha-mask. Anda bisa mewarnainya dengan sumber daya warna atau atribut tema yang mencocokkan ke
    ++sumber daya warna (misalnya, <code>?android:attr/colorPrimary</code>). Biasanya, Anda membuat aset ini
    ++hanya sekali dan mewarnainya secara otomatis agar cocok dengan tema Anda.</p>
    ++
    ++<p>Anda bisa menerapkan warna ke objek {@link android.graphics.drawable.BitmapDrawable} atau {@link
    ++android.graphics.drawable.NinePatchDrawable} dengan metode {@code setTint()}. Anda juga bisa
    ++mengatur warna dan mode dalam layout dengan atribut <code>android:tint</code> dan
    ++<code>android:tintMode</code>.</p>
    ++
    ++
    ++<h2 id="ColorExtract">Mengekstrak Warna Mencolok dari Gambar</h2>
    ++
    ++<p>Android Support Library r21 ke atas menyertakan kelas {@link
    ++android.support.v7.graphics.Palette}, yang memungkinkan Anda mengekstrak warna mencolok dari gambar.
    ++Kelas ini mengekstrak warna mencolok berikut:</p>
    ++
    ++<ul>
    ++<li>Menyala</li>
    ++<li>Menyala pekat</li>
    ++<li>Menyala pucat</li>
    ++<li>Pudar</li>
    ++<li>Pudar pekat</li>
    ++<li>Pudar pucat</li>
    ++</ul>
    ++
    ++<p>Untuk mengekstrak warna-warna ini, teruskan objek {@link android.graphics.Bitmap} ke
    ++metode statis {@link android.support.v7.graphics.Palette#generate Palette.generate()} dalam
    ++thread latar belakang tempat Anda memuat gambar. Jika Anda tidak bisa menggunakan thread itu, panggil metode
    ++{@link android.support.v7.graphics.Palette#generateAsync Palette.generateAsync()} dan
    ++sediakan listener sebagai gantinya.</p>
    ++
    ++<p>Anda bisa mengambil warna mencolok dari gambar dengan metode getter di kelas
    ++<code>Palette</code>, misalnya <code>Palette.getVibrantColor</code>.</p>
    ++
    ++<p>Untuk menggunakan kelas {@link android.support.v7.graphics.Palette} dalam proyek Anda, tambahkan
    ++<a href="{@docRoot}sdk/installing/studio-build.html#dependencies">dependensi Gradle</a> berikut ke
    ++modul aplikasi Anda:</p>
    ++
    ++<pre>
    ++dependencies {
    ++    ...
    ++    compile 'com.android.support:palette-v7:21.0.0'
    ++}
    ++</pre>
    ++
    ++<p>Untuk informasi selengkapnya, lihat referensi API untuk kelas {@link android.support.v7.graphics.Palette}.
    ++</p>
    ++
    ++
    ++<h2 id="VectorDrawables">Membuat Drawable Vektor</h2>
    ++
    ++<!-- video box -->
    ++<a class="notice-developers-video" href="https://www.youtube.com/watch?v=wlFVIIstKmA" style="margin-top:18px">
    ++<div>
    ++    <h3>Video</h3>
    ++    <p>Grafis Vektor Android</p>
    ++</div>
    ++</a>
    ++
    ++<p>Di Android 5.0 (API Level 21) ke atas, Anda bisa mendefinisikan drawable vektor, yang berubah skala tanpa
    ++kehilangan definisi. Anda hanya memerlukan satu file aset per gambar vektor, bukan file aset untuk
    ++setiap densitas layar seperti pada gambar bitmap. Untuk membuat gambar vektor, Anda mendefinisikan detail
    ++bentuknya dalam sebuah elemen XML <code>&lt;vector&gt;</code>.</p>
    ++
    ++<p>Contoh berikut mendefinisikan gambar vektor berbentuk hati:</p>
    ++
    ++<pre>
    ++&lt;!-- res/drawable/heart.xml -->
    ++&lt;vector xmlns:android="http://schemas.android.com/apk/res/android"
    ++    &lt;!-- intrinsic size of the drawable -->
    ++    android:height="256dp"
    ++    android:width="256dp"
    ++    &lt;!-- size of the virtual canvas -->
    ++    android:viewportWidth="32"
    ++    android:viewportHeight="32">
    ++
    ++  &lt;!-- draw a path -->
    ++  &lt;path android:fillColor="#8fff"
    ++      android:pathData="M20.5,9.5
    ++                        c-1.955,0,-3.83,1.268,-4.5,3
    ++                        c-0.67,-1.732,-2.547,-3,-4.5,-3
    ++                        C8.957,9.5,7,11.432,7,14
    ++                        c0,3.53,3.793,6.257,9,11.5
    ++                        c5.207,-5.242,9,-7.97,9,-11.5
    ++                        C25,11.432,23.043,9.5,20.5,9.5z" />
    ++&lt;/vector>
    ++</pre>
    ++
    ++<p>Gambar vektor direpresentasikan di Android sebagai objek {@link android.graphics.drawable.VectorDrawable}.
    ++ Untuk informasi selengkapnya tentang sintaks <code>pathData</code>, lihat <a href="http://www.w3.org/TR/SVG11/paths.html#PathData">Referensi Path SVG</a>. Untuk informasi selengkapnya
    ++tentang menganimasikan properti drawable vektor, lihat
    ++<a href="{@docRoot}training/material/animations.html#AnimVector">Menganimasikan Drawable Vektor</a>.</p>
    +diff --git a/docs/html-intl/intl/id/training/material/get-started.jd b/docs/html-intl/intl/id/training/material/get-started.jd
    +new file mode 100644
    +index 0000000..1a551a9
    +--- /dev/null
    ++++ b/docs/html-intl/intl/id/training/material/get-started.jd
    +@@ -0,0 +1,171 @@
    ++page.title=Memulai
    ++
    ++@jd:body
    ++
    ++<div id="tb-wrapper">
    ++<div id="tb">
    ++<h2>Pelajaran ini mengajarkan Anda cara</h2>
    ++<ol>
    ++  <li><a href="#ApplyTheme">Menerapkan Tema Bahan</a></li>
    ++  <li><a href="#Layouts">Mendesain Layout Anda</a></li>
    ++  <li><a href="#Depth">Menetapkan Ketinggian di Tampilan Anda</a></li>
    ++  <li><a href="#ListsCards">Membuat Daftar dan Kartu</a></li>
    ++  <li><a href="#Animations">Menyesuaikan Animasi Anda</a></li>
    ++</ol>
    ++<h2>Anda juga harus membaca</h2>
    ++<ul>
    ++  <li><a href="http://www.google.com/design/spec">Spesifikasi desain bahan</a></li>
    ++  <li><a href="{@docRoot}design/material/index.html">Desain bahan di Android</a></li>
    ++</ul>
    ++</div>
    ++</div>
    ++
    ++
    ++<p>Untuk membuat aplikasi dengan desain bahan:</p>
    ++
    ++<ol>
    ++  <li style="margin-bottom:10px">
    ++    Tinjaulah <a href="http://www.google.com/design/spec">spesifikasi desain bahan</a>.</li>
    ++  <li style="margin-bottom:10px">
    ++    Terapkan <strong>tema</strong> bahan ke aplikasi Anda.</li>
    ++  <li style="margin-bottom:10px">
    ++    Buat <strong>layout</strong> agar mengikuti panduan desain bahan.</li>
    ++  <li style="margin-bottom:10px">
    ++    Tetapkan <strong>ketinggian</strong> tampilan Anda untuk menghasilkan bayangan.</li>
    ++  <li style="margin-bottom:10px">
    ++    Gunakan <strong>widget</strong> sistem untuk daftar dan kartu.</li>
    ++  <li style="margin-bottom:10px">
    ++    Sesuaikan <strong>animasi</strong> di aplikasi Anda.</li>
    ++</ol>
    ++
    ++<h3>Mempertahankan kompatibilitas mundur</h3>
    ++
    ++<p>Anda bisa menambahkan banyak fitur desain bahan ke aplikasi sekaligus mempertahankan kompatibilitas dengan
    ++versi Android sebelum 5.0. Untuk informasi selengkapnya, lihat
    ++<a href="{@docRoot}training/material/compatibility.html">Mempertahankan Kompatibilitas</a>.</p>
    ++
    ++<h3>Memperbarui aplikasi dengan desain bahan</h3>
    ++
    ++<p>Untuk memperbarui aplikasi yang ada guna memasukkan desain bahan, perbarui layout Anda dengan mengikuti
    ++panduan desain bahan. Juga pastikan memasukkan kedalaman, umpan balik sentuh, dan
    ++animasi.</p>
    ++
    ++<h3>Membuat aplikasi baru dengan desain bahan</h3>
    ++
    ++<p>Jika Anda sedang membuat aplikasi baru dengan fitur desain bahan, <a href="http://www.google.com/design/spec">panduan desain bahan</a> akan memberi Anda
    ++kerangka kerja desain yang kohesif. Ikuti panduan itu dan gunakan fungsionalitas baru di
    ++kerangka kerja Android untuk mendesain dan mengembangkan aplikasi Anda.</p>
    ++
    ++
    ++<h2 id="ApplyTheme">Menerapkan Tema Bahan</h2>
    ++
    ++<p>Untuk menerapkan tema bahan dalam aplikasi Anda, tetapkan gaya yang mewarisi
    ++<code>android:Theme.Material</code>:</p>
    ++
    ++<pre>
    ++&lt;!-- res/values/styles.xml -->
    ++&lt;resources>
    ++  &lt;!-- your theme inherits from the material theme -->
    ++  &lt;style name="AppTheme" parent="android:Theme.Material">
    ++    &lt;!-- theme customizations -->
    ++  &lt;/style>
    ++&lt;/resources>
    ++</pre>
    ++
    ++<p>Tema bahan menyediakan widget sistem terbaru yang memungkinkan Anda mengatur palet warnanya dan
    ++animasi default untuk umpan balik sentuh dan transisi aktivitas. Untuk detail selengkapnya, lihat
    ++<a href="{@docRoot}training/material/theme.html">Menggunakan Tema Bahan</a>.</p>
    ++
    ++
    ++<h2 id="Layouts">Mendesain Layout Anda</h2>
    ++
    ++<p>Selain menerapkan dan menyesuaikan tema bahan, layout Anda harus mematuhi
    ++<a href="http://www.google.com/design/spec">panduan desain bahan</a>. Bila Anda mendesain
    ++layout, berikan perhatian khusus pada hal-hal berikut:</p>
    ++
    ++<ul>
    ++<li>Petak patokan</li>
    ++<li>Garis utama</li>
    ++<li>Pengaturan Jarak</li>
    ++<li>Ukuran target sentuh</li>
    ++<li>Struktur layout</li>
    ++</ul>
    ++
    ++
    ++<h2 id="Depth">Menetapkan Ketinggian di Tampilan Anda</h2>
    ++
    ++<p>Tampilan bisa menghasilkan bayangan, dan nilai ketinggian tampilan
    ++menentukan ukuran bayangan dan urutan penggambarannya. Untuk mengatur ketinggian tampilan, gunakan
    ++atribut <code>android:elevation</code> dalam layout:</p>
    ++
    ++<pre>
    ++&lt;TextView
    ++    android:id="&#64;+id/my_textview"
    ++    android:layout_width="wrap_content"
    ++    android:layout_height="wrap_content"
    ++    android:text="&#64;string/next"
    ++    android:background="&#64;color/white"
    ++    android:elevation="5dp" />
    ++</pre>
    ++
    ++<p>Properti <code>translationZ</code> baru memungkinkan Anda membuat animasi yang mencerminkan
    ++perubahan sementara pada ketinggian tampilan. Perubahan ketinggian bisa berguna saat
    ++<a href="{@docRoot}training/material/animations.html#ViewState">merespons
    ++gerakan sentuh</a>.</p>
    ++
    ++<p>Untuk detail selengkapnya, lihat <a href="{@docRoot}training/material/shadows-clipping.html">Mendefinisikan
    ++Bayangan dan Memangkas Tampilan</a>.</p>
    ++
    ++
    ++<h2 id="ListsCards">Membuat Daftar dan Kartu</h2>
    ++
    ++<p>{@link android.support.v7.widget.RecyclerView} adalah versi {@link
    ++android.widget.ListView} yang lebih mudah dimasukkan dan mendukung beragam tipe layout serta memberikan peningkatan kinerja.
    ++{@link android.support.v7.widget.CardView} memungkinkan Anda menampilkan potongan informasi dalam kartu dengan
    ++tampilan konsisten di seluruh aplikasi. Contoh kode berikut memperagakan cara menyertakan
    ++{@link android.support.v7.widget.CardView} dalam layout Anda:</p>
    ++
    ++<pre>
    ++&lt;android.support.v7.widget.CardView
    ++    android:id="&#64;+id/card_view"
    ++    android:layout_width="200dp"
    ++    android:layout_height="200dp"
    ++    card_view:cardCornerRadius="3dp">
    ++    ...
    ++&lt;/android.support.v7.widget.CardView>
    ++</pre>
    ++
    ++<p>Untuk informasi selengkapnya, lihat <a href="{@docRoot}training/material/lists-cards.html">Membuat Daftar
    ++dan Kartu</a>.</p>
    ++
    ++
    ++<h2 id="Animations">Menyesuaikan Animasi Anda</h2>
    ++
    ++<p>Android 5.0 (API level 21) menyertakan API baru untuk membuat animasi custom di aplikasi Anda.
    ++Misalnya, Anda bisa mengaktifkan transisi aktivitas dan mendefinisikan transisi keluar di
    ++aktivitas:</p>
    ++
    ++<pre>
    ++public class MyActivity extends Activity {
    ++
    ++    &#64;Override
    ++    protected void onCreate(Bundle savedInstanceState) {
    ++        super.onCreate(savedInstanceState);
    ++        // enable transitions
    ++        getWindow().requestFeature(Window.FEATURE_CONTENT_TRANSITIONS);
    ++        setContentView(R.layout.activity_my);
    ++    }
    ++
    ++    public void onSomeButtonClicked(View view) {
    ++        getWindow().setExitTransition(new Explode());
    ++        Intent intent = new Intent(this, MyOtherActivity.class);
    ++        startActivity(intent,
    ++                      ActivityOptions
    ++                          .makeSceneTransitionAnimation(this).toBundle());
    ++    }
    ++}
    ++</pre>
    ++
    ++<p>Bila Anda memulai aktivitas lain dari aktivitas ini, transisi keluar akan diaktifkan.</p>
    ++
    ++<p>Untuk mengetahui selengkapnya tentang API animasi yang baru, lihat <a href="{@docRoot}training/material/animations.html">Mendefinisikan Animasi Custom</a>.</p>
    +diff --git a/docs/html-intl/intl/id/training/material/index.jd b/docs/html-intl/intl/id/training/material/index.jd
    +new file mode 100644
    +index 0000000..53697d2
    +--- /dev/null
    ++++ b/docs/html-intl/intl/id/training/material/index.jd
    +@@ -0,0 +1,60 @@
    ++page.title=Desain Bahan untuk Pengembang
    ++page.image=images/cards/material_2x.png
    ++page.metaDescription=Pelajari cara menerapkan desain bahan pada aplikasi Anda.
    ++
    ++
    ++@jd:body
    ++
    ++<div id="tb-wrapper">
    ++<div id="tb">
    ++  <h2>Dependensi dan Prasyarat</h2>
    ++  <ul>
    ++    <li>Android 5.0 (API Level 21)</li>
    ++  </ul>
    ++</div>
    ++</div>
    ++
    ++<p>Desain bahan adalah panduan komprehensif untuk desain visual, gerak, dan interaksi di
    ++berbagai platform dan perangkat. Untuk menggunakan desain bahan di aplikasi Android, ikuti panduan
    ++yang dijelaskan dalam
    ++<a href="http://www.google.com/design/spec/material-design/introduction.html">spesifikasi desain bahan
    ++</a> dan gunakan komponen serta fungsionalitas baru yang tersedia di Android 5.0
    ++(API level 21).</p>
    ++
    ++<p>Kelas ini menampilkan kepada Anda cara membuat aplikasi desain bahan dengan elemen-elemen berikut:</p>
    ++
    ++<ul>
    ++<li>Tema bahan</li>
    ++<li>Widget untuk kartu dan daftar</li>
    ++<li>Bayangan custom dan pemangkasan tampilan</li>
    ++<li>Drawable vektor</li>
    ++<li>Animasi custom</li>
    ++</ul>
    ++
    ++<p>Kelas ini juga mengajarkan cara mempertahankan kompatibilitas dengan versi Android sebelum
    ++5.0 (API level 21) bila Anda menggunakan fitur desain bahan dalam aplikasi.</p>
    ++
    ++<h2>Pelajaran</h2>
    ++
    ++<dl>
    ++  <dt><a href="{@docRoot}training/material/get-started.html">Memulai</a></dt>
    ++  <dd>Pelajari cara memperbarui aplikasi Anda dengan fitur desain bahan.</dd>
    ++
    ++  <dt><a href="{@docRoot}training/material/theme.html">Menggunakan Tema Bahan</a></dt>
    ++  <dd>Pelajari cara menerapkan gaya desain bahan pada aplikasi Anda.</dd>
    ++
    ++  <dt><a href="{@docRoot}training/material/lists-cards.html">Membuat Daftar dan Kartu</a></dt>
    ++  <dd>Pelajari cara membuat daftar dan kartu dengan tampilan dan cara kerja yang konsisten menggunakan widget sistem.</dd>
    ++
    ++  <dt><a href="{@docRoot}training/material/shadows-clipping.html">Mendefinisikan Bayangan dan Memangkas Tampilan</a></dt>
    ++  <dd>Pelajari cara mengatur elevasi tampilan Anda untuk membuat bayangan custom dan cara memangkas tampilan.</dd>
    ++
    ++  <dt><a href="{@docRoot}training/material/drawables.html">Bekerja dengan Drawable</a></dt>
    ++  <dd>Pelajari cara membuat drawable vektor dan cara mewarnai sumber daya drawable.</dd>
    ++
    ++  <dt><a href="{@docRoot}training/material/animations.html">Mendefinisikan Animasi Custom</a></dt>
    ++  <dd>Pelajari cara membuat animasi custom untuk tampilan dan transisi aktivitas dengan elemen bersama.</dd>
    ++
    ++  <dt><a href="{@docRoot}training/material/compatibility.html">Mempertahankan Kompatibilitas</a></dt>
    ++  <dd>Pelajari cara mempertahankan kompatibilitas dengan versi platform sebelum Android 5.0.</dd>
    ++</dl>
    +diff --git a/docs/html-intl/intl/id/training/material/lists-cards.jd b/docs/html-intl/intl/id/training/material/lists-cards.jd
    +new file mode 100644
    +index 0000000..46dd19a
    +--- /dev/null
    ++++ b/docs/html-intl/intl/id/training/material/lists-cards.jd
    +@@ -0,0 +1,266 @@
    ++page.title=Membuat Daftar dan Kartu
    ++
    ++@jd:body
    ++
    ++<div id="tb-wrapper">
    ++<div id="tb">
    ++<h2>Pelajaran ini mengajarkan Anda cara</h2>
    ++<ol>
    ++  <li><a href="#RecyclerView">Membuat Daftar</a></li>
    ++  <li><a href="#CardView">Membuat Kartu</a></li>
    ++  <li><a href="#Dependencies">Menambahkan Dependensi</a></li>
    ++</ol>
    ++<h2>Anda juga harus membaca</h2>
    ++<ul>
    ++  <li><a href="http://www.google.com/design/spec">Spesifikasi desain bahan</a></li>
    ++  <li><a href="{@docRoot}design/material/index.html">Desain bahan di Android</a></li>
    ++</ul>
    ++</div>
    ++</div>
    ++
    ++
    ++<p>Untuk membuat daftar dan kartu yang kompleks dengan gaya desain bahan di aplikasi, Anda bisa menggunakan widget
    ++{@link android.support.v7.widget.RecyclerView} dan {@link android.support.v7.widget.CardView}.
    ++</p>
    ++
    ++
    ++<h2 id="RecyclerView">Membuat Daftar</h2>
    ++
    ++<p>Widget {@link android.support.v7.widget.RecyclerView} adalah
    ++versi {@link android.widget.ListView} yang lebih maju dan fleksibel. Widget ini adalah kontainer untuk menampilkan set data
    ++besar yang bisa digulir secara sangat efisien dengan mempertahankan tampilan dalam jumlah terbatas. Gunakan
    ++widget {@link android.support.v7.widget.RecyclerView} bila Anda memiliki kumpulan data dengan elemen
    ++yang berubah saat runtime berdasarkan tindakan pengguna atau kejadian jaringan.</p>
    ++
    ++<p>Kelas {@link android.support.v7.widget.RecyclerView} menyederhanakan penampilan dan penanganan
    ++set data yang besar dengan menyediakan:</p>
    ++
    ++<ul>
    ++  <li>Pengelola layout untuk memosisikan item</li>
    ++  <li>Animasi default untuk operasi item umum, misalnya penghapusan atau penambahan item</li>
    ++</ul>
    ++
    ++<p>Anda juga memiliki keluwesan untuk mendefinisikan pengelola layout custom dan animasi untuk widget {@link
    ++android.support.v7.widget.RecyclerView}.</p>
    ++
    ++<img src="{@docRoot}training/material/images/RecyclerView.png" alt="" width="550" height="106" />
    ++<p class="img-caption">
    ++<strong>Gambar 1</strong>. Widget <code>RecyclerView</code>.
    ++</p>
    ++
    ++<p>Untuk menggunakan widget {@link android.support.v7.widget.RecyclerView}, Anda harus menetapkan
    ++adaptor dan pengelola layout. Untuk membuat adaptor, perluas kelas {@link
    ++android.support.v7.widget.RecyclerView.Adapter RecyclerView.Adapter}. Detail
    ++implementasi bergantung pada detail set data Anda dan tipe tampilan. Untuk informasi selengkapnya,
    ++ lihat <a href="#RVExamples">contoh-contoh</a> di bawah.</p>
    ++
    ++<div style="float:right">
    ++<img src="{@docRoot}design/material/images/list_mail.png" alt="" width="250" height="426" />
    ++<p class="img-caption" style="margin-left:8px">
    ++<strong>Gambar 2</strong> - Daftar berisi <code>RecyclerView</code>.
    ++</p>
    ++</div>
    ++
    ++<p><strong>Pengelola layout</strong> memosisikan tampilan item dalam {@link
    ++android.support.v7.widget.RecyclerView} dan menentukan waktu untuk menggunakan ulang tampilan item yang tidak
    ++lagi terlihat oleh pengguna. Untuk menggunakan ulang (atau <em>mendaur ulang</em>) tampilan, pengelola layout bisa meminta
    ++adaptor untuk mengganti konten tampilan dengan elemen lain dalam dataset. Mendaur ulang
    ++tampilan dengan cara ini akan meningkatkan kinerja karena menghindari pembuatan tampilan yang tidak diperlukan atau
    ++melakukan pencarian {@link android.app.Activity#findViewById findViewById()} yang mahal.</p>
    ++
    ++<p>{@link android.support.v7.widget.RecyclerView} menyediakan semua pengelola layout bawaan ini:</p>
    ++
    ++<ul>
    ++<li>{@link android.support.v7.widget.LinearLayoutManager} menampilkan item dalam
    ++daftar gulir vertikal atau horizontal.</li>
    ++<li>{@link android.support.v7.widget.GridLayoutManager} menampilkan item dalam petak.</li>
    ++<li>{@link android.support.v7.widget.StaggeredGridLayoutManager} menampilkan item dalam petak zigzag.</li>
    ++</ul>
    ++
    ++<p>Untuk membuat pengelola layout custom, perluas kelas {@link
    ++android.support.v7.widget.RecyclerView.LayoutManager RecyclerView.LayoutManager}.</p>
    ++
    ++<h3>Animasi</h3>
    ++
    ++<p>Animasi untuk menambahkan dan menghapus item diaktifkan secara default di {@link
    ++android.support.v7.widget.RecyclerView}. Untuk menyesuaikan animasi ini, perluas kelas
    ++{@link android.support.v7.widget.RecyclerView.ItemAnimator RecyclerView.ItemAnimator}dan gunakan
    ++metode {@link android.support.v7.widget.RecyclerView#setItemAnimator RecyclerView.setItemAnimator()}.
    ++</p>
    ++
    ++<h3 id="RVExamples">Contoh</h3>
    ++
    ++<p>Contoh kode berikut memperagakan cara menambahkan
    ++{@link android.support.v7.widget.RecyclerView} ke layout:</p>
    ++
    ++<pre>
    ++&lt;!-- A RecyclerView with some commonly used attributes -->
    ++&lt;android.support.v7.widget.RecyclerView
    ++    android:id="@+id/my_recycler_view"
    ++    android:scrollbars="vertical"
    ++    android:layout_width="match_parent"
    ++    android:layout_height="match_parent"/>
    ++</pre>
    ++
    ++<p>Begitu Anda menambahkan widget {@link android.support.v7.widget.RecyclerView} ke layout,
    ++dapatkan pengatur atau handle objek itu, hubungkan dengan pengelola layout, dan sertakan adaptor untuk data
    ++yang akan ditampilkan:</p>
    ++
    ++<pre>
    ++public class MyActivity extends Activity {
    ++    private RecyclerView mRecyclerView;
    ++    private RecyclerView.Adapter mAdapter;
    ++    private RecyclerView.LayoutManager mLayoutManager;
    ++
    ++    &#64;Override
    ++    protected void onCreate(Bundle savedInstanceState) {
    ++        super.onCreate(savedInstanceState);
    ++        setContentView(R.layout.my_activity);
    ++        mRecyclerView = (RecyclerView) findViewById(R.id.my_recycler_view);
    ++
    ++        // use this setting to improve performance if you know that changes
    ++        // in content do not change the layout size of the RecyclerView
    ++        mRecyclerView.setHasFixedSize(true);
    ++
    ++        // use a linear layout manager
    ++        mLayoutManager = new LinearLayoutManager(this);
    ++        mRecyclerView.setLayoutManager(mLayoutManager);
    ++
    ++        // specify an adapter (see also next example)
    ++        mAdapter = new MyAdapter(myDataset);
    ++        mRecyclerView.setAdapter(mAdapter);
    ++    }
    ++    ...
    ++}
    ++</pre>
    ++
    ++<p>Adaptor menyediakan akses ke item dataset Anda, membuat tampilan untuk item, dan
    ++mengganti konten sebagian tampilan dengan item data baru bila item semula tidak lagi
    ++terlihat. Contoh kode berikut menampilkan implementasi sederhana untuk sebuah dataset yang terdiri dari
    ++larik string yang ditampilkan dengan menggunakan widget {@link android.widget.TextView}:</p>
    ++
    ++<pre>
    ++public class MyAdapter extends RecyclerView.Adapter&lt;MyAdapter.ViewHolder> {
    ++    private String[] mDataset;
    ++
    ++    // Provide a reference to the views for each data item
    ++    // Complex data items may need more than one view per item, and
    ++    // you provide access to all the views for a data item in a view holder
    ++    public static class ViewHolder extends RecyclerView.ViewHolder {
    ++        // each data item is just a string in this case
    ++        public TextView mTextView;
    ++        public ViewHolder(TextView v) {
    ++            super(v);
    ++            mTextView = v;
    ++        }
    ++    }
    ++
    ++    // Provide a suitable constructor (depends on the kind of dataset)
    ++    public MyAdapter(String[] myDataset) {
    ++        mDataset = myDataset;
    ++    }
    ++
    ++    // Create new views (invoked by the layout manager)
    ++    &#64;Override
    ++    public MyAdapter.ViewHolder onCreateViewHolder(ViewGroup parent,
    ++                                                   int viewType) {
    ++        // create a new view
    ++        View v = LayoutInflater.from(parent.getContext())
    ++                               .inflate(R.layout.my_text_view, parent, false);
    ++        // set the view's size, margins, paddings and layout parameters
    ++        ...
    ++        ViewHolder vh = new ViewHolder(v);
    ++        return vh;
    ++    }
    ++
    ++    // Replace the contents of a view (invoked by the layout manager)
    ++    &#64;Override
    ++    public void onBindViewHolder(ViewHolder holder, int position) {
    ++        // - get element from your dataset at this position
    ++        // - replace the contents of the view with that element
    ++        holder.mTextView.setText(mDataset[position]);
    ++
    ++    }
    ++
    ++    // Return the size of your dataset (invoked by the layout manager)
    ++    &#64;Override
    ++    public int getItemCount() {
    ++        return mDataset.length;
    ++    }
    ++}
    ++</pre>
    ++
    ++
    ++<div style="float:right;margin-top:15px;margin-left:30px">
    ++<img src="{@docRoot}design/material/images/card_travel.png" alt="" width="225" height="383">
    ++<p class="img-caption" style="margin-left:12px">
    ++<strong>Gambar 3</strong>. Contoh kartu.
    ++</p>
    ++</div>
    ++
    ++<h2 id="CardView">Membuat Kartu</h2>
    ++
    ++<p>{@link android.support.v7.widget.CardView} memperluas kelas {@link android.widget.FrameLayout}
    ++dan memungkinkan Anda menampilkan informasi dalam kartu yang memiliki tampilan konsisten lintas platform. Widget {@link
    ++android.support.v7.widget.CardView} bisa memiliki bayangan dan sudut membulat.</p>
    ++
    ++<p>Untuk membuat kartu dengan bayangan, gunakan atribut <code>card_view:cardElevation</code>.
    ++{@link android.support.v7.widget.CardView} menggunakan elevasi nyata dan bayangan dinamis pada Android 5.0
    ++(API level 21) ke atas dan memundurkan ke implementasi bayangan terprogram pada versi terdahulu.
    ++Untuk informasi selengkapnya, lihat <a href="{@docRoot}training/material/compatibility.html">Mempertahankan
    ++Kompatibilitas</a>.</p>
    ++
    ++<p>Gunakan properti-properti ini untuk menyesuaikan penampilan
    ++widget {@link android.support.v7.widget.CardView}:</p>
    ++
    ++<ul>
    ++  <li>Untuk mengatur radius sudut pada layout Anda, gunakan atribut <code>card_view:cardCornerRadius</code>.
    ++</li>
    ++  <li>Untuk mengatur radius sudut dalam kode Anda, gunakan metode <code>CardView.setRadius</code>.</li>
    ++  <li>Untuk mengatur warna latar belakang kartu, gunakan atribut <code>card_view:cardBackgroundColor</code>.
    ++</li>
    ++</ul>
    ++
    ++<p>Contoh kode berikut menampilkan cara menyertakan widget {@link android.support.v7.widget.CardView}
    ++dalam layout:</p>
    ++
    ++<pre>
    ++&lt;LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    ++    xmlns:tools="http://schemas.android.com/tools"
    ++    xmlns:card_view="http://schemas.android.com/apk/res-auto"
    ++    ... >
    ++    &lt;!-- A CardView that contains a TextView -->
    ++    &lt;android.support.v7.widget.CardView
    ++        xmlns:card_view="http://schemas.android.com/apk/res-auto"
    ++        android:id="@+id/card_view"
    ++        android:layout_gravity="center"
    ++        android:layout_width="200dp"
    ++        android:layout_height="200dp"
    ++        card_view:cardCornerRadius="4dp">
    ++
    ++        &lt;TextView
    ++            android:id="@+id/info_text"
    ++            android:layout_width="match_parent"
    ++            android:layout_height="match_parent" />
    ++    &lt;/android.support.v7.widget.CardView>
    ++&lt;/LinearLayout>
    ++</pre>
    ++
    ++<p>Untuk informasi selengkapnya, lihat referensi API untuk {@link android.support.v7.widget.CardView}.</p>
    ++
    ++
    ++<h2 id="Dependencies">Menambahkan Dependensi</h2>
    ++
    ++<p>Widget {@link android.support.v7.widget.RecyclerView} dan {@link android.support.v7.widget.CardView}
    ++adalah bagian dari <a href="{@docRoot}tools/support-library/features.html#v7">v7 Support
    ++Library</a>. Untuk menggunakan widget dalam proyek Anda, tambahkan
    ++<a href="{@docRoot}sdk/installing/studio-build.html#dependencies">dependensi Gradle</a> ini ke
    ++modul aplikasi Anda:</p>
    ++
    ++<pre>
    ++dependencies {
    ++    ...
    ++    compile 'com.android.support:cardview-v7:21.0.+'
    ++    compile 'com.android.support:recyclerview-v7:21.0.+'
    ++}
    ++</pre>
    +diff --git a/docs/html-intl/intl/id/training/material/shadows-clipping.jd b/docs/html-intl/intl/id/training/material/shadows-clipping.jd
    +new file mode 100644
    +index 0000000..5431926
    +--- /dev/null
    ++++ b/docs/html-intl/intl/id/training/material/shadows-clipping.jd
    +@@ -0,0 +1,133 @@
    ++page.title=Mendefinisikan Bayangan dan Memangkas Tampilan
    ++
    ++@jd:body
    ++
    ++<div id="tb-wrapper">
    ++<div id="tb">
    ++<h2>Pelajaran ini mengajarkan Anda cara</h2>
    ++<ol>
    ++  <li><a href="#Elevation">Menetapkan Elevasi pada Tampilan Anda</a></li>
    ++  <li><a href="#Shadows">Menyesuaikan Bayangan dan Garis Luar Tampilan</a></li>
    ++  <li><a href="#Clip">Memangkas Tampilan</a></li>
    ++</ol>
    ++<h2>Anda juga harus membaca</h2>
    ++<ul>
    ++  <li><a href="http://www.google.com/design/spec">Spesifikasi desain bahan</a></li>
    ++  <li><a href="{@docRoot}design/material/index.html">Desain bahan di Android</a></li>
    ++</ul>
    ++</div>
    ++</div>
    ++
    ++<p>Desain bahan memperkenalkan elevasi untuk elemen-elemen UI. Elevasi membantu pengguna memahami
    ++arti penting relatif masing-masing elemen dan memfokuskan perhatian pada tugas yang ada.</p>
    ++
    ++<p>Elevasi tampilan, yang dinyatakan dengan properti Z, menentukan tampilan visual
    ++bayangannya: tampilan dengan nilai Z lebih tinggi menghasilkan bayangan lebih besar dan lebih halus. Tampilan dengan nilai Z lebih tinggi menutupi
    ++tampilan dengan nilai Z lebih rendah; akan tetapi, nilai Z tampilan tidak memengaruhi ukuran tampilan.</p>
    ++
    ++<p>Bayangan digambar oleh induk tampilan yang dinaikkan, sehingga terkena pemangkasan standar tampilan,
    ++yang dipangkas oleh induk secara default.</p>
    ++
    ++<p>Elevasi juga berguna untuk membuat animasi tempat memunculkan widget untuk sementara di atas
    ++bidang tampilan saat melakukan beberapa tindakan.</p>
    ++
    ++<p>Untuk informasi selengkapnya tentang elevasi dalam desain bahan, lihat
    ++<a href="http://www.google.com/design/spec/what-is-material/objects-in-3d-space.html">Objek
    ++di ruang 3D</a>.</p>
    ++
    ++
    ++<h2 id="Elevation">Menetapkan Elevasi pada Tampilan Anda</h2>
    ++
    ++<p>Nilai Z untuk tampilan memiliki dua komponen:
    ++
    ++<ul>
    ++<li>Elevasi: Komponen statis.</li>
    ++<li>Transformasi: Komponen dinamis yang digunakan untuk animasi.</li>
    ++</ul>
    ++
    ++<p><code>Z = elevation + translationZ</code></p>
    ++
    ++<img src="{@docRoot}training/material/images/shadows-depth.png" width="580" height="261" alt="" />
    ++<p class="img-caption"><strong>Gambar 1</strong> - Bayangan untuk berbagai elevasi tampilan.</p>
    ++
    ++<p>Untuk mengatur elevasi tampilan dalam definisi layout, gunakan atribut <code>android:elevation</code>.
    ++ Untuk mengatur elevasi tampilan dalam kode aktivitas, gunakan
    ++metode {@link android.view.View#setElevation View.setElevation()}.</p>
    ++
    ++<p>Untuk mengatur transformasi tampilan, gunakan metode {@link android.view.View#setTranslationZ
    ++View.setTranslationZ()}.</p>
    ++
    ++<p>Metode {@link android.view.ViewPropertyAnimator#z ViewPropertyAnimator.z()} dan {@link
    ++android.view.ViewPropertyAnimator#translationZ ViewPropertyAnimator.translationZ()} yang baru memudahkan
    ++Anda menganimasikan elevasi tampilan. Untuk informasi selengkapnya, lihat referensi API untuk
    ++{@link android.view.ViewPropertyAnimator} dan panduan pengembang <a href="{@docRoot}guide/topics/graphics/prop-animation.html">Animasi Properti</a>.
    ++</p>
    ++
    ++<p>Anda juga bisa menggunakan {@link android.animation.StateListAnimator}
    ++untuk menetapkan animasi ini secara deklaratif. Ini khususnya berguna bila
    ++perubahan status memicu animasi, seperti saat seorang pengguna menekan tombol. Untuk informasi selengkapnya, lihat
    ++<a href="{@docRoot}training/material/animations.html#ViewState">Menganimasikan Perubahan Status Tampilan</a>.</p>
    ++
    ++<p>Nilai Z diukur dengan satuan dp (density-independent pixel).</p>
    ++
    ++
    ++<h2 id="Shadows">Menyesuaikan Bayangan dan Garis Luar Tampilan</h2>
    ++
    ++<p>Batas-batas drawable latar belakang tampilan menentukan bentuk default bayangannya.
    ++<strong>Garis luar</strong> menyatakan bentuk luar objek grafis dan mendefinisikan
    ++bidang riak untuk umpan balik sentuh.</p>
    ++
    ++<p>Perhatikan tampilan ini, yang didefinisikan dengan drawable latar belakang:</p>
    ++
    ++<pre>
    ++&lt;TextView
    ++    android:id="@+id/myview"
    ++    ...
    ++    android:elevation="2dp"
    ++    android:background="@drawable/myrect" />
    ++</pre>
    ++
    ++<p>Drawable latar belakang didefinisikan sebagai persegi panjang dengan sudut membulat:</p>
    ++
    ++<pre>
    ++&lt;!-- res/drawable/myrect.xml -->
    ++&lt;shape xmlns:android="http://schemas.android.com/apk/res/android"
    ++       android:shape="rectangle">
    ++    &lt;solid android:color="#42000000" />
    ++    &lt;corners android:radius="5dp" />
    ++&lt;/shape>
    ++</pre>
    ++
    ++<p>Tampilan ini menghasilkan bayangan dengan sudut membulat, karena drawable latar belakang mendefinisikan
    ++garis luar tampilan. Memberikan garis luar custom akan mengesampingkan bentuk default bayangan tampilan.</p>
    ++
    ++<p>Untuk mendefinisikan garis luar custom suatu tampilan dalam kode Anda:<p>
    ++
    ++<ol>
    ++<li>Perluas kelas {@link android.view.ViewOutlineProvider}.</li>
    ++<li>Kesampingkan metode {@link android.view.ViewOutlineProvider#getOutline getOutline()}.</li>
    ++<li>Tetapkan penyedia garis luar baru untuk tampilan Anda dengan metode {@link
    ++android.view.View#setOutlineProvider View.setOutlineProvider()}.</li>
    ++</ol>
    ++
    ++<p>Anda bisa membuat garis luar lonjong dan persegi panjang yang bersudut membulat dengan menggunakan metode dalam
    ++kelas {@link android.graphics.Outline}. Penyedia garis luar default untuk tampilan memperoleh garis luar
    ++dari latar belakang tampilan. Untuk mencegah tampilan menghasilkan bayangan, atur penyedia garis luarnya
    ++ke <code>null</code>.</p>
    ++
    ++
    ++<h2 id="Clip">Memangkas Tampilan</h2>
    ++
    ++<p>Memangkas tampilan memudahkan Anda mengubah bentuk tampilan. Anda bisa memangkas tampilan agar
    ++konsistensi dengan elemen desain lainnya atau mengubah bentuk tampilan untuk merespons input pengguna.
    ++Anda bisa memangkas tampilan hingga area garis luarnya dengan menggunakan metode {@link android.view.View#setClipToOutline
    ++View.setClipToOutline()} atau atribut <code>android:clipToOutline</code>. Hanya
    ++garis-garis luar persegi panjang, lingkaran, dan persegi panjang bersudut bulat yang mendukung pemangkasan, seperti yang ditentukan oleh
    ++metode {@link android.graphics.Outline#canClip Outline.canClip()}.</p>
    ++
    ++<p>Untuk memangkas tampilan ke bentuk drawable, atur drawable sebagai latar belakang tampilan
    ++(seperti yang ditampilkan di atas) dan panggil metode {@link android.view.View#setClipToOutline View.setClipToOutline()}.
    ++</p>
    ++
    ++<p>Memangkas tampilan adalah operasi yang mahal; jadi, jangan animasikan bentuk yang Anda gunakan
    ++untuk memangkas tampilan. Untuk memperoleh efek ini, gunakan animasi <a href="{@docRoot}training/material/animations.html#Reveal">Reveal Effect</a>.</p>
    +diff --git a/docs/html-intl/intl/id/training/material/theme.jd b/docs/html-intl/intl/id/training/material/theme.jd
    +new file mode 100644
    +index 0000000..5acdcd2
    +--- /dev/null
    ++++ b/docs/html-intl/intl/id/training/material/theme.jd
    +@@ -0,0 +1,131 @@
    ++page.title=Menggunakan Tema Bahan
    ++
    ++@jd:body
    ++
    ++<div id="tb-wrapper">
    ++<div id="tb">
    ++<h2>Pelajaran ini mengajarkan Anda cara</h2>
    ++<ol>
    ++  <li><a href="#ColorPalette">Menyesuaikan Palet Warna</a></li>
    ++  <li><a href="#StatusBar">Menyesuaikan Baris Status</a></li>
    ++  <li><a href="#Inheritance">Tampilan Setiap Tema</a></li>
    ++</ol>
    ++<h2>Anda juga harus membaca</h2>
    ++<ul>
    ++  <li><a href="http://www.google.com/design/spec">Spesifikasi desain bahan</a></li>
    ++  <li><a href="{@docRoot}design/material/index.html">Desain bahan di Android</a></li>
    ++</ul>
    ++</div>
    ++</div>
    ++
    ++
    ++<p>Tema bahan yang baru menyediakan:</p>
    ++
    ++<ul>
    ++  <li>Widget sistem yang memungkinkan Anda mengatur palet warnanya</li>
    ++  <li>Animasi umpan balik sentuh untuk widget sistem</li>
    ++  <li>Animasi transisi aktivitas</li>
    ++</ul>
    ++
    ++<p>Anda bisa menyesuaikan tampilan tema bahan
    ++sesuai dengan identitas merek Anda dengan palet warna yang Anda kontrol. Anda bisa mewarnai action-bar dan
    ++baris status dengan menggunakan atribut tema, seperti yang ditampilkan dalam <a href="#fig3">Gambar 3</a>.</p>
    ++
    ++<p>Widget sistem memiliki desain baru dan animasi umpan balik sentuh. Anda bisa menyesuaikan
    ++palet warna, animasi umpan balik sentuh, dan transisi aktivitas untuk aplikasi.</p>
    ++
    ++<p>Tema bahan didefinisikan sebagai:</p>
    ++
    ++<ul>
    ++  <li><code>@android:style/Theme.Material</code> (versi gelap)</li>
    ++  <li><code>@android:style/Theme.Material.Light</code> (versi terang)</li>
    ++  <li><code>@android:style/Theme.Material.Light.DarkActionBar</code></li>
    ++</ul>
    ++
    ++<p>Untuk daftar gaya bahan yang bisa Anda gunakan, lihat referensi API untuk
    ++{@link android.R.style R.style}.</p>
    ++
    ++<!-- two columns, dark/light material theme example -->
    ++<div style="width:700px;margin-top:25px;margin-bottom:10px">
    ++<div style="float:left;width:250px;margin-left:40px;margin-right:60px;">
    ++  <img src="{@docRoot}design/material/images/MaterialDark.png" width="500" height="238">
    ++  <div style="width:170px;margin:0 auto">
    ++  <p style="margin-top:8px;font-size:12px"><strong>Gambar 1</strong>. Tema bahan gelap</p>
    ++  </div>
    ++</div>
    ++<div style="float:left;width:250px;margin-right:0px;">
    ++  <img src="{@docRoot}design/material/images/MaterialLight.png" width="500" height="238">
    ++  <div style="width:170px;margin:0 auto">
    ++  <p style="margin-top:8px;font-size:12px"><strong>Gambar 2</strong>. Tema bahan terang</p>
    ++  </div>
    ++</div>
    ++<br style="clear:left">
    ++</div>
    ++
    ++<p class="note">
    ++<strong>Catatan:</strong> Tema bahan hanya tersedia di Android 5.0 (API level 21)
    ++ke atas. <a href="{@docRoot}tools/support-library/features.html#v7">v7 Support Library</a>
    ++menyediakan tema dengan gaya desain bahan untuk beberapa widget dan dukungan untuk menyesuaikan
    ++palet warna. Untuk informasi selengkapnya, lihat
    ++<a href="{@docRoot}training/material/compatibility.html">Mempertahankan Kompatibilitas</a>.
    ++</p>
    ++
    ++
    ++<h2 id="ColorPalette">Menyesuaikan Palet Warna</h2>
    ++
    ++<p style="margin-bottom:30px">Untuk menyesuaikan warna dasar tema agar cocok dengan merek Anda, definisikan
    ++warna custom menggunakan atribut tema saat Anda mewariskan dari tema bahan:</p>
    ++
    ++<pre>
    ++&lt;resources>
    ++  &lt;!-- inherit from the material theme -->
    ++  &lt;style name="AppTheme" parent="android:Theme.Material">
    ++    &lt;!-- Main theme colors -->
    ++    &lt;!--   your app branding color for the app bar -->
    ++    &lt;item name="android:colorPrimary">@color/primary&lt;/item>
    ++    &lt;!--   darker variant for the status bar and contextual app bars -->
    ++    &lt;item name="android:colorPrimaryDark">@color/primary_dark&lt;/item>
    ++    &lt;!--   theme UI controls like checkboxes and text fields -->
    ++    &lt;item name="android:colorAccent">@color/accent&lt;/item>
    ++  &lt;/style>
    ++&lt;/resources>
    ++</pre>
    ++
    ++<div style="float:right;margin-left:25px;margin-top:20px;margin-bottom:10px" id="fig3">
    ++<img src="{@docRoot}training/material/images/ThemeColors.png" width="250" height="445" />
    ++<p class="img-caption" style="margin-bottom:0px">
    ++<strong>Gambar 3.</strong> Menyesuaikan tema bahan.</p>
    ++</div>
    ++
    ++
    ++<h2 id="StatusBar">Menyesuaikan Baris Status</h2>
    ++
    ++<p>Tema bahan memungkinkan Anda menyesuaikan baris status dengan mudah; jadi Anda bisa menetapkan
    ++warna yang cocok dengan merek Anda dan memberikan kontras yang cukup untuk menampilkan ikon status putih. Untuk
    ++mengatur warna custom bagi baris status, gunakan atribut <code>android:statusBarColor</code> bila
    ++Anda memperluas tema bahan. Secara default, <code>android:statusBarColor</code> mewarisi
    ++nilai <code>android:colorPrimaryDark</code>.</p>
    ++
    ++<p>Anda juga bisa menggambar sendiri di belakang baris status. Misalnya, jika Anda ingin menampilkan
    ++baris status secara transparan di atas foto, dengan gradasi gelap yang halus untuk memastikan
    ++ikon status putih tetap terlihat. Caranya, atur atribut <code>android:statusBarColor</code> ke
    ++<code>&#64;android:color/transparent</code> dan sesuaikan flag jendela seperti yang diperlukan. Anda juga bisa
    ++menggunakan metode {@link android.view.Window#setStatusBarColor Window.setStatusBarColor()} untuk
    ++animasi atau pemudaran.</p>
    ++
    ++<p class="note">
    ++<strong>Catatan:</strong> Baris status harus selalu memiliki delineasi yang jelas dari
    ++toolbar utama, kecuali bila Anda menampilkan gambar detail atau konten media tepi-ke-tepi di belakang
    ++baris ini dan bila Anda menggunakan gradasi untuk memastikan ikon tetap terlihat.
    ++</p>
    ++
    ++<p>Bila Anda menyesuaikan baris navigasi dan baris status, jadikan keduanya transparan atau modifikasi
    ++baris status saja. Baris navigasi harus tetap hitam di semua kasus lainnya.</p>
    ++
    ++
    ++<h2 id="Inheritance">Tampilan Setiap Tema</h3>
    ++
    ++<p>Elemen dalam definisi layout XML bisa menetapkan atribut <code>android:theme</code>,
    ++yang merujuk sumber daya tema. Atribut ini memodifikasi tema untuk elemen itu dan setiap
    ++elemen anak, yang berguna untuk mengubah palet warna tema dalam porsi tertentu
    ++pada antarmuka.</p>
    +diff --git a/docs/html-intl/intl/id/training/tv/playback/picture-in-picture.jd b/docs/html-intl/intl/id/training/tv/playback/picture-in-picture.jd
    +new file mode 100644
    +index 0000000..41af6de
    +--- /dev/null
    ++++ b/docs/html-intl/intl/id/training/tv/playback/picture-in-picture.jd
    +@@ -0,0 +1,213 @@
    ++page.title=Gambar-dalam-gambar
    ++page.keywords=pratinjau,sdk,PIP,Gambar-dalam-gambar
    ++page.tags=androidn
    ++
    ++@jd:body
    ++
    ++<div id="tb-wrapper">
    ++<div id="tb">
    ++
    ++<h2>Dalam dokumen ini</h2>
    ++<ol>
    ++  <li><a href="#declaring">Mendeklarasikan Bahwa Aktivitas Anda Mendukung
    ++Gambar-dalam-gambar</a></li>
    ++  <li><a href="#pip_button">Mengalihkan Aktivitas Anda ke Gambar-dalam-gambar</a>
    ++</li>
    ++  <li><a href="#handling_ui">Menangani UI Selama Gambar-dalam-gambar</a>
    ++</li>
    ++  <li><a href="#continuing_playback">Melanjutkan Pemutaran Video Saat dalam
    ++Gambar-dalam-gambar</a></li>
    ++  <li><a href="#single_playback">Menggunakan Aktivitas Pemutaran Tunggal untuk
    ++ Gambar-dalam-gambar</a></li>
    ++  <li><a href="#best">Praktik Terbaik</a></li>
    ++</ol>
    ++
    ++<h2>Lihat Juga</h2>
    ++<ol>
    ++  <li><a href="{@docRoot}preview/features/multi-window.html">Dukungan
    ++Multi-Jendela</a></li>
    ++</ol>
    ++
    ++</div>
    ++</div>
    ++
    ++<p>Di Android N, pengguna Android TV sekarang bisa menonton video
    ++dalam jendela yang disematkan di sudut layar saat menyusuri
    ++aplikasi. Mode gambar-dalam-gambar (PIP) memungkinkan aplikasi menjalankan aktivitas
    ++video dalam jendela yang disematkan selagi aktivitas lain tetap berjalan di
    ++latar belakang. Jendela PIP memungkinkan pengguna melakukan multitasking saat menggunakan aplikasi Anda, yang
    ++membantu pengguna menjadi lebih produktif.</p>
    ++
    ++<p>Aplikasi Anda bisa memutuskan kapan memicu mode PIP. Inilah beberapa contoh
    ++kapan memasuki mode PIP:</p>
    ++
    ++<ul>
    ++<li>Aplikasi Anda bisa memindahkan video ke dalam mode PIP bila pengguna mengarah
    ++mundur dari video untuk menjelajah materi lainnya.</li>
    ++<li>Aplikasi Anda bisa mengalihkan video ke dalam mode PIP selagi pengguna menonton akhir episode
    ++dari materi. Layar utama menampilkan informasi
    ++promosi atau rangkuman tentang episode berikutnya dalam seri tersebut.</li>
    ++<li>Aplikasi Anda bisa menyediakan suatu cara bagi pengguna untuk mengantre materi tambahan selagi
    ++mereka menonton video. Video terus dimainkan dalam mode PIP selagi layar
    ++utama menampilkan aktivitas pemilihan materi.</li>
    ++</ul>
    ++
    ++<p>Jendela PIP memiliki luas 240x135 dp dan ditampilkan di layer paling atas pada salah satu
    ++dari empat sudut layar, yang dipilih oleh sistem. Pengguna bisa memunculkan
    ++menu PIP yang memungkinkan mereka untuk beralih mode dari jendela PIP ke layar penuh, atau menutup jendela
    ++PIP, dengan menekan dan menahan tombol <b>Beranda</b> pada remote. Jika video
    ++lain mulai diputar pada layar utama, jendela PIP secara otomatis
    ++ditutup. Pengguna juga bisa menutup jendela PIP melalui Recents.</p>
    ++
    ++<img src="{@docRoot}images/android-7.0/pip-active.png" />
    ++<p class="img-caption"><strong>Gambar 1.</strong> Video
    ++Gambar-dalam-gambar terlihat di sudut layar selagi pengguna menjelajahi materi pada layar
    ++utama.</p>
    ++
    ++<p>PIP memanfaatkan API multi-jendela yang tersedia di Android N untuk
    ++menyediakan jendela hamparan video yang disematkan. Untuk menambahkan PIP ke aplikasi, Anda harus
    ++mendaftarkan aktivitas yang mendukung PIP, mengalihkan aktivitas Anda ke mode PIP bila
    ++diperlukan, serta memastikan elemen UI disembunyikan dan pemutaran video berlanjut bila
    ++aktivitas dalam mode PIP.</p>
    ++
    ++<h2 id="declaring">Mendeklarasikan Bahwa Aktivitas Anda Mendukung Gambar-dalam-gambar</h2>
    ++
    ++<p>Secara default, sistem tidak secara otomatis mendukung PIP untuk aplikasi.
    ++Jika Anda ingin mendukung PIP dalam aplikasi, daftarkan aktivitas
    ++video Anda dalam manifes dengan menyetel
    ++<code>android:supportsPictureInPicture</code> dan
    ++<code>android:resizeableActivity</code> ke <code>true</code>. Juga, tetapkan
    ++bahwa aktivitas Anda menangani perubahan konfigurasi layout sehingga aktivitas
    ++Anda tidak diluncurkan ulang saat terjadi perubahan layout selama transisi mode PIP.</p>
    ++
    ++<pre>
    ++&lt;activity android:name="VideoActivity"
    ++    android:resizeableActivity="true"
    ++    android:supportsPictureInPicture="true"
    ++    android:configChanges=
    ++        "screenSize|smallestScreenSize|screenLayout|orientation"
    ++    ...
    ++</pre>
    ++
    ++<p>Saat mendaftarkan aktivitas Anda, ingatlah bahwa dalam mode PIP aktivitas
    ++Anda akan ditampilkan pada jendela hamparan kecil pada layar TV. Aktivitas
    ++pemutaran video dengan UI minimal akan memberikan pengalaman pengguna terbaik. Aktivitas yang
    ++mengandung elemen UI kecil mungkin tidak memberikan pengalaman pengguna yang baik
    ++ketika beralih ke mode PIP, karena pengguna tidak dapat melihat elemen UI secara jelas
    ++di jendela PIP.</p>
    ++
    ++<h2 id="pip_button">Mengalihkan Aktivitas Anda ke Gambar-dalam-gambar</h2>
    ++
    ++Bila Anda perlu untuk mengalihkan aktivitas ke mode PIP, panggil
    ++<code>Activity.enterPictureInPictureMode()</code>. Contoh berikut mengalihkan
    ++ke mode PIP bila pengguna memilih tombol PIP khusus pada baris
    ++kontrol media:</p>
    ++
    ++<pre>
    ++&#64;Override
    ++public void onActionClicked(Action action) {
    ++    if (action.getId() == R.id.lb_control_picture_in_picture) {
    ++        getActivity().enterPictureInPictureMode();
    ++        return;
    ++    }
    ++    ...
    ++</pre>
    ++
    ++<p>Menambahkan tombol PIP ke baris kontrol media Anda akan memungkinkan pengguna dengan mudah beralih
    ++ke mode PIP selagi mengontrol pemutaran video.</p>
    ++
    ++<img src="{@docRoot}images/android-7.0/pip-button.png" />
    ++<p class="img-caption"><strong>Gambar 1.</strong> Tombol
    ++gambar-dalam-gambar pada baris kontrol media.</p>
    ++
    ++<p>Android N menyertakan kelas
    ++<code>PlaybackControlsRow.PictureInPictureAction</code> baru yang mendefinisikan
    ++tindakan PIP baris kontrol dan menggunakan ikon PIP.</p>
    ++
    ++<h2 id="handling_ui">Menangani UI Selama Gambar-dalam-gambar</h2>
    ++
    ++<p>Bila aktivitas memasuki mode PIP, aktivitas Anda seharusnya hanya menampilkan pemutaran
    ++video. Buang elemen UI sebelum aktivitas Anda memasuki PIP,
    ++dan pulihkan elemen ini bila aktivitas Anda beralih ke layar penuh lagi.
    ++Ganti <code>Activity.onPictureInPictureModeChanged()</code> atau
    ++<code>Fragment.onPictureInPictureModeChanged()</code> dan aktifkan atau
    ++nonaktifkan elemen UI saat diperlukan, misalnya:</p>
    ++
    ++<pre>
    ++&#64;Override
    ++public void onPictureInPictureModeChanged(boolean isInPictureInPictureMode) {
    ++    if (isInPictureInPictureMode) {
    ++        // Hide the controls in picture-in-picture mode.
    ++        ...
    ++    } else {
    ++        // Restore the playback UI based on the playback status.
    ++        ...
    ++    }
    ++}
    ++</pre>
    ++
    ++<h2 id="continuing_playback">Melanjutkan Pemutaran Video Saat dalam
    ++Gambar-dalam-gambar</h2>
    ++
    ++<p>Bila aktivitas Anda beralih ke PIP, sistem akan menganggap aktivitas tersebut berada dalam
    ++keadaan berhenti sementara, dan akan memanggil metode <code>onPause()</code> aktivitas Anda. Pemutaran
    ++video tidak boleh berhenti sementara dan harus terus diputar jika aktivitas tersebut
    ++berhenti sementara karena mode PIP. Periksa PIP dalam metode
    ++<code>onPause()</code> aktivitas Anda dan tangani pemutaran dengan tepat,
    ++misalnya:</p>
    ++
    ++<pre>
    ++&#64;Override
    ++public void onPause() {
    ++    // If called while in PIP mode, do not pause playback
    ++    if (isInPictureInPictureMode()) {
    ++        // Continue playback
    ++        ...
    ++    }
    ++    // If paused but not in PIP, pause playback if necessary
    ++    ...
    ++}
    ++</pre>
    ++
    ++<p>Bila aktivitas meninggalkan mode PIP dan kembali ke mode layar penuh, sistem
    ++akan melanjutkan aktivitas Anda dan memanggil metode <code>onResume()</code>.</p>
    ++
    ++<h2 id="single_playback">Menggunakan Aktivitas Pemutaran Tunggal untuk
    ++ Gambar-dalam-gambar</h2>
    ++
    ++<p>Di aplikasi Anda, seorang pengguna bisa memilih video baru saat menyusuri materi di
    ++layar utama, selagi aktivitas pemutaran video dalam mode PIP. Putar
    ++video baru di aktivitas pemutaran yang ada dalam mode layar penuh, sebagai ganti
    ++meluncurkan aktivitas baru yang dapat membingungkan pengguna.</p>
    ++
    ++<p>Guna memastikan aktivitas tunggal digunakan untuk permintaan pemutaran video dan
    ++beralih ke atau dari mode PIP bila dibutuhkan, setel
    ++<code>android:launchMode</code> aktivitas ke <code>singleTask</code> dalam manifes Anda:
    ++</p>
    ++
    ++<pre>
    ++&lt;activity android:name="VideoActivity"
    ++    ...
    ++    android:supportsPictureInPicture="true"
    ++    android:launchMode="singleTask"
    ++    ...
    ++</pre>
    ++
    ++<p>Di aktivitas Anda, ganti {@link android.app.Activity#onNewIntent
    ++Activity.onNewIntent()} dan tangani video baru, yang akan menghentikan pemutaran video
    ++jika diperlukan.</p>
    ++
    ++<h2 id="best">Praktik Terbaik</h2>
    ++
    ++<p>PIP ditujukan untuk aktivitas yang memutar video layar penuh. Saat mengalihkan
    ++aktivitas Anda ke mode PIP, hindari menampilkan apa pun selain materi video.
    ++Pantau saat aktivitas Anda memasuki mode PIP dan sembunyikan elemen UI, seperti dijelaskan
    ++dalam <a href="#handling_ui">Menangani UI Selama Gambar-dalam-gambar</a>.</p>
    ++
    ++<p>Karena jendela PIP ditampilkan sebagai jendela mengambang di sudut
    ++layar, Anda harus menghindari menampilkan informasi penting di layar utama
    ++di area mana saja yang bisa terhalang oleh jendela PIP.</p>
    ++
    ++<p>Bila aktivitas ada berada dalam mode PIP, secara default aktivitas itu tidak mendapatkan fokus masukan. Untuk
    ++menerima kejadian masukan saat dalam mode PIP, gunakan
    ++<code>MediaSession.setMediaButtonReceiver()</code>.</p>
    +diff --git a/docs/html-intl/intl/id/training/tv/tif/content-recording.jd b/docs/html-intl/intl/id/training/tv/tif/content-recording.jd
    +new file mode 100644
    +index 0000000..3389dbf
    +--- /dev/null
    ++++ b/docs/html-intl/intl/id/training/tv/tif/content-recording.jd
    +@@ -0,0 +1,142 @@
    ++page.title=Perekaman TV
    ++page.keywords=pratinjau,sdk,tv,perekaman
    ++page.tags=androidn
    ++page.image=images/cards/card-nyc_2x.jpg
    ++
    ++@jd:body
    ++
    ++<div id="tb-wrapper">
    ++<div id="tb">
    ++  <h2>Dalam dokumen ini</h2>
    ++  <ol>
    ++    <li><a href="#supporting">Menunjukkan Dukungan untuk Perekaman</a></li>
    ++    <li><a href="#recording">Merekam Sesi</a></li>
    ++    <li><a href="#errors">Menangani Kesalahan Perekaman</a></li>
    ++    <li><a href="#sessions">Mengelola Sesi yang Direkam</a></li>
    ++    <li><a href="#best">Praktik Terbaik</a></li>
    ++  </ol>
    ++</div>
    ++</div>
    ++
    ++<p>Layanan masukan TV memungkinkan pengguna menghentikan sementara dan melanjutkan pemutaran saluran melalui
    ++API perekaman. Android N telah berkembang hingga ke perekaman
    ++dengan memungkinkan pengguna menyimpan beberapa sesi rekaman.</p>
    ++
    ++<p>Pengguna bisa menjadwalkan rekaman terlebih dahulu, atau memulai rekaman sambil menonton
    ++suatu acara. Setelah sistem menyimpan rekaman, pengguna bisa menjelajah, menata,
    ++dan memutar kembali rekaman tersebut menggunakan aplikasi TV di sistem.</p>
    ++
    ++<p>Jika Anda ingin menyediakan fungsi perekaman untuk layanan masukan TV,
    ++Anda harus menunjukkan pada sistem bahwa aplikasi Anda mendukung perekaman, mengimplementasikan
    ++kemampuan merekam program, menangani dan mengomunikasikan kesalahan yang muncul
    ++selama perekaman, dan mengelola sesi perekaman Anda.</p>
    ++
    ++<p class="note"><strong>Catatan:</strong> Aplikasi Live Channels belum
    ++menyediakan cara bagi pengguna untuk membuat atau mengakses perekaman. Hingga dibuat perubahan
    ++di aplikasi Live Channels, mungkin sulit menguji sepenuhnya pengalaman
    ++perekaman untuk layanan masukan TV Anda.</p>
    ++
    ++<h2 id="supporting">Menunjukkan Dukungan untuk Perekaman</h2>
    ++
    ++<p>Untuk memberi tahu sistem bahwa layanan masukan TV Anda mendukung perekaman, setel
    ++atribut <code>android:canRecord</code> di file XML metadata layanan Anda
    ++ke <code>true</code>:
    ++</p>
    ++
    ++<pre>
    ++&lt;tv-input xmlns:android="http://schemas.android.com/apk/res/android"
    ++  <b>android:canRecord="true"</b>
    ++  android:setupActivity="com.example.sampletvinput.SampleTvInputSetupActivity" /&gt;
    ++</pre>
    ++
    ++<p>Untuk informasi selengkapnya mengenai layanan file metadata, lihat
    ++<a href="{@docRoot}training/tv/tif/tvinput.html#manifest">Mendeklarasikan Layanan Masukan TV Anda
    ++di Manifes</a>.
    ++</p>
    ++
    ++<p>Atau, Anda bisa menunjukkan dukungan perekaman dalam kode Anda menggunakan
    ++langkah-langkah ini:</p>
    ++
    ++<ol>
    ++<li>Dalam metode <code>TvInputService.onCreate()</code> Anda, buat objek
    ++<code>TvInputInfo</code> baru menggunakan kelas <code>TvInputInfo.Builder</code>.
    ++</li>
    ++<li>Saat membuat objek <code>TvInputInfo</code> baru, panggil
    ++<code>setCanRecord(true)</code> sebelum memanggil <code>build()</code> untuk
    ++ menunjukkan layanan Anda mendukung perekaman.</li>
    ++<li>Daftarkan objek <code>TvInputInfo</code> Anda pada sistem dengan memanggil
    ++<code>TvInputManager.updateTvInputInfo()</code>.</li>
    ++</ol>
    ++
    ++<h2 id="recording">Merekam Sesi</h2>
    ++
    ++<p>Setelah layanan masukan TV Anda mendaftar bahwa mendukung fungsionalitas
    ++perekaman, sistem akan memanggil
    ++<code>TvInputService.onCreateRecordingSession()</code> bila perlu untuk mengakses
    ++implementasi perekaman aplikasi Anda. Implementasikan subkelas
    ++<code>TvInputService.RecordingSession</code> Anda sendiri dan kembalikan
    ++bila callback <code>onCreateRecordingSession()</code> dipicu.
    ++ Subkelas ini bertanggung jawab mengalihkan ke saluran data yang benar,
    ++merekam data yang diminta, dan memberitahukan status perekaman serta kesalahan ke
    ++sistem.</p>
    ++
    ++<p>Bila sistem memanggil <code>RecordingSession.onTune()</code>, dengan meneruskan
    ++URI saluran, setel ke saluran yang ditetapkan URI. Beri tahu sistem bahwa
    ++aplikasi Anda telah disetel ke saluran yang diinginkan dengan memanggil <code>notifyTuned()</code>,
    ++atau, jika aplikasi Anda tidak bisa disetel ke saluran yang tepat, panggil
    ++<code>notifyError()</code>.</p>
    ++
    ++<p>Sistem berikutnya akan memanggil callback <code>RecordingSession.onStartRecording()</code>.
    ++ Aplikasi Anda harus segera mulai merekam. Bila sistem memanggil
    ++callback ini, sistem mungkin akan memberikan URI yang berisi informasi tentang program
    ++yang akan direkam. Bila perekaman selesai, Anda perlu menyalin data
    ++ini ke tabel data <code>RecordedPrograms</code>.</p>
    ++
    ++<p>Terakhir, sistem akan memanggil <code>RecordingSession.onStopRecording()</code>.
    ++Pada tahap ini, aplikasi Anda harus segera berhenti merekam. Anda juga perlu
    ++membuat entri dalam tabel <code>RecordedPrograms</code>. Entri ini harus
    ++menyertakan URI data sesi yang direkam dalam kolom
    ++<code>RecordedPrograms.COLUMN_RECORDING_DATA_URI</code>, dan informasi
    ++program yang diberikan sistem dalam panggilan awal ke
    ++<code>onStartRecording()</code>.</p>
    ++
    ++<p>Untuk detail selengkapnya tentang cara mengakses tabel <code>RecordedPrograms</code>
    ++lihat <a href="#sessions">Mengelola Sesi yang Direkam</a>.</p>
    ++
    ++<h2 id="errors">Menangani Kesalahan Perekaman</h2>
    ++
    ++<p>Jika terjadi kesalahan selama perekaman, yang menghasilkan data terekam yang tidak bisa digunakan,
    ++beri tahu sistem dengan memanggil <code>RecordingSession.notifyError()</code>.
    ++Begitu juga, Anda bisa memanggil <code>notifyError()</code> setelah sesi rekaman dibuat
    ++agar sistem mengetahui bahwa aplikasi Anda tidak bisa lagi merekam sesi.</p>
    ++
    ++<p>Jika terjadi kesalahan selama perekaman, namun Anda ingin menyediakan rekaman parsial
    ++yang bisa digunakan pengguna untuk pemutaran, panggil
    ++<code>RecordingSession.notifyRecordingStopped()</code> untuk memungkinkan sistem
    ++menggunakan sesi parsial.</p>
    ++
    ++<h2 id="sessions">Mengelola Sesi yang Direkam</h2>
    ++
    ++<p>Sistem menyimpan informasi untuk semua sesi yang direkam dari semua
    ++aplikasi saluran yang mampu merekam dalam tabel penyedia materi <code>TvContract.RecordedPrograms</code>.
    ++ Informasi ini bisa diakses lewat URI materi
    ++<code>RecordedPrograms.Uri</code>. Gunakan API penyedia materi untuk
    ++membaca, menambahkan, dan menghapus entri dari tabel ini.</p>
    ++
    ++<p>Untuk informasi selengkapnya tentang menangani data penyedia materi, lihat
    ++<a href="{@docRoot}guide/topics/providers/content-provider-basics.html">
    ++Dasar-Dasar Penyedia Materi</a>.</p>
    ++
    ++<h2 id="best">Praktik Terbaik</h2>
    ++
    ++<p>Perangkat TV mungkin memiliki penyimpanan terbatas, jadi pertimbangkan sebaik mungkin saat
    ++mengalokasikan penyimpanan untuk menyimpan sesi rekaman. Gunakan
    ++<code>RecordingCallback.onError(RECORDING_ERROR_INSUFFICIENT_SPACE)</code> bila
    ++tidak cukup ruang untuk menyimpan sesi rekaman.</p>
    ++
    ++<p>Bila pengguna memulai perekaman, Anda harus memulai perekaman data
    ++secepatnya. Untuk memfasilitasinya, selesaikan setiap tugas yang memakan waktu di awal,
    ++seperti mengakses dan mengalokasikan ruang penyimpanan, saat sistem memanggil callback
    ++<code>onCreateRecordingSession()</code>. Hal ini akan memungkinkan Anda memulai
    ++perekaman dengan segera bila callback <code>onStartRecording()</code>
    ++dipicu.</p>
    +diff --git a/docs/html-intl/intl/in/about/versions/nougat/index.jd b/docs/html-intl/intl/in/about/versions/nougat/index.jd
    +index 5234f91..212870a 100644
    +--- a/docs/html-intl/intl/in/about/versions/nougat/index.jd
    ++++ b/docs/html-intl/intl/in/about/versions/nougat/index.jd
    +@@ -7,16 +7,6 @@ header.hide=1
    + footer.hide=1
    + @jd:body
    + 
    +-<script>
    +-  $(document).ready(function() {
    +-    if (useUpdatedTemplates) {
    +-      $("#useUpdatedTemplates").css("display","block");
    +-    } else {
    +-      $("#useOldTemplates").css("display","block");
    +-    }
    +-  })
    +-</script>
    +-
    + <section class="dac-expand dac-hero dac-light">
    +   <div class="wrap" style="max-width:1100px;margin-top:0">
    +   <a href="{@docRoot}about/versions/nougat/android-7.0.html">
    +@@ -55,7 +45,7 @@ footer.hide=1
    + </section>
    + 
    + 
    +-<div id="useUpdatedTemplates" style="display:none" class="dac-section dac-slim dac-gray dac-expand">
    ++<div class="dac-section dac-slim dac-gray dac-expand">
    +   <div class="wrap dac-offset-parent">
    +     <a class="dac-fab dac-scroll-button" data-scroll-button href="#latest">
    +       <i class="dac-sprite dac-arrow-down-gray"></i>
    +@@ -77,26 +67,6 @@ footer.hide=1
    +   </div><!-- end .wrap -->
    + </div><!-- end .dac-actions -->
    + 
    +-<div id="useOldTemplates" style="display:none;color:black" class="actions-bar dac-expand dac-invert">
    +-  <div class="wrap dac-offset-parent">
    +-
    +-    <div class="actions">
    +-      <div><a href="https://developer.android.com/preview/bug">
    +-        <span class="dac-sprite dac-auto-chevron-large"></span>
    +-        Laporkan masalah
    +-          </a></div>
    +-      <div><a href="{@docRoot}preview/support.html">
    +-        <span class="dac-sprite dac-auto-chevron-large"></span>
    +-        Lihat catatan rilis
    +-          </a></div>
    +-      <div><a href="{@docRoot}preview/dev-community">
    +-        <span class="dac-sprite dac-auto-chevron-large"></span>
    +-        Bergabunglah dengan komunitas pengembang
    +-          </a></div>
    +-    </div><!-- end .actions -->
    +-  </div><!-- end .wrap -->
    +-</div>
    +-
    + <section class="dac-section dac-light dac-small" id="latest"><div class="wrap">
    +   <h2 class="norule">Terbaru</h2>
    +   <div class="resource-widget resource-flow-layout col-16"
    +diff --git a/docs/html-intl/intl/ja/about/versions/nougat/index.jd b/docs/html-intl/intl/ja/about/versions/nougat/index.jd
    +index 5881cf6..7c5fe5d 100644
    +--- a/docs/html-intl/intl/ja/about/versions/nougat/index.jd
    ++++ b/docs/html-intl/intl/ja/about/versions/nougat/index.jd
    +@@ -7,16 +7,6 @@ header.hide=1
    + footer.hide=1
    + @jd:body
    + 
    +-<script>
    +-  $(document).ready(function() {
    +-    if (useUpdatedTemplates) {
    +-      $("#useUpdatedTemplates").css("display","block");
    +-    } else {
    +-      $("#useOldTemplates").css("display","block");
    +-    }
    +-  })
    +-</script>
    +-
    + <section class="dac-expand dac-hero dac-light">
    +   <div class="wrap" style="max-width:1100px;margin-top:0">
    +   <a href="{@docRoot}about/versions/nougat/android-7.0.html">
    +@@ -55,7 +45,7 @@ footer.hide=1
    + </section>
    + 
    + 
    +-<div id="useUpdatedTemplates" style="display:none" class="dac-section dac-slim dac-gray dac-expand">
    ++<div class="dac-section dac-slim dac-gray dac-expand">
    +   <div class="wrap dac-offset-parent">
    +     <a class="dac-fab dac-scroll-button" data-scroll-button href="#latest">
    +       <i class="dac-sprite dac-arrow-down-gray"></i>
    +@@ -77,26 +67,6 @@ footer.hide=1
    +   </div><!-- end .wrap -->
    + </div><!-- end .dac-actions -->
    + 
    +-<div id="useOldTemplates" style="display:none;color:black" class="actions-bar dac-expand dac-invert">
    +-  <div class="wrap dac-offset-parent">
    +-
    +-    <div class="actions">
    +-      <div><a href="https://developer.android.com/preview/bug">
    +-        <span class="dac-sprite dac-auto-chevron-large"></span>
    +-        問題の報告</a>
    +-</div>
    +-      <div><a href="{@docRoot}preview/support.html">
    +-        <span class="dac-sprite dac-auto-chevron-large"></span>
    +-        リリースノートの確認</a>
    +-</div>
    +-      <div><a href="{@docRoot}preview/dev-community">
    +-        <span class="dac-sprite dac-auto-chevron-large"></span>
    +-        開発者コミュニティに参加</a>
    +-</div>
    +-    </div><!-- end .actions -->
    +-  </div><!-- end .wrap -->
    +-</div>
    +-
    + <section class="dac-section dac-light dac-small" id="latest"><div class="wrap">
    +   <h2 class="norule">新着</h2>
    +   <div class="resource-widget resource-flow-layout col-16"
    +diff --git a/docs/html-intl/intl/ja/index.jd b/docs/html-intl/intl/ja/index.jd
    +index ba73c41..3220f19 100644
    +--- a/docs/html-intl/intl/ja/index.jd
    ++++ b/docs/html-intl/intl/ja/index.jd
    +@@ -5,16 +5,6 @@ page.customHeadTag=<meta name="google-site-verification" content="sa-bIAI6GKvct3
    + 
    + @jd:body
    + 
    +-<script>
    +-  $(document).ready(function() {
    +-    if (useUpdatedTemplates) {
    +-      $("#useUpdatedTemplates").css("display","block");
    +-    } else {
    +-      $("#useOldTemplates").css("display","block");
    +-    }
    +-  })
    +-</script>
    +-
    + <section class="dac-expand dac-hero" style="background-color:#b2dfdb;">
    +   <div class="wrap" style="max-width:1000px;margin-top:0">
    +     <div class="col-7of16 col-push-8of16">
    +@@ -44,7 +34,7 @@ page.customHeadTag=<meta name="google-site-verification" content="sa-bIAI6GKvct3
    +   </div>
    + </section>
    + 
    +-<div id="useUpdatedTemplates" style="display:none" class="dac-section dac-slim dac-gray dac-expand">
    ++<div class="dac-section dac-slim dac-gray dac-expand">
    +   <div class="wrap dac-offset-parent">
    +     <a class="dac-fab dac-scroll-button" data-scroll-button href="#build-apps">
    +       <i class="dac-sprite dac-arrow-down-gray"></i>
    +@@ -72,28 +62,6 @@ page.customHeadTag=<meta name="google-site-verification" content="sa-bIAI6GKvct3
    +   </div><!-- end .wrap -->
    + </div><!-- end .dac-actions -->
    + 
    +-<div id="useOldTemplates" style="display:none" class="actions-bar dac-expand dac-invert">
    +-  <div class="wrap dac-offset-parent">
    +-    <a class="dac-fab dac-scroll-button" data-scroll-button="" href="#build-apps">
    +-      <i class="dac-sprite dac-arrow-down-gray"></i>
    +-    </a>
    +-    <div class="actions">
    +-      <div><a href="{@docRoot}sdk/index.html">
    +-        <span class="dac-sprite dac-auto-chevron-large"></span>
    +-        Get the SDK
    +-      </a></div>
    +-      <div><a href="{@docRoot}samples/index.html">
    +-        <span class="dac-sprite dac-auto-chevron-large"></span>
    +-        Browse Samples
    +-      </a></div>
    +-      <div><a href="{@docRoot}distribute/stories/index.html">
    +-        <span class="dac-sprite dac-auto-chevron-large"></span>
    +-        Watch Stories
    +-      </a></div>
    +-    </div><!-- end .actions -->
    +-  </div><!-- end .wrap -->
    +-</div>
    +-
    + <section class="dac-section dac-light" id="build-apps"><div class="wrap">
    +   <h1 class="dac-section-title">Build Beautiful Apps</h1>
    +   <div class="dac-section-subtitle">
    +diff --git a/docs/html-intl/intl/ko/about/versions/nougat/index.jd b/docs/html-intl/intl/ko/about/versions/nougat/index.jd
    +index 6ed065b..20561a4 100644
    +--- a/docs/html-intl/intl/ko/about/versions/nougat/index.jd
    ++++ b/docs/html-intl/intl/ko/about/versions/nougat/index.jd
    +@@ -7,16 +7,6 @@ header.hide=1
    + footer.hide=1
    + @jd:body
    + 
    +-<script>
    +-  $(document).ready(function() {
    +-    if (useUpdatedTemplates) {
    +-      $("#useUpdatedTemplates").css("display","block");
    +-    } else {
    +-      $("#useOldTemplates").css("display","block");
    +-    }
    +-  })
    +-</script>
    +-
    + <section class="dac-expand dac-hero dac-light">
    +   <div class="wrap" style="max-width:1100px;margin-top:0">
    +   <a href="{@docRoot}about/versions/nougat/android-7.0.html">
    +@@ -54,7 +44,7 @@ footer.hide=1
    +   </div>
    + </section>
    + 
    +-<div id="useUpdatedTemplates" style="display:none" class="dac-section dac-slim dac-gray dac-expand">
    ++<div class="dac-section dac-slim dac-gray dac-expand">
    +   <div class="wrap dac-offset-parent">
    +     <a class="dac-fab dac-scroll-button" data-scroll-button href="#latest">
    +       <i class="dac-sprite dac-arrow-down-gray"></i>
    +@@ -76,26 +66,6 @@ footer.hide=1
    +   </div><!-- end .wrap -->
    + </div><!-- end .dac-actions -->
    + 
    +-<div id="useOldTemplates" style="display:none;color:black" class="actions-bar dac-expand dac-invert">
    +-  <div class="wrap dac-offset-parent">
    +-
    +-    <div class="actions">
    +-      <div><a href="https://developer.android.com/preview/bug">
    +-        <span class="dac-sprite dac-auto-chevron-large"></span>
    +-        문제 보고
    +-      </a></div>
    +-      <div><a href="{@docRoot}preview/support.html">
    +-        <span class="dac-sprite dac-auto-chevron-large"></span>
    +-        릴리스 노트 보기
    +-        </a></div>
    +-      <div><a href="{@docRoot}preview/dev-community">
    +-        <span class="dac-sprite dac-auto-chevron-large"></span>
    +-        개발자 커뮤니티 가입
    +-      </a></div>
    +-    </div><!-- end .actions -->
    +-  </div><!-- end .wrap -->
    +-</div>
    +-
    + <section class="dac-section dac-light dac-small" id="latest"><div class="wrap">
    +   <h2 class="norule">최신</h2>
    +   <div class="resource-widget resource-flow-layout col-16"
    +diff --git a/docs/html-intl/intl/ko/guide/topics/providers/content-provider-basics.jd b/docs/html-intl/intl/ko/guide/topics/providers/content-provider-basics.jd
    +index 68ed568..0f58b79 100644
    +--- a/docs/html-intl/intl/ko/guide/topics/providers/content-provider-basics.jd
    ++++ b/docs/html-intl/intl/ko/guide/topics/providers/content-provider-basics.jd
    +@@ -891,7 +891,7 @@ mRowsDeleted = getContentResolver().delete(
    +     사용자 사전 제공자의 데이터 유형은 제공자의 계약 클래스
    + {@link android.provider.UserDictionary.Words}의 참조 문서에 나열되어 있습니다(계약 클래스는
    + <a href="#ContractClasses">계약 클래스</a> 섹션에 설명되어 있습니다).
    +-    @link android.database.Cursor#getType
    ++    {@link android.database.Cursor#getType
    +     Cursor.getType()}을 호출해서도 데이터 유형을 결정할 수 있습니다.
    + </p>
    + <p>
    +diff --git a/docs/html-intl/intl/ko/index.jd b/docs/html-intl/intl/ko/index.jd
    +index e102411..b459df7 100644
    +--- a/docs/html-intl/intl/ko/index.jd
    ++++ b/docs/html-intl/intl/ko/index.jd
    +@@ -5,16 +5,6 @@ page.customHeadTag=<meta name="google-site-verification" content="sa-bIAI6GKvct3
    + 
    + @jd:body
    + 
    +-<script>
    +-  $(document).ready(function() {
    +-    if (useUpdatedTemplates) {
    +-      $("#useUpdatedTemplates").css("display","block");
    +-    } else {
    +-      $("#useOldTemplates").css("display","block");
    +-    }
    +-  })
    +-</script>
    +-
    + <section class="dac-expand dac-hero" style="background-color:#b2dfdb;">
    +   <div class="wrap" style="max-width:1000px;margin-top:0">
    +     <div class="col-7of16 col-push-8of16">
    +@@ -44,7 +34,7 @@ page.customHeadTag=<meta name="google-site-verification" content="sa-bIAI6GKvct3
    +   </div>
    + </section>
    + 
    +-<div id="useUpdatedTemplates" style="display:none" class="dac-section dac-slim dac-gray dac-expand">
    ++<div class="dac-section dac-slim dac-gray dac-expand">
    +   <div class="wrap dac-offset-parent">
    +     <a class="dac-fab dac-scroll-button" data-scroll-button href="#build-apps">
    +       <i class="dac-sprite dac-arrow-down-gray"></i>
    +@@ -72,28 +62,6 @@ page.customHeadTag=<meta name="google-site-verification" content="sa-bIAI6GKvct3
    +   </div><!-- end .wrap -->
    + </div><!-- end .dac-actions -->
    + 
    +-<div id="useOldTemplates" style="display:none" class="actions-bar dac-expand dac-invert">
    +-  <div class="wrap dac-offset-parent">
    +-    <a class="dac-fab dac-scroll-button" data-scroll-button="" href="#build-apps">
    +-      <i class="dac-sprite dac-arrow-down-gray"></i>
    +-    </a>
    +-    <div class="actions">
    +-      <div><a href="{@docRoot}sdk/index.html">
    +-        <span class="dac-sprite dac-auto-chevron-large"></span>
    +-        Get the SDK
    +-      </a></div>
    +-      <div><a href="{@docRoot}samples/index.html">
    +-        <span class="dac-sprite dac-auto-chevron-large"></span>
    +-        Browse Samples
    +-      </a></div>
    +-      <div><a href="{@docRoot}distribute/stories/index.html">
    +-        <span class="dac-sprite dac-auto-chevron-large"></span>
    +-        Watch Stories
    +-      </a></div>
    +-    </div><!-- end .actions -->
    +-  </div><!-- end .wrap -->
    +-</div>
    +-
    + <section class="dac-section dac-light" id="build-apps"><div class="wrap">
    +   <h1 class="dac-section-title">Build Beautiful Apps</h1>
    +   <div class="dac-section-subtitle">
    +diff --git a/docs/html-intl/intl/pt-br/about/versions/nougat/index.jd b/docs/html-intl/intl/pt-br/about/versions/nougat/index.jd
    +index c7aee2a..ff44f6a 100644
    +--- a/docs/html-intl/intl/pt-br/about/versions/nougat/index.jd
    ++++ b/docs/html-intl/intl/pt-br/about/versions/nougat/index.jd
    +@@ -7,16 +7,6 @@ header.hide=1
    + footer.hide=1
    + @jd:body
    + 
    +-<script>
    +-  $(document).ready(function() {
    +-    if (useUpdatedTemplates) {
    +-      $("#useUpdatedTemplates").css("display","block");
    +-    } else {
    +-      $("#useOldTemplates").css("display","block");
    +-    }
    +-  })
    +-</script>
    +-
    + <section class="dac-expand dac-hero dac-light">
    +   <div class="wrap" style="max-width:1100px;margin-top:0">
    +   <a href="{@docRoot}about/versions/nougat/android-7.0.html">
    +@@ -54,7 +44,7 @@ footer.hide=1
    +   </div>
    + </section>
    + 
    +-<div id="useUpdatedTemplates" style="display:none" class="dac-section dac-slim dac-gray dac-expand">
    ++<div class="dac-section dac-slim dac-gray dac-expand">
    +   <div class="wrap dac-offset-parent">
    +     <a class="dac-fab dac-scroll-button" data-scroll-button href="#latest">
    +       <i class="dac-sprite dac-arrow-down-gray"></i>
    +diff --git a/docs/html-intl/intl/pt-br/index.jd b/docs/html-intl/intl/pt-br/index.jd
    +index 3c8f75d..b15ecc8 100644
    +--- a/docs/html-intl/intl/pt-br/index.jd
    ++++ b/docs/html-intl/intl/pt-br/index.jd
    +@@ -5,16 +5,6 @@ page.customHeadTag=<meta name="google-site-verification" content="sa-bIAI6GKvct3
    + 
    + @jd:body
    + 
    +-<script>
    +-  $(document).ready(function() {
    +-    if (useUpdatedTemplates) {
    +-      $("#useUpdatedTemplates").css("display","block");
    +-    } else {
    +-      $("#useOldTemplates").css("display","block");
    +-    }
    +-  })
    +-</script>
    +-
    + <section class="dac-expand dac-hero" style="background-color:#b2dfdb;">
    +   <div class="wrap" style="max-width:1000px;margin-top:0">
    +     <div class="col-7of16 col-push-8of16">
    +@@ -44,7 +34,7 @@ page.customHeadTag=<meta name="google-site-verification" content="sa-bIAI6GKvct3
    +   </div>
    + </section>
    + 
    +-<div id="useUpdatedTemplates" style="display:none" class="dac-section dac-slim dac-gray dac-expand">
    ++<div class="dac-section dac-slim dac-gray dac-expand">
    +   <div class="wrap dac-offset-parent">
    +     <a class="dac-fab dac-scroll-button" data-scroll-button href="#build-apps">
    +       <i class="dac-sprite dac-arrow-down-gray"></i>
    +@@ -72,28 +62,6 @@ page.customHeadTag=<meta name="google-site-verification" content="sa-bIAI6GKvct3
    +   </div><!-- end .wrap -->
    + </div><!-- end .dac-actions -->
    + 
    +-<div id="useOldTemplates" style="display:none" class="actions-bar dac-expand dac-invert">
    +-  <div class="wrap dac-offset-parent">
    +-    <a class="dac-fab dac-scroll-button" data-scroll-button="" href="#build-apps">
    +-      <i class="dac-sprite dac-arrow-down-gray"></i>
    +-    </a>
    +-    <div class="actions">
    +-      <div><a href="{@docRoot}sdk/index.html">
    +-        <span class="dac-sprite dac-auto-chevron-large"></span>
    +-        Get the SDK
    +-      </a></div>
    +-      <div><a href="{@docRoot}samples/index.html">
    +-        <span class="dac-sprite dac-auto-chevron-large"></span>
    +-        Browse Samples
    +-      </a></div>
    +-      <div><a href="{@docRoot}distribute/stories/index.html">
    +-        <span class="dac-sprite dac-auto-chevron-large"></span>
    +-        Watch Stories
    +-      </a></div>
    +-    </div><!-- end .actions -->
    +-  </div><!-- end .wrap -->
    +-</div>
    +-
    + <section class="dac-section dac-light" id="build-apps"><div class="wrap">
    +   <h1 class="dac-section-title">Build Beautiful Apps</h1>
    +   <div class="dac-section-subtitle">
    +diff --git a/docs/html-intl/intl/ru/about/versions/nougat/index.jd b/docs/html-intl/intl/ru/about/versions/nougat/index.jd
    +index 1103166..0365061 100644
    +--- a/docs/html-intl/intl/ru/about/versions/nougat/index.jd
    ++++ b/docs/html-intl/intl/ru/about/versions/nougat/index.jd
    +@@ -7,16 +7,6 @@ header.hide=1
    + footer.hide=1
    + @jd:body
    + 
    +-<script>
    +-  $(document).ready(function() {
    +-    if (useUpdatedTemplates) {
    +-      $("#useUpdatedTemplates").css("display","block");
    +-    } else {
    +-      $("#useOldTemplates").css("display","block");
    +-    }
    +-  })
    +-</script>
    +-
    + <section class="dac-expand dac-hero dac-light">
    +   <div class="wrap" style="max-width:1100px;margin-top:0">
    +   <a href="{@docRoot}about/versions/nougat/android-7.0.html">
    +@@ -54,7 +44,7 @@ footer.hide=1
    +   </div>
    + </section>
    + 
    +-<div id="useUpdatedTemplates" style="display:none" class="dac-section dac-slim dac-gray dac-expand">
    ++<div class="dac-section dac-slim dac-gray dac-expand">
    +   <div class="wrap dac-offset-parent">
    +     <a class="dac-fab dac-scroll-button" data-scroll-button href="#latest">
    +       <i class="dac-sprite dac-arrow-down-gray"></i>
    +@@ -76,26 +66,6 @@ footer.hide=1
    +   </div><!-- end .wrap -->
    + </div><!-- end .dac-actions -->
    + 
    +-<div id="useOldTemplates" style="display:none;color:black" class="actions-bar dac-expand dac-invert">
    +-  <div class="wrap dac-offset-parent">
    +-
    +-    <div class="actions">
    +-      <div><a href="https://developer.android.com/preview/bug">
    +-        <span class="dac-sprite dac-auto-chevron-large"></span>
    +-        Сообщить о проблеме
    +-        </a></div>
    +-      <div><a href="{@docRoot}preview/support.html">
    +-        <span class="dac-sprite dac-auto-chevron-large"></span>
    +-        См. примечания к выпуску
    +-        </a></div>
    +-      <div><a href="{@docRoot}preview/dev-community">
    +-        <span class="dac-sprite dac-auto-chevron-large"></span>
    +-        Вступить в сообщество разработчиков
    +-        </a></div>
    +-    </div><!-- end .actions -->
    +-  </div><!-- end .wrap -->
    +-</div>
    +-
    + <section class="dac-section dac-light dac-small" id="latest"><div class="wrap">
    +   <h2 class="norule">Latest</h2>
    +   <div class="resource-widget resource-flow-layout col-16"
    +diff --git a/docs/html-intl/intl/ru/index.jd b/docs/html-intl/intl/ru/index.jd
    +index b3f3cc2..83a506e 100644
    +--- a/docs/html-intl/intl/ru/index.jd
    ++++ b/docs/html-intl/intl/ru/index.jd
    +@@ -5,16 +5,6 @@ page.customHeadTag=<meta name="google-site-verification" content="sa-bIAI6GKvct3
    + 
    + @jd:body
    + 
    +-<script>
    +-  $(document).ready(function() {
    +-    if (useUpdatedTemplates) {
    +-      $("#useUpdatedTemplates").css("display","block");
    +-    } else {
    +-      $("#useOldTemplates").css("display","block");
    +-    }
    +-  })
    +-</script>
    +-
    + <section class="dac-expand dac-hero" style="background-color:#b2dfdb;">
    +   <div class="wrap" style="max-width:1000px;margin-top:0">
    +     <div class="col-7of16 col-push-8of16">
    +@@ -44,7 +34,7 @@ page.customHeadTag=<meta name="google-site-verification" content="sa-bIAI6GKvct3
    +   </div>
    + </section>
    + 
    +-<div id="useUpdatedTemplates" style="display:none" class="dac-section dac-slim dac-gray dac-expand">
    ++<div class="dac-section dac-slim dac-gray dac-expand">
    +   <div class="wrap dac-offset-parent">
    +     <a class="dac-fab dac-scroll-button" data-scroll-button href="#build-apps">
    +       <i class="dac-sprite dac-arrow-down-gray"></i>
    +@@ -72,28 +62,6 @@ page.customHeadTag=<meta name="google-site-verification" content="sa-bIAI6GKvct3
    +   </div><!-- end .wrap -->
    + </div><!-- end .dac-actions -->
    + 
    +-<div id="useOldTemplates" style="display:none" class="actions-bar dac-expand dac-invert">
    +-  <div class="wrap dac-offset-parent">
    +-    <a class="dac-fab dac-scroll-button" data-scroll-button="" href="#build-apps">
    +-      <i class="dac-sprite dac-arrow-down-gray"></i>
    +-    </a>
    +-    <div class="actions">
    +-      <div><a href="{@docRoot}sdk/index.html">
    +-        <span class="dac-sprite dac-auto-chevron-large"></span>
    +-        Get the SDK
    +-      </a></div>
    +-      <div><a href="{@docRoot}samples/index.html">
    +-        <span class="dac-sprite dac-auto-chevron-large"></span>
    +-        Browse Samples
    +-      </a></div>
    +-      <div><a href="{@docRoot}distribute/stories/index.html">
    +-        <span class="dac-sprite dac-auto-chevron-large"></span>
    +-        Watch Stories
    +-      </a></div>
    +-    </div><!-- end .actions -->
    +-  </div><!-- end .wrap -->
    +-</div>
    +-
    + <section class="dac-section dac-light" id="build-apps"><div class="wrap">
    +   <h1 class="dac-section-title">Build Beautiful Apps</h1>
    +   <div class="dac-section-subtitle">
    +diff --git a/docs/html-intl/intl/vi/about/versions/nougat/index.jd b/docs/html-intl/intl/vi/about/versions/nougat/index.jd
    +index 58b4b5f..2d57fa6 100644
    +--- a/docs/html-intl/intl/vi/about/versions/nougat/index.jd
    ++++ b/docs/html-intl/intl/vi/about/versions/nougat/index.jd
    +@@ -7,16 +7,6 @@ header.hide=1
    + footer.hide=1
    + @jd:body
    + 
    +-<script>
    +-  $(document).ready(function() {
    +-    if (useUpdatedTemplates) {
    +-      $("#useUpdatedTemplates").css("display","block");
    +-    } else {
    +-      $("#useOldTemplates").css("display","block");
    +-    }
    +-  })
    +-</script>
    +-
    + <section class="dac-expand dac-hero dac-light">
    +   <div class="wrap" style="max-width:1100px;margin-top:0">
    +   <a href="{@docRoot}about/versions/nougat/android-7.0.html">
    +@@ -55,7 +45,7 @@ footer.hide=1
    + </section>
    + 
    + 
    +-<div id="useUpdatedTemplates" style="display:none" class="dac-section dac-slim dac-gray dac-expand">
    ++<div class="dac-section dac-slim dac-gray dac-expand">
    +   <div class="wrap dac-offset-parent">
    +     <a class="dac-fab dac-scroll-button" data-scroll-button href="#latest">
    +       <i class="dac-sprite dac-arrow-down-gray"></i>
    +@@ -77,26 +67,6 @@ footer.hide=1
    +   </div><!-- end .wrap -->
    + </div><!-- end .dac-actions -->
    + 
    +-<div id="useOldTemplates" style="display:none;color:black" class="actions-bar dac-expand dac-invert">
    +-  <div class="wrap dac-offset-parent">
    +-
    +-    <div class="actions">
    +-      <div><a href="https://developer.android.com/preview/bug">
    +-        <span class="dac-sprite dac-auto-chevron-large"></span>
    +-        Báo cáo vấn đề
    +-      </a></div>
    +-      <div><a href="{@docRoot}preview/support.html">
    +-        <span class="dac-sprite dac-auto-chevron-large"></span>
    +-        Xem ghi chú phát hành
    +-      </a></div>
    +-      <div><a href="{@docRoot}preview/dev-community">
    +-        <span class="dac-sprite dac-auto-chevron-large"></span>
    +-        Tham gia cộng đồng nhà phát triển
    +-      </a></div>
    +-    </div><!-- end .actions -->
    +-  </div><!-- end .wrap -->
    +-</div>
    +-
    + <section class="dac-section dac-light dac-small" id="latest"><div class="wrap">
    +   <h2 class="norule">Latest</h2>
    +   <div class="resource-widget resource-flow-layout col-16"
    +diff --git a/docs/html-intl/intl/zh-cn/about/versions/nougat/index.jd b/docs/html-intl/intl/zh-cn/about/versions/nougat/index.jd
    +index c1eb423..5619de8 100644
    +--- a/docs/html-intl/intl/zh-cn/about/versions/nougat/index.jd
    ++++ b/docs/html-intl/intl/zh-cn/about/versions/nougat/index.jd
    +@@ -7,16 +7,6 @@ header.hide=1
    + footer.hide=1
    + @jd:body
    + 
    +-<script>
    +-  $(document).ready(function() {
    +-    if (useUpdatedTemplates) {
    +-      $("#useUpdatedTemplates").css("display","block");
    +-    } else {
    +-      $("#useOldTemplates").css("display","block");
    +-    }
    +-  })
    +-</script>
    +-
    + <section class="dac-expand dac-hero dac-light">
    +   <div class="wrap" style="max-width:1100px;margin-top:0">
    +   <a href="{@docRoot}about/versions/nougat/android-7.0.html">
    +@@ -55,7 +45,7 @@ footer.hide=1
    + </section>
    + 
    + 
    +-<div id="useUpdatedTemplates" style="display:none" class="dac-section dac-slim dac-gray dac-expand">
    ++<div class="dac-section dac-slim dac-gray dac-expand">
    +   <div class="wrap dac-offset-parent">
    +     <a class="dac-fab dac-scroll-button" data-scroll-button href="#latest">
    +       <i class="dac-sprite dac-arrow-down-gray"></i>
    +@@ -77,26 +67,6 @@ footer.hide=1
    +   </div><!-- end .wrap -->
    + </div><!-- end .dac-actions -->
    + 
    +-<div id="useOldTemplates" style="display:none;color:black" class="actions-bar dac-expand dac-invert">
    +-  <div class="wrap dac-offset-parent">
    +-
    +-    <div class="actions">
    +-      <div><a href="https://developer.android.com/preview/bug">
    +-        <span class="dac-sprite dac-auto-chevron-large"></span>
    +-        报告问题
    +-      </a></div>
    +-      <div><a href="{@docRoot}preview/support.html">
    +-        <span class="dac-sprite dac-auto-chevron-large"></span>
    +-        查阅版本说明
    +-      </a></div>
    +-      <div><a href="{@docRoot}preview/dev-community">
    +-        <span class="dac-sprite dac-auto-chevron-large"></span>
    +-        加入开发者社区</a>
    +-</div>
    +-    </div><!-- end .actions -->
    +-  </div><!-- end .wrap -->
    +-</div>
    +-
    + <section class="dac-section dac-light dac-small" id="latest"><div class="wrap">
    +   <h2 class="norule">最新</h2>
    +   <div class="resource-widget resource-flow-layout col-16"
    +diff --git a/docs/html-intl/intl/zh-cn/distribute/tools/promote/badges.jd b/docs/html-intl/intl/zh-cn/distribute/tools/promote/badges.jd
    +index 1c82161..cc1234d 100644
    +--- a/docs/html-intl/intl/zh-cn/distribute/tools/promote/badges.jd
    ++++ b/docs/html-intl/intl/zh-cn/distribute/tools/promote/badges.jd
    +@@ -35,7 +35,7 @@ div.button-row input {
    +   vertical-align: middle;
    +   margin: 0 5px 0 0;
    + }
    +-#jd-content div.button-row img {
    ++#body-content div.button-row img {
    +   margin: 0;
    +   vertical-align: middle;
    + }
    +diff --git a/docs/html-intl/intl/zh-cn/index.jd b/docs/html-intl/intl/zh-cn/index.jd
    +index 8872d16..c1a5d6f 100644
    +--- a/docs/html-intl/intl/zh-cn/index.jd
    ++++ b/docs/html-intl/intl/zh-cn/index.jd
    +@@ -5,16 +5,6 @@ page.customHeadTag=<meta name="google-site-verification" content="sa-bIAI6GKvct3
    + 
    + @jd:body
    + 
    +-<script>
    +-  $(document).ready(function() {
    +-    if (useUpdatedTemplates) {
    +-      $("#useUpdatedTemplates").css("display","block");
    +-    } else {
    +-      $("#useOldTemplates").css("display","block");
    +-    }
    +-  })
    +-</script>
    +-
    + <section class="dac-expand dac-hero" style="background-color:#b2dfdb;">
    +   <div class="wrap" style="max-width:1000px;margin-top:0">
    +     <div class="col-7of16 col-push-8of16">
    +@@ -44,7 +34,7 @@ page.customHeadTag=<meta name="google-site-verification" content="sa-bIAI6GKvct3
    +   </div>
    + </section>
    + 
    +-<div id="useUpdatedTemplates" style="display:none" class="dac-section dac-slim dac-gray dac-expand">
    ++<div class="dac-section dac-slim dac-gray dac-expand">
    +   <div class="wrap dac-offset-parent">
    +     <a class="dac-fab dac-scroll-button" data-scroll-button href="#build-apps">
    +       <i class="dac-sprite dac-arrow-down-gray"></i>
    +@@ -72,28 +62,6 @@ page.customHeadTag=<meta name="google-site-verification" content="sa-bIAI6GKvct3
    +   </div><!-- end .wrap -->
    + </div><!-- end .dac-actions -->
    + 
    +-<div id="useOldTemplates" style="display:none" class="actions-bar dac-expand dac-invert">
    +-  <div class="wrap dac-offset-parent">
    +-    <a class="dac-fab dac-scroll-button" data-scroll-button="" href="#build-apps">
    +-      <i class="dac-sprite dac-arrow-down-gray"></i>
    +-    </a>
    +-    <div class="actions">
    +-      <div><a href="{@docRoot}sdk/index.html">
    +-        <span class="dac-sprite dac-auto-chevron-large"></span>
    +-        Get the SDK
    +-      </a></div>
    +-      <div><a href="{@docRoot}samples/index.html">
    +-        <span class="dac-sprite dac-auto-chevron-large"></span>
    +-        Browse Samples
    +-      </a></div>
    +-      <div><a href="{@docRoot}distribute/stories/index.html">
    +-        <span class="dac-sprite dac-auto-chevron-large"></span>
    +-        Watch Stories
    +-      </a></div>
    +-    </div><!-- end .actions -->
    +-  </div><!-- end .wrap -->
    +-</div>
    +-
    + <section class="dac-section dac-light" id="build-apps"><div class="wrap">
    +   <h1 class="dac-section-title">Build Beautiful Apps</h1>
    +   <div class="dac-section-subtitle">
    +diff --git a/docs/html-intl/intl/zh-tw/about/versions/nougat/index.jd b/docs/html-intl/intl/zh-tw/about/versions/nougat/index.jd
    +index d4db467..ae9e164 100644
    +--- a/docs/html-intl/intl/zh-tw/about/versions/nougat/index.jd
    ++++ b/docs/html-intl/intl/zh-tw/about/versions/nougat/index.jd
    +@@ -7,16 +7,6 @@ header.hide=1
    + footer.hide=1
    + @jd:body
    + 
    +-<script>
    +-  $(document).ready(function() {
    +-    if (useUpdatedTemplates) {
    +-      $("#useUpdatedTemplates").css("display","block");
    +-    } else {
    +-      $("#useOldTemplates").css("display","block");
    +-    }
    +-  })
    +-</script>
    +-
    + <section class="dac-expand dac-hero dac-light">
    +   <div class="wrap" style="max-width:1100px;margin-top:0">
    +   <a href="{@docRoot}about/versions/nougat/android-7.0.html">
    +@@ -55,7 +45,7 @@ footer.hide=1
    + </section>
    + 
    + 
    +-<div id="useUpdatedTemplates" style="display:none" class="dac-section dac-slim dac-gray dac-expand">
    ++<div class="dac-section dac-slim dac-gray dac-expand">
    +   <div class="wrap dac-offset-parent">
    +     <a class="dac-fab dac-scroll-button" data-scroll-button href="#latest">
    +       <i class="dac-sprite dac-arrow-down-gray"></i>
    +@@ -77,26 +67,6 @@ footer.hide=1
    +   </div><!-- end .wrap -->
    + </div><!-- end .dac-actions -->
    + 
    +-<div id="useOldTemplates" style="display:none;color:black" class="actions-bar dac-expand dac-invert">
    +-  <div class="wrap dac-offset-parent">
    +-
    +-    <div class="actions">
    +-      <div><a href="https://developer.android.com/preview/bug">
    +-        <span class="dac-sprite dac-auto-chevron-large"></span>
    +-        回報問題</a>
    +-</div>
    +-      <div><a href="{@docRoot}preview/support.html">
    +-        <span class="dac-sprite dac-auto-chevron-large"></span>
    +-        查看版本資訊</a>
    +-</div>
    +-      <div><a href="{@docRoot}preview/dev-community">
    +-        <span class="dac-sprite dac-auto-chevron-large"></span>
    +-        加入開發人員社群</a>
    +-</div>
    +-    </div><!-- end .actions -->
    +-  </div><!-- end .wrap -->
    +-</div>
    +-
    + <section class="dac-section dac-light dac-small" id="latest"><div class="wrap">
    +   <h2 class="norule">Latest</h2>
    +   <div class="resource-widget resource-flow-layout col-16"
    +diff --git a/docs/html-intl/intl/zh-tw/guide/components/intents-filters.jd b/docs/html-intl/intl/zh-tw/guide/components/intents-filters.jd
    +index d3edac3..7e61f5e 100644
    +--- a/docs/html-intl/intl/zh-tw/guide/components/intents-filters.jd
    ++++ b/docs/html-intl/intl/zh-tw/guide/components/intents-filters.jd
    +@@ -76,7 +76,7 @@ android.content.Context#bindService bindService()} 來繫結至另一個元件
    + <li><b>如何傳送廣播:</b>
    + <p>廣播是指任何應用程式都可接收的訊息。系統會傳送各種系統事件廣播,例如系統開機或裝置開始充電。
    + 您可以將 {@link android.content.Intent} 傳送至 {@link android.content.Context#sendBroadcast(Intent) sendBroadcast()}、
    +-{@link android.content.Context#sendOrderedBroadcast(Intent, String) 或{@link
    ++{@link android.content.Context#sendOrderedBroadcast(Intent, String)} 或{@link
    + android.content.Context#sendStickyBroadcast sendStickyBroadcast()},以向其他應用程式傳送廣播。
    + 
    + 
    +diff --git a/docs/html-intl/intl/zh-tw/index.jd b/docs/html-intl/intl/zh-tw/index.jd
    +index 540801a..022df77 100644
    +--- a/docs/html-intl/intl/zh-tw/index.jd
    ++++ b/docs/html-intl/intl/zh-tw/index.jd
    +@@ -5,16 +5,6 @@ page.customHeadTag=<meta name="google-site-verification" content="sa-bIAI6GKvct3
    + 
    + @jd:body
    + 
    +-<script>
    +-  $(document).ready(function() {
    +-    if (useUpdatedTemplates) {
    +-      $("#useUpdatedTemplates").css("display","block");
    +-    } else {
    +-      $("#useOldTemplates").css("display","block");
    +-    }
    +-  })
    +-</script>
    +-
    + <section class="dac-expand dac-hero" style="background-color:#b2dfdb;">
    +   <div class="wrap" style="max-width:1000px;margin-top:0">
    +     <div class="col-7of16 col-push-8of16">
    +@@ -44,7 +34,7 @@ page.customHeadTag=<meta name="google-site-verification" content="sa-bIAI6GKvct3
    +   </div>
    + </section>
    + 
    +-<div id="useUpdatedTemplates" style="display:none" class="dac-section dac-slim dac-gray dac-expand">
    ++<div class="dac-section dac-slim dac-gray dac-expand">
    +   <div class="wrap dac-offset-parent">
    +     <a class="dac-fab dac-scroll-button" data-scroll-button href="#build-apps">
    +       <i class="dac-sprite dac-arrow-down-gray"></i>
    +@@ -72,28 +62,6 @@ page.customHeadTag=<meta name="google-site-verification" content="sa-bIAI6GKvct3
    +   </div><!-- end .wrap -->
    + </div><!-- end .dac-actions -->
    + 
    +-<div id="useOldTemplates" style="display:none" class="actions-bar dac-expand dac-invert">
    +-  <div class="wrap dac-offset-parent">
    +-    <a class="dac-fab dac-scroll-button" data-scroll-button="" href="#build-apps">
    +-      <i class="dac-sprite dac-arrow-down-gray"></i>
    +-    </a>
    +-    <div class="actions">
    +-      <div><a href="{@docRoot}sdk/index.html">
    +-        <span class="dac-sprite dac-auto-chevron-large"></span>
    +-        Get the SDK
    +-      </a></div>
    +-      <div><a href="{@docRoot}samples/index.html">
    +-        <span class="dac-sprite dac-auto-chevron-large"></span>
    +-        Browse Samples
    +-      </a></div>
    +-      <div><a href="{@docRoot}distribute/stories/index.html">
    +-        <span class="dac-sprite dac-auto-chevron-large"></span>
    +-        Watch Stories
    +-      </a></div>
    +-    </div><!-- end .actions -->
    +-  </div><!-- end .wrap -->
    +-</div>
    +-
    + <section class="dac-section dac-light" id="build-apps"><div class="wrap">
    +   <h1 class="dac-section-title">Build Beautiful Apps</h1>
    +   <div class="dac-section-subtitle">
    +diff --git a/docs/html/_redirects.yaml b/docs/html/_redirects.yaml
    +index 1557dce..7daf85c 100644
    +--- a/docs/html/_redirects.yaml
    ++++ b/docs/html/_redirects.yaml
    +@@ -1,6 +1,8 @@
    + # For information about this file's format, see
    + # https://developers.google.com/internal/publishing/redirects
    + redirects:
    ++- from: /guide/topics/fundamentals/fragments.html
    ++  to: /guide/components/fragments.html
    + - from: /about/versions/index.html
    +   to: /about/index.html
    + - from: /about/versions/api-levels.html
    +@@ -41,8 +43,8 @@ redirects:
    +   to: /studio/intro/update.html
    + - from: /sdk/ndk/overview.html
    +   to: /ndk/index.html
    +-- from: /sdk/ndk/
    +-  to: /ndk/
    ++- from: /sdk/ndk/...
    ++  to: /ndk/...
    + - from: /go/vulkan
    +   to: /ndk/guides/graphics/index.html
    + - from: /tools/sdk/win-usb.html
    +@@ -101,18 +103,18 @@ redirects:
    +   to: /training/testing/unit-testing/index.html
    + - from: /training/activity-testing/activity-functional-testing.html
    +   to: /training/testing/ui-testing/index.html
    +-- from: /guide/market/
    +-  to: /google/play/
    ++- from: /guide/market/...
    ++  to: /google/play/...
    + - from: /guide/google/play/services.html
    +   to: https://developers.google.com/android/guides/overview
    +-- from: /guide/google/
    +-  to: /google/
    +-- from: /training/id-auth/...
    ++- from: /guide/google/...
    ++  to: /google/...
    ++- from: /training/id-auth/
    +   to: /google/auth/http-auth.html
    + - from: /google/play-services/auth.html
    +   to: https://developers.google.com/android/guides/http-auth
    + - from: /google/play-services/games.html
    +-  to: https://developers.google.com/games/services/
    ++  to: https://developers.google.com/games/services
    + - from: /google/play-services/location.html
    +   to: /training/location/index.html
    + - from: /google/play-services/plus.html
    +@@ -120,21 +122,21 @@ redirects:
    + - from: /google/play-services/maps.html
    +   to: /training/maps/index.html
    + - from: /google/play-services/drive.html
    +-  to: https://developers.google.com/drive/android/
    ++  to: https://developers.google.com/drive/android
    + - from: /google/play-services/cast.html
    +-  to: https://developers.google.com/cast/
    ++  to: https://developers.google.com/cast
    + - from: /google/play-services/ads.html
    +-  to: https://developers.google.com/mobile-ads-sdk/
    ++  to: https://developers.google.com/mobile-ads-sdk
    + - from: /google/play-services/wallet.html
    +-  to: https://developers.google.com/wallet/instant-buy/
    ++  to: https://developers.google.com/wallet/instant-buy
    + - from: /google/play-services/id.html
    +   to: https://developers.google.com/android/reference/com/google/android/gms/ads/identifier/AdvertisingIdClient
    + - from: /google/play/safetynet/...
    +   to: /training/safetynet/index.html
    + - from: /google/gcm/...
    +-  to: https://developers.google.com/cloud-messaging/
    ++  to: https://developers.google.com/cloud-messaging/...
    + - from: /google/gcs/...
    +-  to: https://developers.google.com/datastore/
    ++  to: https://developers.google.com/datastore/...
    + - from: /google/play-services/safetynet.html
    +   to: /training/safetynet/index.html
    + - from: /google/play/billing/v2/api.html
    +@@ -158,29 +160,29 @@ redirects:
    + - from: /guide/developing/tools/aidl.html
    +   to: /guide/components/aidl.html
    + - from: /guide/developing/tools/...
    +-  to: /studio/command-line/
    ++  to: /studio/command-line/...
    + - from: /guide/developing/...
    +-  to: /studio/
    ++  to: /studio/...
    + - from: /tools/aidl.html
    +   to: /guide/components/aidl.html
    + - from: /guide/market/publishing/multiple-apks.html
    +   to: /google/play/publishing/multiple-apks.html
    + - from: /guide/publishing/publishing.html
    +   to: /distribute/tools/launch-checklist.html
    +-- from: /guide/publishing/
    ++- from: /guide/publishing/...
    +   to: /studio/publish/index.html
    + - from: /guide/topics/fundamentals.html
    +   to: /guide/components/fundamentals.html
    + - from: /guide/topics/intents/intents-filters.html
    +   to: /guide/components/intents-filters.html
    +-- from: /guide/topics/fundamentals/
    +-  to: /guide/components/
    ++- from: /guide/topics/fundamentals/...
    ++  to: /guide/components/...
    + - from: /guide/topics/clipboard/copy-paste.html
    +   to: /guide/topics/text/copy-paste.html
    + - from: /guide/topics/ui/notifiers/index.html
    +   to: /guide/topics/ui/notifiers/notifications.html
    +-- from: /guide/topics/wireless/
    +-  to: /guide/topics/connectivity/
    ++- from: /guide/topics/wireless/...
    ++  to: /guide/topics/connectivity/...
    + - from: /guide/topics/drawing/...
    +   to: /guide/topics/graphics/opengl.html
    + - from: /guide/topics/connectivity/usb/adk.html
    +@@ -217,8 +219,8 @@ redirects:
    +   to: /training/articles/security-tips.html
    + - from: /guide/appendix/market-filters.html
    +   to: /google/play/filters.html
    +-- from: /guide/topics/testing/
    +-  to: /studio/test/
    ++- from: /guide/topics/testing/...
    ++  to: /studio/test/...
    + - from: /guide/topics/graphics/animation.html
    +   to: /guide/topics/graphics/overview.html
    + - from: /guide/topics/graphics/renderscript/compute.html
    +@@ -235,24 +237,24 @@ redirects:
    +   to: /guide/topics/renderscript/reference/overview.html
    + - from: /guide/topics/location/obtaining-user-location.html
    +   to: /guide/topics/location/strategies.html
    +-- from: /guide/topics/nfc/
    +-  to: /guide/topics/connectivity/nfc/
    +-- from: /guide/topics/wireless/
    +-  to: /guide/topics/connectivity/
    +-- from: /guide/topics/network/
    +-  to: /guide/topics/connectivity/
    ++- from: /guide/topics/nfc/...
    ++  to: /guide/topics/connectivity/nfc/...
    ++- from: /guide/topics/wireless/...
    ++  to: /guide/topics/connectivity/...
    ++- from: /guide/topics/network/...
    ++  to: /guide/topics/connectivity/...
    + - from: /resources/articles/creating-input-method.html
    +   to: /guide/topics/text/creating-input-method.html
    + - from: /resources/articles/spell-checker-framework.html
    +   to: /guide/topics/text/spell-checker-framework.html
    +-- from: /resources/tutorials/notepad/
    ++- from: /resources/tutorials/notepad/...
    +   to: https://developer.android.com/training/basics/firstapp/index.html
    +-- from: /resources/faq/
    +-  to: /guide/faq/
    ++- from: /resources/faq/...
    ++  to: /guide/faq/...
    + - from: /resources/tutorials/hello-world.html
    +   to: /training/basics/firstapp/index.html
    +-- from: /guide/practices/design/
    +-  to: /guide/practices/
    ++- from: /guide/practices/design/...
    ++  to: /guide/practices/...
    + - from: /guide/practices/accessibility.html
    +   to: /guide/topics/ui/accessibility/index.html
    + - from: /guide/practices/app-design/performance.html
    +@@ -287,6 +289,8 @@ redirects:
    +   to: /design/patterns/app-structure.html
    + - from: /guide/practices/ui_guidelines/menu_design.html
    +   to: /design/patterns/actionbar.html
    ++- from: /design/patterns/accessibility.html
    ++  to: https://material.google.com/usability/accessibility.html
    + - from: /design/get-started/ui-overview.html
    +   to: /design/handhelds/index.html
    + - from: /design/building-blocks/buttons.html
    +@@ -361,8 +365,8 @@ redirects:
    +   to: /training/wearables/notifications/pages.html
    + - from: /wear/notifications/stacks.html
    +   to: /training/wearables/notifications/stacks.html
    +-- from: /reference/android/preview/support/
    +-  to: /reference/android/support/
    ++- from: /reference/android/preview/support/...
    ++  to: /reference/android/support/...
    + - from: /wear/license.html
    +   to: /wear/index.html
    + - from: /resources/dashboard/...
    +@@ -371,8 +375,8 @@ redirects:
    +   to: /support.html
    + - from: /community/index.html
    +   to: /support.html
    +-- from: /guide/tutorials/
    +-  to: /resources/tutorials/
    ++- from: /guide/tutorials/...
    ++  to: /resources/tutorials/...
    + - from: /resources/tutorials/views/hello-linearlayout.html
    +   to: /guide/topics/ui/layout/linear.html
    + - from: /resources/tutorials/views/hello-relativelayout.html
    +@@ -412,11 +416,9 @@ redirects:
    + - from: /resources/samples/...
    +   to: /samples/index.html
    + - from: /resources/...
    +-  to: /training/
    ++  to: /training/...
    + - from: /tools/samples/index.html
    +   to: /samples/index.html
    +-- from: /guide/publishing/publishing.html\#BuildaButton
    +-  to: https://play.google.com/intl/en_us/badges/
    + - from: /distribute/essentials/best-practices/games.html
    +   to: /distribute/googleplay/guide.html
    + - from: /distribute/essentials/best-practices/apps.html
    +@@ -430,13 +432,19 @@ redirects:
    + - from: /training/cloudsync/aesync.html
    +   to: /google/gcm/index.html
    + - from: /training/cloudsync/index.html
    +-  to: /training/backup/index.html
    +-- from: /training/basics/location/
    +-  to: /training/location/
    ++  to: /guide/topics/data/backup.html
    ++- from: /training/backup/index.html
    ++  to: /guide/topics/data/backup.html
    ++- from: /training/backup/autosyncapi.html
    ++  to: /guide/topics/data/autobackup.html
    ++- from: /training/backup/backupapi.html
    ++  to: /guide/topics/data/keyvaluebackup.html
    ++- from: /training/basics/location/...
    ++  to: /training/location/...
    + - from: /training/monetization/index.html
    +   to: /distribute/monetize/index.html
    + - from: /training/monetization/ads-and-ux.html
    +-  to: https://developers.google.com/mobile-ads-sdk/
    ++  to: https://developers.google.com/mobile-ads-sdk/index.html
    + - from: /training/notepad/...
    +   to: https://developer.android.com/training/basics/firstapp/index.html
    + - from: /training/basics/actionbar/setting-up.html
    +@@ -447,8 +455,8 @@ redirects:
    +   to: /training/appbar/index.html
    + - from: /distribute/open.html
    +   to: /distribute/tools/open-distribution.html
    +-- from: /distribute/googleplay/promote/
    +-  to: /distribute/tools/promote/
    ++- from: /distribute/googleplay/promote/...
    ++  to: /distribute/tools/promote/...
    + - from: /distribute/googleplay/publish/preparing.html
    +   to: /distribute/tools/launch-checklist.html
    + - from: /distribute/googleplay/publish/index.html
    +@@ -477,8 +485,8 @@ redirects:
    +   to: /distribute/monetize/index.html
    + - from: /distribute/googleplay/about/distribution.html
    +   to: /distribute/googleplay/developer-console.html
    +-- from: /distribute/googleplay/spotlight/
    +-  to: /distribute/stories/
    ++- from: /distribute/googleplay/spotlight/...
    ++  to: /distribute/stories/...
    + - from: /distribute/stories/localization.html
    +   to: /distribute/stories/index.html
    + - from: /distribute/stories/tablets.html
    +@@ -540,11 +548,11 @@ redirects:
    + - from: /videos/index.html
    +   to: /develop/index.html
    + - from: /live/index.html
    +-  to: https://developers.google.com/live/
    +-- from: /intl/zh-CN/
    +-  to: /intl/zh-cn/
    +-- from: /intl/zh-TW/
    +-  to: /intl/zh-tw/
    ++  to: https://developers.google.com/live/index.html
    ++- from: /intl/zh-CN/...
    ++  to: /intl/zh-cn/...
    ++- from: /intl/zh-TW/...
    ++  to: /intl/zh-tw/...
    + - from: /4.2
    +   to: /about/versions/android-4.2.html
    + - from: /4.1
    +@@ -553,111 +561,111 @@ redirects:
    +   to: /about/versions/android-4.0.html
    + - from: /5
    +   to: /about/versions/android-5.0.html
    +-- from: /5/
    ++- from: /5/...
    +   to: /about/versions/android-5.0.html
    + 
    + - from: /m
    +   to: /about/versions/marshmallow/index.html
    +-- from: /m/
    ++- from: /m/...
    +   to: /about/versions/marshmallow/index.html
    + - from: /mm
    +   to: /about/versions/marshmallow/index.html
    +-- from: /mm/
    ++- from: /mm/...
    +   to: /about/versions/marshmallow/index.html
    + - from: /marshmallow
    +   to: /about/versions/marshmallow/index.html
    +-- from: /marshmallow/
    ++- from: /marshmallow/...
    +   to: /about/versions/marshmallow/index.html
    + 
    + - from: /l
    +   to: /about/versions/lollipop.html
    +-- from: /l/
    ++- from: /l/...
    +   to: /about/versions/lollipop.html
    + - from: /ll
    +   to: /about/versions/lollipop.html
    +-- from: /ll/
    ++- from: /ll/...
    +   to: /about/versions/lollipop.html
    + - from: /lp
    +   to: /about/versions/lollipop.html
    +-- from: /lp/
    ++- from: /lp/...
    +   to: /about/versions/lollipop.html
    + - from: /lollipop
    +   to: /about/versions/lollipop.html
    +-- from: /lollipop/
    ++- from: /lollipop/...
    +   to: /about/versions/lollipop.html
    + 
    + - from: /k
    +   to: /about/versions/kitkat.html
    +-- from: /k/
    ++- from: /k/...
    +   to: /about/versions/kitkat.html
    + - from: /kk
    +   to: /about/versions/kitkat.html
    +-- from: /kk/
    ++- from: /kk/...
    +   to: /about/versions/kitkat.html
    + - from: /kitkat
    +   to: /about/versions/kitkat.html
    +-- from: /kitkat/
    ++- from: /kitkat/...
    +   to: /about/versions/kitkat.html
    + 
    + - from: /j
    +   to: /about/versions/jelly-bean.html
    +-- from: /j/
    ++- from: /j/...
    +   to: /about/versions/jelly-bean.html
    + - from: /jj
    +   to: /about/versions/jelly-bean.html
    +-- from: /jj/
    ++- from: /jj/...
    +   to: /about/versions/jelly-bean.html
    + - from: /jellybean
    +   to: /about/versions/jelly-bean.html
    +-- from: /jellybean/
    ++- from: /jellybean/...
    +   to: /about/versions/jelly-bean.html
    + 
    + - from: /i
    +   to: /about/versions/android-4.0-highlights.html
    +-- from: /i/
    ++- from: /i/...
    +   to: /about/versions/android-4.0-highlights.html
    + - from: /ics
    +   to: /about/versions/android-4.0-highlights.html
    +-- from: /ics/
    ++- from: /ics/...
    +   to: /about/versions/android-4.0-highlights.html
    + - from: /icecreamsandwich
    +   to: /about/versions/android-4.0-highlights.html
    +-- from: /icecreamsandwich/
    ++- from: /icecreamsandwich/...
    +   to: /about/versions/android-4.0-highlights.html
    + 
    + - from: /%2B
    +   to: https://plus.google.com/108967384991768947849/posts
    +-- from: /%2B/
    ++- from: /%2B/...
    +   to: https://plus.google.com/108967384991768947849/posts
    + - from: /blog
    +-  to: https://android-developers.blogspot.com/
    ++  to: https://android-developers.blogspot.com
    + - from: /stats
    +   to: /about/dashboards/index.html
    + - from: /youtube
    +   to: https://www.youtube.com/user/androiddevelopers
    + - from: /playbadge
    +-  to: https://play.google.com/intl/en_us/badges/
    +-- from: /playbadge/
    +-  to: https://play.google.com/intl/en_us/badges/
    ++  to: https://play.google.com/intl/en_us/badges
    ++- from: /playbadge/...
    ++  to: https://play.google.com/intl/en_us/badges/...
    + - from: /distribute/tools/promote/badges.html
    +-  to: https://play.google.com/intl/en_us/badges/
    ++  to: https://play.google.com/intl/en_us/badges
    + - from: /deviceart
    +   to: /distribute/tools/promote/device-art.html
    +-- from: /deviceart/
    ++- from: /deviceart/...
    +   to: /distribute/tools/promote/device-art.html
    + - from: /distribute/promote/device-art.html
    +   to: /distribute/tools/promote/device-art.html
    + - from: /edu/signup
    +   to: https://services.google.com/fb/forms/playedu
    +-- from: /edu/signup/
    ++- from: /edu/signup/...
    +   to: https://services.google.com/fb/forms/playedu
    + - from: /edu
    +   to: /distribute/googleplay/edu/about.html
    +-- from: /edu/
    ++- from: /edu/...
    +   to: /distribute/googleplay/edu/about.html
    + - from: /families
    +   to: /distribute/googleplay/families/about.html
    +-- from: /families/
    ++- from: /families/...
    +   to: /distribute/googleplay/families/about.html
    + - from: /preview/google-play-services-wear.html
    +   to: /training/building-wearables.html
    +@@ -713,9 +721,9 @@ redirects:
    +   to: /training/material/animations.html
    + - from: /preview/material/compatibility.html
    +   to: /training/material/compatibility.html
    +-- from: /preview/material/
    ++- from: /preview/material/...
    +   to: /design/material/index.html
    +-- from: /auto/overview/
    ++- from: /auto/overview/...
    +   to: /training/auto/start/index.html
    + - from: /training/location/activity-recognition.html
    +   to: /training/location/index.html
    +@@ -738,9 +746,9 @@ redirects:
    + - from: /training/enterprise/work-policy-ctrl.html
    +   to: https://developers.google.com/android/work/build-dpc
    + - from: /distribute/tools/promote/badge-files.html
    +-  to: https://play.google.com/intl/en_us/badges/
    ++  to: https://play.google.com/intl/en_us/badges
    + - from: /google/gcm/...
    +-  to: https://developers.google.com/cloud-messaging/
    ++  to: https://developers.google.com/cloud-messaging
    + - from: /training/cloudsync/gcm.html
    +   to: /training/cloudsync/index.html
    + 
    +@@ -796,29 +804,32 @@ redirects:
    + - from: /preview/features/app-linking.html
    +   to: /training/app-links/index.html
    + - from: /preview/backup/index.html
    +-  to: /training/backup/autosyncapi.html
    ++  to: /guide/topics/data/backup/autobackup.html
    + - from: /preview/features/power-mgmt.html
    +   to: /training/monitoring-device-state/doze-standby.html
    + - from: /preview/dev-community
    +-  to: https://plus.google.com/communities/103655397235276743411
    ++  to: https://plus.google.com/communities/105153134372062985968
    + - from: /preview/bug
    +   to: https://source.android.com/source/report-bugs.html
    +-- from: /preview/bug/
    ++- from: /preview/bug/...
    +   to: https://source.android.com/source/report-bugs.html
    + - from: /preview/bugreport
    +   to: https://source.android.com/source/report-bugs.html
    +-- from: /preview/bugreport/
    ++- from: /preview/bugreport/...
    +   to: https://source.android.com/source/report-bugs.html
    + - from: /preview/bugs
    +   to: https://code.google.com/p/android/issues/list?can=2&q=label%3ADevPreview-N
    +-- from: /preview/bugs/
    ++- from: /preview/bugs/...
    +   to: https://code.google.com/p/android/issues/list?can=2&q=label%3ADevPreview-N
    + - from: /preview/bugreports
    +   to: https://code.google.com/p/android/issues/list?can=2&q=label%3ADevPreview-N
    +-- from: /preview/bugreports/
    ++- from: /preview/bugreports/...
    +   to: https://code.google.com/p/android/issues/list?can=2&q=label%3ADevPreview-N
    ++- from: /preview/setup-sdk.html
    ++  to: /studio/index.html
    + - from: /2016/03/first-preview-of-android-n-developer.html
    +   to: http://android-developers.blogspot.com/2016/03/first-preview-of-android-n-developer.html
    ++
    + - from: /reference/org/apache/http/...
    +   to: /about/versions/marshmallow/android-6.0-changes.html#behavior-apache-http-client
    + - from: /shareables/...
    +@@ -839,6 +850,10 @@ redirects:
    +   to: /topic/performance/power/network/gather-data.html
    + - from: /training/performance/battery/network/index.html
    +   to: /topic/performance/power/network/index.html
    ++- from: /training/articles/memory.html
    ++  to: /topic/performance/memory.html
    ++- from: /topic/performance/optimizing-view-hierarchies.html
    ++  to: /topic/performance/rendering/optimizing-view-hierarchies.html
    + 
    + # Redirects for the new [dac]/topic/libraries/ area
    + 
    +@@ -1153,92 +1168,132 @@ redirects:
    + # Vanity urls
    + - from: /background_optimizations
    +   to: /preview/features/background-optimization.html
    +-- from: /background_optimizations/
    ++- from: /background_optimizations/...
    +   to: /preview/features/background-optimization.html
    + - from: /bgopt
    +   to: /preview/features/background-optimization.html
    +-- from: /bgopt/
    ++- from: /bgopt/...
    +   to: /preview/features/background-optimization.html
    + 
    + 
    + 
    + # Android Studio help button redirects
    + - from: /r/studio-ui/vector-asset-studio.html
    +-  to: /studio/write/vector-asset-studio.html?utm_medium=android-studio
    ++  to: /studio/write/vector-asset-studio.html?utm_source=android-studio
    + - from: /r/studio-ui/image-asset-studio.html
    +-  to: /studio/write/image-asset-studio.html?utm_medium=android-studio
    ++  to: /studio/write/image-asset-studio.html?utm_source=android-studio
    + - from: /r/studio-ui/project-structure.html
    +-  to: /studio/projects/index.html?utm_medium=android-studio
    ++  to: /studio/projects/index.html?utm_source=android-studio
    + - from: /r/studio-ui/android-monitor.html
    +-  to: /studio/profile/android-monitor.html?utm_medium=android-studio
    ++  to: /studio/profile/android-monitor.html?utm_source=android-studio
    + - from: /r/studio-ui/am-logcat.html
    +-  to: /studio/debug/am-logcat.html?utm_medium=android-studio
    ++  to: /studio/debug/am-logcat.html?utm_source=android-studio
    + - from: /r/studio-ui/am-memory.html
    +-  to: /studio/profile/am-memory.html?utm_medium=android-studio
    ++  to: /studio/profile/am-memory.html?utm_source=android-studio
    + - from: /r/studio-ui/am-cpu.html
    +-  to: /studio/profile/am-cpu.html?utm_medium=android-studio
    ++  to: /studio/profile/am-cpu.html?utm_source=android-studio
    + - from: /r/studio-ui/am-gpu.html
    +-  to: /studio/profile/am-gpu.html?utm_medium=android-studio
    ++  to: /studio/profile/am-gpu.html?utm_source=android-studio
    + - from: /r/studio-ui/am-network.html
    +-  to: /studio/profile/am-network.html?utm_medium=android-studio
    ++  to: /studio/profile/am-network.html?utm_source=android-studio
    + - from: /r/studio-ui/am-hprof.html
    +-  to: /studio/profile/am-hprof.html?utm_medium=android-studio
    ++  to: /studio/profile/am-hprof.html?utm_source=android-studio
    + - from: /r/studio-ui/am-allocation.html
    +-  to: /studio/profile/am-allocation.html?utm_medium=android-studio
    ++  to: /studio/profile/am-allocation.html?utm_source=android-studio
    + - from: /r/studio-ui/am-methodtrace.html
    +-  to: /studio/profile/am-methodtrace.html?utm_medium=android-studio
    ++  to: /studio/profile/am-methodtrace.html?utm_source=android-studio
    + - from: /r/studio-ui/am-sysinfo.html
    +-  to: /studio/profile/am-sysinfo.html?utm_medium=android-studio
    ++  to: /studio/profile/am-sysinfo.html?utm_source=android-studio
    + - from: /r/studio-ui/am-screenshot.html
    +-  to: /studio/debug/am-screenshot.html?utm_medium=android-studio
    ++  to: /studio/debug/am-screenshot.html?utm_source=android-studio
    + - from: /r/studio-ui/am-video.html
    +-  to: /studio/debug/am-video.html?utm_medium=android-studio
    ++  to: /studio/debug/am-video.html?utm_source=android-studio
    + - from: /r/studio-ui/avd-manager.html
    +-  to: /studio/run/managing-avds.html?utm_medium=android-studio
    ++  to: /studio/run/managing-avds.html?utm_source=android-studio
    + - from: /r/studio-ui/rundebugconfig.html
    +-  to: /studio/run/rundebugconfig.html?utm_medium=android-studio
    ++  to: /studio/run/rundebugconfig.html?utm_source=android-studio
    + - from: /r/studio-ui/devicechooser.html
    +-  to: /studio/run/emulator.html?utm_medium=android-studio
    ++  to: /studio/run/emulator.html?utm_source=android-studio
    + - from: /r/studio-ui/virtualdeviceconfig.html
    +-  to: /studio/run/managing-avds.html?utm_medium=android-studio
    ++  to: /studio/run/managing-avds.html?utm_source=android-studio
    + - from: /r/studio-ui/emulator.html
    +-  to: /studio/run/emulator.html?utm_medium=android-studio
    ++  to: /studio/run/emulator.html?utm_source=android-studio
    + - from: /r/studio-ui/instant-run.html
    +-  to: /studio/run/index.html?utm_medium=android-studio#instant-run
    ++  to: /studio/run/index.html?utm_source=android-studio#instant-run
    + - from: /r/studio-ui/test-recorder.html
    +-  to: http://tools.android.com/tech-docs/test-recorder
    ++  to: /studio/test/espresso-test-recorder.html?utm_source=android-studio
    + - from: /r/studio-ui/export-licenses.html
    +   to: http://tools.android.com/tech-docs/new-build-system/license
    + - from: /r/studio-ui/experimental-to-stable-gradle.html
    +   to: http://tools.android.com/tech-docs/new-build-system/gradle-experimental/experimental-to-stable-gradle
    + - from: /r/studio-ui/sdk-manager.html
    +-  to: /studio/intro/update.html?utm_medium=android-studio#sdk-manager
    ++  to: /studio/intro/update.html?utm_source=android-studio#sdk-manager
    + - from: /r/studio-ui/newjclass.html
    +-  to: /studio/write/create-java-class.html?utm_medium=android-studio
    ++  to: /studio/write/create-java-class.html?utm_source=android-studio
    + - from: /r/studio-ui/menu-help.html
    +-  to: /studio/intro/index.html?utm_medium=android-studio
    ++  to: /studio/intro/index.html?utm_source=android-studio
    + - from: /r/studio-ui/menu-start.html
    +-  to: /training/index.html?utm_medium=android-studio
    ++  to: /training/index.html?utm_source=android-studio
    + - from: /r/studio-ui/run-with-work-profile.html
    +-  to: /studio/run/index.html#ir-work-profile?utm_medium=android-studio
    ++  to: /studio/run/index.html?utm_source=android-studio#ir-work-profile
    + - from: /r/studio-ui/am-gpu-debugger.html
    +-  to: /studio/profile/am-gpu.html?utm_medium=android-studio
    ++  to: /studio/debug/am-gpu-debugger.html?utm_source=android-studio
    + - from: /r/studio-ui/theme-editor.html
    +-  to: /studio/write/theme-editor.html?utm_medium=android-studio
    ++  to: /studio/write/theme-editor.html?utm_source=android-studio
    + - from: /r/studio-ui/translations-editor.html
    +-  to: /studio/write/translations-editor.html?utm_medium=android-studio
    ++  to: /studio/write/translations-editor.html?utm_source=android-studio
    + - from: /r/studio-ui/debug.html
    +-  to: /studio/debug/index.html?utm_medium=android-studio
    ++  to: /studio/debug/index.html?utm_source=android-studio
    + - from: /r/studio-ui/run.html
    +-  to: /studio/run/index.html?utm_medium=android-studio
    ++  to: /studio/run/index.html?utm_source=android-studio
    + - from: /r/studio-ui/layout-editor.html
    +-  to: /studio/write/layout-editor.html?utm_medium=android-studio
    ++  to: /studio/write/layout-editor.html?utm_source=android-studio
    + - from: /r/studio-ui/project-window.html
    +-  to: /studio/projects/index.html?utm_medium=android-studio
    ++  to: /studio/projects/index.html?utm_source=android-studio
    + - from: /r/studio-ui/lint-inspection-results.html
    +-  to: /studio/write/lint.html?utm_medium=android-studio
    ++  to: /studio/write/lint.html?utm_source=android-studio
    + - from: /r/studio-ui/gradle-console.html
    +-  to: /studio/run/index.html#gradle-console?utm_medium=android-studio
    ++  to: /studio/run/index.html?utm_source=android-studio#gradle-console
    ++- from: /r/studio-ui/app-indexing-test.html
    ++  to: /studio/write/app-link-indexing.html#appindexingtest?utm_source=android-studio
    ++- from: /r/studio-ui/vcs.html
    ++  to: /studio/intro/index.html#version_control_basics?utm_source=android-studio
    ++- from: /r/studio-ui/create-new-module.html
    ++  to: /studio/projects/index.html#ApplicationModules?utm_source=android-studio
    ++- from: /r/studio-ui/build-variants.html
    ++  to: /studio/run/index.html#changing-variant?utm_source=android-studio
    ++- from: /r/studio-ui/generate-signed-apk.html
    ++  to: /studio/publish/app-signing.html#release-mode?utm_source=android-studio
    ++- from: /r/studio-ui/import-project-vcs.html
    ++  to: /studio/projects/create-project.html#ImportAProject?utm_source=android-studio
    ++- from: /r/studio-ui/apk-analyzer.html
    ++  to: /studio/build/apk-analyzer.html?utm_source=android-studio
    ++- from: /r/studio-ui/breakpoints.html
    ++  to: /studio/debug/index.html#breakPointsView?utm_source=android-studio
    ++- from: /r/studio-ui/attach-debugger-to-process.html
    ++  to: /studio/debug/index.html?utm_source=android-studio
    ++- from: /r/studio-ui/import-sample.html
    ++  to: /samples/index.html?utm_source=android-studio
    ++- from: /r/studio-ui/import-module.html
    ++  to: /studio/projects/add-app-module.html#ImportAModule?utm_source=android-studio
    ++- from: /r/studio-ui/import-project.html
    ++  to: /studio/projects/create-project.html#ImportAProject?utm_source=android-studio
    ++- from: /r/studio-ui/create-project.html
    ++  to: /studio/projects/create-project.html?utm_source=android-studio
    ++- from: /r/studio-ui/new-activity.html
    ++  to: /studio/projects/template.html?utm_source=android-studio
    ++- from: /r/studio-ui/new-resource-file.html
    ++  to: /studio/write/add-resources.html?utm_source=android-studio
    ++- from: /r/studio-ui/new-resource-dir.html
    ++  to: /studio/write/add-resources.html#add_a_resource_directory?utm_source=android-studio
    ++- from: /r/studio-ui/configure-component.html
    ++  to: /studio/write/add-resources.html?utm_source=android-studio
    ++- from: /r/studio-ui/ninepatch.html
    ++  to: /studio/write/draw9patch.html?utm_source=android-studio
    ++- from: /r/studio-ui/firebase-assistant.html
    ++  to: /studio/write/firebase.html?utm_source=android-studio
    ++- from: /r/studio-ui/ir-flight-recorder.html
    ++  to: /studio/run/index.html?utm_source=android-studio#submit-feedback
    + 
    + # Redirects from (removed) N Preview documentation
    + - from: /preview/features/afw.html
    +@@ -1281,4 +1336,3 @@ redirects:
    +   to: /topic/performance/background-optimization.html
    + - from: /preview/features/data-saver.html
    +   to: /training/basics/network-ops/data-saver.html
    +-
    +diff --git a/docs/html/about/dashboards/index.jd b/docs/html/about/dashboards/index.jd
    +index f5d23e8..2721c85 100644
    +--- a/docs/html/about/dashboards/index.jd
    ++++ b/docs/html/about/dashboards/index.jd
    +@@ -59,7 +59,7 @@ Platform Versions</a>.</p>
    + </div>
    + 
    + 
    +-<p style="clear:both"><em>Data collected during a 7-day period ending on August 1, 2016.
    ++<p style="clear:both"><em>Data collected during a 7-day period ending on September 5, 2016.
    + <br/>Any versions with less than 0.1% distribution are not shown.</em>
    + </p>
    + 
    +@@ -81,7 +81,7 @@ Screens</a>.</p>
    + </div>
    + 
    + 
    +-<p style="clear:both"><em>Data collected during a 7-day period ending on August 1, 2016.
    ++<p style="clear:both"><em>Data collected during a 7-day period ending on September 5, 2016.
    + 
    + <br/>Any screen configurations with less than 0.1% distribution are not shown.</em></p>
    + 
    +@@ -101,7 +101,7 @@ support for any lower version (for example, support for version 2.0 also implies
    + 
    + 
    + <img alt="" style="float:right"
    +-src="//chart.googleapis.com/chart?chl=GL%202.0%7CGL%203.0%7CGL%203.1&chf=bg%2Cs%2C00000000&chd=t%3A46.0%2C42.6%2C11.4&chco=c4df9b%2C6fad0c&cht=p&chs=400x250">
    ++src="//chart.googleapis.com/chart?chl=GL%202.0%7CGL%203.0%7CGL%203.1&chf=bg%2Cs%2C00000000&chd=t%3A44.9%2C42.3%2C12.8&chco=c4df9b%2C6fad0c&cht=p&chs=400x250">
    + 
    + <p>To declare which version of OpenGL ES your application requires, you should use the {@code
    + android:glEsVersion} attribute of the <a
    +@@ -119,21 +119,21 @@ uses.</p>
    + </tr>
    + <tr>
    + <td>2.0</td>
    +-<td>46.0%</td>
    ++<td>44.9%</td>
    + </tr>
    + <tr>
    + <td>3.0</td>
    +-<td>42.6%</td>
    ++<td>42.3%</td>
    + </tr>
    + <tr>
    + <td>3.1</td>
    +-<td>11.4%</td>
    ++<td>12.8%</td>
    + </tr>
    + </table>
    + 
    + 
    + 
    +-<p style="clear:both"><em>Data collected during a 7-day period ending on August 1, 2016</em></p>
    ++<p style="clear:both"><em>Data collected during a 7-day period ending on September 5, 2016</em></p>
    + 
    + 
    + 
    +@@ -147,19 +147,19 @@ var SCREEN_DATA =
    +       "Large": {
    +         "hdpi": "0.5",
    +         "ldpi": "0.2",
    +-        "mdpi": "4.3",
    ++        "mdpi": "4.1",
    +         "tvdpi": "2.1",
    +         "xhdpi": "0.5"
    +       },
    +       "Normal": {
    +-        "hdpi": "40.0",
    +-        "mdpi": "3.8",
    +-        "tvdpi": "0.1",
    +-        "xhdpi": "27.3",
    ++        "hdpi": "39.5",
    ++        "mdpi": "3.5",
    ++        "tvdpi": "0.2",
    ++        "xhdpi": "28.4",
    +         "xxhdpi": "15.5"
    +       },
    +       "Small": {
    +-        "ldpi": "1.8"
    ++        "ldpi": "1.6"
    +       },
    +       "Xlarge": {
    +         "hdpi": "0.3",
    +@@ -167,8 +167,8 @@ var SCREEN_DATA =
    +         "xhdpi": "0.7"
    +       }
    +     },
    +-    "densitychart": "//chart.googleapis.com/chart?chd=t%3A2.0%2C11.0%2C2.2%2C40.8%2C28.5%2C15.5&chf=bg%2Cs%2C00000000&chl=ldpi%7Cmdpi%7Ctvdpi%7Chdpi%7Cxhdpi%7Cxxhdpi&cht=p&chs=400x250&chco=c4df9b%2C6fad0c",
    +-    "layoutchart": "//chart.googleapis.com/chart?chd=t%3A3.9%2C7.6%2C86.7%2C1.8&chf=bg%2Cs%2C00000000&chl=Xlarge%7CLarge%7CNormal%7CSmall&cht=p&chs=400x250&chco=c4df9b%2C6fad0c"
    ++    "densitychart": "//chart.googleapis.com/chart?chl=ldpi%7Cmdpi%7Ctvdpi%7Chdpi%7Cxhdpi%7Cxxhdpi&chd=t%3A1.8%2C10.5%2C2.3%2C40.4%2C29.6%2C15.5&chf=bg%2Cs%2C00000000&chco=c4df9b%2C6fad0c&cht=p&chs=400x250",
    ++    "layoutchart": "//chart.googleapis.com/chart?chl=Xlarge%7CLarge%7CNormal%7CSmall&chd=t%3A3.9%2C7.4%2C87.2%2C1.6&chf=bg%2Cs%2C00000000&chco=c4df9b%2C6fad0c&cht=p&chs=400x250"
    +   }
    + ];
    + 
    +@@ -176,7 +176,7 @@ var SCREEN_DATA =
    + var VERSION_DATA =
    + [
    +   {
    +-    "chart": "//chart.googleapis.com/chart?chd=t%3A0.1%2C1.7%2C1.6%2C16.7%2C29.2%2C35.5%2C15.2&chf=bg%2Cs%2C00000000&chl=Froyo%7CGingerbread%7CIce%20Cream%20Sandwich%7CJelly%20Bean%7CKitKat%7CLollipop%7CMarshmallow&cht=p&chs=500x250&chco=c4df9b%2C6fad0c",
    ++    "chart": "//chart.googleapis.com/chart?chl=Froyo%7CGingerbread%7CIce%20Cream%20Sandwich%7CJelly%20Bean%7CKitKat%7CLollipop%7CMarshmallow&chd=t%3A0.1%2C1.5%2C1.4%2C15.6%2C27.7%2C35.0%2C18.7&chf=bg%2Cs%2C00000000&chco=c4df9b%2C6fad0c&cht=p&chs=500x250",
    +     "data": [
    +       {
    +         "api": 8,
    +@@ -186,47 +186,47 @@ var VERSION_DATA =
    +       {
    +         "api": 10,
    +         "name": "Gingerbread",
    +-        "perc": "1.7"
    ++        "perc": "1.5"
    +       },
    +       {
    +         "api": 15,
    +         "name": "Ice Cream Sandwich",
    +-        "perc": "1.6"
    ++        "perc": "1.4"
    +       },
    +       {
    +         "api": 16,
    +         "name": "Jelly Bean",
    +-        "perc": "6.0"
    ++        "perc": "5.6"
    +       },
    +       {
    +         "api": 17,
    +         "name": "Jelly Bean",
    +-        "perc": "8.3"
    ++        "perc": "7.7"
    +       },
    +       {
    +         "api": 18,
    +         "name": "Jelly Bean",
    +-        "perc": "2.4"
    ++        "perc": "2.3"
    +       },
    +       {
    +         "api": 19,
    +         "name": "KitKat",
    +-        "perc": "29.2"
    ++        "perc": "27.7"
    +       },
    +       {
    +         "api": 21,
    +         "name": "Lollipop",
    +-        "perc": "14.1"
    ++        "perc": "13.1"
    +       },
    +       {
    +         "api": 22,
    +         "name": "Lollipop",
    +-        "perc": "21.4"
    ++        "perc": "21.9"
    +       },
    +       {
    +         "api": 23,
    +         "name": "Marshmallow",
    +-        "perc": "15.2"
    ++        "perc": "18.7"
    +       }
    +     ]
    +   }
    +diff --git a/docs/html/about/versions/_project.yaml b/docs/html/about/versions/_project.yaml
    +new file mode 100644
    +index 0000000..3f0e85e
    +--- /dev/null
    ++++ b/docs/html/about/versions/_project.yaml
    +@@ -0,0 +1,6 @@
    ++name: "Versions"
    ++home_url: /about/versions/
    ++description: "Android, the world's most popular mobile platform"
    ++content_license: cc3-apache2
    ++buganizer_id: 30209417
    ++parent_project_metadata_path: /about/_project.yaml
    +diff --git a/docs/html/about/versions/android-1.5.jd b/docs/html/about/versions/android-1.5.jd
    +index 45a27ee..6db5472 100644
    +--- a/docs/html/about/versions/android-1.5.jd
    ++++ b/docs/html/about/versions/android-1.5.jd
    +@@ -101,7 +101,7 @@ function toggleDiv(link) {
    + .toggleable.closed .toggleme {
    +   display:none;
    + }
    +-#jd-content .toggle-img {
    ++#body-content .toggle-img {
    +   margin:0;
    + }
    + </style>
    +diff --git a/docs/html/about/versions/android-1.6-highlights.jd b/docs/html/about/versions/android-1.6-highlights.jd
    +index 9179579..f594449 100644
    +--- a/docs/html/about/versions/android-1.6-highlights.jd
    ++++ b/docs/html/about/versions/android-1.6-highlights.jd
    +@@ -6,8 +6,8 @@ sdk.date=September 2009
    + 
    + 
    + <style type="text/css">
    +-#jd-content div.screenshot,
    +-#jd-content div.video {
    ++#body-content div.screenshot,
    ++#body-content div.video {
    +   float:right;
    +   clear:right;
    +   padding:15px 70px;
    +@@ -15,11 +15,11 @@ sdk.date=September 2009
    +   font-weight:bold;
    +   line-height:1.7em;
    + }
    +-#jd-content div.video {
    ++#body-content div.video {
    +   padding-top:0;
    +   margin-top:-15px;
    + }
    +-#jd-content div.screenshot img {
    ++#body-content div.screenshot img {
    +   margin:0;
    + }
    + </style>
    +diff --git a/docs/html/about/versions/android-1.6.jd b/docs/html/about/versions/android-1.6.jd
    +index 970c343..a84c225 100755
    +--- a/docs/html/about/versions/android-1.6.jd
    ++++ b/docs/html/about/versions/android-1.6.jd
    +@@ -103,7 +103,7 @@ function toggleDiv(link) {
    + .toggleable.closed .toggleme {
    +   display:none;
    + }
    +-#jd-content .toggle-img {
    ++#body-content .toggle-img {
    +   margin:0;
    + }
    + </style>
    +diff --git a/docs/html/about/versions/android-2.0-highlights.jd b/docs/html/about/versions/android-2.0-highlights.jd
    +index 3f7e1c8..017b16f 100644
    +--- a/docs/html/about/versions/android-2.0-highlights.jd
    ++++ b/docs/html/about/versions/android-2.0-highlights.jd
    +@@ -6,8 +6,8 @@ sdk.date=October 2009
    + 
    + 
    + <style type="text/css">
    +-#jd-content div.screenshot,
    +-#jd-content div.video {
    ++#body-content div.screenshot,
    ++#body-content div.video {
    +   float:right;
    +   clear:right;
    +   padding:15px 60px;
    +@@ -15,15 +15,15 @@ sdk.date=October 2009
    +   font-weight:bold;
    +   line-height:1.7em;
    + }
    +-#jd-content div.video {
    ++#body-content div.video {
    +   padding-top:0;
    +   margin-top:-15px;
    + }
    +-#jd-content div.screenshot.second {
    ++#body-content div.screenshot.second {
    +   clear:none;
    +   padding:15px 0 15px 60px;
    + }
    +-#jd-content div.screenshot img {
    ++#body-content div.screenshot img {
    +   margin:0;
    +   border:1px solid #ccc;
    + }
    +diff --git a/docs/html/about/versions/android-2.0.1.jd b/docs/html/about/versions/android-2.0.1.jd
    +index b0f4db6..21bfa65 100644
    +--- a/docs/html/about/versions/android-2.0.1.jd
    ++++ b/docs/html/about/versions/android-2.0.1.jd
    +@@ -99,7 +99,7 @@ padding: .25em 1em;
    + .toggleable.closed .toggleme {
    +   display:none;
    + }
    +-#jd-content .toggle-img {
    ++#body-content .toggle-img {
    +   margin:0;
    + }
    + </style>
    +diff --git a/docs/html/about/versions/android-2.0.jd b/docs/html/about/versions/android-2.0.jd
    +index 0323686..8029633 100644
    +--- a/docs/html/about/versions/android-2.0.jd
    ++++ b/docs/html/about/versions/android-2.0.jd
    +@@ -92,7 +92,7 @@ padding: .25em 1em;
    + .toggleable.closed .toggleme {
    +   display:none;
    + }
    +-#jd-content .toggle-img {
    ++#body-content .toggle-img {
    +   margin:0;
    + }
    + </style>
    +diff --git a/docs/html/about/versions/android-2.2-highlights.jd b/docs/html/about/versions/android-2.2-highlights.jd
    +index afbf26b..37a7a82 100644
    +--- a/docs/html/about/versions/android-2.2-highlights.jd
    ++++ b/docs/html/about/versions/android-2.2-highlights.jd
    +@@ -5,32 +5,32 @@ excludeFromSuggestions=true
    + 
    + 
    + <style type="text/css">
    +-#jd-content {
    ++#body-content {
    +   max-width:800px;
    + }
    +-#jd-content div.screenshot {
    ++#body-content div.screenshot {
    +   float:left;
    +   clear:left;
    +   padding:15px 30px 15px 0;
    + }
    +-#jd-content div.video {
    ++#body-content div.video {
    +   float:right;
    +   padding:0 60px 40px;
    +   margin-top:-15px;
    + }
    +-#jd-content table.columns {
    ++#body-content table.columns {
    +   margin:0 0 1em 0;
    + }
    +-#jd-content table.columns td {
    ++#body-content table.columns td {
    +   padding:0;
    + }
    +-#jd-content table.columns td+td {
    ++#body-content table.columns td+td {
    +   padding:0 2em;
    + }
    +-#jd-content table.columns td img {
    ++#body-content table.columns td img {
    +   margin:0;
    + }
    +-#jd-content table.columns td+td>*:first-child {
    ++#body-content table.columns td+td>*:first-child {
    +   margin-top:-2em;
    + }
    + .green {
    +diff --git a/docs/html/about/versions/android-2.3-highlights.jd b/docs/html/about/versions/android-2.3-highlights.jd
    +index 582bce9..013ec7f 100644
    +--- a/docs/html/about/versions/android-2.3-highlights.jd
    ++++ b/docs/html/about/versions/android-2.3-highlights.jd
    +@@ -4,31 +4,31 @@ page.title=Gingerbread
    + 
    + 
    + <style type="text/css">
    +-#jd-content {
    ++#body-content {
    +   max-width:1200px;
    + }
    +-#jd-content div.screenshot {
    ++#body-content div.screenshot {
    +   float:left;
    +   clear:left;
    +   padding:15px 30px 15px 0;
    + }
    +-#jd-content div.video {
    ++#body-content div.video {
    +   float:right;
    +   padding:0 0 0 40px;
    + }
    +-#jd-content table.columns {
    ++#body-content table.columns {
    +   margin:0 0 1em 0;
    + }
    +-#jd-content table.columns td {
    ++#body-content table.columns td {
    +   padding:0;
    + }
    +-#jd-content table.columns td+td {
    ++#body-content table.columns td+td {
    +   padding:0 2em;
    + }
    +-#jd-content table.columns td img {
    ++#body-content table.columns td img {
    +   margin:0;
    + }
    +-#jd-content table.columns td+td>*:first-child {
    ++#body-content table.columns td+td>*:first-child {
    +   margin-top:-2em;
    + }
    + .green {
    +diff --git a/docs/html/about/versions/android-3.0-highlights.jd b/docs/html/about/versions/android-3.0-highlights.jd
    +index e9d2b39..50d4667 100644
    +--- a/docs/html/about/versions/android-3.0-highlights.jd
    ++++ b/docs/html/about/versions/android-3.0-highlights.jd
    +@@ -4,31 +4,31 @@ page.title=Honeycomb
    + 
    + 
    + <style type="text/css">
    +-#jd-content {
    ++#body-content {
    +   max-width:1200px;
    + }
    +-#jd-content div.screenshot {
    ++#body-content div.screenshot {
    +   float:left;
    +   clear:left;
    +   padding:15px 30px 15px 0;
    + }
    +-#jd-content div.video {
    ++#body-content div.video {
    +   float:right;
    +   padding:0 60px 40px;
    + }
    +-#jd-content table.columns {
    ++#body-content table.columns {
    +   margin:0 0 1em 0;
    + }
    +-#jd-content table.columns td {
    ++#body-content table.columns td {
    +   padding:0;
    + }
    +-#jd-content table.columns td+td {
    ++#body-content table.columns td+td {
    +   padding:0 2em;
    + }
    +-#jd-content table.columns td img {
    ++#body-content table.columns td img {
    +   margin:0;
    + }
    +-#jd-content table.columns td+td>*:first-child {
    ++#body-content table.columns td+td>*:first-child {
    +   margin-top:-2em;
    + }
    + .green {
    +diff --git a/docs/html/about/versions/android-3.1-highlights.jd b/docs/html/about/versions/android-3.1-highlights.jd
    +index 2a70698..22df372 100644
    +--- a/docs/html/about/versions/android-3.1-highlights.jd
    ++++ b/docs/html/about/versions/android-3.1-highlights.jd
    +@@ -4,31 +4,31 @@ page.title=Honeycomb MR1
    + 
    + 
    + <style type="text/css">
    +-#jd-content {
    ++#body-content {
    +   max-width:1200px;
    + }
    +-#jd-content div.screenshot {
    ++#body-content div.screenshot {
    +   float:left;
    +   clear:left;
    +   padding:15px 30px 15px 0;
    + }
    +-#jd-content div.video {
    ++#body-content div.video {
    +   float:right;
    +   padding:0 60px 40px;
    + }
    +-#jd-content table.columns {
    ++#body-content table.columns {
    +   margin:0 0 1em 0;
    + }
    +-#jd-content table.columns td {
    ++#body-content table.columns td {
    +   padding:0;
    + }
    +-#jd-content table.columns td+td {
    ++#body-content table.columns td+td {
    +   padding:0 2em;
    + }
    +-#jd-content table.columns td img {
    ++#body-content table.columns td img {
    +   margin:0;
    + }
    +-#jd-content table.columns td+td>*:first-child {
    ++#body-content table.columns td+td>*:first-child {
    +   margin-top:-2em;
    + }
    + .green {
    +diff --git a/docs/html/about/versions/android-4.0-highlights.jd b/docs/html/about/versions/android-4.0-highlights.jd
    +index c980af6..57eb2a3 100755
    +--- a/docs/html/about/versions/android-4.0-highlights.jd
    ++++ b/docs/html/about/versions/android-4.0-highlights.jd
    +@@ -4,31 +4,31 @@ page.title=Ice Cream Sandwich
    + 
    + 
    + <style type="text/css">
    +-#jd-content {
    ++#body-content {
    +   max-width:1024px;
    + }
    +-#jd-content div.screenshot {
    ++#body-content div.screenshot {
    +   float:left;
    +   clear:left;
    +   padding:15px 30px 15px 0;
    + }
    +-#jd-content div.video {
    ++#body-content div.video {
    +   float:right;
    +   padding:0 0 40px 60px;
    + }
    +-#jd-content table.columns {
    ++#body-content table.columns {
    +   margin:0 0 1em 0;
    + }
    +-#jd-content table.columns td {
    ++#body-content table.columns td {
    +   padding:0;
    + }
    +-#jd-content table.columns td+td {
    ++#body-content table.columns td+td {
    +   padding:0 2em;
    + }
    +-#jd-content table.columns td img {
    ++#body-content table.columns td img {
    +   margin:0;
    + }
    +-#jd-content table.columns td+td>*:first-child {
    ++#body-content table.columns td+td>*:first-child {
    +   margin-top:-2em;
    + }
    + .green {
    +diff --git a/docs/html/about/versions/android-4.0.jd b/docs/html/about/versions/android-4.0.jd
    +index bf68584..48afcd4 100644
    +--- a/docs/html/about/versions/android-4.0.jd
    ++++ b/docs/html/about/versions/android-4.0.jd
    +@@ -631,8 +631,8 @@ Bluetooth connection.</p>
    + <p>A new package, {@link android.net.wifi.p2p}, contains all the APIs for performing peer-to-peer
    + connections with Wi-Fi. The primary class you need to work with is {@link
    + android.net.wifi.p2p.WifiP2pManager}, which you can acquire by calling {@link
    +-android.app.Activity#getSystemService(java.lang.String) getSystemService(WIFI_P2P_SERVICE)}.
    +-The {@link android.net.wifi.p2p.WifiP2pManager} includes APIs that allow you to:</p>
    ++android.app.Activity#getSystemService getSystemService(WIFI_P2P_SERVICE)}. The {@link
    ++android.net.wifi.p2p.WifiP2pManager} includes APIs that allow you to:</p>
    + <ul>
    + <li>Initialize your application for P2P connections by calling {@link
    + android.net.wifi.p2p.WifiP2pManager#initialize initialize()}</li>
    +@@ -798,7 +798,7 @@ text content to the {@link android.view.accessibility.AccessibilityEvent} if the
    + android.R.attr#contentDescription android:contentDescription} text is missing or
    + insufficient. To add more text description to the
    + {@link android.view.accessibility.AccessibilityEvent}, call {@link
    +-android.view.accessibility.AccessibilityRecord#getText()}.{@link java.util.List#add add()}.</p>
    ++android.view.accessibility.AccessibilityEvent#getText()}.{@link java.util.List#add add()}.</p>
    + </li>
    +   <li>At this point, the {@link android.view.View} passes the event up the view hierarchy by calling
    + {@link android.view.ViewGroup#requestSendAccessibilityEvent requestSendAccessibilityEvent()} on the
    +diff --git a/docs/html/about/versions/android-4.2.jd b/docs/html/about/versions/android-4.2.jd
    +index ac84d0f..34fa1d4 100755
    +--- a/docs/html/about/versions/android-4.2.jd
    ++++ b/docs/html/about/versions/android-4.2.jd
    +@@ -213,9 +213,9 @@ setScreenBright(true)} allows you to instead set the display at its usual bright
    + <p>Android now allows your app to display unique content on additional screens that are connected
    + to the user’s device over either a wired connection or Wi-Fi.
    +  To create unique content for a secondary display, extend the {@link android.app.Presentation}
    +-class and implement the {@link android.app.Dialog#onCreate onCreate()} callback. Within
    +-{@link android.app.Dialog#onCreate onCreate()}, specify your UI for the secondary display
    +-by calling {@link android.app.Dialog#setContentView setContentView()}.
    ++class and implement the {@link android.app.Presentation#onCreate onCreate()} callback. Within
    ++{@link android.app.Presentation#onCreate onCreate()}, specify your UI for the secondary display
    ++by calling {@link android.app.Presentation#setContentView setContentView()}.
    + As an extension of the {@link android.app.Dialog} class, the {@link
    + android.app.Presentation} class provides the region in which your app can display a unique UI on the
    + secondary display.</p>
    +@@ -241,13 +241,13 @@ appear on the secondary display.</p>
    + 
    + <p>To detect at runtime when a new display has been connected, create an instance of {@link
    + android.media.MediaRouter.SimpleCallback} in which you implement the {@link
    +-android.media.MediaRouter.Callback#onRoutePresentationDisplayChanged
    ++android.media.MediaRouter.SimpleCallback#onRoutePresentationDisplayChanged
    + onRoutePresentationDisplayChanged()} callback method, which the system will call when a new
    + presentation display is connected. Then register the {@link
    + android.media.MediaRouter.SimpleCallback} by passing it to {@link
    + android.media.MediaRouter#addCallback MediaRouter.addCallback()} along with the {@link
    + android.media.MediaRouter#ROUTE_TYPE_LIVE_VIDEO} route type. When you receive a call to
    +-{@link android.media.MediaRouter.Callback#onRoutePresentationDisplayChanged
    ++{@link android.media.MediaRouter.SimpleCallback#onRoutePresentationDisplayChanged
    + onRoutePresentationDisplayChanged()}, simply call {@link
    + android.media.MediaRouter#getSelectedRoute MediaRouter.getSelectedRoute()} as mentioned above.</p>
    + 
    +@@ -262,7 +262,7 @@ applied to your application or activity.</p>
    + likely a different screen density. Because the screen characteristics may different, you should
    + provide resources that are optimized specifically for such larger displays. If you need
    + to request additional resources from your {@link
    +-android.app.Presentation}, call {@link android.app.Dialog#getContext()}{@link
    ++android.app.Presentation}, call {@link android.app.Presentation#getContext()}{@link
    + android.content.Context#getResources .getResources()} to get the {@link
    + android.content.res.Resources} object corresponding to the display. This provides
    + the appropriate resources from your app that are best suited for the
    +@@ -510,7 +510,7 @@ common operations for you such as:</p>
    +   <p>To use a script intrinsic, call the static <code>create()</code> method of each instrinsic
    +   to create an instance of the script. You then call the available <code>set()</code>
    +   methods of each script intrinsic to set any necessary inputs and options.
    +-  Finally, call the {@link android.renderscript.Script#forEach forEach()}</code>
    ++  Finally, call the {@link android.renderscript.ScriptC#forEach forEach()}</code>
    +   method to execute the script.</p>
    +   </dd>
    + 
    +diff --git a/docs/html/about/versions/android-4.3.jd b/docs/html/about/versions/android-4.3.jd
    +index 34a701b..547b2f8 100644
    +--- a/docs/html/about/versions/android-4.3.jd
    ++++ b/docs/html/about/versions/android-4.3.jd
    +@@ -907,7 +907,7 @@ external data.</p>
    + 
    + <p>To track changes to inserts and updates, you can now include the {@link android.provider.ContactsContract.ContactsColumns#CONTACT_LAST_UPDATED_TIMESTAMP} parameter with your selection to query only the contacts that have changed since the last time you queried the provider.</p>
    + 
    +-<p>To track which contacts have been deleted, the new table {@link android.provider.ContactsContract.DeletedContacts} provides a log of contacts that have been deleted (but each contact deleted is held in this table for a limited time). Similar to {@link android.provider.ContactsContract.ContactsColumns#CONTACT_LAST_UPDATED_TIMESTAMP}, you can use the new selection parameter, {@link android.provider.ContactsContract.DeletedContactsColumns#CONTACT_DELETED_TIMESTAMP} to check which contacts have been deleted since the last time you queried the provider. The table also contains the constant {@link android.provider.ContactsContract.DeletedContacts#DAYS_KEPT_MILLISECONDS} containing the number of days (in milliseconds) that the log will be kept.</p>
    ++<p>To track which contacts have been deleted, the new table {@link android.provider.ContactsContract.DeletedContacts} provides a log of contacts that have been deleted (but each contact deleted is held in this table for a limited time). Similar to {@link android.provider.ContactsContract.ContactsColumns#CONTACT_LAST_UPDATED_TIMESTAMP}, you can use the new selection parameter, {@link android.provider.ContactsContract.DeletedContacts#CONTACT_DELETED_TIMESTAMP} to check which contacts have been deleted since the last time you queried the provider. The table also contains the constant {@link android.provider.ContactsContract.DeletedContacts#DAYS_KEPT_MILLISECONDS} containing the number of days (in milliseconds) that the log will be kept.</p>
    + 
    + <p>Additionally, the Contacts Provider now broadcasts the {@link
    + android.provider.ContactsContract.Intents#CONTACTS_DATABASE_CREATED} action when the user
    +diff --git a/docs/html/about/versions/marshmallow/android-6.0-changes.jd b/docs/html/about/versions/marshmallow/android-6.0-changes.jd
    +index 65c976b..b44142e 100644
    +--- a/docs/html/about/versions/marshmallow/android-6.0-changes.jd
    ++++ b/docs/html/about/versions/marshmallow/android-6.0-changes.jd
    +@@ -280,7 +280,7 @@ change fixes a problem where Dalvik was checking access rules incorrectly in pre
    + If your app uses the
    + {@link java.lang.reflect.Constructor#newInstance(java.lang.Object...) newInstance()} method and you
    + want to override access checks, call the
    +-{@link java.lang.reflect.AccessibleObject#setAccessible(boolean) setAccessible()} method with the input
    ++{@link java.lang.reflect.Constructor#setAccessible(boolean) setAccessible()} method with the input
    + parameter set to {@code true}. If your app uses the
    + <a href="{@docRoot}tools/support-library/features.html#v7-appcompat">v7 appcompat library</a> or the
    + <a href="{@docRoot}tools/support-library/features.html#v7-recyclerview">v7 recyclerview library</a>,
    +diff --git a/docs/html/about/versions/nougat/android-7.0-changes.jd b/docs/html/about/versions/nougat/android-7.0-changes.jd
    +index 84a56d0..cb92f19 100644
    +--- a/docs/html/about/versions/nougat/android-7.0-changes.jd
    ++++ b/docs/html/about/versions/nougat/android-7.0-changes.jd
    +@@ -182,8 +182,8 @@ certain implicit intents.
    + </p>
    + 
    + <p>
    +-  For more information about background optimizations in N and how to adapt your app,
    +-  see <a href=
    ++  For more information about background optimizations in Android 7.0 (API level
    ++  24) and how to adapt your app, see <a href=
    +   "{@docRoot}preview/features/background-optimization.html">Background
    +   Optimizations</a>.
    + </p>
    +@@ -427,12 +427,13 @@ see <a href="{@docRoot}training/secure-file-sharing/index.html">Sharing Files</a
    +   released apps, a set of libraries that see significant use—such as
    +   <code>libandroid_runtime.so</code>, <code>libcutils.so</code>,
    +   <code>libcrypto.so</code>, and <code>libssl.so</code>—are temporarily
    +-  accessible on N for apps targeting API level 23 or lower. If your app loads
    +-  one of these libraries, logcat generates a warning and a toast appears on the
    +-  target device to notify you. If you see these warnings, you should update
    +-  your app to either include its own copy of those libraries or only use the
    +-  public NDK APIs. Future releases of the Android platform may restrict the use
    +-  of private libraries altogether and cause your app to crash.
    ++  accessible on Android 7.0 (API level 24) for apps targeting API level 23 or
    ++  lower. If your app loads one of these libraries, logcat generates a warning
    ++  and a toast appears on the target device to notify you. If you see these
    ++  warnings, you should update your app to either include its own copy of those
    ++  libraries or only use the public NDK APIs. Future releases of the Android
    ++  platform may restrict the use of private libraries altogether and cause your
    ++  app to crash.
    + </p>
    + 
    + <p>
    +@@ -441,9 +442,9 @@ see <a href="{@docRoot}training/secure-file-sharing/index.html">Sharing Files</a
    +   <code>System.loadLibrary</code> and <code>dlopen(3)</code> both return
    +   <code>NULL</code>, and may cause your app to crash. You should review your
    +   app code to remove use of private platform APIs and thoroughly test your apps
    +-  using a preview device or emulator. If you are unsure whether your app uses
    +-  private libraries, you can <a href="#ndk-errors">check logcat</a> to identify
    +-  the runtime error.
    ++  using a device or emulator running Android 7.0 (API level 24). If you are
    ++  unsure whether your app uses private libraries, you can <a href=
    ++  "#ndk-errors">check logcat</a> to identify the runtime error.
    + </p>
    + 
    + <p>
    +@@ -454,11 +455,6 @@ see <a href="{@docRoot}training/secure-file-sharing/index.html">Sharing Files</a
    + 
    + <table id="ndk-table">
    +   <col width="15%">
    +-  <col width="15%">
    +-  <col width="15%">
    +-  <col width="20%">
    +-  <col width="20%">
    +-  <col width="20%">
    +   <tr>
    +     <th scope="col">
    +       Libraries
    +@@ -470,10 +466,7 @@ see <a href="{@docRoot}training/secure-file-sharing/index.html">Sharing Files</a
    +       Runtime access via dynamic linker
    +     </th>
    +     <th scope="col">
    +-      N Developer Preview behavior
    +-    </th>
    +-    <th scope="col">
    +-      Final N Release behavior
    ++      Android 7.0 (API level 24) behavior
    +     </th>
    +     <th scope="col">
    +       Future Android platform behavior
    +@@ -500,10 +493,6 @@ see <a href="{@docRoot}training/secure-file-sharing/index.html">Sharing Files</a
    +   <td style="background-color:#DCEDC8">
    +     Works as expected
    +   </td>
    +-
    +-  <td style="background-color:#DCEDC8">
    +-    Works as expected
    +-  </td>
    + </tr>
    + 
    + <tr>
    +@@ -520,11 +509,6 @@ see <a href="{@docRoot}training/secure-file-sharing/index.html">Sharing Files</a
    +   </td>
    + 
    +   <td style="background-color:#FFF9C4">
    +-      Works as expected, but you receive a logcat warning and a message on the
    +-      target device.
    +-  </td>
    +-
    +-  <td style="background-color:#FFF9C4">
    +     Works as expected, but you receive a logcat warning.
    +   </td>
    + 
    +@@ -553,10 +537,6 @@ see <a href="{@docRoot}training/secure-file-sharing/index.html">Sharing Files</a
    +   <td style="background-color:#ffcdd2">
    +     Runtime error
    +   </td>
    +-
    +-  <td style="background-color:#ffcdd2">
    +-    Runtime error
    +-  </td>
    + </tr>
    + 
    + <tr>
    +@@ -579,10 +559,6 @@ see <a href="{@docRoot}training/secure-file-sharing/index.html">Sharing Files</a
    +   <td style="background-color:#ffcdd2">
    +     Runtime error
    +   </td>
    +-
    +-  <td style="background-color:#ffcdd2">
    +-    Runtime error
    +-  </td>
    + </tr>
    + </table>
    + 
    +@@ -699,8 +675,8 @@ JavaVM::AttachCurrentThread from &lt;jni.h&gt;.
    + 
    + <ul>
    +   <li>You must install a delegated certificate installer before the DPC can set
    +-  it. For both profile and device-owner apps targeting the N SDK, you should
    +-  install the delegated certificate installer before the device policy
    ++  it. For both profile and device-owner apps targeting Android 7.0 (API level 24),
    ++  you should install the delegated certificate installer before the device policy
    +   controller (DPC) calls
    +   <code>DevicePolicyManager.setCertInstallerPackage()</code>. If the installer
    +   is not already installed, the system throws an
    +@@ -747,12 +723,13 @@ JavaVM::AttachCurrentThread from &lt;jni.h&gt;.
    +   DER-encoded format under a .crt or .cer file extension.
    +   </li>
    + 
    +-  <li>Starting in Android 7.0, fingerprint enrollment and storage are managed per user.
    +-  If a profile owner’s Device Policy Client (DPC) targets pre-N on an N device,
    +-  the user is still able to set fingerprint on the device, but work
    +-  applications cannot access device fingerprint. When the DPC targets N and
    +-  above, the user can set fingerprint specifically for work profile by going to
    +-  <strong>Settings &gt; Security &gt; Work profile security</strong>.
    ++  <li>Starting in Android 7.0, fingerprint enrollment and storage are managed
    ++  per user. If a profile owner’s Device Policy Client (DPC) targets API level
    ++  23 (or lower) on a device running Android 7.0 (API level 24), the user is
    ++  still able to set fingerprint on the device, but work applications cannot
    ++  access device fingerprint. When the DPC targets API level 24 and above, the user can set
    ++  fingerprint specifically for work profile by going to <strong>Settings &gt;
    ++  Security &gt; Work profile security</strong>.
    +   </li>
    + 
    +   <li>A new encryption status <code>ENCRYPTION_STATUS_ACTIVE_PER_USER</code> is
    +@@ -822,8 +799,9 @@ when killing the app manually via DDMS.
    + </p>
    + 
    + <p>
    +-Apps targeting N and above are not automatically killed on density changes;
    +-however, they may still respond poorly to configuration changes.
    ++  Apps targeting Android 7.0 (API level 24) and above are not automatically
    ++  killed on density changes; however, they may still respond poorly to
    ++  configuration changes.
    + </p>
    + </li>
    + 
    +diff --git a/docs/html/about/versions/nougat/android-7.0-samples.jd b/docs/html/about/versions/nougat/android-7.0-samples.jd
    +index e283a7a..ff63bef 100644
    +--- a/docs/html/about/versions/nougat/android-7.0-samples.jd
    ++++ b/docs/html/about/versions/nougat/android-7.0-samples.jd
    +@@ -6,7 +6,7 @@ page.image=images/cards/card-n-samples_2x.png
    + 
    + <p>
    +   Use the code samples below to learn about Android 7.0 capabilities and APIs. To
    +-  download the samples in Android Studio, select the <b>File &gt; Import
    ++  download the samples in Android Studio, select the <b>File &gt; New &gt; Import
    +   Samples</b> menu option.
    + </p>
    + 
    +diff --git a/docs/html/about/versions/nougat/android-7.0.jd b/docs/html/about/versions/nougat/android-7.0.jd
    +index 1ca540c..8ef8bd6 100644
    +--- a/docs/html/about/versions/nougat/android-7.0.jd
    ++++ b/docs/html/about/versions/nougat/android-7.0.jd
    +@@ -44,7 +44,7 @@ page.image=images/cards/card-n-apis_2x.png
    +         <li><a href="#vr">VR Support</a></li>
    +         <li><a href="#print_svc">Print Service Enhancements</a></li>
    +         <li><a href="#virtual_files">Virtual Files</a></li>
    +-        <li><a href="#framemetrics_api">FrameMetricsListener API</a></li>
    ++        <li><a href="#framemetrics_api">Frame Metrics API</a></li>
    +       </ol>
    + </div>
    + </div>
    +@@ -434,9 +434,8 @@ displayed &mdash; users can add or move tiles just by dragging and dropping them
    + </p>
    + 
    + <p>
    +-  For information about creating an app tile, see the documentation for
    +-  <code>android.service.quicksettings.Tile</code> in the downloadable <a href=
    +-  "{@docRoot}preview/setup-sdk.html#docs-dl">API Reference</a>.
    ++  For information about creating an app tile, see the reference documentation
    ++  for {@link android.service.quicksettings.Tile Tile}.
    + </p>
    + 
    + 
    +@@ -465,9 +464,8 @@ for the user in order to stop unwanted calls and texts from reaching the user
    + through any medium, such as a VOIP endpoint or forwarding phones.</p>
    + 
    + <p>
    +-  For more information, see <code>android.provider.BlockedNumberContract</code>
    +-  in the downloadable <a href="{@docRoot}preview/setup-sdk.html#docs-dl">API
    +-  Reference</a>.
    ++  For more information, see the reference documentation for
    ++  {@link android.provider.BlockedNumberContract BlockedNumberContract}.
    + </p>
    + 
    + <h2 id="call_screening">Call Screening</h2>
    +@@ -486,9 +484,8 @@ through any medium, such as a VOIP endpoint or forwarding phones.</p>
    + </ul>
    + 
    + <p>
    +-  For more information, see <code>android.telecom.CallScreeningService</code>
    +-  in the downloadable <a href="{@docRoot}preview/setup-sdk.html#docs-dl">API
    +-  Reference</a>.
    ++  For more information, see the reference documentation for
    ++  {@link android.telecom.CallScreeningService CallScreeningService}.
    + </p>
    + 
    + 
    +@@ -780,8 +777,9 @@ impairments to touch the screen. The new API allows building services with
    + features such as face-tracking, eye-tracking, point scanning, and so on, to
    + meet the needs of those users.</p>
    + 
    +-<p>For more information, see <code>android.accessibilityservice.GestureDescription</code>
    +-  in the downloadable <a href="{@docRoot}preview/setup-sdk.html#docs-dl">API Reference</a>.</p>
    ++<p>For more information, see the reference documentation for
    ++{@link android.accessibilityservice.GestureDescription GestureDescription}.
    ++</p>
    + 
    + 
    + <h2 id="direct_boot">Direct Boot</h2>
    +@@ -972,9 +970,8 @@ Directory Access</a> developer documentation.</p>
    +   from the system and from the app in focus. The system retrieves these
    +   shortcuts automatically from the app’s menu if the shortcuts exist. You can
    +   also provide your own fine-tuned shortcuts lists for the screen. You can do
    +-  this by overriding the new <code>Activity.onProvideKeyboardShortcuts()</code>
    +-  method, described in the downloadable <a href=
    +-  "{@docRoot}preview/setup-sdk.html#docs-dl">API Reference</a>.
    ++  this by overriding the {@link android.view.Window.Callback#onProvideKeyboardShortcuts
    ++  onProvideKeyboardShortcuts()} method.
    + </p>
    + 
    + <p class="note">
    +@@ -986,7 +983,8 @@ Directory Access</a> developer documentation.</p>
    + 
    + <p>
    +   To trigger Keyboard Shortcuts Helper from anywhere in your app, call
    +-  {@code Activity.requestKeyboardShortcutsHelper()} for the relevant activity.
    ++  {@link android.app.Activity#requestShowKeyboardShortcuts requestShowKeyboardShortcuts()}
    ++  from the relevant activity.
    + </p>
    + 
    + <h2 id="custom_pointer_api">
    +@@ -1062,37 +1060,32 @@ see the <a href="https://developers.google.com/vr/android/">Google VR SDK for An
    + 
    + <ul>
    +   <li>You can set an icon from a resource ID by calling
    +-  <code>PrinterInfo.Builder.setResourceIconId()</code>
    ++  {@link android.print.PrinterInfo.Builder#setIconResourceId setIconResourceId()}.
    +   </li>
    + 
    +   <li>You can show an icon from the network by calling
    +-  <code>PrinterInfo.Builder.setHasCustomPrinterIcon()</code>, and setting a
    +-  callback for when the icon is requested using
    +-  <code>android.printservice.PrinterDiscoverySession.onRequestCustomPrinterIcon()</code>
    ++  {@link android.print.PrinterInfo.Builder#setHasCustomPrinterIcon setHasCustomPrinterIcon()},
    ++  and setting a callback for when the icon is requested using
    ++  {@link android.printservice.PrinterDiscoverySession#onRequestCustomPrinterIcon onRequestCustomPrinterIcon()}.
    +   </li>
    + </ul>
    + 
    + <p>
    +   In addition, you can provide a per-printer activity to display additional
    +-  information by calling <code>PrinterInfo.Builder.setInfoIntent()</code>.
    ++  information by calling {@link android.print.PrinterInfo.Builder#setInfoIntent setInfoIntent()}.
    + </p>
    + 
    + <p>
    +   You can indicate the progress and status of print jobs in the print job
    +   notification by calling
    +-  <code>android.printservice.PrintJob.setProgress()</code> and
    +-  <code>android.printservice.PrintJob.setStatus()</code>, respectively.
    +-</p>
    +-
    +-<p>
    +-  For more information about these methods, see the downloadable <a href=
    +-  "{@docRoot}preview/setup-sdk.html#docs-dl">API Reference</a>.
    ++  {@link android.printservice.PrintJob#setProgress setProgress()} and
    ++  {@link android.printservice.PrintJob#setStatus setStatus()}, respectively.
    + </p>
    + 
    +-<h2 id="framemetrics_api">FrameMetricsListener API</h2>
    ++<h2 id="framemetrics_api">Frame Metrics API</h2>
    + 
    + <p>
    +-The FrameMetricsListener API allows an app to monitor its UI rendering
    ++The Frame Metrics API allows an app to monitor its UI rendering
    + performance. The API provides this capability by exposing a streaming Pub/Sub API to transfer frame
    + timing info for the app's current window. The data returned is
    + equivalent to that which <code><a href="{@docRoot}tools/help/shell.html#shellcommands">adb shell</a>
    +@@ -1100,7 +1093,7 @@ dumpsys gfxinfo framestats</code> displays, but is not limited to the past 120 f
    + </p>
    + 
    + <p>
    +-You can use FrameMetricsListener to measure interaction-level UI
    ++You can use the Frame Metrics API to measure interaction-level UI
    + performance in production, without a USB connection. This API
    + allows collection of data at a much higher granularity than does
    + {@code adb shell dumpsys gfxinfo}. This higher granularity is possible because
    +@@ -1112,16 +1105,15 @@ for real use cases within an app.
    + </p>
    + 
    + <p>
    +-To monitor a window, implement the <code>FrameMetricsListener.onMetricsAvailable()</code>
    +-callback method and register it on that window. For more information, refer to
    +-the {@code FrameMetricsListener} class documentation in
    +-the downloadable <a href="{@docRoot}preview/setup-sdk.html#docs-dl">API Reference</a>.
    ++To monitor a window, implement the
    ++{@link android.view.Window.OnFrameMetricsAvailableListener#onFrameMetricsAvailable OnFrameMetricsAvailableListener.onFrameMetricsAvailable()}
    ++callback method and register it on that window.
    + </p>
    + 
    + <p>
    +-The API provides a {@code FrameMetrics} object, which contains timing data that
    +-the rendering subsystem reports for various milestones in a frame lifecycle.
    +-The supported metrics are: {@code UNKNOWN_DELAY_DURATION},
    ++The API provides a {@link android.view.FrameMetrics FrameMetrics} object, which
    ++contains timing data that the rendering subsystem reports for various milestones
    ++in a frame lifecycle. The supported metrics are: {@code UNKNOWN_DELAY_DURATION},
    + {@code INPUT_HANDLING_DURATION}, {@code ANIMATION_DURATION},
    + {@code LAYOUT_MEASURE_DURATION}, {@code DRAW_DURATION}, {@code SYNC_DURATION},
    + {@code COMMAND_ISSUE_DURATION}, {@code SWAP_BUFFERS_DURATION},
    +diff --git a/docs/html/about/versions/nougat/index.jd b/docs/html/about/versions/nougat/index.jd
    +index 30a3576..8661d77 100644
    +--- a/docs/html/about/versions/nougat/index.jd
    ++++ b/docs/html/about/versions/nougat/index.jd
    +@@ -7,16 +7,6 @@ header.hide=1
    + footer.hide=1
    + @jd:body
    + 
    +-<script>
    +-  $(document).ready(function() {
    +-    if (useUpdatedTemplates) {
    +-      $("#useUpdatedTemplates").css("display","block");
    +-    } else {
    +-      $("#useOldTemplates").css("display","block");
    +-    }
    +-  })
    +-</script>
    +-
    + <section class="dac-expand dac-hero dac-light">
    +   <div class="wrap" style="max-width:1100px;margin-top:0">
    +   <a href="{@docRoot}about/versions/nougat/android-7.0.html">
    +@@ -54,8 +44,7 @@ footer.hide=1
    +   </div>
    + </section>
    + 
    +-
    +-<div id="useUpdatedTemplates" style="display:none" class="dac-section dac-slim dac-gray dac-expand">
    ++<div class="dac-section dac-slim dac-gray dac-expand">
    +   <div class="wrap dac-offset-parent">
    +     <a class="dac-fab dac-scroll-button" data-scroll-button href="#latest">
    +       <i class="dac-sprite dac-arrow-down-gray"></i>
    +@@ -77,26 +66,6 @@ footer.hide=1
    +   </div><!-- end .wrap -->
    + </div><!-- end .dac-actions -->
    + 
    +-<div id="useOldTemplates" style="display:none;color:black" class="actions-bar dac-expand dac-invert">
    +-  <div class="wrap dac-offset-parent">
    +-
    +-    <div class="actions">
    +-      <div><a href="https://developer.android.com/preview/bug">
    +-        <span class="dac-sprite dac-auto-chevron-large"></span>
    +-        Report an issue
    +-      </a></div>
    +-      <div><a href="{@docRoot}preview/support.html">
    +-        <span class="dac-sprite dac-auto-chevron-large"></span>
    +-        See release notes
    +-      </a></div>
    +-      <div><a href="{@docRoot}preview/dev-community">
    +-        <span class="dac-sprite dac-auto-chevron-large"></span>
    +-        Join dev community
    +-      </a></div>
    +-    </div><!-- end .actions -->
    +-  </div><!-- end .wrap -->
    +-</div>
    +-
    + <section class="dac-section dac-light dac-small" id="latest"><div class="wrap">
    +   <h2 class="norule">Latest</h2>
    +   <div class="resource-widget resource-flow-layout col-16"
    +diff --git a/docs/html/auto/_project.yaml b/docs/html/auto/_project.yaml
    +new file mode 100644
    +index 0000000..fc4ab2b
    +--- /dev/null
    ++++ b/docs/html/auto/_project.yaml
    +@@ -0,0 +1,6 @@
    ++name: "Auto"
    ++home_url: /auto/
    ++description: "Let drivers listen to and control content in your music and other audio apps."
    ++content_license: cc3-apache2
    ++buganizer_id: 30209417
    ++parent_project_metadata_path: /about/_project.yaml
    +diff --git a/docs/html/auto/index.jd b/docs/html/auto/index.jd
    +index e6fde38..3ebd87d 100644
    +--- a/docs/html/auto/index.jd
    ++++ b/docs/html/auto/index.jd
    +@@ -10,7 +10,7 @@ nonavpage=true
    + 
    + <style>
    + .fullpage>#footer,
    +-#jd-content>.content-footer.wrap {
    ++#body-content>.content-footer.wrap {
    +   display:none;
    + }
    + .img-logo {
    +diff --git a/docs/html/design/_book.yaml b/docs/html/design/_book.yaml
    +index 18b4719..8ffa9a4 100644
    +--- a/docs/html/design/_book.yaml
    ++++ b/docs/html/design/_book.yaml
    +@@ -117,8 +117,6 @@ toc:
    +     path: /design/patterns/pure-android.html
    +   - title: Compatibility
    +     path: /design/patterns/compatibility.html
    +-  - title: Accessibility
    +-    path: /design/patterns/accessibility.html
    +   - title: Help
    +     path: /design/patterns/help.html
    + 
    +diff --git a/docs/html/design/patterns/accessibility.jd b/docs/html/design/patterns/accessibility.jd
    +deleted file mode 100644
    +index b910294..0000000
    +--- a/docs/html/design/patterns/accessibility.jd
    ++++ /dev/null
    +@@ -1,98 +0,0 @@
    +-page.title=Accessibility
    +-page.tags="accessibility","navigation","input"
    +-page.metaDescription=Design an app that's universally accessible to people with visual impairment, color deficiency, hearing loss, and limited dexterity.
    +-@jd:body
    +-
    +-<a class="notice-designers-material"
    +-  href="http://www.google.com/design/spec/usability/accessibility.html">
    +-  <div>
    +-    <h3>Material Design</h3>
    +-    <p>Accessibility<p>
    +-  </div>
    +-</a>
    +-
    +-<a class="notice-developers" href="{@docRoot}training/accessibility/index.html">
    +-  <div>
    +-    <h3>Developer Docs</h3>
    +-    <p>Implementing Accessibility</p>
    +-  </div>
    +-</a>
    +-
    +-<p>One of Android's missions is to organize the world's information and make it universally accessible and useful. Accessibility is the measure of how successfully a product can be used by people with varying abilities. Our mission applies to all users-including people with disabilities such as visual impairment, color deficiency, hearing loss, and limited dexterity.</p>
    +-<p><a href="https://www.google.com/#hl=en&q=universal+design&fp=1">Universal design</a> is the practice of making products that are inherently accessible to all users, regardless of ability. The Android design patterns were created in accordance with universal design principles, and following them will help your app meet basic usability standards. Adhering to universal design and enabling Android's accessibility tools will make your app as accessible as possible.</p>
    +-<p>Robust support for accessibility will increase your app's user base. It may also be required for adoption by some organizations.</p>
    +-<p><a href="http://www.google.com/accessibility/">Learn more about Google and accessibility.</a></p>
    +-
    +-<h2 id="tools">Android's Accessibility Tools</h2>
    +-<p>Android includes several features that support access for users with visual impairments; they don't require drastic visual changes to your app.</p>
    +-
    +-<ul>
    +-  <li><strong><a href="https://play.google.com/store/apps/details?id=com.google.android.marvin.talkback">TalkBack</a></strong> is a pre-installed screen reader service provided by Google. It uses spoken feedback to describe the results of actions such as launching an app, and events such as notifications.</li>
    +-  <li><strong>Explore by Touch</strong> is a system feature that works with TalkBack, allowing you to touch your device's screen and hear what's under your finger via spoken feedback. This feature is helpful to users with low vision.</li>
    +-  <li><strong>Accessibility settings</strong> let you modify your device's display and sound options, such as increasing the text size, changing the speed at which text is spoken, and more.</li>
    +-</ul>
    +-
    +-<p>Some users use hardware or software directional controllers (such as a D-pad, trackball, keyboard) to jump from selection to selection on a screen. They interact with the structure of your app in a linear fashion, similar to 4-way remote control navigation on a television.</p>
    +-
    +-<h2 id="tools">Guidelines</h2>
    +-<p>The Android design principle "I should always know where I am" is key for accessibility concerns. As a user navigates through an application, they need feedback and a mental model of where they are. All users benefit from a strong sense of information hierarchy and an architecture that makes sense. Most users benefit from visual and haptic feedback during their navigation (such as labels, colors, icons, touch feedback) Low vision users benefit from explicit verbal descriptions and large visuals with high contrast.</p>
    +-<p>As you design your app, think about the labels and notations needed to navigate your app by sound. When using Explore by Touch, the user enables an invisible but audible layer of structure in your application. Like any other aspect of app design, this structure can be simple, elegant, and robust. The following are Android's recommended guidelines to enable effective navigation for all users.</p>
    +-
    +-<h4>Make navigation intuitive</h4>
    +-<p>Design well-defined, clear task flows with minimal navigation steps, especially for major user tasks. Make sure those tasks are navigable via focus controls. </p>
    +-
    +-<h4>Use recommended touch target sizes</h4>
    +-<p>48 dp is the recommended touch target size for on screen elements. Read about <a href="{@docRoot}design/style/metrics-grids.html">Android Metrics and Grids</a> to learn about implementation strategies to help most of your users. For certain users, it may be appropriate to use larger touch targets. An example of this is educational apps, where buttons larger than the minimum recommendations are appropriate for children with developing motor skills and people with manual dexterity challenges.</p>
    +-
    +-
    +-<h4>Label visual UI elements meaningfully</h4>
    +-<p>In your wireframes, <a href="{@docRoot}guide/topics/ui/accessibility/apps.html#label-ui">label functional UI components</a> that have no visible text. Those components might be buttons, icons, tabs with icons, and icons with state (like stars). Developers can use the <code><a href="{@docRoot}guide/topics/ui/accessibility/apps.html#label-ui">contentDescription</a></code> attribute to set the label.</p>
    +-
    +-<div class ="cols">
    +-    <div class="col-8">
    +-      <img src="{@docRoot}design/media/accessibility_contentdesc.png">
    +-    </div>
    +-    <div class="col-5 with-callouts">
    +-      <ol>
    +-        <li class="value-1">group</li>
    +-        <li class="value-2">all contacts</li>
    +-        <li class="value-3">favorites</li>
    +-        <li class="value-4">search</li>
    +-        <li class="value-5">action overflow button</li>
    +-        <li class="value-6">
    +-          <em>when starred:</em> remove from favorites </br>
    +-          <em>when not starred:</em> add to favorties</li>
    +-        <li class="value-7">action overflow button</li>
    +-        <li class="value-8">text message</li>
    +-      </ol>
    +-  </div>
    +-</div>
    +-
    +-<h4>Provide alternatives to affordances that time out</h4>
    +-<p>Your app may have icons or controls that disappear after a certain amount of time. For example, five seconds after starting a video, playback controls may fade from the screen.</p>
    +-
    +-<p>Due to the way that TalkBack works, those controls are not read out loud unless they are focused on. If they fade out from the screen quickly, your user may not even be aware that they are available. Therefore, make sure that you are not relying on timed out controls for high priority task flows. (This is a good universal design guideline too.) If the controls enable an important function, make sure that the user can turn on the controls again and/or their function is duplicated elsewhere. You can also change the behavior of your app when accessibility services are turned on. Your developer may be able to make sure that timed-out controls won't disappear.</p>
    +-
    +-<h4>Use standard framework controls or enable TalkBack for custom controls</h4>
    +-<p>Standard Android framework controls work automatically with accessibility services and have ContentDescriptions built in by default.</p>
    +-
    +-<p>An oft-overlooked system control is font size. Users can turn on a system-wide large font size in Settings; using the default system font size in your application will enable the user's preferences in your app as well. To enable system font size in your app, mark text and their associated containers to be measured in <a href="{@docRoot}guide/practices/screens_support.html#screen-independence">scale pixels</a>.</p>
    +-
    +-<p>Also, keep in mind that when users have large fonts enabled or speak a different language than you, their type might be larger than the space you've allotted for it. Read <a href="{@docRoot}design/style/devices-displays.html">Devices and Displays</a> and <a href="http://developer.android.com/guide/practices/screens_support.html">Supporting Multiple Screens</a> for design strategies.</p>
    +-
    +-<p>If you use custom controls, Android has the developer tools in place to allow adherence to the above guidelines and provide meaningful descriptions about the UI. Provide adequate notation on your wireframes and direct your developer to the <a href="{@docRoot}guide/topics/ui/accessibility/apps.html#custom-views">Custom Views</a> documentation.</p>
    +-
    +-<h4>Try it out yourself</h4>
    +-<p>Turn on the TalkBack service in <strong>Settings > Accessibility</strong> and navigate your application using directional controls or eyes-free navigation.</p>
    +-
    +-
    +-
    +-<h2>Checklist</h2>
    +-<ul>
    +-  <li>Make navigation intuitive</li>
    +-  <li>Use recommended touch target sizes</li>
    +-  <li>Label visual UI elements meaningfully</li>
    +-  <li>Provide alternatives to affordances that time out</li>
    +-  <li>Use standard framework controls or enable TalkBack for custom controls</li>
    +-  <li>Try it out yourself</li>
    +-</ul>
    +diff --git a/docs/html/develop/index.jd b/docs/html/develop/index.jd
    +index bd933f4..564dbf9 100644
    +--- a/docs/html/develop/index.jd
    ++++ b/docs/html/develop/index.jd
    +@@ -14,29 +14,36 @@ excludeFromSuggestions=true
    +   <div class="wrap">
    +     <div class="cols dac-hero-content">
    +       <div class="col-1of2 col-push-1of2 dac-hero-figure">
    +-        <img class="dac-hero-image" src="/images/develop/hero_image_studio5_2x.png" srcset="/images/develop/hero_image_studio5.png 1x, /images/develop/hero_image_studio5_2x.png 2x">
    ++        <img class="dac-hero-image" style="padding-top:32px"
    ++          src="/images/develop/hero-layout-editor_2x.png"
    ++          srcset="/images/develop/hero-layout-editor_2x.png 2x,
    ++                  /images/develop/hero-layout-editor.png 1x">
    +       </div>
    +       <div class="col-1of2 col-pull-1of2" style="margin-bottom:40px">
    +         <h1 class="dac-hero-title">
    +             <a style="color:inherit" href="{@docRoot}studio/index.html">
    +-            Android Studio 2.1,<br>now available!</a></h1>
    ++            Android Studio 2.2</a></h1>
    + 
    +-<p class="dac-hero-description">Android Studio provides the fastest tools for
    +-building apps on every type of Android device.</p>
    ++<p class="dac-hero-description">There are 20+ new features in this release
    ++focused on helping you code faster and smarter. With Android Studio 2.2 you
    ++can:</p>
    + 
    +-<p class="dac-hero-description">The latest version, Android Studio 2.1, adds
    +-support for N Preview development on top of the faster Android Emulator and
    +-Instant Run feature from 2.0.</p>
    ++<ul class="dac-hero-description">
    ++  <li>Develop your app user interface faster with the new Layout Editor &amp;
    ++    Constraint Layout</li>
    ++  <li>Develop smarter with the APK analyzer &amp; expanded code analysis</li>
    ++  <li>Develop with the the latest Android 7.0 Nougat APIs &amp; features</li>
    ++</ul>
    + 
    + <p style="margin-top:24px">
    +     <a class="dac-hero-cta" href="{@docRoot}studio/index.html">
    +       <span class="dac-sprite dac-auto-chevron"></span>
    +-      Get Android Studio
    ++      Get Android Studio 2.2
    +     </a>
    +   &nbsp;&nbsp;&nbsp;&nbsp;<wbr>
    +-    <a class="dac-hero-cta" href="{@docRoot}studio/releases/index.html">
    ++    <a class="dac-hero-cta" href="{@docRoot}studio/features.html">
    +     <span class="dac-sprite dac-auto-chevron"></span>
    +-    See the release notes</a>
    ++    See more features</a>
    + </p>
    + 
    +       </div>
    +diff --git a/docs/html/distribute/essentials/quality/wear.jd b/docs/html/distribute/essentials/quality/wear.jd
    +index 34c6cc5..be48491 100644
    +--- a/docs/html/distribute/essentials/quality/wear.jd
    ++++ b/docs/html/distribute/essentials/quality/wear.jd
    +@@ -42,6 +42,13 @@ page.image=/distribute/images/gp-wear-quality.png
    +   understand the basic implementation requirements for a Wear app.
    + </p>
    + 
    ++<p>
    ++  This document helps you assess basic aspects of quality in your Wear app through a
    ++  compact set of functional and user interface quality criteria.
    ++   Make sure to check out the <a href="https://developer.android.com/wear/preview/index.html">Wear 2.0 preview</a>
    ++  documentation to get ready for the next version of Android Wear.
    ++</p>
    ++
    + <p class="caution">
    +   <strong>Important:</strong> To ensure a great user experience, apps for wearables must meet
    +   specific requirements for usability. Only apps that meet the following quality criteria will
    +@@ -50,8 +57,8 @@ page.image=/distribute/images/gp-wear-quality.png
    + </p>
    + 
    + <p class="note">
    +- <strong>Note:</strong> For information about how to publish your Wear apps in Google Play, see <a
    +- href="{@docRoot}distribute/googleplay/wear.html">Distributing to Android Wear</a>.
    ++  <strong>Note:</strong> For information about how to publish your Wear apps in Google Play, see <a
    ++  href="{@docRoot}distribute/googleplay/wear.html">Distributing to Android Wear</a>.
    + </p>
    + 
    + <div class="headerLine">
    +@@ -67,6 +74,19 @@ page.image=/distribute/images/gp-wear-quality.png
    +   functional behavior.
    + </p>
    + 
    ++<p class="caution">
    ++  <strong>Important:</strong> To learn about how Wear 2.0 platform changes may affect
    ++   your apps, see the <a href="https://developer.android.com/wear/preview/index.html">Wear 2.0 preview</a>
    ++   documentation.
    ++</p>
    ++
    ++<p class="note">
    ++  <strong>Note:</strong> The symbol &#10008; is used in the table below to indicate
    ++  quality criteria that are not required for the corresponding Wear version.
    ++</p>
    ++
    ++<p class="table-caption"><strong>Table 1</strong>. Functional criteria.
    ++</p>
    + 
    + <table>
    + <tr>
    +@@ -79,6 +99,12 @@ page.image=/distribute/images/gp-wear-quality.png
    +   <th>
    +     Description
    +   </th>
    ++  <th>
    ++    Wear 1.0
    ++  </th>
    ++  <th>
    ++    Wear 2.0
    ++  </th>
    + </tr>
    + 
    + <tr>
    +@@ -96,6 +122,12 @@ page.image=/distribute/images/gp-wear-quality.png
    +       (<a href="{@docRoot}training/building-wearables.html">Learn how</a>)
    +     </p>
    +   </td>
    ++  <td>
    ++    &#10004;
    ++  </td>
    ++  <td>
    ++    &#10004;
    ++  </td>
    + </tr>
    + 
    + <tr>
    +@@ -107,6 +139,12 @@ page.image=/distribute/images/gp-wear-quality.png
    +       App has Wear functionality that is visible to the user.
    +     </p>
    +   </td>
    ++  <td>
    ++    &#10004;
    ++  </td>
    ++  <td>
    ++    &#10004;
    ++  </td>
    + </tr>
    + 
    + <tr>
    +@@ -118,6 +156,12 @@ page.image=/distribute/images/gp-wear-quality.png
    +       Wear functionality works as expected or as described in the app's Google Play Store listing.
    +     </p>
    +   </td>
    ++  <td>
    ++    &#10004;
    ++  </td>
    ++  <td>
    ++    &#10004;
    ++  </td>
    + </tr>
    + 
    + <tr>
    +@@ -135,6 +179,12 @@ page.image=/distribute/images/gp-wear-quality.png
    +       (<a href="{@docRoot}training/wearables/apps/packaging.html">Learn how</a>)
    +     </p>
    +   </td>
    ++  <td>
    ++    &#10004;
    ++  </td>
    ++  <td>
    ++    &#10008;
    ++  </td>
    + </tr>
    + 
    + <tr>
    +@@ -152,6 +202,12 @@ page.image=/distribute/images/gp-wear-quality.png
    +       (<a href="{@docRoot}training/wearables/notifications/index.html">Learn how</a>)
    +     </p>
    +   </td>
    ++  <td>
    ++    &#10004;
    ++  </td>
    ++  <td>
    ++    &#10008;
    ++  </td>
    + </tr>
    + 
    + <tr>
    +@@ -164,6 +220,12 @@ page.image=/distribute/images/gp-wear-quality.png
    +       (<a href="{@docRoot}training/wearables/notifications/voice-input.html">Learn how</a>)
    +     </p>
    +   </td>
    ++  <td>
    ++    &#10004;
    ++  </td>
    ++  <td>
    ++    &#10008;
    ++  </td>
    + </tr>
    + 
    + <tr>
    +@@ -176,6 +238,12 @@ page.image=/distribute/images/gp-wear-quality.png
    +       (<a href="{@docRoot}training/wearables/notifications/stacks.html">Learn how</a>)
    +     </p>
    +   </td>
    ++  <td>
    ++    &#10004;
    ++  </td>
    ++  <td>
    ++    &#10008;
    ++  </td>
    + </tr>
    + 
    + <tr>
    +@@ -193,6 +261,12 @@ page.image=/distribute/images/gp-wear-quality.png
    +       (<a href="{@docRoot}training/wearables/ui/exit.html">Learn how</a>)
    +     </p>
    +   </td>
    ++  <td>
    ++    &#10004;
    ++  </td>
    ++  <td>
    ++    &#10008;
    ++  </td>
    + </tr>
    + 
    + <tr>
    +@@ -206,6 +280,12 @@ page.image=/distribute/images/gp-wear-quality.png
    +       (<a href="{@docRoot}training/wearables/ui/exit.html">Learn how</a>)
    +     </p>
    +   </td>
    ++  <td>
    ++    &#10004;
    ++  </td>
    ++  <td>
    ++    &#10008;
    ++  </td>
    + </tr>
    + 
    + <tr>
    +@@ -222,6 +302,12 @@ page.image=/distribute/images/gp-wear-quality.png
    +       (<a href="{@docRoot}training/wearables/watch-faces/index.html">Learn how</a>)
    +     </p>
    +   </td>
    ++  <td>
    ++    &#10004;
    ++  </td>
    ++  <td>
    ++    &#10008;
    ++  </td>
    + </tr>
    + 
    + </table>
    +@@ -245,8 +331,15 @@ data-sortorder="-timestamp" data-cardsizes="6x2" data-maxresults="6">
    + <p>
    +   These criteria ensure that your app follows critical design and interaction patterns to provide a
    +   consistent, intuitive, and enjoyable user experience on wearables.
    ++
    ++</p>
    ++<p clase="note">
    ++  <strong>Note:</strong> The symbol &#10008; is used in the table below to indicate
    ++  quality criteria that are not required for the corresponding Wear version.
    + </p>
    + 
    ++<p class="table-caption"><strong>Table 2</strong>. Visual criteria.
    ++</p>
    + <table>
    + 
    + <tr>
    +@@ -259,6 +352,12 @@ data-sortorder="-timestamp" data-cardsizes="6x2" data-maxresults="6">
    +   <th>
    +     Description
    +   </th>
    ++  <th>
    ++    Wear 1.0
    ++  </th>
    ++  <th>
    ++    Wear 2.0
    ++  </th>
    + </tr>
    + 
    + <tr>
    +@@ -277,6 +376,12 @@ data-sortorder="-timestamp" data-cardsizes="6x2" data-maxresults="6">
    +       (<a href="{@docRoot}training/wearables/ui/layouts.html">Learn how</a>)
    +     </p>
    +   </td>
    ++  <td>
    ++    &#10004;
    ++  </td>
    ++  <td>
    ++    &#10004;
    ++  </td>
    + </tr>
    + 
    + <tr>
    +@@ -292,6 +397,13 @@ data-sortorder="-timestamp" data-cardsizes="6x2" data-maxresults="6">
    +       (<a href="{@docRoot}training/wearables/ui/layouts.html">Learn how</a>)
    +     </p>
    +   </td>
    ++  <td>
    ++    &#10004;
    ++  </td>
    ++  <td>
    ++    &#10004;
    ++  </td>
    ++
    + </tr>
    + 
    + <tr>
    +@@ -304,6 +416,12 @@ data-sortorder="-timestamp" data-cardsizes="6x2" data-maxresults="6">
    +       (<a href="{@docRoot}design/wear/style.html#Typography">Learn how</a>)
    +     </p>
    +   </td>
    ++  <td>
    ++    &#10004;
    ++  </td>
    ++  <td>
    ++    &#10004;
    ++  </td>
    + </tr>
    + 
    + <tr>
    +@@ -320,6 +438,12 @@ data-sortorder="-timestamp" data-cardsizes="6x2" data-maxresults="6">
    +       (<a href="{@docRoot}guide/topics/manifest/intent-filter-element.html">Learn how</a>)
    +     </p>
    +   </td>
    ++  <td>
    ++    &#10004;
    ++  </td>
    ++  <td>
    ++    &#10008;
    ++  </td>
    + </tr>
    + 
    + <tr>
    +@@ -336,6 +460,12 @@ data-sortorder="-timestamp" data-cardsizes="6x2" data-maxresults="6">
    +       (<a href="{@docRoot}design/wear/patterns.html#Countdown">Learn how</a>)
    +     </p>
    +   </td>
    ++  <td>
    ++    &#10004;
    ++  </td>
    ++  <td>
    ++    &#10004;
    ++  </td>
    + </tr>
    + 
    + <tr>
    +@@ -350,6 +480,12 @@ data-sortorder="-timestamp" data-cardsizes="6x2" data-maxresults="6">
    +       (<a href="{@docRoot}design/wear/style.html#Assets">Learn how</a>)
    +     </p>
    +   </td>
    ++  <td>
    ++    &#10004;
    ++  </td>
    ++  <td>
    ++    &#10008;
    ++  </td>
    + </tr>
    + 
    + <tr>
    +@@ -363,6 +499,12 @@ data-sortorder="-timestamp" data-cardsizes="6x2" data-maxresults="6">
    +       (<a href="{@docRoot}training/wearables/notifications/creating.html#ActionButtons">Learn how</a>)
    +     </p>
    +   </td>
    ++  <td>
    ++    &#10004;
    ++  </td>
    ++  <td>
    ++    &#10004;
    ++  </td>
    + </tr>
    + 
    + <tr>
    +@@ -375,6 +517,12 @@ data-sortorder="-timestamp" data-cardsizes="6x2" data-maxresults="6">
    +       (<a href="{@docRoot}design/wear/style.html#Branding">Learn how</a>)
    +     </p>
    +   </td>
    ++  <td>
    ++    &#10004;
    ++  </td>
    ++  <td>
    ++    &#10008;
    ++  </td>
    + </tr>
    + 
    + <tr>
    +@@ -387,6 +535,12 @@ data-sortorder="-timestamp" data-cardsizes="6x2" data-maxresults="6">
    +       (<a href="{@docRoot}training/wearables/notifications/creating.html#AddWearableFeatures">Learn how</a>)
    +     </p>
    +   </td>
    ++  <td>
    ++    &#10004;
    ++  </td>
    ++  <td>
    ++    &#10008;
    ++  </td>
    + </tr>
    + 
    + <tr>
    +@@ -403,6 +557,12 @@ data-sortorder="-timestamp" data-cardsizes="6x2" data-maxresults="6">
    +       (<a href="https://support.google.com/googleplay/android-developer/answer/1078870?hl=en">Learn how</a>)
    +     </p>
    +   </td>
    ++  <td>
    ++    &#10004;
    ++  </td>
    ++  <td>
    ++    &#10004;
    ++  </td>
    + </tr>
    + 
    + 
    +diff --git a/docs/html/distribute/index.jd b/docs/html/distribute/index.jd
    +index 424983d..3d75758 100644
    +--- a/docs/html/distribute/index.jd
    ++++ b/docs/html/distribute/index.jd
    +@@ -9,16 +9,6 @@ page.metaDescription=The most visited store in the world for Android apps. Cloud
    + 
    + @jd:body
    + 
    +-<script>
    +-  $(document).ready(function() {
    +-    if (useUpdatedTemplates) {
    +-      $("#useUpdatedTemplates").css("display","block");
    +-    } else {
    +-      $("#useOldTemplates").css("display","block");
    +-    }
    +-  })
    +-</script>
    +-
    + <div class="dac-hero-carousel" data-carousel-query="collection:distribute/landing/carousel">
    + </div>
    + 
    +@@ -28,18 +18,7 @@ page.metaDescription=The most visited store in the world for Android apps. Cloud
    +   </a>
    + </div>
    + 
    +-<section id="useOldTemplates" style="display:none" class="dac-section dac-gray dac-small" id="latest"><div class="wrap">
    +-  <h2 class="norule">Latest</h2>
    +-  <div class="resource-widget resource-flow-layout col-16"
    +-      data-query="type:youtube+tag:googleplay+tag:developerstory+tag:featured, type:blog+tag:googleplay+tag:distribute+tag:featured"
    +-      data-sortOrder="-timestamp"
    +-      data-cardSizes="6x6"
    +-      data-maxResults="3"
    +-      data-items-per-page="6"
    +-      data-initial-results="3"></div>
    +-</div></section>
    +-
    +-<section id="useUpdatedTemplates" style="display:none" class="dac-section dac-gray dac-small" id="latest"><div class="wrap">
    ++<section class="dac-section dac-gray dac-small" id="latest"><div class="wrap">
    +   <h2 class="norule">Latest</h2>
    + 
    +   <div class="dac-filter dac-filter-section" data-filter="#latest-resources">
    +diff --git a/docs/html/distribute/stories/apps.jd b/docs/html/distribute/stories/apps.jd
    +index 76e9f5a..47f4f7f 100644
    +--- a/docs/html/distribute/stories/apps.jd
    ++++ b/docs/html/distribute/stories/apps.jd
    +@@ -25,8 +25,7 @@ page.metaDescription=How app developers are making use of localization, tablet f
    +   <h2 class="norule">Articles</h2>
    + 
    +   <div class="resource-widget resource-flow-layout col-16"
    +-      data-query="type:distribute+tag:developerstory+tag:apps"
    +-      data-sortOrder="-timestamp"
    ++      data-query="collection:distribute/stories/apps/docs"
    +       data-cardSizes="6x6"
    +       data-items-per-page="15"
    +       data-initial-results="6"></div>
    +diff --git a/docs/html/distribute/stories/apps/condenast-shopping.jd b/docs/html/distribute/stories/apps/condenast-shopping.jd
    +new file mode 100644
    +index 0000000..37c2b1f
    +--- /dev/null
    ++++ b/docs/html/distribute/stories/apps/condenast-shopping.jd
    +@@ -0,0 +1,76 @@
    ++page.title=Glamour.de Connects Offline and Online Shopping Experiences with Google Play Billing
    ++page.metaDescription=Cond&eacute; Nast improves features on its Glamour app.
    ++page.tags="developerstory", "apps", "googleplay"
    ++page.image=images/cards/distribute/stories/glamour.png
    ++page.timestamp=null
    ++
    ++@jd:body
    ++
    ++
    ++<h3>Background</h3>
    ++
    ++<div class="figure">
    ++  <img src="{@docRoot}images/distribute/stories/glamour-icon.png" />
    ++</div>
    ++
    ++<p>
    ++  Glamour is one of the main
    ++  <a class="external-link"
    ++  href="https://play.google.com/store/apps/developer?id=Cond%C3%A9%20Nast%20Verlag%20GmbH&hl=en">
    ++  Cond&eacute; Nast</a> traditional brands. Every year, Glamour hosts a
    ++  successful shopping event called
    ++  <a class="external-link"
    ++  href="https://play.google.com/store/apps/details?id=de.glamour.android&e=-EnableAppDetailsPageRedesign">
    ++  <em>GLAMOUR Shopping-Week</em></a> in Germany, Austria, and Switzerland.
    ++  This event has always been print-focused, as readers received a shopping
    ++  card with the magazine to redeem discounts in selected shops, both offline
    ++  and online, for one week.
    ++</p>
    ++
    ++<p>
    ++  In March 2016, Glamour digitized this experience.
    ++</p>
    ++
    ++<h3>What they did</h3>
    ++
    ++<p>
    ++  To make the most of <em>GLAMOUR Shopping-Week</em>, Cond&eacute; Nast relaunched the
    ++  <a class="external-link"
    ++  href="https://play.google.com/store/apps/details?id=de.condenast.glamourde&e=-EnableAppDetailsPageRedesign">
    ++  GLAMOUR app</a> with a more appealing design and an improved user experience:
    ++<ul>
    ++  <li>The main features updated for the shopping week included a shop finder, online offers, and
    ++      a digital shopping card.</li>
    ++  <li>The current e-paper magazine was made available through the app and sold via Google Play
    ++      Billing.</li>
    ++  <li>They offered readers the in-app purchase of digital shopping cards and activation codes
    ++      through Google Play Billing. Readers can activate digital shopping cards via in-app
    ++      purchases or with the print shopping card activation code.</li>
    ++  <li>The online and offline shopping experience was also supported by online shopping discount
    ++      codes in the app or offline through the shop finder.</li>
    ++</ul>
    ++</p>
    ++
    ++<h3>Results</h3>
    ++
    ++<p>
    ++  The offline and online combination resulted in positive engagement both in terms of app
    ++  installs and sales:
    ++<ul>
    ++  <li>There were 130,000 new app downloads, and 100,000 users enabled location access to use
    ++      the shop finder.</li>
    ++  <li><strong>Sessions increased by 140%</strong> compared to previous weeks. Session length
    ++      doubled and <strong>the number of active users grew by five times</strong>.</li>
    ++  <li>12,000 in-app purchases were generated, increasing general e-paper sales by six times,
    ++      which resulted in <strong>an increase in total magazine circulation</strong>.</li>
    ++  <li>The digital shopping card was shown more than 200,000 times to redeem offers in shops.</li>
    ++</ul>
    ++</p>
    ++
    ++<h3>Get started</h3>
    ++
    ++<p>
    ++  Find out more about
    ++  <a href="https://developer.android.com/google/play/billing/billing_overview.html">
    ++  in-app purchases</a>.
    ++</p>
    +\ No newline at end of file
    +diff --git a/docs/html/distribute/stories/apps/drupe-communications.jd b/docs/html/distribute/stories/apps/drupe-communications.jd
    +new file mode 100644
    +index 0000000..4284077
    +--- /dev/null
    ++++ b/docs/html/distribute/stories/apps/drupe-communications.jd
    +@@ -0,0 +1,98 @@
    ++page.title=drupe Launches Android First and Finds Global Success with Beta Testing
    ++page.metaDescription=Drupe uses beta testing to increase its global reach.
    ++page.tags="developerstory", "apps", "googleplay"
    ++page.image=images/cards/distribute/stories/drupe.jpg
    ++page.timestamp=1468901832
    ++
    ++@jd:body
    ++
    ++<div class="figure">
    ++  <img src="{@docRoot}images/distribute/stories/drupe-icon.png" />
    ++</div>
    ++
    ++<h3>
    ++  Background
    ++</h3>
    ++
    ++<p>
    ++  In 2015, <a class="external-link" href=
    ++  "https://play.google.com/store/apps/dev?id=8486231504544197967">
    ++  drupe mobile</a>, founded by Assaf Ziv and Barak Witkowski, launched the
    ++  <a class="external-link" href=
    ++  "https://play.google.com/store/apps/details?id=mobi.drupe.app">drupe app</a>
    ++  on Android first. With a unique, people-first approach, their communications
    ++  app is focused on reinventing the way people use their phone to do basic
    ++  actions. By constantly improving and expanding their cross-app
    ++  functionality, the app is used globally and was recently awarded Google
    ++  Play’s Editor’s Choice recognition.
    ++</p>
    ++
    ++<h3>
    ++  What they did
    ++</h3>
    ++
    ++<dl>
    ++  <dt><strong>Android openness</strong></dt>
    ++  <dd>From the start, drupe knew Android was their ideal mobile platform.
    ++  <em>"Thanks to the openness of the system, we can build a truly native
    ++  experience on Android. The real way to supply a people-centric experience
    ++  requires such an openness, not always existing on other platforms,"</em>
    ++  said Barak Witkowski, co-founder and CEO of drupe. Key to their innovative
    ++  approach, drupe uses the current context of the user to show them the
    ++  right contacts and actions to optimize the drupe experience.</dd>
    ++
    ++<div class="figure">
    ++  <img src="{@docRoot}images/distribute/stories/drupe-screenshot.png">
    ++</div>
    ++
    ++  <dt><strong>Beta testing</strong></dt>
    ++  <dd>They have a large community of 20,000 <em>druper</em> beta users on
    ++  Android, which has been critical to their success. To minimize risk and seek
    ++  feedback from valued users, the team built beta testing into their regular
    ++  development process. By having a dialogue with users worldwide, they are able
    ++  to gauge interest in new app versions, collect feature requests, and more.
    ++  This has helped the team achieve a 99.7% crash-free user ratio, as well
    ++  as verify new versions in real-life scenarios, on various devices, before
    ++  full launch.</dd>
    ++
    ++  <dt><strong>Going global</strong></dt>
    ++  <dd>With initial focus on building a high quality app, drupe then set out
    ++  to take advantage of Android’s global scale. Key to their international
    ++  growth, the app is now translated in 17 languages, and the store listing
    ++  page is available in 28 languages. This led to an increase in conversion
    ++  and retention rates. Additionally, when entering India, the team noticed
    ++  several user reviews requesting integration with a specific messaging app
    ++  widely used in the Indian market. Through a combination of this integration,
    ++  adding Hindi language translation, and other new features, drupe saw improved
    ++  performance. In six months, <strong>daily active users increased 300%, and
    ++  actions per average daily user increased 25% in the Indian
    ++  market</strong>.</dd>
    ++</dl>
    ++
    ++<h3>
    ++  Results
    ++</h3>
    ++
    ++<p>
    ++  Drupe’s focus on innovation and building a truly contextual and intuitive
    ++  app proved to be a model of success for attaining growth in both engagement
    ++  and new global reach. The team has continued to increase its relevance
    ++  through feedback loops and feature adoptions. <strong>This has led to 700%
    ++  growth in daily active users, and 550% growth in number of interactions
    ++  triggered via drupe</strong> in the past six months. The team is focused on
    ++  enhancing their recommendation engine to add even more contextual abilities
    ++  for their users while continuing to grow a successful business on Google
    ++  Play.
    ++</p>
    ++
    ++<h3>
    ++  Get started
    ++</h3>
    ++
    ++<p>
    ++  Learn more about
    ++  <a href="{@docRoot}distribute/engage/beta.html">beta testing</a>
    ++  and find out how to
    ++  <a href="{@docRoot}distribute/tools/localization-checklist.html">
    ++  localize your app</a> to create a high-quality experience for global users.
    ++</p>
    +\ No newline at end of file
    +diff --git a/docs/html/distribute/stories/apps/economist-espresso.jd b/docs/html/distribute/stories/apps/economist-espresso.jd
    +new file mode 100644
    +index 0000000..441393b
    +--- /dev/null
    ++++ b/docs/html/distribute/stories/apps/economist-espresso.jd
    +@@ -0,0 +1,70 @@
    ++page.title=The Economist Espresso Increases Ratings by Launching Rating Requests
    ++page.metaDescription=The Economist improves ratings through user participation.
    ++page.tags="developerstory", "apps", "googleplay"
    ++page.image=images/cards/distribute/stories/economist-espresso.png
    ++page.timestamp=null
    ++
    ++@jd:body
    ++
    ++
    ++<h3>Background</h3>
    ++
    ++<div class="figure">
    ++  <img src="{@docRoot}images/distribute/stories/economist-espresso-icon.png" />
    ++</div>
    ++
    ++<p>
    ++  <a class="external-link" href="https://play.google.com/store/apps/details?id=uk.co.economist">
    ++  The Economist</a> launched the
    ++  <a class="external-link" href="https://play.google.com/store/apps/details?id=com.economist.darwin">
    ++  Espresso</a> app in November 2014. Espresso offers a morning briefing from the editors of The
    ++  Economist, six days a week. Delivered to readers’ mobile phones first thing in the morning, it
    ++  provides an overview of the global agenda for the coming day. It informs readers about what to
    ++  look out for in business, finance, and politics, and most importantly, what to make of it.
    ++</p>
    ++
    ++<p>
    ++  While the app received a lot of positive feedback from users on traditional customer support
    ++  channels, it received less feedback through direct app reviews. The Economist decided to run
    ++  tests to increase app reviews, resulting in improved ratings.
    ++
    ++<h3>What they did</h3>
    ++
    ++<p>
    ++  In April 2016, The Economist began testing to determine if asking for reviews would improve
    ++  user participation. They introduced rating requests into the app whereby users received a
    ++  notification asking them to rate the app while using it.
    ++</p>
    ++
    ++<p>
    ++  They prompted only users who had fully experienced the app, notifying those who had read more
    ++  than 25 articles after using it for more than a week. The prompt text was branded:
    ++  <em>Are you enjoying the Economist Espresso?</em> Upon clicking <em>yes</em>, the user was
    ++  taken to the Google Play store to review and rate the app.
    ++
    ++<h3>Results</h3>
    ++
    ++<p>
    ++  By capturing readers’ feedback in the Play store, The Economist was able to share the goodwill
    ++  and positive sentiment, <strong>further increasing its star rating and the number of app
    ++  installs</strong>.
    ++</p>
    ++
    ++<p>
    ++  After just one week following the launch of rating requests, The Espresso app's star rating
    ++  increased by 5%, with <strong>the average number of ratings received growing 40 times</strong>.
    ++</p>
    ++
    ++<h3>Get started</h3>
    ++
    ++<p>
    ++  Find out more about
    ++  <a class="external-link" href="https://support.google.com/googleplay/android-developer/answer/138230">
    ++  ratings and reviews</a>.
    ++</p>
    ++
    ++<p>
    ++  Get best practices for news publishers in
    ++  <a class="external-link" href="https://play.google.com/store/books/details/Google_Inc_The_News_Publisher_Playbook_for_Android?id=O7T3CwAAQBAJ&hl=en_GB&e=-EnableAppDetailsPageRedesign">
    ++  The News Publisher Playbook (for Android development)</a>.
    ++</p>
    +\ No newline at end of file
    +diff --git a/docs/html/distribute/stories/apps/expressen-sports.jd b/docs/html/distribute/stories/apps/expressen-sports.jd
    +new file mode 100644
    +index 0000000..b53cb62
    +--- /dev/null
    ++++ b/docs/html/distribute/stories/apps/expressen-sports.jd
    +@@ -0,0 +1,57 @@
    ++page.title=Expressen Sport App Improves Content Engagement with New Onboarding and Navigation
    ++page.metaDescription=Expressen enhances their Sport app.
    ++page.tags="developerstory", "apps", "googleplay"
    ++page.image=images/cards/distribute/stories/expressen-sport.png
    ++page.timestamp=null
    ++
    ++@jd:body
    ++
    ++
    ++<h3>Background</h3>
    ++
    ++<div class="figure">
    ++  <img src="{@docRoot}images/distribute/stories/expressen-icon.png" />
    ++</div>
    ++
    ++<p>
    ++  In January 2016,
    ++  <a class="external-link" href="https://play.google.com/store/apps/details?id=se.expressen.launcher&hl=en">
    ++  Expressen</a> launched a new sports app to reach sports enthusiasts directly
    ++  and to better optimize the app for sports content. They decided to analyze
    ++  users' behavior by looking at user paths in existing sports content,
    ++  combined with user research and testing various prototypes with real users.
    ++  They found that readers have different needs and preferences. For example,
    ++  some people like a specific sport, league, or player that others have no
    ++  interest in. Following these results, they integrated two main changes to
    ++  increase appeal to different types of readers.
    ++</p>
    ++
    ++<h3>What they did</h3>
    ++
    ++<p>
    ++  Expressen introduced a new onboarding flow that allows users to select the
    ++  type of push notifications they want to subscribe to. They also implemented
    ++  contextual navigation where the top header navigational links change,
    ++  showing the most relevant links to the reader at that moment in time. For
    ++  example, if you're reading about football, relevant links about that sport
    ++  are displayed.
    ++</p>
    ++
    ++<h3>Results</h3>
    ++
    ++<p>
    ++  After the new release of the app, <strong>results showed a higher opt-in
    ++  rate for push notifications in the Sport app (+16.9%)</strong> compared to
    ++  their main app, and content consumption increased +7% for page views and
    ++  +8.3% for video views.
    ++</p>
    ++
    ++<h3>Get started</h3>
    ++
    ++<p>
    ++  Learn more about the
    ++  <a href="https://developer.android.com/training/tv/playback/onboarding.html?hl=mk">
    ++  user onboarding flow</a> and find out how to
    ++  <a href="https://developer.android.com/design/patterns/navigation.html">
    ++  implement contextual navigation</a>.
    ++</p>
    +\ No newline at end of file
    +diff --git a/docs/html/distribute/stories/apps/lifesum-health.jd b/docs/html/distribute/stories/apps/lifesum-health.jd
    +new file mode 100644
    +index 0000000..2d3f203
    +--- /dev/null
    ++++ b/docs/html/distribute/stories/apps/lifesum-health.jd
    +@@ -0,0 +1,60 @@
    ++page.title=Lifesum Doubles Retention of Google Fit Users Following Integration on Android
    ++page.metaDescription=Lifesum integrates Google Fit into their app.
    ++page.tags="developerstory", "apps", "googleplay"
    ++page.image=images/cards/distribute/stories/lifesum.png
    ++page.timestamp=null
    ++
    ++@jd:body
    ++
    ++
    ++<h3>Background</h3>
    ++
    ++<div class="figure">
    ++  <img src="{@docRoot}images/distribute/stories/lifesum-icon.png" />
    ++</div>
    ++
    ++<p>
    ++  <a class="external-link" href="https://play.google.com/store/apps/details?id=com.sillens.shapeupclub">
    ++  Lifesum</a> is a health and fitness app from Sweden that was launched on Android in 2012.
    ++  Since then, the app has had more than five million installs on Android, and Lifesum collaborated
    ++  with Google for the launch of <a class="external-link" href="http://www.google.com/fit/">
    ++  Google Fit</a> in 2014. Google Fit soon became a key component of user activity outside the
    ++  app and has enabled Lifesum to scale partner integrations, accelerate development cycle, and
    ++  increase user satisfaction and engagement.
    ++</p>
    ++
    ++<h3>What they did</h3>
    ++
    ++<p>
    ++  Lifesum integrated Google Fit APIs to gather more insightful data, leading to a shift in
    ++  focus from simply gathering large amounts of user data to actual analysis of it. Google Fit has
    ++  also made direct integrations with partners much easier to scale and sometimes even
    ++  unnecessary, and has largely reduced app development time. Lifesum used findings from the
    ++  integration to launch their second app, <em>Movesum</em>, a step-counter app that imports steps
    ++  and calories and displays the information in a fun way. Thanks to the integration, the app was
    ++  developed in just two weeks.
    ++</p>
    ++
    ++<h3>Results</h3>
    ++
    ++<p>
    ++  Lifesum’s users now actively request integration with Google Fit, resulting in an improvement
    ++  in the app's ratings and reviews on the Google Play store. Engagement is also much higher for
    ++  Google Fit-connected users, whose <strong>retention rate is twice that of other Android
    ++  users</strong>. User retention on Android is 5-10% better than on other platforms.
    ++</p>
    ++
    ++<p>
    ++  Joakim Hammer, Android developer at Lifesum, says "Google Fit is our infrastructure for
    ++  integrating with other apps. It's great for the user as it increases the trustworthiness of the
    ++  data. Personally, it’s been a great experience leading the integration. The implementation was
    ++  fast and easy, and it has helped us with everything from product development and user
    ++  engagement, to partnerships."
    ++</p>
    ++
    ++<h3>Get started</h3>
    ++
    ++<p>
    ++  Find out more about <a class="external-link" href="https://developers.google.com/fit/">
    ++  The Google Fit SDK</a>.
    ++</p>
    +\ No newline at end of file
    +diff --git a/docs/html/distribute/stories/apps/noom-health.jd b/docs/html/distribute/stories/apps/noom-health.jd
    +new file mode 100644
    +index 0000000..c99efac
    +--- /dev/null
    ++++ b/docs/html/distribute/stories/apps/noom-health.jd
    +@@ -0,0 +1,115 @@
    ++page.title=Noom Grows International Revenue by 80% Through Localization on Google Play
    ++page.metaDescription=Noom increases revenue by localizing their app.
    ++page.tags="developerstory", "apps", "googleplay"
    ++page.image=images/cards/distribute/stories/noom.jpg
    ++page.timestamp=1468901832
    ++
    ++@jd:body
    ++
    ++<div class="figure">
    ++  <img src="{@docRoot}images/distribute/stories/noom-icon.png" />
    ++</div>
    ++
    ++<h3>
    ++  Background
    ++</h3>
    ++
    ++<p>
    ++  With a mission to help people live healthier lives,
    ++  <a class="external-link" href=
    ++  "https://play.google.com/store/apps/developer?id=Noom+Inc.">Noom</a> guides
    ++  their users through behavior change programs to create lifestyle habits and
    ++  target global health challenges. Available initially on Google Play,
    ++  Android first and Noom have achieved success expanding to international
    ++  markets, taking advantage of the broad reach of Android.
    ++</p>
    ++
    ++<h3>
    ++  What they did
    ++</h3>
    ++
    ++<p>
    ++  Launching first in the US, Noom created a series of programs tailored to
    ++  their users’ specific <a class="external-link" href=
    ++  "https://play.google.com/store/apps/details?id=com.wsl.noom">
    ++  health goals</a>. Key to their approach is offering a holistic solution,
    ++  including simple personalized tasks, progress tracking, meal feedback, and
    ++  support from both personal coaches and peers. The team has a strategic
    ++  approach to expanding their user base globally. Noom localized their app to
    ++  better connect with users in the following areas:
    ++</p>
    ++
    ++<ul>
    ++  <li><strong>Localized product</strong>
    ++    <ul style="list-style: none;">
    ++    <li>In addition to translating their app to five languages and their store
    ++      listing page to 11 languages, Noom conducted extensive analysis to
    ++      determine the right financial model tailored to each international
    ++      market. This included evaluation of their competitive landscape and
    ++      local health and wellness spending behavior, in addition to running
    ++      pricing experiments to determine the optimal offering between
    ++      subscriptions, IAPs, or a premium app.</li>
    ++    </ul>
    ++  </li>
    ++
    ++  <li><strong>Localized cuisines</strong>
    ++    <ul style="list-style: none;">
    ++    <li>When Noom started researching the Korean, Japanese, German, and Latin
    ++      American markets, they immediately focused on localizing their food
    ++      database. Using a combination of local food editors, existing food
    ++      databases, and user suggestions, their app now includes local cuisine
    ++      and popular packaged food brands, offering a simpler and more
    ++      comprehensive experience for users.</li>
    ++    </ul>
    ++  </li>
    ++
    ++  <li><strong>Localized coaches</strong>
    ++    <ul style="list-style: none;">
    ++    <li>Hiring local coaches not only removed language barriers, but also
    ++      reduced response times as they are located within the same time zone
    ++      as their users. Using various notification types, Noom has increased
    ++      user engagement by three to four times.</li>
    ++    </ul>
    ++  </li>
    ++</ul>
    ++
    ++<img src="{@docRoot}images/distribute/stories/noom-screenshot.png">
    ++  <p class="img-caption">
    ++  <strong>Figure 1.</strong> German Play Store listing page, Korean recipes,
    ++  and Japanese meal plan
    ++  </p>
    ++
    ++<h3>
    ++  Results
    ++</h3>
    ++
    ++<p>
    ++  <em>"Android's global focus and great localization tooling made the decision
    ++  to go global much easier. Localization to new markets has been a consistent
    ++  growth driver at Noom,"</em> said Artem Petakov, co-founder and President
    ++  at Noom.
    ++</p>
    ++
    ++<p>
    ++  Over the last three years, Noom’s localization efforts led to an <strong>80%
    ++  increase in international revenue growth on Android</strong>. In Japan
    ++  alone, <strong>revenue increased more than 480%</strong> during the same
    ++  time period. To identify future expansion opportunities, the team looks
    ++  towards countries with strong Android penetration and install growth
    ++  using the English product and plans to apply their localization methods to
    ++  achieve even greater success.
    ++</p>
    ++
    ++<h3>
    ++  Get started
    ++</h3>
    ++
    ++<p>
    ++  Learn more about <a class="external-link" href=
    ++  "https://material.google.com/patterns/notifications.html">Notifications</a>,
    ++  and find out about
    ++  <a href="{@docRoot}distribute/tools/localization-checklist.html">
    ++  app localization</a> and how to
    ++  <a href="{@docRoot}distribute/users/expand-to-new-markets.html">
    ++  Expand Into New Markets</a>.
    ++</p>
    +\ No newline at end of file
    +diff --git a/docs/html/distribute/stories/games.jd b/docs/html/distribute/stories/games.jd
    +index daaac0d..cd31aae 100644
    +--- a/docs/html/distribute/stories/games.jd
    ++++ b/docs/html/distribute/stories/games.jd
    +@@ -25,8 +25,7 @@ page.metaDescription=How game studios are using Google Play game services to del
    +   <h2 class="norule">Articles</h2>
    + 
    +   <div class="resource-widget resource-flow-layout col-16"
    +-      data-query="type:distribute+tag:developerstory+tag:games"
    +-      data-sortOrder="-timestamp"
    ++      data-query="collection:distribute/stories/games/docs"
    +       data-cardSizes="6x6"
    +       data-items-per-page="15"
    +       data-initial-results="6"></div>
    +diff --git a/docs/html/distribute/stories/games/animoca-star-girl.jd b/docs/html/distribute/stories/games/animoca-star-girl.jd
    +new file mode 100644
    +index 0000000..a38eed2
    +--- /dev/null
    ++++ b/docs/html/distribute/stories/games/animoca-star-girl.jd
    +@@ -0,0 +1,89 @@
    ++page.title=Star Girl Increases In-App Purchases by 3.5X Through More Flexible Minimum Pricing on Google Play
    ++page.metaDescription=Star Girl Increases In-App Purchases by 3.5X.
    ++page.tags="developerstory", "games", "googleplay", "google play"
    ++page.image=images/cards/distribute/stories/animoca.jpg
    ++
    ++@jd:body
    ++
    ++<style type="text/css">
    ++  span.positive{
    ++    color:green;
    ++    font-size: 125%;
    ++    font-weight:bold;">
    ++  }
    ++  span.negative{
    ++    color:red;
    ++    font-size: 125%;
    ++    font-weight:bold;">
    ++  }
    ++</style>
    ++
    ++<h3>Background</h3>
    ++
    ++<div class="figure">
    ++  <img src="{@docRoot}images/distribute/stories/animoca-logo.png" />
    ++</div>
    ++
    ++<p>
    ++  <a class="external-link"
    ++  href="https://play.google.com/store/apps/details?id=com.animoca.google.starGirl&hl=en&e=-EnableAppDetailsPageRedesign">
    ++  Star Girl</a> is a series of SIM/role playing games published by <a class="external-link"
    ++  href="https://play.google.com/store/apps/dev?id=8271704752057011334&hl=en&e=-EnableAppDetailsPageRedesign">
    ++  Animoca</a>, a Hong Kong based game developer. The Star Girl series has more than 70 million
    ++  downloads and is localized in 18 languages. With a fast-growing user base in markets
    ++  including SEA, India, and Latin America, Animoca is exploring ways to effectively increase
    ++  monetization with a localized pricing strategy.
    ++</p>
    ++
    ++<h3>What they did</h3>
    ++
    ++<p>
    ++ Following the introduction of
    ++ <a class="external-link" href="http://android-developers.blogspot.com/2015/11/minimum-purchase-price-for-apps-and-in.html">
    ++ more flexible minimum pricing</a> in November 2015, Animoca took the opportunity to test
    ++ sachet pricing models across Thailand, Malaysia, Philippines, Indonesia, Brazil, and Russia:
    ++</p>
    ++
    ++<p>
    ++ <img src="{@docRoot}images/distribute/stories/animoca-flow.jpg" />
    ++</p>
    ++
    ++<p>
    ++ Animoca created a new sachet SKU, which offered 100 diamonds and 5,000 coins, at the new lower
    ++ minimum price available in these markets. The new SKU is approximately 60% cheaper than the
    ++ previous minimum-priced product and is accessible only through geo-targeted, in-game
    ++ banners in localized languages.
    ++</p>
    ++
    ++<h3>Results</h3>
    ++
    ++<div class="figure">
    ++ <img src="{@docRoot}images/distribute/stories/animoca-graph.jpg" />
    ++</div>
    ++
    ++<p>
    ++ The changes to minimum prices across these markets resulted in positive results, with the
    ++ number of transactions increasing 3.5X in the three months following launch.
    ++</p>
    ++
    ++<p>
    ++ Also, 90% of these transactions were first-time new buyers, half of which
    ++ followed up with purchases of regular packages. This helps to create a more sustainable revenue
    ++ impact, as described by Yusuf Goolamabbas, CTO of Animoca:
    ++</p>
    ++
    ++<p>
    ++ <em>“Sachet marketing has made IAPs more affordable to users in emerging markets. We are seeing
    ++ significant growth in new buyers as well as returning buyers and a positive impact on revenue in
    ++ emerging markets.”</em>
    ++</p>
    ++
    ++<h3>Get started</h3>
    ++
    ++<p>
    ++ <a class="external-link" href="https://support.google.com/googleplay/android-developer/answer/6334373?hl=en-GB">
    ++ Learn more about flexible minimum pricing</a> and
    ++ <a class="external-link" href="http://g.co/play/playbook-dac-writtenstudies-evergreen">
    ++ get the Playbook for Developers app</a> to grow your business and improve
    ++ monetization with Google Play.
    ++</p>
    +\ No newline at end of file
    +diff --git a/docs/html/distribute/stories/games/happy-labs-experiment.jd b/docs/html/distribute/stories/games/happy-labs-experiment.jd
    +new file mode 100644
    +index 0000000..e317e21
    +--- /dev/null
    ++++ b/docs/html/distribute/stories/games/happy-labs-experiment.jd
    +@@ -0,0 +1,105 @@
    ++page.title=Happy Labs Increases Installs by 32% on Google Play with Store Listing Experiments
    ++page.metaDescription=Happy Labs Increases Installs by 32%.
    ++page.tags="developerstory", "games", "googleplay", "google play"
    ++page.image=images/cards/distribute/stories/happylabs-logo.png
    ++
    ++@jd:body
    ++
    ++<style type="text/css">
    ++  span.positive{
    ++    color:green;
    ++    font-size: 125%;
    ++    font-weight:bold;">
    ++  }
    ++  span.negative{
    ++    color:red;
    ++    font-size: 125%;
    ++    font-weight:bold;">
    ++  }
    ++</style>
    ++
    ++<h3>Background</h3>
    ++
    ++<div class="figure">
    ++  <img src="{@docRoot}images/distribute/stories/happylabs-logo.png" />
    ++</div>
    ++
    ++<p>
    ++  <a class="external-link"
    ++  href="https://play.google.com/store/apps/dev?id=5211519071117278745&hl=en">
    ++  Happy Labs</a>, founded in 2012, is a successful game developer in Southeast Asia with 13
    ++  game titles and over 30 million downloads. Its flagship free-to-play virtual sim game,
    ++  <a class="external-link"
    ++  href="https://play.google.com/store/apps/dev?id=5211519071117278745&hl=en">Happy Pet Story</a>,
    ++  launched in February 2016 and is designed for female gamers of all ages.
    ++</p>
    ++
    ++<p>
    ++ Following the announcement of Store Listing Experiments in May, Happy Labs decided to test
    ++ variations of their game icon and screenshots to optimize their store listing.
    ++</p>
    ++
    ++<h3>What they did</h3>
    ++
    ++<p>
    ++ Happy Labs used the Store Listing Experiments feature in the Google Play Developer Console to
    ++ test three new variations of their new game icon. Encouraged by early results, they then
    ++ optimized the game screenshots displayed in their store listing.
    ++</p>
    ++
    ++<h3>Results</h3>
    ++
    ++<p>
    ++ The results showed that the new icon, <em>Sweet Bubbles</em> without a frame, outperformed
    ++ the initial <em>Mojo</em> icon and two other variants, with a 38.6% increase in installs:
    ++</p>
    ++
    ++<p>
    ++ <img src="{@docRoot}images/distribute/stories/happylabs-happy_pet_icon.png" />
    ++</p>
    ++
    ++<p>
    ++ Based on these findings, Happy Labs changed the Happy Pet Story icon to the new image globally
    ++ on Google Play.
    ++</p>
    ++
    ++<p>
    ++ Following the positive icon testing results, Happy Labs ran global store listing experiments
    ++ with a combination of screenshots from their store listing over a five week period. They then took
    ++ their best performing screenshots from the experiments and tested them across three specific
    ++ countries: Indonesia, Thailand, and Japan. The results showed an average increase of 19.87% in
    ++ installs.
    ++</p>
    ++
    ++<p>
    ++ Migrating from the original images to the variants shown in the following figure increased organic
    ++ installs in Thailand by 13.9%:
    ++</p>
    ++
    ++<p>
    ++ <img src="{@docRoot}images/distribute/stories/happylabs-variant.png" />
    ++</p>
    ++
    ++<p>
    ++ With the combination of both store listing experiments, Happy Pet Story saw an average increase of
    ++ 32% in month-on-month organic daily downloads globally, as described by Jeffrey Chee, CEO of Happy
    ++ Labs:
    ++</p>
    ++
    ++<p>
    ++ <em>“Store listing experiments have been an invaluable tool for us in optimizing our Play store
    ++ presence. I am really happy that we were able to get an uplift of 32% in organic installs with
    ++ minimal investment in terms of resources.”</em>
    ++</p>
    ++
    ++<h3>Get started</h3>
    ++
    ++<p>
    ++ Learn how to run
    ++ <a class="external-link" href="https://support.google.com/googleplay/android-developer/answer/6227309">
    ++ Store Listing Experiments</a> and read our best practices for
    ++ <a href="https://developer.android.com/distribute/users/experiments.html">
    ++ running successful experiments</a>. For more best practices on growing your business with Google
    ++ Play, <a class="external-link" href="http://g.co/play/playbook-dac-writtenstudies-evergreen">
    ++ get the Playbook for Developers app</a>.
    ++</p>
    +\ No newline at end of file
    +diff --git a/docs/html/distribute/stories/games/playlab-puzzles.jd b/docs/html/distribute/stories/games/playlab-puzzles.jd
    +new file mode 100644
    +index 0000000..ef1ccff
    +--- /dev/null
    ++++ b/docs/html/distribute/stories/games/playlab-puzzles.jd
    +@@ -0,0 +1,87 @@
    ++page.title=Playlab Increases Juice Cubes Conversions by 25% with Store Listing Experiments
    ++page.metaDescription=Playlab uses store listing experiments to refresh their Juice Cubes icon.
    ++page.tags="developerstory", "apps", "googleplay"
    ++page.image=images/cards/distribute/stories/playlab.jpg
    ++page.timestamp=1468901832
    ++
    ++@jd:body
    ++
    ++<div class="figure">
    ++  <img src="{@docRoot}images/distribute/stories/playlab-icon.png" />
    ++</div>
    ++
    ++<h3>
    ++  Background
    ++</h3>
    ++
    ++<p>
    ++  <a class="external-link" href=
    ++  "https://play.google.com/store/apps/dev?id=9190927840679184784&e=-EnableAppDetailsPageRedesign">
    ++  Playlab</a> is a game developer and publisher based in Hong Kong, with
    ++  production studios in Bangkok and Manila. Playlab apps include
    ++  <a class="external-link" href=
    ++  "https://play.google.com/store/apps/details?id=ppl.unity.JuiceCubesBeta">
    ++  Juice Cubes</a>, <a class="external-link" href=
    ++  "https://play.google.com/store/apps/details?id=ppl.unity.junglecubes">
    ++  Jungle Cubes</a>, and <a class="external-link" href=
    ++  "https://play.google.com/store/apps/details?id=ppl.cocos2dx.ranchrun&hl=en">
    ++  Ranch Run</a>.
    ++
    ++  Released in 2013, <a class="external-link" href=
    ++  "https://play.google.com/store/apps/details?id=ppl.unity.JuiceCubesBeta">
    ++  Juice Cubes</a> is a strategy puzzle game with over 25 million downloads
    ++  worldwide and over 100,000 five-star reviews on Google Play. The game has
    ++  gained success in Southeast Asian markets such as Indonesia and Thailand,
    ++  and in Western markets such as the US, Australia, the UK, and Canada.
    ++</p>
    ++
    ++<h3>
    ++  What they did
    ++</h3>
    ++
    ++<p>
    ++  As part of Juice Cubes’ content update in April 2016, Playlab decided to
    ++  refresh its Play Store icon and test whether different icons could increase
    ++  their conversion rate.
    ++</p>
    ++
    ++<p>
    ++  Playlab used the <em>Store Listing Experiments</em> feature on the Google
    ++  Play Developer Console to test three variations of their new game icon.
    ++</p>
    ++
    ++<h3>
    ++  Results
    ++</h3>
    ++
    ++<p>
    ++  Within three days of running the store listing experiment, Playlab saw
    ++  positive results which led them to make an informed decision to change the
    ++  current icon to the best-performing version. Variant C outperformed the
    ++  initial control icon and the two other variants, with a <strong>25% increase
    ++  in installs</strong>. One month after applying the best-performing icon,
    ++  Juice Cubes continued to see a 25% increase in the number of conversions
    ++  from store visitors who made organic installs.
    ++</p>
    ++
    ++<img src="{@docRoot}images/distribute/stories/playlab-screenshot.png">
    ++
    ++<p>
    ++  <em>"Google Play Store Listing Experiments offer a fast, easy, and free way
    ++  to do A/B testing on an icon. The data provided after each test helped us
    ++  to make a decision really quickly. The best part is the team no longer needs
    ++  so many resources to decide which icon to use because we can let the
    ++  users decide."</em> said Jakob Lykkegaard, CEO and co-founder of Playlab.
    ++</p>
    ++
    ++<h3>
    ++  Get started
    ++</h3>
    ++
    ++<p>
    ++  Learn how to use <a class="external-link" href=
    ++  "https://support.google.com/googleplay/android-developer/answer/6227309">
    ++  A/B testing</a> and find out more about how to run
    ++  <a href="{@docRoot}distribute/users/experiments.html">
    ++  store listing experiments</a> on Google Play.
    ++</p>
    +\ No newline at end of file
    +diff --git a/docs/html/distribute/stories/index.jd b/docs/html/distribute/stories/index.jd
    +index 1adc5ae..7d84ce4 100644
    +--- a/docs/html/distribute/stories/index.jd
    ++++ b/docs/html/distribute/stories/index.jd
    +@@ -4,16 +4,6 @@ page.metaDescription=Android developers, their apps, and their successes with An
    + 
    + @jd:body
    + 
    +-<script>
    +-  $(document).ready(function() {
    +-    if (useUpdatedTemplates) {
    +-      $("#useUpdatedTemplates").css("display","block");
    +-    } else {
    +-      $("#useOldTemplates").css("display","block");
    +-    }
    +-  })
    +-</script>
    +-
    + <p>Android developers, their apps, and their successes with Android and Google Play.</p>
    + 
    + <section class="dac-section dac-small" id="latest-apps"><div class="wrap">
    +@@ -31,11 +21,11 @@ page.metaDescription=Android developers, their apps, and their successes with An
    +   <h3 class="norule">Articles</h3>
    + 
    +   <div class="resource-widget resource-flow-layout col-16"
    +-      data-query="type:distribute+tag:developerstory+tag:apps"
    +-      data-sortOrder="-timestamp"
    ++      data-query="collection:distribute/stories/apps/docs"
    +       data-cardSizes="6x6"
    +       data-items-per-page="15"
    +       data-initial-results="6"></div>
    ++
    + </div></section>
    + 
    + <section class="dac-section dac-small" id="latest-games"><div class="wrap">
    +@@ -53,9 +43,9 @@ page.metaDescription=Android developers, their apps, and their successes with An
    +   <h3 class="norule">Articles</h3>
    + 
    +   <div class="resource-widget resource-flow-layout col-16"
    +-      data-query="type:distribute+tag:developerstory+tag:games"
    +-      data-sortOrder="-timestamp"
    ++      data-query="collection:distribute/stories/games/docs"
    +       data-cardSizes="6x6"
    +       data-items-per-page="15"
    +       data-initial-results="6"></div>
    ++
    + </div></section>
    +diff --git a/docs/html/distribute/tools/promote/brand.jd b/docs/html/distribute/tools/promote/brand.jd
    +index 409dfdd..ba2bed7 100644
    +--- a/docs/html/distribute/tools/promote/brand.jd
    ++++ b/docs/html/distribute/tools/promote/brand.jd
    +@@ -34,30 +34,31 @@ marketing for review.</p>
    +     <ul>
    +     <li>Android&trade; should have a trademark symbol the first time it appears in a creative.</li>
    +     <li>Android should always be capitalized and is never plural or possessive.</li>
    +-    <li>"Android" cannot be used in names of applications or accessory products,
    +-    including phones, tablets, TVs, speakers, headphones, watches, and other devices. Instead use "for Android".
    ++    <li>"Android", or anything confusingly similar to "Android", cannot be used
    ++    in names of applications or accessory products, including phones, tablets, TVs,
    ++    speakers, headphones, watches, and other devices. Instead, use "for Android".
    +       <ul>
    +-        <li><span style="color:red">Incorrect</span>: "Android MediaPlayer"</li>
    ++        <li><span style="color:red">Incorrect</span>: "Android MediaPlayer" or "Ndroid MediaPlayer"</li>
    +         <li><span style="color:green">Correct</span>: "MediaPlayer for Android"</li>
    +       </ul>
    +-      <p>If used with your logo, "for Android" should be no larger than 90% of your logo’s size.
    +-      First instance of this use should be followed by a TM symbol, "for Android&trade;".</p>
    ++      <p>If used with your logo, "for Android" should be no larger than 90% of your logo's size.
    ++      The first instance of this use should be followed by a TM symbol: "for Android&trade;".</p>
    +     </li>
    +-    <li>"Android TV", "Android Wear" and "Android Auto" may only be used to identify or market
    ++    <li>"Android TV", "Android Wear", and "Android Auto" may only be used to identify or market
    +       products or services with prior approval.  Use "for Android" or "with Android" for all
    +-      other Android-based products
    ++      other Android-based products.
    +       <ul>
    +         <li><span style="color:red">Incorrect</span>: "Android TV Streaming Stick",
    +           "Streaming Stick with Android TV"</li>
    +         <li><span style="color:green">Correct</span>: "Streaming Stick with Android"</li>
    +       </ul>
    +       <p>If used with your logo, "for Android" or "with Android" should be no larger than 90% of
    +-        your logo’s size. First instance of this use should be followed by a TM symbol,
    ++        your logo's size. The first instance of this use should be followed by a TM symbol:
    +         "for Android&trade;".</p>
    +     </li>
    +-    <li>Android may be used as a descriptor, as long as it is followed by a
    +-        proper generic term. (Think of "Android" as a term used in place of
    +-        "the Android platform.")
    ++    <li>Android may be used as a descriptor in text, as long as it is followed by a
    ++        proper generic term and is not the name of your product, app, or service.
    ++        Think of "Android" as a term used in place of "the Android platform."
    +       <ul>
    +         <li><span style="color:red">Incorrect</span>: "Android MediaPlayer" or "Android XYZ app"</li>
    +         <li><span style="color:green">Correct</span>: "Android features" or "Android applications"</li>
    +@@ -100,7 +101,9 @@ used according to terms described in the Creative Commons 3.0 Attribution Licens
    + <h4 style="clear:right">Android logo</h4>
    + 
    + <div style="float:right;width:210px;margin-left:30px;margin-top:-10px">
    +-  <img alt="" src="{@docRoot}images/brand/android_logo_no.png">
    ++  <img alt="" src="{@docRoot}images/brand/android_logo_no.png"
    ++    srcset="{@docRoot}images/brand/android_logo_no.png 1x,
    ++    {@docRoot}images/brand/android_logo_no_2x.png 2x">
    + </div>
    + 
    + <p>The Android logo may not be used.</p>
    +diff --git a/docs/html/distribute/users/build-buzz.jd b/docs/html/distribute/users/build-buzz.jd
    +index 7bc6f6c..65aa44a 100644
    +--- a/docs/html/distribute/users/build-buzz.jd
    ++++ b/docs/html/distribute/users/build-buzz.jd
    +@@ -28,9 +28,6 @@ page.tags="users, growth, promotion"
    +     Link to Your Apps in Google Play
    +   </h2>
    + 
    +-
    +-</div>
    +-
    + <p>
    +   After publishing your apps, you can take Android users directly to your
    +   app/games detail page on Google Play by <a href=
    +@@ -64,9 +61,6 @@ page.tags="users, growth, promotion"
    +     Use the Google Play Badge
    +   </h2>
    + 
    +-
    +-</div>
    +-
    + <div class="figure" style="margin:0 3em;">
    +   <img src="{@docRoot}images/gp-build-buzz-uplift-1.png">
    + </div>
    +diff --git a/docs/html/google/play/billing/billing_admin.jd b/docs/html/google/play/billing/billing_admin.jd
    +index 292cfcc..9936489 100644
    +--- a/docs/html/google/play/billing/billing_admin.jd
    ++++ b/docs/html/google/play/billing/billing_admin.jd
    +@@ -51,9 +51,9 @@ apps. You can sell an item using Google Play's in-app billing feature only if th
    + listed on an app's product list. Each app has its own product list; you cannot sell
    + items that appear on another app's product list.</p>
    + 
    +-<p>You can access an app's product list by opening the <strong>In-app Products</strong>
    ++<p>You can access an app's product list by opening the <em>In-app Products</em>
    + page for an app that is listed in your developer account. The link to the
    +-<strong>In-app Products</strong> page appears only if you have a Google payments merchant
    ++<em>In-app Products</em> page appears only if you have a Google payments merchant
    + account and the app's manifest includes the
    + <code>com.android.vending.BILLING</code> permission. For more information about this
    + permission, see <a href="{@docRoot}google/play/billing/billing_integrate.html#billing-permission">
    +@@ -73,7 +73,7 @@ uploading an unpublished draft version. This functionality is no longer
    + supported; instead, you must publish it to the alpha or beta distribution
    + channel. For more information, see <a
    + href="{@docRoot}google/play/billing/billing_testing.html#draft_apps">Draft Apps
    +-are No Longer Supported</a>.
    ++are No Longer Supported</a>.</p>
    + 
    + <p>In addition, an app package can have only one product list. If you create a product
    + list for an app, and you use the <a
    +@@ -82,8 +82,8 @@ more than one APK for that app, the product list applies to all APK versions tha
    + associated with the app listing. You cannot create individual product lists for each APK if
    + you are using the multiple APK feature.</p>
    + 
    +-<p>You can add items to a product list two ways: you can add items one at a time on the <strong>In-app
    +-Products</strong> page, or you can add a batch of items by importing the items from a
    ++<p>You can add items to a product list two ways: you can add items one at a time on the <em>In-app
    ++Products</em> page, or you can add a batch of items by importing the items from a
    + comma-separated values (CSV) file. Adding items one at a time is useful if your
    + app has only a few in-app items or you are adding only a few items to a
    + product list for testing purposes. The CSV file method is useful if your app has a large
    +@@ -100,14 +100,14 @@ number of in-app items.</p>
    + 
    + <ol>
    +   <li><a href="http://play.google.com/apps/publish">Log in</a> to your publisher account.</li>
    +-  <li>In the <strong>All applications</strong> panel, click on the
    +-  app name, then open the <strong>In-app Products</strong> page.</li>
    ++  <li>In the <em>All applications</em> panel, click on the
    ++  app name, then open the <em>In-app Products</em> page.</li>
    +   <li><p>Click <strong>Add new product</strong>. After you provide the product type and ID for the item you are
    +   selling, click <strong>Continue</strong>.</p>
    +   <dl>
    +       <dt>Product Type</dt>
    +       <dd>
    +-        <p>The product type can be <strong>Managed product</strong> or <strong>Subscription</strong>. You cannot
    ++        <p>The product type can be "Managed product" or "Subscription." You cannot
    +         change an item's product type after you create the item. For more information, see
    +         <a href="#billing-purchase-type">Choosing a Product Type</a>.</p>
    +         <p class="note"><strong>Note: </strong>For subscription items, you cannot change the
    +@@ -169,7 +169,7 @@ number of in-app items.</p>
    +         <p>You can also change prices for other currencies manually, but you can do
    +           this only if a currency is used in one of the target countries for your
    +           app. You can specify target countries for your app on the
    +-          <strong>Pricing &amp; Distribution</strong> page in the Google Play
    ++          <em>Pricing &amp; Distribution</em> page in the Google Play
    +           Developer Console.</p>
    +       </dd>
    +     </dl>
    +@@ -187,235 +187,412 @@ number of in-app items.</p>
    + 
    + <h3 id="billing-bulk-add">Adding a batch of items to a product list</h3>
    + 
    +-<p>To add a batch of items to a product list using a CSV file, you first need to create your CSV
    +-file. The data values that you specify in the CSV file represent the same data values you specify
    +-manually through the In-app Products UI (see <a href="#billing-form-add">Adding items one at a time
    +-to a product list</a>).
    ++<p>To add a batch of items to a product list using a CSV file, you first need to
    ++create your CSV file. The data values that you specify in the CSV file represent
    ++the options that you set when adding in-app products to a product list using the
    ++Google Play Developer Console UI. For more information about using this UI, see
    ++<a href="#billing-form-add">Adding items one at a time to a product list</a>.
    + 
    +-<p>If you are importing and exporting CSV files with in-app products, keep
    +-country-specific pricing in mind. If you use auto-fill, you can provide a
    +-tax-exclusive default price, and tax-inclusive prices will be auto-filled. If you
    +-do not use auto-fill, prices you provide must include tax.</p>
    ++<p class="note"><strong>Note:</strong> Batch upload of in-app product lists
    ++containing subscriptions is not supported. Also, when updating existing items in
    ++a batch upload, you cannot include changes to in-app products that are linked to
    ++a <a href="#pricing-template">pricing template</a>.</p>
    + 
    +-<p class="note"><strong>Note:</strong> Batch upload of product lists containing
    +-subscriptions is not supported. Also, when updating existing items in a batch
    +-upload, you cannot include changes to in-app products that are linked to a
    +-<a href="#pricing-template">pricing template</a>.</p>
    +-
    +-<p>To import the items that are specified in your CSV file, do the following:</p>
    ++<p>To import the in-app products that are specified in your CSV file, do the
    ++following:</p>
    + 
    + <ol>
    +-  <li><a href="http://play.google.com/apps/publish">Log in</a> to your publisher account.</li>
    +-  <li>In the <strong>All applications</strong> panel, select the app
    +-  name, then open the <strong>In-app Products</strong> page.</li>
    +-  <li>On the In-app Products List page, click <strong>Import/Export</strong>
    +-  &gt; <strong>Import in-app products from CSV file</strong>, then select your
    +-  CSV file.
    +-    <p>The CSV file must be on your local computer or on a local disk that is connected to your
    +-    computer.</p>
    +-  </li>
    +-  <li>Select the <strong>Overwrite</strong> checkbox if you want to overwrite existing items in
    +-  your product list.
    +-    <p>This option overwrites values of existing items only if the value of the <em>product_id</em>
    +-    in the CSV file matches the In-app Product ID for an existing item in the product list.
    +-    Overwriting doesn't delete items that are on a product list but not present in the CSV
    +-    file.</p>
    ++  <li>
    ++    <a href="http://play.google.com/apps/publish">Log in</a> to your
    ++    publisher account.
    ++  </li>
    ++  <li>In the <em>All applications</em> panel, select the app
    ++  name, then open the <em>In-app Products</em> page.</li>
    ++  <li>
    ++    <p>On the <em>In-app Products</em> page, click
    ++    <strong>Import/Export</strong> &gt; <strong>Import in-app products from CSV
    ++    file</strong> to open the <em>Import In-app Products</em> dialog.</p>
    ++  </li>
    ++  <li>
    ++    <p>
    ++      If you want to overwrite existing in-app products in your product list
    ++      during the import process, select the <strong>Overwrite existing
    ++      products</strong> checkbox.
    ++    </p>
    ++    <p>
    ++      This option overwrites values of existing items only if the value of the
    ++      <code>Product ID</code> in the CSV file matches the in-app product ID for
    ++      an existing in-app product in the product list. The overwriting process
    ++      doesn't delete in-app products that exist in a product list but aren't
    ++      included in the CSV file
    ++    </p>
    ++    <p class="note"><strong>Note: </strong>If you choose not to overwrite
    ++    existing items, the <code>Product ID</code> given to each item in the CSV
    ++    file must be different from any of the <code>Product ID</code> values
    ++    assigned to existing in-app products.
    ++    </p>
    ++  </li>
    ++  <li>
    ++    Select <strong>Browse files</strong>, then choose the CSV file that contains
    ++    the items you want to import. The CSV file must be stored locally.
    +   </li>
    + </ol>
    + 
    +-<p>You can also export an existing product list to a CSV file by clicking <strong>Export to CSV
    +-</strong> on the In-app Product List page. This is useful if you have manually added items to
    +-a product list and you want to start managing the product list through a CSV file.</p>
    ++<p>
    ++  You can also export an existing product list to a CSV file by clicking
    ++  <strong>Import/Export</strong> &gt; <strong>Export in-app products to CSV file
    ++  </strong> on the <em>In-app Products page</em>. This is useful if you have
    ++  used the UI to add in-app products to your app but you want to start managing
    ++  the product list through a CSV file instead.
    ++</p>
    + 
    + <h4 id="billing-bulk-format">Formatting batches of items</h4>
    + 
    +-<p>The CSV file uses commas (,) and semicolons (;) to separate data values.
    +-Commas are used to separate primary data values, and semicolons are used to
    +-separate subvalues. For example, the syntax for the CSV file is as follows:</p>
    ++<p>
    ++  The CSV file uses commas (<code>,</code>) and semicolons (<code>;</code>) to
    ++  separate data values. Commas are used to separate primary data values, and
    ++  semicolons are used to separate subvalues. Each item must appear entirely on a
    ++  single line within the CSV file.
    ++</p>
    ++<p>
    ++  When creating a CSV file that represents a list of items, you must specify the
    ++  CSV syntax on the first row, followed by the items themselves on subsequent
    ++  rows, as shown in the following example:
    ++</p>
    ++
    ++<pre class="no-pretty-print">
    ++Product ID,Published State,Purchase Type,Auto Translate,Locale; Title; Description,Auto Fill Prices,Price,Pricing Template ID
    ++basic_sleeping_potion,published,managed_by_android,false,en_US; Basic Sleeping Potion; Puts small creatures to sleep.; es_ES; Poción básica de dormir; Causa las criaturas pequeñas ir a dormir.,false,,4637138456024710495
    ++standard_sleeping_potion,published,managed_by_android,false,en_US; Standard Sleeping Potion; Puts all creatures to sleep for 2 minutes.,true, 1990000,
    ++invisibility_potion,published,managed_by_android,false,en_US; Invisibility Potion; Invisible to all enemies for 5 minutes.,false, US; 1990000; BR; 6990000; RU; 129000000; IN; 130000000; ID; 27000000000; MX; 37000000;
    ++</pre>
    + 
    +-<p>"<em>product_id</em>","<em>publish_state</em>","<em>purchase_type</em>","<em>autotranslate</em>
    +-","<em>locale</em>; <em>title</em>; <em>description</em>","<em>autofill</em>","<em>country</em>;
    +-<em>price</em>"
    ++<p>
    ++  This example contains details for three items, each of which represents an
    ++  in-app product:
    + </p>
    ++<ul>
    ++  <li>
    ++    The first item defines a title and description for the <code>en_US</code>
    ++    and <code>es_ES</code> locales. A pricing template defines the item's
    ++    price.
    ++  </li>
    ++  <li>
    ++    The second item doesn't use a pricing template. Instead, it specifies a
    ++    price for the default country (US). The Google Play Developer Console
    ++    uses current exchange rates and locally relevant pricing patterns to
    ++    automatically set the prices in all other countries where the app is
    ++    distributed.
    ++  </li>
    ++  <li>
    ++    The third item also doesn't use a pricing template. The item's price is
    ++    specified manually for each country where the app is distributed.
    ++  </li>
    ++</ul>
    + 
    +-<p>Descriptions and usage details are provided below.</p>
    ++<p>
    ++  Each row in a CSV file can contain the following values, though at least one
    ++  of these values is undefined in each row:
    ++</p>
    + 
    + <dl>
    +-  <dt>product_id</dt>
    ++  <dt><code>Product ID</code></dt>
    +   <dd>
    +-    This is equivalent to the In-app Product ID setting in the In-app Products UI. If you specify
    +-    a <em>product_id</em> that already exists in a product list, and you choose to overwrite
    +-    the product list while importing the CSV file, the data for the existing item is overwritten with
    +-    the values specified in the CSV file. The overwrite feature does not delete items that are on a
    +-    product list but not present in the CSV file.
    ++    <p>
    ++      Setting this value in the CSV file has the same effect as entering a
    ++      <em>Product ID</em> when creating a new in-app product.
    ++    </p>
    ++    <p>
    ++      If you specify a <code>Product ID</code> assigned to an in-app product that already
    ++      exists in a product list, and you've checked the <strong>Overwrite
    ++      existing products</strong> checkbox in the <em>Import In-app Products</em>
    ++      dialog, the data for the existing in-app product is overwritten with the
    ++      values that you specify in the CSV file.
    ++    </p>
    +   </dd>
    +-  <dt>publish_state</dt>
    ++  <dt><code>Publish State</code></dt>
    +   <dd>
    +-    This is equivalent to the Publishing State setting in the In-app Products UI. Can be <code>
    +-    published</code> or <code>unpublished</code>.
    ++    <p>
    ++      This value must be set to <code>published</code>
    ++      or <code>unpublished</code>.
    ++    </p>
    ++    <p>
    ++      Setting this value to <code>published</code> has the same effect as
    ++      navigating to an item's <em>Managed Product Details</em> page and choosing
    ++      <strong>Active</strong> in the drop-down list next to the in-app product's
    ++      title and product ID. Setting the value to <code>unpublished</code>
    ++      has the same effect as choosing <strong>Inactive</strong> in the same
    ++      drop-down list.
    ++    </p>
    +   </dd>
    +-  <dt>purchase_type</dt>
    ++  <dt><code>Purchase Type</code></dt>
    +   <dd>
    +-    This is equivalent to the Product Type setting in the In-app Products UI. Can be <code>
    +-    managed_by_android</code>, which is equivalent to <strong>Managed per user account
    +-    </strong> in the In-app Products UI, or <code>managed_by_publisher</code>, which is equivalent
    +-    to <strong>Unmanaged</strong> in the In-app Products UI.
    ++    <p>
    ++      This value must be set to <code>managed_by_android</code> because batch
    ++      upload of product lists containing subscriptions is not supported.
    ++    </p>
    ++    <p>
    ++      Setting this value to <code>managed_by_android</code> has the same effect
    ++      as selecting <strong>Managed product</strong> in the <em>Add New
    ++      Product</em> dialog when creating an in-app product.
    ++    </p>
    +   </dd>
    +-  <dt>autotranslate</dt>
    ++  <dt><code>Auto Translate</code></dt>
    +   <dd>
    +-    This is equivalent to selecting the <strong>Fill fields with auto translation</strong>
    +-    checkbox in the In-app Products UI. Can be <code>true</code> or <code>false</code>.
    ++    <p>
    ++      This value must be set to <code>false</code> because auto-translation of
    ++      in-app product details isn't supported.
    ++    </p>
    ++    <p>
    ++      If you want to provide translations of an in-app product's title and
    ++      description, you need to specify these translations explicitly within the
    ++      <code>Locale</code> value.
    ++    </p>
    +   </dd>
    +-  <dt>locale</dt>
    ++  <dt><code>Locale</code>, <code>Title</code>, and <code>Description</code></dt>
    +   <dd>
    +-    <p>This is equivalent to the Language setting in the In-app Products UI. You must have an entry
    +-    for the default locale. The default locale must be the first entry in the list of
    +-    locales, and it must include a <em>title</em> and <em>description</em>. If you want to provide
    +-    translated versions of the <em>title</em> and <em>description</em> in addition to the default,
    +-    you must use the following syntax rules:</p>
    +-    <ul>
    ++    <p>
    ++      If you include only one locale for an item, you must specify your app's
    ++      default locale and the item's default title and description:
    ++    </p>
    ++
    ++<pre class="no-pretty-print">
    ++<var>app_default_locale</var>; <var>item_default_title</var>; <var>item_default_description</var>;
    ++</pre>
    ++
    ++    <p>
    ++      Setting these values has the same effect as performing the following
    ++      sequence of actions:
    ++    </p>
    ++    <ol>
    +       <li>
    +-      <p>If <em>autotranslate</em> is <code>true</code>, you must specify the default locale,
    +-      default title, default description, and other locales using the following format:</p>
    +-      <p>"true,"<em>default_locale</em>; <em>default_locale_title</em>;
    +-      <em>default_locale_description</em>; <em>locale_2</em>;    <em>locale_3</em>, ..."</p>
    ++        Choosing a default language when you add a new app to your
    ++        publisher account.
    +       </li>
    +       <li>
    +-      <p>If <em>autotranslate</em> is <code>false</code>, you must specify the default locale,
    +-      default title, and default description as well as the translated titles and descriptions using
    +-      the following format:</p>
    +-      <p>"false,"<em>default_locale</em>; <em>default_locale_title</em>;
    +-      <em>default_locale_description</em>; <em>locale_2</em>; <em>locale_2_title</em>;
    +-      <em>local_2_description</em>; <em>locale_3</em>; <em>locale_3_title</em>;
    +-       <em>locale_3_description</em>; ..."</p>
    ++        Navigating to an in-app product's <em>Managed Product Details</em> page.
    +       </li>
    +-    </ul>
    +-    <p>See table 1 for a list of the language codes you can use with the <em>locale</em> field.</p>
    +-  </dd>
    +-  <dt>title</dt>
    +-  <dd>
    +-    This is equivalent to the Title setting in the In-app Products UI. If the <em>title</em>
    +-    contains a semicolon, it must be escaped with a backslash (for example, <code>\;</code>). Also, a backslash
    +-    must be escaped with a backslash (for example, <code>\\</code>).
    +-  </dd>
    +-  <dt>description</dt>
    +-  <dd>
    +-    This is equivalent to the Description in the In-app Products UI. If the <em>description</em>
    +-    contains a semicolon, it must be escaped with a backslash (for example, <code>\;</code>). Also, a backslash
    +-    must be escaped with a backslash (for example, <code>\\</code>).
    ++      <li>
    ++        Specifying the in-app product's default title and description.
    ++      </li>
    ++    </ol>
    ++    <p>
    ++      When setting the <code>Locale</code> value, you can use any of the
    ++      language codes that appear within the <em>Add Your Own Translations</em>
    ++      dialog. You can access this dialog by navigating to an in-app product's
    ++      <em>Managed Product Details</em> page and clicking <strong>Add
    ++      translations</strong> or <strong>Manage translations</strong>.
    ++    </p>
    ++    <p class="note">
    ++      <strong>Note: </strong>When specifying the <code>Title</code> and
    ++      <code>Description</code> values, use backslashes to escape the semicolon
    ++      (<code>\;</code>) and backslash (<code>\\</code>) characters.
    ++    </p>
    ++    <p>
    ++      If you want to include translated versions of the item's title and
    ++      description, you must list the default locale, title, and description,
    ++      followed by the locales, titles, and descriptions for each translation.
    ++      In the following example, the in-app product uses <code>en_US</code>
    ++      (United States English) as the default locale and <code>es_ES</code>
    ++      (Spain Spanish) as a translation:
    ++    </p>
    ++<pre class="no-pretty-print">
    ++en_US; Invisibility Cloak; Makes you invisible.; es_ES; Capote Invisible; Se vuelven invisible.
    ++</pre>
    ++    <p class="note">
    ++      <strong>Note: </strong>An app contains a single default language, but each
    ++      in-app product maintains its own list of translations. Therefore, although
    ++      the first locale in each item's <code>Locale</code> value must be the same
    ++      throughout the CSV file, the other locales can differ from one item to
    ++      another.
    ++    </p>
    ++    <p>
    ++      Providing values for multiple translations has the same effect as
    ++      performing the following sequence of actions:
    ++    </p>
    ++    <ol>
    ++      <li>
    ++        Navigating to an in-app product's <em>Managed Product Details</em> page.
    ++      </li>
    ++      <li>
    ++        Clicking <strong>Add translations</strong>.
    ++      </li>
    ++      <li>
    ++        Selecting the languages for the translations and clicking
    ++        <strong>Add</strong>.
    ++      </li>
    ++      <li>
    ++        Choosing one of the languages you added in the previous step.
    ++      </li>
    ++      <li>
    ++        Specifying a new title and description, which serve as translations into
    ++        the selected language.
    ++      </li>
    ++      <li>
    ++        Repeating steps 4 and 5 to add translations into all other non-default
    ++        languages.
    ++      </li>
    ++    </ol>
    +   </dd>
    +-  <dt>autofill</dt>
    ++  <dt><code>Auto Fill Prices</code>, <code>Country</code>, and
    ++  <code>Price</code></dt>
    +   <dd>
    +-    <p>This is equivalent to clicking <strong>Auto Fill</strong> in the In-app Products UI. Can be
    +-    <code>true</code> or <code>false</code>. The syntax for specifying the <em>country</em>
    +-    and <em>price</em> varies depending on which <em>autofill</em> setting you use:</p>
    ++    <p>
    ++      You can set <code>Auto Fill Prices</code> to <code>true</code> or
    ++      <code>false</code>.
    ++      If an in-app product uses a <a href="#pricing-template">pricing
    ++      template</a>, you should set <code>Auto Fill Prices</code> to
    ++      <code>false</code>, and you shouldn't set a value for the
    ++      <code>Price</code>.
    ++    </p>
    ++    <p class="note">
    ++      <strong>Note: </strong>When you specify an item's price in a CSV file, you
    ++      provide a price in <em>micro-units</em>, where 1,000,000 micro-units is
    ++      equivalent to 1 unit of real currency.
    ++    </p>
    ++    <p>
    ++      The following sections describe how the value of
    ++      <code>Auto Fill Prices</code> affects the syntax and meaning of the
    ++      <code>Country</code> and <code>Price</code> values.
    ++    </p>
    ++    <h5>Using auto-filled prices</h5>
    ++    <p>
    ++      If you set <code>Auto Fill Prices</code> to <code>true</code>, you specify
    ++      only the item's default price; you don't include a <code>Country</code>
    ++      value. Setting <code>Auto Fill Prices</code> to <code>true</code> has the
    ++      same effect as performing the following sequence of actions:
    ++    </p>
    ++    <ol>
    ++      <li>
    ++        Navigating to an in-app product's <em>Managed Product Details</em> page.
    ++      </li>
    ++      <li>
    ++        Selecting <strong>Edit</strong> in the <em>Price</em> section.
    ++      </li>
    ++      <li>
    ++        Entering a default, tax-exclusive price. Auto-filled prices include tax.
    ++      </li>
    ++      <li>
    ++        Clicking the checkbox next to <em>COUNTRY</em> in the <em>Edit Local
    ++        Prices</em> dialog that appears.
    ++      </li>
    ++      <li>
    ++        Selecting <strong>Refresh exchange rates</strong>.
    ++      </li>
    ++      <li>
    ++        Selecting <strong>Apply</strong>.
    ++      </li>
    ++    </ol>
    ++    <p>
    ++      For example, under the following conditions:
    ++    </p>
    +     <ul>
    ++      <li>Your app's default locale is <code>en_US</code>.</li>
    ++      <li>An in-app product's default, tax-exclusive price is $1.99.</li>
    ++      <li>You want the prices for other countries auto-filled.</li>
    ++    </ul>
    ++    <p>
    ++      ...you'd set the values of <code>Auto Fill Prices</code> and
    ++      <code>Price</code> at the end of a row in the CSV file as follows:
    ++    </p>
    ++
    ++<pre class="no-pretty-print">
    ++true,1990000,
    ++</pre>
    ++
    ++    <h5>Not using auto-filled prices</h5>
    ++    <p>
    ++      If you set <code>Auto Fill Prices</code> to <code>false</code> instead,
    ++      you specify a series of <code>Country</code> and <code>Price</code>
    ++      values for all countries where you distribute your app, including the country corresponding to your app's default locale.
    ++      Each <code>Country</code> value is the two-letter uppercase <a
    ++      class="external-link"
    ++      href="https://en.wikipedia.org/wiki/ISO_3166-1_alpha-2">ISO country
    ++      code</a> that represents a country where your app is distributed.
    ++    </p>
    ++    <p class="note">
    ++      <strong>Note: </strong>You must provide a country code and price for each
    ++      country that your app is targeting. To view and edit the list of countries
    ++      that your app targets, open your app's <em>Pricing &amp; Distribution</em>
    ++      page.
    ++    </p>
    ++    <p>
    ++      Each <code>Price</code> value represents the cost of the item in
    ++      micro-units of the currency used in that country. Setting <code>Auto Fill
    ++      Prices</code> to <code>false</code> has the same effect as performing
    ++      the following sequence of actions:
    ++    </p>
    ++    <ol>
    ++      <li>
    ++        Navigating to an in-app product's <em>Managed Product Details</em> page.
    ++      </li>
    ++      <li>
    ++        Selecting <strong>Edit</strong> in the <em>Price</em> section.
    ++      </li>
    +       <li>
    +-        <p>If <em>autofill</em> is set to <code>true</code>, you need to specify only the default
    +-        price in your home currency, and you must use this syntax:</p>
    +-        <p>"true","<em>default_price_in_home_currency</em>"
    ++        Explicitly setting tax-inclusive prices for different countries in the
    ++        <em>Edit Local Prices</em> dialog that appears.
    +       </li>
    +       <li>
    +-        <p>If <em>autofill</em> is set to <code>false</code>, you need to specify a <em>country</em>
    +-        and a <em>price</em> for each currency, and you must use the following syntax:</p>
    +-        <p>"false", "<em>home_country</em>; <em>default_price_in_home_currency</em>; <em>country_2</em>;
    +-        <em>country_2_price</em>; <em>country_3</em>; <em>country_3_price</em>; ..."</p>
    ++        Selecting <strong>Apply</strong>.
    +       </li>
    ++    </ol>
    ++    <p>
    ++      For example, if you're offering your app for the following prices (all
    ++      taxes included) in other countries:
    ++    </p>
    ++    <ul>
    ++      <li>R$6.99 in Brazil.</li>
    ++      <li>129&nbsp;&#8381; in Russia.</li>
    ++      <li>&#8377;130 in India.</li>
    ++      <li>Rp&nbsp;27,000 in Indonesia.</li>
    ++      <li>$37 in Mexico.</li>
    +     </ul>
    +-    <p class="note"><strong>Note: </strong>If you use an <em>autofill</em> value of <code>false</code>
    +-    and set country prices manually, you must incorporate country-specific
    +-    pricing patterns, including tax rates, into the prices you provide.</p>
    +-  </dd>
    +-  <dt>country</dt>
    +-  <dd>
    +-    The country for which you are specifying a price. You can only list countries that your
    +-    app is targeting. The country codes are two-letter uppercase
    +-    ISO country codes (such as "US"), as defined by
    +-    <a href="http://en.wikipedia.org/wiki/ISO_3166-1_alpha-2">ISO 3166-2</a>.
    ++    <p>
    ++      ...you'd set the values of <code>Auto Fill Prices</code>,
    ++      <code>Country</code>, and <code>Price</code> at the end of a row in the
    ++      CSV file as follows:
    ++    </p>
    ++
    ++<pre class="no-pretty-print">
    ++false, BR; 6990000; RU; 129000000; IN; 130000000; ID; 27000000000; MX; 37000000;
    ++</pre>
    ++
    +   </dd>
    +-  <dt>price</dt>
    ++  <dt><code>Pricing Template ID</code></dt>
    +   <dd>
    +-    This is equivalent to the Price in the In-app Products UI. The price must be specified in
    +-    micro-units. To convert a currency value to micro-units, you multiply the real value by
    +-    1,000,000.
    +-    For example, if you want to sell an in-app item for $1.99, you specify <code>1990000</code> in the
    +-    <em>price</em> field.
    ++  <p>
    ++    If an item is linked to a pricing template, you should set <code>Auto Fill
    ++    Prices</code> to <code>false</code>, and you shouldn't set a value for the
    ++    <code>Price</code> column. If the item isn't linked to a pricing template,
    ++    you shouldn't set a value for the <code>Pricing Template ID</code>; instead,
    ++    you should set <code>Auto Fill Prices</code>, <code>Country</code>, and
    ++    <code>Price</code> based on how you want to set the in-app product's prices.
    ++  </p>
    ++  <p>
    ++    Setting this value has the same effect as navigating to an in-app product's
    ++    <em>Managed Product Details</em> page and linking the product's price to the
    ++    pricing template that has the same pricing template ID as the one specified
    ++    in the CSV file. This pricing template ID appears underneath a pricing
    ++    template's name on the <em>Pricing template</em> page.
    ++  </p>
    ++  <p>
    ++    If you import a CSV file, and you've checked the <strong>Overwrite existing
    ++    products</strong> checkbox in the <em>Import In-app Products</em> dialog,
    ++    you can update the links between in-app products and pricing templates. To
    ++    link the product to a specific pricing template, set the <code>Pricing
    ++    Template ID</code> value to that pricing template's ID. To unlink an in-app
    ++    product from all pricing templates, don't set a value for its <code>Pricing
    ++    Template ID</code>.
    ++  </p>
    ++  <p>
    ++    You can link up to 100 app prices or in-app product prices to a particular
    ++    pricing template. Therefore, don't specify the same <code>Pricing Template
    ++    ID</code> value in more than 100 rows of a CSV file.
    ++  </p>
    +   </dd>
    + </dl>
    + 
    +-<p class="table-caption" id="language-table"><strong>Table 1.</strong> Language codes you can use
    +-with the <em>locale</em> field.</p>
    +-
    +-<table>
    +-
    +-<tr>
    +-<th>Language</th>
    +-<th>Code</th>
    +-<th>Language</th>
    +-<th>Code</th>
    +-</tr>
    +-<tr>
    +-<td>Chinese</td>
    +-<td>zh_TW</td>
    +-<td>Italian</td>
    +-<td>it_IT</td>
    +-</tr>
    +-<tr>
    +-<td>Czech</td>
    +-<td>cs_CZ</td>
    +-<td>Japanese</td>
    +-<td>ja_JP</td>
    +-</tr>
    +-<tr>
    +-<td>Danish</td>
    +-<td>da_DK</td>
    +-<td>Korean</td>
    +-<td>ko_KR</td>
    +-</tr>
    +-<tr>
    +-<td>Dutch</td>
    +-<td>nl_NL</td>
    +-<td>Norwegian</td>
    +-<td>no_NO</td>
    +-</tr>
    +-<tr>
    +-<td>English</td>
    +-<td>en_US</td>
    +-<td>Polish</td>
    +-<td>pl_PL</td>
    +-</tr>
    +-<tr>
    +-<td>French</td>
    +-<td>fr_FR</td>
    +-<td>Portuguese</td>
    +-<td>pt_PT</td>
    +-</tr>
    +-<tr>
    +-<td>Finnish</td>
    +-<td>fi_FI</td>
    +-<td>Russian</td>
    +-<td>ru_RU</td>
    +-</tr>
    +-<tr>
    +-<td>German</td>
    +-<td>de_DE</td>
    +-<td>Spanish</td>
    +-<td>es_ES</td>
    +-</tr>
    +-<tr>
    +-<td>Hebrew</td>
    +-<td>iw_IL</td>
    +-<td>Swedish</td>
    +-<td>sv_SE</td>
    +-</tr>
    +-<tr>
    +-<td>Hindi</td>
    +-<td>hi_IN</td>
    +-<td>--</td>
    +-<td>--</td>
    +-</tr>
    +-</table>
    +-
    + <h2 id="pricing-template">
    +   Pricing Templates
    + </h2>
    +@@ -432,8 +609,12 @@ with the <em>locale</em> field.</p>
    + 
    + <p>
    +   When creating a pricing template, you provide new pricing information that you
    +-  can apply to paid apps and in-app products. To add a pricing template, do the
    +-  following:
    ++  can apply to paid apps and in-app products. You can link the prices of up to
    ++  100 apps and in-app products to a single pricing template.
    ++</p>
    ++
    ++<p>
    ++  To add a pricing template, do the following:
    + </p>
    + 
    + <ol>
    +@@ -442,14 +623,14 @@ with the <em>locale</em> field.</p>
    +     account.
    +   </li>
    + 
    +-  <li>In the <strong>Settings</strong> panel, open the <strong>Pricing
    +-  template</strong> page.
    ++  <li>In the <em>Settings</em> panel, open the <em>Pricing
    ++  template</em> page.
    +   </li>
    + 
    +   <li>
    +     <p>
    +-      If you are adding your first pricing template, the <strong>Add a Pricing
    +-      Template</strong> banner appears. Select <strong>Add template</strong> to
    ++      If you are adding your first pricing template, the <em>Add a Pricing
    ++      Template</em> banner appears. Select <strong>Add template</strong> to
    +       create a new template. The new template's <em>Pricing</em> tab appears.
    +     </p>
    + 
    +@@ -510,8 +691,8 @@ with the <em>locale</em> field.</p>
    +     account.
    +   </li>
    + 
    +-  <li>In the <strong>Settings</strong> panel, open the <strong>Pricing
    +-  template</strong> page. This page shows the list of pricing templates you have
    ++  <li>In the <em>Settings</em> panel, open the <em>Pricing
    ++  template</em> page. This page shows the list of pricing templates you have
    +   created for your account.
    +   </li>
    + 
    +@@ -571,8 +752,8 @@ with the <em>locale</em> field.</p>
    +     account.
    +   </li>
    + 
    +-  <li>In the <strong>All applications</strong> panel, select the app name, then
    +-  open the <strong>In-app Products</strong> page.
    ++  <li>In the <em>All applications</em> panel, select the app name, then
    ++  open the <em>In-app Products</em> page.
    +   </li>
    + 
    +   <li>Choose the in-app product that you want to link to a pricing template.
    +@@ -591,7 +772,7 @@ with the <em>locale</em> field.</p>
    + 
    + <p>
    +   To link the price of a paid app to a pricing template, you follow a similar
    +-  process on the app's <strong>Pricing &amp; Distribution</strong> page.
    ++  process on the app's <em>Pricing &amp; Distribution</em> page.
    + </p>
    + 
    + <h3 id="delete-linked-item">
    +@@ -623,7 +804,7 @@ with the <em>locale</em> field.</p>
    +   <li>Select the app that contains the in-app product you want to delete.
    +   </li>
    + 
    +-  <li>Open the app's <strong>In-app Products</strong> page.
    ++  <li>Open the app's <em>In-app Products</em> page.
    +   </li>
    + 
    +   <li>Choose the in-app product that you want to delete.
    +@@ -697,8 +878,8 @@ with the <em>locale</em> field.</p>
    +     account.
    +   </li>
    + 
    +-  <li>In the <strong>Settings</strong> panel, open the <strong>Pricing
    +-  template</strong> page, which shows the list of pricing templates you have
    ++  <li>In the <em>Settings</em> panel, open the <em>Pricing
    ++  template</em> page, which shows the list of pricing templates you have
    +   created for your account.
    +   </li>
    + 
    +@@ -712,15 +893,15 @@ with the <em>locale</em> field.</p>
    +   </li>
    + </ol>
    + 
    +-<h2 id="billing-purchase-type">Choosing a Product Type</h3>
    ++<h2 id="billing-purchase-type">Choosing a Product Type</h2>
    + 
    + <p>An item's product type controls how Google Play manages the purchase of the item. The supported
    + product types include "managed product" and "subscription." Since support for different product
    + types can vary among versions of the In-app Billing API, make sure that you choose a product
    +-type that's valid for the version of the In-app Billing API that your app uses. </p>
    ++type that's valid for the version of the In-app Billing API that your app uses.</p>
    + 
    + <p>For details, refer to the documentation for the <a
    +-href="{@docRoot}google/play/billing/api.html#producttype">In-app Billing API</a>.
    ++href="{@docRoot}google/play/billing/api.html#producttype">In-app Billing API</a>.</p>
    + 
    + <h2 id="billing-refunds">Handling Refunds</h2>
    + 
    +@@ -748,9 +929,10 @@ you at the conclusion of the purchase flow, as the value of the
    + intent.</p>
    + 
    + <p class="note">
    +-  <strong>Note:</strong> Test purchases don't have an <code>orderId</code>
    +-  field. To track test transactions, you use the <code>purchaseToken</code>
    +-  field instead. For more information about working with test purchases, see <a
    ++  <strong>Note:</strong> When a user completes a test purchase, the
    ++  <code>orderId</code> field remains blank. To track test transactions, use
    ++  the <code>purchaseToken</code> field instead. For more information about
    ++  working with test purchases, see <a
    +   href="{@docRoot}google/play/billing/billing_testing.html">Testing In-app
    +   Billing</a>.
    + </p>
    +@@ -765,14 +947,14 @@ assigned and managed by Google.</p>
    + 
    + <p>For transactions dated 5 December 2012 or later, Google payments assigns a
    + Merchant Order Number (rather than a Google Order Number) and reports the Merchant
    +-Order Number as the value of <code>orderId</code>. Here's an
    ++Order Number as the value of <code>orderID</code>. Here's an
    + example:</p>
    + 
    + <pre>"orderId" : "GPA.1234-5678-9012-34567"</pre>
    + 
    + <p>For transactions dated previous to 5 December 2012, Google checkout assigned
    + a Google Order Number and reported that number as the value of
    +-<code>orderId</code>. Here's an example of an <code>orderId</code> holding a
    ++<code>orderID</code>. Here's an example of an <code>orderID</code> holding a
    + Google Order Number:</p>
    + 
    + <pre>"orderId" : "556515565155651"</pre>
    +@@ -819,8 +1001,8 @@ app.</p>
    + 
    + <p>To locate the key for an app, follow these steps:</p>
    + <ol>
    +-  <li>Open the <strong>All applications</strong> panel.</li>
    +-  <li>Click on the app name, then open the <strong>Services &amp; APIs</strong>
    ++  <li>Open the <em>All applications</em> panel.</li>
    ++  <li>Click on the app name, then open the <em>Services &amp; APIs</em>
    +   page.</li>
    +   <li>Scroll down to the section of the page labeled Your License Key for This
    +   Application, as shown in figure 5.</li>
    +@@ -835,7 +1017,7 @@ for apps that depend on the (former) developer key. </p>
    +   width="700" alt="">
    +   <figcaption>
    +     <b>Figure 5. </b>You can find the license key for each app on the
    +-    <strong>Services &amp; APIs</strong> page.
    ++    <em>Services &amp; APIs</em> page.
    +   </figcaption>
    + </figure>
    + 
    +diff --git a/docs/html/google/play/billing/billing_integrate.jd b/docs/html/google/play/billing/billing_integrate.jd
    +index 5d6b3a8..506a440 100755
    +--- a/docs/html/google/play/billing/billing_integrate.jd
    ++++ b/docs/html/google/play/billing/billing_integrate.jd
    +@@ -9,18 +9,18 @@ page.tags="inapp, billing, iap"
    +   <h2>In this document</h2>
    +   <ol>
    +     <li><a href="#billing-add-aidl">Adding the AIDL file</a></li>
    +-    <li><a href="#billing-permission">Updating Your Manifest</a></li>
    ++    <li><a href="#billing-permission">Updating your manifest</a></li>
    +     <li><a href="#billing-service">Creating a ServiceConnection</a></li>
    +-    <li><a href="#billing-requests">Making In-app Billing Requests</a>
    ++    <li><a href="#billing-requests">Making In-app Billing requests</a>
    +        <ol>
    +-       <li><a href="#QueryDetails">Querying Items Available for Purchase</a><li>
    +-       <li><a href="#Purchase">Purchasing an Item</a></li>
    +-       <li><a href="#QueryPurchases">Querying Purchased Items</a></li>
    +-       <li><a href="#Consume">Consuming a Purchase</a></li>
    +-       <li><a href="#Subs">Implementing Subscriptions</a></li>
    ++       <li><a href="#QueryDetails">Querying items available for purchase</a><li>
    ++       <li><a href="#Purchase">Purchasing an item</a></li>
    ++       <li><a href="#QueryPurchases">Querying purchased items</a></li>
    ++       <li><a href="#Consume">Consuming a purchase</a></li>
    ++       <li><a href="#Subs">Implementing subscriptions</a></li>
    +        </ol>
    +     </li>
    +-    <li><a href="#billing-security">Securing Your App</a>
    ++    <li><a href="#billing-security">Securing your app</a>
    +   </ol>
    +   <h2>Reference</h2>
    +   <ol>
    +@@ -42,7 +42,7 @@ page.tags="inapp, billing, iap"
    +   In-app Billing on Google Play provides a straightforward, simple interface
    +   for sending In-app Billing requests and managing In-app Billing transactions
    +   using Google Play. The information below covers the basics of how to make
    +-  calls from your application to the In-app Billing service using the Version 3
    ++  calls from your application to the In-app Billing service using the In-app Billing Version 3
    +   API.
    + </p>
    + 
    +@@ -51,26 +51,25 @@ page.tags="inapp, billing, iap"
    +   your application, see the <a href=
    +   "{@docRoot}training/in-app-billing/index.html">Selling In-app Products</a>
    +   training class. The training class provides a complete sample In-app Billing
    +-  application, including convenience classes to handle key tasks related to
    +-  setting up your connection, sending billing requests and processing responses
    ++  application, including convenience classes to handle key tasks that are related to
    ++  setting up your connection, sending billing requests, processing responses
    +   from Google Play, and managing background threading so that you can make
    +   In-app Billing calls from your main activity.
    + </p>
    + 
    + <p>
    +-  Before you start, be sure that you read the <a href=
    ++  Before you start, read the <a href=
    +   "{@docRoot}google/play/billing/billing_overview.html">In-app Billing
    +-  Overview</a> to familiarize yourself with concepts that will make it easier
    ++  Overview</a> to familiarize yourself with concepts that make it easier
    +   for you to implement In-app Billing.
    + </p>
    + 
    +-<p>To implement In-app Billing in your application, you need to do the
    +-following:</p>
    ++<p>Complete these steps to implement In-app Billing in your application:</p>
    + 
    + <ol>
    +   <li>Add the In-app Billing library to your project.</li>
    +   <li>Update your {@code AndroidManifest.xml} file.</li>
    +-  <li>Create a {@code ServiceConnection} and bind it to
    ++  <li>Create a {@code ServiceConnection} and bind it to the
    + {@code IInAppBillingService}.</li>
    +   <li>Send In-app Billing requests from your application to
    + {@code IInAppBillingService}.</li>
    +@@ -79,55 +78,56 @@ following:</p>
    + 
    + <h2 id="billing-add-aidl">Adding the AIDL file to your project</h2>
    + 
    +-<p>{@code IInAppBillingService.aidl} is an Android Interface Definition
    ++<p>The {@code IInAppBillingService.aidl} is an Android Interface Definition
    + Language (AIDL) file that defines the interface to the In-app Billing Version
    +-3 service. You will use this interface to make billing requests by invoking IPC
    ++3 service. You can use this interface to make billing requests by invoking IPC
    + method calls.</p>
    +-<p>To get the AIDL file:</p>
    ++
    ++<p>Complete these steps to get the AIDL file:</p>
    + <ol>
    + <li>Open the <a href="{@docRoot}tools/help/sdk-manager.html">Android SDK Manager</a>.</li>
    + <li>In the SDK Manager, expand the {@code Extras} section.</li>
    + <li>Select <strong>Google Play Billing Library</strong>.</li>
    + <li>Click <strong>Install packages</strong> to complete the download.</li>
    + </ol>
    +-<p>The {@code IInAppBillingService.aidl} file will be installed to {@code <sdk>/extras/google/play_billing/}.</p>
    ++<p>The {@code IInAppBillingService.aidl} file will be installed to {@code &lt;sdk&gt;/extras/google/play_billing/}.</p>
    + 
    +-<p>To add the AIDL to your project:</p>
    ++<p>Complete these steps to add the AIDL to your project:</p>
    + 
    + <ol>
    +-  <li>First, download the Google Play Billing Library to your Android project:
    ++  <li>Download the Google Play Billing Library to your Android project:
    +       <ol type="a">
    +       <li>Select <strong>Tools > Android > SDK Manager</strong>.</li>
    +       <li>Under <strong>Appearance & Behavior > System Settings > Android SDK</strong>,
    +           select the <em>SDK Tools</em> tab to select and download <em>Google Play Billing
    +           Library</em>.</li></ol>
    + 
    +-  <li>Next, copy the {@code IInAppBillingService.aidl} file to your project.
    ++  <li>Copy the {@code IInAppBillingService.aidl} file to your project.
    +     <ul>
    +-      <li>If you are using Android Studio:
    ++      <li>If you are using Android Studio, complete these steps to copy the file:
    +         <ol type="a">
    +           <li>Navigate to {@code src/main} in the Project tool window.</li>
    + 
    +-          <li>Select <strong>File > New > Directory</strong> and enter {@code aidl} in the
    +-          <em>New Directory</em> window, then select <strong>OK</strong>.
    ++          <li>Select <strong>File > New > Directory</strong>, enter {@code aidl} in the
    ++          <em>New Directory</em> window, and select <strong>OK</strong>.
    + 
    +-          <li>Select <strong>File > New > Package</strong> and enter
    +-          {@code com.android.vending.billing} in the <em>New Package</em> window, then select
    ++          <li>Select <strong>File > New > Package</strong>, enter
    ++          {@code com.android.vending.billing} in the <em>New Package</em> window, and select
    +           <strong>OK</strong>.</li>
    + 
    +           <li>Using your operating system file explorer, navigate to
    +-          {@code <sdk>/extras/google/play_billing/}, copy the
    ++          {@code &lt;sdk&gt;/extras/google/play_billing/}, copy the
    +           {@code IInAppBillingService.aidl} file, and paste it into the
    +           {@code com.android.vending.billing} package in your project.
    +           </li>
    +         </ol>
    +       </li>
    + 
    +-      <li>If you are developing in a non-Android Studio environment: Create the
    +-      following directory {@code /src/com/android/vending/billing} and copy the
    +-      {@code IInAppBillingService.aidl} file into this directory. Put the AIDL
    +-      file into your project and use the Gradle tool to build your project so that
    +-      the <code>IInAppBillingService.java</code> file gets generated.
    ++      <li>If you are developing in a non-Android Studio environment, create the
    ++      following directory: {@code /src/com/android/vending/billing}. Copy the
    ++      {@code IInAppBillingService.aidl} file into this directory. Place the AIDL
    ++      file in your project and use the Gradle tool to build your project so that
    ++      the <code>IInAppBillingService.java</code> file is generated.
    +       </li>
    +     </ul>
    +   </li>
    +@@ -137,16 +137,16 @@ method calls.</p>
    +   </li>
    + </ol>
    + 
    +-<h2 id="billing-permission">Updating Your App's Manifest</h2>
    ++<h2 id="billing-permission">Updating your app's manifest</h2>
    + 
    + <p>
    +   In-app billing relies on the Google Play application, which handles all
    +-  communication between your application and the Google Play server. To use the
    ++  of the communication between your application and the Google Play server. To use the
    +   Google Play application, your application must request the proper permission.
    +   You can do this by adding the {@code com.android.vending.BILLING} permission
    +   to your AndroidManifest.xml file. If your application does not declare the
    +   In-app Billing permission, but attempts to send billing requests, Google Play
    +-  will refuse the requests and respond with an error.
    ++  refuses the requests and responds with an error.
    + </p>
    + 
    + <p>
    +@@ -182,7 +182,7 @@ method calls.</p>
    +   onServiceDisconnected} and {@link
    +   android.content.ServiceConnection#onServiceConnected onServiceConnected}
    +   methods to get a reference to the {@code IInAppBillingService} instance after
    +-  a connection has been established.
    ++  a connection is established.
    + </p>
    + 
    + <pre>
    +@@ -208,20 +208,25 @@ ServiceConnection mServiceConn = new ServiceConnection() {
    +   bindService} method. Pass the method an {@link android.content.Intent} that
    +   references the In-app Billing service and an instance of the {@link
    +   android.content.ServiceConnection} that you created, and explicitly set the
    +-  Intent's target package name to <code>com.android.vending</code> — the
    ++  Intent's target package name to <code>com.android.vending</code>&mdash;the
    +   package name of Google Play app.
    + </p>
    + 
    + <p class="caution">
    +   <strong>Caution:</strong> To protect the security of billing transactions,
    +-  always make sure to explicitly set the intent's target package name to
    ++  always explicitly set the intent's target package name to
    +   <code>com.android.vending</code>, using {@link
    +-  android.content.Intent#setPackage(java.lang.String) setPackage()} as shown in
    +-  the example below. Setting the package name explicitly ensures that
    ++  android.content.Intent#setPackage(java.lang.String) setPackage()}.
    ++  Setting the package name explicitly ensures that
    +   <em>only</em> the Google Play app can handle billing requests from your app,
    +   preventing other apps from intercepting those requests.
    + </p>
    + 
    ++<p>
    ++  The following code sample demonstrates how to set the intent's target package
    ++  to protect the security of transactions:
    ++</p>
    ++
    + <pre>&#64;Override
    + public void onCreate(Bundle savedInstanceState) {
    +   super.onCreate(savedInstanceState);
    +@@ -233,6 +238,13 @@ public void onCreate(Bundle savedInstanceState) {
    + }
    + </pre>
    + 
    ++<p class="caution"><strong>Caution</strong>: To ensure that your app is secure, always use an
    ++explicit intent when starting a {@link android.app.Service} and do not declare intent filters for
    ++your services. Using an implicit intent to start a service is a security hazard because you cannot
    ++be certain of the service that will respond to the intent, and the user cannot see which service
    ++starts. Beginning with Android 5.0 (API level 21), the system throws an exception if you call
    ++{@link android.content.Context#bindService bindService()} with an implicit intent.</p>
    ++
    + <p>
    +   You can now use the mService reference to communicate with the Google Play
    +   service.
    +@@ -242,10 +254,14 @@ public void onCreate(Bundle savedInstanceState) {
    +   <strong>Important:</strong> Remember to unbind from the In-app Billing
    +   service when you are done with your {@link android.app.Activity}. If you
    +   don’t unbind, the open service connection could cause your device’s
    +-  performance to degrade. This example shows how to perform the unbind
    ++  performance to degrade.
    ++</p>
    ++
    ++<p>
    ++  This example shows how to perform the unbind
    +   operation on a service connection to In-app Billing called {@code
    +   mServiceConn} by overriding the activity’s {@link
    +-  android.app.Activity#onDestroy onDestroy} method.
    ++  android.app.Activity#onDestroy onDestroy} method:
    + </p>
    + 
    + <pre>
    +@@ -264,29 +280,29 @@ public void onDestroy() {
    +   "{@docRoot}training/in-app-billing/preparing-iab-app.html">Selling In-app
    +   Products</a> training class and associated sample.
    + </p>
    +-<h2 id="billing-requests">Making In-app Billing Requests</h2>
    ++<h2 id="billing-requests">Making In-app Billing requests</h2>
    + <p>
    +-  Once your application is connected to Google Play, you can initiate purchase
    ++  After your application is connected to Google Play, you can initiate purchase
    +   requests for in-app products. Google Play provides a checkout interface for
    +-  users to enter their payment method, so your application does not need to
    ++  users to enter their payment method, so your application doesn't need to
    +   handle payment transactions directly. When an item is purchased, Google Play
    +   recognizes that the user has ownership of that item and prevents the user
    +   from purchasing another item with the same product ID until it is consumed.
    +-  You can control how the item is consumed in your application, and notify
    ++  You can control how the item is consumed in your application and notify
    +   Google Play to make the item available for purchase again. You can also query
    +-  Google Play to quickly retrieve the list of purchases that were made by the
    +-  user. This is useful, for example, when you want to restore the user's
    ++  Google Play to quickly retrieve the list of purchases that the
    ++  user made. This is useful, for example, when you want to restore the user's
    +   purchases when your user launches your app.
    + </p>
    + 
    +-<h3 id="QueryDetails">Querying for Items Available for Purchase</h3>
    ++<h3 id="QueryDetails">Querying for items available for purchase</h3>
    + 
    + <p>
    +   In your application, you can query the item details from Google Play using
    +   the In-app Billing Version 3 API. To pass a request to the In-app Billing
    +-  service, first create a {@link android.os.Bundle} that contains a String
    ++  service, create a {@link android.os.Bundle} that contains a String
    +   {@link java.util.ArrayList} of product IDs with key "ITEM_ID_LIST", where
    +-  each string is a product ID for an purchasable item.
    ++  each string is a product ID for an purchasable item. Here is an example:
    + </p>
    + 
    + <pre>
    +@@ -299,9 +315,9 @@ querySkus.putStringArrayList(“ITEM_ID_LIST”, skuList);
    + 
    + <p>
    +   To retrieve this information from Google Play, call the {@code getSkuDetails}
    +-  method on the In-app Billing Version 3 API, and pass the method the In-app
    ++  method on the In-app Billing Version 3 API and pass the In-app
    +   Billing API version (“3”), the package name of your calling app, the purchase
    +-  type (“inapp”), and the {@link android.os.Bundle} that you created.
    ++  type (“inapp”), and the {@link android.os.Bundle} that you created, into the method:
    + </p>
    + 
    + <pre>
    +@@ -310,35 +326,35 @@ Bundle skuDetails = mService.getSkuDetails(3,
    + </pre>
    + 
    + <p>
    +-  If the request is successful, the returned {@link android.os.Bundle}has a
    ++  If the request is successful, the returned {@link android.os.Bundle} has a
    +   response code of {@code BILLING_RESPONSE_RESULT_OK} (0).
    + </p>
    + 
    + <p class="note">
    +-  <strong>Warning:</strong> Do not call the {@code getSkuDetails} method on the
    +-  main thread. Calling this method triggers a network request which could block
    ++  <strong>Warning:</strong> Don't call the {@code getSkuDetails} method on the
    ++  main thread. Calling this method triggers a network request that could block
    +   your main thread. Instead, create a separate thread and call the {@code
    +-  getSkuDetails} method from inside that thread.
    ++  getSkuDetails} method from inside of that thread.
    + </p>
    + 
    + <p>
    +-  To see all the possible response codes from Google Play, see <a href=
    ++  To view all of the possible response codes from Google Play, see <a href=
    +   "{@docRoot}google/play/billing/billing_reference.html#billing-codes">In-app
    +   Billing Reference</a>.
    + </p>
    + 
    + <p>
    +   The query results are stored in a String ArrayList with key {@code
    +-  DETAILS_LIST}. The purchase information is stored in the String in JSON
    +-  format. To see the types of product detail information that are returned, see
    ++  DETAILS_LIST}. The purchase information is stored within the String in JSON
    ++  format. To view the types of product detail information that are returned, see
    +   <a href=
    +   "{@docRoot}google/play/billing/billing_reference.html#getSkuDetails">In-app
    +   Billing Reference</a>.
    + </p>
    + 
    + <p>
    +-  In this example, you are retrieving the prices for your in-app items from the
    +-  skuDetails {@link android.os.Bundle} returned from the previous code snippet.
    ++  In this example shows how to retrieve the prices for your in-app items from the
    ++  skuDetails {@link android.os.Bundle} that is returned from the previous code snippet:
    + </p>
    + 
    + <pre>
    +@@ -357,15 +373,15 @@ if (response == 0) {
    + }
    + </pre>
    + 
    +-<h3 id="Purchase">Purchasing an Item</h3>
    ++<h3 id="Purchase">Purchasing an item</h3>
    + <p>
    +   To start a purchase request from your app, call the {@code getBuyIntent}
    +-  method on the In-app Billing service. Pass in to the method the In-app
    ++  method on the In-app Billing service. Pass the In-app
    +   Billing API version (“3”), the package name of your calling app, the product
    +   ID for the item to purchase, the purchase type (“inapp” or "subs"), and a
    +-  {@code developerPayload} String. The {@code developerPayload} String is used
    ++  {@code developerPayload} String into the method. The {@code developerPayload} String is used
    +   to specify any additional arguments that you want Google Play to send back
    +-  along with the purchase information.
    ++  along with the purchase information. Here is an example:
    + </p>
    + 
    + <pre>
    +@@ -377,10 +393,13 @@ Bundle buyIntentBundle = mService.getBuyIntent(3, getPackageName(),
    +   If the request is successful, the returned {@link android.os.Bundle} has a
    +   response code of {@code BILLING_RESPONSE_RESULT_OK} (0) and a {@link
    +   android.app.PendingIntent} that you can use to start the purchase flow. To
    +-  see all the possible response codes from Google Play, see <a href=
    ++  view all of the possible response codes from Google Play, see <a href=
    +   "{@docRoot}google/play/billing/billing_reference.html#billing-codes">In-app
    +-  Billing Reference</a>. Next, extract a {@link android.app.PendingIntent} from
    +-  the response {@link android.os.Bundle} with key {@code BUY_INTENT}.
    ++  Billing Reference</a>.
    ++
    ++<p>
    ++  The next step is to extract a {@link android.app.PendingIntent} from
    ++  the response {@link android.os.Bundle} with key {@code BUY_INTENT}, as shown here:
    + </p>
    + 
    + <pre>
    +@@ -390,8 +409,8 @@ PendingIntent pendingIntent = buyIntentBundle.getParcelable("BUY_INTENT");
    + <p>
    +   To complete the purchase transaction, call the {@link
    +   android.app.Activity#startIntentSenderForResult startIntentSenderForResult}
    +-  method and use the {@link android.app.PendingIntent} that you created. In
    +-  this example, you are using an arbitrary value of 1001 for the request code.
    ++  method and use the {@link android.app.PendingIntent} that you created. This
    ++  example uses an arbitrary value of 1001 for the request code:
    + </p>
    + 
    + <pre>
    +@@ -404,9 +423,9 @@ startIntentSenderForResult(pendingIntent.getIntentSender(),
    +   Google Play sends a response to your {@link android.app.PendingIntent} to the
    +   {@link android.app.Activity#onActivityResult onActivityResult} method of your
    +   application. The {@link android.app.Activity#onActivityResult
    +-  onActivityResult} method will have a result code of {@code
    +-  Activity.RESULT_OK} (1) or {@code Activity.RESULT_CANCELED} (0). To see the
    +-  types of order information that is returned in the response {@link
    ++  onActivityResult} method has a result code of {@code
    ++  Activity.RESULT_OK} (1) or {@code Activity.RESULT_CANCELED} (0). To view the
    ++  types of order information that are returned in the response {@link
    +   android.content.Intent}, see <a href=
    +   "{@docRoot}google/play/billing/billing_reference.html#getBuyIntent">In-app
    +   Billing Reference</a>.
    +@@ -415,7 +434,7 @@ startIntentSenderForResult(pendingIntent.getIntentSender(),
    + <p>
    +   The purchase data for the order is a String in JSON format that is mapped to
    +   the {@code INAPP_PURCHASE_DATA} key in the response {@link
    +-  android.content.Intent}, for example:
    ++  android.content.Intent}. Here is an example:
    + </p>
    + 
    + <pre>
    +@@ -436,13 +455,13 @@ startIntentSenderForResult(pendingIntent.getIntentSender(),
    +   long. Pass this entire token to other methods, such as when you consume the
    +   purchase, as described in <a href=
    +   "{@docRoot}training/in-app-billing/purchase-iab-products.html#Consume">Consume
    +-  a Purchase</a>. Do not abbreviate or truncate this token; you must save and
    ++  a Purchase</a>. Don't abbreviate or truncate this token; you must save and
    +   return the entire token.
    + </p>
    + 
    + <p>
    +-  Continuing from the previous example, you get the response code, purchase
    +-  data, and signature from the response {@link android.content.Intent}.
    ++  Continuing from the previous example, you receive the response code, purchase
    ++  data, and signature from the response {@link android.content.Intent}:
    + </p>
    + 
    + <pre>
    +@@ -472,23 +491,23 @@ protected void onActivityResult(int requestCode, int resultCode, Intent data) {
    + <p class="note">
    +   <strong>Security Recommendation:</strong> When you send a purchase request,
    +   create a String token that uniquely identifies this purchase request and
    +-  include this token in the {@code developerPayload}.You can use a randomly
    +-  generated string as the token. When you receive the purchase response from
    +-  Google Play, make sure to check the returned data signature, the {@code
    ++  include this token in the {@code developerPayload}. You can use a randomly-generated
    ++  string as the token. When you receive the purchase response from
    ++  Google Play, ensure that you check the returned data signature, the {@code
    +   orderId}, and the {@code developerPayload} String. For added security, you
    +-  should perform the checking on your own secure server. Make sure to verify
    ++  should perform the checking on your own secure server. Verify
    +   that the {@code orderId} is a unique value that you have not previously
    +-  processed, and the {@code developerPayload} String matches the token that you
    ++  processed and that the {@code developerPayload} String matches the token that you
    +   sent previously with the purchase request.
    + </p>
    + 
    +-<h3 id="QueryPurchases">Querying for Purchased Items</h3>
    ++<h3 id="QueryPurchases">Querying for purchased items</h3>
    + 
    + <p>
    +-  To retrieve information about purchases made by a user from your app, call
    ++  To retrieve information about purchases that are made by a user from your app, call
    +   the {@code getPurchases} method on the In-app Billing Version 3 service. Pass
    +-  in to the method the In-app Billing API version (“3”), the package name of
    +-  your calling app, and the purchase type (“inapp” or "subs").
    ++  the In-app Billing API version (“3”), the package name of
    ++  your calling app, and the purchase type (“inapp” or "subs") into the method. Here is an example:
    + </p>
    + 
    + <pre>
    +@@ -507,18 +526,18 @@ Bundle ownedItems = mService.getPurchases(3, getPackageName(), "inapp", null);
    +   To improve performance, the In-app Billing service returns only up to 700
    +   products that are owned by the user when {@code getPurchase} is first called.
    +   If the user owns a large number of products, Google Play includes a String
    +-  token mapped to the key {@code INAPP_CONTINUATION_TOKEN} in the response
    ++  token that is mapped to the key {@code INAPP_CONTINUATION_TOKEN} in the response
    +   {@link android.os.Bundle} to indicate that more products can be retrieved.
    +-  Your application can then make a subsequent {@code getPurchases} call, and
    ++  Your application can then make a subsequent {@code getPurchases} call and
    +   pass in this token as an argument. Google Play continues to return a
    +   continuation token in the response {@link android.os.Bundle} until all
    +-  products that are owned by the user has been sent to your app.
    ++  of the products that are owned by the user are sent to your app.
    + </p>
    + 
    +-<p>For more information about the data returned by {@code getPurchases}, see
    ++<p>For more information about the data that is returned by {@code getPurchases}, see
    +   <a href="{@docRoot}google/play/billing/billing_reference.html#getPurchases">
    +   In-app Billing Reference</a>. The following example shows how you can
    +-  retrieve this data from the response.
    ++  retrieve this data from the response:
    + </p>
    + 
    + <pre>
    +@@ -548,26 +567,26 @@ if (response == 0) {
    + </pre>
    + 
    + 
    +-<h3 id="Consume">Consuming a Purchase</h3>
    ++<h3 id="Consume">Consuming a purchase</h3>
    + 
    + <p>
    +   You can use the In-app Billing Version 3 API to track the ownership of
    +   purchased in-app products in Google Play. Once an in-app product is
    +-  purchased, it is considered to be "owned" and cannot be purchased from Google
    ++  purchased, it is considered to be <em>owned</em> and cannot be purchased from Google
    +   Play. You must send a consumption request for the in-app product before
    +   Google Play makes it available for purchase again.
    + </p>
    + 
    +-<p class="caution">
    ++<p class="note">
    +   <strong>Important</strong>: Managed in-app products are consumable, but
    +   subscriptions are not.
    + </p>
    + 
    + <p>
    +-  How you use the consumption mechanism in your app is up to you. Typically,
    +-  you would implement consumption for in-app products with temporary benefits
    ++  The way that you use the consumption mechanism in your app is up to you. Typically,
    ++  you implement consumption for in-app products with temporary benefits
    +   that users may want to purchase multiple times (for example, in-game currency
    +-  or equipment). You would typically not want to implement consumption for
    ++  or equipment). You typically don't want to implement consumption for
    +   in-app products that are purchased once and provide a permanent effect (for
    +   example, a premium upgrade).
    + </p>
    +@@ -576,21 +595,21 @@ if (response == 0) {
    +   To record a purchase consumption, send the {@code consumePurchase} method to
    +   the In-app Billing service and pass in the {@code purchaseToken} String value
    +   that identifies the purchase to be removed. The {@code purchaseToken} is part
    +-  of the data returned in the {@code INAPP_PURCHASE_DATA} String by the Google
    +-  Play service following a successful purchase request. In this example, you
    +-  are recording the consumption of a product that is identified with the {@code
    +-  purchaseToken} in the {@code token} variable.
    ++  of the data that is returned in the {@code INAPP_PURCHASE_DATA} String by the Google
    ++  Play service following a successful purchase request. This example
    ++  records the consumption of a product that is identified with the {@code
    ++  purchaseToken} in the {@code token} variable:
    + </p>
    + 
    + <pre>
    + int response = mService.consumePurchase(3, getPackageName(), token);
    + </pre>
    + 
    +-<p class="note">
    +-  <strong>Warning:</strong> Do not call the {@code consumePurchase} method on
    +-  the main thread. Calling this method triggers a network request which could
    ++<p class="caution">
    ++  <strong>Warning:</strong> Don't call the {@code consumePurchase} method on
    ++  the main thread. Calling this method triggers a network request that could
    +   block your main thread. Instead, create a separate thread and call the {@code
    +-  consumePurchase} method from inside that thread.
    ++  consumePurchase} method from inside of that thread.
    + </p>
    + 
    + <p>
    +@@ -600,20 +619,20 @@ int response = mService.consumePurchase(3, getPackageName(), token);
    +   purchased.
    + </p>
    + 
    +-<p class="note">
    +-  <strong>Security Recommendation:</strong> You must send a consumption request
    ++<p class="caution">
    ++  <strong>Security Recommendation:</strong> Send a consumption request
    +   before provisioning the benefit of the consumable in-app purchase to the
    +-  user. Make sure that you have received a successful consumption response from
    ++  user. Ensure that you receive a successful consumption response from
    +   Google Play before you provision the item.
    + </p>
    + 
    +-<h3 id="Subs">Implementing Subscriptions</h3>
    ++<h3 id="Subs">Implementing subscriptions</h3>
    + 
    + <p>Launching a purchase flow for a subscription is similar to launching the
    + purchase flow for a product, with the exception that the product type must be set
    + to "subs". The purchase result is delivered to your Activity's
    + {@link android.app.Activity#onActivityResult onActivityResult} method, exactly
    +-as in the case of in-app products.</p>
    ++as in the case of in-app products. Here is an example:</p>
    + 
    + <pre>
    + Bundle bundle = mService.getBuyIntent(3, "com.example.myapp",
    +@@ -629,18 +648,18 @@ if (bundle.getInt(RESPONSE_CODE) == BILLING_RESPONSE_RESULT_OK) {
    + </pre>
    + 
    + <p>To query for active subscriptions, use the {@code getPurchases} method, again
    +-with the product type parameter set to "subs".</p>
    ++with the product type parameter set to "subs":</p>
    + 
    + <pre>
    + Bundle activeSubs = mService.getPurchases(3, "com.example.myapp",
    +                    "subs", continueToken);
    + </pre>
    + 
    +-<p>The call returns a {@code Bundle} with all the active subscriptions owned by
    +-the user. Once a subscription expires without renewal, it will no longer appear
    ++<p>The call returns a {@code Bundle} with all of the active subscriptions that are owned by
    ++the user. When a subscription expires without renewal, it no longer appears
    + in the returned {@code Bundle}.</p>
    + 
    +-<h2 id="billing-security">Securing Your Application</h2>
    ++<h2 id="billing-security">Securing your application</h2>
    + 
    + <p>To help ensure the integrity of the transaction information that is sent to
    + your application, Google Play signs the JSON string that contains the response
    +@@ -648,21 +667,21 @@ data for a purchase order. Google Play uses the private key that is associated
    + with your application in the Developer Console to create this signature. The
    + Developer Console generates an RSA key pair for each application.<p>
    + 
    +-<p class="note"><strong>Note:</strong>To find the public key portion of this key
    +-pair, open your application's details in the Developer Console, then click on
    +-<strong>Services &amp; APIs</strong>, and look at the field titled
    ++<p class="note"><strong>Note:</strong> To find the public key portion of this key
    ++pair, open your application's details in the Developer Console, click
    ++<strong>Services &amp; APIs</strong>, and review the field titled
    + <strong>Your License Key for This Application</strong>.</p>
    + 
    +-<p>The Base64-encoded RSA public key generated by Google Play is in binary
    ++<p>The Base64-encoded RSA public key that is generated by Google Play is in binary
    + encoded, X.509 subjectPublicKeyInfo DER SEQUENCE format. It is the same public
    + key that is used with Google Play licensing.</p>
    + 
    +-<p>When your application receives this signed response you can
    ++<p>When your application receives this signed response, you can
    + use the public key portion of your RSA key pair to verify the signature.
    +-By performing signature verification you can detect responses that have
    ++By performing signature verification, you can detect any responses that have
    + been tampered with or that have been spoofed. You can perform this signature
    + verification step in your application; however, if your application connects
    +-to a secure remote server then we recommend that you perform the signature
    ++to a secure remote server, Google recommends that you perform the signature
    + verification on that server.</p>
    + 
    + <p>For more information about best practices for security and design, see <a
    +diff --git a/docs/html/google/play/filters.jd b/docs/html/google/play/filters.jd
    +index 50cc807..a73b17f 100644
    +--- a/docs/html/google/play/filters.jd
    ++++ b/docs/html/google/play/filters.jd
    +@@ -382,9 +382,12 @@ characteristics that affect filtering on Google Play.</p>
    +   suspended, users will not be able to reinstall or update it, even if it appears in their Downloads.</p> </td></tr>
    +   <tr>
    +   <td valign="top">Priced
    +-    Status</td> <td valign="top"><p>Not all users can see paid apps. To show paid apps, a device
    +-must have a SIM card and be running Android 1.1 or later, and it must be in a
    +-country (as determined by SIM carrier) in which paid apps are available.</p></td>
    ++    Status</td> <td valign="top"><p>Not all users can see paid apps. To show
    ++    paid apps, a device must be running Android 1.1 or later, and it must be in
    ++    a country where paid apps are available. If a device has a SIM card, the SIM
    ++    carrier determines whether paid apps are available. If a device doesn't have
    ++    a SIM card, the device's IP address is used to determine whether the device
    ++    is in a country where paid apps are available.</p></td>
    + </tr> <tr>
    +   <td valign="top">Country Targeting</td> <td valign="top"> <p>When you upload your app to
    +     Google Play, you can select the countries in which to distribute your app
    +diff --git a/docs/html/guide/_book.yaml b/docs/html/guide/_book.yaml
    +index 20ee483..f09fe77 100644
    +--- a/docs/html/guide/_book.yaml
    ++++ b/docs/html/guide/_book.yaml
    +@@ -396,14 +396,16 @@ toc:
    +     path: /guide/topics/data/data-storage.html
    +   - title: Data Backup
    +     path: /guide/topics/data/backup.html
    ++    section:
    ++    - title: Auto Backup
    ++      path: /guide/topics/data/autobackup.html
    ++    - title: Key/Value Backup
    ++      path: /guide/topics/data/keyvaluebackup.html
    ++    - title: Testing Backup and Restore
    ++      path: /guide/topics/data/testingbackup.html
    +   - title: App Install Location
    +     path: /guide/topics/data/install-location.html
    + 
    +-- title: Libraries
    +-  path: /topic/libraries/index.html
    +-  section:
    +-  - include: /topic/libraries/_book.yaml
    +-
    + - title: Administration
    +   path: /guide/topics/admin/index.html
    +   section:
    +diff --git a/docs/html/guide/components/activities.jd b/docs/html/guide/components/activities.jd
    +index 9443924..e757288 100644
    +--- a/docs/html/guide/components/activities.jd
    ++++ b/docs/html/guide/components/activities.jd
    +@@ -624,8 +624,8 @@ android.app.Activity#onSaveInstanceState onSaveInstanceState()}.</p>
    + before making the activity vulnerable to destruction. The system passes this method
    + a {@link android.os.Bundle} in which you can save
    + state information about the activity as name-value pairs, using methods such as {@link
    +-android.os.BaseBundle#putString putString()} and {@link
    +-android.os.BaseBundle#putInt putInt()}. Then, if the system kills your application
    ++android.os.Bundle#putString putString()} and {@link
    ++android.os.Bundle#putInt putInt()}. Then, if the system kills your application
    + process and the user navigates back to your activity, the system recreates the activity and passes
    + the {@link android.os.Bundle} to both {@link android.app.Activity#onCreate onCreate()} and {@link
    + android.app.Activity#onRestoreInstanceState onRestoreInstanceState()}. Using either of these
    +diff --git a/docs/html/guide/components/bound-services.jd b/docs/html/guide/components/bound-services.jd
    +index f71ba87..2ee2061 100644
    +--- a/docs/html/guide/components/bound-services.jd
    ++++ b/docs/html/guide/components/bound-services.jd
    +@@ -8,19 +8,19 @@ parent.link=services.html
    + <ol id="qv">
    + <h2>In this document</h2>
    + <ol>
    +-  <li><a href="#Basics">The Basics</a></li>
    +-  <li><a href="#Creating">Creating a Bound Service</a>
    ++  <li><a href="#Basics">The basics</a></li>
    ++  <li><a href="#Creating">Creating a bound service</a>
    +     <ol>
    +       <li><a href="#Binder">Extending the Binder class</a></li>
    +       <li><a href="#Messenger">Using a Messenger</a></li>
    +     </ol>
    +   </li>
    +-  <li><a href="#Binding">Binding to a Service</a>
    ++  <li><a href="#Binding">Binding to a service</a>
    +     <ol>
    +       <li><a href="#Additional_Notes">Additional notes</a></li>
    +     </ol>
    +   </li>
    +-  <li><a href="#Lifecycle">Managing the Lifecycle of a Bound Service</a></li>
    ++  <li><a href="#Lifecycle">Managing the lifecycle of a bound service</a></li>
    + </ol>
    + 
    + <h2>Key classes</h2>
    +@@ -32,9 +32,13 @@ parent.link=services.html
    + 
    + <h2>Samples</h2>
    + <ol>
    +-  <li><a href="{@docRoot}resources/samples/ApiDemos/src/com/example/android/apis/app/RemoteService.html">{@code
    ++  <li><a
    ++ href="{@docRoot}resources/samples/ApiDemos/src/com/example/android/apis/app/RemoteService.html">
    ++  {@code
    +       RemoteService}</a></li>
    +-  <li><a href="{@docRoot}resources/samples/ApiDemos/src/com/example/android/apis/app/LocalService.html">{@code
    ++  <li><a
    ++ href="{@docRoot}resources/samples/ApiDemos/src/com/example/android/apis/app/LocalService.html">
    ++ {@code
    +       LocalService}</a></li>
    + </ol>
    + 
    +@@ -45,19 +49,23 @@ parent.link=services.html
    + </div>
    + 
    + 
    +-<p>A bound service is the server in a client-server interface. A bound service allows components
    +-(such as activities) to bind to the service, send requests, receive responses, and even perform
    ++<p>A bound service is the server in a client-server interface. It allows components
    ++(such as activities) to bind to the service, send requests, receive responses, and perform
    + interprocess communication (IPC). A bound service typically lives only while it serves another
    + application component and does not run in the background indefinitely.</p>
    + 
    +-<p>This document shows you how to create a bound service, including how to bind
    +-to the service from other application components. However, you should also refer to the <a
    +-href="{@docRoot}guide/components/services.html">Services</a> document for additional
    +-information about services in general, such as how to deliver notifications from a service, set
    +-the service to run in the foreground, and more.</p>
    ++<p class="note"><strong>Note:</strong> If your app targets Android 5.0 (API level 21) or later,
    ++it's recommended that you use the {@link android.app.job.JobScheduler} to execute background
    ++ services. For more information about {@link android.app.job.JobScheduler}, see its
    ++ {@link android.app.job.JobScheduler API-reference documentation}.</p>
    + 
    ++<p>This document describes how to create a bound service, including how to bind
    ++to the service from other application components. For additional information about services in
    ++ general, such as how to deliver notifications from a service and set the service to run
    ++ in the foreground, refer to the <a href="{@docRoot}guide/components/services.html">
    ++ Services</a> document.</p>
    + 
    +-<h2 id="Basics">The Basics</h2>
    ++<h2 id="Basics">The basics</h2>
    + 
    + <p>A bound service is an implementation of the {@link android.app.Service} class that allows
    + other applications to bind to it and interact with it. To provide binding for a
    +@@ -67,57 +75,61 @@ clients can use to interact with the service.</p>
    + 
    + <div class="sidebox-wrapper">
    + <div class="sidebox">
    +-  <h3>Binding to a Started Service</h3>
    ++  <h3>Binding to a started service</h3>
    + 
    + <p>As discussed in the <a href="{@docRoot}guide/components/services.html">Services</a>
    +-document, you can create a service that is both started and bound. That is, the service can be
    +-started by calling {@link android.content.Context#startService startService()}, which allows the
    +-service to run indefinitely, and also allow a client to bind to the service by calling {@link
    ++document, you can create a service that is both started and bound. That is, you can start a
    ++ service by calling {@link android.content.Context#startService startService()}, which allows the
    ++service to run indefinitely, and you can also allow a client to bind to the service by
    ++ calling {@link
    + android.content.Context#bindService bindService()}.
    +   <p>If you do allow your service to be started and bound, then when the service has been
    +-started, the system does <em>not</em> destroy the service when all clients unbind. Instead, you must
    +-explicitly stop the service, by calling {@link android.app.Service#stopSelf stopSelf()} or {@link
    ++started, the system does <em>not</em> destroy the service when all clients unbind.
    ++ Instead, you must
    ++explicitly stop the service by calling {@link android.app.Service#stopSelf stopSelf()} or {@link
    + android.content.Context#stopService stopService()}.</p>
    + 
    +-<p>Although you should usually implement either {@link android.app.Service#onBind onBind()}
    +-<em>or</em> {@link android.app.Service#onStartCommand onStartCommand()}, it's sometimes necessary to
    ++<p>Although you usually implement either {@link android.app.Service#onBind onBind()}
    ++<em>or</em> {@link android.app.Service#onStartCommand onStartCommand()}, it's sometimes
    ++ necessary to
    + implement both. For example, a music player might find it useful to allow its service to run
    + indefinitely and also provide binding. This way, an activity can start the service to play some
    + music and the music continues to play even if the user leaves the application. Then, when the user
    +-returns to the application, the activity can bind to the service to regain control of playback.</p>
    ++returns to the application, the activity can bind to the service to regain control of
    ++ playback.</p>
    + 
    +-<p>Be sure to read the section about <a href="#Lifecycle">Managing the Lifecycle of a Bound
    +-Service</a>, for more information about the service lifecycle when adding binding to a
    +-started service.</p>
    ++<p>For more information about the service lifecycle when adding binding to a started service,
    ++ see <a href="#Lifecycle">Managing the lifecycle of a bound Service</a>.</p>
    + </div>
    + </div>
    + 
    +-<p>A client can bind to the service by calling {@link android.content.Context#bindService
    ++<p>A client can bind to a service by calling {@link android.content.Context#bindService
    + bindService()}. When it does, it must provide an implementation of {@link
    + android.content.ServiceConnection}, which monitors the connection with the service. The {@link
    +-android.content.Context#bindService bindService()} method returns immediately without a value, but
    ++android.content.Context#bindService bindService()} method returns immediately without a
    ++ value, but
    + when the Android system creates the connection between the
    + client and service, it calls {@link
    + android.content.ServiceConnection#onServiceConnected onServiceConnected()} on the {@link
    + android.content.ServiceConnection}, to deliver the {@link android.os.IBinder} that
    + the client can use to communicate with the service.</p>
    + 
    +-<p>Multiple clients can connect to the service at once. However, the system calls your service's
    +-{@link android.app.Service#onBind onBind()} method to retrieve the {@link android.os.IBinder} only
    ++<p>Multiple clients can connect to a service simultaneously. However, the system calls your service's
    ++{@link android.app.Service#onBind onBind()} method to retrieve the
    ++ {@link android.os.IBinder} only
    + when the first client binds. The system then delivers the same {@link android.os.IBinder} to any
    +-additional clients that bind, without calling {@link android.app.Service#onBind onBind()} again.</p>
    ++additional clients that bind, without calling {@link android.app.Service#onBind onBind()}
    ++ again.</p>
    + 
    +-<p>When the last client unbinds from the service, the system destroys the service (unless the
    +-service was also started by {@link android.content.Context#startService startService()}).</p>
    ++<p>When the last client unbinds from the service, the system destroys the service, unless the
    ++service was also started by {@link android.content.Context#startService startService()}.</p>
    + 
    +-<p>When you implement your bound service, the most important part is defining the interface
    +-that your {@link android.app.Service#onBind onBind()} callback method returns. There are a few
    +-different ways you can define your service's {@link android.os.IBinder} interface and the following
    +-section discusses each technique.</p>
    ++<p>The most important part of your bound service implementation is defining the interface
    ++that your {@link android.app.Service#onBind onBind()} callback method returns. The following
    ++section discusses several different ways that you can define your service's
    ++ {@link android.os.IBinder} interface.</p>
    + 
    +-
    +-
    +-<h2 id="Creating">Creating a Bound Service</h2>
    ++<h2 id="Creating">Creating a bound service</h2>
    + 
    + <p>When creating a service that provides binding, you must provide an {@link android.os.IBinder}
    + that provides the programming interface that clients can use to interact with the service. There
    +@@ -125,12 +137,14 @@ are three ways you can define the interface:</p>
    + 
    + <dl>
    +   <dt><a href="#Binder">Extending the Binder class</a></dt>
    +-  <dd>If your service is private to your own application and runs in the same process as the client
    +-(which is common), you should create your interface by extending the {@link android.os.Binder} class
    ++  <dd>If your service is private to your own application and runs in the same process
    ++  as the client
    ++(which is common), you should create your interface by extending the {@link android.os.Binder}
    ++ class
    + and returning an instance of it from
    + {@link android.app.Service#onBind onBind()}. The client receives the {@link android.os.Binder} and
    + can use it to directly access public methods available in either the {@link android.os.Binder}
    +-implementation or even the {@link android.app.Service}.
    ++implementation or the {@link android.app.Service}.
    +   <p>This is the preferred technique when your service is merely a background worker for your own
    + application. The only reason you would not create your interface this way is because
    + your service is used by other applications or across separate processes.</dd>
    +@@ -143,20 +157,20 @@ android.os.Message} objects. This {@link android.os.Handler}
    + is the basis for a {@link android.os.Messenger} that can then share an {@link android.os.IBinder}
    + with the client, allowing the client to send commands to the service using {@link
    + android.os.Message} objects. Additionally, the client can define a {@link android.os.Messenger} of
    +-its own so the service can send messages back.
    ++its own, so the service can send messages back.
    +   <p>This is the simplest way to perform interprocess communication (IPC), because the {@link
    + android.os.Messenger} queues all requests into a single thread so that you don't have to design
    + your service to be thread-safe.</p>
    +   </dd>
    + 
    +-  <dt>Using AIDL</dt>
    +-  <dd>AIDL (Android Interface Definition Language) performs all the work to decompose objects into
    +-primitives that the operating system can understand and marshall them across processes to perform
    ++  <dt><a href="{@docRoot}guide/components/aidl.html">Using AIDL</a></dt>
    ++  <dd>Android Interface Definition Language (AIDL) decomposes objects into
    ++primitives that the operating system can understand and marshals them across processes to perform
    + IPC. The previous technique, using a {@link android.os.Messenger}, is actually based on AIDL as
    + its underlying structure. As mentioned above, the {@link android.os.Messenger} creates a queue of
    + all the client requests in a single thread, so the service receives requests one at a time. If,
    + however, you want your service to handle multiple requests simultaneously, then you can use AIDL
    +-directly. In this case, your service must be capable of multi-threading and be built thread-safe.
    ++directly. In this case, your service must be thread-safe and capable of multi-threading.
    +   <p>To use AIDL directly, you must
    + create an {@code .aidl} file that defines the programming interface. The Android SDK tools use
    + this file to generate an abstract class that implements the interface and handles IPC, which you
    +@@ -164,19 +178,18 @@ can then extend within your service.</p>
    +   </dd>
    + </dl>
    + 
    +-  <p class="note"><strong>Note:</strong> Most applications <strong>should not</strong> use AIDL to
    ++  <p class="note"><strong>Note:</strong> Most applications <em>shouldn't</em> use AIDL to
    + create a bound service, because it may require multithreading capabilities and
    +-can result in a more complicated implementation. As such, AIDL is not suitable for most applications
    ++can result in a more complicated implementation. As such, AIDL is not suitable for
    ++ most applications
    + and this document does not discuss how to use it for your service. If you're certain that you need
    + to use AIDL directly, see the <a href="{@docRoot}guide/components/aidl.html">AIDL</a>
    + document.</p>
    + 
    +-
    +-
    +-
    + <h3 id="Binder">Extending the Binder class</h3>
    + 
    +-<p>If your service is used only by the local application and does not need to work across processes,
    ++<p>If your service is used only by the local application and does not need to
    ++ work across processes,
    + then you can implement your own {@link android.os.Binder} class that provides your client direct
    + access to public methods in the service.</p>
    + 
    +@@ -187,13 +200,14 @@ background.</p>
    + 
    + <p>Here's how to set it up:</p>
    + <ol>
    +-  <li>In your service, create an instance of {@link android.os.Binder} that either:
    ++  <li>In your service, create an instance of {@link android.os.Binder} that does
    ++  one of the following:
    +     <ul>
    +-      <li>contains public methods that the client can call</li>
    +-      <li>returns the current {@link android.app.Service} instance, which has public methods the
    +-client can call</li>
    +-      <li>or, returns an instance of another class hosted by the service with public methods the
    +-client can call</li>
    ++      <li>Contains public methods that the client can call.</li>
    ++      <li>Returns the current {@link android.app.Service} instance, which has public methods the
    ++client can call.</li>
    ++      <li>Returns an instance of another class hosted by the service with public methods the
    ++client can call.</li>
    +     </ul>
    +   <li>Return this instance of {@link android.os.Binder} from the {@link
    + android.app.Service#onBind onBind()} callback method.</li>
    +@@ -202,12 +216,13 @@ android.content.ServiceConnection#onServiceConnected onServiceConnected()} callb
    + make calls to the bound service using the methods provided.</li>
    + </ol>
    + 
    +-<p class="note"><strong>Note:</strong> The reason the service and client must be in the same
    +-application is so the client can cast the returned object and properly call its APIs. The service
    ++<p class="note"><strong>Note:</strong> The service and client must be in the same
    ++application so that the client can cast the returned object and properly call its APIs.
    ++ The service
    + and client must also be in the same process, because this technique does not perform any
    +-marshalling across processes.</p>
    ++marshaling across processes.</p>
    + 
    +-<p>For example, here's a service that provides clients access to methods in the service through
    ++<p>For example, here's a service that provides clients with access to methods in the service through
    + a {@link android.os.Binder} implementation:</p>
    + 
    + <pre>
    +@@ -316,32 +331,30 @@ section provides more information about this process of binding to the service.<
    + <p class="note"><strong>Note:</strong> In the example above, the
    + {@link android.app.Activity#onStop onStop()} method unbinds the client from the service. Clients
    + should unbind from services at appropriate times, as discussed in
    +-<a href="#Additional_Notes">Additional Notes</a>.
    ++<a href="#Additional_Notes">Additional notes</a>.
    + </p>
    + 
    + <p>For more sample code, see the <a
    +-href="{@docRoot}resources/samples/ApiDemos/src/com/example/android/apis/app/LocalService.html">{@code
    ++href="{@docRoot}resources/samples/ApiDemos/src/com/example/android/apis/app/LocalService.html">
    ++{@code
    + LocalService.java}</a> class and the <a
    +-href="{@docRoot}resources/samples/ApiDemos/src/com/example/android/apis/app/LocalServiceActivities.html">{@code
    ++href="{@docRoot}resources/samples/ApiDemos/src/com/example/android/apis/app/LocalServiceActivities.html">
    ++{@code
    + LocalServiceActivities.java}</a> class in <a
    + href="{@docRoot}resources/samples/ApiDemos/index.html">ApiDemos</a>.</p>
    + 
    +-
    +-
    +-
    +-
    + <h3 id="Messenger">Using a Messenger</h3>
    + 
    + <div class="sidebox-wrapper">
    + <div class="sidebox">
    +   <h4>Compared to AIDL</h4>
    +   <p>When you need to perform IPC, using a {@link android.os.Messenger} for your interface is
    +-simpler than implementing it with AIDL, because {@link android.os.Messenger} queues
    +-all calls to the service, whereas, a pure AIDL interface sends simultaneous requests to the
    ++simpler than using AIDL, because {@link android.os.Messenger} queues
    ++all calls to the service. A pure AIDL interface sends simultaneous requests to the
    + service, which must then handle multi-threading.</p>
    +   <p>For most applications, the service doesn't need to perform multi-threading, so using a {@link
    + android.os.Messenger} allows the service to handle one call at a time. If it's important
    +-that your service be multi-threaded, then you should use <a
    ++that your service be multi-threaded, use <a
    + href="{@docRoot}guide/components/aidl.html">AIDL</a> to define your interface.</p>
    + </div>
    + </div>
    +@@ -352,10 +365,11 @@ you to perform interprocess communication (IPC) without the need to use AIDL.</p
    + 
    + <p>Here's a summary of how to use a {@link android.os.Messenger}:</p>
    + 
    +-<ul>
    ++<ol>
    +   <li>The service implements a {@link android.os.Handler} that receives a callback for each
    + call from a client.</li>
    +-  <li>The {@link android.os.Handler} is used to create a {@link android.os.Messenger} object
    ++  <li>The service uses the {@link android.os.Handler} to create a {@link android.os.Messenger}
    ++  object
    + (which is a reference to the {@link android.os.Handler}).</li>
    +   <li>The {@link android.os.Messenger} creates an {@link android.os.IBinder} that the service
    + returns to clients from {@link android.app.Service#onBind onBind()}.</li>
    +@@ -365,11 +379,12 @@ returns to clients from {@link android.app.Service#onBind onBind()}.</li>
    +   <li>The service receives each {@link android.os.Message} in its {@link
    + android.os.Handler}&mdash;specifically, in the {@link android.os.Handler#handleMessage
    + handleMessage()} method.</li>
    +-</ul>
    ++</ol>
    + 
    + 
    +-<p>In this way, there are no "methods" for the client to call on the service. Instead, the
    +-client delivers "messages" ({@link android.os.Message} objects) that the service receives in
    ++<p>In this way, there are no <em>methods</em> for the client to call on the service. Instead, the
    ++client delivers <em>messages</em> ({@link android.os.Message} objects) that the service
    ++ receives in
    + its {@link android.os.Handler}.</p>
    + 
    + <p>Here's a simple example service that uses a {@link android.os.Messenger} interface:</p>
    +@@ -488,41 +503,42 @@ public class ActivityMessenger extends Activity {
    + }
    + </pre>
    + 
    +-<p>Notice that this example does not show how the service can respond to the client. If you want the
    +-service to respond, then you need to also create a {@link android.os.Messenger} in the client. Then
    +-when the client receives the {@link android.content.ServiceConnection#onServiceConnected
    ++<p>Notice that this example does not show how the service can respond to the client.
    ++ If you want the
    ++service to respond, you need to also create a {@link android.os.Messenger} in the client.
    ++When the client receives the {@link android.content.ServiceConnection#onServiceConnected
    + onServiceConnected()} callback, it sends a {@link android.os.Message} to the service that includes
    + the client's {@link android.os.Messenger} in the {@link android.os.Message#replyTo} parameter
    + of the {@link android.os.Messenger#send send()} method.</p>
    + 
    + <p>You can see an example of how to provide two-way messaging in the <a
    +-href="{@docRoot}resources/samples/ApiDemos/src/com/example/android/apis/app/MessengerService.html">{@code
    ++href="{@docRoot}resources/samples/ApiDemos/src/com/example/android/apis/app/MessengerService.html">
    ++{@code
    + MessengerService.java}</a> (service) and <a
    +-href="{@docRoot}resources/samples/ApiDemos/src/com/example/android/apis/app/MessengerServiceActivities.html">{@code
    ++href="{@docRoot}resources/samples/ApiDemos/src/com/example/android/apis/app/MessengerServiceActivities.html">
    ++{@code
    + MessengerServiceActivities.java}</a> (client) samples.</p>
    + 
    +-
    +-
    +-
    +-
    +-<h2 id="Binding">Binding to a Service</h2>
    ++<h2 id="Binding">Binding to a service</h2>
    + 
    + <p>Application components (clients) can bind to a service by calling
    + {@link android.content.Context#bindService bindService()}. The Android
    + system then calls the service's {@link android.app.Service#onBind
    +-onBind()} method, which returns an {@link android.os.IBinder} for interacting with the service.</p>
    ++onBind()} method, which returns an {@link android.os.IBinder} for interacting with
    ++ the service.</p>
    + 
    +-<p>The binding is asynchronous. {@link android.content.Context#bindService
    +-bindService()} returns immediately and does <em>not</em> return the {@link android.os.IBinder} to
    +-the client. To receive the {@link android.os.IBinder}, the client must create an instance of {@link
    ++<p>The binding is asynchronous, and {@link android.content.Context#bindService
    ++bindService()} returns immediately without <em>not</em> returning the {@link android.os.IBinder} to
    ++the client. To receive the {@link android.os.IBinder}, the client must create an
    ++ instance of {@link
    + android.content.ServiceConnection} and pass it to {@link android.content.Context#bindService
    + bindService()}. The {@link android.content.ServiceConnection} includes a callback method that the
    + system calls to deliver the {@link android.os.IBinder}.</p>
    + 
    + <p class="note"><strong>Note:</strong> Only activities, services, and content providers can bind
    +-to a service&mdash;you <strong>cannot</strong> bind to a service from a broadcast receiver.</p>
    ++to a service&mdash;you <strong>can't</strong> bind to a service from a broadcast receiver.</p>
    + 
    +-<p>So, to bind to a service from your client, you must: </p>
    ++<p>To bind to a service from your client, follow these steps: </p>
    + <ol>
    +   <li>Implement {@link android.content.ServiceConnection}.
    +     <p>Your implementation must override two callback methods:</p>
    +@@ -533,7 +549,8 @@ the service's {@link android.app.Service#onBind onBind()} method.</dd>
    +       <dt>{@link android.content.ServiceConnection#onServiceDisconnected
    + onServiceDisconnected()}</dt>
    +         <dd>The Android system calls this when the connection to the service is unexpectedly
    +-lost, such as when the service has crashed or has been killed. This is <em>not</em> called when the
    ++lost, such as when the service has crashed or has been killed. This is <em>not</em>
    ++ called when the
    + client unbinds.</dd>
    +     </dl>
    +   </li>
    +@@ -548,12 +565,12 @@ android.content.Context#unbindService unbindService()}.
    +   <p>If your client is still bound to a service when your app destroys the client, destruction
    + causes the client to unbind. It is better practice to unbind the client as soon as it is done
    + interacting with the service. Doing so allows the idle service to shut down. For more information
    +-about appropriate times to bind and unbind, see <a href="#Additional_Notes">Additional Notes</a>.
    ++about appropriate times to bind and unbind, see <a href="#Additional_Notes">Additional notes</a>.
    + </p>
    +   </li>
    + </ol>
    + 
    +-<p>For example, the following snippet connects the client to the service created above by
    ++<p>The following example connects the client to the service created above by
    + <a href="#Binder">extending the Binder class</a>, so all it must do is cast the returned
    + {@link android.os.IBinder} to the {@code LocalService} class and request the {@code
    + LocalService} instance:</p>
    +@@ -579,8 +596,9 @@ private ServiceConnection mConnection = new ServiceConnection() {
    + };
    + </pre>
    + 
    +-<p>With this {@link android.content.ServiceConnection}, the client can bind to a service by passing
    +-it to {@link android.content.Context#bindService bindService()}. For example:</p>
    ++<p>With this {@link android.content.ServiceConnection}, the client can bind to a service
    ++ by passing
    ++it to {@link android.content.Context#bindService bindService()}, as shown in the following example:</p>
    + 
    + <pre>
    + Intent intent = new Intent(this, LocalService.class);
    +@@ -589,11 +607,21 @@ bindService(intent, mConnection, Context.BIND_AUTO_CREATE);
    + 
    + <ul>
    +   <li>The first parameter of {@link android.content.Context#bindService bindService()} is an
    +-{@link android.content.Intent} that explicitly names the service to bind (thought the intent
    +-could be implicit).</li>
    ++{@link android.content.Intent} that explicitly names the service to bind.
    ++<p class="caution"><strong>Caution:</strong> If you use an intent to bind to a
    ++ {@link android.app.Service}, ensure that your app is secure by using an <a href="{@docRoot}guide/components/intents-filters.html#Types">explicit</a>
    ++intent. Using an implicit intent to start a service is a
    ++security hazard because you can't be certain what service will respond to the intent,
    ++and the user can't see which service starts. Beginning with Android 5.0 (API level 21),
    ++ the system
    ++throws an exception if you call {@link android.content.Context#bindService bindService()}
    ++with an implicit intent.</p>
    ++</li>
    ++
    + <li>The second parameter is the {@link android.content.ServiceConnection} object.</li>
    + <li>The third parameter is a flag indicating options for the binding. It should usually be {@link
    +-android.content.Context#BIND_AUTO_CREATE} in order to create the service if its not already alive.
    ++android.content.Context#BIND_AUTO_CREATE} in order to create the service if it's not already
    ++ alive.
    + Other possible values are {@link android.content.Context#BIND_DEBUG_UNBIND}
    + and {@link android.content.Context#BIND_NOT_FOREGROUND}, or {@code 0} for none.</li>
    + </ul>
    +@@ -606,10 +634,11 @@ and {@link android.content.Context#BIND_NOT_FOREGROUND}, or {@code 0} for none.<
    +   <li>You should always trap {@link android.os.DeadObjectException} exceptions, which are thrown
    + when the connection has broken. This is the only exception thrown by remote methods.</li>
    +   <li>Objects are reference counted across processes. </li>
    +-  <li>You should usually pair the binding and unbinding during
    +-matching bring-up and tear-down moments of the client's lifecycle. For example:
    ++  <li>You usually pair the binding and unbinding during
    ++matching bring-up and tear-down moments of the client's lifecycle, as described in the
    ++ following examples:
    +     <ul>
    +-      <li>If you only need to interact with the service while your activity is visible, you
    ++      <li>If you need to interact with the service only while your activity is visible, you
    + should bind during {@link android.app.Activity#onStart onStart()} and unbind during {@link
    + android.app.Activity#onStop onStop()}.</li>
    +       <li>If you want your activity to receive responses even while it is stopped in the
    +@@ -619,33 +648,34 @@ activity needs to use the service the entire time it's running (even in the back
    + the service is in another process, then you increase the weight of the process and it becomes
    + more likely that the system will kill it.</li>
    +     </ul>
    +-    <p class="note"><strong>Note:</strong> You should usually <strong>not</strong> bind and unbind
    ++    <p class="note"><strong>Note:</strong> You <em>don't</em> usually bind and unbind
    + during your activity's {@link android.app.Activity#onResume onResume()} and {@link
    +-android.app.Activity#onPause onPause()}, because these callbacks occur at every lifecycle transition
    ++android.app.Activity#onPause onPause()}, because these callbacks occur at every
    ++ lifecycle transition
    + and you should keep the processing that occurs at these transitions to a minimum. Also, if
    +-multiple activities in your application bind to the same service and there is a transition between
    +-two of those activities, the service may be destroyed and recreated as the current activity unbinds
    +-(during pause) before the next one binds (during resume). (This activity transition for how
    ++multiple activities in your application bind to the same service and there is a
    ++ transition between
    ++two of those activities, the service may be destroyed and recreated as the current
    ++ activity unbinds
    ++(during pause) before the next one binds (during resume). This activity transition for how
    + activities coordinate their lifecycles is described in the <a
    + href="{@docRoot}guide/components/activities.html#CoordinatingActivities">Activities</a>
    +-document.)</p>
    ++document.</p>
    + </ul>
    + 
    + <p>For more sample code, showing how to bind to a service, see the <a
    +-href="{@docRoot}resources/samples/ApiDemos/src/com/example/android/apis/app/RemoteService.html">{@code
    ++href="{@docRoot}resources/samples/ApiDemos/src/com/example/android/apis/app/RemoteService.html">
    ++{@code
    + RemoteService.java}</a> class in <a
    + href="{@docRoot}resources/samples/ApiDemos/index.html">ApiDemos</a>.</p>
    + 
    +-
    +-
    +-
    +-
    +-<h2 id="Lifecycle">Managing the Lifecycle of a Bound Service</h2>
    ++<h2 id="Lifecycle">Managing the lifecycle of a bound service</h2>
    + 
    + <p>When a service is unbound from all clients, the Android system destroys it (unless it was also
    + started with {@link android.app.Service#onStartCommand onStartCommand()}). As such, you don't have
    + to manage the lifecycle of your service if it's purely a bound
    +-service&mdash;the Android system manages it for you based on whether it is bound to any clients.</p>
    ++service&mdash;the Android system manages it for you based on whether it is bound to
    ++ any clients.</p>
    + 
    + <p>However, if you choose to implement the {@link android.app.Service#onStartCommand
    + onStartCommand()} callback method, then you must explicitly stop the service, because the
    +@@ -660,17 +690,11 @@ your {@link android.app.Service#onUnbind onUnbind()} method, you can optionally
    + onRebind()} the next time a client binds to the service. {@link android.app.Service#onRebind
    + onRebind()} returns void, but the client still receives the {@link android.os.IBinder} in its
    + {@link android.content.ServiceConnection#onServiceConnected onServiceConnected()} callback.
    +-Below, figure 1 illustrates the logic for this kind of lifecycle.</p>
    +-
    ++The following figure illustrates the logic for this kind of lifecycle.</p>
    + 
    + <img src="{@docRoot}images/fundamentals/service_binding_tree_lifecycle.png" alt="" />
    + <p class="img-caption"><strong>Figure 1.</strong> The lifecycle for a service that is started
    + and also allows binding.</p>
    + 
    +-
    + <p>For more information about the lifecycle of a started service, see the <a
    + href="{@docRoot}guide/components/services.html#Lifecycle">Services</a> document.</p>
    +-
    +-
    +-
    +-
    +diff --git a/docs/html/guide/components/fundamentals.jd b/docs/html/guide/components/fundamentals.jd
    +index ed3ba7d..eaa82c8 100644
    +--- a/docs/html/guide/components/fundamentals.jd
    ++++ b/docs/html/guide/components/fundamentals.jd
    +@@ -6,28 +6,29 @@ page.title=Application Fundamentals
    + 
    + <h2>In this document</h2>
    + <ol>
    +-<li><a href="#Components">App Components</a>
    ++<li><a href="#Components">App components</a>
    +   <ol>
    +     <li><a href="#ActivatingComponents">Activating components</a></li>
    +   </ol>
    + </li>
    +-<li><a href="#Manifest">The Manifest File</a>
    ++<li><a href="#Manifest">The manifest file</a>
    +   <ol>
    +     <li><a href="#DeclaringComponents">Declaring components</a></li>
    +     <li><a href="#DeclaringRequirements">Declaring app requirements</a></li>
    +   </ol>
    + </li>
    +-<li><a href="#Resources">App Resources</a></li>
    ++<li><a href="#Resources">App resources</a></li>
    + </ol>
    + </div>
    + </div>
    + 
    + <p>Android apps are written in the Java programming language. The Android SDK tools compile
    +-your code&mdash;along with any data and resource files&mdash;into an APK: an <i>Android package</i>,
    ++your code along with any data and resource files into an APK, an <i>Android package</i>,
    + which is an archive file with an {@code .apk} suffix. One APK file contains all the contents
    + of an Android app and is the file that Android-powered devices use to install the app.</p>
    + 
    +-<p>Once installed on a device, each Android app lives in its own security sandbox: </p>
    ++<p>Each Android app lives in its own security sandbox, protected by
    ++ the following Android security features: </p>
    + 
    + <ul>
    +  <li>The Android operating system is a multi-user Linux system in which each app is a
    +@@ -40,54 +41,61 @@ app so that only the user ID assigned to that app can access them. </li>
    + <li>Each process has its own virtual machine (VM), so an app's code runs in isolation from
    + other apps.</li>
    + 
    +-<li>By default, every app runs in its own Linux process. Android starts the process when any
    +-of the app's components need to be executed, then shuts down the process when it's no longer
    ++<li>By default, every app runs in its own Linux process. The Android system starts
    ++ the process when any
    ++of the app's components need to be executed, and then shuts down the process
    ++ when it's no longer
    + needed or when the system must recover memory for other apps.</li>
    + </ul>
    + 
    +-<p>In this way, the Android system implements the <em>principle of least privilege</em>. That is,
    ++<p>The Android system implements the <em>principle of least privilege</em>. That is,
    + each app, by default, has access only to the components that it requires to do its work and
    + no more. This creates a very secure environment in which an app cannot access parts of
    +-the system for which it is not given permission.</p>
    +-
    +-<p>However, there are ways for an app to share data with other apps and for an
    ++the system for which it is not given permission. However, there are ways for an app to share
    ++ data with other apps and for an
    + app to access system services:</p>
    + 
    + <ul>
    +   <li>It's possible to arrange for two apps to share the same Linux user ID, in which case
    + they are able to access each other's files.  To conserve system resources, apps with the
    +-same user ID can also arrange to run in the same Linux process and share the same VM (the
    +-apps must also be signed with the same certificate).</li>
    ++same user ID can also arrange to run in the same Linux process and share the same VM. The
    ++apps must also be signed with the same certificate.</li>
    +   <li>An app can request permission to access device data such as the user's
    +-contacts, SMS messages, the mountable storage (SD card), camera, Bluetooth, and more. The user has
    ++contacts, SMS messages, the mountable storage (SD card), camera, and Bluetooth. The user has
    + to explicitly grant these permissions. For more information, see
    + <a href="{@docRoot}training/permissions/index.html">Working with System Permissions</a>.</li>
    + </ul>
    + 
    +-<p>That covers the basics regarding how an Android app exists within the system. The rest of
    +-this document introduces you to:</p>
    ++<p>The rest of this document introduces the following concepts:</p>
    + <ul>
    +   <li>The core framework components that define your app.</li>
    +-  <li>The manifest file in which you declare components and required device features for your
    ++  <li>The manifest file in which you declare the components and the required device
    ++  features for your
    + app.</li>
    +-  <li>Resources that are separate from the app code and allow your app to
    ++  <li>Resources that are separate from the app code and that allow your app to
    + gracefully optimize its behavior for a variety of device configurations.</li>
    + </ul>
    + 
    + 
    + 
    +-<h2 id="Components">App Components</h2>
    ++<h2 id="Components">App components</h2>
    + 
    + <p>App components are the essential building blocks of an Android app. Each
    + component is a different point through which the system can enter your app. Not all
    +-components are actual entry points for the user and some depend on each other, but each one exists
    +-as its own entity and plays a specific role&mdash;each one is a unique building block that
    +-helps define your app's overall behavior.</p>
    +-
    +-<p>There are four different types of app components. Each type serves a distinct purpose
    +-and has a distinct lifecycle that defines how the component is created and destroyed.</p>
    ++components are actual entry points for the user and some depend on each other,
    ++ but each one exists
    ++as its own entity and plays a specific role.</p>
    + 
    +-<p>Here are the four types of app components:</p>
    ++<p>There are four different types of app components:
    ++<ul>
    ++<li>Activities.</li>
    ++<li>Services.</li>
    ++<li>Content providers.</li>
    ++<li>Broadcast receivers.</li>
    ++</ul></p>
    ++Each type serves a distinct purpose
    ++and has a distinct lifecycle that defines how the component is created and destroyed.
    ++ The following sections describe the four types of app components.</p>
    + 
    + <dl>
    + 
    +@@ -98,11 +106,12 @@ an email app might have one activity that shows a list of new
    + emails, another activity to compose an email, and another activity for reading emails. Although
    + the activities work together to form a cohesive user experience in the email app, each one
    + is independent of the others. As such, a different app can start any one of these
    +-activities (if the email app allows it). For example, a camera app can start the
    +-activity in the email app that composes new mail, in order for the user to share a picture.
    ++activities if the email app allows it. For example, a camera app can start the
    ++activity in the email app that composes new mail to allow the user to share a picture.
    + 
    +-<p>An activity is implemented as a subclass of {@link android.app.Activity} and you can learn more
    +-about it in the <a href="{@docRoot}guide/components/activities.html">Activities</a>
    ++<p>An activity is implemented as a subclass of {@link android.app.Activity}. You can learn more
    ++about  {@link android.app.Activity} in the
    ++ <a href="{@docRoot}guide/components/activities.html">Activities</a>
    + developer guide.</p>
    + </dd>
    + 
    +@@ -111,13 +120,16 @@ developer guide.</p>
    + 
    + <dd>A <i>service</i> is a component that runs in the background to perform long-running
    + operations or to perform work for remote processes. A service
    +-does not provide a user interface. For example, a service might play music in the background while
    ++does not provide a user interface. For example, a service might play music in the
    ++ background while
    + the user is in a different app, or it might fetch data over the network without
    +-blocking user interaction with an activity. Another component, such as an activity, can start the
    ++blocking user interaction with an activity. Another component, such as an activity,
    ++ can start the
    + service and let it run or bind to it in order to interact with it.
    + 
    +-<p>A service is implemented as a subclass of {@link android.app.Service} and you can learn more
    +-about it in the <a href="{@docRoot}guide/components/services.html">Services</a> developer
    ++<p>A service is implemented as a subclass of {@link android.app.Service}. You can learn more
    ++about  {@link android.app.Service} in the <a href="{@docRoot}guide/components/services.html">
    ++Services</a> developer
    + guide.</p>
    + </dd>
    + 
    +@@ -125,12 +137,14 @@ guide.</p>
    + <dt><b>Content providers</b></dt>
    + 
    + <dd>A <i>content provider</i> manages a shared set of app data. You can store the data in
    +-the file system, an SQLite database, on the web, or any other persistent storage location your
    +-app can access. Through the content provider, other apps can query or even modify
    +-the data (if the content provider allows it). For example, the Android system provides a content
    ++the file system, in a SQLite database, on the web, or on any other persistent storage
    ++ location that your
    ++app can access. Through the content provider, other apps can query or modify
    ++the data if the content provider allows it. For example, the Android system provides a content
    + provider that manages the user's contact information. As such, any app with the proper
    +-permissions can query part of the content provider (such as {@link
    +-android.provider.ContactsContract.Data}) to read and write information about a particular person.
    ++permissions can query part of the content provider, such as {@link
    ++android.provider.ContactsContract.Data}, to read and write information about
    ++ a particular person.
    + 
    + <p>Content providers are also useful for reading and writing data that is private to your
    + app and not shared. For example, the <a
    +@@ -148,15 +162,17 @@ guide.</p>
    + <dt><b>Broadcast receivers</b></dt>
    + 
    + <dd>A <i>broadcast receiver</i> is a component that responds to system-wide broadcast
    +-announcements.  Many broadcasts originate from the system&mdash;for example, a broadcast announcing
    ++announcements.  Many broadcasts originate from the system&mdash;for example,
    ++ a broadcast announcing
    + that the screen has turned off, the battery is low, or a picture was captured.
    + Apps can also initiate broadcasts&mdash;for example, to let other apps know that
    +-some data has been downloaded to the device and is available for them to use. Although broadcast
    ++some data has been downloaded to the device and is available for them to use.
    ++ Although broadcast
    + receivers don't display a user interface, they may <a
    + href="{@docRoot}guide/topics/ui/notifiers/notifications.html">create a status bar notification</a>
    + to alert the user when a broadcast event occurs. More commonly, though, a broadcast receiver is
    +-just a "gateway" to other components and is intended to do a very minimal amount of work. For
    +-instance, it might initiate a service to perform some work based on the event.
    ++just a <em>gateway</em> to other components and is intended to do a very minimal amount of work.
    ++ For instance, it might initiate a service to perform some work based on the event.
    + 
    + <p>A broadcast receiver is implemented as a subclass of {@link android.content.BroadcastReceiver}
    + and each broadcast is delivered as an {@link android.content.Intent} object. For more information,
    +@@ -170,52 +186,59 @@ see the {@link android.content.BroadcastReceiver} class.</p>
    + <p>A unique aspect of the Android system design is that any app can start another
    + app’s component. For example, if you want the user to capture a
    + photo with the device camera, there's probably another app that does that and your
    +-app can use it, instead of developing an activity to capture a photo yourself. You don't
    ++app can use it instead of developing an activity to capture a photo yourself. You don't
    + need to incorporate or even link to the code from the camera app.
    + Instead, you can simply start the activity in the camera app that captures a
    + photo. When complete, the photo is even returned to your app so you can use it. To the user,
    + it seems as if the camera is actually a part of your app.</p>
    + 
    +-<p>When the system starts a component, it starts the process for that app (if it's not
    +-already running) and instantiates the classes needed for the component. For example, if your
    ++<p>When the system starts a component, it starts the process for that app if it's not
    ++already running and instantiates the classes needed for the component. For example, if your
    + app starts the activity in the camera app that captures a photo, that activity
    + runs in the process that belongs to the camera app, not in your app's process.
    + Therefore, unlike apps on most other systems, Android apps don't have a single entry
    +-point (there's no {@code main()} function, for example).</p>
    ++point (there's no {@code main()} function).</p>
    + 
    + <p>Because the system runs each app in a separate process with file permissions that
    + restrict access to other apps, your app cannot directly activate a component from
    +-another app. The Android system, however, can. So, to activate a component in
    +-another app, you must deliver a message to the system that specifies your <em>intent</em> to
    ++another app. However, the Android system can. To activate a component in
    ++another app, deliver a message to the system that specifies your <em>intent</em> to
    + start a particular component. The system then activates the component for you.</p>
    + 
    + 
    +-<h3 id="ActivatingComponents">Activating Components</h3>
    ++<h3 id="ActivatingComponents">Activating components</h3>
    + 
    + <p>Three of the four component types&mdash;activities, services, and
    + broadcast receivers&mdash;are activated by an asynchronous message called an <em>intent</em>.
    +-Intents bind individual components to each other at runtime (you can think of them
    +-as the messengers that request an action from other components), whether the component belongs
    ++Intents bind individual components to each other at runtime. You can think of them
    ++as the messengers that request an action from other components, whether the component belongs
    + to your app or another.</p>
    + 
    ++<p class="note"><strong>Note:</strong> If your app targets Android 5.0 (API level 21) or later,
    ++ use the {@link android.app.job.JobScheduler} to execute background
    ++ services. For more information about using this class, see the
    ++ {@link android.app.job.JobScheduler} reference documentation.</p>
    ++
    + <p>An intent is created with an {@link android.content.Intent} object, which defines a message to
    +-activate either a specific component or a specific <em>type</em> of component&mdash;an intent
    +-can be either explicit or implicit, respectively.</p>
    ++activate either a specific component (explicit intent) or a specific <em>type</em> of component
    ++ (implicit intent).</p>
    + 
    +-<p>For activities and services, an intent defines the action to perform (for example, to "view" or
    +-"send" something) and may specify the URI of the data to act on (among other things that the
    +-component being started might need to know). For example, an intent might convey a request for an
    ++<p>For activities and services, an intent defines the action to perform (for example, to
    ++ <em>view</em> or
    ++<em>send</em> something) and may specify the URI of the data to act on, among other things that the
    ++component being started might need to know. For example, an intent might convey a request for an
    + activity to show an image or to open a web page. In some cases, you can start an
    +-activity to receive a result, in which case, the activity also returns
    +-the result in an {@link android.content.Intent} (for example, you can issue an intent to let
    +-the user pick a personal contact and have it returned to you&mdash;the return intent includes a
    +-URI pointing to the chosen contact).</p>
    ++activity to receive a result, in which case the activity also returns
    ++the result in an {@link android.content.Intent}. For example, you can issue an intent to let
    ++the user pick a personal contact and have it returned to you. The return intent includes a
    ++URI pointing to the chosen contact.</p>
    + 
    + <p>For broadcast receivers, the intent simply defines the
    +-announcement being broadcast (for example, a broadcast to indicate the device battery is low
    +-includes only a known action string that indicates "battery is low").</p>
    ++announcement being broadcast. For example, a broadcast to indicate the device battery is low
    ++includes only a known action string that indicates <em>battery is low</em>.</p>
    + 
    +-<p>The other component type, content provider, is not activated by intents. Rather, it is
    ++<p>Unlike activities, services, and broadcast receivers, content providers are not activated
    ++ by intents. Rather, they are
    + activated when targeted by a request from a {@link android.content.ContentResolver}. The content
    + resolver handles all direct transactions with the content provider so that the component that's
    + performing transactions with the provider doesn't need to and instead calls methods on the {@link
    +@@ -224,15 +247,19 @@ provider and the component requesting information (for security).</p>
    + 
    + <p>There are separate methods for activating each type of component:</p>
    + <ul>
    +-  <li>You can start an activity (or give it something new to do) by
    ++  <li>You can start an activity or give it something new to do by
    + passing an {@link android.content.Intent} to {@link android.content.Context#startActivity
    + startActivity()} or {@link android.app.Activity#startActivityForResult startActivityForResult()}
    + (when you want the activity to return a result).</li>
    +-  <li>You can start a service (or give new instructions to an ongoing service) by
    ++
    ++
    ++  <li>With Android 5.0 (API level 21) and later, you can start a service with
    ++  {@link android.app.job.JobScheduler}. For earlier Android versions, you can start
    ++  a service (or give new instructions to an ongoing service) by
    + passing an {@link android.content.Intent} to {@link android.content.Context#startService
    +-startService()}. Or you can bind to the service by passing an {@link android.content.Intent} to
    +-{@link android.content.Context#bindService bindService()}.</li>
    +-  <li>You can initiate a broadcast by passing an {@link android.content.Intent} to methods like
    ++startService()}. You can bind to the service by passing an {@link android.content.Intent} to
    ++{@link android.content.Context#bindService bindService()}. </li>
    ++  <li>You can initiate a broadcast by passing an {@link android.content.Intent} to methods such as
    + {@link android.content.Context#sendBroadcast(Intent) sendBroadcast()}, {@link
    + android.content.Context#sendOrderedBroadcast(Intent, String) sendOrderedBroadcast()}, or {@link
    + android.content.Context#sendStickyBroadcast sendStickyBroadcast()}.</li>
    +@@ -242,35 +269,35 @@ android.content.ContentProvider#query query()} on a {@link android.content.Conte
    + 
    + <p>For more information about using intents, see the <a
    + href="{@docRoot}guide/components/intents-filters.html">Intents and
    +-Intent Filters</a> document. More information about activating specific components is also provided
    +-in the following documents: <a
    +-href="{@docRoot}guide/components/activities.html">Activities</a>, <a
    +-href="{@docRoot}guide/components/services.html">Services</a>, {@link
    +-android.content.BroadcastReceiver} and <a
    +-href="{@docRoot}guide/topics/providers/content-providers.html">Content Providers</a>.</p>
    +-
    ++Intent Filters</a> document.
    ++ The following documents provide more information about activating specifc components:
    ++ <a href="{@docRoot}guide/components/activities.html">Activities</a>,
    ++ <a href="{@docRoot}guide/components/services.html">Services
    ++ {@link android.content.BroadcastReceiver}, and
    ++ <a ref="{@docRoot}guide/topics/providers/content-providers.html">Content Providers</a>.</p>
    + 
    +-<h2 id="Manifest">The Manifest File</h2>
    ++<h2 id="Manifest">The manifest file</h2>
    + 
    + <p>Before the Android system can start an app component, the system must know that the
    +-component exists by reading the app's {@code AndroidManifest.xml} file (the "manifest"
    +-file). Your app must declare all its components in this file, which must be at the root of
    +-the app project directory.</p>
    ++component exists by reading the app's <em>manifest file</em>, {@code AndroidManifest.xml}.
    ++ Your app must declare all its components in this file, which must be at the root of the
    ++ app project directory.</p>
    + 
    + <p>The manifest does a number of things in addition to declaring the app's components,
    +-such as:</p>
    ++such as the following:</p>
    + <ul>
    +-  <li>Identify any user permissions the app requires, such as Internet access or
    ++  <li>Identifies any user permissions the app requires, such as Internet access or
    + read-access to the user's contacts.</li>
    +-  <li>Declare the minimum <a href="{@docRoot}guide/topics/manifest/uses-sdk-element.html#ApiLevels">API Level</a>
    ++  <li>Declares the minimum
    ++  <a href="{@docRoot}guide/topics/manifest/uses-sdk-element.html#ApiLevels">API Level</a>
    + required by the app, based on which APIs the app uses.</li>
    +-  <li>Declare hardware and software features used or required by the app, such as a camera,
    ++  <li>Declares hardware and software features used or required by the app, such as a camera,
    + bluetooth services, or a multitouch screen.</li>
    +-  <li>API libraries the app needs to be linked against (other than the Android framework
    ++  <li>Declares API libraries the app needs to be linked against (other than the Android framework
    + APIs), such as the <a
    +-href="http://code.google.com/android/add-ons/google-apis/maps-overview.html">Google Maps
    +-library</a>.</li>
    +-  <li>And more</li>
    ++href="http://code.google.com/android/add-ons/google-apis/maps-overview.html">
    ++Google Maps library</a>.</li>
    ++
    + </ul>
    + 
    + 
    +@@ -301,47 +328,59 @@ the {@code android:name} attribute specifies the fully qualified class name of t
    + android.app.Activity} subclass and the {@code android:label} attribute specifies a string
    + to use as the user-visible label for the activity.</p>
    + 
    +-<p>You must declare all app components this way:</p>
    ++<p>You must declare all app components using the following elements:</p>
    + <ul>
    +   <li><code><a
    + href="{@docRoot}guide/topics/manifest/activity-element.html">&lt;activity&gt;</a></code> elements
    +-for activities</li>
    ++for activities.</li>
    +   <li><code><a
    + href="{@docRoot}guide/topics/manifest/service-element.html">&lt;service&gt;</a></code> elements for
    +-services</li>
    ++services.</li>
    +   <li><code><a
    + href="{@docRoot}guide/topics/manifest/receiver-element.html">&lt;receiver&gt;</a></code> elements
    +-for broadcast receivers</li>
    ++for broadcast receivers.</li>
    +   <li><code><a
    + href="{@docRoot}guide/topics/manifest/provider-element.html">&lt;provider&gt;</a></code> elements
    +-for content providers</li>
    ++for content providers.</li>
    + </ul>
    + 
    + <p>Activities, services, and content providers that you include in your source but do not declare
    + in the manifest are not visible to the system and, consequently, can never run.  However,
    + broadcast
    +-receivers can be either declared in the manifest or created dynamically in code (as
    +-{@link android.content.BroadcastReceiver} objects) and registered with the system by calling
    ++receivers can be either declared in the manifest or created dynamically in code as
    ++{@link android.content.BroadcastReceiver} objects and registered with the system by calling
    + {@link android.content.Context#registerReceiver registerReceiver()}.</p>
    + 
    + <p>For more about how to structure the manifest file for your app, see <a
    + href="{@docRoot}guide/topics/manifest/manifest-intro.html">The AndroidManifest.xml File</a>
    + documentation. </p>
    + 
    ++<h3 id="DeclaringComponentCapabilities">Declaring component capabilities</h3>
    + 
    ++<p>As discussed above, in <a href="#ActivatingComponents">Activating components</a>, you can use an
    ++{@link android.content.Intent} to start activities, services, and broadcast receivers.
    + 
    +-<h3 id="DeclaringComponentCapabilities">Declaring component capabilities</h3>
    + 
    +-<p>As discussed above, in <a href="#ActivatingComponents">Activating Components</a>, you can use an
    +-{@link android.content.Intent} to start activities, services, and broadcast receivers. You can do so
    +-by explicitly naming the target component (using the component class name) in the intent. However,
    +-the real power of intents lies in the concept of <em>implicit intents</em>. An implicit intent
    +-simply describes the type of action to perform (and, optionally, the data upon which you’d like to
    +-perform the action) and allows the system to find a component on the device that can perform the
    +-action and start it. If there are multiple components that can perform the action described by the
    +-intent, then the user selects which one to use.</p>
    + 
    +-<p>The way the system identifies the components that can respond to an intent is by comparing the
    ++You can use an {@link android.content.Intent}
    ++ by explicitly naming the target component (using the component class name) in the intent.
    ++ You can also use an implicit intent, which
    ++describes the type of action to perform and, optionally, the data upon which you’d like to
    ++perform the action. The implicit intent allows the system to find a component on the device
    ++ that can perform the
    ++action and start it. If there are multiple components that can perform the action described by the
    ++intent, the user selects which one to use.</p>
    ++
    ++<p class="caution"><strong>Caution:</strong> If you use an intent to start a
    ++ {@link android.app.Service}, ensure that your app is secure by using an
    ++ <a href="{@docRoot}guide/components/intents-filters.html#Types">explicit</a>
    ++intent. Using an implicit intent to start a service is a
    ++security hazard because you cannot be certain what service will respond to the intent,
    ++and the user cannot see which service starts. Beginning with Android 5.0 (API level 21), the system
    ++throws an exception if you call {@link android.content.Context#bindService bindService()}
    ++with an implicit intent. Do not declare intent filters for your services. </p>
    ++
    ++<p>The system identifies the components that can respond to an intent by comparing the
    + intent received to the <i>intent filters</i> provided in the manifest file of other apps on
    + the device.</p>
    + 
    +@@ -351,8 +390,9 @@ from other apps. You can declare an intent filter for your component by
    + adding an <a href="{@docRoot}guide/topics/manifest/intent-filter-element.html">{@code
    + <intent-filter>}</a> element as a child of the component's declaration element.</p>
    + 
    +-<p>For example, if you've built an email app with an activity for composing a new email, you can
    +-declare an intent filter to respond to "send" intents (in order to send a new email) like this:</p>
    ++<p>For example, if you build an email app with an activity for composing a new email, you can
    ++declare an intent filter to respond to "send" intents (in order to send a new email),
    ++ as shown in the following example:</p>
    + <pre>
    + &lt;manifest ... >
    +     ...
    +@@ -368,8 +408,9 @@ declare an intent filter to respond to "send" intents (in order to send a new em
    + &lt;/manifest>
    + </pre>
    + 
    +-<p>Then, if another app creates an intent with the {@link
    +-android.content.Intent#ACTION_SEND} action and passes it to {@link android.app.Activity#startActivity
    ++<p>If another app creates an intent with the {@link
    ++android.content.Intent#ACTION_SEND} action and passes it to
    ++ {@link android.app.Activity#startActivity
    + startActivity()}, the system may start your activity so the user can draft and send an
    + email.</p>
    + 
    +@@ -382,7 +423,7 @@ href="{@docRoot}guide/components/intents-filters.html">Intents and Intent Filter
    + <h3 id="DeclaringRequirements">Declaring app requirements</h3>
    + 
    + <p>There are a variety of devices powered by Android and not all of them provide the
    +-same features and capabilities. In order to prevent your app from being installed on devices
    ++same features and capabilities. To prevent your app from being installed on devices
    + that lack features needed by your app, it's important that you clearly define a profile for
    + the types of devices your app supports by declaring device and software requirements in your
    + manifest file. Most of these declarations are informational only and the system does not read
    +@@ -391,7 +432,7 @@ for users when they search for apps from their device.</p>
    + 
    + <p>For example, if your app requires a camera and uses APIs introduced in Android 2.1 (<a
    + href="{@docRoot}guide/topics/manifest/uses-sdk-element.html#ApiLevels">API Level</a> 7),
    +-you should declare these as requirements in your manifest file like this:</p>
    ++you must declare these as requirements in your manifest file as shown in the following example:</p>
    + 
    + <pre>
    + &lt;manifest ... >
    +@@ -402,10 +443,10 @@ you should declare these as requirements in your manifest file like this:</p>
    + &lt;/manifest>
    + </pre>
    + 
    +-<p>Now, devices that do <em>not</em> have a camera and have an
    +-Android version <em>lower</em> than 2.1 cannot install your app from Google Play.</p>
    +-
    +-<p>However, you can also declare that your app uses the camera, but does not
    ++<p>With the declarations shown in the example, devices that do <em>not</em> have a
    ++ camera and have an
    ++Android version <em>lower</em> than 2.1 cannot install your app from Google Play.
    ++ However, you can declare that your app uses the camera, but does not
    + <em>require</em> it. In that case, your app must set the <a href=
    + "{@docRoot}guide/topics/manifest/uses-feature-element.html#required">{@code required}</a>
    + attribute to {@code "false"} and check at runtime whether
    +@@ -417,15 +458,15 @@ document.</p>
    + 
    + 
    + 
    +-<h2 id="Resources">App Resources</h2>
    ++<h2 id="Resources">App resources</h2>
    + 
    + <p>An Android app is composed of more than just code&mdash;it requires resources that are
    + separate from the source code, such as images, audio files, and anything relating to the visual
    +-presentation of the app. For example, you should define animations, menus, styles, colors,
    ++presentation of the app. For example, you can define animations, menus, styles, colors,
    + and the layout of activity user interfaces with XML files. Using app resources makes it easy
    +-to update various characteristics of your app without modifying code and&mdash;by providing
    +-sets of alternative resources&mdash;enables you to optimize your app for a  variety of
    +-device configurations (such as different languages and screen sizes).</p>
    ++to update various characteristics of your app without modifying code. Providing
    ++sets of alternative resources enables you to optimize your app for a variety of
    ++device configurations, such as different languages and screen sizes.</p>
    + 
    + <p>For every resource that you include in your Android project, the SDK build tools define a unique
    + integer ID, which you can use to reference the resource from your app code or from
    +@@ -435,20 +476,22 @@ named {@code R.drawable.logo}, which you can use to reference the image and inse
    + user interface.</p>
    + 
    + <p>One of the most important aspects of providing resources separate from your source code
    +-is the ability for you to provide alternative resources for different device
    +-configurations. For example, by defining UI strings in XML, you can translate the strings into other
    +-languages and save those strings in separate files. Then, based on a language <em>qualifier</em>
    ++is the ability to provide alternative resources for different device
    ++configurations. For example, by defining UI strings in XML, you can translate
    ++ the strings into other
    ++languages and save those strings in separate files. Then Android applies the
    ++ appropriate language strings
    ++to your UI based on a language <em>qualifier</em>
    + that you append to the resource directory's name (such as {@code res/values-fr/} for French string
    +-values) and the user's language setting, the Android system applies the appropriate language strings
    +-to your UI.</p>
    ++values) and the user's language setting.</p>
    + 
    + <p>Android supports many different <em>qualifiers</em> for your alternative resources. The
    + qualifier is a short string that you include in the name of your resource directories in order to
    +-define the device configuration for which those resources should be used. As another
    +-example, you should often create different layouts for your activities, depending on the
    +-device's screen orientation and size. For example, when the device screen is in portrait
    ++define the device configuration for which those resources should be used. For
    ++example, you should create different layouts for your activities, depending on the
    ++device's screen orientation and size. When the device screen is in portrait
    + orientation (tall), you might want a layout with buttons to be vertical, but when the screen is in
    +-landscape orientation (wide), the buttons should be aligned horizontally. To change the layout
    ++landscape orientation (wide), the buttons could be aligned horizontally. To change the layout
    + depending on the orientation, you can define two different layouts and apply the appropriate
    + qualifier to each layout's directory name. Then, the system automatically applies the appropriate
    + layout depending on the current device orientation.</p>
    +@@ -465,15 +508,15 @@ create alternative resources for different device configurations, read <a href=
    +   <dl>
    +     <dt><a href="{@docRoot}guide/components/intents-filters.html">Intents and Intent Filters</a>
    +     </dt>
    +-    <dd>Information about how to use the {@link android.content.Intent} APIs to
    ++    <dd>How to use the {@link android.content.Intent} APIs to
    +     activate app components, such as activities and services, and how to make your app components
    +     available for use by other apps.</dd>
    +     <dt><a href="{@docRoot}guide/components/activities.html">Activities</a></dt>
    +-    <dd>Information about how to create an instance of the {@link android.app.Activity} class,
    ++    <dd>How to create an instance of the {@link android.app.Activity} class,
    +     which provides a distinct screen in your application with a user interface.</dd>
    +     <dt><a
    + href="{@docRoot}guide/topics/resources/providing-resources.html">Providing Resources</a></dt>
    +-    <dd>Information about how Android apps are structured to separate app resources from the
    ++    <dd>How Android apps are structured to separate app resources from the
    +    app code, including how you can provide alternative resources for specific device
    +    configurations.
    +     </dd>
    +@@ -484,14 +527,13 @@ href="{@docRoot}guide/topics/resources/providing-resources.html">Providing Resou
    +   <dl>
    +     <dt><a href="{@docRoot}guide/practices/compatibility.html"
    +         >Device Compatibility</a></dt>
    +-    <dd>Information about Android works on different types of devices and an introduction
    ++    <dd>How Android works on different types of devices and an introduction
    +     to how you can optimize your app for each device or restrict your app's availability
    +     to different devices.</dd>
    +     <dt><a href="{@docRoot}guide/topics/security/permissions.html"
    +         >System Permissions</a></dt>
    +-    <dd>Information about how Android restricts app access to certain APIs with a permission
    ++    <dd>How Android restricts app access to certain APIs with a permission
    +     system that requires the user's consent for your app to use those APIs.</dd>
    +   </dl>
    + </div>
    + </div>
    +-
    +diff --git a/docs/html/guide/components/intents-common.jd b/docs/html/guide/components/intents-common.jd
    +index e6c9fc6..47174d2 100644
    +--- a/docs/html/guide/components/intents-common.jd
    ++++ b/docs/html/guide/components/intents-common.jd
    +@@ -2155,7 +2155,7 @@ that are available.</p>
    + <p><b>Example intent:</b></p>
    + <pre>
    + public void openWifiSettings() {
    +-    Intent intent = new Intent(Intent.ACTION_WIFI_SETTINGS);
    ++    Intent intent = new Intent(Settings.ACTION_WIFI_SETTINGS);
    +     if (intent.resolveActivity(getPackageManager()) != null) {
    +         startActivity(intent);
    +     }
    +diff --git a/docs/html/guide/components/intents-filters.jd b/docs/html/guide/components/intents-filters.jd
    +index d1d8c78..8f41bc3 100644
    +--- a/docs/html/guide/components/intents-filters.jd
    ++++ b/docs/html/guide/components/intents-filters.jd
    +@@ -7,21 +7,21 @@ page.tags="IntentFilter"
    + 
    + <h2>In this document</h2>
    + <ol>
    +-  <li><a href="#Types">Intent Types</a></li>
    +-  <li><a href="#Building">Building an Intent</a>
    ++  <li><a href="#Types">Intent types</a></li>
    ++  <li><a href="#Building">Building an intent</a>
    +     <ol>
    +       <li><a href="#ExampleExplicit">Example explicit intent</a></li>
    +       <li><a href="#ExampleSend">Example implicit intent</a></li>
    +       <li><a href="#ForceChooser">Forcing an app chooser</a></li>
    +     </ol>
    +   </li>
    +-  <li><a href="#Receiving">Receiving an Implicit Intent</a>
    ++  <li><a href="#Receiving">Receiving an implicit intent</a>
    +     <ol>
    +       <li><a href="#ExampleFilters">Example filters</a></li>
    +     </ol>
    +   </li>
    +-  <li><a href="#PendingIntent">Using a Pending Intent</a></li>
    +-  <li><a href="#Resolution">Intent Resolution</a>
    ++  <li><a href="#PendingIntent">Using a pending intent</a></li>
    ++  <li><a href="#Resolution">Intent resolution</a>
    +     <ol>
    +       <li><a href="#ActionTest">Action test</a></li>
    +       <li><a href="#CategoryTest">Category test</a></li>
    +@@ -46,13 +46,14 @@ page.tags="IntentFilter"
    + <p>An {@link android.content.Intent} is a messaging object you can use to request an action
    + from another <a href="{@docRoot}guide/components/fundamentals.html#Components">app component</a>.
    + Although intents facilitate communication between components in several ways, there are three
    +-fundamental use-cases:</p>
    ++fundamental use cases:</p>
    + 
    + <ul>
    +-<li><b>To start an activity:</b>
    ++<li><b>Starting an activity</b>
    + <p>An {@link android.app.Activity} represents a single screen in an app. You can start a new
    + instance of an {@link android.app.Activity} by passing an {@link android.content.Intent}
    +-to {@link android.content.Context#startActivity startActivity()}. The {@link android.content.Intent}
    ++to {@link android.content.Context#startActivity startActivity()}.
    ++ The {@link android.content.Intent}
    + describes the activity to start and carries any necessary data.</p>
    + 
    + <p>If you want to receive a result from the activity when it finishes,
    +@@ -63,10 +64,16 @@ android.app.Activity#onActivityResult onActivityResult()} callback.
    + For more information, see the <a
    + href="{@docRoot}guide/components/activities.html">Activities</a> guide.</p></li>
    + 
    +-<li><b>To start a service:</b>
    ++<li><b>Starting a service</b>
    + <p>A {@link android.app.Service} is a component that performs operations in the background
    +-without a user interface. You can start a service to perform a one-time operation
    +-(such as download a file) by passing an {@link android.content.Intent}
    ++without a user interface. With Android 5.0 (API level 21) and later, you can start a service
    ++ with {@link android.app.job.JobScheduler}. For more information
    ++ about {@link android.app.job.JobScheduler}, see its
    ++    {@link android.app.job.JobScheduler API-reference documentation}.</p>
    ++<p>For versions earlier than Android 5.0 (API level 21), you can start a service by using
    ++methods of the  {@link android.app.Service} class. You can start a service
    ++ to perform a one-time operation
    ++(such as downloading a file) by passing an {@link android.content.Intent}
    + to {@link android.content.Context#startService startService()}. The {@link android.content.Intent}
    + describes the service to start and carries any necessary data.</p>
    + 
    +@@ -75,7 +82,7 @@ from another component by passing an {@link android.content.Intent} to {@link
    + android.content.Context#bindService bindService()}</code>. For more information, see the <a
    + href="{@docRoot}guide/components/services.html">Services</a> guide.</p></li>
    + 
    +-<li><b>To deliver a broadcast:</b>
    ++<li><b>Delivering a broadcast</b>
    + <p>A broadcast is a message that any app can receive. The system delivers various
    + broadcasts for system events, such as when the system boots up or the device starts charging.
    + You can deliver a broadcast to other apps by passing an {@link android.content.Intent}
    +@@ -89,7 +96,7 @@ android.content.Context#sendStickyBroadcast sendStickyBroadcast()}.</p>
    + 
    + 
    + 
    +-<h2 id="Types">Intent Types</h2>
    ++<h2 id="Types">Intent types</h2>
    + 
    + <p>There are two types of intents:</p>
    + 
    +@@ -97,7 +104,7 @@ android.content.Context#sendStickyBroadcast sendStickyBroadcast()}.</p>
    + <li><b>Explicit intents</b> specify the component to start by name (the
    + fully-qualified class name). You'll typically use an explicit intent to start a component in
    + your own app, because you know the class name of the activity or service you want to start. For
    +-example, start a new activity in response to a user action or start a service to download
    ++example, you can start a new activity in response to a user action or start a service to download
    + a file in the background.</li>
    + 
    + <li><b>Implicit intents</b> do not name a specific component, but instead declare a general action
    +@@ -106,12 +113,13 @@ show the user a location on a map, you can use an implicit intent to request tha
    + app show a specified location on a map.</li>
    + </ul>
    + 
    +-<p>When you create an explicit intent to start an activity or service, the system immediately
    ++<p>Figure 1 shows how an intent is delivered to start an activity. When you create an
    ++ explicit intent to start an activity or service, the system immediately
    + starts the app component specified in the {@link android.content.Intent} object.</p>
    + 
    + <div class="figure" style="width:446px">
    + <img src="{@docRoot}images/components/intent-filters@2x.png" width="446" alt=""/>
    +-<p class="img-caption"><strong>Figure 1.</strong> Illustration of how an implicit intent is
    ++<p class="img-caption"><strong>Figure 1.</strong> How an implicit intent is
    + delivered through the system to start another activity: <b>[1]</b> <em>Activity A</em> creates an
    + {@link android.content.Intent} with an action description and passes it to {@link
    + android.content.Context#startActivity startActivity()}. <b>[2]</b> The Android System searches all
    +@@ -135,11 +143,12 @@ you make it possible for other apps to directly start your activity with a certa
    + Likewise, if you do <em>not</em> declare any intent filters for an activity, then it can be started
    + only with an explicit intent.</p>
    + 
    +-<p class="caution"><strong>Caution:</strong> To ensure your app is secure, always use an explicit
    ++<p class="caution"><strong>Caution:</strong> To ensure that your app is secure, always
    ++ use an explicit
    + intent when starting a {@link android.app.Service} and do not
    + declare intent filters for your services. Using an implicit intent to start a service is a
    +-security hazard because you cannot be certain what service will respond to the intent,
    +-and the user cannot see which service starts. Beginning with Android 5.0 (API level 21), the system
    ++security hazard because you can't be certain what service will respond to the intent,
    ++and the user can't see which service starts. Beginning with Android 5.0 (API level 21), the system
    + throws an exception if you call {@link android.content.Context#bindService bindService()}
    + with an implicit intent.</p>
    + 
    +@@ -147,7 +156,7 @@ with an implicit intent.</p>
    + 
    + 
    + 
    +-<h2 id="Building">Building an Intent</h2>
    ++<h2 id="Building">Building an intent</h2>
    + 
    + <p>An {@link android.content.Intent} object carries information that the Android system uses
    + to determine which component to start (such as the exact component name or component
    +@@ -163,22 +172,23 @@ order to properly perform the action (such as the action to take and the data to
    + <dd>The name of the component to start.
    + 
    + <p>This is optional, but it's the critical piece of information that makes an intent
    +-<b>explicit</b>, meaning that the intent should be delivered only to the app component
    +-defined by the component name. Without a component name, the intent is <b>implicit</b> and the
    ++<em>explicit</em>, meaning that the intent should be delivered only to the app component
    ++defined by the component name. Without a component name, the intent is <em>implicit</em> and the
    + system decides which component should receive the intent based on the other intent information
    +-(such as the action, data, and category&mdash;described below). So if you need to start a specific
    ++(such as the action, data, and category&mdash;described below). If you need to start a specific
    + component in your app, you should specify the component name.</p>
    + 
    +-<p class="note"><strong>Note:</strong> When starting a {@link android.app.Service}, you should
    +-<strong>always specify the component name</strong>. Otherwise, you cannot be certain what service
    ++<p class="note"><strong>Note:</strong> When starting a {@link android.app.Service},
    ++ <em>always specify the component name</em>. Otherwise, you cannot be certain what service
    + will respond to the intent, and the user cannot see which service starts.</p>
    + 
    + <p>This field of the {@link android.content.Intent} is a
    + {@link android.content.ComponentName} object, which you can specify using a fully
    +-qualified class name of the target component, including the package name of the app. For example,
    ++qualified class name of the target component, including the package name of the app, for example,
    + {@code com.example.ExampleActivity}. You can set the component name with {@link
    + android.content.Intent#setComponent setComponent()}, {@link android.content.Intent#setClass
    +-setClass()}, {@link android.content.Intent#setClassName(String, String) setClassName()}, or with the
    ++setClass()}, {@link android.content.Intent#setClassName(String, String) setClassName()},
    ++ or with the
    + {@link android.content.Intent} constructor.</p>
    + 
    + </dd>
    +@@ -188,10 +198,10 @@ setClass()}, {@link android.content.Intent#setClassName(String, String) setClass
    + 
    + <p>In the case of a broadcast intent, this is the action that took place and is being reported.
    + The action largely determines how the rest of the intent is structured&mdash;particularly
    +-what is contained in the data and extras.
    ++the information that is contained in the data and extras.
    + 
    + <p>You can specify your own actions for use by intents within your app (or for use by other
    +-apps to invoke components in your app), but you should usually use action constants
    ++apps to invoke components in your app), but you usually specify action constants
    + defined by the {@link android.content.Intent} class or other framework classes. Here are some
    + common actions for starting an activity:</p>
    + 
    +@@ -203,7 +213,7 @@ common actions for starting an activity:</p>
    +    view in a map app.</dd>
    + 
    + <dt>{@link android.content.Intent#ACTION_SEND}</dt>
    +-   <dd>Also known as the "share" intent, you should use this in an intent with {@link
    ++   <dd>Also known as the <em>share</em> intent, you should use this in an intent with {@link
    +    android.content.Context#startActivity startActivity()} when you have some data that the user can
    +    share through another app, such as an email app or social sharing app.</dd>
    + </dl>
    +@@ -217,12 +227,13 @@ that open specific screens in the system's Settings app.</p>
    + setAction()} or with an {@link android.content.Intent} constructor.</p>
    + 
    + <p>If you define your own actions, be sure to include your app's package name
    +-as a prefix. For example:</p>
    ++as a prefix, as shown in the following example:</p>
    + <pre>static final String ACTION_TIMETRAVEL = "com.example.action.TIMETRAVEL";</pre>
    + </dd>
    + 
    + <dt><b>Data</b></dt>
    +-<dd>The URI (a {@link android.net.Uri} object) that references the data to be acted on and/or the
    ++<dd>The URI (a {@link android.net.Uri} object) that references the data to
    ++ be acted on and/or the
    + MIME type of that data. The type of data supplied is generally dictated by the intent's action. For
    + example, if the action is {@link android.content.Intent#ACTION_EDIT}, the data should contain the
    + URI of the document to edit.
    +@@ -231,10 +242,11 @@ URI of the document to edit.
    + it's often important to specify the type of data (its MIME type) in addition to its URI.
    + For example, an activity that's able to display images probably won't be able
    + to play an audio file, even though the URI formats could be similar.
    +-So specifying the MIME type of your data helps the Android
    ++Specifying the MIME type of your data helps the Android
    + system find the best component to receive your intent.
    + However, the MIME type can sometimes be inferred from the URI&mdash;particularly when the data is a
    +-{@code content:} URI, which indicates the data is located on the device and controlled by a
    ++{@code content:} URI. A {@code content:} URI indicates the data is located on the device
    ++ and controlled by a
    + {@link android.content.ContentProvider}, which makes the data MIME type visible to the system.</p>
    + 
    + <p>To set only the data URI, call {@link android.content.Intent#setData setData()}.
    +@@ -243,7 +255,7 @@ can set both explicitly with {@link
    + android.content.Intent#setDataAndType setDataAndType()}.</p>
    + 
    + <p class="caution"><strong>Caution:</strong> If you want to set both the URI and MIME type,
    +-<strong>do not</strong> call {@link android.content.Intent#setData setData()} and
    ++<em>don't</em> call {@link android.content.Intent#setData setData()} and
    + {@link android.content.Intent#setType setType()} because they each nullify the value of the other.
    + Always use {@link android.content.Intent#setDataAndType setDataAndType()} to set both
    + URI and MIME type.</p>
    +@@ -258,7 +270,7 @@ Here are some common categories:
    + <dl>
    + <dt>{@link android.content.Intent#CATEGORY_BROWSABLE}</dt>
    +   <dd>The target activity allows itself to be started by a web browser to display data
    +-       referenced by a link&mdash;such as an image or an e-mail message.
    ++       referenced by a link, such as an image or an e-mail message.
    +   </dd>
    + <dt>{@link android.content.Intent#CATEGORY_LAUNCHER}</dt>
    +   <dd>The activity is the initial activity of a task and is listed in
    +@@ -276,14 +288,14 @@ categories.</p>
    + 
    + <p>These properties listed above (component name, action, data, and category) represent the
    + defining characteristics of an intent. By reading these properties, the Android system
    +-is able to resolve which app component it should start.</p>
    +-
    +-<p>However, an intent can carry additional information that does not affect
    +-how it is resolved to an app component. An intent can also supply:</p>
    ++is able to resolve which app component it should start. However, an intent can carry
    ++ additional information that does not affect
    ++how it is resolved to an app component. An intent can also supply the following information:</p>
    + 
    + <dl>
    + <dt><b>Extras</b></dt>
    +-<dd>Key-value pairs that carry additional information required to accomplish the requested action.
    ++<dd>Key-value pairs that carry additional information required to accomplish
    ++ the requested action.
    + Just as some actions use particular kinds of data URIs, some actions also use particular extras.
    + 
    + <p>You can add extra data with various {@link android.content.Intent#putExtra putExtra()} methods,
    +@@ -293,21 +305,22 @@ the {@link android.os.Bundle} in the {@link android.content.Intent} with {@link
    + android.content.Intent#putExtras putExtras()}.</p>
    + 
    + <p>For example, when creating an intent to send an email with
    +-{@link android.content.Intent#ACTION_SEND}, you can specify the "to" recipient with the
    +-{@link android.content.Intent#EXTRA_EMAIL} key, and specify the "subject" with the
    ++{@link android.content.Intent#ACTION_SEND}, you can specify the <em>to</em> recipient with the
    ++{@link android.content.Intent#EXTRA_EMAIL} key, and specify the <em>subject</em> with the
    + {@link android.content.Intent#EXTRA_SUBJECT} key.</p>
    + 
    + <p>The {@link android.content.Intent} class specifies many {@code EXTRA_*} constants
    + for standardized data types. If you need to declare your own extra keys (for intents that
    + your app receives), be sure to include your app's package name
    +-as a prefix. For example:</p>
    ++as a prefix, as shown in the following example:</p>
    + <pre>static final String EXTRA_GIGAWATTS = "com.example.EXTRA_GIGAWATTS";</pre>
    + </dd>
    + 
    + <dt><b>Flags</b></dt>
    +-<dd>Flags defined in the {@link android.content.Intent} class that function as metadata for the
    ++<dd>Flags are defined in the {@link android.content.Intent} class that function as metadata for the
    + intent. The flags may instruct the Android system how to launch an activity (for example, which
    +-<a href="{@docRoot}guide/components/tasks-and-back-stack.html">task</a> the activity should belong
    ++<a href="{@docRoot}guide/components/tasks-and-back-stack.html">task</a>
    ++ the activity should belong
    + to) and how to treat it after it's launched (for example, whether it belongs in the list of recent
    + activities).
    + 
    +@@ -354,7 +367,8 @@ this intent explicitly starts the {@code DownloadService} class in the app.</p>
    + to perform the action. Using an implicit intent is useful when your app cannot perform the
    + action, but other apps probably can and you'd like the user to pick which app to use.</p>
    + 
    +-<p>For example, if you have content you want the user to share with other people, create an intent
    ++<p>For example, if you have content that you want the user to share with other people,
    ++ create an intent
    + with the {@link android.content.Intent#ACTION_SEND} action
    + and add extras that specify the content to share. When you call
    + {@link android.content.Context#startActivity startActivity()} with that intent, the user can
    +@@ -362,13 +376,15 @@ pick an app through which to share the content.</p>
    + 
    + <p class="caution"><strong>Caution:</strong> It's possible that a user won't have <em>any</em>
    + apps that handle the implicit intent you send to {@link android.content.Context#startActivity
    +-startActivity()}. If that happens, the call will fail and your app will crash. To verify
    ++startActivity()}. If that happens, the call fails and your app crashes. To verify
    + that an activity will receive the intent, call {@link android.content.Intent#resolveActivity
    + resolveActivity()} on your {@link android.content.Intent} object. If the result is non-null,
    +-then there is at least one app that can handle the intent and it's safe to call
    ++ there is at least one app that can handle the intent and it's safe to call
    + {@link android.content.Context#startActivity startActivity()}. If the result is null,
    +-you should not use the intent and, if possible, you should disable the feature that issues
    +-the intent.</p>
    ++ do not use the intent and, if possible, you should disable the feature that issues
    ++the intent. The following example shows how to verify that the intent resolves
    ++to an activity. This example doesn't use a URI, but the intent's data type
    ++is declared to specify the content carried by the extras.</p>
    + 
    + 
    + <pre>
    +@@ -384,8 +400,7 @@ if (sendIntent.resolveActivity(getPackageManager()) != null) {
    + }
    + </pre>
    + 
    +-<p class="note"><strong>Note:</strong> In this case, a URI is not used, but the intent's data type
    +-is declared to specify the content carried by the extras.</p>
    ++
    + 
    + 
    + <p>When {@link android.content.Context#startActivity startActivity()} is called, the system
    +@@ -393,7 +408,7 @@ examines all of the installed apps to determine which ones can handle this kind
    + intent with the {@link android.content.Intent#ACTION_SEND} action and that carries "text/plain"
    + data). If there's only one app that can handle it, that app opens immediately and is given the
    + intent. If multiple activities accept the intent, the system
    +-displays a dialog so the user can pick which app to use..</p>
    ++displays a dialog such as the one shown in Figure 2, so the user can pick which app to use.</p>
    + 
    + 
    + <div class="figure" style="width:200px">
    +@@ -405,23 +420,26 @@ displays a dialog so the user can pick which app to use..</p>
    + 
    + <p>When there is more than one app that responds to your implicit intent,
    + the user can select which app to use and make that app the default choice for the
    +-action. This is nice when performing an action for which the user
    +-probably wants to use the same app from now on, such as when opening a web page (users
    +-often prefer just one web browser) .</p>
    ++action. The ability to select a default is helpful when performing an action for which the user
    ++probably wants to use the same app every time, such as when opening a web page (users
    ++often prefer just one web browser).</p>
    + 
    + <p>However, if multiple apps can respond to the intent and the user might want to use a different
    + app each time, you should explicitly show a chooser dialog. The chooser dialog asks the
    +-user to select which app to use for the action every time (the user cannot select a default app for
    ++user to select which app to use for the action (the user cannot select a default app for
    + the action). For example, when your app performs "share" with the {@link
    + android.content.Intent#ACTION_SEND} action, users may want to share using a different app depending
    +-on their current situation, so you should always use the chooser dialog, as shown in figure 2.</p>
    ++on their current situation, so you should always use the chooser dialog, as shown in Figure 2.</p>
    + 
    + 
    + 
    + 
    + <p>To show the chooser, create an {@link android.content.Intent} using {@link
    + android.content.Intent#createChooser createChooser()} and pass it to {@link
    +-android.app.Activity#startActivity startActivity()}. For example:</p>
    ++android.app.Activity#startActivity startActivity()}, as shown in the following example.
    ++ This example displays a dialog with a list of apps that respond to the intent passed to the {@link
    ++android.content.Intent#createChooser createChooser()} method and uses the supplied text as the
    ++dialog title.</p>
    + 
    + <pre>
    + Intent sendIntent = new Intent(Intent.ACTION_SEND);
    +@@ -439,26 +457,16 @@ if (sendIntent.resolveActivity(getPackageManager()) != null) {
    + }
    + </pre>
    + 
    +-<p>This displays a dialog with a list of apps that respond to the intent passed to the {@link
    +-android.content.Intent#createChooser createChooser()} method and uses the supplied text as the
    +-dialog title.</p>
    +-
    +-
    + 
    + 
    +-
    +-
    +-
    +-
    +-
    +-<h2 id="Receiving">Receiving an Implicit Intent</h2>
    ++<h2 id="Receiving">Receiving an implicit intent</h2>
    + 
    + <p>To advertise which implicit intents your app can receive, declare one or more intent filters for
    + each of your app components with an <a href=
    +-"{@docRoot}guide/topics/manifest/intent-filter-element.html">{@code <intent-filter>}</a>
    ++"{@docRoot}guide/topics/manifest/intent-filter-element.html">{@code &lt;intent-filter&gt;}</a>
    + element in your <a href="{@docRoot}guide/topics/manifest/manifest-intro.html">manifest file</a>.
    + Each intent filter specifies the type of intents it accepts based on the intent's action,
    +-data, and category. The system will deliver an implicit intent to your app component only if the
    ++data, and category. The system delivers an implicit intent to your app component only if the
    + intent can pass through one of your intent filters.</p>
    + 
    + <p class="note"><strong>Note:</strong> An explicit intent is always delivered to its target,
    +@@ -471,28 +479,28 @@ it inspects the {@link android.content.Intent} and decides how to behave based o
    + in the {@link android.content.Intent} (such as to show the editor controls or not).</p>
    + 
    + <p>Each intent filter is defined by an <a
    +-href="{@docRoot}guide/topics/manifest/intent-filter-element.html">{@code <intent-filter>}</a>
    ++href="{@docRoot}guide/topics/manifest/intent-filter-element.html">{@code &lt;intent-filter>}</a>
    + element in the app's manifest file, nested in the corresponding app component (such
    +-as an <a href="{@docRoot}guide/topics/manifest/activity-element.html">{@code <activity>}</a>
    ++as an <a href="{@docRoot}guide/topics/manifest/activity-element.html">{@code &lt;activity>}</a>
    + element). Inside the <a
    +-href="{@docRoot}guide/topics/manifest/intent-filter-element.html">{@code <intent-filter>}</a>,
    ++href="{@docRoot}guide/topics/manifest/intent-filter-element.html">{@code &lt;intent-filter>}</a>,
    + you can specify the type of intents to accept using one or more
    + of these three elements:</p>
    + 
    + <dl>
    +-<dt><a href="{@docRoot}guide/topics/manifest/action-element.html">{@code <action>}</a></dt>
    ++<dt><a href="{@docRoot}guide/topics/manifest/action-element.html">{@code &lt;action>}</a></dt>
    +   <dd>Declares the intent action accepted, in the {@code name} attribute. The value
    +   must be the literal string value of an action, not the class constant.</dd>
    +-<dt><a href="{@docRoot}guide/topics/manifest/data-element.html">{@code <data>}</a></dt>
    ++<dt><a href="{@docRoot}guide/topics/manifest/data-element.html">{@code &lt;data>}</a></dt>
    +   <dd>Declares the type of data accepted, using one or more attributes that specify various
    +   aspects of the data URI (<code>scheme</code>, <code>host</code>, <code>port</code>,
    +-  <code>path</code>, etc.) and MIME type.</dd>
    +-<dt><a href="{@docRoot}guide/topics/manifest/category-element.html">{@code <category>}</a></dt>
    ++  <code>path</code>) and MIME type.</dd>
    ++<dt><a href="{@docRoot}guide/topics/manifest/category-element.html">{@code &lt;category>}</a></dt>
    +   <dd>Declares the intent category accepted, in the {@code name} attribute. The value
    +   must be the literal string value of an action, not the class constant.
    + 
    +-  <p class="note"><strong>Note:</strong> In order to receive implicit intents, you
    +-  <strong>must include</strong> the
    ++  <p class="note"><strong>Note:</strong> To receive implicit intents, you
    ++  <em>must include</em> the
    +   {@link android.content.Intent#CATEGORY_DEFAULT} category in the intent filter. The methods
    +   {@link android.app.Activity#startActivity startActivity()} and
    +   {@link android.app.Activity#startActivityForResult startActivityForResult()} treat all intents
    +@@ -515,12 +523,12 @@ of these three elements:</p>
    + &lt;/activity>
    + </pre>
    + 
    +-<p>It's okay to create a filter that includes more than one instance of
    +-<a href="{@docRoot}guide/topics/manifest/action-element.html">{@code <action>}</a>,
    +-<a href="{@docRoot}guide/topics/manifest/data-element.html">{@code <data>}</a>, or
    +-<a href="{@docRoot}guide/topics/manifest/category-element.html">{@code <category>}</a>.
    +-If you do, you simply need to be certain that the component can handle any and all combinations
    +-of those filter elements.</p>
    ++<p>You can create a filter that includes more than one instance of
    ++<a href="{@docRoot}guide/topics/manifest/action-element.html">{@code &lt;action>}</a>,
    ++<a href="{@docRoot}guide/topics/manifest/data-element.html">{@code &lt;data>}</a>, or
    ++<a href="{@docRoot}guide/topics/manifest/category-element.html">{@code &lt;category>}</a>.
    ++If you do, you need to be certain that the component can handle any and all
    ++combinations of those filter elements.</p>
    + 
    + <p>When you want to handle multiple kinds of intents, but only in specific combinations of
    + action, data, and category type, then you need to create multiple intent filters.</p>
    +@@ -569,8 +577,8 @@ is running.</p>
    + 
    + <h3 id="ExampleFilters">Example filters</h3>
    + 
    +-<p>To better understand some of the intent filter behaviors, look at the following snippet
    +-from the manifest file of a social-sharing app.</p>
    ++<p>To demonstrate some of the intent filter behaviors, here is an example
    ++from the manifest file of a social-sharing app:</p>
    + 
    + <pre>
    + &lt;activity android:name="MainActivity">
    +@@ -607,9 +615,9 @@ opens when the user initially launches the app with the launcher icon:</p>
    +   indicates this is the main entry point and does not expect any intent data.</li>
    +   <li>The {@link android.content.Intent#CATEGORY_LAUNCHER} category indicates that this activity's
    +   icon should be placed in the system's app launcher. If the <a
    +-  href="{@docRoot}guide/topics/manifest/activity-element.html">{@code <activity>}</a> element
    ++  href="{@docRoot}guide/topics/manifest/activity-element.html">{@code &lt;activity>}</a> element
    +   does not specify an icon with {@code icon}, then the system uses the icon from the <a
    +-  href="{@docRoot}guide/topics/manifest/application-element.html">{@code <application>}</a>
    ++  href="{@docRoot}guide/topics/manifest/application-element.html">{@code &lt;application>}</a>
    +   element.</li>
    + </ul>
    + <p>These two must be paired together in order for the activity to appear in the app launcher.</p>
    +@@ -620,7 +628,7 @@ they can also enter {@code ShareActivity} directly from another app that issues
    + intent matching one of the two intent filters.</p>
    + 
    + <p class="note"><strong>Note:</strong> The MIME type,
    +-<a href="https://developers.google.com/panorama/android/">{@code
    ++<a href="https://developers.google.com/panorama/android/" class="external-link">{@code
    + application/vnd.google.panorama360+jpg}</a>, is a special data type that specifies
    + panoramic photos, which you can handle with the <a
    + href="{@docRoot}reference/com/google/android/gms/panorama/package-summary.html">Google
    +@@ -638,7 +646,7 @@ panorama</a> APIs.</p>
    + 
    + 
    + 
    +-<h2 id="PendingIntent">Using a Pending Intent</h2>
    ++<h2 id="PendingIntent">Using a pending intent</h2>
    + 
    + <p>A {@link android.app.PendingIntent} object is a wrapper around an {@link
    + android.content.Intent} object. The primary purpose of a {@link android.app.PendingIntent}
    +@@ -646,25 +654,25 @@ is to grant permission to a foreign application
    + to use the contained {@link android.content.Intent} as if it were executed from your
    + app's own process.</p>
    + 
    +-<p>Major use cases for a pending intent include:</p>
    ++<p>Major use cases for a pending intent include the following:</p>
    + <ul>
    +-  <li>Declare an intent to be executed when the user performs an action with your <a
    ++  <li>Declaring an intent to be executed when the user performs an action with your <a
    +   href="{@docRoot}guide/topics/ui/notifiers/notifications.html">Notification</a>
    +   (the Android system's {@link android.app.NotificationManager}
    +   executes the {@link android.content.Intent}).
    +-  <li>Declare an intent to be executed when the user performs an action with your
    ++  <li>Declaring an intent to be executed when the user performs an action with your
    +   <a href="{@docRoot}guide/topics/appwidgets/index.html">App Widget</a>
    +   (the Home screen app executes the {@link android.content.Intent}).
    +-  <li>Declare an intent to be executed at a specified time in the future (the Android
    ++  <li>Declaring an intent to be executed at a specified future time (the Android
    +   system's {@link android.app.AlarmManager} executes the {@link android.content.Intent}).
    + </ul>
    + 
    +-<p>Because each {@link android.content.Intent} object is designed to be handled by a specific
    ++<p>Just as each {@link android.content.Intent} object is designed to be handled by a specific
    + type of app component (either an {@link android.app.Activity}, a {@link android.app.Service}, or
    + a {@link android.content.BroadcastReceiver}), so too must a {@link android.app.PendingIntent} be
    +-created with the same consideration. When using a pending intent, your app will not
    ++created with the same consideration. When using a pending intent, your app doesn't
    + execute the intent with a call such as {@link android.content.Context#startActivity
    +-startActivity()}. You must instead declare the intended component type when you create the
    ++startActivity()}. Instead, you must declare the intended component type when you create the
    + {@link android.app.PendingIntent} by calling the respective creator method:</p>
    + 
    + <ul>
    +@@ -677,14 +685,14 @@ startActivity()}. You must instead declare the intended component type when you
    + </ul>
    + 
    + <p>Unless your app is <em>receiving</em> pending intents from other apps,
    +-the above methods to create a {@link android.app.PendingIntent} are the only
    +-{@link android.app.PendingIntent} methods you'll probably ever need.</p>
    ++the above methods to create a {@link android.app.PendingIntent} are probably the only
    ++{@link android.app.PendingIntent} methods you'll ever need.</p>
    + 
    + <p>Each method takes the current app {@link android.content.Context}, the
    + {@link android.content.Intent} you want to wrap, and one or more flags that specify
    + how the intent should be used (such as whether the intent can be used more than once).</p>
    + 
    +-<p>More information about using pending intents is provided with the documentation for each
    ++<p>For more information about using pending intents, see the documentation for each
    + of the respective use cases, such as in the <a
    + href="{@docRoot}guide/topics/ui/notifiers/notifications.html">Notifications</a>
    + and <a href="{@docRoot}guide/topics/appwidgets/index.html">App Widgets</a> API guides.</p>
    +@@ -695,27 +703,27 @@ and <a href="{@docRoot}guide/topics/appwidgets/index.html">App Widgets</a> API g
    + 
    + 
    + 
    +-<h2 id="Resolution">Intent Resolution</h2>
    ++<h2 id="Resolution">Intent resolution</h2>
    + 
    + 
    + <p>When the system receives an implicit intent to start an activity, it searches for the
    +-best activity for the intent by comparing the intent to intent filters based on three aspects:</p>
    ++best activity for the intent by comparing the it to intent filters based on three aspects:</p>
    + 
    + <ul>
    +-  <li>The intent action
    +-  <li>The intent data (both URI and data type)
    +-  <li>The intent category
    ++  <li>Action.
    ++  <li>Data (both URI and data type).
    ++  <li>Category.
    + </ul>
    + 
    +-<p>The following sections describe how intents are matched to the appropriate component(s)
    +-in terms of how the intent filter is declared in an app's manifest file.</p>
    ++<p>The following sections describe how intents are matched to the appropriate components
    ++according to the intent filter declaration in an app's manifest file.</p>
    + 
    + 
    + <h3 id="ActionTest">Action test</h3>
    + 
    + <p>To specify accepted intent actions, an intent filter can declare zero or more
    + <a href="{@docRoot}guide/topics/manifest/action-element.html">{@code
    +-<action>}</a> elements.  For example:</p>
    ++&lt;action&gt;}</a> elements, as shown in the following example:</p>
    + 
    + <pre>
    + &lt;intent-filter&gt;
    +@@ -725,13 +733,13 @@ in terms of how the intent filter is declared in an app's manifest file.</p>
    + &lt;/intent-filter&gt;
    + </pre>
    + 
    +-<p>To get through this filter, the action specified in the {@link android.content.Intent}
    ++<p>To pass this filter, the action specified in the {@link android.content.Intent}
    +   must match one of the actions listed in the filter.</p>
    + 
    + <p>If the filter does not list any actions, there is nothing for an
    + intent to match, so all intents fail the test. However, if an {@link android.content.Intent}
    +-does not specify an action, it will pass the test (as long as the filter
    +-contains at least one action).</p>
    ++does not specify an action, it passes the test as long as the filter
    ++contains at least one action.</p>
    + 
    + 
    + 
    +@@ -739,7 +747,7 @@ contains at least one action).</p>
    + 
    + <p>To specify accepted intent categories, an intent filter can declare zero or more
    + <a href="{@docRoot}guide/topics/manifest/category-element.html">{@code
    +-<category>}</a> elements.  For example:</p>
    ++<category>}</a> elements, as shown in the following example:</p>
    + 
    + <pre>
    + &lt;intent-filter&gt;
    +@@ -752,17 +760,17 @@ contains at least one action).</p>
    + <p>For an intent to pass the category test, every category in the {@link android.content.Intent}
    + must match a category in the filter. The reverse is not necessary&mdash;the intent filter may
    + declare more categories than are specified in the {@link android.content.Intent} and the
    +-{@link android.content.Intent} will still pass. Therefore, an intent with no categories should
    +-always pass this test, regardless of what categories are declared in the filter.</p>
    ++{@link android.content.Intent} still passes. Therefore, an intent with no categories
    ++always passes this test, regardless of what categories are declared in the filter.</p>
    + 
    + <p class="note"><strong>Note:</strong>
    +-Android automatically applies the the {@link android.content.Intent#CATEGORY_DEFAULT} category
    ++Android automatically applies the {@link android.content.Intent#CATEGORY_DEFAULT} category
    + to all implicit intents passed to {@link
    + android.content.Context#startActivity startActivity()} and {@link
    + android.app.Activity#startActivityForResult startActivityForResult()}.
    +-So if you want your activity to receive implicit intents, it must
    +-include a category for {@code "android.intent.category.DEFAULT"} in its intent filters (as
    +-shown in the previous {@code <intent-filter>} example.</p>
    ++If you want your activity to receive implicit intents, it must
    ++include a category for {@code "android.intent.category.DEFAULT"} in its intent filters, as
    ++shown in the previous {@code &lt;intent-filter>} example.</p>
    + 
    + 
    + 
    +@@ -770,7 +778,7 @@ shown in the previous {@code <intent-filter>} example.</p>
    + 
    + <p>To specify accepted intent data, an intent filter can declare zero or more
    + <a href="{@docRoot}guide/topics/manifest/data-element.html">{@code
    +-<data>}</a> elements.  For example:</p>
    ++&lt;data&gt;}</a> elements, as shown in the following example:</p>
    + 
    + <pre>
    + &lt;intent-filter&gt;
    +@@ -781,15 +789,16 @@ shown in the previous {@code <intent-filter>} example.</p>
    + </pre>
    + 
    + <p>Each <code><a href="{@docRoot}guide/topics/manifest/data-element.html">&lt;data&gt;</a></code>
    +-element can specify a URI structure and a data type (MIME media type).  There are separate
    +-attributes &mdash; {@code scheme}, {@code host}, {@code port},
    +-and {@code path} &mdash; for each part of the URI:
    ++element can specify a URI structure and a data type (MIME media type).
    ++ Each part of the URI is a separate
    ++attribute: {@code scheme}, {@code host}, {@code port},
    ++and {@code path}:
    + </p>
    + 
    +-<p style="margin-left: 2em">{@code <scheme>://<host>:<port>/<path>}</p>
    ++<p style="margin-left: 2em">{@code &lt;scheme>://&lt;host>:&lt;port>/&lt;path>}</p>
    + 
    + <p>
    +-For example:
    ++The following example shows possible values for these attributes:
    + </p>
    + 
    + <p style="margin-left: 2em">{@code content://com.example.project:200/folder/subfolder/etc}</p>
    +@@ -799,7 +808,7 @@ the port is {@code 200}, and the path is {@code folder/subfolder/etc}.
    + </p>
    + 
    + <p>Each of these attributes is optional in a <a
    +-href="{@docRoot}guide/topics/manifest/data-element.html">{@code <data>}</a> element,
    ++href="{@docRoot}guide/topics/manifest/data-element.html">{@code &lt;data>}</a> element,
    + but there are linear dependencies:</p>
    + <ul>
    +   <li>If a scheme is not specified, the host is ignored.</li>
    +@@ -842,17 +851,17 @@ type matches a type listed in the filter.  It passes the URI part of the test
    + either if its URI matches a URI in the filter or if it has a {@code content:}
    + or {@code file:} URI and the filter does not specify a URI.  In other words,
    + a component is presumed to support {@code content:} and {@code file:} data if
    +-its filter lists <em>only</em> a MIME type.</p></li>
    ++its filter lists <em>only</em> a MIME type.</li>
    + </ol>
    + 
    + <p>
    + This last rule, rule (d), reflects the expectation
    + that components are able to get local data from a file or content provider.
    +-Therefore, their filters can list just a data type and do not need to explicitly
    ++Therefore, their filters can list just a data type and don't need to explicitly
    + name the {@code content:} and {@code file:} schemes.
    +-This is a typical case.  A <a
    +-href="{@docRoot}guide/topics/manifest/data-element.html">{@code <data>}</a> element
    +-like the following, for example, tells Android that the component can get image data from a content
    ++The following example shows a typical case in which a <a
    ++href="{@docRoot}guide/topics/manifest/data-element.html">{@code &lt;data>}</a> element
    ++ tells Android that the component can get image data from a content
    + provider and display it:
    + </p>
    + 
    +@@ -863,14 +872,15 @@ provider and display it:
    + &lt;/intent-filter&gt;</pre>
    + 
    + <p>
    +-Because most available data is dispensed by content providers, filters that
    +-specify a data type but not a URI are perhaps the most common.
    ++Filters that
    ++specify a data type but not a URI are perhaps the most common because most available
    ++ data is dispensed by content providers.
    + </p>
    + 
    + <p>
    +-Another common configuration is filters with a scheme and a data type.  For
    ++Another common configuration is a filter with a scheme and a data type.  For
    + example, a <a
    +-href="{@docRoot}guide/topics/manifest/data-element.html">{@code <data>}</a>
    ++href="{@docRoot}guide/topics/manifest/data-element.html">{@code &lt;data>}</a>
    + element like the following tells Android that
    + the component can retrieve video data from the network in order to perform the action:
    + </p>
    +@@ -894,7 +904,7 @@ by finding all the  activities with intent filters that specify the
    + 
    + <p>Your application can use intent matching in a similar way.
    + The {@link android.content.pm.PackageManager} has a set of {@code query...()}
    +-methods that return all components that can accept a particular intent, and
    ++methods that return all components that can accept a particular intent and
    + a similar series of {@code resolve...()} methods that determine the best
    + component to respond to an intent.  For example,
    + {@link android.content.pm.PackageManager#queryIntentActivities
    +@@ -907,7 +917,3 @@ can respond.  There's a similar method,
    + {@link android.content.pm.PackageManager#queryBroadcastReceivers
    + queryBroadcastReceivers()}, for broadcast receivers.
    + </p>
    +-
    +-
    +-
    +-
    +diff --git a/docs/html/guide/components/services.jd b/docs/html/guide/components/services.jd
    +index e646a17..a7ed718 100644
    +--- a/docs/html/guide/components/services.jd
    ++++ b/docs/html/guide/components/services.jd
    +@@ -5,11 +5,11 @@ page.title=Services
    + <ol id="qv">
    + <h2>In this document</h2>
    + <ol>
    +-<li><a href="#Basics">The Basics</a></li>
    ++<li><a href="#Basics">The basics</a></li>
    + <ol>
    +   <li><a href="#Declaring">Declaring a service in the manifest</a></li>
    + </ol>
    +-<li><a href="#CreatingAService">Creating a Started Service</a>
    ++<li><a href="#CreatingAService">Creating a started service</a>
    +   <ol>
    +     <li><a href="#ExtendingIntentService">Extending the IntentService class</a></li>
    +     <li><a href="#ExtendingService">Extending the Service class</a></li>
    +@@ -17,10 +17,10 @@ page.title=Services
    +     <li><a href="#Stopping">Stopping a service</a></li>
    +   </ol>
    + </li>
    +-<li><a href="#CreatingBoundService">Creating a Bound Service</a></li>
    +-<li><a href="#Notifications">Sending Notifications to the User</a></li>
    +-<li><a href="#Foreground">Running a Service in the Foreground</a></li>
    +-<li><a href="#Lifecycle">Managing the Lifecycle of a Service</a>
    ++<li><a href="#CreatingBoundService">Creating a bound service</a></li>
    ++<li><a href="#Notifications">Sending notifications to the user</a></li>
    ++<li><a href="#Foreground">Running a service in the foreground</a></li>
    ++<li><a href="#Lifecycle">Managing the lifecycle of a service</a>
    + <ol>
    +   <li><a href="#LifecycleCallbacks">Implementing the lifecycle callbacks</a></li>
    + </ol>
    +@@ -48,70 +48,80 @@ page.title=Services
    + 
    + </div>
    + 
    +-
    + <p>A {@link android.app.Service} is an application component that can perform
    +-long-running operations in the background and does not provide a user interface. Another
    +-application component can start a service and it will continue to run in the background even if the
    ++long-running operations in the background, and it does not provide a user interface. Another
    ++application component can start a service, and it continues to run in the background even if the
    + user switches to another application. Additionally, a component can bind to a service to
    +-interact with it and even perform interprocess communication (IPC). For example, a service might
    ++interact with it and even perform interprocess communication (IPC). For example, a service can
    + handle network transactions, play music, perform file I/O, or interact with a content provider, all
    + from the background.</p>
    + 
    +-<p>A service can essentially take two forms:</p>
    ++<p>These are the three different types of services:</p>
    + 
    + <dl>
    ++  <dt>Scheduled</dt>
    ++  <dd>A service is <em>scheduled</em> when an API such as the {@link android.app.job.JobScheduler},
    ++  introduced in Android 5.0 (API level 21), launches the service. You can use the
    ++  {@link android.app.job.JobScheduler} by registering jobs and specifying their requirements for
    ++  network and timing. The system then gracefully schedules the jobs for execution at the
    ++  appropriate times. The {@link android.app.job.JobScheduler} provides many methods to define
    ++  service-execution conditions.
    ++    <p class="note"><strong>Note:</strong> If your app targets Android 5.0 (API level 21), Google
    ++    recommends that you use the {@link android.app.job.JobScheduler} to execute background
    ++    services. For more information about using this class, see the
    ++    {@link android.app.job.JobScheduler} reference documentation.</p></dd>
    +   <dt>Started</dt>
    +-  <dd>A service is "started" when an application component (such as an activity) starts it by
    +-calling {@link android.content.Context#startService startService()}. Once started, a service
    +-can run in the background indefinitely, even if the component that started it is destroyed. Usually,
    +-a started service performs a single operation and does not return a result to the caller.
    +-For example, it might download or upload a file over the network. When the operation is done, the
    +-service should stop itself.</dd>
    ++  <dd>A service is <em>started</em> when an application component (such as an activity)
    ++  calls {@link android.content.Context#startService startService()}. After it's started, a
    ++  service can run in the background indefinitely, even if the component that started it is
    ++  destroyed. Usually, a started service performs a single operation and does not return a result to
    ++  the caller. For example, it can download or upload a file over the network. When the operation is
    ++  complete, the service should stop itself.</dd>
    +   <dt>Bound</dt>
    +-  <dd>A service is "bound" when an application component binds to it by calling {@link
    +-android.content.Context#bindService bindService()}. A bound service offers a client-server
    +-interface that allows components to interact with the service, send requests, get results, and even
    +-do so across processes with interprocess communication (IPC). A bound service runs only as long as
    +-another application component is bound to it. Multiple components can bind to the service at once,
    +-but when all of them unbind, the service is destroyed.</dd>
    ++  <dd>A service is <em>bound</em> when an application component binds to it by calling {@link
    ++  android.content.Context#bindService bindService()}. A bound service offers a client-server
    ++  interface that allows components to interact with the service, send requests, receive results,
    ++  and even do so across processes with interprocess communication (IPC). A bound service runs only
    ++  as long as another application component is bound to it. Multiple components can bind to the
    ++  service at once, but when all of them unbind, the service is destroyed.</dd>
    + </dl>
    + 
    +-<p>Although this documentation generally discusses these two types of services separately, your
    +-service can work both ways&mdash;it can be started (to run indefinitely) and also allow binding.
    +-It's simply a matter of whether you implement a couple callback methods: {@link
    ++<p>Although this documentation generally discusses started and bound services separately,
    ++your service can work both ways&mdash;it can be started (to run indefinitely) and also allow
    ++binding. It's simply a matter of whether you implement a couple of callback methods: {@link
    + android.app.Service#onStartCommand onStartCommand()} to allow components to start it and {@link
    + android.app.Service#onBind onBind()} to allow binding.</p>
    + 
    + <p>Regardless of whether your application is started, bound, or both, any application component
    +-can use the service (even from a separate application), in the same way that any component can use
    ++can use the service (even from a separate application) in the same way that any component can use
    + an activity&mdash;by starting it with an {@link android.content.Intent}. However, you can declare
    +-the service as private, in the manifest file, and block access from other applications. This is
    +-discussed more in the section about <a href="#Declaring">Declaring the service in the
    ++the service as <em>private</em> in the manifest file and block access from other applications.
    ++This is discussed more in the section about <a href="#Declaring">Declaring the service in the
    + manifest</a>.</p>
    + 
    + <p class="caution"><strong>Caution:</strong> A service runs in the
    +-main thread of its hosting process&mdash;the service does <strong>not</strong> create its own thread
    +-and does <strong>not</strong> run in a separate process (unless you specify otherwise). This means
    +-that, if your service is going to do any CPU intensive work or blocking operations (such as MP3
    +-playback or networking), you should create a new thread within the service to do that work. By using
    +-a separate thread, you will reduce the risk of Application Not Responding (ANR) errors and the
    +-application's main thread can remain dedicated to user interaction with your activities.</p>
    +-
    ++main thread of its hosting process; the service does <strong>not</strong> create its own
    ++thread and does <strong>not</strong> run in a separate process unless you specify otherwise. If
    ++your service is going to perform any CPU-intensive work or blocking operations, such as MP3
    ++playback or networking, you should create a new thread within the service to complete that work.
    ++By using a separate thread, you can reduce the risk of Application Not Responding (ANR) errors,
    ++and the application's main thread can remain dedicated to user interaction with your
    ++activities.</p>
    + 
    +-<h2 id="Basics">The Basics</h2>
    ++<h2 id="Basics">The basics</h2>
    + 
    + <div class="sidebox-wrapper">
    + <div class="sidebox">
    +   <h3>Should you use a service or a thread?</h3>
    +-  <p>A service is simply a component that can run in the background even when the user is not
    +-interacting with your application. Thus, you should create a service only if that is what you
    ++  <p>A service is simply a component that can run in the background, even when the user is not
    ++interacting with your application, so you should create a service only if that is what you
    + need.</p>
    +-  <p>If you need to perform work outside your main thread, but only while the user is interacting
    +-with your application, then you should probably instead create a new thread and not a service. For
    +-example, if you want to play some music, but only while your activity is running, you might create
    ++  <p>If you must perform work outside of your main thread, but only while the user is interacting
    ++with your application, you should instead create a new thread. For example, if you want to
    ++play some music, but only while your activity is running, you might create
    + a thread in {@link android.app.Activity#onCreate onCreate()}, start running it in {@link
    +-android.app.Activity#onStart onStart()}, then stop it in {@link android.app.Activity#onStop
    +-onStop()}. Also consider using {@link android.os.AsyncTask} or {@link android.os.HandlerThread},
    ++android.app.Activity#onStart onStart()}, and stop it in {@link android.app.Activity#onStop
    ++onStop()}. Also consider using {@link android.os.AsyncTask} or {@link android.os.HandlerThread}
    + instead of the traditional {@link java.lang.Thread} class. See the <a
    + href="{@docRoot}guide/components/processes-and-threads.html#Threads">Processes and
    + Threading</a> document for more information about threads.</p>
    +@@ -121,78 +131,81 @@ blocking operations.</p>
    + </div>
    + </div>
    + 
    +-<p>To create a service, you must create a subclass of {@link android.app.Service} (or one
    +-of its existing subclasses). In your implementation, you need to override some callback methods that
    +-handle key aspects of the service lifecycle and provide a mechanism for components to bind to
    +-the service, if appropriate. The most important callback methods you should override are:</p>
    ++<p>To create a service, you must create a subclass of {@link android.app.Service} or use one
    ++of its existing subclasses. In your implementation, you must override some callback methods that
    ++handle key aspects of the service lifecycle and provide a mechanism that allows the components to
    ++bind to the service, if appropriate. These are the most important callback methods that you should
    ++override:</p>
    + 
    + <dl>
    +   <dt>{@link android.app.Service#onStartCommand onStartCommand()}</dt>
    +-    <dd>The system calls this method when another component, such as an activity,
    +-requests that the service be started, by calling {@link android.content.Context#startService
    +-startService()}. Once this method executes, the service is started and can run in the
    ++    <dd>The system invokes this method by calling {@link android.content.Context#startService
    ++startService()} when another component (such as an activity) requests that the service be started.
    ++When this method executes, the service is started and can run in the
    + background indefinitely. If you implement this, it is your responsibility to stop the service when
    +-its work is done, by calling {@link android.app.Service#stopSelf stopSelf()} or {@link
    +-android.content.Context#stopService stopService()}. (If you only want to provide binding, you don't
    +-need to implement this method.)</dd>
    ++its work is complete by calling {@link android.app.Service#stopSelf stopSelf()} or {@link
    ++android.content.Context#stopService stopService()}. If you only want to provide binding, you don't
    ++need to implement this method.</dd>
    +   <dt>{@link android.app.Service#onBind onBind()}</dt>
    +-    <dd>The system calls this method when another component wants to bind with the
    +-service (such as to perform RPC), by calling {@link android.content.Context#bindService
    +-bindService()}. In your implementation of this method, you must provide an interface that clients
    +-use to communicate with the service, by returning an {@link android.os.IBinder}. You must always
    +-implement this method, but if you don't want to allow binding, then you should return null.</dd>
    ++    <dd>The system invokes this method by calling {@link android.content.Context#bindService
    ++bindService()} when another component wants to bind with the service (such as to perform RPC).
    ++In your implementation of this method, you must provide an interface that clients
    ++use to communicate with the service by returning an {@link android.os.IBinder}. You must always
    ++implement this method; however, if you don't want to allow binding, you should return
    ++null.</dd>
    +   <dt>{@link android.app.Service#onCreate()}</dt>
    +-    <dd>The system calls this method when the service is first created, to perform one-time setup
    +-procedures (before it calls either {@link android.app.Service#onStartCommand onStartCommand()} or
    ++    <dd>The system invokes this method to perform one-time setup procedures when the service is
    ++initially created (before it calls either
    ++{@link android.app.Service#onStartCommand onStartCommand()} or
    + {@link android.app.Service#onBind onBind()}). If the service is already running, this method is not
    + called.</dd>
    +   <dt>{@link android.app.Service#onDestroy()}</dt>
    +-    <dd>The system calls this method when the service is no longer used and is being destroyed.
    ++    <dd>The system invokes this method when the service is no longer used and is being destroyed.
    + Your service should implement this to clean up any resources such as threads, registered
    +-listeners, receivers, etc. This is the last call the service receives.</dd>
    ++listeners, or receivers. This is the last call that the service receives.</dd>
    + </dl>
    + 
    + <p>If a component starts the service by calling {@link
    + android.content.Context#startService startService()} (which results in a call to {@link
    +-android.app.Service#onStartCommand onStartCommand()}), then the service
    +-remains running until it stops itself with {@link android.app.Service#stopSelf()} or another
    ++android.app.Service#onStartCommand onStartCommand()}), the service
    ++continues to run until it stops itself with {@link android.app.Service#stopSelf()} or another
    + component stops it by calling {@link android.content.Context#stopService stopService()}.</p>
    + 
    + <p>If a component calls
    +-{@link android.content.Context#bindService bindService()} to create the service (and {@link
    +-android.app.Service#onStartCommand onStartCommand()} is <em>not</em> called), then the service runs
    +-only as long as the component is bound to it. Once the service is unbound from all clients, the
    +-system destroys it.</p>
    ++{@link android.content.Context#bindService bindService()} to create the service and {@link
    ++android.app.Service#onStartCommand onStartCommand()} is <em>not</em> called, the service runs
    ++only as long as the component is bound to it. After the service is unbound from all of its clients,
    ++the system destroys it.</p>
    + 
    +-<p>The Android system will force-stop a service only when memory is low and it must recover system
    ++<p>The Android system force-stops a service only when memory is low and it must recover system
    + resources for the activity that has user focus. If the service is bound to an activity that has user
    +-focus, then it's less likely to be killed, and if the service is declared to <a
    +-href="#Foreground">run in the foreground</a> (discussed later), then it will almost never be killed.
    +-Otherwise, if the service was started and is long-running, then the system will lower its position
    +-in the list of background tasks over time and the service will become highly susceptible to
    +-killing&mdash;if your service is started, then you must design it to gracefully handle restarts
    ++focus, it's less likely to be killed; if the service is declared to <a
    ++href="#Foreground">run in the foreground</a>, it's rarely killed.
    ++If the service is started and is long-running, the system lowers its position
    ++in the list of background tasks over time, and the service becomes highly susceptible to
    ++killing&mdash;if your service is started, you must design it to gracefully handle restarts
    + by the system. If the system kills your service, it restarts it as soon as resources become
    +-available again (though this also depends on the value you return from {@link
    +-android.app.Service#onStartCommand onStartCommand()}, as discussed later). For more information
    ++available, but this also depends on the value that you return from {@link
    ++android.app.Service#onStartCommand onStartCommand()}. For more information
    + about when the system might destroy a service, see the <a
    + href="{@docRoot}guide/components/processes-and-threads.html">Processes and Threading</a>
    + document.</p>
    + 
    +-<p>In the following sections, you'll see how you can create each type of service and how to use
    +-it from other application components.</p>
    +-
    +-
    ++<p>In the following sections, you'll see how you can create the
    ++{@link android.content.Context#startService startService()} and
    ++{@link android.content.Context#bindService bindService()} service methods, as well as how to use
    ++them from other application components.</p>
    + 
    + <h3 id="Declaring">Declaring a service in the manifest</h3>
    + 
    +-<p>Like activities (and other components), you must declare all services in your application's
    +-manifest file.</p>
    ++<p>You must declare all services in your application's
    ++manifest file, just as you do for activities and other components.</p>
    + 
    + <p>To declare your service, add a <a
    +-href="{@docRoot}guide/topics/manifest/service-element.html">{@code <service>}</a> element
    ++href="{@docRoot}guide/topics/manifest/service-element.html">{@code &lt;service&gt;}</a> element
    + as a child of the <a
    +-href="{@docRoot}guide/topics/manifest/application-element.html">{@code <application>}</a>
    +-element. For example:</p>
    ++href="{@docRoot}guide/topics/manifest/application-element.html">{@code &lt;application&gt;}</a>
    ++element. Here is an example:</p>
    + 
    + <pre>
    + &lt;manifest ... &gt;
    +@@ -205,48 +218,44 @@ element. For example:</p>
    + </pre>
    + 
    + <p>See the <a
    +-href="{@docRoot}guide/topics/manifest/service-element.html">{@code <service>}</a> element
    ++href="{@docRoot}guide/topics/manifest/service-element.html">{@code &lt;service&gt;}</a> element
    + reference for more information about declaring your service in the manifest.</p>
    + 
    +-<p>There are other attributes you can include in the <a
    +-href="{@docRoot}guide/topics/manifest/service-element.html">{@code <service>}</a> element to
    +-define properties such as permissions required to start the service and the process in
    ++<p>There are other attributes that you can include in the <a
    ++href="{@docRoot}guide/topics/manifest/service-element.html">{@code &lt;service&gt;}</a> element to
    ++define properties such as the permissions that are required to start the service and the process in
    + which the service should run. The <a
    + href="{@docRoot}guide/topics/manifest/service-element.html#nm">{@code android:name}</a>
    +-attribute is the only required attribute&mdash;it specifies the class name of the service. Once
    +-you publish your application, you should not change this name, because if you do, you risk breaking
    ++attribute is the only required attribute&mdash;it specifies the class name of the service. After
    ++you publish your application, leave this name unchanged to avoid the risk of breaking
    + code due to dependence on explicit intents to start or bind the service (read the blog post, <a
    + href="http://android-developers.blogspot.com/2011/06/things-that-cannot-change.html">Things
    + That Cannot Change</a>).
    + 
    +-<p>To ensure your app is secure, <strong>always use an explicit intent when starting or binding
    +-your {@link android.app.Service}</strong> and do not declare intent filters for the service. If
    +-it's critical that you allow for some amount of ambiguity as to which service starts, you can
    +-supply intent filters for your services and exclude the component name from the {@link
    +-android.content.Intent}, but you then must set the package for the intent with {@link
    +-android.content.Intent#setPackage setPackage()}, which provides sufficient disambiguation for the
    +-target service.</p>
    ++<p class="caution"><strong>Caution</strong>: To ensure that your app is secure, always use an
    ++explicit intent when starting a {@link android.app.Service} and do not declare intent filters for
    ++your services. Using an implicit intent to start a service is a security hazard because you cannot
    ++be certain of the service that will respond to the intent, and the user cannot see which service
    ++starts. Beginning with Android 5.0 (API level 21), the system throws an exception if you call
    ++{@link android.content.Context#bindService bindService()} with an implicit intent.</p>
    + 
    +-<p>Additionally, you can ensure that your service is available to only your app by
    ++<p>You can ensure that your service is available to only your app by
    + including the <a
    + href="{@docRoot}guide/topics/manifest/service-element.html#exported">{@code android:exported}</a>
    +-attribute and setting it to {@code "false"}. This effectively stops other apps from starting your
    ++attribute and setting it to {@code false}. This effectively stops other apps from starting your
    + service, even when using an explicit intent.</p>
    + 
    +-
    +-
    +-
    +-<h2 id="CreatingStartedService">Creating a Started Service</h2>
    ++<h2 id="CreatingStartedService">Creating a started service</h2>
    + 
    + <p>A started service is one that another component starts by calling {@link
    +-android.content.Context#startService startService()}, resulting in a call to the service's
    ++android.content.Context#startService startService()}, which results in a call to the service's
    + {@link android.app.Service#onStartCommand onStartCommand()} method.</p>
    + 
    + <p>When a service is started, it has a lifecycle that's independent of the
    +-component that started it and the service can run in the background indefinitely, even if
    ++component that started it. The service can run in the background indefinitely, even if
    + the component that started it is destroyed. As such, the service should stop itself when its job
    +-is done by calling {@link android.app.Service#stopSelf stopSelf()}, or another component can stop it
    +-by calling {@link android.content.Context#stopService stopService()}.</p>
    ++is complete by calling {@link android.app.Service#stopSelf stopSelf()}, or another component can
    ++stop it by calling {@link android.content.Context#stopService stopService()}.</p>
    + 
    + <p>An application component such as an activity can start the service by calling {@link
    + android.content.Context#startService startService()} and passing an {@link android.content.Intent}
    +@@ -254,65 +263,65 @@ that specifies the service and includes any data for the service to use. The ser
    + this {@link android.content.Intent} in the {@link android.app.Service#onStartCommand
    + onStartCommand()} method.</p>
    + 
    +-<p>For instance, suppose an activity needs to save some data to an online database. The activity can
    +-start a companion service and deliver it the data to save by passing an intent to {@link
    ++<p>For instance, suppose an activity needs to save some data to an online database. The activity
    ++can start a companion service and deliver it the data to save by passing an intent to {@link
    + android.content.Context#startService startService()}. The service receives the intent in {@link
    +-android.app.Service#onStartCommand onStartCommand()}, connects to the Internet and performs the
    +-database transaction. When the transaction is done, the service stops itself and it is
    ++android.app.Service#onStartCommand onStartCommand()}, connects to the Internet, and performs the
    ++database transaction. When the transaction is complete, the service stops itself and is
    + destroyed.</p>
    + 
    + <p class="caution"><strong>Caution:</strong> A service runs in the same process as the application
    +-in which it is declared and in the main thread of that application, by default. So, if your service
    ++in which it is declared and in the main thread of that application by default. If your service
    + performs intensive or blocking operations while the user interacts with an activity from the same
    +-application, the service will slow down activity performance. To avoid impacting application
    +-performance, you should start a new thread inside the service.</p>
    ++application, the service slows down activity performance. To avoid impacting application
    ++performance, start a new thread inside the service.</p>
    + 
    + <p>Traditionally, there are two classes you can extend to create a started service:</p>
    ++
    + <dl>
    +   <dt>{@link android.app.Service}</dt>
    +-  <dd>This is the base class for all services. When you extend this class, it's important that
    +-you create a new thread in which to do all the service's work, because the service uses your
    +-application's main thread, by default, which could slow the performance of any activity your
    ++  <dd>This is the base class for all services. When you extend this class, it's important to
    ++create a new thread in which the service can complete all of its work; the service uses your
    ++application's main thread by default, which can slow the performance of any activity that your
    + application is running.</dd>
    +   <dt>{@link android.app.IntentService}</dt>
    +-  <dd>This is a subclass of {@link android.app.Service} that uses a worker thread to handle all
    +-start requests, one at a time. This is the best option if you don't require that your service
    +-handle multiple requests simultaneously. All you need to do is implement {@link
    ++  <dd>This is a subclass of {@link android.app.Service} that uses a worker thread to handle all of
    ++the start requests, one at a time. This is the best option if you don't require that your service
    ++handle multiple requests simultaneously. Implement {@link
    + android.app.IntentService#onHandleIntent onHandleIntent()}, which receives the intent for each
    +-start request so you can do the background work.</dd>
    ++start request so that you can complete the background work.</dd>
    + </dl>
    + 
    + <p>The following sections describe how you can implement your service using either one for these
    + classes.</p>
    + 
    +-
    + <h3 id="ExtendingIntentService">Extending the IntentService class</h3>
    + 
    +-<p>Because most started services don't need to handle multiple requests simultaneously
    +-(which can actually be a dangerous multi-threading scenario), it's probably best if you
    ++<p>Because most of the started services don't need to handle multiple requests simultaneously
    ++(which can actually be a dangerous multi-threading scenario), it's best that you
    + implement your service using the {@link android.app.IntentService} class.</p>
    + 
    +-<p>The {@link android.app.IntentService} does the following:</p>
    ++<p>The {@link android.app.IntentService} class does the following:</p>
    + 
    + <ul>
    +-  <li>Creates a default worker thread that executes all intents delivered to {@link
    +-android.app.Service#onStartCommand onStartCommand()} separate from your application's main
    ++  <li>It creates a default worker thread that executes all of the intents that are delivered to
    ++{@link android.app.Service#onStartCommand onStartCommand()}, separate from your application's main
    + thread.</li>
    +   <li>Creates a work queue that passes one intent at a time to your {@link
    + android.app.IntentService#onHandleIntent onHandleIntent()} implementation, so you never have to
    + worry about multi-threading.</li>
    +-  <li>Stops the service after all start requests have been handled, so you never have to call
    ++  <li>Stops the service after all of the start requests are handled, so you never have to call
    + {@link android.app.Service#stopSelf}.</li>
    +-  <li>Provides default implementation of {@link android.app.IntentService#onBind onBind()} that
    +-returns null.</li>
    ++  <li>Provides a default implementation of {@link android.app.IntentService#onBind onBind()}
    ++  that returns null.</li>
    +   <li>Provides a default implementation of {@link android.app.IntentService#onStartCommand
    + onStartCommand()} that sends the intent to the work queue and then to your {@link
    + android.app.IntentService#onHandleIntent onHandleIntent()} implementation.</li>
    + </ul>
    + 
    +-<p>All this adds up to the fact that all you need to do is implement {@link
    +-android.app.IntentService#onHandleIntent onHandleIntent()} to do the work provided by the
    +-client. (Though, you also need to provide a small constructor for the service.)</p>
    ++<p>To complete the work that is provided by the client, implement {@link
    ++android.app.IntentService#onHandleIntent onHandleIntent()}.
    ++However, you also need to provide a small constructor for the service.</p>
    + 
    + <p>Here's an example implementation of {@link android.app.IntentService}:</p>
    + 
    +@@ -352,12 +361,12 @@ android.app.IntentService#onHandleIntent onHandleIntent()}.</p>
    + <p>If you decide to also override other callback methods, such as {@link
    + android.app.IntentService#onCreate onCreate()}, {@link
    + android.app.IntentService#onStartCommand onStartCommand()}, or {@link
    +-android.app.IntentService#onDestroy onDestroy()}, be sure to call the super implementation, so
    ++android.app.IntentService#onDestroy onDestroy()}, be sure to call the super implementation so
    + that the {@link android.app.IntentService} can properly handle the life of the worker thread.</p>
    + 
    + <p>For example, {@link android.app.IntentService#onStartCommand onStartCommand()} must return
    +-the default implementation (which is how the intent gets delivered to {@link
    +-android.app.IntentService#onHandleIntent onHandleIntent()}):</p>
    ++the default implementation, which is how the intent is delivered to {@link
    ++android.app.IntentService#onHandleIntent onHandleIntent()}:</p>
    + 
    + <pre>
    + &#64;Override
    +@@ -369,22 +378,21 @@ public int onStartCommand(Intent intent, int flags, int startId) {
    + 
    + <p>Besides {@link android.app.IntentService#onHandleIntent onHandleIntent()}, the only method
    + from which you don't need to call the super class is {@link android.app.IntentService#onBind
    +-onBind()} (but you only need to implement that if your service allows binding).</p>
    ++onBind()}. You need to implement this only if your service allows binding.</p>
    + 
    + <p>In the next section, you'll see how the same kind of service is implemented when extending
    +-the base {@link android.app.Service} class, which is a lot more code, but which might be
    ++the base {@link android.app.Service} class, which uses more code, but might be
    + appropriate if you need to handle simultaneous start requests.</p>
    + 
    +-
    + <h3 id="ExtendingService">Extending the Service class</h3>
    + 
    +-<p>As you saw in the previous section, using {@link android.app.IntentService} makes your
    ++<p>Using {@link android.app.IntentService} makes your
    + implementation of a started service very simple. If, however, you require your service to
    +-perform multi-threading (instead of processing start requests through a work queue), then you
    ++perform multi-threading (instead of processing start requests through a work queue), you
    + can extend the {@link android.app.Service} class to handle each intent.</p>
    + 
    +-<p>For comparison, the following example code is an implementation of the {@link
    +-android.app.Service} class that performs the exact same work as the example above using {@link
    ++<p>For comparison, the following example code shows an implementation of the {@link
    ++android.app.Service} class that performs the same work as the previous example using {@link
    + android.app.IntentService}. That is, for each start request, it uses a worker thread to perform the
    + job and processes only one request at a time.</p>
    + 
    +@@ -460,20 +468,20 @@ public class HelloService extends Service {
    + 
    + <p>However, because you handle each call to {@link android.app.Service#onStartCommand
    + onStartCommand()} yourself, you can perform multiple requests simultaneously. That's not what
    +-this example does, but if that's what you want, then you can create a new thread for each
    +-request and run them right away (instead of waiting for the previous request to finish).</p>
    ++this example does, but if that's what you want, you can create a new thread for each
    ++request and run them right away instead of waiting for the previous request to finish.</p>
    + 
    + <p>Notice that the {@link android.app.Service#onStartCommand onStartCommand()} method must return an
    + integer. The integer is a value that describes how the system should continue the service in the
    +-event that the system kills it (as discussed above, the default implementation for {@link
    +-android.app.IntentService} handles this for you, though you are able to modify it). The return value
    ++event that the system kills it. The default implementation for {@link
    ++android.app.IntentService} handles this for you, but you are able to modify it. The return value
    + from {@link android.app.Service#onStartCommand onStartCommand()} must be one of the following
    + constants:</p>
    + 
    + <dl>
    +   <dt>{@link android.app.Service#START_NOT_STICKY}</dt>
    +     <dd>If the system kills the service after {@link android.app.Service#onStartCommand
    +-onStartCommand()} returns, <em>do not</em> recreate the service, unless there are pending
    ++onStartCommand()} returns, <em>do not</em> recreate the service unless there are pending
    + intents to deliver. This is the safest option to avoid running your service when not necessary
    + and when your application can simply restart any unfinished jobs.</dd>
    +   <dt>{@link android.app.Service#START_STICKY}</dt>
    +@@ -481,9 +489,9 @@ and when your application can simply restart any unfinished jobs.</dd>
    + onStartCommand()} returns, recreate the service and call {@link
    + android.app.Service#onStartCommand onStartCommand()}, but <em>do not</em> redeliver the last intent.
    + Instead, the system calls {@link android.app.Service#onStartCommand onStartCommand()} with a
    +-null intent, unless there were pending intents to start the service, in which case,
    ++null intent unless there are pending intents to start the service. In that case,
    + those intents are delivered. This is suitable for media players (or similar services) that are not
    +-executing commands, but running indefinitely and waiting for a job.</dd>
    ++executing commands but are running indefinitely and waiting for a job.</dd>
    +   <dt>{@link android.app.Service#START_REDELIVER_INTENT}</dt>
    +     <dd>If the system kills the service after {@link android.app.Service#onStartCommand
    + onStartCommand()} returns, recreate the service and call {@link
    +@@ -494,35 +502,35 @@ actively performing a job that should be immediately resumed, such as downloadin
    + <p>For more details about these return values, see the linked reference documentation for each
    + constant.</p>
    + 
    +-
    +-
    +-<h3 id="StartingAService">Starting a Service</h3>
    ++<h3 id="StartingAService">Starting a service</h3>
    + 
    + <p>You can start a service from an activity or other application component by passing an
    + {@link android.content.Intent} (specifying the service to start) to {@link
    + android.content.Context#startService startService()}. The Android system calls the service's {@link
    + android.app.Service#onStartCommand onStartCommand()} method and passes it the {@link
    +-android.content.Intent}. (You should never call {@link android.app.Service#onStartCommand
    +-onStartCommand()} directly.)</p>
    ++android.content.Intent}.
    ++
    ++<p class="note"><strong>Note</strong>: Never call
    ++{@link android.app.Service#onStartCommand onStartCommand()} directly.</p>
    + 
    + <p>For example, an activity can start the example service in the previous section ({@code
    + HelloService}) using an explicit intent with {@link android.content.Context#startService
    +-startService()}:</p>
    ++startService()}, as shown here:</p>
    + 
    + <pre>
    + Intent intent = new Intent(this, HelloService.class);
    + startService(intent);
    + </pre>
    + 
    +-<p>The {@link android.content.Context#startService startService()} method returns immediately and
    ++<p>The {@link android.content.Context#startService startService()} method returns immediately, and
    + the Android system calls the service's {@link android.app.Service#onStartCommand
    + onStartCommand()} method. If the service is not already running, the system first calls {@link
    +-android.app.Service#onCreate onCreate()}, then calls {@link android.app.Service#onStartCommand
    +-onStartCommand()}.</p>
    ++android.app.Service#onCreate onCreate()}, and then it calls
    ++{@link android.app.Service#onStartCommand onStartCommand()}.</p>
    + 
    +-<p>If the service does not also provide binding, the intent delivered with {@link
    ++<p>If the service does not also provide binding, the intent that is delivered with {@link
    + android.content.Context#startService startService()} is the only mode of communication between the
    +-application component and the service. However, if you want the service to send a result back, then
    ++application component and the service. However, if you want the service to send a result back,
    + the client that starts the service can create a {@link android.app.PendingIntent} for a broadcast
    + (with {@link android.app.PendingIntent#getBroadcast getBroadcast()}) and deliver it to the service
    + in the {@link android.content.Intent} that starts the service. The service can then use the
    +@@ -533,109 +541,102 @@ broadcast to deliver a result.</p>
    + the service (with {@link android.app.Service#stopSelf stopSelf()} or {@link
    + android.content.Context#stopService stopService()}) is required to stop it.</p>
    + 
    +-
    + <h3 id="Stopping">Stopping a service</h3>
    + 
    + <p>A started service must manage its own lifecycle. That is, the system does not stop or
    + destroy the service unless it must recover system memory and the service
    +-continues to run after {@link android.app.Service#onStartCommand onStartCommand()} returns. So,
    +-the service must stop itself by calling {@link android.app.Service#stopSelf stopSelf()} or another
    ++continues to run after {@link android.app.Service#onStartCommand onStartCommand()} returns. The
    ++service must stop itself by calling {@link android.app.Service#stopSelf stopSelf()}, or another
    + component can stop it by calling {@link android.content.Context#stopService stopService()}.</p>
    + 
    + <p>Once requested to stop with {@link android.app.Service#stopSelf stopSelf()} or {@link
    + android.content.Context#stopService stopService()}, the system destroys the service as soon as
    + possible.</p>
    + 
    +-<p>However, if your service handles multiple requests to {@link
    +-android.app.Service#onStartCommand onStartCommand()} concurrently, then you shouldn't stop the
    +-service when you're done processing a start request, because you might have since received a new
    ++<p>If your service handles multiple requests to {@link
    ++android.app.Service#onStartCommand onStartCommand()} concurrently, you shouldn't stop the
    ++service when you're done processing a start request, as you might have received a new
    + start request (stopping at the end of the first request would terminate the second one). To avoid
    + this problem, you can use {@link android.app.Service#stopSelf(int)} to ensure that your request to
    + stop the service is always based on the most recent start request. That is, when you call {@link
    + android.app.Service#stopSelf(int)}, you pass the ID of the start request (the <code>startId</code>
    + delivered to {@link android.app.Service#onStartCommand onStartCommand()}) to which your stop request
    +-corresponds. Then if the service received a new start request before you were able to call {@link
    +-android.app.Service#stopSelf(int)}, then the ID will not match and the service will not stop.</p>
    ++corresponds. Then, if the service receives a new start request before you are able to call {@link
    ++android.app.Service#stopSelf(int)}, the ID does not match and the service does not stop.</p>
    + 
    +-<p class="caution"><strong>Caution:</strong> It's important that your application stops its services
    +-when it's done working, to avoid wasting system resources and consuming battery power. If necessary,
    +-other components can stop the service by calling {@link
    ++<p class="caution"><strong>Caution:</strong> To avoid wasting system resources and consuming
    ++battery power, ensure that your application stops its services when it's done working.
    ++If necessary, other components can stop the service by calling {@link
    + android.content.Context#stopService stopService()}. Even if you enable binding for the service,
    +-you must always stop the service yourself if it ever received a call to {@link
    ++you must always stop the service yourself if it ever receives a call to {@link
    + android.app.Service#onStartCommand onStartCommand()}.</p>
    + 
    + <p>For more information about the lifecycle of a service, see the section below about <a
    + href="#Lifecycle">Managing the Lifecycle of a Service</a>.</p>
    + 
    +-
    +-
    +-<h2 id="CreatingBoundService">Creating a Bound Service</h2>
    ++<h2 id="CreatingBoundService">Creating a bound service</h2>
    + 
    + <p>A bound service is one that allows application components to bind to it by calling {@link
    +-android.content.Context#bindService bindService()} in order to create a long-standing connection
    +-(and generally does not allow components to <em>start</em> it by calling {@link
    +-android.content.Context#startService startService()}).</p>
    ++android.content.Context#bindService bindService()} to create a long-standing connection.
    ++It generally doesn't allow components to <em>start</em> it by calling {@link
    ++android.content.Context#startService startService()}.</p>
    + 
    +-<p>You should create a bound service when you want to interact with the service from activities
    ++<p>Create a bound service when you want to interact with the service from activities
    + and other components in your application or to expose some of your application's functionality to
    +-other applications, through interprocess communication (IPC).</p>
    ++other applications through interprocess communication (IPC).</p>
    + 
    +-<p>To create a bound service, you must implement the {@link
    ++<p>To create a bound service, implement the {@link
    + android.app.Service#onBind onBind()} callback method to return an {@link android.os.IBinder} that
    + defines the interface for communication with the service. Other application components can then call
    + {@link android.content.Context#bindService bindService()} to retrieve the interface and
    + begin calling methods on the service. The service lives only to serve the application component that
    +-is bound to it, so when there are no components bound to the service, the system destroys it
    +-(you do <em>not</em> need to stop a bound service in the way you must when the service is started
    +-through {@link android.app.Service#onStartCommand onStartCommand()}).</p>
    ++is bound to it, so when there are no components bound to the service, the system destroys it.
    ++You do <em>not</em> need to stop a bound service in the same way that you must when the service is
    ++started through {@link android.app.Service#onStartCommand onStartCommand()}.</p>
    + 
    +-<p>To create a bound service, the first thing you must do is define the interface that specifies
    +-how a client can communicate with the service. This interface between the service
    ++<p>To create a bound service, you must define the interface that specifies how a client can
    ++communicate with the service. This interface between the service
    + and a client must be an implementation of {@link android.os.IBinder} and is what your service must
    + return from the {@link android.app.Service#onBind
    +-onBind()} callback method. Once the client receives the {@link android.os.IBinder}, it can begin
    ++onBind()} callback method. After the client receives the {@link android.os.IBinder}, it can begin
    + interacting with the service through that interface.</p>
    + 
    +-<p>Multiple clients can bind to the service at once. When a client is done interacting with the
    +-service, it calls {@link android.content.Context#unbindService unbindService()} to unbind. Once
    +-there are no clients bound to the service, the system destroys the service.</p>
    ++<p>Multiple clients can bind to the service simultaneously. When a client is done interacting with
    ++the service, it calls {@link android.content.Context#unbindService unbindService()} to unbind.
    ++When there are no clients bound to the service, the system destroys the service.</p>
    + 
    +-<p>There are multiple ways to implement a bound service and the implementation is more
    +-complicated than a started service, so the bound service discussion appears in a separate
    +-document about <a
    ++<p>There are multiple ways to implement a bound service, and the implementation is more
    ++complicated than a started service. For these reasons, the bound service discussion appears in a
    ++separate document about <a
    + href="{@docRoot}guide/components/bound-services.html">Bound Services</a>.</p>
    + 
    ++<h2 id="Notifications">Sending notifications to the user</h2>
    + 
    +-
    +-<h2 id="Notifications">Sending Notifications to the User</h2>
    +-
    +-<p>Once running, a service can notify the user of events using <a
    ++<p>When a service is running, it can notify the user of events using <a
    + href="{@docRoot}guide/topics/ui/notifiers/toasts.html">Toast Notifications</a> or <a
    + href="{@docRoot}guide/topics/ui/notifiers/notifications.html">Status Bar Notifications</a>.</p>
    + 
    +-<p>A toast notification is a message that appears on the surface of the current window for a
    +-moment then disappears, while a status bar notification provides an icon in the status bar with a
    ++<p>A toast notification is a message that appears on the surface of the current window for only a
    ++moment before disappearing. A status bar notification provides an icon in the status bar with a
    + message, which the user can select in order to take an action (such as start an activity).</p>
    + 
    +-<p>Usually, a status bar notification is the best technique when some background work has completed
    +-(such as a file completed
    +-downloading) and the user can now act on it. When the user selects the notification from the
    +-expanded view, the notification can start an activity (such as to view the downloaded file).</p>
    ++<p>Usually, a status bar notification is the best technique to use when background work such as
    ++a file download has completed, and the user can now act on it. When the user
    ++selects the notification from the expanded view, the notification can start an activity
    ++(such as to display the downloaded file).</p>
    + 
    + <p>See the <a
    + href="{@docRoot}guide/topics/ui/notifiers/toasts.html">Toast Notifications</a> or <a
    + href="{@docRoot}guide/topics/ui/notifiers/notifications.html">Status Bar Notifications</a>
    + developer guides for more information.</p>
    + 
    ++<h2 id="Foreground">Running a service in the foreground</h2>
    + 
    +-
    +-<h2 id="Foreground">Running a Service in the Foreground</h2>
    +-
    +-<p>A foreground service is a service that's considered to be something the
    +-user is actively aware of and thus not a candidate for the system to kill when low on memory. A
    ++<p>A foreground service is a service that the
    ++user is actively aware of and is not a candidate for the system to kill when low on memory. A
    + foreground service must provide a notification for the status bar, which is placed under the
    +-"Ongoing" heading, which means that the notification cannot be dismissed unless the service is
    +-either stopped or removed from the foreground.</p>
    ++<em>Ongoing</em> heading. This means that the notification cannot be dismissed unless the service
    ++is either stopped or removed from the foreground.</p>
    + 
    + <p>For example, a music player that plays music from a service should be set to run in the
    + foreground, because the user is explicitly aware
    +@@ -643,9 +644,9 @@ of its operation. The notification in the status bar might indicate the current
    + the user to launch an activity to interact with the music player.</p>
    + 
    + <p>To request that your service run in the foreground, call {@link
    +-android.app.Service#startForeground startForeground()}. This method takes two parameters: an integer
    +-that uniquely identifies the notification and the {@link
    +-android.app.Notification} for the status bar. For example:</p>
    ++android.app.Service#startForeground startForeground()}. This method takes two parameters: an
    ++integer that uniquely identifies the notification and the {@link
    ++android.app.Notification} for the status bar. Here is an example:</p>
    + 
    + <pre>
    + Notification notification = new Notification(R.drawable.icon, getText(R.string.ticker_text),
    +@@ -657,30 +658,27 @@ notification.setLatestEventInfo(this, getText(R.string.notification_title),
    + startForeground(ONGOING_NOTIFICATION_ID, notification);
    + </pre>
    + 
    +-<p class="caution"><strong>Caution:</strong> The integer ID you give to {@link
    ++<p class="caution"><strong>Caution:</strong> The integer ID that you give to {@link
    + android.app.Service#startForeground startForeground()} must not be 0.</p>
    + 
    +-
    + <p>To remove the service from the foreground, call {@link
    +-android.app.Service#stopForeground stopForeground()}. This method takes a boolean, indicating
    ++android.app.Service#stopForeground stopForeground()}. This method takes a boolean, which indicates
    + whether to remove the status bar notification as well. This method does <em>not</em> stop the
    +-service. However, if you stop the service while it's still running in the foreground, then the
    ++service. However, if you stop the service while it's still running in the foreground, the
    + notification is also removed.</p>
    + 
    + <p>For more information about notifications, see <a
    + href="{@docRoot}guide/topics/ui/notifiers/notifications.html">Creating Status Bar
    + Notifications</a>.</p>
    + 
    ++<h2 id="Lifecycle">Managing the lifecycle of a service</h2>
    + 
    ++<p>The lifecycle of a service is much simpler than that of an activity. However, it's even more
    ++important that you pay close attention to how your service is created and destroyed because a
    ++service can run in the background without the user being aware.</p>
    + 
    +-<h2 id="Lifecycle">Managing the Lifecycle of a Service</h2>
    +-
    +-<p>The lifecycle of a service is much simpler than that of an activity. However, it's even more important
    +-that you pay close attention to how your service is created and destroyed, because a service
    +-can run in the background without the user being aware.</p>
    +-
    +-<p>The service lifecycle&mdash;from when it's created to when it's destroyed&mdash;can follow two
    +-different paths:</p>
    ++<p>The service lifecycle&mdash;from when it's created to when it's destroyed&mdash;can follow
    ++either of these two paths:</p>
    + 
    + <ul>
    + <li>A started service
    +@@ -689,27 +687,26 @@ android.content.Context#startService startService()}. The service then runs inde
    + stop itself by calling {@link
    + android.app.Service#stopSelf() stopSelf()}. Another component can also stop the
    + service by calling {@link android.content.Context#stopService
    +-stopService()}. When the service is stopped, the system destroys it..</p></li>
    ++stopService()}. When the service is stopped, the system destroys it.</p></li>
    + 
    + <li>A bound service
    +   <p>The service is created when another component (a client) calls {@link
    + android.content.Context#bindService bindService()}. The client then communicates with the service
    + through an {@link android.os.IBinder} interface. The client can close the connection by calling
    + {@link android.content.Context#unbindService unbindService()}. Multiple clients can bind to
    +-the same service and when all of them unbind, the system destroys the service. (The service
    +-does <em>not</em> need to stop itself.)</p></li>
    ++the same service and when all of them unbind, the system destroys the service. The service
    ++does <em>not</em> need to stop itself.</p></li>
    + </ul>
    + 
    +-<p>These two paths are not entirely separate. That is, you can bind to a service that was already
    +-started with {@link android.content.Context#startService startService()}. For example, a background
    +-music service could be started by calling {@link android.content.Context#startService
    ++<p>These two paths are not entirely separate. You can bind to a service that is already
    ++started with {@link android.content.Context#startService startService()}. For example, you can
    ++start a background music service by calling {@link android.content.Context#startService
    + startService()} with an {@link android.content.Intent} that identifies the music to play. Later,
    + possibly when the user wants to exercise some control over the player or get information about the
    + current song, an activity can bind to the service by calling {@link
    +-android.content.Context#bindService bindService()}. In cases like this, {@link
    ++android.content.Context#bindService bindService()}. In cases such as this, {@link
    + android.content.Context#stopService stopService()} or {@link android.app.Service#stopSelf
    +-stopSelf()} does not actually stop the service until all clients unbind. </p>
    +-
    ++stopSelf()} doesn't actually stop the service until all of the clients unbind.</p>
    + 
    + <h3 id="LifecycleCallbacks">Implementing the lifecycle callbacks</h3>
    + 
    +@@ -763,20 +760,30 @@ shows the lifecycle when the service is created with {@link android.content.Cont
    + startService()} and the diagram on the right shows the lifecycle when the service is created
    + with {@link android.content.Context#bindService bindService()}.</p>
    + 
    +-<p>By implementing these methods, you can monitor two nested loops of the service's lifecycle: </p>
    ++<p>Figure 2 illustrates the typical callback methods for a service. Although the figure separates
    ++services that are created by {@link android.content.Context#startService startService()} from those
    ++created by {@link android.content.Context#bindService bindService()}, keep
    ++in mind that any service, no matter how it's started, can potentially allow clients to bind to it.
    ++A service that was initially started with {@link android.app.Service#onStartCommand
    ++onStartCommand()} (by a client calling {@link android.content.Context#startService startService()})
    ++can still receive a call to {@link android.app.Service#onBind onBind()} (when a client calls
    ++{@link android.content.Context#bindService bindService()}).</p>
    ++
    ++<p>By implementing these methods, you can monitor these two nested loops of the service's
    ++lifecycle:</p>
    + 
    + <ul>
    +-<li>The <strong>entire lifetime</strong> of a service happens between the time {@link
    +-android.app.Service#onCreate onCreate()} is called and the time {@link
    ++<li>The <strong>entire lifetime</strong> of a service occurs between the time that {@link
    ++android.app.Service#onCreate onCreate()} is called and the time that {@link
    + android.app.Service#onDestroy} returns. Like an activity, a service does its initial setup in
    + {@link android.app.Service#onCreate onCreate()} and releases all remaining resources in {@link
    +-android.app.Service#onDestroy onDestroy()}.  For example, a
    +-music playback service could create the thread where the music will be played in {@link
    +-android.app.Service#onCreate onCreate()}, then stop the thread in {@link
    ++android.app.Service#onDestroy onDestroy()}. For example, a
    ++music playback service can create the thread where the music is played in {@link
    ++android.app.Service#onCreate onCreate()}, and then it can stop the thread in {@link
    + android.app.Service#onDestroy onDestroy()}.
    + 
    +-<p>The {@link android.app.Service#onCreate onCreate()} and {@link android.app.Service#onDestroy
    +-onDestroy()} methods are called for all services, whether
    ++<p class="note"><strong>Note</strong>: The {@link android.app.Service#onCreate onCreate()}
    ++and {@link android.app.Service#onDestroy onDestroy()} methods are called for all services, whether
    + they're created by {@link android.content.Context#startService startService()} or {@link
    + android.content.Context#bindService bindService()}.</p></li>
    + 
    +@@ -784,8 +791,8 @@ android.content.Context#bindService bindService()}.</p></li>
    + android.app.Service#onStartCommand onStartCommand()} or {@link android.app.Service#onBind onBind()}.
    + Each method is handed the {@link
    + android.content.Intent} that was passed to either {@link android.content.Context#startService
    +-startService()} or {@link android.content.Context#bindService bindService()}, respectively.
    +-<p>If the service is started, the active lifetime ends the same time that the entire lifetime
    ++startService()} or {@link android.content.Context#bindService bindService()}.
    ++<p>If the service is started, the active lifetime ends at the same time that the entire lifetime
    + ends (the service is still active even after {@link android.app.Service#onStartCommand
    + onStartCommand()} returns). If the service is bound, the active lifetime ends when {@link
    + android.app.Service#onUnbind onUnbind()} returns.</p>
    +@@ -795,26 +802,16 @@ android.app.Service#onUnbind onUnbind()} returns.</p>
    + <p class="note"><strong>Note:</strong> Although a started service is stopped by a call to
    + either {@link android.app.Service#stopSelf stopSelf()} or {@link
    + android.content.Context#stopService stopService()}, there is not a respective callback for the
    +-service (there's no {@code onStop()} callback). So, unless the service is bound to a client,
    ++service (there's no {@code onStop()} callback). Unless the service is bound to a client,
    + the system destroys it when the service is stopped&mdash;{@link
    + android.app.Service#onDestroy onDestroy()} is the only callback received.</p>
    + 
    +-<p>Figure 2 illustrates the typical callback methods for a service. Although the figure separates
    +-services that are created by {@link android.content.Context#startService startService()} from those
    +-created by {@link android.content.Context#bindService bindService()}, keep
    +-in mind that any service, no matter how it's started, can potentially allow clients to bind to it.
    +-So, a service that was initially started with {@link android.app.Service#onStartCommand
    +-onStartCommand()} (by a client calling {@link android.content.Context#startService startService()})
    +-can still receive a call to {@link android.app.Service#onBind onBind()} (when a client calls
    +-{@link android.content.Context#bindService bindService()}).</p>
    +-
    + <p>For more information about creating a service that provides binding, see the <a
    + href="{@docRoot}guide/components/bound-services.html">Bound Services</a> document,
    + which includes more information about the {@link android.app.Service#onRebind onRebind()}
    + callback method in the section about <a
    +-href="{@docRoot}guide/components/bound-services.html#Lifecycle">Managing the Lifecycle of
    +-a Bound Service</a>.</p>
    +-
    ++href="{@docRoot}guide/components/bound-services.html#Lifecycle">Managing the lifecycle of
    ++a bound service</a>.</p>
    + 
    + <!--
    + <h2>Beginner's Path</h2>
    +diff --git a/docs/html/guide/guide_toc.cs b/docs/html/guide/guide_toc.cs
    +index 9257a76..8fe3f20 100644
    +--- a/docs/html/guide/guide_toc.cs
    ++++ b/docs/html/guide/guide_toc.cs
    +@@ -545,9 +545,16 @@
    +          <li><a href="<?cs var:toroot ?>guide/topics/data/data-storage.html">
    +             <span class="en">Storage Options</span>
    +            </a></li>
    +-        <li><a href="<?cs var:toroot ?>guide/topics/data/backup.html">
    ++        <li class="nav-section">
    ++          <div class="nav-section-header"><a href="<?cs var:toroot ?>guide/topics/data/backup.html">
    +             <span class="en">Data Backup</span>
    +-          </a></li>
    ++          </a></div>
    ++          <ul>
    ++            <li><a href="<?cs var:toroot ?>guide/topics/data/autobackup.html">Auto Backup</a></li>
    ++            <li><a href="<?cs var:toroot ?>guide/topics/data/keyvaluebackup.html">Key/Value Backup</a></li>
    ++            <li><a href="<?cs var:toroot ?>guide/topics/data/testingbackup.html">Testing Backup and Restore</a></li>
    ++          </ul>
    ++        </li>
    +         <li><a href="<?cs var:toroot ?>guide/topics/data/install-location.html">
    +             <span class="en">App Install Location</span>
    +           </a></li>
    +diff --git a/docs/html/guide/topics/connectivity/nfc/nfc.jd b/docs/html/guide/topics/connectivity/nfc/nfc.jd
    +index 520f520..881a75f 100644
    +--- a/docs/html/guide/topics/connectivity/nfc/nfc.jd
    ++++ b/docs/html/guide/topics/connectivity/nfc/nfc.jd
    +@@ -487,19 +487,22 @@ intent. The following example checks for the {@link android.nfc.NfcAdapter#ACTIO
    + intent and gets the NDEF messages from an intent extra.</p>
    + 
    + <pre>
    +-public void onResume() {
    +-    super.onResume();
    ++&#64;Override
    ++protected void onNewIntent(Intent intent) {
    ++    super.onNewIntent(intent);
    +     ...
    +-    if (NfcAdapter.ACTION_NDEF_DISCOVERED.equals(getIntent().getAction())) {
    +-        Parcelable[] rawMsgs = intent.getParcelableArrayExtra(NfcAdapter.EXTRA_NDEF_MESSAGES);
    +-        if (rawMsgs != null) {
    +-            msgs = new NdefMessage[rawMsgs.length];
    +-            for (int i = 0; i &lt; rawMsgs.length; i++) {
    +-                msgs[i] = (NdefMessage) rawMsgs[i];
    ++    if (intent != null &amp;&amp; NfcAdapter.ACTION_NDEF_DISCOVERED.equals(intent.getAction())) {
    ++        Parcelable[] rawMessages =
    ++            intent.getParcelableArrayExtra(NfcAdapter.EXTRA_NDEF_MESSAGES);
    ++        if (rawMessages != null) {
    ++            NdefMessage[] messages = new NdefMessage[rawMessages.length];
    ++            for (int i = 0; i < rawMessages.length; i++) {
    ++                messages[i] = (NdefMessage) rawMessages[i];
    +             }
    ++            // Process the messages array.
    ++            ...
    +         }
    +     }
    +-    //process the msgs array
    + }
    + </pre>
    + 
    +diff --git a/docs/html/guide/topics/data/autobackup.jd b/docs/html/guide/topics/data/autobackup.jd
    +new file mode 100644
    +index 0000000..3be09d7
    +--- /dev/null
    ++++ b/docs/html/guide/topics/data/autobackup.jd
    +@@ -0,0 +1,257 @@
    ++page.title=Auto Backup for Apps
    ++page.tags=backup, marshmallow, androidm
    ++page.keywords=backup, autobackup
    ++page.image=images/cards/card-auto-backup_2x.png
    ++
    ++@jd:body
    ++
    ++<div id="qv-wrapper">
    ++<div id="qv">
    ++  <h2>In this document</h2>
    ++  <ol>
    ++    <li><a href="#Files">Files that are backed up</a></li>
    ++    <li><a href="#BackupLocation">Backup location</a></li>
    ++    <li><a href="#BackupSchedule">Backup schedule</a></li>
    ++    <li><a href="#RestoreSchedule">Restore schedule</a></li>
    ++    <li><a href="#EnablingAutoBackup">Enabling and disabling Auto Backup</a></li>
    ++    <li><a href="#IncludingFiles">Including and excluding files</a><ul>
    ++      <li><a href="#XMLSyntax">XML config syntax</a></li>
    ++    </ul></li>
    ++    <li><a href="#ImplementingBackupAgent">Implementing BackupAgent</a></li>
    ++  </ol>
    ++
    ++  <h2>Key classes</h2>
    ++  <ol>
    ++    <li>{@link android.app.backup.BackupAgent}</li>
    ++    <li><a href="{@docRoot}reference/android/R.attr.html">R.attr</a></li>
    ++  </ol>
    ++
    ++</div>
    ++</div>
    ++
    ++Since Android 6.0 (API 23), Android has offered the <em>Auto Backup for Apps</em> feature as
    ++a way for developers to quickly add backup functionality to their apps. Auto
    ++Backup preserves app data by uploading it to the user’s Google Drive account.
    ++The amount of data is limited to 25MB per user of your app and there is no
    ++charge for storing backup data.
    ++
    ++<h2 id="Files">Files that are backed up</h2>
    ++<p>By default, Auto Backup includes files in most of the directories that are
    ++assigned to your app by the system:
    ++<ul>
    ++  <li>Shared preferences files.
    ++  <li>Files in the directory returned by {@link android.content.Context#getFilesDir()}.
    ++  <li>Files in the directory returned by {@link android.content.Context#getDatabasePath(String)},
    ++    which also includes files created with the
    ++    {@link android.database.sqlite.SQLiteOpenHelper} class.
    ++  <li>Files in directories created with {@link android.content.Context#getDir(String,int)}.
    ++  <li>Files on external storage in the directory returned by
    ++    {@link android.content.Context#getExternalFilesDir(String)}.</li></ul>
    ++
    ++<p>Auto Backup excludes files in directories returned by
    ++  {@link android.content.Context#getCacheDir()},
    ++  {@link android.content.Context#getCodeCacheDir()}, or
    ++  {@link android.content.Context#getNoBackupFilesDir()}. The files saved
    ++  in these locations are only needed temporarily, or are intentionally
    ++  excluded from backup operations.
    ++
    ++<p>You can configure your app to include and exclude particular files.
    ++For more information, see the <a href="#IncludingFiles">Include and exclude files</a>
    ++section.
    ++
    ++<h2 id="BackupLocation">Backup location</h2>
    ++<p>Backup data is stored in a private folder in the user's Google Drive account,
    ++limited to 25MB per app. The saved data does not count towards the user's
    ++personal Google Drive quota. Only the most recent backup is stored. When a
    ++backup is made, the previous backup (if one exists) is deleted.
    ++
    ++<p>Users can see a list of apps that have been backed up in the Google Drive app under
    ++<strong>Settings -> Auto Backup for apps -> Manage backup</strong>. The
    ++backup data cannot be read by the user or other applications on the device.
    ++
    ++<p>Backups from each device-setup-lifetime are stored in separate datasets
    ++as shown in the following examples:
    ++<ul>
    ++  <li>If the user owns two devices, then a backup dataset exists for each device.
    ++  <li>If the user factory resets a device and then sets up the device with the
    ++    same account, the backup is stored in a new dataset. Obsolete datasets are
    ++    automatically deleted after a period of inactivity.</li></ul>
    ++
    ++<p class="caution"><strong>Caution:</strong> Once the amount of data reaches
    ++25MB, the app is banned from sending data to the
    ++cloud, even if the amount of data later falls under the 25MB threshold. The ban
    ++affects only the offending device (not other devices that the user owns) and
    ++lasts for the entire device-setup-lifetime. For example, if the user removes and
    ++reinstalls the application, the ban is still in effect. The ban is lifted when
    ++the user performs factory reset on the device.
    ++
    ++<h2 id="BackupSchedule">Backup schedule</h2>
    ++<p>Backups occur automatically when all of the following conditions are met:
    ++<ul>
    ++  <li>The user has enabled backup on the device in <strong>Settings</strong> >
    ++    <strong>Backup &amp; Reset</strong>.
    ++  <li>At least 24 hours have elapsed since the last backup.
    ++  <li>The device is idle and charging.
    ++  <li>The device is connected to a Wi-Fi network. If the device is never connected
    ++    to a wifi network, then Auto Backup never occurs.</li></ul>
    ++
    ++<p>In practice, these conditions occur roughly every night. To conserve network
    ++bandwidth, upload takes place only if app data has changed.
    ++
    ++<p>During Auto Backup, the system shuts down the app to make sure it is no longer
    ++writing to the file system. By default, the backup system ignores apps that are
    ++running in the foreground because users would notice their apps being shut down.
    ++You can override the default behavior by setting the
    ++<a href="{@docRoot}reference/android/R.attr.html#backupInForeground">backupInForeground</a>
    ++attribute to true.
    ++
    ++<p>To simplify testing, Android includes tools that let you manually initiate
    ++a backup of your app. For more information, see
    ++<a href="{@docRoot}guide/topics/data/testingbackup.html">Testing Backup and Restore</a>.
    ++
    ++<h2 id="RestoreSchedule">Restore schedule</h2>
    ++<p>Data is restored whenever the app is installed, either from the Play store,
    ++during device setup (when the system installs previously installed apps), or
    ++from running adb install. The restore operation occurs after the APK is
    ++installed, but before the app is available to be launched by the user.
    ++
    ++<p>During the initial device setup wizard, the user is shown a list of available backup
    ++datasets and is asked which one to restore the data from. Whichever backup
    ++dataset is selected becomes the ancestral dataset for the device. The device can
    ++restore from either its own backups or the ancestral dataset. The device
    ++prioritize its own backup if backups from both sources are available. If the
    ++user didn't go through the device setup wizard, then the device can restore only from
    ++its own backups.
    ++
    ++<p>To simplify testing, Android includes tools that let you manually initiate
    ++a restore of your app. For more information, see
    ++<a href="{@docRoot}guide/topics/data/testingbackup.html">Testing Backup and Restore</a>.
    ++
    ++<h2 id="EnablingAutoBackup">Enabling and disabling backup</h2>
    ++<p>Apps that target Android 6.0 (API level 23) or higher automatically participate
    ++in Auto Backup. This is because the
    ++<a href="{@docRoot}reference/android/R.attr.html#allowBackup">android:allowBackup</a>
    ++attribute, which enables/disables backup, defaults to <code>true</code> if omitted.
    ++To avoid confusion, we recommend you explicitly set the attribute in the <code>&lt;application></code>
    ++element of your <code>AndroidManifest.xml</code>. For example:
    ++
    ++<pre class="prettyprint">&lt;application ...
    ++    android:allowBackup="true">
    ++&lt;/app></pre>
    ++
    ++<p>To disable Auto Backup, add either of the following attributes to the
    ++application element in your manifest file:
    ++
    ++<ul>
    ++  <li>set <code>android:allowBackup</code> to <code>false</code>. This completely disables data
    ++    backup. You may want to disable backups when your app can recreate its state
    ++    through some other mechanism or when your app deals with sensitive
    ++    information that should not be backed up.</li>
    ++  <li>set <code>android:allowBackup</code> to <code>true</code> and
    ++    <code>android:fullBackupOnly</code> to <code>false</code>. With these settings,
    ++    your app always participates in Key/Value Backup, even when running on devices that
    ++    support Auto Backup.</li></ul>
    ++
    ++<h2 id="IncludingFiles">Including and excluding files</h2>
    ++<p>By default, the system backs up almost all app data. For more information,
    ++see <a href="#Files">Files that are backed up</a>. This section shows you how to
    ++define custom XML rules to control what gets backed up.
    ++
    ++<ol>
    ++  <li>In <code>AndroidManifest.xml</code>, add the <a href="{@docRoot}reference/android/R.attr.html#fullBackupContent">android:fullBackupContent</a> attribute to the
    ++  <code>&lt;application></code> element. This attribute points to an XML file that contains backup
    ++  rules. For example:
    ++  <pre class="prettyprint">&lt;application ...
    ++    android:fullBackupContent="@xml/my_backup_rules">
    ++  &lt;/app></pre></li>
    ++  <li>Create an XML file called <code>my_backup_rules.xml</code> in the <code>res/xml/</code> directory. Inside the file, add rules with the <code>&lt;include></code> and <code>&lt;exclude></code> elements. The following sample backs up all shared preferences except <code>device.xml</code>:
    ++  <pre>&lt;?xml version="1.0" encoding="utf-8"?>
    ++&lt;full-backup-content>
    ++    &lt;include domain="sharedpref" path="."/>
    ++    &lt;exclude domain="sharedpref" path="device.xml"/>
    ++&lt;/full-backup-content></pre></li>
    ++
    ++<h3 id="XMLSyntax">XML Config Syntax</h3>
    ++<p>The XML syntax for the configuration file is shown below:
    ++
    ++<pre class="prettyprint">&lt;full-backup-content>
    ++    &lt;include domain=["file" | "database" | "sharedpref" | "external" | "root"]
    ++    path="string" />
    ++    &lt;exclude domain=["file" | "database" | "sharedpref" | "external" | "root"]
    ++    path="string" />
    ++&lt;/full-backup-content></pre>
    ++
    ++<p>Inside the <code>&lt;full-backup-content></code> tag, you can define <code>&lt;include></code> and <code>&lt;exclude></code>
    ++elements:
    ++
    ++<ul>
    ++  <li><code>&lt;include></code> - Specifies a file or folder to backup. By default, Auto Backup
    ++includes almost all app files. If you specify an &lt;include> element, the system
    ++no longer includes any files by default and backs up <em>only the files
    ++specified</em>. To include multiple files, use multiple &lt;include> elements.
    ++  <p>note: Files in directories returned by <code>getCacheDir()</code>, <code>getCodeCacheDir()</code>, or
    ++<code>getNoBackupFilesDir()</code> are always excluded even if you try to include them.</li>
    ++
    ++  <li><code>&lt;exclude></code> - Specifies a file or folder to exclude during backup. Here are
    ++some files that are typically excluded from backup: <ul>
    ++    <li>Files that have device specific identifiers, either issued by a server or
    ++generated on the device. For example, <a href="https://developers.google.com/cloud-messaging/android/start">Google Cloud Messaging (GCM)</a> needs to
    ++generate a registration token every time a user installs your app on a new
    ++device. If the old registration token is restored, the app may behave
    ++unexpectedly.
    ++    <li>Account credentials or other sensitive information. Consider asking the
    ++user to reauthenticate the first time they launch a restored app rather than
    ++allowing for storage of such information in the backup.
    ++    <li>Files related to app debugging, such as <a href="{@docRoot}studio/run/index.html#instant-run">instant run files</a>. To exclude instant run files, add the rule <code>&lt;exclude
    ++domain="file" path="instant-run"/></code>
    ++    <li>Large files that cause the app to exceed the 25MB backup quota.</li> </ul>
    ++  </li> </ul>
    ++
    ++<p class="note"><strong>Note:</strong> If your configuration file specifies both elements, then the
    ++backup contains everything captured by the <code>&lt;include></code> elements minus the
    ++resources named in the <code>&lt;exclude></code> elements. In other words,
    ++<code>&lt;exclude></code> takes precedence.
    ++
    ++<p>Each element must include the following two attributes:
    ++<ul>
    ++  <li><code>domain</code> - specifies the location of resource. Valid values for this attribute
    ++include the following: <ul>
    ++    <li><code>root</code> - the directory on the filesystem where all private files belonging to
    ++this app are stored.
    ++    <li><code>file</code> - directories returned by {@link android.content.Context#getFilesDir()}.
    ++    <li><code>database</code> - directories returned by {@link android.content.Context#getDatabasePath(String) getDatabasePath()}.
    ++Databases created with {@link android.database.sqlite.SQLiteOpenHelper}
    ++are stored here.
    ++    <li><code>sharedpref</code> - the directory where {@link android.content.SharedPreferences}
    ++are stored.
    ++    <li><code>external</code> the directory returned by {@link android.content.Context#getExternalFilesDir(String) getExternalFilesDir()}
    ++    <p>Note: You cannot backup files outside of these locations.</li></ul>
    ++  <li><code>path</code>: Specifies a file or folder to include in or exclude from backup. Note
    ++that: <ul>
    ++    <li>This attribute does not support wildcard or regex syntax.
    ++    <li>You can use <code>.</code> to reference the current directory, however, you cannot
    ++reference the parent directory <code>..</code> for security reasons.
    ++    <li>If you specify a directory, then the rule applies to all files in the
    ++directory and recursive sub-directories.</li></ul></li></ul>
    ++
    ++<h2 id="ImplementingBackupAgent">Implementing BackupAgent</h2>
    ++<p>Apps that implement Auto Backup do not need to implement {@link android.app.backup.BackupAgent}. However, you can optionally implement a custom {@link android.app.backup.BackupAgent}. Typically, there are two reasons for doing this:
    ++<ul>
    ++  <li>You want to receive notification of backup events such as,
    ++{@link android.app.backup.BackupAgent#onRestoreFinished()} or {@link android.app.backup.BackupAgent#onQuotaExceeded(long,long)}. These callback methods are executed
    ++even if the app is not running.
    ++<li>You can't easily express the set of files you want to backup with XML rules.
    ++In these very rare cases, you can implement a BackupAgent that overrides {@link android.app.backup.BackupAgent#onFullBackup(FullBackupDataOutput)} to
    ++store what you want. To retain the system's default implementation, call the
    ++corresponding method on the superclass with <code>super.onFullBackup()</code>.</li></ul>
    ++
    ++<p class="note"><strong>Note:</strong> Your <code>BackupAgent</code> must
    ++implement the abstract methods
    ++{@link android.app.backup.BackupAgent#onBackup(ParcelFileDescriptor,BackupDataOutput,ParcelFileDescriptor) onBackup()}
    ++and {@link android.app.backup.BackupAgent#onRestore(BackupDataInput,int,ParcelFileDescriptor) onRestore()}.
    ++Those methods are used for Key/Value Backup. So if
    ++you are not using Key/Value Backup, implement those methods and leave them blank.
    ++
    ++<p>For more information, see
    ++<a href="{@docRoot}guide/topics/data/keyvaluebackup.html#BackupAgent">Extending
    ++BackupAgent</a>.
    +\ No newline at end of file
    +diff --git a/docs/html/guide/topics/data/backup.jd b/docs/html/guide/topics/data/backup.jd
    +index 619c790..a688c6e 100644
    +--- a/docs/html/guide/topics/data/backup.jd
    ++++ b/docs/html/guide/topics/data/backup.jd
    +@@ -1,930 +1,34 @@
    +-page.title=Data Backup
    +-@jd:body
    +-
    +-
    +-<div id="qv-wrapper">
    +-<div id="qv">
    +-
    +-  <h2>Quickview</h2>
    +-  <ul>
    +-    <li>Back up the user's data to the cloud in case the user loses it</li>
    +-    <li>If the user upgrades to a new Android-powered device, your app can restore the user's
    +-data onto the new device</li>
    +-    <li>Easily back up SharedPreferences and private files with BackupAgentHelper</li>
    +-    <li>Requires API Level 8</li>
    +-  </ul>
    +-
    +-  <h2>In this document</h2>
    +-  <ol>
    +-    <li><a href="#Basics">The Basics</a></li>
    +-    <li><a href="#BackupManifest">Declaring the Backup Agent in Your Manifest</a></li>
    +-    <li><a href="#BackupKey">Registering for Android Backup Service</a></li>
    +-    <li><a href="#BackupAgent">Extending BackupAgent</a>
    +-      <ol>
    +-        <li><a href="#RequiredMethods">Required Methods</a></li>
    +-        <li><a href="#PerformingBackup">Performing backup</a></li>
    +-        <li><a href="#PerformingRestore">Performing restore</a></li>
    +-      </ol>
    +-    </li>
    +-    <li><a href="#BackupAgentHelper">Extending BackupAgentHelper</a>
    +-      <ol>
    +-        <li><a href="#SharedPreferences">Backing up SharedPreferences</a></li>
    +-        <li><a href="#Files">Backing up Private Files</a></li>
    +-      </ol>
    +-    </li>
    +-    <li><a href="#RestoreVersion">Checking the Restore Data Version</a></li>
    +-    <li><a href="#RequestingBackup">Requesting Backup</a></li>
    +-    <li><a href="#RequestingRestore">Requesting Restore</a></li>
    +-    <li><a href="#Testing">Testing Your Backup Agent</a></li>
    +-  </ol>
    +-
    +-  <h2>Key classes</h2>
    +-  <ol>
    +-    <li>{@link android.app.backup.BackupManager}</li>
    +-    <li>{@link android.app.backup.BackupAgent}</li>
    +-    <li>{@link android.app.backup.BackupAgentHelper}</li>
    +-  </ol>
    +-
    +-  <h2>See also</h2>
    +-  <ol>
    +-    <li><a href="{@docRoot}tools/help/bmgr.html">{@code bmgr} tool</a></li>
    +-  </ol>
    +-
    +-</div>
    +-</div>
    +-
    +-<p>Android's {@link android.app.backup backup} service allows you to copy your persistent
    +-application data to remote "cloud" storage, in order to provide a restore point for the
    +-application data and settings. If a user performs a factory reset or converts to a new
    +-Android-powered device, the system automatically restores your backup data when the application
    +-is re-installed. This way, your users don't need to reproduce their previous data or
    +-application settings. This process is completely transparent to the user and does not affect the
    +-functionality or user experience in your application.</p>
    +-
    +-<p>During a backup operation (which your application can request), Android's Backup Manager ({@link
    +-android.app.backup.BackupManager}) queries your application for backup data, then hands it to
    +-a backup transport, which then delivers the data to the cloud storage. During a
    +-restore operation, the Backup Manager retrieves the backup data from the backup transport and
    +-returns it to your application so your application can restore the data to the device. It's
    +-possible for your application to request a restore, but that shouldn't be necessary&mdash;Android
    +-automatically performs a restore operation when your application is installed and there exists
    +-backup data associated with the user. The primary scenario in which backup data is restored is when
    +-a user resets their device or upgrades to a new device and their previously installed
    +-applications are re-installed.</p>
    +-
    +-<p class="note"><strong>Note:</strong> The backup service is <em>not</em> designed for
    +-synchronizing application data with other clients or saving data that you'd like to access during
    +-the normal application lifecycle. You cannot read or write backup data on demand and cannot access
    +-it in any way other than through the APIs provided by the Backup Manager.</p>
    +-
    +-<p>The backup transport is the client-side component of Android's backup framework, which is
    +-customizable by
    +-the device manufacturer and service provider. The backup transport may differ from device to device
    +-and which backup transport is available on any given device is transparent to your application. The
    +-Backup Manager APIs isolate your application from the actual backup transport available on a given
    +-device&mdash;your application communicates with the Backup Manager through a fixed set of APIs,
    +-regardless of the underlying transport.</p>
    +-
    +-<p>Data backup is <em>not</em> guaranteed to be available on all Android-powered
    +-devices. However, your application is not adversely affected in the event
    +-that a device does not provide a backup transport. If you believe that users will benefit from data
    +-backup in your application, then you can implement it as described in this document, test it, then
    +-publish your application without any concern about which devices actually perform backup. When your
    +-application runs on a device that does not provide a backup transport, your application operates
    +-normally, but will not receive callbacks from the Backup Manager to backup data.</p>
    +-
    +-<p>Although you cannot know what the current transport is, you are always assured that your
    +-backup data cannot be read by other applications on the device. Only the Backup Manager and backup
    +-transport have access to the data you provide during a backup operation.</p>
    +-
    +-<p class="caution"><strong>Caution:</strong> Because the cloud storage and transport service can
    +-differ from device to device, Android makes no guarantees about the security of your data while
    +-using backup. You should always be cautious about using backup to store sensitive data, such as
    +-usernames and passwords.</p>
    +-
    +-
    +-<h2 id="Basics">The Basics</h2>
    +-
    +-<p>To backup your application data, you need to implement a backup agent. Your backup
    +-agent is called by the Backup Manager to provide the data you want to back up. It is also called
    +-to restore your backup data when the application is re-installed. The Backup Manager handles all
    +-your data transactions with the cloud storage (using the backup transport) and your backup agent
    +-handles all your data transactions on the device.</p>
    +-
    +-<p>To implement a backup agent, you must:</p>
    +-
    +-<ol>
    +-  <li>Declare your backup agent in your manifest file with the <a
    +-href="{@docRoot}guide/topics/manifest/application-element.html#agent">{@code
    +-android:backupAgent}</a> attribute.</li>
    +-  <li>Register your application with a backup service. Google offers <a
    +-href="http://code.google.com/android/backup/index.html">Android Backup Service</a> as a backup
    +-service for most Android-powered devices, which requires that you register your application in
    +-order for it to work. Any other backup services available might also require you to register
    +-in order to store your data on their servers.</li>
    +-  <li>Define a backup agent by either:</p>
    +-    <ol type="a">
    +-      <li><a href="#BackupAgent">Extending BackupAgent</a>
    +-        <p>The {@link android.app.backup.BackupAgent} class provides the central interface with
    +-which your application communicates with the Backup Manager. If you extend this class
    +-directly, you must override {@link
    +-android.app.backup.BackupAgent#onBackup(ParcelFileDescriptor,BackupDataOutput,ParcelFileDescriptor)
    +-onBackup()} and {@link
    +-android.app.backup.BackupAgent#onRestore(BackupDataInput,int,ParcelFileDescriptor)
    +-onRestore()} to handle the backup and restore operations for your data.</p>
    +-        <p><em>Or</em></p>
    +-      <li><a href="#BackupAgentHelper">Extending BackupAgentHelper</a>
    +-        <p>The {@link android.app.backup.BackupAgentHelper} class provides a convenient
    +-wrapper around the {@link android.app.backup.BackupAgent} class, which minimizes the amount of code
    +-you need to write. In your {@link android.app.backup.BackupAgentHelper}, you must use one or more
    +-"helper" objects, which automatically backup and restore certain types of data, so that you do not
    +-need to implement {@link
    +-android.app.backup.BackupAgent#onBackup(ParcelFileDescriptor,BackupDataOutput,ParcelFileDescriptor)
    +-onBackup()} and {@link
    +-android.app.backup.BackupAgent#onRestore(BackupDataInput,int,ParcelFileDescriptor)
    +-onRestore()}.</p>
    +-        <p>Android currently provides backup helpers that will backup and restore complete files
    +-from {@link android.content.SharedPreferences} and <a
    +-href="{@docRoot}guide/topics/data/data-storage.html#filesInternal">internal storage</a>.</p>
    +-      </li>
    +-    </ol>
    +-  </li>
    +-</ol>
    +-
    +-
    +-
    +-<h2 id="BackupManifest">Declaring the Backup Agent in Your Manifest</h2>
    +-
    +-<p>This is the easiest step, so once you've decided on the class name for your backup agent, declare
    +-it in your manifest with the <a
    +-href="{@docRoot}guide/topics/manifest/application-element.html#agent">{@code
    +-android:backupAgent}</a> attribute in the <a
    +-href="{@docRoot}guide/topics/manifest/application-element.html">{@code
    +-<application>}</a> tag.</p>
    +-
    +-<p>For example:</p>
    +-
    +-<pre>
    +-&lt;manifest ... &gt;
    +-    ...
    +-    &lt;application android:label="MyApplication"
    +-                 <b>android:backupAgent="MyBackupAgent"</b>&gt;
    +-        &lt;activity ... &gt;
    +-            ...
    +-        &lt;/activity&gt;
    +-    &lt;/application&gt;
    +-&lt;/manifest&gt;
    +-</pre>
    +-
    +-<p>Another attribute you might want to use is <a
    +-href="{@docRoot}guide/topics/manifest/application-element.html#restoreany">{@code
    +-android:restoreAnyVersion}</a>. This attribute takes a boolean value to indicate whether you
    +-want to restore the application data regardless of the current application version compared to the
    +-version that produced the backup data. (The default value is "{@code false}".) See <a
    +-href="#RestoreVersion">Checking the Restore Data Version</a> for more information.</p>
    +-
    +-<p class="note"><strong>Note:</strong> The backup service and the APIs you must use are
    +-available only on devices running API Level 8 (Android 2.2) or greater, so you should also
    +-set your <a
    +-href="{@docRoot}guide/topics/manifest/uses-sdk-element.html#min">{@code android:minSdkVersion}</a>
    +-attribute to "8".</p>
    +-
    +-
    +-
    +-
    +-<h2 id="BackupKey">Registering for Android Backup Service</h2>
    +-
    +-<p>Google provides a backup transport with <a
    +-href="http://code.google.com/android/backup/index.html">Android Backup Service</a> for most
    +-Android-powered devices running Android 2.2 or greater.</p>
    +-
    +-<p>In order for your application to perform backup using Android Backup Service, you must
    +-register your application with the service to receive a Backup Service Key, then
    +-declare the Backup Service Key in your Android manifest.</p>
    +-
    +-<p>To get your Backup Service Key, <a
    +-href="http://code.google.com/android/backup/signup.html">register for Android Backup Service</a>.
    +-When you register, you will be provided a Backup Service Key and the appropriate {@code
    +-<meta-data>} XML code for your Android manifest file, which you must include as a child of the
    +-{@code <application>} element. For example:</p>
    +-
    +-<pre>
    +-&lt;application android:label="MyApplication"
    +-             android:backupAgent="MyBackupAgent"&gt;
    +-    ...
    +-    &lt;meta-data android:name="com.google.android.backup.api_key"
    +-        android:value="AEdPqrEAAAAIDaYEVgU6DJnyJdBmU7KLH3kszDXLv_4DIsEIyQ" /&gt;
    +-&lt;/application&gt;
    +-</pre>
    +-
    +-<p>The <code>android:name</code> must be <code>"com.google.android.backup.api_key"</code> and
    +-the <code>android:value</code> must be the Backup Service Key received from the Android Backup
    +-Service registration.</p>
    +-
    +-<p>If you have multiple applications, you must register each one, using the respective package
    +-name.</p>
    +-
    +-<p class="note"><strong>Note:</strong> The backup transport provided by Android Backup Service is
    +-not guaranteed to be available
    +-on all Android-powered devices that support backup. Some devices might support backup
    +-using a different transport, some devices might not support backup at all, and there is no way for
    +-your application to know what transport is used on the device. However, if you implement backup for
    +-your application, you should always include a Backup Service Key for Android Backup Service so
    +-your application can perform backup when the device uses the Android Backup Service transport. If
    +-the device does not use Android Backup Service, then the {@code <meta-data>} element with the
    +-Backup Service Key is ignored.</p>
    +-
    +-
    +-
    +-
    +-<h2 id="BackupAgent">Extending BackupAgent</h2>
    +-
    +-<p>Most applications shouldn't need to extend the {@link android.app.backup.BackupAgent} class
    +-directly, but should instead <a href="#BackupAgentHelper">extend BackupAgentHelper</a> to take
    +-advantage of the built-in helper classes that automatically backup and restore your files. However,
    +-you might want to extend {@link android.app.backup.BackupAgent} directly if you need to:</p>
    +-<ul>
    +-  <li>Version your data format. For instance, if you anticipate the need to revise the
    +-format in which you write your application data, you can build a backup agent to cross-check your
    +-application version during a restore operation and perform any necessary compatibility work if the
    +-version on the device is different than that of the backup data. For more information, see <a
    +-href="#RestoreVersion">Checking the Restore Data Version</a>.</li>
    +-  <li>Instead of backing up an entire file, you can specify the portions of data the should be
    +-backed up and how each portion is then restored to the device. (This can also help you manage
    +-different versions, because you read and write your data as unique entities, rather than
    +-complete files.)</li>
    +-  <li>Back up data in a database. If you have an SQLite database that you want to restore when
    +-the user re-installs your application, you need to build a custom {@link
    +-android.app.backup.BackupAgent} that reads the appropriate data during a backup operation, then
    +-create your table and insert the data during a restore operation.</li>
    +-</ul>
    +-
    +-<p>If you don't need to perform any of the tasks above and want to back up complete files from
    +-{@link android.content.SharedPreferences} or <a
    +-href="{@docRoot}guide/topics/data/data-storage.html#filesInternal">internal storage</a>, you
    +-should skip to <a href="#BackupAgentHelper">Extending BackupAgentHelper</a>.</p>
    +-
    +-
    +-
    +-<h3 id="RequiredMethods">Required Methods</h3>
    +-
    +-<p>When you create a backup agent by extending {@link android.app.backup.BackupAgent}, you
    +-must implement the following callback methods:</p>
    +-
    +-<dl>
    +-  <dt>{@link
    +-android.app.backup.BackupAgent#onBackup(ParcelFileDescriptor,BackupDataOutput,ParcelFileDescriptor)
    +-onBackup()}</dt>
    +-    <dd>The Backup Manager calls this method after you <a href="#RequestingBackup">request a
    +-backup</a>. In this method, you read your application data from the device and pass the data you
    +-want to back up to the Backup Manager, as described below in <a href="#PerformingBackup">Performing
    +-backup</a>.</dd>
    +-
    +-  <dt>{@link
    +-android.app.backup.BackupAgent#onRestore(BackupDataInput,int,ParcelFileDescriptor)
    +-onRestore()}</dt>
    +-    <dd>The Backup Manager calls this method during a restore operation (you can <a
    +-href="#RequestingRestore">request a restore</a>, but the system automatically performs restore when
    +-the user re-installs your application). When it calls this method, the Backup Manager delivers your
    +-backup data, which you then restore to the device, as described below in <a
    +-href="#PerformingRestore">Performing restore</a>.</dd>
    +-</dl>
    +-
    +-
    +-
    +-<h3 id="PerformingBackup">Performing backup</h3>
    +-
    +-
    +-<p>When it's time to back up your application data, the Backup Manager calls your {@link
    +-android.app.backup.BackupAgent#onBackup(ParcelFileDescriptor,BackupDataOutput,ParcelFileDescriptor)
    +-onBackup()} method. This is where you must provide your application data to the Backup Manager so
    +-it can be saved to cloud storage.</p>
    +-
    +-<p>Only the Backup Manager can call your backup agent's {@link
    +-android.app.backup.BackupAgent#onBackup(ParcelFileDescriptor,BackupDataOutput,ParcelFileDescriptor)
    +-onBackup()} method. Each time that your application data changes and you want to perform a backup,
    +-you must request a backup operation by calling {@link
    +-android.app.backup.BackupManager#dataChanged()} (see <a href="#RequestingBackup">Requesting
    +-Backup</a> for more information). A backup request does not result in an immediate call to your
    +-{@link
    +-android.app.backup.BackupAgent#onBackup(ParcelFileDescriptor,BackupDataOutput,ParcelFileDescriptor)
    +-onBackup()} method. Instead, the Backup Manager waits for an appropriate time, then performs
    +-backup for all applications that have requested a backup since the last backup was performed.</p>
    +-
    +-<p class="note"><strong>Tip:</strong> While developing your application, you can initiate an
    +-immediate backup operation from the Backup Manager with the <a
    +-href="{@docRoot}tools/help/bmgr.html">{@code bmgr} tool</a>.</p>
    +-
    +-<p>When the Backup Manager calls your {@link
    +-android.app.backup.BackupAgent#onBackup(ParcelFileDescriptor,BackupDataOutput,ParcelFileDescriptor)
    +-onBackup()} method, it passes three parameters:</p>
    +-
    +-<dl>
    +-  <dt>{@code oldState}</dt>
    +-    <dd>An open, read-only {@link android.os.ParcelFileDescriptor} pointing to the last backup
    +-state provided by your application. This is not the backup data from cloud storage, but a
    +-local representation of the data that was backed up the last time {@link
    +-android.app.backup.BackupAgent#onBackup(ParcelFileDescriptor,BackupDataOutput,ParcelFileDescriptor)
    +-onBackup()} was called (as defined by {@code newState}, below, or from {@link
    +-android.app.backup.BackupAgent#onRestore(BackupDataInput,int,ParcelFileDescriptor)
    +-onRestore()}&mdash;more about this in the next section). Because {@link
    +-android.app.backup.BackupAgent#onBackup(ParcelFileDescriptor,BackupDataOutput,ParcelFileDescriptor)
    +-onBackup()} does not allow you to read existing backup data in
    +-the cloud storage, you can use this local representation to determine whether your data has changed
    +-since the last backup.</dd>
    +-  <dt>{@code data}</dt>
    +-    <dd>A {@link android.app.backup.BackupDataOutput} object, which you use to deliver your backup
    +-data to the Backup Manager.</dd>
    +-  <dt>{@code newState}</dt>
    +-    <dd>An open, read/write {@link android.os.ParcelFileDescriptor} pointing to a file in which
    +-you must write a representation of the data that you delivered to {@code data} (a representation
    +-can be as simple as the last-modified timestamp for your file). This object is
    +-returned as {@code oldState} the next time the Backup Manager calls your {@link
    +-android.app.backup.BackupAgent#onBackup(ParcelFileDescriptor,BackupDataOutput,ParcelFileDescriptor)
    +-onBackup()} method. If you do not write your backup data to {@code newState}, then {@code oldState}
    +-will point to an empty file next time Backup Manager calls {@link
    +-android.app.backup.BackupAgent#onBackup(ParcelFileDescriptor,BackupDataOutput,ParcelFileDescriptor)
    +-onBackup()}.</dd>
    +-</dl>
    +-
    +-<p>Using these parameters, you should implement your {@link
    +-android.app.backup.BackupAgent#onBackup(ParcelFileDescriptor,BackupDataOutput,ParcelFileDescriptor)
    +-onBackup()} method to do the following:</p>
    +-
    +-<ol>
    +-  <li>Check whether your data has changed since the last backup by comparing {@code oldState} to
    +-your current data. How you read data in {@code oldState} depends on how you originally wrote it to
    +-{@code newState} (see step 3). The easiest way to record the state of a file is with its
    +-last-modified timestamp. For example, here's how you can read and compare a timestamp from {@code
    +-oldState}:
    +-    <pre>
    +-// Get the oldState input stream
    +-FileInputStream instream = new FileInputStream(oldState.getFileDescriptor());
    +-DataInputStream in = new DataInputStream(instream);
    +-
    +-try {
    +-    // Get the last modified timestamp from the state file and data file
    +-    long stateModified = in.readLong();
    +-    long fileModified = mDataFile.lastModified();
    +-
    +-    if (stateModified != fileModified) {
    +-        // The file has been modified, so do a backup
    +-        // Or the time on the device changed, so be safe and do a backup
    +-    } else {
    +-        // Don't back up because the file hasn't changed
    +-        return;
    +-    }
    +-} catch (IOException e) {
    +-    // Unable to read state file... be safe and do a backup
    +-}
    +-</pre>
    +-    <p>If nothing has changed and you don't need to back up, skip to step 3.</p>
    +-  </li>
    +-  <li>If your data has changed, compared to {@code oldState}, write the current data to
    +-{@code data} to back it up to the cloud storage.
    +-    <p>You must write each chunk of data as an "entity" in the {@link
    +-android.app.backup.BackupDataOutput}. An entity is a flattened binary data
    +-record that is identified by a unique key string. Thus, the data set that you back up is
    +-conceptually a set of key-value pairs.</p>
    +-    <p>To add an entity to your backup data set, you must:</p>
    +-    <ol>
    +-      <li>Call {@link android.app.backup.BackupDataOutput#writeEntityHeader(String,int)
    +-writeEntityHeader()}, passing a unique string key for the data you're about to write and the data
    +-size.</li>
    +-      <li>Call {@link android.app.backup.BackupDataOutput#writeEntityData(byte[],int)
    +-writeEntityData()}, passing a byte buffer that contains your data and the number of bytes to write
    +-from the buffer (which should match the size passed to {@link
    +-android.app.backup.BackupDataOutput#writeEntityHeader(String,int) writeEntityHeader()}).</li>
    +-    </ol>
    +-    <p>For example, the following code flattens some data into a byte stream and writes it into a
    +-single entity:</p>
    +-    <pre>
    +-// Create buffer stream and data output stream for our data
    +-ByteArrayOutputStream bufStream = new ByteArrayOutputStream();
    +-DataOutputStream outWriter = new DataOutputStream(bufStream);
    +-// Write structured data
    +-outWriter.writeUTF(mPlayerName);
    +-outWriter.writeInt(mPlayerScore);
    +-// Send the data to the Backup Manager via the BackupDataOutput
    +-byte[] buffer = bufStream.toByteArray();
    +-int len = buffer.length;
    +-data.writeEntityHeader(TOPSCORE_BACKUP_KEY, len);
    +-data.writeEntityData(buffer, len);
    +-</pre>
    +-    <p>Perform this for each piece of data that you want to back up. How you divide your data into
    +-entities is up to you (and you might use just one entity).</p>
    +-  </li>
    +-  <li>Whether or not you perform a backup (in step 2), write a representation of the current data to
    +-the {@code newState} {@link android.os.ParcelFileDescriptor}. The Backup Manager retains this object
    +-locally as a representation of the data that is currently backed up. It passes this back to you as
    +-{@code oldState} the next time it calls {@link
    +-android.app.backup.BackupAgent#onBackup(ParcelFileDescriptor,BackupDataOutput,ParcelFileDescriptor)
    +-onBackup()} so you can determine whether another backup is necessary (as handled in step 1). If you
    +-do not write the current data state to this file, then
    +-{@code oldState} will be empty during the next callback.
    +-    <p>The following example saves a representation of the current data into {@code newState} using
    +-the file's last-modified timestamp:</p>
    +-    <pre>
    +-FileOutputStream outstream = new FileOutputStream(newState.getFileDescriptor());
    +-DataOutputStream out = new DataOutputStream(outstream);
    +-
    +-long modified = mDataFile.lastModified();
    +-out.writeLong(modified);
    +-</pre>
    +-  </li>
    +-</ol>
    +-
    +-<p class="caution"><strong>Caution:</strong> If your application data is saved to a file, make sure
    +-that you use synchronized statements while accessing the file so that your backup agent does not
    +-read the file while an Activity in your application is also writing the file.</p>
    +-
    +-
    +-
    +-
    +-<h3 id="PerformingRestore">Performing restore</h3>
    +-
    +-<p>When it's time to restore your application data, the Backup Manager calls your backup
    +-agent's {@link android.app.backup.BackupAgent#onRestore(BackupDataInput,int,ParcelFileDescriptor)
    +-onRestore()} method. When it calls this method, the Backup Manager delivers your backup data so
    +-you can restore it onto the device.</p>
    +-
    +-<p>Only the Backup Manager can call {@link
    +-android.app.backup.BackupAgent#onRestore(BackupDataInput,int,ParcelFileDescriptor)
    +-onRestore()}, which happens automatically when the system installs your application and
    +-finds existing backup data. However, you can request a restore operation for
    +-your application by calling {@link
    +-android.app.backup.BackupManager#requestRestore(RestoreObserver) requestRestore()} (see <a
    +-href="#RequestingRestore">Requesting restore</a> for more information).</p>
    +-
    +-<p class="note"><strong>Note:</strong> While developing your application, you can also request a
    +-restore operation with the <a href="{@docRoot}tools/help/bmgr.html">{@code bmgr}
    +-tool</a>.</p>
    +-
    +-<p>When the Backup Manager calls your {@link
    +-android.app.backup.BackupAgent#onRestore(BackupDataInput,int,ParcelFileDescriptor)
    +-onRestore()} method, it passes three parameters:</p>
    +-
    +-<dl>
    +-  <dt>{@code data}</dt>
    +-    <dd>A {@link android.app.backup.BackupDataInput}, which allows you to read your backup
    +-data.</dd>
    +-  <dt>{@code appVersionCode}</dt>
    +-    <dd>An integer representing the value of your application's <a
    +-href="{@docRoot}guide/topics/manifest/manifest-element.html#vcode">{@code android:versionCode}</a>
    +-manifest attribute, as it was when this data was backed up. You can use this to cross-check the
    +-current application version and determine if the data format is compatible. For more
    +-information about using this to handle different versions of restore data, see the section
    +-below about <a href="#RestoreVersion">Checking the Restore Data Version</a>.</dd>
    +-  <dt>{@code newState}</dt>
    +-    <dd>An open, read/write {@link android.os.ParcelFileDescriptor} pointing to a file in which
    +-you must write the final backup state that was provided with {@code data}. This object is
    +-returned as {@code oldState} the next time {@link
    +-android.app.backup.BackupAgent#onBackup(ParcelFileDescriptor,BackupDataOutput,ParcelFileDescriptor)
    +-onBackup()} is called. Recall that you must also write the same {@code newState} object in the
    +-{@link
    +-android.app.backup.BackupAgent#onBackup(ParcelFileDescriptor,BackupDataOutput,ParcelFileDescriptor)
    +-onBackup()} callback&mdash;also doing it here ensures that the {@code oldState} object given to
    +-{@link
    +-android.app.backup.BackupAgent#onBackup(ParcelFileDescriptor,BackupDataOutput,ParcelFileDescriptor)
    +-onBackup()} is valid even the first time {@link
    +-android.app.backup.BackupAgent#onBackup(ParcelFileDescriptor,BackupDataOutput,ParcelFileDescriptor)
    +-onBackup()} is called after the device is restored.</dd>
    +-</dl>
    +-
    +-<p>In your implementation of {@link
    +-android.app.backup.BackupAgent#onRestore(BackupDataInput,int,ParcelFileDescriptor)
    +-onRestore()}, you should call {@link android.app.backup.BackupDataInput#readNextHeader()} on the
    +-{@code data} to iterate
    +-through all entities in the data set. For each entity found, do the following:</p>
    +-
    +-<ol>
    +-  <li>Get the entity key with {@link android.app.backup.BackupDataInput#getKey()}.</li>
    +-  <li>Compare the entity key to a list of known key values that you should have declared as static
    +-final strings inside your {@link android.app.backup.BackupAgent} class. When the key matches one of
    +-your known key strings, enter into a statement to extract the entity data and save it to the device:
    +-    <ol>
    +-      <li>Get the entity data size with {@link
    +-android.app.backup.BackupDataInput#getDataSize()} and create a byte array of that size.</li>
    +-      <li>Call {@link android.app.backup.BackupDataInput#readEntityData(byte[],int,int)
    +-readEntityData()} and pass it the byte array, which is where the data will go, and specify the
    +-start offset and the size to read.</li>
    +-      <li>Your byte array is now full and you can read the data and write it to the device
    +-however you like.</li>
    +-    </ol>
    +-  </li>
    +-  <li>After you read and write your data back to the device, write the state of your data to the
    +-{@code newState} parameter the same as you do during {@link
    +-android.app.backup.BackupAgent#onBackup(ParcelFileDescriptor,BackupDataOutput,ParcelFileDescriptor)
    +-onBackup()}.
    +-</ol>
    ++page.title=Backing up App Data to the Cloud
    ++page.tags=cloud,sync,backup
    + 
    +-<p>For example, here's how you can restore the data backed up by the example in the previous
    +-section:</p>
    +-
    +-<pre>
    +-&#64;Override
    +-public void onRestore(BackupDataInput data, int appVersionCode,
    +-                      ParcelFileDescriptor newState) throws IOException {
    +-    // There should be only one entity, but the safest
    +-    // way to consume it is using a while loop
    +-    while (data.readNextHeader()) {
    +-        String key = data.getKey();
    +-        int dataSize = data.getDataSize();
    +-
    +-        // If the key is ours (for saving top score). Note this key was used when
    +-        // we wrote the backup entity header
    +-        if (TOPSCORE_BACKUP_KEY.equals(key)) {
    +-            // Create an input stream for the BackupDataInput
    +-            byte[] dataBuf = new byte[dataSize];
    +-            data.readEntityData(dataBuf, 0, dataSize);
    +-            ByteArrayInputStream baStream = new ByteArrayInputStream(dataBuf);
    +-            DataInputStream in = new DataInputStream(baStream);
    +-
    +-            // Read the player name and score from the backup data
    +-            mPlayerName = in.readUTF();
    +-            mPlayerScore = in.readInt();
    +-
    +-            // Record the score on the device (to a file or something)
    +-            recordScore(mPlayerName, mPlayerScore);
    +-        } else {
    +-            // We don't know this entity key. Skip it. (Shouldn't happen.)
    +-            data.skipEntityData();
    +-        }
    +-    }
    +-
    +-    // Finally, write to the state blob (newState) that describes the restored data
    +-    FileOutputStream outstream = new FileOutputStream(newState.getFileDescriptor());
    +-    DataOutputStream out = new DataOutputStream(outstream);
    +-    out.writeUTF(mPlayerName);
    +-    out.writeInt(mPlayerScore);
    +-}
    +-</pre>
    +-
    +-<p>In this example, the {@code appVersionCode} parameter passed to {@link
    +-android.app.backup.BackupAgent#onRestore onRestore()} is not used. However, you might want to use
    +-it if you've chosen to perform backup when the user's version of the application has actually moved
    +-backward (for example, the user went from version 1.5 of your app to 1.0). For more information, see
    +-the section about <a href="#RestoreVersion">Checking the Restore Data Version</a>.</p>
    +-
    +-<div class="special">
    +-<p>For an example implementation of {@link android.app.backup.BackupAgent}, see the <a
    +-href="{@docRoot}resources/samples/BackupRestore/src/com/example/android/backuprestore/ExampleAgent.html">{@code
    +-ExampleAgent}</a> class in the <a
    +-href="{@docRoot}resources/samples/BackupRestore/index.html">Backup and Restore</a> sample
    +-application.</p>
    +-</div>
    +-
    +-
    +-
    +-
    +-
    +-
    +-<h2 id="BackupAgentHelper">Extending BackupAgentHelper</h2>
    +-
    +-<p>You should build your backup agent using {@link android.app.backup.BackupAgentHelper} if you want
    +-to back up complete files (from either {@link android.content.SharedPreferences} or <a
    +-href="{@docRoot}guide/topics/data/data-storage.html#filesInternal">internal storage</a>).
    +-Building your backup agent with {@link android.app.backup.BackupAgentHelper} requires far less
    +-code than extending {@link android.app.backup.BackupAgent}, because you don't have to implement
    +-{@link
    +-android.app.backup.BackupAgent#onBackup(ParcelFileDescriptor,BackupDataOutput,ParcelFileDescriptor)
    +-onBackup()} and {@link
    +-android.app.backup.BackupAgent#onRestore(BackupDataInput,int,ParcelFileDescriptor)
    +-onRestore()}.</p>
    +-
    +-<p>Your implementation of {@link android.app.backup.BackupAgentHelper} must
    +-use one or more backup helpers. A backup helper is a specialized
    +-component that {@link android.app.backup.BackupAgentHelper} summons to perform backup and
    +-restore operations for a particular type of data. The Android framework currently provides two
    +-different helpers:</p>
    +-<ul>
    +-  <li>{@link android.app.backup.SharedPreferencesBackupHelper} to backup {@link
    +-android.content.SharedPreferences} files.</li>
    +-  <li>{@link android.app.backup.FileBackupHelper} to backup files from <a
    +-href="{@docRoot}guide/topics/data/data-storage.html#filesInternal">internal storage</a>.</li>
    +-</ul>
    +-
    +-<p>You can include multiple helpers in your {@link android.app.backup.BackupAgentHelper}, but only
    +-one helper is needed for each data type. That is, if you have multiple {@link
    +-android.content.SharedPreferences} files, then you need only one {@link
    +-android.app.backup.SharedPreferencesBackupHelper}.</p>
    +-
    +-<p>For each helper you want to add to your {@link android.app.backup.BackupAgentHelper}, you must do
    +-the following during your {@link android.app.backup.BackupAgent#onCreate()} method:</p>
    +-<ol>
    +-  <li>Instantiate in instance of the desired helper class. In the class constructor, you must
    +-specify the appropriate file(s) you want to backup.</li>
    +-  <li>Call {@link android.app.backup.BackupAgentHelper#addHelper(String,BackupHelper) addHelper()}
    +-to add the helper to your {@link android.app.backup.BackupAgentHelper}.</li>
    +-</ol>
    +-
    +-<p>The following sections describe how to create a backup agent using each of the available
    +-helpers.</p>
    +-
    +-
    +-
    +-<h3 id="SharedPreferences">Backing up SharedPreferences</h3>
    +-
    +-<p>When you instantiate a {@link android.app.backup.SharedPreferencesBackupHelper}, you must
    +-include the name of one or more {@link android.content.SharedPreferences} files.</p>
    +-
    +-<p>For example, to back up a {@link android.content.SharedPreferences} file named
    +-"user_preferences", a complete backup agent using {@link android.app.backup.BackupAgentHelper} looks
    +-like this:</p>
    +-
    +-<pre>
    +-public class MyPrefsBackupAgent extends BackupAgentHelper {
    +-    // The name of the SharedPreferences file
    +-    static final String PREFS = "user_preferences";
    +-
    +-    // A key to uniquely identify the set of backup data
    +-    static final String PREFS_BACKUP_KEY = "prefs";
    +-
    +-    // Allocate a helper and add it to the backup agent
    +-    &#64;Override
    +-    public void onCreate() {
    +-        SharedPreferencesBackupHelper helper =
    +-                new SharedPreferencesBackupHelper(this, PREFS);
    +-        addHelper(PREFS_BACKUP_KEY, helper);
    +-    }
    +-}
    +-</pre>
    +-
    +-<p>That's it! That's your entire backup agent. The {@link
    +-android.app.backup.SharedPreferencesBackupHelper} includes all the code
    +-needed to backup and restore a {@link android.content.SharedPreferences} file.</p>
    +-
    +-<p>When the Backup Manager calls {@link
    +-android.app.backup.BackupAgent#onBackup(ParcelFileDescriptor,BackupDataOutput,ParcelFileDescriptor)
    +-onBackup()} and {@link
    +-android.app.backup.BackupAgent#onRestore(BackupDataInput,int,ParcelFileDescriptor)
    +-onRestore()}, {@link android.app.backup.BackupAgentHelper} calls your backup helpers to perform
    +-backup and restore for your specified files.</p>
    +-
    +-<p class="note"><strong>Note:</strong> {@link android.content.SharedPreferences} are threadsafe, so
    +-you can safely read and write the shared preferences file from your backup agent and
    +-other activities.</p>
    +-
    +-
    +-
    +-<h3 id="Files">Backing up other files</h3>
    +-
    +-<p>When you instantiate a {@link android.app.backup.FileBackupHelper}, you must include the name of
    +-one or more files that are saved to your application's <a
    +-href="{@docRoot}guide/topics/data/data-storage.html#filesInternal">internal storage</a>
    +-(as specified by {@link android.content.ContextWrapper#getFilesDir()}, which is the same
    +-location where {@link android.content.Context#openFileOutput(String,int) openFileOutput()} writes
    +-files).</p>
    +-
    +-<p>For example, to backup two files named "scores" and "stats," a backup agent using {@link
    +-android.app.backup.BackupAgentHelper} looks like this:</p>
    +-
    +-<pre>
    +-public class MyFileBackupAgent extends BackupAgentHelper {
    +-    // The name of the file
    +-    static final String TOP_SCORES = "scores";
    +-    static final String PLAYER_STATS = "stats";
    +-
    +-    // A key to uniquely identify the set of backup data
    +-    static final String FILES_BACKUP_KEY = "myfiles";
    +-
    +-    // Allocate a helper and add it to the backup agent
    +-    &#64;Override
    +-    public void onCreate() {
    +-        FileBackupHelper helper = new FileBackupHelper(this,
    +-                TOP_SCORES, PLAYER_STATS);
    +-        addHelper(FILES_BACKUP_KEY, helper);
    +-    }
    +-}
    +-</pre>
    +-
    +-<p>The {@link android.app.backup.FileBackupHelper} includes all the code necessary to backup and
    +-restore files that are saved to your application's <a
    +-href="{@docRoot}guide/topics/data/data-storage.html#filesInternal">internal storage</a>..</p>
    +-
    +-<p>However, reading and writing to files on internal storage is <strong>not threadsafe</strong>. To
    +-ensure that your backup agent does not read or write your files at the same time as your activities,
    +-you must use synchronized statements each time you perform a read or write. For example,
    +-in any Activity where you read and write the file, you need an object to use as the intrinsic
    +-lock for the synchronized statements:</p>
    +-
    +-<pre>
    +-// Object for intrinsic lock
    +-static final Object sDataLock = new Object();
    +-</pre>
    +-
    +-<p>Then create a synchronized statement with this lock each time you read or write the files. For
    +-example, here's a synchronized statement for writing the latest score in a game to a file:</p>
    +-
    +-<pre>
    +-try {
    +-    synchronized (MyActivity.sDataLock) {
    +-        File dataFile = new File({@link android.content.Context#getFilesDir()}, TOP_SCORES);
    +-        RandomAccessFile raFile = new RandomAccessFile(dataFile, "rw");
    +-        raFile.writeInt(score);
    +-    }
    +-} catch (IOException e) {
    +-    Log.e(TAG, "Unable to write to file");
    +-}
    +-</pre>
    +-
    +-<p>You should synchronize your read statements with the same lock.</p>
    +-
    +-<p>Then, in your {@link android.app.backup.BackupAgentHelper}, you must override {@link
    +-android.app.backup.BackupAgent#onBackup(ParcelFileDescriptor,BackupDataOutput,ParcelFileDescriptor)
    +-onBackup()} and {@link
    +-android.app.backup.BackupAgent#onRestore(BackupDataInput,int,ParcelFileDescriptor)
    +-onRestore()} to synchronize the backup and restore operations with the same
    +-intrinsic lock. For example, the {@code MyFileBackupAgent} example from above needs the following
    +-methods:</p>
    +-
    +-<pre>
    +-&#64;Override
    +-public void onBackup(ParcelFileDescriptor oldState, BackupDataOutput data,
    +-          ParcelFileDescriptor newState) throws IOException {
    +-    // Hold the lock while the FileBackupHelper performs backup
    +-    synchronized (MyActivity.sDataLock) {
    +-        super.onBackup(oldState, data, newState);
    +-    }
    +-}
    +-
    +-&#64;Override
    +-public void onRestore(BackupDataInput data, int appVersionCode,
    +-        ParcelFileDescriptor newState) throws IOException {
    +-    // Hold the lock while the FileBackupHelper restores the file
    +-    synchronized (MyActivity.sDataLock) {
    +-        super.onRestore(data, appVersionCode, newState);
    +-    }
    +-}
    +-</pre>
    +-
    +-<p>That's it. All you need to do is add your {@link android.app.backup.FileBackupHelper} in the
    +-{@link android.app.backup.BackupAgent#onCreate()} method and override {@link
    +-android.app.backup.BackupAgent#onBackup(ParcelFileDescriptor,BackupDataOutput,ParcelFileDescriptor)
    +-onBackup()} and {@link
    +-android.app.backup.BackupAgent#onRestore(BackupDataInput,int,ParcelFileDescriptor)
    +-onRestore()} to synchronize read and write operations.</p>
    +-
    +-<div class="special">
    +-<p>For an example implementation of {@link
    +-android.app.backup.BackupAgentHelper} with {@link android.app.backup.FileBackupHelper}, see the
    +-{@code FileHelperExampleAgent} class in the <a
    +-href="{@docRoot}resources/samples/BackupRestore/index.html">Backup and Restore</a> sample
    +-application.</p>
    +-</div>
    +-
    +-
    +-
    +-
    +-
    +-
    +-<h2 id="RestoreVersion">Checking the Restore Data Version</h2>
    +-
    +-<p>When the Backup Manager saves your data to cloud storage, it automatically includes the version
    +-of your application, as defined by your manifest file's <a
    +-href="{@docRoot}guide/topics/manifest/manifest-element.html#vcode">{@code android:versionCode}</a>
    +-attribute. Before the Backup Manager calls your backup agent to restore your data, it
    +-looks at the <a
    +-href="{@docRoot}guide/topics/manifest/manifest-element.html#vcode">{@code
    +-android:versionCode}</a> of the installed application and compares it to the value
    +-recorded in the restore data set. If the version recorded in the restore data set is
    +-<em>newer</em> than the application version on the device, then the user has downgraded their
    +-application. In this case, the Backup Manager will abort the restore operation for your application
    +-and not call your {@link
    +-android.app.backup.BackupAgent#onRestore(BackupDataInput,int,ParcelFileDescriptor) onRestore()}
    +-method, because the restore set is considered meaningless to an older version.</p>
    +-
    +-<p>You can override this behavior with the <a
    +-href="{@docRoot}guide/topics/manifest/application-element.html#restoreany">{@code
    +-android:restoreAnyVersion}</a> attribute. This attribute is either "{@code true}" or "{@code
    +-false}" to indicate whether you want to restore the application regardless of the restore set
    +-version. The default value is "{@code false}". If you define this to be "{@code true}" then the
    +-Backup Manager will ignore the <a
    +-href="{@docRoot}guide/topics/manifest/manifest-element.html#vcode">{@code android:versionCode}</a>
    +-and call your {@link
    +-android.app.backup.BackupAgent#onRestore(BackupDataInput,int,ParcelFileDescriptor) onRestore()}
    +-method in all cases. In doing so, you can manually check for the version difference in your {@link
    +-android.app.backup.BackupAgent#onRestore(BackupDataInput,int,ParcelFileDescriptor) onRestore()}
    +-method and take any steps necessary to make the data compatible if the versions conflict.</p>
    +-
    +-<p>To help you handle different versions during a restore operation, the {@link
    +-android.app.backup.BackupAgent#onRestore(BackupDataInput,int,ParcelFileDescriptor) onRestore()}
    +-method passes you the version code included with the restore data set as the {@code appVersionCode}
    +-parameter. You can then query the current application's version code with the {@link
    +-android.content.pm.PackageInfo#versionCode PackageInfo.versionCode} field. For example:</p>
    +-
    +-<pre>
    +-PackageInfo info;
    +-try {
    +-    String name = {@link android.content.ContextWrapper#getPackageName() getPackageName}();
    +-    info = {@link android.content.ContextWrapper#getPackageManager
    +-getPackageManager}().{@link android.content.pm.PackageManager#getPackageInfo(String,int)
    +-getPackageInfo}(name,0);
    +-} catch (NameNotFoundException nnfe) {
    +-    info = null;
    +-}
    +-
    +-int version;
    +-if (info != null) {
    +-    version = info.versionCode;
    +-}
    +-</pre>
    +-
    +-<p>Then simply compare the {@code version} acquired from {@link android.content.pm.PackageInfo}
    +-to the {@code appVersionCode} passed into {@link
    +-android.app.backup.BackupAgent#onRestore(BackupDataInput,int,ParcelFileDescriptor) onRestore()}.
    +-</p>
    +-
    +-<p class="caution"><strong>Caution:</strong> Be certain you understand the consequences of setting
    +-<a href="{@docRoot}guide/topics/manifest/application-element.html#restoreany">{@code
    +-android:restoreAnyVersion}</a> to "{@code true}" for your application. If each version of your
    +-application that supports backup does not properly account for variations in your data format during
    +-{@link
    +-android.app.backup.BackupAgent#onRestore(BackupDataInput,int,ParcelFileDescriptor) onRestore()},
    +-then the data on the device could be saved in a format incompatible with the version currently
    +-installed on the device.</p>
    +-
    +-
    +-
    +-<h2 id="RequestingBackup">Requesting Backup</h2>
    +-
    +-<p>You can request a backup operation at any time by calling {@link
    +-android.app.backup.BackupManager#dataChanged()}. This method notifies the Backup Manager that you'd
    +-like to backup your data using your backup agent. The Backup Manager then calls your backup
    +-agent's {@link
    +-android.app.backup.BackupAgent#onBackup(ParcelFileDescriptor,BackupDataOutput,ParcelFileDescriptor)
    +-onBackup()} method at an opportune time in the future. Typically, you should
    +-request a backup each time your data changes (such as when the user changes an application
    +-preference that you'd like to back up). If you call {@link
    +-android.app.backup.BackupManager#dataChanged()} several times consecutively, before the Backup
    +-Manager requests a backup from your agent, your agent still receives just one call to {@link
    +-android.app.backup.BackupAgent#onBackup(ParcelFileDescriptor,BackupDataOutput,ParcelFileDescriptor)
    +-onBackup()}.</p>
    +-
    +-<p class="note"><strong>Note:</strong> While developing your application, you can request a
    +-backup and initiate an immediate backup operation with the <a
    +-href="{@docRoot}tools/help/bmgr.html">{@code bmgr}
    +-tool</a>.</p>
    +-
    +-
    +-<h2 id="RequestingRestore">Requesting Restore</h2>
    +-
    +-<p>During the normal life of your application, you shouldn't need to request a restore operation.
    +-They system automatically checks for backup data and performs a restore when your application is
    +-installed. However, you can manually request a restore operation by calling {@link
    +-android.app.backup.BackupManager#requestRestore(RestoreObserver) requestRestore()}, if necessary. In
    +-which case, the Backup Manager calls your {@link
    +-android.app.backup.BackupAgent#onRestore(BackupDataInput,int,ParcelFileDescriptor) onRestore()}
    +-implementation, passing the data from the current set of backup data.</p>
    +-
    +-<p class="note"><strong>Note:</strong> While developing your application, you can request a
    +-restore operation with the <a href="{@docRoot}tools/help/bmgr.html">{@code bmgr}
    +-tool</a>.</p>
    +-
    +-
    +-<h2 id="Testing">Testing Your Backup Agent</h2>
    +-
    +-<p>Once you've implemented your backup agent, you can test the backup and restore functionality
    +-with the following procedure, using <a
    +-href="{@docRoot}tools/help/bmgr.html">{@code bmgr}</a>.</p>
    +-
    +-<ol>
    +-  <li>Install your application on a suitable Android system image
    +-    <ul>
    +-      <li>If using the emulator, create and use an AVD with Android 2.2 (API Level 8).</li>
    +-      <li>If using a device, the device must be running Android 2.2 or greater and have Google
    +-Play built in.</li>
    +-    </ul>
    +-  </li>
    +-  <li>Ensure that backup is enabled
    +-    <ul>
    +-      <li>If using the emulator, you can enable backup with the following command from your SDK
    +-{@code tools/} path:
    +-<pre class="no-pretty-print">adb shell bmgr enable true</pre>
    +-      </li>
    +-      <li>If using a device, open the system <b>Settings</b>, select
    +-      <b>Backup & reset</b>, then enable
    +-      <b>Back up my data</b> and <b>Automatic restore</b>.</li>
    +-    </ul>
    +-  </li>
    +-  <li>Open your application and initialize some data
    +-    <p>If you've properly implemented backup in your application, then it should request a
    +-backup each time the data changes. For example, each time the user changes some data, your app
    +-should call {@link android.app.backup.BackupManager#dataChanged()}, which adds a backup request to
    +-the Backup Manager queue. For testing purposes, you can also make a request with the following
    +-{@code bmgr} command:</p>
    +-<pre class="no-pretty-print">adb shell bmgr backup <em>your.package.name</em></pre>
    +-  </li>
    +-  <li>Initiate a backup operation:
    +-<pre class="no-pretty-print">adb shell bmgr run</pre>
    +-    <p>This forces the Backup Manager to perform all backup requests that are in its
    +-queue.</p>
    +-  <li>Uninstall your application:
    +-<pre class="no-pretty-print">adb uninstall <em>your.package.name</em></pre>
    +-  </li>
    +-  <li>Re-install your application.</li>
    +-</ol>
    +-
    +-<p>If your backup agent is successful, all the data you initialized in step 4 is restored.</p>
    ++startpage=true
    + 
    ++@jd:body
    + 
    ++<p>Users often invest significant time and effort creating data and setting
    ++preferences within apps. Preserving that data for users if they replace a broken
    ++device or upgrade to a new one is an important part of ensuring a great user
    ++experience. This section covers techniques for backing up data to the cloud so
    ++that users can restore their data.
    ++
    ++<p>Android provides two ways for apps to backup their data to the cloud:
    ++<a href="{@docRoot}guide/topics/data/autobackup.html">Auto Backup for Apps</a> and
    ++<a href="{@docRoot}guide/topics/data/keyvaluebackup.html">Key/Value Backup</a>.
    ++Auto Backup, which is available starting API 23, preserves app data by uploading
    ++it to the user’s Google Drive account. The Key/Value Backup feature (formerly
    ++known as the Backup API and the Android Backup Service) preserves app data by
    ++uploading it to the <a href="{@docRoot}google/backup/index.html">Android Backup Service</a>.
    ++
    ++<p>Generally, we recommend Auto Backup because it requires no work to implement.
    ++Apps that target Android 6.0 (API level 23) or higher are automatically enabled
    ++for Auto Backup. The Auto Backup feature does have some limitations in terms of
    ++what data it can backup and it's availability on Android 6.0 and higher devices.
    ++Consider using the Key/Value Backup feature if you have more specific needs for
    ++backing up your app data. For more information, see <a href="{@docRoot}guide/topics/data/keyvaluebackup.html#Comparison">Comparison of Key/Value and Auto Backup</a></p>
    ++
    ++<p class="note"><strong>Note:</strong> These data backup features are not designed for synchronizing app data with other clients or
    ++saving data that you'd like to access during the normal application lifecycle.
    ++You cannot read or write backup data on demand. For synchronizing app data, see
    ++<a href="{@docRoot}training/sync-adapters/index.html">Transferring
    ++Data Using Sync Adapters</a> or <a href="https://developers.google.com/drive/android/">Google Drive Android
    ++API</a>.
    +\ No newline at end of file
    +diff --git a/docs/html/guide/topics/data/images/backup-framework.png b/docs/html/guide/topics/data/images/backup-framework.png
    +new file mode 100644
    +index 0000000..2ba2e612
    +Binary files /dev/null and b/docs/html/guide/topics/data/images/backup-framework.png differ
    +diff --git a/docs/html/guide/topics/data/index.jd b/docs/html/guide/topics/data/index.jd
    +index 3872825..2365f18 100644
    +--- a/docs/html/guide/topics/data/index.jd
    ++++ b/docs/html/guide/topics/data/index.jd
    +@@ -5,21 +5,3 @@ page.landing.image=
    + 
    + @jd:body
    + 
    +-<div class="landing-docs">
    +-
    +-
    +-  <div class="col-12">
    +-    <h3>Training</h3>
    +-
    +-    <a href="{@docRoot}training/backup/index.html">
    +-      <h4>Backing up App Data to the Cloud</h4>
    +-      <p>
    +-        This class covers techniques for backing up data to the cloud so that
    +-        users can restore their data when recovering from a data loss (such as a
    +-        factory reset) or installing your application on a new device.
    +-      </p>
    +-    </a>
    +-
    +-  </div>
    +-
    +-</div>
    +diff --git a/docs/html/guide/topics/data/keyvaluebackup.jd b/docs/html/guide/topics/data/keyvaluebackup.jd
    +new file mode 100644
    +index 0000000..c7c5e2f
    +--- /dev/null
    ++++ b/docs/html/guide/topics/data/keyvaluebackup.jd
    +@@ -0,0 +1,884 @@
    ++page.title=Key/Value Backup
    ++page.tags=backup, marshmallow, androidm
    ++page.keywords=backup, kvbackup
    ++
    ++@jd:body
    ++
    ++<div id="qv-wrapper">
    ++<div id="qv">
    ++  <h2>In this document</h2>
    ++  <ol>
    ++    <li><a href="#Comparison">Comparison to Auto Backup</a></li>
    ++    <li><a href="#ImplementingBackup">Implementing Key/Value Backup</a></li>
    ++
    ++    <li><a href="#BackupManifest">Declaring the backup agent in your manifest</a></li>
    ++    <li><a href="#BackupKey">Registering for Android Backup Service</a></li>
    ++    <li><a href="#BackupAgent">Extending BackupAgent</a>
    ++      <ol>
    ++        <li><a href="#RequiredMethods">Required methods</a></li>
    ++        <li><a href="#PerformingBackup">Performing backup</a></li>
    ++        <li><a href="#PerformingRestore">Performing restore</a></li>
    ++      </ol>
    ++    </li>
    ++    <li><a href="#BackupAgentHelper">Extending BackupAgentHelper</a>
    ++      <ol>
    ++        <li><a href="#SharedPreferences">Backing up SharedPreferences</a></li>
    ++        <li><a href="#Files">Backing up private files</a></li>
    ++      </ol>
    ++    </li>
    ++    <li><a href="#RestoreVersion">Checking the restore data version</a></li>
    ++    <li><a href="#RequestingBackup">Requesting backup</a></li>
    ++    <li><a href="#RequestingRestore">Requesting restore</a></li>
    ++    <li><a href="#Migrating">Migrating to Auto Backup</a></li>
    ++  </ol>
    ++
    ++  <h2>Key classes</h2>
    ++  <ol>
    ++    <li>{@link android.app.backup.BackupManager}</li>
    ++    <li>{@link android.app.backup.BackupAgent}</li>
    ++    <li>{@link android.app.backup.BackupAgentHelper}</li>
    ++  </ol>
    ++
    ++</div>
    ++</div>
    ++
    ++
    ++<p>Since Android 2.2 (API 8), Android has offered the <em>Key/Value Backup</em>
    ++feature as a way for developers to backup app data to the cloud. The Key/Value
    ++Backup feature (formerly known as the Backup API and the Android Backup Service)
    ++preserves app data by uploading it to
    ++<a href="{@docRoot}google/backup/index.html">Android Backup Service</a>.
    ++The amount of data is limited to 5MB per user of your app and there is
    ++no charge for storing backup data.
    ++
    ++<p class="note"><strong>Note:</strong> If your app implements Key/Value Backup
    ++and targets API 23 or higher, you should set
    ++<a href="{@docRoot}reference/android/R.attr.html#fullBackupOnly">android:fullBackupOnly</a>.
    ++This attribute indicates whether or not to use Auto Backup on devices where it is available.
    ++
    ++<h2 id="Comparison">Comparison to Auto Backup</h2>
    ++<p>Like Auto Backup, Key/Value Backups are restored automatically whenever the app
    ++is installed. The following table describes some of the key differences between Key/Value Backup and Auto Backup:
    ++
    ++<table>
    ++  <tr>
    ++   <th>Key/Value Backup</th>
    ++   <th>Auto Backup</th>
    ++  </tr>
    ++  <tr>
    ++   <td>Available in API 8, Android 2.2</td>
    ++   <td>Available in API 23, Android 6.0</td>
    ++  </tr>
    ++  <tr>
    ++   <td>Apps must implement a {@link android.app.backup.BackupAgent}. The backup agent defines what data to backup and how to
    ++restore data.</td>
    ++   <td>By default, Auto Backup includes almost all of the app's files. You can
    ++use XML to include and exclude files. Under the hood, Auto Backup relies on a
    ++backup agent that is built into the framework.</td>
    ++  </tr>
    ++  <tr>
    ++   <td>Apps must issue a request when there is data
    ++that is ready to be backed up. Requests
    ++from multiple apps are batched and executed every few hours.</td>
    ++   <td>Backups happen automatically roughly once a day.</td>
    ++  </tr>
    ++  <tr>
    ++   <td>Backup data can be transmitted via wifi or cellular data.</td>
    ++   <td>Backup data is tranmitted only via wifi. If the device is never connected to a
    ++wifi network, then Auto Backup never occurs.</td>
    ++  </tr>
    ++  <tr>
    ++   <td>Apps are not shut down during backup.</td>
    ++   <td>The system shuts down the app during backup.</td>
    ++  </tr>
    ++  <tr>
    ++   <td>Backup data is stored in <a href="{@docRoot}google/backup/index.html">Android Backup Service</a> limited to 5MB per app.</td>
    ++   <td>Backup data is stored in the user's Google Drive limited to 25MB per app.</td>
    ++  </tr>
    ++  <tr>
    ++   <td>Related API methods are not filed based:<ul>
    ++      <li>{@link android.app.backup.BackupAgent#onBackup(ParcelFileDescriptor, BackupDataOutput, ParcelFileDescriptor) onBackup()}
    ++      <li>{@link android.app.backup.BackupAgent#onRestore(BackupDataInput, int, ParcelFileDescriptor) onRestore()}</ul></td>
    ++   <td>Related API methods are filed based:<ul>
    ++<li>{@link android.app.backup.BackupAgent#onFullBackup(FullBackupDataOutput) onFullBackup()}
    ++<li>{@link android.app.backup.BackupAgent#onRestoreFile(ParcelFileDescriptor,long,File,int,long,long) onRestoreFile()}</ul></td>
    ++  </tr>
    ++</table>
    ++
    ++<h2 id="ImplementingBackup">Implementing Key/Value Backup</h2>
    ++<p>To backup your application data, you need to implement a backup agent. Your backup
    ++agent is called by the Backup Manager both during backup and restore.</p>
    ++
    ++<p>To implement a backup agent, you must:</p>
    ++
    ++<ol>
    ++  <li>Declare your backup agent in your manifest file with the <a
    ++href="{@docRoot}guide/topics/manifest/application-element.html#agent">{@code
    ++android:backupAgent}</a> attribute.</li>
    ++  <li>Register your application with <a href="{@docRoot}google/backup/index.html">Android
    ++   Backup Service</a></li>
    ++  <li>Define a backup agent by either:</p>
    ++    <ol type="a">
    ++      <li><a href="#BackupAgent">Extending BackupAgent</a>
    ++        <p>The {@link android.app.backup.BackupAgent} class provides the central interface with
    ++which your application communicates with the Backup Manager. If you extend this class
    ++directly, you must override {@link
    ++android.app.backup.BackupAgent#onBackup(ParcelFileDescriptor,BackupDataOutput,ParcelFileDescriptor)
    ++onBackup()} and {@link
    ++android.app.backup.BackupAgent#onRestore(BackupDataInput,int,ParcelFileDescriptor)
    ++onRestore()} to handle the backup and restore operations for your data.</p>
    ++        <p><em>Or</em></p>
    ++      <li><a href="#BackupAgentHelper">Extending BackupAgentHelper</a>
    ++        <p>The {@link android.app.backup.BackupAgentHelper} class provides a convenient
    ++wrapper around the {@link android.app.backup.BackupAgent} class, which minimizes the amount of code
    ++you need to write. In your {@link android.app.backup.BackupAgentHelper}, you must use one or more
    ++"helper" objects, which automatically backup and restore certain types of data, so that you do not
    ++need to implement {@link
    ++android.app.backup.BackupAgent#onBackup(ParcelFileDescriptor,BackupDataOutput,ParcelFileDescriptor)
    ++onBackup()} and {@link
    ++android.app.backup.BackupAgent#onRestore(BackupDataInput,int,ParcelFileDescriptor)
    ++onRestore()}.</p>
    ++        <p>Android currently provides backup helpers that will backup and restore complete files
    ++from {@link android.content.SharedPreferences} and <a
    ++href="{@docRoot}guide/topics/data/data-storage.html#filesInternal">internal storage</a>.</p>
    ++      </li>
    ++    </ol>
    ++  </li>
    ++</ol>
    ++
    ++<h2 id="BackupManifest">Declaring the backup agent in your manifest</h2>
    ++
    ++<p>This is the easiest step, so once you've decided on the class name for your backup agent, declare
    ++it in your manifest with the <a
    ++href="{@docRoot}guide/topics/manifest/application-element.html#agent">{@code
    ++android:backupAgent}</a> attribute in the <a
    ++href="{@docRoot}guide/topics/manifest/application-element.html">{@code
    ++<application>}</a> tag.</p>
    ++
    ++<p>For example:</p>
    ++
    ++<pre>
    ++&lt;manifest ... &gt;
    ++    ...
    ++    &lt;application android:label="MyApplication"
    ++                 <b>android:backupAgent="MyBackupAgent"</b>&gt;
    ++        &lt;activity ... &gt;
    ++            ...
    ++        &lt;/activity&gt;
    ++    &lt;/application&gt;
    ++&lt;/manifest&gt;
    ++</pre>
    ++
    ++<p>Another attribute you might want to use is <a
    ++href="{@docRoot}guide/topics/manifest/application-element.html#restoreany">{@code
    ++android:restoreAnyVersion}</a>. This attribute takes a boolean value to indicate whether you
    ++want to restore the application data regardless of the current application version compared to the
    ++version that produced the backup data. (The default value is "{@code false}".) See <a
    ++href="#RestoreVersion">Checking the Restore Data Version</a> for more information.</p>
    ++
    ++<p class="note"><strong>Note:</strong> The backup service and the APIs you must use are
    ++available only on devices running API Level 8 (Android 2.2) or greater, so you should also
    ++set your <a
    ++href="{@docRoot}guide/topics/manifest/uses-sdk-element.html#min">{@code android:minSdkVersion}</a>
    ++attribute to "8".</p>
    ++
    ++
    ++
    ++
    ++<h2 id="BackupKey">Registering for Android Backup Service</h2>
    ++
    ++<p>Google provides a backup transport with <a
    ++href="{@docRoot}google/backup/index.html">Android Backup Service</a> for most
    ++Android-powered devices running Android 2.2 or greater.</p>
    ++
    ++<p>In order for your application to perform backup using Android Backup Service, you must
    ++register your application with the service to receive a Backup Service Key, then
    ++declare the Backup Service Key in your Android manifest.</p>
    ++
    ++<p>To get your Backup Service Key, <a
    ++href="{@docRoot}google/backup/signup.html">register for Android Backup Service</a>.
    ++When you register, you will be provided a Backup Service Key and the appropriate {@code
    ++<meta-data>} XML code for your Android manifest file, which you must include as a child of the
    ++{@code <application>} element. For example:</p>
    ++
    ++<pre>
    ++&lt;application android:label="MyApplication"
    ++             android:backupAgent="MyBackupAgent"&gt;
    ++    ...
    ++    &lt;meta-data android:name="com.google.android.backup.api_key"
    ++        android:value="AEdPqrEAAAAIDaYEVgU6DJnyJdBmU7KLH3kszDXLv_4DIsEIyQ" /&gt;
    ++&lt;/application&gt;
    ++</pre>
    ++
    ++<p>The <code>android:name</code> must be <code>"com.google.android.backup.api_key"</code> and
    ++the <code>android:value</code> must be the Backup Service Key received from the Android Backup
    ++Service registration.</p>
    ++
    ++<p>If you have multiple applications, you must register each one, using the respective package
    ++name.</p>
    ++
    ++<p class="note"><strong>Note:</strong> The backup transport provided by Android Backup Service is
    ++not guaranteed to be available
    ++on all Android-powered devices that support backup. Some devices might support backup
    ++using a different transport, some devices might not support backup at all, and there is no way for
    ++your application to know what transport is used on the device. However, if you implement backup for
    ++your application, you should always include a Backup Service Key for Android Backup Service so
    ++your application can perform backup when the device uses the Android Backup Service transport. If
    ++the device does not use Android Backup Service, then the {@code <meta-data>} element with the
    ++Backup Service Key is ignored.</p>
    ++
    ++
    ++
    ++
    ++<h2 id="BackupAgent">Extending BackupAgent</h2>
    ++
    ++<p>Most applications shouldn't need to extend the {@link android.app.backup.BackupAgent} class
    ++directly, but should instead <a href="#BackupAgentHelper">extend BackupAgentHelper</a> to take
    ++advantage of the built-in helper classes that automatically backup and restore your files. However,
    ++you might want to extend {@link android.app.backup.BackupAgent} directly if you need to:</p>
    ++<ul>
    ++  <li>Version your data format. For instance, if you anticipate the need to revise the
    ++format in which you write your application data, you can build a backup agent to cross-check your
    ++application version during a restore operation and perform any necessary compatibility work if the
    ++version on the device is different than that of the backup data. For more information, see <a
    ++href="#RestoreVersion">Checking the Restore Data Version</a>.</li>
    ++  <li>Instead of backing up an entire file, you can specify the portions of data the should be
    ++backed up and how each portion is then restored to the device. (This can also help you manage
    ++different versions, because you read and write your data as unique entities, rather than
    ++complete files.)</li>
    ++  <li>Back up data in a database. If you have an SQLite database that you want to restore when
    ++the user re-installs your application, you need to build a custom {@link
    ++android.app.backup.BackupAgent} that reads the appropriate data during a backup operation, then
    ++create your table and insert the data during a restore operation.</li>
    ++</ul>
    ++
    ++<p>If you don't need to perform any of the tasks above and want to back up complete files from
    ++{@link android.content.SharedPreferences} or <a
    ++href="{@docRoot}guide/topics/data/data-storage.html#filesInternal">internal storage</a>, you
    ++should skip to <a href="#BackupAgentHelper">Extending BackupAgentHelper</a>.</p>
    ++
    ++
    ++
    ++<h3 id="RequiredMethods">Required methods</h3>
    ++
    ++<p>When you create a backup agent by extending {@link android.app.backup.BackupAgent}, you
    ++must implement the following callback methods:</p>
    ++
    ++<dl>
    ++  <dt>{@link
    ++android.app.backup.BackupAgent#onBackup(ParcelFileDescriptor,BackupDataOutput,ParcelFileDescriptor)
    ++onBackup()}</dt>
    ++    <dd>The Backup Manager calls this method after you <a href="#RequestingBackup">request a
    ++backup</a>. In this method, you read your application data from the device and pass the data you
    ++want to back up to the Backup Manager, as described below in <a href="#PerformingBackup">Performing
    ++backup</a>.</dd>
    ++
    ++  <dt>{@link
    ++android.app.backup.BackupAgent#onRestore(BackupDataInput,int,ParcelFileDescriptor)
    ++onRestore()}</dt>
    ++    <dd>The Backup Manager calls this method during a restore operation (you can <a
    ++href="#RequestingRestore">request a restore</a>, but the system automatically performs restore when
    ++the user re-installs your application). When it calls this method, the Backup Manager delivers your
    ++backup data, which you then restore to the device, as described below in <a
    ++href="#PerformingRestore">Performing restore</a>.</dd>
    ++</dl>
    ++
    ++
    ++
    ++<h3 id="PerformingBackup">Performing backup</h3>
    ++
    ++
    ++<p>When it's time to back up your application data, the Backup Manager calls your {@link
    ++android.app.backup.BackupAgent#onBackup(ParcelFileDescriptor,BackupDataOutput,ParcelFileDescriptor)
    ++onBackup()} method. This is where you must provide your application data to the Backup Manager so
    ++it can be saved to cloud storage.</p>
    ++
    ++<p>Only the Backup Manager can call your backup agent's {@link
    ++android.app.backup.BackupAgent#onBackup(ParcelFileDescriptor,BackupDataOutput,ParcelFileDescriptor)
    ++onBackup()} method. Each time that your application data changes and you want to perform a backup,
    ++you must request a backup operation by calling {@link
    ++android.app.backup.BackupManager#dataChanged()} (see <a href="#RequestingBackup">Requesting
    ++Backup</a> for more information). A backup request does not result in an immediate call to your
    ++{@link
    ++android.app.backup.BackupAgent#onBackup(ParcelFileDescriptor,BackupDataOutput,ParcelFileDescriptor)
    ++onBackup()} method. Instead, the Backup Manager waits for an appropriate time, then performs
    ++backup for all applications that have requested a backup since the last backup was performed.</p>
    ++
    ++<p class="note"><strong>Tip:</strong> While developing your application, you can initiate an
    ++immediate backup operation from the Backup Manager with the <a
    ++href="{@docRoot}tools/help/bmgr.html">{@code bmgr} tool</a>.</p>
    ++
    ++<p>When the Backup Manager calls your {@link
    ++android.app.backup.BackupAgent#onBackup(ParcelFileDescriptor,BackupDataOutput,ParcelFileDescriptor)
    ++onBackup()} method, it passes three parameters:</p>
    ++
    ++<dl>
    ++  <dt>{@code oldState}</dt>
    ++    <dd>An open, read-only {@link android.os.ParcelFileDescriptor} pointing to the last backup
    ++state provided by your application. This is not the backup data from cloud storage, but a
    ++local representation of the data that was backed up the last time {@link
    ++android.app.backup.BackupAgent#onBackup(ParcelFileDescriptor,BackupDataOutput,ParcelFileDescriptor)
    ++onBackup()} was called (as defined by {@code newState}, below, or from {@link
    ++android.app.backup.BackupAgent#onRestore(BackupDataInput,int,ParcelFileDescriptor)
    ++onRestore()}&mdash;more about this in the next section). Because {@link
    ++android.app.backup.BackupAgent#onBackup(ParcelFileDescriptor,BackupDataOutput,ParcelFileDescriptor)
    ++onBackup()} does not allow you to read existing backup data in
    ++the cloud storage, you can use this local representation to determine whether your data has changed
    ++since the last backup.</dd>
    ++  <dt>{@code data}</dt>
    ++    <dd>A {@link android.app.backup.BackupDataOutput} object, which you use to deliver your backup
    ++data to the Backup Manager.</dd>
    ++  <dt>{@code newState}</dt>
    ++    <dd>An open, read/write {@link android.os.ParcelFileDescriptor} pointing to a file in which
    ++you must write a representation of the data that you delivered to {@code data} (a representation
    ++can be as simple as the last-modified timestamp for your file). This object is
    ++returned as {@code oldState} the next time the Backup Manager calls your {@link
    ++android.app.backup.BackupAgent#onBackup(ParcelFileDescriptor,BackupDataOutput,ParcelFileDescriptor)
    ++onBackup()} method. If you do not write your backup data to {@code newState}, then {@code oldState}
    ++will point to an empty file next time Backup Manager calls {@link
    ++android.app.backup.BackupAgent#onBackup(ParcelFileDescriptor,BackupDataOutput,ParcelFileDescriptor)
    ++onBackup()}.</dd>
    ++</dl>
    ++
    ++<p>Using these parameters, you should implement your {@link
    ++android.app.backup.BackupAgent#onBackup(ParcelFileDescriptor,BackupDataOutput,ParcelFileDescriptor)
    ++onBackup()} method to do the following:</p>
    ++
    ++<ol>
    ++  <li>Check whether your data has changed since the last backup by comparing {@code oldState} to
    ++your current data. How you read data in {@code oldState} depends on how you originally wrote it to
    ++{@code newState} (see step 3). The easiest way to record the state of a file is with its
    ++last-modified timestamp. For example, here's how you can read and compare a timestamp from {@code
    ++oldState}:
    ++    <pre>
    ++// Get the oldState input stream
    ++FileInputStream instream = new FileInputStream(oldState.getFileDescriptor());
    ++DataInputStream in = new DataInputStream(instream);
    ++
    ++try {
    ++    // Get the last modified timestamp from the state file and data file
    ++    long stateModified = in.readLong();
    ++    long fileModified = mDataFile.lastModified();
    ++
    ++    if (stateModified != fileModified) {
    ++        // The file has been modified, so do a backup
    ++        // Or the time on the device changed, so be safe and do a backup
    ++    } else {
    ++        // Don't back up because the file hasn't changed
    ++        return;
    ++    }
    ++} catch (IOException e) {
    ++    // Unable to read state file... be safe and do a backup
    ++}
    ++</pre>
    ++    <p>If nothing has changed and you don't need to back up, skip to step 3.</p>
    ++  </li>
    ++  <li>If your data has changed, compared to {@code oldState}, write the current data to
    ++{@code data} to back it up to the cloud storage.
    ++    <p>You must write each chunk of data as an "entity" in the {@link
    ++android.app.backup.BackupDataOutput}. An entity is a flattened binary data
    ++record that is identified by a unique key string. Thus, the data set that you back up is
    ++conceptually a set of key-value pairs.</p>
    ++    <p>To add an entity to your backup data set, you must:</p>
    ++    <ol>
    ++      <li>Call {@link android.app.backup.BackupDataOutput#writeEntityHeader(String,int)
    ++writeEntityHeader()}, passing a unique string key for the data you're about to write and the data
    ++size.</li>
    ++      <li>Call {@link android.app.backup.BackupDataOutput#writeEntityData(byte[],int)
    ++writeEntityData()}, passing a byte buffer that contains your data and the number of bytes to write
    ++from the buffer (which should match the size passed to {@link
    ++android.app.backup.BackupDataOutput#writeEntityHeader(String,int) writeEntityHeader()}).</li>
    ++    </ol>
    ++    <p>For example, the following code flattens some data into a byte stream and writes it into a
    ++single entity:</p>
    ++    <pre>
    ++// Create buffer stream and data output stream for our data
    ++ByteArrayOutputStream bufStream = new ByteArrayOutputStream();
    ++DataOutputStream outWriter = new DataOutputStream(bufStream);
    ++// Write structured data
    ++outWriter.writeUTF(mPlayerName);
    ++outWriter.writeInt(mPlayerScore);
    ++// Send the data to the Backup Manager via the BackupDataOutput
    ++byte[] buffer = bufStream.toByteArray();
    ++int len = buffer.length;
    ++data.writeEntityHeader(TOPSCORE_BACKUP_KEY, len);
    ++data.writeEntityData(buffer, len);
    ++</pre>
    ++    <p>Perform this for each piece of data that you want to back up. How you divide your data into
    ++entities is up to you (and you might use just one entity).</p>
    ++  </li>
    ++  <li>Whether or not you perform a backup (in step 2), write a representation of the current data to
    ++the {@code newState} {@link android.os.ParcelFileDescriptor}. The Backup Manager retains this object
    ++locally as a representation of the data that is currently backed up. It passes this back to you as
    ++{@code oldState} the next time it calls {@link
    ++android.app.backup.BackupAgent#onBackup(ParcelFileDescriptor,BackupDataOutput,ParcelFileDescriptor)
    ++onBackup()} so you can determine whether another backup is necessary (as handled in step 1). If you
    ++do not write the current data state to this file, then
    ++{@code oldState} will be empty during the next callback.
    ++    <p>The following example saves a representation of the current data into {@code newState} using
    ++the file's last-modified timestamp:</p>
    ++    <pre>
    ++FileOutputStream outstream = new FileOutputStream(newState.getFileDescriptor());
    ++DataOutputStream out = new DataOutputStream(outstream);
    ++
    ++long modified = mDataFile.lastModified();
    ++out.writeLong(modified);
    ++</pre>
    ++  </li>
    ++</ol>
    ++
    ++<p class="caution"><strong>Caution:</strong> If your application data is saved to a file, make sure
    ++that you use synchronized statements while accessing the file so that your backup agent does not
    ++read the file while an Activity in your application is also writing the file.</p>
    ++
    ++
    ++
    ++
    ++<h3 id="PerformingRestore">Performing restore</h3>
    ++
    ++<p>When it's time to restore your application data, the Backup Manager calls your backup
    ++agent's {@link android.app.backup.BackupAgent#onRestore(BackupDataInput,int,ParcelFileDescriptor)
    ++onRestore()} method. When it calls this method, the Backup Manager delivers your backup data so
    ++you can restore it onto the device.</p>
    ++
    ++<p>Only the Backup Manager can call {@link
    ++android.app.backup.BackupAgent#onRestore(BackupDataInput,int,ParcelFileDescriptor)
    ++onRestore()}, which happens automatically when the system installs your application and
    ++finds existing backup data. However, you can request a restore operation for
    ++your application by calling {@link
    ++android.app.backup.BackupManager#requestRestore(RestoreObserver) requestRestore()} (see <a
    ++href="#RequestingRestore">Requesting restore</a> for more information).</p>
    ++
    ++<p class="note"><strong>Note:</strong> While developing your application, you can also request a
    ++restore operation with the <a href="{@docRoot}tools/help/bmgr.html">{@code bmgr}
    ++tool</a>.</p>
    ++
    ++<p>When the Backup Manager calls your {@link
    ++android.app.backup.BackupAgent#onRestore(BackupDataInput,int,ParcelFileDescriptor)
    ++onRestore()} method, it passes three parameters:</p>
    ++
    ++<dl>
    ++  <dt>{@code data}</dt>
    ++    <dd>A {@link android.app.backup.BackupDataInput}, which allows you to read your backup
    ++data.</dd>
    ++  <dt>{@code appVersionCode}</dt>
    ++    <dd>An integer representing the value of your application's <a
    ++href="{@docRoot}guide/topics/manifest/manifest-element.html#vcode">{@code android:versionCode}</a>
    ++manifest attribute, as it was when this data was backed up. You can use this to cross-check the
    ++current application version and determine if the data format is compatible. For more
    ++information about using this to handle different versions of restore data, see the section
    ++below about <a href="#RestoreVersion">Checking the Restore Data Version</a>.</dd>
    ++  <dt>{@code newState}</dt>
    ++    <dd>An open, read/write {@link android.os.ParcelFileDescriptor} pointing to a file in which
    ++you must write the final backup state that was provided with {@code data}. This object is
    ++returned as {@code oldState} the next time {@link
    ++android.app.backup.BackupAgent#onBackup(ParcelFileDescriptor,BackupDataOutput,ParcelFileDescriptor)
    ++onBackup()} is called. Recall that you must also write the same {@code newState} object in the
    ++{@link
    ++android.app.backup.BackupAgent#onBackup(ParcelFileDescriptor,BackupDataOutput,ParcelFileDescriptor)
    ++onBackup()} callback&mdash;also doing it here ensures that the {@code oldState} object given to
    ++{@link
    ++android.app.backup.BackupAgent#onBackup(ParcelFileDescriptor,BackupDataOutput,ParcelFileDescriptor)
    ++onBackup()} is valid even the first time {@link
    ++android.app.backup.BackupAgent#onBackup(ParcelFileDescriptor,BackupDataOutput,ParcelFileDescriptor)
    ++onBackup()} is called after the device is restored.</dd>
    ++</dl>
    ++
    ++<p>In your implementation of {@link
    ++android.app.backup.BackupAgent#onRestore(BackupDataInput,int,ParcelFileDescriptor)
    ++onRestore()}, you should call {@link android.app.backup.BackupDataInput#readNextHeader()} on the
    ++{@code data} to iterate
    ++through all entities in the data set. For each entity found, do the following:</p>
    ++
    ++<ol>
    ++  <li>Get the entity key with {@link android.app.backup.BackupDataInput#getKey()}.</li>
    ++  <li>Compare the entity key to a list of known key values that you should have declared as static
    ++final strings inside your {@link android.app.backup.BackupAgent} class. When the key matches one of
    ++your known key strings, enter into a statement to extract the entity data and save it to the device:
    ++    <ol>
    ++      <li>Get the entity data size with {@link
    ++android.app.backup.BackupDataInput#getDataSize()} and create a byte array of that size.</li>
    ++      <li>Call {@link android.app.backup.BackupDataInput#readEntityData(byte[],int,int)
    ++readEntityData()} and pass it the byte array, which is where the data will go, and specify the
    ++start offset and the size to read.</li>
    ++      <li>Your byte array is now full and you can read the data and write it to the device
    ++however you like.</li>
    ++    </ol>
    ++  </li>
    ++  <li>After you read and write your data back to the device, write the state of your data to the
    ++{@code newState} parameter the same as you do during {@link
    ++android.app.backup.BackupAgent#onBackup(ParcelFileDescriptor,BackupDataOutput,ParcelFileDescriptor)
    ++onBackup()}.
    ++</ol>
    ++
    ++<p>For example, here's how you can restore the data backed up by the example in the previous
    ++section:</p>
    ++
    ++<pre>
    ++&#64;Override
    ++public void onRestore(BackupDataInput data, int appVersionCode,
    ++                      ParcelFileDescriptor newState) throws IOException {
    ++    // There should be only one entity, but the safest
    ++    // way to consume it is using a while loop
    ++    while (data.readNextHeader()) {
    ++        String key = data.getKey();
    ++        int dataSize = data.getDataSize();
    ++
    ++        // If the key is ours (for saving top score). Note this key was used when
    ++        // we wrote the backup entity header
    ++        if (TOPSCORE_BACKUP_KEY.equals(key)) {
    ++            // Create an input stream for the BackupDataInput
    ++            byte[] dataBuf = new byte[dataSize];
    ++            data.readEntityData(dataBuf, 0, dataSize);
    ++            ByteArrayInputStream baStream = new ByteArrayInputStream(dataBuf);
    ++            DataInputStream in = new DataInputStream(baStream);
    ++
    ++            // Read the player name and score from the backup data
    ++            mPlayerName = in.readUTF();
    ++            mPlayerScore = in.readInt();
    ++
    ++            // Record the score on the device (to a file or something)
    ++            recordScore(mPlayerName, mPlayerScore);
    ++        } else {
    ++            // We don't know this entity key. Skip it. (Shouldn't happen.)
    ++            data.skipEntityData();
    ++        }
    ++    }
    ++
    ++    // Finally, write to the state blob (newState) that describes the restored data
    ++    FileOutputStream outstream = new FileOutputStream(newState.getFileDescriptor());
    ++    DataOutputStream out = new DataOutputStream(outstream);
    ++    out.writeUTF(mPlayerName);
    ++    out.writeInt(mPlayerScore);
    ++}
    ++</pre>
    ++
    ++<p>In this example, the {@code appVersionCode} parameter passed to {@link
    ++android.app.backup.BackupAgent#onRestore onRestore()} is not used. However, you might want to use
    ++it if you've chosen to perform backup when the user's version of the application has actually moved
    ++backward (for example, the user went from version 1.5 of your app to 1.0). For more information, see
    ++the section about <a href="#RestoreVersion">Checking the Restore Data Version</a>.</p>
    ++
    ++<div class="special">
    ++<p>For an example implementation of {@link android.app.backup.BackupAgent}, see the <a
    ++href="{@docRoot}resources/samples/BackupRestore/src/com/example/android/backuprestore/ExampleAgent.html">{@code
    ++ExampleAgent}</a> class in the <a
    ++href="{@docRoot}resources/samples/BackupRestore/index.html">Backup and Restore</a> sample
    ++application.</p>
    ++</div>
    ++
    ++
    ++
    ++
    ++
    ++
    ++<h2 id="BackupAgentHelper">Extending BackupAgentHelper</h2>
    ++
    ++<p>You should build your backup agent using {@link android.app.backup.BackupAgentHelper} if you want
    ++to back up complete files (from either {@link android.content.SharedPreferences} or <a
    ++href="{@docRoot}guide/topics/data/data-storage.html#filesInternal">internal storage</a>).
    ++Building your backup agent with {@link android.app.backup.BackupAgentHelper} requires far less
    ++code than extending {@link android.app.backup.BackupAgent}, because you don't have to implement
    ++{@link
    ++android.app.backup.BackupAgent#onBackup(ParcelFileDescriptor,BackupDataOutput,ParcelFileDescriptor)
    ++onBackup()} and {@link
    ++android.app.backup.BackupAgent#onRestore(BackupDataInput,int,ParcelFileDescriptor)
    ++onRestore()}.</p>
    ++
    ++<p>Your implementation of {@link android.app.backup.BackupAgentHelper} must
    ++use one or more backup helpers. A backup helper is a specialized
    ++component that {@link android.app.backup.BackupAgentHelper} summons to perform backup and
    ++restore operations for a particular type of data. The Android framework currently provides two
    ++different helpers:</p>
    ++<ul>
    ++  <li>{@link android.app.backup.SharedPreferencesBackupHelper} to backup {@link
    ++android.content.SharedPreferences} files.</li>
    ++  <li>{@link android.app.backup.FileBackupHelper} to backup files from <a
    ++href="{@docRoot}guide/topics/data/data-storage.html#filesInternal">internal storage</a>.</li>
    ++</ul>
    ++
    ++<p>You can include multiple helpers in your {@link android.app.backup.BackupAgentHelper}, but only
    ++one helper is needed for each data type. That is, if you have multiple {@link
    ++android.content.SharedPreferences} files, then you need only one {@link
    ++android.app.backup.SharedPreferencesBackupHelper}.</p>
    ++
    ++<p>For each helper you want to add to your {@link android.app.backup.BackupAgentHelper}, you must do
    ++the following during your {@link android.app.backup.BackupAgent#onCreate()} method:</p>
    ++<ol>
    ++  <li>Instantiate in instance of the desired helper class. In the class constructor, you must
    ++specify the appropriate file(s) you want to backup.</li>
    ++  <li>Call {@link android.app.backup.BackupAgentHelper#addHelper(String,BackupHelper) addHelper()}
    ++to add the helper to your {@link android.app.backup.BackupAgentHelper}.</li>
    ++</ol>
    ++
    ++<p>The following sections describe how to create a backup agent using each of the available
    ++helpers.</p>
    ++
    ++
    ++
    ++<h3 id="SharedPreferences">Backing up SharedPreferences</h3>
    ++
    ++<p>When you instantiate a {@link android.app.backup.SharedPreferencesBackupHelper}, you must
    ++include the name of one or more {@link android.content.SharedPreferences} files.</p>
    ++
    ++<p>For example, to back up a {@link android.content.SharedPreferences} file named
    ++"user_preferences", a complete backup agent using {@link android.app.backup.BackupAgentHelper} looks
    ++like this:</p>
    ++
    ++<pre>
    ++public class MyPrefsBackupAgent extends BackupAgentHelper {
    ++    // The name of the SharedPreferences file
    ++    static final String PREFS = "user_preferences";
    ++
    ++    // A key to uniquely identify the set of backup data
    ++    static final String PREFS_BACKUP_KEY = "prefs";
    ++
    ++    // Allocate a helper and add it to the backup agent
    ++    &#64;Override
    ++    public void onCreate() {
    ++        SharedPreferencesBackupHelper helper =
    ++                new SharedPreferencesBackupHelper(this, PREFS);
    ++        addHelper(PREFS_BACKUP_KEY, helper);
    ++    }
    ++}
    ++</pre>
    ++
    ++<p>That's it! That's your entire backup agent. The {@link
    ++android.app.backup.SharedPreferencesBackupHelper} includes all the code
    ++needed to backup and restore a {@link android.content.SharedPreferences} file.</p>
    ++
    ++<p>When the Backup Manager calls {@link
    ++android.app.backup.BackupAgent#onBackup(ParcelFileDescriptor,BackupDataOutput,ParcelFileDescriptor)
    ++onBackup()} and {@link
    ++android.app.backup.BackupAgent#onRestore(BackupDataInput,int,ParcelFileDescriptor)
    ++onRestore()}, {@link android.app.backup.BackupAgentHelper} calls your backup helpers to perform
    ++backup and restore for your specified files.</p>
    ++
    ++<p class="note"><strong>Note:</strong> The methods of {@link android.content.SharedPreferences}
    ++are threadsafe, so
    ++you can safely read and write the shared preferences file from your backup agent and
    ++other activities.</p>
    ++
    ++
    ++
    ++<h3 id="Files">Backing up other files</h3>
    ++
    ++<p>When you instantiate a {@link android.app.backup.FileBackupHelper}, you must include the name of
    ++one or more files that are saved to your application's <a
    ++href="{@docRoot}guide/topics/data/data-storage.html#filesInternal">internal storage</a>
    ++(as specified by {@link android.content.ContextWrapper#getFilesDir()}, which is the same
    ++location where {@link android.content.Context#openFileOutput(String,int) openFileOutput()} writes
    ++files).</p>
    ++
    ++<p>For example, to backup two files named "scores" and "stats," a backup agent using {@link
    ++android.app.backup.BackupAgentHelper} looks like this:</p>
    ++
    ++<pre>
    ++public class MyFileBackupAgent extends BackupAgentHelper {
    ++    // The name of the file
    ++    static final String TOP_SCORES = "scores";
    ++    static final String PLAYER_STATS = "stats";
    ++
    ++    // A key to uniquely identify the set of backup data
    ++    static final String FILES_BACKUP_KEY = "myfiles";
    ++
    ++    // Allocate a helper and add it to the backup agent
    ++    &#64;Override
    ++    public void onCreate() {
    ++        FileBackupHelper helper = new FileBackupHelper(this,
    ++                TOP_SCORES, PLAYER_STATS);
    ++        addHelper(FILES_BACKUP_KEY, helper);
    ++    }
    ++}
    ++</pre>
    ++
    ++<p>The {@link android.app.backup.FileBackupHelper} includes all the code necessary to backup and
    ++restore files that are saved to your application's <a
    ++href="{@docRoot}guide/topics/data/data-storage.html#filesInternal">internal storage</a>..</p>
    ++
    ++<p>However, reading and writing to files on internal storage is <strong>not threadsafe</strong>. To
    ++ensure that your backup agent does not read or write your files at the same time as your activities,
    ++you must use synchronized statements each time you perform a read or write. For example,
    ++in any Activity where you read and write the file, you need an object to use as the intrinsic
    ++lock for the synchronized statements:</p>
    ++
    ++<pre>
    ++// Object for intrinsic lock
    ++static final Object sDataLock = new Object();
    ++</pre>
    ++
    ++<p>Then create a synchronized statement with this lock each time you read or write the files. For
    ++example, here's a synchronized statement for writing the latest score in a game to a file:</p>
    ++
    ++<pre>
    ++try {
    ++    synchronized (MyActivity.sDataLock) {
    ++        File dataFile = new File({@link android.content.Context#getFilesDir()}, TOP_SCORES);
    ++        RandomAccessFile raFile = new RandomAccessFile(dataFile, "rw");
    ++        raFile.writeInt(score);
    ++    }
    ++} catch (IOException e) {
    ++    Log.e(TAG, "Unable to write to file");
    ++}
    ++</pre>
    ++
    ++<p>You should synchronize your read statements with the same lock.</p>
    ++
    ++<p>Then, in your {@link android.app.backup.BackupAgentHelper}, you must override {@link
    ++android.app.backup.BackupAgent#onBackup(ParcelFileDescriptor,BackupDataOutput,ParcelFileDescriptor)
    ++onBackup()} and {@link
    ++android.app.backup.BackupAgent#onRestore(BackupDataInput,int,ParcelFileDescriptor)
    ++onRestore()} to synchronize the backup and restore operations with the same
    ++intrinsic lock. For example, the {@code MyFileBackupAgent} example from above needs the following
    ++methods:</p>
    ++
    ++<pre>
    ++&#64;Override
    ++public void onBackup(ParcelFileDescriptor oldState, BackupDataOutput data,
    ++          ParcelFileDescriptor newState) throws IOException {
    ++    // Hold the lock while the FileBackupHelper performs backup
    ++    synchronized (MyActivity.sDataLock) {
    ++        super.onBackup(oldState, data, newState);
    ++    }
    ++}
    ++
    ++&#64;Override
    ++public void onRestore(BackupDataInput data, int appVersionCode,
    ++        ParcelFileDescriptor newState) throws IOException {
    ++    // Hold the lock while the FileBackupHelper restores the file
    ++    synchronized (MyActivity.sDataLock) {
    ++        super.onRestore(data, appVersionCode, newState);
    ++    }
    ++}
    ++</pre>
    ++
    ++<p>That's it. All you need to do is add your {@link android.app.backup.FileBackupHelper} in the
    ++{@link android.app.backup.BackupAgent#onCreate()} method and override {@link
    ++android.app.backup.BackupAgent#onBackup(ParcelFileDescriptor,BackupDataOutput,ParcelFileDescriptor)
    ++onBackup()} and {@link
    ++android.app.backup.BackupAgent#onRestore(BackupDataInput,int,ParcelFileDescriptor)
    ++onRestore()} to synchronize read and write operations.</p>
    ++
    ++<div class="special">
    ++<p>For an example implementation of {@link
    ++android.app.backup.BackupAgentHelper} with {@link android.app.backup.FileBackupHelper}, see the
    ++{@code FileHelperExampleAgent} class in the <a
    ++href="{@docRoot}resources/samples/BackupRestore/index.html">Backup and Restore</a> sample
    ++application.</p>
    ++</div>
    ++
    ++
    ++
    ++
    ++
    ++
    ++<h2 id="RestoreVersion">Checking the restore data version</h2>
    ++
    ++<p>When the Backup Manager saves your data to cloud storage, it automatically includes the version
    ++of your application, as defined by your manifest file's <a
    ++href="{@docRoot}guide/topics/manifest/manifest-element.html#vcode">{@code android:versionCode}</a>
    ++attribute. Before the Backup Manager calls your backup agent to restore your data, it
    ++looks at the <a
    ++href="{@docRoot}guide/topics/manifest/manifest-element.html#vcode">{@code
    ++android:versionCode}</a> of the installed application and compares it to the value
    ++recorded in the restore data set. If the version recorded in the restore data set is
    ++<em>newer</em> than the application version on the device, then the user has downgraded their
    ++application. In this case, the Backup Manager will abort the restore operation for your application
    ++and not call your {@link
    ++android.app.backup.BackupAgent#onRestore(BackupDataInput,int,ParcelFileDescriptor) onRestore()}
    ++method, because the restore set is considered meaningless to an older version.</p>
    ++
    ++<p>You can override this behavior with the <a
    ++href="{@docRoot}guide/topics/manifest/application-element.html#restoreany">{@code
    ++android:restoreAnyVersion}</a> attribute. This attribute is either "{@code true}" or "{@code
    ++false}" to indicate whether you want to restore the application regardless of the restore set
    ++version. The default value is "{@code false}". If you define this to be "{@code true}" then the
    ++Backup Manager will ignore the <a
    ++href="{@docRoot}guide/topics/manifest/manifest-element.html#vcode">{@code android:versionCode}</a>
    ++and call your {@link
    ++android.app.backup.BackupAgent#onRestore(BackupDataInput,int,ParcelFileDescriptor) onRestore()}
    ++method in all cases. In doing so, you can manually check for the version difference in your {@link
    ++android.app.backup.BackupAgent#onRestore(BackupDataInput,int,ParcelFileDescriptor) onRestore()}
    ++method and take any steps necessary to make the data compatible if the versions conflict.</p>
    ++
    ++<p>To help you handle different versions during a restore operation, the {@link
    ++android.app.backup.BackupAgent#onRestore(BackupDataInput,int,ParcelFileDescriptor) onRestore()}
    ++method passes you the version code included with the restore data set as the {@code appVersionCode}
    ++parameter. You can then query the current application's version code with the {@link
    ++android.content.pm.PackageInfo#versionCode PackageInfo.versionCode} field. For example:</p>
    ++
    ++<pre>
    ++PackageInfo info;
    ++try {
    ++    String name = {@link android.content.ContextWrapper#getPackageName() getPackageName}();
    ++    info = {@link android.content.ContextWrapper#getPackageManager
    ++getPackageManager}().{@link android.content.pm.PackageManager#getPackageInfo(String,int)
    ++getPackageInfo}(name,0);
    ++} catch (NameNotFoundException nnfe) {
    ++    info = null;
    ++}
    ++
    ++int version;
    ++if (info != null) {
    ++    version = info.versionCode;
    ++}
    ++</pre>
    ++
    ++<p>Then simply compare the {@code version} acquired from {@link android.content.pm.PackageInfo}
    ++to the {@code appVersionCode} passed into {@link
    ++android.app.backup.BackupAgent#onRestore(BackupDataInput,int,ParcelFileDescriptor) onRestore()}.
    ++</p>
    ++
    ++<p class="caution"><strong>Caution:</strong> Be certain you understand the consequences of setting
    ++<a href="{@docRoot}guide/topics/manifest/application-element.html#restoreany">{@code
    ++android:restoreAnyVersion}</a> to "{@code true}" for your application. If each version of your
    ++application that supports backup does not properly account for variations in your data format during
    ++{@link
    ++android.app.backup.BackupAgent#onRestore(BackupDataInput,int,ParcelFileDescriptor) onRestore()},
    ++then the data on the device could be saved in a format incompatible with the version currently
    ++installed on the device.</p>
    ++
    ++
    ++
    ++<h2 id="RequestingBackup">Requesting backup</h2>
    ++
    ++<p>You can request a backup operation at any time by calling {@link
    ++android.app.backup.BackupManager#dataChanged()}. This method notifies the Backup Manager that you'd
    ++like to backup your data using your backup agent. The Backup Manager then calls your backup
    ++agent's {@link
    ++android.app.backup.BackupAgent#onBackup(ParcelFileDescriptor,BackupDataOutput,ParcelFileDescriptor)
    ++onBackup()} method at an opportune time in the future. Typically, you should
    ++request a backup each time your data changes (such as when the user changes an application
    ++preference that you'd like to back up). If you call {@link
    ++android.app.backup.BackupManager#dataChanged()} several times consecutively, before the Backup
    ++Manager requests a backup from your agent, your agent still receives just one call to {@link
    ++android.app.backup.BackupAgent#onBackup(ParcelFileDescriptor,BackupDataOutput,ParcelFileDescriptor)
    ++onBackup()}.</p>
    ++
    ++<p class="note"><strong>Note:</strong> While developing your application, you can request a
    ++backup and initiate an immediate backup operation with the <a
    ++href="{@docRoot}tools/help/bmgr.html">{@code bmgr}
    ++tool</a>.</p>
    ++
    ++
    ++<h2 id="RequestingRestore">Requesting restore</h2>
    ++
    ++<p>During the normal life of your application, you shouldn't need to request a restore operation.
    ++They system automatically checks for backup data and performs a restore when your application is
    ++installed. However, you can manually request a restore operation by calling {@link
    ++android.app.backup.BackupManager#requestRestore(RestoreObserver) requestRestore()}, if necessary. In
    ++which case, the Backup Manager calls your {@link
    ++android.app.backup.BackupAgent#onRestore(BackupDataInput,int,ParcelFileDescriptor) onRestore()}
    ++implementation, passing the data from the current set of backup data.</p>
    ++
    ++<p class="note"><strong>Note:</strong> While developing your application, you can request a
    ++restore operation with the <a href="{@docRoot}tools/help/bmgr.html">{@code bmgr}
    ++tool</a>.</p>
    ++
    ++
    ++<h2 id="Migrating">Migrating to Auto Backup</h2>
    ++<p>You can transition your app to full-data backups by setting <a href="{@docRoot}reference/android/R.attr.html#fullBackupOnly">android:fullBackupOnly</a> to <code>true</code> in the <code>&lt;application></code> element in the manifest file. When
    ++running on a device with Android 5.1 (API level 22) or lower, your app ignores
    ++this value in the manifest, and continues performing Key/Value Backups. When
    ++running on a device with Android 6.0 (API level 23) or higher, your app performs
    ++Auto Backup instead of Key/Value Backup.
    +\ No newline at end of file
    +diff --git a/docs/html/guide/topics/data/testingbackup.jd b/docs/html/guide/topics/data/testingbackup.jd
    +new file mode 100644
    +index 0000000..6ff5837
    +--- /dev/null
    ++++ b/docs/html/guide/topics/data/testingbackup.jd
    +@@ -0,0 +1,181 @@
    ++page.title=Testing Backup and Restore
    ++page.tags=backup, marshmallow, androidm
    ++page.keywords=backup, restore, testing
    ++
    ++@jd:body
    ++
    ++<div id="qv-wrapper">
    ++<div id="qv">
    ++  <h2>In this document</h2>
    ++  <ol>
    ++    <li><a href="#HowBackupWorks">How backup works</a></li>
    ++    <li><a href="#Prerequisites">Prerequisites</a></li>
    ++    <li><a href="#Preparing">Preparing your device or emulator</a></li>
    ++    <li><a href="#TestingBackup">Testing backup</a></li>
    ++    <li><a href="#TestingRestore">Testing restore</a></li>
    ++    <li><a href="#Troubleshooting">Troubleshooting</a></li>
    ++  </ol>
    ++
    ++</div>
    ++</div>
    ++
    ++<p>This page shows you how to manually trigger Auto Backup, Key/Value Backup, and restore operations to
    ++ensure your app saves and restores data properly.
    ++
    ++<h2 id="HowBackupWorkso">How backup works</h2>
    ++<p>The section describes various pieces in the Android backup framework and how they
    ++interact with apps that support Auto Backup and Key/Value Backup. During the app
    ++development phase, most of the inner working of the framework were abstracted away, so you didn't need to know this information. However, during the
    ++testing phase, an understanding of these concepts is important.
    ++
    ++<p>The following diagram illustrates how data flows during backup and restore:
    ++
    ++<img src="images/backup-framework.png" alt="backup-framework">
    ++
    ++<p>The <em>Backup Manager Service</em> is an Android system
    ++service which orchestrates and initiates backup and restore operations. The service
    ++is accessible through the {@link android.app.backup.BackupManager}
    ++API. During a backup operation, the service queries your app for backup data,
    ++then hands it to the <em>backup transport</em>, which then archives the data.
    ++During a restore operation, the backup manager service retrieves the backup data
    ++from the backup transport and restores the data to the device.
    ++
    ++<p><em>Backup Transports</em> are Android components that are responsible
    ++for storing and retrieving backups. An Android device can have zero or more
    ++backup transports, but only one of those transports can be marked active. The
    ++available backup transports may differ from device to device (due to
    ++customizations by device manufacturers and service providers), but most Google
    ++Play enabled devices ship with the following transports:
    ++</p><ul>
    ++<li><strong>Google GMS Transport</strong>(default) - the active backup
    ++transport on most devices, part of <a href="https://www.android.com/gms/">Google Mobile Services</a>. This documentation assumes that users are using the
    ++Google GMS transport. This transport stores Auto Backup data in a private folder in the
    ++user's Google Drive account. Key/Value Backup data is stored in the <a href="{@docRoot}google/backup/index.html">Android Backup Service</a>.
    ++<li><strong>Local Transport</strong> - stores backup data locally on the device.
    ++This transport is typically used for development/debugging purposes and is not
    ++useful in the real world.</li></ul>
    ++
    ++<p>If a device does not have any backup transports, then the data cannot be
    ++backed up. Your app is not adversely affected.
    ++
    ++<p class="caution"><strong>Caution:</strong> Because the backup transport
    ++can differ from device to device, Android cannot guarantee the security
    ++of your data while using backup. Be cautious about using backup to store
    ++sensitive data, such as usernames and passwords.
    ++
    ++<h2 id="Prerequisites">Prerequisites</h2>
    ++<p>You need to know a bit about the following tools:
    ++
    ++<ul>
    ++  <li><a href="{@docRoot}studio/command-line/adb.html">adb</a>
    ++- to run commands on the device or emulator
    ++  <li><a href="{@docRoot}studio/command-line/bmgr.html">bmgr</a> - to
    ++perform various backup and restore operations
    ++  <li><a href="{@docRoot}studio/command-line/logcat.html">logcat</a>
    ++- to see the output of backup and restore operations.</li></ul>
    ++
    ++<h2 id="Preparing">Preparing your device or
    ++emulator</h2>
    ++<p>Prepare your device or emulator for backup testing by working through the
    ++following checklist:
    ++<ul>
    ++  <li>For Auto Backup, check that you are using a device or emulator running
    ++Android 6.0 (API level 23) or higher.</li>
    ++  <li>For Key/Value Backup, check that you are using a device or emulator running
    ++Android 2.2 (API level 8) or higher.</li>
    ++  <li>Check that backup and restore is enabled on the device or emulator. There
    ++are two ways to check: <ul>
    ++    <li>On the device, go to <strong>Settings -> Backup &amp; Restore</strong>.
    ++    <li>From adb shell, run <code>bmgr enable</code></li></ul>
    ++    <p>On physical devices, backup and restore is typically enabled during the
    ++initial setup wizard. Emulators do not run the setup wizard, so don't forget to
    ++enable backup and specify a backup account in device settings.
    ++  <li>Make sure the GMS Backup Transport is available and active by running the
    ++command from adb shell:
    ++  <pre class="prettyprint">$ bmgr list transports</pre>
    ++  <p>Then, check the console for the following output:
    ++  <pre class="prettyprint">android/com.android.internal.backup.LocalTransport
    ++* com.google.android.gms/.backup.BackupTransportService</pre>
    ++  <p>Physical devices without Google Play and emulators without Google APIs
    ++might not include the GMS Backup Transport. This article assumes you are using
    ++the GMS Backup Transport. You can test backup and restore with other backup
    ++transports, but the procedure and output can differ.
    ++</ul>
    ++
    ++<h2 id="TestingBackup">Testing backup</h2>
    ++<p>To initiate a backup of your app, run the following command:
    ++
    ++<pre class="prettyprint">$ bmgr backupnow &lt;PACKAGE></pre>
    ++
    ++<p>The <code>backupnow</code> command runs either a Key/Value Backup or Auto Backup depending on
    ++the package's manifest declarations. Check logcat to see the output of the
    ++backup procedure. For example:
    ++
    ++<pre class="prettyprint">D/BackupManagerService: fullTransportBackup()
    ++I/GmsBackupTransport: Attempt to do full backup on &lt;PACKAGE>
    ++
    ++---- or ----
    ++
    ++V/BackupManagerService: Scheduling immediate backup pass
    ++D/PerformBackupTask: starting key/value Backup of BackupRequest{pkg=&lt;PACKAGE>}
    ++</pre>
    ++
    ++<p>If the <code>backupnow</code> command is not available on your device, you need to run one
    ++of the following commands:
    ++<ul>
    ++  <li>For Auto Backups, run: <code>bmgr fullbackup &lt;PACKAGE></code>
    ++  <li>For Key/Value Backups, schedule and run your backup with the following
    ++commands:
    ++  <pre class="prettyprint">$ bmgr backup &lt;PACKAGE>
    ++$ bmgr run</pre>
    ++  <p><code>bmgr backup</code> adds your app to the Backup Manager's queue. <code>bmgr run</code> initiates the
    ++backup operation, which forces the Backup Manager to perform all backup requests
    ++that are in its queue.
    ++  </li></ul>
    ++
    ++<h2 id="TestingRestore">Testing restore</h2>
    ++<p>To manually initiate a restore, run the following command:
    ++
    ++<pre class="prettyprint">$ bmgr restore &lt;PACKAGE></pre>
    ++
    ++<p>Warning: This action stops your app and wipes its data before performing the
    ++restore operation.
    ++
    ++<p>Then, check logcat to see the output of the restore procedure. For example:
    ++
    ++<pre class="prettyprint">V/BackupManagerService: beginRestoreSession: pkg=&lt;PACKAGE> transport=null
    ++V/RestoreSession: restorePackage pkg=&lt;PACKAGE> token=368abb4465c5c683
    ++...
    ++I/BackupManagerService: Restore complete.
    ++</pre>
    ++
    ++<p>You also can test automatic restore for your app by uninstalling and
    ++reinstalling your app either with <code>adb</code> or through the Google
    ++Play Store app.
    ++
    ++<h2 id="Troubleshooting">Troubleshooting</h2>
    ++<p><strong>Exceeded Quota</strong>
    ++
    ++<p>If you see the the following messages in logcat:
    ++
    ++<pre class="prettyprint">I/PFTBT: Transport rejected backup of &lt;PACKAGE>, skipping
    ++
    ++--- or ---
    ++
    ++I/PFTBT: Transport quota exceeded for package: &lt;PACKAGE>
    ++</pre>
    ++
    ++<p>Your app has exceeded the quota and has been banned from backing up
    ++data on this device. To lift the ban, either factory reset your device or change
    ++the backup account.
    ++
    ++<p><strong>Full Backup Not Possible</strong>
    ++
    ++<p>If you see the the following message in logcat:
    ++
    ++<pre class="prettyprint">I/BackupManagerService: Full backup not currently possible -- key/value backup not yet run?
    ++</pre>
    ++
    ++<p>The fullbackup operation failed because no Key/Value Backup operation has yet
    ++occurred on the device. Trigger a Key/Value Backup with the command <code>bmgr
    ++run </code>and then try again.
    +\ No newline at end of file
    +diff --git a/docs/html/guide/topics/graphics/2d-graphics.jd b/docs/html/guide/topics/graphics/2d-graphics.jd
    +index 9cae53c..d7dd038 100644
    +--- a/docs/html/guide/topics/graphics/2d-graphics.jd
    ++++ b/docs/html/guide/topics/graphics/2d-graphics.jd
    +@@ -21,6 +21,7 @@ parent.link=index.html
    +     </li>
    +     <li><a href="#shape-drawable">Shape Drawable</a></li>
    +     <li><a href="#nine-patch">Nine-patch</a></li>
    ++    <li><a href="#vector-drawable">Vector Drawables</a></li>
    +   </ol>
    + 
    +   <h2>See also</h2>
    +@@ -428,58 +429,66 @@ state
    +          of the object it's attached to.
    +          -->
    + 
    +-         <h2 id="nine-patch">Nine-patch</h2>
    +-
    +-         <p>A {@link android.graphics.drawable.NinePatchDrawable} graphic is a stretchable bitmap
    +-image,           which Android
    +-           will automatically resize to accommodate the contents of the View in which you have
    +-placed it as the           background.
    +-           An example use of a NinePatch is the backgrounds used by standard Android buttons &mdash;
    +-           buttons must stretch to accommodate strings of various lengths. A NinePatch drawable is a
    +-standard           PNG
    +-           image that includes an extra 1-pixel-wide border. It must be saved with the extension
    +-           <code>.9.png</code>,
    +-           and saved into the <code>res/drawable/</code> directory of your project.
    +-         </p>
    +-         <p>
    +-           The border is used to define the stretchable and static areas of
    +-           the image. You indicate a stretchable section by drawing one (or more) 1-pixel-wide
    +-           black line(s) in the left and top part of the border (the other border pixels should
    +-           be fully transparent or white). You can have as many stretchable sections as you want:
    +-           their relative size stays the same, so the largest sections always remain the largest.
    +-         </p>
    +-         <p>
    +-           You can also define an optional drawable section of the image (effectively,
    +-           the padding lines) by drawing a line on the right and bottom lines.
    +-           If a View object sets the NinePatch as its background and then specifies the
    +-           View's text, it will stretch itself so that all the text fits inside only
    +-           the area designated by the right and bottom lines (if included). If the
    +-           padding lines are not included, Android uses the left and top lines to
    +-           define this drawable area.
    +-         </p>
    +-         <p>To clarify the difference between the different lines, the left and top lines define
    +-           which pixels of the image are allowed to be replicated in order to stretch the image.
    +-           The bottom and right lines define the relative area within the image that the contents
    +-           of the View are allowed to lie within.</p>
    +-         <p>
    +-           Here is a sample NinePatch file used to define a button:
    +-         </p>
    +-         <img src="{@docRoot}images/ninepatch_raw.png" alt="" />
    +-
    +-         <p>This NinePatch defines one stretchable area with the left and top lines
    +-           and the drawable area with the bottom and right lines. In the top image, the dotted grey
    +-           lines identify the regions of the image that will be replicated in order to stretch the
    +-image. The           pink
    +-           rectangle in the bottom image identifies the region in which the contents of the View are
    +-allowed.
    +-           If the contents don't fit in this region, then the image will be stretched so that they
    +-do.
    ++<h2 id="nine-patch">Nine-patch</h2>
    ++
    ++<p>
    ++  A {@link android.graphics.drawable.NinePatchDrawable} graphic is a
    ++  stretchable bitmap image, which Android will automatically resize to
    ++  accommodate the contents of the View in which you have placed it as the
    ++  background. An example use of a NinePatch is the backgrounds used by
    ++  standard Android buttons — buttons must stretch to accommodate strings of
    ++  various lengths. A NinePatch drawable is a standard PNG image that includes
    ++  an extra 1-pixel-wide border. It must be saved with the extension
    ++  <code>.9.png</code>, and saved into the <code>res/drawable/</code> directory
    ++  of your project.
    + </p>
    + 
    +-<p>The <a href="{@docRoot}tools/help/draw9patch.html">Draw 9-patch</a> tool offers
    +-   an extremely handy way to create your NinePatch images, using a WYSIWYG graphics editor. It
    +-even raises warnings if the region you've defined for the stretchable area is at risk of
    +-producing drawing artifacts as a result of the pixel replication.
    ++<p>
    ++  The border is used to define the stretchable and static areas of the image.
    ++  You indicate a stretchable section by drawing one (or more) 1-pixel-wide
    ++  black line(s) in the left and top part of the border (the other border
    ++  pixels should be fully transparent or white). You can have as many
    ++  stretchable sections as you want: their relative size stays the same, so the
    ++  largest sections always remain the largest.
    ++</p>
    ++
    ++<p>
    ++  You can also define an optional drawable section of the image (effectively,
    ++  the padding lines) by drawing a line on the right and bottom lines. If a
    ++  View object sets the NinePatch as its background and then specifies the
    ++  View's text, it will stretch itself so that all the text fits inside only
    ++  the area designated by the right and bottom lines (if included). If the
    ++  padding lines are not included, Android uses the left and top lines to
    ++  define this drawable area.
    ++</p>
    ++
    ++<p>
    ++  To clarify the difference between the different lines, the left and top
    ++  lines define which pixels of the image are allowed to be replicated in order
    ++  to stretch the image. The bottom and right lines define the relative area
    ++  within the image that the contents of the View are allowed to lie within.
    ++</p>
    ++
    ++<p>
    ++  Here is a sample NinePatch file used to define a button:
    ++</p>
    ++<img src="{@docRoot}images/ninepatch_raw.png" alt="">
    ++<p>
    ++  This NinePatch defines one stretchable area with the left and top lines and
    ++  the drawable area with the bottom and right lines. In the top image, the
    ++  dotted grey lines identify the regions of the image that will be replicated
    ++  in order to stretch the image. The pink rectangle in the bottom image
    ++  identifies the region in which the contents of the View are allowed. If the
    ++  contents don't fit in this region, then the image will be stretched so that
    ++  they do.
    ++</p>
    ++
    ++<p>
    ++  The <a href="{@docRoot}tools/help/draw9patch.html">Draw 9-patch</a> tool
    ++  offers an extremely handy way to create your NinePatch images, using a
    ++  WYSIWYG graphics editor. It even raises warnings if the region you've
    ++  defined for the stretchable area is at risk of producing drawing artifacts
    ++  as a result of the pixel replication.
    + </p>
    + 
    + <h3>Example XML</h3>
    +@@ -516,3 +525,265 @@ stretches to accommodate it.
    + </p>
    + 
    + <img src="{@docRoot}images/ninepatch_examples.png" alt=""/>
    ++
    ++<h2 id="vector-drawable">
    ++  Vector Drawables
    ++</h2>
    ++
    ++<p>
    ++  A {@link android.graphics.drawable.VectorDrawable} graphic replaces multiple
    ++  PNG assets with a single vector graphic. The vector graphic is defined in an
    ++  XML file as a set of points, lines, and curves along with its associated
    ++  color information.
    ++</p>
    ++
    ++<p>
    ++  The major advantage of using a vector graphic is image scalability. Using
    ++  vector graphics resizes the same file for different screen densities without
    ++  loss of image quality. This results in smaller APK files and less developer
    ++  maintenance. You can also use vector images for animation by using multiple
    ++  XML files instead of multiple images for each display resolution.
    ++</p>
    ++
    ++<p>
    ++  Let's go through an example to understand the benefits. An image of size 100
    ++  x 100 dp may render good quality on a smaller display resolution. On larger
    ++  devices, the app might want to use a 400 x 400 dp version of the image.
    ++  Normally, developers create multiple versions of an asset to cater to
    ++  different screen densities. This approach consumes more development efforts,
    ++  and results in a larger APK, which takes more space on the device.
    ++</p>
    ++
    ++<p>
    ++  As of Android 5.0 (API level 21), there are two classes that support vector
    ++  graphics as a drawable resource: {@link
    ++  android.graphics.drawable.VectorDrawable} and {@link
    ++  android.graphics.drawable.AnimatedVectorDrawable}. For more information
    ++  about using the VectorDrawable and the AnimatedVectorDrawable classes, read
    ++  the <a href="#vector-drawable-class">About VectorDrawable class</a> and
    ++  <a href="#animated-vector-drawable-class">About AnimatedVectorDrawable
    ++  class</a> sections.
    ++</p>
    ++
    ++<h3 id="vector-drawable-class">About VectorDrawable class</h3>
    ++<p>
    ++  {@link android.graphics.drawable.VectorDrawable} defines a static drawable
    ++  object. Similar to the SVG format, each vector graphic is defined as a tree
    ++  hierachy, which is made up of <code>path</code> and <code>group</code> objects.
    ++  Each <code>path</code> contains the geometry of the object's outline and
    ++  <code>group</code> contains details for transformation. All paths are drawn
    ++  in the same order as they appear in the XML file.
    ++</p>
    ++
    ++<img src="{@docRoot}images/guide/topics/graphics/vectorpath.png" alt=""/>
    ++<p class="img-caption">
    ++  <strong>Figure 1.</strong> Sample hierarchy of a vector drawable asset
    ++</p>
    ++
    ++
    ++<p>
    ++  The <a href="{@docRoot}studio/write/vector-asset-studio.html">Vector Asset
    ++  Studio</a> tool offers a simple way to add a vector graphic to the project
    ++  as an XML file.
    ++</p>
    ++
    ++<h4>
    ++  Example XML
    ++</h4>
    ++
    ++<p>
    ++  Here is a sample <code>VectorDrawable</code> XML file that renders an image
    ++  of a battery in the charging mode.
    ++</p>
    ++
    ++<pre>
    ++&lt;!-- res/drawable/battery_charging.xml --&gt;
    ++&lt;vector xmlns:android="http://schemas.android.com/apk/res/android"
    ++    &lt;!-- intrinsic size of the drawable --&gt;
    ++    android:height="24dp"
    ++    android:width="24dp"
    ++    &lt;!-- size of the virtual canvas --&gt;
    ++    android:viewportWidth="24.0"
    ++    android:viewportHeight="24.0"&gt;
    ++   &lt;group
    ++         android:name="rotationGroup"
    ++         android:pivotX="10.0"
    ++         android:pivotY="10.0"
    ++         android:rotation="15.0" &gt;
    ++      &lt;path
    ++        android:name="vect"
    ++        android:fillColor="#FF000000"
    ++        android:pathData="M15.67,4H14V2h-4v2H8.33C7.6,4 7,4.6 7,5.33V9h4.93L13,7v2h4V5.33C17,4.6 16.4,4 15.67,4z"
    ++        android:fillAlpha=".3"/&gt;
    ++      &lt;path
    ++        android:name="draw"
    ++        android:fillColor="#FF000000"
    ++        android:pathData="M13,12.5h2L11,20v-5.5H9L11.93,9H7v11.67C7,21.4 7.6,22 8.33,22h7.33c0.74,0 1.34,-0.6 1.34,-1.33V9h-4v3.5z"/&gt;
    ++   &lt;/group&gt;
    ++&lt;/vector&gt;
    ++</pre>
    ++
    ++<p>This XML renders the following image:
    ++</p>
    ++
    ++<img src=
    ++"{@docRoot}images/guide/topics/graphics/ic_battery_charging_80_black_24dp.png"
    ++alt=""/>
    ++
    ++<h3 id="animated-vector-drawable-class">
    ++  About AnimatedVectorDrawable class
    ++</h3>
    ++
    ++<p>
    ++  {@link android.graphics.drawable.AnimatedVectorDrawable
    ++  AnimatedVectorDrawable} adds animation to the properties of a vector
    ++  graphic. You can define an animated vector graphic as three separate
    ++  resource files or as a single XML file defining the entire drawable. Let's
    ++  look at both the approaches for better understanding: <a href=
    ++  "#multiple-files">Multiple XML files</a> and <a href="#single-file">Single
    ++  XML file</a>.
    ++</p>
    ++
    ++<h4 id="multiple-files">
    ++  Multiple XML files
    ++</h4>
    ++<p>
    ++  By using this approach, you can define three separate XML files:
    ++
    ++<ul>
    ++  <li>A {@link android.graphics.drawable.VectorDrawable} XML file.
    ++  </li>
    ++
    ++  <li>
    ++  An {@link android.graphics.drawable.AnimatedVectorDrawable} XML file that
    ++defines the target {@link android.graphics.drawable.VectorDrawable}, the
    ++target paths and groups to animate, the properties, and the animations defined
    ++as {@link android.animation.ObjectAnimator ObjectAnimator} objects or {@link
    ++android.animation.AnimatorSet AnimatorSet} objects.
    ++  </li>
    ++
    ++  <li>An animator XML file.
    ++  </li>
    ++</ul>
    ++</p>
    ++
    ++<h5>
    ++  Example of multiple XML files
    ++</h5>
    ++<p>
    ++  The following XML files demonstrate the animation of a vector graphic.
    ++
    ++<ul>
    ++  <li>VectorDrawable's XML file: <code>vd.xml</code>
    ++  </li>
    ++
    ++  <li style="list-style: none; display: inline">
    ++<pre>
    ++&lt;vector xmlns:android="http://schemas.android.com/apk/res/android"
    ++   android:height="64dp"
    ++   android:width="64dp"
    ++   android:viewportHeight="600"
    ++   android:viewportWidth="600" &gt;
    ++   &lt;group
    ++      android:name="rotationGroup"
    ++      android:pivotX="300.0"
    ++      android:pivotY="300.0"
    ++      android:rotation="45.0" &gt;
    ++      &lt;path
    ++         android:name="vectorPath"
    ++         android:fillColor="#000000"
    ++         android:pathData="M300,70 l 0,-70 70,70 0,0 -70,70z" /&gt;
    ++   &lt;/group&gt;
    ++&lt;/vector&gt;
    ++</pre>
    ++  </li>
    ++
    ++  <li>AnimatedVectorDrawable's XML file: <code>avd.xml</code>
    ++  </li>
    ++
    ++  <li style="list-style: none; display: inline">
    ++<pre>
    ++&lt;animated-vector xmlns:android="http://schemas.android.com/apk/res/android"
    ++   android:drawable="@drawable/vd" &gt;
    ++     &lt;target
    ++         android:name="rotationGroup"
    ++         android:animation="@anim/rotation" /&gt;
    ++     &lt;target
    ++         android:name="vectorPath"
    ++         android:animation="@anim/path_morph" /&gt;
    ++&lt;/animated-vector&gt;
    ++</pre>
    ++  </li>
    ++
    ++  <li>Animator XML files that are used in the AnimatedVectorDrawable's XML
    ++  file: <code>rotation.xml</code> and <code>path_morph.xml</code>
    ++  </li>
    ++
    ++  <li style="list-style: none; display: inline">
    ++<pre>
    ++&lt;objectAnimator
    ++   android:duration="6000"
    ++   android:propertyName="rotation"
    ++   android:valueFrom="0"
    ++   android:valueTo="360" /&gt;
    ++</pre>
    ++
    ++<pre>
    ++&lt;set xmlns:android="http://schemas.android.com/apk/res/android"&gt;
    ++   &lt;objectAnimator
    ++      android:duration="3000"
    ++      android:propertyName="pathData"
    ++      android:valueFrom="M300,70 l 0,-70 70,70 0,0   -70,70z"
    ++      android:valueTo="M300,70 l 0,-70 70,0  0,140 -70,0 z"
    ++      android:valueType="pathType"/&gt;
    ++&lt;/set&gt;
    ++</pre>
    ++  </li>
    ++</ul>
    ++</p>
    ++<h4 id="single-file">
    ++  Single XML file
    ++</h4>
    ++
    ++<p>
    ++  By using this approach, you can merge the related XML files into a single
    ++  XML file through the XML Bundle Format. At the time of building the app, the
    ++  <code>aapt</code> tag creates separate resources and references them in the
    ++  animated vector. This approach requires Build Tools 24 or higher, and the
    ++  output is backward compatible.
    ++</p>
    ++
    ++<h5>
    ++  Example of a single XML file
    ++</h5>
    ++<pre>
    ++&lt;animated-vector
    ++    xmlns:android="http://schemas.android.com/apk/res/android"
    ++    xmlns:aapt="http://schemas.android.com/aapt"&gt;
    ++    &lt;aapt:attr name="android:drawable"&gt;
    ++        &lt;vector
    ++            android:width="24dp"
    ++            android:height="24dp"
    ++            android:viewportWidth="24"
    ++            android:viewportHeight="24"&gt;
    ++            &lt;path
    ++                android:name="root"
    ++                android:strokeWidth="2"
    ++                android:strokeLineCap="square"
    ++                android:strokeColor="?android:colorControlNormal"
    ++                android:pathData="M4.8,13.4 L9,17.6 M10.4,16.2 L19.6,7" /&gt;
    ++        &lt;/vector&gt;
    ++    &lt;/aapt:attr&gt;
    ++    &lt;target android:name="root"&gt;
    ++        &lt;aapt:attr name="android:animation"&gt;
    ++            &lt;objectAnimator
    ++                android:propertyName="pathData"
    ++                android:valueFrom="M4.8,13.4 L9,17.6 M10.4,16.2 L19.6,7"
    ++                android:valueTo="M6.4,6.4 L17.6,17.6 M6.4,17.6 L17.6,6.4"
    ++                android:duration="300"
    ++                android:interpolator="@android:interpolator/fast_out_slow_in"
    ++                android:valueType="pathType" /&gt;
    ++        &lt;/aapt:attr&gt;
    ++    &lt;/target&gt;
    ++&lt;/animated-vector&gt;
    ++</pre>
    +\ No newline at end of file
    +diff --git a/docs/html/guide/topics/location/strategies.jd b/docs/html/guide/topics/location/strategies.jd
    +index 2dfed2c..548ed9c 100755
    +--- a/docs/html/guide/topics/location/strategies.jd
    ++++ b/docs/html/guide/topics/location/strategies.jd
    +@@ -133,36 +133,69 @@ notifications and the third is the minimum change in distance between notificati
    + both to zero requests location notifications as frequently as possible. The last parameter is your
    + {@link android.location.LocationListener}, which receives callbacks for location updates.</p>
    + 
    +-<p>To request location updates from the GPS provider,
    +-substitute <code>GPS_PROVIDER</code> for <code>NETWORK_PROVIDER</code>. You can also request
    +-location updates from both the GPS and the Network Location Provider by calling {@link
    +-android.location.LocationManager#requestLocationUpdates requestLocationUpdates()} twice&mdash;once
    +-for <code>NETWORK_PROVIDER</code> and once for <code>GPS_PROVIDER</code>.</p>
    ++<p>To request location updates from the GPS provider, use {@link
    ++android.location.LocationManager#GPS_PROVIDER} instead of {@link
    ++android.location.LocationManager#NETWORK_PROVIDER}. You can also request
    ++location updates from both the GPS and the Network Location Provider by calling
    ++{@link android.location.LocationManager#requestLocationUpdates
    ++requestLocationUpdates()} twice&mdash;once for {@link
    ++android.location.LocationManager#NETWORK_PROVIDER} and once for {@link
    ++android.location.LocationManager#GPS_PROVIDER}.</p>
    + 
    + 
    + <h3 id="Permission">Requesting User Permissions</h3>
    + 
    +-<p>In order to receive location updates from <code>NETWORK_PROVIDER</code> or
    +-<code>GPS_PROVIDER</code>, you must request user permission by declaring either the {@code
    +-ACCESS_COARSE_LOCATION} or {@code ACCESS_FINE_LOCATION} permission, respectively, in your Android
    +-manifest file. For example:</p>
    ++<p>
    ++  In order to receive location updates from {@link
    ++  android.location.LocationManager#NETWORK_PROVIDER} or {@link
    ++  android.location.LocationManager#GPS_PROVIDER}, you must request the user's
    ++  permission by declaring either the {@code ACCESS_COARSE_LOCATION} or {@code
    ++  ACCESS_FINE_LOCATION} permission, respectively, in your Android manifest file.
    ++  Without these permissions, your application will fail at runtime when
    ++  requesting location updates.
    ++</p>
    ++
    ++<p>
    ++  If you are using both {@link
    ++  android.location.LocationManager#NETWORK_PROVIDER} and {@link
    ++  android.location.LocationManager#GPS_PROVIDER}, then you need to request only
    ++  the {@code ACCESS_FINE_LOCATION} permission, because it includes permission
    ++  for both providers. Permission for {@code ACCESS_COARSE_LOCATION} allows
    ++  access only to {@link android.location.LocationManager#NETWORK_PROVIDER}.
    ++</p>
    ++
    ++<p id="location-feature-caution" class="caution">
    ++  <strong>Caution:</strong> If your app targets Android 5.0 (API level 21) or
    ++  higher, you <em>must</em> declare that your app uses the
    ++  <code>android.hardware.location.network</code> or
    ++  <code>android.hardware.location.gps</code> hardware feature in the manifest
    ++  file, depending on whether your app receives location updates from {@link
    ++  android.location.LocationManager#NETWORK_PROVIDER} or from {@link
    ++  android.location.LocationManager#GPS_PROVIDER}. If your app receives location
    ++  information from either of these location provider sources, you need to
    ++  declare that the app uses these hardware features in your app manifest.
    ++  On devices running verions prior to Android 5.0 (API 21), requesting the
    ++  {@code ACCESS_FINE_LOCATION} or {@code ACCESS_COARSE_LOCATION} permission
    ++  includes an implied request for location hardware features. However,
    ++  requesting those permissions <em>does not</em> automatically request location
    ++  hardware features on Android 5.0 (API level 21) and higher.
    ++</p>
    + 
    ++<p>
    ++   The following code sample demonstrates how to declare the permission and
    ++   hardware feature in the manifest file of an app that reads data from the
    ++   device's GPS:
    ++</p>
    + <pre>
    + &lt;manifest ... &gt;
    +     &lt;uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" /&gt;
    +     ...
    ++    &lt;!-- Needed only if your app targets Android 5.0 (API level 21) or higher. --&gt;
    ++    &lt;uses-feature android:name="android.hardware.location.gps" /&gt;
    ++    ...
    + &lt;/manifest&gt;
    + </pre>
    + 
    +-<p>Without these permissions, your application will fail at runtime when requesting
    +-location updates.</p>
    +-
    +-<p class="note"><strong>Note:</strong> If you are using both <code>NETWORK_PROVIDER</code> and
    +-<code>GPS_PROVIDER</code>, then you need to request only the {@code ACCESS_FINE_LOCATION}
    +-permission, because it includes permission for both providers. (Permission for {@code
    +-ACCESS_COARSE_LOCATION} includes permission only for <code>NETWORK_PROVIDER</code>.)</p>
    +-
    +-
    + <h2 id="BestPerformance">Defining a Model for the Best Performance</h2>
    + 
    +   <p>Location-based applications are now commonplace, but due to the less than optimal
    +@@ -404,9 +437,10 @@ don't have a device, you can still test your location-based features by mocking
    + the Android emulator. There are three different ways to send your application mock location
    + data: using Android Studio, DDMS, or the "geo" command in the emulator console.</p>
    + 
    +-<p class="note"><strong>Note:</strong> Providing mock location data is injected as GPS location
    +-data, so you must request location updates from <code>GPS_PROVIDER</code> in order for mock location
    +-data to work.</p>
    ++<p class="note"><strong>Note:</strong> Providing mock location data is injected
    ++as GPS location data, so you must request location updates from {@link
    ++android.location.LocationManager#GPS_PROVIDER} in order for mock location data
    ++to work.</p>
    + 
    + <h3 id="MockAVD">Using Android Studio</h3>
    + 
    +diff --git a/docs/html/guide/topics/manifest/meta-data-element.jd b/docs/html/guide/topics/manifest/meta-data-element.jd
    +index 945b116..2d1bdfe 100644
    +--- a/docs/html/guide/topics/manifest/meta-data-element.jd
    ++++ b/docs/html/guide/topics/manifest/meta-data-element.jd
    +@@ -60,7 +60,7 @@ Java-style naming convention &mdash; for example,
    + <dt><a name="rsrc"></a>{@code android:resource}</dt>
    + <dd>A reference to a resource.  The ID of the resource is the value assigned
    + to the item.  The ID can be retrieved from the meta-data Bundle by the
    +-{@link android.os.BaseBundle#getInt Bundle.getInt()} method.</dd>
    ++{@link android.os.Bundle#getInt Bundle.getInt()} method.</dd>
    + 
    + <dt><a name="val"></a>{@code android:value}</dt>
    + <dd>The value assigned to the item.  The data types that can be assigned as values and the Bundle methods that  components use to retrieve those values are listed in the following table:
    +@@ -72,17 +72,17 @@ to the item.  The ID can be retrieved from the meta-data Bundle by the
    + </tr><tr>
    +   <td>String value, using double backslashes ({@code \\}) to escape characters
    +       &mdash; such as "{@code \\n}" and "{@code \\uxxxxx}" for a Unicode character.</td>
    +-  <td>{@link android.os.BaseBundle#getString(String) getString()}</td>
    ++  <td>{@link android.os.Bundle#getString(String) getString()}</td>
    + </tr><tr>
    +   <td>Integer value, such as "{@code 100}"</td>
    +-  <td>{@link android.os.BaseBundle#getInt(String) getInt()}</td>
    ++  <td>{@link android.os.Bundle#getInt(String) getInt()}</td>
    + </tr><tr>
    +   <td>Boolean value, either "{@code true}" or "{@code false}"</td>
    +-  <td>{@link android.os.BaseBundle#getBoolean(String) getBoolean()}</td>
    ++  <td>{@link android.os.Bundle#getBoolean(String) getBoolean()}</td>
    + </tr><tr>
    +   <td>Color value, in the form "{@code #rgb}", "{@code #argb}",
    +       "{@code #rrggbb}", or "{@code #aarrggbb}"</td>
    +-  <td>{@link android.os.BaseBundle#getInt(String) getInt()}</td>
    ++  <td>{@link android.os.Bundle#getInt(String) getInt()}</td>
    + </tr><tr>
    +   <td>Float value, such as "{@code 1.23}"</td>
    +   <td>{@link android.os.Bundle#getFloat(String) getFloat()}</td>
    +diff --git a/docs/html/guide/topics/manifest/provider-element.jd b/docs/html/guide/topics/manifest/provider-element.jd
    +index 1947849..0e729c3 100644
    +--- a/docs/html/guide/topics/manifest/provider-element.jd
    ++++ b/docs/html/guide/topics/manifest/provider-element.jd
    +@@ -215,17 +215,15 @@ it can also be set as a raw string.
    + </p></dd>
    + 
    + <dt><a name="multi"></a>{@code android:multiprocess}</dt>
    +-<dd>Whether or not an instance of the content provider can be created in
    +-every client process &mdash; "{@code true}" if instances can run in multiple
    +-processes, and "{@code false}" if not.  The default value is "{@code false}".
    +-
    +-<p>
    +-Normally, a content provider is instantiated in the process of the
    +-application that defined it.  However, if this flag is set to "{@code true}",
    +-the system can create an instance in every process where there's a client
    +-that wants to interact with it, thus avoiding the overhead of interprocess
    +-communication.
    +-</p></dd>
    ++<dd>If the app runs in multiple processes, this attribute determines whether
    ++multiple instances of the content provder are created. If <code>true</code>,
    ++each of the app's processes has its own content provider object. If
    ++<code>false</code>, the app's processes share only one content provider object.
    ++The default value is <code>false</code>.
    ++
    ++<p>Setting this flag to <code>true</code> may improve performance by reducing
    ++the overhead of interprocess communication, but it also increases the memory
    ++footprint of each process.</p></dd>
    + 
    + <dt><a name="nm"></a>{@code android:name}</dt>
    + <dd>The name of the class that implements the content provider, a subclass of
    +diff --git a/docs/html/guide/topics/manifest/receiver-element.jd b/docs/html/guide/topics/manifest/receiver-element.jd
    +index 800ee8a..c866047 100644
    +--- a/docs/html/guide/topics/manifest/receiver-element.jd
    ++++ b/docs/html/guide/topics/manifest/receiver-element.jd
    +@@ -33,8 +33,18 @@ There are two ways to make a broadcast receiver known to the system:  One is
    + declare it in the manifest file with this element.  The other is to create
    + the receiver dynamically in code and register it with the <code>{@link
    + android.content.Context#registerReceiver Context.registerReceiver()}</code>
    +-method.  See the {@link android.content.BroadcastReceiver} class description
    +-for more on dynamically created receivers.
    ++method. For more information about how to dynamically create receivers, see the
    ++{@link android.content.BroadcastReceiver} class description.
    ++</p>
    ++
    ++<p class="warning">
    ++    <strong>Warning:</strong> Limit how many broadcast
    ++    receivers you set in your app. Having too many broadcast receivers can
    ++    affect your app's performance and the battery life of users' devices.
    ++    For more information about APIs you can use instead of the
    ++    {@link android.content.BroadcastReceiver} class for scheduling background
    ++    work, see
    ++    <a href="/topic/performance/background-optimization.html">Background Optimizations</a>.
    + </p></dd>
    + 
    + <dt>attributes:</dt>
    +diff --git a/docs/html/guide/topics/manifest/uses-feature-element.jd b/docs/html/guide/topics/manifest/uses-feature-element.jd
    +index 9b32244..843fe1c 100755
    +--- a/docs/html/guide/topics/manifest/uses-feature-element.jd
    ++++ b/docs/html/guide/topics/manifest/uses-feature-element.jd
    +@@ -512,10 +512,11 @@ You can find your unsigned <code>.apk</code> in the
    + 
    + <li>Next, locate the <code>aapt</code> tool, if it is not already in your PATH.
    + If you are using SDK Tools r8 or higher, you can find <code>aapt</code> in the
    +-<code>&lt;<em>SDK</em>&gt;/platform-tools/</code> directory.
    ++<code>&lt;<em>SDK</em>&gt;/build-tools/&lt;<em>tools version number</em>&gt;</code>
    ++directory.
    + <p class="note"><strong>Note:</strong> You must use the version of
    +-<code>aapt</code> that is provided for the latest Platform-Tools component available. If
    +-you do not have the latest Platform-Tools component, download it using the <a
    ++<code>aapt</code> that is provided for the latest Build-Tools component available. If
    ++you do not have the latest Build-Tools component, download it using the <a
    + href="{@docRoot}studio/intro/update.html">Android SDK Manager</a>.
    + </p></li>
    + <li>Run <code>aapt</code> using this syntax: </li>
    +@@ -1666,6 +1667,15 @@ densities: '160'
    + 
    + <pre>&lt;uses-feature android:name="android.hardware.camera" android:required="false" /&gt;</pre>
    + 
    ++<p class="caution">
    ++  <strong>Caution:</strong> If your app targets Android 5.0 (API level 21) or
    ++  higher and uses the <code>ACCESS_COARSE_LOCATION</code> or
    ++  <code>ACCESS_FINE_LOCATION</code> permission in order to receive location
    ++  updates from the network or a GPS, respectively, you must also explicitly
    ++  declare that your app uses the <code>android.hardware.location.network</code>
    ++  or <code>android.hardware.location.gps</code> hardware features.
    ++</p>
    ++
    + <p class="table-caption" id="permissions-features">
    +   <strong>Table 2. </strong>Device permissions that imply device hardware use.
    + </p>
    +@@ -1717,14 +1727,29 @@ densities: '160'
    + </tr>
    + <tr>
    +   <td><code>ACCESS_COARSE_LOCATION</code></td>
    +-  <td><code>android.hardware.location.network</code> <em>and</em>
    +-<br><code>android.hardware.location</code></td>
    ++  <td>
    ++    <p>
    ++      <code>android.hardware.location</code>
    ++    </p>
    ++    <p>
    ++      <code>android.hardware.location.network</code>
    ++      (Only when target API level is 20 or lower.)
    ++    </p>
    ++  </td>
    + <!--  <td></td> -->
    + </tr>
    + <tr>
    +   <td><code>ACCESS_FINE_LOCATION</code></td>
    +-  <td><code>android.hardware.location.gps</code> <em>and</em>
    +-<br><code>android.hardware.location</code></td>
    ++  <td>
    ++    <p>
    ++      <code>android.hardware.location</code>
    ++    </p>
    ++    <p>
    ++      <code>android.hardware.location.gps</code>
    ++      (Only when target API level is 20 or lower.)
    ++    </p>
    ++  </td>
    ++
    + <!--  <td></td> -->
    + </tr>
    + 
    +diff --git a/docs/html/guide/topics/media/camera.jd b/docs/html/guide/topics/media/camera.jd
    +index 4995a13..383b6c1 100644
    +--- a/docs/html/guide/topics/media/camera.jd
    ++++ b/docs/html/guide/topics/media/camera.jd
    +@@ -154,10 +154,16 @@ application must request the audio capture permission.
    + &lt;uses-permission android:name="android.permission.RECORD_AUDIO" /&gt;
    + </pre>
    +   </li>
    +-  <li><strong>Location Permission</strong> - If your application tags images with GPS location
    +-information, you must request location permission:
    ++  <li>
    ++    <p><strong>Location Permission</strong> - If your application tags images
    ++    with GPS location information, you must request the {@code ACCESS_FINE_LOCATION}
    ++    permission. Note that, if your app targets Android 5.0 (API level 21) or
    ++    higher, you also need to declare that your app uses the device's GPS:</p>
    + <pre>
    + &lt;uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" /&gt;
    ++...
    ++&lt;!-- Needed only if your app targets Android 5.0 (API level 21) or higher. --&gt;
    ++&lt;uses-feature android:name="android.hardware.location.gps" /&gt;
    + </pre>
    + <p>For more information about getting user location, see
    + <a href="{@docRoot}guide/topics/location/strategies.html">Location Strategies</a>.</p>
    +diff --git a/docs/html/guide/topics/providers/calendar-provider.jd b/docs/html/guide/topics/providers/calendar-provider.jd
    +index 01a1bfc..485f3c1 100644
    +--- a/docs/html/guide/topics/providers/calendar-provider.jd
    ++++ b/docs/html/guide/topics/providers/calendar-provider.jd
    +@@ -278,9 +278,9 @@ private static final int PROJECTION_OWNER_ACCOUNT_INDEX = 3;</pre>
    + 
    + <div class="sidebox-wrapper"> <div class="sidebox"> <h3>Why must you include
    + ACCOUNT_TYPE?</h3> <p>If you query on a {@link
    +-android.provider.CalendarContract.SyncColumns#ACCOUNT_NAME
    ++android.provider.CalendarContract.Calendars#ACCOUNT_NAME
    + Calendars.ACCOUNT_NAME}, you must also include
    +-{@link android.provider.CalendarContract.SyncColumns#ACCOUNT_TYPE Calendars.ACCOUNT_TYPE}
    ++{@link android.provider.CalendarContract.Calendars#ACCOUNT_TYPE Calendars.ACCOUNT_TYPE}
    + in the selection. That is because a given account is
    + only considered unique given both its <code>ACCOUNT_NAME</code> and its
    + <code>ACCOUNT_TYPE</code>. The <code>ACCOUNT_TYPE</code> is the string corresponding to the
    +diff --git a/docs/html/guide/topics/providers/contacts-provider.jd b/docs/html/guide/topics/providers/contacts-provider.jd
    +index ac855aa..2b14558 100644
    +--- a/docs/html/guide/topics/providers/contacts-provider.jd
    ++++ b/docs/html/guide/topics/providers/contacts-provider.jd
    +@@ -329,13 +329,13 @@ page.title=Contacts Provider
    + </p>
    + <dl>
    +     <dt>
    +-        {@link android.provider.ContactsContract.DataColumns#RAW_CONTACT_ID}
    ++        {@link android.provider.ContactsContract.Data#RAW_CONTACT_ID}
    +     </dt>
    +     <dd>
    +         The value of the <code>_ID</code> column of the raw contact for this data.
    +     </dd>
    +     <dt>
    +-        {@link android.provider.ContactsContract.DataColumns#MIMETYPE}
    ++        {@link android.provider.ContactsContract.Data#MIMETYPE}
    +     </dt>
    +     <dd>
    +         The type of data stored in this row, expressed as a custom MIME type. The Contacts Provider
    +@@ -2351,7 +2351,7 @@ child elements that provide specific data to the
    +     {@link android.provider.ContactsContract.Data} table, selecting on the raw contact's
    +     {@link android.provider.BaseColumns#_ID}, the
    +     {@link android.provider.ContactsContract.CommonDataKinds.Photo#CONTENT_ITEM_TYPE
    +-    Photo.CONTENT_ITEM_TYPE}, and the {@link android.provider.ContactsContract.DataColumns#IS_PRIMARY}
    ++    Photo.CONTENT_ITEM_TYPE}, and the {@link android.provider.ContactsContract.Data#IS_PRIMARY}
    +     column to find the raw contact's primary photo row.
    + </p>
    + <p>
    +diff --git a/docs/html/guide/topics/providers/content-provider-creating.jd b/docs/html/guide/topics/providers/content-provider-creating.jd
    +index ec6909c..59dc108 100755
    +--- a/docs/html/guide/topics/providers/content-provider-creating.jd
    ++++ b/docs/html/guide/topics/providers/content-provider-creating.jd
    +@@ -460,7 +460,7 @@ public class ExampleProvider extends ContentProvider {
    +                  * present. Get the last path segment from the URI; this is the _ID value.
    +                  * Then, append the value to the WHERE clause for the query
    +                  */
    +-                selection = selection + "_ID = " uri.getLastPathSegment();
    ++                selection = selection + "_ID = " + uri.getLastPathSegment();
    +                 break;
    + 
    +             default:
    +diff --git a/docs/html/guide/topics/renderscript/reference/rs_allocation_create.jd b/docs/html/guide/topics/renderscript/reference/rs_allocation_create.jd
    +new file mode 100644
    +index 0000000..2defca3
    +--- /dev/null
    ++++ b/docs/html/guide/topics/renderscript/reference/rs_allocation_create.jd
    +@@ -0,0 +1,1060 @@
    ++page.title=RenderScript Allocation Creation Functions
    ++
    ++@jd:body
    ++
    ++<div class='renderscript'>
    ++<h2>Overview</h2>
    ++<p> The functions below are used to create allocations from within a script.
    ++These functions can be called directly or indirectly from an invokable
    ++function. It is an error if any control flow can result in calling these functions
    ++from a RenderScript kernel function.
    ++</p>
    ++<h2>Summary</h2>
    ++<table class='jd-sumtable'><tbody>
    ++  <tr><th colspan='2'>Functions</th></tr>
    ++  <tr class='alt-color api apilevel-1'>
    ++    <td class='jd-linkcol'>
    ++      <a href='rs_allocation_create.html#android_rs:rsCreateAllocation'>rsCreateAllocation</a>
    ++    </td>
    ++    <td class='jd-descrcol' width='100%'>
    ++      Creates an <a href={@docRoot}guide/topics/renderscript/reference/rs_object_types.html#android_rs:rs_allocation>rs_allocation</a> object of given <a href={@docRoot}guide/topics/renderscript/reference/rs_object_types.html#android_rs:rs_type>rs_type</a>
    ++    </td>
    ++  </tr>
    ++  <tr class='alt-color api apilevel-1'>
    ++    <td class='jd-linkcol'>
    ++      <a href='rs_allocation_create.html#android_rs:rsCreateElement'>rsCreateElement</a>
    ++    </td>
    ++    <td class='jd-descrcol' width='100%'>
    ++      Creates an <a href={@docRoot}guide/topics/renderscript/reference/rs_object_types.html#android_rs:rs_element>rs_element</a> object of the specified data type
    ++    </td>
    ++  </tr>
    ++  <tr class='alt-color api apilevel-1'>
    ++    <td class='jd-linkcol'>
    ++      <a href='rs_allocation_create.html#android_rs:rsCreatePixelElement'>rsCreatePixelElement</a>
    ++    </td>
    ++    <td class='jd-descrcol' width='100%'>
    ++      Creates an <a href={@docRoot}guide/topics/renderscript/reference/rs_object_types.html#android_rs:rs_element>rs_element</a> object of the specified data type and data kind
    ++    </td>
    ++  </tr>
    ++  <tr class='alt-color api apilevel-1'>
    ++    <td class='jd-linkcol'>
    ++      <a href='rs_allocation_create.html#android_rs:rsCreateType'>rsCreateType</a>
    ++    </td>
    ++    <td class='jd-descrcol' width='100%'>
    ++      Creates an <a href={@docRoot}guide/topics/renderscript/reference/rs_object_types.html#android_rs:rs_type>rs_type</a> object with the specified <a href={@docRoot}guide/topics/renderscript/reference/rs_object_types.html#android_rs:rs_element>rs_element</a> and shape attributes
    ++    </td>
    ++  </tr>
    ++  <tr class='alt-color api apilevel-1'>
    ++    <td class='jd-linkcol'>
    ++      <a href='rs_allocation_create.html#android_rs:rsCreateVectorElement'>rsCreateVectorElement</a>
    ++    </td>
    ++    <td class='jd-descrcol' width='100%'>
    ++      Creates an <a href={@docRoot}guide/topics/renderscript/reference/rs_object_types.html#android_rs:rs_element>rs_element</a> object of the specified data type and vector width
    ++    </td>
    ++  </tr>
    ++</tbody></table>
    ++<h2>Functions</h2>
    ++<a name='android_rs:rsCreateAllocation'></a>
    ++<div class='jd-details'>
    ++  <h4 class='jd-details-title'>
    ++    <span class='sympad'>rsCreateAllocation</span>
    ++    <span class='normal'>: Creates an <a href={@docRoot}guide/topics/renderscript/reference/rs_object_types.html#android_rs:rs_allocation>rs_allocation</a> object of given <a href={@docRoot}guide/topics/renderscript/reference/rs_object_types.html#android_rs:rs_type>rs_type</a></span>
    ++  </h4>
    ++  <div class='jd-details-descr'>
    ++    <table class='jd-tagtable'><tbody>
    ++      <tr>
    ++        <td><a href='rs_object_types.html#android_rs:rs_allocation'>rs_allocation</a> rsCreateAllocation(<a href='rs_object_types.html#android_rs:rs_type'>rs_type</a> type);
    ++</td>
    ++        <td>    Added in <a href='http://developer.android.com/guide/topics/manifest/uses-sdk-element.html#ApiLevels'>API level 24</a>
    ++        </td>
    ++      </tr>
    ++      <tr>
    ++        <td><a href='rs_object_types.html#android_rs:rs_allocation'>rs_allocation</a> rsCreateAllocation(<a href='rs_object_types.html#android_rs:rs_type'>rs_type</a> type, <a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> usage);
    ++</td>
    ++        <td>    Added in <a href='http://developer.android.com/guide/topics/manifest/uses-sdk-element.html#ApiLevels'>API level 24</a>
    ++        </td>
    ++      </tr>
    ++      <tr>
    ++        <td><a href='rs_object_types.html#android_rs:rs_allocation'>rs_allocation</a> rsCreateAllocation_char(<a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimX);
    ++</td>
    ++        <td>    Added in <a href='http://developer.android.com/guide/topics/manifest/uses-sdk-element.html#ApiLevels'>API level 24</a>
    ++        </td>
    ++      </tr>
    ++      <tr>
    ++        <td><a href='rs_object_types.html#android_rs:rs_allocation'>rs_allocation</a> rsCreateAllocation_char(<a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimX, <a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimY);
    ++</td>
    ++        <td>    Added in <a href='http://developer.android.com/guide/topics/manifest/uses-sdk-element.html#ApiLevels'>API level 24</a>
    ++        </td>
    ++      </tr>
    ++      <tr>
    ++        <td><a href='rs_object_types.html#android_rs:rs_allocation'>rs_allocation</a> rsCreateAllocation_char(<a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimX, <a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimY, <a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimZ);
    ++</td>
    ++        <td>    Added in <a href='http://developer.android.com/guide/topics/manifest/uses-sdk-element.html#ApiLevels'>API level 24</a>
    ++        </td>
    ++      </tr>
    ++      <tr>
    ++        <td><a href='rs_object_types.html#android_rs:rs_allocation'>rs_allocation</a> rsCreateAllocation_char2(<a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimX);
    ++</td>
    ++        <td>    Added in <a href='http://developer.android.com/guide/topics/manifest/uses-sdk-element.html#ApiLevels'>API level 24</a>
    ++        </td>
    ++      </tr>
    ++      <tr>
    ++        <td><a href='rs_object_types.html#android_rs:rs_allocation'>rs_allocation</a> rsCreateAllocation_char2(<a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimX, <a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimY);
    ++</td>
    ++        <td>    Added in <a href='http://developer.android.com/guide/topics/manifest/uses-sdk-element.html#ApiLevels'>API level 24</a>
    ++        </td>
    ++      </tr>
    ++      <tr>
    ++        <td><a href='rs_object_types.html#android_rs:rs_allocation'>rs_allocation</a> rsCreateAllocation_char2(<a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimX, <a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimY, <a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimZ);
    ++</td>
    ++        <td>    Added in <a href='http://developer.android.com/guide/topics/manifest/uses-sdk-element.html#ApiLevels'>API level 24</a>
    ++        </td>
    ++      </tr>
    ++      <tr>
    ++        <td><a href='rs_object_types.html#android_rs:rs_allocation'>rs_allocation</a> rsCreateAllocation_char3(<a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimX);
    ++</td>
    ++        <td>    Added in <a href='http://developer.android.com/guide/topics/manifest/uses-sdk-element.html#ApiLevels'>API level 24</a>
    ++        </td>
    ++      </tr>
    ++      <tr>
    ++        <td><a href='rs_object_types.html#android_rs:rs_allocation'>rs_allocation</a> rsCreateAllocation_char3(<a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimX, <a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimY);
    ++</td>
    ++        <td>    Added in <a href='http://developer.android.com/guide/topics/manifest/uses-sdk-element.html#ApiLevels'>API level 24</a>
    ++        </td>
    ++      </tr>
    ++      <tr>
    ++        <td><a href='rs_object_types.html#android_rs:rs_allocation'>rs_allocation</a> rsCreateAllocation_char3(<a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimX, <a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimY, <a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimZ);
    ++</td>
    ++        <td>    Added in <a href='http://developer.android.com/guide/topics/manifest/uses-sdk-element.html#ApiLevels'>API level 24</a>
    ++        </td>
    ++      </tr>
    ++      <tr>
    ++        <td><a href='rs_object_types.html#android_rs:rs_allocation'>rs_allocation</a> rsCreateAllocation_char4(<a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimX);
    ++</td>
    ++        <td>    Added in <a href='http://developer.android.com/guide/topics/manifest/uses-sdk-element.html#ApiLevels'>API level 24</a>
    ++        </td>
    ++      </tr>
    ++      <tr>
    ++        <td><a href='rs_object_types.html#android_rs:rs_allocation'>rs_allocation</a> rsCreateAllocation_char4(<a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimX, <a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimY);
    ++</td>
    ++        <td>    Added in <a href='http://developer.android.com/guide/topics/manifest/uses-sdk-element.html#ApiLevels'>API level 24</a>
    ++        </td>
    ++      </tr>
    ++      <tr>
    ++        <td><a href='rs_object_types.html#android_rs:rs_allocation'>rs_allocation</a> rsCreateAllocation_char4(<a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimX, <a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimY, <a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimZ);
    ++</td>
    ++        <td>    Added in <a href='http://developer.android.com/guide/topics/manifest/uses-sdk-element.html#ApiLevels'>API level 24</a>
    ++        </td>
    ++      </tr>
    ++      <tr>
    ++        <td><a href='rs_object_types.html#android_rs:rs_allocation'>rs_allocation</a> rsCreateAllocation_double(<a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimX);
    ++</td>
    ++        <td>    Added in <a href='http://developer.android.com/guide/topics/manifest/uses-sdk-element.html#ApiLevels'>API level 24</a>
    ++        </td>
    ++      </tr>
    ++      <tr>
    ++        <td><a href='rs_object_types.html#android_rs:rs_allocation'>rs_allocation</a> rsCreateAllocation_double(<a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimX, <a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimY);
    ++</td>
    ++        <td>    Added in <a href='http://developer.android.com/guide/topics/manifest/uses-sdk-element.html#ApiLevels'>API level 24</a>
    ++        </td>
    ++      </tr>
    ++      <tr>
    ++        <td><a href='rs_object_types.html#android_rs:rs_allocation'>rs_allocation</a> rsCreateAllocation_double(<a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimX, <a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimY, <a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimZ);
    ++</td>
    ++        <td>    Added in <a href='http://developer.android.com/guide/topics/manifest/uses-sdk-element.html#ApiLevels'>API level 24</a>
    ++        </td>
    ++      </tr>
    ++      <tr>
    ++        <td><a href='rs_object_types.html#android_rs:rs_allocation'>rs_allocation</a> rsCreateAllocation_double2(<a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimX);
    ++</td>
    ++        <td>    Added in <a href='http://developer.android.com/guide/topics/manifest/uses-sdk-element.html#ApiLevels'>API level 24</a>
    ++        </td>
    ++      </tr>
    ++      <tr>
    ++        <td><a href='rs_object_types.html#android_rs:rs_allocation'>rs_allocation</a> rsCreateAllocation_double2(<a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimX, <a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimY);
    ++</td>
    ++        <td>    Added in <a href='http://developer.android.com/guide/topics/manifest/uses-sdk-element.html#ApiLevels'>API level 24</a>
    ++        </td>
    ++      </tr>
    ++      <tr>
    ++        <td><a href='rs_object_types.html#android_rs:rs_allocation'>rs_allocation</a> rsCreateAllocation_double2(<a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimX, <a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimY, <a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimZ);
    ++</td>
    ++        <td>    Added in <a href='http://developer.android.com/guide/topics/manifest/uses-sdk-element.html#ApiLevels'>API level 24</a>
    ++        </td>
    ++      </tr>
    ++      <tr>
    ++        <td><a href='rs_object_types.html#android_rs:rs_allocation'>rs_allocation</a> rsCreateAllocation_double3(<a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimX);
    ++</td>
    ++        <td>    Added in <a href='http://developer.android.com/guide/topics/manifest/uses-sdk-element.html#ApiLevels'>API level 24</a>
    ++        </td>
    ++      </tr>
    ++      <tr>
    ++        <td><a href='rs_object_types.html#android_rs:rs_allocation'>rs_allocation</a> rsCreateAllocation_double3(<a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimX, <a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimY);
    ++</td>
    ++        <td>    Added in <a href='http://developer.android.com/guide/topics/manifest/uses-sdk-element.html#ApiLevels'>API level 24</a>
    ++        </td>
    ++      </tr>
    ++      <tr>
    ++        <td><a href='rs_object_types.html#android_rs:rs_allocation'>rs_allocation</a> rsCreateAllocation_double3(<a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimX, <a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimY, <a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimZ);
    ++</td>
    ++        <td>    Added in <a href='http://developer.android.com/guide/topics/manifest/uses-sdk-element.html#ApiLevels'>API level 24</a>
    ++        </td>
    ++      </tr>
    ++      <tr>
    ++        <td><a href='rs_object_types.html#android_rs:rs_allocation'>rs_allocation</a> rsCreateAllocation_double4(<a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimX);
    ++</td>
    ++        <td>    Added in <a href='http://developer.android.com/guide/topics/manifest/uses-sdk-element.html#ApiLevels'>API level 24</a>
    ++        </td>
    ++      </tr>
    ++      <tr>
    ++        <td><a href='rs_object_types.html#android_rs:rs_allocation'>rs_allocation</a> rsCreateAllocation_double4(<a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimX, <a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimY);
    ++</td>
    ++        <td>    Added in <a href='http://developer.android.com/guide/topics/manifest/uses-sdk-element.html#ApiLevels'>API level 24</a>
    ++        </td>
    ++      </tr>
    ++      <tr>
    ++        <td><a href='rs_object_types.html#android_rs:rs_allocation'>rs_allocation</a> rsCreateAllocation_double4(<a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimX, <a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimY, <a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimZ);
    ++</td>
    ++        <td>    Added in <a href='http://developer.android.com/guide/topics/manifest/uses-sdk-element.html#ApiLevels'>API level 24</a>
    ++        </td>
    ++      </tr>
    ++      <tr>
    ++        <td><a href='rs_object_types.html#android_rs:rs_allocation'>rs_allocation</a> rsCreateAllocation_float(<a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimX);
    ++</td>
    ++        <td>    Added in <a href='http://developer.android.com/guide/topics/manifest/uses-sdk-element.html#ApiLevels'>API level 24</a>
    ++        </td>
    ++      </tr>
    ++      <tr>
    ++        <td><a href='rs_object_types.html#android_rs:rs_allocation'>rs_allocation</a> rsCreateAllocation_float(<a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimX, <a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimY);
    ++</td>
    ++        <td>    Added in <a href='http://developer.android.com/guide/topics/manifest/uses-sdk-element.html#ApiLevels'>API level 24</a>
    ++        </td>
    ++      </tr>
    ++      <tr>
    ++        <td><a href='rs_object_types.html#android_rs:rs_allocation'>rs_allocation</a> rsCreateAllocation_float(<a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimX, <a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimY, <a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimZ);
    ++</td>
    ++        <td>    Added in <a href='http://developer.android.com/guide/topics/manifest/uses-sdk-element.html#ApiLevels'>API level 24</a>
    ++        </td>
    ++      </tr>
    ++      <tr>
    ++        <td><a href='rs_object_types.html#android_rs:rs_allocation'>rs_allocation</a> rsCreateAllocation_float2(<a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimX);
    ++</td>
    ++        <td>    Added in <a href='http://developer.android.com/guide/topics/manifest/uses-sdk-element.html#ApiLevels'>API level 24</a>
    ++        </td>
    ++      </tr>
    ++      <tr>
    ++        <td><a href='rs_object_types.html#android_rs:rs_allocation'>rs_allocation</a> rsCreateAllocation_float2(<a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimX, <a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimY);
    ++</td>
    ++        <td>    Added in <a href='http://developer.android.com/guide/topics/manifest/uses-sdk-element.html#ApiLevels'>API level 24</a>
    ++        </td>
    ++      </tr>
    ++      <tr>
    ++        <td><a href='rs_object_types.html#android_rs:rs_allocation'>rs_allocation</a> rsCreateAllocation_float2(<a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimX, <a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimY, <a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimZ);
    ++</td>
    ++        <td>    Added in <a href='http://developer.android.com/guide/topics/manifest/uses-sdk-element.html#ApiLevels'>API level 24</a>
    ++        </td>
    ++      </tr>
    ++      <tr>
    ++        <td><a href='rs_object_types.html#android_rs:rs_allocation'>rs_allocation</a> rsCreateAllocation_float3(<a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimX);
    ++</td>
    ++        <td>    Added in <a href='http://developer.android.com/guide/topics/manifest/uses-sdk-element.html#ApiLevels'>API level 24</a>
    ++        </td>
    ++      </tr>
    ++      <tr>
    ++        <td><a href='rs_object_types.html#android_rs:rs_allocation'>rs_allocation</a> rsCreateAllocation_float3(<a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimX, <a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimY);
    ++</td>
    ++        <td>    Added in <a href='http://developer.android.com/guide/topics/manifest/uses-sdk-element.html#ApiLevels'>API level 24</a>
    ++        </td>
    ++      </tr>
    ++      <tr>
    ++        <td><a href='rs_object_types.html#android_rs:rs_allocation'>rs_allocation</a> rsCreateAllocation_float3(<a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimX, <a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimY, <a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimZ);
    ++</td>
    ++        <td>    Added in <a href='http://developer.android.com/guide/topics/manifest/uses-sdk-element.html#ApiLevels'>API level 24</a>
    ++        </td>
    ++      </tr>
    ++      <tr>
    ++        <td><a href='rs_object_types.html#android_rs:rs_allocation'>rs_allocation</a> rsCreateAllocation_float4(<a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimX);
    ++</td>
    ++        <td>    Added in <a href='http://developer.android.com/guide/topics/manifest/uses-sdk-element.html#ApiLevels'>API level 24</a>
    ++        </td>
    ++      </tr>
    ++      <tr>
    ++        <td><a href='rs_object_types.html#android_rs:rs_allocation'>rs_allocation</a> rsCreateAllocation_float4(<a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimX, <a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimY);
    ++</td>
    ++        <td>    Added in <a href='http://developer.android.com/guide/topics/manifest/uses-sdk-element.html#ApiLevels'>API level 24</a>
    ++        </td>
    ++      </tr>
    ++      <tr>
    ++        <td><a href='rs_object_types.html#android_rs:rs_allocation'>rs_allocation</a> rsCreateAllocation_float4(<a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimX, <a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimY, <a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimZ);
    ++</td>
    ++        <td>    Added in <a href='http://developer.android.com/guide/topics/manifest/uses-sdk-element.html#ApiLevels'>API level 24</a>
    ++        </td>
    ++      </tr>
    ++      <tr>
    ++        <td><a href='rs_object_types.html#android_rs:rs_allocation'>rs_allocation</a> rsCreateAllocation_half(<a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimX);
    ++</td>
    ++        <td>    Added in <a href='http://developer.android.com/guide/topics/manifest/uses-sdk-element.html#ApiLevels'>API level 24</a>
    ++        </td>
    ++      </tr>
    ++      <tr>
    ++        <td><a href='rs_object_types.html#android_rs:rs_allocation'>rs_allocation</a> rsCreateAllocation_half(<a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimX, <a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimY);
    ++</td>
    ++        <td>    Added in <a href='http://developer.android.com/guide/topics/manifest/uses-sdk-element.html#ApiLevels'>API level 24</a>
    ++        </td>
    ++      </tr>
    ++      <tr>
    ++        <td><a href='rs_object_types.html#android_rs:rs_allocation'>rs_allocation</a> rsCreateAllocation_half(<a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimX, <a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimY, <a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimZ);
    ++</td>
    ++        <td>    Added in <a href='http://developer.android.com/guide/topics/manifest/uses-sdk-element.html#ApiLevels'>API level 24</a>
    ++        </td>
    ++      </tr>
    ++      <tr>
    ++        <td><a href='rs_object_types.html#android_rs:rs_allocation'>rs_allocation</a> rsCreateAllocation_half2(<a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimX);
    ++</td>
    ++        <td>    Added in <a href='http://developer.android.com/guide/topics/manifest/uses-sdk-element.html#ApiLevels'>API level 24</a>
    ++        </td>
    ++      </tr>
    ++      <tr>
    ++        <td><a href='rs_object_types.html#android_rs:rs_allocation'>rs_allocation</a> rsCreateAllocation_half2(<a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimX, <a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimY);
    ++</td>
    ++        <td>    Added in <a href='http://developer.android.com/guide/topics/manifest/uses-sdk-element.html#ApiLevels'>API level 24</a>
    ++        </td>
    ++      </tr>
    ++      <tr>
    ++        <td><a href='rs_object_types.html#android_rs:rs_allocation'>rs_allocation</a> rsCreateAllocation_half2(<a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimX, <a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimY, <a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimZ);
    ++</td>
    ++        <td>    Added in <a href='http://developer.android.com/guide/topics/manifest/uses-sdk-element.html#ApiLevels'>API level 24</a>
    ++        </td>
    ++      </tr>
    ++      <tr>
    ++        <td><a href='rs_object_types.html#android_rs:rs_allocation'>rs_allocation</a> rsCreateAllocation_half3(<a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimX);
    ++</td>
    ++        <td>    Added in <a href='http://developer.android.com/guide/topics/manifest/uses-sdk-element.html#ApiLevels'>API level 24</a>
    ++        </td>
    ++      </tr>
    ++      <tr>
    ++        <td><a href='rs_object_types.html#android_rs:rs_allocation'>rs_allocation</a> rsCreateAllocation_half3(<a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimX, <a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimY);
    ++</td>
    ++        <td>    Added in <a href='http://developer.android.com/guide/topics/manifest/uses-sdk-element.html#ApiLevels'>API level 24</a>
    ++        </td>
    ++      </tr>
    ++      <tr>
    ++        <td><a href='rs_object_types.html#android_rs:rs_allocation'>rs_allocation</a> rsCreateAllocation_half3(<a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimX, <a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimY, <a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimZ);
    ++</td>
    ++        <td>    Added in <a href='http://developer.android.com/guide/topics/manifest/uses-sdk-element.html#ApiLevels'>API level 24</a>
    ++        </td>
    ++      </tr>
    ++      <tr>
    ++        <td><a href='rs_object_types.html#android_rs:rs_allocation'>rs_allocation</a> rsCreateAllocation_half4(<a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimX);
    ++</td>
    ++        <td>    Added in <a href='http://developer.android.com/guide/topics/manifest/uses-sdk-element.html#ApiLevels'>API level 24</a>
    ++        </td>
    ++      </tr>
    ++      <tr>
    ++        <td><a href='rs_object_types.html#android_rs:rs_allocation'>rs_allocation</a> rsCreateAllocation_half4(<a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimX, <a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimY);
    ++</td>
    ++        <td>    Added in <a href='http://developer.android.com/guide/topics/manifest/uses-sdk-element.html#ApiLevels'>API level 24</a>
    ++        </td>
    ++      </tr>
    ++      <tr>
    ++        <td><a href='rs_object_types.html#android_rs:rs_allocation'>rs_allocation</a> rsCreateAllocation_half4(<a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimX, <a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimY, <a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimZ);
    ++</td>
    ++        <td>    Added in <a href='http://developer.android.com/guide/topics/manifest/uses-sdk-element.html#ApiLevels'>API level 24</a>
    ++        </td>
    ++      </tr>
    ++      <tr>
    ++        <td><a href='rs_object_types.html#android_rs:rs_allocation'>rs_allocation</a> rsCreateAllocation_int(<a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimX);
    ++</td>
    ++        <td>    Added in <a href='http://developer.android.com/guide/topics/manifest/uses-sdk-element.html#ApiLevels'>API level 24</a>
    ++        </td>
    ++      </tr>
    ++      <tr>
    ++        <td><a href='rs_object_types.html#android_rs:rs_allocation'>rs_allocation</a> rsCreateAllocation_int(<a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimX, <a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimY);
    ++</td>
    ++        <td>    Added in <a href='http://developer.android.com/guide/topics/manifest/uses-sdk-element.html#ApiLevels'>API level 24</a>
    ++        </td>
    ++      </tr>
    ++      <tr>
    ++        <td><a href='rs_object_types.html#android_rs:rs_allocation'>rs_allocation</a> rsCreateAllocation_int(<a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimX, <a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimY, <a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimZ);
    ++</td>
    ++        <td>    Added in <a href='http://developer.android.com/guide/topics/manifest/uses-sdk-element.html#ApiLevels'>API level 24</a>
    ++        </td>
    ++      </tr>
    ++      <tr>
    ++        <td><a href='rs_object_types.html#android_rs:rs_allocation'>rs_allocation</a> rsCreateAllocation_int2(<a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimX);
    ++</td>
    ++        <td>    Added in <a href='http://developer.android.com/guide/topics/manifest/uses-sdk-element.html#ApiLevels'>API level 24</a>
    ++        </td>
    ++      </tr>
    ++      <tr>
    ++        <td><a href='rs_object_types.html#android_rs:rs_allocation'>rs_allocation</a> rsCreateAllocation_int2(<a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimX, <a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimY);
    ++</td>
    ++        <td>    Added in <a href='http://developer.android.com/guide/topics/manifest/uses-sdk-element.html#ApiLevels'>API level 24</a>
    ++        </td>
    ++      </tr>
    ++      <tr>
    ++        <td><a href='rs_object_types.html#android_rs:rs_allocation'>rs_allocation</a> rsCreateAllocation_int2(<a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimX, <a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimY, <a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimZ);
    ++</td>
    ++        <td>    Added in <a href='http://developer.android.com/guide/topics/manifest/uses-sdk-element.html#ApiLevels'>API level 24</a>
    ++        </td>
    ++      </tr>
    ++      <tr>
    ++        <td><a href='rs_object_types.html#android_rs:rs_allocation'>rs_allocation</a> rsCreateAllocation_int3(<a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimX);
    ++</td>
    ++        <td>    Added in <a href='http://developer.android.com/guide/topics/manifest/uses-sdk-element.html#ApiLevels'>API level 24</a>
    ++        </td>
    ++      </tr>
    ++      <tr>
    ++        <td><a href='rs_object_types.html#android_rs:rs_allocation'>rs_allocation</a> rsCreateAllocation_int3(<a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimX, <a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimY);
    ++</td>
    ++        <td>    Added in <a href='http://developer.android.com/guide/topics/manifest/uses-sdk-element.html#ApiLevels'>API level 24</a>
    ++        </td>
    ++      </tr>
    ++      <tr>
    ++        <td><a href='rs_object_types.html#android_rs:rs_allocation'>rs_allocation</a> rsCreateAllocation_int3(<a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimX, <a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimY, <a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimZ);
    ++</td>
    ++        <td>    Added in <a href='http://developer.android.com/guide/topics/manifest/uses-sdk-element.html#ApiLevels'>API level 24</a>
    ++        </td>
    ++      </tr>
    ++      <tr>
    ++        <td><a href='rs_object_types.html#android_rs:rs_allocation'>rs_allocation</a> rsCreateAllocation_int4(<a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimX);
    ++</td>
    ++        <td>    Added in <a href='http://developer.android.com/guide/topics/manifest/uses-sdk-element.html#ApiLevels'>API level 24</a>
    ++        </td>
    ++      </tr>
    ++      <tr>
    ++        <td><a href='rs_object_types.html#android_rs:rs_allocation'>rs_allocation</a> rsCreateAllocation_int4(<a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimX, <a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimY);
    ++</td>
    ++        <td>    Added in <a href='http://developer.android.com/guide/topics/manifest/uses-sdk-element.html#ApiLevels'>API level 24</a>
    ++        </td>
    ++      </tr>
    ++      <tr>
    ++        <td><a href='rs_object_types.html#android_rs:rs_allocation'>rs_allocation</a> rsCreateAllocation_int4(<a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimX, <a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimY, <a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimZ);
    ++</td>
    ++        <td>    Added in <a href='http://developer.android.com/guide/topics/manifest/uses-sdk-element.html#ApiLevels'>API level 24</a>
    ++        </td>
    ++      </tr>
    ++      <tr>
    ++        <td><a href='rs_object_types.html#android_rs:rs_allocation'>rs_allocation</a> rsCreateAllocation_long(<a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimX);
    ++</td>
    ++        <td>    Added in <a href='http://developer.android.com/guide/topics/manifest/uses-sdk-element.html#ApiLevels'>API level 24</a>
    ++        </td>
    ++      </tr>
    ++      <tr>
    ++        <td><a href='rs_object_types.html#android_rs:rs_allocation'>rs_allocation</a> rsCreateAllocation_long(<a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimX, <a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimY);
    ++</td>
    ++        <td>    Added in <a href='http://developer.android.com/guide/topics/manifest/uses-sdk-element.html#ApiLevels'>API level 24</a>
    ++        </td>
    ++      </tr>
    ++      <tr>
    ++        <td><a href='rs_object_types.html#android_rs:rs_allocation'>rs_allocation</a> rsCreateAllocation_long(<a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimX, <a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimY, <a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimZ);
    ++</td>
    ++        <td>    Added in <a href='http://developer.android.com/guide/topics/manifest/uses-sdk-element.html#ApiLevels'>API level 24</a>
    ++        </td>
    ++      </tr>
    ++      <tr>
    ++        <td><a href='rs_object_types.html#android_rs:rs_allocation'>rs_allocation</a> rsCreateAllocation_long2(<a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimX);
    ++</td>
    ++        <td>    Added in <a href='http://developer.android.com/guide/topics/manifest/uses-sdk-element.html#ApiLevels'>API level 24</a>
    ++        </td>
    ++      </tr>
    ++      <tr>
    ++        <td><a href='rs_object_types.html#android_rs:rs_allocation'>rs_allocation</a> rsCreateAllocation_long2(<a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimX, <a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimY);
    ++</td>
    ++        <td>    Added in <a href='http://developer.android.com/guide/topics/manifest/uses-sdk-element.html#ApiLevels'>API level 24</a>
    ++        </td>
    ++      </tr>
    ++      <tr>
    ++        <td><a href='rs_object_types.html#android_rs:rs_allocation'>rs_allocation</a> rsCreateAllocation_long2(<a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimX, <a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimY, <a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimZ);
    ++</td>
    ++        <td>    Added in <a href='http://developer.android.com/guide/topics/manifest/uses-sdk-element.html#ApiLevels'>API level 24</a>
    ++        </td>
    ++      </tr>
    ++      <tr>
    ++        <td><a href='rs_object_types.html#android_rs:rs_allocation'>rs_allocation</a> rsCreateAllocation_long3(<a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimX);
    ++</td>
    ++        <td>    Added in <a href='http://developer.android.com/guide/topics/manifest/uses-sdk-element.html#ApiLevels'>API level 24</a>
    ++        </td>
    ++      </tr>
    ++      <tr>
    ++        <td><a href='rs_object_types.html#android_rs:rs_allocation'>rs_allocation</a> rsCreateAllocation_long3(<a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimX, <a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimY);
    ++</td>
    ++        <td>    Added in <a href='http://developer.android.com/guide/topics/manifest/uses-sdk-element.html#ApiLevels'>API level 24</a>
    ++        </td>
    ++      </tr>
    ++      <tr>
    ++        <td><a href='rs_object_types.html#android_rs:rs_allocation'>rs_allocation</a> rsCreateAllocation_long3(<a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimX, <a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimY, <a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimZ);
    ++</td>
    ++        <td>    Added in <a href='http://developer.android.com/guide/topics/manifest/uses-sdk-element.html#ApiLevels'>API level 24</a>
    ++        </td>
    ++      </tr>
    ++      <tr>
    ++        <td><a href='rs_object_types.html#android_rs:rs_allocation'>rs_allocation</a> rsCreateAllocation_long4(<a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimX);
    ++</td>
    ++        <td>    Added in <a href='http://developer.android.com/guide/topics/manifest/uses-sdk-element.html#ApiLevels'>API level 24</a>
    ++        </td>
    ++      </tr>
    ++      <tr>
    ++        <td><a href='rs_object_types.html#android_rs:rs_allocation'>rs_allocation</a> rsCreateAllocation_long4(<a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimX, <a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimY);
    ++</td>
    ++        <td>    Added in <a href='http://developer.android.com/guide/topics/manifest/uses-sdk-element.html#ApiLevels'>API level 24</a>
    ++        </td>
    ++      </tr>
    ++      <tr>
    ++        <td><a href='rs_object_types.html#android_rs:rs_allocation'>rs_allocation</a> rsCreateAllocation_long4(<a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimX, <a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimY, <a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimZ);
    ++</td>
    ++        <td>    Added in <a href='http://developer.android.com/guide/topics/manifest/uses-sdk-element.html#ApiLevels'>API level 24</a>
    ++        </td>
    ++      </tr>
    ++      <tr>
    ++        <td><a href='rs_object_types.html#android_rs:rs_allocation'>rs_allocation</a> rsCreateAllocation_short(<a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimX);
    ++</td>
    ++        <td>    Added in <a href='http://developer.android.com/guide/topics/manifest/uses-sdk-element.html#ApiLevels'>API level 24</a>
    ++        </td>
    ++      </tr>
    ++      <tr>
    ++        <td><a href='rs_object_types.html#android_rs:rs_allocation'>rs_allocation</a> rsCreateAllocation_short(<a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimX, <a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimY);
    ++</td>
    ++        <td>    Added in <a href='http://developer.android.com/guide/topics/manifest/uses-sdk-element.html#ApiLevels'>API level 24</a>
    ++        </td>
    ++      </tr>
    ++      <tr>
    ++        <td><a href='rs_object_types.html#android_rs:rs_allocation'>rs_allocation</a> rsCreateAllocation_short(<a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimX, <a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimY, <a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimZ);
    ++</td>
    ++        <td>    Added in <a href='http://developer.android.com/guide/topics/manifest/uses-sdk-element.html#ApiLevels'>API level 24</a>
    ++        </td>
    ++      </tr>
    ++      <tr>
    ++        <td><a href='rs_object_types.html#android_rs:rs_allocation'>rs_allocation</a> rsCreateAllocation_short2(<a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimX);
    ++</td>
    ++        <td>    Added in <a href='http://developer.android.com/guide/topics/manifest/uses-sdk-element.html#ApiLevels'>API level 24</a>
    ++        </td>
    ++      </tr>
    ++      <tr>
    ++        <td><a href='rs_object_types.html#android_rs:rs_allocation'>rs_allocation</a> rsCreateAllocation_short2(<a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimX, <a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimY);
    ++</td>
    ++        <td>    Added in <a href='http://developer.android.com/guide/topics/manifest/uses-sdk-element.html#ApiLevels'>API level 24</a>
    ++        </td>
    ++      </tr>
    ++      <tr>
    ++        <td><a href='rs_object_types.html#android_rs:rs_allocation'>rs_allocation</a> rsCreateAllocation_short2(<a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimX, <a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimY, <a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimZ);
    ++</td>
    ++        <td>    Added in <a href='http://developer.android.com/guide/topics/manifest/uses-sdk-element.html#ApiLevels'>API level 24</a>
    ++        </td>
    ++      </tr>
    ++      <tr>
    ++        <td><a href='rs_object_types.html#android_rs:rs_allocation'>rs_allocation</a> rsCreateAllocation_short3(<a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimX);
    ++</td>
    ++        <td>    Added in <a href='http://developer.android.com/guide/topics/manifest/uses-sdk-element.html#ApiLevels'>API level 24</a>
    ++        </td>
    ++      </tr>
    ++      <tr>
    ++        <td><a href='rs_object_types.html#android_rs:rs_allocation'>rs_allocation</a> rsCreateAllocation_short3(<a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimX, <a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimY);
    ++</td>
    ++        <td>    Added in <a href='http://developer.android.com/guide/topics/manifest/uses-sdk-element.html#ApiLevels'>API level 24</a>
    ++        </td>
    ++      </tr>
    ++      <tr>
    ++        <td><a href='rs_object_types.html#android_rs:rs_allocation'>rs_allocation</a> rsCreateAllocation_short3(<a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimX, <a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimY, <a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimZ);
    ++</td>
    ++        <td>    Added in <a href='http://developer.android.com/guide/topics/manifest/uses-sdk-element.html#ApiLevels'>API level 24</a>
    ++        </td>
    ++      </tr>
    ++      <tr>
    ++        <td><a href='rs_object_types.html#android_rs:rs_allocation'>rs_allocation</a> rsCreateAllocation_short4(<a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimX);
    ++</td>
    ++        <td>    Added in <a href='http://developer.android.com/guide/topics/manifest/uses-sdk-element.html#ApiLevels'>API level 24</a>
    ++        </td>
    ++      </tr>
    ++      <tr>
    ++        <td><a href='rs_object_types.html#android_rs:rs_allocation'>rs_allocation</a> rsCreateAllocation_short4(<a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimX, <a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimY);
    ++</td>
    ++        <td>    Added in <a href='http://developer.android.com/guide/topics/manifest/uses-sdk-element.html#ApiLevels'>API level 24</a>
    ++        </td>
    ++      </tr>
    ++      <tr>
    ++        <td><a href='rs_object_types.html#android_rs:rs_allocation'>rs_allocation</a> rsCreateAllocation_short4(<a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimX, <a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimY, <a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimZ);
    ++</td>
    ++        <td>    Added in <a href='http://developer.android.com/guide/topics/manifest/uses-sdk-element.html#ApiLevels'>API level 24</a>
    ++        </td>
    ++      </tr>
    ++      <tr>
    ++        <td><a href='rs_object_types.html#android_rs:rs_allocation'>rs_allocation</a> rsCreateAllocation_uchar(<a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimX);
    ++</td>
    ++        <td>    Added in <a href='http://developer.android.com/guide/topics/manifest/uses-sdk-element.html#ApiLevels'>API level 24</a>
    ++        </td>
    ++      </tr>
    ++      <tr>
    ++        <td><a href='rs_object_types.html#android_rs:rs_allocation'>rs_allocation</a> rsCreateAllocation_uchar(<a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimX, <a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimY);
    ++</td>
    ++        <td>    Added in <a href='http://developer.android.com/guide/topics/manifest/uses-sdk-element.html#ApiLevels'>API level 24</a>
    ++        </td>
    ++      </tr>
    ++      <tr>
    ++        <td><a href='rs_object_types.html#android_rs:rs_allocation'>rs_allocation</a> rsCreateAllocation_uchar(<a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimX, <a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimY, <a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimZ);
    ++</td>
    ++        <td>    Added in <a href='http://developer.android.com/guide/topics/manifest/uses-sdk-element.html#ApiLevels'>API level 24</a>
    ++        </td>
    ++      </tr>
    ++      <tr>
    ++        <td><a href='rs_object_types.html#android_rs:rs_allocation'>rs_allocation</a> rsCreateAllocation_uchar2(<a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimX);
    ++</td>
    ++        <td>    Added in <a href='http://developer.android.com/guide/topics/manifest/uses-sdk-element.html#ApiLevels'>API level 24</a>
    ++        </td>
    ++      </tr>
    ++      <tr>
    ++        <td><a href='rs_object_types.html#android_rs:rs_allocation'>rs_allocation</a> rsCreateAllocation_uchar2(<a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimX, <a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimY);
    ++</td>
    ++        <td>    Added in <a href='http://developer.android.com/guide/topics/manifest/uses-sdk-element.html#ApiLevels'>API level 24</a>
    ++        </td>
    ++      </tr>
    ++      <tr>
    ++        <td><a href='rs_object_types.html#android_rs:rs_allocation'>rs_allocation</a> rsCreateAllocation_uchar2(<a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimX, <a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimY, <a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimZ);
    ++</td>
    ++        <td>    Added in <a href='http://developer.android.com/guide/topics/manifest/uses-sdk-element.html#ApiLevels'>API level 24</a>
    ++        </td>
    ++      </tr>
    ++      <tr>
    ++        <td><a href='rs_object_types.html#android_rs:rs_allocation'>rs_allocation</a> rsCreateAllocation_uchar3(<a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimX);
    ++</td>
    ++        <td>    Added in <a href='http://developer.android.com/guide/topics/manifest/uses-sdk-element.html#ApiLevels'>API level 24</a>
    ++        </td>
    ++      </tr>
    ++      <tr>
    ++        <td><a href='rs_object_types.html#android_rs:rs_allocation'>rs_allocation</a> rsCreateAllocation_uchar3(<a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimX, <a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimY);
    ++</td>
    ++        <td>    Added in <a href='http://developer.android.com/guide/topics/manifest/uses-sdk-element.html#ApiLevels'>API level 24</a>
    ++        </td>
    ++      </tr>
    ++      <tr>
    ++        <td><a href='rs_object_types.html#android_rs:rs_allocation'>rs_allocation</a> rsCreateAllocation_uchar3(<a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimX, <a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimY, <a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimZ);
    ++</td>
    ++        <td>    Added in <a href='http://developer.android.com/guide/topics/manifest/uses-sdk-element.html#ApiLevels'>API level 24</a>
    ++        </td>
    ++      </tr>
    ++      <tr>
    ++        <td><a href='rs_object_types.html#android_rs:rs_allocation'>rs_allocation</a> rsCreateAllocation_uchar4(<a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimX);
    ++</td>
    ++        <td>    Added in <a href='http://developer.android.com/guide/topics/manifest/uses-sdk-element.html#ApiLevels'>API level 24</a>
    ++        </td>
    ++      </tr>
    ++      <tr>
    ++        <td><a href='rs_object_types.html#android_rs:rs_allocation'>rs_allocation</a> rsCreateAllocation_uchar4(<a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimX, <a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimY);
    ++</td>
    ++        <td>    Added in <a href='http://developer.android.com/guide/topics/manifest/uses-sdk-element.html#ApiLevels'>API level 24</a>
    ++        </td>
    ++      </tr>
    ++      <tr>
    ++        <td><a href='rs_object_types.html#android_rs:rs_allocation'>rs_allocation</a> rsCreateAllocation_uchar4(<a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimX, <a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimY, <a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimZ);
    ++</td>
    ++        <td>    Added in <a href='http://developer.android.com/guide/topics/manifest/uses-sdk-element.html#ApiLevels'>API level 24</a>
    ++        </td>
    ++      </tr>
    ++      <tr>
    ++        <td><a href='rs_object_types.html#android_rs:rs_allocation'>rs_allocation</a> rsCreateAllocation_uint(<a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimX);
    ++</td>
    ++        <td>    Added in <a href='http://developer.android.com/guide/topics/manifest/uses-sdk-element.html#ApiLevels'>API level 24</a>
    ++        </td>
    ++      </tr>
    ++      <tr>
    ++        <td><a href='rs_object_types.html#android_rs:rs_allocation'>rs_allocation</a> rsCreateAllocation_uint(<a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimX, <a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimY);
    ++</td>
    ++        <td>    Added in <a href='http://developer.android.com/guide/topics/manifest/uses-sdk-element.html#ApiLevels'>API level 24</a>
    ++        </td>
    ++      </tr>
    ++      <tr>
    ++        <td><a href='rs_object_types.html#android_rs:rs_allocation'>rs_allocation</a> rsCreateAllocation_uint(<a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimX, <a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimY, <a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimZ);
    ++</td>
    ++        <td>    Added in <a href='http://developer.android.com/guide/topics/manifest/uses-sdk-element.html#ApiLevels'>API level 24</a>
    ++        </td>
    ++      </tr>
    ++      <tr>
    ++        <td><a href='rs_object_types.html#android_rs:rs_allocation'>rs_allocation</a> rsCreateAllocation_uint2(<a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimX);
    ++</td>
    ++        <td>    Added in <a href='http://developer.android.com/guide/topics/manifest/uses-sdk-element.html#ApiLevels'>API level 24</a>
    ++        </td>
    ++      </tr>
    ++      <tr>
    ++        <td><a href='rs_object_types.html#android_rs:rs_allocation'>rs_allocation</a> rsCreateAllocation_uint2(<a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimX, <a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimY);
    ++</td>
    ++        <td>    Added in <a href='http://developer.android.com/guide/topics/manifest/uses-sdk-element.html#ApiLevels'>API level 24</a>
    ++        </td>
    ++      </tr>
    ++      <tr>
    ++        <td><a href='rs_object_types.html#android_rs:rs_allocation'>rs_allocation</a> rsCreateAllocation_uint2(<a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimX, <a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimY, <a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimZ);
    ++</td>
    ++        <td>    Added in <a href='http://developer.android.com/guide/topics/manifest/uses-sdk-element.html#ApiLevels'>API level 24</a>
    ++        </td>
    ++      </tr>
    ++      <tr>
    ++        <td><a href='rs_object_types.html#android_rs:rs_allocation'>rs_allocation</a> rsCreateAllocation_uint3(<a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimX);
    ++</td>
    ++        <td>    Added in <a href='http://developer.android.com/guide/topics/manifest/uses-sdk-element.html#ApiLevels'>API level 24</a>
    ++        </td>
    ++      </tr>
    ++      <tr>
    ++        <td><a href='rs_object_types.html#android_rs:rs_allocation'>rs_allocation</a> rsCreateAllocation_uint3(<a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimX, <a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimY);
    ++</td>
    ++        <td>    Added in <a href='http://developer.android.com/guide/topics/manifest/uses-sdk-element.html#ApiLevels'>API level 24</a>
    ++        </td>
    ++      </tr>
    ++      <tr>
    ++        <td><a href='rs_object_types.html#android_rs:rs_allocation'>rs_allocation</a> rsCreateAllocation_uint3(<a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimX, <a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimY, <a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimZ);
    ++</td>
    ++        <td>    Added in <a href='http://developer.android.com/guide/topics/manifest/uses-sdk-element.html#ApiLevels'>API level 24</a>
    ++        </td>
    ++      </tr>
    ++      <tr>
    ++        <td><a href='rs_object_types.html#android_rs:rs_allocation'>rs_allocation</a> rsCreateAllocation_uint4(<a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimX);
    ++</td>
    ++        <td>    Added in <a href='http://developer.android.com/guide/topics/manifest/uses-sdk-element.html#ApiLevels'>API level 24</a>
    ++        </td>
    ++      </tr>
    ++      <tr>
    ++        <td><a href='rs_object_types.html#android_rs:rs_allocation'>rs_allocation</a> rsCreateAllocation_uint4(<a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimX, <a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimY);
    ++</td>
    ++        <td>    Added in <a href='http://developer.android.com/guide/topics/manifest/uses-sdk-element.html#ApiLevels'>API level 24</a>
    ++        </td>
    ++      </tr>
    ++      <tr>
    ++        <td><a href='rs_object_types.html#android_rs:rs_allocation'>rs_allocation</a> rsCreateAllocation_uint4(<a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimX, <a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimY, <a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimZ);
    ++</td>
    ++        <td>    Added in <a href='http://developer.android.com/guide/topics/manifest/uses-sdk-element.html#ApiLevels'>API level 24</a>
    ++        </td>
    ++      </tr>
    ++      <tr>
    ++        <td><a href='rs_object_types.html#android_rs:rs_allocation'>rs_allocation</a> rsCreateAllocation_ulong(<a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimX);
    ++</td>
    ++        <td>    Added in <a href='http://developer.android.com/guide/topics/manifest/uses-sdk-element.html#ApiLevels'>API level 24</a>
    ++        </td>
    ++      </tr>
    ++      <tr>
    ++        <td><a href='rs_object_types.html#android_rs:rs_allocation'>rs_allocation</a> rsCreateAllocation_ulong(<a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimX, <a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimY);
    ++</td>
    ++        <td>    Added in <a href='http://developer.android.com/guide/topics/manifest/uses-sdk-element.html#ApiLevels'>API level 24</a>
    ++        </td>
    ++      </tr>
    ++      <tr>
    ++        <td><a href='rs_object_types.html#android_rs:rs_allocation'>rs_allocation</a> rsCreateAllocation_ulong(<a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimX, <a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimY, <a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimZ);
    ++</td>
    ++        <td>    Added in <a href='http://developer.android.com/guide/topics/manifest/uses-sdk-element.html#ApiLevels'>API level 24</a>
    ++        </td>
    ++      </tr>
    ++      <tr>
    ++        <td><a href='rs_object_types.html#android_rs:rs_allocation'>rs_allocation</a> rsCreateAllocation_ulong2(<a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimX);
    ++</td>
    ++        <td>    Added in <a href='http://developer.android.com/guide/topics/manifest/uses-sdk-element.html#ApiLevels'>API level 24</a>
    ++        </td>
    ++      </tr>
    ++      <tr>
    ++        <td><a href='rs_object_types.html#android_rs:rs_allocation'>rs_allocation</a> rsCreateAllocation_ulong2(<a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimX, <a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimY);
    ++</td>
    ++        <td>    Added in <a href='http://developer.android.com/guide/topics/manifest/uses-sdk-element.html#ApiLevels'>API level 24</a>
    ++        </td>
    ++      </tr>
    ++      <tr>
    ++        <td><a href='rs_object_types.html#android_rs:rs_allocation'>rs_allocation</a> rsCreateAllocation_ulong2(<a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimX, <a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimY, <a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimZ);
    ++</td>
    ++        <td>    Added in <a href='http://developer.android.com/guide/topics/manifest/uses-sdk-element.html#ApiLevels'>API level 24</a>
    ++        </td>
    ++      </tr>
    ++      <tr>
    ++        <td><a href='rs_object_types.html#android_rs:rs_allocation'>rs_allocation</a> rsCreateAllocation_ulong3(<a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimX);
    ++</td>
    ++        <td>    Added in <a href='http://developer.android.com/guide/topics/manifest/uses-sdk-element.html#ApiLevels'>API level 24</a>
    ++        </td>
    ++      </tr>
    ++      <tr>
    ++        <td><a href='rs_object_types.html#android_rs:rs_allocation'>rs_allocation</a> rsCreateAllocation_ulong3(<a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimX, <a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimY);
    ++</td>
    ++        <td>    Added in <a href='http://developer.android.com/guide/topics/manifest/uses-sdk-element.html#ApiLevels'>API level 24</a>
    ++        </td>
    ++      </tr>
    ++      <tr>
    ++        <td><a href='rs_object_types.html#android_rs:rs_allocation'>rs_allocation</a> rsCreateAllocation_ulong3(<a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimX, <a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimY, <a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimZ);
    ++</td>
    ++        <td>    Added in <a href='http://developer.android.com/guide/topics/manifest/uses-sdk-element.html#ApiLevels'>API level 24</a>
    ++        </td>
    ++      </tr>
    ++      <tr>
    ++        <td><a href='rs_object_types.html#android_rs:rs_allocation'>rs_allocation</a> rsCreateAllocation_ulong4(<a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimX);
    ++</td>
    ++        <td>    Added in <a href='http://developer.android.com/guide/topics/manifest/uses-sdk-element.html#ApiLevels'>API level 24</a>
    ++        </td>
    ++      </tr>
    ++      <tr>
    ++        <td><a href='rs_object_types.html#android_rs:rs_allocation'>rs_allocation</a> rsCreateAllocation_ulong4(<a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimX, <a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimY);
    ++</td>
    ++        <td>    Added in <a href='http://developer.android.com/guide/topics/manifest/uses-sdk-element.html#ApiLevels'>API level 24</a>
    ++        </td>
    ++      </tr>
    ++      <tr>
    ++        <td><a href='rs_object_types.html#android_rs:rs_allocation'>rs_allocation</a> rsCreateAllocation_ulong4(<a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimX, <a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimY, <a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimZ);
    ++</td>
    ++        <td>    Added in <a href='http://developer.android.com/guide/topics/manifest/uses-sdk-element.html#ApiLevels'>API level 24</a>
    ++        </td>
    ++      </tr>
    ++      <tr>
    ++        <td><a href='rs_object_types.html#android_rs:rs_allocation'>rs_allocation</a> rsCreateAllocation_ushort(<a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimX);
    ++</td>
    ++        <td>    Added in <a href='http://developer.android.com/guide/topics/manifest/uses-sdk-element.html#ApiLevels'>API level 24</a>
    ++        </td>
    ++      </tr>
    ++      <tr>
    ++        <td><a href='rs_object_types.html#android_rs:rs_allocation'>rs_allocation</a> rsCreateAllocation_ushort(<a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimX, <a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimY);
    ++</td>
    ++        <td>    Added in <a href='http://developer.android.com/guide/topics/manifest/uses-sdk-element.html#ApiLevels'>API level 24</a>
    ++        </td>
    ++      </tr>
    ++      <tr>
    ++        <td><a href='rs_object_types.html#android_rs:rs_allocation'>rs_allocation</a> rsCreateAllocation_ushort(<a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimX, <a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimY, <a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimZ);
    ++</td>
    ++        <td>    Added in <a href='http://developer.android.com/guide/topics/manifest/uses-sdk-element.html#ApiLevels'>API level 24</a>
    ++        </td>
    ++      </tr>
    ++      <tr>
    ++        <td><a href='rs_object_types.html#android_rs:rs_allocation'>rs_allocation</a> rsCreateAllocation_ushort2(<a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimX);
    ++</td>
    ++        <td>    Added in <a href='http://developer.android.com/guide/topics/manifest/uses-sdk-element.html#ApiLevels'>API level 24</a>
    ++        </td>
    ++      </tr>
    ++      <tr>
    ++        <td><a href='rs_object_types.html#android_rs:rs_allocation'>rs_allocation</a> rsCreateAllocation_ushort2(<a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimX, <a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimY);
    ++</td>
    ++        <td>    Added in <a href='http://developer.android.com/guide/topics/manifest/uses-sdk-element.html#ApiLevels'>API level 24</a>
    ++        </td>
    ++      </tr>
    ++      <tr>
    ++        <td><a href='rs_object_types.html#android_rs:rs_allocation'>rs_allocation</a> rsCreateAllocation_ushort2(<a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimX, <a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimY, <a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimZ);
    ++</td>
    ++        <td>    Added in <a href='http://developer.android.com/guide/topics/manifest/uses-sdk-element.html#ApiLevels'>API level 24</a>
    ++        </td>
    ++      </tr>
    ++      <tr>
    ++        <td><a href='rs_object_types.html#android_rs:rs_allocation'>rs_allocation</a> rsCreateAllocation_ushort3(<a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimX);
    ++</td>
    ++        <td>    Added in <a href='http://developer.android.com/guide/topics/manifest/uses-sdk-element.html#ApiLevels'>API level 24</a>
    ++        </td>
    ++      </tr>
    ++      <tr>
    ++        <td><a href='rs_object_types.html#android_rs:rs_allocation'>rs_allocation</a> rsCreateAllocation_ushort3(<a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimX, <a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimY);
    ++</td>
    ++        <td>    Added in <a href='http://developer.android.com/guide/topics/manifest/uses-sdk-element.html#ApiLevels'>API level 24</a>
    ++        </td>
    ++      </tr>
    ++      <tr>
    ++        <td><a href='rs_object_types.html#android_rs:rs_allocation'>rs_allocation</a> rsCreateAllocation_ushort3(<a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimX, <a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimY, <a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimZ);
    ++</td>
    ++        <td>    Added in <a href='http://developer.android.com/guide/topics/manifest/uses-sdk-element.html#ApiLevels'>API level 24</a>
    ++        </td>
    ++      </tr>
    ++      <tr>
    ++        <td><a href='rs_object_types.html#android_rs:rs_allocation'>rs_allocation</a> rsCreateAllocation_ushort4(<a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimX);
    ++</td>
    ++        <td>    Added in <a href='http://developer.android.com/guide/topics/manifest/uses-sdk-element.html#ApiLevels'>API level 24</a>
    ++        </td>
    ++      </tr>
    ++      <tr>
    ++        <td><a href='rs_object_types.html#android_rs:rs_allocation'>rs_allocation</a> rsCreateAllocation_ushort4(<a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimX, <a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimY);
    ++</td>
    ++        <td>    Added in <a href='http://developer.android.com/guide/topics/manifest/uses-sdk-element.html#ApiLevels'>API level 24</a>
    ++        </td>
    ++      </tr>
    ++      <tr>
    ++        <td><a href='rs_object_types.html#android_rs:rs_allocation'>rs_allocation</a> rsCreateAllocation_ushort4(<a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimX, <a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimY, <a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimZ);
    ++</td>
    ++        <td>    Added in <a href='http://developer.android.com/guide/topics/manifest/uses-sdk-element.html#ApiLevels'>API level 24</a>
    ++        </td>
    ++      </tr>
    ++    </tbody></table>
    ++  </div>
    ++  <div class='jd-tagdata'>    <h5 class='jd-tagtitle'>Parameters</h5>
    ++    <table class='jd-tagtable'><tbody>
    ++    <tr><th>type</th><td>Type of the allocation</td></tr>
    ++    <tr><th>usage</th><td>How the allocation should be used. A valid value is either of the following or their combination:<br>RS_ALLOCATION_USAGE_GRAPHICS_TEXTURE,<br>RS_ALLOCATION_USAGE_SCRIPT.</td></tr>
    ++    <tr><th>mipmap</th><td>A boolean flag indicating if the allocation is mipmapped and has multiple levels of detail (LoD).</td></tr>
    ++    <tr><th>dimX</th><td>Size on dimension x. Must be non zero.</td></tr>
    ++    <tr><th>dimY</th><td>Size on dimension y. 0 for single-dimension allocations.</td></tr>
    ++    <tr><th>dimZ</th><td>Size on dimension z. 0 for single-dimension and two-dimension allocations.</td></tr>
    ++    </tbody></table>
    ++  </div>
    ++  <div class='jd-tagdata jd-tagdescr'>
    ++<p>  Creates an rs_allocation object of the given rs_type and for the specified usages.
    ++</p>
    ++
    ++<p>  RS_ALLOCATION_USAGE_SCRIPT and RS_ALLOCATION_USAGE_GRAPHICS_TEXTURE are the
    ++ only supported usage flags for Allocations created from within a RenderScript
    ++ script.
    ++</p>
    ++
    ++<p>  You can also use rsCreateAllocation_<type><width> wrapper functions to directly
    ++ create allocations of scalar and vector numerical types without creating
    ++ intermediate rs_element or rs_type objects.
    ++</p>
    ++
    ++<p>  For example, rsCreateAllocation_int4() returns an Allocation of int4 data type of
    ++ specified dimensions.
    ++</p>
    ++  </div>
    ++</div>
    ++
    ++<a name='android_rs:rsCreateElement'></a>
    ++<div class='jd-details'>
    ++  <h4 class='jd-details-title'>
    ++    <span class='sympad'>rsCreateElement</span>
    ++    <span class='normal'>: Creates an <a href={@docRoot}guide/topics/renderscript/reference/rs_object_types.html#android_rs:rs_element>rs_element</a> object of the specified data type</span>
    ++  </h4>
    ++  <div class='jd-details-descr'>
    ++    <table class='jd-tagtable'><tbody>
    ++      <tr>
    ++        <td><a href='rs_object_types.html#android_rs:rs_element'>rs_element</a> rsCreateElement(<a href='rs_object_types.html#android_rs:rs_data_type'>rs_data_type</a> data_type);
    ++</td>
    ++        <td>    Added in <a href='http://developer.android.com/guide/topics/manifest/uses-sdk-element.html#ApiLevels'>API level 24</a>
    ++        </td>
    ++      </tr>
    ++    </tbody></table>
    ++  </div>
    ++  <div class='jd-tagdata'>    <h5 class='jd-tagtitle'>Parameters</h5>
    ++    <table class='jd-tagtable'><tbody>
    ++    <tr><th>data_type</th><td>Data type of the Element</td></tr>
    ++    </tbody></table>
    ++  </div>
    ++  <div class='jd-tagdata jd-tagdescr'>
    ++<p>  Creates an rs_element object of the specified data type.  The data kind of
    ++ the element will be set to RS_KIND_USER and vector width will be set to 1,
    ++ indicating non-vector.
    ++</p>
    ++  </div>
    ++</div>
    ++
    ++<a name='android_rs:rsCreatePixelElement'></a>
    ++<div class='jd-details'>
    ++  <h4 class='jd-details-title'>
    ++    <span class='sympad'>rsCreatePixelElement</span>
    ++    <span class='normal'>: Creates an <a href={@docRoot}guide/topics/renderscript/reference/rs_object_types.html#android_rs:rs_element>rs_element</a> object of the specified data type and data kind</span>
    ++  </h4>
    ++  <div class='jd-details-descr'>
    ++    <table class='jd-tagtable'><tbody>
    ++      <tr>
    ++        <td><a href='rs_object_types.html#android_rs:rs_element'>rs_element</a> rsCreatePixelElement(<a href='rs_object_types.html#android_rs:rs_data_type'>rs_data_type</a> data_type, <a href='rs_object_types.html#android_rs:rs_data_kind'>rs_data_kind</a> data_kind);
    ++</td>
    ++        <td>    Added in <a href='http://developer.android.com/guide/topics/manifest/uses-sdk-element.html#ApiLevels'>API level 24</a>
    ++        </td>
    ++      </tr>
    ++    </tbody></table>
    ++  </div>
    ++  <div class='jd-tagdata'>    <h5 class='jd-tagtitle'>Parameters</h5>
    ++    <table class='jd-tagtable'><tbody>
    ++    <tr><th>data_type</th><td>Data type of the Element</td></tr>
    ++    <tr><th>data_kind</th><td>Data kind of the Element</td></tr>
    ++    </tbody></table>
    ++  </div>
    ++  <div class='jd-tagdata jd-tagdescr'>
    ++<p>  Creates an rs_element object of the specified data type and data kind. The
    ++ vector width of the rs_element object will be set to 1, indicating non-vector.
    ++</p>
    ++  </div>
    ++</div>
    ++
    ++<a name='android_rs:rsCreateType'></a>
    ++<div class='jd-details'>
    ++  <h4 class='jd-details-title'>
    ++    <span class='sympad'>rsCreateType</span>
    ++    <span class='normal'>: Creates an <a href={@docRoot}guide/topics/renderscript/reference/rs_object_types.html#android_rs:rs_type>rs_type</a> object with the specified <a href={@docRoot}guide/topics/renderscript/reference/rs_object_types.html#android_rs:rs_element>rs_element</a> and shape attributes</span>
    ++  </h4>
    ++  <div class='jd-details-descr'>
    ++    <table class='jd-tagtable'><tbody>
    ++      <tr>
    ++        <td><a href='rs_object_types.html#android_rs:rs_type'>rs_type</a> rsCreateType(<a href='rs_object_types.html#android_rs:rs_element'>rs_element</a> element, <a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimX);
    ++</td>
    ++        <td>    Added in <a href='http://developer.android.com/guide/topics/manifest/uses-sdk-element.html#ApiLevels'>API level 24</a>
    ++        </td>
    ++      </tr>
    ++      <tr>
    ++        <td><a href='rs_object_types.html#android_rs:rs_type'>rs_type</a> rsCreateType(<a href='rs_object_types.html#android_rs:rs_element'>rs_element</a> element, <a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimX, <a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimY);
    ++</td>
    ++        <td>    Added in <a href='http://developer.android.com/guide/topics/manifest/uses-sdk-element.html#ApiLevels'>API level 24</a>
    ++        </td>
    ++      </tr>
    ++      <tr>
    ++        <td><a href='rs_object_types.html#android_rs:rs_type'>rs_type</a> rsCreateType(<a href='rs_object_types.html#android_rs:rs_element'>rs_element</a> element, <a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimX, <a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimY, <a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimZ);
    ++</td>
    ++        <td>    Added in <a href='http://developer.android.com/guide/topics/manifest/uses-sdk-element.html#ApiLevels'>API level 24</a>
    ++        </td>
    ++      </tr>
    ++      <tr>
    ++        <td><a href='rs_object_types.html#android_rs:rs_type'>rs_type</a> rsCreateType(<a href='rs_object_types.html#android_rs:rs_element'>rs_element</a> element, <a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimX, <a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimY, <a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimZ, bool mipmaps, bool faces, <a href='rs_object_types.html#android_rs:rs_yuv_format'>rs_yuv_format</a> yuv_format);
    ++</td>
    ++        <td>    Added in <a href='http://developer.android.com/guide/topics/manifest/uses-sdk-element.html#ApiLevels'>API level 24</a>
    ++        </td>
    ++      </tr>
    ++    </tbody></table>
    ++  </div>
    ++  <div class='jd-tagdata'>    <h5 class='jd-tagtitle'>Parameters</h5>
    ++    <table class='jd-tagtable'><tbody>
    ++    <tr><th>element</th><td>An <a href={@docRoot}guide/topics/renderscript/reference/rs_object_types.html#android_rs:rs_element>rs_element</a> object that specifies the cell data type of an allocation.</td></tr>
    ++    <tr><th>dimX</th><td>Size on dimension x. Must be non zero.</td></tr>
    ++    <tr><th>dimY</th><td>Size on dimension y. 0 for single-dimension allocations.</td></tr>
    ++    <tr><th>dimZ</th><td>Size on dimension z. 0 for single-dimension and two-dimension allocations.</td></tr>
    ++    <tr><th>mipmaps</th><td>A boolean flag indicating if the allocation is mipmapped and has multiple levels of detail (LoD).</td></tr>
    ++    <tr><th>faces</th><td>A boolean flag indicating if the allocation is a cubemap that has cube faces.</td></tr>
    ++    <tr><th>yuv_format</th><td>Tye YUV layout.</td></tr>
    ++    </tbody></table>
    ++  </div>
    ++  <div class='jd-tagdata jd-tagdescr'>
    ++<p>  Creates an rs_type object with the specified element and shape attributes.
    ++</p>
    ++
    ++<p>  dimX specifies the size of the X dimension.
    ++</p>
    ++
    ++<p>  dimY, if present and non-zero, indicates that the Y dimension is present and
    ++ indicates its size.
    ++</p>
    ++
    ++<p>  dimZ, if present and non-zero, indicates that the Z dimension is present and
    ++ indicates its size.
    ++</p>
    ++
    ++<p>  mipmaps indicates the presence of level of detail (LOD).
    ++</p>
    ++
    ++<p>  faces indicates the  presence of cubemap faces.
    ++</p>
    ++
    ++<p>  yuv_format indicates the associated YUV format (or RS_YUV_NONE).
    ++</p>
    ++  </div>
    ++</div>
    ++
    ++<a name='android_rs:rsCreateVectorElement'></a>
    ++<div class='jd-details'>
    ++  <h4 class='jd-details-title'>
    ++    <span class='sympad'>rsCreateVectorElement</span>
    ++    <span class='normal'>: Creates an <a href={@docRoot}guide/topics/renderscript/reference/rs_object_types.html#android_rs:rs_element>rs_element</a> object of the specified data type and vector width</span>
    ++  </h4>
    ++  <div class='jd-details-descr'>
    ++    <table class='jd-tagtable'><tbody>
    ++      <tr>
    ++        <td><a href='rs_object_types.html#android_rs:rs_element'>rs_element</a> rsCreateVectorElement(<a href='rs_object_types.html#android_rs:rs_data_type'>rs_data_type</a> data_type, <a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> vector_width);
    ++</td>
    ++        <td>    Added in <a href='http://developer.android.com/guide/topics/manifest/uses-sdk-element.html#ApiLevels'>API level 24</a>
    ++        </td>
    ++      </tr>
    ++    </tbody></table>
    ++  </div>
    ++  <div class='jd-tagdata'>    <h5 class='jd-tagtitle'>Parameters</h5>
    ++    <table class='jd-tagtable'><tbody>
    ++    <tr><th>data_type</th><td>Data type of the Element</td></tr>
    ++    <tr><th>vector_width</th><td>Vector width</td></tr>
    ++    </tbody></table>
    ++  </div>
    ++  <div class='jd-tagdata jd-tagdescr'>
    ++<p>  Creates an rs_element object of the specified data type and vector width.
    ++ Value of vector_width must be 2, 3 or 4.  The data kind of the rs_element object will
    ++ be set to RS_KIND_USER.
    ++</p>
    ++  </div>
    ++</div>
    ++
    ++</div>
    +diff --git a/docs/html/guide/topics/renderscript/reference/rs_for_each.jd b/docs/html/guide/topics/renderscript/reference/rs_for_each.jd
    +index 9ba5614..8b19ba6 100644
    +--- a/docs/html/guide/topics/renderscript/reference/rs_for_each.jd
    ++++ b/docs/html/guide/topics/renderscript/reference/rs_for_each.jd
    +@@ -1,10 +1,10 @@
    +-page.title=RenderScript Kernel Invocation Functions and Types
    ++page.title=RenderScript Kernel Launch Functions and Types
    + 
    + @jd:body
    + 
    + <div class='renderscript'>
    + <h2>Overview</h2>
    +-<p> The <a href='rs_for_each.html#android_rs:rsForEach'>rsForEach</a>() function can be used to invoke the root kernel of a script.
    ++<p> The <a href='rs_for_each.html#android_rs:rsForEach'>rsForEach</a>() and <a href='rs_for_each.html#android_rs:rsForEachWithOptions'>rsForEachWithOptions</a>() functions are used to launch foreach kernels.
    + </p>
    + 
    + <p> The other functions are used to get the characteristics of the invocation of
    +@@ -24,6 +24,14 @@ a <a href='rs_for_each.html#android_rs:rs_kernel_context'>rs_kernel_context</a>
    +   </tr>
    +   <tr class='alt-color api apilevel-1'>
    +     <td class='jd-linkcol'>
    ++      <a href='rs_for_each.html#android_rs:rs_kernel'>rs_kernel</a>
    ++    </td>
    ++    <td class='jd-descrcol' width='100%'>
    ++      Handle to a kernel function
    ++    </td>
    ++  </tr>
    ++  <tr class='alt-color api apilevel-1'>
    ++    <td class='jd-linkcol'>
    +       <a href='rs_for_each.html#android_rs:rs_kernel_context'>rs_kernel_context</a>
    +     </td>
    +     <td class='jd-descrcol' width='100%'>
    +@@ -46,7 +54,15 @@ a <a href='rs_for_each.html#android_rs:rs_kernel_context'>rs_kernel_context</a>
    +       <a href='rs_for_each.html#android_rs:rsForEach'>rsForEach</a>
    +     </td>
    +     <td class='jd-descrcol' width='100%'>
    +-      Invoke the root kernel of a script
    ++      Launches a kernel
    ++    </td>
    ++  </tr>
    ++  <tr class='alt-color api apilevel-1'>
    ++    <td class='jd-linkcol'>
    ++      <a href='rs_for_each.html#android_rs:rsForEachWithOptions'>rsForEachWithOptions</a>
    ++    </td>
    ++    <td class='jd-descrcol' width='100%'>
    ++      Launches a kernel with options
    +     </td>
    +   </tr>
    +   <tr class='alt-color api apilevel-1'>
    +@@ -198,6 +214,21 @@ locality when the processing is distributed over multiple cores.
    +   </div>
    + </div>
    + 
    ++<a name='android_rs:rs_kernel'></a>
    ++<div class='jd-details'>
    ++  <h4 class='jd-details-title'>
    ++    <span class='sympad'>rs_kernel</span>
    ++    <span class='normal'>: Handle to a kernel function</span>
    ++  </h4>
    ++  <div class='jd-details-descr'>
    ++<p>A typedef of: void*&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Added in <a href='http://developer.android.com/guide/topics/manifest/uses-sdk-element.html#ApiLevels'>API level 24</a>
    ++</p>
    ++<p>  An opaque type for a function that is defined with the kernel attribute.  A value
    ++ of this type can be used in a <a href='rs_for_each.html#android_rs:rsForEach'>rsForEach</a> call to launch a kernel.
    ++</p>
    ++  </div>
    ++</div>
    ++
    + <a name='android_rs:rs_kernel_context'></a>
    + <div class='jd-details'>
    +   <h4 class='jd-details-title'>
    +@@ -249,7 +280,7 @@ versions, it will also be used to provide hint on how to best iterate over
    + the cells.
    + </p>
    + 
    +-<p> The Start fields are inclusive and the End fields are exclusive.  E.g. to iterate
    ++<p> The Start fields are inclusive and the End fields are exclusive.  For example, to iterate
    + over cells 4, 5, 6, and 7 in the X dimension, set xStart to 4 and xEnd to 8.
    + </p>
    +   </div>
    +@@ -260,14 +291,20 @@ over cells 4, 5, 6, and 7 in the X dimension, set xStart to 4 and xEnd to 8.
    + <div class='jd-details'>
    +   <h4 class='jd-details-title'>
    +     <span class='sympad'>rsForEach</span>
    +-    <span class='normal'>: Invoke the root kernel of a script</span>
    ++    <span class='normal'>: Launches a kernel</span>
    +   </h4>
    +   <div class='jd-details-descr'>
    +     <table class='jd-tagtable'><tbody>
    +       <tr>
    ++        <td>void rsForEach(<a href='rs_for_each.html#android_rs:rs_kernel'>rs_kernel</a> kernel, ... ...);
    ++</td>
    ++        <td>    Added in <a href='http://developer.android.com/guide/topics/manifest/uses-sdk-element.html#ApiLevels'>API level 24</a>
    ++        </td>
    ++      </tr>
    ++      <tr>
    +         <td>void rsForEach(<a href='rs_object_types.html#android_rs:rs_script'>rs_script</a> script, <a href='rs_object_types.html#android_rs:rs_allocation'>rs_allocation</a> input, <a href='rs_object_types.html#android_rs:rs_allocation'>rs_allocation</a> output);
    + </td>
    +-        <td>    Added in <a href='http://developer.android.com/guide/topics/manifest/uses-sdk-element.html#ApiLevels'>API level 14</a>
    ++        <td>    <a href='http://developer.android.com/guide/topics/manifest/uses-sdk-element.html#ApiLevels'>API level 14 - 23</a>
    +         </td>
    +       </tr>
    +       <tr>
    +@@ -300,35 +337,89 @@ over cells 4, 5, 6, and 7 in the X dimension, set xStart to 4 and xEnd to 8.
    +     <table class='jd-tagtable'><tbody>
    +     <tr><th>script</th><td>Script to call.</td></tr>
    +     <tr><th>input</th><td>Allocation to source data from.</td></tr>
    +-    <tr><th>output</th><td>Allocation to write date into.</td></tr>
    ++    <tr><th>output</th><td>Allocation to write data into.</td></tr>
    +     <tr><th>usrData</th><td>User defined data to pass to the script.  May be NULL.</td></tr>
    +     <tr><th>sc</th><td>Extra control information used to select a sub-region of the allocation to be processed or suggest a walking strategy.  May be NULL.</td></tr>
    +     <tr><th>usrDataLen</th><td>Size of the userData structure.  This will be used to perform a shallow copy of the data if necessary.</td></tr>
    ++    <tr><th>kernel</th><td>Function designator of the kernel function to call, which must be defined with the kernel attribute.</td></tr>
    ++    <tr><th>...</th><td>Input and output allocations</td></tr>
    +     </tbody></table>
    +   </div>
    +   <div class='jd-tagdata jd-tagdescr'>
    +-<p> Invoke the kernel named "root" of the specified script.  Like other kernels, this root()
    +-function will be invoked repeatedly over the cells of the specificed allocation, filling
    +-the output allocation with the results.
    ++<p> Runs the kernel over zero or more input allocations. They are passed after the
    ++<a href='rs_for_each.html#android_rs:rs_kernel'>rs_kernel</a> argument. If the specified kernel returns a value, an output allocation
    ++must be specified as the last argument. All input allocations,
    ++and the output allocation if it exists, must have the same dimensions.
    + </p>
    + 
    +-<p> When rsForEach is called, the root script is launched immediately.  rsForEach returns
    +-only when the script has completed and the output allocation is ready to use.
    ++<p> This is a synchronous function. A call to this function only returns after all
    ++the work has completed. If the kernel
    ++function returns any value, the call waits until all results have been written
    ++to the output allocation.
    + </p>
    + 
    +-<p> The rs_script argument is typically initialized using a global variable set from Java.
    ++<p> Up to API level 23, the kernel is implicitly specified as the kernel named
    ++"root" in the specified script, and only a single input allocation can be used.
    ++Starting in API level 24, an arbitrary kernel function can be used,
    ++as specified by the kernel argument.
    ++The kernel must be defined in the current script. In addition, more than one
    ++input can be used.
    + </p>
    + 
    +-<p> The kernel can be invoked with just an input allocation or just an output allocation.
    +-This can be done by defining an rs_allocation variable and not initializing it.  E.g.<code><br/>
    +-rs_script gCustomScript;<br/>
    +-void specializedProcessing(rs_allocation in) {<br/>
    +-&nbsp;&nbsp;rs_allocation ignoredOut;<br/>
    +-&nbsp;&nbsp;rsForEach(gCustomScript, in, ignoredOut);<br/>
    +-}<br/></code>
    ++<p> For example,<code><br/>
    ++float __attribute__((kernel)) square(float a) {<br/>
    ++&nbsp;&nbsp;return a * a;<br/>
    ++}<br/>
    ++<br/>
    ++void compute(rs_allocation ain, rs_allocation aout) {<br/>
    ++&nbsp;&nbsp;rsForEach(square, ain, aout);<br/>
    ++}<br/>
    ++<br/></code>
    ++</p>
    ++  </div>
    ++</div>
    ++
    ++<a name='android_rs:rsForEachWithOptions'></a>
    ++<div class='jd-details'>
    ++  <h4 class='jd-details-title'>
    ++    <span class='sympad'>rsForEachWithOptions</span>
    ++    <span class='normal'>: Launches a kernel with options</span>
    ++  </h4>
    ++  <div class='jd-details-descr'>
    ++    <table class='jd-tagtable'><tbody>
    ++      <tr>
    ++        <td>void rsForEachWithOptions(<a href='rs_for_each.html#android_rs:rs_kernel'>rs_kernel</a> kernel, <a href='rs_for_each.html#android_rs:rs_script_call_t'>rs_script_call_t</a>* options, ... ...);
    ++</td>
    ++        <td>    Added in <a href='http://developer.android.com/guide/topics/manifest/uses-sdk-element.html#ApiLevels'>API level 24</a>
    ++        </td>
    ++      </tr>
    ++    </tbody></table>
    ++  </div>
    ++  <div class='jd-tagdata'>    <h5 class='jd-tagtitle'>Parameters</h5>
    ++    <table class='jd-tagtable'><tbody>
    ++    <tr><th>kernel</th><td>Function designator to a function that is defined with the kernel attribute.</td></tr>
    ++    <tr><th>options</th><td>Launch options</td></tr>
    ++    <tr><th>...</th><td>Input and output allocations</td></tr>
    ++    </tbody></table>
    ++  </div>
    ++  <div class='jd-tagdata jd-tagdescr'>
    ++<p> Launches kernel in a way similar to <a href='rs_for_each.html#android_rs:rsForEach'>rsForEach</a>. However, instead of processing
    ++all cells in the input, this function only processes cells in the subspace of
    ++the index space specified in options. With the index space explicitly specified
    ++by options, no input or output allocation is required for a kernel launch using
    ++this API. If allocations are passed in, they must match the number of arguments
    ++and return value expected by the kernel function. The output allocation is
    ++present if and only if the kernel has a non-void return value.
    + </p>
    + 
    +-<p> If both input and output allocations are specified, they must have the same dimensions.
    ++<p> For example,<code><br/>
    ++   rs_script_call_t opts = {0};<br/>
    ++   opts.xStart = 0;<br/>
    ++   opts.xEnd = dimX;<br/>
    ++   opts.yStart = 0;<br/>
    ++   opts.yEnd = dimY / 2;<br/>
    ++   rsForEachWithOptions(foo, &opts, out, out);<br/>
    ++</code>
    + </p>
    +   </div>
    + </div>
    +@@ -359,7 +450,7 @@ over and rarely used indices, like the Array0 index.
    + </p>
    + 
    + <p> You can access the kernel context by adding a special parameter named "context" of
    +-type rs_kernel_context to your kernel function.  E.g.<br/>
    ++type rs_kernel_context to your kernel function.  For example,<br/>
    + <code>short RS_KERNEL myKernel(short value, uint32_t x, rs_kernel_context context) {<br/>
    + &nbsp;&nbsp;// The current index in the common x, y, z dimensions are accessed by<br/>
    + &nbsp;&nbsp;// adding these variables as arguments.  For the more rarely used indices<br/>
    +@@ -644,7 +735,7 @@ over and rarely used indices, like the Array0 index.
    + </p>
    + 
    + <p> You can access it by adding a special parameter named "context" of
    +-type rs_kernel_context to your kernel function.  E.g.<br/>
    ++type rs_kernel_context to your kernel function.  For example,<br/>
    + <code>int4 RS_KERNEL myKernel(int4 value, rs_kernel_context context) {<br/>
    + &nbsp;&nbsp;uint32_t size = rsGetDimX(context); //...<br/></code>
    + </p>
    +diff --git a/docs/html/guide/topics/resources/drawable-resource.jd b/docs/html/guide/topics/resources/drawable-resource.jd
    +index aae0cba..4587ae4 100644
    +--- a/docs/html/guide/topics/resources/drawable-resource.jd
    ++++ b/docs/html/guide/topics/resources/drawable-resource.jd
    +@@ -1270,7 +1270,7 @@ the right edge, a right gravity clips the left edge, and neither clips both edge
    + progressively reveal the image:</p>
    + <pre>
    + ImageView imageview = (ImageView) findViewById(R.id.image);
    +-ClipDrawable drawable = (ClipDrawable) imageview.getDrawable();
    ++ClipDrawable drawable = (ClipDrawable) imageview.getBackground();
    + drawable.setLevel(drawable.getLevel() + 1000);
    + </pre>
    + 
    +diff --git a/docs/html/guide/topics/resources/multilingual-support.jd b/docs/html/guide/topics/resources/multilingual-support.jd
    +index 8d8484b..28699fe 100644
    +--- a/docs/html/guide/topics/resources/multilingual-support.jd
    ++++ b/docs/html/guide/topics/resources/multilingual-support.jd
    +@@ -88,15 +88,17 @@ today.</p>
    + 
    + <h2 id="postN">Improvements to Resource-Resolution Strategy</h2>
    + <p>Android 7.0 (API level 24) brings more robust resource resolution, and
    +- finds better fallbacks automatically. However, to speed up resolution and
    +- improve
    ++ finds better fallbacks automatically.
    ++ However, to speed up resolution and improve
    +  maintainability, you should store resources in the most common parent dialect.
    +- For example, if you were storing Spanish resources in the {@code es-US}
    +- directory
    +- before, move them into the {@code es-419} directory, which contains Latin
    +- American Spanish.
    +- Similarly, if you have resource strings in a folder named {@code en-GB}, rename
    +- the folder to {@code en-001} (international English), because the most common
    ++ For example, if you were storing Spanish resources
    ++ in the {@code values-es-rUS} directory
    ++ before, move them into the {@code values-b+es+419} directory,
    ++ which contains Latin American Spanish.
    ++ Similarly, if you have resource strings in a
    ++ directory named {@code values-en-rGB}, rename
    ++ the directory to {@code values-b+en+001} (International
    ++ English), because the most common
    +  parent for <code>en-GB</code> strings is {@code en-001}.
    +  The following examples explain why these practices improve performance and
    + reliability of resource resolution.</p>
    +diff --git a/docs/html/guide/topics/search/search-dialog.jd b/docs/html/guide/topics/search/search-dialog.jd
    +index 8278ab1..4d6b400 100644
    +--- a/docs/html/guide/topics/search/search-dialog.jd
    ++++ b/docs/html/guide/topics/search/search-dialog.jd
    +@@ -699,7 +699,7 @@ public boolean onCreateOptionsMenu(Menu menu) {
    +     inflater.inflate(R.menu.options_menu, menu);
    + 
    +     // Get the SearchView and set the searchable configuration
    +-    SearchManager searchManager = (SearchManager) {@link android.app.Activity#getSystemService(java.lang.String) getSystemService()}(Context.SEARCH_SERVICE);
    ++    SearchManager searchManager = (SearchManager) {@link android.app.Activity#getSystemService getSystemService}(Context.SEARCH_SERVICE);
    +     SearchView searchView = (SearchView) menu.findItem(R.id.menu_search).getActionView();
    +     // Assumes current activity is the searchable activity
    +     searchView.setSearchableInfo(searchManager.getSearchableInfo({@link android.app.Activity#getComponentName()}));
    +diff --git a/docs/html/guide/topics/ui/accessibility/apps.jd b/docs/html/guide/topics/ui/accessibility/apps.jd
    +index c415762..ab8c792 100644
    +--- a/docs/html/guide/topics/ui/accessibility/apps.jd
    ++++ b/docs/html/guide/topics/ui/accessibility/apps.jd
    +@@ -298,7 +298,7 @@ then the {@link android.view.View#dispatchPopulateAccessibilityEvent
    + dispatchPopulateAccessibilityEvent()} method for each child of this view. In order to support
    + accessibility services on revisions of Android <em>prior</em> to 4.0 (API Level 14) you
    + <em>must</em> override this method and populate {@link
    +-android.view.accessibility.AccessibilityRecord#getText} with descriptive text for your custom
    ++android.view.accessibility.AccessibilityEvent#getText} with descriptive text for your custom
    + view, which is spoken by accessibility services, such as TalkBack.</dd>
    + 
    +   <dt>{@link android.view.View#onPopulateAccessibilityEvent onPopulateAccessibilityEvent()}</dt>
    +diff --git a/docs/html/guide/topics/ui/accessibility/services.jd b/docs/html/guide/topics/ui/accessibility/services.jd
    +index d08022e..dbc69ef 100644
    +--- a/docs/html/guide/topics/ui/accessibility/services.jd
    ++++ b/docs/html/guide/topics/ui/accessibility/services.jd
    +@@ -79,22 +79,15 @@ must also request the {@link android.Manifest.permission#BIND_ACCESSIBILITY_SERV
    + as shown in the following sample:</p>
    + 
    + <pre>
    +-&lt;manifest&gt;
    +-  ...
    +-  &lt;uses-permission ... /&gt;
    +-  ...
    +   &lt;application&gt;
    +-    ...
    +     &lt;service android:name=&quot;.MyAccessibilityService&quot;
    +-        android:label=&quot;@string/accessibility_service_label&quot;
    +-        android:permission=&quot;android.permission.BIND_ACCESSIBILITY_SERVICE&quot&gt;
    ++        android:permission="android.permission.BIND_ACCESSIBILITY_SERVICE"
    ++        android:label=&quot;@string/accessibility_service_label&quot;&gt;
    +       &lt;intent-filter&gt;
    +         &lt;action android:name=&quot;android.accessibilityservice.AccessibilityService&quot; /&gt;
    +       &lt;/intent-filter&gt;
    +     &lt;/service&gt;
    +-    &lt;uses-permission android:name="android.permission.BIND_ACCESSIBILITY_SERVICE" /&gt;
    +   &lt;/application&gt;
    +-&lt;/manifest&gt;
    + </pre>
    + 
    + <p>These declarations are required for all accessibility services deployed on Android 1.6 (API Level
    +@@ -205,7 +198,7 @@ from when the service is started
    + while it is running ({@link android.accessibilityservice.AccessibilityService#onAccessibilityEvent
    + onAccessibilityEvent()},
    + {@link android.accessibilityservice.AccessibilityService#onInterrupt onInterrupt()}) to when it is
    +-shut down ({@link android.app.Service#onUnbind onUnbind()}).</p>
    ++shut down ({@link android.accessibilityservice.AccessibilityService#onUnbind onUnbind()}).</p>
    + 
    + <ul>
    +   <li>{@link android.accessibilityservice.AccessibilityService#onServiceConnected
    +@@ -231,7 +224,7 @@ service.</li>
    + providing, usually in response to a user action such as moving focus to a different control. This
    + method may be called many times over the lifecycle of your service.</li>
    + 
    +-  <li>{@link android.app.Service#onUnbind onUnbind()} - (optional)
    ++  <li>{@link android.accessibilityservice.AccessibilityService#onUnbind onUnbind()} - (optional)
    + This method is called when the system is about to shutdown the accessibility service. Use this
    + method to do any one-time shutdown procedures, including de-allocating user feedback system
    + services, such as the audio manager or device vibrator.</li>
    +@@ -283,7 +276,7 @@ retrieve the set of {@link android.view.accessibility.AccessibilityRecord} objec
    + to the {@link android.view.accessibility.AccessibilityEvent} passed to you by the system. This level
    + of detail provides more context for the event that triggered your accessibility service.</li>
    + 
    +-  <li>{@link android.view.accessibility.AccessibilityRecord#getSource
    ++  <li>{@link android.view.accessibility.AccessibilityEvent#getSource
    + AccessibilityEvent.getSource()} - This method returns an {@link
    + android.view.accessibility.AccessibilityNodeInfo} object. This object allows you to request view
    + layout hierarchy (parents and children) of the component that originated the accessibility event.
    +@@ -296,10 +289,10 @@ user information to your accessibility service. For this reason, your service mu
    + level of access through the accessibility <a href="#service-config">service configuration XML</a>
    + file, by including the {@code canRetrieveWindowContent} attribute and setting it to {@code true}. If
    + you do not include this setting in your service configuration xml file, calls to {@link
    +-android.view.accessibility.AccessibilityRecord#getSource getSource()} fail.</p>
    ++android.view.accessibility.AccessibilityEvent#getSource getSource()} fail.</p>
    + 
    + <p class="note"><strong>Note:</strong> In Android 4.1 (API Level 16) and higher, the
    +-{@link android.view.accessibility.AccessibilityRecord#getSource getSource()} method,
    ++{@link android.view.accessibility.AccessibilityEvent#getSource getSource()} method,
    + as well as {@link android.view.accessibility.AccessibilityNodeInfo#getChild
    + AccessibilityNodeInfo.getChild()} and
    + {@link android.view.accessibility.AccessibilityNodeInfo#getParent getParent()}, return only
    +@@ -372,7 +365,7 @@ public class MyAccessibilityService extends AccessibilityService {
    +   <a href="#service-config">service configuration file</a>. When events are received by your
    +   service, it can then retrieve the
    +   {@link android.view.accessibility.AccessibilityNodeInfo} object from the event using
    +-  {@link android.view.accessibility.AccessibilityRecord#getSource getSource()}.
    ++  {@link android.view.accessibility.AccessibilityEvent#getSource getSource()}.
    +   With the {@link android.view.accessibility.AccessibilityNodeInfo} object, your service can then
    +   explore the view hierarchy to determine what action to take and then act for the user using
    +   {@link android.view.accessibility.AccessibilityNodeInfo#performAction performAction()}.</p>
    +diff --git a/docs/html/guide/topics/ui/controls/togglebutton.jd b/docs/html/guide/topics/ui/controls/togglebutton.jd
    +index e0549ec..181647c 100644
    +--- a/docs/html/guide/topics/ui/controls/togglebutton.jd
    ++++ b/docs/html/guide/topics/ui/controls/togglebutton.jd
    +@@ -14,6 +14,7 @@ page.tags=switch,togglebutton
    +   <ol>
    +     <li>{@link android.widget.ToggleButton}</li>
    +     <li>{@link android.widget.Switch}</li>
    ++    <li>{@link android.support.v7.widget.SwitchCompat}</li>
    +     <li>{@link android.widget.CompoundButton}</li>
    +   </ol>
    + </div>
    +@@ -21,9 +22,12 @@ page.tags=switch,togglebutton
    + 
    + <p>A toggle button allows the user to change a setting between two states.</p>
    + 
    +-<p>You can add a basic toggle button to your layout with the {@link android.widget.ToggleButton}
    +-object. Android 4.0 (API level 14) introduces another kind of toggle button called a switch that
    +-provides a slider control, which you can add with a {@link android.widget.Switch} object.</p>
    ++<p>You can add a basic toggle button to your layout with the
    ++{@link android.widget.ToggleButton} object. Android 4.0 (API level 14)
    ++introduces another kind of toggle button called a switch that provides a slider
    ++control, which you can add with a {@link android.widget.Switch} object.
    ++{@link android.support.v7.widget.SwitchCompat} is a version of the Switch
    ++widget which runs on devices back to API 7.</p>
    + 
    + <p>
    +   If you need to change a button's state yourself, you can use the {@link
    +diff --git a/docs/html/guide/topics/ui/declaring-layout.jd b/docs/html/guide/topics/ui/declaring-layout.jd
    +index ecdcfdc..bf0db57 100755
    +--- a/docs/html/guide/topics/ui/declaring-layout.jd
    ++++ b/docs/html/guide/topics/ui/declaring-layout.jd
    +@@ -423,7 +423,7 @@ ArrayAdapter&lt;String> adapter = new ArrayAdapter&lt;String>(this,
    +   <li>The string array</li>
    + </ul>
    + <p>Then simply call
    +-{@link android.widget.AdapterView#setAdapter setAdapter()} on your {@link android.widget.ListView}:</p>
    ++{@link android.widget.ListView#setAdapter setAdapter()} on your {@link android.widget.ListView}:</p>
    + <pre>
    + ListView listView = (ListView) findViewById(R.id.listview);
    + listView.setAdapter(adapter);
    +diff --git a/docs/html/guide/topics/ui/dialogs.jd b/docs/html/guide/topics/ui/dialogs.jd
    +index 52cd1a0..7ab4ca5 100644
    +--- a/docs/html/guide/topics/ui/dialogs.jd
    ++++ b/docs/html/guide/topics/ui/dialogs.jd
    +@@ -643,7 +643,7 @@ android.support.v4.app.Fragment}.</p>
    + or other {@link android.app.Dialog} objects to build the dialog in this case. If
    + you want the {@link android.support.v4.app.DialogFragment} to be
    + embeddable, you must define the dialog's UI in a layout, then load the layout in the
    +-{@link android.support.v4.app.Fragment#onCreateView
    ++{@link android.support.v4.app.DialogFragment#onCreateView
    + onCreateView()} callback.</p>
    + 
    + <p>Here's an example {@link android.support.v4.app.DialogFragment} that can appear as either a
    +diff --git a/docs/html/guide/topics/ui/drag-drop.jd b/docs/html/guide/topics/ui/drag-drop.jd
    +index 8871c87..8e4297f 100644
    +--- a/docs/html/guide/topics/ui/drag-drop.jd
    ++++ b/docs/html/guide/topics/ui/drag-drop.jd
    +@@ -152,7 +152,7 @@ DraggableDot.java</a> in <a href="{@docRoot}resources/samples/ApiDemos/index.htm
    +     drag event listeners or callback methods of each View in the layout. The listeners or callback
    +     methods can use the metadata to decide if they want to accept the data when it is dropped.
    +     If the user drops the data over a View object, and that View object's listener or callback
    +-    method has previously told the system that it wants to accept the drop, then the system sends
    ++    method has previously told the system that it wants to accept the data, then the system sends
    +     the data to the listener or callback method in a drag event.
    + </p>
    + <p>
    +@@ -226,7 +226,8 @@ DraggableDot.java</a> in <a href="{@docRoot}resources/samples/ApiDemos/index.htm
    +     </dt>
    +     <dd>
    +         The user releases the drag shadow within the bounding box of a View that can accept the
    +-        data. The system sends the View object's listener a drag event with action type
    ++        data, but not within its descendant view that can accept the data. The system sends the View
    ++        object's listener a drag event with action type
    +         {@link android.view.DragEvent#ACTION_DROP}. The drag event contains the data that was
    +         passed to the system in the call to
    +         {@link android.view.View#startDrag(ClipData,View.DragShadowBuilder,Object,int) startDrag()}
    +@@ -317,6 +318,10 @@ DraggableDot.java</a> in <a href="{@docRoot}resources/samples/ApiDemos/index.htm
    +             application calls
    + {@link android.view.View#startDrag(ClipData,View.DragShadowBuilder,Object,int) startDrag()} and
    +             gets a drag shadow.
    ++            <p>
    ++                If the listener wants to continue receiving drag events for this operation, it must
    ++                return boolean <code>true</code> to the system.
    ++            </p>
    +         </td>
    +     </tr>
    +     <tr>
    +@@ -324,9 +329,7 @@ DraggableDot.java</a> in <a href="{@docRoot}resources/samples/ApiDemos/index.htm
    +         <td>
    +             A View object's drag event listener receives this event action type when the drag shadow
    +             has just entered the bounding box of the View. This is the first event action type the
    +-            listener receives when the drag shadow enters the bounding box. If the listener wants to
    +-            continue receiving drag events for this operation, it must return boolean
    +-            <code>true</code> to the system.
    ++            listener receives when the drag shadow enters the bounding box.
    +         </td>
    +     </tr>
    +     <tr>
    +@@ -334,7 +337,8 @@ DraggableDot.java</a> in <a href="{@docRoot}resources/samples/ApiDemos/index.htm
    +         <td>
    +             A View object's drag event listener receives this event action type after it receives a
    +             {@link android.view.DragEvent#ACTION_DRAG_ENTERED} event while the drag shadow is
    +-            still within the bounding box of the View.
    ++            still within the bounding box of the View and not within a descendant view that can
    ++            accept the data.
    +         </td>
    +     </tr>
    +     <tr>
    +@@ -343,7 +347,8 @@ DraggableDot.java</a> in <a href="{@docRoot}resources/samples/ApiDemos/index.htm
    +             A View object's drag event listener receives this event action type after it receives a
    +             {@link android.view.DragEvent#ACTION_DRAG_ENTERED} and at least one
    +             {@link android.view.DragEvent#ACTION_DRAG_LOCATION} event, and after the user has moved
    +-            the drag shadow outside the bounding box of the View.
    ++            the drag shadow outside the bounding box of the View or into a descendant view that can
    ++            accept the data.
    +         </td>
    +     </tr>
    +     <tr>
    +@@ -395,7 +400,7 @@ DraggableDot.java</a> in <a href="{@docRoot}resources/samples/ApiDemos/index.htm
    +         <td style="text-align: center;">X</td>
    +         <td style="text-align: center;">X</td>
    +         <td style="text-align: center;">X</td>
    +-        <td style="text-align: center;">&nbsp;</td>
    ++        <td style="text-align: center;">X</td>
    +         <td style="text-align: center;">&nbsp;</td>
    +         <td style="text-align: center;">&nbsp;</td>
    +     </tr>
    +@@ -711,8 +716,7 @@ imageView.setOnLongClickListener(new View.OnLongClickListener() {
    +         If the listener can accept a drop, it should return <code>true</code>. This tells
    +         the system to continue to send drag events to the listener.
    +         If it can't accept a drop, it should return <code>false</code>, and the system
    +-        will stop sending drag events until it sends out
    +-        {@link android.view.DragEvent#ACTION_DRAG_ENDED}.
    ++        will stop sending drag events for the current drag operation.
    +     </li>
    + </ol>
    + <p>
    +@@ -754,7 +758,8 @@ imageView.setOnLongClickListener(new View.OnLongClickListener() {
    +     <li>
    +         {@link android.view.DragEvent#ACTION_DRAG_EXITED}:  This event is sent to a listener that
    +         previously received {@link android.view.DragEvent#ACTION_DRAG_ENTERED}, after
    +-        the drag shadow is no longer within the bounding box of the listener's View.
    ++        the drag shadow is no longer within the bounding box of the listener's View or it's within
    ++        the bounding box of a descendant view that can accept the data.
    +     </li>
    + </ul>
    + <p>
    +diff --git a/docs/html/guide/topics/ui/layout/gridview.jd b/docs/html/guide/topics/ui/layout/gridview.jd
    +index 4ed6ff5..13467ae 100644
    +--- a/docs/html/guide/topics/ui/layout/gridview.jd
    ++++ b/docs/html/guide/topics/ui/layout/gridview.jd
    +@@ -81,7 +81,7 @@ public void onCreate(Bundle savedInstanceState) {
    +   <p>After the {@code main.xml} layout is set for the content view, the
    + {@link android.widget.GridView} is captured from the layout with {@link
    + android.app.Activity#findViewById(int)}. The {@link
    +-android.widget.AdapterView#setAdapter(T) setAdapter()} method then sets a custom adapter ({@code
    ++android.widget.GridView#setAdapter(T) setAdapter()} method then sets a custom adapter ({@code
    + ImageAdapter}) as the source for all items to be displayed in the grid. The {@code ImageAdapter} is
    + created in the next step.</p>
    + <p>To do something when an item in the grid is clicked, the {@link
    +@@ -170,7 +170,7 @@ the height and width for the View&mdash;this ensures that, no matter the size of
    + image is resized and cropped to fit in these dimensions, as appropriate.</li>
    +   <li>{@link android.widget.ImageView#setScaleType(ImageView.ScaleType)} declares that images should
    + be cropped toward the center (if necessary).</li>
    +-  <li>{@link android.view.View#setPadding(int,int,int,int)} defines the padding for all
    ++  <li>{@link android.widget.ImageView#setPadding(int,int,int,int)} defines the padding for all
    + sides. (Note that, if the images have different aspect-ratios, then less
    + padding will cause more cropping of the image if it does not match
    + the dimensions given to the ImageView.)</li>
    +diff --git a/docs/html/guide/topics/ui/menus.jd b/docs/html/guide/topics/ui/menus.jd
    +index 38f6e21..3325c0e 100644
    +--- a/docs/html/guide/topics/ui/menus.jd
    ++++ b/docs/html/guide/topics/ui/menus.jd
    +@@ -682,7 +682,7 @@ listView.setMultiChoiceModeListener(new MultiChoiceModeListener() {
    + </pre>
    + 
    + <p>That's it. Now when the user selects an item with a long-click, the system calls the {@link
    +-android.view.ActionMode.Callback#onCreateActionMode onCreateActionMode()}
    ++android.widget.AbsListView.MultiChoiceModeListener#onCreateActionMode onCreateActionMode()}
    + method and displays the contextual action bar with the specified actions. While the contextual
    + action bar is visible, users can select additional items.</p>
    + 
    +diff --git a/docs/html/guide/topics/ui/multi-window.jd b/docs/html/guide/topics/ui/multi-window.jd
    +index dede557..bab582d 100644
    +--- a/docs/html/guide/topics/ui/multi-window.jd
    ++++ b/docs/html/guide/topics/ui/multi-window.jd
    +@@ -215,7 +215,7 @@ android:resizeableActivity=["true" | "false"]
    +   Set this attribute in your manifest's <a href=
    +   "{@docRoot}guide/topics/manifest/activity-element"><code>&lt;activity&gt;</code></a>
    +   node to indicate whether the activity supports <a href=
    +-  "{@docRoot}training/tv/playback/picture-in-picture.jd">Picture-in-Picture</a>
    ++  "{@docRoot}training/tv/playback/picture-in-picture.html">Picture-in-Picture</a>
    +   display. This attribute is ignored if <code>android:resizeableActivity</code>
    +   is false.
    + </p>
    +diff --git a/docs/html/images/brand/android_logo_no.png b/docs/html/images/brand/android_logo_no.png
    +index 8de22d8..946bc49 100644
    +Binary files a/docs/html/images/brand/android_logo_no.png and b/docs/html/images/brand/android_logo_no.png differ
    +diff --git a/docs/html/images/brand/android_logo_no_2x.png b/docs/html/images/brand/android_logo_no_2x.png
    +new file mode 100644
    +index 0000000..8434c79
    +Binary files /dev/null and b/docs/html/images/brand/android_logo_no_2x.png differ
    +diff --git a/docs/html/images/cards/distribute/stories/animoca.jpg b/docs/html/images/cards/distribute/stories/animoca.jpg
    +new file mode 100644
    +index 0000000..1886bce
    +Binary files /dev/null and b/docs/html/images/cards/distribute/stories/animoca.jpg differ
    +diff --git a/docs/html/images/cards/distribute/stories/drupe.jpg b/docs/html/images/cards/distribute/stories/drupe.jpg
    +new file mode 100644
    +index 0000000..5295695
    +Binary files /dev/null and b/docs/html/images/cards/distribute/stories/drupe.jpg differ
    +diff --git a/docs/html/images/cards/distribute/stories/economist-espresso.png b/docs/html/images/cards/distribute/stories/economist-espresso.png
    +new file mode 100644
    +index 0000000..923bf57
    +Binary files /dev/null and b/docs/html/images/cards/distribute/stories/economist-espresso.png differ
    +diff --git a/docs/html/images/cards/distribute/stories/expressen-sport.png b/docs/html/images/cards/distribute/stories/expressen-sport.png
    +new file mode 100644
    +index 0000000..842ed3d
    +Binary files /dev/null and b/docs/html/images/cards/distribute/stories/expressen-sport.png differ
    +diff --git a/docs/html/images/cards/distribute/stories/glamour.png b/docs/html/images/cards/distribute/stories/glamour.png
    +new file mode 100644
    +index 0000000..770b03f
    +Binary files /dev/null and b/docs/html/images/cards/distribute/stories/glamour.png differ
    +diff --git a/docs/html/images/cards/distribute/stories/happylabs-logo.png b/docs/html/images/cards/distribute/stories/happylabs-logo.png
    +new file mode 100644
    +index 0000000..ea20e71
    +Binary files /dev/null and b/docs/html/images/cards/distribute/stories/happylabs-logo.png differ
    +diff --git a/docs/html/images/cards/distribute/stories/lifesum.png b/docs/html/images/cards/distribute/stories/lifesum.png
    +new file mode 100644
    +index 0000000..3975ff2
    +Binary files /dev/null and b/docs/html/images/cards/distribute/stories/lifesum.png differ
    +diff --git a/docs/html/images/cards/distribute/stories/noom.jpg b/docs/html/images/cards/distribute/stories/noom.jpg
    +new file mode 100644
    +index 0000000..dde18a2
    +Binary files /dev/null and b/docs/html/images/cards/distribute/stories/noom.jpg differ
    +diff --git a/docs/html/images/cards/distribute/stories/playlab.jpg b/docs/html/images/cards/distribute/stories/playlab.jpg
    +new file mode 100644
    +index 0000000..3b641e6
    +Binary files /dev/null and b/docs/html/images/cards/distribute/stories/playlab.jpg differ
    +diff --git a/docs/html/images/develop/hero-layout-editor.png b/docs/html/images/develop/hero-layout-editor.png
    +new file mode 100644
    +index 0000000..195150e
    +Binary files /dev/null and b/docs/html/images/develop/hero-layout-editor.png differ
    +diff --git a/docs/html/images/develop/hero-layout-editor_2x.png b/docs/html/images/develop/hero-layout-editor_2x.png
    +new file mode 100644
    +index 0000000..60c3d24
    +Binary files /dev/null and b/docs/html/images/develop/hero-layout-editor_2x.png differ
    +diff --git a/docs/html/images/distribute/stories/animoca-flow.jpg b/docs/html/images/distribute/stories/animoca-flow.jpg
    +new file mode 100644
    +index 0000000..d2aa2f6
    +Binary files /dev/null and b/docs/html/images/distribute/stories/animoca-flow.jpg differ
    +diff --git a/docs/html/images/distribute/stories/animoca-graph.jpg b/docs/html/images/distribute/stories/animoca-graph.jpg
    +new file mode 100644
    +index 0000000..c2a42f4
    +Binary files /dev/null and b/docs/html/images/distribute/stories/animoca-graph.jpg differ
    +diff --git a/docs/html/images/distribute/stories/animoca-logo.png b/docs/html/images/distribute/stories/animoca-logo.png
    +new file mode 100644
    +index 0000000..4b5b6b5
    +Binary files /dev/null and b/docs/html/images/distribute/stories/animoca-logo.png differ
    +diff --git a/docs/html/images/distribute/stories/drupe-icon.png b/docs/html/images/distribute/stories/drupe-icon.png
    +new file mode 100644
    +index 0000000..1b75cca
    +Binary files /dev/null and b/docs/html/images/distribute/stories/drupe-icon.png differ
    +diff --git a/docs/html/images/distribute/stories/drupe-screenshot.png b/docs/html/images/distribute/stories/drupe-screenshot.png
    +new file mode 100644
    +index 0000000..6fd4445
    +Binary files /dev/null and b/docs/html/images/distribute/stories/drupe-screenshot.png differ
    +diff --git a/docs/html/images/distribute/stories/economist-espresso-icon.png b/docs/html/images/distribute/stories/economist-espresso-icon.png
    +new file mode 100644
    +index 0000000..923bf57
    +Binary files /dev/null and b/docs/html/images/distribute/stories/economist-espresso-icon.png differ
    +diff --git a/docs/html/images/distribute/stories/expressen-icon.png b/docs/html/images/distribute/stories/expressen-icon.png
    +new file mode 100644
    +index 0000000..4547ce7
    +Binary files /dev/null and b/docs/html/images/distribute/stories/expressen-icon.png differ
    +diff --git a/docs/html/images/distribute/stories/glamour-icon.png b/docs/html/images/distribute/stories/glamour-icon.png
    +new file mode 100644
    +index 0000000..770b03f
    +Binary files /dev/null and b/docs/html/images/distribute/stories/glamour-icon.png differ
    +diff --git a/docs/html/images/distribute/stories/happylabs-happy_pet_icon.png b/docs/html/images/distribute/stories/happylabs-happy_pet_icon.png
    +new file mode 100644
    +index 0000000..9b24c4a
    +Binary files /dev/null and b/docs/html/images/distribute/stories/happylabs-happy_pet_icon.png differ
    +diff --git a/docs/html/images/distribute/stories/happylabs-logo.png b/docs/html/images/distribute/stories/happylabs-logo.png
    +new file mode 100644
    +index 0000000..ea20e71
    +Binary files /dev/null and b/docs/html/images/distribute/stories/happylabs-logo.png differ
    +diff --git a/docs/html/images/distribute/stories/happylabs-variant.png b/docs/html/images/distribute/stories/happylabs-variant.png
    +new file mode 100644
    +index 0000000..3ce5342
    +Binary files /dev/null and b/docs/html/images/distribute/stories/happylabs-variant.png differ
    +diff --git a/docs/html/images/distribute/stories/lifesum-icon.png b/docs/html/images/distribute/stories/lifesum-icon.png
    +new file mode 100644
    +index 0000000..3975ff2
    +Binary files /dev/null and b/docs/html/images/distribute/stories/lifesum-icon.png differ
    +diff --git a/docs/html/images/distribute/stories/noom-icon.png b/docs/html/images/distribute/stories/noom-icon.png
    +new file mode 100644
    +index 0000000..a853218
    +Binary files /dev/null and b/docs/html/images/distribute/stories/noom-icon.png differ
    +diff --git a/docs/html/images/distribute/stories/noom-screenshot.png b/docs/html/images/distribute/stories/noom-screenshot.png
    +new file mode 100644
    +index 0000000..0293eea
    +Binary files /dev/null and b/docs/html/images/distribute/stories/noom-screenshot.png differ
    +diff --git a/docs/html/images/distribute/stories/playlab-icon.png b/docs/html/images/distribute/stories/playlab-icon.png
    +new file mode 100644
    +index 0000000..af80183
    +Binary files /dev/null and b/docs/html/images/distribute/stories/playlab-icon.png differ
    +diff --git a/docs/html/images/distribute/stories/playlab-screenshot.png b/docs/html/images/distribute/stories/playlab-screenshot.png
    +new file mode 100644
    +index 0000000..42ffb6a
    +Binary files /dev/null and b/docs/html/images/distribute/stories/playlab-screenshot.png differ
    +diff --git a/docs/html/images/guide/topics/graphics/ic_battery_charging_80_black_24dp.png b/docs/html/images/guide/topics/graphics/ic_battery_charging_80_black_24dp.png
    +new file mode 100644
    +index 0000000..44a4e86
    +Binary files /dev/null and b/docs/html/images/guide/topics/graphics/ic_battery_charging_80_black_24dp.png differ
    +diff --git a/docs/html/images/guide/topics/graphics/vectorpath.png b/docs/html/images/guide/topics/graphics/vectorpath.png
    +new file mode 100644
    +index 0000000..592bab6
    +Binary files /dev/null and b/docs/html/images/guide/topics/graphics/vectorpath.png differ
    +diff --git a/docs/html/images/tools/sdk-manager-support-libs.png b/docs/html/images/tools/sdk-manager-support-libs.png
    +deleted file mode 100644
    +index cb4cea5..0000000
    +Binary files a/docs/html/images/tools/sdk-manager-support-libs.png and /dev/null differ
    +diff --git a/docs/html/images/tools/studio-sdk-manager-packages.png b/docs/html/images/tools/studio-sdk-manager-packages.png
    +deleted file mode 100644
    +index 79ea912..0000000
    +Binary files a/docs/html/images/tools/studio-sdk-manager-packages.png and /dev/null differ
    +diff --git a/docs/html/images/training/ctl-config.png b/docs/html/images/training/ctl-config.png
    +index 82f63c8..3a4f738 100644
    +Binary files a/docs/html/images/training/ctl-config.png and b/docs/html/images/training/ctl-config.png differ
    +diff --git a/docs/html/images/training/tv/playback/onboarding-fragment-diagram.png b/docs/html/images/training/tv/playback/onboarding-fragment-diagram.png
    +new file mode 100644
    +index 0000000..5839a50
    +Binary files /dev/null and b/docs/html/images/training/tv/playback/onboarding-fragment-diagram.png differ
    +diff --git a/docs/html/images/training/tv/playback/onboarding-fragment.png b/docs/html/images/training/tv/playback/onboarding-fragment.png
    +new file mode 100644
    +index 0000000..5b7da55
    +Binary files /dev/null and b/docs/html/images/training/tv/playback/onboarding-fragment.png differ
    +diff --git a/docs/html/images/training/tv/playback/onboarding-fragment_2x.png b/docs/html/images/training/tv/playback/onboarding-fragment_2x.png
    +new file mode 100644
    +index 0000000..0034be4
    +Binary files /dev/null and b/docs/html/images/training/tv/playback/onboarding-fragment_2x.png differ
    +diff --git a/docs/html/index.jd b/docs/html/index.jd
    +index dc59b71..78fc848 100644
    +--- a/docs/html/index.jd
    ++++ b/docs/html/index.jd
    +@@ -6,16 +6,6 @@ nonavpage=true
    + 
    + @jd:body
    + 
    +-<script>
    +-  $(document).ready(function() {
    +-    if (useUpdatedTemplates) {
    +-      $("#useUpdatedTemplates").css("display","block");
    +-    } else {
    +-      $("#useOldTemplates").css("display","block");
    +-    }
    +-  })
    +-</script>
    +-
    + <section class="dac-expand dac-hero" style="background-color:#b2dfdb;">
    +   <div class="wrap" style="max-width:1000px;margin-top:0">
    +     <div class="col-7of16 col-push-8of16">
    +@@ -45,7 +35,7 @@ nonavpage=true
    +   </div>
    + </section>
    + 
    +-<div id="useUpdatedTemplates" style="display:none" class="dac-section dac-slim dac-gray dac-expand">
    ++<div class="dac-section dac-slim dac-gray dac-expand">
    +   <div class="wrap dac-offset-parent">
    +     <a class="dac-fab dac-scroll-button" data-scroll-button href="#build-apps">
    +       <i class="dac-sprite dac-arrow-down-gray"></i>
    +@@ -73,27 +63,44 @@ nonavpage=true
    +   </div><!-- end .wrap -->
    + </div><!-- end .dac-actions -->
    + 
    +-<div id="useOldTemplates" style="display:none" class="actions-bar dac-expand dac-invert">
    +-  <div class="wrap dac-offset-parent">
    +-    <a class="dac-fab dac-scroll-button" data-scroll-button="" href="#build-apps">
    +-      <i class="dac-sprite dac-arrow-down-gray"></i>
    ++
    ++<section class="dac-expand dac-hero" style="background-color:#FFF0B4;">
    ++  <div class="wrap" style="max-width:1000px;margin-top:0;overflow:auto">
    ++    <div class="col-7of16 col-push-8of16 dac-hero-figure">
    ++      <a href="/studio/index.html">
    ++        <img class="dac-hero-image" style="padding-top:24px"
    ++          src="/studio/images/hero_image_studio_2-2_2x.png">
    ++      </a>
    ++    </div>
    ++    <div class="col-7of16 col-pull-6of16">
    ++        <h1 class="dac-hero-title" style="color:#004d40">Android Studio 2.2</h1>
    ++
    ++<p class="dac-hero-description" style="color:#004d40">Packed with 20+ new
    ++features, Android Studio 2.2 focuses on speed, smarts, and Android platform
    ++support.</p>
    ++
    ++<p class="dac-hero-description" style="color:#004d40">Develop faster with
    ++features such as the new Layout Editor, and develop smarter with the new APK
    ++analyzer, expanded code analysis and more.</p>
    ++
    ++<p class="dac-hero-description" style="color:#004d40">Plus, this update
    ++includes support for all the latest developer features in Android 7.0 Nougat,
    ++with an updated emulator to test them all out.</p>
    ++
    ++<p style="margin-top:24px">
    ++   <a class="dac-hero-cta" href="/studio/index.html" style="color:#004d40">
    ++      <span class="dac-sprite dac-auto-chevron"></span>
    ++      Get Android Studio 2.2
    +     </a>
    +-    <div class="actions">
    +-      <div><a href="{@docRoot}studio/index.html">
    +-        <span class="dac-sprite dac-auto-chevron-large"></span>
    +-        Get Android Studio
    +-      </a></div>
    +-      <div><a href="{@docRoot}samples/index.html">
    +-        <span class="dac-sprite dac-auto-chevron-large"></span>
    +-        Browse Samples
    +-      </a></div>
    +-      <div><a href="{@docRoot}distribute/stories/index.html">
    +-        <span class="dac-sprite dac-auto-chevron-large"></span>
    +-        Watch Stories
    +-      </a></div>
    +-    </div><!-- end .actions -->
    +-  </div><!-- end .wrap -->
    +-</div>
    ++  &nbsp;&nbsp;&nbsp;&nbsp;<wbr>
    ++   <a class="dac-hero-cta" href="/studio/features.html" style="color:#004d40">
    ++    <span class="dac-sprite dac-auto-chevron"></span>
    ++    See more features</a>
    ++</p>
    ++    </div>
    ++  </div>
    ++</section>
    ++
    + 
    + <section class="dac-section dac-light" id="build-apps"><div class="wrap">
    +   <h1 class="dac-section-title">Build Beautiful Apps</h1>
    +diff --git a/docs/html/jd_collections.js b/docs/html/jd_collections.js
    +deleted file mode 100644
    +index 3ceddf2..0000000
    +--- a/docs/html/jd_collections.js
    ++++ /dev/null
    +@@ -1,1935 +0,0 @@
    +-/*
    +- * THIS FILE IS DEPRECATED.
    +- *
    +- * Please add and edit resource collections in jd_extras_<lang>.js
    +- * where lang matches the language code appropriate for the resource.
    +- * Last sync'd with jd_extras_<lang>.js on 29 Apr 2016.
    +- *
    +- */
    +-var RESOURCE_COLLECTIONS = {
    +-  "index/carousel": {
    +-    "title": "",
    +-    "resources": [
    +-      "about/versions/lollipop.html"
    +-    ]
    +-  },
    +-  "index/primary": {
    +-    "title": "",
    +-    "resources": [
    +-      "training/building-wearables.html",
    +-      "training/material/index.html",
    +-      "studio/index.html"
    +-    ]
    +-  },
    +-  "index/secondary/carousel": {
    +-    "title": "",
    +-    "resources": [
    +-      "http://www.youtube.com/watch?v=9m6MoBM-sFI",
    +-      "http://www.youtube.com/watch?v=Pms0pcyPbAM",
    +-      "http://www.youtube.com/watch?v=e7t3svG9PTk",
    +-      "http://www.youtube.com/watch?v=J3IvOfvH1ys"
    +-    ]
    +-  },
    +-  "index/multiscreen": {
    +-    "title": "",
    +-    "resources": [
    +-      "wear/index.html",
    +-      "tv/index.html",
    +-      "auto/index.html"
    +-    ]
    +-  },
    +-  "index/primary/zhcn": {
    +-    "title": "",
    +-    "resources": [
    +-      "intl/zh-cn/resources.html",
    +-      "intl/zh-cn/distribute/tools/launch-checklist.html",
    +-      "intl/zh-cn/distribute/tools/localization-checklist.html"
    +-    ]
    +-  },
    +-  "design/landing/latest": {
    +-    "title": "",
    +-    "resources": [
    +-      "https://www.youtube.com/watch?v=p4gmvHyuZzw",
    +-      "https://www.youtube.com/watch?v=YaG_ljfzeUw",
    +-      "https://www.youtube.com/watch?v=XOcCOBe8PTc"
    +-    ]
    +-  },
    +-  "design/landing/materialdesign": {
    +-    "title": "",
    +-    "resources": [
    +-      "https://www.google.com/design/spec/animation/",
    +-      "https://www.google.com/design/spec/style/",
    +-      "https://www.google.com/design/spec/layout/",
    +-      "https://www.google.com/design/spec/components/",
    +-      "https://www.google.com/design/spec/patterns/",
    +-      "https://www.google.com/design/spec/usability/"
    +-    ]
    +-  },
    +-  "design/landing/pureandroid": {
    +-    "title": "",
    +-    "resources": [
    +-      "design/get-started/creative-vision.html",
    +-      "design/material/index.html",
    +-      "training/material/index.html",
    +-      "design/patterns/pure-android.html",
    +-      "design/patterns/new.html",
    +-      "design/devices.html"
    +-    ]
    +-  },
    +-  "design/landing/resources": {
    +-    "title": "",
    +-    "resources": [
    +-      "https://www.google.com/design/spec/resources/color-palettes.html",
    +-      "https://www.google.com/design/spec/resources/layout-templates.html",
    +-      "https://www.google.com/design/spec/resources/sticker-sheets-icons.html",
    +-      "https://www.google.com/design/spec/resources/roboto-noto-fonts.html",
    +-      "https://www.google.com/design/icons/index.html",
    +-      "design/downloads/index.html#Wear"
    +-    ]
    +-  },
    +-  "develop/landing/mainlinks": {
    +-    "title": "",
    +-    "resources": [
    +-      "tools/studio/index.html",
    +-      "samples/new/index.html",
    +-      "tools/projects/templates.html"
    +-    ]
    +-  },
    +-  "develop/landing/latest": {
    +-    "title": "",
    +-    "resources": [
    +-      "https://android-developers.blogspot.com/2015/04/new-android-code-samples.html",
    +-      "https://android-developers.blogspot.com/2015/04/android-support-library-221.html",
    +-      "https://android-developers.blogspot.com/2015/03/a-new-reference-app-for-multi-device.html"
    +-    ]
    +-  },
    +-  "develop/landing/devpatterns": {
    +-    "title": "",
    +-    "resources": [
    +-      "https://www.youtube.com/watch?v=kmUGLURRPkI",
    +-      "https://www.youtube.com/watch?v=HGElAW224dE",
    +-      "https://www.youtube.com/watch?v=zQekzaAgIlQ"
    +-    ]
    +-  },
    +-  "develop/landing/performance": {
    +-    "title": "",
    +-    "resources": [
    +-      "https://www.youtube.com/watch?v=fEEulSk1kNY",
    +-      "https://www.youtube.com/watch?v=-3ry8PxcJJA",
    +-      "https://www.youtube.com/watch?v=_kKTGK-Cb_4"
    +-    ]
    +-  },
    +-  "develop/landing/buildwithgoogle": {
    +-    "title": "",
    +-    "resources": [
    +-    ]
    +-  },
    +-  "develop/landing/ubicomp": {
    +-    "title": "",
    +-    "resources": [
    +-      "https://www.youtube.com/watch?v=AK38PJZmIW8&list=PLWz5rJ2EKKc-kIrPiq098QH9dOle-fLef",
    +-      "https://www.youtube.com/watch?v=6K_jxccHv5M&index=1&list=PLOU2XLYxmsILFBfx66ens76VMLMEPJAB0",
    +-      "https://www.youtube.com/watch?v=ctiaVxgclsg&list=PLWz5rJ2EKKc9BdE_PSLNIGjXXr3h_orXM"
    +-    ]
    +-  },
    +-  "develop/landing/tools": {
    +-    "title": "",
    +-    "resources": [
    +-      "https://www.youtube.com/watch?v=K2dodTXARqc&list=PLWz5rJ2EKKc8I9gHTMh5yKkwRRGE8BjbQ",
    +-      "https://www.youtube.com/watch?v=cD7NPxuuXYY&list=PLWz5rJ2EKKc8I9gHTMh5yKkwRRGE8BjbQ",
    +-      "https://www.youtube.com/watch?v=JLLnhwtDoHw&list=PLWz5rJ2EKKc8I9gHTMh5yKkwRRGE8BjbQ",
    +-      "https://www.youtube.com/watch?v=2I6fuD20qlY&list=PLWz5rJ2EKKc8I9gHTMh5yKkwRRGE8BjbQ",
    +-      "https://www.youtube.com/watch?v=5Be2mJzP-Uw&list=PLWz5rJ2EKKc9e0d55YHgJFHXNZbGHEXJX"
    +-    ]
    +-  },
    +-  "preview/landing/resources": {
    +-    "title": "",
    +-    "resources": [
    +-      "preview/overview.html",
    +-      "preview/api-overview.html",
    +-      "preview/behavior-changes.html",
    +-      "preview/setup-sdk.html",
    +-      "preview/samples.html",
    +-      "preview/support.html"
    +-    ]
    +-  },
    +-  "preview/landing/more": {
    +-    "title": "",
    +-    "resources": [
    +-      "https://www.youtube.com/watch?v=CsulIu3UaUM",
    +-      "preview/features/multi-window.html",
    +-      "preview/features/notification-updates.html",
    +-      "preview/features/background-optimization.html",
    +-      "preview/features/data-saver.html",
    +-      "preview/features/direct-boot.html",
    +-      "preview/features/icu4j-framework.html",
    +-      "preview/features/multilingual-support.html",
    +-      "preview/features/scoped-folder-access.html",
    +-      "preview/features/picture-in-picture.html",
    +-      "preview/features/tv-recording-api.html"
    +-    ]
    +-  },
    +-  "wear/preview/landing": {
    +-    "title": "",
    +-    "resources": [
    +-      "wear/preview/api-overview.html",
    +-      "wear/preview/downloads.html",
    +-      "wear/preview/start.html"
    +-    ]
    +-  },
    +-  "wear/preview/landing/resources": {
    +-    "title": "",
    +-    "resources": [
    +-      "wear/preview/features/complications.html",
    +-      "wear/preview/features/notifications.html",
    +-      "wear/preview/features/ui-nav-actions.html"
    +-    ]
    +-  },
    +-  "google/landing/services": {
    +-    "title": "",
    +-    "resources": [
    +-      "https://developers.google.com/analytics/devguides/collection/android/",
    +-      "https://developers.google.com/maps/documentation/android/",
    +-      "https://developers.google.com/identity/sign-in/android/",
    +-      "https://developers.google.com/mobile-ads-sdk/download",
    +-      "https://developers.google.com/cloud-messaging/gcm",
    +-      "https://developers.google.com/app-indexing/"
    +-    ]
    +-  },
    +-  "google/landing/videos": {
    +-    "title": "",
    +-    "resources": [
    +-      "https://www.youtube.com/watch?v=M3Udfu6qidk&list=PLWz5rJ2EKKc9Qk1_iCZNbBp6adYnJf9Vf",
    +-      "https://www.youtube.com/watch?v=FOn64iqlphk&list=PLWz5rJ2EKKc9Qk1_iCZNbBp6adYnJf9Vf",
    +-      "https://www.youtube.com/watch?v=F0Kh_RnSM0w&list=PLWz5rJ2EKKc9Qk1_iCZNbBp6adYnJf9Vf",
    +-      "https://www.youtube.com/watch?v=fvtMtfCuEpw&list=PLWz5rJ2EKKc9Qk1_iCZNbBp6adYnJf9Vf"
    +-    ]
    +-  },
    +-  "google/landing/googleplay": {
    +-    "title": "",
    +-    "resources": [
    +-      "google/play/billing/index.html",
    +-      "google/play/billing/billing_subscriptions.html",
    +-      "google/play/developer-api.html"
    +-    ]
    +-  },
    +-  "develop/landing/courses": {
    +-    "title": "",
    +-    "resources": [
    +-      "https://www.udacity.com/course/ud849",
    +-      "https://www.udacity.com/course/ud853",
    +-      "https://www.udacity.com/course/ud825",
    +-      "https://www.udacity.com/android",
    +-      "https://www.udacity.com/course/ud855",
    +-      "https://www.udacity.com/course/ud875A",
    +-      "https://www.udacity.com/course/ud875B",
    +-      "https://www.udacity.com/course/ud875C",
    +-      "https://www.udacity.com/course/ud876--1",
    +-      "https://www.udacity.com/course/ud876--2",
    +-      "https://www.udacity.com/course/ud876--3",
    +-      "https://www.udacity.com/course/ud876--4",
    +-      "https://www.udacity.com/course/ud876--5",
    +-      "https://www.udacity.com/course/ud862",
    +-      "https://www.udacity.com/course/ud837",
    +-      "https://www.udacity.com/course/ud867"
    +-    ]
    +-  },
    +-  "distribute/landing/carousel": {
    +-    "title": "",
    +-    "resources": [
    +-    "distribute/googleplay/guide.html",
    +-    "https://www.youtube.com/watch?v=JrR6o5tYMWQ",
    +-    "https://www.youtube.com/watch?v=B6ydLpkhq04&list=PLOU2XLYxmsIKLNUPiFCWVtcO7mZRZ9MmS",
    +-    "https://www.youtube.com/watch?v=yJisuP94lHU",
    +-    ]
    +-  },
    +-  "distribute/landing/googleplay": {
    +-    "title": "",
    +-    "resources": [
    +-      "distribute/googleplay/about.html",
    +-      "distribute/googleplay/developer-console.html",
    +-      "distribute/googleplay/index.html#opportunities"
    +-    ]
    +-  },
    +-  "distribute/landing/more": {
    +-    "title": "",
    +-    "resources": [
    +-      "distribute/users/promote-with-ads.html",
    +-      "distribute/monetize/ads.html",
    +-      "distribute/analyze/index.html",
    +-      "distribute/engage/deep-linking.html",
    +-      "distribute/engage/easy-signin.html",
    +-      "https://cloud.google.com/docs/"
    +-    ]
    +-  },
    +-  "distribute/edu/videos/stories": {
    +-    "title": "",
    +-    "resources": [
    +-      "https://www.youtube.com/watch?v=Idu7VcTTXfk",
    +-      "https://www.youtube.com/watch?v=iokH4SAIfRw"
    +-    ]
    +-  },
    +-  "distribute/edu/videos/bestpractices": {
    +-    "title": "",
    +-    "resources": [
    +-      "https://www.youtube.com/watch?v=iulXz8QTD1g",
    +-      "https://www.youtube.com/watch?v=IKhU180eJMo",
    +-      "https://www.youtube.com/watch?v=_AZ6UcPz-_g",
    +-      "https://www.youtube.com/watch?v=Eh2adsAyTKc"
    +-    ]
    +-  },
    +-  "distribute/edu/videos/experience": {
    +-    "title": "",
    +-    "resources": [
    +-      "https://youtu.be/vzvpcEffvaE"
    +-    ]
    +-  },
    +-/*  "launch/static": {
    +-    "title": "",
    +-    "resources": [
    +-      "https://www.youtube.com/watch?v=1RIz-cmTQB4",
    +-      "https://www.youtube.com/watch?v=MVBMWDzyHAI",
    +-      "https://android-developers.blogspot.com/2013/11/app-translation-service-now-available.html",
    +-      "https://android-developers.blogspot.com/2013/10/more-visibility-for-tablet-apps-in.html",
    +-      "https://android-developers.blogspot.com/2013/11/bring-your-apps-into-classroom-with.html",
    +-      "distribute/essentials/quality/tablets.html",
    +-      "distribute/users/build-buzz.html",
    +-      "distribute/monetize/premium.html",
    +-      "distribute/monetize/freemium.html",
    +-      "distribute/monetize/ads.html",
    +-      "distribute/essentials/best-practices/apps.html",
    +-      "distribute/essentials/best-practices/games.html",
    +-      "distribute/users/know-your-user.html",
    +-      "distribute/googleplay/developer-console.html"
    +-    ]
    +-  }, */
    +-  "launch/static/ja": {
    +-    "title": "",
    +-    "resources": [
    +-      "https://www.youtube.com/watch?v=xelYnWcYkuE",
    +-      "https://www.youtube.com/playlist?list=PLCOC_kP3nqGIHEgwm9mybvA04Vn4Cg9nn",
    +-      "https://googledevjp.blogspot.jp/2014/12/android-wear.html",
    +-      "https://googledevjp.blogspot.jp/2014/12/android-studio-10.html",
    +-      "https://googledevjp.blogspot.jp/2014/12/google-play-65.html",
    +-      "intl/ja/distribute/googleplay/developer-console.html#alpha-beta",
    +-      "intl/ja/distribute/googleplay/guide.html",
    +-      "intl/ja/distribute/essentials/quality/core.html",
    +-      "https://support.google.com/googleplay/android-developer/answer/4430948?hl=ja",
    +-      "intl/ja/support.html",
    +-      "intl/ja/distribute/essentials/quality/wear.html",
    +-      "intl/ja/training/tv/start/index.html",
    +-      "https://googleforwork-japan.blogspot.jp/2014/12/gcp-google-cloud-platform-rpg-gcp.html",
    +-      "intl/ja/distribute/monetize/ads.html"
    +-    ]
    +-  },
    +-  "launch/static/ko": {
    +-    "title": "",
    +-    "resources": [
    +-      "https://www.youtube.com/watch?v=7X9Ue0Nfdh4&index=2&list=PL_WJkTbDHdBksDBRoqfeyLchEQqBAOlNl",
    +-      "https://www.youtube.com/watch?v=83FpwuschCQ",
    +-      "https://googledevkr.blogspot.com/2014/11/android50guidefordevelopers.html",
    +-      "https://googledevkr.blogspot.com/2014/10/material-design-on-android-checklist.html",
    +-      "https://googledevkr.blogspot.com/2014/10/appcompat-v21-material-design-for-pre.html",
    +-      "intl/ko/distribute/googleplay/developer-console.html#alpha-beta",
    +-      "intl/ko/distribute/googleplay/guide.html",
    +-      "intl/ko/distribute/essentials/quality/core.html",
    +-      "https://support.google.com/googleplay/android-developer/answer/4430948?hl=ko",
    +-      "intl/ko/support.html",
    +-      "intl/ko/distribute/essentials/quality/wear.html",
    +-      "intl/ko/tv/index.html",
    +-      "intl/ko/google/play-services/games.html",
    +-      "intl/ko/distribute/monetize/ads.html"
    +-    ]
    +-  },
    +-  "distribute/gp/gplanding": {
    +-    "resources": [
    +-      "distribute/googleplay/about.html",
    +-      "distribute/googleplay/start.html",
    +-      "distribute/googleplay/developer-console.html"
    +-    ]
    +-  },
    +-  "distribute/gp/gpfelanding": {
    +-    "resources": [
    +-      "distribute/googleplay/wear.html",
    +-      "distribute/googleplay/tv.html",
    +-      "distribute/googleplay/auto.html",
    +-      "distribute/googleplay/families/about.html",
    +-      "distribute/googleplay/work/about.html",
    +-      "distribute/googleplay/edu/about.html",
    +-      "distribute/googleplay/cast.html",
    +-      "distribute/googleplay/cardboard.html",
    +-      "distribute/googleplay/guide.html"
    +-    ]
    +-  },
    +-  "distribute/googleplay/gpfw": {
    +-    "resources": [
    +-      "https://www.android.com/work/",
    +-      "https://www.youtube.com/watch?v=jQWB_-o1kz4&list=PLOU2XLYxmsIKAK2Bhv19H2THwF-22O5WX",
    +-      "work/index.html"
    +-    ]
    +-  },
    +-  "distribute/essentials": {
    +-    "resources": [
    +-      "distribute/essentials/quality/core.html",
    +-      "distribute/essentials/quality/tablets.html",
    +-      "distribute/essentials/quality/tv.html",
    +-      "distribute/essentials/quality/wear.html",
    +-      "distribute/essentials/quality/auto.html",
    +-      "distribute/essentials/quality/billions.html"
    +-    ]
    +-  },
    +-  "distribute/essentials/zhcn": {
    +-    "resources": [
    +-      "intl/zh-cn/distribute/essentials/quality/core.html",
    +-      "intl/zh-cn/distribute/essentials/quality/tablets.html",
    +-      "distribute/essentials/quality/tv.html",
    +-      "distribute/essentials/quality/wear.html",
    +-      "https://developers.google.com/edu/guidelines",
    +-      "distribute/essentials/optimizing-your-app.html"
    +-    ]
    +-  },
    +-  "distribute/users": {
    +-    "title": "",
    +-    "resources": [
    +-      "distribute/users/your-listing.html",
    +-      "distribute/users/promote-with-ads.html",
    +-      "distribute/googleplay/index.html#opportunities",
    +-      "distribute/analyze/improve-roi.html",
    +-      "distribute/users/expand-to-new-markets.html",
    +-      "distribute/analyze/index.html",
    +-      "distribute/users/app-invites.html",
    +-      "distribute/users/ota-installs.html",
    +-      "distribute/users/youtube.html",
    +-      "distribute/users/house-ads.html",
    +-      "distribute/users/experiments.html",
    +-      "distribute/users/user-acquisition.html",
    +-      "distribute/users/banners.html",
    +-      "distribute/users/beta.html"
    +-    ]
    +-  },
    +-  "distribute/engagelanding": {
    +-    "resources": [
    +-      "distribute/engage/intents.html",
    +-      "distribute/engage/widgets.html",
    +-      "distribute/engage/translate.html",
    +-      "distribute/engage/notifications.html",
    +-      "distribute/engage/deep-linking.html",
    +-      "distribute/engage/ads.html",
    +-      "distribute/engage/game-services.html",
    +-      "distribute/engage/easy-signin.html",
    +-      "distribute/analyze/build-better-apps.html",
    +-      "distribute/engage/gcm.html",
    +-      "distribute/engage/beta.html",
    +-      "distribute/engage/nearby.html"
    +-    ]
    +-  },
    +-  "distribute/monetize": {
    +-    "resources": [
    +-      "distribute/monetize/premium.html",
    +-      "distribute/monetize/freemium.html",
    +-      "distribute/monetize/subscriptions.html",
    +-      "distribute/monetize/ads.html",
    +-      "distribute/monetize/ecommerce.html",
    +-      "distribute/monetize/payments.html",
    +-      "distribute/monetize/conversions.html",
    +-      "distribute/analyze/understand-user-value.html",
    +-    ]
    +-  },
    +-  "distribute/analyzelanding": {
    +-    "resources": [
    +-      "distribute/analyze/start.html",
    +-      "distribute/analyze/measure.html",
    +-      "distribute/analyze/understand-user-value.html",
    +-      "distribute/analyze/improve-roi.html",
    +-      "distribute/analyze/build-better-apps.html",
    +-      "distribute/analyze/google-services.html"
    +-    ]
    +-  },
    +-  "distribute/analyzestart": {
    +-    "resources": [
    +-      "https://analyticsacademy.withgoogle.com/course04",
    +-      "google/play-services/index.html",
    +-      "https://developers.google.com/analytics/solutions/mobile-implementation-guide",
    +-      "https://developers.google.com/analytics/devguides/collection/android/",
    +-      "https://www.google.com/tagmanager/",
    +-      "https://github.com/googleanalytics/google-analytics-plugin-for-unity"
    +-    ]
    +-  },
    +-  "distribute/analyzemeasure": {
    +-    "resources": [
    +-
    +-      "https://developers.google.com/analytics/solutions/mobile-implementation-guide",
    +-      "https://developers.google.com/analytics/devguides/collection/android/v4/enhanced-ecommerce",
    +-      "https://support.google.com/analytics/answer/1032415",
    +-      "https://developers.google.com/analytics/devguides/collection/android/v4/events",
    +-      "https://developers.google.com/analytics/devguides/collection/android/v4/customdimsmets",
    +-      "https://developers.google.com/analytics/devguides/collection/android/v4/user-id"
    +-    ]
    +-  },
    +-  "distribute/analyzeunderstand": {
    +-    "resources": [
    +-      "https://developers.google.com/analytics/devguides/collection/android/v4/display-features",
    +-      "https://support.google.com/analytics/answer/3123906",
    +-      "https://support.google.com/analytics/answer/2568874?ref_topic=6012392",
    +-      "https://developers.google.com/analytics/devguides/collection/android/v4/enhanced-ecommerce",
    +-      "https://support.google.com/analytics/answer/1032415",
    +-    ]
    +-  },
    +-  "distribute/analyzeimprove": {
    +-    "resources": [
    +-
    +-      "https://developers.google.com/analytics/devguides/collection/android/v4/campaigns",
    +-      "https://support.google.com/analytics/answer/2956981",
    +-      "https://support.google.com/analytics/answer/1033961",
    +-      "https://developers.google.com/analytics/devguides/collection/android/v4/campaigns#google-play-url-builder",
    +-      "https://developers.google.com/analytics/solutions/mobile-campaign-deep-link"
    +-    ]
    +-  },
    +-  "distribute/analyzebuild": {
    +-    "resources": [
    +-      "https://support.google.com/tagmanager/answer/6003007",
    +-      "https://support.google.com/analytics/answer/2785577",
    +-      "https://support.google.com/analytics/answer/1151300"
    +-    ]
    +-  },
    +-  "distribute/analyzeact": {
    +-    "resources": [
    +-      "https://support.google.com/analytics/answer/2611268",
    +-      "https://support.google.com/analytics/answer/1033961",
    +-      "https://support.google.com/admob/answer/3508177",
    +-      "https://support.google.com/analytics/answer/2956981",
    +-      "https://support.google.com/tagmanager/answer/6003007"
    +-    ]
    +-  },
    +-  "distribute/essentials/guidelines": {
    +-    "title": "",
    +-    "resources": [
    +-      "distribute/essentials/quality/core.html",
    +-      "distribute/essentials/quality/tablets.html",
    +-      "distribute/essentials/quality/wear.html",
    +-      "distribute/essentials/quality/tv.html",
    +-      "distribute/essentials/quality/auto.html",
    +-      "distribute/essentials/quality/billions.html"
    +-    ]
    +-  },
    +-  "distribute/essentials/tools": {
    +-    "title": "",
    +-    "resources": [
    +-      "distribute/tools/launch-checklist.html",
    +-      "distribute/tools/localization-checklist.html",
    +-      "https://support.google.com/googleplay/android-developer",
    +-      "distribute/tools/promote/brand.html",
    +-      "distribute/tools/promote/device-art.html",
    +-      "https://play.google.com/intl/en_us/badges/",
    +-      "distribute/tools/promote/linking.html",
    +-      "distribute/tools/open-distribution.html",
    +-      "about/dashboards/index.html"
    +-    ]
    +-  },
    +-  "distribute/tools/checklists": {
    +-    "title": "",
    +-    "resources": [
    +-      "distribute/tools/launch-checklist.html",
    +-      "distribute/tools/localization-checklist.html"
    +-    ]
    +-  },
    +-  "distribute/tools/checklists/zhcn": {
    +-    "title": "",
    +-    "resources": [
    +-      "intl/zh-cn/distribute/tools/launch-checklist.html",
    +-      "intl/zh-cn/distribute/tools/localization-checklist.html"
    +-    ]
    +-  },
    +-  "distribute/tools/promote": {
    +-    "resources": [
    +-      "distribute/tools/promote/device-art.html",
    +-      "https://play.google.com/intl/en_us/badges/",
    +-      "distribute/tools/promote/linking.html"
    +-    ]
    +-  },
    +-  "distribute/tools/promote/zhcn": {
    +-    "resources": [
    +-      "intl/zh-cn/distribute/tools/promote/device-art.html",
    +-      "https://play.google.com/intl/en_us/badges/",
    +-      "intl/zh-cn/distribute/tools/promote/linking.html"
    +-    ]
    +-  },
    +-  "distribute/tools/support": {
    +-    "title": "Google Play",
    +-    "resources": [
    +-      "https://support.google.com/googleplay/android-developer",
    +-      "https://support.google.com/googleplay/android-developer/answer/4430948",
    +-      "support.html"
    +-    ]
    +-  },
    +-  "distribute/tools/support/zhcn": {
    +-    "title": "Google Play",
    +-    "resources": [
    +-      "https://support.google.com/googleplay/android-developer?hl=zh-Hans",
    +-      "https://support.google.com/googleplay/android-developer/answer/4430948?hl=zh-Hans",
    +-      "support.html"
    +-    ]
    +-  },
    +-  "distribute/tools/news": {
    +-    "title": "",
    +-    "resources": [
    +-      "https://android-developers.blogspot.com/",
    +-      "https://plus.google.com/+AndroidDevelopers/"
    +-    ]
    +-  },
    +-  "distribute/tools/more": {
    +-    "title": "Google Play",
    +-    "resources": [
    +-      "distribute/tools/promote/brand.html",
    +-      "distribute/tools/open-distribution.html",
    +-      "about/dashboards/index.html"
    +-    ]
    +-  },
    +-  "distribute/tools/more/zhcn": {
    +-    "title": "Google Play",
    +-    "resources": [
    +-      "intl/zh-cn/distribute/tools/promote/brand.html",
    +-      "distribute/tools/open-distribution.html",
    +-      "about/dashboards/index.html"
    +-    ]
    +-  },
    +-  "distribute/googleplay": {
    +-    "title": "Google Play",
    +-    "resources": [
    +-      "distribute/googleplay/developer-console.html",
    +-      "distribute/essentials/best-practices/apps.html",
    +-      "distribute/tools/launch-checklist.html",
    +-      "distribute/essentials/best-practices/games.html",
    +-    ]
    +-  },
    +-  "distribute/googleplay/gettingstarted": {
    +-    "title": "Get Started",
    +-    "resources": [
    +-      "distribute/googleplay/developer-console.html",
    +-      "https://support.google.com/googleplay/android-developer/answer/113468",
    +-      "https://support.google.com/googleplay/android-developer/answer/138294",
    +-      "https://support.google.com/googleplay/android-developer"
    +-    ]
    +-  },
    +-  "distribute/googleplay/developerconsole/related": {
    +-    "title": "Developer Console",
    +-    "resources": [
    +-      "google/play/billing/index.html",
    +-      "https://support.google.com/googleplay/android-developer/answer/138294"
    +-    ]
    +-  },
    +-  "distribute/googleplay/beta": {
    +-    "title": "Alpha and Beta Testing",
    +-    "resources": [
    +-      "https://support.google.com/googleplay/android-developer/answer/3131213",
    +-      "https://support.google.com/googleplay/android-developer/answer/3131213#games",
    +-      "distribute/googleplay/experiments.html"
    +-    ]
    +-  },
    +-  "distribute/googleplay/experiments/successes": {
    +-    "title": "Store Listing Experiment successes",
    +-    "resources": [
    +-    ]
    +-  },
    +-  "distribute/googleplay/experiments/related": {
    +-    "title": "Store Listing Experiments",
    +-    "resources": [
    +-      "https://support.google.com/googleplay/android-developer/answer/6227309",
    +-      "https://www.youtube.com/watch?v=B6ydLpkhq04",
    +-      "https://support.google.com/tagmanager/answer/6003007"
    +-    ]
    +-  },
    +-  "distribute/googleplay/banners/related": {
    +-    "title": "App Install Banners",
    +-    "resources": [
    +-      "https://developers.google.com/web/updates/2015/03/increasing-engagement-with-app-install-banners-in-chrome-for-android#native"
    +-    ]
    +-  },
    +-  "distribute/googleplay/useracquisition/related": {
    +-    "title": "User Acquisition",
    +-    "resources": [
    +-      "https://support.google.com/googleplay/android-developer/answer/6263332"
    +-    ]
    +-  },
    +-  "distribute/googleplay/cast": {
    +-    "title": "Google Cast",
    +-    "resources": [
    +-      "https://developers.google.com/cast/docs/ux_guidelines",
    +-      "https://developers.google.com/cast/docs/android_sender",
    +-      "https://www.github.com/googlecast"
    +-    ]
    +-  },
    +-  "distribute/googleplay/cardboard": {
    +-    "title": "Google Cast",
    +-    "resources": [
    +-      "https://www.google.com/get/cardboard/get-cardboard/",
    +-      "https://developers.google.com/cardboard/android/download",
    +-      "https://www.google.com/design/spec-vr"
    +-    ]
    +-  },
    +-  "distribute/googleplay/gpfe/highlight": {
    +-    "title": "About Google Play for Education",
    +-    "resources": [
    +-      "https://youtu.be/vzvpcEffvaE"
    +-    ]
    +-  },
    +-  "distribute/googleplay/gpfe/dev/about": {
    +-    "title": "About Google Play for Education / Developers",
    +-    "resources": [
    +-      "distribute/googleplay/edu/start.html",
    +-      "https://developers.google.com/edu/guidelines",
    +-      "https://developers.google.com/edu/faq",
    +-      "distribute/essentials/quality/tablets.html",
    +-      "https://developers.google.com/edu/",
    +-      "https://www.google.com/edu/tablets/#tablets-family"
    +-    ]
    +-  },
    +-  "distribute/googleplay/gpfe/dev": {
    +-    "title": "About Google Play for Education / Developers",
    +-    "resources": [
    +-      "distribute/googleplay/edu/about.html",
    +-      "https://developers.google.com/edu/guidelines",
    +-      "distribute/essentials/quality/tablets.html",
    +-      "distribute/googleplay/developer-console.html",
    +-      "https://play.google.com/about/developer-distribution-agreement-addendum.html",
    +-    ]
    +-  },
    +-  "distribute/googleplay/aboutgpfe/educators/about": {
    +-    "title": "About Google Play for Education / Educators",
    +-    "resources": [
    +-      "https://www.google.com/edu/tablets/",
    +-      "https://www.youtube.com/watch?v=haEmsMo0f3w"
    +-    ]
    +-  },
    +-  "distribute/googleplay/aboutgpfe/educators": {
    +-    "title": "About Google Play for Education / Educators",
    +-    "resources": [
    +-      "https://www.google.com/edu/tablets/",
    +-      "https://youtu.be/vzvpcEffvaE"
    +-    ]
    +-  },
    +-  "distribute/googleplay/gettingstartedgpfe/educators": {
    +-    "title": "About Google Play for Education / Educators",
    +-    "resources": [
    +-      "https://www.google.com/edu/tablets/",
    +-      "https://youtu.be/vzvpcEffvaE"
    +-    ]
    +-  },
    +-  "distribute/essentials/eduessentials/developers": {
    +-    "title": "",
    +-    "resources": [
    +-      "distribute/googleplay/developer-console.html",
    +-      "distribute/googleplay/edu/start.html",
    +-      "https://developers.google.com/edu/faq"
    +-    ]
    +-  },
    +-  "distribute/essentials/eduessentials/educators": {
    +-    "title": "",
    +-    "resources": [
    +-      "https://www.google.com/edu/tablets/",
    +-      "distribute/essentials/quality/tablets.html",
    +-    ]
    +-  },
    +-  "distribute/essentials/optimizing": {
    +-    "title": "Optimizing Your App",
    +-    "resources": [
    +-      "design/index.html",
    +-      "training/articles/perf-anr.html",
    +-      "https://android-developers.blogspot.com/2013/10/improved-app-insight-by-linking-google.html"
    +-     ]
    +-  },
    +-  "distribute/users/appinvites": {
    +-    "title": "",
    +-    "resources": [
    +-      "https://developers.google.com/app-invites/",
    +-      "https://developers.google.com/identity/sign-in/android/",
    +-      "https://developers.google.com/app-indexing/"
    +-    ]
    +-  },
    +-  "distribute/users/knowyouruser": {
    +-    "title": "",
    +-    "resources": [
    +-      "distribute/essentials/optimizing-your-app.html",
    +-      "http://www.youtube.com/watch?v=RRelFvc6Czo",
    +-      "distribute/stories/games/rvappstudios-zombie.html"
    +-    ]
    +-  },
    +-  "distribute/users/promotewithads": {
    +-    "title": "",
    +-    "resources": [
    +-      "https://support.google.com/adwords/answer/6032059",
    +-      "https://support.google.com/adwords/answer/6032073",
    +-      "https://support.google.com/adwords/answer/6167164",
    +-      "https://support.google.com/adwords/answer/6167162"
    +-    ]
    +-  },
    +-  "distribute/users/nearby": {
    +-    "title": "",
    +-    "resources": [
    +-      "https://developers.google.com/nearby/",
    +-      "https://www.youtube.com/watch?v=hultDpBS22s",
    +-      "https://developers.google.com/beacons"
    +-    ]
    +-  },
    +-  "distribute/users/buildbuzz": {
    +-    "title": "",
    +-    "resources": [
    +-      "https://play.google.com/intl/en_us/badges/",
    +-      "distribute/tools/promote/linking.html",
    +-      "distribute/tools/promote/device-art.html",
    +-      "https://plus.google.com/+GooglePlay"
    +-    ]
    +-  },
    +-  "distribute/users/createagreatlisting": {
    +-    "title": "",
    +-    "resources": [
    +-      "https://support.google.com/googleplay/android-developer/answer/1078870",
    +-      "https://android-developers.blogspot.com/2011/10/android-market-featured-image.html",
    +-      "distribute/tools/launch-checklist.html",
    +-      "https://android-developers.blogspot.com/2013/07/making-beautiful-android-app-icons.html",
    +-      "https://android-developers.blogspot.com/2012/12/localize-your-promotional-graphics-on.html",
    +-      "https://android-developers.blogspot.com/2013/10/making-your-app-content-more-accessible.html"
    +-    ]
    +-  },
    +-  "distribute/users/buildcommunity": {
    +-    "title": "",
    +-    "resources": [
    +-      "distribute/googleplay/developer-console.html",
    +-      "https://support.google.com/groups/answer/46601",
    +-      "https://support.google.com/plus/topic/2888488",
    +-      "https://www.youtube.com/yt/dev/"
    +-    ]
    +-  },
    +-  "distribute/users/appindexing": {
    +-    "title": "",
    +-    "resources": [
    +-      "https://developers.google.com/app-indexing/",
    +-      "https://developers.google.com/app-indexing/webmasters/details",
    +-      "distribute/engage/deep-linking.html",
    +-      "training/app-indexing/index.html"
    +-    ]
    +-  },
    +-  "distribute/users/otas": {
    +-    "title": "",
    +-    "resources": [
    +-      "https://developers.google.com/identity/sign-in/android/",
    +-      "https://developers.google.com/+/features/play-installs",
    +-      "https://developers.google.com/+/features/analytics"
    +-    ]
    +-  },
    +-  "distribute/users/houseads": {
    +-    "title": "",
    +-    "resources": [
    +-      "https://support.google.com/admob/topic/2784623",
    +-      "https://developers.google.com/mobile-ads-sdk/download",
    +-      "https://support.google.com/googleplay/android-developer/topic/2985714",
    +-      "https://analyticsacademy.withgoogle.com/mobile-app",
    +-      "https://support.google.com/analytics/answer/2611404",
    +-      "https://support.google.com/admob/answer/3111064"
    +-    ]
    +-  },
    +-  "distribute/users/youtube": {
    +-    "title": "",
    +-    "resources": [
    +-      "https://support.google.com/youtube/answer/6140493",
    +-      "https://support.google.com/youtube/answer/2797387"
    +-    ]
    +-  },
    +-  "distribute/toolsreference/bestpractices/apps": {
    +-    "title": "",
    +-    "resources": [
    +-      "distribute/googleplay/developer-console.html",
    +-      "https://android-developers.blogspot.com/"
    +-    ]
    +-  },
    +-  "distribute/toolsreference/bestpractices/games": {
    +-    "title": "",
    +-    "resources": [
    +-      "google/play-services/games.html",
    +-      "https://android-developers.blogspot.com/",
    +-      "distribute/googleplay/developer-console.html",
    +-      "https://www.youtube.com/watch?v=1RIz-cmTQB4"
    +-    ]
    +-  },
    +-  "distribute/essentials/corequalityguidelines/visualdesign": {
    +-    "title": "",
    +-    "resources": [
    +-      "design/index.html",
    +-      "design/patterns/navigation.html",
    +-      "design/patterns/actionbar.html",
    +-      "design/style/iconography.html"
    +-    ]
    +-  },
    +-  "distribute/essentials/corequalityguidelines/functionality": {
    +-    "title": "",
    +-    "resources": [
    +-      "https://android-developers.blogspot.com/2011/11/making-android-games-that-play-nice.html",
    +-      "guide/components/tasks-and-back-stack.html",
    +-      "training/basics/activity-lifecycle/recreating.html"
    +-    ]
    +-  },
    +-  "distribute/essentials/tvqualityguidelines/visualdesign": {
    +-    "title": "",
    +-    "resources": [
    +-      "design/tv/index.html",
    +-      "training/tv/start/index.html"
    +-    ]
    +-  },
    +-  "distribute/essentials/tvqualityguidelines/functionality": {
    +-    "title": "",
    +-    "resources": [
    +-      "training/tv/start/hardware.html",
    +-      "training/tv/games/index.html"
    +-    ]
    +-  },
    +-  "distribute/essentials/wearqualityguidelines/visualdesign": {
    +-    "title": "",
    +-    "resources": [
    +-      "design/wear/index.html",
    +-      "training/building-wearables.html",
    +-      "training/wearables/ui/index.html"
    +-    ]
    +-  },
    +-  "distribute/essentials/wearqualityguidelines/functionality": {
    +-    "title": "",
    +-    "resources": [
    +-      "training/wearables/notifications/index.html",
    +-      "training/wearables/apps/index.html",
    +-      "training/wearables/notifications/voice-input.html"
    +-    ]
    +-  },
    +-    "distribute/essentials/autoqualityguidelines/visualdesign": {
    +-    "title": "",
    +-    "resources": [
    +-      "training/auto/messaging/index.html",
    +-      "training/auto/start/index.html"
    +-    ]
    +-  },
    +-  "distribute/essentials/core/performance": {
    +-    "title": "",
    +-    "resources": [
    +-      "https://android-developers.blogspot.com/2010/12/new-gingerbread-api-strictmode.html",
    +-      "training/articles/perf-anr.html",
    +-      "https://android-developers.blogspot.com/2010/07/multithreading-for-performance.html"
    +-    ]
    +-  },
    +-  "distribute/essentials/core/play": {
    +-    "title": "",
    +-    "resources": [
    +-      "distribute/tools/launch-checklist.html",
    +-      "https://play.google.com/about/developer-content-policy.html?hl=zh-Hans",
    +-      "https://support.google.com/googleplay/android-developer/answer/188189?hl=zh-Hans",
    +-      "https://support.google.com/googleplay/android-developer/answer/1078870?hl=zh-Hans",
    +-      "https://android-developers.blogspot.com/2011/10/android-market-featured-image.html",
    +-      "https://support.google.com/googleplay/android-developer/answer/113477?hl=zh-Hans"
    +-    ]
    +-  },
    +-  "distribute/essentials/core/play/zhcn": {
    +-    "title": "",
    +-    "resources": [
    +-      "intl/zh-cn/distribute/tools/launch-checklist.html",
    +-      "https://play.google.com/about/developer-content-policy.html",
    +-      "https://support.google.com/googleplay/android-developer/answer/188189?hl=zh-Hans",
    +-      "https://support.google.com/googleplay/android-developer/answer/1078870?hl=zh-Hans",
    +-      "https://android-developers.blogspot.com/2011/10/android-market-featured-image.html",
    +-      "https://support.google.com/googleplay/android-developer/answer/113477?hl=zh-Hans"
    +-    ]
    +-  },
    +-  "distribute/essentials/tabletguidelines/optimize": {
    +-    "title": "",
    +-    "resources": [
    +-      "design/style/metrics-grids.html",
    +-      "design/style/devices-displays.html",
    +-      "guide/practices/screens_support.html",
    +-      //"guide/practices/screens_support.html#ConfigurationExamples",
    +-    ]
    +-  },
    +-  "distribute/essentials/tabletguidelines/extrascreen": {
    +-    "title": "",
    +-    "resources": [
    +-      "design/patterns/multi-pane-layouts.html",
    +-      "training/design-navigation/multiple-sizes.html",
    +-      "training/multiscreen/index.html",
    +-    ]
    +-  },
    +-  "distribute/essentials/tabletguidelines/assets": {
    +-    "title": "",
    +-    "resources": [
    +-      "design/style/iconography.html",
    +-      "guide/topics/resources/providing-resources.html",
    +-      "guide/practices/screens_support.html",
    +-      "training/basics/supporting-devices/screens.html"
    +-    ]
    +-  },
    +-  "distribute/essentials/tabletguidelines/fonts": {
    +-    "title": "",
    +-    "resources": [
    +-      "design/style/metrics-grids.html",
    +-      "design/style/typography.html",
    +-      "guide/practices/screens_support.html",
    +-      "training/multiscreen/screendensities.html"
    +-    ]
    +-  },
    +-  "distribute/essentials/tabletguidelines/widgets": {
    +-    "title": "",
    +-    "resources": [
    +-      "guide/topics/appwidgets/index.html#MetaData",
    +-      "guide/topics/appwidgets/index.html",
    +-      "design/patterns/widgets.html"
    +-    ]
    +-  },
    +-  "distribute/essentials/tabletguidelines/versions": {
    +-    "title": "",
    +-    "resources": [
    +-      "guide/topics/manifest/uses-sdk-element.html#ApiLevels",
    +-      "guide/topics/manifest/uses-sdk-element.html",
    +-      "training/basics/supporting-devices/platforms.html"
    +-    ]
    +-  },
    +-  "distribute/essentials/tabletguidelines/hardware": {
    +-    "title": "",
    +-    "resources": [
    +-      "guide/topics/manifest/uses-feature-element.html",
    +-      "guide/topics/manifest/uses-feature-element.html#testing"
    +-    ]
    +-  },
    +- "distribute/essentials/tabletguidelines/tabletscreens": {
    +-    "title": "",
    +-    "resources": [
    +-      "guide/practices/screens_support.html#DeclaringScreenSizeSupport",
    +-      "guide/practices/screens_support.html"
    +-    ]
    +-  },
    +-  "distribute/essentials/tabletguidelines/showcase": {
    +-    "title": "",
    +-    "resources": [
    +-      "distribute/tools/launch-checklist.html",
    +-      "https://play.google.com/apps/publish/",
    +-      "https://play.google.com/intl/en_us/badges/",
    +-      "distribute/tools/promote/device-art.html"
    +-    ]
    +-  },
    +-  "distribute/essentials/tabletguidelines/showcase/zhcn": {
    +-    "title": "",
    +-    "resources": [
    +-      "intl/zh-cn/distribute/tools/launch-checklist.html",
    +-      "https://play.google.com/apps/publish/?hl=zh-Hans",
    +-      "https://play.google.com/intl/en_us/badges/",
    +-      "intl/zh-cn/distribute/tools/promote/device-art.html"
    +-    ]
    +-  },
    +-  "distribute/essentials/tabletguidelines/googleplay": {
    +-    "title": "",
    +-    "resources": [
    +-      "https://android-developers.blogspot.com/2013/10/more-visibility-for-tablet-apps-in.html",
    +-      "google/play/filters.html"
    +-    ]
    +-  },
    +- "distribute/essentials/billionsquality/connectivity": {
    +-    "title": "",
    +-    "resources": [
    +-      "training/basics/network-ops/managing.html",
    +-      "training/monitoring-device-state/connectivity-monitoring.html",
    +-      "guide/topics/providers/content-providers.html"
    +-    ]
    +-  },
    +-  "distribute/essentials/billionsquality/capability": {
    +-    "title": "",
    +-    "resources": [
    +-      "guide/practices/screens_support.html",
    +-      "training/multiscreen/screendensities.html",
    +-      "training/articles/memory.html"
    +-    ]
    +-  },
    +-  "distribute/essentials/billionsquality/cost": {
    +-    "title": "",
    +-    "resources": [
    +-      "https://medium.com/@wkalicinski/smallerapk-part-6-image-optimization-zopfli-webp-4c462955647d#.23hlddo3x",
    +-      "training/basics/network-ops/managing.html"
    +-    ]
    +-  },
    +-  "distribute/essentials/billionsquality/consumption": {
    +-    "title": "",
    +-    "resources": [
    +-      "training/efficient-downloads/efficient-network-access.html",
    +-      "training/monitoring-device-state/index.html"
    +-    ]
    +-  },
    +-  "distribute/essentials/billionsquality/content": {
    +-    "title": "",
    +-    "resources": [
    +-      "training/material/animations.html#Touch",
    +-      "training/articles/perf-anr.html",
    +-      "training/improving-layouts/index.html"
    +-    ]
    +-  },
    +-  "distribute/essentials/tabletguidelines": {
    +-    "title": "",
    +-    "resources": [
    +-      "distribute/essentials/quality/core.html",
    +-      "https://android-developers.blogspot.com/2013/10/more-visibility-for-tablet-apps-in.html",
    +-      "distribute/tools/launch-checklist.html",
    +-      "distribute/tools/promote/device-art.html"
    +-    ]
    +-  },
    +-  "distribute/getusers/notifications": {
    +-    "title": "",
    +-    "resources": [
    +-      "distribute/engage/gcm.html",
    +-      "https://play.google.com/about/developer-content-policy.html"
    +-    ]
    +-  },
    +-  "distribute/engage/analytics": {
    +-    "title": "",
    +-    "resources": [
    +-      "https://www.google.com/analytics/mobile/",
    +-      "https://android-developers.blogspot.com/2013/10/improved-app-insight-by-linking-google.html",
    +-      "https://developers.google.com/analytics/devguides/collection/android/"
    +-    ]
    +-  },
    +-  "distribute/engage/widgets": {
    +-    "title": "",
    +-    "resources": [
    +-      "design/patterns/widgets.html",
    +-      "guide/topics/appwidgets/index.html"
    +-    ]
    +-  },
    +-  "distribute/engage/translate": {
    +-    "title": "",
    +-    "resources": [
    +-      "https://support.google.com/l10n/answer/6359997"
    +-    ]
    +-  },
    +-  "distribute/engage/reengage": {
    +-    "title": "",
    +-    "resources": [
    +-      "https://support.google.com/adwords/answer/6032073",
    +-      "distribute/engage/deep-linking.html",
    +-      "https://support.google.com/adwords/answer/6167162",
    +-      "distribute/users/promote-with-ads.html"
    +-    ]
    +-  },
    +-  "distribute/engage/appindexing": {
    +-    "title": "",
    +-    "resources": [
    +-      "distribute/engage/intents.html",
    +-      "distribute/engage/deep-linking.html",
    +-      "training/app-indexing/index.html"
    +-    ]
    +-  },
    +-  "distribute/engage/intents": {
    +-    "title": "",
    +-    "resources": [
    +-      "guide/components/intents-filters.html",
    +-      "distribute/engage/deep-linking.html",
    +-      "distribute/engage/ads.html"
    +-    ]
    +-  },
    +-  "distribute/getusers/expandnewmarkets": {
    +-    "title": "",
    +-    "resources": [
    +-      "distribute/tools/localization-checklist.html",
    +-      "https://support.google.com/googleplay/android-developer/table/3541286",
    +-      "https://play.google.com/intl/en_us/badges/",
    +-      "distribute/tools/promote/device-art.html",
    +-      "https://www.youtube.com/watch?v=SkHHPf3EdzE"
    +-    ]
    +-  },
    +-  "distribute/engage/gcm": {
    +-    "title": "",
    +-    "resources": [
    +-      "https://developers.google.com/cloud-messaging/gcm",
    +-      "https://developers.google.com/cloud-messaging/android/client",
    +-    ]
    +-  },
    +-  "distribute/engage/gamesservices/related": {
    +-    "title": "",
    +-    "resources": [
    +-      "https://developers.google.com/games/services/",
    +-      "distribute/analyze/start.html",
    +-      "distribute/googleplay/cardboard.html",
    +-      "https://www.google.com/admob/"
    +-    ]
    +-  },
    +-  "distribute/engage/gplus": {
    +-    "title": "",
    +-    "resources": [
    +-      "distribute/users/ota-installs.html",
    +-      "https://developers.google.com/identity/sign-in/android/people",
    +-      "https://developers.google.com/+/mobile/android/"
    +-    ]
    +-  },
    +-  "distribute/engage/community": {
    +-    "title": "",
    +-    "resources": [
    +-      "distribute/users/build-community.html",
    +-      "distribute/engage/video.html"
    +-    ]
    +-  },
    +-  "distribute/engage/deeplinks": {
    +-    "title": "",
    +-    "resources": [
    +-      "distribute/engage/easy-signin.html",
    +-      "https://developers.google.com/app-indexing/",
    +-      "https://developers.google.com/+/mobile/android/share/interactive-post"
    +-    ]
    +-  },
    +-  "distribute/engage/appupdates": {
    +-    "title": "",
    +-    "resources": [
    +-      "distribute/essentials/optimizing-your-app.html",
    +-      "distribute/tools/launch-checklist.html",
    +-      "distribute/googleplay/developer-console.html"
    +-    ]
    +-  },
    +-  "distribute/engage/video/more": {
    +-    "title": "",
    +-    "resources": [
    +-      "https://www.youtube.com/yt/dev/",
    +-      "distribute/essentials/best-practices/games.html",
    +-      "https://www.youtube.com/watch?v=RRelFvc6Czo"
    +-    ]
    +-  },
    +-  "distribute/engage/community": {
    +-    "title": "",
    +-    "resources": [
    +-      "distribute/users/build-community.html",
    +-      "distribute/engage/video.html"
    +-    ]
    +-  },
    +-  "distribute/engage/kiwi": {
    +-    "title": "",
    +-    "resources": [
    +-      "https://www.youtube.com/watch?v=WWArLD6nqrk"
    +-    ]
    +-  },
    +-  "distribute/toolsreference/gpfefaq": {
    +-    "title": "",
    +-    "resources": [
    +-      "https://www.google.com/edu/tablets/",
    +-      "distribute/googleplay/edu/start.html",
    +-      "https://play.google.com/about/developer-distribution-agreement-addendum.html",
    +-      "distribute/essentials/quality/core.html",
    +-      "distribute/essentials/quality/tablets.html"
    +-    ]
    +-  },
    +-  "distribute/toolsreference/localizationchecklist/identifylocales": {
    +-    "title": "",
    +-    "resources": [
    +-      "https://support.google.com/googleplay/android-developer/answer/138294"
    +-    ]
    +-  },
    +-  "distribute/toolsreference/localizationchecklist/identifylocales/zhcn": {
    +-    "title": "",
    +-    "resources": [
    +-      "https://support.google.com/googleplay/android-developer/answer/138294?hl=zh-Hans"
    +-    ]
    +-  },
    +-  "distribute/tools/loc/designforloc": {
    +-    "title": "",
    +-    "resources": [
    +-      "https://android-developers.blogspot.com/2013/03/native-rtl-support-in-android-42.html",
    +-      "guide/topics/resources/string-resource.html#Plurals",
    +-      "guide/topics/resources/string-resource.html",
    +-      "reference/java/util/Locale.html"
    +-    ]
    +-  },
    +-  "distribute/toolsreference/localizationchecklist/managestrings": {
    +-    "title": "",
    +-    "resources": [
    +-      "guide/topics/resources/string-resource.html",
    +-      "design/style/writing.html",
    +-      "https://en.wikipedia.org/wiki/XLIFF"
    +-    ]
    +-  },
    +-  "distribute/toolsreference/localizationchecklist/managestrings/zhcn": {
    +-    "title": "",
    +-    "resources": [
    +-      "guide/topics/resources/string-resource.html",
    +-      "intl/zh-cn/design/style/writing.html",
    +-      "https://en.wikipedia.org/wiki/XLIFF"
    +-    ]
    +-  },
    +-  "distribute/toolsreference/localizationchecklist/preplaunch": {
    +-    "title": "",
    +-    "resources": [
    +-      "https://play.google.com/intl/en_us/badges/",
    +-      "distribute/tools/promote/device-art.html"
    +-    ]
    +-  },
    +-  "distribute/toolsreference/localizationchecklist/preplaunch/zhcn": {
    +-    "title": "",
    +-    "resources": [
    +-      "https://play.google.com/intl/en_us/badges/",
    +-      "intl/zh-cn/distribute/tools/promote/device-art.html"
    +-    ]
    +-  },
    +-  "distribute/toolsreference/localizationchecklist/supportlaunch": {
    +-    "title": "",
    +-    "resources": [
    +-      "distribute/tools/launch-checklist.html",
    +-    ]
    +-  },
    +-  "distribute/toolsreference/localizationchecklist/supportlaunch/zhcn": {
    +-    "title": "",
    +-    "resources": [
    +-      "intl/zh-cn/distribute/tools/launch-checklist.html",
    +-    ]
    +-  },
    +-  "distribute/toolsreference/launchchecklist/understanding": {
    +-    "title": "",
    +-    "resources": [
    +-      "tools/publishing/publishing_overview.html",
    +-      "tools/publishing/preparing.html"
    +-    ]
    +-  },
    +-  "distribute/toolsreference/launchchecklist/policies": {
    +-    "title": "",
    +-    "resources": [
    +-      "https://support.google.com/googleplay/android-developer/answer/4430948",
    +-      "https://support.google.com/googleplay/android-developer/topic/2364761",
    +-      "https://support.google.com/googleplay/android-developer"
    +-    ]
    +-  },
    +-  "distribute/toolsreference/launchchecklist/quality": {
    +-    "title": "",
    +-    "resources": [
    +-      "distribute/essentials/quality/core.html",
    +-      "distribute/essentials/quality/tablets.html",
    +-      "https://developers.google.com/edu/guidelines"
    +-    ]
    +-  },
    +-  "distribute/toolsreference/launchchecklist/rating": {
    +-    "title": "",
    +-    "resources": [
    +-      "https://support.google.com/googleplay/android-developer/answer/188189",
    +-    ]
    +-  },
    +-  "distribute/toolsreference/launchchecklist/country": {
    +-    "title": "",
    +-    "resources": [
    +-      "https://support.google.com/googleplay/android-developer/answer/138294"
    +-    ]
    +-  },
    +-  "distribute/toolsreference/launchchecklist/size": {
    +-    "title": "",
    +-    "resources": [
    +-      "google/play/expansion-files.html",
    +-      "tools/help/proguard.html"
    +-    ]
    +-  },
    +-  "distribute/toolsreference/launchchecklist/platform": {
    +-    "title": "",
    +-    "resources": [
    +-      "guide/practices/screens_support.html",
    +-      "about/dashboards/index.html",
    +-      "guide/topics/manifest/uses-sdk-element.html"
    +-    ]
    +-  },
    +-  "distribute/toolsreference/launchchecklist/price": {
    +-    "title": "",
    +-    "resources": [
    +-      "https://support.google.com/googleplay/android-developer/table/3541286",
    +-    ]
    +-  },
    +-  "distribute/toolsreference/launchchecklist/purchasemethod": {
    +-    "title": "",
    +-    "resources": [
    +-      "google/play/billing/index.html",
    +-      "google/play/billing/billing_subscriptions.html"
    +-    ]
    +-  },
    +-  "distribute/toolsreference/launchchecklist/setprice": {
    +-    "title": "",
    +-    "resources": [
    +-      "https://support.google.com/googleplay/android-developer/answer/1169947",
    +-      "https://support.google.com/googleplay/android-developer/answer/138412",
    +-      "https://support.google.com/googleplay/android-developer/answer/112622",
    +-      "https://support.google.com/googleplay/android-developer/answer/138000"
    +-    ]
    +-  },
    +-  "distribute/toolsreference/launchchecklist/localization": {
    +-    "title": "",
    +-    "resources": [
    +-      "distribute/tools/localization-checklist.html",
    +-      "https://support.google.com/l10n/answer/6359997"
    +-    ]
    +-  },
    +-  "distribute/toolsreference/launchchecklist/graphics": {
    +-    "title": "",
    +-    "resources": [
    +-      "https://support.google.com/googleplay/android-developer/answer/1078870",
    +-      "https://android-developers.blogspot.com/2011/10/android-market-featured-image.html"
    +-    ]
    +-  },
    +-  "distribute/toolsreference/launchchecklist/productdetails": {
    +-    "title": "",
    +-    "resources": [
    +-      "https://support.google.com/googleplay/android-developer/answer/113475",
    +-      "https://support.google.com/googleplay/android-developer/answer/1078870"
    +-    ]
    +-  },
    +-  "distribute/toolsreference/launchchecklist/badges": {
    +-    "title": "",
    +-    "resources": [
    +-      "https://play.google.com/intl/en_us/badges/",
    +-      "distribute/tools/promote/linking.html"
    +-    ]
    +-  },
    +-  "distribute/toolsreference/launchchecklist/finalchecks": {
    +-    "title": "",
    +-    "resources": [
    +-      "https://play.google.com/about/developer-content-policy.html",
    +-      "https://support.google.com/googleplay/android-developer/answer/113476",
    +-      "support.html"
    +-    ]
    +-  },
    +-  "distribute/toolsreference/launchchecklist/afterlaunch": {
    +-    "title": "",
    +-    "resources": [
    +-      "https://support.google.com/googleplay/android-developer/answer/113477",
    +-      "https://support.google.com/googleplay/android-developer/answer/1153479",
    +-      "https://support.google.com/payments/answer/2741495",
    +-      "distribute/essentials/optimizing-your-app.html"
    +-    ]
    +-  },
    +-  "distribute/toolsreference/launchchecklist/understanding/zhcn": {
    +-    "title": "",
    +-    "resources": [
    +-      "intl/zh-cn/tools/publishing/publishing_overview.html",
    +-      "intl/zh-cn/tools/publishing/preparing.html"
    +-    ]
    +-  },
    +-  "distribute/toolsreference/launchchecklist/policies/zhcn": {
    +-    "title": "",
    +-    "resources": [
    +-      "https://support.google.com/googleplay/android-developer/answer/4430948?hl=zh-Hans",
    +-      "https://support.google.com/googleplay/android-developer/topic/2364761?hl=zh-Hans",
    +-      "https://support.google.com/googleplay/android-developer?hl=zh-Hans"
    +-    ]
    +-  },
    +-  "distribute/toolsreference/launchchecklist/quality/zhcn": {
    +-    "title": "",
    +-    "resources": [
    +-      "intl/zh-cn/distribute/essentials/quality/core.html",
    +-      "intl/zh-cn/distribute/essentials/quality/tablets.html",
    +-      "https://developers.google.com/edu/guidelines?hl=zh-Hans"
    +-    ]
    +-  },
    +-
    +-  "distribute/toolsreference/launchchecklist/rating/zhcn": {
    +-    "title": "",
    +-    "resources": [
    +-      "https://support.google.com/googleplay/android-developer/answer/188189?hl=zh-Hans",
    +-    ]
    +-  },
    +-  "distribute/toolsreference/launchchecklist/country/zhcn": {
    +-    "title": "",
    +-    "resources": [
    +-      "https://support.google.com/googleplay/android-developer/answer/138294?hl=zh-Hans"
    +-    ]
    +-  },
    +-  "distribute/toolsreference/launchchecklist/size/zhcn": {
    +-    "title": "",
    +-    "resources": [
    +-      "google/play/expansion-files.html",
    +-      "intl/zh-cn/tools/help/proguard.html"
    +-    ]
    +-  },
    +-  "distribute/toolsreference/launchchecklist/price/zhcn": {
    +-    "title": "",
    +-    "resources": [
    +-      "https://support.google.com/googleplay/android-developer/table/3541286?hl=zh-Hans",
    +-    ]
    +-  },
    +-  "distribute/toolsreference/launchchecklist/purchasemethod/zhcn": {
    +-    "title": "",
    +-    "resources": [
    +-      "intl/zh-cn/google/play/billing/index.html",
    +-      "google/play/billing/billing_subscriptions.html"
    +-    ]
    +-  },
    +-  "distribute/toolsreference/launchchecklist/setprice/zhcn": {
    +-    "title": "",
    +-    "resources": [
    +-      "https://support.google.com/googleplay/android-developer/answer/1169947?hl=zh-Hans",
    +-      "https://support.google.com/googleplay/android-developer/answer/138412?hl=zh-Hans",
    +-      "https://support.google.com/googleplay/android-developer/answer/112622?hl=zh-Hans",
    +-      "https://support.google.com/googleplay/android-developer/answer/138000?hl=zh-Hans"
    +-    ]
    +-  },
    +-  "distribute/stories/localization": {
    +-    "title": "",
    +-    "resources": [
    +-      "distribute/stories/games/rvappstudios-zombie.html",
    +-      "distribute/stories/games/g4a-indian-rummy.html",
    +-      "distribute/stories/apps/sayhi.html"
    +-    ]
    +-  },
    +-  "distribute/toolsreference/launchchecklist/localization/zhcn": {
    +-    "title": "",
    +-    "resources": [
    +-      "intl/zh-cn/distribute/tools/localization-checklist.html",
    +-    ]
    +-  },
    +-  "distribute/toolsreference/launchchecklist/graphics/zhcn": {
    +-    "title": "",
    +-    "resources": [
    +-      "https://support.google.com/googleplay/android-developer/answer/1078870?hl=zh-Hans",
    +-      "https://android-developers.blogspot.com/2011/10/android-market-featured-image.html"
    +-    ]
    +-  },
    +-  "distribute/toolsreference/launchchecklist/productdetails/zhcn": {
    +-    "title": "",
    +-    "resources": [
    +-      "https://support.google.com/googleplay/android-developer/answer/113475?hl=zh-Hans",
    +-      "https://support.google.com/googleplay/android-developer/answer/1078870?hl=zh-Hans"
    +-    ]
    +-  },
    +-  "distribute/toolsreference/launchchecklist/badges/zhcn": {
    +-    "title": "",
    +-    "resources": [
    +-      "https://play.google.com/intl/en_us/badges/",
    +-      "intl/zh-cn/distribute/tools/promote/linking.html"
    +-    ]
    +-  },
    +-  "distribute/toolsreference/launchchecklist/finalchecks/zhcn": {
    +-    "title": "",
    +-    "resources": [
    +-      "https://play.google.com/about/developer-content-policy.html",
    +-      "https://support.google.com/googleplay/android-developer/answer/113476?hl=zh-Hans",
    +-      "support.html"
    +-    ]
    +-  },
    +-  "distribute/toolsreference/launchchecklist/afterlaunch/zhcn": {
    +-    "title": "",
    +-    "resources": [
    +-      "https://support.google.com/googleplay/android-developer/answer/113477?hl=zh-Hans",
    +-      "https://support.google.com/googleplay/android-developer/answer/1153479?hl=zh-Hans",
    +-      "https://support.google.com/payments/answer/2741495?hl=zh-Hans",
    +-      "distribute/essentials/optimizing-your-app.html"
    +-    ]
    +-  },
    +-  "distribute/monetize/premium": {
    +-    "title": "",
    +-    "resources": [
    +-      "google/play/billing/index.html",
    +-      "https://support.google.com/googleplay/android-developer/answer/4407611"
    +-    ]
    +-  },
    +-  "distribute/monetize/freemium": {
    +-    "title": "",
    +-    "resources": [
    +-      "google/play/billing/index.html",
    +-      "https://support.google.com/googleplay/android-developer/answer/4407611"
    +-    ]
    +-  },
    +-  "distribute/monetize/subscriptions": {
    +-    "title": "",
    +-    "resources": [
    +-      "google/play/billing/billing_subscriptions.html",
    +-      "https://support.google.com/googleplay/android-developer/answer/4407611"
    +-    ]
    +-  },
    +-  "distribute/monetize/ecommerce": {
    +-    "title": "",
    +-    "resources": [
    +-      "https://developers.google.com/wallet/instant-buy/",
    +-      "https://support.google.com/googleplay/android-developer/answer/4407611"
    +-    ]
    +-  },
    +-  "distribute/monetize/advertising": {
    +-    "title": "",
    +-    "resources": [
    +-      "https://www.google.com/ads/admob/#subid=us-en-et-dac",
    +-      "https://www.google.com/doubleclick/publishers/small-business/index.html",
    +-      "https://support.google.com/googleplay/android-developer/topic/2985714",
    +-      "training/monetization/ads-and-ux.html"
    +-    ]
    +-  },
    +-  "distribute/monetize/admob": {
    +-    "title": "",
    +-    "resources": [
    +-      "https://support.google.com/admob/topic/2784623",
    +-      "https://admob.blogspot.com/",
    +-      "https://analyticsacademy.withgoogle.com/mobile-app",
    +-      "https://www.udacity.com/courses/ud876-3"
    +-    ]
    +-  },
    +-  "distribute/monetize/paymentmethods": {
    +-    "title": "",
    +-    "resources": [
    +-      "https://play.google.com/about/giftcards/",
    +-      "https://support.google.com/googleplay/answer/2651410"
    +-    ]
    +-  },
    +-  "distribute/monetize/conversions": {
    +-    "title": "",
    +-    "resources": [
    +-      "https://support.google.com/adwords/answer/2471188",
    +-      "https://developers.google.com/app-conversion-tracking/",
    +-      "https://support.google.com/analytics/answer/2611404",
    +-      "https://support.google.com/adwords/answer/1704341"
    +-    ]
    +-  },
    +-  "autolanding": {
    +-    "title": "",
    +-    "resources": [
    +-      "auto/index.html",
    +-      "design/auto/index.html",
    +-      "training/auto/index.html"
    +-    ]
    +-  },
    +-  "tvlanding": {
    +-    "title": "",
    +-    "resources": [
    +-      "tv/index.html",
    +-      "design/tv/index.html",
    +-      "training/tv/index.html"
    +-    ]
    +-  },
    +-  "wearlanding": {
    +-    "title": "",
    +-    "resources": [
    +-      "design/wear/index.html",
    +-      "training/building-wearables.html",
    +-      "training/wearables/ui/index.html"
    +-    ]
    +-  },
    +-  "design/auto/auto_ui_guidelines": {
    +-    "title": "",
    +-    "resources": [
    +-      "shareables/auto/AndroidAuto-audio-apps.pdf",
    +-      "shareables/auto/AndroidAuto-messaging-apps.pdf",
    +-      "shareables/auto/AndroidAuto-custom-colors.pdf"
    +-    ]
    +-  },
    +-  "training/auto/overview": {
    +-    "title": "",
    +-    "resources": [
    +-      "training/auto/start/index.html",
    +-      "design/auto/index.html",
    +-      "shareables/auto/AndroidAuto-custom-colors.pdf"
    +-    ]
    +-  },
    +-  "training/auto/messaging": {
    +-    "title": "",
    +-    "resources": [
    +-      "training/auto/messaging/index.html",
    +-      "shareables/auto/AndroidAuto-messaging-apps.pdf",
    +-      "samples/MessagingService/index.html"
    +-    ]
    +-  },
    +-  "training/auto/media": {
    +-    "title": "",
    +-    "resources": [
    +-      "training/auto/audio/index.html",
    +-      "shareables/auto/AndroidAuto-audio-apps.pdf",
    +-      "samples/MediaBrowserService/index.html"
    +-    ]
    +-  },
    +-  "training/auto/distribute": {
    +-    "title": "",
    +-    "resources": [
    +-      "distribute/essentials/quality/auto.html",
    +-      "distribute/googleplay/auto.html"
    +-    ]
    +-  },
    +-  "training/testing/overview": {
    +-    "title": "",
    +-    "resources": [
    +-      "training/testing/start/index.html",
    +-      "tools/testing/testing_android.html",
    +-      "https://www.youtube.com/watch?v=vdasFFfXKOY"
    +-    ]
    +-  },
    +-  "training/testing/tools": {
    +-    "title": "",
    +-    "resources": [
    +-      "tools/testing-support-library/index.html",
    +-      "tools/help/monkey.html",
    +-      "tools/help/monkeyrunner_concepts.html",
    +-      "tools/testing/testing_otheride.html",
    +-      "https://source.android.com/devices/tech/debug/dumpsys.html"
    +-    ]
    +-  },
    +-  "training/testing/techniques": {
    +-    "title": "",
    +-    "resources": [
    +-      "training/testing/ui-testing/index.html",
    +-      "training/testing/unit-testing/index.html",
    +-      "training/testing/performance.html"
    +-    ]
    +-  },
    +-  "training/testing/resources": {
    +-    "title": "",
    +-    "resources": [
    +-      "https://github.com/googlesamples/android-testing",
    +-      "https://www.youtube.com/watch?v=2I6fuD20qlY",
    +-      "https://codelabs.developers.google.com/codelabs/android-testing/index.html",
    +-      "https://github.com/googlesamples/android-testing-templates",
    +-      "https://google.github.io/android-testing-support-library"
    +-    ]
    +-  },
    +-  "distribute/stories/games": {
    +-    "title": "",
    +-    "resources": [
    +-      "https://storage.googleapis.com/androiddevelopers/shareables/stories/Glu_Deerhunter2014_gpgs.pdf",
    +-      "https://storage.googleapis.com/androiddevelopers/shareables/stories/ConcreteSoftware_PBABowling_gpgs.pdf",
    +-      "https://storage.googleapis.com/androiddevelopers/shareables/stories/Dragonplay_DragonplaySlots_gpgs.pdf",
    +-      "https://storage.googleapis.com/androiddevelopers/shareables/stories/Gameloft_Asphalt8_gpgs.pdf",
    +-      "https://storage.googleapis.com/androiddevelopers/shareables/stories/Glu_EternityWarriors3_gpgs.pdf",
    +-      "https://storage.googleapis.com/androiddevelopers/shareables/stories/HotheadGames_RivalsatWar_gpgs.pdf",
    +-      "https://storage.googleapis.com/androiddevelopers/shareables/stories/TMSOFT_Compulsive_gpgs.pdf",
    +-      "https://storage.googleapis.com/androiddevelopers/shareables/stories/Noodlecake_SuperStickmanGolf2_gpgs.pdf",
    +-      "https://storage.googleapis.com/androiddevelopers/shareables/stories/TinyRebel_DoctorWhoLegacy_gpgs.pdf",
    +-      "https://storage.googleapis.com/androiddevelopers/shareables/stories/Senri_LeosFortune_gpgs.pdf"
    +-    ]
    +-  },
    +-  "overview/zhcn/1": {
    +-    "title": "",
    +-    "resources": [
    +-      "intl/zh-cn/distribute/essentials/quality/core.html",
    +-      "intl/zh-cn/distribute/essentials/quality/tablets.html",
    +-      "intl/zh-cn/distribute/tools/launch-checklist.html",
    +-      "intl/zh-cn/tools/publishing/publishing_overview.html",
    +-      "intl/zh-cn/distribute/tools/localization-checklist.html"
    +-    ]
    +-  },
    +-    "overview/zhcn/2": {
    +-    "title": "",
    +-    "resources": [
    +-      "intl/zh-cn/google/play/billing/index.html",
    +-      "intl/zh-cn/google/play/billing/api.html",
    +-      "intl/zh-cn/google/play/billing/billing_admin.html",
    +-      "intl/zh-cn/google/play/billing/billing_testing.html",
    +-      "intl/zh-cn/google/play/billing/billing_best_practices.html"
    +-    ]
    +-  },
    +-  "overview/zhcn/3": {
    +-    "title": "",
    +-    "resources": [
    +-      "https://play.google.com/intl/en_us/badges/",
    +-
    +-      "intl/zh-cn/distribute/tools/promote/device-art.html",
    +-      "intl/zh-cn/distribute/tools/promote/linking.html",
    +-      "intl/zh-cn/distribute/tools/promote/brand.html",
    +-      "intl/zh-cn/tools/help/proguard.html"
    +-    ]
    +-  },
    +-  "overview/zhcn/4": {
    +-    "title": "",
    +-    "resources": [
    +-      "intl/zh-cn/design/style/writing.html",
    +-      "intl/zh-cn/training/basics/fragments/fragment-ui.html",
    +-      "intl/zh-cn/training/multiscreen/index.html",
    +-      "intl/zh-cn/training/monitoring-device-state/index.html"
    +-    ]
    +-  },
    +-  "overview/carousel/zhcn": {
    +-    "title": "",
    +-    "resources": [
    +-      "https://www.youtube.com/watch?v=vGV7FHGzpFU",
    +-      "https://www.youtube.com/watch?v=aqc3ZOTzpdk",
    +-      "https://www.youtube.com/watch?v=jaNrJ8uyLSc"
    +-    ]
    +-  },
    +-  "overview/1": {
    +-    "title": "",
    +-    "resources": [
    +-      "distribute/essentials/quality/core.html",
    +-      "distribute/essentials/quality/tablets.html",
    +-      "distribute/tools/launch-checklist.html",
    +-      "tools/publishing/publishing_overview.html",
    +-      "distribute/tools/localization-checklist.html"
    +-    ]
    +-  },
    +-    "overview/2": {
    +-    "title": "",
    +-    "resources": [
    +-      "google/play/billing/index.html",
    +-      "google/play/billing/api.html",
    +-      "google/play/billing/billing_admin.html",
    +-      "google/play/billing/billing_testing.html",
    +-      "google/play/billing/billing_best_practices.html"
    +-    ]
    +-  },
    +-  "overview/3": {
    +-    "title": "",
    +-    "resources": [
    +-      "https://play.google.com/intl/en_us/badges/",
    +-      "distribute/tools/promote/device-art.html",
    +-      "distribute/tools/promote/linking.html",
    +-      "distribute/tools/promote/brand.html",
    +-      "tools/help/proguard.html"
    +-    ]
    +-  },
    +-  "overview/4": {
    +-    "title": "",
    +-    "resources": [
    +-      "design/style/writing.html",
    +-      "training/basics/fragments/fragment-ui.html",
    +-      "training/multiscreen/index.html",
    +-      "training/monitoring-device-state/index.html"
    +-    ]
    +-  },
    +-"tools/help/log": {
    +-    "title": "",
    +-    "resources": [
    +-       "tools/help/am-logcat.html"
    +-    ]
    +-  },
    +-"tools/help/monitor": {
    +-    "title": "",
    +-    "resources": [
    +-       "tools/help/am-memory.html",
    +-       "tools/help/am-cpu.html",
    +-       "tools/help/am-gpu.html",
    +-       "tools/help/am-network.html"
    +-    ]
    +-  },
    +- "tools/help/data": {
    +-    "title": "",
    +-    "resources": [
    +-       "tools/help/am-hprof.html",
    +-       "tools/help/am-allocation.html",
    +-       "tools/help/am-methodtrace.html",
    +-       "tools/help/am-sysinfo.html"
    +-    ]
    +-  },
    +-  "tools/help/shot": {
    +-    "title": "",
    +-    "resources": [
    +-       "tools/help/am-screenshot.html",
    +-       "tools/help/am-video.html"
    +-    ]
    +-  },
    +-  "tools/performance/rendering": {
    +-    "title": "",
    +-    "resources": [
    +-       "tools/performance/debug-gpu-overdraw/index.html",
    +-       "tools/performance/profile-gpu-rendering/index.html",
    +-       "tools/performance/hierarchy-viewer/setup.html",
    +-       "tools/performance/hierarchy-viewer/index.html",
    +-       "tools/performance/hierarchy-viewer/profiling.html"
    +-    ]
    +-  },
    +-  "tools/performance/memory": {
    +-    "title": "",
    +-    "resources": [
    +-       "tools/performance/memory-monitor/index.html",
    +-       "tools/performance/heap-viewer/index.html",
    +-       "tools/performance/allocation-tracker/index.html",
    +-       "tools/performance/comparison.html"
    +-    ]
    +-  },
    +-  "tools/performance/cpu": {
    +-    "title": "",
    +-    "resources": [
    +-       "tools/performance/traceview/index.html",
    +-       "tools/performance/systrace/index.html"
    +-    ]
    +-  },
    +-  "tools/performance/battery": {
    +-    "title": "",
    +-    "resources": [
    +-       "tools/performance/batterystats-battery-historian/index.html",
    +-       "tools/performance/batterystats-battery-historian/charts.html"
    +-    ]
    +-  },
    +-  "marshmallow/landing/resources": {
    +-    "title": "",
    +-    "resources": [
    +-       "about/versions/marshmallow/android-6.0-changes.html",
    +-       "about/versions/marshmallow/android-6.0.html",
    +-       "about/versions/marshmallow/samples.html"
    +-    ]
    +-  },
    +-  "marshmallow/landing/videos": {
    +-    "title": "",
    +-    "resources": [
    +-       "https://youtu.be/U9tw5ypqEN0",
    +-       "https://youtu.be/N72ksDKrX6c",
    +-       "https://youtu.be/iZqDdvhTZj0",
    +-       "https://www.youtube.com/watch?v=vcSj8ln-BlE",
    +-       "https://youtu.be/LQoohRwojmw",
    +-       "https://www.youtube.com/watch?v=VOn7VrTRlA4",
    +-       "https://youtu.be/5sCQjeGoE7M",
    +-       "https://www.youtube.com/watch?v=C8lUdPVSzDk",
    +-       "https://www.youtube.com/watch?v=HXacyy0HSW0",
    +-       "https://www.youtube.com/watch?v=OW1A4XFRuyc",
    +-       "https://www.youtube.com/watch?v=j3QC6hcpy90",
    +-       "https://www.youtube.com/watch?v=f17qe9vZ8RM",
    +-       "https://www.youtube.com/watch?v=ndBdf1_oOGA"
    +-    ]
    +-  },
    +-  "marshmallow/landing/more": {
    +-    "title": "",
    +-    "resources": [
    +-      "training/permissions/requesting.html",
    +-      "training/backup/autosyncapi.html",
    +-      "training/monitoring-device-state/doze-standby.html",
    +-      "training/app-links/index.html",
    +-      "training/articles/assistant.html",
    +-      "training/testing/performance.html",
    +-      "https://developers.google.com/android/nexus/images"
    +-    ]
    +-  },
    +-  "tools/landing/resources": {
    +-    "title": "",
    +-    "resources": [
    +-    "tools/studio/index.html",
    +-    "tools/studio/studio-features.html",
    +-    "studio/intro/index.html",
    +-    ]
    +-  },
    +-  "tools/landing/latest": {
    +-    "title": "",
    +-    "resources": [
    +-    "https://medium.com/google-developers/how-often-should-you-update-android-studio-db25785c488e#.8blbql35x",
    +-    "http://android-developers.blogspot.com/2016/04/android-studio-2-0.html",
    +-    "https://medium.com/google-developers/writing-more-code-by-writing-less-code-with-android-studio-live-templates-244f648d17c7#.hczcm02du",
    +-    ]
    +-  },
    +-  "work/landing/primary": {
    +-    "title": "",
    +-    "resources": [
    +-      "work/overview.html",
    +-      "work/guide.html",
    +-      "https://www.google.com/work/android/developers/applyDevHub/",
    +-      "work/managed-configurations.html",
    +-      "work/cosu.html",
    +-      "work/managed-profiles.html"
    +-    ]
    +-  },
    +-  "work/landing/resources": {
    +-    "title": "",
    +-    "resources": [
    +-      "https://developers.google.com/android/work/",
    +-      "https://www.google.com/work/android/",
    +-      "https://developers.google.com/android/work/build-dpc",
    +-      "https://www.youtube.com/watch?v=jQWB_-o1kz4&list=PLOU2XLYxmsIKAK2Bhv19H2THwF-22O5WX",
    +-      "https://www.youtube.com/watch?v=Za0OQo8DRM4",
    +-      "https://www.youtube.com/watch?v=dH41OutAMNM&list=PLOU2XLYxmsIKAK2Bhv19H2THwF-22O5WX"
    +-    ]
    +-  },
    +-  "work/apps": {
    +-    "title": "",
    +-    "resources": [
    +-      "work/managed-profiles.html",
    +-      "work/managed-configurations.html",
    +-      "work/cosu.html",
    +-      "https://www.youtube.com/watch?v=39NkpWkaH8M&index=2&list=PLOU2XLYxmsIKAK2Bhv19H2THwF-22O5WX",
    +-      "samples/AppRestrictionSchema/index.html",
    +-      "samples/AppRestrictionEnforcer/index.html"
    +-    ]
    +-  },
    +-  "work/admin": {
    +-    "title": "",
    +-    "resources": [
    +-      "https://developers.google.com/android/work/build-dpc",
    +-      "samples/BasicManagedProfile/index.html",
    +-      "https://www.youtube.com/watch?v=j3QC6hcpy90"
    +-    ]
    +-  }
    +-};
    +diff --git a/docs/html/jd_extras.js b/docs/html/jd_extras.js
    +deleted file mode 100644
    +index 44ccafa..0000000
    +--- a/docs/html/jd_extras.js
    ++++ /dev/null
    +@@ -1,4120 +0,0 @@
    +-/*
    +- * THIS FILE IS DEPRECATED.
    +- *
    +- * Please add and edit resource collections in jd_extras_<lang>.js
    +- * where lang matches the language code appropriate for the resource.
    +- * Last sync'd with jd_extras_<lang>.js on 29 Apr 2016.
    +- *
    +- */
    +-DISTRIBUTE_RESOURCES = DISTRIBUTE_RESOURCES.concat([
    +- /* TODO Remove standard resources from here, such as below
    +- */
    +-  {
    +-    "title":"Writing More Code by Writing Less Code with Android Studio Live Templates",
    +-    "titleFriendly":"",
    +-    "summary":"Unless you’re getting paid by the keystroke, no one wants to write repetitive boilerplate code.",
    +-    "url":"https://medium.com/google-developers/writing-more-code-by-writing-less-code-with-android-studio-live-templates-244f648d17c7#.hczcm02du",
    +-    "group":"",
    +-    "keywords": [],
    +-    "tags": ['studio'],
    +-    "image":"https://cdn-images-1.medium.com/max/800/1*JkrYXGs1AxZAbK0sCLrJAQ.gif",
    +-    "type":"medium"
    +-  },
    +-  {
    +-    "title":"How Often Should You Update Android Studio?",
    +-    "titleFriendly":"",
    +-    "summary":"One of the beauties of Android Studio is how quickly is evolves and improves.",
    +-    "url":"https://medium.com/google-developers/how-often-should-you-update-android-studio-db25785c488e#.8blbql35x",
    +-    "group":"",
    +-    "keywords": [],
    +-    "tags": ['studio'],
    +-    "image":"https://cdn-images-1.medium.com/max/2000/1*chMiA9mGa_FBUOoesHHk3Q.png",
    +-    "type":"medium"
    +-  },
    +-  {
    +-    "title":"SmallerAPK, Part 6: Image optimization, Zopfli & WebP",
    +-    "category":"",
    +-    "summary":"Series of posts on minimizing your APK size.",
    +-    "url":"https://medium.com/@wkalicinski/smallerapk-part-6-image-optimization-zopfli-webp-4c462955647d#.23hlddo3x",
    +-    "group":"",
    +-    "keywords": [],
    +-    "tags": [],
    +-    "image":"https://cdn-images-1.medium.com/max/2000/1*chMiA9mGa_FBUOoesHHk3Q.png",
    +-    "type":"medium"
    +-  },
    +-  {
    +-    "title":"Measure your app’s user acquisition channels",
    +-    "titleFriendly":"",
    +-    "summary":"Get details on how to use the Developer Console User Acquisitions reports to discover where your users come from.",
    +-    "url":"https://support.google.com/googleplay/android-developer/answer/6263332",
    +-    "group":"",
    +-    "keywords": [],
    +-    "tags": [],
    +-    "image":"images/play_dev.jpg",
    +-    "type":"google"
    +-  },
    +-  {
    +-    "title":"Set up native app install banners in Chrome",
    +-    "titleFriendly":"",
    +-    "summary":"Get the details you need to add your native app or game to your site’s web app manifest file.",
    +-    "url":"https://developers.google.com/web/updates/2015/03/increasing-engagement-with-app-install-banners-in-chrome-for-android#native",
    +-    "group":"",
    +-    "keywords": [],
    +-    "tags": [],
    +-    "image":"images/play_dev.jpg",
    +-    "type":"google"
    +-  },
    +-  {
    +-    "title":"Optimize your store listing pages with experiments",
    +-    "titleFriendly":"",
    +-    "summary":"You can run experiments to find the most effective graphics and localized text for your app.",
    +-    "url":"https://support.google.com/googleplay/android-developer/answer/6227309",
    +-    "group":"",
    +-    "keywords": [],
    +-    "tags": [],
    +-    "image":"images/play_dev.jpg",
    +-    "type":"google"
    +-  },
    +-  {
    +-    "title":"Content Experiments for Mobile Apps",
    +-    "titleFriendly":"",
    +-    "summary":"Google Analytics Content Experiments allows you to test multiple variations of a given web page.",
    +-    "url":"https://support.google.com/tagmanager/answer/6003007",
    +-    "group":"",
    +-    "keywords": [],
    +-    "tags": [],
    +-    "image":"images/play_dev.jpg",
    +-    "type":"google"
    +-  },
    +-  {
    +-    "title":"Store Listing Experiments for Google Play",
    +-    "titleFriendly":"",
    +-    "summary":"Learn how to use Google Play’s new store listing optimization feature to get more installs of your app.",
    +-    "url":"https://www.youtube.com/watch?v=B6ydLpkhq04",
    +-    "group":"",
    +-    "keywords": [],
    +-    "tags": [],
    +-    "image":"https://i1.ytimg.com/vi/B6ydLpkhq04/maxresdefault.jpg",
    +-    "type":"video"
    +-  },
    +-  {
    +-    "title":"Use alpha/beta testing & staged rollouts",
    +-    "titleFriendly":"",
    +-    "summary":"Using the Google Play Developer Console, you can choose groups of users to test different versions of your app.",
    +-    "url":"https://support.google.com/googleplay/android-developer/answer/3131213",
    +-    "group":"",
    +-    "keywords": [],
    +-    "tags": [],
    +-    "image":"images/play_dev.jpg",
    +-    "type":"google"
    +-  },
    +-  {
    +-    "title":"Quizlet Developer Story",
    +-    "titleFriendly":"",
    +-    "summary":"Quizlet is an extremely popular online learning tool for students. See how they optimized for the classroom with Android and the power of Google Play for Education.",
    +-    "url":"https://www.youtube.com/watch?v=Idu7VcTTXfk",
    +-    "group":"",
    +-    "keywords": [],
    +-    "tags": [
    +-      "#gpfe",
    +-      "#googleplay"
    +-    ],
    +-    "image":"https://i1.ytimg.com/vi/Idu7VcTTXfk/maxresdefault.jpg",
    +-    "type":"video"
    +-  },
    +-  {
    +-    "title":"What's New in GPFE",
    +-    "titleFriendly":"",
    +-    "summary":"Learn about the vision and philosophy behind Google Play for Education",
    +-    "url":"https://www.youtube.com/watch?v=IKhU180eJMo",
    +-    "group":"",
    +-    "keywords": [],
    +-    "tags": [
    +-      "#gpfe",
    +-      "#googleplay"
    +-    ],
    +-    "image":"https://i1.ytimg.com/vi/IKhU180eJMo/maxresdefault.jpg",
    +-    "type":"video"
    +-  },
    +-  {
    +-    "title":"Get started with Google Cast",
    +-    "titleFriendly":"",
    +-    "summary":"Build multi-screen experiences, let the user send video and audio content to TVs and speakers.",
    +-    "url":"https://developers.google.com/cast/docs/ux_guidelines",
    +-    "group":"",
    +-    "keywords": ["cast", "chromecast", "video", "audio"],
    +-    "tags": [],
    +-    "image":"images/cards/card-cast_2x.jpg",
    +-    "type":"Guide"
    +-  },
    +-  {
    +-    "title":"Android Sender Applications",
    +-    "titleFriendly":"",
    +-    "summary":"Get an overview of how your Android app can act as a Google Cast sender app.",
    +-    "url":"https://developers.google.com/cast/docs/android_sender",
    +-    "group":"",
    +-    "keywords": ["cast", "sender"],
    +-    "tags": [],
    +-    "image":"images/cards/card-cast_2x.jpg",
    +-    "type":"Guide"
    +-  },
    +-  {
    +-    "title":"Cast sample apps",
    +-    "titleFriendly":"",
    +-    "summary":"Get example Google Cast applications for both senders and receivers.",
    +-    "url":"https://www.github.com/googlecast",
    +-    "group":"",
    +-    "keywords": ["cast", "samples"],
    +-    "tags": [],
    +-    "image":"images/cards/card-cast_2x.jpg",
    +-    "type":"Samples"
    +-  },
    +-  {
    +-    "title":"Get Cardboard",
    +-    "titleFriendly":"",
    +-    "summary":"Get your own Cardboard, today. Buy one from a manufacturer or build your own, and start developing.",
    +-    "url":"https://www.google.com/get/cardboard/get-cardboard/",
    +-    "group":"",
    +-    "keywords": ["carboard","vr"],
    +-    "tags": [],
    +-    "image":"images/cards/card-cardboard_2x.png",
    +-    "type":"Guide"
    +-  },
    +-    {
    +-    "title":"Download the Cardboard SDK",
    +-    "titleFriendly":"",
    +-    "summary":"Grab the Cardboard libraries from GitHub and start creating VR apps in your favorite development environment.",
    +-    "url":"https://developers.google.com/cardboard/android/download",
    +-    "group":"",
    +-    "keywords": ["carboard","vr"],
    +-    "tags": [],
    +-    "image":"images/cards/card-cardboard_2x.png",
    +-    "type":"Guide"
    +-  },
    +-  {
    +-    "title":"Cardboard design guidelines",
    +-    "titleFriendly":"",
    +-    "summary":"Focus on overall usability and avoiding common VR pitfalls while creating an immersive experience of your own.",
    +-    "url":"https://www.google.com/design/spec-vr",
    +-    "group":"",
    +-    "keywords": ["carboard","vr"],
    +-    "tags": [],
    +-    "image":"images/cards/card-cardboard_2x.png",
    +-    "type":"Design"
    +-  },
    +-  {
    +-    "title":"Maps",
    +-    "titleFriendly":"",
    +-    "summary":"Give users the map that more than a billion people use every month.",
    +-    "url":"https://developers.google.com/maps/documentation/android/",
    +-    "group":"",
    +-    "keywords": ["maps"],
    +-    "tags": [],
    +-    "image":"images/google/gps-maps.png",
    +-    "type":"Guide"
    +-  },
    +-    {
    +-    "title":"Places API",
    +-    "titleFriendly":"",
    +-    "summary":"give your users contextual information about where they are, when they’re there.",
    +-    "url":"https://developers.google.com/places/android/",
    +-    "group":"",
    +-    "keywords": ["places","location", "context"],
    +-    "tags": [],
    +-    "image":"images/cards/card-places_2x.png",
    +-    "type":"Guide"
    +-  },
    +-  {
    +-    "title":"GCM Client for Android",
    +-    "titleFriendly":"",
    +-    "summary":"Send push notifications and pubsub from your server to Android devices around the world.",
    +-    "url":"https://developers.google.com/cloud-messaging/android/client",
    +-    "group":"",
    +-    "keywords": ["push","gcm"],
    +-    "tags": [],
    +-    "image":"images/cards/card-google-cloud-messaging_16-9_2x.png",
    +-    "type":"Guide"
    +-  },
    +-  {
    +-    "title":"Google Cloud Messaging",
    +-    "titleFriendly":"",
    +-    "summary":"Learn about GCM and the kinds of services you can offer to users through push notifications",
    +-    "url":"https://developers.google.com/cloud-messaging/gcm",
    +-    "group":"",
    +-    "keywords": ["push","gcm"],
    +-    "tags": [],
    +-    "image":"images/cards/card-google-cloud-messaging_16-9_2x.png",
    +-    "type":"Guide"
    +-  },
    +-  {
    +-    "title":"ClassDojo Developer Story",
    +-    "titleFriendly":"",
    +-    "summary":"ClassDojo is a classroom tool that helps teachers improve behavior in their classrooms quickly and easily. See how they optimized for the classroom with Android and the power of Google Play for Education.",
    +-    "url":"https://www.youtube.com/watch?v=iokH4SAIfRw",
    +-    "group":"",
    +-    "keywords": [],
    +-    "tags": [
    +-      "#gpfe",
    +-      "#googleplay"
    +-    ],
    +-    "image":"https://i1.ytimg.com/vi/iokH4SAIfRw/maxresdefault.jpg",
    +-    "type":"video"
    +-  },
    +-  {
    +-    "title":"Plan for Success",
    +-    "titleFriendly":"",
    +-    "summary":"5 tips from developers on creating great EDU apps.",
    +-    "url":"https://www.youtube.com/watch?v=Eh2adsAyTKc",
    +-    "group":"",
    +-    "keywords": [],
    +-    "tags": [
    +-      "#gpfe",
    +-      "#googleplay"
    +-    ],
    +-    "image":"https://i1.ytimg.com/vi/Eh2adsAyTKc/maxresdefault.jpg",
    +-    "type":"video"
    +-  },
    +-  {
    +-    "title":"Optimizing Apps for Education",
    +-    "titleFriendly":"",
    +-    "summary":"Learn how to optimize your app for teachers and students.",
    +-    "url":"https://www.youtube.com/watch?v=_AZ6UcPz-_g",
    +-    "group":"",
    +-    "keywords": [],
    +-    "tags": [
    +-      "#gpfe",
    +-      "#googleplay"
    +-    ],
    +-    "image":"https://i1.ytimg.com/vi/_AZ6UcPz-_g/maxresdefault.jpg",
    +-    "type":"video"
    +-  },
    +-  {
    +-    "title":"Ideas and Tools for Building Innovative Education Apps",
    +-    "titleFriendly":"",
    +-    "summary":"Are you hungry to build an awesome app for education but don't quite know where to start? Come hear about apps that teachers want, and the APIs you're going to need to build them! In particular, we'll talk about app ideas that combine APIs for Google Drive, Google Login, Android Single Task Mode and more to build transformative Educational apps that will delight educators and kids in and out of the classroom.",
    +-    "url":"https://www.youtube.com/watch?v=iulXz8QTD1g",
    +-    "group":"",
    +-    "keywords": [],
    +-    "tags": [
    +-      "#gpfe",
    +-      "#googleplay"
    +-    ],
    +-    "image":"https://i1.ytimg.com/vi/iulXz8QTD1g/maxresdefault.jpg",
    +-    "type":"video"
    +-  },
    +-  {
    +-    "title":"DesignBytes: Intro To Material Design",
    +-    "titleFriendly":"",
    +-    "summary":"These days, UI designers need to be thinking about phones, tablets, laptops, TVs, smartwatches, and beyond. In this DesignByte we talk about how Google designers have been working on making cross-platform and multi-screen design easier. We wanted to build a design system that felt at home on every screen, from the smallest watch to the largest TV.",
    +-    "url":"https://www.youtube.com/watch?v=p4gmvHyuZzw",
    +-    "group":"",
    +-    "keywords": [],
    +-    "tags": [
    +-    ],
    +-    "image":"https://i1.ytimg.com/vi/p4gmvHyuZzw/maxresdefault.jpg",
    +-    "type":"video"
    +-  },
    +-  {
    +-    "title":"DesignBytes: Paper and Ink: The Materials that Matter",
    +-    "titleFriendly":"",
    +-    "summary":"Join Rich Fulcher to learn about the materials of material design. See how virtual paper and ink form the foundation of your tactile user interface and master the rules that govern their behaviour.",
    +-    "url":"https://www.youtube.com/watch?v=YaG_ljfzeUw",
    +-    "group":"",
    +-    "keywords": [],
    +-    "tags": [
    +-    ],
    +-    "image":"https://i1.ytimg.com/vi/YaG_ljfzeUw/maxresdefault.jpg",
    +-    "type":"video"
    +-  },
    +-  {
    +-    "title":"DesignBytes: Material Design in the Google I/O App",
    +-    "titleFriendly":"",
    +-    "summary":"Roman Nurik shares details on the design process for the Google I/O 2014 app. To check out the app's source code, visit github.com/google/iosched.",
    +-    "url":"https://www.youtube.com/watch?v=XOcCOBe8PTc",
    +-    "group":"",
    +-    "keywords": [],
    +-    "tags": [
    +-    ],
    +-    "image":"https://i1.ytimg.com/vi/XOcCOBe8PTc/maxresdefault.jpg",
    +-    "type":"video"
    +-  },
    +-  {
    +-    "title":"Toolbars for a flexible Action Bar & more",
    +-    "titleFriendly":"",
    +-    "summary":"Toolbars are a flexible View you can add to your Android app which provides many of the same APIs as the system provided Action Bar, but can also do so much more such as reacting to scrolling or being integrated directly into your layouts.",
    +-    "url":"https://www.youtube.com/watch?v=kmUGLURRPkI",
    +-    "group":"",
    +-    "keywords": [],
    +-    "tags": [
    +-    ],
    +-    "image":"https://i1.ytimg.com/vi/kmUGLURRPkI/maxresdefault.jpg",
    +-    "type":"video"
    +-  },
    +-  {
    +-    "title":"Protecting Implicit Intents with Runtime Checks",
    +-    "titleFriendly":"",
    +-    "summary":"Make sure you protect your implicit intents with a simple runtime check.",
    +-    "url":"https://www.youtube.com/watch?v=HGElAW224dE",
    +-    "group":"",
    +-    "keywords": [],
    +-    "tags": [
    +-    ],
    +-    "image":"https://i1.ytimg.com/vi/HGElAW224dE/maxresdefault.jpg",
    +-    "type":"video"
    +-  },
    +-  {
    +-    "title":"Tabs and ViewPager",
    +-    "titleFriendly":"",
    +-    "summary":"Showing multiple screens or pages of content is easy with the help of ViewPager and a PagerAdapter. Combining that with tabs make for an effective top level navigation strategy for your app or for moving between content at the same level of hierarchy within your app.",
    +-    "url":"https://www.youtube.com/watch?v=zQekzaAgIlQ",
    +-    "group":"",
    +-    "keywords": [],
    +-    "tags": [
    +-    ],
    +-    "image":"https://i1.ytimg.com/vi/zQekzaAgIlQ/maxresdefault.jpg",
    +-    "type":"video"
    +-  },
    +-  {
    +-    "title":"Battery Drain and Networking",
    +-    "titleFriendly":"",
    +-    "summary":"Let’s take a moment to make something insanely clear: As far as battery is concerned, NETWORKING is the biggest, baddest, dirtiest offender there is. And optimizing performance here isn’t easy. Since the chip isn’t always awake and draining power, means you can optimize how it wakes up, sends traffic, and saves battery.",
    +-    "url":"https://www.youtube.com/watch?v=fEEulSk1kNY",
    +-    "group":"",
    +-    "keywords": [],
    +-    "tags": [
    +-    ],
    +-    "image":"https://i1.ytimg.com/vi/fEEulSk1kNY/maxresdefault.jpg",
    +-    "type":"video"
    +-  },
    +-  {
    +-    "title":"Batching Background Work Until Later",
    +-    "titleFriendly":"",
    +-    "summary":"Yes, your app is special. But when it comes to battery use, sometimes it’s better to be part of the crowd. Why not spread the battery blame around a bit? Ian Ni-Lewis shows you how ridiculously easy it is to go from battery hog to team player in this video.",
    +-    "url":"https://www.youtube.com/watch?v=-3ry8PxcJJA",
    +-    "group":"",
    +-    "keywords": [],
    +-    "tags": [
    +-    ],
    +-    "image":"https://i1.ytimg.com/vi/-3ry8PxcJJA/maxresdefault.jpg",
    +-    "type":"video"
    +-  },
    +-  {
    +-    "title":"The Performance Lifecycle",
    +-    "titleFriendly":"",
    +-    "summary":"Performance problems surface in your application at the least-wanted times (like right before you’re about to ship your first build). But don’t freak out: There’s a simple process that you can follow to help get your performance back under control.",
    +-    "url":"https://www.youtube.com/watch?v=_kKTGK-Cb_4",
    +-    "group":"",
    +-    "keywords": [],
    +-    "tags": [
    +-    ],
    +-    "image":"https://i1.ytimg.com/vi/_kKTGK-Cb_4/maxresdefault.jpg",
    +-    "type":"video"
    +-  },
    +-  {
    +-    "title":"Introduction to Android Studio",
    +-    "titleFriendly":"",
    +-    "summary":"Learn why you should migrate your projects to Android Studio now and how it can help you be more productive as a developer. Rich layout editor, handy suggestions and fixes, new Android project view - these are just some of the things you can expect from the IDE, which is built on the successful IntelliJ IDEA.",
    +-    "url":"https://www.youtube.com/watch?v=K2dodTXARqc&list=PLWz5rJ2EKKc8I9gHTMh5yKkwRRGE8BjbQ",
    +-    "group":"",
    +-    "keywords": ["studio", "tools"],
    +-    "tags": [
    +-    ],
    +-    "image":"https://i1.ytimg.com/vi/K2dodTXARqc/maxresdefault.jpg",
    +-    "type":"video"
    +-  },
    +-
    +-  {
    +-    "title":"Google Play Services 7.5",
    +-    "titleFriendly":"",
    +-    "summary":"This update brings App Invites, topics to GCM, GCMNetworkManager, Cast Remote Display API, Smart Lock for Passwords, Maps API for Android Wear, Google Fit extensions and more.",
    +-    "url":"https://www.youtube.com/watch?v=M3Udfu6qidk&list=PLWz5rJ2EKKc9Qk1_iCZNbBp6adYnJf9Vf",
    +-    "group":"",
    +-    "keywords": ["google play services"],
    +-    "tags": [
    +-    ],
    +-    "image":"https://i1.ytimg.com/vi/M3Udfu6qidk/maxresdefault.jpg",
    +-    "type":"video"
    +-  },
    +-  {
    +-    "title":"Google Play Services 7.3",
    +-    "titleFriendly":"",
    +-    "summary":"This update brings the ability to connect multiple wearables simultaneously to a single phone. There are also some great new updates to Google Fit, including nutrition types, and to Location.",
    +-    "url":"https://www.youtube.com/watch?v=FOn64iqlphk&list=PLWz5rJ2EKKc9Qk1_iCZNbBp6adYnJf9Vf",
    +-    "group":"",
    +-    "keywords": ["google play services"],
    +-    "tags": [
    +-    ],
    +-    "image":"https://i1.ytimg.com/vi/FOn64iqlphk/maxresdefault.jpg",
    +-    "type":"video"
    +-  },
    +-  {
    +-    "title":"Google Play Services 6.5",
    +-    "titleFriendly":"",
    +-    "summary":"Google Play services 6.5 includes new features in Google Maps, Google Drive and Google Wallet as well as the recently launched Google Fit API. ",
    +-    "url":"https://www.youtube.com/watch?v=fvtMtfCuEpw&list=PLWz5rJ2EKKc9Qk1_iCZNbBp6adYnJf9Vf",
    +-    "group":"",
    +-    "keywords": ["google play services"],
    +-    "tags": [
    +-    ],
    +-    "image":"https://i1.ytimg.com/vi/fvtMtfCuEpw/maxresdefault.jpg",
    +-    "type":"video"
    +-  },
    +-    {
    +-    "title":"Google Play Services 7.0",
    +-    "titleFriendly":"",
    +-    "summary":"Google Play services 7.0 is here! we've added the Places API, made enhancements to Location and Google Fit, and you can also remote control your Android TV through the new Nearby Connections API.",
    +-    "url":"https://www.youtube.com/watch?v=F0Kh_RnSM0w&list=PLWz5rJ2EKKc9Qk1_iCZNbBp6adYnJf9Vf",
    +-    "group":"",
    +-    "keywords": ["google play services"],
    +-    "tags": [
    +-    ],
    +-    "image":"https://i1.ytimg.com/vi/F0Kh_RnSM0w/maxresdefault.jpg",
    +-    "type":"video"
    +-  },
    +-  {
    +-    "title":"Running a Successful Games Business with Google",
    +-    "titleFriendly":"",
    +-    "summary":"Sure, we all want to make the next great gaming masterpiece. But we also want to feed our families and/or dogs. Join Bob Meese from the Google Play team as he gives you some key pointers on how to make sure you're best taking advantage of Google Play and running a successful games business.",
    +-    "url":"https://www.youtube.com/watch?v=tDmnGNkTtlE",
    +-    "group":"",
    +-    "keywords": [],
    +-    "tags": [
    +-    ],
    +-    "image":"https://i1.ytimg.com/vi/tDmnGNkTtlE/maxresdefault.jpg",
    +-    "type":"video"
    +-  },
    +-  {
    +-    "title":"Introduction to Android TV",
    +-    "titleFriendly":"",
    +-    "summary":"Android TV brings the Android platform to the living room with rich content and entertaining app experiences. In this video, Timothy introduces the design philosophy and developer components that make building TV experiences easier than ever before.",
    +-    "url":"https://www.youtube.com/watch?v=6K_jxccHv5M&index=1&list=PLOU2XLYxmsILFBfx66ens76VMLMEPJAB0",
    +-    "group":"",
    +-    "keywords": ["tv"],
    +-    "tags": [
    +-    ],
    +-    "image":"https://i1.ytimg.com/vi/6K_jxccHv5M/maxresdefault.jpg",
    +-    "type":"video"
    +-  },
    +-  {
    +-    "title":"Introduction to Android Auto",
    +-    "titleFriendly":"",
    +-    "summary":"Android Auto brings the Android platform to the car in a way that's optimized for the driving experience. It's the same platform you already use for phones, tablets, televisions, wearables, and more. ",
    +-    "url":"https://www.youtube.com/watch?v=ctiaVxgclsg&list=PLWz5rJ2EKKc9BdE_PSLNIGjXXr3h_orXM",
    +-    "group":"",
    +-    "keywords": ["auto"],
    +-    "tags": [
    +-    ],
    +-    "image":"https://i1.ytimg.com/vi/ctiaVxgclsg/maxresdefault.jpg",
    +-    "type":"video"
    +-  },
    +-  {
    +-    "title":"Debugging and testing in Android Studio",
    +-    "titleFriendly":"",
    +-    "summary":"This video introduces the state of unit testing support in Studio and Google’s new Android Testing Support Library for functional UI testing and running instrumented tests on a device.",
    +-    "url":"https://www.youtube.com/watch?v=2I6fuD20qlY",
    +-    "group":"",
    +-    "keywords": ["testing"],
    +-    "tags": [
    +-    ],
    +-    "image":"https://i1.ytimg.com/vi/2I6fuD20qlY/maxresdefault.jpg",
    +-    "type":"video"
    +-  },
    +-  {
    +-    "title":"Android Testing (Android Dev Summit 2015)",
    +-    "titleFriendly":"",
    +-    "summary":"Overview of the testing tools and frameworks provided by Google and how they can help you to iterate more quickly and maintain a more healthy codebase.",
    +-    "url":"https://www.youtube.com/watch?v=vdasFFfXKOY",
    +-    "group":"",
    +-    "keywords": ["testing"],
    +-    "tags": [
    +-    ],
    +-    "image":"https://i1.ytimg.com/vi/vdasFFfXKOY/maxresdefault.jpg",
    +-    "type":"video"
    +-  },
    +-  {
    +-    "title":"dumpsys",
    +-    "titleFriendly":"",
    +-    "summary":"A tool that runs on the device and provides information about the status of system services.",
    +-    "url":"https://source.android.com/devices/tech/debug/dumpsys.html",
    +-    "group":"",
    +-    "keywords": ["testing"],
    +-    "tags": [
    +-    ],
    +-    "image":"",
    +-    "type":"google"
    +-  },
    +-  {
    +-    "title":"Android Testing Samples",
    +-    "titleFriendly":"",
    +-    "summary":"A collection of samples demonstrating different frameworks and techniques for automated testing.",
    +-    "url":"https://github.com/googlesamples/android-testing",
    +-    "group":"",
    +-    "keywords": ["testing"],
    +-    "tags": [
    +-    ],
    +-    "image":"images/testing/testing-icon.png",
    +-    "type":"Samples"
    +-  },
    +-  {
    +-    "title":"Android Testing Templates",
    +-    "titleFriendly":"",
    +-    "summary":"A collection of Google's Android testing tools and frameworks, all integrated in a single application project.",
    +-    "url":"https://github.com/googlesamples/android-testing-templates",
    +-    "group":"",
    +-    "keywords": ["testing"],
    +-    "tags": [
    +-    ],
    +-    "image":"images/testing/testing-icon.png",
    +-    "type":"Samples"
    +-  },
    +-   {
    +-    "title":"Android Testing Support Library (GitHub)",
    +-    "titleFriendly":"",
    +-    "summary":"A resource page on GitHub for the Android Testing Support Library.",
    +-    "url":"https://google.github.io/android-testing-support-library",
    +-    "group":"",
    +-    "keywords": ["testing"],
    +-    "tags": [
    +-    ],
    +-    "image":"images/testing/testing-icon.png",
    +-    "type":"Samples"
    +-  },
    +-  {
    +-    "title":"Android Testing Codelab",
    +-    "titleFriendly":"",
    +-    "summary":"This codelab shows how to build an Android app from the ground up in Android Studio, using a Model View Presenter architecture, Unit Tests and Instrumentation Tests.",
    +-    "url":"https://codelabs.developers.google.com/codelabs/android-testing/index.html",
    +-    "group":"",
    +-    "keywords": ["testing"],
    +-    "tags": [
    +-    ],
    +-    "image":"images/testing/testing-icon.png",
    +-    "type":"google"
    +-  },
    +-  {
    +-    "title":"Developer Registration",
    +-    "titleFriendly":"",
    +-    "summary":"Additional information about the registration process.",
    +-    "url":"https://support.google.com/googleplay/android-developer/answer/113468",
    +-    "group":"",
    +-    "keywords": [],
    +-    "tags": [],
    +-    "image":"images/play_dev.jpg",
    +-    "type":"google"
    +-  },
    +-  {
    +-    "title": "Google Play Distribution and Seller Countries",
    +-    "titleFriendly":"",
    +-    "summary": "List of countries and territories where you can distribute your apps in Google Play.",
    +-    "url":"https://support.google.com/googleplay/android-developer/answer/138294",
    +-    "group":"",
    +-    "keywords": [],
    +-    "tags": [],
    +-    "image":"images/play_dev.jpg",
    +-    "type":"google"
    +-  },
    +-  {
    +-    "title": "支持向Google Play用户发布应用的地区",
    +-    "lang": "zh-cn",
    +-    "titleFriendly":"",
    +-    "summary": "支持向Google Play用户发布应用的国家/地区。",
    +-    "url":"https://support.google.com/googleplay/android-developer/answer/138294?hl=zh-Hans",
    +-    "group":"",
    +-    "keywords": [],
    +-    "tags": [],
    +-    "image":"images/play_dev.jpg",
    +-    "type":"google"
    +-  },
    +-  {
    +-    "title":"Google Play Content Policies",
    +-    "titleFriendly":"",
    +-    "summary":"Details on policies relating to your developer account and app distribution is governed.",
    +-    "url":"https://support.google.com/googleplay/android-developer/topic/3453577",
    +-    "group":"",
    +-    "keywords": [],
    +-    "tags": ["#developersupport"],
    +-    "image":"images/play_dev.jpg",
    +-    "type":"google"
    +-  },
    +-  {
    +-    "title":"Google Play Badge Generator",
    +-    "titleFriendly":"",
    +-    "summary":"Build badges for your app in just a few clicks, or download hi-res badge assets localized for a variety of languages.",
    +-    "url":"https://play.google.com/intl/en_us/badges/",
    +-    "group":"",
    +-    "keywords": [],
    +-    "tags": ["#developersupport"],
    +-    "image":"images/gp-badges-set.png",
    +-    "type":"google"
    +-  },
    +-  {
    +-    "lang": "en",
    +-    "group": "",
    +-    "tags": ["#developersupport #termsandpolicies"],
    +-    "url": "https://support.google.com/googleplay/android-developer/answer/4407611",
    +-    "timestamp": 1194884220000,
    +-    "image": 'images/play_dev.jpg',
    +-    "title": "Google Play Terms and Policies",
    +-    "summary": "Developer terms and policies that apply when you distribute apps in Google Play.",
    +-    "keywords": [],
    +-    "type": "distribute",
    +-    "titleFriendly": ""
    +-  },
    +-  {
    +-    "title":"Google Play Policy Center",
    +-    "titleFriendly":"",
    +-    "summary":"A central resource for you to learn about Google Play policies and guidelines.",
    +-    "url":"https://support.google.com/googleplay/android-developer/answer/4430948",
    +-    "group":"",
    +-    "keywords": [],
    +-    "tags": [],
    +-    "image":"https://storage.googleapis.com/support-kms-prod/SNP_712EA2784949DDF085C46E3BE7B1DC618A09_4389397_en_v0",
    +-    "type":"google"
    +-  },
    +-  {
    +-    "title":"Google Play应用政策中心",
    +-    "titleFriendly":"",
    +-    "summary":"一个方便你了解Google Play政策和指南的中心资源。",
    +-    "url":"https://support.google.com/googleplay/android-developer/answer/4430948?hl=zh-Hans",
    +-    "group":"",
    +-    "keywords": [],
    +-    "tags": [],
    +-    "image":"https://storage.googleapis.com/support-kms-prod/SNP_712EA2784949DDF085C46E3BE7B1DC618A09_4389397_en_v0",
    +-    "type":"google"
    +-  },
    +-  {
    +-    "title":"Developer Help Center",
    +-    "titleFriendly":"",
    +-    "summary":"Complete details on getting started, publishing, troubleshooting, and more.",
    +-    "url":"https://support.google.com/googleplay/android-developer",
    +-    "group":"",
    +-    "keywords": [],
    +-    "tags": [],
    +-    "image":"images/cards/google-play_2x.png",
    +-    "type":"google"
    +-  },
    +-  {
    +-    "title":"开发者帮助中心",
    +-    "titleFriendly":"",
    +-    "summary":"完整资料帮助开发者新手入手,发布,故障排除,等等",
    +-    "url":"https://support.google.com/googleplay/android-developer?hl=zh-Hans",
    +-    "group":"",
    +-    "keywords": [],
    +-    "tags": [],
    +-    "image":"images/play_dev.jpg",
    +-    "type":"google"
    +-  },
    +-  {
    +-    "title":"Google for Education",
    +-    "titleFriendly":"",
    +-    "summary":"Find out more about how Google can support your work with apps and tablets.",
    +-    "url":"https://www.google.com/edu/tablets/",
    +-    "group":"",
    +-    "keywords": [],
    +-    "tags": [],
    +-    "image":"distribute/images/gp-edu-apps-image.jpg",
    +-    "type":"google"
    +-  },
    +-  {
    +-    "title":"Keeping Your App Responsive",
    +-    "titleFriendly":"",
    +-    "summary":"This document describes how the Android system determines whether an application is not responding and provides guidelines for ensuring that your application stays responsive.",
    +-    "url":"training/articles/perf-anr.html",
    +-    "group":"",
    +-    "keywords": [],
    +-    "tags": [],
    +-    "image":"",
    +-    "type":"google"
    +-  },
    +-  {
    +-    "title":"Google Play Game Services",
    +-    "titleFriendly":"",
    +-    "summary":"Make your games social with Google Play game services. Add achievements, leaderboards, real-time multiplayer, and other popular features using the Google Play game services SDK.",
    +-    "url":"https://developers.google.com/games/services/",
    +-    "group":"",
    +-    "keywords": ["games","play games"],
    +-    "tags": [],
    +-    "image":"images/google/gps-play_games_logo.png",
    +-    "type":"google"
    +-  },
    +-  {
    +-    "title":"Get Started with Analytics",
    +-    "titleFriendly":"",
    +-    "summary":"Get advanced insight into how players discover and play your games.",
    +-    "url":"distribute/analyze/start.html",
    +-    "group":"",
    +-    "keywords": ["analytics"],
    +-    "tags": [],
    +-    "image": "images/cards/analytics-mobile_2x.jpg",
    +-    "type": "distribute"
    +-  },
    +-  {
    +-    "title":"Build VR with Google Cardboard",
    +-    "titleFriendly":"",
    +-    "summary":"Turn any phone into a virtual reality headset with a Cardboard viewer and experiment with adding virtual reality to your games with the Cardboard SDK.",
    +-    "url":"distribute/googleplay/cardboard.html",
    +-    "group":"",
    +-    "keywords": ["cardboard"],
    +-    "tags": [],
    +-    "image":"images/cards/card-cardboard_2x.png",
    +-    "type": "distribute"
    +-  },
    +-  {
    +-    "title":"Monetize your apps intelligently",
    +-    "titleFriendly":"",
    +-    "summary":"Generate revenue from your free games with ads tailored to match your game's look and feel.",
    +-    "url":"https://www.google.com/admob/",
    +-    "group":"",
    +-    "keywords": ["AdMob"],
    +-    "tags": [],
    +-    "image":"images/cards/admob-analytics_2x.png",
    +-    "type": "distribute"
    +-  },
    +-  {
    +-    "lang": "en",
    +-    "group": "",
    +-    "tags": [
    +-      "versions", "blog", "googleplay"
    +-    ],
    +-    "url": "https://android-developers.blogspot.com/",
    +-    "timestamp": 1004884220000,
    +-    "image": "images/blog.jpg",
    +-    "title": "Android Developers Blog",
    +-    "summary": "Follow the latest news on Android design, development, and distribution.",
    +-    "keywords": [],
    +-    "type": "blog",
    +-    "titleFriendly": ""
    +-  },
    +-  {
    +-    "lang": "en",
    +-    "group": "",
    +-    "tags": [],
    +-    "url": "https://android-developers.blogspot.com/2011/11/making-android-games-that-play-nice.html",
    +-    "timestamp": 1194884220000,
    +-    "image": null,
    +-    "title": "Making Android Apps that Play Nice",
    +-    "summary": "Audio lifecycle and expected audio behaviors for Android apps.",
    +-    "keywords": [],
    +-    "type": "blog",
    +-    "titleFriendly": ""
    +-  },
    +-  {
    +-    "lang": "en",
    +-    "group": "",
    +-    "tags": [],
    +-    "url": "https://android-developers.blogspot.com/2010/07/multithreading-for-performance.html",
    +-    "timestamp": 1194884220000,
    +-    "image": null,
    +-    "title": "Multithreading for Performance",
    +-    "summary": "Ways to improve performance through multi-threading.",
    +-    "keywords": [],
    +-    "type": "blog",
    +-    "titleFriendly": ""
    +-  },
    +-  {
    +-    "lang": "en",
    +-    "group": "",
    +-    "tags": [],
    +-    "url": "https://play.google.com/about/developer-content-policy.html",
    +-    "timestamp": 1194884220000,
    +-    "image": "images/play_dev.jpg",
    +-    "title": "Developer Program Policies",
    +-    "summary": "Guidelines acceptable content in Google Play. Please read and understand the policies before publishing.",
    +-    "keywords": [],
    +-    "type": "google",
    +-    "titleFriendly": ""
    +-  },
    +-  {
    +-    "lang": "en",
    +-    "group": "",
    +-    "tags": [],
    +-    "url": "https://support.google.com/googleplay/android-developer/answer/188189",
    +-    "timestamp": 1194884220000,
    +-    "image": "images/play_dev.jpg",
    +-    "title": "Rating your application content for Google Play",
    +-    "summary": "How to choose the appropriate content ratings level for your apps.",
    +-    "keywords": [],
    +-    "type": "support",
    +-    "titleFriendly": ""
    +-  },
    +-  {
    +-    "lang": "en",
    +-    "group": "",
    +-    "tags": ["devices", "nexus", "testing"],
    +-    "url": "https://developers.google.com/android/nexus/images",
    +-    "timestamp": 1194884220000,
    +-    "image": "images/cards/card-download_16-9_2x.png",
    +-    "title": "Factory Images for Nexus Devices",
    +-    "summary": "System image files for Android 6.0 and other Android releases.",
    +-    "keywords": ["nexus, downloads"],
    +-    "type": "support",
    +-    "titleFriendly": ""
    +-  },
    +-  {
    +-    "lang": "zh-cn",
    +-    "group": "",
    +-    "tags": [],
    +-    "url": "https://support.google.com/googleplay/android-developer/answer/188189?hl=zh-Hans",
    +-    "timestamp": 1194884220000,
    +-    "image": "images/play_dev.jpg",
    +-    "title": "针对Google Play为你的应用内容分级",
    +-    "summary": "如何为你的应用内容分级。",
    +-    "keywords": [],
    +-    "type": "support",
    +-    "titleFriendly": ""
    +-  },
    +-  {
    +-    "lang": "en",
    +-    "group": "",
    +-    "tags": [],
    +-    "url": "https://android-developers.blogspot.com/2011/10/android-market-featured-image.html",
    +-    "timestamp": 1194884220000,
    +-    "image": "images/play_dev.jpg",
    +-    "title": "Google Play Featured Image Guidelines",
    +-    "summary": "How to create attractive, effective Featured Images for your apps.",
    +-    "keywords": [],
    +-    "type": "support",
    +-    "titleFriendly": ""
    +-  },
    +-{
    +-    "lang": "en",
    +-    "group": "",
    +-    "tags": [],
    +-    "url": "https://support.google.com/googleplay/android-developer/answer/113477",
    +-    "timestamp": 1194884220000,
    +-    "image": "images/play_dev.jpg",
    +-    "title": "Supporting your users",
    +-    "summary": "Options for supporting users.",
    +-    "keywords": [],
    +-    "type": "support",
    +-    "titleFriendly": ""
    +-  },
    +-{
    +-    "lang": "zh-cn",
    +-    "group": "",
    +-    "tags": [],
    +-    "url": "https://support.google.com/googleplay/android-developer/answer/113477?hl=zh-Hans",
    +-    "timestamp": 1194884220000,
    +-    "image": "images/play_dev.jpg",
    +-    "title": "为用户提供支持",
    +-    "summary": "为用户提供支持的各种选择。",
    +-    "keywords": [],
    +-    "type": "support",
    +-    "titleFriendly": ""
    +-  },
    +-  {
    +-    "lang": "en",
    +-    "group": "",
    +-    "tags": [],
    +-    "url": "guide/practices/screens_support.html#ConfigurationExamples",
    +-    "timestamp": 1194884220000,
    +-    "image": null,
    +-    "title": "Configuration examples",
    +-    "summary": "How to declare layouts and other resources for specific screen sizes.",
    +-    "keywords": [],
    +-    "type": "design",
    +-    "titleFriendly": ""
    +-  },
    +-  {
    +-    "lang": "en",
    +-    "group": "",
    +-    "tags": [],
    +-    "url": "training/design-navigation/multiple-sizes.html",
    +-    "timestamp": 1194884220000,
    +-    "image": null,
    +-    "title": "Planning for Multiple Touchscreen Sizes",
    +-    "summary": "",
    +-    "keywords": [],
    +-    "type": "design",
    +-    "titleFriendly": ""
    +-  },
    +-  {
    +-    "lang": "en",
    +-    "group": "",
    +-    "tags": [],
    +-    "url": "training/multiscreen/index.html",
    +-    "timestamp": 1194884220000,
    +-    "image": null,
    +-    "title": "Designing for Multiple Screens",
    +-    "summary": "Designing an intuitive, effective navigation for tablets and other devices.",
    +-    "keywords": [],
    +-    "type": "design",
    +-    "titleFriendly": ""
    +-  },
    +-  {
    +-    "lang": "en",
    +-    "group": "",
    +-    "tags": [],
    +-    "url": "guide/topics/resources/providing-resources.html",
    +-    "timestamp": 1194884220000,
    +-    "image": null,
    +-    "title": "Providing Resources",
    +-    "summary": "Layouts and drawable resources for specific ranges of device screens.",
    +-    "keywords": [],
    +-    "type": "design",
    +-    "titleFriendly": ""
    +-  },
    +-  {
    +-    "lang": "en",
    +-    "group": "",
    +-    "tags": [],
    +-    "url": "training/basics/supporting-devices/screens.html",
    +-    "timestamp": 1194884220000,
    +-    "image": null,
    +-    "title": "Supporting Different Screens",
    +-    "summary": "Optimizing the user experience for different screen sizes and densities.",
    +-    "keywords": [],
    +-    "type": "design",
    +-    "titleFriendly": ""
    +-  },
    +-  {
    +-    "lang": "en",
    +-    "group": "",
    +-    "tags": [],
    +-    "url": "guide/topics/appwidgets/index.html#MetaData",
    +-    "timestamp": 1194884220000,
    +-    "image": null,
    +-    "title": "Adding the AppWidgetProviderInfo Metadata",
    +-    "summary": "How to set the height and width dimensions of a widget.",
    +-    "keywords": [],
    +-    "type": "design",
    +-    "titleFriendly": ""
    +-  },
    +-  {
    +-    "lang": "en",
    +-    "group": "",
    +-    "tags": [],
    +-    "url": "guide/topics/manifest/uses-sdk-element.html#ApiLevels",
    +-    "timestamp": 1194884220000,
    +-    "image": null,
    +-    "title": "Android API Levels",
    +-    "summary": "Introduction to API levels and how they relate to compatibility.",
    +-    "keywords": [],
    +-    "type": "guide",
    +-    "titleFriendly": ""
    +-  },
    +-  {
    +-    "lang": "en",
    +-    "group": "",
    +-    "tags": [],
    +-    "url": "guide/practices/screens_support.html#DeclaringScreenSizeSupport",
    +-    "timestamp": 1194884220000,
    +-    "image": null,
    +-    "title": "Declaring screen size support",
    +-    "summary": "How to declare support for screen sizes in your app\'s manifest.",
    +-    "keywords": [],
    +-    "type": "guide",
    +-    "titleFriendly": ""
    +-  },
    +-  {
    +-    "lang": "en",
    +-    "group": "",
    +-    "tags": [],
    +-    "url": "training/material/animations.html#Touch",
    +-    "timestamp": 1194884220000,
    +-    "image": null,
    +-    "title": "Customize Touch Feedback",
    +-    "summary": "Provide visual confirmation when users interact with your UI.",
    +-    "keywords": [],
    +-    "type": "develop",
    +-    "category": "guide"
    +-  },
    +-  {
    +-    "lang": "en",
    +-    "group": "",
    +-    "tags": [],
    +-    "url": "guide/topics/manifest/uses-feature-element.html#testing",
    +-    "timestamp": 1194884220000,
    +-    "image": null,
    +-    "title": "Checking for hardware feature requirements",
    +-    "summary": "Determining an app’s hardware and software requirements.",
    +-    "keywords": [],
    +-    "type": "guide",
    +-    "titleFriendly": ""
    +-  },
    +-  {
    +-    "lang": "en",
    +-    "group": "",
    +-    "tags": [],
    +-    "url": "https://play.google.com/apps/publish/",
    +-    "timestamp": 1194884220000,
    +-    "image": null,
    +-    "title": "Google Play Developer Console",
    +-    "summary": "The tools console for publishing your app.",
    +-    "keywords": [],
    +-    "type": "guide",
    +-    "titleFriendly": ""
    +-  },
    +-  {
    +-    "lang": "zh-cn",
    +-    "group": "",
    +-    "tags": [],
    +-    "url": "https://play.google.com/apps/publish/?hl=zh-Hans",
    +-    "timestamp": 1194884220000,
    +-    "image": null,
    +-    "title": "Google Play 开发者控制台",
    +-    "summary": "发布应用的开发者控制台",
    +-    "keywords": [],
    +-    "type": "guide",
    +-    "titleFriendly": ""
    +-  },
    +-  {
    +-    "lang": "en",
    +-    "group": "",
    +-    "tags": [],
    +-    "url": "https://youtu.be/SkHHPf3EdzE",
    +-    "timestamp": 1194884220000,
    +-    "image": "https://i1.ytimg.com/vi/SkHHPf3EdzE/maxresdefault.jpg",
    +-    "title": "Level Up Your Android Game",
    +-    "summary": "Learn how to take your game to the next level on Google Play.",
    +-    "keywords": [],
    +-    "type": "guide",
    +-    "titleFriendly": ""
    +-  },
    +-  {
    +-    "lang": "en",
    +-    "group": "",
    +-    "tags": [],
    +-    "url": "https://developers.google.com/+/mobile/android/share/interactive-post",
    +-    "timestamp": 1194884220000,
    +-    "image": 'images/google/gps-googleplus.png',
    +-    "title": "Sharing interactive posts to Google+ from your Android app",
    +-    "summary": "Interactive posts provide an easy and prominent way to allow users to share your site or app with their friends and invite them to take a specific action.",
    +-    "keywords": ["Interactive", "Google+"],
    +-    "type": "guide",
    +-    "titleFriendly": ""
    +-  },
    +-  {
    +-    "lang": "en",
    +-    "group": "",
    +-    "tags": [],
    +-    "url": "https://play.google.com/about/developer-distribution-agreement.html",
    +-    "timestamp": 1194884220000,
    +-    "image": "images/play_dev.jpg",
    +-    "title": "Developer Distribution Agreement",
    +-    "summary": "Terms for distributing and selling apps and in-app products in Google Play.",
    +-    "keywords": [],
    +-    "type": "guide",
    +-    "titleFriendly": ""
    +-  },
    +-  {
    +-    "lang": "en",
    +-    "group": "",
    +-    "tags": [],
    +-    "url": "https://support.google.com/googleplay/android-developer/answer/113417",
    +-    "timestamp": 1194884220000,
    +-    "image": null,
    +-    "title": "Inappropriate content in comments and applications",
    +-    "summary": "More details on what content is appropriate.",
    +-    "keywords": [],
    +-    "type": "guide",
    +-    "titleFriendly": ""
    +-  },
    +-  {
    +-    "lang": "en",
    +-    "group": "",
    +-    "tags": [],
    +-    "url": "https://support.google.com/legal/troubleshooter/1114905",
    +-    "timestamp": 1194884220000,
    +-    "image": null,
    +-    "title": "Removing content from Google",
    +-    "summary": "Find how how to request the removal of content that infringes on your trademark.",
    +-    "keywords": [],
    +-    "type": "guide",
    +-    "titleFriendly": ""
    +-  },
    +-  {
    +-    "lang": "en",
    +-    "group": "",
    +-    "tags": [],
    +-    "url": "https://play.google.com/about/developer-distribution-agreement-addendum.html",
    +-    "timestamp": 1194884220000,
    +-    "image": "images/play_dev.jpg",
    +-    "title": "Google Play for Education Addendum",
    +-    "summary": "Review the education-specific requirements.",
    +-    "keywords": [],
    +-    "type": "guide",
    +-    "titleFriendly": ""
    +-  },
    +-  {
    +-    "lang": "en",
    +-    "group": "",
    +-    "tags": [],
    +-    "url": "https://android-developers.blogspot.com/2013/03/native-rtl-support-in-android-42.html",
    +-    "timestamp": null,
    +-    "image": null,
    +-    "title": "Native RTL Support in Android 4.2",
    +-    "summary": "Blog post that explains how to support RTL in your UI.",
    +-    "keywords": [],
    +-    "type": "guide",
    +-    "titleFriendly": ""
    +-  },
    +-  {
    +-    "lang": "en",
    +-    "group": "",
    +-    "tags": [],
    +-    "url": "guide/topics/resources/string-resource.html#Plurals",
    +-    "timestamp": 1194884220000,
    +-    "image": null,
    +-    "title": "Quantity Strings (Plurals)",
    +-    "summary": "How to work with string plurals according to rules of grammar in a given locale.",
    +-    "keywords": [],
    +-    "type": "guide",
    +-    "titleFriendly": ""
    +-  },
    +-  {
    +-    "lang": "en",
    +-    "group": "",
    +-    "tags": [],
    +-    "url": "reference/java/util/Locale.html",
    +-    "timestamp": 1194884220000,
    +-    "image": null,
    +-    "title": "Locale",
    +-    "summary": "Determine what CLDR data or version of the Unicode spec a particular Android platform version uses.",
    +-    "keywords": [],
    +-    "type": "guide",
    +-    "titleFriendly": ""
    +-  },
    +-    {
    +-    "lang": "en",
    +-    "group": "",
    +-    "tags": [],
    +-    "url": "guide/topics/resources/string-resource.html",
    +-    "timestamp": 1194884220000,
    +-    "image": null,
    +-    "title": "String Resources",
    +-    "summary": "Explains how to use string resources in your UI.",
    +-    "keywords": [],
    +-    "type": "guide",
    +-    "titleFriendly": ""
    +-  },
    +-  {
    +-    "lang": "en",
    +-    "group": "",
    +-    "tags": [],
    +-    "url": "distribute/tools/localization-checklist.html#strings",
    +-    "timestamp": 1194884220000,
    +-    "image": null,
    +-    "title": "Manage strings for localization",
    +-    "summary": "Guidance on having your strings translation ready.",
    +-    "keywords": [],
    +-    "type": "guide",
    +-    "titleFriendly": ""
    +-  },
    +-  {
    +-    "lang": "en",
    +-    "group": "",
    +-    "tags": [],
    +-    "url": "tools/publishing/publishing_overview.html",
    +-    "timestamp": 1194884220000,
    +-    "image": null,
    +-    "title": "General Publishing Overview",
    +-    "summary": "Start here for an overview of publishing options for Android apps.",
    +-    "keywords": [],
    +-    "type": "guide",
    +-    "titleFriendly": ""
    +-  },
    +-  {
    +-    "lang": "en",
    +-    "group": "",
    +-    "tags": [],
    +-    "url": "tools/publishing/preparing.html",
    +-    "timestamp": 1194884220000,
    +-    "image": null,
    +-    "title": "Preparing for Release",
    +-    "summary": "Developer documentation on how to build the signed, release-ready APK. This process is the same for all Android apps.",
    +-    "keywords": [],
    +-    "type": "guide",
    +-    "titleFriendly": ""
    +-  },
    +-  {
    +-    "lang": "en",
    +-    "group": "",
    +-    "tags": [],
    +-    "url": "distribute/googleplay/policies/index.html",
    +-    "timestamp": 1194884220000,
    +-    "image": "images/play_dev.jpg",
    +-    "title": "Google Play Policies and Guidelines",
    +-    "summary": "An overview of Google Play policies for spam, intellectual property, and ads, with examples of common problems.",
    +-    "keywords": [],
    +-    "type": "guide",
    +-    "titleFriendly": ""
    +-  },
    +-  {
    +-    "lang": "en",
    +-    "group": "",
    +-    "tags": [],
    +-    "url": "https://support.google.com/googleplay/android-developer/topic/2364761",
    +-    "timestamp": 1194884220000,
    +-    "image": "images/play_dev.jpg",
    +-    "title": "Policy and Best Practices",
    +-    "summary": "Help Center document describing various content policies and processes.",
    +-    "keywords": [],
    +-    "type": "distribute",
    +-    "titleFriendly": ""
    +-  },
    +-  {
    +-    "lang": "zh-cn",
    +-    "group": "",
    +-    "tags": [],
    +-    "url": "https://support.google.com/googleplay/android-developer/topic/2364761?hl=zh-Hans",
    +-    "timestamp": 1194884220000,
    +-    "image": "images/play_dev.jpg",
    +-    "title": "政策和最佳做法",
    +-    "summary": "内容政策和流程",
    +-    "keywords": [],
    +-    "type": "distribute",
    +-    "titleFriendly": ""
    +-  },
    +-  {
    +-    "lang": "en",
    +-    "group": "",
    +-    "tags": [],
    +-    "url": "google/play/expansion-files.html",
    +-    "timestamp": 1194884220000,
    +-    "image": null,
    +-    "title": "APK Expansion Files",
    +-    "summary": "Developer documentation describing APK Expansion Files and how to support them in your app.",
    +-    "keywords": [],
    +-    "type": "guide",
    +-    "titleFriendly": ""
    +-  },
    +-  {
    +-    "lang": "en",
    +-    "group": "",
    +-    "tags": [],
    +-    "url": "tools/help/proguard.html",
    +-    "timestamp": 1194884220000,
    +-    "image": null,
    +-    "title": "ProGuard",
    +-    "summary": "Developer documentation describing how to use ProGuard to shrink, optimize, and obfuscate your code prior to release.",
    +-    "keywords": [],
    +-    "type": "guide",
    +-    "titleFriendly": ""
    +-  },
    +-  {
    +-    "title":"Dashboards",
    +-    "titleFriendly":"",
    +-    "summary":"This page provides information about the relative number of devices that share a certain characteristic, such as Android version or screen size. This information may help you prioritize efforts for supporting different devices by revealing which devices…",
    +-    "url":"about/dashboards/index.html",
    +-    "group":"",
    +-    "keywords": ["android","dashboard","platforms","versions"],
    +-    "tags": ["#ecosystem","#versions","#whatsnew"],
    +-    "image":"https://chart.googleapis.com/chart?chl=GL%201.1%20only%7CGL%202.0%7CGL%203.0&chf=bg%2Cs%2C00000000&chd=t%3A0.1%2C93.5%2C6.4&chco=c4df9b%2C6fad0c&chs=400x250&cht=p",
    +-    "lang":"en",
    +-    "type":"about"
    +-  },
    +-  {
    +-    "lang": "en",
    +-    "group": "",
    +-    "tags": [],
    +-    "url": "https://developers.google.com/wallet/instant-buy/",
    +-    "timestamp": 1194884220000,
    +-    "image": "",
    +-    "title": "Android Pay APIs",
    +-    "summary": "Developer documentation describing Instant Buy and how to support it in your apps.",
    +-    "keywords": [],
    +-    "type": "guide",
    +-    "titleFriendly": ""
    +-  },
    +-  {
    +-    "lang": "en",
    +-    "group": "",
    +-    "tags": [],
    +-    "url": "https://support.google.com/googleplay/android-developer/answer/1169947",
    +-    "timestamp": 1194884220000,
    +-    "image": "images/play_dev.jpg",
    +-    "title": "Selling Apps in Multiple Currencies",
    +-    "summary": "Help Center document describing how pricing works in Google Play.",
    +-    "keywords": [],
    +-    "type": "guide",
    +-    "titleFriendly": ""
    +-  },
    +-  {
    +-    "lang": "en",
    +-    "group": "",
    +-    "tags": [],
    +-    "url": "https://support.google.com/googleplay/android-developer/answer/1169947?hl=zh-Hans",
    +-    "timestamp": 1194884220000,
    +-    "image": "images/play_dev.jpg",
    +-    "title": "以多种货币销售应用",
    +-    "summary": "如何在Google Play为应用定价",
    +-    "keywords": [],
    +-    "type": "guide",
    +-    "titleFriendly": ""
    +-  },
    +-  {
    +-    "lang": "en",
    +-    "group": "",
    +-    "tags": [],
    +-    "url": "https://support.google.com/googleplay/android-developer/answer/138412",
    +-    "timestamp": 1194884220000,
    +-    "image": "images/play_dev.jpg",
    +-    "title": "Prices and supported currencies",
    +-    "summary": "Help Center document listing supported currencies for pricing your apps.",
    +-    "keywords": [],
    +-    "type": "guide",
    +-    "titleFriendly": ""
    +-  },
    +-    {
    +-    "lang": "zh-cn",
    +-    "group": "",
    +-    "tags": [],
    +-    "url": "https://support.google.com/googleplay/android-developer/answer/138412?hl=zh-Hans",
    +-    "timestamp": 1194884220000,
    +-    "image": "images/play_dev.jpg",
    +-    "title": "各国家/地区获许定价范围和货币",
    +-    "summary": "各国家/地区获许定价范围和货币列表",
    +-    "keywords": [],
    +-    "type": "guide",
    +-    "titleFriendly": ""
    +-  },
    +-  {
    +-    "lang": "en",
    +-    "group": "",
    +-    "tags": [],
    +-    "url": "https://support.google.com/googleplay/android-developer/answer/112622",
    +-    "timestamp": 1194884220000,
    +-    "image": "images/play_dev.jpg",
    +-    "title": "Transaction Fees",
    +-    "summary": "Help Center document describing transaction fees for priced apps and in-app products.",
    +-    "keywords": [],
    +-    "type": "guide",
    +-    "titleFriendly": ""
    +-  },
    +-  {
    +-    "lang": "zh-cn",
    +-    "group": "",
    +-    "tags": [],
    +-    "url": "https://support.google.com/googleplay/android-developer/answer/112622?hl=zh-Hans",
    +-    "timestamp": 1194884220000,
    +-    "image": "images/play_dev.jpg",
    +-    "title": "交易费用",
    +-    "summary": "销售的应用和应用内产品的交易费。",
    +-    "keywords": [],
    +-    "type": "guide",
    +-    "titleFriendly": ""
    +-  },
    +-  {
    +-    "lang": "en",
    +-    "group": "",
    +-    "tags": [],
    +-    "url": "https://support.google.com/googleplay/android-developer/answer/138000",
    +-    "timestamp": 1194884220000,
    +-    "image": "images/play_dev.jpg",
    +-    "title": "Specifying tax rates",
    +-    "summary": "Help Center document describing how to set tax rates for different countries.",
    +-    "keywords": [],
    +-    "type": "guide",
    +-    "titleFriendly": ""
    +-  },
    +-  {
    +-    "lang": "zh-cn",
    +-    "group": "",
    +-    "tags": [],
    +-    "url": "https://support.google.com/googleplay/android-developer/answer/138000?hl=zh-Hans",
    +-    "timestamp": 1194884220000,
    +-    "image": "images/play_dev.jpg",
    +-    "title": "税率",
    +-    "summary": "如何设置不同国家/地区的税率",
    +-    "keywords": [],
    +-    "type": "guide",
    +-    "titleFriendly": ""
    +-  },
    +-  {
    +-    "lang": "en",
    +-    "group": "",
    +-    "tags": [],
    +-    "url": "guide/topics/resources/localization.html",
    +-    "timestamp": 1194884220000,
    +-    "image": "images/play_dev.jpg",
    +-    "title": "Localizing with Resources",
    +-    "summary": "Developer guide to localizing resources in your app.",
    +-    "keywords": [],
    +-    "type": "guide",
    +-    "titleFriendly": ""
    +-  },
    +-  {
    +-    "lang": "en",
    +-    "group": "",
    +-    "tags": [],
    +-    "url": "https://support.google.com/googleplay/android-developer/answer/113475",
    +-    "timestamp": 1194884220000,
    +-    "image": "images/play_dev.jpg",
    +-    "title": "Category types",
    +-    "summary": "Help Center document listing available categories for apps.",
    +-    "keywords": [],
    +-    "type": "guide",
    +-    "titleFriendly": ""
    +-  },
    +-  {
    +-    "lang": "zh-cn",
    +-    "group": "",
    +-    "tags": [],
    +-    "url": "https://support.google.com/googleplay/android-developer/answer/113475?hl=zh-Hans",
    +-    "timestamp": 1194884220000,
    +-    "image": "images/play_dev.jpg",
    +-    "title": "类别",
    +-    "summary": "应用的类别列表。",
    +-    "keywords": [],
    +-    "type": "guide",
    +-    "titleFriendly": ""
    +-  },
    +-  {
    +-    "lang": "en",
    +-    "group": "",
    +-    "tags": [],
    +-    "url": "https://support.google.com/googleplay/android-developer/answer/113476",
    +-    "timestamp": 1194884220000,
    +-    "image": "images/play_dev.jpg",
    +-    "title": "Updates",
    +-    "summary": "Requirements for app updates in Google Play.",
    +-    "keywords": [],
    +-    "type": "guide",
    +-    "titleFriendly": ""
    +-  },
    +-  {
    +-    "lang": "zh-cn",
    +-    "group": "",
    +-    "tags": [],
    +-    "url": "https://support.google.com/googleplay/android-developer/answer/113476?hl=zh-Hans",
    +-    "timestamp": 1194884220000,
    +-    "image": "images/play_dev.jpg",
    +-    "title": "更新应用",
    +-    "summary": "更新Google Play应用的要求。",
    +-    "keywords": [],
    +-    "type": "guide",
    +-    "titleFriendly": ""
    +-  },
    +-  {
    +-    "lang": "en",
    +-    "group": "",
    +-    "tags": [],
    +-    "url": "https://support.google.com/googleplay/android-developer/answer/1153479",
    +-    "timestamp": 1194884220000,
    +-    "image": null,
    +-    "title": "In-app Billing",
    +-    "summary": "Help Center document describing how to correctly set up In-app Billing.",
    +-    "keywords": [],
    +-    "type": "guide",
    +-    "titleFriendly": ""
    +-  },
    +-  {
    +-    "lang": "zh-cn",
    +-    "group": "",
    +-    "tags": [],
    +-    "url": "https://support.google.com/googleplay/android-developer/answer/1153479?hl=zh-Hans",
    +-    "timestamp": 1194884220000,
    +-    "image": null,
    +-    "title": "应用内结算",
    +-    "summary": "如何正确设置应用内商品和订阅结算。",
    +-    "keywords": [],
    +-    "type": "guide",
    +-    "titleFriendly": ""
    +-  },
    +-  {
    +-    "lang": "en",
    +-    "group": "",
    +-    "tags": [
    +-      "#gpfe",
    +-      "#googleplay"
    +-    ],
    +-    "url": "https://youtu.be/vzvpcEffvaE",
    +-    "timestamp": 1383243492000,
    +-    "image": "https://i1.ytimg.com/vi/vzvpcEffvaE/maxresdefault.jpg",
    +-    "title": "Introducing Tablets with Google Play for Education",
    +-    "summary": "Schools in Hillsborough, New Jersey were among the first to try out Nexus 7 tablets with Google Play for Education. See the difference it made for students, teachers, and administrators.",
    +-    "keywords": [],
    +-    "type": "video",
    +-    "titleFriendly": ""
    +-  },
    +-  {
    +-    "lang": "en",
    +-    "group": "",
    +-    "tags": [
    +-      "#engagement",
    +-    ],
    +-    "url": "https://www.youtube.com/yt/dev/",
    +-    "timestamp": 1383243492000,
    +-    "image": "https://www.youtube.com/yt/dev/media/images/yt-dev-home-hero.jpg",
    +-    "title": "YouTube for Developers",
    +-    "summary": "The YouTube APIs and Tools enable you to integrate YouTube's video content and functionality into your website, app, or device.",
    +-    "keywords": [],
    +-    "type": "youtube",
    +-    "titleFriendly": ""
    +-  },
    +-  {
    +-    "lang": "en",
    +-    "group": "",
    +-    "tags": [
    +-      "#engagement",
    +-    ],
    +-    "url": "https://www.google.com/analytics/mobile/",
    +-    "timestamp": 1383243492000,
    +-    "image": "images/cards/analytics-mobile_2x.jpg",
    +-    "title": "Mobile App Analytics",
    +-    "summary": "Mobile App Analytics measures what matters most at all key stages: from first discovery and download to in-app purchases. ",
    +-    "keywords": ["analytics,user behavior"],
    +-    "type": "Guide",
    +-    "titleFriendly": ""
    +-  },
    +-
    +-
    +-  {
    +-    "lang": "en",
    +-    "group": "",
    +-    "tags": [
    +-      "#gcm",
    +-    ],
    +-    "url": "https://www.youtube.com/watch?v=y76rjidm8cU",
    +-    "timestamp": 1383243492000,
    +-    "image": "https://1.bp.blogspot.com/-IF-1-1kA0sg/UYwTidxdi3I/AAAAAAAAAEU/ellLeQ-E1vs/s800/google-io-lockup-2.png",
    +-    "title": "Google Cloud Messaging at I/O 2013",
    +-    "summary": "Google Cloud Messaging allows your services to efficiently send data to applications on Android devices. See what's new, and learn how to use GCM to make your apps more efficient.",
    +-    "keywords": ["gcm"],
    +-    "type": "youtube",
    +-    "titleFriendly": ""
    +-  },
    +-  {
    +-    "lang": "en",
    +-    "group": "",
    +-    "tags": [
    +-      "#gcm",
    +-    ],
    +-    "url": "https://developer.chrome.com/apps/cloudMessagingV2",
    +-    "timestamp": 1383243492000,
    +-    "image": "images/kk-chromium-icon.png",
    +-    "title": "Google Cloud Messaging for Chrome",
    +-    "summary": "Google Cloud Messaging for Chrome (GCM) is a service for signed-in Chrome users that helps developers send message data from servers to their Chrome apps and extensions.",
    +-    "keywords": ["gcm"],
    +-    "type": "guide",
    +-    "titleFriendly": ""
    +-  },
    +-
    +-  {
    +-    "lang": "en",
    +-    "group": "",
    +-    "tags": [
    +-      "#sdkupdates"
    +-    ],
    +-    "url": "https://android-developers.blogspot.com/2013/07/making-beautiful-android-app-icons.html",
    +-    "timestamp": 1194884220000,
    +-    "image": null,
    +-    "title": "Make Beautiful Android App Icons",
    +-    "summary": "Follow these in-depth launcher icon tips on the Android Developers blog.",
    +-    "keywords": [],
    +-    "type": "blog",
    +-    "titleFriendly": ""
    +-  },
    +-     {
    +-    "lang": "en",
    +-    "group": "",
    +-    "tags": [
    +-      "#sdkupdates"
    +-    ],
    +-    "url": "https://android-developers.blogspot.com/2012/12/localize-your-promotional-graphics-on.html",
    +-    "timestamp": 1194884220000,
    +-    "image": null,
    +-    "title": "Localize Your Promotional Graphics",
    +-    "summary": "Learn how to capitalise on international audiences.",
    +-    "keywords": [],
    +-    "type": "blog",
    +-    "titleFriendly": ""
    +-  },
    +-   {
    +-    "lang": "en",
    +-    "group": "",
    +-    "tags": [
    +-      "#sdkupdates"
    +-    ],
    +-    "url": "https://android-developers.blogspot.com/2013/10/making-your-app-content-more-accessible.html",
    +-    "timestamp": 1194884220000,
    +-    "image": null,
    +-    "title": "Make your App Content more Accessible with App Linking",
    +-    "summary": "About using search and deep linking to get more users.",
    +-    "keywords": [],
    +-    "type": "blog",
    +-    "titleFriendly": ""
    +-  },
    +-  {
    +-    "lang": "en",
    +-    "group": "",
    +-    "tags": [],
    +-    "url": "https://developers.google.com/+/mobile/android/share/interactive-post",
    +-    "timestamp": 1194884220000,
    +-    "image": 'images/google/gps-googleplus.png',
    +-    "title": "Sharing interactive posts to Google+ from your Android app",
    +-    "summary": "Interactive posts provide an easy and prominent way to allow users to share your site or app with their friends and invite them to take a specific action.",
    +-    "keywords": ["Interactive", "Google+"],
    +-    "type": "guide",
    +-    "titleFriendly": ""
    +-  },
    +-  {
    +-    "lang": "en",
    +-    "group": "",
    +-    "tags": [],
    +-    "url": "https://developers.google.com/+/mobile/android/",
    +-    "timestamp": 1194884220000,
    +-    "image": 'images/google/gps-googleplus.png',
    +-    "title": "Google+ Platform",
    +-    "summary": "Find out about features such as interactive posts, Hangouts, accessing basic user details and their social graphs to make your app more personal.",
    +-    "keywords": ["Google+"],
    +-    "type": "guide",
    +-    "titleFriendly": ""
    +-  },
    +-  {
    +-    "lang": "en",
    +-    "group": "",
    +-    "tags": [],
    +-    "url": "https://support.google.com/googleplay/android-developer/answer/2528691",
    +-    "timestamp": 1194884220000,
    +-    "image": "images/play_dev.jpg",
    +-    "title": "How to add multiple user accounts to your Developer Console for testing and more.",
    +-    "summary": "",
    +-    "keywords": [],
    +-    "type": "guide",
    +-    "titleFriendly": ""
    +-  },
    +-  {
    +-    "lang": "en",
    +-    "group": "",
    +-    "tags": [],
    +-    "url": "https://developers.google.com/+/mobile/android/share/deep-link",
    +-    "timestamp": 1194884220000,
    +-    "image": null,
    +-    "title": "Adding deep linking to Google+ posts shared from your Android app",
    +-    "summary": "",
    +-    "keywords": [],
    +-    "type": "guide",
    +-    "titleFriendly": ""
    +-  },
    +-  {
    +-    "lang": "en",
    +-    "group": "",
    +-    "tags": [],
    +-    "url": "google/play/licensing/index.html",
    +-    "timestamp": 1194884220000,
    +-    "image": null,
    +-    "title": "Application Licensing",
    +-    "summary": "Information on the features of Google Play to protect your apps’ licences.",
    +-    "keywords": [],
    +-    "type": "guide",
    +-    "titleFriendly": ""
    +-  },
    +-  {
    +-    "lang": "en",
    +-    "group": "",
    +-    "tags": [],
    +-    "url": "design/style/writing.html",
    +-    "timestamp": 1194884220000,
    +-    "image": null,
    +-    "title": "Writing Style",
    +-    "summary": "Android Design guidelines for voice and style in your UI.",
    +-    "keywords": [],
    +-    "type": "guide",
    +-    "titleFriendly": ""
    +-  },
    +-  {
    +-    "lang": "en",
    +-    "group": "",
    +-    "tags": [],
    +-    "url": "https://en.wikipedia.org/wiki/XLIFF",
    +-    "timestamp": 1194884220000,
    +-    "image": null,
    +-    "title": "XML Localisation Interchange File Format (XLIFF)",
    +-    "summary": "Background information on XLIFF.",
    +-    "keywords": [],
    +-    "type": "guide",
    +-    "titleFriendly": ""
    +-  },
    +-  {
    +-    "lang": "en",
    +-    "group": "",
    +-    "tags": [],
    +-    "url": "https://support.google.com/googleplay/android-developer/answer/1078870",
    +-    "timestamp": 1194884220000,
    +-    "image": "images/play_dev.jpg",
    +-    "title": "Graphic Assets for your Application",
    +-    "summary": "Details about the graphics you can add to your product listing.",
    +-    "keywords": [],
    +-    "type": "guide",
    +-    "titleFriendly": ""
    +-  },
    +-  {
    +-    "lang": "zh-cn",
    +-    "group": "",
    +-    "tags": [],
    +-    "url": "https://support.google.com/googleplay/android-developer/answer/1078870?hl=zh-Hans",
    +-    "timestamp": 1194884220000,
    +-    "image": "images/play_dev.jpg",
    +-    "title": "为你的应用的图片资源",
    +-    "summary": "如何在你的应用的商品详情页面上添加图片资源。",
    +-    "keywords": [],
    +-    "type": "guide",
    +-    "titleFriendly": ""
    +-  },
    +-  {
    +-    "lang": "en",
    +-    "group": "",
    +-    "tags": [],
    +-    "url": "https://support.google.com/payments/answer/2741495",
    +-    "timestamp": null,
    +-    "image": null,
    +-    "title": "Issuing Refunds",
    +-    "summary": "Help Center document describing how to issue refunds.",
    +-    "keywords": [],
    +-    "type": "guide",
    +-    "titleFriendly": ""
    +-  },
    +-  {
    +-    "lang": "zh-cn",
    +-    "group": "",
    +-    "tags": [],
    +-    "url": "https://support.google.com/payments/answer/2741495?hl=zh-Hans",
    +-    "timestamp": null,
    +-    "image": null,
    +-    "title": "退回訂單款項",
    +-    "summary": "如何退还已收取的订单款项。",
    +-    "keywords": [],
    +-    "type": "guide",
    +-    "titleFriendly": ""
    +-  },
    +-  {
    +-    "lang": "en",
    +-    "group": "",
    +-    "tags": [],
    +-    "url": "https://android-developers.blogspot.com/2013/11/bring-your-apps-into-classroom-with.html",
    +-    "timestamp": null,
    +-    "image": "distribute/images/gp-edu-apps-image.jpg",
    +-    "title": "Google play for education",
    +-    "summary": " ",
    +-    "keywords": [],
    +-    "type": "distribute",
    +-    "titleFriendly": ""
    +-  },
    +-  {
    +-    "lang": "en",
    +-    "group": "",
    +-    "tags": ["localization", "pricing", "developer support"],
    +-    "url": "https://support.google.com/googleplay/android-developer/table/3541286",
    +-    "timestamp": null,
    +-    "image": "images/play_dev.jpg",
    +-    "title": "Supported locations for distributing your apps in Google Play",
    +-    "summary": "Countries and regions where you can distribute your app in Google Play.",
    +-    "keywords": [],
    +-    "type": "distribute",
    +-    "titleFriendly": ""
    +-  },
    +-  {
    +-    "lang": "zh-cn",
    +-    "group": "",
    +-    "tags": ["localization", "pricing", "developer support"],
    +-    "url": "https://support.google.com/googleplay/android-developer/table/3541286?hl=zh-Hans",
    +-    "timestamp": null,
    +-    "image": "images/play_dev.jpg",
    +-    "title": "支持向Google Play用户发布应用的地区",
    +-    "summary": "支持向Google Play用户发布应用的国家/地区。",
    +-    "keywords": [],
    +-    "type": "distribute",
    +-    "titleFriendly": ""
    +-  },
    +-  {
    +-    "lang": "en",
    +-    "group": "",
    +-    "tags": ["games", "localization", "quality"],
    +-    "url": "https://www.youtube.com/watch?v=SkHHPf3EdzE",
    +-    "timestamp": null,
    +-    "image": "https://developers.google.com/apps/images/io_2013/google-io-logo.png",
    +-    "title": "Level Up Your Android Game",
    +-    "summary": "Learn how to take your game to the next level in this Google I/O session.",
    +-    "keywords": [],
    +-    "type": "distribute",
    +-    "titleFriendly": ""
    +-  },
    +-  {
    +-    "lang": "en",
    +-    "group": "",
    +-    "tags": ["support"],
    +-    "url": "https://support.google.com/groups/answer/46601",
    +-    "timestamp": null,
    +-    "image": null,
    +-    "title": "Google Groups",
    +-    "summary": "Create a group for your community.",
    +-    "keywords": [],
    +-    "type": "distribute",
    +-    "titleFriendly": ""
    +-  },
    +-  {
    +-    "lang": "en",
    +-    "group": "",
    +-    "tags": ["support"],
    +-    "url": "https://support.google.com/plus/topic/2888488",
    +-    "timestamp": null,
    +-    "image": null,
    +-    "title": "Google+ Communities",
    +-    "summary": "Host a Google+ community for testers or users.",
    +-    "keywords": [],
    +-    "type": "distribute",
    +-    "titleFriendly": ""
    +-  },
    +-  {
    +-    "lang": "en",
    +-    "group": "",
    +-    "tags": ["monetize", "ads"],
    +-    "url": "https://www.google.com/doubleclick/publishers/small-business/index.html",
    +-    "timestamp": null,
    +-    "image": "https://www.google.com/doubleclick/publishers/small-business/images/define_ad.png",
    +-    "title": "DoubleClick for Publishers",
    +-    "summary": "A free ad management solution that helps growing publishers sell, schedule, deliver, and measure all of their digital ad inventory.",
    +-    "keywords": ["ads"],
    +-    "type": "distribute",
    +-    "titleFriendly": ""
    +-  },
    +-  {
    +-    "lang": "en",
    +-    "group": "",
    +-    "tags": ["monetize", "ads"],
    +-    "url": "https://support.google.com/googleplay/android-developer/topic/2985714",
    +-    "timestamp": null,
    +-    "image":"images/play_dev.jpg",
    +-    "title": "Policy Center: Ads",
    +-    "summary": "Introduction to ads and system interference policies in Google Play.",
    +-    "keywords": ["ads"],
    +-    "type": "distribute",
    +-    "titleFriendly": ""
    +-  },
    +-  {
    +-    "lang": "en",
    +-    "group": "",
    +-    "tags": [],
    +-    "url": "https://support.google.com/analytics/answer/2611404",
    +-    "timestamp": null,
    +-    "image": "images/cards/analytics-mobile_2x.jpg",
    +-    "title": "Create Audience lists in Google Analytics",
    +-    "summary": "Find out how to use your analytics data to discover high value users and create remarketing audiences to use in AdMob.",
    +-    "keywords": ["ads, analytics, monetize"],
    +-    "type": "distribute",
    +-    "titleFriendly": ""
    +-  },
    +-  {
    +-    "lang": "en",
    +-    "group": "",
    +-    "tags": [],
    +-    "url": "https://admob.blogspot.com/",
    +-    "timestamp": null,
    +-    "image": "images/cards/analytics-mobile_2x.jpg",
    +-    "title": "Inside Admob",
    +-    "summary": "Google’s official blog for news, tips, and information on the AdMob developer platform.",
    +-    "keywords": ["ads, analytics, monetize"],
    +-    "type": "distribute",
    +-    "titleFriendly": ""
    +-  },
    +-  {
    +-    "lang": "en",
    +-    "group": "",
    +-    "tags": [],
    +-    "url": "https://support.google.com/admob/answer/3111064",
    +-    "timestamp": null,
    +-    "image": "distribute/images/advertising.jpg",
    +-    "title": "AdMob in-app conversion tracking",
    +-    "summary": "Use in-app conversion tracking to attribute revenue back to your IAP promotion campaigns and determine which ones earn you the most.",
    +-    "keywords": ["ads, analytics, conversions"],
    +-    "type": "distribute",
    +-    "titleFriendly": ""
    +-  },
    +-  {
    +-    "lang": "en",
    +-    "group": "",
    +-    "tags": ["monetize", "giftcards"],
    +-    "url": "https://play.google.com/about/giftcards/",
    +-    "timestamp": null,
    +-    "image": "images/gp-balance.png",
    +-    "title": "Google Play Gift Cards",
    +-    "summary": "Buy Google Play gift cards online or at a variety of retail stores.",
    +-    "keywords": ["gift card"],
    +-    "type": "distribute",
    +-    "titleFriendly": ""
    +-  },
    +-  {
    +-    "lang": "en",
    +-    "group": "",
    +-    "tags": ["monetize", "paymentmethods"],
    +-    "url": "https://support.google.com/googleplay/answer/2651410",
    +-    "timestamp": null,
    +-    "image": "images/play_dev.jpg",
    +-    "title": "Google Play accepted payment methods",
    +-    "summary": "Support details on the payment methods supported in Google Play.",
    +-    "keywords": ["gift card"],
    +-    "type": "distribute",
    +-    "titleFriendly": ""
    +-  },
    +-  {
    +-    "lang": "en",
    +-    "group": "",
    +-    "tags": [],
    +-    "url": "https://support.google.com/adwords/answer/2471188",
    +-    "timestamp": null,
    +-    "image": "images/play_dev.jpg",
    +-    "title": "AdWords Conversion Optimizer",
    +-    "summary": "Learn how Conversion Optimizer works to find the users who are most likely to convert and to serve them your conversion ads.",
    +-    "keywords": [],
    +-    "type": "distribute",
    +-    "titleFriendly": ""
    +-  },
    +-  {
    +-    "lang": "en",
    +-    "group": "",
    +-    "tags": [],
    +-    "url": "https://developers.google.com/app-conversion-tracking/",
    +-    "timestamp": null,
    +-    "image": "images/play_dev.jpg",
    +-    "title": "Track conversions with the AdWords SDK or server API",
    +-    "summary": "Use the lightweight AdWords app SDK or server-to-server API to track remarketing conversions.",
    +-    "keywords": [],
    +-    "type": "distribute",
    +-    "titleFriendly": ""
    +-  },
    +-  {
    +-    "lang": "en",
    +-    "group": "",
    +-    "tags": [],
    +-    "url": "https://support.google.com/analytics/answer/2611404",
    +-    "timestamp": null,
    +-    "image": "images/play_dev.jpg",
    +-    "title": "Create Remarketing Audiences in Google Analytics",
    +-    "summary": "Learn how to use preconfigured audiences created by the Analytics team or create your own to use in your conversion campaigns.",
    +-    "keywords": [],
    +-    "type": "distribute",
    +-    "titleFriendly": ""
    +-  },
    +-  {
    +-    "lang": "en",
    +-    "group": "",
    +-    "tags": [],
    +-    "url": "https://support.google.com/adwords/answer/1704341",
    +-    "timestamp": null,
    +-    "image": "images/play_dev.jpg",
    +-    "title": "Link your Google Analytics and AdWords accounts",
    +-    "summary": "Gain greater insight into how AdWords is driving app engagement and conversions, and use this insight to improve your ads and app.",
    +-    "keywords": [],
    +-    "type": "distribute",
    +-    "titleFriendly": ""
    +-  },
    +-
    +-  {
    +-    "lang": "en",
    +-    "group": "",
    +-    "tags": ["plus", "social"],
    +-    "url": "https://plus.google.com/+AndroidDevelopers/",
    +-    "timestamp": null,
    +-    "image": "images/plus.jpg",
    +-    "title": "+Android Developers",
    +-    "summary": "Sharing news, ideas, and techniques for success.",
    +-    "keywords": ["+AndroidDevelopers"],
    +-    "type": "Google+",
    +-    "titleFriendly": ""
    +-  },
    +-  {
    +-    "lang": "en",
    +-    "group": "",
    +-    "tags": ["plus", "social"],
    +-    "url": "https://plus.google.com/+GooglePlay",
    +-    "timestamp": null,
    +-    "image": "https://lh4.googleusercontent.com/-IKezweZlcXI/AAAAAAAAAAI/AAAAAAABOvg/uK8Z0jekVE4/s120-c/photo.jpg",
    +-    "title": "+Google Play",
    +-    "summary": "News and discussion about Google Play, apps, and other content in Google+.",
    +-    "keywords": ["+GooglePlay"],
    +-    "type": "Google+",
    +-    "titleFriendly": ""
    +-  },
    +-  {
    +-    "lang": "en",
    +-    "group": "",
    +-    "tags": ["support", "android"],
    +-    "url": "support.html",
    +-    "timestamp": null,
    +-    "image": null,
    +-    "title": "Developer Support",
    +-    "summary": "Links to community and support resources for Android developers.",
    +-    "keywords": ["support"],
    +-    "type": "Google+",
    +-    "titleFriendly": ""
    +-  },
    +-  {
    +-    "lang": "en",
    +-    "group": "",
    +-    "tags": [],
    +-    "url": "https://developers.google.com/analytics/devguides/collection/android/",
    +-    "timestamp": null,
    +-    "image": "images/cards/analytics-mobile_2x.jpg",
    +-    "title": "Mobile App Analytics SDK",
    +-    "summary": "Measure everything about your app. Get started with the Google Analytics SDK for Android.",
    +-    "keywords": ["analytics, user behavior"],
    +-    "type": "sdk",
    +-    "titleFriendly": ""
    +-  },
    +-  {
    +-    "lang": "en",
    +-    "group": "",
    +-    "tags": [],
    +-    "url": "https://developers.google.com/edu/guidelines",
    +-    "timestamp": null,
    +-    "image": "https://developer.android.com/distribute/images/edu-guidelines.jpg",
    +-    "title": "Education Guidelines",
    +-    "summary": "These guidelines and requirements help you develop great apps for students, which offer compelling content and an intuitive user experience on Android tablets.",
    +-    "keywords": [],
    +-    "type": "",
    +-    "titleFriendly": ""
    +-  },
    +-  {
    +-    "lang": "zh-cn",
    +-    "group": "",
    +-    "tags": [],
    +-    "url": "https://developers.google.com/edu/guidelines?hl=zh-Hans",
    +-    "timestamp": null,
    +-    "image": "https://developer.android.com/distribute/images/edu-guidelines.jpg",
    +-    "title": "Education Guidelines",
    +-    "summary": "These guidelines and requirements help you develop great apps for students, which offer compelling content and an intuitive user experience on Android tablets.",
    +-    "keywords": [],
    +-    "type": "",
    +-    "titleFriendly": ""
    +-  },
    +-  {
    +-    "lang": "en",
    +-    "group": "",
    +-    "tags": [],
    +-    "url": "https://developers.google.com/edu/faq",
    +-    "timestamp": null,
    +-    "image": "https://developer.android.com/distribute/images/gpfe-faq.jpg",
    +-    "title": "Education FAQ",
    +-    "summary": "Answers to common questions you might have about Google Play for Education.",
    +-    "keywords": [],
    +-    "type": "",
    +-    "titleFriendly": ""
    +-  },
    +-  {
    +-    "lang": "en",
    +-    "group": "",
    +-    "tags": [],
    +-    "url": "https://developers.google.com/edu/",
    +-    "timestamp": null,
    +-    "image": "https://developers.google.com/edu/images/home-android.png",
    +-    "title": "Chrome Apps in Google Play for Education",
    +-    "summary": "Find out more about Chrome apps in Google Play for Education.",
    +-    "keywords": [],
    +-    "type": "",
    +-    "titleFriendly": ""
    +-  },
    +-  {
    +-    "lang": "en",
    +-    "group": "",
    +-    "tags": [],
    +-    "url": "https://www.google.com/edu/tablets/#tablets-family",
    +-    "timestamp": null,
    +-    "image": "https://www.google.com/edu/images/tablets/big-tablet.png",
    +-    "title": "Google Play for Education Tablets",
    +-    "summary": "Google Play for Education leverages a diverse set up tablets approved for the classroom which may help inform you how to build educational apps.",
    +-    "keywords": [],
    +-    "type": "",
    +-    "titleFriendly": ""
    +-  },
    +-  {
    +-    "lang": "en",
    +-    "group": "",
    +-    "tags": [],
    +-    "url": "https://storage.googleapis.com/androiddevelopers/shareables/stories/Glu_Deerhunter2014_gpgs.pdf",
    +-    "timestamp": null,
    +-    "image": "https://storage.googleapis.com/androiddevelopers/shareables/stories/Glu_Deerhunter2014_gpgs.png",
    +-    "title": "Deer Hunter 2014 by Glu &mdash; Sign-in",
    +-    "summary": "Glu finds that Google Play Game Services helps improve the user experience which leads to increased player happiness. They also find that Play Games Services signed in users tend to play longer and have a higher lifetime value.",
    +-    "keywords": ["stories"],
    +-    "type": "Case Study Deck",
    +-    "titleFriendly": ""
    +-  },
    +-  {
    +-    "lang": "en",
    +-    "group": "",
    +-    "tags": [],
    +-    "url": "https://storage.googleapis.com/androiddevelopers/shareables/stories/ConcreteSoftware_PBABowling_gpgs.pdf",
    +-    "timestamp": null,
    +-    "image": "https://storage.googleapis.com/androiddevelopers/shareables/stories/ConcreteSoftware_PBABowling_gpgs.png",
    +-    "title": "PBA® Bowling Challenge by Concrete Software &mdash; Quests",
    +-    "summary": "Concrete Software finds that Google Play Game Services' quests are a great way to create new content for users that leads to higher engagement.",
    +-    "keywords": ["stories"],
    +-    "type": "Case Study Deck",
    +-    "titleFriendly": ""
    +-  },
    +-  {
    +-    "lang": "en",
    +-    "group": "",
    +-    "tags": [],
    +-    "url": "https://storage.googleapis.com/androiddevelopers/shareables/stories/Dragonplay_DragonplaySlots_gpgs.pdf",
    +-    "timestamp": null,
    +-    "image": "https://storage.googleapis.com/androiddevelopers/shareables/stories/Dragonplay_DragonplaySlots_gpgs.png",
    +-    "title": "Dragonplay Slots by Dragonplay &mdash; Sign-in",
    +-    "summary": "Dragonplay finds that players who sign in with Google Play Games services tend to be high quality users who were highly engaged. They also tend to be easier to convert to paying users.",
    +-    "keywords": ["stories"],
    +-    "type": "Case Study Deck",
    +-    "titleFriendly": ""
    +-  },
    +-  {
    +-    "lang": "en",
    +-    "group": "",
    +-    "tags": [],
    +-    "url": "https://storage.googleapis.com/androiddevelopers/shareables/stories/Gameloft_Asphalt8_gpgs.pdf",
    +-    "timestamp": null,
    +-    "image": "https://storage.googleapis.com/androiddevelopers/shareables/stories/Gameloft_Asphalt8_gpgs.png",
    +-    "title": "Asphalt 8 by Gameloft &mdash; Friends invitations",
    +-    "summary": "Gameloft finds that Google Play Game Services users are more engaged than the average Android user and more likely to convert to paying players.",
    +-    "keywords": ["stories"],
    +-    "type": "Case Study Deck",
    +-    "titleFriendly": ""
    +-  },
    +-  {
    +-    "lang": "en",
    +-    "group": "",
    +-    "tags": [],
    +-    "url": "https://storage.googleapis.com/androiddevelopers/shareables/stories/Glu_EternityWarriors3_gpgs.pdf",
    +-    "timestamp": null,
    +-    "image": "https://storage.googleapis.com/androiddevelopers/shareables/stories/Glu_EternityWarriors3_gpgs.png",
    +-    "title": "Eternity Warriors 3 by Glu &mdash; Gifting",
    +-    "summary": "Glu finds that Google Play Game Services gifting outperforms other implementations (including those with incentives) because of its seamless flow and consistent performance.",
    +-    "keywords": ["stories"],
    +-    "type": "Case Study Deck",
    +-    "titleFriendly": ""
    +-  },
    +-  {
    +-    "lang": "en",
    +-    "group": "",
    +-    "tags": [],
    +-    "url": "https://storage.googleapis.com/androiddevelopers/shareables/stories/HotheadGames_RivalsatWar_gpgs.pdf",
    +-    "timestamp": null,
    +-    "image": "https://storage.googleapis.com/androiddevelopers/shareables/stories/HotheadGames_RivalsatWar_gpgs.jpg",
    +-    "title": "Rivals at War: Firefight by Hothead Games &mdash; Leaderboards",
    +-    "summary": "Hothead Games is planning to include Google Play Game Services features in all their games going forwards after seeing that players that signed in with Play Games Services tend to show higher retention and a higher average revenue.",
    +-    "keywords": ["stories"],
    +-    "type": "Case Study Deck",
    +-    "titleFriendly": ""
    +-  },
    +-  {
    +-    "lang": "en",
    +-    "group": "",
    +-    "tags": [],
    +-    "url": "https://storage.googleapis.com/androiddevelopers/shareables/stories/TMSOFT_Compulsive_gpgs.pdf",
    +-    "timestamp": null,
    +-    "image": "https://storage.googleapis.com/androiddevelopers/shareables/stories/TMSOFT_Compulsive_gpgs.png",
    +-    "title": "Compulsive by TMSOFT &mdash; Cross-platform",
    +-    "summary": "TMSOFT finds that users who authenticate with Play Games Services on Android and iOS play Compulsive twice as much and purchase in-app products over four times as much.",
    +-    "keywords": ["stories"],
    +-    "type": "Case Study Deck",
    +-    "titleFriendly": ""
    +-  },
    +-  {
    +-    "lang": "en",
    +-    "group": "",
    +-    "tags": [],
    +-    "url": "https://storage.googleapis.com/androiddevelopers/shareables/stories/Noodlecake_SuperStickmanGolf2_gpgs.pdf",
    +-    "timestamp": null,
    +-    "image": "https://storage.googleapis.com/androiddevelopers/shareables/stories/Noodlecake_SuperStickmanGolf2_gpgs.png",
    +-    "title": "Super Stickman Golf 2 by Noodlecake Studios &mdash; Multiplayer",
    +-    "summary": "Noodlecake Studios finds that Google Play Game Services’ multiplayer feature helps reduce attrition.",
    +-    "keywords": ["stories"],
    +-    "type": "Case Study Deck",
    +-    "titleFriendly": ""
    +-  },
    +-  {
    +-    "lang": "en",
    +-    "group": "",
    +-    "tags": [],
    +-    "url": "https://storage.googleapis.com/androiddevelopers/shareables/stories/TinyRebel_DoctorWhoLegacy_gpgs.pdf",
    +-    "timestamp": null,
    +-    "image": "https://storage.googleapis.com/androiddevelopers/shareables/stories/TinyRebelGames_DrWhoLegacy_pgps.png",
    +-    "title": "Dr. Doctor Who: Legacy by Tiny Rebel Games &mdash; Achievements",
    +-    "summary": "After integrating achievements and cloud services from Google Play Game Services, Tiny Rebel Games saw a dramatic increase in daily revenues as a result of an increase in daily installs and an increase in the average revenue per install.",
    +-    "keywords": ["stories"],
    +-    "type": "Case Study Deck",
    +-    "titleFriendly": ""
    +-  },
    +-  {
    +-    "lang": "en",
    +-    "group": "",
    +-    "tags": [],
    +-    "url": "https://storage.googleapis.com/androiddevelopers/shareables/stories/Senri_LeosFortune_gpgs.pdf",
    +-    "timestamp": null,
    +-    "image": "https://storage.googleapis.com/androiddevelopers/shareables/stories/Senri_LeosFortune_gpgs.png",
    +-    "title": "Leo’s Fortune by 1337 &amp; Senri &mdash; Saved games",
    +-    "summary": "1337 + Senri finds that Google Play Game Services is easy to integrate and provides essential game functions like cloud saved games, achievements and leaderboards which have a very large adoption rate amongst players.",
    +-    "keywords": ["stories"],
    +-    "type": "Case Study Deck",
    +-    "titleFriendly": ""
    +-  },
    +-  {
    +-    "lang": "en",
    +-    "group": "",
    +-    "tags": ["play,protips"],
    +-    "url": "shareables/distribute/secrets_play/v2/web/secrets_to_app_success_v2_en.pdf",
    +-    "timestamp": 1447437450,
    +-    "image": "images/distribute/secrets_v2_banner.jpg",
    +-    "title": "The Secrets to App Success on Google Play",
    +-    "summary": "Get the updated guide full of useful features, tips, and best practices that will help you grow a successful app or game business on Google Play.",
    +-    "keywords": ["secrets, success, play, google"],
    +-    "type": "Book",
    +-    "category": "distribute"
    +-  },
    +-  {
    +-    "lang": "en",
    +-    "group": "",
    +-    "tags": [],
    +-    "url": "shareables/auto/AndroidAuto-audio-apps.pdf",
    +-    "timestamp": null,
    +-    "image": "auto/images/assets/icons/media_app_playback.png",
    +-    "title": "Android Auto Audio Apps UI Guidelines",
    +-    "summary": "Guidelines for designing audio apps that work with Auto. ",
    +-    "keywords": ["design", "Auto", "Automotive"],
    +-    "type": "Design",
    +-    "titleFriendly": ""
    +-  },
    +-  {
    +-    "lang": "en",
    +-    "group": "",
    +-    "tags": [],
    +-    "url": "shareables/auto/AndroidAuto-messaging-apps.pdf",
    +-    "timestamp": null,
    +-    "image": "auto/images/assets/icons/messaging_app_notifications.png",
    +-    "title": "Android Auto Messaging Apps UI Guidelines",
    +-    "summary": "Guidelines for designing messaging apps that work with Auto. ",
    +-    "keywords": ["design", "Auto", "Automotive"],
    +-    "type": "Design",
    +-    "titleFriendly": ""
    +-  },
    +-  {
    +-    "lang": "en",
    +-    "group": "",
    +-    "tags": [],
    +-    "url": "shareables/auto/AndroidAuto-custom-colors.pdf",
    +-    "timestamp": null,
    +-    "image": "auto/images/ui/gearhead_generic_UI.png",
    +-    "title": "Android Auto Color Customization UI Guidelines",
    +-    "summary": "Guidelines for color-customizing apps that work with Auto. ",
    +-    "keywords": ["design", "Auto", "Automotive"],
    +-    "type": "Design",
    +-    "titleFriendly": ""
    +-  },
    +-  {
    +-    "lang": "en",
    +-    "group": "",
    +-    "tags": [],
    +-    "url": "http://www.youtube.com/watch?v=RRelFvc6Czo",
    +-    "timestamp": null,
    +-    "image": "https://i1.ytimg.com/vi/RRelFvc6Czo/maxresdefault.jpg",
    +-    "title": "Android Developer Story: Smule",
    +-    "summary": "The creators of AutoRap, Magic Piano, and Songify talk about their experiences launching on Android and the explosive global growth they've seen on Google Play.",
    +-    "keywords": ["success", "users"],
    +-    "type": "video",
    +-    "titleFriendly": ""
    +-  },
    +-  {
    +-    "lang": "en",
    +-    "group": "",
    +-    "tags": [],
    +-    "url": "https://developers.google.com/analytics/solutions/mobile-implementation-guide",
    +-    "timestamp": null,
    +-    "image": "images/cards/analytics-mobile_2x.jpg",
    +-    "title": "Mobile Analytics Implementation Guide",
    +-    "summary": "Learn how you can implement additional Google Analytics features to better understand your users and their behavior.",
    +-    "keywords": ["analytics", "Play", "users"],
    +-    "type": "guide",
    +-    "titleFriendly": ""
    +-  },
    +-  {
    +-    "lang": "en",
    +-    "group": "",
    +-    "tags": [],
    +-    "url": "https://www.google.com/tagmanager/",
    +-    "timestamp": null,
    +-    "image": "https://www.google.com/tagmanager/images/gtm-hero-illustration-small.png",
    +-    "title": "Google Tag Manager",
    +-    "summary": "Google Tag Manager enables you to change configuration values in your mobile apps using the Google Tag Manager interface, without having to rebuild and resubmit application binaries to app marketplaces.",
    +-    "keywords": ["analytics", "tagmanager"],
    +-    "type": "guide",
    +-    "titleFriendly": ""
    +-  },
    +-  {
    +-    "lang": "en",
    +-    "group": "",
    +-    "tags": [],
    +-    "url": "https://analyticsacademy.withgoogle.com/course04",
    +-    "timestamp": null,
    +-    "image": "images/cards/analytics-mobile_2x.jpg",
    +-    "title": "Mobile App Analytics Fundamentals",
    +-    "summary": "This self-paced online course on mobile app measurement shows you how Google Analytics data can help you make your app more discoverable and profitable.",
    +-    "keywords": ["analytics"],
    +-    "type": "Open Source Project",
    +-    "titleFriendly": ""
    +-  },
    +-  {
    +-    "lang": "en",
    +-    "group": "",
    +-    "tags": [],
    +-    "url": "https://github.com/googleanalytics/google-analytics-plugin-for-unity",
    +-    "timestamp": null,
    +-    "image": "images/cards/analytics-mobile_2x.jpg",
    +-    "title": "Analytics Plugin for Unity",
    +-    "summary": "If you're building games with Unity, you can now implement Analytics once and ship it on multiple platforms automatically.",
    +-    "keywords": ["analytics", "unity"],
    +-    "type": "Open Source Project",
    +-    "titleFriendly": ""
    +-  },
    +-  {
    +-    "lang": "en",
    +-    "group": "",
    +-    "tags": [],
    +-    "url": "https://developers.google.com/analytics/devguides/collection/android/v4/enhanced-ecommerce",
    +-    "timestamp": null,
    +-    "image": "images/cards/analytics-mobile_2x.jpg",
    +-    "title": "In-App Purchases & Ecommerce",
    +-    "summary": "If your app sells virtual or real goods, ecommerce tracking can help you understand what behaviors lead to purchases.",
    +-    "keywords": ["analytics, ecommerce"],
    +-    "type": "Guide",
    +-    "titleFriendly": ""
    +-  },
    +-  {
    +-    "lang": "en",
    +-    "group": "",
    +-    "tags": [],
    +-    "url": "https://support.google.com/analytics/answer/1032415",
    +-    "timestamp": null,
    +-    "image": "images/cards/analytics-mobile_2x.jpg",
    +-    "title": "Goals",
    +-    "summary": "Track important actions in your app as goals and measure performance against your objectives.",
    +-    "keywords": ["analytics"],
    +-    "type": "Guide",
    +-    "titleFriendly": ""
    +-  },
    +-  {
    +-    "lang": "en",
    +-    "group": "",
    +-    "tags": [],
    +-    "url": "https://support.google.com/analytics/answer/2568874?ref_topic=6012392",
    +-    "timestamp": null,
    +-    "image": "images/cards/analytics-mobile_2x.jpg",
    +-    "title": "Active Users",
    +-    "summary": "The active user report displays your 1-day, 7-day, 14-day and 30-day trailing active users next to each other, to help you analyze performance over time.",
    +-    "keywords": ["analytics"],
    +-    "type": "Guide",
    +-    "titleFriendly": ""
    +-  },
    +-  {
    +-    "lang": "en",
    +-    "group": "",
    +-    "tags": [],
    +-    "url": "https://developers.google.com/analytics/devguides/collection/android/v4/events",
    +-    "timestamp": null,
    +-    "image": "images/cards/analytics-mobile_2x.jpg",
    +-    "title": "Events",
    +-    "summary": "Events let you measure granular in-app activities and understand user journeys.",
    +-    "keywords": ["analytics"],
    +-    "type": "Guide",
    +-    "titleFriendly": ""
    +-  },
    +-  {
    +-    "lang": "en",
    +-    "group": "",
    +-    "tags": [],
    +-    "url": "https://developers.google.com/analytics/devguides/collection/android/v4/customdimsmets",
    +-    "timestamp": null,
    +-    "image": "images/cards/analytics-mobile_2x.jpg",
    +-    "title": "Custom Dimensions",
    +-    "summary": "Custom dimensions enable the association of metadata with hits, users, and sessions in Google Analytics.",
    +-    "keywords": ["analytics"],
    +-    "type": "Guide",
    +-    "titleFriendly": ""
    +-  },
    +-  {
    +-    "lang": "en",
    +-    "group": "",
    +-    "tags": [],
    +-    "url": "https://developers.google.com/analytics/devguides/collection/android/v4/user-id",
    +-    "timestamp": null,
    +-    "image": "images/cards/analytics-mobile_2x.jpg",
    +-    "title": "User ID",
    +-    "summary": "The User ID feature enables Google Analytics to measure user activities that span across devices.",
    +-    "keywords": ["analytics"],
    +-    "type": "Guide",
    +-    "titleFriendly": ""
    +-  },
    +-  {
    +-    "lang": "en",
    +-    "group": "",
    +-    "tags": [],
    +-    "url": "https://developers.google.com/analytics/devguides/collection/android/v4/display-features",
    +-    "timestamp": null,
    +-    "image": "images/cards/analytics-mobile_2x.jpg",
    +-    "title": "Demographic Reporting",
    +-    "summary": "By enabling display features, you can see just how different user segments engage and monetize.",
    +-    "keywords": ["analytics"],
    +-    "type": "Guide",
    +-    "titleFriendly": ""
    +-  },
    +-  {
    +-    "lang": "en",
    +-    "group": "",
    +-    "tags": [],
    +-    "url": "https://support.google.com/analytics/answer/3123906",
    +-    "timestamp": null,
    +-    "image": "images/cards/analytics-mobile_2x.jpg",
    +-    "title": "User Segmentation",
    +-    "summary": "Segments let you compare metrics for different subsets of users to identify trends and opportunities for your apps.",
    +-    "keywords": ["analytics"],
    +-    "type": "Guide",
    +-    "titleFriendly": ""
    +-  },
    +-  {
    +-    "lang": "en",
    +-    "group": "",
    +-    "tags": [],
    +-    "url": "https://developers.google.com/analytics/devguides/collection/android/v4/campaigns",
    +-    "timestamp": null,
    +-    "image": "images/cards/analytics-mobile_2x.jpg",
    +-    "title": "Campaign Tracking",
    +-    "summary": "Measuring campaigns in Google Analytics enables the attribution of campaigns and traffic sources to user activity within your app.",
    +-    "keywords": ["analytics"],
    +-    "type": "Guide",
    +-    "titleFriendly": ""
    +-  },
    +-  {
    +-    "lang": "en",
    +-    "group": "",
    +-    "tags": [],
    +-    "url": "https://support.google.com/analytics/answer/2956981",
    +-    "timestamp": null,
    +-    "image": "images/play_dev.jpg",
    +-    "title": "Google Play Integration",
    +-    "summary": "By linking Analytics and the Play Developer Console, you can gain additional insights into the acquisition flow.",
    +-    "keywords": ["play, analytics"],
    +-    "type": "Guide",
    +-    "titleFriendly": ""
    +-  },
    +-  {
    +-    "lang": "en",
    +-    "group": "",
    +-    "tags": [],
    +-    "url": "https://support.google.com/analytics/answer/1033961",
    +-    "timestamp": null,
    +-    "image": "images/cards/analytics-mobile_2x.jpg",
    +-    "title": "AdWords Integration",
    +-    "summary": "Link Analytics and AdWords to see the entire picture of customer behavior, from ad click or impression through your site to conversion. ",
    +-    "keywords": ["adwords, analytics"],
    +-    "type": "Guide",
    +-    "titleFriendly": ""
    +-  },
    +-  {
    +-    "lang": "en",
    +-    "group": "",
    +-    "tags": [],
    +-    "url": "https://developers.google.com/analytics/devguides/collection/android/v4/campaigns#google-play-url-builder",
    +-    "timestamp": null,
    +-    "image": "images/cards/analytics-mobile_2x.jpg",
    +-    "title": "Campaign URL builder for Google Play",
    +-    "summary": "Easily create your URLs to track install campaigns.",
    +-    "keywords": ["play, analytics"],
    +-    "type": "Guide",
    +-    "titleFriendly": ""
    +-  },
    +-  {
    +-    "lang": "en",
    +-    "group": "",
    +-    "tags": [],
    +-    "url": "https://support.google.com/tagmanager/answer/6003007",
    +-    "timestamp": null,
    +-    "image": "https://www.google.com/tagmanager/images/gtm-hero-illustration-small.png",
    +-    "title": "In-App A/B Testing",
    +-    "summary": "With content experiments in Google Tag Manager you can test multiple variations of your app to find which works best.",
    +-    "keywords": ["tagmanager"],
    +-    "type": "Guide",
    +-    "titleFriendly": ""
    +-  },
    +-  {
    +-    "lang": "en",
    +-    "group": "",
    +-    "tags": [],
    +-    "url": "https://support.google.com/analytics/answer/2785577",
    +-    "timestamp": null,
    +-    "image": "images/cards/analytics-mobile_2x.jpg",
    +-    "title": "Behavior Flow",
    +-    "summary": "The Behavior Flow report visualizes the path users traveled from one Screen or Event to the next. This report can help you discover what content keeps users engaged with your app.",
    +-    "keywords": ["analytics"],
    +-    "type": "Guide",
    +-    "titleFriendly": ""
    +-  },
    +-  {
    +-    "lang": "en",
    +-    "group": "",
    +-    "tags": [],
    +-    "url": "https://support.google.com/analytics/answer/1151300",
    +-    "timestamp": null,
    +-    "image": "images/cards/analytics-mobile_2x.jpg",
    +-    "title": "Custom Reports",
    +-    "summary": "Custom Reports let you create your own reports in your Google Analytics account.",
    +-    "keywords": ["analytics"],
    +-    "type": "Guide",
    +-    "titleFriendly": ""
    +-  },
    +-  {
    +-    "lang": "en",
    +-    "group": "",
    +-    "tags": [],
    +-    "url": "https://support.google.com/analytics/answer/2611268",
    +-    "timestamp": null,
    +-    "image": "images/cards/analytics-mobile_2x.jpg",
    +-    "title": "Audience Lists &amp; Remarketing",
    +-    "summary": "Remarketing with Google Analytics lets you deliver targeted ads to users who've already been to your site or app. You can even base those ads on the behavior those users displayed during their sessions.",
    +-    "keywords": ["analytics"],
    +-    "type": "Guide",
    +-    "titleFriendly": ""
    +-  },
    +-  {
    +-    "lang": "en",
    +-    "group": "",
    +-    "tags": [],
    +-    "url": "https://support.google.com/admob/answer/3508177",
    +-    "timestamp": null,
    +-    "image": "images/cards/analytics-mobile_2x.jpg",
    +-    "title": "AdMob Integration",
    +-    "summary": "With Google Analytics in AdMob, you can view Google Analytics data for your linked apps from within your AdMob account.",
    +-    "keywords": ["analytics"],
    +-    "type": "Guide",
    +-    "titleFriendly": ""
    +-  },
    +-  {
    +-    "lang": "en",
    +-    "group": "",
    +-    "tags": [],
    +-    "url": "https://developers.google.com/analytics/solutions/mobile-campaign-deep-link",
    +-    "timestamp": null,
    +-    "image": "images/cards/analytics-mobile_2x.jpg",
    +-    "title": "Deep-Linking",
    +-    "summary": "Google Analytics gives you a full view of how returning users are interacting with your app, for a holistic view beyond the install.",
    +-    "keywords": ["analytics"],
    +-    "type": "Guide",
    +-    "titleFriendly": ""
    +-  },
    +-  {
    +-    "lang": "en",
    +-    "group": "",
    +-    "tags": [],
    +-    "url": "https://support.google.com/admob/answer/3508177",
    +-    "timestamp": null,
    +-    "image": "images/cards/analytics-mobile_2x.jpg",
    +-    "title": "AdMob Integration",
    +-    "summary": "With Google Analytics in AdMob, you can view Google Analytics data for your linked apps from within your AdMob account.",
    +-    "keywords": ["analytics"],
    +-    "type": "Guide",
    +-    "titleFriendly": ""
    +-  },
    +-  {
    +-    "lang": "en",
    +-    "group": "",
    +-    "tags": [],
    +-    "url": "https://support.google.com/analytics/answer/2568874",
    +-    "timestamp": null,
    +-    "image": "images/cards/analytics-mobile_2x.jpg",
    +-    "title": "Active User Report",
    +-    "summary": "Active user report displays your 1-day, 7-day, 14-day and 30-day trailing active users next to each other, to help you run benchmark analyses of their performance over time.",
    +-    "keywords": ["analytics"],
    +-    "type": "Guide",
    +-    "titleFriendly": ""
    +-  },
    +-  {
    +-    "lang": "en",
    +-    "group": "",
    +-    "tags": [],
    +-    "url": "https://www.google.com/design/spec/animation/",
    +-    "timestamp": null,
    +-    "image": "images/cards/material-animation_2x.png",
    +-    "title": "Animation",
    +-    "summary": "",
    +-    "keywords": [],
    +-    "type": "material design",
    +-    "titleFriendly": ""
    +-  },
    +-  {
    +-    "lang": "en",
    +-    "group": "",
    +-    "tags": [],
    +-    "url": "https://www.google.com/design/spec/style/",
    +-    "timestamp": null,
    +-    "image": "images/cards/material-style_2x.jpg",
    +-    "title": "Style",
    +-    "summary": "",
    +-    "keywords": [],
    +-    "type": "material design",
    +-    "titleFriendly": ""
    +-  },
    +-  {
    +-    "lang": "en",
    +-    "group": "",
    +-    "tags": [],
    +-    "url": "https://www.google.com/design/spec/layout/",
    +-    "timestamp": null,
    +-    "image": "images/cards/material-layout_2x.png",
    +-    "title": "Layout",
    +-    "summary": "",
    +-    "keywords": [],
    +-    "type": "material design",
    +-    "titleFriendly": ""
    +-  },
    +-  {
    +-    "lang": "en",
    +-    "group": "",
    +-    "tags": [],
    +-    "url": "https://www.google.com/design/spec/components/",
    +-    "timestamp": null,
    +-    "image": "images/cards/material-components_2x.jpg",
    +-    "title": "Components",
    +-    "summary": "",
    +-    "keywords": [],
    +-    "type": "material design",
    +-    "titleFriendly": ""
    +-  },
    +-  {
    +-    "lang": "en",
    +-    "group": "",
    +-    "tags": [],
    +-    "url": "https://www.google.com/design/spec/patterns/",
    +-    "timestamp": null,
    +-    "image": "images/cards/material-patterns_2x.png",
    +-    "title": "Patterns",
    +-    "summary": "",
    +-    "keywords": [],
    +-    "type": "material design",
    +-    "titleFriendly": ""
    +-  },
    +-  {
    +-    "lang": "en",
    +-    "group": "",
    +-    "tags": [],
    +-    "url": "https://www.google.com/design/spec/usability/",
    +-    "timestamp": null,
    +-    "image": "images/cards/material-usability_2x.png",
    +-    "title": "Usability",
    +-    "summary": "",
    +-    "keywords": [],
    +-    "type": "material design",
    +-    "titleFriendly": ""
    +-  },
    +-  {
    +-    "lang": "en",
    +-    "group": "",
    +-    "tags": [],
    +-    "url": "https://www.google.com/design/spec/resources/color-palettes.html",
    +-    "timestamp": null,
    +-    "image": "images/cards/material-color-palette_2x.jpg",
    +-    "title": "Color Palettes",
    +-    "summary": "",
    +-    "keywords": [],
    +-    "type": "material design",
    +-    "titleFriendly": ""
    +-  },
    +-  {
    +-    "lang": "en",
    +-    "group": "",
    +-    "tags": [],
    +-    "url": "https://www.google.com/design/spec/resources/layout-templates.html",
    +-    "timestamp": null,
    +-    "image": "images/cards/material-layout-template_2x.jpg",
    +-    "title": "Layout Templates",
    +-    "summary": "",
    +-    "keywords": [],
    +-    "type": "material design",
    +-    "titleFriendly": ""
    +-  },
    +-  {
    +-    "lang": "en",
    +-    "group": "",
    +-    "tags": [],
    +-    "url": "https://www.google.com/design/spec/resources/sticker-sheets-icons.html",
    +-    "timestamp": null,
    +-    "image": "images/cards/material-sticker-sheet_2x.jpg",
    +-    "title": "Sticker Sheets & Icons",
    +-    "summary": "",
    +-    "keywords": [],
    +-    "type": "material design",
    +-    "titleFriendly": ""
    +-  },
    +-  {
    +-    "lang": "en",
    +-    "group": "",
    +-    "tags": [],
    +-    "url": "https://www.google.com/design/spec/resources/roboto-noto-fonts.html",
    +-    "timestamp": null,
    +-    "image": "images/cards/material-typography_2x.jpg",
    +-    "title": "Typography: Roboto and Noto Sans fonts",
    +-    "summary": "",
    +-    "keywords": [],
    +-    "type": "materialdesign",
    +-    "titleFriendly": ""
    +-  },
    +-  {
    +-    "lang": "en",
    +-    "group": "",
    +-    "tags": [
    +-      "icons",
    +-      "material",
    +-      "iconography"
    +-    ],
    +-    "url": "https://www.google.com/design/icons/index.html",
    +-    "timestamp": null,
    +-    "image": "images/cards/card-material-icons-16x9_2x.jpg",
    +-    "title": "Material icon collection",
    +-    "summary": "",
    +-    "keywords": ["icons"],
    +-    "type": "material design",
    +-    "titleFriendly": ""
    +-  },
    +-  {
    +-    "lang": "en",
    +-    "group": "",
    +-    "tags": [],
    +-    "url": "https://support.google.com/adwords/answer/6032059",
    +-    "timestamp": null,
    +-    "image": "distribute/images/advertising.jpg",
    +-    "title": "Setting up Mobile App Install Ads",
    +-    "summary": "With Mobile app installs campaigns on the Search and Display Networks, and TrueView for mobile app promotion on YouTube, you can create custom app install ads that run exclusively on phones and tablets.",
    +-    "keywords": ["marketing", "admob"],
    +-    "type": "distribute",
    +-    "titleFriendly": ""
    +-  },
    +-  {
    +-    "lang": "en",
    +-    "group": "",
    +-    "tags": [],
    +-    "url": "https://developers.google.com/nearby/",
    +-    "timestamp": null,
    +-    "image": "images/play_dev.jpg",
    +-    "title": "Create features based on proximity",
    +-    "summary": "Build simple interactions between nearby devices and people.",
    +-    "keywords": ["nearby", "engage"],
    +-    "type": "distribute",
    +-    "titleFriendly": ""
    +-  },
    +-  {
    +-    "lang": "en",
    +-    "group": "",
    +-    "tags": [],
    +-    "url": "https://www.youtube.com/watch?v=hultDpBS22s",
    +-    "timestamp": null,
    +-    "image": "images/play_dev.jpg",
    +-    "title": "Use Nearby Messages to collaborate",
    +-    "summary": "Nearby Messages is perfect for setting up ad-hoc groups, collaborative sessions, or sharing resources with people in a co-located space.",
    +-    "keywords": ["nearby", "engage"],
    +-    "type": "distribute",
    +-    "titleFriendly": ""
    +-  },
    +-  {
    +-    "lang": "en",
    +-    "group": "",
    +-    "tags": [],
    +-    "url": "https://developers.google.com/beacons",
    +-    "timestamp": null,
    +-    "image": "images/play_dev.jpg",
    +-    "title": "Mark up the world using beacons",
    +-    "summary": "Give your users better location and proximity experiences by providing a strong context signal for their devices in the form of Bluetooth low energy (BLE) beacons with Eddystone.",
    +-    "keywords": ["nearby", "engage"],
    +-    "type": "distribute",
    +-    "titleFriendly": ""
    +-  },
    +-  {
    +-    "lang": "en",
    +-    "group": "",
    +-    "tags": [],
    +-    "url": "https://support.google.com/adwords/answer/6167164",
    +-    "timestamp": null,
    +-    "image": "distribute/images/advertising.jpg",
    +-    "title": "Best practices for Mobile App Engagement",
    +-    "summary": "Learn how to market to your user base to drive re-engagement with your app. ",
    +-    "keywords": ["marketing", "admob"],
    +-    "type": "distribute",
    +-    "titleFriendly": ""
    +-  },
    +-  {
    +-    "lang": "en",
    +-    "group": "",
    +-    "tags": [
    +-      "marketing",
    +-      "engagement",
    +-      "adwords1"
    +-    ],
    +-    "url": "https://support.google.com/adwords/answer/6032073",
    +-    "timestamp": null,
    +-    "image": "https://www.gstatic.com/images/icons/material/product/2x/adwords_64dp.png",
    +-    "title": "Setting up Mobile App Engagement Ads",
    +-    "summary": "Mobile app engagement campaigns are a great choice for advertisers focused on connecting with people who already have their app.",
    +-    "keywords": [
    +-      "marketing",
    +-      "engagement",
    +-      "adwords"
    +-    ],
    +-    "type": "distribute",
    +-    "titleFriendly": ""
    +-  },
    +-  {
    +-    "lang": "en",
    +-    "group": "",
    +-    "tags": [
    +-      "marketing",
    +-      "engagement",
    +-      "translate"
    +-    ],
    +-    "url": "https://support.google.com/l10n/answer/6359997",
    +-    "timestamp": null,
    +-    "image": "images/play_dev.jpg",
    +-    "title": "Use the App Translation Service",
    +-    "summary": "The App Translation Service is a human translation service. It makes it easy to order translations for app UI strings, Play Store text, in-app purchase products, and universal app campaign ads.",
    +-    "keywords": [
    +-      "marketing",
    +-      "engagement",
    +-      "translate"
    +-    ],
    +-    "type": "distribute",
    +-    "titleFriendly": ""
    +-  },
    +-  {
    +-    "lang": "en",
    +-    "group": "",
    +-    "tags": [
    +-      "marketing",
    +-      "engagement"
    +-    ],
    +-    "url": "https://support.google.com/adwords/answer/6167162",
    +-    "timestamp": null,
    +-    "image": "https://www.gstatic.com/images/icons/material/product/2x/adwords_64dp.png",
    +-    "title": "Best Practices for Mobile App Installs",
    +-    "summary": "Getting your mobile app discovered can be challenging. Learn how to drive downloads of your app and grow a valuable user base.",
    +-    "keywords": ["marketing", "adwords"],
    +-    "type": "distribute",
    +-    "titleFriendly": ""
    +-  },
    +-  {
    +-    "lang": "en",
    +-    "group": "",
    +-    "tags": [],
    +-    "url": "https://support.google.com/admob/topic/2784623",
    +-    "timestamp": null,
    +-    "image": "distribute/images/advertising.jpg",
    +-    "title": "Set up your AdMob account",
    +-    "summary": "Setting up your AdMob account in the right way will help you get the most value, check out the Setup and Basics guide.",
    +-    "keywords": ["marketing", "admob"],
    +-    "type": "distribute",
    +-    "titleFriendly": ""
    +-    },
    +-    {
    +-    "lang": "en",
    +-    "group": "",
    +-    "tags": [],
    +-    "url": "https://analyticsacademy.withgoogle.com/mobile-app",
    +-    "timestamp": null,
    +-    "image": "distribute/images/advertising.jpg",
    +-    "title": "Analytics Academy for Mobile Apps",
    +-    "summary": "Learn how to use Google Analytics to make your app more discoverable and profitable.",
    +-    "keywords": ["marketing", "analytics"],
    +-    "type": "distribute",
    +-    "titleFriendly": ""
    +-  },
    +-  {
    +-    "lang": "en",
    +-    "group": "",
    +-    "tags": [],
    +-    "url": "https://www.udacity.com/courses/ud876-3",
    +-    "timestamp": null,
    +-    "image": "distribute/images/advertising.jpg",
    +-    "title": "Learn how to show ads in your Android app",
    +-    "summary": "Take this online course to learn how to use AdMob to display ads in your Android app.",
    +-    "keywords": ["marketing", "analytics"],
    +-    "type": "distribute",
    +-    "titleFriendly": ""
    +-  },
    +-  {
    +-    "lang": "en",
    +-    "group": "",
    +-    "tags": [],
    +-    "url": "https://developers.google.com/mobile-ads-sdk/download",
    +-    "timestamp": null,
    +-    "image": "distribute/images/advertising.jpg",
    +-    "title": "Admob Ads",
    +-    "summary": "Use the Mobile Ads SDK to start showing AdMob ads in your apps.",
    +-    "keywords": ["marketing", "adwords"],
    +-    "type": "Guide",
    +-    "titleFriendly": ""
    +-  },
    +-  {
    +-    "lang": "en",
    +-    "group": "",
    +-    "tags": [],
    +-    "url": "https://support.google.com/admob/",
    +-    "timestamp": null,
    +-    "image": "distribute/images/advertising.jpg",
    +-    "title": "AdMob Help Center",
    +-    "summary": "For setup assistance, general info, and fixes for specific problems check out the AdMob Help Center.",
    +-    "keywords": ["admob"],
    +-    "type": "distribute",
    +-    "titleFriendly": ""
    +-  },
    +-  {
    +-    "lang": "en",
    +-    "group": "",
    +-    "tags": [],
    +-    "url": "https://support.google.com/admob/answer/2753860",
    +-    "timestamp": null,
    +-    "image": "distribute/images/advertising.jpg",
    +-    "title": "AdMob Policy Guidelines",
    +-    "summary": "Learn about best practices for displaying AdMob ads in your apps to maximize revenue.",
    +-    "keywords": ["admob"],
    +-    "type": "distribute",
    +-    "titleFriendly": ""
    +-  },
    +-  {
    +-    "lang": "en",
    +-    "group": "",
    +-    "tags": [],
    +-    "url": "https://developers.google.com/app-invites/",
    +-    "timestamp": 1383243492000,
    +-    "image": "images/cards/google-search_2x.png",
    +-    "title": "Set up App Invites",
    +-    "summary": "Bring new users to your apps with personal recommendations, incentives, and offers.",
    +-    "keywords": ["invites", "appinvites", "engagement", "getusers"],
    +-    "type": "guide",
    +-    "titleFriendly": ""
    +-  },
    +-
    +-  {
    +-    "lang": "en",
    +-    "group": "",
    +-    "tags": [],
    +-    "url": "https://developers.google.com/app-indexing/",
    +-    "timestamp": 1383243492000,
    +-    "image": "images/cards/google-search_2x.png",
    +-    "title": "Set Up App Indexing",
    +-    "summary": "Surface your app content in Google seaerch. Deep link direct to your apps.",
    +-    "keywords": ["search", "appindexing", "engagement", "getusers"],
    +-    "type": "guide",
    +-    "titleFriendly": ""
    +-  },
    +-  {
    +-    "lang": "en",
    +-    "group": "",
    +-    "tags": [],
    +-    "url": "https://developers.google.com/app-indexing/webmasters/details",
    +-    "timestamp": null,
    +-    "image": "images/cards/google-search_2x.png",
    +-    "title": "Index your app",
    +-    "summary": "Index your app today by adding deep links and verifying its official web site to ensure it starts appearing in Google Search results. ",
    +-    "keywords": ["appindexing","search","getusers"],
    +-    "type": "distribute",
    +-    "titleFriendly": ""
    +-  },
    +-  {
    +-    "lang": "en",
    +-    "group": "",
    +-    "tags": [],
    +-    "url": "https://developers.google.com/identity/sign-in/android/people",
    +-    "timestamp": 1383243492000,
    +-    "image": "images/cards/google-sign-in_2x.png",
    +-    "title": "Get user profile details",
    +-    "summary": "After users sign-in with Google, you can access their age range, language, and public profile information.",
    +-    "keywords": ["signin", "identity", "google"],
    +-    "type": "guide",
    +-    "titleFriendly": ""
    +-  },
    +-
    +-
    +-  {
    +-    "lang": "en",
    +-    "group": "",
    +-    "tags": [],
    +-    "url": "https://developers.google.com/identity/sign-in/android/",
    +-    "timestamp": "",
    +-    "image": "images/cards/google-sign-in_2x.png",
    +-    "title": "Google Sign-In",
    +-    "summary": "Discover how you can enhance user experiences on your website or in your app using information provided by their Google identity.",
    +-    "keywords": ["signin", "identity", "google"],
    +-    "type": "guide",
    +-    "titleFriendly": ""
    +-  },
    +-  {
    +-    "lang": "en",
    +-    "group": "",
    +-    "tags": [],
    +-    "url": "https://developers.google.com/+/features/play-installs",
    +-    "timestamp": 1383243492000,
    +-    "image": "images/cards/google-sign-in_2x.png",
    +-    "title": "Over-the-air installs",
    +-    "summary": "Follow this step-by-step guide to quickly add Google Sign-in and over-the-air app installs to your website.",
    +-    "keywords": ["signin", "google", "installs"],
    +-    "type": "guide",
    +-    "titleFriendly": ""
    +-  },
    +-  {
    +-    "lang": "en",
    +-    "group": "",
    +-    "tags": [],
    +-    "url": "https://developers.google.com/+/features/analytics",
    +-    "timestamp": 1383243492000,
    +-    "image": 'images/google/gps-googleplus.png',
    +-    "title": "Google+ Insights",
    +-    "summary": "Measure impressions of the over-the-air install prompt, resulting installs, and success rate by day, week, and month.",
    +-    "keywords": ["signin", "identity"],
    +-    "type": "guide",
    +-    "titleFriendly": ""
    +-  },
    +-
    +- // Online courses
    +-
    +- {
    +-    "title":"UX Design for Mobile Developers",
    +-    "titleFriendly":"",
    +-    "summary":"Learn how to design a 5-star app.",
    +-    "url":"https://www.udacity.com/course/ud849",
    +-    "group":"",
    +-    "keywords": ["mobile","ux","design"],
    +-    "tags": ["courses, start"],
    +-    "image":"images/cards/courses/mobile_ux_course.jpg",
    +-    "lang":"en",
    +-    "type":"online course"
    +-  },
    +-  {
    +-    "title":"Developing Android Apps",
    +-    "titleFriendly":"",
    +-    "summary":"Learn Android and build an app!",
    +-    "url":"https://www.udacity.com/course/ud853",
    +-    "group":"",
    +-    "keywords": ["android", "start","firstapp","sdk"],
    +-    "tags": ["courses, start"],
    +-    "image":"images/cards/courses/android_fundamentals_course.jpg",
    +-    "lang":"en",
    +-    "type":"online course"
    +-  },
    +-  {
    +-    "title":"Android Performance",
    +-    "titleFriendly":"",
    +-    "summary":"Optimize your apps for speed and usability.",
    +-    "url":"https://www.udacity.com/course/ud825",
    +-    "group":"",
    +-    "keywords": ["android, performance","battery"],
    +-    "tags": ["courses, performance"],
    +-    "image":"images/cards/courses/android_performance_course.jpg",
    +-    "lang":"en",
    +-    "type":"online course"
    +-  },
    +-  {
    +-    "title":"Enroll in the Android Nanodegree",
    +-    "titleFriendly":"",
    +-    "summary":"Enroll in the Android Nanodegree to build the skills to work as an Android developer.",
    +-    "url":"https://www.udacity.com/android",
    +-    "group":"",
    +-    "keywords": ["android, nanodegree"],
    +-    "tags": ["courses"],
    +-    "image":"images/cards/courses/android_nanodegree.png",
    +-    "lang":"en",
    +-    "type":"online course"
    +-  },
    +-  {
    +-    "title":"Advanced Android App Development",
    +-    "titleFriendly":"",
    +-    "summary":"Productionize and publish your apps.",
    +-    "url":"https://www.udacity.com/course/ud855",
    +-    "group":"",
    +-    "keywords": ["android, experts"],
    +-    "tags": ["courses, expert"],
    +-    "image":"images/cards/courses/advanced_android_course.jpg",
    +-    "lang":"en",
    +-    "type":"online course"
    +-  },
    +-  {
    +-    "title":"Material Design for Android Developers",
    +-    "titleFriendly":"",
    +-    "summary":"Learn how to make your apps material.",
    +-    "url":"https://www.udacity.com/course/ud862",
    +-    "group":"",
    +-    "keywords": ["android, design, pure, material"],
    +-    "tags": ["courses, start, material"],
    +-    "image":"images/cards/courses/android_design_course.jpg",
    +-    "lang":"en",
    +-    "type":"online course"
    +-  },
    +-  {
    +-    "title":"Android for Beginners",
    +-    "titleFriendly":"",
    +-    "summary":"Make your first Android app, even if you don't write code.",
    +-    "url":"https://www.udacity.com/course/ud837",
    +-    "group":"",
    +-    "keywords": ["android, sdk, firstapp"],
    +-    "tags": ["courses, start"],
    +-    "image":"images/cards/courses/beginning_android_course.jpg",
    +-    "lang":"en",
    +-    "type":"online course"
    +-  },
    +-  {
    +-    "title":"Gradle for Android and Java",
    +-    "titleFriendly":"",
    +-    "summary":"Build better apps through automation",
    +-    "url":"https://www.udacity.com/course/ud867",
    +-    "group":"",
    +-    "keywords": ["gradle","studio", "sdk"],
    +-    "tags": ["courses, gradle, sdk"],
    +-    "image":"images/cards/courses/gradle_course.jpg",
    +-    "lang":"en",
    +-    "type":"online course"
    +-  },
    +-  {
    +-    "title":"Add Location and Context to your app",
    +-    "titleFriendly":"",
    +-    "summary":"Make Your Android App Location Aware.",
    +-    "url":"https://www.udacity.com/course/ud876-1",
    +-    "group":"",
    +-    "keywords": ["google services, context, location"],
    +-    "tags": ["courses, google, location, context"],
    +-    "image":"images/cards/courses/android_location_course.png",
    +-    "lang":"en",
    +-    "type":"online course"
    +-  },
    +-  {
    +-    "title":"Analytics and Tag Manager for Android",
    +-    "titleFriendly":"",
    +-    "summary":"Use Analytics and Tag Manager in Your Apps.",
    +-    "url":"https://www.udacity.com/course/ud876-2",
    +-    "group":"",
    +-    "keywords": ["google services, analytics, tag manager"],
    +-    "tags": ["courses, google, analytics"],
    +-    "image":"images/cards/courses/android_analytics_course.png",
    +-    "lang":"en",
    +-    "type":"online course"
    +-  },
    +-  {
    +-    "title":"AdMob for Android",
    +-    "titleFriendly":"",
    +-    "summary":"Monetize Your App by Displaying Ads.",
    +-    "url":"https://www.udacity.com/course/ud876-3",
    +-    "group":"",
    +-    "keywords": ["monetize, google services, ads, admob"],
    +-    "tags": ["courses, google, ads, admob"],
    +-    "image":"images/cards/courses/admob_course.png",
    +-    "lang":"en",
    +-    "type":"online course"
    +-  },
    +-  {
    +-    "title":"Add Maps to your Android app",
    +-    "titleFriendly":"",
    +-    "summary":"Use maps, cameras, markers and more in your app.",
    +-    "url":"https://www.udacity.com/course/ud876-4",
    +-    "group":"",
    +-    "keywords": ["google, maps, marker, camera"],
    +-    "tags": ["courses, google, maps"],
    +-    "image":"images/cards/courses/android_maps_course.png",
    +-    "lang":"en",
    +-    "type":"online course"
    +-  },
    +-  {
    +-    "title":"Add Sign-in to your Android app",
    +-    "titleFriendly":"",
    +-    "summary":"Build a Seamless Sign-In Experience.",
    +-    "url":"https://www.udacity.com/course/ud876-5",
    +-    "group":"",
    +-    "keywords": ["google services, signin, authorization"],
    +-    "tags": ["courses, google, auth"],
    +-    "image":"images/cards/courses/android_identity_course.png",
    +-    "lang":"en",
    +-    "type":"online course"
    +-  },
    +-  {
    +-    "title":"Android Wear Development",
    +-    "titleFriendly":"",
    +-    "summary":"Extend your Apps to Android Smartwatches.",
    +-    "url":"https://www.udacity.com/course/ud875A",
    +-    "group":"",
    +-    "keywords": ["wear, wearables, smartwatch"],
    +-    "tags": ["courses, wear, wearable"],
    +-    "image":"images/cards/courses/android_wear_course.jpg",
    +-    "lang":"en",
    +-    "type":"online course"
    +-  },
    +-  {
    +-    "title":"Android TV and Google Cast Development",
    +-    "titleFriendly":"",
    +-    "summary":"Extend your Apps to the Big Screen.",
    +-    "url":"https://www.udacity.com/course/ud875B",
    +-    "group":"",
    +-    "keywords": ["cast, living room"],
    +-    "tags": ["courses, cast, tv"],
    +-    "image":"images/cards/courses/android_tv_cast_course.jpg",
    +-    "lang":"en",
    +-    "type":"online course"
    +-  },
    +-  {
    +-    "title":"Android Auto Development",
    +-    "titleFriendly":"",
    +-    "summary":"Put your apps in the driver's seat.",
    +-    "url":"https://www.udacity.com/course/ud875C",
    +-    "group":"",
    +-    "keywords": ["auto"],
    +-    "tags": ["courses, auto"],
    +-    "image":"images/cards/courses/android_auto_course.jpg",
    +-    "lang":"en",
    +-    "type":"online course"
    +-  },
    +-
    +-
    +- // TODO remove this?
    +-  {
    +-    "title":"Android Wear Materials",
    +-    "titleFriendly":"",
    +-    "summary":"Drag and drop your way to beautifully designed Android Wear apps.",
    +-    "url":"design/downloads/index.html#Wear",
    +-    "group":"",
    +-    "keywords": ["icons","stencils","color swatches"],
    +-    "tags": ["icons","stencils","colorswatches"],
    +-    "image":"images/cards/android-wear-materials_2x.jpg",
    +-    "lang":"en",
    +-    "type":"design"
    +-  },
    +-  {
    +-    "title":"Watch Faces for Android Wear",
    +-    "titleFriendly":"",
    +-    "summary":"Watch faces let you customize the most prominent UI feature of Android wearables. The API is simple enough for rapid development and flexible enough to build something awesome.",
    +-    "url":"https://www.youtube.com/watch?v=AK38PJZmIW8&list=PLWz5rJ2EKKc-kIrPiq098QH9dOle-fLef",
    +-    "group":"",
    +-    "keywords": ["wear", "wearable", "watch face"],
    +-    "tags": [],
    +-    "image":"https://i1.ytimg.com/vi/AK38PJZmIW8/maxresdefault.jpg",
    +-    "lang":"en",
    +-    "type":"video"
    +-  },
    +-  {
    +-    "title":"Android Support Library",
    +-    "titleFriendly":"",
    +-    "summary":"These essential components help you build a great app that works on the huge variety of Android devices, faster.",
    +-    "url":"https://www.youtube.com/watch?v=3PIc-DuEU2s&list=PLWz5rJ2EKKc9e0d55YHgJFHXNZbGHEXJX",
    +-    "group":"",
    +-    "keywords": ["support", "compatibility"],
    +-    "tags": [],
    +-    "image":"https://i1.ytimg.com/vi/3PIc-DuEU2s/maxresdefault.jpg",
    +-    "lang":"en",
    +-    "type":"Video"
    +-  },
    +-  {
    +-    "title":"Consistent Design with the AppCompat Support Library",
    +-    "titleFriendly":"",
    +-    "summary":"Getting a great looking app doesn't have to be hard: AppCompat, part of the Android Support Library, gives you a consistent design baseline that works on all Android 2.1 or higher devices.",
    +-    "url":"https://www.youtube.com/watch?v=5Be2mJzP-Uw&list=PLWz5rJ2EKKc9e0d55YHgJFHXNZbGHEXJX",
    +-    "group":"",
    +-    "keywords": ["support", "compatibility","design-code"],
    +-    "tags": [],
    +-    "image":"https://i1.ytimg.com/vi/5Be2mJzP-Uw/maxresdefault.jpg",
    +-    "lang":"en",
    +-    "type":"Video"
    +-  },
    +-  {
    +-    "title":"Introducing Gradle",
    +-    "titleFriendly":"",
    +-    "summary":"Android Studio uses an entirely new and flexible Gradle-based build system. You will be able to create multiple build variants for a single project, manage library dependencies and always be sure that your application builds correctly across different environments.",
    +-    "url":"https://www.youtube.com/watch?v=cD7NPxuuXYY&list=PLWz5rJ2EKKc8I9gHTMh5yKkwRRGE8BjbQ",
    +-    "group":"",
    +-    "keywords": ["tools", "studio","gradle"],
    +-    "tags": [],
    +-    "image":"https://i1.ytimg.com/vi/cD7NPxuuXYY/maxresdefault.jpg",
    +-    "lang":"en",
    +-    "type":"Video"
    +-  },
    +-  {
    +-    "title":"Android Studio Layout Editor",
    +-    "titleFriendly":"",
    +-    "summary":"Android Studio includes a rich, visual layout editor that helps developers create better user interfaces. It eliminates the need to deploy the APK on a real device with each change, making iterations faster and helping eliminate common errors earlier in the development process.",
    +-    "url":"https://www.youtube.com/watch?v=JLLnhwtDoHw&list=PLWz5rJ2EKKc8I9gHTMh5yKkwRRGE8BjbQ",
    +-    "group":"",
    +-    "keywords": ["tools", "studio","layout"],
    +-    "tags": [],
    +-    "image":"https://i1.ytimg.com/vi/JLLnhwtDoHw/maxresdefault.jpg",
    +-    "lang":"en",
    +-    "type":"Video"
    +-  },
    +-  {
    +-    "title":"Debugging and testing in Android Studio",
    +-    "titleFriendly":"",
    +-    "summary":"Learn about new debugger features in Android Studio 1.2: value inlining, quick access to referring objects and a Java .class decompiler, just to name a few. See some new tools and views that let you monitor the CPU and memory performance of your app from within the IDE. ",
    +-    "url":"https://www.youtube.com/watch?v=2I6fuD20qlY&list=PLWz5rJ2EKKc8I9gHTMh5yKkwRRGE8BjbQ",
    +-    "group":"",
    +-    "keywords": ["tools", "studio","debugging","profiling","performance"],
    +-    "tags": [],
    +-    "image":"https://i1.ytimg.com/vi/2I6fuD20qlY/maxresdefault.jpg",
    +-    "lang":"en",
    +-    "type":"Video"
    +-  },
    +-  {
    +-    "title":"Scale with Google Cloud Platform",
    +-    "titleFriendly":"",
    +-    "summary":"Build, test, and deploy applications on Google's highly-scalable and reliable infrastructure for your web, mobile and backend solutions.",
    +-    "url":"https://cloud.google.com/docs/",
    +-    "group":"",
    +-    "keywords": [],
    +-    "tags": [],
    +-    "image":"images/cards/cloud-platform_2x.png",
    +-    "lang":"en",
    +-    "type":"distribute"
    +-  },
    +-  {
    +-    "title":"Opportunities & Programs",
    +-    "titleFriendly":"",
    +-    "summary":"Take advantage of the many ways you can distribute your app to consumers, students, and businesses through Google Play.",
    +-    "url":"distribute/googleplay/index.html#opportunities",
    +-    "group":"",
    +-    "keywords": [],
    +-    "tags": [],
    +-    "image":"images/cards/program-edu_2x.jpg",
    +-    "lang":"en",
    +-    "type":"distribute"
    +-  },
    +-  {
    +-    "title":"Join the Android for Work DevHub",
    +-    "titleFriendly":"",
    +-    "summary":"The Android for Work DevHub is a place to help developers keep up with Android in the workplace.",
    +-    "url":"https://www.google.com/work/android/developers/applyDevHub/",
    +-    "group":"",
    +-    "keywords": ["work", "enterprise", "isv", "devhub"],
    +-    "tags": [],
    +-    "image":"images/work/cards/work-devhub_600px.png",
    +-    "lang":"en",
    +-    "type":"Community"
    +-  },
    +-  {
    +-    "title":"Enterprise Mobility Managers",
    +-    "titleFriendly":"",
    +-    "summary":"Integrate Android for Work into your enterprise mobility management (EMM) solution.",
    +-    "url":"https://developers.google.com/android/work/",
    +-    "group":"",
    +-    "keywords": ["work", "enterprise", "emm"],
    +-    "tags": [],
    +-    "image":"images/work/cards/work-cloud_600px.png",
    +-    "lang":"en",
    +-    "type":"guide"
    +-  },
    +-  {
    +-    "title":"Learn More About Android for Work",
    +-    "titleFriendly":"",
    +-    "summary":"Android for Work makes your favorite phones and tablets the perfect business tools.",
    +-    "url":"https://www.google.com/work/android/",
    +-    "group":"",
    +-    "keywords": ["work", "enterprise", "emm"],
    +-    "tags": [],
    +-    "image":"images/work/cards/work-profile_600px.png",
    +-    "lang":"en",
    +-    "type":"about"
    +-  },
    +-  {
    +-    "title":"Build a Device Policy Controller",
    +-    "titleFriendly":"",
    +-    "summary":"Create and administer a managed profile on an employee's device.",
    +-    "url":"https://developers.google.com/android/work/build-dpc",
    +-    "group":"",
    +-    "keywords": ["work", "enterprise", "emm"],
    +-    "tags": [],
    +-    "image":"images/work/cards/work-folder_600px.png",
    +-    "lang":"en",
    +-    "type":"guide"
    +-  },
    +-  {
    +-    "title":"Android for Work for Developers",
    +-    "titleFriendly":"",
    +-    "summary":"Watch the videos in this playlist to understand more about Android for Work and get tips on developing enterprise apps.",
    +-    "url":"https://www.youtube.com/watch?v=jQWB_-o1kz4&list=PLOU2XLYxmsIKAK2Bhv19H2THwF-22O5WX",
    +-    "group":"",
    +-    "keywords": ["work", "enterprise", "emm"],
    +-    "tags": [],
    +-    "image":"https://i1.ytimg.com/vi/jQWB_-o1kz4/maxresdefault.jpg",
    +-    "lang":"en",
    +-    "type":"youtube"
    +-  },
    +-  {
    +-    "title":"App Configurations, Testing and Launchers",
    +-    "titleFriendly":"",
    +-    "summary":"With Android for Work you can make your apps remotely configurable. We also cover how to test your app in a managed environment.",
    +-    "url":"https://www.youtube.com/watch?v=39NkpWkaH8M&index=2&list=PLOU2XLYxmsIKAK2Bhv19H2THwF-22O5WX",
    +-    "group":"",
    +-    "keywords": ["work", "enterprise", "emm"],
    +-    "tags": [],
    +-    "image":"https://i1.ytimg.com/vi/39NkpWkaH8M/maxresdefault.jpg",
    +-    "lang":"en",
    +-    "type":"youtube"
    +-  },
    +-  {
    +-    "title":"Building an Enterprise Ready App",
    +-    "titleFriendly":"",
    +-    "summary":"A holistic view of Android for Work for developers.",
    +-    "url":"https://www.youtube.com/watch?v=dH41OutAMNM&list=PLOU2XLYxmsIKAK2Bhv19H2THwF-22O5WX",
    +-    "group":"",
    +-    "keywords": ["work", "enterprise", "emm"],
    +-    "tags": [],
    +-    "image":"https://i1.ytimg.com/vi/dH41OutAMNM/maxresdefault.jpg",
    +-    "lang":"en",
    +-    "type":"youtube"
    +-  },
    +-  {
    +-    "title":"Android for Work: Single Use Devices",
    +-    "titleFriendly":"",
    +-    "summary":"Single-purpose computers are everywhere, and Android can meet that need.",
    +-    "url":"https://www.youtube.com/watch?v=j3QC6hcpy90",
    +-    "group":"",
    +-    "keywords": ["work", "enterprise", "emm"],
    +-    "tags": [],
    +-    "image":"https://i1.ytimg.com/vi/j3QC6hcpy90/maxresdefault.jpg",
    +-    "lang":"en",
    +-    "type":"youtube"
    +-  },
    +-  {
    +-    "title":"Your Apps at Work",
    +-    "titleFriendly":"",
    +-    "summary":"In this Google I/O 2016 session we’ll give you details for making your app more attractive to businesses.",
    +-    "url":"https://www.youtube.com/watch?v=Za0OQo8DRM4",
    +-    "group":"",
    +-    "keywords": ["work", "enterprise", "emm"],
    +-    "tags": [],
    +-    "image":"https://i1.ytimg.com/vi/Za0OQo8DRM4/maxresdefault.jpg",
    +-    "lang":"en",
    +-    "type":"youtube"
    +-  },
    +-  {
    +-    "title":"Discover YouTube cards",
    +-    "titleFriendly":"",
    +-    "summary":"Find out more about YouTube cards, the options available, and how to use them to get the most from your YouTube content.",
    +-    "url":"https://support.google.com/youtube/answer/6140493",
    +-    "group":"",
    +-    "keywords": ["youtube", "video", "users", "installs"],
    +-    "tags": [],
    +-    "image":"images/cards/card-youtube_2x.png",
    +-    "lang":"en",
    +-    "type":"distribute"
    +-  },
    +-    {
    +-    "title":"What is YouTube account good standing?",
    +-    "titleFriendly":"",
    +-    "summary":"Learn what it means for an account to be in good standing from the YouTube Help Center.",
    +-    "url":"https://support.google.com/youtube/answer/2797387",
    +-    "group":"",
    +-    "keywords": ["youtube", "video", "users", "installs"],
    +-    "tags": [],
    +-    "image":"images/cards/card-youtube_2x.png",
    +-    "lang":"en",
    +-    "type":"distribute"
    +-  },
    +-  {
    +-    "title":"What’s New in Android N Developer Preview",
    +-    "titleFriendly":"",
    +-    "summary":"Learn all about the new features in the Android N Preview.",
    +-    "url":"https://www.youtube.com/watch?v=CsulIu3UaUM",
    +-    "group":"",
    +-    "keywords": ["n preview"],
    +-    "tags": [],
    +-    "image":"https://i1.ytimg.com/vi/CsulIu3UaUM/maxresdefault.jpg",
    +-    "lang":"en",
    +-    "type":"Video"
    +-  },
    +-  {
    +-    "title":"Developing for Android 6.0 (Marshmallow)",
    +-    "titleFriendly":"",
    +-    "summary":"This video covers how to get started with the preview, important APIs to test and how to provide feedback on the preview.",
    +-    "url":"https://www.youtube.com/watch?v=yYU4DHLwoRk",
    +-    "group":"",
    +-    "keywords": ["Marshmallow"],
    +-    "tags": [],
    +-    "image":"https://i1.ytimg.com/vi/yYU4DHLwoRk/maxresdefault.jpg",
    +-    "lang":"en",
    +-    "type":"Video"
    +-  },
    +-  {
    +-    "title":"Google I/O 2015 - What's new in Android",
    +-    "titleFriendly":"",
    +-    "summary":"This session will highlight the most exciting new developer features of the Android platform.",
    +-    "url":"https://www.youtube.com/watch?v=ndBdf1_oOGA",
    +-    "group":"",
    +-    "keywords": ["Marshmallow"],
    +-    "tags": [],
    +-    "image":"https://i1.ytimg.com/vi/ndBdf1_oOGA/maxresdefault.jpg",
    +-    "lang":"en",
    +-    "type":"Video"
    +-  },
    +-  {
    +-    "title":"Fingerprint and payments APIs",
    +-    "titleFriendly":"",
    +-    "summary":"New fingerprint and payments APIs are introduced in M, to enable enhanced UX and security for online purchasing, banking, and retail payments.",
    +-    "url":"https://www.youtube.com/watch?v=VOn7VrTRlA4",
    +-    "group":"",
    +-    "keywords": ["Marshmallow"],
    +-    "tags": [],
    +-    "image":"https://i1.ytimg.com/vi/VOn7VrTRlA4/maxresdefault.jpg",
    +-    "lang":"en",
    +-    "type":"Video"
    +-  },
    +-  {
    +-    "title":"Introduction to Voice Interaction API",
    +-    "titleFriendly":"",
    +-    "summary":"This video covers how to use the Voice Interaction API to support system or custom voice actions.",
    +-    "url":"https://www.youtube.com/watch?v=OW1A4XFRuyc",
    +-    "group":"",
    +-    "keywords": ["Marshmallow"],
    +-    "tags": [],
    +-    "image":"https://i1.ytimg.com/vi/OW1A4XFRuyc/maxresdefault.jpg",
    +-    "lang":"en",
    +-    "type":"Video"
    +-  },
    +-  {
    +-    "title":"Android Auto Backup for Apps",
    +-    "titleFriendly":"",
    +-    "summary":"Android Backup is the automatic, cloud-based backup and restore of users’ apps when they set up a new device.",
    +-    "url":"https://www.youtube.com/watch?v=HXacyy0HSW0",
    +-    "group":"",
    +-    "keywords": ["Marshmallow"],
    +-    "tags": [],
    +-    "image":"https://i1.ytimg.com/vi/HXacyy0HSW0/maxresdefault.jpg",
    +-    "lang":"en",
    +-    "type":"Video"
    +-  },
    +-  {
    +-    "title":"New APIs in M for Android for Work",
    +-    "titleFriendly":"",
    +-    "summary":"Android M extends Android for Work functionality with a new set of APIs for Enterprise Mobility Management providers to offer new features and policy controls to IT Departments.",
    +-    "url":"https://www.youtube.com/watch?v=vcSj8ln-BlE",
    +-    "group":"",
    +-    "keywords": ["Marshmallow"],
    +-    "tags": [],
    +-    "image":"https://i1.ytimg.com/vi/vcSj8ln-BlE/maxresdefault.jpg",
    +-    "lang":"en",
    +-    "type":"Video"
    +-  },
    +-  {
    +-    "title":"Runtime Permissions in Android 6.0 Marshmallow",
    +-    "titleFriendly":"",
    +-    "summary":"Learn how to integrate runtime permissions into your Android app.",
    +-    "url":"https://www.youtube.com/watch?v=C8lUdPVSzDk",
    +-    "group":"",
    +-    "keywords": ["Marshmallow"],
    +-    "tags": [],
    +-    "image":"https://i1.ytimg.com/vi/C8lUdPVSzDk/maxresdefault.jpg",
    +-    "lang":"en",
    +-    "type":"Video"
    +-  },
    +-  {
    +-    "title":"Introduction to Doze",
    +-    "titleFriendly":"",
    +-    "summary":"An overview of Doze and how to make sure that your app behaves as expected both in and out of Doze mode. ",
    +-    "url":"https://youtu.be/N72ksDKrX6c",
    +-    "group":"",
    +-    "keywords": ["Marshmallow"],
    +-    "tags": [],
    +-    "image":"https://i1.ytimg.com/vi/N72ksDKrX6c/maxresdefault.jpg",
    +-    "lang":"en",
    +-    "type":"Video"
    +-  },
    +-  {
    +-    "title":"The Nexus 5X, Nexus 6P and Android Marshmallow",
    +-    "titleFriendly":"",
    +-    "summary":"The new Nexus 5X and Nexus 6P along with some of the most significant developer features in the latest Android release,.",
    +-    "url":"https://youtu.be/U9tw5ypqEN0",
    +-    "group":"",
    +-    "keywords": ["Marshmallow"],
    +-    "tags": [],
    +-    "image":"https://i1.ytimg.com/vi/U9tw5ypqEN0/maxresdefault.jpg",
    +-    "lang":"en",
    +-    "type":"Video"
    +-  },
    +-  {
    +-    "title":"Asking For Permission Fine",
    +-    "titleFriendly":"",
    +-    "summary":"Picking the right way and time to ask for a permission is critical to it being granted. ",
    +-    "url":"https://youtu.be/iZqDdvhTZj0",
    +-    "group":"",
    +-    "keywords": ["Marshmallow"],
    +-    "tags": [],
    +-    "image":"https://i1.ytimg.com/vi/iZqDdvhTZj0/maxresdefault.jpg",
    +-    "lang":"en",
    +-    "type":"Video"
    +-  },
    +-  {
    +-    "title":"Data Binding Library",
    +-    "titleFriendly":"",
    +-    "summary":"Data Binding Library is a way to write declarative layouts and minimize the glue code necessary to bind your application logic and layouts. ",
    +-    "url":"https://youtu.be/5sCQjeGoE7M",
    +-    "group":"",
    +-    "keywords": ["Marshmallow"],
    +-    "tags": [],
    +-    "image":"https://i1.ytimg.com/vi/5sCQjeGoE7M/maxresdefault.jpg",
    +-    "lang":"en",
    +-    "type":"Video"
    +-  },
    +-  {
    +-    "title":"App Links",
    +-    "titleFriendly":"",
    +-    "summary":"App Links is a new feature of Android Marshmallow that brings a faster way of opening website links for domains that you own.",
    +-    "url":"https://youtu.be/LQoohRwojmw",
    +-    "group":"",
    +-    "keywords": ["Marshmallow"],
    +-    "tags": [],
    +-    "image":"https://i1.ytimg.com/vi/LQoohRwojmw/maxresdefault.jpg",
    +-    "lang":"en",
    +-    "type":"Video"
    +-  },
    +-  {
    +-    "title":"Android M Permissions",
    +-    "titleFriendly":"",
    +-    "summary":"An introduction to Android M runtime permissions in Android M from Google I/O 2015. ",
    +-    "url":"https://www.youtube.com/watch?v=f17qe9vZ8RM",
    +-    "group":"",
    +-    "keywords": ["Marshmallow"],
    +-    "tags": [],
    +-    "image":"https://i1.ytimg.com/vi/f17qe9vZ8RM/maxresdefault.jpg",
    +-    "lang":"en",
    +-    "type":"Video"
    +-  },
    +-  {
    +-    "lang": "ja",
    +-    "title": "Gaming Everywhere",
    +-    "titleFriendly": "",
    +-    "summary": "東京ゲームショウ 2014 の基調講演より。",
    +-    "url": "https://www.youtube.com/watch?v=xelYnWcYkuE",
    +-    "group": "",
    +-    "keywords": [],
    +-    "tags": [],
    +-    "image": "https://img.youtube.com/vi/xelYnWcYkuE/hqdefault.jpg",
    +-    "type": "youtube"
    +-  },
    +-  {
    +-    "lang": "ja",
    +-    "title": "Playtime Tokyo",
    +-    "titleFriendly": "",
    +-    "summary": "アプリビジネスのノウハウを各担当者が講演しました。",
    +-    "url": "https://www.youtube.com/playlist?list=PLCOC_kP3nqGIHEgwm9mybvA04Vn4Cg9nn",
    +-    "group": "",
    +-    "keywords": [],
    +-    "tags": [],
    +-    "image": "https://img.youtube.com/vi/lJdjY3z6-LY/hqdefault.jpg",
    +-    "type": "youtube"
    +-  },
    +-  {
    +-    "lang": "ja",
    +-    "title": "Android Wear 関連の動画に日本語字幕が付きました",
    +-    "titleFriendly": "",
    +-    "summary": "",
    +-    "url": "https://googledevjp.blogspot.jp/2014/12/android-wear.html",
    +-    "group": "",
    +-    "keywords": [],
    +-    "tags": [],
    +-    "image": "https://i1.ytimg.com/vi/4JcDYkgqksY/maxresdefault.jpg",
    +-    "type": "blog"
    +-  },
    +-  {
    +-    "lang": "ja",
    +-    "title": "Android Studio 1.0 をリリースしました",
    +-    "titleFriendly": "",
    +-    "summary": "",
    +-    "url": "https://googledevjp.blogspot.jp/2014/12/android-studio-10.html",
    +-    "group": "",
    +-    "keywords": [],
    +-    "tags": [],
    +-    "image": "https://3.bp.blogspot.com/-1hV3sD1At74/VIaQSWBasUI/AAAAAAAABAU/9vYLJMsmMuQ/s1600/studio-logo.png",
    +-    "type": "blog"
    +-  },
    +-  {
    +-    "lang": "ja",
    +-    "title": "Google Play 開発者サービス 6.5 のご紹介",
    +-    "titleFriendly": "",
    +-    "summary": "",
    +-    "url": "https://googledevjp.blogspot.jp/2014/12/google-play-65.html",
    +-    "group": "",
    +-    "keywords": [],
    +-    "tags": [],
    +-    "image": "https://1.bp.blogspot.com/-4BNREC0Jojo/VGo7ahW35wI/AAAAAAAABAc/9thZl94F6fY/s1600/GMS%2B-%2BRelease%2BBlog%2BNacho%2B-%2BMap%2BToolbar.png",
    +-    "type": "blog"
    +-  },
    +-  {
    +-    "lang": "ja",
    +-    "title": "Alpha and Beta Testing",
    +-    "titleFriendly": "",
    +-    "summary": "アプリのローンチにまつわるリスクを最小限にするために必須のツールです。[英語コンテンツ]",
    +-    "url": "intl/ja/distribute/googleplay/developer-console.html#alpha-beta",
    +-    "group": "",
    +-    "keywords": [],
    +-    "tags": [],
    +-    "image": "images/gp-dc-ab.png",
    +-    "type": "distribute"
    +-  },
    +-  {
    +-    "lang": "ja",
    +-    "title": "Finding Success on Google Play",
    +-    "titleFriendly": "",
    +-    "summary": "Google Play での成功の秘訣がこの一冊に。[英語コンテンツ]",
    +-    "url": "intl/ja/distribute/googleplay/guide.html",
    +-    "group": "",
    +-    "keywords": [],
    +-    "tags": [],
    +-    "image": "distribute/images/play_dev_guide_b.jpg",
    +-    "type": "distribute"
    +-  },
    +-  {
    +-    "lang": "ja",
    +-    "title": "Core App Quality",
    +-    "titleFriendly": "",
    +-    "summary": "",
    +-    "url": "intl/ja/distribute/essentials/quality/core.html",
    +-    "group": "",
    +-    "keywords": [],
    +-    "tags": [],
    +-    "image": "images/gp-core-quality.png",
    +-    "type": "distribute"
    +-  },
    +-  {
    +-    "lang": "ja",
    +-    "title": "Google Play アプリ ポリシー センター",
    +-    "titleFriendly": "",
    +-    "summary": "",
    +-    "url": "https://support.google.com/googleplay/android-developer/answer/4430948?hl=ja",
    +-    "group": "",
    +-    "keywords": [],
    +-    "tags": [],
    +-    "image": "https://storage.googleapis.com/support-kms-prod/SNP_712EA2784949DDF085C46E3BE7B1DC618A09_4389356_en_v0",
    +-    "type": "distribute"
    +-  },
    +-  {
    +-    "lang": "ja",
    +-    "title": "Developer Support",
    +-    "titleFriendly": "",
    +-    "summary": "",
    +-    "url": "intl/ja/support.html",
    +-    "group": "",
    +-    "keywords": [],
    +-    "tags": [],
    +-    "image": "",
    +-    "type": "distribute"
    +-  },
    +-  {
    +-    "lang": "ja",
    +-    "title": "Wear App Quality",
    +-    "titleFriendly": "",
    +-    "summary": "いよいよウェアラブルの時代が到来。[英語コンテンツ]",
    +-    "url": "intl/ja/distribute/essentials/quality/wear.html",
    +-    "group": "",
    +-    "keywords": [],
    +-    "tags": [],
    +-    "image": "distribute/images/gp-wear-quality.png",
    +-    "type": "distribute"
    +-  },
    +-  {
    +-    "lang": "ja",
    +-    "title": "Google Cloud Platform が支える、新感覚リアルタイム RPG ユニゾンリーグ - 株式会社エイチームの GCP 導入事例",
    +-    "titleFriendly": "",
    +-    "summary": "スケーラブルなバックエンドを実現する Google Cloud Platform の最新導入事例。",
    +-    "url": "https://googleforwork-japan.blogspot.jp/2014/12/gcp-google-cloud-platform-rpg-gcp.html",
    +-    "group": "",
    +-    "keywords": [],
    +-    "tags": [],
    +-    "image": "https://3.bp.blogspot.com/-xp7KoPkbne4/VI_PfoFil3I/AAAAAAAAA3U/-k1UZ0zjCBc/s1600/unison-league.jpeg",
    +-    "type": "distribute"
    +-  },
    +-  {
    +-    "lang": "ja",
    +-    "title": "Monetize with Ads",
    +-    "titleFriendly": "",
    +-    "summary": "アプリ内広告成功のコツがここに。[英語コンテンツ]",
    +-    "url": "intl/ja/distribute/monetize/ads.html",
    +-    "group": "",
    +-    "keywords": [],
    +-    "tags": [],
    +-    "image": "distribute/images/advertising.jpg",
    +-    "type": "distribute"
    +-  },
    +-  {
    +-    "lang": "ko",
    +-    "title": "구글 플레이 2015년 비전",
    +-    "titleFriendly": "",
    +-    "summary": "G-Star 구글 컨퍼런스",
    +-    "url": "https://www.youtube.com/watch?v=7X9Ue0Nfdh4&index=2&list=PL_WJkTbDHdBksDBRoqfeyLchEQqBAOlNl",
    +-    "group": "",
    +-    "keywords": [],
    +-    "tags": [],
    +-    "image": "https://img.youtube.com/vi/7X9Ue0Nfdh4/hqdefault.jpg",
    +-    "type": "youtube"
    +-  },
    +-  {
    +-    "lang": "ko",
    +-    "title": "구글 플레이 게임",
    +-    "titleFriendly": "",
    +-    "summary": "게임 프로필, 퀘스트, 세이브드 게임 등의 신기능 소개",
    +-    "url": "https://www.youtube.com/watch?v=83FpwuschCQ",
    +-    "group": "",
    +-    "keywords": [],
    +-    "tags": [],
    +-    "image": "https://img.youtube.com/vi/83FpwuschCQ/hqdefault.jpg",
    +-    "type": "youtube"
    +-  },
    +-  {
    +-    "lang": "ko",
    +-    "title": "안드로이드 5.0 롤리팝을 맞이하는 개발자를 위한 안내서",
    +-    "titleFriendly": "",
    +-    "summary": "",
    +-    "url": "https://googledevkr.blogspot.com/2014/11/android50guidefordevelopers.html",
    +-    "group": "",
    +-    "keywords": [],
    +-    "tags": [],
    +-    "image": "https://lh5.googleusercontent.com/0Gx4Ob_WvIgNOMv3hVMuUm4O7KuSWyxCEFIvy39_6fgXh2q2azqjZf3bpZoEk-LMW-K8GwYMfyYfMUAwp38hhPQ6WFNnddhN2E2_GF3-XBQI_qjhISviz10h_mGgDWsZKA",
    +-    "type": "blog"
    +-  },
    +-  {
    +-    "lang": "ko",
    +-    "title": "안드로이드 앱을 위한 머티리얼 디자인 체크 리스트",
    +-    "titleFriendly": "",
    +-    "summary": "",
    +-    "url": "https://googledevkr.blogspot.com/2014/10/material-design-on-android-checklist.html",
    +-    "group": "",
    +-    "keywords": [],
    +-    "tags": [],
    +-    "image": "https://lh4.googleusercontent.com/JKoxeDdmsj6gYHV8rmp96U1jHj7FKeMzGBaaFu35kXp5EpJR9Ei9MQFAYghjwJoycdgydw-FZTuFNY8pDx63MWhy37rKC96ajoDXEMzvo9W0sj5yC2-uSYJdhpazVOP2cA",
    +-    "type": "blog"
    +-  },
    +-  {
    +-    "lang": "ko",
    +-    "title": "App Compat 라이브러리",
    +-    "titleFriendly": "",
    +-    "summary": "",
    +-    "url": "https://googledevkr.blogspot.com/2014/10/appcompat-v21-material-design-for-pre.html",
    +-    "group": "",
    +-    "keywords": [],
    +-    "tags": [],
    +-    "image": "https://2.bp.blogspot.com/-7fF9ayZ6PgI/U9iFpk5FNEI/AAAAAAAAAs0/4P4SCvdB_4M/s640/image00.png",
    +-    "type": "blog"
    +-  },
    +-  {
    +-    "lang": "ko",
    +-    "title": "Alpha and Beta Testing",
    +-    "titleFriendly": "",
    +-    "summary": "출시 전에 완벽한 사전 테스트 [영문]",
    +-    "url": "intl/ko/distribute/googleplay/developer-console.html#alpha-beta",
    +-    "group": "",
    +-    "keywords": [],
    +-    "tags": [],
    +-    "image": "images/gp-dc-ab.png",
    +-    "type": "distribute"
    +-  },
    +-  {
    +-    "lang": "ko",
    +-    "title": "Finding Success on Google Play",
    +-    "titleFriendly": "",
    +-    "summary": "구글 플레이에서 성공하는 비결 [영문]",
    +-    "url": "intl/ko/distribute/googleplay/guide.html",
    +-    "group": "",
    +-    "keywords": [],
    +-    "tags": [],
    +-    "image": "distribute/images/play_dev_guide_b.jpg",
    +-    "type": "distribute"
    +-  },
    +-  {
    +-    "lang": "ko",
    +-    "title": "Core App Quality",
    +-    "titleFriendly": "",
    +-    "summary": "고품질 안드로이드 앱 개발 가이드 [영문]",
    +-    "url": "intl/ko/distribute/essentials/quality/core.html",
    +-    "group": "",
    +-    "keywords": [],
    +-    "tags": [],
    +-    "image": "images/gp-core-quality.png",
    +-    "type": "distribute"
    +-  },
    +-  {
    +-    "lang": "ko",
    +-    "title": "Policy Guidelines and Practices",
    +-    "titleFriendly": "",
    +-    "summary": "숙지해야할 중요한 정책 [영문]",
    +-    "url": "https://support.google.com/googleplay/android-developer/answer/4430948?hl=ko",
    +-    "group": "",
    +-    "keywords": [],
    +-    "tags": [],
    +-    "image": "https://storage.googleapis.com/support-kms-prod/SNP_712EA2784949DDF085C46E3BE7B1DC618A09_4389356_en_v0",
    +-    "type": "distribute"
    +-  },
    +-  {
    +-    "lang": "ko",
    +-    "title": "Developer Support",
    +-    "titleFriendly": "",
    +-    "summary": "개발자 지원 센터 활용 [영문]",
    +-    "url": "intl/ko/support.html",
    +-    "group": "",
    +-    "keywords": [],
    +-    "tags": [],
    +-    "image": "https://lh3.googleusercontent.com/-mGTYed3Uh-E/AAAAAAAAAAI/AAAAAAAAF58/qNYbk4mMhI0/s120-c/photo.jpg",
    +-    "type": "distribute"
    +-  },
    +-  {
    +-    "lang": "ko",
    +-    "title": "Wear App Quality",
    +-    "titleFriendly": "",
    +-    "summary": "웨어러블 앱 개발 가이드 [영문]",
    +-    "url": "intl/ko/distribute/essentials/quality/wear.html",
    +-    "group": "",
    +-    "keywords": [],
    +-    "tags": [],
    +-    "image": "distribute/images/gp-wear-quality.png",
    +-    "type": "distribute"
    +-  },
    +-  {
    +-    "lang": "ko",
    +-    "title": "Android TV 어플리케이션 개발",
    +-    "titleFriendly": "",
    +-    "summary": "앱과 게임을 거실에서 가족과 함께 [영문]",
    +-    "url": "intl/ko/tv/index.html",
    +-    "group": "",
    +-    "keywords": [],
    +-    "tags": [],
    +-    "image": "design/tv/images/atv-home.jpg",
    +-    "type": "distribute"
    +-  },
    +-  {
    +-    "lang": "ko",
    +-    "title": "구글 플레이 게임 서비스",
    +-    "titleFriendly": "",
    +-    "summary": "다양한 구글 플레이 게임 서비스 기능 알아보기 [영문]",
    +-    "url": "intl/ko/google/play-services/games.html",
    +-    "group": "",
    +-    "keywords": [],
    +-    "tags": [],
    +-    "image": "https://developers.google.com/games/services/images/gamescreen3.jpg",
    +-    "type": "distribute"
    +-  },
    +-  {
    +-    "lang": "ko",
    +-    "title": "Monetize with Ads",
    +-    "titleFriendly": "",
    +-    "summary": "광고로 수익 창출하기 [영문]",
    +-    "url": "intl/ko/distribute/monetize/ads.html",
    +-    "group": "",
    +-    "keywords": [],
    +-    "tags": [],
    +-    "image": "distribute/images/advertising.jpg",
    +-    "type": "distribute"
    +-  },
    +-  {
    +-    "url":"https://www.youtube.com/watch?v=QDM52bblwlg",
    +-    "image": "images/distribute/hero-family-discovery.jpg",
    +-    "title": "Introducing the new family discovery experience on Google Play",
    +-    "summary": "Help families create little moments on Google Play. Opt-in your apps now.",
    +-    "tags":["families","googleplay"],
    +-    "type":"youtube"
    +-  },
    +-  {
    +-    "url":"https://www.youtube.com/watch?v=wcjqBSei3a0&list=PLOU2XLYxmsIKLNUPiFCWVtcO7mZRZ9MmS",
    +-    "image": "https://i1.ytimg.com/vi/wcjqBSei3a0/maxresdefault.jpg",
    +-    "title": "Developers connecting the world through Google Play",
    +-    "summary": "The mobile ecosystem is empowering developers to make good on the dream of connecting the world through technology to improve people's lives.",
    +-    "tags":["io15","googleplay"],
    +-    "keywords":["Google I/O 2015","io"],
    +-    "type":"youtube"
    +-  },
    +-  {
    +-    "url":"https://www.youtube.com/watch?v=B6ydLpkhq04&list=PLOU2XLYxmsIKLNUPiFCWVtcO7mZRZ9MmS",
    +-    "image": "https://i1.ytimg.com/vi/B6ydLpkhq04/maxresdefault.jpg",
    +-    "title": "Store Listing Experiments for Google Play",
    +-    "summary": "Learn how to use Google Play’s new store listing optimization feature to get more installs of your app, and how to test different graphics and text to find out which options perform the best. ",
    +-    "tags":["io15","googleplay","store listing"],
    +-    "tags":["google i/o","google play","store listing"],
    +-    "type":"youtube"
    +-  },
    +-  {
    +-    "url":"https://www.youtube.com/watch?v=jyO3-rF4Mu0&list=PLOU2XLYxmsIKLNUPiFCWVtcO7mZRZ9MmS",
    +-    "image": "https://i1.ytimg.com/vi/jyO3-rF4Mu0/maxresdefault.jpg",
    +-    "title": "Growing games with Google",
    +-    "summary": "The games industry has never been more promising and full of opportunities. This talk covers how Google is helping developers across a broad range of existing and emerging platforms.",
    +-    "tags":["io15","android", "googleplay","games"],
    +-    "keywords":["Google I/O","google play","games"],
    +-    "type":"youtube"
    +-  },
    +-  {
    +-    "url":"https://www.youtube.com/watch?v=yJisuP94lHU",
    +-    "image": "images/distribute/hero-playtime-opener.jpg",
    +-    "title": "Playtime 2015: Innovation happens everywhere",
    +-    "type":"Video",
    +-    "tags":["googleplay"],
    +-    "summary": "Watch the opening video from Google Play's annual event series, Playtime, which celebrates inspirational developers who are changing the world around them.",
    +-  },
    +-{
    +-    "url":"https://www.youtube.com/watch?v=JrR6o5tYMWQ",
    +-    "image": "images/distribute/hero-acquisition-devbyte.jpg",
    +-    "title": "User acquisition and tracking on Google Play",
    +-    "type" : "Video",
    +-    "tags" : "users,googleplay,googleio",
    +-    "summary": "Learn how to get new users, using Universal app campaigns directly within the Google Play Developer Console to increase your installs from ads, and find out how your acquisition channels perform.",
    +-  },
    +-]);
    +-
    +-var CAROUSEL_OVERRIDE = {
    +-  "distribute/googleplay/guide.html": {
    +-    "image": "images/distribute/hero-secrets-to-app-success.jpg",
    +-    "title": "The Secrets to App Success on Google Play",
    +-    "summary": "Get the updated guide full of useful features, tips, and best practices that will help you grow a successful app or game business on Google Play.",
    +-  },
    +-  "about/versions/lollipop.html": {
    +-    "image": "images/home/hero-lollipop_2x.png",
    +-    "heroColor": "#263238",
    +-    "heroInvert": true,
    +-    "title": "Android 5.0 Lollipop",
    +-    "summary": "The Android 5.0 update adds a variety of new features for your apps, such as notifications on the lock screen, an all-new camera API, OpenGL ES 3.1, the new naterial design interface, and much more.",
    +-  },
    +-  "http://www.youtube.com/watch?v=Pms0pcyPbAM": {
    +-    "url":"https://www.youtube.com/watch?v=Pms0pcyPbAM&list=PLWz5rJ2EKKc9ofd2f-_-xmUi07wIGZa1c]",
    +-    "image": "images/distribute/hero-carousel-giftedmom.jpg",
    +-    "title": "Gifted Mom reaches more mothers across Africa with Android",
    +-    "type":"youtube",
    +-    "summary": "Gifted Mom is an app developed in Cameroon which provides users with critical information about pregnancy, breastfeeding and child vaccinations. Hear the creators explain how they built their business on Google Play.",
    +-  },
    +-  "http://www.youtube.com/watch?v=9m6MoBM-sFI": {
    +-    "url":"https://www.youtube.com/watch?v=9m6MoBM-sFI&list=PLWz5rJ2EKKc9ofd2f-_-xmUi07wIGZa1c&index=3",
    +-    "image": "images/distribute/hero-carousel-sgn.jpg",
    +-    "title": "SGN increases installs with Store Listing Experiments",
    +-    "type" : "youtube",
    +-    "summary": "Watch mobile game developer SGN talk about how using Store Listing Experiments to test multiple variants across their portfolio of games helped improve their ROI, conversion rates and gamer retention.",
    +-  },
    +-  "http://www.youtube.com/watch?v=e7t3svG9PTk": {
    +-    "url":"https://www.youtube.com/watch?v=e7t3svG9PTk&index=2&list=PLWz5rJ2EKKc9ofd2f-_-xmUi07wIGZa1c",
    +-    "image": "images/distribute/hero-carousel-djit.jpg",
    +-    "title": "DJiT builds higher quality experiences on Android",
    +-    "type" : "youtube",
    +-    "summary": "Learn how Music app developer DJiT create higher quality apps with improved latency on Android Marshmallow, as well as other Android and Google Play features.",
    +-  },
    +-  "http://www.youtube.com/watch?v=J3IvOfvH1ys": {
    +-    "url":"https://www.youtube.com/watch?v=J3IvOfvH1ys&list=PLWz5rJ2EKKc9ofd2f-_-xmUi07wIGZa1c&index=1",
    +-    "image": "images/distribute/hero-carousel-wego.jpg",
    +-    "title": "Wego increases user retention with material design",
    +-    "type" : "youtube",
    +-    "summary": "Hear how online travel marketplace Wego, increased monthly user retention by 300% and reduced uninstall rates by up to 25% with material design.",
    +-  },
    +-  "https://www.youtube.com/watch?v=QDM52bblwlg": {
    +-    "url":"distribute/googleplay/families/about.html",
    +-    "image": "images/distribute/hero-family-discovery.jpg",
    +-    "title": "Designed for families",
    +-    "summary": "Introducing the new family discovery experience in Google Play. Your apps can benefit from enhanced discoverability and maintain their existing categories, rankings, and reviews elsewhere in the store. Opt-in your apps today.",
    +-    "type":"distribute",
    +-  },
    +-  "https://www.youtube.com/watch?v=wcjqBSei3a0&list=PLOU2XLYxmsIKLNUPiFCWVtcO7mZRZ9MmS": {
    +-    "url":"https://www.youtube.com/watch?v=wcjqBSei3a0&list=PLOU2XLYxmsIKLNUPiFCWVtcO7mZRZ9MmS",
    +-    "image": "images/distribute/hero-IO15-google-play.jpg",
    +-    "title": "Connecting the world through Google Play",
    +-    "tags":["io15"],
    +-    "summary": "In this this Google I/O talk, hear how the mobile ecosystem is empowering developers to connect the world through technology and improve people's lives.",
    +-  },
    +-  "https://www.youtube.com/watch?v=B6ydLpkhq04&list=PLOU2XLYxmsIKLNUPiFCWVtcO7mZRZ9MmS": {
    +-    "image": "images/distribute/hero-store-listing-experience.jpg",
    +-    "title": "Using Google Play store listing experiments",
    +-    "tags":["io15"],
    +-    "summary": "Learn how to use Google Play store listing experiments to get more installs in this Google I/O talk. Test different graphics and text to find out which options perform the best. ",
    +-  },
    +-  "https://www.youtube.com/watch?v=jyO3-rF4Mu0&list=PLOU2XLYxmsIKLNUPiFCWVtcO7mZRZ9MmS": {
    +-    "image": "images/distribute/hero-IO15-growing-games.jpg",
    +-    "title": "Growing games with Google",
    +-    "tags":["io15"],
    +-    "summary": "The games industry has never been more promising and full of opportunities. This talk from Google I/O 2015 covers how Google is helping developers across a broad range of existing and emerging platforms.",
    +-  }
    +-};
    +diff --git a/docs/html/jd_extras_en.js b/docs/html/jd_extras_en.js
    +index dfc30c3..1a97db4 100644
    +--- a/docs/html/jd_extras_en.js
    ++++ b/docs/html/jd_extras_en.js
    +@@ -156,6 +156,16 @@ METADATA['en'].extras = METADATA['en'].extras.concat([
    +     "lang":"en"
    +   },
    +   {
    ++    "title":"GPU Debugger",
    ++    "summary":"Use the GPU Debugger to analyze and debug your OpenGL ES apps. Inspect the GPU state and understand what caused a specific rendering outcome.",
    ++    "url":"studio/debug/am-gpu-debugger.html",
    ++    "image":"images/tools/thumbnails/am-gpu-debugger_2-2_2x.png",
    ++    "type":"tools",
    ++    "keywords": ["android","performance","profiling","tools","monitor","debug"],
    ++    "tags": ["android","performance","profiling","tools","monitor","debug"],
    ++    "lang":"en"
    ++  },
    ++  {
    +     "title":"HPROF Viewer and Analyzer",
    +     "summary":"Use the Memory Monitor to dump the Java heap to an HPROF file. The HPROF Viewer displays classes, instances of each class, and a reference tree to help you track memory usage and find memory leaks.",
    +     "url":"studio/profile/am-hprof.html",
    +@@ -1022,6 +1032,17 @@ METADATA['en'].extras = METADATA['en'].extras.concat([
    +     "type":"distribute"
    +   },
    +   {
    ++    "title": "Play Games Quality",
    ++    "category": "google",
    ++    "summary": "Meet the basic expectations of game players through compelling features and an intuitive, well-designed UI.",
    ++    "url": "https://developers.google.com/games/services/checklist",
    ++    "group": "",
    ++    "keywords": ["games", "play games", "quality"],
    ++    "tags": [],
    ++    "image": "images/cards/distribute/engage/card-game-services.png",
    ++    "type": "distribute"
    ++  },
    ++  {
    +     "title":"Get Started with Analytics",
    +     "category":"google",
    +     "summary":"Get advanced insight into how players discover and play your games.",
    +@@ -2960,7 +2981,6 @@ METADATA['en'].extras = METADATA['en'].extras.concat([
    +     "type": "distribute",
    +     "category": "google"
    +   },
    +-
    +   {
    +     "lang": "en",
    +     "group": "",
    +@@ -2969,7 +2989,7 @@ METADATA['en'].extras = METADATA['en'].extras.concat([
    +     "timestamp": 1383243492000,
    +     "image": "images/cards/google-search_2x.png",
    +     "title": "Set Up App Indexing",
    +-    "summary": "Surface your app content in Google seaerch. Deep link direct to your apps.",
    ++    "summary": "Surface your app content in Google search. Deep link direct to your apps.",
    +     "keywords": ["search", "appindexing", "engagement", "getusers"],
    +     "type": "distribute",
    +     "category": "google"
    +@@ -4117,8 +4137,8 @@ METADATA['en'].collections = {
    +   "develop/landing/tools": {
    +     "title": "",
    +     "resources": [
    +-      "https://www.youtube.com/watch?v=ZOz_yr8Yxq8&list=PLWz5rJ2EKKc_w6fodMGrA1_tsI3pqPbqa",
    +-      "https://www.youtube.com/watch?v=eOV2owswDkE&list=PLWz5rJ2EKKc_w6fodMGrA1_tsI3pqPbqa",
    ++      "https://www.youtube.com/watch?v=NbHsi3-uR8E&list=PLWz5rJ2EKKc_w6fodMGrA1_tsI3pqPbqa",
    ++      "https://www.youtube.com/watch?v=-SY5nkNVUn0&list=PLWz5rJ2EKKc_w6fodMGrA1_tsI3pqPbqa",
    +       "https://www.youtube.com/watch?v=StqAZ1OQbqA&list=PLWz5rJ2EKKc_w6fodMGrA1_tsI3pqPbqa",
    +       "https://www.youtube.com/watch?v=-SY5nkNVUn0&list=PLWz5rJ2EKKc_w6fodMGrA1_tsI3pqPbqa",
    +       "https://www.youtube.com/watch?v=4rI4tTd7-J8&list=PLWz5rJ2EKKc_w6fodMGrA1_tsI3pqPbqa",
    +@@ -4366,6 +4386,7 @@ METADATA['en'].collections = {
    +       "distribute/essentials/quality/wear.html",
    +       "distribute/essentials/quality/tv.html",
    +       "distribute/essentials/quality/auto.html",
    ++      "https://developers.google.com/games/services/checklist",
    +       "distribute/essentials/quality/billions.html",
    +       "https://developers.google.com/edu/guidelines"
    +     ]
    +@@ -5354,6 +5375,47 @@ METADATA['en'].collections = {
    +       "https://storage.googleapis.com/androiddevelopers/shareables/stories/Senri_LeosFortune_gpgs.pdf"
    +     ]
    +   },
    ++  "distribute/stories/games/docs": {
    ++    "title": "",
    ++    "resources": [
    ++      "distribute/stories/games/animoca-star-girl.html",
    ++      "distribute/stories/games/happy-labs-experiment.html",
    ++      "distribute/stories/games/playlab-puzzles.html",
    ++      "distribute/stories/games/upbeat-games.html",
    ++      "distribute/stories/games/tapps.html",
    ++      "distribute/stories/games/noodlecake-super-stickman.html",
    ++      "distribute/stories/games/glu-tap-baseball.html",
    ++      "distribute/stories/games/doctor-who-legacy.html",
    ++      "distribute/stories/games/glu-dh.html",
    ++      "distribute/stories/games/dots.html",
    ++      "distribute/stories/games/kongregate-adv-cap.html",
    ++      "distribute/stories/games/kongregate-global-assault.html",
    ++      "distribute/stories/games/leos-fortune.html",
    ++      "distribute/stories/games/tiny-co.html",
    ++      "distribute/stories/games/g4a-indian-rummy.html",
    ++      "distribute/stories/games/rvappstudios-zombie.html",
    ++      "distribute/stories/games/glu-eternity-warriors.html",
    ++      "distribute/stories/games/hotheadgames-firefight.html",
    ++      "distribute/stories/games/concrete-bowling.html",
    ++      "distribute/stories/games/gameloft-asphalt8.html"
    ++    ]
    ++  },
    ++  "distribute/stories/apps/docs": {
    ++    "title": "",
    ++    "resources": [
    ++      "distribute/stories/apps/condenast-shopping.html",
    ++      "distribute/stories/apps/economist-espresso.html",
    ++      "distribute/stories/apps/expressen-sports.html",
    ++      "distribute/stories/apps/drupe-communications.html",
    ++      "distribute/stories/apps/noom-health.html",
    ++      "distribute/stories/apps/aftenposten.html",
    ++      "distribute/stories/apps/el-mundo.html",
    ++      "distribute/stories/apps/segundamano.html",
    ++      "distribute/stories/apps/remember-the-milk.html",
    ++      "distribute/stories/apps/intuit-mint.html",
    ++      "distribute/stories/apps/sayhi.html",
    ++    ]
    ++  },
    +   "training/testing/overview": {
    +     "title": "",
    +     "resources": [
    +@@ -5453,6 +5515,12 @@ METADATA['en'].collections = {
    +        "studio/profile/am-sysinfo.html"
    +     ]
    +   },
    ++"tools/help/gpu": {
    ++    "title": "",
    ++    "resources": [
    ++       "studio/debug/am-gpu-debugger.html"
    ++    ]
    ++  },
    +   "tools/help/shot": {
    +     "title": "",
    +     "resources": [
    +@@ -5552,7 +5620,7 @@ METADATA['en'].collections = {
    +     "title": "",
    +     "resources": [
    +     "https://medium.com/google-developers/how-often-should-you-update-android-studio-db25785c488e#.8blbql35x",
    +-    "http://android-developers.blogspot.com/2016/04/android-studio-2-0.html",
    ++    "https://android-developers.blogspot.com/2016/09/android-studio-2-2.html",
    +     "https://medium.com/google-developers/writing-more-code-by-writing-less-code-with-android-studio-live-templates-244f648d17c7#.hczcm02du",
    +     ]
    +   },
    +diff --git a/docs/html/jd_extras_zh-cn.js b/docs/html/jd_extras_zh-cn.js
    +index cb1ccb7..866a87e 100644
    +--- a/docs/html/jd_extras_zh-cn.js
    ++++ b/docs/html/jd_extras_zh-cn.js
    +@@ -244,40 +244,40 @@ METADATA['zh-cn'].collections = {
    +   "overview/zhcn/1": {
    +     "title": "",
    +     "resources": [
    +-      "intl/zh-cn/distribute/essentials/quality/core.html",
    +-      "intl/zh-cn/distribute/essentials/quality/tablets.html",
    +-      "intl/zh-cn/distribute/tools/launch-checklist.html",
    +-      "intl/zh-cn/tools/publishing/publishing_overview.html",
    +-      "intl/zh-cn/distribute/tools/localization-checklist.html"
    ++      "distribute/essentials/quality/core.html",
    ++      "distribute/essentials/quality/tablets.html",
    ++      "distribute/tools/launch-checklist.html",
    ++      "tools/publishing/publishing_overview.html",
    ++      "distribute/tools/localization-checklist.html"
    +     ]
    +   },
    +   "overview/zhcn/2": {
    +     "title": "",
    +     "resources": [
    +-      "intl/zh-cn/google/play/billing/index.html",
    +-      "intl/zh-cn/google/play/billing/api.html",
    +-      "intl/zh-cn/google/play/billing/billing_admin.html",
    +-      "intl/zh-cn/google/play/billing/billing_testing.html",
    +-      "intl/zh-cn/google/play/billing/billing_best_practices.html"
    ++      "google/play/billing/index.html",
    ++      "google/play/billing/api.html",
    ++      "google/play/billing/billing_admin.html",
    ++      "google/play/billing/billing_testing.html",
    ++      "google/play/billing/billing_best_practices.html"
    +     ]
    +   },
    +   "overview/zhcn/3": {
    +     "title": "",
    +     "resources": [
    +       "https://play.google.com/intl/en_us/badges/",
    +-      "intl/zh-cn/distribute/tools/promote/device-art.html",
    +-      "intl/zh-cn/distribute/tools/promote/linking.html",
    +-      "intl/zh-cn/distribute/tools/promote/brand.html",
    +-      "intl/zh-cn/tools/help/proguard.html"
    ++      "distribute/tools/promote/device-art.html",
    ++      "distribute/tools/promote/linking.html",
    ++      "distribute/tools/promote/brand.html",
    ++      "tools/help/proguard.html"
    +     ]
    +   },
    +   "overview/zhcn/4": {
    +     "title": "",
    +     "resources": [
    +-      "intl/zh-cn/design/style/writing.html",
    +-      "intl/zh-cn/training/basics/fragments/fragment-ui.html",
    +-      "intl/zh-cn/training/multiscreen/index.html",
    +-      "intl/zh-cn/training/monitoring-device-state/index.html"
    ++      "design/style/writing.html",
    ++      "training/basics/fragments/fragment-ui.html",
    ++      "training/multiscreen/index.html",
    ++      "training/monitoring-device-state/index.html"
    +     ]
    +   },
    +   "overview/carousel/zhcn": {
    +diff --git a/docs/html/samples/new/index.jd b/docs/html/samples/new/index.jd
    +index a7ffa8c..4d6262e 100644
    +--- a/docs/html/samples/new/index.jd
    ++++ b/docs/html/samples/new/index.jd
    +@@ -5,7 +5,7 @@ page.image=images/cards/samples-new_2x.png
    + 
    + <p>The following code samples were recently published. You can
    + download them in the Android SDK Manager under the <b>Samples for SDK</b>
    +-component for Android 6.0 (API 23).</p>
    ++component for Android 7.1 (API 25).</p>
    + 
    + <p class="note">
    +   <strong>Note:</strong> The downloadable projects are designed
    +@@ -14,115 +14,67 @@ component for Android 6.0 (API 23).</p>
    + 
    + <!-- NOTE TO EDITORS: add most recent samples first -->
    + 
    +-<h3 id="ActiveNotification">
    +-  <a href="{@docRoot}samples/ActiveNotifications/index.html">Active
    +-  Notification</a>
    +-</h3>
    + 
    +-<p>
    +-  This sample demonstrates how to use the {@link
    +-  android.app.NotificationManager} to tell you how many notifications your app
    +-  is currently showing.
    +-</p>
    +-
    +-<h3 id="AutomaticBackup">
    +-  <a href="{@docRoot}samples/AutoBackupForApps/index.html">Auto Backup for
    +-  Apps</a>
    +-</h3>
    +-
    +-<p>
    +-  Android 6.0 (API level 23) introduces automatic backup for app settings. This
    +-  sample demonstrates how to add filtering rules to an app to manage settings
    +-  backup.
    +-</p>
    ++<h3 id="app-shortcuts">App shortcuts sample</h3>
    + 
    +-<h3 id="Camera2Raw">
    +-  <a href="{@docRoot}samples/Camera2Raw/index.html">Camera 2 Raw</a>
    +-</h3>
    ++<!-- TBA
    ++<img src="sample-img.png" style="float: left; padding-right: 0.5em"
    ++ width="xxx"/>
    ++-->
    + 
    + <p>
    +-  This sample demonstrates how to use the
    +-  <a href="{@docRoot}reference/android/hardware/camera2/package-summary.html">
    +-  <code>Camera2</code></a> API to capture RAW camera buffers and save them as
    +-  DNG files.
    +-</p>
    +-
    +-<h3 id="ConfirmCredential">
    +-  <a href="{@docRoot}samples/ConfirmCredential/index.html">Confirm
    +-  Credential</a>
    +-</h3>
    +-
    +-<p>
    +- This sample demonstrates how to use device credentials as an authentication method in your app.
    ++  This sample demonstrates how to use the <a href=
    ++  "/preview/app-shortcuts.html">app shortcuts API</a> introduced in Android 7.1
    ++  (API level 25). This API allows an application to define a set of intents
    ++  which are displayed when a user long-presses on the app's launcher icon.
    ++  Examples are given for registering links both statically in XML, as well as
    ++  dynamically at runtime.
    + </p>
    + 
    +-<h3 id="DeviceOwner">
    +-  <a href="{@docRoot}samples/DeviceOwner/index.html">Device Owner</a>
    +-</h3>
    +-
    + <p>
    +-  This sample demonstrates how to use the device owner features to manage and
    +-  configure a device.
    ++  <a href="/samples/AppShortcuts/index.html">App shortcuts sample</a>
    + </p>
    + 
    +-<h3 id="DirectShare">
    +-  <a href="{@docRoot}samples/DirectShare/index.html">Direct Share</a>
    +-</h3>
    +-
    +-<p>
    +-  This sample demonstrates how to provide the
    +-  <a href="{@docRoot}about/versions/marshmallow/android-6.0.html#direct-share">Direct
    +-  Share</a> feature. The app shows some options directly in the list of share
    +-  intent candidates.
    +-</p>
    ++<h3 id="img-kbd-app">Image keyboard app sample</h3>
    + 
    +-<h3 id="FingerprintDialog">
    +-  <a href="{@docRoot}samples/FingerprintDialog/index.html">Fingerprint
    +-  Dialog</a>
    +-</h3>
    ++<!-- TBA
    ++<img src="sample-img.png" style="float: left; padding-right: 0.5em"
    ++ width="xxx"/>
    ++-->
    + 
    + <p>
    +-  This sample demonstrates how to recognize registered fingerprints to
    +-  authenticate your app's user.
    ++  This sample demonstrates how to implement the <a href=
    ++  "/reference/android/view/inputmethod/InputConnection.html#commitContent(android.view.inputmethod.InputContentInfo,%20int,%20android.os.Bundle)">
    ++  Commit Content API</a>, using the <a href=
    ++  "/topic/libraries/support-library/index.html">Android Support Library</a>.
    ++  This API provides a universal way for IMEs to send images and other rich
    ++  content directly to a text editor in an app, allowing users to compose
    ++  content using custom emojis, stickers, or other rich content provided by
    ++  other applications.
    + </p>
    + 
    +-<h3 id="MidiScope">
    +-  <a href="{@docRoot}samples/MidiScope/index.html">MidiScope</a>
    +-</h3>
    +-
    + <p>
    +-  This sample demonstrates how to use the <a href=
    +-  "{@docRoot}reference/android/media/midi/package-summary.html">MIDI API</a> to
    +-  receive and process MIDI signals coming from an attached input device.
    ++  <a href="/samples/CommitContentSampleApp/index.html">Image keyboard app sample</a>
    + </p>
    + 
    +-<h3 id="MidiSynth">
    +-  <a href="{@docRoot}samples/MidiSynth/index.html">MidiSynth</a>
    +-</h3>
    ++<h3 id="img-kbd-ime">Image keyboard IME sample</h3>
    + 
    +-<p>
    +-  This sample demonstrates how to use the <a href=
    +-  "{@docRoot}reference/android/media/midi/package-summary.html">MIDI API</a> to
    +-  receive and play MIDI messages coming from an attached input device.
    +-</p>
    +-
    +-<h3 id="NfcProvisioning">
    +-  <a href="{@docRoot}samples/NfcProvisioning/index.html">NFC Provisioning</a>
    +-</h3>
    ++<!-- TBA
    ++<img src="sample-img.png" style="float: left; padding-right: 0.5em"
    ++ width="xxx"/>
    ++-->
    + 
    + <p>
    +-  This sample demonstrates how to use NFC to provision other devices with a
    +-  specific device owner.
    ++  This sample demonstrates how to write a <a href=
    ++  "/preview/image-keyboard.html">custom image keyboard</a> using the <a href=
    ++  "/reference/android/view/inputmethod/InputConnection.html#commitContent(android.view.inputmethod.InputContentInfo,%20int,%20android.os.Bundle)">
    ++  Commit Content API</a> and the <a href=
    ++  "/topic/libraries/support-library/index.html">Android Support Library</a>.
    ++  This keyboard will be displayed inside compatible apps (also using the Commit
    ++  Content API), allowing users to insert emojis, stickers, or other rich
    ++  content into text editors.
    + </p>
    + 
    +-<h3 id="RuntimePermissions">
    +-  <a href=
    +-  "{@docRoot}samples/RuntimePermissions/index.html">RuntimePermissions</a>
    +-</h3>
    +-
    + <p>
    +-  This sample shows runtime permissions available in Android 6.0 (API level 23)
    +-  and higher. Display the log on screen to follow the execution. If executed on
    +-  an Android 6.0 device, the app displays an additional option to access
    +-  contacts using an 6.0-only optional permission.
    ++  <a href="/samples/CommitContentSampleIME/index.html">Image keyboard IME sample</a>
    + </p>
    +diff --git a/docs/html/sdk/1.0_r1/installing.jd b/docs/html/sdk/1.0_r1/installing.jd
    +index 38c2a1a..eb02742 100644
    +--- a/docs/html/sdk/1.0_r1/installing.jd
    ++++ b/docs/html/sdk/1.0_r1/installing.jd
    +@@ -1,3 +1,4 @@
    ++excludeFromSuggestions=true
    + @jd:body
    + 
    + <script type="text/javascript">
    +diff --git a/docs/html/sdk/1.0_r1/requirements.jd b/docs/html/sdk/1.0_r1/requirements.jd
    +index 96fdcb2..41774f0 100644
    +--- a/docs/html/sdk/1.0_r1/requirements.jd
    ++++ b/docs/html/sdk/1.0_r1/requirements.jd
    +@@ -1,3 +1,4 @@
    ++excludeFromSuggestions=true
    + @jd:body
    + 
    + <script type="text/javascript">
    +diff --git a/docs/html/sdk/1.0_r2/installing.jd b/docs/html/sdk/1.0_r2/installing.jd
    +index 38c2a1a..eb02742 100644
    +--- a/docs/html/sdk/1.0_r2/installing.jd
    ++++ b/docs/html/sdk/1.0_r2/installing.jd
    +@@ -1,3 +1,4 @@
    ++excludeFromSuggestions=true
    + @jd:body
    + 
    + <script type="text/javascript">
    +diff --git a/docs/html/sdk/1.0_r2/requirements.jd b/docs/html/sdk/1.0_r2/requirements.jd
    +index 96fdcb2..41774f0 100644
    +--- a/docs/html/sdk/1.0_r2/requirements.jd
    ++++ b/docs/html/sdk/1.0_r2/requirements.jd
    +@@ -1,3 +1,4 @@
    ++excludeFromSuggestions=true
    + @jd:body
    + 
    + <script type="text/javascript">
    +diff --git a/docs/html/sdk/1.1_r1/installing.jd b/docs/html/sdk/1.1_r1/installing.jd
    +index 38c2a1a..eb02742 100644
    +--- a/docs/html/sdk/1.1_r1/installing.jd
    ++++ b/docs/html/sdk/1.1_r1/installing.jd
    +@@ -1,3 +1,4 @@
    ++excludeFromSuggestions=true
    + @jd:body
    + 
    + <script type="text/javascript">
    +diff --git a/docs/html/sdk/1.1_r1/requirements.jd b/docs/html/sdk/1.1_r1/requirements.jd
    +index 96fdcb2..41774f0 100644
    +--- a/docs/html/sdk/1.1_r1/requirements.jd
    ++++ b/docs/html/sdk/1.1_r1/requirements.jd
    +@@ -1,3 +1,4 @@
    ++excludeFromSuggestions=true
    + @jd:body
    + 
    + <script type="text/javascript">
    +diff --git a/docs/html/sdk/1.5_r1/installing.jd b/docs/html/sdk/1.5_r1/installing.jd
    +index 38c2a1a..eb02742 100644
    +--- a/docs/html/sdk/1.5_r1/installing.jd
    ++++ b/docs/html/sdk/1.5_r1/installing.jd
    +@@ -1,3 +1,4 @@
    ++excludeFromSuggestions=true
    + @jd:body
    + 
    + <script type="text/javascript">
    +diff --git a/docs/html/sdk/1.5_r1/requirements.jd b/docs/html/sdk/1.5_r1/requirements.jd
    +index 96fdcb2..41774f0 100644
    +--- a/docs/html/sdk/1.5_r1/requirements.jd
    ++++ b/docs/html/sdk/1.5_r1/requirements.jd
    +@@ -1,3 +1,4 @@
    ++excludeFromSuggestions=true
    + @jd:body
    + 
    + <script type="text/javascript">
    +diff --git a/docs/html/sdk/1.5_r2/installing.jd b/docs/html/sdk/1.5_r2/installing.jd
    +index 38c2a1a..eb02742 100644
    +--- a/docs/html/sdk/1.5_r2/installing.jd
    ++++ b/docs/html/sdk/1.5_r2/installing.jd
    +@@ -1,3 +1,4 @@
    ++excludeFromSuggestions=true
    + @jd:body
    + 
    + <script type="text/javascript">
    +diff --git a/docs/html/sdk/1.5_r2/requirements.jd b/docs/html/sdk/1.5_r2/requirements.jd
    +index 96fdcb2..41774f0 100644
    +--- a/docs/html/sdk/1.5_r2/requirements.jd
    ++++ b/docs/html/sdk/1.5_r2/requirements.jd
    +@@ -1,3 +1,4 @@
    ++excludeFromSuggestions=true
    + @jd:body
    + 
    + <script type="text/javascript">
    +diff --git a/docs/html/sdk/1.5_r3/installing.jd b/docs/html/sdk/1.5_r3/installing.jd
    +index 38c2a1a..eb02742 100644
    +--- a/docs/html/sdk/1.5_r3/installing.jd
    ++++ b/docs/html/sdk/1.5_r3/installing.jd
    +@@ -1,3 +1,4 @@
    ++excludeFromSuggestions=true
    + @jd:body
    + 
    + <script type="text/javascript">
    +diff --git a/docs/html/sdk/1.5_r3/requirements.jd b/docs/html/sdk/1.5_r3/requirements.jd
    +index 96fdcb2..41774f0 100644
    +--- a/docs/html/sdk/1.5_r3/requirements.jd
    ++++ b/docs/html/sdk/1.5_r3/requirements.jd
    +@@ -1,3 +1,4 @@
    ++excludeFromSuggestions=true
    + @jd:body
    + 
    + <script type="text/javascript">
    +diff --git a/docs/html/sdk/1.6_r1/installing.jd b/docs/html/sdk/1.6_r1/installing.jd
    +index 38c2a1a..eb02742 100644
    +--- a/docs/html/sdk/1.6_r1/installing.jd
    ++++ b/docs/html/sdk/1.6_r1/installing.jd
    +@@ -1,3 +1,4 @@
    ++excludeFromSuggestions=true
    + @jd:body
    + 
    + <script type="text/javascript">
    +diff --git a/docs/html/sdk/1.6_r1/requirements.jd b/docs/html/sdk/1.6_r1/requirements.jd
    +index 96fdcb2..41774f0 100644
    +--- a/docs/html/sdk/1.6_r1/requirements.jd
    ++++ b/docs/html/sdk/1.6_r1/requirements.jd
    +@@ -1,3 +1,4 @@
    ++excludeFromSuggestions=true
    + @jd:body
    + 
    + <script type="text/javascript">
    +diff --git a/docs/html/sdk/support_api_diff/22.2.0/changes/alldiffs_index_additions.html b/docs/html/sdk/support_api_diff/22.2.0/changes/alldiffs_index_additions.html
    +index 9786c92..fcff8ea 100644
    +--- a/docs/html/sdk/support_api_diff/22.2.0/changes/alldiffs_index_additions.html
    ++++ b/docs/html/sdk/support_api_diff/22.2.0/changes/alldiffs_index_additions.html
    +@@ -332,7 +332,7 @@ Listed as: <span style="color:#069"><strong>Added</strong></span>,  <span style=
    + <!-- Method zBy -->
    + <nobr><A HREF="android.support.v4.view.ViewPropertyAnimatorCompat.html#android.support.v4.view.ViewPropertyAnimatorCompat.zBy_added(float)" class="hiddenlink" target="rightframe"><b>zBy</b>
    + (<code>float</code>)</A></nobr><br>
    +-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    + </script>
    + <script type="text/javascript">
    +   try {
    +diff --git a/docs/html/sdk/support_api_diff/22.2.0/changes/alldiffs_index_all.html b/docs/html/sdk/support_api_diff/22.2.0/changes/alldiffs_index_all.html
    +index 7055d15..4e923e6 100644
    +--- a/docs/html/sdk/support_api_diff/22.2.0/changes/alldiffs_index_all.html
    ++++ b/docs/html/sdk/support_api_diff/22.2.0/changes/alldiffs_index_all.html
    +@@ -425,7 +425,7 @@ Listed as: <span style="color:#069"><strong>Added</strong></span>,  <span style=
    + <!-- Method zBy -->
    + <nobr><A HREF="android.support.v4.view.ViewPropertyAnimatorCompat.html#android.support.v4.view.ViewPropertyAnimatorCompat.zBy_added(float)" class="hiddenlink" target="rightframe"><b>zBy</b>
    + (<code>float</code>)</A></nobr><br>
    +-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    + </script>
    + <script type="text/javascript">
    +   try {
    +diff --git a/docs/html/sdk/support_api_diff/22.2.0/changes/alldiffs_index_changes.html b/docs/html/sdk/support_api_diff/22.2.0/changes/alldiffs_index_changes.html
    +index c40c9f5..4002f63 100644
    +--- a/docs/html/sdk/support_api_diff/22.2.0/changes/alldiffs_index_changes.html
    ++++ b/docs/html/sdk/support_api_diff/22.2.0/changes/alldiffs_index_changes.html
    +@@ -114,7 +114,7 @@ Listed as: <span style="color:#069"><strong>Added</strong></span>,  <span style=
    + <A HREF="android.support.v4.view.ViewParentCompat.html" class="hiddenlink" target="rightframe">ViewParentCompat</A><br>
    + <!-- Class ViewPropertyAnimatorCompat -->
    + <A HREF="android.support.v4.view.ViewPropertyAnimatorCompat.html" class="hiddenlink" target="rightframe">ViewPropertyAnimatorCompat</A><br>
    +-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    + </script>
    + <script type="text/javascript">
    +   try {
    +diff --git a/docs/html/sdk/support_api_diff/22.2.0/changes/alldiffs_index_removals.html b/docs/html/sdk/support_api_diff/22.2.0/changes/alldiffs_index_removals.html
    +index 68d2c20..c6ec566 100644
    +--- a/docs/html/sdk/support_api_diff/22.2.0/changes/alldiffs_index_removals.html
    ++++ b/docs/html/sdk/support_api_diff/22.2.0/changes/alldiffs_index_removals.html
    +@@ -47,7 +47,7 @@ body{overflow:auto;}
    + <div id="indexTableCaption" style="background-color:#eee;padding:0 4px 0 4px;font-size:11px;margin-bottom:1em;">
    + Listed as: <span style="color:#069"><strong>Added</strong></span>,  <span style="color:#069"><strike>Removed</strike></span>,  <span style="color:#069">Changed</span></font>
    + </div>
    +-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    + </script>
    + <script type="text/javascript">
    +   try {
    +diff --git a/docs/html/sdk/support_api_diff/22.2.0/changes/android.support.v4.media.session.PlaybackStateCompat.Builder.html b/docs/html/sdk/support_api_diff/22.2.0/changes/android.support.v4.media.session.PlaybackStateCompat.Builder.html
    +index ae6415e..42084ee 100644
    +--- a/docs/html/sdk/support_api_diff/22.2.0/changes/android.support.v4.media.session.PlaybackStateCompat.Builder.html
    ++++ b/docs/html/sdk/support_api_diff/22.2.0/changes/android.support.v4.media.session.PlaybackStateCompat.Builder.html
    +@@ -129,7 +129,7 @@ Class android.support.v4.media.session.<A HREF="../../../../reference/android/su
    +     </div> <!-- end footer -->
    +     </div><!-- end doc-content -->
    +     </div> <!-- end body-content --> 
    +-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    + </script>
    + <script type="text/javascript">
    +   try {
    +diff --git a/docs/html/sdk/support_api_diff/22.2.0/changes/android.support.v4.media.session.PlaybackStateCompat.CustomAction.html b/docs/html/sdk/support_api_diff/22.2.0/changes/android.support.v4.media.session.PlaybackStateCompat.CustomAction.html
    +index 4e476b3..deab0af 100644
    +--- a/docs/html/sdk/support_api_diff/22.2.0/changes/android.support.v4.media.session.PlaybackStateCompat.CustomAction.html
    ++++ b/docs/html/sdk/support_api_diff/22.2.0/changes/android.support.v4.media.session.PlaybackStateCompat.CustomAction.html
    +@@ -115,7 +115,7 @@ Class android.support.v4.media.session.<A HREF="../../../../reference/android/su
    +     </div> <!-- end footer -->
    +     </div><!-- end doc-content -->
    +     </div> <!-- end body-content --> 
    +-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    + </script>
    + <script type="text/javascript">
    +   try {
    +diff --git a/docs/html/sdk/support_api_diff/22.2.0/changes/android.support.v4.media.session.PlaybackStateCompat.html b/docs/html/sdk/support_api_diff/22.2.0/changes/android.support.v4.media.session.PlaybackStateCompat.html
    +index bd3e5dd..16b5462 100644
    +--- a/docs/html/sdk/support_api_diff/22.2.0/changes/android.support.v4.media.session.PlaybackStateCompat.html
    ++++ b/docs/html/sdk/support_api_diff/22.2.0/changes/android.support.v4.media.session.PlaybackStateCompat.html
    +@@ -144,7 +144,7 @@ Class android.support.v4.media.session.<A HREF="../../../../reference/android/su
    +     </div> <!-- end footer -->
    +     </div><!-- end doc-content -->
    +     </div> <!-- end body-content --> 
    +-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    + </script>
    + <script type="text/javascript">
    +   try {
    +diff --git a/docs/html/sdk/support_api_diff/22.2.0/changes/android.support.v4.view.ViewCompat.html b/docs/html/sdk/support_api_diff/22.2.0/changes/android.support.v4.view.ViewCompat.html
    +index 1574050..d48ce71 100644
    +--- a/docs/html/sdk/support_api_diff/22.2.0/changes/android.support.v4.view.ViewCompat.html
    ++++ b/docs/html/sdk/support_api_diff/22.2.0/changes/android.support.v4.view.ViewCompat.html
    +@@ -122,7 +122,7 @@ Class android.support.v4.view.<A HREF="../../../../reference/android/support/v4/
    +     </div> <!-- end footer -->
    +     </div><!-- end doc-content -->
    +     </div> <!-- end body-content --> 
    +-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    + </script>
    + <script type="text/javascript">
    +   try {
    +diff --git a/docs/html/sdk/support_api_diff/22.2.0/changes/android.support.v4.view.ViewPager.html b/docs/html/sdk/support_api_diff/22.2.0/changes/android.support.v4.view.ViewPager.html
    +index f03c403..bed9612 100644
    +--- a/docs/html/sdk/support_api_diff/22.2.0/changes/android.support.v4.view.ViewPager.html
    ++++ b/docs/html/sdk/support_api_diff/22.2.0/changes/android.support.v4.view.ViewPager.html
    +@@ -140,7 +140,7 @@ Class android.support.v4.view.<A HREF="../../../../reference/android/support/v4/
    +     </div> <!-- end footer -->
    +     </div><!-- end doc-content -->
    +     </div> <!-- end body-content --> 
    +-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    + </script>
    + <script type="text/javascript">
    +   try {
    +diff --git a/docs/html/sdk/support_api_diff/22.2.0/changes/android.support.v4.view.ViewParentCompat.html b/docs/html/sdk/support_api_diff/22.2.0/changes/android.support.v4.view.ViewParentCompat.html
    +index 6cdd299..08d2ab2 100644
    +--- a/docs/html/sdk/support_api_diff/22.2.0/changes/android.support.v4.view.ViewParentCompat.html
    ++++ b/docs/html/sdk/support_api_diff/22.2.0/changes/android.support.v4.view.ViewParentCompat.html
    +@@ -108,7 +108,7 @@ Class android.support.v4.view.<A HREF="../../../../reference/android/support/v4/
    +     </div> <!-- end footer -->
    +     </div><!-- end doc-content -->
    +     </div> <!-- end body-content --> 
    +-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    + </script>
    + <script type="text/javascript">
    +   try {
    +diff --git a/docs/html/sdk/support_api_diff/22.2.0/changes/android.support.v4.view.ViewPropertyAnimatorCompat.html b/docs/html/sdk/support_api_diff/22.2.0/changes/android.support.v4.view.ViewPropertyAnimatorCompat.html
    +index 5706997..1bfa2b3 100644
    +--- a/docs/html/sdk/support_api_diff/22.2.0/changes/android.support.v4.view.ViewPropertyAnimatorCompat.html
    ++++ b/docs/html/sdk/support_api_diff/22.2.0/changes/android.support.v4.view.ViewPropertyAnimatorCompat.html
    +@@ -129,7 +129,7 @@ Class android.support.v4.view.<A HREF="../../../../reference/android/support/v4/
    +     </div> <!-- end footer -->
    +     </div><!-- end doc-content -->
    +     </div> <!-- end body-content --> 
    +-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    + </script>
    + <script type="text/javascript">
    +   try {
    +diff --git a/docs/html/sdk/support_api_diff/22.2.0/changes/android.support.v4.view.accessibility.AccessibilityEventCompat.html b/docs/html/sdk/support_api_diff/22.2.0/changes/android.support.v4.view.accessibility.AccessibilityEventCompat.html
    +index e746f08..09b19c2 100644
    +--- a/docs/html/sdk/support_api_diff/22.2.0/changes/android.support.v4.view.accessibility.AccessibilityEventCompat.html
    ++++ b/docs/html/sdk/support_api_diff/22.2.0/changes/android.support.v4.view.accessibility.AccessibilityEventCompat.html
    +@@ -151,7 +151,7 @@ Class android.support.v4.view.accessibility.<A HREF="../../../../reference/andro
    +     </div> <!-- end footer -->
    +     </div><!-- end doc-content -->
    +     </div> <!-- end body-content --> 
    +-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    + </script>
    + <script type="text/javascript">
    +   try {
    +diff --git a/docs/html/sdk/support_api_diff/22.2.0/changes/android.support.v7.app.AppCompatActivity.html b/docs/html/sdk/support_api_diff/22.2.0/changes/android.support.v7.app.AppCompatActivity.html
    +index ccce9c5..7b2f8bb 100644
    +--- a/docs/html/sdk/support_api_diff/22.2.0/changes/android.support.v7.app.AppCompatActivity.html
    ++++ b/docs/html/sdk/support_api_diff/22.2.0/changes/android.support.v7.app.AppCompatActivity.html
    +@@ -108,7 +108,7 @@ Class android.support.v7.app.<A HREF="../../../../reference/android/support/v7/a
    +     </div> <!-- end footer -->
    +     </div><!-- end doc-content -->
    +     </div> <!-- end body-content --> 
    +-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    + </script>
    + <script type="text/javascript">
    +   try {
    +diff --git a/docs/html/sdk/support_api_diff/22.2.0/changes/android.support.v7.app.AppCompatCallback.html b/docs/html/sdk/support_api_diff/22.2.0/changes/android.support.v7.app.AppCompatCallback.html
    +index f53a519..fd75b74 100644
    +--- a/docs/html/sdk/support_api_diff/22.2.0/changes/android.support.v7.app.AppCompatCallback.html
    ++++ b/docs/html/sdk/support_api_diff/22.2.0/changes/android.support.v7.app.AppCompatCallback.html
    +@@ -108,7 +108,7 @@ Interface android.support.v7.app.<A HREF="../../../../reference/android/support/
    +     </div> <!-- end footer -->
    +     </div><!-- end doc-content -->
    +     </div> <!-- end body-content --> 
    +-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    + </script>
    + <script type="text/javascript">
    +   try {
    +diff --git a/docs/html/sdk/support_api_diff/22.2.0/changes/android.support.v7.app.AppCompatDelegate.html b/docs/html/sdk/support_api_diff/22.2.0/changes/android.support.v7.app.AppCompatDelegate.html
    +index 88490d4..5df87b9 100644
    +--- a/docs/html/sdk/support_api_diff/22.2.0/changes/android.support.v7.app.AppCompatDelegate.html
    ++++ b/docs/html/sdk/support_api_diff/22.2.0/changes/android.support.v7.app.AppCompatDelegate.html
    +@@ -115,7 +115,7 @@ Class android.support.v7.app.<A HREF="../../../../reference/android/support/v7/a
    +     </div> <!-- end footer -->
    +     </div><!-- end doc-content -->
    +     </div> <!-- end body-content --> 
    +-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    + </script>
    + <script type="text/javascript">
    +   try {
    +diff --git a/docs/html/sdk/support_api_diff/22.2.0/changes/android.support.v7.app.AppCompatDialog.html b/docs/html/sdk/support_api_diff/22.2.0/changes/android.support.v7.app.AppCompatDialog.html
    +index 42d29a8..6d992ad 100644
    +--- a/docs/html/sdk/support_api_diff/22.2.0/changes/android.support.v7.app.AppCompatDialog.html
    ++++ b/docs/html/sdk/support_api_diff/22.2.0/changes/android.support.v7.app.AppCompatDialog.html
    +@@ -108,7 +108,7 @@ Class android.support.v7.app.<A HREF="../../../../reference/android/support/v7/a
    +     </div> <!-- end footer -->
    +     </div><!-- end doc-content -->
    +     </div> <!-- end body-content --> 
    +-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    + </script>
    + <script type="text/javascript">
    +   try {
    +diff --git a/docs/html/sdk/support_api_diff/22.2.0/changes/android.support.v7.util.SortedList.html b/docs/html/sdk/support_api_diff/22.2.0/changes/android.support.v7.util.SortedList.html
    +index 0364519..edfb8bd 100644
    +--- a/docs/html/sdk/support_api_diff/22.2.0/changes/android.support.v7.util.SortedList.html
    ++++ b/docs/html/sdk/support_api_diff/22.2.0/changes/android.support.v7.util.SortedList.html
    +@@ -108,7 +108,7 @@ Class android.support.v7.util.<A HREF="../../../../reference/android/support/v7/
    +     </div> <!-- end footer -->
    +     </div><!-- end doc-content -->
    +     </div> <!-- end body-content --> 
    +-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    + </script>
    + <script type="text/javascript">
    +   try {
    +diff --git a/docs/html/sdk/support_api_diff/22.2.0/changes/changes-summary.html b/docs/html/sdk/support_api_diff/22.2.0/changes/changes-summary.html
    +index c6736cd..72ddc5a 100644
    +--- a/docs/html/sdk/support_api_diff/22.2.0/changes/changes-summary.html
    ++++ b/docs/html/sdk/support_api_diff/22.2.0/changes/changes-summary.html
    +@@ -233,7 +233,7 @@ see the <a href="http://developer.android.com/index.html" target="_top">Android
    +     </div> <!-- end footer -->
    +     </div><!-- end doc-content -->
    +     </div> <!-- end body-content --> 
    +-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    + </script>
    + <script type="text/javascript">
    +   try {
    +diff --git a/docs/html/sdk/support_api_diff/22.2.0/changes/classes_index_additions.html b/docs/html/sdk/support_api_diff/22.2.0/changes/classes_index_additions.html
    +index ccd5b66..4537739 100644
    +--- a/docs/html/sdk/support_api_diff/22.2.0/changes/classes_index_additions.html
    ++++ b/docs/html/sdk/support_api_diff/22.2.0/changes/classes_index_additions.html
    +@@ -47,7 +47,7 @@ body{overflow:auto;}
    + <div id="indexTableCaption" style="background-color:#eee;padding:0 4px 0 4px;font-size:11px;margin-bottom:1em;">
    + Listed as: <span style="color:#069"><strong>Added</strong></span>,  <span style="color:#069"><strike>Removed</strike></span>,  <span style="color:#069">Changed</span></font>
    + </div>
    +-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    + </script>
    + <script type="text/javascript">
    +   try {
    +diff --git a/docs/html/sdk/support_api_diff/22.2.0/changes/classes_index_all.html b/docs/html/sdk/support_api_diff/22.2.0/changes/classes_index_all.html
    +index 728e37d..50a77aa 100644
    +--- a/docs/html/sdk/support_api_diff/22.2.0/changes/classes_index_all.html
    ++++ b/docs/html/sdk/support_api_diff/22.2.0/changes/classes_index_all.html
    +@@ -88,7 +88,7 @@ Listed as: <span style="color:#069"><strong>Added</strong></span>,  <span style=
    + <A HREF="android.support.v4.view.ViewPager.html" class="hiddenlink" target="rightframe">ViewPager</A><br>
    + <A HREF="android.support.v4.view.ViewParentCompat.html" class="hiddenlink" target="rightframe">ViewParentCompat</A><br>
    + <A HREF="android.support.v4.view.ViewPropertyAnimatorCompat.html" class="hiddenlink" target="rightframe">ViewPropertyAnimatorCompat</A><br>
    +-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    + </script>
    + <script type="text/javascript">
    +   try {
    +diff --git a/docs/html/sdk/support_api_diff/22.2.0/changes/classes_index_changes.html b/docs/html/sdk/support_api_diff/22.2.0/changes/classes_index_changes.html
    +index 64e7f44..04fc9bc 100644
    +--- a/docs/html/sdk/support_api_diff/22.2.0/changes/classes_index_changes.html
    ++++ b/docs/html/sdk/support_api_diff/22.2.0/changes/classes_index_changes.html
    +@@ -88,7 +88,7 @@ Listed as: <span style="color:#069"><strong>Added</strong></span>,  <span style=
    + <A HREF="android.support.v4.view.ViewPager.html" class="hiddenlink" target="rightframe">ViewPager</A><br>
    + <A HREF="android.support.v4.view.ViewParentCompat.html" class="hiddenlink" target="rightframe">ViewParentCompat</A><br>
    + <A HREF="android.support.v4.view.ViewPropertyAnimatorCompat.html" class="hiddenlink" target="rightframe">ViewPropertyAnimatorCompat</A><br>
    +-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    + </script>
    + <script type="text/javascript">
    +   try {
    +diff --git a/docs/html/sdk/support_api_diff/22.2.0/changes/classes_index_removals.html b/docs/html/sdk/support_api_diff/22.2.0/changes/classes_index_removals.html
    +index 792fc4e..8881d7d 100644
    +--- a/docs/html/sdk/support_api_diff/22.2.0/changes/classes_index_removals.html
    ++++ b/docs/html/sdk/support_api_diff/22.2.0/changes/classes_index_removals.html
    +@@ -47,7 +47,7 @@ body{overflow:auto;}
    + <div id="indexTableCaption" style="background-color:#eee;padding:0 4px 0 4px;font-size:11px;margin-bottom:1em;">
    + Listed as: <span style="color:#069"><strong>Added</strong></span>,  <span style="color:#069"><strike>Removed</strike></span>,  <span style="color:#069">Changed</span></font>
    + </div>
    +-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    + </script>
    + <script type="text/javascript">
    +   try {
    +diff --git a/docs/html/sdk/support_api_diff/22.2.0/changes/constructors_index_additions.html b/docs/html/sdk/support_api_diff/22.2.0/changes/constructors_index_additions.html
    +index 3237ba3..603d376 100644
    +--- a/docs/html/sdk/support_api_diff/22.2.0/changes/constructors_index_additions.html
    ++++ b/docs/html/sdk/support_api_diff/22.2.0/changes/constructors_index_additions.html
    +@@ -47,7 +47,7 @@ body{overflow:auto;}
    + <div id="indexTableCaption" style="background-color:#eee;padding:0 4px 0 4px;font-size:11px;margin-bottom:1em;">
    + Listed as: <span style="color:#069"><strong>Added</strong></span>,  <span style="color:#069"><strike>Removed</strike></span>,  <span style="color:#069">Changed</span></font>
    + </div>
    +-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    + </script>
    + <script type="text/javascript">
    +   try {
    +diff --git a/docs/html/sdk/support_api_diff/22.2.0/changes/constructors_index_all.html b/docs/html/sdk/support_api_diff/22.2.0/changes/constructors_index_all.html
    +index 637582e..a29ef64 100644
    +--- a/docs/html/sdk/support_api_diff/22.2.0/changes/constructors_index_all.html
    ++++ b/docs/html/sdk/support_api_diff/22.2.0/changes/constructors_index_all.html
    +@@ -47,7 +47,7 @@ body{overflow:auto;}
    + <div id="indexTableCaption" style="background-color:#eee;padding:0 4px 0 4px;font-size:11px;margin-bottom:1em;">
    + Listed as: <span style="color:#069"><strong>Added</strong></span>,  <span style="color:#069"><strike>Removed</strike></span>,  <span style="color:#069">Changed</span></font>
    + </div>
    +-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    + </script>
    + <script type="text/javascript">
    +   try {
    +diff --git a/docs/html/sdk/support_api_diff/22.2.0/changes/constructors_index_changes.html b/docs/html/sdk/support_api_diff/22.2.0/changes/constructors_index_changes.html
    +index 728fa2d..182ad3c 100644
    +--- a/docs/html/sdk/support_api_diff/22.2.0/changes/constructors_index_changes.html
    ++++ b/docs/html/sdk/support_api_diff/22.2.0/changes/constructors_index_changes.html
    +@@ -47,7 +47,7 @@ body{overflow:auto;}
    + <div id="indexTableCaption" style="background-color:#eee;padding:0 4px 0 4px;font-size:11px;margin-bottom:1em;">
    + Listed as: <span style="color:#069"><strong>Added</strong></span>,  <span style="color:#069"><strike>Removed</strike></span>,  <span style="color:#069">Changed</span></font>
    + </div>
    +-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    + </script>
    + <script type="text/javascript">
    +   try {
    +diff --git a/docs/html/sdk/support_api_diff/22.2.0/changes/constructors_index_removals.html b/docs/html/sdk/support_api_diff/22.2.0/changes/constructors_index_removals.html
    +index 1b95544..9f9bb43 100644
    +--- a/docs/html/sdk/support_api_diff/22.2.0/changes/constructors_index_removals.html
    ++++ b/docs/html/sdk/support_api_diff/22.2.0/changes/constructors_index_removals.html
    +@@ -47,7 +47,7 @@ body{overflow:auto;}
    + <div id="indexTableCaption" style="background-color:#eee;padding:0 4px 0 4px;font-size:11px;margin-bottom:1em;">
    + Listed as: <span style="color:#069"><strong>Added</strong></span>,  <span style="color:#069"><strike>Removed</strike></span>,  <span style="color:#069">Changed</span></font>
    + </div>
    +-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    + </script>
    + <script type="text/javascript">
    +   try {
    +diff --git a/docs/html/sdk/support_api_diff/22.2.0/changes/fields_index_additions.html b/docs/html/sdk/support_api_diff/22.2.0/changes/fields_index_additions.html
    +index 48de992..6b0d997 100644
    +--- a/docs/html/sdk/support_api_diff/22.2.0/changes/fields_index_additions.html
    ++++ b/docs/html/sdk/support_api_diff/22.2.0/changes/fields_index_additions.html
    +@@ -69,7 +69,7 @@ Listed as: <span style="color:#069"><strong>Added</strong></span>,  <span style=
    + </nobr><br>
    + <nobr><A HREF="android.support.v4.media.session.PlaybackStateCompat.html#android.support.v4.media.session.PlaybackStateCompat.STATE_SKIPPING_TO_QUEUE_ITEM" class="hiddenlink" target="rightframe">STATE_SKIPPING_TO_QUEUE_ITEM</A>
    + </nobr><br>
    +-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    + </script>
    + <script type="text/javascript">
    +   try {
    +diff --git a/docs/html/sdk/support_api_diff/22.2.0/changes/fields_index_all.html b/docs/html/sdk/support_api_diff/22.2.0/changes/fields_index_all.html
    +index 02f6dc0..726deb6 100644
    +--- a/docs/html/sdk/support_api_diff/22.2.0/changes/fields_index_all.html
    ++++ b/docs/html/sdk/support_api_diff/22.2.0/changes/fields_index_all.html
    +@@ -69,7 +69,7 @@ Listed as: <span style="color:#069"><strong>Added</strong></span>,  <span style=
    + </nobr><br>
    + <nobr><A HREF="android.support.v4.media.session.PlaybackStateCompat.html#android.support.v4.media.session.PlaybackStateCompat.STATE_SKIPPING_TO_QUEUE_ITEM" class="hiddenlink" target="rightframe">STATE_SKIPPING_TO_QUEUE_ITEM</A>
    + </nobr><br>
    +-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    + </script>
    + <script type="text/javascript">
    +   try {
    +diff --git a/docs/html/sdk/support_api_diff/22.2.0/changes/fields_index_changes.html b/docs/html/sdk/support_api_diff/22.2.0/changes/fields_index_changes.html
    +index 4ebfa31..e4376a5 100644
    +--- a/docs/html/sdk/support_api_diff/22.2.0/changes/fields_index_changes.html
    ++++ b/docs/html/sdk/support_api_diff/22.2.0/changes/fields_index_changes.html
    +@@ -47,7 +47,7 @@ body{overflow:auto;}
    + <div id="indexTableCaption" style="background-color:#eee;padding:0 4px 0 4px;font-size:11px;margin-bottom:1em;">
    + Listed as: <span style="color:#069"><strong>Added</strong></span>,  <span style="color:#069"><strike>Removed</strike></span>,  <span style="color:#069">Changed</span></font>
    + </div>
    +-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    + </script>
    + <script type="text/javascript">
    +   try {
    +diff --git a/docs/html/sdk/support_api_diff/22.2.0/changes/fields_index_removals.html b/docs/html/sdk/support_api_diff/22.2.0/changes/fields_index_removals.html
    +index 09b0726..db6d007 100644
    +--- a/docs/html/sdk/support_api_diff/22.2.0/changes/fields_index_removals.html
    ++++ b/docs/html/sdk/support_api_diff/22.2.0/changes/fields_index_removals.html
    +@@ -47,7 +47,7 @@ body{overflow:auto;}
    + <div id="indexTableCaption" style="background-color:#eee;padding:0 4px 0 4px;font-size:11px;margin-bottom:1em;">
    + Listed as: <span style="color:#069"><strong>Added</strong></span>,  <span style="color:#069"><strike>Removed</strike></span>,  <span style="color:#069">Changed</span></font>
    + </div>
    +-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    + </script>
    + <script type="text/javascript">
    +   try {
    +diff --git a/docs/html/sdk/support_api_diff/22.2.0/changes/jdiff_help.html b/docs/html/sdk/support_api_diff/22.2.0/changes/jdiff_help.html
    +index 8bfbd1d..e978be0 100644
    +--- a/docs/html/sdk/support_api_diff/22.2.0/changes/jdiff_help.html
    ++++ b/docs/html/sdk/support_api_diff/22.2.0/changes/jdiff_help.html
    +@@ -120,7 +120,7 @@ These links show and hide the HTML frames. All pages are available with or witho
    + There are some complex changes which can occur between versions, for example, when two or more methods with the same name change simultaneously, or when a method or field is moved into or from a superclass. 
    + In these cases, the change will be seen as a removal and an addition, rather than as a change. Unexpected removals or additions are often part of one of these type of changes. 
    + </BLOCKQUOTE>
    +-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    + </script>
    + <script type="text/javascript">
    +   try {
    +diff --git a/docs/html/sdk/support_api_diff/22.2.0/changes/jdiff_statistics.html b/docs/html/sdk/support_api_diff/22.2.0/changes/jdiff_statistics.html
    +index 229819b..6a96e39 100644
    +--- a/docs/html/sdk/support_api_diff/22.2.0/changes/jdiff_statistics.html
    ++++ b/docs/html/sdk/support_api_diff/22.2.0/changes/jdiff_statistics.html
    +@@ -265,7 +265,7 @@ added, the change will be 100%.</p>
    +     </div> <!-- end footer -->
    +     </div><!-- end doc-content -->
    +     </div> <!-- end body-content --> 
    +-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    + </script>
    + <script type="text/javascript">
    +   try {
    +diff --git a/docs/html/sdk/support_api_diff/22.2.0/changes/jdiff_topleftframe.html b/docs/html/sdk/support_api_diff/22.2.0/changes/jdiff_topleftframe.html
    +index 36f9836..6a2e76e 100644
    +--- a/docs/html/sdk/support_api_diff/22.2.0/changes/jdiff_topleftframe.html
    ++++ b/docs/html/sdk/support_api_diff/22.2.0/changes/jdiff_topleftframe.html
    +@@ -49,7 +49,7 @@ body{overflow:auto;}
    +   <TD NOWRAP><FONT CLASS="indexText" size="-2"><A HREF="fields_index_all.html" TARGET="bottomleftframe">By Field</A></FONT><br></TD>
    + </TR>
    + </TABLE>
    +-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    + </script>
    + <script type="text/javascript">
    +   try {
    +diff --git a/docs/html/sdk/support_api_diff/22.2.0/changes/methods_index_additions.html b/docs/html/sdk/support_api_diff/22.2.0/changes/methods_index_additions.html
    +index f7c8488..b7b94ac 100644
    +--- a/docs/html/sdk/support_api_diff/22.2.0/changes/methods_index_additions.html
    ++++ b/docs/html/sdk/support_api_diff/22.2.0/changes/methods_index_additions.html
    +@@ -264,7 +264,7 @@ Listed as: <span style="color:#069"><strong>Added</strong></span>,  <span style=
    + (<code>float</code>)</A></nobr><br>
    + <nobr><A HREF="android.support.v4.view.ViewPropertyAnimatorCompat.html#android.support.v4.view.ViewPropertyAnimatorCompat.zBy_added(float)" class="hiddenlink" target="rightframe"><b>zBy</b>
    + (<code>float</code>)</A></nobr><br>
    +-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    + </script>
    + <script type="text/javascript">
    +   try {
    +diff --git a/docs/html/sdk/support_api_diff/22.2.0/changes/methods_index_all.html b/docs/html/sdk/support_api_diff/22.2.0/changes/methods_index_all.html
    +index 63a2848..04d3884 100644
    +--- a/docs/html/sdk/support_api_diff/22.2.0/changes/methods_index_all.html
    ++++ b/docs/html/sdk/support_api_diff/22.2.0/changes/methods_index_all.html
    +@@ -266,7 +266,7 @@ Listed as: <span style="color:#069"><strong>Added</strong></span>,  <span style=
    + (<code>float</code>)</A></nobr><br>
    + <nobr><A HREF="android.support.v4.view.ViewPropertyAnimatorCompat.html#android.support.v4.view.ViewPropertyAnimatorCompat.zBy_added(float)" class="hiddenlink" target="rightframe"><b>zBy</b>
    + (<code>float</code>)</A></nobr><br>
    +-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    + </script>
    + <script type="text/javascript">
    +   try {
    +diff --git a/docs/html/sdk/support_api_diff/22.2.0/changes/methods_index_changes.html b/docs/html/sdk/support_api_diff/22.2.0/changes/methods_index_changes.html
    +index 3e43f87..3bfd471 100644
    +--- a/docs/html/sdk/support_api_diff/22.2.0/changes/methods_index_changes.html
    ++++ b/docs/html/sdk/support_api_diff/22.2.0/changes/methods_index_changes.html
    +@@ -53,7 +53,7 @@ Listed as: <span style="color:#069"><strong>Added</strong></span>,  <span style=
    + <p><div style="line-height:1.5em;color:black">
    + <nobr><A HREF="android.support.v4.view.ViewPager.html#android.support.v4.view.ViewPager.setOnPageChangeListener_changed(android.support.v4.view.ViewPager.OnPageChangeListener)" class="hiddenlink" target="rightframe">setOnPageChangeListener
    + (<code>OnPageChangeListener</code>)</A></nobr><br>
    +-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    + </script>
    + <script type="text/javascript">
    +   try {
    +diff --git a/docs/html/sdk/support_api_diff/22.2.0/changes/methods_index_removals.html b/docs/html/sdk/support_api_diff/22.2.0/changes/methods_index_removals.html
    +index b5aea4f..e85e6fc 100644
    +--- a/docs/html/sdk/support_api_diff/22.2.0/changes/methods_index_removals.html
    ++++ b/docs/html/sdk/support_api_diff/22.2.0/changes/methods_index_removals.html
    +@@ -47,7 +47,7 @@ body{overflow:auto;}
    + <div id="indexTableCaption" style="background-color:#eee;padding:0 4px 0 4px;font-size:11px;margin-bottom:1em;">
    + Listed as: <span style="color:#069"><strong>Added</strong></span>,  <span style="color:#069"><strike>Removed</strike></span>,  <span style="color:#069">Changed</span></font>
    + </div>
    +-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    + </script>
    + <script type="text/javascript">
    +   try {
    +diff --git a/docs/html/sdk/support_api_diff/22.2.0/changes/packages_index_additions.html b/docs/html/sdk/support_api_diff/22.2.0/changes/packages_index_additions.html
    +index 7d92a82..183d500 100644
    +--- a/docs/html/sdk/support_api_diff/22.2.0/changes/packages_index_additions.html
    ++++ b/docs/html/sdk/support_api_diff/22.2.0/changes/packages_index_additions.html
    +@@ -61,7 +61,7 @@ Listed as: <span style="color:#069"><strong>Added</strong></span>,  <span style=
    + <A HREF="changes-summary.html#android.support.v7.appcompat" class="hiddenlink" target="rightframe"><b>android.support.v7.appcompat</b></A><br>
    + <A HREF="changes-summary.html#android.support.v7.recyclerview" class="hiddenlink" target="rightframe"><b>android.support.v7.recyclerview</b></A><br>
    + <A HREF="changes-summary.html#android.support.v7.widget.helper" class="hiddenlink" target="rightframe"><b>android.support.v7.widget.helper</b></A><br>
    +-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    + </script>
    + <script type="text/javascript">
    +   try {
    +diff --git a/docs/html/sdk/support_api_diff/22.2.0/changes/packages_index_all.html b/docs/html/sdk/support_api_diff/22.2.0/changes/packages_index_all.html
    +index 2735fe9..0fb83cf 100644
    +--- a/docs/html/sdk/support_api_diff/22.2.0/changes/packages_index_all.html
    ++++ b/docs/html/sdk/support_api_diff/22.2.0/changes/packages_index_all.html
    +@@ -66,7 +66,7 @@ Listed as: <span style="color:#069"><strong>Added</strong></span>,  <span style=
    + <A HREF="changes-summary.html#android.support.v7.recyclerview" class="hiddenlink" target="rightframe"><b>android.support.v7.recyclerview</b></A><br>
    + <A HREF="pkg_android.support.v7.util.html" class="hiddenlink" target="rightframe">android.support.v7.util</A><br>
    + <A HREF="changes-summary.html#android.support.v7.widget.helper" class="hiddenlink" target="rightframe"><b>android.support.v7.widget.helper</b></A><br>
    +-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    + </script>
    + <script type="text/javascript">
    +   try {
    +diff --git a/docs/html/sdk/support_api_diff/22.2.0/changes/packages_index_changes.html b/docs/html/sdk/support_api_diff/22.2.0/changes/packages_index_changes.html
    +index 3e40878..917e060 100644
    +--- a/docs/html/sdk/support_api_diff/22.2.0/changes/packages_index_changes.html
    ++++ b/docs/html/sdk/support_api_diff/22.2.0/changes/packages_index_changes.html
    +@@ -55,7 +55,7 @@ Listed as: <span style="color:#069"><strong>Added</strong></span>,  <span style=
    + <A HREF="pkg_android.support.v4.view.accessibility.html" class="hiddenlink" target="rightframe">android.support.v4.view.accessibility</A><br>
    + <A HREF="pkg_android.support.v7.app.html" class="hiddenlink" target="rightframe">android.support.v7.app</A><br>
    + <A HREF="pkg_android.support.v7.util.html" class="hiddenlink" target="rightframe">android.support.v7.util</A><br>
    +-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    + </script>
    + <script type="text/javascript">
    +   try {
    +diff --git a/docs/html/sdk/support_api_diff/22.2.0/changes/packages_index_removals.html b/docs/html/sdk/support_api_diff/22.2.0/changes/packages_index_removals.html
    +index d0ffabc..d5a825d 100644
    +--- a/docs/html/sdk/support_api_diff/22.2.0/changes/packages_index_removals.html
    ++++ b/docs/html/sdk/support_api_diff/22.2.0/changes/packages_index_removals.html
    +@@ -49,7 +49,7 @@ Listed as: <span style="color:#069"><strong>Added</strong></span>,  <span style=
    + </div>
    + <br>
    + <div id="indexTableEntries">
    +-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    + </script>
    + <script type="text/javascript">
    +   try {
    +diff --git a/docs/html/sdk/support_api_diff/22.2.0/changes/pkg_android.support.v4.media.session.html b/docs/html/sdk/support_api_diff/22.2.0/changes/pkg_android.support.v4.media.session.html
    +index 4dfd7de..992f05d 100644
    +--- a/docs/html/sdk/support_api_diff/22.2.0/changes/pkg_android.support.v4.media.session.html
    ++++ b/docs/html/sdk/support_api_diff/22.2.0/changes/pkg_android.support.v4.media.session.html
    +@@ -119,7 +119,7 @@ Package <A HREF="../../../../reference/android/support/v4/media/session/package-
    +     </div> <!-- end footer -->
    +     </div><!-- end doc-content -->
    +     </div> <!-- end body-content --> 
    +-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    + </script>
    + <script type="text/javascript">
    +   try {
    +diff --git a/docs/html/sdk/support_api_diff/22.2.0/changes/pkg_android.support.v4.view.accessibility.html b/docs/html/sdk/support_api_diff/22.2.0/changes/pkg_android.support.v4.view.accessibility.html
    +index f52efcb..86dc841 100644
    +--- a/docs/html/sdk/support_api_diff/22.2.0/changes/pkg_android.support.v4.view.accessibility.html
    ++++ b/docs/html/sdk/support_api_diff/22.2.0/changes/pkg_android.support.v4.view.accessibility.html
    +@@ -105,7 +105,7 @@ Package <A HREF="../../../../reference/android/support/v4/view/accessibility/pac
    +     </div> <!-- end footer -->
    +     </div><!-- end doc-content -->
    +     </div> <!-- end body-content --> 
    +-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    + </script>
    + <script type="text/javascript">
    +   try {
    +diff --git a/docs/html/sdk/support_api_diff/22.2.0/changes/pkg_android.support.v4.view.html b/docs/html/sdk/support_api_diff/22.2.0/changes/pkg_android.support.v4.view.html
    +index f05d812..ad51e62 100644
    +--- a/docs/html/sdk/support_api_diff/22.2.0/changes/pkg_android.support.v4.view.html
    ++++ b/docs/html/sdk/support_api_diff/22.2.0/changes/pkg_android.support.v4.view.html
    +@@ -126,7 +126,7 @@ Package <A HREF="../../../../reference/android/support/v4/view/package-summary.h
    +     </div> <!-- end footer -->
    +     </div><!-- end doc-content -->
    +     </div> <!-- end body-content --> 
    +-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    + </script>
    + <script type="text/javascript">
    +   try {
    +diff --git a/docs/html/sdk/support_api_diff/22.2.0/changes/pkg_android.support.v7.app.html b/docs/html/sdk/support_api_diff/22.2.0/changes/pkg_android.support.v7.app.html
    +index 44bf61d..508323f 100644
    +--- a/docs/html/sdk/support_api_diff/22.2.0/changes/pkg_android.support.v7.app.html
    ++++ b/docs/html/sdk/support_api_diff/22.2.0/changes/pkg_android.support.v7.app.html
    +@@ -126,7 +126,7 @@ Package <A HREF="../../../../reference/android/support/v7/app/package-summary.ht
    +     </div> <!-- end footer -->
    +     </div><!-- end doc-content -->
    +     </div> <!-- end body-content --> 
    +-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    + </script>
    + <script type="text/javascript">
    +   try {
    +diff --git a/docs/html/sdk/support_api_diff/22.2.0/changes/pkg_android.support.v7.util.html b/docs/html/sdk/support_api_diff/22.2.0/changes/pkg_android.support.v7.util.html
    +index d08d9af..8f74fb7 100644
    +--- a/docs/html/sdk/support_api_diff/22.2.0/changes/pkg_android.support.v7.util.html
    ++++ b/docs/html/sdk/support_api_diff/22.2.0/changes/pkg_android.support.v7.util.html
    +@@ -105,7 +105,7 @@ Package <A HREF="../../../../reference/android/support/v7/util/package-summary.h
    +     </div> <!-- end footer -->
    +     </div><!-- end doc-content -->
    +     </div> <!-- end body-content --> 
    +-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    + </script>
    + <script type="text/javascript">
    +   try {
    +diff --git a/docs/html/sdk/support_api_diff/22.2.1/changes/alldiffs_index_additions.html b/docs/html/sdk/support_api_diff/22.2.1/changes/alldiffs_index_additions.html
    +index 3374ffd..a1055f1 100644
    +--- a/docs/html/sdk/support_api_diff/22.2.1/changes/alldiffs_index_additions.html
    ++++ b/docs/html/sdk/support_api_diff/22.2.1/changes/alldiffs_index_additions.html
    +@@ -660,7 +660,7 @@ Listed as: <span style="color:#069"><strong>Added</strong></span>,  <span style=
    + <!-- Method useStaticShadow -->
    + <nobr><A HREF="android.support.v17.leanback.widget.ShadowOverlayContainer.html#android.support.v17.leanback.widget.ShadowOverlayContainer.useStaticShadow_added()" class="hiddenlink" target="rightframe"><b>useStaticShadow</b>
    + ()</A></nobr><br>
    +-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    + </script>
    + <script type="text/javascript">
    +   try {
    +diff --git a/docs/html/sdk/support_api_diff/22.2.1/changes/alldiffs_index_all.html b/docs/html/sdk/support_api_diff/22.2.1/changes/alldiffs_index_all.html
    +index bb24c29..48f43d2 100644
    +--- a/docs/html/sdk/support_api_diff/22.2.1/changes/alldiffs_index_all.html
    ++++ b/docs/html/sdk/support_api_diff/22.2.1/changes/alldiffs_index_all.html
    +@@ -913,7 +913,7 @@ Listed as: <span style="color:#069"><strong>Added</strong></span>,  <span style=
    +  <a href="#topheader"><font size="-2">TOP</font></a>
    + <p><div style="line-height:1.5em;color:black">
    + <A HREF="android.support.v17.leanback.widget.VerticalGridPresenter.html" class="hiddenlink" target="rightframe">VerticalGridPresenter</A><br>
    +-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    + </script>
    + <script type="text/javascript">
    +   try {
    +diff --git a/docs/html/sdk/support_api_diff/22.2.1/changes/alldiffs_index_changes.html b/docs/html/sdk/support_api_diff/22.2.1/changes/alldiffs_index_changes.html
    +index 8340749..d5b60c9 100644
    +--- a/docs/html/sdk/support_api_diff/22.2.1/changes/alldiffs_index_changes.html
    ++++ b/docs/html/sdk/support_api_diff/22.2.1/changes/alldiffs_index_changes.html
    +@@ -389,7 +389,7 @@ Listed as: <span style="color:#069"><strong>Added</strong></span>,  <span style=
    +  <a href="#topheader"><font size="-2">TOP</font></a>
    + <p><div style="line-height:1.5em;color:black">
    + <A HREF="android.support.v17.leanback.widget.VerticalGridPresenter.html" class="hiddenlink" target="rightframe">VerticalGridPresenter</A><br>
    +-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    + </script>
    + <script type="text/javascript">
    +   try {
    +diff --git a/docs/html/sdk/support_api_diff/22.2.1/changes/alldiffs_index_removals.html b/docs/html/sdk/support_api_diff/22.2.1/changes/alldiffs_index_removals.html
    +index 0d670c0..f2a8797 100644
    +--- a/docs/html/sdk/support_api_diff/22.2.1/changes/alldiffs_index_removals.html
    ++++ b/docs/html/sdk/support_api_diff/22.2.1/changes/alldiffs_index_removals.html
    +@@ -83,7 +83,7 @@ Listed as: <span style="color:#069"><strong>Added</strong></span>,  <span style=
    + <!-- Field Platform_V12_AppCompat_Light -->
    + <nobr><A HREF="android.support.v7.appcompat.R.style.html#android.support.v7.appcompat.R.style.Platform_V12_AppCompat_Light" class="hiddenlink" target="rightframe"><strike>Platform_V12_AppCompat_Light</strike></A>
    + </nobr><br>
    +-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    + </script>
    + <script type="text/javascript">
    +   try {
    +diff --git a/docs/html/sdk/support_api_diff/22.2.1/changes/android.support.design.widget.CoordinatorLayout.Behavior.html b/docs/html/sdk/support_api_diff/22.2.1/changes/android.support.design.widget.CoordinatorLayout.Behavior.html
    +index 78392f4..c45efa2 100644
    +--- a/docs/html/sdk/support_api_diff/22.2.1/changes/android.support.design.widget.CoordinatorLayout.Behavior.html
    ++++ b/docs/html/sdk/support_api_diff/22.2.1/changes/android.support.design.widget.CoordinatorLayout.Behavior.html
    +@@ -108,7 +108,7 @@ Class android.support.design.widget.<A HREF="../../../../reference/android/suppo
    +     </div> <!-- end footer -->
    +     </div><!-- end doc-content -->
    +     </div> <!-- end body-content --> 
    +-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    + </script>
    + <script type="text/javascript">
    +   try {
    +diff --git a/docs/html/sdk/support_api_diff/22.2.1/changes/android.support.design.widget.FloatingActionButton.Behavior.html b/docs/html/sdk/support_api_diff/22.2.1/changes/android.support.design.widget.FloatingActionButton.Behavior.html
    +index 6d68976..a23105a 100644
    +--- a/docs/html/sdk/support_api_diff/22.2.1/changes/android.support.design.widget.FloatingActionButton.Behavior.html
    ++++ b/docs/html/sdk/support_api_diff/22.2.1/changes/android.support.design.widget.FloatingActionButton.Behavior.html
    +@@ -115,7 +115,7 @@ Class android.support.design.widget.<A HREF="../../../../reference/android/suppo
    +     </div> <!-- end footer -->
    +     </div><!-- end doc-content -->
    +     </div> <!-- end body-content --> 
    +-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    + </script>
    + <script type="text/javascript">
    +   try {
    +diff --git a/docs/html/sdk/support_api_diff/22.2.1/changes/android.support.design.widget.FloatingActionButton.html b/docs/html/sdk/support_api_diff/22.2.1/changes/android.support.design.widget.FloatingActionButton.html
    +index 21b55c0..91a6d77 100644
    +--- a/docs/html/sdk/support_api_diff/22.2.1/changes/android.support.design.widget.FloatingActionButton.html
    ++++ b/docs/html/sdk/support_api_diff/22.2.1/changes/android.support.design.widget.FloatingActionButton.html
    +@@ -115,7 +115,7 @@ Class android.support.design.widget.<A HREF="../../../../reference/android/suppo
    +     </div> <!-- end footer -->
    +     </div><!-- end doc-content -->
    +     </div> <!-- end body-content --> 
    +-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    + </script>
    + <script type="text/javascript">
    +   try {
    +diff --git a/docs/html/sdk/support_api_diff/22.2.1/changes/android.support.design.widget.Snackbar.html b/docs/html/sdk/support_api_diff/22.2.1/changes/android.support.design.widget.Snackbar.html
    +index 028df73..24fdf70 100644
    +--- a/docs/html/sdk/support_api_diff/22.2.1/changes/android.support.design.widget.Snackbar.html
    ++++ b/docs/html/sdk/support_api_diff/22.2.1/changes/android.support.design.widget.Snackbar.html
    +@@ -130,7 +130,7 @@ Class android.support.design.widget.<A HREF="../../../../reference/android/suppo
    +     </div> <!-- end footer -->
    +     </div><!-- end doc-content -->
    +     </div> <!-- end body-content --> 
    +-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    + </script>
    + <script type="text/javascript">
    +   try {
    +diff --git a/docs/html/sdk/support_api_diff/22.2.1/changes/android.support.design.widget.TabLayout.Tab.html b/docs/html/sdk/support_api_diff/22.2.1/changes/android.support.design.widget.TabLayout.Tab.html
    +index 2acf995..74a296d 100644
    +--- a/docs/html/sdk/support_api_diff/22.2.1/changes/android.support.design.widget.TabLayout.Tab.html
    ++++ b/docs/html/sdk/support_api_diff/22.2.1/changes/android.support.design.widget.TabLayout.Tab.html
    +@@ -108,7 +108,7 @@ Class android.support.design.widget.<A HREF="../../../../reference/android/suppo
    +     </div> <!-- end footer -->
    +     </div><!-- end doc-content -->
    +     </div> <!-- end body-content --> 
    +-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    + </script>
    + <script type="text/javascript">
    +   try {
    +diff --git a/docs/html/sdk/support_api_diff/22.2.1/changes/android.support.design.widget.TabLayout.html b/docs/html/sdk/support_api_diff/22.2.1/changes/android.support.design.widget.TabLayout.html
    +index 22a5ff5..3a8d151 100644
    +--- a/docs/html/sdk/support_api_diff/22.2.1/changes/android.support.design.widget.TabLayout.html
    ++++ b/docs/html/sdk/support_api_diff/22.2.1/changes/android.support.design.widget.TabLayout.html
    +@@ -108,7 +108,7 @@ Class android.support.design.widget.<A HREF="../../../../reference/android/suppo
    +     </div> <!-- end footer -->
    +     </div><!-- end doc-content -->
    +     </div> <!-- end body-content --> 
    +-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    + </script>
    + <script type="text/javascript">
    +   try {
    +diff --git a/docs/html/sdk/support_api_diff/22.2.1/changes/android.support.v17.leanback.app.DetailsFragment.html b/docs/html/sdk/support_api_diff/22.2.1/changes/android.support.v17.leanback.app.DetailsFragment.html
    +index 16e5798..7ae6ce1 100644
    +--- a/docs/html/sdk/support_api_diff/22.2.1/changes/android.support.v17.leanback.app.DetailsFragment.html
    ++++ b/docs/html/sdk/support_api_diff/22.2.1/changes/android.support.v17.leanback.app.DetailsFragment.html
    +@@ -136,7 +136,7 @@ Class android.support.v17.leanback.app.<A HREF="../../../../reference/android/su
    +     </div> <!-- end footer -->
    +     </div><!-- end doc-content -->
    +     </div> <!-- end body-content --> 
    +-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    + </script>
    + <script type="text/javascript">
    +   try {
    +diff --git a/docs/html/sdk/support_api_diff/22.2.1/changes/android.support.v17.leanback.app.DetailsSupportFragment.html b/docs/html/sdk/support_api_diff/22.2.1/changes/android.support.v17.leanback.app.DetailsSupportFragment.html
    +index 7825292..d1733ac 100644
    +--- a/docs/html/sdk/support_api_diff/22.2.1/changes/android.support.v17.leanback.app.DetailsSupportFragment.html
    ++++ b/docs/html/sdk/support_api_diff/22.2.1/changes/android.support.v17.leanback.app.DetailsSupportFragment.html
    +@@ -136,7 +136,7 @@ Class android.support.v17.leanback.app.<A HREF="../../../../reference/android/su
    +     </div> <!-- end footer -->
    +     </div><!-- end doc-content -->
    +     </div> <!-- end body-content --> 
    +-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    + </script>
    + <script type="text/javascript">
    +   try {
    +diff --git a/docs/html/sdk/support_api_diff/22.2.1/changes/android.support.v17.leanback.widget.DetailsOverviewRowPresenter.html b/docs/html/sdk/support_api_diff/22.2.1/changes/android.support.v17.leanback.widget.DetailsOverviewRowPresenter.html
    +index ba8e6af..799db3d 100644
    +--- a/docs/html/sdk/support_api_diff/22.2.1/changes/android.support.v17.leanback.widget.DetailsOverviewRowPresenter.html
    ++++ b/docs/html/sdk/support_api_diff/22.2.1/changes/android.support.v17.leanback.widget.DetailsOverviewRowPresenter.html
    +@@ -94,7 +94,7 @@ Class android.support.v17.leanback.widget.<A HREF="../../../../reference/android
    +     </div> <!-- end footer -->
    +     </div><!-- end doc-content -->
    +     </div> <!-- end body-content --> 
    +-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    + </script>
    + <script type="text/javascript">
    +   try {
    +diff --git a/docs/html/sdk/support_api_diff/22.2.1/changes/android.support.v17.leanback.widget.ItemBridgeAdapter.ViewHolder.html b/docs/html/sdk/support_api_diff/22.2.1/changes/android.support.v17.leanback.widget.ItemBridgeAdapter.ViewHolder.html
    +index 25f1b48..f8c0cbf 100644
    +--- a/docs/html/sdk/support_api_diff/22.2.1/changes/android.support.v17.leanback.widget.ItemBridgeAdapter.ViewHolder.html
    ++++ b/docs/html/sdk/support_api_diff/22.2.1/changes/android.support.v17.leanback.widget.ItemBridgeAdapter.ViewHolder.html
    +@@ -109,7 +109,7 @@ Class android.support.v17.leanback.widget.<A HREF="../../../../reference/android
    +     </div> <!-- end footer -->
    +     </div><!-- end doc-content -->
    +     </div> <!-- end body-content --> 
    +-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    + </script>
    + <script type="text/javascript">
    +   try {
    +diff --git a/docs/html/sdk/support_api_diff/22.2.1/changes/android.support.v17.leanback.widget.ItemBridgeAdapter.html b/docs/html/sdk/support_api_diff/22.2.1/changes/android.support.v17.leanback.widget.ItemBridgeAdapter.html
    +index a88f694..b98c33e 100644
    +--- a/docs/html/sdk/support_api_diff/22.2.1/changes/android.support.v17.leanback.widget.ItemBridgeAdapter.html
    ++++ b/docs/html/sdk/support_api_diff/22.2.1/changes/android.support.v17.leanback.widget.ItemBridgeAdapter.html
    +@@ -109,7 +109,7 @@ Class android.support.v17.leanback.widget.<A HREF="../../../../reference/android
    +     </div> <!-- end footer -->
    +     </div><!-- end doc-content -->
    +     </div> <!-- end body-content --> 
    +-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    + </script>
    + <script type="text/javascript">
    +   try {
    +diff --git a/docs/html/sdk/support_api_diff/22.2.1/changes/android.support.v17.leanback.widget.ListRowPresenter.html b/docs/html/sdk/support_api_diff/22.2.1/changes/android.support.v17.leanback.widget.ListRowPresenter.html
    +index 5d71011..f9ad877 100644
    +--- a/docs/html/sdk/support_api_diff/22.2.1/changes/android.support.v17.leanback.widget.ListRowPresenter.html
    ++++ b/docs/html/sdk/support_api_diff/22.2.1/changes/android.support.v17.leanback.widget.ListRowPresenter.html
    +@@ -111,7 +111,7 @@ Change in signature from <code>void</code> to <code>Context</code>.<br>
    +     </div> <!-- end footer -->
    +     </div><!-- end doc-content -->
    +     </div> <!-- end body-content --> 
    +-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    + </script>
    + <script type="text/javascript">
    +   try {
    +diff --git a/docs/html/sdk/support_api_diff/22.2.1/changes/android.support.v17.leanback.widget.OnChildSelectedListener.html b/docs/html/sdk/support_api_diff/22.2.1/changes/android.support.v17.leanback.widget.OnChildSelectedListener.html
    +index eb8a563..f13b147 100644
    +--- a/docs/html/sdk/support_api_diff/22.2.1/changes/android.support.v17.leanback.widget.OnChildSelectedListener.html
    ++++ b/docs/html/sdk/support_api_diff/22.2.1/changes/android.support.v17.leanback.widget.OnChildSelectedListener.html
    +@@ -94,7 +94,7 @@ Interface android.support.v17.leanback.widget.<A HREF="../../../../reference/and
    +     </div> <!-- end footer -->
    +     </div><!-- end doc-content -->
    +     </div> <!-- end body-content --> 
    +-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    + </script>
    + <script type="text/javascript">
    +   try {
    +diff --git a/docs/html/sdk/support_api_diff/22.2.1/changes/android.support.v17.leanback.widget.Presenter.ViewHolder.html b/docs/html/sdk/support_api_diff/22.2.1/changes/android.support.v17.leanback.widget.Presenter.ViewHolder.html
    +index a94d9f5..55f3575 100644
    +--- a/docs/html/sdk/support_api_diff/22.2.1/changes/android.support.v17.leanback.widget.Presenter.ViewHolder.html
    ++++ b/docs/html/sdk/support_api_diff/22.2.1/changes/android.support.v17.leanback.widget.Presenter.ViewHolder.html
    +@@ -116,7 +116,7 @@ Class android.support.v17.leanback.widget.<A HREF="../../../../reference/android
    +     </div> <!-- end footer -->
    +     </div><!-- end doc-content -->
    +     </div> <!-- end body-content --> 
    +-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    + </script>
    + <script type="text/javascript">
    +   try {
    +diff --git a/docs/html/sdk/support_api_diff/22.2.1/changes/android.support.v17.leanback.widget.Presenter.html b/docs/html/sdk/support_api_diff/22.2.1/changes/android.support.v17.leanback.widget.Presenter.html
    +index fde5e4b..417bf86 100644
    +--- a/docs/html/sdk/support_api_diff/22.2.1/changes/android.support.v17.leanback.widget.Presenter.html
    ++++ b/docs/html/sdk/support_api_diff/22.2.1/changes/android.support.v17.leanback.widget.Presenter.html
    +@@ -116,7 +116,7 @@ Class android.support.v17.leanback.widget.<A HREF="../../../../reference/android
    +     </div> <!-- end footer -->
    +     </div><!-- end doc-content -->
    +     </div> <!-- end body-content --> 
    +-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    + </script>
    + <script type="text/javascript">
    +   try {
    +diff --git a/docs/html/sdk/support_api_diff/22.2.1/changes/android.support.v17.leanback.widget.PresenterSelector.html b/docs/html/sdk/support_api_diff/22.2.1/changes/android.support.v17.leanback.widget.PresenterSelector.html
    +index 06a0a79..827b2cf 100644
    +--- a/docs/html/sdk/support_api_diff/22.2.1/changes/android.support.v17.leanback.widget.PresenterSelector.html
    ++++ b/docs/html/sdk/support_api_diff/22.2.1/changes/android.support.v17.leanback.widget.PresenterSelector.html
    +@@ -108,7 +108,7 @@ Class android.support.v17.leanback.widget.<A HREF="../../../../reference/android
    +     </div> <!-- end footer -->
    +     </div><!-- end doc-content -->
    +     </div> <!-- end body-content --> 
    +-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    + </script>
    + <script type="text/javascript">
    +   try {
    +diff --git a/docs/html/sdk/support_api_diff/22.2.1/changes/android.support.v17.leanback.widget.RowPresenter.html b/docs/html/sdk/support_api_diff/22.2.1/changes/android.support.v17.leanback.widget.RowPresenter.html
    +index 6da5f9b..24b7683 100644
    +--- a/docs/html/sdk/support_api_diff/22.2.1/changes/android.support.v17.leanback.widget.RowPresenter.html
    ++++ b/docs/html/sdk/support_api_diff/22.2.1/changes/android.support.v17.leanback.widget.RowPresenter.html
    +@@ -108,7 +108,7 @@ Class android.support.v17.leanback.widget.<A HREF="../../../../reference/android
    +     </div> <!-- end footer -->
    +     </div><!-- end doc-content -->
    +     </div> <!-- end body-content --> 
    +-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    + </script>
    + <script type="text/javascript">
    +   try {
    +diff --git a/docs/html/sdk/support_api_diff/22.2.1/changes/android.support.v17.leanback.widget.ShadowOverlayContainer.html b/docs/html/sdk/support_api_diff/22.2.1/changes/android.support.v17.leanback.widget.ShadowOverlayContainer.html
    +index ac3ac3a..9814065 100644
    +--- a/docs/html/sdk/support_api_diff/22.2.1/changes/android.support.v17.leanback.widget.ShadowOverlayContainer.html
    ++++ b/docs/html/sdk/support_api_diff/22.2.1/changes/android.support.v17.leanback.widget.ShadowOverlayContainer.html
    +@@ -172,7 +172,7 @@ Class android.support.v17.leanback.widget.<A HREF="../../../../reference/android
    +     </div> <!-- end footer -->
    +     </div><!-- end doc-content -->
    +     </div> <!-- end body-content --> 
    +-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    + </script>
    + <script type="text/javascript">
    +   try {
    +diff --git a/docs/html/sdk/support_api_diff/22.2.1/changes/android.support.v17.leanback.widget.VerticalGridPresenter.html b/docs/html/sdk/support_api_diff/22.2.1/changes/android.support.v17.leanback.widget.VerticalGridPresenter.html
    +index ab9ce07..c18075e 100644
    +--- a/docs/html/sdk/support_api_diff/22.2.1/changes/android.support.v17.leanback.widget.VerticalGridPresenter.html
    ++++ b/docs/html/sdk/support_api_diff/22.2.1/changes/android.support.v17.leanback.widget.VerticalGridPresenter.html
    +@@ -111,7 +111,7 @@ Change in signature from <code>void</code> to <code>Context</code>.<br>
    +     </div> <!-- end footer -->
    +     </div><!-- end doc-content -->
    +     </div> <!-- end body-content --> 
    +-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    + </script>
    + <script type="text/javascript">
    +   try {
    +diff --git a/docs/html/sdk/support_api_diff/22.2.1/changes/android.support.v4.app.NotificationCompat.Action.html b/docs/html/sdk/support_api_diff/22.2.1/changes/android.support.v4.app.NotificationCompat.Action.html
    +index 8519610..d96b874 100644
    +--- a/docs/html/sdk/support_api_diff/22.2.1/changes/android.support.v4.app.NotificationCompat.Action.html
    ++++ b/docs/html/sdk/support_api_diff/22.2.1/changes/android.support.v4.app.NotificationCompat.Action.html
    +@@ -131,7 +131,7 @@ Change of visibility from protected to public.<br>
    +     </div> <!-- end footer -->
    +     </div><!-- end doc-content -->
    +     </div> <!-- end body-content --> 
    +-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    + </script>
    + <script type="text/javascript">
    +   try {
    +diff --git a/docs/html/sdk/support_api_diff/22.2.1/changes/android.support.v4.app.NotificationCompatBase.Action.html b/docs/html/sdk/support_api_diff/22.2.1/changes/android.support.v4.app.NotificationCompatBase.Action.html
    +index 498374e..09ae7fc 100644
    +--- a/docs/html/sdk/support_api_diff/22.2.1/changes/android.support.v4.app.NotificationCompatBase.Action.html
    ++++ b/docs/html/sdk/support_api_diff/22.2.1/changes/android.support.v4.app.NotificationCompatBase.Action.html
    +@@ -151,7 +151,7 @@ Change of visibility from protected to public.<br>
    +     </div> <!-- end footer -->
    +     </div><!-- end doc-content -->
    +     </div> <!-- end body-content --> 
    +-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    + </script>
    + <script type="text/javascript">
    +   try {
    +diff --git a/docs/html/sdk/support_api_diff/22.2.1/changes/android.support.v4.app.NotificationCompatBase.html b/docs/html/sdk/support_api_diff/22.2.1/changes/android.support.v4.app.NotificationCompatBase.html
    +index 309d7b6..9824574 100644
    +--- a/docs/html/sdk/support_api_diff/22.2.1/changes/android.support.v4.app.NotificationCompatBase.html
    ++++ b/docs/html/sdk/support_api_diff/22.2.1/changes/android.support.v4.app.NotificationCompatBase.html
    +@@ -109,7 +109,7 @@ Class android.support.v4.app.<A HREF="../../../../reference/android/support/v4/a
    +     </div> <!-- end footer -->
    +     </div><!-- end doc-content -->
    +     </div> <!-- end body-content --> 
    +-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    + </script>
    + <script type="text/javascript">
    +   try {
    +diff --git a/docs/html/sdk/support_api_diff/22.2.1/changes/android.support.v7.appcompat.R.attr.html b/docs/html/sdk/support_api_diff/22.2.1/changes/android.support.v7.appcompat.R.attr.html
    +index 229289c..541f134 100644
    +--- a/docs/html/sdk/support_api_diff/22.2.1/changes/android.support.v7.appcompat.R.attr.html
    ++++ b/docs/html/sdk/support_api_diff/22.2.1/changes/android.support.v7.appcompat.R.attr.html
    +@@ -108,7 +108,7 @@ Class android.support.v7.appcompat.<A HREF="../../../../reference/android/suppor
    +     </div> <!-- end footer -->
    +     </div><!-- end doc-content -->
    +     </div> <!-- end body-content --> 
    +-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    + </script>
    + <script type="text/javascript">
    +   try {
    +diff --git a/docs/html/sdk/support_api_diff/22.2.1/changes/android.support.v7.appcompat.R.dimen.html b/docs/html/sdk/support_api_diff/22.2.1/changes/android.support.v7.appcompat.R.dimen.html
    +index a253e59..584073e 100644
    +--- a/docs/html/sdk/support_api_diff/22.2.1/changes/android.support.v7.appcompat.R.dimen.html
    ++++ b/docs/html/sdk/support_api_diff/22.2.1/changes/android.support.v7.appcompat.R.dimen.html
    +@@ -122,7 +122,7 @@ Class android.support.v7.appcompat.<A HREF="../../../../reference/android/suppor
    +     </div> <!-- end footer -->
    +     </div><!-- end doc-content -->
    +     </div> <!-- end body-content --> 
    +-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    + </script>
    + <script type="text/javascript">
    +   try {
    +diff --git a/docs/html/sdk/support_api_diff/22.2.1/changes/android.support.v7.appcompat.R.drawable.html b/docs/html/sdk/support_api_diff/22.2.1/changes/android.support.v7.appcompat.R.drawable.html
    +index 4f87127..45a1dc7 100644
    +--- a/docs/html/sdk/support_api_diff/22.2.1/changes/android.support.v7.appcompat.R.drawable.html
    ++++ b/docs/html/sdk/support_api_diff/22.2.1/changes/android.support.v7.appcompat.R.drawable.html
    +@@ -108,7 +108,7 @@ Class android.support.v7.appcompat.<A HREF="../../../../reference/android/suppor
    +     </div> <!-- end footer -->
    +     </div><!-- end doc-content -->
    +     </div> <!-- end body-content --> 
    +-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    + </script>
    + <script type="text/javascript">
    +   try {
    +diff --git a/docs/html/sdk/support_api_diff/22.2.1/changes/android.support.v7.appcompat.R.id.html b/docs/html/sdk/support_api_diff/22.2.1/changes/android.support.v7.appcompat.R.id.html
    +index e856c8b..cecd912 100644
    +--- a/docs/html/sdk/support_api_diff/22.2.1/changes/android.support.v7.appcompat.R.id.html
    ++++ b/docs/html/sdk/support_api_diff/22.2.1/changes/android.support.v7.appcompat.R.id.html
    +@@ -192,7 +192,7 @@ Class android.support.v7.appcompat.<A HREF="../../../../reference/android/suppor
    +     </div> <!-- end footer -->
    +     </div><!-- end doc-content -->
    +     </div> <!-- end body-content --> 
    +-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    + </script>
    + <script type="text/javascript">
    +   try {
    +diff --git a/docs/html/sdk/support_api_diff/22.2.1/changes/android.support.v7.appcompat.R.integer.html b/docs/html/sdk/support_api_diff/22.2.1/changes/android.support.v7.appcompat.R.integer.html
    +index 70585a7..4b90739 100644
    +--- a/docs/html/sdk/support_api_diff/22.2.1/changes/android.support.v7.appcompat.R.integer.html
    ++++ b/docs/html/sdk/support_api_diff/22.2.1/changes/android.support.v7.appcompat.R.integer.html
    +@@ -115,7 +115,7 @@ Class android.support.v7.appcompat.<A HREF="../../../../reference/android/suppor
    +     </div> <!-- end footer -->
    +     </div><!-- end doc-content -->
    +     </div> <!-- end body-content --> 
    +-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    + </script>
    + <script type="text/javascript">
    +   try {
    +diff --git a/docs/html/sdk/support_api_diff/22.2.1/changes/android.support.v7.appcompat.R.layout.html b/docs/html/sdk/support_api_diff/22.2.1/changes/android.support.v7.appcompat.R.layout.html
    +index 8130707..c0a1304 100644
    +--- a/docs/html/sdk/support_api_diff/22.2.1/changes/android.support.v7.appcompat.R.layout.html
    ++++ b/docs/html/sdk/support_api_diff/22.2.1/changes/android.support.v7.appcompat.R.layout.html
    +@@ -157,7 +157,7 @@ Class android.support.v7.appcompat.<A HREF="../../../../reference/android/suppor
    +     </div> <!-- end footer -->
    +     </div><!-- end doc-content -->
    +     </div> <!-- end body-content --> 
    +-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    + </script>
    + <script type="text/javascript">
    +   try {
    +diff --git a/docs/html/sdk/support_api_diff/22.2.1/changes/android.support.v7.appcompat.R.string.html b/docs/html/sdk/support_api_diff/22.2.1/changes/android.support.v7.appcompat.R.string.html
    +index 6a01b20..39be2b2 100644
    +--- a/docs/html/sdk/support_api_diff/22.2.1/changes/android.support.v7.appcompat.R.string.html
    ++++ b/docs/html/sdk/support_api_diff/22.2.1/changes/android.support.v7.appcompat.R.string.html
    +@@ -108,7 +108,7 @@ Class android.support.v7.appcompat.<A HREF="../../../../reference/android/suppor
    +     </div> <!-- end footer -->
    +     </div><!-- end doc-content -->
    +     </div> <!-- end body-content --> 
    +-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    + </script>
    + <script type="text/javascript">
    +   try {
    +diff --git a/docs/html/sdk/support_api_diff/22.2.1/changes/android.support.v7.appcompat.R.style.html b/docs/html/sdk/support_api_diff/22.2.1/changes/android.support.v7.appcompat.R.style.html
    +index 886f2ce..ffc3690 100644
    +--- a/docs/html/sdk/support_api_diff/22.2.1/changes/android.support.v7.appcompat.R.style.html
    ++++ b/docs/html/sdk/support_api_diff/22.2.1/changes/android.support.v7.appcompat.R.style.html
    +@@ -186,7 +186,7 @@ Class android.support.v7.appcompat.<A HREF="../../../../reference/android/suppor
    +     </div> <!-- end footer -->
    +     </div><!-- end doc-content -->
    +     </div> <!-- end body-content --> 
    +-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    + </script>
    + <script type="text/javascript">
    +   try {
    +diff --git a/docs/html/sdk/support_api_diff/22.2.1/changes/android.support.v7.appcompat.R.styleable.html b/docs/html/sdk/support_api_diff/22.2.1/changes/android.support.v7.appcompat.R.styleable.html
    +index cd9cd60..713526b 100644
    +--- a/docs/html/sdk/support_api_diff/22.2.1/changes/android.support.v7.appcompat.R.styleable.html
    ++++ b/docs/html/sdk/support_api_diff/22.2.1/changes/android.support.v7.appcompat.R.styleable.html
    +@@ -108,7 +108,7 @@ Class android.support.v7.appcompat.<A HREF="../../../../reference/android/suppor
    +     </div> <!-- end footer -->
    +     </div><!-- end doc-content -->
    +     </div> <!-- end body-content --> 
    +-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    + </script>
    + <script type="text/javascript">
    +   try {
    +diff --git a/docs/html/sdk/support_api_diff/22.2.1/changes/android.support.v7.util.SortedList.html b/docs/html/sdk/support_api_diff/22.2.1/changes/android.support.v7.util.SortedList.html
    +index b38c632..181a0fc 100644
    +--- a/docs/html/sdk/support_api_diff/22.2.1/changes/android.support.v7.util.SortedList.html
    ++++ b/docs/html/sdk/support_api_diff/22.2.1/changes/android.support.v7.util.SortedList.html
    +@@ -122,7 +122,7 @@ Class android.support.v7.util.<A HREF="../../../../reference/android/support/v7/
    +     </div> <!-- end footer -->
    +     </div><!-- end doc-content -->
    +     </div> <!-- end body-content --> 
    +-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    + </script>
    + <script type="text/javascript">
    +   try {
    +diff --git a/docs/html/sdk/support_api_diff/22.2.1/changes/changes-summary.html b/docs/html/sdk/support_api_diff/22.2.1/changes/changes-summary.html
    +index e05b67d..b500246 100644
    +--- a/docs/html/sdk/support_api_diff/22.2.1/changes/changes-summary.html
    ++++ b/docs/html/sdk/support_api_diff/22.2.1/changes/changes-summary.html
    +@@ -177,7 +177,7 @@ see the <a href="http://developer.android.com/index.html" target="_top">Android
    +     </div> <!-- end footer -->
    +     </div><!-- end doc-content -->
    +     </div> <!-- end body-content --> 
    +-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    + </script>
    + <script type="text/javascript">
    +   try {
    +diff --git a/docs/html/sdk/support_api_diff/22.2.1/changes/classes_index_additions.html b/docs/html/sdk/support_api_diff/22.2.1/changes/classes_index_additions.html
    +index 52b4ab7..f2fe6ec 100644
    +--- a/docs/html/sdk/support_api_diff/22.2.1/changes/classes_index_additions.html
    ++++ b/docs/html/sdk/support_api_diff/22.2.1/changes/classes_index_additions.html
    +@@ -103,7 +103,7 @@ Listed as: <span style="color:#069"><strong>Added</strong></span>,  <span style=
    +  <a href="#topheader"><font size="-2">TOP</font></a>
    + <p><div style="line-height:1.5em;color:black">
    + <A HREF="pkg_android.support.v17.leanback.widget.html#OnChildViewHolderSelectedListener" class="hiddenlink" target="rightframe"><b>OnChildViewHolderSelectedListener</b></A><br>
    +-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    + </script>
    + <script type="text/javascript">
    +   try {
    +diff --git a/docs/html/sdk/support_api_diff/22.2.1/changes/classes_index_all.html b/docs/html/sdk/support_api_diff/22.2.1/changes/classes_index_all.html
    +index 1edab7a..16ebdfa 100644
    +--- a/docs/html/sdk/support_api_diff/22.2.1/changes/classes_index_all.html
    ++++ b/docs/html/sdk/support_api_diff/22.2.1/changes/classes_index_all.html
    +@@ -339,7 +339,7 @@ Listed as: <span style="color:#069"><strong>Added</strong></span>,  <span style=
    +  <a href="#topheader"><font size="-2">TOP</font></a>
    + <p><div style="line-height:1.5em;color:black">
    + <A HREF="android.support.v17.leanback.widget.VerticalGridPresenter.html" class="hiddenlink" target="rightframe">VerticalGridPresenter</A><br>
    +-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    + </script>
    + <script type="text/javascript">
    +   try {
    +diff --git a/docs/html/sdk/support_api_diff/22.2.1/changes/classes_index_changes.html b/docs/html/sdk/support_api_diff/22.2.1/changes/classes_index_changes.html
    +index f46bc67..8072f0f 100644
    +--- a/docs/html/sdk/support_api_diff/22.2.1/changes/classes_index_changes.html
    ++++ b/docs/html/sdk/support_api_diff/22.2.1/changes/classes_index_changes.html
    +@@ -259,7 +259,7 @@ Listed as: <span style="color:#069"><strong>Added</strong></span>,  <span style=
    +  <a href="#topheader"><font size="-2">TOP</font></a>
    + <p><div style="line-height:1.5em;color:black">
    + <A HREF="android.support.v17.leanback.widget.VerticalGridPresenter.html" class="hiddenlink" target="rightframe">VerticalGridPresenter</A><br>
    +-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    + </script>
    + <script type="text/javascript">
    +   try {
    +diff --git a/docs/html/sdk/support_api_diff/22.2.1/changes/classes_index_removals.html b/docs/html/sdk/support_api_diff/22.2.1/changes/classes_index_removals.html
    +index 09c0d19..757f5bb 100644
    +--- a/docs/html/sdk/support_api_diff/22.2.1/changes/classes_index_removals.html
    ++++ b/docs/html/sdk/support_api_diff/22.2.1/changes/classes_index_removals.html
    +@@ -63,7 +63,7 @@ Listed as: <span style="color:#069"><strong>Added</strong></span>,  <span style=
    +  <a href="#topheader"><font size="-2">TOP</font></a>
    + <p><div style="line-height:1.5em;color:black">
    + <A HREF="pkg_android.support.v17.leanback.widget.html#GridLayoutManager" class="hiddenlink" target="rightframe"><strike>GridLayoutManager</strike></A><br>
    +-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    + </script>
    + <script type="text/javascript">
    +   try {
    +diff --git a/docs/html/sdk/support_api_diff/22.2.1/changes/constructors_index_additions.html b/docs/html/sdk/support_api_diff/22.2.1/changes/constructors_index_additions.html
    +index e694216..3bced29 100644
    +--- a/docs/html/sdk/support_api_diff/22.2.1/changes/constructors_index_additions.html
    ++++ b/docs/html/sdk/support_api_diff/22.2.1/changes/constructors_index_additions.html
    +@@ -53,7 +53,7 @@ Listed as: <span style="color:#069"><strong>Added</strong></span>,  <span style=
    + <p><div style="line-height:1.5em;color:black">
    + <nobr><A HREF="android.support.v4.app.NotificationCompatBase.html#android.support.v4.app.NotificationCompatBase.ctor_added()" class="hiddenlink" target="rightframe"><b>NotificationCompatBase</b>
    + ()</A></nobr>&nbsp;constructor<br>
    +-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    + </script>
    + <script type="text/javascript">
    +   try {
    +diff --git a/docs/html/sdk/support_api_diff/22.2.1/changes/constructors_index_all.html b/docs/html/sdk/support_api_diff/22.2.1/changes/constructors_index_all.html
    +index 27d7557..7769d75 100644
    +--- a/docs/html/sdk/support_api_diff/22.2.1/changes/constructors_index_all.html
    ++++ b/docs/html/sdk/support_api_diff/22.2.1/changes/constructors_index_all.html
    +@@ -53,7 +53,7 @@ Listed as: <span style="color:#069"><strong>Added</strong></span>,  <span style=
    + <p><div style="line-height:1.5em;color:black">
    + <nobr><A HREF="android.support.v4.app.NotificationCompatBase.html#android.support.v4.app.NotificationCompatBase.ctor_added()" class="hiddenlink" target="rightframe"><b>NotificationCompatBase</b>
    + ()</A></nobr>&nbsp;constructor<br>
    +-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    + </script>
    + <script type="text/javascript">
    +   try {
    +diff --git a/docs/html/sdk/support_api_diff/22.2.1/changes/constructors_index_changes.html b/docs/html/sdk/support_api_diff/22.2.1/changes/constructors_index_changes.html
    +index a5ca2ef..122cdce 100644
    +--- a/docs/html/sdk/support_api_diff/22.2.1/changes/constructors_index_changes.html
    ++++ b/docs/html/sdk/support_api_diff/22.2.1/changes/constructors_index_changes.html
    +@@ -47,7 +47,7 @@ body{overflow:auto;}
    + <div id="indexTableCaption" style="background-color:#eee;padding:0 4px 0 4px;font-size:11px;margin-bottom:1em;">
    + Listed as: <span style="color:#069"><strong>Added</strong></span>,  <span style="color:#069"><strike>Removed</strike></span>,  <span style="color:#069">Changed</span></font>
    + </div>
    +-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    + </script>
    + <script type="text/javascript">
    +   try {
    +diff --git a/docs/html/sdk/support_api_diff/22.2.1/changes/constructors_index_removals.html b/docs/html/sdk/support_api_diff/22.2.1/changes/constructors_index_removals.html
    +index 74a09ba..dadd1cd 100644
    +--- a/docs/html/sdk/support_api_diff/22.2.1/changes/constructors_index_removals.html
    ++++ b/docs/html/sdk/support_api_diff/22.2.1/changes/constructors_index_removals.html
    +@@ -47,7 +47,7 @@ body{overflow:auto;}
    + <div id="indexTableCaption" style="background-color:#eee;padding:0 4px 0 4px;font-size:11px;margin-bottom:1em;">
    + Listed as: <span style="color:#069"><strong>Added</strong></span>,  <span style="color:#069"><strike>Removed</strike></span>,  <span style="color:#069">Changed</span></font>
    + </div>
    +-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    + </script>
    + <script type="text/javascript">
    +   try {
    +diff --git a/docs/html/sdk/support_api_diff/22.2.1/changes/fields_index_additions.html b/docs/html/sdk/support_api_diff/22.2.1/changes/fields_index_additions.html
    +index 2ae5237..5d6411a 100644
    +--- a/docs/html/sdk/support_api_diff/22.2.1/changes/fields_index_additions.html
    ++++ b/docs/html/sdk/support_api_diff/22.2.1/changes/fields_index_additions.html
    +@@ -263,7 +263,7 @@ Listed as: <span style="color:#069"><strong>Added</strong></span>,  <span style=
    + </nobr><br>
    + <nobr><A HREF="android.support.v7.appcompat.R.id.html#android.support.v7.appcompat.R.id.time" class="hiddenlink" target="rightframe">time</A>
    + </nobr><br>
    +-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    + </script>
    + <script type="text/javascript">
    +   try {
    +diff --git a/docs/html/sdk/support_api_diff/22.2.1/changes/fields_index_all.html b/docs/html/sdk/support_api_diff/22.2.1/changes/fields_index_all.html
    +index 4a9194d..85420c3 100644
    +--- a/docs/html/sdk/support_api_diff/22.2.1/changes/fields_index_all.html
    ++++ b/docs/html/sdk/support_api_diff/22.2.1/changes/fields_index_all.html
    +@@ -291,7 +291,7 @@ Listed as: <span style="color:#069"><strong>Added</strong></span>,  <span style=
    + </nobr><br>
    + <nobr><A HREF="android.support.v7.appcompat.R.id.html#android.support.v7.appcompat.R.id.time" class="hiddenlink" target="rightframe">time</A>
    + </nobr><br>
    +-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    + </script>
    + <script type="text/javascript">
    +   try {
    +diff --git a/docs/html/sdk/support_api_diff/22.2.1/changes/fields_index_changes.html b/docs/html/sdk/support_api_diff/22.2.1/changes/fields_index_changes.html
    +index 0e2ccff..301881a 100644
    +--- a/docs/html/sdk/support_api_diff/22.2.1/changes/fields_index_changes.html
    ++++ b/docs/html/sdk/support_api_diff/22.2.1/changes/fields_index_changes.html
    +@@ -47,7 +47,7 @@ body{overflow:auto;}
    + <div id="indexTableCaption" style="background-color:#eee;padding:0 4px 0 4px;font-size:11px;margin-bottom:1em;">
    + Listed as: <span style="color:#069"><strong>Added</strong></span>,  <span style="color:#069"><strike>Removed</strike></span>,  <span style="color:#069">Changed</span></font>
    + </div>
    +-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    + </script>
    + <script type="text/javascript">
    +   try {
    +diff --git a/docs/html/sdk/support_api_diff/22.2.1/changes/fields_index_removals.html b/docs/html/sdk/support_api_diff/22.2.1/changes/fields_index_removals.html
    +index 6245b05..b1bf691 100644
    +--- a/docs/html/sdk/support_api_diff/22.2.1/changes/fields_index_removals.html
    ++++ b/docs/html/sdk/support_api_diff/22.2.1/changes/fields_index_removals.html
    +@@ -55,7 +55,7 @@ Listed as: <span style="color:#069"><strong>Added</strong></span>,  <span style=
    + </nobr><br>
    + <nobr><A HREF="android.support.v7.appcompat.R.style.html#android.support.v7.appcompat.R.style.Platform_V12_AppCompat_Light" class="hiddenlink" target="rightframe"><strike>Platform_V12_AppCompat_Light</strike></A>
    + </nobr><br>
    +-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    + </script>
    + <script type="text/javascript">
    +   try {
    +diff --git a/docs/html/sdk/support_api_diff/22.2.1/changes/jdiff_help.html b/docs/html/sdk/support_api_diff/22.2.1/changes/jdiff_help.html
    +index 25acfbe..f9c1f08 100644
    +--- a/docs/html/sdk/support_api_diff/22.2.1/changes/jdiff_help.html
    ++++ b/docs/html/sdk/support_api_diff/22.2.1/changes/jdiff_help.html
    +@@ -120,7 +120,7 @@ These links show and hide the HTML frames. All pages are available with or witho
    + There are some complex changes which can occur between versions, for example, when two or more methods with the same name change simultaneously, or when a method or field is moved into or from a superclass. 
    + In these cases, the change will be seen as a removal and an addition, rather than as a change. Unexpected removals or additions are often part of one of these type of changes. 
    + </BLOCKQUOTE>
    +-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    + </script>
    + <script type="text/javascript">
    +   try {
    +diff --git a/docs/html/sdk/support_api_diff/22.2.1/changes/jdiff_statistics.html b/docs/html/sdk/support_api_diff/22.2.1/changes/jdiff_statistics.html
    +index 0f4805f..322ad44 100644
    +--- a/docs/html/sdk/support_api_diff/22.2.1/changes/jdiff_statistics.html
    ++++ b/docs/html/sdk/support_api_diff/22.2.1/changes/jdiff_statistics.html
    +@@ -368,7 +368,7 @@ added, the change will be 100%.</p>
    +     </div> <!-- end footer -->
    +     </div><!-- end doc-content -->
    +     </div> <!-- end body-content --> 
    +-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    + </script>
    + <script type="text/javascript">
    +   try {
    +diff --git a/docs/html/sdk/support_api_diff/22.2.1/changes/jdiff_topleftframe.html b/docs/html/sdk/support_api_diff/22.2.1/changes/jdiff_topleftframe.html
    +index 36f9836..6a2e76e 100644
    +--- a/docs/html/sdk/support_api_diff/22.2.1/changes/jdiff_topleftframe.html
    ++++ b/docs/html/sdk/support_api_diff/22.2.1/changes/jdiff_topleftframe.html
    +@@ -49,7 +49,7 @@ body{overflow:auto;}
    +   <TD NOWRAP><FONT CLASS="indexText" size="-2"><A HREF="fields_index_all.html" TARGET="bottomleftframe">By Field</A></FONT><br></TD>
    + </TR>
    + </TABLE>
    +-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    + </script>
    + <script type="text/javascript">
    +   try {
    +diff --git a/docs/html/sdk/support_api_diff/22.2.1/changes/methods_index_additions.html b/docs/html/sdk/support_api_diff/22.2.1/changes/methods_index_additions.html
    +index 33a155f..5a237de 100644
    +--- a/docs/html/sdk/support_api_diff/22.2.1/changes/methods_index_additions.html
    ++++ b/docs/html/sdk/support_api_diff/22.2.1/changes/methods_index_additions.html
    +@@ -224,7 +224,7 @@ Listed as: <span style="color:#069"><strong>Added</strong></span>,  <span style=
    + </A></nobr><br>
    + <nobr><A HREF="android.support.v17.leanback.widget.ShadowOverlayContainer.html#android.support.v17.leanback.widget.ShadowOverlayContainer.useStaticShadow_added()" class="hiddenlink" target="rightframe"><b>useStaticShadow</b>
    + ()</A></nobr><br>
    +-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    + </script>
    + <script type="text/javascript">
    +   try {
    +diff --git a/docs/html/sdk/support_api_diff/22.2.1/changes/methods_index_all.html b/docs/html/sdk/support_api_diff/22.2.1/changes/methods_index_all.html
    +index b9cf858..014ef9a 100644
    +--- a/docs/html/sdk/support_api_diff/22.2.1/changes/methods_index_all.html
    ++++ b/docs/html/sdk/support_api_diff/22.2.1/changes/methods_index_all.html
    +@@ -256,7 +256,7 @@ Listed as: <span style="color:#069"><strong>Added</strong></span>,  <span style=
    + </A></nobr><br>
    + <nobr><A HREF="android.support.v17.leanback.widget.ShadowOverlayContainer.html#android.support.v17.leanback.widget.ShadowOverlayContainer.useStaticShadow_added()" class="hiddenlink" target="rightframe"><b>useStaticShadow</b>
    + ()</A></nobr><br>
    +-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    + </script>
    + <script type="text/javascript">
    +   try {
    +diff --git a/docs/html/sdk/support_api_diff/22.2.1/changes/methods_index_changes.html b/docs/html/sdk/support_api_diff/22.2.1/changes/methods_index_changes.html
    +index 4e2d329..6b02e2a 100644
    +--- a/docs/html/sdk/support_api_diff/22.2.1/changes/methods_index_changes.html
    ++++ b/docs/html/sdk/support_api_diff/22.2.1/changes/methods_index_changes.html
    +@@ -89,7 +89,7 @@ Listed as: <span style="color:#069"><strong>Added</strong></span>,  <span style=
    + &nbsp;&nbsp;<nobr><A HREF="android.support.v17.leanback.widget.VerticalGridPresenter.html#android.support.v17.leanback.widget.VerticalGridPresenter.isUsingZOrder_changed(android.content.Context)" class="hiddenlink" target="rightframe">type&nbsp;
    + (<code>Context</code>)&nbsp;in&nbsp;android.support.v17.leanback.widget.VerticalGridPresenter
    + </A></nobr><br>
    +-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    + </script>
    + <script type="text/javascript">
    +   try {
    +diff --git a/docs/html/sdk/support_api_diff/22.2.1/changes/methods_index_removals.html b/docs/html/sdk/support_api_diff/22.2.1/changes/methods_index_removals.html
    +index b5aea4f..e85e6fc 100644
    +--- a/docs/html/sdk/support_api_diff/22.2.1/changes/methods_index_removals.html
    ++++ b/docs/html/sdk/support_api_diff/22.2.1/changes/methods_index_removals.html
    +@@ -47,7 +47,7 @@ body{overflow:auto;}
    + <div id="indexTableCaption" style="background-color:#eee;padding:0 4px 0 4px;font-size:11px;margin-bottom:1em;">
    + Listed as: <span style="color:#069"><strong>Added</strong></span>,  <span style="color:#069"><strike>Removed</strike></span>,  <span style="color:#069">Changed</span></font>
    + </div>
    +-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    + </script>
    + <script type="text/javascript">
    +   try {
    +diff --git a/docs/html/sdk/support_api_diff/22.2.1/changes/packages_index_additions.html b/docs/html/sdk/support_api_diff/22.2.1/changes/packages_index_additions.html
    +index 6311752..d08c85c 100644
    +--- a/docs/html/sdk/support_api_diff/22.2.1/changes/packages_index_additions.html
    ++++ b/docs/html/sdk/support_api_diff/22.2.1/changes/packages_index_additions.html
    +@@ -51,7 +51,7 @@ Listed as: <span style="color:#069"><strong>Added</strong></span>,  <span style=
    + <div id="indexTableEntries">
    + <A NAME="A"></A>
    + <A HREF="changes-summary.html#android.support.v17.leanback.system" class="hiddenlink" target="rightframe"><b>android.support.v17.leanback.system</b></A><br>
    +-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    + </script>
    + <script type="text/javascript">
    +   try {
    +diff --git a/docs/html/sdk/support_api_diff/22.2.1/changes/packages_index_all.html b/docs/html/sdk/support_api_diff/22.2.1/changes/packages_index_all.html
    +index 3f5ee13..712eac9 100644
    +--- a/docs/html/sdk/support_api_diff/22.2.1/changes/packages_index_all.html
    ++++ b/docs/html/sdk/support_api_diff/22.2.1/changes/packages_index_all.html
    +@@ -58,7 +58,7 @@ Listed as: <span style="color:#069"><strong>Added</strong></span>,  <span style=
    + <A HREF="pkg_android.support.v7.app.html" class="hiddenlink" target="rightframe">android.support.v7.app</A><br>
    + <A HREF="pkg_android.support.v7.appcompat.html" class="hiddenlink" target="rightframe">android.support.v7.appcompat</A><br>
    + <A HREF="pkg_android.support.v7.util.html" class="hiddenlink" target="rightframe">android.support.v7.util</A><br>
    +-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    + </script>
    + <script type="text/javascript">
    +   try {
    +diff --git a/docs/html/sdk/support_api_diff/22.2.1/changes/packages_index_changes.html b/docs/html/sdk/support_api_diff/22.2.1/changes/packages_index_changes.html
    +index a4637a7..e53ee87 100644
    +--- a/docs/html/sdk/support_api_diff/22.2.1/changes/packages_index_changes.html
    ++++ b/docs/html/sdk/support_api_diff/22.2.1/changes/packages_index_changes.html
    +@@ -57,7 +57,7 @@ Listed as: <span style="color:#069"><strong>Added</strong></span>,  <span style=
    + <A HREF="pkg_android.support.v7.app.html" class="hiddenlink" target="rightframe">android.support.v7.app</A><br>
    + <A HREF="pkg_android.support.v7.appcompat.html" class="hiddenlink" target="rightframe">android.support.v7.appcompat</A><br>
    + <A HREF="pkg_android.support.v7.util.html" class="hiddenlink" target="rightframe">android.support.v7.util</A><br>
    +-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    + </script>
    + <script type="text/javascript">
    +   try {
    +diff --git a/docs/html/sdk/support_api_diff/22.2.1/changes/packages_index_removals.html b/docs/html/sdk/support_api_diff/22.2.1/changes/packages_index_removals.html
    +index d0ffabc..d5a825d 100644
    +--- a/docs/html/sdk/support_api_diff/22.2.1/changes/packages_index_removals.html
    ++++ b/docs/html/sdk/support_api_diff/22.2.1/changes/packages_index_removals.html
    +@@ -49,7 +49,7 @@ Listed as: <span style="color:#069"><strong>Added</strong></span>,  <span style=
    + </div>
    + <br>
    + <div id="indexTableEntries">
    +-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    + </script>
    + <script type="text/javascript">
    +   try {
    +diff --git a/docs/html/sdk/support_api_diff/22.2.1/changes/pkg_android.support.design.widget.html b/docs/html/sdk/support_api_diff/22.2.1/changes/pkg_android.support.design.widget.html
    +index 345f33b..25070ce 100644
    +--- a/docs/html/sdk/support_api_diff/22.2.1/changes/pkg_android.support.design.widget.html
    ++++ b/docs/html/sdk/support_api_diff/22.2.1/changes/pkg_android.support.design.widget.html
    +@@ -140,7 +140,7 @@ Package <A HREF="../../../../reference/android/support/design/widget/package-sum
    +     </div> <!-- end footer -->
    +     </div><!-- end doc-content -->
    +     </div> <!-- end body-content --> 
    +-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    + </script>
    + <script type="text/javascript">
    +   try {
    +diff --git a/docs/html/sdk/support_api_diff/22.2.1/changes/pkg_android.support.v17.leanback.app.html b/docs/html/sdk/support_api_diff/22.2.1/changes/pkg_android.support.v17.leanback.app.html
    +index 873bc6b..48f868b 100644
    +--- a/docs/html/sdk/support_api_diff/22.2.1/changes/pkg_android.support.v17.leanback.app.html
    ++++ b/docs/html/sdk/support_api_diff/22.2.1/changes/pkg_android.support.v17.leanback.app.html
    +@@ -112,7 +112,7 @@ Package <A HREF="../../../../reference/android/support/v17/leanback/app/package-
    +     </div> <!-- end footer -->
    +     </div><!-- end doc-content -->
    +     </div> <!-- end body-content --> 
    +-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    + </script>
    + <script type="text/javascript">
    +   try {
    +diff --git a/docs/html/sdk/support_api_diff/22.2.1/changes/pkg_android.support.v17.leanback.widget.html b/docs/html/sdk/support_api_diff/22.2.1/changes/pkg_android.support.v17.leanback.widget.html
    +index 7197d3a..ac3d843 100644
    +--- a/docs/html/sdk/support_api_diff/22.2.1/changes/pkg_android.support.v17.leanback.widget.html
    ++++ b/docs/html/sdk/support_api_diff/22.2.1/changes/pkg_android.support.v17.leanback.widget.html
    +@@ -324,7 +324,7 @@ Package <A HREF="../../../../reference/android/support/v17/leanback/widget/packa
    +     </div> <!-- end footer -->
    +     </div><!-- end doc-content -->
    +     </div> <!-- end body-content --> 
    +-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    + </script>
    + <script type="text/javascript">
    +   try {
    +diff --git a/docs/html/sdk/support_api_diff/22.2.1/changes/pkg_android.support.v4.app.html b/docs/html/sdk/support_api_diff/22.2.1/changes/pkg_android.support.v4.app.html
    +index 1d15399..3122461 100644
    +--- a/docs/html/sdk/support_api_diff/22.2.1/changes/pkg_android.support.v4.app.html
    ++++ b/docs/html/sdk/support_api_diff/22.2.1/changes/pkg_android.support.v4.app.html
    +@@ -119,7 +119,7 @@ Package <A HREF="../../../../reference/android/support/v4/app/package-summary.ht
    +     </div> <!-- end footer -->
    +     </div><!-- end doc-content -->
    +     </div> <!-- end body-content --> 
    +-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    + </script>
    + <script type="text/javascript">
    +   try {
    +diff --git a/docs/html/sdk/support_api_diff/22.2.1/changes/pkg_android.support.v7.app.html b/docs/html/sdk/support_api_diff/22.2.1/changes/pkg_android.support.v7.app.html
    +index 47c0894..5f69310 100644
    +--- a/docs/html/sdk/support_api_diff/22.2.1/changes/pkg_android.support.v7.app.html
    ++++ b/docs/html/sdk/support_api_diff/22.2.1/changes/pkg_android.support.v7.app.html
    +@@ -119,7 +119,7 @@ Package <A HREF="../../../../reference/android/support/v7/app/package-summary.ht
    +     </div> <!-- end footer -->
    +     </div><!-- end doc-content -->
    +     </div> <!-- end body-content --> 
    +-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    + </script>
    + <script type="text/javascript">
    +   try {
    +diff --git a/docs/html/sdk/support_api_diff/22.2.1/changes/pkg_android.support.v7.appcompat.html b/docs/html/sdk/support_api_diff/22.2.1/changes/pkg_android.support.v7.appcompat.html
    +index 4c562ae..00bcf19 100644
    +--- a/docs/html/sdk/support_api_diff/22.2.1/changes/pkg_android.support.v7.appcompat.html
    ++++ b/docs/html/sdk/support_api_diff/22.2.1/changes/pkg_android.support.v7.appcompat.html
    +@@ -161,7 +161,7 @@ Package <A HREF="../../../../reference/android/support/v7/appcompat/package-summ
    +     </div> <!-- end footer -->
    +     </div><!-- end doc-content -->
    +     </div> <!-- end body-content --> 
    +-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    + </script>
    + <script type="text/javascript">
    +   try {
    +diff --git a/docs/html/sdk/support_api_diff/22.2.1/changes/pkg_android.support.v7.util.html b/docs/html/sdk/support_api_diff/22.2.1/changes/pkg_android.support.v7.util.html
    +index bac0313..e0f4bcd 100644
    +--- a/docs/html/sdk/support_api_diff/22.2.1/changes/pkg_android.support.v7.util.html
    ++++ b/docs/html/sdk/support_api_diff/22.2.1/changes/pkg_android.support.v7.util.html
    +@@ -105,7 +105,7 @@ Package <A HREF="../../../../reference/android/support/v7/util/package-summary.h
    +     </div> <!-- end footer -->
    +     </div><!-- end doc-content -->
    +     </div> <!-- end body-content --> 
    +-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    + </script>
    + <script type="text/javascript">
    +   try {
    +diff --git a/docs/html/sdk/support_api_diff/23.1.0/changes/alldiffs_index_additions.html b/docs/html/sdk/support_api_diff/23.1.0/changes/alldiffs_index_additions.html
    +index 5495f89..1717f7d 100644
    +--- a/docs/html/sdk/support_api_diff/23.1.0/changes/alldiffs_index_additions.html
    ++++ b/docs/html/sdk/support_api_diff/23.1.0/changes/alldiffs_index_additions.html
    +@@ -1104,7 +1104,7 @@ Listed as: <span style="color:#069"><strong>Added</strong></span>,  <span style=
    + <!-- Field Widget_AppCompat_SeekBar -->
    + <nobr><A HREF="android.support.v7.appcompat.R.style.html#android.support.v7.appcompat.R.style.Widget_AppCompat_SeekBar" class="hiddenlink" target="rightframe">Widget_AppCompat_SeekBar</A>
    + </nobr><br>
    +-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    + </script>
    + <script type="text/javascript">
    +   try {
    +diff --git a/docs/html/sdk/support_api_diff/23.1.0/changes/alldiffs_index_all.html b/docs/html/sdk/support_api_diff/23.1.0/changes/alldiffs_index_all.html
    +index 575ee95..d4c30e3 100644
    +--- a/docs/html/sdk/support_api_diff/23.1.0/changes/alldiffs_index_all.html
    ++++ b/docs/html/sdk/support_api_diff/23.1.0/changes/alldiffs_index_all.html
    +@@ -1511,7 +1511,7 @@ Listed as: <span style="color:#069"><strong>Added</strong></span>,  <span style=
    + <!-- Field Widget_AppCompat_SeekBar -->
    + <nobr><A HREF="android.support.v7.appcompat.R.style.html#android.support.v7.appcompat.R.style.Widget_AppCompat_SeekBar" class="hiddenlink" target="rightframe">Widget_AppCompat_SeekBar</A>
    + </nobr><br>
    +-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    + </script>
    + <script type="text/javascript">
    +   try {
    +diff --git a/docs/html/sdk/support_api_diff/23.1.0/changes/alldiffs_index_changes.html b/docs/html/sdk/support_api_diff/23.1.0/changes/alldiffs_index_changes.html
    +index d7ebd36..6562fa8 100644
    +--- a/docs/html/sdk/support_api_diff/23.1.0/changes/alldiffs_index_changes.html
    ++++ b/docs/html/sdk/support_api_diff/23.1.0/changes/alldiffs_index_changes.html
    +@@ -548,7 +548,7 @@ Listed as: <span style="color:#069"><strong>Added</strong></span>,  <span style=
    + <A HREF="android.support.v17.leanback.app.VerticalGridSupportFragment.html" class="hiddenlink" target="rightframe">VerticalGridSupportFragment</A><br>
    + <!-- Class ViewCompat -->
    + <A HREF="android.support.v4.view.ViewCompat.html" class="hiddenlink" target="rightframe">ViewCompat</A><br>
    +-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    + </script>
    + <script type="text/javascript">
    +   try {
    +diff --git a/docs/html/sdk/support_api_diff/23.1.0/changes/alldiffs_index_removals.html b/docs/html/sdk/support_api_diff/23.1.0/changes/alldiffs_index_removals.html
    +index 0d7da0f..9b21b1d 100644
    +--- a/docs/html/sdk/support_api_diff/23.1.0/changes/alldiffs_index_removals.html
    ++++ b/docs/html/sdk/support_api_diff/23.1.0/changes/alldiffs_index_removals.html
    +@@ -270,7 +270,7 @@ Listed as: <span style="color:#069"><strong>Added</strong></span>,  <span style=
    + <p><div style="line-height:1.5em;color:black">
    + <nobr><A HREF="android.support.v17.leanback.app.GuidedStepFragment.html#android.support.v17.leanback.app.GuidedStepFragment.setEntryTransitionEnabled_removed(boolean)" class="hiddenlink" target="rightframe"><strike>setEntryTransitionEnabled</strike>
    + (<code>boolean</code>)</A></nobr><br>
    +-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    + </script>
    + <script type="text/javascript">
    +   try {
    +diff --git a/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.customtabs.CustomTabsCallback.html b/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.customtabs.CustomTabsCallback.html
    +index 0466d5d..6ba5f83 100644
    +--- a/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.customtabs.CustomTabsCallback.html
    ++++ b/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.customtabs.CustomTabsCallback.html
    +@@ -115,7 +115,7 @@ Class android.support.customtabs.<A HREF="../../../../reference/android/support/
    +     </div> <!-- end footer -->
    +     </div><!-- end doc-content -->
    +     </div> <!-- end body-content --> 
    +-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    + </script>
    + <script type="text/javascript">
    +   try {
    +diff --git a/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.customtabs.CustomTabsIntent.Builder.html b/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.customtabs.CustomTabsIntent.Builder.html
    +index e3aefb5..c53722b 100644
    +--- a/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.customtabs.CustomTabsIntent.Builder.html
    ++++ b/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.customtabs.CustomTabsIntent.Builder.html
    +@@ -115,7 +115,7 @@ Class android.support.customtabs.<A HREF="../../../../reference/android/support/
    +     </div> <!-- end footer -->
    +     </div><!-- end doc-content -->
    +     </div> <!-- end body-content --> 
    +-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    + </script>
    + <script type="text/javascript">
    +   try {
    +diff --git a/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.customtabs.CustomTabsIntent.html b/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.customtabs.CustomTabsIntent.html
    +index 9312755..db59258 100644
    +--- a/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.customtabs.CustomTabsIntent.html
    ++++ b/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.customtabs.CustomTabsIntent.html
    +@@ -115,7 +115,7 @@ Class android.support.customtabs.<A HREF="../../../../reference/android/support/
    +     </div> <!-- end footer -->
    +     </div><!-- end doc-content -->
    +     </div> <!-- end body-content --> 
    +-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    + </script>
    + <script type="text/javascript">
    +   try {
    +diff --git a/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.customtabs.CustomTabsService.html b/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.customtabs.CustomTabsService.html
    +index 2a0fd18..fd5a12b 100644
    +--- a/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.customtabs.CustomTabsService.html
    ++++ b/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.customtabs.CustomTabsService.html
    +@@ -108,7 +108,7 @@ Class android.support.customtabs.<A HREF="../../../../reference/android/support/
    +     </div> <!-- end footer -->
    +     </div><!-- end doc-content -->
    +     </div> <!-- end body-content --> 
    +-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    + </script>
    + <script type="text/javascript">
    +   try {
    +diff --git a/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.customtabs.CustomTabsSession.html b/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.customtabs.CustomTabsSession.html
    +index 6b70224..6910bab 100644
    +--- a/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.customtabs.CustomTabsSession.html
    ++++ b/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.customtabs.CustomTabsSession.html
    +@@ -108,7 +108,7 @@ Class android.support.customtabs.<A HREF="../../../../reference/android/support/
    +     </div> <!-- end footer -->
    +     </div><!-- end doc-content -->
    +     </div> <!-- end body-content --> 
    +-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    + </script>
    + <script type="text/javascript">
    +   try {
    +diff --git a/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.customtabs.CustomTabsSessionToken.html b/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.customtabs.CustomTabsSessionToken.html
    +index 2bdb42e..0282d49 100644
    +--- a/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.customtabs.CustomTabsSessionToken.html
    ++++ b/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.customtabs.CustomTabsSessionToken.html
    +@@ -108,7 +108,7 @@ Class android.support.customtabs.<A HREF="../../../../reference/android/support/
    +     </div> <!-- end footer -->
    +     </div><!-- end doc-content -->
    +     </div> <!-- end body-content --> 
    +-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    + </script>
    + <script type="text/javascript">
    +   try {
    +diff --git a/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.design.widget.AppBarLayout.Behavior.SavedState.html b/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.design.widget.AppBarLayout.Behavior.SavedState.html
    +index bb89bbd..cea16c0 100644
    +--- a/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.design.widget.AppBarLayout.Behavior.SavedState.html
    ++++ b/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.design.widget.AppBarLayout.Behavior.SavedState.html
    +@@ -123,7 +123,7 @@ Class android.support.design.widget.<A HREF="../../../../reference/android/suppo
    +     </div> <!-- end footer -->
    +     </div><!-- end doc-content -->
    +     </div> <!-- end body-content --> 
    +-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    + </script>
    + <script type="text/javascript">
    +   try {
    +diff --git a/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.design.widget.AppBarLayout.Behavior.html b/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.design.widget.AppBarLayout.Behavior.html
    +index b538999a..672951d 100644
    +--- a/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.design.widget.AppBarLayout.Behavior.html
    ++++ b/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.design.widget.AppBarLayout.Behavior.html
    +@@ -131,7 +131,7 @@ Class android.support.design.widget.<A HREF="../../../../reference/android/suppo
    +     </div> <!-- end footer -->
    +     </div><!-- end doc-content -->
    +     </div> <!-- end body-content --> 
    +-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    + </script>
    + <script type="text/javascript">
    +   try {
    +diff --git a/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.design.widget.AppBarLayout.LayoutParams.html b/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.design.widget.AppBarLayout.LayoutParams.html
    +index 6d19d36..0218c30 100644
    +--- a/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.design.widget.AppBarLayout.LayoutParams.html
    ++++ b/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.design.widget.AppBarLayout.LayoutParams.html
    +@@ -108,7 +108,7 @@ Class android.support.design.widget.<A HREF="../../../../reference/android/suppo
    +     </div> <!-- end footer -->
    +     </div><!-- end doc-content -->
    +     </div> <!-- end body-content --> 
    +-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    + </script>
    + <script type="text/javascript">
    +   try {
    +diff --git a/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.design.widget.AppBarLayout.ScrollingViewBehavior.html b/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.design.widget.AppBarLayout.ScrollingViewBehavior.html
    +index c089db3..424a618 100644
    +--- a/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.design.widget.AppBarLayout.ScrollingViewBehavior.html
    ++++ b/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.design.widget.AppBarLayout.ScrollingViewBehavior.html
    +@@ -124,7 +124,7 @@ Class android.support.design.widget.<A HREF="../../../../reference/android/suppo
    +     </div> <!-- end footer -->
    +     </div><!-- end doc-content -->
    +     </div> <!-- end body-content --> 
    +-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    + </script>
    + <script type="text/javascript">
    +   try {
    +diff --git a/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.design.widget.CollapsingToolbarLayout.html b/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.design.widget.CollapsingToolbarLayout.html
    +index 49d92737..8e708c0 100644
    +--- a/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.design.widget.CollapsingToolbarLayout.html
    ++++ b/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.design.widget.CollapsingToolbarLayout.html
    +@@ -143,7 +143,7 @@ Class android.support.design.widget.<A HREF="../../../../reference/android/suppo
    +     </div> <!-- end footer -->
    +     </div><!-- end doc-content -->
    +     </div> <!-- end body-content --> 
    +-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    + </script>
    + <script type="text/javascript">
    +   try {
    +diff --git a/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.design.widget.CoordinatorLayout.SavedState.html b/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.design.widget.CoordinatorLayout.SavedState.html
    +index f92babd..496a460 100644
    +--- a/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.design.widget.CoordinatorLayout.SavedState.html
    ++++ b/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.design.widget.CoordinatorLayout.SavedState.html
    +@@ -123,7 +123,7 @@ Class android.support.design.widget.<A HREF="../../../../reference/android/suppo
    +     </div> <!-- end footer -->
    +     </div><!-- end doc-content -->
    +     </div> <!-- end body-content --> 
    +-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    + </script>
    + <script type="text/javascript">
    +   try {
    +diff --git a/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.design.widget.FloatingActionButton.Behavior.html b/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.design.widget.FloatingActionButton.Behavior.html
    +index 07fdda1..eba4247 100644
    +--- a/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.design.widget.FloatingActionButton.Behavior.html
    ++++ b/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.design.widget.FloatingActionButton.Behavior.html
    +@@ -108,7 +108,7 @@ Class android.support.design.widget.<A HREF="../../../../reference/android/suppo
    +     </div> <!-- end footer -->
    +     </div><!-- end doc-content -->
    +     </div> <!-- end body-content --> 
    +-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    + </script>
    + <script type="text/javascript">
    +   try {
    +diff --git a/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.design.widget.FloatingActionButton.html b/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.design.widget.FloatingActionButton.html
    +index 90553fa..520fdcf 100644
    +--- a/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.design.widget.FloatingActionButton.html
    ++++ b/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.design.widget.FloatingActionButton.html
    +@@ -116,7 +116,7 @@ Class android.support.design.widget.<A HREF="../../../../reference/android/suppo
    +     </div> <!-- end footer -->
    +     </div><!-- end doc-content -->
    +     </div> <!-- end body-content --> 
    +-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    + </script>
    + <script type="text/javascript">
    +   try {
    +diff --git a/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.design.widget.NavigationView.SavedState.html b/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.design.widget.NavigationView.SavedState.html
    +index 8a9ae80..61428ca 100644
    +--- a/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.design.widget.NavigationView.SavedState.html
    ++++ b/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.design.widget.NavigationView.SavedState.html
    +@@ -123,7 +123,7 @@ Class android.support.design.widget.<A HREF="../../../../reference/android/suppo
    +     </div> <!-- end footer -->
    +     </div><!-- end doc-content -->
    +     </div> <!-- end body-content --> 
    +-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    + </script>
    + <script type="text/javascript">
    +   try {
    +diff --git a/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.design.widget.Snackbar.html b/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.design.widget.Snackbar.html
    +index d741863..f33e47a 100644
    +--- a/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.design.widget.Snackbar.html
    ++++ b/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.design.widget.Snackbar.html
    +@@ -108,7 +108,7 @@ Class android.support.design.widget.<A HREF="../../../../reference/android/suppo
    +     </div> <!-- end footer -->
    +     </div><!-- end doc-content -->
    +     </div> <!-- end body-content --> 
    +-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    + </script>
    + <script type="text/javascript">
    +   try {
    +diff --git a/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.design.widget.TextInputLayout.html b/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.design.widget.TextInputLayout.html
    +index 30d0dd6..609e864 100644
    +--- a/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.design.widget.TextInputLayout.html
    ++++ b/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.design.widget.TextInputLayout.html
    +@@ -129,7 +129,7 @@ Class android.support.design.widget.<A HREF="../../../../reference/android/suppo
    +     </div> <!-- end footer -->
    +     </div><!-- end doc-content -->
    +     </div> <!-- end body-content --> 
    +-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    + </script>
    + <script type="text/javascript">
    +   try {
    +diff --git a/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.percent.PercentLayoutHelper.PercentLayoutInfo.html b/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.percent.PercentLayoutHelper.PercentLayoutInfo.html
    +index b6f2e48..967542f 100644
    +--- a/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.percent.PercentLayoutHelper.PercentLayoutInfo.html
    ++++ b/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.percent.PercentLayoutHelper.PercentLayoutInfo.html
    +@@ -108,7 +108,7 @@ Class android.support.percent.<A HREF="../../../../reference/android/support/per
    +     </div> <!-- end footer -->
    +     </div><!-- end doc-content -->
    +     </div> <!-- end body-content --> 
    +-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    + </script>
    + <script type="text/javascript">
    +   try {
    +diff --git a/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v14.preference.EditTextPreferenceDialogFragment.html b/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v14.preference.EditTextPreferenceDialogFragment.html
    +index 30f22a8..6b6151b 100644
    +--- a/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v14.preference.EditTextPreferenceDialogFragment.html
    ++++ b/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v14.preference.EditTextPreferenceDialogFragment.html
    +@@ -108,7 +108,7 @@ Class android.support.v14.preference.<A HREF="../../../../reference/android/supp
    +     </div> <!-- end footer -->
    +     </div><!-- end doc-content -->
    +     </div> <!-- end body-content --> 
    +-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    + </script>
    + <script type="text/javascript">
    +   try {
    +diff --git a/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v17.leanback.app.BrowseFragment.html b/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v17.leanback.app.BrowseFragment.html
    +index f4d77bf..14f6fdf 100644
    +--- a/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v17.leanback.app.BrowseFragment.html
    ++++ b/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v17.leanback.app.BrowseFragment.html
    +@@ -150,7 +150,7 @@ Class android.support.v17.leanback.app.<A HREF="../../../../reference/android/su
    +     </div> <!-- end footer -->
    +     </div><!-- end doc-content -->
    +     </div> <!-- end body-content --> 
    +-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    + </script>
    + <script type="text/javascript">
    +   try {
    +diff --git a/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v17.leanback.app.BrowseSupportFragment.html b/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v17.leanback.app.BrowseSupportFragment.html
    +index a48ea3b..7adcbe8 100644
    +--- a/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v17.leanback.app.BrowseSupportFragment.html
    ++++ b/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v17.leanback.app.BrowseSupportFragment.html
    +@@ -150,7 +150,7 @@ Class android.support.v17.leanback.app.<A HREF="../../../../reference/android/su
    +     </div> <!-- end footer -->
    +     </div><!-- end doc-content -->
    +     </div> <!-- end body-content --> 
    +-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    + </script>
    + <script type="text/javascript">
    +   try {
    +diff --git a/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v17.leanback.app.DetailsFragment.html b/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v17.leanback.app.DetailsFragment.html
    +index d38127c..2240f4e 100644
    +--- a/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v17.leanback.app.DetailsFragment.html
    ++++ b/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v17.leanback.app.DetailsFragment.html
    +@@ -143,7 +143,7 @@ Class android.support.v17.leanback.app.<A HREF="../../../../reference/android/su
    +     </div> <!-- end footer -->
    +     </div><!-- end doc-content -->
    +     </div> <!-- end body-content --> 
    +-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    + </script>
    + <script type="text/javascript">
    +   try {
    +diff --git a/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v17.leanback.app.DetailsSupportFragment.html b/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v17.leanback.app.DetailsSupportFragment.html
    +index a02b8f3..23ca151 100644
    +--- a/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v17.leanback.app.DetailsSupportFragment.html
    ++++ b/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v17.leanback.app.DetailsSupportFragment.html
    +@@ -143,7 +143,7 @@ Class android.support.v17.leanback.app.<A HREF="../../../../reference/android/su
    +     </div> <!-- end footer -->
    +     </div><!-- end doc-content -->
    +     </div> <!-- end body-content --> 
    +-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    + </script>
    + <script type="text/javascript">
    +   try {
    +diff --git a/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v17.leanback.app.GuidedStepFragment.html b/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v17.leanback.app.GuidedStepFragment.html
    +index 725281a..4c78b30 100644
    +--- a/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v17.leanback.app.GuidedStepFragment.html
    ++++ b/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v17.leanback.app.GuidedStepFragment.html
    +@@ -215,7 +215,7 @@ Class android.support.v17.leanback.app.<A HREF="../../../../reference/android/su
    +     </div> <!-- end footer -->
    +     </div><!-- end doc-content -->
    +     </div> <!-- end body-content --> 
    +-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    + </script>
    + <script type="text/javascript">
    +   try {
    +diff --git a/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v17.leanback.app.PlaybackOverlayFragment.html b/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v17.leanback.app.PlaybackOverlayFragment.html
    +index 71e230b..ecb35be 100644
    +--- a/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v17.leanback.app.PlaybackOverlayFragment.html
    ++++ b/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v17.leanback.app.PlaybackOverlayFragment.html
    +@@ -115,7 +115,7 @@ Class android.support.v17.leanback.app.<A HREF="../../../../reference/android/su
    +     </div> <!-- end footer -->
    +     </div><!-- end doc-content -->
    +     </div> <!-- end body-content --> 
    +-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    + </script>
    + <script type="text/javascript">
    +   try {
    +diff --git a/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v17.leanback.app.PlaybackOverlaySupportFragment.html b/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v17.leanback.app.PlaybackOverlaySupportFragment.html
    +index a794f14..1809374 100644
    +--- a/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v17.leanback.app.PlaybackOverlaySupportFragment.html
    ++++ b/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v17.leanback.app.PlaybackOverlaySupportFragment.html
    +@@ -115,7 +115,7 @@ Class android.support.v17.leanback.app.<A HREF="../../../../reference/android/su
    +     </div> <!-- end footer -->
    +     </div><!-- end doc-content -->
    +     </div> <!-- end body-content --> 
    +-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    + </script>
    + <script type="text/javascript">
    +   try {
    +diff --git a/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v17.leanback.app.SearchFragment.html b/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v17.leanback.app.SearchFragment.html
    +index 827f46b..2c444ae 100644
    +--- a/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v17.leanback.app.SearchFragment.html
    ++++ b/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v17.leanback.app.SearchFragment.html
    +@@ -108,7 +108,7 @@ Class android.support.v17.leanback.app.<A HREF="../../../../reference/android/su
    +     </div> <!-- end footer -->
    +     </div><!-- end doc-content -->
    +     </div> <!-- end body-content --> 
    +-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    + </script>
    + <script type="text/javascript">
    +   try {
    +diff --git a/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v17.leanback.app.SearchSupportFragment.html b/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v17.leanback.app.SearchSupportFragment.html
    +index f1e2826..7ff0204 100644
    +--- a/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v17.leanback.app.SearchSupportFragment.html
    ++++ b/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v17.leanback.app.SearchSupportFragment.html
    +@@ -108,7 +108,7 @@ Class android.support.v17.leanback.app.<A HREF="../../../../reference/android/su
    +     </div> <!-- end footer -->
    +     </div><!-- end doc-content -->
    +     </div> <!-- end body-content --> 
    +-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    + </script>
    + <script type="text/javascript">
    +   try {
    +diff --git a/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v17.leanback.app.VerticalGridFragment.html b/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v17.leanback.app.VerticalGridFragment.html
    +index 01bb4de..5516bda 100644
    +--- a/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v17.leanback.app.VerticalGridFragment.html
    ++++ b/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v17.leanback.app.VerticalGridFragment.html
    +@@ -137,7 +137,7 @@ Class android.support.v17.leanback.app.<A HREF="../../../../reference/android/su
    +     </div> <!-- end footer -->
    +     </div><!-- end doc-content -->
    +     </div> <!-- end body-content --> 
    +-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    + </script>
    + <script type="text/javascript">
    +   try {
    +diff --git a/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v17.leanback.app.VerticalGridSupportFragment.html b/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v17.leanback.app.VerticalGridSupportFragment.html
    +index a818a79..0f09ec0 100644
    +--- a/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v17.leanback.app.VerticalGridSupportFragment.html
    ++++ b/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v17.leanback.app.VerticalGridSupportFragment.html
    +@@ -154,7 +154,7 @@ Method was inherited from <code>android.support.v4.app.Fragment</code>, but is n
    +     </div> <!-- end footer -->
    +     </div><!-- end doc-content -->
    +     </div> <!-- end body-content --> 
    +-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    + </script>
    + <script type="text/javascript">
    +   try {
    +diff --git a/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v17.leanback.widget.FragmentAnimationProvider.html b/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v17.leanback.widget.FragmentAnimationProvider.html
    +index 1cf004d..e457402 100644
    +--- a/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v17.leanback.widget.FragmentAnimationProvider.html
    ++++ b/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v17.leanback.widget.FragmentAnimationProvider.html
    +@@ -165,7 +165,7 @@ Interface android.support.v17.leanback.widget.<A HREF="../../../../reference/and
    +     </div> <!-- end footer -->
    +     </div><!-- end doc-content -->
    +     </div> <!-- end body-content --> 
    +-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    + </script>
    + <script type="text/javascript">
    +   try {
    +diff --git a/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v17.leanback.widget.GuidanceStylist.html b/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v17.leanback.widget.GuidanceStylist.html
    +index e0b94bc..9794929 100644
    +--- a/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v17.leanback.widget.GuidanceStylist.html
    ++++ b/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v17.leanback.widget.GuidanceStylist.html
    +@@ -165,7 +165,7 @@ Class android.support.v17.leanback.widget.<A HREF="../../../../reference/android
    +     </div> <!-- end footer -->
    +     </div><!-- end doc-content -->
    +     </div> <!-- end body-content --> 
    +-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    + </script>
    + <script type="text/javascript">
    +   try {
    +diff --git a/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v17.leanback.widget.GuidedAction.Builder.html b/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v17.leanback.widget.GuidedAction.Builder.html
    +index 96d30a4..3408bd9 100644
    +--- a/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v17.leanback.widget.GuidedAction.Builder.html
    ++++ b/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v17.leanback.widget.GuidedAction.Builder.html
    +@@ -115,7 +115,7 @@ Class android.support.v17.leanback.widget.<A HREF="../../../../reference/android
    +     </div> <!-- end footer -->
    +     </div><!-- end doc-content -->
    +     </div> <!-- end body-content --> 
    +-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    + </script>
    + <script type="text/javascript">
    +   try {
    +diff --git a/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v17.leanback.widget.GuidedAction.html b/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v17.leanback.widget.GuidedAction.html
    +index 84b93bf..857b7d8 100644
    +--- a/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v17.leanback.widget.GuidedAction.html
    ++++ b/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v17.leanback.widget.GuidedAction.html
    +@@ -143,7 +143,7 @@ Class android.support.v17.leanback.widget.<A HREF="../../../../reference/android
    +     </div> <!-- end footer -->
    +     </div><!-- end doc-content -->
    +     </div> <!-- end body-content --> 
    +-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    + </script>
    + <script type="text/javascript">
    +   try {
    +diff --git a/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v17.leanback.widget.GuidedActionsStylist.ViewHolder.html b/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v17.leanback.widget.GuidedActionsStylist.ViewHolder.html
    +index 38e83b4..497e985 100644
    +--- a/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v17.leanback.widget.GuidedActionsStylist.ViewHolder.html
    ++++ b/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v17.leanback.widget.GuidedActionsStylist.ViewHolder.html
    +@@ -108,7 +108,7 @@ Class android.support.v17.leanback.widget.<A HREF="../../../../reference/android
    +     </div> <!-- end footer -->
    +     </div><!-- end doc-content -->
    +     </div> <!-- end body-content --> 
    +-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    + </script>
    + <script type="text/javascript">
    +   try {
    +diff --git a/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v17.leanback.widget.GuidedActionsStylist.html b/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v17.leanback.widget.GuidedActionsStylist.html
    +index 104f325..cd45d6d 100644
    +--- a/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v17.leanback.widget.GuidedActionsStylist.html
    ++++ b/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v17.leanback.widget.GuidedActionsStylist.html
    +@@ -165,7 +165,7 @@ Class android.support.v17.leanback.widget.<A HREF="../../../../reference/android
    +     </div> <!-- end footer -->
    +     </div><!-- end doc-content -->
    +     </div> <!-- end body-content --> 
    +-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    + </script>
    + <script type="text/javascript">
    +   try {
    +diff --git a/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v17.leanback.widget.ImageCardView.html b/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v17.leanback.widget.ImageCardView.html
    +index 1535ca0..a5aa07e 100644
    +--- a/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v17.leanback.widget.ImageCardView.html
    ++++ b/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v17.leanback.widget.ImageCardView.html
    +@@ -151,7 +151,7 @@ Class android.support.v17.leanback.widget.<A HREF="../../../../reference/android
    +     </div> <!-- end footer -->
    +     </div><!-- end doc-content -->
    +     </div> <!-- end body-content --> 
    +-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    + </script>
    + <script type="text/javascript">
    +   try {
    +diff --git a/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v17.leanback.widget.ListRowPresenter.html b/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v17.leanback.widget.ListRowPresenter.html
    +index f536d92..11b95c4 100644
    +--- a/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v17.leanback.widget.ListRowPresenter.html
    ++++ b/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v17.leanback.widget.ListRowPresenter.html
    +@@ -122,7 +122,7 @@ Class android.support.v17.leanback.widget.<A HREF="../../../../reference/android
    +     </div> <!-- end footer -->
    +     </div><!-- end doc-content -->
    +     </div> <!-- end body-content --> 
    +-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    + </script>
    + <script type="text/javascript">
    +   try {
    +diff --git a/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v17.leanback.widget.RowPresenter.html b/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v17.leanback.widget.RowPresenter.html
    +index 3f10b29..0f254d7 100644
    +--- a/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v17.leanback.widget.RowPresenter.html
    ++++ b/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v17.leanback.widget.RowPresenter.html
    +@@ -108,7 +108,7 @@ Class android.support.v17.leanback.widget.<A HREF="../../../../reference/android
    +     </div> <!-- end footer -->
    +     </div><!-- end doc-content -->
    +     </div> <!-- end body-content --> 
    +-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    + </script>
    + <script type="text/javascript">
    +   try {
    +diff --git a/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v17.leanback.widget.SearchBar.html b/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v17.leanback.widget.SearchBar.html
    +index 2965c15..6e4b41c 100644
    +--- a/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v17.leanback.widget.SearchBar.html
    ++++ b/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v17.leanback.widget.SearchBar.html
    +@@ -108,7 +108,7 @@ Class android.support.v17.leanback.widget.<A HREF="../../../../reference/android
    +     </div> <!-- end footer -->
    +     </div><!-- end doc-content -->
    +     </div> <!-- end body-content --> 
    +-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    + </script>
    + <script type="text/javascript">
    +   try {
    +diff --git a/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v17.leanback.widget.ShadowOverlayContainer.html b/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v17.leanback.widget.ShadowOverlayContainer.html
    +index 761fd92..553bbb1 100644
    +--- a/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v17.leanback.widget.ShadowOverlayContainer.html
    ++++ b/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v17.leanback.widget.ShadowOverlayContainer.html
    +@@ -127,7 +127,7 @@ Class android.support.v17.leanback.widget.<A HREF="../../../../reference/android
    +     </div> <!-- end footer -->
    +     </div><!-- end doc-content -->
    +     </div> <!-- end body-content --> 
    +-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    + </script>
    + <script type="text/javascript">
    +   try {
    +diff --git a/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v17.leanback.widget.VerticalGridPresenter.html b/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v17.leanback.widget.VerticalGridPresenter.html
    +index e999838..f1d6fb6 100644
    +--- a/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v17.leanback.widget.VerticalGridPresenter.html
    ++++ b/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v17.leanback.widget.VerticalGridPresenter.html
    +@@ -129,7 +129,7 @@ Class android.support.v17.leanback.widget.<A HREF="../../../../reference/android
    +     </div> <!-- end footer -->
    +     </div><!-- end doc-content -->
    +     </div> <!-- end body-content --> 
    +-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    + </script>
    + <script type="text/javascript">
    +   try {
    +diff --git a/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v4.app.FragmentActivity.html b/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v4.app.FragmentActivity.html
    +index c68356c..dd88aca 100644
    +--- a/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v4.app.FragmentActivity.html
    ++++ b/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v4.app.FragmentActivity.html
    +@@ -115,7 +115,7 @@ Class android.support.v4.app.<A HREF="../../../../reference/android/support/v4/a
    +     </div> <!-- end footer -->
    +     </div><!-- end doc-content -->
    +     </div> <!-- end body-content --> 
    +-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    + </script>
    + <script type="text/javascript">
    +   try {
    +diff --git a/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v4.content.res.ResourcesCompat.html b/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v4.content.res.ResourcesCompat.html
    +index 9bdd4f7..bb339da 100644
    +--- a/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v4.content.res.ResourcesCompat.html
    ++++ b/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v4.content.res.ResourcesCompat.html
    +@@ -115,7 +115,7 @@ Class android.support.v4.content.res.<A HREF="../../../../reference/android/supp
    +     </div> <!-- end footer -->
    +     </div><!-- end doc-content -->
    +     </div> <!-- end body-content --> 
    +-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    + </script>
    + <script type="text/javascript">
    +   try {
    +diff --git a/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v4.media.session.MediaSessionCompat.html b/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v4.media.session.MediaSessionCompat.html
    +index 5b5f1e3..278f42d 100644
    +--- a/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v4.media.session.MediaSessionCompat.html
    ++++ b/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v4.media.session.MediaSessionCompat.html
    +@@ -108,7 +108,7 @@ Class android.support.v4.media.session.<A HREF="../../../../reference/android/su
    +     </div> <!-- end footer -->
    +     </div><!-- end doc-content -->
    +     </div> <!-- end body-content --> 
    +-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    + </script>
    + <script type="text/javascript">
    +   try {
    +diff --git a/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v4.view.ViewCompat.html b/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v4.view.ViewCompat.html
    +index 2e39745..03dda58 100644
    +--- a/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v4.view.ViewCompat.html
    ++++ b/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v4.view.ViewCompat.html
    +@@ -179,7 +179,7 @@ Class android.support.v4.view.<A HREF="../../../../reference/android/support/v4/
    +     </div> <!-- end footer -->
    +     </div><!-- end doc-content -->
    +     </div> <!-- end body-content --> 
    +-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    + </script>
    + <script type="text/javascript">
    +   try {
    +diff --git a/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v4.widget.NestedScrollView.html b/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v4.widget.NestedScrollView.html
    +index 8d4cbaa..cdb3d13 100644
    +--- a/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v4.widget.NestedScrollView.html
    ++++ b/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v4.widget.NestedScrollView.html
    +@@ -109,7 +109,7 @@ Class android.support.v4.widget.<A HREF="../../../../reference/android/support/v
    +     </div> <!-- end footer -->
    +     </div><!-- end doc-content -->
    +     </div> <!-- end body-content --> 
    +-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    + </script>
    + <script type="text/javascript">
    +   try {
    +diff --git a/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v4.widget.ScrollerCompat.html b/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v4.widget.ScrollerCompat.html
    +index 7f47eae..9ef847e 100644
    +--- a/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v4.widget.ScrollerCompat.html
    ++++ b/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v4.widget.ScrollerCompat.html
    +@@ -108,7 +108,7 @@ Class android.support.v4.widget.<A HREF="../../../../reference/android/support/v
    +     </div> <!-- end footer -->
    +     </div><!-- end doc-content -->
    +     </div> <!-- end body-content --> 
    +-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    + </script>
    + <script type="text/javascript">
    +   try {
    +diff --git a/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v4.widget.TextViewCompat.html b/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v4.widget.TextViewCompat.html
    +index 3641625..87b1da2 100644
    +--- a/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v4.widget.TextViewCompat.html
    ++++ b/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v4.widget.TextViewCompat.html
    +@@ -115,7 +115,7 @@ Class android.support.v4.widget.<A HREF="../../../../reference/android/support/v
    +     </div> <!-- end footer -->
    +     </div><!-- end doc-content -->
    +     </div> <!-- end body-content --> 
    +-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    + </script>
    + <script type="text/javascript">
    +   try {
    +diff --git a/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v7.appcompat.R.attr.html b/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v7.appcompat.R.attr.html
    +index dc6fce2..ef31519 100644
    +--- a/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v7.appcompat.R.attr.html
    ++++ b/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v7.appcompat.R.attr.html
    +@@ -122,7 +122,7 @@ Class android.support.v7.appcompat.<A HREF="../../../../reference/android/suppor
    +     </div> <!-- end footer -->
    +     </div><!-- end doc-content -->
    +     </div> <!-- end body-content --> 
    +-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    + </script>
    + <script type="text/javascript">
    +   try {
    +diff --git a/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v7.appcompat.R.bool.html b/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v7.appcompat.R.bool.html
    +index 973cf83..c26367a 100644
    +--- a/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v7.appcompat.R.bool.html
    ++++ b/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v7.appcompat.R.bool.html
    +@@ -108,7 +108,7 @@ Class android.support.v7.appcompat.<A HREF="../../../../reference/android/suppor
    +     </div> <!-- end footer -->
    +     </div><!-- end doc-content -->
    +     </div> <!-- end body-content --> 
    +-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    + </script>
    + <script type="text/javascript">
    +   try {
    +diff --git a/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v7.appcompat.R.dimen.html b/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v7.appcompat.R.dimen.html
    +index ca5fec2..bd324cb 100644
    +--- a/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v7.appcompat.R.dimen.html
    ++++ b/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v7.appcompat.R.dimen.html
    +@@ -186,7 +186,7 @@ Class android.support.v7.appcompat.<A HREF="../../../../reference/android/suppor
    +     </div> <!-- end footer -->
    +     </div><!-- end doc-content -->
    +     </div> <!-- end body-content --> 
    +-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    + </script>
    + <script type="text/javascript">
    +   try {
    +diff --git a/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v7.appcompat.R.drawable.html b/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v7.appcompat.R.drawable.html
    +index 3cfba65..c9264d6 100644
    +--- a/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v7.appcompat.R.drawable.html
    ++++ b/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v7.appcompat.R.drawable.html
    +@@ -157,7 +157,7 @@ Class android.support.v7.appcompat.<A HREF="../../../../reference/android/suppor
    +     </div> <!-- end footer -->
    +     </div><!-- end doc-content -->
    +     </div> <!-- end body-content --> 
    +-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    + </script>
    + <script type="text/javascript">
    +   try {
    +diff --git a/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v7.appcompat.R.id.html b/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v7.appcompat.R.id.html
    +index a25139d..e7f9f95 100644
    +--- a/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v7.appcompat.R.id.html
    ++++ b/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v7.appcompat.R.id.html
    +@@ -122,7 +122,7 @@ Class android.support.v7.appcompat.<A HREF="../../../../reference/android/suppor
    +     </div> <!-- end footer -->
    +     </div><!-- end doc-content -->
    +     </div> <!-- end body-content --> 
    +-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    + </script>
    + <script type="text/javascript">
    +   try {
    +diff --git a/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v7.appcompat.R.layout.html b/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v7.appcompat.R.layout.html
    +index 0b485ea..c04d4f7 100644
    +--- a/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v7.appcompat.R.layout.html
    ++++ b/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v7.appcompat.R.layout.html
    +@@ -108,7 +108,7 @@ Class android.support.v7.appcompat.<A HREF="../../../../reference/android/suppor
    +     </div> <!-- end footer -->
    +     </div><!-- end doc-content -->
    +     </div> <!-- end body-content --> 
    +-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    + </script>
    + <script type="text/javascript">
    +   try {
    +diff --git a/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v7.appcompat.R.string.html b/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v7.appcompat.R.string.html
    +index b5b32c7..9dc84ab 100644
    +--- a/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v7.appcompat.R.string.html
    ++++ b/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v7.appcompat.R.string.html
    +@@ -115,7 +115,7 @@ Class android.support.v7.appcompat.<A HREF="../../../../reference/android/suppor
    +     </div> <!-- end footer -->
    +     </div><!-- end doc-content -->
    +     </div> <!-- end body-content --> 
    +-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    + </script>
    + <script type="text/javascript">
    +   try {
    +diff --git a/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v7.appcompat.R.style.html b/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v7.appcompat.R.style.html
    +index a7b4e2d..58f9025 100644
    +--- a/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v7.appcompat.R.style.html
    ++++ b/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v7.appcompat.R.style.html
    +@@ -158,7 +158,7 @@ Class android.support.v7.appcompat.<A HREF="../../../../reference/android/suppor
    +     </div> <!-- end footer -->
    +     </div><!-- end doc-content -->
    +     </div> <!-- end body-content --> 
    +-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    + </script>
    + <script type="text/javascript">
    +   try {
    +diff --git a/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v7.appcompat.R.styleable.html b/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v7.appcompat.R.styleable.html
    +index 3f6d157..49adae8 100644
    +--- a/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v7.appcompat.R.styleable.html
    ++++ b/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v7.appcompat.R.styleable.html
    +@@ -150,7 +150,7 @@ Class android.support.v7.appcompat.<A HREF="../../../../reference/android/suppor
    +     </div> <!-- end footer -->
    +     </div><!-- end doc-content -->
    +     </div> <!-- end body-content --> 
    +-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    + </script>
    + <script type="text/javascript">
    +   try {
    +diff --git a/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v7.graphics.Palette.Builder.html b/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v7.graphics.Palette.Builder.html
    +index 03171fb..22ee483 100644
    +--- a/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v7.graphics.Palette.Builder.html
    ++++ b/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v7.graphics.Palette.Builder.html
    +@@ -115,7 +115,7 @@ Class android.support.v7.graphics.<A HREF="../../../../reference/android/support
    +     </div> <!-- end footer -->
    +     </div><!-- end doc-content -->
    +     </div> <!-- end body-content --> 
    +-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    + </script>
    + <script type="text/javascript">
    +   try {
    +diff --git a/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v7.graphics.drawable.DrawerArrowDrawable.html b/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v7.graphics.drawable.DrawerArrowDrawable.html
    +index ec3cb15..77232ba 100644
    +--- a/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v7.graphics.drawable.DrawerArrowDrawable.html
    ++++ b/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v7.graphics.drawable.DrawerArrowDrawable.html
    +@@ -108,7 +108,7 @@ Class android.support.v7.graphics.drawable.<A HREF="../../../../reference/androi
    +     </div> <!-- end footer -->
    +     </div><!-- end doc-content -->
    +     </div> <!-- end body-content --> 
    +-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    + </script>
    + <script type="text/javascript">
    +   try {
    +diff --git a/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v7.media.MediaRouteDescriptor.Builder.html b/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v7.media.MediaRouteDescriptor.Builder.html
    +index aec06c0..5cac372 100644
    +--- a/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v7.media.MediaRouteDescriptor.Builder.html
    ++++ b/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v7.media.MediaRouteDescriptor.Builder.html
    +@@ -154,7 +154,7 @@ Class android.support.v7.media.<A HREF="../../../../reference/android/support/v7
    +     </div> <!-- end footer -->
    +     </div><!-- end doc-content -->
    +     </div> <!-- end body-content --> 
    +-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    + </script>
    + <script type="text/javascript">
    +   try {
    +diff --git a/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v7.media.MediaRouteDescriptor.html b/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v7.media.MediaRouteDescriptor.html
    +index 381eb20..437c56d 100644
    +--- a/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v7.media.MediaRouteDescriptor.html
    ++++ b/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v7.media.MediaRouteDescriptor.html
    +@@ -147,7 +147,7 @@ Class android.support.v7.media.<A HREF="../../../../reference/android/support/v7
    +     </div> <!-- end footer -->
    +     </div><!-- end doc-content -->
    +     </div> <!-- end body-content --> 
    +-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    + </script>
    + <script type="text/javascript">
    +   try {
    +diff --git a/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v7.media.MediaRouter.RouteInfo.html b/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v7.media.MediaRouter.RouteInfo.html
    +index 239341d..51afa4f 100644
    +--- a/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v7.media.MediaRouter.RouteInfo.html
    ++++ b/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v7.media.MediaRouter.RouteInfo.html
    +@@ -166,7 +166,7 @@ Class android.support.v7.media.<A HREF="../../../../reference/android/support/v7
    +     </div> <!-- end footer -->
    +     </div><!-- end doc-content -->
    +     </div> <!-- end body-content --> 
    +-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    + </script>
    + <script type="text/javascript">
    +   try {
    +diff --git a/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v7.preference.EditTextPreferenceDialogFragmentCompat.html b/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v7.preference.EditTextPreferenceDialogFragmentCompat.html
    +index 05b65ff..ac63d53 100644
    +--- a/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v7.preference.EditTextPreferenceDialogFragmentCompat.html
    ++++ b/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v7.preference.EditTextPreferenceDialogFragmentCompat.html
    +@@ -108,7 +108,7 @@ Class android.support.v7.preference.<A HREF="../../../../reference/android/suppo
    +     </div> <!-- end footer -->
    +     </div><!-- end doc-content -->
    +     </div> <!-- end body-content --> 
    +-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    + </script>
    + <script type="text/javascript">
    +   try {
    +diff --git a/docs/html/sdk/support_api_diff/23.1.0/changes/changes-summary.html b/docs/html/sdk/support_api_diff/23.1.0/changes/changes-summary.html
    +index 728ade1..d9658ba 100644
    +--- a/docs/html/sdk/support_api_diff/23.1.0/changes/changes-summary.html
    ++++ b/docs/html/sdk/support_api_diff/23.1.0/changes/changes-summary.html
    +@@ -232,7 +232,7 @@ see the <a href="http://developer.android.com/index.html" target="_top">Android
    +     </div> <!-- end footer -->
    +     </div><!-- end doc-content -->
    +     </div> <!-- end body-content --> 
    +-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    + </script>
    + <script type="text/javascript">
    +   try {
    +diff --git a/docs/html/sdk/support_api_diff/23.1.0/changes/classes_index_additions.html b/docs/html/sdk/support_api_diff/23.1.0/changes/classes_index_additions.html
    +index c0022c9..1a97c98 100644
    +--- a/docs/html/sdk/support_api_diff/23.1.0/changes/classes_index_additions.html
    ++++ b/docs/html/sdk/support_api_diff/23.1.0/changes/classes_index_additions.html
    +@@ -197,7 +197,7 @@ Listed as: <span style="color:#069"><strong>Added</strong></span>,  <span style=
    + <A HREF="pkg_android.support.v17.leanback.widget.html#ShadowOverlayHelper" class="hiddenlink" target="rightframe"><b>ShadowOverlayHelper</b></A><br>
    + <A HREF="pkg_android.support.v17.leanback.widget.html#ShadowOverlayHelper.Builder" class="hiddenlink" target="rightframe"><b>ShadowOverlayHelper.Builder</b></A><br>
    + <A HREF="pkg_android.support.v17.leanback.widget.html#ShadowOverlayHelper.Options" class="hiddenlink" target="rightframe"><b>ShadowOverlayHelper.Options</b></A><br>
    +-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    + </script>
    + <script type="text/javascript">
    +   try {
    +diff --git a/docs/html/sdk/support_api_diff/23.1.0/changes/classes_index_all.html b/docs/html/sdk/support_api_diff/23.1.0/changes/classes_index_all.html
    +index 05f83b8..c8f86f4 100644
    +--- a/docs/html/sdk/support_api_diff/23.1.0/changes/classes_index_all.html
    ++++ b/docs/html/sdk/support_api_diff/23.1.0/changes/classes_index_all.html
    +@@ -471,7 +471,7 @@ Listed as: <span style="color:#069"><strong>Added</strong></span>,  <span style=
    + <A HREF="android.support.v17.leanback.widget.VerticalGridPresenter.html" class="hiddenlink" target="rightframe">VerticalGridPresenter</A><br>
    + <A HREF="android.support.v17.leanback.app.VerticalGridSupportFragment.html" class="hiddenlink" target="rightframe">VerticalGridSupportFragment</A><br>
    + <A HREF="android.support.v4.view.ViewCompat.html" class="hiddenlink" target="rightframe">ViewCompat</A><br>
    +-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    + </script>
    + <script type="text/javascript">
    +   try {
    +diff --git a/docs/html/sdk/support_api_diff/23.1.0/changes/classes_index_changes.html b/docs/html/sdk/support_api_diff/23.1.0/changes/classes_index_changes.html
    +index b1ee972..f280906 100644
    +--- a/docs/html/sdk/support_api_diff/23.1.0/changes/classes_index_changes.html
    ++++ b/docs/html/sdk/support_api_diff/23.1.0/changes/classes_index_changes.html
    +@@ -415,7 +415,7 @@ Listed as: <span style="color:#069"><strong>Added</strong></span>,  <span style=
    + <A HREF="android.support.v17.leanback.widget.VerticalGridPresenter.html" class="hiddenlink" target="rightframe">VerticalGridPresenter</A><br>
    + <A HREF="android.support.v17.leanback.app.VerticalGridSupportFragment.html" class="hiddenlink" target="rightframe">VerticalGridSupportFragment</A><br>
    + <A HREF="android.support.v4.view.ViewCompat.html" class="hiddenlink" target="rightframe">ViewCompat</A><br>
    +-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    + </script>
    + <script type="text/javascript">
    +   try {
    +diff --git a/docs/html/sdk/support_api_diff/23.1.0/changes/classes_index_removals.html b/docs/html/sdk/support_api_diff/23.1.0/changes/classes_index_removals.html
    +index e6da73f..c466298 100644
    +--- a/docs/html/sdk/support_api_diff/23.1.0/changes/classes_index_removals.html
    ++++ b/docs/html/sdk/support_api_diff/23.1.0/changes/classes_index_removals.html
    +@@ -47,7 +47,7 @@ body{overflow:auto;}
    + <div id="indexTableCaption" style="background-color:#eee;padding:0 4px 0 4px;font-size:11px;margin-bottom:1em;">
    + Listed as: <span style="color:#069"><strong>Added</strong></span>,  <span style="color:#069"><strike>Removed</strike></span>,  <span style="color:#069">Changed</span></font>
    + </div>
    +-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    + </script>
    + <script type="text/javascript">
    +   try {
    +diff --git a/docs/html/sdk/support_api_diff/23.1.0/changes/constructors_index_additions.html b/docs/html/sdk/support_api_diff/23.1.0/changes/constructors_index_additions.html
    +index 3bf8178..45f72f1 100644
    +--- a/docs/html/sdk/support_api_diff/23.1.0/changes/constructors_index_additions.html
    ++++ b/docs/html/sdk/support_api_diff/23.1.0/changes/constructors_index_additions.html
    +@@ -97,7 +97,7 @@ Listed as: <span style="color:#069"><strong>Added</strong></span>,  <span style=
    + <p><div style="line-height:1.5em;color:black">
    + <nobr><A HREF="android.support.design.widget.NavigationView.SavedState.html#android.support.design.widget.NavigationView.SavedState.ctor_added(android.os.Parcel, java.lang.ClassLoader)" class="hiddenlink" target="rightframe"><b>NavigationView.SavedState</b>
    + (<code>Parcel, ClassLoader</code>)</A></nobr>&nbsp;constructor<br>
    +-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    + </script>
    + <script type="text/javascript">
    +   try {
    +diff --git a/docs/html/sdk/support_api_diff/23.1.0/changes/constructors_index_all.html b/docs/html/sdk/support_api_diff/23.1.0/changes/constructors_index_all.html
    +index 546eae8..8dda68f 100644
    +--- a/docs/html/sdk/support_api_diff/23.1.0/changes/constructors_index_all.html
    ++++ b/docs/html/sdk/support_api_diff/23.1.0/changes/constructors_index_all.html
    +@@ -106,7 +106,7 @@ Listed as: <span style="color:#069"><strong>Added</strong></span>,  <span style=
    + (<code>Parcel</code>)</A></nobr>&nbsp;constructor<br>
    + &nbsp;&nbsp;<nobr><A HREF="android.support.design.widget.NavigationView.SavedState.html#android.support.design.widget.NavigationView.SavedState.ctor_added(android.os.Parcel, java.lang.ClassLoader)" class="hiddenlink" target="rightframe"><b>NavigationView.SavedState</b>
    + (<code>Parcel, ClassLoader</code>)</A></nobr>&nbsp;constructor<br>
    +-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    + </script>
    + <script type="text/javascript">
    +   try {
    +diff --git a/docs/html/sdk/support_api_diff/23.1.0/changes/constructors_index_changes.html b/docs/html/sdk/support_api_diff/23.1.0/changes/constructors_index_changes.html
    +index 52c8b49..d6584d1 100644
    +--- a/docs/html/sdk/support_api_diff/23.1.0/changes/constructors_index_changes.html
    ++++ b/docs/html/sdk/support_api_diff/23.1.0/changes/constructors_index_changes.html
    +@@ -47,7 +47,7 @@ body{overflow:auto;}
    + <div id="indexTableCaption" style="background-color:#eee;padding:0 4px 0 4px;font-size:11px;margin-bottom:1em;">
    + Listed as: <span style="color:#069"><strong>Added</strong></span>,  <span style="color:#069"><strike>Removed</strike></span>,  <span style="color:#069">Changed</span></font>
    + </div>
    +-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    + </script>
    + <script type="text/javascript">
    +   try {
    +diff --git a/docs/html/sdk/support_api_diff/23.1.0/changes/constructors_index_removals.html b/docs/html/sdk/support_api_diff/23.1.0/changes/constructors_index_removals.html
    +index 337274d..49ee23c 100644
    +--- a/docs/html/sdk/support_api_diff/23.1.0/changes/constructors_index_removals.html
    ++++ b/docs/html/sdk/support_api_diff/23.1.0/changes/constructors_index_removals.html
    +@@ -71,7 +71,7 @@ Listed as: <span style="color:#069"><strong>Added</strong></span>,  <span style=
    + <p><div style="line-height:1.5em;color:black">
    + <nobr><A HREF="android.support.design.widget.NavigationView.SavedState.html#android.support.design.widget.NavigationView.SavedState.ctor_removed(android.os.Parcel)" class="hiddenlink" target="rightframe"><strike>NavigationView.SavedState</strike>
    + (<code>Parcel</code>)</A></nobr>&nbsp;constructor<br>
    +-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    + </script>
    + <script type="text/javascript">
    +   try {
    +diff --git a/docs/html/sdk/support_api_diff/23.1.0/changes/fields_index_additions.html b/docs/html/sdk/support_api_diff/23.1.0/changes/fields_index_additions.html
    +index d1ef3ac..0c43320 100644
    +--- a/docs/html/sdk/support_api_diff/23.1.0/changes/fields_index_additions.html
    ++++ b/docs/html/sdk/support_api_diff/23.1.0/changes/fields_index_additions.html
    +@@ -329,7 +329,7 @@ Listed as: <span style="color:#069"><strong>Added</strong></span>,  <span style=
    + </nobr><br>
    + <nobr><A HREF="android.support.v7.appcompat.R.style.html#android.support.v7.appcompat.R.style.Widget_AppCompat_SeekBar" class="hiddenlink" target="rightframe">Widget_AppCompat_SeekBar</A>
    + </nobr><br>
    +-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    + </script>
    + <script type="text/javascript">
    +   try {
    +diff --git a/docs/html/sdk/support_api_diff/23.1.0/changes/fields_index_all.html b/docs/html/sdk/support_api_diff/23.1.0/changes/fields_index_all.html
    +index 697f16a..71d9b71 100644
    +--- a/docs/html/sdk/support_api_diff/23.1.0/changes/fields_index_all.html
    ++++ b/docs/html/sdk/support_api_diff/23.1.0/changes/fields_index_all.html
    +@@ -339,7 +339,7 @@ Listed as: <span style="color:#069"><strong>Added</strong></span>,  <span style=
    + </nobr><br>
    + <nobr><A HREF="android.support.v7.appcompat.R.style.html#android.support.v7.appcompat.R.style.Widget_AppCompat_SeekBar" class="hiddenlink" target="rightframe">Widget_AppCompat_SeekBar</A>
    + </nobr><br>
    +-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    + </script>
    + <script type="text/javascript">
    +   try {
    +diff --git a/docs/html/sdk/support_api_diff/23.1.0/changes/fields_index_changes.html b/docs/html/sdk/support_api_diff/23.1.0/changes/fields_index_changes.html
    +index 0e2ccff..301881a 100644
    +--- a/docs/html/sdk/support_api_diff/23.1.0/changes/fields_index_changes.html
    ++++ b/docs/html/sdk/support_api_diff/23.1.0/changes/fields_index_changes.html
    +@@ -47,7 +47,7 @@ body{overflow:auto;}
    + <div id="indexTableCaption" style="background-color:#eee;padding:0 4px 0 4px;font-size:11px;margin-bottom:1em;">
    + Listed as: <span style="color:#069"><strong>Added</strong></span>,  <span style="color:#069"><strike>Removed</strike></span>,  <span style="color:#069">Changed</span></font>
    + </div>
    +-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    + </script>
    + <script type="text/javascript">
    +   try {
    +diff --git a/docs/html/sdk/support_api_diff/23.1.0/changes/fields_index_removals.html b/docs/html/sdk/support_api_diff/23.1.0/changes/fields_index_removals.html
    +index 93bcdc3..f520de6 100644
    +--- a/docs/html/sdk/support_api_diff/23.1.0/changes/fields_index_removals.html
    ++++ b/docs/html/sdk/support_api_diff/23.1.0/changes/fields_index_removals.html
    +@@ -67,7 +67,7 @@ Listed as: <span style="color:#069"><strong>Added</strong></span>,  <span style=
    + <p><div style="line-height:1.5em;color:black">
    + <nobr><A HREF="android.support.v7.appcompat.R.style.html#android.support.v7.appcompat.R.style.RtlOverlay_Widget_AppCompat_ActionButton_Overflow" class="hiddenlink" target="rightframe"><strike>RtlOverlay_Widget_AppCompat_ActionButton_Overflow</strike></A>
    + </nobr><br>
    +-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    + </script>
    + <script type="text/javascript">
    +   try {
    +diff --git a/docs/html/sdk/support_api_diff/23.1.0/changes/jdiff_help.html b/docs/html/sdk/support_api_diff/23.1.0/changes/jdiff_help.html
    +index b03b763..0ba76e7 100644
    +--- a/docs/html/sdk/support_api_diff/23.1.0/changes/jdiff_help.html
    ++++ b/docs/html/sdk/support_api_diff/23.1.0/changes/jdiff_help.html
    +@@ -120,7 +120,7 @@ These links show and hide the HTML frames. All pages are available with or witho
    + There are some complex changes which can occur between versions, for example, when two or more methods with the same name change simultaneously, or when a method or field is moved into or from a superclass. 
    + In these cases, the change will be seen as a removal and an addition, rather than as a change. Unexpected removals or additions are often part of one of these type of changes. 
    + </BLOCKQUOTE>
    +-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    + </script>
    + <script type="text/javascript">
    +   try {
    +diff --git a/docs/html/sdk/support_api_diff/23.1.0/changes/jdiff_statistics.html b/docs/html/sdk/support_api_diff/23.1.0/changes/jdiff_statistics.html
    +index bdda25f..ac4d43e 100644
    +--- a/docs/html/sdk/support_api_diff/23.1.0/changes/jdiff_statistics.html
    ++++ b/docs/html/sdk/support_api_diff/23.1.0/changes/jdiff_statistics.html
    +@@ -568,7 +568,7 @@ added, the change will be 100%.</p>
    +     </div> <!-- end footer -->
    +     </div><!-- end doc-content -->
    +     </div> <!-- end body-content --> 
    +-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    + </script>
    + <script type="text/javascript">
    +   try {
    +diff --git a/docs/html/sdk/support_api_diff/23.1.0/changes/jdiff_topleftframe.html b/docs/html/sdk/support_api_diff/23.1.0/changes/jdiff_topleftframe.html
    +index 36f9836..6a2e76e 100644
    +--- a/docs/html/sdk/support_api_diff/23.1.0/changes/jdiff_topleftframe.html
    ++++ b/docs/html/sdk/support_api_diff/23.1.0/changes/jdiff_topleftframe.html
    +@@ -49,7 +49,7 @@ body{overflow:auto;}
    +   <TD NOWRAP><FONT CLASS="indexText" size="-2"><A HREF="fields_index_all.html" TARGET="bottomleftframe">By Field</A></FONT><br></TD>
    + </TR>
    + </TABLE>
    +-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    + </script>
    + <script type="text/javascript">
    +   try {
    +diff --git a/docs/html/sdk/support_api_diff/23.1.0/changes/methods_index_additions.html b/docs/html/sdk/support_api_diff/23.1.0/changes/methods_index_additions.html
    +index 9b4eab3..fee36df 100644
    +--- a/docs/html/sdk/support_api_diff/23.1.0/changes/methods_index_additions.html
    ++++ b/docs/html/sdk/support_api_diff/23.1.0/changes/methods_index_additions.html
    +@@ -516,7 +516,7 @@ Listed as: <span style="color:#069"><strong>Added</strong></span>,  <span style=
    + <p><div style="line-height:1.5em;color:black">
    + <nobr><A HREF="android.support.customtabs.CustomTabsService.html#android.support.customtabs.CustomTabsService.updateVisuals_added(android.support.customtabs.CustomTabsSessionToken, android.os.Bundle)" class="hiddenlink" target="rightframe"><b>updateVisuals</b>
    + (<code>CustomTabsSessionToken, Bundle</code>)</A></nobr><br>
    +-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    + </script>
    + <script type="text/javascript">
    +   try {
    +diff --git a/docs/html/sdk/support_api_diff/23.1.0/changes/methods_index_all.html b/docs/html/sdk/support_api_diff/23.1.0/changes/methods_index_all.html
    +index d63656c..7a2fe5c 100644
    +--- a/docs/html/sdk/support_api_diff/23.1.0/changes/methods_index_all.html
    ++++ b/docs/html/sdk/support_api_diff/23.1.0/changes/methods_index_all.html
    +@@ -616,7 +616,7 @@ Listed as: <span style="color:#069"><strong>Added</strong></span>,  <span style=
    + <p><div style="line-height:1.5em;color:black">
    + <nobr><A HREF="android.support.customtabs.CustomTabsService.html#android.support.customtabs.CustomTabsService.updateVisuals_added(android.support.customtabs.CustomTabsSessionToken, android.os.Bundle)" class="hiddenlink" target="rightframe"><b>updateVisuals</b>
    + (<code>CustomTabsSessionToken, Bundle</code>)</A></nobr><br>
    +-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    + </script>
    + <script type="text/javascript">
    +   try {
    +diff --git a/docs/html/sdk/support_api_diff/23.1.0/changes/methods_index_changes.html b/docs/html/sdk/support_api_diff/23.1.0/changes/methods_index_changes.html
    +index 8271b35..254a721 100644
    +--- a/docs/html/sdk/support_api_diff/23.1.0/changes/methods_index_changes.html
    ++++ b/docs/html/sdk/support_api_diff/23.1.0/changes/methods_index_changes.html
    +@@ -77,7 +77,7 @@ Listed as: <span style="color:#069"><strong>Added</strong></span>,  <span style=
    + <p><div style="line-height:1.5em;color:black">
    + <nobr><A HREF="android.support.v7.media.MediaRouteDescriptor.Builder.html#android.support.v7.media.MediaRouteDescriptor.Builder.setConnecting_changed(boolean)" class="hiddenlink" target="rightframe">setConnecting
    + (<code>boolean</code>)</A></nobr><br>
    +-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    + </script>
    + <script type="text/javascript">
    +   try {
    +diff --git a/docs/html/sdk/support_api_diff/23.1.0/changes/methods_index_removals.html b/docs/html/sdk/support_api_diff/23.1.0/changes/methods_index_removals.html
    +index 7250505..0b6f2b4 100644
    +--- a/docs/html/sdk/support_api_diff/23.1.0/changes/methods_index_removals.html
    ++++ b/docs/html/sdk/support_api_diff/23.1.0/changes/methods_index_removals.html
    +@@ -158,7 +158,7 @@ Listed as: <span style="color:#069"><strong>Added</strong></span>,  <span style=
    + <p><div style="line-height:1.5em;color:black">
    + <nobr><A HREF="android.support.v17.leanback.app.GuidedStepFragment.html#android.support.v17.leanback.app.GuidedStepFragment.setEntryTransitionEnabled_removed(boolean)" class="hiddenlink" target="rightframe"><strike>setEntryTransitionEnabled</strike>
    + (<code>boolean</code>)</A></nobr><br>
    +-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    + </script>
    + <script type="text/javascript">
    +   try {
    +diff --git a/docs/html/sdk/support_api_diff/23.1.0/changes/packages_index_additions.html b/docs/html/sdk/support_api_diff/23.1.0/changes/packages_index_additions.html
    +index 1776064..e7ed63e 100644
    +--- a/docs/html/sdk/support_api_diff/23.1.0/changes/packages_index_additions.html
    ++++ b/docs/html/sdk/support_api_diff/23.1.0/changes/packages_index_additions.html
    +@@ -49,7 +49,7 @@ Listed as: <span style="color:#069"><strong>Added</strong></span>,  <span style=
    + </div>
    + <br>
    + <div id="indexTableEntries">
    +-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    + </script>
    + <script type="text/javascript">
    +   try {
    +diff --git a/docs/html/sdk/support_api_diff/23.1.0/changes/packages_index_all.html b/docs/html/sdk/support_api_diff/23.1.0/changes/packages_index_all.html
    +index 2bf0974..4236847 100644
    +--- a/docs/html/sdk/support_api_diff/23.1.0/changes/packages_index_all.html
    ++++ b/docs/html/sdk/support_api_diff/23.1.0/changes/packages_index_all.html
    +@@ -67,7 +67,7 @@ Listed as: <span style="color:#069"><strong>Added</strong></span>,  <span style=
    + <A HREF="pkg_android.support.v7.graphics.drawable.html" class="hiddenlink" target="rightframe">android.support.v7.graphics.drawable</A><br>
    + <A HREF="pkg_android.support.v7.media.html" class="hiddenlink" target="rightframe">android.support.v7.media</A><br>
    + <A HREF="pkg_android.support.v7.preference.html" class="hiddenlink" target="rightframe">android.support.v7.preference</A><br>
    +-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    + </script>
    + <script type="text/javascript">
    +   try {
    +diff --git a/docs/html/sdk/support_api_diff/23.1.0/changes/packages_index_changes.html b/docs/html/sdk/support_api_diff/23.1.0/changes/packages_index_changes.html
    +index 519e9aa..8d51ea2 100644
    +--- a/docs/html/sdk/support_api_diff/23.1.0/changes/packages_index_changes.html
    ++++ b/docs/html/sdk/support_api_diff/23.1.0/changes/packages_index_changes.html
    +@@ -67,7 +67,7 @@ Listed as: <span style="color:#069"><strong>Added</strong></span>,  <span style=
    + <A HREF="pkg_android.support.v7.graphics.drawable.html" class="hiddenlink" target="rightframe">android.support.v7.graphics.drawable</A><br>
    + <A HREF="pkg_android.support.v7.media.html" class="hiddenlink" target="rightframe">android.support.v7.media</A><br>
    + <A HREF="pkg_android.support.v7.preference.html" class="hiddenlink" target="rightframe">android.support.v7.preference</A><br>
    +-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    + </script>
    + <script type="text/javascript">
    +   try {
    +diff --git a/docs/html/sdk/support_api_diff/23.1.0/changes/packages_index_removals.html b/docs/html/sdk/support_api_diff/23.1.0/changes/packages_index_removals.html
    +index 9fd0f7e..ae935f4 100644
    +--- a/docs/html/sdk/support_api_diff/23.1.0/changes/packages_index_removals.html
    ++++ b/docs/html/sdk/support_api_diff/23.1.0/changes/packages_index_removals.html
    +@@ -49,7 +49,7 @@ Listed as: <span style="color:#069"><strong>Added</strong></span>,  <span style=
    + </div>
    + <br>
    + <div id="indexTableEntries">
    +-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    + </script>
    + <script type="text/javascript">
    +   try {
    +diff --git a/docs/html/sdk/support_api_diff/23.1.0/changes/pkg_android.support.customtabs.html b/docs/html/sdk/support_api_diff/23.1.0/changes/pkg_android.support.customtabs.html
    +index d85f3f8..ea62004 100644
    +--- a/docs/html/sdk/support_api_diff/23.1.0/changes/pkg_android.support.customtabs.html
    ++++ b/docs/html/sdk/support_api_diff/23.1.0/changes/pkg_android.support.customtabs.html
    +@@ -140,7 +140,7 @@ Package <A HREF="../../../../reference/android/support/customtabs/package-summar
    +     </div> <!-- end footer -->
    +     </div><!-- end doc-content -->
    +     </div> <!-- end body-content --> 
    +-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    + </script>
    + <script type="text/javascript">
    +   try {
    +diff --git a/docs/html/sdk/support_api_diff/23.1.0/changes/pkg_android.support.design.widget.html b/docs/html/sdk/support_api_diff/23.1.0/changes/pkg_android.support.design.widget.html
    +index 449afa6..45625b9 100644
    +--- a/docs/html/sdk/support_api_diff/23.1.0/changes/pkg_android.support.design.widget.html
    ++++ b/docs/html/sdk/support_api_diff/23.1.0/changes/pkg_android.support.design.widget.html
    +@@ -211,7 +211,7 @@ Package <A HREF="../../../../reference/android/support/design/widget/package-sum
    +     </div> <!-- end footer -->
    +     </div><!-- end doc-content -->
    +     </div> <!-- end body-content --> 
    +-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    + </script>
    + <script type="text/javascript">
    +   try {
    +diff --git a/docs/html/sdk/support_api_diff/23.1.0/changes/pkg_android.support.percent.html b/docs/html/sdk/support_api_diff/23.1.0/changes/pkg_android.support.percent.html
    +index 53b92a9..13b9732 100644
    +--- a/docs/html/sdk/support_api_diff/23.1.0/changes/pkg_android.support.percent.html
    ++++ b/docs/html/sdk/support_api_diff/23.1.0/changes/pkg_android.support.percent.html
    +@@ -105,7 +105,7 @@ Package <A HREF="../../../../reference/android/support/percent/package-summary.h
    +     </div> <!-- end footer -->
    +     </div><!-- end doc-content -->
    +     </div> <!-- end body-content --> 
    +-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    + </script>
    + <script type="text/javascript">
    +   try {
    +diff --git a/docs/html/sdk/support_api_diff/23.1.0/changes/pkg_android.support.v14.preference.html b/docs/html/sdk/support_api_diff/23.1.0/changes/pkg_android.support.v14.preference.html
    +index 3ef0a0f..7364b7c 100644
    +--- a/docs/html/sdk/support_api_diff/23.1.0/changes/pkg_android.support.v14.preference.html
    ++++ b/docs/html/sdk/support_api_diff/23.1.0/changes/pkg_android.support.v14.preference.html
    +@@ -105,7 +105,7 @@ Package <A HREF="../../../../reference/android/support/v14/preference/package-su
    +     </div> <!-- end footer -->
    +     </div><!-- end doc-content -->
    +     </div> <!-- end body-content --> 
    +-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    + </script>
    + <script type="text/javascript">
    +   try {
    +diff --git a/docs/html/sdk/support_api_diff/23.1.0/changes/pkg_android.support.v17.leanback.app.html b/docs/html/sdk/support_api_diff/23.1.0/changes/pkg_android.support.v17.leanback.app.html
    +index 49ee52f..21763fb 100644
    +--- a/docs/html/sdk/support_api_diff/23.1.0/changes/pkg_android.support.v17.leanback.app.html
    ++++ b/docs/html/sdk/support_api_diff/23.1.0/changes/pkg_android.support.v17.leanback.app.html
    +@@ -211,7 +211,7 @@ Package <A HREF="../../../../reference/android/support/v17/leanback/app/package-
    +     </div> <!-- end footer -->
    +     </div><!-- end doc-content -->
    +     </div> <!-- end body-content --> 
    +-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    + </script>
    + <script type="text/javascript">
    +   try {
    +diff --git a/docs/html/sdk/support_api_diff/23.1.0/changes/pkg_android.support.v17.leanback.widget.html b/docs/html/sdk/support_api_diff/23.1.0/changes/pkg_android.support.v17.leanback.widget.html
    +index 73d5050..ff00794 100644
    +--- a/docs/html/sdk/support_api_diff/23.1.0/changes/pkg_android.support.v17.leanback.widget.html
    ++++ b/docs/html/sdk/support_api_diff/23.1.0/changes/pkg_android.support.v17.leanback.widget.html
    +@@ -239,7 +239,7 @@ Package <A HREF="../../../../reference/android/support/v17/leanback/widget/packa
    +     </div> <!-- end footer -->
    +     </div><!-- end doc-content -->
    +     </div> <!-- end body-content --> 
    +-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    + </script>
    + <script type="text/javascript">
    +   try {
    +diff --git a/docs/html/sdk/support_api_diff/23.1.0/changes/pkg_android.support.v4.app.html b/docs/html/sdk/support_api_diff/23.1.0/changes/pkg_android.support.v4.app.html
    +index b1645a6..ccdb5fe 100644
    +--- a/docs/html/sdk/support_api_diff/23.1.0/changes/pkg_android.support.v4.app.html
    ++++ b/docs/html/sdk/support_api_diff/23.1.0/changes/pkg_android.support.v4.app.html
    +@@ -120,7 +120,7 @@ Package <A HREF="../../../../reference/android/support/v4/app/package-summary.ht
    +     </div> <!-- end footer -->
    +     </div><!-- end doc-content -->
    +     </div> <!-- end body-content --> 
    +-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    + </script>
    + <script type="text/javascript">
    +   try {
    +diff --git a/docs/html/sdk/support_api_diff/23.1.0/changes/pkg_android.support.v4.content.html b/docs/html/sdk/support_api_diff/23.1.0/changes/pkg_android.support.v4.content.html
    +index efc62c9..b1b6ffc 100644
    +--- a/docs/html/sdk/support_api_diff/23.1.0/changes/pkg_android.support.v4.content.html
    ++++ b/docs/html/sdk/support_api_diff/23.1.0/changes/pkg_android.support.v4.content.html
    +@@ -105,7 +105,7 @@ Package <A HREF="../../../../reference/android/support/v4/content/package-summar
    +     </div> <!-- end footer -->
    +     </div><!-- end doc-content -->
    +     </div> <!-- end body-content --> 
    +-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    + </script>
    + <script type="text/javascript">
    +   try {
    +diff --git a/docs/html/sdk/support_api_diff/23.1.0/changes/pkg_android.support.v4.content.res.html b/docs/html/sdk/support_api_diff/23.1.0/changes/pkg_android.support.v4.content.res.html
    +index fd9c9f8..f6a1367 100644
    +--- a/docs/html/sdk/support_api_diff/23.1.0/changes/pkg_android.support.v4.content.res.html
    ++++ b/docs/html/sdk/support_api_diff/23.1.0/changes/pkg_android.support.v4.content.res.html
    +@@ -105,7 +105,7 @@ Package <A HREF="../../../../reference/android/support/v4/content/res/package-su
    +     </div> <!-- end footer -->
    +     </div><!-- end doc-content -->
    +     </div> <!-- end body-content --> 
    +-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    + </script>
    + <script type="text/javascript">
    +   try {
    +diff --git a/docs/html/sdk/support_api_diff/23.1.0/changes/pkg_android.support.v4.media.session.html b/docs/html/sdk/support_api_diff/23.1.0/changes/pkg_android.support.v4.media.session.html
    +index afd23b1..1182648 100644
    +--- a/docs/html/sdk/support_api_diff/23.1.0/changes/pkg_android.support.v4.media.session.html
    ++++ b/docs/html/sdk/support_api_diff/23.1.0/changes/pkg_android.support.v4.media.session.html
    +@@ -120,7 +120,7 @@ Package <A HREF="../../../../reference/android/support/v4/media/session/package-
    +     </div> <!-- end footer -->
    +     </div><!-- end doc-content -->
    +     </div> <!-- end body-content --> 
    +-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    + </script>
    + <script type="text/javascript">
    +   try {
    +diff --git a/docs/html/sdk/support_api_diff/23.1.0/changes/pkg_android.support.v4.view.html b/docs/html/sdk/support_api_diff/23.1.0/changes/pkg_android.support.v4.view.html
    +index 7d74c82..b4fe9b2 100644
    +--- a/docs/html/sdk/support_api_diff/23.1.0/changes/pkg_android.support.v4.view.html
    ++++ b/docs/html/sdk/support_api_diff/23.1.0/changes/pkg_android.support.v4.view.html
    +@@ -105,7 +105,7 @@ Package <A HREF="../../../../reference/android/support/v4/view/package-summary.h
    +     </div> <!-- end footer -->
    +     </div><!-- end doc-content -->
    +     </div> <!-- end body-content --> 
    +-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    + </script>
    + <script type="text/javascript">
    +   try {
    +diff --git a/docs/html/sdk/support_api_diff/23.1.0/changes/pkg_android.support.v4.widget.html b/docs/html/sdk/support_api_diff/23.1.0/changes/pkg_android.support.v4.widget.html
    +index 4ca7874..e32ebc8 100644
    +--- a/docs/html/sdk/support_api_diff/23.1.0/changes/pkg_android.support.v4.widget.html
    ++++ b/docs/html/sdk/support_api_diff/23.1.0/changes/pkg_android.support.v4.widget.html
    +@@ -134,7 +134,7 @@ Package <A HREF="../../../../reference/android/support/v4/widget/package-summary
    +     </div> <!-- end footer -->
    +     </div><!-- end doc-content -->
    +     </div> <!-- end body-content --> 
    +-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    + </script>
    + <script type="text/javascript">
    +   try {
    +diff --git a/docs/html/sdk/support_api_diff/23.1.0/changes/pkg_android.support.v7.appcompat.html b/docs/html/sdk/support_api_diff/23.1.0/changes/pkg_android.support.v7.appcompat.html
    +index 553bdf2..b516a35 100644
    +--- a/docs/html/sdk/support_api_diff/23.1.0/changes/pkg_android.support.v7.appcompat.html
    ++++ b/docs/html/sdk/support_api_diff/23.1.0/changes/pkg_android.support.v7.appcompat.html
    +@@ -161,7 +161,7 @@ Package <A HREF="../../../../reference/android/support/v7/appcompat/package-summ
    +     </div> <!-- end footer -->
    +     </div><!-- end doc-content -->
    +     </div> <!-- end body-content --> 
    +-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    + </script>
    + <script type="text/javascript">
    +   try {
    +diff --git a/docs/html/sdk/support_api_diff/23.1.0/changes/pkg_android.support.v7.graphics.drawable.html b/docs/html/sdk/support_api_diff/23.1.0/changes/pkg_android.support.v7.graphics.drawable.html
    +index e9d5cd9..69c91d5 100644
    +--- a/docs/html/sdk/support_api_diff/23.1.0/changes/pkg_android.support.v7.graphics.drawable.html
    ++++ b/docs/html/sdk/support_api_diff/23.1.0/changes/pkg_android.support.v7.graphics.drawable.html
    +@@ -105,7 +105,7 @@ Package <A HREF="../../../../reference/android/support/v7/graphics/drawable/pack
    +     </div> <!-- end footer -->
    +     </div><!-- end doc-content -->
    +     </div> <!-- end body-content --> 
    +-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    + </script>
    + <script type="text/javascript">
    +   try {
    +diff --git a/docs/html/sdk/support_api_diff/23.1.0/changes/pkg_android.support.v7.graphics.html b/docs/html/sdk/support_api_diff/23.1.0/changes/pkg_android.support.v7.graphics.html
    +index ba9a092..13d6ef9 100644
    +--- a/docs/html/sdk/support_api_diff/23.1.0/changes/pkg_android.support.v7.graphics.html
    ++++ b/docs/html/sdk/support_api_diff/23.1.0/changes/pkg_android.support.v7.graphics.html
    +@@ -105,7 +105,7 @@ Package <A HREF="../../../../reference/android/support/v7/graphics/package-summa
    +     </div> <!-- end footer -->
    +     </div><!-- end doc-content -->
    +     </div> <!-- end body-content --> 
    +-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    + </script>
    + <script type="text/javascript">
    +   try {
    +diff --git a/docs/html/sdk/support_api_diff/23.1.0/changes/pkg_android.support.v7.media.html b/docs/html/sdk/support_api_diff/23.1.0/changes/pkg_android.support.v7.media.html
    +index 7892bf9..4c2094c 100644
    +--- a/docs/html/sdk/support_api_diff/23.1.0/changes/pkg_android.support.v7.media.html
    ++++ b/docs/html/sdk/support_api_diff/23.1.0/changes/pkg_android.support.v7.media.html
    +@@ -134,7 +134,7 @@ Package <A HREF="../../../../reference/android/support/v7/media/package-summary.
    +     </div> <!-- end footer -->
    +     </div><!-- end doc-content -->
    +     </div> <!-- end body-content --> 
    +-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    + </script>
    + <script type="text/javascript">
    +   try {
    +diff --git a/docs/html/sdk/support_api_diff/23.1.0/changes/pkg_android.support.v7.preference.html b/docs/html/sdk/support_api_diff/23.1.0/changes/pkg_android.support.v7.preference.html
    +index ced3a90..ed590bb 100644
    +--- a/docs/html/sdk/support_api_diff/23.1.0/changes/pkg_android.support.v7.preference.html
    ++++ b/docs/html/sdk/support_api_diff/23.1.0/changes/pkg_android.support.v7.preference.html
    +@@ -105,7 +105,7 @@ Package <A HREF="../../../../reference/android/support/v7/preference/package-sum
    +     </div> <!-- end footer -->
    +     </div><!-- end doc-content -->
    +     </div> <!-- end body-content --> 
    +-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    + </script>
    + <script type="text/javascript">
    +   try {
    +diff --git a/docs/html/sdk/support_api_diff/23.2.0/changes/alldiffs_index_additions.html b/docs/html/sdk/support_api_diff/23.2.0/changes/alldiffs_index_additions.html
    +index 09ec1eb..3b43f27 100644
    +--- a/docs/html/sdk/support_api_diff/23.2.0/changes/alldiffs_index_additions.html
    ++++ b/docs/html/sdk/support_api_diff/23.2.0/changes/alldiffs_index_additions.html
    +@@ -1955,7 +1955,7 @@ Listed as: <span style="color:#069"><strong>Added</strong></span>,  <span style=
    + <!-- Method XYZToLAB -->
    + <nobr><A HREF="android.support.v4.graphics.ColorUtils.html#android.support.v4.graphics.ColorUtils.XYZToLAB_added(double, double, double, double[])" class="hiddenlink" target="rightframe"><b>XYZToLAB</b>
    + (<code>double, double, double, double[]</code>)</A></nobr><br>
    +-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    + </script>
    + <script type="text/javascript">
    +   try {
    +diff --git a/docs/html/sdk/support_api_diff/23.2.0/changes/alldiffs_index_all.html b/docs/html/sdk/support_api_diff/23.2.0/changes/alldiffs_index_all.html
    +index 770d615..6264757 100644
    +--- a/docs/html/sdk/support_api_diff/23.2.0/changes/alldiffs_index_all.html
    ++++ b/docs/html/sdk/support_api_diff/23.2.0/changes/alldiffs_index_all.html
    +@@ -2914,7 +2914,7 @@ Listed as: <span style="color:#069"><strong>Added</strong></span>,  <span style=
    + <!-- Method XYZToLAB -->
    + <nobr><A HREF="android.support.v4.graphics.ColorUtils.html#android.support.v4.graphics.ColorUtils.XYZToLAB_added(double, double, double, double[])" class="hiddenlink" target="rightframe"><b>XYZToLAB</b>
    + (<code>double, double, double, double[]</code>)</A></nobr><br>
    +-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    + </script>
    + <script type="text/javascript">
    +   try {
    +diff --git a/docs/html/sdk/support_api_diff/23.2.0/changes/alldiffs_index_changes.html b/docs/html/sdk/support_api_diff/23.2.0/changes/alldiffs_index_changes.html
    +index 134580d..6113a9e 100644
    +--- a/docs/html/sdk/support_api_diff/23.2.0/changes/alldiffs_index_changes.html
    ++++ b/docs/html/sdk/support_api_diff/23.2.0/changes/alldiffs_index_changes.html
    +@@ -939,7 +939,7 @@ Listed as: <span style="color:#069"><strong>Added</strong></span>,  <span style=
    +  <a href="#topheader"><font size="-2">TOP</font></a>
    + <p><div style="line-height:1.5em;color:black">
    + <A HREF="android.support.v4.view.WindowCompat.html" class="hiddenlink" target="rightframe">WindowCompat</A><br>
    +-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    + </script>
    + <script type="text/javascript">
    +   try {
    +diff --git a/docs/html/sdk/support_api_diff/23.2.0/changes/alldiffs_index_removals.html b/docs/html/sdk/support_api_diff/23.2.0/changes/alldiffs_index_removals.html
    +index a60b244..2df39dc 100644
    +--- a/docs/html/sdk/support_api_diff/23.2.0/changes/alldiffs_index_removals.html
    ++++ b/docs/html/sdk/support_api_diff/23.2.0/changes/alldiffs_index_removals.html
    +@@ -956,7 +956,7 @@ Listed as: <span style="color:#069"><strong>Added</strong></span>,  <span style=
    + <p><div style="line-height:1.5em;color:black">
    + <nobr><A HREF="android.support.v4.view.WindowCompat.html#android.support.v4.view.WindowCompat.ctor_removed()" class="hiddenlink" target="rightframe"><strike>WindowCompat</strike>
    + ()</A></nobr>&nbsp;constructor<br>
    +-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    + </script>
    + <script type="text/javascript">
    +   try {
    +diff --git a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.customtabs.CustomTabsIntent.Builder.html b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.customtabs.CustomTabsIntent.Builder.html
    +index 46a0548..3e97afd 100644
    +--- a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.customtabs.CustomTabsIntent.Builder.html
    ++++ b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.customtabs.CustomTabsIntent.Builder.html
    +@@ -122,7 +122,7 @@ Class android.support.customtabs.<A HREF="../../../../reference/android/support/
    +     </div> <!-- end footer -->
    +     </div><!-- end doc-content -->
    +     </div> <!-- end body-content --> 
    +-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    + </script>
    + <script type="text/javascript">
    +   try {
    +diff --git a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.customtabs.CustomTabsIntent.html b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.customtabs.CustomTabsIntent.html
    +index 7987724..d7745e6 100644
    +--- a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.customtabs.CustomTabsIntent.html
    ++++ b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.customtabs.CustomTabsIntent.html
    +@@ -151,7 +151,7 @@ Class android.support.customtabs.<A HREF="../../../../reference/android/support/
    +     </div> <!-- end footer -->
    +     </div><!-- end doc-content -->
    +     </div> <!-- end body-content --> 
    +-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    + </script>
    + <script type="text/javascript">
    +   try {
    +diff --git a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.customtabs.CustomTabsSession.html b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.customtabs.CustomTabsSession.html
    +index 1296d4c..9b48018 100644
    +--- a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.customtabs.CustomTabsSession.html
    ++++ b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.customtabs.CustomTabsSession.html
    +@@ -108,7 +108,7 @@ Class android.support.customtabs.<A HREF="../../../../reference/android/support/
    +     </div> <!-- end footer -->
    +     </div><!-- end doc-content -->
    +     </div> <!-- end body-content --> 
    +-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    + </script>
    + <script type="text/javascript">
    +   try {
    +diff --git a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.design.widget.AppBarLayout.ScrollingViewBehavior.html b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.design.widget.AppBarLayout.ScrollingViewBehavior.html
    +index d539481..80c8e11 100644
    +--- a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.design.widget.AppBarLayout.ScrollingViewBehavior.html
    ++++ b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.design.widget.AppBarLayout.ScrollingViewBehavior.html
    +@@ -136,7 +136,7 @@ Method was locally defined, but is now inherited from <a href="../../../../refer
    +     </div> <!-- end footer -->
    +     </div><!-- end doc-content -->
    +     </div> <!-- end body-content --> 
    +-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    + </script>
    + <script type="text/javascript">
    +   try {
    +diff --git a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.design.widget.CollapsingToolbarLayout.html b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.design.widget.CollapsingToolbarLayout.html
    +index e47f317..e1ae295 100644
    +--- a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.design.widget.CollapsingToolbarLayout.html
    ++++ b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.design.widget.CollapsingToolbarLayout.html
    +@@ -164,7 +164,7 @@ Class android.support.design.widget.<A HREF="../../../../reference/android/suppo
    +     </div> <!-- end footer -->
    +     </div><!-- end doc-content -->
    +     </div> <!-- end body-content --> 
    +-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    + </script>
    + <script type="text/javascript">
    +   try {
    +diff --git a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.design.widget.CoordinatorLayout.Behavior.html b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.design.widget.CoordinatorLayout.Behavior.html
    +index 04efe89..ee87ca6 100644
    +--- a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.design.widget.CoordinatorLayout.Behavior.html
    ++++ b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.design.widget.CoordinatorLayout.Behavior.html
    +@@ -121,7 +121,7 @@ Change from final to non-final.<br>
    +     </div> <!-- end footer -->
    +     </div><!-- end doc-content -->
    +     </div> <!-- end body-content --> 
    +-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    + </script>
    + <script type="text/javascript">
    +   try {
    +diff --git a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.design.widget.FloatingActionButton.html b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.design.widget.FloatingActionButton.html
    +index 985adba..33d67e2 100644
    +--- a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.design.widget.FloatingActionButton.html
    ++++ b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.design.widget.FloatingActionButton.html
    +@@ -144,7 +144,7 @@ Class android.support.design.widget.<A HREF="../../../../reference/android/suppo
    +     </div> <!-- end footer -->
    +     </div><!-- end doc-content -->
    +     </div> <!-- end body-content --> 
    +-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    + </script>
    + <script type="text/javascript">
    +   try {
    +diff --git a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.design.widget.HeaderScrollingViewBehavior.html b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.design.widget.HeaderScrollingViewBehavior.html
    +index 7021ba2..0e24356 100644
    +--- a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.design.widget.HeaderScrollingViewBehavior.html
    ++++ b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.design.widget.HeaderScrollingViewBehavior.html
    +@@ -122,7 +122,7 @@ Class android.support.design.widget.<A HREF="../../../../reference/android/suppo
    +     </div> <!-- end footer -->
    +     </div><!-- end doc-content -->
    +     </div> <!-- end body-content --> 
    +-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    + </script>
    + <script type="text/javascript">
    +   try {
    +diff --git a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.design.widget.TabLayout.html b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.design.widget.TabLayout.html
    +index 9224ddb..3d0eb9f 100644
    +--- a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.design.widget.TabLayout.html
    ++++ b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.design.widget.TabLayout.html
    +@@ -111,7 +111,7 @@ Class android.support.design.widget.<A HREF="../../../../reference/android/suppo
    +     </div> <!-- end footer -->
    +     </div><!-- end doc-content -->
    +     </div> <!-- end body-content --> 
    +-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    + </script>
    + <script type="text/javascript">
    +   try {
    +diff --git a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.design.widget.TextInputLayout.html b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.design.widget.TextInputLayout.html
    +index b0f5d63..d72b373 100644
    +--- a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.design.widget.TextInputLayout.html
    ++++ b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.design.widget.TextInputLayout.html
    +@@ -129,7 +129,7 @@ Class android.support.design.widget.<A HREF="../../../../reference/android/suppo
    +     </div> <!-- end footer -->
    +     </div><!-- end doc-content -->
    +     </div> <!-- end body-content --> 
    +-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    + </script>
    + <script type="text/javascript">
    +   try {
    +diff --git a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.design.widget.ViewOffsetBehavior.html b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.design.widget.ViewOffsetBehavior.html
    +index 1b4625f..9faa826 100644
    +--- a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.design.widget.ViewOffsetBehavior.html
    ++++ b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.design.widget.ViewOffsetBehavior.html
    +@@ -108,7 +108,7 @@ Class android.support.design.widget.<A HREF="../../../../reference/android/suppo
    +     </div> <!-- end footer -->
    +     </div><!-- end doc-content -->
    +     </div> <!-- end body-content --> 
    +-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    + </script>
    + <script type="text/javascript">
    +   try {
    +diff --git a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.percent.PercentLayoutHelper.PercentLayoutInfo.html b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.percent.PercentLayoutHelper.PercentLayoutInfo.html
    +index c13de02..13c0b4e 100644
    +--- a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.percent.PercentLayoutHelper.PercentLayoutInfo.html
    ++++ b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.percent.PercentLayoutHelper.PercentLayoutInfo.html
    +@@ -130,7 +130,7 @@ Class android.support.percent.<A HREF="../../../../reference/android/support/per
    +     </div> <!-- end footer -->
    +     </div><!-- end doc-content -->
    +     </div> <!-- end body-content --> 
    +-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    + </script>
    + <script type="text/javascript">
    +   try {
    +diff --git a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v14.preference.PreferenceFragment.html b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v14.preference.PreferenceFragment.html
    +index 3a910d0..7ead465 100644
    +--- a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v14.preference.PreferenceFragment.html
    ++++ b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v14.preference.PreferenceFragment.html
    +@@ -115,7 +115,7 @@ Class android.support.v14.preference.<A HREF="../../../../reference/android/supp
    +     </div> <!-- end footer -->
    +     </div><!-- end doc-content -->
    +     </div> <!-- end body-content --> 
    +-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    + </script>
    + <script type="text/javascript">
    +   try {
    +diff --git a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v17.leanback.app.BaseRowFragment.html b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v17.leanback.app.BaseRowFragment.html
    +index 003f04b..9bd2bd7 100644
    +--- a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v17.leanback.app.BaseRowFragment.html
    ++++ b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v17.leanback.app.BaseRowFragment.html
    +@@ -108,7 +108,7 @@ Class android.support.v17.leanback.app.<A HREF="../../../../reference/android/su
    +     </div> <!-- end footer -->
    +     </div><!-- end doc-content -->
    +     </div> <!-- end body-content --> 
    +-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    + </script>
    + <script type="text/javascript">
    +   try {
    +diff --git a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v17.leanback.app.BaseRowSupportFragment.html b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v17.leanback.app.BaseRowSupportFragment.html
    +index 6a30cc3..cf9900c 100644
    +--- a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v17.leanback.app.BaseRowSupportFragment.html
    ++++ b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v17.leanback.app.BaseRowSupportFragment.html
    +@@ -108,7 +108,7 @@ Class android.support.v17.leanback.app.<A HREF="../../../../reference/android/su
    +     </div> <!-- end footer -->
    +     </div><!-- end doc-content -->
    +     </div> <!-- end body-content --> 
    +-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    + </script>
    + <script type="text/javascript">
    +   try {
    +diff --git a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v17.leanback.app.BrowseFragment.html b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v17.leanback.app.BrowseFragment.html
    +index 74cb151..d7d0e76 100644
    +--- a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v17.leanback.app.BrowseFragment.html
    ++++ b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v17.leanback.app.BrowseFragment.html
    +@@ -129,7 +129,7 @@ Class android.support.v17.leanback.app.<A HREF="../../../../reference/android/su
    +     </div> <!-- end footer -->
    +     </div><!-- end doc-content -->
    +     </div> <!-- end body-content --> 
    +-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    + </script>
    + <script type="text/javascript">
    +   try {
    +diff --git a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v17.leanback.app.BrowseSupportFragment.html b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v17.leanback.app.BrowseSupportFragment.html
    +index a46a8ed..d7bb8c9 100644
    +--- a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v17.leanback.app.BrowseSupportFragment.html
    ++++ b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v17.leanback.app.BrowseSupportFragment.html
    +@@ -129,7 +129,7 @@ Class android.support.v17.leanback.app.<A HREF="../../../../reference/android/su
    +     </div> <!-- end footer -->
    +     </div><!-- end doc-content -->
    +     </div> <!-- end body-content --> 
    +-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    + </script>
    + <script type="text/javascript">
    +   try {
    +diff --git a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v17.leanback.app.DetailsFragment.html b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v17.leanback.app.DetailsFragment.html
    +index 34875c3..852b28a 100644
    +--- a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v17.leanback.app.DetailsFragment.html
    ++++ b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v17.leanback.app.DetailsFragment.html
    +@@ -108,7 +108,7 @@ Class android.support.v17.leanback.app.<A HREF="../../../../reference/android/su
    +     </div> <!-- end footer -->
    +     </div><!-- end doc-content -->
    +     </div> <!-- end body-content --> 
    +-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    + </script>
    + <script type="text/javascript">
    +   try {
    +diff --git a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v17.leanback.app.DetailsSupportFragment.html b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v17.leanback.app.DetailsSupportFragment.html
    +index 4cd41ed..444a537 100644
    +--- a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v17.leanback.app.DetailsSupportFragment.html
    ++++ b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v17.leanback.app.DetailsSupportFragment.html
    +@@ -108,7 +108,7 @@ Class android.support.v17.leanback.app.<A HREF="../../../../reference/android/su
    +     </div> <!-- end footer -->
    +     </div><!-- end doc-content -->
    +     </div> <!-- end body-content --> 
    +-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    + </script>
    + <script type="text/javascript">
    +   try {
    +diff --git a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v17.leanback.app.GuidedStepFragment.html b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v17.leanback.app.GuidedStepFragment.html
    +index 0962be7..1cfc19e 100644
    +--- a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v17.leanback.app.GuidedStepFragment.html
    ++++ b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v17.leanback.app.GuidedStepFragment.html
    +@@ -330,7 +330,7 @@ Class android.support.v17.leanback.app.<A HREF="../../../../reference/android/su
    +     </div> <!-- end footer -->
    +     </div><!-- end doc-content -->
    +     </div> <!-- end body-content --> 
    +-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    + </script>
    + <script type="text/javascript">
    +   try {
    +diff --git a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v17.leanback.app.GuidedStepSupportFragment.html b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v17.leanback.app.GuidedStepSupportFragment.html
    +index b464afa..c5f0d5a 100644
    +--- a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v17.leanback.app.GuidedStepSupportFragment.html
    ++++ b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v17.leanback.app.GuidedStepSupportFragment.html
    +@@ -330,7 +330,7 @@ Class android.support.v17.leanback.app.<A HREF="../../../../reference/android/su
    +     </div> <!-- end footer -->
    +     </div><!-- end doc-content -->
    +     </div> <!-- end body-content --> 
    +-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    + </script>
    + <script type="text/javascript">
    +   try {
    +diff --git a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v17.leanback.app.HeadersFragment.OnHeaderClickedListener.html b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v17.leanback.app.HeadersFragment.OnHeaderClickedListener.html
    +index 0df02c4..800f32b 100644
    +--- a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v17.leanback.app.HeadersFragment.OnHeaderClickedListener.html
    ++++ b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v17.leanback.app.HeadersFragment.OnHeaderClickedListener.html
    +@@ -112,7 +112,7 @@ Change in signature from <code>void</code> to (<code>ViewHolder, Row</code>).<br
    +     </div> <!-- end footer -->
    +     </div><!-- end doc-content -->
    +     </div> <!-- end body-content --> 
    +-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    + </script>
    + <script type="text/javascript">
    +   try {
    +diff --git a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v17.leanback.app.HeadersFragment.OnHeaderViewSelectedListener.html b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v17.leanback.app.HeadersFragment.OnHeaderViewSelectedListener.html
    +index cc2eeda..70ec556 100644
    +--- a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v17.leanback.app.HeadersFragment.OnHeaderViewSelectedListener.html
    ++++ b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v17.leanback.app.HeadersFragment.OnHeaderViewSelectedListener.html
    +@@ -94,7 +94,7 @@ Interface android.support.v17.leanback.app.<A HREF="../../../../reference/androi
    +     </div> <!-- end footer -->
    +     </div><!-- end doc-content -->
    +     </div> <!-- end body-content --> 
    +-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    + </script>
    + <script type="text/javascript">
    +   try {
    +diff --git a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v17.leanback.app.HeadersSupportFragment.OnHeaderClickedListener.html b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v17.leanback.app.HeadersSupportFragment.OnHeaderClickedListener.html
    +index 0c59abd..ee37373 100644
    +--- a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v17.leanback.app.HeadersSupportFragment.OnHeaderClickedListener.html
    ++++ b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v17.leanback.app.HeadersSupportFragment.OnHeaderClickedListener.html
    +@@ -112,7 +112,7 @@ Change in signature from <code>void</code> to (<code>ViewHolder, Row</code>).<br
    +     </div> <!-- end footer -->
    +     </div><!-- end doc-content -->
    +     </div> <!-- end body-content --> 
    +-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    + </script>
    + <script type="text/javascript">
    +   try {
    +diff --git a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v17.leanback.app.HeadersSupportFragment.OnHeaderViewSelectedListener.html b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v17.leanback.app.HeadersSupportFragment.OnHeaderViewSelectedListener.html
    +index ee27726..99e380d 100644
    +--- a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v17.leanback.app.HeadersSupportFragment.OnHeaderViewSelectedListener.html
    ++++ b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v17.leanback.app.HeadersSupportFragment.OnHeaderViewSelectedListener.html
    +@@ -94,7 +94,7 @@ Interface android.support.v17.leanback.app.<A HREF="../../../../reference/androi
    +     </div> <!-- end footer -->
    +     </div><!-- end doc-content -->
    +     </div> <!-- end body-content --> 
    +-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    + </script>
    + <script type="text/javascript">
    +   try {
    +diff --git a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v17.leanback.app.RowsFragment.html b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v17.leanback.app.RowsFragment.html
    +index 612c05a..7c78322 100644
    +--- a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v17.leanback.app.RowsFragment.html
    ++++ b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v17.leanback.app.RowsFragment.html
    +@@ -115,7 +115,7 @@ Class android.support.v17.leanback.app.<A HREF="../../../../reference/android/su
    +     </div> <!-- end footer -->
    +     </div><!-- end doc-content -->
    +     </div> <!-- end body-content --> 
    +-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    + </script>
    + <script type="text/javascript">
    +   try {
    +diff --git a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v17.leanback.app.RowsSupportFragment.html b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v17.leanback.app.RowsSupportFragment.html
    +index 7cbdf0c..a112b19 100644
    +--- a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v17.leanback.app.RowsSupportFragment.html
    ++++ b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v17.leanback.app.RowsSupportFragment.html
    +@@ -115,7 +115,7 @@ Class android.support.v17.leanback.app.<A HREF="../../../../reference/android/su
    +     </div> <!-- end footer -->
    +     </div><!-- end doc-content -->
    +     </div> <!-- end body-content --> 
    +-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    + </script>
    + <script type="text/javascript">
    +   try {
    +diff --git a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v17.leanback.widget.DetailsOverviewLogoPresenter.ViewHolder.html b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v17.leanback.widget.DetailsOverviewLogoPresenter.ViewHolder.html
    +index 674231e..ef74a40 100644
    +--- a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v17.leanback.widget.DetailsOverviewLogoPresenter.ViewHolder.html
    ++++ b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v17.leanback.widget.DetailsOverviewLogoPresenter.ViewHolder.html
    +@@ -129,7 +129,7 @@ Class android.support.v17.leanback.widget.<A HREF="../../../../reference/android
    +     </div> <!-- end footer -->
    +     </div><!-- end doc-content -->
    +     </div> <!-- end body-content --> 
    +-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    + </script>
    + <script type="text/javascript">
    +   try {
    +diff --git a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v17.leanback.widget.DetailsOverviewLogoPresenter.html b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v17.leanback.widget.DetailsOverviewLogoPresenter.html
    +index 74e170c..05a2205 100644
    +--- a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v17.leanback.widget.DetailsOverviewLogoPresenter.html
    ++++ b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v17.leanback.widget.DetailsOverviewLogoPresenter.html
    +@@ -108,7 +108,7 @@ Class android.support.v17.leanback.widget.<A HREF="../../../../reference/android
    +     </div> <!-- end footer -->
    +     </div><!-- end doc-content -->
    +     </div> <!-- end body-content --> 
    +-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    + </script>
    + <script type="text/javascript">
    +   try {
    +diff --git a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v17.leanback.widget.GuidanceStylist.html b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v17.leanback.widget.GuidanceStylist.html
    +index 0a20eb4..f67942e 100644
    +--- a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v17.leanback.widget.GuidanceStylist.html
    ++++ b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v17.leanback.widget.GuidanceStylist.html
    +@@ -108,7 +108,7 @@ Class android.support.v17.leanback.widget.<A HREF="../../../../reference/android
    +     </div> <!-- end footer -->
    +     </div><!-- end doc-content -->
    +     </div> <!-- end body-content --> 
    +-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    + </script>
    + <script type="text/javascript">
    +   try {
    +diff --git a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v17.leanback.widget.GuidedAction.Builder.html b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v17.leanback.widget.GuidedAction.Builder.html
    +index b77684b..4d1d86b 100644
    +--- a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v17.leanback.widget.GuidedAction.Builder.html
    ++++ b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v17.leanback.widget.GuidedAction.Builder.html
    +@@ -281,7 +281,7 @@ Change in return type from <code>Builder</code> to <code>B</code>.<br>
    +     </div> <!-- end footer -->
    +     </div><!-- end doc-content -->
    +     </div> <!-- end body-content --> 
    +-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    + </script>
    + <script type="text/javascript">
    +   try {
    +diff --git a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v17.leanback.widget.GuidedAction.html b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v17.leanback.widget.GuidedAction.html
    +index 20165c7..2ce2773 100644
    +--- a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v17.leanback.widget.GuidedAction.html
    ++++ b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v17.leanback.widget.GuidedAction.html
    +@@ -307,7 +307,7 @@ Class android.support.v17.leanback.widget.<A HREF="../../../../reference/android
    +     </div> <!-- end footer -->
    +     </div><!-- end doc-content -->
    +     </div> <!-- end body-content --> 
    +-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    + </script>
    + <script type="text/javascript">
    +   try {
    +diff --git a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v17.leanback.widget.GuidedActionsStylist.ViewHolder.html b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v17.leanback.widget.GuidedActionsStylist.ViewHolder.html
    +index 0849383..b9b78cb 100644
    +--- a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v17.leanback.widget.GuidedActionsStylist.ViewHolder.html
    ++++ b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v17.leanback.widget.GuidedActionsStylist.ViewHolder.html
    +@@ -195,7 +195,7 @@ Class android.support.v17.leanback.widget.<A HREF="../../../../reference/android
    +     </div> <!-- end footer -->
    +     </div><!-- end doc-content -->
    +     </div> <!-- end body-content --> 
    +-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    + </script>
    + <script type="text/javascript">
    +   try {
    +diff --git a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v17.leanback.widget.GuidedActionsStylist.html b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v17.leanback.widget.GuidedActionsStylist.html
    +index a8dff6f..fbe6bb4 100644
    +--- a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v17.leanback.widget.GuidedActionsStylist.html
    ++++ b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v17.leanback.widget.GuidedActionsStylist.html
    +@@ -306,7 +306,7 @@ Class android.support.v17.leanback.widget.<A HREF="../../../../reference/android
    +     </div> <!-- end footer -->
    +     </div><!-- end doc-content -->
    +     </div> <!-- end body-content --> 
    +-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    + </script>
    + <script type="text/javascript">
    +   try {
    +diff --git a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v17.leanback.widget.ImageCardView.html b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v17.leanback.widget.ImageCardView.html
    +index f110a16..dde52dd 100644
    +--- a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v17.leanback.widget.ImageCardView.html
    ++++ b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v17.leanback.widget.ImageCardView.html
    +@@ -111,7 +111,7 @@ Class android.support.v17.leanback.widget.<A HREF="../../../../reference/android
    +     </div> <!-- end footer -->
    +     </div><!-- end doc-content -->
    +     </div> <!-- end body-content --> 
    +-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    + </script>
    + <script type="text/javascript">
    +   try {
    +diff --git a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v17.leanback.widget.ListRowPresenter.ViewHolder.html b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v17.leanback.widget.ListRowPresenter.ViewHolder.html
    +index 2207a6d..9aadb33 100644
    +--- a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v17.leanback.widget.ListRowPresenter.ViewHolder.html
    ++++ b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v17.leanback.widget.ListRowPresenter.ViewHolder.html
    +@@ -115,7 +115,7 @@ Class android.support.v17.leanback.widget.<A HREF="../../../../reference/android
    +     </div> <!-- end footer -->
    +     </div><!-- end doc-content -->
    +     </div> <!-- end body-content --> 
    +-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    + </script>
    + <script type="text/javascript">
    +   try {
    +diff --git a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.accessibilityservice.AccessibilityServiceInfoCompat.html b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.accessibilityservice.AccessibilityServiceInfoCompat.html
    +index 2479a86..4545dc6 100644
    +--- a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.accessibilityservice.AccessibilityServiceInfoCompat.html
    ++++ b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.accessibilityservice.AccessibilityServiceInfoCompat.html
    +@@ -94,7 +94,7 @@ Class android.support.v4.accessibilityservice.<A HREF="../../../../reference/and
    +     </div> <!-- end footer -->
    +     </div><!-- end doc-content -->
    +     </div> <!-- end body-content --> 
    +-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    + </script>
    + <script type="text/javascript">
    +   try {
    +diff --git a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.app.AppOpsManagerCompat.html b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.app.AppOpsManagerCompat.html
    +index 15ddb44..8d4b281 100644
    +--- a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.app.AppOpsManagerCompat.html
    ++++ b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.app.AppOpsManagerCompat.html
    +@@ -109,7 +109,7 @@ Class android.support.v4.app.<A HREF="../../../../reference/android/support/v4/a
    +     </div> <!-- end footer -->
    +     </div><!-- end doc-content -->
    +     </div> <!-- end body-content --> 
    +-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    + </script>
    + <script type="text/javascript">
    +   try {
    +diff --git a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.app.BundleCompat.html b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.app.BundleCompat.html
    +index 63ecf79..65cb6ce 100644
    +--- a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.app.BundleCompat.html
    ++++ b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.app.BundleCompat.html
    +@@ -109,7 +109,7 @@ Class android.support.v4.app.<A HREF="../../../../reference/android/support/v4/a
    +     </div> <!-- end footer -->
    +     </div><!-- end doc-content -->
    +     </div> <!-- end body-content --> 
    +-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    + </script>
    + <script type="text/javascript">
    +   try {
    +diff --git a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.app.Fragment.html b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.app.Fragment.html
    +index d6c9e88..adb8e8a 100644
    +--- a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.app.Fragment.html
    ++++ b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.app.Fragment.html
    +@@ -115,7 +115,7 @@ Class android.support.v4.app.<A HREF="../../../../reference/android/support/v4/a
    +     </div> <!-- end footer -->
    +     </div><!-- end doc-content -->
    +     </div> <!-- end body-content --> 
    +-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    + </script>
    + <script type="text/javascript">
    +   try {
    +diff --git a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.app.FragmentActivity.html b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.app.FragmentActivity.html
    +index 72bd4de..843cf68 100644
    +--- a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.app.FragmentActivity.html
    ++++ b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.app.FragmentActivity.html
    +@@ -108,7 +108,7 @@ Class android.support.v4.app.<A HREF="../../../../reference/android/support/v4/a
    +     </div> <!-- end footer -->
    +     </div><!-- end doc-content -->
    +     </div> <!-- end body-content --> 
    +-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    + </script>
    + <script type="text/javascript">
    +   try {
    +diff --git a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.app.FragmentHostCallback.html b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.app.FragmentHostCallback.html
    +index fcb311f..ca9cab8 100644
    +--- a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.app.FragmentHostCallback.html
    ++++ b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.app.FragmentHostCallback.html
    +@@ -108,7 +108,7 @@ Class android.support.v4.app.<A HREF="../../../../reference/android/support/v4/a
    +     </div> <!-- end footer -->
    +     </div><!-- end doc-content -->
    +     </div> <!-- end body-content --> 
    +-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    + </script>
    + <script type="text/javascript">
    +   try {
    +diff --git a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.app.NavUtils.html b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.app.NavUtils.html
    +index e4fb7fa..7267e50 100644
    +--- a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.app.NavUtils.html
    ++++ b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.app.NavUtils.html
    +@@ -94,7 +94,7 @@ Class android.support.v4.app.<A HREF="../../../../reference/android/support/v4/a
    +     </div> <!-- end footer -->
    +     </div><!-- end doc-content -->
    +     </div> <!-- end body-content --> 
    +-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    + </script>
    + <script type="text/javascript">
    +   try {
    +diff --git a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.app.NotificationManagerCompat.html b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.app.NotificationManagerCompat.html
    +index be48aac..06346b2 100644
    +--- a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.app.NotificationManagerCompat.html
    ++++ b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.app.NotificationManagerCompat.html
    +@@ -94,7 +94,7 @@ Class android.support.v4.app.<A HREF="../../../../reference/android/support/v4/a
    +     </div> <!-- end footer -->
    +     </div><!-- end doc-content -->
    +     </div> <!-- end body-content --> 
    +-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    + </script>
    + <script type="text/javascript">
    +   try {
    +diff --git a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.app.RemoteInput.html b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.app.RemoteInput.html
    +index a6a2a2d..006eeee 100644
    +--- a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.app.RemoteInput.html
    ++++ b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.app.RemoteInput.html
    +@@ -94,7 +94,7 @@ Class android.support.v4.app.<A HREF="../../../../reference/android/support/v4/a
    +     </div> <!-- end footer -->
    +     </div><!-- end doc-content -->
    +     </div> <!-- end body-content --> 
    +-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    + </script>
    + <script type="text/javascript">
    +   try {
    +diff --git a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.app.ServiceCompat.html b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.app.ServiceCompat.html
    +index c038e52..613affe 100644
    +--- a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.app.ServiceCompat.html
    ++++ b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.app.ServiceCompat.html
    +@@ -94,7 +94,7 @@ Class android.support.v4.app.<A HREF="../../../../reference/android/support/v4/a
    +     </div> <!-- end footer -->
    +     </div><!-- end doc-content -->
    +     </div> <!-- end body-content --> 
    +-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    + </script>
    + <script type="text/javascript">
    +   try {
    +diff --git a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.app.ShareCompat.html b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.app.ShareCompat.html
    +index 8e9c945..90c0630 100644
    +--- a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.app.ShareCompat.html
    ++++ b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.app.ShareCompat.html
    +@@ -109,7 +109,7 @@ Class android.support.v4.app.<A HREF="../../../../reference/android/support/v4/a
    +     </div> <!-- end footer -->
    +     </div><!-- end doc-content -->
    +     </div> <!-- end body-content --> 
    +-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    + </script>
    + <script type="text/javascript">
    +   try {
    +diff --git a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.app.TaskStackBuilder.html b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.app.TaskStackBuilder.html
    +index 8a8a3c7..12d44de 100644
    +--- a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.app.TaskStackBuilder.html
    ++++ b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.app.TaskStackBuilder.html
    +@@ -94,7 +94,7 @@ Class android.support.v4.app.<A HREF="../../../../reference/android/support/v4/a
    +     </div> <!-- end footer -->
    +     </div><!-- end doc-content -->
    +     </div> <!-- end body-content --> 
    +-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    + </script>
    + <script type="text/javascript">
    +   try {
    +diff --git a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.content.ContentResolverCompat.html b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.content.ContentResolverCompat.html
    +index 6abd31a..37ab80d 100644
    +--- a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.content.ContentResolverCompat.html
    ++++ b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.content.ContentResolverCompat.html
    +@@ -94,7 +94,7 @@ Class android.support.v4.content.<A HREF="../../../../reference/android/support/
    +     </div> <!-- end footer -->
    +     </div><!-- end doc-content -->
    +     </div> <!-- end body-content --> 
    +-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    + </script>
    + <script type="text/javascript">
    +   try {
    +diff --git a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.content.ContextCompat.html b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.content.ContextCompat.html
    +index c0abad2..92f9469 100644
    +--- a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.content.ContextCompat.html
    ++++ b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.content.ContextCompat.html
    +@@ -111,7 +111,7 @@ Change from non-static to static.<br> Change from final to non-final.<br>
    +     </div> <!-- end footer -->
    +     </div><!-- end doc-content -->
    +     </div> <!-- end body-content --> 
    +-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    + </script>
    + <script type="text/javascript">
    +   try {
    +diff --git a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.content.IntentCompat.html b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.content.IntentCompat.html
    +index 707b2de..37a8b42 100644
    +--- a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.content.IntentCompat.html
    ++++ b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.content.IntentCompat.html
    +@@ -94,7 +94,7 @@ Class android.support.v4.content.<A HREF="../../../../reference/android/support/
    +     </div> <!-- end footer -->
    +     </div><!-- end doc-content -->
    +     </div> <!-- end body-content --> 
    +-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    + </script>
    + <script type="text/javascript">
    +   try {
    +diff --git a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.content.LocalBroadcastManager.html b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.content.LocalBroadcastManager.html
    +index fb0f8eb..a3d8f89 100644
    +--- a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.content.LocalBroadcastManager.html
    ++++ b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.content.LocalBroadcastManager.html
    +@@ -94,7 +94,7 @@ Class android.support.v4.content.<A HREF="../../../../reference/android/support/
    +     </div> <!-- end footer -->
    +     </div><!-- end doc-content -->
    +     </div> <!-- end body-content --> 
    +-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    + </script>
    + <script type="text/javascript">
    +   try {
    +diff --git a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.content.ParallelExecutorCompat.html b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.content.ParallelExecutorCompat.html
    +index 135c65a..3dd3598 100644
    +--- a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.content.ParallelExecutorCompat.html
    ++++ b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.content.ParallelExecutorCompat.html
    +@@ -109,7 +109,7 @@ Class android.support.v4.content.<A HREF="../../../../reference/android/support/
    +     </div> <!-- end footer -->
    +     </div><!-- end doc-content -->
    +     </div> <!-- end body-content --> 
    +-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    + </script>
    + <script type="text/javascript">
    +   try {
    +diff --git a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.content.SharedPreferencesCompat.EditorCompat.html b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.content.SharedPreferencesCompat.EditorCompat.html
    +index 2a46cc8..5159fec 100644
    +--- a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.content.SharedPreferencesCompat.EditorCompat.html
    ++++ b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.content.SharedPreferencesCompat.EditorCompat.html
    +@@ -94,7 +94,7 @@ Class android.support.v4.content.<A HREF="../../../../reference/android/support/
    +     </div> <!-- end footer -->
    +     </div><!-- end doc-content -->
    +     </div> <!-- end body-content --> 
    +-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    + </script>
    + <script type="text/javascript">
    +   try {
    +diff --git a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.content.SharedPreferencesCompat.html b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.content.SharedPreferencesCompat.html
    +index 99e7e84..3c4513a 100644
    +--- a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.content.SharedPreferencesCompat.html
    ++++ b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.content.SharedPreferencesCompat.html
    +@@ -109,7 +109,7 @@ Class android.support.v4.content.<A HREF="../../../../reference/android/support/
    +     </div> <!-- end footer -->
    +     </div><!-- end doc-content -->
    +     </div> <!-- end body-content --> 
    +-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    + </script>
    + <script type="text/javascript">
    +   try {
    +diff --git a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.content.pm.ActivityInfoCompat.html b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.content.pm.ActivityInfoCompat.html
    +index 201f6e2..1fa3936 100644
    +--- a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.content.pm.ActivityInfoCompat.html
    ++++ b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.content.pm.ActivityInfoCompat.html
    +@@ -94,7 +94,7 @@ Class android.support.v4.content.pm.<A HREF="../../../../reference/android/suppo
    +     </div> <!-- end footer -->
    +     </div><!-- end doc-content -->
    +     </div> <!-- end body-content --> 
    +-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    + </script>
    + <script type="text/javascript">
    +   try {
    +diff --git a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.content.res.ResourcesCompat.html b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.content.res.ResourcesCompat.html
    +index 497d73b..77e6d43 100644
    +--- a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.content.res.ResourcesCompat.html
    ++++ b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.content.res.ResourcesCompat.html
    +@@ -137,7 +137,7 @@ Change from non-static to static.<br>
    +     </div> <!-- end footer -->
    +     </div><!-- end doc-content -->
    +     </div> <!-- end body-content --> 
    +-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    + </script>
    + <script type="text/javascript">
    +   try {
    +diff --git a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.database.DatabaseUtilsCompat.html b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.database.DatabaseUtilsCompat.html
    +index 0feb04b..90a5d72 100644
    +--- a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.database.DatabaseUtilsCompat.html
    ++++ b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.database.DatabaseUtilsCompat.html
    +@@ -94,7 +94,7 @@ Class android.support.v4.database.<A HREF="../../../../reference/android/support
    +     </div> <!-- end footer -->
    +     </div><!-- end doc-content -->
    +     </div> <!-- end body-content --> 
    +-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    + </script>
    + <script type="text/javascript">
    +   try {
    +diff --git a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.graphics.BitmapCompat.html b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.graphics.BitmapCompat.html
    +index 3b50f8e..912d5ee 100644
    +--- a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.graphics.BitmapCompat.html
    ++++ b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.graphics.BitmapCompat.html
    +@@ -109,7 +109,7 @@ Class android.support.v4.graphics.<A HREF="../../../../reference/android/support
    +     </div> <!-- end footer -->
    +     </div><!-- end doc-content -->
    +     </div> <!-- end body-content --> 
    +-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    + </script>
    + <script type="text/javascript">
    +   try {
    +diff --git a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.graphics.ColorUtils.html b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.graphics.ColorUtils.html
    +index 68c2dce..1dfcdc5 100644
    +--- a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.graphics.ColorUtils.html
    ++++ b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.graphics.ColorUtils.html
    +@@ -186,7 +186,7 @@ Class android.support.v4.graphics.<A HREF="../../../../reference/android/support
    +     </div> <!-- end footer -->
    +     </div><!-- end doc-content -->
    +     </div> <!-- end body-content --> 
    +-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    + </script>
    + <script type="text/javascript">
    +   try {
    +diff --git a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.graphics.drawable.DrawableCompat.html b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.graphics.drawable.DrawableCompat.html
    +index 735909e..041cbfd 100644
    +--- a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.graphics.drawable.DrawableCompat.html
    ++++ b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.graphics.drawable.DrawableCompat.html
    +@@ -152,7 +152,7 @@ Class android.support.v4.graphics.drawable.<A HREF="../../../../reference/androi
    +     </div> <!-- end footer -->
    +     </div><!-- end doc-content -->
    +     </div> <!-- end body-content --> 
    +-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    + </script>
    + <script type="text/javascript">
    +   try {
    +diff --git a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.graphics.drawable.RoundedBitmapDrawableFactory.html b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.graphics.drawable.RoundedBitmapDrawableFactory.html
    +index f0e4cbf..2323bf0 100644
    +--- a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.graphics.drawable.RoundedBitmapDrawableFactory.html
    ++++ b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.graphics.drawable.RoundedBitmapDrawableFactory.html
    +@@ -109,7 +109,7 @@ Class android.support.v4.graphics.drawable.<A HREF="../../../../reference/androi
    +     </div> <!-- end footer -->
    +     </div><!-- end doc-content -->
    +     </div> <!-- end body-content --> 
    +-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    + </script>
    + <script type="text/javascript">
    +   try {
    +diff --git a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.hardware.fingerprint.FingerprintManagerCompat.html b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.hardware.fingerprint.FingerprintManagerCompat.html
    +index 3c5e74d..8a49a32 100644
    +--- a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.hardware.fingerprint.FingerprintManagerCompat.html
    ++++ b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.hardware.fingerprint.FingerprintManagerCompat.html
    +@@ -94,7 +94,7 @@ Class android.support.v4.hardware.fingerprint.<A HREF="../../../../reference/and
    +     </div> <!-- end footer -->
    +     </div><!-- end doc-content -->
    +     </div> <!-- end body-content --> 
    +-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    + </script>
    + <script type="text/javascript">
    +   try {
    +diff --git a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.net.ConnectivityManagerCompat.html b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.net.ConnectivityManagerCompat.html
    +index 585fbe1..45e77fa 100644
    +--- a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.net.ConnectivityManagerCompat.html
    ++++ b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.net.ConnectivityManagerCompat.html
    +@@ -109,7 +109,7 @@ Class android.support.v4.net.<A HREF="../../../../reference/android/support/v4/n
    +     </div> <!-- end footer -->
    +     </div><!-- end doc-content -->
    +     </div> <!-- end body-content --> 
    +-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    + </script>
    + <script type="text/javascript">
    +   try {
    +diff --git a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.net.TrafficStatsCompat.html b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.net.TrafficStatsCompat.html
    +index d8d8d74..89403e7 100644
    +--- a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.net.TrafficStatsCompat.html
    ++++ b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.net.TrafficStatsCompat.html
    +@@ -109,7 +109,7 @@ Class android.support.v4.net.<A HREF="../../../../reference/android/support/v4/n
    +     </div> <!-- end footer -->
    +     </div><!-- end doc-content -->
    +     </div> <!-- end body-content --> 
    +-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    + </script>
    + <script type="text/javascript">
    +   try {
    +diff --git a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.os.AsyncTaskCompat.html b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.os.AsyncTaskCompat.html
    +index 0ea4b47..fcde361 100644
    +--- a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.os.AsyncTaskCompat.html
    ++++ b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.os.AsyncTaskCompat.html
    +@@ -109,7 +109,7 @@ Class android.support.v4.os.<A HREF="../../../../reference/android/support/v4/os
    +     </div> <!-- end footer -->
    +     </div><!-- end doc-content -->
    +     </div> <!-- end body-content --> 
    +-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    + </script>
    + <script type="text/javascript">
    +   try {
    +diff --git a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.os.EnvironmentCompat.html b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.os.EnvironmentCompat.html
    +index 4d625b1..914f3f0 100644
    +--- a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.os.EnvironmentCompat.html
    ++++ b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.os.EnvironmentCompat.html
    +@@ -109,7 +109,7 @@ Class android.support.v4.os.<A HREF="../../../../reference/android/support/v4/os
    +     </div> <!-- end footer -->
    +     </div><!-- end doc-content -->
    +     </div> <!-- end body-content --> 
    +-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    + </script>
    + <script type="text/javascript">
    +   try {
    +diff --git a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.os.ParcelableCompat.html b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.os.ParcelableCompat.html
    +index 0192ed6..8933edd 100644
    +--- a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.os.ParcelableCompat.html
    ++++ b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.os.ParcelableCompat.html
    +@@ -109,7 +109,7 @@ Class android.support.v4.os.<A HREF="../../../../reference/android/support/v4/os
    +     </div> <!-- end footer -->
    +     </div><!-- end doc-content -->
    +     </div> <!-- end body-content --> 
    +-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    + </script>
    + <script type="text/javascript">
    +   try {
    +diff --git a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.os.TraceCompat.html b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.os.TraceCompat.html
    +index 3f490ba..8778c2e4 100644
    +--- a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.os.TraceCompat.html
    ++++ b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.os.TraceCompat.html
    +@@ -109,7 +109,7 @@ Class android.support.v4.os.<A HREF="../../../../reference/android/support/v4/os
    +     </div> <!-- end footer -->
    +     </div><!-- end doc-content -->
    +     </div> <!-- end body-content --> 
    +-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    + </script>
    + <script type="text/javascript">
    +   try {
    +diff --git a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.text.ICUCompat.html b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.text.ICUCompat.html
    +index 2b97440..c4ea966 100644
    +--- a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.text.ICUCompat.html
    ++++ b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.text.ICUCompat.html
    +@@ -109,7 +109,7 @@ Class android.support.v4.text.<A HREF="../../../../reference/android/support/v4/
    +     </div> <!-- end footer -->
    +     </div><!-- end doc-content -->
    +     </div> <!-- end body-content --> 
    +-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    + </script>
    + <script type="text/javascript">
    +   try {
    +diff --git a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.text.TextDirectionHeuristicsCompat.html b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.text.TextDirectionHeuristicsCompat.html
    +index 45557e1..351a162 100644
    +--- a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.text.TextDirectionHeuristicsCompat.html
    ++++ b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.text.TextDirectionHeuristicsCompat.html
    +@@ -109,7 +109,7 @@ Class android.support.v4.text.<A HREF="../../../../reference/android/support/v4/
    +     </div> <!-- end footer -->
    +     </div><!-- end doc-content -->
    +     </div> <!-- end body-content --> 
    +-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    + </script>
    + <script type="text/javascript">
    +   try {
    +diff --git a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.text.TextUtilsCompat.html b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.text.TextUtilsCompat.html
    +index 16d0835..d3ab7ce 100644
    +--- a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.text.TextUtilsCompat.html
    ++++ b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.text.TextUtilsCompat.html
    +@@ -109,7 +109,7 @@ Class android.support.v4.text.<A HREF="../../../../reference/android/support/v4/
    +     </div> <!-- end footer -->
    +     </div><!-- end doc-content -->
    +     </div> <!-- end body-content --> 
    +-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    + </script>
    + <script type="text/javascript">
    +   try {
    +diff --git a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.view.GestureDetectorCompat.html b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.view.GestureDetectorCompat.html
    +index 5c0463d..e66c261 100644
    +--- a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.view.GestureDetectorCompat.html
    ++++ b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.view.GestureDetectorCompat.html
    +@@ -94,7 +94,7 @@ Class android.support.v4.view.<A HREF="../../../../reference/android/support/v4/
    +     </div> <!-- end footer -->
    +     </div><!-- end doc-content -->
    +     </div> <!-- end body-content --> 
    +-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    + </script>
    + <script type="text/javascript">
    +   try {
    +diff --git a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.view.GravityCompat.html b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.view.GravityCompat.html
    +index 9ee14c5..95c665e 100644
    +--- a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.view.GravityCompat.html
    ++++ b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.view.GravityCompat.html
    +@@ -109,7 +109,7 @@ Class android.support.v4.view.<A HREF="../../../../reference/android/support/v4/
    +     </div> <!-- end footer -->
    +     </div><!-- end doc-content -->
    +     </div> <!-- end body-content --> 
    +-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    + </script>
    + <script type="text/javascript">
    +   try {
    +diff --git a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.view.InputDeviceCompat.html b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.view.InputDeviceCompat.html
    +index 4a7f385..38a1cd8 100644
    +--- a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.view.InputDeviceCompat.html
    ++++ b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.view.InputDeviceCompat.html
    +@@ -109,7 +109,7 @@ Class android.support.v4.view.<A HREF="../../../../reference/android/support/v4/
    +     </div> <!-- end footer -->
    +     </div><!-- end doc-content -->
    +     </div> <!-- end body-content --> 
    +-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    + </script>
    + <script type="text/javascript">
    +   try {
    +diff --git a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.view.KeyEventCompat.html b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.view.KeyEventCompat.html
    +index 49526ab..58692a9 100644
    +--- a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.view.KeyEventCompat.html
    ++++ b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.view.KeyEventCompat.html
    +@@ -109,7 +109,7 @@ Class android.support.v4.view.<A HREF="../../../../reference/android/support/v4/
    +     </div> <!-- end footer -->
    +     </div><!-- end doc-content -->
    +     </div> <!-- end body-content --> 
    +-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    + </script>
    + <script type="text/javascript">
    +   try {
    +diff --git a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.view.LayoutInflaterCompat.html b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.view.LayoutInflaterCompat.html
    +index 7329ff7..b62e876 100644
    +--- a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.view.LayoutInflaterCompat.html
    ++++ b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.view.LayoutInflaterCompat.html
    +@@ -109,7 +109,7 @@ Class android.support.v4.view.<A HREF="../../../../reference/android/support/v4/
    +     </div> <!-- end footer -->
    +     </div><!-- end doc-content -->
    +     </div> <!-- end body-content --> 
    +-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    + </script>
    + <script type="text/javascript">
    +   try {
    +diff --git a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.view.MarginLayoutParamsCompat.html b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.view.MarginLayoutParamsCompat.html
    +index 86a7b57..444980d 100644
    +--- a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.view.MarginLayoutParamsCompat.html
    ++++ b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.view.MarginLayoutParamsCompat.html
    +@@ -109,7 +109,7 @@ Class android.support.v4.view.<A HREF="../../../../reference/android/support/v4/
    +     </div> <!-- end footer -->
    +     </div><!-- end doc-content -->
    +     </div> <!-- end body-content --> 
    +-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    + </script>
    + <script type="text/javascript">
    +   try {
    +diff --git a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.view.MenuCompat.html b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.view.MenuCompat.html
    +index 22ead5e..17b8b7d 100644
    +--- a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.view.MenuCompat.html
    ++++ b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.view.MenuCompat.html
    +@@ -109,7 +109,7 @@ Class android.support.v4.view.<A HREF="../../../../reference/android/support/v4/
    +     </div> <!-- end footer -->
    +     </div><!-- end doc-content -->
    +     </div> <!-- end body-content --> 
    +-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    + </script>
    + <script type="text/javascript">
    +   try {
    +diff --git a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.view.MenuItemCompat.html b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.view.MenuItemCompat.html
    +index a321ac3..415dae2 100644
    +--- a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.view.MenuItemCompat.html
    ++++ b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.view.MenuItemCompat.html
    +@@ -109,7 +109,7 @@ Class android.support.v4.view.<A HREF="../../../../reference/android/support/v4/
    +     </div> <!-- end footer -->
    +     </div><!-- end doc-content -->
    +     </div> <!-- end body-content --> 
    +-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    + </script>
    + <script type="text/javascript">
    +   try {
    +diff --git a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.view.MotionEventCompat.html b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.view.MotionEventCompat.html
    +index cb8895d..c1f81ba 100644
    +--- a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.view.MotionEventCompat.html
    ++++ b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.view.MotionEventCompat.html
    +@@ -109,7 +109,7 @@ Class android.support.v4.view.<A HREF="../../../../reference/android/support/v4/
    +     </div> <!-- end footer -->
    +     </div><!-- end doc-content -->
    +     </div> <!-- end body-content --> 
    +-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    + </script>
    + <script type="text/javascript">
    +   try {
    +diff --git a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.view.ScaleGestureDetectorCompat.html b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.view.ScaleGestureDetectorCompat.html
    +index 23f8718..8733e6b 100644
    +--- a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.view.ScaleGestureDetectorCompat.html
    ++++ b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.view.ScaleGestureDetectorCompat.html
    +@@ -94,7 +94,7 @@ Class android.support.v4.view.<A HREF="../../../../reference/android/support/v4/
    +     </div> <!-- end footer -->
    +     </div><!-- end doc-content -->
    +     </div> <!-- end body-content --> 
    +-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    + </script>
    + <script type="text/javascript">
    +   try {
    +diff --git a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.view.VelocityTrackerCompat.html b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.view.VelocityTrackerCompat.html
    +index 31a2b66..078bb96 100644
    +--- a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.view.VelocityTrackerCompat.html
    ++++ b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.view.VelocityTrackerCompat.html
    +@@ -109,7 +109,7 @@ Class android.support.v4.view.<A HREF="../../../../reference/android/support/v4/
    +     </div> <!-- end footer -->
    +     </div><!-- end doc-content -->
    +     </div> <!-- end body-content --> 
    +-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    + </script>
    + <script type="text/javascript">
    +   try {
    +diff --git a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.view.ViewCompat.html b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.view.ViewCompat.html
    +index bbfebc1..0647acb 100644
    +--- a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.view.ViewCompat.html
    ++++ b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.view.ViewCompat.html
    +@@ -109,7 +109,7 @@ Class android.support.v4.view.<A HREF="../../../../reference/android/support/v4/
    +     </div> <!-- end footer -->
    +     </div><!-- end doc-content -->
    +     </div> <!-- end body-content --> 
    +-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    + </script>
    + <script type="text/javascript">
    +   try {
    +diff --git a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.view.ViewConfigurationCompat.html b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.view.ViewConfigurationCompat.html
    +index 3deb282..0721e0c 100644
    +--- a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.view.ViewConfigurationCompat.html
    ++++ b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.view.ViewConfigurationCompat.html
    +@@ -109,7 +109,7 @@ Class android.support.v4.view.<A HREF="../../../../reference/android/support/v4/
    +     </div> <!-- end footer -->
    +     </div><!-- end doc-content -->
    +     </div> <!-- end body-content --> 
    +-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    + </script>
    + <script type="text/javascript">
    +   try {
    +diff --git a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.view.ViewGroupCompat.html b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.view.ViewGroupCompat.html
    +index 973f25d..7c3f280 100644
    +--- a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.view.ViewGroupCompat.html
    ++++ b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.view.ViewGroupCompat.html
    +@@ -94,7 +94,7 @@ Class android.support.v4.view.<A HREF="../../../../reference/android/support/v4/
    +     </div> <!-- end footer -->
    +     </div><!-- end doc-content -->
    +     </div> <!-- end body-content --> 
    +-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    + </script>
    + <script type="text/javascript">
    +   try {
    +diff --git a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.view.ViewParentCompat.html b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.view.ViewParentCompat.html
    +index 0ff6977..186cdce 100644
    +--- a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.view.ViewParentCompat.html
    ++++ b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.view.ViewParentCompat.html
    +@@ -94,7 +94,7 @@ Class android.support.v4.view.<A HREF="../../../../reference/android/support/v4/
    +     </div> <!-- end footer -->
    +     </div><!-- end doc-content -->
    +     </div> <!-- end body-content --> 
    +-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    + </script>
    + <script type="text/javascript">
    +   try {
    +diff --git a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.view.ViewPropertyAnimatorCompat.html b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.view.ViewPropertyAnimatorCompat.html
    +index dcb75fc..7611f00 100644
    +--- a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.view.ViewPropertyAnimatorCompat.html
    ++++ b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.view.ViewPropertyAnimatorCompat.html
    +@@ -94,7 +94,7 @@ Class android.support.v4.view.<A HREF="../../../../reference/android/support/v4/
    +     </div> <!-- end footer -->
    +     </div><!-- end doc-content -->
    +     </div> <!-- end body-content --> 
    +-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    + </script>
    + <script type="text/javascript">
    +   try {
    +diff --git a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.view.WindowCompat.html b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.view.WindowCompat.html
    +index a9711fa..bf16942a 100644
    +--- a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.view.WindowCompat.html
    ++++ b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.view.WindowCompat.html
    +@@ -109,7 +109,7 @@ Class android.support.v4.view.<A HREF="../../../../reference/android/support/v4/
    +     </div> <!-- end footer -->
    +     </div><!-- end doc-content -->
    +     </div> <!-- end body-content --> 
    +-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    + </script>
    + <script type="text/javascript">
    +   try {
    +diff --git a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.view.accessibility.AccessibilityEventCompat.html b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.view.accessibility.AccessibilityEventCompat.html
    +index e2045d7..b9b15c8 100644
    +--- a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.view.accessibility.AccessibilityEventCompat.html
    ++++ b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.view.accessibility.AccessibilityEventCompat.html
    +@@ -94,7 +94,7 @@ Class android.support.v4.view.accessibility.<A HREF="../../../../reference/andro
    +     </div> <!-- end footer -->
    +     </div><!-- end doc-content -->
    +     </div> <!-- end body-content --> 
    +-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    + </script>
    + <script type="text/javascript">
    +   try {
    +diff --git a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.view.accessibility.AccessibilityManagerCompat.html b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.view.accessibility.AccessibilityManagerCompat.html
    +index d74f936..5180523 100644
    +--- a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.view.accessibility.AccessibilityManagerCompat.html
    ++++ b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.view.accessibility.AccessibilityManagerCompat.html
    +@@ -109,7 +109,7 @@ Class android.support.v4.view.accessibility.<A HREF="../../../../reference/andro
    +     </div> <!-- end footer -->
    +     </div><!-- end doc-content -->
    +     </div> <!-- end body-content --> 
    +-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    + </script>
    + <script type="text/javascript">
    +   try {
    +diff --git a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.view.animation.PathInterpolatorCompat.html b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.view.animation.PathInterpolatorCompat.html
    +index 6701f77..715f73f 100644
    +--- a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.view.animation.PathInterpolatorCompat.html
    ++++ b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.view.animation.PathInterpolatorCompat.html
    +@@ -94,7 +94,7 @@ Class android.support.v4.view.animation.<A HREF="../../../../reference/android/s
    +     </div> <!-- end footer -->
    +     </div><!-- end doc-content -->
    +     </div> <!-- end body-content --> 
    +-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    + </script>
    + <script type="text/javascript">
    +   try {
    +diff --git a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.widget.DrawerLayout.html b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.widget.DrawerLayout.html
    +index c2e7c83..f859501 100644
    +--- a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.widget.DrawerLayout.html
    ++++ b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.widget.DrawerLayout.html
    +@@ -148,7 +148,7 @@ Class android.support.v4.widget.<A HREF="../../../../reference/android/support/v
    +     </div> <!-- end footer -->
    +     </div><!-- end doc-content -->
    +     </div> <!-- end body-content --> 
    +-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    + </script>
    + <script type="text/javascript">
    +   try {
    +diff --git a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.widget.EdgeEffectCompat.html b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.widget.EdgeEffectCompat.html
    +index 6993bec..a476dfb 100644
    +--- a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.widget.EdgeEffectCompat.html
    ++++ b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.widget.EdgeEffectCompat.html
    +@@ -94,7 +94,7 @@ Class android.support.v4.widget.<A HREF="../../../../reference/android/support/v
    +     </div> <!-- end footer -->
    +     </div><!-- end doc-content -->
    +     </div> <!-- end body-content --> 
    +-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    + </script>
    + <script type="text/javascript">
    +   try {
    +diff --git a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.widget.ListPopupWindowCompat.html b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.widget.ListPopupWindowCompat.html
    +index fc5ed8d..243f6d2 100644
    +--- a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.widget.ListPopupWindowCompat.html
    ++++ b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.widget.ListPopupWindowCompat.html
    +@@ -94,7 +94,7 @@ Class android.support.v4.widget.<A HREF="../../../../reference/android/support/v
    +     </div> <!-- end footer -->
    +     </div><!-- end doc-content -->
    +     </div> <!-- end body-content --> 
    +-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    + </script>
    + <script type="text/javascript">
    +   try {
    +diff --git a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.widget.PopupMenuCompat.html b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.widget.PopupMenuCompat.html
    +index 1d55628..c3cca70 100644
    +--- a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.widget.PopupMenuCompat.html
    ++++ b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.widget.PopupMenuCompat.html
    +@@ -94,7 +94,7 @@ Class android.support.v4.widget.<A HREF="../../../../reference/android/support/v
    +     </div> <!-- end footer -->
    +     </div><!-- end doc-content -->
    +     </div> <!-- end body-content --> 
    +-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    + </script>
    + <script type="text/javascript">
    +   try {
    +diff --git a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.widget.PopupWindowCompat.html b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.widget.PopupWindowCompat.html
    +index 215118c..0523e9f 100644
    +--- a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.widget.PopupWindowCompat.html
    ++++ b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.widget.PopupWindowCompat.html
    +@@ -94,7 +94,7 @@ Class android.support.v4.widget.<A HREF="../../../../reference/android/support/v
    +     </div> <!-- end footer -->
    +     </div><!-- end doc-content -->
    +     </div> <!-- end body-content --> 
    +-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    + </script>
    + <script type="text/javascript">
    +   try {
    +diff --git a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.widget.ScrollerCompat.html b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.widget.ScrollerCompat.html
    +index ea76c92..f13086d 100644
    +--- a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.widget.ScrollerCompat.html
    ++++ b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.widget.ScrollerCompat.html
    +@@ -94,7 +94,7 @@ Class android.support.v4.widget.<A HREF="../../../../reference/android/support/v
    +     </div> <!-- end footer -->
    +     </div><!-- end doc-content -->
    +     </div> <!-- end body-content --> 
    +-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    + </script>
    + <script type="text/javascript">
    +   try {
    +diff --git a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.widget.SearchViewCompat.html b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.widget.SearchViewCompat.html
    +index ce5abd3..e3de11d 100644
    +--- a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.widget.SearchViewCompat.html
    ++++ b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.widget.SearchViewCompat.html
    +@@ -94,7 +94,7 @@ Class android.support.v4.widget.<A HREF="../../../../reference/android/support/v
    +     </div> <!-- end footer -->
    +     </div><!-- end doc-content -->
    +     </div> <!-- end body-content --> 
    +-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    + </script>
    + <script type="text/javascript">
    +   try {
    +diff --git a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.widget.TextViewCompat.html b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.widget.TextViewCompat.html
    +index e2078f4..e3a0f9a 100644
    +--- a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.widget.TextViewCompat.html
    ++++ b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.widget.TextViewCompat.html
    +@@ -109,7 +109,7 @@ Class android.support.v4.widget.<A HREF="../../../../reference/android/support/v
    +     </div> <!-- end footer -->
    +     </div><!-- end doc-content -->
    +     </div> <!-- end body-content --> 
    +-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    + </script>
    + <script type="text/javascript">
    +   try {
    +diff --git a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v7.app.AppCompatDelegate.html b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v7.app.AppCompatDelegate.html
    +index 6fd286c..2dbee43 100644
    +--- a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v7.app.AppCompatDelegate.html
    ++++ b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v7.app.AppCompatDelegate.html
    +@@ -172,7 +172,7 @@ Class android.support.v7.app.<A HREF="../../../../reference/android/support/v7/a
    +     </div> <!-- end footer -->
    +     </div><!-- end doc-content -->
    +     </div> <!-- end body-content --> 
    +-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    + </script>
    + <script type="text/javascript">
    +   try {
    +diff --git a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v7.appcompat.R.attr.html b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v7.appcompat.R.attr.html
    +index c399a8a..2a2364a 100644
    +--- a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v7.appcompat.R.attr.html
    ++++ b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v7.appcompat.R.attr.html
    +@@ -122,7 +122,7 @@ Class android.support.v7.appcompat.<A HREF="../../../../reference/android/suppor
    +     </div> <!-- end footer -->
    +     </div><!-- end doc-content -->
    +     </div> <!-- end body-content --> 
    +-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    + </script>
    + <script type="text/javascript">
    +   try {
    +diff --git a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v7.appcompat.R.drawable.html b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v7.appcompat.R.drawable.html
    +index ec1ee38..a2e1dc3 100644
    +--- a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v7.appcompat.R.drawable.html
    ++++ b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v7.appcompat.R.drawable.html
    +@@ -347,7 +347,7 @@ Class android.support.v7.appcompat.<A HREF="../../../../reference/android/suppor
    +     </div> <!-- end footer -->
    +     </div><!-- end doc-content -->
    +     </div> <!-- end body-content --> 
    +-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    + </script>
    + <script type="text/javascript">
    +   try {
    +diff --git a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v7.appcompat.R.style.html b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v7.appcompat.R.style.html
    +index 478d333..32befe4 100644
    +--- a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v7.appcompat.R.style.html
    ++++ b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v7.appcompat.R.style.html
    +@@ -178,7 +178,7 @@ Class android.support.v7.appcompat.<A HREF="../../../../reference/android/suppor
    +     </div> <!-- end footer -->
    +     </div><!-- end doc-content -->
    +     </div> <!-- end body-content --> 
    +-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    + </script>
    + <script type="text/javascript">
    +   try {
    +diff --git a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v7.appcompat.R.styleable.html b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v7.appcompat.R.styleable.html
    +index 498ec51..6433bc2 100644
    +--- a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v7.appcompat.R.styleable.html
    ++++ b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v7.appcompat.R.styleable.html
    +@@ -1705,7 +1705,7 @@ Class android.support.v7.appcompat.<A HREF="../../../../reference/android/suppor
    +     </div> <!-- end footer -->
    +     </div><!-- end doc-content -->
    +     </div> <!-- end body-content --> 
    +-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    + </script>
    + <script type="text/javascript">
    +   try {
    +diff --git a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v7.graphics.Palette.Builder.html b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v7.graphics.Palette.Builder.html
    +index 83f441b..2758189 100644
    +--- a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v7.graphics.Palette.Builder.html
    ++++ b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v7.graphics.Palette.Builder.html
    +@@ -140,7 +140,7 @@ Class android.support.v7.graphics.<A HREF="../../../../reference/android/support
    +     </div> <!-- end footer -->
    +     </div><!-- end doc-content -->
    +     </div> <!-- end body-content --> 
    +-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    + </script>
    + <script type="text/javascript">
    +   try {
    +diff --git a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v7.graphics.Palette.html b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v7.graphics.Palette.html
    +index be157a7..d7752f5 100644
    +--- a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v7.graphics.Palette.html
    ++++ b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v7.graphics.Palette.html
    +@@ -122,7 +122,7 @@ Class android.support.v7.graphics.<A HREF="../../../../reference/android/support
    +     </div> <!-- end footer -->
    +     </div><!-- end doc-content -->
    +     </div> <!-- end body-content --> 
    +-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    + </script>
    + <script type="text/javascript">
    +   try {
    +diff --git a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v7.media.MediaRouteDescriptor.Builder.html b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v7.media.MediaRouteDescriptor.Builder.html
    +index 7db6666..9181648 100644
    +--- a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v7.media.MediaRouteDescriptor.Builder.html
    ++++ b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v7.media.MediaRouteDescriptor.Builder.html
    +@@ -115,7 +115,7 @@ Class android.support.v7.media.<A HREF="../../../../reference/android/support/v7
    +     </div> <!-- end footer -->
    +     </div><!-- end doc-content -->
    +     </div> <!-- end body-content --> 
    +-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    + </script>
    + <script type="text/javascript">
    +   try {
    +diff --git a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v7.media.MediaRouteDescriptor.html b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v7.media.MediaRouteDescriptor.html
    +index 315ba3d..0cb71cf 100644
    +--- a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v7.media.MediaRouteDescriptor.html
    ++++ b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v7.media.MediaRouteDescriptor.html
    +@@ -108,7 +108,7 @@ Class android.support.v7.media.<A HREF="../../../../reference/android/support/v7
    +     </div> <!-- end footer -->
    +     </div><!-- end doc-content -->
    +     </div> <!-- end body-content --> 
    +-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    + </script>
    + <script type="text/javascript">
    +   try {
    +diff --git a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v7.media.MediaRouter.Callback.html b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v7.media.MediaRouter.Callback.html
    +index 66be68d..5d68006 100644
    +--- a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v7.media.MediaRouter.Callback.html
    ++++ b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v7.media.MediaRouter.Callback.html
    +@@ -108,7 +108,7 @@ Class android.support.v7.media.<A HREF="../../../../reference/android/support/v7
    +     </div> <!-- end footer -->
    +     </div><!-- end doc-content -->
    +     </div> <!-- end body-content --> 
    +-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    + </script>
    + <script type="text/javascript">
    +   try {
    +diff --git a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v7.preference.PreferenceFragmentCompat.html b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v7.preference.PreferenceFragmentCompat.html
    +index 68aa733..980ff0d 100644
    +--- a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v7.preference.PreferenceFragmentCompat.html
    ++++ b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v7.preference.PreferenceFragmentCompat.html
    +@@ -115,7 +115,7 @@ Class android.support.v7.preference.<A HREF="../../../../reference/android/suppo
    +     </div> <!-- end footer -->
    +     </div><!-- end doc-content -->
    +     </div> <!-- end body-content --> 
    +-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    + </script>
    + <script type="text/javascript">
    +   try {
    +diff --git a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v7.preference.PreferenceScreen.html b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v7.preference.PreferenceScreen.html
    +index 12de78c..de14ee0 100644
    +--- a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v7.preference.PreferenceScreen.html
    ++++ b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v7.preference.PreferenceScreen.html
    +@@ -115,7 +115,7 @@ Class android.support.v7.preference.<A HREF="../../../../reference/android/suppo
    +     </div> <!-- end footer -->
    +     </div><!-- end doc-content -->
    +     </div> <!-- end body-content --> 
    +-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    + </script>
    + <script type="text/javascript">
    +   try {
    +diff --git a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v7.preference.PreferenceViewHolder.html b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v7.preference.PreferenceViewHolder.html
    +index b27e66c..0597c2a 100644
    +--- a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v7.preference.PreferenceViewHolder.html
    ++++ b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v7.preference.PreferenceViewHolder.html
    +@@ -129,7 +129,7 @@ Class android.support.v7.preference.<A HREF="../../../../reference/android/suppo
    +     </div> <!-- end footer -->
    +     </div><!-- end doc-content -->
    +     </div> <!-- end body-content --> 
    +-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    + </script>
    + <script type="text/javascript">
    +   try {
    +diff --git a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v7.recyclerview.R.dimen.html b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v7.recyclerview.R.dimen.html
    +index b38c6dc..a56e112 100644
    +--- a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v7.recyclerview.R.dimen.html
    ++++ b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v7.recyclerview.R.dimen.html
    +@@ -115,7 +115,7 @@ Class android.support.v7.recyclerview.<A HREF="../../../../reference/android/sup
    +     </div> <!-- end footer -->
    +     </div><!-- end doc-content -->
    +     </div> <!-- end body-content --> 
    +-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    + </script>
    + <script type="text/javascript">
    +   try {
    +diff --git a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v7.widget.OrientationHelper.html b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v7.widget.OrientationHelper.html
    +index 6a2a9b3..9111877 100644
    +--- a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v7.widget.OrientationHelper.html
    ++++ b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v7.widget.OrientationHelper.html
    +@@ -115,7 +115,7 @@ Class android.support.v7.widget.<A HREF="../../../../reference/android/support/v
    +     </div> <!-- end footer -->
    +     </div><!-- end doc-content -->
    +     </div> <!-- end body-content --> 
    +-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    + </script>
    + <script type="text/javascript">
    +   try {
    +diff --git a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v7.widget.RecyclerView.ItemAnimator.html b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v7.widget.RecyclerView.ItemAnimator.html
    +index 95e642e..a641975 100644
    +--- a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v7.widget.RecyclerView.ItemAnimator.html
    ++++ b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v7.widget.RecyclerView.ItemAnimator.html
    +@@ -108,7 +108,7 @@ Class android.support.v7.widget.<A HREF="../../../../reference/android/support/v
    +     </div> <!-- end footer -->
    +     </div><!-- end doc-content -->
    +     </div> <!-- end body-content --> 
    +-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    + </script>
    + <script type="text/javascript">
    +   try {
    +diff --git a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v7.widget.RecyclerView.LayoutManager.html b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v7.widget.RecyclerView.LayoutManager.html
    +index 30b0a78..173d636 100644
    +--- a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v7.widget.RecyclerView.LayoutManager.html
    ++++ b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v7.widget.RecyclerView.LayoutManager.html
    +@@ -193,7 +193,7 @@ Class android.support.v7.widget.<A HREF="../../../../reference/android/support/v
    +     </div> <!-- end footer -->
    +     </div><!-- end doc-content -->
    +     </div> <!-- end body-content --> 
    +-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    + </script>
    + <script type="text/javascript">
    +   try {
    +diff --git a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v7.widget.RecyclerView.State.html b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v7.widget.RecyclerView.State.html
    +index 2b3ac61..86d91dc 100644
    +--- a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v7.widget.RecyclerView.State.html
    ++++ b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v7.widget.RecyclerView.State.html
    +@@ -108,7 +108,7 @@ Class android.support.v7.widget.<A HREF="../../../../reference/android/support/v
    +     </div> <!-- end footer -->
    +     </div><!-- end doc-content -->
    +     </div> <!-- end body-content --> 
    +-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    + </script>
    + <script type="text/javascript">
    +   try {
    +diff --git a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v7.widget.RecyclerView.html b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v7.widget.RecyclerView.html
    +index 5cdc7a0..a53430b 100644
    +--- a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v7.widget.RecyclerView.html
    ++++ b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v7.widget.RecyclerView.html
    +@@ -115,7 +115,7 @@ Class android.support.v7.widget.<A HREF="../../../../reference/android/support/v
    +     </div> <!-- end footer -->
    +     </div><!-- end doc-content -->
    +     </div> <!-- end body-content --> 
    +-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    + </script>
    + <script type="text/javascript">
    +   try {
    +diff --git a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v7.widget.helper.ItemTouchHelper.Callback.html b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v7.widget.helper.ItemTouchHelper.Callback.html
    +index 1237408..b241e6e 100644
    +--- a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v7.widget.helper.ItemTouchHelper.Callback.html
    ++++ b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v7.widget.helper.ItemTouchHelper.Callback.html
    +@@ -115,7 +115,7 @@ Class android.support.v7.widget.helper.<A HREF="../../../../reference/android/su
    +     </div> <!-- end footer -->
    +     </div><!-- end doc-content -->
    +     </div> <!-- end body-content --> 
    +-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    + </script>
    + <script type="text/javascript">
    +   try {
    +diff --git a/docs/html/sdk/support_api_diff/23.2.0/changes/changes-summary.html b/docs/html/sdk/support_api_diff/23.2.0/changes/changes-summary.html
    +index d41ec1f..431b2ae 100644
    +--- a/docs/html/sdk/support_api_diff/23.2.0/changes/changes-summary.html
    ++++ b/docs/html/sdk/support_api_diff/23.2.0/changes/changes-summary.html
    +@@ -352,7 +352,7 @@ see the <a href="http://developer.android.com/index.html" target="_top">Android
    +     </div> <!-- end footer -->
    +     </div><!-- end doc-content -->
    +     </div> <!-- end body-content --> 
    +-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    + </script>
    + <script type="text/javascript">
    +   try {
    +diff --git a/docs/html/sdk/support_api_diff/23.2.0/changes/classes_index_additions.html b/docs/html/sdk/support_api_diff/23.2.0/changes/classes_index_additions.html
    +index a2e1d44..eb0457c 100644
    +--- a/docs/html/sdk/support_api_diff/23.2.0/changes/classes_index_additions.html
    ++++ b/docs/html/sdk/support_api_diff/23.2.0/changes/classes_index_additions.html
    +@@ -143,7 +143,7 @@ Listed as: <span style="color:#069"><strong>Added</strong></span>,  <span style=
    + <p><div style="line-height:1.5em;color:black">
    + <A HREF="pkg_android.support.v17.leanback.widget.html#ViewHolderTask" class="hiddenlink" target="rightframe"><b><i>ViewHolderTask</i></b></A><br>
    + <A HREF="pkg_android.support.design.widget.html#VisibilityAwareImageButton" class="hiddenlink" target="rightframe"><b>VisibilityAwareImageButton</b></A><br>
    +-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    + </script>
    + <script type="text/javascript">
    +   try {
    +diff --git a/docs/html/sdk/support_api_diff/23/changes/alldiffs_index_additions.html b/docs/html/sdk/support_api_diff/23/changes/alldiffs_index_additions.html
    +index 78c94e1..c526b45 100644
    +--- a/docs/html/sdk/support_api_diff/23/changes/alldiffs_index_additions.html
    ++++ b/docs/html/sdk/support_api_diff/23/changes/alldiffs_index_additions.html
    +@@ -1128,7 +1128,7 @@ Listed as: <span style="color:#069"><strong>Added</strong></span>,  <span style=
    + <p><div style="line-height:1.5em;color:black">
    + <nobr><A HREF="android.support.v7.appcompat.R.style.html#android.support.v7.appcompat.R.style.Widget_AppCompat_Button_Colored" class="hiddenlink" target="rightframe">Widget_AppCompat_Button_Colored</A>
    + </nobr><br>
    +-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    + </script>
    + <script type="text/javascript">
    +   try {
    +diff --git a/docs/html/sdk/support_api_diff/23/changes/alldiffs_index_all.html b/docs/html/sdk/support_api_diff/23/changes/alldiffs_index_all.html
    +index f39d82e..61459ad 100644
    +--- a/docs/html/sdk/support_api_diff/23/changes/alldiffs_index_all.html
    ++++ b/docs/html/sdk/support_api_diff/23/changes/alldiffs_index_all.html
    +@@ -1457,7 +1457,7 @@ Listed as: <span style="color:#069"><strong>Added</strong></span>,  <span style=
    + <p><div style="line-height:1.5em;color:black">
    + <nobr><A HREF="android.support.v7.appcompat.R.style.html#android.support.v7.appcompat.R.style.Widget_AppCompat_Button_Colored" class="hiddenlink" target="rightframe">Widget_AppCompat_Button_Colored</A>
    + </nobr><br>
    +-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    + </script>
    + <script type="text/javascript">
    +   try {
    +diff --git a/docs/html/sdk/support_api_diff/23/changes/alldiffs_index_changes.html b/docs/html/sdk/support_api_diff/23/changes/alldiffs_index_changes.html
    +index debbb14..0a63a58 100644
    +--- a/docs/html/sdk/support_api_diff/23/changes/alldiffs_index_changes.html
    ++++ b/docs/html/sdk/support_api_diff/23/changes/alldiffs_index_changes.html
    +@@ -485,7 +485,7 @@ Listed as: <span style="color:#069"><strong>Added</strong></span>,  <span style=
    +  <a href="#topheader"><font size="-2">TOP</font></a>
    + <p><div style="line-height:1.5em;color:black">
    + <A HREF="android.support.v4.view.ViewCompat.html" class="hiddenlink" target="rightframe">ViewCompat</A><br>
    +-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    + </script>
    + <script type="text/javascript">
    +   try {
    +diff --git a/docs/html/sdk/support_api_diff/23/changes/alldiffs_index_removals.html b/docs/html/sdk/support_api_diff/23/changes/alldiffs_index_removals.html
    +index a6cdb59..9f13a01 100644
    +--- a/docs/html/sdk/support_api_diff/23/changes/alldiffs_index_removals.html
    ++++ b/docs/html/sdk/support_api_diff/23/changes/alldiffs_index_removals.html
    +@@ -332,7 +332,7 @@ Listed as: <span style="color:#069"><strong>Added</strong></span>,  <span style=
    + <!-- Field View_backgroundTintMode -->
    + <nobr><A HREF="android.support.v7.appcompat.R.styleable.html#android.support.v7.appcompat.R.styleable.View_backgroundTintMode" class="hiddenlink" target="rightframe"><strike>View_backgroundTintMode</strike></A>
    + </nobr><br>
    +-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    + </script>
    + <script type="text/javascript">
    +   try {
    +diff --git a/docs/html/sdk/support_api_diff/23/changes/android.support.design.widget.AppBarLayout.Behavior.html b/docs/html/sdk/support_api_diff/23/changes/android.support.design.widget.AppBarLayout.Behavior.html
    +index a6bbf2d..352dcfd 100644
    +--- a/docs/html/sdk/support_api_diff/23/changes/android.support.design.widget.AppBarLayout.Behavior.html
    ++++ b/docs/html/sdk/support_api_diff/23/changes/android.support.design.widget.AppBarLayout.Behavior.html
    +@@ -115,7 +115,7 @@ Class android.support.design.widget.<A HREF="../../../../reference/android/suppo
    +     </div> <!-- end footer -->
    +     </div><!-- end doc-content -->
    +     </div> <!-- end body-content --> 
    +-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    + </script>
    + <script type="text/javascript">
    +   try {
    +diff --git a/docs/html/sdk/support_api_diff/23/changes/android.support.design.widget.AppBarLayout.html b/docs/html/sdk/support_api_diff/23/changes/android.support.design.widget.AppBarLayout.html
    +index 71e3167..cd2a11f 100644
    +--- a/docs/html/sdk/support_api_diff/23/changes/android.support.design.widget.AppBarLayout.html
    ++++ b/docs/html/sdk/support_api_diff/23/changes/android.support.design.widget.AppBarLayout.html
    +@@ -115,7 +115,7 @@ Class android.support.design.widget.<A HREF="../../../../reference/android/suppo
    +     </div> <!-- end footer -->
    +     </div><!-- end doc-content -->
    +     </div> <!-- end body-content --> 
    +-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    + </script>
    + <script type="text/javascript">
    +   try {
    +diff --git a/docs/html/sdk/support_api_diff/23/changes/android.support.design.widget.CollapsingToolbarLayout.html b/docs/html/sdk/support_api_diff/23/changes/android.support.design.widget.CollapsingToolbarLayout.html
    +index 7244be9..d80f7ee 100644
    +--- a/docs/html/sdk/support_api_diff/23/changes/android.support.design.widget.CollapsingToolbarLayout.html
    ++++ b/docs/html/sdk/support_api_diff/23/changes/android.support.design.widget.CollapsingToolbarLayout.html
    +@@ -150,7 +150,7 @@ Class android.support.design.widget.<A HREF="../../../../reference/android/suppo
    +     </div> <!-- end footer -->
    +     </div><!-- end doc-content -->
    +     </div> <!-- end body-content --> 
    +-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    + </script>
    + <script type="text/javascript">
    +   try {
    +diff --git a/docs/html/sdk/support_api_diff/23/changes/android.support.design.widget.NavigationView.html b/docs/html/sdk/support_api_diff/23/changes/android.support.design.widget.NavigationView.html
    +index a38990a..5dd3104 100644
    +--- a/docs/html/sdk/support_api_diff/23/changes/android.support.design.widget.NavigationView.html
    ++++ b/docs/html/sdk/support_api_diff/23/changes/android.support.design.widget.NavigationView.html
    +@@ -115,7 +115,7 @@ Class android.support.design.widget.<A HREF="../../../../reference/android/suppo
    +     </div> <!-- end footer -->
    +     </div><!-- end doc-content -->
    +     </div> <!-- end body-content --> 
    +-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    + </script>
    + <script type="text/javascript">
    +   try {
    +diff --git a/docs/html/sdk/support_api_diff/23/changes/android.support.design.widget.Snackbar.html b/docs/html/sdk/support_api_diff/23/changes/android.support.design.widget.Snackbar.html
    +index 9a53448..2247297 100644
    +--- a/docs/html/sdk/support_api_diff/23/changes/android.support.design.widget.Snackbar.html
    ++++ b/docs/html/sdk/support_api_diff/23/changes/android.support.design.widget.Snackbar.html
    +@@ -116,7 +116,7 @@ Class android.support.design.widget.<A HREF="../../../../reference/android/suppo
    +     </div> <!-- end footer -->
    +     </div><!-- end doc-content -->
    +     </div> <!-- end body-content --> 
    +-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    + </script>
    + <script type="text/javascript">
    +   try {
    +diff --git a/docs/html/sdk/support_api_diff/23/changes/android.support.design.widget.TabLayout.Tab.html b/docs/html/sdk/support_api_diff/23/changes/android.support.design.widget.TabLayout.Tab.html
    +index b7a01f5..a0ea052 100644
    +--- a/docs/html/sdk/support_api_diff/23/changes/android.support.design.widget.TabLayout.Tab.html
    ++++ b/docs/html/sdk/support_api_diff/23/changes/android.support.design.widget.TabLayout.Tab.html
    +@@ -108,7 +108,7 @@ Class android.support.design.widget.<A HREF="../../../../reference/android/suppo
    +     </div> <!-- end footer -->
    +     </div><!-- end doc-content -->
    +     </div> <!-- end body-content --> 
    +-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    + </script>
    + <script type="text/javascript">
    +   try {
    +diff --git a/docs/html/sdk/support_api_diff/23/changes/android.support.design.widget.TabLayout.html b/docs/html/sdk/support_api_diff/23/changes/android.support.design.widget.TabLayout.html
    +index df626ac..bd3c8e6 100644
    +--- a/docs/html/sdk/support_api_diff/23/changes/android.support.design.widget.TabLayout.html
    ++++ b/docs/html/sdk/support_api_diff/23/changes/android.support.design.widget.TabLayout.html
    +@@ -115,7 +115,7 @@ Class android.support.design.widget.<A HREF="../../../../reference/android/suppo
    +     </div> <!-- end footer -->
    +     </div><!-- end doc-content -->
    +     </div> <!-- end body-content --> 
    +-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    + </script>
    + <script type="text/javascript">
    +   try {
    +diff --git a/docs/html/sdk/support_api_diff/23/changes/android.support.design.widget.TextInputLayout.html b/docs/html/sdk/support_api_diff/23/changes/android.support.design.widget.TextInputLayout.html
    +index 471e267..a9a7b49 100644
    +--- a/docs/html/sdk/support_api_diff/23/changes/android.support.design.widget.TextInputLayout.html
    ++++ b/docs/html/sdk/support_api_diff/23/changes/android.support.design.widget.TextInputLayout.html
    +@@ -165,7 +165,7 @@ Class android.support.design.widget.<A HREF="../../../../reference/android/suppo
    +     </div> <!-- end footer -->
    +     </div><!-- end doc-content -->
    +     </div> <!-- end body-content --> 
    +-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    + </script>
    + <script type="text/javascript">
    +   try {
    +diff --git a/docs/html/sdk/support_api_diff/23/changes/android.support.v13.app.FragmentCompat.html b/docs/html/sdk/support_api_diff/23/changes/android.support.v13.app.FragmentCompat.html
    +index 9eb5b24..b61fb5a 100644
    +--- a/docs/html/sdk/support_api_diff/23/changes/android.support.v13.app.FragmentCompat.html
    ++++ b/docs/html/sdk/support_api_diff/23/changes/android.support.v13.app.FragmentCompat.html
    +@@ -115,7 +115,7 @@ Class android.support.v13.app.<A HREF="../../../../reference/android/support/v13
    +     </div> <!-- end footer -->
    +     </div><!-- end doc-content -->
    +     </div> <!-- end body-content --> 
    +-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    + </script>
    + <script type="text/javascript">
    +   try {
    +diff --git a/docs/html/sdk/support_api_diff/23/changes/android.support.v17.leanback.widget.FullWidthDetailsOverviewRowPresenter.ViewHolder.html b/docs/html/sdk/support_api_diff/23/changes/android.support.v17.leanback.widget.FullWidthDetailsOverviewRowPresenter.ViewHolder.html
    +index 3c6165f..f189083 100644
    +--- a/docs/html/sdk/support_api_diff/23/changes/android.support.v17.leanback.widget.FullWidthDetailsOverviewRowPresenter.ViewHolder.html
    ++++ b/docs/html/sdk/support_api_diff/23/changes/android.support.v17.leanback.widget.FullWidthDetailsOverviewRowPresenter.ViewHolder.html
    +@@ -108,7 +108,7 @@ Class android.support.v17.leanback.widget.<A HREF="../../../../reference/android
    +     </div> <!-- end footer -->
    +     </div><!-- end doc-content -->
    +     </div> <!-- end body-content --> 
    +-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    + </script>
    + <script type="text/javascript">
    +   try {
    +diff --git a/docs/html/sdk/support_api_diff/23/changes/android.support.v17.leanback.widget.FullWidthDetailsOverviewRowPresenter.html b/docs/html/sdk/support_api_diff/23/changes/android.support.v17.leanback.widget.FullWidthDetailsOverviewRowPresenter.html
    +index b6d8863..cb2156a 100644
    +--- a/docs/html/sdk/support_api_diff/23/changes/android.support.v17.leanback.widget.FullWidthDetailsOverviewRowPresenter.html
    ++++ b/docs/html/sdk/support_api_diff/23/changes/android.support.v17.leanback.widget.FullWidthDetailsOverviewRowPresenter.html
    +@@ -179,7 +179,7 @@ Change from non-final to final.<br>
    +     </div> <!-- end footer -->
    +     </div><!-- end doc-content -->
    +     </div> <!-- end body-content --> 
    +-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    + </script>
    + <script type="text/javascript">
    +   try {
    +diff --git a/docs/html/sdk/support_api_diff/23/changes/android.support.v4.animation.AnimatorCompatHelper.html b/docs/html/sdk/support_api_diff/23/changes/android.support.v4.animation.AnimatorCompatHelper.html
    +index 092a6c3..5d5a9fc 100644
    +--- a/docs/html/sdk/support_api_diff/23/changes/android.support.v4.animation.AnimatorCompatHelper.html
    ++++ b/docs/html/sdk/support_api_diff/23/changes/android.support.v4.animation.AnimatorCompatHelper.html
    +@@ -108,7 +108,7 @@ Class android.support.v4.animation.<A HREF="../../../../reference/android/suppor
    +     </div> <!-- end footer -->
    +     </div><!-- end doc-content -->
    +     </div> <!-- end body-content --> 
    +-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    + </script>
    + <script type="text/javascript">
    +   try {
    +diff --git a/docs/html/sdk/support_api_diff/23/changes/android.support.v4.app.ActivityCompat.html b/docs/html/sdk/support_api_diff/23/changes/android.support.v4.app.ActivityCompat.html
    +index 76e8ce9..c318b70 100644
    +--- a/docs/html/sdk/support_api_diff/23/changes/android.support.v4.app.ActivityCompat.html
    ++++ b/docs/html/sdk/support_api_diff/23/changes/android.support.v4.app.ActivityCompat.html
    +@@ -122,7 +122,7 @@ Class android.support.v4.app.<A HREF="../../../../reference/android/support/v4/a
    +     </div> <!-- end footer -->
    +     </div><!-- end doc-content -->
    +     </div> <!-- end body-content --> 
    +-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    + </script>
    + <script type="text/javascript">
    +   try {
    +diff --git a/docs/html/sdk/support_api_diff/23/changes/android.support.v4.app.Fragment.html b/docs/html/sdk/support_api_diff/23/changes/android.support.v4.app.Fragment.html
    +index 53a8bd5..2f56f59 100644
    +--- a/docs/html/sdk/support_api_diff/23/changes/android.support.v4.app.Fragment.html
    ++++ b/docs/html/sdk/support_api_diff/23/changes/android.support.v4.app.Fragment.html
    +@@ -190,7 +190,7 @@ Class android.support.v4.app.<A HREF="../../../../reference/android/support/v4/a
    +     </div> <!-- end footer -->
    +     </div><!-- end doc-content -->
    +     </div> <!-- end body-content --> 
    +-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    + </script>
    + <script type="text/javascript">
    +   try {
    +diff --git a/docs/html/sdk/support_api_diff/23/changes/android.support.v4.app.FragmentActivity.html b/docs/html/sdk/support_api_diff/23/changes/android.support.v4.app.FragmentActivity.html
    +index 8d2321f..0338069 100644
    +--- a/docs/html/sdk/support_api_diff/23/changes/android.support.v4.app.FragmentActivity.html
    ++++ b/docs/html/sdk/support_api_diff/23/changes/android.support.v4.app.FragmentActivity.html
    +@@ -109,7 +109,7 @@ Class android.support.v4.app.<A HREF="../../../../reference/android/support/v4/a
    +     </div> <!-- end footer -->
    +     </div><!-- end doc-content -->
    +     </div> <!-- end body-content --> 
    +-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    + </script>
    + <script type="text/javascript">
    +   try {
    +diff --git a/docs/html/sdk/support_api_diff/23/changes/android.support.v4.content.AsyncTaskLoader.html b/docs/html/sdk/support_api_diff/23/changes/android.support.v4.content.AsyncTaskLoader.html
    +index 19be27c..5dfbe6c 100644
    +--- a/docs/html/sdk/support_api_diff/23/changes/android.support.v4.content.AsyncTaskLoader.html
    ++++ b/docs/html/sdk/support_api_diff/23/changes/android.support.v4.content.AsyncTaskLoader.html
    +@@ -133,7 +133,7 @@ Method was locally defined, but is now inherited from <a href="../../../../refer
    +     </div> <!-- end footer -->
    +     </div><!-- end doc-content -->
    +     </div> <!-- end body-content --> 
    +-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    + </script>
    + <script type="text/javascript">
    +   try {
    +diff --git a/docs/html/sdk/support_api_diff/23/changes/android.support.v4.content.ContextCompat.html b/docs/html/sdk/support_api_diff/23/changes/android.support.v4.content.ContextCompat.html
    +index 6ed5b3e..64d09ac 100644
    +--- a/docs/html/sdk/support_api_diff/23/changes/android.support.v4.content.ContextCompat.html
    ++++ b/docs/html/sdk/support_api_diff/23/changes/android.support.v4.content.ContextCompat.html
    +@@ -122,7 +122,7 @@ Class android.support.v4.content.<A HREF="../../../../reference/android/support/
    +     </div> <!-- end footer -->
    +     </div><!-- end doc-content -->
    +     </div> <!-- end body-content --> 
    +-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    + </script>
    + <script type="text/javascript">
    +   try {
    +diff --git a/docs/html/sdk/support_api_diff/23/changes/android.support.v4.content.Loader.html b/docs/html/sdk/support_api_diff/23/changes/android.support.v4.content.Loader.html
    +index d4c3bb0..f97def1 100644
    +--- a/docs/html/sdk/support_api_diff/23/changes/android.support.v4.content.Loader.html
    ++++ b/docs/html/sdk/support_api_diff/23/changes/android.support.v4.content.Loader.html
    +@@ -136,7 +136,7 @@ Class android.support.v4.content.<A HREF="../../../../reference/android/support/
    +     </div> <!-- end footer -->
    +     </div><!-- end doc-content -->
    +     </div> <!-- end body-content --> 
    +-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    + </script>
    + <script type="text/javascript">
    +   try {
    +diff --git a/docs/html/sdk/support_api_diff/23/changes/android.support.v4.graphics.drawable.DrawableCompat.html b/docs/html/sdk/support_api_diff/23/changes/android.support.v4.graphics.drawable.DrawableCompat.html
    +index 87fefee..ca42f3d 100644
    +--- a/docs/html/sdk/support_api_diff/23/changes/android.support.v4.graphics.drawable.DrawableCompat.html
    ++++ b/docs/html/sdk/support_api_diff/23/changes/android.support.v4.graphics.drawable.DrawableCompat.html
    +@@ -115,7 +115,7 @@ Class android.support.v4.graphics.drawable.<A HREF="../../../../reference/androi
    +     </div> <!-- end footer -->
    +     </div><!-- end doc-content -->
    +     </div> <!-- end body-content --> 
    +-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    + </script>
    + <script type="text/javascript">
    +   try {
    +diff --git a/docs/html/sdk/support_api_diff/23/changes/android.support.v4.graphics.drawable.RoundedBitmapDrawable.html b/docs/html/sdk/support_api_diff/23/changes/android.support.v4.graphics.drawable.RoundedBitmapDrawable.html
    +index 7c72cf4..793bd8b 100644
    +--- a/docs/html/sdk/support_api_diff/23/changes/android.support.v4.graphics.drawable.RoundedBitmapDrawable.html
    ++++ b/docs/html/sdk/support_api_diff/23/changes/android.support.v4.graphics.drawable.RoundedBitmapDrawable.html
    +@@ -115,7 +115,7 @@ Class android.support.v4.graphics.drawable.<A HREF="../../../../reference/androi
    +     </div> <!-- end footer -->
    +     </div><!-- end doc-content -->
    +     </div> <!-- end body-content --> 
    +-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    + </script>
    + <script type="text/javascript">
    +   try {
    +diff --git a/docs/html/sdk/support_api_diff/23/changes/android.support.v4.media.MediaDescriptionCompat.Builder.html b/docs/html/sdk/support_api_diff/23/changes/android.support.v4.media.MediaDescriptionCompat.Builder.html
    +index c429c39..6ae7186 100644
    +--- a/docs/html/sdk/support_api_diff/23/changes/android.support.v4.media.MediaDescriptionCompat.Builder.html
    ++++ b/docs/html/sdk/support_api_diff/23/changes/android.support.v4.media.MediaDescriptionCompat.Builder.html
    +@@ -108,7 +108,7 @@ Class android.support.v4.media.<A HREF="../../../../reference/android/support/v4
    +     </div> <!-- end footer -->
    +     </div><!-- end doc-content -->
    +     </div> <!-- end body-content --> 
    +-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    + </script>
    + <script type="text/javascript">
    +   try {
    +diff --git a/docs/html/sdk/support_api_diff/23/changes/android.support.v4.media.MediaDescriptionCompat.html b/docs/html/sdk/support_api_diff/23/changes/android.support.v4.media.MediaDescriptionCompat.html
    +index 4053435..dde12a5 100644
    +--- a/docs/html/sdk/support_api_diff/23/changes/android.support.v4.media.MediaDescriptionCompat.html
    ++++ b/docs/html/sdk/support_api_diff/23/changes/android.support.v4.media.MediaDescriptionCompat.html
    +@@ -108,7 +108,7 @@ Class android.support.v4.media.<A HREF="../../../../reference/android/support/v4
    +     </div> <!-- end footer -->
    +     </div><!-- end doc-content -->
    +     </div> <!-- end body-content --> 
    +-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    + </script>
    + <script type="text/javascript">
    +   try {
    +diff --git a/docs/html/sdk/support_api_diff/23/changes/android.support.v4.media.session.MediaControllerCompat.TransportControls.html b/docs/html/sdk/support_api_diff/23/changes/android.support.v4.media.session.MediaControllerCompat.TransportControls.html
    +index 4d10769..12743cd 100644
    +--- a/docs/html/sdk/support_api_diff/23/changes/android.support.v4.media.session.MediaControllerCompat.TransportControls.html
    ++++ b/docs/html/sdk/support_api_diff/23/changes/android.support.v4.media.session.MediaControllerCompat.TransportControls.html
    +@@ -108,7 +108,7 @@ Class android.support.v4.media.session.<A HREF="../../../../reference/android/su
    +     </div> <!-- end footer -->
    +     </div><!-- end doc-content -->
    +     </div> <!-- end body-content --> 
    +-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    + </script>
    + <script type="text/javascript">
    +   try {
    +diff --git a/docs/html/sdk/support_api_diff/23/changes/android.support.v4.media.session.MediaSessionCompat.Callback.html b/docs/html/sdk/support_api_diff/23/changes/android.support.v4.media.session.MediaSessionCompat.Callback.html
    +index a0bbbf6..4acf244 100644
    +--- a/docs/html/sdk/support_api_diff/23/changes/android.support.v4.media.session.MediaSessionCompat.Callback.html
    ++++ b/docs/html/sdk/support_api_diff/23/changes/android.support.v4.media.session.MediaSessionCompat.Callback.html
    +@@ -108,7 +108,7 @@ Class android.support.v4.media.session.<A HREF="../../../../reference/android/su
    +     </div> <!-- end footer -->
    +     </div><!-- end doc-content -->
    +     </div> <!-- end body-content --> 
    +-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    + </script>
    + <script type="text/javascript">
    +   try {
    +diff --git a/docs/html/sdk/support_api_diff/23/changes/android.support.v4.media.session.PlaybackStateCompat.html b/docs/html/sdk/support_api_diff/23/changes/android.support.v4.media.session.PlaybackStateCompat.html
    +index 29e5f0b..0f568c4 100644
    +--- a/docs/html/sdk/support_api_diff/23/changes/android.support.v4.media.session.PlaybackStateCompat.html
    ++++ b/docs/html/sdk/support_api_diff/23/changes/android.support.v4.media.session.PlaybackStateCompat.html
    +@@ -108,7 +108,7 @@ Class android.support.v4.media.session.<A HREF="../../../../reference/android/su
    +     </div> <!-- end footer -->
    +     </div><!-- end doc-content -->
    +     </div> <!-- end body-content --> 
    +-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    + </script>
    + <script type="text/javascript">
    +   try {
    +diff --git a/docs/html/sdk/support_api_diff/23/changes/android.support.v4.text.ICUCompat.html b/docs/html/sdk/support_api_diff/23/changes/android.support.v4.text.ICUCompat.html
    +index 5f9f31e..e357c50 100644
    +--- a/docs/html/sdk/support_api_diff/23/changes/android.support.v4.text.ICUCompat.html
    ++++ b/docs/html/sdk/support_api_diff/23/changes/android.support.v4.text.ICUCompat.html
    +@@ -130,7 +130,7 @@ Class android.support.v4.text.<A HREF="../../../../reference/android/support/v4/
    +     </div> <!-- end footer -->
    +     </div><!-- end doc-content -->
    +     </div> <!-- end body-content --> 
    +-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    + </script>
    + <script type="text/javascript">
    +   try {
    +diff --git a/docs/html/sdk/support_api_diff/23/changes/android.support.v4.view.ViewCompat.html b/docs/html/sdk/support_api_diff/23/changes/android.support.v4.view.ViewCompat.html
    +index 548502c..caaf19a 100644
    +--- a/docs/html/sdk/support_api_diff/23/changes/android.support.v4.view.ViewCompat.html
    ++++ b/docs/html/sdk/support_api_diff/23/changes/android.support.v4.view.ViewCompat.html
    +@@ -122,7 +122,7 @@ Class android.support.v4.view.<A HREF="../../../../reference/android/support/v4/
    +     </div> <!-- end footer -->
    +     </div><!-- end doc-content -->
    +     </div> <!-- end body-content --> 
    +-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    + </script>
    + <script type="text/javascript">
    +   try {
    +diff --git a/docs/html/sdk/support_api_diff/23/changes/android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat.html b/docs/html/sdk/support_api_diff/23/changes/android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat.html
    +index ce98f64..c60e7e1 100644
    +--- a/docs/html/sdk/support_api_diff/23/changes/android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat.html
    ++++ b/docs/html/sdk/support_api_diff/23/changes/android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat.html
    +@@ -255,7 +255,7 @@ Class android.support.v4.view.accessibility.<A HREF="../../../../reference/andro
    +     </div> <!-- end footer -->
    +     </div><!-- end doc-content -->
    +     </div> <!-- end body-content --> 
    +-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    + </script>
    + <script type="text/javascript">
    +   try {
    +diff --git a/docs/html/sdk/support_api_diff/23/changes/android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.html b/docs/html/sdk/support_api_diff/23/changes/android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.html
    +index f3ef666..6f2e809 100644
    +--- a/docs/html/sdk/support_api_diff/23/changes/android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.html
    ++++ b/docs/html/sdk/support_api_diff/23/changes/android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.html
    +@@ -361,7 +361,7 @@ Class android.support.v4.view.accessibility.<A HREF="../../../../reference/andro
    +     </div> <!-- end footer -->
    +     </div><!-- end doc-content -->
    +     </div> <!-- end body-content --> 
    +-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    + </script>
    + <script type="text/javascript">
    +   try {
    +diff --git a/docs/html/sdk/support_api_diff/23/changes/android.support.v4.widget.DrawerLayout.html b/docs/html/sdk/support_api_diff/23/changes/android.support.v4.widget.DrawerLayout.html
    +index 3297157..c18ae6c 100644
    +--- a/docs/html/sdk/support_api_diff/23/changes/android.support.v4.widget.DrawerLayout.html
    ++++ b/docs/html/sdk/support_api_diff/23/changes/android.support.v4.widget.DrawerLayout.html
    +@@ -115,7 +115,7 @@ Class android.support.v4.widget.<A HREF="../../../../reference/android/support/v
    +     </div> <!-- end footer -->
    +     </div><!-- end doc-content -->
    +     </div> <!-- end body-content --> 
    +-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    + </script>
    + <script type="text/javascript">
    +   try {
    +diff --git a/docs/html/sdk/support_api_diff/23/changes/android.support.v4.widget.ExploreByTouchHelper.html b/docs/html/sdk/support_api_diff/23/changes/android.support.v4.widget.ExploreByTouchHelper.html
    +index 4026cd2..be8512f 100644
    +--- a/docs/html/sdk/support_api_diff/23/changes/android.support.v4.widget.ExploreByTouchHelper.html
    ++++ b/docs/html/sdk/support_api_diff/23/changes/android.support.v4.widget.ExploreByTouchHelper.html
    +@@ -123,7 +123,7 @@ Class android.support.v4.widget.<A HREF="../../../../reference/android/support/v
    +     </div> <!-- end footer -->
    +     </div><!-- end doc-content -->
    +     </div> <!-- end body-content --> 
    +-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    + </script>
    + <script type="text/javascript">
    +   try {
    +diff --git a/docs/html/sdk/support_api_diff/23/changes/android.support.v4.widget.PopupWindowCompat.html b/docs/html/sdk/support_api_diff/23/changes/android.support.v4.widget.PopupWindowCompat.html
    +index 8a9b9c6..284dab4 100644
    +--- a/docs/html/sdk/support_api_diff/23/changes/android.support.v4.widget.PopupWindowCompat.html
    ++++ b/docs/html/sdk/support_api_diff/23/changes/android.support.v4.widget.PopupWindowCompat.html
    +@@ -129,7 +129,7 @@ Class android.support.v4.widget.<A HREF="../../../../reference/android/support/v
    +     </div> <!-- end footer -->
    +     </div><!-- end doc-content -->
    +     </div> <!-- end body-content --> 
    +-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    + </script>
    + <script type="text/javascript">
    +   try {
    +diff --git a/docs/html/sdk/support_api_diff/23/changes/android.support.v4.widget.SwipeRefreshLayout.html b/docs/html/sdk/support_api_diff/23/changes/android.support.v4.widget.SwipeRefreshLayout.html
    +index 91a99cb..1fb912f 100644
    +--- a/docs/html/sdk/support_api_diff/23/changes/android.support.v4.widget.SwipeRefreshLayout.html
    ++++ b/docs/html/sdk/support_api_diff/23/changes/android.support.v4.widget.SwipeRefreshLayout.html
    +@@ -94,7 +94,7 @@ Class android.support.v4.widget.<A HREF="../../../../reference/android/support/v
    +     </div> <!-- end footer -->
    +     </div><!-- end doc-content -->
    +     </div> <!-- end body-content --> 
    +-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    + </script>
    + <script type="text/javascript">
    +   try {
    +diff --git a/docs/html/sdk/support_api_diff/23/changes/android.support.v7.app.AppCompatDelegate.html b/docs/html/sdk/support_api_diff/23/changes/android.support.v7.app.AppCompatDelegate.html
    +index 42ef289..9f768b9 100644
    +--- a/docs/html/sdk/support_api_diff/23/changes/android.support.v7.app.AppCompatDelegate.html
    ++++ b/docs/html/sdk/support_api_diff/23/changes/android.support.v7.app.AppCompatDelegate.html
    +@@ -137,7 +137,7 @@ Class android.support.v7.app.<A HREF="../../../../reference/android/support/v7/a
    +     </div> <!-- end footer -->
    +     </div><!-- end doc-content -->
    +     </div> <!-- end body-content --> 
    +-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    + </script>
    + <script type="text/javascript">
    +   try {
    +diff --git a/docs/html/sdk/support_api_diff/23/changes/android.support.v7.appcompat.R.attr.html b/docs/html/sdk/support_api_diff/23/changes/android.support.v7.appcompat.R.attr.html
    +index cc28516..98d2c2c 100644
    +--- a/docs/html/sdk/support_api_diff/23/changes/android.support.v7.appcompat.R.attr.html
    ++++ b/docs/html/sdk/support_api_diff/23/changes/android.support.v7.appcompat.R.attr.html
    +@@ -221,7 +221,7 @@ Class android.support.v7.appcompat.<A HREF="../../../../reference/android/suppor
    +     </div> <!-- end footer -->
    +     </div><!-- end doc-content -->
    +     </div> <!-- end body-content --> 
    +-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    + </script>
    + <script type="text/javascript">
    +   try {
    +diff --git a/docs/html/sdk/support_api_diff/23/changes/android.support.v7.appcompat.R.color.html b/docs/html/sdk/support_api_diff/23/changes/android.support.v7.appcompat.R.color.html
    +index 5f1a3f6..852d595 100644
    +--- a/docs/html/sdk/support_api_diff/23/changes/android.support.v7.appcompat.R.color.html
    ++++ b/docs/html/sdk/support_api_diff/23/changes/android.support.v7.appcompat.R.color.html
    +@@ -193,7 +193,7 @@ Class android.support.v7.appcompat.<A HREF="../../../../reference/android/suppor
    +     </div> <!-- end footer -->
    +     </div><!-- end doc-content -->
    +     </div> <!-- end body-content --> 
    +-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    + </script>
    + <script type="text/javascript">
    +   try {
    +diff --git a/docs/html/sdk/support_api_diff/23/changes/android.support.v7.appcompat.R.dimen.html b/docs/html/sdk/support_api_diff/23/changes/android.support.v7.appcompat.R.dimen.html
    +index c4fba92..893ea25 100644
    +--- a/docs/html/sdk/support_api_diff/23/changes/android.support.v7.appcompat.R.dimen.html
    ++++ b/docs/html/sdk/support_api_diff/23/changes/android.support.v7.appcompat.R.dimen.html
    +@@ -158,7 +158,7 @@ Class android.support.v7.appcompat.<A HREF="../../../../reference/android/suppor
    +     </div> <!-- end footer -->
    +     </div><!-- end doc-content -->
    +     </div> <!-- end body-content --> 
    +-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    + </script>
    + <script type="text/javascript">
    +   try {
    +diff --git a/docs/html/sdk/support_api_diff/23/changes/android.support.v7.appcompat.R.drawable.html b/docs/html/sdk/support_api_diff/23/changes/android.support.v7.appcompat.R.drawable.html
    +index 0bf5ce1..482e9ff 100644
    +--- a/docs/html/sdk/support_api_diff/23/changes/android.support.v7.appcompat.R.drawable.html
    ++++ b/docs/html/sdk/support_api_diff/23/changes/android.support.v7.appcompat.R.drawable.html
    +@@ -144,7 +144,7 @@ Class android.support.v7.appcompat.<A HREF="../../../../reference/android/suppor
    +     </div> <!-- end footer -->
    +     </div><!-- end doc-content -->
    +     </div> <!-- end body-content --> 
    +-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    + </script>
    + <script type="text/javascript">
    +   try {
    +diff --git a/docs/html/sdk/support_api_diff/23/changes/android.support.v7.appcompat.R.id.html b/docs/html/sdk/support_api_diff/23/changes/android.support.v7.appcompat.R.id.html
    +index 2b34b3a..818a5b0 100644
    +--- a/docs/html/sdk/support_api_diff/23/changes/android.support.v7.appcompat.R.id.html
    ++++ b/docs/html/sdk/support_api_diff/23/changes/android.support.v7.appcompat.R.id.html
    +@@ -115,7 +115,7 @@ Class android.support.v7.appcompat.<A HREF="../../../../reference/android/suppor
    +     </div> <!-- end footer -->
    +     </div><!-- end doc-content -->
    +     </div> <!-- end body-content --> 
    +-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    + </script>
    + <script type="text/javascript">
    +   try {
    +diff --git a/docs/html/sdk/support_api_diff/23/changes/android.support.v7.appcompat.R.layout.html b/docs/html/sdk/support_api_diff/23/changes/android.support.v7.appcompat.R.layout.html
    +index 9d24903..a0a33fb 100644
    +--- a/docs/html/sdk/support_api_diff/23/changes/android.support.v7.appcompat.R.layout.html
    ++++ b/docs/html/sdk/support_api_diff/23/changes/android.support.v7.appcompat.R.layout.html
    +@@ -108,7 +108,7 @@ Class android.support.v7.appcompat.<A HREF="../../../../reference/android/suppor
    +     </div> <!-- end footer -->
    +     </div><!-- end doc-content -->
    +     </div> <!-- end body-content --> 
    +-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    + </script>
    + <script type="text/javascript">
    +   try {
    +diff --git a/docs/html/sdk/support_api_diff/23/changes/android.support.v7.appcompat.R.style.html b/docs/html/sdk/support_api_diff/23/changes/android.support.v7.appcompat.R.style.html
    +index 8b16f1c..d084de0 100644
    +--- a/docs/html/sdk/support_api_diff/23/changes/android.support.v7.appcompat.R.style.html
    ++++ b/docs/html/sdk/support_api_diff/23/changes/android.support.v7.appcompat.R.style.html
    +@@ -207,7 +207,7 @@ Class android.support.v7.appcompat.<A HREF="../../../../reference/android/suppor
    +     </div> <!-- end footer -->
    +     </div><!-- end doc-content -->
    +     </div> <!-- end body-content --> 
    +-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    + </script>
    + <script type="text/javascript">
    +   try {
    +diff --git a/docs/html/sdk/support_api_diff/23/changes/android.support.v7.appcompat.R.styleable.html b/docs/html/sdk/support_api_diff/23/changes/android.support.v7.appcompat.R.styleable.html
    +index 5365376..c021cbe 100644
    +--- a/docs/html/sdk/support_api_diff/23/changes/android.support.v7.appcompat.R.styleable.html
    ++++ b/docs/html/sdk/support_api_diff/23/changes/android.support.v7.appcompat.R.styleable.html
    +@@ -333,7 +333,7 @@ Class android.support.v7.appcompat.<A HREF="../../../../reference/android/suppor
    +     </div> <!-- end footer -->
    +     </div><!-- end doc-content -->
    +     </div> <!-- end body-content --> 
    +-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    + </script>
    + <script type="text/javascript">
    +   try {
    +diff --git a/docs/html/sdk/support_api_diff/23/changes/android.support.v7.graphics.Palette.Builder.html b/docs/html/sdk/support_api_diff/23/changes/android.support.v7.graphics.Palette.Builder.html
    +index 3893441..e707730 100644
    +--- a/docs/html/sdk/support_api_diff/23/changes/android.support.v7.graphics.Palette.Builder.html
    ++++ b/docs/html/sdk/support_api_diff/23/changes/android.support.v7.graphics.Palette.Builder.html
    +@@ -115,7 +115,7 @@ Class android.support.v7.graphics.<A HREF="../../../../reference/android/support
    +     </div> <!-- end footer -->
    +     </div><!-- end doc-content -->
    +     </div> <!-- end body-content --> 
    +-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    + </script>
    + <script type="text/javascript">
    +   try {
    +diff --git a/docs/html/sdk/support_api_diff/23/changes/changes-summary.html b/docs/html/sdk/support_api_diff/23/changes/changes-summary.html
    +index 3deee46..75c1eb3 100644
    +--- a/docs/html/sdk/support_api_diff/23/changes/changes-summary.html
    ++++ b/docs/html/sdk/support_api_diff/23/changes/changes-summary.html
    +@@ -310,7 +310,7 @@ see the <a href="http://developer.android.com/index.html" target="_top">Android
    +     </div> <!-- end footer -->
    +     </div><!-- end doc-content -->
    +     </div> <!-- end body-content --> 
    +-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    + </script>
    + <script type="text/javascript">
    +   try {
    +diff --git a/docs/html/sdk/support_api_diff/23/changes/classes_index_additions.html b/docs/html/sdk/support_api_diff/23/changes/classes_index_additions.html
    +index 094fff5..bc69616 100644
    +--- a/docs/html/sdk/support_api_diff/23/changes/classes_index_additions.html
    ++++ b/docs/html/sdk/support_api_diff/23/changes/classes_index_additions.html
    +@@ -160,7 +160,7 @@ Listed as: <span style="color:#069"><strong>Added</strong></span>,  <span style=
    + <A HREF="pkg_android.support.v4.content.html#SharedPreferencesCompat" class="hiddenlink" target="rightframe"><b>SharedPreferencesCompat</b></A><br>
    + <A HREF="pkg_android.support.v4.content.html#SharedPreferencesCompat.EditorCompat" class="hiddenlink" target="rightframe"><b>SharedPreferencesCompat.EditorCompat</b></A><br>
    + <A HREF="pkg_android.support.design.widget.html#Snackbar.Callback" class="hiddenlink" target="rightframe"><b>Snackbar.Callback</b></A><br>
    +-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    + </script>
    + <script type="text/javascript">
    +   try {
    +diff --git a/docs/html/sdk/support_api_diff/23/changes/classes_index_all.html b/docs/html/sdk/support_api_diff/23/changes/classes_index_all.html
    +index cb1ed5f..33a23bf 100644
    +--- a/docs/html/sdk/support_api_diff/23/changes/classes_index_all.html
    ++++ b/docs/html/sdk/support_api_diff/23/changes/classes_index_all.html
    +@@ -419,7 +419,7 @@ Listed as: <span style="color:#069"><strong>Added</strong></span>,  <span style=
    +  <a href="#topheader"><font size="-2">TOP</font></a>
    + <p><div style="line-height:1.5em;color:black">
    + <A HREF="android.support.v4.view.ViewCompat.html" class="hiddenlink" target="rightframe">ViewCompat</A><br>
    +-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    + </script>
    + <script type="text/javascript">
    +   try {
    +diff --git a/docs/html/sdk/support_api_diff/23/changes/classes_index_changes.html b/docs/html/sdk/support_api_diff/23/changes/classes_index_changes.html
    +index b674f27..9588a73 100644
    +--- a/docs/html/sdk/support_api_diff/23/changes/classes_index_changes.html
    ++++ b/docs/html/sdk/support_api_diff/23/changes/classes_index_changes.html
    +@@ -328,7 +328,7 @@ Listed as: <span style="color:#069"><strong>Added</strong></span>,  <span style=
    +  <a href="#topheader"><font size="-2">TOP</font></a>
    + <p><div style="line-height:1.5em;color:black">
    + <A HREF="android.support.v4.view.ViewCompat.html" class="hiddenlink" target="rightframe">ViewCompat</A><br>
    +-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    + </script>
    + <script type="text/javascript">
    +   try {
    +diff --git a/docs/html/sdk/support_api_diff/23/changes/classes_index_removals.html b/docs/html/sdk/support_api_diff/23/changes/classes_index_removals.html
    +index e6da73f..c466298 100644
    +--- a/docs/html/sdk/support_api_diff/23/changes/classes_index_removals.html
    ++++ b/docs/html/sdk/support_api_diff/23/changes/classes_index_removals.html
    +@@ -47,7 +47,7 @@ body{overflow:auto;}
    + <div id="indexTableCaption" style="background-color:#eee;padding:0 4px 0 4px;font-size:11px;margin-bottom:1em;">
    + Listed as: <span style="color:#069"><strong>Added</strong></span>,  <span style="color:#069"><strike>Removed</strike></span>,  <span style="color:#069">Changed</span></font>
    + </div>
    +-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    + </script>
    + <script type="text/javascript">
    +   try {
    +diff --git a/docs/html/sdk/support_api_diff/23/changes/constructors_index_additions.html b/docs/html/sdk/support_api_diff/23/changes/constructors_index_additions.html
    +index d1e5215..ae8c0d3 100644
    +--- a/docs/html/sdk/support_api_diff/23/changes/constructors_index_additions.html
    ++++ b/docs/html/sdk/support_api_diff/23/changes/constructors_index_additions.html
    +@@ -53,7 +53,7 @@ Listed as: <span style="color:#069"><strong>Added</strong></span>,  <span style=
    + <p><div style="line-height:1.5em;color:black">
    + <nobr><A HREF="android.support.design.widget.TextInputLayout.html#android.support.design.widget.TextInputLayout.ctor_added(android.content.Context, android.util.AttributeSet, int)" class="hiddenlink" target="rightframe"><b>TextInputLayout</b>
    + (<code>Context, AttributeSet, int</code>)</A></nobr>&nbsp;constructor<br>
    +-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    + </script>
    + <script type="text/javascript">
    +   try {
    +diff --git a/docs/html/sdk/support_api_diff/23/changes/constructors_index_all.html b/docs/html/sdk/support_api_diff/23/changes/constructors_index_all.html
    +index 4618d88..401df57 100644
    +--- a/docs/html/sdk/support_api_diff/23/changes/constructors_index_all.html
    ++++ b/docs/html/sdk/support_api_diff/23/changes/constructors_index_all.html
    +@@ -53,7 +53,7 @@ Listed as: <span style="color:#069"><strong>Added</strong></span>,  <span style=
    + <p><div style="line-height:1.5em;color:black">
    + <nobr><A HREF="android.support.design.widget.TextInputLayout.html#android.support.design.widget.TextInputLayout.ctor_added(android.content.Context, android.util.AttributeSet, int)" class="hiddenlink" target="rightframe"><b>TextInputLayout</b>
    + (<code>Context, AttributeSet, int</code>)</A></nobr>&nbsp;constructor<br>
    +-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    + </script>
    + <script type="text/javascript">
    +   try {
    +diff --git a/docs/html/sdk/support_api_diff/23/changes/constructors_index_changes.html b/docs/html/sdk/support_api_diff/23/changes/constructors_index_changes.html
    +index a5ca2ef..122cdce 100644
    +--- a/docs/html/sdk/support_api_diff/23/changes/constructors_index_changes.html
    ++++ b/docs/html/sdk/support_api_diff/23/changes/constructors_index_changes.html
    +@@ -47,7 +47,7 @@ body{overflow:auto;}
    + <div id="indexTableCaption" style="background-color:#eee;padding:0 4px 0 4px;font-size:11px;margin-bottom:1em;">
    + Listed as: <span style="color:#069"><strong>Added</strong></span>,  <span style="color:#069"><strike>Removed</strike></span>,  <span style="color:#069">Changed</span></font>
    + </div>
    +-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    + </script>
    + <script type="text/javascript">
    +   try {
    +diff --git a/docs/html/sdk/support_api_diff/23/changes/constructors_index_removals.html b/docs/html/sdk/support_api_diff/23/changes/constructors_index_removals.html
    +index 74a09ba..dadd1cd 100644
    +--- a/docs/html/sdk/support_api_diff/23/changes/constructors_index_removals.html
    ++++ b/docs/html/sdk/support_api_diff/23/changes/constructors_index_removals.html
    +@@ -47,7 +47,7 @@ body{overflow:auto;}
    + <div id="indexTableCaption" style="background-color:#eee;padding:0 4px 0 4px;font-size:11px;margin-bottom:1em;">
    + Listed as: <span style="color:#069"><strong>Added</strong></span>,  <span style="color:#069"><strike>Removed</strike></span>,  <span style="color:#069">Changed</span></font>
    + </div>
    +-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    + </script>
    + <script type="text/javascript">
    +   try {
    +diff --git a/docs/html/sdk/support_api_diff/23/changes/fields_index_additions.html b/docs/html/sdk/support_api_diff/23/changes/fields_index_additions.html
    +index 2f6ac9c..f9137b8 100644
    +--- a/docs/html/sdk/support_api_diff/23/changes/fields_index_additions.html
    ++++ b/docs/html/sdk/support_api_diff/23/changes/fields_index_additions.html
    +@@ -444,7 +444,7 @@ Listed as: <span style="color:#069"><strong>Added</strong></span>,  <span style=
    + <p><div style="line-height:1.5em;color:black">
    + <nobr><A HREF="android.support.v7.appcompat.R.style.html#android.support.v7.appcompat.R.style.Widget_AppCompat_Button_Colored" class="hiddenlink" target="rightframe">Widget_AppCompat_Button_Colored</A>
    + </nobr><br>
    +-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    + </script>
    + <script type="text/javascript">
    +   try {
    +diff --git a/docs/html/sdk/support_api_diff/23/changes/fields_index_all.html b/docs/html/sdk/support_api_diff/23/changes/fields_index_all.html
    +index a7f5e18..909dbcc 100644
    +--- a/docs/html/sdk/support_api_diff/23/changes/fields_index_all.html
    ++++ b/docs/html/sdk/support_api_diff/23/changes/fields_index_all.html
    +@@ -538,7 +538,7 @@ Listed as: <span style="color:#069"><strong>Added</strong></span>,  <span style=
    + <p><div style="line-height:1.5em;color:black">
    + <nobr><A HREF="android.support.v7.appcompat.R.style.html#android.support.v7.appcompat.R.style.Widget_AppCompat_Button_Colored" class="hiddenlink" target="rightframe">Widget_AppCompat_Button_Colored</A>
    + </nobr><br>
    +-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    + </script>
    + <script type="text/javascript">
    +   try {
    +diff --git a/docs/html/sdk/support_api_diff/23/changes/fields_index_changes.html b/docs/html/sdk/support_api_diff/23/changes/fields_index_changes.html
    +index 0e2ccff..301881a 100644
    +--- a/docs/html/sdk/support_api_diff/23/changes/fields_index_changes.html
    ++++ b/docs/html/sdk/support_api_diff/23/changes/fields_index_changes.html
    +@@ -47,7 +47,7 @@ body{overflow:auto;}
    + <div id="indexTableCaption" style="background-color:#eee;padding:0 4px 0 4px;font-size:11px;margin-bottom:1em;">
    + Listed as: <span style="color:#069"><strong>Added</strong></span>,  <span style="color:#069"><strike>Removed</strike></span>,  <span style="color:#069">Changed</span></font>
    + </div>
    +-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    + </script>
    + <script type="text/javascript">
    +   try {
    +diff --git a/docs/html/sdk/support_api_diff/23/changes/fields_index_removals.html b/docs/html/sdk/support_api_diff/23/changes/fields_index_removals.html
    +index 5027374..174a576 100644
    +--- a/docs/html/sdk/support_api_diff/23/changes/fields_index_removals.html
    ++++ b/docs/html/sdk/support_api_diff/23/changes/fields_index_removals.html
    +@@ -241,7 +241,7 @@ Listed as: <span style="color:#069"><strong>Added</strong></span>,  <span style=
    + </nobr><br>
    + <nobr><A HREF="android.support.v7.appcompat.R.styleable.html#android.support.v7.appcompat.R.styleable.View_backgroundTintMode" class="hiddenlink" target="rightframe"><strike>View_backgroundTintMode</strike></A>
    + </nobr><br>
    +-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    + </script>
    + <script type="text/javascript">
    +   try {
    +diff --git a/docs/html/sdk/support_api_diff/23/changes/jdiff_help.html b/docs/html/sdk/support_api_diff/23/changes/jdiff_help.html
    +index acb8508..125d4e8 100644
    +--- a/docs/html/sdk/support_api_diff/23/changes/jdiff_help.html
    ++++ b/docs/html/sdk/support_api_diff/23/changes/jdiff_help.html
    +@@ -120,7 +120,7 @@ These links show and hide the HTML frames. All pages are available with or witho
    + There are some complex changes which can occur between versions, for example, when two or more methods with the same name change simultaneously, or when a method or field is moved into or from a superclass. 
    + In these cases, the change will be seen as a removal and an addition, rather than as a change. Unexpected removals or additions are often part of one of these type of changes. 
    + </BLOCKQUOTE>
    +-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    + </script>
    + <script type="text/javascript">
    +   try {
    +diff --git a/docs/html/sdk/support_api_diff/23/changes/jdiff_statistics.html b/docs/html/sdk/support_api_diff/23/changes/jdiff_statistics.html
    +index 4480788..1e865b7 100644
    +--- a/docs/html/sdk/support_api_diff/23/changes/jdiff_statistics.html
    ++++ b/docs/html/sdk/support_api_diff/23/changes/jdiff_statistics.html
    +@@ -467,7 +467,7 @@ added, the change will be 100%.</p>
    +     </div> <!-- end footer -->
    +     </div><!-- end doc-content -->
    +     </div> <!-- end body-content --> 
    +-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    + </script>
    + <script type="text/javascript">
    +   try {
    +diff --git a/docs/html/sdk/support_api_diff/23/changes/jdiff_topleftframe.html b/docs/html/sdk/support_api_diff/23/changes/jdiff_topleftframe.html
    +index 36f9836..6a2e76e 100644
    +--- a/docs/html/sdk/support_api_diff/23/changes/jdiff_topleftframe.html
    ++++ b/docs/html/sdk/support_api_diff/23/changes/jdiff_topleftframe.html
    +@@ -49,7 +49,7 @@ body{overflow:auto;}
    +   <TD NOWRAP><FONT CLASS="indexText" size="-2"><A HREF="fields_index_all.html" TARGET="bottomleftframe">By Field</A></FONT><br></TD>
    + </TR>
    + </TABLE>
    +-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    + </script>
    + <script type="text/javascript">
    +   try {
    +diff --git a/docs/html/sdk/support_api_diff/23/changes/methods_index_additions.html b/docs/html/sdk/support_api_diff/23/changes/methods_index_additions.html
    +index 3cec9a3..c3e4176 100644
    +--- a/docs/html/sdk/support_api_diff/23/changes/methods_index_additions.html
    ++++ b/docs/html/sdk/support_api_diff/23/changes/methods_index_additions.html
    +@@ -529,7 +529,7 @@ Listed as: <span style="color:#069"><strong>Added</strong></span>,  <span style=
    + <p><div style="line-height:1.5em;color:black">
    + <nobr><A HREF="android.support.v4.app.FragmentActivity.html#android.support.v4.app.FragmentActivity.validateRequestPermissionsRequestCode_added(int)" class="hiddenlink" target="rightframe"><b>validateRequestPermissionsRequestCode</b>
    + (<code>int</code>)</A></nobr><br>
    +-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    + </script>
    + <script type="text/javascript">
    +   try {
    +diff --git a/docs/html/sdk/support_api_diff/23/changes/methods_index_all.html b/docs/html/sdk/support_api_diff/23/changes/methods_index_all.html
    +index 072b2ff..7b2f1d4 100644
    +--- a/docs/html/sdk/support_api_diff/23/changes/methods_index_all.html
    ++++ b/docs/html/sdk/support_api_diff/23/changes/methods_index_all.html
    +@@ -550,7 +550,7 @@ Listed as: <span style="color:#069"><strong>Added</strong></span>,  <span style=
    + <p><div style="line-height:1.5em;color:black">
    + <nobr><A HREF="android.support.v4.app.FragmentActivity.html#android.support.v4.app.FragmentActivity.validateRequestPermissionsRequestCode_added(int)" class="hiddenlink" target="rightframe"><b>validateRequestPermissionsRequestCode</b>
    + (<code>int</code>)</A></nobr><br>
    +-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    + </script>
    + <script type="text/javascript">
    +   try {
    +diff --git a/docs/html/sdk/support_api_diff/23/changes/methods_index_changes.html b/docs/html/sdk/support_api_diff/23/changes/methods_index_changes.html
    +index d190580..90a0a23 100644
    +--- a/docs/html/sdk/support_api_diff/23/changes/methods_index_changes.html
    ++++ b/docs/html/sdk/support_api_diff/23/changes/methods_index_changes.html
    +@@ -83,7 +83,7 @@ Listed as: <span style="color:#069"><strong>Added</strong></span>,  <span style=
    + <p><div style="line-height:1.5em;color:black">
    + <nobr><A HREF="android.support.v17.leanback.widget.FullWidthDetailsOverviewRowPresenter.html#android.support.v17.leanback.widget.FullWidthDetailsOverviewRowPresenter.setBackgroundColor_changed(int)" class="hiddenlink" target="rightframe">setBackgroundColor
    + (<code>int</code>)</A></nobr><br>
    +-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    + </script>
    + <script type="text/javascript">
    +   try {
    +diff --git a/docs/html/sdk/support_api_diff/23/changes/methods_index_removals.html b/docs/html/sdk/support_api_diff/23/changes/methods_index_removals.html
    +index 2517575..ce89d27 100644
    +--- a/docs/html/sdk/support_api_diff/23/changes/methods_index_removals.html
    ++++ b/docs/html/sdk/support_api_diff/23/changes/methods_index_removals.html
    +@@ -71,7 +71,7 @@ Listed as: <span style="color:#069"><strong>Added</strong></span>,  <span style=
    + <p><div style="line-height:1.5em;color:black">
    + <nobr><A HREF="android.support.v4.app.Fragment.html#android.support.v4.app.Fragment.onAttach_removed(android.app.Activity)" class="hiddenlink" target="rightframe"><strike>onAttach</strike>
    + (<code>Activity</code>)</A></nobr><br>
    +-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    + </script>
    + <script type="text/javascript">
    +   try {
    +diff --git a/docs/html/sdk/support_api_diff/23/changes/packages_index_additions.html b/docs/html/sdk/support_api_diff/23/changes/packages_index_additions.html
    +index 446ee58..fc6d24d 100644
    +--- a/docs/html/sdk/support_api_diff/23/changes/packages_index_additions.html
    ++++ b/docs/html/sdk/support_api_diff/23/changes/packages_index_additions.html
    +@@ -59,7 +59,7 @@ Listed as: <span style="color:#069"><strong>Added</strong></span>,  <span style=
    + <A HREF="changes-summary.html#android.support.v7.graphics.drawable" class="hiddenlink" target="rightframe"><b>android.support.v7.graphics.drawable</b></A><br>
    + <A HREF="changes-summary.html#android.support.v7.preference" class="hiddenlink" target="rightframe"><b>android.support.v7.preference</b></A><br>
    + <A HREF="changes-summary.html#android.support.v8.renderscript" class="hiddenlink" target="rightframe"><b>android.support.v8.renderscript</b></A><br>
    +-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    + </script>
    + <script type="text/javascript">
    +   try {
    +diff --git a/docs/html/sdk/support_api_diff/23/changes/packages_index_all.html b/docs/html/sdk/support_api_diff/23/changes/packages_index_all.html
    +index d1dbbe1..c770167 100644
    +--- a/docs/html/sdk/support_api_diff/23/changes/packages_index_all.html
    ++++ b/docs/html/sdk/support_api_diff/23/changes/packages_index_all.html
    +@@ -77,7 +77,7 @@ Listed as: <span style="color:#069"><strong>Added</strong></span>,  <span style=
    + <A HREF="changes-summary.html#android.support.v7.preference" class="hiddenlink" target="rightframe"><b>android.support.v7.preference</b></A><br>
    + <A HREF="pkg_android.support.v7.util.html" class="hiddenlink" target="rightframe">android.support.v7.util</A><br>
    + <A HREF="changes-summary.html#android.support.v8.renderscript" class="hiddenlink" target="rightframe"><b>android.support.v8.renderscript</b></A><br>
    +-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    + </script>
    + <script type="text/javascript">
    +   try {
    +diff --git a/docs/html/sdk/support_api_diff/23/changes/packages_index_changes.html b/docs/html/sdk/support_api_diff/23/changes/packages_index_changes.html
    +index 730633e..2140313 100644
    +--- a/docs/html/sdk/support_api_diff/23/changes/packages_index_changes.html
    ++++ b/docs/html/sdk/support_api_diff/23/changes/packages_index_changes.html
    +@@ -68,7 +68,7 @@ Listed as: <span style="color:#069"><strong>Added</strong></span>,  <span style=
    + <A HREF="pkg_android.support.v7.appcompat.html" class="hiddenlink" target="rightframe">android.support.v7.appcompat</A><br>
    + <A HREF="pkg_android.support.v7.graphics.html" class="hiddenlink" target="rightframe">android.support.v7.graphics</A><br>
    + <A HREF="pkg_android.support.v7.util.html" class="hiddenlink" target="rightframe">android.support.v7.util</A><br>
    +-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    + </script>
    + <script type="text/javascript">
    +   try {
    +diff --git a/docs/html/sdk/support_api_diff/23/changes/packages_index_removals.html b/docs/html/sdk/support_api_diff/23/changes/packages_index_removals.html
    +index d0ffabc..d5a825d 100644
    +--- a/docs/html/sdk/support_api_diff/23/changes/packages_index_removals.html
    ++++ b/docs/html/sdk/support_api_diff/23/changes/packages_index_removals.html
    +@@ -49,7 +49,7 @@ Listed as: <span style="color:#069"><strong>Added</strong></span>,  <span style=
    + </div>
    + <br>
    + <div id="indexTableEntries">
    +-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    + </script>
    + <script type="text/javascript">
    +   try {
    +diff --git a/docs/html/sdk/support_api_diff/23/changes/pkg_android.support.design.widget.html b/docs/html/sdk/support_api_diff/23/changes/pkg_android.support.design.widget.html
    +index a8630f7..6ebc3a7 100644
    +--- a/docs/html/sdk/support_api_diff/23/changes/pkg_android.support.design.widget.html
    ++++ b/docs/html/sdk/support_api_diff/23/changes/pkg_android.support.design.widget.html
    +@@ -169,7 +169,7 @@ Package <A HREF="../../../../reference/android/support/design/widget/package-sum
    +     </div> <!-- end footer -->
    +     </div><!-- end doc-content -->
    +     </div> <!-- end body-content --> 
    +-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    + </script>
    + <script type="text/javascript">
    +   try {
    +diff --git a/docs/html/sdk/support_api_diff/23/changes/pkg_android.support.v13.app.html b/docs/html/sdk/support_api_diff/23/changes/pkg_android.support.v13.app.html
    +index c56e8a4..877fd6c 100644
    +--- a/docs/html/sdk/support_api_diff/23/changes/pkg_android.support.v13.app.html
    ++++ b/docs/html/sdk/support_api_diff/23/changes/pkg_android.support.v13.app.html
    +@@ -120,7 +120,7 @@ Package <A HREF="../../../../reference/android/support/v13/app/package-summary.h
    +     </div> <!-- end footer -->
    +     </div><!-- end doc-content -->
    +     </div> <!-- end body-content --> 
    +-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    + </script>
    + <script type="text/javascript">
    +   try {
    +diff --git a/docs/html/sdk/support_api_diff/23/changes/pkg_android.support.v17.leanback.widget.html b/docs/html/sdk/support_api_diff/23/changes/pkg_android.support.v17.leanback.widget.html
    +index 3d7f780..ea3848e 100644
    +--- a/docs/html/sdk/support_api_diff/23/changes/pkg_android.support.v17.leanback.widget.html
    ++++ b/docs/html/sdk/support_api_diff/23/changes/pkg_android.support.v17.leanback.widget.html
    +@@ -112,7 +112,7 @@ Package <A HREF="../../../../reference/android/support/v17/leanback/widget/packa
    +     </div> <!-- end footer -->
    +     </div><!-- end doc-content -->
    +     </div> <!-- end body-content --> 
    +-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    + </script>
    + <script type="text/javascript">
    +   try {
    +diff --git a/docs/html/sdk/support_api_diff/23/changes/pkg_android.support.v4.animation.html b/docs/html/sdk/support_api_diff/23/changes/pkg_android.support.v4.animation.html
    +index 36965dd..4a51cf8 100644
    +--- a/docs/html/sdk/support_api_diff/23/changes/pkg_android.support.v4.animation.html
    ++++ b/docs/html/sdk/support_api_diff/23/changes/pkg_android.support.v4.animation.html
    +@@ -105,7 +105,7 @@ Package <A HREF="../../../../reference/android/support/v4/animation/package-summ
    +     </div> <!-- end footer -->
    +     </div><!-- end doc-content -->
    +     </div> <!-- end body-content --> 
    +-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    + </script>
    + <script type="text/javascript">
    +   try {
    +diff --git a/docs/html/sdk/support_api_diff/23/changes/pkg_android.support.v4.app.html b/docs/html/sdk/support_api_diff/23/changes/pkg_android.support.v4.app.html
    +index 692e7ef..9fbee40 100644
    +--- a/docs/html/sdk/support_api_diff/23/changes/pkg_android.support.v4.app.html
    ++++ b/docs/html/sdk/support_api_diff/23/changes/pkg_android.support.v4.app.html
    +@@ -176,7 +176,7 @@ Package <A HREF="../../../../reference/android/support/v4/app/package-summary.ht
    +     </div> <!-- end footer -->
    +     </div><!-- end doc-content -->
    +     </div> <!-- end body-content --> 
    +-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    + </script>
    + <script type="text/javascript">
    +   try {
    +diff --git a/docs/html/sdk/support_api_diff/23/changes/pkg_android.support.v4.content.html b/docs/html/sdk/support_api_diff/23/changes/pkg_android.support.v4.content.html
    +index 44e9f81..9e654a6 100644
    +--- a/docs/html/sdk/support_api_diff/23/changes/pkg_android.support.v4.content.html
    ++++ b/docs/html/sdk/support_api_diff/23/changes/pkg_android.support.v4.content.html
    +@@ -169,7 +169,7 @@ Package <A HREF="../../../../reference/android/support/v4/content/package-summar
    +     </div> <!-- end footer -->
    +     </div><!-- end doc-content -->
    +     </div> <!-- end body-content --> 
    +-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    + </script>
    + <script type="text/javascript">
    +   try {
    +diff --git a/docs/html/sdk/support_api_diff/23/changes/pkg_android.support.v4.graphics.drawable.html b/docs/html/sdk/support_api_diff/23/changes/pkg_android.support.v4.graphics.drawable.html
    +index 6139c8e..de77561 100644
    +--- a/docs/html/sdk/support_api_diff/23/changes/pkg_android.support.v4.graphics.drawable.html
    ++++ b/docs/html/sdk/support_api_diff/23/changes/pkg_android.support.v4.graphics.drawable.html
    +@@ -112,7 +112,7 @@ Package <A HREF="../../../../reference/android/support/v4/graphics/drawable/pack
    +     </div> <!-- end footer -->
    +     </div><!-- end doc-content -->
    +     </div> <!-- end body-content --> 
    +-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    + </script>
    + <script type="text/javascript">
    +   try {
    +diff --git a/docs/html/sdk/support_api_diff/23/changes/pkg_android.support.v4.media.html b/docs/html/sdk/support_api_diff/23/changes/pkg_android.support.v4.media.html
    +index e6fe510..761e746 100644
    +--- a/docs/html/sdk/support_api_diff/23/changes/pkg_android.support.v4.media.html
    ++++ b/docs/html/sdk/support_api_diff/23/changes/pkg_android.support.v4.media.html
    +@@ -112,7 +112,7 @@ Package <A HREF="../../../../reference/android/support/v4/media/package-summary.
    +     </div> <!-- end footer -->
    +     </div><!-- end doc-content -->
    +     </div> <!-- end body-content --> 
    +-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    + </script>
    + <script type="text/javascript">
    +   try {
    +diff --git a/docs/html/sdk/support_api_diff/23/changes/pkg_android.support.v4.media.session.html b/docs/html/sdk/support_api_diff/23/changes/pkg_android.support.v4.media.session.html
    +index 9b0e472..18893f4 100644
    +--- a/docs/html/sdk/support_api_diff/23/changes/pkg_android.support.v4.media.session.html
    ++++ b/docs/html/sdk/support_api_diff/23/changes/pkg_android.support.v4.media.session.html
    +@@ -119,7 +119,7 @@ Package <A HREF="../../../../reference/android/support/v4/media/session/package-
    +     </div> <!-- end footer -->
    +     </div><!-- end doc-content -->
    +     </div> <!-- end body-content --> 
    +-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    + </script>
    + <script type="text/javascript">
    +   try {
    +diff --git a/docs/html/sdk/support_api_diff/23/changes/pkg_android.support.v4.os.html b/docs/html/sdk/support_api_diff/23/changes/pkg_android.support.v4.os.html
    +index 9a76a7b..2ed8d04 100644
    +--- a/docs/html/sdk/support_api_diff/23/changes/pkg_android.support.v4.os.html
    ++++ b/docs/html/sdk/support_api_diff/23/changes/pkg_android.support.v4.os.html
    +@@ -119,7 +119,7 @@ Package <A HREF="../../../../reference/android/support/v4/os/package-summary.htm
    +     </div> <!-- end footer -->
    +     </div><!-- end doc-content -->
    +     </div> <!-- end body-content --> 
    +-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    + </script>
    + <script type="text/javascript">
    +   try {
    +diff --git a/docs/html/sdk/support_api_diff/23/changes/pkg_android.support.v4.text.html b/docs/html/sdk/support_api_diff/23/changes/pkg_android.support.v4.text.html
    +index b2a178a..c995ed8 100644
    +--- a/docs/html/sdk/support_api_diff/23/changes/pkg_android.support.v4.text.html
    ++++ b/docs/html/sdk/support_api_diff/23/changes/pkg_android.support.v4.text.html
    +@@ -105,7 +105,7 @@ Package <A HREF="../../../../reference/android/support/v4/text/package-summary.h
    +     </div> <!-- end footer -->
    +     </div><!-- end doc-content -->
    +     </div> <!-- end body-content --> 
    +-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    + </script>
    + <script type="text/javascript">
    +   try {
    +diff --git a/docs/html/sdk/support_api_diff/23/changes/pkg_android.support.v4.view.accessibility.html b/docs/html/sdk/support_api_diff/23/changes/pkg_android.support.v4.view.accessibility.html
    +index dcdbc56..ec69556 100644
    +--- a/docs/html/sdk/support_api_diff/23/changes/pkg_android.support.v4.view.accessibility.html
    ++++ b/docs/html/sdk/support_api_diff/23/changes/pkg_android.support.v4.view.accessibility.html
    +@@ -127,7 +127,7 @@ Package <A HREF="../../../../reference/android/support/v4/view/accessibility/pac
    +     </div> <!-- end footer -->
    +     </div><!-- end doc-content -->
    +     </div> <!-- end body-content --> 
    +-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    + </script>
    + <script type="text/javascript">
    +   try {
    +diff --git a/docs/html/sdk/support_api_diff/23/changes/pkg_android.support.v4.view.html b/docs/html/sdk/support_api_diff/23/changes/pkg_android.support.v4.view.html
    +index 2a955d3..2361c0f 100644
    +--- a/docs/html/sdk/support_api_diff/23/changes/pkg_android.support.v4.view.html
    ++++ b/docs/html/sdk/support_api_diff/23/changes/pkg_android.support.v4.view.html
    +@@ -105,7 +105,7 @@ Package <A HREF="../../../../reference/android/support/v4/view/package-summary.h
    +     </div> <!-- end footer -->
    +     </div><!-- end doc-content -->
    +     </div> <!-- end body-content --> 
    +-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    + </script>
    + <script type="text/javascript">
    +   try {
    +diff --git a/docs/html/sdk/support_api_diff/23/changes/pkg_android.support.v4.widget.html b/docs/html/sdk/support_api_diff/23/changes/pkg_android.support.v4.widget.html
    +index 482bf1f..c6b5e0c 100644
    +--- a/docs/html/sdk/support_api_diff/23/changes/pkg_android.support.v4.widget.html
    ++++ b/docs/html/sdk/support_api_diff/23/changes/pkg_android.support.v4.widget.html
    +@@ -141,7 +141,7 @@ Package <A HREF="../../../../reference/android/support/v4/widget/package-summary
    +     </div> <!-- end footer -->
    +     </div><!-- end doc-content -->
    +     </div> <!-- end body-content --> 
    +-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    + </script>
    + <script type="text/javascript">
    +   try {
    +diff --git a/docs/html/sdk/support_api_diff/23/changes/pkg_android.support.v7.app.html b/docs/html/sdk/support_api_diff/23/changes/pkg_android.support.v7.app.html
    +index 1dd5425..a99b641 100644
    +--- a/docs/html/sdk/support_api_diff/23/changes/pkg_android.support.v7.app.html
    ++++ b/docs/html/sdk/support_api_diff/23/changes/pkg_android.support.v7.app.html
    +@@ -120,7 +120,7 @@ Package <A HREF="../../../../reference/android/support/v7/app/package-summary.ht
    +     </div> <!-- end footer -->
    +     </div><!-- end doc-content -->
    +     </div> <!-- end body-content --> 
    +-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    + </script>
    + <script type="text/javascript">
    +   try {
    +diff --git a/docs/html/sdk/support_api_diff/23/changes/pkg_android.support.v7.appcompat.html b/docs/html/sdk/support_api_diff/23/changes/pkg_android.support.v7.appcompat.html
    +index e014278..eb5ed08 100644
    +--- a/docs/html/sdk/support_api_diff/23/changes/pkg_android.support.v7.appcompat.html
    ++++ b/docs/html/sdk/support_api_diff/23/changes/pkg_android.support.v7.appcompat.html
    +@@ -154,7 +154,7 @@ Package <A HREF="../../../../reference/android/support/v7/appcompat/package-summ
    +     </div> <!-- end footer -->
    +     </div><!-- end doc-content -->
    +     </div> <!-- end body-content --> 
    +-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    + </script>
    + <script type="text/javascript">
    +   try {
    +diff --git a/docs/html/sdk/support_api_diff/23/changes/pkg_android.support.v7.graphics.html b/docs/html/sdk/support_api_diff/23/changes/pkg_android.support.v7.graphics.html
    +index cb6c97b..9f88138 100644
    +--- a/docs/html/sdk/support_api_diff/23/changes/pkg_android.support.v7.graphics.html
    ++++ b/docs/html/sdk/support_api_diff/23/changes/pkg_android.support.v7.graphics.html
    +@@ -120,7 +120,7 @@ Package <A HREF="../../../../reference/android/support/v7/graphics/package-summa
    +     </div> <!-- end footer -->
    +     </div><!-- end doc-content -->
    +     </div> <!-- end body-content --> 
    +-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    + </script>
    + <script type="text/javascript">
    +   try {
    +diff --git a/docs/html/sdk/support_api_diff/23/changes/pkg_android.support.v7.util.html b/docs/html/sdk/support_api_diff/23/changes/pkg_android.support.v7.util.html
    +index cc0065d..e4da229 100644
    +--- a/docs/html/sdk/support_api_diff/23/changes/pkg_android.support.v7.util.html
    ++++ b/docs/html/sdk/support_api_diff/23/changes/pkg_android.support.v7.util.html
    +@@ -119,7 +119,7 @@ Package <A HREF="../../../../reference/android/support/v7/util/package-summary.h
    +     </div> <!-- end footer -->
    +     </div><!-- end doc-content -->
    +     </div> <!-- end body-content --> 
    +-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    + </script>
    + <script type="text/javascript">
    +   try {
    +diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes.html b/docs/html/sdk/support_api_diff/24.2.0/changes.html
    +new file mode 100644
    +index 0000000..cdf8f36
    +--- /dev/null
    ++++ b/docs/html/sdk/support_api_diff/24.2.0/changes.html
    +@@ -0,0 +1,45 @@
    ++<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
    ++<HTML style="overflow:auto;">
    ++<HEAD>
    ++<meta name="generator" content="JDiff v1.1.0">
    ++<!-- Generated by the JDiff Javadoc doclet -->
    ++<!-- (http://www.jdiff.org) -->
    ++<!-- on Tue Aug 16 14:03:10 EDT 2016 -->
    ++<meta name="description" content="JDiff is a Javadoc doclet which generates an HTML report of all the packages, classes, constructors, methods, and fields which have been removed, added or changed in any way, including their documentation, when two APIs are compared.">
    ++<meta name="keywords" content="diff, jdiff, javadiff, java diff, java difference, API difference, difference between two APIs, API diff, Javadoc, doclet">
    ++<TITLE>
    ++Support&nbsp;Library&nbsp;API&nbsp;Differences&nbsp;Report
    ++</TITLE>
    ++<link href="../../../assets/android-developer-docs.css" rel="stylesheet" type="text/css" />
    ++<link href="stylesheet-jdiff.css" rel="stylesheet" type="text/css" />
    ++<noscript>
    ++<style type="text/css">
    ++body{overflow:auto;}
    ++#body-content{position:relative; top:0;}
    ++#doc-content{overflow:visible;border-left:3px solid #666;}
    ++#side-nav{padding:0;}
    ++#side-nav .toggle-list ul {display:block;}
    ++#resize-packages-nav{border-bottom:3px solid #666;}
    ++</style>
    ++</noscript>
    ++<style type="text/css">
    ++</style>
    ++</head>
    ++<frameset cols="242,**" framespacing="1" frameborder="yes" border="1" bordercolor="#e9e9e9"> 
    ++<frameset rows="174,**" framespacing="1" frameborder="yes"  border="1" bordercolor="#e9e9e9">
    ++    <frame src="changes/jdiff_topleftframe.html" scrolling="no" name="topleftframe" frameborder="1">
    ++    <frame src="changes/alldiffs_index_all.html" scrolling="auto" name="bottomleftframe" frameborder="1">
    ++  </frameset>
    ++  <frame src="changes/changes-summary.html" scrolling="auto" name="rightframe" frameborder="1">
    ++</frameset>
    ++<noframes>
    ++<h2>
    ++Frame Alert
    ++</h2>
    ++
    ++<p>
    ++This document is designed to be viewed using the frames feature. If you see this message, you are using a non-frame-capable web client.
    ++<br>
    ++Link to <a href="changes/changes-summary.html" target="_top">Non-frame version.</A>
    ++</noframes>
    ++</html>
    +diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/alldiffs_index_additions.html b/docs/html/sdk/support_api_diff/24.2.0/changes/alldiffs_index_additions.html
    +new file mode 100644
    +index 0000000..f73d864
    +--- /dev/null
    ++++ b/docs/html/sdk/support_api_diff/24.2.0/changes/alldiffs_index_additions.html
    +@@ -0,0 +1,947 @@
    ++<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
    ++<HTML style="overflow:auto;">
    ++<HEAD>
    ++<meta name="generator" content="JDiff v1.1.0">
    ++<!-- Generated by the JDiff Javadoc doclet -->
    ++<!-- (http://www.jdiff.org) -->
    ++<meta name="description" content="JDiff is a Javadoc doclet which generates an HTML report of all the packages, classes, constructors, methods, and fields which have been removed, added or changed in any way, including their documentation, when two APIs are compared.">
    ++<meta name="keywords" content="diff, jdiff, javadiff, java diff, java difference, API difference, difference between two APIs, API diff, Javadoc, doclet">
    ++<TITLE>
    ++All Additions Index
    ++</TITLE>
    ++<link href="../../../../assets/android-developer-docs.css" rel="stylesheet" type="text/css" />
    ++<link href="../stylesheet-jdiff.css" rel="stylesheet" type="text/css" />
    ++<noscript>
    ++<style type="text/css">
    ++body{overflow:auto;}
    ++#body-content{position:relative; top:0;}
    ++#doc-content{overflow:visible;border-left:3px solid #666;}
    ++#side-nav{padding:0;}
    ++#side-nav .toggle-list ul {display:block;}
    ++#resize-packages-nav{border-bottom:3px solid #666;}
    ++</style>
    ++</noscript>
    ++<style type="text/css">
    ++</style>
    ++</HEAD>
    ++<BODY class="gc-documentation" style="padding:12px;">
    ++<a NAME="topheader"></a>
    ++<table summary="Index for All Differences" width="100%" class="jdiffIndex" border="0" cellspacing="0" cellpadding="0" style="padding-bottom:0;margin-bottom:0;">
    ++  <tr>
    ++  <th class="indexHeader">
    ++    Filter the Index:
    ++  </th>
    ++  </tr>
    ++  <tr>
    ++  <td class="indexText" style="line-height:1.3em;padding-left:2em;">
    ++<a href="alldiffs_index_all.html" xclass="hiddenlink">All Differences</a>
    ++  <br>
    ++<A HREF="alldiffs_index_removals.html" xclass="hiddenlink">Removals</A>
    ++  <br>
    ++<b>Additions</b>
    ++  <br>
    ++<A HREF="alldiffs_index_changes.html"xclass="hiddenlink">Changes</A>
    ++  </td>
    ++  </tr>
    ++</table>
    ++<div id="indexTableCaption" style="background-color:#eee;padding:0 4px 0 4px;font-size:11px;margin-bottom:1em;">
    ++Listed as: <span style="color:#069"><strong>Added</strong></span>,  <span style="color:#069"><strike>Removed</strike></span>,  <span style="color:#069">Changed</span></font>
    ++</div>
    ++<!-- Class AccessibilityManagerCompat.AccessibilityStateChangeListener -->
    ++<A NAME="A"></A>
    ++<br><font size="+2">A</font>&nbsp;
    ++<a href="#B"><font size="-2">B</font></a> 
    ++<a href="#C"><font size="-2">C</font></a> 
    ++<a href="#D"><font size="-2">D</font></a> 
    ++<a href="#E"><font size="-2">E</font></a> 
    ++<a href="#F"><font size="-2">F</font></a> 
    ++<a href="#G"><font size="-2">G</font></a> 
    ++<a href="#H"><font size="-2">H</font></a> 
    ++<a href="#I"><font size="-2">I</font></a> 
    ++<a href="#L"><font size="-2">L</font></a> 
    ++<a href="#M"><font size="-2">M</font></a> 
    ++<a href="#N"><font size="-2">N</font></a> 
    ++<a href="#O"><font size="-2">O</font></a> 
    ++<a href="#P"><font size="-2">P</font></a> 
    ++<a href="#R"><font size="-2">R</font></a> 
    ++<a href="#S"><font size="-2">S</font></a> 
    ++<a href="#T"><font size="-2">T</font></a> 
    ++<a href="#W"><font size="-2">W</font></a> 
    ++ <a href="#topheader"><font size="-2">TOP</font></a>
    ++<p><div style="line-height:1.5em;color:black">
    ++<A HREF="pkg_android.support.v4.view.accessibility.html#AccessibilityManagerCompat.AccessibilityStateChangeListener" class="hiddenlink" target="rightframe"><b><i>AccessibilityManagerCompat.AccessibilityStateChangeListener</i></b></A><br>
    ++<!-- Class AccessibilityManagerCompat.TouchExplorationStateChangeListener -->
    ++<A HREF="pkg_android.support.v4.view.accessibility.html#AccessibilityManagerCompat.TouchExplorationStateChangeListener" class="hiddenlink" target="rightframe"><b><i>AccessibilityManagerCompat.TouchExplorationStateChangeListener</i></b></A><br>
    ++<!-- Field ACTION_ARGUMENT_COLUMN_INT -->
    ++<nobr><A HREF="android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.html#android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.ACTION_ARGUMENT_COLUMN_INT" class="hiddenlink" target="rightframe">ACTION_ARGUMENT_COLUMN_INT</A>
    ++</nobr><br>
    ++<!-- Field ACTION_ARGUMENT_PROGRESS_VALUE -->
    ++<nobr><A HREF="android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.html#android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.ACTION_ARGUMENT_PROGRESS_VALUE" class="hiddenlink" target="rightframe">ACTION_ARGUMENT_PROGRESS_VALUE</A>
    ++</nobr><br>
    ++<!-- Field ACTION_ARGUMENT_ROW_INT -->
    ++<nobr><A HREF="android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.html#android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.ACTION_ARGUMENT_ROW_INT" class="hiddenlink" target="rightframe">ACTION_ARGUMENT_ROW_INT</A>
    ++</nobr><br>
    ++<!-- Field ACTION_CONTEXT_CLICK -->
    ++<nobr><A HREF="android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat.html#android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat.ACTION_CONTEXT_CLICK" class="hiddenlink" target="rightframe">ACTION_CONTEXT_CLICK</A>
    ++</nobr><br>
    ++<!-- Field ACTION_SCROLL_DOWN -->
    ++<nobr><A HREF="android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat.html#android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat.ACTION_SCROLL_DOWN" class="hiddenlink" target="rightframe">ACTION_SCROLL_DOWN</A>
    ++</nobr><br>
    ++<!-- Field ACTION_SCROLL_LEFT -->
    ++<nobr><A HREF="android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat.html#android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat.ACTION_SCROLL_LEFT" class="hiddenlink" target="rightframe">ACTION_SCROLL_LEFT</A>
    ++</nobr><br>
    ++<!-- Field ACTION_SCROLL_RIGHT -->
    ++<nobr><A HREF="android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat.html#android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat.ACTION_SCROLL_RIGHT" class="hiddenlink" target="rightframe">ACTION_SCROLL_RIGHT</A>
    ++</nobr><br>
    ++<!-- Field ACTION_SCROLL_TO_POSITION -->
    ++<nobr><A HREF="android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat.html#android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat.ACTION_SCROLL_TO_POSITION" class="hiddenlink" target="rightframe">ACTION_SCROLL_TO_POSITION</A>
    ++</nobr><br>
    ++<!-- Field ACTION_SCROLL_UP -->
    ++<nobr><A HREF="android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat.html#android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat.ACTION_SCROLL_UP" class="hiddenlink" target="rightframe">ACTION_SCROLL_UP</A>
    ++</nobr><br>
    ++<!-- Field ACTION_SET_PROGRESS -->
    ++<nobr><A HREF="android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat.html#android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat.ACTION_SET_PROGRESS" class="hiddenlink" target="rightframe">ACTION_SET_PROGRESS</A>
    ++</nobr><br>
    ++<!-- Field ACTION_SHOW_ON_SCREEN -->
    ++<nobr><A HREF="android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat.html#android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat.ACTION_SHOW_ON_SCREEN" class="hiddenlink" target="rightframe">ACTION_SHOW_ON_SCREEN</A>
    ++</nobr><br>
    ++<!-- Class ActionBarActivity -->
    ++<A HREF="pkg_android.support.v7.app.html#ActionBarActivity" class="hiddenlink" target="rightframe"><b>ActionBarActivity</b></A><br>
    ++<!-- Class ActionMenuView -->
    ++<A HREF="pkg_android.support.v7.widget.html#ActionMenuView" class="hiddenlink" target="rightframe"><b>ActionMenuView</b></A><br>
    ++<!-- Class ActionMenuView.LayoutParams -->
    ++<A HREF="pkg_android.support.v7.widget.html#ActionMenuView.LayoutParams" class="hiddenlink" target="rightframe"><b>ActionMenuView.LayoutParams</b></A><br>
    ++<!-- Class ActionMenuView.OnMenuItemClickListener -->
    ++<A HREF="pkg_android.support.v7.widget.html#ActionMenuView.OnMenuItemClickListener" class="hiddenlink" target="rightframe"><b><i>ActionMenuView.OnMenuItemClickListener</i></b></A><br>
    ++<!-- Method addTouchExplorationStateChangeListener -->
    ++<nobr><A HREF="android.support.v4.view.accessibility.AccessibilityManagerCompat.html#android.support.v4.view.accessibility.AccessibilityManagerCompat.addTouchExplorationStateChangeListener_added(android.view.accessibility.AccessibilityManager, android.support.v4.view.accessibility.AccessibilityManagerCompat.TouchExplorationStateChangeListener)" class="hiddenlink" target="rightframe"><b>addTouchExplorationStateChangeListener</b>
    ++(<code>AccessibilityManager, TouchExplorationStateChangeListener</code>)</A></nobr><br>
    ++<!-- Package android.support.transition -->
    ++<A HREF="changes-summary.html#android.support.transition" class="hiddenlink" target="rightframe"><b>android.support.transition</b></A><br>
    ++<!-- Package android.support.v4.text.util -->
    ++<A HREF="changes-summary.html#android.support.v4.text.util" class="hiddenlink" target="rightframe"><b>android.support.v4.text.util</b></A><br>
    ++<!-- Class AppCompatActivity -->
    ++<A HREF="pkg_android.support.v7.app.html#AppCompatActivity" class="hiddenlink" target="rightframe"><b>AppCompatActivity</b></A><br>
    ++<!-- Class AppCompatAutoCompleteTextView -->
    ++<A HREF="pkg_android.support.v7.widget.html#AppCompatAutoCompleteTextView" class="hiddenlink" target="rightframe"><b>AppCompatAutoCompleteTextView</b></A><br>
    ++<!-- Class AppCompatButton -->
    ++<A HREF="pkg_android.support.v7.widget.html#AppCompatButton" class="hiddenlink" target="rightframe"><b>AppCompatButton</b></A><br>
    ++<!-- Class AppCompatCheckBox -->
    ++<A HREF="pkg_android.support.v7.widget.html#AppCompatCheckBox" class="hiddenlink" target="rightframe"><b>AppCompatCheckBox</b></A><br>
    ++<!-- Class AppCompatCheckedTextView -->
    ++<A HREF="pkg_android.support.v7.widget.html#AppCompatCheckedTextView" class="hiddenlink" target="rightframe"><b>AppCompatCheckedTextView</b></A><br>
    ++<!-- Class AppCompatDialogFragment -->
    ++<A HREF="pkg_android.support.v7.app.html#AppCompatDialogFragment" class="hiddenlink" target="rightframe"><b>AppCompatDialogFragment</b></A><br>
    ++<!-- Class AppCompatEditText -->
    ++<A HREF="pkg_android.support.v7.widget.html#AppCompatEditText" class="hiddenlink" target="rightframe"><b>AppCompatEditText</b></A><br>
    ++<!-- Class AppCompatImageButton -->
    ++<A HREF="pkg_android.support.v7.widget.html#AppCompatImageButton" class="hiddenlink" target="rightframe"><b>AppCompatImageButton</b></A><br>
    ++<!-- Class AppCompatImageView -->
    ++<A HREF="pkg_android.support.v7.widget.html#AppCompatImageView" class="hiddenlink" target="rightframe"><b>AppCompatImageView</b></A><br>
    ++<!-- Class AppCompatMultiAutoCompleteTextView -->
    ++<A HREF="pkg_android.support.v7.widget.html#AppCompatMultiAutoCompleteTextView" class="hiddenlink" target="rightframe"><b>AppCompatMultiAutoCompleteTextView</b></A><br>
    ++<!-- Class AppCompatRadioButton -->
    ++<A HREF="pkg_android.support.v7.widget.html#AppCompatRadioButton" class="hiddenlink" target="rightframe"><b>AppCompatRadioButton</b></A><br>
    ++<!-- Class AppCompatRatingBar -->
    ++<A HREF="pkg_android.support.v7.widget.html#AppCompatRatingBar" class="hiddenlink" target="rightframe"><b>AppCompatRatingBar</b></A><br>
    ++<!-- Class AppCompatSeekBar -->
    ++<A HREF="pkg_android.support.v7.widget.html#AppCompatSeekBar" class="hiddenlink" target="rightframe"><b>AppCompatSeekBar</b></A><br>
    ++<!-- Class AppCompatSpinner -->
    ++<A HREF="pkg_android.support.v7.widget.html#AppCompatSpinner" class="hiddenlink" target="rightframe"><b>AppCompatSpinner</b></A><br>
    ++<!-- Class AppCompatTextView -->
    ++<A HREF="pkg_android.support.v7.widget.html#AppCompatTextView" class="hiddenlink" target="rightframe"><b>AppCompatTextView</b></A><br>
    ++<!-- Class BatchingListUpdateCallback -->
    ++<A NAME="B"></A>
    ++<br><font size="+2">B</font>&nbsp;
    ++<a href="#A"><font size="-2">A</font></a> 
    ++<a href="#C"><font size="-2">C</font></a> 
    ++<a href="#D"><font size="-2">D</font></a> 
    ++<a href="#E"><font size="-2">E</font></a> 
    ++<a href="#F"><font size="-2">F</font></a> 
    ++<a href="#G"><font size="-2">G</font></a> 
    ++<a href="#H"><font size="-2">H</font></a> 
    ++<a href="#I"><font size="-2">I</font></a> 
    ++<a href="#L"><font size="-2">L</font></a> 
    ++<a href="#M"><font size="-2">M</font></a> 
    ++<a href="#N"><font size="-2">N</font></a> 
    ++<a href="#O"><font size="-2">O</font></a> 
    ++<a href="#P"><font size="-2">P</font></a> 
    ++<a href="#R"><font size="-2">R</font></a> 
    ++<a href="#S"><font size="-2">S</font></a> 
    ++<a href="#T"><font size="-2">T</font></a> 
    ++<a href="#W"><font size="-2">W</font></a> 
    ++ <a href="#topheader"><font size="-2">TOP</font></a>
    ++<p><div style="line-height:1.5em;color:black">
    ++<A HREF="pkg_android.support.v7.util.html#BatchingListUpdateCallback" class="hiddenlink" target="rightframe"><b>BatchingListUpdateCallback</b></A><br>
    ++<!-- Field BT_FOLDER_TYPE_ALBUMS -->
    ++<nobr><A HREF="android.support.v4.media.MediaDescriptionCompat.html#android.support.v4.media.MediaDescriptionCompat.BT_FOLDER_TYPE_ALBUMS" class="hiddenlink" target="rightframe">BT_FOLDER_TYPE_ALBUMS</A>
    ++</nobr><br>
    ++<!-- Field BT_FOLDER_TYPE_ARTISTS -->
    ++<nobr><A HREF="android.support.v4.media.MediaDescriptionCompat.html#android.support.v4.media.MediaDescriptionCompat.BT_FOLDER_TYPE_ARTISTS" class="hiddenlink" target="rightframe">BT_FOLDER_TYPE_ARTISTS</A>
    ++</nobr><br>
    ++<!-- Field BT_FOLDER_TYPE_GENRES -->
    ++<nobr><A HREF="android.support.v4.media.MediaDescriptionCompat.html#android.support.v4.media.MediaDescriptionCompat.BT_FOLDER_TYPE_GENRES" class="hiddenlink" target="rightframe">BT_FOLDER_TYPE_GENRES</A>
    ++</nobr><br>
    ++<!-- Field BT_FOLDER_TYPE_MIXED -->
    ++<nobr><A HREF="android.support.v4.media.MediaDescriptionCompat.html#android.support.v4.media.MediaDescriptionCompat.BT_FOLDER_TYPE_MIXED" class="hiddenlink" target="rightframe">BT_FOLDER_TYPE_MIXED</A>
    ++</nobr><br>
    ++<!-- Field BT_FOLDER_TYPE_PLAYLISTS -->
    ++<nobr><A HREF="android.support.v4.media.MediaDescriptionCompat.html#android.support.v4.media.MediaDescriptionCompat.BT_FOLDER_TYPE_PLAYLISTS" class="hiddenlink" target="rightframe">BT_FOLDER_TYPE_PLAYLISTS</A>
    ++</nobr><br>
    ++<!-- Field BT_FOLDER_TYPE_TITLES -->
    ++<nobr><A HREF="android.support.v4.media.MediaDescriptionCompat.html#android.support.v4.media.MediaDescriptionCompat.BT_FOLDER_TYPE_TITLES" class="hiddenlink" target="rightframe">BT_FOLDER_TYPE_TITLES</A>
    ++</nobr><br>
    ++<!-- Field BT_FOLDER_TYPE_YEARS -->
    ++<nobr><A HREF="android.support.v4.media.MediaDescriptionCompat.html#android.support.v4.media.MediaDescriptionCompat.BT_FOLDER_TYPE_YEARS" class="hiddenlink" target="rightframe">BT_FOLDER_TYPE_YEARS</A>
    ++</nobr><br>
    ++<!-- Method buildMediaButtonPendingIntent -->
    ++<i>buildMediaButtonPendingIntent</i><br>
    ++&nbsp;&nbsp;<nobr><A HREF="android.support.v4.media.session.MediaButtonReceiver.html#android.support.v4.media.session.MediaButtonReceiver.buildMediaButtonPendingIntent_added(android.content.Context, android.content.ComponentName, long)" class="hiddenlink" target="rightframe">type&nbsp;<b>
    ++(<code>Context, ComponentName, long</code>)</b>&nbsp;in&nbsp;android.support.v4.media.session.MediaButtonReceiver
    ++</A></nobr><br>
    ++<!-- Method buildMediaButtonPendingIntent -->
    ++&nbsp;&nbsp;<nobr><A HREF="android.support.v4.media.session.MediaButtonReceiver.html#android.support.v4.media.session.MediaButtonReceiver.buildMediaButtonPendingIntent_added(android.content.Context, long)" class="hiddenlink" target="rightframe">type&nbsp;<b>
    ++(<code>Context, long</code>)</b>&nbsp;in&nbsp;android.support.v4.media.session.MediaButtonReceiver
    ++</A></nobr><br>
    ++<!-- Class CardView -->
    ++<A NAME="C"></A>
    ++<br><font size="+2">C</font>&nbsp;
    ++<a href="#A"><font size="-2">A</font></a> 
    ++<a href="#B"><font size="-2">B</font></a> 
    ++<a href="#D"><font size="-2">D</font></a> 
    ++<a href="#E"><font size="-2">E</font></a> 
    ++<a href="#F"><font size="-2">F</font></a> 
    ++<a href="#G"><font size="-2">G</font></a> 
    ++<a href="#H"><font size="-2">H</font></a> 
    ++<a href="#I"><font size="-2">I</font></a> 
    ++<a href="#L"><font size="-2">L</font></a> 
    ++<a href="#M"><font size="-2">M</font></a> 
    ++<a href="#N"><font size="-2">N</font></a> 
    ++<a href="#O"><font size="-2">O</font></a> 
    ++<a href="#P"><font size="-2">P</font></a> 
    ++<a href="#R"><font size="-2">R</font></a> 
    ++<a href="#S"><font size="-2">S</font></a> 
    ++<a href="#T"><font size="-2">T</font></a> 
    ++<a href="#W"><font size="-2">W</font></a> 
    ++ <a href="#topheader"><font size="-2">TOP</font></a>
    ++<p><div style="line-height:1.5em;color:black">
    ++<A HREF="pkg_android.support.v7.widget.html#CardView" class="hiddenlink" target="rightframe"><b>CardView</b></A><br>
    ++<!-- Method clearColorFilter -->
    ++<nobr><A HREF="android.support.v4.graphics.drawable.DrawableCompat.html#android.support.v4.graphics.drawable.DrawableCompat.clearColorFilter_added(android.graphics.drawable.Drawable)" class="hiddenlink" target="rightframe"><b>clearColorFilter</b>
    ++(<code>Drawable</code>)</A></nobr><br>
    ++<!-- Method clearOnTabSelectedListeners -->
    ++<nobr><A HREF="android.support.design.widget.TabLayout.html#android.support.design.widget.TabLayout.clearOnTabSelectedListeners_added()" class="hiddenlink" target="rightframe"><b>clearOnTabSelectedListeners</b>
    ++()</A></nobr><br>
    ++<!-- Method computeScrollVectorForPosition -->
    ++<nobr><A HREF="android.support.v7.widget.StaggeredGridLayoutManager.html#android.support.v7.widget.StaggeredGridLayoutManager.computeScrollVectorForPosition_added(int)" class="hiddenlink" target="rightframe"><b>computeScrollVectorForPosition</b>
    ++(<code>int</code>)</A></nobr><br>
    ++<!-- Class DiffUtil -->
    ++<A NAME="D"></A>
    ++<br><font size="+2">D</font>&nbsp;
    ++<a href="#A"><font size="-2">A</font></a> 
    ++<a href="#B"><font size="-2">B</font></a> 
    ++<a href="#C"><font size="-2">C</font></a> 
    ++<a href="#E"><font size="-2">E</font></a> 
    ++<a href="#F"><font size="-2">F</font></a> 
    ++<a href="#G"><font size="-2">G</font></a> 
    ++<a href="#H"><font size="-2">H</font></a> 
    ++<a href="#I"><font size="-2">I</font></a> 
    ++<a href="#L"><font size="-2">L</font></a> 
    ++<a href="#M"><font size="-2">M</font></a> 
    ++<a href="#N"><font size="-2">N</font></a> 
    ++<a href="#O"><font size="-2">O</font></a> 
    ++<a href="#P"><font size="-2">P</font></a> 
    ++<a href="#R"><font size="-2">R</font></a> 
    ++<a href="#S"><font size="-2">S</font></a> 
    ++<a href="#T"><font size="-2">T</font></a> 
    ++<a href="#W"><font size="-2">W</font></a> 
    ++ <a href="#topheader"><font size="-2">TOP</font></a>
    ++<p><div style="line-height:1.5em;color:black">
    ++<A HREF="pkg_android.support.v7.util.html#DiffUtil" class="hiddenlink" target="rightframe"><b>DiffUtil</b></A><br>
    ++<!-- Class DiffUtil.Callback -->
    ++<A HREF="pkg_android.support.v7.util.html#DiffUtil.Callback" class="hiddenlink" target="rightframe"><b>DiffUtil.Callback</b></A><br>
    ++<!-- Class DiffUtil.DiffResult -->
    ++<A HREF="pkg_android.support.v7.util.html#DiffUtil.DiffResult" class="hiddenlink" target="rightframe"><b>DiffUtil.DiffResult</b></A><br>
    ++<!-- Field dodgeInsetEdges -->
    ++<nobr><A HREF="android.support.design.widget.CoordinatorLayout.LayoutParams.html#android.support.design.widget.CoordinatorLayout.LayoutParams.dodgeInsetEdges" class="hiddenlink" target="rightframe">dodgeInsetEdges</A>
    ++</nobr><br>
    ++<!-- Field EXTRA_BT_FOLDER_TYPE -->
    ++<A NAME="E"></A>
    ++<br><font size="+2">E</font>&nbsp;
    ++<a href="#A"><font size="-2">A</font></a> 
    ++<a href="#B"><font size="-2">B</font></a> 
    ++<a href="#C"><font size="-2">C</font></a> 
    ++<a href="#D"><font size="-2">D</font></a> 
    ++<a href="#F"><font size="-2">F</font></a> 
    ++<a href="#G"><font size="-2">G</font></a> 
    ++<a href="#H"><font size="-2">H</font></a> 
    ++<a href="#I"><font size="-2">I</font></a> 
    ++<a href="#L"><font size="-2">L</font></a> 
    ++<a href="#M"><font size="-2">M</font></a> 
    ++<a href="#N"><font size="-2">N</font></a> 
    ++<a href="#O"><font size="-2">O</font></a> 
    ++<a href="#P"><font size="-2">P</font></a> 
    ++<a href="#R"><font size="-2">R</font></a> 
    ++<a href="#S"><font size="-2">S</font></a> 
    ++<a href="#T"><font size="-2">T</font></a> 
    ++<a href="#W"><font size="-2">W</font></a> 
    ++ <a href="#topheader"><font size="-2">TOP</font></a>
    ++<p><div style="line-height:1.5em;color:black">
    ++<nobr><A HREF="android.support.v4.media.MediaDescriptionCompat.html#android.support.v4.media.MediaDescriptionCompat.EXTRA_BT_FOLDER_TYPE" class="hiddenlink" target="rightframe">EXTRA_BT_FOLDER_TYPE</A>
    ++</nobr><br>
    ++<!-- Field EXTRA_ENABLE_INSTANT_APPS -->
    ++<nobr><A HREF="android.support.customtabs.CustomTabsIntent.html#android.support.customtabs.CustomTabsIntent.EXTRA_ENABLE_INSTANT_APPS" class="hiddenlink" target="rightframe">EXTRA_ENABLE_INSTANT_APPS</A>
    ++</nobr><br>
    ++<!-- Field EXTRA_SUGGESTION_KEYWORDS -->
    ++<nobr><A HREF="android.support.v4.media.MediaBrowserServiceCompat.BrowserRoot.html#android.support.v4.media.MediaBrowserServiceCompat.BrowserRoot.EXTRA_SUGGESTION_KEYWORDS" class="hiddenlink" target="rightframe">EXTRA_SUGGESTION_KEYWORDS</A>
    ++</nobr><br>
    ++<!-- Field EXTRA_USAGE_TIME_REPORT -->
    ++<nobr><A HREF="android.support.v4.app.ActivityOptionsCompat.html#android.support.v4.app.ActivityOptionsCompat.EXTRA_USAGE_TIME_REPORT" class="hiddenlink" target="rightframe">EXTRA_USAGE_TIME_REPORT</A>
    ++</nobr><br>
    ++<!-- Field EXTRA_USAGE_TIME_REPORT_PACKAGES -->
    ++<nobr><A HREF="android.support.v4.app.ActivityOptionsCompat.html#android.support.v4.app.ActivityOptionsCompat.EXTRA_USAGE_TIME_REPORT_PACKAGES" class="hiddenlink" target="rightframe">EXTRA_USAGE_TIME_REPORT_PACKAGES</A>
    ++</nobr><br>
    ++<!-- Method findFragmentByWho -->
    ++<A NAME="F"></A>
    ++<br><font size="+2">F</font>&nbsp;
    ++<a href="#A"><font size="-2">A</font></a> 
    ++<a href="#B"><font size="-2">B</font></a> 
    ++<a href="#C"><font size="-2">C</font></a> 
    ++<a href="#D"><font size="-2">D</font></a> 
    ++<a href="#E"><font size="-2">E</font></a> 
    ++<a href="#G"><font size="-2">G</font></a> 
    ++<a href="#H"><font size="-2">H</font></a> 
    ++<a href="#I"><font size="-2">I</font></a> 
    ++<a href="#L"><font size="-2">L</font></a> 
    ++<a href="#M"><font size="-2">M</font></a> 
    ++<a href="#N"><font size="-2">N</font></a> 
    ++<a href="#O"><font size="-2">O</font></a> 
    ++<a href="#P"><font size="-2">P</font></a> 
    ++<a href="#R"><font size="-2">R</font></a> 
    ++<a href="#S"><font size="-2">S</font></a> 
    ++<a href="#T"><font size="-2">T</font></a> 
    ++<a href="#W"><font size="-2">W</font></a> 
    ++ <a href="#topheader"><font size="-2">TOP</font></a>
    ++<p><div style="line-height:1.5em;color:black">
    ++<nobr><A HREF="android.support.v4.app.FragmentController.html#android.support.v4.app.FragmentController.findFragmentByWho_added(java.lang.String)" class="hiddenlink" target="rightframe"><b>findFragmentByWho</b>
    ++(<code>String</code>)</A></nobr><br>
    ++<!-- Method fromMediaItem -->
    ++<nobr><A HREF="android.support.v4.media.MediaBrowserCompat.MediaItem.html#android.support.v4.media.MediaBrowserCompat.MediaItem.fromMediaItem_added(java.lang.Object)" class="hiddenlink" target="rightframe"><b>fromMediaItem</b>
    ++(<code>Object</code>)</A></nobr><br>
    ++<!-- Method fromMediaItemList -->
    ++<nobr><A HREF="android.support.v4.media.MediaBrowserCompat.MediaItem.html#android.support.v4.media.MediaBrowserCompat.MediaItem.fromMediaItemList_added(java.util.List<?>)" class="hiddenlink" target="rightframe"><b>fromMediaItemList</b>
    ++(<code>List&lt;?&gt;</code>)</A></nobr><br>
    ++<!-- Method fromMediaSession -->
    ++<nobr><A HREF="android.support.v4.media.session.MediaSessionCompat.html#android.support.v4.media.session.MediaSessionCompat.fromMediaSession_added(android.content.Context, java.lang.Object)" class="hiddenlink" target="rightframe"><b>fromMediaSession</b>
    ++(<code>Context, Object</code>)</A></nobr><br>
    ++<!-- Method fromQueueItem -->
    ++<nobr><A HREF="android.support.v4.media.session.MediaSessionCompat.QueueItem.html#android.support.v4.media.session.MediaSessionCompat.QueueItem.fromQueueItem_added(java.lang.Object)" class="hiddenlink" target="rightframe"><b>fromQueueItem</b>
    ++(<code>Object</code>)</A></nobr><br>
    ++<!-- Method fromQueueItemList -->
    ++<nobr><A HREF="android.support.v4.media.session.MediaSessionCompat.QueueItem.html#android.support.v4.media.session.MediaSessionCompat.QueueItem.fromQueueItemList_added(java.util.List<?>)" class="hiddenlink" target="rightframe"><b>fromQueueItemList</b>
    ++(<code>List&lt;?&gt;</code>)</A></nobr><br>
    ++<!-- Method getAction -->
    ++<A NAME="G"></A>
    ++<br><font size="+2">G</font>&nbsp;
    ++<a href="#A"><font size="-2">A</font></a> 
    ++<a href="#B"><font size="-2">B</font></a> 
    ++<a href="#C"><font size="-2">C</font></a> 
    ++<a href="#D"><font size="-2">D</font></a> 
    ++<a href="#E"><font size="-2">E</font></a> 
    ++<a href="#F"><font size="-2">F</font></a> 
    ++<a href="#H"><font size="-2">H</font></a> 
    ++<a href="#I"><font size="-2">I</font></a> 
    ++<a href="#L"><font size="-2">L</font></a> 
    ++<a href="#M"><font size="-2">M</font></a> 
    ++<a href="#N"><font size="-2">N</font></a> 
    ++<a href="#O"><font size="-2">O</font></a> 
    ++<a href="#P"><font size="-2">P</font></a> 
    ++<a href="#R"><font size="-2">R</font></a> 
    ++<a href="#S"><font size="-2">S</font></a> 
    ++<a href="#T"><font size="-2">T</font></a> 
    ++<a href="#W"><font size="-2">W</font></a> 
    ++ <a href="#topheader"><font size="-2">TOP</font></a>
    ++<p><div style="line-height:1.5em;color:black">
    ++<nobr><A HREF="android.support.v4.view.accessibility.AccessibilityEventCompat.html#android.support.v4.view.accessibility.AccessibilityEventCompat.getAction_added(android.view.accessibility.AccessibilityEvent)" class="hiddenlink" target="rightframe"><b>getAction</b>
    ++(<code>AccessibilityEvent</code>)</A></nobr><br>
    ++<!-- Method getCompoundDrawablesRelative -->
    ++<nobr><A HREF="android.support.v4.widget.TextViewCompat.html#android.support.v4.widget.TextViewCompat.getCompoundDrawablesRelative_added(android.widget.TextView)" class="hiddenlink" target="rightframe"><b>getCompoundDrawablesRelative</b>
    ++(<code>TextView</code>)</A></nobr><br>
    ++<!-- Method getDependents -->
    ++<nobr><A HREF="android.support.design.widget.CoordinatorLayout.html#android.support.design.widget.CoordinatorLayout.getDependents_added(android.view.View)" class="hiddenlink" target="rightframe"><b>getDependents</b>
    ++(<code>View</code>)</A></nobr><br>
    ++<!-- Method getDominantColor -->
    ++<nobr><A HREF="android.support.v7.graphics.Palette.html#android.support.v7.graphics.Palette.getDominantColor_added(int)" class="hiddenlink" target="rightframe"><b>getDominantColor</b>
    ++(<code>int</code>)</A></nobr><br>
    ++<!-- Method getDominantSwatch -->
    ++<nobr><A HREF="android.support.v7.graphics.Palette.html#android.support.v7.graphics.Palette.getDominantSwatch_added()" class="hiddenlink" target="rightframe"><b>getDominantSwatch</b>
    ++()</A></nobr><br>
    ++<!-- Method getDrawable -->
    ++<nobr><A HREF="android.support.v7.content.res.AppCompatResources.html#android.support.v7.content.res.AppCompatResources.getDrawable_added(android.content.Context, int)" class="hiddenlink" target="rightframe"><b>getDrawable</b>
    ++(<code>Context, int</code>)</A></nobr><br>
    ++<!-- Method getDrawerArrowDrawable -->
    ++<nobr><A HREF="android.support.v7.app.ActionBarDrawerToggle.html#android.support.v7.app.ActionBarDrawerToggle.getDrawerArrowDrawable_added()" class="hiddenlink" target="rightframe"><b>getDrawerArrowDrawable</b>
    ++()</A></nobr><br>
    ++<!-- Method getInsetDodgeRect -->
    ++<i>getInsetDodgeRect</i><br>
    ++&nbsp;&nbsp;<nobr><A HREF="android.support.design.widget.CoordinatorLayout.Behavior.html#android.support.design.widget.CoordinatorLayout.Behavior.getInsetDodgeRect_added(android.support.design.widget.CoordinatorLayout, V, android.graphics.Rect)" class="hiddenlink" target="rightframe">type&nbsp;<b>
    ++(<code>CoordinatorLayout, V, Rect</code>)</b>&nbsp;in&nbsp;android.support.design.widget.CoordinatorLayout.Behavior
    ++</A></nobr><br>
    ++<!-- Method getInsetDodgeRect -->
    ++&nbsp;&nbsp;<nobr><A HREF="android.support.design.widget.FloatingActionButton.Behavior.html#android.support.design.widget.FloatingActionButton.Behavior.getInsetDodgeRect_added(android.support.design.widget.CoordinatorLayout, android.support.design.widget.FloatingActionButton, android.graphics.Rect)" class="hiddenlink" target="rightframe">type&nbsp;<b>
    ++(<code>CoordinatorLayout, FloatingActionButton, Rect</code>)</b>&nbsp;in&nbsp;android.support.design.widget.FloatingActionButton.Behavior
    ++</A></nobr><br>
    ++<!-- Method getLaunchBounds -->
    ++<nobr><A HREF="android.support.v4.app.ActivityOptionsCompat.html#android.support.v4.app.ActivityOptionsCompat.getLaunchBounds_added()" class="hiddenlink" target="rightframe"><b>getLaunchBounds</b>
    ++()</A></nobr><br>
    ++<!-- Method getMediaItemNumberViewFlipper -->
    ++<nobr><A HREF="android.support.v17.leanback.widget.AbstractMediaItemPresenter.ViewHolder.html#android.support.v17.leanback.widget.AbstractMediaItemPresenter.ViewHolder.getMediaItemNumberViewFlipper_added()" class="hiddenlink" target="rightframe"><b>getMediaItemNumberViewFlipper</b>
    ++()</A></nobr><br>
    ++<!-- Method getMediaItemPausedView -->
    ++<nobr><A HREF="android.support.v17.leanback.widget.AbstractMediaItemPresenter.ViewHolder.html#android.support.v17.leanback.widget.AbstractMediaItemPresenter.ViewHolder.getMediaItemPausedView_added()" class="hiddenlink" target="rightframe"><b>getMediaItemPausedView</b>
    ++()</A></nobr><br>
    ++<!-- Method getMediaItemPlayingView -->
    ++<nobr><A HREF="android.support.v17.leanback.widget.AbstractMediaItemPresenter.ViewHolder.html#android.support.v17.leanback.widget.AbstractMediaItemPresenter.ViewHolder.getMediaItemPlayingView_added()" class="hiddenlink" target="rightframe"><b>getMediaItemPlayingView</b>
    ++()</A></nobr><br>
    ++<!-- Method getMediaPlayState -->
    ++<nobr><A HREF="android.support.v17.leanback.widget.AbstractMediaItemPresenter.html#android.support.v17.leanback.widget.AbstractMediaItemPresenter.getMediaPlayState_added(java.lang.Object)" class="hiddenlink" target="rightframe"><b>getMediaPlayState</b>
    ++(<code>Object</code>)</A></nobr><br>
    ++<!-- Method getMovementGranularity -->
    ++<nobr><A HREF="android.support.v4.view.accessibility.AccessibilityEventCompat.html#android.support.v4.view.accessibility.AccessibilityEventCompat.getMovementGranularity_added(android.view.accessibility.AccessibilityEvent)" class="hiddenlink" target="rightframe"><b>getMovementGranularity</b>
    ++(<code>AccessibilityEvent</code>)</A></nobr><br>
    ++<!-- Method getOnFlingListener -->
    ++<nobr><A HREF="android.support.v7.widget.RecyclerView.html#android.support.v7.widget.RecyclerView.getOnFlingListener_added()" class="hiddenlink" target="rightframe"><b>getOnFlingListener</b>
    ++()</A></nobr><br>
    ++<!-- Method getPasswordVisibilityToggleContentDescription -->
    ++<nobr><A HREF="android.support.design.widget.TextInputLayout.html#android.support.design.widget.TextInputLayout.getPasswordVisibilityToggleContentDescription_added()" class="hiddenlink" target="rightframe"><b>getPasswordVisibilityToggleContentDescription</b>
    ++()</A></nobr><br>
    ++<!-- Method getPasswordVisibilityToggleDrawable -->
    ++<nobr><A HREF="android.support.design.widget.TextInputLayout.html#android.support.design.widget.TextInputLayout.getPasswordVisibilityToggleDrawable_added()" class="hiddenlink" target="rightframe"><b>getPasswordVisibilityToggleDrawable</b>
    ++()</A></nobr><br>
    ++<!-- Method getSelectionMode -->
    ++<nobr><A HREF="android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.CollectionInfoCompat.html#android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.CollectionInfoCompat.getSelectionMode_added()" class="hiddenlink" target="rightframe"><b>getSelectionMode</b>
    ++()</A></nobr><br>
    ++<!-- Class GridLayout -->
    ++<A HREF="pkg_android.support.v7.widget.html#GridLayout" class="hiddenlink" target="rightframe"><b>GridLayout</b></A><br>
    ++<!-- Class GridLayout.Alignment -->
    ++<A HREF="pkg_android.support.v7.widget.html#GridLayout.Alignment" class="hiddenlink" target="rightframe"><b>GridLayout.Alignment</b></A><br>
    ++<!-- Class GridLayout.LayoutParams -->
    ++<A HREF="pkg_android.support.v7.widget.html#GridLayout.LayoutParams" class="hiddenlink" target="rightframe"><b>GridLayout.LayoutParams</b></A><br>
    ++<!-- Class GridLayout.Spec -->
    ++<A HREF="pkg_android.support.v7.widget.html#GridLayout.Spec" class="hiddenlink" target="rightframe"><b>GridLayout.Spec</b></A><br>
    ++<!-- Field HOST_VIEW_ID -->
    ++<A NAME="H"></A>
    ++<br><font size="+2">H</font>&nbsp;
    ++<a href="#A"><font size="-2">A</font></a> 
    ++<a href="#B"><font size="-2">B</font></a> 
    ++<a href="#C"><font size="-2">C</font></a> 
    ++<a href="#D"><font size="-2">D</font></a> 
    ++<a href="#E"><font size="-2">E</font></a> 
    ++<a href="#F"><font size="-2">F</font></a> 
    ++<a href="#G"><font size="-2">G</font></a> 
    ++<a href="#I"><font size="-2">I</font></a> 
    ++<a href="#L"><font size="-2">L</font></a> 
    ++<a href="#M"><font size="-2">M</font></a> 
    ++<a href="#N"><font size="-2">N</font></a> 
    ++<a href="#O"><font size="-2">O</font></a> 
    ++<a href="#P"><font size="-2">P</font></a> 
    ++<a href="#R"><font size="-2">R</font></a> 
    ++<a href="#S"><font size="-2">S</font></a> 
    ++<a href="#T"><font size="-2">T</font></a> 
    ++<a href="#W"><font size="-2">W</font></a> 
    ++ <a href="#topheader"><font size="-2">TOP</font></a>
    ++<p><div style="line-height:1.5em;color:black">
    ++<nobr><A HREF="android.support.v4.view.accessibility.AccessibilityNodeProviderCompat.html#android.support.v4.view.accessibility.AccessibilityNodeProviderCompat.HOST_VIEW_ID" class="hiddenlink" target="rightframe">HOST_VIEW_ID</A>
    ++</nobr><br>
    ++<!-- Field insetEdge -->
    ++<A NAME="I"></A>
    ++<br><font size="+2">I</font>&nbsp;
    ++<a href="#A"><font size="-2">A</font></a> 
    ++<a href="#B"><font size="-2">B</font></a> 
    ++<a href="#C"><font size="-2">C</font></a> 
    ++<a href="#D"><font size="-2">D</font></a> 
    ++<a href="#E"><font size="-2">E</font></a> 
    ++<a href="#F"><font size="-2">F</font></a> 
    ++<a href="#G"><font size="-2">G</font></a> 
    ++<a href="#H"><font size="-2">H</font></a> 
    ++<a href="#L"><font size="-2">L</font></a> 
    ++<a href="#M"><font size="-2">M</font></a> 
    ++<a href="#N"><font size="-2">N</font></a> 
    ++<a href="#O"><font size="-2">O</font></a> 
    ++<a href="#P"><font size="-2">P</font></a> 
    ++<a href="#R"><font size="-2">R</font></a> 
    ++<a href="#S"><font size="-2">S</font></a> 
    ++<a href="#T"><font size="-2">T</font></a> 
    ++<a href="#W"><font size="-2">W</font></a> 
    ++ <a href="#topheader"><font size="-2">TOP</font></a>
    ++<p><div style="line-height:1.5em;color:black">
    ++<nobr><A HREF="android.support.design.widget.CoordinatorLayout.LayoutParams.html#android.support.design.widget.CoordinatorLayout.LayoutParams.insetEdge" class="hiddenlink" target="rightframe">insetEdge</A>
    ++</nobr><br>
    ++<!-- Method isAtLeastNMR1 -->
    ++<nobr><A HREF="android.support.v4.os.BuildCompat.html#android.support.v4.os.BuildCompat.isAtLeastNMR1_added()" class="hiddenlink" target="rightframe"><b>isAtLeastNMR1</b>
    ++()</A></nobr><br>
    ++<!-- Method isAutoHideEnabled -->
    ++<nobr><A HREF="android.support.design.widget.FloatingActionButton.Behavior.html#android.support.design.widget.FloatingActionButton.Behavior.isAutoHideEnabled_added()" class="hiddenlink" target="rightframe"><b>isAutoHideEnabled</b>
    ++()</A></nobr><br>
    ++<!-- Method isContextClickable -->
    ++<nobr><A HREF="android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.html#android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.isContextClickable_added()" class="hiddenlink" target="rightframe"><b>isContextClickable</b>
    ++()</A></nobr><br>
    ++<!-- Method isImmediateNotifySupported -->
    ++<nobr><A HREF="android.support.v17.leanback.widget.ObjectAdapter.html#android.support.v17.leanback.widget.ObjectAdapter.isImmediateNotifySupported_added()" class="hiddenlink" target="rightframe"><b>isImmediateNotifySupported</b>
    ++()</A></nobr><br>
    ++<!-- Method isImportantForAccessibility -->
    ++<nobr><A HREF="android.support.v4.view.ViewCompat.html#android.support.v4.view.ViewCompat.isImportantForAccessibility_added(android.view.View)" class="hiddenlink" target="rightframe"><b>isImportantForAccessibility</b>
    ++(<code>View</code>)</A></nobr><br>
    ++<!-- Method isPasswordVisibilityToggleEnabled -->
    ++<nobr><A HREF="android.support.design.widget.TextInputLayout.html#android.support.design.widget.TextInputLayout.isPasswordVisibilityToggleEnabled_added()" class="hiddenlink" target="rightframe"><b>isPasswordVisibilityToggleEnabled</b>
    ++()</A></nobr><br>
    ++<!-- Class LinearLayoutCompat -->
    ++<A NAME="L"></A>
    ++<br><font size="+2">L</font>&nbsp;
    ++<a href="#A"><font size="-2">A</font></a> 
    ++<a href="#B"><font size="-2">B</font></a> 
    ++<a href="#C"><font size="-2">C</font></a> 
    ++<a href="#D"><font size="-2">D</font></a> 
    ++<a href="#E"><font size="-2">E</font></a> 
    ++<a href="#F"><font size="-2">F</font></a> 
    ++<a href="#G"><font size="-2">G</font></a> 
    ++<a href="#H"><font size="-2">H</font></a> 
    ++<a href="#I"><font size="-2">I</font></a> 
    ++<a href="#M"><font size="-2">M</font></a> 
    ++<a href="#N"><font size="-2">N</font></a> 
    ++<a href="#O"><font size="-2">O</font></a> 
    ++<a href="#P"><font size="-2">P</font></a> 
    ++<a href="#R"><font size="-2">R</font></a> 
    ++<a href="#S"><font size="-2">S</font></a> 
    ++<a href="#T"><font size="-2">T</font></a> 
    ++<a href="#W"><font size="-2">W</font></a> 
    ++ <a href="#topheader"><font size="-2">TOP</font></a>
    ++<p><div style="line-height:1.5em;color:black">
    ++<A HREF="pkg_android.support.v7.widget.html#LinearLayoutCompat" class="hiddenlink" target="rightframe"><b>LinearLayoutCompat</b></A><br>
    ++<!-- Class LinearLayoutCompat.LayoutParams -->
    ++<A HREF="pkg_android.support.v7.widget.html#LinearLayoutCompat.LayoutParams" class="hiddenlink" target="rightframe"><b>LinearLayoutCompat.LayoutParams</b></A><br>
    ++<!-- Class LinearSnapHelper -->
    ++<A HREF="pkg_android.support.v7.widget.html#LinearSnapHelper" class="hiddenlink" target="rightframe"><b>LinearSnapHelper</b></A><br>
    ++<!-- Class ListPopupWindow -->
    ++<A HREF="pkg_android.support.v7.widget.html#ListPopupWindow" class="hiddenlink" target="rightframe"><b>ListPopupWindow</b></A><br>
    ++<!-- Class ListUpdateCallback -->
    ++<A HREF="pkg_android.support.v7.util.html#ListUpdateCallback" class="hiddenlink" target="rightframe"><b><i>ListUpdateCallback</i></b></A><br>
    ++<!-- Method loadDescription -->
    ++<nobr><A HREF="android.support.v4.accessibilityservice.AccessibilityServiceInfoCompat.html#android.support.v4.accessibilityservice.AccessibilityServiceInfoCompat.loadDescription_added(android.accessibilityservice.AccessibilityServiceInfo, android.content.pm.PackageManager)" class="hiddenlink" target="rightframe"><b>loadDescription</b>
    ++(<code>AccessibilityServiceInfo, PackageManager</code>)</A></nobr><br>
    ++<!-- Method makeBasic -->
    ++<A NAME="M"></A>
    ++<br><font size="+2">M</font>&nbsp;
    ++<a href="#A"><font size="-2">A</font></a> 
    ++<a href="#B"><font size="-2">B</font></a> 
    ++<a href="#C"><font size="-2">C</font></a> 
    ++<a href="#D"><font size="-2">D</font></a> 
    ++<a href="#E"><font size="-2">E</font></a> 
    ++<a href="#F"><font size="-2">F</font></a> 
    ++<a href="#G"><font size="-2">G</font></a> 
    ++<a href="#H"><font size="-2">H</font></a> 
    ++<a href="#I"><font size="-2">I</font></a> 
    ++<a href="#L"><font size="-2">L</font></a> 
    ++<a href="#N"><font size="-2">N</font></a> 
    ++<a href="#O"><font size="-2">O</font></a> 
    ++<a href="#P"><font size="-2">P</font></a> 
    ++<a href="#R"><font size="-2">R</font></a> 
    ++<a href="#S"><font size="-2">S</font></a> 
    ++<a href="#T"><font size="-2">T</font></a> 
    ++<a href="#W"><font size="-2">W</font></a> 
    ++ <a href="#topheader"><font size="-2">TOP</font></a>
    ++<p><div style="line-height:1.5em;color:black">
    ++<nobr><A HREF="android.support.v4.app.ActivityOptionsCompat.html#android.support.v4.app.ActivityOptionsCompat.makeBasic_added()" class="hiddenlink" target="rightframe"><b>makeBasic</b>
    ++()</A></nobr><br>
    ++<!-- Method makeClipRevealAnimation -->
    ++<nobr><A HREF="android.support.v4.app.ActivityOptionsCompat.html#android.support.v4.app.ActivityOptionsCompat.makeClipRevealAnimation_added(android.view.View, int, int, int, int)" class="hiddenlink" target="rightframe"><b>makeClipRevealAnimation</b>
    ++(<code>View, int, int, int, int</code>)</A></nobr><br>
    ++<!-- Method makeTaskLaunchBehind -->
    ++<nobr><A HREF="android.support.v4.app.ActivityOptionsCompat.html#android.support.v4.app.ActivityOptionsCompat.makeTaskLaunchBehind_added()" class="hiddenlink" target="rightframe"><b>makeTaskLaunchBehind</b>
    ++()</A></nobr><br>
    ++<!-- Field METADATA_KEY_BT_FOLDER_TYPE -->
    ++<nobr><A HREF="android.support.v4.media.MediaMetadataCompat.html#android.support.v4.media.MediaMetadataCompat.METADATA_KEY_BT_FOLDER_TYPE" class="hiddenlink" target="rightframe">METADATA_KEY_BT_FOLDER_TYPE</A>
    ++</nobr><br>
    ++<!-- Field METADATA_KEY_MEDIA_URI -->
    ++<nobr><A HREF="android.support.v4.media.MediaMetadataCompat.html#android.support.v4.media.MediaMetadataCompat.METADATA_KEY_MEDIA_URI" class="hiddenlink" target="rightframe">METADATA_KEY_MEDIA_URI</A>
    ++</nobr><br>
    ++<!-- Class MultiSelectListPreferenceDialogFragmentCompat -->
    ++<A HREF="pkg_android.support.v7.preference.html#MultiSelectListPreferenceDialogFragmentCompat" class="hiddenlink" target="rightframe"><b>MultiSelectListPreferenceDialogFragmentCompat</b></A><br>
    ++<!-- Class NotificationCompat -->
    ++<A NAME="N"></A>
    ++<br><font size="+2">N</font>&nbsp;
    ++<a href="#A"><font size="-2">A</font></a> 
    ++<a href="#B"><font size="-2">B</font></a> 
    ++<a href="#C"><font size="-2">C</font></a> 
    ++<a href="#D"><font size="-2">D</font></a> 
    ++<a href="#E"><font size="-2">E</font></a> 
    ++<a href="#F"><font size="-2">F</font></a> 
    ++<a href="#G"><font size="-2">G</font></a> 
    ++<a href="#H"><font size="-2">H</font></a> 
    ++<a href="#I"><font size="-2">I</font></a> 
    ++<a href="#L"><font size="-2">L</font></a> 
    ++<a href="#M"><font size="-2">M</font></a> 
    ++<a href="#O"><font size="-2">O</font></a> 
    ++<a href="#P"><font size="-2">P</font></a> 
    ++<a href="#R"><font size="-2">R</font></a> 
    ++<a href="#S"><font size="-2">S</font></a> 
    ++<a href="#T"><font size="-2">T</font></a> 
    ++<a href="#W"><font size="-2">W</font></a> 
    ++ <a href="#topheader"><font size="-2">TOP</font></a>
    ++<p><div style="line-height:1.5em;color:black">
    ++<A HREF="pkg_android.support.v7.app.html#NotificationCompat" class="hiddenlink" target="rightframe"><b>NotificationCompat</b></A><br>
    ++<!-- Class NotificationCompat.Builder -->
    ++<A HREF="pkg_android.support.v7.app.html#NotificationCompat.Builder" class="hiddenlink" target="rightframe"><b>NotificationCompat.Builder</b></A><br>
    ++<!-- Class NotificationCompat.MediaStyle -->
    ++<A HREF="pkg_android.support.v7.app.html#NotificationCompat.MediaStyle" class="hiddenlink" target="rightframe"><b>NotificationCompat.MediaStyle</b></A><br>
    ++<!-- Method notifyPlayStateChanged -->
    ++<nobr><A HREF="android.support.v17.leanback.widget.AbstractMediaItemPresenter.ViewHolder.html#android.support.v17.leanback.widget.AbstractMediaItemPresenter.ViewHolder.notifyPlayStateChanged_added()" class="hiddenlink" target="rightframe"><b>notifyPlayStateChanged</b>
    ++()</A></nobr><br>
    ++<!-- Method obtain -->
    ++<A NAME="O"></A>
    ++<br><font size="+2">O</font>&nbsp;
    ++<a href="#A"><font size="-2">A</font></a> 
    ++<a href="#B"><font size="-2">B</font></a> 
    ++<a href="#C"><font size="-2">C</font></a> 
    ++<a href="#D"><font size="-2">D</font></a> 
    ++<a href="#E"><font size="-2">E</font></a> 
    ++<a href="#F"><font size="-2">F</font></a> 
    ++<a href="#G"><font size="-2">G</font></a> 
    ++<a href="#H"><font size="-2">H</font></a> 
    ++<a href="#I"><font size="-2">I</font></a> 
    ++<a href="#L"><font size="-2">L</font></a> 
    ++<a href="#M"><font size="-2">M</font></a> 
    ++<a href="#N"><font size="-2">N</font></a> 
    ++<a href="#P"><font size="-2">P</font></a> 
    ++<a href="#R"><font size="-2">R</font></a> 
    ++<a href="#S"><font size="-2">S</font></a> 
    ++<a href="#T"><font size="-2">T</font></a> 
    ++<a href="#W"><font size="-2">W</font></a> 
    ++ <a href="#topheader"><font size="-2">TOP</font></a>
    ++<p><div style="line-height:1.5em;color:black">
    ++<i>obtain</i><br>
    ++&nbsp;&nbsp;<nobr><A HREF="android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.CollectionInfoCompat.html#android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.CollectionInfoCompat.obtain_added(int, int, boolean)" class="hiddenlink" target="rightframe">type&nbsp;<b>
    ++(<code>int, int, boolean</code>)</b>&nbsp;in&nbsp;android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.CollectionInfoCompat
    ++</A></nobr><br>
    ++<!-- Method obtain -->
    ++&nbsp;&nbsp;<nobr><A HREF="android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.CollectionItemInfoCompat.html#android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.CollectionItemInfoCompat.obtain_added(int, int, int, int, boolean)" class="hiddenlink" target="rightframe">type&nbsp;<b>
    ++(<code>int, int, int, int, boolean</code>)</b>&nbsp;in&nbsp;android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.CollectionItemInfoCompat
    ++</A></nobr><br>
    ++<!-- Method obtain -->
    ++&nbsp;&nbsp;<nobr><A HREF="android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.RangeInfoCompat.html#android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.RangeInfoCompat.obtain_added(int, float, float, float)" class="hiddenlink" target="rightframe">type&nbsp;<b>
    ++(<code>int, float, float, float</code>)</b>&nbsp;in&nbsp;android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.RangeInfoCompat
    ++</A></nobr><br>
    ++<!-- Method onAttachedToLayoutParams -->
    ++<nobr><A HREF="android.support.design.widget.CoordinatorLayout.Behavior.html#android.support.design.widget.CoordinatorLayout.Behavior.onAttachedToLayoutParams_added(android.support.design.widget.CoordinatorLayout.LayoutParams)" class="hiddenlink" target="rightframe"><b>onAttachedToLayoutParams</b>
    ++(<code>LayoutParams</code>)</A></nobr><br>
    ++<!-- Method onBindMediaPlayState -->
    ++<nobr><A HREF="android.support.v17.leanback.widget.AbstractMediaItemPresenter.html#android.support.v17.leanback.widget.AbstractMediaItemPresenter.onBindMediaPlayState_added(android.support.v17.leanback.widget.AbstractMediaItemPresenter.ViewHolder)" class="hiddenlink" target="rightframe"><b>onBindMediaPlayState</b>
    ++(<code>ViewHolder</code>)</A></nobr><br>
    ++<!-- Method onChanged -->
    ++<nobr><A HREF="android.support.v7.util.SortedList.Callback.html#android.support.v7.util.SortedList.Callback.onChanged_added(int, int, java.lang.Object)" class="hiddenlink" target="rightframe"><b>onChanged</b>
    ++(<code>int, int, Object</code>)</A></nobr><br>
    ++<!-- Method onDetachedFromLayoutParams -->
    ++<nobr><A HREF="android.support.design.widget.CoordinatorLayout.Behavior.html#android.support.design.widget.CoordinatorLayout.Behavior.onDetachedFromLayoutParams_added()" class="hiddenlink" target="rightframe"><b>onDetachedFromLayoutParams</b>
    ++()</A></nobr><br>
    ++<!-- Method onRequestChildRectangleOnScreen -->
    ++<i>onRequestChildRectangleOnScreen</i><br>
    ++&nbsp;&nbsp;<nobr><A HREF="android.support.design.widget.AppBarLayout.ScrollingViewBehavior.html#android.support.design.widget.AppBarLayout.ScrollingViewBehavior.onRequestChildRectangleOnScreen_added(android.support.design.widget.CoordinatorLayout, android.view.View, android.graphics.Rect, boolean)" class="hiddenlink" target="rightframe">type&nbsp;<b>
    ++(<code>CoordinatorLayout, View, Rect, boolean</code>)</b>&nbsp;in&nbsp;android.support.design.widget.AppBarLayout.ScrollingViewBehavior
    ++</A></nobr><br>
    ++<!-- Method onRequestChildRectangleOnScreen -->
    ++&nbsp;&nbsp;<nobr><A HREF="android.support.design.widget.CoordinatorLayout.Behavior.html#android.support.design.widget.CoordinatorLayout.Behavior.onRequestChildRectangleOnScreen_added(android.support.design.widget.CoordinatorLayout, V, android.graphics.Rect, boolean)" class="hiddenlink" target="rightframe">type&nbsp;<b>
    ++(<code>CoordinatorLayout, V, Rect, boolean</code>)</b>&nbsp;in&nbsp;android.support.design.widget.CoordinatorLayout.Behavior
    ++</A></nobr><br>
    ++<!-- Method onSharedElementsArrived -->
    ++<nobr><A HREF="android.support.v4.app.SharedElementCallback.html#android.support.v4.app.SharedElementCallback.onSharedElementsArrived_added(java.util.List<java.lang.String>, java.util.List<android.view.View>, android.support.v4.app.SharedElementCallback.OnSharedElementsReadyListener)" class="hiddenlink" target="rightframe"><b>onSharedElementsArrived</b>
    ++(<code>List&lt;String&gt;, List&lt;View&gt;, OnSharedElementsReadyListener</code>)</A></nobr><br>
    ++<!-- Method onStart -->
    ++<nobr><A HREF="android.support.v7.app.AppCompatDelegate.html#android.support.v7.app.AppCompatDelegate.onStart_added()" class="hiddenlink" target="rightframe"><b>onStart</b>
    ++()</A></nobr><br>
    ++<!-- Method onUnbindMediaPlayState -->
    ++<nobr><A HREF="android.support.v17.leanback.widget.AbstractMediaItemPresenter.html#android.support.v17.leanback.widget.AbstractMediaItemPresenter.onUnbindMediaPlayState_added(android.support.v17.leanback.widget.AbstractMediaItemPresenter.ViewHolder)" class="hiddenlink" target="rightframe"><b>onUnbindMediaPlayState</b>
    ++(<code>ViewHolder</code>)</A></nobr><br>
    ++<!-- Class PatternsCompat -->
    ++<A NAME="P"></A>
    ++<br><font size="+2">P</font>&nbsp;
    ++<a href="#A"><font size="-2">A</font></a> 
    ++<a href="#B"><font size="-2">B</font></a> 
    ++<a href="#C"><font size="-2">C</font></a> 
    ++<a href="#D"><font size="-2">D</font></a> 
    ++<a href="#E"><font size="-2">E</font></a> 
    ++<a href="#F"><font size="-2">F</font></a> 
    ++<a href="#G"><font size="-2">G</font></a> 
    ++<a href="#H"><font size="-2">H</font></a> 
    ++<a href="#I"><font size="-2">I</font></a> 
    ++<a href="#L"><font size="-2">L</font></a> 
    ++<a href="#M"><font size="-2">M</font></a> 
    ++<a href="#N"><font size="-2">N</font></a> 
    ++<a href="#O"><font size="-2">O</font></a> 
    ++<a href="#R"><font size="-2">R</font></a> 
    ++<a href="#S"><font size="-2">S</font></a> 
    ++<a href="#T"><font size="-2">T</font></a> 
    ++<a href="#W"><font size="-2">W</font></a> 
    ++ <a href="#topheader"><font size="-2">TOP</font></a>
    ++<p><div style="line-height:1.5em;color:black">
    ++<A HREF="pkg_android.support.v4.util.html#PatternsCompat" class="hiddenlink" target="rightframe"><b>PatternsCompat</b></A><br>
    ++<!-- Field PEEK_HEIGHT_AUTO -->
    ++<nobr><A HREF="android.support.design.widget.BottomSheetBehavior.html#android.support.design.widget.BottomSheetBehavior.PEEK_HEIGHT_AUTO" class="hiddenlink" target="rightframe">PEEK_HEIGHT_AUTO</A>
    ++</nobr><br>
    ++<!-- Field PLAY_STATE_INITIAL -->
    ++<nobr><A HREF="android.support.v17.leanback.widget.AbstractMediaItemPresenter.html#android.support.v17.leanback.widget.AbstractMediaItemPresenter.PLAY_STATE_INITIAL" class="hiddenlink" target="rightframe">PLAY_STATE_INITIAL</A>
    ++</nobr><br>
    ++<!-- Field PLAY_STATE_PAUSED -->
    ++<nobr><A HREF="android.support.v17.leanback.widget.AbstractMediaItemPresenter.html#android.support.v17.leanback.widget.AbstractMediaItemPresenter.PLAY_STATE_PAUSED" class="hiddenlink" target="rightframe">PLAY_STATE_PAUSED</A>
    ++</nobr><br>
    ++<!-- Field PLAY_STATE_PLAYING -->
    ++<nobr><A HREF="android.support.v17.leanback.widget.AbstractMediaItemPresenter.html#android.support.v17.leanback.widget.AbstractMediaItemPresenter.PLAY_STATE_PLAYING" class="hiddenlink" target="rightframe">PLAY_STATE_PLAYING</A>
    ++</nobr><br>
    ++<!-- Class PopupMenu -->
    ++<A HREF="pkg_android.support.v7.widget.html#PopupMenu" class="hiddenlink" target="rightframe"><b>PopupMenu</b></A><br>
    ++<!-- Class PopupMenu.OnDismissListener -->
    ++<A HREF="pkg_android.support.v7.widget.html#PopupMenu.OnDismissListener" class="hiddenlink" target="rightframe"><b><i>PopupMenu.OnDismissListener</i></b></A><br>
    ++<!-- Class PopupMenu.OnMenuItemClickListener -->
    ++<A HREF="pkg_android.support.v7.widget.html#PopupMenu.OnMenuItemClickListener" class="hiddenlink" target="rightframe"><b><i>PopupMenu.OnMenuItemClickListener</i></b></A><br>
    ++<!-- Class RecyclerView.OnFlingListener -->
    ++<A NAME="R"></A>
    ++<br><font size="+2">R</font>&nbsp;
    ++<a href="#A"><font size="-2">A</font></a> 
    ++<a href="#B"><font size="-2">B</font></a> 
    ++<a href="#C"><font size="-2">C</font></a> 
    ++<a href="#D"><font size="-2">D</font></a> 
    ++<a href="#E"><font size="-2">E</font></a> 
    ++<a href="#F"><font size="-2">F</font></a> 
    ++<a href="#G"><font size="-2">G</font></a> 
    ++<a href="#H"><font size="-2">H</font></a> 
    ++<a href="#I"><font size="-2">I</font></a> 
    ++<a href="#L"><font size="-2">L</font></a> 
    ++<a href="#M"><font size="-2">M</font></a> 
    ++<a href="#N"><font size="-2">N</font></a> 
    ++<a href="#O"><font size="-2">O</font></a> 
    ++<a href="#P"><font size="-2">P</font></a> 
    ++<a href="#S"><font size="-2">S</font></a> 
    ++<a href="#T"><font size="-2">T</font></a> 
    ++<a href="#W"><font size="-2">W</font></a> 
    ++ <a href="#topheader"><font size="-2">TOP</font></a>
    ++<p><div style="line-height:1.5em;color:black">
    ++<A HREF="pkg_android.support.v7.widget.html#RecyclerView.OnFlingListener" class="hiddenlink" target="rightframe"><b>RecyclerView.OnFlingListener</b></A><br>
    ++<!-- Class RecyclerView.SmoothScroller.ScrollVectorProvider -->
    ++<A HREF="pkg_android.support.v7.widget.html#RecyclerView.SmoothScroller.ScrollVectorProvider" class="hiddenlink" target="rightframe"><b><i>RecyclerView.SmoothScroller.ScrollVectorProvider</i></b></A><br>
    ++<!-- Method removeTouchExplorationStateChangeListener -->
    ++<nobr><A HREF="android.support.v4.view.accessibility.AccessibilityManagerCompat.html#android.support.v4.view.accessibility.AccessibilityManagerCompat.removeTouchExplorationStateChangeListener_added(android.view.accessibility.AccessibilityManager, android.support.v4.view.accessibility.AccessibilityManagerCompat.TouchExplorationStateChangeListener)" class="hiddenlink" target="rightframe"><b>removeTouchExplorationStateChangeListener</b>
    ++(<code>AccessibilityManager, TouchExplorationStateChangeListener</code>)</A></nobr><br>
    ++<!-- Method requestUsageTimeReport -->
    ++<nobr><A HREF="android.support.v4.app.ActivityOptionsCompat.html#android.support.v4.app.ActivityOptionsCompat.requestUsageTimeReport_added(android.app.PendingIntent)" class="hiddenlink" target="rightframe"><b>requestUsageTimeReport</b>
    ++(<code>PendingIntent</code>)</A></nobr><br>
    ++<!-- Class SearchView -->
    ++<A NAME="S"></A>
    ++<br><font size="+2">S</font>&nbsp;
    ++<a href="#A"><font size="-2">A</font></a> 
    ++<a href="#B"><font size="-2">B</font></a> 
    ++<a href="#C"><font size="-2">C</font></a> 
    ++<a href="#D"><font size="-2">D</font></a> 
    ++<a href="#E"><font size="-2">E</font></a> 
    ++<a href="#F"><font size="-2">F</font></a> 
    ++<a href="#G"><font size="-2">G</font></a> 
    ++<a href="#H"><font size="-2">H</font></a> 
    ++<a href="#I"><font size="-2">I</font></a> 
    ++<a href="#L"><font size="-2">L</font></a> 
    ++<a href="#M"><font size="-2">M</font></a> 
    ++<a href="#N"><font size="-2">N</font></a> 
    ++<a href="#O"><font size="-2">O</font></a> 
    ++<a href="#P"><font size="-2">P</font></a> 
    ++<a href="#R"><font size="-2">R</font></a> 
    ++<a href="#T"><font size="-2">T</font></a> 
    ++<a href="#W"><font size="-2">W</font></a> 
    ++ <a href="#topheader"><font size="-2">TOP</font></a>
    ++<p><div style="line-height:1.5em;color:black">
    ++<A HREF="pkg_android.support.v7.widget.html#SearchView" class="hiddenlink" target="rightframe"><b>SearchView</b></A><br>
    ++<!-- Class SearchView.OnCloseListener -->
    ++<A HREF="pkg_android.support.v7.widget.html#SearchView.OnCloseListener" class="hiddenlink" target="rightframe"><b><i>SearchView.OnCloseListener</i></b></A><br>
    ++<!-- Class SearchView.OnQueryTextListener -->
    ++<A HREF="pkg_android.support.v7.widget.html#SearchView.OnQueryTextListener" class="hiddenlink" target="rightframe"><b><i>SearchView.OnQueryTextListener</i></b></A><br>
    ++<!-- Class SearchView.OnSuggestionListener -->
    ++<A HREF="pkg_android.support.v7.widget.html#SearchView.OnSuggestionListener" class="hiddenlink" target="rightframe"><b><i>SearchView.OnSuggestionListener</i></b></A><br>
    ++<!-- Class SearchViewCompat.OnCloseListener -->
    ++<A HREF="pkg_android.support.v4.widget.html#SearchViewCompat.OnCloseListener" class="hiddenlink" target="rightframe"><b><i>SearchViewCompat.OnCloseListener</i></b></A><br>
    ++<!-- Class SearchViewCompat.OnQueryTextListener -->
    ++<A HREF="pkg_android.support.v4.widget.html#SearchViewCompat.OnQueryTextListener" class="hiddenlink" target="rightframe"><b><i>SearchViewCompat.OnQueryTextListener</i></b></A><br>
    ++<!-- Method setAction -->
    ++<nobr><A HREF="android.support.v4.view.accessibility.AccessibilityEventCompat.html#android.support.v4.view.accessibility.AccessibilityEventCompat.setAction_added(android.view.accessibility.AccessibilityEvent, int)" class="hiddenlink" target="rightframe"><b>setAction</b>
    ++(<code>AccessibilityEvent, int</code>)</A></nobr><br>
    ++<!-- Method setAlwaysUseBrowserUI -->
    ++<nobr><A HREF="android.support.customtabs.CustomTabsIntent.html#android.support.customtabs.CustomTabsIntent.setAlwaysUseBrowserUI_added(android.content.Intent)" class="hiddenlink" target="rightframe"><b>setAlwaysUseBrowserUI</b>
    ++(<code>Intent</code>)</A></nobr><br>
    ++<!-- Method setAutoHideEnabled -->
    ++<nobr><A HREF="android.support.design.widget.FloatingActionButton.Behavior.html#android.support.design.widget.FloatingActionButton.Behavior.setAutoHideEnabled_added(boolean)" class="hiddenlink" target="rightframe"><b>setAutoHideEnabled</b>
    ++(<code>boolean</code>)</A></nobr><br>
    ++<!-- Method setCollapsedTitleTextColor -->
    ++<nobr><A HREF="android.support.design.widget.CollapsingToolbarLayout.html#android.support.design.widget.CollapsingToolbarLayout.setCollapsedTitleTextColor_added(android.content.res.ColorStateList)" class="hiddenlink" target="rightframe"><b>setCollapsedTitleTextColor</b>
    ++(<code>ColorStateList</code>)</A></nobr><br>
    ++<!-- Method setContextClickable -->
    ++<nobr><A HREF="android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.html#android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.setContextClickable_added(boolean)" class="hiddenlink" target="rightframe"><b>setContextClickable</b>
    ++(<code>boolean</code>)</A></nobr><br>
    ++<!-- Method setDrawerArrowDrawable -->
    ++<nobr><A HREF="android.support.v7.app.ActionBarDrawerToggle.html#android.support.v7.app.ActionBarDrawerToggle.setDrawerArrowDrawable_added(android.support.v7.graphics.drawable.DrawerArrowDrawable)" class="hiddenlink" target="rightframe"><b>setDrawerArrowDrawable</b>
    ++(<code>DrawerArrowDrawable</code>)</A></nobr><br>
    ++<!-- Method setExpandedTitleTextColor -->
    ++<nobr><A HREF="android.support.design.widget.CollapsingToolbarLayout.html#android.support.design.widget.CollapsingToolbarLayout.setExpandedTitleTextColor_added(android.content.res.ColorStateList)" class="hiddenlink" target="rightframe"><b>setExpandedTitleTextColor</b>
    ++(<code>ColorStateList</code>)</A></nobr><br>
    ++<!-- Method setInstantAppsEnabled -->
    ++<nobr><A HREF="android.support.customtabs.CustomTabsIntent.Builder.html#android.support.customtabs.CustomTabsIntent.Builder.setInstantAppsEnabled_added(boolean)" class="hiddenlink" target="rightframe"><b>setInstantAppsEnabled</b>
    ++(<code>boolean</code>)</A></nobr><br>
    ++<!-- Method setLaunchBounds -->
    ++<nobr><A HREF="android.support.v4.app.ActivityOptionsCompat.html#android.support.v4.app.ActivityOptionsCompat.setLaunchBounds_added(android.graphics.Rect)" class="hiddenlink" target="rightframe"><b>setLaunchBounds</b>
    ++(<code>Rect</code>)</A></nobr><br>
    ++<!-- Method setMovementGranularity -->
    ++<nobr><A HREF="android.support.v4.view.accessibility.AccessibilityEventCompat.html#android.support.v4.view.accessibility.AccessibilityEventCompat.setMovementGranularity_added(android.view.accessibility.AccessibilityEvent, int)" class="hiddenlink" target="rightframe"><b>setMovementGranularity</b>
    ++(<code>AccessibilityEvent, int</code>)</A></nobr><br>
    ++<!-- Method setOnChildScrollUpCallback -->
    ++<nobr><A HREF="android.support.v4.widget.SwipeRefreshLayout.html#android.support.v4.widget.SwipeRefreshLayout.setOnChildScrollUpCallback_added(android.support.v4.widget.SwipeRefreshLayout.OnChildScrollUpCallback)" class="hiddenlink" target="rightframe"><b>setOnChildScrollUpCallback</b>
    ++(<code>OnChildScrollUpCallback</code>)</A></nobr><br>
    ++<!-- Method setOnFlingListener -->
    ++<nobr><A HREF="android.support.v7.widget.RecyclerView.html#android.support.v7.widget.RecyclerView.setOnFlingListener_added(android.support.v7.widget.RecyclerView.OnFlingListener)" class="hiddenlink" target="rightframe"><b>setOnFlingListener</b>
    ++(<code>OnFlingListener</code>)</A></nobr><br>
    ++<!-- Method setPasswordVisibilityToggleContentDescription -->
    ++<i>setPasswordVisibilityToggleContentDescription</i><br>
    ++&nbsp;&nbsp;<nobr><A HREF="android.support.design.widget.TextInputLayout.html#android.support.design.widget.TextInputLayout.setPasswordVisibilityToggleContentDescription_added(int)" class="hiddenlink" target="rightframe">type&nbsp;<b>
    ++(<code>int</code>)</b>&nbsp;in&nbsp;android.support.design.widget.TextInputLayout
    ++</A></nobr><br>
    ++<!-- Method setPasswordVisibilityToggleContentDescription -->
    ++&nbsp;&nbsp;<nobr><A HREF="android.support.design.widget.TextInputLayout.html#android.support.design.widget.TextInputLayout.setPasswordVisibilityToggleContentDescription_added(java.lang.CharSequence)" class="hiddenlink" target="rightframe">type&nbsp;<b>
    ++(<code>CharSequence</code>)</b>&nbsp;in&nbsp;android.support.design.widget.TextInputLayout
    ++</A></nobr><br>
    ++<!-- Method setPasswordVisibilityToggleDrawable -->
    ++<i>setPasswordVisibilityToggleDrawable</i><br>
    ++&nbsp;&nbsp;<nobr><A HREF="android.support.design.widget.TextInputLayout.html#android.support.design.widget.TextInputLayout.setPasswordVisibilityToggleDrawable_added(android.graphics.drawable.Drawable)" class="hiddenlink" target="rightframe">type&nbsp;<b>
    ++(<code>Drawable</code>)</b>&nbsp;in&nbsp;android.support.design.widget.TextInputLayout
    ++</A></nobr><br>
    ++<!-- Method setPasswordVisibilityToggleDrawable -->
    ++&nbsp;&nbsp;<nobr><A HREF="android.support.design.widget.TextInputLayout.html#android.support.design.widget.TextInputLayout.setPasswordVisibilityToggleDrawable_added(int)" class="hiddenlink" target="rightframe">type&nbsp;<b>
    ++(<code>int</code>)</b>&nbsp;in&nbsp;android.support.design.widget.TextInputLayout
    ++</A></nobr><br>
    ++<!-- Method setPasswordVisibilityToggleEnabled -->
    ++<nobr><A HREF="android.support.design.widget.TextInputLayout.html#android.support.design.widget.TextInputLayout.setPasswordVisibilityToggleEnabled_added(boolean)" class="hiddenlink" target="rightframe"><b>setPasswordVisibilityToggleEnabled</b>
    ++(<code>boolean</code>)</A></nobr><br>
    ++<!-- Method setPasswordVisibilityToggleTintList -->
    ++<nobr><A HREF="android.support.design.widget.TextInputLayout.html#android.support.design.widget.TextInputLayout.setPasswordVisibilityToggleTintList_added(android.content.res.ColorStateList)" class="hiddenlink" target="rightframe"><b>setPasswordVisibilityToggleTintList</b>
    ++(<code>ColorStateList</code>)</A></nobr><br>
    ++<!-- Method setPasswordVisibilityToggleTintMode -->
    ++<nobr><A HREF="android.support.design.widget.TextInputLayout.html#android.support.design.widget.TextInputLayout.setPasswordVisibilityToggleTintMode_added(android.graphics.PorterDuff.Mode)" class="hiddenlink" target="rightframe"><b>setPasswordVisibilityToggleTintMode</b>
    ++(<code>Mode</code>)</A></nobr><br>
    ++<!-- Method setSecondaryToolbarViews -->
    ++<nobr><A HREF="android.support.customtabs.CustomTabsSession.html#android.support.customtabs.CustomTabsSession.setSecondaryToolbarViews_added(android.widget.RemoteViews, int[], android.app.PendingIntent)" class="hiddenlink" target="rightframe"><b>setSecondaryToolbarViews</b>
    ++(<code>RemoteViews, int[], PendingIntent</code>)</A></nobr><br>
    ++<!-- Method setSelectedMediaItemNumberView -->
    ++<nobr><A HREF="android.support.v17.leanback.widget.AbstractMediaItemPresenter.ViewHolder.html#android.support.v17.leanback.widget.AbstractMediaItemPresenter.ViewHolder.setSelectedMediaItemNumberView_added(int)" class="hiddenlink" target="rightframe"><b>setSelectedMediaItemNumberView</b>
    ++(<code>int</code>)</A></nobr><br>
    ++<!-- Class ShareActionProvider -->
    ++<A HREF="pkg_android.support.v7.widget.html#ShareActionProvider" class="hiddenlink" target="rightframe"><b>ShareActionProvider</b></A><br>
    ++<!-- Class ShareActionProvider.OnShareTargetSelectedListener -->
    ++<A HREF="pkg_android.support.v7.widget.html#ShareActionProvider.OnShareTargetSelectedListener" class="hiddenlink" target="rightframe"><b><i>ShareActionProvider.OnShareTargetSelectedListener</i></b></A><br>
    ++<!-- Class SharedElementCallback.OnSharedElementsReadyListener -->
    ++<A HREF="pkg_android.support.v4.app.html#SharedElementCallback.OnSharedElementsReadyListener" class="hiddenlink" target="rightframe"><b><i>SharedElementCallback.OnSharedElementsReadyListener</i></b></A><br>
    ++<!-- Method shouldAlwaysUseBrowserUI -->
    ++<nobr><A HREF="android.support.customtabs.CustomTabsIntent.html#android.support.customtabs.CustomTabsIntent.shouldAlwaysUseBrowserUI_added(android.content.Intent)" class="hiddenlink" target="rightframe"><b>shouldAlwaysUseBrowserUI</b>
    ++(<code>Intent</code>)</A></nobr><br>
    ++<!-- Class SnapHelper -->
    ++<A HREF="pkg_android.support.v7.widget.html#SnapHelper" class="hiddenlink" target="rightframe"><b>SnapHelper</b></A><br>
    ++<!-- Class Space -->
    ++<A HREF="pkg_android.support.v7.widget.html#Space" class="hiddenlink" target="rightframe"><b>Space</b></A><br>
    ++<!-- Field STOP_FOREGROUND_DETACH -->
    ++<nobr><A HREF="android.support.v4.app.ServiceCompat.html#android.support.v4.app.ServiceCompat.STOP_FOREGROUND_DETACH" class="hiddenlink" target="rightframe">STOP_FOREGROUND_DETACH</A>
    ++</nobr><br>
    ++<!-- Field STOP_FOREGROUND_REMOVE -->
    ++<nobr><A HREF="android.support.v4.app.ServiceCompat.html#android.support.v4.app.ServiceCompat.STOP_FOREGROUND_REMOVE" class="hiddenlink" target="rightframe">STOP_FOREGROUND_REMOVE</A>
    ++</nobr><br>
    ++<!-- Method stopForeground -->
    ++<nobr><A HREF="android.support.v4.app.ServiceCompat.html#android.support.v4.app.ServiceCompat.stopForeground_added(android.app.Service, int)" class="hiddenlink" target="rightframe"><b>stopForeground</b>
    ++(<code>Service, int</code>)</A></nobr><br>
    ++<!-- Class SwipeRefreshLayout.OnChildScrollUpCallback -->
    ++<A HREF="pkg_android.support.v4.widget.html#SwipeRefreshLayout.OnChildScrollUpCallback" class="hiddenlink" target="rightframe"><b><i>SwipeRefreshLayout.OnChildScrollUpCallback</i></b></A><br>
    ++<!-- Class SwitchCompat -->
    ++<A HREF="pkg_android.support.v7.widget.html#SwitchCompat" class="hiddenlink" target="rightframe"><b>SwitchCompat</b></A><br>
    ++<!-- Class ThemedSpinnerAdapter -->
    ++<A NAME="T"></A>
    ++<br><font size="+2">T</font>&nbsp;
    ++<a href="#A"><font size="-2">A</font></a> 
    ++<a href="#B"><font size="-2">B</font></a> 
    ++<a href="#C"><font size="-2">C</font></a> 
    ++<a href="#D"><font size="-2">D</font></a> 
    ++<a href="#E"><font size="-2">E</font></a> 
    ++<a href="#F"><font size="-2">F</font></a> 
    ++<a href="#G"><font size="-2">G</font></a> 
    ++<a href="#H"><font size="-2">H</font></a> 
    ++<a href="#I"><font size="-2">I</font></a> 
    ++<a href="#L"><font size="-2">L</font></a> 
    ++<a href="#M"><font size="-2">M</font></a> 
    ++<a href="#N"><font size="-2">N</font></a> 
    ++<a href="#O"><font size="-2">O</font></a> 
    ++<a href="#P"><font size="-2">P</font></a> 
    ++<a href="#R"><font size="-2">R</font></a> 
    ++<a href="#S"><font size="-2">S</font></a> 
    ++<a href="#W"><font size="-2">W</font></a> 
    ++ <a href="#topheader"><font size="-2">TOP</font></a>
    ++<p><div style="line-height:1.5em;color:black">
    ++<A HREF="pkg_android.support.v7.widget.html#ThemedSpinnerAdapter" class="hiddenlink" target="rightframe"><b><i>ThemedSpinnerAdapter</i></b></A><br>
    ++<!-- Class ThemedSpinnerAdapter.Helper -->
    ++<A HREF="pkg_android.support.v7.widget.html#ThemedSpinnerAdapter.Helper" class="hiddenlink" target="rightframe"><b>ThemedSpinnerAdapter.Helper</b></A><br>
    ++<!-- Method toKeyCode -->
    ++<nobr><A HREF="android.support.v4.media.session.PlaybackStateCompat.html#android.support.v4.media.session.PlaybackStateCompat.toKeyCode_added(long)" class="hiddenlink" target="rightframe"><b>toKeyCode</b>
    ++(<code>long</code>)</A></nobr><br>
    ++<!-- Class Toolbar -->
    ++<A HREF="pkg_android.support.v7.widget.html#Toolbar" class="hiddenlink" target="rightframe"><b>Toolbar</b></A><br>
    ++<!-- Class Toolbar.LayoutParams -->
    ++<A HREF="pkg_android.support.v7.widget.html#Toolbar.LayoutParams" class="hiddenlink" target="rightframe"><b>Toolbar.LayoutParams</b></A><br>
    ++<!-- Class Toolbar.OnMenuItemClickListener -->
    ++<A HREF="pkg_android.support.v7.widget.html#Toolbar.OnMenuItemClickListener" class="hiddenlink" target="rightframe"><b><i>Toolbar.OnMenuItemClickListener</i></b></A><br>
    ++<!-- Class Toolbar.SavedState -->
    ++<A HREF="pkg_android.support.v7.widget.html#Toolbar.SavedState" class="hiddenlink" target="rightframe"><b>Toolbar.SavedState</b></A><br>
    ++<!-- Field TYPE_ASSIST_READING_CONTEXT -->
    ++<nobr><A HREF="android.support.v4.view.accessibility.AccessibilityEventCompat.html#android.support.v4.view.accessibility.AccessibilityEventCompat.TYPE_ASSIST_READING_CONTEXT" class="hiddenlink" target="rightframe">TYPE_ASSIST_READING_CONTEXT</A>
    ++</nobr><br>
    ++<!-- Field TYPE_SPLIT_SCREEN_DIVIDER -->
    ++<nobr><A HREF="android.support.v4.view.accessibility.AccessibilityWindowInfoCompat.html#android.support.v4.view.accessibility.AccessibilityWindowInfoCompat.TYPE_SPLIT_SCREEN_DIVIDER" class="hiddenlink" target="rightframe">TYPE_SPLIT_SCREEN_DIVIDER</A>
    ++</nobr><br>
    ++<!-- Field TYPE_VIEW_CONTEXT_CLICKED -->
    ++<nobr><A HREF="android.support.v4.view.accessibility.AccessibilityEventCompat.html#android.support.v4.view.accessibility.AccessibilityEventCompat.TYPE_VIEW_CONTEXT_CLICKED" class="hiddenlink" target="rightframe">TYPE_VIEW_CONTEXT_CLICKED</A>
    ++</nobr><br>
    ++<!-- Field TYPE_WINDOWS_CHANGED -->
    ++<nobr><A HREF="android.support.v4.view.accessibility.AccessibilityEventCompat.html#android.support.v4.view.accessibility.AccessibilityEventCompat.TYPE_WINDOWS_CHANGED" class="hiddenlink" target="rightframe">TYPE_WINDOWS_CHANGED</A>
    ++</nobr><br>
    ++<!-- Constructor WindowInsetsCompat -->
    ++<A NAME="W"></A>
    ++<br><font size="+2">W</font>&nbsp;
    ++<a href="#A"><font size="-2">A</font></a> 
    ++<a href="#B"><font size="-2">B</font></a> 
    ++<a href="#C"><font size="-2">C</font></a> 
    ++<a href="#D"><font size="-2">D</font></a> 
    ++<a href="#E"><font size="-2">E</font></a> 
    ++<a href="#F"><font size="-2">F</font></a> 
    ++<a href="#G"><font size="-2">G</font></a> 
    ++<a href="#H"><font size="-2">H</font></a> 
    ++<a href="#I"><font size="-2">I</font></a> 
    ++<a href="#L"><font size="-2">L</font></a> 
    ++<a href="#M"><font size="-2">M</font></a> 
    ++<a href="#N"><font size="-2">N</font></a> 
    ++<a href="#O"><font size="-2">O</font></a> 
    ++<a href="#P"><font size="-2">P</font></a> 
    ++<a href="#R"><font size="-2">R</font></a> 
    ++<a href="#S"><font size="-2">S</font></a> 
    ++<a href="#T"><font size="-2">T</font></a> 
    ++ <a href="#topheader"><font size="-2">TOP</font></a>
    ++<p><div style="line-height:1.5em;color:black">
    ++<nobr><A HREF="android.support.v4.view.WindowInsetsCompat.html#android.support.v4.view.WindowInsetsCompat.ctor_added(android.support.v4.view.WindowInsetsCompat)" class="hiddenlink" target="rightframe"><b>WindowInsetsCompat</b>
    ++(<code>WindowInsetsCompat</code>)</A></nobr>&nbsp;constructor<br>
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    ++</script>
    ++<script type="text/javascript">
    ++  try {
    ++    var pageTracker = _gat._getTracker("UA-5831155-1");
    ++    pageTracker._setAllowAnchor(true);
    ++    pageTracker._initData();
    ++    pageTracker._trackPageview();
    ++  } catch(e) {}
    ++</script>
    ++</BODY>
    ++</HTML>
    +diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/alldiffs_index_all.html b/docs/html/sdk/support_api_diff/24.2.0/changes/alldiffs_index_all.html
    +new file mode 100644
    +index 0000000..fb553f8
    +--- /dev/null
    ++++ b/docs/html/sdk/support_api_diff/24.2.0/changes/alldiffs_index_all.html
    +@@ -0,0 +1,1327 @@
    ++<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
    ++<HTML style="overflow:auto;">
    ++<HEAD>
    ++<meta name="generator" content="JDiff v1.1.0">
    ++<!-- Generated by the JDiff Javadoc doclet -->
    ++<!-- (http://www.jdiff.org) -->
    ++<meta name="description" content="JDiff is a Javadoc doclet which generates an HTML report of all the packages, classes, constructors, methods, and fields which have been removed, added or changed in any way, including their documentation, when two APIs are compared.">
    ++<meta name="keywords" content="diff, jdiff, javadiff, java diff, java difference, API difference, difference between two APIs, API diff, Javadoc, doclet">
    ++<TITLE>
    ++All Differences Index
    ++</TITLE>
    ++<link href="../../../../assets/android-developer-docs.css" rel="stylesheet" type="text/css" />
    ++<link href="../stylesheet-jdiff.css" rel="stylesheet" type="text/css" />
    ++<noscript>
    ++<style type="text/css">
    ++body{overflow:auto;}
    ++#body-content{position:relative; top:0;}
    ++#doc-content{overflow:visible;border-left:3px solid #666;}
    ++#side-nav{padding:0;}
    ++#side-nav .toggle-list ul {display:block;}
    ++#resize-packages-nav{border-bottom:3px solid #666;}
    ++</style>
    ++</noscript>
    ++<style type="text/css">
    ++</style>
    ++</HEAD>
    ++<BODY class="gc-documentation" style="padding:12px;">
    ++<a NAME="topheader"></a>
    ++<table summary="Index for All Differences" width="100%" class="jdiffIndex" border="0" cellspacing="0" cellpadding="0" style="padding-bottom:0;margin-bottom:0;">
    ++  <tr>
    ++  <th class="indexHeader">
    ++    Filter the Index:
    ++  </th>
    ++  </tr>
    ++  <tr>
    ++  <td class="indexText" style="line-height:1.3em;padding-left:2em;">
    ++<b>All Differences</b>
    ++  <br>
    ++<A HREF="alldiffs_index_removals.html" xclass="hiddenlink">Removals</A>
    ++  <br>
    ++<A HREF="alldiffs_index_additions.html"xclass="hiddenlink">Additions</A>
    ++  <br>
    ++<A HREF="alldiffs_index_changes.html"xclass="hiddenlink">Changes</A>
    ++  </td>
    ++  </tr>
    ++</table>
    ++<div id="indexTableCaption" style="background-color:#eee;padding:0 4px 0 4px;font-size:11px;margin-bottom:1em;">
    ++Listed as: <span style="color:#069"><strong>Added</strong></span>,  <span style="color:#069"><strike>Removed</strike></span>,  <span style="color:#069">Changed</span></font>
    ++</div>
    ++<!-- Class AbstractMediaItemPresenter -->
    ++<A NAME="A"></A>
    ++<br><font size="+2">A</font>&nbsp;
    ++<a href="#B"><font size="-2">B</font></a> 
    ++<a href="#C"><font size="-2">C</font></a> 
    ++<a href="#D"><font size="-2">D</font></a> 
    ++<a href="#E"><font size="-2">E</font></a> 
    ++<a href="#F"><font size="-2">F</font></a> 
    ++<a href="#G"><font size="-2">G</font></a> 
    ++<a href="#H"><font size="-2">H</font></a> 
    ++<a href="#I"><font size="-2">I</font></a> 
    ++<a href="#K"><font size="-2">K</font></a> 
    ++<a href="#L"><font size="-2">L</font></a> 
    ++<a href="#M"><font size="-2">M</font></a> 
    ++<a href="#N"><font size="-2">N</font></a> 
    ++<a href="#O"><font size="-2">O</font></a> 
    ++<a href="#P"><font size="-2">P</font></a> 
    ++<a href="#R"><font size="-2">R</font></a> 
    ++<a href="#S"><font size="-2">S</font></a> 
    ++<a href="#T"><font size="-2">T</font></a> 
    ++<a href="#V"><font size="-2">V</font></a> 
    ++<a href="#W"><font size="-2">W</font></a> 
    ++ <a href="#topheader"><font size="-2">TOP</font></a>
    ++<p><div style="line-height:1.5em;color:black">
    ++<A HREF="android.support.v17.leanback.widget.AbstractMediaItemPresenter.html" class="hiddenlink" target="rightframe">AbstractMediaItemPresenter</A><br>
    ++<!-- Class AbstractMediaItemPresenter.ViewHolder -->
    ++<A HREF="android.support.v17.leanback.widget.AbstractMediaItemPresenter.ViewHolder.html" class="hiddenlink" target="rightframe">AbstractMediaItemPresenter.ViewHolder</A><br>
    ++<!-- Class AccessibilityEventCompat -->
    ++<A HREF="android.support.v4.view.accessibility.AccessibilityEventCompat.html" class="hiddenlink" target="rightframe">AccessibilityEventCompat</A><br>
    ++<!-- Class AccessibilityManagerCompat -->
    ++<A HREF="android.support.v4.view.accessibility.AccessibilityManagerCompat.html" class="hiddenlink" target="rightframe">AccessibilityManagerCompat</A><br>
    ++<!-- Class AccessibilityManagerCompat.AccessibilityStateChangeListener -->
    ++<A HREF="pkg_android.support.v4.view.accessibility.html#AccessibilityManagerCompat.AccessibilityStateChangeListener" class="hiddenlink" target="rightframe"><b><i>AccessibilityManagerCompat.AccessibilityStateChangeListener</i></b></A><br>
    ++<!-- Class AccessibilityManagerCompat.AccessibilityStateChangeListenerCompat -->
    ++<A HREF="android.support.v4.view.accessibility.AccessibilityManagerCompat.AccessibilityStateChangeListenerCompat.html" class="hiddenlink" target="rightframe">AccessibilityManagerCompat.AccessibilityStateChangeListenerCompat</A><br>
    ++<!-- Class AccessibilityManagerCompat.TouchExplorationStateChangeListener -->
    ++<A HREF="pkg_android.support.v4.view.accessibility.html#AccessibilityManagerCompat.TouchExplorationStateChangeListener" class="hiddenlink" target="rightframe"><b><i>AccessibilityManagerCompat.TouchExplorationStateChangeListener</i></b></A><br>
    ++<!-- Class AccessibilityNodeInfoCompat -->
    ++<A HREF="android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.html" class="hiddenlink" target="rightframe">AccessibilityNodeInfoCompat</A><br>
    ++<!-- Class AccessibilityNodeInfoCompat.AccessibilityActionCompat -->
    ++<A HREF="android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat.html" class="hiddenlink" target="rightframe">AccessibilityNodeInfoCompat.AccessibilityActionCompat</A><br>
    ++<!-- Class AccessibilityNodeInfoCompat.CollectionInfoCompat -->
    ++<A HREF="android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.CollectionInfoCompat.html" class="hiddenlink" target="rightframe">AccessibilityNodeInfoCompat.CollectionInfoCompat</A><br>
    ++<!-- Class AccessibilityNodeInfoCompat.CollectionItemInfoCompat -->
    ++<A HREF="android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.CollectionItemInfoCompat.html" class="hiddenlink" target="rightframe">AccessibilityNodeInfoCompat.CollectionItemInfoCompat</A><br>
    ++<!-- Class AccessibilityNodeInfoCompat.RangeInfoCompat -->
    ++<A HREF="android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.RangeInfoCompat.html" class="hiddenlink" target="rightframe">AccessibilityNodeInfoCompat.RangeInfoCompat</A><br>
    ++<!-- Class AccessibilityNodeProviderCompat -->
    ++<A HREF="android.support.v4.view.accessibility.AccessibilityNodeProviderCompat.html" class="hiddenlink" target="rightframe">AccessibilityNodeProviderCompat</A><br>
    ++<!-- Class AccessibilityServiceInfoCompat -->
    ++<A HREF="android.support.v4.accessibilityservice.AccessibilityServiceInfoCompat.html" class="hiddenlink" target="rightframe">AccessibilityServiceInfoCompat</A><br>
    ++<!-- Class AccessibilityWindowInfoCompat -->
    ++<A HREF="android.support.v4.view.accessibility.AccessibilityWindowInfoCompat.html" class="hiddenlink" target="rightframe">AccessibilityWindowInfoCompat</A><br>
    ++<!-- Field ACTION_ARGUMENT_COLUMN_INT -->
    ++<nobr><A HREF="android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.html#android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.ACTION_ARGUMENT_COLUMN_INT" class="hiddenlink" target="rightframe">ACTION_ARGUMENT_COLUMN_INT</A>
    ++</nobr><br>
    ++<!-- Field ACTION_ARGUMENT_PROGRESS_VALUE -->
    ++<nobr><A HREF="android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.html#android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.ACTION_ARGUMENT_PROGRESS_VALUE" class="hiddenlink" target="rightframe">ACTION_ARGUMENT_PROGRESS_VALUE</A>
    ++</nobr><br>
    ++<!-- Field ACTION_ARGUMENT_ROW_INT -->
    ++<nobr><A HREF="android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.html#android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.ACTION_ARGUMENT_ROW_INT" class="hiddenlink" target="rightframe">ACTION_ARGUMENT_ROW_INT</A>
    ++</nobr><br>
    ++<!-- Field ACTION_CONTEXT_CLICK -->
    ++<nobr><A HREF="android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat.html#android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat.ACTION_CONTEXT_CLICK" class="hiddenlink" target="rightframe">ACTION_CONTEXT_CLICK</A>
    ++</nobr><br>
    ++<!-- Field ACTION_SCROLL_DOWN -->
    ++<nobr><A HREF="android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat.html#android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat.ACTION_SCROLL_DOWN" class="hiddenlink" target="rightframe">ACTION_SCROLL_DOWN</A>
    ++</nobr><br>
    ++<!-- Field ACTION_SCROLL_LEFT -->
    ++<nobr><A HREF="android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat.html#android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat.ACTION_SCROLL_LEFT" class="hiddenlink" target="rightframe">ACTION_SCROLL_LEFT</A>
    ++</nobr><br>
    ++<!-- Field ACTION_SCROLL_RIGHT -->
    ++<nobr><A HREF="android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat.html#android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat.ACTION_SCROLL_RIGHT" class="hiddenlink" target="rightframe">ACTION_SCROLL_RIGHT</A>
    ++</nobr><br>
    ++<!-- Field ACTION_SCROLL_TO_POSITION -->
    ++<nobr><A HREF="android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat.html#android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat.ACTION_SCROLL_TO_POSITION" class="hiddenlink" target="rightframe">ACTION_SCROLL_TO_POSITION</A>
    ++</nobr><br>
    ++<!-- Field ACTION_SCROLL_UP -->
    ++<nobr><A HREF="android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat.html#android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat.ACTION_SCROLL_UP" class="hiddenlink" target="rightframe">ACTION_SCROLL_UP</A>
    ++</nobr><br>
    ++<!-- Field ACTION_SET_PROGRESS -->
    ++<nobr><A HREF="android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat.html#android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat.ACTION_SET_PROGRESS" class="hiddenlink" target="rightframe">ACTION_SET_PROGRESS</A>
    ++</nobr><br>
    ++<!-- Field ACTION_SHOW_ON_SCREEN -->
    ++<nobr><A HREF="android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat.html#android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat.ACTION_SHOW_ON_SCREEN" class="hiddenlink" target="rightframe">ACTION_SHOW_ON_SCREEN</A>
    ++</nobr><br>
    ++<!-- Class ActionBarActivity -->
    ++<A HREF="pkg_android.support.v7.app.html#ActionBarActivity" class="hiddenlink" target="rightframe"><b>ActionBarActivity</b></A><br>
    ++<!-- Class ActionBarDrawerToggle -->
    ++<A HREF="android.support.v7.app.ActionBarDrawerToggle.html" class="hiddenlink" target="rightframe">ActionBarDrawerToggle</A><br>
    ++<!-- Class ActionMenuView -->
    ++<A HREF="pkg_android.support.v7.widget.html#ActionMenuView" class="hiddenlink" target="rightframe"><b>ActionMenuView</b></A><br>
    ++<!-- Class ActionMenuView.LayoutParams -->
    ++<A HREF="pkg_android.support.v7.widget.html#ActionMenuView.LayoutParams" class="hiddenlink" target="rightframe"><b>ActionMenuView.LayoutParams</b></A><br>
    ++<!-- Class ActionMenuView.OnMenuItemClickListener -->
    ++<A HREF="pkg_android.support.v7.widget.html#ActionMenuView.OnMenuItemClickListener" class="hiddenlink" target="rightframe"><b><i>ActionMenuView.OnMenuItemClickListener</i></b></A><br>
    ++<!-- Class ActivityCompat -->
    ++<i>ActivityCompat</i><br>
    ++&nbsp;&nbsp;<A HREF="android.support.v4.app.ActivityCompat.html" class="hiddenlink" target="rightframe">android.support.v4.app</A><br>
    ++<!-- Constructor ActivityCompat -->
    ++&nbsp;&nbsp;<nobr><A HREF="android.support.v4.app.ActivityCompat.html#android.support.v4.app.ActivityCompat.ctor_changed()" class="hiddenlink" target="rightframe">ActivityCompat
    ++()</A></nobr>&nbsp;constructor<br>
    ++<!-- Class ActivityOptionsCompat -->
    ++<A HREF="android.support.v4.app.ActivityOptionsCompat.html" class="hiddenlink" target="rightframe">ActivityOptionsCompat</A><br>
    ++<!-- Method addAccessibilityStateChangeListener -->
    ++<nobr><A HREF="android.support.v4.view.accessibility.AccessibilityManagerCompat.html#android.support.v4.view.accessibility.AccessibilityManagerCompat.addAccessibilityStateChangeListener_changed(android.view.accessibility.AccessibilityManager, android.support.v4.view.accessibility.AccessibilityManagerCompat.AccessibilityStateChangeListener)" class="hiddenlink" target="rightframe">addAccessibilityStateChangeListener
    ++(<code>AccessibilityManager, AccessibilityStateChangeListener</code>)</A></nobr><br>
    ++<!-- Method addTouchExplorationStateChangeListener -->
    ++<nobr><A HREF="android.support.v4.view.accessibility.AccessibilityManagerCompat.html#android.support.v4.view.accessibility.AccessibilityManagerCompat.addTouchExplorationStateChangeListener_added(android.view.accessibility.AccessibilityManager, android.support.v4.view.accessibility.AccessibilityManagerCompat.TouchExplorationStateChangeListener)" class="hiddenlink" target="rightframe"><b>addTouchExplorationStateChangeListener</b>
    ++(<code>AccessibilityManager, TouchExplorationStateChangeListener</code>)</A></nobr><br>
    ++<!-- Package android.support.customtabs -->
    ++<A HREF="pkg_android.support.customtabs.html" class="hiddenlink" target="rightframe">android.support.customtabs</A><br>
    ++<!-- Package android.support.design.widget -->
    ++<A HREF="pkg_android.support.design.widget.html" class="hiddenlink" target="rightframe">android.support.design.widget</A><br>
    ++<!-- Package android.support.transition -->
    ++<A HREF="changes-summary.html#android.support.transition" class="hiddenlink" target="rightframe"><b>android.support.transition</b></A><br>
    ++<!-- Package android.support.v14.preference -->
    ++<A HREF="pkg_android.support.v14.preference.html" class="hiddenlink" target="rightframe">android.support.v14.preference</A><br>
    ++<!-- Package android.support.v17.leanback.widget -->
    ++<A HREF="pkg_android.support.v17.leanback.widget.html" class="hiddenlink" target="rightframe">android.support.v17.leanback.widget</A><br>
    ++<!-- Package android.support.v17.preference -->
    ++<A HREF="pkg_android.support.v17.preference.html" class="hiddenlink" target="rightframe">android.support.v17.preference</A><br>
    ++<!-- Package android.support.v4.accessibilityservice -->
    ++<A HREF="pkg_android.support.v4.accessibilityservice.html" class="hiddenlink" target="rightframe">android.support.v4.accessibilityservice</A><br>
    ++<!-- Package android.support.v4.app -->
    ++<A HREF="pkg_android.support.v4.app.html" class="hiddenlink" target="rightframe">android.support.v4.app</A><br>
    ++<!-- Package android.support.v4.content -->
    ++<A HREF="pkg_android.support.v4.content.html" class="hiddenlink" target="rightframe">android.support.v4.content</A><br>
    ++<!-- Package android.support.v4.graphics.drawable -->
    ++<A HREF="pkg_android.support.v4.graphics.drawable.html" class="hiddenlink" target="rightframe">android.support.v4.graphics.drawable</A><br>
    ++<!-- Package android.support.v4.media -->
    ++<A HREF="pkg_android.support.v4.media.html" class="hiddenlink" target="rightframe">android.support.v4.media</A><br>
    ++<!-- Package android.support.v4.media.session -->
    ++<A HREF="pkg_android.support.v4.media.session.html" class="hiddenlink" target="rightframe">android.support.v4.media.session</A><br>
    ++<!-- Package android.support.v4.os -->
    ++<A HREF="pkg_android.support.v4.os.html" class="hiddenlink" target="rightframe">android.support.v4.os</A><br>
    ++<!-- Package android.support.v4.text.util -->
    ++<A HREF="changes-summary.html#android.support.v4.text.util" class="hiddenlink" target="rightframe"><b>android.support.v4.text.util</b></A><br>
    ++<!-- Package android.support.v4.util -->
    ++<A HREF="pkg_android.support.v4.util.html" class="hiddenlink" target="rightframe">android.support.v4.util</A><br>
    ++<!-- Package android.support.v4.view -->
    ++<A HREF="pkg_android.support.v4.view.html" class="hiddenlink" target="rightframe">android.support.v4.view</A><br>
    ++<!-- Package android.support.v4.view.accessibility -->
    ++<A HREF="pkg_android.support.v4.view.accessibility.html" class="hiddenlink" target="rightframe">android.support.v4.view.accessibility</A><br>
    ++<!-- Package android.support.v4.widget -->
    ++<A HREF="pkg_android.support.v4.widget.html" class="hiddenlink" target="rightframe">android.support.v4.widget</A><br>
    ++<!-- Package android.support.v7.app -->
    ++<A HREF="pkg_android.support.v7.app.html" class="hiddenlink" target="rightframe">android.support.v7.app</A><br>
    ++<!-- Package android.support.v7.appcompat -->
    ++<A HREF="changes-summary.html#android.support.v7.appcompat" class="hiddenlink" target="rightframe"><strike>android.support.v7.appcompat</strike></A><br>
    ++<!-- Package android.support.v7.content.res -->
    ++<A HREF="pkg_android.support.v7.content.res.html" class="hiddenlink" target="rightframe">android.support.v7.content.res</A><br>
    ++<!-- Package android.support.v7.graphics -->
    ++<A HREF="pkg_android.support.v7.graphics.html" class="hiddenlink" target="rightframe">android.support.v7.graphics</A><br>
    ++<!-- Package android.support.v7.preference -->
    ++<A HREF="pkg_android.support.v7.preference.html" class="hiddenlink" target="rightframe">android.support.v7.preference</A><br>
    ++<!-- Package android.support.v7.recyclerview -->
    ++<A HREF="changes-summary.html#android.support.v7.recyclerview" class="hiddenlink" target="rightframe"><strike>android.support.v7.recyclerview</strike></A><br>
    ++<!-- Package android.support.v7.util -->
    ++<A HREF="pkg_android.support.v7.util.html" class="hiddenlink" target="rightframe">android.support.v7.util</A><br>
    ++<!-- Package android.support.v7.widget -->
    ++<A HREF="pkg_android.support.v7.widget.html" class="hiddenlink" target="rightframe">android.support.v7.widget</A><br>
    ++<!-- Package android.support.v8.renderscript -->
    ++<A HREF="changes-summary.html#android.support.v8.renderscript" class="hiddenlink" target="rightframe"><strike>android.support.v8.renderscript</strike></A><br>
    ++<!-- Class AppBarLayout.ScrollingViewBehavior -->
    ++<A HREF="android.support.design.widget.AppBarLayout.ScrollingViewBehavior.html" class="hiddenlink" target="rightframe">AppBarLayout.ScrollingViewBehavior</A><br>
    ++<!-- Class AppCompatActivity -->
    ++<A HREF="pkg_android.support.v7.app.html#AppCompatActivity" class="hiddenlink" target="rightframe"><b>AppCompatActivity</b></A><br>
    ++<!-- Class AppCompatAutoCompleteTextView -->
    ++<A HREF="pkg_android.support.v7.widget.html#AppCompatAutoCompleteTextView" class="hiddenlink" target="rightframe"><b>AppCompatAutoCompleteTextView</b></A><br>
    ++<!-- Class AppCompatButton -->
    ++<A HREF="pkg_android.support.v7.widget.html#AppCompatButton" class="hiddenlink" target="rightframe"><b>AppCompatButton</b></A><br>
    ++<!-- Class AppCompatCheckBox -->
    ++<A HREF="pkg_android.support.v7.widget.html#AppCompatCheckBox" class="hiddenlink" target="rightframe"><b>AppCompatCheckBox</b></A><br>
    ++<!-- Class AppCompatCheckedTextView -->
    ++<A HREF="pkg_android.support.v7.widget.html#AppCompatCheckedTextView" class="hiddenlink" target="rightframe"><b>AppCompatCheckedTextView</b></A><br>
    ++<!-- Class AppCompatDelegate -->
    ++<A HREF="android.support.v7.app.AppCompatDelegate.html" class="hiddenlink" target="rightframe">AppCompatDelegate</A><br>
    ++<!-- Class AppCompatDialogFragment -->
    ++<A HREF="pkg_android.support.v7.app.html#AppCompatDialogFragment" class="hiddenlink" target="rightframe"><b>AppCompatDialogFragment</b></A><br>
    ++<!-- Class AppCompatEditText -->
    ++<A HREF="pkg_android.support.v7.widget.html#AppCompatEditText" class="hiddenlink" target="rightframe"><b>AppCompatEditText</b></A><br>
    ++<!-- Class AppCompatImageButton -->
    ++<A HREF="pkg_android.support.v7.widget.html#AppCompatImageButton" class="hiddenlink" target="rightframe"><b>AppCompatImageButton</b></A><br>
    ++<!-- Class AppCompatImageView -->
    ++<A HREF="pkg_android.support.v7.widget.html#AppCompatImageView" class="hiddenlink" target="rightframe"><b>AppCompatImageView</b></A><br>
    ++<!-- Class AppCompatMultiAutoCompleteTextView -->
    ++<A HREF="pkg_android.support.v7.widget.html#AppCompatMultiAutoCompleteTextView" class="hiddenlink" target="rightframe"><b>AppCompatMultiAutoCompleteTextView</b></A><br>
    ++<!-- Class AppCompatRadioButton -->
    ++<A HREF="pkg_android.support.v7.widget.html#AppCompatRadioButton" class="hiddenlink" target="rightframe"><b>AppCompatRadioButton</b></A><br>
    ++<!-- Class AppCompatRatingBar -->
    ++<A HREF="pkg_android.support.v7.widget.html#AppCompatRatingBar" class="hiddenlink" target="rightframe"><b>AppCompatRatingBar</b></A><br>
    ++<!-- Class AppCompatResources -->
    ++<A HREF="android.support.v7.content.res.AppCompatResources.html" class="hiddenlink" target="rightframe">AppCompatResources</A><br>
    ++<!-- Class AppCompatSeekBar -->
    ++<A HREF="pkg_android.support.v7.widget.html#AppCompatSeekBar" class="hiddenlink" target="rightframe"><b>AppCompatSeekBar</b></A><br>
    ++<!-- Class AppCompatSpinner -->
    ++<A HREF="pkg_android.support.v7.widget.html#AppCompatSpinner" class="hiddenlink" target="rightframe"><b>AppCompatSpinner</b></A><br>
    ++<!-- Class AppCompatTextView -->
    ++<A HREF="pkg_android.support.v7.widget.html#AppCompatTextView" class="hiddenlink" target="rightframe"><b>AppCompatTextView</b></A><br>
    ++<!-- Class BatchingListUpdateCallback -->
    ++<A NAME="B"></A>
    ++<br><font size="+2">B</font>&nbsp;
    ++<a href="#A"><font size="-2">A</font></a> 
    ++<a href="#C"><font size="-2">C</font></a> 
    ++<a href="#D"><font size="-2">D</font></a> 
    ++<a href="#E"><font size="-2">E</font></a> 
    ++<a href="#F"><font size="-2">F</font></a> 
    ++<a href="#G"><font size="-2">G</font></a> 
    ++<a href="#H"><font size="-2">H</font></a> 
    ++<a href="#I"><font size="-2">I</font></a> 
    ++<a href="#K"><font size="-2">K</font></a> 
    ++<a href="#L"><font size="-2">L</font></a> 
    ++<a href="#M"><font size="-2">M</font></a> 
    ++<a href="#N"><font size="-2">N</font></a> 
    ++<a href="#O"><font size="-2">O</font></a> 
    ++<a href="#P"><font size="-2">P</font></a> 
    ++<a href="#R"><font size="-2">R</font></a> 
    ++<a href="#S"><font size="-2">S</font></a> 
    ++<a href="#T"><font size="-2">T</font></a> 
    ++<a href="#V"><font size="-2">V</font></a> 
    ++<a href="#W"><font size="-2">W</font></a> 
    ++ <a href="#topheader"><font size="-2">TOP</font></a>
    ++<p><div style="line-height:1.5em;color:black">
    ++<A HREF="pkg_android.support.v7.util.html#BatchingListUpdateCallback" class="hiddenlink" target="rightframe"><b>BatchingListUpdateCallback</b></A><br>
    ++<!-- Class BottomSheetBehavior -->
    ++<A HREF="android.support.design.widget.BottomSheetBehavior.html" class="hiddenlink" target="rightframe">BottomSheetBehavior</A><br>
    ++<!-- Field BT_FOLDER_TYPE_ALBUMS -->
    ++<nobr><A HREF="android.support.v4.media.MediaDescriptionCompat.html#android.support.v4.media.MediaDescriptionCompat.BT_FOLDER_TYPE_ALBUMS" class="hiddenlink" target="rightframe">BT_FOLDER_TYPE_ALBUMS</A>
    ++</nobr><br>
    ++<!-- Field BT_FOLDER_TYPE_ARTISTS -->
    ++<nobr><A HREF="android.support.v4.media.MediaDescriptionCompat.html#android.support.v4.media.MediaDescriptionCompat.BT_FOLDER_TYPE_ARTISTS" class="hiddenlink" target="rightframe">BT_FOLDER_TYPE_ARTISTS</A>
    ++</nobr><br>
    ++<!-- Field BT_FOLDER_TYPE_GENRES -->
    ++<nobr><A HREF="android.support.v4.media.MediaDescriptionCompat.html#android.support.v4.media.MediaDescriptionCompat.BT_FOLDER_TYPE_GENRES" class="hiddenlink" target="rightframe">BT_FOLDER_TYPE_GENRES</A>
    ++</nobr><br>
    ++<!-- Field BT_FOLDER_TYPE_MIXED -->
    ++<nobr><A HREF="android.support.v4.media.MediaDescriptionCompat.html#android.support.v4.media.MediaDescriptionCompat.BT_FOLDER_TYPE_MIXED" class="hiddenlink" target="rightframe">BT_FOLDER_TYPE_MIXED</A>
    ++</nobr><br>
    ++<!-- Field BT_FOLDER_TYPE_PLAYLISTS -->
    ++<nobr><A HREF="android.support.v4.media.MediaDescriptionCompat.html#android.support.v4.media.MediaDescriptionCompat.BT_FOLDER_TYPE_PLAYLISTS" class="hiddenlink" target="rightframe">BT_FOLDER_TYPE_PLAYLISTS</A>
    ++</nobr><br>
    ++<!-- Field BT_FOLDER_TYPE_TITLES -->
    ++<nobr><A HREF="android.support.v4.media.MediaDescriptionCompat.html#android.support.v4.media.MediaDescriptionCompat.BT_FOLDER_TYPE_TITLES" class="hiddenlink" target="rightframe">BT_FOLDER_TYPE_TITLES</A>
    ++</nobr><br>
    ++<!-- Field BT_FOLDER_TYPE_YEARS -->
    ++<nobr><A HREF="android.support.v4.media.MediaDescriptionCompat.html#android.support.v4.media.MediaDescriptionCompat.BT_FOLDER_TYPE_YEARS" class="hiddenlink" target="rightframe">BT_FOLDER_TYPE_YEARS</A>
    ++</nobr><br>
    ++<!-- Class BuildCompat -->
    ++<A HREF="android.support.v4.os.BuildCompat.html" class="hiddenlink" target="rightframe">BuildCompat</A><br>
    ++<!-- Method buildMediaButtonPendingIntent -->
    ++<i>buildMediaButtonPendingIntent</i><br>
    ++&nbsp;&nbsp;<nobr><A HREF="android.support.v4.media.session.MediaButtonReceiver.html#android.support.v4.media.session.MediaButtonReceiver.buildMediaButtonPendingIntent_added(android.content.Context, android.content.ComponentName, long)" class="hiddenlink" target="rightframe">type&nbsp;<b>
    ++(<code>Context, ComponentName, long</code>)</b>&nbsp;in&nbsp;android.support.v4.media.session.MediaButtonReceiver
    ++</A></nobr><br>
    ++<!-- Method buildMediaButtonPendingIntent -->
    ++&nbsp;&nbsp;<nobr><A HREF="android.support.v4.media.session.MediaButtonReceiver.html#android.support.v4.media.session.MediaButtonReceiver.buildMediaButtonPendingIntent_added(android.content.Context, long)" class="hiddenlink" target="rightframe">type&nbsp;<b>
    ++(<code>Context, long</code>)</b>&nbsp;in&nbsp;android.support.v4.media.session.MediaButtonReceiver
    ++</A></nobr><br>
    ++<!-- Class CardView -->
    ++<A NAME="C"></A>
    ++<br><font size="+2">C</font>&nbsp;
    ++<a href="#A"><font size="-2">A</font></a> 
    ++<a href="#B"><font size="-2">B</font></a> 
    ++<a href="#D"><font size="-2">D</font></a> 
    ++<a href="#E"><font size="-2">E</font></a> 
    ++<a href="#F"><font size="-2">F</font></a> 
    ++<a href="#G"><font size="-2">G</font></a> 
    ++<a href="#H"><font size="-2">H</font></a> 
    ++<a href="#I"><font size="-2">I</font></a> 
    ++<a href="#K"><font size="-2">K</font></a> 
    ++<a href="#L"><font size="-2">L</font></a> 
    ++<a href="#M"><font size="-2">M</font></a> 
    ++<a href="#N"><font size="-2">N</font></a> 
    ++<a href="#O"><font size="-2">O</font></a> 
    ++<a href="#P"><font size="-2">P</font></a> 
    ++<a href="#R"><font size="-2">R</font></a> 
    ++<a href="#S"><font size="-2">S</font></a> 
    ++<a href="#T"><font size="-2">T</font></a> 
    ++<a href="#V"><font size="-2">V</font></a> 
    ++<a href="#W"><font size="-2">W</font></a> 
    ++ <a href="#topheader"><font size="-2">TOP</font></a>
    ++<p><div style="line-height:1.5em;color:black">
    ++<A HREF="pkg_android.support.v7.widget.html#CardView" class="hiddenlink" target="rightframe"><b>CardView</b></A><br>
    ++<!-- Method clearColorFilter -->
    ++<nobr><A HREF="android.support.v4.graphics.drawable.DrawableCompat.html#android.support.v4.graphics.drawable.DrawableCompat.clearColorFilter_added(android.graphics.drawable.Drawable)" class="hiddenlink" target="rightframe"><b>clearColorFilter</b>
    ++(<code>Drawable</code>)</A></nobr><br>
    ++<!-- Method clearOnTabSelectedListeners -->
    ++<nobr><A HREF="android.support.design.widget.TabLayout.html#android.support.design.widget.TabLayout.clearOnTabSelectedListeners_added()" class="hiddenlink" target="rightframe"><b>clearOnTabSelectedListeners</b>
    ++()</A></nobr><br>
    ++<!-- Class CollapsingToolbarLayout -->
    ++<A HREF="android.support.design.widget.CollapsingToolbarLayout.html" class="hiddenlink" target="rightframe">CollapsingToolbarLayout</A><br>
    ++<!-- Method computeScrollVectorForPosition -->
    ++<i>computeScrollVectorForPosition</i><br>
    ++&nbsp;&nbsp;<nobr><A HREF="android.support.v7.widget.LinearSmoothScroller.html#android.support.v7.widget.LinearSmoothScroller.computeScrollVectorForPosition_changed(int)" class="hiddenlink" target="rightframe">type&nbsp;
    ++(<code>int</code>)&nbsp;in&nbsp;android.support.v7.widget.LinearSmoothScroller
    ++</A></nobr><br>
    ++<!-- Method computeScrollVectorForPosition -->
    ++&nbsp;&nbsp;<nobr><A HREF="android.support.v7.widget.StaggeredGridLayoutManager.html#android.support.v7.widget.StaggeredGridLayoutManager.computeScrollVectorForPosition_added(int)" class="hiddenlink" target="rightframe">type&nbsp;<b>
    ++(<code>int</code>)</b>&nbsp;in&nbsp;android.support.v7.widget.StaggeredGridLayoutManager
    ++</A></nobr><br>
    ++<!-- Class ContextCompat -->
    ++<i>ContextCompat</i><br>
    ++&nbsp;&nbsp;<A HREF="android.support.v4.content.ContextCompat.html" class="hiddenlink" target="rightframe">android.support.v4.content</A><br>
    ++<!-- Constructor ContextCompat -->
    ++&nbsp;&nbsp;<nobr><A HREF="android.support.v4.content.ContextCompat.html#android.support.v4.content.ContextCompat.ctor_changed()" class="hiddenlink" target="rightframe">ContextCompat
    ++()</A></nobr>&nbsp;constructor<br>
    ++<!-- Class CoordinatorLayout -->
    ++<A HREF="android.support.design.widget.CoordinatorLayout.html" class="hiddenlink" target="rightframe">CoordinatorLayout</A><br>
    ++<!-- Class CoordinatorLayout.Behavior -->
    ++<A HREF="android.support.design.widget.CoordinatorLayout.Behavior.html" class="hiddenlink" target="rightframe">CoordinatorLayout.Behavior</A><br>
    ++<!-- Class CoordinatorLayout.LayoutParams -->
    ++<A HREF="android.support.design.widget.CoordinatorLayout.LayoutParams.html" class="hiddenlink" target="rightframe">CoordinatorLayout.LayoutParams</A><br>
    ++<!-- Class CustomTabsIntent -->
    ++<A HREF="android.support.customtabs.CustomTabsIntent.html" class="hiddenlink" target="rightframe">CustomTabsIntent</A><br>
    ++<!-- Class CustomTabsIntent.Builder -->
    ++<A HREF="android.support.customtabs.CustomTabsIntent.Builder.html" class="hiddenlink" target="rightframe">CustomTabsIntent.Builder</A><br>
    ++<!-- Class CustomTabsSession -->
    ++<A HREF="android.support.customtabs.CustomTabsSession.html" class="hiddenlink" target="rightframe">CustomTabsSession</A><br>
    ++<!-- Class DiffUtil -->
    ++<A NAME="D"></A>
    ++<br><font size="+2">D</font>&nbsp;
    ++<a href="#A"><font size="-2">A</font></a> 
    ++<a href="#B"><font size="-2">B</font></a> 
    ++<a href="#C"><font size="-2">C</font></a> 
    ++<a href="#E"><font size="-2">E</font></a> 
    ++<a href="#F"><font size="-2">F</font></a> 
    ++<a href="#G"><font size="-2">G</font></a> 
    ++<a href="#H"><font size="-2">H</font></a> 
    ++<a href="#I"><font size="-2">I</font></a> 
    ++<a href="#K"><font size="-2">K</font></a> 
    ++<a href="#L"><font size="-2">L</font></a> 
    ++<a href="#M"><font size="-2">M</font></a> 
    ++<a href="#N"><font size="-2">N</font></a> 
    ++<a href="#O"><font size="-2">O</font></a> 
    ++<a href="#P"><font size="-2">P</font></a> 
    ++<a href="#R"><font size="-2">R</font></a> 
    ++<a href="#S"><font size="-2">S</font></a> 
    ++<a href="#T"><font size="-2">T</font></a> 
    ++<a href="#V"><font size="-2">V</font></a> 
    ++<a href="#W"><font size="-2">W</font></a> 
    ++ <a href="#topheader"><font size="-2">TOP</font></a>
    ++<p><div style="line-height:1.5em;color:black">
    ++<A HREF="pkg_android.support.v7.util.html#DiffUtil" class="hiddenlink" target="rightframe"><b>DiffUtil</b></A><br>
    ++<!-- Class DiffUtil.Callback -->
    ++<A HREF="pkg_android.support.v7.util.html#DiffUtil.Callback" class="hiddenlink" target="rightframe"><b>DiffUtil.Callback</b></A><br>
    ++<!-- Class DiffUtil.DiffResult -->
    ++<A HREF="pkg_android.support.v7.util.html#DiffUtil.DiffResult" class="hiddenlink" target="rightframe"><b>DiffUtil.DiffResult</b></A><br>
    ++<!-- Method dispatch -->
    ++<nobr><A HREF="android.support.v4.view.KeyEventCompat.html#android.support.v4.view.KeyEventCompat.dispatch_changed(android.view.KeyEvent, android.view.KeyEvent.Callback, java.lang.Object, java.lang.Object)" class="hiddenlink" target="rightframe">dispatch
    ++(<code>KeyEvent, Callback, Object, Object</code>)</A></nobr><br>
    ++<!-- Field dodgeInsetEdges -->
    ++<nobr><A HREF="android.support.design.widget.CoordinatorLayout.LayoutParams.html#android.support.design.widget.CoordinatorLayout.LayoutParams.dodgeInsetEdges" class="hiddenlink" target="rightframe">dodgeInsetEdges</A>
    ++</nobr><br>
    ++<!-- Class DrawableCompat -->
    ++<A HREF="android.support.v4.graphics.drawable.DrawableCompat.html" class="hiddenlink" target="rightframe">DrawableCompat</A><br>
    ++<!-- Field EXTRA_BT_FOLDER_TYPE -->
    ++<A NAME="E"></A>
    ++<br><font size="+2">E</font>&nbsp;
    ++<a href="#A"><font size="-2">A</font></a> 
    ++<a href="#B"><font size="-2">B</font></a> 
    ++<a href="#C"><font size="-2">C</font></a> 
    ++<a href="#D"><font size="-2">D</font></a> 
    ++<a href="#F"><font size="-2">F</font></a> 
    ++<a href="#G"><font size="-2">G</font></a> 
    ++<a href="#H"><font size="-2">H</font></a> 
    ++<a href="#I"><font size="-2">I</font></a> 
    ++<a href="#K"><font size="-2">K</font></a> 
    ++<a href="#L"><font size="-2">L</font></a> 
    ++<a href="#M"><font size="-2">M</font></a> 
    ++<a href="#N"><font size="-2">N</font></a> 
    ++<a href="#O"><font size="-2">O</font></a> 
    ++<a href="#P"><font size="-2">P</font></a> 
    ++<a href="#R"><font size="-2">R</font></a> 
    ++<a href="#S"><font size="-2">S</font></a> 
    ++<a href="#T"><font size="-2">T</font></a> 
    ++<a href="#V"><font size="-2">V</font></a> 
    ++<a href="#W"><font size="-2">W</font></a> 
    ++ <a href="#topheader"><font size="-2">TOP</font></a>
    ++<p><div style="line-height:1.5em;color:black">
    ++<nobr><A HREF="android.support.v4.media.MediaDescriptionCompat.html#android.support.v4.media.MediaDescriptionCompat.EXTRA_BT_FOLDER_TYPE" class="hiddenlink" target="rightframe">EXTRA_BT_FOLDER_TYPE</A>
    ++</nobr><br>
    ++<!-- Field EXTRA_ENABLE_INSTANT_APPS -->
    ++<nobr><A HREF="android.support.customtabs.CustomTabsIntent.html#android.support.customtabs.CustomTabsIntent.EXTRA_ENABLE_INSTANT_APPS" class="hiddenlink" target="rightframe">EXTRA_ENABLE_INSTANT_APPS</A>
    ++</nobr><br>
    ++<!-- Field EXTRA_SUGGESTION_KEYWORDS -->
    ++<nobr><A HREF="android.support.v4.media.MediaBrowserServiceCompat.BrowserRoot.html#android.support.v4.media.MediaBrowserServiceCompat.BrowserRoot.EXTRA_SUGGESTION_KEYWORDS" class="hiddenlink" target="rightframe">EXTRA_SUGGESTION_KEYWORDS</A>
    ++</nobr><br>
    ++<!-- Field EXTRA_USAGE_TIME_REPORT -->
    ++<nobr><A HREF="android.support.v4.app.ActivityOptionsCompat.html#android.support.v4.app.ActivityOptionsCompat.EXTRA_USAGE_TIME_REPORT" class="hiddenlink" target="rightframe">EXTRA_USAGE_TIME_REPORT</A>
    ++</nobr><br>
    ++<!-- Field EXTRA_USAGE_TIME_REPORT_PACKAGES -->
    ++<nobr><A HREF="android.support.v4.app.ActivityOptionsCompat.html#android.support.v4.app.ActivityOptionsCompat.EXTRA_USAGE_TIME_REPORT_PACKAGES" class="hiddenlink" target="rightframe">EXTRA_USAGE_TIME_REPORT_PACKAGES</A>
    ++</nobr><br>
    ++<!-- Method findFragmentByWho -->
    ++<A NAME="F"></A>
    ++<br><font size="+2">F</font>&nbsp;
    ++<a href="#A"><font size="-2">A</font></a> 
    ++<a href="#B"><font size="-2">B</font></a> 
    ++<a href="#C"><font size="-2">C</font></a> 
    ++<a href="#D"><font size="-2">D</font></a> 
    ++<a href="#E"><font size="-2">E</font></a> 
    ++<a href="#G"><font size="-2">G</font></a> 
    ++<a href="#H"><font size="-2">H</font></a> 
    ++<a href="#I"><font size="-2">I</font></a> 
    ++<a href="#K"><font size="-2">K</font></a> 
    ++<a href="#L"><font size="-2">L</font></a> 
    ++<a href="#M"><font size="-2">M</font></a> 
    ++<a href="#N"><font size="-2">N</font></a> 
    ++<a href="#O"><font size="-2">O</font></a> 
    ++<a href="#P"><font size="-2">P</font></a> 
    ++<a href="#R"><font size="-2">R</font></a> 
    ++<a href="#S"><font size="-2">S</font></a> 
    ++<a href="#T"><font size="-2">T</font></a> 
    ++<a href="#V"><font size="-2">V</font></a> 
    ++<a href="#W"><font size="-2">W</font></a> 
    ++ <a href="#topheader"><font size="-2">TOP</font></a>
    ++<p><div style="line-height:1.5em;color:black">
    ++<nobr><A HREF="android.support.v4.app.FragmentController.html#android.support.v4.app.FragmentController.findFragmentByWho_added(java.lang.String)" class="hiddenlink" target="rightframe"><b>findFragmentByWho</b>
    ++(<code>String</code>)</A></nobr><br>
    ++<!-- Method findPointerIndex -->
    ++<nobr><A HREF="android.support.v4.view.MotionEventCompat.html#android.support.v4.view.MotionEventCompat.findPointerIndex_changed(android.view.MotionEvent, int)" class="hiddenlink" target="rightframe">findPointerIndex
    ++(<code>MotionEvent, int</code>)</A></nobr><br>
    ++<!-- Class FloatingActionButton.Behavior -->
    ++<A HREF="android.support.design.widget.FloatingActionButton.Behavior.html" class="hiddenlink" target="rightframe">FloatingActionButton.Behavior</A><br>
    ++<!-- Class FragmentController -->
    ++<A HREF="android.support.v4.app.FragmentController.html" class="hiddenlink" target="rightframe">FragmentController</A><br>
    ++<!-- Method fromMediaItem -->
    ++<nobr><A HREF="android.support.v4.media.MediaBrowserCompat.MediaItem.html#android.support.v4.media.MediaBrowserCompat.MediaItem.fromMediaItem_added(java.lang.Object)" class="hiddenlink" target="rightframe"><b>fromMediaItem</b>
    ++(<code>Object</code>)</A></nobr><br>
    ++<!-- Method fromMediaItemList -->
    ++<nobr><A HREF="android.support.v4.media.MediaBrowserCompat.MediaItem.html#android.support.v4.media.MediaBrowserCompat.MediaItem.fromMediaItemList_added(java.util.List<?>)" class="hiddenlink" target="rightframe"><b>fromMediaItemList</b>
    ++(<code>List&lt;?&gt;</code>)</A></nobr><br>
    ++<!-- Method fromMediaSession -->
    ++<nobr><A HREF="android.support.v4.media.session.MediaSessionCompat.html#android.support.v4.media.session.MediaSessionCompat.fromMediaSession_added(android.content.Context, java.lang.Object)" class="hiddenlink" target="rightframe"><b>fromMediaSession</b>
    ++(<code>Context, Object</code>)</A></nobr><br>
    ++<!-- Method fromQueueItem -->
    ++<nobr><A HREF="android.support.v4.media.session.MediaSessionCompat.QueueItem.html#android.support.v4.media.session.MediaSessionCompat.QueueItem.fromQueueItem_added(java.lang.Object)" class="hiddenlink" target="rightframe"><b>fromQueueItem</b>
    ++(<code>Object</code>)</A></nobr><br>
    ++<!-- Method fromQueueItemList -->
    ++<nobr><A HREF="android.support.v4.media.session.MediaSessionCompat.QueueItem.html#android.support.v4.media.session.MediaSessionCompat.QueueItem.fromQueueItemList_added(java.util.List<?>)" class="hiddenlink" target="rightframe"><b>fromQueueItemList</b>
    ++(<code>List&lt;?&gt;</code>)</A></nobr><br>
    ++<!-- Method getAction -->
    ++<A NAME="G"></A>
    ++<br><font size="+2">G</font>&nbsp;
    ++<a href="#A"><font size="-2">A</font></a> 
    ++<a href="#B"><font size="-2">B</font></a> 
    ++<a href="#C"><font size="-2">C</font></a> 
    ++<a href="#D"><font size="-2">D</font></a> 
    ++<a href="#E"><font size="-2">E</font></a> 
    ++<a href="#F"><font size="-2">F</font></a> 
    ++<a href="#H"><font size="-2">H</font></a> 
    ++<a href="#I"><font size="-2">I</font></a> 
    ++<a href="#K"><font size="-2">K</font></a> 
    ++<a href="#L"><font size="-2">L</font></a> 
    ++<a href="#M"><font size="-2">M</font></a> 
    ++<a href="#N"><font size="-2">N</font></a> 
    ++<a href="#O"><font size="-2">O</font></a> 
    ++<a href="#P"><font size="-2">P</font></a> 
    ++<a href="#R"><font size="-2">R</font></a> 
    ++<a href="#S"><font size="-2">S</font></a> 
    ++<a href="#T"><font size="-2">T</font></a> 
    ++<a href="#V"><font size="-2">V</font></a> 
    ++<a href="#W"><font size="-2">W</font></a> 
    ++ <a href="#topheader"><font size="-2">TOP</font></a>
    ++<p><div style="line-height:1.5em;color:black">
    ++<nobr><A HREF="android.support.v4.view.accessibility.AccessibilityEventCompat.html#android.support.v4.view.accessibility.AccessibilityEventCompat.getAction_added(android.view.accessibility.AccessibilityEvent)" class="hiddenlink" target="rightframe"><b>getAction</b>
    ++(<code>AccessibilityEvent</code>)</A></nobr><br>
    ++<!-- Method getCompoundDrawablesRelative -->
    ++<nobr><A HREF="android.support.v4.widget.TextViewCompat.html#android.support.v4.widget.TextViewCompat.getCompoundDrawablesRelative_added(android.widget.TextView)" class="hiddenlink" target="rightframe"><b>getCompoundDrawablesRelative</b>
    ++(<code>TextView</code>)</A></nobr><br>
    ++<!-- Method getDependents -->
    ++<nobr><A HREF="android.support.design.widget.CoordinatorLayout.html#android.support.design.widget.CoordinatorLayout.getDependents_added(android.view.View)" class="hiddenlink" target="rightframe"><b>getDependents</b>
    ++(<code>View</code>)</A></nobr><br>
    ++<!-- Method getDescription -->
    ++<nobr><A HREF="android.support.v4.accessibilityservice.AccessibilityServiceInfoCompat.html#android.support.v4.accessibilityservice.AccessibilityServiceInfoCompat.getDescription_changed(android.accessibilityservice.AccessibilityServiceInfo)" class="hiddenlink" target="rightframe">getDescription
    ++(<code>AccessibilityServiceInfo</code>)</A></nobr><br>
    ++<!-- Method getDominantColor -->
    ++<nobr><A HREF="android.support.v7.graphics.Palette.html#android.support.v7.graphics.Palette.getDominantColor_added(int)" class="hiddenlink" target="rightframe"><b>getDominantColor</b>
    ++(<code>int</code>)</A></nobr><br>
    ++<!-- Method getDominantSwatch -->
    ++<nobr><A HREF="android.support.v7.graphics.Palette.html#android.support.v7.graphics.Palette.getDominantSwatch_added()" class="hiddenlink" target="rightframe"><b>getDominantSwatch</b>
    ++()</A></nobr><br>
    ++<!-- Method getDrawable -->
    ++<nobr><A HREF="android.support.v7.content.res.AppCompatResources.html#android.support.v7.content.res.AppCompatResources.getDrawable_added(android.content.Context, int)" class="hiddenlink" target="rightframe"><b>getDrawable</b>
    ++(<code>Context, int</code>)</A></nobr><br>
    ++<!-- Method getDrawerArrowDrawable -->
    ++<nobr><A HREF="android.support.v7.app.ActionBarDrawerToggle.html#android.support.v7.app.ActionBarDrawerToggle.getDrawerArrowDrawable_added()" class="hiddenlink" target="rightframe"><b>getDrawerArrowDrawable</b>
    ++()</A></nobr><br>
    ++<!-- Method getInsetDodgeRect -->
    ++<i>getInsetDodgeRect</i><br>
    ++&nbsp;&nbsp;<nobr><A HREF="android.support.design.widget.CoordinatorLayout.Behavior.html#android.support.design.widget.CoordinatorLayout.Behavior.getInsetDodgeRect_added(android.support.design.widget.CoordinatorLayout, V, android.graphics.Rect)" class="hiddenlink" target="rightframe">type&nbsp;<b>
    ++(<code>CoordinatorLayout, V, Rect</code>)</b>&nbsp;in&nbsp;android.support.design.widget.CoordinatorLayout.Behavior
    ++</A></nobr><br>
    ++<!-- Method getInsetDodgeRect -->
    ++&nbsp;&nbsp;<nobr><A HREF="android.support.design.widget.FloatingActionButton.Behavior.html#android.support.design.widget.FloatingActionButton.Behavior.getInsetDodgeRect_added(android.support.design.widget.CoordinatorLayout, android.support.design.widget.FloatingActionButton, android.graphics.Rect)" class="hiddenlink" target="rightframe">type&nbsp;<b>
    ++(<code>CoordinatorLayout, FloatingActionButton, Rect</code>)</b>&nbsp;in&nbsp;android.support.design.widget.FloatingActionButton.Behavior
    ++</A></nobr><br>
    ++<!-- Method getKeyDispatcherState -->
    ++<nobr><A HREF="android.support.v4.view.KeyEventCompat.html#android.support.v4.view.KeyEventCompat.getKeyDispatcherState_changed(android.view.View)" class="hiddenlink" target="rightframe">getKeyDispatcherState
    ++(<code>View</code>)</A></nobr><br>
    ++<!-- Method getLaunchBounds -->
    ++<nobr><A HREF="android.support.v4.app.ActivityOptionsCompat.html#android.support.v4.app.ActivityOptionsCompat.getLaunchBounds_added()" class="hiddenlink" target="rightframe"><b>getLaunchBounds</b>
    ++()</A></nobr><br>
    ++<!-- Method getMediaItemNumberViewFlipper -->
    ++<nobr><A HREF="android.support.v17.leanback.widget.AbstractMediaItemPresenter.ViewHolder.html#android.support.v17.leanback.widget.AbstractMediaItemPresenter.ViewHolder.getMediaItemNumberViewFlipper_added()" class="hiddenlink" target="rightframe"><b>getMediaItemNumberViewFlipper</b>
    ++()</A></nobr><br>
    ++<!-- Method getMediaItemPausedView -->
    ++<nobr><A HREF="android.support.v17.leanback.widget.AbstractMediaItemPresenter.ViewHolder.html#android.support.v17.leanback.widget.AbstractMediaItemPresenter.ViewHolder.getMediaItemPausedView_added()" class="hiddenlink" target="rightframe"><b>getMediaItemPausedView</b>
    ++()</A></nobr><br>
    ++<!-- Method getMediaItemPlayingView -->
    ++<nobr><A HREF="android.support.v17.leanback.widget.AbstractMediaItemPresenter.ViewHolder.html#android.support.v17.leanback.widget.AbstractMediaItemPresenter.ViewHolder.getMediaItemPlayingView_added()" class="hiddenlink" target="rightframe"><b>getMediaItemPlayingView</b>
    ++()</A></nobr><br>
    ++<!-- Method getMediaPlayState -->
    ++<nobr><A HREF="android.support.v17.leanback.widget.AbstractMediaItemPresenter.html#android.support.v17.leanback.widget.AbstractMediaItemPresenter.getMediaPlayState_added(java.lang.Object)" class="hiddenlink" target="rightframe"><b>getMediaPlayState</b>
    ++(<code>Object</code>)</A></nobr><br>
    ++<!-- Method getMovementGranularity -->
    ++<nobr><A HREF="android.support.v4.view.accessibility.AccessibilityEventCompat.html#android.support.v4.view.accessibility.AccessibilityEventCompat.getMovementGranularity_added(android.view.accessibility.AccessibilityEvent)" class="hiddenlink" target="rightframe"><b>getMovementGranularity</b>
    ++(<code>AccessibilityEvent</code>)</A></nobr><br>
    ++<!-- Method getOnFlingListener -->
    ++<nobr><A HREF="android.support.v7.widget.RecyclerView.html#android.support.v7.widget.RecyclerView.getOnFlingListener_added()" class="hiddenlink" target="rightframe"><b>getOnFlingListener</b>
    ++()</A></nobr><br>
    ++<!-- Method getOverScrollMode -->
    ++<nobr><A HREF="android.support.v4.view.ViewCompat.html#android.support.v4.view.ViewCompat.getOverScrollMode_changed(android.view.View)" class="hiddenlink" target="rightframe">getOverScrollMode
    ++(<code>View</code>)</A></nobr><br>
    ++<!-- Method getPasswordVisibilityToggleContentDescription -->
    ++<nobr><A HREF="android.support.design.widget.TextInputLayout.html#android.support.design.widget.TextInputLayout.getPasswordVisibilityToggleContentDescription_added()" class="hiddenlink" target="rightframe"><b>getPasswordVisibilityToggleContentDescription</b>
    ++()</A></nobr><br>
    ++<!-- Method getPasswordVisibilityToggleDrawable -->
    ++<nobr><A HREF="android.support.design.widget.TextInputLayout.html#android.support.design.widget.TextInputLayout.getPasswordVisibilityToggleDrawable_added()" class="hiddenlink" target="rightframe"><b>getPasswordVisibilityToggleDrawable</b>
    ++()</A></nobr><br>
    ++<!-- Method getPointerCount -->
    ++<nobr><A HREF="android.support.v4.view.MotionEventCompat.html#android.support.v4.view.MotionEventCompat.getPointerCount_changed(android.view.MotionEvent)" class="hiddenlink" target="rightframe">getPointerCount
    ++(<code>MotionEvent</code>)</A></nobr><br>
    ++<!-- Method getPointerId -->
    ++<nobr><A HREF="android.support.v4.view.MotionEventCompat.html#android.support.v4.view.MotionEventCompat.getPointerId_changed(android.view.MotionEvent, int)" class="hiddenlink" target="rightframe">getPointerId
    ++(<code>MotionEvent, int</code>)</A></nobr><br>
    ++<!-- Method getReferrer -->
    ++<nobr><A HREF="android.support.v4.app.ActivityCompat.html#android.support.v4.app.ActivityCompat.getReferrer_changed(android.app.Activity)" class="hiddenlink" target="rightframe">getReferrer
    ++(<code>Activity</code>)</A></nobr><br>
    ++<!-- Method getScaledPagingTouchSlop -->
    ++<nobr><A HREF="android.support.v4.view.ViewConfigurationCompat.html#android.support.v4.view.ViewConfigurationCompat.getScaledPagingTouchSlop_changed(android.view.ViewConfiguration)" class="hiddenlink" target="rightframe">getScaledPagingTouchSlop
    ++(<code>ViewConfiguration</code>)</A></nobr><br>
    ++<!-- Method getSelectionMode -->
    ++<nobr><A HREF="android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.CollectionInfoCompat.html#android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.CollectionInfoCompat.getSelectionMode_added()" class="hiddenlink" target="rightframe"><b>getSelectionMode</b>
    ++()</A></nobr><br>
    ++<!-- Method getSource -->
    ++<nobr><A HREF="android.support.v4.view.MotionEventCompat.html#android.support.v4.view.MotionEventCompat.getSource_changed(android.view.MotionEvent)" class="hiddenlink" target="rightframe">getSource
    ++(<code>MotionEvent</code>)</A></nobr><br>
    ++<!-- Method getX -->
    ++<nobr><A HREF="android.support.v4.view.MotionEventCompat.html#android.support.v4.view.MotionEventCompat.getX_changed(android.view.MotionEvent, int)" class="hiddenlink" target="rightframe">getX
    ++(<code>MotionEvent, int</code>)</A></nobr><br>
    ++<!-- Method getY -->
    ++<nobr><A HREF="android.support.v4.view.MotionEventCompat.html#android.support.v4.view.MotionEventCompat.getY_changed(android.view.MotionEvent, int)" class="hiddenlink" target="rightframe">getY
    ++(<code>MotionEvent, int</code>)</A></nobr><br>
    ++<!-- Class GridLayout -->
    ++<A HREF="pkg_android.support.v7.widget.html#GridLayout" class="hiddenlink" target="rightframe"><b>GridLayout</b></A><br>
    ++<!-- Class GridLayout.Alignment -->
    ++<A HREF="pkg_android.support.v7.widget.html#GridLayout.Alignment" class="hiddenlink" target="rightframe"><b>GridLayout.Alignment</b></A><br>
    ++<!-- Class GridLayout.LayoutParams -->
    ++<A HREF="pkg_android.support.v7.widget.html#GridLayout.LayoutParams" class="hiddenlink" target="rightframe"><b>GridLayout.LayoutParams</b></A><br>
    ++<!-- Class GridLayout.Spec -->
    ++<A HREF="pkg_android.support.v7.widget.html#GridLayout.Spec" class="hiddenlink" target="rightframe"><b>GridLayout.Spec</b></A><br>
    ++<!-- Field HOST_VIEW_ID -->
    ++<A NAME="H"></A>
    ++<br><font size="+2">H</font>&nbsp;
    ++<a href="#A"><font size="-2">A</font></a> 
    ++<a href="#B"><font size="-2">B</font></a> 
    ++<a href="#C"><font size="-2">C</font></a> 
    ++<a href="#D"><font size="-2">D</font></a> 
    ++<a href="#E"><font size="-2">E</font></a> 
    ++<a href="#F"><font size="-2">F</font></a> 
    ++<a href="#G"><font size="-2">G</font></a> 
    ++<a href="#I"><font size="-2">I</font></a> 
    ++<a href="#K"><font size="-2">K</font></a> 
    ++<a href="#L"><font size="-2">L</font></a> 
    ++<a href="#M"><font size="-2">M</font></a> 
    ++<a href="#N"><font size="-2">N</font></a> 
    ++<a href="#O"><font size="-2">O</font></a> 
    ++<a href="#P"><font size="-2">P</font></a> 
    ++<a href="#R"><font size="-2">R</font></a> 
    ++<a href="#S"><font size="-2">S</font></a> 
    ++<a href="#T"><font size="-2">T</font></a> 
    ++<a href="#V"><font size="-2">V</font></a> 
    ++<a href="#W"><font size="-2">W</font></a> 
    ++ <a href="#topheader"><font size="-2">TOP</font></a>
    ++<p><div style="line-height:1.5em;color:black">
    ++<nobr><A HREF="android.support.v4.view.accessibility.AccessibilityNodeProviderCompat.html#android.support.v4.view.accessibility.AccessibilityNodeProviderCompat.HOST_VIEW_ID" class="hiddenlink" target="rightframe">HOST_VIEW_ID</A>
    ++</nobr><br>
    ++<!-- Field insetEdge -->
    ++<A NAME="I"></A>
    ++<br><font size="+2">I</font>&nbsp;
    ++<a href="#A"><font size="-2">A</font></a> 
    ++<a href="#B"><font size="-2">B</font></a> 
    ++<a href="#C"><font size="-2">C</font></a> 
    ++<a href="#D"><font size="-2">D</font></a> 
    ++<a href="#E"><font size="-2">E</font></a> 
    ++<a href="#F"><font size="-2">F</font></a> 
    ++<a href="#G"><font size="-2">G</font></a> 
    ++<a href="#H"><font size="-2">H</font></a> 
    ++<a href="#K"><font size="-2">K</font></a> 
    ++<a href="#L"><font size="-2">L</font></a> 
    ++<a href="#M"><font size="-2">M</font></a> 
    ++<a href="#N"><font size="-2">N</font></a> 
    ++<a href="#O"><font size="-2">O</font></a> 
    ++<a href="#P"><font size="-2">P</font></a> 
    ++<a href="#R"><font size="-2">R</font></a> 
    ++<a href="#S"><font size="-2">S</font></a> 
    ++<a href="#T"><font size="-2">T</font></a> 
    ++<a href="#V"><font size="-2">V</font></a> 
    ++<a href="#W"><font size="-2">W</font></a> 
    ++ <a href="#topheader"><font size="-2">TOP</font></a>
    ++<p><div style="line-height:1.5em;color:black">
    ++<nobr><A HREF="android.support.design.widget.CoordinatorLayout.LayoutParams.html#android.support.design.widget.CoordinatorLayout.LayoutParams.insetEdge" class="hiddenlink" target="rightframe">insetEdge</A>
    ++</nobr><br>
    ++<!-- Method isAtLeastNMR1 -->
    ++<nobr><A HREF="android.support.v4.os.BuildCompat.html#android.support.v4.os.BuildCompat.isAtLeastNMR1_added()" class="hiddenlink" target="rightframe"><b>isAtLeastNMR1</b>
    ++()</A></nobr><br>
    ++<!-- Method isAutoHideEnabled -->
    ++<nobr><A HREF="android.support.design.widget.FloatingActionButton.Behavior.html#android.support.design.widget.FloatingActionButton.Behavior.isAutoHideEnabled_added()" class="hiddenlink" target="rightframe"><b>isAutoHideEnabled</b>
    ++()</A></nobr><br>
    ++<!-- Method isContextClickable -->
    ++<nobr><A HREF="android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.html#android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.isContextClickable_added()" class="hiddenlink" target="rightframe"><b>isContextClickable</b>
    ++()</A></nobr><br>
    ++<!-- Method isDirty -->
    ++<nobr><A HREF="android.support.design.widget.CoordinatorLayout.Behavior.html#android.support.design.widget.CoordinatorLayout.Behavior.isDirty_changed(android.support.design.widget.CoordinatorLayout, V)" class="hiddenlink" target="rightframe">isDirty
    ++(<code>CoordinatorLayout, V</code>)</A></nobr><br>
    ++<!-- Method isImmediateNotifySupported -->
    ++<nobr><A HREF="android.support.v17.leanback.widget.ObjectAdapter.html#android.support.v17.leanback.widget.ObjectAdapter.isImmediateNotifySupported_added()" class="hiddenlink" target="rightframe"><b>isImmediateNotifySupported</b>
    ++()</A></nobr><br>
    ++<!-- Method isImportantForAccessibility -->
    ++<nobr><A HREF="android.support.v4.view.ViewCompat.html#android.support.v4.view.ViewCompat.isImportantForAccessibility_added(android.view.View)" class="hiddenlink" target="rightframe"><b>isImportantForAccessibility</b>
    ++(<code>View</code>)</A></nobr><br>
    ++<!-- Method isOpaque -->
    ++<nobr><A HREF="android.support.v4.view.ViewCompat.html#android.support.v4.view.ViewCompat.isOpaque_changed(android.view.View)" class="hiddenlink" target="rightframe">isOpaque
    ++(<code>View</code>)</A></nobr><br>
    ++<!-- Method isPasswordVisibilityToggleEnabled -->
    ++<nobr><A HREF="android.support.design.widget.TextInputLayout.html#android.support.design.widget.TextInputLayout.isPasswordVisibilityToggleEnabled_added()" class="hiddenlink" target="rightframe"><b>isPasswordVisibilityToggleEnabled</b>
    ++()</A></nobr><br>
    ++<!-- Method isTracking -->
    ++<nobr><A HREF="android.support.v4.view.KeyEventCompat.html#android.support.v4.view.KeyEventCompat.isTracking_changed(android.view.KeyEvent)" class="hiddenlink" target="rightframe">isTracking
    ++(<code>KeyEvent</code>)</A></nobr><br>
    ++<!-- Class KeyEventCompat -->
    ++<A NAME="K"></A>
    ++<br><font size="+2">K</font>&nbsp;
    ++<a href="#A"><font size="-2">A</font></a> 
    ++<a href="#B"><font size="-2">B</font></a> 
    ++<a href="#C"><font size="-2">C</font></a> 
    ++<a href="#D"><font size="-2">D</font></a> 
    ++<a href="#E"><font size="-2">E</font></a> 
    ++<a href="#F"><font size="-2">F</font></a> 
    ++<a href="#G"><font size="-2">G</font></a> 
    ++<a href="#H"><font size="-2">H</font></a> 
    ++<a href="#I"><font size="-2">I</font></a> 
    ++<a href="#L"><font size="-2">L</font></a> 
    ++<a href="#M"><font size="-2">M</font></a> 
    ++<a href="#N"><font size="-2">N</font></a> 
    ++<a href="#O"><font size="-2">O</font></a> 
    ++<a href="#P"><font size="-2">P</font></a> 
    ++<a href="#R"><font size="-2">R</font></a> 
    ++<a href="#S"><font size="-2">S</font></a> 
    ++<a href="#T"><font size="-2">T</font></a> 
    ++<a href="#V"><font size="-2">V</font></a> 
    ++<a href="#W"><font size="-2">W</font></a> 
    ++ <a href="#topheader"><font size="-2">TOP</font></a>
    ++<p><div style="line-height:1.5em;color:black">
    ++<A HREF="android.support.v4.view.KeyEventCompat.html" class="hiddenlink" target="rightframe">KeyEventCompat</A><br>
    ++<!-- Method layoutDependsOn -->
    ++<A NAME="L"></A>
    ++<br><font size="+2">L</font>&nbsp;
    ++<a href="#A"><font size="-2">A</font></a> 
    ++<a href="#B"><font size="-2">B</font></a> 
    ++<a href="#C"><font size="-2">C</font></a> 
    ++<a href="#D"><font size="-2">D</font></a> 
    ++<a href="#E"><font size="-2">E</font></a> 
    ++<a href="#F"><font size="-2">F</font></a> 
    ++<a href="#G"><font size="-2">G</font></a> 
    ++<a href="#H"><font size="-2">H</font></a> 
    ++<a href="#I"><font size="-2">I</font></a> 
    ++<a href="#K"><font size="-2">K</font></a> 
    ++<a href="#M"><font size="-2">M</font></a> 
    ++<a href="#N"><font size="-2">N</font></a> 
    ++<a href="#O"><font size="-2">O</font></a> 
    ++<a href="#P"><font size="-2">P</font></a> 
    ++<a href="#R"><font size="-2">R</font></a> 
    ++<a href="#S"><font size="-2">S</font></a> 
    ++<a href="#T"><font size="-2">T</font></a> 
    ++<a href="#V"><font size="-2">V</font></a> 
    ++<a href="#W"><font size="-2">W</font></a> 
    ++ <a href="#topheader"><font size="-2">TOP</font></a>
    ++<p><div style="line-height:1.5em;color:black">
    ++<nobr><A HREF="android.support.design.widget.FloatingActionButton.Behavior.html#android.support.design.widget.FloatingActionButton.Behavior.layoutDependsOn_removed(android.support.design.widget.CoordinatorLayout, android.support.design.widget.FloatingActionButton, android.view.View)" class="hiddenlink" target="rightframe"><strike>layoutDependsOn</strike>
    ++(<code>CoordinatorLayout, FloatingActionButton, View</code>)</A></nobr><br>
    ++<!-- Class LeanbackSettingsFragment -->
    ++<A HREF="android.support.v17.preference.LeanbackSettingsFragment.html" class="hiddenlink" target="rightframe">LeanbackSettingsFragment</A><br>
    ++<!-- Class LinearLayoutCompat -->
    ++<A HREF="pkg_android.support.v7.widget.html#LinearLayoutCompat" class="hiddenlink" target="rightframe"><b>LinearLayoutCompat</b></A><br>
    ++<!-- Class LinearLayoutCompat.LayoutParams -->
    ++<A HREF="pkg_android.support.v7.widget.html#LinearLayoutCompat.LayoutParams" class="hiddenlink" target="rightframe"><b>LinearLayoutCompat.LayoutParams</b></A><br>
    ++<!-- Class LinearLayoutManager -->
    ++<A HREF="android.support.v7.widget.LinearLayoutManager.html" class="hiddenlink" target="rightframe">LinearLayoutManager</A><br>
    ++<!-- Class LinearSmoothScroller -->
    ++<A HREF="android.support.v7.widget.LinearSmoothScroller.html" class="hiddenlink" target="rightframe">LinearSmoothScroller</A><br>
    ++<!-- Class LinearSnapHelper -->
    ++<A HREF="pkg_android.support.v7.widget.html#LinearSnapHelper" class="hiddenlink" target="rightframe"><b>LinearSnapHelper</b></A><br>
    ++<!-- Class ListPopupWindow -->
    ++<A HREF="pkg_android.support.v7.widget.html#ListPopupWindow" class="hiddenlink" target="rightframe"><b>ListPopupWindow</b></A><br>
    ++<!-- Class ListUpdateCallback -->
    ++<A HREF="pkg_android.support.v7.util.html#ListUpdateCallback" class="hiddenlink" target="rightframe"><b><i>ListUpdateCallback</i></b></A><br>
    ++<!-- Method loadDescription -->
    ++<nobr><A HREF="android.support.v4.accessibilityservice.AccessibilityServiceInfoCompat.html#android.support.v4.accessibilityservice.AccessibilityServiceInfoCompat.loadDescription_added(android.accessibilityservice.AccessibilityServiceInfo, android.content.pm.PackageManager)" class="hiddenlink" target="rightframe"><b>loadDescription</b>
    ++(<code>AccessibilityServiceInfo, PackageManager</code>)</A></nobr><br>
    ++<!-- Method makeBasic -->
    ++<A NAME="M"></A>
    ++<br><font size="+2">M</font>&nbsp;
    ++<a href="#A"><font size="-2">A</font></a> 
    ++<a href="#B"><font size="-2">B</font></a> 
    ++<a href="#C"><font size="-2">C</font></a> 
    ++<a href="#D"><font size="-2">D</font></a> 
    ++<a href="#E"><font size="-2">E</font></a> 
    ++<a href="#F"><font size="-2">F</font></a> 
    ++<a href="#G"><font size="-2">G</font></a> 
    ++<a href="#H"><font size="-2">H</font></a> 
    ++<a href="#I"><font size="-2">I</font></a> 
    ++<a href="#K"><font size="-2">K</font></a> 
    ++<a href="#L"><font size="-2">L</font></a> 
    ++<a href="#N"><font size="-2">N</font></a> 
    ++<a href="#O"><font size="-2">O</font></a> 
    ++<a href="#P"><font size="-2">P</font></a> 
    ++<a href="#R"><font size="-2">R</font></a> 
    ++<a href="#S"><font size="-2">S</font></a> 
    ++<a href="#T"><font size="-2">T</font></a> 
    ++<a href="#V"><font size="-2">V</font></a> 
    ++<a href="#W"><font size="-2">W</font></a> 
    ++ <a href="#topheader"><font size="-2">TOP</font></a>
    ++<p><div style="line-height:1.5em;color:black">
    ++<nobr><A HREF="android.support.v4.app.ActivityOptionsCompat.html#android.support.v4.app.ActivityOptionsCompat.makeBasic_added()" class="hiddenlink" target="rightframe"><b>makeBasic</b>
    ++()</A></nobr><br>
    ++<!-- Method makeClipRevealAnimation -->
    ++<nobr><A HREF="android.support.v4.app.ActivityOptionsCompat.html#android.support.v4.app.ActivityOptionsCompat.makeClipRevealAnimation_added(android.view.View, int, int, int, int)" class="hiddenlink" target="rightframe"><b>makeClipRevealAnimation</b>
    ++(<code>View, int, int, int, int</code>)</A></nobr><br>
    ++<!-- Method makeTaskLaunchBehind -->
    ++<nobr><A HREF="android.support.v4.app.ActivityOptionsCompat.html#android.support.v4.app.ActivityOptionsCompat.makeTaskLaunchBehind_added()" class="hiddenlink" target="rightframe"><b>makeTaskLaunchBehind</b>
    ++()</A></nobr><br>
    ++<!-- Class MediaBrowserCompat.MediaItem -->
    ++<A HREF="android.support.v4.media.MediaBrowserCompat.MediaItem.html" class="hiddenlink" target="rightframe">MediaBrowserCompat.MediaItem</A><br>
    ++<!-- Class MediaBrowserServiceCompat.BrowserRoot -->
    ++<A HREF="android.support.v4.media.MediaBrowserServiceCompat.BrowserRoot.html" class="hiddenlink" target="rightframe">MediaBrowserServiceCompat.BrowserRoot</A><br>
    ++<!-- Class MediaButtonReceiver -->
    ++<A HREF="android.support.v4.media.session.MediaButtonReceiver.html" class="hiddenlink" target="rightframe">MediaButtonReceiver</A><br>
    ++<!-- Class MediaDescriptionCompat -->
    ++<A HREF="android.support.v4.media.MediaDescriptionCompat.html" class="hiddenlink" target="rightframe">MediaDescriptionCompat</A><br>
    ++<!-- Class MediaMetadataCompat -->
    ++<A HREF="android.support.v4.media.MediaMetadataCompat.html" class="hiddenlink" target="rightframe">MediaMetadataCompat</A><br>
    ++<!-- Class MediaSessionCompat -->
    ++<A HREF="android.support.v4.media.session.MediaSessionCompat.html" class="hiddenlink" target="rightframe">MediaSessionCompat</A><br>
    ++<!-- Class MediaSessionCompat.QueueItem -->
    ++<A HREF="android.support.v4.media.session.MediaSessionCompat.QueueItem.html" class="hiddenlink" target="rightframe">MediaSessionCompat.QueueItem</A><br>
    ++<!-- Field METADATA_KEY_BT_FOLDER_TYPE -->
    ++<nobr><A HREF="android.support.v4.media.MediaMetadataCompat.html#android.support.v4.media.MediaMetadataCompat.METADATA_KEY_BT_FOLDER_TYPE" class="hiddenlink" target="rightframe">METADATA_KEY_BT_FOLDER_TYPE</A>
    ++</nobr><br>
    ++<!-- Field METADATA_KEY_MEDIA_URI -->
    ++<nobr><A HREF="android.support.v4.media.MediaMetadataCompat.html#android.support.v4.media.MediaMetadataCompat.METADATA_KEY_MEDIA_URI" class="hiddenlink" target="rightframe">METADATA_KEY_MEDIA_URI</A>
    ++</nobr><br>
    ++<!-- Class MotionEventCompat -->
    ++<A HREF="android.support.v4.view.MotionEventCompat.html" class="hiddenlink" target="rightframe">MotionEventCompat</A><br>
    ++<!-- Class MultiSelectListPreferenceDialogFragmentCompat -->
    ++<A HREF="pkg_android.support.v7.preference.html#MultiSelectListPreferenceDialogFragmentCompat" class="hiddenlink" target="rightframe"><b>MultiSelectListPreferenceDialogFragmentCompat</b></A><br>
    ++<!-- Class NotificationCompat -->
    ++<A NAME="N"></A>
    ++<br><font size="+2">N</font>&nbsp;
    ++<a href="#A"><font size="-2">A</font></a> 
    ++<a href="#B"><font size="-2">B</font></a> 
    ++<a href="#C"><font size="-2">C</font></a> 
    ++<a href="#D"><font size="-2">D</font></a> 
    ++<a href="#E"><font size="-2">E</font></a> 
    ++<a href="#F"><font size="-2">F</font></a> 
    ++<a href="#G"><font size="-2">G</font></a> 
    ++<a href="#H"><font size="-2">H</font></a> 
    ++<a href="#I"><font size="-2">I</font></a> 
    ++<a href="#K"><font size="-2">K</font></a> 
    ++<a href="#L"><font size="-2">L</font></a> 
    ++<a href="#M"><font size="-2">M</font></a> 
    ++<a href="#O"><font size="-2">O</font></a> 
    ++<a href="#P"><font size="-2">P</font></a> 
    ++<a href="#R"><font size="-2">R</font></a> 
    ++<a href="#S"><font size="-2">S</font></a> 
    ++<a href="#T"><font size="-2">T</font></a> 
    ++<a href="#V"><font size="-2">V</font></a> 
    ++<a href="#W"><font size="-2">W</font></a> 
    ++ <a href="#topheader"><font size="-2">TOP</font></a>
    ++<p><div style="line-height:1.5em;color:black">
    ++<A HREF="pkg_android.support.v7.app.html#NotificationCompat" class="hiddenlink" target="rightframe"><b>NotificationCompat</b></A><br>
    ++<!-- Class NotificationCompat.Builder -->
    ++<A HREF="pkg_android.support.v7.app.html#NotificationCompat.Builder" class="hiddenlink" target="rightframe"><b>NotificationCompat.Builder</b></A><br>
    ++<!-- Class NotificationCompat.MediaStyle -->
    ++<A HREF="pkg_android.support.v7.app.html#NotificationCompat.MediaStyle" class="hiddenlink" target="rightframe"><b>NotificationCompat.MediaStyle</b></A><br>
    ++<!-- Method notifyPlayStateChanged -->
    ++<nobr><A HREF="android.support.v17.leanback.widget.AbstractMediaItemPresenter.ViewHolder.html#android.support.v17.leanback.widget.AbstractMediaItemPresenter.ViewHolder.notifyPlayStateChanged_added()" class="hiddenlink" target="rightframe"><b>notifyPlayStateChanged</b>
    ++()</A></nobr><br>
    ++<!-- Class ObjectAdapter -->
    ++<A NAME="O"></A>
    ++<br><font size="+2">O</font>&nbsp;
    ++<a href="#A"><font size="-2">A</font></a> 
    ++<a href="#B"><font size="-2">B</font></a> 
    ++<a href="#C"><font size="-2">C</font></a> 
    ++<a href="#D"><font size="-2">D</font></a> 
    ++<a href="#E"><font size="-2">E</font></a> 
    ++<a href="#F"><font size="-2">F</font></a> 
    ++<a href="#G"><font size="-2">G</font></a> 
    ++<a href="#H"><font size="-2">H</font></a> 
    ++<a href="#I"><font size="-2">I</font></a> 
    ++<a href="#K"><font size="-2">K</font></a> 
    ++<a href="#L"><font size="-2">L</font></a> 
    ++<a href="#M"><font size="-2">M</font></a> 
    ++<a href="#N"><font size="-2">N</font></a> 
    ++<a href="#P"><font size="-2">P</font></a> 
    ++<a href="#R"><font size="-2">R</font></a> 
    ++<a href="#S"><font size="-2">S</font></a> 
    ++<a href="#T"><font size="-2">T</font></a> 
    ++<a href="#V"><font size="-2">V</font></a> 
    ++<a href="#W"><font size="-2">W</font></a> 
    ++ <a href="#topheader"><font size="-2">TOP</font></a>
    ++<p><div style="line-height:1.5em;color:black">
    ++<A HREF="android.support.v17.leanback.widget.ObjectAdapter.html" class="hiddenlink" target="rightframe">ObjectAdapter</A><br>
    ++<!-- Method obtain -->
    ++<i>obtain</i><br>
    ++&nbsp;&nbsp;<nobr><A HREF="android.support.v4.media.session.MediaSessionCompat.html#android.support.v4.media.session.MediaSessionCompat.obtain_changed(android.content.Context, java.lang.Object)" class="hiddenlink" target="rightframe">type&nbsp;
    ++(<code>Context, Object</code>)&nbsp;in&nbsp;android.support.v4.media.session.MediaSessionCompat
    ++</A></nobr><br>
    ++<!-- Method obtain -->
    ++&nbsp;&nbsp;<nobr><A HREF="android.support.v4.media.session.MediaSessionCompat.QueueItem.html#android.support.v4.media.session.MediaSessionCompat.QueueItem.obtain_changed(java.lang.Object)" class="hiddenlink" target="rightframe">type&nbsp;
    ++(<code>Object</code>)&nbsp;in&nbsp;android.support.v4.media.session.MediaSessionCompat.QueueItem
    ++</A></nobr><br>
    ++<!-- Method obtain -->
    ++&nbsp;&nbsp;<nobr><A HREF="android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.CollectionInfoCompat.html#android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.CollectionInfoCompat.obtain_added(int, int, boolean)" class="hiddenlink" target="rightframe">type&nbsp;<b>
    ++(<code>int, int, boolean</code>)</b>&nbsp;in&nbsp;android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.CollectionInfoCompat
    ++</A></nobr><br>
    ++<!-- Method obtain -->
    ++&nbsp;&nbsp;<nobr><A HREF="android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.CollectionItemInfoCompat.html#android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.CollectionItemInfoCompat.obtain_added(int, int, int, int, boolean)" class="hiddenlink" target="rightframe">type&nbsp;<b>
    ++(<code>int, int, int, int, boolean</code>)</b>&nbsp;in&nbsp;android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.CollectionItemInfoCompat
    ++</A></nobr><br>
    ++<!-- Method obtain -->
    ++&nbsp;&nbsp;<nobr><A HREF="android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.RangeInfoCompat.html#android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.RangeInfoCompat.obtain_added(int, float, float, float)" class="hiddenlink" target="rightframe">type&nbsp;<b>
    ++(<code>int, float, float, float</code>)</b>&nbsp;in&nbsp;android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.RangeInfoCompat
    ++</A></nobr><br>
    ++<!-- Method onAccessibilityStateChanged -->
    ++<nobr><A HREF="android.support.v4.view.accessibility.AccessibilityManagerCompat.AccessibilityStateChangeListenerCompat.html#android.support.v4.view.accessibility.AccessibilityManagerCompat.AccessibilityStateChangeListenerCompat.onAccessibilityStateChanged_removed(boolean)" class="hiddenlink" target="rightframe"><strike>onAccessibilityStateChanged</strike>
    ++(<code>boolean</code>)</A></nobr><br>
    ++<!-- Method onAttachedToLayoutParams -->
    ++<nobr><A HREF="android.support.design.widget.CoordinatorLayout.Behavior.html#android.support.design.widget.CoordinatorLayout.Behavior.onAttachedToLayoutParams_added(android.support.design.widget.CoordinatorLayout.LayoutParams)" class="hiddenlink" target="rightframe"><b>onAttachedToLayoutParams</b>
    ++(<code>LayoutParams</code>)</A></nobr><br>
    ++<!-- Method onBindMediaPlayState -->
    ++<nobr><A HREF="android.support.v17.leanback.widget.AbstractMediaItemPresenter.html#android.support.v17.leanback.widget.AbstractMediaItemPresenter.onBindMediaPlayState_added(android.support.v17.leanback.widget.AbstractMediaItemPresenter.ViewHolder)" class="hiddenlink" target="rightframe"><b>onBindMediaPlayState</b>
    ++(<code>ViewHolder</code>)</A></nobr><br>
    ++<!-- Method onChanged -->
    ++<nobr><A HREF="android.support.v7.util.SortedList.Callback.html#android.support.v7.util.SortedList.Callback.onChanged_added(int, int, java.lang.Object)" class="hiddenlink" target="rightframe"><b>onChanged</b>
    ++(<code>int, int, Object</code>)</A></nobr><br>
    ++<!-- Method onDependentViewRemoved -->
    ++<nobr><A HREF="android.support.design.widget.FloatingActionButton.Behavior.html#android.support.design.widget.FloatingActionButton.Behavior.onDependentViewRemoved_removed(android.support.design.widget.CoordinatorLayout, android.support.design.widget.FloatingActionButton, android.view.View)" class="hiddenlink" target="rightframe"><strike>onDependentViewRemoved</strike>
    ++(<code>CoordinatorLayout, FloatingActionButton, View</code>)</A></nobr><br>
    ++<!-- Method onDetachedFromLayoutParams -->
    ++<nobr><A HREF="android.support.design.widget.CoordinatorLayout.Behavior.html#android.support.design.widget.CoordinatorLayout.Behavior.onDetachedFromLayoutParams_added()" class="hiddenlink" target="rightframe"><b>onDetachedFromLayoutParams</b>
    ++()</A></nobr><br>
    ++<!-- Method onInserted -->
    ++<nobr><A HREF="android.support.v7.util.SortedList.Callback.html#android.support.v7.util.SortedList.Callback.onInserted_removed(int, int)" class="hiddenlink" target="rightframe"><strike>onInserted</strike>
    ++(<code>int, int</code>)</A></nobr><br>
    ++<!-- Method onMoved -->
    ++<nobr><A HREF="android.support.v7.util.SortedList.Callback.html#android.support.v7.util.SortedList.Callback.onMoved_removed(int, int)" class="hiddenlink" target="rightframe"><strike>onMoved</strike>
    ++(<code>int, int</code>)</A></nobr><br>
    ++<!-- Method onRemoved -->
    ++<nobr><A HREF="android.support.v7.util.SortedList.Callback.html#android.support.v7.util.SortedList.Callback.onRemoved_removed(int, int)" class="hiddenlink" target="rightframe"><strike>onRemoved</strike>
    ++(<code>int, int</code>)</A></nobr><br>
    ++<!-- Method onRequestChildRectangleOnScreen -->
    ++<i>onRequestChildRectangleOnScreen</i><br>
    ++&nbsp;&nbsp;<nobr><A HREF="android.support.design.widget.AppBarLayout.ScrollingViewBehavior.html#android.support.design.widget.AppBarLayout.ScrollingViewBehavior.onRequestChildRectangleOnScreen_added(android.support.design.widget.CoordinatorLayout, android.view.View, android.graphics.Rect, boolean)" class="hiddenlink" target="rightframe">type&nbsp;<b>
    ++(<code>CoordinatorLayout, View, Rect, boolean</code>)</b>&nbsp;in&nbsp;android.support.design.widget.AppBarLayout.ScrollingViewBehavior
    ++</A></nobr><br>
    ++<!-- Method onRequestChildRectangleOnScreen -->
    ++&nbsp;&nbsp;<nobr><A HREF="android.support.design.widget.CoordinatorLayout.Behavior.html#android.support.design.widget.CoordinatorLayout.Behavior.onRequestChildRectangleOnScreen_added(android.support.design.widget.CoordinatorLayout, V, android.graphics.Rect, boolean)" class="hiddenlink" target="rightframe">type&nbsp;<b>
    ++(<code>CoordinatorLayout, V, Rect, boolean</code>)</b>&nbsp;in&nbsp;android.support.design.widget.CoordinatorLayout.Behavior
    ++</A></nobr><br>
    ++<!-- Method onSharedElementsArrived -->
    ++<nobr><A HREF="android.support.v4.app.SharedElementCallback.html#android.support.v4.app.SharedElementCallback.onSharedElementsArrived_added(java.util.List<java.lang.String>, java.util.List<android.view.View>, android.support.v4.app.SharedElementCallback.OnSharedElementsReadyListener)" class="hiddenlink" target="rightframe"><b>onSharedElementsArrived</b>
    ++(<code>List&lt;String&gt;, List&lt;View&gt;, OnSharedElementsReadyListener</code>)</A></nobr><br>
    ++<!-- Method onStart -->
    ++<nobr><A HREF="android.support.v7.app.AppCompatDelegate.html#android.support.v7.app.AppCompatDelegate.onStart_added()" class="hiddenlink" target="rightframe"><b>onStart</b>
    ++()</A></nobr><br>
    ++<!-- Method onUnbindMediaPlayState -->
    ++<nobr><A HREF="android.support.v17.leanback.widget.AbstractMediaItemPresenter.html#android.support.v17.leanback.widget.AbstractMediaItemPresenter.onUnbindMediaPlayState_added(android.support.v17.leanback.widget.AbstractMediaItemPresenter.ViewHolder)" class="hiddenlink" target="rightframe"><b>onUnbindMediaPlayState</b>
    ++(<code>ViewHolder</code>)</A></nobr><br>
    ++<!-- Field OVER_SCROLL_ALWAYS -->
    ++<nobr><A HREF="android.support.v4.view.ViewCompat.html#android.support.v4.view.ViewCompat.OVER_SCROLL_ALWAYS" class="hiddenlink" target="rightframe">OVER_SCROLL_ALWAYS</A>
    ++</nobr><br>
    ++<!-- Field OVER_SCROLL_IF_CONTENT_SCROLLS -->
    ++<nobr><A HREF="android.support.v4.view.ViewCompat.html#android.support.v4.view.ViewCompat.OVER_SCROLL_IF_CONTENT_SCROLLS" class="hiddenlink" target="rightframe">OVER_SCROLL_IF_CONTENT_SCROLLS</A>
    ++</nobr><br>
    ++<!-- Field OVER_SCROLL_NEVER -->
    ++<nobr><A HREF="android.support.v4.view.ViewCompat.html#android.support.v4.view.ViewCompat.OVER_SCROLL_NEVER" class="hiddenlink" target="rightframe">OVER_SCROLL_NEVER</A>
    ++</nobr><br>
    ++<!-- Class Palette -->
    ++<A NAME="P"></A>
    ++<br><font size="+2">P</font>&nbsp;
    ++<a href="#A"><font size="-2">A</font></a> 
    ++<a href="#B"><font size="-2">B</font></a> 
    ++<a href="#C"><font size="-2">C</font></a> 
    ++<a href="#D"><font size="-2">D</font></a> 
    ++<a href="#E"><font size="-2">E</font></a> 
    ++<a href="#F"><font size="-2">F</font></a> 
    ++<a href="#G"><font size="-2">G</font></a> 
    ++<a href="#H"><font size="-2">H</font></a> 
    ++<a href="#I"><font size="-2">I</font></a> 
    ++<a href="#K"><font size="-2">K</font></a> 
    ++<a href="#L"><font size="-2">L</font></a> 
    ++<a href="#M"><font size="-2">M</font></a> 
    ++<a href="#N"><font size="-2">N</font></a> 
    ++<a href="#O"><font size="-2">O</font></a> 
    ++<a href="#R"><font size="-2">R</font></a> 
    ++<a href="#S"><font size="-2">S</font></a> 
    ++<a href="#T"><font size="-2">T</font></a> 
    ++<a href="#V"><font size="-2">V</font></a> 
    ++<a href="#W"><font size="-2">W</font></a> 
    ++ <a href="#topheader"><font size="-2">TOP</font></a>
    ++<p><div style="line-height:1.5em;color:black">
    ++<A HREF="android.support.v7.graphics.Palette.html" class="hiddenlink" target="rightframe">Palette</A><br>
    ++<!-- Class PatternsCompat -->
    ++<A HREF="pkg_android.support.v4.util.html#PatternsCompat" class="hiddenlink" target="rightframe"><b>PatternsCompat</b></A><br>
    ++<!-- Field PEEK_HEIGHT_AUTO -->
    ++<nobr><A HREF="android.support.design.widget.BottomSheetBehavior.html#android.support.design.widget.BottomSheetBehavior.PEEK_HEIGHT_AUTO" class="hiddenlink" target="rightframe">PEEK_HEIGHT_AUTO</A>
    ++</nobr><br>
    ++<!-- Field PLAY_STATE_INITIAL -->
    ++<nobr><A HREF="android.support.v17.leanback.widget.AbstractMediaItemPresenter.html#android.support.v17.leanback.widget.AbstractMediaItemPresenter.PLAY_STATE_INITIAL" class="hiddenlink" target="rightframe">PLAY_STATE_INITIAL</A>
    ++</nobr><br>
    ++<!-- Field PLAY_STATE_PAUSED -->
    ++<nobr><A HREF="android.support.v17.leanback.widget.AbstractMediaItemPresenter.html#android.support.v17.leanback.widget.AbstractMediaItemPresenter.PLAY_STATE_PAUSED" class="hiddenlink" target="rightframe">PLAY_STATE_PAUSED</A>
    ++</nobr><br>
    ++<!-- Field PLAY_STATE_PLAYING -->
    ++<nobr><A HREF="android.support.v17.leanback.widget.AbstractMediaItemPresenter.html#android.support.v17.leanback.widget.AbstractMediaItemPresenter.PLAY_STATE_PLAYING" class="hiddenlink" target="rightframe">PLAY_STATE_PLAYING</A>
    ++</nobr><br>
    ++<!-- Class PlaybackStateCompat -->
    ++<A HREF="android.support.v4.media.session.PlaybackStateCompat.html" class="hiddenlink" target="rightframe">PlaybackStateCompat</A><br>
    ++<!-- Class PopupMenu -->
    ++<A HREF="pkg_android.support.v7.widget.html#PopupMenu" class="hiddenlink" target="rightframe"><b>PopupMenu</b></A><br>
    ++<!-- Class PopupMenu.OnDismissListener -->
    ++<A HREF="pkg_android.support.v7.widget.html#PopupMenu.OnDismissListener" class="hiddenlink" target="rightframe"><b><i>PopupMenu.OnDismissListener</i></b></A><br>
    ++<!-- Class PopupMenu.OnMenuItemClickListener -->
    ++<A HREF="pkg_android.support.v7.widget.html#PopupMenu.OnMenuItemClickListener" class="hiddenlink" target="rightframe"><b><i>PopupMenu.OnMenuItemClickListener</i></b></A><br>
    ++<!-- Class PreferenceFragment -->
    ++<A HREF="android.support.v14.preference.PreferenceFragment.html" class="hiddenlink" target="rightframe">PreferenceFragment</A><br>
    ++<!-- Method prepareForDrop -->
    ++<nobr><A HREF="android.support.v7.widget.LinearLayoutManager.html#android.support.v7.widget.LinearLayoutManager.prepareForDrop_removed(android.view.View, android.view.View, int, int)" class="hiddenlink" target="rightframe"><strike>prepareForDrop</strike>
    ++(<code>View, View, int, int</code>)</A></nobr><br>
    ++<!-- Class RecyclerView -->
    ++<A NAME="R"></A>
    ++<br><font size="+2">R</font>&nbsp;
    ++<a href="#A"><font size="-2">A</font></a> 
    ++<a href="#B"><font size="-2">B</font></a> 
    ++<a href="#C"><font size="-2">C</font></a> 
    ++<a href="#D"><font size="-2">D</font></a> 
    ++<a href="#E"><font size="-2">E</font></a> 
    ++<a href="#F"><font size="-2">F</font></a> 
    ++<a href="#G"><font size="-2">G</font></a> 
    ++<a href="#H"><font size="-2">H</font></a> 
    ++<a href="#I"><font size="-2">I</font></a> 
    ++<a href="#K"><font size="-2">K</font></a> 
    ++<a href="#L"><font size="-2">L</font></a> 
    ++<a href="#M"><font size="-2">M</font></a> 
    ++<a href="#N"><font size="-2">N</font></a> 
    ++<a href="#O"><font size="-2">O</font></a> 
    ++<a href="#P"><font size="-2">P</font></a> 
    ++<a href="#S"><font size="-2">S</font></a> 
    ++<a href="#T"><font size="-2">T</font></a> 
    ++<a href="#V"><font size="-2">V</font></a> 
    ++<a href="#W"><font size="-2">W</font></a> 
    ++ <a href="#topheader"><font size="-2">TOP</font></a>
    ++<p><div style="line-height:1.5em;color:black">
    ++<A HREF="android.support.v7.widget.RecyclerView.html" class="hiddenlink" target="rightframe">RecyclerView</A><br>
    ++<!-- Class RecyclerView.OnFlingListener -->
    ++<A HREF="pkg_android.support.v7.widget.html#RecyclerView.OnFlingListener" class="hiddenlink" target="rightframe"><b>RecyclerView.OnFlingListener</b></A><br>
    ++<!-- Class RecyclerView.SmoothScroller.ScrollVectorProvider -->
    ++<A HREF="pkg_android.support.v7.widget.html#RecyclerView.SmoothScroller.ScrollVectorProvider" class="hiddenlink" target="rightframe"><b><i>RecyclerView.SmoothScroller.ScrollVectorProvider</i></b></A><br>
    ++<!-- Method removeAccessibilityStateChangeListener -->
    ++<nobr><A HREF="android.support.v4.view.accessibility.AccessibilityManagerCompat.html#android.support.v4.view.accessibility.AccessibilityManagerCompat.removeAccessibilityStateChangeListener_changed(android.view.accessibility.AccessibilityManager, android.support.v4.view.accessibility.AccessibilityManagerCompat.AccessibilityStateChangeListener)" class="hiddenlink" target="rightframe">removeAccessibilityStateChangeListener
    ++(<code>AccessibilityManager, AccessibilityStateChangeListener</code>)</A></nobr><br>
    ++<!-- Method removeTouchExplorationStateChangeListener -->
    ++<nobr><A HREF="android.support.v4.view.accessibility.AccessibilityManagerCompat.html#android.support.v4.view.accessibility.AccessibilityManagerCompat.removeTouchExplorationStateChangeListener_added(android.view.accessibility.AccessibilityManager, android.support.v4.view.accessibility.AccessibilityManagerCompat.TouchExplorationStateChangeListener)" class="hiddenlink" target="rightframe"><b>removeTouchExplorationStateChangeListener</b>
    ++(<code>AccessibilityManager, TouchExplorationStateChangeListener</code>)</A></nobr><br>
    ++<!-- Method requestUsageTimeReport -->
    ++<nobr><A HREF="android.support.v4.app.ActivityOptionsCompat.html#android.support.v4.app.ActivityOptionsCompat.requestUsageTimeReport_added(android.app.PendingIntent)" class="hiddenlink" target="rightframe"><b>requestUsageTimeReport</b>
    ++(<code>PendingIntent</code>)</A></nobr><br>
    ++<!-- Class SearchView -->
    ++<A NAME="S"></A>
    ++<br><font size="+2">S</font>&nbsp;
    ++<a href="#A"><font size="-2">A</font></a> 
    ++<a href="#B"><font size="-2">B</font></a> 
    ++<a href="#C"><font size="-2">C</font></a> 
    ++<a href="#D"><font size="-2">D</font></a> 
    ++<a href="#E"><font size="-2">E</font></a> 
    ++<a href="#F"><font size="-2">F</font></a> 
    ++<a href="#G"><font size="-2">G</font></a> 
    ++<a href="#H"><font size="-2">H</font></a> 
    ++<a href="#I"><font size="-2">I</font></a> 
    ++<a href="#K"><font size="-2">K</font></a> 
    ++<a href="#L"><font size="-2">L</font></a> 
    ++<a href="#M"><font size="-2">M</font></a> 
    ++<a href="#N"><font size="-2">N</font></a> 
    ++<a href="#O"><font size="-2">O</font></a> 
    ++<a href="#P"><font size="-2">P</font></a> 
    ++<a href="#R"><font size="-2">R</font></a> 
    ++<a href="#T"><font size="-2">T</font></a> 
    ++<a href="#V"><font size="-2">V</font></a> 
    ++<a href="#W"><font size="-2">W</font></a> 
    ++ <a href="#topheader"><font size="-2">TOP</font></a>
    ++<p><div style="line-height:1.5em;color:black">
    ++<A HREF="pkg_android.support.v7.widget.html#SearchView" class="hiddenlink" target="rightframe"><b>SearchView</b></A><br>
    ++<!-- Class SearchView.OnCloseListener -->
    ++<A HREF="pkg_android.support.v7.widget.html#SearchView.OnCloseListener" class="hiddenlink" target="rightframe"><b><i>SearchView.OnCloseListener</i></b></A><br>
    ++<!-- Class SearchView.OnQueryTextListener -->
    ++<A HREF="pkg_android.support.v7.widget.html#SearchView.OnQueryTextListener" class="hiddenlink" target="rightframe"><b><i>SearchView.OnQueryTextListener</i></b></A><br>
    ++<!-- Class SearchView.OnSuggestionListener -->
    ++<A HREF="pkg_android.support.v7.widget.html#SearchView.OnSuggestionListener" class="hiddenlink" target="rightframe"><b><i>SearchView.OnSuggestionListener</i></b></A><br>
    ++<!-- Class SearchViewCompat -->
    ++<A HREF="android.support.v4.widget.SearchViewCompat.html" class="hiddenlink" target="rightframe">SearchViewCompat</A><br>
    ++<!-- Class SearchViewCompat.OnCloseListener -->
    ++<A HREF="pkg_android.support.v4.widget.html#SearchViewCompat.OnCloseListener" class="hiddenlink" target="rightframe"><b><i>SearchViewCompat.OnCloseListener</i></b></A><br>
    ++<!-- Class SearchViewCompat.OnCloseListenerCompat -->
    ++<A HREF="android.support.v4.widget.SearchViewCompat.OnCloseListenerCompat.html" class="hiddenlink" target="rightframe">SearchViewCompat.OnCloseListenerCompat</A><br>
    ++<!-- Class SearchViewCompat.OnQueryTextListener -->
    ++<A HREF="pkg_android.support.v4.widget.html#SearchViewCompat.OnQueryTextListener" class="hiddenlink" target="rightframe"><b><i>SearchViewCompat.OnQueryTextListener</i></b></A><br>
    ++<!-- Class SearchViewCompat.OnQueryTextListenerCompat -->
    ++<A HREF="android.support.v4.widget.SearchViewCompat.OnQueryTextListenerCompat.html" class="hiddenlink" target="rightframe">SearchViewCompat.OnQueryTextListenerCompat</A><br>
    ++<!-- Class ServiceCompat -->
    ++<A HREF="android.support.v4.app.ServiceCompat.html" class="hiddenlink" target="rightframe">ServiceCompat</A><br>
    ++<!-- Method setAction -->
    ++<nobr><A HREF="android.support.v4.view.accessibility.AccessibilityEventCompat.html#android.support.v4.view.accessibility.AccessibilityEventCompat.setAction_added(android.view.accessibility.AccessibilityEvent, int)" class="hiddenlink" target="rightframe"><b>setAction</b>
    ++(<code>AccessibilityEvent, int</code>)</A></nobr><br>
    ++<!-- Method setAlwaysUseBrowserUI -->
    ++<nobr><A HREF="android.support.customtabs.CustomTabsIntent.html#android.support.customtabs.CustomTabsIntent.setAlwaysUseBrowserUI_added(android.content.Intent)" class="hiddenlink" target="rightframe"><b>setAlwaysUseBrowserUI</b>
    ++(<code>Intent</code>)</A></nobr><br>
    ++<!-- Method setAutoHideEnabled -->
    ++<nobr><A HREF="android.support.design.widget.FloatingActionButton.Behavior.html#android.support.design.widget.FloatingActionButton.Behavior.setAutoHideEnabled_added(boolean)" class="hiddenlink" target="rightframe"><b>setAutoHideEnabled</b>
    ++(<code>boolean</code>)</A></nobr><br>
    ++<!-- Method setCollapsedTitleTextColor -->
    ++<nobr><A HREF="android.support.design.widget.CollapsingToolbarLayout.html#android.support.design.widget.CollapsingToolbarLayout.setCollapsedTitleTextColor_added(android.content.res.ColorStateList)" class="hiddenlink" target="rightframe"><b>setCollapsedTitleTextColor</b>
    ++(<code>ColorStateList</code>)</A></nobr><br>
    ++<!-- Method setContextClickable -->
    ++<nobr><A HREF="android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.html#android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.setContextClickable_added(boolean)" class="hiddenlink" target="rightframe"><b>setContextClickable</b>
    ++(<code>boolean</code>)</A></nobr><br>
    ++<!-- Method setDrawerArrowDrawable -->
    ++<nobr><A HREF="android.support.v7.app.ActionBarDrawerToggle.html#android.support.v7.app.ActionBarDrawerToggle.setDrawerArrowDrawable_added(android.support.v7.graphics.drawable.DrawerArrowDrawable)" class="hiddenlink" target="rightframe"><b>setDrawerArrowDrawable</b>
    ++(<code>DrawerArrowDrawable</code>)</A></nobr><br>
    ++<!-- Method setExpandedTitleTextColor -->
    ++<nobr><A HREF="android.support.design.widget.CollapsingToolbarLayout.html#android.support.design.widget.CollapsingToolbarLayout.setExpandedTitleTextColor_added(android.content.res.ColorStateList)" class="hiddenlink" target="rightframe"><b>setExpandedTitleTextColor</b>
    ++(<code>ColorStateList</code>)</A></nobr><br>
    ++<!-- Method setInstantAppsEnabled -->
    ++<nobr><A HREF="android.support.customtabs.CustomTabsIntent.Builder.html#android.support.customtabs.CustomTabsIntent.Builder.setInstantAppsEnabled_added(boolean)" class="hiddenlink" target="rightframe"><b>setInstantAppsEnabled</b>
    ++(<code>boolean</code>)</A></nobr><br>
    ++<!-- Method setLaunchBounds -->
    ++<nobr><A HREF="android.support.v4.app.ActivityOptionsCompat.html#android.support.v4.app.ActivityOptionsCompat.setLaunchBounds_added(android.graphics.Rect)" class="hiddenlink" target="rightframe"><b>setLaunchBounds</b>
    ++(<code>Rect</code>)</A></nobr><br>
    ++<!-- Method setMovementGranularity -->
    ++<nobr><A HREF="android.support.v4.view.accessibility.AccessibilityEventCompat.html#android.support.v4.view.accessibility.AccessibilityEventCompat.setMovementGranularity_added(android.view.accessibility.AccessibilityEvent, int)" class="hiddenlink" target="rightframe"><b>setMovementGranularity</b>
    ++(<code>AccessibilityEvent, int</code>)</A></nobr><br>
    ++<!-- Method setOnChildScrollUpCallback -->
    ++<nobr><A HREF="android.support.v4.widget.SwipeRefreshLayout.html#android.support.v4.widget.SwipeRefreshLayout.setOnChildScrollUpCallback_added(android.support.v4.widget.SwipeRefreshLayout.OnChildScrollUpCallback)" class="hiddenlink" target="rightframe"><b>setOnChildScrollUpCallback</b>
    ++(<code>OnChildScrollUpCallback</code>)</A></nobr><br>
    ++<!-- Method setOnCloseListener -->
    ++<nobr><A HREF="android.support.v4.widget.SearchViewCompat.html#android.support.v4.widget.SearchViewCompat.setOnCloseListener_changed(android.view.View, android.support.v4.widget.SearchViewCompat.OnCloseListener)" class="hiddenlink" target="rightframe">setOnCloseListener
    ++(<code>View, OnCloseListener</code>)</A></nobr><br>
    ++<!-- Method setOnFlingListener -->
    ++<nobr><A HREF="android.support.v7.widget.RecyclerView.html#android.support.v7.widget.RecyclerView.setOnFlingListener_added(android.support.v7.widget.RecyclerView.OnFlingListener)" class="hiddenlink" target="rightframe"><b>setOnFlingListener</b>
    ++(<code>OnFlingListener</code>)</A></nobr><br>
    ++<!-- Method setOnQueryTextListener -->
    ++<nobr><A HREF="android.support.v4.widget.SearchViewCompat.html#android.support.v4.widget.SearchViewCompat.setOnQueryTextListener_changed(android.view.View, android.support.v4.widget.SearchViewCompat.OnQueryTextListener)" class="hiddenlink" target="rightframe">setOnQueryTextListener
    ++(<code>View, OnQueryTextListener</code>)</A></nobr><br>
    ++<!-- Method setOverScrollMode -->
    ++<nobr><A HREF="android.support.v4.view.ViewCompat.html#android.support.v4.view.ViewCompat.setOverScrollMode_changed(android.view.View, int)" class="hiddenlink" target="rightframe">setOverScrollMode
    ++(<code>View, int</code>)</A></nobr><br>
    ++<!-- Method setPasswordVisibilityToggleContentDescription -->
    ++<i>setPasswordVisibilityToggleContentDescription</i><br>
    ++&nbsp;&nbsp;<nobr><A HREF="android.support.design.widget.TextInputLayout.html#android.support.design.widget.TextInputLayout.setPasswordVisibilityToggleContentDescription_added(int)" class="hiddenlink" target="rightframe">type&nbsp;<b>
    ++(<code>int</code>)</b>&nbsp;in&nbsp;android.support.design.widget.TextInputLayout
    ++</A></nobr><br>
    ++<!-- Method setPasswordVisibilityToggleContentDescription -->
    ++&nbsp;&nbsp;<nobr><A HREF="android.support.design.widget.TextInputLayout.html#android.support.design.widget.TextInputLayout.setPasswordVisibilityToggleContentDescription_added(java.lang.CharSequence)" class="hiddenlink" target="rightframe">type&nbsp;<b>
    ++(<code>CharSequence</code>)</b>&nbsp;in&nbsp;android.support.design.widget.TextInputLayout
    ++</A></nobr><br>
    ++<!-- Method setPasswordVisibilityToggleDrawable -->
    ++<i>setPasswordVisibilityToggleDrawable</i><br>
    ++&nbsp;&nbsp;<nobr><A HREF="android.support.design.widget.TextInputLayout.html#android.support.design.widget.TextInputLayout.setPasswordVisibilityToggleDrawable_added(android.graphics.drawable.Drawable)" class="hiddenlink" target="rightframe">type&nbsp;<b>
    ++(<code>Drawable</code>)</b>&nbsp;in&nbsp;android.support.design.widget.TextInputLayout
    ++</A></nobr><br>
    ++<!-- Method setPasswordVisibilityToggleDrawable -->
    ++&nbsp;&nbsp;<nobr><A HREF="android.support.design.widget.TextInputLayout.html#android.support.design.widget.TextInputLayout.setPasswordVisibilityToggleDrawable_added(int)" class="hiddenlink" target="rightframe">type&nbsp;<b>
    ++(<code>int</code>)</b>&nbsp;in&nbsp;android.support.design.widget.TextInputLayout
    ++</A></nobr><br>
    ++<!-- Method setPasswordVisibilityToggleEnabled -->
    ++<nobr><A HREF="android.support.design.widget.TextInputLayout.html#android.support.design.widget.TextInputLayout.setPasswordVisibilityToggleEnabled_added(boolean)" class="hiddenlink" target="rightframe"><b>setPasswordVisibilityToggleEnabled</b>
    ++(<code>boolean</code>)</A></nobr><br>
    ++<!-- Method setPasswordVisibilityToggleTintList -->
    ++<nobr><A HREF="android.support.design.widget.TextInputLayout.html#android.support.design.widget.TextInputLayout.setPasswordVisibilityToggleTintList_added(android.content.res.ColorStateList)" class="hiddenlink" target="rightframe"><b>setPasswordVisibilityToggleTintList</b>
    ++(<code>ColorStateList</code>)</A></nobr><br>
    ++<!-- Method setPasswordVisibilityToggleTintMode -->
    ++<nobr><A HREF="android.support.design.widget.TextInputLayout.html#android.support.design.widget.TextInputLayout.setPasswordVisibilityToggleTintMode_added(android.graphics.PorterDuff.Mode)" class="hiddenlink" target="rightframe"><b>setPasswordVisibilityToggleTintMode</b>
    ++(<code>Mode</code>)</A></nobr><br>
    ++<!-- Method setSecondaryToolbarViews -->
    ++<nobr><A HREF="android.support.customtabs.CustomTabsSession.html#android.support.customtabs.CustomTabsSession.setSecondaryToolbarViews_added(android.widget.RemoteViews, int[], android.app.PendingIntent)" class="hiddenlink" target="rightframe"><b>setSecondaryToolbarViews</b>
    ++(<code>RemoteViews, int[], PendingIntent</code>)</A></nobr><br>
    ++<!-- Method setSelectedMediaItemNumberView -->
    ++<nobr><A HREF="android.support.v17.leanback.widget.AbstractMediaItemPresenter.ViewHolder.html#android.support.v17.leanback.widget.AbstractMediaItemPresenter.ViewHolder.setSelectedMediaItemNumberView_added(int)" class="hiddenlink" target="rightframe"><b>setSelectedMediaItemNumberView</b>
    ++(<code>int</code>)</A></nobr><br>
    ++<!-- Method setToolbarItem -->
    ++<nobr><A HREF="android.support.customtabs.CustomTabsSession.html#android.support.customtabs.CustomTabsSession.setToolbarItem_changed(int, android.graphics.Bitmap, java.lang.String)" class="hiddenlink" target="rightframe">setToolbarItem
    ++(<code>int, Bitmap, String</code>)</A></nobr><br>
    ++<!-- Class ShareActionProvider -->
    ++<A HREF="pkg_android.support.v7.widget.html#ShareActionProvider" class="hiddenlink" target="rightframe"><b>ShareActionProvider</b></A><br>
    ++<!-- Class ShareActionProvider.OnShareTargetSelectedListener -->
    ++<A HREF="pkg_android.support.v7.widget.html#ShareActionProvider.OnShareTargetSelectedListener" class="hiddenlink" target="rightframe"><b><i>ShareActionProvider.OnShareTargetSelectedListener</i></b></A><br>
    ++<!-- Class SharedElementCallback -->
    ++<A HREF="android.support.v4.app.SharedElementCallback.html" class="hiddenlink" target="rightframe">SharedElementCallback</A><br>
    ++<!-- Class SharedElementCallback.OnSharedElementsReadyListener -->
    ++<A HREF="pkg_android.support.v4.app.html#SharedElementCallback.OnSharedElementsReadyListener" class="hiddenlink" target="rightframe"><b><i>SharedElementCallback.OnSharedElementsReadyListener</i></b></A><br>
    ++<!-- Method shouldAlwaysUseBrowserUI -->
    ++<nobr><A HREF="android.support.customtabs.CustomTabsIntent.html#android.support.customtabs.CustomTabsIntent.shouldAlwaysUseBrowserUI_added(android.content.Intent)" class="hiddenlink" target="rightframe"><b>shouldAlwaysUseBrowserUI</b>
    ++(<code>Intent</code>)</A></nobr><br>
    ++<!-- Class SnapHelper -->
    ++<A HREF="pkg_android.support.v7.widget.html#SnapHelper" class="hiddenlink" target="rightframe"><b>SnapHelper</b></A><br>
    ++<!-- Class SortedList.Callback -->
    ++<A HREF="android.support.v7.util.SortedList.Callback.html" class="hiddenlink" target="rightframe">SortedList.Callback</A><br>
    ++<!-- Class Space -->
    ++<A HREF="pkg_android.support.v7.widget.html#Space" class="hiddenlink" target="rightframe"><b>Space</b></A><br>
    ++<!-- Class StaggeredGridLayoutManager -->
    ++<A HREF="android.support.v7.widget.StaggeredGridLayoutManager.html" class="hiddenlink" target="rightframe">StaggeredGridLayoutManager</A><br>
    ++<!-- Method startTracking -->
    ++<nobr><A HREF="android.support.v4.view.KeyEventCompat.html#android.support.v4.view.KeyEventCompat.startTracking_changed(android.view.KeyEvent)" class="hiddenlink" target="rightframe">startTracking
    ++(<code>KeyEvent</code>)</A></nobr><br>
    ++<!-- Field STOP_FOREGROUND_DETACH -->
    ++<nobr><A HREF="android.support.v4.app.ServiceCompat.html#android.support.v4.app.ServiceCompat.STOP_FOREGROUND_DETACH" class="hiddenlink" target="rightframe">STOP_FOREGROUND_DETACH</A>
    ++</nobr><br>
    ++<!-- Field STOP_FOREGROUND_REMOVE -->
    ++<nobr><A HREF="android.support.v4.app.ServiceCompat.html#android.support.v4.app.ServiceCompat.STOP_FOREGROUND_REMOVE" class="hiddenlink" target="rightframe">STOP_FOREGROUND_REMOVE</A>
    ++</nobr><br>
    ++<!-- Method stopForeground -->
    ++<nobr><A HREF="android.support.v4.app.ServiceCompat.html#android.support.v4.app.ServiceCompat.stopForeground_added(android.app.Service, int)" class="hiddenlink" target="rightframe"><b>stopForeground</b>
    ++(<code>Service, int</code>)</A></nobr><br>
    ++<!-- Class SwipeRefreshLayout -->
    ++<A HREF="android.support.v4.widget.SwipeRefreshLayout.html" class="hiddenlink" target="rightframe">SwipeRefreshLayout</A><br>
    ++<!-- Class SwipeRefreshLayout.OnChildScrollUpCallback -->
    ++<A HREF="pkg_android.support.v4.widget.html#SwipeRefreshLayout.OnChildScrollUpCallback" class="hiddenlink" target="rightframe"><b><i>SwipeRefreshLayout.OnChildScrollUpCallback</i></b></A><br>
    ++<!-- Class SwitchCompat -->
    ++<A HREF="pkg_android.support.v7.widget.html#SwitchCompat" class="hiddenlink" target="rightframe"><b>SwitchCompat</b></A><br>
    ++<!-- Class TabLayout -->
    ++<A NAME="T"></A>
    ++<br><font size="+2">T</font>&nbsp;
    ++<a href="#A"><font size="-2">A</font></a> 
    ++<a href="#B"><font size="-2">B</font></a> 
    ++<a href="#C"><font size="-2">C</font></a> 
    ++<a href="#D"><font size="-2">D</font></a> 
    ++<a href="#E"><font size="-2">E</font></a> 
    ++<a href="#F"><font size="-2">F</font></a> 
    ++<a href="#G"><font size="-2">G</font></a> 
    ++<a href="#H"><font size="-2">H</font></a> 
    ++<a href="#I"><font size="-2">I</font></a> 
    ++<a href="#K"><font size="-2">K</font></a> 
    ++<a href="#L"><font size="-2">L</font></a> 
    ++<a href="#M"><font size="-2">M</font></a> 
    ++<a href="#N"><font size="-2">N</font></a> 
    ++<a href="#O"><font size="-2">O</font></a> 
    ++<a href="#P"><font size="-2">P</font></a> 
    ++<a href="#R"><font size="-2">R</font></a> 
    ++<a href="#S"><font size="-2">S</font></a> 
    ++<a href="#V"><font size="-2">V</font></a> 
    ++<a href="#W"><font size="-2">W</font></a> 
    ++ <a href="#topheader"><font size="-2">TOP</font></a>
    ++<p><div style="line-height:1.5em;color:black">
    ++<A HREF="android.support.design.widget.TabLayout.html" class="hiddenlink" target="rightframe">TabLayout</A><br>
    ++<!-- Field TAG -->
    ++<nobr><A HREF="android.support.v7.widget.StaggeredGridLayoutManager.html#android.support.v7.widget.StaggeredGridLayoutManager.TAG" class="hiddenlink" target="rightframe"><strike>TAG</strike></A>
    ++</nobr><br>
    ++<!-- Class TextInputLayout -->
    ++<A HREF="android.support.design.widget.TextInputLayout.html" class="hiddenlink" target="rightframe">TextInputLayout</A><br>
    ++<!-- Class TextViewCompat -->
    ++<A HREF="android.support.v4.widget.TextViewCompat.html" class="hiddenlink" target="rightframe">TextViewCompat</A><br>
    ++<!-- Class ThemedSpinnerAdapter -->
    ++<A HREF="pkg_android.support.v7.widget.html#ThemedSpinnerAdapter" class="hiddenlink" target="rightframe"><b><i>ThemedSpinnerAdapter</i></b></A><br>
    ++<!-- Class ThemedSpinnerAdapter.Helper -->
    ++<A HREF="pkg_android.support.v7.widget.html#ThemedSpinnerAdapter.Helper" class="hiddenlink" target="rightframe"><b>ThemedSpinnerAdapter.Helper</b></A><br>
    ++<!-- Method toKeyCode -->
    ++<nobr><A HREF="android.support.v4.media.session.PlaybackStateCompat.html#android.support.v4.media.session.PlaybackStateCompat.toKeyCode_added(long)" class="hiddenlink" target="rightframe"><b>toKeyCode</b>
    ++(<code>long</code>)</A></nobr><br>
    ++<!-- Class Toolbar -->
    ++<A HREF="pkg_android.support.v7.widget.html#Toolbar" class="hiddenlink" target="rightframe"><b>Toolbar</b></A><br>
    ++<!-- Class Toolbar.LayoutParams -->
    ++<A HREF="pkg_android.support.v7.widget.html#Toolbar.LayoutParams" class="hiddenlink" target="rightframe"><b>Toolbar.LayoutParams</b></A><br>
    ++<!-- Class Toolbar.OnMenuItemClickListener -->
    ++<A HREF="pkg_android.support.v7.widget.html#Toolbar.OnMenuItemClickListener" class="hiddenlink" target="rightframe"><b><i>Toolbar.OnMenuItemClickListener</i></b></A><br>
    ++<!-- Class Toolbar.SavedState -->
    ++<A HREF="pkg_android.support.v7.widget.html#Toolbar.SavedState" class="hiddenlink" target="rightframe"><b>Toolbar.SavedState</b></A><br>
    ++<!-- Field TYPE_ASSIST_READING_CONTEXT -->
    ++<nobr><A HREF="android.support.v4.view.accessibility.AccessibilityEventCompat.html#android.support.v4.view.accessibility.AccessibilityEventCompat.TYPE_ASSIST_READING_CONTEXT" class="hiddenlink" target="rightframe">TYPE_ASSIST_READING_CONTEXT</A>
    ++</nobr><br>
    ++<!-- Field TYPE_SPLIT_SCREEN_DIVIDER -->
    ++<nobr><A HREF="android.support.v4.view.accessibility.AccessibilityWindowInfoCompat.html#android.support.v4.view.accessibility.AccessibilityWindowInfoCompat.TYPE_SPLIT_SCREEN_DIVIDER" class="hiddenlink" target="rightframe">TYPE_SPLIT_SCREEN_DIVIDER</A>
    ++</nobr><br>
    ++<!-- Field TYPE_VIEW_CONTEXT_CLICKED -->
    ++<nobr><A HREF="android.support.v4.view.accessibility.AccessibilityEventCompat.html#android.support.v4.view.accessibility.AccessibilityEventCompat.TYPE_VIEW_CONTEXT_CLICKED" class="hiddenlink" target="rightframe">TYPE_VIEW_CONTEXT_CLICKED</A>
    ++</nobr><br>
    ++<!-- Field TYPE_WINDOWS_CHANGED -->
    ++<nobr><A HREF="android.support.v4.view.accessibility.AccessibilityEventCompat.html#android.support.v4.view.accessibility.AccessibilityEventCompat.TYPE_WINDOWS_CHANGED" class="hiddenlink" target="rightframe">TYPE_WINDOWS_CHANGED</A>
    ++</nobr><br>
    ++<!-- Class ViewCompat -->
    ++<A NAME="V"></A>
    ++<br><font size="+2">V</font>&nbsp;
    ++<a href="#A"><font size="-2">A</font></a> 
    ++<a href="#B"><font size="-2">B</font></a> 
    ++<a href="#C"><font size="-2">C</font></a> 
    ++<a href="#D"><font size="-2">D</font></a> 
    ++<a href="#E"><font size="-2">E</font></a> 
    ++<a href="#F"><font size="-2">F</font></a> 
    ++<a href="#G"><font size="-2">G</font></a> 
    ++<a href="#H"><font size="-2">H</font></a> 
    ++<a href="#I"><font size="-2">I</font></a> 
    ++<a href="#K"><font size="-2">K</font></a> 
    ++<a href="#L"><font size="-2">L</font></a> 
    ++<a href="#M"><font size="-2">M</font></a> 
    ++<a href="#N"><font size="-2">N</font></a> 
    ++<a href="#O"><font size="-2">O</font></a> 
    ++<a href="#P"><font size="-2">P</font></a> 
    ++<a href="#R"><font size="-2">R</font></a> 
    ++<a href="#S"><font size="-2">S</font></a> 
    ++<a href="#T"><font size="-2">T</font></a> 
    ++<a href="#W"><font size="-2">W</font></a> 
    ++ <a href="#topheader"><font size="-2">TOP</font></a>
    ++<p><div style="line-height:1.5em;color:black">
    ++<A HREF="android.support.v4.view.ViewCompat.html" class="hiddenlink" target="rightframe">ViewCompat</A><br>
    ++<!-- Class ViewConfigurationCompat -->
    ++<A HREF="android.support.v4.view.ViewConfigurationCompat.html" class="hiddenlink" target="rightframe">ViewConfigurationCompat</A><br>
    ++<!-- Class WindowInsetsCompat -->
    ++<A NAME="W"></A>
    ++<br><font size="+2">W</font>&nbsp;
    ++<a href="#A"><font size="-2">A</font></a> 
    ++<a href="#B"><font size="-2">B</font></a> 
    ++<a href="#C"><font size="-2">C</font></a> 
    ++<a href="#D"><font size="-2">D</font></a> 
    ++<a href="#E"><font size="-2">E</font></a> 
    ++<a href="#F"><font size="-2">F</font></a> 
    ++<a href="#G"><font size="-2">G</font></a> 
    ++<a href="#H"><font size="-2">H</font></a> 
    ++<a href="#I"><font size="-2">I</font></a> 
    ++<a href="#K"><font size="-2">K</font></a> 
    ++<a href="#L"><font size="-2">L</font></a> 
    ++<a href="#M"><font size="-2">M</font></a> 
    ++<a href="#N"><font size="-2">N</font></a> 
    ++<a href="#O"><font size="-2">O</font></a> 
    ++<a href="#P"><font size="-2">P</font></a> 
    ++<a href="#R"><font size="-2">R</font></a> 
    ++<a href="#S"><font size="-2">S</font></a> 
    ++<a href="#T"><font size="-2">T</font></a> 
    ++<a href="#V"><font size="-2">V</font></a> 
    ++ <a href="#topheader"><font size="-2">TOP</font></a>
    ++<p><div style="line-height:1.5em;color:black">
    ++<i>WindowInsetsCompat</i><br>
    ++&nbsp;&nbsp;<A HREF="android.support.v4.view.WindowInsetsCompat.html" class="hiddenlink" target="rightframe">android.support.v4.view</A><br>
    ++<!-- Constructor WindowInsetsCompat -->
    ++&nbsp;&nbsp;<nobr><A HREF="android.support.v4.view.WindowInsetsCompat.html#android.support.v4.view.WindowInsetsCompat.ctor_added(android.support.v4.view.WindowInsetsCompat)" class="hiddenlink" target="rightframe"><b>WindowInsetsCompat</b>
    ++(<code>WindowInsetsCompat</code>)</A></nobr>&nbsp;constructor<br>
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    ++</script>
    ++<script type="text/javascript">
    ++  try {
    ++    var pageTracker = _gat._getTracker("UA-5831155-1");
    ++    pageTracker._setAllowAnchor(true);
    ++    pageTracker._initData();
    ++    pageTracker._trackPageview();
    ++  } catch(e) {}
    ++</script>
    ++</BODY>
    ++</HTML>
    +diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/alldiffs_index_changes.html b/docs/html/sdk/support_api_diff/24.2.0/changes/alldiffs_index_changes.html
    +new file mode 100644
    +index 0000000..4718b46
    +--- /dev/null
    ++++ b/docs/html/sdk/support_api_diff/24.2.0/changes/alldiffs_index_changes.html
    +@@ -0,0 +1,666 @@
    ++<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
    ++<HTML style="overflow:auto;">
    ++<HEAD>
    ++<meta name="generator" content="JDiff v1.1.0">
    ++<!-- Generated by the JDiff Javadoc doclet -->
    ++<!-- (http://www.jdiff.org) -->
    ++<meta name="description" content="JDiff is a Javadoc doclet which generates an HTML report of all the packages, classes, constructors, methods, and fields which have been removed, added or changed in any way, including their documentation, when two APIs are compared.">
    ++<meta name="keywords" content="diff, jdiff, javadiff, java diff, java difference, API difference, difference between two APIs, API diff, Javadoc, doclet">
    ++<TITLE>
    ++All Changes Index
    ++</TITLE>
    ++<link href="../../../../assets/android-developer-docs.css" rel="stylesheet" type="text/css" />
    ++<link href="../stylesheet-jdiff.css" rel="stylesheet" type="text/css" />
    ++<noscript>
    ++<style type="text/css">
    ++body{overflow:auto;}
    ++#body-content{position:relative; top:0;}
    ++#doc-content{overflow:visible;border-left:3px solid #666;}
    ++#side-nav{padding:0;}
    ++#side-nav .toggle-list ul {display:block;}
    ++#resize-packages-nav{border-bottom:3px solid #666;}
    ++</style>
    ++</noscript>
    ++<style type="text/css">
    ++</style>
    ++</HEAD>
    ++<BODY class="gc-documentation" style="padding:12px;">
    ++<a NAME="topheader"></a>
    ++<table summary="Index for All Differences" width="100%" class="jdiffIndex" border="0" cellspacing="0" cellpadding="0" style="padding-bottom:0;margin-bottom:0;">
    ++  <tr>
    ++  <th class="indexHeader">
    ++    Filter the Index:
    ++  </th>
    ++  </tr>
    ++  <tr>
    ++  <td class="indexText" style="line-height:1.3em;padding-left:2em;">
    ++<a href="alldiffs_index_all.html" xclass="hiddenlink">All Differences</a>
    ++  <br>
    ++<A HREF="alldiffs_index_removals.html" xclass="hiddenlink">Removals</A>
    ++  <br>
    ++<A HREF="alldiffs_index_additions.html"xclass="hiddenlink">Additions</A>
    ++  <br>
    ++<b>Changes</b>
    ++  </td>
    ++  </tr>
    ++</table>
    ++<div id="indexTableCaption" style="background-color:#eee;padding:0 4px 0 4px;font-size:11px;margin-bottom:1em;">
    ++Listed as: <span style="color:#069"><strong>Added</strong></span>,  <span style="color:#069"><strike>Removed</strike></span>,  <span style="color:#069">Changed</span></font>
    ++</div>
    ++<!-- Class AbstractMediaItemPresenter -->
    ++<A NAME="A"></A>
    ++<br><font size="+2">A</font>&nbsp;
    ++<a href="#B"><font size="-2">B</font></a> 
    ++<a href="#C"><font size="-2">C</font></a> 
    ++<a href="#D"><font size="-2">D</font></a> 
    ++<a href="#F"><font size="-2">F</font></a> 
    ++<a href="#G"><font size="-2">G</font></a> 
    ++<a href="#I"><font size="-2">I</font></a> 
    ++<a href="#K"><font size="-2">K</font></a> 
    ++<a href="#L"><font size="-2">L</font></a> 
    ++<a href="#M"><font size="-2">M</font></a> 
    ++<a href="#O"><font size="-2">O</font></a> 
    ++<a href="#P"><font size="-2">P</font></a> 
    ++<a href="#R"><font size="-2">R</font></a> 
    ++<a href="#S"><font size="-2">S</font></a> 
    ++<a href="#T"><font size="-2">T</font></a> 
    ++<a href="#V"><font size="-2">V</font></a> 
    ++<a href="#W"><font size="-2">W</font></a> 
    ++ <a href="#topheader"><font size="-2">TOP</font></a>
    ++<p><div style="line-height:1.5em;color:black">
    ++<A HREF="android.support.v17.leanback.widget.AbstractMediaItemPresenter.html" class="hiddenlink" target="rightframe">AbstractMediaItemPresenter</A><br>
    ++<!-- Class AbstractMediaItemPresenter.ViewHolder -->
    ++<A HREF="android.support.v17.leanback.widget.AbstractMediaItemPresenter.ViewHolder.html" class="hiddenlink" target="rightframe">AbstractMediaItemPresenter.ViewHolder</A><br>
    ++<!-- Class AccessibilityEventCompat -->
    ++<A HREF="android.support.v4.view.accessibility.AccessibilityEventCompat.html" class="hiddenlink" target="rightframe">AccessibilityEventCompat</A><br>
    ++<!-- Class AccessibilityManagerCompat -->
    ++<A HREF="android.support.v4.view.accessibility.AccessibilityManagerCompat.html" class="hiddenlink" target="rightframe">AccessibilityManagerCompat</A><br>
    ++<!-- Class AccessibilityManagerCompat.AccessibilityStateChangeListenerCompat -->
    ++<A HREF="android.support.v4.view.accessibility.AccessibilityManagerCompat.AccessibilityStateChangeListenerCompat.html" class="hiddenlink" target="rightframe">AccessibilityManagerCompat.AccessibilityStateChangeListenerCompat</A><br>
    ++<!-- Class AccessibilityNodeInfoCompat -->
    ++<A HREF="android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.html" class="hiddenlink" target="rightframe">AccessibilityNodeInfoCompat</A><br>
    ++<!-- Class AccessibilityNodeInfoCompat.AccessibilityActionCompat -->
    ++<A HREF="android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat.html" class="hiddenlink" target="rightframe">AccessibilityNodeInfoCompat.AccessibilityActionCompat</A><br>
    ++<!-- Class AccessibilityNodeInfoCompat.CollectionInfoCompat -->
    ++<A HREF="android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.CollectionInfoCompat.html" class="hiddenlink" target="rightframe">AccessibilityNodeInfoCompat.CollectionInfoCompat</A><br>
    ++<!-- Class AccessibilityNodeInfoCompat.CollectionItemInfoCompat -->
    ++<A HREF="android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.CollectionItemInfoCompat.html" class="hiddenlink" target="rightframe">AccessibilityNodeInfoCompat.CollectionItemInfoCompat</A><br>
    ++<!-- Class AccessibilityNodeInfoCompat.RangeInfoCompat -->
    ++<A HREF="android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.RangeInfoCompat.html" class="hiddenlink" target="rightframe">AccessibilityNodeInfoCompat.RangeInfoCompat</A><br>
    ++<!-- Class AccessibilityNodeProviderCompat -->
    ++<A HREF="android.support.v4.view.accessibility.AccessibilityNodeProviderCompat.html" class="hiddenlink" target="rightframe">AccessibilityNodeProviderCompat</A><br>
    ++<!-- Class AccessibilityServiceInfoCompat -->
    ++<A HREF="android.support.v4.accessibilityservice.AccessibilityServiceInfoCompat.html" class="hiddenlink" target="rightframe">AccessibilityServiceInfoCompat</A><br>
    ++<!-- Class AccessibilityWindowInfoCompat -->
    ++<A HREF="android.support.v4.view.accessibility.AccessibilityWindowInfoCompat.html" class="hiddenlink" target="rightframe">AccessibilityWindowInfoCompat</A><br>
    ++<!-- Class ActionBarDrawerToggle -->
    ++<A HREF="android.support.v7.app.ActionBarDrawerToggle.html" class="hiddenlink" target="rightframe">ActionBarDrawerToggle</A><br>
    ++<!-- Class ActivityCompat -->
    ++<i>ActivityCompat</i><br>
    ++&nbsp;&nbsp;<A HREF="android.support.v4.app.ActivityCompat.html" class="hiddenlink" target="rightframe">android.support.v4.app</A><br>
    ++<!-- Constructor ActivityCompat -->
    ++&nbsp;&nbsp;<nobr><A HREF="android.support.v4.app.ActivityCompat.html#android.support.v4.app.ActivityCompat.ctor_changed()" class="hiddenlink" target="rightframe">ActivityCompat
    ++()</A></nobr>&nbsp;constructor<br>
    ++<!-- Class ActivityOptionsCompat -->
    ++<A HREF="android.support.v4.app.ActivityOptionsCompat.html" class="hiddenlink" target="rightframe">ActivityOptionsCompat</A><br>
    ++<!-- Method addAccessibilityStateChangeListener -->
    ++<nobr><A HREF="android.support.v4.view.accessibility.AccessibilityManagerCompat.html#android.support.v4.view.accessibility.AccessibilityManagerCompat.addAccessibilityStateChangeListener_changed(android.view.accessibility.AccessibilityManager, android.support.v4.view.accessibility.AccessibilityManagerCompat.AccessibilityStateChangeListener)" class="hiddenlink" target="rightframe">addAccessibilityStateChangeListener
    ++(<code>AccessibilityManager, AccessibilityStateChangeListener</code>)</A></nobr><br>
    ++<!-- Package android.support.customtabs -->
    ++<A HREF="pkg_android.support.customtabs.html" class="hiddenlink" target="rightframe">android.support.customtabs</A><br>
    ++<!-- Package android.support.design.widget -->
    ++<A HREF="pkg_android.support.design.widget.html" class="hiddenlink" target="rightframe">android.support.design.widget</A><br>
    ++<!-- Package android.support.v14.preference -->
    ++<A HREF="pkg_android.support.v14.preference.html" class="hiddenlink" target="rightframe">android.support.v14.preference</A><br>
    ++<!-- Package android.support.v17.leanback.widget -->
    ++<A HREF="pkg_android.support.v17.leanback.widget.html" class="hiddenlink" target="rightframe">android.support.v17.leanback.widget</A><br>
    ++<!-- Package android.support.v17.preference -->
    ++<A HREF="pkg_android.support.v17.preference.html" class="hiddenlink" target="rightframe">android.support.v17.preference</A><br>
    ++<!-- Package android.support.v4.accessibilityservice -->
    ++<A HREF="pkg_android.support.v4.accessibilityservice.html" class="hiddenlink" target="rightframe">android.support.v4.accessibilityservice</A><br>
    ++<!-- Package android.support.v4.app -->
    ++<A HREF="pkg_android.support.v4.app.html" class="hiddenlink" target="rightframe">android.support.v4.app</A><br>
    ++<!-- Package android.support.v4.content -->
    ++<A HREF="pkg_android.support.v4.content.html" class="hiddenlink" target="rightframe">android.support.v4.content</A><br>
    ++<!-- Package android.support.v4.graphics.drawable -->
    ++<A HREF="pkg_android.support.v4.graphics.drawable.html" class="hiddenlink" target="rightframe">android.support.v4.graphics.drawable</A><br>
    ++<!-- Package android.support.v4.media -->
    ++<A HREF="pkg_android.support.v4.media.html" class="hiddenlink" target="rightframe">android.support.v4.media</A><br>
    ++<!-- Package android.support.v4.media.session -->
    ++<A HREF="pkg_android.support.v4.media.session.html" class="hiddenlink" target="rightframe">android.support.v4.media.session</A><br>
    ++<!-- Package android.support.v4.os -->
    ++<A HREF="pkg_android.support.v4.os.html" class="hiddenlink" target="rightframe">android.support.v4.os</A><br>
    ++<!-- Package android.support.v4.util -->
    ++<A HREF="pkg_android.support.v4.util.html" class="hiddenlink" target="rightframe">android.support.v4.util</A><br>
    ++<!-- Package android.support.v4.view -->
    ++<A HREF="pkg_android.support.v4.view.html" class="hiddenlink" target="rightframe">android.support.v4.view</A><br>
    ++<!-- Package android.support.v4.view.accessibility -->
    ++<A HREF="pkg_android.support.v4.view.accessibility.html" class="hiddenlink" target="rightframe">android.support.v4.view.accessibility</A><br>
    ++<!-- Package android.support.v4.widget -->
    ++<A HREF="pkg_android.support.v4.widget.html" class="hiddenlink" target="rightframe">android.support.v4.widget</A><br>
    ++<!-- Package android.support.v7.app -->
    ++<A HREF="pkg_android.support.v7.app.html" class="hiddenlink" target="rightframe">android.support.v7.app</A><br>
    ++<!-- Package android.support.v7.content.res -->
    ++<A HREF="pkg_android.support.v7.content.res.html" class="hiddenlink" target="rightframe">android.support.v7.content.res</A><br>
    ++<!-- Package android.support.v7.graphics -->
    ++<A HREF="pkg_android.support.v7.graphics.html" class="hiddenlink" target="rightframe">android.support.v7.graphics</A><br>
    ++<!-- Package android.support.v7.preference -->
    ++<A HREF="pkg_android.support.v7.preference.html" class="hiddenlink" target="rightframe">android.support.v7.preference</A><br>
    ++<!-- Package android.support.v7.util -->
    ++<A HREF="pkg_android.support.v7.util.html" class="hiddenlink" target="rightframe">android.support.v7.util</A><br>
    ++<!-- Package android.support.v7.widget -->
    ++<A HREF="pkg_android.support.v7.widget.html" class="hiddenlink" target="rightframe">android.support.v7.widget</A><br>
    ++<!-- Class AppBarLayout.ScrollingViewBehavior -->
    ++<A HREF="android.support.design.widget.AppBarLayout.ScrollingViewBehavior.html" class="hiddenlink" target="rightframe">AppBarLayout.ScrollingViewBehavior</A><br>
    ++<!-- Class AppCompatDelegate -->
    ++<A HREF="android.support.v7.app.AppCompatDelegate.html" class="hiddenlink" target="rightframe">AppCompatDelegate</A><br>
    ++<!-- Class AppCompatResources -->
    ++<A HREF="android.support.v7.content.res.AppCompatResources.html" class="hiddenlink" target="rightframe">AppCompatResources</A><br>
    ++<!-- Class BottomSheetBehavior -->
    ++<A NAME="B"></A>
    ++<br><font size="+2">B</font>&nbsp;
    ++<a href="#A"><font size="-2">A</font></a> 
    ++<a href="#C"><font size="-2">C</font></a> 
    ++<a href="#D"><font size="-2">D</font></a> 
    ++<a href="#F"><font size="-2">F</font></a> 
    ++<a href="#G"><font size="-2">G</font></a> 
    ++<a href="#I"><font size="-2">I</font></a> 
    ++<a href="#K"><font size="-2">K</font></a> 
    ++<a href="#L"><font size="-2">L</font></a> 
    ++<a href="#M"><font size="-2">M</font></a> 
    ++<a href="#O"><font size="-2">O</font></a> 
    ++<a href="#P"><font size="-2">P</font></a> 
    ++<a href="#R"><font size="-2">R</font></a> 
    ++<a href="#S"><font size="-2">S</font></a> 
    ++<a href="#T"><font size="-2">T</font></a> 
    ++<a href="#V"><font size="-2">V</font></a> 
    ++<a href="#W"><font size="-2">W</font></a> 
    ++ <a href="#topheader"><font size="-2">TOP</font></a>
    ++<p><div style="line-height:1.5em;color:black">
    ++<A HREF="android.support.design.widget.BottomSheetBehavior.html" class="hiddenlink" target="rightframe">BottomSheetBehavior</A><br>
    ++<!-- Class BuildCompat -->
    ++<A HREF="android.support.v4.os.BuildCompat.html" class="hiddenlink" target="rightframe">BuildCompat</A><br>
    ++<!-- Class CollapsingToolbarLayout -->
    ++<A NAME="C"></A>
    ++<br><font size="+2">C</font>&nbsp;
    ++<a href="#A"><font size="-2">A</font></a> 
    ++<a href="#B"><font size="-2">B</font></a> 
    ++<a href="#D"><font size="-2">D</font></a> 
    ++<a href="#F"><font size="-2">F</font></a> 
    ++<a href="#G"><font size="-2">G</font></a> 
    ++<a href="#I"><font size="-2">I</font></a> 
    ++<a href="#K"><font size="-2">K</font></a> 
    ++<a href="#L"><font size="-2">L</font></a> 
    ++<a href="#M"><font size="-2">M</font></a> 
    ++<a href="#O"><font size="-2">O</font></a> 
    ++<a href="#P"><font size="-2">P</font></a> 
    ++<a href="#R"><font size="-2">R</font></a> 
    ++<a href="#S"><font size="-2">S</font></a> 
    ++<a href="#T"><font size="-2">T</font></a> 
    ++<a href="#V"><font size="-2">V</font></a> 
    ++<a href="#W"><font size="-2">W</font></a> 
    ++ <a href="#topheader"><font size="-2">TOP</font></a>
    ++<p><div style="line-height:1.5em;color:black">
    ++<A HREF="android.support.design.widget.CollapsingToolbarLayout.html" class="hiddenlink" target="rightframe">CollapsingToolbarLayout</A><br>
    ++<!-- Method computeScrollVectorForPosition -->
    ++<nobr><A HREF="android.support.v7.widget.LinearSmoothScroller.html#android.support.v7.widget.LinearSmoothScroller.computeScrollVectorForPosition_changed(int)" class="hiddenlink" target="rightframe">computeScrollVectorForPosition
    ++(<code>int</code>)</A></nobr><br>
    ++<!-- Class ContextCompat -->
    ++<i>ContextCompat</i><br>
    ++&nbsp;&nbsp;<A HREF="android.support.v4.content.ContextCompat.html" class="hiddenlink" target="rightframe">android.support.v4.content</A><br>
    ++<!-- Constructor ContextCompat -->
    ++&nbsp;&nbsp;<nobr><A HREF="android.support.v4.content.ContextCompat.html#android.support.v4.content.ContextCompat.ctor_changed()" class="hiddenlink" target="rightframe">ContextCompat
    ++()</A></nobr>&nbsp;constructor<br>
    ++<!-- Class CoordinatorLayout -->
    ++<A HREF="android.support.design.widget.CoordinatorLayout.html" class="hiddenlink" target="rightframe">CoordinatorLayout</A><br>
    ++<!-- Class CoordinatorLayout.Behavior -->
    ++<A HREF="android.support.design.widget.CoordinatorLayout.Behavior.html" class="hiddenlink" target="rightframe">CoordinatorLayout.Behavior</A><br>
    ++<!-- Class CoordinatorLayout.LayoutParams -->
    ++<A HREF="android.support.design.widget.CoordinatorLayout.LayoutParams.html" class="hiddenlink" target="rightframe">CoordinatorLayout.LayoutParams</A><br>
    ++<!-- Class CustomTabsIntent -->
    ++<A HREF="android.support.customtabs.CustomTabsIntent.html" class="hiddenlink" target="rightframe">CustomTabsIntent</A><br>
    ++<!-- Class CustomTabsIntent.Builder -->
    ++<A HREF="android.support.customtabs.CustomTabsIntent.Builder.html" class="hiddenlink" target="rightframe">CustomTabsIntent.Builder</A><br>
    ++<!-- Class CustomTabsSession -->
    ++<A HREF="android.support.customtabs.CustomTabsSession.html" class="hiddenlink" target="rightframe">CustomTabsSession</A><br>
    ++<!-- Method dispatch -->
    ++<A NAME="D"></A>
    ++<br><font size="+2">D</font>&nbsp;
    ++<a href="#A"><font size="-2">A</font></a> 
    ++<a href="#B"><font size="-2">B</font></a> 
    ++<a href="#C"><font size="-2">C</font></a> 
    ++<a href="#F"><font size="-2">F</font></a> 
    ++<a href="#G"><font size="-2">G</font></a> 
    ++<a href="#I"><font size="-2">I</font></a> 
    ++<a href="#K"><font size="-2">K</font></a> 
    ++<a href="#L"><font size="-2">L</font></a> 
    ++<a href="#M"><font size="-2">M</font></a> 
    ++<a href="#O"><font size="-2">O</font></a> 
    ++<a href="#P"><font size="-2">P</font></a> 
    ++<a href="#R"><font size="-2">R</font></a> 
    ++<a href="#S"><font size="-2">S</font></a> 
    ++<a href="#T"><font size="-2">T</font></a> 
    ++<a href="#V"><font size="-2">V</font></a> 
    ++<a href="#W"><font size="-2">W</font></a> 
    ++ <a href="#topheader"><font size="-2">TOP</font></a>
    ++<p><div style="line-height:1.5em;color:black">
    ++<nobr><A HREF="android.support.v4.view.KeyEventCompat.html#android.support.v4.view.KeyEventCompat.dispatch_changed(android.view.KeyEvent, android.view.KeyEvent.Callback, java.lang.Object, java.lang.Object)" class="hiddenlink" target="rightframe">dispatch
    ++(<code>KeyEvent, Callback, Object, Object</code>)</A></nobr><br>
    ++<!-- Class DrawableCompat -->
    ++<A HREF="android.support.v4.graphics.drawable.DrawableCompat.html" class="hiddenlink" target="rightframe">DrawableCompat</A><br>
    ++<!-- Method findPointerIndex -->
    ++<A NAME="F"></A>
    ++<br><font size="+2">F</font>&nbsp;
    ++<a href="#A"><font size="-2">A</font></a> 
    ++<a href="#B"><font size="-2">B</font></a> 
    ++<a href="#C"><font size="-2">C</font></a> 
    ++<a href="#D"><font size="-2">D</font></a> 
    ++<a href="#G"><font size="-2">G</font></a> 
    ++<a href="#I"><font size="-2">I</font></a> 
    ++<a href="#K"><font size="-2">K</font></a> 
    ++<a href="#L"><font size="-2">L</font></a> 
    ++<a href="#M"><font size="-2">M</font></a> 
    ++<a href="#O"><font size="-2">O</font></a> 
    ++<a href="#P"><font size="-2">P</font></a> 
    ++<a href="#R"><font size="-2">R</font></a> 
    ++<a href="#S"><font size="-2">S</font></a> 
    ++<a href="#T"><font size="-2">T</font></a> 
    ++<a href="#V"><font size="-2">V</font></a> 
    ++<a href="#W"><font size="-2">W</font></a> 
    ++ <a href="#topheader"><font size="-2">TOP</font></a>
    ++<p><div style="line-height:1.5em;color:black">
    ++<nobr><A HREF="android.support.v4.view.MotionEventCompat.html#android.support.v4.view.MotionEventCompat.findPointerIndex_changed(android.view.MotionEvent, int)" class="hiddenlink" target="rightframe">findPointerIndex
    ++(<code>MotionEvent, int</code>)</A></nobr><br>
    ++<!-- Class FloatingActionButton.Behavior -->
    ++<A HREF="android.support.design.widget.FloatingActionButton.Behavior.html" class="hiddenlink" target="rightframe">FloatingActionButton.Behavior</A><br>
    ++<!-- Class FragmentController -->
    ++<A HREF="android.support.v4.app.FragmentController.html" class="hiddenlink" target="rightframe">FragmentController</A><br>
    ++<!-- Method getDescription -->
    ++<A NAME="G"></A>
    ++<br><font size="+2">G</font>&nbsp;
    ++<a href="#A"><font size="-2">A</font></a> 
    ++<a href="#B"><font size="-2">B</font></a> 
    ++<a href="#C"><font size="-2">C</font></a> 
    ++<a href="#D"><font size="-2">D</font></a> 
    ++<a href="#F"><font size="-2">F</font></a> 
    ++<a href="#I"><font size="-2">I</font></a> 
    ++<a href="#K"><font size="-2">K</font></a> 
    ++<a href="#L"><font size="-2">L</font></a> 
    ++<a href="#M"><font size="-2">M</font></a> 
    ++<a href="#O"><font size="-2">O</font></a> 
    ++<a href="#P"><font size="-2">P</font></a> 
    ++<a href="#R"><font size="-2">R</font></a> 
    ++<a href="#S"><font size="-2">S</font></a> 
    ++<a href="#T"><font size="-2">T</font></a> 
    ++<a href="#V"><font size="-2">V</font></a> 
    ++<a href="#W"><font size="-2">W</font></a> 
    ++ <a href="#topheader"><font size="-2">TOP</font></a>
    ++<p><div style="line-height:1.5em;color:black">
    ++<nobr><A HREF="android.support.v4.accessibilityservice.AccessibilityServiceInfoCompat.html#android.support.v4.accessibilityservice.AccessibilityServiceInfoCompat.getDescription_changed(android.accessibilityservice.AccessibilityServiceInfo)" class="hiddenlink" target="rightframe">getDescription
    ++(<code>AccessibilityServiceInfo</code>)</A></nobr><br>
    ++<!-- Method getKeyDispatcherState -->
    ++<nobr><A HREF="android.support.v4.view.KeyEventCompat.html#android.support.v4.view.KeyEventCompat.getKeyDispatcherState_changed(android.view.View)" class="hiddenlink" target="rightframe">getKeyDispatcherState
    ++(<code>View</code>)</A></nobr><br>
    ++<!-- Method getOverScrollMode -->
    ++<nobr><A HREF="android.support.v4.view.ViewCompat.html#android.support.v4.view.ViewCompat.getOverScrollMode_changed(android.view.View)" class="hiddenlink" target="rightframe">getOverScrollMode
    ++(<code>View</code>)</A></nobr><br>
    ++<!-- Method getPointerCount -->
    ++<nobr><A HREF="android.support.v4.view.MotionEventCompat.html#android.support.v4.view.MotionEventCompat.getPointerCount_changed(android.view.MotionEvent)" class="hiddenlink" target="rightframe">getPointerCount
    ++(<code>MotionEvent</code>)</A></nobr><br>
    ++<!-- Method getPointerId -->
    ++<nobr><A HREF="android.support.v4.view.MotionEventCompat.html#android.support.v4.view.MotionEventCompat.getPointerId_changed(android.view.MotionEvent, int)" class="hiddenlink" target="rightframe">getPointerId
    ++(<code>MotionEvent, int</code>)</A></nobr><br>
    ++<!-- Method getReferrer -->
    ++<nobr><A HREF="android.support.v4.app.ActivityCompat.html#android.support.v4.app.ActivityCompat.getReferrer_changed(android.app.Activity)" class="hiddenlink" target="rightframe">getReferrer
    ++(<code>Activity</code>)</A></nobr><br>
    ++<!-- Method getScaledPagingTouchSlop -->
    ++<nobr><A HREF="android.support.v4.view.ViewConfigurationCompat.html#android.support.v4.view.ViewConfigurationCompat.getScaledPagingTouchSlop_changed(android.view.ViewConfiguration)" class="hiddenlink" target="rightframe">getScaledPagingTouchSlop
    ++(<code>ViewConfiguration</code>)</A></nobr><br>
    ++<!-- Method getSource -->
    ++<nobr><A HREF="android.support.v4.view.MotionEventCompat.html#android.support.v4.view.MotionEventCompat.getSource_changed(android.view.MotionEvent)" class="hiddenlink" target="rightframe">getSource
    ++(<code>MotionEvent</code>)</A></nobr><br>
    ++<!-- Method getX -->
    ++<nobr><A HREF="android.support.v4.view.MotionEventCompat.html#android.support.v4.view.MotionEventCompat.getX_changed(android.view.MotionEvent, int)" class="hiddenlink" target="rightframe">getX
    ++(<code>MotionEvent, int</code>)</A></nobr><br>
    ++<!-- Method getY -->
    ++<nobr><A HREF="android.support.v4.view.MotionEventCompat.html#android.support.v4.view.MotionEventCompat.getY_changed(android.view.MotionEvent, int)" class="hiddenlink" target="rightframe">getY
    ++(<code>MotionEvent, int</code>)</A></nobr><br>
    ++<!-- Method isDirty -->
    ++<A NAME="I"></A>
    ++<br><font size="+2">I</font>&nbsp;
    ++<a href="#A"><font size="-2">A</font></a> 
    ++<a href="#B"><font size="-2">B</font></a> 
    ++<a href="#C"><font size="-2">C</font></a> 
    ++<a href="#D"><font size="-2">D</font></a> 
    ++<a href="#F"><font size="-2">F</font></a> 
    ++<a href="#G"><font size="-2">G</font></a> 
    ++<a href="#K"><font size="-2">K</font></a> 
    ++<a href="#L"><font size="-2">L</font></a> 
    ++<a href="#M"><font size="-2">M</font></a> 
    ++<a href="#O"><font size="-2">O</font></a> 
    ++<a href="#P"><font size="-2">P</font></a> 
    ++<a href="#R"><font size="-2">R</font></a> 
    ++<a href="#S"><font size="-2">S</font></a> 
    ++<a href="#T"><font size="-2">T</font></a> 
    ++<a href="#V"><font size="-2">V</font></a> 
    ++<a href="#W"><font size="-2">W</font></a> 
    ++ <a href="#topheader"><font size="-2">TOP</font></a>
    ++<p><div style="line-height:1.5em;color:black">
    ++<nobr><A HREF="android.support.design.widget.CoordinatorLayout.Behavior.html#android.support.design.widget.CoordinatorLayout.Behavior.isDirty_changed(android.support.design.widget.CoordinatorLayout, V)" class="hiddenlink" target="rightframe">isDirty
    ++(<code>CoordinatorLayout, V</code>)</A></nobr><br>
    ++<!-- Method isOpaque -->
    ++<nobr><A HREF="android.support.v4.view.ViewCompat.html#android.support.v4.view.ViewCompat.isOpaque_changed(android.view.View)" class="hiddenlink" target="rightframe">isOpaque
    ++(<code>View</code>)</A></nobr><br>
    ++<!-- Method isTracking -->
    ++<nobr><A HREF="android.support.v4.view.KeyEventCompat.html#android.support.v4.view.KeyEventCompat.isTracking_changed(android.view.KeyEvent)" class="hiddenlink" target="rightframe">isTracking
    ++(<code>KeyEvent</code>)</A></nobr><br>
    ++<!-- Class KeyEventCompat -->
    ++<A NAME="K"></A>
    ++<br><font size="+2">K</font>&nbsp;
    ++<a href="#A"><font size="-2">A</font></a> 
    ++<a href="#B"><font size="-2">B</font></a> 
    ++<a href="#C"><font size="-2">C</font></a> 
    ++<a href="#D"><font size="-2">D</font></a> 
    ++<a href="#F"><font size="-2">F</font></a> 
    ++<a href="#G"><font size="-2">G</font></a> 
    ++<a href="#I"><font size="-2">I</font></a> 
    ++<a href="#L"><font size="-2">L</font></a> 
    ++<a href="#M"><font size="-2">M</font></a> 
    ++<a href="#O"><font size="-2">O</font></a> 
    ++<a href="#P"><font size="-2">P</font></a> 
    ++<a href="#R"><font size="-2">R</font></a> 
    ++<a href="#S"><font size="-2">S</font></a> 
    ++<a href="#T"><font size="-2">T</font></a> 
    ++<a href="#V"><font size="-2">V</font></a> 
    ++<a href="#W"><font size="-2">W</font></a> 
    ++ <a href="#topheader"><font size="-2">TOP</font></a>
    ++<p><div style="line-height:1.5em;color:black">
    ++<A HREF="android.support.v4.view.KeyEventCompat.html" class="hiddenlink" target="rightframe">KeyEventCompat</A><br>
    ++<!-- Class LeanbackSettingsFragment -->
    ++<A NAME="L"></A>
    ++<br><font size="+2">L</font>&nbsp;
    ++<a href="#A"><font size="-2">A</font></a> 
    ++<a href="#B"><font size="-2">B</font></a> 
    ++<a href="#C"><font size="-2">C</font></a> 
    ++<a href="#D"><font size="-2">D</font></a> 
    ++<a href="#F"><font size="-2">F</font></a> 
    ++<a href="#G"><font size="-2">G</font></a> 
    ++<a href="#I"><font size="-2">I</font></a> 
    ++<a href="#K"><font size="-2">K</font></a> 
    ++<a href="#M"><font size="-2">M</font></a> 
    ++<a href="#O"><font size="-2">O</font></a> 
    ++<a href="#P"><font size="-2">P</font></a> 
    ++<a href="#R"><font size="-2">R</font></a> 
    ++<a href="#S"><font size="-2">S</font></a> 
    ++<a href="#T"><font size="-2">T</font></a> 
    ++<a href="#V"><font size="-2">V</font></a> 
    ++<a href="#W"><font size="-2">W</font></a> 
    ++ <a href="#topheader"><font size="-2">TOP</font></a>
    ++<p><div style="line-height:1.5em;color:black">
    ++<A HREF="android.support.v17.preference.LeanbackSettingsFragment.html" class="hiddenlink" target="rightframe">LeanbackSettingsFragment</A><br>
    ++<!-- Class LinearLayoutManager -->
    ++<A HREF="android.support.v7.widget.LinearLayoutManager.html" class="hiddenlink" target="rightframe">LinearLayoutManager</A><br>
    ++<!-- Class LinearSmoothScroller -->
    ++<A HREF="android.support.v7.widget.LinearSmoothScroller.html" class="hiddenlink" target="rightframe">LinearSmoothScroller</A><br>
    ++<!-- Class MediaBrowserCompat.MediaItem -->
    ++<A NAME="M"></A>
    ++<br><font size="+2">M</font>&nbsp;
    ++<a href="#A"><font size="-2">A</font></a> 
    ++<a href="#B"><font size="-2">B</font></a> 
    ++<a href="#C"><font size="-2">C</font></a> 
    ++<a href="#D"><font size="-2">D</font></a> 
    ++<a href="#F"><font size="-2">F</font></a> 
    ++<a href="#G"><font size="-2">G</font></a> 
    ++<a href="#I"><font size="-2">I</font></a> 
    ++<a href="#K"><font size="-2">K</font></a> 
    ++<a href="#L"><font size="-2">L</font></a> 
    ++<a href="#O"><font size="-2">O</font></a> 
    ++<a href="#P"><font size="-2">P</font></a> 
    ++<a href="#R"><font size="-2">R</font></a> 
    ++<a href="#S"><font size="-2">S</font></a> 
    ++<a href="#T"><font size="-2">T</font></a> 
    ++<a href="#V"><font size="-2">V</font></a> 
    ++<a href="#W"><font size="-2">W</font></a> 
    ++ <a href="#topheader"><font size="-2">TOP</font></a>
    ++<p><div style="line-height:1.5em;color:black">
    ++<A HREF="android.support.v4.media.MediaBrowserCompat.MediaItem.html" class="hiddenlink" target="rightframe">MediaBrowserCompat.MediaItem</A><br>
    ++<!-- Class MediaBrowserServiceCompat.BrowserRoot -->
    ++<A HREF="android.support.v4.media.MediaBrowserServiceCompat.BrowserRoot.html" class="hiddenlink" target="rightframe">MediaBrowserServiceCompat.BrowserRoot</A><br>
    ++<!-- Class MediaButtonReceiver -->
    ++<A HREF="android.support.v4.media.session.MediaButtonReceiver.html" class="hiddenlink" target="rightframe">MediaButtonReceiver</A><br>
    ++<!-- Class MediaDescriptionCompat -->
    ++<A HREF="android.support.v4.media.MediaDescriptionCompat.html" class="hiddenlink" target="rightframe">MediaDescriptionCompat</A><br>
    ++<!-- Class MediaMetadataCompat -->
    ++<A HREF="android.support.v4.media.MediaMetadataCompat.html" class="hiddenlink" target="rightframe">MediaMetadataCompat</A><br>
    ++<!-- Class MediaSessionCompat -->
    ++<A HREF="android.support.v4.media.session.MediaSessionCompat.html" class="hiddenlink" target="rightframe">MediaSessionCompat</A><br>
    ++<!-- Class MediaSessionCompat.QueueItem -->
    ++<A HREF="android.support.v4.media.session.MediaSessionCompat.QueueItem.html" class="hiddenlink" target="rightframe">MediaSessionCompat.QueueItem</A><br>
    ++<!-- Class MotionEventCompat -->
    ++<A HREF="android.support.v4.view.MotionEventCompat.html" class="hiddenlink" target="rightframe">MotionEventCompat</A><br>
    ++<!-- Class ObjectAdapter -->
    ++<A NAME="O"></A>
    ++<br><font size="+2">O</font>&nbsp;
    ++<a href="#A"><font size="-2">A</font></a> 
    ++<a href="#B"><font size="-2">B</font></a> 
    ++<a href="#C"><font size="-2">C</font></a> 
    ++<a href="#D"><font size="-2">D</font></a> 
    ++<a href="#F"><font size="-2">F</font></a> 
    ++<a href="#G"><font size="-2">G</font></a> 
    ++<a href="#I"><font size="-2">I</font></a> 
    ++<a href="#K"><font size="-2">K</font></a> 
    ++<a href="#L"><font size="-2">L</font></a> 
    ++<a href="#M"><font size="-2">M</font></a> 
    ++<a href="#P"><font size="-2">P</font></a> 
    ++<a href="#R"><font size="-2">R</font></a> 
    ++<a href="#S"><font size="-2">S</font></a> 
    ++<a href="#T"><font size="-2">T</font></a> 
    ++<a href="#V"><font size="-2">V</font></a> 
    ++<a href="#W"><font size="-2">W</font></a> 
    ++ <a href="#topheader"><font size="-2">TOP</font></a>
    ++<p><div style="line-height:1.5em;color:black">
    ++<A HREF="android.support.v17.leanback.widget.ObjectAdapter.html" class="hiddenlink" target="rightframe">ObjectAdapter</A><br>
    ++<!-- Method obtain -->
    ++<i>obtain</i><br>
    ++&nbsp;&nbsp;<nobr><A HREF="android.support.v4.media.session.MediaSessionCompat.html#android.support.v4.media.session.MediaSessionCompat.obtain_changed(android.content.Context, java.lang.Object)" class="hiddenlink" target="rightframe">type&nbsp;
    ++(<code>Context, Object</code>)&nbsp;in&nbsp;android.support.v4.media.session.MediaSessionCompat
    ++</A></nobr><br>
    ++<!-- Method obtain -->
    ++&nbsp;&nbsp;<nobr><A HREF="android.support.v4.media.session.MediaSessionCompat.QueueItem.html#android.support.v4.media.session.MediaSessionCompat.QueueItem.obtain_changed(java.lang.Object)" class="hiddenlink" target="rightframe">type&nbsp;
    ++(<code>Object</code>)&nbsp;in&nbsp;android.support.v4.media.session.MediaSessionCompat.QueueItem
    ++</A></nobr><br>
    ++<!-- Field OVER_SCROLL_ALWAYS -->
    ++<nobr><A HREF="android.support.v4.view.ViewCompat.html#android.support.v4.view.ViewCompat.OVER_SCROLL_ALWAYS" class="hiddenlink" target="rightframe">OVER_SCROLL_ALWAYS</A>
    ++</nobr><br>
    ++<!-- Field OVER_SCROLL_IF_CONTENT_SCROLLS -->
    ++<nobr><A HREF="android.support.v4.view.ViewCompat.html#android.support.v4.view.ViewCompat.OVER_SCROLL_IF_CONTENT_SCROLLS" class="hiddenlink" target="rightframe">OVER_SCROLL_IF_CONTENT_SCROLLS</A>
    ++</nobr><br>
    ++<!-- Field OVER_SCROLL_NEVER -->
    ++<nobr><A HREF="android.support.v4.view.ViewCompat.html#android.support.v4.view.ViewCompat.OVER_SCROLL_NEVER" class="hiddenlink" target="rightframe">OVER_SCROLL_NEVER</A>
    ++</nobr><br>
    ++<!-- Class Palette -->
    ++<A NAME="P"></A>
    ++<br><font size="+2">P</font>&nbsp;
    ++<a href="#A"><font size="-2">A</font></a> 
    ++<a href="#B"><font size="-2">B</font></a> 
    ++<a href="#C"><font size="-2">C</font></a> 
    ++<a href="#D"><font size="-2">D</font></a> 
    ++<a href="#F"><font size="-2">F</font></a> 
    ++<a href="#G"><font size="-2">G</font></a> 
    ++<a href="#I"><font size="-2">I</font></a> 
    ++<a href="#K"><font size="-2">K</font></a> 
    ++<a href="#L"><font size="-2">L</font></a> 
    ++<a href="#M"><font size="-2">M</font></a> 
    ++<a href="#O"><font size="-2">O</font></a> 
    ++<a href="#R"><font size="-2">R</font></a> 
    ++<a href="#S"><font size="-2">S</font></a> 
    ++<a href="#T"><font size="-2">T</font></a> 
    ++<a href="#V"><font size="-2">V</font></a> 
    ++<a href="#W"><font size="-2">W</font></a> 
    ++ <a href="#topheader"><font size="-2">TOP</font></a>
    ++<p><div style="line-height:1.5em;color:black">
    ++<A HREF="android.support.v7.graphics.Palette.html" class="hiddenlink" target="rightframe">Palette</A><br>
    ++<!-- Class PlaybackStateCompat -->
    ++<A HREF="android.support.v4.media.session.PlaybackStateCompat.html" class="hiddenlink" target="rightframe">PlaybackStateCompat</A><br>
    ++<!-- Class PreferenceFragment -->
    ++<A HREF="android.support.v14.preference.PreferenceFragment.html" class="hiddenlink" target="rightframe">PreferenceFragment</A><br>
    ++<!-- Class RecyclerView -->
    ++<A NAME="R"></A>
    ++<br><font size="+2">R</font>&nbsp;
    ++<a href="#A"><font size="-2">A</font></a> 
    ++<a href="#B"><font size="-2">B</font></a> 
    ++<a href="#C"><font size="-2">C</font></a> 
    ++<a href="#D"><font size="-2">D</font></a> 
    ++<a href="#F"><font size="-2">F</font></a> 
    ++<a href="#G"><font size="-2">G</font></a> 
    ++<a href="#I"><font size="-2">I</font></a> 
    ++<a href="#K"><font size="-2">K</font></a> 
    ++<a href="#L"><font size="-2">L</font></a> 
    ++<a href="#M"><font size="-2">M</font></a> 
    ++<a href="#O"><font size="-2">O</font></a> 
    ++<a href="#P"><font size="-2">P</font></a> 
    ++<a href="#S"><font size="-2">S</font></a> 
    ++<a href="#T"><font size="-2">T</font></a> 
    ++<a href="#V"><font size="-2">V</font></a> 
    ++<a href="#W"><font size="-2">W</font></a> 
    ++ <a href="#topheader"><font size="-2">TOP</font></a>
    ++<p><div style="line-height:1.5em;color:black">
    ++<A HREF="android.support.v7.widget.RecyclerView.html" class="hiddenlink" target="rightframe">RecyclerView</A><br>
    ++<!-- Method removeAccessibilityStateChangeListener -->
    ++<nobr><A HREF="android.support.v4.view.accessibility.AccessibilityManagerCompat.html#android.support.v4.view.accessibility.AccessibilityManagerCompat.removeAccessibilityStateChangeListener_changed(android.view.accessibility.AccessibilityManager, android.support.v4.view.accessibility.AccessibilityManagerCompat.AccessibilityStateChangeListener)" class="hiddenlink" target="rightframe">removeAccessibilityStateChangeListener
    ++(<code>AccessibilityManager, AccessibilityStateChangeListener</code>)</A></nobr><br>
    ++<!-- Class SearchViewCompat -->
    ++<A NAME="S"></A>
    ++<br><font size="+2">S</font>&nbsp;
    ++<a href="#A"><font size="-2">A</font></a> 
    ++<a href="#B"><font size="-2">B</font></a> 
    ++<a href="#C"><font size="-2">C</font></a> 
    ++<a href="#D"><font size="-2">D</font></a> 
    ++<a href="#F"><font size="-2">F</font></a> 
    ++<a href="#G"><font size="-2">G</font></a> 
    ++<a href="#I"><font size="-2">I</font></a> 
    ++<a href="#K"><font size="-2">K</font></a> 
    ++<a href="#L"><font size="-2">L</font></a> 
    ++<a href="#M"><font size="-2">M</font></a> 
    ++<a href="#O"><font size="-2">O</font></a> 
    ++<a href="#P"><font size="-2">P</font></a> 
    ++<a href="#R"><font size="-2">R</font></a> 
    ++<a href="#T"><font size="-2">T</font></a> 
    ++<a href="#V"><font size="-2">V</font></a> 
    ++<a href="#W"><font size="-2">W</font></a> 
    ++ <a href="#topheader"><font size="-2">TOP</font></a>
    ++<p><div style="line-height:1.5em;color:black">
    ++<A HREF="android.support.v4.widget.SearchViewCompat.html" class="hiddenlink" target="rightframe">SearchViewCompat</A><br>
    ++<!-- Class SearchViewCompat.OnCloseListenerCompat -->
    ++<A HREF="android.support.v4.widget.SearchViewCompat.OnCloseListenerCompat.html" class="hiddenlink" target="rightframe">SearchViewCompat.OnCloseListenerCompat</A><br>
    ++<!-- Class SearchViewCompat.OnQueryTextListenerCompat -->
    ++<A HREF="android.support.v4.widget.SearchViewCompat.OnQueryTextListenerCompat.html" class="hiddenlink" target="rightframe">SearchViewCompat.OnQueryTextListenerCompat</A><br>
    ++<!-- Class ServiceCompat -->
    ++<A HREF="android.support.v4.app.ServiceCompat.html" class="hiddenlink" target="rightframe">ServiceCompat</A><br>
    ++<!-- Method setOnCloseListener -->
    ++<nobr><A HREF="android.support.v4.widget.SearchViewCompat.html#android.support.v4.widget.SearchViewCompat.setOnCloseListener_changed(android.view.View, android.support.v4.widget.SearchViewCompat.OnCloseListener)" class="hiddenlink" target="rightframe">setOnCloseListener
    ++(<code>View, OnCloseListener</code>)</A></nobr><br>
    ++<!-- Method setOnQueryTextListener -->
    ++<nobr><A HREF="android.support.v4.widget.SearchViewCompat.html#android.support.v4.widget.SearchViewCompat.setOnQueryTextListener_changed(android.view.View, android.support.v4.widget.SearchViewCompat.OnQueryTextListener)" class="hiddenlink" target="rightframe">setOnQueryTextListener
    ++(<code>View, OnQueryTextListener</code>)</A></nobr><br>
    ++<!-- Method setOverScrollMode -->
    ++<nobr><A HREF="android.support.v4.view.ViewCompat.html#android.support.v4.view.ViewCompat.setOverScrollMode_changed(android.view.View, int)" class="hiddenlink" target="rightframe">setOverScrollMode
    ++(<code>View, int</code>)</A></nobr><br>
    ++<!-- Method setToolbarItem -->
    ++<nobr><A HREF="android.support.customtabs.CustomTabsSession.html#android.support.customtabs.CustomTabsSession.setToolbarItem_changed(int, android.graphics.Bitmap, java.lang.String)" class="hiddenlink" target="rightframe">setToolbarItem
    ++(<code>int, Bitmap, String</code>)</A></nobr><br>
    ++<!-- Class SharedElementCallback -->
    ++<A HREF="android.support.v4.app.SharedElementCallback.html" class="hiddenlink" target="rightframe">SharedElementCallback</A><br>
    ++<!-- Class SortedList.Callback -->
    ++<A HREF="android.support.v7.util.SortedList.Callback.html" class="hiddenlink" target="rightframe">SortedList.Callback</A><br>
    ++<!-- Class StaggeredGridLayoutManager -->
    ++<A HREF="android.support.v7.widget.StaggeredGridLayoutManager.html" class="hiddenlink" target="rightframe">StaggeredGridLayoutManager</A><br>
    ++<!-- Method startTracking -->
    ++<nobr><A HREF="android.support.v4.view.KeyEventCompat.html#android.support.v4.view.KeyEventCompat.startTracking_changed(android.view.KeyEvent)" class="hiddenlink" target="rightframe">startTracking
    ++(<code>KeyEvent</code>)</A></nobr><br>
    ++<!-- Class SwipeRefreshLayout -->
    ++<A HREF="android.support.v4.widget.SwipeRefreshLayout.html" class="hiddenlink" target="rightframe">SwipeRefreshLayout</A><br>
    ++<!-- Class TabLayout -->
    ++<A NAME="T"></A>
    ++<br><font size="+2">T</font>&nbsp;
    ++<a href="#A"><font size="-2">A</font></a> 
    ++<a href="#B"><font size="-2">B</font></a> 
    ++<a href="#C"><font size="-2">C</font></a> 
    ++<a href="#D"><font size="-2">D</font></a> 
    ++<a href="#F"><font size="-2">F</font></a> 
    ++<a href="#G"><font size="-2">G</font></a> 
    ++<a href="#I"><font size="-2">I</font></a> 
    ++<a href="#K"><font size="-2">K</font></a> 
    ++<a href="#L"><font size="-2">L</font></a> 
    ++<a href="#M"><font size="-2">M</font></a> 
    ++<a href="#O"><font size="-2">O</font></a> 
    ++<a href="#P"><font size="-2">P</font></a> 
    ++<a href="#R"><font size="-2">R</font></a> 
    ++<a href="#S"><font size="-2">S</font></a> 
    ++<a href="#V"><font size="-2">V</font></a> 
    ++<a href="#W"><font size="-2">W</font></a> 
    ++ <a href="#topheader"><font size="-2">TOP</font></a>
    ++<p><div style="line-height:1.5em;color:black">
    ++<A HREF="android.support.design.widget.TabLayout.html" class="hiddenlink" target="rightframe">TabLayout</A><br>
    ++<!-- Class TextInputLayout -->
    ++<A HREF="android.support.design.widget.TextInputLayout.html" class="hiddenlink" target="rightframe">TextInputLayout</A><br>
    ++<!-- Class TextViewCompat -->
    ++<A HREF="android.support.v4.widget.TextViewCompat.html" class="hiddenlink" target="rightframe">TextViewCompat</A><br>
    ++<!-- Class ViewCompat -->
    ++<A NAME="V"></A>
    ++<br><font size="+2">V</font>&nbsp;
    ++<a href="#A"><font size="-2">A</font></a> 
    ++<a href="#B"><font size="-2">B</font></a> 
    ++<a href="#C"><font size="-2">C</font></a> 
    ++<a href="#D"><font size="-2">D</font></a> 
    ++<a href="#F"><font size="-2">F</font></a> 
    ++<a href="#G"><font size="-2">G</font></a> 
    ++<a href="#I"><font size="-2">I</font></a> 
    ++<a href="#K"><font size="-2">K</font></a> 
    ++<a href="#L"><font size="-2">L</font></a> 
    ++<a href="#M"><font size="-2">M</font></a> 
    ++<a href="#O"><font size="-2">O</font></a> 
    ++<a href="#P"><font size="-2">P</font></a> 
    ++<a href="#R"><font size="-2">R</font></a> 
    ++<a href="#S"><font size="-2">S</font></a> 
    ++<a href="#T"><font size="-2">T</font></a> 
    ++<a href="#W"><font size="-2">W</font></a> 
    ++ <a href="#topheader"><font size="-2">TOP</font></a>
    ++<p><div style="line-height:1.5em;color:black">
    ++<A HREF="android.support.v4.view.ViewCompat.html" class="hiddenlink" target="rightframe">ViewCompat</A><br>
    ++<!-- Class ViewConfigurationCompat -->
    ++<A HREF="android.support.v4.view.ViewConfigurationCompat.html" class="hiddenlink" target="rightframe">ViewConfigurationCompat</A><br>
    ++<!-- Class WindowInsetsCompat -->
    ++<A NAME="W"></A>
    ++<br><font size="+2">W</font>&nbsp;
    ++<a href="#A"><font size="-2">A</font></a> 
    ++<a href="#B"><font size="-2">B</font></a> 
    ++<a href="#C"><font size="-2">C</font></a> 
    ++<a href="#D"><font size="-2">D</font></a> 
    ++<a href="#F"><font size="-2">F</font></a> 
    ++<a href="#G"><font size="-2">G</font></a> 
    ++<a href="#I"><font size="-2">I</font></a> 
    ++<a href="#K"><font size="-2">K</font></a> 
    ++<a href="#L"><font size="-2">L</font></a> 
    ++<a href="#M"><font size="-2">M</font></a> 
    ++<a href="#O"><font size="-2">O</font></a> 
    ++<a href="#P"><font size="-2">P</font></a> 
    ++<a href="#R"><font size="-2">R</font></a> 
    ++<a href="#S"><font size="-2">S</font></a> 
    ++<a href="#T"><font size="-2">T</font></a> 
    ++<a href="#V"><font size="-2">V</font></a> 
    ++ <a href="#topheader"><font size="-2">TOP</font></a>
    ++<p><div style="line-height:1.5em;color:black">
    ++<A HREF="android.support.v4.view.WindowInsetsCompat.html" class="hiddenlink" target="rightframe">WindowInsetsCompat</A><br>
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    ++</script>
    ++<script type="text/javascript">
    ++  try {
    ++    var pageTracker = _gat._getTracker("UA-5831155-1");
    ++    pageTracker._setAllowAnchor(true);
    ++    pageTracker._initData();
    ++    pageTracker._trackPageview();
    ++  } catch(e) {}
    ++</script>
    ++</BODY>
    ++</HTML>
    +diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/alldiffs_index_removals.html b/docs/html/sdk/support_api_diff/24.2.0/changes/alldiffs_index_removals.html
    +new file mode 100644
    +index 0000000..179472a
    +--- /dev/null
    ++++ b/docs/html/sdk/support_api_diff/24.2.0/changes/alldiffs_index_removals.html
    +@@ -0,0 +1,124 @@
    ++<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
    ++<HTML style="overflow:auto;">
    ++<HEAD>
    ++<meta name="generator" content="JDiff v1.1.0">
    ++<!-- Generated by the JDiff Javadoc doclet -->
    ++<!-- (http://www.jdiff.org) -->
    ++<meta name="description" content="JDiff is a Javadoc doclet which generates an HTML report of all the packages, classes, constructors, methods, and fields which have been removed, added or changed in any way, including their documentation, when two APIs are compared.">
    ++<meta name="keywords" content="diff, jdiff, javadiff, java diff, java difference, API difference, difference between two APIs, API diff, Javadoc, doclet">
    ++<TITLE>
    ++All Removals Index
    ++</TITLE>
    ++<link href="../../../../assets/android-developer-docs.css" rel="stylesheet" type="text/css" />
    ++<link href="../stylesheet-jdiff.css" rel="stylesheet" type="text/css" />
    ++<noscript>
    ++<style type="text/css">
    ++body{overflow:auto;}
    ++#body-content{position:relative; top:0;}
    ++#doc-content{overflow:visible;border-left:3px solid #666;}
    ++#side-nav{padding:0;}
    ++#side-nav .toggle-list ul {display:block;}
    ++#resize-packages-nav{border-bottom:3px solid #666;}
    ++</style>
    ++</noscript>
    ++<style type="text/css">
    ++</style>
    ++</HEAD>
    ++<BODY class="gc-documentation" style="padding:12px;">
    ++<a NAME="topheader"></a>
    ++<table summary="Index for All Differences" width="100%" class="jdiffIndex" border="0" cellspacing="0" cellpadding="0" style="padding-bottom:0;margin-bottom:0;">
    ++  <tr>
    ++  <th class="indexHeader">
    ++    Filter the Index:
    ++  </th>
    ++  </tr>
    ++  <tr>
    ++  <td class="indexText" style="line-height:1.3em;padding-left:2em;">
    ++<a href="alldiffs_index_all.html" xclass="hiddenlink">All Differences</a>
    ++  <br>
    ++<b>Removals</b>
    ++  <br>
    ++<A HREF="alldiffs_index_additions.html"xclass="hiddenlink">Additions</A>
    ++  <br>
    ++<A HREF="alldiffs_index_changes.html"xclass="hiddenlink">Changes</A>
    ++  </td>
    ++  </tr>
    ++</table>
    ++<div id="indexTableCaption" style="background-color:#eee;padding:0 4px 0 4px;font-size:11px;margin-bottom:1em;">
    ++Listed as: <span style="color:#069"><strong>Added</strong></span>,  <span style="color:#069"><strike>Removed</strike></span>,  <span style="color:#069">Changed</span></font>
    ++</div>
    ++<!-- Package android.support.v7.appcompat -->
    ++<A NAME="A"></A>
    ++<A HREF="changes-summary.html#android.support.v7.appcompat" class="hiddenlink" target="rightframe"><strike>android.support.v7.appcompat</strike></A><br>
    ++<!-- Package android.support.v7.recyclerview -->
    ++<A HREF="changes-summary.html#android.support.v7.recyclerview" class="hiddenlink" target="rightframe"><strike>android.support.v7.recyclerview</strike></A><br>
    ++<!-- Package android.support.v8.renderscript -->
    ++<A HREF="changes-summary.html#android.support.v8.renderscript" class="hiddenlink" target="rightframe"><strike>android.support.v8.renderscript</strike></A><br>
    ++<!-- Method layoutDependsOn -->
    ++<A NAME="L"></A>
    ++<br><font size="+2">L</font>&nbsp;
    ++<a href="#A"><font size="-2">A</font></a> 
    ++<a href="#O"><font size="-2">O</font></a> 
    ++<a href="#P"><font size="-2">P</font></a> 
    ++<a href="#T"><font size="-2">T</font></a> 
    ++ <a href="#topheader"><font size="-2">TOP</font></a>
    ++<p><div style="line-height:1.5em;color:black">
    ++<nobr><A HREF="android.support.design.widget.FloatingActionButton.Behavior.html#android.support.design.widget.FloatingActionButton.Behavior.layoutDependsOn_removed(android.support.design.widget.CoordinatorLayout, android.support.design.widget.FloatingActionButton, android.view.View)" class="hiddenlink" target="rightframe"><strike>layoutDependsOn</strike>
    ++(<code>CoordinatorLayout, FloatingActionButton, View</code>)</A></nobr><br>
    ++<!-- Method onAccessibilityStateChanged -->
    ++<A NAME="O"></A>
    ++<br><font size="+2">O</font>&nbsp;
    ++<a href="#A"><font size="-2">A</font></a> 
    ++<a href="#L"><font size="-2">L</font></a> 
    ++<a href="#P"><font size="-2">P</font></a> 
    ++<a href="#T"><font size="-2">T</font></a> 
    ++ <a href="#topheader"><font size="-2">TOP</font></a>
    ++<p><div style="line-height:1.5em;color:black">
    ++<nobr><A HREF="android.support.v4.view.accessibility.AccessibilityManagerCompat.AccessibilityStateChangeListenerCompat.html#android.support.v4.view.accessibility.AccessibilityManagerCompat.AccessibilityStateChangeListenerCompat.onAccessibilityStateChanged_removed(boolean)" class="hiddenlink" target="rightframe"><strike>onAccessibilityStateChanged</strike>
    ++(<code>boolean</code>)</A></nobr><br>
    ++<!-- Method onDependentViewRemoved -->
    ++<nobr><A HREF="android.support.design.widget.FloatingActionButton.Behavior.html#android.support.design.widget.FloatingActionButton.Behavior.onDependentViewRemoved_removed(android.support.design.widget.CoordinatorLayout, android.support.design.widget.FloatingActionButton, android.view.View)" class="hiddenlink" target="rightframe"><strike>onDependentViewRemoved</strike>
    ++(<code>CoordinatorLayout, FloatingActionButton, View</code>)</A></nobr><br>
    ++<!-- Method onInserted -->
    ++<nobr><A HREF="android.support.v7.util.SortedList.Callback.html#android.support.v7.util.SortedList.Callback.onInserted_removed(int, int)" class="hiddenlink" target="rightframe"><strike>onInserted</strike>
    ++(<code>int, int</code>)</A></nobr><br>
    ++<!-- Method onMoved -->
    ++<nobr><A HREF="android.support.v7.util.SortedList.Callback.html#android.support.v7.util.SortedList.Callback.onMoved_removed(int, int)" class="hiddenlink" target="rightframe"><strike>onMoved</strike>
    ++(<code>int, int</code>)</A></nobr><br>
    ++<!-- Method onRemoved -->
    ++<nobr><A HREF="android.support.v7.util.SortedList.Callback.html#android.support.v7.util.SortedList.Callback.onRemoved_removed(int, int)" class="hiddenlink" target="rightframe"><strike>onRemoved</strike>
    ++(<code>int, int</code>)</A></nobr><br>
    ++<!-- Method prepareForDrop -->
    ++<A NAME="P"></A>
    ++<br><font size="+2">P</font>&nbsp;
    ++<a href="#A"><font size="-2">A</font></a> 
    ++<a href="#L"><font size="-2">L</font></a> 
    ++<a href="#O"><font size="-2">O</font></a> 
    ++<a href="#T"><font size="-2">T</font></a> 
    ++ <a href="#topheader"><font size="-2">TOP</font></a>
    ++<p><div style="line-height:1.5em;color:black">
    ++<nobr><A HREF="android.support.v7.widget.LinearLayoutManager.html#android.support.v7.widget.LinearLayoutManager.prepareForDrop_removed(android.view.View, android.view.View, int, int)" class="hiddenlink" target="rightframe"><strike>prepareForDrop</strike>
    ++(<code>View, View, int, int</code>)</A></nobr><br>
    ++<!-- Field TAG -->
    ++<A NAME="T"></A>
    ++<br><font size="+2">T</font>&nbsp;
    ++<a href="#A"><font size="-2">A</font></a> 
    ++<a href="#L"><font size="-2">L</font></a> 
    ++<a href="#O"><font size="-2">O</font></a> 
    ++<a href="#P"><font size="-2">P</font></a> 
    ++ <a href="#topheader"><font size="-2">TOP</font></a>
    ++<p><div style="line-height:1.5em;color:black">
    ++<nobr><A HREF="android.support.v7.widget.StaggeredGridLayoutManager.html#android.support.v7.widget.StaggeredGridLayoutManager.TAG" class="hiddenlink" target="rightframe"><strike>TAG</strike></A>
    ++</nobr><br>
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    ++</script>
    ++<script type="text/javascript">
    ++  try {
    ++    var pageTracker = _gat._getTracker("UA-5831155-1");
    ++    pageTracker._setAllowAnchor(true);
    ++    pageTracker._initData();
    ++    pageTracker._trackPageview();
    ++  } catch(e) {}
    ++</script>
    ++</BODY>
    ++</HTML>
    +diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.customtabs.CustomTabsIntent.Builder.html b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.customtabs.CustomTabsIntent.Builder.html
    +new file mode 100644
    +index 0000000..41ac368
    +--- /dev/null
    ++++ b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.customtabs.CustomTabsIntent.Builder.html
    +@@ -0,0 +1,122 @@
    ++<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
    ++<HTML style="overflow:auto;">
    ++<HEAD>
    ++<meta name="generator" content="JDiff v1.1.0">
    ++<!-- Generated by the JDiff Javadoc doclet -->
    ++<!-- (http://www.jdiff.org) -->
    ++<meta name="description" content="JDiff is a Javadoc doclet which generates an HTML report of all the packages, classes, constructors, methods, and fields which have been removed, added or changed in any way, including their documentation, when two APIs are compared.">
    ++<meta name="keywords" content="diff, jdiff, javadiff, java diff, java difference, API difference, difference between two APIs, API diff, Javadoc, doclet">
    ++<TITLE>
    ++android.support.customtabs.CustomTabsIntent.Builder
    ++</TITLE>
    ++<link href="../../../../assets/android-developer-docs.css" rel="stylesheet" type="text/css" />
    ++<link href="../stylesheet-jdiff.css" rel="stylesheet" type="text/css" />
    ++<noscript>
    ++<style type="text/css">
    ++body{overflow:auto;}
    ++#body-content{position:relative; top:0;}
    ++#doc-content{overflow:visible;border-left:3px solid #666;}
    ++#side-nav{padding:0;}
    ++#side-nav .toggle-list ul {display:block;}
    ++#resize-packages-nav{border-bottom:3px solid #666;}
    ++</style>
    ++</noscript>
    ++<style type="text/css">
    ++</style>
    ++</HEAD>
    ++<BODY>
    ++<!-- Start of nav bar -->
    ++<a name="top"></a>
    ++<div id="header" style="margin-bottom:0;padding-bottom:0;">
    ++<div id="headerLeft">
    ++<a href="../../../../index.html" tabindex="-1" target="_top"><img src="../../../../assets/images/bg_logo.png" alt="Android Developers" /></a>
    ++</div>
    ++  <div id="headerRight">
    ++  <div id="headerLinks">
    ++<!-- <img src="/assets/images/icon_world.jpg" alt="" /> -->
    ++<span class="text">
    ++<!-- &nbsp;<a href="#">English</a> | -->
    ++<nobr><a href="http://developer.android.com" target="_top">Android Developers</a> | <a href="http://www.android.com" target="_top">Android.com</a></nobr>
    ++</span>
    ++</div>
    ++  <div class="and-diff-id" style="margin-top:6px;margin-right:8px;">
    ++    <table class="diffspectable">
    ++      <tr>
    ++        <td colspan="2" class="diffspechead">API Diff Specification</td>
    ++      </tr>
    ++      <tr>
    ++        <td class="diffspec" style="padding-top:.25em">To Level:</td>
    ++        <td class="diffvaluenew" style="padding-top:.25em">24.2.0</td>
    ++      </tr>
    ++      <tr>
    ++        <td class="diffspec">From Level:</td>
    ++        <td class="diffvalueold">24.1.0</td>
    ++      </tr>
    ++      <tr>
    ++        <td class="diffspec">Generated</td>
    ++        <td class="diffvalue">2016.08.16 14:03</td>
    ++      </tr>
    ++    </table>
    ++    </div><!-- End and-diff-id -->
    ++  <div class="and-diff-id" style="margin-right:8px;">
    ++    <table class="diffspectable">
    ++      <tr>
    ++        <td class="diffspec" colspan="2"><a href="jdiff_statistics.html">Statistics</a>
    ++      </tr>
    ++    </table>
    ++  </div> <!-- End and-diff-id -->
    ++  </div> <!-- End headerRight -->
    ++  </div> <!-- End header -->
    ++<div id="body-content" xstyle="padding:12px;padding-right:18px;">
    ++<div id="doc-content" style="position:relative;">
    ++<div id="mainBodyFluid">
    ++<H2>
    ++Class android.support.customtabs.<A HREF="../../../../reference/android/support/customtabs/CustomTabsIntent.Builder.html" target="_top"><font size="+2"><code>CustomTabsIntent.Builder</code></font></A>
    ++</H2>
    ++<a NAME="constructors"></a>
    ++<a NAME="methods"></a>
    ++<p>
    ++<a NAME="Added"></a>
    ++<TABLE summary="Added Methods" WIDTH="100%">
    ++<TR>
    ++  <TH VALIGN="TOP" COLSPAN=2>Added Methods</FONT></TD>
    ++</TH>
    ++<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    ++  <TD VALIGN="TOP" WIDTH="25%">
    ++  <A NAME="android.support.customtabs.CustomTabsIntent.Builder.setInstantAppsEnabled_added(boolean)"></A>
    ++  <nobr><code>Builder</code>&nbsp;<A HREF="../../../../reference/android/support/customtabs/CustomTabsIntent.Builder.html#setInstantAppsEnabled(boolean)" target="_top"><code>setInstantAppsEnabled</code></A>(<code>boolean</code>)</nobr>
    ++  </TD>
    ++  <TD>&nbsp;</TD>
    ++</TR>
    ++</TABLE>
    ++&nbsp;
    ++<a NAME="fields"></a>
    ++      </div>	
    ++      <div id="footer">
    ++        <div id="copyright">
    ++        Except as noted, this content is licensed under 
    ++        <a href="http://creativecommons.org/licenses/by/2.5/"> Creative Commons Attribution 2.5</a>.
    ++        For details and restrictions, see the <a href="/license.html">Content License</a>.
    ++        </div>
    ++      <div id="footerlinks">
    ++      <p>
    ++        <a href="http://www.android.com/terms.html">Site Terms of Service</a> -
    ++        <a href="http://www.android.com/privacy.html">Privacy Policy</a> -
    ++        <a href="http://www.android.com/branding.html">Brand Guidelines</a>
    ++      </p>
    ++    </div>
    ++    </div> <!-- end footer -->
    ++    </div><!-- end doc-content -->
    ++    </div> <!-- end body-content --> 
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    ++</script>
    ++<script type="text/javascript">
    ++  try {
    ++    var pageTracker = _gat._getTracker("UA-5831155-1");
    ++    pageTracker._setAllowAnchor(true);
    ++    pageTracker._initData();
    ++    pageTracker._trackPageview();
    ++  } catch(e) {}
    ++</script>
    ++</BODY>
    ++</HTML>
    +diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.customtabs.CustomTabsIntent.html b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.customtabs.CustomTabsIntent.html
    +new file mode 100644
    +index 0000000..c4f0bfb
    +--- /dev/null
    ++++ b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.customtabs.CustomTabsIntent.html
    +@@ -0,0 +1,144 @@
    ++<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
    ++<HTML style="overflow:auto;">
    ++<HEAD>
    ++<meta name="generator" content="JDiff v1.1.0">
    ++<!-- Generated by the JDiff Javadoc doclet -->
    ++<!-- (http://www.jdiff.org) -->
    ++<meta name="description" content="JDiff is a Javadoc doclet which generates an HTML report of all the packages, classes, constructors, methods, and fields which have been removed, added or changed in any way, including their documentation, when two APIs are compared.">
    ++<meta name="keywords" content="diff, jdiff, javadiff, java diff, java difference, API difference, difference between two APIs, API diff, Javadoc, doclet">
    ++<TITLE>
    ++android.support.customtabs.CustomTabsIntent
    ++</TITLE>
    ++<link href="../../../../assets/android-developer-docs.css" rel="stylesheet" type="text/css" />
    ++<link href="../stylesheet-jdiff.css" rel="stylesheet" type="text/css" />
    ++<noscript>
    ++<style type="text/css">
    ++body{overflow:auto;}
    ++#body-content{position:relative; top:0;}
    ++#doc-content{overflow:visible;border-left:3px solid #666;}
    ++#side-nav{padding:0;}
    ++#side-nav .toggle-list ul {display:block;}
    ++#resize-packages-nav{border-bottom:3px solid #666;}
    ++</style>
    ++</noscript>
    ++<style type="text/css">
    ++</style>
    ++</HEAD>
    ++<BODY>
    ++<!-- Start of nav bar -->
    ++<a name="top"></a>
    ++<div id="header" style="margin-bottom:0;padding-bottom:0;">
    ++<div id="headerLeft">
    ++<a href="../../../../index.html" tabindex="-1" target="_top"><img src="../../../../assets/images/bg_logo.png" alt="Android Developers" /></a>
    ++</div>
    ++  <div id="headerRight">
    ++  <div id="headerLinks">
    ++<!-- <img src="/assets/images/icon_world.jpg" alt="" /> -->
    ++<span class="text">
    ++<!-- &nbsp;<a href="#">English</a> | -->
    ++<nobr><a href="http://developer.android.com" target="_top">Android Developers</a> | <a href="http://www.android.com" target="_top">Android.com</a></nobr>
    ++</span>
    ++</div>
    ++  <div class="and-diff-id" style="margin-top:6px;margin-right:8px;">
    ++    <table class="diffspectable">
    ++      <tr>
    ++        <td colspan="2" class="diffspechead">API Diff Specification</td>
    ++      </tr>
    ++      <tr>
    ++        <td class="diffspec" style="padding-top:.25em">To Level:</td>
    ++        <td class="diffvaluenew" style="padding-top:.25em">24.2.0</td>
    ++      </tr>
    ++      <tr>
    ++        <td class="diffspec">From Level:</td>
    ++        <td class="diffvalueold">24.1.0</td>
    ++      </tr>
    ++      <tr>
    ++        <td class="diffspec">Generated</td>
    ++        <td class="diffvalue">2016.08.16 14:03</td>
    ++      </tr>
    ++    </table>
    ++    </div><!-- End and-diff-id -->
    ++  <div class="and-diff-id" style="margin-right:8px;">
    ++    <table class="diffspectable">
    ++      <tr>
    ++        <td class="diffspec" colspan="2"><a href="jdiff_statistics.html">Statistics</a>
    ++      </tr>
    ++    </table>
    ++  </div> <!-- End and-diff-id -->
    ++  </div> <!-- End headerRight -->
    ++  </div> <!-- End header -->
    ++<div id="body-content" xstyle="padding:12px;padding-right:18px;">
    ++<div id="doc-content" style="position:relative;">
    ++<div id="mainBodyFluid">
    ++<H2>
    ++Class android.support.customtabs.<A HREF="../../../../reference/android/support/customtabs/CustomTabsIntent.html" target="_top"><font size="+2"><code>CustomTabsIntent</code></font></A>
    ++</H2>
    ++<a NAME="constructors"></a>
    ++<a NAME="methods"></a>
    ++<p>
    ++<a NAME="Added"></a>
    ++<TABLE summary="Added Methods" WIDTH="100%">
    ++<TR>
    ++  <TH VALIGN="TOP" COLSPAN=2>Added Methods</FONT></TD>
    ++</TH>
    ++<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    ++  <TD VALIGN="TOP" WIDTH="25%">
    ++  <A NAME="android.support.customtabs.CustomTabsIntent.setAlwaysUseBrowserUI_added(android.content.Intent)"></A>
    ++  <nobr><code>Intent</code>&nbsp;<A HREF="../../../../reference/android/support/customtabs/CustomTabsIntent.html#setAlwaysUseBrowserUI(android.content.Intent)" target="_top"><code>setAlwaysUseBrowserUI</code></A>(<code>Intent</code>)</nobr>
    ++  </TD>
    ++  <TD>&nbsp;</TD>
    ++</TR>
    ++<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    ++  <TD VALIGN="TOP" WIDTH="25%">
    ++  <A NAME="android.support.customtabs.CustomTabsIntent.shouldAlwaysUseBrowserUI_added(android.content.Intent)"></A>
    ++  <nobr><code>boolean</code>&nbsp;<A HREF="../../../../reference/android/support/customtabs/CustomTabsIntent.html#shouldAlwaysUseBrowserUI(android.content.Intent)" target="_top"><code>shouldAlwaysUseBrowserUI</code></A>(<code>Intent</code>)</nobr>
    ++  </TD>
    ++  <TD>&nbsp;</TD>
    ++</TR>
    ++</TABLE>
    ++&nbsp;
    ++<a NAME="fields"></a>
    ++<p>
    ++<a NAME="Added"></a>
    ++<TABLE summary="Added Fields" WIDTH="100%">
    ++<TR>
    ++  <TH VALIGN="TOP" COLSPAN=2>Added Fields</FONT></TD>
    ++</TH>
    ++<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    ++  <TD VALIGN="TOP" WIDTH="25%">
    ++  <A NAME="android.support.customtabs.CustomTabsIntent.EXTRA_ENABLE_INSTANT_APPS"></A>
    ++  <nobr><code>String</code>&nbsp;<A HREF="../../../../reference/android/support/customtabs/CustomTabsIntent.html#EXTRA_ENABLE_INSTANT_APPS" target="_top"><code>EXTRA_ENABLE_INSTANT_APPS</code></A></nobr>
    ++  </TD>
    ++  <TD>&nbsp;</TD>
    ++</TR>
    ++</TABLE>
    ++&nbsp;
    ++      </div>	
    ++      <div id="footer">
    ++        <div id="copyright">
    ++        Except as noted, this content is licensed under 
    ++        <a href="http://creativecommons.org/licenses/by/2.5/"> Creative Commons Attribution 2.5</a>.
    ++        For details and restrictions, see the <a href="/license.html">Content License</a>.
    ++        </div>
    ++      <div id="footerlinks">
    ++      <p>
    ++        <a href="http://www.android.com/terms.html">Site Terms of Service</a> -
    ++        <a href="http://www.android.com/privacy.html">Privacy Policy</a> -
    ++        <a href="http://www.android.com/branding.html">Brand Guidelines</a>
    ++      </p>
    ++    </div>
    ++    </div> <!-- end footer -->
    ++    </div><!-- end doc-content -->
    ++    </div> <!-- end body-content --> 
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    ++</script>
    ++<script type="text/javascript">
    ++  try {
    ++    var pageTracker = _gat._getTracker("UA-5831155-1");
    ++    pageTracker._setAllowAnchor(true);
    ++    pageTracker._initData();
    ++    pageTracker._trackPageview();
    ++  } catch(e) {}
    ++</script>
    ++</BODY>
    ++</HTML>
    +diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.customtabs.CustomTabsSession.html b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.customtabs.CustomTabsSession.html
    +new file mode 100644
    +index 0000000..1ccaab3
    +--- /dev/null
    ++++ b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.customtabs.CustomTabsSession.html
    +@@ -0,0 +1,140 @@
    ++<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
    ++<HTML style="overflow:auto;">
    ++<HEAD>
    ++<meta name="generator" content="JDiff v1.1.0">
    ++<!-- Generated by the JDiff Javadoc doclet -->
    ++<!-- (http://www.jdiff.org) -->
    ++<meta name="description" content="JDiff is a Javadoc doclet which generates an HTML report of all the packages, classes, constructors, methods, and fields which have been removed, added or changed in any way, including their documentation, when two APIs are compared.">
    ++<meta name="keywords" content="diff, jdiff, javadiff, java diff, java difference, API difference, difference between two APIs, API diff, Javadoc, doclet">
    ++<TITLE>
    ++android.support.customtabs.CustomTabsSession
    ++</TITLE>
    ++<link href="../../../../assets/android-developer-docs.css" rel="stylesheet" type="text/css" />
    ++<link href="../stylesheet-jdiff.css" rel="stylesheet" type="text/css" />
    ++<noscript>
    ++<style type="text/css">
    ++body{overflow:auto;}
    ++#body-content{position:relative; top:0;}
    ++#doc-content{overflow:visible;border-left:3px solid #666;}
    ++#side-nav{padding:0;}
    ++#side-nav .toggle-list ul {display:block;}
    ++#resize-packages-nav{border-bottom:3px solid #666;}
    ++</style>
    ++</noscript>
    ++<style type="text/css">
    ++</style>
    ++</HEAD>
    ++<BODY>
    ++<!-- Start of nav bar -->
    ++<a name="top"></a>
    ++<div id="header" style="margin-bottom:0;padding-bottom:0;">
    ++<div id="headerLeft">
    ++<a href="../../../../index.html" tabindex="-1" target="_top"><img src="../../../../assets/images/bg_logo.png" alt="Android Developers" /></a>
    ++</div>
    ++  <div id="headerRight">
    ++  <div id="headerLinks">
    ++<!-- <img src="/assets/images/icon_world.jpg" alt="" /> -->
    ++<span class="text">
    ++<!-- &nbsp;<a href="#">English</a> | -->
    ++<nobr><a href="http://developer.android.com" target="_top">Android Developers</a> | <a href="http://www.android.com" target="_top">Android.com</a></nobr>
    ++</span>
    ++</div>
    ++  <div class="and-diff-id" style="margin-top:6px;margin-right:8px;">
    ++    <table class="diffspectable">
    ++      <tr>
    ++        <td colspan="2" class="diffspechead">API Diff Specification</td>
    ++      </tr>
    ++      <tr>
    ++        <td class="diffspec" style="padding-top:.25em">To Level:</td>
    ++        <td class="diffvaluenew" style="padding-top:.25em">24.2.0</td>
    ++      </tr>
    ++      <tr>
    ++        <td class="diffspec">From Level:</td>
    ++        <td class="diffvalueold">24.1.0</td>
    ++      </tr>
    ++      <tr>
    ++        <td class="diffspec">Generated</td>
    ++        <td class="diffvalue">2016.08.16 14:03</td>
    ++      </tr>
    ++    </table>
    ++    </div><!-- End and-diff-id -->
    ++  <div class="and-diff-id" style="margin-right:8px;">
    ++    <table class="diffspectable">
    ++      <tr>
    ++        <td class="diffspec" colspan="2"><a href="jdiff_statistics.html">Statistics</a>
    ++      </tr>
    ++    </table>
    ++  </div> <!-- End and-diff-id -->
    ++  </div> <!-- End headerRight -->
    ++  </div> <!-- End header -->
    ++<div id="body-content" xstyle="padding:12px;padding-right:18px;">
    ++<div id="doc-content" style="position:relative;">
    ++<div id="mainBodyFluid">
    ++<H2>
    ++Class android.support.customtabs.<A HREF="../../../../reference/android/support/customtabs/CustomTabsSession.html" target="_top"><font size="+2"><code>CustomTabsSession</code></font></A>
    ++</H2>
    ++<a NAME="constructors"></a>
    ++<a NAME="methods"></a>
    ++<p>
    ++<a NAME="Added"></a>
    ++<TABLE summary="Added Methods" WIDTH="100%">
    ++<TR>
    ++  <TH VALIGN="TOP" COLSPAN=2>Added Methods</FONT></TD>
    ++</TH>
    ++<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    ++  <TD VALIGN="TOP" WIDTH="25%">
    ++  <A NAME="android.support.customtabs.CustomTabsSession.setSecondaryToolbarViews_added(android.widget.RemoteViews, int[], android.app.PendingIntent)"></A>
    ++  <nobr><code>boolean</code>&nbsp;<A HREF="../../../../reference/android/support/customtabs/CustomTabsSession.html#setSecondaryToolbarViews(android.widget.RemoteViews, int[], android.app.PendingIntent)" target="_top"><code>setSecondaryToolbarViews</code></A>(<code>RemoteViews,</nobr> int[]<nobr>,</nobr> PendingIntent<nobr><nobr></code>)</nobr>
    ++  </TD>
    ++  <TD>&nbsp;</TD>
    ++</TR>
    ++</TABLE>
    ++&nbsp;
    ++<p>
    ++<a NAME="Changed"></a>
    ++<TABLE summary="Changed Methods" WIDTH="100%">
    ++<TR>
    ++  <TH VALIGN="TOP" COLSPAN=3>Changed Methods</FONT></TD>
    ++</TH>
    ++<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    ++  <TD VALIGN="TOP" WIDTH="25%">
    ++  <A NAME="android.support.customtabs.CustomTabsSession.setToolbarItem_changed(int, android.graphics.Bitmap, java.lang.String)"></A>
    ++  <nobr><code>boolean</code>&nbsp;<A HREF="../../../../reference/android/support/customtabs/CustomTabsSession.html#setToolbarItem(int, android.graphics.Bitmap, java.lang.String)" target="_top"><code>setToolbarItem</code></A>(<code>int,</nobr> Bitmap<nobr>,</nobr> String<nobr><nobr></code>)  </nobr>
    ++  </TD>
    ++  <TD VALIGN="TOP" WIDTH="30%">
    ++<b>Now deprecated</b>.<br>
    ++  </TD>
    ++  <TD>&nbsp;</TD>
    ++</TR>
    ++</TABLE>
    ++&nbsp;
    ++<a NAME="fields"></a>
    ++      </div>	
    ++      <div id="footer">
    ++        <div id="copyright">
    ++        Except as noted, this content is licensed under 
    ++        <a href="http://creativecommons.org/licenses/by/2.5/"> Creative Commons Attribution 2.5</a>.
    ++        For details and restrictions, see the <a href="/license.html">Content License</a>.
    ++        </div>
    ++      <div id="footerlinks">
    ++      <p>
    ++        <a href="http://www.android.com/terms.html">Site Terms of Service</a> -
    ++        <a href="http://www.android.com/privacy.html">Privacy Policy</a> -
    ++        <a href="http://www.android.com/branding.html">Brand Guidelines</a>
    ++      </p>
    ++    </div>
    ++    </div> <!-- end footer -->
    ++    </div><!-- end doc-content -->
    ++    </div> <!-- end body-content --> 
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    ++</script>
    ++<script type="text/javascript">
    ++  try {
    ++    var pageTracker = _gat._getTracker("UA-5831155-1");
    ++    pageTracker._setAllowAnchor(true);
    ++    pageTracker._initData();
    ++    pageTracker._trackPageview();
    ++  } catch(e) {}
    ++</script>
    ++</BODY>
    ++</HTML>
    +diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.design.widget.AppBarLayout.ScrollingViewBehavior.html b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.design.widget.AppBarLayout.ScrollingViewBehavior.html
    +new file mode 100644
    +index 0000000..ad3dfd8
    +--- /dev/null
    ++++ b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.design.widget.AppBarLayout.ScrollingViewBehavior.html
    +@@ -0,0 +1,122 @@
    ++<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
    ++<HTML style="overflow:auto;">
    ++<HEAD>
    ++<meta name="generator" content="JDiff v1.1.0">
    ++<!-- Generated by the JDiff Javadoc doclet -->
    ++<!-- (http://www.jdiff.org) -->
    ++<meta name="description" content="JDiff is a Javadoc doclet which generates an HTML report of all the packages, classes, constructors, methods, and fields which have been removed, added or changed in any way, including their documentation, when two APIs are compared.">
    ++<meta name="keywords" content="diff, jdiff, javadiff, java diff, java difference, API difference, difference between two APIs, API diff, Javadoc, doclet">
    ++<TITLE>
    ++android.support.design.widget.AppBarLayout.ScrollingViewBehavior
    ++</TITLE>
    ++<link href="../../../../assets/android-developer-docs.css" rel="stylesheet" type="text/css" />
    ++<link href="../stylesheet-jdiff.css" rel="stylesheet" type="text/css" />
    ++<noscript>
    ++<style type="text/css">
    ++body{overflow:auto;}
    ++#body-content{position:relative; top:0;}
    ++#doc-content{overflow:visible;border-left:3px solid #666;}
    ++#side-nav{padding:0;}
    ++#side-nav .toggle-list ul {display:block;}
    ++#resize-packages-nav{border-bottom:3px solid #666;}
    ++</style>
    ++</noscript>
    ++<style type="text/css">
    ++</style>
    ++</HEAD>
    ++<BODY>
    ++<!-- Start of nav bar -->
    ++<a name="top"></a>
    ++<div id="header" style="margin-bottom:0;padding-bottom:0;">
    ++<div id="headerLeft">
    ++<a href="../../../../index.html" tabindex="-1" target="_top"><img src="../../../../assets/images/bg_logo.png" alt="Android Developers" /></a>
    ++</div>
    ++  <div id="headerRight">
    ++  <div id="headerLinks">
    ++<!-- <img src="/assets/images/icon_world.jpg" alt="" /> -->
    ++<span class="text">
    ++<!-- &nbsp;<a href="#">English</a> | -->
    ++<nobr><a href="http://developer.android.com" target="_top">Android Developers</a> | <a href="http://www.android.com" target="_top">Android.com</a></nobr>
    ++</span>
    ++</div>
    ++  <div class="and-diff-id" style="margin-top:6px;margin-right:8px;">
    ++    <table class="diffspectable">
    ++      <tr>
    ++        <td colspan="2" class="diffspechead">API Diff Specification</td>
    ++      </tr>
    ++      <tr>
    ++        <td class="diffspec" style="padding-top:.25em">To Level:</td>
    ++        <td class="diffvaluenew" style="padding-top:.25em">24.2.0</td>
    ++      </tr>
    ++      <tr>
    ++        <td class="diffspec">From Level:</td>
    ++        <td class="diffvalueold">24.1.0</td>
    ++      </tr>
    ++      <tr>
    ++        <td class="diffspec">Generated</td>
    ++        <td class="diffvalue">2016.08.16 14:03</td>
    ++      </tr>
    ++    </table>
    ++    </div><!-- End and-diff-id -->
    ++  <div class="and-diff-id" style="margin-right:8px;">
    ++    <table class="diffspectable">
    ++      <tr>
    ++        <td class="diffspec" colspan="2"><a href="jdiff_statistics.html">Statistics</a>
    ++      </tr>
    ++    </table>
    ++  </div> <!-- End and-diff-id -->
    ++  </div> <!-- End headerRight -->
    ++  </div> <!-- End header -->
    ++<div id="body-content" xstyle="padding:12px;padding-right:18px;">
    ++<div id="doc-content" style="position:relative;">
    ++<div id="mainBodyFluid">
    ++<H2>
    ++Class android.support.design.widget.<A HREF="../../../../reference/android/support/design/widget/AppBarLayout.ScrollingViewBehavior.html" target="_top"><font size="+2"><code>AppBarLayout.ScrollingViewBehavior</code></font></A>
    ++</H2>
    ++<a NAME="constructors"></a>
    ++<a NAME="methods"></a>
    ++<p>
    ++<a NAME="Added"></a>
    ++<TABLE summary="Added Methods" WIDTH="100%">
    ++<TR>
    ++  <TH VALIGN="TOP" COLSPAN=2>Added Methods</FONT></TD>
    ++</TH>
    ++<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    ++  <TD VALIGN="TOP" WIDTH="25%">
    ++  <A NAME="android.support.design.widget.AppBarLayout.ScrollingViewBehavior.onRequestChildRectangleOnScreen_added(android.support.design.widget.CoordinatorLayout, android.view.View, android.graphics.Rect, boolean)"></A>
    ++  <nobr><code>boolean</code>&nbsp;<A HREF="../../../../reference/android/support/design/widget/AppBarLayout.ScrollingViewBehavior.html#onRequestChildRectangleOnScreen(android.support.design.widget.CoordinatorLayout, android.view.View, android.graphics.Rect, boolean)" target="_top"><code>onRequestChildRectangleOnScreen</code></A>(<code>CoordinatorLayout,</nobr> View<nobr>,</nobr> Rect<nobr>,</nobr> boolean<nobr><nobr></code>)</nobr>
    ++  </TD>
    ++  <TD>&nbsp;</TD>
    ++</TR>
    ++</TABLE>
    ++&nbsp;
    ++<a NAME="fields"></a>
    ++      </div>	
    ++      <div id="footer">
    ++        <div id="copyright">
    ++        Except as noted, this content is licensed under 
    ++        <a href="http://creativecommons.org/licenses/by/2.5/"> Creative Commons Attribution 2.5</a>.
    ++        For details and restrictions, see the <a href="/license.html">Content License</a>.
    ++        </div>
    ++      <div id="footerlinks">
    ++      <p>
    ++        <a href="http://www.android.com/terms.html">Site Terms of Service</a> -
    ++        <a href="http://www.android.com/privacy.html">Privacy Policy</a> -
    ++        <a href="http://www.android.com/branding.html">Brand Guidelines</a>
    ++      </p>
    ++    </div>
    ++    </div> <!-- end footer -->
    ++    </div><!-- end doc-content -->
    ++    </div> <!-- end body-content --> 
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    ++</script>
    ++<script type="text/javascript">
    ++  try {
    ++    var pageTracker = _gat._getTracker("UA-5831155-1");
    ++    pageTracker._setAllowAnchor(true);
    ++    pageTracker._initData();
    ++    pageTracker._trackPageview();
    ++  } catch(e) {}
    ++</script>
    ++</BODY>
    ++</HTML>
    +diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.design.widget.BottomSheetBehavior.html b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.design.widget.BottomSheetBehavior.html
    +new file mode 100644
    +index 0000000..22984b8
    +--- /dev/null
    ++++ b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.design.widget.BottomSheetBehavior.html
    +@@ -0,0 +1,122 @@
    ++<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
    ++<HTML style="overflow:auto;">
    ++<HEAD>
    ++<meta name="generator" content="JDiff v1.1.0">
    ++<!-- Generated by the JDiff Javadoc doclet -->
    ++<!-- (http://www.jdiff.org) -->
    ++<meta name="description" content="JDiff is a Javadoc doclet which generates an HTML report of all the packages, classes, constructors, methods, and fields which have been removed, added or changed in any way, including their documentation, when two APIs are compared.">
    ++<meta name="keywords" content="diff, jdiff, javadiff, java diff, java difference, API difference, difference between two APIs, API diff, Javadoc, doclet">
    ++<TITLE>
    ++android.support.design.widget.BottomSheetBehavior
    ++</TITLE>
    ++<link href="../../../../assets/android-developer-docs.css" rel="stylesheet" type="text/css" />
    ++<link href="../stylesheet-jdiff.css" rel="stylesheet" type="text/css" />
    ++<noscript>
    ++<style type="text/css">
    ++body{overflow:auto;}
    ++#body-content{position:relative; top:0;}
    ++#doc-content{overflow:visible;border-left:3px solid #666;}
    ++#side-nav{padding:0;}
    ++#side-nav .toggle-list ul {display:block;}
    ++#resize-packages-nav{border-bottom:3px solid #666;}
    ++</style>
    ++</noscript>
    ++<style type="text/css">
    ++</style>
    ++</HEAD>
    ++<BODY>
    ++<!-- Start of nav bar -->
    ++<a name="top"></a>
    ++<div id="header" style="margin-bottom:0;padding-bottom:0;">
    ++<div id="headerLeft">
    ++<a href="../../../../index.html" tabindex="-1" target="_top"><img src="../../../../assets/images/bg_logo.png" alt="Android Developers" /></a>
    ++</div>
    ++  <div id="headerRight">
    ++  <div id="headerLinks">
    ++<!-- <img src="/assets/images/icon_world.jpg" alt="" /> -->
    ++<span class="text">
    ++<!-- &nbsp;<a href="#">English</a> | -->
    ++<nobr><a href="http://developer.android.com" target="_top">Android Developers</a> | <a href="http://www.android.com" target="_top">Android.com</a></nobr>
    ++</span>
    ++</div>
    ++  <div class="and-diff-id" style="margin-top:6px;margin-right:8px;">
    ++    <table class="diffspectable">
    ++      <tr>
    ++        <td colspan="2" class="diffspechead">API Diff Specification</td>
    ++      </tr>
    ++      <tr>
    ++        <td class="diffspec" style="padding-top:.25em">To Level:</td>
    ++        <td class="diffvaluenew" style="padding-top:.25em">24.2.0</td>
    ++      </tr>
    ++      <tr>
    ++        <td class="diffspec">From Level:</td>
    ++        <td class="diffvalueold">24.1.0</td>
    ++      </tr>
    ++      <tr>
    ++        <td class="diffspec">Generated</td>
    ++        <td class="diffvalue">2016.08.16 14:03</td>
    ++      </tr>
    ++    </table>
    ++    </div><!-- End and-diff-id -->
    ++  <div class="and-diff-id" style="margin-right:8px;">
    ++    <table class="diffspectable">
    ++      <tr>
    ++        <td class="diffspec" colspan="2"><a href="jdiff_statistics.html">Statistics</a>
    ++      </tr>
    ++    </table>
    ++  </div> <!-- End and-diff-id -->
    ++  </div> <!-- End headerRight -->
    ++  </div> <!-- End header -->
    ++<div id="body-content" xstyle="padding:12px;padding-right:18px;">
    ++<div id="doc-content" style="position:relative;">
    ++<div id="mainBodyFluid">
    ++<H2>
    ++Class android.support.design.widget.<A HREF="../../../../reference/android/support/design/widget/BottomSheetBehavior.html" target="_top"><font size="+2"><code>BottomSheetBehavior</code></font></A>
    ++</H2>
    ++<a NAME="constructors"></a>
    ++<a NAME="methods"></a>
    ++<a NAME="fields"></a>
    ++<p>
    ++<a NAME="Added"></a>
    ++<TABLE summary="Added Fields" WIDTH="100%">
    ++<TR>
    ++  <TH VALIGN="TOP" COLSPAN=2>Added Fields</FONT></TD>
    ++</TH>
    ++<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    ++  <TD VALIGN="TOP" WIDTH="25%">
    ++  <A NAME="android.support.design.widget.BottomSheetBehavior.PEEK_HEIGHT_AUTO"></A>
    ++  <nobr><code>int</code>&nbsp;<A HREF="../../../../reference/android/support/design/widget/BottomSheetBehavior.html#PEEK_HEIGHT_AUTO" target="_top"><code>PEEK_HEIGHT_AUTO</code></A></nobr>
    ++  </TD>
    ++  <TD>&nbsp;</TD>
    ++</TR>
    ++</TABLE>
    ++&nbsp;
    ++      </div>	
    ++      <div id="footer">
    ++        <div id="copyright">
    ++        Except as noted, this content is licensed under 
    ++        <a href="http://creativecommons.org/licenses/by/2.5/"> Creative Commons Attribution 2.5</a>.
    ++        For details and restrictions, see the <a href="/license.html">Content License</a>.
    ++        </div>
    ++      <div id="footerlinks">
    ++      <p>
    ++        <a href="http://www.android.com/terms.html">Site Terms of Service</a> -
    ++        <a href="http://www.android.com/privacy.html">Privacy Policy</a> -
    ++        <a href="http://www.android.com/branding.html">Brand Guidelines</a>
    ++      </p>
    ++    </div>
    ++    </div> <!-- end footer -->
    ++    </div><!-- end doc-content -->
    ++    </div> <!-- end body-content --> 
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    ++</script>
    ++<script type="text/javascript">
    ++  try {
    ++    var pageTracker = _gat._getTracker("UA-5831155-1");
    ++    pageTracker._setAllowAnchor(true);
    ++    pageTracker._initData();
    ++    pageTracker._trackPageview();
    ++  } catch(e) {}
    ++</script>
    ++</BODY>
    ++</HTML>
    +diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.design.widget.CollapsingToolbarLayout.html b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.design.widget.CollapsingToolbarLayout.html
    +new file mode 100644
    +index 0000000..a20a1ed
    +--- /dev/null
    ++++ b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.design.widget.CollapsingToolbarLayout.html
    +@@ -0,0 +1,129 @@
    ++<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
    ++<HTML style="overflow:auto;">
    ++<HEAD>
    ++<meta name="generator" content="JDiff v1.1.0">
    ++<!-- Generated by the JDiff Javadoc doclet -->
    ++<!-- (http://www.jdiff.org) -->
    ++<meta name="description" content="JDiff is a Javadoc doclet which generates an HTML report of all the packages, classes, constructors, methods, and fields which have been removed, added or changed in any way, including their documentation, when two APIs are compared.">
    ++<meta name="keywords" content="diff, jdiff, javadiff, java diff, java difference, API difference, difference between two APIs, API diff, Javadoc, doclet">
    ++<TITLE>
    ++android.support.design.widget.CollapsingToolbarLayout
    ++</TITLE>
    ++<link href="../../../../assets/android-developer-docs.css" rel="stylesheet" type="text/css" />
    ++<link href="../stylesheet-jdiff.css" rel="stylesheet" type="text/css" />
    ++<noscript>
    ++<style type="text/css">
    ++body{overflow:auto;}
    ++#body-content{position:relative; top:0;}
    ++#doc-content{overflow:visible;border-left:3px solid #666;}
    ++#side-nav{padding:0;}
    ++#side-nav .toggle-list ul {display:block;}
    ++#resize-packages-nav{border-bottom:3px solid #666;}
    ++</style>
    ++</noscript>
    ++<style type="text/css">
    ++</style>
    ++</HEAD>
    ++<BODY>
    ++<!-- Start of nav bar -->
    ++<a name="top"></a>
    ++<div id="header" style="margin-bottom:0;padding-bottom:0;">
    ++<div id="headerLeft">
    ++<a href="../../../../index.html" tabindex="-1" target="_top"><img src="../../../../assets/images/bg_logo.png" alt="Android Developers" /></a>
    ++</div>
    ++  <div id="headerRight">
    ++  <div id="headerLinks">
    ++<!-- <img src="/assets/images/icon_world.jpg" alt="" /> -->
    ++<span class="text">
    ++<!-- &nbsp;<a href="#">English</a> | -->
    ++<nobr><a href="http://developer.android.com" target="_top">Android Developers</a> | <a href="http://www.android.com" target="_top">Android.com</a></nobr>
    ++</span>
    ++</div>
    ++  <div class="and-diff-id" style="margin-top:6px;margin-right:8px;">
    ++    <table class="diffspectable">
    ++      <tr>
    ++        <td colspan="2" class="diffspechead">API Diff Specification</td>
    ++      </tr>
    ++      <tr>
    ++        <td class="diffspec" style="padding-top:.25em">To Level:</td>
    ++        <td class="diffvaluenew" style="padding-top:.25em">24.2.0</td>
    ++      </tr>
    ++      <tr>
    ++        <td class="diffspec">From Level:</td>
    ++        <td class="diffvalueold">24.1.0</td>
    ++      </tr>
    ++      <tr>
    ++        <td class="diffspec">Generated</td>
    ++        <td class="diffvalue">2016.08.16 14:03</td>
    ++      </tr>
    ++    </table>
    ++    </div><!-- End and-diff-id -->
    ++  <div class="and-diff-id" style="margin-right:8px;">
    ++    <table class="diffspectable">
    ++      <tr>
    ++        <td class="diffspec" colspan="2"><a href="jdiff_statistics.html">Statistics</a>
    ++      </tr>
    ++    </table>
    ++  </div> <!-- End and-diff-id -->
    ++  </div> <!-- End headerRight -->
    ++  </div> <!-- End header -->
    ++<div id="body-content" xstyle="padding:12px;padding-right:18px;">
    ++<div id="doc-content" style="position:relative;">
    ++<div id="mainBodyFluid">
    ++<H2>
    ++Class android.support.design.widget.<A HREF="../../../../reference/android/support/design/widget/CollapsingToolbarLayout.html" target="_top"><font size="+2"><code>CollapsingToolbarLayout</code></font></A>
    ++</H2>
    ++<a NAME="constructors"></a>
    ++<a NAME="methods"></a>
    ++<p>
    ++<a NAME="Added"></a>
    ++<TABLE summary="Added Methods" WIDTH="100%">
    ++<TR>
    ++  <TH VALIGN="TOP" COLSPAN=2>Added Methods</FONT></TD>
    ++</TH>
    ++<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    ++  <TD VALIGN="TOP" WIDTH="25%">
    ++  <A NAME="android.support.design.widget.CollapsingToolbarLayout.setCollapsedTitleTextColor_added(android.content.res.ColorStateList)"></A>
    ++  <nobr><code>void</code>&nbsp;<A HREF="../../../../reference/android/support/design/widget/CollapsingToolbarLayout.html#setCollapsedTitleTextColor(android.content.res.ColorStateList)" target="_top"><code>setCollapsedTitleTextColor</code></A>(<code>ColorStateList</code>)</nobr>
    ++  </TD>
    ++  <TD>&nbsp;</TD>
    ++</TR>
    ++<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    ++  <TD VALIGN="TOP" WIDTH="25%">
    ++  <A NAME="android.support.design.widget.CollapsingToolbarLayout.setExpandedTitleTextColor_added(android.content.res.ColorStateList)"></A>
    ++  <nobr><code>void</code>&nbsp;<A HREF="../../../../reference/android/support/design/widget/CollapsingToolbarLayout.html#setExpandedTitleTextColor(android.content.res.ColorStateList)" target="_top"><code>setExpandedTitleTextColor</code></A>(<code>ColorStateList</code>)</nobr>
    ++  </TD>
    ++  <TD>&nbsp;</TD>
    ++</TR>
    ++</TABLE>
    ++&nbsp;
    ++<a NAME="fields"></a>
    ++      </div>	
    ++      <div id="footer">
    ++        <div id="copyright">
    ++        Except as noted, this content is licensed under 
    ++        <a href="http://creativecommons.org/licenses/by/2.5/"> Creative Commons Attribution 2.5</a>.
    ++        For details and restrictions, see the <a href="/license.html">Content License</a>.
    ++        </div>
    ++      <div id="footerlinks">
    ++      <p>
    ++        <a href="http://www.android.com/terms.html">Site Terms of Service</a> -
    ++        <a href="http://www.android.com/privacy.html">Privacy Policy</a> -
    ++        <a href="http://www.android.com/branding.html">Brand Guidelines</a>
    ++      </p>
    ++    </div>
    ++    </div> <!-- end footer -->
    ++    </div><!-- end doc-content -->
    ++    </div> <!-- end body-content --> 
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    ++</script>
    ++<script type="text/javascript">
    ++  try {
    ++    var pageTracker = _gat._getTracker("UA-5831155-1");
    ++    pageTracker._setAllowAnchor(true);
    ++    pageTracker._initData();
    ++    pageTracker._trackPageview();
    ++  } catch(e) {}
    ++</script>
    ++</BODY>
    ++</HTML>
    +diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.design.widget.CoordinatorLayout.Behavior.html b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.design.widget.CoordinatorLayout.Behavior.html
    +new file mode 100644
    +index 0000000..edc96ed
    +--- /dev/null
    ++++ b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.design.widget.CoordinatorLayout.Behavior.html
    +@@ -0,0 +1,161 @@
    ++<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
    ++<HTML style="overflow:auto;">
    ++<HEAD>
    ++<meta name="generator" content="JDiff v1.1.0">
    ++<!-- Generated by the JDiff Javadoc doclet -->
    ++<!-- (http://www.jdiff.org) -->
    ++<meta name="description" content="JDiff is a Javadoc doclet which generates an HTML report of all the packages, classes, constructors, methods, and fields which have been removed, added or changed in any way, including their documentation, when two APIs are compared.">
    ++<meta name="keywords" content="diff, jdiff, javadiff, java diff, java difference, API difference, difference between two APIs, API diff, Javadoc, doclet">
    ++<TITLE>
    ++android.support.design.widget.CoordinatorLayout.Behavior
    ++</TITLE>
    ++<link href="../../../../assets/android-developer-docs.css" rel="stylesheet" type="text/css" />
    ++<link href="../stylesheet-jdiff.css" rel="stylesheet" type="text/css" />
    ++<noscript>
    ++<style type="text/css">
    ++body{overflow:auto;}
    ++#body-content{position:relative; top:0;}
    ++#doc-content{overflow:visible;border-left:3px solid #666;}
    ++#side-nav{padding:0;}
    ++#side-nav .toggle-list ul {display:block;}
    ++#resize-packages-nav{border-bottom:3px solid #666;}
    ++</style>
    ++</noscript>
    ++<style type="text/css">
    ++</style>
    ++</HEAD>
    ++<BODY>
    ++<!-- Start of nav bar -->
    ++<a name="top"></a>
    ++<div id="header" style="margin-bottom:0;padding-bottom:0;">
    ++<div id="headerLeft">
    ++<a href="../../../../index.html" tabindex="-1" target="_top"><img src="../../../../assets/images/bg_logo.png" alt="Android Developers" /></a>
    ++</div>
    ++  <div id="headerRight">
    ++  <div id="headerLinks">
    ++<!-- <img src="/assets/images/icon_world.jpg" alt="" /> -->
    ++<span class="text">
    ++<!-- &nbsp;<a href="#">English</a> | -->
    ++<nobr><a href="http://developer.android.com" target="_top">Android Developers</a> | <a href="http://www.android.com" target="_top">Android.com</a></nobr>
    ++</span>
    ++</div>
    ++  <div class="and-diff-id" style="margin-top:6px;margin-right:8px;">
    ++    <table class="diffspectable">
    ++      <tr>
    ++        <td colspan="2" class="diffspechead">API Diff Specification</td>
    ++      </tr>
    ++      <tr>
    ++        <td class="diffspec" style="padding-top:.25em">To Level:</td>
    ++        <td class="diffvaluenew" style="padding-top:.25em">24.2.0</td>
    ++      </tr>
    ++      <tr>
    ++        <td class="diffspec">From Level:</td>
    ++        <td class="diffvalueold">24.1.0</td>
    ++      </tr>
    ++      <tr>
    ++        <td class="diffspec">Generated</td>
    ++        <td class="diffvalue">2016.08.16 14:03</td>
    ++      </tr>
    ++    </table>
    ++    </div><!-- End and-diff-id -->
    ++  <div class="and-diff-id" style="margin-right:8px;">
    ++    <table class="diffspectable">
    ++      <tr>
    ++        <td class="diffspec" colspan="2"><a href="jdiff_statistics.html">Statistics</a>
    ++      </tr>
    ++    </table>
    ++  </div> <!-- End and-diff-id -->
    ++  </div> <!-- End headerRight -->
    ++  </div> <!-- End header -->
    ++<div id="body-content" xstyle="padding:12px;padding-right:18px;">
    ++<div id="doc-content" style="position:relative;">
    ++<div id="mainBodyFluid">
    ++<H2>
    ++Class android.support.design.widget.<A HREF="../../../../reference/android/support/design/widget/CoordinatorLayout.Behavior.html" target="_top"><font size="+2"><code>CoordinatorLayout.Behavior</code></font></A>
    ++</H2>
    ++<a NAME="constructors"></a>
    ++<a NAME="methods"></a>
    ++<p>
    ++<a NAME="Added"></a>
    ++<TABLE summary="Added Methods" WIDTH="100%">
    ++<TR>
    ++  <TH VALIGN="TOP" COLSPAN=2>Added Methods</FONT></TD>
    ++</TH>
    ++<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    ++  <TD VALIGN="TOP" WIDTH="25%">
    ++  <A NAME="android.support.design.widget.CoordinatorLayout.Behavior.getInsetDodgeRect_added(android.support.design.widget.CoordinatorLayout, V, android.graphics.Rect)"></A>
    ++  <nobr><code>boolean</code>&nbsp;<A HREF="../../../../reference/android/support/design/widget/CoordinatorLayout.Behavior.html#getInsetDodgeRect(android.support.design.widget.CoordinatorLayout, V, android.graphics.Rect)" target="_top"><code>getInsetDodgeRect</code></A>(<code>CoordinatorLayout,</nobr> V<nobr>,</nobr> Rect<nobr><nobr></code>)</nobr>
    ++  </TD>
    ++  <TD>&nbsp;</TD>
    ++</TR>
    ++<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    ++  <TD VALIGN="TOP" WIDTH="25%">
    ++  <A NAME="android.support.design.widget.CoordinatorLayout.Behavior.onAttachedToLayoutParams_added(android.support.design.widget.CoordinatorLayout.LayoutParams)"></A>
    ++  <nobr><code>void</code>&nbsp;<A HREF="../../../../reference/android/support/design/widget/CoordinatorLayout.Behavior.html#onAttachedToLayoutParams(android.support.design.widget.CoordinatorLayout.LayoutParams)" target="_top"><code>onAttachedToLayoutParams</code></A>(<code>LayoutParams</code>)</nobr>
    ++  </TD>
    ++  <TD>&nbsp;</TD>
    ++</TR>
    ++<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    ++  <TD VALIGN="TOP" WIDTH="25%">
    ++  <A NAME="android.support.design.widget.CoordinatorLayout.Behavior.onDetachedFromLayoutParams_added()"></A>
    ++  <nobr><code>void</code>&nbsp;<A HREF="../../../../reference/android/support/design/widget/CoordinatorLayout.Behavior.html#onDetachedFromLayoutParams()" target="_top"><code>onDetachedFromLayoutParams</code></A>()</nobr>
    ++  </TD>
    ++  <TD>&nbsp;</TD>
    ++</TR>
    ++<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    ++  <TD VALIGN="TOP" WIDTH="25%">
    ++  <A NAME="android.support.design.widget.CoordinatorLayout.Behavior.onRequestChildRectangleOnScreen_added(android.support.design.widget.CoordinatorLayout, V, android.graphics.Rect, boolean)"></A>
    ++  <nobr><code>boolean</code>&nbsp;<A HREF="../../../../reference/android/support/design/widget/CoordinatorLayout.Behavior.html#onRequestChildRectangleOnScreen(android.support.design.widget.CoordinatorLayout, V, android.graphics.Rect, boolean)" target="_top"><code>onRequestChildRectangleOnScreen</code></A>(<code>CoordinatorLayout,</nobr> V<nobr>,</nobr> Rect<nobr>,</nobr> boolean<nobr><nobr></code>)</nobr>
    ++  </TD>
    ++  <TD>&nbsp;</TD>
    ++</TR>
    ++</TABLE>
    ++&nbsp;
    ++<p>
    ++<a NAME="Changed"></a>
    ++<TABLE summary="Changed Methods" WIDTH="100%">
    ++<TR>
    ++  <TH VALIGN="TOP" COLSPAN=3>Changed Methods</FONT></TD>
    ++</TH>
    ++<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    ++  <TD VALIGN="TOP" WIDTH="25%">
    ++  <A NAME="android.support.design.widget.CoordinatorLayout.Behavior.isDirty_changed(android.support.design.widget.CoordinatorLayout, V)"></A>
    ++  <nobr><code>boolean</code>&nbsp;<A HREF="../../../../reference/android/support/design/widget/CoordinatorLayout.Behavior.html#isDirty(android.support.design.widget.CoordinatorLayout, V)" target="_top"><code>isDirty</code></A>(<code>CoordinatorLayout,</nobr> V<nobr><nobr></code>)  </nobr>
    ++  </TD>
    ++  <TD VALIGN="TOP" WIDTH="30%">
    ++<b>Now deprecated</b>.<br>
    ++  </TD>
    ++  <TD>&nbsp;</TD>
    ++</TR>
    ++</TABLE>
    ++&nbsp;
    ++<a NAME="fields"></a>
    ++      </div>	
    ++      <div id="footer">
    ++        <div id="copyright">
    ++        Except as noted, this content is licensed under 
    ++        <a href="http://creativecommons.org/licenses/by/2.5/"> Creative Commons Attribution 2.5</a>.
    ++        For details and restrictions, see the <a href="/license.html">Content License</a>.
    ++        </div>
    ++      <div id="footerlinks">
    ++      <p>
    ++        <a href="http://www.android.com/terms.html">Site Terms of Service</a> -
    ++        <a href="http://www.android.com/privacy.html">Privacy Policy</a> -
    ++        <a href="http://www.android.com/branding.html">Brand Guidelines</a>
    ++      </p>
    ++    </div>
    ++    </div> <!-- end footer -->
    ++    </div><!-- end doc-content -->
    ++    </div> <!-- end body-content --> 
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    ++</script>
    ++<script type="text/javascript">
    ++  try {
    ++    var pageTracker = _gat._getTracker("UA-5831155-1");
    ++    pageTracker._setAllowAnchor(true);
    ++    pageTracker._initData();
    ++    pageTracker._trackPageview();
    ++  } catch(e) {}
    ++</script>
    ++</BODY>
    ++</HTML>
    +diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.design.widget.CoordinatorLayout.LayoutParams.html b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.design.widget.CoordinatorLayout.LayoutParams.html
    +new file mode 100644
    +index 0000000..445da88
    +--- /dev/null
    ++++ b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.design.widget.CoordinatorLayout.LayoutParams.html
    +@@ -0,0 +1,129 @@
    ++<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
    ++<HTML style="overflow:auto;">
    ++<HEAD>
    ++<meta name="generator" content="JDiff v1.1.0">
    ++<!-- Generated by the JDiff Javadoc doclet -->
    ++<!-- (http://www.jdiff.org) -->
    ++<meta name="description" content="JDiff is a Javadoc doclet which generates an HTML report of all the packages, classes, constructors, methods, and fields which have been removed, added or changed in any way, including their documentation, when two APIs are compared.">
    ++<meta name="keywords" content="diff, jdiff, javadiff, java diff, java difference, API difference, difference between two APIs, API diff, Javadoc, doclet">
    ++<TITLE>
    ++android.support.design.widget.CoordinatorLayout.LayoutParams
    ++</TITLE>
    ++<link href="../../../../assets/android-developer-docs.css" rel="stylesheet" type="text/css" />
    ++<link href="../stylesheet-jdiff.css" rel="stylesheet" type="text/css" />
    ++<noscript>
    ++<style type="text/css">
    ++body{overflow:auto;}
    ++#body-content{position:relative; top:0;}
    ++#doc-content{overflow:visible;border-left:3px solid #666;}
    ++#side-nav{padding:0;}
    ++#side-nav .toggle-list ul {display:block;}
    ++#resize-packages-nav{border-bottom:3px solid #666;}
    ++</style>
    ++</noscript>
    ++<style type="text/css">
    ++</style>
    ++</HEAD>
    ++<BODY>
    ++<!-- Start of nav bar -->
    ++<a name="top"></a>
    ++<div id="header" style="margin-bottom:0;padding-bottom:0;">
    ++<div id="headerLeft">
    ++<a href="../../../../index.html" tabindex="-1" target="_top"><img src="../../../../assets/images/bg_logo.png" alt="Android Developers" /></a>
    ++</div>
    ++  <div id="headerRight">
    ++  <div id="headerLinks">
    ++<!-- <img src="/assets/images/icon_world.jpg" alt="" /> -->
    ++<span class="text">
    ++<!-- &nbsp;<a href="#">English</a> | -->
    ++<nobr><a href="http://developer.android.com" target="_top">Android Developers</a> | <a href="http://www.android.com" target="_top">Android.com</a></nobr>
    ++</span>
    ++</div>
    ++  <div class="and-diff-id" style="margin-top:6px;margin-right:8px;">
    ++    <table class="diffspectable">
    ++      <tr>
    ++        <td colspan="2" class="diffspechead">API Diff Specification</td>
    ++      </tr>
    ++      <tr>
    ++        <td class="diffspec" style="padding-top:.25em">To Level:</td>
    ++        <td class="diffvaluenew" style="padding-top:.25em">24.2.0</td>
    ++      </tr>
    ++      <tr>
    ++        <td class="diffspec">From Level:</td>
    ++        <td class="diffvalueold">24.1.0</td>
    ++      </tr>
    ++      <tr>
    ++        <td class="diffspec">Generated</td>
    ++        <td class="diffvalue">2016.08.16 14:03</td>
    ++      </tr>
    ++    </table>
    ++    </div><!-- End and-diff-id -->
    ++  <div class="and-diff-id" style="margin-right:8px;">
    ++    <table class="diffspectable">
    ++      <tr>
    ++        <td class="diffspec" colspan="2"><a href="jdiff_statistics.html">Statistics</a>
    ++      </tr>
    ++    </table>
    ++  </div> <!-- End and-diff-id -->
    ++  </div> <!-- End headerRight -->
    ++  </div> <!-- End header -->
    ++<div id="body-content" xstyle="padding:12px;padding-right:18px;">
    ++<div id="doc-content" style="position:relative;">
    ++<div id="mainBodyFluid">
    ++<H2>
    ++Class android.support.design.widget.<A HREF="../../../../reference/android/support/design/widget/CoordinatorLayout.LayoutParams.html" target="_top"><font size="+2"><code>CoordinatorLayout.LayoutParams</code></font></A>
    ++</H2>
    ++<a NAME="constructors"></a>
    ++<a NAME="methods"></a>
    ++<a NAME="fields"></a>
    ++<p>
    ++<a NAME="Added"></a>
    ++<TABLE summary="Added Fields" WIDTH="100%">
    ++<TR>
    ++  <TH VALIGN="TOP" COLSPAN=2>Added Fields</FONT></TD>
    ++</TH>
    ++<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    ++  <TD VALIGN="TOP" WIDTH="25%">
    ++  <A NAME="android.support.design.widget.CoordinatorLayout.LayoutParams.dodgeInsetEdges"></A>
    ++  <nobr><code>int</code>&nbsp;<A HREF="../../../../reference/android/support/design/widget/CoordinatorLayout.LayoutParams.html#dodgeInsetEdges" target="_top"><code>dodgeInsetEdges</code></A></nobr>
    ++  </TD>
    ++  <TD>&nbsp;</TD>
    ++</TR>
    ++<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    ++  <TD VALIGN="TOP" WIDTH="25%">
    ++  <A NAME="android.support.design.widget.CoordinatorLayout.LayoutParams.insetEdge"></A>
    ++  <nobr><code>int</code>&nbsp;<A HREF="../../../../reference/android/support/design/widget/CoordinatorLayout.LayoutParams.html#insetEdge" target="_top"><code>insetEdge</code></A></nobr>
    ++  </TD>
    ++  <TD>&nbsp;</TD>
    ++</TR>
    ++</TABLE>
    ++&nbsp;
    ++      </div>	
    ++      <div id="footer">
    ++        <div id="copyright">
    ++        Except as noted, this content is licensed under 
    ++        <a href="http://creativecommons.org/licenses/by/2.5/"> Creative Commons Attribution 2.5</a>.
    ++        For details and restrictions, see the <a href="/license.html">Content License</a>.
    ++        </div>
    ++      <div id="footerlinks">
    ++      <p>
    ++        <a href="http://www.android.com/terms.html">Site Terms of Service</a> -
    ++        <a href="http://www.android.com/privacy.html">Privacy Policy</a> -
    ++        <a href="http://www.android.com/branding.html">Brand Guidelines</a>
    ++      </p>
    ++    </div>
    ++    </div> <!-- end footer -->
    ++    </div><!-- end doc-content -->
    ++    </div> <!-- end body-content --> 
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    ++</script>
    ++<script type="text/javascript">
    ++  try {
    ++    var pageTracker = _gat._getTracker("UA-5831155-1");
    ++    pageTracker._setAllowAnchor(true);
    ++    pageTracker._initData();
    ++    pageTracker._trackPageview();
    ++  } catch(e) {}
    ++</script>
    ++</BODY>
    ++</HTML>
    +diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.design.widget.CoordinatorLayout.html b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.design.widget.CoordinatorLayout.html
    +new file mode 100644
    +index 0000000..3ba5c1e
    +--- /dev/null
    ++++ b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.design.widget.CoordinatorLayout.html
    +@@ -0,0 +1,123 @@
    ++<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
    ++<HTML style="overflow:auto;">
    ++<HEAD>
    ++<meta name="generator" content="JDiff v1.1.0">
    ++<!-- Generated by the JDiff Javadoc doclet -->
    ++<!-- (http://www.jdiff.org) -->
    ++<meta name="description" content="JDiff is a Javadoc doclet which generates an HTML report of all the packages, classes, constructors, methods, and fields which have been removed, added or changed in any way, including their documentation, when two APIs are compared.">
    ++<meta name="keywords" content="diff, jdiff, javadiff, java diff, java difference, API difference, difference between two APIs, API diff, Javadoc, doclet">
    ++<TITLE>
    ++android.support.design.widget.CoordinatorLayout
    ++</TITLE>
    ++<link href="../../../../assets/android-developer-docs.css" rel="stylesheet" type="text/css" />
    ++<link href="../stylesheet-jdiff.css" rel="stylesheet" type="text/css" />
    ++<noscript>
    ++<style type="text/css">
    ++body{overflow:auto;}
    ++#body-content{position:relative; top:0;}
    ++#doc-content{overflow:visible;border-left:3px solid #666;}
    ++#side-nav{padding:0;}
    ++#side-nav .toggle-list ul {display:block;}
    ++#resize-packages-nav{border-bottom:3px solid #666;}
    ++</style>
    ++</noscript>
    ++<style type="text/css">
    ++</style>
    ++</HEAD>
    ++<BODY>
    ++<!-- Start of nav bar -->
    ++<a name="top"></a>
    ++<div id="header" style="margin-bottom:0;padding-bottom:0;">
    ++<div id="headerLeft">
    ++<a href="../../../../index.html" tabindex="-1" target="_top"><img src="../../../../assets/images/bg_logo.png" alt="Android Developers" /></a>
    ++</div>
    ++  <div id="headerRight">
    ++  <div id="headerLinks">
    ++<!-- <img src="/assets/images/icon_world.jpg" alt="" /> -->
    ++<span class="text">
    ++<!-- &nbsp;<a href="#">English</a> | -->
    ++<nobr><a href="http://developer.android.com" target="_top">Android Developers</a> | <a href="http://www.android.com" target="_top">Android.com</a></nobr>
    ++</span>
    ++</div>
    ++  <div class="and-diff-id" style="margin-top:6px;margin-right:8px;">
    ++    <table class="diffspectable">
    ++      <tr>
    ++        <td colspan="2" class="diffspechead">API Diff Specification</td>
    ++      </tr>
    ++      <tr>
    ++        <td class="diffspec" style="padding-top:.25em">To Level:</td>
    ++        <td class="diffvaluenew" style="padding-top:.25em">24.2.0</td>
    ++      </tr>
    ++      <tr>
    ++        <td class="diffspec">From Level:</td>
    ++        <td class="diffvalueold">24.1.0</td>
    ++      </tr>
    ++      <tr>
    ++        <td class="diffspec">Generated</td>
    ++        <td class="diffvalue">2016.08.16 14:03</td>
    ++      </tr>
    ++    </table>
    ++    </div><!-- End and-diff-id -->
    ++  <div class="and-diff-id" style="margin-right:8px;">
    ++    <table class="diffspectable">
    ++      <tr>
    ++        <td class="diffspec" colspan="2"><a href="jdiff_statistics.html">Statistics</a>
    ++      </tr>
    ++    </table>
    ++  </div> <!-- End and-diff-id -->
    ++  </div> <!-- End headerRight -->
    ++  </div> <!-- End header -->
    ++<div id="body-content" xstyle="padding:12px;padding-right:18px;">
    ++<div id="doc-content" style="position:relative;">
    ++<div id="mainBodyFluid">
    ++<H2>
    ++Class android.support.design.widget.<A HREF="../../../../reference/android/support/design/widget/CoordinatorLayout.html" target="_top"><font size="+2"><code>CoordinatorLayout</code></font></A>
    ++</H2>
    ++<p><font xsize="+1">Added interface <code>android.support.v4.view.NestedScrollingParent</code>.<br></font>
    ++<a NAME="constructors"></a>
    ++<a NAME="methods"></a>
    ++<p>
    ++<a NAME="Added"></a>
    ++<TABLE summary="Added Methods" WIDTH="100%">
    ++<TR>
    ++  <TH VALIGN="TOP" COLSPAN=2>Added Methods</FONT></TD>
    ++</TH>
    ++<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    ++  <TD VALIGN="TOP" WIDTH="25%">
    ++  <A NAME="android.support.design.widget.CoordinatorLayout.getDependents_added(android.view.View)"></A>
    ++  <nobr><code>List&lt;View&gt;</code>&nbsp;<A HREF="../../../../reference/android/support/design/widget/CoordinatorLayout.html#getDependents(android.view.View)" target="_top"><code>getDependents</code></A>(<code>View</code>)</nobr>
    ++  </TD>
    ++  <TD>&nbsp;</TD>
    ++</TR>
    ++</TABLE>
    ++&nbsp;
    ++<a NAME="fields"></a>
    ++      </div>	
    ++      <div id="footer">
    ++        <div id="copyright">
    ++        Except as noted, this content is licensed under 
    ++        <a href="http://creativecommons.org/licenses/by/2.5/"> Creative Commons Attribution 2.5</a>.
    ++        For details and restrictions, see the <a href="/license.html">Content License</a>.
    ++        </div>
    ++      <div id="footerlinks">
    ++      <p>
    ++        <a href="http://www.android.com/terms.html">Site Terms of Service</a> -
    ++        <a href="http://www.android.com/privacy.html">Privacy Policy</a> -
    ++        <a href="http://www.android.com/branding.html">Brand Guidelines</a>
    ++      </p>
    ++    </div>
    ++    </div> <!-- end footer -->
    ++    </div><!-- end doc-content -->
    ++    </div> <!-- end body-content --> 
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    ++</script>
    ++<script type="text/javascript">
    ++  try {
    ++    var pageTracker = _gat._getTracker("UA-5831155-1");
    ++    pageTracker._setAllowAnchor(true);
    ++    pageTracker._initData();
    ++    pageTracker._trackPageview();
    ++  } catch(e) {}
    ++</script>
    ++</BODY>
    ++</HTML>
    +diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.design.widget.FloatingActionButton.Behavior.html b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.design.widget.FloatingActionButton.Behavior.html
    +new file mode 100644
    +index 0000000..07099d6
    +--- /dev/null
    ++++ b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.design.widget.FloatingActionButton.Behavior.html
    +@@ -0,0 +1,158 @@
    ++<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
    ++<HTML style="overflow:auto;">
    ++<HEAD>
    ++<meta name="generator" content="JDiff v1.1.0">
    ++<!-- Generated by the JDiff Javadoc doclet -->
    ++<!-- (http://www.jdiff.org) -->
    ++<meta name="description" content="JDiff is a Javadoc doclet which generates an HTML report of all the packages, classes, constructors, methods, and fields which have been removed, added or changed in any way, including their documentation, when two APIs are compared.">
    ++<meta name="keywords" content="diff, jdiff, javadiff, java diff, java difference, API difference, difference between two APIs, API diff, Javadoc, doclet">
    ++<TITLE>
    ++android.support.design.widget.FloatingActionButton.Behavior
    ++</TITLE>
    ++<link href="../../../../assets/android-developer-docs.css" rel="stylesheet" type="text/css" />
    ++<link href="../stylesheet-jdiff.css" rel="stylesheet" type="text/css" />
    ++<noscript>
    ++<style type="text/css">
    ++body{overflow:auto;}
    ++#body-content{position:relative; top:0;}
    ++#doc-content{overflow:visible;border-left:3px solid #666;}
    ++#side-nav{padding:0;}
    ++#side-nav .toggle-list ul {display:block;}
    ++#resize-packages-nav{border-bottom:3px solid #666;}
    ++</style>
    ++</noscript>
    ++<style type="text/css">
    ++</style>
    ++</HEAD>
    ++<BODY>
    ++<!-- Start of nav bar -->
    ++<a name="top"></a>
    ++<div id="header" style="margin-bottom:0;padding-bottom:0;">
    ++<div id="headerLeft">
    ++<a href="../../../../index.html" tabindex="-1" target="_top"><img src="../../../../assets/images/bg_logo.png" alt="Android Developers" /></a>
    ++</div>
    ++  <div id="headerRight">
    ++  <div id="headerLinks">
    ++<!-- <img src="/assets/images/icon_world.jpg" alt="" /> -->
    ++<span class="text">
    ++<!-- &nbsp;<a href="#">English</a> | -->
    ++<nobr><a href="http://developer.android.com" target="_top">Android Developers</a> | <a href="http://www.android.com" target="_top">Android.com</a></nobr>
    ++</span>
    ++</div>
    ++  <div class="and-diff-id" style="margin-top:6px;margin-right:8px;">
    ++    <table class="diffspectable">
    ++      <tr>
    ++        <td colspan="2" class="diffspechead">API Diff Specification</td>
    ++      </tr>
    ++      <tr>
    ++        <td class="diffspec" style="padding-top:.25em">To Level:</td>
    ++        <td class="diffvaluenew" style="padding-top:.25em">24.2.0</td>
    ++      </tr>
    ++      <tr>
    ++        <td class="diffspec">From Level:</td>
    ++        <td class="diffvalueold">24.1.0</td>
    ++      </tr>
    ++      <tr>
    ++        <td class="diffspec">Generated</td>
    ++        <td class="diffvalue">2016.08.16 14:03</td>
    ++      </tr>
    ++    </table>
    ++    </div><!-- End and-diff-id -->
    ++  <div class="and-diff-id" style="margin-right:8px;">
    ++    <table class="diffspectable">
    ++      <tr>
    ++        <td class="diffspec" colspan="2"><a href="jdiff_statistics.html">Statistics</a>
    ++      </tr>
    ++    </table>
    ++  </div> <!-- End and-diff-id -->
    ++  </div> <!-- End headerRight -->
    ++  </div> <!-- End header -->
    ++<div id="body-content" xstyle="padding:12px;padding-right:18px;">
    ++<div id="doc-content" style="position:relative;">
    ++<div id="mainBodyFluid">
    ++<H2>
    ++Class android.support.design.widget.<A HREF="../../../../reference/android/support/design/widget/FloatingActionButton.Behavior.html" target="_top"><font size="+2"><code>FloatingActionButton.Behavior</code></font></A>
    ++</H2>
    ++<a NAME="constructors"></a>
    ++<a NAME="methods"></a>
    ++<p>
    ++<a NAME="Removed"></a>
    ++<TABLE summary="Removed Methods" WIDTH="100%">
    ++<TR>
    ++  <TH VALIGN="TOP" COLSPAN=2>Removed Methods</FONT></TD>
    ++</TH>
    ++<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    ++  <TD VALIGN="TOP" WIDTH="25%">
    ++  <A NAME="android.support.design.widget.FloatingActionButton.Behavior.layoutDependsOn_removed(android.support.design.widget.CoordinatorLayout, android.support.design.widget.FloatingActionButton, android.view.View)"></A>
    ++  <nobr><code>boolean</code>&nbsp;layoutDependsOn(<code>CoordinatorLayout,</nobr> FloatingActionButton<nobr>,</nobr> View<nobr><nobr></code>)</nobr>
    ++  </TD>
    ++  <TD>&nbsp;</TD>
    ++</TR>
    ++<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    ++  <TD VALIGN="TOP" WIDTH="25%">
    ++  <A NAME="android.support.design.widget.FloatingActionButton.Behavior.onDependentViewRemoved_removed(android.support.design.widget.CoordinatorLayout, android.support.design.widget.FloatingActionButton, android.view.View)"></A>
    ++  <nobr><code>void</code>&nbsp;onDependentViewRemoved(<code>CoordinatorLayout,</nobr> FloatingActionButton<nobr>,</nobr> View<nobr><nobr></code>)</nobr>
    ++  </TD>
    ++  <TD>&nbsp;</TD>
    ++</TR>
    ++</TABLE>
    ++&nbsp;
    ++<p>
    ++<a NAME="Added"></a>
    ++<TABLE summary="Added Methods" WIDTH="100%">
    ++<TR>
    ++  <TH VALIGN="TOP" COLSPAN=2>Added Methods</FONT></TD>
    ++</TH>
    ++<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    ++  <TD VALIGN="TOP" WIDTH="25%">
    ++  <A NAME="android.support.design.widget.FloatingActionButton.Behavior.getInsetDodgeRect_added(android.support.design.widget.CoordinatorLayout, android.support.design.widget.FloatingActionButton, android.graphics.Rect)"></A>
    ++  <nobr><code>boolean</code>&nbsp;<A HREF="../../../../reference/android/support/design/widget/FloatingActionButton.Behavior.html#getInsetDodgeRect(android.support.design.widget.CoordinatorLayout, android.support.design.widget.FloatingActionButton, android.graphics.Rect)" target="_top"><code>getInsetDodgeRect</code></A>(<code>CoordinatorLayout,</nobr> FloatingActionButton<nobr>,</nobr> Rect<nobr><nobr></code>)</nobr>
    ++  </TD>
    ++  <TD>&nbsp;</TD>
    ++</TR>
    ++<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    ++  <TD VALIGN="TOP" WIDTH="25%">
    ++  <A NAME="android.support.design.widget.FloatingActionButton.Behavior.isAutoHideEnabled_added()"></A>
    ++  <nobr><code>boolean</code>&nbsp;<A HREF="../../../../reference/android/support/design/widget/FloatingActionButton.Behavior.html#isAutoHideEnabled()" target="_top"><code>isAutoHideEnabled</code></A>()</nobr>
    ++  </TD>
    ++  <TD>&nbsp;</TD>
    ++</TR>
    ++<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    ++  <TD VALIGN="TOP" WIDTH="25%">
    ++  <A NAME="android.support.design.widget.FloatingActionButton.Behavior.setAutoHideEnabled_added(boolean)"></A>
    ++  <nobr><code>void</code>&nbsp;<A HREF="../../../../reference/android/support/design/widget/FloatingActionButton.Behavior.html#setAutoHideEnabled(boolean)" target="_top"><code>setAutoHideEnabled</code></A>(<code>boolean</code>)</nobr>
    ++  </TD>
    ++  <TD>&nbsp;</TD>
    ++</TR>
    ++</TABLE>
    ++&nbsp;
    ++<a NAME="fields"></a>
    ++      </div>	
    ++      <div id="footer">
    ++        <div id="copyright">
    ++        Except as noted, this content is licensed under 
    ++        <a href="http://creativecommons.org/licenses/by/2.5/"> Creative Commons Attribution 2.5</a>.
    ++        For details and restrictions, see the <a href="/license.html">Content License</a>.
    ++        </div>
    ++      <div id="footerlinks">
    ++      <p>
    ++        <a href="http://www.android.com/terms.html">Site Terms of Service</a> -
    ++        <a href="http://www.android.com/privacy.html">Privacy Policy</a> -
    ++        <a href="http://www.android.com/branding.html">Brand Guidelines</a>
    ++      </p>
    ++    </div>
    ++    </div> <!-- end footer -->
    ++    </div><!-- end doc-content -->
    ++    </div> <!-- end body-content --> 
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    ++</script>
    ++<script type="text/javascript">
    ++  try {
    ++    var pageTracker = _gat._getTracker("UA-5831155-1");
    ++    pageTracker._setAllowAnchor(true);
    ++    pageTracker._initData();
    ++    pageTracker._trackPageview();
    ++  } catch(e) {}
    ++</script>
    ++</BODY>
    ++</HTML>
    +diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.design.widget.TabLayout.html b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.design.widget.TabLayout.html
    +new file mode 100644
    +index 0000000..a09656a
    +--- /dev/null
    ++++ b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.design.widget.TabLayout.html
    +@@ -0,0 +1,122 @@
    ++<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
    ++<HTML style="overflow:auto;">
    ++<HEAD>
    ++<meta name="generator" content="JDiff v1.1.0">
    ++<!-- Generated by the JDiff Javadoc doclet -->
    ++<!-- (http://www.jdiff.org) -->
    ++<meta name="description" content="JDiff is a Javadoc doclet which generates an HTML report of all the packages, classes, constructors, methods, and fields which have been removed, added or changed in any way, including their documentation, when two APIs are compared.">
    ++<meta name="keywords" content="diff, jdiff, javadiff, java diff, java difference, API difference, difference between two APIs, API diff, Javadoc, doclet">
    ++<TITLE>
    ++android.support.design.widget.TabLayout
    ++</TITLE>
    ++<link href="../../../../assets/android-developer-docs.css" rel="stylesheet" type="text/css" />
    ++<link href="../stylesheet-jdiff.css" rel="stylesheet" type="text/css" />
    ++<noscript>
    ++<style type="text/css">
    ++body{overflow:auto;}
    ++#body-content{position:relative; top:0;}
    ++#doc-content{overflow:visible;border-left:3px solid #666;}
    ++#side-nav{padding:0;}
    ++#side-nav .toggle-list ul {display:block;}
    ++#resize-packages-nav{border-bottom:3px solid #666;}
    ++</style>
    ++</noscript>
    ++<style type="text/css">
    ++</style>
    ++</HEAD>
    ++<BODY>
    ++<!-- Start of nav bar -->
    ++<a name="top"></a>
    ++<div id="header" style="margin-bottom:0;padding-bottom:0;">
    ++<div id="headerLeft">
    ++<a href="../../../../index.html" tabindex="-1" target="_top"><img src="../../../../assets/images/bg_logo.png" alt="Android Developers" /></a>
    ++</div>
    ++  <div id="headerRight">
    ++  <div id="headerLinks">
    ++<!-- <img src="/assets/images/icon_world.jpg" alt="" /> -->
    ++<span class="text">
    ++<!-- &nbsp;<a href="#">English</a> | -->
    ++<nobr><a href="http://developer.android.com" target="_top">Android Developers</a> | <a href="http://www.android.com" target="_top">Android.com</a></nobr>
    ++</span>
    ++</div>
    ++  <div class="and-diff-id" style="margin-top:6px;margin-right:8px;">
    ++    <table class="diffspectable">
    ++      <tr>
    ++        <td colspan="2" class="diffspechead">API Diff Specification</td>
    ++      </tr>
    ++      <tr>
    ++        <td class="diffspec" style="padding-top:.25em">To Level:</td>
    ++        <td class="diffvaluenew" style="padding-top:.25em">24.2.0</td>
    ++      </tr>
    ++      <tr>
    ++        <td class="diffspec">From Level:</td>
    ++        <td class="diffvalueold">24.1.0</td>
    ++      </tr>
    ++      <tr>
    ++        <td class="diffspec">Generated</td>
    ++        <td class="diffvalue">2016.08.16 14:03</td>
    ++      </tr>
    ++    </table>
    ++    </div><!-- End and-diff-id -->
    ++  <div class="and-diff-id" style="margin-right:8px;">
    ++    <table class="diffspectable">
    ++      <tr>
    ++        <td class="diffspec" colspan="2"><a href="jdiff_statistics.html">Statistics</a>
    ++      </tr>
    ++    </table>
    ++  </div> <!-- End and-diff-id -->
    ++  </div> <!-- End headerRight -->
    ++  </div> <!-- End header -->
    ++<div id="body-content" xstyle="padding:12px;padding-right:18px;">
    ++<div id="doc-content" style="position:relative;">
    ++<div id="mainBodyFluid">
    ++<H2>
    ++Class android.support.design.widget.<A HREF="../../../../reference/android/support/design/widget/TabLayout.html" target="_top"><font size="+2"><code>TabLayout</code></font></A>
    ++</H2>
    ++<a NAME="constructors"></a>
    ++<a NAME="methods"></a>
    ++<p>
    ++<a NAME="Added"></a>
    ++<TABLE summary="Added Methods" WIDTH="100%">
    ++<TR>
    ++  <TH VALIGN="TOP" COLSPAN=2>Added Methods</FONT></TD>
    ++</TH>
    ++<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    ++  <TD VALIGN="TOP" WIDTH="25%">
    ++  <A NAME="android.support.design.widget.TabLayout.clearOnTabSelectedListeners_added()"></A>
    ++  <nobr><code>void</code>&nbsp;<A HREF="../../../../reference/android/support/design/widget/TabLayout.html#clearOnTabSelectedListeners()" target="_top"><code>clearOnTabSelectedListeners</code></A>()</nobr>
    ++  </TD>
    ++  <TD>&nbsp;</TD>
    ++</TR>
    ++</TABLE>
    ++&nbsp;
    ++<a NAME="fields"></a>
    ++      </div>	
    ++      <div id="footer">
    ++        <div id="copyright">
    ++        Except as noted, this content is licensed under 
    ++        <a href="http://creativecommons.org/licenses/by/2.5/"> Creative Commons Attribution 2.5</a>.
    ++        For details and restrictions, see the <a href="/license.html">Content License</a>.
    ++        </div>
    ++      <div id="footerlinks">
    ++      <p>
    ++        <a href="http://www.android.com/terms.html">Site Terms of Service</a> -
    ++        <a href="http://www.android.com/privacy.html">Privacy Policy</a> -
    ++        <a href="http://www.android.com/branding.html">Brand Guidelines</a>
    ++      </p>
    ++    </div>
    ++    </div> <!-- end footer -->
    ++    </div><!-- end doc-content -->
    ++    </div> <!-- end body-content --> 
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    ++</script>
    ++<script type="text/javascript">
    ++  try {
    ++    var pageTracker = _gat._getTracker("UA-5831155-1");
    ++    pageTracker._setAllowAnchor(true);
    ++    pageTracker._initData();
    ++    pageTracker._trackPageview();
    ++  } catch(e) {}
    ++</script>
    ++</BODY>
    ++</HTML>
    +diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.design.widget.TextInputLayout.html b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.design.widget.TextInputLayout.html
    +new file mode 100644
    +index 0000000..9ad13eb
    +--- /dev/null
    ++++ b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.design.widget.TextInputLayout.html
    +@@ -0,0 +1,185 @@
    ++<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
    ++<HTML style="overflow:auto;">
    ++<HEAD>
    ++<meta name="generator" content="JDiff v1.1.0">
    ++<!-- Generated by the JDiff Javadoc doclet -->
    ++<!-- (http://www.jdiff.org) -->
    ++<meta name="description" content="JDiff is a Javadoc doclet which generates an HTML report of all the packages, classes, constructors, methods, and fields which have been removed, added or changed in any way, including their documentation, when two APIs are compared.">
    ++<meta name="keywords" content="diff, jdiff, javadiff, java diff, java difference, API difference, difference between two APIs, API diff, Javadoc, doclet">
    ++<TITLE>
    ++android.support.design.widget.TextInputLayout
    ++</TITLE>
    ++<link href="../../../../assets/android-developer-docs.css" rel="stylesheet" type="text/css" />
    ++<link href="../stylesheet-jdiff.css" rel="stylesheet" type="text/css" />
    ++<noscript>
    ++<style type="text/css">
    ++body{overflow:auto;}
    ++#body-content{position:relative; top:0;}
    ++#doc-content{overflow:visible;border-left:3px solid #666;}
    ++#side-nav{padding:0;}
    ++#side-nav .toggle-list ul {display:block;}
    ++#resize-packages-nav{border-bottom:3px solid #666;}
    ++</style>
    ++</noscript>
    ++<style type="text/css">
    ++</style>
    ++</HEAD>
    ++<BODY>
    ++<!-- Start of nav bar -->
    ++<a name="top"></a>
    ++<div id="header" style="margin-bottom:0;padding-bottom:0;">
    ++<div id="headerLeft">
    ++<a href="../../../../index.html" tabindex="-1" target="_top"><img src="../../../../assets/images/bg_logo.png" alt="Android Developers" /></a>
    ++</div>
    ++  <div id="headerRight">
    ++  <div id="headerLinks">
    ++<!-- <img src="/assets/images/icon_world.jpg" alt="" /> -->
    ++<span class="text">
    ++<!-- &nbsp;<a href="#">English</a> | -->
    ++<nobr><a href="http://developer.android.com" target="_top">Android Developers</a> | <a href="http://www.android.com" target="_top">Android.com</a></nobr>
    ++</span>
    ++</div>
    ++  <div class="and-diff-id" style="margin-top:6px;margin-right:8px;">
    ++    <table class="diffspectable">
    ++      <tr>
    ++        <td colspan="2" class="diffspechead">API Diff Specification</td>
    ++      </tr>
    ++      <tr>
    ++        <td class="diffspec" style="padding-top:.25em">To Level:</td>
    ++        <td class="diffvaluenew" style="padding-top:.25em">24.2.0</td>
    ++      </tr>
    ++      <tr>
    ++        <td class="diffspec">From Level:</td>
    ++        <td class="diffvalueold">24.1.0</td>
    ++      </tr>
    ++      <tr>
    ++        <td class="diffspec">Generated</td>
    ++        <td class="diffvalue">2016.08.16 14:03</td>
    ++      </tr>
    ++    </table>
    ++    </div><!-- End and-diff-id -->
    ++  <div class="and-diff-id" style="margin-right:8px;">
    ++    <table class="diffspectable">
    ++      <tr>
    ++        <td class="diffspec" colspan="2"><a href="jdiff_statistics.html">Statistics</a>
    ++      </tr>
    ++    </table>
    ++  </div> <!-- End and-diff-id -->
    ++  </div> <!-- End headerRight -->
    ++  </div> <!-- End header -->
    ++<div id="body-content" xstyle="padding:12px;padding-right:18px;">
    ++<div id="doc-content" style="position:relative;">
    ++<div id="mainBodyFluid">
    ++<H2>
    ++Class android.support.design.widget.<A HREF="../../../../reference/android/support/design/widget/TextInputLayout.html" target="_top"><font size="+2"><code>TextInputLayout</code></font></A>
    ++</H2>
    ++<a NAME="constructors"></a>
    ++<a NAME="methods"></a>
    ++<p>
    ++<a NAME="Added"></a>
    ++<TABLE summary="Added Methods" WIDTH="100%">
    ++<TR>
    ++  <TH VALIGN="TOP" COLSPAN=2>Added Methods</FONT></TD>
    ++</TH>
    ++<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    ++  <TD VALIGN="TOP" WIDTH="25%">
    ++  <A NAME="android.support.design.widget.TextInputLayout.getPasswordVisibilityToggleContentDescription_added()"></A>
    ++  <nobr><code>CharSequence</code>&nbsp;<A HREF="../../../../reference/android/support/design/widget/TextInputLayout.html#getPasswordVisibilityToggleContentDescription()" target="_top"><code>getPasswordVisibilityToggleContentDescription</code></A>()</nobr>
    ++  </TD>
    ++  <TD>&nbsp;</TD>
    ++</TR>
    ++<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    ++  <TD VALIGN="TOP" WIDTH="25%">
    ++  <A NAME="android.support.design.widget.TextInputLayout.getPasswordVisibilityToggleDrawable_added()"></A>
    ++  <nobr><code>Drawable</code>&nbsp;<A HREF="../../../../reference/android/support/design/widget/TextInputLayout.html#getPasswordVisibilityToggleDrawable()" target="_top"><code>getPasswordVisibilityToggleDrawable</code></A>()</nobr>
    ++  </TD>
    ++  <TD>&nbsp;</TD>
    ++</TR>
    ++<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    ++  <TD VALIGN="TOP" WIDTH="25%">
    ++  <A NAME="android.support.design.widget.TextInputLayout.isPasswordVisibilityToggleEnabled_added()"></A>
    ++  <nobr><code>boolean</code>&nbsp;<A HREF="../../../../reference/android/support/design/widget/TextInputLayout.html#isPasswordVisibilityToggleEnabled()" target="_top"><code>isPasswordVisibilityToggleEnabled</code></A>()</nobr>
    ++  </TD>
    ++  <TD>&nbsp;</TD>
    ++</TR>
    ++<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    ++  <TD VALIGN="TOP" WIDTH="25%">
    ++  <A NAME="android.support.design.widget.TextInputLayout.setPasswordVisibilityToggleContentDescription_added(int)"></A>
    ++  <nobr><code>void</code>&nbsp;<A HREF="../../../../reference/android/support/design/widget/TextInputLayout.html#setPasswordVisibilityToggleContentDescription(int)" target="_top"><code>setPasswordVisibilityToggleContentDescription</code></A>(<code>int</code>)</nobr>
    ++  </TD>
    ++  <TD>&nbsp;</TD>
    ++</TR>
    ++<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    ++  <TD VALIGN="TOP" WIDTH="25%">
    ++  <A NAME="android.support.design.widget.TextInputLayout.setPasswordVisibilityToggleContentDescription_added(java.lang.CharSequence)"></A>
    ++  <nobr><code>void</code>&nbsp;<A HREF="../../../../reference/android/support/design/widget/TextInputLayout.html#setPasswordVisibilityToggleContentDescription(java.lang.CharSequence)" target="_top"><code>setPasswordVisibilityToggleContentDescription</code></A>(<code>CharSequence</code>)</nobr>
    ++  </TD>
    ++  <TD>&nbsp;</TD>
    ++</TR>
    ++<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    ++  <TD VALIGN="TOP" WIDTH="25%">
    ++  <A NAME="android.support.design.widget.TextInputLayout.setPasswordVisibilityToggleDrawable_added(android.graphics.drawable.Drawable)"></A>
    ++  <nobr><code>void</code>&nbsp;<A HREF="../../../../reference/android/support/design/widget/TextInputLayout.html#setPasswordVisibilityToggleDrawable(android.graphics.drawable.Drawable)" target="_top"><code>setPasswordVisibilityToggleDrawable</code></A>(<code>Drawable</code>)</nobr>
    ++  </TD>
    ++  <TD>&nbsp;</TD>
    ++</TR>
    ++<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    ++  <TD VALIGN="TOP" WIDTH="25%">
    ++  <A NAME="android.support.design.widget.TextInputLayout.setPasswordVisibilityToggleDrawable_added(int)"></A>
    ++  <nobr><code>void</code>&nbsp;<A HREF="../../../../reference/android/support/design/widget/TextInputLayout.html#setPasswordVisibilityToggleDrawable(int)" target="_top"><code>setPasswordVisibilityToggleDrawable</code></A>(<code>int</code>)</nobr>
    ++  </TD>
    ++  <TD>&nbsp;</TD>
    ++</TR>
    ++<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    ++  <TD VALIGN="TOP" WIDTH="25%">
    ++  <A NAME="android.support.design.widget.TextInputLayout.setPasswordVisibilityToggleEnabled_added(boolean)"></A>
    ++  <nobr><code>void</code>&nbsp;<A HREF="../../../../reference/android/support/design/widget/TextInputLayout.html#setPasswordVisibilityToggleEnabled(boolean)" target="_top"><code>setPasswordVisibilityToggleEnabled</code></A>(<code>boolean</code>)</nobr>
    ++  </TD>
    ++  <TD>&nbsp;</TD>
    ++</TR>
    ++<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    ++  <TD VALIGN="TOP" WIDTH="25%">
    ++  <A NAME="android.support.design.widget.TextInputLayout.setPasswordVisibilityToggleTintList_added(android.content.res.ColorStateList)"></A>
    ++  <nobr><code>void</code>&nbsp;<A HREF="../../../../reference/android/support/design/widget/TextInputLayout.html#setPasswordVisibilityToggleTintList(android.content.res.ColorStateList)" target="_top"><code>setPasswordVisibilityToggleTintList</code></A>(<code>ColorStateList</code>)</nobr>
    ++  </TD>
    ++  <TD>&nbsp;</TD>
    ++</TR>
    ++<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    ++  <TD VALIGN="TOP" WIDTH="25%">
    ++  <A NAME="android.support.design.widget.TextInputLayout.setPasswordVisibilityToggleTintMode_added(android.graphics.PorterDuff.Mode)"></A>
    ++  <nobr><code>void</code>&nbsp;<A HREF="../../../../reference/android/support/design/widget/TextInputLayout.html#setPasswordVisibilityToggleTintMode(android.graphics.PorterDuff.Mode)" target="_top"><code>setPasswordVisibilityToggleTintMode</code></A>(<code>Mode</code>)</nobr>
    ++  </TD>
    ++  <TD>&nbsp;</TD>
    ++</TR>
    ++</TABLE>
    ++&nbsp;
    ++<a NAME="fields"></a>
    ++      </div>	
    ++      <div id="footer">
    ++        <div id="copyright">
    ++        Except as noted, this content is licensed under 
    ++        <a href="http://creativecommons.org/licenses/by/2.5/"> Creative Commons Attribution 2.5</a>.
    ++        For details and restrictions, see the <a href="/license.html">Content License</a>.
    ++        </div>
    ++      <div id="footerlinks">
    ++      <p>
    ++        <a href="http://www.android.com/terms.html">Site Terms of Service</a> -
    ++        <a href="http://www.android.com/privacy.html">Privacy Policy</a> -
    ++        <a href="http://www.android.com/branding.html">Brand Guidelines</a>
    ++      </p>
    ++    </div>
    ++    </div> <!-- end footer -->
    ++    </div><!-- end doc-content -->
    ++    </div> <!-- end body-content --> 
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    ++</script>
    ++<script type="text/javascript">
    ++  try {
    ++    var pageTracker = _gat._getTracker("UA-5831155-1");
    ++    pageTracker._setAllowAnchor(true);
    ++    pageTracker._initData();
    ++    pageTracker._trackPageview();
    ++  } catch(e) {}
    ++</script>
    ++</BODY>
    ++</HTML>
    +diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v14.preference.PreferenceFragment.html b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v14.preference.PreferenceFragment.html
    +new file mode 100644
    +index 0000000..6b23c17
    +--- /dev/null
    ++++ b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v14.preference.PreferenceFragment.html
    +@@ -0,0 +1,108 @@
    ++<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
    ++<HTML style="overflow:auto;">
    ++<HEAD>
    ++<meta name="generator" content="JDiff v1.1.0">
    ++<!-- Generated by the JDiff Javadoc doclet -->
    ++<!-- (http://www.jdiff.org) -->
    ++<meta name="description" content="JDiff is a Javadoc doclet which generates an HTML report of all the packages, classes, constructors, methods, and fields which have been removed, added or changed in any way, including their documentation, when two APIs are compared.">
    ++<meta name="keywords" content="diff, jdiff, javadiff, java diff, java difference, API difference, difference between two APIs, API diff, Javadoc, doclet">
    ++<TITLE>
    ++android.support.v14.preference.PreferenceFragment
    ++</TITLE>
    ++<link href="../../../../assets/android-developer-docs.css" rel="stylesheet" type="text/css" />
    ++<link href="../stylesheet-jdiff.css" rel="stylesheet" type="text/css" />
    ++<noscript>
    ++<style type="text/css">
    ++body{overflow:auto;}
    ++#body-content{position:relative; top:0;}
    ++#doc-content{overflow:visible;border-left:3px solid #666;}
    ++#side-nav{padding:0;}
    ++#side-nav .toggle-list ul {display:block;}
    ++#resize-packages-nav{border-bottom:3px solid #666;}
    ++</style>
    ++</noscript>
    ++<style type="text/css">
    ++</style>
    ++</HEAD>
    ++<BODY>
    ++<!-- Start of nav bar -->
    ++<a name="top"></a>
    ++<div id="header" style="margin-bottom:0;padding-bottom:0;">
    ++<div id="headerLeft">
    ++<a href="../../../../index.html" tabindex="-1" target="_top"><img src="../../../../assets/images/bg_logo.png" alt="Android Developers" /></a>
    ++</div>
    ++  <div id="headerRight">
    ++  <div id="headerLinks">
    ++<!-- <img src="/assets/images/icon_world.jpg" alt="" /> -->
    ++<span class="text">
    ++<!-- &nbsp;<a href="#">English</a> | -->
    ++<nobr><a href="http://developer.android.com" target="_top">Android Developers</a> | <a href="http://www.android.com" target="_top">Android.com</a></nobr>
    ++</span>
    ++</div>
    ++  <div class="and-diff-id" style="margin-top:6px;margin-right:8px;">
    ++    <table class="diffspectable">
    ++      <tr>
    ++        <td colspan="2" class="diffspechead">API Diff Specification</td>
    ++      </tr>
    ++      <tr>
    ++        <td class="diffspec" style="padding-top:.25em">To Level:</td>
    ++        <td class="diffvaluenew" style="padding-top:.25em">24.2.0</td>
    ++      </tr>
    ++      <tr>
    ++        <td class="diffspec">From Level:</td>
    ++        <td class="diffvalueold">24.1.0</td>
    ++      </tr>
    ++      <tr>
    ++        <td class="diffspec">Generated</td>
    ++        <td class="diffvalue">2016.08.16 14:03</td>
    ++      </tr>
    ++    </table>
    ++    </div><!-- End and-diff-id -->
    ++  <div class="and-diff-id" style="margin-right:8px;">
    ++    <table class="diffspectable">
    ++      <tr>
    ++        <td class="diffspec" colspan="2"><a href="jdiff_statistics.html">Statistics</a>
    ++      </tr>
    ++    </table>
    ++  </div> <!-- End and-diff-id -->
    ++  </div> <!-- End headerRight -->
    ++  </div> <!-- End header -->
    ++<div id="body-content" xstyle="padding:12px;padding-right:18px;">
    ++<div id="doc-content" style="position:relative;">
    ++<div id="mainBodyFluid">
    ++<H2>
    ++Class android.support.v14.preference.<A HREF="../../../../reference/android/support/v14/preference/PreferenceFragment.html" target="_top"><font size="+2"><code>PreferenceFragment</code></font></A>
    ++</H2>
    ++<p><font xsize="+1">Added interface <code>android.support.v7.preference.DialogPreference.TargetFragment</code>.<br></font>
    ++<a NAME="constructors"></a>
    ++<a NAME="methods"></a>
    ++<a NAME="fields"></a>
    ++      </div>	
    ++      <div id="footer">
    ++        <div id="copyright">
    ++        Except as noted, this content is licensed under 
    ++        <a href="http://creativecommons.org/licenses/by/2.5/"> Creative Commons Attribution 2.5</a>.
    ++        For details and restrictions, see the <a href="/license.html">Content License</a>.
    ++        </div>
    ++      <div id="footerlinks">
    ++      <p>
    ++        <a href="http://www.android.com/terms.html">Site Terms of Service</a> -
    ++        <a href="http://www.android.com/privacy.html">Privacy Policy</a> -
    ++        <a href="http://www.android.com/branding.html">Brand Guidelines</a>
    ++      </p>
    ++    </div>
    ++    </div> <!-- end footer -->
    ++    </div><!-- end doc-content -->
    ++    </div> <!-- end body-content --> 
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    ++</script>
    ++<script type="text/javascript">
    ++  try {
    ++    var pageTracker = _gat._getTracker("UA-5831155-1");
    ++    pageTracker._setAllowAnchor(true);
    ++    pageTracker._initData();
    ++    pageTracker._trackPageview();
    ++  } catch(e) {}
    ++</script>
    ++</BODY>
    ++</HTML>
    +diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v17.leanback.widget.AbstractMediaItemPresenter.ViewHolder.html b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v17.leanback.widget.AbstractMediaItemPresenter.ViewHolder.html
    +new file mode 100644
    +index 0000000..9f1f00c
    +--- /dev/null
    ++++ b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v17.leanback.widget.AbstractMediaItemPresenter.ViewHolder.html
    +@@ -0,0 +1,150 @@
    ++<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
    ++<HTML style="overflow:auto;">
    ++<HEAD>
    ++<meta name="generator" content="JDiff v1.1.0">
    ++<!-- Generated by the JDiff Javadoc doclet -->
    ++<!-- (http://www.jdiff.org) -->
    ++<meta name="description" content="JDiff is a Javadoc doclet which generates an HTML report of all the packages, classes, constructors, methods, and fields which have been removed, added or changed in any way, including their documentation, when two APIs are compared.">
    ++<meta name="keywords" content="diff, jdiff, javadiff, java diff, java difference, API difference, difference between two APIs, API diff, Javadoc, doclet">
    ++<TITLE>
    ++android.support.v17.leanback.widget.AbstractMediaItemPresenter.ViewHolder
    ++</TITLE>
    ++<link href="../../../../assets/android-developer-docs.css" rel="stylesheet" type="text/css" />
    ++<link href="../stylesheet-jdiff.css" rel="stylesheet" type="text/css" />
    ++<noscript>
    ++<style type="text/css">
    ++body{overflow:auto;}
    ++#body-content{position:relative; top:0;}
    ++#doc-content{overflow:visible;border-left:3px solid #666;}
    ++#side-nav{padding:0;}
    ++#side-nav .toggle-list ul {display:block;}
    ++#resize-packages-nav{border-bottom:3px solid #666;}
    ++</style>
    ++</noscript>
    ++<style type="text/css">
    ++</style>
    ++</HEAD>
    ++<BODY>
    ++<!-- Start of nav bar -->
    ++<a name="top"></a>
    ++<div id="header" style="margin-bottom:0;padding-bottom:0;">
    ++<div id="headerLeft">
    ++<a href="../../../../index.html" tabindex="-1" target="_top"><img src="../../../../assets/images/bg_logo.png" alt="Android Developers" /></a>
    ++</div>
    ++  <div id="headerRight">
    ++  <div id="headerLinks">
    ++<!-- <img src="/assets/images/icon_world.jpg" alt="" /> -->
    ++<span class="text">
    ++<!-- &nbsp;<a href="#">English</a> | -->
    ++<nobr><a href="http://developer.android.com" target="_top">Android Developers</a> | <a href="http://www.android.com" target="_top">Android.com</a></nobr>
    ++</span>
    ++</div>
    ++  <div class="and-diff-id" style="margin-top:6px;margin-right:8px;">
    ++    <table class="diffspectable">
    ++      <tr>
    ++        <td colspan="2" class="diffspechead">API Diff Specification</td>
    ++      </tr>
    ++      <tr>
    ++        <td class="diffspec" style="padding-top:.25em">To Level:</td>
    ++        <td class="diffvaluenew" style="padding-top:.25em">24.2.0</td>
    ++      </tr>
    ++      <tr>
    ++        <td class="diffspec">From Level:</td>
    ++        <td class="diffvalueold">24.1.0</td>
    ++      </tr>
    ++      <tr>
    ++        <td class="diffspec">Generated</td>
    ++        <td class="diffvalue">2016.08.16 14:03</td>
    ++      </tr>
    ++    </table>
    ++    </div><!-- End and-diff-id -->
    ++  <div class="and-diff-id" style="margin-right:8px;">
    ++    <table class="diffspectable">
    ++      <tr>
    ++        <td class="diffspec" colspan="2"><a href="jdiff_statistics.html">Statistics</a>
    ++      </tr>
    ++    </table>
    ++  </div> <!-- End and-diff-id -->
    ++  </div> <!-- End headerRight -->
    ++  </div> <!-- End header -->
    ++<div id="body-content" xstyle="padding:12px;padding-right:18px;">
    ++<div id="doc-content" style="position:relative;">
    ++<div id="mainBodyFluid">
    ++<H2>
    ++Class android.support.v17.leanback.widget.<A HREF="../../../../reference/android/support/v17/leanback/widget/AbstractMediaItemPresenter.ViewHolder.html" target="_top"><font size="+2"><code>AbstractMediaItemPresenter.ViewHolder</code></font></A>
    ++</H2>
    ++<a NAME="constructors"></a>
    ++<a NAME="methods"></a>
    ++<p>
    ++<a NAME="Added"></a>
    ++<TABLE summary="Added Methods" WIDTH="100%">
    ++<TR>
    ++  <TH VALIGN="TOP" COLSPAN=2>Added Methods</FONT></TD>
    ++</TH>
    ++<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    ++  <TD VALIGN="TOP" WIDTH="25%">
    ++  <A NAME="android.support.v17.leanback.widget.AbstractMediaItemPresenter.ViewHolder.getMediaItemNumberViewFlipper_added()"></A>
    ++  <nobr><code>ViewFlipper</code>&nbsp;<A HREF="../../../../reference/android/support/v17/leanback/widget/AbstractMediaItemPresenter.ViewHolder.html#getMediaItemNumberViewFlipper()" target="_top"><code>getMediaItemNumberViewFlipper</code></A>()</nobr>
    ++  </TD>
    ++  <TD>&nbsp;</TD>
    ++</TR>
    ++<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    ++  <TD VALIGN="TOP" WIDTH="25%">
    ++  <A NAME="android.support.v17.leanback.widget.AbstractMediaItemPresenter.ViewHolder.getMediaItemPausedView_added()"></A>
    ++  <nobr><code>View</code>&nbsp;<A HREF="../../../../reference/android/support/v17/leanback/widget/AbstractMediaItemPresenter.ViewHolder.html#getMediaItemPausedView()" target="_top"><code>getMediaItemPausedView</code></A>()</nobr>
    ++  </TD>
    ++  <TD>&nbsp;</TD>
    ++</TR>
    ++<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    ++  <TD VALIGN="TOP" WIDTH="25%">
    ++  <A NAME="android.support.v17.leanback.widget.AbstractMediaItemPresenter.ViewHolder.getMediaItemPlayingView_added()"></A>
    ++  <nobr><code>View</code>&nbsp;<A HREF="../../../../reference/android/support/v17/leanback/widget/AbstractMediaItemPresenter.ViewHolder.html#getMediaItemPlayingView()" target="_top"><code>getMediaItemPlayingView</code></A>()</nobr>
    ++  </TD>
    ++  <TD>&nbsp;</TD>
    ++</TR>
    ++<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    ++  <TD VALIGN="TOP" WIDTH="25%">
    ++  <A NAME="android.support.v17.leanback.widget.AbstractMediaItemPresenter.ViewHolder.notifyPlayStateChanged_added()"></A>
    ++  <nobr><code>void</code>&nbsp;<A HREF="../../../../reference/android/support/v17/leanback/widget/AbstractMediaItemPresenter.ViewHolder.html#notifyPlayStateChanged()" target="_top"><code>notifyPlayStateChanged</code></A>()</nobr>
    ++  </TD>
    ++  <TD>&nbsp;</TD>
    ++</TR>
    ++<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    ++  <TD VALIGN="TOP" WIDTH="25%">
    ++  <A NAME="android.support.v17.leanback.widget.AbstractMediaItemPresenter.ViewHolder.setSelectedMediaItemNumberView_added(int)"></A>
    ++  <nobr><code>void</code>&nbsp;<A HREF="../../../../reference/android/support/v17/leanback/widget/AbstractMediaItemPresenter.ViewHolder.html#setSelectedMediaItemNumberView(int)" target="_top"><code>setSelectedMediaItemNumberView</code></A>(<code>int</code>)</nobr>
    ++  </TD>
    ++  <TD>&nbsp;</TD>
    ++</TR>
    ++</TABLE>
    ++&nbsp;
    ++<a NAME="fields"></a>
    ++      </div>	
    ++      <div id="footer">
    ++        <div id="copyright">
    ++        Except as noted, this content is licensed under 
    ++        <a href="http://creativecommons.org/licenses/by/2.5/"> Creative Commons Attribution 2.5</a>.
    ++        For details and restrictions, see the <a href="/license.html">Content License</a>.
    ++        </div>
    ++      <div id="footerlinks">
    ++      <p>
    ++        <a href="http://www.android.com/terms.html">Site Terms of Service</a> -
    ++        <a href="http://www.android.com/privacy.html">Privacy Policy</a> -
    ++        <a href="http://www.android.com/branding.html">Brand Guidelines</a>
    ++      </p>
    ++    </div>
    ++    </div> <!-- end footer -->
    ++    </div><!-- end doc-content -->
    ++    </div> <!-- end body-content --> 
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    ++</script>
    ++<script type="text/javascript">
    ++  try {
    ++    var pageTracker = _gat._getTracker("UA-5831155-1");
    ++    pageTracker._setAllowAnchor(true);
    ++    pageTracker._initData();
    ++    pageTracker._trackPageview();
    ++  } catch(e) {}
    ++</script>
    ++</BODY>
    ++</HTML>
    +diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v17.leanback.widget.AbstractMediaItemPresenter.html b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v17.leanback.widget.AbstractMediaItemPresenter.html
    +new file mode 100644
    +index 0000000..a0b0aa9
    +--- /dev/null
    ++++ b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v17.leanback.widget.AbstractMediaItemPresenter.html
    +@@ -0,0 +1,165 @@
    ++<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
    ++<HTML style="overflow:auto;">
    ++<HEAD>
    ++<meta name="generator" content="JDiff v1.1.0">
    ++<!-- Generated by the JDiff Javadoc doclet -->
    ++<!-- (http://www.jdiff.org) -->
    ++<meta name="description" content="JDiff is a Javadoc doclet which generates an HTML report of all the packages, classes, constructors, methods, and fields which have been removed, added or changed in any way, including their documentation, when two APIs are compared.">
    ++<meta name="keywords" content="diff, jdiff, javadiff, java diff, java difference, API difference, difference between two APIs, API diff, Javadoc, doclet">
    ++<TITLE>
    ++android.support.v17.leanback.widget.AbstractMediaItemPresenter
    ++</TITLE>
    ++<link href="../../../../assets/android-developer-docs.css" rel="stylesheet" type="text/css" />
    ++<link href="../stylesheet-jdiff.css" rel="stylesheet" type="text/css" />
    ++<noscript>
    ++<style type="text/css">
    ++body{overflow:auto;}
    ++#body-content{position:relative; top:0;}
    ++#doc-content{overflow:visible;border-left:3px solid #666;}
    ++#side-nav{padding:0;}
    ++#side-nav .toggle-list ul {display:block;}
    ++#resize-packages-nav{border-bottom:3px solid #666;}
    ++</style>
    ++</noscript>
    ++<style type="text/css">
    ++</style>
    ++</HEAD>
    ++<BODY>
    ++<!-- Start of nav bar -->
    ++<a name="top"></a>
    ++<div id="header" style="margin-bottom:0;padding-bottom:0;">
    ++<div id="headerLeft">
    ++<a href="../../../../index.html" tabindex="-1" target="_top"><img src="../../../../assets/images/bg_logo.png" alt="Android Developers" /></a>
    ++</div>
    ++  <div id="headerRight">
    ++  <div id="headerLinks">
    ++<!-- <img src="/assets/images/icon_world.jpg" alt="" /> -->
    ++<span class="text">
    ++<!-- &nbsp;<a href="#">English</a> | -->
    ++<nobr><a href="http://developer.android.com" target="_top">Android Developers</a> | <a href="http://www.android.com" target="_top">Android.com</a></nobr>
    ++</span>
    ++</div>
    ++  <div class="and-diff-id" style="margin-top:6px;margin-right:8px;">
    ++    <table class="diffspectable">
    ++      <tr>
    ++        <td colspan="2" class="diffspechead">API Diff Specification</td>
    ++      </tr>
    ++      <tr>
    ++        <td class="diffspec" style="padding-top:.25em">To Level:</td>
    ++        <td class="diffvaluenew" style="padding-top:.25em">24.2.0</td>
    ++      </tr>
    ++      <tr>
    ++        <td class="diffspec">From Level:</td>
    ++        <td class="diffvalueold">24.1.0</td>
    ++      </tr>
    ++      <tr>
    ++        <td class="diffspec">Generated</td>
    ++        <td class="diffvalue">2016.08.16 14:03</td>
    ++      </tr>
    ++    </table>
    ++    </div><!-- End and-diff-id -->
    ++  <div class="and-diff-id" style="margin-right:8px;">
    ++    <table class="diffspectable">
    ++      <tr>
    ++        <td class="diffspec" colspan="2"><a href="jdiff_statistics.html">Statistics</a>
    ++      </tr>
    ++    </table>
    ++  </div> <!-- End and-diff-id -->
    ++  </div> <!-- End headerRight -->
    ++  </div> <!-- End header -->
    ++<div id="body-content" xstyle="padding:12px;padding-right:18px;">
    ++<div id="doc-content" style="position:relative;">
    ++<div id="mainBodyFluid">
    ++<H2>
    ++Class android.support.v17.leanback.widget.<A HREF="../../../../reference/android/support/v17/leanback/widget/AbstractMediaItemPresenter.html" target="_top"><font size="+2"><code>AbstractMediaItemPresenter</code></font></A>
    ++</H2>
    ++<a NAME="constructors"></a>
    ++<a NAME="methods"></a>
    ++<p>
    ++<a NAME="Added"></a>
    ++<TABLE summary="Added Methods" WIDTH="100%">
    ++<TR>
    ++  <TH VALIGN="TOP" COLSPAN=2>Added Methods</FONT></TD>
    ++</TH>
    ++<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    ++  <TD VALIGN="TOP" WIDTH="25%">
    ++  <A NAME="android.support.v17.leanback.widget.AbstractMediaItemPresenter.getMediaPlayState_added(java.lang.Object)"></A>
    ++  <nobr><code>int</code>&nbsp;<A HREF="../../../../reference/android/support/v17/leanback/widget/AbstractMediaItemPresenter.html#getMediaPlayState(java.lang.Object)" target="_top"><code>getMediaPlayState</code></A>(<code>Object</code>)</nobr>
    ++  </TD>
    ++  <TD>&nbsp;</TD>
    ++</TR>
    ++<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    ++  <TD VALIGN="TOP" WIDTH="25%">
    ++  <A NAME="android.support.v17.leanback.widget.AbstractMediaItemPresenter.onBindMediaPlayState_added(android.support.v17.leanback.widget.AbstractMediaItemPresenter.ViewHolder)"></A>
    ++  <nobr><code>void</code>&nbsp;<A HREF="../../../../reference/android/support/v17/leanback/widget/AbstractMediaItemPresenter.html#onBindMediaPlayState(android.support.v17.leanback.widget.AbstractMediaItemPresenter.ViewHolder)" target="_top"><code>onBindMediaPlayState</code></A>(<code>ViewHolder</code>)</nobr>
    ++  </TD>
    ++  <TD>&nbsp;</TD>
    ++</TR>
    ++<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    ++  <TD VALIGN="TOP" WIDTH="25%">
    ++  <A NAME="android.support.v17.leanback.widget.AbstractMediaItemPresenter.onUnbindMediaPlayState_added(android.support.v17.leanback.widget.AbstractMediaItemPresenter.ViewHolder)"></A>
    ++  <nobr><code>void</code>&nbsp;<A HREF="../../../../reference/android/support/v17/leanback/widget/AbstractMediaItemPresenter.html#onUnbindMediaPlayState(android.support.v17.leanback.widget.AbstractMediaItemPresenter.ViewHolder)" target="_top"><code>onUnbindMediaPlayState</code></A>(<code>ViewHolder</code>)</nobr>
    ++  </TD>
    ++  <TD>&nbsp;</TD>
    ++</TR>
    ++</TABLE>
    ++&nbsp;
    ++<a NAME="fields"></a>
    ++<p>
    ++<a NAME="Added"></a>
    ++<TABLE summary="Added Fields" WIDTH="100%">
    ++<TR>
    ++  <TH VALIGN="TOP" COLSPAN=2>Added Fields</FONT></TD>
    ++</TH>
    ++<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    ++  <TD VALIGN="TOP" WIDTH="25%">
    ++  <A NAME="android.support.v17.leanback.widget.AbstractMediaItemPresenter.PLAY_STATE_INITIAL"></A>
    ++  <nobr><code>int</code>&nbsp;<A HREF="../../../../reference/android/support/v17/leanback/widget/AbstractMediaItemPresenter.html#PLAY_STATE_INITIAL" target="_top"><code>PLAY_STATE_INITIAL</code></A></nobr>
    ++  </TD>
    ++  <TD>&nbsp;</TD>
    ++</TR>
    ++<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    ++  <TD VALIGN="TOP" WIDTH="25%">
    ++  <A NAME="android.support.v17.leanback.widget.AbstractMediaItemPresenter.PLAY_STATE_PAUSED"></A>
    ++  <nobr><code>int</code>&nbsp;<A HREF="../../../../reference/android/support/v17/leanback/widget/AbstractMediaItemPresenter.html#PLAY_STATE_PAUSED" target="_top"><code>PLAY_STATE_PAUSED</code></A></nobr>
    ++  </TD>
    ++  <TD>&nbsp;</TD>
    ++</TR>
    ++<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    ++  <TD VALIGN="TOP" WIDTH="25%">
    ++  <A NAME="android.support.v17.leanback.widget.AbstractMediaItemPresenter.PLAY_STATE_PLAYING"></A>
    ++  <nobr><code>int</code>&nbsp;<A HREF="../../../../reference/android/support/v17/leanback/widget/AbstractMediaItemPresenter.html#PLAY_STATE_PLAYING" target="_top"><code>PLAY_STATE_PLAYING</code></A></nobr>
    ++  </TD>
    ++  <TD>&nbsp;</TD>
    ++</TR>
    ++</TABLE>
    ++&nbsp;
    ++      </div>	
    ++      <div id="footer">
    ++        <div id="copyright">
    ++        Except as noted, this content is licensed under 
    ++        <a href="http://creativecommons.org/licenses/by/2.5/"> Creative Commons Attribution 2.5</a>.
    ++        For details and restrictions, see the <a href="/license.html">Content License</a>.
    ++        </div>
    ++      <div id="footerlinks">
    ++      <p>
    ++        <a href="http://www.android.com/terms.html">Site Terms of Service</a> -
    ++        <a href="http://www.android.com/privacy.html">Privacy Policy</a> -
    ++        <a href="http://www.android.com/branding.html">Brand Guidelines</a>
    ++      </p>
    ++    </div>
    ++    </div> <!-- end footer -->
    ++    </div><!-- end doc-content -->
    ++    </div> <!-- end body-content --> 
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    ++</script>
    ++<script type="text/javascript">
    ++  try {
    ++    var pageTracker = _gat._getTracker("UA-5831155-1");
    ++    pageTracker._setAllowAnchor(true);
    ++    pageTracker._initData();
    ++    pageTracker._trackPageview();
    ++  } catch(e) {}
    ++</script>
    ++</BODY>
    ++</HTML>
    +diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v17.leanback.widget.ObjectAdapter.html b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v17.leanback.widget.ObjectAdapter.html
    +new file mode 100644
    +index 0000000..3dad1a2
    +--- /dev/null
    ++++ b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v17.leanback.widget.ObjectAdapter.html
    +@@ -0,0 +1,122 @@
    ++<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
    ++<HTML style="overflow:auto;">
    ++<HEAD>
    ++<meta name="generator" content="JDiff v1.1.0">
    ++<!-- Generated by the JDiff Javadoc doclet -->
    ++<!-- (http://www.jdiff.org) -->
    ++<meta name="description" content="JDiff is a Javadoc doclet which generates an HTML report of all the packages, classes, constructors, methods, and fields which have been removed, added or changed in any way, including their documentation, when two APIs are compared.">
    ++<meta name="keywords" content="diff, jdiff, javadiff, java diff, java difference, API difference, difference between two APIs, API diff, Javadoc, doclet">
    ++<TITLE>
    ++android.support.v17.leanback.widget.ObjectAdapter
    ++</TITLE>
    ++<link href="../../../../assets/android-developer-docs.css" rel="stylesheet" type="text/css" />
    ++<link href="../stylesheet-jdiff.css" rel="stylesheet" type="text/css" />
    ++<noscript>
    ++<style type="text/css">
    ++body{overflow:auto;}
    ++#body-content{position:relative; top:0;}
    ++#doc-content{overflow:visible;border-left:3px solid #666;}
    ++#side-nav{padding:0;}
    ++#side-nav .toggle-list ul {display:block;}
    ++#resize-packages-nav{border-bottom:3px solid #666;}
    ++</style>
    ++</noscript>
    ++<style type="text/css">
    ++</style>
    ++</HEAD>
    ++<BODY>
    ++<!-- Start of nav bar -->
    ++<a name="top"></a>
    ++<div id="header" style="margin-bottom:0;padding-bottom:0;">
    ++<div id="headerLeft">
    ++<a href="../../../../index.html" tabindex="-1" target="_top"><img src="../../../../assets/images/bg_logo.png" alt="Android Developers" /></a>
    ++</div>
    ++  <div id="headerRight">
    ++  <div id="headerLinks">
    ++<!-- <img src="/assets/images/icon_world.jpg" alt="" /> -->
    ++<span class="text">
    ++<!-- &nbsp;<a href="#">English</a> | -->
    ++<nobr><a href="http://developer.android.com" target="_top">Android Developers</a> | <a href="http://www.android.com" target="_top">Android.com</a></nobr>
    ++</span>
    ++</div>
    ++  <div class="and-diff-id" style="margin-top:6px;margin-right:8px;">
    ++    <table class="diffspectable">
    ++      <tr>
    ++        <td colspan="2" class="diffspechead">API Diff Specification</td>
    ++      </tr>
    ++      <tr>
    ++        <td class="diffspec" style="padding-top:.25em">To Level:</td>
    ++        <td class="diffvaluenew" style="padding-top:.25em">24.2.0</td>
    ++      </tr>
    ++      <tr>
    ++        <td class="diffspec">From Level:</td>
    ++        <td class="diffvalueold">24.1.0</td>
    ++      </tr>
    ++      <tr>
    ++        <td class="diffspec">Generated</td>
    ++        <td class="diffvalue">2016.08.16 14:03</td>
    ++      </tr>
    ++    </table>
    ++    </div><!-- End and-diff-id -->
    ++  <div class="and-diff-id" style="margin-right:8px;">
    ++    <table class="diffspectable">
    ++      <tr>
    ++        <td class="diffspec" colspan="2"><a href="jdiff_statistics.html">Statistics</a>
    ++      </tr>
    ++    </table>
    ++  </div> <!-- End and-diff-id -->
    ++  </div> <!-- End headerRight -->
    ++  </div> <!-- End header -->
    ++<div id="body-content" xstyle="padding:12px;padding-right:18px;">
    ++<div id="doc-content" style="position:relative;">
    ++<div id="mainBodyFluid">
    ++<H2>
    ++Class android.support.v17.leanback.widget.<A HREF="../../../../reference/android/support/v17/leanback/widget/ObjectAdapter.html" target="_top"><font size="+2"><code>ObjectAdapter</code></font></A>
    ++</H2>
    ++<a NAME="constructors"></a>
    ++<a NAME="methods"></a>
    ++<p>
    ++<a NAME="Added"></a>
    ++<TABLE summary="Added Methods" WIDTH="100%">
    ++<TR>
    ++  <TH VALIGN="TOP" COLSPAN=2>Added Methods</FONT></TD>
    ++</TH>
    ++<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    ++  <TD VALIGN="TOP" WIDTH="25%">
    ++  <A NAME="android.support.v17.leanback.widget.ObjectAdapter.isImmediateNotifySupported_added()"></A>
    ++  <nobr><code>boolean</code>&nbsp;<A HREF="../../../../reference/android/support/v17/leanback/widget/ObjectAdapter.html#isImmediateNotifySupported()" target="_top"><code>isImmediateNotifySupported</code></A>()</nobr>
    ++  </TD>
    ++  <TD>&nbsp;</TD>
    ++</TR>
    ++</TABLE>
    ++&nbsp;
    ++<a NAME="fields"></a>
    ++      </div>	
    ++      <div id="footer">
    ++        <div id="copyright">
    ++        Except as noted, this content is licensed under 
    ++        <a href="http://creativecommons.org/licenses/by/2.5/"> Creative Commons Attribution 2.5</a>.
    ++        For details and restrictions, see the <a href="/license.html">Content License</a>.
    ++        </div>
    ++      <div id="footerlinks">
    ++      <p>
    ++        <a href="http://www.android.com/terms.html">Site Terms of Service</a> -
    ++        <a href="http://www.android.com/privacy.html">Privacy Policy</a> -
    ++        <a href="http://www.android.com/branding.html">Brand Guidelines</a>
    ++      </p>
    ++    </div>
    ++    </div> <!-- end footer -->
    ++    </div><!-- end doc-content -->
    ++    </div> <!-- end body-content --> 
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    ++</script>
    ++<script type="text/javascript">
    ++  try {
    ++    var pageTracker = _gat._getTracker("UA-5831155-1");
    ++    pageTracker._setAllowAnchor(true);
    ++    pageTracker._initData();
    ++    pageTracker._trackPageview();
    ++  } catch(e) {}
    ++</script>
    ++</BODY>
    ++</HTML>
    +diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v17.preference.LeanbackSettingsFragment.html b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v17.preference.LeanbackSettingsFragment.html
    +new file mode 100644
    +index 0000000..690328a
    +--- /dev/null
    ++++ b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v17.preference.LeanbackSettingsFragment.html
    +@@ -0,0 +1,108 @@
    ++<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
    ++<HTML style="overflow:auto;">
    ++<HEAD>
    ++<meta name="generator" content="JDiff v1.1.0">
    ++<!-- Generated by the JDiff Javadoc doclet -->
    ++<!-- (http://www.jdiff.org) -->
    ++<meta name="description" content="JDiff is a Javadoc doclet which generates an HTML report of all the packages, classes, constructors, methods, and fields which have been removed, added or changed in any way, including their documentation, when two APIs are compared.">
    ++<meta name="keywords" content="diff, jdiff, javadiff, java diff, java difference, API difference, difference between two APIs, API diff, Javadoc, doclet">
    ++<TITLE>
    ++android.support.v17.preference.LeanbackSettingsFragment
    ++</TITLE>
    ++<link href="../../../../assets/android-developer-docs.css" rel="stylesheet" type="text/css" />
    ++<link href="../stylesheet-jdiff.css" rel="stylesheet" type="text/css" />
    ++<noscript>
    ++<style type="text/css">
    ++body{overflow:auto;}
    ++#body-content{position:relative; top:0;}
    ++#doc-content{overflow:visible;border-left:3px solid #666;}
    ++#side-nav{padding:0;}
    ++#side-nav .toggle-list ul {display:block;}
    ++#resize-packages-nav{border-bottom:3px solid #666;}
    ++</style>
    ++</noscript>
    ++<style type="text/css">
    ++</style>
    ++</HEAD>
    ++<BODY>
    ++<!-- Start of nav bar -->
    ++<a name="top"></a>
    ++<div id="header" style="margin-bottom:0;padding-bottom:0;">
    ++<div id="headerLeft">
    ++<a href="../../../../index.html" tabindex="-1" target="_top"><img src="../../../../assets/images/bg_logo.png" alt="Android Developers" /></a>
    ++</div>
    ++  <div id="headerRight">
    ++  <div id="headerLinks">
    ++<!-- <img src="/assets/images/icon_world.jpg" alt="" /> -->
    ++<span class="text">
    ++<!-- &nbsp;<a href="#">English</a> | -->
    ++<nobr><a href="http://developer.android.com" target="_top">Android Developers</a> | <a href="http://www.android.com" target="_top">Android.com</a></nobr>
    ++</span>
    ++</div>
    ++  <div class="and-diff-id" style="margin-top:6px;margin-right:8px;">
    ++    <table class="diffspectable">
    ++      <tr>
    ++        <td colspan="2" class="diffspechead">API Diff Specification</td>
    ++      </tr>
    ++      <tr>
    ++        <td class="diffspec" style="padding-top:.25em">To Level:</td>
    ++        <td class="diffvaluenew" style="padding-top:.25em">24.2.0</td>
    ++      </tr>
    ++      <tr>
    ++        <td class="diffspec">From Level:</td>
    ++        <td class="diffvalueold">24.1.0</td>
    ++      </tr>
    ++      <tr>
    ++        <td class="diffspec">Generated</td>
    ++        <td class="diffvalue">2016.08.16 14:03</td>
    ++      </tr>
    ++    </table>
    ++    </div><!-- End and-diff-id -->
    ++  <div class="and-diff-id" style="margin-right:8px;">
    ++    <table class="diffspectable">
    ++      <tr>
    ++        <td class="diffspec" colspan="2"><a href="jdiff_statistics.html">Statistics</a>
    ++      </tr>
    ++    </table>
    ++  </div> <!-- End and-diff-id -->
    ++  </div> <!-- End headerRight -->
    ++  </div> <!-- End header -->
    ++<div id="body-content" xstyle="padding:12px;padding-right:18px;">
    ++<div id="doc-content" style="position:relative;">
    ++<div id="mainBodyFluid">
    ++<H2>
    ++Class android.support.v17.preference.<A HREF="../../../../reference/android/support/v17/preference/LeanbackSettingsFragment.html" target="_top"><font size="+2"><code>LeanbackSettingsFragment</code></font></A>
    ++</H2>
    ++<p><font xsize="+1">Added interfaces <code>android.support.v14.preference.PreferenceFragment.OnPreferenceDisplayDialogCallback, android.support.v14.preference.PreferenceFragment.OnPreferenceStartFragmentCallback, android.support.v14.preference.PreferenceFragment.OnPreferenceStartScreenCallback</code>.<br></font>
    ++<a NAME="constructors"></a>
    ++<a NAME="methods"></a>
    ++<a NAME="fields"></a>
    ++      </div>	
    ++      <div id="footer">
    ++        <div id="copyright">
    ++        Except as noted, this content is licensed under 
    ++        <a href="http://creativecommons.org/licenses/by/2.5/"> Creative Commons Attribution 2.5</a>.
    ++        For details and restrictions, see the <a href="/license.html">Content License</a>.
    ++        </div>
    ++      <div id="footerlinks">
    ++      <p>
    ++        <a href="http://www.android.com/terms.html">Site Terms of Service</a> -
    ++        <a href="http://www.android.com/privacy.html">Privacy Policy</a> -
    ++        <a href="http://www.android.com/branding.html">Brand Guidelines</a>
    ++      </p>
    ++    </div>
    ++    </div> <!-- end footer -->
    ++    </div><!-- end doc-content -->
    ++    </div> <!-- end body-content --> 
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    ++</script>
    ++<script type="text/javascript">
    ++  try {
    ++    var pageTracker = _gat._getTracker("UA-5831155-1");
    ++    pageTracker._setAllowAnchor(true);
    ++    pageTracker._initData();
    ++    pageTracker._trackPageview();
    ++  } catch(e) {}
    ++</script>
    ++</BODY>
    ++</HTML>
    +diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.accessibilityservice.AccessibilityServiceInfoCompat.html b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.accessibilityservice.AccessibilityServiceInfoCompat.html
    +new file mode 100644
    +index 0000000..a353745
    +--- /dev/null
    ++++ b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.accessibilityservice.AccessibilityServiceInfoCompat.html
    +@@ -0,0 +1,140 @@
    ++<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
    ++<HTML style="overflow:auto;">
    ++<HEAD>
    ++<meta name="generator" content="JDiff v1.1.0">
    ++<!-- Generated by the JDiff Javadoc doclet -->
    ++<!-- (http://www.jdiff.org) -->
    ++<meta name="description" content="JDiff is a Javadoc doclet which generates an HTML report of all the packages, classes, constructors, methods, and fields which have been removed, added or changed in any way, including their documentation, when two APIs are compared.">
    ++<meta name="keywords" content="diff, jdiff, javadiff, java diff, java difference, API difference, difference between two APIs, API diff, Javadoc, doclet">
    ++<TITLE>
    ++android.support.v4.accessibilityservice.AccessibilityServiceInfoCompat
    ++</TITLE>
    ++<link href="../../../../assets/android-developer-docs.css" rel="stylesheet" type="text/css" />
    ++<link href="../stylesheet-jdiff.css" rel="stylesheet" type="text/css" />
    ++<noscript>
    ++<style type="text/css">
    ++body{overflow:auto;}
    ++#body-content{position:relative; top:0;}
    ++#doc-content{overflow:visible;border-left:3px solid #666;}
    ++#side-nav{padding:0;}
    ++#side-nav .toggle-list ul {display:block;}
    ++#resize-packages-nav{border-bottom:3px solid #666;}
    ++</style>
    ++</noscript>
    ++<style type="text/css">
    ++</style>
    ++</HEAD>
    ++<BODY>
    ++<!-- Start of nav bar -->
    ++<a name="top"></a>
    ++<div id="header" style="margin-bottom:0;padding-bottom:0;">
    ++<div id="headerLeft">
    ++<a href="../../../../index.html" tabindex="-1" target="_top"><img src="../../../../assets/images/bg_logo.png" alt="Android Developers" /></a>
    ++</div>
    ++  <div id="headerRight">
    ++  <div id="headerLinks">
    ++<!-- <img src="/assets/images/icon_world.jpg" alt="" /> -->
    ++<span class="text">
    ++<!-- &nbsp;<a href="#">English</a> | -->
    ++<nobr><a href="http://developer.android.com" target="_top">Android Developers</a> | <a href="http://www.android.com" target="_top">Android.com</a></nobr>
    ++</span>
    ++</div>
    ++  <div class="and-diff-id" style="margin-top:6px;margin-right:8px;">
    ++    <table class="diffspectable">
    ++      <tr>
    ++        <td colspan="2" class="diffspechead">API Diff Specification</td>
    ++      </tr>
    ++      <tr>
    ++        <td class="diffspec" style="padding-top:.25em">To Level:</td>
    ++        <td class="diffvaluenew" style="padding-top:.25em">24.2.0</td>
    ++      </tr>
    ++      <tr>
    ++        <td class="diffspec">From Level:</td>
    ++        <td class="diffvalueold">24.1.0</td>
    ++      </tr>
    ++      <tr>
    ++        <td class="diffspec">Generated</td>
    ++        <td class="diffvalue">2016.08.16 14:03</td>
    ++      </tr>
    ++    </table>
    ++    </div><!-- End and-diff-id -->
    ++  <div class="and-diff-id" style="margin-right:8px;">
    ++    <table class="diffspectable">
    ++      <tr>
    ++        <td class="diffspec" colspan="2"><a href="jdiff_statistics.html">Statistics</a>
    ++      </tr>
    ++    </table>
    ++  </div> <!-- End and-diff-id -->
    ++  </div> <!-- End headerRight -->
    ++  </div> <!-- End header -->
    ++<div id="body-content" xstyle="padding:12px;padding-right:18px;">
    ++<div id="doc-content" style="position:relative;">
    ++<div id="mainBodyFluid">
    ++<H2>
    ++Class android.support.v4.accessibilityservice.<A HREF="../../../../reference/android/support/v4/accessibilityservice/AccessibilityServiceInfoCompat.html" target="_top"><font size="+2"><code>AccessibilityServiceInfoCompat</code></font></A>
    ++</H2>
    ++<a NAME="constructors"></a>
    ++<a NAME="methods"></a>
    ++<p>
    ++<a NAME="Added"></a>
    ++<TABLE summary="Added Methods" WIDTH="100%">
    ++<TR>
    ++  <TH VALIGN="TOP" COLSPAN=2>Added Methods</FONT></TD>
    ++</TH>
    ++<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    ++  <TD VALIGN="TOP" WIDTH="25%">
    ++  <A NAME="android.support.v4.accessibilityservice.AccessibilityServiceInfoCompat.loadDescription_added(android.accessibilityservice.AccessibilityServiceInfo, android.content.pm.PackageManager)"></A>
    ++  <nobr><code>String</code>&nbsp;<A HREF="../../../../reference/android/support/v4/accessibilityservice/AccessibilityServiceInfoCompat.html#loadDescription(android.accessibilityservice.AccessibilityServiceInfo, android.content.pm.PackageManager)" target="_top"><code>loadDescription</code></A>(<code>AccessibilityServiceInfo,</nobr> PackageManager<nobr><nobr></code>)</nobr>
    ++  </TD>
    ++  <TD>&nbsp;</TD>
    ++</TR>
    ++</TABLE>
    ++&nbsp;
    ++<p>
    ++<a NAME="Changed"></a>
    ++<TABLE summary="Changed Methods" WIDTH="100%">
    ++<TR>
    ++  <TH VALIGN="TOP" COLSPAN=3>Changed Methods</FONT></TD>
    ++</TH>
    ++<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    ++  <TD VALIGN="TOP" WIDTH="25%">
    ++  <A NAME="android.support.v4.accessibilityservice.AccessibilityServiceInfoCompat.getDescription_changed(android.accessibilityservice.AccessibilityServiceInfo)"></A>
    ++  <nobr><code>String</code>&nbsp;<A HREF="../../../../reference/android/support/v4/accessibilityservice/AccessibilityServiceInfoCompat.html#getDescription(android.accessibilityservice.AccessibilityServiceInfo)" target="_top"><code>getDescription</code></A>(<code>AccessibilityServiceInfo</code>)  </nobr>
    ++  </TD>
    ++  <TD VALIGN="TOP" WIDTH="30%">
    ++<b>Now deprecated</b>.<br>
    ++  </TD>
    ++  <TD>&nbsp;</TD>
    ++</TR>
    ++</TABLE>
    ++&nbsp;
    ++<a NAME="fields"></a>
    ++      </div>	
    ++      <div id="footer">
    ++        <div id="copyright">
    ++        Except as noted, this content is licensed under 
    ++        <a href="http://creativecommons.org/licenses/by/2.5/"> Creative Commons Attribution 2.5</a>.
    ++        For details and restrictions, see the <a href="/license.html">Content License</a>.
    ++        </div>
    ++      <div id="footerlinks">
    ++      <p>
    ++        <a href="http://www.android.com/terms.html">Site Terms of Service</a> -
    ++        <a href="http://www.android.com/privacy.html">Privacy Policy</a> -
    ++        <a href="http://www.android.com/branding.html">Brand Guidelines</a>
    ++      </p>
    ++    </div>
    ++    </div> <!-- end footer -->
    ++    </div><!-- end doc-content -->
    ++    </div> <!-- end body-content --> 
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    ++</script>
    ++<script type="text/javascript">
    ++  try {
    ++    var pageTracker = _gat._getTracker("UA-5831155-1");
    ++    pageTracker._setAllowAnchor(true);
    ++    pageTracker._initData();
    ++    pageTracker._trackPageview();
    ++  } catch(e) {}
    ++</script>
    ++</BODY>
    ++</HTML>
    +diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.app.ActivityCompat.html b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.app.ActivityCompat.html
    +new file mode 100644
    +index 0000000..95b4fc6
    +--- /dev/null
    ++++ b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.app.ActivityCompat.html
    +@@ -0,0 +1,143 @@
    ++<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
    ++<HTML style="overflow:auto;">
    ++<HEAD>
    ++<meta name="generator" content="JDiff v1.1.0">
    ++<!-- Generated by the JDiff Javadoc doclet -->
    ++<!-- (http://www.jdiff.org) -->
    ++<meta name="description" content="JDiff is a Javadoc doclet which generates an HTML report of all the packages, classes, constructors, methods, and fields which have been removed, added or changed in any way, including their documentation, when two APIs are compared.">
    ++<meta name="keywords" content="diff, jdiff, javadiff, java diff, java difference, API difference, difference between two APIs, API diff, Javadoc, doclet">
    ++<TITLE>
    ++android.support.v4.app.ActivityCompat
    ++</TITLE>
    ++<link href="../../../../assets/android-developer-docs.css" rel="stylesheet" type="text/css" />
    ++<link href="../stylesheet-jdiff.css" rel="stylesheet" type="text/css" />
    ++<noscript>
    ++<style type="text/css">
    ++body{overflow:auto;}
    ++#body-content{position:relative; top:0;}
    ++#doc-content{overflow:visible;border-left:3px solid #666;}
    ++#side-nav{padding:0;}
    ++#side-nav .toggle-list ul {display:block;}
    ++#resize-packages-nav{border-bottom:3px solid #666;}
    ++</style>
    ++</noscript>
    ++<style type="text/css">
    ++</style>
    ++</HEAD>
    ++<BODY>
    ++<!-- Start of nav bar -->
    ++<a name="top"></a>
    ++<div id="header" style="margin-bottom:0;padding-bottom:0;">
    ++<div id="headerLeft">
    ++<a href="../../../../index.html" tabindex="-1" target="_top"><img src="../../../../assets/images/bg_logo.png" alt="Android Developers" /></a>
    ++</div>
    ++  <div id="headerRight">
    ++  <div id="headerLinks">
    ++<!-- <img src="/assets/images/icon_world.jpg" alt="" /> -->
    ++<span class="text">
    ++<!-- &nbsp;<a href="#">English</a> | -->
    ++<nobr><a href="http://developer.android.com" target="_top">Android Developers</a> | <a href="http://www.android.com" target="_top">Android.com</a></nobr>
    ++</span>
    ++</div>
    ++  <div class="and-diff-id" style="margin-top:6px;margin-right:8px;">
    ++    <table class="diffspectable">
    ++      <tr>
    ++        <td colspan="2" class="diffspechead">API Diff Specification</td>
    ++      </tr>
    ++      <tr>
    ++        <td class="diffspec" style="padding-top:.25em">To Level:</td>
    ++        <td class="diffvaluenew" style="padding-top:.25em">24.2.0</td>
    ++      </tr>
    ++      <tr>
    ++        <td class="diffspec">From Level:</td>
    ++        <td class="diffvalueold">24.1.0</td>
    ++      </tr>
    ++      <tr>
    ++        <td class="diffspec">Generated</td>
    ++        <td class="diffvalue">2016.08.16 14:03</td>
    ++      </tr>
    ++    </table>
    ++    </div><!-- End and-diff-id -->
    ++  <div class="and-diff-id" style="margin-right:8px;">
    ++    <table class="diffspectable">
    ++      <tr>
    ++        <td class="diffspec" colspan="2"><a href="jdiff_statistics.html">Statistics</a>
    ++      </tr>
    ++    </table>
    ++  </div> <!-- End and-diff-id -->
    ++  </div> <!-- End headerRight -->
    ++  </div> <!-- End header -->
    ++<div id="body-content" xstyle="padding:12px;padding-right:18px;">
    ++<div id="doc-content" style="position:relative;">
    ++<div id="mainBodyFluid">
    ++<H2>
    ++Class android.support.v4.app.<A HREF="../../../../reference/android/support/v4/app/ActivityCompat.html" target="_top"><font size="+2"><code>ActivityCompat</code></font></A>
    ++</H2>
    ++<a NAME="constructors"></a>
    ++<p>
    ++<a NAME="Changed"></a>
    ++<TABLE summary="Changed Constructors" WIDTH="100%">
    ++<TR>
    ++  <TH VALIGN="TOP" COLSPAN=3>Changed Constructors</FONT></TD>
    ++</TH>
    ++<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    ++  <TD VALIGN="TOP" WIDTH="25%">
    ++  <A NAME="android.support.v4.app.ActivityCompat.ctor_changed()"></A>
    ++  <nobr><A HREF="../../../../reference/android/support/v4/app/ActivityCompat.html#ActivityCompat()" target="_top"><code>ActivityCompat</code></A>()  </nobr>
    ++  </TD>
    ++  <TD VALIGN="TOP" WIDTH="30%">
    ++<b>Now deprecated</b>.<br>
    ++  </TD>
    ++  <TD>&nbsp;</TD>
    ++</TR>
    ++</TABLE>
    ++&nbsp;
    ++<a NAME="methods"></a>
    ++<p>
    ++<a NAME="Changed"></a>
    ++<TABLE summary="Changed Methods" WIDTH="100%">
    ++<TR>
    ++  <TH VALIGN="TOP" COLSPAN=3>Changed Methods</FONT></TD>
    ++</TH>
    ++<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    ++  <TD VALIGN="TOP" WIDTH="25%">
    ++  <A NAME="android.support.v4.app.ActivityCompat.getReferrer_changed(android.app.Activity)"></A>
    ++  <nobr><code>Uri</code>&nbsp;<A HREF="../../../../reference/android/support/v4/app/ActivityCompat.html#getReferrer(android.app.Activity)" target="_top"><code>getReferrer</code></A>(<code>Activity</code>)  </nobr>
    ++  </TD>
    ++  <TD VALIGN="TOP" WIDTH="30%">
    ++<b>Now deprecated</b>.<br>
    ++  </TD>
    ++  <TD>&nbsp;</TD>
    ++</TR>
    ++</TABLE>
    ++&nbsp;
    ++<a NAME="fields"></a>
    ++      </div>	
    ++      <div id="footer">
    ++        <div id="copyright">
    ++        Except as noted, this content is licensed under 
    ++        <a href="http://creativecommons.org/licenses/by/2.5/"> Creative Commons Attribution 2.5</a>.
    ++        For details and restrictions, see the <a href="/license.html">Content License</a>.
    ++        </div>
    ++      <div id="footerlinks">
    ++      <p>
    ++        <a href="http://www.android.com/terms.html">Site Terms of Service</a> -
    ++        <a href="http://www.android.com/privacy.html">Privacy Policy</a> -
    ++        <a href="http://www.android.com/branding.html">Brand Guidelines</a>
    ++      </p>
    ++    </div>
    ++    </div> <!-- end footer -->
    ++    </div><!-- end doc-content -->
    ++    </div> <!-- end body-content --> 
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    ++</script>
    ++<script type="text/javascript">
    ++  try {
    ++    var pageTracker = _gat._getTracker("UA-5831155-1");
    ++    pageTracker._setAllowAnchor(true);
    ++    pageTracker._initData();
    ++    pageTracker._trackPageview();
    ++  } catch(e) {}
    ++</script>
    ++</BODY>
    ++</HTML>
    +diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.app.ActivityOptionsCompat.html b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.app.ActivityOptionsCompat.html
    +new file mode 100644
    +index 0000000..e675b7f
    +--- /dev/null
    ++++ b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.app.ActivityOptionsCompat.html
    +@@ -0,0 +1,179 @@
    ++<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
    ++<HTML style="overflow:auto;">
    ++<HEAD>
    ++<meta name="generator" content="JDiff v1.1.0">
    ++<!-- Generated by the JDiff Javadoc doclet -->
    ++<!-- (http://www.jdiff.org) -->
    ++<meta name="description" content="JDiff is a Javadoc doclet which generates an HTML report of all the packages, classes, constructors, methods, and fields which have been removed, added or changed in any way, including their documentation, when two APIs are compared.">
    ++<meta name="keywords" content="diff, jdiff, javadiff, java diff, java difference, API difference, difference between two APIs, API diff, Javadoc, doclet">
    ++<TITLE>
    ++android.support.v4.app.ActivityOptionsCompat
    ++</TITLE>
    ++<link href="../../../../assets/android-developer-docs.css" rel="stylesheet" type="text/css" />
    ++<link href="../stylesheet-jdiff.css" rel="stylesheet" type="text/css" />
    ++<noscript>
    ++<style type="text/css">
    ++body{overflow:auto;}
    ++#body-content{position:relative; top:0;}
    ++#doc-content{overflow:visible;border-left:3px solid #666;}
    ++#side-nav{padding:0;}
    ++#side-nav .toggle-list ul {display:block;}
    ++#resize-packages-nav{border-bottom:3px solid #666;}
    ++</style>
    ++</noscript>
    ++<style type="text/css">
    ++</style>
    ++</HEAD>
    ++<BODY>
    ++<!-- Start of nav bar -->
    ++<a name="top"></a>
    ++<div id="header" style="margin-bottom:0;padding-bottom:0;">
    ++<div id="headerLeft">
    ++<a href="../../../../index.html" tabindex="-1" target="_top"><img src="../../../../assets/images/bg_logo.png" alt="Android Developers" /></a>
    ++</div>
    ++  <div id="headerRight">
    ++  <div id="headerLinks">
    ++<!-- <img src="/assets/images/icon_world.jpg" alt="" /> -->
    ++<span class="text">
    ++<!-- &nbsp;<a href="#">English</a> | -->
    ++<nobr><a href="http://developer.android.com" target="_top">Android Developers</a> | <a href="http://www.android.com" target="_top">Android.com</a></nobr>
    ++</span>
    ++</div>
    ++  <div class="and-diff-id" style="margin-top:6px;margin-right:8px;">
    ++    <table class="diffspectable">
    ++      <tr>
    ++        <td colspan="2" class="diffspechead">API Diff Specification</td>
    ++      </tr>
    ++      <tr>
    ++        <td class="diffspec" style="padding-top:.25em">To Level:</td>
    ++        <td class="diffvaluenew" style="padding-top:.25em">24.2.0</td>
    ++      </tr>
    ++      <tr>
    ++        <td class="diffspec">From Level:</td>
    ++        <td class="diffvalueold">24.1.0</td>
    ++      </tr>
    ++      <tr>
    ++        <td class="diffspec">Generated</td>
    ++        <td class="diffvalue">2016.08.16 14:03</td>
    ++      </tr>
    ++    </table>
    ++    </div><!-- End and-diff-id -->
    ++  <div class="and-diff-id" style="margin-right:8px;">
    ++    <table class="diffspectable">
    ++      <tr>
    ++        <td class="diffspec" colspan="2"><a href="jdiff_statistics.html">Statistics</a>
    ++      </tr>
    ++    </table>
    ++  </div> <!-- End and-diff-id -->
    ++  </div> <!-- End headerRight -->
    ++  </div> <!-- End header -->
    ++<div id="body-content" xstyle="padding:12px;padding-right:18px;">
    ++<div id="doc-content" style="position:relative;">
    ++<div id="mainBodyFluid">
    ++<H2>
    ++Class android.support.v4.app.<A HREF="../../../../reference/android/support/v4/app/ActivityOptionsCompat.html" target="_top"><font size="+2"><code>ActivityOptionsCompat</code></font></A>
    ++</H2>
    ++<a NAME="constructors"></a>
    ++<a NAME="methods"></a>
    ++<p>
    ++<a NAME="Added"></a>
    ++<TABLE summary="Added Methods" WIDTH="100%">
    ++<TR>
    ++  <TH VALIGN="TOP" COLSPAN=2>Added Methods</FONT></TD>
    ++</TH>
    ++<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    ++  <TD VALIGN="TOP" WIDTH="25%">
    ++  <A NAME="android.support.v4.app.ActivityOptionsCompat.getLaunchBounds_added()"></A>
    ++  <nobr><code>Rect</code>&nbsp;<A HREF="../../../../reference/android/support/v4/app/ActivityOptionsCompat.html#getLaunchBounds()" target="_top"><code>getLaunchBounds</code></A>()</nobr>
    ++  </TD>
    ++  <TD>&nbsp;</TD>
    ++</TR>
    ++<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    ++  <TD VALIGN="TOP" WIDTH="25%">
    ++  <A NAME="android.support.v4.app.ActivityOptionsCompat.makeBasic_added()"></A>
    ++  <nobr><code>ActivityOptionsCompat</code>&nbsp;<A HREF="../../../../reference/android/support/v4/app/ActivityOptionsCompat.html#makeBasic()" target="_top"><code>makeBasic</code></A>()</nobr>
    ++  </TD>
    ++  <TD>&nbsp;</TD>
    ++</TR>
    ++<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    ++  <TD VALIGN="TOP" WIDTH="25%">
    ++  <A NAME="android.support.v4.app.ActivityOptionsCompat.makeClipRevealAnimation_added(android.view.View, int, int, int, int)"></A>
    ++  <nobr><code>ActivityOptionsCompat</code>&nbsp;<A HREF="../../../../reference/android/support/v4/app/ActivityOptionsCompat.html#makeClipRevealAnimation(android.view.View, int, int, int, int)" target="_top"><code>makeClipRevealAnimation</code></A>(<code>View,</nobr> int<nobr>,</nobr> int<nobr>,</nobr> int<nobr>,</nobr> int<nobr><nobr></code>)</nobr>
    ++  </TD>
    ++  <TD>&nbsp;</TD>
    ++</TR>
    ++<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    ++  <TD VALIGN="TOP" WIDTH="25%">
    ++  <A NAME="android.support.v4.app.ActivityOptionsCompat.makeTaskLaunchBehind_added()"></A>
    ++  <nobr><code>ActivityOptionsCompat</code>&nbsp;<A HREF="../../../../reference/android/support/v4/app/ActivityOptionsCompat.html#makeTaskLaunchBehind()" target="_top"><code>makeTaskLaunchBehind</code></A>()</nobr>
    ++  </TD>
    ++  <TD>&nbsp;</TD>
    ++</TR>
    ++<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    ++  <TD VALIGN="TOP" WIDTH="25%">
    ++  <A NAME="android.support.v4.app.ActivityOptionsCompat.requestUsageTimeReport_added(android.app.PendingIntent)"></A>
    ++  <nobr><code>void</code>&nbsp;<A HREF="../../../../reference/android/support/v4/app/ActivityOptionsCompat.html#requestUsageTimeReport(android.app.PendingIntent)" target="_top"><code>requestUsageTimeReport</code></A>(<code>PendingIntent</code>)</nobr>
    ++  </TD>
    ++  <TD>&nbsp;</TD>
    ++</TR>
    ++<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    ++  <TD VALIGN="TOP" WIDTH="25%">
    ++  <A NAME="android.support.v4.app.ActivityOptionsCompat.setLaunchBounds_added(android.graphics.Rect)"></A>
    ++  <nobr><code>ActivityOptionsCompat</code>&nbsp;<A HREF="../../../../reference/android/support/v4/app/ActivityOptionsCompat.html#setLaunchBounds(android.graphics.Rect)" target="_top"><code>setLaunchBounds</code></A>(<code>Rect</code>)</nobr>
    ++  </TD>
    ++  <TD>&nbsp;</TD>
    ++</TR>
    ++</TABLE>
    ++&nbsp;
    ++<a NAME="fields"></a>
    ++<p>
    ++<a NAME="Added"></a>
    ++<TABLE summary="Added Fields" WIDTH="100%">
    ++<TR>
    ++  <TH VALIGN="TOP" COLSPAN=2>Added Fields</FONT></TD>
    ++</TH>
    ++<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    ++  <TD VALIGN="TOP" WIDTH="25%">
    ++  <A NAME="android.support.v4.app.ActivityOptionsCompat.EXTRA_USAGE_TIME_REPORT"></A>
    ++  <nobr><code>String</code>&nbsp;<A HREF="../../../../reference/android/support/v4/app/ActivityOptionsCompat.html#EXTRA_USAGE_TIME_REPORT" target="_top"><code>EXTRA_USAGE_TIME_REPORT</code></A></nobr>
    ++  </TD>
    ++  <TD>&nbsp;</TD>
    ++</TR>
    ++<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    ++  <TD VALIGN="TOP" WIDTH="25%">
    ++  <A NAME="android.support.v4.app.ActivityOptionsCompat.EXTRA_USAGE_TIME_REPORT_PACKAGES"></A>
    ++  <nobr><code>String</code>&nbsp;<A HREF="../../../../reference/android/support/v4/app/ActivityOptionsCompat.html#EXTRA_USAGE_TIME_REPORT_PACKAGES" target="_top"><code>EXTRA_USAGE_TIME_REPORT_PACKAGES</code></A></nobr>
    ++  </TD>
    ++  <TD>&nbsp;</TD>
    ++</TR>
    ++</TABLE>
    ++&nbsp;
    ++      </div>	
    ++      <div id="footer">
    ++        <div id="copyright">
    ++        Except as noted, this content is licensed under 
    ++        <a href="http://creativecommons.org/licenses/by/2.5/"> Creative Commons Attribution 2.5</a>.
    ++        For details and restrictions, see the <a href="/license.html">Content License</a>.
    ++        </div>
    ++      <div id="footerlinks">
    ++      <p>
    ++        <a href="http://www.android.com/terms.html">Site Terms of Service</a> -
    ++        <a href="http://www.android.com/privacy.html">Privacy Policy</a> -
    ++        <a href="http://www.android.com/branding.html">Brand Guidelines</a>
    ++      </p>
    ++    </div>
    ++    </div> <!-- end footer -->
    ++    </div><!-- end doc-content -->
    ++    </div> <!-- end body-content --> 
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    ++</script>
    ++<script type="text/javascript">
    ++  try {
    ++    var pageTracker = _gat._getTracker("UA-5831155-1");
    ++    pageTracker._setAllowAnchor(true);
    ++    pageTracker._initData();
    ++    pageTracker._trackPageview();
    ++  } catch(e) {}
    ++</script>
    ++</BODY>
    ++</HTML>
    +diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.app.FragmentController.html b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.app.FragmentController.html
    +new file mode 100644
    +index 0000000..dfc1a60
    +--- /dev/null
    ++++ b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.app.FragmentController.html
    +@@ -0,0 +1,122 @@
    ++<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
    ++<HTML style="overflow:auto;">
    ++<HEAD>
    ++<meta name="generator" content="JDiff v1.1.0">
    ++<!-- Generated by the JDiff Javadoc doclet -->
    ++<!-- (http://www.jdiff.org) -->
    ++<meta name="description" content="JDiff is a Javadoc doclet which generates an HTML report of all the packages, classes, constructors, methods, and fields which have been removed, added or changed in any way, including their documentation, when two APIs are compared.">
    ++<meta name="keywords" content="diff, jdiff, javadiff, java diff, java difference, API difference, difference between two APIs, API diff, Javadoc, doclet">
    ++<TITLE>
    ++android.support.v4.app.FragmentController
    ++</TITLE>
    ++<link href="../../../../assets/android-developer-docs.css" rel="stylesheet" type="text/css" />
    ++<link href="../stylesheet-jdiff.css" rel="stylesheet" type="text/css" />
    ++<noscript>
    ++<style type="text/css">
    ++body{overflow:auto;}
    ++#body-content{position:relative; top:0;}
    ++#doc-content{overflow:visible;border-left:3px solid #666;}
    ++#side-nav{padding:0;}
    ++#side-nav .toggle-list ul {display:block;}
    ++#resize-packages-nav{border-bottom:3px solid #666;}
    ++</style>
    ++</noscript>
    ++<style type="text/css">
    ++</style>
    ++</HEAD>
    ++<BODY>
    ++<!-- Start of nav bar -->
    ++<a name="top"></a>
    ++<div id="header" style="margin-bottom:0;padding-bottom:0;">
    ++<div id="headerLeft">
    ++<a href="../../../../index.html" tabindex="-1" target="_top"><img src="../../../../assets/images/bg_logo.png" alt="Android Developers" /></a>
    ++</div>
    ++  <div id="headerRight">
    ++  <div id="headerLinks">
    ++<!-- <img src="/assets/images/icon_world.jpg" alt="" /> -->
    ++<span class="text">
    ++<!-- &nbsp;<a href="#">English</a> | -->
    ++<nobr><a href="http://developer.android.com" target="_top">Android Developers</a> | <a href="http://www.android.com" target="_top">Android.com</a></nobr>
    ++</span>
    ++</div>
    ++  <div class="and-diff-id" style="margin-top:6px;margin-right:8px;">
    ++    <table class="diffspectable">
    ++      <tr>
    ++        <td colspan="2" class="diffspechead">API Diff Specification</td>
    ++      </tr>
    ++      <tr>
    ++        <td class="diffspec" style="padding-top:.25em">To Level:</td>
    ++        <td class="diffvaluenew" style="padding-top:.25em">24.2.0</td>
    ++      </tr>
    ++      <tr>
    ++        <td class="diffspec">From Level:</td>
    ++        <td class="diffvalueold">24.1.0</td>
    ++      </tr>
    ++      <tr>
    ++        <td class="diffspec">Generated</td>
    ++        <td class="diffvalue">2016.08.16 14:03</td>
    ++      </tr>
    ++    </table>
    ++    </div><!-- End and-diff-id -->
    ++  <div class="and-diff-id" style="margin-right:8px;">
    ++    <table class="diffspectable">
    ++      <tr>
    ++        <td class="diffspec" colspan="2"><a href="jdiff_statistics.html">Statistics</a>
    ++      </tr>
    ++    </table>
    ++  </div> <!-- End and-diff-id -->
    ++  </div> <!-- End headerRight -->
    ++  </div> <!-- End header -->
    ++<div id="body-content" xstyle="padding:12px;padding-right:18px;">
    ++<div id="doc-content" style="position:relative;">
    ++<div id="mainBodyFluid">
    ++<H2>
    ++Class android.support.v4.app.<A HREF="../../../../reference/android/support/v4/app/FragmentController.html" target="_top"><font size="+2"><code>FragmentController</code></font></A>
    ++</H2>
    ++<a NAME="constructors"></a>
    ++<a NAME="methods"></a>
    ++<p>
    ++<a NAME="Added"></a>
    ++<TABLE summary="Added Methods" WIDTH="100%">
    ++<TR>
    ++  <TH VALIGN="TOP" COLSPAN=2>Added Methods</FONT></TD>
    ++</TH>
    ++<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    ++  <TD VALIGN="TOP" WIDTH="25%">
    ++  <A NAME="android.support.v4.app.FragmentController.findFragmentByWho_added(java.lang.String)"></A>
    ++  <nobr><code>Fragment</code>&nbsp;<A HREF="../../../../reference/android/support/v4/app/FragmentController.html#findFragmentByWho(java.lang.String)" target="_top"><code>findFragmentByWho</code></A>(<code>String</code>)</nobr>
    ++  </TD>
    ++  <TD>&nbsp;</TD>
    ++</TR>
    ++</TABLE>
    ++&nbsp;
    ++<a NAME="fields"></a>
    ++      </div>	
    ++      <div id="footer">
    ++        <div id="copyright">
    ++        Except as noted, this content is licensed under 
    ++        <a href="http://creativecommons.org/licenses/by/2.5/"> Creative Commons Attribution 2.5</a>.
    ++        For details and restrictions, see the <a href="/license.html">Content License</a>.
    ++        </div>
    ++      <div id="footerlinks">
    ++      <p>
    ++        <a href="http://www.android.com/terms.html">Site Terms of Service</a> -
    ++        <a href="http://www.android.com/privacy.html">Privacy Policy</a> -
    ++        <a href="http://www.android.com/branding.html">Brand Guidelines</a>
    ++      </p>
    ++    </div>
    ++    </div> <!-- end footer -->
    ++    </div><!-- end doc-content -->
    ++    </div> <!-- end body-content --> 
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    ++</script>
    ++<script type="text/javascript">
    ++  try {
    ++    var pageTracker = _gat._getTracker("UA-5831155-1");
    ++    pageTracker._setAllowAnchor(true);
    ++    pageTracker._initData();
    ++    pageTracker._trackPageview();
    ++  } catch(e) {}
    ++</script>
    ++</BODY>
    ++</HTML>
    +diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.app.ServiceCompat.html b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.app.ServiceCompat.html
    +new file mode 100644
    +index 0000000..211a88f
    +--- /dev/null
    ++++ b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.app.ServiceCompat.html
    +@@ -0,0 +1,144 @@
    ++<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
    ++<HTML style="overflow:auto;">
    ++<HEAD>
    ++<meta name="generator" content="JDiff v1.1.0">
    ++<!-- Generated by the JDiff Javadoc doclet -->
    ++<!-- (http://www.jdiff.org) -->
    ++<meta name="description" content="JDiff is a Javadoc doclet which generates an HTML report of all the packages, classes, constructors, methods, and fields which have been removed, added or changed in any way, including their documentation, when two APIs are compared.">
    ++<meta name="keywords" content="diff, jdiff, javadiff, java diff, java difference, API difference, difference between two APIs, API diff, Javadoc, doclet">
    ++<TITLE>
    ++android.support.v4.app.ServiceCompat
    ++</TITLE>
    ++<link href="../../../../assets/android-developer-docs.css" rel="stylesheet" type="text/css" />
    ++<link href="../stylesheet-jdiff.css" rel="stylesheet" type="text/css" />
    ++<noscript>
    ++<style type="text/css">
    ++body{overflow:auto;}
    ++#body-content{position:relative; top:0;}
    ++#doc-content{overflow:visible;border-left:3px solid #666;}
    ++#side-nav{padding:0;}
    ++#side-nav .toggle-list ul {display:block;}
    ++#resize-packages-nav{border-bottom:3px solid #666;}
    ++</style>
    ++</noscript>
    ++<style type="text/css">
    ++</style>
    ++</HEAD>
    ++<BODY>
    ++<!-- Start of nav bar -->
    ++<a name="top"></a>
    ++<div id="header" style="margin-bottom:0;padding-bottom:0;">
    ++<div id="headerLeft">
    ++<a href="../../../../index.html" tabindex="-1" target="_top"><img src="../../../../assets/images/bg_logo.png" alt="Android Developers" /></a>
    ++</div>
    ++  <div id="headerRight">
    ++  <div id="headerLinks">
    ++<!-- <img src="/assets/images/icon_world.jpg" alt="" /> -->
    ++<span class="text">
    ++<!-- &nbsp;<a href="#">English</a> | -->
    ++<nobr><a href="http://developer.android.com" target="_top">Android Developers</a> | <a href="http://www.android.com" target="_top">Android.com</a></nobr>
    ++</span>
    ++</div>
    ++  <div class="and-diff-id" style="margin-top:6px;margin-right:8px;">
    ++    <table class="diffspectable">
    ++      <tr>
    ++        <td colspan="2" class="diffspechead">API Diff Specification</td>
    ++      </tr>
    ++      <tr>
    ++        <td class="diffspec" style="padding-top:.25em">To Level:</td>
    ++        <td class="diffvaluenew" style="padding-top:.25em">24.2.0</td>
    ++      </tr>
    ++      <tr>
    ++        <td class="diffspec">From Level:</td>
    ++        <td class="diffvalueold">24.1.0</td>
    ++      </tr>
    ++      <tr>
    ++        <td class="diffspec">Generated</td>
    ++        <td class="diffvalue">2016.08.16 14:03</td>
    ++      </tr>
    ++    </table>
    ++    </div><!-- End and-diff-id -->
    ++  <div class="and-diff-id" style="margin-right:8px;">
    ++    <table class="diffspectable">
    ++      <tr>
    ++        <td class="diffspec" colspan="2"><a href="jdiff_statistics.html">Statistics</a>
    ++      </tr>
    ++    </table>
    ++  </div> <!-- End and-diff-id -->
    ++  </div> <!-- End headerRight -->
    ++  </div> <!-- End header -->
    ++<div id="body-content" xstyle="padding:12px;padding-right:18px;">
    ++<div id="doc-content" style="position:relative;">
    ++<div id="mainBodyFluid">
    ++<H2>
    ++Class android.support.v4.app.<A HREF="../../../../reference/android/support/v4/app/ServiceCompat.html" target="_top"><font size="+2"><code>ServiceCompat</code></font></A>
    ++</H2>
    ++<a NAME="constructors"></a>
    ++<a NAME="methods"></a>
    ++<p>
    ++<a NAME="Added"></a>
    ++<TABLE summary="Added Methods" WIDTH="100%">
    ++<TR>
    ++  <TH VALIGN="TOP" COLSPAN=2>Added Methods</FONT></TD>
    ++</TH>
    ++<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    ++  <TD VALIGN="TOP" WIDTH="25%">
    ++  <A NAME="android.support.v4.app.ServiceCompat.stopForeground_added(android.app.Service, int)"></A>
    ++  <nobr><code>void</code>&nbsp;<A HREF="../../../../reference/android/support/v4/app/ServiceCompat.html#stopForeground(android.app.Service, int)" target="_top"><code>stopForeground</code></A>(<code>Service,</nobr> int<nobr><nobr></code>)</nobr>
    ++  </TD>
    ++  <TD>&nbsp;</TD>
    ++</TR>
    ++</TABLE>
    ++&nbsp;
    ++<a NAME="fields"></a>
    ++<p>
    ++<a NAME="Added"></a>
    ++<TABLE summary="Added Fields" WIDTH="100%">
    ++<TR>
    ++  <TH VALIGN="TOP" COLSPAN=2>Added Fields</FONT></TD>
    ++</TH>
    ++<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    ++  <TD VALIGN="TOP" WIDTH="25%">
    ++  <A NAME="android.support.v4.app.ServiceCompat.STOP_FOREGROUND_DETACH"></A>
    ++  <nobr><code>int</code>&nbsp;<A HREF="../../../../reference/android/support/v4/app/ServiceCompat.html#STOP_FOREGROUND_DETACH" target="_top"><code>STOP_FOREGROUND_DETACH</code></A></nobr>
    ++  </TD>
    ++  <TD>&nbsp;</TD>
    ++</TR>
    ++<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    ++  <TD VALIGN="TOP" WIDTH="25%">
    ++  <A NAME="android.support.v4.app.ServiceCompat.STOP_FOREGROUND_REMOVE"></A>
    ++  <nobr><code>int</code>&nbsp;<A HREF="../../../../reference/android/support/v4/app/ServiceCompat.html#STOP_FOREGROUND_REMOVE" target="_top"><code>STOP_FOREGROUND_REMOVE</code></A></nobr>
    ++  </TD>
    ++  <TD>&nbsp;</TD>
    ++</TR>
    ++</TABLE>
    ++&nbsp;
    ++      </div>	
    ++      <div id="footer">
    ++        <div id="copyright">
    ++        Except as noted, this content is licensed under 
    ++        <a href="http://creativecommons.org/licenses/by/2.5/"> Creative Commons Attribution 2.5</a>.
    ++        For details and restrictions, see the <a href="/license.html">Content License</a>.
    ++        </div>
    ++      <div id="footerlinks">
    ++      <p>
    ++        <a href="http://www.android.com/terms.html">Site Terms of Service</a> -
    ++        <a href="http://www.android.com/privacy.html">Privacy Policy</a> -
    ++        <a href="http://www.android.com/branding.html">Brand Guidelines</a>
    ++      </p>
    ++    </div>
    ++    </div> <!-- end footer -->
    ++    </div><!-- end doc-content -->
    ++    </div> <!-- end body-content --> 
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    ++</script>
    ++<script type="text/javascript">
    ++  try {
    ++    var pageTracker = _gat._getTracker("UA-5831155-1");
    ++    pageTracker._setAllowAnchor(true);
    ++    pageTracker._initData();
    ++    pageTracker._trackPageview();
    ++  } catch(e) {}
    ++</script>
    ++</BODY>
    ++</HTML>
    +diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.app.SharedElementCallback.html b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.app.SharedElementCallback.html
    +new file mode 100644
    +index 0000000..7394059
    +--- /dev/null
    ++++ b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.app.SharedElementCallback.html
    +@@ -0,0 +1,122 @@
    ++<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
    ++<HTML style="overflow:auto;">
    ++<HEAD>
    ++<meta name="generator" content="JDiff v1.1.0">
    ++<!-- Generated by the JDiff Javadoc doclet -->
    ++<!-- (http://www.jdiff.org) -->
    ++<meta name="description" content="JDiff is a Javadoc doclet which generates an HTML report of all the packages, classes, constructors, methods, and fields which have been removed, added or changed in any way, including their documentation, when two APIs are compared.">
    ++<meta name="keywords" content="diff, jdiff, javadiff, java diff, java difference, API difference, difference between two APIs, API diff, Javadoc, doclet">
    ++<TITLE>
    ++android.support.v4.app.SharedElementCallback
    ++</TITLE>
    ++<link href="../../../../assets/android-developer-docs.css" rel="stylesheet" type="text/css" />
    ++<link href="../stylesheet-jdiff.css" rel="stylesheet" type="text/css" />
    ++<noscript>
    ++<style type="text/css">
    ++body{overflow:auto;}
    ++#body-content{position:relative; top:0;}
    ++#doc-content{overflow:visible;border-left:3px solid #666;}
    ++#side-nav{padding:0;}
    ++#side-nav .toggle-list ul {display:block;}
    ++#resize-packages-nav{border-bottom:3px solid #666;}
    ++</style>
    ++</noscript>
    ++<style type="text/css">
    ++</style>
    ++</HEAD>
    ++<BODY>
    ++<!-- Start of nav bar -->
    ++<a name="top"></a>
    ++<div id="header" style="margin-bottom:0;padding-bottom:0;">
    ++<div id="headerLeft">
    ++<a href="../../../../index.html" tabindex="-1" target="_top"><img src="../../../../assets/images/bg_logo.png" alt="Android Developers" /></a>
    ++</div>
    ++  <div id="headerRight">
    ++  <div id="headerLinks">
    ++<!-- <img src="/assets/images/icon_world.jpg" alt="" /> -->
    ++<span class="text">
    ++<!-- &nbsp;<a href="#">English</a> | -->
    ++<nobr><a href="http://developer.android.com" target="_top">Android Developers</a> | <a href="http://www.android.com" target="_top">Android.com</a></nobr>
    ++</span>
    ++</div>
    ++  <div class="and-diff-id" style="margin-top:6px;margin-right:8px;">
    ++    <table class="diffspectable">
    ++      <tr>
    ++        <td colspan="2" class="diffspechead">API Diff Specification</td>
    ++      </tr>
    ++      <tr>
    ++        <td class="diffspec" style="padding-top:.25em">To Level:</td>
    ++        <td class="diffvaluenew" style="padding-top:.25em">24.2.0</td>
    ++      </tr>
    ++      <tr>
    ++        <td class="diffspec">From Level:</td>
    ++        <td class="diffvalueold">24.1.0</td>
    ++      </tr>
    ++      <tr>
    ++        <td class="diffspec">Generated</td>
    ++        <td class="diffvalue">2016.08.16 14:03</td>
    ++      </tr>
    ++    </table>
    ++    </div><!-- End and-diff-id -->
    ++  <div class="and-diff-id" style="margin-right:8px;">
    ++    <table class="diffspectable">
    ++      <tr>
    ++        <td class="diffspec" colspan="2"><a href="jdiff_statistics.html">Statistics</a>
    ++      </tr>
    ++    </table>
    ++  </div> <!-- End and-diff-id -->
    ++  </div> <!-- End headerRight -->
    ++  </div> <!-- End header -->
    ++<div id="body-content" xstyle="padding:12px;padding-right:18px;">
    ++<div id="doc-content" style="position:relative;">
    ++<div id="mainBodyFluid">
    ++<H2>
    ++Class android.support.v4.app.<A HREF="../../../../reference/android/support/v4/app/SharedElementCallback.html" target="_top"><font size="+2"><code>SharedElementCallback</code></font></A>
    ++</H2>
    ++<a NAME="constructors"></a>
    ++<a NAME="methods"></a>
    ++<p>
    ++<a NAME="Added"></a>
    ++<TABLE summary="Added Methods" WIDTH="100%">
    ++<TR>
    ++  <TH VALIGN="TOP" COLSPAN=2>Added Methods</FONT></TD>
    ++</TH>
    ++<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    ++  <TD VALIGN="TOP" WIDTH="25%">
    ++  <A NAME="android.support.v4.app.SharedElementCallback.onSharedElementsArrived_added(java.util.List<java.lang.String>, java.util.List<android.view.View>, android.support.v4.app.SharedElementCallback.OnSharedElementsReadyListener)"></A>
    ++  <nobr><code>void</code>&nbsp;<A HREF="../../../../reference/android/support/v4/app/SharedElementCallback.html#onSharedElementsArrived(java.util.List<java.lang.String>, java.util.List<android.view.View>, android.support.v4.app.SharedElementCallback.OnSharedElementsReadyListener)" target="_top"><code>onSharedElementsArrived</code></A>(<code>List&lt;String&gt;,</nobr> List&lt;View&gt;<nobr>,</nobr> OnSharedElementsReadyListener<nobr><nobr></code>)</nobr>
    ++  </TD>
    ++  <TD>&nbsp;</TD>
    ++</TR>
    ++</TABLE>
    ++&nbsp;
    ++<a NAME="fields"></a>
    ++      </div>	
    ++      <div id="footer">
    ++        <div id="copyright">
    ++        Except as noted, this content is licensed under 
    ++        <a href="http://creativecommons.org/licenses/by/2.5/"> Creative Commons Attribution 2.5</a>.
    ++        For details and restrictions, see the <a href="/license.html">Content License</a>.
    ++        </div>
    ++      <div id="footerlinks">
    ++      <p>
    ++        <a href="http://www.android.com/terms.html">Site Terms of Service</a> -
    ++        <a href="http://www.android.com/privacy.html">Privacy Policy</a> -
    ++        <a href="http://www.android.com/branding.html">Brand Guidelines</a>
    ++      </p>
    ++    </div>
    ++    </div> <!-- end footer -->
    ++    </div><!-- end doc-content -->
    ++    </div> <!-- end body-content --> 
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    ++</script>
    ++<script type="text/javascript">
    ++  try {
    ++    var pageTracker = _gat._getTracker("UA-5831155-1");
    ++    pageTracker._setAllowAnchor(true);
    ++    pageTracker._initData();
    ++    pageTracker._trackPageview();
    ++  } catch(e) {}
    ++</script>
    ++</BODY>
    ++</HTML>
    +diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.content.ContextCompat.html b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.content.ContextCompat.html
    +new file mode 100644
    +index 0000000..b6157a2
    +--- /dev/null
    ++++ b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.content.ContextCompat.html
    +@@ -0,0 +1,125 @@
    ++<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
    ++<HTML style="overflow:auto;">
    ++<HEAD>
    ++<meta name="generator" content="JDiff v1.1.0">
    ++<!-- Generated by the JDiff Javadoc doclet -->
    ++<!-- (http://www.jdiff.org) -->
    ++<meta name="description" content="JDiff is a Javadoc doclet which generates an HTML report of all the packages, classes, constructors, methods, and fields which have been removed, added or changed in any way, including their documentation, when two APIs are compared.">
    ++<meta name="keywords" content="diff, jdiff, javadiff, java diff, java difference, API difference, difference between two APIs, API diff, Javadoc, doclet">
    ++<TITLE>
    ++android.support.v4.content.ContextCompat
    ++</TITLE>
    ++<link href="../../../../assets/android-developer-docs.css" rel="stylesheet" type="text/css" />
    ++<link href="../stylesheet-jdiff.css" rel="stylesheet" type="text/css" />
    ++<noscript>
    ++<style type="text/css">
    ++body{overflow:auto;}
    ++#body-content{position:relative; top:0;}
    ++#doc-content{overflow:visible;border-left:3px solid #666;}
    ++#side-nav{padding:0;}
    ++#side-nav .toggle-list ul {display:block;}
    ++#resize-packages-nav{border-bottom:3px solid #666;}
    ++</style>
    ++</noscript>
    ++<style type="text/css">
    ++</style>
    ++</HEAD>
    ++<BODY>
    ++<!-- Start of nav bar -->
    ++<a name="top"></a>
    ++<div id="header" style="margin-bottom:0;padding-bottom:0;">
    ++<div id="headerLeft">
    ++<a href="../../../../index.html" tabindex="-1" target="_top"><img src="../../../../assets/images/bg_logo.png" alt="Android Developers" /></a>
    ++</div>
    ++  <div id="headerRight">
    ++  <div id="headerLinks">
    ++<!-- <img src="/assets/images/icon_world.jpg" alt="" /> -->
    ++<span class="text">
    ++<!-- &nbsp;<a href="#">English</a> | -->
    ++<nobr><a href="http://developer.android.com" target="_top">Android Developers</a> | <a href="http://www.android.com" target="_top">Android.com</a></nobr>
    ++</span>
    ++</div>
    ++  <div class="and-diff-id" style="margin-top:6px;margin-right:8px;">
    ++    <table class="diffspectable">
    ++      <tr>
    ++        <td colspan="2" class="diffspechead">API Diff Specification</td>
    ++      </tr>
    ++      <tr>
    ++        <td class="diffspec" style="padding-top:.25em">To Level:</td>
    ++        <td class="diffvaluenew" style="padding-top:.25em">24.2.0</td>
    ++      </tr>
    ++      <tr>
    ++        <td class="diffspec">From Level:</td>
    ++        <td class="diffvalueold">24.1.0</td>
    ++      </tr>
    ++      <tr>
    ++        <td class="diffspec">Generated</td>
    ++        <td class="diffvalue">2016.08.16 14:03</td>
    ++      </tr>
    ++    </table>
    ++    </div><!-- End and-diff-id -->
    ++  <div class="and-diff-id" style="margin-right:8px;">
    ++    <table class="diffspectable">
    ++      <tr>
    ++        <td class="diffspec" colspan="2"><a href="jdiff_statistics.html">Statistics</a>
    ++      </tr>
    ++    </table>
    ++  </div> <!-- End and-diff-id -->
    ++  </div> <!-- End headerRight -->
    ++  </div> <!-- End header -->
    ++<div id="body-content" xstyle="padding:12px;padding-right:18px;">
    ++<div id="doc-content" style="position:relative;">
    ++<div id="mainBodyFluid">
    ++<H2>
    ++Class android.support.v4.content.<A HREF="../../../../reference/android/support/v4/content/ContextCompat.html" target="_top"><font size="+2"><code>ContextCompat</code></font></A>
    ++</H2>
    ++<a NAME="constructors"></a>
    ++<p>
    ++<a NAME="Changed"></a>
    ++<TABLE summary="Changed Constructors" WIDTH="100%">
    ++<TR>
    ++  <TH VALIGN="TOP" COLSPAN=3>Changed Constructors</FONT></TD>
    ++</TH>
    ++<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    ++  <TD VALIGN="TOP" WIDTH="25%">
    ++  <A NAME="android.support.v4.content.ContextCompat.ctor_changed()"></A>
    ++  <nobr><A HREF="../../../../reference/android/support/v4/content/ContextCompat.html#ContextCompat()" target="_top"><code>ContextCompat</code></A>()  </nobr>
    ++  </TD>
    ++  <TD VALIGN="TOP" WIDTH="30%">
    ++<b>Now deprecated</b>.<br>
    ++  </TD>
    ++  <TD>&nbsp;</TD>
    ++</TR>
    ++</TABLE>
    ++&nbsp;
    ++<a NAME="methods"></a>
    ++<a NAME="fields"></a>
    ++      </div>	
    ++      <div id="footer">
    ++        <div id="copyright">
    ++        Except as noted, this content is licensed under 
    ++        <a href="http://creativecommons.org/licenses/by/2.5/"> Creative Commons Attribution 2.5</a>.
    ++        For details and restrictions, see the <a href="/license.html">Content License</a>.
    ++        </div>
    ++      <div id="footerlinks">
    ++      <p>
    ++        <a href="http://www.android.com/terms.html">Site Terms of Service</a> -
    ++        <a href="http://www.android.com/privacy.html">Privacy Policy</a> -
    ++        <a href="http://www.android.com/branding.html">Brand Guidelines</a>
    ++      </p>
    ++    </div>
    ++    </div> <!-- end footer -->
    ++    </div><!-- end doc-content -->
    ++    </div> <!-- end body-content --> 
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    ++</script>
    ++<script type="text/javascript">
    ++  try {
    ++    var pageTracker = _gat._getTracker("UA-5831155-1");
    ++    pageTracker._setAllowAnchor(true);
    ++    pageTracker._initData();
    ++    pageTracker._trackPageview();
    ++  } catch(e) {}
    ++</script>
    ++</BODY>
    ++</HTML>
    +diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.graphics.drawable.DrawableCompat.html b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.graphics.drawable.DrawableCompat.html
    +new file mode 100644
    +index 0000000..92f1ba4
    +--- /dev/null
    ++++ b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.graphics.drawable.DrawableCompat.html
    +@@ -0,0 +1,122 @@
    ++<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
    ++<HTML style="overflow:auto;">
    ++<HEAD>
    ++<meta name="generator" content="JDiff v1.1.0">
    ++<!-- Generated by the JDiff Javadoc doclet -->
    ++<!-- (http://www.jdiff.org) -->
    ++<meta name="description" content="JDiff is a Javadoc doclet which generates an HTML report of all the packages, classes, constructors, methods, and fields which have been removed, added or changed in any way, including their documentation, when two APIs are compared.">
    ++<meta name="keywords" content="diff, jdiff, javadiff, java diff, java difference, API difference, difference between two APIs, API diff, Javadoc, doclet">
    ++<TITLE>
    ++android.support.v4.graphics.drawable.DrawableCompat
    ++</TITLE>
    ++<link href="../../../../assets/android-developer-docs.css" rel="stylesheet" type="text/css" />
    ++<link href="../stylesheet-jdiff.css" rel="stylesheet" type="text/css" />
    ++<noscript>
    ++<style type="text/css">
    ++body{overflow:auto;}
    ++#body-content{position:relative; top:0;}
    ++#doc-content{overflow:visible;border-left:3px solid #666;}
    ++#side-nav{padding:0;}
    ++#side-nav .toggle-list ul {display:block;}
    ++#resize-packages-nav{border-bottom:3px solid #666;}
    ++</style>
    ++</noscript>
    ++<style type="text/css">
    ++</style>
    ++</HEAD>
    ++<BODY>
    ++<!-- Start of nav bar -->
    ++<a name="top"></a>
    ++<div id="header" style="margin-bottom:0;padding-bottom:0;">
    ++<div id="headerLeft">
    ++<a href="../../../../index.html" tabindex="-1" target="_top"><img src="../../../../assets/images/bg_logo.png" alt="Android Developers" /></a>
    ++</div>
    ++  <div id="headerRight">
    ++  <div id="headerLinks">
    ++<!-- <img src="/assets/images/icon_world.jpg" alt="" /> -->
    ++<span class="text">
    ++<!-- &nbsp;<a href="#">English</a> | -->
    ++<nobr><a href="http://developer.android.com" target="_top">Android Developers</a> | <a href="http://www.android.com" target="_top">Android.com</a></nobr>
    ++</span>
    ++</div>
    ++  <div class="and-diff-id" style="margin-top:6px;margin-right:8px;">
    ++    <table class="diffspectable">
    ++      <tr>
    ++        <td colspan="2" class="diffspechead">API Diff Specification</td>
    ++      </tr>
    ++      <tr>
    ++        <td class="diffspec" style="padding-top:.25em">To Level:</td>
    ++        <td class="diffvaluenew" style="padding-top:.25em">24.2.0</td>
    ++      </tr>
    ++      <tr>
    ++        <td class="diffspec">From Level:</td>
    ++        <td class="diffvalueold">24.1.0</td>
    ++      </tr>
    ++      <tr>
    ++        <td class="diffspec">Generated</td>
    ++        <td class="diffvalue">2016.08.16 14:03</td>
    ++      </tr>
    ++    </table>
    ++    </div><!-- End and-diff-id -->
    ++  <div class="and-diff-id" style="margin-right:8px;">
    ++    <table class="diffspectable">
    ++      <tr>
    ++        <td class="diffspec" colspan="2"><a href="jdiff_statistics.html">Statistics</a>
    ++      </tr>
    ++    </table>
    ++  </div> <!-- End and-diff-id -->
    ++  </div> <!-- End headerRight -->
    ++  </div> <!-- End header -->
    ++<div id="body-content" xstyle="padding:12px;padding-right:18px;">
    ++<div id="doc-content" style="position:relative;">
    ++<div id="mainBodyFluid">
    ++<H2>
    ++Class android.support.v4.graphics.drawable.<A HREF="../../../../reference/android/support/v4/graphics/drawable/DrawableCompat.html" target="_top"><font size="+2"><code>DrawableCompat</code></font></A>
    ++</H2>
    ++<a NAME="constructors"></a>
    ++<a NAME="methods"></a>
    ++<p>
    ++<a NAME="Added"></a>
    ++<TABLE summary="Added Methods" WIDTH="100%">
    ++<TR>
    ++  <TH VALIGN="TOP" COLSPAN=2>Added Methods</FONT></TD>
    ++</TH>
    ++<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    ++  <TD VALIGN="TOP" WIDTH="25%">
    ++  <A NAME="android.support.v4.graphics.drawable.DrawableCompat.clearColorFilter_added(android.graphics.drawable.Drawable)"></A>
    ++  <nobr><code>void</code>&nbsp;<A HREF="../../../../reference/android/support/v4/graphics/drawable/DrawableCompat.html#clearColorFilter(android.graphics.drawable.Drawable)" target="_top"><code>clearColorFilter</code></A>(<code>Drawable</code>)</nobr>
    ++  </TD>
    ++  <TD>&nbsp;</TD>
    ++</TR>
    ++</TABLE>
    ++&nbsp;
    ++<a NAME="fields"></a>
    ++      </div>	
    ++      <div id="footer">
    ++        <div id="copyright">
    ++        Except as noted, this content is licensed under 
    ++        <a href="http://creativecommons.org/licenses/by/2.5/"> Creative Commons Attribution 2.5</a>.
    ++        For details and restrictions, see the <a href="/license.html">Content License</a>.
    ++        </div>
    ++      <div id="footerlinks">
    ++      <p>
    ++        <a href="http://www.android.com/terms.html">Site Terms of Service</a> -
    ++        <a href="http://www.android.com/privacy.html">Privacy Policy</a> -
    ++        <a href="http://www.android.com/branding.html">Brand Guidelines</a>
    ++      </p>
    ++    </div>
    ++    </div> <!-- end footer -->
    ++    </div><!-- end doc-content -->
    ++    </div> <!-- end body-content --> 
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    ++</script>
    ++<script type="text/javascript">
    ++  try {
    ++    var pageTracker = _gat._getTracker("UA-5831155-1");
    ++    pageTracker._setAllowAnchor(true);
    ++    pageTracker._initData();
    ++    pageTracker._trackPageview();
    ++  } catch(e) {}
    ++</script>
    ++</BODY>
    ++</HTML>
    +diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.media.MediaBrowserCompat.MediaItem.html b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.media.MediaBrowserCompat.MediaItem.html
    +new file mode 100644
    +index 0000000..52da3d4
    +--- /dev/null
    ++++ b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.media.MediaBrowserCompat.MediaItem.html
    +@@ -0,0 +1,129 @@
    ++<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
    ++<HTML style="overflow:auto;">
    ++<HEAD>
    ++<meta name="generator" content="JDiff v1.1.0">
    ++<!-- Generated by the JDiff Javadoc doclet -->
    ++<!-- (http://www.jdiff.org) -->
    ++<meta name="description" content="JDiff is a Javadoc doclet which generates an HTML report of all the packages, classes, constructors, methods, and fields which have been removed, added or changed in any way, including their documentation, when two APIs are compared.">
    ++<meta name="keywords" content="diff, jdiff, javadiff, java diff, java difference, API difference, difference between two APIs, API diff, Javadoc, doclet">
    ++<TITLE>
    ++android.support.v4.media.MediaBrowserCompat.MediaItem
    ++</TITLE>
    ++<link href="../../../../assets/android-developer-docs.css" rel="stylesheet" type="text/css" />
    ++<link href="../stylesheet-jdiff.css" rel="stylesheet" type="text/css" />
    ++<noscript>
    ++<style type="text/css">
    ++body{overflow:auto;}
    ++#body-content{position:relative; top:0;}
    ++#doc-content{overflow:visible;border-left:3px solid #666;}
    ++#side-nav{padding:0;}
    ++#side-nav .toggle-list ul {display:block;}
    ++#resize-packages-nav{border-bottom:3px solid #666;}
    ++</style>
    ++</noscript>
    ++<style type="text/css">
    ++</style>
    ++</HEAD>
    ++<BODY>
    ++<!-- Start of nav bar -->
    ++<a name="top"></a>
    ++<div id="header" style="margin-bottom:0;padding-bottom:0;">
    ++<div id="headerLeft">
    ++<a href="../../../../index.html" tabindex="-1" target="_top"><img src="../../../../assets/images/bg_logo.png" alt="Android Developers" /></a>
    ++</div>
    ++  <div id="headerRight">
    ++  <div id="headerLinks">
    ++<!-- <img src="/assets/images/icon_world.jpg" alt="" /> -->
    ++<span class="text">
    ++<!-- &nbsp;<a href="#">English</a> | -->
    ++<nobr><a href="http://developer.android.com" target="_top">Android Developers</a> | <a href="http://www.android.com" target="_top">Android.com</a></nobr>
    ++</span>
    ++</div>
    ++  <div class="and-diff-id" style="margin-top:6px;margin-right:8px;">
    ++    <table class="diffspectable">
    ++      <tr>
    ++        <td colspan="2" class="diffspechead">API Diff Specification</td>
    ++      </tr>
    ++      <tr>
    ++        <td class="diffspec" style="padding-top:.25em">To Level:</td>
    ++        <td class="diffvaluenew" style="padding-top:.25em">24.2.0</td>
    ++      </tr>
    ++      <tr>
    ++        <td class="diffspec">From Level:</td>
    ++        <td class="diffvalueold">24.1.0</td>
    ++      </tr>
    ++      <tr>
    ++        <td class="diffspec">Generated</td>
    ++        <td class="diffvalue">2016.08.16 14:03</td>
    ++      </tr>
    ++    </table>
    ++    </div><!-- End and-diff-id -->
    ++  <div class="and-diff-id" style="margin-right:8px;">
    ++    <table class="diffspectable">
    ++      <tr>
    ++        <td class="diffspec" colspan="2"><a href="jdiff_statistics.html">Statistics</a>
    ++      </tr>
    ++    </table>
    ++  </div> <!-- End and-diff-id -->
    ++  </div> <!-- End headerRight -->
    ++  </div> <!-- End header -->
    ++<div id="body-content" xstyle="padding:12px;padding-right:18px;">
    ++<div id="doc-content" style="position:relative;">
    ++<div id="mainBodyFluid">
    ++<H2>
    ++Class android.support.v4.media.<A HREF="../../../../reference/android/support/v4/media/MediaBrowserCompat.MediaItem.html" target="_top"><font size="+2"><code>MediaBrowserCompat.MediaItem</code></font></A>
    ++</H2>
    ++<a NAME="constructors"></a>
    ++<a NAME="methods"></a>
    ++<p>
    ++<a NAME="Added"></a>
    ++<TABLE summary="Added Methods" WIDTH="100%">
    ++<TR>
    ++  <TH VALIGN="TOP" COLSPAN=2>Added Methods</FONT></TD>
    ++</TH>
    ++<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    ++  <TD VALIGN="TOP" WIDTH="25%">
    ++  <A NAME="android.support.v4.media.MediaBrowserCompat.MediaItem.fromMediaItem_added(java.lang.Object)"></A>
    ++  <nobr><code>MediaItem</code>&nbsp;<A HREF="../../../../reference/android/support/v4/media/MediaBrowserCompat.MediaItem.html#fromMediaItem(java.lang.Object)" target="_top"><code>fromMediaItem</code></A>(<code>Object</code>)</nobr>
    ++  </TD>
    ++  <TD>&nbsp;</TD>
    ++</TR>
    ++<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    ++  <TD VALIGN="TOP" WIDTH="25%">
    ++  <A NAME="android.support.v4.media.MediaBrowserCompat.MediaItem.fromMediaItemList_added(java.util.List<?>)"></A>
    ++  <nobr><code>List&lt;MediaItem&gt;</code>&nbsp;<A HREF="../../../../reference/android/support/v4/media/MediaBrowserCompat.MediaItem.html#fromMediaItemList(java.util.List<?>)" target="_top"><code>fromMediaItemList</code></A>(<code>List&lt;?&gt;</code>)</nobr>
    ++  </TD>
    ++  <TD>&nbsp;</TD>
    ++</TR>
    ++</TABLE>
    ++&nbsp;
    ++<a NAME="fields"></a>
    ++      </div>	
    ++      <div id="footer">
    ++        <div id="copyright">
    ++        Except as noted, this content is licensed under 
    ++        <a href="http://creativecommons.org/licenses/by/2.5/"> Creative Commons Attribution 2.5</a>.
    ++        For details and restrictions, see the <a href="/license.html">Content License</a>.
    ++        </div>
    ++      <div id="footerlinks">
    ++      <p>
    ++        <a href="http://www.android.com/terms.html">Site Terms of Service</a> -
    ++        <a href="http://www.android.com/privacy.html">Privacy Policy</a> -
    ++        <a href="http://www.android.com/branding.html">Brand Guidelines</a>
    ++      </p>
    ++    </div>
    ++    </div> <!-- end footer -->
    ++    </div><!-- end doc-content -->
    ++    </div> <!-- end body-content --> 
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    ++</script>
    ++<script type="text/javascript">
    ++  try {
    ++    var pageTracker = _gat._getTracker("UA-5831155-1");
    ++    pageTracker._setAllowAnchor(true);
    ++    pageTracker._initData();
    ++    pageTracker._trackPageview();
    ++  } catch(e) {}
    ++</script>
    ++</BODY>
    ++</HTML>
    +diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.media.MediaBrowserServiceCompat.BrowserRoot.html b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.media.MediaBrowserServiceCompat.BrowserRoot.html
    +new file mode 100644
    +index 0000000..7ea97f3
    +--- /dev/null
    ++++ b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.media.MediaBrowserServiceCompat.BrowserRoot.html
    +@@ -0,0 +1,122 @@
    ++<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
    ++<HTML style="overflow:auto;">
    ++<HEAD>
    ++<meta name="generator" content="JDiff v1.1.0">
    ++<!-- Generated by the JDiff Javadoc doclet -->
    ++<!-- (http://www.jdiff.org) -->
    ++<meta name="description" content="JDiff is a Javadoc doclet which generates an HTML report of all the packages, classes, constructors, methods, and fields which have been removed, added or changed in any way, including their documentation, when two APIs are compared.">
    ++<meta name="keywords" content="diff, jdiff, javadiff, java diff, java difference, API difference, difference between two APIs, API diff, Javadoc, doclet">
    ++<TITLE>
    ++android.support.v4.media.MediaBrowserServiceCompat.BrowserRoot
    ++</TITLE>
    ++<link href="../../../../assets/android-developer-docs.css" rel="stylesheet" type="text/css" />
    ++<link href="../stylesheet-jdiff.css" rel="stylesheet" type="text/css" />
    ++<noscript>
    ++<style type="text/css">
    ++body{overflow:auto;}
    ++#body-content{position:relative; top:0;}
    ++#doc-content{overflow:visible;border-left:3px solid #666;}
    ++#side-nav{padding:0;}
    ++#side-nav .toggle-list ul {display:block;}
    ++#resize-packages-nav{border-bottom:3px solid #666;}
    ++</style>
    ++</noscript>
    ++<style type="text/css">
    ++</style>
    ++</HEAD>
    ++<BODY>
    ++<!-- Start of nav bar -->
    ++<a name="top"></a>
    ++<div id="header" style="margin-bottom:0;padding-bottom:0;">
    ++<div id="headerLeft">
    ++<a href="../../../../index.html" tabindex="-1" target="_top"><img src="../../../../assets/images/bg_logo.png" alt="Android Developers" /></a>
    ++</div>
    ++  <div id="headerRight">
    ++  <div id="headerLinks">
    ++<!-- <img src="/assets/images/icon_world.jpg" alt="" /> -->
    ++<span class="text">
    ++<!-- &nbsp;<a href="#">English</a> | -->
    ++<nobr><a href="http://developer.android.com" target="_top">Android Developers</a> | <a href="http://www.android.com" target="_top">Android.com</a></nobr>
    ++</span>
    ++</div>
    ++  <div class="and-diff-id" style="margin-top:6px;margin-right:8px;">
    ++    <table class="diffspectable">
    ++      <tr>
    ++        <td colspan="2" class="diffspechead">API Diff Specification</td>
    ++      </tr>
    ++      <tr>
    ++        <td class="diffspec" style="padding-top:.25em">To Level:</td>
    ++        <td class="diffvaluenew" style="padding-top:.25em">24.2.0</td>
    ++      </tr>
    ++      <tr>
    ++        <td class="diffspec">From Level:</td>
    ++        <td class="diffvalueold">24.1.0</td>
    ++      </tr>
    ++      <tr>
    ++        <td class="diffspec">Generated</td>
    ++        <td class="diffvalue">2016.08.16 14:03</td>
    ++      </tr>
    ++    </table>
    ++    </div><!-- End and-diff-id -->
    ++  <div class="and-diff-id" style="margin-right:8px;">
    ++    <table class="diffspectable">
    ++      <tr>
    ++        <td class="diffspec" colspan="2"><a href="jdiff_statistics.html">Statistics</a>
    ++      </tr>
    ++    </table>
    ++  </div> <!-- End and-diff-id -->
    ++  </div> <!-- End headerRight -->
    ++  </div> <!-- End header -->
    ++<div id="body-content" xstyle="padding:12px;padding-right:18px;">
    ++<div id="doc-content" style="position:relative;">
    ++<div id="mainBodyFluid">
    ++<H2>
    ++Class android.support.v4.media.<A HREF="../../../../reference/android/support/v4/media/MediaBrowserServiceCompat.BrowserRoot.html" target="_top"><font size="+2"><code>MediaBrowserServiceCompat.BrowserRoot</code></font></A>
    ++</H2>
    ++<a NAME="constructors"></a>
    ++<a NAME="methods"></a>
    ++<a NAME="fields"></a>
    ++<p>
    ++<a NAME="Added"></a>
    ++<TABLE summary="Added Fields" WIDTH="100%">
    ++<TR>
    ++  <TH VALIGN="TOP" COLSPAN=2>Added Fields</FONT></TD>
    ++</TH>
    ++<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    ++  <TD VALIGN="TOP" WIDTH="25%">
    ++  <A NAME="android.support.v4.media.MediaBrowserServiceCompat.BrowserRoot.EXTRA_SUGGESTION_KEYWORDS"></A>
    ++  <nobr><code>String</code>&nbsp;<A HREF="../../../../reference/android/support/v4/media/MediaBrowserServiceCompat.BrowserRoot.html#EXTRA_SUGGESTION_KEYWORDS" target="_top"><code>EXTRA_SUGGESTION_KEYWORDS</code></A></nobr>
    ++  </TD>
    ++  <TD>&nbsp;</TD>
    ++</TR>
    ++</TABLE>
    ++&nbsp;
    ++      </div>	
    ++      <div id="footer">
    ++        <div id="copyright">
    ++        Except as noted, this content is licensed under 
    ++        <a href="http://creativecommons.org/licenses/by/2.5/"> Creative Commons Attribution 2.5</a>.
    ++        For details and restrictions, see the <a href="/license.html">Content License</a>.
    ++        </div>
    ++      <div id="footerlinks">
    ++      <p>
    ++        <a href="http://www.android.com/terms.html">Site Terms of Service</a> -
    ++        <a href="http://www.android.com/privacy.html">Privacy Policy</a> -
    ++        <a href="http://www.android.com/branding.html">Brand Guidelines</a>
    ++      </p>
    ++    </div>
    ++    </div> <!-- end footer -->
    ++    </div><!-- end doc-content -->
    ++    </div> <!-- end body-content --> 
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    ++</script>
    ++<script type="text/javascript">
    ++  try {
    ++    var pageTracker = _gat._getTracker("UA-5831155-1");
    ++    pageTracker._setAllowAnchor(true);
    ++    pageTracker._initData();
    ++    pageTracker._trackPageview();
    ++  } catch(e) {}
    ++</script>
    ++</BODY>
    ++</HTML>
    +diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.media.MediaDescriptionCompat.html b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.media.MediaDescriptionCompat.html
    +new file mode 100644
    +index 0000000..fa1d610
    +--- /dev/null
    ++++ b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.media.MediaDescriptionCompat.html
    +@@ -0,0 +1,171 @@
    ++<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
    ++<HTML style="overflow:auto;">
    ++<HEAD>
    ++<meta name="generator" content="JDiff v1.1.0">
    ++<!-- Generated by the JDiff Javadoc doclet -->
    ++<!-- (http://www.jdiff.org) -->
    ++<meta name="description" content="JDiff is a Javadoc doclet which generates an HTML report of all the packages, classes, constructors, methods, and fields which have been removed, added or changed in any way, including their documentation, when two APIs are compared.">
    ++<meta name="keywords" content="diff, jdiff, javadiff, java diff, java difference, API difference, difference between two APIs, API diff, Javadoc, doclet">
    ++<TITLE>
    ++android.support.v4.media.MediaDescriptionCompat
    ++</TITLE>
    ++<link href="../../../../assets/android-developer-docs.css" rel="stylesheet" type="text/css" />
    ++<link href="../stylesheet-jdiff.css" rel="stylesheet" type="text/css" />
    ++<noscript>
    ++<style type="text/css">
    ++body{overflow:auto;}
    ++#body-content{position:relative; top:0;}
    ++#doc-content{overflow:visible;border-left:3px solid #666;}
    ++#side-nav{padding:0;}
    ++#side-nav .toggle-list ul {display:block;}
    ++#resize-packages-nav{border-bottom:3px solid #666;}
    ++</style>
    ++</noscript>
    ++<style type="text/css">
    ++</style>
    ++</HEAD>
    ++<BODY>
    ++<!-- Start of nav bar -->
    ++<a name="top"></a>
    ++<div id="header" style="margin-bottom:0;padding-bottom:0;">
    ++<div id="headerLeft">
    ++<a href="../../../../index.html" tabindex="-1" target="_top"><img src="../../../../assets/images/bg_logo.png" alt="Android Developers" /></a>
    ++</div>
    ++  <div id="headerRight">
    ++  <div id="headerLinks">
    ++<!-- <img src="/assets/images/icon_world.jpg" alt="" /> -->
    ++<span class="text">
    ++<!-- &nbsp;<a href="#">English</a> | -->
    ++<nobr><a href="http://developer.android.com" target="_top">Android Developers</a> | <a href="http://www.android.com" target="_top">Android.com</a></nobr>
    ++</span>
    ++</div>
    ++  <div class="and-diff-id" style="margin-top:6px;margin-right:8px;">
    ++    <table class="diffspectable">
    ++      <tr>
    ++        <td colspan="2" class="diffspechead">API Diff Specification</td>
    ++      </tr>
    ++      <tr>
    ++        <td class="diffspec" style="padding-top:.25em">To Level:</td>
    ++        <td class="diffvaluenew" style="padding-top:.25em">24.2.0</td>
    ++      </tr>
    ++      <tr>
    ++        <td class="diffspec">From Level:</td>
    ++        <td class="diffvalueold">24.1.0</td>
    ++      </tr>
    ++      <tr>
    ++        <td class="diffspec">Generated</td>
    ++        <td class="diffvalue">2016.08.16 14:03</td>
    ++      </tr>
    ++    </table>
    ++    </div><!-- End and-diff-id -->
    ++  <div class="and-diff-id" style="margin-right:8px;">
    ++    <table class="diffspectable">
    ++      <tr>
    ++        <td class="diffspec" colspan="2"><a href="jdiff_statistics.html">Statistics</a>
    ++      </tr>
    ++    </table>
    ++  </div> <!-- End and-diff-id -->
    ++  </div> <!-- End headerRight -->
    ++  </div> <!-- End header -->
    ++<div id="body-content" xstyle="padding:12px;padding-right:18px;">
    ++<div id="doc-content" style="position:relative;">
    ++<div id="mainBodyFluid">
    ++<H2>
    ++Class android.support.v4.media.<A HREF="../../../../reference/android/support/v4/media/MediaDescriptionCompat.html" target="_top"><font size="+2"><code>MediaDescriptionCompat</code></font></A>
    ++</H2>
    ++<a NAME="constructors"></a>
    ++<a NAME="methods"></a>
    ++<a NAME="fields"></a>
    ++<p>
    ++<a NAME="Added"></a>
    ++<TABLE summary="Added Fields" WIDTH="100%">
    ++<TR>
    ++  <TH VALIGN="TOP" COLSPAN=2>Added Fields</FONT></TD>
    ++</TH>
    ++<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    ++  <TD VALIGN="TOP" WIDTH="25%">
    ++  <A NAME="android.support.v4.media.MediaDescriptionCompat.BT_FOLDER_TYPE_ALBUMS"></A>
    ++  <nobr><code>long</code>&nbsp;<A HREF="../../../../reference/android/support/v4/media/MediaDescriptionCompat.html#BT_FOLDER_TYPE_ALBUMS" target="_top"><code>BT_FOLDER_TYPE_ALBUMS</code></A></nobr>
    ++  </TD>
    ++  <TD>&nbsp;</TD>
    ++</TR>
    ++<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    ++  <TD VALIGN="TOP" WIDTH="25%">
    ++  <A NAME="android.support.v4.media.MediaDescriptionCompat.BT_FOLDER_TYPE_ARTISTS"></A>
    ++  <nobr><code>long</code>&nbsp;<A HREF="../../../../reference/android/support/v4/media/MediaDescriptionCompat.html#BT_FOLDER_TYPE_ARTISTS" target="_top"><code>BT_FOLDER_TYPE_ARTISTS</code></A></nobr>
    ++  </TD>
    ++  <TD>&nbsp;</TD>
    ++</TR>
    ++<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    ++  <TD VALIGN="TOP" WIDTH="25%">
    ++  <A NAME="android.support.v4.media.MediaDescriptionCompat.BT_FOLDER_TYPE_GENRES"></A>
    ++  <nobr><code>long</code>&nbsp;<A HREF="../../../../reference/android/support/v4/media/MediaDescriptionCompat.html#BT_FOLDER_TYPE_GENRES" target="_top"><code>BT_FOLDER_TYPE_GENRES</code></A></nobr>
    ++  </TD>
    ++  <TD>&nbsp;</TD>
    ++</TR>
    ++<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    ++  <TD VALIGN="TOP" WIDTH="25%">
    ++  <A NAME="android.support.v4.media.MediaDescriptionCompat.BT_FOLDER_TYPE_MIXED"></A>
    ++  <nobr><code>long</code>&nbsp;<A HREF="../../../../reference/android/support/v4/media/MediaDescriptionCompat.html#BT_FOLDER_TYPE_MIXED" target="_top"><code>BT_FOLDER_TYPE_MIXED</code></A></nobr>
    ++  </TD>
    ++  <TD>&nbsp;</TD>
    ++</TR>
    ++<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    ++  <TD VALIGN="TOP" WIDTH="25%">
    ++  <A NAME="android.support.v4.media.MediaDescriptionCompat.BT_FOLDER_TYPE_PLAYLISTS"></A>
    ++  <nobr><code>long</code>&nbsp;<A HREF="../../../../reference/android/support/v4/media/MediaDescriptionCompat.html#BT_FOLDER_TYPE_PLAYLISTS" target="_top"><code>BT_FOLDER_TYPE_PLAYLISTS</code></A></nobr>
    ++  </TD>
    ++  <TD>&nbsp;</TD>
    ++</TR>
    ++<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    ++  <TD VALIGN="TOP" WIDTH="25%">
    ++  <A NAME="android.support.v4.media.MediaDescriptionCompat.BT_FOLDER_TYPE_TITLES"></A>
    ++  <nobr><code>long</code>&nbsp;<A HREF="../../../../reference/android/support/v4/media/MediaDescriptionCompat.html#BT_FOLDER_TYPE_TITLES" target="_top"><code>BT_FOLDER_TYPE_TITLES</code></A></nobr>
    ++  </TD>
    ++  <TD>&nbsp;</TD>
    ++</TR>
    ++<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    ++  <TD VALIGN="TOP" WIDTH="25%">
    ++  <A NAME="android.support.v4.media.MediaDescriptionCompat.BT_FOLDER_TYPE_YEARS"></A>
    ++  <nobr><code>long</code>&nbsp;<A HREF="../../../../reference/android/support/v4/media/MediaDescriptionCompat.html#BT_FOLDER_TYPE_YEARS" target="_top"><code>BT_FOLDER_TYPE_YEARS</code></A></nobr>
    ++  </TD>
    ++  <TD>&nbsp;</TD>
    ++</TR>
    ++<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    ++  <TD VALIGN="TOP" WIDTH="25%">
    ++  <A NAME="android.support.v4.media.MediaDescriptionCompat.EXTRA_BT_FOLDER_TYPE"></A>
    ++  <nobr><code>String</code>&nbsp;<A HREF="../../../../reference/android/support/v4/media/MediaDescriptionCompat.html#EXTRA_BT_FOLDER_TYPE" target="_top"><code>EXTRA_BT_FOLDER_TYPE</code></A></nobr>
    ++  </TD>
    ++  <TD>&nbsp;</TD>
    ++</TR>
    ++</TABLE>
    ++&nbsp;
    ++      </div>	
    ++      <div id="footer">
    ++        <div id="copyright">
    ++        Except as noted, this content is licensed under 
    ++        <a href="http://creativecommons.org/licenses/by/2.5/"> Creative Commons Attribution 2.5</a>.
    ++        For details and restrictions, see the <a href="/license.html">Content License</a>.
    ++        </div>
    ++      <div id="footerlinks">
    ++      <p>
    ++        <a href="http://www.android.com/terms.html">Site Terms of Service</a> -
    ++        <a href="http://www.android.com/privacy.html">Privacy Policy</a> -
    ++        <a href="http://www.android.com/branding.html">Brand Guidelines</a>
    ++      </p>
    ++    </div>
    ++    </div> <!-- end footer -->
    ++    </div><!-- end doc-content -->
    ++    </div> <!-- end body-content --> 
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    ++</script>
    ++<script type="text/javascript">
    ++  try {
    ++    var pageTracker = _gat._getTracker("UA-5831155-1");
    ++    pageTracker._setAllowAnchor(true);
    ++    pageTracker._initData();
    ++    pageTracker._trackPageview();
    ++  } catch(e) {}
    ++</script>
    ++</BODY>
    ++</HTML>
    +diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.media.MediaMetadataCompat.html b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.media.MediaMetadataCompat.html
    +new file mode 100644
    +index 0000000..7e0f137
    +--- /dev/null
    ++++ b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.media.MediaMetadataCompat.html
    +@@ -0,0 +1,129 @@
    ++<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
    ++<HTML style="overflow:auto;">
    ++<HEAD>
    ++<meta name="generator" content="JDiff v1.1.0">
    ++<!-- Generated by the JDiff Javadoc doclet -->
    ++<!-- (http://www.jdiff.org) -->
    ++<meta name="description" content="JDiff is a Javadoc doclet which generates an HTML report of all the packages, classes, constructors, methods, and fields which have been removed, added or changed in any way, including their documentation, when two APIs are compared.">
    ++<meta name="keywords" content="diff, jdiff, javadiff, java diff, java difference, API difference, difference between two APIs, API diff, Javadoc, doclet">
    ++<TITLE>
    ++android.support.v4.media.MediaMetadataCompat
    ++</TITLE>
    ++<link href="../../../../assets/android-developer-docs.css" rel="stylesheet" type="text/css" />
    ++<link href="../stylesheet-jdiff.css" rel="stylesheet" type="text/css" />
    ++<noscript>
    ++<style type="text/css">
    ++body{overflow:auto;}
    ++#body-content{position:relative; top:0;}
    ++#doc-content{overflow:visible;border-left:3px solid #666;}
    ++#side-nav{padding:0;}
    ++#side-nav .toggle-list ul {display:block;}
    ++#resize-packages-nav{border-bottom:3px solid #666;}
    ++</style>
    ++</noscript>
    ++<style type="text/css">
    ++</style>
    ++</HEAD>
    ++<BODY>
    ++<!-- Start of nav bar -->
    ++<a name="top"></a>
    ++<div id="header" style="margin-bottom:0;padding-bottom:0;">
    ++<div id="headerLeft">
    ++<a href="../../../../index.html" tabindex="-1" target="_top"><img src="../../../../assets/images/bg_logo.png" alt="Android Developers" /></a>
    ++</div>
    ++  <div id="headerRight">
    ++  <div id="headerLinks">
    ++<!-- <img src="/assets/images/icon_world.jpg" alt="" /> -->
    ++<span class="text">
    ++<!-- &nbsp;<a href="#">English</a> | -->
    ++<nobr><a href="http://developer.android.com" target="_top">Android Developers</a> | <a href="http://www.android.com" target="_top">Android.com</a></nobr>
    ++</span>
    ++</div>
    ++  <div class="and-diff-id" style="margin-top:6px;margin-right:8px;">
    ++    <table class="diffspectable">
    ++      <tr>
    ++        <td colspan="2" class="diffspechead">API Diff Specification</td>
    ++      </tr>
    ++      <tr>
    ++        <td class="diffspec" style="padding-top:.25em">To Level:</td>
    ++        <td class="diffvaluenew" style="padding-top:.25em">24.2.0</td>
    ++      </tr>
    ++      <tr>
    ++        <td class="diffspec">From Level:</td>
    ++        <td class="diffvalueold">24.1.0</td>
    ++      </tr>
    ++      <tr>
    ++        <td class="diffspec">Generated</td>
    ++        <td class="diffvalue">2016.08.16 14:03</td>
    ++      </tr>
    ++    </table>
    ++    </div><!-- End and-diff-id -->
    ++  <div class="and-diff-id" style="margin-right:8px;">
    ++    <table class="diffspectable">
    ++      <tr>
    ++        <td class="diffspec" colspan="2"><a href="jdiff_statistics.html">Statistics</a>
    ++      </tr>
    ++    </table>
    ++  </div> <!-- End and-diff-id -->
    ++  </div> <!-- End headerRight -->
    ++  </div> <!-- End header -->
    ++<div id="body-content" xstyle="padding:12px;padding-right:18px;">
    ++<div id="doc-content" style="position:relative;">
    ++<div id="mainBodyFluid">
    ++<H2>
    ++Class android.support.v4.media.<A HREF="../../../../reference/android/support/v4/media/MediaMetadataCompat.html" target="_top"><font size="+2"><code>MediaMetadataCompat</code></font></A>
    ++</H2>
    ++<a NAME="constructors"></a>
    ++<a NAME="methods"></a>
    ++<a NAME="fields"></a>
    ++<p>
    ++<a NAME="Added"></a>
    ++<TABLE summary="Added Fields" WIDTH="100%">
    ++<TR>
    ++  <TH VALIGN="TOP" COLSPAN=2>Added Fields</FONT></TD>
    ++</TH>
    ++<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    ++  <TD VALIGN="TOP" WIDTH="25%">
    ++  <A NAME="android.support.v4.media.MediaMetadataCompat.METADATA_KEY_BT_FOLDER_TYPE"></A>
    ++  <nobr><code>String</code>&nbsp;<A HREF="../../../../reference/android/support/v4/media/MediaMetadataCompat.html#METADATA_KEY_BT_FOLDER_TYPE" target="_top"><code>METADATA_KEY_BT_FOLDER_TYPE</code></A></nobr>
    ++  </TD>
    ++  <TD>&nbsp;</TD>
    ++</TR>
    ++<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    ++  <TD VALIGN="TOP" WIDTH="25%">
    ++  <A NAME="android.support.v4.media.MediaMetadataCompat.METADATA_KEY_MEDIA_URI"></A>
    ++  <nobr><code>String</code>&nbsp;<A HREF="../../../../reference/android/support/v4/media/MediaMetadataCompat.html#METADATA_KEY_MEDIA_URI" target="_top"><code>METADATA_KEY_MEDIA_URI</code></A></nobr>
    ++  </TD>
    ++  <TD>&nbsp;</TD>
    ++</TR>
    ++</TABLE>
    ++&nbsp;
    ++      </div>	
    ++      <div id="footer">
    ++        <div id="copyright">
    ++        Except as noted, this content is licensed under 
    ++        <a href="http://creativecommons.org/licenses/by/2.5/"> Creative Commons Attribution 2.5</a>.
    ++        For details and restrictions, see the <a href="/license.html">Content License</a>.
    ++        </div>
    ++      <div id="footerlinks">
    ++      <p>
    ++        <a href="http://www.android.com/terms.html">Site Terms of Service</a> -
    ++        <a href="http://www.android.com/privacy.html">Privacy Policy</a> -
    ++        <a href="http://www.android.com/branding.html">Brand Guidelines</a>
    ++      </p>
    ++    </div>
    ++    </div> <!-- end footer -->
    ++    </div><!-- end doc-content -->
    ++    </div> <!-- end body-content --> 
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    ++</script>
    ++<script type="text/javascript">
    ++  try {
    ++    var pageTracker = _gat._getTracker("UA-5831155-1");
    ++    pageTracker._setAllowAnchor(true);
    ++    pageTracker._initData();
    ++    pageTracker._trackPageview();
    ++  } catch(e) {}
    ++</script>
    ++</BODY>
    ++</HTML>
    +diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.media.session.MediaButtonReceiver.html b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.media.session.MediaButtonReceiver.html
    +new file mode 100644
    +index 0000000..65467b8
    +--- /dev/null
    ++++ b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.media.session.MediaButtonReceiver.html
    +@@ -0,0 +1,129 @@
    ++<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
    ++<HTML style="overflow:auto;">
    ++<HEAD>
    ++<meta name="generator" content="JDiff v1.1.0">
    ++<!-- Generated by the JDiff Javadoc doclet -->
    ++<!-- (http://www.jdiff.org) -->
    ++<meta name="description" content="JDiff is a Javadoc doclet which generates an HTML report of all the packages, classes, constructors, methods, and fields which have been removed, added or changed in any way, including their documentation, when two APIs are compared.">
    ++<meta name="keywords" content="diff, jdiff, javadiff, java diff, java difference, API difference, difference between two APIs, API diff, Javadoc, doclet">
    ++<TITLE>
    ++android.support.v4.media.session.MediaButtonReceiver
    ++</TITLE>
    ++<link href="../../../../assets/android-developer-docs.css" rel="stylesheet" type="text/css" />
    ++<link href="../stylesheet-jdiff.css" rel="stylesheet" type="text/css" />
    ++<noscript>
    ++<style type="text/css">
    ++body{overflow:auto;}
    ++#body-content{position:relative; top:0;}
    ++#doc-content{overflow:visible;border-left:3px solid #666;}
    ++#side-nav{padding:0;}
    ++#side-nav .toggle-list ul {display:block;}
    ++#resize-packages-nav{border-bottom:3px solid #666;}
    ++</style>
    ++</noscript>
    ++<style type="text/css">
    ++</style>
    ++</HEAD>
    ++<BODY>
    ++<!-- Start of nav bar -->
    ++<a name="top"></a>
    ++<div id="header" style="margin-bottom:0;padding-bottom:0;">
    ++<div id="headerLeft">
    ++<a href="../../../../index.html" tabindex="-1" target="_top"><img src="../../../../assets/images/bg_logo.png" alt="Android Developers" /></a>
    ++</div>
    ++  <div id="headerRight">
    ++  <div id="headerLinks">
    ++<!-- <img src="/assets/images/icon_world.jpg" alt="" /> -->
    ++<span class="text">
    ++<!-- &nbsp;<a href="#">English</a> | -->
    ++<nobr><a href="http://developer.android.com" target="_top">Android Developers</a> | <a href="http://www.android.com" target="_top">Android.com</a></nobr>
    ++</span>
    ++</div>
    ++  <div class="and-diff-id" style="margin-top:6px;margin-right:8px;">
    ++    <table class="diffspectable">
    ++      <tr>
    ++        <td colspan="2" class="diffspechead">API Diff Specification</td>
    ++      </tr>
    ++      <tr>
    ++        <td class="diffspec" style="padding-top:.25em">To Level:</td>
    ++        <td class="diffvaluenew" style="padding-top:.25em">24.2.0</td>
    ++      </tr>
    ++      <tr>
    ++        <td class="diffspec">From Level:</td>
    ++        <td class="diffvalueold">24.1.0</td>
    ++      </tr>
    ++      <tr>
    ++        <td class="diffspec">Generated</td>
    ++        <td class="diffvalue">2016.08.16 14:03</td>
    ++      </tr>
    ++    </table>
    ++    </div><!-- End and-diff-id -->
    ++  <div class="and-diff-id" style="margin-right:8px;">
    ++    <table class="diffspectable">
    ++      <tr>
    ++        <td class="diffspec" colspan="2"><a href="jdiff_statistics.html">Statistics</a>
    ++      </tr>
    ++    </table>
    ++  </div> <!-- End and-diff-id -->
    ++  </div> <!-- End headerRight -->
    ++  </div> <!-- End header -->
    ++<div id="body-content" xstyle="padding:12px;padding-right:18px;">
    ++<div id="doc-content" style="position:relative;">
    ++<div id="mainBodyFluid">
    ++<H2>
    ++Class android.support.v4.media.session.<A HREF="../../../../reference/android/support/v4/media/session/MediaButtonReceiver.html" target="_top"><font size="+2"><code>MediaButtonReceiver</code></font></A>
    ++</H2>
    ++<a NAME="constructors"></a>
    ++<a NAME="methods"></a>
    ++<p>
    ++<a NAME="Added"></a>
    ++<TABLE summary="Added Methods" WIDTH="100%">
    ++<TR>
    ++  <TH VALIGN="TOP" COLSPAN=2>Added Methods</FONT></TD>
    ++</TH>
    ++<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    ++  <TD VALIGN="TOP" WIDTH="25%">
    ++  <A NAME="android.support.v4.media.session.MediaButtonReceiver.buildMediaButtonPendingIntent_added(android.content.Context, android.content.ComponentName, long)"></A>
    ++  <nobr><code>PendingIntent</code>&nbsp;<A HREF="../../../../reference/android/support/v4/media/session/MediaButtonReceiver.html#buildMediaButtonPendingIntent(android.content.Context, android.content.ComponentName, long)" target="_top"><code>buildMediaButtonPendingIntent</code></A>(<code>Context,</nobr> ComponentName<nobr>,</nobr> long<nobr><nobr></code>)</nobr>
    ++  </TD>
    ++  <TD>&nbsp;</TD>
    ++</TR>
    ++<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    ++  <TD VALIGN="TOP" WIDTH="25%">
    ++  <A NAME="android.support.v4.media.session.MediaButtonReceiver.buildMediaButtonPendingIntent_added(android.content.Context, long)"></A>
    ++  <nobr><code>PendingIntent</code>&nbsp;<A HREF="../../../../reference/android/support/v4/media/session/MediaButtonReceiver.html#buildMediaButtonPendingIntent(android.content.Context, long)" target="_top"><code>buildMediaButtonPendingIntent</code></A>(<code>Context,</nobr> long<nobr><nobr></code>)</nobr>
    ++  </TD>
    ++  <TD>&nbsp;</TD>
    ++</TR>
    ++</TABLE>
    ++&nbsp;
    ++<a NAME="fields"></a>
    ++      </div>	
    ++      <div id="footer">
    ++        <div id="copyright">
    ++        Except as noted, this content is licensed under 
    ++        <a href="http://creativecommons.org/licenses/by/2.5/"> Creative Commons Attribution 2.5</a>.
    ++        For details and restrictions, see the <a href="/license.html">Content License</a>.
    ++        </div>
    ++      <div id="footerlinks">
    ++      <p>
    ++        <a href="http://www.android.com/terms.html">Site Terms of Service</a> -
    ++        <a href="http://www.android.com/privacy.html">Privacy Policy</a> -
    ++        <a href="http://www.android.com/branding.html">Brand Guidelines</a>
    ++      </p>
    ++    </div>
    ++    </div> <!-- end footer -->
    ++    </div><!-- end doc-content -->
    ++    </div> <!-- end body-content --> 
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    ++</script>
    ++<script type="text/javascript">
    ++  try {
    ++    var pageTracker = _gat._getTracker("UA-5831155-1");
    ++    pageTracker._setAllowAnchor(true);
    ++    pageTracker._initData();
    ++    pageTracker._trackPageview();
    ++  } catch(e) {}
    ++</script>
    ++</BODY>
    ++</HTML>
    +diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.media.session.MediaSessionCompat.QueueItem.html b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.media.session.MediaSessionCompat.QueueItem.html
    +new file mode 100644
    +index 0000000..e3b0184
    +--- /dev/null
    ++++ b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.media.session.MediaSessionCompat.QueueItem.html
    +@@ -0,0 +1,147 @@
    ++<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
    ++<HTML style="overflow:auto;">
    ++<HEAD>
    ++<meta name="generator" content="JDiff v1.1.0">
    ++<!-- Generated by the JDiff Javadoc doclet -->
    ++<!-- (http://www.jdiff.org) -->
    ++<meta name="description" content="JDiff is a Javadoc doclet which generates an HTML report of all the packages, classes, constructors, methods, and fields which have been removed, added or changed in any way, including their documentation, when two APIs are compared.">
    ++<meta name="keywords" content="diff, jdiff, javadiff, java diff, java difference, API difference, difference between two APIs, API diff, Javadoc, doclet">
    ++<TITLE>
    ++android.support.v4.media.session.MediaSessionCompat.QueueItem
    ++</TITLE>
    ++<link href="../../../../assets/android-developer-docs.css" rel="stylesheet" type="text/css" />
    ++<link href="../stylesheet-jdiff.css" rel="stylesheet" type="text/css" />
    ++<noscript>
    ++<style type="text/css">
    ++body{overflow:auto;}
    ++#body-content{position:relative; top:0;}
    ++#doc-content{overflow:visible;border-left:3px solid #666;}
    ++#side-nav{padding:0;}
    ++#side-nav .toggle-list ul {display:block;}
    ++#resize-packages-nav{border-bottom:3px solid #666;}
    ++</style>
    ++</noscript>
    ++<style type="text/css">
    ++</style>
    ++</HEAD>
    ++<BODY>
    ++<!-- Start of nav bar -->
    ++<a name="top"></a>
    ++<div id="header" style="margin-bottom:0;padding-bottom:0;">
    ++<div id="headerLeft">
    ++<a href="../../../../index.html" tabindex="-1" target="_top"><img src="../../../../assets/images/bg_logo.png" alt="Android Developers" /></a>
    ++</div>
    ++  <div id="headerRight">
    ++  <div id="headerLinks">
    ++<!-- <img src="/assets/images/icon_world.jpg" alt="" /> -->
    ++<span class="text">
    ++<!-- &nbsp;<a href="#">English</a> | -->
    ++<nobr><a href="http://developer.android.com" target="_top">Android Developers</a> | <a href="http://www.android.com" target="_top">Android.com</a></nobr>
    ++</span>
    ++</div>
    ++  <div class="and-diff-id" style="margin-top:6px;margin-right:8px;">
    ++    <table class="diffspectable">
    ++      <tr>
    ++        <td colspan="2" class="diffspechead">API Diff Specification</td>
    ++      </tr>
    ++      <tr>
    ++        <td class="diffspec" style="padding-top:.25em">To Level:</td>
    ++        <td class="diffvaluenew" style="padding-top:.25em">24.2.0</td>
    ++      </tr>
    ++      <tr>
    ++        <td class="diffspec">From Level:</td>
    ++        <td class="diffvalueold">24.1.0</td>
    ++      </tr>
    ++      <tr>
    ++        <td class="diffspec">Generated</td>
    ++        <td class="diffvalue">2016.08.16 14:03</td>
    ++      </tr>
    ++    </table>
    ++    </div><!-- End and-diff-id -->
    ++  <div class="and-diff-id" style="margin-right:8px;">
    ++    <table class="diffspectable">
    ++      <tr>
    ++        <td class="diffspec" colspan="2"><a href="jdiff_statistics.html">Statistics</a>
    ++      </tr>
    ++    </table>
    ++  </div> <!-- End and-diff-id -->
    ++  </div> <!-- End headerRight -->
    ++  </div> <!-- End header -->
    ++<div id="body-content" xstyle="padding:12px;padding-right:18px;">
    ++<div id="doc-content" style="position:relative;">
    ++<div id="mainBodyFluid">
    ++<H2>
    ++Class android.support.v4.media.session.<A HREF="../../../../reference/android/support/v4/media/session/MediaSessionCompat.QueueItem.html" target="_top"><font size="+2"><code>MediaSessionCompat.QueueItem</code></font></A>
    ++</H2>
    ++<a NAME="constructors"></a>
    ++<a NAME="methods"></a>
    ++<p>
    ++<a NAME="Added"></a>
    ++<TABLE summary="Added Methods" WIDTH="100%">
    ++<TR>
    ++  <TH VALIGN="TOP" COLSPAN=2>Added Methods</FONT></TD>
    ++</TH>
    ++<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    ++  <TD VALIGN="TOP" WIDTH="25%">
    ++  <A NAME="android.support.v4.media.session.MediaSessionCompat.QueueItem.fromQueueItem_added(java.lang.Object)"></A>
    ++  <nobr><code>QueueItem</code>&nbsp;<A HREF="../../../../reference/android/support/v4/media/session/MediaSessionCompat.QueueItem.html#fromQueueItem(java.lang.Object)" target="_top"><code>fromQueueItem</code></A>(<code>Object</code>)</nobr>
    ++  </TD>
    ++  <TD>&nbsp;</TD>
    ++</TR>
    ++<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    ++  <TD VALIGN="TOP" WIDTH="25%">
    ++  <A NAME="android.support.v4.media.session.MediaSessionCompat.QueueItem.fromQueueItemList_added(java.util.List<?>)"></A>
    ++  <nobr><code>List&lt;QueueItem&gt;</code>&nbsp;<A HREF="../../../../reference/android/support/v4/media/session/MediaSessionCompat.QueueItem.html#fromQueueItemList(java.util.List<?>)" target="_top"><code>fromQueueItemList</code></A>(<code>List&lt;?&gt;</code>)</nobr>
    ++  </TD>
    ++  <TD>&nbsp;</TD>
    ++</TR>
    ++</TABLE>
    ++&nbsp;
    ++<p>
    ++<a NAME="Changed"></a>
    ++<TABLE summary="Changed Methods" WIDTH="100%">
    ++<TR>
    ++  <TH VALIGN="TOP" COLSPAN=3>Changed Methods</FONT></TD>
    ++</TH>
    ++<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    ++  <TD VALIGN="TOP" WIDTH="25%">
    ++  <A NAME="android.support.v4.media.session.MediaSessionCompat.QueueItem.obtain_changed(java.lang.Object)"></A>
    ++  <nobr><code>QueueItem</code>&nbsp;<A HREF="../../../../reference/android/support/v4/media/session/MediaSessionCompat.QueueItem.html#obtain(java.lang.Object)" target="_top"><code>obtain</code></A>(<code>Object</code>)  </nobr>
    ++  </TD>
    ++  <TD VALIGN="TOP" WIDTH="30%">
    ++<b>Now deprecated</b>.<br>
    ++  </TD>
    ++  <TD>&nbsp;</TD>
    ++</TR>
    ++</TABLE>
    ++&nbsp;
    ++<a NAME="fields"></a>
    ++      </div>	
    ++      <div id="footer">
    ++        <div id="copyright">
    ++        Except as noted, this content is licensed under 
    ++        <a href="http://creativecommons.org/licenses/by/2.5/"> Creative Commons Attribution 2.5</a>.
    ++        For details and restrictions, see the <a href="/license.html">Content License</a>.
    ++        </div>
    ++      <div id="footerlinks">
    ++      <p>
    ++        <a href="http://www.android.com/terms.html">Site Terms of Service</a> -
    ++        <a href="http://www.android.com/privacy.html">Privacy Policy</a> -
    ++        <a href="http://www.android.com/branding.html">Brand Guidelines</a>
    ++      </p>
    ++    </div>
    ++    </div> <!-- end footer -->
    ++    </div><!-- end doc-content -->
    ++    </div> <!-- end body-content --> 
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    ++</script>
    ++<script type="text/javascript">
    ++  try {
    ++    var pageTracker = _gat._getTracker("UA-5831155-1");
    ++    pageTracker._setAllowAnchor(true);
    ++    pageTracker._initData();
    ++    pageTracker._trackPageview();
    ++  } catch(e) {}
    ++</script>
    ++</BODY>
    ++</HTML>
    +diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.media.session.MediaSessionCompat.html b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.media.session.MediaSessionCompat.html
    +new file mode 100644
    +index 0000000..90bd5eb
    +--- /dev/null
    ++++ b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.media.session.MediaSessionCompat.html
    +@@ -0,0 +1,140 @@
    ++<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
    ++<HTML style="overflow:auto;">
    ++<HEAD>
    ++<meta name="generator" content="JDiff v1.1.0">
    ++<!-- Generated by the JDiff Javadoc doclet -->
    ++<!-- (http://www.jdiff.org) -->
    ++<meta name="description" content="JDiff is a Javadoc doclet which generates an HTML report of all the packages, classes, constructors, methods, and fields which have been removed, added or changed in any way, including their documentation, when two APIs are compared.">
    ++<meta name="keywords" content="diff, jdiff, javadiff, java diff, java difference, API difference, difference between two APIs, API diff, Javadoc, doclet">
    ++<TITLE>
    ++android.support.v4.media.session.MediaSessionCompat
    ++</TITLE>
    ++<link href="../../../../assets/android-developer-docs.css" rel="stylesheet" type="text/css" />
    ++<link href="../stylesheet-jdiff.css" rel="stylesheet" type="text/css" />
    ++<noscript>
    ++<style type="text/css">
    ++body{overflow:auto;}
    ++#body-content{position:relative; top:0;}
    ++#doc-content{overflow:visible;border-left:3px solid #666;}
    ++#side-nav{padding:0;}
    ++#side-nav .toggle-list ul {display:block;}
    ++#resize-packages-nav{border-bottom:3px solid #666;}
    ++</style>
    ++</noscript>
    ++<style type="text/css">
    ++</style>
    ++</HEAD>
    ++<BODY>
    ++<!-- Start of nav bar -->
    ++<a name="top"></a>
    ++<div id="header" style="margin-bottom:0;padding-bottom:0;">
    ++<div id="headerLeft">
    ++<a href="../../../../index.html" tabindex="-1" target="_top"><img src="../../../../assets/images/bg_logo.png" alt="Android Developers" /></a>
    ++</div>
    ++  <div id="headerRight">
    ++  <div id="headerLinks">
    ++<!-- <img src="/assets/images/icon_world.jpg" alt="" /> -->
    ++<span class="text">
    ++<!-- &nbsp;<a href="#">English</a> | -->
    ++<nobr><a href="http://developer.android.com" target="_top">Android Developers</a> | <a href="http://www.android.com" target="_top">Android.com</a></nobr>
    ++</span>
    ++</div>
    ++  <div class="and-diff-id" style="margin-top:6px;margin-right:8px;">
    ++    <table class="diffspectable">
    ++      <tr>
    ++        <td colspan="2" class="diffspechead">API Diff Specification</td>
    ++      </tr>
    ++      <tr>
    ++        <td class="diffspec" style="padding-top:.25em">To Level:</td>
    ++        <td class="diffvaluenew" style="padding-top:.25em">24.2.0</td>
    ++      </tr>
    ++      <tr>
    ++        <td class="diffspec">From Level:</td>
    ++        <td class="diffvalueold">24.1.0</td>
    ++      </tr>
    ++      <tr>
    ++        <td class="diffspec">Generated</td>
    ++        <td class="diffvalue">2016.08.16 14:03</td>
    ++      </tr>
    ++    </table>
    ++    </div><!-- End and-diff-id -->
    ++  <div class="and-diff-id" style="margin-right:8px;">
    ++    <table class="diffspectable">
    ++      <tr>
    ++        <td class="diffspec" colspan="2"><a href="jdiff_statistics.html">Statistics</a>
    ++      </tr>
    ++    </table>
    ++  </div> <!-- End and-diff-id -->
    ++  </div> <!-- End headerRight -->
    ++  </div> <!-- End header -->
    ++<div id="body-content" xstyle="padding:12px;padding-right:18px;">
    ++<div id="doc-content" style="position:relative;">
    ++<div id="mainBodyFluid">
    ++<H2>
    ++Class android.support.v4.media.session.<A HREF="../../../../reference/android/support/v4/media/session/MediaSessionCompat.html" target="_top"><font size="+2"><code>MediaSessionCompat</code></font></A>
    ++</H2>
    ++<a NAME="constructors"></a>
    ++<a NAME="methods"></a>
    ++<p>
    ++<a NAME="Added"></a>
    ++<TABLE summary="Added Methods" WIDTH="100%">
    ++<TR>
    ++  <TH VALIGN="TOP" COLSPAN=2>Added Methods</FONT></TD>
    ++</TH>
    ++<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    ++  <TD VALIGN="TOP" WIDTH="25%">
    ++  <A NAME="android.support.v4.media.session.MediaSessionCompat.fromMediaSession_added(android.content.Context, java.lang.Object)"></A>
    ++  <nobr><code>MediaSessionCompat</code>&nbsp;<A HREF="../../../../reference/android/support/v4/media/session/MediaSessionCompat.html#fromMediaSession(android.content.Context, java.lang.Object)" target="_top"><code>fromMediaSession</code></A>(<code>Context,</nobr> Object<nobr><nobr></code>)</nobr>
    ++  </TD>
    ++  <TD>&nbsp;</TD>
    ++</TR>
    ++</TABLE>
    ++&nbsp;
    ++<p>
    ++<a NAME="Changed"></a>
    ++<TABLE summary="Changed Methods" WIDTH="100%">
    ++<TR>
    ++  <TH VALIGN="TOP" COLSPAN=3>Changed Methods</FONT></TD>
    ++</TH>
    ++<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    ++  <TD VALIGN="TOP" WIDTH="25%">
    ++  <A NAME="android.support.v4.media.session.MediaSessionCompat.obtain_changed(android.content.Context, java.lang.Object)"></A>
    ++  <nobr><code>MediaSessionCompat</code>&nbsp;<A HREF="../../../../reference/android/support/v4/media/session/MediaSessionCompat.html#obtain(android.content.Context, java.lang.Object)" target="_top"><code>obtain</code></A>(<code>Context,</nobr> Object<nobr><nobr></code>)  </nobr>
    ++  </TD>
    ++  <TD VALIGN="TOP" WIDTH="30%">
    ++<b>Now deprecated</b>.<br>
    ++  </TD>
    ++  <TD>&nbsp;</TD>
    ++</TR>
    ++</TABLE>
    ++&nbsp;
    ++<a NAME="fields"></a>
    ++      </div>	
    ++      <div id="footer">
    ++        <div id="copyright">
    ++        Except as noted, this content is licensed under 
    ++        <a href="http://creativecommons.org/licenses/by/2.5/"> Creative Commons Attribution 2.5</a>.
    ++        For details and restrictions, see the <a href="/license.html">Content License</a>.
    ++        </div>
    ++      <div id="footerlinks">
    ++      <p>
    ++        <a href="http://www.android.com/terms.html">Site Terms of Service</a> -
    ++        <a href="http://www.android.com/privacy.html">Privacy Policy</a> -
    ++        <a href="http://www.android.com/branding.html">Brand Guidelines</a>
    ++      </p>
    ++    </div>
    ++    </div> <!-- end footer -->
    ++    </div><!-- end doc-content -->
    ++    </div> <!-- end body-content --> 
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    ++</script>
    ++<script type="text/javascript">
    ++  try {
    ++    var pageTracker = _gat._getTracker("UA-5831155-1");
    ++    pageTracker._setAllowAnchor(true);
    ++    pageTracker._initData();
    ++    pageTracker._trackPageview();
    ++  } catch(e) {}
    ++</script>
    ++</BODY>
    ++</HTML>
    +diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.media.session.PlaybackStateCompat.html b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.media.session.PlaybackStateCompat.html
    +new file mode 100644
    +index 0000000..07e2449
    +--- /dev/null
    ++++ b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.media.session.PlaybackStateCompat.html
    +@@ -0,0 +1,122 @@
    ++<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
    ++<HTML style="overflow:auto;">
    ++<HEAD>
    ++<meta name="generator" content="JDiff v1.1.0">
    ++<!-- Generated by the JDiff Javadoc doclet -->
    ++<!-- (http://www.jdiff.org) -->
    ++<meta name="description" content="JDiff is a Javadoc doclet which generates an HTML report of all the packages, classes, constructors, methods, and fields which have been removed, added or changed in any way, including their documentation, when two APIs are compared.">
    ++<meta name="keywords" content="diff, jdiff, javadiff, java diff, java difference, API difference, difference between two APIs, API diff, Javadoc, doclet">
    ++<TITLE>
    ++android.support.v4.media.session.PlaybackStateCompat
    ++</TITLE>
    ++<link href="../../../../assets/android-developer-docs.css" rel="stylesheet" type="text/css" />
    ++<link href="../stylesheet-jdiff.css" rel="stylesheet" type="text/css" />
    ++<noscript>
    ++<style type="text/css">
    ++body{overflow:auto;}
    ++#body-content{position:relative; top:0;}
    ++#doc-content{overflow:visible;border-left:3px solid #666;}
    ++#side-nav{padding:0;}
    ++#side-nav .toggle-list ul {display:block;}
    ++#resize-packages-nav{border-bottom:3px solid #666;}
    ++</style>
    ++</noscript>
    ++<style type="text/css">
    ++</style>
    ++</HEAD>
    ++<BODY>
    ++<!-- Start of nav bar -->
    ++<a name="top"></a>
    ++<div id="header" style="margin-bottom:0;padding-bottom:0;">
    ++<div id="headerLeft">
    ++<a href="../../../../index.html" tabindex="-1" target="_top"><img src="../../../../assets/images/bg_logo.png" alt="Android Developers" /></a>
    ++</div>
    ++  <div id="headerRight">
    ++  <div id="headerLinks">
    ++<!-- <img src="/assets/images/icon_world.jpg" alt="" /> -->
    ++<span class="text">
    ++<!-- &nbsp;<a href="#">English</a> | -->
    ++<nobr><a href="http://developer.android.com" target="_top">Android Developers</a> | <a href="http://www.android.com" target="_top">Android.com</a></nobr>
    ++</span>
    ++</div>
    ++  <div class="and-diff-id" style="margin-top:6px;margin-right:8px;">
    ++    <table class="diffspectable">
    ++      <tr>
    ++        <td colspan="2" class="diffspechead">API Diff Specification</td>
    ++      </tr>
    ++      <tr>
    ++        <td class="diffspec" style="padding-top:.25em">To Level:</td>
    ++        <td class="diffvaluenew" style="padding-top:.25em">24.2.0</td>
    ++      </tr>
    ++      <tr>
    ++        <td class="diffspec">From Level:</td>
    ++        <td class="diffvalueold">24.1.0</td>
    ++      </tr>
    ++      <tr>
    ++        <td class="diffspec">Generated</td>
    ++        <td class="diffvalue">2016.08.16 14:03</td>
    ++      </tr>
    ++    </table>
    ++    </div><!-- End and-diff-id -->
    ++  <div class="and-diff-id" style="margin-right:8px;">
    ++    <table class="diffspectable">
    ++      <tr>
    ++        <td class="diffspec" colspan="2"><a href="jdiff_statistics.html">Statistics</a>
    ++      </tr>
    ++    </table>
    ++  </div> <!-- End and-diff-id -->
    ++  </div> <!-- End headerRight -->
    ++  </div> <!-- End header -->
    ++<div id="body-content" xstyle="padding:12px;padding-right:18px;">
    ++<div id="doc-content" style="position:relative;">
    ++<div id="mainBodyFluid">
    ++<H2>
    ++Class android.support.v4.media.session.<A HREF="../../../../reference/android/support/v4/media/session/PlaybackStateCompat.html" target="_top"><font size="+2"><code>PlaybackStateCompat</code></font></A>
    ++</H2>
    ++<a NAME="constructors"></a>
    ++<a NAME="methods"></a>
    ++<p>
    ++<a NAME="Added"></a>
    ++<TABLE summary="Added Methods" WIDTH="100%">
    ++<TR>
    ++  <TH VALIGN="TOP" COLSPAN=2>Added Methods</FONT></TD>
    ++</TH>
    ++<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    ++  <TD VALIGN="TOP" WIDTH="25%">
    ++  <A NAME="android.support.v4.media.session.PlaybackStateCompat.toKeyCode_added(long)"></A>
    ++  <nobr><code>int</code>&nbsp;<A HREF="../../../../reference/android/support/v4/media/session/PlaybackStateCompat.html#toKeyCode(long)" target="_top"><code>toKeyCode</code></A>(<code>long</code>)</nobr>
    ++  </TD>
    ++  <TD>&nbsp;</TD>
    ++</TR>
    ++</TABLE>
    ++&nbsp;
    ++<a NAME="fields"></a>
    ++      </div>	
    ++      <div id="footer">
    ++        <div id="copyright">
    ++        Except as noted, this content is licensed under 
    ++        <a href="http://creativecommons.org/licenses/by/2.5/"> Creative Commons Attribution 2.5</a>.
    ++        For details and restrictions, see the <a href="/license.html">Content License</a>.
    ++        </div>
    ++      <div id="footerlinks">
    ++      <p>
    ++        <a href="http://www.android.com/terms.html">Site Terms of Service</a> -
    ++        <a href="http://www.android.com/privacy.html">Privacy Policy</a> -
    ++        <a href="http://www.android.com/branding.html">Brand Guidelines</a>
    ++      </p>
    ++    </div>
    ++    </div> <!-- end footer -->
    ++    </div><!-- end doc-content -->
    ++    </div> <!-- end body-content --> 
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    ++</script>
    ++<script type="text/javascript">
    ++  try {
    ++    var pageTracker = _gat._getTracker("UA-5831155-1");
    ++    pageTracker._setAllowAnchor(true);
    ++    pageTracker._initData();
    ++    pageTracker._trackPageview();
    ++  } catch(e) {}
    ++</script>
    ++</BODY>
    ++</HTML>
    +diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.os.BuildCompat.html b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.os.BuildCompat.html
    +new file mode 100644
    +index 0000000..372415a
    +--- /dev/null
    ++++ b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.os.BuildCompat.html
    +@@ -0,0 +1,122 @@
    ++<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
    ++<HTML style="overflow:auto;">
    ++<HEAD>
    ++<meta name="generator" content="JDiff v1.1.0">
    ++<!-- Generated by the JDiff Javadoc doclet -->
    ++<!-- (http://www.jdiff.org) -->
    ++<meta name="description" content="JDiff is a Javadoc doclet which generates an HTML report of all the packages, classes, constructors, methods, and fields which have been removed, added or changed in any way, including their documentation, when two APIs are compared.">
    ++<meta name="keywords" content="diff, jdiff, javadiff, java diff, java difference, API difference, difference between two APIs, API diff, Javadoc, doclet">
    ++<TITLE>
    ++android.support.v4.os.BuildCompat
    ++</TITLE>
    ++<link href="../../../../assets/android-developer-docs.css" rel="stylesheet" type="text/css" />
    ++<link href="../stylesheet-jdiff.css" rel="stylesheet" type="text/css" />
    ++<noscript>
    ++<style type="text/css">
    ++body{overflow:auto;}
    ++#body-content{position:relative; top:0;}
    ++#doc-content{overflow:visible;border-left:3px solid #666;}
    ++#side-nav{padding:0;}
    ++#side-nav .toggle-list ul {display:block;}
    ++#resize-packages-nav{border-bottom:3px solid #666;}
    ++</style>
    ++</noscript>
    ++<style type="text/css">
    ++</style>
    ++</HEAD>
    ++<BODY>
    ++<!-- Start of nav bar -->
    ++<a name="top"></a>
    ++<div id="header" style="margin-bottom:0;padding-bottom:0;">
    ++<div id="headerLeft">
    ++<a href="../../../../index.html" tabindex="-1" target="_top"><img src="../../../../assets/images/bg_logo.png" alt="Android Developers" /></a>
    ++</div>
    ++  <div id="headerRight">
    ++  <div id="headerLinks">
    ++<!-- <img src="/assets/images/icon_world.jpg" alt="" /> -->
    ++<span class="text">
    ++<!-- &nbsp;<a href="#">English</a> | -->
    ++<nobr><a href="http://developer.android.com" target="_top">Android Developers</a> | <a href="http://www.android.com" target="_top">Android.com</a></nobr>
    ++</span>
    ++</div>
    ++  <div class="and-diff-id" style="margin-top:6px;margin-right:8px;">
    ++    <table class="diffspectable">
    ++      <tr>
    ++        <td colspan="2" class="diffspechead">API Diff Specification</td>
    ++      </tr>
    ++      <tr>
    ++        <td class="diffspec" style="padding-top:.25em">To Level:</td>
    ++        <td class="diffvaluenew" style="padding-top:.25em">24.2.0</td>
    ++      </tr>
    ++      <tr>
    ++        <td class="diffspec">From Level:</td>
    ++        <td class="diffvalueold">24.1.0</td>
    ++      </tr>
    ++      <tr>
    ++        <td class="diffspec">Generated</td>
    ++        <td class="diffvalue">2016.08.16 14:03</td>
    ++      </tr>
    ++    </table>
    ++    </div><!-- End and-diff-id -->
    ++  <div class="and-diff-id" style="margin-right:8px;">
    ++    <table class="diffspectable">
    ++      <tr>
    ++        <td class="diffspec" colspan="2"><a href="jdiff_statistics.html">Statistics</a>
    ++      </tr>
    ++    </table>
    ++  </div> <!-- End and-diff-id -->
    ++  </div> <!-- End headerRight -->
    ++  </div> <!-- End header -->
    ++<div id="body-content" xstyle="padding:12px;padding-right:18px;">
    ++<div id="doc-content" style="position:relative;">
    ++<div id="mainBodyFluid">
    ++<H2>
    ++Class android.support.v4.os.<A HREF="../../../../reference/android/support/v4/os/BuildCompat.html" target="_top"><font size="+2"><code>BuildCompat</code></font></A>
    ++</H2>
    ++<a NAME="constructors"></a>
    ++<a NAME="methods"></a>
    ++<p>
    ++<a NAME="Added"></a>
    ++<TABLE summary="Added Methods" WIDTH="100%">
    ++<TR>
    ++  <TH VALIGN="TOP" COLSPAN=2>Added Methods</FONT></TD>
    ++</TH>
    ++<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    ++  <TD VALIGN="TOP" WIDTH="25%">
    ++  <A NAME="android.support.v4.os.BuildCompat.isAtLeastNMR1_added()"></A>
    ++  <nobr><code>boolean</code>&nbsp;<A HREF="../../../../reference/android/support/v4/os/BuildCompat.html#isAtLeastNMR1()" target="_top"><code>isAtLeastNMR1</code></A>()</nobr>
    ++  </TD>
    ++  <TD>&nbsp;</TD>
    ++</TR>
    ++</TABLE>
    ++&nbsp;
    ++<a NAME="fields"></a>
    ++      </div>	
    ++      <div id="footer">
    ++        <div id="copyright">
    ++        Except as noted, this content is licensed under 
    ++        <a href="http://creativecommons.org/licenses/by/2.5/"> Creative Commons Attribution 2.5</a>.
    ++        For details and restrictions, see the <a href="/license.html">Content License</a>.
    ++        </div>
    ++      <div id="footerlinks">
    ++      <p>
    ++        <a href="http://www.android.com/terms.html">Site Terms of Service</a> -
    ++        <a href="http://www.android.com/privacy.html">Privacy Policy</a> -
    ++        <a href="http://www.android.com/branding.html">Brand Guidelines</a>
    ++      </p>
    ++    </div>
    ++    </div> <!-- end footer -->
    ++    </div><!-- end doc-content -->
    ++    </div> <!-- end body-content --> 
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    ++</script>
    ++<script type="text/javascript">
    ++  try {
    ++    var pageTracker = _gat._getTracker("UA-5831155-1");
    ++    pageTracker._setAllowAnchor(true);
    ++    pageTracker._initData();
    ++    pageTracker._trackPageview();
    ++  } catch(e) {}
    ++</script>
    ++</BODY>
    ++</HTML>
    +diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.view.KeyEventCompat.html b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.view.KeyEventCompat.html
    +new file mode 100644
    +index 0000000..d62437e
    +--- /dev/null
    ++++ b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.view.KeyEventCompat.html
    +@@ -0,0 +1,155 @@
    ++<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
    ++<HTML style="overflow:auto;">
    ++<HEAD>
    ++<meta name="generator" content="JDiff v1.1.0">
    ++<!-- Generated by the JDiff Javadoc doclet -->
    ++<!-- (http://www.jdiff.org) -->
    ++<meta name="description" content="JDiff is a Javadoc doclet which generates an HTML report of all the packages, classes, constructors, methods, and fields which have been removed, added or changed in any way, including their documentation, when two APIs are compared.">
    ++<meta name="keywords" content="diff, jdiff, javadiff, java diff, java difference, API difference, difference between two APIs, API diff, Javadoc, doclet">
    ++<TITLE>
    ++android.support.v4.view.KeyEventCompat
    ++</TITLE>
    ++<link href="../../../../assets/android-developer-docs.css" rel="stylesheet" type="text/css" />
    ++<link href="../stylesheet-jdiff.css" rel="stylesheet" type="text/css" />
    ++<noscript>
    ++<style type="text/css">
    ++body{overflow:auto;}
    ++#body-content{position:relative; top:0;}
    ++#doc-content{overflow:visible;border-left:3px solid #666;}
    ++#side-nav{padding:0;}
    ++#side-nav .toggle-list ul {display:block;}
    ++#resize-packages-nav{border-bottom:3px solid #666;}
    ++</style>
    ++</noscript>
    ++<style type="text/css">
    ++</style>
    ++</HEAD>
    ++<BODY>
    ++<!-- Start of nav bar -->
    ++<a name="top"></a>
    ++<div id="header" style="margin-bottom:0;padding-bottom:0;">
    ++<div id="headerLeft">
    ++<a href="../../../../index.html" tabindex="-1" target="_top"><img src="../../../../assets/images/bg_logo.png" alt="Android Developers" /></a>
    ++</div>
    ++  <div id="headerRight">
    ++  <div id="headerLinks">
    ++<!-- <img src="/assets/images/icon_world.jpg" alt="" /> -->
    ++<span class="text">
    ++<!-- &nbsp;<a href="#">English</a> | -->
    ++<nobr><a href="http://developer.android.com" target="_top">Android Developers</a> | <a href="http://www.android.com" target="_top">Android.com</a></nobr>
    ++</span>
    ++</div>
    ++  <div class="and-diff-id" style="margin-top:6px;margin-right:8px;">
    ++    <table class="diffspectable">
    ++      <tr>
    ++        <td colspan="2" class="diffspechead">API Diff Specification</td>
    ++      </tr>
    ++      <tr>
    ++        <td class="diffspec" style="padding-top:.25em">To Level:</td>
    ++        <td class="diffvaluenew" style="padding-top:.25em">24.2.0</td>
    ++      </tr>
    ++      <tr>
    ++        <td class="diffspec">From Level:</td>
    ++        <td class="diffvalueold">24.1.0</td>
    ++      </tr>
    ++      <tr>
    ++        <td class="diffspec">Generated</td>
    ++        <td class="diffvalue">2016.08.16 14:03</td>
    ++      </tr>
    ++    </table>
    ++    </div><!-- End and-diff-id -->
    ++  <div class="and-diff-id" style="margin-right:8px;">
    ++    <table class="diffspectable">
    ++      <tr>
    ++        <td class="diffspec" colspan="2"><a href="jdiff_statistics.html">Statistics</a>
    ++      </tr>
    ++    </table>
    ++  </div> <!-- End and-diff-id -->
    ++  </div> <!-- End headerRight -->
    ++  </div> <!-- End header -->
    ++<div id="body-content" xstyle="padding:12px;padding-right:18px;">
    ++<div id="doc-content" style="position:relative;">
    ++<div id="mainBodyFluid">
    ++<H2>
    ++Class android.support.v4.view.<A HREF="../../../../reference/android/support/v4/view/KeyEventCompat.html" target="_top"><font size="+2"><code>KeyEventCompat</code></font></A>
    ++</H2>
    ++<a NAME="constructors"></a>
    ++<a NAME="methods"></a>
    ++<p>
    ++<a NAME="Changed"></a>
    ++<TABLE summary="Changed Methods" WIDTH="100%">
    ++<TR>
    ++  <TH VALIGN="TOP" COLSPAN=3>Changed Methods</FONT></TD>
    ++</TH>
    ++<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    ++  <TD VALIGN="TOP" WIDTH="25%">
    ++  <A NAME="android.support.v4.view.KeyEventCompat.dispatch_changed(android.view.KeyEvent, android.view.KeyEvent.Callback, java.lang.Object, java.lang.Object)"></A>
    ++  <nobr><code>boolean</code>&nbsp;<A HREF="../../../../reference/android/support/v4/view/KeyEventCompat.html#dispatch(android.view.KeyEvent, android.view.KeyEvent.Callback, java.lang.Object, java.lang.Object)" target="_top"><code>dispatch</code></A>(<code>KeyEvent,</nobr> Callback<nobr>,</nobr> Object<nobr>,</nobr> Object<nobr><nobr></code>)  </nobr>
    ++  </TD>
    ++  <TD VALIGN="TOP" WIDTH="30%">
    ++<b>Now deprecated</b>.<br>
    ++  </TD>
    ++  <TD>&nbsp;</TD>
    ++</TR>
    ++<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    ++  <TD VALIGN="TOP" WIDTH="25%">
    ++  <A NAME="android.support.v4.view.KeyEventCompat.getKeyDispatcherState_changed(android.view.View)"></A>
    ++  <nobr><code>Object</code>&nbsp;<A HREF="../../../../reference/android/support/v4/view/KeyEventCompat.html#getKeyDispatcherState(android.view.View)" target="_top"><code>getKeyDispatcherState</code></A>(<code>View</code>)  </nobr>
    ++  </TD>
    ++  <TD VALIGN="TOP" WIDTH="30%">
    ++<b>Now deprecated</b>.<br>
    ++  </TD>
    ++  <TD>&nbsp;</TD>
    ++</TR>
    ++<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    ++  <TD VALIGN="TOP" WIDTH="25%">
    ++  <A NAME="android.support.v4.view.KeyEventCompat.isTracking_changed(android.view.KeyEvent)"></A>
    ++  <nobr><code>boolean</code>&nbsp;<A HREF="../../../../reference/android/support/v4/view/KeyEventCompat.html#isTracking(android.view.KeyEvent)" target="_top"><code>isTracking</code></A>(<code>KeyEvent</code>)  </nobr>
    ++  </TD>
    ++  <TD VALIGN="TOP" WIDTH="30%">
    ++<b>Now deprecated</b>.<br>
    ++  </TD>
    ++  <TD>&nbsp;</TD>
    ++</TR>
    ++<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    ++  <TD VALIGN="TOP" WIDTH="25%">
    ++  <A NAME="android.support.v4.view.KeyEventCompat.startTracking_changed(android.view.KeyEvent)"></A>
    ++  <nobr><code>void</code>&nbsp;<A HREF="../../../../reference/android/support/v4/view/KeyEventCompat.html#startTracking(android.view.KeyEvent)" target="_top"><code>startTracking</code></A>(<code>KeyEvent</code>)  </nobr>
    ++  </TD>
    ++  <TD VALIGN="TOP" WIDTH="30%">
    ++<b>Now deprecated</b>.<br>
    ++  </TD>
    ++  <TD>&nbsp;</TD>
    ++</TR>
    ++</TABLE>
    ++&nbsp;
    ++<a NAME="fields"></a>
    ++      </div>	
    ++      <div id="footer">
    ++        <div id="copyright">
    ++        Except as noted, this content is licensed under 
    ++        <a href="http://creativecommons.org/licenses/by/2.5/"> Creative Commons Attribution 2.5</a>.
    ++        For details and restrictions, see the <a href="/license.html">Content License</a>.
    ++        </div>
    ++      <div id="footerlinks">
    ++      <p>
    ++        <a href="http://www.android.com/terms.html">Site Terms of Service</a> -
    ++        <a href="http://www.android.com/privacy.html">Privacy Policy</a> -
    ++        <a href="http://www.android.com/branding.html">Brand Guidelines</a>
    ++      </p>
    ++    </div>
    ++    </div> <!-- end footer -->
    ++    </div><!-- end doc-content -->
    ++    </div> <!-- end body-content --> 
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    ++</script>
    ++<script type="text/javascript">
    ++  try {
    ++    var pageTracker = _gat._getTracker("UA-5831155-1");
    ++    pageTracker._setAllowAnchor(true);
    ++    pageTracker._initData();
    ++    pageTracker._trackPageview();
    ++  } catch(e) {}
    ++</script>
    ++</BODY>
    ++</HTML>
    +diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.view.MotionEventCompat.html b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.view.MotionEventCompat.html
    +new file mode 100644
    +index 0000000..8f58037
    +--- /dev/null
    ++++ b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.view.MotionEventCompat.html
    +@@ -0,0 +1,175 @@
    ++<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
    ++<HTML style="overflow:auto;">
    ++<HEAD>
    ++<meta name="generator" content="JDiff v1.1.0">
    ++<!-- Generated by the JDiff Javadoc doclet -->
    ++<!-- (http://www.jdiff.org) -->
    ++<meta name="description" content="JDiff is a Javadoc doclet which generates an HTML report of all the packages, classes, constructors, methods, and fields which have been removed, added or changed in any way, including their documentation, when two APIs are compared.">
    ++<meta name="keywords" content="diff, jdiff, javadiff, java diff, java difference, API difference, difference between two APIs, API diff, Javadoc, doclet">
    ++<TITLE>
    ++android.support.v4.view.MotionEventCompat
    ++</TITLE>
    ++<link href="../../../../assets/android-developer-docs.css" rel="stylesheet" type="text/css" />
    ++<link href="../stylesheet-jdiff.css" rel="stylesheet" type="text/css" />
    ++<noscript>
    ++<style type="text/css">
    ++body{overflow:auto;}
    ++#body-content{position:relative; top:0;}
    ++#doc-content{overflow:visible;border-left:3px solid #666;}
    ++#side-nav{padding:0;}
    ++#side-nav .toggle-list ul {display:block;}
    ++#resize-packages-nav{border-bottom:3px solid #666;}
    ++</style>
    ++</noscript>
    ++<style type="text/css">
    ++</style>
    ++</HEAD>
    ++<BODY>
    ++<!-- Start of nav bar -->
    ++<a name="top"></a>
    ++<div id="header" style="margin-bottom:0;padding-bottom:0;">
    ++<div id="headerLeft">
    ++<a href="../../../../index.html" tabindex="-1" target="_top"><img src="../../../../assets/images/bg_logo.png" alt="Android Developers" /></a>
    ++</div>
    ++  <div id="headerRight">
    ++  <div id="headerLinks">
    ++<!-- <img src="/assets/images/icon_world.jpg" alt="" /> -->
    ++<span class="text">
    ++<!-- &nbsp;<a href="#">English</a> | -->
    ++<nobr><a href="http://developer.android.com" target="_top">Android Developers</a> | <a href="http://www.android.com" target="_top">Android.com</a></nobr>
    ++</span>
    ++</div>
    ++  <div class="and-diff-id" style="margin-top:6px;margin-right:8px;">
    ++    <table class="diffspectable">
    ++      <tr>
    ++        <td colspan="2" class="diffspechead">API Diff Specification</td>
    ++      </tr>
    ++      <tr>
    ++        <td class="diffspec" style="padding-top:.25em">To Level:</td>
    ++        <td class="diffvaluenew" style="padding-top:.25em">24.2.0</td>
    ++      </tr>
    ++      <tr>
    ++        <td class="diffspec">From Level:</td>
    ++        <td class="diffvalueold">24.1.0</td>
    ++      </tr>
    ++      <tr>
    ++        <td class="diffspec">Generated</td>
    ++        <td class="diffvalue">2016.08.16 14:03</td>
    ++      </tr>
    ++    </table>
    ++    </div><!-- End and-diff-id -->
    ++  <div class="and-diff-id" style="margin-right:8px;">
    ++    <table class="diffspectable">
    ++      <tr>
    ++        <td class="diffspec" colspan="2"><a href="jdiff_statistics.html">Statistics</a>
    ++      </tr>
    ++    </table>
    ++  </div> <!-- End and-diff-id -->
    ++  </div> <!-- End headerRight -->
    ++  </div> <!-- End header -->
    ++<div id="body-content" xstyle="padding:12px;padding-right:18px;">
    ++<div id="doc-content" style="position:relative;">
    ++<div id="mainBodyFluid">
    ++<H2>
    ++Class android.support.v4.view.<A HREF="../../../../reference/android/support/v4/view/MotionEventCompat.html" target="_top"><font size="+2"><code>MotionEventCompat</code></font></A>
    ++</H2>
    ++<a NAME="constructors"></a>
    ++<a NAME="methods"></a>
    ++<p>
    ++<a NAME="Changed"></a>
    ++<TABLE summary="Changed Methods" WIDTH="100%">
    ++<TR>
    ++  <TH VALIGN="TOP" COLSPAN=3>Changed Methods</FONT></TD>
    ++</TH>
    ++<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    ++  <TD VALIGN="TOP" WIDTH="25%">
    ++  <A NAME="android.support.v4.view.MotionEventCompat.findPointerIndex_changed(android.view.MotionEvent, int)"></A>
    ++  <nobr><code>int</code>&nbsp;<A HREF="../../../../reference/android/support/v4/view/MotionEventCompat.html#findPointerIndex(android.view.MotionEvent, int)" target="_top"><code>findPointerIndex</code></A>(<code>MotionEvent,</nobr> int<nobr><nobr></code>)  </nobr>
    ++  </TD>
    ++  <TD VALIGN="TOP" WIDTH="30%">
    ++<b>Now deprecated</b>.<br>
    ++  </TD>
    ++  <TD>&nbsp;</TD>
    ++</TR>
    ++<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    ++  <TD VALIGN="TOP" WIDTH="25%">
    ++  <A NAME="android.support.v4.view.MotionEventCompat.getPointerCount_changed(android.view.MotionEvent)"></A>
    ++  <nobr><code>int</code>&nbsp;<A HREF="../../../../reference/android/support/v4/view/MotionEventCompat.html#getPointerCount(android.view.MotionEvent)" target="_top"><code>getPointerCount</code></A>(<code>MotionEvent</code>)  </nobr>
    ++  </TD>
    ++  <TD VALIGN="TOP" WIDTH="30%">
    ++<b>Now deprecated</b>.<br>
    ++  </TD>
    ++  <TD>&nbsp;</TD>
    ++</TR>
    ++<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    ++  <TD VALIGN="TOP" WIDTH="25%">
    ++  <A NAME="android.support.v4.view.MotionEventCompat.getPointerId_changed(android.view.MotionEvent, int)"></A>
    ++  <nobr><code>int</code>&nbsp;<A HREF="../../../../reference/android/support/v4/view/MotionEventCompat.html#getPointerId(android.view.MotionEvent, int)" target="_top"><code>getPointerId</code></A>(<code>MotionEvent,</nobr> int<nobr><nobr></code>)  </nobr>
    ++  </TD>
    ++  <TD VALIGN="TOP" WIDTH="30%">
    ++<b>Now deprecated</b>.<br>
    ++  </TD>
    ++  <TD>&nbsp;</TD>
    ++</TR>
    ++<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    ++  <TD VALIGN="TOP" WIDTH="25%">
    ++  <A NAME="android.support.v4.view.MotionEventCompat.getSource_changed(android.view.MotionEvent)"></A>
    ++  <nobr><code>int</code>&nbsp;<A HREF="../../../../reference/android/support/v4/view/MotionEventCompat.html#getSource(android.view.MotionEvent)" target="_top"><code>getSource</code></A>(<code>MotionEvent</code>)  </nobr>
    ++  </TD>
    ++  <TD VALIGN="TOP" WIDTH="30%">
    ++<b>Now deprecated</b>.<br>
    ++  </TD>
    ++  <TD>&nbsp;</TD>
    ++</TR>
    ++<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    ++  <TD VALIGN="TOP" WIDTH="25%">
    ++  <A NAME="android.support.v4.view.MotionEventCompat.getX_changed(android.view.MotionEvent, int)"></A>
    ++  <nobr><code>float</code>&nbsp;<A HREF="../../../../reference/android/support/v4/view/MotionEventCompat.html#getX(android.view.MotionEvent, int)" target="_top"><code>getX</code></A>(<code>MotionEvent,</nobr> int<nobr><nobr></code>)  </nobr>
    ++  </TD>
    ++  <TD VALIGN="TOP" WIDTH="30%">
    ++<b>Now deprecated</b>.<br>
    ++  </TD>
    ++  <TD>&nbsp;</TD>
    ++</TR>
    ++<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    ++  <TD VALIGN="TOP" WIDTH="25%">
    ++  <A NAME="android.support.v4.view.MotionEventCompat.getY_changed(android.view.MotionEvent, int)"></A>
    ++  <nobr><code>float</code>&nbsp;<A HREF="../../../../reference/android/support/v4/view/MotionEventCompat.html#getY(android.view.MotionEvent, int)" target="_top"><code>getY</code></A>(<code>MotionEvent,</nobr> int<nobr><nobr></code>)  </nobr>
    ++  </TD>
    ++  <TD VALIGN="TOP" WIDTH="30%">
    ++<b>Now deprecated</b>.<br>
    ++  </TD>
    ++  <TD>&nbsp;</TD>
    ++</TR>
    ++</TABLE>
    ++&nbsp;
    ++<a NAME="fields"></a>
    ++      </div>	
    ++      <div id="footer">
    ++        <div id="copyright">
    ++        Except as noted, this content is licensed under 
    ++        <a href="http://creativecommons.org/licenses/by/2.5/"> Creative Commons Attribution 2.5</a>.
    ++        For details and restrictions, see the <a href="/license.html">Content License</a>.
    ++        </div>
    ++      <div id="footerlinks">
    ++      <p>
    ++        <a href="http://www.android.com/terms.html">Site Terms of Service</a> -
    ++        <a href="http://www.android.com/privacy.html">Privacy Policy</a> -
    ++        <a href="http://www.android.com/branding.html">Brand Guidelines</a>
    ++      </p>
    ++    </div>
    ++    </div> <!-- end footer -->
    ++    </div><!-- end doc-content -->
    ++    </div> <!-- end body-content --> 
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    ++</script>
    ++<script type="text/javascript">
    ++  try {
    ++    var pageTracker = _gat._getTracker("UA-5831155-1");
    ++    pageTracker._setAllowAnchor(true);
    ++    pageTracker._initData();
    ++    pageTracker._trackPageview();
    ++  } catch(e) {}
    ++</script>
    ++</BODY>
    ++</HTML>
    +diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.view.ViewCompat.html b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.view.ViewCompat.html
    +new file mode 100644
    +index 0000000..0974230
    +--- /dev/null
    ++++ b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.view.ViewCompat.html
    +@@ -0,0 +1,195 @@
    ++<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
    ++<HTML style="overflow:auto;">
    ++<HEAD>
    ++<meta name="generator" content="JDiff v1.1.0">
    ++<!-- Generated by the JDiff Javadoc doclet -->
    ++<!-- (http://www.jdiff.org) -->
    ++<meta name="description" content="JDiff is a Javadoc doclet which generates an HTML report of all the packages, classes, constructors, methods, and fields which have been removed, added or changed in any way, including their documentation, when two APIs are compared.">
    ++<meta name="keywords" content="diff, jdiff, javadiff, java diff, java difference, API difference, difference between two APIs, API diff, Javadoc, doclet">
    ++<TITLE>
    ++android.support.v4.view.ViewCompat
    ++</TITLE>
    ++<link href="../../../../assets/android-developer-docs.css" rel="stylesheet" type="text/css" />
    ++<link href="../stylesheet-jdiff.css" rel="stylesheet" type="text/css" />
    ++<noscript>
    ++<style type="text/css">
    ++body{overflow:auto;}
    ++#body-content{position:relative; top:0;}
    ++#doc-content{overflow:visible;border-left:3px solid #666;}
    ++#side-nav{padding:0;}
    ++#side-nav .toggle-list ul {display:block;}
    ++#resize-packages-nav{border-bottom:3px solid #666;}
    ++</style>
    ++</noscript>
    ++<style type="text/css">
    ++</style>
    ++</HEAD>
    ++<BODY>
    ++<!-- Start of nav bar -->
    ++<a name="top"></a>
    ++<div id="header" style="margin-bottom:0;padding-bottom:0;">
    ++<div id="headerLeft">
    ++<a href="../../../../index.html" tabindex="-1" target="_top"><img src="../../../../assets/images/bg_logo.png" alt="Android Developers" /></a>
    ++</div>
    ++  <div id="headerRight">
    ++  <div id="headerLinks">
    ++<!-- <img src="/assets/images/icon_world.jpg" alt="" /> -->
    ++<span class="text">
    ++<!-- &nbsp;<a href="#">English</a> | -->
    ++<nobr><a href="http://developer.android.com" target="_top">Android Developers</a> | <a href="http://www.android.com" target="_top">Android.com</a></nobr>
    ++</span>
    ++</div>
    ++  <div class="and-diff-id" style="margin-top:6px;margin-right:8px;">
    ++    <table class="diffspectable">
    ++      <tr>
    ++        <td colspan="2" class="diffspechead">API Diff Specification</td>
    ++      </tr>
    ++      <tr>
    ++        <td class="diffspec" style="padding-top:.25em">To Level:</td>
    ++        <td class="diffvaluenew" style="padding-top:.25em">24.2.0</td>
    ++      </tr>
    ++      <tr>
    ++        <td class="diffspec">From Level:</td>
    ++        <td class="diffvalueold">24.1.0</td>
    ++      </tr>
    ++      <tr>
    ++        <td class="diffspec">Generated</td>
    ++        <td class="diffvalue">2016.08.16 14:03</td>
    ++      </tr>
    ++    </table>
    ++    </div><!-- End and-diff-id -->
    ++  <div class="and-diff-id" style="margin-right:8px;">
    ++    <table class="diffspectable">
    ++      <tr>
    ++        <td class="diffspec" colspan="2"><a href="jdiff_statistics.html">Statistics</a>
    ++      </tr>
    ++    </table>
    ++  </div> <!-- End and-diff-id -->
    ++  </div> <!-- End headerRight -->
    ++  </div> <!-- End header -->
    ++<div id="body-content" xstyle="padding:12px;padding-right:18px;">
    ++<div id="doc-content" style="position:relative;">
    ++<div id="mainBodyFluid">
    ++<H2>
    ++Class android.support.v4.view.<A HREF="../../../../reference/android/support/v4/view/ViewCompat.html" target="_top"><font size="+2"><code>ViewCompat</code></font></A>
    ++</H2>
    ++<a NAME="constructors"></a>
    ++<a NAME="methods"></a>
    ++<p>
    ++<a NAME="Added"></a>
    ++<TABLE summary="Added Methods" WIDTH="100%">
    ++<TR>
    ++  <TH VALIGN="TOP" COLSPAN=2>Added Methods</FONT></TD>
    ++</TH>
    ++<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    ++  <TD VALIGN="TOP" WIDTH="25%">
    ++  <A NAME="android.support.v4.view.ViewCompat.isImportantForAccessibility_added(android.view.View)"></A>
    ++  <nobr><code>boolean</code>&nbsp;<A HREF="../../../../reference/android/support/v4/view/ViewCompat.html#isImportantForAccessibility(android.view.View)" target="_top"><code>isImportantForAccessibility</code></A>(<code>View</code>)</nobr>
    ++  </TD>
    ++  <TD>&nbsp;</TD>
    ++</TR>
    ++</TABLE>
    ++&nbsp;
    ++<p>
    ++<a NAME="Changed"></a>
    ++<TABLE summary="Changed Methods" WIDTH="100%">
    ++<TR>
    ++  <TH VALIGN="TOP" COLSPAN=3>Changed Methods</FONT></TD>
    ++</TH>
    ++<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    ++  <TD VALIGN="TOP" WIDTH="25%">
    ++  <A NAME="android.support.v4.view.ViewCompat.getOverScrollMode_changed(android.view.View)"></A>
    ++  <nobr><code>int</code>&nbsp;<A HREF="../../../../reference/android/support/v4/view/ViewCompat.html#getOverScrollMode(android.view.View)" target="_top"><code>getOverScrollMode</code></A>(<code>View</code>)  </nobr>
    ++  </TD>
    ++  <TD VALIGN="TOP" WIDTH="30%">
    ++<b>Now deprecated</b>.<br>
    ++  </TD>
    ++  <TD>&nbsp;</TD>
    ++</TR>
    ++<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    ++  <TD VALIGN="TOP" WIDTH="25%">
    ++  <A NAME="android.support.v4.view.ViewCompat.isOpaque_changed(android.view.View)"></A>
    ++  <nobr><code>boolean</code>&nbsp;<A HREF="../../../../reference/android/support/v4/view/ViewCompat.html#isOpaque(android.view.View)" target="_top"><code>isOpaque</code></A>(<code>View</code>)  </nobr>
    ++  </TD>
    ++  <TD VALIGN="TOP" WIDTH="30%">
    ++<b>Now deprecated</b>.<br>
    ++  </TD>
    ++  <TD>&nbsp;</TD>
    ++</TR>
    ++<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    ++  <TD VALIGN="TOP" WIDTH="25%">
    ++  <A NAME="android.support.v4.view.ViewCompat.setOverScrollMode_changed(android.view.View, int)"></A>
    ++  <nobr><code>void</code>&nbsp;<A HREF="../../../../reference/android/support/v4/view/ViewCompat.html#setOverScrollMode(android.view.View, int)" target="_top"><code>setOverScrollMode</code></A>(<code>View,</nobr> int<nobr><nobr></code>)  </nobr>
    ++  </TD>
    ++  <TD VALIGN="TOP" WIDTH="30%">
    ++<b>Now deprecated</b>.<br>
    ++  </TD>
    ++  <TD>&nbsp;</TD>
    ++</TR>
    ++</TABLE>
    ++&nbsp;
    ++<a NAME="fields"></a>
    ++<p>
    ++<a NAME="Changed"></a>
    ++<TABLE summary="Changed Fields" WIDTH="100%">
    ++<TR>
    ++  <TH VALIGN="TOP" COLSPAN=3>Changed Fields</FONT></TD>
    ++</TH>
    ++<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    ++  <TD VALIGN="TOP" WIDTH="25%">
    ++  <A NAME="android.support.v4.view.ViewCompat.OVER_SCROLL_ALWAYS"></A>
    ++  <nobr><code>int</code>&nbsp;<A HREF="../../../../reference/android/support/v4/view/ViewCompat.html#OVER_SCROLL_ALWAYS" target="_top"><code>OVER_SCROLL_ALWAYS</code></font></A></nobr>  </TD>
    ++  <TD VALIGN="TOP" WIDTH="30%">
    ++<b>Now deprecated</b>.<br>
    ++  </TD>
    ++  <TD>&nbsp;</TD>
    ++</TR>
    ++<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    ++  <TD VALIGN="TOP" WIDTH="25%">
    ++  <A NAME="android.support.v4.view.ViewCompat.OVER_SCROLL_IF_CONTENT_SCROLLS"></A>
    ++  <nobr><code>int</code>&nbsp;<A HREF="../../../../reference/android/support/v4/view/ViewCompat.html#OVER_SCROLL_IF_CONTENT_SCROLLS" target="_top"><code>OVER_SCROLL_IF_CONTENT_SCROLLS</code></font></A></nobr>  </TD>
    ++  <TD VALIGN="TOP" WIDTH="30%">
    ++<b>Now deprecated</b>.<br>
    ++  </TD>
    ++  <TD>&nbsp;</TD>
    ++</TR>
    ++<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    ++  <TD VALIGN="TOP" WIDTH="25%">
    ++  <A NAME="android.support.v4.view.ViewCompat.OVER_SCROLL_NEVER"></A>
    ++  <nobr><code>int</code>&nbsp;<A HREF="../../../../reference/android/support/v4/view/ViewCompat.html#OVER_SCROLL_NEVER" target="_top"><code>OVER_SCROLL_NEVER</code></font></A></nobr>  </TD>
    ++  <TD VALIGN="TOP" WIDTH="30%">
    ++<b>Now deprecated</b>.<br>
    ++  </TD>
    ++  <TD>&nbsp;</TD>
    ++</TR>
    ++</TABLE>
    ++&nbsp;
    ++      </div>	
    ++      <div id="footer">
    ++        <div id="copyright">
    ++        Except as noted, this content is licensed under 
    ++        <a href="http://creativecommons.org/licenses/by/2.5/"> Creative Commons Attribution 2.5</a>.
    ++        For details and restrictions, see the <a href="/license.html">Content License</a>.
    ++        </div>
    ++      <div id="footerlinks">
    ++      <p>
    ++        <a href="http://www.android.com/terms.html">Site Terms of Service</a> -
    ++        <a href="http://www.android.com/privacy.html">Privacy Policy</a> -
    ++        <a href="http://www.android.com/branding.html">Brand Guidelines</a>
    ++      </p>
    ++    </div>
    ++    </div> <!-- end footer -->
    ++    </div><!-- end doc-content -->
    ++    </div> <!-- end body-content --> 
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    ++</script>
    ++<script type="text/javascript">
    ++  try {
    ++    var pageTracker = _gat._getTracker("UA-5831155-1");
    ++    pageTracker._setAllowAnchor(true);
    ++    pageTracker._initData();
    ++    pageTracker._trackPageview();
    ++  } catch(e) {}
    ++</script>
    ++</BODY>
    ++</HTML>
    +diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.view.ViewConfigurationCompat.html b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.view.ViewConfigurationCompat.html
    +new file mode 100644
    +index 0000000..3eec7fa
    +--- /dev/null
    ++++ b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.view.ViewConfigurationCompat.html
    +@@ -0,0 +1,125 @@
    ++<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
    ++<HTML style="overflow:auto;">
    ++<HEAD>
    ++<meta name="generator" content="JDiff v1.1.0">
    ++<!-- Generated by the JDiff Javadoc doclet -->
    ++<!-- (http://www.jdiff.org) -->
    ++<meta name="description" content="JDiff is a Javadoc doclet which generates an HTML report of all the packages, classes, constructors, methods, and fields which have been removed, added or changed in any way, including their documentation, when two APIs are compared.">
    ++<meta name="keywords" content="diff, jdiff, javadiff, java diff, java difference, API difference, difference between two APIs, API diff, Javadoc, doclet">
    ++<TITLE>
    ++android.support.v4.view.ViewConfigurationCompat
    ++</TITLE>
    ++<link href="../../../../assets/android-developer-docs.css" rel="stylesheet" type="text/css" />
    ++<link href="../stylesheet-jdiff.css" rel="stylesheet" type="text/css" />
    ++<noscript>
    ++<style type="text/css">
    ++body{overflow:auto;}
    ++#body-content{position:relative; top:0;}
    ++#doc-content{overflow:visible;border-left:3px solid #666;}
    ++#side-nav{padding:0;}
    ++#side-nav .toggle-list ul {display:block;}
    ++#resize-packages-nav{border-bottom:3px solid #666;}
    ++</style>
    ++</noscript>
    ++<style type="text/css">
    ++</style>
    ++</HEAD>
    ++<BODY>
    ++<!-- Start of nav bar -->
    ++<a name="top"></a>
    ++<div id="header" style="margin-bottom:0;padding-bottom:0;">
    ++<div id="headerLeft">
    ++<a href="../../../../index.html" tabindex="-1" target="_top"><img src="../../../../assets/images/bg_logo.png" alt="Android Developers" /></a>
    ++</div>
    ++  <div id="headerRight">
    ++  <div id="headerLinks">
    ++<!-- <img src="/assets/images/icon_world.jpg" alt="" /> -->
    ++<span class="text">
    ++<!-- &nbsp;<a href="#">English</a> | -->
    ++<nobr><a href="http://developer.android.com" target="_top">Android Developers</a> | <a href="http://www.android.com" target="_top">Android.com</a></nobr>
    ++</span>
    ++</div>
    ++  <div class="and-diff-id" style="margin-top:6px;margin-right:8px;">
    ++    <table class="diffspectable">
    ++      <tr>
    ++        <td colspan="2" class="diffspechead">API Diff Specification</td>
    ++      </tr>
    ++      <tr>
    ++        <td class="diffspec" style="padding-top:.25em">To Level:</td>
    ++        <td class="diffvaluenew" style="padding-top:.25em">24.2.0</td>
    ++      </tr>
    ++      <tr>
    ++        <td class="diffspec">From Level:</td>
    ++        <td class="diffvalueold">24.1.0</td>
    ++      </tr>
    ++      <tr>
    ++        <td class="diffspec">Generated</td>
    ++        <td class="diffvalue">2016.08.16 14:03</td>
    ++      </tr>
    ++    </table>
    ++    </div><!-- End and-diff-id -->
    ++  <div class="and-diff-id" style="margin-right:8px;">
    ++    <table class="diffspectable">
    ++      <tr>
    ++        <td class="diffspec" colspan="2"><a href="jdiff_statistics.html">Statistics</a>
    ++      </tr>
    ++    </table>
    ++  </div> <!-- End and-diff-id -->
    ++  </div> <!-- End headerRight -->
    ++  </div> <!-- End header -->
    ++<div id="body-content" xstyle="padding:12px;padding-right:18px;">
    ++<div id="doc-content" style="position:relative;">
    ++<div id="mainBodyFluid">
    ++<H2>
    ++Class android.support.v4.view.<A HREF="../../../../reference/android/support/v4/view/ViewConfigurationCompat.html" target="_top"><font size="+2"><code>ViewConfigurationCompat</code></font></A>
    ++</H2>
    ++<a NAME="constructors"></a>
    ++<a NAME="methods"></a>
    ++<p>
    ++<a NAME="Changed"></a>
    ++<TABLE summary="Changed Methods" WIDTH="100%">
    ++<TR>
    ++  <TH VALIGN="TOP" COLSPAN=3>Changed Methods</FONT></TD>
    ++</TH>
    ++<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    ++  <TD VALIGN="TOP" WIDTH="25%">
    ++  <A NAME="android.support.v4.view.ViewConfigurationCompat.getScaledPagingTouchSlop_changed(android.view.ViewConfiguration)"></A>
    ++  <nobr><code>int</code>&nbsp;<A HREF="../../../../reference/android/support/v4/view/ViewConfigurationCompat.html#getScaledPagingTouchSlop(android.view.ViewConfiguration)" target="_top"><code>getScaledPagingTouchSlop</code></A>(<code>ViewConfiguration</code>)  </nobr>
    ++  </TD>
    ++  <TD VALIGN="TOP" WIDTH="30%">
    ++<b>Now deprecated</b>.<br>
    ++  </TD>
    ++  <TD>&nbsp;</TD>
    ++</TR>
    ++</TABLE>
    ++&nbsp;
    ++<a NAME="fields"></a>
    ++      </div>	
    ++      <div id="footer">
    ++        <div id="copyright">
    ++        Except as noted, this content is licensed under 
    ++        <a href="http://creativecommons.org/licenses/by/2.5/"> Creative Commons Attribution 2.5</a>.
    ++        For details and restrictions, see the <a href="/license.html">Content License</a>.
    ++        </div>
    ++      <div id="footerlinks">
    ++      <p>
    ++        <a href="http://www.android.com/terms.html">Site Terms of Service</a> -
    ++        <a href="http://www.android.com/privacy.html">Privacy Policy</a> -
    ++        <a href="http://www.android.com/branding.html">Brand Guidelines</a>
    ++      </p>
    ++    </div>
    ++    </div> <!-- end footer -->
    ++    </div><!-- end doc-content -->
    ++    </div> <!-- end body-content --> 
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    ++</script>
    ++<script type="text/javascript">
    ++  try {
    ++    var pageTracker = _gat._getTracker("UA-5831155-1");
    ++    pageTracker._setAllowAnchor(true);
    ++    pageTracker._initData();
    ++    pageTracker._trackPageview();
    ++  } catch(e) {}
    ++</script>
    ++</BODY>
    ++</HTML>
    +diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.view.WindowInsetsCompat.html b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.view.WindowInsetsCompat.html
    +new file mode 100644
    +index 0000000..c5c1d22
    +--- /dev/null
    ++++ b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.view.WindowInsetsCompat.html
    +@@ -0,0 +1,122 @@
    ++<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
    ++<HTML style="overflow:auto;">
    ++<HEAD>
    ++<meta name="generator" content="JDiff v1.1.0">
    ++<!-- Generated by the JDiff Javadoc doclet -->
    ++<!-- (http://www.jdiff.org) -->
    ++<meta name="description" content="JDiff is a Javadoc doclet which generates an HTML report of all the packages, classes, constructors, methods, and fields which have been removed, added or changed in any way, including their documentation, when two APIs are compared.">
    ++<meta name="keywords" content="diff, jdiff, javadiff, java diff, java difference, API difference, difference between two APIs, API diff, Javadoc, doclet">
    ++<TITLE>
    ++android.support.v4.view.WindowInsetsCompat
    ++</TITLE>
    ++<link href="../../../../assets/android-developer-docs.css" rel="stylesheet" type="text/css" />
    ++<link href="../stylesheet-jdiff.css" rel="stylesheet" type="text/css" />
    ++<noscript>
    ++<style type="text/css">
    ++body{overflow:auto;}
    ++#body-content{position:relative; top:0;}
    ++#doc-content{overflow:visible;border-left:3px solid #666;}
    ++#side-nav{padding:0;}
    ++#side-nav .toggle-list ul {display:block;}
    ++#resize-packages-nav{border-bottom:3px solid #666;}
    ++</style>
    ++</noscript>
    ++<style type="text/css">
    ++</style>
    ++</HEAD>
    ++<BODY>
    ++<!-- Start of nav bar -->
    ++<a name="top"></a>
    ++<div id="header" style="margin-bottom:0;padding-bottom:0;">
    ++<div id="headerLeft">
    ++<a href="../../../../index.html" tabindex="-1" target="_top"><img src="../../../../assets/images/bg_logo.png" alt="Android Developers" /></a>
    ++</div>
    ++  <div id="headerRight">
    ++  <div id="headerLinks">
    ++<!-- <img src="/assets/images/icon_world.jpg" alt="" /> -->
    ++<span class="text">
    ++<!-- &nbsp;<a href="#">English</a> | -->
    ++<nobr><a href="http://developer.android.com" target="_top">Android Developers</a> | <a href="http://www.android.com" target="_top">Android.com</a></nobr>
    ++</span>
    ++</div>
    ++  <div class="and-diff-id" style="margin-top:6px;margin-right:8px;">
    ++    <table class="diffspectable">
    ++      <tr>
    ++        <td colspan="2" class="diffspechead">API Diff Specification</td>
    ++      </tr>
    ++      <tr>
    ++        <td class="diffspec" style="padding-top:.25em">To Level:</td>
    ++        <td class="diffvaluenew" style="padding-top:.25em">24.2.0</td>
    ++      </tr>
    ++      <tr>
    ++        <td class="diffspec">From Level:</td>
    ++        <td class="diffvalueold">24.1.0</td>
    ++      </tr>
    ++      <tr>
    ++        <td class="diffspec">Generated</td>
    ++        <td class="diffvalue">2016.08.16 14:03</td>
    ++      </tr>
    ++    </table>
    ++    </div><!-- End and-diff-id -->
    ++  <div class="and-diff-id" style="margin-right:8px;">
    ++    <table class="diffspectable">
    ++      <tr>
    ++        <td class="diffspec" colspan="2"><a href="jdiff_statistics.html">Statistics</a>
    ++      </tr>
    ++    </table>
    ++  </div> <!-- End and-diff-id -->
    ++  </div> <!-- End headerRight -->
    ++  </div> <!-- End header -->
    ++<div id="body-content" xstyle="padding:12px;padding-right:18px;">
    ++<div id="doc-content" style="position:relative;">
    ++<div id="mainBodyFluid">
    ++<H2>
    ++Class android.support.v4.view.<A HREF="../../../../reference/android/support/v4/view/WindowInsetsCompat.html" target="_top"><font size="+2"><code>WindowInsetsCompat</code></font></A>
    ++</H2>
    ++<a NAME="constructors"></a>
    ++<p>
    ++<a NAME="Added"></a>
    ++<TABLE summary="Added Constructors" WIDTH="100%">
    ++<TR>
    ++  <TH VALIGN="TOP" COLSPAN=2>Added Constructors</FONT></TD>
    ++</TH>
    ++<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    ++  <TD VALIGN="TOP" WIDTH="25%">
    ++  <A NAME="android.support.v4.view.WindowInsetsCompat.ctor_added(android.support.v4.view.WindowInsetsCompat)"></A>
    ++  <nobr><A HREF="../../../../reference/android/support/v4/view/WindowInsetsCompat.html#WindowInsetsCompat(android.support.v4.view.WindowInsetsCompat)" target="_top"><code>WindowInsetsCompat</code></A>(<code>WindowInsetsCompat</code>)</nobr>
    ++  </TD>
    ++  <TD>&nbsp;</TD>
    ++</TR>
    ++</TABLE>
    ++&nbsp;
    ++<a NAME="methods"></a>
    ++<a NAME="fields"></a>
    ++      </div>	
    ++      <div id="footer">
    ++        <div id="copyright">
    ++        Except as noted, this content is licensed under 
    ++        <a href="http://creativecommons.org/licenses/by/2.5/"> Creative Commons Attribution 2.5</a>.
    ++        For details and restrictions, see the <a href="/license.html">Content License</a>.
    ++        </div>
    ++      <div id="footerlinks">
    ++      <p>
    ++        <a href="http://www.android.com/terms.html">Site Terms of Service</a> -
    ++        <a href="http://www.android.com/privacy.html">Privacy Policy</a> -
    ++        <a href="http://www.android.com/branding.html">Brand Guidelines</a>
    ++      </p>
    ++    </div>
    ++    </div> <!-- end footer -->
    ++    </div><!-- end doc-content -->
    ++    </div> <!-- end body-content --> 
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    ++</script>
    ++<script type="text/javascript">
    ++  try {
    ++    var pageTracker = _gat._getTracker("UA-5831155-1");
    ++    pageTracker._setAllowAnchor(true);
    ++    pageTracker._initData();
    ++    pageTracker._trackPageview();
    ++  } catch(e) {}
    ++</script>
    ++</BODY>
    ++</HTML>
    +diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.view.accessibility.AccessibilityEventCompat.html b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.view.accessibility.AccessibilityEventCompat.html
    +new file mode 100644
    +index 0000000..1f9801f
    +--- /dev/null
    ++++ b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.view.accessibility.AccessibilityEventCompat.html
    +@@ -0,0 +1,172 @@
    ++<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
    ++<HTML style="overflow:auto;">
    ++<HEAD>
    ++<meta name="generator" content="JDiff v1.1.0">
    ++<!-- Generated by the JDiff Javadoc doclet -->
    ++<!-- (http://www.jdiff.org) -->
    ++<meta name="description" content="JDiff is a Javadoc doclet which generates an HTML report of all the packages, classes, constructors, methods, and fields which have been removed, added or changed in any way, including their documentation, when two APIs are compared.">
    ++<meta name="keywords" content="diff, jdiff, javadiff, java diff, java difference, API difference, difference between two APIs, API diff, Javadoc, doclet">
    ++<TITLE>
    ++android.support.v4.view.accessibility.AccessibilityEventCompat
    ++</TITLE>
    ++<link href="../../../../assets/android-developer-docs.css" rel="stylesheet" type="text/css" />
    ++<link href="../stylesheet-jdiff.css" rel="stylesheet" type="text/css" />
    ++<noscript>
    ++<style type="text/css">
    ++body{overflow:auto;}
    ++#body-content{position:relative; top:0;}
    ++#doc-content{overflow:visible;border-left:3px solid #666;}
    ++#side-nav{padding:0;}
    ++#side-nav .toggle-list ul {display:block;}
    ++#resize-packages-nav{border-bottom:3px solid #666;}
    ++</style>
    ++</noscript>
    ++<style type="text/css">
    ++</style>
    ++</HEAD>
    ++<BODY>
    ++<!-- Start of nav bar -->
    ++<a name="top"></a>
    ++<div id="header" style="margin-bottom:0;padding-bottom:0;">
    ++<div id="headerLeft">
    ++<a href="../../../../index.html" tabindex="-1" target="_top"><img src="../../../../assets/images/bg_logo.png" alt="Android Developers" /></a>
    ++</div>
    ++  <div id="headerRight">
    ++  <div id="headerLinks">
    ++<!-- <img src="/assets/images/icon_world.jpg" alt="" /> -->
    ++<span class="text">
    ++<!-- &nbsp;<a href="#">English</a> | -->
    ++<nobr><a href="http://developer.android.com" target="_top">Android Developers</a> | <a href="http://www.android.com" target="_top">Android.com</a></nobr>
    ++</span>
    ++</div>
    ++  <div class="and-diff-id" style="margin-top:6px;margin-right:8px;">
    ++    <table class="diffspectable">
    ++      <tr>
    ++        <td colspan="2" class="diffspechead">API Diff Specification</td>
    ++      </tr>
    ++      <tr>
    ++        <td class="diffspec" style="padding-top:.25em">To Level:</td>
    ++        <td class="diffvaluenew" style="padding-top:.25em">24.2.0</td>
    ++      </tr>
    ++      <tr>
    ++        <td class="diffspec">From Level:</td>
    ++        <td class="diffvalueold">24.1.0</td>
    ++      </tr>
    ++      <tr>
    ++        <td class="diffspec">Generated</td>
    ++        <td class="diffvalue">2016.08.16 14:03</td>
    ++      </tr>
    ++    </table>
    ++    </div><!-- End and-diff-id -->
    ++  <div class="and-diff-id" style="margin-right:8px;">
    ++    <table class="diffspectable">
    ++      <tr>
    ++        <td class="diffspec" colspan="2"><a href="jdiff_statistics.html">Statistics</a>
    ++      </tr>
    ++    </table>
    ++  </div> <!-- End and-diff-id -->
    ++  </div> <!-- End headerRight -->
    ++  </div> <!-- End header -->
    ++<div id="body-content" xstyle="padding:12px;padding-right:18px;">
    ++<div id="doc-content" style="position:relative;">
    ++<div id="mainBodyFluid">
    ++<H2>
    ++Class android.support.v4.view.accessibility.<A HREF="../../../../reference/android/support/v4/view/accessibility/AccessibilityEventCompat.html" target="_top"><font size="+2"><code>AccessibilityEventCompat</code></font></A>
    ++</H2>
    ++<a NAME="constructors"></a>
    ++<a NAME="methods"></a>
    ++<p>
    ++<a NAME="Added"></a>
    ++<TABLE summary="Added Methods" WIDTH="100%">
    ++<TR>
    ++  <TH VALIGN="TOP" COLSPAN=2>Added Methods</FONT></TD>
    ++</TH>
    ++<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    ++  <TD VALIGN="TOP" WIDTH="25%">
    ++  <A NAME="android.support.v4.view.accessibility.AccessibilityEventCompat.getAction_added(android.view.accessibility.AccessibilityEvent)"></A>
    ++  <nobr><code>int</code>&nbsp;<A HREF="../../../../reference/android/support/v4/view/accessibility/AccessibilityEventCompat.html#getAction(android.view.accessibility.AccessibilityEvent)" target="_top"><code>getAction</code></A>(<code>AccessibilityEvent</code>)</nobr>
    ++  </TD>
    ++  <TD>&nbsp;</TD>
    ++</TR>
    ++<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    ++  <TD VALIGN="TOP" WIDTH="25%">
    ++  <A NAME="android.support.v4.view.accessibility.AccessibilityEventCompat.getMovementGranularity_added(android.view.accessibility.AccessibilityEvent)"></A>
    ++  <nobr><code>int</code>&nbsp;<A HREF="../../../../reference/android/support/v4/view/accessibility/AccessibilityEventCompat.html#getMovementGranularity(android.view.accessibility.AccessibilityEvent)" target="_top"><code>getMovementGranularity</code></A>(<code>AccessibilityEvent</code>)</nobr>
    ++  </TD>
    ++  <TD>&nbsp;</TD>
    ++</TR>
    ++<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    ++  <TD VALIGN="TOP" WIDTH="25%">
    ++  <A NAME="android.support.v4.view.accessibility.AccessibilityEventCompat.setAction_added(android.view.accessibility.AccessibilityEvent, int)"></A>
    ++  <nobr><code>void</code>&nbsp;<A HREF="../../../../reference/android/support/v4/view/accessibility/AccessibilityEventCompat.html#setAction(android.view.accessibility.AccessibilityEvent, int)" target="_top"><code>setAction</code></A>(<code>AccessibilityEvent,</nobr> int<nobr><nobr></code>)</nobr>
    ++  </TD>
    ++  <TD>&nbsp;</TD>
    ++</TR>
    ++<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    ++  <TD VALIGN="TOP" WIDTH="25%">
    ++  <A NAME="android.support.v4.view.accessibility.AccessibilityEventCompat.setMovementGranularity_added(android.view.accessibility.AccessibilityEvent, int)"></A>
    ++  <nobr><code>void</code>&nbsp;<A HREF="../../../../reference/android/support/v4/view/accessibility/AccessibilityEventCompat.html#setMovementGranularity(android.view.accessibility.AccessibilityEvent, int)" target="_top"><code>setMovementGranularity</code></A>(<code>AccessibilityEvent,</nobr> int<nobr><nobr></code>)</nobr>
    ++  </TD>
    ++  <TD>&nbsp;</TD>
    ++</TR>
    ++</TABLE>
    ++&nbsp;
    ++<a NAME="fields"></a>
    ++<p>
    ++<a NAME="Added"></a>
    ++<TABLE summary="Added Fields" WIDTH="100%">
    ++<TR>
    ++  <TH VALIGN="TOP" COLSPAN=2>Added Fields</FONT></TD>
    ++</TH>
    ++<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    ++  <TD VALIGN="TOP" WIDTH="25%">
    ++  <A NAME="android.support.v4.view.accessibility.AccessibilityEventCompat.TYPE_ASSIST_READING_CONTEXT"></A>
    ++  <nobr><code>int</code>&nbsp;<A HREF="../../../../reference/android/support/v4/view/accessibility/AccessibilityEventCompat.html#TYPE_ASSIST_READING_CONTEXT" target="_top"><code>TYPE_ASSIST_READING_CONTEXT</code></A></nobr>
    ++  </TD>
    ++  <TD>&nbsp;</TD>
    ++</TR>
    ++<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    ++  <TD VALIGN="TOP" WIDTH="25%">
    ++  <A NAME="android.support.v4.view.accessibility.AccessibilityEventCompat.TYPE_VIEW_CONTEXT_CLICKED"></A>
    ++  <nobr><code>int</code>&nbsp;<A HREF="../../../../reference/android/support/v4/view/accessibility/AccessibilityEventCompat.html#TYPE_VIEW_CONTEXT_CLICKED" target="_top"><code>TYPE_VIEW_CONTEXT_CLICKED</code></A></nobr>
    ++  </TD>
    ++  <TD>&nbsp;</TD>
    ++</TR>
    ++<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    ++  <TD VALIGN="TOP" WIDTH="25%">
    ++  <A NAME="android.support.v4.view.accessibility.AccessibilityEventCompat.TYPE_WINDOWS_CHANGED"></A>
    ++  <nobr><code>int</code>&nbsp;<A HREF="../../../../reference/android/support/v4/view/accessibility/AccessibilityEventCompat.html#TYPE_WINDOWS_CHANGED" target="_top"><code>TYPE_WINDOWS_CHANGED</code></A></nobr>
    ++  </TD>
    ++  <TD>&nbsp;</TD>
    ++</TR>
    ++</TABLE>
    ++&nbsp;
    ++      </div>	
    ++      <div id="footer">
    ++        <div id="copyright">
    ++        Except as noted, this content is licensed under 
    ++        <a href="http://creativecommons.org/licenses/by/2.5/"> Creative Commons Attribution 2.5</a>.
    ++        For details and restrictions, see the <a href="/license.html">Content License</a>.
    ++        </div>
    ++      <div id="footerlinks">
    ++      <p>
    ++        <a href="http://www.android.com/terms.html">Site Terms of Service</a> -
    ++        <a href="http://www.android.com/privacy.html">Privacy Policy</a> -
    ++        <a href="http://www.android.com/branding.html">Brand Guidelines</a>
    ++      </p>
    ++    </div>
    ++    </div> <!-- end footer -->
    ++    </div><!-- end doc-content -->
    ++    </div> <!-- end body-content --> 
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    ++</script>
    ++<script type="text/javascript">
    ++  try {
    ++    var pageTracker = _gat._getTracker("UA-5831155-1");
    ++    pageTracker._setAllowAnchor(true);
    ++    pageTracker._initData();
    ++    pageTracker._trackPageview();
    ++  } catch(e) {}
    ++</script>
    ++</BODY>
    ++</HTML>
    +diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.view.accessibility.AccessibilityManagerCompat.AccessibilityStateChangeListenerCompat.html b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.view.accessibility.AccessibilityManagerCompat.AccessibilityStateChangeListenerCompat.html
    +new file mode 100644
    +index 0000000..923ec80
    +--- /dev/null
    ++++ b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.view.accessibility.AccessibilityManagerCompat.AccessibilityStateChangeListenerCompat.html
    +@@ -0,0 +1,124 @@
    ++<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
    ++<HTML style="overflow:auto;">
    ++<HEAD>
    ++<meta name="generator" content="JDiff v1.1.0">
    ++<!-- Generated by the JDiff Javadoc doclet -->
    ++<!-- (http://www.jdiff.org) -->
    ++<meta name="description" content="JDiff is a Javadoc doclet which generates an HTML report of all the packages, classes, constructors, methods, and fields which have been removed, added or changed in any way, including their documentation, when two APIs are compared.">
    ++<meta name="keywords" content="diff, jdiff, javadiff, java diff, java difference, API difference, difference between two APIs, API diff, Javadoc, doclet">
    ++<TITLE>
    ++android.support.v4.view.accessibility.AccessibilityManagerCompat.AccessibilityStateChangeListenerCompat
    ++</TITLE>
    ++<link href="../../../../assets/android-developer-docs.css" rel="stylesheet" type="text/css" />
    ++<link href="../stylesheet-jdiff.css" rel="stylesheet" type="text/css" />
    ++<noscript>
    ++<style type="text/css">
    ++body{overflow:auto;}
    ++#body-content{position:relative; top:0;}
    ++#doc-content{overflow:visible;border-left:3px solid #666;}
    ++#side-nav{padding:0;}
    ++#side-nav .toggle-list ul {display:block;}
    ++#resize-packages-nav{border-bottom:3px solid #666;}
    ++</style>
    ++</noscript>
    ++<style type="text/css">
    ++</style>
    ++</HEAD>
    ++<BODY>
    ++<!-- Start of nav bar -->
    ++<a name="top"></a>
    ++<div id="header" style="margin-bottom:0;padding-bottom:0;">
    ++<div id="headerLeft">
    ++<a href="../../../../index.html" tabindex="-1" target="_top"><img src="../../../../assets/images/bg_logo.png" alt="Android Developers" /></a>
    ++</div>
    ++  <div id="headerRight">
    ++  <div id="headerLinks">
    ++<!-- <img src="/assets/images/icon_world.jpg" alt="" /> -->
    ++<span class="text">
    ++<!-- &nbsp;<a href="#">English</a> | -->
    ++<nobr><a href="http://developer.android.com" target="_top">Android Developers</a> | <a href="http://www.android.com" target="_top">Android.com</a></nobr>
    ++</span>
    ++</div>
    ++  <div class="and-diff-id" style="margin-top:6px;margin-right:8px;">
    ++    <table class="diffspectable">
    ++      <tr>
    ++        <td colspan="2" class="diffspechead">API Diff Specification</td>
    ++      </tr>
    ++      <tr>
    ++        <td class="diffspec" style="padding-top:.25em">To Level:</td>
    ++        <td class="diffvaluenew" style="padding-top:.25em">24.2.0</td>
    ++      </tr>
    ++      <tr>
    ++        <td class="diffspec">From Level:</td>
    ++        <td class="diffvalueold">24.1.0</td>
    ++      </tr>
    ++      <tr>
    ++        <td class="diffspec">Generated</td>
    ++        <td class="diffvalue">2016.08.16 14:03</td>
    ++      </tr>
    ++    </table>
    ++    </div><!-- End and-diff-id -->
    ++  <div class="and-diff-id" style="margin-right:8px;">
    ++    <table class="diffspectable">
    ++      <tr>
    ++        <td class="diffspec" colspan="2"><a href="jdiff_statistics.html">Statistics</a>
    ++      </tr>
    ++    </table>
    ++  </div> <!-- End and-diff-id -->
    ++  </div> <!-- End headerRight -->
    ++  </div> <!-- End header -->
    ++<div id="body-content" xstyle="padding:12px;padding-right:18px;">
    ++<div id="doc-content" style="position:relative;">
    ++<div id="mainBodyFluid">
    ++<H2>
    ++Class android.support.v4.view.accessibility.<A HREF="../../../../reference/android/support/v4/view/accessibility/AccessibilityManagerCompat.AccessibilityStateChangeListenerCompat.html" target="_top"><font size="+2"><code>AccessibilityManagerCompat.AccessibilityStateChangeListenerCompat</code></font></A>
    ++</H2>
    ++<p><font xsize="+1">Added interface <code>android.support.v4.view.accessibility.AccessibilityManagerCompat.AccessibilityStateChangeListener</code>.<br></font>
    ++<p><b>Now deprecated</b>.<br>
    ++<a NAME="constructors"></a>
    ++<a NAME="methods"></a>
    ++<p>
    ++<a NAME="Removed"></a>
    ++<TABLE summary="Removed Methods" WIDTH="100%">
    ++<TR>
    ++  <TH VALIGN="TOP" COLSPAN=2>Removed Methods</FONT></TD>
    ++</TH>
    ++<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    ++  <TD VALIGN="TOP" WIDTH="25%">
    ++  <A NAME="android.support.v4.view.accessibility.AccessibilityManagerCompat.AccessibilityStateChangeListenerCompat.onAccessibilityStateChanged_removed(boolean)"></A>
    ++  <nobr><code>void</code>&nbsp;onAccessibilityStateChanged(<code>boolean</code>)</nobr>
    ++  </TD>
    ++  <TD>&nbsp;</TD>
    ++</TR>
    ++</TABLE>
    ++&nbsp;
    ++<a NAME="fields"></a>
    ++      </div>	
    ++      <div id="footer">
    ++        <div id="copyright">
    ++        Except as noted, this content is licensed under 
    ++        <a href="http://creativecommons.org/licenses/by/2.5/"> Creative Commons Attribution 2.5</a>.
    ++        For details and restrictions, see the <a href="/license.html">Content License</a>.
    ++        </div>
    ++      <div id="footerlinks">
    ++      <p>
    ++        <a href="http://www.android.com/terms.html">Site Terms of Service</a> -
    ++        <a href="http://www.android.com/privacy.html">Privacy Policy</a> -
    ++        <a href="http://www.android.com/branding.html">Brand Guidelines</a>
    ++      </p>
    ++    </div>
    ++    </div> <!-- end footer -->
    ++    </div><!-- end doc-content -->
    ++    </div> <!-- end body-content --> 
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    ++</script>
    ++<script type="text/javascript">
    ++  try {
    ++    var pageTracker = _gat._getTracker("UA-5831155-1");
    ++    pageTracker._setAllowAnchor(true);
    ++    pageTracker._initData();
    ++    pageTracker._trackPageview();
    ++  } catch(e) {}
    ++</script>
    ++</BODY>
    ++</HTML>
    +diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.view.accessibility.AccessibilityManagerCompat.html b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.view.accessibility.AccessibilityManagerCompat.html
    +new file mode 100644
    +index 0000000..defa406
    +--- /dev/null
    ++++ b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.view.accessibility.AccessibilityManagerCompat.html
    +@@ -0,0 +1,157 @@
    ++<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
    ++<HTML style="overflow:auto;">
    ++<HEAD>
    ++<meta name="generator" content="JDiff v1.1.0">
    ++<!-- Generated by the JDiff Javadoc doclet -->
    ++<!-- (http://www.jdiff.org) -->
    ++<meta name="description" content="JDiff is a Javadoc doclet which generates an HTML report of all the packages, classes, constructors, methods, and fields which have been removed, added or changed in any way, including their documentation, when two APIs are compared.">
    ++<meta name="keywords" content="diff, jdiff, javadiff, java diff, java difference, API difference, difference between two APIs, API diff, Javadoc, doclet">
    ++<TITLE>
    ++android.support.v4.view.accessibility.AccessibilityManagerCompat
    ++</TITLE>
    ++<link href="../../../../assets/android-developer-docs.css" rel="stylesheet" type="text/css" />
    ++<link href="../stylesheet-jdiff.css" rel="stylesheet" type="text/css" />
    ++<noscript>
    ++<style type="text/css">
    ++body{overflow:auto;}
    ++#body-content{position:relative; top:0;}
    ++#doc-content{overflow:visible;border-left:3px solid #666;}
    ++#side-nav{padding:0;}
    ++#side-nav .toggle-list ul {display:block;}
    ++#resize-packages-nav{border-bottom:3px solid #666;}
    ++</style>
    ++</noscript>
    ++<style type="text/css">
    ++</style>
    ++</HEAD>
    ++<BODY>
    ++<!-- Start of nav bar -->
    ++<a name="top"></a>
    ++<div id="header" style="margin-bottom:0;padding-bottom:0;">
    ++<div id="headerLeft">
    ++<a href="../../../../index.html" tabindex="-1" target="_top"><img src="../../../../assets/images/bg_logo.png" alt="Android Developers" /></a>
    ++</div>
    ++  <div id="headerRight">
    ++  <div id="headerLinks">
    ++<!-- <img src="/assets/images/icon_world.jpg" alt="" /> -->
    ++<span class="text">
    ++<!-- &nbsp;<a href="#">English</a> | -->
    ++<nobr><a href="http://developer.android.com" target="_top">Android Developers</a> | <a href="http://www.android.com" target="_top">Android.com</a></nobr>
    ++</span>
    ++</div>
    ++  <div class="and-diff-id" style="margin-top:6px;margin-right:8px;">
    ++    <table class="diffspectable">
    ++      <tr>
    ++        <td colspan="2" class="diffspechead">API Diff Specification</td>
    ++      </tr>
    ++      <tr>
    ++        <td class="diffspec" style="padding-top:.25em">To Level:</td>
    ++        <td class="diffvaluenew" style="padding-top:.25em">24.2.0</td>
    ++      </tr>
    ++      <tr>
    ++        <td class="diffspec">From Level:</td>
    ++        <td class="diffvalueold">24.1.0</td>
    ++      </tr>
    ++      <tr>
    ++        <td class="diffspec">Generated</td>
    ++        <td class="diffvalue">2016.08.16 14:03</td>
    ++      </tr>
    ++    </table>
    ++    </div><!-- End and-diff-id -->
    ++  <div class="and-diff-id" style="margin-right:8px;">
    ++    <table class="diffspectable">
    ++      <tr>
    ++        <td class="diffspec" colspan="2"><a href="jdiff_statistics.html">Statistics</a>
    ++      </tr>
    ++    </table>
    ++  </div> <!-- End and-diff-id -->
    ++  </div> <!-- End headerRight -->
    ++  </div> <!-- End header -->
    ++<div id="body-content" xstyle="padding:12px;padding-right:18px;">
    ++<div id="doc-content" style="position:relative;">
    ++<div id="mainBodyFluid">
    ++<H2>
    ++Class android.support.v4.view.accessibility.<A HREF="../../../../reference/android/support/v4/view/accessibility/AccessibilityManagerCompat.html" target="_top"><font size="+2"><code>AccessibilityManagerCompat</code></font></A>
    ++</H2>
    ++<a NAME="constructors"></a>
    ++<a NAME="methods"></a>
    ++<p>
    ++<a NAME="Added"></a>
    ++<TABLE summary="Added Methods" WIDTH="100%">
    ++<TR>
    ++  <TH VALIGN="TOP" COLSPAN=2>Added Methods</FONT></TD>
    ++</TH>
    ++<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    ++  <TD VALIGN="TOP" WIDTH="25%">
    ++  <A NAME="android.support.v4.view.accessibility.AccessibilityManagerCompat.addTouchExplorationStateChangeListener_added(android.view.accessibility.AccessibilityManager, android.support.v4.view.accessibility.AccessibilityManagerCompat.TouchExplorationStateChangeListener)"></A>
    ++  <nobr><code>boolean</code>&nbsp;<A HREF="../../../../reference/android/support/v4/view/accessibility/AccessibilityManagerCompat.html#addTouchExplorationStateChangeListener(android.view.accessibility.AccessibilityManager, android.support.v4.view.accessibility.AccessibilityManagerCompat.TouchExplorationStateChangeListener)" target="_top"><code>addTouchExplorationStateChangeListener</code></A>(<code>AccessibilityManager,</nobr> TouchExplorationStateChangeListener<nobr><nobr></code>)</nobr>
    ++  </TD>
    ++  <TD>&nbsp;</TD>
    ++</TR>
    ++<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    ++  <TD VALIGN="TOP" WIDTH="25%">
    ++  <A NAME="android.support.v4.view.accessibility.AccessibilityManagerCompat.removeTouchExplorationStateChangeListener_added(android.view.accessibility.AccessibilityManager, android.support.v4.view.accessibility.AccessibilityManagerCompat.TouchExplorationStateChangeListener)"></A>
    ++  <nobr><code>boolean</code>&nbsp;<A HREF="../../../../reference/android/support/v4/view/accessibility/AccessibilityManagerCompat.html#removeTouchExplorationStateChangeListener(android.view.accessibility.AccessibilityManager, android.support.v4.view.accessibility.AccessibilityManagerCompat.TouchExplorationStateChangeListener)" target="_top"><code>removeTouchExplorationStateChangeListener</code></A>(<code>AccessibilityManager,</nobr> TouchExplorationStateChangeListener<nobr><nobr></code>)</nobr>
    ++  </TD>
    ++  <TD>&nbsp;</TD>
    ++</TR>
    ++</TABLE>
    ++&nbsp;
    ++<p>
    ++<a NAME="Changed"></a>
    ++<TABLE summary="Changed Methods" WIDTH="100%">
    ++<TR>
    ++  <TH VALIGN="TOP" COLSPAN=3>Changed Methods</FONT></TD>
    ++</TH>
    ++<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    ++  <TD VALIGN="TOP" WIDTH="25%">
    ++  <A NAME="android.support.v4.view.accessibility.AccessibilityManagerCompat.addAccessibilityStateChangeListener_changed(android.view.accessibility.AccessibilityManager, android.support.v4.view.accessibility.AccessibilityManagerCompat.AccessibilityStateChangeListener)"></A>
    ++  <nobr><code>boolean</code>&nbsp;<A HREF="../../../../reference/android/support/v4/view/accessibility/AccessibilityManagerCompat.html#addAccessibilityStateChangeListener(android.view.accessibility.AccessibilityManager, android.support.v4.view.accessibility.AccessibilityManagerCompat.AccessibilityStateChangeListener)" target="_top"><code>addAccessibilityStateChangeListener</code></A>(<code>AccessibilityManager,</nobr> AccessibilityStateChangeListener<nobr><nobr></code>)  </nobr>
    ++  </TD>
    ++  <TD VALIGN="TOP" WIDTH="30%">
    ++Change in signature from (<code>AccessibilityManager, AccessibilityStateChangeListenerCompat</code>) to (<code>AccessibilityManager, AccessibilityStateChangeListener</code>).<br>
    ++  </TD>
    ++  <TD>&nbsp;</TD>
    ++</TR>
    ++<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    ++  <TD VALIGN="TOP" WIDTH="25%">
    ++  <A NAME="android.support.v4.view.accessibility.AccessibilityManagerCompat.removeAccessibilityStateChangeListener_changed(android.view.accessibility.AccessibilityManager, android.support.v4.view.accessibility.AccessibilityManagerCompat.AccessibilityStateChangeListener)"></A>
    ++  <nobr><code>boolean</code>&nbsp;<A HREF="../../../../reference/android/support/v4/view/accessibility/AccessibilityManagerCompat.html#removeAccessibilityStateChangeListener(android.view.accessibility.AccessibilityManager, android.support.v4.view.accessibility.AccessibilityManagerCompat.AccessibilityStateChangeListener)" target="_top"><code>removeAccessibilityStateChangeListener</code></A>(<code>AccessibilityManager,</nobr> AccessibilityStateChangeListener<nobr><nobr></code>)  </nobr>
    ++  </TD>
    ++  <TD VALIGN="TOP" WIDTH="30%">
    ++Change in signature from (<code>AccessibilityManager, AccessibilityStateChangeListenerCompat</code>) to (<code>AccessibilityManager, AccessibilityStateChangeListener</code>).<br>
    ++  </TD>
    ++  <TD>&nbsp;</TD>
    ++</TR>
    ++</TABLE>
    ++&nbsp;
    ++<a NAME="fields"></a>
    ++      </div>	
    ++      <div id="footer">
    ++        <div id="copyright">
    ++        Except as noted, this content is licensed under 
    ++        <a href="http://creativecommons.org/licenses/by/2.5/"> Creative Commons Attribution 2.5</a>.
    ++        For details and restrictions, see the <a href="/license.html">Content License</a>.
    ++        </div>
    ++      <div id="footerlinks">
    ++      <p>
    ++        <a href="http://www.android.com/terms.html">Site Terms of Service</a> -
    ++        <a href="http://www.android.com/privacy.html">Privacy Policy</a> -
    ++        <a href="http://www.android.com/branding.html">Brand Guidelines</a>
    ++      </p>
    ++    </div>
    ++    </div> <!-- end footer -->
    ++    </div><!-- end doc-content -->
    ++    </div> <!-- end body-content --> 
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    ++</script>
    ++<script type="text/javascript">
    ++  try {
    ++    var pageTracker = _gat._getTracker("UA-5831155-1");
    ++    pageTracker._setAllowAnchor(true);
    ++    pageTracker._initData();
    ++    pageTracker._trackPageview();
    ++  } catch(e) {}
    ++</script>
    ++</BODY>
    ++</HTML>
    +diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat.html b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat.html
    +new file mode 100644
    +index 0000000..d6f719e
    +--- /dev/null
    ++++ b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat.html
    +@@ -0,0 +1,171 @@
    ++<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
    ++<HTML style="overflow:auto;">
    ++<HEAD>
    ++<meta name="generator" content="JDiff v1.1.0">
    ++<!-- Generated by the JDiff Javadoc doclet -->
    ++<!-- (http://www.jdiff.org) -->
    ++<meta name="description" content="JDiff is a Javadoc doclet which generates an HTML report of all the packages, classes, constructors, methods, and fields which have been removed, added or changed in any way, including their documentation, when two APIs are compared.">
    ++<meta name="keywords" content="diff, jdiff, javadiff, java diff, java difference, API difference, difference between two APIs, API diff, Javadoc, doclet">
    ++<TITLE>
    ++android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat
    ++</TITLE>
    ++<link href="../../../../assets/android-developer-docs.css" rel="stylesheet" type="text/css" />
    ++<link href="../stylesheet-jdiff.css" rel="stylesheet" type="text/css" />
    ++<noscript>
    ++<style type="text/css">
    ++body{overflow:auto;}
    ++#body-content{position:relative; top:0;}
    ++#doc-content{overflow:visible;border-left:3px solid #666;}
    ++#side-nav{padding:0;}
    ++#side-nav .toggle-list ul {display:block;}
    ++#resize-packages-nav{border-bottom:3px solid #666;}
    ++</style>
    ++</noscript>
    ++<style type="text/css">
    ++</style>
    ++</HEAD>
    ++<BODY>
    ++<!-- Start of nav bar -->
    ++<a name="top"></a>
    ++<div id="header" style="margin-bottom:0;padding-bottom:0;">
    ++<div id="headerLeft">
    ++<a href="../../../../index.html" tabindex="-1" target="_top"><img src="../../../../assets/images/bg_logo.png" alt="Android Developers" /></a>
    ++</div>
    ++  <div id="headerRight">
    ++  <div id="headerLinks">
    ++<!-- <img src="/assets/images/icon_world.jpg" alt="" /> -->
    ++<span class="text">
    ++<!-- &nbsp;<a href="#">English</a> | -->
    ++<nobr><a href="http://developer.android.com" target="_top">Android Developers</a> | <a href="http://www.android.com" target="_top">Android.com</a></nobr>
    ++</span>
    ++</div>
    ++  <div class="and-diff-id" style="margin-top:6px;margin-right:8px;">
    ++    <table class="diffspectable">
    ++      <tr>
    ++        <td colspan="2" class="diffspechead">API Diff Specification</td>
    ++      </tr>
    ++      <tr>
    ++        <td class="diffspec" style="padding-top:.25em">To Level:</td>
    ++        <td class="diffvaluenew" style="padding-top:.25em">24.2.0</td>
    ++      </tr>
    ++      <tr>
    ++        <td class="diffspec">From Level:</td>
    ++        <td class="diffvalueold">24.1.0</td>
    ++      </tr>
    ++      <tr>
    ++        <td class="diffspec">Generated</td>
    ++        <td class="diffvalue">2016.08.16 14:03</td>
    ++      </tr>
    ++    </table>
    ++    </div><!-- End and-diff-id -->
    ++  <div class="and-diff-id" style="margin-right:8px;">
    ++    <table class="diffspectable">
    ++      <tr>
    ++        <td class="diffspec" colspan="2"><a href="jdiff_statistics.html">Statistics</a>
    ++      </tr>
    ++    </table>
    ++  </div> <!-- End and-diff-id -->
    ++  </div> <!-- End headerRight -->
    ++  </div> <!-- End header -->
    ++<div id="body-content" xstyle="padding:12px;padding-right:18px;">
    ++<div id="doc-content" style="position:relative;">
    ++<div id="mainBodyFluid">
    ++<H2>
    ++Class android.support.v4.view.accessibility.<A HREF="../../../../reference/android/support/v4/view/accessibility/AccessibilityNodeInfoCompat.AccessibilityActionCompat.html" target="_top"><font size="+2"><code>AccessibilityNodeInfoCompat.AccessibilityActionCompat</code></font></A>
    ++</H2>
    ++<a NAME="constructors"></a>
    ++<a NAME="methods"></a>
    ++<a NAME="fields"></a>
    ++<p>
    ++<a NAME="Added"></a>
    ++<TABLE summary="Added Fields" WIDTH="100%">
    ++<TR>
    ++  <TH VALIGN="TOP" COLSPAN=2>Added Fields</FONT></TD>
    ++</TH>
    ++<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    ++  <TD VALIGN="TOP" WIDTH="25%">
    ++  <A NAME="android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat.ACTION_CONTEXT_CLICK"></A>
    ++  <nobr><code>AccessibilityActionCompat</code>&nbsp;<A HREF="../../../../reference/android/support/v4/view/accessibility/AccessibilityNodeInfoCompat.AccessibilityActionCompat.html#ACTION_CONTEXT_CLICK" target="_top"><code>ACTION_CONTEXT_CLICK</code></A></nobr>
    ++  </TD>
    ++  <TD>&nbsp;</TD>
    ++</TR>
    ++<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    ++  <TD VALIGN="TOP" WIDTH="25%">
    ++  <A NAME="android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat.ACTION_SCROLL_DOWN"></A>
    ++  <nobr><code>AccessibilityActionCompat</code>&nbsp;<A HREF="../../../../reference/android/support/v4/view/accessibility/AccessibilityNodeInfoCompat.AccessibilityActionCompat.html#ACTION_SCROLL_DOWN" target="_top"><code>ACTION_SCROLL_DOWN</code></A></nobr>
    ++  </TD>
    ++  <TD>&nbsp;</TD>
    ++</TR>
    ++<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    ++  <TD VALIGN="TOP" WIDTH="25%">
    ++  <A NAME="android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat.ACTION_SCROLL_LEFT"></A>
    ++  <nobr><code>AccessibilityActionCompat</code>&nbsp;<A HREF="../../../../reference/android/support/v4/view/accessibility/AccessibilityNodeInfoCompat.AccessibilityActionCompat.html#ACTION_SCROLL_LEFT" target="_top"><code>ACTION_SCROLL_LEFT</code></A></nobr>
    ++  </TD>
    ++  <TD>&nbsp;</TD>
    ++</TR>
    ++<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    ++  <TD VALIGN="TOP" WIDTH="25%">
    ++  <A NAME="android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat.ACTION_SCROLL_RIGHT"></A>
    ++  <nobr><code>AccessibilityActionCompat</code>&nbsp;<A HREF="../../../../reference/android/support/v4/view/accessibility/AccessibilityNodeInfoCompat.AccessibilityActionCompat.html#ACTION_SCROLL_RIGHT" target="_top"><code>ACTION_SCROLL_RIGHT</code></A></nobr>
    ++  </TD>
    ++  <TD>&nbsp;</TD>
    ++</TR>
    ++<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    ++  <TD VALIGN="TOP" WIDTH="25%">
    ++  <A NAME="android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat.ACTION_SCROLL_TO_POSITION"></A>
    ++  <nobr><code>AccessibilityActionCompat</code>&nbsp;<A HREF="../../../../reference/android/support/v4/view/accessibility/AccessibilityNodeInfoCompat.AccessibilityActionCompat.html#ACTION_SCROLL_TO_POSITION" target="_top"><code>ACTION_SCROLL_TO_POSITION</code></A></nobr>
    ++  </TD>
    ++  <TD>&nbsp;</TD>
    ++</TR>
    ++<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    ++  <TD VALIGN="TOP" WIDTH="25%">
    ++  <A NAME="android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat.ACTION_SCROLL_UP"></A>
    ++  <nobr><code>AccessibilityActionCompat</code>&nbsp;<A HREF="../../../../reference/android/support/v4/view/accessibility/AccessibilityNodeInfoCompat.AccessibilityActionCompat.html#ACTION_SCROLL_UP" target="_top"><code>ACTION_SCROLL_UP</code></A></nobr>
    ++  </TD>
    ++  <TD>&nbsp;</TD>
    ++</TR>
    ++<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    ++  <TD VALIGN="TOP" WIDTH="25%">
    ++  <A NAME="android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat.ACTION_SET_PROGRESS"></A>
    ++  <nobr><code>AccessibilityActionCompat</code>&nbsp;<A HREF="../../../../reference/android/support/v4/view/accessibility/AccessibilityNodeInfoCompat.AccessibilityActionCompat.html#ACTION_SET_PROGRESS" target="_top"><code>ACTION_SET_PROGRESS</code></A></nobr>
    ++  </TD>
    ++  <TD>&nbsp;</TD>
    ++</TR>
    ++<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    ++  <TD VALIGN="TOP" WIDTH="25%">
    ++  <A NAME="android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat.ACTION_SHOW_ON_SCREEN"></A>
    ++  <nobr><code>AccessibilityActionCompat</code>&nbsp;<A HREF="../../../../reference/android/support/v4/view/accessibility/AccessibilityNodeInfoCompat.AccessibilityActionCompat.html#ACTION_SHOW_ON_SCREEN" target="_top"><code>ACTION_SHOW_ON_SCREEN</code></A></nobr>
    ++  </TD>
    ++  <TD>&nbsp;</TD>
    ++</TR>
    ++</TABLE>
    ++&nbsp;
    ++      </div>	
    ++      <div id="footer">
    ++        <div id="copyright">
    ++        Except as noted, this content is licensed under 
    ++        <a href="http://creativecommons.org/licenses/by/2.5/"> Creative Commons Attribution 2.5</a>.
    ++        For details and restrictions, see the <a href="/license.html">Content License</a>.
    ++        </div>
    ++      <div id="footerlinks">
    ++      <p>
    ++        <a href="http://www.android.com/terms.html">Site Terms of Service</a> -
    ++        <a href="http://www.android.com/privacy.html">Privacy Policy</a> -
    ++        <a href="http://www.android.com/branding.html">Brand Guidelines</a>
    ++      </p>
    ++    </div>
    ++    </div> <!-- end footer -->
    ++    </div><!-- end doc-content -->
    ++    </div> <!-- end body-content --> 
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    ++</script>
    ++<script type="text/javascript">
    ++  try {
    ++    var pageTracker = _gat._getTracker("UA-5831155-1");
    ++    pageTracker._setAllowAnchor(true);
    ++    pageTracker._initData();
    ++    pageTracker._trackPageview();
    ++  } catch(e) {}
    ++</script>
    ++</BODY>
    ++</HTML>
    +diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.CollectionInfoCompat.html b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.CollectionInfoCompat.html
    +new file mode 100644
    +index 0000000..d087e4a
    +--- /dev/null
    ++++ b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.CollectionInfoCompat.html
    +@@ -0,0 +1,129 @@
    ++<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
    ++<HTML style="overflow:auto;">
    ++<HEAD>
    ++<meta name="generator" content="JDiff v1.1.0">
    ++<!-- Generated by the JDiff Javadoc doclet -->
    ++<!-- (http://www.jdiff.org) -->
    ++<meta name="description" content="JDiff is a Javadoc doclet which generates an HTML report of all the packages, classes, constructors, methods, and fields which have been removed, added or changed in any way, including their documentation, when two APIs are compared.">
    ++<meta name="keywords" content="diff, jdiff, javadiff, java diff, java difference, API difference, difference between two APIs, API diff, Javadoc, doclet">
    ++<TITLE>
    ++android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.CollectionInfoCompat
    ++</TITLE>
    ++<link href="../../../../assets/android-developer-docs.css" rel="stylesheet" type="text/css" />
    ++<link href="../stylesheet-jdiff.css" rel="stylesheet" type="text/css" />
    ++<noscript>
    ++<style type="text/css">
    ++body{overflow:auto;}
    ++#body-content{position:relative; top:0;}
    ++#doc-content{overflow:visible;border-left:3px solid #666;}
    ++#side-nav{padding:0;}
    ++#side-nav .toggle-list ul {display:block;}
    ++#resize-packages-nav{border-bottom:3px solid #666;}
    ++</style>
    ++</noscript>
    ++<style type="text/css">
    ++</style>
    ++</HEAD>
    ++<BODY>
    ++<!-- Start of nav bar -->
    ++<a name="top"></a>
    ++<div id="header" style="margin-bottom:0;padding-bottom:0;">
    ++<div id="headerLeft">
    ++<a href="../../../../index.html" tabindex="-1" target="_top"><img src="../../../../assets/images/bg_logo.png" alt="Android Developers" /></a>
    ++</div>
    ++  <div id="headerRight">
    ++  <div id="headerLinks">
    ++<!-- <img src="/assets/images/icon_world.jpg" alt="" /> -->
    ++<span class="text">
    ++<!-- &nbsp;<a href="#">English</a> | -->
    ++<nobr><a href="http://developer.android.com" target="_top">Android Developers</a> | <a href="http://www.android.com" target="_top">Android.com</a></nobr>
    ++</span>
    ++</div>
    ++  <div class="and-diff-id" style="margin-top:6px;margin-right:8px;">
    ++    <table class="diffspectable">
    ++      <tr>
    ++        <td colspan="2" class="diffspechead">API Diff Specification</td>
    ++      </tr>
    ++      <tr>
    ++        <td class="diffspec" style="padding-top:.25em">To Level:</td>
    ++        <td class="diffvaluenew" style="padding-top:.25em">24.2.0</td>
    ++      </tr>
    ++      <tr>
    ++        <td class="diffspec">From Level:</td>
    ++        <td class="diffvalueold">24.1.0</td>
    ++      </tr>
    ++      <tr>
    ++        <td class="diffspec">Generated</td>
    ++        <td class="diffvalue">2016.08.16 14:03</td>
    ++      </tr>
    ++    </table>
    ++    </div><!-- End and-diff-id -->
    ++  <div class="and-diff-id" style="margin-right:8px;">
    ++    <table class="diffspectable">
    ++      <tr>
    ++        <td class="diffspec" colspan="2"><a href="jdiff_statistics.html">Statistics</a>
    ++      </tr>
    ++    </table>
    ++  </div> <!-- End and-diff-id -->
    ++  </div> <!-- End headerRight -->
    ++  </div> <!-- End header -->
    ++<div id="body-content" xstyle="padding:12px;padding-right:18px;">
    ++<div id="doc-content" style="position:relative;">
    ++<div id="mainBodyFluid">
    ++<H2>
    ++Class android.support.v4.view.accessibility.<A HREF="../../../../reference/android/support/v4/view/accessibility/AccessibilityNodeInfoCompat.CollectionInfoCompat.html" target="_top"><font size="+2"><code>AccessibilityNodeInfoCompat.CollectionInfoCompat</code></font></A>
    ++</H2>
    ++<a NAME="constructors"></a>
    ++<a NAME="methods"></a>
    ++<p>
    ++<a NAME="Added"></a>
    ++<TABLE summary="Added Methods" WIDTH="100%">
    ++<TR>
    ++  <TH VALIGN="TOP" COLSPAN=2>Added Methods</FONT></TD>
    ++</TH>
    ++<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    ++  <TD VALIGN="TOP" WIDTH="25%">
    ++  <A NAME="android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.CollectionInfoCompat.getSelectionMode_added()"></A>
    ++  <nobr><code>int</code>&nbsp;<A HREF="../../../../reference/android/support/v4/view/accessibility/AccessibilityNodeInfoCompat.CollectionInfoCompat.html#getSelectionMode()" target="_top"><code>getSelectionMode</code></A>()</nobr>
    ++  </TD>
    ++  <TD>&nbsp;</TD>
    ++</TR>
    ++<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    ++  <TD VALIGN="TOP" WIDTH="25%">
    ++  <A NAME="android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.CollectionInfoCompat.obtain_added(int, int, boolean)"></A>
    ++  <nobr><code>CollectionInfoCompat</code>&nbsp;<A HREF="../../../../reference/android/support/v4/view/accessibility/AccessibilityNodeInfoCompat.CollectionInfoCompat.html#obtain(int, int, boolean)" target="_top"><code>obtain</code></A>(<code>int,</nobr> int<nobr>,</nobr> boolean<nobr><nobr></code>)</nobr>
    ++  </TD>
    ++  <TD>&nbsp;</TD>
    ++</TR>
    ++</TABLE>
    ++&nbsp;
    ++<a NAME="fields"></a>
    ++      </div>	
    ++      <div id="footer">
    ++        <div id="copyright">
    ++        Except as noted, this content is licensed under 
    ++        <a href="http://creativecommons.org/licenses/by/2.5/"> Creative Commons Attribution 2.5</a>.
    ++        For details and restrictions, see the <a href="/license.html">Content License</a>.
    ++        </div>
    ++      <div id="footerlinks">
    ++      <p>
    ++        <a href="http://www.android.com/terms.html">Site Terms of Service</a> -
    ++        <a href="http://www.android.com/privacy.html">Privacy Policy</a> -
    ++        <a href="http://www.android.com/branding.html">Brand Guidelines</a>
    ++      </p>
    ++    </div>
    ++    </div> <!-- end footer -->
    ++    </div><!-- end doc-content -->
    ++    </div> <!-- end body-content --> 
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    ++</script>
    ++<script type="text/javascript">
    ++  try {
    ++    var pageTracker = _gat._getTracker("UA-5831155-1");
    ++    pageTracker._setAllowAnchor(true);
    ++    pageTracker._initData();
    ++    pageTracker._trackPageview();
    ++  } catch(e) {}
    ++</script>
    ++</BODY>
    ++</HTML>
    +diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.CollectionItemInfoCompat.html b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.CollectionItemInfoCompat.html
    +new file mode 100644
    +index 0000000..84fc73b
    +--- /dev/null
    ++++ b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.CollectionItemInfoCompat.html
    +@@ -0,0 +1,122 @@
    ++<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
    ++<HTML style="overflow:auto;">
    ++<HEAD>
    ++<meta name="generator" content="JDiff v1.1.0">
    ++<!-- Generated by the JDiff Javadoc doclet -->
    ++<!-- (http://www.jdiff.org) -->
    ++<meta name="description" content="JDiff is a Javadoc doclet which generates an HTML report of all the packages, classes, constructors, methods, and fields which have been removed, added or changed in any way, including their documentation, when two APIs are compared.">
    ++<meta name="keywords" content="diff, jdiff, javadiff, java diff, java difference, API difference, difference between two APIs, API diff, Javadoc, doclet">
    ++<TITLE>
    ++android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.CollectionItemInfoCompat
    ++</TITLE>
    ++<link href="../../../../assets/android-developer-docs.css" rel="stylesheet" type="text/css" />
    ++<link href="../stylesheet-jdiff.css" rel="stylesheet" type="text/css" />
    ++<noscript>
    ++<style type="text/css">
    ++body{overflow:auto;}
    ++#body-content{position:relative; top:0;}
    ++#doc-content{overflow:visible;border-left:3px solid #666;}
    ++#side-nav{padding:0;}
    ++#side-nav .toggle-list ul {display:block;}
    ++#resize-packages-nav{border-bottom:3px solid #666;}
    ++</style>
    ++</noscript>
    ++<style type="text/css">
    ++</style>
    ++</HEAD>
    ++<BODY>
    ++<!-- Start of nav bar -->
    ++<a name="top"></a>
    ++<div id="header" style="margin-bottom:0;padding-bottom:0;">
    ++<div id="headerLeft">
    ++<a href="../../../../index.html" tabindex="-1" target="_top"><img src="../../../../assets/images/bg_logo.png" alt="Android Developers" /></a>
    ++</div>
    ++  <div id="headerRight">
    ++  <div id="headerLinks">
    ++<!-- <img src="/assets/images/icon_world.jpg" alt="" /> -->
    ++<span class="text">
    ++<!-- &nbsp;<a href="#">English</a> | -->
    ++<nobr><a href="http://developer.android.com" target="_top">Android Developers</a> | <a href="http://www.android.com" target="_top">Android.com</a></nobr>
    ++</span>
    ++</div>
    ++  <div class="and-diff-id" style="margin-top:6px;margin-right:8px;">
    ++    <table class="diffspectable">
    ++      <tr>
    ++        <td colspan="2" class="diffspechead">API Diff Specification</td>
    ++      </tr>
    ++      <tr>
    ++        <td class="diffspec" style="padding-top:.25em">To Level:</td>
    ++        <td class="diffvaluenew" style="padding-top:.25em">24.2.0</td>
    ++      </tr>
    ++      <tr>
    ++        <td class="diffspec">From Level:</td>
    ++        <td class="diffvalueold">24.1.0</td>
    ++      </tr>
    ++      <tr>
    ++        <td class="diffspec">Generated</td>
    ++        <td class="diffvalue">2016.08.16 14:03</td>
    ++      </tr>
    ++    </table>
    ++    </div><!-- End and-diff-id -->
    ++  <div class="and-diff-id" style="margin-right:8px;">
    ++    <table class="diffspectable">
    ++      <tr>
    ++        <td class="diffspec" colspan="2"><a href="jdiff_statistics.html">Statistics</a>
    ++      </tr>
    ++    </table>
    ++  </div> <!-- End and-diff-id -->
    ++  </div> <!-- End headerRight -->
    ++  </div> <!-- End header -->
    ++<div id="body-content" xstyle="padding:12px;padding-right:18px;">
    ++<div id="doc-content" style="position:relative;">
    ++<div id="mainBodyFluid">
    ++<H2>
    ++Class android.support.v4.view.accessibility.<A HREF="../../../../reference/android/support/v4/view/accessibility/AccessibilityNodeInfoCompat.CollectionItemInfoCompat.html" target="_top"><font size="+2"><code>AccessibilityNodeInfoCompat.CollectionItemInfoCompat</code></font></A>
    ++</H2>
    ++<a NAME="constructors"></a>
    ++<a NAME="methods"></a>
    ++<p>
    ++<a NAME="Added"></a>
    ++<TABLE summary="Added Methods" WIDTH="100%">
    ++<TR>
    ++  <TH VALIGN="TOP" COLSPAN=2>Added Methods</FONT></TD>
    ++</TH>
    ++<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    ++  <TD VALIGN="TOP" WIDTH="25%">
    ++  <A NAME="android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.CollectionItemInfoCompat.obtain_added(int, int, int, int, boolean)"></A>
    ++  <nobr><code>CollectionItemInfoCompat</code>&nbsp;<A HREF="../../../../reference/android/support/v4/view/accessibility/AccessibilityNodeInfoCompat.CollectionItemInfoCompat.html#obtain(int, int, int, int, boolean)" target="_top"><code>obtain</code></A>(<code>int,</nobr> int<nobr>,</nobr> int<nobr>,</nobr> int<nobr>,</nobr> boolean<nobr><nobr></code>)</nobr>
    ++  </TD>
    ++  <TD>&nbsp;</TD>
    ++</TR>
    ++</TABLE>
    ++&nbsp;
    ++<a NAME="fields"></a>
    ++      </div>	
    ++      <div id="footer">
    ++        <div id="copyright">
    ++        Except as noted, this content is licensed under 
    ++        <a href="http://creativecommons.org/licenses/by/2.5/"> Creative Commons Attribution 2.5</a>.
    ++        For details and restrictions, see the <a href="/license.html">Content License</a>.
    ++        </div>
    ++      <div id="footerlinks">
    ++      <p>
    ++        <a href="http://www.android.com/terms.html">Site Terms of Service</a> -
    ++        <a href="http://www.android.com/privacy.html">Privacy Policy</a> -
    ++        <a href="http://www.android.com/branding.html">Brand Guidelines</a>
    ++      </p>
    ++    </div>
    ++    </div> <!-- end footer -->
    ++    </div><!-- end doc-content -->
    ++    </div> <!-- end body-content --> 
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    ++</script>
    ++<script type="text/javascript">
    ++  try {
    ++    var pageTracker = _gat._getTracker("UA-5831155-1");
    ++    pageTracker._setAllowAnchor(true);
    ++    pageTracker._initData();
    ++    pageTracker._trackPageview();
    ++  } catch(e) {}
    ++</script>
    ++</BODY>
    ++</HTML>
    +diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.RangeInfoCompat.html b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.RangeInfoCompat.html
    +new file mode 100644
    +index 0000000..41abf7e
    +--- /dev/null
    ++++ b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.RangeInfoCompat.html
    +@@ -0,0 +1,122 @@
    ++<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
    ++<HTML style="overflow:auto;">
    ++<HEAD>
    ++<meta name="generator" content="JDiff v1.1.0">
    ++<!-- Generated by the JDiff Javadoc doclet -->
    ++<!-- (http://www.jdiff.org) -->
    ++<meta name="description" content="JDiff is a Javadoc doclet which generates an HTML report of all the packages, classes, constructors, methods, and fields which have been removed, added or changed in any way, including their documentation, when two APIs are compared.">
    ++<meta name="keywords" content="diff, jdiff, javadiff, java diff, java difference, API difference, difference between two APIs, API diff, Javadoc, doclet">
    ++<TITLE>
    ++android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.RangeInfoCompat
    ++</TITLE>
    ++<link href="../../../../assets/android-developer-docs.css" rel="stylesheet" type="text/css" />
    ++<link href="../stylesheet-jdiff.css" rel="stylesheet" type="text/css" />
    ++<noscript>
    ++<style type="text/css">
    ++body{overflow:auto;}
    ++#body-content{position:relative; top:0;}
    ++#doc-content{overflow:visible;border-left:3px solid #666;}
    ++#side-nav{padding:0;}
    ++#side-nav .toggle-list ul {display:block;}
    ++#resize-packages-nav{border-bottom:3px solid #666;}
    ++</style>
    ++</noscript>
    ++<style type="text/css">
    ++</style>
    ++</HEAD>
    ++<BODY>
    ++<!-- Start of nav bar -->
    ++<a name="top"></a>
    ++<div id="header" style="margin-bottom:0;padding-bottom:0;">
    ++<div id="headerLeft">
    ++<a href="../../../../index.html" tabindex="-1" target="_top"><img src="../../../../assets/images/bg_logo.png" alt="Android Developers" /></a>
    ++</div>
    ++  <div id="headerRight">
    ++  <div id="headerLinks">
    ++<!-- <img src="/assets/images/icon_world.jpg" alt="" /> -->
    ++<span class="text">
    ++<!-- &nbsp;<a href="#">English</a> | -->
    ++<nobr><a href="http://developer.android.com" target="_top">Android Developers</a> | <a href="http://www.android.com" target="_top">Android.com</a></nobr>
    ++</span>
    ++</div>
    ++  <div class="and-diff-id" style="margin-top:6px;margin-right:8px;">
    ++    <table class="diffspectable">
    ++      <tr>
    ++        <td colspan="2" class="diffspechead">API Diff Specification</td>
    ++      </tr>
    ++      <tr>
    ++        <td class="diffspec" style="padding-top:.25em">To Level:</td>
    ++        <td class="diffvaluenew" style="padding-top:.25em">24.2.0</td>
    ++      </tr>
    ++      <tr>
    ++        <td class="diffspec">From Level:</td>
    ++        <td class="diffvalueold">24.1.0</td>
    ++      </tr>
    ++      <tr>
    ++        <td class="diffspec">Generated</td>
    ++        <td class="diffvalue">2016.08.16 14:03</td>
    ++      </tr>
    ++    </table>
    ++    </div><!-- End and-diff-id -->
    ++  <div class="and-diff-id" style="margin-right:8px;">
    ++    <table class="diffspectable">
    ++      <tr>
    ++        <td class="diffspec" colspan="2"><a href="jdiff_statistics.html">Statistics</a>
    ++      </tr>
    ++    </table>
    ++  </div> <!-- End and-diff-id -->
    ++  </div> <!-- End headerRight -->
    ++  </div> <!-- End header -->
    ++<div id="body-content" xstyle="padding:12px;padding-right:18px;">
    ++<div id="doc-content" style="position:relative;">
    ++<div id="mainBodyFluid">
    ++<H2>
    ++Class android.support.v4.view.accessibility.<A HREF="../../../../reference/android/support/v4/view/accessibility/AccessibilityNodeInfoCompat.RangeInfoCompat.html" target="_top"><font size="+2"><code>AccessibilityNodeInfoCompat.RangeInfoCompat</code></font></A>
    ++</H2>
    ++<a NAME="constructors"></a>
    ++<a NAME="methods"></a>
    ++<p>
    ++<a NAME="Added"></a>
    ++<TABLE summary="Added Methods" WIDTH="100%">
    ++<TR>
    ++  <TH VALIGN="TOP" COLSPAN=2>Added Methods</FONT></TD>
    ++</TH>
    ++<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    ++  <TD VALIGN="TOP" WIDTH="25%">
    ++  <A NAME="android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.RangeInfoCompat.obtain_added(int, float, float, float)"></A>
    ++  <nobr><code>RangeInfoCompat</code>&nbsp;<A HREF="../../../../reference/android/support/v4/view/accessibility/AccessibilityNodeInfoCompat.RangeInfoCompat.html#obtain(int, float, float, float)" target="_top"><code>obtain</code></A>(<code>int,</nobr> float<nobr>,</nobr> float<nobr>,</nobr> float<nobr><nobr></code>)</nobr>
    ++  </TD>
    ++  <TD>&nbsp;</TD>
    ++</TR>
    ++</TABLE>
    ++&nbsp;
    ++<a NAME="fields"></a>
    ++      </div>	
    ++      <div id="footer">
    ++        <div id="copyright">
    ++        Except as noted, this content is licensed under 
    ++        <a href="http://creativecommons.org/licenses/by/2.5/"> Creative Commons Attribution 2.5</a>.
    ++        For details and restrictions, see the <a href="/license.html">Content License</a>.
    ++        </div>
    ++      <div id="footerlinks">
    ++      <p>
    ++        <a href="http://www.android.com/terms.html">Site Terms of Service</a> -
    ++        <a href="http://www.android.com/privacy.html">Privacy Policy</a> -
    ++        <a href="http://www.android.com/branding.html">Brand Guidelines</a>
    ++      </p>
    ++    </div>
    ++    </div> <!-- end footer -->
    ++    </div><!-- end doc-content -->
    ++    </div> <!-- end body-content --> 
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    ++</script>
    ++<script type="text/javascript">
    ++  try {
    ++    var pageTracker = _gat._getTracker("UA-5831155-1");
    ++    pageTracker._setAllowAnchor(true);
    ++    pageTracker._initData();
    ++    pageTracker._trackPageview();
    ++  } catch(e) {}
    ++</script>
    ++</BODY>
    ++</HTML>
    +diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.html b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.html
    +new file mode 100644
    +index 0000000..005616a
    +--- /dev/null
    ++++ b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.html
    +@@ -0,0 +1,158 @@
    ++<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
    ++<HTML style="overflow:auto;">
    ++<HEAD>
    ++<meta name="generator" content="JDiff v1.1.0">
    ++<!-- Generated by the JDiff Javadoc doclet -->
    ++<!-- (http://www.jdiff.org) -->
    ++<meta name="description" content="JDiff is a Javadoc doclet which generates an HTML report of all the packages, classes, constructors, methods, and fields which have been removed, added or changed in any way, including their documentation, when two APIs are compared.">
    ++<meta name="keywords" content="diff, jdiff, javadiff, java diff, java difference, API difference, difference between two APIs, API diff, Javadoc, doclet">
    ++<TITLE>
    ++android.support.v4.view.accessibility.AccessibilityNodeInfoCompat
    ++</TITLE>
    ++<link href="../../../../assets/android-developer-docs.css" rel="stylesheet" type="text/css" />
    ++<link href="../stylesheet-jdiff.css" rel="stylesheet" type="text/css" />
    ++<noscript>
    ++<style type="text/css">
    ++body{overflow:auto;}
    ++#body-content{position:relative; top:0;}
    ++#doc-content{overflow:visible;border-left:3px solid #666;}
    ++#side-nav{padding:0;}
    ++#side-nav .toggle-list ul {display:block;}
    ++#resize-packages-nav{border-bottom:3px solid #666;}
    ++</style>
    ++</noscript>
    ++<style type="text/css">
    ++</style>
    ++</HEAD>
    ++<BODY>
    ++<!-- Start of nav bar -->
    ++<a name="top"></a>
    ++<div id="header" style="margin-bottom:0;padding-bottom:0;">
    ++<div id="headerLeft">
    ++<a href="../../../../index.html" tabindex="-1" target="_top"><img src="../../../../assets/images/bg_logo.png" alt="Android Developers" /></a>
    ++</div>
    ++  <div id="headerRight">
    ++  <div id="headerLinks">
    ++<!-- <img src="/assets/images/icon_world.jpg" alt="" /> -->
    ++<span class="text">
    ++<!-- &nbsp;<a href="#">English</a> | -->
    ++<nobr><a href="http://developer.android.com" target="_top">Android Developers</a> | <a href="http://www.android.com" target="_top">Android.com</a></nobr>
    ++</span>
    ++</div>
    ++  <div class="and-diff-id" style="margin-top:6px;margin-right:8px;">
    ++    <table class="diffspectable">
    ++      <tr>
    ++        <td colspan="2" class="diffspechead">API Diff Specification</td>
    ++      </tr>
    ++      <tr>
    ++        <td class="diffspec" style="padding-top:.25em">To Level:</td>
    ++        <td class="diffvaluenew" style="padding-top:.25em">24.2.0</td>
    ++      </tr>
    ++      <tr>
    ++        <td class="diffspec">From Level:</td>
    ++        <td class="diffvalueold">24.1.0</td>
    ++      </tr>
    ++      <tr>
    ++        <td class="diffspec">Generated</td>
    ++        <td class="diffvalue">2016.08.16 14:03</td>
    ++      </tr>
    ++    </table>
    ++    </div><!-- End and-diff-id -->
    ++  <div class="and-diff-id" style="margin-right:8px;">
    ++    <table class="diffspectable">
    ++      <tr>
    ++        <td class="diffspec" colspan="2"><a href="jdiff_statistics.html">Statistics</a>
    ++      </tr>
    ++    </table>
    ++  </div> <!-- End and-diff-id -->
    ++  </div> <!-- End headerRight -->
    ++  </div> <!-- End header -->
    ++<div id="body-content" xstyle="padding:12px;padding-right:18px;">
    ++<div id="doc-content" style="position:relative;">
    ++<div id="mainBodyFluid">
    ++<H2>
    ++Class android.support.v4.view.accessibility.<A HREF="../../../../reference/android/support/v4/view/accessibility/AccessibilityNodeInfoCompat.html" target="_top"><font size="+2"><code>AccessibilityNodeInfoCompat</code></font></A>
    ++</H2>
    ++<a NAME="constructors"></a>
    ++<a NAME="methods"></a>
    ++<p>
    ++<a NAME="Added"></a>
    ++<TABLE summary="Added Methods" WIDTH="100%">
    ++<TR>
    ++  <TH VALIGN="TOP" COLSPAN=2>Added Methods</FONT></TD>
    ++</TH>
    ++<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    ++  <TD VALIGN="TOP" WIDTH="25%">
    ++  <A NAME="android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.isContextClickable_added()"></A>
    ++  <nobr><code>boolean</code>&nbsp;<A HREF="../../../../reference/android/support/v4/view/accessibility/AccessibilityNodeInfoCompat.html#isContextClickable()" target="_top"><code>isContextClickable</code></A>()</nobr>
    ++  </TD>
    ++  <TD>&nbsp;</TD>
    ++</TR>
    ++<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    ++  <TD VALIGN="TOP" WIDTH="25%">
    ++  <A NAME="android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.setContextClickable_added(boolean)"></A>
    ++  <nobr><code>void</code>&nbsp;<A HREF="../../../../reference/android/support/v4/view/accessibility/AccessibilityNodeInfoCompat.html#setContextClickable(boolean)" target="_top"><code>setContextClickable</code></A>(<code>boolean</code>)</nobr>
    ++  </TD>
    ++  <TD>&nbsp;</TD>
    ++</TR>
    ++</TABLE>
    ++&nbsp;
    ++<a NAME="fields"></a>
    ++<p>
    ++<a NAME="Added"></a>
    ++<TABLE summary="Added Fields" WIDTH="100%">
    ++<TR>
    ++  <TH VALIGN="TOP" COLSPAN=2>Added Fields</FONT></TD>
    ++</TH>
    ++<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    ++  <TD VALIGN="TOP" WIDTH="25%">
    ++  <A NAME="android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.ACTION_ARGUMENT_COLUMN_INT"></A>
    ++  <nobr><code>String</code>&nbsp;<A HREF="../../../../reference/android/support/v4/view/accessibility/AccessibilityNodeInfoCompat.html#ACTION_ARGUMENT_COLUMN_INT" target="_top"><code>ACTION_ARGUMENT_COLUMN_INT</code></A></nobr>
    ++  </TD>
    ++  <TD>&nbsp;</TD>
    ++</TR>
    ++<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    ++  <TD VALIGN="TOP" WIDTH="25%">
    ++  <A NAME="android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.ACTION_ARGUMENT_PROGRESS_VALUE"></A>
    ++  <nobr><code>String</code>&nbsp;<A HREF="../../../../reference/android/support/v4/view/accessibility/AccessibilityNodeInfoCompat.html#ACTION_ARGUMENT_PROGRESS_VALUE" target="_top"><code>ACTION_ARGUMENT_PROGRESS_VALUE</code></A></nobr>
    ++  </TD>
    ++  <TD>&nbsp;</TD>
    ++</TR>
    ++<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    ++  <TD VALIGN="TOP" WIDTH="25%">
    ++  <A NAME="android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.ACTION_ARGUMENT_ROW_INT"></A>
    ++  <nobr><code>String</code>&nbsp;<A HREF="../../../../reference/android/support/v4/view/accessibility/AccessibilityNodeInfoCompat.html#ACTION_ARGUMENT_ROW_INT" target="_top"><code>ACTION_ARGUMENT_ROW_INT</code></A></nobr>
    ++  </TD>
    ++  <TD>&nbsp;</TD>
    ++</TR>
    ++</TABLE>
    ++&nbsp;
    ++      </div>	
    ++      <div id="footer">
    ++        <div id="copyright">
    ++        Except as noted, this content is licensed under 
    ++        <a href="http://creativecommons.org/licenses/by/2.5/"> Creative Commons Attribution 2.5</a>.
    ++        For details and restrictions, see the <a href="/license.html">Content License</a>.
    ++        </div>
    ++      <div id="footerlinks">
    ++      <p>
    ++        <a href="http://www.android.com/terms.html">Site Terms of Service</a> -
    ++        <a href="http://www.android.com/privacy.html">Privacy Policy</a> -
    ++        <a href="http://www.android.com/branding.html">Brand Guidelines</a>
    ++      </p>
    ++    </div>
    ++    </div> <!-- end footer -->
    ++    </div><!-- end doc-content -->
    ++    </div> <!-- end body-content --> 
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    ++</script>
    ++<script type="text/javascript">
    ++  try {
    ++    var pageTracker = _gat._getTracker("UA-5831155-1");
    ++    pageTracker._setAllowAnchor(true);
    ++    pageTracker._initData();
    ++    pageTracker._trackPageview();
    ++  } catch(e) {}
    ++</script>
    ++</BODY>
    ++</HTML>
    +diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.view.accessibility.AccessibilityNodeProviderCompat.html b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.view.accessibility.AccessibilityNodeProviderCompat.html
    +new file mode 100644
    +index 0000000..bd6b7f8
    +--- /dev/null
    ++++ b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.view.accessibility.AccessibilityNodeProviderCompat.html
    +@@ -0,0 +1,122 @@
    ++<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
    ++<HTML style="overflow:auto;">
    ++<HEAD>
    ++<meta name="generator" content="JDiff v1.1.0">
    ++<!-- Generated by the JDiff Javadoc doclet -->
    ++<!-- (http://www.jdiff.org) -->
    ++<meta name="description" content="JDiff is a Javadoc doclet which generates an HTML report of all the packages, classes, constructors, methods, and fields which have been removed, added or changed in any way, including their documentation, when two APIs are compared.">
    ++<meta name="keywords" content="diff, jdiff, javadiff, java diff, java difference, API difference, difference between two APIs, API diff, Javadoc, doclet">
    ++<TITLE>
    ++android.support.v4.view.accessibility.AccessibilityNodeProviderCompat
    ++</TITLE>
    ++<link href="../../../../assets/android-developer-docs.css" rel="stylesheet" type="text/css" />
    ++<link href="../stylesheet-jdiff.css" rel="stylesheet" type="text/css" />
    ++<noscript>
    ++<style type="text/css">
    ++body{overflow:auto;}
    ++#body-content{position:relative; top:0;}
    ++#doc-content{overflow:visible;border-left:3px solid #666;}
    ++#side-nav{padding:0;}
    ++#side-nav .toggle-list ul {display:block;}
    ++#resize-packages-nav{border-bottom:3px solid #666;}
    ++</style>
    ++</noscript>
    ++<style type="text/css">
    ++</style>
    ++</HEAD>
    ++<BODY>
    ++<!-- Start of nav bar -->
    ++<a name="top"></a>
    ++<div id="header" style="margin-bottom:0;padding-bottom:0;">
    ++<div id="headerLeft">
    ++<a href="../../../../index.html" tabindex="-1" target="_top"><img src="../../../../assets/images/bg_logo.png" alt="Android Developers" /></a>
    ++</div>
    ++  <div id="headerRight">
    ++  <div id="headerLinks">
    ++<!-- <img src="/assets/images/icon_world.jpg" alt="" /> -->
    ++<span class="text">
    ++<!-- &nbsp;<a href="#">English</a> | -->
    ++<nobr><a href="http://developer.android.com" target="_top">Android Developers</a> | <a href="http://www.android.com" target="_top">Android.com</a></nobr>
    ++</span>
    ++</div>
    ++  <div class="and-diff-id" style="margin-top:6px;margin-right:8px;">
    ++    <table class="diffspectable">
    ++      <tr>
    ++        <td colspan="2" class="diffspechead">API Diff Specification</td>
    ++      </tr>
    ++      <tr>
    ++        <td class="diffspec" style="padding-top:.25em">To Level:</td>
    ++        <td class="diffvaluenew" style="padding-top:.25em">24.2.0</td>
    ++      </tr>
    ++      <tr>
    ++        <td class="diffspec">From Level:</td>
    ++        <td class="diffvalueold">24.1.0</td>
    ++      </tr>
    ++      <tr>
    ++        <td class="diffspec">Generated</td>
    ++        <td class="diffvalue">2016.08.16 14:03</td>
    ++      </tr>
    ++    </table>
    ++    </div><!-- End and-diff-id -->
    ++  <div class="and-diff-id" style="margin-right:8px;">
    ++    <table class="diffspectable">
    ++      <tr>
    ++        <td class="diffspec" colspan="2"><a href="jdiff_statistics.html">Statistics</a>
    ++      </tr>
    ++    </table>
    ++  </div> <!-- End and-diff-id -->
    ++  </div> <!-- End headerRight -->
    ++  </div> <!-- End header -->
    ++<div id="body-content" xstyle="padding:12px;padding-right:18px;">
    ++<div id="doc-content" style="position:relative;">
    ++<div id="mainBodyFluid">
    ++<H2>
    ++Class android.support.v4.view.accessibility.<A HREF="../../../../reference/android/support/v4/view/accessibility/AccessibilityNodeProviderCompat.html" target="_top"><font size="+2"><code>AccessibilityNodeProviderCompat</code></font></A>
    ++</H2>
    ++<a NAME="constructors"></a>
    ++<a NAME="methods"></a>
    ++<a NAME="fields"></a>
    ++<p>
    ++<a NAME="Added"></a>
    ++<TABLE summary="Added Fields" WIDTH="100%">
    ++<TR>
    ++  <TH VALIGN="TOP" COLSPAN=2>Added Fields</FONT></TD>
    ++</TH>
    ++<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    ++  <TD VALIGN="TOP" WIDTH="25%">
    ++  <A NAME="android.support.v4.view.accessibility.AccessibilityNodeProviderCompat.HOST_VIEW_ID"></A>
    ++  <nobr><code>int</code>&nbsp;<A HREF="../../../../reference/android/support/v4/view/accessibility/AccessibilityNodeProviderCompat.html#HOST_VIEW_ID" target="_top"><code>HOST_VIEW_ID</code></A></nobr>
    ++  </TD>
    ++  <TD>&nbsp;</TD>
    ++</TR>
    ++</TABLE>
    ++&nbsp;
    ++      </div>	
    ++      <div id="footer">
    ++        <div id="copyright">
    ++        Except as noted, this content is licensed under 
    ++        <a href="http://creativecommons.org/licenses/by/2.5/"> Creative Commons Attribution 2.5</a>.
    ++        For details and restrictions, see the <a href="/license.html">Content License</a>.
    ++        </div>
    ++      <div id="footerlinks">
    ++      <p>
    ++        <a href="http://www.android.com/terms.html">Site Terms of Service</a> -
    ++        <a href="http://www.android.com/privacy.html">Privacy Policy</a> -
    ++        <a href="http://www.android.com/branding.html">Brand Guidelines</a>
    ++      </p>
    ++    </div>
    ++    </div> <!-- end footer -->
    ++    </div><!-- end doc-content -->
    ++    </div> <!-- end body-content --> 
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    ++</script>
    ++<script type="text/javascript">
    ++  try {
    ++    var pageTracker = _gat._getTracker("UA-5831155-1");
    ++    pageTracker._setAllowAnchor(true);
    ++    pageTracker._initData();
    ++    pageTracker._trackPageview();
    ++  } catch(e) {}
    ++</script>
    ++</BODY>
    ++</HTML>
    +diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.view.accessibility.AccessibilityWindowInfoCompat.html b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.view.accessibility.AccessibilityWindowInfoCompat.html
    +new file mode 100644
    +index 0000000..40f3ca2
    +--- /dev/null
    ++++ b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.view.accessibility.AccessibilityWindowInfoCompat.html
    +@@ -0,0 +1,122 @@
    ++<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
    ++<HTML style="overflow:auto;">
    ++<HEAD>
    ++<meta name="generator" content="JDiff v1.1.0">
    ++<!-- Generated by the JDiff Javadoc doclet -->
    ++<!-- (http://www.jdiff.org) -->
    ++<meta name="description" content="JDiff is a Javadoc doclet which generates an HTML report of all the packages, classes, constructors, methods, and fields which have been removed, added or changed in any way, including their documentation, when two APIs are compared.">
    ++<meta name="keywords" content="diff, jdiff, javadiff, java diff, java difference, API difference, difference between two APIs, API diff, Javadoc, doclet">
    ++<TITLE>
    ++android.support.v4.view.accessibility.AccessibilityWindowInfoCompat
    ++</TITLE>
    ++<link href="../../../../assets/android-developer-docs.css" rel="stylesheet" type="text/css" />
    ++<link href="../stylesheet-jdiff.css" rel="stylesheet" type="text/css" />
    ++<noscript>
    ++<style type="text/css">
    ++body{overflow:auto;}
    ++#body-content{position:relative; top:0;}
    ++#doc-content{overflow:visible;border-left:3px solid #666;}
    ++#side-nav{padding:0;}
    ++#side-nav .toggle-list ul {display:block;}
    ++#resize-packages-nav{border-bottom:3px solid #666;}
    ++</style>
    ++</noscript>
    ++<style type="text/css">
    ++</style>
    ++</HEAD>
    ++<BODY>
    ++<!-- Start of nav bar -->
    ++<a name="top"></a>
    ++<div id="header" style="margin-bottom:0;padding-bottom:0;">
    ++<div id="headerLeft">
    ++<a href="../../../../index.html" tabindex="-1" target="_top"><img src="../../../../assets/images/bg_logo.png" alt="Android Developers" /></a>
    ++</div>
    ++  <div id="headerRight">
    ++  <div id="headerLinks">
    ++<!-- <img src="/assets/images/icon_world.jpg" alt="" /> -->
    ++<span class="text">
    ++<!-- &nbsp;<a href="#">English</a> | -->
    ++<nobr><a href="http://developer.android.com" target="_top">Android Developers</a> | <a href="http://www.android.com" target="_top">Android.com</a></nobr>
    ++</span>
    ++</div>
    ++  <div class="and-diff-id" style="margin-top:6px;margin-right:8px;">
    ++    <table class="diffspectable">
    ++      <tr>
    ++        <td colspan="2" class="diffspechead">API Diff Specification</td>
    ++      </tr>
    ++      <tr>
    ++        <td class="diffspec" style="padding-top:.25em">To Level:</td>
    ++        <td class="diffvaluenew" style="padding-top:.25em">24.2.0</td>
    ++      </tr>
    ++      <tr>
    ++        <td class="diffspec">From Level:</td>
    ++        <td class="diffvalueold">24.1.0</td>
    ++      </tr>
    ++      <tr>
    ++        <td class="diffspec">Generated</td>
    ++        <td class="diffvalue">2016.08.16 14:03</td>
    ++      </tr>
    ++    </table>
    ++    </div><!-- End and-diff-id -->
    ++  <div class="and-diff-id" style="margin-right:8px;">
    ++    <table class="diffspectable">
    ++      <tr>
    ++        <td class="diffspec" colspan="2"><a href="jdiff_statistics.html">Statistics</a>
    ++      </tr>
    ++    </table>
    ++  </div> <!-- End and-diff-id -->
    ++  </div> <!-- End headerRight -->
    ++  </div> <!-- End header -->
    ++<div id="body-content" xstyle="padding:12px;padding-right:18px;">
    ++<div id="doc-content" style="position:relative;">
    ++<div id="mainBodyFluid">
    ++<H2>
    ++Class android.support.v4.view.accessibility.<A HREF="../../../../reference/android/support/v4/view/accessibility/AccessibilityWindowInfoCompat.html" target="_top"><font size="+2"><code>AccessibilityWindowInfoCompat</code></font></A>
    ++</H2>
    ++<a NAME="constructors"></a>
    ++<a NAME="methods"></a>
    ++<a NAME="fields"></a>
    ++<p>
    ++<a NAME="Added"></a>
    ++<TABLE summary="Added Fields" WIDTH="100%">
    ++<TR>
    ++  <TH VALIGN="TOP" COLSPAN=2>Added Fields</FONT></TD>
    ++</TH>
    ++<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    ++  <TD VALIGN="TOP" WIDTH="25%">
    ++  <A NAME="android.support.v4.view.accessibility.AccessibilityWindowInfoCompat.TYPE_SPLIT_SCREEN_DIVIDER"></A>
    ++  <nobr><code>int</code>&nbsp;<A HREF="../../../../reference/android/support/v4/view/accessibility/AccessibilityWindowInfoCompat.html#TYPE_SPLIT_SCREEN_DIVIDER" target="_top"><code>TYPE_SPLIT_SCREEN_DIVIDER</code></A></nobr>
    ++  </TD>
    ++  <TD>&nbsp;</TD>
    ++</TR>
    ++</TABLE>
    ++&nbsp;
    ++      </div>	
    ++      <div id="footer">
    ++        <div id="copyright">
    ++        Except as noted, this content is licensed under 
    ++        <a href="http://creativecommons.org/licenses/by/2.5/"> Creative Commons Attribution 2.5</a>.
    ++        For details and restrictions, see the <a href="/license.html">Content License</a>.
    ++        </div>
    ++      <div id="footerlinks">
    ++      <p>
    ++        <a href="http://www.android.com/terms.html">Site Terms of Service</a> -
    ++        <a href="http://www.android.com/privacy.html">Privacy Policy</a> -
    ++        <a href="http://www.android.com/branding.html">Brand Guidelines</a>
    ++      </p>
    ++    </div>
    ++    </div> <!-- end footer -->
    ++    </div><!-- end doc-content -->
    ++    </div> <!-- end body-content --> 
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    ++</script>
    ++<script type="text/javascript">
    ++  try {
    ++    var pageTracker = _gat._getTracker("UA-5831155-1");
    ++    pageTracker._setAllowAnchor(true);
    ++    pageTracker._initData();
    ++    pageTracker._trackPageview();
    ++  } catch(e) {}
    ++</script>
    ++</BODY>
    ++</HTML>
    +diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.widget.SearchViewCompat.OnCloseListenerCompat.html b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.widget.SearchViewCompat.OnCloseListenerCompat.html
    +new file mode 100644
    +index 0000000..3d9f2ea
    +--- /dev/null
    ++++ b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.widget.SearchViewCompat.OnCloseListenerCompat.html
    +@@ -0,0 +1,109 @@
    ++<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
    ++<HTML style="overflow:auto;">
    ++<HEAD>
    ++<meta name="generator" content="JDiff v1.1.0">
    ++<!-- Generated by the JDiff Javadoc doclet -->
    ++<!-- (http://www.jdiff.org) -->
    ++<meta name="description" content="JDiff is a Javadoc doclet which generates an HTML report of all the packages, classes, constructors, methods, and fields which have been removed, added or changed in any way, including their documentation, when two APIs are compared.">
    ++<meta name="keywords" content="diff, jdiff, javadiff, java diff, java difference, API difference, difference between two APIs, API diff, Javadoc, doclet">
    ++<TITLE>
    ++android.support.v4.widget.SearchViewCompat.OnCloseListenerCompat
    ++</TITLE>
    ++<link href="../../../../assets/android-developer-docs.css" rel="stylesheet" type="text/css" />
    ++<link href="../stylesheet-jdiff.css" rel="stylesheet" type="text/css" />
    ++<noscript>
    ++<style type="text/css">
    ++body{overflow:auto;}
    ++#body-content{position:relative; top:0;}
    ++#doc-content{overflow:visible;border-left:3px solid #666;}
    ++#side-nav{padding:0;}
    ++#side-nav .toggle-list ul {display:block;}
    ++#resize-packages-nav{border-bottom:3px solid #666;}
    ++</style>
    ++</noscript>
    ++<style type="text/css">
    ++</style>
    ++</HEAD>
    ++<BODY>
    ++<!-- Start of nav bar -->
    ++<a name="top"></a>
    ++<div id="header" style="margin-bottom:0;padding-bottom:0;">
    ++<div id="headerLeft">
    ++<a href="../../../../index.html" tabindex="-1" target="_top"><img src="../../../../assets/images/bg_logo.png" alt="Android Developers" /></a>
    ++</div>
    ++  <div id="headerRight">
    ++  <div id="headerLinks">
    ++<!-- <img src="/assets/images/icon_world.jpg" alt="" /> -->
    ++<span class="text">
    ++<!-- &nbsp;<a href="#">English</a> | -->
    ++<nobr><a href="http://developer.android.com" target="_top">Android Developers</a> | <a href="http://www.android.com" target="_top">Android.com</a></nobr>
    ++</span>
    ++</div>
    ++  <div class="and-diff-id" style="margin-top:6px;margin-right:8px;">
    ++    <table class="diffspectable">
    ++      <tr>
    ++        <td colspan="2" class="diffspechead">API Diff Specification</td>
    ++      </tr>
    ++      <tr>
    ++        <td class="diffspec" style="padding-top:.25em">To Level:</td>
    ++        <td class="diffvaluenew" style="padding-top:.25em">24.2.0</td>
    ++      </tr>
    ++      <tr>
    ++        <td class="diffspec">From Level:</td>
    ++        <td class="diffvalueold">24.1.0</td>
    ++      </tr>
    ++      <tr>
    ++        <td class="diffspec">Generated</td>
    ++        <td class="diffvalue">2016.08.16 14:03</td>
    ++      </tr>
    ++    </table>
    ++    </div><!-- End and-diff-id -->
    ++  <div class="and-diff-id" style="margin-right:8px;">
    ++    <table class="diffspectable">
    ++      <tr>
    ++        <td class="diffspec" colspan="2"><a href="jdiff_statistics.html">Statistics</a>
    ++      </tr>
    ++    </table>
    ++  </div> <!-- End and-diff-id -->
    ++  </div> <!-- End headerRight -->
    ++  </div> <!-- End header -->
    ++<div id="body-content" xstyle="padding:12px;padding-right:18px;">
    ++<div id="doc-content" style="position:relative;">
    ++<div id="mainBodyFluid">
    ++<H2>
    ++Class android.support.v4.widget.<A HREF="../../../../reference/android/support/v4/widget/SearchViewCompat.OnCloseListenerCompat.html" target="_top"><font size="+2"><code>SearchViewCompat.OnCloseListenerCompat</code></font></A>
    ++</H2>
    ++<p><font xsize="+1">Added interface <code>android.support.v4.widget.SearchViewCompat.OnCloseListener</code>.<br></font>
    ++<p><b>Now deprecated</b>.<br>
    ++<a NAME="constructors"></a>
    ++<a NAME="methods"></a>
    ++<a NAME="fields"></a>
    ++      </div>	
    ++      <div id="footer">
    ++        <div id="copyright">
    ++        Except as noted, this content is licensed under 
    ++        <a href="http://creativecommons.org/licenses/by/2.5/"> Creative Commons Attribution 2.5</a>.
    ++        For details and restrictions, see the <a href="/license.html">Content License</a>.
    ++        </div>
    ++      <div id="footerlinks">
    ++      <p>
    ++        <a href="http://www.android.com/terms.html">Site Terms of Service</a> -
    ++        <a href="http://www.android.com/privacy.html">Privacy Policy</a> -
    ++        <a href="http://www.android.com/branding.html">Brand Guidelines</a>
    ++      </p>
    ++    </div>
    ++    </div> <!-- end footer -->
    ++    </div><!-- end doc-content -->
    ++    </div> <!-- end body-content --> 
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    ++</script>
    ++<script type="text/javascript">
    ++  try {
    ++    var pageTracker = _gat._getTracker("UA-5831155-1");
    ++    pageTracker._setAllowAnchor(true);
    ++    pageTracker._initData();
    ++    pageTracker._trackPageview();
    ++  } catch(e) {}
    ++</script>
    ++</BODY>
    ++</HTML>
    +diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.widget.SearchViewCompat.OnQueryTextListenerCompat.html b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.widget.SearchViewCompat.OnQueryTextListenerCompat.html
    +new file mode 100644
    +index 0000000..df0f3e1
    +--- /dev/null
    ++++ b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.widget.SearchViewCompat.OnQueryTextListenerCompat.html
    +@@ -0,0 +1,109 @@
    ++<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
    ++<HTML style="overflow:auto;">
    ++<HEAD>
    ++<meta name="generator" content="JDiff v1.1.0">
    ++<!-- Generated by the JDiff Javadoc doclet -->
    ++<!-- (http://www.jdiff.org) -->
    ++<meta name="description" content="JDiff is a Javadoc doclet which generates an HTML report of all the packages, classes, constructors, methods, and fields which have been removed, added or changed in any way, including their documentation, when two APIs are compared.">
    ++<meta name="keywords" content="diff, jdiff, javadiff, java diff, java difference, API difference, difference between two APIs, API diff, Javadoc, doclet">
    ++<TITLE>
    ++android.support.v4.widget.SearchViewCompat.OnQueryTextListenerCompat
    ++</TITLE>
    ++<link href="../../../../assets/android-developer-docs.css" rel="stylesheet" type="text/css" />
    ++<link href="../stylesheet-jdiff.css" rel="stylesheet" type="text/css" />
    ++<noscript>
    ++<style type="text/css">
    ++body{overflow:auto;}
    ++#body-content{position:relative; top:0;}
    ++#doc-content{overflow:visible;border-left:3px solid #666;}
    ++#side-nav{padding:0;}
    ++#side-nav .toggle-list ul {display:block;}
    ++#resize-packages-nav{border-bottom:3px solid #666;}
    ++</style>
    ++</noscript>
    ++<style type="text/css">
    ++</style>
    ++</HEAD>
    ++<BODY>
    ++<!-- Start of nav bar -->
    ++<a name="top"></a>
    ++<div id="header" style="margin-bottom:0;padding-bottom:0;">
    ++<div id="headerLeft">
    ++<a href="../../../../index.html" tabindex="-1" target="_top"><img src="../../../../assets/images/bg_logo.png" alt="Android Developers" /></a>
    ++</div>
    ++  <div id="headerRight">
    ++  <div id="headerLinks">
    ++<!-- <img src="/assets/images/icon_world.jpg" alt="" /> -->
    ++<span class="text">
    ++<!-- &nbsp;<a href="#">English</a> | -->
    ++<nobr><a href="http://developer.android.com" target="_top">Android Developers</a> | <a href="http://www.android.com" target="_top">Android.com</a></nobr>
    ++</span>
    ++</div>
    ++  <div class="and-diff-id" style="margin-top:6px;margin-right:8px;">
    ++    <table class="diffspectable">
    ++      <tr>
    ++        <td colspan="2" class="diffspechead">API Diff Specification</td>
    ++      </tr>
    ++      <tr>
    ++        <td class="diffspec" style="padding-top:.25em">To Level:</td>
    ++        <td class="diffvaluenew" style="padding-top:.25em">24.2.0</td>
    ++      </tr>
    ++      <tr>
    ++        <td class="diffspec">From Level:</td>
    ++        <td class="diffvalueold">24.1.0</td>
    ++      </tr>
    ++      <tr>
    ++        <td class="diffspec">Generated</td>
    ++        <td class="diffvalue">2016.08.16 14:03</td>
    ++      </tr>
    ++    </table>
    ++    </div><!-- End and-diff-id -->
    ++  <div class="and-diff-id" style="margin-right:8px;">
    ++    <table class="diffspectable">
    ++      <tr>
    ++        <td class="diffspec" colspan="2"><a href="jdiff_statistics.html">Statistics</a>
    ++      </tr>
    ++    </table>
    ++  </div> <!-- End and-diff-id -->
    ++  </div> <!-- End headerRight -->
    ++  </div> <!-- End header -->
    ++<div id="body-content" xstyle="padding:12px;padding-right:18px;">
    ++<div id="doc-content" style="position:relative;">
    ++<div id="mainBodyFluid">
    ++<H2>
    ++Class android.support.v4.widget.<A HREF="../../../../reference/android/support/v4/widget/SearchViewCompat.OnQueryTextListenerCompat.html" target="_top"><font size="+2"><code>SearchViewCompat.OnQueryTextListenerCompat</code></font></A>
    ++</H2>
    ++<p><font xsize="+1">Added interface <code>android.support.v4.widget.SearchViewCompat.OnQueryTextListener</code>.<br></font>
    ++<p><b>Now deprecated</b>.<br>
    ++<a NAME="constructors"></a>
    ++<a NAME="methods"></a>
    ++<a NAME="fields"></a>
    ++      </div>	
    ++      <div id="footer">
    ++        <div id="copyright">
    ++        Except as noted, this content is licensed under 
    ++        <a href="http://creativecommons.org/licenses/by/2.5/"> Creative Commons Attribution 2.5</a>.
    ++        For details and restrictions, see the <a href="/license.html">Content License</a>.
    ++        </div>
    ++      <div id="footerlinks">
    ++      <p>
    ++        <a href="http://www.android.com/terms.html">Site Terms of Service</a> -
    ++        <a href="http://www.android.com/privacy.html">Privacy Policy</a> -
    ++        <a href="http://www.android.com/branding.html">Brand Guidelines</a>
    ++      </p>
    ++    </div>
    ++    </div> <!-- end footer -->
    ++    </div><!-- end doc-content -->
    ++    </div> <!-- end body-content --> 
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    ++</script>
    ++<script type="text/javascript">
    ++  try {
    ++    var pageTracker = _gat._getTracker("UA-5831155-1");
    ++    pageTracker._setAllowAnchor(true);
    ++    pageTracker._initData();
    ++    pageTracker._trackPageview();
    ++  } catch(e) {}
    ++</script>
    ++</BODY>
    ++</HTML>
    +diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.widget.SearchViewCompat.html b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.widget.SearchViewCompat.html
    +new file mode 100644
    +index 0000000..4af1e46
    +--- /dev/null
    ++++ b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.widget.SearchViewCompat.html
    +@@ -0,0 +1,135 @@
    ++<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
    ++<HTML style="overflow:auto;">
    ++<HEAD>
    ++<meta name="generator" content="JDiff v1.1.0">
    ++<!-- Generated by the JDiff Javadoc doclet -->
    ++<!-- (http://www.jdiff.org) -->
    ++<meta name="description" content="JDiff is a Javadoc doclet which generates an HTML report of all the packages, classes, constructors, methods, and fields which have been removed, added or changed in any way, including their documentation, when two APIs are compared.">
    ++<meta name="keywords" content="diff, jdiff, javadiff, java diff, java difference, API difference, difference between two APIs, API diff, Javadoc, doclet">
    ++<TITLE>
    ++android.support.v4.widget.SearchViewCompat
    ++</TITLE>
    ++<link href="../../../../assets/android-developer-docs.css" rel="stylesheet" type="text/css" />
    ++<link href="../stylesheet-jdiff.css" rel="stylesheet" type="text/css" />
    ++<noscript>
    ++<style type="text/css">
    ++body{overflow:auto;}
    ++#body-content{position:relative; top:0;}
    ++#doc-content{overflow:visible;border-left:3px solid #666;}
    ++#side-nav{padding:0;}
    ++#side-nav .toggle-list ul {display:block;}
    ++#resize-packages-nav{border-bottom:3px solid #666;}
    ++</style>
    ++</noscript>
    ++<style type="text/css">
    ++</style>
    ++</HEAD>
    ++<BODY>
    ++<!-- Start of nav bar -->
    ++<a name="top"></a>
    ++<div id="header" style="margin-bottom:0;padding-bottom:0;">
    ++<div id="headerLeft">
    ++<a href="../../../../index.html" tabindex="-1" target="_top"><img src="../../../../assets/images/bg_logo.png" alt="Android Developers" /></a>
    ++</div>
    ++  <div id="headerRight">
    ++  <div id="headerLinks">
    ++<!-- <img src="/assets/images/icon_world.jpg" alt="" /> -->
    ++<span class="text">
    ++<!-- &nbsp;<a href="#">English</a> | -->
    ++<nobr><a href="http://developer.android.com" target="_top">Android Developers</a> | <a href="http://www.android.com" target="_top">Android.com</a></nobr>
    ++</span>
    ++</div>
    ++  <div class="and-diff-id" style="margin-top:6px;margin-right:8px;">
    ++    <table class="diffspectable">
    ++      <tr>
    ++        <td colspan="2" class="diffspechead">API Diff Specification</td>
    ++      </tr>
    ++      <tr>
    ++        <td class="diffspec" style="padding-top:.25em">To Level:</td>
    ++        <td class="diffvaluenew" style="padding-top:.25em">24.2.0</td>
    ++      </tr>
    ++      <tr>
    ++        <td class="diffspec">From Level:</td>
    ++        <td class="diffvalueold">24.1.0</td>
    ++      </tr>
    ++      <tr>
    ++        <td class="diffspec">Generated</td>
    ++        <td class="diffvalue">2016.08.16 14:03</td>
    ++      </tr>
    ++    </table>
    ++    </div><!-- End and-diff-id -->
    ++  <div class="and-diff-id" style="margin-right:8px;">
    ++    <table class="diffspectable">
    ++      <tr>
    ++        <td class="diffspec" colspan="2"><a href="jdiff_statistics.html">Statistics</a>
    ++      </tr>
    ++    </table>
    ++  </div> <!-- End and-diff-id -->
    ++  </div> <!-- End headerRight -->
    ++  </div> <!-- End header -->
    ++<div id="body-content" xstyle="padding:12px;padding-right:18px;">
    ++<div id="doc-content" style="position:relative;">
    ++<div id="mainBodyFluid">
    ++<H2>
    ++Class android.support.v4.widget.<A HREF="../../../../reference/android/support/v4/widget/SearchViewCompat.html" target="_top"><font size="+2"><code>SearchViewCompat</code></font></A>
    ++</H2>
    ++<a NAME="constructors"></a>
    ++<a NAME="methods"></a>
    ++<p>
    ++<a NAME="Changed"></a>
    ++<TABLE summary="Changed Methods" WIDTH="100%">
    ++<TR>
    ++  <TH VALIGN="TOP" COLSPAN=3>Changed Methods</FONT></TD>
    ++</TH>
    ++<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    ++  <TD VALIGN="TOP" WIDTH="25%">
    ++  <A NAME="android.support.v4.widget.SearchViewCompat.setOnCloseListener_changed(android.view.View, android.support.v4.widget.SearchViewCompat.OnCloseListener)"></A>
    ++  <nobr><code>void</code>&nbsp;<A HREF="../../../../reference/android/support/v4/widget/SearchViewCompat.html#setOnCloseListener(android.view.View, android.support.v4.widget.SearchViewCompat.OnCloseListener)" target="_top"><code>setOnCloseListener</code></A>(<code>View,</nobr> OnCloseListener<nobr><nobr></code>)  </nobr>
    ++  </TD>
    ++  <TD VALIGN="TOP" WIDTH="30%">
    ++Change in signature from (<code>View, OnCloseListenerCompat</code>) to (<code>View, OnCloseListener</code>).<br>
    ++  </TD>
    ++  <TD>&nbsp;</TD>
    ++</TR>
    ++<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    ++  <TD VALIGN="TOP" WIDTH="25%">
    ++  <A NAME="android.support.v4.widget.SearchViewCompat.setOnQueryTextListener_changed(android.view.View, android.support.v4.widget.SearchViewCompat.OnQueryTextListener)"></A>
    ++  <nobr><code>void</code>&nbsp;<A HREF="../../../../reference/android/support/v4/widget/SearchViewCompat.html#setOnQueryTextListener(android.view.View, android.support.v4.widget.SearchViewCompat.OnQueryTextListener)" target="_top"><code>setOnQueryTextListener</code></A>(<code>View,</nobr> OnQueryTextListener<nobr><nobr></code>)  </nobr>
    ++  </TD>
    ++  <TD VALIGN="TOP" WIDTH="30%">
    ++Change in signature from (<code>View, OnQueryTextListenerCompat</code>) to (<code>View, OnQueryTextListener</code>).<br>
    ++  </TD>
    ++  <TD>&nbsp;</TD>
    ++</TR>
    ++</TABLE>
    ++&nbsp;
    ++<a NAME="fields"></a>
    ++      </div>	
    ++      <div id="footer">
    ++        <div id="copyright">
    ++        Except as noted, this content is licensed under 
    ++        <a href="http://creativecommons.org/licenses/by/2.5/"> Creative Commons Attribution 2.5</a>.
    ++        For details and restrictions, see the <a href="/license.html">Content License</a>.
    ++        </div>
    ++      <div id="footerlinks">
    ++      <p>
    ++        <a href="http://www.android.com/terms.html">Site Terms of Service</a> -
    ++        <a href="http://www.android.com/privacy.html">Privacy Policy</a> -
    ++        <a href="http://www.android.com/branding.html">Brand Guidelines</a>
    ++      </p>
    ++    </div>
    ++    </div> <!-- end footer -->
    ++    </div><!-- end doc-content -->
    ++    </div> <!-- end body-content --> 
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    ++</script>
    ++<script type="text/javascript">
    ++  try {
    ++    var pageTracker = _gat._getTracker("UA-5831155-1");
    ++    pageTracker._setAllowAnchor(true);
    ++    pageTracker._initData();
    ++    pageTracker._trackPageview();
    ++  } catch(e) {}
    ++</script>
    ++</BODY>
    ++</HTML>
    +diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.widget.SwipeRefreshLayout.html b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.widget.SwipeRefreshLayout.html
    +new file mode 100644
    +index 0000000..5848782
    +--- /dev/null
    ++++ b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.widget.SwipeRefreshLayout.html
    +@@ -0,0 +1,122 @@
    ++<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
    ++<HTML style="overflow:auto;">
    ++<HEAD>
    ++<meta name="generator" content="JDiff v1.1.0">
    ++<!-- Generated by the JDiff Javadoc doclet -->
    ++<!-- (http://www.jdiff.org) -->
    ++<meta name="description" content="JDiff is a Javadoc doclet which generates an HTML report of all the packages, classes, constructors, methods, and fields which have been removed, added or changed in any way, including their documentation, when two APIs are compared.">
    ++<meta name="keywords" content="diff, jdiff, javadiff, java diff, java difference, API difference, difference between two APIs, API diff, Javadoc, doclet">
    ++<TITLE>
    ++android.support.v4.widget.SwipeRefreshLayout
    ++</TITLE>
    ++<link href="../../../../assets/android-developer-docs.css" rel="stylesheet" type="text/css" />
    ++<link href="../stylesheet-jdiff.css" rel="stylesheet" type="text/css" />
    ++<noscript>
    ++<style type="text/css">
    ++body{overflow:auto;}
    ++#body-content{position:relative; top:0;}
    ++#doc-content{overflow:visible;border-left:3px solid #666;}
    ++#side-nav{padding:0;}
    ++#side-nav .toggle-list ul {display:block;}
    ++#resize-packages-nav{border-bottom:3px solid #666;}
    ++</style>
    ++</noscript>
    ++<style type="text/css">
    ++</style>
    ++</HEAD>
    ++<BODY>
    ++<!-- Start of nav bar -->
    ++<a name="top"></a>
    ++<div id="header" style="margin-bottom:0;padding-bottom:0;">
    ++<div id="headerLeft">
    ++<a href="../../../../index.html" tabindex="-1" target="_top"><img src="../../../../assets/images/bg_logo.png" alt="Android Developers" /></a>
    ++</div>
    ++  <div id="headerRight">
    ++  <div id="headerLinks">
    ++<!-- <img src="/assets/images/icon_world.jpg" alt="" /> -->
    ++<span class="text">
    ++<!-- &nbsp;<a href="#">English</a> | -->
    ++<nobr><a href="http://developer.android.com" target="_top">Android Developers</a> | <a href="http://www.android.com" target="_top">Android.com</a></nobr>
    ++</span>
    ++</div>
    ++  <div class="and-diff-id" style="margin-top:6px;margin-right:8px;">
    ++    <table class="diffspectable">
    ++      <tr>
    ++        <td colspan="2" class="diffspechead">API Diff Specification</td>
    ++      </tr>
    ++      <tr>
    ++        <td class="diffspec" style="padding-top:.25em">To Level:</td>
    ++        <td class="diffvaluenew" style="padding-top:.25em">24.2.0</td>
    ++      </tr>
    ++      <tr>
    ++        <td class="diffspec">From Level:</td>
    ++        <td class="diffvalueold">24.1.0</td>
    ++      </tr>
    ++      <tr>
    ++        <td class="diffspec">Generated</td>
    ++        <td class="diffvalue">2016.08.16 14:03</td>
    ++      </tr>
    ++    </table>
    ++    </div><!-- End and-diff-id -->
    ++  <div class="and-diff-id" style="margin-right:8px;">
    ++    <table class="diffspectable">
    ++      <tr>
    ++        <td class="diffspec" colspan="2"><a href="jdiff_statistics.html">Statistics</a>
    ++      </tr>
    ++    </table>
    ++  </div> <!-- End and-diff-id -->
    ++  </div> <!-- End headerRight -->
    ++  </div> <!-- End header -->
    ++<div id="body-content" xstyle="padding:12px;padding-right:18px;">
    ++<div id="doc-content" style="position:relative;">
    ++<div id="mainBodyFluid">
    ++<H2>
    ++Class android.support.v4.widget.<A HREF="../../../../reference/android/support/v4/widget/SwipeRefreshLayout.html" target="_top"><font size="+2"><code>SwipeRefreshLayout</code></font></A>
    ++</H2>
    ++<a NAME="constructors"></a>
    ++<a NAME="methods"></a>
    ++<p>
    ++<a NAME="Added"></a>
    ++<TABLE summary="Added Methods" WIDTH="100%">
    ++<TR>
    ++  <TH VALIGN="TOP" COLSPAN=2>Added Methods</FONT></TD>
    ++</TH>
    ++<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    ++  <TD VALIGN="TOP" WIDTH="25%">
    ++  <A NAME="android.support.v4.widget.SwipeRefreshLayout.setOnChildScrollUpCallback_added(android.support.v4.widget.SwipeRefreshLayout.OnChildScrollUpCallback)"></A>
    ++  <nobr><code>void</code>&nbsp;<A HREF="../../../../reference/android/support/v4/widget/SwipeRefreshLayout.html#setOnChildScrollUpCallback(android.support.v4.widget.SwipeRefreshLayout.OnChildScrollUpCallback)" target="_top"><code>setOnChildScrollUpCallback</code></A>(<code>OnChildScrollUpCallback</code>)</nobr>
    ++  </TD>
    ++  <TD>&nbsp;</TD>
    ++</TR>
    ++</TABLE>
    ++&nbsp;
    ++<a NAME="fields"></a>
    ++      </div>	
    ++      <div id="footer">
    ++        <div id="copyright">
    ++        Except as noted, this content is licensed under 
    ++        <a href="http://creativecommons.org/licenses/by/2.5/"> Creative Commons Attribution 2.5</a>.
    ++        For details and restrictions, see the <a href="/license.html">Content License</a>.
    ++        </div>
    ++      <div id="footerlinks">
    ++      <p>
    ++        <a href="http://www.android.com/terms.html">Site Terms of Service</a> -
    ++        <a href="http://www.android.com/privacy.html">Privacy Policy</a> -
    ++        <a href="http://www.android.com/branding.html">Brand Guidelines</a>
    ++      </p>
    ++    </div>
    ++    </div> <!-- end footer -->
    ++    </div><!-- end doc-content -->
    ++    </div> <!-- end body-content --> 
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    ++</script>
    ++<script type="text/javascript">
    ++  try {
    ++    var pageTracker = _gat._getTracker("UA-5831155-1");
    ++    pageTracker._setAllowAnchor(true);
    ++    pageTracker._initData();
    ++    pageTracker._trackPageview();
    ++  } catch(e) {}
    ++</script>
    ++</BODY>
    ++</HTML>
    +diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.widget.TextViewCompat.html b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.widget.TextViewCompat.html
    +new file mode 100644
    +index 0000000..87b9e69
    +--- /dev/null
    ++++ b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.widget.TextViewCompat.html
    +@@ -0,0 +1,122 @@
    ++<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
    ++<HTML style="overflow:auto;">
    ++<HEAD>
    ++<meta name="generator" content="JDiff v1.1.0">
    ++<!-- Generated by the JDiff Javadoc doclet -->
    ++<!-- (http://www.jdiff.org) -->
    ++<meta name="description" content="JDiff is a Javadoc doclet which generates an HTML report of all the packages, classes, constructors, methods, and fields which have been removed, added or changed in any way, including their documentation, when two APIs are compared.">
    ++<meta name="keywords" content="diff, jdiff, javadiff, java diff, java difference, API difference, difference between two APIs, API diff, Javadoc, doclet">
    ++<TITLE>
    ++android.support.v4.widget.TextViewCompat
    ++</TITLE>
    ++<link href="../../../../assets/android-developer-docs.css" rel="stylesheet" type="text/css" />
    ++<link href="../stylesheet-jdiff.css" rel="stylesheet" type="text/css" />
    ++<noscript>
    ++<style type="text/css">
    ++body{overflow:auto;}
    ++#body-content{position:relative; top:0;}
    ++#doc-content{overflow:visible;border-left:3px solid #666;}
    ++#side-nav{padding:0;}
    ++#side-nav .toggle-list ul {display:block;}
    ++#resize-packages-nav{border-bottom:3px solid #666;}
    ++</style>
    ++</noscript>
    ++<style type="text/css">
    ++</style>
    ++</HEAD>
    ++<BODY>
    ++<!-- Start of nav bar -->
    ++<a name="top"></a>
    ++<div id="header" style="margin-bottom:0;padding-bottom:0;">
    ++<div id="headerLeft">
    ++<a href="../../../../index.html" tabindex="-1" target="_top"><img src="../../../../assets/images/bg_logo.png" alt="Android Developers" /></a>
    ++</div>
    ++  <div id="headerRight">
    ++  <div id="headerLinks">
    ++<!-- <img src="/assets/images/icon_world.jpg" alt="" /> -->
    ++<span class="text">
    ++<!-- &nbsp;<a href="#">English</a> | -->
    ++<nobr><a href="http://developer.android.com" target="_top">Android Developers</a> | <a href="http://www.android.com" target="_top">Android.com</a></nobr>
    ++</span>
    ++</div>
    ++  <div class="and-diff-id" style="margin-top:6px;margin-right:8px;">
    ++    <table class="diffspectable">
    ++      <tr>
    ++        <td colspan="2" class="diffspechead">API Diff Specification</td>
    ++      </tr>
    ++      <tr>
    ++        <td class="diffspec" style="padding-top:.25em">To Level:</td>
    ++        <td class="diffvaluenew" style="padding-top:.25em">24.2.0</td>
    ++      </tr>
    ++      <tr>
    ++        <td class="diffspec">From Level:</td>
    ++        <td class="diffvalueold">24.1.0</td>
    ++      </tr>
    ++      <tr>
    ++        <td class="diffspec">Generated</td>
    ++        <td class="diffvalue">2016.08.16 14:03</td>
    ++      </tr>
    ++    </table>
    ++    </div><!-- End and-diff-id -->
    ++  <div class="and-diff-id" style="margin-right:8px;">
    ++    <table class="diffspectable">
    ++      <tr>
    ++        <td class="diffspec" colspan="2"><a href="jdiff_statistics.html">Statistics</a>
    ++      </tr>
    ++    </table>
    ++  </div> <!-- End and-diff-id -->
    ++  </div> <!-- End headerRight -->
    ++  </div> <!-- End header -->
    ++<div id="body-content" xstyle="padding:12px;padding-right:18px;">
    ++<div id="doc-content" style="position:relative;">
    ++<div id="mainBodyFluid">
    ++<H2>
    ++Class android.support.v4.widget.<A HREF="../../../../reference/android/support/v4/widget/TextViewCompat.html" target="_top"><font size="+2"><code>TextViewCompat</code></font></A>
    ++</H2>
    ++<a NAME="constructors"></a>
    ++<a NAME="methods"></a>
    ++<p>
    ++<a NAME="Added"></a>
    ++<TABLE summary="Added Methods" WIDTH="100%">
    ++<TR>
    ++  <TH VALIGN="TOP" COLSPAN=2>Added Methods</FONT></TD>
    ++</TH>
    ++<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    ++  <TD VALIGN="TOP" WIDTH="25%">
    ++  <A NAME="android.support.v4.widget.TextViewCompat.getCompoundDrawablesRelative_added(android.widget.TextView)"></A>
    ++  <nobr><code>Drawable[]</code>&nbsp;<A HREF="../../../../reference/android/support/v4/widget/TextViewCompat.html#getCompoundDrawablesRelative(android.widget.TextView)" target="_top"><code>getCompoundDrawablesRelative</code></A>(<code>TextView</code>)</nobr>
    ++  </TD>
    ++  <TD>&nbsp;</TD>
    ++</TR>
    ++</TABLE>
    ++&nbsp;
    ++<a NAME="fields"></a>
    ++      </div>	
    ++      <div id="footer">
    ++        <div id="copyright">
    ++        Except as noted, this content is licensed under 
    ++        <a href="http://creativecommons.org/licenses/by/2.5/"> Creative Commons Attribution 2.5</a>.
    ++        For details and restrictions, see the <a href="/license.html">Content License</a>.
    ++        </div>
    ++      <div id="footerlinks">
    ++      <p>
    ++        <a href="http://www.android.com/terms.html">Site Terms of Service</a> -
    ++        <a href="http://www.android.com/privacy.html">Privacy Policy</a> -
    ++        <a href="http://www.android.com/branding.html">Brand Guidelines</a>
    ++      </p>
    ++    </div>
    ++    </div> <!-- end footer -->
    ++    </div><!-- end doc-content -->
    ++    </div> <!-- end body-content --> 
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    ++</script>
    ++<script type="text/javascript">
    ++  try {
    ++    var pageTracker = _gat._getTracker("UA-5831155-1");
    ++    pageTracker._setAllowAnchor(true);
    ++    pageTracker._initData();
    ++    pageTracker._trackPageview();
    ++  } catch(e) {}
    ++</script>
    ++</BODY>
    ++</HTML>
    +diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v7.app.ActionBarDrawerToggle.html b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v7.app.ActionBarDrawerToggle.html
    +new file mode 100644
    +index 0000000..bc8abd6
    +--- /dev/null
    ++++ b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v7.app.ActionBarDrawerToggle.html
    +@@ -0,0 +1,129 @@
    ++<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
    ++<HTML style="overflow:auto;">
    ++<HEAD>
    ++<meta name="generator" content="JDiff v1.1.0">
    ++<!-- Generated by the JDiff Javadoc doclet -->
    ++<!-- (http://www.jdiff.org) -->
    ++<meta name="description" content="JDiff is a Javadoc doclet which generates an HTML report of all the packages, classes, constructors, methods, and fields which have been removed, added or changed in any way, including their documentation, when two APIs are compared.">
    ++<meta name="keywords" content="diff, jdiff, javadiff, java diff, java difference, API difference, difference between two APIs, API diff, Javadoc, doclet">
    ++<TITLE>
    ++android.support.v7.app.ActionBarDrawerToggle
    ++</TITLE>
    ++<link href="../../../../assets/android-developer-docs.css" rel="stylesheet" type="text/css" />
    ++<link href="../stylesheet-jdiff.css" rel="stylesheet" type="text/css" />
    ++<noscript>
    ++<style type="text/css">
    ++body{overflow:auto;}
    ++#body-content{position:relative; top:0;}
    ++#doc-content{overflow:visible;border-left:3px solid #666;}
    ++#side-nav{padding:0;}
    ++#side-nav .toggle-list ul {display:block;}
    ++#resize-packages-nav{border-bottom:3px solid #666;}
    ++</style>
    ++</noscript>
    ++<style type="text/css">
    ++</style>
    ++</HEAD>
    ++<BODY>
    ++<!-- Start of nav bar -->
    ++<a name="top"></a>
    ++<div id="header" style="margin-bottom:0;padding-bottom:0;">
    ++<div id="headerLeft">
    ++<a href="../../../../index.html" tabindex="-1" target="_top"><img src="../../../../assets/images/bg_logo.png" alt="Android Developers" /></a>
    ++</div>
    ++  <div id="headerRight">
    ++  <div id="headerLinks">
    ++<!-- <img src="/assets/images/icon_world.jpg" alt="" /> -->
    ++<span class="text">
    ++<!-- &nbsp;<a href="#">English</a> | -->
    ++<nobr><a href="http://developer.android.com" target="_top">Android Developers</a> | <a href="http://www.android.com" target="_top">Android.com</a></nobr>
    ++</span>
    ++</div>
    ++  <div class="and-diff-id" style="margin-top:6px;margin-right:8px;">
    ++    <table class="diffspectable">
    ++      <tr>
    ++        <td colspan="2" class="diffspechead">API Diff Specification</td>
    ++      </tr>
    ++      <tr>
    ++        <td class="diffspec" style="padding-top:.25em">To Level:</td>
    ++        <td class="diffvaluenew" style="padding-top:.25em">24.2.0</td>
    ++      </tr>
    ++      <tr>
    ++        <td class="diffspec">From Level:</td>
    ++        <td class="diffvalueold">24.1.0</td>
    ++      </tr>
    ++      <tr>
    ++        <td class="diffspec">Generated</td>
    ++        <td class="diffvalue">2016.08.16 14:03</td>
    ++      </tr>
    ++    </table>
    ++    </div><!-- End and-diff-id -->
    ++  <div class="and-diff-id" style="margin-right:8px;">
    ++    <table class="diffspectable">
    ++      <tr>
    ++        <td class="diffspec" colspan="2"><a href="jdiff_statistics.html">Statistics</a>
    ++      </tr>
    ++    </table>
    ++  </div> <!-- End and-diff-id -->
    ++  </div> <!-- End headerRight -->
    ++  </div> <!-- End header -->
    ++<div id="body-content" xstyle="padding:12px;padding-right:18px;">
    ++<div id="doc-content" style="position:relative;">
    ++<div id="mainBodyFluid">
    ++<H2>
    ++Class android.support.v7.app.<A HREF="../../../../reference/android/support/v7/app/ActionBarDrawerToggle.html" target="_top"><font size="+2"><code>ActionBarDrawerToggle</code></font></A>
    ++</H2>
    ++<a NAME="constructors"></a>
    ++<a NAME="methods"></a>
    ++<p>
    ++<a NAME="Added"></a>
    ++<TABLE summary="Added Methods" WIDTH="100%">
    ++<TR>
    ++  <TH VALIGN="TOP" COLSPAN=2>Added Methods</FONT></TD>
    ++</TH>
    ++<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    ++  <TD VALIGN="TOP" WIDTH="25%">
    ++  <A NAME="android.support.v7.app.ActionBarDrawerToggle.getDrawerArrowDrawable_added()"></A>
    ++  <nobr><code>DrawerArrowDrawable</code>&nbsp;<A HREF="../../../../reference/android/support/v7/app/ActionBarDrawerToggle.html#getDrawerArrowDrawable()" target="_top"><code>getDrawerArrowDrawable</code></A>()</nobr>
    ++  </TD>
    ++  <TD>&nbsp;</TD>
    ++</TR>
    ++<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    ++  <TD VALIGN="TOP" WIDTH="25%">
    ++  <A NAME="android.support.v7.app.ActionBarDrawerToggle.setDrawerArrowDrawable_added(android.support.v7.graphics.drawable.DrawerArrowDrawable)"></A>
    ++  <nobr><code>void</code>&nbsp;<A HREF="../../../../reference/android/support/v7/app/ActionBarDrawerToggle.html#setDrawerArrowDrawable(android.support.v7.graphics.drawable.DrawerArrowDrawable)" target="_top"><code>setDrawerArrowDrawable</code></A>(<code>DrawerArrowDrawable</code>)</nobr>
    ++  </TD>
    ++  <TD>&nbsp;</TD>
    ++</TR>
    ++</TABLE>
    ++&nbsp;
    ++<a NAME="fields"></a>
    ++      </div>	
    ++      <div id="footer">
    ++        <div id="copyright">
    ++        Except as noted, this content is licensed under 
    ++        <a href="http://creativecommons.org/licenses/by/2.5/"> Creative Commons Attribution 2.5</a>.
    ++        For details and restrictions, see the <a href="/license.html">Content License</a>.
    ++        </div>
    ++      <div id="footerlinks">
    ++      <p>
    ++        <a href="http://www.android.com/terms.html">Site Terms of Service</a> -
    ++        <a href="http://www.android.com/privacy.html">Privacy Policy</a> -
    ++        <a href="http://www.android.com/branding.html">Brand Guidelines</a>
    ++      </p>
    ++    </div>
    ++    </div> <!-- end footer -->
    ++    </div><!-- end doc-content -->
    ++    </div> <!-- end body-content --> 
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    ++</script>
    ++<script type="text/javascript">
    ++  try {
    ++    var pageTracker = _gat._getTracker("UA-5831155-1");
    ++    pageTracker._setAllowAnchor(true);
    ++    pageTracker._initData();
    ++    pageTracker._trackPageview();
    ++  } catch(e) {}
    ++</script>
    ++</BODY>
    ++</HTML>
    +diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v7.app.AppCompatDelegate.html b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v7.app.AppCompatDelegate.html
    +new file mode 100644
    +index 0000000..7b131e6
    +--- /dev/null
    ++++ b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v7.app.AppCompatDelegate.html
    +@@ -0,0 +1,122 @@
    ++<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
    ++<HTML style="overflow:auto;">
    ++<HEAD>
    ++<meta name="generator" content="JDiff v1.1.0">
    ++<!-- Generated by the JDiff Javadoc doclet -->
    ++<!-- (http://www.jdiff.org) -->
    ++<meta name="description" content="JDiff is a Javadoc doclet which generates an HTML report of all the packages, classes, constructors, methods, and fields which have been removed, added or changed in any way, including their documentation, when two APIs are compared.">
    ++<meta name="keywords" content="diff, jdiff, javadiff, java diff, java difference, API difference, difference between two APIs, API diff, Javadoc, doclet">
    ++<TITLE>
    ++android.support.v7.app.AppCompatDelegate
    ++</TITLE>
    ++<link href="../../../../assets/android-developer-docs.css" rel="stylesheet" type="text/css" />
    ++<link href="../stylesheet-jdiff.css" rel="stylesheet" type="text/css" />
    ++<noscript>
    ++<style type="text/css">
    ++body{overflow:auto;}
    ++#body-content{position:relative; top:0;}
    ++#doc-content{overflow:visible;border-left:3px solid #666;}
    ++#side-nav{padding:0;}
    ++#side-nav .toggle-list ul {display:block;}
    ++#resize-packages-nav{border-bottom:3px solid #666;}
    ++</style>
    ++</noscript>
    ++<style type="text/css">
    ++</style>
    ++</HEAD>
    ++<BODY>
    ++<!-- Start of nav bar -->
    ++<a name="top"></a>
    ++<div id="header" style="margin-bottom:0;padding-bottom:0;">
    ++<div id="headerLeft">
    ++<a href="../../../../index.html" tabindex="-1" target="_top"><img src="../../../../assets/images/bg_logo.png" alt="Android Developers" /></a>
    ++</div>
    ++  <div id="headerRight">
    ++  <div id="headerLinks">
    ++<!-- <img src="/assets/images/icon_world.jpg" alt="" /> -->
    ++<span class="text">
    ++<!-- &nbsp;<a href="#">English</a> | -->
    ++<nobr><a href="http://developer.android.com" target="_top">Android Developers</a> | <a href="http://www.android.com" target="_top">Android.com</a></nobr>
    ++</span>
    ++</div>
    ++  <div class="and-diff-id" style="margin-top:6px;margin-right:8px;">
    ++    <table class="diffspectable">
    ++      <tr>
    ++        <td colspan="2" class="diffspechead">API Diff Specification</td>
    ++      </tr>
    ++      <tr>
    ++        <td class="diffspec" style="padding-top:.25em">To Level:</td>
    ++        <td class="diffvaluenew" style="padding-top:.25em">24.2.0</td>
    ++      </tr>
    ++      <tr>
    ++        <td class="diffspec">From Level:</td>
    ++        <td class="diffvalueold">24.1.0</td>
    ++      </tr>
    ++      <tr>
    ++        <td class="diffspec">Generated</td>
    ++        <td class="diffvalue">2016.08.16 14:03</td>
    ++      </tr>
    ++    </table>
    ++    </div><!-- End and-diff-id -->
    ++  <div class="and-diff-id" style="margin-right:8px;">
    ++    <table class="diffspectable">
    ++      <tr>
    ++        <td class="diffspec" colspan="2"><a href="jdiff_statistics.html">Statistics</a>
    ++      </tr>
    ++    </table>
    ++  </div> <!-- End and-diff-id -->
    ++  </div> <!-- End headerRight -->
    ++  </div> <!-- End header -->
    ++<div id="body-content" xstyle="padding:12px;padding-right:18px;">
    ++<div id="doc-content" style="position:relative;">
    ++<div id="mainBodyFluid">
    ++<H2>
    ++Class android.support.v7.app.<A HREF="../../../../reference/android/support/v7/app/AppCompatDelegate.html" target="_top"><font size="+2"><code>AppCompatDelegate</code></font></A>
    ++</H2>
    ++<a NAME="constructors"></a>
    ++<a NAME="methods"></a>
    ++<p>
    ++<a NAME="Added"></a>
    ++<TABLE summary="Added Methods" WIDTH="100%">
    ++<TR>
    ++  <TH VALIGN="TOP" COLSPAN=2>Added Methods</FONT></TD>
    ++</TH>
    ++<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    ++  <TD VALIGN="TOP" WIDTH="25%">
    ++  <A NAME="android.support.v7.app.AppCompatDelegate.onStart_added()"></A>
    ++  <nobr><code>void</code>&nbsp;<A HREF="../../../../reference/android/support/v7/app/AppCompatDelegate.html#onStart()" target="_top"><code>onStart</code></A>()</nobr>
    ++  </TD>
    ++  <TD>&nbsp;</TD>
    ++</TR>
    ++</TABLE>
    ++&nbsp;
    ++<a NAME="fields"></a>
    ++      </div>	
    ++      <div id="footer">
    ++        <div id="copyright">
    ++        Except as noted, this content is licensed under 
    ++        <a href="http://creativecommons.org/licenses/by/2.5/"> Creative Commons Attribution 2.5</a>.
    ++        For details and restrictions, see the <a href="/license.html">Content License</a>.
    ++        </div>
    ++      <div id="footerlinks">
    ++      <p>
    ++        <a href="http://www.android.com/terms.html">Site Terms of Service</a> -
    ++        <a href="http://www.android.com/privacy.html">Privacy Policy</a> -
    ++        <a href="http://www.android.com/branding.html">Brand Guidelines</a>
    ++      </p>
    ++    </div>
    ++    </div> <!-- end footer -->
    ++    </div><!-- end doc-content -->
    ++    </div> <!-- end body-content --> 
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    ++</script>
    ++<script type="text/javascript">
    ++  try {
    ++    var pageTracker = _gat._getTracker("UA-5831155-1");
    ++    pageTracker._setAllowAnchor(true);
    ++    pageTracker._initData();
    ++    pageTracker._trackPageview();
    ++  } catch(e) {}
    ++</script>
    ++</BODY>
    ++</HTML>
    +diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v7.content.res.AppCompatResources.html b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v7.content.res.AppCompatResources.html
    +new file mode 100644
    +index 0000000..02f43fd
    +--- /dev/null
    ++++ b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v7.content.res.AppCompatResources.html
    +@@ -0,0 +1,122 @@
    ++<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
    ++<HTML style="overflow:auto;">
    ++<HEAD>
    ++<meta name="generator" content="JDiff v1.1.0">
    ++<!-- Generated by the JDiff Javadoc doclet -->
    ++<!-- (http://www.jdiff.org) -->
    ++<meta name="description" content="JDiff is a Javadoc doclet which generates an HTML report of all the packages, classes, constructors, methods, and fields which have been removed, added or changed in any way, including their documentation, when two APIs are compared.">
    ++<meta name="keywords" content="diff, jdiff, javadiff, java diff, java difference, API difference, difference between two APIs, API diff, Javadoc, doclet">
    ++<TITLE>
    ++android.support.v7.content.res.AppCompatResources
    ++</TITLE>
    ++<link href="../../../../assets/android-developer-docs.css" rel="stylesheet" type="text/css" />
    ++<link href="../stylesheet-jdiff.css" rel="stylesheet" type="text/css" />
    ++<noscript>
    ++<style type="text/css">
    ++body{overflow:auto;}
    ++#body-content{position:relative; top:0;}
    ++#doc-content{overflow:visible;border-left:3px solid #666;}
    ++#side-nav{padding:0;}
    ++#side-nav .toggle-list ul {display:block;}
    ++#resize-packages-nav{border-bottom:3px solid #666;}
    ++</style>
    ++</noscript>
    ++<style type="text/css">
    ++</style>
    ++</HEAD>
    ++<BODY>
    ++<!-- Start of nav bar -->
    ++<a name="top"></a>
    ++<div id="header" style="margin-bottom:0;padding-bottom:0;">
    ++<div id="headerLeft">
    ++<a href="../../../../index.html" tabindex="-1" target="_top"><img src="../../../../assets/images/bg_logo.png" alt="Android Developers" /></a>
    ++</div>
    ++  <div id="headerRight">
    ++  <div id="headerLinks">
    ++<!-- <img src="/assets/images/icon_world.jpg" alt="" /> -->
    ++<span class="text">
    ++<!-- &nbsp;<a href="#">English</a> | -->
    ++<nobr><a href="http://developer.android.com" target="_top">Android Developers</a> | <a href="http://www.android.com" target="_top">Android.com</a></nobr>
    ++</span>
    ++</div>
    ++  <div class="and-diff-id" style="margin-top:6px;margin-right:8px;">
    ++    <table class="diffspectable">
    ++      <tr>
    ++        <td colspan="2" class="diffspechead">API Diff Specification</td>
    ++      </tr>
    ++      <tr>
    ++        <td class="diffspec" style="padding-top:.25em">To Level:</td>
    ++        <td class="diffvaluenew" style="padding-top:.25em">24.2.0</td>
    ++      </tr>
    ++      <tr>
    ++        <td class="diffspec">From Level:</td>
    ++        <td class="diffvalueold">24.1.0</td>
    ++      </tr>
    ++      <tr>
    ++        <td class="diffspec">Generated</td>
    ++        <td class="diffvalue">2016.08.16 14:03</td>
    ++      </tr>
    ++    </table>
    ++    </div><!-- End and-diff-id -->
    ++  <div class="and-diff-id" style="margin-right:8px;">
    ++    <table class="diffspectable">
    ++      <tr>
    ++        <td class="diffspec" colspan="2"><a href="jdiff_statistics.html">Statistics</a>
    ++      </tr>
    ++    </table>
    ++  </div> <!-- End and-diff-id -->
    ++  </div> <!-- End headerRight -->
    ++  </div> <!-- End header -->
    ++<div id="body-content" xstyle="padding:12px;padding-right:18px;">
    ++<div id="doc-content" style="position:relative;">
    ++<div id="mainBodyFluid">
    ++<H2>
    ++Class android.support.v7.content.res.<A HREF="../../../../reference/android/support/v7/content/res/AppCompatResources.html" target="_top"><font size="+2"><code>AppCompatResources</code></font></A>
    ++</H2>
    ++<a NAME="constructors"></a>
    ++<a NAME="methods"></a>
    ++<p>
    ++<a NAME="Added"></a>
    ++<TABLE summary="Added Methods" WIDTH="100%">
    ++<TR>
    ++  <TH VALIGN="TOP" COLSPAN=2>Added Methods</FONT></TD>
    ++</TH>
    ++<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    ++  <TD VALIGN="TOP" WIDTH="25%">
    ++  <A NAME="android.support.v7.content.res.AppCompatResources.getDrawable_added(android.content.Context, int)"></A>
    ++  <nobr><code>Drawable</code>&nbsp;<A HREF="../../../../reference/android/support/v7/content/res/AppCompatResources.html#getDrawable(android.content.Context, int)" target="_top"><code>getDrawable</code></A>(<code>Context,</nobr> int<nobr><nobr></code>)</nobr>
    ++  </TD>
    ++  <TD>&nbsp;</TD>
    ++</TR>
    ++</TABLE>
    ++&nbsp;
    ++<a NAME="fields"></a>
    ++      </div>	
    ++      <div id="footer">
    ++        <div id="copyright">
    ++        Except as noted, this content is licensed under 
    ++        <a href="http://creativecommons.org/licenses/by/2.5/"> Creative Commons Attribution 2.5</a>.
    ++        For details and restrictions, see the <a href="/license.html">Content License</a>.
    ++        </div>
    ++      <div id="footerlinks">
    ++      <p>
    ++        <a href="http://www.android.com/terms.html">Site Terms of Service</a> -
    ++        <a href="http://www.android.com/privacy.html">Privacy Policy</a> -
    ++        <a href="http://www.android.com/branding.html">Brand Guidelines</a>
    ++      </p>
    ++    </div>
    ++    </div> <!-- end footer -->
    ++    </div><!-- end doc-content -->
    ++    </div> <!-- end body-content --> 
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    ++</script>
    ++<script type="text/javascript">
    ++  try {
    ++    var pageTracker = _gat._getTracker("UA-5831155-1");
    ++    pageTracker._setAllowAnchor(true);
    ++    pageTracker._initData();
    ++    pageTracker._trackPageview();
    ++  } catch(e) {}
    ++</script>
    ++</BODY>
    ++</HTML>
    +diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v7.graphics.Palette.html b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v7.graphics.Palette.html
    +new file mode 100644
    +index 0000000..1999a48
    +--- /dev/null
    ++++ b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v7.graphics.Palette.html
    +@@ -0,0 +1,129 @@
    ++<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
    ++<HTML style="overflow:auto;">
    ++<HEAD>
    ++<meta name="generator" content="JDiff v1.1.0">
    ++<!-- Generated by the JDiff Javadoc doclet -->
    ++<!-- (http://www.jdiff.org) -->
    ++<meta name="description" content="JDiff is a Javadoc doclet which generates an HTML report of all the packages, classes, constructors, methods, and fields which have been removed, added or changed in any way, including their documentation, when two APIs are compared.">
    ++<meta name="keywords" content="diff, jdiff, javadiff, java diff, java difference, API difference, difference between two APIs, API diff, Javadoc, doclet">
    ++<TITLE>
    ++android.support.v7.graphics.Palette
    ++</TITLE>
    ++<link href="../../../../assets/android-developer-docs.css" rel="stylesheet" type="text/css" />
    ++<link href="../stylesheet-jdiff.css" rel="stylesheet" type="text/css" />
    ++<noscript>
    ++<style type="text/css">
    ++body{overflow:auto;}
    ++#body-content{position:relative; top:0;}
    ++#doc-content{overflow:visible;border-left:3px solid #666;}
    ++#side-nav{padding:0;}
    ++#side-nav .toggle-list ul {display:block;}
    ++#resize-packages-nav{border-bottom:3px solid #666;}
    ++</style>
    ++</noscript>
    ++<style type="text/css">
    ++</style>
    ++</HEAD>
    ++<BODY>
    ++<!-- Start of nav bar -->
    ++<a name="top"></a>
    ++<div id="header" style="margin-bottom:0;padding-bottom:0;">
    ++<div id="headerLeft">
    ++<a href="../../../../index.html" tabindex="-1" target="_top"><img src="../../../../assets/images/bg_logo.png" alt="Android Developers" /></a>
    ++</div>
    ++  <div id="headerRight">
    ++  <div id="headerLinks">
    ++<!-- <img src="/assets/images/icon_world.jpg" alt="" /> -->
    ++<span class="text">
    ++<!-- &nbsp;<a href="#">English</a> | -->
    ++<nobr><a href="http://developer.android.com" target="_top">Android Developers</a> | <a href="http://www.android.com" target="_top">Android.com</a></nobr>
    ++</span>
    ++</div>
    ++  <div class="and-diff-id" style="margin-top:6px;margin-right:8px;">
    ++    <table class="diffspectable">
    ++      <tr>
    ++        <td colspan="2" class="diffspechead">API Diff Specification</td>
    ++      </tr>
    ++      <tr>
    ++        <td class="diffspec" style="padding-top:.25em">To Level:</td>
    ++        <td class="diffvaluenew" style="padding-top:.25em">24.2.0</td>
    ++      </tr>
    ++      <tr>
    ++        <td class="diffspec">From Level:</td>
    ++        <td class="diffvalueold">24.1.0</td>
    ++      </tr>
    ++      <tr>
    ++        <td class="diffspec">Generated</td>
    ++        <td class="diffvalue">2016.08.16 14:03</td>
    ++      </tr>
    ++    </table>
    ++    </div><!-- End and-diff-id -->
    ++  <div class="and-diff-id" style="margin-right:8px;">
    ++    <table class="diffspectable">
    ++      <tr>
    ++        <td class="diffspec" colspan="2"><a href="jdiff_statistics.html">Statistics</a>
    ++      </tr>
    ++    </table>
    ++  </div> <!-- End and-diff-id -->
    ++  </div> <!-- End headerRight -->
    ++  </div> <!-- End header -->
    ++<div id="body-content" xstyle="padding:12px;padding-right:18px;">
    ++<div id="doc-content" style="position:relative;">
    ++<div id="mainBodyFluid">
    ++<H2>
    ++Class android.support.v7.graphics.<A HREF="../../../../reference/android/support/v7/graphics/Palette.html" target="_top"><font size="+2"><code>Palette</code></font></A>
    ++</H2>
    ++<a NAME="constructors"></a>
    ++<a NAME="methods"></a>
    ++<p>
    ++<a NAME="Added"></a>
    ++<TABLE summary="Added Methods" WIDTH="100%">
    ++<TR>
    ++  <TH VALIGN="TOP" COLSPAN=2>Added Methods</FONT></TD>
    ++</TH>
    ++<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    ++  <TD VALIGN="TOP" WIDTH="25%">
    ++  <A NAME="android.support.v7.graphics.Palette.getDominantColor_added(int)"></A>
    ++  <nobr><code>int</code>&nbsp;<A HREF="../../../../reference/android/support/v7/graphics/Palette.html#getDominantColor(int)" target="_top"><code>getDominantColor</code></A>(<code>int</code>)</nobr>
    ++  </TD>
    ++  <TD>&nbsp;</TD>
    ++</TR>
    ++<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    ++  <TD VALIGN="TOP" WIDTH="25%">
    ++  <A NAME="android.support.v7.graphics.Palette.getDominantSwatch_added()"></A>
    ++  <nobr><code>Swatch</code>&nbsp;<A HREF="../../../../reference/android/support/v7/graphics/Palette.html#getDominantSwatch()" target="_top"><code>getDominantSwatch</code></A>()</nobr>
    ++  </TD>
    ++  <TD>&nbsp;</TD>
    ++</TR>
    ++</TABLE>
    ++&nbsp;
    ++<a NAME="fields"></a>
    ++      </div>	
    ++      <div id="footer">
    ++        <div id="copyright">
    ++        Except as noted, this content is licensed under 
    ++        <a href="http://creativecommons.org/licenses/by/2.5/"> Creative Commons Attribution 2.5</a>.
    ++        For details and restrictions, see the <a href="/license.html">Content License</a>.
    ++        </div>
    ++      <div id="footerlinks">
    ++      <p>
    ++        <a href="http://www.android.com/terms.html">Site Terms of Service</a> -
    ++        <a href="http://www.android.com/privacy.html">Privacy Policy</a> -
    ++        <a href="http://www.android.com/branding.html">Brand Guidelines</a>
    ++      </p>
    ++    </div>
    ++    </div> <!-- end footer -->
    ++    </div><!-- end doc-content -->
    ++    </div> <!-- end body-content --> 
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    ++</script>
    ++<script type="text/javascript">
    ++  try {
    ++    var pageTracker = _gat._getTracker("UA-5831155-1");
    ++    pageTracker._setAllowAnchor(true);
    ++    pageTracker._initData();
    ++    pageTracker._trackPageview();
    ++  } catch(e) {}
    ++</script>
    ++</BODY>
    ++</HTML>
    +diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v7.util.SortedList.Callback.html b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v7.util.SortedList.Callback.html
    +new file mode 100644
    +index 0000000..95be79c
    +--- /dev/null
    ++++ b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v7.util.SortedList.Callback.html
    +@@ -0,0 +1,152 @@
    ++<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
    ++<HTML style="overflow:auto;">
    ++<HEAD>
    ++<meta name="generator" content="JDiff v1.1.0">
    ++<!-- Generated by the JDiff Javadoc doclet -->
    ++<!-- (http://www.jdiff.org) -->
    ++<meta name="description" content="JDiff is a Javadoc doclet which generates an HTML report of all the packages, classes, constructors, methods, and fields which have been removed, added or changed in any way, including their documentation, when two APIs are compared.">
    ++<meta name="keywords" content="diff, jdiff, javadiff, java diff, java difference, API difference, difference between two APIs, API diff, Javadoc, doclet">
    ++<TITLE>
    ++android.support.v7.util.SortedList.Callback
    ++</TITLE>
    ++<link href="../../../../assets/android-developer-docs.css" rel="stylesheet" type="text/css" />
    ++<link href="../stylesheet-jdiff.css" rel="stylesheet" type="text/css" />
    ++<noscript>
    ++<style type="text/css">
    ++body{overflow:auto;}
    ++#body-content{position:relative; top:0;}
    ++#doc-content{overflow:visible;border-left:3px solid #666;}
    ++#side-nav{padding:0;}
    ++#side-nav .toggle-list ul {display:block;}
    ++#resize-packages-nav{border-bottom:3px solid #666;}
    ++</style>
    ++</noscript>
    ++<style type="text/css">
    ++</style>
    ++</HEAD>
    ++<BODY>
    ++<!-- Start of nav bar -->
    ++<a name="top"></a>
    ++<div id="header" style="margin-bottom:0;padding-bottom:0;">
    ++<div id="headerLeft">
    ++<a href="../../../../index.html" tabindex="-1" target="_top"><img src="../../../../assets/images/bg_logo.png" alt="Android Developers" /></a>
    ++</div>
    ++  <div id="headerRight">
    ++  <div id="headerLinks">
    ++<!-- <img src="/assets/images/icon_world.jpg" alt="" /> -->
    ++<span class="text">
    ++<!-- &nbsp;<a href="#">English</a> | -->
    ++<nobr><a href="http://developer.android.com" target="_top">Android Developers</a> | <a href="http://www.android.com" target="_top">Android.com</a></nobr>
    ++</span>
    ++</div>
    ++  <div class="and-diff-id" style="margin-top:6px;margin-right:8px;">
    ++    <table class="diffspectable">
    ++      <tr>
    ++        <td colspan="2" class="diffspechead">API Diff Specification</td>
    ++      </tr>
    ++      <tr>
    ++        <td class="diffspec" style="padding-top:.25em">To Level:</td>
    ++        <td class="diffvaluenew" style="padding-top:.25em">24.2.0</td>
    ++      </tr>
    ++      <tr>
    ++        <td class="diffspec">From Level:</td>
    ++        <td class="diffvalueold">24.1.0</td>
    ++      </tr>
    ++      <tr>
    ++        <td class="diffspec">Generated</td>
    ++        <td class="diffvalue">2016.08.16 14:03</td>
    ++      </tr>
    ++    </table>
    ++    </div><!-- End and-diff-id -->
    ++  <div class="and-diff-id" style="margin-right:8px;">
    ++    <table class="diffspectable">
    ++      <tr>
    ++        <td class="diffspec" colspan="2"><a href="jdiff_statistics.html">Statistics</a>
    ++      </tr>
    ++    </table>
    ++  </div> <!-- End and-diff-id -->
    ++  </div> <!-- End headerRight -->
    ++  </div> <!-- End header -->
    ++<div id="body-content" xstyle="padding:12px;padding-right:18px;">
    ++<div id="doc-content" style="position:relative;">
    ++<div id="mainBodyFluid">
    ++<H2>
    ++Class android.support.v7.util.<A HREF="../../../../reference/android/support/v7/util/SortedList.Callback.html" target="_top"><font size="+2"><code>SortedList.Callback</code></font></A>
    ++</H2>
    ++<p><font xsize="+1">Added interface <code>android.support.v7.util.ListUpdateCallback</code>.<br></font>
    ++<a NAME="constructors"></a>
    ++<a NAME="methods"></a>
    ++<p>
    ++<a NAME="Removed"></a>
    ++<TABLE summary="Removed Methods" WIDTH="100%">
    ++<TR>
    ++  <TH VALIGN="TOP" COLSPAN=2>Removed Methods</FONT></TD>
    ++</TH>
    ++<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    ++  <TD VALIGN="TOP" WIDTH="25%">
    ++  <A NAME="android.support.v7.util.SortedList.Callback.onInserted_removed(int, int)"></A>
    ++  <nobr><code>void</code>&nbsp;onInserted(<code>int,</nobr> int<nobr><nobr></code>)</nobr>
    ++  </TD>
    ++  <TD>&nbsp;</TD>
    ++</TR>
    ++<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    ++  <TD VALIGN="TOP" WIDTH="25%">
    ++  <A NAME="android.support.v7.util.SortedList.Callback.onMoved_removed(int, int)"></A>
    ++  <nobr><code>void</code>&nbsp;onMoved(<code>int,</nobr> int<nobr><nobr></code>)</nobr>
    ++  </TD>
    ++  <TD>&nbsp;</TD>
    ++</TR>
    ++<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    ++  <TD VALIGN="TOP" WIDTH="25%">
    ++  <A NAME="android.support.v7.util.SortedList.Callback.onRemoved_removed(int, int)"></A>
    ++  <nobr><code>void</code>&nbsp;onRemoved(<code>int,</nobr> int<nobr><nobr></code>)</nobr>
    ++  </TD>
    ++  <TD>&nbsp;</TD>
    ++</TR>
    ++</TABLE>
    ++&nbsp;
    ++<p>
    ++<a NAME="Added"></a>
    ++<TABLE summary="Added Methods" WIDTH="100%">
    ++<TR>
    ++  <TH VALIGN="TOP" COLSPAN=2>Added Methods</FONT></TD>
    ++</TH>
    ++<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    ++  <TD VALIGN="TOP" WIDTH="25%">
    ++  <A NAME="android.support.v7.util.SortedList.Callback.onChanged_added(int, int, java.lang.Object)"></A>
    ++  <nobr><code>void</code>&nbsp;<A HREF="../../../../reference/android/support/v7/util/SortedList.Callback.html#onChanged(int, int, java.lang.Object)" target="_top"><code>onChanged</code></A>(<code>int,</nobr> int<nobr>,</nobr> Object<nobr><nobr></code>)</nobr>
    ++  </TD>
    ++  <TD>&nbsp;</TD>
    ++</TR>
    ++</TABLE>
    ++&nbsp;
    ++<a NAME="fields"></a>
    ++      </div>	
    ++      <div id="footer">
    ++        <div id="copyright">
    ++        Except as noted, this content is licensed under 
    ++        <a href="http://creativecommons.org/licenses/by/2.5/"> Creative Commons Attribution 2.5</a>.
    ++        For details and restrictions, see the <a href="/license.html">Content License</a>.
    ++        </div>
    ++      <div id="footerlinks">
    ++      <p>
    ++        <a href="http://www.android.com/terms.html">Site Terms of Service</a> -
    ++        <a href="http://www.android.com/privacy.html">Privacy Policy</a> -
    ++        <a href="http://www.android.com/branding.html">Brand Guidelines</a>
    ++      </p>
    ++    </div>
    ++    </div> <!-- end footer -->
    ++    </div><!-- end doc-content -->
    ++    </div> <!-- end body-content --> 
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    ++</script>
    ++<script type="text/javascript">
    ++  try {
    ++    var pageTracker = _gat._getTracker("UA-5831155-1");
    ++    pageTracker._setAllowAnchor(true);
    ++    pageTracker._initData();
    ++    pageTracker._trackPageview();
    ++  } catch(e) {}
    ++</script>
    ++</BODY>
    ++</HTML>
    +diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v7.widget.LinearLayoutManager.html b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v7.widget.LinearLayoutManager.html
    +new file mode 100644
    +index 0000000..2fdfb0e
    +--- /dev/null
    ++++ b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v7.widget.LinearLayoutManager.html
    +@@ -0,0 +1,123 @@
    ++<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
    ++<HTML style="overflow:auto;">
    ++<HEAD>
    ++<meta name="generator" content="JDiff v1.1.0">
    ++<!-- Generated by the JDiff Javadoc doclet -->
    ++<!-- (http://www.jdiff.org) -->
    ++<meta name="description" content="JDiff is a Javadoc doclet which generates an HTML report of all the packages, classes, constructors, methods, and fields which have been removed, added or changed in any way, including their documentation, when two APIs are compared.">
    ++<meta name="keywords" content="diff, jdiff, javadiff, java diff, java difference, API difference, difference between two APIs, API diff, Javadoc, doclet">
    ++<TITLE>
    ++android.support.v7.widget.LinearLayoutManager
    ++</TITLE>
    ++<link href="../../../../assets/android-developer-docs.css" rel="stylesheet" type="text/css" />
    ++<link href="../stylesheet-jdiff.css" rel="stylesheet" type="text/css" />
    ++<noscript>
    ++<style type="text/css">
    ++body{overflow:auto;}
    ++#body-content{position:relative; top:0;}
    ++#doc-content{overflow:visible;border-left:3px solid #666;}
    ++#side-nav{padding:0;}
    ++#side-nav .toggle-list ul {display:block;}
    ++#resize-packages-nav{border-bottom:3px solid #666;}
    ++</style>
    ++</noscript>
    ++<style type="text/css">
    ++</style>
    ++</HEAD>
    ++<BODY>
    ++<!-- Start of nav bar -->
    ++<a name="top"></a>
    ++<div id="header" style="margin-bottom:0;padding-bottom:0;">
    ++<div id="headerLeft">
    ++<a href="../../../../index.html" tabindex="-1" target="_top"><img src="../../../../assets/images/bg_logo.png" alt="Android Developers" /></a>
    ++</div>
    ++  <div id="headerRight">
    ++  <div id="headerLinks">
    ++<!-- <img src="/assets/images/icon_world.jpg" alt="" /> -->
    ++<span class="text">
    ++<!-- &nbsp;<a href="#">English</a> | -->
    ++<nobr><a href="http://developer.android.com" target="_top">Android Developers</a> | <a href="http://www.android.com" target="_top">Android.com</a></nobr>
    ++</span>
    ++</div>
    ++  <div class="and-diff-id" style="margin-top:6px;margin-right:8px;">
    ++    <table class="diffspectable">
    ++      <tr>
    ++        <td colspan="2" class="diffspechead">API Diff Specification</td>
    ++      </tr>
    ++      <tr>
    ++        <td class="diffspec" style="padding-top:.25em">To Level:</td>
    ++        <td class="diffvaluenew" style="padding-top:.25em">24.2.0</td>
    ++      </tr>
    ++      <tr>
    ++        <td class="diffspec">From Level:</td>
    ++        <td class="diffvalueold">24.1.0</td>
    ++      </tr>
    ++      <tr>
    ++        <td class="diffspec">Generated</td>
    ++        <td class="diffvalue">2016.08.16 14:03</td>
    ++      </tr>
    ++    </table>
    ++    </div><!-- End and-diff-id -->
    ++  <div class="and-diff-id" style="margin-right:8px;">
    ++    <table class="diffspectable">
    ++      <tr>
    ++        <td class="diffspec" colspan="2"><a href="jdiff_statistics.html">Statistics</a>
    ++      </tr>
    ++    </table>
    ++  </div> <!-- End and-diff-id -->
    ++  </div> <!-- End headerRight -->
    ++  </div> <!-- End header -->
    ++<div id="body-content" xstyle="padding:12px;padding-right:18px;">
    ++<div id="doc-content" style="position:relative;">
    ++<div id="mainBodyFluid">
    ++<H2>
    ++Class android.support.v7.widget.<A HREF="../../../../reference/android/support/v7/widget/LinearLayoutManager.html" target="_top"><font size="+2"><code>LinearLayoutManager</code></font></A>
    ++</H2>
    ++<p><font xsize="+1">Added interface <code>android.support.v7.widget.RecyclerView.SmoothScroller.ScrollVectorProvider</code>.<br></font>
    ++<a NAME="constructors"></a>
    ++<a NAME="methods"></a>
    ++<p>
    ++<a NAME="Removed"></a>
    ++<TABLE summary="Removed Methods" WIDTH="100%">
    ++<TR>
    ++  <TH VALIGN="TOP" COLSPAN=2>Removed Methods</FONT></TD>
    ++</TH>
    ++<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    ++  <TD VALIGN="TOP" WIDTH="25%">
    ++  <A NAME="android.support.v7.widget.LinearLayoutManager.prepareForDrop_removed(android.view.View, android.view.View, int, int)"></A>
    ++  <nobr><code>void</code>&nbsp;prepareForDrop(<code>View,</nobr> View<nobr>,</nobr> int<nobr>,</nobr> int<nobr><nobr></code>)</nobr>
    ++  </TD>
    ++  <TD>&nbsp;</TD>
    ++</TR>
    ++</TABLE>
    ++&nbsp;
    ++<a NAME="fields"></a>
    ++      </div>	
    ++      <div id="footer">
    ++        <div id="copyright">
    ++        Except as noted, this content is licensed under 
    ++        <a href="http://creativecommons.org/licenses/by/2.5/"> Creative Commons Attribution 2.5</a>.
    ++        For details and restrictions, see the <a href="/license.html">Content License</a>.
    ++        </div>
    ++      <div id="footerlinks">
    ++      <p>
    ++        <a href="http://www.android.com/terms.html">Site Terms of Service</a> -
    ++        <a href="http://www.android.com/privacy.html">Privacy Policy</a> -
    ++        <a href="http://www.android.com/branding.html">Brand Guidelines</a>
    ++      </p>
    ++    </div>
    ++    </div> <!-- end footer -->
    ++    </div><!-- end doc-content -->
    ++    </div> <!-- end body-content --> 
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    ++</script>
    ++<script type="text/javascript">
    ++  try {
    ++    var pageTracker = _gat._getTracker("UA-5831155-1");
    ++    pageTracker._setAllowAnchor(true);
    ++    pageTracker._initData();
    ++    pageTracker._trackPageview();
    ++  } catch(e) {}
    ++</script>
    ++</BODY>
    ++</HTML>
    +diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v7.widget.LinearSmoothScroller.html b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v7.widget.LinearSmoothScroller.html
    +new file mode 100644
    +index 0000000..5cf79ee
    +--- /dev/null
    ++++ b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v7.widget.LinearSmoothScroller.html
    +@@ -0,0 +1,126 @@
    ++<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
    ++<HTML style="overflow:auto;">
    ++<HEAD>
    ++<meta name="generator" content="JDiff v1.1.0">
    ++<!-- Generated by the JDiff Javadoc doclet -->
    ++<!-- (http://www.jdiff.org) -->
    ++<meta name="description" content="JDiff is a Javadoc doclet which generates an HTML report of all the packages, classes, constructors, methods, and fields which have been removed, added or changed in any way, including their documentation, when two APIs are compared.">
    ++<meta name="keywords" content="diff, jdiff, javadiff, java diff, java difference, API difference, difference between two APIs, API diff, Javadoc, doclet">
    ++<TITLE>
    ++android.support.v7.widget.LinearSmoothScroller
    ++</TITLE>
    ++<link href="../../../../assets/android-developer-docs.css" rel="stylesheet" type="text/css" />
    ++<link href="../stylesheet-jdiff.css" rel="stylesheet" type="text/css" />
    ++<noscript>
    ++<style type="text/css">
    ++body{overflow:auto;}
    ++#body-content{position:relative; top:0;}
    ++#doc-content{overflow:visible;border-left:3px solid #666;}
    ++#side-nav{padding:0;}
    ++#side-nav .toggle-list ul {display:block;}
    ++#resize-packages-nav{border-bottom:3px solid #666;}
    ++</style>
    ++</noscript>
    ++<style type="text/css">
    ++</style>
    ++</HEAD>
    ++<BODY>
    ++<!-- Start of nav bar -->
    ++<a name="top"></a>
    ++<div id="header" style="margin-bottom:0;padding-bottom:0;">
    ++<div id="headerLeft">
    ++<a href="../../../../index.html" tabindex="-1" target="_top"><img src="../../../../assets/images/bg_logo.png" alt="Android Developers" /></a>
    ++</div>
    ++  <div id="headerRight">
    ++  <div id="headerLinks">
    ++<!-- <img src="/assets/images/icon_world.jpg" alt="" /> -->
    ++<span class="text">
    ++<!-- &nbsp;<a href="#">English</a> | -->
    ++<nobr><a href="http://developer.android.com" target="_top">Android Developers</a> | <a href="http://www.android.com" target="_top">Android.com</a></nobr>
    ++</span>
    ++</div>
    ++  <div class="and-diff-id" style="margin-top:6px;margin-right:8px;">
    ++    <table class="diffspectable">
    ++      <tr>
    ++        <td colspan="2" class="diffspechead">API Diff Specification</td>
    ++      </tr>
    ++      <tr>
    ++        <td class="diffspec" style="padding-top:.25em">To Level:</td>
    ++        <td class="diffvaluenew" style="padding-top:.25em">24.2.0</td>
    ++      </tr>
    ++      <tr>
    ++        <td class="diffspec">From Level:</td>
    ++        <td class="diffvalueold">24.1.0</td>
    ++      </tr>
    ++      <tr>
    ++        <td class="diffspec">Generated</td>
    ++        <td class="diffvalue">2016.08.16 14:03</td>
    ++      </tr>
    ++    </table>
    ++    </div><!-- End and-diff-id -->
    ++  <div class="and-diff-id" style="margin-right:8px;">
    ++    <table class="diffspectable">
    ++      <tr>
    ++        <td class="diffspec" colspan="2"><a href="jdiff_statistics.html">Statistics</a>
    ++      </tr>
    ++    </table>
    ++  </div> <!-- End and-diff-id -->
    ++  </div> <!-- End headerRight -->
    ++  </div> <!-- End header -->
    ++<div id="body-content" xstyle="padding:12px;padding-right:18px;">
    ++<div id="doc-content" style="position:relative;">
    ++<div id="mainBodyFluid">
    ++<H2>
    ++Class android.support.v7.widget.<A HREF="../../../../reference/android/support/v7/widget/LinearSmoothScroller.html" target="_top"><font size="+2"><code>LinearSmoothScroller</code></font></A>
    ++</H2>
    ++<p>Changed from abstract to non-abstract.
    ++<a NAME="constructors"></a>
    ++<a NAME="methods"></a>
    ++<p>
    ++<a NAME="Changed"></a>
    ++<TABLE summary="Changed Methods" WIDTH="100%">
    ++<TR>
    ++  <TH VALIGN="TOP" COLSPAN=3>Changed Methods</FONT></TD>
    ++</TH>
    ++<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    ++  <TD VALIGN="TOP" WIDTH="25%">
    ++  <A NAME="android.support.v7.widget.LinearSmoothScroller.computeScrollVectorForPosition_changed(int)"></A>
    ++  <nobr><code>PointF</code>&nbsp;<A HREF="../../../../reference/android/support/v7/widget/LinearSmoothScroller.html#computeScrollVectorForPosition(int)" target="_top"><code>computeScrollVectorForPosition</code></A>(<code>int</code>)  </nobr>
    ++  </TD>
    ++  <TD VALIGN="TOP" WIDTH="30%">
    ++Changed from abstract to non-abstract.
    ++  </TD>
    ++  <TD>&nbsp;</TD>
    ++</TR>
    ++</TABLE>
    ++&nbsp;
    ++<a NAME="fields"></a>
    ++      </div>	
    ++      <div id="footer">
    ++        <div id="copyright">
    ++        Except as noted, this content is licensed under 
    ++        <a href="http://creativecommons.org/licenses/by/2.5/"> Creative Commons Attribution 2.5</a>.
    ++        For details and restrictions, see the <a href="/license.html">Content License</a>.
    ++        </div>
    ++      <div id="footerlinks">
    ++      <p>
    ++        <a href="http://www.android.com/terms.html">Site Terms of Service</a> -
    ++        <a href="http://www.android.com/privacy.html">Privacy Policy</a> -
    ++        <a href="http://www.android.com/branding.html">Brand Guidelines</a>
    ++      </p>
    ++    </div>
    ++    </div> <!-- end footer -->
    ++    </div><!-- end doc-content -->
    ++    </div> <!-- end body-content --> 
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    ++</script>
    ++<script type="text/javascript">
    ++  try {
    ++    var pageTracker = _gat._getTracker("UA-5831155-1");
    ++    pageTracker._setAllowAnchor(true);
    ++    pageTracker._initData();
    ++    pageTracker._trackPageview();
    ++  } catch(e) {}
    ++</script>
    ++</BODY>
    ++</HTML>
    +diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v7.widget.RecyclerView.html b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v7.widget.RecyclerView.html
    +new file mode 100644
    +index 0000000..5411a1f
    +--- /dev/null
    ++++ b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v7.widget.RecyclerView.html
    +@@ -0,0 +1,130 @@
    ++<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
    ++<HTML style="overflow:auto;">
    ++<HEAD>
    ++<meta name="generator" content="JDiff v1.1.0">
    ++<!-- Generated by the JDiff Javadoc doclet -->
    ++<!-- (http://www.jdiff.org) -->
    ++<meta name="description" content="JDiff is a Javadoc doclet which generates an HTML report of all the packages, classes, constructors, methods, and fields which have been removed, added or changed in any way, including their documentation, when two APIs are compared.">
    ++<meta name="keywords" content="diff, jdiff, javadiff, java diff, java difference, API difference, difference between two APIs, API diff, Javadoc, doclet">
    ++<TITLE>
    ++android.support.v7.widget.RecyclerView
    ++</TITLE>
    ++<link href="../../../../assets/android-developer-docs.css" rel="stylesheet" type="text/css" />
    ++<link href="../stylesheet-jdiff.css" rel="stylesheet" type="text/css" />
    ++<noscript>
    ++<style type="text/css">
    ++body{overflow:auto;}
    ++#body-content{position:relative; top:0;}
    ++#doc-content{overflow:visible;border-left:3px solid #666;}
    ++#side-nav{padding:0;}
    ++#side-nav .toggle-list ul {display:block;}
    ++#resize-packages-nav{border-bottom:3px solid #666;}
    ++</style>
    ++</noscript>
    ++<style type="text/css">
    ++</style>
    ++</HEAD>
    ++<BODY>
    ++<!-- Start of nav bar -->
    ++<a name="top"></a>
    ++<div id="header" style="margin-bottom:0;padding-bottom:0;">
    ++<div id="headerLeft">
    ++<a href="../../../../index.html" tabindex="-1" target="_top"><img src="../../../../assets/images/bg_logo.png" alt="Android Developers" /></a>
    ++</div>
    ++  <div id="headerRight">
    ++  <div id="headerLinks">
    ++<!-- <img src="/assets/images/icon_world.jpg" alt="" /> -->
    ++<span class="text">
    ++<!-- &nbsp;<a href="#">English</a> | -->
    ++<nobr><a href="http://developer.android.com" target="_top">Android Developers</a> | <a href="http://www.android.com" target="_top">Android.com</a></nobr>
    ++</span>
    ++</div>
    ++  <div class="and-diff-id" style="margin-top:6px;margin-right:8px;">
    ++    <table class="diffspectable">
    ++      <tr>
    ++        <td colspan="2" class="diffspechead">API Diff Specification</td>
    ++      </tr>
    ++      <tr>
    ++        <td class="diffspec" style="padding-top:.25em">To Level:</td>
    ++        <td class="diffvaluenew" style="padding-top:.25em">24.2.0</td>
    ++      </tr>
    ++      <tr>
    ++        <td class="diffspec">From Level:</td>
    ++        <td class="diffvalueold">24.1.0</td>
    ++      </tr>
    ++      <tr>
    ++        <td class="diffspec">Generated</td>
    ++        <td class="diffvalue">2016.08.16 14:03</td>
    ++      </tr>
    ++    </table>
    ++    </div><!-- End and-diff-id -->
    ++  <div class="and-diff-id" style="margin-right:8px;">
    ++    <table class="diffspectable">
    ++      <tr>
    ++        <td class="diffspec" colspan="2"><a href="jdiff_statistics.html">Statistics</a>
    ++      </tr>
    ++    </table>
    ++  </div> <!-- End and-diff-id -->
    ++  </div> <!-- End headerRight -->
    ++  </div> <!-- End header -->
    ++<div id="body-content" xstyle="padding:12px;padding-right:18px;">
    ++<div id="doc-content" style="position:relative;">
    ++<div id="mainBodyFluid">
    ++<H2>
    ++Class android.support.v7.widget.<A HREF="../../../../reference/android/support/v7/widget/RecyclerView.html" target="_top"><font size="+2"><code>RecyclerView</code></font></A>
    ++</H2>
    ++<p><font xsize="+1">Added interfaces <code>android.support.v4.view.NestedScrollingChild, android.support.v4.view.ScrollingView</code>.<br></font>
    ++<a NAME="constructors"></a>
    ++<a NAME="methods"></a>
    ++<p>
    ++<a NAME="Added"></a>
    ++<TABLE summary="Added Methods" WIDTH="100%">
    ++<TR>
    ++  <TH VALIGN="TOP" COLSPAN=2>Added Methods</FONT></TD>
    ++</TH>
    ++<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    ++  <TD VALIGN="TOP" WIDTH="25%">
    ++  <A NAME="android.support.v7.widget.RecyclerView.getOnFlingListener_added()"></A>
    ++  <nobr><code>OnFlingListener</code>&nbsp;<A HREF="../../../../reference/android/support/v7/widget/RecyclerView.html#getOnFlingListener()" target="_top"><code>getOnFlingListener</code></A>()</nobr>
    ++  </TD>
    ++  <TD>&nbsp;</TD>
    ++</TR>
    ++<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    ++  <TD VALIGN="TOP" WIDTH="25%">
    ++  <A NAME="android.support.v7.widget.RecyclerView.setOnFlingListener_added(android.support.v7.widget.RecyclerView.OnFlingListener)"></A>
    ++  <nobr><code>void</code>&nbsp;<A HREF="../../../../reference/android/support/v7/widget/RecyclerView.html#setOnFlingListener(android.support.v7.widget.RecyclerView.OnFlingListener)" target="_top"><code>setOnFlingListener</code></A>(<code>OnFlingListener</code>)</nobr>
    ++  </TD>
    ++  <TD>&nbsp;</TD>
    ++</TR>
    ++</TABLE>
    ++&nbsp;
    ++<a NAME="fields"></a>
    ++      </div>	
    ++      <div id="footer">
    ++        <div id="copyright">
    ++        Except as noted, this content is licensed under 
    ++        <a href="http://creativecommons.org/licenses/by/2.5/"> Creative Commons Attribution 2.5</a>.
    ++        For details and restrictions, see the <a href="/license.html">Content License</a>.
    ++        </div>
    ++      <div id="footerlinks">
    ++      <p>
    ++        <a href="http://www.android.com/terms.html">Site Terms of Service</a> -
    ++        <a href="http://www.android.com/privacy.html">Privacy Policy</a> -
    ++        <a href="http://www.android.com/branding.html">Brand Guidelines</a>
    ++      </p>
    ++    </div>
    ++    </div> <!-- end footer -->
    ++    </div><!-- end doc-content -->
    ++    </div> <!-- end body-content --> 
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    ++</script>
    ++<script type="text/javascript">
    ++  try {
    ++    var pageTracker = _gat._getTracker("UA-5831155-1");
    ++    pageTracker._setAllowAnchor(true);
    ++    pageTracker._initData();
    ++    pageTracker._trackPageview();
    ++  } catch(e) {}
    ++</script>
    ++</BODY>
    ++</HTML>
    +diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v7.widget.StaggeredGridLayoutManager.html b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v7.widget.StaggeredGridLayoutManager.html
    +new file mode 100644
    +index 0000000..9d0ab87
    +--- /dev/null
    ++++ b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v7.widget.StaggeredGridLayoutManager.html
    +@@ -0,0 +1,138 @@
    ++<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
    ++<HTML style="overflow:auto;">
    ++<HEAD>
    ++<meta name="generator" content="JDiff v1.1.0">
    ++<!-- Generated by the JDiff Javadoc doclet -->
    ++<!-- (http://www.jdiff.org) -->
    ++<meta name="description" content="JDiff is a Javadoc doclet which generates an HTML report of all the packages, classes, constructors, methods, and fields which have been removed, added or changed in any way, including their documentation, when two APIs are compared.">
    ++<meta name="keywords" content="diff, jdiff, javadiff, java diff, java difference, API difference, difference between two APIs, API diff, Javadoc, doclet">
    ++<TITLE>
    ++android.support.v7.widget.StaggeredGridLayoutManager
    ++</TITLE>
    ++<link href="../../../../assets/android-developer-docs.css" rel="stylesheet" type="text/css" />
    ++<link href="../stylesheet-jdiff.css" rel="stylesheet" type="text/css" />
    ++<noscript>
    ++<style type="text/css">
    ++body{overflow:auto;}
    ++#body-content{position:relative; top:0;}
    ++#doc-content{overflow:visible;border-left:3px solid #666;}
    ++#side-nav{padding:0;}
    ++#side-nav .toggle-list ul {display:block;}
    ++#resize-packages-nav{border-bottom:3px solid #666;}
    ++</style>
    ++</noscript>
    ++<style type="text/css">
    ++</style>
    ++</HEAD>
    ++<BODY>
    ++<!-- Start of nav bar -->
    ++<a name="top"></a>
    ++<div id="header" style="margin-bottom:0;padding-bottom:0;">
    ++<div id="headerLeft">
    ++<a href="../../../../index.html" tabindex="-1" target="_top"><img src="../../../../assets/images/bg_logo.png" alt="Android Developers" /></a>
    ++</div>
    ++  <div id="headerRight">
    ++  <div id="headerLinks">
    ++<!-- <img src="/assets/images/icon_world.jpg" alt="" /> -->
    ++<span class="text">
    ++<!-- &nbsp;<a href="#">English</a> | -->
    ++<nobr><a href="http://developer.android.com" target="_top">Android Developers</a> | <a href="http://www.android.com" target="_top">Android.com</a></nobr>
    ++</span>
    ++</div>
    ++  <div class="and-diff-id" style="margin-top:6px;margin-right:8px;">
    ++    <table class="diffspectable">
    ++      <tr>
    ++        <td colspan="2" class="diffspechead">API Diff Specification</td>
    ++      </tr>
    ++      <tr>
    ++        <td class="diffspec" style="padding-top:.25em">To Level:</td>
    ++        <td class="diffvaluenew" style="padding-top:.25em">24.2.0</td>
    ++      </tr>
    ++      <tr>
    ++        <td class="diffspec">From Level:</td>
    ++        <td class="diffvalueold">24.1.0</td>
    ++      </tr>
    ++      <tr>
    ++        <td class="diffspec">Generated</td>
    ++        <td class="diffvalue">2016.08.16 14:03</td>
    ++      </tr>
    ++    </table>
    ++    </div><!-- End and-diff-id -->
    ++  <div class="and-diff-id" style="margin-right:8px;">
    ++    <table class="diffspectable">
    ++      <tr>
    ++        <td class="diffspec" colspan="2"><a href="jdiff_statistics.html">Statistics</a>
    ++      </tr>
    ++    </table>
    ++  </div> <!-- End and-diff-id -->
    ++  </div> <!-- End headerRight -->
    ++  </div> <!-- End header -->
    ++<div id="body-content" xstyle="padding:12px;padding-right:18px;">
    ++<div id="doc-content" style="position:relative;">
    ++<div id="mainBodyFluid">
    ++<H2>
    ++Class android.support.v7.widget.<A HREF="../../../../reference/android/support/v7/widget/StaggeredGridLayoutManager.html" target="_top"><font size="+2"><code>StaggeredGridLayoutManager</code></font></A>
    ++</H2>
    ++<p><font xsize="+1">Added interface <code>android.support.v7.widget.RecyclerView.SmoothScroller.ScrollVectorProvider</code>.<br></font>
    ++<a NAME="constructors"></a>
    ++<a NAME="methods"></a>
    ++<p>
    ++<a NAME="Added"></a>
    ++<TABLE summary="Added Methods" WIDTH="100%">
    ++<TR>
    ++  <TH VALIGN="TOP" COLSPAN=2>Added Methods</FONT></TD>
    ++</TH>
    ++<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    ++  <TD VALIGN="TOP" WIDTH="25%">
    ++  <A NAME="android.support.v7.widget.StaggeredGridLayoutManager.computeScrollVectorForPosition_added(int)"></A>
    ++  <nobr><code>PointF</code>&nbsp;<A HREF="../../../../reference/android/support/v7/widget/StaggeredGridLayoutManager.html#computeScrollVectorForPosition(int)" target="_top"><code>computeScrollVectorForPosition</code></A>(<code>int</code>)</nobr>
    ++  </TD>
    ++  <TD>&nbsp;</TD>
    ++</TR>
    ++</TABLE>
    ++&nbsp;
    ++<a NAME="fields"></a>
    ++<p>
    ++<a NAME="Removed"></a>
    ++<TABLE summary="Removed Fields" WIDTH="100%">
    ++<TR>
    ++  <TH VALIGN="TOP" COLSPAN=2>Removed Fields</FONT></TD>
    ++</TH>
    ++<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    ++  <TD VALIGN="TOP" WIDTH="25%">
    ++  <A NAME="android.support.v7.widget.StaggeredGridLayoutManager.TAG"></A>
    ++  <code>String</code>&nbsp;TAG
    ++  </TD>
    ++  <TD>&nbsp;</TD>
    ++</TR>
    ++</TABLE>
    ++&nbsp;
    ++      </div>	
    ++      <div id="footer">
    ++        <div id="copyright">
    ++        Except as noted, this content is licensed under 
    ++        <a href="http://creativecommons.org/licenses/by/2.5/"> Creative Commons Attribution 2.5</a>.
    ++        For details and restrictions, see the <a href="/license.html">Content License</a>.
    ++        </div>
    ++      <div id="footerlinks">
    ++      <p>
    ++        <a href="http://www.android.com/terms.html">Site Terms of Service</a> -
    ++        <a href="http://www.android.com/privacy.html">Privacy Policy</a> -
    ++        <a href="http://www.android.com/branding.html">Brand Guidelines</a>
    ++      </p>
    ++    </div>
    ++    </div> <!-- end footer -->
    ++    </div><!-- end doc-content -->
    ++    </div> <!-- end body-content --> 
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    ++</script>
    ++<script type="text/javascript">
    ++  try {
    ++    var pageTracker = _gat._getTracker("UA-5831155-1");
    ++    pageTracker._setAllowAnchor(true);
    ++    pageTracker._initData();
    ++    pageTracker._trackPageview();
    ++  } catch(e) {}
    ++</script>
    ++</BODY>
    ++</HTML>
    +diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/changes-summary.html b/docs/html/sdk/support_api_diff/24.2.0/changes/changes-summary.html
    +new file mode 100644
    +index 0000000..4456c22
    +--- /dev/null
    ++++ b/docs/html/sdk/support_api_diff/24.2.0/changes/changes-summary.html
    +@@ -0,0 +1,329 @@
    ++<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
    ++<HTML style="overflow:auto;">
    ++<HEAD>
    ++<meta name="generator" content="JDiff v1.1.0">
    ++<!-- Generated by the JDiff Javadoc doclet -->
    ++<!-- (http://www.jdiff.org) -->
    ++<meta name="description" content="JDiff is a Javadoc doclet which generates an HTML report of all the packages, classes, constructors, methods, and fields which have been removed, added or changed in any way, including their documentation, when two APIs are compared.">
    ++<meta name="keywords" content="diff, jdiff, javadiff, java diff, java difference, API difference, difference between two APIs, API diff, Javadoc, doclet">
    ++<TITLE>
    ++Support&nbsp;Library&nbsp;API&nbsp;Differences&nbsp;Report
    ++</TITLE>
    ++<link href="../../../../assets/android-developer-docs.css" rel="stylesheet" type="text/css" />
    ++<link href="../stylesheet-jdiff.css" rel="stylesheet" type="text/css" />
    ++<noscript>
    ++<style type="text/css">
    ++body{overflow:auto;}
    ++#body-content{position:relative; top:0;}
    ++#doc-content{overflow:visible;border-left:3px solid #666;}
    ++#side-nav{padding:0;}
    ++#side-nav .toggle-list ul {display:block;}
    ++#resize-packages-nav{border-bottom:3px solid #666;}
    ++</style>
    ++</noscript>
    ++<style type="text/css">
    ++</style>
    ++</HEAD>
    ++<body class="gc-documentation">
    ++<!-- Start of nav bar -->
    ++<a name="top"></a>
    ++<div id="header" style="margin-bottom:0;padding-bottom:0;">
    ++<div id="headerLeft">
    ++<a href="../../../../index.html" tabindex="-1" target="_top"><img src="../../../../assets/images/bg_logo.png" alt="Android Developers" /></a>
    ++</div>
    ++  <div id="headerRight">
    ++  <div id="headerLinks">
    ++<!-- <img src="/assets/images/icon_world.jpg" alt="" /> -->
    ++<span class="text">
    ++<!-- &nbsp;<a href="#">English</a> | -->
    ++<nobr><a href="http://developer.android.com" target="_top">Android Developers</a> | <a href="http://www.android.com" target="_top">Android.com</a></nobr>
    ++</span>
    ++</div>
    ++  <div class="and-diff-id" style="margin-top:6px;margin-right:8px;">
    ++    <table class="diffspectable">
    ++      <tr>
    ++        <td colspan="2" class="diffspechead">API Diff Specification</td>
    ++      </tr>
    ++      <tr>
    ++        <td class="diffspec" style="padding-top:.25em">To Level:</td>
    ++        <td class="diffvaluenew" style="padding-top:.25em">24.2.0</td>
    ++      </tr>
    ++      <tr>
    ++        <td class="diffspec">From Level:</td>
    ++        <td class="diffvalueold">24.1.0</td>
    ++      </tr>
    ++      <tr>
    ++        <td class="diffspec">Generated</td>
    ++        <td class="diffvalue">2016.08.16 14:03</td>
    ++      </tr>
    ++    </table>
    ++    </div><!-- End and-diff-id -->
    ++  <div class="and-diff-id" style="margin-right:8px;">
    ++    <table class="diffspectable">
    ++      <tr>
    ++        <td class="diffspec" colspan="2"><a href="jdiff_statistics.html">Statistics</a>
    ++      </tr>
    ++    </table>
    ++  </div> <!-- End and-diff-id -->
    ++  </div> <!-- End headerRight -->
    ++  </div> <!-- End header -->
    ++<div id="body-content" xstyle="padding:12px;padding-right:18px;">
    ++<div id="doc-content" style="position:relative;">
    ++<div id="mainBodyFluid">
    ++    <div id="docTitleContainer">
    ++    <h1>Support&nbsp;Library&nbsp;API&nbsp;Differences&nbsp;Report</h1>
    ++<p>This report details the changes in the Android Support Library API between two versions. 
    ++It shows additions, modifications, and removals for packages, classes, methods, and fields. 
    ++The report also includes general statistics that characterize the extent and type of the differences.</p>
    ++<p>This report is based a comparison of the Support Library API specifications 
    ++whose version level identifiers are given in the upper-right corner of this page. It compares a 
    ++newer "to" version's API to an older "from" version's API, noting all changes relative to the 
    ++older API. So, for example, API elements marked as removed are no longer present in the "to" 
    ++API specification.</p>
    ++<p>To navigate the report, use the "Select a Diffs Index" and "Filter the Index" 
    ++controls on the left. The report uses text formatting to indicate <em>interface names</em>, 
    ++<a href= ><code>links to reference documentation</code></a>, and <a href= >links to change 
    ++description</a>. The statistics are accessible from the "Statistics" link in the upper-right corner.</p>
    ++<p>For more information about the Android API and SDK, 
    ++see the <a href="http://developer.android.com/index.html" target="_top">Android Developers site</a>.</p>
    ++<p>
    ++<a NAME="Removed"></a>
    ++<TABLE summary="Removed Packages" WIDTH="100%">
    ++<TR>
    ++  <TH VALIGN="TOP" COLSPAN=2>Removed Packages</FONT></TD>
    ++</TH>
    ++<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    ++  <TD VALIGN="TOP" WIDTH="25%">
    ++  <A NAME="android.support.v7.appcompat"></A>
    ++  android.support.v7.appcompat  </TD>
    ++  <TD>&nbsp;</TD>
    ++</TR>
    ++<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    ++  <TD VALIGN="TOP" WIDTH="25%">
    ++  <A NAME="android.support.v7.recyclerview"></A>
    ++  android.support.v7.recyclerview  </TD>
    ++  <TD>&nbsp;</TD>
    ++</TR>
    ++<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    ++  <TD VALIGN="TOP" WIDTH="25%">
    ++  <A NAME="android.support.v8.renderscript"></A>
    ++  android.support.v8.renderscript  </TD>
    ++  <TD>&nbsp;</TD>
    ++</TR>
    ++</TABLE>
    ++&nbsp;
    ++<p>
    ++<a NAME="Added"></a>
    ++<TABLE summary="Added Packages" WIDTH="100%">
    ++<TR>
    ++  <TH VALIGN="TOP" COLSPAN=2>Added Packages</FONT></TD>
    ++</TH>
    ++<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    ++  <TD VALIGN="TOP" WIDTH="25%">
    ++  <A NAME="android.support.transition"></A>
    ++  <nobr><A HREF="../../../../reference/android/support/transition/package-summary.html" target="_top"><code>android.support.transition</code></A></nobr>
    ++  </TD>
    ++  <TD>&nbsp;</TD>
    ++</TR>
    ++<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    ++  <TD VALIGN="TOP" WIDTH="25%">
    ++  <A NAME="android.support.v4.text.util"></A>
    ++  <nobr><A HREF="../../../../reference/android/support/v4/text/util/package-summary.html" target="_top"><code>android.support.v4.text.util</code></A></nobr>
    ++  </TD>
    ++  <TD>&nbsp;</TD>
    ++</TR>
    ++</TABLE>
    ++&nbsp;
    ++<p>
    ++<a NAME="Changed"></a>
    ++<TABLE summary="Changed Packages" WIDTH="100%">
    ++<TR>
    ++  <TH VALIGN="TOP" COLSPAN=3>Changed Packages</FONT></TD>
    ++</TH>
    ++<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    ++  <TD VALIGN="TOP" WIDTH="25%">
    ++  <A NAME="android.support.customtabs"></A>
    ++  <nobr><A HREF="pkg_android.support.customtabs.html">android.support.customtabs</A></nobr>
    ++  </TD>
    ++  <TD>&nbsp;</TD>
    ++</TR>
    ++<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    ++  <TD VALIGN="TOP" WIDTH="25%">
    ++  <A NAME="android.support.design.widget"></A>
    ++  <nobr><A HREF="pkg_android.support.design.widget.html">android.support.design.widget</A></nobr>
    ++  </TD>
    ++  <TD>&nbsp;</TD>
    ++</TR>
    ++<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    ++  <TD VALIGN="TOP" WIDTH="25%">
    ++  <A NAME="android.support.v14.preference"></A>
    ++  <nobr><A HREF="pkg_android.support.v14.preference.html">android.support.v14.preference</A></nobr>
    ++  </TD>
    ++  <TD>&nbsp;</TD>
    ++</TR>
    ++<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    ++  <TD VALIGN="TOP" WIDTH="25%">
    ++  <A NAME="android.support.v17.leanback.widget"></A>
    ++  <nobr><A HREF="pkg_android.support.v17.leanback.widget.html">android.support.v17.leanback.widget</A></nobr>
    ++  </TD>
    ++  <TD>&nbsp;</TD>
    ++</TR>
    ++<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    ++  <TD VALIGN="TOP" WIDTH="25%">
    ++  <A NAME="android.support.v17.preference"></A>
    ++  <nobr><A HREF="pkg_android.support.v17.preference.html">android.support.v17.preference</A></nobr>
    ++  </TD>
    ++  <TD>&nbsp;</TD>
    ++</TR>
    ++<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    ++  <TD VALIGN="TOP" WIDTH="25%">
    ++  <A NAME="android.support.v4.accessibilityservice"></A>
    ++  <nobr><A HREF="pkg_android.support.v4.accessibilityservice.html">android.support.v4.accessibilityservice</A></nobr>
    ++  </TD>
    ++  <TD>&nbsp;</TD>
    ++</TR>
    ++<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    ++  <TD VALIGN="TOP" WIDTH="25%">
    ++  <A NAME="android.support.v4.app"></A>
    ++  <nobr><A HREF="pkg_android.support.v4.app.html">android.support.v4.app</A></nobr>
    ++  </TD>
    ++  <TD>&nbsp;</TD>
    ++</TR>
    ++<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    ++  <TD VALIGN="TOP" WIDTH="25%">
    ++  <A NAME="android.support.v4.content"></A>
    ++  <nobr><A HREF="pkg_android.support.v4.content.html">android.support.v4.content</A></nobr>
    ++  </TD>
    ++  <TD>&nbsp;</TD>
    ++</TR>
    ++<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    ++  <TD VALIGN="TOP" WIDTH="25%">
    ++  <A NAME="android.support.v4.graphics.drawable"></A>
    ++  <nobr><A HREF="pkg_android.support.v4.graphics.drawable.html">android.support.v4.graphics.drawable</A></nobr>
    ++  </TD>
    ++  <TD>&nbsp;</TD>
    ++</TR>
    ++<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    ++  <TD VALIGN="TOP" WIDTH="25%">
    ++  <A NAME="android.support.v4.media"></A>
    ++  <nobr><A HREF="pkg_android.support.v4.media.html">android.support.v4.media</A></nobr>
    ++  </TD>
    ++  <TD>&nbsp;</TD>
    ++</TR>
    ++<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    ++  <TD VALIGN="TOP" WIDTH="25%">
    ++  <A NAME="android.support.v4.media.session"></A>
    ++  <nobr><A HREF="pkg_android.support.v4.media.session.html">android.support.v4.media.session</A></nobr>
    ++  </TD>
    ++  <TD>&nbsp;</TD>
    ++</TR>
    ++<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    ++  <TD VALIGN="TOP" WIDTH="25%">
    ++  <A NAME="android.support.v4.os"></A>
    ++  <nobr><A HREF="pkg_android.support.v4.os.html">android.support.v4.os</A></nobr>
    ++  </TD>
    ++  <TD>&nbsp;</TD>
    ++</TR>
    ++<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    ++  <TD VALIGN="TOP" WIDTH="25%">
    ++  <A NAME="android.support.v4.util"></A>
    ++  <nobr><A HREF="pkg_android.support.v4.util.html">android.support.v4.util</A></nobr>
    ++  </TD>
    ++  <TD>&nbsp;</TD>
    ++</TR>
    ++<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    ++  <TD VALIGN="TOP" WIDTH="25%">
    ++  <A NAME="android.support.v4.view"></A>
    ++  <nobr><A HREF="pkg_android.support.v4.view.html">android.support.v4.view</A></nobr>
    ++  </TD>
    ++  <TD>&nbsp;</TD>
    ++</TR>
    ++<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    ++  <TD VALIGN="TOP" WIDTH="25%">
    ++  <A NAME="android.support.v4.view.accessibility"></A>
    ++  <nobr><A HREF="pkg_android.support.v4.view.accessibility.html">android.support.v4.view.accessibility</A></nobr>
    ++  </TD>
    ++  <TD>&nbsp;</TD>
    ++</TR>
    ++<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    ++  <TD VALIGN="TOP" WIDTH="25%">
    ++  <A NAME="android.support.v4.widget"></A>
    ++  <nobr><A HREF="pkg_android.support.v4.widget.html">android.support.v4.widget</A></nobr>
    ++  </TD>
    ++  <TD>&nbsp;</TD>
    ++</TR>
    ++<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    ++  <TD VALIGN="TOP" WIDTH="25%">
    ++  <A NAME="android.support.v7.app"></A>
    ++  <nobr><A HREF="pkg_android.support.v7.app.html">android.support.v7.app</A></nobr>
    ++  </TD>
    ++  <TD>&nbsp;</TD>
    ++</TR>
    ++<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    ++  <TD VALIGN="TOP" WIDTH="25%">
    ++  <A NAME="android.support.v7.content.res"></A>
    ++  <nobr><A HREF="pkg_android.support.v7.content.res.html">android.support.v7.content.res</A></nobr>
    ++  </TD>
    ++  <TD>&nbsp;</TD>
    ++</TR>
    ++<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    ++  <TD VALIGN="TOP" WIDTH="25%">
    ++  <A NAME="android.support.v7.graphics"></A>
    ++  <nobr><A HREF="pkg_android.support.v7.graphics.html">android.support.v7.graphics</A></nobr>
    ++  </TD>
    ++  <TD>&nbsp;</TD>
    ++</TR>
    ++<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    ++  <TD VALIGN="TOP" WIDTH="25%">
    ++  <A NAME="android.support.v7.preference"></A>
    ++  <nobr><A HREF="pkg_android.support.v7.preference.html">android.support.v7.preference</A></nobr>
    ++  </TD>
    ++  <TD>&nbsp;</TD>
    ++</TR>
    ++<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    ++  <TD VALIGN="TOP" WIDTH="25%">
    ++  <A NAME="android.support.v7.util"></A>
    ++  <nobr><A HREF="pkg_android.support.v7.util.html">android.support.v7.util</A></nobr>
    ++  </TD>
    ++  <TD>&nbsp;</TD>
    ++</TR>
    ++<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    ++  <TD VALIGN="TOP" WIDTH="25%">
    ++  <A NAME="android.support.v7.widget"></A>
    ++  <nobr><A HREF="pkg_android.support.v7.widget.html">android.support.v7.widget</A></nobr>
    ++  </TD>
    ++  <TD>&nbsp;</TD>
    ++</TR>
    ++</TABLE>
    ++&nbsp;
    ++<!-- End of API section -->
    ++<!-- Start of packages section -->
    ++      </div>	
    ++      <div id="footer">
    ++        <div id="copyright">
    ++        Except as noted, this content is licensed under 
    ++        <a href="http://creativecommons.org/licenses/by/2.5/"> Creative Commons Attribution 2.5</a>.
    ++        For details and restrictions, see the <a href="/license.html">Content License</a>.
    ++        </div>
    ++      <div id="footerlinks">
    ++      <p>
    ++        <a href="http://www.android.com/terms.html">Site Terms of Service</a> -
    ++        <a href="http://www.android.com/privacy.html">Privacy Policy</a> -
    ++        <a href="http://www.android.com/branding.html">Brand Guidelines</a>
    ++      </p>
    ++    </div>
    ++    </div> <!-- end footer -->
    ++    </div><!-- end doc-content -->
    ++    </div> <!-- end body-content --> 
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    ++</script>
    ++<script type="text/javascript">
    ++  try {
    ++    var pageTracker = _gat._getTracker("UA-5831155-1");
    ++    pageTracker._setAllowAnchor(true);
    ++    pageTracker._initData();
    ++    pageTracker._trackPageview();
    ++  } catch(e) {}
    ++</script>
    ++</BODY>
    ++</HTML>
    +diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/classes_index_additions.html b/docs/html/sdk/support_api_diff/24.2.0/changes/classes_index_additions.html
    +new file mode 100644
    +index 0000000..acb8115
    +--- /dev/null
    ++++ b/docs/html/sdk/support_api_diff/24.2.0/changes/classes_index_additions.html
    +@@ -0,0 +1,305 @@
    ++<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
    ++<HTML style="overflow:auto;">
    ++<HEAD>
    ++<meta name="generator" content="JDiff v1.1.0">
    ++<!-- Generated by the JDiff Javadoc doclet -->
    ++<!-- (http://www.jdiff.org) -->
    ++<meta name="description" content="JDiff is a Javadoc doclet which generates an HTML report of all the packages, classes, constructors, methods, and fields which have been removed, added or changed in any way, including their documentation, when two APIs are compared.">
    ++<meta name="keywords" content="diff, jdiff, javadiff, java diff, java difference, API difference, difference between two APIs, API diff, Javadoc, doclet">
    ++<TITLE>
    ++Class Additions Index
    ++</TITLE>
    ++<link href="../../../../assets/android-developer-docs.css" rel="stylesheet" type="text/css" />
    ++<link href="../stylesheet-jdiff.css" rel="stylesheet" type="text/css" />
    ++<noscript>
    ++<style type="text/css">
    ++body{overflow:auto;}
    ++#body-content{position:relative; top:0;}
    ++#doc-content{overflow:visible;border-left:3px solid #666;}
    ++#side-nav{padding:0;}
    ++#side-nav .toggle-list ul {display:block;}
    ++#resize-packages-nav{border-bottom:3px solid #666;}
    ++</style>
    ++</noscript>
    ++<style type="text/css">
    ++</style>
    ++</HEAD>
    ++<BODY class="gc-documentation" style="padding:12px;">
    ++<a NAME="topheader"></a>
    ++<table summary="Index for Classes" width="100%" class="jdiffIndex" border="0" cellspacing="0" cellpadding="0" style="padding-bottom:0;margin-bottom:0;">
    ++  <tr>
    ++  <th class="indexHeader">
    ++    Filter the Index:
    ++  </th>
    ++  </tr>
    ++  <tr>
    ++  <td class="indexText" style="line-height:1.3em;padding-left:2em;">
    ++<a href="classes_index_all.html" class="staysblack">All Classes</a>
    ++  <br>
    ++<font color="#999999">Removals</font>
    ++  <br>
    ++<b>Additions</b>
    ++  <br>
    ++<A HREF="classes_index_changes.html"xclass="hiddenlink">Changes</A>
    ++  </td>
    ++  </tr>
    ++</table>
    ++<div id="indexTableCaption" style="background-color:#eee;padding:0 4px 0 4px;font-size:11px;margin-bottom:1em;">
    ++Listed as: <span style="color:#069"><strong>Added</strong></span>,  <span style="color:#069"><strike>Removed</strike></span>,  <span style="color:#069">Changed</span></font>
    ++</div>
    ++<A NAME="A"></A>
    ++<br><font size="+2">A</font>&nbsp;
    ++<a href="#B"><font size="-2">B</font></a> 
    ++<a href="#C"><font size="-2">C</font></a> 
    ++<a href="#D"><font size="-2">D</font></a> 
    ++<a href="#G"><font size="-2">G</font></a> 
    ++<a href="#L"><font size="-2">L</font></a> 
    ++<a href="#M"><font size="-2">M</font></a> 
    ++<a href="#N"><font size="-2">N</font></a> 
    ++<a href="#P"><font size="-2">P</font></a> 
    ++<a href="#R"><font size="-2">R</font></a> 
    ++<a href="#S"><font size="-2">S</font></a> 
    ++<a href="#T"><font size="-2">T</font></a> 
    ++ <a href="#topheader"><font size="-2">TOP</font></a>
    ++<p><div style="line-height:1.5em;color:black">
    ++<A HREF="pkg_android.support.v4.view.accessibility.html#AccessibilityManagerCompat.AccessibilityStateChangeListener" class="hiddenlink" target="rightframe"><b><i>AccessibilityManagerCompat.AccessibilityStateChangeListener</i></b></A><br>
    ++<A HREF="pkg_android.support.v4.view.accessibility.html#AccessibilityManagerCompat.TouchExplorationStateChangeListener" class="hiddenlink" target="rightframe"><b><i>AccessibilityManagerCompat.TouchExplorationStateChangeListener</i></b></A><br>
    ++<A HREF="pkg_android.support.v7.app.html#ActionBarActivity" class="hiddenlink" target="rightframe"><b>ActionBarActivity</b></A><br>
    ++<A HREF="pkg_android.support.v7.widget.html#ActionMenuView" class="hiddenlink" target="rightframe"><b>ActionMenuView</b></A><br>
    ++<A HREF="pkg_android.support.v7.widget.html#ActionMenuView.LayoutParams" class="hiddenlink" target="rightframe"><b>ActionMenuView.LayoutParams</b></A><br>
    ++<A HREF="pkg_android.support.v7.widget.html#ActionMenuView.OnMenuItemClickListener" class="hiddenlink" target="rightframe"><b><i>ActionMenuView.OnMenuItemClickListener</i></b></A><br>
    ++<A HREF="pkg_android.support.v7.app.html#AppCompatActivity" class="hiddenlink" target="rightframe"><b>AppCompatActivity</b></A><br>
    ++<A HREF="pkg_android.support.v7.widget.html#AppCompatAutoCompleteTextView" class="hiddenlink" target="rightframe"><b>AppCompatAutoCompleteTextView</b></A><br>
    ++<A HREF="pkg_android.support.v7.widget.html#AppCompatButton" class="hiddenlink" target="rightframe"><b>AppCompatButton</b></A><br>
    ++<A HREF="pkg_android.support.v7.widget.html#AppCompatCheckBox" class="hiddenlink" target="rightframe"><b>AppCompatCheckBox</b></A><br>
    ++<A HREF="pkg_android.support.v7.widget.html#AppCompatCheckedTextView" class="hiddenlink" target="rightframe"><b>AppCompatCheckedTextView</b></A><br>
    ++<A HREF="pkg_android.support.v7.app.html#AppCompatDialogFragment" class="hiddenlink" target="rightframe"><b>AppCompatDialogFragment</b></A><br>
    ++<A HREF="pkg_android.support.v7.widget.html#AppCompatEditText" class="hiddenlink" target="rightframe"><b>AppCompatEditText</b></A><br>
    ++<A HREF="pkg_android.support.v7.widget.html#AppCompatImageButton" class="hiddenlink" target="rightframe"><b>AppCompatImageButton</b></A><br>
    ++<A HREF="pkg_android.support.v7.widget.html#AppCompatImageView" class="hiddenlink" target="rightframe"><b>AppCompatImageView</b></A><br>
    ++<A HREF="pkg_android.support.v7.widget.html#AppCompatMultiAutoCompleteTextView" class="hiddenlink" target="rightframe"><b>AppCompatMultiAutoCompleteTextView</b></A><br>
    ++<A HREF="pkg_android.support.v7.widget.html#AppCompatRadioButton" class="hiddenlink" target="rightframe"><b>AppCompatRadioButton</b></A><br>
    ++<A HREF="pkg_android.support.v7.widget.html#AppCompatRatingBar" class="hiddenlink" target="rightframe"><b>AppCompatRatingBar</b></A><br>
    ++<A HREF="pkg_android.support.v7.widget.html#AppCompatSeekBar" class="hiddenlink" target="rightframe"><b>AppCompatSeekBar</b></A><br>
    ++<A HREF="pkg_android.support.v7.widget.html#AppCompatSpinner" class="hiddenlink" target="rightframe"><b>AppCompatSpinner</b></A><br>
    ++<A HREF="pkg_android.support.v7.widget.html#AppCompatTextView" class="hiddenlink" target="rightframe"><b>AppCompatTextView</b></A><br>
    ++<A NAME="B"></A>
    ++<br><font size="+2">B</font>&nbsp;
    ++<a href="#A"><font size="-2">A</font></a> 
    ++<a href="#C"><font size="-2">C</font></a> 
    ++<a href="#D"><font size="-2">D</font></a> 
    ++<a href="#G"><font size="-2">G</font></a> 
    ++<a href="#L"><font size="-2">L</font></a> 
    ++<a href="#M"><font size="-2">M</font></a> 
    ++<a href="#N"><font size="-2">N</font></a> 
    ++<a href="#P"><font size="-2">P</font></a> 
    ++<a href="#R"><font size="-2">R</font></a> 
    ++<a href="#S"><font size="-2">S</font></a> 
    ++<a href="#T"><font size="-2">T</font></a> 
    ++ <a href="#topheader"><font size="-2">TOP</font></a>
    ++<p><div style="line-height:1.5em;color:black">
    ++<A HREF="pkg_android.support.v7.util.html#BatchingListUpdateCallback" class="hiddenlink" target="rightframe"><b>BatchingListUpdateCallback</b></A><br>
    ++<A NAME="C"></A>
    ++<br><font size="+2">C</font>&nbsp;
    ++<a href="#A"><font size="-2">A</font></a> 
    ++<a href="#B"><font size="-2">B</font></a> 
    ++<a href="#D"><font size="-2">D</font></a> 
    ++<a href="#G"><font size="-2">G</font></a> 
    ++<a href="#L"><font size="-2">L</font></a> 
    ++<a href="#M"><font size="-2">M</font></a> 
    ++<a href="#N"><font size="-2">N</font></a> 
    ++<a href="#P"><font size="-2">P</font></a> 
    ++<a href="#R"><font size="-2">R</font></a> 
    ++<a href="#S"><font size="-2">S</font></a> 
    ++<a href="#T"><font size="-2">T</font></a> 
    ++ <a href="#topheader"><font size="-2">TOP</font></a>
    ++<p><div style="line-height:1.5em;color:black">
    ++<A HREF="pkg_android.support.v7.widget.html#CardView" class="hiddenlink" target="rightframe"><b>CardView</b></A><br>
    ++<A NAME="D"></A>
    ++<br><font size="+2">D</font>&nbsp;
    ++<a href="#A"><font size="-2">A</font></a> 
    ++<a href="#B"><font size="-2">B</font></a> 
    ++<a href="#C"><font size="-2">C</font></a> 
    ++<a href="#G"><font size="-2">G</font></a> 
    ++<a href="#L"><font size="-2">L</font></a> 
    ++<a href="#M"><font size="-2">M</font></a> 
    ++<a href="#N"><font size="-2">N</font></a> 
    ++<a href="#P"><font size="-2">P</font></a> 
    ++<a href="#R"><font size="-2">R</font></a> 
    ++<a href="#S"><font size="-2">S</font></a> 
    ++<a href="#T"><font size="-2">T</font></a> 
    ++ <a href="#topheader"><font size="-2">TOP</font></a>
    ++<p><div style="line-height:1.5em;color:black">
    ++<A HREF="pkg_android.support.v7.util.html#DiffUtil" class="hiddenlink" target="rightframe"><b>DiffUtil</b></A><br>
    ++<A HREF="pkg_android.support.v7.util.html#DiffUtil.Callback" class="hiddenlink" target="rightframe"><b>DiffUtil.Callback</b></A><br>
    ++<A HREF="pkg_android.support.v7.util.html#DiffUtil.DiffResult" class="hiddenlink" target="rightframe"><b>DiffUtil.DiffResult</b></A><br>
    ++<A NAME="G"></A>
    ++<br><font size="+2">G</font>&nbsp;
    ++<a href="#A"><font size="-2">A</font></a> 
    ++<a href="#B"><font size="-2">B</font></a> 
    ++<a href="#C"><font size="-2">C</font></a> 
    ++<a href="#D"><font size="-2">D</font></a> 
    ++<a href="#L"><font size="-2">L</font></a> 
    ++<a href="#M"><font size="-2">M</font></a> 
    ++<a href="#N"><font size="-2">N</font></a> 
    ++<a href="#P"><font size="-2">P</font></a> 
    ++<a href="#R"><font size="-2">R</font></a> 
    ++<a href="#S"><font size="-2">S</font></a> 
    ++<a href="#T"><font size="-2">T</font></a> 
    ++ <a href="#topheader"><font size="-2">TOP</font></a>
    ++<p><div style="line-height:1.5em;color:black">
    ++<A HREF="pkg_android.support.v7.widget.html#GridLayout" class="hiddenlink" target="rightframe"><b>GridLayout</b></A><br>
    ++<A HREF="pkg_android.support.v7.widget.html#GridLayout.Alignment" class="hiddenlink" target="rightframe"><b>GridLayout.Alignment</b></A><br>
    ++<A HREF="pkg_android.support.v7.widget.html#GridLayout.LayoutParams" class="hiddenlink" target="rightframe"><b>GridLayout.LayoutParams</b></A><br>
    ++<A HREF="pkg_android.support.v7.widget.html#GridLayout.Spec" class="hiddenlink" target="rightframe"><b>GridLayout.Spec</b></A><br>
    ++<A NAME="L"></A>
    ++<br><font size="+2">L</font>&nbsp;
    ++<a href="#A"><font size="-2">A</font></a> 
    ++<a href="#B"><font size="-2">B</font></a> 
    ++<a href="#C"><font size="-2">C</font></a> 
    ++<a href="#D"><font size="-2">D</font></a> 
    ++<a href="#G"><font size="-2">G</font></a> 
    ++<a href="#M"><font size="-2">M</font></a> 
    ++<a href="#N"><font size="-2">N</font></a> 
    ++<a href="#P"><font size="-2">P</font></a> 
    ++<a href="#R"><font size="-2">R</font></a> 
    ++<a href="#S"><font size="-2">S</font></a> 
    ++<a href="#T"><font size="-2">T</font></a> 
    ++ <a href="#topheader"><font size="-2">TOP</font></a>
    ++<p><div style="line-height:1.5em;color:black">
    ++<A HREF="pkg_android.support.v7.widget.html#LinearLayoutCompat" class="hiddenlink" target="rightframe"><b>LinearLayoutCompat</b></A><br>
    ++<A HREF="pkg_android.support.v7.widget.html#LinearLayoutCompat.LayoutParams" class="hiddenlink" target="rightframe"><b>LinearLayoutCompat.LayoutParams</b></A><br>
    ++<A HREF="pkg_android.support.v7.widget.html#LinearSnapHelper" class="hiddenlink" target="rightframe"><b>LinearSnapHelper</b></A><br>
    ++<A HREF="pkg_android.support.v7.widget.html#ListPopupWindow" class="hiddenlink" target="rightframe"><b>ListPopupWindow</b></A><br>
    ++<A HREF="pkg_android.support.v7.util.html#ListUpdateCallback" class="hiddenlink" target="rightframe"><b><i>ListUpdateCallback</i></b></A><br>
    ++<A NAME="M"></A>
    ++<br><font size="+2">M</font>&nbsp;
    ++<a href="#A"><font size="-2">A</font></a> 
    ++<a href="#B"><font size="-2">B</font></a> 
    ++<a href="#C"><font size="-2">C</font></a> 
    ++<a href="#D"><font size="-2">D</font></a> 
    ++<a href="#G"><font size="-2">G</font></a> 
    ++<a href="#L"><font size="-2">L</font></a> 
    ++<a href="#N"><font size="-2">N</font></a> 
    ++<a href="#P"><font size="-2">P</font></a> 
    ++<a href="#R"><font size="-2">R</font></a> 
    ++<a href="#S"><font size="-2">S</font></a> 
    ++<a href="#T"><font size="-2">T</font></a> 
    ++ <a href="#topheader"><font size="-2">TOP</font></a>
    ++<p><div style="line-height:1.5em;color:black">
    ++<A HREF="pkg_android.support.v7.preference.html#MultiSelectListPreferenceDialogFragmentCompat" class="hiddenlink" target="rightframe"><b>MultiSelectListPreferenceDialogFragmentCompat</b></A><br>
    ++<A NAME="N"></A>
    ++<br><font size="+2">N</font>&nbsp;
    ++<a href="#A"><font size="-2">A</font></a> 
    ++<a href="#B"><font size="-2">B</font></a> 
    ++<a href="#C"><font size="-2">C</font></a> 
    ++<a href="#D"><font size="-2">D</font></a> 
    ++<a href="#G"><font size="-2">G</font></a> 
    ++<a href="#L"><font size="-2">L</font></a> 
    ++<a href="#M"><font size="-2">M</font></a> 
    ++<a href="#P"><font size="-2">P</font></a> 
    ++<a href="#R"><font size="-2">R</font></a> 
    ++<a href="#S"><font size="-2">S</font></a> 
    ++<a href="#T"><font size="-2">T</font></a> 
    ++ <a href="#topheader"><font size="-2">TOP</font></a>
    ++<p><div style="line-height:1.5em;color:black">
    ++<A HREF="pkg_android.support.v7.app.html#NotificationCompat" class="hiddenlink" target="rightframe"><b>NotificationCompat</b></A><br>
    ++<A HREF="pkg_android.support.v7.app.html#NotificationCompat.Builder" class="hiddenlink" target="rightframe"><b>NotificationCompat.Builder</b></A><br>
    ++<A HREF="pkg_android.support.v7.app.html#NotificationCompat.MediaStyle" class="hiddenlink" target="rightframe"><b>NotificationCompat.MediaStyle</b></A><br>
    ++<A NAME="P"></A>
    ++<br><font size="+2">P</font>&nbsp;
    ++<a href="#A"><font size="-2">A</font></a> 
    ++<a href="#B"><font size="-2">B</font></a> 
    ++<a href="#C"><font size="-2">C</font></a> 
    ++<a href="#D"><font size="-2">D</font></a> 
    ++<a href="#G"><font size="-2">G</font></a> 
    ++<a href="#L"><font size="-2">L</font></a> 
    ++<a href="#M"><font size="-2">M</font></a> 
    ++<a href="#N"><font size="-2">N</font></a> 
    ++<a href="#R"><font size="-2">R</font></a> 
    ++<a href="#S"><font size="-2">S</font></a> 
    ++<a href="#T"><font size="-2">T</font></a> 
    ++ <a href="#topheader"><font size="-2">TOP</font></a>
    ++<p><div style="line-height:1.5em;color:black">
    ++<A HREF="pkg_android.support.v4.util.html#PatternsCompat" class="hiddenlink" target="rightframe"><b>PatternsCompat</b></A><br>
    ++<A HREF="pkg_android.support.v7.widget.html#PopupMenu" class="hiddenlink" target="rightframe"><b>PopupMenu</b></A><br>
    ++<A HREF="pkg_android.support.v7.widget.html#PopupMenu.OnDismissListener" class="hiddenlink" target="rightframe"><b><i>PopupMenu.OnDismissListener</i></b></A><br>
    ++<A HREF="pkg_android.support.v7.widget.html#PopupMenu.OnMenuItemClickListener" class="hiddenlink" target="rightframe"><b><i>PopupMenu.OnMenuItemClickListener</i></b></A><br>
    ++<A NAME="R"></A>
    ++<br><font size="+2">R</font>&nbsp;
    ++<a href="#A"><font size="-2">A</font></a> 
    ++<a href="#B"><font size="-2">B</font></a> 
    ++<a href="#C"><font size="-2">C</font></a> 
    ++<a href="#D"><font size="-2">D</font></a> 
    ++<a href="#G"><font size="-2">G</font></a> 
    ++<a href="#L"><font size="-2">L</font></a> 
    ++<a href="#M"><font size="-2">M</font></a> 
    ++<a href="#N"><font size="-2">N</font></a> 
    ++<a href="#P"><font size="-2">P</font></a> 
    ++<a href="#S"><font size="-2">S</font></a> 
    ++<a href="#T"><font size="-2">T</font></a> 
    ++ <a href="#topheader"><font size="-2">TOP</font></a>
    ++<p><div style="line-height:1.5em;color:black">
    ++<A HREF="pkg_android.support.v7.widget.html#RecyclerView.OnFlingListener" class="hiddenlink" target="rightframe"><b>RecyclerView.OnFlingListener</b></A><br>
    ++<A HREF="pkg_android.support.v7.widget.html#RecyclerView.SmoothScroller.ScrollVectorProvider" class="hiddenlink" target="rightframe"><b><i>RecyclerView.SmoothScroller.ScrollVectorProvider</i></b></A><br>
    ++<A NAME="S"></A>
    ++<br><font size="+2">S</font>&nbsp;
    ++<a href="#A"><font size="-2">A</font></a> 
    ++<a href="#B"><font size="-2">B</font></a> 
    ++<a href="#C"><font size="-2">C</font></a> 
    ++<a href="#D"><font size="-2">D</font></a> 
    ++<a href="#G"><font size="-2">G</font></a> 
    ++<a href="#L"><font size="-2">L</font></a> 
    ++<a href="#M"><font size="-2">M</font></a> 
    ++<a href="#N"><font size="-2">N</font></a> 
    ++<a href="#P"><font size="-2">P</font></a> 
    ++<a href="#R"><font size="-2">R</font></a> 
    ++<a href="#T"><font size="-2">T</font></a> 
    ++ <a href="#topheader"><font size="-2">TOP</font></a>
    ++<p><div style="line-height:1.5em;color:black">
    ++<A HREF="pkg_android.support.v7.widget.html#SearchView" class="hiddenlink" target="rightframe"><b>SearchView</b></A><br>
    ++<A HREF="pkg_android.support.v7.widget.html#SearchView.OnCloseListener" class="hiddenlink" target="rightframe"><b><i>SearchView.OnCloseListener</i></b></A><br>
    ++<A HREF="pkg_android.support.v7.widget.html#SearchView.OnQueryTextListener" class="hiddenlink" target="rightframe"><b><i>SearchView.OnQueryTextListener</i></b></A><br>
    ++<A HREF="pkg_android.support.v7.widget.html#SearchView.OnSuggestionListener" class="hiddenlink" target="rightframe"><b><i>SearchView.OnSuggestionListener</i></b></A><br>
    ++<A HREF="pkg_android.support.v4.widget.html#SearchViewCompat.OnCloseListener" class="hiddenlink" target="rightframe"><b><i>SearchViewCompat.OnCloseListener</i></b></A><br>
    ++<A HREF="pkg_android.support.v4.widget.html#SearchViewCompat.OnQueryTextListener" class="hiddenlink" target="rightframe"><b><i>SearchViewCompat.OnQueryTextListener</i></b></A><br>
    ++<A HREF="pkg_android.support.v7.widget.html#ShareActionProvider" class="hiddenlink" target="rightframe"><b>ShareActionProvider</b></A><br>
    ++<A HREF="pkg_android.support.v7.widget.html#ShareActionProvider.OnShareTargetSelectedListener" class="hiddenlink" target="rightframe"><b><i>ShareActionProvider.OnShareTargetSelectedListener</i></b></A><br>
    ++<A HREF="pkg_android.support.v4.app.html#SharedElementCallback.OnSharedElementsReadyListener" class="hiddenlink" target="rightframe"><b><i>SharedElementCallback.OnSharedElementsReadyListener</i></b></A><br>
    ++<A HREF="pkg_android.support.v7.widget.html#SnapHelper" class="hiddenlink" target="rightframe"><b>SnapHelper</b></A><br>
    ++<A HREF="pkg_android.support.v7.widget.html#Space" class="hiddenlink" target="rightframe"><b>Space</b></A><br>
    ++<A HREF="pkg_android.support.v4.widget.html#SwipeRefreshLayout.OnChildScrollUpCallback" class="hiddenlink" target="rightframe"><b><i>SwipeRefreshLayout.OnChildScrollUpCallback</i></b></A><br>
    ++<A HREF="pkg_android.support.v7.widget.html#SwitchCompat" class="hiddenlink" target="rightframe"><b>SwitchCompat</b></A><br>
    ++<A NAME="T"></A>
    ++<br><font size="+2">T</font>&nbsp;
    ++<a href="#A"><font size="-2">A</font></a> 
    ++<a href="#B"><font size="-2">B</font></a> 
    ++<a href="#C"><font size="-2">C</font></a> 
    ++<a href="#D"><font size="-2">D</font></a> 
    ++<a href="#G"><font size="-2">G</font></a> 
    ++<a href="#L"><font size="-2">L</font></a> 
    ++<a href="#M"><font size="-2">M</font></a> 
    ++<a href="#N"><font size="-2">N</font></a> 
    ++<a href="#P"><font size="-2">P</font></a> 
    ++<a href="#R"><font size="-2">R</font></a> 
    ++<a href="#S"><font size="-2">S</font></a> 
    ++ <a href="#topheader"><font size="-2">TOP</font></a>
    ++<p><div style="line-height:1.5em;color:black">
    ++<A HREF="pkg_android.support.v7.widget.html#ThemedSpinnerAdapter" class="hiddenlink" target="rightframe"><b><i>ThemedSpinnerAdapter</i></b></A><br>
    ++<A HREF="pkg_android.support.v7.widget.html#ThemedSpinnerAdapter.Helper" class="hiddenlink" target="rightframe"><b>ThemedSpinnerAdapter.Helper</b></A><br>
    ++<A HREF="pkg_android.support.v7.widget.html#Toolbar" class="hiddenlink" target="rightframe"><b>Toolbar</b></A><br>
    ++<A HREF="pkg_android.support.v7.widget.html#Toolbar.LayoutParams" class="hiddenlink" target="rightframe"><b>Toolbar.LayoutParams</b></A><br>
    ++<A HREF="pkg_android.support.v7.widget.html#Toolbar.OnMenuItemClickListener" class="hiddenlink" target="rightframe"><b><i>Toolbar.OnMenuItemClickListener</i></b></A><br>
    ++<A HREF="pkg_android.support.v7.widget.html#Toolbar.SavedState" class="hiddenlink" target="rightframe"><b>Toolbar.SavedState</b></A><br>
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    ++</script>
    ++<script type="text/javascript">
    ++  try {
    ++    var pageTracker = _gat._getTracker("UA-5831155-1");
    ++    pageTracker._setAllowAnchor(true);
    ++    pageTracker._initData();
    ++    pageTracker._trackPageview();
    ++  } catch(e) {}
    ++</script>
    ++</BODY>
    ++</HTML>
    +diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/classes_index_all.html b/docs/html/sdk/support_api_diff/24.2.0/changes/classes_index_all.html
    +new file mode 100644
    +index 0000000..3e77bf2
    +--- /dev/null
    ++++ b/docs/html/sdk/support_api_diff/24.2.0/changes/classes_index_all.html
    +@@ -0,0 +1,528 @@
    ++<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
    ++<HTML style="overflow:auto;">
    ++<HEAD>
    ++<meta name="generator" content="JDiff v1.1.0">
    ++<!-- Generated by the JDiff Javadoc doclet -->
    ++<!-- (http://www.jdiff.org) -->
    ++<meta name="description" content="JDiff is a Javadoc doclet which generates an HTML report of all the packages, classes, constructors, methods, and fields which have been removed, added or changed in any way, including their documentation, when two APIs are compared.">
    ++<meta name="keywords" content="diff, jdiff, javadiff, java diff, java difference, API difference, difference between two APIs, API diff, Javadoc, doclet">
    ++<TITLE>
    ++Class Differences Index
    ++</TITLE>
    ++<link href="../../../../assets/android-developer-docs.css" rel="stylesheet" type="text/css" />
    ++<link href="../stylesheet-jdiff.css" rel="stylesheet" type="text/css" />
    ++<noscript>
    ++<style type="text/css">
    ++body{overflow:auto;}
    ++#body-content{position:relative; top:0;}
    ++#doc-content{overflow:visible;border-left:3px solid #666;}
    ++#side-nav{padding:0;}
    ++#side-nav .toggle-list ul {display:block;}
    ++#resize-packages-nav{border-bottom:3px solid #666;}
    ++</style>
    ++</noscript>
    ++<style type="text/css">
    ++</style>
    ++</HEAD>
    ++<BODY class="gc-documentation" style="padding:12px;">
    ++<a NAME="topheader"></a>
    ++<table summary="Index for Classes" width="100%" class="jdiffIndex" border="0" cellspacing="0" cellpadding="0" style="padding-bottom:0;margin-bottom:0;">
    ++  <tr>
    ++  <th class="indexHeader">
    ++    Filter the Index:
    ++  </th>
    ++  </tr>
    ++  <tr>
    ++  <td class="indexText" style="line-height:1.3em;padding-left:2em;">
    ++<b>Classes</b>
    ++  <br>
    ++<font color="#999999">Removals</font>
    ++  <br>
    ++<A HREF="classes_index_additions.html"xclass="hiddenlink">Additions</A>
    ++  <br>
    ++<A HREF="classes_index_changes.html"xclass="hiddenlink">Changes</A>
    ++  </td>
    ++  </tr>
    ++</table>
    ++<div id="indexTableCaption" style="background-color:#eee;padding:0 4px 0 4px;font-size:11px;margin-bottom:1em;">
    ++Listed as: <span style="color:#069"><strong>Added</strong></span>,  <span style="color:#069"><strike>Removed</strike></span>,  <span style="color:#069">Changed</span></font>
    ++</div>
    ++<A NAME="A"></A>
    ++<br><font size="+2">A</font>&nbsp;
    ++<a href="#B"><font size="-2">B</font></a> 
    ++<a href="#C"><font size="-2">C</font></a> 
    ++<a href="#D"><font size="-2">D</font></a> 
    ++<a href="#F"><font size="-2">F</font></a> 
    ++<a href="#G"><font size="-2">G</font></a> 
    ++<a href="#K"><font size="-2">K</font></a> 
    ++<a href="#L"><font size="-2">L</font></a> 
    ++<a href="#M"><font size="-2">M</font></a> 
    ++<a href="#N"><font size="-2">N</font></a> 
    ++<a href="#O"><font size="-2">O</font></a> 
    ++<a href="#P"><font size="-2">P</font></a> 
    ++<a href="#R"><font size="-2">R</font></a> 
    ++<a href="#S"><font size="-2">S</font></a> 
    ++<a href="#T"><font size="-2">T</font></a> 
    ++<a href="#V"><font size="-2">V</font></a> 
    ++<a href="#W"><font size="-2">W</font></a> 
    ++ <a href="#topheader"><font size="-2">TOP</font></a>
    ++<p><div style="line-height:1.5em;color:black">
    ++<A HREF="android.support.v17.leanback.widget.AbstractMediaItemPresenter.html" class="hiddenlink" target="rightframe">AbstractMediaItemPresenter</A><br>
    ++<A HREF="android.support.v17.leanback.widget.AbstractMediaItemPresenter.ViewHolder.html" class="hiddenlink" target="rightframe">AbstractMediaItemPresenter.ViewHolder</A><br>
    ++<A HREF="android.support.v4.view.accessibility.AccessibilityEventCompat.html" class="hiddenlink" target="rightframe">AccessibilityEventCompat</A><br>
    ++<A HREF="android.support.v4.view.accessibility.AccessibilityManagerCompat.html" class="hiddenlink" target="rightframe">AccessibilityManagerCompat</A><br>
    ++<A HREF="pkg_android.support.v4.view.accessibility.html#AccessibilityManagerCompat.AccessibilityStateChangeListener" class="hiddenlink" target="rightframe"><b><i>AccessibilityManagerCompat.AccessibilityStateChangeListener</i></b></A><br>
    ++<A HREF="android.support.v4.view.accessibility.AccessibilityManagerCompat.AccessibilityStateChangeListenerCompat.html" class="hiddenlink" target="rightframe">AccessibilityManagerCompat.AccessibilityStateChangeListenerCompat</A><br>
    ++<A HREF="pkg_android.support.v4.view.accessibility.html#AccessibilityManagerCompat.TouchExplorationStateChangeListener" class="hiddenlink" target="rightframe"><b><i>AccessibilityManagerCompat.TouchExplorationStateChangeListener</i></b></A><br>
    ++<A HREF="android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.html" class="hiddenlink" target="rightframe">AccessibilityNodeInfoCompat</A><br>
    ++<A HREF="android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat.html" class="hiddenlink" target="rightframe">AccessibilityNodeInfoCompat.AccessibilityActionCompat</A><br>
    ++<A HREF="android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.CollectionInfoCompat.html" class="hiddenlink" target="rightframe">AccessibilityNodeInfoCompat.CollectionInfoCompat</A><br>
    ++<A HREF="android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.CollectionItemInfoCompat.html" class="hiddenlink" target="rightframe">AccessibilityNodeInfoCompat.CollectionItemInfoCompat</A><br>
    ++<A HREF="android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.RangeInfoCompat.html" class="hiddenlink" target="rightframe">AccessibilityNodeInfoCompat.RangeInfoCompat</A><br>
    ++<A HREF="android.support.v4.view.accessibility.AccessibilityNodeProviderCompat.html" class="hiddenlink" target="rightframe">AccessibilityNodeProviderCompat</A><br>
    ++<A HREF="android.support.v4.accessibilityservice.AccessibilityServiceInfoCompat.html" class="hiddenlink" target="rightframe">AccessibilityServiceInfoCompat</A><br>
    ++<A HREF="android.support.v4.view.accessibility.AccessibilityWindowInfoCompat.html" class="hiddenlink" target="rightframe">AccessibilityWindowInfoCompat</A><br>
    ++<A HREF="pkg_android.support.v7.app.html#ActionBarActivity" class="hiddenlink" target="rightframe"><b>ActionBarActivity</b></A><br>
    ++<A HREF="android.support.v7.app.ActionBarDrawerToggle.html" class="hiddenlink" target="rightframe">ActionBarDrawerToggle</A><br>
    ++<A HREF="pkg_android.support.v7.widget.html#ActionMenuView" class="hiddenlink" target="rightframe"><b>ActionMenuView</b></A><br>
    ++<A HREF="pkg_android.support.v7.widget.html#ActionMenuView.LayoutParams" class="hiddenlink" target="rightframe"><b>ActionMenuView.LayoutParams</b></A><br>
    ++<A HREF="pkg_android.support.v7.widget.html#ActionMenuView.OnMenuItemClickListener" class="hiddenlink" target="rightframe"><b><i>ActionMenuView.OnMenuItemClickListener</i></b></A><br>
    ++<A HREF="android.support.v4.app.ActivityCompat.html" class="hiddenlink" target="rightframe">ActivityCompat</A><br>
    ++<A HREF="android.support.v4.app.ActivityOptionsCompat.html" class="hiddenlink" target="rightframe">ActivityOptionsCompat</A><br>
    ++<A HREF="android.support.design.widget.AppBarLayout.ScrollingViewBehavior.html" class="hiddenlink" target="rightframe">AppBarLayout.ScrollingViewBehavior</A><br>
    ++<A HREF="pkg_android.support.v7.app.html#AppCompatActivity" class="hiddenlink" target="rightframe"><b>AppCompatActivity</b></A><br>
    ++<A HREF="pkg_android.support.v7.widget.html#AppCompatAutoCompleteTextView" class="hiddenlink" target="rightframe"><b>AppCompatAutoCompleteTextView</b></A><br>
    ++<A HREF="pkg_android.support.v7.widget.html#AppCompatButton" class="hiddenlink" target="rightframe"><b>AppCompatButton</b></A><br>
    ++<A HREF="pkg_android.support.v7.widget.html#AppCompatCheckBox" class="hiddenlink" target="rightframe"><b>AppCompatCheckBox</b></A><br>
    ++<A HREF="pkg_android.support.v7.widget.html#AppCompatCheckedTextView" class="hiddenlink" target="rightframe"><b>AppCompatCheckedTextView</b></A><br>
    ++<A HREF="android.support.v7.app.AppCompatDelegate.html" class="hiddenlink" target="rightframe">AppCompatDelegate</A><br>
    ++<A HREF="pkg_android.support.v7.app.html#AppCompatDialogFragment" class="hiddenlink" target="rightframe"><b>AppCompatDialogFragment</b></A><br>
    ++<A HREF="pkg_android.support.v7.widget.html#AppCompatEditText" class="hiddenlink" target="rightframe"><b>AppCompatEditText</b></A><br>
    ++<A HREF="pkg_android.support.v7.widget.html#AppCompatImageButton" class="hiddenlink" target="rightframe"><b>AppCompatImageButton</b></A><br>
    ++<A HREF="pkg_android.support.v7.widget.html#AppCompatImageView" class="hiddenlink" target="rightframe"><b>AppCompatImageView</b></A><br>
    ++<A HREF="pkg_android.support.v7.widget.html#AppCompatMultiAutoCompleteTextView" class="hiddenlink" target="rightframe"><b>AppCompatMultiAutoCompleteTextView</b></A><br>
    ++<A HREF="pkg_android.support.v7.widget.html#AppCompatRadioButton" class="hiddenlink" target="rightframe"><b>AppCompatRadioButton</b></A><br>
    ++<A HREF="pkg_android.support.v7.widget.html#AppCompatRatingBar" class="hiddenlink" target="rightframe"><b>AppCompatRatingBar</b></A><br>
    ++<A HREF="android.support.v7.content.res.AppCompatResources.html" class="hiddenlink" target="rightframe">AppCompatResources</A><br>
    ++<A HREF="pkg_android.support.v7.widget.html#AppCompatSeekBar" class="hiddenlink" target="rightframe"><b>AppCompatSeekBar</b></A><br>
    ++<A HREF="pkg_android.support.v7.widget.html#AppCompatSpinner" class="hiddenlink" target="rightframe"><b>AppCompatSpinner</b></A><br>
    ++<A HREF="pkg_android.support.v7.widget.html#AppCompatTextView" class="hiddenlink" target="rightframe"><b>AppCompatTextView</b></A><br>
    ++<A NAME="B"></A>
    ++<br><font size="+2">B</font>&nbsp;
    ++<a href="#A"><font size="-2">A</font></a> 
    ++<a href="#C"><font size="-2">C</font></a> 
    ++<a href="#D"><font size="-2">D</font></a> 
    ++<a href="#F"><font size="-2">F</font></a> 
    ++<a href="#G"><font size="-2">G</font></a> 
    ++<a href="#K"><font size="-2">K</font></a> 
    ++<a href="#L"><font size="-2">L</font></a> 
    ++<a href="#M"><font size="-2">M</font></a> 
    ++<a href="#N"><font size="-2">N</font></a> 
    ++<a href="#O"><font size="-2">O</font></a> 
    ++<a href="#P"><font size="-2">P</font></a> 
    ++<a href="#R"><font size="-2">R</font></a> 
    ++<a href="#S"><font size="-2">S</font></a> 
    ++<a href="#T"><font size="-2">T</font></a> 
    ++<a href="#V"><font size="-2">V</font></a> 
    ++<a href="#W"><font size="-2">W</font></a> 
    ++ <a href="#topheader"><font size="-2">TOP</font></a>
    ++<p><div style="line-height:1.5em;color:black">
    ++<A HREF="pkg_android.support.v7.util.html#BatchingListUpdateCallback" class="hiddenlink" target="rightframe"><b>BatchingListUpdateCallback</b></A><br>
    ++<A HREF="android.support.design.widget.BottomSheetBehavior.html" class="hiddenlink" target="rightframe">BottomSheetBehavior</A><br>
    ++<A HREF="android.support.v4.os.BuildCompat.html" class="hiddenlink" target="rightframe">BuildCompat</A><br>
    ++<A NAME="C"></A>
    ++<br><font size="+2">C</font>&nbsp;
    ++<a href="#A"><font size="-2">A</font></a> 
    ++<a href="#B"><font size="-2">B</font></a> 
    ++<a href="#D"><font size="-2">D</font></a> 
    ++<a href="#F"><font size="-2">F</font></a> 
    ++<a href="#G"><font size="-2">G</font></a> 
    ++<a href="#K"><font size="-2">K</font></a> 
    ++<a href="#L"><font size="-2">L</font></a> 
    ++<a href="#M"><font size="-2">M</font></a> 
    ++<a href="#N"><font size="-2">N</font></a> 
    ++<a href="#O"><font size="-2">O</font></a> 
    ++<a href="#P"><font size="-2">P</font></a> 
    ++<a href="#R"><font size="-2">R</font></a> 
    ++<a href="#S"><font size="-2">S</font></a> 
    ++<a href="#T"><font size="-2">T</font></a> 
    ++<a href="#V"><font size="-2">V</font></a> 
    ++<a href="#W"><font size="-2">W</font></a> 
    ++ <a href="#topheader"><font size="-2">TOP</font></a>
    ++<p><div style="line-height:1.5em;color:black">
    ++<A HREF="pkg_android.support.v7.widget.html#CardView" class="hiddenlink" target="rightframe"><b>CardView</b></A><br>
    ++<A HREF="android.support.design.widget.CollapsingToolbarLayout.html" class="hiddenlink" target="rightframe">CollapsingToolbarLayout</A><br>
    ++<A HREF="android.support.v4.content.ContextCompat.html" class="hiddenlink" target="rightframe">ContextCompat</A><br>
    ++<A HREF="android.support.design.widget.CoordinatorLayout.html" class="hiddenlink" target="rightframe">CoordinatorLayout</A><br>
    ++<A HREF="android.support.design.widget.CoordinatorLayout.Behavior.html" class="hiddenlink" target="rightframe">CoordinatorLayout.Behavior</A><br>
    ++<A HREF="android.support.design.widget.CoordinatorLayout.LayoutParams.html" class="hiddenlink" target="rightframe">CoordinatorLayout.LayoutParams</A><br>
    ++<A HREF="android.support.customtabs.CustomTabsIntent.html" class="hiddenlink" target="rightframe">CustomTabsIntent</A><br>
    ++<A HREF="android.support.customtabs.CustomTabsIntent.Builder.html" class="hiddenlink" target="rightframe">CustomTabsIntent.Builder</A><br>
    ++<A HREF="android.support.customtabs.CustomTabsSession.html" class="hiddenlink" target="rightframe">CustomTabsSession</A><br>
    ++<A NAME="D"></A>
    ++<br><font size="+2">D</font>&nbsp;
    ++<a href="#A"><font size="-2">A</font></a> 
    ++<a href="#B"><font size="-2">B</font></a> 
    ++<a href="#C"><font size="-2">C</font></a> 
    ++<a href="#F"><font size="-2">F</font></a> 
    ++<a href="#G"><font size="-2">G</font></a> 
    ++<a href="#K"><font size="-2">K</font></a> 
    ++<a href="#L"><font size="-2">L</font></a> 
    ++<a href="#M"><font size="-2">M</font></a> 
    ++<a href="#N"><font size="-2">N</font></a> 
    ++<a href="#O"><font size="-2">O</font></a> 
    ++<a href="#P"><font size="-2">P</font></a> 
    ++<a href="#R"><font size="-2">R</font></a> 
    ++<a href="#S"><font size="-2">S</font></a> 
    ++<a href="#T"><font size="-2">T</font></a> 
    ++<a href="#V"><font size="-2">V</font></a> 
    ++<a href="#W"><font size="-2">W</font></a> 
    ++ <a href="#topheader"><font size="-2">TOP</font></a>
    ++<p><div style="line-height:1.5em;color:black">
    ++<A HREF="pkg_android.support.v7.util.html#DiffUtil" class="hiddenlink" target="rightframe"><b>DiffUtil</b></A><br>
    ++<A HREF="pkg_android.support.v7.util.html#DiffUtil.Callback" class="hiddenlink" target="rightframe"><b>DiffUtil.Callback</b></A><br>
    ++<A HREF="pkg_android.support.v7.util.html#DiffUtil.DiffResult" class="hiddenlink" target="rightframe"><b>DiffUtil.DiffResult</b></A><br>
    ++<A HREF="android.support.v4.graphics.drawable.DrawableCompat.html" class="hiddenlink" target="rightframe">DrawableCompat</A><br>
    ++<A NAME="F"></A>
    ++<br><font size="+2">F</font>&nbsp;
    ++<a href="#A"><font size="-2">A</font></a> 
    ++<a href="#B"><font size="-2">B</font></a> 
    ++<a href="#C"><font size="-2">C</font></a> 
    ++<a href="#D"><font size="-2">D</font></a> 
    ++<a href="#G"><font size="-2">G</font></a> 
    ++<a href="#K"><font size="-2">K</font></a> 
    ++<a href="#L"><font size="-2">L</font></a> 
    ++<a href="#M"><font size="-2">M</font></a> 
    ++<a href="#N"><font size="-2">N</font></a> 
    ++<a href="#O"><font size="-2">O</font></a> 
    ++<a href="#P"><font size="-2">P</font></a> 
    ++<a href="#R"><font size="-2">R</font></a> 
    ++<a href="#S"><font size="-2">S</font></a> 
    ++<a href="#T"><font size="-2">T</font></a> 
    ++<a href="#V"><font size="-2">V</font></a> 
    ++<a href="#W"><font size="-2">W</font></a> 
    ++ <a href="#topheader"><font size="-2">TOP</font></a>
    ++<p><div style="line-height:1.5em;color:black">
    ++<A HREF="android.support.design.widget.FloatingActionButton.Behavior.html" class="hiddenlink" target="rightframe">FloatingActionButton.Behavior</A><br>
    ++<A HREF="android.support.v4.app.FragmentController.html" class="hiddenlink" target="rightframe">FragmentController</A><br>
    ++<A NAME="G"></A>
    ++<br><font size="+2">G</font>&nbsp;
    ++<a href="#A"><font size="-2">A</font></a> 
    ++<a href="#B"><font size="-2">B</font></a> 
    ++<a href="#C"><font size="-2">C</font></a> 
    ++<a href="#D"><font size="-2">D</font></a> 
    ++<a href="#F"><font size="-2">F</font></a> 
    ++<a href="#K"><font size="-2">K</font></a> 
    ++<a href="#L"><font size="-2">L</font></a> 
    ++<a href="#M"><font size="-2">M</font></a> 
    ++<a href="#N"><font size="-2">N</font></a> 
    ++<a href="#O"><font size="-2">O</font></a> 
    ++<a href="#P"><font size="-2">P</font></a> 
    ++<a href="#R"><font size="-2">R</font></a> 
    ++<a href="#S"><font size="-2">S</font></a> 
    ++<a href="#T"><font size="-2">T</font></a> 
    ++<a href="#V"><font size="-2">V</font></a> 
    ++<a href="#W"><font size="-2">W</font></a> 
    ++ <a href="#topheader"><font size="-2">TOP</font></a>
    ++<p><div style="line-height:1.5em;color:black">
    ++<A HREF="pkg_android.support.v7.widget.html#GridLayout" class="hiddenlink" target="rightframe"><b>GridLayout</b></A><br>
    ++<A HREF="pkg_android.support.v7.widget.html#GridLayout.Alignment" class="hiddenlink" target="rightframe"><b>GridLayout.Alignment</b></A><br>
    ++<A HREF="pkg_android.support.v7.widget.html#GridLayout.LayoutParams" class="hiddenlink" target="rightframe"><b>GridLayout.LayoutParams</b></A><br>
    ++<A HREF="pkg_android.support.v7.widget.html#GridLayout.Spec" class="hiddenlink" target="rightframe"><b>GridLayout.Spec</b></A><br>
    ++<A NAME="K"></A>
    ++<br><font size="+2">K</font>&nbsp;
    ++<a href="#A"><font size="-2">A</font></a> 
    ++<a href="#B"><font size="-2">B</font></a> 
    ++<a href="#C"><font size="-2">C</font></a> 
    ++<a href="#D"><font size="-2">D</font></a> 
    ++<a href="#F"><font size="-2">F</font></a> 
    ++<a href="#G"><font size="-2">G</font></a> 
    ++<a href="#L"><font size="-2">L</font></a> 
    ++<a href="#M"><font size="-2">M</font></a> 
    ++<a href="#N"><font size="-2">N</font></a> 
    ++<a href="#O"><font size="-2">O</font></a> 
    ++<a href="#P"><font size="-2">P</font></a> 
    ++<a href="#R"><font size="-2">R</font></a> 
    ++<a href="#S"><font size="-2">S</font></a> 
    ++<a href="#T"><font size="-2">T</font></a> 
    ++<a href="#V"><font size="-2">V</font></a> 
    ++<a href="#W"><font size="-2">W</font></a> 
    ++ <a href="#topheader"><font size="-2">TOP</font></a>
    ++<p><div style="line-height:1.5em;color:black">
    ++<A HREF="android.support.v4.view.KeyEventCompat.html" class="hiddenlink" target="rightframe">KeyEventCompat</A><br>
    ++<A NAME="L"></A>
    ++<br><font size="+2">L</font>&nbsp;
    ++<a href="#A"><font size="-2">A</font></a> 
    ++<a href="#B"><font size="-2">B</font></a> 
    ++<a href="#C"><font size="-2">C</font></a> 
    ++<a href="#D"><font size="-2">D</font></a> 
    ++<a href="#F"><font size="-2">F</font></a> 
    ++<a href="#G"><font size="-2">G</font></a> 
    ++<a href="#K"><font size="-2">K</font></a> 
    ++<a href="#M"><font size="-2">M</font></a> 
    ++<a href="#N"><font size="-2">N</font></a> 
    ++<a href="#O"><font size="-2">O</font></a> 
    ++<a href="#P"><font size="-2">P</font></a> 
    ++<a href="#R"><font size="-2">R</font></a> 
    ++<a href="#S"><font size="-2">S</font></a> 
    ++<a href="#T"><font size="-2">T</font></a> 
    ++<a href="#V"><font size="-2">V</font></a> 
    ++<a href="#W"><font size="-2">W</font></a> 
    ++ <a href="#topheader"><font size="-2">TOP</font></a>
    ++<p><div style="line-height:1.5em;color:black">
    ++<A HREF="android.support.v17.preference.LeanbackSettingsFragment.html" class="hiddenlink" target="rightframe">LeanbackSettingsFragment</A><br>
    ++<A HREF="pkg_android.support.v7.widget.html#LinearLayoutCompat" class="hiddenlink" target="rightframe"><b>LinearLayoutCompat</b></A><br>
    ++<A HREF="pkg_android.support.v7.widget.html#LinearLayoutCompat.LayoutParams" class="hiddenlink" target="rightframe"><b>LinearLayoutCompat.LayoutParams</b></A><br>
    ++<A HREF="android.support.v7.widget.LinearLayoutManager.html" class="hiddenlink" target="rightframe">LinearLayoutManager</A><br>
    ++<A HREF="android.support.v7.widget.LinearSmoothScroller.html" class="hiddenlink" target="rightframe">LinearSmoothScroller</A><br>
    ++<A HREF="pkg_android.support.v7.widget.html#LinearSnapHelper" class="hiddenlink" target="rightframe"><b>LinearSnapHelper</b></A><br>
    ++<A HREF="pkg_android.support.v7.widget.html#ListPopupWindow" class="hiddenlink" target="rightframe"><b>ListPopupWindow</b></A><br>
    ++<A HREF="pkg_android.support.v7.util.html#ListUpdateCallback" class="hiddenlink" target="rightframe"><b><i>ListUpdateCallback</i></b></A><br>
    ++<A NAME="M"></A>
    ++<br><font size="+2">M</font>&nbsp;
    ++<a href="#A"><font size="-2">A</font></a> 
    ++<a href="#B"><font size="-2">B</font></a> 
    ++<a href="#C"><font size="-2">C</font></a> 
    ++<a href="#D"><font size="-2">D</font></a> 
    ++<a href="#F"><font size="-2">F</font></a> 
    ++<a href="#G"><font size="-2">G</font></a> 
    ++<a href="#K"><font size="-2">K</font></a> 
    ++<a href="#L"><font size="-2">L</font></a> 
    ++<a href="#N"><font size="-2">N</font></a> 
    ++<a href="#O"><font size="-2">O</font></a> 
    ++<a href="#P"><font size="-2">P</font></a> 
    ++<a href="#R"><font size="-2">R</font></a> 
    ++<a href="#S"><font size="-2">S</font></a> 
    ++<a href="#T"><font size="-2">T</font></a> 
    ++<a href="#V"><font size="-2">V</font></a> 
    ++<a href="#W"><font size="-2">W</font></a> 
    ++ <a href="#topheader"><font size="-2">TOP</font></a>
    ++<p><div style="line-height:1.5em;color:black">
    ++<A HREF="android.support.v4.media.MediaBrowserCompat.MediaItem.html" class="hiddenlink" target="rightframe">MediaBrowserCompat.MediaItem</A><br>
    ++<A HREF="android.support.v4.media.MediaBrowserServiceCompat.BrowserRoot.html" class="hiddenlink" target="rightframe">MediaBrowserServiceCompat.BrowserRoot</A><br>
    ++<A HREF="android.support.v4.media.session.MediaButtonReceiver.html" class="hiddenlink" target="rightframe">MediaButtonReceiver</A><br>
    ++<A HREF="android.support.v4.media.MediaDescriptionCompat.html" class="hiddenlink" target="rightframe">MediaDescriptionCompat</A><br>
    ++<A HREF="android.support.v4.media.MediaMetadataCompat.html" class="hiddenlink" target="rightframe">MediaMetadataCompat</A><br>
    ++<A HREF="android.support.v4.media.session.MediaSessionCompat.html" class="hiddenlink" target="rightframe">MediaSessionCompat</A><br>
    ++<A HREF="android.support.v4.media.session.MediaSessionCompat.QueueItem.html" class="hiddenlink" target="rightframe">MediaSessionCompat.QueueItem</A><br>
    ++<A HREF="android.support.v4.view.MotionEventCompat.html" class="hiddenlink" target="rightframe">MotionEventCompat</A><br>
    ++<A HREF="pkg_android.support.v7.preference.html#MultiSelectListPreferenceDialogFragmentCompat" class="hiddenlink" target="rightframe"><b>MultiSelectListPreferenceDialogFragmentCompat</b></A><br>
    ++<A NAME="N"></A>
    ++<br><font size="+2">N</font>&nbsp;
    ++<a href="#A"><font size="-2">A</font></a> 
    ++<a href="#B"><font size="-2">B</font></a> 
    ++<a href="#C"><font size="-2">C</font></a> 
    ++<a href="#D"><font size="-2">D</font></a> 
    ++<a href="#F"><font size="-2">F</font></a> 
    ++<a href="#G"><font size="-2">G</font></a> 
    ++<a href="#K"><font size="-2">K</font></a> 
    ++<a href="#L"><font size="-2">L</font></a> 
    ++<a href="#M"><font size="-2">M</font></a> 
    ++<a href="#O"><font size="-2">O</font></a> 
    ++<a href="#P"><font size="-2">P</font></a> 
    ++<a href="#R"><font size="-2">R</font></a> 
    ++<a href="#S"><font size="-2">S</font></a> 
    ++<a href="#T"><font size="-2">T</font></a> 
    ++<a href="#V"><font size="-2">V</font></a> 
    ++<a href="#W"><font size="-2">W</font></a> 
    ++ <a href="#topheader"><font size="-2">TOP</font></a>
    ++<p><div style="line-height:1.5em;color:black">
    ++<A HREF="pkg_android.support.v7.app.html#NotificationCompat" class="hiddenlink" target="rightframe"><b>NotificationCompat</b></A><br>
    ++<A HREF="pkg_android.support.v7.app.html#NotificationCompat.Builder" class="hiddenlink" target="rightframe"><b>NotificationCompat.Builder</b></A><br>
    ++<A HREF="pkg_android.support.v7.app.html#NotificationCompat.MediaStyle" class="hiddenlink" target="rightframe"><b>NotificationCompat.MediaStyle</b></A><br>
    ++<A NAME="O"></A>
    ++<br><font size="+2">O</font>&nbsp;
    ++<a href="#A"><font size="-2">A</font></a> 
    ++<a href="#B"><font size="-2">B</font></a> 
    ++<a href="#C"><font size="-2">C</font></a> 
    ++<a href="#D"><font size="-2">D</font></a> 
    ++<a href="#F"><font size="-2">F</font></a> 
    ++<a href="#G"><font size="-2">G</font></a> 
    ++<a href="#K"><font size="-2">K</font></a> 
    ++<a href="#L"><font size="-2">L</font></a> 
    ++<a href="#M"><font size="-2">M</font></a> 
    ++<a href="#N"><font size="-2">N</font></a> 
    ++<a href="#P"><font size="-2">P</font></a> 
    ++<a href="#R"><font size="-2">R</font></a> 
    ++<a href="#S"><font size="-2">S</font></a> 
    ++<a href="#T"><font size="-2">T</font></a> 
    ++<a href="#V"><font size="-2">V</font></a> 
    ++<a href="#W"><font size="-2">W</font></a> 
    ++ <a href="#topheader"><font size="-2">TOP</font></a>
    ++<p><div style="line-height:1.5em;color:black">
    ++<A HREF="android.support.v17.leanback.widget.ObjectAdapter.html" class="hiddenlink" target="rightframe">ObjectAdapter</A><br>
    ++<A NAME="P"></A>
    ++<br><font size="+2">P</font>&nbsp;
    ++<a href="#A"><font size="-2">A</font></a> 
    ++<a href="#B"><font size="-2">B</font></a> 
    ++<a href="#C"><font size="-2">C</font></a> 
    ++<a href="#D"><font size="-2">D</font></a> 
    ++<a href="#F"><font size="-2">F</font></a> 
    ++<a href="#G"><font size="-2">G</font></a> 
    ++<a href="#K"><font size="-2">K</font></a> 
    ++<a href="#L"><font size="-2">L</font></a> 
    ++<a href="#M"><font size="-2">M</font></a> 
    ++<a href="#N"><font size="-2">N</font></a> 
    ++<a href="#O"><font size="-2">O</font></a> 
    ++<a href="#R"><font size="-2">R</font></a> 
    ++<a href="#S"><font size="-2">S</font></a> 
    ++<a href="#T"><font size="-2">T</font></a> 
    ++<a href="#V"><font size="-2">V</font></a> 
    ++<a href="#W"><font size="-2">W</font></a> 
    ++ <a href="#topheader"><font size="-2">TOP</font></a>
    ++<p><div style="line-height:1.5em;color:black">
    ++<A HREF="android.support.v7.graphics.Palette.html" class="hiddenlink" target="rightframe">Palette</A><br>
    ++<A HREF="pkg_android.support.v4.util.html#PatternsCompat" class="hiddenlink" target="rightframe"><b>PatternsCompat</b></A><br>
    ++<A HREF="android.support.v4.media.session.PlaybackStateCompat.html" class="hiddenlink" target="rightframe">PlaybackStateCompat</A><br>
    ++<A HREF="pkg_android.support.v7.widget.html#PopupMenu" class="hiddenlink" target="rightframe"><b>PopupMenu</b></A><br>
    ++<A HREF="pkg_android.support.v7.widget.html#PopupMenu.OnDismissListener" class="hiddenlink" target="rightframe"><b><i>PopupMenu.OnDismissListener</i></b></A><br>
    ++<A HREF="pkg_android.support.v7.widget.html#PopupMenu.OnMenuItemClickListener" class="hiddenlink" target="rightframe"><b><i>PopupMenu.OnMenuItemClickListener</i></b></A><br>
    ++<A HREF="android.support.v14.preference.PreferenceFragment.html" class="hiddenlink" target="rightframe">PreferenceFragment</A><br>
    ++<A NAME="R"></A>
    ++<br><font size="+2">R</font>&nbsp;
    ++<a href="#A"><font size="-2">A</font></a> 
    ++<a href="#B"><font size="-2">B</font></a> 
    ++<a href="#C"><font size="-2">C</font></a> 
    ++<a href="#D"><font size="-2">D</font></a> 
    ++<a href="#F"><font size="-2">F</font></a> 
    ++<a href="#G"><font size="-2">G</font></a> 
    ++<a href="#K"><font size="-2">K</font></a> 
    ++<a href="#L"><font size="-2">L</font></a> 
    ++<a href="#M"><font size="-2">M</font></a> 
    ++<a href="#N"><font size="-2">N</font></a> 
    ++<a href="#O"><font size="-2">O</font></a> 
    ++<a href="#P"><font size="-2">P</font></a> 
    ++<a href="#S"><font size="-2">S</font></a> 
    ++<a href="#T"><font size="-2">T</font></a> 
    ++<a href="#V"><font size="-2">V</font></a> 
    ++<a href="#W"><font size="-2">W</font></a> 
    ++ <a href="#topheader"><font size="-2">TOP</font></a>
    ++<p><div style="line-height:1.5em;color:black">
    ++<A HREF="android.support.v7.widget.RecyclerView.html" class="hiddenlink" target="rightframe">RecyclerView</A><br>
    ++<A HREF="pkg_android.support.v7.widget.html#RecyclerView.OnFlingListener" class="hiddenlink" target="rightframe"><b>RecyclerView.OnFlingListener</b></A><br>
    ++<A HREF="pkg_android.support.v7.widget.html#RecyclerView.SmoothScroller.ScrollVectorProvider" class="hiddenlink" target="rightframe"><b><i>RecyclerView.SmoothScroller.ScrollVectorProvider</i></b></A><br>
    ++<A NAME="S"></A>
    ++<br><font size="+2">S</font>&nbsp;
    ++<a href="#A"><font size="-2">A</font></a> 
    ++<a href="#B"><font size="-2">B</font></a> 
    ++<a href="#C"><font size="-2">C</font></a> 
    ++<a href="#D"><font size="-2">D</font></a> 
    ++<a href="#F"><font size="-2">F</font></a> 
    ++<a href="#G"><font size="-2">G</font></a> 
    ++<a href="#K"><font size="-2">K</font></a> 
    ++<a href="#L"><font size="-2">L</font></a> 
    ++<a href="#M"><font size="-2">M</font></a> 
    ++<a href="#N"><font size="-2">N</font></a> 
    ++<a href="#O"><font size="-2">O</font></a> 
    ++<a href="#P"><font size="-2">P</font></a> 
    ++<a href="#R"><font size="-2">R</font></a> 
    ++<a href="#T"><font size="-2">T</font></a> 
    ++<a href="#V"><font size="-2">V</font></a> 
    ++<a href="#W"><font size="-2">W</font></a> 
    ++ <a href="#topheader"><font size="-2">TOP</font></a>
    ++<p><div style="line-height:1.5em;color:black">
    ++<A HREF="pkg_android.support.v7.widget.html#SearchView" class="hiddenlink" target="rightframe"><b>SearchView</b></A><br>
    ++<A HREF="pkg_android.support.v7.widget.html#SearchView.OnCloseListener" class="hiddenlink" target="rightframe"><b><i>SearchView.OnCloseListener</i></b></A><br>
    ++<A HREF="pkg_android.support.v7.widget.html#SearchView.OnQueryTextListener" class="hiddenlink" target="rightframe"><b><i>SearchView.OnQueryTextListener</i></b></A><br>
    ++<A HREF="pkg_android.support.v7.widget.html#SearchView.OnSuggestionListener" class="hiddenlink" target="rightframe"><b><i>SearchView.OnSuggestionListener</i></b></A><br>
    ++<A HREF="android.support.v4.widget.SearchViewCompat.html" class="hiddenlink" target="rightframe">SearchViewCompat</A><br>
    ++<A HREF="pkg_android.support.v4.widget.html#SearchViewCompat.OnCloseListener" class="hiddenlink" target="rightframe"><b><i>SearchViewCompat.OnCloseListener</i></b></A><br>
    ++<A HREF="android.support.v4.widget.SearchViewCompat.OnCloseListenerCompat.html" class="hiddenlink" target="rightframe">SearchViewCompat.OnCloseListenerCompat</A><br>
    ++<A HREF="pkg_android.support.v4.widget.html#SearchViewCompat.OnQueryTextListener" class="hiddenlink" target="rightframe"><b><i>SearchViewCompat.OnQueryTextListener</i></b></A><br>
    ++<A HREF="android.support.v4.widget.SearchViewCompat.OnQueryTextListenerCompat.html" class="hiddenlink" target="rightframe">SearchViewCompat.OnQueryTextListenerCompat</A><br>
    ++<A HREF="android.support.v4.app.ServiceCompat.html" class="hiddenlink" target="rightframe">ServiceCompat</A><br>
    ++<A HREF="pkg_android.support.v7.widget.html#ShareActionProvider" class="hiddenlink" target="rightframe"><b>ShareActionProvider</b></A><br>
    ++<A HREF="pkg_android.support.v7.widget.html#ShareActionProvider.OnShareTargetSelectedListener" class="hiddenlink" target="rightframe"><b><i>ShareActionProvider.OnShareTargetSelectedListener</i></b></A><br>
    ++<A HREF="android.support.v4.app.SharedElementCallback.html" class="hiddenlink" target="rightframe">SharedElementCallback</A><br>
    ++<A HREF="pkg_android.support.v4.app.html#SharedElementCallback.OnSharedElementsReadyListener" class="hiddenlink" target="rightframe"><b><i>SharedElementCallback.OnSharedElementsReadyListener</i></b></A><br>
    ++<A HREF="pkg_android.support.v7.widget.html#SnapHelper" class="hiddenlink" target="rightframe"><b>SnapHelper</b></A><br>
    ++<A HREF="android.support.v7.util.SortedList.Callback.html" class="hiddenlink" target="rightframe">SortedList.Callback</A><br>
    ++<A HREF="pkg_android.support.v7.widget.html#Space" class="hiddenlink" target="rightframe"><b>Space</b></A><br>
    ++<A HREF="android.support.v7.widget.StaggeredGridLayoutManager.html" class="hiddenlink" target="rightframe">StaggeredGridLayoutManager</A><br>
    ++<A HREF="android.support.v4.widget.SwipeRefreshLayout.html" class="hiddenlink" target="rightframe">SwipeRefreshLayout</A><br>
    ++<A HREF="pkg_android.support.v4.widget.html#SwipeRefreshLayout.OnChildScrollUpCallback" class="hiddenlink" target="rightframe"><b><i>SwipeRefreshLayout.OnChildScrollUpCallback</i></b></A><br>
    ++<A HREF="pkg_android.support.v7.widget.html#SwitchCompat" class="hiddenlink" target="rightframe"><b>SwitchCompat</b></A><br>
    ++<A NAME="T"></A>
    ++<br><font size="+2">T</font>&nbsp;
    ++<a href="#A"><font size="-2">A</font></a> 
    ++<a href="#B"><font size="-2">B</font></a> 
    ++<a href="#C"><font size="-2">C</font></a> 
    ++<a href="#D"><font size="-2">D</font></a> 
    ++<a href="#F"><font size="-2">F</font></a> 
    ++<a href="#G"><font size="-2">G</font></a> 
    ++<a href="#K"><font size="-2">K</font></a> 
    ++<a href="#L"><font size="-2">L</font></a> 
    ++<a href="#M"><font size="-2">M</font></a> 
    ++<a href="#N"><font size="-2">N</font></a> 
    ++<a href="#O"><font size="-2">O</font></a> 
    ++<a href="#P"><font size="-2">P</font></a> 
    ++<a href="#R"><font size="-2">R</font></a> 
    ++<a href="#S"><font size="-2">S</font></a> 
    ++<a href="#V"><font size="-2">V</font></a> 
    ++<a href="#W"><font size="-2">W</font></a> 
    ++ <a href="#topheader"><font size="-2">TOP</font></a>
    ++<p><div style="line-height:1.5em;color:black">
    ++<A HREF="android.support.design.widget.TabLayout.html" class="hiddenlink" target="rightframe">TabLayout</A><br>
    ++<A HREF="android.support.design.widget.TextInputLayout.html" class="hiddenlink" target="rightframe">TextInputLayout</A><br>
    ++<A HREF="android.support.v4.widget.TextViewCompat.html" class="hiddenlink" target="rightframe">TextViewCompat</A><br>
    ++<A HREF="pkg_android.support.v7.widget.html#ThemedSpinnerAdapter" class="hiddenlink" target="rightframe"><b><i>ThemedSpinnerAdapter</i></b></A><br>
    ++<A HREF="pkg_android.support.v7.widget.html#ThemedSpinnerAdapter.Helper" class="hiddenlink" target="rightframe"><b>ThemedSpinnerAdapter.Helper</b></A><br>
    ++<A HREF="pkg_android.support.v7.widget.html#Toolbar" class="hiddenlink" target="rightframe"><b>Toolbar</b></A><br>
    ++<A HREF="pkg_android.support.v7.widget.html#Toolbar.LayoutParams" class="hiddenlink" target="rightframe"><b>Toolbar.LayoutParams</b></A><br>
    ++<A HREF="pkg_android.support.v7.widget.html#Toolbar.OnMenuItemClickListener" class="hiddenlink" target="rightframe"><b><i>Toolbar.OnMenuItemClickListener</i></b></A><br>
    ++<A HREF="pkg_android.support.v7.widget.html#Toolbar.SavedState" class="hiddenlink" target="rightframe"><b>Toolbar.SavedState</b></A><br>
    ++<A NAME="V"></A>
    ++<br><font size="+2">V</font>&nbsp;
    ++<a href="#A"><font size="-2">A</font></a> 
    ++<a href="#B"><font size="-2">B</font></a> 
    ++<a href="#C"><font size="-2">C</font></a> 
    ++<a href="#D"><font size="-2">D</font></a> 
    ++<a href="#F"><font size="-2">F</font></a> 
    ++<a href="#G"><font size="-2">G</font></a> 
    ++<a href="#K"><font size="-2">K</font></a> 
    ++<a href="#L"><font size="-2">L</font></a> 
    ++<a href="#M"><font size="-2">M</font></a> 
    ++<a href="#N"><font size="-2">N</font></a> 
    ++<a href="#O"><font size="-2">O</font></a> 
    ++<a href="#P"><font size="-2">P</font></a> 
    ++<a href="#R"><font size="-2">R</font></a> 
    ++<a href="#S"><font size="-2">S</font></a> 
    ++<a href="#T"><font size="-2">T</font></a> 
    ++<a href="#W"><font size="-2">W</font></a> 
    ++ <a href="#topheader"><font size="-2">TOP</font></a>
    ++<p><div style="line-height:1.5em;color:black">
    ++<A HREF="android.support.v4.view.ViewCompat.html" class="hiddenlink" target="rightframe">ViewCompat</A><br>
    ++<A HREF="android.support.v4.view.ViewConfigurationCompat.html" class="hiddenlink" target="rightframe">ViewConfigurationCompat</A><br>
    ++<A NAME="W"></A>
    ++<br><font size="+2">W</font>&nbsp;
    ++<a href="#A"><font size="-2">A</font></a> 
    ++<a href="#B"><font size="-2">B</font></a> 
    ++<a href="#C"><font size="-2">C</font></a> 
    ++<a href="#D"><font size="-2">D</font></a> 
    ++<a href="#F"><font size="-2">F</font></a> 
    ++<a href="#G"><font size="-2">G</font></a> 
    ++<a href="#K"><font size="-2">K</font></a> 
    ++<a href="#L"><font size="-2">L</font></a> 
    ++<a href="#M"><font size="-2">M</font></a> 
    ++<a href="#N"><font size="-2">N</font></a> 
    ++<a href="#O"><font size="-2">O</font></a> 
    ++<a href="#P"><font size="-2">P</font></a> 
    ++<a href="#R"><font size="-2">R</font></a> 
    ++<a href="#S"><font size="-2">S</font></a> 
    ++<a href="#T"><font size="-2">T</font></a> 
    ++<a href="#V"><font size="-2">V</font></a> 
    ++ <a href="#topheader"><font size="-2">TOP</font></a>
    ++<p><div style="line-height:1.5em;color:black">
    ++<A HREF="android.support.v4.view.WindowInsetsCompat.html" class="hiddenlink" target="rightframe">WindowInsetsCompat</A><br>
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    ++</script>
    ++<script type="text/javascript">
    ++  try {
    ++    var pageTracker = _gat._getTracker("UA-5831155-1");
    ++    pageTracker._setAllowAnchor(true);
    ++    pageTracker._initData();
    ++    pageTracker._trackPageview();
    ++  } catch(e) {}
    ++</script>
    ++</BODY>
    ++</HTML>
    +diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/classes_index_changes.html b/docs/html/sdk/support_api_diff/24.2.0/changes/classes_index_changes.html
    +new file mode 100644
    +index 0000000..58fe615
    +--- /dev/null
    ++++ b/docs/html/sdk/support_api_diff/24.2.0/changes/classes_index_changes.html
    +@@ -0,0 +1,394 @@
    ++<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
    ++<HTML style="overflow:auto;">
    ++<HEAD>
    ++<meta name="generator" content="JDiff v1.1.0">
    ++<!-- Generated by the JDiff Javadoc doclet -->
    ++<!-- (http://www.jdiff.org) -->
    ++<meta name="description" content="JDiff is a Javadoc doclet which generates an HTML report of all the packages, classes, constructors, methods, and fields which have been removed, added or changed in any way, including their documentation, when two APIs are compared.">
    ++<meta name="keywords" content="diff, jdiff, javadiff, java diff, java difference, API difference, difference between two APIs, API diff, Javadoc, doclet">
    ++<TITLE>
    ++Class Changes Index
    ++</TITLE>
    ++<link href="../../../../assets/android-developer-docs.css" rel="stylesheet" type="text/css" />
    ++<link href="../stylesheet-jdiff.css" rel="stylesheet" type="text/css" />
    ++<noscript>
    ++<style type="text/css">
    ++body{overflow:auto;}
    ++#body-content{position:relative; top:0;}
    ++#doc-content{overflow:visible;border-left:3px solid #666;}
    ++#side-nav{padding:0;}
    ++#side-nav .toggle-list ul {display:block;}
    ++#resize-packages-nav{border-bottom:3px solid #666;}
    ++</style>
    ++</noscript>
    ++<style type="text/css">
    ++</style>
    ++</HEAD>
    ++<BODY class="gc-documentation" style="padding:12px;">
    ++<a NAME="topheader"></a>
    ++<table summary="Index for Classes" width="100%" class="jdiffIndex" border="0" cellspacing="0" cellpadding="0" style="padding-bottom:0;margin-bottom:0;">
    ++  <tr>
    ++  <th class="indexHeader">
    ++    Filter the Index:
    ++  </th>
    ++  </tr>
    ++  <tr>
    ++  <td class="indexText" style="line-height:1.3em;padding-left:2em;">
    ++<a href="classes_index_all.html" class="staysblack">All Classes</a>
    ++  <br>
    ++<font color="#999999">Removals</font>
    ++  <br>
    ++<A HREF="classes_index_additions.html"xclass="hiddenlink">Additions</A>
    ++  <br>
    ++<b>Changes</b>
    ++  </td>
    ++  </tr>
    ++</table>
    ++<div id="indexTableCaption" style="background-color:#eee;padding:0 4px 0 4px;font-size:11px;margin-bottom:1em;">
    ++Listed as: <span style="color:#069"><strong>Added</strong></span>,  <span style="color:#069"><strike>Removed</strike></span>,  <span style="color:#069">Changed</span></font>
    ++</div>
    ++<A NAME="A"></A>
    ++<br><font size="+2">A</font>&nbsp;
    ++<a href="#B"><font size="-2">B</font></a> 
    ++<a href="#C"><font size="-2">C</font></a> 
    ++<a href="#D"><font size="-2">D</font></a> 
    ++<a href="#F"><font size="-2">F</font></a> 
    ++<a href="#K"><font size="-2">K</font></a> 
    ++<a href="#L"><font size="-2">L</font></a> 
    ++<a href="#M"><font size="-2">M</font></a> 
    ++<a href="#O"><font size="-2">O</font></a> 
    ++<a href="#P"><font size="-2">P</font></a> 
    ++<a href="#R"><font size="-2">R</font></a> 
    ++<a href="#S"><font size="-2">S</font></a> 
    ++<a href="#T"><font size="-2">T</font></a> 
    ++<a href="#V"><font size="-2">V</font></a> 
    ++<a href="#W"><font size="-2">W</font></a> 
    ++ <a href="#topheader"><font size="-2">TOP</font></a>
    ++<p><div style="line-height:1.5em;color:black">
    ++<A HREF="android.support.v17.leanback.widget.AbstractMediaItemPresenter.html" class="hiddenlink" target="rightframe">AbstractMediaItemPresenter</A><br>
    ++<A HREF="android.support.v17.leanback.widget.AbstractMediaItemPresenter.ViewHolder.html" class="hiddenlink" target="rightframe">AbstractMediaItemPresenter.ViewHolder</A><br>
    ++<A HREF="android.support.v4.view.accessibility.AccessibilityEventCompat.html" class="hiddenlink" target="rightframe">AccessibilityEventCompat</A><br>
    ++<A HREF="android.support.v4.view.accessibility.AccessibilityManagerCompat.html" class="hiddenlink" target="rightframe">AccessibilityManagerCompat</A><br>
    ++<A HREF="android.support.v4.view.accessibility.AccessibilityManagerCompat.AccessibilityStateChangeListenerCompat.html" class="hiddenlink" target="rightframe">AccessibilityManagerCompat.AccessibilityStateChangeListenerCompat</A><br>
    ++<A HREF="android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.html" class="hiddenlink" target="rightframe">AccessibilityNodeInfoCompat</A><br>
    ++<A HREF="android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat.html" class="hiddenlink" target="rightframe">AccessibilityNodeInfoCompat.AccessibilityActionCompat</A><br>
    ++<A HREF="android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.CollectionInfoCompat.html" class="hiddenlink" target="rightframe">AccessibilityNodeInfoCompat.CollectionInfoCompat</A><br>
    ++<A HREF="android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.CollectionItemInfoCompat.html" class="hiddenlink" target="rightframe">AccessibilityNodeInfoCompat.CollectionItemInfoCompat</A><br>
    ++<A HREF="android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.RangeInfoCompat.html" class="hiddenlink" target="rightframe">AccessibilityNodeInfoCompat.RangeInfoCompat</A><br>
    ++<A HREF="android.support.v4.view.accessibility.AccessibilityNodeProviderCompat.html" class="hiddenlink" target="rightframe">AccessibilityNodeProviderCompat</A><br>
    ++<A HREF="android.support.v4.accessibilityservice.AccessibilityServiceInfoCompat.html" class="hiddenlink" target="rightframe">AccessibilityServiceInfoCompat</A><br>
    ++<A HREF="android.support.v4.view.accessibility.AccessibilityWindowInfoCompat.html" class="hiddenlink" target="rightframe">AccessibilityWindowInfoCompat</A><br>
    ++<A HREF="android.support.v7.app.ActionBarDrawerToggle.html" class="hiddenlink" target="rightframe">ActionBarDrawerToggle</A><br>
    ++<A HREF="android.support.v4.app.ActivityCompat.html" class="hiddenlink" target="rightframe">ActivityCompat</A><br>
    ++<A HREF="android.support.v4.app.ActivityOptionsCompat.html" class="hiddenlink" target="rightframe">ActivityOptionsCompat</A><br>
    ++<A HREF="android.support.design.widget.AppBarLayout.ScrollingViewBehavior.html" class="hiddenlink" target="rightframe">AppBarLayout.ScrollingViewBehavior</A><br>
    ++<A HREF="android.support.v7.app.AppCompatDelegate.html" class="hiddenlink" target="rightframe">AppCompatDelegate</A><br>
    ++<A HREF="android.support.v7.content.res.AppCompatResources.html" class="hiddenlink" target="rightframe">AppCompatResources</A><br>
    ++<A NAME="B"></A>
    ++<br><font size="+2">B</font>&nbsp;
    ++<a href="#A"><font size="-2">A</font></a> 
    ++<a href="#C"><font size="-2">C</font></a> 
    ++<a href="#D"><font size="-2">D</font></a> 
    ++<a href="#F"><font size="-2">F</font></a> 
    ++<a href="#K"><font size="-2">K</font></a> 
    ++<a href="#L"><font size="-2">L</font></a> 
    ++<a href="#M"><font size="-2">M</font></a> 
    ++<a href="#O"><font size="-2">O</font></a> 
    ++<a href="#P"><font size="-2">P</font></a> 
    ++<a href="#R"><font size="-2">R</font></a> 
    ++<a href="#S"><font size="-2">S</font></a> 
    ++<a href="#T"><font size="-2">T</font></a> 
    ++<a href="#V"><font size="-2">V</font></a> 
    ++<a href="#W"><font size="-2">W</font></a> 
    ++ <a href="#topheader"><font size="-2">TOP</font></a>
    ++<p><div style="line-height:1.5em;color:black">
    ++<A HREF="android.support.design.widget.BottomSheetBehavior.html" class="hiddenlink" target="rightframe">BottomSheetBehavior</A><br>
    ++<A HREF="android.support.v4.os.BuildCompat.html" class="hiddenlink" target="rightframe">BuildCompat</A><br>
    ++<A NAME="C"></A>
    ++<br><font size="+2">C</font>&nbsp;
    ++<a href="#A"><font size="-2">A</font></a> 
    ++<a href="#B"><font size="-2">B</font></a> 
    ++<a href="#D"><font size="-2">D</font></a> 
    ++<a href="#F"><font size="-2">F</font></a> 
    ++<a href="#K"><font size="-2">K</font></a> 
    ++<a href="#L"><font size="-2">L</font></a> 
    ++<a href="#M"><font size="-2">M</font></a> 
    ++<a href="#O"><font size="-2">O</font></a> 
    ++<a href="#P"><font size="-2">P</font></a> 
    ++<a href="#R"><font size="-2">R</font></a> 
    ++<a href="#S"><font size="-2">S</font></a> 
    ++<a href="#T"><font size="-2">T</font></a> 
    ++<a href="#V"><font size="-2">V</font></a> 
    ++<a href="#W"><font size="-2">W</font></a> 
    ++ <a href="#topheader"><font size="-2">TOP</font></a>
    ++<p><div style="line-height:1.5em;color:black">
    ++<A HREF="android.support.design.widget.CollapsingToolbarLayout.html" class="hiddenlink" target="rightframe">CollapsingToolbarLayout</A><br>
    ++<A HREF="android.support.v4.content.ContextCompat.html" class="hiddenlink" target="rightframe">ContextCompat</A><br>
    ++<A HREF="android.support.design.widget.CoordinatorLayout.html" class="hiddenlink" target="rightframe">CoordinatorLayout</A><br>
    ++<A HREF="android.support.design.widget.CoordinatorLayout.Behavior.html" class="hiddenlink" target="rightframe">CoordinatorLayout.Behavior</A><br>
    ++<A HREF="android.support.design.widget.CoordinatorLayout.LayoutParams.html" class="hiddenlink" target="rightframe">CoordinatorLayout.LayoutParams</A><br>
    ++<A HREF="android.support.customtabs.CustomTabsIntent.html" class="hiddenlink" target="rightframe">CustomTabsIntent</A><br>
    ++<A HREF="android.support.customtabs.CustomTabsIntent.Builder.html" class="hiddenlink" target="rightframe">CustomTabsIntent.Builder</A><br>
    ++<A HREF="android.support.customtabs.CustomTabsSession.html" class="hiddenlink" target="rightframe">CustomTabsSession</A><br>
    ++<A NAME="D"></A>
    ++<br><font size="+2">D</font>&nbsp;
    ++<a href="#A"><font size="-2">A</font></a> 
    ++<a href="#B"><font size="-2">B</font></a> 
    ++<a href="#C"><font size="-2">C</font></a> 
    ++<a href="#F"><font size="-2">F</font></a> 
    ++<a href="#K"><font size="-2">K</font></a> 
    ++<a href="#L"><font size="-2">L</font></a> 
    ++<a href="#M"><font size="-2">M</font></a> 
    ++<a href="#O"><font size="-2">O</font></a> 
    ++<a href="#P"><font size="-2">P</font></a> 
    ++<a href="#R"><font size="-2">R</font></a> 
    ++<a href="#S"><font size="-2">S</font></a> 
    ++<a href="#T"><font size="-2">T</font></a> 
    ++<a href="#V"><font size="-2">V</font></a> 
    ++<a href="#W"><font size="-2">W</font></a> 
    ++ <a href="#topheader"><font size="-2">TOP</font></a>
    ++<p><div style="line-height:1.5em;color:black">
    ++<A HREF="android.support.v4.graphics.drawable.DrawableCompat.html" class="hiddenlink" target="rightframe">DrawableCompat</A><br>
    ++<A NAME="F"></A>
    ++<br><font size="+2">F</font>&nbsp;
    ++<a href="#A"><font size="-2">A</font></a> 
    ++<a href="#B"><font size="-2">B</font></a> 
    ++<a href="#C"><font size="-2">C</font></a> 
    ++<a href="#D"><font size="-2">D</font></a> 
    ++<a href="#K"><font size="-2">K</font></a> 
    ++<a href="#L"><font size="-2">L</font></a> 
    ++<a href="#M"><font size="-2">M</font></a> 
    ++<a href="#O"><font size="-2">O</font></a> 
    ++<a href="#P"><font size="-2">P</font></a> 
    ++<a href="#R"><font size="-2">R</font></a> 
    ++<a href="#S"><font size="-2">S</font></a> 
    ++<a href="#T"><font size="-2">T</font></a> 
    ++<a href="#V"><font size="-2">V</font></a> 
    ++<a href="#W"><font size="-2">W</font></a> 
    ++ <a href="#topheader"><font size="-2">TOP</font></a>
    ++<p><div style="line-height:1.5em;color:black">
    ++<A HREF="android.support.design.widget.FloatingActionButton.Behavior.html" class="hiddenlink" target="rightframe">FloatingActionButton.Behavior</A><br>
    ++<A HREF="android.support.v4.app.FragmentController.html" class="hiddenlink" target="rightframe">FragmentController</A><br>
    ++<A NAME="K"></A>
    ++<br><font size="+2">K</font>&nbsp;
    ++<a href="#A"><font size="-2">A</font></a> 
    ++<a href="#B"><font size="-2">B</font></a> 
    ++<a href="#C"><font size="-2">C</font></a> 
    ++<a href="#D"><font size="-2">D</font></a> 
    ++<a href="#F"><font size="-2">F</font></a> 
    ++<a href="#L"><font size="-2">L</font></a> 
    ++<a href="#M"><font size="-2">M</font></a> 
    ++<a href="#O"><font size="-2">O</font></a> 
    ++<a href="#P"><font size="-2">P</font></a> 
    ++<a href="#R"><font size="-2">R</font></a> 
    ++<a href="#S"><font size="-2">S</font></a> 
    ++<a href="#T"><font size="-2">T</font></a> 
    ++<a href="#V"><font size="-2">V</font></a> 
    ++<a href="#W"><font size="-2">W</font></a> 
    ++ <a href="#topheader"><font size="-2">TOP</font></a>
    ++<p><div style="line-height:1.5em;color:black">
    ++<A HREF="android.support.v4.view.KeyEventCompat.html" class="hiddenlink" target="rightframe">KeyEventCompat</A><br>
    ++<A NAME="L"></A>
    ++<br><font size="+2">L</font>&nbsp;
    ++<a href="#A"><font size="-2">A</font></a> 
    ++<a href="#B"><font size="-2">B</font></a> 
    ++<a href="#C"><font size="-2">C</font></a> 
    ++<a href="#D"><font size="-2">D</font></a> 
    ++<a href="#F"><font size="-2">F</font></a> 
    ++<a href="#K"><font size="-2">K</font></a> 
    ++<a href="#M"><font size="-2">M</font></a> 
    ++<a href="#O"><font size="-2">O</font></a> 
    ++<a href="#P"><font size="-2">P</font></a> 
    ++<a href="#R"><font size="-2">R</font></a> 
    ++<a href="#S"><font size="-2">S</font></a> 
    ++<a href="#T"><font size="-2">T</font></a> 
    ++<a href="#V"><font size="-2">V</font></a> 
    ++<a href="#W"><font size="-2">W</font></a> 
    ++ <a href="#topheader"><font size="-2">TOP</font></a>
    ++<p><div style="line-height:1.5em;color:black">
    ++<A HREF="android.support.v17.preference.LeanbackSettingsFragment.html" class="hiddenlink" target="rightframe">LeanbackSettingsFragment</A><br>
    ++<A HREF="android.support.v7.widget.LinearLayoutManager.html" class="hiddenlink" target="rightframe">LinearLayoutManager</A><br>
    ++<A HREF="android.support.v7.widget.LinearSmoothScroller.html" class="hiddenlink" target="rightframe">LinearSmoothScroller</A><br>
    ++<A NAME="M"></A>
    ++<br><font size="+2">M</font>&nbsp;
    ++<a href="#A"><font size="-2">A</font></a> 
    ++<a href="#B"><font size="-2">B</font></a> 
    ++<a href="#C"><font size="-2">C</font></a> 
    ++<a href="#D"><font size="-2">D</font></a> 
    ++<a href="#F"><font size="-2">F</font></a> 
    ++<a href="#K"><font size="-2">K</font></a> 
    ++<a href="#L"><font size="-2">L</font></a> 
    ++<a href="#O"><font size="-2">O</font></a> 
    ++<a href="#P"><font size="-2">P</font></a> 
    ++<a href="#R"><font size="-2">R</font></a> 
    ++<a href="#S"><font size="-2">S</font></a> 
    ++<a href="#T"><font size="-2">T</font></a> 
    ++<a href="#V"><font size="-2">V</font></a> 
    ++<a href="#W"><font size="-2">W</font></a> 
    ++ <a href="#topheader"><font size="-2">TOP</font></a>
    ++<p><div style="line-height:1.5em;color:black">
    ++<A HREF="android.support.v4.media.MediaBrowserCompat.MediaItem.html" class="hiddenlink" target="rightframe">MediaBrowserCompat.MediaItem</A><br>
    ++<A HREF="android.support.v4.media.MediaBrowserServiceCompat.BrowserRoot.html" class="hiddenlink" target="rightframe">MediaBrowserServiceCompat.BrowserRoot</A><br>
    ++<A HREF="android.support.v4.media.session.MediaButtonReceiver.html" class="hiddenlink" target="rightframe">MediaButtonReceiver</A><br>
    ++<A HREF="android.support.v4.media.MediaDescriptionCompat.html" class="hiddenlink" target="rightframe">MediaDescriptionCompat</A><br>
    ++<A HREF="android.support.v4.media.MediaMetadataCompat.html" class="hiddenlink" target="rightframe">MediaMetadataCompat</A><br>
    ++<A HREF="android.support.v4.media.session.MediaSessionCompat.html" class="hiddenlink" target="rightframe">MediaSessionCompat</A><br>
    ++<A HREF="android.support.v4.media.session.MediaSessionCompat.QueueItem.html" class="hiddenlink" target="rightframe">MediaSessionCompat.QueueItem</A><br>
    ++<A HREF="android.support.v4.view.MotionEventCompat.html" class="hiddenlink" target="rightframe">MotionEventCompat</A><br>
    ++<A NAME="O"></A>
    ++<br><font size="+2">O</font>&nbsp;
    ++<a href="#A"><font size="-2">A</font></a> 
    ++<a href="#B"><font size="-2">B</font></a> 
    ++<a href="#C"><font size="-2">C</font></a> 
    ++<a href="#D"><font size="-2">D</font></a> 
    ++<a href="#F"><font size="-2">F</font></a> 
    ++<a href="#K"><font size="-2">K</font></a> 
    ++<a href="#L"><font size="-2">L</font></a> 
    ++<a href="#M"><font size="-2">M</font></a> 
    ++<a href="#P"><font size="-2">P</font></a> 
    ++<a href="#R"><font size="-2">R</font></a> 
    ++<a href="#S"><font size="-2">S</font></a> 
    ++<a href="#T"><font size="-2">T</font></a> 
    ++<a href="#V"><font size="-2">V</font></a> 
    ++<a href="#W"><font size="-2">W</font></a> 
    ++ <a href="#topheader"><font size="-2">TOP</font></a>
    ++<p><div style="line-height:1.5em;color:black">
    ++<A HREF="android.support.v17.leanback.widget.ObjectAdapter.html" class="hiddenlink" target="rightframe">ObjectAdapter</A><br>
    ++<A NAME="P"></A>
    ++<br><font size="+2">P</font>&nbsp;
    ++<a href="#A"><font size="-2">A</font></a> 
    ++<a href="#B"><font size="-2">B</font></a> 
    ++<a href="#C"><font size="-2">C</font></a> 
    ++<a href="#D"><font size="-2">D</font></a> 
    ++<a href="#F"><font size="-2">F</font></a> 
    ++<a href="#K"><font size="-2">K</font></a> 
    ++<a href="#L"><font size="-2">L</font></a> 
    ++<a href="#M"><font size="-2">M</font></a> 
    ++<a href="#O"><font size="-2">O</font></a> 
    ++<a href="#R"><font size="-2">R</font></a> 
    ++<a href="#S"><font size="-2">S</font></a> 
    ++<a href="#T"><font size="-2">T</font></a> 
    ++<a href="#V"><font size="-2">V</font></a> 
    ++<a href="#W"><font size="-2">W</font></a> 
    ++ <a href="#topheader"><font size="-2">TOP</font></a>
    ++<p><div style="line-height:1.5em;color:black">
    ++<A HREF="android.support.v7.graphics.Palette.html" class="hiddenlink" target="rightframe">Palette</A><br>
    ++<A HREF="android.support.v4.media.session.PlaybackStateCompat.html" class="hiddenlink" target="rightframe">PlaybackStateCompat</A><br>
    ++<A HREF="android.support.v14.preference.PreferenceFragment.html" class="hiddenlink" target="rightframe">PreferenceFragment</A><br>
    ++<A NAME="R"></A>
    ++<br><font size="+2">R</font>&nbsp;
    ++<a href="#A"><font size="-2">A</font></a> 
    ++<a href="#B"><font size="-2">B</font></a> 
    ++<a href="#C"><font size="-2">C</font></a> 
    ++<a href="#D"><font size="-2">D</font></a> 
    ++<a href="#F"><font size="-2">F</font></a> 
    ++<a href="#K"><font size="-2">K</font></a> 
    ++<a href="#L"><font size="-2">L</font></a> 
    ++<a href="#M"><font size="-2">M</font></a> 
    ++<a href="#O"><font size="-2">O</font></a> 
    ++<a href="#P"><font size="-2">P</font></a> 
    ++<a href="#S"><font size="-2">S</font></a> 
    ++<a href="#T"><font size="-2">T</font></a> 
    ++<a href="#V"><font size="-2">V</font></a> 
    ++<a href="#W"><font size="-2">W</font></a> 
    ++ <a href="#topheader"><font size="-2">TOP</font></a>
    ++<p><div style="line-height:1.5em;color:black">
    ++<A HREF="android.support.v7.widget.RecyclerView.html" class="hiddenlink" target="rightframe">RecyclerView</A><br>
    ++<A NAME="S"></A>
    ++<br><font size="+2">S</font>&nbsp;
    ++<a href="#A"><font size="-2">A</font></a> 
    ++<a href="#B"><font size="-2">B</font></a> 
    ++<a href="#C"><font size="-2">C</font></a> 
    ++<a href="#D"><font size="-2">D</font></a> 
    ++<a href="#F"><font size="-2">F</font></a> 
    ++<a href="#K"><font size="-2">K</font></a> 
    ++<a href="#L"><font size="-2">L</font></a> 
    ++<a href="#M"><font size="-2">M</font></a> 
    ++<a href="#O"><font size="-2">O</font></a> 
    ++<a href="#P"><font size="-2">P</font></a> 
    ++<a href="#R"><font size="-2">R</font></a> 
    ++<a href="#T"><font size="-2">T</font></a> 
    ++<a href="#V"><font size="-2">V</font></a> 
    ++<a href="#W"><font size="-2">W</font></a> 
    ++ <a href="#topheader"><font size="-2">TOP</font></a>
    ++<p><div style="line-height:1.5em;color:black">
    ++<A HREF="android.support.v4.widget.SearchViewCompat.html" class="hiddenlink" target="rightframe">SearchViewCompat</A><br>
    ++<A HREF="android.support.v4.widget.SearchViewCompat.OnCloseListenerCompat.html" class="hiddenlink" target="rightframe">SearchViewCompat.OnCloseListenerCompat</A><br>
    ++<A HREF="android.support.v4.widget.SearchViewCompat.OnQueryTextListenerCompat.html" class="hiddenlink" target="rightframe">SearchViewCompat.OnQueryTextListenerCompat</A><br>
    ++<A HREF="android.support.v4.app.ServiceCompat.html" class="hiddenlink" target="rightframe">ServiceCompat</A><br>
    ++<A HREF="android.support.v4.app.SharedElementCallback.html" class="hiddenlink" target="rightframe">SharedElementCallback</A><br>
    ++<A HREF="android.support.v7.util.SortedList.Callback.html" class="hiddenlink" target="rightframe">SortedList.Callback</A><br>
    ++<A HREF="android.support.v7.widget.StaggeredGridLayoutManager.html" class="hiddenlink" target="rightframe">StaggeredGridLayoutManager</A><br>
    ++<A HREF="android.support.v4.widget.SwipeRefreshLayout.html" class="hiddenlink" target="rightframe">SwipeRefreshLayout</A><br>
    ++<A NAME="T"></A>
    ++<br><font size="+2">T</font>&nbsp;
    ++<a href="#A"><font size="-2">A</font></a> 
    ++<a href="#B"><font size="-2">B</font></a> 
    ++<a href="#C"><font size="-2">C</font></a> 
    ++<a href="#D"><font size="-2">D</font></a> 
    ++<a href="#F"><font size="-2">F</font></a> 
    ++<a href="#K"><font size="-2">K</font></a> 
    ++<a href="#L"><font size="-2">L</font></a> 
    ++<a href="#M"><font size="-2">M</font></a> 
    ++<a href="#O"><font size="-2">O</font></a> 
    ++<a href="#P"><font size="-2">P</font></a> 
    ++<a href="#R"><font size="-2">R</font></a> 
    ++<a href="#S"><font size="-2">S</font></a> 
    ++<a href="#V"><font size="-2">V</font></a> 
    ++<a href="#W"><font size="-2">W</font></a> 
    ++ <a href="#topheader"><font size="-2">TOP</font></a>
    ++<p><div style="line-height:1.5em;color:black">
    ++<A HREF="android.support.design.widget.TabLayout.html" class="hiddenlink" target="rightframe">TabLayout</A><br>
    ++<A HREF="android.support.design.widget.TextInputLayout.html" class="hiddenlink" target="rightframe">TextInputLayout</A><br>
    ++<A HREF="android.support.v4.widget.TextViewCompat.html" class="hiddenlink" target="rightframe">TextViewCompat</A><br>
    ++<A NAME="V"></A>
    ++<br><font size="+2">V</font>&nbsp;
    ++<a href="#A"><font size="-2">A</font></a> 
    ++<a href="#B"><font size="-2">B</font></a> 
    ++<a href="#C"><font size="-2">C</font></a> 
    ++<a href="#D"><font size="-2">D</font></a> 
    ++<a href="#F"><font size="-2">F</font></a> 
    ++<a href="#K"><font size="-2">K</font></a> 
    ++<a href="#L"><font size="-2">L</font></a> 
    ++<a href="#M"><font size="-2">M</font></a> 
    ++<a href="#O"><font size="-2">O</font></a> 
    ++<a href="#P"><font size="-2">P</font></a> 
    ++<a href="#R"><font size="-2">R</font></a> 
    ++<a href="#S"><font size="-2">S</font></a> 
    ++<a href="#T"><font size="-2">T</font></a> 
    ++<a href="#W"><font size="-2">W</font></a> 
    ++ <a href="#topheader"><font size="-2">TOP</font></a>
    ++<p><div style="line-height:1.5em;color:black">
    ++<A HREF="android.support.v4.view.ViewCompat.html" class="hiddenlink" target="rightframe">ViewCompat</A><br>
    ++<A HREF="android.support.v4.view.ViewConfigurationCompat.html" class="hiddenlink" target="rightframe">ViewConfigurationCompat</A><br>
    ++<A NAME="W"></A>
    ++<br><font size="+2">W</font>&nbsp;
    ++<a href="#A"><font size="-2">A</font></a> 
    ++<a href="#B"><font size="-2">B</font></a> 
    ++<a href="#C"><font size="-2">C</font></a> 
    ++<a href="#D"><font size="-2">D</font></a> 
    ++<a href="#F"><font size="-2">F</font></a> 
    ++<a href="#K"><font size="-2">K</font></a> 
    ++<a href="#L"><font size="-2">L</font></a> 
    ++<a href="#M"><font size="-2">M</font></a> 
    ++<a href="#O"><font size="-2">O</font></a> 
    ++<a href="#P"><font size="-2">P</font></a> 
    ++<a href="#R"><font size="-2">R</font></a> 
    ++<a href="#S"><font size="-2">S</font></a> 
    ++<a href="#T"><font size="-2">T</font></a> 
    ++<a href="#V"><font size="-2">V</font></a> 
    ++ <a href="#topheader"><font size="-2">TOP</font></a>
    ++<p><div style="line-height:1.5em;color:black">
    ++<A HREF="android.support.v4.view.WindowInsetsCompat.html" class="hiddenlink" target="rightframe">WindowInsetsCompat</A><br>
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    ++</script>
    ++<script type="text/javascript">
    ++  try {
    ++    var pageTracker = _gat._getTracker("UA-5831155-1");
    ++    pageTracker._setAllowAnchor(true);
    ++    pageTracker._initData();
    ++    pageTracker._trackPageview();
    ++  } catch(e) {}
    ++</script>
    ++</BODY>
    ++</HTML>
    +diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/classes_index_removals.html b/docs/html/sdk/support_api_diff/24.2.0/changes/classes_index_removals.html
    +new file mode 100644
    +index 0000000..c466298
    +--- /dev/null
    ++++ b/docs/html/sdk/support_api_diff/24.2.0/changes/classes_index_removals.html
    +@@ -0,0 +1,61 @@
    ++<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
    ++<HTML style="overflow:auto;">
    ++<HEAD>
    ++<meta name="generator" content="JDiff v1.1.0">
    ++<!-- Generated by the JDiff Javadoc doclet -->
    ++<!-- (http://www.jdiff.org) -->
    ++<meta name="description" content="JDiff is a Javadoc doclet which generates an HTML report of all the packages, classes, constructors, methods, and fields which have been removed, added or changed in any way, including their documentation, when two APIs are compared.">
    ++<meta name="keywords" content="diff, jdiff, javadiff, java diff, java difference, API difference, difference between two APIs, API diff, Javadoc, doclet">
    ++<TITLE>
    ++Class Removals Index
    ++</TITLE>
    ++<link href="../../../../assets/android-developer-docs.css" rel="stylesheet" type="text/css" />
    ++<link href="../stylesheet-jdiff.css" rel="stylesheet" type="text/css" />
    ++<noscript>
    ++<style type="text/css">
    ++body{overflow:auto;}
    ++#body-content{position:relative; top:0;}
    ++#doc-content{overflow:visible;border-left:3px solid #666;}
    ++#side-nav{padding:0;}
    ++#side-nav .toggle-list ul {display:block;}
    ++#resize-packages-nav{border-bottom:3px solid #666;}
    ++</style>
    ++</noscript>
    ++<style type="text/css">
    ++</style>
    ++</HEAD>
    ++<BODY class="gc-documentation" style="padding:12px;">
    ++<a NAME="topheader"></a>
    ++<table summary="Index for Classes" width="100%" class="jdiffIndex" border="0" cellspacing="0" cellpadding="0" style="padding-bottom:0;margin-bottom:0;">
    ++  <tr>
    ++  <th class="indexHeader">
    ++    Filter the Index:
    ++  </th>
    ++  </tr>
    ++  <tr>
    ++  <td class="indexText" style="line-height:1.3em;padding-left:2em;">
    ++<a href="classes_index_all.html" class="staysblack">All Classes</a>
    ++  <br>
    ++<font color="#999999">Removals</font>
    ++  <br>
    ++<A HREF="classes_index_additions.html"xclass="hiddenlink">Additions</A>
    ++  <br>
    ++<A HREF="classes_index_changes.html"xclass="hiddenlink">Changes</A>
    ++  </td>
    ++  </tr>
    ++</table>
    ++<div id="indexTableCaption" style="background-color:#eee;padding:0 4px 0 4px;font-size:11px;margin-bottom:1em;">
    ++Listed as: <span style="color:#069"><strong>Added</strong></span>,  <span style="color:#069"><strike>Removed</strike></span>,  <span style="color:#069">Changed</span></font>
    ++</div>
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    ++</script>
    ++<script type="text/javascript">
    ++  try {
    ++    var pageTracker = _gat._getTracker("UA-5831155-1");
    ++    pageTracker._setAllowAnchor(true);
    ++    pageTracker._initData();
    ++    pageTracker._trackPageview();
    ++  } catch(e) {}
    ++</script>
    ++</BODY>
    ++</HTML>
    +diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/constructors_index_additions.html b/docs/html/sdk/support_api_diff/24.2.0/changes/constructors_index_additions.html
    +new file mode 100644
    +index 0000000..312effc
    +--- /dev/null
    ++++ b/docs/html/sdk/support_api_diff/24.2.0/changes/constructors_index_additions.html
    +@@ -0,0 +1,67 @@
    ++<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
    ++<HTML style="overflow:auto;">
    ++<HEAD>
    ++<meta name="generator" content="JDiff v1.1.0">
    ++<!-- Generated by the JDiff Javadoc doclet -->
    ++<!-- (http://www.jdiff.org) -->
    ++<meta name="description" content="JDiff is a Javadoc doclet which generates an HTML report of all the packages, classes, constructors, methods, and fields which have been removed, added or changed in any way, including their documentation, when two APIs are compared.">
    ++<meta name="keywords" content="diff, jdiff, javadiff, java diff, java difference, API difference, difference between two APIs, API diff, Javadoc, doclet">
    ++<TITLE>
    ++Constructor Additions Index
    ++</TITLE>
    ++<link href="../../../../assets/android-developer-docs.css" rel="stylesheet" type="text/css" />
    ++<link href="../stylesheet-jdiff.css" rel="stylesheet" type="text/css" />
    ++<noscript>
    ++<style type="text/css">
    ++body{overflow:auto;}
    ++#body-content{position:relative; top:0;}
    ++#doc-content{overflow:visible;border-left:3px solid #666;}
    ++#side-nav{padding:0;}
    ++#side-nav .toggle-list ul {display:block;}
    ++#resize-packages-nav{border-bottom:3px solid #666;}
    ++</style>
    ++</noscript>
    ++<style type="text/css">
    ++</style>
    ++</HEAD>
    ++<BODY class="gc-documentation" style="padding:12px;">
    ++<a NAME="topheader"></a>
    ++<table summary="Index for Constructors" width="100%" class="jdiffIndex" border="0" cellspacing="0" cellpadding="0" style="padding-bottom:0;margin-bottom:0;">
    ++  <tr>
    ++  <th class="indexHeader">
    ++    Filter the Index:
    ++  </th>
    ++  </tr>
    ++  <tr>
    ++  <td class="indexText" style="line-height:1.3em;padding-left:2em;">
    ++<a href="constructors_index_all.html" class="staysblack">All Constructors</a>
    ++  <br>
    ++<font color="#999999">Removals</font>
    ++  <br>
    ++<b>Additions</b>
    ++  <br>
    ++<A HREF="constructors_index_changes.html"xclass="hiddenlink">Changes</A>
    ++  </td>
    ++  </tr>
    ++</table>
    ++<div id="indexTableCaption" style="background-color:#eee;padding:0 4px 0 4px;font-size:11px;margin-bottom:1em;">
    ++Listed as: <span style="color:#069"><strong>Added</strong></span>,  <span style="color:#069"><strike>Removed</strike></span>,  <span style="color:#069">Changed</span></font>
    ++</div>
    ++<A NAME="W"></A>
    ++<br><font size="+2">W</font>&nbsp;
    ++ <a href="#topheader"><font size="-2">TOP</font></a>
    ++<p><div style="line-height:1.5em;color:black">
    ++<nobr><A HREF="android.support.v4.view.WindowInsetsCompat.html#android.support.v4.view.WindowInsetsCompat.ctor_added(android.support.v4.view.WindowInsetsCompat)" class="hiddenlink" target="rightframe"><b>WindowInsetsCompat</b>
    ++(<code>WindowInsetsCompat</code>)</A></nobr>&nbsp;constructor<br>
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    ++</script>
    ++<script type="text/javascript">
    ++  try {
    ++    var pageTracker = _gat._getTracker("UA-5831155-1");
    ++    pageTracker._setAllowAnchor(true);
    ++    pageTracker._initData();
    ++    pageTracker._trackPageview();
    ++  } catch(e) {}
    ++</script>
    ++</BODY>
    ++</HTML>
    +diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/constructors_index_all.html b/docs/html/sdk/support_api_diff/24.2.0/changes/constructors_index_all.html
    +new file mode 100644
    +index 0000000..24310b7
    +--- /dev/null
    ++++ b/docs/html/sdk/support_api_diff/24.2.0/changes/constructors_index_all.html
    +@@ -0,0 +1,85 @@
    ++<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
    ++<HTML style="overflow:auto;">
    ++<HEAD>
    ++<meta name="generator" content="JDiff v1.1.0">
    ++<!-- Generated by the JDiff Javadoc doclet -->
    ++<!-- (http://www.jdiff.org) -->
    ++<meta name="description" content="JDiff is a Javadoc doclet which generates an HTML report of all the packages, classes, constructors, methods, and fields which have been removed, added or changed in any way, including their documentation, when two APIs are compared.">
    ++<meta name="keywords" content="diff, jdiff, javadiff, java diff, java difference, API difference, difference between two APIs, API diff, Javadoc, doclet">
    ++<TITLE>
    ++Constructor Differences Index
    ++</TITLE>
    ++<link href="../../../../assets/android-developer-docs.css" rel="stylesheet" type="text/css" />
    ++<link href="../stylesheet-jdiff.css" rel="stylesheet" type="text/css" />
    ++<noscript>
    ++<style type="text/css">
    ++body{overflow:auto;}
    ++#body-content{position:relative; top:0;}
    ++#doc-content{overflow:visible;border-left:3px solid #666;}
    ++#side-nav{padding:0;}
    ++#side-nav .toggle-list ul {display:block;}
    ++#resize-packages-nav{border-bottom:3px solid #666;}
    ++</style>
    ++</noscript>
    ++<style type="text/css">
    ++</style>
    ++</HEAD>
    ++<BODY class="gc-documentation" style="padding:12px;">
    ++<a NAME="topheader"></a>
    ++<table summary="Index for Constructors" width="100%" class="jdiffIndex" border="0" cellspacing="0" cellpadding="0" style="padding-bottom:0;margin-bottom:0;">
    ++  <tr>
    ++  <th class="indexHeader">
    ++    Filter the Index:
    ++  </th>
    ++  </tr>
    ++  <tr>
    ++  <td class="indexText" style="line-height:1.3em;padding-left:2em;">
    ++<b>Constructors</b>
    ++  <br>
    ++<font color="#999999">Removals</font>
    ++  <br>
    ++<A HREF="constructors_index_additions.html"xclass="hiddenlink">Additions</A>
    ++  <br>
    ++<A HREF="constructors_index_changes.html"xclass="hiddenlink">Changes</A>
    ++  </td>
    ++  </tr>
    ++</table>
    ++<div id="indexTableCaption" style="background-color:#eee;padding:0 4px 0 4px;font-size:11px;margin-bottom:1em;">
    ++Listed as: <span style="color:#069"><strong>Added</strong></span>,  <span style="color:#069"><strike>Removed</strike></span>,  <span style="color:#069">Changed</span></font>
    ++</div>
    ++<A NAME="A"></A>
    ++<br><font size="+2">A</font>&nbsp;
    ++<a href="#C"><font size="-2">C</font></a> 
    ++<a href="#W"><font size="-2">W</font></a> 
    ++ <a href="#topheader"><font size="-2">TOP</font></a>
    ++<p><div style="line-height:1.5em;color:black">
    ++<nobr><A HREF="android.support.v4.app.ActivityCompat.html#android.support.v4.app.ActivityCompat.ctor_changed()" class="hiddenlink" target="rightframe">ActivityCompat
    ++()</A></nobr>&nbsp;constructor<br>
    ++<A NAME="C"></A>
    ++<br><font size="+2">C</font>&nbsp;
    ++<a href="#A"><font size="-2">A</font></a> 
    ++<a href="#W"><font size="-2">W</font></a> 
    ++ <a href="#topheader"><font size="-2">TOP</font></a>
    ++<p><div style="line-height:1.5em;color:black">
    ++<nobr><A HREF="android.support.v4.content.ContextCompat.html#android.support.v4.content.ContextCompat.ctor_changed()" class="hiddenlink" target="rightframe">ContextCompat
    ++()</A></nobr>&nbsp;constructor<br>
    ++<A NAME="W"></A>
    ++<br><font size="+2">W</font>&nbsp;
    ++<a href="#A"><font size="-2">A</font></a> 
    ++<a href="#C"><font size="-2">C</font></a> 
    ++ <a href="#topheader"><font size="-2">TOP</font></a>
    ++<p><div style="line-height:1.5em;color:black">
    ++<nobr><A HREF="android.support.v4.view.WindowInsetsCompat.html#android.support.v4.view.WindowInsetsCompat.ctor_added(android.support.v4.view.WindowInsetsCompat)" class="hiddenlink" target="rightframe"><b>WindowInsetsCompat</b>
    ++(<code>WindowInsetsCompat</code>)</A></nobr>&nbsp;constructor<br>
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    ++</script>
    ++<script type="text/javascript">
    ++  try {
    ++    var pageTracker = _gat._getTracker("UA-5831155-1");
    ++    pageTracker._setAllowAnchor(true);
    ++    pageTracker._initData();
    ++    pageTracker._trackPageview();
    ++  } catch(e) {}
    ++</script>
    ++</BODY>
    ++</HTML>
    +diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/constructors_index_changes.html b/docs/html/sdk/support_api_diff/24.2.0/changes/constructors_index_changes.html
    +new file mode 100644
    +index 0000000..62a75f8
    +--- /dev/null
    ++++ b/docs/html/sdk/support_api_diff/24.2.0/changes/constructors_index_changes.html
    +@@ -0,0 +1,75 @@
    ++<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
    ++<HTML style="overflow:auto;">
    ++<HEAD>
    ++<meta name="generator" content="JDiff v1.1.0">
    ++<!-- Generated by the JDiff Javadoc doclet -->
    ++<!-- (http://www.jdiff.org) -->
    ++<meta name="description" content="JDiff is a Javadoc doclet which generates an HTML report of all the packages, classes, constructors, methods, and fields which have been removed, added or changed in any way, including their documentation, when two APIs are compared.">
    ++<meta name="keywords" content="diff, jdiff, javadiff, java diff, java difference, API difference, difference between two APIs, API diff, Javadoc, doclet">
    ++<TITLE>
    ++Constructor Changes Index
    ++</TITLE>
    ++<link href="../../../../assets/android-developer-docs.css" rel="stylesheet" type="text/css" />
    ++<link href="../stylesheet-jdiff.css" rel="stylesheet" type="text/css" />
    ++<noscript>
    ++<style type="text/css">
    ++body{overflow:auto;}
    ++#body-content{position:relative; top:0;}
    ++#doc-content{overflow:visible;border-left:3px solid #666;}
    ++#side-nav{padding:0;}
    ++#side-nav .toggle-list ul {display:block;}
    ++#resize-packages-nav{border-bottom:3px solid #666;}
    ++</style>
    ++</noscript>
    ++<style type="text/css">
    ++</style>
    ++</HEAD>
    ++<BODY class="gc-documentation" style="padding:12px;">
    ++<a NAME="topheader"></a>
    ++<table summary="Index for Constructors" width="100%" class="jdiffIndex" border="0" cellspacing="0" cellpadding="0" style="padding-bottom:0;margin-bottom:0;">
    ++  <tr>
    ++  <th class="indexHeader">
    ++    Filter the Index:
    ++  </th>
    ++  </tr>
    ++  <tr>
    ++  <td class="indexText" style="line-height:1.3em;padding-left:2em;">
    ++<a href="constructors_index_all.html" class="staysblack">All Constructors</a>
    ++  <br>
    ++<font color="#999999">Removals</font>
    ++  <br>
    ++<A HREF="constructors_index_additions.html"xclass="hiddenlink">Additions</A>
    ++  <br>
    ++<b>Changes</b>
    ++  </td>
    ++  </tr>
    ++</table>
    ++<div id="indexTableCaption" style="background-color:#eee;padding:0 4px 0 4px;font-size:11px;margin-bottom:1em;">
    ++Listed as: <span style="color:#069"><strong>Added</strong></span>,  <span style="color:#069"><strike>Removed</strike></span>,  <span style="color:#069">Changed</span></font>
    ++</div>
    ++<A NAME="A"></A>
    ++<br><font size="+2">A</font>&nbsp;
    ++<a href="#C"><font size="-2">C</font></a> 
    ++ <a href="#topheader"><font size="-2">TOP</font></a>
    ++<p><div style="line-height:1.5em;color:black">
    ++<nobr><A HREF="android.support.v4.app.ActivityCompat.html#android.support.v4.app.ActivityCompat.ctor_changed()" class="hiddenlink" target="rightframe">ActivityCompat
    ++()</A></nobr>&nbsp;constructor<br>
    ++<A NAME="C"></A>
    ++<br><font size="+2">C</font>&nbsp;
    ++<a href="#A"><font size="-2">A</font></a> 
    ++ <a href="#topheader"><font size="-2">TOP</font></a>
    ++<p><div style="line-height:1.5em;color:black">
    ++<nobr><A HREF="android.support.v4.content.ContextCompat.html#android.support.v4.content.ContextCompat.ctor_changed()" class="hiddenlink" target="rightframe">ContextCompat
    ++()</A></nobr>&nbsp;constructor<br>
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    ++</script>
    ++<script type="text/javascript">
    ++  try {
    ++    var pageTracker = _gat._getTracker("UA-5831155-1");
    ++    pageTracker._setAllowAnchor(true);
    ++    pageTracker._initData();
    ++    pageTracker._trackPageview();
    ++  } catch(e) {}
    ++</script>
    ++</BODY>
    ++</HTML>
    +diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/constructors_index_removals.html b/docs/html/sdk/support_api_diff/24.2.0/changes/constructors_index_removals.html
    +new file mode 100644
    +index 0000000..2fbd2e1
    +--- /dev/null
    ++++ b/docs/html/sdk/support_api_diff/24.2.0/changes/constructors_index_removals.html
    +@@ -0,0 +1,61 @@
    ++<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
    ++<HTML style="overflow:auto;">
    ++<HEAD>
    ++<meta name="generator" content="JDiff v1.1.0">
    ++<!-- Generated by the JDiff Javadoc doclet -->
    ++<!-- (http://www.jdiff.org) -->
    ++<meta name="description" content="JDiff is a Javadoc doclet which generates an HTML report of all the packages, classes, constructors, methods, and fields which have been removed, added or changed in any way, including their documentation, when two APIs are compared.">
    ++<meta name="keywords" content="diff, jdiff, javadiff, java diff, java difference, API difference, difference between two APIs, API diff, Javadoc, doclet">
    ++<TITLE>
    ++Constructor Removals Index
    ++</TITLE>
    ++<link href="../../../../assets/android-developer-docs.css" rel="stylesheet" type="text/css" />
    ++<link href="../stylesheet-jdiff.css" rel="stylesheet" type="text/css" />
    ++<noscript>
    ++<style type="text/css">
    ++body{overflow:auto;}
    ++#body-content{position:relative; top:0;}
    ++#doc-content{overflow:visible;border-left:3px solid #666;}
    ++#side-nav{padding:0;}
    ++#side-nav .toggle-list ul {display:block;}
    ++#resize-packages-nav{border-bottom:3px solid #666;}
    ++</style>
    ++</noscript>
    ++<style type="text/css">
    ++</style>
    ++</HEAD>
    ++<BODY class="gc-documentation" style="padding:12px;">
    ++<a NAME="topheader"></a>
    ++<table summary="Index for Constructors" width="100%" class="jdiffIndex" border="0" cellspacing="0" cellpadding="0" style="padding-bottom:0;margin-bottom:0;">
    ++  <tr>
    ++  <th class="indexHeader">
    ++    Filter the Index:
    ++  </th>
    ++  </tr>
    ++  <tr>
    ++  <td class="indexText" style="line-height:1.3em;padding-left:2em;">
    ++<a href="constructors_index_all.html" class="staysblack">All Constructors</a>
    ++  <br>
    ++<font color="#999999">Removals</font>
    ++  <br>
    ++<A HREF="constructors_index_additions.html"xclass="hiddenlink">Additions</A>
    ++  <br>
    ++<A HREF="constructors_index_changes.html"xclass="hiddenlink">Changes</A>
    ++  </td>
    ++  </tr>
    ++</table>
    ++<div id="indexTableCaption" style="background-color:#eee;padding:0 4px 0 4px;font-size:11px;margin-bottom:1em;">
    ++Listed as: <span style="color:#069"><strong>Added</strong></span>,  <span style="color:#069"><strike>Removed</strike></span>,  <span style="color:#069">Changed</span></font>
    ++</div>
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    ++</script>
    ++<script type="text/javascript">
    ++  try {
    ++    var pageTracker = _gat._getTracker("UA-5831155-1");
    ++    pageTracker._setAllowAnchor(true);
    ++    pageTracker._initData();
    ++    pageTracker._trackPageview();
    ++  } catch(e) {}
    ++</script>
    ++</BODY>
    ++</HTML>
    +diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/fields_index_additions.html b/docs/html/sdk/support_api_diff/24.2.0/changes/fields_index_additions.html
    +new file mode 100644
    +index 0000000..cdb8ee8
    +--- /dev/null
    ++++ b/docs/html/sdk/support_api_diff/24.2.0/changes/fields_index_additions.html
    +@@ -0,0 +1,267 @@
    ++<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
    ++<HTML style="overflow:auto;">
    ++<HEAD>
    ++<meta name="generator" content="JDiff v1.1.0">
    ++<!-- Generated by the JDiff Javadoc doclet -->
    ++<!-- (http://www.jdiff.org) -->
    ++<meta name="description" content="JDiff is a Javadoc doclet which generates an HTML report of all the packages, classes, constructors, methods, and fields which have been removed, added or changed in any way, including their documentation, when two APIs are compared.">
    ++<meta name="keywords" content="diff, jdiff, javadiff, java diff, java difference, API difference, difference between two APIs, API diff, Javadoc, doclet">
    ++<TITLE>
    ++Field Additions Index
    ++</TITLE>
    ++<link href="../../../../assets/android-developer-docs.css" rel="stylesheet" type="text/css" />
    ++<link href="../stylesheet-jdiff.css" rel="stylesheet" type="text/css" />
    ++<noscript>
    ++<style type="text/css">
    ++body{overflow:auto;}
    ++#body-content{position:relative; top:0;}
    ++#doc-content{overflow:visible;border-left:3px solid #666;}
    ++#side-nav{padding:0;}
    ++#side-nav .toggle-list ul {display:block;}
    ++#resize-packages-nav{border-bottom:3px solid #666;}
    ++</style>
    ++</noscript>
    ++<style type="text/css">
    ++</style>
    ++</HEAD>
    ++<BODY class="gc-documentation" style="padding:12px;">
    ++<a NAME="topheader"></a>
    ++<table summary="Index for Fields" width="100%" class="jdiffIndex" border="0" cellspacing="0" cellpadding="0" style="padding-bottom:0;margin-bottom:0;">
    ++  <tr>
    ++  <th class="indexHeader">
    ++    Filter the Index:
    ++  </th>
    ++  </tr>
    ++  <tr>
    ++  <td class="indexText" style="line-height:1.3em;padding-left:2em;">
    ++<a href="fields_index_all.html" class="staysblack">All Fields</a>
    ++  <br>
    ++<A HREF="fields_index_removals.html" xclass="hiddenlink">Removals</A>
    ++  <br>
    ++<b>Additions</b>
    ++  <br>
    ++<A HREF="fields_index_changes.html"xclass="hiddenlink">Changes</A>
    ++  </td>
    ++  </tr>
    ++</table>
    ++<div id="indexTableCaption" style="background-color:#eee;padding:0 4px 0 4px;font-size:11px;margin-bottom:1em;">
    ++Listed as: <span style="color:#069"><strong>Added</strong></span>,  <span style="color:#069"><strike>Removed</strike></span>,  <span style="color:#069">Changed</span></font>
    ++</div>
    ++<A NAME="A"></A>
    ++<br><font size="+2">A</font>&nbsp;
    ++<a href="#B"><font size="-2">B</font></a> 
    ++<a href="#D"><font size="-2">D</font></a> 
    ++<a href="#E"><font size="-2">E</font></a> 
    ++<a href="#H"><font size="-2">H</font></a> 
    ++<a href="#I"><font size="-2">I</font></a> 
    ++<a href="#M"><font size="-2">M</font></a> 
    ++<a href="#P"><font size="-2">P</font></a> 
    ++<a href="#S"><font size="-2">S</font></a> 
    ++<a href="#T"><font size="-2">T</font></a> 
    ++ <a href="#topheader"><font size="-2">TOP</font></a>
    ++<p><div style="line-height:1.5em;color:black">
    ++<nobr><A HREF="android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.html#android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.ACTION_ARGUMENT_COLUMN_INT" class="hiddenlink" target="rightframe">ACTION_ARGUMENT_COLUMN_INT</A>
    ++</nobr><br>
    ++<nobr><A HREF="android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.html#android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.ACTION_ARGUMENT_PROGRESS_VALUE" class="hiddenlink" target="rightframe">ACTION_ARGUMENT_PROGRESS_VALUE</A>
    ++</nobr><br>
    ++<nobr><A HREF="android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.html#android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.ACTION_ARGUMENT_ROW_INT" class="hiddenlink" target="rightframe">ACTION_ARGUMENT_ROW_INT</A>
    ++</nobr><br>
    ++<nobr><A HREF="android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat.html#android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat.ACTION_CONTEXT_CLICK" class="hiddenlink" target="rightframe">ACTION_CONTEXT_CLICK</A>
    ++</nobr><br>
    ++<nobr><A HREF="android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat.html#android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat.ACTION_SCROLL_DOWN" class="hiddenlink" target="rightframe">ACTION_SCROLL_DOWN</A>
    ++</nobr><br>
    ++<nobr><A HREF="android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat.html#android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat.ACTION_SCROLL_LEFT" class="hiddenlink" target="rightframe">ACTION_SCROLL_LEFT</A>
    ++</nobr><br>
    ++<nobr><A HREF="android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat.html#android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat.ACTION_SCROLL_RIGHT" class="hiddenlink" target="rightframe">ACTION_SCROLL_RIGHT</A>
    ++</nobr><br>
    ++<nobr><A HREF="android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat.html#android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat.ACTION_SCROLL_TO_POSITION" class="hiddenlink" target="rightframe">ACTION_SCROLL_TO_POSITION</A>
    ++</nobr><br>
    ++<nobr><A HREF="android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat.html#android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat.ACTION_SCROLL_UP" class="hiddenlink" target="rightframe">ACTION_SCROLL_UP</A>
    ++</nobr><br>
    ++<nobr><A HREF="android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat.html#android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat.ACTION_SET_PROGRESS" class="hiddenlink" target="rightframe">ACTION_SET_PROGRESS</A>
    ++</nobr><br>
    ++<nobr><A HREF="android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat.html#android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat.ACTION_SHOW_ON_SCREEN" class="hiddenlink" target="rightframe">ACTION_SHOW_ON_SCREEN</A>
    ++</nobr><br>
    ++<A NAME="B"></A>
    ++<br><font size="+2">B</font>&nbsp;
    ++<a href="#A"><font size="-2">A</font></a> 
    ++<a href="#D"><font size="-2">D</font></a> 
    ++<a href="#E"><font size="-2">E</font></a> 
    ++<a href="#H"><font size="-2">H</font></a> 
    ++<a href="#I"><font size="-2">I</font></a> 
    ++<a href="#M"><font size="-2">M</font></a> 
    ++<a href="#P"><font size="-2">P</font></a> 
    ++<a href="#S"><font size="-2">S</font></a> 
    ++<a href="#T"><font size="-2">T</font></a> 
    ++ <a href="#topheader"><font size="-2">TOP</font></a>
    ++<p><div style="line-height:1.5em;color:black">
    ++<nobr><A HREF="android.support.v4.media.MediaDescriptionCompat.html#android.support.v4.media.MediaDescriptionCompat.BT_FOLDER_TYPE_ALBUMS" class="hiddenlink" target="rightframe">BT_FOLDER_TYPE_ALBUMS</A>
    ++</nobr><br>
    ++<nobr><A HREF="android.support.v4.media.MediaDescriptionCompat.html#android.support.v4.media.MediaDescriptionCompat.BT_FOLDER_TYPE_ARTISTS" class="hiddenlink" target="rightframe">BT_FOLDER_TYPE_ARTISTS</A>
    ++</nobr><br>
    ++<nobr><A HREF="android.support.v4.media.MediaDescriptionCompat.html#android.support.v4.media.MediaDescriptionCompat.BT_FOLDER_TYPE_GENRES" class="hiddenlink" target="rightframe">BT_FOLDER_TYPE_GENRES</A>
    ++</nobr><br>
    ++<nobr><A HREF="android.support.v4.media.MediaDescriptionCompat.html#android.support.v4.media.MediaDescriptionCompat.BT_FOLDER_TYPE_MIXED" class="hiddenlink" target="rightframe">BT_FOLDER_TYPE_MIXED</A>
    ++</nobr><br>
    ++<nobr><A HREF="android.support.v4.media.MediaDescriptionCompat.html#android.support.v4.media.MediaDescriptionCompat.BT_FOLDER_TYPE_PLAYLISTS" class="hiddenlink" target="rightframe">BT_FOLDER_TYPE_PLAYLISTS</A>
    ++</nobr><br>
    ++<nobr><A HREF="android.support.v4.media.MediaDescriptionCompat.html#android.support.v4.media.MediaDescriptionCompat.BT_FOLDER_TYPE_TITLES" class="hiddenlink" target="rightframe">BT_FOLDER_TYPE_TITLES</A>
    ++</nobr><br>
    ++<nobr><A HREF="android.support.v4.media.MediaDescriptionCompat.html#android.support.v4.media.MediaDescriptionCompat.BT_FOLDER_TYPE_YEARS" class="hiddenlink" target="rightframe">BT_FOLDER_TYPE_YEARS</A>
    ++</nobr><br>
    ++<A NAME="D"></A>
    ++<br><font size="+2">D</font>&nbsp;
    ++<a href="#A"><font size="-2">A</font></a> 
    ++<a href="#B"><font size="-2">B</font></a> 
    ++<a href="#E"><font size="-2">E</font></a> 
    ++<a href="#H"><font size="-2">H</font></a> 
    ++<a href="#I"><font size="-2">I</font></a> 
    ++<a href="#M"><font size="-2">M</font></a> 
    ++<a href="#P"><font size="-2">P</font></a> 
    ++<a href="#S"><font size="-2">S</font></a> 
    ++<a href="#T"><font size="-2">T</font></a> 
    ++ <a href="#topheader"><font size="-2">TOP</font></a>
    ++<p><div style="line-height:1.5em;color:black">
    ++<nobr><A HREF="android.support.design.widget.CoordinatorLayout.LayoutParams.html#android.support.design.widget.CoordinatorLayout.LayoutParams.dodgeInsetEdges" class="hiddenlink" target="rightframe">dodgeInsetEdges</A>
    ++</nobr><br>
    ++<A NAME="E"></A>
    ++<br><font size="+2">E</font>&nbsp;
    ++<a href="#A"><font size="-2">A</font></a> 
    ++<a href="#B"><font size="-2">B</font></a> 
    ++<a href="#D"><font size="-2">D</font></a> 
    ++<a href="#H"><font size="-2">H</font></a> 
    ++<a href="#I"><font size="-2">I</font></a> 
    ++<a href="#M"><font size="-2">M</font></a> 
    ++<a href="#P"><font size="-2">P</font></a> 
    ++<a href="#S"><font size="-2">S</font></a> 
    ++<a href="#T"><font size="-2">T</font></a> 
    ++ <a href="#topheader"><font size="-2">TOP</font></a>
    ++<p><div style="line-height:1.5em;color:black">
    ++<nobr><A HREF="android.support.v4.media.MediaDescriptionCompat.html#android.support.v4.media.MediaDescriptionCompat.EXTRA_BT_FOLDER_TYPE" class="hiddenlink" target="rightframe">EXTRA_BT_FOLDER_TYPE</A>
    ++</nobr><br>
    ++<nobr><A HREF="android.support.customtabs.CustomTabsIntent.html#android.support.customtabs.CustomTabsIntent.EXTRA_ENABLE_INSTANT_APPS" class="hiddenlink" target="rightframe">EXTRA_ENABLE_INSTANT_APPS</A>
    ++</nobr><br>
    ++<nobr><A HREF="android.support.v4.media.MediaBrowserServiceCompat.BrowserRoot.html#android.support.v4.media.MediaBrowserServiceCompat.BrowserRoot.EXTRA_SUGGESTION_KEYWORDS" class="hiddenlink" target="rightframe">EXTRA_SUGGESTION_KEYWORDS</A>
    ++</nobr><br>
    ++<nobr><A HREF="android.support.v4.app.ActivityOptionsCompat.html#android.support.v4.app.ActivityOptionsCompat.EXTRA_USAGE_TIME_REPORT" class="hiddenlink" target="rightframe">EXTRA_USAGE_TIME_REPORT</A>
    ++</nobr><br>
    ++<nobr><A HREF="android.support.v4.app.ActivityOptionsCompat.html#android.support.v4.app.ActivityOptionsCompat.EXTRA_USAGE_TIME_REPORT_PACKAGES" class="hiddenlink" target="rightframe">EXTRA_USAGE_TIME_REPORT_PACKAGES</A>
    ++</nobr><br>
    ++<A NAME="H"></A>
    ++<br><font size="+2">H</font>&nbsp;
    ++<a href="#A"><font size="-2">A</font></a> 
    ++<a href="#B"><font size="-2">B</font></a> 
    ++<a href="#D"><font size="-2">D</font></a> 
    ++<a href="#E"><font size="-2">E</font></a> 
    ++<a href="#I"><font size="-2">I</font></a> 
    ++<a href="#M"><font size="-2">M</font></a> 
    ++<a href="#P"><font size="-2">P</font></a> 
    ++<a href="#S"><font size="-2">S</font></a> 
    ++<a href="#T"><font size="-2">T</font></a> 
    ++ <a href="#topheader"><font size="-2">TOP</font></a>
    ++<p><div style="line-height:1.5em;color:black">
    ++<nobr><A HREF="android.support.v4.view.accessibility.AccessibilityNodeProviderCompat.html#android.support.v4.view.accessibility.AccessibilityNodeProviderCompat.HOST_VIEW_ID" class="hiddenlink" target="rightframe">HOST_VIEW_ID</A>
    ++</nobr><br>
    ++<A NAME="I"></A>
    ++<br><font size="+2">I</font>&nbsp;
    ++<a href="#A"><font size="-2">A</font></a> 
    ++<a href="#B"><font size="-2">B</font></a> 
    ++<a href="#D"><font size="-2">D</font></a> 
    ++<a href="#E"><font size="-2">E</font></a> 
    ++<a href="#H"><font size="-2">H</font></a> 
    ++<a href="#M"><font size="-2">M</font></a> 
    ++<a href="#P"><font size="-2">P</font></a> 
    ++<a href="#S"><font size="-2">S</font></a> 
    ++<a href="#T"><font size="-2">T</font></a> 
    ++ <a href="#topheader"><font size="-2">TOP</font></a>
    ++<p><div style="line-height:1.5em;color:black">
    ++<nobr><A HREF="android.support.design.widget.CoordinatorLayout.LayoutParams.html#android.support.design.widget.CoordinatorLayout.LayoutParams.insetEdge" class="hiddenlink" target="rightframe">insetEdge</A>
    ++</nobr><br>
    ++<A NAME="M"></A>
    ++<br><font size="+2">M</font>&nbsp;
    ++<a href="#A"><font size="-2">A</font></a> 
    ++<a href="#B"><font size="-2">B</font></a> 
    ++<a href="#D"><font size="-2">D</font></a> 
    ++<a href="#E"><font size="-2">E</font></a> 
    ++<a href="#H"><font size="-2">H</font></a> 
    ++<a href="#I"><font size="-2">I</font></a> 
    ++<a href="#P"><font size="-2">P</font></a> 
    ++<a href="#S"><font size="-2">S</font></a> 
    ++<a href="#T"><font size="-2">T</font></a> 
    ++ <a href="#topheader"><font size="-2">TOP</font></a>
    ++<p><div style="line-height:1.5em;color:black">
    ++<nobr><A HREF="android.support.v4.media.MediaMetadataCompat.html#android.support.v4.media.MediaMetadataCompat.METADATA_KEY_BT_FOLDER_TYPE" class="hiddenlink" target="rightframe">METADATA_KEY_BT_FOLDER_TYPE</A>
    ++</nobr><br>
    ++<nobr><A HREF="android.support.v4.media.MediaMetadataCompat.html#android.support.v4.media.MediaMetadataCompat.METADATA_KEY_MEDIA_URI" class="hiddenlink" target="rightframe">METADATA_KEY_MEDIA_URI</A>
    ++</nobr><br>
    ++<A NAME="P"></A>
    ++<br><font size="+2">P</font>&nbsp;
    ++<a href="#A"><font size="-2">A</font></a> 
    ++<a href="#B"><font size="-2">B</font></a> 
    ++<a href="#D"><font size="-2">D</font></a> 
    ++<a href="#E"><font size="-2">E</font></a> 
    ++<a href="#H"><font size="-2">H</font></a> 
    ++<a href="#I"><font size="-2">I</font></a> 
    ++<a href="#M"><font size="-2">M</font></a> 
    ++<a href="#S"><font size="-2">S</font></a> 
    ++<a href="#T"><font size="-2">T</font></a> 
    ++ <a href="#topheader"><font size="-2">TOP</font></a>
    ++<p><div style="line-height:1.5em;color:black">
    ++<nobr><A HREF="android.support.design.widget.BottomSheetBehavior.html#android.support.design.widget.BottomSheetBehavior.PEEK_HEIGHT_AUTO" class="hiddenlink" target="rightframe">PEEK_HEIGHT_AUTO</A>
    ++</nobr><br>
    ++<nobr><A HREF="android.support.v17.leanback.widget.AbstractMediaItemPresenter.html#android.support.v17.leanback.widget.AbstractMediaItemPresenter.PLAY_STATE_INITIAL" class="hiddenlink" target="rightframe">PLAY_STATE_INITIAL</A>
    ++</nobr><br>
    ++<nobr><A HREF="android.support.v17.leanback.widget.AbstractMediaItemPresenter.html#android.support.v17.leanback.widget.AbstractMediaItemPresenter.PLAY_STATE_PAUSED" class="hiddenlink" target="rightframe">PLAY_STATE_PAUSED</A>
    ++</nobr><br>
    ++<nobr><A HREF="android.support.v17.leanback.widget.AbstractMediaItemPresenter.html#android.support.v17.leanback.widget.AbstractMediaItemPresenter.PLAY_STATE_PLAYING" class="hiddenlink" target="rightframe">PLAY_STATE_PLAYING</A>
    ++</nobr><br>
    ++<A NAME="S"></A>
    ++<br><font size="+2">S</font>&nbsp;
    ++<a href="#A"><font size="-2">A</font></a> 
    ++<a href="#B"><font size="-2">B</font></a> 
    ++<a href="#D"><font size="-2">D</font></a> 
    ++<a href="#E"><font size="-2">E</font></a> 
    ++<a href="#H"><font size="-2">H</font></a> 
    ++<a href="#I"><font size="-2">I</font></a> 
    ++<a href="#M"><font size="-2">M</font></a> 
    ++<a href="#P"><font size="-2">P</font></a> 
    ++<a href="#T"><font size="-2">T</font></a> 
    ++ <a href="#topheader"><font size="-2">TOP</font></a>
    ++<p><div style="line-height:1.5em;color:black">
    ++<nobr><A HREF="android.support.v4.app.ServiceCompat.html#android.support.v4.app.ServiceCompat.STOP_FOREGROUND_DETACH" class="hiddenlink" target="rightframe">STOP_FOREGROUND_DETACH</A>
    ++</nobr><br>
    ++<nobr><A HREF="android.support.v4.app.ServiceCompat.html#android.support.v4.app.ServiceCompat.STOP_FOREGROUND_REMOVE" class="hiddenlink" target="rightframe">STOP_FOREGROUND_REMOVE</A>
    ++</nobr><br>
    ++<A NAME="T"></A>
    ++<br><font size="+2">T</font>&nbsp;
    ++<a href="#A"><font size="-2">A</font></a> 
    ++<a href="#B"><font size="-2">B</font></a> 
    ++<a href="#D"><font size="-2">D</font></a> 
    ++<a href="#E"><font size="-2">E</font></a> 
    ++<a href="#H"><font size="-2">H</font></a> 
    ++<a href="#I"><font size="-2">I</font></a> 
    ++<a href="#M"><font size="-2">M</font></a> 
    ++<a href="#P"><font size="-2">P</font></a> 
    ++<a href="#S"><font size="-2">S</font></a> 
    ++ <a href="#topheader"><font size="-2">TOP</font></a>
    ++<p><div style="line-height:1.5em;color:black">
    ++<nobr><A HREF="android.support.v4.view.accessibility.AccessibilityEventCompat.html#android.support.v4.view.accessibility.AccessibilityEventCompat.TYPE_ASSIST_READING_CONTEXT" class="hiddenlink" target="rightframe">TYPE_ASSIST_READING_CONTEXT</A>
    ++</nobr><br>
    ++<nobr><A HREF="android.support.v4.view.accessibility.AccessibilityWindowInfoCompat.html#android.support.v4.view.accessibility.AccessibilityWindowInfoCompat.TYPE_SPLIT_SCREEN_DIVIDER" class="hiddenlink" target="rightframe">TYPE_SPLIT_SCREEN_DIVIDER</A>
    ++</nobr><br>
    ++<nobr><A HREF="android.support.v4.view.accessibility.AccessibilityEventCompat.html#android.support.v4.view.accessibility.AccessibilityEventCompat.TYPE_VIEW_CONTEXT_CLICKED" class="hiddenlink" target="rightframe">TYPE_VIEW_CONTEXT_CLICKED</A>
    ++</nobr><br>
    ++<nobr><A HREF="android.support.v4.view.accessibility.AccessibilityEventCompat.html#android.support.v4.view.accessibility.AccessibilityEventCompat.TYPE_WINDOWS_CHANGED" class="hiddenlink" target="rightframe">TYPE_WINDOWS_CHANGED</A>
    ++</nobr><br>
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    ++</script>
    ++<script type="text/javascript">
    ++  try {
    ++    var pageTracker = _gat._getTracker("UA-5831155-1");
    ++    pageTracker._setAllowAnchor(true);
    ++    pageTracker._initData();
    ++    pageTracker._trackPageview();
    ++  } catch(e) {}
    ++</script>
    ++</BODY>
    ++</HTML>
    +diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/fields_index_all.html b/docs/html/sdk/support_api_diff/24.2.0/changes/fields_index_all.html
    +new file mode 100644
    +index 0000000..14b3e97
    +--- /dev/null
    ++++ b/docs/html/sdk/support_api_diff/24.2.0/changes/fields_index_all.html
    +@@ -0,0 +1,299 @@
    ++<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
    ++<HTML style="overflow:auto;">
    ++<HEAD>
    ++<meta name="generator" content="JDiff v1.1.0">
    ++<!-- Generated by the JDiff Javadoc doclet -->
    ++<!-- (http://www.jdiff.org) -->
    ++<meta name="description" content="JDiff is a Javadoc doclet which generates an HTML report of all the packages, classes, constructors, methods, and fields which have been removed, added or changed in any way, including their documentation, when two APIs are compared.">
    ++<meta name="keywords" content="diff, jdiff, javadiff, java diff, java difference, API difference, difference between two APIs, API diff, Javadoc, doclet">
    ++<TITLE>
    ++Field Differences Index
    ++</TITLE>
    ++<link href="../../../../assets/android-developer-docs.css" rel="stylesheet" type="text/css" />
    ++<link href="../stylesheet-jdiff.css" rel="stylesheet" type="text/css" />
    ++<noscript>
    ++<style type="text/css">
    ++body{overflow:auto;}
    ++#body-content{position:relative; top:0;}
    ++#doc-content{overflow:visible;border-left:3px solid #666;}
    ++#side-nav{padding:0;}
    ++#side-nav .toggle-list ul {display:block;}
    ++#resize-packages-nav{border-bottom:3px solid #666;}
    ++</style>
    ++</noscript>
    ++<style type="text/css">
    ++</style>
    ++</HEAD>
    ++<BODY class="gc-documentation" style="padding:12px;">
    ++<a NAME="topheader"></a>
    ++<table summary="Index for Fields" width="100%" class="jdiffIndex" border="0" cellspacing="0" cellpadding="0" style="padding-bottom:0;margin-bottom:0;">
    ++  <tr>
    ++  <th class="indexHeader">
    ++    Filter the Index:
    ++  </th>
    ++  </tr>
    ++  <tr>
    ++  <td class="indexText" style="line-height:1.3em;padding-left:2em;">
    ++<b>Fields</b>
    ++  <br>
    ++<A HREF="fields_index_removals.html" xclass="hiddenlink">Removals</A>
    ++  <br>
    ++<A HREF="fields_index_additions.html"xclass="hiddenlink">Additions</A>
    ++  <br>
    ++<A HREF="fields_index_changes.html"xclass="hiddenlink">Changes</A>
    ++  </td>
    ++  </tr>
    ++</table>
    ++<div id="indexTableCaption" style="background-color:#eee;padding:0 4px 0 4px;font-size:11px;margin-bottom:1em;">
    ++Listed as: <span style="color:#069"><strong>Added</strong></span>,  <span style="color:#069"><strike>Removed</strike></span>,  <span style="color:#069">Changed</span></font>
    ++</div>
    ++<A NAME="A"></A>
    ++<br><font size="+2">A</font>&nbsp;
    ++<a href="#B"><font size="-2">B</font></a> 
    ++<a href="#D"><font size="-2">D</font></a> 
    ++<a href="#E"><font size="-2">E</font></a> 
    ++<a href="#H"><font size="-2">H</font></a> 
    ++<a href="#I"><font size="-2">I</font></a> 
    ++<a href="#M"><font size="-2">M</font></a> 
    ++<a href="#O"><font size="-2">O</font></a> 
    ++<a href="#P"><font size="-2">P</font></a> 
    ++<a href="#S"><font size="-2">S</font></a> 
    ++<a href="#T"><font size="-2">T</font></a> 
    ++ <a href="#topheader"><font size="-2">TOP</font></a>
    ++<p><div style="line-height:1.5em;color:black">
    ++<nobr><A HREF="android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.html#android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.ACTION_ARGUMENT_COLUMN_INT" class="hiddenlink" target="rightframe">ACTION_ARGUMENT_COLUMN_INT</A>
    ++</nobr><br>
    ++<nobr><A HREF="android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.html#android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.ACTION_ARGUMENT_PROGRESS_VALUE" class="hiddenlink" target="rightframe">ACTION_ARGUMENT_PROGRESS_VALUE</A>
    ++</nobr><br>
    ++<nobr><A HREF="android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.html#android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.ACTION_ARGUMENT_ROW_INT" class="hiddenlink" target="rightframe">ACTION_ARGUMENT_ROW_INT</A>
    ++</nobr><br>
    ++<nobr><A HREF="android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat.html#android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat.ACTION_CONTEXT_CLICK" class="hiddenlink" target="rightframe">ACTION_CONTEXT_CLICK</A>
    ++</nobr><br>
    ++<nobr><A HREF="android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat.html#android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat.ACTION_SCROLL_DOWN" class="hiddenlink" target="rightframe">ACTION_SCROLL_DOWN</A>
    ++</nobr><br>
    ++<nobr><A HREF="android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat.html#android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat.ACTION_SCROLL_LEFT" class="hiddenlink" target="rightframe">ACTION_SCROLL_LEFT</A>
    ++</nobr><br>
    ++<nobr><A HREF="android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat.html#android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat.ACTION_SCROLL_RIGHT" class="hiddenlink" target="rightframe">ACTION_SCROLL_RIGHT</A>
    ++</nobr><br>
    ++<nobr><A HREF="android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat.html#android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat.ACTION_SCROLL_TO_POSITION" class="hiddenlink" target="rightframe">ACTION_SCROLL_TO_POSITION</A>
    ++</nobr><br>
    ++<nobr><A HREF="android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat.html#android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat.ACTION_SCROLL_UP" class="hiddenlink" target="rightframe">ACTION_SCROLL_UP</A>
    ++</nobr><br>
    ++<nobr><A HREF="android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat.html#android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat.ACTION_SET_PROGRESS" class="hiddenlink" target="rightframe">ACTION_SET_PROGRESS</A>
    ++</nobr><br>
    ++<nobr><A HREF="android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat.html#android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat.ACTION_SHOW_ON_SCREEN" class="hiddenlink" target="rightframe">ACTION_SHOW_ON_SCREEN</A>
    ++</nobr><br>
    ++<A NAME="B"></A>
    ++<br><font size="+2">B</font>&nbsp;
    ++<a href="#A"><font size="-2">A</font></a> 
    ++<a href="#D"><font size="-2">D</font></a> 
    ++<a href="#E"><font size="-2">E</font></a> 
    ++<a href="#H"><font size="-2">H</font></a> 
    ++<a href="#I"><font size="-2">I</font></a> 
    ++<a href="#M"><font size="-2">M</font></a> 
    ++<a href="#O"><font size="-2">O</font></a> 
    ++<a href="#P"><font size="-2">P</font></a> 
    ++<a href="#S"><font size="-2">S</font></a> 
    ++<a href="#T"><font size="-2">T</font></a> 
    ++ <a href="#topheader"><font size="-2">TOP</font></a>
    ++<p><div style="line-height:1.5em;color:black">
    ++<nobr><A HREF="android.support.v4.media.MediaDescriptionCompat.html#android.support.v4.media.MediaDescriptionCompat.BT_FOLDER_TYPE_ALBUMS" class="hiddenlink" target="rightframe">BT_FOLDER_TYPE_ALBUMS</A>
    ++</nobr><br>
    ++<nobr><A HREF="android.support.v4.media.MediaDescriptionCompat.html#android.support.v4.media.MediaDescriptionCompat.BT_FOLDER_TYPE_ARTISTS" class="hiddenlink" target="rightframe">BT_FOLDER_TYPE_ARTISTS</A>
    ++</nobr><br>
    ++<nobr><A HREF="android.support.v4.media.MediaDescriptionCompat.html#android.support.v4.media.MediaDescriptionCompat.BT_FOLDER_TYPE_GENRES" class="hiddenlink" target="rightframe">BT_FOLDER_TYPE_GENRES</A>
    ++</nobr><br>
    ++<nobr><A HREF="android.support.v4.media.MediaDescriptionCompat.html#android.support.v4.media.MediaDescriptionCompat.BT_FOLDER_TYPE_MIXED" class="hiddenlink" target="rightframe">BT_FOLDER_TYPE_MIXED</A>
    ++</nobr><br>
    ++<nobr><A HREF="android.support.v4.media.MediaDescriptionCompat.html#android.support.v4.media.MediaDescriptionCompat.BT_FOLDER_TYPE_PLAYLISTS" class="hiddenlink" target="rightframe">BT_FOLDER_TYPE_PLAYLISTS</A>
    ++</nobr><br>
    ++<nobr><A HREF="android.support.v4.media.MediaDescriptionCompat.html#android.support.v4.media.MediaDescriptionCompat.BT_FOLDER_TYPE_TITLES" class="hiddenlink" target="rightframe">BT_FOLDER_TYPE_TITLES</A>
    ++</nobr><br>
    ++<nobr><A HREF="android.support.v4.media.MediaDescriptionCompat.html#android.support.v4.media.MediaDescriptionCompat.BT_FOLDER_TYPE_YEARS" class="hiddenlink" target="rightframe">BT_FOLDER_TYPE_YEARS</A>
    ++</nobr><br>
    ++<A NAME="D"></A>
    ++<br><font size="+2">D</font>&nbsp;
    ++<a href="#A"><font size="-2">A</font></a> 
    ++<a href="#B"><font size="-2">B</font></a> 
    ++<a href="#E"><font size="-2">E</font></a> 
    ++<a href="#H"><font size="-2">H</font></a> 
    ++<a href="#I"><font size="-2">I</font></a> 
    ++<a href="#M"><font size="-2">M</font></a> 
    ++<a href="#O"><font size="-2">O</font></a> 
    ++<a href="#P"><font size="-2">P</font></a> 
    ++<a href="#S"><font size="-2">S</font></a> 
    ++<a href="#T"><font size="-2">T</font></a> 
    ++ <a href="#topheader"><font size="-2">TOP</font></a>
    ++<p><div style="line-height:1.5em;color:black">
    ++<nobr><A HREF="android.support.design.widget.CoordinatorLayout.LayoutParams.html#android.support.design.widget.CoordinatorLayout.LayoutParams.dodgeInsetEdges" class="hiddenlink" target="rightframe">dodgeInsetEdges</A>
    ++</nobr><br>
    ++<A NAME="E"></A>
    ++<br><font size="+2">E</font>&nbsp;
    ++<a href="#A"><font size="-2">A</font></a> 
    ++<a href="#B"><font size="-2">B</font></a> 
    ++<a href="#D"><font size="-2">D</font></a> 
    ++<a href="#H"><font size="-2">H</font></a> 
    ++<a href="#I"><font size="-2">I</font></a> 
    ++<a href="#M"><font size="-2">M</font></a> 
    ++<a href="#O"><font size="-2">O</font></a> 
    ++<a href="#P"><font size="-2">P</font></a> 
    ++<a href="#S"><font size="-2">S</font></a> 
    ++<a href="#T"><font size="-2">T</font></a> 
    ++ <a href="#topheader"><font size="-2">TOP</font></a>
    ++<p><div style="line-height:1.5em;color:black">
    ++<nobr><A HREF="android.support.v4.media.MediaDescriptionCompat.html#android.support.v4.media.MediaDescriptionCompat.EXTRA_BT_FOLDER_TYPE" class="hiddenlink" target="rightframe">EXTRA_BT_FOLDER_TYPE</A>
    ++</nobr><br>
    ++<nobr><A HREF="android.support.customtabs.CustomTabsIntent.html#android.support.customtabs.CustomTabsIntent.EXTRA_ENABLE_INSTANT_APPS" class="hiddenlink" target="rightframe">EXTRA_ENABLE_INSTANT_APPS</A>
    ++</nobr><br>
    ++<nobr><A HREF="android.support.v4.media.MediaBrowserServiceCompat.BrowserRoot.html#android.support.v4.media.MediaBrowserServiceCompat.BrowserRoot.EXTRA_SUGGESTION_KEYWORDS" class="hiddenlink" target="rightframe">EXTRA_SUGGESTION_KEYWORDS</A>
    ++</nobr><br>
    ++<nobr><A HREF="android.support.v4.app.ActivityOptionsCompat.html#android.support.v4.app.ActivityOptionsCompat.EXTRA_USAGE_TIME_REPORT" class="hiddenlink" target="rightframe">EXTRA_USAGE_TIME_REPORT</A>
    ++</nobr><br>
    ++<nobr><A HREF="android.support.v4.app.ActivityOptionsCompat.html#android.support.v4.app.ActivityOptionsCompat.EXTRA_USAGE_TIME_REPORT_PACKAGES" class="hiddenlink" target="rightframe">EXTRA_USAGE_TIME_REPORT_PACKAGES</A>
    ++</nobr><br>
    ++<A NAME="H"></A>
    ++<br><font size="+2">H</font>&nbsp;
    ++<a href="#A"><font size="-2">A</font></a> 
    ++<a href="#B"><font size="-2">B</font></a> 
    ++<a href="#D"><font size="-2">D</font></a> 
    ++<a href="#E"><font size="-2">E</font></a> 
    ++<a href="#I"><font size="-2">I</font></a> 
    ++<a href="#M"><font size="-2">M</font></a> 
    ++<a href="#O"><font size="-2">O</font></a> 
    ++<a href="#P"><font size="-2">P</font></a> 
    ++<a href="#S"><font size="-2">S</font></a> 
    ++<a href="#T"><font size="-2">T</font></a> 
    ++ <a href="#topheader"><font size="-2">TOP</font></a>
    ++<p><div style="line-height:1.5em;color:black">
    ++<nobr><A HREF="android.support.v4.view.accessibility.AccessibilityNodeProviderCompat.html#android.support.v4.view.accessibility.AccessibilityNodeProviderCompat.HOST_VIEW_ID" class="hiddenlink" target="rightframe">HOST_VIEW_ID</A>
    ++</nobr><br>
    ++<A NAME="I"></A>
    ++<br><font size="+2">I</font>&nbsp;
    ++<a href="#A"><font size="-2">A</font></a> 
    ++<a href="#B"><font size="-2">B</font></a> 
    ++<a href="#D"><font size="-2">D</font></a> 
    ++<a href="#E"><font size="-2">E</font></a> 
    ++<a href="#H"><font size="-2">H</font></a> 
    ++<a href="#M"><font size="-2">M</font></a> 
    ++<a href="#O"><font size="-2">O</font></a> 
    ++<a href="#P"><font size="-2">P</font></a> 
    ++<a href="#S"><font size="-2">S</font></a> 
    ++<a href="#T"><font size="-2">T</font></a> 
    ++ <a href="#topheader"><font size="-2">TOP</font></a>
    ++<p><div style="line-height:1.5em;color:black">
    ++<nobr><A HREF="android.support.design.widget.CoordinatorLayout.LayoutParams.html#android.support.design.widget.CoordinatorLayout.LayoutParams.insetEdge" class="hiddenlink" target="rightframe">insetEdge</A>
    ++</nobr><br>
    ++<A NAME="M"></A>
    ++<br><font size="+2">M</font>&nbsp;
    ++<a href="#A"><font size="-2">A</font></a> 
    ++<a href="#B"><font size="-2">B</font></a> 
    ++<a href="#D"><font size="-2">D</font></a> 
    ++<a href="#E"><font size="-2">E</font></a> 
    ++<a href="#H"><font size="-2">H</font></a> 
    ++<a href="#I"><font size="-2">I</font></a> 
    ++<a href="#O"><font size="-2">O</font></a> 
    ++<a href="#P"><font size="-2">P</font></a> 
    ++<a href="#S"><font size="-2">S</font></a> 
    ++<a href="#T"><font size="-2">T</font></a> 
    ++ <a href="#topheader"><font size="-2">TOP</font></a>
    ++<p><div style="line-height:1.5em;color:black">
    ++<nobr><A HREF="android.support.v4.media.MediaMetadataCompat.html#android.support.v4.media.MediaMetadataCompat.METADATA_KEY_BT_FOLDER_TYPE" class="hiddenlink" target="rightframe">METADATA_KEY_BT_FOLDER_TYPE</A>
    ++</nobr><br>
    ++<nobr><A HREF="android.support.v4.media.MediaMetadataCompat.html#android.support.v4.media.MediaMetadataCompat.METADATA_KEY_MEDIA_URI" class="hiddenlink" target="rightframe">METADATA_KEY_MEDIA_URI</A>
    ++</nobr><br>
    ++<A NAME="O"></A>
    ++<br><font size="+2">O</font>&nbsp;
    ++<a href="#A"><font size="-2">A</font></a> 
    ++<a href="#B"><font size="-2">B</font></a> 
    ++<a href="#D"><font size="-2">D</font></a> 
    ++<a href="#E"><font size="-2">E</font></a> 
    ++<a href="#H"><font size="-2">H</font></a> 
    ++<a href="#I"><font size="-2">I</font></a> 
    ++<a href="#M"><font size="-2">M</font></a> 
    ++<a href="#P"><font size="-2">P</font></a> 
    ++<a href="#S"><font size="-2">S</font></a> 
    ++<a href="#T"><font size="-2">T</font></a> 
    ++ <a href="#topheader"><font size="-2">TOP</font></a>
    ++<p><div style="line-height:1.5em;color:black">
    ++<nobr><A HREF="android.support.v4.view.ViewCompat.html#android.support.v4.view.ViewCompat.OVER_SCROLL_ALWAYS" class="hiddenlink" target="rightframe">OVER_SCROLL_ALWAYS</A>
    ++</nobr><br>
    ++<nobr><A HREF="android.support.v4.view.ViewCompat.html#android.support.v4.view.ViewCompat.OVER_SCROLL_IF_CONTENT_SCROLLS" class="hiddenlink" target="rightframe">OVER_SCROLL_IF_CONTENT_SCROLLS</A>
    ++</nobr><br>
    ++<nobr><A HREF="android.support.v4.view.ViewCompat.html#android.support.v4.view.ViewCompat.OVER_SCROLL_NEVER" class="hiddenlink" target="rightframe">OVER_SCROLL_NEVER</A>
    ++</nobr><br>
    ++<A NAME="P"></A>
    ++<br><font size="+2">P</font>&nbsp;
    ++<a href="#A"><font size="-2">A</font></a> 
    ++<a href="#B"><font size="-2">B</font></a> 
    ++<a href="#D"><font size="-2">D</font></a> 
    ++<a href="#E"><font size="-2">E</font></a> 
    ++<a href="#H"><font size="-2">H</font></a> 
    ++<a href="#I"><font size="-2">I</font></a> 
    ++<a href="#M"><font size="-2">M</font></a> 
    ++<a href="#O"><font size="-2">O</font></a> 
    ++<a href="#S"><font size="-2">S</font></a> 
    ++<a href="#T"><font size="-2">T</font></a> 
    ++ <a href="#topheader"><font size="-2">TOP</font></a>
    ++<p><div style="line-height:1.5em;color:black">
    ++<nobr><A HREF="android.support.design.widget.BottomSheetBehavior.html#android.support.design.widget.BottomSheetBehavior.PEEK_HEIGHT_AUTO" class="hiddenlink" target="rightframe">PEEK_HEIGHT_AUTO</A>
    ++</nobr><br>
    ++<nobr><A HREF="android.support.v17.leanback.widget.AbstractMediaItemPresenter.html#android.support.v17.leanback.widget.AbstractMediaItemPresenter.PLAY_STATE_INITIAL" class="hiddenlink" target="rightframe">PLAY_STATE_INITIAL</A>
    ++</nobr><br>
    ++<nobr><A HREF="android.support.v17.leanback.widget.AbstractMediaItemPresenter.html#android.support.v17.leanback.widget.AbstractMediaItemPresenter.PLAY_STATE_PAUSED" class="hiddenlink" target="rightframe">PLAY_STATE_PAUSED</A>
    ++</nobr><br>
    ++<nobr><A HREF="android.support.v17.leanback.widget.AbstractMediaItemPresenter.html#android.support.v17.leanback.widget.AbstractMediaItemPresenter.PLAY_STATE_PLAYING" class="hiddenlink" target="rightframe">PLAY_STATE_PLAYING</A>
    ++</nobr><br>
    ++<A NAME="S"></A>
    ++<br><font size="+2">S</font>&nbsp;
    ++<a href="#A"><font size="-2">A</font></a> 
    ++<a href="#B"><font size="-2">B</font></a> 
    ++<a href="#D"><font size="-2">D</font></a> 
    ++<a href="#E"><font size="-2">E</font></a> 
    ++<a href="#H"><font size="-2">H</font></a> 
    ++<a href="#I"><font size="-2">I</font></a> 
    ++<a href="#M"><font size="-2">M</font></a> 
    ++<a href="#O"><font size="-2">O</font></a> 
    ++<a href="#P"><font size="-2">P</font></a> 
    ++<a href="#T"><font size="-2">T</font></a> 
    ++ <a href="#topheader"><font size="-2">TOP</font></a>
    ++<p><div style="line-height:1.5em;color:black">
    ++<nobr><A HREF="android.support.v4.app.ServiceCompat.html#android.support.v4.app.ServiceCompat.STOP_FOREGROUND_DETACH" class="hiddenlink" target="rightframe">STOP_FOREGROUND_DETACH</A>
    ++</nobr><br>
    ++<nobr><A HREF="android.support.v4.app.ServiceCompat.html#android.support.v4.app.ServiceCompat.STOP_FOREGROUND_REMOVE" class="hiddenlink" target="rightframe">STOP_FOREGROUND_REMOVE</A>
    ++</nobr><br>
    ++<A NAME="T"></A>
    ++<br><font size="+2">T</font>&nbsp;
    ++<a href="#A"><font size="-2">A</font></a> 
    ++<a href="#B"><font size="-2">B</font></a> 
    ++<a href="#D"><font size="-2">D</font></a> 
    ++<a href="#E"><font size="-2">E</font></a> 
    ++<a href="#H"><font size="-2">H</font></a> 
    ++<a href="#I"><font size="-2">I</font></a> 
    ++<a href="#M"><font size="-2">M</font></a> 
    ++<a href="#O"><font size="-2">O</font></a> 
    ++<a href="#P"><font size="-2">P</font></a> 
    ++<a href="#S"><font size="-2">S</font></a> 
    ++ <a href="#topheader"><font size="-2">TOP</font></a>
    ++<p><div style="line-height:1.5em;color:black">
    ++<nobr><A HREF="android.support.v7.widget.StaggeredGridLayoutManager.html#android.support.v7.widget.StaggeredGridLayoutManager.TAG" class="hiddenlink" target="rightframe"><strike>TAG</strike></A>
    ++</nobr><br>
    ++<nobr><A HREF="android.support.v4.view.accessibility.AccessibilityEventCompat.html#android.support.v4.view.accessibility.AccessibilityEventCompat.TYPE_ASSIST_READING_CONTEXT" class="hiddenlink" target="rightframe">TYPE_ASSIST_READING_CONTEXT</A>
    ++</nobr><br>
    ++<nobr><A HREF="android.support.v4.view.accessibility.AccessibilityWindowInfoCompat.html#android.support.v4.view.accessibility.AccessibilityWindowInfoCompat.TYPE_SPLIT_SCREEN_DIVIDER" class="hiddenlink" target="rightframe">TYPE_SPLIT_SCREEN_DIVIDER</A>
    ++</nobr><br>
    ++<nobr><A HREF="android.support.v4.view.accessibility.AccessibilityEventCompat.html#android.support.v4.view.accessibility.AccessibilityEventCompat.TYPE_VIEW_CONTEXT_CLICKED" class="hiddenlink" target="rightframe">TYPE_VIEW_CONTEXT_CLICKED</A>
    ++</nobr><br>
    ++<nobr><A HREF="android.support.v4.view.accessibility.AccessibilityEventCompat.html#android.support.v4.view.accessibility.AccessibilityEventCompat.TYPE_WINDOWS_CHANGED" class="hiddenlink" target="rightframe">TYPE_WINDOWS_CHANGED</A>
    ++</nobr><br>
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    ++</script>
    ++<script type="text/javascript">
    ++  try {
    ++    var pageTracker = _gat._getTracker("UA-5831155-1");
    ++    pageTracker._setAllowAnchor(true);
    ++    pageTracker._initData();
    ++    pageTracker._trackPageview();
    ++  } catch(e) {}
    ++</script>
    ++</BODY>
    ++</HTML>
    +diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/fields_index_changes.html b/docs/html/sdk/support_api_diff/24.2.0/changes/fields_index_changes.html
    +new file mode 100644
    +index 0000000..c72b2de
    +--- /dev/null
    ++++ b/docs/html/sdk/support_api_diff/24.2.0/changes/fields_index_changes.html
    +@@ -0,0 +1,71 @@
    ++<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
    ++<HTML style="overflow:auto;">
    ++<HEAD>
    ++<meta name="generator" content="JDiff v1.1.0">
    ++<!-- Generated by the JDiff Javadoc doclet -->
    ++<!-- (http://www.jdiff.org) -->
    ++<meta name="description" content="JDiff is a Javadoc doclet which generates an HTML report of all the packages, classes, constructors, methods, and fields which have been removed, added or changed in any way, including their documentation, when two APIs are compared.">
    ++<meta name="keywords" content="diff, jdiff, javadiff, java diff, java difference, API difference, difference between two APIs, API diff, Javadoc, doclet">
    ++<TITLE>
    ++Field Changes Index
    ++</TITLE>
    ++<link href="../../../../assets/android-developer-docs.css" rel="stylesheet" type="text/css" />
    ++<link href="../stylesheet-jdiff.css" rel="stylesheet" type="text/css" />
    ++<noscript>
    ++<style type="text/css">
    ++body{overflow:auto;}
    ++#body-content{position:relative; top:0;}
    ++#doc-content{overflow:visible;border-left:3px solid #666;}
    ++#side-nav{padding:0;}
    ++#side-nav .toggle-list ul {display:block;}
    ++#resize-packages-nav{border-bottom:3px solid #666;}
    ++</style>
    ++</noscript>
    ++<style type="text/css">
    ++</style>
    ++</HEAD>
    ++<BODY class="gc-documentation" style="padding:12px;">
    ++<a NAME="topheader"></a>
    ++<table summary="Index for Fields" width="100%" class="jdiffIndex" border="0" cellspacing="0" cellpadding="0" style="padding-bottom:0;margin-bottom:0;">
    ++  <tr>
    ++  <th class="indexHeader">
    ++    Filter the Index:
    ++  </th>
    ++  </tr>
    ++  <tr>
    ++  <td class="indexText" style="line-height:1.3em;padding-left:2em;">
    ++<a href="fields_index_all.html" class="staysblack">All Fields</a>
    ++  <br>
    ++<A HREF="fields_index_removals.html" xclass="hiddenlink">Removals</A>
    ++  <br>
    ++<A HREF="fields_index_additions.html"xclass="hiddenlink">Additions</A>
    ++  <br>
    ++<b>Changes</b>
    ++  </td>
    ++  </tr>
    ++</table>
    ++<div id="indexTableCaption" style="background-color:#eee;padding:0 4px 0 4px;font-size:11px;margin-bottom:1em;">
    ++Listed as: <span style="color:#069"><strong>Added</strong></span>,  <span style="color:#069"><strike>Removed</strike></span>,  <span style="color:#069">Changed</span></font>
    ++</div>
    ++<A NAME="O"></A>
    ++<br><font size="+2">O</font>&nbsp;
    ++ <a href="#topheader"><font size="-2">TOP</font></a>
    ++<p><div style="line-height:1.5em;color:black">
    ++<nobr><A HREF="android.support.v4.view.ViewCompat.html#android.support.v4.view.ViewCompat.OVER_SCROLL_ALWAYS" class="hiddenlink" target="rightframe">OVER_SCROLL_ALWAYS</A>
    ++</nobr><br>
    ++<nobr><A HREF="android.support.v4.view.ViewCompat.html#android.support.v4.view.ViewCompat.OVER_SCROLL_IF_CONTENT_SCROLLS" class="hiddenlink" target="rightframe">OVER_SCROLL_IF_CONTENT_SCROLLS</A>
    ++</nobr><br>
    ++<nobr><A HREF="android.support.v4.view.ViewCompat.html#android.support.v4.view.ViewCompat.OVER_SCROLL_NEVER" class="hiddenlink" target="rightframe">OVER_SCROLL_NEVER</A>
    ++</nobr><br>
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    ++</script>
    ++<script type="text/javascript">
    ++  try {
    ++    var pageTracker = _gat._getTracker("UA-5831155-1");
    ++    pageTracker._setAllowAnchor(true);
    ++    pageTracker._initData();
    ++    pageTracker._trackPageview();
    ++  } catch(e) {}
    ++</script>
    ++</BODY>
    ++</HTML>
    +diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/fields_index_removals.html b/docs/html/sdk/support_api_diff/24.2.0/changes/fields_index_removals.html
    +new file mode 100644
    +index 0000000..61820d1
    +--- /dev/null
    ++++ b/docs/html/sdk/support_api_diff/24.2.0/changes/fields_index_removals.html
    +@@ -0,0 +1,67 @@
    ++<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
    ++<HTML style="overflow:auto;">
    ++<HEAD>
    ++<meta name="generator" content="JDiff v1.1.0">
    ++<!-- Generated by the JDiff Javadoc doclet -->
    ++<!-- (http://www.jdiff.org) -->
    ++<meta name="description" content="JDiff is a Javadoc doclet which generates an HTML report of all the packages, classes, constructors, methods, and fields which have been removed, added or changed in any way, including their documentation, when two APIs are compared.">
    ++<meta name="keywords" content="diff, jdiff, javadiff, java diff, java difference, API difference, difference between two APIs, API diff, Javadoc, doclet">
    ++<TITLE>
    ++Field Removals Index
    ++</TITLE>
    ++<link href="../../../../assets/android-developer-docs.css" rel="stylesheet" type="text/css" />
    ++<link href="../stylesheet-jdiff.css" rel="stylesheet" type="text/css" />
    ++<noscript>
    ++<style type="text/css">
    ++body{overflow:auto;}
    ++#body-content{position:relative; top:0;}
    ++#doc-content{overflow:visible;border-left:3px solid #666;}
    ++#side-nav{padding:0;}
    ++#side-nav .toggle-list ul {display:block;}
    ++#resize-packages-nav{border-bottom:3px solid #666;}
    ++</style>
    ++</noscript>
    ++<style type="text/css">
    ++</style>
    ++</HEAD>
    ++<BODY class="gc-documentation" style="padding:12px;">
    ++<a NAME="topheader"></a>
    ++<table summary="Index for Fields" width="100%" class="jdiffIndex" border="0" cellspacing="0" cellpadding="0" style="padding-bottom:0;margin-bottom:0;">
    ++  <tr>
    ++  <th class="indexHeader">
    ++    Filter the Index:
    ++  </th>
    ++  </tr>
    ++  <tr>
    ++  <td class="indexText" style="line-height:1.3em;padding-left:2em;">
    ++<a href="fields_index_all.html" class="staysblack">All Fields</a>
    ++  <br>
    ++<b>Removals</b>
    ++  <br>
    ++<A HREF="fields_index_additions.html"xclass="hiddenlink">Additions</A>
    ++  <br>
    ++<A HREF="fields_index_changes.html"xclass="hiddenlink">Changes</A>
    ++  </td>
    ++  </tr>
    ++</table>
    ++<div id="indexTableCaption" style="background-color:#eee;padding:0 4px 0 4px;font-size:11px;margin-bottom:1em;">
    ++Listed as: <span style="color:#069"><strong>Added</strong></span>,  <span style="color:#069"><strike>Removed</strike></span>,  <span style="color:#069">Changed</span></font>
    ++</div>
    ++<A NAME="T"></A>
    ++<br><font size="+2">T</font>&nbsp;
    ++ <a href="#topheader"><font size="-2">TOP</font></a>
    ++<p><div style="line-height:1.5em;color:black">
    ++<nobr><A HREF="android.support.v7.widget.StaggeredGridLayoutManager.html#android.support.v7.widget.StaggeredGridLayoutManager.TAG" class="hiddenlink" target="rightframe"><strike>TAG</strike></A>
    ++</nobr><br>
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    ++</script>
    ++<script type="text/javascript">
    ++  try {
    ++    var pageTracker = _gat._getTracker("UA-5831155-1");
    ++    pageTracker._setAllowAnchor(true);
    ++    pageTracker._initData();
    ++    pageTracker._trackPageview();
    ++  } catch(e) {}
    ++</script>
    ++</BODY>
    ++</HTML>
    +diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/jdiff_help.html b/docs/html/sdk/support_api_diff/24.2.0/changes/jdiff_help.html
    +new file mode 100644
    +index 0000000..966dda8
    +--- /dev/null
    ++++ b/docs/html/sdk/support_api_diff/24.2.0/changes/jdiff_help.html
    +@@ -0,0 +1,134 @@
    ++<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
    ++<HTML style="overflow:auto;">
    ++<HEAD>
    ++<meta name="generator" content="JDiff v1.1.0">
    ++<!-- Generated by the JDiff Javadoc doclet -->
    ++<!-- (http://www.jdiff.org) -->
    ++<meta name="description" content="JDiff is a Javadoc doclet which generates an HTML report of all the packages, classes, constructors, methods, and fields which have been removed, added or changed in any way, including their documentation, when two APIs are compared.">
    ++<meta name="keywords" content="diff, jdiff, javadiff, java diff, java difference, API difference, difference between two APIs, API diff, Javadoc, doclet">
    ++<TITLE>
    ++JDiff Help
    ++</TITLE>
    ++<link href="../../../../assets/android-developer-docs.css" rel="stylesheet" type="text/css" />
    ++<link href="../stylesheet-jdiff.css" rel="stylesheet" type="text/css" />
    ++<noscript>
    ++<style type="text/css">
    ++body{overflow:auto;}
    ++#body-content{position:relative; top:0;}
    ++#doc-content{overflow:visible;border-left:3px solid #666;}
    ++#side-nav{padding:0;}
    ++#side-nav .toggle-list ul {display:block;}
    ++#resize-packages-nav{border-bottom:3px solid #666;}
    ++</style>
    ++</noscript>
    ++<style type="text/css">
    ++</style>
    ++</HEAD>
    ++<BODY>
    ++<!-- Start of nav bar -->
    ++<TABLE summary="Navigation bar" BORDER="0" WIDTH="100%" CELLPADDING="1" CELLSPACING="0">
    ++<TR>
    ++<TD COLSPAN=2 BGCOLOR="#EEEEFF" CLASS="NavBarCell1">
    ++  <TABLE summary="Navigation bar" BORDER="0" CELLPADDING="0" CELLSPACING="3">
    ++    <TR ALIGN="center" VALIGN="top">
    ++      <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../../reference/index.html" target="_top"><FONT CLASS="NavBarFont1"><B><code>24.2.0</code></B></FONT></A>&nbsp;</TD>
    ++      <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="changes-summary.html"><FONT CLASS="NavBarFont1"><B>Overview</B></FONT></A>&nbsp;</TD>
    ++      <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> &nbsp;<FONT CLASS="NavBarFont1">Package</FONT>&nbsp;</TD>
    ++      <TD BGCOLOR="#FFFFFF" CLASS="NavBarCell1"> &nbsp;<FONT CLASS="NavBarFont1">Class</FONT>&nbsp;</TD>
    ++      <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="jdiff_statistics.html"><FONT CLASS="NavBarFont1"><B>Statistics</B></FONT></A>&nbsp;</TD>
    ++      <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1Rev"> &nbsp;<FONT CLASS="NavBarFont1Rev"><B>Help</B></FONT>&nbsp;</TD>
    ++    </TR>
    ++  </TABLE>
    ++</TD>
    ++<TD ALIGN="right" VALIGN="top" ROWSPAN=3><EM><b>Generated by<br><a href="http://www.jdiff.org" class="staysblack" target="_top">JDiff</a></b></EM></TD>
    ++</TR>
    ++<TR>
    ++  <TD BGCOLOR="#FFFFFF" CLASS="NavBarCell2"><FONT SIZE="-2"></FONT>
    ++</TD>
    ++  <TD BGCOLOR="#FFFFFF" CLASS="NavBarCell2"><FONT SIZE="-2">
    ++  <A HREF="../changes.html" TARGET="_top"><B>FRAMES</B></A>  &nbsp;
    ++  &nbsp;<A HREF="jdiff_help.html" TARGET="_top"><B>NO FRAMES</B></A></FONT></TD>
    ++</TR>
    ++</TABLE>
    ++<HR>
    ++<!-- End of nav bar -->
    ++<center>
    ++<H1>JDiff Documentation</H1>
    ++</center>
    ++<BLOCKQUOTE>
    ++JDiff is a <a href="http://java.sun.com/j2se/javadoc/" target="_top">Javadoc</a> doclet which generates a report of the API differences between two versions of a product. It does not report changes in Javadoc comments, or changes in what a class or method does. 
    ++This help page describes the different parts of the output from JDiff.
    ++</BLOCKQUOTE>
    ++<BLOCKQUOTE>
    ++ See the reference page in the <a href="http://www.jdiff.org">source for JDiff</a> for information about how to generate a report like this one.
    ++</BLOCKQUOTE>
    ++<BLOCKQUOTE>
    ++The indexes shown in the top-left frame help show each type of change in more detail. The index "All Differences" contains all the differences between the APIs, in alphabetical order. 
    ++These indexes all use the same format:
    ++<ul>
    ++<li>Removed packages, classes, constructors, methods and fields are <strike>struck through</strike>.</li>
    ++<li>Added packages, classes, constructors, methods and fields appear in <b>bold</b>.</li>
    ++<li>Changed packages, classes, constructors, methods and fields appear in normal text.</li>
    ++</ul>
    ++</BLOCKQUOTE>
    ++<BLOCKQUOTE>
    ++You can always tell when you are reading a JDiff page, rather than a Javadoc page, by the color of the index bar and the color of the background. 
    ++Links which take you to a Javadoc page are always in a <code>typewriter</code> font. 
    ++Just like Javadoc, all interface names are in <i>italic</i>, and class names are not italicized. Where there are multiple entries in an index with the same name, the heading for them is also in italics, but is not a link.
    ++</BLOCKQUOTE>
    ++<BLOCKQUOTE>
    ++<H3><b><code>Javadoc</code></b></H3>
    ++This is a link to the <a href="../../../../reference/index.html" target="_top">top-level</a> Javadoc page for the new version of the product.
    ++</BLOCKQUOTE>
    ++<BLOCKQUOTE>
    ++<H3>Overview</H3>
    ++The <a href="changes-summary.html">overview</a> is the top-level summary of what was removed, added and changed between versions.
    ++</BLOCKQUOTE>
    ++<BLOCKQUOTE>
    ++<H3>Package</H3>
    ++This is a link to the package containing the current changed class or interface.
    ++</BLOCKQUOTE>
    ++<BLOCKQUOTE>
    ++<H3>Class</H3>
    ++This is highlighted when you are looking at the changed class or interface.
    ++</BLOCKQUOTE>
    ++<BLOCKQUOTE>
    ++<H3>Text Changes</H3>
    ++This is a link to the top-level index of all documentation changes for the current package or class. 
    ++If it is not present, then there are no documentation changes for the current package or class. 
    ++This link can be removed entirely by not using the <code>-docchanges</code> option.
    ++</BLOCKQUOTE>
    ++<BLOCKQUOTE>
    ++<H3>Statistics</H3>
    ++This is a link to a page which shows statistics about the changes between the two APIs.
    ++This link can be removed entirely by not using the <code>-stats</code> option.
    ++</BLOCKQUOTE>
    ++<BLOCKQUOTE>
    ++<H3>Help</H3>
    ++A link to this Help page for JDiff.
    ++</BLOCKQUOTE>
    ++<BLOCKQUOTE>
    ++<H3>Prev/Next</H3>
    ++These links take you to the previous  and next changed package or class.
    ++</BLOCKQUOTE>
    ++<BLOCKQUOTE>
    ++<H3>Frames/No Frames</H3>
    ++These links show and hide the HTML frames. All pages are available with or without frames.
    ++</BLOCKQUOTE>
    ++<BLOCKQUOTE>
    ++<H2>Complex Changes</H2>
    ++There are some complex changes which can occur between versions, for example, when two or more methods with the same name change simultaneously, or when a method or field is moved into or from a superclass. 
    ++In these cases, the change will be seen as a removal and an addition, rather than as a change. Unexpected removals or additions are often part of one of these type of changes. 
    ++</BLOCKQUOTE>
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    ++</script>
    ++<script type="text/javascript">
    ++  try {
    ++    var pageTracker = _gat._getTracker("UA-5831155-1");
    ++    pageTracker._setAllowAnchor(true);
    ++    pageTracker._initData();
    ++    pageTracker._trackPageview();
    ++  } catch(e) {}
    ++</script>
    ++</BODY>
    ++</HTML>
    +diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/jdiff_statistics.html b/docs/html/sdk/support_api_diff/24.2.0/changes/jdiff_statistics.html
    +new file mode 100644
    +index 0000000..7010da6
    +--- /dev/null
    ++++ b/docs/html/sdk/support_api_diff/24.2.0/changes/jdiff_statistics.html
    +@@ -0,0 +1,596 @@
    ++<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
    ++<HTML style="overflow:auto;">
    ++<HEAD>
    ++<meta name="generator" content="JDiff v1.1.0">
    ++<!-- Generated by the JDiff Javadoc doclet -->
    ++<!-- (http://www.jdiff.org) -->
    ++<meta name="description" content="JDiff is a Javadoc doclet which generates an HTML report of all the packages, classes, constructors, methods, and fields which have been removed, added or changed in any way, including their documentation, when two APIs are compared.">
    ++<meta name="keywords" content="diff, jdiff, javadiff, java diff, java difference, API difference, difference between two APIs, API diff, Javadoc, doclet">
    ++<TITLE>
    ++API Change Statistics
    ++</TITLE>
    ++<link href="../../../../assets/android-developer-docs.css" rel="stylesheet" type="text/css" />
    ++<link href="../stylesheet-jdiff.css" rel="stylesheet" type="text/css" />
    ++<noscript>
    ++<style type="text/css">
    ++body{overflow:auto;}
    ++#body-content{position:relative; top:0;}
    ++#doc-content{overflow:visible;border-left:3px solid #666;}
    ++#side-nav{padding:0;}
    ++#side-nav .toggle-list ul {display:block;}
    ++#resize-packages-nav{border-bottom:3px solid #666;}
    ++</style>
    ++</noscript>
    ++<style type="text/css">
    ++</style>
    ++</HEAD>
    ++<body class="gc-documentation">
    ++<!-- Start of nav bar -->
    ++<a name="top"></a>
    ++<div id="header" style="margin-bottom:0;xborder-bottom:none;">
    ++<div id="headerLeft">
    ++<a href="../../../../index.html" tabindex="-1" target="_top"><img src="../../../../assets/images/bg_logo.png" alt="Android Developers" /></a>
    ++</div>
    ++  <div id="headerRight">
    ++  <div id="headerLinks">
    ++<!-- <img src="/assets/images/icon_world.jpg" alt="" /> -->
    ++<span class="text">
    ++<!-- &nbsp;<a href="#">English</a> | -->
    ++<nobr><a href="http://developer.android.com" target="_top">Android Developers</a> | <a href="http://www.android.com" target="_top">Android.com</a></nobr>
    ++</span>
    ++</div>
    ++  <div class="and-diff-id" style="margin-top:6px;margin-right:8px;">
    ++    <table class="diffspectable">
    ++      <tr>
    ++        <td colspan="2" class="diffspechead">API Diff Specification</td>
    ++      </tr>
    ++      <tr>
    ++        <td class="diffspec" style="padding-top:.25em">To Level:</td>
    ++        <td class="diffvaluenew" style="padding-top:.25em">24.2.0</td>
    ++      </tr>
    ++      <tr>
    ++        <td class="diffspec">From Level:</td>
    ++        <td class="diffvalueold">24.1.0</td>
    ++      </tr>
    ++      <tr>
    ++        <td class="diffspec">Generated</td>
    ++        <td class="diffvalue">2016.08.16 14:03</td>
    ++      </tr>
    ++    </table>
    ++    </div><!-- End and-diff-id -->
    ++  <div class="and-diff-id" style="margin-right:8px;">
    ++    <table class="diffspectable">
    ++      <tr>
    ++        <td class="diffspec" colspan="2"><a href="../changes.html" target="_top">Top of Report</a>
    ++      </tr>
    ++    </table>
    ++  </div> <!-- End and-diff-id -->
    ++  </div> <!-- End headerRight -->
    ++  </div> <!-- End header -->
    ++<div id="body-content">
    ++<div id="doc-content" style="position:relative;">
    ++<div id="mainBodyFluid">
    ++<h1>API&nbsp;Change&nbsp;Statistics</h1>
    ++<p>The overall difference between API Levels 24.1.0 and 24.2.0 is approximately <span style="color:222;font-weight:bold;">8.39%</span>.
    ++</p>
    ++<br>
    ++<a name="numbers"></a>
    ++<h2>Total of Differences, by Number and Type</h2>
    ++<p>
    ++The table below lists the numbers of program elements (packages, classes, constructors, methods, and fields) that were added, changed, or removed. The table includes only the highest-level program elements &mdash; that is, if a class with two methods was added, the number of methods added does not include those two methods, but the number of classes added does include that class.
    ++</p>
    ++<TABLE summary="Number of differences" WIDTH="100%">
    ++<TR>
    ++  <th>Type</th>
    ++  <TH ALIGN="center"><b>Additions</b></TH>
    ++  <TH ALIGN="center"><b>Changes</b></TH>
    ++  <TH ALIGN="center">Removals</TH>
    ++  <TH ALIGN="center"><b>Total</b></TH>
    ++</TR>
    ++<TR>
    ++  <TD>Packages</TD>
    ++  <TD ALIGN="right">2</TD>
    ++  <TD ALIGN="right">22</TD>
    ++  <TD ALIGN="right">3</TD>
    ++  <TD ALIGN="right">27</TD>
    ++</TR>
    ++<TR>
    ++  <TD>Classes and <i>Interfaces</i></TD>
    ++  <TD ALIGN="right">64</TD>
    ++  <TD ALIGN="right">63</TD>
    ++  <TD ALIGN="right">0</TD>
    ++  <TD ALIGN="right">127</TD>
    ++</TR>
    ++<TR>
    ++  <TD>Constructors</TD>
    ++  <TD ALIGN="right">1</TD>
    ++  <TD ALIGN="right">2</TD>
    ++  <TD ALIGN="right">0</TD>
    ++  <TD ALIGN="right">3</TD>
    ++</TR>
    ++<TR>
    ++  <TD>Methods</TD>
    ++  <TD ALIGN="right">80</TD>
    ++  <TD ALIGN="right">25</TD>
    ++  <TD ALIGN="right">7</TD>
    ++  <TD ALIGN="right">112</TD>
    ++</TR>
    ++<TR>
    ++  <TD>Fields</TD>
    ++  <TD ALIGN="right">38</TD>
    ++  <TD ALIGN="right">3</TD>
    ++  <TD ALIGN="right">1</TD>
    ++  <TD ALIGN="right">42</TD>
    ++</TR>
    ++<TR>
    ++  <TD style="background-color:#FAFAFA"><b>Total</b></TD>
    ++  <TD  style="background-color:#FAFAFA" ALIGN="right"><strong>185</strong></TD>
    ++  <TD  style="background-color:#FAFAFA" ALIGN="right"><strong>115</strong></TD>
    ++  <TD  style="background-color:#FAFAFA" ALIGN="right"><strong>11</strong></TD>
    ++  <TD  style="background-color:#FAFAFA" ALIGN="right"><strong>311</strong></TD>
    ++</TR>
    ++</TABLE>
    ++<br>
    ++<a name="packages"></a>
    ++<h2>Changed Packages, Sorted by Percentage Difference</h2>
    ++<TABLE summary="Packages sorted by percentage difference" WIDTH="100%">
    ++<TR>
    ++  <TH  WIDTH="10%">Percentage Difference*</TH>
    ++  <TH>Package</TH>
    ++</TR>
    ++<TR>
    ++  <TD ALIGN="center">37</TD>
    ++  <TD><A HREF="pkg_android.support.v7.widget.html">android.support.v7.widget</A></TD>
    ++</TR>
    ++<TR>
    ++  <TD ALIGN="center">33</TD>
    ++  <TD><A HREF="pkg_android.support.v7.content.res.html">android.support.v7.content.res</A></TD>
    ++</TR>
    ++<TR>
    ++  <TD ALIGN="center">32</TD>
    ++  <TD><A HREF="pkg_android.support.v7.util.html">android.support.v7.util</A></TD>
    ++</TR>
    ++<TR>
    ++  <TD ALIGN="center">19</TD>
    ++  <TD><A HREF="pkg_android.support.v4.view.accessibility.html">android.support.v4.view.accessibility</A></TD>
    ++</TR>
    ++<TR>
    ++  <TD ALIGN="center">12</TD>
    ++  <TD><A HREF="pkg_android.support.v7.app.html">android.support.v7.app</A></TD>
    ++</TR>
    ++<TR>
    ++  <TD ALIGN="center">5</TD>
    ++  <TD><A HREF="pkg_android.support.v4.widget.html">android.support.v4.widget</A></TD>
    ++</TR>
    ++<TR>
    ++  <TD ALIGN="center">4</TD>
    ++  <TD><A HREF="pkg_android.support.v4.accessibilityservice.html">android.support.v4.accessibilityservice</A></TD>
    ++</TR>
    ++<TR>
    ++  <TD ALIGN="center">4</TD>
    ++  <TD><A HREF="pkg_android.support.customtabs.html">android.support.customtabs</A></TD>
    ++</TR>
    ++<TR>
    ++  <TD ALIGN="center">3</TD>
    ++  <TD><A HREF="pkg_android.support.v4.util.html">android.support.v4.util</A></TD>
    ++</TR>
    ++<TR>
    ++  <TD ALIGN="center">3</TD>
    ++  <TD><A HREF="pkg_android.support.v4.os.html">android.support.v4.os</A></TD>
    ++</TR>
    ++<TR>
    ++  <TD ALIGN="center">2</TD>
    ++  <TD><A HREF="pkg_android.support.v4.media.session.html">android.support.v4.media.session</A></TD>
    ++</TR>
    ++<TR>
    ++  <TD ALIGN="center">2</TD>
    ++  <TD><A HREF="pkg_android.support.v4.app.html">android.support.v4.app</A></TD>
    ++</TR>
    ++<TR>
    ++  <TD ALIGN="center">2</TD>
    ++  <TD><A HREF="pkg_android.support.design.widget.html">android.support.design.widget</A></TD>
    ++</TR>
    ++<TR>
    ++  <TD ALIGN="center">2</TD>
    ++  <TD><A HREF="pkg_android.support.v4.media.html">android.support.v4.media</A></TD>
    ++</TR>
    ++<TR>
    ++  <TD ALIGN="center">1</TD>
    ++  <TD><A HREF="pkg_android.support.v7.preference.html">android.support.v7.preference</A></TD>
    ++</TR>
    ++<TR>
    ++  <TD ALIGN="center">1</TD>
    ++  <TD><A HREF="pkg_android.support.v4.view.html">android.support.v4.view</A></TD>
    ++</TR>
    ++<TR>
    ++  <TD ALIGN="center">1</TD>
    ++  <TD><A HREF="pkg_android.support.v17.preference.html">android.support.v17.preference</A></TD>
    ++</TR>
    ++<TR>
    ++  <TD ALIGN="center">&lt;1</TD>
    ++  <TD><A HREF="pkg_android.support.v4.graphics.drawable.html">android.support.v4.graphics.drawable</A></TD>
    ++</TR>
    ++<TR>
    ++  <TD ALIGN="center">&lt;1</TD>
    ++  <TD><A HREF="pkg_android.support.v7.graphics.html">android.support.v7.graphics</A></TD>
    ++</TR>
    ++<TR>
    ++  <TD ALIGN="center">&lt;1</TD>
    ++  <TD><A HREF="pkg_android.support.v17.leanback.widget.html">android.support.v17.leanback.widget</A></TD>
    ++</TR>
    ++<TR>
    ++  <TD ALIGN="center">&lt;1</TD>
    ++  <TD><A HREF="pkg_android.support.v14.preference.html">android.support.v14.preference</A></TD>
    ++</TR>
    ++<TR>
    ++  <TD ALIGN="center">&lt;1</TD>
    ++  <TD><A HREF="pkg_android.support.v4.content.html">android.support.v4.content</A></TD>
    ++</TR>
    ++</TABLE>
    ++<p style="font-size:10px">* See <a href="#calculation">Calculation of Change Percentages</a>, below.</p>
    ++<br>
    ++<a name="classes"></a>
    ++<h2>Changed Classes and <i>Interfaces</i>, Sorted by Percentage Difference</h2>
    ++<TABLE summary="Classes sorted by percentage difference" WIDTH="100%">
    ++<TR WIDTH="20%">
    ++  <TH WIDTH="10%">Percentage<br>Difference*</TH>
    ++  <TH><b>Class or <i>Interface</i></b></TH>
    ++</TR>
    ++<TR>
    ++  <TD ALIGN="center">60</TD>
    ++  <TD><A HREF="android.support.v4.app.ServiceCompat.html">
    ++android.support.v4.app.ServiceCompat</A></TD>
    ++</TR>
    ++<TR>
    ++  <TD ALIGN="center">38</TD>
    ++  <TD><A HREF="android.support.design.widget.FloatingActionButton.Behavior.html">
    ++android.support.design.widget.FloatingActionButton.Behavior</A></TD>
    ++</TR>
    ++<TR>
    ++  <TD ALIGN="center">33</TD>
    ++  <TD><A HREF="android.support.v4.app.ActivityOptionsCompat.html">
    ++android.support.v4.app.ActivityOptionsCompat</A></TD>
    ++</TR>
    ++<TR>
    ++  <TD ALIGN="center">33</TD>
    ++  <TD><A HREF="android.support.v4.os.BuildCompat.html">
    ++android.support.v4.os.BuildCompat</A></TD>
    ++</TR>
    ++<TR>
    ++  <TD ALIGN="center">33</TD>
    ++  <TD><A HREF="android.support.v4.view.accessibility.AccessibilityManagerCompat.html">
    ++android.support.v4.view.accessibility.AccessibilityManagerCompat</A></TD>
    ++</TR>
    ++<TR>
    ++  <TD ALIGN="center">33</TD>
    ++  <TD><A HREF="android.support.v4.view.accessibility.AccessibilityManagerCompat.AccessibilityStateChangeListenerCompat.html">
    ++android.support.v4.view.accessibility.AccessibilityManagerCompat.AccessibilityStateChangeListenerCompat</A></TD>
    ++</TR>
    ++<TR>
    ++  <TD ALIGN="center">33</TD>
    ++  <TD><A HREF="android.support.v7.content.res.AppCompatResources.html">
    ++android.support.v7.content.res.AppCompatResources</A></TD>
    ++</TR>
    ++<TR>
    ++  <TD ALIGN="center">28</TD>
    ++  <TD><A HREF="android.support.customtabs.CustomTabsSession.html">
    ++android.support.customtabs.CustomTabsSession</A></TD>
    ++</TR>
    ++<TR>
    ++  <TD ALIGN="center">28</TD>
    ++  <TD><A HREF="android.support.v7.util.SortedList.Callback.html">
    ++android.support.v7.util.SortedList.Callback</A></TD>
    ++</TR>
    ++<TR>
    ++  <TD ALIGN="center">25</TD>
    ++  <TD><A HREF="android.support.v4.media.session.MediaButtonReceiver.html">
    ++android.support.v4.media.session.MediaButtonReceiver</A></TD>
    ++</TR>
    ++<TR>
    ++  <TD ALIGN="center">25</TD>
    ++  <TD><A HREF="android.support.v4.view.ViewConfigurationCompat.html">
    ++android.support.v4.view.ViewConfigurationCompat</A></TD>
    ++</TR>
    ++<TR>
    ++  <TD ALIGN="center">25</TD>
    ++  <TD><A HREF="android.support.v4.widget.SearchViewCompat.OnCloseListenerCompat.html">
    ++android.support.v4.widget.SearchViewCompat.OnCloseListenerCompat</A></TD>
    ++</TR>
    ++<TR>
    ++  <TD ALIGN="center">23</TD>
    ++  <TD><A HREF="android.support.v4.media.MediaDescriptionCompat.html">
    ++android.support.v4.media.MediaDescriptionCompat</A></TD>
    ++</TR>
    ++<TR>
    ++  <TD ALIGN="center">20</TD>
    ++  <TD><A HREF="android.support.v4.view.KeyEventCompat.html">
    ++android.support.v4.view.KeyEventCompat</A></TD>
    ++</TR>
    ++<TR>
    ++  <TD ALIGN="center">18</TD>
    ++  <TD><A HREF="android.support.v17.leanback.widget.AbstractMediaItemPresenter.html">
    ++android.support.v17.leanback.widget.AbstractMediaItemPresenter</A></TD>
    ++</TR>
    ++<TR>
    ++  <TD ALIGN="center">18</TD>
    ++  <TD><A HREF="android.support.design.widget.TextInputLayout.html">
    ++android.support.design.widget.TextInputLayout</A></TD>
    ++</TR>
    ++<TR>
    ++  <TD ALIGN="center">17</TD>
    ++  <TD><A HREF="android.support.v17.leanback.widget.AbstractMediaItemPresenter.ViewHolder.html">
    ++android.support.v17.leanback.widget.AbstractMediaItemPresenter.ViewHolder</A></TD>
    ++</TR>
    ++<TR>
    ++  <TD ALIGN="center">16</TD>
    ++  <TD><A HREF="android.support.v4.widget.SearchViewCompat.OnQueryTextListenerCompat.html">
    ++android.support.v4.widget.SearchViewCompat.OnQueryTextListenerCompat</A></TD>
    ++</TR>
    ++<TR>
    ++  <TD ALIGN="center">15</TD>
    ++  <TD><A HREF="android.support.v4.media.session.MediaSessionCompat.QueueItem.html">
    ++android.support.v4.media.session.MediaSessionCompat.QueueItem</A></TD>
    ++</TR>
    ++<TR>
    ++  <TD ALIGN="center">13</TD>
    ++  <TD><A HREF="android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat.html">
    ++android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat</A></TD>
    ++</TR>
    ++<TR>
    ++  <TD ALIGN="center">12</TD>
    ++  <TD><A HREF="android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.CollectionInfoCompat.html">
    ++android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.CollectionInfoCompat</A></TD>
    ++</TR>
    ++<TR>
    ++  <TD ALIGN="center">11</TD>
    ++  <TD><A HREF="android.support.v4.view.accessibility.AccessibilityEventCompat.html">
    ++android.support.v4.view.accessibility.AccessibilityEventCompat</A></TD>
    ++</TR>
    ++<TR>
    ++  <TD ALIGN="center">11</TD>
    ++  <TD><A HREF="android.support.design.widget.AppBarLayout.ScrollingViewBehavior.html">
    ++android.support.design.widget.AppBarLayout.ScrollingViewBehavior</A></TD>
    ++</TR>
    ++<TR>
    ++  <TD ALIGN="center">10</TD>
    ++  <TD><A HREF="android.support.v17.preference.LeanbackSettingsFragment.html">
    ++android.support.v17.preference.LeanbackSettingsFragment</A></TD>
    ++</TR>
    ++<TR>
    ++  <TD ALIGN="center">9</TD>
    ++  <TD><A HREF="android.support.design.widget.CoordinatorLayout.Behavior.html">
    ++android.support.design.widget.CoordinatorLayout.Behavior</A></TD>
    ++</TR>
    ++<TR>
    ++  <TD ALIGN="center">8</TD>
    ++  <TD><A HREF="android.support.design.widget.CoordinatorLayout.LayoutParams.html">
    ++android.support.design.widget.CoordinatorLayout.LayoutParams</A></TD>
    ++</TR>
    ++<TR>
    ++  <TD ALIGN="center">8</TD>
    ++  <TD><A HREF="android.support.v4.media.MediaBrowserCompat.MediaItem.html">
    ++android.support.v4.media.MediaBrowserCompat.MediaItem</A></TD>
    ++</TR>
    ++<TR>
    ++  <TD ALIGN="center">7</TD>
    ++  <TD><A HREF="android.support.v4.media.MediaBrowserServiceCompat.BrowserRoot.html">
    ++android.support.v4.media.MediaBrowserServiceCompat.BrowserRoot</A></TD>
    ++</TR>
    ++<TR>
    ++  <TD ALIGN="center">7</TD>
    ++  <TD><A HREF="android.support.v4.widget.TextViewCompat.html">
    ++android.support.v4.widget.TextViewCompat</A></TD>
    ++</TR>
    ++<TR>
    ++  <TD ALIGN="center">7</TD>
    ++  <TD><A HREF="android.support.v4.app.ActivityCompat.html">
    ++android.support.v4.app.ActivityCompat</A></TD>
    ++</TR>
    ++<TR>
    ++  <TD ALIGN="center">6</TD>
    ++  <TD><A HREF="android.support.v4.app.SharedElementCallback.html">
    ++android.support.v4.app.SharedElementCallback</A></TD>
    ++</TR>
    ++<TR>
    ++  <TD ALIGN="center">6</TD>
    ++  <TD><A HREF="android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.CollectionItemInfoCompat.html">
    ++android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.CollectionItemInfoCompat</A></TD>
    ++</TR>
    ++<TR>
    ++  <TD ALIGN="center">6</TD>
    ++  <TD><A HREF="android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.RangeInfoCompat.html">
    ++android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.RangeInfoCompat</A></TD>
    ++</TR>
    ++<TR>
    ++  <TD ALIGN="center">6</TD>
    ++  <TD><A HREF="android.support.v4.view.accessibility.AccessibilityNodeProviderCompat.html">
    ++android.support.v4.view.accessibility.AccessibilityNodeProviderCompat</A></TD>
    ++</TR>
    ++<TR>
    ++  <TD ALIGN="center">6</TD>
    ++  <TD><A HREF="android.support.v4.widget.SearchViewCompat.html">
    ++android.support.v4.widget.SearchViewCompat</A></TD>
    ++</TR>
    ++<TR>
    ++  <TD ALIGN="center">6</TD>
    ++  <TD><A HREF="android.support.v7.app.ActionBarDrawerToggle.html">
    ++android.support.v7.app.ActionBarDrawerToggle</A></TD>
    ++</TR>
    ++<TR>
    ++  <TD ALIGN="center">5</TD>
    ++  <TD><A HREF="android.support.customtabs.CustomTabsIntent.html">
    ++android.support.customtabs.CustomTabsIntent</A></TD>
    ++</TR>
    ++<TR>
    ++  <TD ALIGN="center">4</TD>
    ++  <TD><A HREF="android.support.v4.accessibilityservice.AccessibilityServiceInfoCompat.html">
    ++android.support.v4.accessibilityservice.AccessibilityServiceInfoCompat</A></TD>
    ++</TR>
    ++<TR>
    ++  <TD ALIGN="center">4</TD>
    ++  <TD><A HREF="android.support.v4.view.MotionEventCompat.html">
    ++android.support.v4.view.MotionEventCompat</A></TD>
    ++</TR>
    ++<TR>
    ++  <TD ALIGN="center">4</TD>
    ++  <TD><A HREF="android.support.v7.graphics.Palette.html">
    ++android.support.v7.graphics.Palette</A></TD>
    ++</TR>
    ++<TR>
    ++  <TD ALIGN="center">4</TD>
    ++  <TD><A HREF="android.support.v7.widget.StaggeredGridLayoutManager.html">
    ++android.support.v7.widget.StaggeredGridLayoutManager</A></TD>
    ++</TR>
    ++<TR>
    ++  <TD ALIGN="center">3</TD>
    ++  <TD><A HREF="android.support.v4.media.session.MediaSessionCompat.html">
    ++android.support.v4.media.session.MediaSessionCompat</A></TD>
    ++</TR>
    ++<TR>
    ++  <TD ALIGN="center">3</TD>
    ++  <TD><A HREF="android.support.v4.content.ContextCompat.html">
    ++android.support.v4.content.ContextCompat</A></TD>
    ++</TR>
    ++<TR>
    ++  <TD ALIGN="center">3</TD>
    ++  <TD><A HREF="android.support.customtabs.CustomTabsIntent.Builder.html">
    ++android.support.customtabs.CustomTabsIntent.Builder</A></TD>
    ++</TR>
    ++<TR>
    ++  <TD ALIGN="center">2</TD>
    ++  <TD><A HREF="android.support.design.widget.BottomSheetBehavior.html">
    ++android.support.design.widget.BottomSheetBehavior</A></TD>
    ++</TR>
    ++<TR>
    ++  <TD ALIGN="center">2</TD>
    ++  <TD><A HREF="android.support.design.widget.CoordinatorLayout.html">
    ++android.support.design.widget.CoordinatorLayout</A></TD>
    ++</TR>
    ++<TR>
    ++  <TD ALIGN="center">2</TD>
    ++  <TD><A HREF="android.support.v4.graphics.drawable.DrawableCompat.html">
    ++android.support.v4.graphics.drawable.DrawableCompat</A></TD>
    ++</TR>
    ++<TR>
    ++  <TD ALIGN="center">2</TD>
    ++  <TD><A HREF="android.support.v4.view.WindowInsetsCompat.html">
    ++android.support.v4.view.WindowInsetsCompat</A></TD>
    ++</TR>
    ++<TR>
    ++  <TD ALIGN="center">2</TD>
    ++  <TD><A HREF="android.support.v14.preference.PreferenceFragment.html">
    ++android.support.v14.preference.PreferenceFragment</A></TD>
    ++</TR>
    ++<TR>
    ++  <TD ALIGN="center">2</TD>
    ++  <TD><A HREF="android.support.v4.view.accessibility.AccessibilityWindowInfoCompat.html">
    ++android.support.v4.view.accessibility.AccessibilityWindowInfoCompat</A></TD>
    ++</TR>
    ++<TR>
    ++  <TD ALIGN="center">2</TD>
    ++  <TD><A HREF="android.support.v4.view.ViewCompat.html">
    ++android.support.v4.view.ViewCompat</A></TD>
    ++</TR>
    ++<TR>
    ++  <TD ALIGN="center">2</TD>
    ++  <TD><A HREF="android.support.design.widget.CollapsingToolbarLayout.html">
    ++android.support.design.widget.CollapsingToolbarLayout</A></TD>
    ++</TR>
    ++<TR>
    ++  <TD ALIGN="center">2</TD>
    ++  <TD><A HREF="android.support.v17.leanback.widget.ObjectAdapter.html">
    ++android.support.v17.leanback.widget.ObjectAdapter</A></TD>
    ++</TR>
    ++<TR>
    ++  <TD ALIGN="center">2</TD>
    ++  <TD><A HREF="android.support.v4.media.MediaMetadataCompat.html">
    ++android.support.v4.media.MediaMetadataCompat</A></TD>
    ++</TR>
    ++<TR>
    ++  <TD ALIGN="center">2</TD>
    ++  <TD><A HREF="android.support.v7.widget.LinearSmoothScroller.html">
    ++android.support.v7.widget.LinearSmoothScroller</A></TD>
    ++</TR>
    ++<TR>
    ++  <TD ALIGN="center">2</TD>
    ++  <TD><A HREF="android.support.v4.widget.SwipeRefreshLayout.html">
    ++android.support.v4.widget.SwipeRefreshLayout</A></TD>
    ++</TR>
    ++<TR>
    ++  <TD ALIGN="center">1</TD>
    ++  <TD><A HREF="android.support.v7.widget.LinearLayoutManager.html">
    ++android.support.v7.widget.LinearLayoutManager</A></TD>
    ++</TR>
    ++<TR>
    ++  <TD ALIGN="center">1</TD>
    ++  <TD><A HREF="android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.html">
    ++android.support.v4.view.accessibility.AccessibilityNodeInfoCompat</A></TD>
    ++</TR>
    ++<TR>
    ++  <TD ALIGN="center">1</TD>
    ++  <TD><A HREF="android.support.design.widget.TabLayout.html">
    ++android.support.design.widget.TabLayout</A></TD>
    ++</TR>
    ++<TR>
    ++  <TD ALIGN="center">1</TD>
    ++  <TD><A HREF="android.support.v4.app.FragmentController.html">
    ++android.support.v4.app.FragmentController</A></TD>
    ++</TR>
    ++<TR>
    ++  <TD ALIGN="center">1</TD>
    ++  <TD><A HREF="android.support.v7.app.AppCompatDelegate.html">
    ++android.support.v7.app.AppCompatDelegate</A></TD>
    ++</TR>
    ++<TR>
    ++  <TD ALIGN="center">1</TD>
    ++  <TD><A HREF="android.support.v7.widget.RecyclerView.html">
    ++android.support.v7.widget.RecyclerView</A></TD>
    ++</TR>
    ++<TR>
    ++  <TD ALIGN="center">1</TD>
    ++  <TD><A HREF="android.support.v4.media.session.PlaybackStateCompat.html">
    ++android.support.v4.media.session.PlaybackStateCompat</A></TD>
    ++</TR>
    ++</TABLE>
    ++<p style="font-size:10px">* See <a href="#calculation">Calculation of Change Percentages</a>, below.</p>
    ++<br>
    ++<h2 id="calculation">Calculation of Change Percentages</h2>
    ++<p>
    ++The percent change statistic reported for all elements in the &quot;to&quot; API Level specification is defined recursively as follows:</p>
    ++<pre>
    ++Percentage difference = 100 * (added + removed + 2*changed)
    ++                        -----------------------------------
    ++                        sum of public elements in BOTH APIs
    ++</pre>
    ++<p>where <code>added</code> is the number of packages added, <code>removed</code> is the number of packages removed, and <code>changed</code> is the number of packages changed.
    ++This definition is applied recursively for the classes and their program elements, so the value for a changed package will be less than 1, unless every class in that package has changed.
    ++The definition ensures that if all packages are removed and all new packages are
    ++added, the change will be 100%.</p>
    ++      </div>	
    ++      <div id="footer">
    ++        <div id="copyright">
    ++        Except as noted, this content is licensed under 
    ++        <a href="http://creativecommons.org/licenses/by/2.5/"> Creative Commons Attribution 2.5</a>.
    ++        For details and restrictions, see the <a href="/license.html">Content License</a>.
    ++        </div>
    ++      <div id="footerlinks">
    ++      <p>
    ++        <a href="http://www.android.com/terms.html">Site Terms of Service</a> -
    ++        <a href="http://www.android.com/privacy.html">Privacy Policy</a> -
    ++        <a href="http://www.android.com/branding.html">Brand Guidelines</a>
    ++      </p>
    ++    </div>
    ++    </div> <!-- end footer -->
    ++    </div><!-- end doc-content -->
    ++    </div> <!-- end body-content --> 
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    ++</script>
    ++<script type="text/javascript">
    ++  try {
    ++    var pageTracker = _gat._getTracker("UA-5831155-1");
    ++    pageTracker._setAllowAnchor(true);
    ++    pageTracker._initData();
    ++    pageTracker._trackPageview();
    ++  } catch(e) {}
    ++</script>
    ++</BODY></HTML>
    +diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/jdiff_topleftframe.html b/docs/html/sdk/support_api_diff/24.2.0/changes/jdiff_topleftframe.html
    +new file mode 100644
    +index 0000000..6a2e76e
    +--- /dev/null
    ++++ b/docs/html/sdk/support_api_diff/24.2.0/changes/jdiff_topleftframe.html
    +@@ -0,0 +1,63 @@
    ++<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
    ++<HTML style="overflow:auto;">
    ++<HEAD>
    ++<meta name="generator" content="JDiff v1.1.0">
    ++<!-- Generated by the JDiff Javadoc doclet -->
    ++<!-- (http://www.jdiff.org) -->
    ++<meta name="description" content="JDiff is a Javadoc doclet which generates an HTML report of all the packages, classes, constructors, methods, and fields which have been removed, added or changed in any way, including their documentation, when two APIs are compared.">
    ++<meta name="keywords" content="diff, jdiff, javadiff, java diff, java difference, API difference, difference between two APIs, API diff, Javadoc, doclet">
    ++<TITLE>
    ++Android API Version Differences
    ++</TITLE>
    ++<link href="../../../../assets/android-developer-docs.css" rel="stylesheet" type="text/css" />
    ++<link href="../stylesheet-jdiff.css" rel="stylesheet" type="text/css" />
    ++<noscript>
    ++<style type="text/css">
    ++body{overflow:auto;}
    ++#body-content{position:relative; top:0;}
    ++#doc-content{overflow:visible;border-left:3px solid #666;}
    ++#side-nav{padding:0;}
    ++#side-nav .toggle-list ul {display:block;}
    ++#resize-packages-nav{border-bottom:3px solid #666;}
    ++</style>
    ++</noscript>
    ++<style type="text/css">
    ++</style>
    ++</HEAD>
    ++<BODY class="gc-documentation" style="padding:12px;">
    ++<table class="jdiffIndex" summary="Links to diff index files" BORDER="0" WIDTH="100%" cellspacing="0" cellpadding="0" style="margin:0">
    ++<TR>
    ++  <th class="indexHeader" nowrap>
    ++  Select a Diffs Index:</th>
    ++</TR>
    ++<TR>
    ++  <TD><FONT CLASS="indexText" size="-2"><A HREF="alldiffs_index_all.html" TARGET="bottomleftframe">All Differences</A></FONT><br></TD>
    ++</TR>
    ++<TR>
    ++  <TD NOWRAP><FONT CLASS="indexText" size="-2"><A HREF="packages_index_all.html" TARGET="bottomleftframe">By Package</A></FONT><br></TD>
    ++</TR>
    ++<TR>
    ++  <TD NOWRAP><FONT CLASS="indexText" size="-2"><A HREF="classes_index_all.html" TARGET="bottomleftframe">By Class</A></FONT><br></TD>
    ++</TR>
    ++<TR>
    ++  <TD NOWRAP><FONT CLASS="indexText" size="-2"><A HREF="constructors_index_all.html" TARGET="bottomleftframe">By Constructor</A></FONT><br></TD>
    ++</TR>
    ++<TR>
    ++  <TD NOWRAP><FONT CLASS="indexText" size="-2"><A HREF="methods_index_all.html" TARGET="bottomleftframe">By Method</A></FONT><br></TD>
    ++</TR>
    ++<TR>
    ++  <TD NOWRAP><FONT CLASS="indexText" size="-2"><A HREF="fields_index_all.html" TARGET="bottomleftframe">By Field</A></FONT><br></TD>
    ++</TR>
    ++</TABLE>
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    ++</script>
    ++<script type="text/javascript">
    ++  try {
    ++    var pageTracker = _gat._getTracker("UA-5831155-1");
    ++    pageTracker._setAllowAnchor(true);
    ++    pageTracker._initData();
    ++    pageTracker._trackPageview();
    ++  } catch(e) {}
    ++</script>
    ++</BODY>
    ++</HTML>
    +diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/methods_index_additions.html b/docs/html/sdk/support_api_diff/24.2.0/changes/methods_index_additions.html
    +new file mode 100644
    +index 0000000..419a607
    +--- /dev/null
    ++++ b/docs/html/sdk/support_api_diff/24.2.0/changes/methods_index_additions.html
    +@@ -0,0 +1,448 @@
    ++<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
    ++<HTML style="overflow:auto;">
    ++<HEAD>
    ++<meta name="generator" content="JDiff v1.1.0">
    ++<!-- Generated by the JDiff Javadoc doclet -->
    ++<!-- (http://www.jdiff.org) -->
    ++<meta name="description" content="JDiff is a Javadoc doclet which generates an HTML report of all the packages, classes, constructors, methods, and fields which have been removed, added or changed in any way, including their documentation, when two APIs are compared.">
    ++<meta name="keywords" content="diff, jdiff, javadiff, java diff, java difference, API difference, difference between two APIs, API diff, Javadoc, doclet">
    ++<TITLE>
    ++Method Additions Index
    ++</TITLE>
    ++<link href="../../../../assets/android-developer-docs.css" rel="stylesheet" type="text/css" />
    ++<link href="../stylesheet-jdiff.css" rel="stylesheet" type="text/css" />
    ++<noscript>
    ++<style type="text/css">
    ++body{overflow:auto;}
    ++#body-content{position:relative; top:0;}
    ++#doc-content{overflow:visible;border-left:3px solid #666;}
    ++#side-nav{padding:0;}
    ++#side-nav .toggle-list ul {display:block;}
    ++#resize-packages-nav{border-bottom:3px solid #666;}
    ++</style>
    ++</noscript>
    ++<style type="text/css">
    ++</style>
    ++</HEAD>
    ++<BODY class="gc-documentation" style="padding:12px;">
    ++<a NAME="topheader"></a>
    ++<table summary="Index for Methods" width="100%" class="jdiffIndex" border="0" cellspacing="0" cellpadding="0" style="padding-bottom:0;margin-bottom:0;">
    ++  <tr>
    ++  <th class="indexHeader">
    ++    Filter the Index:
    ++  </th>
    ++  </tr>
    ++  <tr>
    ++  <td class="indexText" style="line-height:1.3em;padding-left:2em;">
    ++<a href="methods_index_all.html" class="staysblack">All Methods</a>
    ++  <br>
    ++<A HREF="methods_index_removals.html" xclass="hiddenlink">Removals</A>
    ++  <br>
    ++<b>Additions</b>
    ++  <br>
    ++<A HREF="methods_index_changes.html"xclass="hiddenlink">Changes</A>
    ++  </td>
    ++  </tr>
    ++</table>
    ++<div id="indexTableCaption" style="background-color:#eee;padding:0 4px 0 4px;font-size:11px;margin-bottom:1em;">
    ++Listed as: <span style="color:#069"><strong>Added</strong></span>,  <span style="color:#069"><strike>Removed</strike></span>,  <span style="color:#069">Changed</span></font>
    ++</div>
    ++<A NAME="A"></A>
    ++<br><font size="+2">A</font>&nbsp;
    ++<a href="#B"><font size="-2">B</font></a> 
    ++<a href="#C"><font size="-2">C</font></a> 
    ++<a href="#F"><font size="-2">F</font></a> 
    ++<a href="#G"><font size="-2">G</font></a> 
    ++<a href="#I"><font size="-2">I</font></a> 
    ++<a href="#L"><font size="-2">L</font></a> 
    ++<a href="#M"><font size="-2">M</font></a> 
    ++<a href="#N"><font size="-2">N</font></a> 
    ++<a href="#O"><font size="-2">O</font></a> 
    ++<a href="#R"><font size="-2">R</font></a> 
    ++<a href="#S"><font size="-2">S</font></a> 
    ++<a href="#T"><font size="-2">T</font></a> 
    ++ <a href="#topheader"><font size="-2">TOP</font></a>
    ++<p><div style="line-height:1.5em;color:black">
    ++<nobr><A HREF="android.support.v4.view.accessibility.AccessibilityManagerCompat.html#android.support.v4.view.accessibility.AccessibilityManagerCompat.addTouchExplorationStateChangeListener_added(android.view.accessibility.AccessibilityManager, android.support.v4.view.accessibility.AccessibilityManagerCompat.TouchExplorationStateChangeListener)" class="hiddenlink" target="rightframe"><b>addTouchExplorationStateChangeListener</b>
    ++(<code>AccessibilityManager, TouchExplorationStateChangeListener</code>)</A></nobr><br>
    ++<A NAME="B"></A>
    ++<br><font size="+2">B</font>&nbsp;
    ++<a href="#A"><font size="-2">A</font></a> 
    ++<a href="#C"><font size="-2">C</font></a> 
    ++<a href="#F"><font size="-2">F</font></a> 
    ++<a href="#G"><font size="-2">G</font></a> 
    ++<a href="#I"><font size="-2">I</font></a> 
    ++<a href="#L"><font size="-2">L</font></a> 
    ++<a href="#M"><font size="-2">M</font></a> 
    ++<a href="#N"><font size="-2">N</font></a> 
    ++<a href="#O"><font size="-2">O</font></a> 
    ++<a href="#R"><font size="-2">R</font></a> 
    ++<a href="#S"><font size="-2">S</font></a> 
    ++<a href="#T"><font size="-2">T</font></a> 
    ++ <a href="#topheader"><font size="-2">TOP</font></a>
    ++<p><div style="line-height:1.5em;color:black">
    ++<i>buildMediaButtonPendingIntent</i><br>
    ++&nbsp;&nbsp;<nobr><A HREF="android.support.v4.media.session.MediaButtonReceiver.html#android.support.v4.media.session.MediaButtonReceiver.buildMediaButtonPendingIntent_added(android.content.Context, android.content.ComponentName, long)" class="hiddenlink" target="rightframe">type&nbsp;<b>
    ++(<code>Context, ComponentName, long</code>)</b>&nbsp;in&nbsp;android.support.v4.media.session.MediaButtonReceiver
    ++</A></nobr><br>
    ++&nbsp;&nbsp;<nobr><A HREF="android.support.v4.media.session.MediaButtonReceiver.html#android.support.v4.media.session.MediaButtonReceiver.buildMediaButtonPendingIntent_added(android.content.Context, long)" class="hiddenlink" target="rightframe">type&nbsp;<b>
    ++(<code>Context, long</code>)</b>&nbsp;in&nbsp;android.support.v4.media.session.MediaButtonReceiver
    ++</A></nobr><br>
    ++<A NAME="C"></A>
    ++<br><font size="+2">C</font>&nbsp;
    ++<a href="#A"><font size="-2">A</font></a> 
    ++<a href="#B"><font size="-2">B</font></a> 
    ++<a href="#F"><font size="-2">F</font></a> 
    ++<a href="#G"><font size="-2">G</font></a> 
    ++<a href="#I"><font size="-2">I</font></a> 
    ++<a href="#L"><font size="-2">L</font></a> 
    ++<a href="#M"><font size="-2">M</font></a> 
    ++<a href="#N"><font size="-2">N</font></a> 
    ++<a href="#O"><font size="-2">O</font></a> 
    ++<a href="#R"><font size="-2">R</font></a> 
    ++<a href="#S"><font size="-2">S</font></a> 
    ++<a href="#T"><font size="-2">T</font></a> 
    ++ <a href="#topheader"><font size="-2">TOP</font></a>
    ++<p><div style="line-height:1.5em;color:black">
    ++<nobr><A HREF="android.support.v4.graphics.drawable.DrawableCompat.html#android.support.v4.graphics.drawable.DrawableCompat.clearColorFilter_added(android.graphics.drawable.Drawable)" class="hiddenlink" target="rightframe"><b>clearColorFilter</b>
    ++(<code>Drawable</code>)</A></nobr><br>
    ++<nobr><A HREF="android.support.design.widget.TabLayout.html#android.support.design.widget.TabLayout.clearOnTabSelectedListeners_added()" class="hiddenlink" target="rightframe"><b>clearOnTabSelectedListeners</b>
    ++()</A></nobr><br>
    ++<nobr><A HREF="android.support.v7.widget.StaggeredGridLayoutManager.html#android.support.v7.widget.StaggeredGridLayoutManager.computeScrollVectorForPosition_added(int)" class="hiddenlink" target="rightframe"><b>computeScrollVectorForPosition</b>
    ++(<code>int</code>)</A></nobr><br>
    ++<A NAME="F"></A>
    ++<br><font size="+2">F</font>&nbsp;
    ++<a href="#A"><font size="-2">A</font></a> 
    ++<a href="#B"><font size="-2">B</font></a> 
    ++<a href="#C"><font size="-2">C</font></a> 
    ++<a href="#G"><font size="-2">G</font></a> 
    ++<a href="#I"><font size="-2">I</font></a> 
    ++<a href="#L"><font size="-2">L</font></a> 
    ++<a href="#M"><font size="-2">M</font></a> 
    ++<a href="#N"><font size="-2">N</font></a> 
    ++<a href="#O"><font size="-2">O</font></a> 
    ++<a href="#R"><font size="-2">R</font></a> 
    ++<a href="#S"><font size="-2">S</font></a> 
    ++<a href="#T"><font size="-2">T</font></a> 
    ++ <a href="#topheader"><font size="-2">TOP</font></a>
    ++<p><div style="line-height:1.5em;color:black">
    ++<nobr><A HREF="android.support.v4.app.FragmentController.html#android.support.v4.app.FragmentController.findFragmentByWho_added(java.lang.String)" class="hiddenlink" target="rightframe"><b>findFragmentByWho</b>
    ++(<code>String</code>)</A></nobr><br>
    ++<nobr><A HREF="android.support.v4.media.MediaBrowserCompat.MediaItem.html#android.support.v4.media.MediaBrowserCompat.MediaItem.fromMediaItem_added(java.lang.Object)" class="hiddenlink" target="rightframe"><b>fromMediaItem</b>
    ++(<code>Object</code>)</A></nobr><br>
    ++<nobr><A HREF="android.support.v4.media.MediaBrowserCompat.MediaItem.html#android.support.v4.media.MediaBrowserCompat.MediaItem.fromMediaItemList_added(java.util.List<?>)" class="hiddenlink" target="rightframe"><b>fromMediaItemList</b>
    ++(<code>List&lt;?&gt;</code>)</A></nobr><br>
    ++<nobr><A HREF="android.support.v4.media.session.MediaSessionCompat.html#android.support.v4.media.session.MediaSessionCompat.fromMediaSession_added(android.content.Context, java.lang.Object)" class="hiddenlink" target="rightframe"><b>fromMediaSession</b>
    ++(<code>Context, Object</code>)</A></nobr><br>
    ++<nobr><A HREF="android.support.v4.media.session.MediaSessionCompat.QueueItem.html#android.support.v4.media.session.MediaSessionCompat.QueueItem.fromQueueItem_added(java.lang.Object)" class="hiddenlink" target="rightframe"><b>fromQueueItem</b>
    ++(<code>Object</code>)</A></nobr><br>
    ++<nobr><A HREF="android.support.v4.media.session.MediaSessionCompat.QueueItem.html#android.support.v4.media.session.MediaSessionCompat.QueueItem.fromQueueItemList_added(java.util.List<?>)" class="hiddenlink" target="rightframe"><b>fromQueueItemList</b>
    ++(<code>List&lt;?&gt;</code>)</A></nobr><br>
    ++<A NAME="G"></A>
    ++<br><font size="+2">G</font>&nbsp;
    ++<a href="#A"><font size="-2">A</font></a> 
    ++<a href="#B"><font size="-2">B</font></a> 
    ++<a href="#C"><font size="-2">C</font></a> 
    ++<a href="#F"><font size="-2">F</font></a> 
    ++<a href="#I"><font size="-2">I</font></a> 
    ++<a href="#L"><font size="-2">L</font></a> 
    ++<a href="#M"><font size="-2">M</font></a> 
    ++<a href="#N"><font size="-2">N</font></a> 
    ++<a href="#O"><font size="-2">O</font></a> 
    ++<a href="#R"><font size="-2">R</font></a> 
    ++<a href="#S"><font size="-2">S</font></a> 
    ++<a href="#T"><font size="-2">T</font></a> 
    ++ <a href="#topheader"><font size="-2">TOP</font></a>
    ++<p><div style="line-height:1.5em;color:black">
    ++<nobr><A HREF="android.support.v4.view.accessibility.AccessibilityEventCompat.html#android.support.v4.view.accessibility.AccessibilityEventCompat.getAction_added(android.view.accessibility.AccessibilityEvent)" class="hiddenlink" target="rightframe"><b>getAction</b>
    ++(<code>AccessibilityEvent</code>)</A></nobr><br>
    ++<nobr><A HREF="android.support.v4.widget.TextViewCompat.html#android.support.v4.widget.TextViewCompat.getCompoundDrawablesRelative_added(android.widget.TextView)" class="hiddenlink" target="rightframe"><b>getCompoundDrawablesRelative</b>
    ++(<code>TextView</code>)</A></nobr><br>
    ++<nobr><A HREF="android.support.design.widget.CoordinatorLayout.html#android.support.design.widget.CoordinatorLayout.getDependents_added(android.view.View)" class="hiddenlink" target="rightframe"><b>getDependents</b>
    ++(<code>View</code>)</A></nobr><br>
    ++<nobr><A HREF="android.support.v7.graphics.Palette.html#android.support.v7.graphics.Palette.getDominantColor_added(int)" class="hiddenlink" target="rightframe"><b>getDominantColor</b>
    ++(<code>int</code>)</A></nobr><br>
    ++<nobr><A HREF="android.support.v7.graphics.Palette.html#android.support.v7.graphics.Palette.getDominantSwatch_added()" class="hiddenlink" target="rightframe"><b>getDominantSwatch</b>
    ++()</A></nobr><br>
    ++<nobr><A HREF="android.support.v7.content.res.AppCompatResources.html#android.support.v7.content.res.AppCompatResources.getDrawable_added(android.content.Context, int)" class="hiddenlink" target="rightframe"><b>getDrawable</b>
    ++(<code>Context, int</code>)</A></nobr><br>
    ++<nobr><A HREF="android.support.v7.app.ActionBarDrawerToggle.html#android.support.v7.app.ActionBarDrawerToggle.getDrawerArrowDrawable_added()" class="hiddenlink" target="rightframe"><b>getDrawerArrowDrawable</b>
    ++()</A></nobr><br>
    ++<i>getInsetDodgeRect</i><br>
    ++&nbsp;&nbsp;<nobr><A HREF="android.support.design.widget.CoordinatorLayout.Behavior.html#android.support.design.widget.CoordinatorLayout.Behavior.getInsetDodgeRect_added(android.support.design.widget.CoordinatorLayout, V, android.graphics.Rect)" class="hiddenlink" target="rightframe">type&nbsp;<b>
    ++(<code>CoordinatorLayout, V, Rect</code>)</b>&nbsp;in&nbsp;android.support.design.widget.CoordinatorLayout.Behavior
    ++</A></nobr><br>
    ++&nbsp;&nbsp;<nobr><A HREF="android.support.design.widget.FloatingActionButton.Behavior.html#android.support.design.widget.FloatingActionButton.Behavior.getInsetDodgeRect_added(android.support.design.widget.CoordinatorLayout, android.support.design.widget.FloatingActionButton, android.graphics.Rect)" class="hiddenlink" target="rightframe">type&nbsp;<b>
    ++(<code>CoordinatorLayout, FloatingActionButton, Rect</code>)</b>&nbsp;in&nbsp;android.support.design.widget.FloatingActionButton.Behavior
    ++</A></nobr><br>
    ++<nobr><A HREF="android.support.v4.app.ActivityOptionsCompat.html#android.support.v4.app.ActivityOptionsCompat.getLaunchBounds_added()" class="hiddenlink" target="rightframe"><b>getLaunchBounds</b>
    ++()</A></nobr><br>
    ++<nobr><A HREF="android.support.v17.leanback.widget.AbstractMediaItemPresenter.ViewHolder.html#android.support.v17.leanback.widget.AbstractMediaItemPresenter.ViewHolder.getMediaItemNumberViewFlipper_added()" class="hiddenlink" target="rightframe"><b>getMediaItemNumberViewFlipper</b>
    ++()</A></nobr><br>
    ++<nobr><A HREF="android.support.v17.leanback.widget.AbstractMediaItemPresenter.ViewHolder.html#android.support.v17.leanback.widget.AbstractMediaItemPresenter.ViewHolder.getMediaItemPausedView_added()" class="hiddenlink" target="rightframe"><b>getMediaItemPausedView</b>
    ++()</A></nobr><br>
    ++<nobr><A HREF="android.support.v17.leanback.widget.AbstractMediaItemPresenter.ViewHolder.html#android.support.v17.leanback.widget.AbstractMediaItemPresenter.ViewHolder.getMediaItemPlayingView_added()" class="hiddenlink" target="rightframe"><b>getMediaItemPlayingView</b>
    ++()</A></nobr><br>
    ++<nobr><A HREF="android.support.v17.leanback.widget.AbstractMediaItemPresenter.html#android.support.v17.leanback.widget.AbstractMediaItemPresenter.getMediaPlayState_added(java.lang.Object)" class="hiddenlink" target="rightframe"><b>getMediaPlayState</b>
    ++(<code>Object</code>)</A></nobr><br>
    ++<nobr><A HREF="android.support.v4.view.accessibility.AccessibilityEventCompat.html#android.support.v4.view.accessibility.AccessibilityEventCompat.getMovementGranularity_added(android.view.accessibility.AccessibilityEvent)" class="hiddenlink" target="rightframe"><b>getMovementGranularity</b>
    ++(<code>AccessibilityEvent</code>)</A></nobr><br>
    ++<nobr><A HREF="android.support.v7.widget.RecyclerView.html#android.support.v7.widget.RecyclerView.getOnFlingListener_added()" class="hiddenlink" target="rightframe"><b>getOnFlingListener</b>
    ++()</A></nobr><br>
    ++<nobr><A HREF="android.support.design.widget.TextInputLayout.html#android.support.design.widget.TextInputLayout.getPasswordVisibilityToggleContentDescription_added()" class="hiddenlink" target="rightframe"><b>getPasswordVisibilityToggleContentDescription</b>
    ++()</A></nobr><br>
    ++<nobr><A HREF="android.support.design.widget.TextInputLayout.html#android.support.design.widget.TextInputLayout.getPasswordVisibilityToggleDrawable_added()" class="hiddenlink" target="rightframe"><b>getPasswordVisibilityToggleDrawable</b>
    ++()</A></nobr><br>
    ++<nobr><A HREF="android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.CollectionInfoCompat.html#android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.CollectionInfoCompat.getSelectionMode_added()" class="hiddenlink" target="rightframe"><b>getSelectionMode</b>
    ++()</A></nobr><br>
    ++<A NAME="I"></A>
    ++<br><font size="+2">I</font>&nbsp;
    ++<a href="#A"><font size="-2">A</font></a> 
    ++<a href="#B"><font size="-2">B</font></a> 
    ++<a href="#C"><font size="-2">C</font></a> 
    ++<a href="#F"><font size="-2">F</font></a> 
    ++<a href="#G"><font size="-2">G</font></a> 
    ++<a href="#L"><font size="-2">L</font></a> 
    ++<a href="#M"><font size="-2">M</font></a> 
    ++<a href="#N"><font size="-2">N</font></a> 
    ++<a href="#O"><font size="-2">O</font></a> 
    ++<a href="#R"><font size="-2">R</font></a> 
    ++<a href="#S"><font size="-2">S</font></a> 
    ++<a href="#T"><font size="-2">T</font></a> 
    ++ <a href="#topheader"><font size="-2">TOP</font></a>
    ++<p><div style="line-height:1.5em;color:black">
    ++<nobr><A HREF="android.support.v4.os.BuildCompat.html#android.support.v4.os.BuildCompat.isAtLeastNMR1_added()" class="hiddenlink" target="rightframe"><b>isAtLeastNMR1</b>
    ++()</A></nobr><br>
    ++<nobr><A HREF="android.support.design.widget.FloatingActionButton.Behavior.html#android.support.design.widget.FloatingActionButton.Behavior.isAutoHideEnabled_added()" class="hiddenlink" target="rightframe"><b>isAutoHideEnabled</b>
    ++()</A></nobr><br>
    ++<nobr><A HREF="android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.html#android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.isContextClickable_added()" class="hiddenlink" target="rightframe"><b>isContextClickable</b>
    ++()</A></nobr><br>
    ++<nobr><A HREF="android.support.v17.leanback.widget.ObjectAdapter.html#android.support.v17.leanback.widget.ObjectAdapter.isImmediateNotifySupported_added()" class="hiddenlink" target="rightframe"><b>isImmediateNotifySupported</b>
    ++()</A></nobr><br>
    ++<nobr><A HREF="android.support.v4.view.ViewCompat.html#android.support.v4.view.ViewCompat.isImportantForAccessibility_added(android.view.View)" class="hiddenlink" target="rightframe"><b>isImportantForAccessibility</b>
    ++(<code>View</code>)</A></nobr><br>
    ++<nobr><A HREF="android.support.design.widget.TextInputLayout.html#android.support.design.widget.TextInputLayout.isPasswordVisibilityToggleEnabled_added()" class="hiddenlink" target="rightframe"><b>isPasswordVisibilityToggleEnabled</b>
    ++()</A></nobr><br>
    ++<A NAME="L"></A>
    ++<br><font size="+2">L</font>&nbsp;
    ++<a href="#A"><font size="-2">A</font></a> 
    ++<a href="#B"><font size="-2">B</font></a> 
    ++<a href="#C"><font size="-2">C</font></a> 
    ++<a href="#F"><font size="-2">F</font></a> 
    ++<a href="#G"><font size="-2">G</font></a> 
    ++<a href="#I"><font size="-2">I</font></a> 
    ++<a href="#M"><font size="-2">M</font></a> 
    ++<a href="#N"><font size="-2">N</font></a> 
    ++<a href="#O"><font size="-2">O</font></a> 
    ++<a href="#R"><font size="-2">R</font></a> 
    ++<a href="#S"><font size="-2">S</font></a> 
    ++<a href="#T"><font size="-2">T</font></a> 
    ++ <a href="#topheader"><font size="-2">TOP</font></a>
    ++<p><div style="line-height:1.5em;color:black">
    ++<nobr><A HREF="android.support.v4.accessibilityservice.AccessibilityServiceInfoCompat.html#android.support.v4.accessibilityservice.AccessibilityServiceInfoCompat.loadDescription_added(android.accessibilityservice.AccessibilityServiceInfo, android.content.pm.PackageManager)" class="hiddenlink" target="rightframe"><b>loadDescription</b>
    ++(<code>AccessibilityServiceInfo, PackageManager</code>)</A></nobr><br>
    ++<A NAME="M"></A>
    ++<br><font size="+2">M</font>&nbsp;
    ++<a href="#A"><font size="-2">A</font></a> 
    ++<a href="#B"><font size="-2">B</font></a> 
    ++<a href="#C"><font size="-2">C</font></a> 
    ++<a href="#F"><font size="-2">F</font></a> 
    ++<a href="#G"><font size="-2">G</font></a> 
    ++<a href="#I"><font size="-2">I</font></a> 
    ++<a href="#L"><font size="-2">L</font></a> 
    ++<a href="#N"><font size="-2">N</font></a> 
    ++<a href="#O"><font size="-2">O</font></a> 
    ++<a href="#R"><font size="-2">R</font></a> 
    ++<a href="#S"><font size="-2">S</font></a> 
    ++<a href="#T"><font size="-2">T</font></a> 
    ++ <a href="#topheader"><font size="-2">TOP</font></a>
    ++<p><div style="line-height:1.5em;color:black">
    ++<nobr><A HREF="android.support.v4.app.ActivityOptionsCompat.html#android.support.v4.app.ActivityOptionsCompat.makeBasic_added()" class="hiddenlink" target="rightframe"><b>makeBasic</b>
    ++()</A></nobr><br>
    ++<nobr><A HREF="android.support.v4.app.ActivityOptionsCompat.html#android.support.v4.app.ActivityOptionsCompat.makeClipRevealAnimation_added(android.view.View, int, int, int, int)" class="hiddenlink" target="rightframe"><b>makeClipRevealAnimation</b>
    ++(<code>View, int, int, int, int</code>)</A></nobr><br>
    ++<nobr><A HREF="android.support.v4.app.ActivityOptionsCompat.html#android.support.v4.app.ActivityOptionsCompat.makeTaskLaunchBehind_added()" class="hiddenlink" target="rightframe"><b>makeTaskLaunchBehind</b>
    ++()</A></nobr><br>
    ++<A NAME="N"></A>
    ++<br><font size="+2">N</font>&nbsp;
    ++<a href="#A"><font size="-2">A</font></a> 
    ++<a href="#B"><font size="-2">B</font></a> 
    ++<a href="#C"><font size="-2">C</font></a> 
    ++<a href="#F"><font size="-2">F</font></a> 
    ++<a href="#G"><font size="-2">G</font></a> 
    ++<a href="#I"><font size="-2">I</font></a> 
    ++<a href="#L"><font size="-2">L</font></a> 
    ++<a href="#M"><font size="-2">M</font></a> 
    ++<a href="#O"><font size="-2">O</font></a> 
    ++<a href="#R"><font size="-2">R</font></a> 
    ++<a href="#S"><font size="-2">S</font></a> 
    ++<a href="#T"><font size="-2">T</font></a> 
    ++ <a href="#topheader"><font size="-2">TOP</font></a>
    ++<p><div style="line-height:1.5em;color:black">
    ++<nobr><A HREF="android.support.v17.leanback.widget.AbstractMediaItemPresenter.ViewHolder.html#android.support.v17.leanback.widget.AbstractMediaItemPresenter.ViewHolder.notifyPlayStateChanged_added()" class="hiddenlink" target="rightframe"><b>notifyPlayStateChanged</b>
    ++()</A></nobr><br>
    ++<A NAME="O"></A>
    ++<br><font size="+2">O</font>&nbsp;
    ++<a href="#A"><font size="-2">A</font></a> 
    ++<a href="#B"><font size="-2">B</font></a> 
    ++<a href="#C"><font size="-2">C</font></a> 
    ++<a href="#F"><font size="-2">F</font></a> 
    ++<a href="#G"><font size="-2">G</font></a> 
    ++<a href="#I"><font size="-2">I</font></a> 
    ++<a href="#L"><font size="-2">L</font></a> 
    ++<a href="#M"><font size="-2">M</font></a> 
    ++<a href="#N"><font size="-2">N</font></a> 
    ++<a href="#R"><font size="-2">R</font></a> 
    ++<a href="#S"><font size="-2">S</font></a> 
    ++<a href="#T"><font size="-2">T</font></a> 
    ++ <a href="#topheader"><font size="-2">TOP</font></a>
    ++<p><div style="line-height:1.5em;color:black">
    ++<i>obtain</i><br>
    ++&nbsp;&nbsp;<nobr><A HREF="android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.CollectionInfoCompat.html#android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.CollectionInfoCompat.obtain_added(int, int, boolean)" class="hiddenlink" target="rightframe">type&nbsp;<b>
    ++(<code>int, int, boolean</code>)</b>&nbsp;in&nbsp;android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.CollectionInfoCompat
    ++</A></nobr><br>
    ++&nbsp;&nbsp;<nobr><A HREF="android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.CollectionItemInfoCompat.html#android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.CollectionItemInfoCompat.obtain_added(int, int, int, int, boolean)" class="hiddenlink" target="rightframe">type&nbsp;<b>
    ++(<code>int, int, int, int, boolean</code>)</b>&nbsp;in&nbsp;android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.CollectionItemInfoCompat
    ++</A></nobr><br>
    ++&nbsp;&nbsp;<nobr><A HREF="android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.RangeInfoCompat.html#android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.RangeInfoCompat.obtain_added(int, float, float, float)" class="hiddenlink" target="rightframe">type&nbsp;<b>
    ++(<code>int, float, float, float</code>)</b>&nbsp;in&nbsp;android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.RangeInfoCompat
    ++</A></nobr><br>
    ++<nobr><A HREF="android.support.design.widget.CoordinatorLayout.Behavior.html#android.support.design.widget.CoordinatorLayout.Behavior.onAttachedToLayoutParams_added(android.support.design.widget.CoordinatorLayout.LayoutParams)" class="hiddenlink" target="rightframe"><b>onAttachedToLayoutParams</b>
    ++(<code>LayoutParams</code>)</A></nobr><br>
    ++<nobr><A HREF="android.support.v17.leanback.widget.AbstractMediaItemPresenter.html#android.support.v17.leanback.widget.AbstractMediaItemPresenter.onBindMediaPlayState_added(android.support.v17.leanback.widget.AbstractMediaItemPresenter.ViewHolder)" class="hiddenlink" target="rightframe"><b>onBindMediaPlayState</b>
    ++(<code>ViewHolder</code>)</A></nobr><br>
    ++<nobr><A HREF="android.support.v7.util.SortedList.Callback.html#android.support.v7.util.SortedList.Callback.onChanged_added(int, int, java.lang.Object)" class="hiddenlink" target="rightframe"><b>onChanged</b>
    ++(<code>int, int, Object</code>)</A></nobr><br>
    ++<nobr><A HREF="android.support.design.widget.CoordinatorLayout.Behavior.html#android.support.design.widget.CoordinatorLayout.Behavior.onDetachedFromLayoutParams_added()" class="hiddenlink" target="rightframe"><b>onDetachedFromLayoutParams</b>
    ++()</A></nobr><br>
    ++<i>onRequestChildRectangleOnScreen</i><br>
    ++&nbsp;&nbsp;<nobr><A HREF="android.support.design.widget.AppBarLayout.ScrollingViewBehavior.html#android.support.design.widget.AppBarLayout.ScrollingViewBehavior.onRequestChildRectangleOnScreen_added(android.support.design.widget.CoordinatorLayout, android.view.View, android.graphics.Rect, boolean)" class="hiddenlink" target="rightframe">type&nbsp;<b>
    ++(<code>CoordinatorLayout, View, Rect, boolean</code>)</b>&nbsp;in&nbsp;android.support.design.widget.AppBarLayout.ScrollingViewBehavior
    ++</A></nobr><br>
    ++&nbsp;&nbsp;<nobr><A HREF="android.support.design.widget.CoordinatorLayout.Behavior.html#android.support.design.widget.CoordinatorLayout.Behavior.onRequestChildRectangleOnScreen_added(android.support.design.widget.CoordinatorLayout, V, android.graphics.Rect, boolean)" class="hiddenlink" target="rightframe">type&nbsp;<b>
    ++(<code>CoordinatorLayout, V, Rect, boolean</code>)</b>&nbsp;in&nbsp;android.support.design.widget.CoordinatorLayout.Behavior
    ++</A></nobr><br>
    ++<nobr><A HREF="android.support.v4.app.SharedElementCallback.html#android.support.v4.app.SharedElementCallback.onSharedElementsArrived_added(java.util.List<java.lang.String>, java.util.List<android.view.View>, android.support.v4.app.SharedElementCallback.OnSharedElementsReadyListener)" class="hiddenlink" target="rightframe"><b>onSharedElementsArrived</b>
    ++(<code>List&lt;String&gt;, List&lt;View&gt;, OnSharedElementsReadyListener</code>)</A></nobr><br>
    ++<nobr><A HREF="android.support.v7.app.AppCompatDelegate.html#android.support.v7.app.AppCompatDelegate.onStart_added()" class="hiddenlink" target="rightframe"><b>onStart</b>
    ++()</A></nobr><br>
    ++<nobr><A HREF="android.support.v17.leanback.widget.AbstractMediaItemPresenter.html#android.support.v17.leanback.widget.AbstractMediaItemPresenter.onUnbindMediaPlayState_added(android.support.v17.leanback.widget.AbstractMediaItemPresenter.ViewHolder)" class="hiddenlink" target="rightframe"><b>onUnbindMediaPlayState</b>
    ++(<code>ViewHolder</code>)</A></nobr><br>
    ++<A NAME="R"></A>
    ++<br><font size="+2">R</font>&nbsp;
    ++<a href="#A"><font size="-2">A</font></a> 
    ++<a href="#B"><font size="-2">B</font></a> 
    ++<a href="#C"><font size="-2">C</font></a> 
    ++<a href="#F"><font size="-2">F</font></a> 
    ++<a href="#G"><font size="-2">G</font></a> 
    ++<a href="#I"><font size="-2">I</font></a> 
    ++<a href="#L"><font size="-2">L</font></a> 
    ++<a href="#M"><font size="-2">M</font></a> 
    ++<a href="#N"><font size="-2">N</font></a> 
    ++<a href="#O"><font size="-2">O</font></a> 
    ++<a href="#S"><font size="-2">S</font></a> 
    ++<a href="#T"><font size="-2">T</font></a> 
    ++ <a href="#topheader"><font size="-2">TOP</font></a>
    ++<p><div style="line-height:1.5em;color:black">
    ++<nobr><A HREF="android.support.v4.view.accessibility.AccessibilityManagerCompat.html#android.support.v4.view.accessibility.AccessibilityManagerCompat.removeTouchExplorationStateChangeListener_added(android.view.accessibility.AccessibilityManager, android.support.v4.view.accessibility.AccessibilityManagerCompat.TouchExplorationStateChangeListener)" class="hiddenlink" target="rightframe"><b>removeTouchExplorationStateChangeListener</b>
    ++(<code>AccessibilityManager, TouchExplorationStateChangeListener</code>)</A></nobr><br>
    ++<nobr><A HREF="android.support.v4.app.ActivityOptionsCompat.html#android.support.v4.app.ActivityOptionsCompat.requestUsageTimeReport_added(android.app.PendingIntent)" class="hiddenlink" target="rightframe"><b>requestUsageTimeReport</b>
    ++(<code>PendingIntent</code>)</A></nobr><br>
    ++<A NAME="S"></A>
    ++<br><font size="+2">S</font>&nbsp;
    ++<a href="#A"><font size="-2">A</font></a> 
    ++<a href="#B"><font size="-2">B</font></a> 
    ++<a href="#C"><font size="-2">C</font></a> 
    ++<a href="#F"><font size="-2">F</font></a> 
    ++<a href="#G"><font size="-2">G</font></a> 
    ++<a href="#I"><font size="-2">I</font></a> 
    ++<a href="#L"><font size="-2">L</font></a> 
    ++<a href="#M"><font size="-2">M</font></a> 
    ++<a href="#N"><font size="-2">N</font></a> 
    ++<a href="#O"><font size="-2">O</font></a> 
    ++<a href="#R"><font size="-2">R</font></a> 
    ++<a href="#T"><font size="-2">T</font></a> 
    ++ <a href="#topheader"><font size="-2">TOP</font></a>
    ++<p><div style="line-height:1.5em;color:black">
    ++<nobr><A HREF="android.support.v4.view.accessibility.AccessibilityEventCompat.html#android.support.v4.view.accessibility.AccessibilityEventCompat.setAction_added(android.view.accessibility.AccessibilityEvent, int)" class="hiddenlink" target="rightframe"><b>setAction</b>
    ++(<code>AccessibilityEvent, int</code>)</A></nobr><br>
    ++<nobr><A HREF="android.support.customtabs.CustomTabsIntent.html#android.support.customtabs.CustomTabsIntent.setAlwaysUseBrowserUI_added(android.content.Intent)" class="hiddenlink" target="rightframe"><b>setAlwaysUseBrowserUI</b>
    ++(<code>Intent</code>)</A></nobr><br>
    ++<nobr><A HREF="android.support.design.widget.FloatingActionButton.Behavior.html#android.support.design.widget.FloatingActionButton.Behavior.setAutoHideEnabled_added(boolean)" class="hiddenlink" target="rightframe"><b>setAutoHideEnabled</b>
    ++(<code>boolean</code>)</A></nobr><br>
    ++<nobr><A HREF="android.support.design.widget.CollapsingToolbarLayout.html#android.support.design.widget.CollapsingToolbarLayout.setCollapsedTitleTextColor_added(android.content.res.ColorStateList)" class="hiddenlink" target="rightframe"><b>setCollapsedTitleTextColor</b>
    ++(<code>ColorStateList</code>)</A></nobr><br>
    ++<nobr><A HREF="android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.html#android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.setContextClickable_added(boolean)" class="hiddenlink" target="rightframe"><b>setContextClickable</b>
    ++(<code>boolean</code>)</A></nobr><br>
    ++<nobr><A HREF="android.support.v7.app.ActionBarDrawerToggle.html#android.support.v7.app.ActionBarDrawerToggle.setDrawerArrowDrawable_added(android.support.v7.graphics.drawable.DrawerArrowDrawable)" class="hiddenlink" target="rightframe"><b>setDrawerArrowDrawable</b>
    ++(<code>DrawerArrowDrawable</code>)</A></nobr><br>
    ++<nobr><A HREF="android.support.design.widget.CollapsingToolbarLayout.html#android.support.design.widget.CollapsingToolbarLayout.setExpandedTitleTextColor_added(android.content.res.ColorStateList)" class="hiddenlink" target="rightframe"><b>setExpandedTitleTextColor</b>
    ++(<code>ColorStateList</code>)</A></nobr><br>
    ++<nobr><A HREF="android.support.customtabs.CustomTabsIntent.Builder.html#android.support.customtabs.CustomTabsIntent.Builder.setInstantAppsEnabled_added(boolean)" class="hiddenlink" target="rightframe"><b>setInstantAppsEnabled</b>
    ++(<code>boolean</code>)</A></nobr><br>
    ++<nobr><A HREF="android.support.v4.app.ActivityOptionsCompat.html#android.support.v4.app.ActivityOptionsCompat.setLaunchBounds_added(android.graphics.Rect)" class="hiddenlink" target="rightframe"><b>setLaunchBounds</b>
    ++(<code>Rect</code>)</A></nobr><br>
    ++<nobr><A HREF="android.support.v4.view.accessibility.AccessibilityEventCompat.html#android.support.v4.view.accessibility.AccessibilityEventCompat.setMovementGranularity_added(android.view.accessibility.AccessibilityEvent, int)" class="hiddenlink" target="rightframe"><b>setMovementGranularity</b>
    ++(<code>AccessibilityEvent, int</code>)</A></nobr><br>
    ++<nobr><A HREF="android.support.v4.widget.SwipeRefreshLayout.html#android.support.v4.widget.SwipeRefreshLayout.setOnChildScrollUpCallback_added(android.support.v4.widget.SwipeRefreshLayout.OnChildScrollUpCallback)" class="hiddenlink" target="rightframe"><b>setOnChildScrollUpCallback</b>
    ++(<code>OnChildScrollUpCallback</code>)</A></nobr><br>
    ++<nobr><A HREF="android.support.v7.widget.RecyclerView.html#android.support.v7.widget.RecyclerView.setOnFlingListener_added(android.support.v7.widget.RecyclerView.OnFlingListener)" class="hiddenlink" target="rightframe"><b>setOnFlingListener</b>
    ++(<code>OnFlingListener</code>)</A></nobr><br>
    ++<i>setPasswordVisibilityToggleContentDescription</i><br>
    ++&nbsp;&nbsp;<nobr><A HREF="android.support.design.widget.TextInputLayout.html#android.support.design.widget.TextInputLayout.setPasswordVisibilityToggleContentDescription_added(int)" class="hiddenlink" target="rightframe">type&nbsp;<b>
    ++(<code>int</code>)</b>&nbsp;in&nbsp;android.support.design.widget.TextInputLayout
    ++</A></nobr><br>
    ++&nbsp;&nbsp;<nobr><A HREF="android.support.design.widget.TextInputLayout.html#android.support.design.widget.TextInputLayout.setPasswordVisibilityToggleContentDescription_added(java.lang.CharSequence)" class="hiddenlink" target="rightframe">type&nbsp;<b>
    ++(<code>CharSequence</code>)</b>&nbsp;in&nbsp;android.support.design.widget.TextInputLayout
    ++</A></nobr><br>
    ++<i>setPasswordVisibilityToggleDrawable</i><br>
    ++&nbsp;&nbsp;<nobr><A HREF="android.support.design.widget.TextInputLayout.html#android.support.design.widget.TextInputLayout.setPasswordVisibilityToggleDrawable_added(android.graphics.drawable.Drawable)" class="hiddenlink" target="rightframe">type&nbsp;<b>
    ++(<code>Drawable</code>)</b>&nbsp;in&nbsp;android.support.design.widget.TextInputLayout
    ++</A></nobr><br>
    ++&nbsp;&nbsp;<nobr><A HREF="android.support.design.widget.TextInputLayout.html#android.support.design.widget.TextInputLayout.setPasswordVisibilityToggleDrawable_added(int)" class="hiddenlink" target="rightframe">type&nbsp;<b>
    ++(<code>int</code>)</b>&nbsp;in&nbsp;android.support.design.widget.TextInputLayout
    ++</A></nobr><br>
    ++<nobr><A HREF="android.support.design.widget.TextInputLayout.html#android.support.design.widget.TextInputLayout.setPasswordVisibilityToggleEnabled_added(boolean)" class="hiddenlink" target="rightframe"><b>setPasswordVisibilityToggleEnabled</b>
    ++(<code>boolean</code>)</A></nobr><br>
    ++<nobr><A HREF="android.support.design.widget.TextInputLayout.html#android.support.design.widget.TextInputLayout.setPasswordVisibilityToggleTintList_added(android.content.res.ColorStateList)" class="hiddenlink" target="rightframe"><b>setPasswordVisibilityToggleTintList</b>
    ++(<code>ColorStateList</code>)</A></nobr><br>
    ++<nobr><A HREF="android.support.design.widget.TextInputLayout.html#android.support.design.widget.TextInputLayout.setPasswordVisibilityToggleTintMode_added(android.graphics.PorterDuff.Mode)" class="hiddenlink" target="rightframe"><b>setPasswordVisibilityToggleTintMode</b>
    ++(<code>Mode</code>)</A></nobr><br>
    ++<nobr><A HREF="android.support.customtabs.CustomTabsSession.html#android.support.customtabs.CustomTabsSession.setSecondaryToolbarViews_added(android.widget.RemoteViews, int[], android.app.PendingIntent)" class="hiddenlink" target="rightframe"><b>setSecondaryToolbarViews</b>
    ++(<code>RemoteViews, int[], PendingIntent</code>)</A></nobr><br>
    ++<nobr><A HREF="android.support.v17.leanback.widget.AbstractMediaItemPresenter.ViewHolder.html#android.support.v17.leanback.widget.AbstractMediaItemPresenter.ViewHolder.setSelectedMediaItemNumberView_added(int)" class="hiddenlink" target="rightframe"><b>setSelectedMediaItemNumberView</b>
    ++(<code>int</code>)</A></nobr><br>
    ++<nobr><A HREF="android.support.customtabs.CustomTabsIntent.html#android.support.customtabs.CustomTabsIntent.shouldAlwaysUseBrowserUI_added(android.content.Intent)" class="hiddenlink" target="rightframe"><b>shouldAlwaysUseBrowserUI</b>
    ++(<code>Intent</code>)</A></nobr><br>
    ++<nobr><A HREF="android.support.v4.app.ServiceCompat.html#android.support.v4.app.ServiceCompat.stopForeground_added(android.app.Service, int)" class="hiddenlink" target="rightframe"><b>stopForeground</b>
    ++(<code>Service, int</code>)</A></nobr><br>
    ++<A NAME="T"></A>
    ++<br><font size="+2">T</font>&nbsp;
    ++<a href="#A"><font size="-2">A</font></a> 
    ++<a href="#B"><font size="-2">B</font></a> 
    ++<a href="#C"><font size="-2">C</font></a> 
    ++<a href="#F"><font size="-2">F</font></a> 
    ++<a href="#G"><font size="-2">G</font></a> 
    ++<a href="#I"><font size="-2">I</font></a> 
    ++<a href="#L"><font size="-2">L</font></a> 
    ++<a href="#M"><font size="-2">M</font></a> 
    ++<a href="#N"><font size="-2">N</font></a> 
    ++<a href="#O"><font size="-2">O</font></a> 
    ++<a href="#R"><font size="-2">R</font></a> 
    ++<a href="#S"><font size="-2">S</font></a> 
    ++ <a href="#topheader"><font size="-2">TOP</font></a>
    ++<p><div style="line-height:1.5em;color:black">
    ++<nobr><A HREF="android.support.v4.media.session.PlaybackStateCompat.html#android.support.v4.media.session.PlaybackStateCompat.toKeyCode_added(long)" class="hiddenlink" target="rightframe"><b>toKeyCode</b>
    ++(<code>long</code>)</A></nobr><br>
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    ++</script>
    ++<script type="text/javascript">
    ++  try {
    ++    var pageTracker = _gat._getTracker("UA-5831155-1");
    ++    pageTracker._setAllowAnchor(true);
    ++    pageTracker._initData();
    ++    pageTracker._trackPageview();
    ++  } catch(e) {}
    ++</script>
    ++</BODY>
    ++</HTML>
    +diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/methods_index_all.html b/docs/html/sdk/support_api_diff/24.2.0/changes/methods_index_all.html
    +new file mode 100644
    +index 0000000..d33bfc0
    +--- /dev/null
    ++++ b/docs/html/sdk/support_api_diff/24.2.0/changes/methods_index_all.html
    +@@ -0,0 +1,579 @@
    ++<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
    ++<HTML style="overflow:auto;">
    ++<HEAD>
    ++<meta name="generator" content="JDiff v1.1.0">
    ++<!-- Generated by the JDiff Javadoc doclet -->
    ++<!-- (http://www.jdiff.org) -->
    ++<meta name="description" content="JDiff is a Javadoc doclet which generates an HTML report of all the packages, classes, constructors, methods, and fields which have been removed, added or changed in any way, including their documentation, when two APIs are compared.">
    ++<meta name="keywords" content="diff, jdiff, javadiff, java diff, java difference, API difference, difference between two APIs, API diff, Javadoc, doclet">
    ++<TITLE>
    ++Method Differences Index
    ++</TITLE>
    ++<link href="../../../../assets/android-developer-docs.css" rel="stylesheet" type="text/css" />
    ++<link href="../stylesheet-jdiff.css" rel="stylesheet" type="text/css" />
    ++<noscript>
    ++<style type="text/css">
    ++body{overflow:auto;}
    ++#body-content{position:relative; top:0;}
    ++#doc-content{overflow:visible;border-left:3px solid #666;}
    ++#side-nav{padding:0;}
    ++#side-nav .toggle-list ul {display:block;}
    ++#resize-packages-nav{border-bottom:3px solid #666;}
    ++</style>
    ++</noscript>
    ++<style type="text/css">
    ++</style>
    ++</HEAD>
    ++<BODY class="gc-documentation" style="padding:12px;">
    ++<a NAME="topheader"></a>
    ++<table summary="Index for Methods" width="100%" class="jdiffIndex" border="0" cellspacing="0" cellpadding="0" style="padding-bottom:0;margin-bottom:0;">
    ++  <tr>
    ++  <th class="indexHeader">
    ++    Filter the Index:
    ++  </th>
    ++  </tr>
    ++  <tr>
    ++  <td class="indexText" style="line-height:1.3em;padding-left:2em;">
    ++<b>Methods</b>
    ++  <br>
    ++<A HREF="methods_index_removals.html" xclass="hiddenlink">Removals</A>
    ++  <br>
    ++<A HREF="methods_index_additions.html"xclass="hiddenlink">Additions</A>
    ++  <br>
    ++<A HREF="methods_index_changes.html"xclass="hiddenlink">Changes</A>
    ++  </td>
    ++  </tr>
    ++</table>
    ++<div id="indexTableCaption" style="background-color:#eee;padding:0 4px 0 4px;font-size:11px;margin-bottom:1em;">
    ++Listed as: <span style="color:#069"><strong>Added</strong></span>,  <span style="color:#069"><strike>Removed</strike></span>,  <span style="color:#069">Changed</span></font>
    ++</div>
    ++<A NAME="A"></A>
    ++<br><font size="+2">A</font>&nbsp;
    ++<a href="#B"><font size="-2">B</font></a> 
    ++<a href="#C"><font size="-2">C</font></a> 
    ++<a href="#D"><font size="-2">D</font></a> 
    ++<a href="#F"><font size="-2">F</font></a> 
    ++<a href="#G"><font size="-2">G</font></a> 
    ++<a href="#I"><font size="-2">I</font></a> 
    ++<a href="#L"><font size="-2">L</font></a> 
    ++<a href="#M"><font size="-2">M</font></a> 
    ++<a href="#N"><font size="-2">N</font></a> 
    ++<a href="#O"><font size="-2">O</font></a> 
    ++<a href="#P"><font size="-2">P</font></a> 
    ++<a href="#R"><font size="-2">R</font></a> 
    ++<a href="#S"><font size="-2">S</font></a> 
    ++<a href="#T"><font size="-2">T</font></a> 
    ++ <a href="#topheader"><font size="-2">TOP</font></a>
    ++<p><div style="line-height:1.5em;color:black">
    ++<nobr><A HREF="android.support.v4.view.accessibility.AccessibilityManagerCompat.html#android.support.v4.view.accessibility.AccessibilityManagerCompat.addAccessibilityStateChangeListener_changed(android.view.accessibility.AccessibilityManager, android.support.v4.view.accessibility.AccessibilityManagerCompat.AccessibilityStateChangeListener)" class="hiddenlink" target="rightframe">addAccessibilityStateChangeListener
    ++(<code>AccessibilityManager, AccessibilityStateChangeListener</code>)</A></nobr><br>
    ++<nobr><A HREF="android.support.v4.view.accessibility.AccessibilityManagerCompat.html#android.support.v4.view.accessibility.AccessibilityManagerCompat.addTouchExplorationStateChangeListener_added(android.view.accessibility.AccessibilityManager, android.support.v4.view.accessibility.AccessibilityManagerCompat.TouchExplorationStateChangeListener)" class="hiddenlink" target="rightframe"><b>addTouchExplorationStateChangeListener</b>
    ++(<code>AccessibilityManager, TouchExplorationStateChangeListener</code>)</A></nobr><br>
    ++<A NAME="B"></A>
    ++<br><font size="+2">B</font>&nbsp;
    ++<a href="#A"><font size="-2">A</font></a> 
    ++<a href="#C"><font size="-2">C</font></a> 
    ++<a href="#D"><font size="-2">D</font></a> 
    ++<a href="#F"><font size="-2">F</font></a> 
    ++<a href="#G"><font size="-2">G</font></a> 
    ++<a href="#I"><font size="-2">I</font></a> 
    ++<a href="#L"><font size="-2">L</font></a> 
    ++<a href="#M"><font size="-2">M</font></a> 
    ++<a href="#N"><font size="-2">N</font></a> 
    ++<a href="#O"><font size="-2">O</font></a> 
    ++<a href="#P"><font size="-2">P</font></a> 
    ++<a href="#R"><font size="-2">R</font></a> 
    ++<a href="#S"><font size="-2">S</font></a> 
    ++<a href="#T"><font size="-2">T</font></a> 
    ++ <a href="#topheader"><font size="-2">TOP</font></a>
    ++<p><div style="line-height:1.5em;color:black">
    ++<i>buildMediaButtonPendingIntent</i><br>
    ++&nbsp;&nbsp;<nobr><A HREF="android.support.v4.media.session.MediaButtonReceiver.html#android.support.v4.media.session.MediaButtonReceiver.buildMediaButtonPendingIntent_added(android.content.Context, android.content.ComponentName, long)" class="hiddenlink" target="rightframe">type&nbsp;<b>
    ++(<code>Context, ComponentName, long</code>)</b>&nbsp;in&nbsp;android.support.v4.media.session.MediaButtonReceiver
    ++</A></nobr><br>
    ++&nbsp;&nbsp;<nobr><A HREF="android.support.v4.media.session.MediaButtonReceiver.html#android.support.v4.media.session.MediaButtonReceiver.buildMediaButtonPendingIntent_added(android.content.Context, long)" class="hiddenlink" target="rightframe">type&nbsp;<b>
    ++(<code>Context, long</code>)</b>&nbsp;in&nbsp;android.support.v4.media.session.MediaButtonReceiver
    ++</A></nobr><br>
    ++<A NAME="C"></A>
    ++<br><font size="+2">C</font>&nbsp;
    ++<a href="#A"><font size="-2">A</font></a> 
    ++<a href="#B"><font size="-2">B</font></a> 
    ++<a href="#D"><font size="-2">D</font></a> 
    ++<a href="#F"><font size="-2">F</font></a> 
    ++<a href="#G"><font size="-2">G</font></a> 
    ++<a href="#I"><font size="-2">I</font></a> 
    ++<a href="#L"><font size="-2">L</font></a> 
    ++<a href="#M"><font size="-2">M</font></a> 
    ++<a href="#N"><font size="-2">N</font></a> 
    ++<a href="#O"><font size="-2">O</font></a> 
    ++<a href="#P"><font size="-2">P</font></a> 
    ++<a href="#R"><font size="-2">R</font></a> 
    ++<a href="#S"><font size="-2">S</font></a> 
    ++<a href="#T"><font size="-2">T</font></a> 
    ++ <a href="#topheader"><font size="-2">TOP</font></a>
    ++<p><div style="line-height:1.5em;color:black">
    ++<nobr><A HREF="android.support.v4.graphics.drawable.DrawableCompat.html#android.support.v4.graphics.drawable.DrawableCompat.clearColorFilter_added(android.graphics.drawable.Drawable)" class="hiddenlink" target="rightframe"><b>clearColorFilter</b>
    ++(<code>Drawable</code>)</A></nobr><br>
    ++<nobr><A HREF="android.support.design.widget.TabLayout.html#android.support.design.widget.TabLayout.clearOnTabSelectedListeners_added()" class="hiddenlink" target="rightframe"><b>clearOnTabSelectedListeners</b>
    ++()</A></nobr><br>
    ++<i>computeScrollVectorForPosition</i><br>
    ++&nbsp;&nbsp;<nobr><A HREF="android.support.v7.widget.LinearSmoothScroller.html#android.support.v7.widget.LinearSmoothScroller.computeScrollVectorForPosition_changed(int)" class="hiddenlink" target="rightframe">type&nbsp;
    ++(<code>int</code>)&nbsp;in&nbsp;android.support.v7.widget.LinearSmoothScroller
    ++</A></nobr><br>
    ++&nbsp;&nbsp;<nobr><A HREF="android.support.v7.widget.StaggeredGridLayoutManager.html#android.support.v7.widget.StaggeredGridLayoutManager.computeScrollVectorForPosition_added(int)" class="hiddenlink" target="rightframe">type&nbsp;<b>
    ++(<code>int</code>)</b>&nbsp;in&nbsp;android.support.v7.widget.StaggeredGridLayoutManager
    ++</A></nobr><br>
    ++<A NAME="D"></A>
    ++<br><font size="+2">D</font>&nbsp;
    ++<a href="#A"><font size="-2">A</font></a> 
    ++<a href="#B"><font size="-2">B</font></a> 
    ++<a href="#C"><font size="-2">C</font></a> 
    ++<a href="#F"><font size="-2">F</font></a> 
    ++<a href="#G"><font size="-2">G</font></a> 
    ++<a href="#I"><font size="-2">I</font></a> 
    ++<a href="#L"><font size="-2">L</font></a> 
    ++<a href="#M"><font size="-2">M</font></a> 
    ++<a href="#N"><font size="-2">N</font></a> 
    ++<a href="#O"><font size="-2">O</font></a> 
    ++<a href="#P"><font size="-2">P</font></a> 
    ++<a href="#R"><font size="-2">R</font></a> 
    ++<a href="#S"><font size="-2">S</font></a> 
    ++<a href="#T"><font size="-2">T</font></a> 
    ++ <a href="#topheader"><font size="-2">TOP</font></a>
    ++<p><div style="line-height:1.5em;color:black">
    ++<nobr><A HREF="android.support.v4.view.KeyEventCompat.html#android.support.v4.view.KeyEventCompat.dispatch_changed(android.view.KeyEvent, android.view.KeyEvent.Callback, java.lang.Object, java.lang.Object)" class="hiddenlink" target="rightframe">dispatch
    ++(<code>KeyEvent, Callback, Object, Object</code>)</A></nobr><br>
    ++<A NAME="F"></A>
    ++<br><font size="+2">F</font>&nbsp;
    ++<a href="#A"><font size="-2">A</font></a> 
    ++<a href="#B"><font size="-2">B</font></a> 
    ++<a href="#C"><font size="-2">C</font></a> 
    ++<a href="#D"><font size="-2">D</font></a> 
    ++<a href="#G"><font size="-2">G</font></a> 
    ++<a href="#I"><font size="-2">I</font></a> 
    ++<a href="#L"><font size="-2">L</font></a> 
    ++<a href="#M"><font size="-2">M</font></a> 
    ++<a href="#N"><font size="-2">N</font></a> 
    ++<a href="#O"><font size="-2">O</font></a> 
    ++<a href="#P"><font size="-2">P</font></a> 
    ++<a href="#R"><font size="-2">R</font></a> 
    ++<a href="#S"><font size="-2">S</font></a> 
    ++<a href="#T"><font size="-2">T</font></a> 
    ++ <a href="#topheader"><font size="-2">TOP</font></a>
    ++<p><div style="line-height:1.5em;color:black">
    ++<nobr><A HREF="android.support.v4.app.FragmentController.html#android.support.v4.app.FragmentController.findFragmentByWho_added(java.lang.String)" class="hiddenlink" target="rightframe"><b>findFragmentByWho</b>
    ++(<code>String</code>)</A></nobr><br>
    ++<nobr><A HREF="android.support.v4.view.MotionEventCompat.html#android.support.v4.view.MotionEventCompat.findPointerIndex_changed(android.view.MotionEvent, int)" class="hiddenlink" target="rightframe">findPointerIndex
    ++(<code>MotionEvent, int</code>)</A></nobr><br>
    ++<nobr><A HREF="android.support.v4.media.MediaBrowserCompat.MediaItem.html#android.support.v4.media.MediaBrowserCompat.MediaItem.fromMediaItem_added(java.lang.Object)" class="hiddenlink" target="rightframe"><b>fromMediaItem</b>
    ++(<code>Object</code>)</A></nobr><br>
    ++<nobr><A HREF="android.support.v4.media.MediaBrowserCompat.MediaItem.html#android.support.v4.media.MediaBrowserCompat.MediaItem.fromMediaItemList_added(java.util.List<?>)" class="hiddenlink" target="rightframe"><b>fromMediaItemList</b>
    ++(<code>List&lt;?&gt;</code>)</A></nobr><br>
    ++<nobr><A HREF="android.support.v4.media.session.MediaSessionCompat.html#android.support.v4.media.session.MediaSessionCompat.fromMediaSession_added(android.content.Context, java.lang.Object)" class="hiddenlink" target="rightframe"><b>fromMediaSession</b>
    ++(<code>Context, Object</code>)</A></nobr><br>
    ++<nobr><A HREF="android.support.v4.media.session.MediaSessionCompat.QueueItem.html#android.support.v4.media.session.MediaSessionCompat.QueueItem.fromQueueItem_added(java.lang.Object)" class="hiddenlink" target="rightframe"><b>fromQueueItem</b>
    ++(<code>Object</code>)</A></nobr><br>
    ++<nobr><A HREF="android.support.v4.media.session.MediaSessionCompat.QueueItem.html#android.support.v4.media.session.MediaSessionCompat.QueueItem.fromQueueItemList_added(java.util.List<?>)" class="hiddenlink" target="rightframe"><b>fromQueueItemList</b>
    ++(<code>List&lt;?&gt;</code>)</A></nobr><br>
    ++<A NAME="G"></A>
    ++<br><font size="+2">G</font>&nbsp;
    ++<a href="#A"><font size="-2">A</font></a> 
    ++<a href="#B"><font size="-2">B</font></a> 
    ++<a href="#C"><font size="-2">C</font></a> 
    ++<a href="#D"><font size="-2">D</font></a> 
    ++<a href="#F"><font size="-2">F</font></a> 
    ++<a href="#I"><font size="-2">I</font></a> 
    ++<a href="#L"><font size="-2">L</font></a> 
    ++<a href="#M"><font size="-2">M</font></a> 
    ++<a href="#N"><font size="-2">N</font></a> 
    ++<a href="#O"><font size="-2">O</font></a> 
    ++<a href="#P"><font size="-2">P</font></a> 
    ++<a href="#R"><font size="-2">R</font></a> 
    ++<a href="#S"><font size="-2">S</font></a> 
    ++<a href="#T"><font size="-2">T</font></a> 
    ++ <a href="#topheader"><font size="-2">TOP</font></a>
    ++<p><div style="line-height:1.5em;color:black">
    ++<nobr><A HREF="android.support.v4.view.accessibility.AccessibilityEventCompat.html#android.support.v4.view.accessibility.AccessibilityEventCompat.getAction_added(android.view.accessibility.AccessibilityEvent)" class="hiddenlink" target="rightframe"><b>getAction</b>
    ++(<code>AccessibilityEvent</code>)</A></nobr><br>
    ++<nobr><A HREF="android.support.v4.widget.TextViewCompat.html#android.support.v4.widget.TextViewCompat.getCompoundDrawablesRelative_added(android.widget.TextView)" class="hiddenlink" target="rightframe"><b>getCompoundDrawablesRelative</b>
    ++(<code>TextView</code>)</A></nobr><br>
    ++<nobr><A HREF="android.support.design.widget.CoordinatorLayout.html#android.support.design.widget.CoordinatorLayout.getDependents_added(android.view.View)" class="hiddenlink" target="rightframe"><b>getDependents</b>
    ++(<code>View</code>)</A></nobr><br>
    ++<nobr><A HREF="android.support.v4.accessibilityservice.AccessibilityServiceInfoCompat.html#android.support.v4.accessibilityservice.AccessibilityServiceInfoCompat.getDescription_changed(android.accessibilityservice.AccessibilityServiceInfo)" class="hiddenlink" target="rightframe">getDescription
    ++(<code>AccessibilityServiceInfo</code>)</A></nobr><br>
    ++<nobr><A HREF="android.support.v7.graphics.Palette.html#android.support.v7.graphics.Palette.getDominantColor_added(int)" class="hiddenlink" target="rightframe"><b>getDominantColor</b>
    ++(<code>int</code>)</A></nobr><br>
    ++<nobr><A HREF="android.support.v7.graphics.Palette.html#android.support.v7.graphics.Palette.getDominantSwatch_added()" class="hiddenlink" target="rightframe"><b>getDominantSwatch</b>
    ++()</A></nobr><br>
    ++<nobr><A HREF="android.support.v7.content.res.AppCompatResources.html#android.support.v7.content.res.AppCompatResources.getDrawable_added(android.content.Context, int)" class="hiddenlink" target="rightframe"><b>getDrawable</b>
    ++(<code>Context, int</code>)</A></nobr><br>
    ++<nobr><A HREF="android.support.v7.app.ActionBarDrawerToggle.html#android.support.v7.app.ActionBarDrawerToggle.getDrawerArrowDrawable_added()" class="hiddenlink" target="rightframe"><b>getDrawerArrowDrawable</b>
    ++()</A></nobr><br>
    ++<i>getInsetDodgeRect</i><br>
    ++&nbsp;&nbsp;<nobr><A HREF="android.support.design.widget.CoordinatorLayout.Behavior.html#android.support.design.widget.CoordinatorLayout.Behavior.getInsetDodgeRect_added(android.support.design.widget.CoordinatorLayout, V, android.graphics.Rect)" class="hiddenlink" target="rightframe">type&nbsp;<b>
    ++(<code>CoordinatorLayout, V, Rect</code>)</b>&nbsp;in&nbsp;android.support.design.widget.CoordinatorLayout.Behavior
    ++</A></nobr><br>
    ++&nbsp;&nbsp;<nobr><A HREF="android.support.design.widget.FloatingActionButton.Behavior.html#android.support.design.widget.FloatingActionButton.Behavior.getInsetDodgeRect_added(android.support.design.widget.CoordinatorLayout, android.support.design.widget.FloatingActionButton, android.graphics.Rect)" class="hiddenlink" target="rightframe">type&nbsp;<b>
    ++(<code>CoordinatorLayout, FloatingActionButton, Rect</code>)</b>&nbsp;in&nbsp;android.support.design.widget.FloatingActionButton.Behavior
    ++</A></nobr><br>
    ++<nobr><A HREF="android.support.v4.view.KeyEventCompat.html#android.support.v4.view.KeyEventCompat.getKeyDispatcherState_changed(android.view.View)" class="hiddenlink" target="rightframe">getKeyDispatcherState
    ++(<code>View</code>)</A></nobr><br>
    ++<nobr><A HREF="android.support.v4.app.ActivityOptionsCompat.html#android.support.v4.app.ActivityOptionsCompat.getLaunchBounds_added()" class="hiddenlink" target="rightframe"><b>getLaunchBounds</b>
    ++()</A></nobr><br>
    ++<nobr><A HREF="android.support.v17.leanback.widget.AbstractMediaItemPresenter.ViewHolder.html#android.support.v17.leanback.widget.AbstractMediaItemPresenter.ViewHolder.getMediaItemNumberViewFlipper_added()" class="hiddenlink" target="rightframe"><b>getMediaItemNumberViewFlipper</b>
    ++()</A></nobr><br>
    ++<nobr><A HREF="android.support.v17.leanback.widget.AbstractMediaItemPresenter.ViewHolder.html#android.support.v17.leanback.widget.AbstractMediaItemPresenter.ViewHolder.getMediaItemPausedView_added()" class="hiddenlink" target="rightframe"><b>getMediaItemPausedView</b>
    ++()</A></nobr><br>
    ++<nobr><A HREF="android.support.v17.leanback.widget.AbstractMediaItemPresenter.ViewHolder.html#android.support.v17.leanback.widget.AbstractMediaItemPresenter.ViewHolder.getMediaItemPlayingView_added()" class="hiddenlink" target="rightframe"><b>getMediaItemPlayingView</b>
    ++()</A></nobr><br>
    ++<nobr><A HREF="android.support.v17.leanback.widget.AbstractMediaItemPresenter.html#android.support.v17.leanback.widget.AbstractMediaItemPresenter.getMediaPlayState_added(java.lang.Object)" class="hiddenlink" target="rightframe"><b>getMediaPlayState</b>
    ++(<code>Object</code>)</A></nobr><br>
    ++<nobr><A HREF="android.support.v4.view.accessibility.AccessibilityEventCompat.html#android.support.v4.view.accessibility.AccessibilityEventCompat.getMovementGranularity_added(android.view.accessibility.AccessibilityEvent)" class="hiddenlink" target="rightframe"><b>getMovementGranularity</b>
    ++(<code>AccessibilityEvent</code>)</A></nobr><br>
    ++<nobr><A HREF="android.support.v7.widget.RecyclerView.html#android.support.v7.widget.RecyclerView.getOnFlingListener_added()" class="hiddenlink" target="rightframe"><b>getOnFlingListener</b>
    ++()</A></nobr><br>
    ++<nobr><A HREF="android.support.v4.view.ViewCompat.html#android.support.v4.view.ViewCompat.getOverScrollMode_changed(android.view.View)" class="hiddenlink" target="rightframe">getOverScrollMode
    ++(<code>View</code>)</A></nobr><br>
    ++<nobr><A HREF="android.support.design.widget.TextInputLayout.html#android.support.design.widget.TextInputLayout.getPasswordVisibilityToggleContentDescription_added()" class="hiddenlink" target="rightframe"><b>getPasswordVisibilityToggleContentDescription</b>
    ++()</A></nobr><br>
    ++<nobr><A HREF="android.support.design.widget.TextInputLayout.html#android.support.design.widget.TextInputLayout.getPasswordVisibilityToggleDrawable_added()" class="hiddenlink" target="rightframe"><b>getPasswordVisibilityToggleDrawable</b>
    ++()</A></nobr><br>
    ++<nobr><A HREF="android.support.v4.view.MotionEventCompat.html#android.support.v4.view.MotionEventCompat.getPointerCount_changed(android.view.MotionEvent)" class="hiddenlink" target="rightframe">getPointerCount
    ++(<code>MotionEvent</code>)</A></nobr><br>
    ++<nobr><A HREF="android.support.v4.view.MotionEventCompat.html#android.support.v4.view.MotionEventCompat.getPointerId_changed(android.view.MotionEvent, int)" class="hiddenlink" target="rightframe">getPointerId
    ++(<code>MotionEvent, int</code>)</A></nobr><br>
    ++<nobr><A HREF="android.support.v4.app.ActivityCompat.html#android.support.v4.app.ActivityCompat.getReferrer_changed(android.app.Activity)" class="hiddenlink" target="rightframe">getReferrer
    ++(<code>Activity</code>)</A></nobr><br>
    ++<nobr><A HREF="android.support.v4.view.ViewConfigurationCompat.html#android.support.v4.view.ViewConfigurationCompat.getScaledPagingTouchSlop_changed(android.view.ViewConfiguration)" class="hiddenlink" target="rightframe">getScaledPagingTouchSlop
    ++(<code>ViewConfiguration</code>)</A></nobr><br>
    ++<nobr><A HREF="android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.CollectionInfoCompat.html#android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.CollectionInfoCompat.getSelectionMode_added()" class="hiddenlink" target="rightframe"><b>getSelectionMode</b>
    ++()</A></nobr><br>
    ++<nobr><A HREF="android.support.v4.view.MotionEventCompat.html#android.support.v4.view.MotionEventCompat.getSource_changed(android.view.MotionEvent)" class="hiddenlink" target="rightframe">getSource
    ++(<code>MotionEvent</code>)</A></nobr><br>
    ++<nobr><A HREF="android.support.v4.view.MotionEventCompat.html#android.support.v4.view.MotionEventCompat.getX_changed(android.view.MotionEvent, int)" class="hiddenlink" target="rightframe">getX
    ++(<code>MotionEvent, int</code>)</A></nobr><br>
    ++<nobr><A HREF="android.support.v4.view.MotionEventCompat.html#android.support.v4.view.MotionEventCompat.getY_changed(android.view.MotionEvent, int)" class="hiddenlink" target="rightframe">getY
    ++(<code>MotionEvent, int</code>)</A></nobr><br>
    ++<A NAME="I"></A>
    ++<br><font size="+2">I</font>&nbsp;
    ++<a href="#A"><font size="-2">A</font></a> 
    ++<a href="#B"><font size="-2">B</font></a> 
    ++<a href="#C"><font size="-2">C</font></a> 
    ++<a href="#D"><font size="-2">D</font></a> 
    ++<a href="#F"><font size="-2">F</font></a> 
    ++<a href="#G"><font size="-2">G</font></a> 
    ++<a href="#L"><font size="-2">L</font></a> 
    ++<a href="#M"><font size="-2">M</font></a> 
    ++<a href="#N"><font size="-2">N</font></a> 
    ++<a href="#O"><font size="-2">O</font></a> 
    ++<a href="#P"><font size="-2">P</font></a> 
    ++<a href="#R"><font size="-2">R</font></a> 
    ++<a href="#S"><font size="-2">S</font></a> 
    ++<a href="#T"><font size="-2">T</font></a> 
    ++ <a href="#topheader"><font size="-2">TOP</font></a>
    ++<p><div style="line-height:1.5em;color:black">
    ++<nobr><A HREF="android.support.v4.os.BuildCompat.html#android.support.v4.os.BuildCompat.isAtLeastNMR1_added()" class="hiddenlink" target="rightframe"><b>isAtLeastNMR1</b>
    ++()</A></nobr><br>
    ++<nobr><A HREF="android.support.design.widget.FloatingActionButton.Behavior.html#android.support.design.widget.FloatingActionButton.Behavior.isAutoHideEnabled_added()" class="hiddenlink" target="rightframe"><b>isAutoHideEnabled</b>
    ++()</A></nobr><br>
    ++<nobr><A HREF="android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.html#android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.isContextClickable_added()" class="hiddenlink" target="rightframe"><b>isContextClickable</b>
    ++()</A></nobr><br>
    ++<nobr><A HREF="android.support.design.widget.CoordinatorLayout.Behavior.html#android.support.design.widget.CoordinatorLayout.Behavior.isDirty_changed(android.support.design.widget.CoordinatorLayout, V)" class="hiddenlink" target="rightframe">isDirty
    ++(<code>CoordinatorLayout, V</code>)</A></nobr><br>
    ++<nobr><A HREF="android.support.v17.leanback.widget.ObjectAdapter.html#android.support.v17.leanback.widget.ObjectAdapter.isImmediateNotifySupported_added()" class="hiddenlink" target="rightframe"><b>isImmediateNotifySupported</b>
    ++()</A></nobr><br>
    ++<nobr><A HREF="android.support.v4.view.ViewCompat.html#android.support.v4.view.ViewCompat.isImportantForAccessibility_added(android.view.View)" class="hiddenlink" target="rightframe"><b>isImportantForAccessibility</b>
    ++(<code>View</code>)</A></nobr><br>
    ++<nobr><A HREF="android.support.v4.view.ViewCompat.html#android.support.v4.view.ViewCompat.isOpaque_changed(android.view.View)" class="hiddenlink" target="rightframe">isOpaque
    ++(<code>View</code>)</A></nobr><br>
    ++<nobr><A HREF="android.support.design.widget.TextInputLayout.html#android.support.design.widget.TextInputLayout.isPasswordVisibilityToggleEnabled_added()" class="hiddenlink" target="rightframe"><b>isPasswordVisibilityToggleEnabled</b>
    ++()</A></nobr><br>
    ++<nobr><A HREF="android.support.v4.view.KeyEventCompat.html#android.support.v4.view.KeyEventCompat.isTracking_changed(android.view.KeyEvent)" class="hiddenlink" target="rightframe">isTracking
    ++(<code>KeyEvent</code>)</A></nobr><br>
    ++<A NAME="L"></A>
    ++<br><font size="+2">L</font>&nbsp;
    ++<a href="#A"><font size="-2">A</font></a> 
    ++<a href="#B"><font size="-2">B</font></a> 
    ++<a href="#C"><font size="-2">C</font></a> 
    ++<a href="#D"><font size="-2">D</font></a> 
    ++<a href="#F"><font size="-2">F</font></a> 
    ++<a href="#G"><font size="-2">G</font></a> 
    ++<a href="#I"><font size="-2">I</font></a> 
    ++<a href="#M"><font size="-2">M</font></a> 
    ++<a href="#N"><font size="-2">N</font></a> 
    ++<a href="#O"><font size="-2">O</font></a> 
    ++<a href="#P"><font size="-2">P</font></a> 
    ++<a href="#R"><font size="-2">R</font></a> 
    ++<a href="#S"><font size="-2">S</font></a> 
    ++<a href="#T"><font size="-2">T</font></a> 
    ++ <a href="#topheader"><font size="-2">TOP</font></a>
    ++<p><div style="line-height:1.5em;color:black">
    ++<nobr><A HREF="android.support.design.widget.FloatingActionButton.Behavior.html#android.support.design.widget.FloatingActionButton.Behavior.layoutDependsOn_removed(android.support.design.widget.CoordinatorLayout, android.support.design.widget.FloatingActionButton, android.view.View)" class="hiddenlink" target="rightframe"><strike>layoutDependsOn</strike>
    ++(<code>CoordinatorLayout, FloatingActionButton, View</code>)</A></nobr><br>
    ++<nobr><A HREF="android.support.v4.accessibilityservice.AccessibilityServiceInfoCompat.html#android.support.v4.accessibilityservice.AccessibilityServiceInfoCompat.loadDescription_added(android.accessibilityservice.AccessibilityServiceInfo, android.content.pm.PackageManager)" class="hiddenlink" target="rightframe"><b>loadDescription</b>
    ++(<code>AccessibilityServiceInfo, PackageManager</code>)</A></nobr><br>
    ++<A NAME="M"></A>
    ++<br><font size="+2">M</font>&nbsp;
    ++<a href="#A"><font size="-2">A</font></a> 
    ++<a href="#B"><font size="-2">B</font></a> 
    ++<a href="#C"><font size="-2">C</font></a> 
    ++<a href="#D"><font size="-2">D</font></a> 
    ++<a href="#F"><font size="-2">F</font></a> 
    ++<a href="#G"><font size="-2">G</font></a> 
    ++<a href="#I"><font size="-2">I</font></a> 
    ++<a href="#L"><font size="-2">L</font></a> 
    ++<a href="#N"><font size="-2">N</font></a> 
    ++<a href="#O"><font size="-2">O</font></a> 
    ++<a href="#P"><font size="-2">P</font></a> 
    ++<a href="#R"><font size="-2">R</font></a> 
    ++<a href="#S"><font size="-2">S</font></a> 
    ++<a href="#T"><font size="-2">T</font></a> 
    ++ <a href="#topheader"><font size="-2">TOP</font></a>
    ++<p><div style="line-height:1.5em;color:black">
    ++<nobr><A HREF="android.support.v4.app.ActivityOptionsCompat.html#android.support.v4.app.ActivityOptionsCompat.makeBasic_added()" class="hiddenlink" target="rightframe"><b>makeBasic</b>
    ++()</A></nobr><br>
    ++<nobr><A HREF="android.support.v4.app.ActivityOptionsCompat.html#android.support.v4.app.ActivityOptionsCompat.makeClipRevealAnimation_added(android.view.View, int, int, int, int)" class="hiddenlink" target="rightframe"><b>makeClipRevealAnimation</b>
    ++(<code>View, int, int, int, int</code>)</A></nobr><br>
    ++<nobr><A HREF="android.support.v4.app.ActivityOptionsCompat.html#android.support.v4.app.ActivityOptionsCompat.makeTaskLaunchBehind_added()" class="hiddenlink" target="rightframe"><b>makeTaskLaunchBehind</b>
    ++()</A></nobr><br>
    ++<A NAME="N"></A>
    ++<br><font size="+2">N</font>&nbsp;
    ++<a href="#A"><font size="-2">A</font></a> 
    ++<a href="#B"><font size="-2">B</font></a> 
    ++<a href="#C"><font size="-2">C</font></a> 
    ++<a href="#D"><font size="-2">D</font></a> 
    ++<a href="#F"><font size="-2">F</font></a> 
    ++<a href="#G"><font size="-2">G</font></a> 
    ++<a href="#I"><font size="-2">I</font></a> 
    ++<a href="#L"><font size="-2">L</font></a> 
    ++<a href="#M"><font size="-2">M</font></a> 
    ++<a href="#O"><font size="-2">O</font></a> 
    ++<a href="#P"><font size="-2">P</font></a> 
    ++<a href="#R"><font size="-2">R</font></a> 
    ++<a href="#S"><font size="-2">S</font></a> 
    ++<a href="#T"><font size="-2">T</font></a> 
    ++ <a href="#topheader"><font size="-2">TOP</font></a>
    ++<p><div style="line-height:1.5em;color:black">
    ++<nobr><A HREF="android.support.v17.leanback.widget.AbstractMediaItemPresenter.ViewHolder.html#android.support.v17.leanback.widget.AbstractMediaItemPresenter.ViewHolder.notifyPlayStateChanged_added()" class="hiddenlink" target="rightframe"><b>notifyPlayStateChanged</b>
    ++()</A></nobr><br>
    ++<A NAME="O"></A>
    ++<br><font size="+2">O</font>&nbsp;
    ++<a href="#A"><font size="-2">A</font></a> 
    ++<a href="#B"><font size="-2">B</font></a> 
    ++<a href="#C"><font size="-2">C</font></a> 
    ++<a href="#D"><font size="-2">D</font></a> 
    ++<a href="#F"><font size="-2">F</font></a> 
    ++<a href="#G"><font size="-2">G</font></a> 
    ++<a href="#I"><font size="-2">I</font></a> 
    ++<a href="#L"><font size="-2">L</font></a> 
    ++<a href="#M"><font size="-2">M</font></a> 
    ++<a href="#N"><font size="-2">N</font></a> 
    ++<a href="#P"><font size="-2">P</font></a> 
    ++<a href="#R"><font size="-2">R</font></a> 
    ++<a href="#S"><font size="-2">S</font></a> 
    ++<a href="#T"><font size="-2">T</font></a> 
    ++ <a href="#topheader"><font size="-2">TOP</font></a>
    ++<p><div style="line-height:1.5em;color:black">
    ++<i>obtain</i><br>
    ++&nbsp;&nbsp;<nobr><A HREF="android.support.v4.media.session.MediaSessionCompat.html#android.support.v4.media.session.MediaSessionCompat.obtain_changed(android.content.Context, java.lang.Object)" class="hiddenlink" target="rightframe">type&nbsp;
    ++(<code>Context, Object</code>)&nbsp;in&nbsp;android.support.v4.media.session.MediaSessionCompat
    ++</A></nobr><br>
    ++&nbsp;&nbsp;<nobr><A HREF="android.support.v4.media.session.MediaSessionCompat.QueueItem.html#android.support.v4.media.session.MediaSessionCompat.QueueItem.obtain_changed(java.lang.Object)" class="hiddenlink" target="rightframe">type&nbsp;
    ++(<code>Object</code>)&nbsp;in&nbsp;android.support.v4.media.session.MediaSessionCompat.QueueItem
    ++</A></nobr><br>
    ++&nbsp;&nbsp;<nobr><A HREF="android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.CollectionInfoCompat.html#android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.CollectionInfoCompat.obtain_added(int, int, boolean)" class="hiddenlink" target="rightframe">type&nbsp;<b>
    ++(<code>int, int, boolean</code>)</b>&nbsp;in&nbsp;android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.CollectionInfoCompat
    ++</A></nobr><br>
    ++&nbsp;&nbsp;<nobr><A HREF="android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.CollectionItemInfoCompat.html#android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.CollectionItemInfoCompat.obtain_added(int, int, int, int, boolean)" class="hiddenlink" target="rightframe">type&nbsp;<b>
    ++(<code>int, int, int, int, boolean</code>)</b>&nbsp;in&nbsp;android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.CollectionItemInfoCompat
    ++</A></nobr><br>
    ++&nbsp;&nbsp;<nobr><A HREF="android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.RangeInfoCompat.html#android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.RangeInfoCompat.obtain_added(int, float, float, float)" class="hiddenlink" target="rightframe">type&nbsp;<b>
    ++(<code>int, float, float, float</code>)</b>&nbsp;in&nbsp;android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.RangeInfoCompat
    ++</A></nobr><br>
    ++<nobr><A HREF="android.support.v4.view.accessibility.AccessibilityManagerCompat.AccessibilityStateChangeListenerCompat.html#android.support.v4.view.accessibility.AccessibilityManagerCompat.AccessibilityStateChangeListenerCompat.onAccessibilityStateChanged_removed(boolean)" class="hiddenlink" target="rightframe"><strike>onAccessibilityStateChanged</strike>
    ++(<code>boolean</code>)</A></nobr><br>
    ++<nobr><A HREF="android.support.design.widget.CoordinatorLayout.Behavior.html#android.support.design.widget.CoordinatorLayout.Behavior.onAttachedToLayoutParams_added(android.support.design.widget.CoordinatorLayout.LayoutParams)" class="hiddenlink" target="rightframe"><b>onAttachedToLayoutParams</b>
    ++(<code>LayoutParams</code>)</A></nobr><br>
    ++<nobr><A HREF="android.support.v17.leanback.widget.AbstractMediaItemPresenter.html#android.support.v17.leanback.widget.AbstractMediaItemPresenter.onBindMediaPlayState_added(android.support.v17.leanback.widget.AbstractMediaItemPresenter.ViewHolder)" class="hiddenlink" target="rightframe"><b>onBindMediaPlayState</b>
    ++(<code>ViewHolder</code>)</A></nobr><br>
    ++<nobr><A HREF="android.support.v7.util.SortedList.Callback.html#android.support.v7.util.SortedList.Callback.onChanged_added(int, int, java.lang.Object)" class="hiddenlink" target="rightframe"><b>onChanged</b>
    ++(<code>int, int, Object</code>)</A></nobr><br>
    ++<nobr><A HREF="android.support.design.widget.FloatingActionButton.Behavior.html#android.support.design.widget.FloatingActionButton.Behavior.onDependentViewRemoved_removed(android.support.design.widget.CoordinatorLayout, android.support.design.widget.FloatingActionButton, android.view.View)" class="hiddenlink" target="rightframe"><strike>onDependentViewRemoved</strike>
    ++(<code>CoordinatorLayout, FloatingActionButton, View</code>)</A></nobr><br>
    ++<nobr><A HREF="android.support.design.widget.CoordinatorLayout.Behavior.html#android.support.design.widget.CoordinatorLayout.Behavior.onDetachedFromLayoutParams_added()" class="hiddenlink" target="rightframe"><b>onDetachedFromLayoutParams</b>
    ++()</A></nobr><br>
    ++<nobr><A HREF="android.support.v7.util.SortedList.Callback.html#android.support.v7.util.SortedList.Callback.onInserted_removed(int, int)" class="hiddenlink" target="rightframe"><strike>onInserted</strike>
    ++(<code>int, int</code>)</A></nobr><br>
    ++<nobr><A HREF="android.support.v7.util.SortedList.Callback.html#android.support.v7.util.SortedList.Callback.onMoved_removed(int, int)" class="hiddenlink" target="rightframe"><strike>onMoved</strike>
    ++(<code>int, int</code>)</A></nobr><br>
    ++<nobr><A HREF="android.support.v7.util.SortedList.Callback.html#android.support.v7.util.SortedList.Callback.onRemoved_removed(int, int)" class="hiddenlink" target="rightframe"><strike>onRemoved</strike>
    ++(<code>int, int</code>)</A></nobr><br>
    ++<i>onRequestChildRectangleOnScreen</i><br>
    ++&nbsp;&nbsp;<nobr><A HREF="android.support.design.widget.AppBarLayout.ScrollingViewBehavior.html#android.support.design.widget.AppBarLayout.ScrollingViewBehavior.onRequestChildRectangleOnScreen_added(android.support.design.widget.CoordinatorLayout, android.view.View, android.graphics.Rect, boolean)" class="hiddenlink" target="rightframe">type&nbsp;<b>
    ++(<code>CoordinatorLayout, View, Rect, boolean</code>)</b>&nbsp;in&nbsp;android.support.design.widget.AppBarLayout.ScrollingViewBehavior
    ++</A></nobr><br>
    ++&nbsp;&nbsp;<nobr><A HREF="android.support.design.widget.CoordinatorLayout.Behavior.html#android.support.design.widget.CoordinatorLayout.Behavior.onRequestChildRectangleOnScreen_added(android.support.design.widget.CoordinatorLayout, V, android.graphics.Rect, boolean)" class="hiddenlink" target="rightframe">type&nbsp;<b>
    ++(<code>CoordinatorLayout, V, Rect, boolean</code>)</b>&nbsp;in&nbsp;android.support.design.widget.CoordinatorLayout.Behavior
    ++</A></nobr><br>
    ++<nobr><A HREF="android.support.v4.app.SharedElementCallback.html#android.support.v4.app.SharedElementCallback.onSharedElementsArrived_added(java.util.List<java.lang.String>, java.util.List<android.view.View>, android.support.v4.app.SharedElementCallback.OnSharedElementsReadyListener)" class="hiddenlink" target="rightframe"><b>onSharedElementsArrived</b>
    ++(<code>List&lt;String&gt;, List&lt;View&gt;, OnSharedElementsReadyListener</code>)</A></nobr><br>
    ++<nobr><A HREF="android.support.v7.app.AppCompatDelegate.html#android.support.v7.app.AppCompatDelegate.onStart_added()" class="hiddenlink" target="rightframe"><b>onStart</b>
    ++()</A></nobr><br>
    ++<nobr><A HREF="android.support.v17.leanback.widget.AbstractMediaItemPresenter.html#android.support.v17.leanback.widget.AbstractMediaItemPresenter.onUnbindMediaPlayState_added(android.support.v17.leanback.widget.AbstractMediaItemPresenter.ViewHolder)" class="hiddenlink" target="rightframe"><b>onUnbindMediaPlayState</b>
    ++(<code>ViewHolder</code>)</A></nobr><br>
    ++<A NAME="P"></A>
    ++<br><font size="+2">P</font>&nbsp;
    ++<a href="#A"><font size="-2">A</font></a> 
    ++<a href="#B"><font size="-2">B</font></a> 
    ++<a href="#C"><font size="-2">C</font></a> 
    ++<a href="#D"><font size="-2">D</font></a> 
    ++<a href="#F"><font size="-2">F</font></a> 
    ++<a href="#G"><font size="-2">G</font></a> 
    ++<a href="#I"><font size="-2">I</font></a> 
    ++<a href="#L"><font size="-2">L</font></a> 
    ++<a href="#M"><font size="-2">M</font></a> 
    ++<a href="#N"><font size="-2">N</font></a> 
    ++<a href="#O"><font size="-2">O</font></a> 
    ++<a href="#R"><font size="-2">R</font></a> 
    ++<a href="#S"><font size="-2">S</font></a> 
    ++<a href="#T"><font size="-2">T</font></a> 
    ++ <a href="#topheader"><font size="-2">TOP</font></a>
    ++<p><div style="line-height:1.5em;color:black">
    ++<nobr><A HREF="android.support.v7.widget.LinearLayoutManager.html#android.support.v7.widget.LinearLayoutManager.prepareForDrop_removed(android.view.View, android.view.View, int, int)" class="hiddenlink" target="rightframe"><strike>prepareForDrop</strike>
    ++(<code>View, View, int, int</code>)</A></nobr><br>
    ++<A NAME="R"></A>
    ++<br><font size="+2">R</font>&nbsp;
    ++<a href="#A"><font size="-2">A</font></a> 
    ++<a href="#B"><font size="-2">B</font></a> 
    ++<a href="#C"><font size="-2">C</font></a> 
    ++<a href="#D"><font size="-2">D</font></a> 
    ++<a href="#F"><font size="-2">F</font></a> 
    ++<a href="#G"><font size="-2">G</font></a> 
    ++<a href="#I"><font size="-2">I</font></a> 
    ++<a href="#L"><font size="-2">L</font></a> 
    ++<a href="#M"><font size="-2">M</font></a> 
    ++<a href="#N"><font size="-2">N</font></a> 
    ++<a href="#O"><font size="-2">O</font></a> 
    ++<a href="#P"><font size="-2">P</font></a> 
    ++<a href="#S"><font size="-2">S</font></a> 
    ++<a href="#T"><font size="-2">T</font></a> 
    ++ <a href="#topheader"><font size="-2">TOP</font></a>
    ++<p><div style="line-height:1.5em;color:black">
    ++<nobr><A HREF="android.support.v4.view.accessibility.AccessibilityManagerCompat.html#android.support.v4.view.accessibility.AccessibilityManagerCompat.removeAccessibilityStateChangeListener_changed(android.view.accessibility.AccessibilityManager, android.support.v4.view.accessibility.AccessibilityManagerCompat.AccessibilityStateChangeListener)" class="hiddenlink" target="rightframe">removeAccessibilityStateChangeListener
    ++(<code>AccessibilityManager, AccessibilityStateChangeListener</code>)</A></nobr><br>
    ++<nobr><A HREF="android.support.v4.view.accessibility.AccessibilityManagerCompat.html#android.support.v4.view.accessibility.AccessibilityManagerCompat.removeTouchExplorationStateChangeListener_added(android.view.accessibility.AccessibilityManager, android.support.v4.view.accessibility.AccessibilityManagerCompat.TouchExplorationStateChangeListener)" class="hiddenlink" target="rightframe"><b>removeTouchExplorationStateChangeListener</b>
    ++(<code>AccessibilityManager, TouchExplorationStateChangeListener</code>)</A></nobr><br>
    ++<nobr><A HREF="android.support.v4.app.ActivityOptionsCompat.html#android.support.v4.app.ActivityOptionsCompat.requestUsageTimeReport_added(android.app.PendingIntent)" class="hiddenlink" target="rightframe"><b>requestUsageTimeReport</b>
    ++(<code>PendingIntent</code>)</A></nobr><br>
    ++<A NAME="S"></A>
    ++<br><font size="+2">S</font>&nbsp;
    ++<a href="#A"><font size="-2">A</font></a> 
    ++<a href="#B"><font size="-2">B</font></a> 
    ++<a href="#C"><font size="-2">C</font></a> 
    ++<a href="#D"><font size="-2">D</font></a> 
    ++<a href="#F"><font size="-2">F</font></a> 
    ++<a href="#G"><font size="-2">G</font></a> 
    ++<a href="#I"><font size="-2">I</font></a> 
    ++<a href="#L"><font size="-2">L</font></a> 
    ++<a href="#M"><font size="-2">M</font></a> 
    ++<a href="#N"><font size="-2">N</font></a> 
    ++<a href="#O"><font size="-2">O</font></a> 
    ++<a href="#P"><font size="-2">P</font></a> 
    ++<a href="#R"><font size="-2">R</font></a> 
    ++<a href="#T"><font size="-2">T</font></a> 
    ++ <a href="#topheader"><font size="-2">TOP</font></a>
    ++<p><div style="line-height:1.5em;color:black">
    ++<nobr><A HREF="android.support.v4.view.accessibility.AccessibilityEventCompat.html#android.support.v4.view.accessibility.AccessibilityEventCompat.setAction_added(android.view.accessibility.AccessibilityEvent, int)" class="hiddenlink" target="rightframe"><b>setAction</b>
    ++(<code>AccessibilityEvent, int</code>)</A></nobr><br>
    ++<nobr><A HREF="android.support.customtabs.CustomTabsIntent.html#android.support.customtabs.CustomTabsIntent.setAlwaysUseBrowserUI_added(android.content.Intent)" class="hiddenlink" target="rightframe"><b>setAlwaysUseBrowserUI</b>
    ++(<code>Intent</code>)</A></nobr><br>
    ++<nobr><A HREF="android.support.design.widget.FloatingActionButton.Behavior.html#android.support.design.widget.FloatingActionButton.Behavior.setAutoHideEnabled_added(boolean)" class="hiddenlink" target="rightframe"><b>setAutoHideEnabled</b>
    ++(<code>boolean</code>)</A></nobr><br>
    ++<nobr><A HREF="android.support.design.widget.CollapsingToolbarLayout.html#android.support.design.widget.CollapsingToolbarLayout.setCollapsedTitleTextColor_added(android.content.res.ColorStateList)" class="hiddenlink" target="rightframe"><b>setCollapsedTitleTextColor</b>
    ++(<code>ColorStateList</code>)</A></nobr><br>
    ++<nobr><A HREF="android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.html#android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.setContextClickable_added(boolean)" class="hiddenlink" target="rightframe"><b>setContextClickable</b>
    ++(<code>boolean</code>)</A></nobr><br>
    ++<nobr><A HREF="android.support.v7.app.ActionBarDrawerToggle.html#android.support.v7.app.ActionBarDrawerToggle.setDrawerArrowDrawable_added(android.support.v7.graphics.drawable.DrawerArrowDrawable)" class="hiddenlink" target="rightframe"><b>setDrawerArrowDrawable</b>
    ++(<code>DrawerArrowDrawable</code>)</A></nobr><br>
    ++<nobr><A HREF="android.support.design.widget.CollapsingToolbarLayout.html#android.support.design.widget.CollapsingToolbarLayout.setExpandedTitleTextColor_added(android.content.res.ColorStateList)" class="hiddenlink" target="rightframe"><b>setExpandedTitleTextColor</b>
    ++(<code>ColorStateList</code>)</A></nobr><br>
    ++<nobr><A HREF="android.support.customtabs.CustomTabsIntent.Builder.html#android.support.customtabs.CustomTabsIntent.Builder.setInstantAppsEnabled_added(boolean)" class="hiddenlink" target="rightframe"><b>setInstantAppsEnabled</b>
    ++(<code>boolean</code>)</A></nobr><br>
    ++<nobr><A HREF="android.support.v4.app.ActivityOptionsCompat.html#android.support.v4.app.ActivityOptionsCompat.setLaunchBounds_added(android.graphics.Rect)" class="hiddenlink" target="rightframe"><b>setLaunchBounds</b>
    ++(<code>Rect</code>)</A></nobr><br>
    ++<nobr><A HREF="android.support.v4.view.accessibility.AccessibilityEventCompat.html#android.support.v4.view.accessibility.AccessibilityEventCompat.setMovementGranularity_added(android.view.accessibility.AccessibilityEvent, int)" class="hiddenlink" target="rightframe"><b>setMovementGranularity</b>
    ++(<code>AccessibilityEvent, int</code>)</A></nobr><br>
    ++<nobr><A HREF="android.support.v4.widget.SwipeRefreshLayout.html#android.support.v4.widget.SwipeRefreshLayout.setOnChildScrollUpCallback_added(android.support.v4.widget.SwipeRefreshLayout.OnChildScrollUpCallback)" class="hiddenlink" target="rightframe"><b>setOnChildScrollUpCallback</b>
    ++(<code>OnChildScrollUpCallback</code>)</A></nobr><br>
    ++<nobr><A HREF="android.support.v4.widget.SearchViewCompat.html#android.support.v4.widget.SearchViewCompat.setOnCloseListener_changed(android.view.View, android.support.v4.widget.SearchViewCompat.OnCloseListener)" class="hiddenlink" target="rightframe">setOnCloseListener
    ++(<code>View, OnCloseListener</code>)</A></nobr><br>
    ++<nobr><A HREF="android.support.v7.widget.RecyclerView.html#android.support.v7.widget.RecyclerView.setOnFlingListener_added(android.support.v7.widget.RecyclerView.OnFlingListener)" class="hiddenlink" target="rightframe"><b>setOnFlingListener</b>
    ++(<code>OnFlingListener</code>)</A></nobr><br>
    ++<nobr><A HREF="android.support.v4.widget.SearchViewCompat.html#android.support.v4.widget.SearchViewCompat.setOnQueryTextListener_changed(android.view.View, android.support.v4.widget.SearchViewCompat.OnQueryTextListener)" class="hiddenlink" target="rightframe">setOnQueryTextListener
    ++(<code>View, OnQueryTextListener</code>)</A></nobr><br>
    ++<nobr><A HREF="android.support.v4.view.ViewCompat.html#android.support.v4.view.ViewCompat.setOverScrollMode_changed(android.view.View, int)" class="hiddenlink" target="rightframe">setOverScrollMode
    ++(<code>View, int</code>)</A></nobr><br>
    ++<i>setPasswordVisibilityToggleContentDescription</i><br>
    ++&nbsp;&nbsp;<nobr><A HREF="android.support.design.widget.TextInputLayout.html#android.support.design.widget.TextInputLayout.setPasswordVisibilityToggleContentDescription_added(int)" class="hiddenlink" target="rightframe">type&nbsp;<b>
    ++(<code>int</code>)</b>&nbsp;in&nbsp;android.support.design.widget.TextInputLayout
    ++</A></nobr><br>
    ++&nbsp;&nbsp;<nobr><A HREF="android.support.design.widget.TextInputLayout.html#android.support.design.widget.TextInputLayout.setPasswordVisibilityToggleContentDescription_added(java.lang.CharSequence)" class="hiddenlink" target="rightframe">type&nbsp;<b>
    ++(<code>CharSequence</code>)</b>&nbsp;in&nbsp;android.support.design.widget.TextInputLayout
    ++</A></nobr><br>
    ++<i>setPasswordVisibilityToggleDrawable</i><br>
    ++&nbsp;&nbsp;<nobr><A HREF="android.support.design.widget.TextInputLayout.html#android.support.design.widget.TextInputLayout.setPasswordVisibilityToggleDrawable_added(android.graphics.drawable.Drawable)" class="hiddenlink" target="rightframe">type&nbsp;<b>
    ++(<code>Drawable</code>)</b>&nbsp;in&nbsp;android.support.design.widget.TextInputLayout
    ++</A></nobr><br>
    ++&nbsp;&nbsp;<nobr><A HREF="android.support.design.widget.TextInputLayout.html#android.support.design.widget.TextInputLayout.setPasswordVisibilityToggleDrawable_added(int)" class="hiddenlink" target="rightframe">type&nbsp;<b>
    ++(<code>int</code>)</b>&nbsp;in&nbsp;android.support.design.widget.TextInputLayout
    ++</A></nobr><br>
    ++<nobr><A HREF="android.support.design.widget.TextInputLayout.html#android.support.design.widget.TextInputLayout.setPasswordVisibilityToggleEnabled_added(boolean)" class="hiddenlink" target="rightframe"><b>setPasswordVisibilityToggleEnabled</b>
    ++(<code>boolean</code>)</A></nobr><br>
    ++<nobr><A HREF="android.support.design.widget.TextInputLayout.html#android.support.design.widget.TextInputLayout.setPasswordVisibilityToggleTintList_added(android.content.res.ColorStateList)" class="hiddenlink" target="rightframe"><b>setPasswordVisibilityToggleTintList</b>
    ++(<code>ColorStateList</code>)</A></nobr><br>
    ++<nobr><A HREF="android.support.design.widget.TextInputLayout.html#android.support.design.widget.TextInputLayout.setPasswordVisibilityToggleTintMode_added(android.graphics.PorterDuff.Mode)" class="hiddenlink" target="rightframe"><b>setPasswordVisibilityToggleTintMode</b>
    ++(<code>Mode</code>)</A></nobr><br>
    ++<nobr><A HREF="android.support.customtabs.CustomTabsSession.html#android.support.customtabs.CustomTabsSession.setSecondaryToolbarViews_added(android.widget.RemoteViews, int[], android.app.PendingIntent)" class="hiddenlink" target="rightframe"><b>setSecondaryToolbarViews</b>
    ++(<code>RemoteViews, int[], PendingIntent</code>)</A></nobr><br>
    ++<nobr><A HREF="android.support.v17.leanback.widget.AbstractMediaItemPresenter.ViewHolder.html#android.support.v17.leanback.widget.AbstractMediaItemPresenter.ViewHolder.setSelectedMediaItemNumberView_added(int)" class="hiddenlink" target="rightframe"><b>setSelectedMediaItemNumberView</b>
    ++(<code>int</code>)</A></nobr><br>
    ++<nobr><A HREF="android.support.customtabs.CustomTabsSession.html#android.support.customtabs.CustomTabsSession.setToolbarItem_changed(int, android.graphics.Bitmap, java.lang.String)" class="hiddenlink" target="rightframe">setToolbarItem
    ++(<code>int, Bitmap, String</code>)</A></nobr><br>
    ++<nobr><A HREF="android.support.customtabs.CustomTabsIntent.html#android.support.customtabs.CustomTabsIntent.shouldAlwaysUseBrowserUI_added(android.content.Intent)" class="hiddenlink" target="rightframe"><b>shouldAlwaysUseBrowserUI</b>
    ++(<code>Intent</code>)</A></nobr><br>
    ++<nobr><A HREF="android.support.v4.view.KeyEventCompat.html#android.support.v4.view.KeyEventCompat.startTracking_changed(android.view.KeyEvent)" class="hiddenlink" target="rightframe">startTracking
    ++(<code>KeyEvent</code>)</A></nobr><br>
    ++<nobr><A HREF="android.support.v4.app.ServiceCompat.html#android.support.v4.app.ServiceCompat.stopForeground_added(android.app.Service, int)" class="hiddenlink" target="rightframe"><b>stopForeground</b>
    ++(<code>Service, int</code>)</A></nobr><br>
    ++<A NAME="T"></A>
    ++<br><font size="+2">T</font>&nbsp;
    ++<a href="#A"><font size="-2">A</font></a> 
    ++<a href="#B"><font size="-2">B</font></a> 
    ++<a href="#C"><font size="-2">C</font></a> 
    ++<a href="#D"><font size="-2">D</font></a> 
    ++<a href="#F"><font size="-2">F</font></a> 
    ++<a href="#G"><font size="-2">G</font></a> 
    ++<a href="#I"><font size="-2">I</font></a> 
    ++<a href="#L"><font size="-2">L</font></a> 
    ++<a href="#M"><font size="-2">M</font></a> 
    ++<a href="#N"><font size="-2">N</font></a> 
    ++<a href="#O"><font size="-2">O</font></a> 
    ++<a href="#P"><font size="-2">P</font></a> 
    ++<a href="#R"><font size="-2">R</font></a> 
    ++<a href="#S"><font size="-2">S</font></a> 
    ++ <a href="#topheader"><font size="-2">TOP</font></a>
    ++<p><div style="line-height:1.5em;color:black">
    ++<nobr><A HREF="android.support.v4.media.session.PlaybackStateCompat.html#android.support.v4.media.session.PlaybackStateCompat.toKeyCode_added(long)" class="hiddenlink" target="rightframe"><b>toKeyCode</b>
    ++(<code>long</code>)</A></nobr><br>
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    ++</script>
    ++<script type="text/javascript">
    ++  try {
    ++    var pageTracker = _gat._getTracker("UA-5831155-1");
    ++    pageTracker._setAllowAnchor(true);
    ++    pageTracker._initData();
    ++    pageTracker._trackPageview();
    ++  } catch(e) {}
    ++</script>
    ++</BODY>
    ++</HTML>
    +diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/methods_index_changes.html b/docs/html/sdk/support_api_diff/24.2.0/changes/methods_index_changes.html
    +new file mode 100644
    +index 0000000..ef008cb
    +--- /dev/null
    ++++ b/docs/html/sdk/support_api_diff/24.2.0/changes/methods_index_changes.html
    +@@ -0,0 +1,222 @@
    ++<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
    ++<HTML style="overflow:auto;">
    ++<HEAD>
    ++<meta name="generator" content="JDiff v1.1.0">
    ++<!-- Generated by the JDiff Javadoc doclet -->
    ++<!-- (http://www.jdiff.org) -->
    ++<meta name="description" content="JDiff is a Javadoc doclet which generates an HTML report of all the packages, classes, constructors, methods, and fields which have been removed, added or changed in any way, including their documentation, when two APIs are compared.">
    ++<meta name="keywords" content="diff, jdiff, javadiff, java diff, java difference, API difference, difference between two APIs, API diff, Javadoc, doclet">
    ++<TITLE>
    ++Method Changes Index
    ++</TITLE>
    ++<link href="../../../../assets/android-developer-docs.css" rel="stylesheet" type="text/css" />
    ++<link href="../stylesheet-jdiff.css" rel="stylesheet" type="text/css" />
    ++<noscript>
    ++<style type="text/css">
    ++body{overflow:auto;}
    ++#body-content{position:relative; top:0;}
    ++#doc-content{overflow:visible;border-left:3px solid #666;}
    ++#side-nav{padding:0;}
    ++#side-nav .toggle-list ul {display:block;}
    ++#resize-packages-nav{border-bottom:3px solid #666;}
    ++</style>
    ++</noscript>
    ++<style type="text/css">
    ++</style>
    ++</HEAD>
    ++<BODY class="gc-documentation" style="padding:12px;">
    ++<a NAME="topheader"></a>
    ++<table summary="Index for Methods" width="100%" class="jdiffIndex" border="0" cellspacing="0" cellpadding="0" style="padding-bottom:0;margin-bottom:0;">
    ++  <tr>
    ++  <th class="indexHeader">
    ++    Filter the Index:
    ++  </th>
    ++  </tr>
    ++  <tr>
    ++  <td class="indexText" style="line-height:1.3em;padding-left:2em;">
    ++<a href="methods_index_all.html" class="staysblack">All Methods</a>
    ++  <br>
    ++<A HREF="methods_index_removals.html" xclass="hiddenlink">Removals</A>
    ++  <br>
    ++<A HREF="methods_index_additions.html"xclass="hiddenlink">Additions</A>
    ++  <br>
    ++<b>Changes</b>
    ++  </td>
    ++  </tr>
    ++</table>
    ++<div id="indexTableCaption" style="background-color:#eee;padding:0 4px 0 4px;font-size:11px;margin-bottom:1em;">
    ++Listed as: <span style="color:#069"><strong>Added</strong></span>,  <span style="color:#069"><strike>Removed</strike></span>,  <span style="color:#069">Changed</span></font>
    ++</div>
    ++<A NAME="A"></A>
    ++<br><font size="+2">A</font>&nbsp;
    ++<a href="#C"><font size="-2">C</font></a> 
    ++<a href="#D"><font size="-2">D</font></a> 
    ++<a href="#F"><font size="-2">F</font></a> 
    ++<a href="#G"><font size="-2">G</font></a> 
    ++<a href="#I"><font size="-2">I</font></a> 
    ++<a href="#O"><font size="-2">O</font></a> 
    ++<a href="#R"><font size="-2">R</font></a> 
    ++<a href="#S"><font size="-2">S</font></a> 
    ++ <a href="#topheader"><font size="-2">TOP</font></a>
    ++<p><div style="line-height:1.5em;color:black">
    ++<nobr><A HREF="android.support.v4.view.accessibility.AccessibilityManagerCompat.html#android.support.v4.view.accessibility.AccessibilityManagerCompat.addAccessibilityStateChangeListener_changed(android.view.accessibility.AccessibilityManager, android.support.v4.view.accessibility.AccessibilityManagerCompat.AccessibilityStateChangeListener)" class="hiddenlink" target="rightframe">addAccessibilityStateChangeListener
    ++(<code>AccessibilityManager, AccessibilityStateChangeListener</code>)</A></nobr><br>
    ++<A NAME="C"></A>
    ++<br><font size="+2">C</font>&nbsp;
    ++<a href="#A"><font size="-2">A</font></a> 
    ++<a href="#D"><font size="-2">D</font></a> 
    ++<a href="#F"><font size="-2">F</font></a> 
    ++<a href="#G"><font size="-2">G</font></a> 
    ++<a href="#I"><font size="-2">I</font></a> 
    ++<a href="#O"><font size="-2">O</font></a> 
    ++<a href="#R"><font size="-2">R</font></a> 
    ++<a href="#S"><font size="-2">S</font></a> 
    ++ <a href="#topheader"><font size="-2">TOP</font></a>
    ++<p><div style="line-height:1.5em;color:black">
    ++<nobr><A HREF="android.support.v7.widget.LinearSmoothScroller.html#android.support.v7.widget.LinearSmoothScroller.computeScrollVectorForPosition_changed(int)" class="hiddenlink" target="rightframe">computeScrollVectorForPosition
    ++(<code>int</code>)</A></nobr><br>
    ++<A NAME="D"></A>
    ++<br><font size="+2">D</font>&nbsp;
    ++<a href="#A"><font size="-2">A</font></a> 
    ++<a href="#C"><font size="-2">C</font></a> 
    ++<a href="#F"><font size="-2">F</font></a> 
    ++<a href="#G"><font size="-2">G</font></a> 
    ++<a href="#I"><font size="-2">I</font></a> 
    ++<a href="#O"><font size="-2">O</font></a> 
    ++<a href="#R"><font size="-2">R</font></a> 
    ++<a href="#S"><font size="-2">S</font></a> 
    ++ <a href="#topheader"><font size="-2">TOP</font></a>
    ++<p><div style="line-height:1.5em;color:black">
    ++<nobr><A HREF="android.support.v4.view.KeyEventCompat.html#android.support.v4.view.KeyEventCompat.dispatch_changed(android.view.KeyEvent, android.view.KeyEvent.Callback, java.lang.Object, java.lang.Object)" class="hiddenlink" target="rightframe">dispatch
    ++(<code>KeyEvent, Callback, Object, Object</code>)</A></nobr><br>
    ++<A NAME="F"></A>
    ++<br><font size="+2">F</font>&nbsp;
    ++<a href="#A"><font size="-2">A</font></a> 
    ++<a href="#C"><font size="-2">C</font></a> 
    ++<a href="#D"><font size="-2">D</font></a> 
    ++<a href="#G"><font size="-2">G</font></a> 
    ++<a href="#I"><font size="-2">I</font></a> 
    ++<a href="#O"><font size="-2">O</font></a> 
    ++<a href="#R"><font size="-2">R</font></a> 
    ++<a href="#S"><font size="-2">S</font></a> 
    ++ <a href="#topheader"><font size="-2">TOP</font></a>
    ++<p><div style="line-height:1.5em;color:black">
    ++<nobr><A HREF="android.support.v4.view.MotionEventCompat.html#android.support.v4.view.MotionEventCompat.findPointerIndex_changed(android.view.MotionEvent, int)" class="hiddenlink" target="rightframe">findPointerIndex
    ++(<code>MotionEvent, int</code>)</A></nobr><br>
    ++<A NAME="G"></A>
    ++<br><font size="+2">G</font>&nbsp;
    ++<a href="#A"><font size="-2">A</font></a> 
    ++<a href="#C"><font size="-2">C</font></a> 
    ++<a href="#D"><font size="-2">D</font></a> 
    ++<a href="#F"><font size="-2">F</font></a> 
    ++<a href="#I"><font size="-2">I</font></a> 
    ++<a href="#O"><font size="-2">O</font></a> 
    ++<a href="#R"><font size="-2">R</font></a> 
    ++<a href="#S"><font size="-2">S</font></a> 
    ++ <a href="#topheader"><font size="-2">TOP</font></a>
    ++<p><div style="line-height:1.5em;color:black">
    ++<nobr><A HREF="android.support.v4.accessibilityservice.AccessibilityServiceInfoCompat.html#android.support.v4.accessibilityservice.AccessibilityServiceInfoCompat.getDescription_changed(android.accessibilityservice.AccessibilityServiceInfo)" class="hiddenlink" target="rightframe">getDescription
    ++(<code>AccessibilityServiceInfo</code>)</A></nobr><br>
    ++<nobr><A HREF="android.support.v4.view.KeyEventCompat.html#android.support.v4.view.KeyEventCompat.getKeyDispatcherState_changed(android.view.View)" class="hiddenlink" target="rightframe">getKeyDispatcherState
    ++(<code>View</code>)</A></nobr><br>
    ++<nobr><A HREF="android.support.v4.view.ViewCompat.html#android.support.v4.view.ViewCompat.getOverScrollMode_changed(android.view.View)" class="hiddenlink" target="rightframe">getOverScrollMode
    ++(<code>View</code>)</A></nobr><br>
    ++<nobr><A HREF="android.support.v4.view.MotionEventCompat.html#android.support.v4.view.MotionEventCompat.getPointerCount_changed(android.view.MotionEvent)" class="hiddenlink" target="rightframe">getPointerCount
    ++(<code>MotionEvent</code>)</A></nobr><br>
    ++<nobr><A HREF="android.support.v4.view.MotionEventCompat.html#android.support.v4.view.MotionEventCompat.getPointerId_changed(android.view.MotionEvent, int)" class="hiddenlink" target="rightframe">getPointerId
    ++(<code>MotionEvent, int</code>)</A></nobr><br>
    ++<nobr><A HREF="android.support.v4.app.ActivityCompat.html#android.support.v4.app.ActivityCompat.getReferrer_changed(android.app.Activity)" class="hiddenlink" target="rightframe">getReferrer
    ++(<code>Activity</code>)</A></nobr><br>
    ++<nobr><A HREF="android.support.v4.view.ViewConfigurationCompat.html#android.support.v4.view.ViewConfigurationCompat.getScaledPagingTouchSlop_changed(android.view.ViewConfiguration)" class="hiddenlink" target="rightframe">getScaledPagingTouchSlop
    ++(<code>ViewConfiguration</code>)</A></nobr><br>
    ++<nobr><A HREF="android.support.v4.view.MotionEventCompat.html#android.support.v4.view.MotionEventCompat.getSource_changed(android.view.MotionEvent)" class="hiddenlink" target="rightframe">getSource
    ++(<code>MotionEvent</code>)</A></nobr><br>
    ++<nobr><A HREF="android.support.v4.view.MotionEventCompat.html#android.support.v4.view.MotionEventCompat.getX_changed(android.view.MotionEvent, int)" class="hiddenlink" target="rightframe">getX
    ++(<code>MotionEvent, int</code>)</A></nobr><br>
    ++<nobr><A HREF="android.support.v4.view.MotionEventCompat.html#android.support.v4.view.MotionEventCompat.getY_changed(android.view.MotionEvent, int)" class="hiddenlink" target="rightframe">getY
    ++(<code>MotionEvent, int</code>)</A></nobr><br>
    ++<A NAME="I"></A>
    ++<br><font size="+2">I</font>&nbsp;
    ++<a href="#A"><font size="-2">A</font></a> 
    ++<a href="#C"><font size="-2">C</font></a> 
    ++<a href="#D"><font size="-2">D</font></a> 
    ++<a href="#F"><font size="-2">F</font></a> 
    ++<a href="#G"><font size="-2">G</font></a> 
    ++<a href="#O"><font size="-2">O</font></a> 
    ++<a href="#R"><font size="-2">R</font></a> 
    ++<a href="#S"><font size="-2">S</font></a> 
    ++ <a href="#topheader"><font size="-2">TOP</font></a>
    ++<p><div style="line-height:1.5em;color:black">
    ++<nobr><A HREF="android.support.design.widget.CoordinatorLayout.Behavior.html#android.support.design.widget.CoordinatorLayout.Behavior.isDirty_changed(android.support.design.widget.CoordinatorLayout, V)" class="hiddenlink" target="rightframe">isDirty
    ++(<code>CoordinatorLayout, V</code>)</A></nobr><br>
    ++<nobr><A HREF="android.support.v4.view.ViewCompat.html#android.support.v4.view.ViewCompat.isOpaque_changed(android.view.View)" class="hiddenlink" target="rightframe">isOpaque
    ++(<code>View</code>)</A></nobr><br>
    ++<nobr><A HREF="android.support.v4.view.KeyEventCompat.html#android.support.v4.view.KeyEventCompat.isTracking_changed(android.view.KeyEvent)" class="hiddenlink" target="rightframe">isTracking
    ++(<code>KeyEvent</code>)</A></nobr><br>
    ++<A NAME="O"></A>
    ++<br><font size="+2">O</font>&nbsp;
    ++<a href="#A"><font size="-2">A</font></a> 
    ++<a href="#C"><font size="-2">C</font></a> 
    ++<a href="#D"><font size="-2">D</font></a> 
    ++<a href="#F"><font size="-2">F</font></a> 
    ++<a href="#G"><font size="-2">G</font></a> 
    ++<a href="#I"><font size="-2">I</font></a> 
    ++<a href="#R"><font size="-2">R</font></a> 
    ++<a href="#S"><font size="-2">S</font></a> 
    ++ <a href="#topheader"><font size="-2">TOP</font></a>
    ++<p><div style="line-height:1.5em;color:black">
    ++<i>obtain</i><br>
    ++&nbsp;&nbsp;<nobr><A HREF="android.support.v4.media.session.MediaSessionCompat.html#android.support.v4.media.session.MediaSessionCompat.obtain_changed(android.content.Context, java.lang.Object)" class="hiddenlink" target="rightframe">type&nbsp;
    ++(<code>Context, Object</code>)&nbsp;in&nbsp;android.support.v4.media.session.MediaSessionCompat
    ++</A></nobr><br>
    ++&nbsp;&nbsp;<nobr><A HREF="android.support.v4.media.session.MediaSessionCompat.QueueItem.html#android.support.v4.media.session.MediaSessionCompat.QueueItem.obtain_changed(java.lang.Object)" class="hiddenlink" target="rightframe">type&nbsp;
    ++(<code>Object</code>)&nbsp;in&nbsp;android.support.v4.media.session.MediaSessionCompat.QueueItem
    ++</A></nobr><br>
    ++<A NAME="R"></A>
    ++<br><font size="+2">R</font>&nbsp;
    ++<a href="#A"><font size="-2">A</font></a> 
    ++<a href="#C"><font size="-2">C</font></a> 
    ++<a href="#D"><font size="-2">D</font></a> 
    ++<a href="#F"><font size="-2">F</font></a> 
    ++<a href="#G"><font size="-2">G</font></a> 
    ++<a href="#I"><font size="-2">I</font></a> 
    ++<a href="#O"><font size="-2">O</font></a> 
    ++<a href="#S"><font size="-2">S</font></a> 
    ++ <a href="#topheader"><font size="-2">TOP</font></a>
    ++<p><div style="line-height:1.5em;color:black">
    ++<nobr><A HREF="android.support.v4.view.accessibility.AccessibilityManagerCompat.html#android.support.v4.view.accessibility.AccessibilityManagerCompat.removeAccessibilityStateChangeListener_changed(android.view.accessibility.AccessibilityManager, android.support.v4.view.accessibility.AccessibilityManagerCompat.AccessibilityStateChangeListener)" class="hiddenlink" target="rightframe">removeAccessibilityStateChangeListener
    ++(<code>AccessibilityManager, AccessibilityStateChangeListener</code>)</A></nobr><br>
    ++<A NAME="S"></A>
    ++<br><font size="+2">S</font>&nbsp;
    ++<a href="#A"><font size="-2">A</font></a> 
    ++<a href="#C"><font size="-2">C</font></a> 
    ++<a href="#D"><font size="-2">D</font></a> 
    ++<a href="#F"><font size="-2">F</font></a> 
    ++<a href="#G"><font size="-2">G</font></a> 
    ++<a href="#I"><font size="-2">I</font></a> 
    ++<a href="#O"><font size="-2">O</font></a> 
    ++<a href="#R"><font size="-2">R</font></a> 
    ++ <a href="#topheader"><font size="-2">TOP</font></a>
    ++<p><div style="line-height:1.5em;color:black">
    ++<nobr><A HREF="android.support.v4.widget.SearchViewCompat.html#android.support.v4.widget.SearchViewCompat.setOnCloseListener_changed(android.view.View, android.support.v4.widget.SearchViewCompat.OnCloseListener)" class="hiddenlink" target="rightframe">setOnCloseListener
    ++(<code>View, OnCloseListener</code>)</A></nobr><br>
    ++<nobr><A HREF="android.support.v4.widget.SearchViewCompat.html#android.support.v4.widget.SearchViewCompat.setOnQueryTextListener_changed(android.view.View, android.support.v4.widget.SearchViewCompat.OnQueryTextListener)" class="hiddenlink" target="rightframe">setOnQueryTextListener
    ++(<code>View, OnQueryTextListener</code>)</A></nobr><br>
    ++<nobr><A HREF="android.support.v4.view.ViewCompat.html#android.support.v4.view.ViewCompat.setOverScrollMode_changed(android.view.View, int)" class="hiddenlink" target="rightframe">setOverScrollMode
    ++(<code>View, int</code>)</A></nobr><br>
    ++<nobr><A HREF="android.support.customtabs.CustomTabsSession.html#android.support.customtabs.CustomTabsSession.setToolbarItem_changed(int, android.graphics.Bitmap, java.lang.String)" class="hiddenlink" target="rightframe">setToolbarItem
    ++(<code>int, Bitmap, String</code>)</A></nobr><br>
    ++<nobr><A HREF="android.support.v4.view.KeyEventCompat.html#android.support.v4.view.KeyEventCompat.startTracking_changed(android.view.KeyEvent)" class="hiddenlink" target="rightframe">startTracking
    ++(<code>KeyEvent</code>)</A></nobr><br>
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    ++</script>
    ++<script type="text/javascript">
    ++  try {
    ++    var pageTracker = _gat._getTracker("UA-5831155-1");
    ++    pageTracker._setAllowAnchor(true);
    ++    pageTracker._initData();
    ++    pageTracker._trackPageview();
    ++  } catch(e) {}
    ++</script>
    ++</BODY>
    ++</HTML>
    +diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/methods_index_removals.html b/docs/html/sdk/support_api_diff/24.2.0/changes/methods_index_removals.html
    +new file mode 100644
    +index 0000000..1c0c6be
    +--- /dev/null
    ++++ b/docs/html/sdk/support_api_diff/24.2.0/changes/methods_index_removals.html
    +@@ -0,0 +1,93 @@
    ++<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
    ++<HTML style="overflow:auto;">
    ++<HEAD>
    ++<meta name="generator" content="JDiff v1.1.0">
    ++<!-- Generated by the JDiff Javadoc doclet -->
    ++<!-- (http://www.jdiff.org) -->
    ++<meta name="description" content="JDiff is a Javadoc doclet which generates an HTML report of all the packages, classes, constructors, methods, and fields which have been removed, added or changed in any way, including their documentation, when two APIs are compared.">
    ++<meta name="keywords" content="diff, jdiff, javadiff, java diff, java difference, API difference, difference between two APIs, API diff, Javadoc, doclet">
    ++<TITLE>
    ++Method Removals Index
    ++</TITLE>
    ++<link href="../../../../assets/android-developer-docs.css" rel="stylesheet" type="text/css" />
    ++<link href="../stylesheet-jdiff.css" rel="stylesheet" type="text/css" />
    ++<noscript>
    ++<style type="text/css">
    ++body{overflow:auto;}
    ++#body-content{position:relative; top:0;}
    ++#doc-content{overflow:visible;border-left:3px solid #666;}
    ++#side-nav{padding:0;}
    ++#side-nav .toggle-list ul {display:block;}
    ++#resize-packages-nav{border-bottom:3px solid #666;}
    ++</style>
    ++</noscript>
    ++<style type="text/css">
    ++</style>
    ++</HEAD>
    ++<BODY class="gc-documentation" style="padding:12px;">
    ++<a NAME="topheader"></a>
    ++<table summary="Index for Methods" width="100%" class="jdiffIndex" border="0" cellspacing="0" cellpadding="0" style="padding-bottom:0;margin-bottom:0;">
    ++  <tr>
    ++  <th class="indexHeader">
    ++    Filter the Index:
    ++  </th>
    ++  </tr>
    ++  <tr>
    ++  <td class="indexText" style="line-height:1.3em;padding-left:2em;">
    ++<a href="methods_index_all.html" class="staysblack">All Methods</a>
    ++  <br>
    ++<b>Removals</b>
    ++  <br>
    ++<A HREF="methods_index_additions.html"xclass="hiddenlink">Additions</A>
    ++  <br>
    ++<A HREF="methods_index_changes.html"xclass="hiddenlink">Changes</A>
    ++  </td>
    ++  </tr>
    ++</table>
    ++<div id="indexTableCaption" style="background-color:#eee;padding:0 4px 0 4px;font-size:11px;margin-bottom:1em;">
    ++Listed as: <span style="color:#069"><strong>Added</strong></span>,  <span style="color:#069"><strike>Removed</strike></span>,  <span style="color:#069">Changed</span></font>
    ++</div>
    ++<A NAME="L"></A>
    ++<br><font size="+2">L</font>&nbsp;
    ++<a href="#O"><font size="-2">O</font></a> 
    ++<a href="#P"><font size="-2">P</font></a> 
    ++ <a href="#topheader"><font size="-2">TOP</font></a>
    ++<p><div style="line-height:1.5em;color:black">
    ++<nobr><A HREF="android.support.design.widget.FloatingActionButton.Behavior.html#android.support.design.widget.FloatingActionButton.Behavior.layoutDependsOn_removed(android.support.design.widget.CoordinatorLayout, android.support.design.widget.FloatingActionButton, android.view.View)" class="hiddenlink" target="rightframe"><strike>layoutDependsOn</strike>
    ++(<code>CoordinatorLayout, FloatingActionButton, View</code>)</A></nobr><br>
    ++<A NAME="O"></A>
    ++<br><font size="+2">O</font>&nbsp;
    ++<a href="#L"><font size="-2">L</font></a> 
    ++<a href="#P"><font size="-2">P</font></a> 
    ++ <a href="#topheader"><font size="-2">TOP</font></a>
    ++<p><div style="line-height:1.5em;color:black">
    ++<nobr><A HREF="android.support.v4.view.accessibility.AccessibilityManagerCompat.AccessibilityStateChangeListenerCompat.html#android.support.v4.view.accessibility.AccessibilityManagerCompat.AccessibilityStateChangeListenerCompat.onAccessibilityStateChanged_removed(boolean)" class="hiddenlink" target="rightframe"><strike>onAccessibilityStateChanged</strike>
    ++(<code>boolean</code>)</A></nobr><br>
    ++<nobr><A HREF="android.support.design.widget.FloatingActionButton.Behavior.html#android.support.design.widget.FloatingActionButton.Behavior.onDependentViewRemoved_removed(android.support.design.widget.CoordinatorLayout, android.support.design.widget.FloatingActionButton, android.view.View)" class="hiddenlink" target="rightframe"><strike>onDependentViewRemoved</strike>
    ++(<code>CoordinatorLayout, FloatingActionButton, View</code>)</A></nobr><br>
    ++<nobr><A HREF="android.support.v7.util.SortedList.Callback.html#android.support.v7.util.SortedList.Callback.onInserted_removed(int, int)" class="hiddenlink" target="rightframe"><strike>onInserted</strike>
    ++(<code>int, int</code>)</A></nobr><br>
    ++<nobr><A HREF="android.support.v7.util.SortedList.Callback.html#android.support.v7.util.SortedList.Callback.onMoved_removed(int, int)" class="hiddenlink" target="rightframe"><strike>onMoved</strike>
    ++(<code>int, int</code>)</A></nobr><br>
    ++<nobr><A HREF="android.support.v7.util.SortedList.Callback.html#android.support.v7.util.SortedList.Callback.onRemoved_removed(int, int)" class="hiddenlink" target="rightframe"><strike>onRemoved</strike>
    ++(<code>int, int</code>)</A></nobr><br>
    ++<A NAME="P"></A>
    ++<br><font size="+2">P</font>&nbsp;
    ++<a href="#L"><font size="-2">L</font></a> 
    ++<a href="#O"><font size="-2">O</font></a> 
    ++ <a href="#topheader"><font size="-2">TOP</font></a>
    ++<p><div style="line-height:1.5em;color:black">
    ++<nobr><A HREF="android.support.v7.widget.LinearLayoutManager.html#android.support.v7.widget.LinearLayoutManager.prepareForDrop_removed(android.view.View, android.view.View, int, int)" class="hiddenlink" target="rightframe"><strike>prepareForDrop</strike>
    ++(<code>View, View, int, int</code>)</A></nobr><br>
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    ++</script>
    ++<script type="text/javascript">
    ++  try {
    ++    var pageTracker = _gat._getTracker("UA-5831155-1");
    ++    pageTracker._setAllowAnchor(true);
    ++    pageTracker._initData();
    ++    pageTracker._trackPageview();
    ++  } catch(e) {}
    ++</script>
    ++</BODY>
    ++</HTML>
    +diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/packages_index_additions.html b/docs/html/sdk/support_api_diff/24.2.0/changes/packages_index_additions.html
    +new file mode 100644
    +index 0000000..bb88d9f
    +--- /dev/null
    ++++ b/docs/html/sdk/support_api_diff/24.2.0/changes/packages_index_additions.html
    +@@ -0,0 +1,66 @@
    ++<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
    ++<HTML style="overflow:auto;">
    ++<HEAD>
    ++<meta name="generator" content="JDiff v1.1.0">
    ++<!-- Generated by the JDiff Javadoc doclet -->
    ++<!-- (http://www.jdiff.org) -->
    ++<meta name="description" content="JDiff is a Javadoc doclet which generates an HTML report of all the packages, classes, constructors, methods, and fields which have been removed, added or changed in any way, including their documentation, when two APIs are compared.">
    ++<meta name="keywords" content="diff, jdiff, javadiff, java diff, java difference, API difference, difference between two APIs, API diff, Javadoc, doclet">
    ++<TITLE>
    ++Package Additions Index
    ++</TITLE>
    ++<link href="../../../../assets/android-developer-docs.css" rel="stylesheet" type="text/css" />
    ++<link href="../stylesheet-jdiff.css" rel="stylesheet" type="text/css" />
    ++<noscript>
    ++<style type="text/css">
    ++body{overflow:auto;}
    ++#body-content{position:relative; top:0;}
    ++#doc-content{overflow:visible;border-left:3px solid #666;}
    ++#side-nav{padding:0;}
    ++#side-nav .toggle-list ul {display:block;}
    ++#resize-packages-nav{border-bottom:3px solid #666;}
    ++</style>
    ++</noscript>
    ++<style type="text/css">
    ++</style>
    ++</HEAD>
    ++<BODY class="gc-documentation" style="padding:12px;">
    ++<a NAME="topheader"></a>
    ++<table summary="Index for Packages" width="100%" class="jdiffIndex" border="0" cellspacing="0" cellpadding="0" style="padding-bottom:0;margin-bottom:0;">
    ++  <tr>
    ++  <th class="indexHeader">
    ++    Filter the Index:
    ++  </th>
    ++  </tr>
    ++  <tr>
    ++  <td class="indexText" style="line-height:1.3em;padding-left:2em;">
    ++<a href="packages_index_all.html" class="staysblack">All Packages</a>
    ++  <br>
    ++<A HREF="packages_index_removals.html" xclass="hiddenlink">Removals</A>
    ++  <br>
    ++<b>Additions</b>
    ++  <br>
    ++<A HREF="packages_index_changes.html"xclass="hiddenlink">Changes</A>
    ++  </td>
    ++  </tr>
    ++</table>
    ++<div id="indexTableCaption" style="background-color:#eee;padding:0 4px 0 4px;font-size:11px;margin-bottom:1em;">
    ++Listed as: <span style="color:#069"><strong>Added</strong></span>,  <span style="color:#069"><strike>Removed</strike></span>,  <span style="color:#069">Changed</span></font>
    ++</div>
    ++<br>
    ++<div id="indexTableEntries">
    ++<A NAME="A"></A>
    ++<A HREF="changes-summary.html#android.support.transition" class="hiddenlink" target="rightframe"><b>android.support.transition</b></A><br>
    ++<A HREF="changes-summary.html#android.support.v4.text.util" class="hiddenlink" target="rightframe"><b>android.support.v4.text.util</b></A><br>
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    ++</script>
    ++<script type="text/javascript">
    ++  try {
    ++    var pageTracker = _gat._getTracker("UA-5831155-1");
    ++    pageTracker._setAllowAnchor(true);
    ++    pageTracker._initData();
    ++    pageTracker._trackPageview();
    ++  } catch(e) {}
    ++</script>
    ++</BODY>
    ++</HTML>
    +diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/packages_index_all.html b/docs/html/sdk/support_api_diff/24.2.0/changes/packages_index_all.html
    +new file mode 100644
    +index 0000000..78805db
    +--- /dev/null
    ++++ b/docs/html/sdk/support_api_diff/24.2.0/changes/packages_index_all.html
    +@@ -0,0 +1,91 @@
    ++<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
    ++<HTML style="overflow:auto;">
    ++<HEAD>
    ++<meta name="generator" content="JDiff v1.1.0">
    ++<!-- Generated by the JDiff Javadoc doclet -->
    ++<!-- (http://www.jdiff.org) -->
    ++<meta name="description" content="JDiff is a Javadoc doclet which generates an HTML report of all the packages, classes, constructors, methods, and fields which have been removed, added or changed in any way, including their documentation, when two APIs are compared.">
    ++<meta name="keywords" content="diff, jdiff, javadiff, java diff, java difference, API difference, difference between two APIs, API diff, Javadoc, doclet">
    ++<TITLE>
    ++Package Differences Index
    ++</TITLE>
    ++<link href="../../../../assets/android-developer-docs.css" rel="stylesheet" type="text/css" />
    ++<link href="../stylesheet-jdiff.css" rel="stylesheet" type="text/css" />
    ++<noscript>
    ++<style type="text/css">
    ++body{overflow:auto;}
    ++#body-content{position:relative; top:0;}
    ++#doc-content{overflow:visible;border-left:3px solid #666;}
    ++#side-nav{padding:0;}
    ++#side-nav .toggle-list ul {display:block;}
    ++#resize-packages-nav{border-bottom:3px solid #666;}
    ++</style>
    ++</noscript>
    ++<style type="text/css">
    ++</style>
    ++</HEAD>
    ++<BODY class="gc-documentation" style="padding:12px;">
    ++<a NAME="topheader"></a>
    ++<table summary="Index for Packages" width="100%" class="jdiffIndex" border="0" cellspacing="0" cellpadding="0" style="padding-bottom:0;margin-bottom:0;">
    ++  <tr>
    ++  <th class="indexHeader">
    ++    Filter the Index:
    ++  </th>
    ++  </tr>
    ++  <tr>
    ++  <td class="indexText" style="line-height:1.3em;padding-left:2em;">
    ++<b>Packages</b>
    ++  <br>
    ++<A HREF="packages_index_removals.html" xclass="hiddenlink">Removals</A>
    ++  <br>
    ++<A HREF="packages_index_additions.html"xclass="hiddenlink">Additions</A>
    ++  <br>
    ++<A HREF="packages_index_changes.html"xclass="hiddenlink">Changes</A>
    ++  </td>
    ++  </tr>
    ++</table>
    ++<div id="indexTableCaption" style="background-color:#eee;padding:0 4px 0 4px;font-size:11px;margin-bottom:1em;">
    ++Listed as: <span style="color:#069"><strong>Added</strong></span>,  <span style="color:#069"><strike>Removed</strike></span>,  <span style="color:#069">Changed</span></font>
    ++</div>
    ++<br>
    ++<div id="indexTableEntries">
    ++<A NAME="A"></A>
    ++<A HREF="pkg_android.support.customtabs.html" class="hiddenlink" target="rightframe">android.support.customtabs</A><br>
    ++<A HREF="pkg_android.support.design.widget.html" class="hiddenlink" target="rightframe">android.support.design.widget</A><br>
    ++<A HREF="changes-summary.html#android.support.transition" class="hiddenlink" target="rightframe"><b>android.support.transition</b></A><br>
    ++<A HREF="pkg_android.support.v14.preference.html" class="hiddenlink" target="rightframe">android.support.v14.preference</A><br>
    ++<A HREF="pkg_android.support.v17.leanback.widget.html" class="hiddenlink" target="rightframe">android.support.v17.leanback.widget</A><br>
    ++<A HREF="pkg_android.support.v17.preference.html" class="hiddenlink" target="rightframe">android.support.v17.preference</A><br>
    ++<A HREF="pkg_android.support.v4.accessibilityservice.html" class="hiddenlink" target="rightframe">android.support.v4.accessibilityservice</A><br>
    ++<A HREF="pkg_android.support.v4.app.html" class="hiddenlink" target="rightframe">android.support.v4.app</A><br>
    ++<A HREF="pkg_android.support.v4.content.html" class="hiddenlink" target="rightframe">android.support.v4.content</A><br>
    ++<A HREF="pkg_android.support.v4.graphics.drawable.html" class="hiddenlink" target="rightframe">android.support.v4.graphics.drawable</A><br>
    ++<A HREF="pkg_android.support.v4.media.html" class="hiddenlink" target="rightframe">android.support.v4.media</A><br>
    ++<A HREF="pkg_android.support.v4.media.session.html" class="hiddenlink" target="rightframe">android.support.v4.media.session</A><br>
    ++<A HREF="pkg_android.support.v4.os.html" class="hiddenlink" target="rightframe">android.support.v4.os</A><br>
    ++<A HREF="changes-summary.html#android.support.v4.text.util" class="hiddenlink" target="rightframe"><b>android.support.v4.text.util</b></A><br>
    ++<A HREF="pkg_android.support.v4.util.html" class="hiddenlink" target="rightframe">android.support.v4.util</A><br>
    ++<A HREF="pkg_android.support.v4.view.html" class="hiddenlink" target="rightframe">android.support.v4.view</A><br>
    ++<A HREF="pkg_android.support.v4.view.accessibility.html" class="hiddenlink" target="rightframe">android.support.v4.view.accessibility</A><br>
    ++<A HREF="pkg_android.support.v4.widget.html" class="hiddenlink" target="rightframe">android.support.v4.widget</A><br>
    ++<A HREF="pkg_android.support.v7.app.html" class="hiddenlink" target="rightframe">android.support.v7.app</A><br>
    ++<A HREF="changes-summary.html#android.support.v7.appcompat" class="hiddenlink" target="rightframe"><strike>android.support.v7.appcompat</strike></A><br>
    ++<A HREF="pkg_android.support.v7.content.res.html" class="hiddenlink" target="rightframe">android.support.v7.content.res</A><br>
    ++<A HREF="pkg_android.support.v7.graphics.html" class="hiddenlink" target="rightframe">android.support.v7.graphics</A><br>
    ++<A HREF="pkg_android.support.v7.preference.html" class="hiddenlink" target="rightframe">android.support.v7.preference</A><br>
    ++<A HREF="changes-summary.html#android.support.v7.recyclerview" class="hiddenlink" target="rightframe"><strike>android.support.v7.recyclerview</strike></A><br>
    ++<A HREF="pkg_android.support.v7.util.html" class="hiddenlink" target="rightframe">android.support.v7.util</A><br>
    ++<A HREF="pkg_android.support.v7.widget.html" class="hiddenlink" target="rightframe">android.support.v7.widget</A><br>
    ++<A HREF="changes-summary.html#android.support.v8.renderscript" class="hiddenlink" target="rightframe"><strike>android.support.v8.renderscript</strike></A><br>
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    ++</script>
    ++<script type="text/javascript">
    ++  try {
    ++    var pageTracker = _gat._getTracker("UA-5831155-1");
    ++    pageTracker._setAllowAnchor(true);
    ++    pageTracker._initData();
    ++    pageTracker._trackPageview();
    ++  } catch(e) {}
    ++</script>
    ++</BODY>
    ++</HTML>
    +diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/packages_index_changes.html b/docs/html/sdk/support_api_diff/24.2.0/changes/packages_index_changes.html
    +new file mode 100644
    +index 0000000..f5f6425
    +--- /dev/null
    ++++ b/docs/html/sdk/support_api_diff/24.2.0/changes/packages_index_changes.html
    +@@ -0,0 +1,86 @@
    ++<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
    ++<HTML style="overflow:auto;">
    ++<HEAD>
    ++<meta name="generator" content="JDiff v1.1.0">
    ++<!-- Generated by the JDiff Javadoc doclet -->
    ++<!-- (http://www.jdiff.org) -->
    ++<meta name="description" content="JDiff is a Javadoc doclet which generates an HTML report of all the packages, classes, constructors, methods, and fields which have been removed, added or changed in any way, including their documentation, when two APIs are compared.">
    ++<meta name="keywords" content="diff, jdiff, javadiff, java diff, java difference, API difference, difference between two APIs, API diff, Javadoc, doclet">
    ++<TITLE>
    ++Package Changes Index
    ++</TITLE>
    ++<link href="../../../../assets/android-developer-docs.css" rel="stylesheet" type="text/css" />
    ++<link href="../stylesheet-jdiff.css" rel="stylesheet" type="text/css" />
    ++<noscript>
    ++<style type="text/css">
    ++body{overflow:auto;}
    ++#body-content{position:relative; top:0;}
    ++#doc-content{overflow:visible;border-left:3px solid #666;}
    ++#side-nav{padding:0;}
    ++#side-nav .toggle-list ul {display:block;}
    ++#resize-packages-nav{border-bottom:3px solid #666;}
    ++</style>
    ++</noscript>
    ++<style type="text/css">
    ++</style>
    ++</HEAD>
    ++<BODY class="gc-documentation" style="padding:12px;">
    ++<a NAME="topheader"></a>
    ++<table summary="Index for Packages" width="100%" class="jdiffIndex" border="0" cellspacing="0" cellpadding="0" style="padding-bottom:0;margin-bottom:0;">
    ++  <tr>
    ++  <th class="indexHeader">
    ++    Filter the Index:
    ++  </th>
    ++  </tr>
    ++  <tr>
    ++  <td class="indexText" style="line-height:1.3em;padding-left:2em;">
    ++<a href="packages_index_all.html" class="staysblack">All Packages</a>
    ++  <br>
    ++<A HREF="packages_index_removals.html" xclass="hiddenlink">Removals</A>
    ++  <br>
    ++<A HREF="packages_index_additions.html"xclass="hiddenlink">Additions</A>
    ++  <br>
    ++<b>Changes</b>
    ++  </td>
    ++  </tr>
    ++</table>
    ++<div id="indexTableCaption" style="background-color:#eee;padding:0 4px 0 4px;font-size:11px;margin-bottom:1em;">
    ++Listed as: <span style="color:#069"><strong>Added</strong></span>,  <span style="color:#069"><strike>Removed</strike></span>,  <span style="color:#069">Changed</span></font>
    ++</div>
    ++<br>
    ++<div id="indexTableEntries">
    ++<A NAME="A"></A>
    ++<A HREF="pkg_android.support.customtabs.html" class="hiddenlink" target="rightframe">android.support.customtabs</A><br>
    ++<A HREF="pkg_android.support.design.widget.html" class="hiddenlink" target="rightframe">android.support.design.widget</A><br>
    ++<A HREF="pkg_android.support.v14.preference.html" class="hiddenlink" target="rightframe">android.support.v14.preference</A><br>
    ++<A HREF="pkg_android.support.v17.leanback.widget.html" class="hiddenlink" target="rightframe">android.support.v17.leanback.widget</A><br>
    ++<A HREF="pkg_android.support.v17.preference.html" class="hiddenlink" target="rightframe">android.support.v17.preference</A><br>
    ++<A HREF="pkg_android.support.v4.accessibilityservice.html" class="hiddenlink" target="rightframe">android.support.v4.accessibilityservice</A><br>
    ++<A HREF="pkg_android.support.v4.app.html" class="hiddenlink" target="rightframe">android.support.v4.app</A><br>
    ++<A HREF="pkg_android.support.v4.content.html" class="hiddenlink" target="rightframe">android.support.v4.content</A><br>
    ++<A HREF="pkg_android.support.v4.graphics.drawable.html" class="hiddenlink" target="rightframe">android.support.v4.graphics.drawable</A><br>
    ++<A HREF="pkg_android.support.v4.media.html" class="hiddenlink" target="rightframe">android.support.v4.media</A><br>
    ++<A HREF="pkg_android.support.v4.media.session.html" class="hiddenlink" target="rightframe">android.support.v4.media.session</A><br>
    ++<A HREF="pkg_android.support.v4.os.html" class="hiddenlink" target="rightframe">android.support.v4.os</A><br>
    ++<A HREF="pkg_android.support.v4.util.html" class="hiddenlink" target="rightframe">android.support.v4.util</A><br>
    ++<A HREF="pkg_android.support.v4.view.html" class="hiddenlink" target="rightframe">android.support.v4.view</A><br>
    ++<A HREF="pkg_android.support.v4.view.accessibility.html" class="hiddenlink" target="rightframe">android.support.v4.view.accessibility</A><br>
    ++<A HREF="pkg_android.support.v4.widget.html" class="hiddenlink" target="rightframe">android.support.v4.widget</A><br>
    ++<A HREF="pkg_android.support.v7.app.html" class="hiddenlink" target="rightframe">android.support.v7.app</A><br>
    ++<A HREF="pkg_android.support.v7.content.res.html" class="hiddenlink" target="rightframe">android.support.v7.content.res</A><br>
    ++<A HREF="pkg_android.support.v7.graphics.html" class="hiddenlink" target="rightframe">android.support.v7.graphics</A><br>
    ++<A HREF="pkg_android.support.v7.preference.html" class="hiddenlink" target="rightframe">android.support.v7.preference</A><br>
    ++<A HREF="pkg_android.support.v7.util.html" class="hiddenlink" target="rightframe">android.support.v7.util</A><br>
    ++<A HREF="pkg_android.support.v7.widget.html" class="hiddenlink" target="rightframe">android.support.v7.widget</A><br>
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    ++</script>
    ++<script type="text/javascript">
    ++  try {
    ++    var pageTracker = _gat._getTracker("UA-5831155-1");
    ++    pageTracker._setAllowAnchor(true);
    ++    pageTracker._initData();
    ++    pageTracker._trackPageview();
    ++  } catch(e) {}
    ++</script>
    ++</BODY>
    ++</HTML>
    +diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/packages_index_removals.html b/docs/html/sdk/support_api_diff/24.2.0/changes/packages_index_removals.html
    +new file mode 100644
    +index 0000000..ce5ca58
    +--- /dev/null
    ++++ b/docs/html/sdk/support_api_diff/24.2.0/changes/packages_index_removals.html
    +@@ -0,0 +1,67 @@
    ++<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
    ++<HTML style="overflow:auto;">
    ++<HEAD>
    ++<meta name="generator" content="JDiff v1.1.0">
    ++<!-- Generated by the JDiff Javadoc doclet -->
    ++<!-- (http://www.jdiff.org) -->
    ++<meta name="description" content="JDiff is a Javadoc doclet which generates an HTML report of all the packages, classes, constructors, methods, and fields which have been removed, added or changed in any way, including their documentation, when two APIs are compared.">
    ++<meta name="keywords" content="diff, jdiff, javadiff, java diff, java difference, API difference, difference between two APIs, API diff, Javadoc, doclet">
    ++<TITLE>
    ++Package Removals Index
    ++</TITLE>
    ++<link href="../../../../assets/android-developer-docs.css" rel="stylesheet" type="text/css" />
    ++<link href="../stylesheet-jdiff.css" rel="stylesheet" type="text/css" />
    ++<noscript>
    ++<style type="text/css">
    ++body{overflow:auto;}
    ++#body-content{position:relative; top:0;}
    ++#doc-content{overflow:visible;border-left:3px solid #666;}
    ++#side-nav{padding:0;}
    ++#side-nav .toggle-list ul {display:block;}
    ++#resize-packages-nav{border-bottom:3px solid #666;}
    ++</style>
    ++</noscript>
    ++<style type="text/css">
    ++</style>
    ++</HEAD>
    ++<BODY class="gc-documentation" style="padding:12px;">
    ++<a NAME="topheader"></a>
    ++<table summary="Index for Packages" width="100%" class="jdiffIndex" border="0" cellspacing="0" cellpadding="0" style="padding-bottom:0;margin-bottom:0;">
    ++  <tr>
    ++  <th class="indexHeader">
    ++    Filter the Index:
    ++  </th>
    ++  </tr>
    ++  <tr>
    ++  <td class="indexText" style="line-height:1.3em;padding-left:2em;">
    ++<a href="packages_index_all.html" class="staysblack">All Packages</a>
    ++  <br>
    ++<b>Removals</b>
    ++  <br>
    ++<A HREF="packages_index_additions.html"xclass="hiddenlink">Additions</A>
    ++  <br>
    ++<A HREF="packages_index_changes.html"xclass="hiddenlink">Changes</A>
    ++  </td>
    ++  </tr>
    ++</table>
    ++<div id="indexTableCaption" style="background-color:#eee;padding:0 4px 0 4px;font-size:11px;margin-bottom:1em;">
    ++Listed as: <span style="color:#069"><strong>Added</strong></span>,  <span style="color:#069"><strike>Removed</strike></span>,  <span style="color:#069">Changed</span></font>
    ++</div>
    ++<br>
    ++<div id="indexTableEntries">
    ++<A NAME="A"></A>
    ++<A HREF="changes-summary.html#android.support.v7.appcompat" class="hiddenlink" target="rightframe"><strike>android.support.v7.appcompat</strike></A><br>
    ++<A HREF="changes-summary.html#android.support.v7.recyclerview" class="hiddenlink" target="rightframe"><strike>android.support.v7.recyclerview</strike></A><br>
    ++<A HREF="changes-summary.html#android.support.v8.renderscript" class="hiddenlink" target="rightframe"><strike>android.support.v8.renderscript</strike></A><br>
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    ++</script>
    ++<script type="text/javascript">
    ++  try {
    ++    var pageTracker = _gat._getTracker("UA-5831155-1");
    ++    pageTracker._setAllowAnchor(true);
    ++    pageTracker._initData();
    ++    pageTracker._trackPageview();
    ++  } catch(e) {}
    ++</script>
    ++</BODY>
    ++</HTML>
    +diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/pkg_android.support.customtabs.html b/docs/html/sdk/support_api_diff/24.2.0/changes/pkg_android.support.customtabs.html
    +new file mode 100644
    +index 0000000..45a31ff
    +--- /dev/null
    ++++ b/docs/html/sdk/support_api_diff/24.2.0/changes/pkg_android.support.customtabs.html
    +@@ -0,0 +1,133 @@
    ++<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
    ++<HTML style="overflow:auto;">
    ++<HEAD>
    ++<meta name="generator" content="JDiff v1.1.0">
    ++<!-- Generated by the JDiff Javadoc doclet -->
    ++<!-- (http://www.jdiff.org) -->
    ++<meta name="description" content="JDiff is a Javadoc doclet which generates an HTML report of all the packages, classes, constructors, methods, and fields which have been removed, added or changed in any way, including their documentation, when two APIs are compared.">
    ++<meta name="keywords" content="diff, jdiff, javadiff, java diff, java difference, API difference, difference between two APIs, API diff, Javadoc, doclet">
    ++<TITLE>
    ++android.support.customtabs
    ++</TITLE>
    ++<link href="../../../../assets/android-developer-docs.css" rel="stylesheet" type="text/css" />
    ++<link href="../stylesheet-jdiff.css" rel="stylesheet" type="text/css" />
    ++<noscript>
    ++<style type="text/css">
    ++body{overflow:auto;}
    ++#body-content{position:relative; top:0;}
    ++#doc-content{overflow:visible;border-left:3px solid #666;}
    ++#side-nav{padding:0;}
    ++#side-nav .toggle-list ul {display:block;}
    ++#resize-packages-nav{border-bottom:3px solid #666;}
    ++</style>
    ++</noscript>
    ++<style type="text/css">
    ++</style>
    ++</HEAD>
    ++<BODY>
    ++<!-- Start of nav bar -->
    ++<a name="top"></a>
    ++<div id="header" style="margin-bottom:0;padding-bottom:0;">
    ++<div id="headerLeft">
    ++<a href="../../../../index.html" tabindex="-1" target="_top"><img src="../../../../assets/images/bg_logo.png" alt="Android Developers" /></a>
    ++</div>
    ++  <div id="headerRight">
    ++  <div id="headerLinks">
    ++<!-- <img src="/assets/images/icon_world.jpg" alt="" /> -->
    ++<span class="text">
    ++<!-- &nbsp;<a href="#">English</a> | -->
    ++<nobr><a href="http://developer.android.com" target="_top">Android Developers</a> | <a href="http://www.android.com" target="_top">Android.com</a></nobr>
    ++</span>
    ++</div>
    ++  <div class="and-diff-id" style="margin-top:6px;margin-right:8px;">
    ++    <table class="diffspectable">
    ++      <tr>
    ++        <td colspan="2" class="diffspechead">API Diff Specification</td>
    ++      </tr>
    ++      <tr>
    ++        <td class="diffspec" style="padding-top:.25em">To Level:</td>
    ++        <td class="diffvaluenew" style="padding-top:.25em">24.2.0</td>
    ++      </tr>
    ++      <tr>
    ++        <td class="diffspec">From Level:</td>
    ++        <td class="diffvalueold">24.1.0</td>
    ++      </tr>
    ++      <tr>
    ++        <td class="diffspec">Generated</td>
    ++        <td class="diffvalue">2016.08.16 14:03</td>
    ++      </tr>
    ++    </table>
    ++    </div><!-- End and-diff-id -->
    ++  <div class="and-diff-id" style="margin-right:8px;">
    ++    <table class="diffspectable">
    ++      <tr>
    ++        <td class="diffspec" colspan="2"><a href="jdiff_statistics.html">Statistics</a>
    ++      </tr>
    ++    </table>
    ++  </div> <!-- End and-diff-id -->
    ++  </div> <!-- End headerRight -->
    ++  </div> <!-- End header -->
    ++<div id="body-content" xstyle="padding:12px;padding-right:18px;">
    ++<div id="doc-content" style="position:relative;">
    ++<div id="mainBodyFluid">
    ++<H2>
    ++Package <A HREF="../../../../reference/android/support/customtabs/package-summary.html" target="_top"><font size="+1"><code>android.support.customtabs</code></font></A>
    ++</H2>
    ++<p>
    ++<a NAME="Changed"></a>
    ++<TABLE summary="Changed Classes" WIDTH="100%">
    ++<TR>
    ++  <TH VALIGN="TOP" COLSPAN=2>Changed Classes</FONT></TD>
    ++</TH>
    ++<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    ++  <TD VALIGN="TOP" WIDTH="25%">
    ++  <A NAME="CustomTabsIntent"></A>
    ++  <nobr><A HREF="android.support.customtabs.CustomTabsIntent.html">CustomTabsIntent</A></nobr>
    ++  </TD>
    ++  <TD>&nbsp;</TD>
    ++</TR>
    ++<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    ++  <TD VALIGN="TOP" WIDTH="25%">
    ++  <A NAME="CustomTabsIntent.Builder"></A>
    ++  <nobr><A HREF="android.support.customtabs.CustomTabsIntent.Builder.html">CustomTabsIntent.Builder</A></nobr>
    ++  </TD>
    ++  <TD>&nbsp;</TD>
    ++</TR>
    ++<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    ++  <TD VALIGN="TOP" WIDTH="25%">
    ++  <A NAME="CustomTabsSession"></A>
    ++  <nobr><A HREF="android.support.customtabs.CustomTabsSession.html">CustomTabsSession</A></nobr>
    ++  </TD>
    ++  <TD>&nbsp;</TD>
    ++</TR>
    ++</TABLE>
    ++&nbsp;
    ++      </div>	
    ++      <div id="footer">
    ++        <div id="copyright">
    ++        Except as noted, this content is licensed under 
    ++        <a href="http://creativecommons.org/licenses/by/2.5/"> Creative Commons Attribution 2.5</a>.
    ++        For details and restrictions, see the <a href="/license.html">Content License</a>.
    ++        </div>
    ++      <div id="footerlinks">
    ++      <p>
    ++        <a href="http://www.android.com/terms.html">Site Terms of Service</a> -
    ++        <a href="http://www.android.com/privacy.html">Privacy Policy</a> -
    ++        <a href="http://www.android.com/branding.html">Brand Guidelines</a>
    ++      </p>
    ++    </div>
    ++    </div> <!-- end footer -->
    ++    </div><!-- end doc-content -->
    ++    </div> <!-- end body-content --> 
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    ++</script>
    ++<script type="text/javascript">
    ++  try {
    ++    var pageTracker = _gat._getTracker("UA-5831155-1");
    ++    pageTracker._setAllowAnchor(true);
    ++    pageTracker._initData();
    ++    pageTracker._trackPageview();
    ++  } catch(e) {}
    ++</script>
    ++</BODY>
    ++</HTML>
    +diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/pkg_android.support.design.widget.html b/docs/html/sdk/support_api_diff/24.2.0/changes/pkg_android.support.design.widget.html
    +new file mode 100644
    +index 0000000..a311b48
    +--- /dev/null
    ++++ b/docs/html/sdk/support_api_diff/24.2.0/changes/pkg_android.support.design.widget.html
    +@@ -0,0 +1,175 @@
    ++<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
    ++<HTML style="overflow:auto;">
    ++<HEAD>
    ++<meta name="generator" content="JDiff v1.1.0">
    ++<!-- Generated by the JDiff Javadoc doclet -->
    ++<!-- (http://www.jdiff.org) -->
    ++<meta name="description" content="JDiff is a Javadoc doclet which generates an HTML report of all the packages, classes, constructors, methods, and fields which have been removed, added or changed in any way, including their documentation, when two APIs are compared.">
    ++<meta name="keywords" content="diff, jdiff, javadiff, java diff, java difference, API difference, difference between two APIs, API diff, Javadoc, doclet">
    ++<TITLE>
    ++android.support.design.widget
    ++</TITLE>
    ++<link href="../../../../assets/android-developer-docs.css" rel="stylesheet" type="text/css" />
    ++<link href="../stylesheet-jdiff.css" rel="stylesheet" type="text/css" />
    ++<noscript>
    ++<style type="text/css">
    ++body{overflow:auto;}
    ++#body-content{position:relative; top:0;}
    ++#doc-content{overflow:visible;border-left:3px solid #666;}
    ++#side-nav{padding:0;}
    ++#side-nav .toggle-list ul {display:block;}
    ++#resize-packages-nav{border-bottom:3px solid #666;}
    ++</style>
    ++</noscript>
    ++<style type="text/css">
    ++</style>
    ++</HEAD>
    ++<BODY>
    ++<!-- Start of nav bar -->
    ++<a name="top"></a>
    ++<div id="header" style="margin-bottom:0;padding-bottom:0;">
    ++<div id="headerLeft">
    ++<a href="../../../../index.html" tabindex="-1" target="_top"><img src="../../../../assets/images/bg_logo.png" alt="Android Developers" /></a>
    ++</div>
    ++  <div id="headerRight">
    ++  <div id="headerLinks">
    ++<!-- <img src="/assets/images/icon_world.jpg" alt="" /> -->
    ++<span class="text">
    ++<!-- &nbsp;<a href="#">English</a> | -->
    ++<nobr><a href="http://developer.android.com" target="_top">Android Developers</a> | <a href="http://www.android.com" target="_top">Android.com</a></nobr>
    ++</span>
    ++</div>
    ++  <div class="and-diff-id" style="margin-top:6px;margin-right:8px;">
    ++    <table class="diffspectable">
    ++      <tr>
    ++        <td colspan="2" class="diffspechead">API Diff Specification</td>
    ++      </tr>
    ++      <tr>
    ++        <td class="diffspec" style="padding-top:.25em">To Level:</td>
    ++        <td class="diffvaluenew" style="padding-top:.25em">24.2.0</td>
    ++      </tr>
    ++      <tr>
    ++        <td class="diffspec">From Level:</td>
    ++        <td class="diffvalueold">24.1.0</td>
    ++      </tr>
    ++      <tr>
    ++        <td class="diffspec">Generated</td>
    ++        <td class="diffvalue">2016.08.16 14:03</td>
    ++      </tr>
    ++    </table>
    ++    </div><!-- End and-diff-id -->
    ++  <div class="and-diff-id" style="margin-right:8px;">
    ++    <table class="diffspectable">
    ++      <tr>
    ++        <td class="diffspec" colspan="2"><a href="jdiff_statistics.html">Statistics</a>
    ++      </tr>
    ++    </table>
    ++  </div> <!-- End and-diff-id -->
    ++  </div> <!-- End headerRight -->
    ++  </div> <!-- End header -->
    ++<div id="body-content" xstyle="padding:12px;padding-right:18px;">
    ++<div id="doc-content" style="position:relative;">
    ++<div id="mainBodyFluid">
    ++<H2>
    ++Package <A HREF="../../../../reference/android/support/design/widget/package-summary.html" target="_top"><font size="+1"><code>android.support.design.widget</code></font></A>
    ++</H2>
    ++<p>
    ++<a NAME="Changed"></a>
    ++<TABLE summary="Changed Classes" WIDTH="100%">
    ++<TR>
    ++  <TH VALIGN="TOP" COLSPAN=2>Changed Classes</FONT></TD>
    ++</TH>
    ++<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    ++  <TD VALIGN="TOP" WIDTH="25%">
    ++  <A NAME="AppBarLayout.ScrollingViewBehavior"></A>
    ++  <nobr><A HREF="android.support.design.widget.AppBarLayout.ScrollingViewBehavior.html">AppBarLayout.ScrollingViewBehavior</A></nobr>
    ++  </TD>
    ++  <TD>&nbsp;</TD>
    ++</TR>
    ++<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    ++  <TD VALIGN="TOP" WIDTH="25%">
    ++  <A NAME="BottomSheetBehavior"></A>
    ++  <nobr><A HREF="android.support.design.widget.BottomSheetBehavior.html">BottomSheetBehavior</A></nobr>
    ++  </TD>
    ++  <TD>&nbsp;</TD>
    ++</TR>
    ++<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    ++  <TD VALIGN="TOP" WIDTH="25%">
    ++  <A NAME="CollapsingToolbarLayout"></A>
    ++  <nobr><A HREF="android.support.design.widget.CollapsingToolbarLayout.html">CollapsingToolbarLayout</A></nobr>
    ++  </TD>
    ++  <TD>&nbsp;</TD>
    ++</TR>
    ++<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    ++  <TD VALIGN="TOP" WIDTH="25%">
    ++  <A NAME="CoordinatorLayout"></A>
    ++  <nobr><A HREF="android.support.design.widget.CoordinatorLayout.html">CoordinatorLayout</A></nobr>
    ++  </TD>
    ++  <TD>&nbsp;</TD>
    ++</TR>
    ++<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    ++  <TD VALIGN="TOP" WIDTH="25%">
    ++  <A NAME="CoordinatorLayout.Behavior"></A>
    ++  <nobr><A HREF="android.support.design.widget.CoordinatorLayout.Behavior.html">CoordinatorLayout.Behavior</A></nobr>
    ++  </TD>
    ++  <TD>&nbsp;</TD>
    ++</TR>
    ++<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    ++  <TD VALIGN="TOP" WIDTH="25%">
    ++  <A NAME="CoordinatorLayout.LayoutParams"></A>
    ++  <nobr><A HREF="android.support.design.widget.CoordinatorLayout.LayoutParams.html">CoordinatorLayout.LayoutParams</A></nobr>
    ++  </TD>
    ++  <TD>&nbsp;</TD>
    ++</TR>
    ++<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    ++  <TD VALIGN="TOP" WIDTH="25%">
    ++  <A NAME="FloatingActionButton.Behavior"></A>
    ++  <nobr><A HREF="android.support.design.widget.FloatingActionButton.Behavior.html">FloatingActionButton.Behavior</A></nobr>
    ++  </TD>
    ++  <TD>&nbsp;</TD>
    ++</TR>
    ++<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    ++  <TD VALIGN="TOP" WIDTH="25%">
    ++  <A NAME="TabLayout"></A>
    ++  <nobr><A HREF="android.support.design.widget.TabLayout.html">TabLayout</A></nobr>
    ++  </TD>
    ++  <TD>&nbsp;</TD>
    ++</TR>
    ++<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    ++  <TD VALIGN="TOP" WIDTH="25%">
    ++  <A NAME="TextInputLayout"></A>
    ++  <nobr><A HREF="android.support.design.widget.TextInputLayout.html">TextInputLayout</A></nobr>
    ++  </TD>
    ++  <TD>&nbsp;</TD>
    ++</TR>
    ++</TABLE>
    ++&nbsp;
    ++      </div>	
    ++      <div id="footer">
    ++        <div id="copyright">
    ++        Except as noted, this content is licensed under 
    ++        <a href="http://creativecommons.org/licenses/by/2.5/"> Creative Commons Attribution 2.5</a>.
    ++        For details and restrictions, see the <a href="/license.html">Content License</a>.
    ++        </div>
    ++      <div id="footerlinks">
    ++      <p>
    ++        <a href="http://www.android.com/terms.html">Site Terms of Service</a> -
    ++        <a href="http://www.android.com/privacy.html">Privacy Policy</a> -
    ++        <a href="http://www.android.com/branding.html">Brand Guidelines</a>
    ++      </p>
    ++    </div>
    ++    </div> <!-- end footer -->
    ++    </div><!-- end doc-content -->
    ++    </div> <!-- end body-content --> 
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    ++</script>
    ++<script type="text/javascript">
    ++  try {
    ++    var pageTracker = _gat._getTracker("UA-5831155-1");
    ++    pageTracker._setAllowAnchor(true);
    ++    pageTracker._initData();
    ++    pageTracker._trackPageview();
    ++  } catch(e) {}
    ++</script>
    ++</BODY>
    ++</HTML>
    +diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/pkg_android.support.v14.preference.html b/docs/html/sdk/support_api_diff/24.2.0/changes/pkg_android.support.v14.preference.html
    +new file mode 100644
    +index 0000000..f24be00
    +--- /dev/null
    ++++ b/docs/html/sdk/support_api_diff/24.2.0/changes/pkg_android.support.v14.preference.html
    +@@ -0,0 +1,119 @@
    ++<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
    ++<HTML style="overflow:auto;">
    ++<HEAD>
    ++<meta name="generator" content="JDiff v1.1.0">
    ++<!-- Generated by the JDiff Javadoc doclet -->
    ++<!-- (http://www.jdiff.org) -->
    ++<meta name="description" content="JDiff is a Javadoc doclet which generates an HTML report of all the packages, classes, constructors, methods, and fields which have been removed, added or changed in any way, including their documentation, when two APIs are compared.">
    ++<meta name="keywords" content="diff, jdiff, javadiff, java diff, java difference, API difference, difference between two APIs, API diff, Javadoc, doclet">
    ++<TITLE>
    ++android.support.v14.preference
    ++</TITLE>
    ++<link href="../../../../assets/android-developer-docs.css" rel="stylesheet" type="text/css" />
    ++<link href="../stylesheet-jdiff.css" rel="stylesheet" type="text/css" />
    ++<noscript>
    ++<style type="text/css">
    ++body{overflow:auto;}
    ++#body-content{position:relative; top:0;}
    ++#doc-content{overflow:visible;border-left:3px solid #666;}
    ++#side-nav{padding:0;}
    ++#side-nav .toggle-list ul {display:block;}
    ++#resize-packages-nav{border-bottom:3px solid #666;}
    ++</style>
    ++</noscript>
    ++<style type="text/css">
    ++</style>
    ++</HEAD>
    ++<BODY>
    ++<!-- Start of nav bar -->
    ++<a name="top"></a>
    ++<div id="header" style="margin-bottom:0;padding-bottom:0;">
    ++<div id="headerLeft">
    ++<a href="../../../../index.html" tabindex="-1" target="_top"><img src="../../../../assets/images/bg_logo.png" alt="Android Developers" /></a>
    ++</div>
    ++  <div id="headerRight">
    ++  <div id="headerLinks">
    ++<!-- <img src="/assets/images/icon_world.jpg" alt="" /> -->
    ++<span class="text">
    ++<!-- &nbsp;<a href="#">English</a> | -->
    ++<nobr><a href="http://developer.android.com" target="_top">Android Developers</a> | <a href="http://www.android.com" target="_top">Android.com</a></nobr>
    ++</span>
    ++</div>
    ++  <div class="and-diff-id" style="margin-top:6px;margin-right:8px;">
    ++    <table class="diffspectable">
    ++      <tr>
    ++        <td colspan="2" class="diffspechead">API Diff Specification</td>
    ++      </tr>
    ++      <tr>
    ++        <td class="diffspec" style="padding-top:.25em">To Level:</td>
    ++        <td class="diffvaluenew" style="padding-top:.25em">24.2.0</td>
    ++      </tr>
    ++      <tr>
    ++        <td class="diffspec">From Level:</td>
    ++        <td class="diffvalueold">24.1.0</td>
    ++      </tr>
    ++      <tr>
    ++        <td class="diffspec">Generated</td>
    ++        <td class="diffvalue">2016.08.16 14:03</td>
    ++      </tr>
    ++    </table>
    ++    </div><!-- End and-diff-id -->
    ++  <div class="and-diff-id" style="margin-right:8px;">
    ++    <table class="diffspectable">
    ++      <tr>
    ++        <td class="diffspec" colspan="2"><a href="jdiff_statistics.html">Statistics</a>
    ++      </tr>
    ++    </table>
    ++  </div> <!-- End and-diff-id -->
    ++  </div> <!-- End headerRight -->
    ++  </div> <!-- End header -->
    ++<div id="body-content" xstyle="padding:12px;padding-right:18px;">
    ++<div id="doc-content" style="position:relative;">
    ++<div id="mainBodyFluid">
    ++<H2>
    ++Package <A HREF="../../../../reference/android/support/v14/preference/package-summary.html" target="_top"><font size="+1"><code>android.support.v14.preference</code></font></A>
    ++</H2>
    ++<p>
    ++<a NAME="Changed"></a>
    ++<TABLE summary="Changed Classes" WIDTH="100%">
    ++<TR>
    ++  <TH VALIGN="TOP" COLSPAN=2>Changed Classes</FONT></TD>
    ++</TH>
    ++<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    ++  <TD VALIGN="TOP" WIDTH="25%">
    ++  <A NAME="PreferenceFragment"></A>
    ++  <nobr><A HREF="android.support.v14.preference.PreferenceFragment.html">PreferenceFragment</A></nobr>
    ++  </TD>
    ++  <TD>&nbsp;</TD>
    ++</TR>
    ++</TABLE>
    ++&nbsp;
    ++      </div>	
    ++      <div id="footer">
    ++        <div id="copyright">
    ++        Except as noted, this content is licensed under 
    ++        <a href="http://creativecommons.org/licenses/by/2.5/"> Creative Commons Attribution 2.5</a>.
    ++        For details and restrictions, see the <a href="/license.html">Content License</a>.
    ++        </div>
    ++      <div id="footerlinks">
    ++      <p>
    ++        <a href="http://www.android.com/terms.html">Site Terms of Service</a> -
    ++        <a href="http://www.android.com/privacy.html">Privacy Policy</a> -
    ++        <a href="http://www.android.com/branding.html">Brand Guidelines</a>
    ++      </p>
    ++    </div>
    ++    </div> <!-- end footer -->
    ++    </div><!-- end doc-content -->
    ++    </div> <!-- end body-content --> 
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    ++</script>
    ++<script type="text/javascript">
    ++  try {
    ++    var pageTracker = _gat._getTracker("UA-5831155-1");
    ++    pageTracker._setAllowAnchor(true);
    ++    pageTracker._initData();
    ++    pageTracker._trackPageview();
    ++  } catch(e) {}
    ++</script>
    ++</BODY>
    ++</HTML>
    +diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/pkg_android.support.v17.leanback.widget.html b/docs/html/sdk/support_api_diff/24.2.0/changes/pkg_android.support.v17.leanback.widget.html
    +new file mode 100644
    +index 0000000..c07a487
    +--- /dev/null
    ++++ b/docs/html/sdk/support_api_diff/24.2.0/changes/pkg_android.support.v17.leanback.widget.html
    +@@ -0,0 +1,133 @@
    ++<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
    ++<HTML style="overflow:auto;">
    ++<HEAD>
    ++<meta name="generator" content="JDiff v1.1.0">
    ++<!-- Generated by the JDiff Javadoc doclet -->
    ++<!-- (http://www.jdiff.org) -->
    ++<meta name="description" content="JDiff is a Javadoc doclet which generates an HTML report of all the packages, classes, constructors, methods, and fields which have been removed, added or changed in any way, including their documentation, when two APIs are compared.">
    ++<meta name="keywords" content="diff, jdiff, javadiff, java diff, java difference, API difference, difference between two APIs, API diff, Javadoc, doclet">
    ++<TITLE>
    ++android.support.v17.leanback.widget
    ++</TITLE>
    ++<link href="../../../../assets/android-developer-docs.css" rel="stylesheet" type="text/css" />
    ++<link href="../stylesheet-jdiff.css" rel="stylesheet" type="text/css" />
    ++<noscript>
    ++<style type="text/css">
    ++body{overflow:auto;}
    ++#body-content{position:relative; top:0;}
    ++#doc-content{overflow:visible;border-left:3px solid #666;}
    ++#side-nav{padding:0;}
    ++#side-nav .toggle-list ul {display:block;}
    ++#resize-packages-nav{border-bottom:3px solid #666;}
    ++</style>
    ++</noscript>
    ++<style type="text/css">
    ++</style>
    ++</HEAD>
    ++<BODY>
    ++<!-- Start of nav bar -->
    ++<a name="top"></a>
    ++<div id="header" style="margin-bottom:0;padding-bottom:0;">
    ++<div id="headerLeft">
    ++<a href="../../../../index.html" tabindex="-1" target="_top"><img src="../../../../assets/images/bg_logo.png" alt="Android Developers" /></a>
    ++</div>
    ++  <div id="headerRight">
    ++  <div id="headerLinks">
    ++<!-- <img src="/assets/images/icon_world.jpg" alt="" /> -->
    ++<span class="text">
    ++<!-- &nbsp;<a href="#">English</a> | -->
    ++<nobr><a href="http://developer.android.com" target="_top">Android Developers</a> | <a href="http://www.android.com" target="_top">Android.com</a></nobr>
    ++</span>
    ++</div>
    ++  <div class="and-diff-id" style="margin-top:6px;margin-right:8px;">
    ++    <table class="diffspectable">
    ++      <tr>
    ++        <td colspan="2" class="diffspechead">API Diff Specification</td>
    ++      </tr>
    ++      <tr>
    ++        <td class="diffspec" style="padding-top:.25em">To Level:</td>
    ++        <td class="diffvaluenew" style="padding-top:.25em">24.2.0</td>
    ++      </tr>
    ++      <tr>
    ++        <td class="diffspec">From Level:</td>
    ++        <td class="diffvalueold">24.1.0</td>
    ++      </tr>
    ++      <tr>
    ++        <td class="diffspec">Generated</td>
    ++        <td class="diffvalue">2016.08.16 14:03</td>
    ++      </tr>
    ++    </table>
    ++    </div><!-- End and-diff-id -->
    ++  <div class="and-diff-id" style="margin-right:8px;">
    ++    <table class="diffspectable">
    ++      <tr>
    ++        <td class="diffspec" colspan="2"><a href="jdiff_statistics.html">Statistics</a>
    ++      </tr>
    ++    </table>
    ++  </div> <!-- End and-diff-id -->
    ++  </div> <!-- End headerRight -->
    ++  </div> <!-- End header -->
    ++<div id="body-content" xstyle="padding:12px;padding-right:18px;">
    ++<div id="doc-content" style="position:relative;">
    ++<div id="mainBodyFluid">
    ++<H2>
    ++Package <A HREF="../../../../reference/android/support/v17/leanback/widget/package-summary.html" target="_top"><font size="+1"><code>android.support.v17.leanback.widget</code></font></A>
    ++</H2>
    ++<p>
    ++<a NAME="Changed"></a>
    ++<TABLE summary="Changed Classes" WIDTH="100%">
    ++<TR>
    ++  <TH VALIGN="TOP" COLSPAN=2>Changed Classes</FONT></TD>
    ++</TH>
    ++<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    ++  <TD VALIGN="TOP" WIDTH="25%">
    ++  <A NAME="AbstractMediaItemPresenter"></A>
    ++  <nobr><A HREF="android.support.v17.leanback.widget.AbstractMediaItemPresenter.html">AbstractMediaItemPresenter</A></nobr>
    ++  </TD>
    ++  <TD>&nbsp;</TD>
    ++</TR>
    ++<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    ++  <TD VALIGN="TOP" WIDTH="25%">
    ++  <A NAME="AbstractMediaItemPresenter.ViewHolder"></A>
    ++  <nobr><A HREF="android.support.v17.leanback.widget.AbstractMediaItemPresenter.ViewHolder.html">AbstractMediaItemPresenter.<br>ViewHolder</A></nobr>
    ++  </TD>
    ++  <TD>&nbsp;</TD>
    ++</TR>
    ++<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    ++  <TD VALIGN="TOP" WIDTH="25%">
    ++  <A NAME="ObjectAdapter"></A>
    ++  <nobr><A HREF="android.support.v17.leanback.widget.ObjectAdapter.html">ObjectAdapter</A></nobr>
    ++  </TD>
    ++  <TD>&nbsp;</TD>
    ++</TR>
    ++</TABLE>
    ++&nbsp;
    ++      </div>	
    ++      <div id="footer">
    ++        <div id="copyright">
    ++        Except as noted, this content is licensed under 
    ++        <a href="http://creativecommons.org/licenses/by/2.5/"> Creative Commons Attribution 2.5</a>.
    ++        For details and restrictions, see the <a href="/license.html">Content License</a>.
    ++        </div>
    ++      <div id="footerlinks">
    ++      <p>
    ++        <a href="http://www.android.com/terms.html">Site Terms of Service</a> -
    ++        <a href="http://www.android.com/privacy.html">Privacy Policy</a> -
    ++        <a href="http://www.android.com/branding.html">Brand Guidelines</a>
    ++      </p>
    ++    </div>
    ++    </div> <!-- end footer -->
    ++    </div><!-- end doc-content -->
    ++    </div> <!-- end body-content --> 
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    ++</script>
    ++<script type="text/javascript">
    ++  try {
    ++    var pageTracker = _gat._getTracker("UA-5831155-1");
    ++    pageTracker._setAllowAnchor(true);
    ++    pageTracker._initData();
    ++    pageTracker._trackPageview();
    ++  } catch(e) {}
    ++</script>
    ++</BODY>
    ++</HTML>
    +diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/pkg_android.support.v17.preference.html b/docs/html/sdk/support_api_diff/24.2.0/changes/pkg_android.support.v17.preference.html
    +new file mode 100644
    +index 0000000..c61d79d
    +--- /dev/null
    ++++ b/docs/html/sdk/support_api_diff/24.2.0/changes/pkg_android.support.v17.preference.html
    +@@ -0,0 +1,119 @@
    ++<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
    ++<HTML style="overflow:auto;">
    ++<HEAD>
    ++<meta name="generator" content="JDiff v1.1.0">
    ++<!-- Generated by the JDiff Javadoc doclet -->
    ++<!-- (http://www.jdiff.org) -->
    ++<meta name="description" content="JDiff is a Javadoc doclet which generates an HTML report of all the packages, classes, constructors, methods, and fields which have been removed, added or changed in any way, including their documentation, when two APIs are compared.">
    ++<meta name="keywords" content="diff, jdiff, javadiff, java diff, java difference, API difference, difference between two APIs, API diff, Javadoc, doclet">
    ++<TITLE>
    ++android.support.v17.preference
    ++</TITLE>
    ++<link href="../../../../assets/android-developer-docs.css" rel="stylesheet" type="text/css" />
    ++<link href="../stylesheet-jdiff.css" rel="stylesheet" type="text/css" />
    ++<noscript>
    ++<style type="text/css">
    ++body{overflow:auto;}
    ++#body-content{position:relative; top:0;}
    ++#doc-content{overflow:visible;border-left:3px solid #666;}
    ++#side-nav{padding:0;}
    ++#side-nav .toggle-list ul {display:block;}
    ++#resize-packages-nav{border-bottom:3px solid #666;}
    ++</style>
    ++</noscript>
    ++<style type="text/css">
    ++</style>
    ++</HEAD>
    ++<BODY>
    ++<!-- Start of nav bar -->
    ++<a name="top"></a>
    ++<div id="header" style="margin-bottom:0;padding-bottom:0;">
    ++<div id="headerLeft">
    ++<a href="../../../../index.html" tabindex="-1" target="_top"><img src="../../../../assets/images/bg_logo.png" alt="Android Developers" /></a>
    ++</div>
    ++  <div id="headerRight">
    ++  <div id="headerLinks">
    ++<!-- <img src="/assets/images/icon_world.jpg" alt="" /> -->
    ++<span class="text">
    ++<!-- &nbsp;<a href="#">English</a> | -->
    ++<nobr><a href="http://developer.android.com" target="_top">Android Developers</a> | <a href="http://www.android.com" target="_top">Android.com</a></nobr>
    ++</span>
    ++</div>
    ++  <div class="and-diff-id" style="margin-top:6px;margin-right:8px;">
    ++    <table class="diffspectable">
    ++      <tr>
    ++        <td colspan="2" class="diffspechead">API Diff Specification</td>
    ++      </tr>
    ++      <tr>
    ++        <td class="diffspec" style="padding-top:.25em">To Level:</td>
    ++        <td class="diffvaluenew" style="padding-top:.25em">24.2.0</td>
    ++      </tr>
    ++      <tr>
    ++        <td class="diffspec">From Level:</td>
    ++        <td class="diffvalueold">24.1.0</td>
    ++      </tr>
    ++      <tr>
    ++        <td class="diffspec">Generated</td>
    ++        <td class="diffvalue">2016.08.16 14:03</td>
    ++      </tr>
    ++    </table>
    ++    </div><!-- End and-diff-id -->
    ++  <div class="and-diff-id" style="margin-right:8px;">
    ++    <table class="diffspectable">
    ++      <tr>
    ++        <td class="diffspec" colspan="2"><a href="jdiff_statistics.html">Statistics</a>
    ++      </tr>
    ++    </table>
    ++  </div> <!-- End and-diff-id -->
    ++  </div> <!-- End headerRight -->
    ++  </div> <!-- End header -->
    ++<div id="body-content" xstyle="padding:12px;padding-right:18px;">
    ++<div id="doc-content" style="position:relative;">
    ++<div id="mainBodyFluid">
    ++<H2>
    ++Package <A HREF="../../../../reference/android/support/v17/preference/package-summary.html" target="_top"><font size="+1"><code>android.support.v17.preference</code></font></A>
    ++</H2>
    ++<p>
    ++<a NAME="Changed"></a>
    ++<TABLE summary="Changed Classes" WIDTH="100%">
    ++<TR>
    ++  <TH VALIGN="TOP" COLSPAN=2>Changed Classes</FONT></TD>
    ++</TH>
    ++<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    ++  <TD VALIGN="TOP" WIDTH="25%">
    ++  <A NAME="LeanbackSettingsFragment"></A>
    ++  <nobr><A HREF="android.support.v17.preference.LeanbackSettingsFragment.html">LeanbackSettingsFragment</A></nobr>
    ++  </TD>
    ++  <TD>&nbsp;</TD>
    ++</TR>
    ++</TABLE>
    ++&nbsp;
    ++      </div>	
    ++      <div id="footer">
    ++        <div id="copyright">
    ++        Except as noted, this content is licensed under 
    ++        <a href="http://creativecommons.org/licenses/by/2.5/"> Creative Commons Attribution 2.5</a>.
    ++        For details and restrictions, see the <a href="/license.html">Content License</a>.
    ++        </div>
    ++      <div id="footerlinks">
    ++      <p>
    ++        <a href="http://www.android.com/terms.html">Site Terms of Service</a> -
    ++        <a href="http://www.android.com/privacy.html">Privacy Policy</a> -
    ++        <a href="http://www.android.com/branding.html">Brand Guidelines</a>
    ++      </p>
    ++    </div>
    ++    </div> <!-- end footer -->
    ++    </div><!-- end doc-content -->
    ++    </div> <!-- end body-content --> 
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    ++</script>
    ++<script type="text/javascript">
    ++  try {
    ++    var pageTracker = _gat._getTracker("UA-5831155-1");
    ++    pageTracker._setAllowAnchor(true);
    ++    pageTracker._initData();
    ++    pageTracker._trackPageview();
    ++  } catch(e) {}
    ++</script>
    ++</BODY>
    ++</HTML>
    +diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/pkg_android.support.v4.accessibilityservice.html b/docs/html/sdk/support_api_diff/24.2.0/changes/pkg_android.support.v4.accessibilityservice.html
    +new file mode 100644
    +index 0000000..2c0f684
    +--- /dev/null
    ++++ b/docs/html/sdk/support_api_diff/24.2.0/changes/pkg_android.support.v4.accessibilityservice.html
    +@@ -0,0 +1,119 @@
    ++<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
    ++<HTML style="overflow:auto;">
    ++<HEAD>
    ++<meta name="generator" content="JDiff v1.1.0">
    ++<!-- Generated by the JDiff Javadoc doclet -->
    ++<!-- (http://www.jdiff.org) -->
    ++<meta name="description" content="JDiff is a Javadoc doclet which generates an HTML report of all the packages, classes, constructors, methods, and fields which have been removed, added or changed in any way, including their documentation, when two APIs are compared.">
    ++<meta name="keywords" content="diff, jdiff, javadiff, java diff, java difference, API difference, difference between two APIs, API diff, Javadoc, doclet">
    ++<TITLE>
    ++android.support.v4.accessibilityservice
    ++</TITLE>
    ++<link href="../../../../assets/android-developer-docs.css" rel="stylesheet" type="text/css" />
    ++<link href="../stylesheet-jdiff.css" rel="stylesheet" type="text/css" />
    ++<noscript>
    ++<style type="text/css">
    ++body{overflow:auto;}
    ++#body-content{position:relative; top:0;}
    ++#doc-content{overflow:visible;border-left:3px solid #666;}
    ++#side-nav{padding:0;}
    ++#side-nav .toggle-list ul {display:block;}
    ++#resize-packages-nav{border-bottom:3px solid #666;}
    ++</style>
    ++</noscript>
    ++<style type="text/css">
    ++</style>
    ++</HEAD>
    ++<BODY>
    ++<!-- Start of nav bar -->
    ++<a name="top"></a>
    ++<div id="header" style="margin-bottom:0;padding-bottom:0;">
    ++<div id="headerLeft">
    ++<a href="../../../../index.html" tabindex="-1" target="_top"><img src="../../../../assets/images/bg_logo.png" alt="Android Developers" /></a>
    ++</div>
    ++  <div id="headerRight">
    ++  <div id="headerLinks">
    ++<!-- <img src="/assets/images/icon_world.jpg" alt="" /> -->
    ++<span class="text">
    ++<!-- &nbsp;<a href="#">English</a> | -->
    ++<nobr><a href="http://developer.android.com" target="_top">Android Developers</a> | <a href="http://www.android.com" target="_top">Android.com</a></nobr>
    ++</span>
    ++</div>
    ++  <div class="and-diff-id" style="margin-top:6px;margin-right:8px;">
    ++    <table class="diffspectable">
    ++      <tr>
    ++        <td colspan="2" class="diffspechead">API Diff Specification</td>
    ++      </tr>
    ++      <tr>
    ++        <td class="diffspec" style="padding-top:.25em">To Level:</td>
    ++        <td class="diffvaluenew" style="padding-top:.25em">24.2.0</td>
    ++      </tr>
    ++      <tr>
    ++        <td class="diffspec">From Level:</td>
    ++        <td class="diffvalueold">24.1.0</td>
    ++      </tr>
    ++      <tr>
    ++        <td class="diffspec">Generated</td>
    ++        <td class="diffvalue">2016.08.16 14:03</td>
    ++      </tr>
    ++    </table>
    ++    </div><!-- End and-diff-id -->
    ++  <div class="and-diff-id" style="margin-right:8px;">
    ++    <table class="diffspectable">
    ++      <tr>
    ++        <td class="diffspec" colspan="2"><a href="jdiff_statistics.html">Statistics</a>
    ++      </tr>
    ++    </table>
    ++  </div> <!-- End and-diff-id -->
    ++  </div> <!-- End headerRight -->
    ++  </div> <!-- End header -->
    ++<div id="body-content" xstyle="padding:12px;padding-right:18px;">
    ++<div id="doc-content" style="position:relative;">
    ++<div id="mainBodyFluid">
    ++<H2>
    ++Package <A HREF="../../../../reference/android/support/v4/accessibilityservice/package-summary.html" target="_top"><font size="+1"><code>android.support.v4.accessibilityservice</code></font></A>
    ++</H2>
    ++<p>
    ++<a NAME="Changed"></a>
    ++<TABLE summary="Changed Classes" WIDTH="100%">
    ++<TR>
    ++  <TH VALIGN="TOP" COLSPAN=2>Changed Classes</FONT></TD>
    ++</TH>
    ++<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    ++  <TD VALIGN="TOP" WIDTH="25%">
    ++  <A NAME="AccessibilityServiceInfoCompat"></A>
    ++  <nobr><A HREF="android.support.v4.accessibilityservice.AccessibilityServiceInfoCompat.html">AccessibilityServiceInfoCompat</A></nobr>
    ++  </TD>
    ++  <TD>&nbsp;</TD>
    ++</TR>
    ++</TABLE>
    ++&nbsp;
    ++      </div>	
    ++      <div id="footer">
    ++        <div id="copyright">
    ++        Except as noted, this content is licensed under 
    ++        <a href="http://creativecommons.org/licenses/by/2.5/"> Creative Commons Attribution 2.5</a>.
    ++        For details and restrictions, see the <a href="/license.html">Content License</a>.
    ++        </div>
    ++      <div id="footerlinks">
    ++      <p>
    ++        <a href="http://www.android.com/terms.html">Site Terms of Service</a> -
    ++        <a href="http://www.android.com/privacy.html">Privacy Policy</a> -
    ++        <a href="http://www.android.com/branding.html">Brand Guidelines</a>
    ++      </p>
    ++    </div>
    ++    </div> <!-- end footer -->
    ++    </div><!-- end doc-content -->
    ++    </div> <!-- end body-content --> 
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    ++</script>
    ++<script type="text/javascript">
    ++  try {
    ++    var pageTracker = _gat._getTracker("UA-5831155-1");
    ++    pageTracker._setAllowAnchor(true);
    ++    pageTracker._initData();
    ++    pageTracker._trackPageview();
    ++  } catch(e) {}
    ++</script>
    ++</BODY>
    ++</HTML>
    +diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/pkg_android.support.v4.app.html b/docs/html/sdk/support_api_diff/24.2.0/changes/pkg_android.support.v4.app.html
    +new file mode 100644
    +index 0000000..58ed06f
    +--- /dev/null
    ++++ b/docs/html/sdk/support_api_diff/24.2.0/changes/pkg_android.support.v4.app.html
    +@@ -0,0 +1,162 @@
    ++<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
    ++<HTML style="overflow:auto;">
    ++<HEAD>
    ++<meta name="generator" content="JDiff v1.1.0">
    ++<!-- Generated by the JDiff Javadoc doclet -->
    ++<!-- (http://www.jdiff.org) -->
    ++<meta name="description" content="JDiff is a Javadoc doclet which generates an HTML report of all the packages, classes, constructors, methods, and fields which have been removed, added or changed in any way, including their documentation, when two APIs are compared.">
    ++<meta name="keywords" content="diff, jdiff, javadiff, java diff, java difference, API difference, difference between two APIs, API diff, Javadoc, doclet">
    ++<TITLE>
    ++android.support.v4.app
    ++</TITLE>
    ++<link href="../../../../assets/android-developer-docs.css" rel="stylesheet" type="text/css" />
    ++<link href="../stylesheet-jdiff.css" rel="stylesheet" type="text/css" />
    ++<noscript>
    ++<style type="text/css">
    ++body{overflow:auto;}
    ++#body-content{position:relative; top:0;}
    ++#doc-content{overflow:visible;border-left:3px solid #666;}
    ++#side-nav{padding:0;}
    ++#side-nav .toggle-list ul {display:block;}
    ++#resize-packages-nav{border-bottom:3px solid #666;}
    ++</style>
    ++</noscript>
    ++<style type="text/css">
    ++</style>
    ++</HEAD>
    ++<BODY>
    ++<!-- Start of nav bar -->
    ++<a name="top"></a>
    ++<div id="header" style="margin-bottom:0;padding-bottom:0;">
    ++<div id="headerLeft">
    ++<a href="../../../../index.html" tabindex="-1" target="_top"><img src="../../../../assets/images/bg_logo.png" alt="Android Developers" /></a>
    ++</div>
    ++  <div id="headerRight">
    ++  <div id="headerLinks">
    ++<!-- <img src="/assets/images/icon_world.jpg" alt="" /> -->
    ++<span class="text">
    ++<!-- &nbsp;<a href="#">English</a> | -->
    ++<nobr><a href="http://developer.android.com" target="_top">Android Developers</a> | <a href="http://www.android.com" target="_top">Android.com</a></nobr>
    ++</span>
    ++</div>
    ++  <div class="and-diff-id" style="margin-top:6px;margin-right:8px;">
    ++    <table class="diffspectable">
    ++      <tr>
    ++        <td colspan="2" class="diffspechead">API Diff Specification</td>
    ++      </tr>
    ++      <tr>
    ++        <td class="diffspec" style="padding-top:.25em">To Level:</td>
    ++        <td class="diffvaluenew" style="padding-top:.25em">24.2.0</td>
    ++      </tr>
    ++      <tr>
    ++        <td class="diffspec">From Level:</td>
    ++        <td class="diffvalueold">24.1.0</td>
    ++      </tr>
    ++      <tr>
    ++        <td class="diffspec">Generated</td>
    ++        <td class="diffvalue">2016.08.16 14:03</td>
    ++      </tr>
    ++    </table>
    ++    </div><!-- End and-diff-id -->
    ++  <div class="and-diff-id" style="margin-right:8px;">
    ++    <table class="diffspectable">
    ++      <tr>
    ++        <td class="diffspec" colspan="2"><a href="jdiff_statistics.html">Statistics</a>
    ++      </tr>
    ++    </table>
    ++  </div> <!-- End and-diff-id -->
    ++  </div> <!-- End headerRight -->
    ++  </div> <!-- End header -->
    ++<div id="body-content" xstyle="padding:12px;padding-right:18px;">
    ++<div id="doc-content" style="position:relative;">
    ++<div id="mainBodyFluid">
    ++<H2>
    ++Package <A HREF="../../../../reference/android/support/v4/app/package-summary.html" target="_top"><font size="+1"><code>android.support.v4.app</code></font></A>
    ++</H2>
    ++<p>
    ++<a NAME="Added"></a>
    ++<TABLE summary="Added Interfaces" WIDTH="100%">
    ++<TR>
    ++  <TH VALIGN="TOP" COLSPAN=2>Added Interfaces</FONT></TD>
    ++</TH>
    ++<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    ++  <TD VALIGN="TOP" WIDTH="25%">
    ++  <A NAME="SharedElementCallback.OnSharedElementsReadyListener"></A>
    ++  <nobr><A HREF="../../../../reference/android/support/v4/app/SharedElementCallback.OnSharedElementsReadyListener.html" target="_top"><code><I>SharedElementCallback.<br>OnSharedElementsReadyListener</I></code></A></nobr>
    ++  </TD>
    ++  <TD>&nbsp;</TD>
    ++</TR>
    ++</TABLE>
    ++&nbsp;
    ++<p>
    ++<a NAME="Changed"></a>
    ++<TABLE summary="Changed Classes" WIDTH="100%">
    ++<TR>
    ++  <TH VALIGN="TOP" COLSPAN=2>Changed Classes</FONT></TD>
    ++</TH>
    ++<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    ++  <TD VALIGN="TOP" WIDTH="25%">
    ++  <A NAME="ActivityCompat"></A>
    ++  <nobr><A HREF="android.support.v4.app.ActivityCompat.html">ActivityCompat</A></nobr>
    ++  </TD>
    ++  <TD>&nbsp;</TD>
    ++</TR>
    ++<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    ++  <TD VALIGN="TOP" WIDTH="25%">
    ++  <A NAME="ActivityOptionsCompat"></A>
    ++  <nobr><A HREF="android.support.v4.app.ActivityOptionsCompat.html">ActivityOptionsCompat</A></nobr>
    ++  </TD>
    ++  <TD>&nbsp;</TD>
    ++</TR>
    ++<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    ++  <TD VALIGN="TOP" WIDTH="25%">
    ++  <A NAME="FragmentController"></A>
    ++  <nobr><A HREF="android.support.v4.app.FragmentController.html">FragmentController</A></nobr>
    ++  </TD>
    ++  <TD>&nbsp;</TD>
    ++</TR>
    ++<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    ++  <TD VALIGN="TOP" WIDTH="25%">
    ++  <A NAME="ServiceCompat"></A>
    ++  <nobr><A HREF="android.support.v4.app.ServiceCompat.html">ServiceCompat</A></nobr>
    ++  </TD>
    ++  <TD>&nbsp;</TD>
    ++</TR>
    ++<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    ++  <TD VALIGN="TOP" WIDTH="25%">
    ++  <A NAME="SharedElementCallback"></A>
    ++  <nobr><A HREF="android.support.v4.app.SharedElementCallback.html">SharedElementCallback</A></nobr>
    ++  </TD>
    ++  <TD>&nbsp;</TD>
    ++</TR>
    ++</TABLE>
    ++&nbsp;
    ++      </div>	
    ++      <div id="footer">
    ++        <div id="copyright">
    ++        Except as noted, this content is licensed under 
    ++        <a href="http://creativecommons.org/licenses/by/2.5/"> Creative Commons Attribution 2.5</a>.
    ++        For details and restrictions, see the <a href="/license.html">Content License</a>.
    ++        </div>
    ++      <div id="footerlinks">
    ++      <p>
    ++        <a href="http://www.android.com/terms.html">Site Terms of Service</a> -
    ++        <a href="http://www.android.com/privacy.html">Privacy Policy</a> -
    ++        <a href="http://www.android.com/branding.html">Brand Guidelines</a>
    ++      </p>
    ++    </div>
    ++    </div> <!-- end footer -->
    ++    </div><!-- end doc-content -->
    ++    </div> <!-- end body-content --> 
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    ++</script>
    ++<script type="text/javascript">
    ++  try {
    ++    var pageTracker = _gat._getTracker("UA-5831155-1");
    ++    pageTracker._setAllowAnchor(true);
    ++    pageTracker._initData();
    ++    pageTracker._trackPageview();
    ++  } catch(e) {}
    ++</script>
    ++</BODY>
    ++</HTML>
    +diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/pkg_android.support.v4.content.html b/docs/html/sdk/support_api_diff/24.2.0/changes/pkg_android.support.v4.content.html
    +new file mode 100644
    +index 0000000..65dd616
    +--- /dev/null
    ++++ b/docs/html/sdk/support_api_diff/24.2.0/changes/pkg_android.support.v4.content.html
    +@@ -0,0 +1,119 @@
    ++<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
    ++<HTML style="overflow:auto;">
    ++<HEAD>
    ++<meta name="generator" content="JDiff v1.1.0">
    ++<!-- Generated by the JDiff Javadoc doclet -->
    ++<!-- (http://www.jdiff.org) -->
    ++<meta name="description" content="JDiff is a Javadoc doclet which generates an HTML report of all the packages, classes, constructors, methods, and fields which have been removed, added or changed in any way, including their documentation, when two APIs are compared.">
    ++<meta name="keywords" content="diff, jdiff, javadiff, java diff, java difference, API difference, difference between two APIs, API diff, Javadoc, doclet">
    ++<TITLE>
    ++android.support.v4.content
    ++</TITLE>
    ++<link href="../../../../assets/android-developer-docs.css" rel="stylesheet" type="text/css" />
    ++<link href="../stylesheet-jdiff.css" rel="stylesheet" type="text/css" />
    ++<noscript>
    ++<style type="text/css">
    ++body{overflow:auto;}
    ++#body-content{position:relative; top:0;}
    ++#doc-content{overflow:visible;border-left:3px solid #666;}
    ++#side-nav{padding:0;}
    ++#side-nav .toggle-list ul {display:block;}
    ++#resize-packages-nav{border-bottom:3px solid #666;}
    ++</style>
    ++</noscript>
    ++<style type="text/css">
    ++</style>
    ++</HEAD>
    ++<BODY>
    ++<!-- Start of nav bar -->
    ++<a name="top"></a>
    ++<div id="header" style="margin-bottom:0;padding-bottom:0;">
    ++<div id="headerLeft">
    ++<a href="../../../../index.html" tabindex="-1" target="_top"><img src="../../../../assets/images/bg_logo.png" alt="Android Developers" /></a>
    ++</div>
    ++  <div id="headerRight">
    ++  <div id="headerLinks">
    ++<!-- <img src="/assets/images/icon_world.jpg" alt="" /> -->
    ++<span class="text">
    ++<!-- &nbsp;<a href="#">English</a> | -->
    ++<nobr><a href="http://developer.android.com" target="_top">Android Developers</a> | <a href="http://www.android.com" target="_top">Android.com</a></nobr>
    ++</span>
    ++</div>
    ++  <div class="and-diff-id" style="margin-top:6px;margin-right:8px;">
    ++    <table class="diffspectable">
    ++      <tr>
    ++        <td colspan="2" class="diffspechead">API Diff Specification</td>
    ++      </tr>
    ++      <tr>
    ++        <td class="diffspec" style="padding-top:.25em">To Level:</td>
    ++        <td class="diffvaluenew" style="padding-top:.25em">24.2.0</td>
    ++      </tr>
    ++      <tr>
    ++        <td class="diffspec">From Level:</td>
    ++        <td class="diffvalueold">24.1.0</td>
    ++      </tr>
    ++      <tr>
    ++        <td class="diffspec">Generated</td>
    ++        <td class="diffvalue">2016.08.16 14:03</td>
    ++      </tr>
    ++    </table>
    ++    </div><!-- End and-diff-id -->
    ++  <div class="and-diff-id" style="margin-right:8px;">
    ++    <table class="diffspectable">
    ++      <tr>
    ++        <td class="diffspec" colspan="2"><a href="jdiff_statistics.html">Statistics</a>
    ++      </tr>
    ++    </table>
    ++  </div> <!-- End and-diff-id -->
    ++  </div> <!-- End headerRight -->
    ++  </div> <!-- End header -->
    ++<div id="body-content" xstyle="padding:12px;padding-right:18px;">
    ++<div id="doc-content" style="position:relative;">
    ++<div id="mainBodyFluid">
    ++<H2>
    ++Package <A HREF="../../../../reference/android/support/v4/content/package-summary.html" target="_top"><font size="+1"><code>android.support.v4.content</code></font></A>
    ++</H2>
    ++<p>
    ++<a NAME="Changed"></a>
    ++<TABLE summary="Changed Classes" WIDTH="100%">
    ++<TR>
    ++  <TH VALIGN="TOP" COLSPAN=2>Changed Classes</FONT></TD>
    ++</TH>
    ++<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    ++  <TD VALIGN="TOP" WIDTH="25%">
    ++  <A NAME="ContextCompat"></A>
    ++  <nobr><A HREF="android.support.v4.content.ContextCompat.html">ContextCompat</A></nobr>
    ++  </TD>
    ++  <TD>&nbsp;</TD>
    ++</TR>
    ++</TABLE>
    ++&nbsp;
    ++      </div>	
    ++      <div id="footer">
    ++        <div id="copyright">
    ++        Except as noted, this content is licensed under 
    ++        <a href="http://creativecommons.org/licenses/by/2.5/"> Creative Commons Attribution 2.5</a>.
    ++        For details and restrictions, see the <a href="/license.html">Content License</a>.
    ++        </div>
    ++      <div id="footerlinks">
    ++      <p>
    ++        <a href="http://www.android.com/terms.html">Site Terms of Service</a> -
    ++        <a href="http://www.android.com/privacy.html">Privacy Policy</a> -
    ++        <a href="http://www.android.com/branding.html">Brand Guidelines</a>
    ++      </p>
    ++    </div>
    ++    </div> <!-- end footer -->
    ++    </div><!-- end doc-content -->
    ++    </div> <!-- end body-content --> 
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    ++</script>
    ++<script type="text/javascript">
    ++  try {
    ++    var pageTracker = _gat._getTracker("UA-5831155-1");
    ++    pageTracker._setAllowAnchor(true);
    ++    pageTracker._initData();
    ++    pageTracker._trackPageview();
    ++  } catch(e) {}
    ++</script>
    ++</BODY>
    ++</HTML>
    +diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/pkg_android.support.v4.graphics.drawable.html b/docs/html/sdk/support_api_diff/24.2.0/changes/pkg_android.support.v4.graphics.drawable.html
    +new file mode 100644
    +index 0000000..f8b31a5
    +--- /dev/null
    ++++ b/docs/html/sdk/support_api_diff/24.2.0/changes/pkg_android.support.v4.graphics.drawable.html
    +@@ -0,0 +1,119 @@
    ++<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
    ++<HTML style="overflow:auto;">
    ++<HEAD>
    ++<meta name="generator" content="JDiff v1.1.0">
    ++<!-- Generated by the JDiff Javadoc doclet -->
    ++<!-- (http://www.jdiff.org) -->
    ++<meta name="description" content="JDiff is a Javadoc doclet which generates an HTML report of all the packages, classes, constructors, methods, and fields which have been removed, added or changed in any way, including their documentation, when two APIs are compared.">
    ++<meta name="keywords" content="diff, jdiff, javadiff, java diff, java difference, API difference, difference between two APIs, API diff, Javadoc, doclet">
    ++<TITLE>
    ++android.support.v4.graphics.drawable
    ++</TITLE>
    ++<link href="../../../../assets/android-developer-docs.css" rel="stylesheet" type="text/css" />
    ++<link href="../stylesheet-jdiff.css" rel="stylesheet" type="text/css" />
    ++<noscript>
    ++<style type="text/css">
    ++body{overflow:auto;}
    ++#body-content{position:relative; top:0;}
    ++#doc-content{overflow:visible;border-left:3px solid #666;}
    ++#side-nav{padding:0;}
    ++#side-nav .toggle-list ul {display:block;}
    ++#resize-packages-nav{border-bottom:3px solid #666;}
    ++</style>
    ++</noscript>
    ++<style type="text/css">
    ++</style>
    ++</HEAD>
    ++<BODY>
    ++<!-- Start of nav bar -->
    ++<a name="top"></a>
    ++<div id="header" style="margin-bottom:0;padding-bottom:0;">
    ++<div id="headerLeft">
    ++<a href="../../../../index.html" tabindex="-1" target="_top"><img src="../../../../assets/images/bg_logo.png" alt="Android Developers" /></a>
    ++</div>
    ++  <div id="headerRight">
    ++  <div id="headerLinks">
    ++<!-- <img src="/assets/images/icon_world.jpg" alt="" /> -->
    ++<span class="text">
    ++<!-- &nbsp;<a href="#">English</a> | -->
    ++<nobr><a href="http://developer.android.com" target="_top">Android Developers</a> | <a href="http://www.android.com" target="_top">Android.com</a></nobr>
    ++</span>
    ++</div>
    ++  <div class="and-diff-id" style="margin-top:6px;margin-right:8px;">
    ++    <table class="diffspectable">
    ++      <tr>
    ++        <td colspan="2" class="diffspechead">API Diff Specification</td>
    ++      </tr>
    ++      <tr>
    ++        <td class="diffspec" style="padding-top:.25em">To Level:</td>
    ++        <td class="diffvaluenew" style="padding-top:.25em">24.2.0</td>
    ++      </tr>
    ++      <tr>
    ++        <td class="diffspec">From Level:</td>
    ++        <td class="diffvalueold">24.1.0</td>
    ++      </tr>
    ++      <tr>
    ++        <td class="diffspec">Generated</td>
    ++        <td class="diffvalue">2016.08.16 14:03</td>
    ++      </tr>
    ++    </table>
    ++    </div><!-- End and-diff-id -->
    ++  <div class="and-diff-id" style="margin-right:8px;">
    ++    <table class="diffspectable">
    ++      <tr>
    ++        <td class="diffspec" colspan="2"><a href="jdiff_statistics.html">Statistics</a>
    ++      </tr>
    ++    </table>
    ++  </div> <!-- End and-diff-id -->
    ++  </div> <!-- End headerRight -->
    ++  </div> <!-- End header -->
    ++<div id="body-content" xstyle="padding:12px;padding-right:18px;">
    ++<div id="doc-content" style="position:relative;">
    ++<div id="mainBodyFluid">
    ++<H2>
    ++Package <A HREF="../../../../reference/android/support/v4/graphics/drawable/package-summary.html" target="_top"><font size="+1"><code>android.support.v4.graphics.drawable</code></font></A>
    ++</H2>
    ++<p>
    ++<a NAME="Changed"></a>
    ++<TABLE summary="Changed Classes" WIDTH="100%">
    ++<TR>
    ++  <TH VALIGN="TOP" COLSPAN=2>Changed Classes</FONT></TD>
    ++</TH>
    ++<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    ++  <TD VALIGN="TOP" WIDTH="25%">
    ++  <A NAME="DrawableCompat"></A>
    ++  <nobr><A HREF="android.support.v4.graphics.drawable.DrawableCompat.html">DrawableCompat</A></nobr>
    ++  </TD>
    ++  <TD>&nbsp;</TD>
    ++</TR>
    ++</TABLE>
    ++&nbsp;
    ++      </div>	
    ++      <div id="footer">
    ++        <div id="copyright">
    ++        Except as noted, this content is licensed under 
    ++        <a href="http://creativecommons.org/licenses/by/2.5/"> Creative Commons Attribution 2.5</a>.
    ++        For details and restrictions, see the <a href="/license.html">Content License</a>.
    ++        </div>
    ++      <div id="footerlinks">
    ++      <p>
    ++        <a href="http://www.android.com/terms.html">Site Terms of Service</a> -
    ++        <a href="http://www.android.com/privacy.html">Privacy Policy</a> -
    ++        <a href="http://www.android.com/branding.html">Brand Guidelines</a>
    ++      </p>
    ++    </div>
    ++    </div> <!-- end footer -->
    ++    </div><!-- end doc-content -->
    ++    </div> <!-- end body-content --> 
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    ++</script>
    ++<script type="text/javascript">
    ++  try {
    ++    var pageTracker = _gat._getTracker("UA-5831155-1");
    ++    pageTracker._setAllowAnchor(true);
    ++    pageTracker._initData();
    ++    pageTracker._trackPageview();
    ++  } catch(e) {}
    ++</script>
    ++</BODY>
    ++</HTML>
    +diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/pkg_android.support.v4.media.html b/docs/html/sdk/support_api_diff/24.2.0/changes/pkg_android.support.v4.media.html
    +new file mode 100644
    +index 0000000..5300c86
    +--- /dev/null
    ++++ b/docs/html/sdk/support_api_diff/24.2.0/changes/pkg_android.support.v4.media.html
    +@@ -0,0 +1,140 @@
    ++<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
    ++<HTML style="overflow:auto;">
    ++<HEAD>
    ++<meta name="generator" content="JDiff v1.1.0">
    ++<!-- Generated by the JDiff Javadoc doclet -->
    ++<!-- (http://www.jdiff.org) -->
    ++<meta name="description" content="JDiff is a Javadoc doclet which generates an HTML report of all the packages, classes, constructors, methods, and fields which have been removed, added or changed in any way, including their documentation, when two APIs are compared.">
    ++<meta name="keywords" content="diff, jdiff, javadiff, java diff, java difference, API difference, difference between two APIs, API diff, Javadoc, doclet">
    ++<TITLE>
    ++android.support.v4.media
    ++</TITLE>
    ++<link href="../../../../assets/android-developer-docs.css" rel="stylesheet" type="text/css" />
    ++<link href="../stylesheet-jdiff.css" rel="stylesheet" type="text/css" />
    ++<noscript>
    ++<style type="text/css">
    ++body{overflow:auto;}
    ++#body-content{position:relative; top:0;}
    ++#doc-content{overflow:visible;border-left:3px solid #666;}
    ++#side-nav{padding:0;}
    ++#side-nav .toggle-list ul {display:block;}
    ++#resize-packages-nav{border-bottom:3px solid #666;}
    ++</style>
    ++</noscript>
    ++<style type="text/css">
    ++</style>
    ++</HEAD>
    ++<BODY>
    ++<!-- Start of nav bar -->
    ++<a name="top"></a>
    ++<div id="header" style="margin-bottom:0;padding-bottom:0;">
    ++<div id="headerLeft">
    ++<a href="../../../../index.html" tabindex="-1" target="_top"><img src="../../../../assets/images/bg_logo.png" alt="Android Developers" /></a>
    ++</div>
    ++  <div id="headerRight">
    ++  <div id="headerLinks">
    ++<!-- <img src="/assets/images/icon_world.jpg" alt="" /> -->
    ++<span class="text">
    ++<!-- &nbsp;<a href="#">English</a> | -->
    ++<nobr><a href="http://developer.android.com" target="_top">Android Developers</a> | <a href="http://www.android.com" target="_top">Android.com</a></nobr>
    ++</span>
    ++</div>
    ++  <div class="and-diff-id" style="margin-top:6px;margin-right:8px;">
    ++    <table class="diffspectable">
    ++      <tr>
    ++        <td colspan="2" class="diffspechead">API Diff Specification</td>
    ++      </tr>
    ++      <tr>
    ++        <td class="diffspec" style="padding-top:.25em">To Level:</td>
    ++        <td class="diffvaluenew" style="padding-top:.25em">24.2.0</td>
    ++      </tr>
    ++      <tr>
    ++        <td class="diffspec">From Level:</td>
    ++        <td class="diffvalueold">24.1.0</td>
    ++      </tr>
    ++      <tr>
    ++        <td class="diffspec">Generated</td>
    ++        <td class="diffvalue">2016.08.16 14:03</td>
    ++      </tr>
    ++    </table>
    ++    </div><!-- End and-diff-id -->
    ++  <div class="and-diff-id" style="margin-right:8px;">
    ++    <table class="diffspectable">
    ++      <tr>
    ++        <td class="diffspec" colspan="2"><a href="jdiff_statistics.html">Statistics</a>
    ++      </tr>
    ++    </table>
    ++  </div> <!-- End and-diff-id -->
    ++  </div> <!-- End headerRight -->
    ++  </div> <!-- End header -->
    ++<div id="body-content" xstyle="padding:12px;padding-right:18px;">
    ++<div id="doc-content" style="position:relative;">
    ++<div id="mainBodyFluid">
    ++<H2>
    ++Package <A HREF="../../../../reference/android/support/v4/media/package-summary.html" target="_top"><font size="+1"><code>android.support.v4.media</code></font></A>
    ++</H2>
    ++<p>
    ++<a NAME="Changed"></a>
    ++<TABLE summary="Changed Classes" WIDTH="100%">
    ++<TR>
    ++  <TH VALIGN="TOP" COLSPAN=2>Changed Classes</FONT></TD>
    ++</TH>
    ++<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    ++  <TD VALIGN="TOP" WIDTH="25%">
    ++  <A NAME="MediaBrowserCompat.MediaItem"></A>
    ++  <nobr><A HREF="android.support.v4.media.MediaBrowserCompat.MediaItem.html">MediaBrowserCompat.MediaItem</A></nobr>
    ++  </TD>
    ++  <TD>&nbsp;</TD>
    ++</TR>
    ++<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    ++  <TD VALIGN="TOP" WIDTH="25%">
    ++  <A NAME="MediaBrowserServiceCompat.BrowserRoot"></A>
    ++  <nobr><A HREF="android.support.v4.media.MediaBrowserServiceCompat.BrowserRoot.html">MediaBrowserServiceCompat.<br>BrowserRoot</A></nobr>
    ++  </TD>
    ++  <TD>&nbsp;</TD>
    ++</TR>
    ++<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    ++  <TD VALIGN="TOP" WIDTH="25%">
    ++  <A NAME="MediaDescriptionCompat"></A>
    ++  <nobr><A HREF="android.support.v4.media.MediaDescriptionCompat.html">MediaDescriptionCompat</A></nobr>
    ++  </TD>
    ++  <TD>&nbsp;</TD>
    ++</TR>
    ++<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    ++  <TD VALIGN="TOP" WIDTH="25%">
    ++  <A NAME="MediaMetadataCompat"></A>
    ++  <nobr><A HREF="android.support.v4.media.MediaMetadataCompat.html">MediaMetadataCompat</A></nobr>
    ++  </TD>
    ++  <TD>&nbsp;</TD>
    ++</TR>
    ++</TABLE>
    ++&nbsp;
    ++      </div>	
    ++      <div id="footer">
    ++        <div id="copyright">
    ++        Except as noted, this content is licensed under 
    ++        <a href="http://creativecommons.org/licenses/by/2.5/"> Creative Commons Attribution 2.5</a>.
    ++        For details and restrictions, see the <a href="/license.html">Content License</a>.
    ++        </div>
    ++      <div id="footerlinks">
    ++      <p>
    ++        <a href="http://www.android.com/terms.html">Site Terms of Service</a> -
    ++        <a href="http://www.android.com/privacy.html">Privacy Policy</a> -
    ++        <a href="http://www.android.com/branding.html">Brand Guidelines</a>
    ++      </p>
    ++    </div>
    ++    </div> <!-- end footer -->
    ++    </div><!-- end doc-content -->
    ++    </div> <!-- end body-content --> 
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    ++</script>
    ++<script type="text/javascript">
    ++  try {
    ++    var pageTracker = _gat._getTracker("UA-5831155-1");
    ++    pageTracker._setAllowAnchor(true);
    ++    pageTracker._initData();
    ++    pageTracker._trackPageview();
    ++  } catch(e) {}
    ++</script>
    ++</BODY>
    ++</HTML>
    +diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/pkg_android.support.v4.media.session.html b/docs/html/sdk/support_api_diff/24.2.0/changes/pkg_android.support.v4.media.session.html
    +new file mode 100644
    +index 0000000..459d0c3
    +--- /dev/null
    ++++ b/docs/html/sdk/support_api_diff/24.2.0/changes/pkg_android.support.v4.media.session.html
    +@@ -0,0 +1,140 @@
    ++<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
    ++<HTML style="overflow:auto;">
    ++<HEAD>
    ++<meta name="generator" content="JDiff v1.1.0">
    ++<!-- Generated by the JDiff Javadoc doclet -->
    ++<!-- (http://www.jdiff.org) -->
    ++<meta name="description" content="JDiff is a Javadoc doclet which generates an HTML report of all the packages, classes, constructors, methods, and fields which have been removed, added or changed in any way, including their documentation, when two APIs are compared.">
    ++<meta name="keywords" content="diff, jdiff, javadiff, java diff, java difference, API difference, difference between two APIs, API diff, Javadoc, doclet">
    ++<TITLE>
    ++android.support.v4.media.session
    ++</TITLE>
    ++<link href="../../../../assets/android-developer-docs.css" rel="stylesheet" type="text/css" />
    ++<link href="../stylesheet-jdiff.css" rel="stylesheet" type="text/css" />
    ++<noscript>
    ++<style type="text/css">
    ++body{overflow:auto;}
    ++#body-content{position:relative; top:0;}
    ++#doc-content{overflow:visible;border-left:3px solid #666;}
    ++#side-nav{padding:0;}
    ++#side-nav .toggle-list ul {display:block;}
    ++#resize-packages-nav{border-bottom:3px solid #666;}
    ++</style>
    ++</noscript>
    ++<style type="text/css">
    ++</style>
    ++</HEAD>
    ++<BODY>
    ++<!-- Start of nav bar -->
    ++<a name="top"></a>
    ++<div id="header" style="margin-bottom:0;padding-bottom:0;">
    ++<div id="headerLeft">
    ++<a href="../../../../index.html" tabindex="-1" target="_top"><img src="../../../../assets/images/bg_logo.png" alt="Android Developers" /></a>
    ++</div>
    ++  <div id="headerRight">
    ++  <div id="headerLinks">
    ++<!-- <img src="/assets/images/icon_world.jpg" alt="" /> -->
    ++<span class="text">
    ++<!-- &nbsp;<a href="#">English</a> | -->
    ++<nobr><a href="http://developer.android.com" target="_top">Android Developers</a> | <a href="http://www.android.com" target="_top">Android.com</a></nobr>
    ++</span>
    ++</div>
    ++  <div class="and-diff-id" style="margin-top:6px;margin-right:8px;">
    ++    <table class="diffspectable">
    ++      <tr>
    ++        <td colspan="2" class="diffspechead">API Diff Specification</td>
    ++      </tr>
    ++      <tr>
    ++        <td class="diffspec" style="padding-top:.25em">To Level:</td>
    ++        <td class="diffvaluenew" style="padding-top:.25em">24.2.0</td>
    ++      </tr>
    ++      <tr>
    ++        <td class="diffspec">From Level:</td>
    ++        <td class="diffvalueold">24.1.0</td>
    ++      </tr>
    ++      <tr>
    ++        <td class="diffspec">Generated</td>
    ++        <td class="diffvalue">2016.08.16 14:03</td>
    ++      </tr>
    ++    </table>
    ++    </div><!-- End and-diff-id -->
    ++  <div class="and-diff-id" style="margin-right:8px;">
    ++    <table class="diffspectable">
    ++      <tr>
    ++        <td class="diffspec" colspan="2"><a href="jdiff_statistics.html">Statistics</a>
    ++      </tr>
    ++    </table>
    ++  </div> <!-- End and-diff-id -->
    ++  </div> <!-- End headerRight -->
    ++  </div> <!-- End header -->
    ++<div id="body-content" xstyle="padding:12px;padding-right:18px;">
    ++<div id="doc-content" style="position:relative;">
    ++<div id="mainBodyFluid">
    ++<H2>
    ++Package <A HREF="../../../../reference/android/support/v4/media/session/package-summary.html" target="_top"><font size="+1"><code>android.support.v4.media.session</code></font></A>
    ++</H2>
    ++<p>
    ++<a NAME="Changed"></a>
    ++<TABLE summary="Changed Classes" WIDTH="100%">
    ++<TR>
    ++  <TH VALIGN="TOP" COLSPAN=2>Changed Classes</FONT></TD>
    ++</TH>
    ++<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    ++  <TD VALIGN="TOP" WIDTH="25%">
    ++  <A NAME="MediaButtonReceiver"></A>
    ++  <nobr><A HREF="android.support.v4.media.session.MediaButtonReceiver.html">MediaButtonReceiver</A></nobr>
    ++  </TD>
    ++  <TD>&nbsp;</TD>
    ++</TR>
    ++<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    ++  <TD VALIGN="TOP" WIDTH="25%">
    ++  <A NAME="MediaSessionCompat"></A>
    ++  <nobr><A HREF="android.support.v4.media.session.MediaSessionCompat.html">MediaSessionCompat</A></nobr>
    ++  </TD>
    ++  <TD>&nbsp;</TD>
    ++</TR>
    ++<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    ++  <TD VALIGN="TOP" WIDTH="25%">
    ++  <A NAME="MediaSessionCompat.QueueItem"></A>
    ++  <nobr><A HREF="android.support.v4.media.session.MediaSessionCompat.QueueItem.html">MediaSessionCompat.QueueItem</A></nobr>
    ++  </TD>
    ++  <TD>&nbsp;</TD>
    ++</TR>
    ++<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    ++  <TD VALIGN="TOP" WIDTH="25%">
    ++  <A NAME="PlaybackStateCompat"></A>
    ++  <nobr><A HREF="android.support.v4.media.session.PlaybackStateCompat.html">PlaybackStateCompat</A></nobr>
    ++  </TD>
    ++  <TD>&nbsp;</TD>
    ++</TR>
    ++</TABLE>
    ++&nbsp;
    ++      </div>	
    ++      <div id="footer">
    ++        <div id="copyright">
    ++        Except as noted, this content is licensed under 
    ++        <a href="http://creativecommons.org/licenses/by/2.5/"> Creative Commons Attribution 2.5</a>.
    ++        For details and restrictions, see the <a href="/license.html">Content License</a>.
    ++        </div>
    ++      <div id="footerlinks">
    ++      <p>
    ++        <a href="http://www.android.com/terms.html">Site Terms of Service</a> -
    ++        <a href="http://www.android.com/privacy.html">Privacy Policy</a> -
    ++        <a href="http://www.android.com/branding.html">Brand Guidelines</a>
    ++      </p>
    ++    </div>
    ++    </div> <!-- end footer -->
    ++    </div><!-- end doc-content -->
    ++    </div> <!-- end body-content --> 
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    ++</script>
    ++<script type="text/javascript">
    ++  try {
    ++    var pageTracker = _gat._getTracker("UA-5831155-1");
    ++    pageTracker._setAllowAnchor(true);
    ++    pageTracker._initData();
    ++    pageTracker._trackPageview();
    ++  } catch(e) {}
    ++</script>
    ++</BODY>
    ++</HTML>
    +diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/pkg_android.support.v4.os.html b/docs/html/sdk/support_api_diff/24.2.0/changes/pkg_android.support.v4.os.html
    +new file mode 100644
    +index 0000000..6d7f399
    +--- /dev/null
    ++++ b/docs/html/sdk/support_api_diff/24.2.0/changes/pkg_android.support.v4.os.html
    +@@ -0,0 +1,119 @@
    ++<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
    ++<HTML style="overflow:auto;">
    ++<HEAD>
    ++<meta name="generator" content="JDiff v1.1.0">
    ++<!-- Generated by the JDiff Javadoc doclet -->
    ++<!-- (http://www.jdiff.org) -->
    ++<meta name="description" content="JDiff is a Javadoc doclet which generates an HTML report of all the packages, classes, constructors, methods, and fields which have been removed, added or changed in any way, including their documentation, when two APIs are compared.">
    ++<meta name="keywords" content="diff, jdiff, javadiff, java diff, java difference, API difference, difference between two APIs, API diff, Javadoc, doclet">
    ++<TITLE>
    ++android.support.v4.os
    ++</TITLE>
    ++<link href="../../../../assets/android-developer-docs.css" rel="stylesheet" type="text/css" />
    ++<link href="../stylesheet-jdiff.css" rel="stylesheet" type="text/css" />
    ++<noscript>
    ++<style type="text/css">
    ++body{overflow:auto;}
    ++#body-content{position:relative; top:0;}
    ++#doc-content{overflow:visible;border-left:3px solid #666;}
    ++#side-nav{padding:0;}
    ++#side-nav .toggle-list ul {display:block;}
    ++#resize-packages-nav{border-bottom:3px solid #666;}
    ++</style>
    ++</noscript>
    ++<style type="text/css">
    ++</style>
    ++</HEAD>
    ++<BODY>
    ++<!-- Start of nav bar -->
    ++<a name="top"></a>
    ++<div id="header" style="margin-bottom:0;padding-bottom:0;">
    ++<div id="headerLeft">
    ++<a href="../../../../index.html" tabindex="-1" target="_top"><img src="../../../../assets/images/bg_logo.png" alt="Android Developers" /></a>
    ++</div>
    ++  <div id="headerRight">
    ++  <div id="headerLinks">
    ++<!-- <img src="/assets/images/icon_world.jpg" alt="" /> -->
    ++<span class="text">
    ++<!-- &nbsp;<a href="#">English</a> | -->
    ++<nobr><a href="http://developer.android.com" target="_top">Android Developers</a> | <a href="http://www.android.com" target="_top">Android.com</a></nobr>
    ++</span>
    ++</div>
    ++  <div class="and-diff-id" style="margin-top:6px;margin-right:8px;">
    ++    <table class="diffspectable">
    ++      <tr>
    ++        <td colspan="2" class="diffspechead">API Diff Specification</td>
    ++      </tr>
    ++      <tr>
    ++        <td class="diffspec" style="padding-top:.25em">To Level:</td>
    ++        <td class="diffvaluenew" style="padding-top:.25em">24.2.0</td>
    ++      </tr>
    ++      <tr>
    ++        <td class="diffspec">From Level:</td>
    ++        <td class="diffvalueold">24.1.0</td>
    ++      </tr>
    ++      <tr>
    ++        <td class="diffspec">Generated</td>
    ++        <td class="diffvalue">2016.08.16 14:03</td>
    ++      </tr>
    ++    </table>
    ++    </div><!-- End and-diff-id -->
    ++  <div class="and-diff-id" style="margin-right:8px;">
    ++    <table class="diffspectable">
    ++      <tr>
    ++        <td class="diffspec" colspan="2"><a href="jdiff_statistics.html">Statistics</a>
    ++      </tr>
    ++    </table>
    ++  </div> <!-- End and-diff-id -->
    ++  </div> <!-- End headerRight -->
    ++  </div> <!-- End header -->
    ++<div id="body-content" xstyle="padding:12px;padding-right:18px;">
    ++<div id="doc-content" style="position:relative;">
    ++<div id="mainBodyFluid">
    ++<H2>
    ++Package <A HREF="../../../../reference/android/support/v4/os/package-summary.html" target="_top"><font size="+1"><code>android.support.v4.os</code></font></A>
    ++</H2>
    ++<p>
    ++<a NAME="Changed"></a>
    ++<TABLE summary="Changed Classes" WIDTH="100%">
    ++<TR>
    ++  <TH VALIGN="TOP" COLSPAN=2>Changed Classes</FONT></TD>
    ++</TH>
    ++<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    ++  <TD VALIGN="TOP" WIDTH="25%">
    ++  <A NAME="BuildCompat"></A>
    ++  <nobr><A HREF="android.support.v4.os.BuildCompat.html">BuildCompat</A></nobr>
    ++  </TD>
    ++  <TD>&nbsp;</TD>
    ++</TR>
    ++</TABLE>
    ++&nbsp;
    ++      </div>	
    ++      <div id="footer">
    ++        <div id="copyright">
    ++        Except as noted, this content is licensed under 
    ++        <a href="http://creativecommons.org/licenses/by/2.5/"> Creative Commons Attribution 2.5</a>.
    ++        For details and restrictions, see the <a href="/license.html">Content License</a>.
    ++        </div>
    ++      <div id="footerlinks">
    ++      <p>
    ++        <a href="http://www.android.com/terms.html">Site Terms of Service</a> -
    ++        <a href="http://www.android.com/privacy.html">Privacy Policy</a> -
    ++        <a href="http://www.android.com/branding.html">Brand Guidelines</a>
    ++      </p>
    ++    </div>
    ++    </div> <!-- end footer -->
    ++    </div><!-- end doc-content -->
    ++    </div> <!-- end body-content --> 
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    ++</script>
    ++<script type="text/javascript">
    ++  try {
    ++    var pageTracker = _gat._getTracker("UA-5831155-1");
    ++    pageTracker._setAllowAnchor(true);
    ++    pageTracker._initData();
    ++    pageTracker._trackPageview();
    ++  } catch(e) {}
    ++</script>
    ++</BODY>
    ++</HTML>
    +diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/pkg_android.support.v4.util.html b/docs/html/sdk/support_api_diff/24.2.0/changes/pkg_android.support.v4.util.html
    +new file mode 100644
    +index 0000000..6f0e777
    +--- /dev/null
    ++++ b/docs/html/sdk/support_api_diff/24.2.0/changes/pkg_android.support.v4.util.html
    +@@ -0,0 +1,119 @@
    ++<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
    ++<HTML style="overflow:auto;">
    ++<HEAD>
    ++<meta name="generator" content="JDiff v1.1.0">
    ++<!-- Generated by the JDiff Javadoc doclet -->
    ++<!-- (http://www.jdiff.org) -->
    ++<meta name="description" content="JDiff is a Javadoc doclet which generates an HTML report of all the packages, classes, constructors, methods, and fields which have been removed, added or changed in any way, including their documentation, when two APIs are compared.">
    ++<meta name="keywords" content="diff, jdiff, javadiff, java diff, java difference, API difference, difference between two APIs, API diff, Javadoc, doclet">
    ++<TITLE>
    ++android.support.v4.util
    ++</TITLE>
    ++<link href="../../../../assets/android-developer-docs.css" rel="stylesheet" type="text/css" />
    ++<link href="../stylesheet-jdiff.css" rel="stylesheet" type="text/css" />
    ++<noscript>
    ++<style type="text/css">
    ++body{overflow:auto;}
    ++#body-content{position:relative; top:0;}
    ++#doc-content{overflow:visible;border-left:3px solid #666;}
    ++#side-nav{padding:0;}
    ++#side-nav .toggle-list ul {display:block;}
    ++#resize-packages-nav{border-bottom:3px solid #666;}
    ++</style>
    ++</noscript>
    ++<style type="text/css">
    ++</style>
    ++</HEAD>
    ++<BODY>
    ++<!-- Start of nav bar -->
    ++<a name="top"></a>
    ++<div id="header" style="margin-bottom:0;padding-bottom:0;">
    ++<div id="headerLeft">
    ++<a href="../../../../index.html" tabindex="-1" target="_top"><img src="../../../../assets/images/bg_logo.png" alt="Android Developers" /></a>
    ++</div>
    ++  <div id="headerRight">
    ++  <div id="headerLinks">
    ++<!-- <img src="/assets/images/icon_world.jpg" alt="" /> -->
    ++<span class="text">
    ++<!-- &nbsp;<a href="#">English</a> | -->
    ++<nobr><a href="http://developer.android.com" target="_top">Android Developers</a> | <a href="http://www.android.com" target="_top">Android.com</a></nobr>
    ++</span>
    ++</div>
    ++  <div class="and-diff-id" style="margin-top:6px;margin-right:8px;">
    ++    <table class="diffspectable">
    ++      <tr>
    ++        <td colspan="2" class="diffspechead">API Diff Specification</td>
    ++      </tr>
    ++      <tr>
    ++        <td class="diffspec" style="padding-top:.25em">To Level:</td>
    ++        <td class="diffvaluenew" style="padding-top:.25em">24.2.0</td>
    ++      </tr>
    ++      <tr>
    ++        <td class="diffspec">From Level:</td>
    ++        <td class="diffvalueold">24.1.0</td>
    ++      </tr>
    ++      <tr>
    ++        <td class="diffspec">Generated</td>
    ++        <td class="diffvalue">2016.08.16 14:03</td>
    ++      </tr>
    ++    </table>
    ++    </div><!-- End and-diff-id -->
    ++  <div class="and-diff-id" style="margin-right:8px;">
    ++    <table class="diffspectable">
    ++      <tr>
    ++        <td class="diffspec" colspan="2"><a href="jdiff_statistics.html">Statistics</a>
    ++      </tr>
    ++    </table>
    ++  </div> <!-- End and-diff-id -->
    ++  </div> <!-- End headerRight -->
    ++  </div> <!-- End header -->
    ++<div id="body-content" xstyle="padding:12px;padding-right:18px;">
    ++<div id="doc-content" style="position:relative;">
    ++<div id="mainBodyFluid">
    ++<H2>
    ++Package <A HREF="../../../../reference/android/support/v4/util/package-summary.html" target="_top"><font size="+1"><code>android.support.v4.util</code></font></A>
    ++</H2>
    ++<p>
    ++<a NAME="Added"></a>
    ++<TABLE summary="Added Classes" WIDTH="100%">
    ++<TR>
    ++  <TH VALIGN="TOP" COLSPAN=2>Added Classes</FONT></TD>
    ++</TH>
    ++<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    ++  <TD VALIGN="TOP" WIDTH="25%">
    ++  <A NAME="PatternsCompat"></A>
    ++  <nobr><A HREF="../../../../reference/android/support/v4/util/PatternsCompat.html" target="_top"><code>PatternsCompat</code></A></nobr>
    ++  </TD>
    ++  <TD>&nbsp;</TD>
    ++</TR>
    ++</TABLE>
    ++&nbsp;
    ++      </div>	
    ++      <div id="footer">
    ++        <div id="copyright">
    ++        Except as noted, this content is licensed under 
    ++        <a href="http://creativecommons.org/licenses/by/2.5/"> Creative Commons Attribution 2.5</a>.
    ++        For details and restrictions, see the <a href="/license.html">Content License</a>.
    ++        </div>
    ++      <div id="footerlinks">
    ++      <p>
    ++        <a href="http://www.android.com/terms.html">Site Terms of Service</a> -
    ++        <a href="http://www.android.com/privacy.html">Privacy Policy</a> -
    ++        <a href="http://www.android.com/branding.html">Brand Guidelines</a>
    ++      </p>
    ++    </div>
    ++    </div> <!-- end footer -->
    ++    </div><!-- end doc-content -->
    ++    </div> <!-- end body-content --> 
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    ++</script>
    ++<script type="text/javascript">
    ++  try {
    ++    var pageTracker = _gat._getTracker("UA-5831155-1");
    ++    pageTracker._setAllowAnchor(true);
    ++    pageTracker._initData();
    ++    pageTracker._trackPageview();
    ++  } catch(e) {}
    ++</script>
    ++</BODY>
    ++</HTML>
    +diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/pkg_android.support.v4.view.accessibility.html b/docs/html/sdk/support_api_diff/24.2.0/changes/pkg_android.support.v4.view.accessibility.html
    +new file mode 100644
    +index 0000000..d5d126c
    +--- /dev/null
    ++++ b/docs/html/sdk/support_api_diff/24.2.0/changes/pkg_android.support.v4.view.accessibility.html
    +@@ -0,0 +1,204 @@
    ++<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
    ++<HTML style="overflow:auto;">
    ++<HEAD>
    ++<meta name="generator" content="JDiff v1.1.0">
    ++<!-- Generated by the JDiff Javadoc doclet -->
    ++<!-- (http://www.jdiff.org) -->
    ++<meta name="description" content="JDiff is a Javadoc doclet which generates an HTML report of all the packages, classes, constructors, methods, and fields which have been removed, added or changed in any way, including their documentation, when two APIs are compared.">
    ++<meta name="keywords" content="diff, jdiff, javadiff, java diff, java difference, API difference, difference between two APIs, API diff, Javadoc, doclet">
    ++<TITLE>
    ++android.support.v4.view.accessibility
    ++</TITLE>
    ++<link href="../../../../assets/android-developer-docs.css" rel="stylesheet" type="text/css" />
    ++<link href="../stylesheet-jdiff.css" rel="stylesheet" type="text/css" />
    ++<noscript>
    ++<style type="text/css">
    ++body{overflow:auto;}
    ++#body-content{position:relative; top:0;}
    ++#doc-content{overflow:visible;border-left:3px solid #666;}
    ++#side-nav{padding:0;}
    ++#side-nav .toggle-list ul {display:block;}
    ++#resize-packages-nav{border-bottom:3px solid #666;}
    ++</style>
    ++</noscript>
    ++<style type="text/css">
    ++</style>
    ++</HEAD>
    ++<BODY>
    ++<!-- Start of nav bar -->
    ++<a name="top"></a>
    ++<div id="header" style="margin-bottom:0;padding-bottom:0;">
    ++<div id="headerLeft">
    ++<a href="../../../../index.html" tabindex="-1" target="_top"><img src="../../../../assets/images/bg_logo.png" alt="Android Developers" /></a>
    ++</div>
    ++  <div id="headerRight">
    ++  <div id="headerLinks">
    ++<!-- <img src="/assets/images/icon_world.jpg" alt="" /> -->
    ++<span class="text">
    ++<!-- &nbsp;<a href="#">English</a> | -->
    ++<nobr><a href="http://developer.android.com" target="_top">Android Developers</a> | <a href="http://www.android.com" target="_top">Android.com</a></nobr>
    ++</span>
    ++</div>
    ++  <div class="and-diff-id" style="margin-top:6px;margin-right:8px;">
    ++    <table class="diffspectable">
    ++      <tr>
    ++        <td colspan="2" class="diffspechead">API Diff Specification</td>
    ++      </tr>
    ++      <tr>
    ++        <td class="diffspec" style="padding-top:.25em">To Level:</td>
    ++        <td class="diffvaluenew" style="padding-top:.25em">24.2.0</td>
    ++      </tr>
    ++      <tr>
    ++        <td class="diffspec">From Level:</td>
    ++        <td class="diffvalueold">24.1.0</td>
    ++      </tr>
    ++      <tr>
    ++        <td class="diffspec">Generated</td>
    ++        <td class="diffvalue">2016.08.16 14:03</td>
    ++      </tr>
    ++    </table>
    ++    </div><!-- End and-diff-id -->
    ++  <div class="and-diff-id" style="margin-right:8px;">
    ++    <table class="diffspectable">
    ++      <tr>
    ++        <td class="diffspec" colspan="2"><a href="jdiff_statistics.html">Statistics</a>
    ++      </tr>
    ++    </table>
    ++  </div> <!-- End and-diff-id -->
    ++  </div> <!-- End headerRight -->
    ++  </div> <!-- End header -->
    ++<div id="body-content" xstyle="padding:12px;padding-right:18px;">
    ++<div id="doc-content" style="position:relative;">
    ++<div id="mainBodyFluid">
    ++<H2>
    ++Package <A HREF="../../../../reference/android/support/v4/view/accessibility/package-summary.html" target="_top"><font size="+1"><code>android.support.v4.view.accessibility</code></font></A>
    ++</H2>
    ++<p>
    ++<a NAME="Added"></a>
    ++<TABLE summary="Added Interfaces" WIDTH="100%">
    ++<TR>
    ++  <TH VALIGN="TOP" COLSPAN=2>Added Interfaces</FONT></TD>
    ++</TH>
    ++<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    ++  <TD VALIGN="TOP" WIDTH="25%">
    ++  <A NAME="AccessibilityManagerCompat.AccessibilityStateChangeListener"></A>
    ++  <nobr><A HREF="../../../../reference/android/support/v4/view/accessibility/AccessibilityManagerCompat.AccessibilityStateChangeListener.html" target="_top"><code><I>AccessibilityManagerCompat.<br>AccessibilityStateChangeListener</I></code></A></nobr>
    ++  </TD>
    ++  <TD>&nbsp;</TD>
    ++</TR>
    ++<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    ++  <TD VALIGN="TOP" WIDTH="25%">
    ++  <A NAME="AccessibilityManagerCompat.TouchExplorationStateChangeListener"></A>
    ++  <nobr><A HREF="../../../../reference/android/support/v4/view/accessibility/AccessibilityManagerCompat.TouchExplorationStateChangeListener.html" target="_top"><code><I>AccessibilityManagerCompat.<br>TouchExplorationStateChangeListener</I></code></A></nobr>
    ++  </TD>
    ++  <TD>&nbsp;</TD>
    ++</TR>
    ++</TABLE>
    ++&nbsp;
    ++<p>
    ++<a NAME="Changed"></a>
    ++<TABLE summary="Changed Classes" WIDTH="100%">
    ++<TR>
    ++  <TH VALIGN="TOP" COLSPAN=2>Changed Classes</FONT></TD>
    ++</TH>
    ++<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    ++  <TD VALIGN="TOP" WIDTH="25%">
    ++  <A NAME="AccessibilityEventCompat"></A>
    ++  <nobr><A HREF="android.support.v4.view.accessibility.AccessibilityEventCompat.html">AccessibilityEventCompat</A></nobr>
    ++  </TD>
    ++  <TD>&nbsp;</TD>
    ++</TR>
    ++<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    ++  <TD VALIGN="TOP" WIDTH="25%">
    ++  <A NAME="AccessibilityManagerCompat"></A>
    ++  <nobr><A HREF="android.support.v4.view.accessibility.AccessibilityManagerCompat.html">AccessibilityManagerCompat</A></nobr>
    ++  </TD>
    ++  <TD>&nbsp;</TD>
    ++</TR>
    ++<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    ++  <TD VALIGN="TOP" WIDTH="25%">
    ++  <A NAME="AccessibilityManagerCompat.AccessibilityStateChangeListenerCompat"></A>
    ++  <nobr><A HREF="android.support.v4.view.accessibility.AccessibilityManagerCompat.AccessibilityStateChangeListenerCompat.html">AccessibilityManagerCompat.<br>AccessibilityStateChangeListenerCompat</A></nobr>
    ++  </TD>
    ++  <TD>&nbsp;</TD>
    ++</TR>
    ++<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    ++  <TD VALIGN="TOP" WIDTH="25%">
    ++  <A NAME="AccessibilityNodeInfoCompat"></A>
    ++  <nobr><A HREF="android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.html">AccessibilityNodeInfoCompat</A></nobr>
    ++  </TD>
    ++  <TD>&nbsp;</TD>
    ++</TR>
    ++<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    ++  <TD VALIGN="TOP" WIDTH="25%">
    ++  <A NAME="AccessibilityNodeInfoCompat.AccessibilityActionCompat"></A>
    ++  <nobr><A HREF="android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat.html">AccessibilityNodeInfoCompat.<br>AccessibilityActionCompat</A></nobr>
    ++  </TD>
    ++  <TD>&nbsp;</TD>
    ++</TR>
    ++<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    ++  <TD VALIGN="TOP" WIDTH="25%">
    ++  <A NAME="AccessibilityNodeInfoCompat.CollectionInfoCompat"></A>
    ++  <nobr><A HREF="android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.CollectionInfoCompat.html">AccessibilityNodeInfoCompat.<br>CollectionInfoCompat</A></nobr>
    ++  </TD>
    ++  <TD>&nbsp;</TD>
    ++</TR>
    ++<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    ++  <TD VALIGN="TOP" WIDTH="25%">
    ++  <A NAME="AccessibilityNodeInfoCompat.CollectionItemInfoCompat"></A>
    ++  <nobr><A HREF="android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.CollectionItemInfoCompat.html">AccessibilityNodeInfoCompat.<br>CollectionItemInfoCompat</A></nobr>
    ++  </TD>
    ++  <TD>&nbsp;</TD>
    ++</TR>
    ++<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    ++  <TD VALIGN="TOP" WIDTH="25%">
    ++  <A NAME="AccessibilityNodeInfoCompat.RangeInfoCompat"></A>
    ++  <nobr><A HREF="android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.RangeInfoCompat.html">AccessibilityNodeInfoCompat.<br>RangeInfoCompat</A></nobr>
    ++  </TD>
    ++  <TD>&nbsp;</TD>
    ++</TR>
    ++<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    ++  <TD VALIGN="TOP" WIDTH="25%">
    ++  <A NAME="AccessibilityNodeProviderCompat"></A>
    ++  <nobr><A HREF="android.support.v4.view.accessibility.AccessibilityNodeProviderCompat.html">AccessibilityNodeProviderCompat</A></nobr>
    ++  </TD>
    ++  <TD>&nbsp;</TD>
    ++</TR>
    ++<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    ++  <TD VALIGN="TOP" WIDTH="25%">
    ++  <A NAME="AccessibilityWindowInfoCompat"></A>
    ++  <nobr><A HREF="android.support.v4.view.accessibility.AccessibilityWindowInfoCompat.html">AccessibilityWindowInfoCompat</A></nobr>
    ++  </TD>
    ++  <TD>&nbsp;</TD>
    ++</TR>
    ++</TABLE>
    ++&nbsp;
    ++      </div>	
    ++      <div id="footer">
    ++        <div id="copyright">
    ++        Except as noted, this content is licensed under 
    ++        <a href="http://creativecommons.org/licenses/by/2.5/"> Creative Commons Attribution 2.5</a>.
    ++        For details and restrictions, see the <a href="/license.html">Content License</a>.
    ++        </div>
    ++      <div id="footerlinks">
    ++      <p>
    ++        <a href="http://www.android.com/terms.html">Site Terms of Service</a> -
    ++        <a href="http://www.android.com/privacy.html">Privacy Policy</a> -
    ++        <a href="http://www.android.com/branding.html">Brand Guidelines</a>
    ++      </p>
    ++    </div>
    ++    </div> <!-- end footer -->
    ++    </div><!-- end doc-content -->
    ++    </div> <!-- end body-content --> 
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    ++</script>
    ++<script type="text/javascript">
    ++  try {
    ++    var pageTracker = _gat._getTracker("UA-5831155-1");
    ++    pageTracker._setAllowAnchor(true);
    ++    pageTracker._initData();
    ++    pageTracker._trackPageview();
    ++  } catch(e) {}
    ++</script>
    ++</BODY>
    ++</HTML>
    +diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/pkg_android.support.v4.view.html b/docs/html/sdk/support_api_diff/24.2.0/changes/pkg_android.support.v4.view.html
    +new file mode 100644
    +index 0000000..d720d41
    +--- /dev/null
    ++++ b/docs/html/sdk/support_api_diff/24.2.0/changes/pkg_android.support.v4.view.html
    +@@ -0,0 +1,147 @@
    ++<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
    ++<HTML style="overflow:auto;">
    ++<HEAD>
    ++<meta name="generator" content="JDiff v1.1.0">
    ++<!-- Generated by the JDiff Javadoc doclet -->
    ++<!-- (http://www.jdiff.org) -->
    ++<meta name="description" content="JDiff is a Javadoc doclet which generates an HTML report of all the packages, classes, constructors, methods, and fields which have been removed, added or changed in any way, including their documentation, when two APIs are compared.">
    ++<meta name="keywords" content="diff, jdiff, javadiff, java diff, java difference, API difference, difference between two APIs, API diff, Javadoc, doclet">
    ++<TITLE>
    ++android.support.v4.view
    ++</TITLE>
    ++<link href="../../../../assets/android-developer-docs.css" rel="stylesheet" type="text/css" />
    ++<link href="../stylesheet-jdiff.css" rel="stylesheet" type="text/css" />
    ++<noscript>
    ++<style type="text/css">
    ++body{overflow:auto;}
    ++#body-content{position:relative; top:0;}
    ++#doc-content{overflow:visible;border-left:3px solid #666;}
    ++#side-nav{padding:0;}
    ++#side-nav .toggle-list ul {display:block;}
    ++#resize-packages-nav{border-bottom:3px solid #666;}
    ++</style>
    ++</noscript>
    ++<style type="text/css">
    ++</style>
    ++</HEAD>
    ++<BODY>
    ++<!-- Start of nav bar -->
    ++<a name="top"></a>
    ++<div id="header" style="margin-bottom:0;padding-bottom:0;">
    ++<div id="headerLeft">
    ++<a href="../../../../index.html" tabindex="-1" target="_top"><img src="../../../../assets/images/bg_logo.png" alt="Android Developers" /></a>
    ++</div>
    ++  <div id="headerRight">
    ++  <div id="headerLinks">
    ++<!-- <img src="/assets/images/icon_world.jpg" alt="" /> -->
    ++<span class="text">
    ++<!-- &nbsp;<a href="#">English</a> | -->
    ++<nobr><a href="http://developer.android.com" target="_top">Android Developers</a> | <a href="http://www.android.com" target="_top">Android.com</a></nobr>
    ++</span>
    ++</div>
    ++  <div class="and-diff-id" style="margin-top:6px;margin-right:8px;">
    ++    <table class="diffspectable">
    ++      <tr>
    ++        <td colspan="2" class="diffspechead">API Diff Specification</td>
    ++      </tr>
    ++      <tr>
    ++        <td class="diffspec" style="padding-top:.25em">To Level:</td>
    ++        <td class="diffvaluenew" style="padding-top:.25em">24.2.0</td>
    ++      </tr>
    ++      <tr>
    ++        <td class="diffspec">From Level:</td>
    ++        <td class="diffvalueold">24.1.0</td>
    ++      </tr>
    ++      <tr>
    ++        <td class="diffspec">Generated</td>
    ++        <td class="diffvalue">2016.08.16 14:03</td>
    ++      </tr>
    ++    </table>
    ++    </div><!-- End and-diff-id -->
    ++  <div class="and-diff-id" style="margin-right:8px;">
    ++    <table class="diffspectable">
    ++      <tr>
    ++        <td class="diffspec" colspan="2"><a href="jdiff_statistics.html">Statistics</a>
    ++      </tr>
    ++    </table>
    ++  </div> <!-- End and-diff-id -->
    ++  </div> <!-- End headerRight -->
    ++  </div> <!-- End header -->
    ++<div id="body-content" xstyle="padding:12px;padding-right:18px;">
    ++<div id="doc-content" style="position:relative;">
    ++<div id="mainBodyFluid">
    ++<H2>
    ++Package <A HREF="../../../../reference/android/support/v4/view/package-summary.html" target="_top"><font size="+1"><code>android.support.v4.view</code></font></A>
    ++</H2>
    ++<p>
    ++<a NAME="Changed"></a>
    ++<TABLE summary="Changed Classes" WIDTH="100%">
    ++<TR>
    ++  <TH VALIGN="TOP" COLSPAN=2>Changed Classes</FONT></TD>
    ++</TH>
    ++<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    ++  <TD VALIGN="TOP" WIDTH="25%">
    ++  <A NAME="KeyEventCompat"></A>
    ++  <nobr><A HREF="android.support.v4.view.KeyEventCompat.html">KeyEventCompat</A></nobr>
    ++  </TD>
    ++  <TD>&nbsp;</TD>
    ++</TR>
    ++<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    ++  <TD VALIGN="TOP" WIDTH="25%">
    ++  <A NAME="MotionEventCompat"></A>
    ++  <nobr><A HREF="android.support.v4.view.MotionEventCompat.html">MotionEventCompat</A></nobr>
    ++  </TD>
    ++  <TD>&nbsp;</TD>
    ++</TR>
    ++<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    ++  <TD VALIGN="TOP" WIDTH="25%">
    ++  <A NAME="ViewCompat"></A>
    ++  <nobr><A HREF="android.support.v4.view.ViewCompat.html">ViewCompat</A></nobr>
    ++  </TD>
    ++  <TD>&nbsp;</TD>
    ++</TR>
    ++<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    ++  <TD VALIGN="TOP" WIDTH="25%">
    ++  <A NAME="ViewConfigurationCompat"></A>
    ++  <nobr><A HREF="android.support.v4.view.ViewConfigurationCompat.html">ViewConfigurationCompat</A></nobr>
    ++  </TD>
    ++  <TD>&nbsp;</TD>
    ++</TR>
    ++<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    ++  <TD VALIGN="TOP" WIDTH="25%">
    ++  <A NAME="WindowInsetsCompat"></A>
    ++  <nobr><A HREF="android.support.v4.view.WindowInsetsCompat.html">WindowInsetsCompat</A></nobr>
    ++  </TD>
    ++  <TD>&nbsp;</TD>
    ++</TR>
    ++</TABLE>
    ++&nbsp;
    ++      </div>	
    ++      <div id="footer">
    ++        <div id="copyright">
    ++        Except as noted, this content is licensed under 
    ++        <a href="http://creativecommons.org/licenses/by/2.5/"> Creative Commons Attribution 2.5</a>.
    ++        For details and restrictions, see the <a href="/license.html">Content License</a>.
    ++        </div>
    ++      <div id="footerlinks">
    ++      <p>
    ++        <a href="http://www.android.com/terms.html">Site Terms of Service</a> -
    ++        <a href="http://www.android.com/privacy.html">Privacy Policy</a> -
    ++        <a href="http://www.android.com/branding.html">Brand Guidelines</a>
    ++      </p>
    ++    </div>
    ++    </div> <!-- end footer -->
    ++    </div><!-- end doc-content -->
    ++    </div> <!-- end body-content --> 
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    ++</script>
    ++<script type="text/javascript">
    ++  try {
    ++    var pageTracker = _gat._getTracker("UA-5831155-1");
    ++    pageTracker._setAllowAnchor(true);
    ++    pageTracker._initData();
    ++    pageTracker._trackPageview();
    ++  } catch(e) {}
    ++</script>
    ++</BODY>
    ++</HTML>
    +diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/pkg_android.support.v4.widget.html b/docs/html/sdk/support_api_diff/24.2.0/changes/pkg_android.support.v4.widget.html
    +new file mode 100644
    +index 0000000..2efef45
    +--- /dev/null
    ++++ b/docs/html/sdk/support_api_diff/24.2.0/changes/pkg_android.support.v4.widget.html
    +@@ -0,0 +1,176 @@
    ++<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
    ++<HTML style="overflow:auto;">
    ++<HEAD>
    ++<meta name="generator" content="JDiff v1.1.0">
    ++<!-- Generated by the JDiff Javadoc doclet -->
    ++<!-- (http://www.jdiff.org) -->
    ++<meta name="description" content="JDiff is a Javadoc doclet which generates an HTML report of all the packages, classes, constructors, methods, and fields which have been removed, added or changed in any way, including their documentation, when two APIs are compared.">
    ++<meta name="keywords" content="diff, jdiff, javadiff, java diff, java difference, API difference, difference between two APIs, API diff, Javadoc, doclet">
    ++<TITLE>
    ++android.support.v4.widget
    ++</TITLE>
    ++<link href="../../../../assets/android-developer-docs.css" rel="stylesheet" type="text/css" />
    ++<link href="../stylesheet-jdiff.css" rel="stylesheet" type="text/css" />
    ++<noscript>
    ++<style type="text/css">
    ++body{overflow:auto;}
    ++#body-content{position:relative; top:0;}
    ++#doc-content{overflow:visible;border-left:3px solid #666;}
    ++#side-nav{padding:0;}
    ++#side-nav .toggle-list ul {display:block;}
    ++#resize-packages-nav{border-bottom:3px solid #666;}
    ++</style>
    ++</noscript>
    ++<style type="text/css">
    ++</style>
    ++</HEAD>
    ++<BODY>
    ++<!-- Start of nav bar -->
    ++<a name="top"></a>
    ++<div id="header" style="margin-bottom:0;padding-bottom:0;">
    ++<div id="headerLeft">
    ++<a href="../../../../index.html" tabindex="-1" target="_top"><img src="../../../../assets/images/bg_logo.png" alt="Android Developers" /></a>
    ++</div>
    ++  <div id="headerRight">
    ++  <div id="headerLinks">
    ++<!-- <img src="/assets/images/icon_world.jpg" alt="" /> -->
    ++<span class="text">
    ++<!-- &nbsp;<a href="#">English</a> | -->
    ++<nobr><a href="http://developer.android.com" target="_top">Android Developers</a> | <a href="http://www.android.com" target="_top">Android.com</a></nobr>
    ++</span>
    ++</div>
    ++  <div class="and-diff-id" style="margin-top:6px;margin-right:8px;">
    ++    <table class="diffspectable">
    ++      <tr>
    ++        <td colspan="2" class="diffspechead">API Diff Specification</td>
    ++      </tr>
    ++      <tr>
    ++        <td class="diffspec" style="padding-top:.25em">To Level:</td>
    ++        <td class="diffvaluenew" style="padding-top:.25em">24.2.0</td>
    ++      </tr>
    ++      <tr>
    ++        <td class="diffspec">From Level:</td>
    ++        <td class="diffvalueold">24.1.0</td>
    ++      </tr>
    ++      <tr>
    ++        <td class="diffspec">Generated</td>
    ++        <td class="diffvalue">2016.08.16 14:03</td>
    ++      </tr>
    ++    </table>
    ++    </div><!-- End and-diff-id -->
    ++  <div class="and-diff-id" style="margin-right:8px;">
    ++    <table class="diffspectable">
    ++      <tr>
    ++        <td class="diffspec" colspan="2"><a href="jdiff_statistics.html">Statistics</a>
    ++      </tr>
    ++    </table>
    ++  </div> <!-- End and-diff-id -->
    ++  </div> <!-- End headerRight -->
    ++  </div> <!-- End header -->
    ++<div id="body-content" xstyle="padding:12px;padding-right:18px;">
    ++<div id="doc-content" style="position:relative;">
    ++<div id="mainBodyFluid">
    ++<H2>
    ++Package <A HREF="../../../../reference/android/support/v4/widget/package-summary.html" target="_top"><font size="+1"><code>android.support.v4.widget</code></font></A>
    ++</H2>
    ++<p>
    ++<a NAME="Added"></a>
    ++<TABLE summary="Added Interfaces" WIDTH="100%">
    ++<TR>
    ++  <TH VALIGN="TOP" COLSPAN=2>Added Interfaces</FONT></TD>
    ++</TH>
    ++<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    ++  <TD VALIGN="TOP" WIDTH="25%">
    ++  <A NAME="SearchViewCompat.OnCloseListener"></A>
    ++  <nobr><A HREF="../../../../reference/android/support/v4/widget/SearchViewCompat.OnCloseListener.html" target="_top"><code><I>SearchViewCompat.OnCloseListener</I></code></A></nobr>
    ++  </TD>
    ++  <TD>&nbsp;</TD>
    ++</TR>
    ++<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    ++  <TD VALIGN="TOP" WIDTH="25%">
    ++  <A NAME="SearchViewCompat.OnQueryTextListener"></A>
    ++  <nobr><A HREF="../../../../reference/android/support/v4/widget/SearchViewCompat.OnQueryTextListener.html" target="_top"><code><I>SearchViewCompat.OnQueryTextListener</I></code></A></nobr>
    ++  </TD>
    ++  <TD>&nbsp;</TD>
    ++</TR>
    ++<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    ++  <TD VALIGN="TOP" WIDTH="25%">
    ++  <A NAME="SwipeRefreshLayout.OnChildScrollUpCallback"></A>
    ++  <nobr><A HREF="../../../../reference/android/support/v4/widget/SwipeRefreshLayout.OnChildScrollUpCallback.html" target="_top"><code><I>SwipeRefreshLayout.OnChildScrollUpCallback</I></code></A></nobr>
    ++  </TD>
    ++  <TD>&nbsp;</TD>
    ++</TR>
    ++</TABLE>
    ++&nbsp;
    ++<p>
    ++<a NAME="Changed"></a>
    ++<TABLE summary="Changed Classes" WIDTH="100%">
    ++<TR>
    ++  <TH VALIGN="TOP" COLSPAN=2>Changed Classes</FONT></TD>
    ++</TH>
    ++<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    ++  <TD VALIGN="TOP" WIDTH="25%">
    ++  <A NAME="SearchViewCompat"></A>
    ++  <nobr><A HREF="android.support.v4.widget.SearchViewCompat.html">SearchViewCompat</A></nobr>
    ++  </TD>
    ++  <TD>&nbsp;</TD>
    ++</TR>
    ++<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    ++  <TD VALIGN="TOP" WIDTH="25%">
    ++  <A NAME="SearchViewCompat.OnCloseListenerCompat"></A>
    ++  <nobr><A HREF="android.support.v4.widget.SearchViewCompat.OnCloseListenerCompat.html">SearchViewCompat.OnCloseListenerCompat</A></nobr>
    ++  </TD>
    ++  <TD>&nbsp;</TD>
    ++</TR>
    ++<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    ++  <TD VALIGN="TOP" WIDTH="25%">
    ++  <A NAME="SearchViewCompat.OnQueryTextListenerCompat"></A>
    ++  <nobr><A HREF="android.support.v4.widget.SearchViewCompat.OnQueryTextListenerCompat.html">SearchViewCompat.OnQueryTextListenerCompat</A></nobr>
    ++  </TD>
    ++  <TD>&nbsp;</TD>
    ++</TR>
    ++<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    ++  <TD VALIGN="TOP" WIDTH="25%">
    ++  <A NAME="SwipeRefreshLayout"></A>
    ++  <nobr><A HREF="android.support.v4.widget.SwipeRefreshLayout.html">SwipeRefreshLayout</A></nobr>
    ++  </TD>
    ++  <TD>&nbsp;</TD>
    ++</TR>
    ++<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    ++  <TD VALIGN="TOP" WIDTH="25%">
    ++  <A NAME="TextViewCompat"></A>
    ++  <nobr><A HREF="android.support.v4.widget.TextViewCompat.html">TextViewCompat</A></nobr>
    ++  </TD>
    ++  <TD>&nbsp;</TD>
    ++</TR>
    ++</TABLE>
    ++&nbsp;
    ++      </div>	
    ++      <div id="footer">
    ++        <div id="copyright">
    ++        Except as noted, this content is licensed under 
    ++        <a href="http://creativecommons.org/licenses/by/2.5/"> Creative Commons Attribution 2.5</a>.
    ++        For details and restrictions, see the <a href="/license.html">Content License</a>.
    ++        </div>
    ++      <div id="footerlinks">
    ++      <p>
    ++        <a href="http://www.android.com/terms.html">Site Terms of Service</a> -
    ++        <a href="http://www.android.com/privacy.html">Privacy Policy</a> -
    ++        <a href="http://www.android.com/branding.html">Brand Guidelines</a>
    ++      </p>
    ++    </div>
    ++    </div> <!-- end footer -->
    ++    </div><!-- end doc-content -->
    ++    </div> <!-- end body-content --> 
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    ++</script>
    ++<script type="text/javascript">
    ++  try {
    ++    var pageTracker = _gat._getTracker("UA-5831155-1");
    ++    pageTracker._setAllowAnchor(true);
    ++    pageTracker._initData();
    ++    pageTracker._trackPageview();
    ++  } catch(e) {}
    ++</script>
    ++</BODY>
    ++</HTML>
    +diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/pkg_android.support.v7.app.html b/docs/html/sdk/support_api_diff/24.2.0/changes/pkg_android.support.v7.app.html
    +new file mode 100644
    +index 0000000..f36cba5
    +--- /dev/null
    ++++ b/docs/html/sdk/support_api_diff/24.2.0/changes/pkg_android.support.v7.app.html
    +@@ -0,0 +1,176 @@
    ++<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
    ++<HTML style="overflow:auto;">
    ++<HEAD>
    ++<meta name="generator" content="JDiff v1.1.0">
    ++<!-- Generated by the JDiff Javadoc doclet -->
    ++<!-- (http://www.jdiff.org) -->
    ++<meta name="description" content="JDiff is a Javadoc doclet which generates an HTML report of all the packages, classes, constructors, methods, and fields which have been removed, added or changed in any way, including their documentation, when two APIs are compared.">
    ++<meta name="keywords" content="diff, jdiff, javadiff, java diff, java difference, API difference, difference between two APIs, API diff, Javadoc, doclet">
    ++<TITLE>
    ++android.support.v7.app
    ++</TITLE>
    ++<link href="../../../../assets/android-developer-docs.css" rel="stylesheet" type="text/css" />
    ++<link href="../stylesheet-jdiff.css" rel="stylesheet" type="text/css" />
    ++<noscript>
    ++<style type="text/css">
    ++body{overflow:auto;}
    ++#body-content{position:relative; top:0;}
    ++#doc-content{overflow:visible;border-left:3px solid #666;}
    ++#side-nav{padding:0;}
    ++#side-nav .toggle-list ul {display:block;}
    ++#resize-packages-nav{border-bottom:3px solid #666;}
    ++</style>
    ++</noscript>
    ++<style type="text/css">
    ++</style>
    ++</HEAD>
    ++<BODY>
    ++<!-- Start of nav bar -->
    ++<a name="top"></a>
    ++<div id="header" style="margin-bottom:0;padding-bottom:0;">
    ++<div id="headerLeft">
    ++<a href="../../../../index.html" tabindex="-1" target="_top"><img src="../../../../assets/images/bg_logo.png" alt="Android Developers" /></a>
    ++</div>
    ++  <div id="headerRight">
    ++  <div id="headerLinks">
    ++<!-- <img src="/assets/images/icon_world.jpg" alt="" /> -->
    ++<span class="text">
    ++<!-- &nbsp;<a href="#">English</a> | -->
    ++<nobr><a href="http://developer.android.com" target="_top">Android Developers</a> | <a href="http://www.android.com" target="_top">Android.com</a></nobr>
    ++</span>
    ++</div>
    ++  <div class="and-diff-id" style="margin-top:6px;margin-right:8px;">
    ++    <table class="diffspectable">
    ++      <tr>
    ++        <td colspan="2" class="diffspechead">API Diff Specification</td>
    ++      </tr>
    ++      <tr>
    ++        <td class="diffspec" style="padding-top:.25em">To Level:</td>
    ++        <td class="diffvaluenew" style="padding-top:.25em">24.2.0</td>
    ++      </tr>
    ++      <tr>
    ++        <td class="diffspec">From Level:</td>
    ++        <td class="diffvalueold">24.1.0</td>
    ++      </tr>
    ++      <tr>
    ++        <td class="diffspec">Generated</td>
    ++        <td class="diffvalue">2016.08.16 14:03</td>
    ++      </tr>
    ++    </table>
    ++    </div><!-- End and-diff-id -->
    ++  <div class="and-diff-id" style="margin-right:8px;">
    ++    <table class="diffspectable">
    ++      <tr>
    ++        <td class="diffspec" colspan="2"><a href="jdiff_statistics.html">Statistics</a>
    ++      </tr>
    ++    </table>
    ++  </div> <!-- End and-diff-id -->
    ++  </div> <!-- End headerRight -->
    ++  </div> <!-- End header -->
    ++<div id="body-content" xstyle="padding:12px;padding-right:18px;">
    ++<div id="doc-content" style="position:relative;">
    ++<div id="mainBodyFluid">
    ++<H2>
    ++Package <A HREF="../../../../reference/android/support/v7/app/package-summary.html" target="_top"><font size="+1"><code>android.support.v7.app</code></font></A>
    ++</H2>
    ++<p>
    ++<a NAME="Added"></a>
    ++<TABLE summary="Added Classes" WIDTH="100%">
    ++<TR>
    ++  <TH VALIGN="TOP" COLSPAN=2>Added Classes</FONT></TD>
    ++</TH>
    ++<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    ++  <TD VALIGN="TOP" WIDTH="25%">
    ++  <A NAME="ActionBarActivity"></A>
    ++  <nobr><A HREF="../../../../reference/android/support/v7/app/ActionBarActivity.html" target="_top"><code>ActionBarActivity</code></A></nobr>
    ++  </TD>
    ++  <TD>&nbsp;</TD>
    ++</TR>
    ++<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    ++  <TD VALIGN="TOP" WIDTH="25%">
    ++  <A NAME="AppCompatActivity"></A>
    ++  <nobr><A HREF="../../../../reference/android/support/v7/app/AppCompatActivity.html" target="_top"><code>AppCompatActivity</code></A></nobr>
    ++  </TD>
    ++  <TD>&nbsp;</TD>
    ++</TR>
    ++<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    ++  <TD VALIGN="TOP" WIDTH="25%">
    ++  <A NAME="AppCompatDialogFragment"></A>
    ++  <nobr><A HREF="../../../../reference/android/support/v7/app/AppCompatDialogFragment.html" target="_top"><code>AppCompatDialogFragment</code></A></nobr>
    ++  </TD>
    ++  <TD>&nbsp;</TD>
    ++</TR>
    ++<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    ++  <TD VALIGN="TOP" WIDTH="25%">
    ++  <A NAME="NotificationCompat"></A>
    ++  <nobr><A HREF="../../../../reference/android/support/v7/app/NotificationCompat.html" target="_top"><code>NotificationCompat</code></A></nobr>
    ++  </TD>
    ++  <TD>&nbsp;</TD>
    ++</TR>
    ++<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    ++  <TD VALIGN="TOP" WIDTH="25%">
    ++  <A NAME="NotificationCompat.Builder"></A>
    ++  <nobr><A HREF="../../../../reference/android/support/v7/app/NotificationCompat.Builder.html" target="_top"><code>NotificationCompat.Builder</code></A></nobr>
    ++  </TD>
    ++  <TD>&nbsp;</TD>
    ++</TR>
    ++<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    ++  <TD VALIGN="TOP" WIDTH="25%">
    ++  <A NAME="NotificationCompat.MediaStyle"></A>
    ++  <nobr><A HREF="../../../../reference/android/support/v7/app/NotificationCompat.MediaStyle.html" target="_top"><code>NotificationCompat.MediaStyle</code></A></nobr>
    ++  </TD>
    ++  <TD>&nbsp;</TD>
    ++</TR>
    ++</TABLE>
    ++&nbsp;
    ++<p>
    ++<a NAME="Changed"></a>
    ++<TABLE summary="Changed Classes" WIDTH="100%">
    ++<TR>
    ++  <TH VALIGN="TOP" COLSPAN=2>Changed Classes</FONT></TD>
    ++</TH>
    ++<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    ++  <TD VALIGN="TOP" WIDTH="25%">
    ++  <A NAME="ActionBarDrawerToggle"></A>
    ++  <nobr><A HREF="android.support.v7.app.ActionBarDrawerToggle.html">ActionBarDrawerToggle</A></nobr>
    ++  </TD>
    ++  <TD>&nbsp;</TD>
    ++</TR>
    ++<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    ++  <TD VALIGN="TOP" WIDTH="25%">
    ++  <A NAME="AppCompatDelegate"></A>
    ++  <nobr><A HREF="android.support.v7.app.AppCompatDelegate.html">AppCompatDelegate</A></nobr>
    ++  </TD>
    ++  <TD>&nbsp;</TD>
    ++</TR>
    ++</TABLE>
    ++&nbsp;
    ++      </div>	
    ++      <div id="footer">
    ++        <div id="copyright">
    ++        Except as noted, this content is licensed under 
    ++        <a href="http://creativecommons.org/licenses/by/2.5/"> Creative Commons Attribution 2.5</a>.
    ++        For details and restrictions, see the <a href="/license.html">Content License</a>.
    ++        </div>
    ++      <div id="footerlinks">
    ++      <p>
    ++        <a href="http://www.android.com/terms.html">Site Terms of Service</a> -
    ++        <a href="http://www.android.com/privacy.html">Privacy Policy</a> -
    ++        <a href="http://www.android.com/branding.html">Brand Guidelines</a>
    ++      </p>
    ++    </div>
    ++    </div> <!-- end footer -->
    ++    </div><!-- end doc-content -->
    ++    </div> <!-- end body-content --> 
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    ++</script>
    ++<script type="text/javascript">
    ++  try {
    ++    var pageTracker = _gat._getTracker("UA-5831155-1");
    ++    pageTracker._setAllowAnchor(true);
    ++    pageTracker._initData();
    ++    pageTracker._trackPageview();
    ++  } catch(e) {}
    ++</script>
    ++</BODY>
    ++</HTML>
    +diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/pkg_android.support.v7.content.res.html b/docs/html/sdk/support_api_diff/24.2.0/changes/pkg_android.support.v7.content.res.html
    +new file mode 100644
    +index 0000000..2e4b703
    +--- /dev/null
    ++++ b/docs/html/sdk/support_api_diff/24.2.0/changes/pkg_android.support.v7.content.res.html
    +@@ -0,0 +1,119 @@
    ++<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
    ++<HTML style="overflow:auto;">
    ++<HEAD>
    ++<meta name="generator" content="JDiff v1.1.0">
    ++<!-- Generated by the JDiff Javadoc doclet -->
    ++<!-- (http://www.jdiff.org) -->
    ++<meta name="description" content="JDiff is a Javadoc doclet which generates an HTML report of all the packages, classes, constructors, methods, and fields which have been removed, added or changed in any way, including their documentation, when two APIs are compared.">
    ++<meta name="keywords" content="diff, jdiff, javadiff, java diff, java difference, API difference, difference between two APIs, API diff, Javadoc, doclet">
    ++<TITLE>
    ++android.support.v7.content.res
    ++</TITLE>
    ++<link href="../../../../assets/android-developer-docs.css" rel="stylesheet" type="text/css" />
    ++<link href="../stylesheet-jdiff.css" rel="stylesheet" type="text/css" />
    ++<noscript>
    ++<style type="text/css">
    ++body{overflow:auto;}
    ++#body-content{position:relative; top:0;}
    ++#doc-content{overflow:visible;border-left:3px solid #666;}
    ++#side-nav{padding:0;}
    ++#side-nav .toggle-list ul {display:block;}
    ++#resize-packages-nav{border-bottom:3px solid #666;}
    ++</style>
    ++</noscript>
    ++<style type="text/css">
    ++</style>
    ++</HEAD>
    ++<BODY>
    ++<!-- Start of nav bar -->
    ++<a name="top"></a>
    ++<div id="header" style="margin-bottom:0;padding-bottom:0;">
    ++<div id="headerLeft">
    ++<a href="../../../../index.html" tabindex="-1" target="_top"><img src="../../../../assets/images/bg_logo.png" alt="Android Developers" /></a>
    ++</div>
    ++  <div id="headerRight">
    ++  <div id="headerLinks">
    ++<!-- <img src="/assets/images/icon_world.jpg" alt="" /> -->
    ++<span class="text">
    ++<!-- &nbsp;<a href="#">English</a> | -->
    ++<nobr><a href="http://developer.android.com" target="_top">Android Developers</a> | <a href="http://www.android.com" target="_top">Android.com</a></nobr>
    ++</span>
    ++</div>
    ++  <div class="and-diff-id" style="margin-top:6px;margin-right:8px;">
    ++    <table class="diffspectable">
    ++      <tr>
    ++        <td colspan="2" class="diffspechead">API Diff Specification</td>
    ++      </tr>
    ++      <tr>
    ++        <td class="diffspec" style="padding-top:.25em">To Level:</td>
    ++        <td class="diffvaluenew" style="padding-top:.25em">24.2.0</td>
    ++      </tr>
    ++      <tr>
    ++        <td class="diffspec">From Level:</td>
    ++        <td class="diffvalueold">24.1.0</td>
    ++      </tr>
    ++      <tr>
    ++        <td class="diffspec">Generated</td>
    ++        <td class="diffvalue">2016.08.16 14:03</td>
    ++      </tr>
    ++    </table>
    ++    </div><!-- End and-diff-id -->
    ++  <div class="and-diff-id" style="margin-right:8px;">
    ++    <table class="diffspectable">
    ++      <tr>
    ++        <td class="diffspec" colspan="2"><a href="jdiff_statistics.html">Statistics</a>
    ++      </tr>
    ++    </table>
    ++  </div> <!-- End and-diff-id -->
    ++  </div> <!-- End headerRight -->
    ++  </div> <!-- End header -->
    ++<div id="body-content" xstyle="padding:12px;padding-right:18px;">
    ++<div id="doc-content" style="position:relative;">
    ++<div id="mainBodyFluid">
    ++<H2>
    ++Package <A HREF="../../../../reference/android/support/v7/content/res/package-summary.html" target="_top"><font size="+1"><code>android.support.v7.content.res</code></font></A>
    ++</H2>
    ++<p>
    ++<a NAME="Changed"></a>
    ++<TABLE summary="Changed Classes" WIDTH="100%">
    ++<TR>
    ++  <TH VALIGN="TOP" COLSPAN=2>Changed Classes</FONT></TD>
    ++</TH>
    ++<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    ++  <TD VALIGN="TOP" WIDTH="25%">
    ++  <A NAME="AppCompatResources"></A>
    ++  <nobr><A HREF="android.support.v7.content.res.AppCompatResources.html">AppCompatResources</A></nobr>
    ++  </TD>
    ++  <TD>&nbsp;</TD>
    ++</TR>
    ++</TABLE>
    ++&nbsp;
    ++      </div>	
    ++      <div id="footer">
    ++        <div id="copyright">
    ++        Except as noted, this content is licensed under 
    ++        <a href="http://creativecommons.org/licenses/by/2.5/"> Creative Commons Attribution 2.5</a>.
    ++        For details and restrictions, see the <a href="/license.html">Content License</a>.
    ++        </div>
    ++      <div id="footerlinks">
    ++      <p>
    ++        <a href="http://www.android.com/terms.html">Site Terms of Service</a> -
    ++        <a href="http://www.android.com/privacy.html">Privacy Policy</a> -
    ++        <a href="http://www.android.com/branding.html">Brand Guidelines</a>
    ++      </p>
    ++    </div>
    ++    </div> <!-- end footer -->
    ++    </div><!-- end doc-content -->
    ++    </div> <!-- end body-content --> 
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    ++</script>
    ++<script type="text/javascript">
    ++  try {
    ++    var pageTracker = _gat._getTracker("UA-5831155-1");
    ++    pageTracker._setAllowAnchor(true);
    ++    pageTracker._initData();
    ++    pageTracker._trackPageview();
    ++  } catch(e) {}
    ++</script>
    ++</BODY>
    ++</HTML>
    +diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/pkg_android.support.v7.graphics.html b/docs/html/sdk/support_api_diff/24.2.0/changes/pkg_android.support.v7.graphics.html
    +new file mode 100644
    +index 0000000..439c8d3
    +--- /dev/null
    ++++ b/docs/html/sdk/support_api_diff/24.2.0/changes/pkg_android.support.v7.graphics.html
    +@@ -0,0 +1,119 @@
    ++<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
    ++<HTML style="overflow:auto;">
    ++<HEAD>
    ++<meta name="generator" content="JDiff v1.1.0">
    ++<!-- Generated by the JDiff Javadoc doclet -->
    ++<!-- (http://www.jdiff.org) -->
    ++<meta name="description" content="JDiff is a Javadoc doclet which generates an HTML report of all the packages, classes, constructors, methods, and fields which have been removed, added or changed in any way, including their documentation, when two APIs are compared.">
    ++<meta name="keywords" content="diff, jdiff, javadiff, java diff, java difference, API difference, difference between two APIs, API diff, Javadoc, doclet">
    ++<TITLE>
    ++android.support.v7.graphics
    ++</TITLE>
    ++<link href="../../../../assets/android-developer-docs.css" rel="stylesheet" type="text/css" />
    ++<link href="../stylesheet-jdiff.css" rel="stylesheet" type="text/css" />
    ++<noscript>
    ++<style type="text/css">
    ++body{overflow:auto;}
    ++#body-content{position:relative; top:0;}
    ++#doc-content{overflow:visible;border-left:3px solid #666;}
    ++#side-nav{padding:0;}
    ++#side-nav .toggle-list ul {display:block;}
    ++#resize-packages-nav{border-bottom:3px solid #666;}
    ++</style>
    ++</noscript>
    ++<style type="text/css">
    ++</style>
    ++</HEAD>
    ++<BODY>
    ++<!-- Start of nav bar -->
    ++<a name="top"></a>
    ++<div id="header" style="margin-bottom:0;padding-bottom:0;">
    ++<div id="headerLeft">
    ++<a href="../../../../index.html" tabindex="-1" target="_top"><img src="../../../../assets/images/bg_logo.png" alt="Android Developers" /></a>
    ++</div>
    ++  <div id="headerRight">
    ++  <div id="headerLinks">
    ++<!-- <img src="/assets/images/icon_world.jpg" alt="" /> -->
    ++<span class="text">
    ++<!-- &nbsp;<a href="#">English</a> | -->
    ++<nobr><a href="http://developer.android.com" target="_top">Android Developers</a> | <a href="http://www.android.com" target="_top">Android.com</a></nobr>
    ++</span>
    ++</div>
    ++  <div class="and-diff-id" style="margin-top:6px;margin-right:8px;">
    ++    <table class="diffspectable">
    ++      <tr>
    ++        <td colspan="2" class="diffspechead">API Diff Specification</td>
    ++      </tr>
    ++      <tr>
    ++        <td class="diffspec" style="padding-top:.25em">To Level:</td>
    ++        <td class="diffvaluenew" style="padding-top:.25em">24.2.0</td>
    ++      </tr>
    ++      <tr>
    ++        <td class="diffspec">From Level:</td>
    ++        <td class="diffvalueold">24.1.0</td>
    ++      </tr>
    ++      <tr>
    ++        <td class="diffspec">Generated</td>
    ++        <td class="diffvalue">2016.08.16 14:03</td>
    ++      </tr>
    ++    </table>
    ++    </div><!-- End and-diff-id -->
    ++  <div class="and-diff-id" style="margin-right:8px;">
    ++    <table class="diffspectable">
    ++      <tr>
    ++        <td class="diffspec" colspan="2"><a href="jdiff_statistics.html">Statistics</a>
    ++      </tr>
    ++    </table>
    ++  </div> <!-- End and-diff-id -->
    ++  </div> <!-- End headerRight -->
    ++  </div> <!-- End header -->
    ++<div id="body-content" xstyle="padding:12px;padding-right:18px;">
    ++<div id="doc-content" style="position:relative;">
    ++<div id="mainBodyFluid">
    ++<H2>
    ++Package <A HREF="../../../../reference/android/support/v7/graphics/package-summary.html" target="_top"><font size="+1"><code>android.support.v7.graphics</code></font></A>
    ++</H2>
    ++<p>
    ++<a NAME="Changed"></a>
    ++<TABLE summary="Changed Classes" WIDTH="100%">
    ++<TR>
    ++  <TH VALIGN="TOP" COLSPAN=2>Changed Classes</FONT></TD>
    ++</TH>
    ++<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    ++  <TD VALIGN="TOP" WIDTH="25%">
    ++  <A NAME="Palette"></A>
    ++  <nobr><A HREF="android.support.v7.graphics.Palette.html">Palette</A></nobr>
    ++  </TD>
    ++  <TD>&nbsp;</TD>
    ++</TR>
    ++</TABLE>
    ++&nbsp;
    ++      </div>	
    ++      <div id="footer">
    ++        <div id="copyright">
    ++        Except as noted, this content is licensed under 
    ++        <a href="http://creativecommons.org/licenses/by/2.5/"> Creative Commons Attribution 2.5</a>.
    ++        For details and restrictions, see the <a href="/license.html">Content License</a>.
    ++        </div>
    ++      <div id="footerlinks">
    ++      <p>
    ++        <a href="http://www.android.com/terms.html">Site Terms of Service</a> -
    ++        <a href="http://www.android.com/privacy.html">Privacy Policy</a> -
    ++        <a href="http://www.android.com/branding.html">Brand Guidelines</a>
    ++      </p>
    ++    </div>
    ++    </div> <!-- end footer -->
    ++    </div><!-- end doc-content -->
    ++    </div> <!-- end body-content --> 
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    ++</script>
    ++<script type="text/javascript">
    ++  try {
    ++    var pageTracker = _gat._getTracker("UA-5831155-1");
    ++    pageTracker._setAllowAnchor(true);
    ++    pageTracker._initData();
    ++    pageTracker._trackPageview();
    ++  } catch(e) {}
    ++</script>
    ++</BODY>
    ++</HTML>
    +diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/pkg_android.support.v7.preference.html b/docs/html/sdk/support_api_diff/24.2.0/changes/pkg_android.support.v7.preference.html
    +new file mode 100644
    +index 0000000..b2b781b
    +--- /dev/null
    ++++ b/docs/html/sdk/support_api_diff/24.2.0/changes/pkg_android.support.v7.preference.html
    +@@ -0,0 +1,119 @@
    ++<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
    ++<HTML style="overflow:auto;">
    ++<HEAD>
    ++<meta name="generator" content="JDiff v1.1.0">
    ++<!-- Generated by the JDiff Javadoc doclet -->
    ++<!-- (http://www.jdiff.org) -->
    ++<meta name="description" content="JDiff is a Javadoc doclet which generates an HTML report of all the packages, classes, constructors, methods, and fields which have been removed, added or changed in any way, including their documentation, when two APIs are compared.">
    ++<meta name="keywords" content="diff, jdiff, javadiff, java diff, java difference, API difference, difference between two APIs, API diff, Javadoc, doclet">
    ++<TITLE>
    ++android.support.v7.preference
    ++</TITLE>
    ++<link href="../../../../assets/android-developer-docs.css" rel="stylesheet" type="text/css" />
    ++<link href="../stylesheet-jdiff.css" rel="stylesheet" type="text/css" />
    ++<noscript>
    ++<style type="text/css">
    ++body{overflow:auto;}
    ++#body-content{position:relative; top:0;}
    ++#doc-content{overflow:visible;border-left:3px solid #666;}
    ++#side-nav{padding:0;}
    ++#side-nav .toggle-list ul {display:block;}
    ++#resize-packages-nav{border-bottom:3px solid #666;}
    ++</style>
    ++</noscript>
    ++<style type="text/css">
    ++</style>
    ++</HEAD>
    ++<BODY>
    ++<!-- Start of nav bar -->
    ++<a name="top"></a>
    ++<div id="header" style="margin-bottom:0;padding-bottom:0;">
    ++<div id="headerLeft">
    ++<a href="../../../../index.html" tabindex="-1" target="_top"><img src="../../../../assets/images/bg_logo.png" alt="Android Developers" /></a>
    ++</div>
    ++  <div id="headerRight">
    ++  <div id="headerLinks">
    ++<!-- <img src="/assets/images/icon_world.jpg" alt="" /> -->
    ++<span class="text">
    ++<!-- &nbsp;<a href="#">English</a> | -->
    ++<nobr><a href="http://developer.android.com" target="_top">Android Developers</a> | <a href="http://www.android.com" target="_top">Android.com</a></nobr>
    ++</span>
    ++</div>
    ++  <div class="and-diff-id" style="margin-top:6px;margin-right:8px;">
    ++    <table class="diffspectable">
    ++      <tr>
    ++        <td colspan="2" class="diffspechead">API Diff Specification</td>
    ++      </tr>
    ++      <tr>
    ++        <td class="diffspec" style="padding-top:.25em">To Level:</td>
    ++        <td class="diffvaluenew" style="padding-top:.25em">24.2.0</td>
    ++      </tr>
    ++      <tr>
    ++        <td class="diffspec">From Level:</td>
    ++        <td class="diffvalueold">24.1.0</td>
    ++      </tr>
    ++      <tr>
    ++        <td class="diffspec">Generated</td>
    ++        <td class="diffvalue">2016.08.16 14:03</td>
    ++      </tr>
    ++    </table>
    ++    </div><!-- End and-diff-id -->
    ++  <div class="and-diff-id" style="margin-right:8px;">
    ++    <table class="diffspectable">
    ++      <tr>
    ++        <td class="diffspec" colspan="2"><a href="jdiff_statistics.html">Statistics</a>
    ++      </tr>
    ++    </table>
    ++  </div> <!-- End and-diff-id -->
    ++  </div> <!-- End headerRight -->
    ++  </div> <!-- End header -->
    ++<div id="body-content" xstyle="padding:12px;padding-right:18px;">
    ++<div id="doc-content" style="position:relative;">
    ++<div id="mainBodyFluid">
    ++<H2>
    ++Package <A HREF="../../../../reference/android/support/v7/preference/package-summary.html" target="_top"><font size="+1"><code>android.support.v7.preference</code></font></A>
    ++</H2>
    ++<p>
    ++<a NAME="Added"></a>
    ++<TABLE summary="Added Classes" WIDTH="100%">
    ++<TR>
    ++  <TH VALIGN="TOP" COLSPAN=2>Added Classes</FONT></TD>
    ++</TH>
    ++<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    ++  <TD VALIGN="TOP" WIDTH="25%">
    ++  <A NAME="MultiSelectListPreferenceDialogFragmentCompat"></A>
    ++  <nobr><A HREF="../../../../reference/android/support/v7/preference/MultiSelectListPreferenceDialogFragmentCompat.html" target="_top"><code>MultiSelectListPreferenceDialogFragmentCompat</code></A></nobr>
    ++  </TD>
    ++  <TD>&nbsp;</TD>
    ++</TR>
    ++</TABLE>
    ++&nbsp;
    ++      </div>	
    ++      <div id="footer">
    ++        <div id="copyright">
    ++        Except as noted, this content is licensed under 
    ++        <a href="http://creativecommons.org/licenses/by/2.5/"> Creative Commons Attribution 2.5</a>.
    ++        For details and restrictions, see the <a href="/license.html">Content License</a>.
    ++        </div>
    ++      <div id="footerlinks">
    ++      <p>
    ++        <a href="http://www.android.com/terms.html">Site Terms of Service</a> -
    ++        <a href="http://www.android.com/privacy.html">Privacy Policy</a> -
    ++        <a href="http://www.android.com/branding.html">Brand Guidelines</a>
    ++      </p>
    ++    </div>
    ++    </div> <!-- end footer -->
    ++    </div><!-- end doc-content -->
    ++    </div> <!-- end body-content --> 
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    ++</script>
    ++<script type="text/javascript">
    ++  try {
    ++    var pageTracker = _gat._getTracker("UA-5831155-1");
    ++    pageTracker._setAllowAnchor(true);
    ++    pageTracker._initData();
    ++    pageTracker._trackPageview();
    ++  } catch(e) {}
    ++</script>
    ++</BODY>
    ++</HTML>
    +diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/pkg_android.support.v7.util.html b/docs/html/sdk/support_api_diff/24.2.0/changes/pkg_android.support.v7.util.html
    +new file mode 100644
    +index 0000000..c35fb8c
    +--- /dev/null
    ++++ b/docs/html/sdk/support_api_diff/24.2.0/changes/pkg_android.support.v7.util.html
    +@@ -0,0 +1,162 @@
    ++<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
    ++<HTML style="overflow:auto;">
    ++<HEAD>
    ++<meta name="generator" content="JDiff v1.1.0">
    ++<!-- Generated by the JDiff Javadoc doclet -->
    ++<!-- (http://www.jdiff.org) -->
    ++<meta name="description" content="JDiff is a Javadoc doclet which generates an HTML report of all the packages, classes, constructors, methods, and fields which have been removed, added or changed in any way, including their documentation, when two APIs are compared.">
    ++<meta name="keywords" content="diff, jdiff, javadiff, java diff, java difference, API difference, difference between two APIs, API diff, Javadoc, doclet">
    ++<TITLE>
    ++android.support.v7.util
    ++</TITLE>
    ++<link href="../../../../assets/android-developer-docs.css" rel="stylesheet" type="text/css" />
    ++<link href="../stylesheet-jdiff.css" rel="stylesheet" type="text/css" />
    ++<noscript>
    ++<style type="text/css">
    ++body{overflow:auto;}
    ++#body-content{position:relative; top:0;}
    ++#doc-content{overflow:visible;border-left:3px solid #666;}
    ++#side-nav{padding:0;}
    ++#side-nav .toggle-list ul {display:block;}
    ++#resize-packages-nav{border-bottom:3px solid #666;}
    ++</style>
    ++</noscript>
    ++<style type="text/css">
    ++</style>
    ++</HEAD>
    ++<BODY>
    ++<!-- Start of nav bar -->
    ++<a name="top"></a>
    ++<div id="header" style="margin-bottom:0;padding-bottom:0;">
    ++<div id="headerLeft">
    ++<a href="../../../../index.html" tabindex="-1" target="_top"><img src="../../../../assets/images/bg_logo.png" alt="Android Developers" /></a>
    ++</div>
    ++  <div id="headerRight">
    ++  <div id="headerLinks">
    ++<!-- <img src="/assets/images/icon_world.jpg" alt="" /> -->
    ++<span class="text">
    ++<!-- &nbsp;<a href="#">English</a> | -->
    ++<nobr><a href="http://developer.android.com" target="_top">Android Developers</a> | <a href="http://www.android.com" target="_top">Android.com</a></nobr>
    ++</span>
    ++</div>
    ++  <div class="and-diff-id" style="margin-top:6px;margin-right:8px;">
    ++    <table class="diffspectable">
    ++      <tr>
    ++        <td colspan="2" class="diffspechead">API Diff Specification</td>
    ++      </tr>
    ++      <tr>
    ++        <td class="diffspec" style="padding-top:.25em">To Level:</td>
    ++        <td class="diffvaluenew" style="padding-top:.25em">24.2.0</td>
    ++      </tr>
    ++      <tr>
    ++        <td class="diffspec">From Level:</td>
    ++        <td class="diffvalueold">24.1.0</td>
    ++      </tr>
    ++      <tr>
    ++        <td class="diffspec">Generated</td>
    ++        <td class="diffvalue">2016.08.16 14:03</td>
    ++      </tr>
    ++    </table>
    ++    </div><!-- End and-diff-id -->
    ++  <div class="and-diff-id" style="margin-right:8px;">
    ++    <table class="diffspectable">
    ++      <tr>
    ++        <td class="diffspec" colspan="2"><a href="jdiff_statistics.html">Statistics</a>
    ++      </tr>
    ++    </table>
    ++  </div> <!-- End and-diff-id -->
    ++  </div> <!-- End headerRight -->
    ++  </div> <!-- End header -->
    ++<div id="body-content" xstyle="padding:12px;padding-right:18px;">
    ++<div id="doc-content" style="position:relative;">
    ++<div id="mainBodyFluid">
    ++<H2>
    ++Package <A HREF="../../../../reference/android/support/v7/util/package-summary.html" target="_top"><font size="+1"><code>android.support.v7.util</code></font></A>
    ++</H2>
    ++<p>
    ++<a NAME="Added"></a>
    ++<TABLE summary="Added Classes and Interfaces" WIDTH="100%">
    ++<TR>
    ++  <TH VALIGN="TOP" COLSPAN=2>Added Classes and Interfaces</FONT></TD>
    ++</TH>
    ++<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    ++  <TD VALIGN="TOP" WIDTH="25%">
    ++  <A NAME="BatchingListUpdateCallback"></A>
    ++  <nobr><A HREF="../../../../reference/android/support/v7/util/BatchingListUpdateCallback.html" target="_top"><code>BatchingListUpdateCallback</code></A></nobr>
    ++  </TD>
    ++  <TD>&nbsp;</TD>
    ++</TR>
    ++<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    ++  <TD VALIGN="TOP" WIDTH="25%">
    ++  <A NAME="DiffUtil"></A>
    ++  <nobr><A HREF="../../../../reference/android/support/v7/util/DiffUtil.html" target="_top"><code>DiffUtil</code></A></nobr>
    ++  </TD>
    ++  <TD>&nbsp;</TD>
    ++</TR>
    ++<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    ++  <TD VALIGN="TOP" WIDTH="25%">
    ++  <A NAME="DiffUtil.Callback"></A>
    ++  <nobr><A HREF="../../../../reference/android/support/v7/util/DiffUtil.Callback.html" target="_top"><code>DiffUtil.Callback</code></A></nobr>
    ++  </TD>
    ++  <TD>&nbsp;</TD>
    ++</TR>
    ++<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    ++  <TD VALIGN="TOP" WIDTH="25%">
    ++  <A NAME="DiffUtil.DiffResult"></A>
    ++  <nobr><A HREF="../../../../reference/android/support/v7/util/DiffUtil.DiffResult.html" target="_top"><code>DiffUtil.DiffResult</code></A></nobr>
    ++  </TD>
    ++  <TD>&nbsp;</TD>
    ++</TR>
    ++<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    ++  <TD VALIGN="TOP" WIDTH="25%">
    ++  <A NAME="ListUpdateCallback"></A>
    ++  <nobr><A HREF="../../../../reference/android/support/v7/util/ListUpdateCallback.html" target="_top"><code><I>ListUpdateCallback</I></code></A></nobr>
    ++  </TD>
    ++  <TD>&nbsp;</TD>
    ++</TR>
    ++</TABLE>
    ++&nbsp;
    ++<p>
    ++<a NAME="Changed"></a>
    ++<TABLE summary="Changed Classes" WIDTH="100%">
    ++<TR>
    ++  <TH VALIGN="TOP" COLSPAN=2>Changed Classes</FONT></TD>
    ++</TH>
    ++<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    ++  <TD VALIGN="TOP" WIDTH="25%">
    ++  <A NAME="SortedList.Callback"></A>
    ++  <nobr><A HREF="android.support.v7.util.SortedList.Callback.html">SortedList.Callback</A></nobr>
    ++  </TD>
    ++  <TD>&nbsp;</TD>
    ++</TR>
    ++</TABLE>
    ++&nbsp;
    ++      </div>	
    ++      <div id="footer">
    ++        <div id="copyright">
    ++        Except as noted, this content is licensed under 
    ++        <a href="http://creativecommons.org/licenses/by/2.5/"> Creative Commons Attribution 2.5</a>.
    ++        For details and restrictions, see the <a href="/license.html">Content License</a>.
    ++        </div>
    ++      <div id="footerlinks">
    ++      <p>
    ++        <a href="http://www.android.com/terms.html">Site Terms of Service</a> -
    ++        <a href="http://www.android.com/privacy.html">Privacy Policy</a> -
    ++        <a href="http://www.android.com/branding.html">Brand Guidelines</a>
    ++      </p>
    ++    </div>
    ++    </div> <!-- end footer -->
    ++    </div><!-- end doc-content -->
    ++    </div> <!-- end body-content --> 
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    ++</script>
    ++<script type="text/javascript">
    ++  try {
    ++    var pageTracker = _gat._getTracker("UA-5831155-1");
    ++    pageTracker._setAllowAnchor(true);
    ++    pageTracker._initData();
    ++    pageTracker._trackPageview();
    ++  } catch(e) {}
    ++</script>
    ++</BODY>
    ++</HTML>
    +diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/pkg_android.support.v7.widget.html b/docs/html/sdk/support_api_diff/24.2.0/changes/pkg_android.support.v7.widget.html
    +new file mode 100644
    +index 0000000..72e5497
    +--- /dev/null
    ++++ b/docs/html/sdk/support_api_diff/24.2.0/changes/pkg_android.support.v7.widget.html
    +@@ -0,0 +1,463 @@
    ++<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
    ++<HTML style="overflow:auto;">
    ++<HEAD>
    ++<meta name="generator" content="JDiff v1.1.0">
    ++<!-- Generated by the JDiff Javadoc doclet -->
    ++<!-- (http://www.jdiff.org) -->
    ++<meta name="description" content="JDiff is a Javadoc doclet which generates an HTML report of all the packages, classes, constructors, methods, and fields which have been removed, added or changed in any way, including their documentation, when two APIs are compared.">
    ++<meta name="keywords" content="diff, jdiff, javadiff, java diff, java difference, API difference, difference between two APIs, API diff, Javadoc, doclet">
    ++<TITLE>
    ++android.support.v7.widget
    ++</TITLE>
    ++<link href="../../../../assets/android-developer-docs.css" rel="stylesheet" type="text/css" />
    ++<link href="../stylesheet-jdiff.css" rel="stylesheet" type="text/css" />
    ++<noscript>
    ++<style type="text/css">
    ++body{overflow:auto;}
    ++#body-content{position:relative; top:0;}
    ++#doc-content{overflow:visible;border-left:3px solid #666;}
    ++#side-nav{padding:0;}
    ++#side-nav .toggle-list ul {display:block;}
    ++#resize-packages-nav{border-bottom:3px solid #666;}
    ++</style>
    ++</noscript>
    ++<style type="text/css">
    ++</style>
    ++</HEAD>
    ++<BODY>
    ++<!-- Start of nav bar -->
    ++<a name="top"></a>
    ++<div id="header" style="margin-bottom:0;padding-bottom:0;">
    ++<div id="headerLeft">
    ++<a href="../../../../index.html" tabindex="-1" target="_top"><img src="../../../../assets/images/bg_logo.png" alt="Android Developers" /></a>
    ++</div>
    ++  <div id="headerRight">
    ++  <div id="headerLinks">
    ++<!-- <img src="/assets/images/icon_world.jpg" alt="" /> -->
    ++<span class="text">
    ++<!-- &nbsp;<a href="#">English</a> | -->
    ++<nobr><a href="http://developer.android.com" target="_top">Android Developers</a> | <a href="http://www.android.com" target="_top">Android.com</a></nobr>
    ++</span>
    ++</div>
    ++  <div class="and-diff-id" style="margin-top:6px;margin-right:8px;">
    ++    <table class="diffspectable">
    ++      <tr>
    ++        <td colspan="2" class="diffspechead">API Diff Specification</td>
    ++      </tr>
    ++      <tr>
    ++        <td class="diffspec" style="padding-top:.25em">To Level:</td>
    ++        <td class="diffvaluenew" style="padding-top:.25em">24.2.0</td>
    ++      </tr>
    ++      <tr>
    ++        <td class="diffspec">From Level:</td>
    ++        <td class="diffvalueold">24.1.0</td>
    ++      </tr>
    ++      <tr>
    ++        <td class="diffspec">Generated</td>
    ++        <td class="diffvalue">2016.08.16 14:03</td>
    ++      </tr>
    ++    </table>
    ++    </div><!-- End and-diff-id -->
    ++  <div class="and-diff-id" style="margin-right:8px;">
    ++    <table class="diffspectable">
    ++      <tr>
    ++        <td class="diffspec" colspan="2"><a href="jdiff_statistics.html">Statistics</a>
    ++      </tr>
    ++    </table>
    ++  </div> <!-- End and-diff-id -->
    ++  </div> <!-- End headerRight -->
    ++  </div> <!-- End header -->
    ++<div id="body-content" xstyle="padding:12px;padding-right:18px;">
    ++<div id="doc-content" style="position:relative;">
    ++<div id="mainBodyFluid">
    ++<H2>
    ++Package <A HREF="../../../../reference/android/support/v7/widget/package-summary.html" target="_top"><font size="+1"><code>android.support.v7.widget</code></font></A>
    ++</H2>
    ++<p>
    ++<a NAME="Added"></a>
    ++<TABLE summary="Added Classes and Interfaces" WIDTH="100%">
    ++<TR>
    ++  <TH VALIGN="TOP" COLSPAN=2>Added Classes and Interfaces</FONT></TD>
    ++</TH>
    ++<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    ++  <TD VALIGN="TOP" WIDTH="25%">
    ++  <A NAME="ActionMenuView"></A>
    ++  <nobr><A HREF="../../../../reference/android/support/v7/widget/ActionMenuView.html" target="_top"><code>ActionMenuView</code></A></nobr>
    ++  </TD>
    ++  <TD>&nbsp;</TD>
    ++</TR>
    ++<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    ++  <TD VALIGN="TOP" WIDTH="25%">
    ++  <A NAME="ActionMenuView.LayoutParams"></A>
    ++  <nobr><A HREF="../../../../reference/android/support/v7/widget/ActionMenuView.LayoutParams.html" target="_top"><code>ActionMenuView.LayoutParams</code></A></nobr>
    ++  </TD>
    ++  <TD>&nbsp;</TD>
    ++</TR>
    ++<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    ++  <TD VALIGN="TOP" WIDTH="25%">
    ++  <A NAME="ActionMenuView.OnMenuItemClickListener"></A>
    ++  <nobr><A HREF="../../../../reference/android/support/v7/widget/ActionMenuView.OnMenuItemClickListener.html" target="_top"><code><I>ActionMenuView.OnMenuItemClickListener</I></code></A></nobr>
    ++  </TD>
    ++  <TD>&nbsp;</TD>
    ++</TR>
    ++<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    ++  <TD VALIGN="TOP" WIDTH="25%">
    ++  <A NAME="AppCompatAutoCompleteTextView"></A>
    ++  <nobr><A HREF="../../../../reference/android/support/v7/widget/AppCompatAutoCompleteTextView.html" target="_top"><code>AppCompatAutoCompleteTextView</code></A></nobr>
    ++  </TD>
    ++  <TD>&nbsp;</TD>
    ++</TR>
    ++<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    ++  <TD VALIGN="TOP" WIDTH="25%">
    ++  <A NAME="AppCompatButton"></A>
    ++  <nobr><A HREF="../../../../reference/android/support/v7/widget/AppCompatButton.html" target="_top"><code>AppCompatButton</code></A></nobr>
    ++  </TD>
    ++  <TD>&nbsp;</TD>
    ++</TR>
    ++<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    ++  <TD VALIGN="TOP" WIDTH="25%">
    ++  <A NAME="AppCompatCheckBox"></A>
    ++  <nobr><A HREF="../../../../reference/android/support/v7/widget/AppCompatCheckBox.html" target="_top"><code>AppCompatCheckBox</code></A></nobr>
    ++  </TD>
    ++  <TD>&nbsp;</TD>
    ++</TR>
    ++<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    ++  <TD VALIGN="TOP" WIDTH="25%">
    ++  <A NAME="AppCompatCheckedTextView"></A>
    ++  <nobr><A HREF="../../../../reference/android/support/v7/widget/AppCompatCheckedTextView.html" target="_top"><code>AppCompatCheckedTextView</code></A></nobr>
    ++  </TD>
    ++  <TD>&nbsp;</TD>
    ++</TR>
    ++<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    ++  <TD VALIGN="TOP" WIDTH="25%">
    ++  <A NAME="AppCompatEditText"></A>
    ++  <nobr><A HREF="../../../../reference/android/support/v7/widget/AppCompatEditText.html" target="_top"><code>AppCompatEditText</code></A></nobr>
    ++  </TD>
    ++  <TD>&nbsp;</TD>
    ++</TR>
    ++<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    ++  <TD VALIGN="TOP" WIDTH="25%">
    ++  <A NAME="AppCompatImageButton"></A>
    ++  <nobr><A HREF="../../../../reference/android/support/v7/widget/AppCompatImageButton.html" target="_top"><code>AppCompatImageButton</code></A></nobr>
    ++  </TD>
    ++  <TD>&nbsp;</TD>
    ++</TR>
    ++<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    ++  <TD VALIGN="TOP" WIDTH="25%">
    ++  <A NAME="AppCompatImageView"></A>
    ++  <nobr><A HREF="../../../../reference/android/support/v7/widget/AppCompatImageView.html" target="_top"><code>AppCompatImageView</code></A></nobr>
    ++  </TD>
    ++  <TD>&nbsp;</TD>
    ++</TR>
    ++<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    ++  <TD VALIGN="TOP" WIDTH="25%">
    ++  <A NAME="AppCompatMultiAutoCompleteTextView"></A>
    ++  <nobr><A HREF="../../../../reference/android/support/v7/widget/AppCompatMultiAutoCompleteTextView.html" target="_top"><code>AppCompatMultiAutoCompleteTextView</code></A></nobr>
    ++  </TD>
    ++  <TD>&nbsp;</TD>
    ++</TR>
    ++<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    ++  <TD VALIGN="TOP" WIDTH="25%">
    ++  <A NAME="AppCompatRadioButton"></A>
    ++  <nobr><A HREF="../../../../reference/android/support/v7/widget/AppCompatRadioButton.html" target="_top"><code>AppCompatRadioButton</code></A></nobr>
    ++  </TD>
    ++  <TD>&nbsp;</TD>
    ++</TR>
    ++<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    ++  <TD VALIGN="TOP" WIDTH="25%">
    ++  <A NAME="AppCompatRatingBar"></A>
    ++  <nobr><A HREF="../../../../reference/android/support/v7/widget/AppCompatRatingBar.html" target="_top"><code>AppCompatRatingBar</code></A></nobr>
    ++  </TD>
    ++  <TD>&nbsp;</TD>
    ++</TR>
    ++<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    ++  <TD VALIGN="TOP" WIDTH="25%">
    ++  <A NAME="AppCompatSeekBar"></A>
    ++  <nobr><A HREF="../../../../reference/android/support/v7/widget/AppCompatSeekBar.html" target="_top"><code>AppCompatSeekBar</code></A></nobr>
    ++  </TD>
    ++  <TD>&nbsp;</TD>
    ++</TR>
    ++<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    ++  <TD VALIGN="TOP" WIDTH="25%">
    ++  <A NAME="AppCompatSpinner"></A>
    ++  <nobr><A HREF="../../../../reference/android/support/v7/widget/AppCompatSpinner.html" target="_top"><code>AppCompatSpinner</code></A></nobr>
    ++  </TD>
    ++  <TD>&nbsp;</TD>
    ++</TR>
    ++<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    ++  <TD VALIGN="TOP" WIDTH="25%">
    ++  <A NAME="AppCompatTextView"></A>
    ++  <nobr><A HREF="../../../../reference/android/support/v7/widget/AppCompatTextView.html" target="_top"><code>AppCompatTextView</code></A></nobr>
    ++  </TD>
    ++  <TD>&nbsp;</TD>
    ++</TR>
    ++<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    ++  <TD VALIGN="TOP" WIDTH="25%">
    ++  <A NAME="CardView"></A>
    ++  <nobr><A HREF="../../../../reference/android/support/v7/widget/CardView.html" target="_top"><code>CardView</code></A></nobr>
    ++  </TD>
    ++  <TD>&nbsp;</TD>
    ++</TR>
    ++<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    ++  <TD VALIGN="TOP" WIDTH="25%">
    ++  <A NAME="GridLayout"></A>
    ++  <nobr><A HREF="../../../../reference/android/support/v7/widget/GridLayout.html" target="_top"><code>GridLayout</code></A></nobr>
    ++  </TD>
    ++  <TD>&nbsp;</TD>
    ++</TR>
    ++<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    ++  <TD VALIGN="TOP" WIDTH="25%">
    ++  <A NAME="GridLayout.Alignment"></A>
    ++  <nobr><A HREF="../../../../reference/android/support/v7/widget/GridLayout.Alignment.html" target="_top"><code>GridLayout.Alignment</code></A></nobr>
    ++  </TD>
    ++  <TD>&nbsp;</TD>
    ++</TR>
    ++<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    ++  <TD VALIGN="TOP" WIDTH="25%">
    ++  <A NAME="GridLayout.LayoutParams"></A>
    ++  <nobr><A HREF="../../../../reference/android/support/v7/widget/GridLayout.LayoutParams.html" target="_top"><code>GridLayout.LayoutParams</code></A></nobr>
    ++  </TD>
    ++  <TD>&nbsp;</TD>
    ++</TR>
    ++<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    ++  <TD VALIGN="TOP" WIDTH="25%">
    ++  <A NAME="GridLayout.Spec"></A>
    ++  <nobr><A HREF="../../../../reference/android/support/v7/widget/GridLayout.Spec.html" target="_top"><code>GridLayout.Spec</code></A></nobr>
    ++  </TD>
    ++  <TD>&nbsp;</TD>
    ++</TR>
    ++<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    ++  <TD VALIGN="TOP" WIDTH="25%">
    ++  <A NAME="LinearLayoutCompat"></A>
    ++  <nobr><A HREF="../../../../reference/android/support/v7/widget/LinearLayoutCompat.html" target="_top"><code>LinearLayoutCompat</code></A></nobr>
    ++  </TD>
    ++  <TD>&nbsp;</TD>
    ++</TR>
    ++<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    ++  <TD VALIGN="TOP" WIDTH="25%">
    ++  <A NAME="LinearLayoutCompat.LayoutParams"></A>
    ++  <nobr><A HREF="../../../../reference/android/support/v7/widget/LinearLayoutCompat.LayoutParams.html" target="_top"><code>LinearLayoutCompat.LayoutParams</code></A></nobr>
    ++  </TD>
    ++  <TD>&nbsp;</TD>
    ++</TR>
    ++<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    ++  <TD VALIGN="TOP" WIDTH="25%">
    ++  <A NAME="LinearSnapHelper"></A>
    ++  <nobr><A HREF="../../../../reference/android/support/v7/widget/LinearSnapHelper.html" target="_top"><code>LinearSnapHelper</code></A></nobr>
    ++  </TD>
    ++  <TD>&nbsp;</TD>
    ++</TR>
    ++<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    ++  <TD VALIGN="TOP" WIDTH="25%">
    ++  <A NAME="ListPopupWindow"></A>
    ++  <nobr><A HREF="../../../../reference/android/support/v7/widget/ListPopupWindow.html" target="_top"><code>ListPopupWindow</code></A></nobr>
    ++  </TD>
    ++  <TD>&nbsp;</TD>
    ++</TR>
    ++<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    ++  <TD VALIGN="TOP" WIDTH="25%">
    ++  <A NAME="PopupMenu"></A>
    ++  <nobr><A HREF="../../../../reference/android/support/v7/widget/PopupMenu.html" target="_top"><code>PopupMenu</code></A></nobr>
    ++  </TD>
    ++  <TD>&nbsp;</TD>
    ++</TR>
    ++<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    ++  <TD VALIGN="TOP" WIDTH="25%">
    ++  <A NAME="PopupMenu.OnDismissListener"></A>
    ++  <nobr><A HREF="../../../../reference/android/support/v7/widget/PopupMenu.OnDismissListener.html" target="_top"><code><I>PopupMenu.OnDismissListener</I></code></A></nobr>
    ++  </TD>
    ++  <TD>&nbsp;</TD>
    ++</TR>
    ++<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    ++  <TD VALIGN="TOP" WIDTH="25%">
    ++  <A NAME="PopupMenu.OnMenuItemClickListener"></A>
    ++  <nobr><A HREF="../../../../reference/android/support/v7/widget/PopupMenu.OnMenuItemClickListener.html" target="_top"><code><I>PopupMenu.OnMenuItemClickListener</I></code></A></nobr>
    ++  </TD>
    ++  <TD>&nbsp;</TD>
    ++</TR>
    ++<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    ++  <TD VALIGN="TOP" WIDTH="25%">
    ++  <A NAME="RecyclerView.OnFlingListener"></A>
    ++  <nobr><A HREF="../../../../reference/android/support/v7/widget/RecyclerView.OnFlingListener.html" target="_top"><code>RecyclerView.OnFlingListener</code></A></nobr>
    ++  </TD>
    ++  <TD>&nbsp;</TD>
    ++</TR>
    ++<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    ++  <TD VALIGN="TOP" WIDTH="25%">
    ++  <A NAME="RecyclerView.SmoothScroller.ScrollVectorProvider"></A>
    ++  <nobr><A HREF="../../../../reference/android/support/v7/widget/RecyclerView.SmoothScroller.ScrollVectorProvider.html" target="_top"><code><I>RecyclerView.SmoothScroller.<br>ScrollVectorProvider</I></code></A></nobr>
    ++  </TD>
    ++  <TD>&nbsp;</TD>
    ++</TR>
    ++<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    ++  <TD VALIGN="TOP" WIDTH="25%">
    ++  <A NAME="SearchView"></A>
    ++  <nobr><A HREF="../../../../reference/android/support/v7/widget/SearchView.html" target="_top"><code>SearchView</code></A></nobr>
    ++  </TD>
    ++  <TD>&nbsp;</TD>
    ++</TR>
    ++<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    ++  <TD VALIGN="TOP" WIDTH="25%">
    ++  <A NAME="SearchView.OnCloseListener"></A>
    ++  <nobr><A HREF="../../../../reference/android/support/v7/widget/SearchView.OnCloseListener.html" target="_top"><code><I>SearchView.OnCloseListener</I></code></A></nobr>
    ++  </TD>
    ++  <TD>&nbsp;</TD>
    ++</TR>
    ++<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    ++  <TD VALIGN="TOP" WIDTH="25%">
    ++  <A NAME="SearchView.OnQueryTextListener"></A>
    ++  <nobr><A HREF="../../../../reference/android/support/v7/widget/SearchView.OnQueryTextListener.html" target="_top"><code><I>SearchView.OnQueryTextListener</I></code></A></nobr>
    ++  </TD>
    ++  <TD>&nbsp;</TD>
    ++</TR>
    ++<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    ++  <TD VALIGN="TOP" WIDTH="25%">
    ++  <A NAME="SearchView.OnSuggestionListener"></A>
    ++  <nobr><A HREF="../../../../reference/android/support/v7/widget/SearchView.OnSuggestionListener.html" target="_top"><code><I>SearchView.OnSuggestionListener</I></code></A></nobr>
    ++  </TD>
    ++  <TD>&nbsp;</TD>
    ++</TR>
    ++<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    ++  <TD VALIGN="TOP" WIDTH="25%">
    ++  <A NAME="ShareActionProvider"></A>
    ++  <nobr><A HREF="../../../../reference/android/support/v7/widget/ShareActionProvider.html" target="_top"><code>ShareActionProvider</code></A></nobr>
    ++  </TD>
    ++  <TD>&nbsp;</TD>
    ++</TR>
    ++<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    ++  <TD VALIGN="TOP" WIDTH="25%">
    ++  <A NAME="ShareActionProvider.OnShareTargetSelectedListener"></A>
    ++  <nobr><A HREF="../../../../reference/android/support/v7/widget/ShareActionProvider.OnShareTargetSelectedListener.html" target="_top"><code><I>ShareActionProvider.OnShareTargetSelectedListener</I></code></A></nobr>
    ++  </TD>
    ++  <TD>&nbsp;</TD>
    ++</TR>
    ++<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    ++  <TD VALIGN="TOP" WIDTH="25%">
    ++  <A NAME="SnapHelper"></A>
    ++  <nobr><A HREF="../../../../reference/android/support/v7/widget/SnapHelper.html" target="_top"><code>SnapHelper</code></A></nobr>
    ++  </TD>
    ++  <TD>&nbsp;</TD>
    ++</TR>
    ++<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    ++  <TD VALIGN="TOP" WIDTH="25%">
    ++  <A NAME="Space"></A>
    ++  <nobr><A HREF="../../../../reference/android/support/v7/widget/Space.html" target="_top"><code>Space</code></A></nobr>
    ++  </TD>
    ++  <TD>&nbsp;</TD>
    ++</TR>
    ++<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    ++  <TD VALIGN="TOP" WIDTH="25%">
    ++  <A NAME="SwitchCompat"></A>
    ++  <nobr><A HREF="../../../../reference/android/support/v7/widget/SwitchCompat.html" target="_top"><code>SwitchCompat</code></A></nobr>
    ++  </TD>
    ++  <TD>&nbsp;</TD>
    ++</TR>
    ++<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    ++  <TD VALIGN="TOP" WIDTH="25%">
    ++  <A NAME="ThemedSpinnerAdapter"></A>
    ++  <nobr><A HREF="../../../../reference/android/support/v7/widget/ThemedSpinnerAdapter.html" target="_top"><code><I>ThemedSpinnerAdapter</I></code></A></nobr>
    ++  </TD>
    ++  <TD>&nbsp;</TD>
    ++</TR>
    ++<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    ++  <TD VALIGN="TOP" WIDTH="25%">
    ++  <A NAME="ThemedSpinnerAdapter.Helper"></A>
    ++  <nobr><A HREF="../../../../reference/android/support/v7/widget/ThemedSpinnerAdapter.Helper.html" target="_top"><code>ThemedSpinnerAdapter.Helper</code></A></nobr>
    ++  </TD>
    ++  <TD>&nbsp;</TD>
    ++</TR>
    ++<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    ++  <TD VALIGN="TOP" WIDTH="25%">
    ++  <A NAME="Toolbar"></A>
    ++  <nobr><A HREF="../../../../reference/android/support/v7/widget/Toolbar.html" target="_top"><code>Toolbar</code></A></nobr>
    ++  </TD>
    ++  <TD>&nbsp;</TD>
    ++</TR>
    ++<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    ++  <TD VALIGN="TOP" WIDTH="25%">
    ++  <A NAME="Toolbar.LayoutParams"></A>
    ++  <nobr><A HREF="../../../../reference/android/support/v7/widget/Toolbar.LayoutParams.html" target="_top"><code>Toolbar.LayoutParams</code></A></nobr>
    ++  </TD>
    ++  <TD>&nbsp;</TD>
    ++</TR>
    ++<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    ++  <TD VALIGN="TOP" WIDTH="25%">
    ++  <A NAME="Toolbar.OnMenuItemClickListener"></A>
    ++  <nobr><A HREF="../../../../reference/android/support/v7/widget/Toolbar.OnMenuItemClickListener.html" target="_top"><code><I>Toolbar.OnMenuItemClickListener</I></code></A></nobr>
    ++  </TD>
    ++  <TD>&nbsp;</TD>
    ++</TR>
    ++<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    ++  <TD VALIGN="TOP" WIDTH="25%">
    ++  <A NAME="Toolbar.SavedState"></A>
    ++  <nobr><A HREF="../../../../reference/android/support/v7/widget/Toolbar.SavedState.html" target="_top"><code>Toolbar.SavedState</code></A></nobr>
    ++  </TD>
    ++  <TD>&nbsp;</TD>
    ++</TR>
    ++</TABLE>
    ++&nbsp;
    ++<p>
    ++<a NAME="Changed"></a>
    ++<TABLE summary="Changed Classes" WIDTH="100%">
    ++<TR>
    ++  <TH VALIGN="TOP" COLSPAN=2>Changed Classes</FONT></TD>
    ++</TH>
    ++<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    ++  <TD VALIGN="TOP" WIDTH="25%">
    ++  <A NAME="LinearLayoutManager"></A>
    ++  <nobr><A HREF="android.support.v7.widget.LinearLayoutManager.html">LinearLayoutManager</A></nobr>
    ++  </TD>
    ++  <TD>&nbsp;</TD>
    ++</TR>
    ++<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    ++  <TD VALIGN="TOP" WIDTH="25%">
    ++  <A NAME="LinearSmoothScroller"></A>
    ++  <nobr><A HREF="android.support.v7.widget.LinearSmoothScroller.html">LinearSmoothScroller</A></nobr>
    ++  </TD>
    ++  <TD>&nbsp;</TD>
    ++</TR>
    ++<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    ++  <TD VALIGN="TOP" WIDTH="25%">
    ++  <A NAME="RecyclerView"></A>
    ++  <nobr><A HREF="android.support.v7.widget.RecyclerView.html">RecyclerView</A></nobr>
    ++  </TD>
    ++  <TD>&nbsp;</TD>
    ++</TR>
    ++<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    ++  <TD VALIGN="TOP" WIDTH="25%">
    ++  <A NAME="StaggeredGridLayoutManager"></A>
    ++  <nobr><A HREF="android.support.v7.widget.StaggeredGridLayoutManager.html">StaggeredGridLayoutManager</A></nobr>
    ++  </TD>
    ++  <TD>&nbsp;</TD>
    ++</TR>
    ++</TABLE>
    ++&nbsp;
    ++      </div>	
    ++      <div id="footer">
    ++        <div id="copyright">
    ++        Except as noted, this content is licensed under 
    ++        <a href="http://creativecommons.org/licenses/by/2.5/"> Creative Commons Attribution 2.5</a>.
    ++        For details and restrictions, see the <a href="/license.html">Content License</a>.
    ++        </div>
    ++      <div id="footerlinks">
    ++      <p>
    ++        <a href="http://www.android.com/terms.html">Site Terms of Service</a> -
    ++        <a href="http://www.android.com/privacy.html">Privacy Policy</a> -
    ++        <a href="http://www.android.com/branding.html">Brand Guidelines</a>
    ++      </p>
    ++    </div>
    ++    </div> <!-- end footer -->
    ++    </div><!-- end doc-content -->
    ++    </div> <!-- end body-content --> 
    ++<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    ++</script>
    ++<script type="text/javascript">
    ++  try {
    ++    var pageTracker = _gat._getTracker("UA-5831155-1");
    ++    pageTracker._setAllowAnchor(true);
    ++    pageTracker._initData();
    ++    pageTracker._trackPageview();
    ++  } catch(e) {}
    ++</script>
    ++</BODY>
    ++</HTML>
    +diff --git a/docs/html/sdk/support_api_diff/24.2.0/missingSinces.txt b/docs/html/sdk/support_api_diff/24.2.0/missingSinces.txt
    +new file mode 100644
    +index 0000000..9514985
    +--- /dev/null
    ++++ b/docs/html/sdk/support_api_diff/24.2.0/missingSinces.txt
    +@@ -0,0 +1,183 @@
    ++NO DOC BLOCK: android.support.v4.view.accessibility.AccessibilityManagerCompat.AccessibilityStateChangeListener Interface
    ++NO DOC BLOCK: android.support.v4.view.accessibility.AccessibilityManagerCompat.TouchExplorationStateChangeListener Interface
    ++NO DOC BLOCK: android.support.v7.app.ActionBarActivity Class
    ++NO DOC BLOCK: android.support.v7.widget.ActionMenuView Class
    ++NO DOC BLOCK: android.support.v7.widget.ActionMenuView.LayoutParams Class
    ++NO DOC BLOCK: android.support.v7.widget.ActionMenuView.OnMenuItemClickListener Interface
    ++NO DOC BLOCK: android.support.v7.app.AppCompatActivity Class
    ++NO DOC BLOCK: android.support.v7.widget.AppCompatAutoCompleteTextView Class
    ++NO DOC BLOCK: android.support.v7.widget.AppCompatButton Class
    ++NO DOC BLOCK: android.support.v7.widget.AppCompatCheckBox Class
    ++NO DOC BLOCK: android.support.v7.widget.AppCompatCheckedTextView Class
    ++NO DOC BLOCK: android.support.v7.app.AppCompatDialogFragment Class
    ++NO DOC BLOCK: android.support.v7.widget.AppCompatEditText Class
    ++NO DOC BLOCK: android.support.v7.widget.AppCompatImageButton Class
    ++NO DOC BLOCK: android.support.v7.widget.AppCompatImageView Class
    ++NO DOC BLOCK: android.support.v7.widget.AppCompatMultiAutoCompleteTextView Class
    ++NO DOC BLOCK: android.support.v7.widget.AppCompatRadioButton Class
    ++NO DOC BLOCK: android.support.v7.widget.AppCompatRatingBar Class
    ++NO DOC BLOCK: android.support.v7.widget.AppCompatSeekBar Class
    ++NO DOC BLOCK: android.support.v7.widget.AppCompatSpinner Class
    ++NO DOC BLOCK: android.support.v7.widget.AppCompatTextView Class
    ++NO DOC BLOCK: android.support.v7.util.BatchingListUpdateCallback Class
    ++NO DOC BLOCK: android.support.v7.widget.CardView Class
    ++NO DOC BLOCK: android.support.v7.util.DiffUtil Class
    ++NO DOC BLOCK: android.support.v7.util.DiffUtil.Callback Class
    ++NO DOC BLOCK: android.support.v7.util.DiffUtil.DiffResult Class
    ++NO DOC BLOCK: android.support.v7.widget.GridLayout Class
    ++NO DOC BLOCK: android.support.v7.widget.GridLayout.Alignment Class
    ++NO DOC BLOCK: android.support.v7.widget.GridLayout.LayoutParams Class
    ++NO DOC BLOCK: android.support.v7.widget.GridLayout.Spec Class
    ++NO DOC BLOCK: android.support.v7.widget.LinearLayoutCompat Class
    ++NO DOC BLOCK: android.support.v7.widget.LinearLayoutCompat.LayoutParams Class
    ++NO DOC BLOCK: android.support.v7.widget.LinearSnapHelper Class
    ++NO DOC BLOCK: android.support.v7.widget.ListPopupWindow Class
    ++NO DOC BLOCK: android.support.v7.util.ListUpdateCallback Interface
    ++NO DOC BLOCK: android.support.v7.preference.MultiSelectListPreferenceDialogFragmentCompat Class
    ++NO DOC BLOCK: android.support.v7.app.NotificationCompat Class
    ++NO DOC BLOCK: android.support.v7.app.NotificationCompat.Builder Class
    ++NO DOC BLOCK: android.support.v7.app.NotificationCompat.MediaStyle Class
    ++NO DOC BLOCK: android.support.v4.util.PatternsCompat Class
    ++NO DOC BLOCK: android.support.v7.widget.PopupMenu Class
    ++NO DOC BLOCK: android.support.v7.widget.PopupMenu.OnDismissListener Interface
    ++NO DOC BLOCK: android.support.v7.widget.PopupMenu.OnMenuItemClickListener Interface
    ++NO DOC BLOCK: android.support.v7.widget.RecyclerView.OnFlingListener Class
    ++NO DOC BLOCK: android.support.v7.widget.RecyclerView.SmoothScroller.ScrollVectorProvider Interface
    ++NO DOC BLOCK: android.support.v7.widget.SearchView Class
    ++NO DOC BLOCK: android.support.v7.widget.SearchView.OnCloseListener Interface
    ++NO DOC BLOCK: android.support.v7.widget.SearchView.OnQueryTextListener Interface
    ++NO DOC BLOCK: android.support.v7.widget.SearchView.OnSuggestionListener Interface
    ++NO DOC BLOCK: android.support.v4.widget.SearchViewCompat.OnCloseListener Interface
    ++NO DOC BLOCK: android.support.v4.widget.SearchViewCompat.OnQueryTextListener Interface
    ++NO DOC BLOCK: android.support.v7.widget.ShareActionProvider Class
    ++NO DOC BLOCK: android.support.v7.widget.ShareActionProvider.OnShareTargetSelectedListener Interface
    ++NO DOC BLOCK: android.support.v4.app.SharedElementCallback.OnSharedElementsReadyListener Interface
    ++NO DOC BLOCK: android.support.v7.widget.SnapHelper Class
    ++NO DOC BLOCK: android.support.v7.widget.Space Class
    ++NO DOC BLOCK: android.support.v4.widget.SwipeRefreshLayout.OnChildScrollUpCallback Interface
    ++NO DOC BLOCK: android.support.v7.widget.SwitchCompat Class
    ++NO DOC BLOCK: android.support.v7.widget.ThemedSpinnerAdapter Interface
    ++NO DOC BLOCK: android.support.v7.widget.ThemedSpinnerAdapter.Helper Class
    ++NO DOC BLOCK: android.support.v7.widget.Toolbar Class
    ++NO DOC BLOCK: android.support.v7.widget.Toolbar.LayoutParams Class
    ++NO DOC BLOCK: android.support.v7.widget.Toolbar.OnMenuItemClickListener Interface
    ++NO DOC BLOCK: android.support.v7.widget.Toolbar.SavedState Class
    ++NO DOC BLOCK: android.support.v4.view.WindowInsetsCompat Constructor (android.support.v4.view.WindowInsetsCompat)
    ++NO DOC BLOCK: android.support.v4.view.accessibility.AccessibilityManagerCompat Method addTouchExplorationStateChangeListener(android.view.accessibility.AccessibilityManager, android.support.v4.view.accessibility.AccessibilityManagerCompat.TouchExplorationStateChangeListener)
    ++NO DOC BLOCK: android.support.v4.media.session.MediaButtonReceiver Method buildMediaButtonPendingIntent(android.content.Context, android.content.ComponentName, long)
    ++NO DOC BLOCK: android.support.v4.media.session.MediaButtonReceiver Method buildMediaButtonPendingIntent(android.content.Context, long)
    ++NO DOC BLOCK: android.support.v4.graphics.drawable.DrawableCompat Method clearColorFilter(android.graphics.drawable.Drawable)
    ++NO DOC BLOCK: android.support.design.widget.TabLayout Method clearOnTabSelectedListeners()
    ++NO DOC BLOCK: android.support.v7.widget.StaggeredGridLayoutManager Method computeScrollVectorForPosition(int)
    ++NO DOC BLOCK: android.support.v4.app.FragmentController Method findFragmentByWho(java.lang.String)
    ++NO DOC BLOCK: android.support.v4.media.MediaBrowserCompat.MediaItem Method fromMediaItem(java.lang.Object)
    ++NO DOC BLOCK: android.support.v4.media.MediaBrowserCompat.MediaItem Method fromMediaItemList(java.util.List<?>)
    ++NO DOC BLOCK: android.support.v4.media.session.MediaSessionCompat Method fromMediaSession(android.content.Context, java.lang.Object)
    ++NO DOC BLOCK: android.support.v4.media.session.MediaSessionCompat.QueueItem Method fromQueueItem(java.lang.Object)
    ++NO DOC BLOCK: android.support.v4.media.session.MediaSessionCompat.QueueItem Method fromQueueItemList(java.util.List<?>)
    ++NO DOC BLOCK: android.support.v4.view.accessibility.AccessibilityEventCompat Method getAction(android.view.accessibility.AccessibilityEvent)
    ++NO DOC BLOCK: android.support.v4.widget.TextViewCompat Method getCompoundDrawablesRelative(android.widget.TextView)
    ++NO DOC BLOCK: android.support.design.widget.CoordinatorLayout Method getDependents(android.view.View)
    ++NO DOC BLOCK: android.support.v7.graphics.Palette Method getDominantColor(int)
    ++NO DOC BLOCK: android.support.v7.graphics.Palette Method getDominantSwatch()
    ++NO DOC BLOCK: android.support.v7.content.res.AppCompatResources Method getDrawable(android.content.Context, int)
    ++NO DOC BLOCK: android.support.v7.app.ActionBarDrawerToggle Method getDrawerArrowDrawable()
    ++NO DOC BLOCK: android.support.design.widget.CoordinatorLayout.Behavior Method getInsetDodgeRect(android.support.design.widget.CoordinatorLayout, V, android.graphics.Rect)
    ++NO DOC BLOCK: android.support.design.widget.FloatingActionButton.Behavior Method getInsetDodgeRect(android.support.design.widget.CoordinatorLayout, android.support.design.widget.FloatingActionButton, android.graphics.Rect)
    ++NO DOC BLOCK: android.support.v4.app.ActivityOptionsCompat Method getLaunchBounds()
    ++NO DOC BLOCK: android.support.v17.leanback.widget.AbstractMediaItemPresenter.ViewHolder Method getMediaItemNumberViewFlipper()
    ++NO DOC BLOCK: android.support.v17.leanback.widget.AbstractMediaItemPresenter.ViewHolder Method getMediaItemPausedView()
    ++NO DOC BLOCK: android.support.v17.leanback.widget.AbstractMediaItemPresenter.ViewHolder Method getMediaItemPlayingView()
    ++NO DOC BLOCK: android.support.v17.leanback.widget.AbstractMediaItemPresenter Method getMediaPlayState(java.lang.Object)
    ++NO DOC BLOCK: android.support.v4.view.accessibility.AccessibilityEventCompat Method getMovementGranularity(android.view.accessibility.AccessibilityEvent)
    ++NO DOC BLOCK: android.support.v7.widget.RecyclerView Method getOnFlingListener()
    ++NO DOC BLOCK: android.support.design.widget.TextInputLayout Method getPasswordVisibilityToggleContentDescription()
    ++NO DOC BLOCK: android.support.design.widget.TextInputLayout Method getPasswordVisibilityToggleDrawable()
    ++NO DOC BLOCK: android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.CollectionInfoCompat Method getSelectionMode()
    ++NO DOC BLOCK: android.support.v4.os.BuildCompat Method isAtLeastNMR1()
    ++NO DOC BLOCK: android.support.design.widget.FloatingActionButton.Behavior Method isAutoHideEnabled()
    ++NO DOC BLOCK: android.support.v4.view.accessibility.AccessibilityNodeInfoCompat Method isContextClickable()
    ++NO DOC BLOCK: android.support.v17.leanback.widget.ObjectAdapter Method isImmediateNotifySupported()
    ++NO DOC BLOCK: android.support.v4.view.ViewCompat Method isImportantForAccessibility(android.view.View)
    ++NO DOC BLOCK: android.support.design.widget.TextInputLayout Method isPasswordVisibilityToggleEnabled()
    ++NO DOC BLOCK: android.support.v4.accessibilityservice.AccessibilityServiceInfoCompat Method loadDescription(android.accessibilityservice.AccessibilityServiceInfo, android.content.pm.PackageManager)
    ++NO DOC BLOCK: android.support.v4.app.ActivityOptionsCompat Method makeBasic()
    ++NO DOC BLOCK: android.support.v4.app.ActivityOptionsCompat Method makeClipRevealAnimation(android.view.View, int, int, int, int)
    ++NO DOC BLOCK: android.support.v4.app.ActivityOptionsCompat Method makeTaskLaunchBehind()
    ++NO DOC BLOCK: android.support.v17.leanback.widget.AbstractMediaItemPresenter.ViewHolder Method notifyPlayStateChanged()
    ++NO DOC BLOCK: android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.CollectionInfoCompat Method obtain(int, int, boolean)
    ++NO DOC BLOCK: android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.CollectionItemInfoCompat Method obtain(int, int, int, int, boolean)
    ++NO DOC BLOCK: android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.RangeInfoCompat Method obtain(int, float, float, float)
    ++NO DOC BLOCK: android.support.design.widget.CoordinatorLayout.Behavior Method onAttachedToLayoutParams(android.support.design.widget.CoordinatorLayout.LayoutParams)
    ++NO DOC BLOCK: android.support.v17.leanback.widget.AbstractMediaItemPresenter Method onBindMediaPlayState(android.support.v17.leanback.widget.AbstractMediaItemPresenter.ViewHolder)
    ++NO DOC BLOCK: android.support.v7.util.SortedList.Callback Method onChanged(int, int, java.lang.Object)
    ++NO DOC BLOCK: android.support.design.widget.CoordinatorLayout.Behavior Method onDetachedFromLayoutParams()
    ++NO DOC BLOCK: android.support.design.widget.AppBarLayout.ScrollingViewBehavior Method onRequestChildRectangleOnScreen(android.support.design.widget.CoordinatorLayout, android.view.View, android.graphics.Rect, boolean)
    ++NO DOC BLOCK: android.support.design.widget.CoordinatorLayout.Behavior Method onRequestChildRectangleOnScreen(android.support.design.widget.CoordinatorLayout, V, android.graphics.Rect, boolean)
    ++NO DOC BLOCK: android.support.v4.app.SharedElementCallback Method onSharedElementsArrived(java.util.List<java.lang.String>, java.util.List<android.view.View>, android.support.v4.app.SharedElementCallback.OnSharedElementsReadyListener)
    ++NO DOC BLOCK: android.support.v7.app.AppCompatDelegate Method onStart()
    ++NO DOC BLOCK: android.support.v17.leanback.widget.AbstractMediaItemPresenter Method onUnbindMediaPlayState(android.support.v17.leanback.widget.AbstractMediaItemPresenter.ViewHolder)
    ++NO DOC BLOCK: android.support.v4.view.accessibility.AccessibilityManagerCompat Method removeTouchExplorationStateChangeListener(android.view.accessibility.AccessibilityManager, android.support.v4.view.accessibility.AccessibilityManagerCompat.TouchExplorationStateChangeListener)
    ++NO DOC BLOCK: android.support.v4.app.ActivityOptionsCompat Method requestUsageTimeReport(android.app.PendingIntent)
    ++NO DOC BLOCK: android.support.v4.view.accessibility.AccessibilityEventCompat Method setAction(android.view.accessibility.AccessibilityEvent, int)
    ++NO DOC BLOCK: android.support.customtabs.CustomTabsIntent Method setAlwaysUseBrowserUI(android.content.Intent)
    ++NO DOC BLOCK: android.support.design.widget.FloatingActionButton.Behavior Method setAutoHideEnabled(boolean)
    ++NO DOC BLOCK: android.support.design.widget.CollapsingToolbarLayout Method setCollapsedTitleTextColor(android.content.res.ColorStateList)
    ++NO DOC BLOCK: android.support.v4.view.accessibility.AccessibilityNodeInfoCompat Method setContextClickable(boolean)
    ++NO DOC BLOCK: android.support.v7.app.ActionBarDrawerToggle Method setDrawerArrowDrawable(android.support.v7.graphics.drawable.DrawerArrowDrawable)
    ++NO DOC BLOCK: android.support.design.widget.CollapsingToolbarLayout Method setExpandedTitleTextColor(android.content.res.ColorStateList)
    ++NO DOC BLOCK: android.support.customtabs.CustomTabsIntent.Builder Method setInstantAppsEnabled(boolean)
    ++NO DOC BLOCK: android.support.v4.app.ActivityOptionsCompat Method setLaunchBounds(android.graphics.Rect)
    ++NO DOC BLOCK: android.support.v4.view.accessibility.AccessibilityEventCompat Method setMovementGranularity(android.view.accessibility.AccessibilityEvent, int)
    ++NO DOC BLOCK: android.support.v4.widget.SwipeRefreshLayout Method setOnChildScrollUpCallback(android.support.v4.widget.SwipeRefreshLayout.OnChildScrollUpCallback)
    ++NO DOC BLOCK: android.support.v7.widget.RecyclerView Method setOnFlingListener(android.support.v7.widget.RecyclerView.OnFlingListener)
    ++NO DOC BLOCK: android.support.design.widget.TextInputLayout Method setPasswordVisibilityToggleContentDescription(int)
    ++NO DOC BLOCK: android.support.design.widget.TextInputLayout Method setPasswordVisibilityToggleContentDescription(java.lang.CharSequence)
    ++NO DOC BLOCK: android.support.design.widget.TextInputLayout Method setPasswordVisibilityToggleDrawable(android.graphics.drawable.Drawable)
    ++NO DOC BLOCK: android.support.design.widget.TextInputLayout Method setPasswordVisibilityToggleDrawable(int)
    ++NO DOC BLOCK: android.support.design.widget.TextInputLayout Method setPasswordVisibilityToggleEnabled(boolean)
    ++NO DOC BLOCK: android.support.design.widget.TextInputLayout Method setPasswordVisibilityToggleTintList(android.content.res.ColorStateList)
    ++NO DOC BLOCK: android.support.design.widget.TextInputLayout Method setPasswordVisibilityToggleTintMode(android.graphics.PorterDuff.Mode)
    ++NO DOC BLOCK: android.support.customtabs.CustomTabsSession Method setSecondaryToolbarViews(android.widget.RemoteViews, int[], android.app.PendingIntent)
    ++NO DOC BLOCK: android.support.v17.leanback.widget.AbstractMediaItemPresenter.ViewHolder Method setSelectedMediaItemNumberView(int)
    ++NO DOC BLOCK: android.support.customtabs.CustomTabsIntent Method shouldAlwaysUseBrowserUI(android.content.Intent)
    ++NO DOC BLOCK: android.support.v4.app.ServiceCompat Method stopForeground(android.app.Service, int)
    ++NO DOC BLOCK: android.support.v4.media.session.PlaybackStateCompat Method toKeyCode(long)
    ++NO DOC BLOCK: android.support.v4.view.accessibility.AccessibilityNodeInfoCompat Field ACTION_ARGUMENT_COLUMN_INT
    ++NO DOC BLOCK: android.support.v4.view.accessibility.AccessibilityNodeInfoCompat Field ACTION_ARGUMENT_PROGRESS_VALUE
    ++NO DOC BLOCK: android.support.v4.view.accessibility.AccessibilityNodeInfoCompat Field ACTION_ARGUMENT_ROW_INT
    ++NO DOC BLOCK: android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat Field ACTION_CONTEXT_CLICK
    ++NO DOC BLOCK: android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat Field ACTION_SCROLL_DOWN
    ++NO DOC BLOCK: android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat Field ACTION_SCROLL_LEFT
    ++NO DOC BLOCK: android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat Field ACTION_SCROLL_RIGHT
    ++NO DOC BLOCK: android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat Field ACTION_SCROLL_TO_POSITION
    ++NO DOC BLOCK: android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat Field ACTION_SCROLL_UP
    ++NO DOC BLOCK: android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat Field ACTION_SET_PROGRESS
    ++NO DOC BLOCK: android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat Field ACTION_SHOW_ON_SCREEN
    ++NO DOC BLOCK: android.support.v4.media.MediaDescriptionCompat Field BT_FOLDER_TYPE_ALBUMS
    ++NO DOC BLOCK: android.support.v4.media.MediaDescriptionCompat Field BT_FOLDER_TYPE_ARTISTS
    ++NO DOC BLOCK: android.support.v4.media.MediaDescriptionCompat Field BT_FOLDER_TYPE_GENRES
    ++NO DOC BLOCK: android.support.v4.media.MediaDescriptionCompat Field BT_FOLDER_TYPE_MIXED
    ++NO DOC BLOCK: android.support.v4.media.MediaDescriptionCompat Field BT_FOLDER_TYPE_PLAYLISTS
    ++NO DOC BLOCK: android.support.v4.media.MediaDescriptionCompat Field BT_FOLDER_TYPE_TITLES
    ++NO DOC BLOCK: android.support.v4.media.MediaDescriptionCompat Field BT_FOLDER_TYPE_YEARS
    ++NO DOC BLOCK: android.support.design.widget.CoordinatorLayout.LayoutParams Field dodgeInsetEdges
    ++NO DOC BLOCK: android.support.v4.media.MediaDescriptionCompat Field EXTRA_BT_FOLDER_TYPE
    ++NO DOC BLOCK: android.support.customtabs.CustomTabsIntent Field EXTRA_ENABLE_INSTANT_APPS
    ++NO DOC BLOCK: android.support.v4.media.MediaBrowserServiceCompat.BrowserRoot Field EXTRA_SUGGESTION_KEYWORDS
    ++NO DOC BLOCK: android.support.v4.app.ActivityOptionsCompat Field EXTRA_USAGE_TIME_REPORT
    ++NO DOC BLOCK: android.support.v4.app.ActivityOptionsCompat Field EXTRA_USAGE_TIME_REPORT_PACKAGES
    ++NO DOC BLOCK: android.support.v4.view.accessibility.AccessibilityNodeProviderCompat Field HOST_VIEW_ID
    ++NO DOC BLOCK: android.support.design.widget.CoordinatorLayout.LayoutParams Field insetEdge
    ++NO DOC BLOCK: android.support.v4.media.MediaMetadataCompat Field METADATA_KEY_BT_FOLDER_TYPE
    ++NO DOC BLOCK: android.support.v4.media.MediaMetadataCompat Field METADATA_KEY_MEDIA_URI
    ++NO DOC BLOCK: android.support.design.widget.BottomSheetBehavior Field PEEK_HEIGHT_AUTO
    ++NO DOC BLOCK: android.support.v17.leanback.widget.AbstractMediaItemPresenter Field PLAY_STATE_INITIAL
    ++NO DOC BLOCK: android.support.v17.leanback.widget.AbstractMediaItemPresenter Field PLAY_STATE_PAUSED
    ++NO DOC BLOCK: android.support.v17.leanback.widget.AbstractMediaItemPresenter Field PLAY_STATE_PLAYING
    ++NO DOC BLOCK: android.support.v4.app.ServiceCompat Field STOP_FOREGROUND_DETACH
    ++NO DOC BLOCK: android.support.v4.app.ServiceCompat Field STOP_FOREGROUND_REMOVE
    ++NO DOC BLOCK: android.support.v4.view.accessibility.AccessibilityEventCompat Field TYPE_ASSIST_READING_CONTEXT
    ++NO DOC BLOCK: android.support.v4.view.accessibility.AccessibilityWindowInfoCompat Field TYPE_SPLIT_SCREEN_DIVIDER
    ++NO DOC BLOCK: android.support.v4.view.accessibility.AccessibilityEventCompat Field TYPE_VIEW_CONTEXT_CLICKED
    ++NO DOC BLOCK: android.support.v4.view.accessibility.AccessibilityEventCompat Field TYPE_WINDOWS_CHANGED
    +diff --git a/docs/html/sdk/support_api_diff/24.2.0/stylesheet-jdiff.css b/docs/html/sdk/support_api_diff/24.2.0/stylesheet-jdiff.css
    +new file mode 100644
    +index 0000000..edafaa3
    +--- /dev/null
    ++++ b/docs/html/sdk/support_api_diff/24.2.0/stylesheet-jdiff.css
    +@@ -0,0 +1,44 @@
    ++
    ++/* (http://www.jdiff.org) */
    ++
    ++div.and-diff-id {border: 1px solid #eee;position:relative;float:right;clear:both;padding:0px;}
    ++table.diffspectable {border:1px;padding:0px;margin:0px;}
    ++.diffspechead {background-color:#eee;}
    ++.diffspectable tr {border:0px;padding:0px;}
    ++.diffspectable td  {background-color:eee;border:0px;font-size:90%;font-weight:normal;padding:0px;padding-left:1px;padding-right:1px;text-align:center;color:777;}
    ++td.diffvalueold {color:orange;background-color:white;border:0px;font-size:80%;font-style:normal;text-align:left;padding:0px;padding-left:1px;padding-right:1px;line-height:.95em;}
    ++td.diffvaluenew {color:green;background-color:white;border:0px;font-size:80%;font-weight:normal;text-align:left;padding:0px;padding-left:1px;padding-right:1px;line-height:.95em;}
    ++td.diffvalue {color:444;background-color:white;border:0px;font-size:80%;font-weight:normal;text-align:left;padding:0px;padding-left:1px;padding-right:1px;line-height:.95em;}
    ++td.diffspec {background-color:white;border:0px;font-size:80%;font-weight:normal;padding:1px;color:444;text-align:right;padding-right:.5em;line-height:.95em;}
    ++tt {font-size:11pt;font-family:monospace;}
    ++.indexHeader {
    ++  font-size:96%;
    ++  line-height:.8em;}
    ++.jdiffIndex td {
    ++  font-size:96%;
    ++  xline-height:.8em;
    ++  padding:2px;
    ++  padding-left:1em;}
    ++.indexText {
    ++  font-size:100%;
    ++  padding-left:1em;}
    ++#indexTableCaption {
    ++  font-size:96%;
    ++  margin-top:.25em;
    ++  margin-bottom:0;
    ++  }
    ++.hiddenlink {
    ++  font-size:96%;
    ++  line-height:.8em;
    ++  text-decoration:none;}
    ++a {
    ++  text-decoration:none;}
    ++a:hover {
    ++  text-decoration:underline;}
    ++.indexBox {
    ++  border: 1px solid red;
    ++  margin:1em 0 0 0;}
    ++.letterIndexHead {
    ++  font-size: 1.5em;font-weight:9;
    ++  margin:0 0 0em 0;
    ++  border: 1px solid red;}
    +diff --git a/docs/html/sdk/support_api_diff/24.2.0/user_comments_for_24.1.0_to_24.2.0.xml b/docs/html/sdk/support_api_diff/24.2.0/user_comments_for_24.1.0_to_24.2.0.xml
    +new file mode 100644
    +index 0000000..5a1bfc6
    +--- /dev/null
    ++++ b/docs/html/sdk/support_api_diff/24.2.0/user_comments_for_24.1.0_to_24.2.0.xml
    +@@ -0,0 +1,1897 @@
    ++<?xml version="1.0" encoding="iso-8859-1" standalone="no"?>
    ++<comments
    ++  xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance'
    ++  xsi:noNamespaceSchemaLocation='comments.xsd'
    ++  name="24.1.0_to_24.2.0"
    ++  jdversion="1.1.0">
    ++
    ++<!-- Use this file to enter an API change description. For example, when you remove a class, 
    ++     you can enter a comment for that class that points developers to the replacement class. 
    ++     You can also provide a change summary for modified API, to give an overview of the changes 
    ++     why they were made, workarounds, etc.  -->
    ++
    ++<!-- When the API diffs report is generated, the comments in this file get added to the tables of 
    ++     removed, added, and modified packages, classes, methods, and fields. This file does not ship 
    ++     with the final report. -->
    ++
    ++<!-- The id attribute in an identifier element identifies the change as noted in the report. 
    ++     An id has the form package[.class[.[ctor|method|field].signature]], where [] indicates optional 
    ++     text. A comment element can have multiple identifier elements, which will will cause the same 
    ++     text to appear at each place in the report, but will be converted to separate comments when the 
    ++     comments file is used. -->
    ++
    ++<!-- HTML tags in the text field will appear in the report. You also need to close p HTML elements, 
    ++     used for paragraphs - see the top-level documentation. -->
    ++
    ++<!-- You can include standard javadoc links in your change descriptions. You can use the @first command  
    ++     to cause jdiff to include the first line of the API documentation. You also need to close p HTML 
    ++     elements, used for paragraphs - see the top-level documentation. -->
    ++
    ++<comment>
    ++  <identifier id="android.support.customtabs"/>
    ++  <text>
    ++    InsertCommentsHere
    ++  </text>
    ++</comment>
    ++<comment>
    ++  <identifier id="android.support.customtabs.CustomTabsIntent"/>
    ++  <text>
    ++    InsertCommentsHere
    ++  </text>
    ++</comment>
    ++<comment>
    ++  <identifier id="android.support.customtabs.CustomTabsIntent.Builder"/>
    ++  <text>
    ++    InsertCommentsHere
    ++  </text>
    ++</comment>
    ++<comment>
    ++  <identifier id="android.support.customtabs.CustomTabsIntent.Builder.setInstantAppsEnabled_added(boolean)"/>
    ++  <text>
    ++    InsertCommentsHere
    ++  </text>
    ++</comment>
    ++<comment>
    ++  <identifier id="android.support.customtabs.CustomTabsIntent.EXTRA_ENABLE_INSTANT_APPS"/>
    ++  <text>
    ++    InsertCommentsHere
    ++  </text>
    ++</comment>
    ++<comment>
    ++  <identifier id="android.support.customtabs.CustomTabsIntent.setAlwaysUseBrowserUI_added(android.content.Intent)"/>
    ++  <text>
    ++    InsertCommentsHere
    ++  </text>
    ++</comment>
    ++<comment>
    ++  <identifier id="android.support.customtabs.CustomTabsIntent.shouldAlwaysUseBrowserUI_added(android.content.Intent)"/>
    ++  <text>
    ++    InsertCommentsHere
    ++  </text>
    ++</comment>
    ++<comment>
    ++  <identifier id="android.support.customtabs.CustomTabsSession"/>
    ++  <text>
    ++    InsertCommentsHere
    ++  </text>
    ++</comment>
    ++<comment>
    ++  <identifier id="android.support.customtabs.CustomTabsSession.setSecondaryToolbarViews_added(android.widget.RemoteViews, int[], android.app.PendingIntent)"/>
    ++  <text>
    ++    InsertCommentsHere
    ++  </text>
    ++</comment>
    ++<comment>
    ++  <identifier id="android.support.customtabs.CustomTabsSession.setToolbarItem_changed(int, android.graphics.Bitmap, java.lang.String)"/>
    ++  <text>
    ++    InsertCommentsHere
    ++  </text>
    ++</comment>
    ++<comment>
    ++  <identifier id="android.support.design.widget"/>
    ++  <text>
    ++    InsertCommentsHere
    ++  </text>
    ++</comment>
    ++<comment>
    ++  <identifier id="android.support.design.widget.AppBarLayout.ScrollingViewBehavior"/>
    ++  <text>
    ++    InsertCommentsHere
    ++  </text>
    ++</comment>
    ++<comment>
    ++  <identifier id="android.support.design.widget.AppBarLayout.ScrollingViewBehavior.onRequestChildRectangleOnScreen_added(android.support.design.widget.CoordinatorLayout, android.view.View, android.graphics.Rect, boolean)"/>
    ++  <text>
    ++    InsertCommentsHere
    ++  </text>
    ++</comment>
    ++<comment>
    ++  <identifier id="android.support.design.widget.BottomSheetBehavior"/>
    ++  <text>
    ++    InsertCommentsHere
    ++  </text>
    ++</comment>
    ++<comment>
    ++  <identifier id="android.support.design.widget.BottomSheetBehavior.PEEK_HEIGHT_AUTO"/>
    ++  <text>
    ++    InsertCommentsHere
    ++  </text>
    ++</comment>
    ++<comment>
    ++  <identifier id="android.support.design.widget.CollapsingToolbarLayout"/>
    ++  <text>
    ++    InsertCommentsHere
    ++  </text>
    ++</comment>
    ++<comment>
    ++  <identifier id="android.support.design.widget.CollapsingToolbarLayout.setCollapsedTitleTextColor_added(android.content.res.ColorStateList)"/>
    ++  <text>
    ++    InsertCommentsHere
    ++  </text>
    ++</comment>
    ++<comment>
    ++  <identifier id="android.support.design.widget.CollapsingToolbarLayout.setExpandedTitleTextColor_added(android.content.res.ColorStateList)"/>
    ++  <text>
    ++    InsertCommentsHere
    ++  </text>
    ++</comment>
    ++<comment>
    ++  <identifier id="android.support.design.widget.CoordinatorLayout"/>
    ++  <text>
    ++    InsertCommentsHere
    ++  </text>
    ++</comment>
    ++<comment>
    ++  <identifier id="android.support.design.widget.CoordinatorLayout.Behavior"/>
    ++  <text>
    ++    InsertCommentsHere
    ++  </text>
    ++</comment>
    ++<comment>
    ++  <identifier id="android.support.design.widget.CoordinatorLayout.Behavior.getInsetDodgeRect_added(android.support.design.widget.CoordinatorLayout, V, android.graphics.Rect)"/>
    ++  <text>
    ++    InsertCommentsHere
    ++  </text>
    ++</comment>
    ++<comment>
    ++  <identifier id="android.support.design.widget.CoordinatorLayout.Behavior.isDirty_changed(android.support.design.widget.CoordinatorLayout, V)"/>
    ++  <text>
    ++    InsertCommentsHere
    ++  </text>
    ++</comment>
    ++<comment>
    ++  <identifier id="android.support.design.widget.CoordinatorLayout.Behavior.onAttachedToLayoutParams_added(android.support.design.widget.CoordinatorLayout.LayoutParams)"/>
    ++  <text>
    ++    InsertCommentsHere
    ++  </text>
    ++</comment>
    ++<comment>
    ++  <identifier id="android.support.design.widget.CoordinatorLayout.Behavior.onDetachedFromLayoutParams_added()"/>
    ++  <text>
    ++    InsertCommentsHere
    ++  </text>
    ++</comment>
    ++<comment>
    ++  <identifier id="android.support.design.widget.CoordinatorLayout.Behavior.onRequestChildRectangleOnScreen_added(android.support.design.widget.CoordinatorLayout, V, android.graphics.Rect, boolean)"/>
    ++  <text>
    ++    InsertCommentsHere
    ++  </text>
    ++</comment>
    ++<comment>
    ++  <identifier id="android.support.design.widget.CoordinatorLayout.LayoutParams"/>
    ++  <text>
    ++    InsertCommentsHere
    ++  </text>
    ++</comment>
    ++<comment>
    ++  <identifier id="android.support.design.widget.CoordinatorLayout.LayoutParams.dodgeInsetEdges"/>
    ++  <text>
    ++    InsertCommentsHere
    ++  </text>
    ++</comment>
    ++<comment>
    ++  <identifier id="android.support.design.widget.CoordinatorLayout.LayoutParams.insetEdge"/>
    ++  <text>
    ++    InsertCommentsHere
    ++  </text>
    ++</comment>
    ++<comment>
    ++  <identifier id="android.support.design.widget.CoordinatorLayout.getDependents_added(android.view.View)"/>
    ++  <text>
    ++    InsertCommentsHere
    ++  </text>
    ++</comment>
    ++<comment>
    ++  <identifier id="android.support.design.widget.FloatingActionButton.Behavior"/>
    ++  <text>
    ++    InsertCommentsHere
    ++  </text>
    ++</comment>
    ++<comment>
    ++  <identifier id="android.support.design.widget.FloatingActionButton.Behavior.getInsetDodgeRect_added(android.support.design.widget.CoordinatorLayout, android.support.design.widget.FloatingActionButton, android.graphics.Rect)"/>
    ++  <text>
    ++    InsertCommentsHere
    ++  </text>
    ++</comment>
    ++<comment>
    ++  <identifier id="android.support.design.widget.FloatingActionButton.Behavior.isAutoHideEnabled_added()"/>
    ++  <text>
    ++    InsertCommentsHere
    ++  </text>
    ++</comment>
    ++<comment>
    ++  <identifier id="android.support.design.widget.FloatingActionButton.Behavior.layoutDependsOn_removed(android.support.design.widget.CoordinatorLayout, android.support.design.widget.FloatingActionButton, android.view.View)"/>
    ++  <text>
    ++    InsertCommentsHere
    ++  </text>
    ++</comment>
    ++<comment>
    ++  <identifier id="android.support.design.widget.FloatingActionButton.Behavior.onDependentViewRemoved_removed(android.support.design.widget.CoordinatorLayout, android.support.design.widget.FloatingActionButton, android.view.View)"/>
    ++  <text>
    ++    InsertCommentsHere
    ++  </text>
    ++</comment>
    ++<comment>
    ++  <identifier id="android.support.design.widget.FloatingActionButton.Behavior.setAutoHideEnabled_added(boolean)"/>
    ++  <text>
    ++    InsertCommentsHere
    ++  </text>
    ++</comment>
    ++<comment>
    ++  <identifier id="android.support.design.widget.TabLayout"/>
    ++  <text>
    ++    InsertCommentsHere
    ++  </text>
    ++</comment>
    ++<comment>
    ++  <identifier id="android.support.design.widget.TabLayout.clearOnTabSelectedListeners_added()"/>
    ++  <text>
    ++    InsertCommentsHere
    ++  </text>
    ++</comment>
    ++<comment>
    ++  <identifier id="android.support.design.widget.TextInputLayout"/>
    ++  <text>
    ++    InsertCommentsHere
    ++  </text>
    ++</comment>
    ++<comment>
    ++  <identifier id="android.support.design.widget.TextInputLayout.getPasswordVisibilityToggleContentDescription_added()"/>
    ++  <text>
    ++    InsertCommentsHere
    ++  </text>
    ++</comment>
    ++<comment>
    ++  <identifier id="android.support.design.widget.TextInputLayout.getPasswordVisibilityToggleDrawable_added()"/>
    ++  <text>
    ++    InsertCommentsHere
    ++  </text>
    ++</comment>
    ++<comment>
    ++  <identifier id="android.support.design.widget.TextInputLayout.isPasswordVisibilityToggleEnabled_added()"/>
    ++  <text>
    ++    InsertCommentsHere
    ++  </text>
    ++</comment>
    ++<comment>
    ++  <identifier id="android.support.design.widget.TextInputLayout.setPasswordVisibilityToggleContentDescription_added(int)"/>
    ++  <text>
    ++    InsertCommentsHere
    ++  </text>
    ++</comment>
    ++<comment>
    ++  <identifier id="android.support.design.widget.TextInputLayout.setPasswordVisibilityToggleContentDescription_added(java.lang.CharSequence)"/>
    ++  <text>
    ++    InsertCommentsHere
    ++  </text>
    ++</comment>
    ++<comment>
    ++  <identifier id="android.support.design.widget.TextInputLayout.setPasswordVisibilityToggleDrawable_added(android.graphics.drawable.Drawable)"/>
    ++  <text>
    ++    InsertCommentsHere
    ++  </text>
    ++</comment>
    ++<comment>
    ++  <identifier id="android.support.design.widget.TextInputLayout.setPasswordVisibilityToggleDrawable_added(int)"/>
    ++  <text>
    ++    InsertCommentsHere
    ++  </text>
    ++</comment>
    ++<comment>
    ++  <identifier id="android.support.design.widget.TextInputLayout.setPasswordVisibilityToggleEnabled_added(boolean)"/>
    ++  <text>
    ++    InsertCommentsHere
    ++  </text>
    ++</comment>
    ++<comment>
    ++  <identifier id="android.support.design.widget.TextInputLayout.setPasswordVisibilityToggleTintList_added(android.content.res.ColorStateList)"/>
    ++  <text>
    ++    InsertCommentsHere
    ++  </text>
    ++</comment>
    ++<comment>
    ++  <identifier id="android.support.design.widget.TextInputLayout.setPasswordVisibilityToggleTintMode_added(android.graphics.PorterDuff.Mode)"/>
    ++  <text>
    ++    InsertCommentsHere
    ++  </text>
    ++</comment>
    ++<comment>
    ++  <identifier id="android.support.transition"/>
    ++  <text>
    ++    InsertCommentsHere
    ++  </text>
    ++</comment>
    ++<comment>
    ++  <identifier id="android.support.v14.preference"/>
    ++  <text>
    ++    InsertCommentsHere
    ++  </text>
    ++</comment>
    ++<comment>
    ++  <identifier id="android.support.v14.preference.PreferenceFragment"/>
    ++  <text>
    ++    InsertCommentsHere
    ++  </text>
    ++</comment>
    ++<comment>
    ++  <identifier id="android.support.v17.leanback.widget"/>
    ++  <text>
    ++    InsertCommentsHere
    ++  </text>
    ++</comment>
    ++<comment>
    ++  <identifier id="android.support.v17.leanback.widget.AbstractMediaItemPresenter"/>
    ++  <text>
    ++    InsertCommentsHere
    ++  </text>
    ++</comment>
    ++<comment>
    ++  <identifier id="android.support.v17.leanback.widget.AbstractMediaItemPresenter.PLAY_STATE_INITIAL"/>
    ++  <text>
    ++    InsertCommentsHere
    ++  </text>
    ++</comment>
    ++<comment>
    ++  <identifier id="android.support.v17.leanback.widget.AbstractMediaItemPresenter.PLAY_STATE_PAUSED"/>
    ++  <text>
    ++    InsertCommentsHere
    ++  </text>
    ++</comment>
    ++<comment>
    ++  <identifier id="android.support.v17.leanback.widget.AbstractMediaItemPresenter.PLAY_STATE_PLAYING"/>
    ++  <text>
    ++    InsertCommentsHere
    ++  </text>
    ++</comment>
    ++<comment>
    ++  <identifier id="android.support.v17.leanback.widget.AbstractMediaItemPresenter.ViewHolder"/>
    ++  <text>
    ++    InsertCommentsHere
    ++  </text>
    ++</comment>
    ++<comment>
    ++  <identifier id="android.support.v17.leanback.widget.AbstractMediaItemPresenter.ViewHolder.getMediaItemNumberViewFlipper_added()"/>
    ++  <text>
    ++    InsertCommentsHere
    ++  </text>
    ++</comment>
    ++<comment>
    ++  <identifier id="android.support.v17.leanback.widget.AbstractMediaItemPresenter.ViewHolder.getMediaItemPausedView_added()"/>
    ++  <text>
    ++    InsertCommentsHere
    ++  </text>
    ++</comment>
    ++<comment>
    ++  <identifier id="android.support.v17.leanback.widget.AbstractMediaItemPresenter.ViewHolder.getMediaItemPlayingView_added()"/>
    ++  <text>
    ++    InsertCommentsHere
    ++  </text>
    ++</comment>
    ++<comment>
    ++  <identifier id="android.support.v17.leanback.widget.AbstractMediaItemPresenter.ViewHolder.notifyPlayStateChanged_added()"/>
    ++  <text>
    ++    InsertCommentsHere
    ++  </text>
    ++</comment>
    ++<comment>
    ++  <identifier id="android.support.v17.leanback.widget.AbstractMediaItemPresenter.ViewHolder.setSelectedMediaItemNumberView_added(int)"/>
    ++  <text>
    ++    InsertCommentsHere
    ++  </text>
    ++</comment>
    ++<comment>
    ++  <identifier id="android.support.v17.leanback.widget.AbstractMediaItemPresenter.getMediaPlayState_added(java.lang.Object)"/>
    ++  <text>
    ++    InsertCommentsHere
    ++  </text>
    ++</comment>
    ++<comment>
    ++  <identifier id="android.support.v17.leanback.widget.AbstractMediaItemPresenter.onBindMediaPlayState_added(android.support.v17.leanback.widget.AbstractMediaItemPresenter.ViewHolder)"/>
    ++  <text>
    ++    InsertCommentsHere
    ++  </text>
    ++</comment>
    ++<comment>
    ++  <identifier id="android.support.v17.leanback.widget.AbstractMediaItemPresenter.onUnbindMediaPlayState_added(android.support.v17.leanback.widget.AbstractMediaItemPresenter.ViewHolder)"/>
    ++  <text>
    ++    InsertCommentsHere
    ++  </text>
    ++</comment>
    ++<comment>
    ++  <identifier id="android.support.v17.leanback.widget.ObjectAdapter"/>
    ++  <text>
    ++    InsertCommentsHere
    ++  </text>
    ++</comment>
    ++<comment>
    ++  <identifier id="android.support.v17.leanback.widget.ObjectAdapter.isImmediateNotifySupported_added()"/>
    ++  <text>
    ++    InsertCommentsHere
    ++  </text>
    ++</comment>
    ++<comment>
    ++  <identifier id="android.support.v17.preference"/>
    ++  <text>
    ++    InsertCommentsHere
    ++  </text>
    ++</comment>
    ++<comment>
    ++  <identifier id="android.support.v17.preference.LeanbackSettingsFragment"/>
    ++  <text>
    ++    InsertCommentsHere
    ++  </text>
    ++</comment>
    ++<comment>
    ++  <identifier id="android.support.v4.accessibilityservice"/>
    ++  <text>
    ++    InsertCommentsHere
    ++  </text>
    ++</comment>
    ++<comment>
    ++  <identifier id="android.support.v4.accessibilityservice.AccessibilityServiceInfoCompat"/>
    ++  <text>
    ++    InsertCommentsHere
    ++  </text>
    ++</comment>
    ++<comment>
    ++  <identifier id="android.support.v4.accessibilityservice.AccessibilityServiceInfoCompat.getDescription_changed(android.accessibilityservice.AccessibilityServiceInfo)"/>
    ++  <text>
    ++    InsertCommentsHere
    ++  </text>
    ++</comment>
    ++<comment>
    ++  <identifier id="android.support.v4.accessibilityservice.AccessibilityServiceInfoCompat.loadDescription_added(android.accessibilityservice.AccessibilityServiceInfo, android.content.pm.PackageManager)"/>
    ++  <text>
    ++    InsertCommentsHere
    ++  </text>
    ++</comment>
    ++<comment>
    ++  <identifier id="android.support.v4.app"/>
    ++  <text>
    ++    InsertCommentsHere
    ++  </text>
    ++</comment>
    ++<comment>
    ++  <identifier id="android.support.v4.app.ActivityCompat"/>
    ++  <text>
    ++    InsertCommentsHere
    ++  </text>
    ++</comment>
    ++<comment>
    ++  <identifier id="android.support.v4.app.ActivityCompat.ctor_changed()"/>
    ++  <text>
    ++    InsertCommentsHere
    ++  </text>
    ++</comment>
    ++<comment>
    ++  <identifier id="android.support.v4.app.ActivityCompat.getReferrer_changed(android.app.Activity)"/>
    ++  <text>
    ++    InsertCommentsHere
    ++  </text>
    ++</comment>
    ++<comment>
    ++  <identifier id="android.support.v4.app.ActivityOptionsCompat"/>
    ++  <text>
    ++    InsertCommentsHere
    ++  </text>
    ++</comment>
    ++<comment>
    ++  <identifier id="android.support.v4.app.ActivityOptionsCompat.EXTRA_USAGE_TIME_REPORT"/>
    ++  <text>
    ++    InsertCommentsHere
    ++  </text>
    ++</comment>
    ++<comment>
    ++  <identifier id="android.support.v4.app.ActivityOptionsCompat.EXTRA_USAGE_TIME_REPORT_PACKAGES"/>
    ++  <text>
    ++    InsertCommentsHere
    ++  </text>
    ++</comment>
    ++<comment>
    ++  <identifier id="android.support.v4.app.ActivityOptionsCompat.getLaunchBounds_added()"/>
    ++  <text>
    ++    InsertCommentsHere
    ++  </text>
    ++</comment>
    ++<comment>
    ++  <identifier id="android.support.v4.app.ActivityOptionsCompat.makeBasic_added()"/>
    ++  <text>
    ++    InsertCommentsHere
    ++  </text>
    ++</comment>
    ++<comment>
    ++  <identifier id="android.support.v4.app.ActivityOptionsCompat.makeClipRevealAnimation_added(android.view.View, int, int, int, int)"/>
    ++  <text>
    ++    InsertCommentsHere
    ++  </text>
    ++</comment>
    ++<comment>
    ++  <identifier id="android.support.v4.app.ActivityOptionsCompat.makeTaskLaunchBehind_added()"/>
    ++  <text>
    ++    InsertCommentsHere
    ++  </text>
    ++</comment>
    ++<comment>
    ++  <identifier id="android.support.v4.app.ActivityOptionsCompat.requestUsageTimeReport_added(android.app.PendingIntent)"/>
    ++  <text>
    ++    InsertCommentsHere
    ++  </text>
    ++</comment>
    ++<comment>
    ++  <identifier id="android.support.v4.app.ActivityOptionsCompat.setLaunchBounds_added(android.graphics.Rect)"/>
    ++  <text>
    ++    InsertCommentsHere
    ++  </text>
    ++</comment>
    ++<comment>
    ++  <identifier id="android.support.v4.app.FragmentController"/>
    ++  <text>
    ++    InsertCommentsHere
    ++  </text>
    ++</comment>
    ++<comment>
    ++  <identifier id="android.support.v4.app.FragmentController.findFragmentByWho_added(java.lang.String)"/>
    ++  <text>
    ++    InsertCommentsHere
    ++  </text>
    ++</comment>
    ++<comment>
    ++  <identifier id="android.support.v4.app.ServiceCompat"/>
    ++  <text>
    ++    InsertCommentsHere
    ++  </text>
    ++</comment>
    ++<comment>
    ++  <identifier id="android.support.v4.app.ServiceCompat.STOP_FOREGROUND_DETACH"/>
    ++  <text>
    ++    InsertCommentsHere
    ++  </text>
    ++</comment>
    ++<comment>
    ++  <identifier id="android.support.v4.app.ServiceCompat.STOP_FOREGROUND_REMOVE"/>
    ++  <text>
    ++    InsertCommentsHere
    ++  </text>
    ++</comment>
    ++<comment>
    ++  <identifier id="android.support.v4.app.ServiceCompat.stopForeground_added(android.app.Service, int)"/>
    ++  <text>
    ++    InsertCommentsHere
    ++  </text>
    ++</comment>
    ++<comment>
    ++  <identifier id="android.support.v4.app.SharedElementCallback"/>
    ++  <text>
    ++    InsertCommentsHere
    ++  </text>
    ++</comment>
    ++<comment>
    ++  <identifier id="android.support.v4.app.SharedElementCallback.OnSharedElementsReadyListener"/>
    ++  <text>
    ++    InsertCommentsHere
    ++  </text>
    ++</comment>
    ++<comment>
    ++  <identifier id="android.support.v4.app.SharedElementCallback.onSharedElementsArrived_added(java.util.List&lt;java.lang.String&gt;, java.util.List&lt;android.view.View&gt;, android.support.v4.app.SharedElementCallback.OnSharedElementsReadyListener)"/>
    ++  <text>
    ++    InsertCommentsHere
    ++  </text>
    ++</comment>
    ++<comment>
    ++  <identifier id="android.support.v4.content"/>
    ++  <text>
    ++    InsertCommentsHere
    ++  </text>
    ++</comment>
    ++<comment>
    ++  <identifier id="android.support.v4.content.ContextCompat"/>
    ++  <text>
    ++    InsertCommentsHere
    ++  </text>
    ++</comment>
    ++<comment>
    ++  <identifier id="android.support.v4.content.ContextCompat.ctor_changed()"/>
    ++  <text>
    ++    InsertCommentsHere
    ++  </text>
    ++</comment>
    ++<comment>
    ++  <identifier id="android.support.v4.graphics.drawable"/>
    ++  <text>
    ++    InsertCommentsHere
    ++  </text>
    ++</comment>
    ++<comment>
    ++  <identifier id="android.support.v4.graphics.drawable.DrawableCompat"/>
    ++  <text>
    ++    InsertCommentsHere
    ++  </text>
    ++</comment>
    ++<comment>
    ++  <identifier id="android.support.v4.graphics.drawable.DrawableCompat.clearColorFilter_added(android.graphics.drawable.Drawable)"/>
    ++  <text>
    ++    InsertCommentsHere
    ++  </text>
    ++</comment>
    ++<comment>
    ++  <identifier id="android.support.v4.media"/>
    ++  <text>
    ++    InsertCommentsHere
    ++  </text>
    ++</comment>
    ++<comment>
    ++  <identifier id="android.support.v4.media.MediaBrowserCompat.MediaItem"/>
    ++  <text>
    ++    InsertCommentsHere
    ++  </text>
    ++</comment>
    ++<comment>
    ++  <identifier id="android.support.v4.media.MediaBrowserCompat.MediaItem.fromMediaItemList_added(java.util.List&lt;?&gt;)"/>
    ++  <text>
    ++    InsertCommentsHere
    ++  </text>
    ++</comment>
    ++<comment>
    ++  <identifier id="android.support.v4.media.MediaBrowserCompat.MediaItem.fromMediaItem_added(java.lang.Object)"/>
    ++  <text>
    ++    InsertCommentsHere
    ++  </text>
    ++</comment>
    ++<comment>
    ++  <identifier id="android.support.v4.media.MediaBrowserServiceCompat.BrowserRoot"/>
    ++  <text>
    ++    InsertCommentsHere
    ++  </text>
    ++</comment>
    ++<comment>
    ++  <identifier id="android.support.v4.media.MediaBrowserServiceCompat.BrowserRoot.EXTRA_SUGGESTION_KEYWORDS"/>
    ++  <text>
    ++    InsertCommentsHere
    ++  </text>
    ++</comment>
    ++<comment>
    ++  <identifier id="android.support.v4.media.MediaDescriptionCompat"/>
    ++  <text>
    ++    InsertCommentsHere
    ++  </text>
    ++</comment>
    ++<comment>
    ++  <identifier id="android.support.v4.media.MediaDescriptionCompat.BT_FOLDER_TYPE_ALBUMS"/>
    ++  <text>
    ++    InsertCommentsHere
    ++  </text>
    ++</comment>
    ++<comment>
    ++  <identifier id="android.support.v4.media.MediaDescriptionCompat.BT_FOLDER_TYPE_ARTISTS"/>
    ++  <text>
    ++    InsertCommentsHere
    ++  </text>
    ++</comment>
    ++<comment>
    ++  <identifier id="android.support.v4.media.MediaDescriptionCompat.BT_FOLDER_TYPE_GENRES"/>
    ++  <text>
    ++    InsertCommentsHere
    ++  </text>
    ++</comment>
    ++<comment>
    ++  <identifier id="android.support.v4.media.MediaDescriptionCompat.BT_FOLDER_TYPE_MIXED"/>
    ++  <text>
    ++    InsertCommentsHere
    ++  </text>
    ++</comment>
    ++<comment>
    ++  <identifier id="android.support.v4.media.MediaDescriptionCompat.BT_FOLDER_TYPE_PLAYLISTS"/>
    ++  <text>
    ++    InsertCommentsHere
    ++  </text>
    ++</comment>
    ++<comment>
    ++  <identifier id="android.support.v4.media.MediaDescriptionCompat.BT_FOLDER_TYPE_TITLES"/>
    ++  <text>
    ++    InsertCommentsHere
    ++  </text>
    ++</comment>
    ++<comment>
    ++  <identifier id="android.support.v4.media.MediaDescriptionCompat.BT_FOLDER_TYPE_YEARS"/>
    ++  <text>
    ++    InsertCommentsHere
    ++  </text>
    ++</comment>
    ++<comment>
    ++  <identifier id="android.support.v4.media.MediaDescriptionCompat.EXTRA_BT_FOLDER_TYPE"/>
    ++  <text>
    ++    InsertCommentsHere
    ++  </text>
    ++</comment>
    ++<comment>
    ++  <identifier id="android.support.v4.media.MediaMetadataCompat"/>
    ++  <text>
    ++    InsertCommentsHere
    ++  </text>
    ++</comment>
    ++<comment>
    ++  <identifier id="android.support.v4.media.MediaMetadataCompat.METADATA_KEY_BT_FOLDER_TYPE"/>
    ++  <text>
    ++    InsertCommentsHere
    ++  </text>
    ++</comment>
    ++<comment>
    ++  <identifier id="android.support.v4.media.MediaMetadataCompat.METADATA_KEY_MEDIA_URI"/>
    ++  <text>
    ++    InsertCommentsHere
    ++  </text>
    ++</comment>
    ++<comment>
    ++  <identifier id="android.support.v4.media.session"/>
    ++  <text>
    ++    InsertCommentsHere
    ++  </text>
    ++</comment>
    ++<comment>
    ++  <identifier id="android.support.v4.media.session.MediaButtonReceiver"/>
    ++  <text>
    ++    InsertCommentsHere
    ++  </text>
    ++</comment>
    ++<comment>
    ++  <identifier id="android.support.v4.media.session.MediaButtonReceiver.buildMediaButtonPendingIntent_added(android.content.Context, android.content.ComponentName, long)"/>
    ++  <text>
    ++    InsertCommentsHere
    ++  </text>
    ++</comment>
    ++<comment>
    ++  <identifier id="android.support.v4.media.session.MediaButtonReceiver.buildMediaButtonPendingIntent_added(android.content.Context, long)"/>
    ++  <text>
    ++    InsertCommentsHere
    ++  </text>
    ++</comment>
    ++<comment>
    ++  <identifier id="android.support.v4.media.session.MediaSessionCompat"/>
    ++  <text>
    ++    InsertCommentsHere
    ++  </text>
    ++</comment>
    ++<comment>
    ++  <identifier id="android.support.v4.media.session.MediaSessionCompat.QueueItem"/>
    ++  <text>
    ++    InsertCommentsHere
    ++  </text>
    ++</comment>
    ++<comment>
    ++  <identifier id="android.support.v4.media.session.MediaSessionCompat.QueueItem.fromQueueItemList_added(java.util.List&lt;?&gt;)"/>
    ++  <text>
    ++    InsertCommentsHere
    ++  </text>
    ++</comment>
    ++<comment>
    ++  <identifier id="android.support.v4.media.session.MediaSessionCompat.QueueItem.fromQueueItem_added(java.lang.Object)"/>
    ++  <text>
    ++    InsertCommentsHere
    ++  </text>
    ++</comment>
    ++<comment>
    ++  <identifier id="android.support.v4.media.session.MediaSessionCompat.QueueItem.obtain_changed(java.lang.Object)"/>
    ++  <text>
    ++    InsertCommentsHere
    ++  </text>
    ++</comment>
    ++<comment>
    ++  <identifier id="android.support.v4.media.session.MediaSessionCompat.fromMediaSession_added(android.content.Context, java.lang.Object)"/>
    ++  <text>
    ++    InsertCommentsHere
    ++  </text>
    ++</comment>
    ++<comment>
    ++  <identifier id="android.support.v4.media.session.MediaSessionCompat.obtain_changed(android.content.Context, java.lang.Object)"/>
    ++  <text>
    ++    InsertCommentsHere
    ++  </text>
    ++</comment>
    ++<comment>
    ++  <identifier id="android.support.v4.media.session.PlaybackStateCompat"/>
    ++  <text>
    ++    InsertCommentsHere
    ++  </text>
    ++</comment>
    ++<comment>
    ++  <identifier id="android.support.v4.media.session.PlaybackStateCompat.toKeyCode_added(long)"/>
    ++  <text>
    ++    InsertCommentsHere
    ++  </text>
    ++</comment>
    ++<comment>
    ++  <identifier id="android.support.v4.os"/>
    ++  <text>
    ++    InsertCommentsHere
    ++  </text>
    ++</comment>
    ++<comment>
    ++  <identifier id="android.support.v4.os.BuildCompat"/>
    ++  <text>
    ++    InsertCommentsHere
    ++  </text>
    ++</comment>
    ++<comment>
    ++  <identifier id="android.support.v4.os.BuildCompat.isAtLeastNMR1_added()"/>
    ++  <text>
    ++    InsertCommentsHere
    ++  </text>
    ++</comment>
    ++<comment>
    ++  <identifier id="android.support.v4.text.util"/>
    ++  <text>
    ++    InsertCommentsHere
    ++  </text>
    ++</comment>
    ++<comment>
    ++  <identifier id="android.support.v4.util"/>
    ++  <text>
    ++    InsertCommentsHere
    ++  </text>
    ++</comment>
    ++<comment>
    ++  <identifier id="android.support.v4.util.PatternsCompat"/>
    ++  <text>
    ++    InsertCommentsHere
    ++  </text>
    ++</comment>
    ++<comment>
    ++  <identifier id="android.support.v4.view"/>
    ++  <text>
    ++    InsertCommentsHere
    ++  </text>
    ++</comment>
    ++<comment>
    ++  <identifier id="android.support.v4.view.KeyEventCompat"/>
    ++  <text>
    ++    InsertCommentsHere
    ++  </text>
    ++</comment>
    ++<comment>
    ++  <identifier id="android.support.v4.view.KeyEventCompat.dispatch_changed(android.view.KeyEvent, android.view.KeyEvent.Callback, java.lang.Object, java.lang.Object)"/>
    ++  <text>
    ++    InsertCommentsHere
    ++  </text>
    ++</comment>
    ++<comment>
    ++  <identifier id="android.support.v4.view.KeyEventCompat.getKeyDispatcherState_changed(android.view.View)"/>
    ++  <text>
    ++    InsertCommentsHere
    ++  </text>
    ++</comment>
    ++<comment>
    ++  <identifier id="android.support.v4.view.KeyEventCompat.isTracking_changed(android.view.KeyEvent)"/>
    ++  <text>
    ++    InsertCommentsHere
    ++  </text>
    ++</comment>
    ++<comment>
    ++  <identifier id="android.support.v4.view.KeyEventCompat.startTracking_changed(android.view.KeyEvent)"/>
    ++  <text>
    ++    InsertCommentsHere
    ++  </text>
    ++</comment>
    ++<comment>
    ++  <identifier id="android.support.v4.view.MotionEventCompat"/>
    ++  <text>
    ++    InsertCommentsHere
    ++  </text>
    ++</comment>
    ++<comment>
    ++  <identifier id="android.support.v4.view.MotionEventCompat.findPointerIndex_changed(android.view.MotionEvent, int)"/>
    ++  <text>
    ++    InsertCommentsHere
    ++  </text>
    ++</comment>
    ++<comment>
    ++  <identifier id="android.support.v4.view.MotionEventCompat.getPointerCount_changed(android.view.MotionEvent)"/>
    ++  <text>
    ++    InsertCommentsHere
    ++  </text>
    ++</comment>
    ++<comment>
    ++  <identifier id="android.support.v4.view.MotionEventCompat.getPointerId_changed(android.view.MotionEvent, int)"/>
    ++  <text>
    ++    InsertCommentsHere
    ++  </text>
    ++</comment>
    ++<comment>
    ++  <identifier id="android.support.v4.view.MotionEventCompat.getSource_changed(android.view.MotionEvent)"/>
    ++  <text>
    ++    InsertCommentsHere
    ++  </text>
    ++</comment>
    ++<comment>
    ++  <identifier id="android.support.v4.view.MotionEventCompat.getX_changed(android.view.MotionEvent, int)"/>
    ++  <text>
    ++    InsertCommentsHere
    ++  </text>
    ++</comment>
    ++<comment>
    ++  <identifier id="android.support.v4.view.MotionEventCompat.getY_changed(android.view.MotionEvent, int)"/>
    ++  <text>
    ++    InsertCommentsHere
    ++  </text>
    ++</comment>
    ++<comment>
    ++  <identifier id="android.support.v4.view.ViewCompat"/>
    ++  <text>
    ++    InsertCommentsHere
    ++  </text>
    ++</comment>
    ++<comment>
    ++  <identifier id="android.support.v4.view.ViewCompat.OVER_SCROLL_ALWAYS"/>
    ++  <text>
    ++    InsertCommentsHere
    ++  </text>
    ++</comment>
    ++<comment>
    ++  <identifier id="android.support.v4.view.ViewCompat.OVER_SCROLL_IF_CONTENT_SCROLLS"/>
    ++  <text>
    ++    InsertCommentsHere
    ++  </text>
    ++</comment>
    ++<comment>
    ++  <identifier id="android.support.v4.view.ViewCompat.OVER_SCROLL_NEVER"/>
    ++  <text>
    ++    InsertCommentsHere
    ++  </text>
    ++</comment>
    ++<comment>
    ++  <identifier id="android.support.v4.view.ViewCompat.getOverScrollMode_changed(android.view.View)"/>
    ++  <text>
    ++    InsertCommentsHere
    ++  </text>
    ++</comment>
    ++<comment>
    ++  <identifier id="android.support.v4.view.ViewCompat.isImportantForAccessibility_added(android.view.View)"/>
    ++  <text>
    ++    InsertCommentsHere
    ++  </text>
    ++</comment>
    ++<comment>
    ++  <identifier id="android.support.v4.view.ViewCompat.isOpaque_changed(android.view.View)"/>
    ++  <text>
    ++    InsertCommentsHere
    ++  </text>
    ++</comment>
    ++<comment>
    ++  <identifier id="android.support.v4.view.ViewCompat.setOverScrollMode_changed(android.view.View, int)"/>
    ++  <text>
    ++    InsertCommentsHere
    ++  </text>
    ++</comment>
    ++<comment>
    ++  <identifier id="android.support.v4.view.ViewConfigurationCompat"/>
    ++  <text>
    ++    InsertCommentsHere
    ++  </text>
    ++</comment>
    ++<comment>
    ++  <identifier id="android.support.v4.view.ViewConfigurationCompat.getScaledPagingTouchSlop_changed(android.view.ViewConfiguration)"/>
    ++  <text>
    ++    InsertCommentsHere
    ++  </text>
    ++</comment>
    ++<comment>
    ++  <identifier id="android.support.v4.view.WindowInsetsCompat"/>
    ++  <text>
    ++    InsertCommentsHere
    ++  </text>
    ++</comment>
    ++<comment>
    ++  <identifier id="android.support.v4.view.WindowInsetsCompat.ctor_added(android.support.v4.view.WindowInsetsCompat)"/>
    ++  <text>
    ++    InsertCommentsHere
    ++  </text>
    ++</comment>
    ++<comment>
    ++  <identifier id="android.support.v4.view.accessibility"/>
    ++  <text>
    ++    InsertCommentsHere
    ++  </text>
    ++</comment>
    ++<comment>
    ++  <identifier id="android.support.v4.view.accessibility.AccessibilityEventCompat"/>
    ++  <text>
    ++    InsertCommentsHere
    ++  </text>
    ++</comment>
    ++<comment>
    ++  <identifier id="android.support.v4.view.accessibility.AccessibilityEventCompat.TYPE_ASSIST_READING_CONTEXT"/>
    ++  <text>
    ++    InsertCommentsHere
    ++  </text>
    ++</comment>
    ++<comment>
    ++  <identifier id="android.support.v4.view.accessibility.AccessibilityEventCompat.TYPE_VIEW_CONTEXT_CLICKED"/>
    ++  <text>
    ++    InsertCommentsHere
    ++  </text>
    ++</comment>
    ++<comment>
    ++  <identifier id="android.support.v4.view.accessibility.AccessibilityEventCompat.TYPE_WINDOWS_CHANGED"/>
    ++  <text>
    ++    InsertCommentsHere
    ++  </text>
    ++</comment>
    ++<comment>
    ++  <identifier id="android.support.v4.view.accessibility.AccessibilityEventCompat.getAction_added(android.view.accessibility.AccessibilityEvent)"/>
    ++  <text>
    ++    InsertCommentsHere
    ++  </text>
    ++</comment>
    ++<comment>
    ++  <identifier id="android.support.v4.view.accessibility.AccessibilityEventCompat.getMovementGranularity_added(android.view.accessibility.AccessibilityEvent)"/>
    ++  <text>
    ++    InsertCommentsHere
    ++  </text>
    ++</comment>
    ++<comment>
    ++  <identifier id="android.support.v4.view.accessibility.AccessibilityEventCompat.setAction_added(android.view.accessibility.AccessibilityEvent, int)"/>
    ++  <text>
    ++    InsertCommentsHere
    ++  </text>
    ++</comment>
    ++<comment>
    ++  <identifier id="android.support.v4.view.accessibility.AccessibilityEventCompat.setMovementGranularity_added(android.view.accessibility.AccessibilityEvent, int)"/>
    ++  <text>
    ++    InsertCommentsHere
    ++  </text>
    ++</comment>
    ++<comment>
    ++  <identifier id="android.support.v4.view.accessibility.AccessibilityManagerCompat"/>
    ++  <text>
    ++    InsertCommentsHere
    ++  </text>
    ++</comment>
    ++<comment>
    ++  <identifier id="android.support.v4.view.accessibility.AccessibilityManagerCompat.AccessibilityStateChangeListener"/>
    ++  <text>
    ++    InsertCommentsHere
    ++  </text>
    ++</comment>
    ++<comment>
    ++  <identifier id="android.support.v4.view.accessibility.AccessibilityManagerCompat.AccessibilityStateChangeListenerCompat"/>
    ++  <text>
    ++    InsertCommentsHere
    ++  </text>
    ++</comment>
    ++<comment>
    ++  <identifier id="android.support.v4.view.accessibility.AccessibilityManagerCompat.AccessibilityStateChangeListenerCompat.onAccessibilityStateChanged_removed(boolean)"/>
    ++  <text>
    ++    InsertCommentsHere
    ++  </text>
    ++</comment>
    ++<comment>
    ++  <identifier id="android.support.v4.view.accessibility.AccessibilityManagerCompat.TouchExplorationStateChangeListener"/>
    ++  <text>
    ++    InsertCommentsHere
    ++  </text>
    ++</comment>
    ++<comment>
    ++  <identifier id="android.support.v4.view.accessibility.AccessibilityManagerCompat.addAccessibilityStateChangeListener_changed(android.view.accessibility.AccessibilityManager, android.support.v4.view.accessibility.AccessibilityManagerCompat.AccessibilityStateChangeListener)"/>
    ++  <text>
    ++    InsertCommentsHere
    ++  </text>
    ++</comment>
    ++<comment>
    ++  <identifier id="android.support.v4.view.accessibility.AccessibilityManagerCompat.addTouchExplorationStateChangeListener_added(android.view.accessibility.AccessibilityManager, android.support.v4.view.accessibility.AccessibilityManagerCompat.TouchExplorationStateChangeListener)"/>
    ++  <text>
    ++    InsertCommentsHere
    ++  </text>
    ++</comment>
    ++<comment>
    ++  <identifier id="android.support.v4.view.accessibility.AccessibilityManagerCompat.removeAccessibilityStateChangeListener_changed(android.view.accessibility.AccessibilityManager, android.support.v4.view.accessibility.AccessibilityManagerCompat.AccessibilityStateChangeListener)"/>
    ++  <text>
    ++    InsertCommentsHere
    ++  </text>
    ++</comment>
    ++<comment>
    ++  <identifier id="android.support.v4.view.accessibility.AccessibilityManagerCompat.removeTouchExplorationStateChangeListener_added(android.view.accessibility.AccessibilityManager, android.support.v4.view.accessibility.AccessibilityManagerCompat.TouchExplorationStateChangeListener)"/>
    ++  <text>
    ++    InsertCommentsHere
    ++  </text>
    ++</comment>
    ++<comment>
    ++  <identifier id="android.support.v4.view.accessibility.AccessibilityNodeInfoCompat"/>
    ++  <text>
    ++    InsertCommentsHere
    ++  </text>
    ++</comment>
    ++<comment>
    ++  <identifier id="android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.ACTION_ARGUMENT_COLUMN_INT"/>
    ++  <text>
    ++    InsertCommentsHere
    ++  </text>
    ++</comment>
    ++<comment>
    ++  <identifier id="android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.ACTION_ARGUMENT_PROGRESS_VALUE"/>
    ++  <text>
    ++    InsertCommentsHere
    ++  </text>
    ++</comment>
    ++<comment>
    ++  <identifier id="android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.ACTION_ARGUMENT_ROW_INT"/>
    ++  <text>
    ++    InsertCommentsHere
    ++  </text>
    ++</comment>
    ++<comment>
    ++  <identifier id="android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat"/>
    ++  <text>
    ++    InsertCommentsHere
    ++  </text>
    ++</comment>
    ++<comment>
    ++  <identifier id="android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat.ACTION_CONTEXT_CLICK"/>
    ++  <text>
    ++    InsertCommentsHere
    ++  </text>
    ++</comment>
    ++<comment>
    ++  <identifier id="android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat.ACTION_SCROLL_DOWN"/>
    ++  <text>
    ++    InsertCommentsHere
    ++  </text>
    ++</comment>
    ++<comment>
    ++  <identifier id="android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat.ACTION_SCROLL_LEFT"/>
    ++  <text>
    ++    InsertCommentsHere
    ++  </text>
    ++</comment>
    ++<comment>
    ++  <identifier id="android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat.ACTION_SCROLL_RIGHT"/>
    ++  <text>
    ++    InsertCommentsHere
    ++  </text>
    ++</comment>
    ++<comment>
    ++  <identifier id="android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat.ACTION_SCROLL_TO_POSITION"/>
    ++  <text>
    ++    InsertCommentsHere
    ++  </text>
    ++</comment>
    ++<comment>
    ++  <identifier id="android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat.ACTION_SCROLL_UP"/>
    ++  <text>
    ++    InsertCommentsHere
    ++  </text>
    ++</comment>
    ++<comment>
    ++  <identifier id="android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat.ACTION_SET_PROGRESS"/>
    ++  <text>
    ++    InsertCommentsHere
    ++  </text>
    ++</comment>
    ++<comment>
    ++  <identifier id="android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat.ACTION_SHOW_ON_SCREEN"/>
    ++  <text>
    ++    InsertCommentsHere
    ++  </text>
    ++</comment>
    ++<comment>
    ++  <identifier id="android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.CollectionInfoCompat"/>
    ++  <text>
    ++    InsertCommentsHere
    ++  </text>
    ++</comment>
    ++<comment>
    ++  <identifier id="android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.CollectionInfoCompat.getSelectionMode_added()"/>
    ++  <text>
    ++    InsertCommentsHere
    ++  </text>
    ++</comment>
    ++<comment>
    ++  <identifier id="android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.CollectionInfoCompat.obtain_added(int, int, boolean)"/>
    ++  <text>
    ++    InsertCommentsHere
    ++  </text>
    ++</comment>
    ++<comment>
    ++  <identifier id="android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.CollectionItemInfoCompat"/>
    ++  <text>
    ++    InsertCommentsHere
    ++  </text>
    ++</comment>
    ++<comment>
    ++  <identifier id="android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.CollectionItemInfoCompat.obtain_added(int, int, int, int, boolean)"/>
    ++  <text>
    ++    InsertCommentsHere
    ++  </text>
    ++</comment>
    ++<comment>
    ++  <identifier id="android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.RangeInfoCompat"/>
    ++  <text>
    ++    InsertCommentsHere
    ++  </text>
    ++</comment>
    ++<comment>
    ++  <identifier id="android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.RangeInfoCompat.obtain_added(int, float, float, float)"/>
    ++  <text>
    ++    InsertCommentsHere
    ++  </text>
    ++</comment>
    ++<comment>
    ++  <identifier id="android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.isContextClickable_added()"/>
    ++  <text>
    ++    InsertCommentsHere
    ++  </text>
    ++</comment>
    ++<comment>
    ++  <identifier id="android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.setContextClickable_added(boolean)"/>
    ++  <text>
    ++    InsertCommentsHere
    ++  </text>
    ++</comment>
    ++<comment>
    ++  <identifier id="android.support.v4.view.accessibility.AccessibilityNodeProviderCompat"/>
    ++  <text>
    ++    InsertCommentsHere
    ++  </text>
    ++</comment>
    ++<comment>
    ++  <identifier id="android.support.v4.view.accessibility.AccessibilityNodeProviderCompat.HOST_VIEW_ID"/>
    ++  <text>
    ++    InsertCommentsHere
    ++  </text>
    ++</comment>
    ++<comment>
    ++  <identifier id="android.support.v4.view.accessibility.AccessibilityWindowInfoCompat"/>
    ++  <text>
    ++    InsertCommentsHere
    ++  </text>
    ++</comment>
    ++<comment>
    ++  <identifier id="android.support.v4.view.accessibility.AccessibilityWindowInfoCompat.TYPE_SPLIT_SCREEN_DIVIDER"/>
    ++  <text>
    ++    InsertCommentsHere
    ++  </text>
    ++</comment>
    ++<comment>
    ++  <identifier id="android.support.v4.widget"/>
    ++  <text>
    ++    InsertCommentsHere
    ++  </text>
    ++</comment>
    ++<comment>
    ++  <identifier id="android.support.v4.widget.SearchViewCompat"/>
    ++  <text>
    ++    InsertCommentsHere
    ++  </text>
    ++</comment>
    ++<comment>
    ++  <identifier id="android.support.v4.widget.SearchViewCompat.OnCloseListener"/>
    ++  <text>
    ++    InsertCommentsHere
    ++  </text>
    ++</comment>
    ++<comment>
    ++  <identifier id="android.support.v4.widget.SearchViewCompat.OnCloseListenerCompat"/>
    ++  <text>
    ++    InsertCommentsHere
    ++  </text>
    ++</comment>
    ++<comment>
    ++  <identifier id="android.support.v4.widget.SearchViewCompat.OnQueryTextListener"/>
    ++  <text>
    ++    InsertCommentsHere
    ++  </text>
    ++</comment>
    ++<comment>
    ++  <identifier id="android.support.v4.widget.SearchViewCompat.OnQueryTextListenerCompat"/>
    ++  <text>
    ++    InsertCommentsHere
    ++  </text>
    ++</comment>
    ++<comment>
    ++  <identifier id="android.support.v4.widget.SearchViewCompat.setOnCloseListener_changed(android.view.View, android.support.v4.widget.SearchViewCompat.OnCloseListener)"/>
    ++  <text>
    ++    InsertCommentsHere
    ++  </text>
    ++</comment>
    ++<comment>
    ++  <identifier id="android.support.v4.widget.SearchViewCompat.setOnQueryTextListener_changed(android.view.View, android.support.v4.widget.SearchViewCompat.OnQueryTextListener)"/>
    ++  <text>
    ++    InsertCommentsHere
    ++  </text>
    ++</comment>
    ++<comment>
    ++  <identifier id="android.support.v4.widget.SwipeRefreshLayout"/>
    ++  <text>
    ++    InsertCommentsHere
    ++  </text>
    ++</comment>
    ++<comment>
    ++  <identifier id="android.support.v4.widget.SwipeRefreshLayout.OnChildScrollUpCallback"/>
    ++  <text>
    ++    InsertCommentsHere
    ++  </text>
    ++</comment>
    ++<comment>
    ++  <identifier id="android.support.v4.widget.SwipeRefreshLayout.setOnChildScrollUpCallback_added(android.support.v4.widget.SwipeRefreshLayout.OnChildScrollUpCallback)"/>
    ++  <text>
    ++    InsertCommentsHere
    ++  </text>
    ++</comment>
    ++<comment>
    ++  <identifier id="android.support.v4.widget.TextViewCompat"/>
    ++  <text>
    ++    InsertCommentsHere
    ++  </text>
    ++</comment>
    ++<comment>
    ++  <identifier id="android.support.v4.widget.TextViewCompat.getCompoundDrawablesRelative_added(android.widget.TextView)"/>
    ++  <text>
    ++    InsertCommentsHere
    ++  </text>
    ++</comment>
    ++<comment>
    ++  <identifier id="android.support.v7.app"/>
    ++  <text>
    ++    InsertCommentsHere
    ++  </text>
    ++</comment>
    ++<comment>
    ++  <identifier id="android.support.v7.app.ActionBarActivity"/>
    ++  <text>
    ++    InsertCommentsHere
    ++  </text>
    ++</comment>
    ++<comment>
    ++  <identifier id="android.support.v7.app.ActionBarDrawerToggle"/>
    ++  <text>
    ++    InsertCommentsHere
    ++  </text>
    ++</comment>
    ++<comment>
    ++  <identifier id="android.support.v7.app.ActionBarDrawerToggle.getDrawerArrowDrawable_added()"/>
    ++  <text>
    ++    InsertCommentsHere
    ++  </text>
    ++</comment>
    ++<comment>
    ++  <identifier id="android.support.v7.app.ActionBarDrawerToggle.setDrawerArrowDrawable_added(android.support.v7.graphics.drawable.DrawerArrowDrawable)"/>
    ++  <text>
    ++    InsertCommentsHere
    ++  </text>
    ++</comment>
    ++<comment>
    ++  <identifier id="android.support.v7.app.AppCompatActivity"/>
    ++  <text>
    ++    InsertCommentsHere
    ++  </text>
    ++</comment>
    ++<comment>
    ++  <identifier id="android.support.v7.app.AppCompatDelegate"/>
    ++  <text>
    ++    InsertCommentsHere
    ++  </text>
    ++</comment>
    ++<comment>
    ++  <identifier id="android.support.v7.app.AppCompatDelegate.onStart_added()"/>
    ++  <text>
    ++    InsertCommentsHere
    ++  </text>
    ++</comment>
    ++<comment>
    ++  <identifier id="android.support.v7.app.AppCompatDialogFragment"/>
    ++  <text>
    ++    InsertCommentsHere
    ++  </text>
    ++</comment>
    ++<comment>
    ++  <identifier id="android.support.v7.app.NotificationCompat"/>
    ++  <text>
    ++    InsertCommentsHere
    ++  </text>
    ++</comment>
    ++<comment>
    ++  <identifier id="android.support.v7.app.NotificationCompat.Builder"/>
    ++  <text>
    ++    InsertCommentsHere
    ++  </text>
    ++</comment>
    ++<comment>
    ++  <identifier id="android.support.v7.app.NotificationCompat.MediaStyle"/>
    ++  <text>
    ++    InsertCommentsHere
    ++  </text>
    ++</comment>
    ++<comment>
    ++  <identifier id="android.support.v7.appcompat"/>
    ++  <text>
    ++    InsertCommentsHere
    ++  </text>
    ++</comment>
    ++<comment>
    ++  <identifier id="android.support.v7.content.res"/>
    ++  <text>
    ++    InsertCommentsHere
    ++  </text>
    ++</comment>
    ++<comment>
    ++  <identifier id="android.support.v7.content.res.AppCompatResources"/>
    ++  <text>
    ++    InsertCommentsHere
    ++  </text>
    ++</comment>
    ++<comment>
    ++  <identifier id="android.support.v7.content.res.AppCompatResources.getDrawable_added(android.content.Context, int)"/>
    ++  <text>
    ++    InsertCommentsHere
    ++  </text>
    ++</comment>
    ++<comment>
    ++  <identifier id="android.support.v7.graphics"/>
    ++  <text>
    ++    InsertCommentsHere
    ++  </text>
    ++</comment>
    ++<comment>
    ++  <identifier id="android.support.v7.graphics.Palette"/>
    ++  <text>
    ++    InsertCommentsHere
    ++  </text>
    ++</comment>
    ++<comment>
    ++  <identifier id="android.support.v7.graphics.Palette.getDominantColor_added(int)"/>
    ++  <text>
    ++    InsertCommentsHere
    ++  </text>
    ++</comment>
    ++<comment>
    ++  <identifier id="android.support.v7.graphics.Palette.getDominantSwatch_added()"/>
    ++  <text>
    ++    InsertCommentsHere
    ++  </text>
    ++</comment>
    ++<comment>
    ++  <identifier id="android.support.v7.preference"/>
    ++  <text>
    ++    InsertCommentsHere
    ++  </text>
    ++</comment>
    ++<comment>
    ++  <identifier id="android.support.v7.preference.MultiSelectListPreferenceDialogFragmentCompat"/>
    ++  <text>
    ++    InsertCommentsHere
    ++  </text>
    ++</comment>
    ++<comment>
    ++  <identifier id="android.support.v7.recyclerview"/>
    ++  <text>
    ++    InsertCommentsHere
    ++  </text>
    ++</comment>
    ++<comment>
    ++  <identifier id="android.support.v7.util"/>
    ++  <text>
    ++    InsertCommentsHere
    ++  </text>
    ++</comment>
    ++<comment>
    ++  <identifier id="android.support.v7.util.BatchingListUpdateCallback"/>
    ++  <text>
    ++    InsertCommentsHere
    ++  </text>
    ++</comment>
    ++<comment>
    ++  <identifier id="android.support.v7.util.DiffUtil"/>
    ++  <text>
    ++    InsertCommentsHere
    ++  </text>
    ++</comment>
    ++<comment>
    ++  <identifier id="android.support.v7.util.DiffUtil.Callback"/>
    ++  <text>
    ++    InsertCommentsHere
    ++  </text>
    ++</comment>
    ++<comment>
    ++  <identifier id="android.support.v7.util.DiffUtil.DiffResult"/>
    ++  <text>
    ++    InsertCommentsHere
    ++  </text>
    ++</comment>
    ++<comment>
    ++  <identifier id="android.support.v7.util.ListUpdateCallback"/>
    ++  <text>
    ++    InsertCommentsHere
    ++  </text>
    ++</comment>
    ++<comment>
    ++  <identifier id="android.support.v7.util.SortedList.Callback"/>
    ++  <text>
    ++    InsertCommentsHere
    ++  </text>
    ++</comment>
    ++<comment>
    ++  <identifier id="android.support.v7.util.SortedList.Callback.onChanged_added(int, int, java.lang.Object)"/>
    ++  <text>
    ++    InsertCommentsHere
    ++  </text>
    ++</comment>
    ++<comment>
    ++  <identifier id="android.support.v7.util.SortedList.Callback.onInserted_removed(int, int)"/>
    ++  <text>
    ++    InsertCommentsHere
    ++  </text>
    ++</comment>
    ++<comment>
    ++  <identifier id="android.support.v7.util.SortedList.Callback.onMoved_removed(int, int)"/>
    ++  <text>
    ++    InsertCommentsHere
    ++  </text>
    ++</comment>
    ++<comment>
    ++  <identifier id="android.support.v7.util.SortedList.Callback.onRemoved_removed(int, int)"/>
    ++  <text>
    ++    InsertCommentsHere
    ++  </text>
    ++</comment>
    ++<comment>
    ++  <identifier id="android.support.v7.widget"/>
    ++  <text>
    ++    InsertCommentsHere
    ++  </text>
    ++</comment>
    ++<comment>
    ++  <identifier id="android.support.v7.widget.ActionMenuView"/>
    ++  <text>
    ++    InsertCommentsHere
    ++  </text>
    ++</comment>
    ++<comment>
    ++  <identifier id="android.support.v7.widget.ActionMenuView.LayoutParams"/>
    ++  <text>
    ++    InsertCommentsHere
    ++  </text>
    ++</comment>
    ++<comment>
    ++  <identifier id="android.support.v7.widget.ActionMenuView.OnMenuItemClickListener"/>
    ++  <text>
    ++    InsertCommentsHere
    ++  </text>
    ++</comment>
    ++<comment>
    ++  <identifier id="android.support.v7.widget.AppCompatAutoCompleteTextView"/>
    ++  <text>
    ++    InsertCommentsHere
    ++  </text>
    ++</comment>
    ++<comment>
    ++  <identifier id="android.support.v7.widget.AppCompatButton"/>
    ++  <text>
    ++    InsertCommentsHere
    ++  </text>
    ++</comment>
    ++<comment>
    ++  <identifier id="android.support.v7.widget.AppCompatCheckBox"/>
    ++  <text>
    ++    InsertCommentsHere
    ++  </text>
    ++</comment>
    ++<comment>
    ++  <identifier id="android.support.v7.widget.AppCompatCheckedTextView"/>
    ++  <text>
    ++    InsertCommentsHere
    ++  </text>
    ++</comment>
    ++<comment>
    ++  <identifier id="android.support.v7.widget.AppCompatEditText"/>
    ++  <text>
    ++    InsertCommentsHere
    ++  </text>
    ++</comment>
    ++<comment>
    ++  <identifier id="android.support.v7.widget.AppCompatImageButton"/>
    ++  <text>
    ++    InsertCommentsHere
    ++  </text>
    ++</comment>
    ++<comment>
    ++  <identifier id="android.support.v7.widget.AppCompatImageView"/>
    ++  <text>
    ++    InsertCommentsHere
    ++  </text>
    ++</comment>
    ++<comment>
    ++  <identifier id="android.support.v7.widget.AppCompatMultiAutoCompleteTextView"/>
    ++  <text>
    ++    InsertCommentsHere
    ++  </text>
    ++</comment>
    ++<comment>
    ++  <identifier id="android.support.v7.widget.AppCompatRadioButton"/>
    ++  <text>
    ++    InsertCommentsHere
    ++  </text>
    ++</comment>
    ++<comment>
    ++  <identifier id="android.support.v7.widget.AppCompatRatingBar"/>
    ++  <text>
    ++    InsertCommentsHere
    ++  </text>
    ++</comment>
    ++<comment>
    ++  <identifier id="android.support.v7.widget.AppCompatSeekBar"/>
    ++  <text>
    ++    InsertCommentsHere
    ++  </text>
    ++</comment>
    ++<comment>
    ++  <identifier id="android.support.v7.widget.AppCompatSpinner"/>
    ++  <text>
    ++    InsertCommentsHere
    ++  </text>
    ++</comment>
    ++<comment>
    ++  <identifier id="android.support.v7.widget.AppCompatTextView"/>
    ++  <text>
    ++    InsertCommentsHere
    ++  </text>
    ++</comment>
    ++<comment>
    ++  <identifier id="android.support.v7.widget.CardView"/>
    ++  <text>
    ++    InsertCommentsHere
    ++  </text>
    ++</comment>
    ++<comment>
    ++  <identifier id="android.support.v7.widget.GridLayout"/>
    ++  <text>
    ++    InsertCommentsHere
    ++  </text>
    ++</comment>
    ++<comment>
    ++  <identifier id="android.support.v7.widget.GridLayout.Alignment"/>
    ++  <text>
    ++    InsertCommentsHere
    ++  </text>
    ++</comment>
    ++<comment>
    ++  <identifier id="android.support.v7.widget.GridLayout.LayoutParams"/>
    ++  <text>
    ++    InsertCommentsHere
    ++  </text>
    ++</comment>
    ++<comment>
    ++  <identifier id="android.support.v7.widget.GridLayout.Spec"/>
    ++  <text>
    ++    InsertCommentsHere
    ++  </text>
    ++</comment>
    ++<comment>
    ++  <identifier id="android.support.v7.widget.LinearLayoutCompat"/>
    ++  <text>
    ++    InsertCommentsHere
    ++  </text>
    ++</comment>
    ++<comment>
    ++  <identifier id="android.support.v7.widget.LinearLayoutCompat.LayoutParams"/>
    ++  <text>
    ++    InsertCommentsHere
    ++  </text>
    ++</comment>
    ++<comment>
    ++  <identifier id="android.support.v7.widget.LinearLayoutManager"/>
    ++  <text>
    ++    InsertCommentsHere
    ++  </text>
    ++</comment>
    ++<comment>
    ++  <identifier id="android.support.v7.widget.LinearLayoutManager.prepareForDrop_removed(android.view.View, android.view.View, int, int)"/>
    ++  <text>
    ++    InsertCommentsHere
    ++  </text>
    ++</comment>
    ++<comment>
    ++  <identifier id="android.support.v7.widget.LinearSmoothScroller"/>
    ++  <text>
    ++    InsertCommentsHere
    ++  </text>
    ++</comment>
    ++<comment>
    ++  <identifier id="android.support.v7.widget.LinearSmoothScroller.computeScrollVectorForPosition_changed(int)"/>
    ++  <text>
    ++    InsertCommentsHere
    ++  </text>
    ++</comment>
    ++<comment>
    ++  <identifier id="android.support.v7.widget.LinearSnapHelper"/>
    ++  <text>
    ++    InsertCommentsHere
    ++  </text>
    ++</comment>
    ++<comment>
    ++  <identifier id="android.support.v7.widget.ListPopupWindow"/>
    ++  <text>
    ++    InsertCommentsHere
    ++  </text>
    ++</comment>
    ++<comment>
    ++  <identifier id="android.support.v7.widget.PopupMenu"/>
    ++  <text>
    ++    InsertCommentsHere
    ++  </text>
    ++</comment>
    ++<comment>
    ++  <identifier id="android.support.v7.widget.PopupMenu.OnDismissListener"/>
    ++  <text>
    ++    InsertCommentsHere
    ++  </text>
    ++</comment>
    ++<comment>
    ++  <identifier id="android.support.v7.widget.PopupMenu.OnMenuItemClickListener"/>
    ++  <text>
    ++    InsertCommentsHere
    ++  </text>
    ++</comment>
    ++<comment>
    ++  <identifier id="android.support.v7.widget.RecyclerView"/>
    ++  <text>
    ++    InsertCommentsHere
    ++  </text>
    ++</comment>
    ++<comment>
    ++  <identifier id="android.support.v7.widget.RecyclerView.OnFlingListener"/>
    ++  <text>
    ++    InsertCommentsHere
    ++  </text>
    ++</comment>
    ++<comment>
    ++  <identifier id="android.support.v7.widget.RecyclerView.SmoothScroller.ScrollVectorProvider"/>
    ++  <text>
    ++    InsertCommentsHere
    ++  </text>
    ++</comment>
    ++<comment>
    ++  <identifier id="android.support.v7.widget.RecyclerView.getOnFlingListener_added()"/>
    ++  <text>
    ++    InsertCommentsHere
    ++  </text>
    ++</comment>
    ++<comment>
    ++  <identifier id="android.support.v7.widget.RecyclerView.setOnFlingListener_added(android.support.v7.widget.RecyclerView.OnFlingListener)"/>
    ++  <text>
    ++    InsertCommentsHere
    ++  </text>
    ++</comment>
    ++<comment>
    ++  <identifier id="android.support.v7.widget.SearchView"/>
    ++  <text>
    ++    InsertCommentsHere
    ++  </text>
    ++</comment>
    ++<comment>
    ++  <identifier id="android.support.v7.widget.SearchView.OnCloseListener"/>
    ++  <text>
    ++    InsertCommentsHere
    ++  </text>
    ++</comment>
    ++<comment>
    ++  <identifier id="android.support.v7.widget.SearchView.OnQueryTextListener"/>
    ++  <text>
    ++    InsertCommentsHere
    ++  </text>
    ++</comment>
    ++<comment>
    ++  <identifier id="android.support.v7.widget.SearchView.OnSuggestionListener"/>
    ++  <text>
    ++    InsertCommentsHere
    ++  </text>
    ++</comment>
    ++<comment>
    ++  <identifier id="android.support.v7.widget.ShareActionProvider"/>
    ++  <text>
    ++    InsertCommentsHere
    ++  </text>
    ++</comment>
    ++<comment>
    ++  <identifier id="android.support.v7.widget.ShareActionProvider.OnShareTargetSelectedListener"/>
    ++  <text>
    ++    InsertCommentsHere
    ++  </text>
    ++</comment>
    ++<comment>
    ++  <identifier id="android.support.v7.widget.SnapHelper"/>
    ++  <text>
    ++    InsertCommentsHere
    ++  </text>
    ++</comment>
    ++<comment>
    ++  <identifier id="android.support.v7.widget.Space"/>
    ++  <text>
    ++    InsertCommentsHere
    ++  </text>
    ++</comment>
    ++<comment>
    ++  <identifier id="android.support.v7.widget.StaggeredGridLayoutManager"/>
    ++  <text>
    ++    InsertCommentsHere
    ++  </text>
    ++</comment>
    ++<comment>
    ++  <identifier id="android.support.v7.widget.StaggeredGridLayoutManager.TAG"/>
    ++  <text>
    ++    InsertCommentsHere
    ++  </text>
    ++</comment>
    ++<comment>
    ++  <identifier id="android.support.v7.widget.StaggeredGridLayoutManager.computeScrollVectorForPosition_added(int)"/>
    ++  <text>
    ++    InsertCommentsHere
    ++  </text>
    ++</comment>
    ++<comment>
    ++  <identifier id="android.support.v7.widget.SwitchCompat"/>
    ++  <text>
    ++    InsertCommentsHere
    ++  </text>
    ++</comment>
    ++<comment>
    ++  <identifier id="android.support.v7.widget.ThemedSpinnerAdapter"/>
    ++  <text>
    ++    InsertCommentsHere
    ++  </text>
    ++</comment>
    ++<comment>
    ++  <identifier id="android.support.v7.widget.ThemedSpinnerAdapter.Helper"/>
    ++  <text>
    ++    InsertCommentsHere
    ++  </text>
    ++</comment>
    ++<comment>
    ++  <identifier id="android.support.v7.widget.Toolbar"/>
    ++  <text>
    ++    InsertCommentsHere
    ++  </text>
    ++</comment>
    ++<comment>
    ++  <identifier id="android.support.v7.widget.Toolbar.LayoutParams"/>
    ++  <text>
    ++    InsertCommentsHere
    ++  </text>
    ++</comment>
    ++<comment>
    ++  <identifier id="android.support.v7.widget.Toolbar.OnMenuItemClickListener"/>
    ++  <text>
    ++    InsertCommentsHere
    ++  </text>
    ++</comment>
    ++<comment>
    ++  <identifier id="android.support.v7.widget.Toolbar.SavedState"/>
    ++  <text>
    ++    InsertCommentsHere
    ++  </text>
    ++</comment>
    ++<comment>
    ++  <identifier id="android.support.v8.renderscript"/>
    ++  <text>
    ++    InsertCommentsHere
    ++  </text>
    ++</comment>
    ++
    ++</comments>
    +diff --git a/docs/html/topic/arc/index.jd b/docs/html/topic/arc/index.jd
    +index d46fbc8..a025459 100644
    +--- a/docs/html/topic/arc/index.jd
    ++++ b/docs/html/topic/arc/index.jd
    +@@ -51,7 +51,7 @@ review your mouse and keyboard interactions.
    +     &lt;!-- Some Chromebooks don't support touch. Although not essential,
    +          it's a good idea to explicitly include this declaration. --&gt;
    +     &lt;uses-feature android:name="android.hardware.touchscreen"
    +-                  required="false" /&gt;
    ++                  android:required="false" /&gt;
    + &lt;/manifest&gt;
    + </pre>
    + 
    +diff --git a/docs/html/topic/libraries/data-binding/index.jd b/docs/html/topic/libraries/data-binding/index.jd
    +index ddcc9f2..0faa1db 100644
    +--- a/docs/html/topic/libraries/data-binding/index.jd
    ++++ b/docs/html/topic/libraries/data-binding/index.jd
    +@@ -162,7 +162,9 @@ page.tags="databinding", "layouts"
    + 
    + <p>
    +   To use data binding, Android Plugin for Gradle <strong>1.5.0-alpha1</strong>
    +-  or higher is required.
    ++  or higher is required. See how to <a
    ++href="/studio/releases/gradle-plugin.html#updating-plugin">update the Android
    ++Plugin for Gradle</a>.
    + </p>
    + 
    + <h2 id="build_environment">
    +diff --git a/docs/html/topic/libraries/support-library/features.jd b/docs/html/topic/libraries/support-library/features.jd
    +index 614392e..b5f189a 100755
    +--- a/docs/html/topic/libraries/support-library/features.jd
    ++++ b/docs/html/topic/libraries/support-library/features.jd
    +@@ -108,7 +108,7 @@ page.title=Support Library Features
    + <p>The Gradle build script dependency identifier for this library is as follows:</p>
    + 
    + <pre>
    +-com.android.support:support-compat:24.2.0
    ++com.android.support:support-compat:24.2.1
    + </pre>
    + 
    + <h3 id="v4-core-utils">v4 core-utils library</h3>
    +@@ -124,7 +124,7 @@ com.android.support:support-compat:24.2.0
    + </p>
    + 
    + <pre>
    +-com.android.support:support-core-utils:24.2.0
    ++com.android.support:support-core-utils:24.2.1
    + </pre>
    + 
    + <h3 id="v4-core-ui">v4 core-ui library</h3>
    +@@ -141,7 +141,7 @@ com.android.support:support-core-utils:24.2.0
    + </p>
    + 
    + <pre>
    +-com.android.support:support-core-ui:24.2.0
    ++com.android.support:support-core-ui:24.2.1
    + </pre>
    + 
    + <h3 id="v4-media-compat">v4 media-compat library</h3>
    +@@ -158,7 +158,7 @@ com.android.support:support-core-ui:24.2.0
    + </p>
    + 
    + <pre>
    +-com.android.support:support-media-compat:24.2.0
    ++com.android.support:support-media-compat:24.2.1
    + </pre>
    + 
    + <h3 id="v4-fragment">v4 fragment library</h3>
    +@@ -178,7 +178,7 @@ com.android.support:support-media-compat:24.2.0
    + </p>
    + 
    + <pre>
    +-com.android.support:support-fragment:24.2.0
    ++com.android.support:support-fragment:24.2.1
    + </pre>
    + 
    + <h2 id="multidex">Multidex Support Library</h2>
    +@@ -245,7 +245,7 @@ com.android.support:multidex:1.0.0
    + <p>The Gradle build script dependency identifier for this library is as follows:</p>
    + 
    + <pre>
    +-com.android.support:appcompat-v7:24.2.0
    ++com.android.support:appcompat-v7:24.2.1
    + </pre>
    + 
    + 
    +@@ -260,7 +260,7 @@ implementations, and are used extensively in layouts for TV apps.</p>
    + <p>The Gradle build script dependency identifier for this library is as follows:</p>
    + 
    + <pre>
    +-com.android.support:cardview-v7:24.2.0
    ++com.android.support:cardview-v7:24.2.1
    + </pre>
    + 
    + 
    +@@ -276,7 +276,7 @@ For detailed information about the v7 gridlayout library APIs, see the
    + <p>The Gradle build script dependency identifier for this library is as follows:</p>
    + 
    + <pre>
    +-com.android.support:gridlayout-v7:24.2.0
    ++com.android.support:gridlayout-v7:24.2.1
    + </pre>
    + 
    + 
    +@@ -299,7 +299,7 @@ reference.</p>
    + <p>The Gradle build script dependency identifier for this library is as follows:</p>
    + 
    + <pre>
    +-com.android.support:mediarouter-v7:24.2.0
    ++com.android.support:mediarouter-v7:24.2.1
    + </pre>
    + 
    + <p class="caution">The v7 mediarouter library APIs introduced in Support Library
    +@@ -319,7 +319,7 @@ title card.</p>
    + <p>The Gradle build script dependency identifier for this library is as follows:</p>
    + 
    + <pre>
    +-com.android.support:palette-v7:24.2.0
    ++com.android.support:palette-v7:24.2.1
    + </pre>
    + 
    + 
    +@@ -335,7 +335,7 @@ limited window of data items.</p>
    + <p>The Gradle build script dependency identifier for this library is as follows:</p>
    + 
    + <pre>
    +-com.android.support:recyclerview-v7:24.2.0
    ++com.android.support:recyclerview-v7:24.2.1
    + </pre>
    + 
    + 
    +@@ -358,7 +358,7 @@ such as {@link android.support.v7.preference.CheckBoxPreference} and
    + <p>The Gradle build script dependency identifier for this library is as follows:</p>
    + 
    + <pre>
    +-com.android.support:preference-v7:24.2.0
    ++com.android.support:preference-v7:24.2.1
    + </pre>
    + 
    + <h2 id="v8">v8 Support Library</h2>
    +@@ -409,7 +409,7 @@ defaultConfig {
    + <p>The Gradle build script dependency identifier for this library is as follows:</p>
    + 
    + <pre>
    +-com.android.support:support-v13:24.2.0
    ++com.android.support:support-v13:24.2.1
    + </pre>
    + 
    + 
    +@@ -435,7 +435,7 @@ for preference interfaces such as
    + <p>The Gradle build script dependency identifier for this library is as follows:</p>
    + 
    + <pre>
    +-com.android.support:preference-v14:24.2.0
    ++com.android.support:preference-v14:24.2.1
    + </pre>
    + 
    + 
    +@@ -458,7 +458,7 @@ interface and classes, such as
    + <p>The Gradle build script dependency identifier for this library is as follows:</p>
    + 
    + <pre>
    +-com.android.support:preference-leanback-v17:24.2.0
    ++com.android.support:preference-leanback-v17:24.2.1
    + </pre>
    + 
    + 
    +@@ -494,7 +494,7 @@ com.android.support:preference-leanback-v17:24.2.0
    + <p>The Gradle build script dependency identifier for this library is as follows:</p>
    + 
    + <pre>
    +-com.android.support:leanback-v17:24.2.0
    ++com.android.support:leanback-v17:24.2.1
    + </pre>
    + 
    + 
    +@@ -509,7 +509,7 @@ package provides APIs to support adding annotation metadata to your apps. </p>
    + <p>The Gradle build script dependency identifier for this library is as follows:</p>
    + 
    + <pre>
    +-com.android.support:support-annotations:24.2.0
    ++com.android.support:support-annotations:24.2.1
    + </pre>
    + 
    + 
    +@@ -527,7 +527,7 @@ snackbars, and <a href="{@docRoot}design/building-blocks/tabs.html">tabs</a>.  <
    + <p>The Gradle build script dependency identifier for this library is as follows:</p>
    + 
    + <pre>
    +-com.android.support:design:24.2.0
    ++com.android.support:design:24.2.1
    + </pre>
    + 
    + 
    +@@ -548,7 +548,7 @@ Callback</a>.  </p>
    + <p>The Gradle build script dependency identifier for this library is as follows:</p>
    + 
    + <pre>
    +-com.android.support:customtabs:24.2.0
    ++com.android.support:customtabs:24.2.1
    + </pre>
    + 
    + 
    +@@ -572,7 +572,7 @@ PercentRelativeLayout</a>.  </p>
    + <p>The Gradle build script dependency identifier for this library is as follows:</p>
    + 
    + <pre>
    +-com.android.support:percent:24.2.0
    ++com.android.support:percent:24.2.1
    + </pre>
    + 
    + 
    +@@ -595,5 +595,5 @@ RecommendationExtender</a>.  </p>
    + <p>The Gradle build script dependency identifier for this library is as follows:</p>
    + 
    + <pre>
    +-com.android.support:recommendation:24.2.0
    ++com.android.support:recommendation:24.2.1
    + </pre>
    +diff --git a/docs/html/topic/libraries/support-library/revisions.jd b/docs/html/topic/libraries/support-library/revisions.jd
    +index 4e14c70..9a24d15 100644
    +--- a/docs/html/topic/libraries/support-library/revisions.jd
    ++++ b/docs/html/topic/libraries/support-library/revisions.jd
    +@@ -6,9 +6,71 @@ page.metaDescription=This page provides details about the Support Library packag
    + <p>This page provides details about the Support Library package releases.</p>
    + 
    + <div class="toggle-content opened">
    +-  <p id="rev24-2-0">
    ++  <p id="rev24-2-1">
    +     <a href="#" onclick="return toggleContent(this)"><img src=
    +     "{@docRoot}assets/images/styles/disclosure_up.png" class=
    ++    "toggle-content-img" alt="">Android Support Library, revision 24.2.1</a>
    ++    <em>(September 2016)</em>
    ++  </p>
    ++
    ++  <div class="toggle-content-toggleme">
    ++
    ++    <p>Fixed issues:</p>
    ++
    ++<ul>
    ++  <li>{@link android.support.design.widget.FloatingActionButton} can no longer
    ++  be anchored to indirect children of {@link
    ++  android.support.design.widget.CoordinatorLayout}. (AOSP issue <a href=
    ++  "https://code.google.com/p/android/issues/detail?id=220250">220250</a>)
    ++  </li>
    ++
    ++  <li>Image inside {@link
    ++  android.support.design.widget.CollapsingToolbarLayout} doesn’t scale properly
    ++  with <code>fitsSystemWindows=true</code>. (AOSP issue <a href=
    ++  "https://code.google.com/p/android/issues/detail?id=220389">220389</a>)
    ++  </li>
    ++
    ++  <li>{@link android.support.design.widget.CoordinatorLayout} throws {@link
    ++  java.lang.IndexOutOfBoundsException} when {@link
    ++  android.support.design.widget.Snackbar} is shown and dismissed. (AOSP issue
    ++  <a href="https://code.google.com/p/android/issues/detail?id=220762"
    ++  >220762</a>)
    ++  </li>
    ++
    ++  <li>{@link android.support.design.widget.TextInputLayout} fails to resolve
    ++  error text color. (AOSP issue <a href=
    ++  "https://code.google.com/p/android/issues/detail?id=220305">220305</a>)
    ++  </li>
    ++
    ++  <li>{@link android.support.v7.util.SortedList.BatchedCallback#onMoved
    ++  BatchedCallback.onMoved()} calls {@link
    ++  android.support.v7.util.SortedList.BatchedCallback#onInserted
    ++  BatchedCallback.onInserted()}. (AOSP issue <a href=
    ++  "https://code.google.com/p/android/issues/detail?id=220309">220309</a>)
    ++  </li>
    ++
    ++  <li>{@link android.support.design.widget.TextInputLayout} overrides right
    ++  compound drawable. (AOSP issue <a href=
    ++  "https://code.google.com/p/android/issues/detail?id=220728">220728</a>)
    ++  </li>
    ++</ul>
    ++
    ++<p>
    ++  A complete list of public bug fixes is available on the <a href=
    ++  "https://code.google.com/p/android/issues/list?can=1&q=label%3ATarget-Support-24.2.1">
    ++  AOSP Issue Tracker</a>.
    ++</p>
    ++
    ++
    ++  </div>
    ++</div>
    ++
    ++<!-- end of collapsible section: 24.2.1 -->
    ++
    ++<div class="toggle-content closed">
    ++  <p id="rev24-2-0">
    ++    <a href="#" onclick="return toggleContent(this)"><img src=
    ++    "{@docRoot}assets/images/styles/disclosure_down.png" class=
    +     "toggle-content-img" alt="">Android Support Library, revision 24.2.0</a>
    +     <em>(August 2016)</em>
    +   </p>
    +@@ -174,6 +236,14 @@ APK size, we recommend that you just list the specific modules your app needs.
    +     behavior similar to {@link android.support.v4.view.ViewPager}.
    +   </li>
    + 
    ++  <li>The Custom Tabs library now allows clients to request the standard
    ++  browser UI, rather than custom tabs UI, by calling <a href=
    ++  "/reference/android/support/customtabs/CustomTabsIntent.html#setAlwaysUseBrowserUI(android.content.Intent)">
    ++    <code>CustomTabsIntent.setAlwaysUseBrowserUI()</code></a>. This behavior is
    ++    useful in cases where the browser defaults to custom tabs UI but the user
    ++    has expressed a preference for the standard browser UI.
    ++  </li>
    ++
    + </ul>
    + 
    + <h3 id="24-2-0-behavior">Behavior changes</h3>
    +@@ -189,8 +259,17 @@ APK size, we recommend that you just list the specific modules your app needs.
    +   <li>{@link android.support.design.widget.Snackbar} now draws behind the
    +   navigation bar if the status bar is translucent.
    +   </li>
    ++
    + </ul>
    + 
    ++<h4>MediaRouter library</h4>
    ++
    ++<p>
    ++  Bluetooth devices are no longer listed as media routes. Routing audio to
    ++  Bluetooth devices is now solely controlled at the Android system level.
    ++</p>
    ++
    ++
    + <h3 id="24-2-0-deprecations">Deprecations</h3>
    + 
    + <p>Deprecated classes and methods are subject to removal in a future release. You should migrate away from these APIs as soon as possible.</p>
    +@@ -2895,8 +2974,6 @@ if (animator instanceof SimpleItemAnimator) {
    +         <ul>
    +           <li>Added {@link android.support.v7.widget.GridLayout} to provide support for the
    +             {@link android.widget.GridLayout} layout object.</li>
    +-          <li>Added {@link android.support.v7.widget.Space} which can be used to create blank areas
    +-            within a {@link android.support.v7.widget.GridLayout} layout object.</li>
    +         </ul>
    +     </dl>
    +   </div>
    +diff --git a/docs/html/topic/performance/_book.yaml b/docs/html/topic/performance/_book.yaml
    +index e053a2c..4021e85 100644
    +--- a/docs/html/topic/performance/_book.yaml
    ++++ b/docs/html/topic/performance/_book.yaml
    +@@ -1,34 +1,61 @@
    + toc:
    +-- title: Reducing Network Battery Drain
    +-  path: /topic/performance/power/network/index.html
    ++- title: Optimizing for Battery Life
    ++  path: /topic/performance/power/index.html
    +   path_attributes:
    +   - name: description
    +-    value: Access the network while going easy on battery life.
    ++    value: Learn to make your app more battery-friendly.
    +   section:
    +-  - title: Collecting Network Traffic Data
    +-    path: /topic/performance/power/network/gather-data.html
    +-  - title: Analyzing Network Traffic Data
    +-    path: /topic/performance/power/network/analyze-data.html
    +-  - title: Optimizing User-Initiated Network Use
    +-    path: /topic/performance/power/network/action-user-traffic.html
    +-  - title: Optimizing Server-Initiated Network Use
    +-    path: /topic/performance/power/network/action-server-traffic.html
    +-  - title: Optimizing General Network Use
    +-    path: /topic/performance/power/network/action-any-traffic.html
    +-- title: Implementing Doze
    +-  path: /training/monitoring-device-state/doze-standby.html
    ++  - title: Network Use and Battery Consumption
    ++    path: /topic/performance/power/network/index.html
    ++    section:
    ++    - title: Collecting Network Traffic Data
    ++      path: /topic/performance/power/network/gather-data.html
    ++    - title: Analyzing Data Traffic
    ++      path: /topic/performance/power/network/analyze-data.html
    ++    - title: Optimizing User-Initiated Network Use
    ++      path: /topic/performance/power/network/action-user-traffic.html
    ++    - title: Optimizing App-Initiated Network Use
    ++      path: topic/performance/power/network/action-app-traffic.html
    ++    - title: Optimizing Server-Initiated Network Use
    ++      path: /topic/performance/power/network/action-server-traffic.html
    ++    - title: Optimizing General Network Use
    ++      path: /topic/performance/power/network/action-any-traffic.html
    ++  - title: Doze and App Standby
    ++    path: /training/monitoring-device-state/doze-standby.html
    ++    path_attributes:
    ++    - name: description
    ++      value: Help ensure the device isn't depleting the battery when not in use.
    ++  - title: Battery Historian
    ++    path: /topic/performance/power/battery-historian.html
    ++- title: Rendering
    ++  path: /topic/performance/rendering/index.html
    +   path_attributes:
    +   - name: description
    +-    value: Help ensure the device isn't depleting the battery when not in use.
    +-- title: Launch-Time Performance
    +-  path: /topic/performance/launch-time.html
    +-- title: Better Performance through Threading
    +-  path: /topic/performance/threads.html
    +-- title: Optimizing View Hierarchies
    +-  path: /topic/performance/optimizing-view-hierarchies.html
    +-- title: Background Optimization
    +-  path: /topic/performance/background-optimization.html
    ++    value: Speed up your app's rendering
    ++  section:
    ++  - title: Reducing Overdraw
    ++    path: /topic/performance/rendering/overdraw.html
    ++  - title: Performance and View Hierarchies
    ++    path: /topic/performance/rendering/optimizing-view-hierarchies.html
    ++  - title: Analyzing with Profile GPU Rendering
    ++    path: /topic/performance/rendering/profile-gpu.html
    + - title: Intelligent Job-Scheduling
    +   path: /topic/performance/scheduling.html
    ++- title: Background Optimization
    ++  path: /topic/performance/background-optimization.html
    + - title: Reducing APK Size
    +   path: /topic/performance/reduce-apk-size.html
    ++- title: Reducing Image Download Sizes
    ++  path: /topic/performance/network-xfer.html
    ++- title: Launch-Time Performance
    ++  path: /topic/performance/launch-time.html
    ++- title: Better Performance through Threading
    ++  path: /topic/performance/threads.html
    ++- title: Manage Your App's Memory
    ++  path: /topic/performance/memory.html
    ++- title: Overview of Memory Managemement
    ++  path: /topic/performance/memory-overview.html
    ++  path_attributes:
    ++  - name: description
    ++    value: How to keep your app's memory footprint small in order to improve performance on a variety of mobile devices.
    ++
    +diff --git a/docs/html/topic/performance/background-optimization.jd b/docs/html/topic/performance/background-optimization.jd
    +index 3e4c041..0a1a6f5 100644
    +--- a/docs/html/topic/performance/background-optimization.jd
    ++++ b/docs/html/topic/performance/background-optimization.jd
    +@@ -14,29 +14,31 @@ page.image=images/cards/card-nyc_2x.jpg
    +     <ol>
    +       <li>
    +         <a href="#connectivity-action">Restrictions on CONNECTIVITY_ACTION</a>
    +-      </li>
    +-
    +-      <li>
    +-        <a href="#sched-jobs">Scheduling Network Jobs on Unmetered
    +-        Connections</a>
    +-      </li>
    +-
    +-      <li>
    +-        <a href="#monitor-conn">Monitoring Network Connectivity While the App
    +-        is Running</a>
    ++        <ul>
    ++          <li>
    ++            <a href="#sched-jobs">Scheduling Network Jobs on Unmetered
    ++            Connections</a>
    ++          </li>
    ++
    ++          <li>
    ++            <a href="#monitor-conn">Monitoring Network Connectivity While the
    ++            App is Running</a>
    ++          </li>
    ++        </ul>
    +       </li>
    + 
    +       <li>
    +         <a href="#media-broadcasts">Restrictions on NEW_PICTURE and
    +         NEW_VIDEO</a>
    +-      </li>
    +-
    +-      <li>
    +-        <a href="#new-jobinfo">New JobInfo methods</a>
    +-      </li>
    +-
    +-      <li>
    +-        <a href="#new-jobparam">New JobParameter Methods</a>
    ++        <ul>
    ++          <li>
    ++            <a href="#new-jobinfo">New JobInfo methods</a>
    ++          </li>
    ++
    ++          <li>
    ++            <a href="#new-jobparam">New JobParameter Methods</a>
    ++          </li>
    ++        </ul>
    +       </li>
    + 
    +       <li>
    +@@ -54,12 +56,12 @@ page.image=images/cards/card-nyc_2x.jpg
    + </p>
    + 
    + <p>
    +-  To alleviate this issue, Android N applies the following
    ++  To alleviate this issue, Android 7.0 (API level 24) applies the following
    +   restrictions:
    + </p>
    + 
    + <ul>
    +-  <li>Apps targeting the Preview do not receive {@link
    ++  <li>Apps targeting Android 7.0 (API level 24) do not receive {@link
    +   android.net.ConnectivityManager#CONNECTIVITY_ACTION} broadcasts if they
    +   register to receive them in their manifest. Apps that are running can still
    +   listen for {@code CONNECTIVITY_CHANGE} on their main thread by registering a
    +@@ -70,16 +72,16 @@ page.image=images/cards/card-nyc_2x.jpg
    +   <li>Apps cannot send or receive {@link
    +   android.hardware.Camera#ACTION_NEW_PICTURE} or {@link
    +   android.hardware.Camera#ACTION_NEW_VIDEO} broadcasts. This optimization
    +-  affects all apps, not only those targeting the Preview.
    ++  affects all apps, not only those targeting Android 7.0 (API level 24).
    +   </li>
    + </ul>
    + 
    + <p>
    +-  If your app uses any of these intents, you should remove dependencies on
    +-  them as soon as possible so that you can target Android N devices properly.
    +-  The Android framework provides several solutions to mitigate the need for
    +-  these implicit broadcasts. For example, {@link android.app.job.JobScheduler}
    +-  and <a href=
    ++  If your app uses any of these intents, you should remove dependencies on them
    ++  as soon as possible so that you can target devices running Android 7.0
    ++  properly. The Android framework provides several solutions to mitigate the
    ++  need for these implicit broadcasts. For example, {@link
    ++  android.app.job.JobScheduler} and <a href=
    +   "https://developers.google.com/android/reference/com/google/android/gms/gcm/GcmNetworkManager">
    +   {@code GcmNetworkManager}</a> provide robust mechanisms to schedule network
    +   operations when specified conditions, such as a connection to an unmetered
    +@@ -101,7 +103,7 @@ page.image=images/cards/card-nyc_2x.jpg
    + </h2>
    + 
    + <p>
    +-  Apps targeting the Android N do not receive {@link
    ++  Apps targeting Android 7.0 (API level 24) do not receive {@link
    +   android.net.ConnectivityManager#CONNECTIVITY_ACTION} broadcasts if they
    +   register to receive them in their manifest, and processes that depend on this
    +   broadcast will not start. This could pose a problem for apps that want
    +@@ -198,11 +200,11 @@ public static void scheduleJob(Context context) {
    + </h2>
    + 
    + <p>
    +-  In the Android N, apps are not able to send or receive {@link
    ++  In Android 7.0 (API level 24), apps are not able to send or receive {@link
    +   android.hardware.Camera#ACTION_NEW_PICTURE} or {@link
    +   android.hardware.Camera#ACTION_NEW_VIDEO} broadcasts. This restriction helps
    +   alleviate the performance and user experience impacts when several apps must
    +-  wake up in order to process a new image or video. Android N
    ++  wake up in order to process a new image or video. Android 7.0 (API level 24)
    +   extends {@link android.app.job.JobInfo} and {@link
    +   android.app.job.JobParameters} to provide an alternative solution.
    + </p>
    +@@ -212,7 +214,7 @@ public static void scheduleJob(Context context) {
    + </h3>
    + 
    + <p>
    +-  To trigger jobs on content URI changes, Android N extends
    ++  To trigger jobs on content URI changes, Android 7.0 (API level 24) extends
    +   the {@link android.app.job.JobInfo} API with the following methods:
    + </p>
    + 
    +@@ -287,7 +289,7 @@ public static void scheduleJob(Context context) {
    + </h3>
    + 
    + <p>
    +-  Android N also extends {@link android.app.job.JobParameters} to
    ++  Android 7.0 (API level 24) also extends {@link android.app.job.JobParameters} to
    +   allow your app to receive useful information about what content authorities
    +   and URIs triggered the job:
    + </p>
    +@@ -361,13 +363,13 @@ public boolean onStartJob(JobParameters params) {
    +   conditions, can improve performance and user experience. Removing
    +   dependencies on background services and statically-registered implicit
    +   broadcast receivers can help your app run better on such devices. Although
    +-  Android N takes steps to reduce some of these issues, it is
    ++  Android 7.0 (API level 24) takes steps to reduce some of these issues, it is
    +   recommended that you optimize your app to run without the use of these
    +   background processes entirely.
    + </p>
    + 
    + <p>
    +-  Android N introduces some additional <a href=
    ++  Android 7.0 (API level 24) introduces some additional <a href=
    +   "{@docRoot}tools/help/adb.html">Android Debug Bridge (ADB)</a> commands that
    +   you can use to test app behavior with those background processes disabled:
    + </p>
    +@@ -379,7 +381,7 @@ public boolean onStartJob(JobParameters params) {
    + 
    +   <li style="list-style: none; display: inline">
    + <pre class="no-pretty-print">
    +-{@code $ adb shell cmd appops set &lt;package_name&gt; RUN_IN_BACKGROUND ignore}
    ++{@code $ adb shell cmd appops set <package_name> RUN_IN_BACKGROUND ignore}
    + </pre>
    +   </li>
    + 
    +@@ -389,7 +391,7 @@ public boolean onStartJob(JobParameters params) {
    + 
    +   <li style="list-style: none; display: inline">
    + <pre class="no-pretty-print">
    +-{@code $ adb shell cmd appops set &lt;package_name&gt; RUN_IN_BACKGROUND allow}
    ++{@code $ adb shell cmd appops set <package_name> RUN_IN_BACKGROUND allow}
    + </pre>
    +   </li>
    + </ul>
    +diff --git a/docs/html/topic/performance/images/app-rankings.png b/docs/html/topic/performance/images/app-rankings.png
    +new file mode 100644
    +index 0000000..9dd60e5
    +Binary files /dev/null and b/docs/html/topic/performance/images/app-rankings.png differ
    +diff --git a/docs/html/topic/performance/images/bars.png b/docs/html/topic/performance/images/bars.png
    +new file mode 100644
    +index 0000000..3afea46
    +Binary files /dev/null and b/docs/html/topic/performance/images/bars.png differ
    +diff --git a/docs/html/topic/performance/images/beforeafterindexed.png b/docs/html/topic/performance/images/beforeafterindexed.png
    +new file mode 100644
    +index 0000000..dc7762e
    +Binary files /dev/null and b/docs/html/topic/performance/images/beforeafterindexed.png differ
    +diff --git a/docs/html/topic/performance/images/comparison.png b/docs/html/topic/performance/images/comparison.png
    +new file mode 100644
    +index 0000000..18f204c
    +Binary files /dev/null and b/docs/html/topic/performance/images/comparison.png differ
    +diff --git a/docs/html/topic/performance/images/decisions.png b/docs/html/topic/performance/images/decisions.png
    +new file mode 100644
    +index 0000000..d4f21f8
    +Binary files /dev/null and b/docs/html/topic/performance/images/decisions.png differ
    +diff --git a/docs/html/topic/performance/images/dropdown.png b/docs/html/topic/performance/images/dropdown.png
    +new file mode 100644
    +index 0000000..59ec6110
    +Binary files /dev/null and b/docs/html/topic/performance/images/dropdown.png differ
    +diff --git a/docs/html/topic/performance/images/generic-timeline.png b/docs/html/topic/performance/images/generic-timeline.png
    +new file mode 100644
    +index 0000000..04388b6
    +Binary files /dev/null and b/docs/html/topic/performance/images/generic-timeline.png differ
    +diff --git a/docs/html/topic/performance/images/moarparrots.png b/docs/html/topic/performance/images/moarparrots.png
    +new file mode 100644
    +index 0000000..ee10ec1
    +Binary files /dev/null and b/docs/html/topic/performance/images/moarparrots.png differ
    +diff --git a/docs/html/topic/performance/images/palette.png b/docs/html/topic/performance/images/palette.png
    +new file mode 100644
    +index 0000000..eb6be6b
    +Binary files /dev/null and b/docs/html/topic/performance/images/palette.png differ
    +diff --git a/docs/html/topic/performance/images/parrot.png b/docs/html/topic/performance/images/parrot.png
    +new file mode 100644
    +index 0000000..7a8b86a
    +Binary files /dev/null and b/docs/html/topic/performance/images/parrot.png differ
    +diff --git a/docs/html/topic/performance/images/pug-visualization.png b/docs/html/topic/performance/images/pug-visualization.png
    +new file mode 100644
    +index 0000000..8270d0e
    +Binary files /dev/null and b/docs/html/topic/performance/images/pug-visualization.png differ
    +diff --git a/docs/html/topic/performance/images/pugspecificdata.png b/docs/html/topic/performance/images/pugspecificdata.png
    +new file mode 100644
    +index 0000000..1c2be83
    +Binary files /dev/null and b/docs/html/topic/performance/images/pugspecificdata.png differ
    +diff --git a/docs/html/topic/performance/images/s-generic-closeup.png b/docs/html/topic/performance/images/s-generic-closeup.png
    +new file mode 100644
    +index 0000000..6685d51
    +Binary files /dev/null and b/docs/html/topic/performance/images/s-generic-closeup.png differ
    +diff --git a/docs/html/topic/performance/images/s-profiler-legend.png b/docs/html/topic/performance/images/s-profiler-legend.png
    +new file mode 100644
    +index 0000000..968fd38
    +Binary files /dev/null and b/docs/html/topic/performance/images/s-profiler-legend.png differ
    +diff --git a/docs/html/topic/performance/images/vq.gif b/docs/html/topic/performance/images/vq.gif
    +new file mode 100644
    +index 0000000..cbf6a35
    +Binary files /dev/null and b/docs/html/topic/performance/images/vq.gif differ
    +diff --git a/docs/html/topic/performance/index.jd b/docs/html/topic/performance/index.jd
    +index e08db15..2b6b197 100644
    +--- a/docs/html/topic/performance/index.jd
    ++++ b/docs/html/topic/performance/index.jd
    +@@ -1,4 +1,4 @@
    +-page.title=Performance
    ++page.title=Performance and Power
    + page.article=true
    + page.metaDescription=Improve your app's performance by learning how to optimize power consumption, launch times, and other important areas of performance.
    + 
    +diff --git a/docs/html/topic/performance/memory-overview.jd b/docs/html/topic/performance/memory-overview.jd
    +new file mode 100644
    +index 0000000..58067d2
    +--- /dev/null
    ++++ b/docs/html/topic/performance/memory-overview.jd
    +@@ -0,0 +1,288 @@
    ++page.title=Overview of Android Memory Management
    ++page.tags=ram,memory,paging,mmap
    ++
    ++@jd:body
    ++
    ++<div id="qv-wrapper">
    ++<div id="qv">
    ++
    ++<h2>In this document</h2>
    ++<ol class="nolist">
    ++  <li><a href="#gc">Garbage collection</a></li>
    ++  <li><a href="#SharingRAM">Sharing Memory</a></li>
    ++  <li><a href="#AllocatingRAM">Allocating and Reclaiming App Memory</a></li>
    ++  <li><a href="#RestrictingMemory">Restricting App Memory</a></li>
    ++  <li><a href="#SwitchingApps">Switching Apps</a></li>
    ++</ol>
    ++<h2>See Also</h2>
    ++<ul>
    ++  <li><a href="{@docRoot}training/articles/memory.html">Manage Your App's Memory</a>
    ++  </li>
    ++  <li><a href="{@docRoot}studio/profile/investigate-ram.html">Investigating Your RAM Usage</a>
    ++  </li>
    ++</ul>
    ++
    ++</div>
    ++</div>
    ++
    ++<p>
    ++  The Android Runtime (ART) and Dalvik virtual machine use
    ++  <a href="http://en.wikipedia.org/wiki/Paging" class="external-link">paging</a>
    ++  and <a href="http://en.wikipedia.org/wiki/Memory-mapped_files" class="external-link">memory-mapping</a>
    ++  (mmapping) to manage memory. This means that any memory an app
    ++  modifies&mdash;whether by allocating
    ++  new objects or touching mmapped pages&mdash;remains resident in RAM and
    ++  cannot be paged out. The only way to release memory from an app is to release
    ++  object references that the app holds, making the memory available to the
    ++  garbage collector.
    ++  That is with one exception: any files
    ++  mmapped in without modification, such as code,
    ++  can be paged out of RAM if the system wants to use that memory elsewhere.
    ++</p>
    ++
    ++<p>
    ++  This page explains how Android manages app processes and memory
    ++  allocation. For more information about how to manage memory more efficiently
    ++  in your app, see
    ++  <a href="{@docRoot}training/articles/memory.html">Manage Your App's Memory</a>.
    ++</p>
    ++
    ++<!-- Section 1 #################################################### -->
    ++
    ++<h2 id="gc">Garbage collection</h2>
    ++
    ++<p>
    ++  A managed memory environment, like the ART or Dalvik virtual machine,
    ++  keeps track of each memory allocation. Once it determines
    ++  that a piece of memory is no longer being used by the program,
    ++  it frees it back to the heap, without any intervention from the programmer.
    ++  The mechanism for reclaiming unused memory
    ++  within a managed memory environment
    ++  is known as <i>garbage collection</i>. Garbage collection has two goals:
    ++  find data objects in a program that cannot be accessed in the future; and
    ++  reclaim the resources used by those objects.
    ++</p>
    ++
    ++<p>
    ++  Android’s memory heap is a generational one, meaning that there are
    ++  different buckets of allocations that it tracks,
    ++  based on the expected life and size of an object being allocated.
    ++  For example, recently allocated objects belong in the <i>Young generation</i>.
    ++  When an object stays active long enough, it can be promoted
    ++  to an older generation, followed by a permanent generation.
    ++</p>
    ++
    ++<p>
    ++  Each heap generation has its own dedicated upper limit on the amount
    ++  of memory that objects there can occupy. Any time a generation starts
    ++  to fill up, the system executes a garbage collection
    ++  event in an attempt to free up memory. The duration of the garbage collection
    ++  depends on which generation of objects it's collecting
    ++  and how many active objects are in each generation.
    ++</p>
    ++
    ++<p>
    ++  Even though garbage collection can be quite fast, it can still
    ++  affect your app's performance. You don’t generally control
    ++  when a garbage collection event occurs from within your code.
    ++  The system has a running set of criteria for determining when to perform
    ++  garbage collection. When the criteria are satisfied,
    ++  the system stops executing the process and begins garbage collection. If
    ++  garbage collection occurs in the middle of an intensive processing loop
    ++  like an animation or during music playback, it can increase processing time.
    ++  This increase can potentially push code execution in your app past the
    ++  recommended 16ms threshold for efficient and smooth frame rendering.
    ++</p>
    ++
    ++<p>
    ++  Additionally, your code flow may perform kinds of work that
    ++  force garbage collection events to occur
    ++  more often or make them last longer-than-normal.
    ++  For example, if you allocate multiple objects in the
    ++  innermost part of a for-loop during each frame of an alpha
    ++  blending animation, you might pollute your memory heap with a
    ++  lot of objects.
    ++  In that circumstance, the garbage collector executes multiple garbage
    ++  collection events and can degrade the performance of your app.
    ++</p>
    ++
    ++<p>
    ++  For more general information about garbage collection, see
    ++  <a href="https://en.wikipedia.org/wiki/Garbage_collection_(computer_science)"
    ++  class="external-link">Garbage collection</a>.
    ++</p>
    ++
    ++<!-- Section 2 #################################################### -->
    ++
    ++<h2 id="SharingRAM">Sharing Memory</h2>
    ++
    ++<p>
    ++  In order to fit everything it needs in RAM,
    ++  Android tries to share RAM pages across processes. It
    ++  can do so in the following ways:
    ++</p>
    ++
    ++<ul>
    ++  <li>
    ++    Each app process is forked from an existing process called Zygote.
    ++    The Zygote process starts when the system boots and loads common
    ++    framework code and resources
    ++    (such as activity themes). To start a new app process,
    ++    the system forks the Zygote process then
    ++    loads and runs the app's code in the new process.
    ++    This approach allows most of the RAM pages allocated for
    ++    framework code and resources to be shared across all app processes.
    ++  </li>
    ++
    ++  <li>
    ++    Most static data is mmapped into a process.
    ++    This technique allows data to be shared
    ++    between processes, and also allows it to be paged
    ++    out when needed. Example static data include:
    ++    Dalvik code (by placing it in a pre-linked <code>.odex</code>
    ++    file for direct mmapping), app resources
    ++    (by designing the resource table to be a structure
    ++    that can be mmapped and by aligning the zip
    ++    entries of the APK), and traditional project
    ++    elements like native code in <code>.so</code> files.
    ++  </li>
    ++
    ++  <li>
    ++    In many places, Android shares the same dynamic
    ++    RAM across processes using explicitly allocated
    ++    shared memory regions (either with ashmem or gralloc).
    ++    For example, window surfaces use shared
    ++    memory between the app and screen compositor, and
    ++    cursor buffers use shared memory between the
    ++    content provider and client.
    ++  </li>
    ++</ul>
    ++
    ++<p>
    ++  Due to the extensive use of shared memory, determining
    ++  how much memory your app is using requires
    ++  care. Techniques to properly determine your app's
    ++  memory use are discussed in
    ++  <a href="{@docRoot}studio/profile/investigate-ram.html">Investigating Your RAM Usage</a>.
    ++</p>
    ++
    ++<!-- Section 3 #################################################### -->
    ++
    ++<h2 id="AllocatingRAM">Allocating and Reclaiming App Memory</h2>
    ++
    ++<p>
    ++  The Dalvik heap is constrained to a
    ++  single virtual memory range for each app process. This defines
    ++  the logical heap size, which can grow as it needs to
    ++  but only up to a limit that the system defines
    ++  for each app.
    ++</p>
    ++
    ++<p>
    ++  The logical size of the heap is not the same as
    ++  the amount of physical memory used by the heap.
    ++  When inspecting your app's heap, Android computes
    ++  a value called the Proportional Set Size (PSS),
    ++  which accounts for both dirty and clean pages
    ++  that are shared with other processes—but only in an
    ++  amount that's proportional to how many apps share
    ++  that RAM. This (PSS) total is what the system
    ++  considers to be your physical memory footprint.
    ++  For more information about PSS, see the
    ++  <a href="{@docRoot}studio/profile/investigate-ram.html">Investigating Your RAM Usage</a>
    ++  guide.
    ++</p>
    ++
    ++<p>
    ++  The Dalvik heap does not compact the logical
    ++  size of the heap, meaning that Android does not
    ++  defragment the heap to close up space. Android
    ++  can only shrink the logical heap size when there
    ++  is unused space at the end of the heap. However,
    ++  the system can still reduce physical memory used by the heap.
    ++  After garbage collection, Dalvik
    ++  walks the heap and finds unused pages, then returns
    ++  those pages to the kernel using madvise. So, paired
    ++  allocations and deallocations of large
    ++  chunks should result in reclaiming all (or nearly all)
    ++  the physical memory used. However,
    ++  reclaiming memory from small allocations can be much
    ++  less efficient because the page used
    ++  for a small allocation may still be shared with
    ++  something else that has not yet been freed.
    ++
    ++</p>
    ++
    ++<!-- Section 4 #################################################### -->
    ++
    ++<h2 id="RestrictingMemory">Restricting App Memory</h2>
    ++
    ++<p>
    ++  To maintain a functional multi-tasking environment,
    ++  Android sets a hard limit on the heap size
    ++  for each app. The exact heap size limit varies
    ++  between devices based on how much RAM the device
    ++  has available overall. If your app has reached the
    ++  heap capacity and tries to allocate more
    ++  memory, it can receive an {@link java.lang.OutOfMemoryError}.
    ++</p>
    ++
    ++<p>
    ++  In some cases, you might want to query the
    ++  system to determine exactly how much heap space you
    ++  have available on the current device—for example, to
    ++  determine how much data is safe to keep in a
    ++  cache. You can query the system for this figure by calling
    ++  {@link android.app.ActivityManager#getMemoryClass() }.
    ++  This method returns an integer indicating the number of
    ++  megabytes available for your app's heap.
    ++</p>
    ++
    ++<!-- Section 5 #################################################### -->
    ++
    ++<h2 id="SwitchingApps">Switching apps</h2>
    ++
    ++<p>
    ++  When users switch between apps,
    ++  Android keeps apps that
    ++  are not foreground&mdash;that is, not visible to the user or running a
    ++  foreground service like music playback&mdash;
    ++  in a least-recently used (LRU) cache.
    ++  For example, when a user first launches an app,
    ++  a process is created for it; but when the user
    ++  leaves the app, that process does <em>not</em> quit.
    ++  The system keeps the process cached. If
    ++  the user later returns to the app, the system reuses the process, thereby
    ++  making the app switching faster.
    ++</p>
    ++
    ++<p>
    ++  If your app has a cached process and it retains memory
    ++  that it currently does not need,
    ++  then your app&mdash;even while the user is not using it&mdash;
    ++  affects the system's
    ++  overall performance. As the system runs low on memory,
    ++  it kills processes in the LRU cache
    ++  beginning with the process least recently used. The system also
    ++  accounts for processes that hold onto the most memory
    ++  and can terminate them to free up RAM.
    ++</p>
    ++
    ++<p class="note">
    ++  <strong>Note:</strong> When the system begins killing processes in the
    ++  LRU cache, it primarily works bottom-up. The system also considers which
    ++  processes consume more memory and thus provide the system
    ++  more memory gain if killed.
    ++  The less memory you consume while in the LRU list overall,
    ++  the better your chances are
    ++  to remain in the list and be able to quickly resume.
    ++</p>
    ++
    ++<p>
    ++  For more information about how processes are cached while
    ++  not running in the foreground and how
    ++  Android decides which ones
    ++  can be killed, see the
    ++  <a href="{@docRoot}guide/components/processes-and-threads.html">Processes and Threads</a>
    ++  guide.
    ++</p>
    +diff --git a/docs/html/topic/performance/memory.jd b/docs/html/topic/performance/memory.jd
    +new file mode 100644
    +index 0000000..ef1c4ae
    +--- /dev/null
    ++++ b/docs/html/topic/performance/memory.jd
    +@@ -0,0 +1,593 @@
    ++page.title=Manage Your App's Memory
    ++page.tags=ram,low memory,OutOfMemoryError,onTrimMemory
    ++
    ++@jd:body
    ++
    ++<div id="qv-wrapper">
    ++<div id="qv">
    ++
    ++<h2>In this document</h2>
    ++<ol>
    ++  <li><a href="#monitor">Monitor Available Memory and Memory Usage</a>
    ++    <ul>
    ++      <li><a href="#AnalyzeRam">Tools for analyzing RAM usage</a></li>
    ++      <li><a href="#release">Release memory in response to events</a></li>
    ++      <li><a href="#CheckHowMuchMemory">Check how much memory you should use</a></li>
    ++    </ul>
    ++  </li>
    ++  <li><a href="#code">Use More Efficient Code Constructs</a>
    ++    <ul>
    ++      <li><a href="#Services">Use services sparingly</a></li>
    ++      <li><a href="#DataContainers">Use optimized data containers</a></li>
    ++      <li><a href="#Abstractions">Be careful with code abstractions</a></li>
    ++      <li><a href="#NanoProto">Use nano protobufs for serialized data</a></li>
    ++      <li><a href="#churn">Avoid memory churn</a></li>
    ++    </ul>
    ++  </li>
    ++  <li><a href="#remove">Remove Memory-Intensive Resources and Libraries</a>
    ++    <ul>
    ++      <li><a href="#reduce">Reduce overall APK size</a></li>
    ++      <li><a href="#DependencyInjection">Avoid dependency injection frameworks</a></li>
    ++      <li><a href="#ExternalLibs">Be careful about using external libraries</a></li>
    ++    </ul>
    ++  </li>
    ++</ol>
    ++<h2>See Also</h2>
    ++<ul>
    ++  <li><a href="{@docRoot}training/articles/memory-overview.html">Overview of Android Memory Management</a>
    ++  </li>
    ++  <li><a href="{@docRoot}studio/profile/investigate-ram.html">Investigating Your RAM Usage</a>
    ++  </li>
    ++  <li><a href="{@docRoot}topic/performance/reduce-apk-size.html">Reduce APK Size</a></li>
    ++</ul>
    ++
    ++</div>
    ++</div>
    ++
    ++<!-- INTRO #################################################### -->
    ++
    ++<p>
    ++  Random-access memory (RAM) is a valuable
    ++  resource in any software development environment, but
    ++  it's even more valuable on a mobile operating system
    ++  where physical memory is often constrained.
    ++  Although both the Android Runtime (ART) and Dalvik virtual machine perform
    ++  routine garbage collection, this does not mean you can ignore
    ++  when and where your app allocates and releases memory.
    ++  You still need to avoid
    ++  introducing memory leaks, usually caused by holding onto
    ++  object references in static member variables, and
    ++  release any {@link java.lang.ref.Reference} objects at the appropriate
    ++  time as defined by
    ++  lifecycle callbacks.
    ++</p>
    ++
    ++<p>
    ++  This page explains how you can
    ++  proactively reduce memory usage within your app.
    ++  For more information about general
    ++  practices to clean up your resources when programming in Java,
    ++  refer to other books or online
    ++  documentation about managing resource references.
    ++  If you’re looking for information about how to
    ++  analyze memory in a running app, read
    ++  <a href="#AnalyzeRam">Tools for analyzing RAM usage</a>.
    ++  For more detailed information about how the Android Runtime and Dalvik
    ++  virtual machine manage memory, see the
    ++  <a href="{@docRoot}training/articles/memory-overview.html">Overview of Android Memory Management</a>.
    ++</p>
    ++
    ++<!-- Section 1 #################################################### -->
    ++
    ++<h2 id="monitor">Monitor Available Memory and Memory Usage</h2>
    ++
    ++<p>
    ++  The Android framework, Android Studio, and Android SDK
    ++  can help you analyze and adjust your app's memory usage.
    ++  The Android framework
    ++  exposes several APIs that allow your app to reduce its memory usage
    ++  dynamically during runtime. Android Studio and the Android SDK
    ++  contain several tools  that allow you to investigate how your
    ++  app uses memory.
    ++</p>
    ++
    ++<!-- Section 1.1 #################################################### -->
    ++
    ++<h3 id="AnalyzeRam">Tools for analyzing RAM usage</h3>
    ++
    ++<p>
    ++  Before you can fix the memory usage problems in your app, you first need
    ++  to find them. Android Studio and the Android SDK include several tools
    ++  for analyzing memory usage in your app:
    ++</p>
    ++
    ++<ol>
    ++  <li>
    ++    The Device Monitor has a Dalvik Debug Monitor Server (DDMS) tool that allows
    ++    you to inspect memory allocation within your app process.
    ++    You can use this information to understand how your
    ++    app uses memory overall. For example, you can force a garbage collection
    ++    event and then view the types of objects that remain in memory. You can
    ++    use this information to identify operations or actions within your app
    ++    that allocate or leave excessive amounts of objects in memory.
    ++
    ++    <p>For more information about how to use the DDMS tool, see
    ++      <a href="/studio/profile/ddms.html">Using DDMS</a>.
    ++    </p>
    ++  </li>
    ++
    ++  <li>
    ++    The Memory Monitor in Android Studio shows you how your app allocates
    ++    memory over the course of a single session.
    ++    The tool shows a graph of available
    ++    and allocated Java memory over time, including garbage collection events.
    ++    You can also initiate garbage collection events and take a snapshot of
    ++    the Java heap while your app runs. The output from the Memory Monitor tool
    ++    can help you identify points when your app experiences excessive garbage
    ++    collection events, leading to app slowness.
    ++    <p>
    ++      For more information about how to use Memory Monitor tool, see
    ++      <a href="{@docRoot}tools/debugging/debugging-memory.html#ViewHeap">Viewing Heap Updates</a>.
    ++    </p>
    ++  </li>
    ++
    ++  <li>
    ++    Garbage collection events also show up in the Traceview viewer. Traceview
    ++    allows you to view trace log files as both a timeline and as a profile
    ++    of what happened within a method. You can use this tool to determine
    ++    what code was executing when a garbage collection event occurred.
    ++    <p>
    ++      For more information about how to use the Traceview viewer, see
    ++      <a href="https://developer.android.com/studio/profile/traceview.html">Profiling with Traceview and dmtracedump</a>.
    ++    </p>
    ++  </li>
    ++
    ++  <li>
    ++    The Allocation Tracker tool in Android Studio gives you a detailed look
    ++    at how your app allocates memory.
    ++    The Allocation Tracker records an app's memory allocations and lists
    ++    all allocated objects within the profiling snapshot. You can use this
    ++    tool to track down parts of your code that allocate too many objects.
    ++
    ++    <p>
    ++      For more information about how to use the Allocation Tracker tool, see
    ++      <a href="{docRoot}studio/profile/allocation-tracker-walkthru.html">Allocation Tracker Walkthrough</a>.
    ++    </p>
    ++  </li>
    ++
    ++</ol>
    ++
    ++<!-- Section 1.2 #################################################### -->
    ++
    ++<h3 id="release">Release memory in response to events</h3>
    ++
    ++<p>
    ++  An Android device can run with varying amounts of free memory
    ++  depending on the physical amount of RAM on the device and how the user
    ++  operates it. The system broadcasts signals to indicate when it is under
    ++  memory pressure, and apps should listen for these signals and adjust
    ++  their memory usage as appropriate.
    ++</p>
    ++
    ++</p>
    ++  You can use the {@link android.content.ComponentCallbacks2} API
    ++  to listen for these signals and then adjust your memory
    ++  usage in response to app lifecycle
    ++  or device events. The
    ++  {@link android.content.ComponentCallbacks2#onTrimMemory onTrimMemory()}
    ++  method allows your app to listen for memory related events when the app runs
    ++  in the foreground (is visible) and when it runs in the background.
    ++</p>
    ++
    ++<p>
    ++  To listen for these events, implement the {@link
    ++  android.content.ComponentCallbacks2#onTrimMemory onTrimMemory()}
    ++  callback in your {@link android.app.Activity}
    ++  classes, as shown in the following code snippet.
    ++</p>
    ++
    ++<pre class="prettyprint">
    ++import android.content.ComponentCallbacks2;
    ++// Other import statements ...
    ++
    ++public class MainActivity extends AppCompatActivity
    ++    implements ComponentCallbacks2 {
    ++
    ++    // Other activity code ...
    ++
    ++    /**
    ++     * Release memory when the UI becomes hidden or when system resources become low.
    ++     * @param level the memory-related event that was raised.
    ++     */
    ++    public void onTrimMemory(int level) {
    ++
    ++        // Determine which lifecycle or system event was raised.
    ++        switch (level) {
    ++
    ++            case ComponentCallbacks2.TRIM_MEMORY_UI_HIDDEN:
    ++
    ++                /*
    ++                   Release any UI objects that currently hold memory.
    ++
    ++                   The user interface has moved to the background.
    ++                */
    ++
    ++                break;
    ++
    ++            case ComponentCallbacks2.TRIM_MEMORY_RUNNING_MODERATE:
    ++            case ComponentCallbacks2.TRIM_MEMORY_RUNNING_LOW:
    ++            case ComponentCallbacks2.TRIM_MEMORY_RUNNING_CRITICAL:
    ++
    ++                /*
    ++                   Release any memory that your app doesn't need to run.
    ++
    ++                   The device is running low on memory while the app is running.
    ++                   The event raised indicates the severity of the memory-related event.
    ++                   If the event is TRIM_MEMORY_RUNNING_CRITICAL, then the system will
    ++                   begin killing background processes.
    ++                */
    ++
    ++                break;
    ++
    ++            case ComponentCallbacks2.TRIM_MEMORY_BACKGROUND:
    ++            case ComponentCallbacks2.TRIM_MEMORY_MODERATE:
    ++            case ComponentCallbacks2.TRIM_MEMORY_COMPLETE:
    ++
    ++                /*
    ++                   Release as much memory as the process can.
    ++
    ++                   The app is on the LRU list and the system is running low on memory.
    ++                   The event raised indicates where the app sits within the LRU list.
    ++                   If the event is TRIM_MEMORY_COMPLETE, the process will be one of
    ++                   the first to be terminated.
    ++                */
    ++
    ++                break;
    ++
    ++            default:
    ++                /*
    ++                  Release any non-critical data structures.
    ++
    ++                  The app received an unrecognized memory level value
    ++                  from the system. Treat this as a generic low-memory message.
    ++                */
    ++                break;
    ++        }
    ++    }
    ++}
    ++</pre>
    ++
    ++<p>
    ++  The
    ++  {@link android.content.ComponentCallbacks2#onTrimMemory onTrimMemory()}
    ++  callback was added in Android 4.0 (API level 14). For earlier versions,
    ++  you can use the
    ++  {@link android.content.ComponentCallbacks#onLowMemory()}
    ++  callback as a fallback for older versions, which is roughly equivalent to the
    ++  {@link android.content.ComponentCallbacks2#TRIM_MEMORY_COMPLETE} event.
    ++</p>
    ++
    ++<!-- Section 1.3 #################################################### -->
    ++
    ++<h3 id="CheckHowMuchMemory">Check how much memory you should use</h3>
    ++
    ++<p>
    ++  To allow multiple running processes, Android sets a hard limit
    ++  on the heap size alloted for each app. The exact heap size limit varies
    ++  between devices based on how much RAM the device
    ++  has available overall. If your app has reached the heap capacity and
    ++  tries to allocate more
    ++  memory, the system throws an {@link java.lang.OutOfMemoryError}.
    ++</p>
    ++
    ++<p>
    ++  To avoid running out of memory, you can to query the system to determine
    ++  how much heap space you have available on the current device.
    ++  You can query the system for this figure by calling
    ++  {@link android.app.ActivityManager#getMemoryInfo(android.app.ActivityManager.MemoryInfo) getMemoryInfo()}.
    ++  This returns an
    ++  {@link android.app.ActivityManager.MemoryInfo } object that provides
    ++  information about the device's
    ++  current memory status, including available memory, total memory, and
    ++  the memory threshold&mdash;the memory level below which the system begins
    ++  to kill processes. The
    ++  {@link android.app.ActivityManager.MemoryInfo } class also exposes a simple
    ++  boolean field,
    ++  {@link android.app.ActivityManager.MemoryInfo#lowMemory }
    ++  that tells you whether the device is running low on memory.
    ++</p>
    ++
    ++<p>
    ++  The following code snippet shows an example of how you can use the
    ++  {@link android.app.ActivityManager#getMemoryInfo(android.app.ActivityManager.MemoryInfo) getMemoryInfo()}.
    ++  method in your application.
    ++</p>
    ++
    ++<pre class="prettyprint">
    ++public void doSomethingMemoryIntensive() {
    ++
    ++    // Before doing something that requires a lot of memory,
    ++    // check to see whether the device is in a low memory state.
    ++    ActivityManager.MemoryInfo memoryInfo = getAvailableMemory();
    ++
    ++    if (!memoryInfo.lowMemory) {
    ++        // Do memory intensive work ...
    ++    }
    ++}
    ++
    ++// Get a MemoryInfo object for the device's current memory status.
    ++private ActivityManager.MemoryInfo getAvailableMemory() {
    ++    ActivityManager activityManager = (ActivityManager) this.getSystemService(ACTIVITY_SERVICE);
    ++    ActivityManager.MemoryInfo memoryInfo = new ActivityManager.MemoryInfo();
    ++    activityManager.getMemoryInfo(memoryInfo);
    ++    return memoryInfo;
    ++}
    ++</pre>
    ++
    ++<!-- Section 2 #################################################### -->
    ++
    ++<h2 id="code">Use More Memory-Efficient Code Constructs</h2>
    ++
    ++<p>
    ++  Some Android features, Java classes, and code constructs tend to
    ++  use more memory than others. You can minimize how
    ++  much memory your app uses by choosing more efficient alternatives in
    ++  your code.
    ++</p>
    ++
    ++<!-- Section 2.1 #################################################### -->
    ++
    ++<h3 id="Services">Use services sparingly</h3>
    ++
    ++<p>
    ++  Leaving a service running when it’s not needed is
    ++  <strong>one of the worst memory-management
    ++  mistakes</strong> an Android app can make. If your app needs a
    ++  <a href="{@docRoot}guide/components/services.html">service</a>
    ++  to perform work in the background, do not keep it running unless
    ++  it needs to run a job. Remember to stop your service when it has completed
    ++  its task. Otherwise, you can inadvertently cause a memory leak.
    ++</p>
    ++
    ++<p>
    ++  When you start a service, the system prefers to always keep the process
    ++  for that service running. This behavior
    ++  makes services processes very expensive
    ++  because the RAM used by a service remains unavailable to other processes.
    ++  This reduces the number of cached processes that the system can keep in
    ++  the LRU cache, making app switching less efficient. It can even lead to
    ++  thrashing in the system when memory is tight and the system can’t
    ++  maintain enough processes to host all the services currently running.
    ++</p>
    ++
    ++<p>
    ++  You should generally avoid use of persistent services because of
    ++  the on-going demands they place on available memory. Instead, we
    ++  recommend that you use an alternative implementation
    ++  such as {@link android.app.job.JobScheduler}. For more information about
    ++  how to use {@link android.app.job.JobScheduler} to schedule background
    ++  processes, see
    ++  <a href="/topic/performance/background-optimization.html">Background Optimizations</a>.
    ++<p>
    ++  If you must use a service, the
    ++  best way to limit the lifespan of your service is to use an {@link
    ++  android.app.IntentService}, which finishes
    ++  itself as soon as it's done handling the intent that started it.
    ++  For more information, read
    ++  <a href="{@docRoot}training/run-background-service/index.html">Running in a Background Service</a>.
    ++</p>
    ++
    ++<!-- Section 2.2 #################################################### -->
    ++
    ++<h3 id="DataContainers">Use optimized data containers</h3>
    ++
    ++<p>
    ++  Some of the classes provided by the programming language are not optimized for
    ++  use on mobile devices. For example, the generic
    ++  {@link java.util.HashMap} implementation can be quite memory
    ++  inefficient because it needs a separate entry object for every mapping.
    ++</p>
    ++
    ++<p>
    ++  The Android framework includes several optimized data containers, including
    ++  {@link android.util.SparseArray}, {@link android.util.SparseBooleanArray},
    ++  and {@link android.support.v4.util.LongSparseArray}.
    ++  For example, the {@link android.util.SparseArray} classes are more
    ++  efficient because they avoid the system's need to
    ++  <acronym title="Automatic conversion from primitive types to object classes (such as int to Integer)">autobox</acronym>
    ++  the key and sometimes value (which creates yet another object or
    ++  two per entry).
    ++</p>
    ++
    ++<p>
    ++  If necessary, you can always switch to raw arrays for a really lean data
    ++  structure.
    ++</p>
    ++
    ++<!-- Section 2.3 #################################################### -->
    ++
    ++<h3 id="Abstractions">Be careful with code abstractions</h3>
    ++
    ++<p>
    ++  Developers often use abstractions simply as a good programming practice,
    ++  because abstractions can improve code flexibility and maintenance.
    ++  However, abstractions come at a significant cost:
    ++  generally they require a fair amount more code that
    ++  needs to be executed, requiring more time and
    ++  more RAM for that code to be mapped into memory.
    ++  So if your abstractions aren't supplying a
    ++  significant benefit, you should avoid them.
    ++</p>
    ++
    ++<p>
    ++  For example, enums often require more than twice as much memory as static
    ++  constants. You should strictly avoid using enums on Android.
    ++</p>
    ++
    ++<!-- Section 2.4 #################################################### -->
    ++
    ++<h3 id="NanoProto">Use nano protobufs for serialized data</h3>
    ++
    ++<p>
    ++  <a href="https://developers.google.com/protocol-buffers/docs/overview">Protocol buffers</a>
    ++  are a language-neutral, platform-neutral, extensible mechanism
    ++  designed by Google for serializing structured data&mdash;similar to XML, but
    ++  smaller, faster, and simpler. If you decide to use
    ++  protobufs for your data, you should always use nano protobufs in your
    ++  client-side code. Regular protobufs generate extremely verbose code, which
    ++  can cause many kinds of problems in your app such as
    ++  increased RAM use, significant APK size increase, and slower execution.
    ++</p>
    ++
    ++<p>
    ++  For more information, see the "Nano version" section in the
    ++  <a href="https://android.googlesource.com/platform/external/protobuf/+/master/java/README.txt"
    ++class="external-link">protobuf readme</a>.
    ++</p>
    ++
    ++<!-- Section 2.5 #################################################### -->
    ++
    ++<h3 id="churn">Avoid memory churn</h3>
    ++
    ++<p>
    ++  As mentioned previously, garbage collections events don't normally affect
    ++  your app's performance. However, many garbage collection events that occur
    ++  over a short period of time can quickly eat up your frame time. The more time
    ++  that the system spends on garbage collection, the less time it has to do
    ++  other stuff like rendering or streaming audio.
    ++</p>
    ++
    ++<p>
    ++  Often, <em>memory churn</em> can cause a large number of
    ++  garbage collection events to occur. In practice, memory churn describes the
    ++  number of allocated temporary objects that occur in a given amount of time.
    ++</p>
    ++
    ++<p>
    ++  For example, you might allocate multiple temporary objects within a
    ++  <code>for</code> loop. Or you might create new
    ++  {@link android.graphics.Paint} or {@link android.graphics.Bitmap}
    ++  objects inside the
    ++  {@link android.view.View#onDraw(android.graphics.Canvas) onDraw()}
    ++  function of a view.
    ++  In both cases, the app creates a lot of objects quickly at high volume.
    ++  These can quickly consume all the available memory in the young generation,
    ++  forcing a garbage collection event to occur.
    ++</p>
    ++
    ++<p>
    ++  Of course, you need to find the places in your code where
    ++  the memory churn is high before you can fix them. Use the tools discussed in
    ++  <a href="#AnalyzeRam">Analyze your RAM usage</a>
    ++</p>
    ++
    ++<p>
    ++  Once you identify the problem areas in your code, try to reduce the number of
    ++  allocations within performance critical areas. Consider moving things out of
    ++  inner loops or perhaps moving them into a
    ++  <a href="https://en.wikipedia.org/wiki/Factory_method_pattern" class="external-link">Factory</a>
    ++  based allocation structure.
    ++</p>
    ++
    ++<!-- Section 3 #################################################### -->
    ++
    ++<h2 id="remove">Remove Memory-Intensive Resources and Libraries</h2>
    ++
    ++<p>
    ++  Some resources and libraries within your code can gobble up memory without
    ++  you knowing it. Overall size of your APK, including third-party libraries
    ++  or embedded resources, can affect how much memory your app consumes. You can
    ++  improve your app's memory consumption by removing any redundant, unnecessary,
    ++  or bloated components, resources, or libraries from your code.
    ++</p>
    ++
    ++<!-- Section 3.1 #################################################### -->
    ++
    ++<h3 id="reduce">Reduce overall APK size</h3>
    ++
    ++<p>
    ++  You can significantly reduce your app's memory usage by reducing the overall
    ++  size of your app. Bitmap size, resources, animation frames, and third-party
    ++  libraries can all contribute to the size of your APK.
    ++  Android Studio and the Android SDK provide multiple tools
    ++  to help you reduce the size of your resources and external dependencies.
    ++</p>
    ++
    ++<p>
    ++  For more information about how to reduce your overall APK size, see
    ++  <a href="{@docRoot}topic/performance/reduce-apk-size.html">Reduce APK Size</a>.
    ++</p>
    ++
    ++<!-- Section 3.2 #################################################### -->
    ++
    ++<h3 id="DependencyInjection">Use caution with dependency injection frameworks</h3>
    ++
    ++<p>
    ++  Dependency injection framework such as
    ++  <a href="https://code.google.com/p/google-guice/" class="external-link">Guice</a>
    ++  or
    ++  <a href="https://github.com/roboguice/roboguice" class="external-link">RoboGuice</a>
    ++  can simplify the code you write and provide an adaptive environment
    ++  that's useful for testing and other configuration changes. However, dependency
    ++  frameworks aren't always optimized for mobile devices.
    ++</p>
    ++
    ++<p>
    ++  For example, these frameworks tend to initialize processes by
    ++  scanning your code for annotations. This which can require significant
    ++  amounts of your code to be mapped into RAM unnecessarily. The system
    ++  allocates these mapped pages into clean memory so Android can drop them; yet
    ++  that can't happen until the pages have remained in memory for a long period
    ++  of time.
    ++ </p>
    ++
    ++<p>
    ++  If you need to use a dependency injection framework in your app, consider
    ++  using
    ++  <a class="external-link" href="http://google.github.io/dagger/">Dagger</a>
    ++  instead. For example, Dagger does not use reflection to scan your app's code.
    ++  Dagger's strict implementation means that it can be used in Android apps
    ++  without needlessly increasing memory usage.
    ++</p>
    ++
    ++<!-- Section 3.3 #################################################### -->
    ++
    ++<h3 id="ExternalLibs">Be careful about using external libraries</h3>
    ++
    ++<p>
    ++  External library code is often not written for mobile environments and
    ++  can be inefficient when used
    ++  for work on a mobile client. When you decide to use an
    ++  external library, you may need to optimize that library for mobile devices.
    ++  Plan for that work up-front and analyze the library in terms of code size and
    ++  RAM footprint before deciding to use it at all.
    ++</p>
    ++
    ++<p>
    ++  Even some mobile-optimized libraries can cause problems due to differing
    ++  implementations. For example, one library may use nano protobufs
    ++  while another uses micro protobufs, resulting in two different protobuf
    ++  implementations in your app. This can happen with different
    ++  implementations of logging, analytics, image loading frameworks,
    ++  caching, and many other things you don't expect.
    ++</p>
    ++
    ++<p>
    ++  Although <a href="{@docRoot}tools/help/proguard.html">ProGuard</a> can
    ++  help to remove APIs and resources with the right flags, it can't remove a
    ++  library's large internal dependencies. The features that you want in these
    ++  libraries may require lower-level dependencies. This becomes especially
    ++  problematic when you use an {@link android.app.Activity } subclass from a
    ++  library (which will tend to have wide swaths of dependencies),
    ++  when libraries use reflection (which is common and means you need to spend a
    ++  lot of time manually tweaking ProGuard to get it to work), and so on.
    ++</p>
    ++
    ++<p>
    ++  Also avoid using a shared library for just one or two features out of dozens.
    ++  You don't want to pull in a large amount of code and overhead that
    ++  you don't even use. When you consider whether to use a library, look for
    ++  an implementation that strongly matches what you need. Otherwise, you might
    ++  decide to create your own implementation.
    ++</p>
    ++
    +diff --git a/docs/html/topic/performance/network-xfer.jd b/docs/html/topic/performance/network-xfer.jd
    +new file mode 100644
    +index 0000000..7fe5594
    +--- /dev/null
    ++++ b/docs/html/topic/performance/network-xfer.jd
    +@@ -0,0 +1,374 @@
    ++page.title=Reducing Image Download Sizes
    ++page.metaDescription=Improve network performance by optimizing image size.
    ++
    ++meta.tags="performance"
    ++page.tags="performance"
    ++
    ++@jd:body
    ++
    ++<div id="qv-wrapper">
    ++<div id="qv">
    ++
    ++<h2>In this document</h2>
    ++    <ol>
    ++
    ++      <li>
    ++        <a href="#uif">Understanding Image Formats</a>
    ++        <ul>
    ++           <li><a href="#png">PNG</a></li>
    ++           <li><a href="#jpg">JPG</a></li>
    ++           <li><a href="#webp">WebP</a></li>
    ++        </ul>
    ++      </li>
    ++      <li>
    ++        <a href="#sf">Selecting a Format</a></li>
    ++      <li><a href="#doqv">Determining Optimal Quality Values</a>
    ++        <ul>
    ++           <li><a href="#sv">Scalar Values (JPG, WebP only)</a></li>
    ++           <li><a href="#butter">Butteraugli</a></li>
    ++        </ul>
    ++      </li>
    ++      <li><a href="#sizes">Serving Sizes</a></li>
    ++    </ol>
    ++  </div>
    ++</div>
    ++
    ++<p>
    ++Most download traffic consists of images. As a result, the smaller you can make
    ++your downloadable images, the better a network experience your app can provide
    ++for users. This page provides guidance on making image files smaller and more
    ++network-friendly.
    ++</p>
    ++
    ++<h2 id="uif">Understanding Image Formats</h2>
    ++
    ++<p>Android apps typically use images that are in one or more of the following file
    ++formats: PNG, JPG, and WebP. For each of these formats, there are steps you can
    ++take to reduce image sizes.
    ++</p>
    ++
    ++<h3 id="png">PNG</h3>
    ++
    ++<p>
    ++A key to making your PNG files smaller is reducing the number of unique
    ++colors used in each row of pixels that comprises the image. By using fewer
    ++colors, you improve the compression potential at all of the other stages of
    ++the pipeline.
    ++</p>
    ++
    ++<p>
    ++Reducing the number of unique colors makes a significant difference because PNG
    ++compression effectiveness is partly a function of the degree to which
    ++horizontally adjacent pixel colors vary. Thus, reducing the number of unique
    ++colors in each row of your PNG images can help in reducing their file sizes.
    ++</p>
    ++
    ++<p>
    ++When deciding whether to pursue this strategy, you should keep in mind that
    ++reducing the number of unique colors effectively amounts to applying a lossy
    ++encoding stage to the image. However, an encoding tool may not be a good
    ++judge of how bad a seemingly small error looks to the human eye. Therefore,
    ++you should perform this work manually in order to help ensure
    ++the right balance between efficient compression and acceptable image quality.
    ++</p>
    ++
    ++<p>
    ++There are two particularly useful approaches you can take: striving for indexed
    ++formats, and applying vector quantization.
    ++</p>
    ++
    ++
    ++<h4 id="strive">Strive for indexed formats</h4>
    ++
    ++<p>
    ++Any attempt at color reduction should start with trying to optimize your colors
    ++so that you can use the INDEXED format when exporting the image as a PNG. The
    ++INDEXED color mode works by choosing the best 256 colors to use, and replacing
    ++all pixel values with indices into that color palette. The result is a
    ++reduction from 16 million (potential) colors to only 256 colors: from 3 (without
    ++transparency) or 4 (with transparency) bytes per pixel to 1 byte per pixel.
    ++This change is a significant first-step file size reduction.
    ++</p>
    ++
    ++<p>
    ++Figure 1 shows shows an image and its indexed variant.
    ++</p>
    ++
    ++  <img src="{@docRoot}topic/performance/images/beforeafterindexed.png">
    ++  <p class="img-caption">
    ++Figure 1. An image before and after conversion to the INDEXED format.
    ++  </p>
    ++
    ++
    ++<p>
    ++Figure 2 shows the color palette for the image in Figure 1:
    ++</p>
    ++
    ++  <img src="{@docRoot}topic/performance/images/palette.png">
    ++  <p class="img-caption">
    ++Figure 2. The color palette for the image in Figure 1.
    ++  </p>
    ++
    ++<p>
    ++Representing your image as a paletted image goes a long way toward
    ++significantly improving the file size, so it's worth investigating if the
    ++majority of your images can be converted.
    ++</p>
    ++
    ++<p>
    ++Of course, not every image can be accurately represented with only 256 colors.
    ++Some images, for example, might need 257, 310, 512, or 912 colors to
    ++look correct. In such cases, vector quantization can also be helpful.
    ++</p>
    ++
    ++<h4 id="vq">Vector quantization</h4>
    ++
    ++<p>
    ++The process of creating an indexed image may be better described as vector
    ++quantization (VQ). VQ serves as a rounding process for multidimensional
    ++numbers.  In this process, all the colors in your image get grouped based upon
    ++their similarity. For a given group, all colors in that group are replaced by a
    ++single <em>center point</em> value, which minimizes error for colors in that
    ++cell (or "site" if you're using the Voronoi terminology). In Figure 3,
    ++the green dots represent input colors, and the red dots are the center points
    ++that replace the input colors. Each cell is bounded by blue lines.
    ++</p>
    ++
    ++  <img src="{@docRoot}topic/performance/images/vq.gif">
    ++  <p class="img-caption">
    ++Figure 3. Applying vector quantization to the colors in an image.
    ++</p>
    ++
    ++<p>
    ++The result of applying VQ to an image reduces the number of unique colors,
    ++replacing each group of colors with a single color that's "pretty close"
    ++in visual quality.
    ++</p>
    ++
    ++<p>
    ++This technique also allows you to define the maximum number of unique colors in
    ++your image. For example, Figure 4 shows the a parrot head in 16.7 million colors
    ++(24 bits per pixel, or bpp) alongside a version that only allows only
    ++16 (3 bpp) unique colors to be used.
    ++</p>
    ++
    ++  <img src="{@docRoot}topic/performance/images/parrot.png">
    ++  <p class="img-caption">
    ++Figure 4. Image before and after application of vector quantification.
    ++  </p>
    ++
    ++<p>
    ++Immediately, you can see that there's a loss of quality; most of the gradient
    ++colors have been replaced, imparting a banding effect to the image. This image
    ++needs more than 16 unique colors.
    ++</p>
    ++
    ++<p>
    ++Setting up a VQ step in your pipeline can help you get a better sense of the
    ++true number of unique colors that your image uses, and can help you reduce them
    ++significantly. There are a number of readily available tools that you can use
    ++to help you implement this technique.
    ++</p>
    ++
    ++<h3 id="jpg">JPG</h3>
    ++
    ++<p>
    ++If you are using JPG images, there are several small changes you can make that
    ++potentially provide significant file-size savings. These include:
    ++</p>
    ++
    ++<ul>
    ++   <li>
    ++Producing a smaller file size through different encoding methods (without
    ++impacting quality).
    ++   </li>
    ++
    ++   <li>
    ++Adjusting quality slightly in order to yield better compression.
    ++   </li>
    ++</ul>
    ++
    ++<p>Pursuing these strategies can often net you file-size reductions of up to
    ++25%.
    ++</p>
    ++
    ++<p>
    ++When choosing tools, remember that photo exporting tools can
    ++insert unnecessary metadata, such as GPS information, into your images. At
    ++a minimum, try to leverage existing tools to help strip out this information
    ++from your files.
    ++</p>
    ++
    ++<h3 id="webp">WebP</h3>
    ++
    ++<p>
    ++WebP is a newer image format supported from Android 4.2.1 (API level 17). This
    ++format provides superior lossless and lossy compression for images on the web.
    ++Using WebP, developers can create smaller, richer images. WebP lossless image
    ++files are, on average,
    ++<a href="https://developers.google.com/speed/webp/docs/webp_lossless_alpha_study#conclusions">
    ++26% smaller</a> than PNGs. These image files also support
    ++transparency (also known as alpha channel) at a cost of just
    ++<a href="https://developers.google.com/speed/webp/docs/webp_lossless_alpha_study#results">
    ++22% more</a> bytes.
    ++</p>
    ++
    ++<p>
    ++WebP lossy images are
    ++<a href="https://developers.google.com/speed/webp/docs/webp_study#experiment_1_webp_vs_jpeg_at_equal_ssim_index">
    ++25-34% smaller</a> than comparable JPG images at equivalent
    ++<a href="https://en.wikipedia.org/wiki/Structural_similarity">SSIM</a>
    ++quality indices. For cases when lossy RGB compression is acceptable, lossy
    ++WebP also supports transparency, typically producing file sizes 3 times smaller
    ++than PNG.
    ++</p>
    ++
    ++<p>
    ++For more information about WebP, visit the
    ++<a href="https://developers.google.com/speed/webp/">WebP site</a>.
    ++</p>
    ++
    ++<h2 id="sf">Selecting a Format</h2>
    ++
    ++<p>
    ++Different image formats are suitable for different types of images. JPG and PNG
    ++have very different compression processes, and they produce quite different
    ++results.
    ++</p>
    ++
    ++<p>
    ++The decision between PNG and JPG often comes down to the complexity of the
    ++image itself. Figure 5 shows two images that come out quite differently
    ++depending on which compression scheme the developer applies. The image on the
    ++left has many small details, and thus compresses more efficiently with JPG. The
    ++image on the right, with runs of the same color, compresses more efficiently
    ++with PNG.
    ++</p>
    ++
    ++  <img src="{@docRoot}topic/performance/images/comparison.png">
    ++  <p class="img-caption">
    ++Figure 5. Suitable cases for JPG vs. PNG
    ++  </p>
    ++
    ++
    ++<p>
    ++WebP as a format can support both lossy and lossless modes, making it an ideal
    ++replacement for both PNG and JPG. The only thing to keep in mind is that it
    ++only has native support on devices running Android 4.2.1 (API level 17) and
    ++higher. Fortunately, the large
    ++<a
    ++href="https://developer.android.com/about/dashboards/index.html#Platform">
    ++majority of devices</a> satisfy that requirement.
    ++</p>
    ++
    ++<p>
    ++Figure 6 provides a simple visualization to help you decide which compression
    ++scheme to use.
    ++</p>
    ++
    ++  <img src="{@docRoot}topic/performance/images/decisions.png">
    ++  <p class="img-caption">
    ++Figure 6. Deciding on a compression scheme
    ++  </p>
    ++
    ++<h2 id="doqv">Determining Optimal Quality Values</h2>
    ++
    ++<p>
    ++There are several techniques you can use to achieve the right balance between
    ++compression and image quality. One technique uses scalar values and therefore
    ++only works for JPG and WebP. The other technique takes advantage of the
    ++Butteraugli library, and is usable for all image formats.
    ++</p>
    ++
    ++<h3 id="sv">Scalar values (JPG and WebP only)</h3>
    ++
    ++<p>
    ++The power of JPG and WebP comes from the fact that you can use a scalar value
    ++to balance quality against file size. The trick is finding out what the correct
    ++quality value is for your image. Too low a quality level produces a small file
    ++at the cost of image quality. Too high a quality level increases file size
    ++without providing a noticeable benefit to the user.
    ++</p>
    ++
    ++<p>
    ++The most straightforward solution is to pick some non-maximum value, and use
    ++that value. However, be aware that the quality value affects every image
    ++differently. While a quality of 75%, for example, may look fine on most images,
    ++there may be some cases do not fare as well. You should make sure to test your
    ++chosen maximum value against a representative sample of images. Also, make
    ++sure to perform all of your tests against the original images, and not on
    ++compressed versions.
    ++</p>
    ++
    ++<p>
    ++For large media applications that upload and re-send millions of JPGs a day,
    ++hand-tuning for each asset is impractical. You might address this challenge by
    ++specifying several different quality levels, according to image category. For
    ++example, you might set 35% as the quality setting for thumbnails, since a
    ++smaller image hides more compression artifacts.
    ++</p>
    ++
    ++<h3 id="butter">Butteraugli</h4>
    ++
    ++<p>
    ++The Butteraugli project is a library to test an image's Psychovisual Error
    ++Threshold: the point at which a viewer starts to notice image degradation. In
    ++other words, this project attempts to quantify how distorted your compressed
    ++image is.
    ++</p>
    ++
    ++<p>
    ++Butteraugli allows you to define a goal for visual quality, and then run PNG,
    ++JPG, WebP lossy, and WebP lossless compressions. You can then choose the image
    ++that is the best balance of file size and Butteraugli level. Figure 7 shows an
    ++example of how Butteraugli was used to find the minimal JPG quality level
    ++before the visual distortion was high enough for a user could perceive a
    ++problem; the result is a roughly 65% reduction in file size.
    ++</p>
    ++
    ++  <img src="{@docRoot}topic/performance/images/moarparrots.png">
    ++  <p class="img-caption">
    ++Figure 7. An image before and after application of Butteraugli technology.
    ++  </p>
    ++
    ++<p>
    ++Butteraugli allows you to proceed based on either output or input. That is, you
    ++can look for the lowest quality setting before a user perceives noticeable
    ++distortion in the resulting image, or you can iteratively set image-distortion
    ++levels to learn their associated quality levels.
    ++</p>
    ++
    ++<h2 id="sizes">Serving Sizes</h2>
    ++
    ++<p>
    ++It is tempting to keep only a single resolution of an image on a server. When a
    ++device accesses the image, the server serves it at that one resolution and
    ++leaves downscaling to the device.
    ++</p>
    ++
    ++<p>
    ++This solution is convenient for the developer, but potentially painful for the
    ++user, because the solution forces the user to download much more data than they
    ++need.
    ++
    ++You should instead store multiple sizes of images, and serve the size that is
    ++most appropriate for a particular use case. For example, for a thumbnail,
    ++serving an actual thumbnail image instead of serving and downscaling a
    ++full-size version consumes much less network bandwidth
    ++</p>
    ++
    ++</p>
    ++This approach is good for download speed, and is less costly for users who may
    ++be using limited or metered data plans. Proceeding like this also results in
    ++the image's taking less space on the device and in main memory. In the
    ++case of large images, such as 4K ones, this approach also saves the device
    ++from having to resize images before loading them.
    ++</p>
    ++
    ++<p>
    ++Implementing this approach requires that you have a backend image service to
    ++provide images at various resolutions with proper caching. There are existing
    ++services that can provide help with this task. For example,
    ++<a href="https://cloud.google.com/appengine/">App Engine</a> comes
    ++with image resizing functionality already installed.
    ++</p>
    +diff --git a/docs/html/topic/performance/optimizing-view-hierarchies.jd b/docs/html/topic/performance/optimizing-view-hierarchies.jd
    +deleted file mode 100644
    +index 27d3d16..0000000
    +--- a/docs/html/topic/performance/optimizing-view-hierarchies.jd
    ++++ /dev/null
    +@@ -1,388 +0,0 @@
    +-page.title=Performance and View Hierarchies
    +-@jd:body
    +-
    +-<div id="qv-wrapper">
    +-<div id="qv">
    +-
    +-<h2>In this document</h2>
    +-<ol>
    +-<li><a href="#lmp">Layout-and-Measure Performance</a>
    +-  <ol>
    +-    <li><a href="#managing">Managing complexity: layouts matter</a></li>
    +-    <li><a href="#double">Double taxation</a></li>
    +-  </ol>
    +-</li>
    +-<li><a href="#dx">Diagnosing View Hierarchy Issues</a>
    +-  <ol>
    +-    <li><a href="#systrace">Systrace</a></li>
    +-    <li><a href="#profile">Profile GPU rendering</a></li>
    +-    <li><a href="#lint">Lint</a></li>
    +-    <li><a href="#hv">Hierarchy Viewer</a></li>
    +-  </ol>
    +-</li>
    +-<li><a href="#solving">Solving View Hierarchy Issues</a>
    +-   <ol>
    +-      <li><a href="#removing">Removing redundant nested layouts</a></li>
    +-      <li><a href="#cheaper">Adopting a cheaper layout</a></li>
    +-   </ol>
    +-      </li>
    +-</ol>
    +-</div>
    +-</div>
    +-
    +-
    +-<p>
    +-The way you manage the hierarchy of your {@link android.view.View} objects can
    +-have a substantial impact on your app’s performance. This page describes how to
    +-assess whether your view hierarchy is slowing your app down, and offers some
    +-strategies for addressing issues that may arise.
    +-</p>
    +-
    +-<h2 id="lmp">Layout and Measure Performance</h2>
    +-<p>
    +-The rendering pipeline includes a <em>layout-and-measure</em>
    +-stage, during which the system appropriately positions the relevant items in
    +-your view hierarchy. The measure part of this stage determines the sizes and
    +-boundaries of {@link android.view.View} objects. The layout part determines where on the screen to
    +-position the {@link android.view.View} objects.
    +-</p>
    +-
    +-<p>
    +-Both of these pipeline stages incur some small cost per view or layout that they
    +-process. Most of the time, this cost is minimal and doesn’t noticeably affect
    +-performance. However, it can be greater when an app adds or removes View
    +-objects, such as when a {@link android.support.v7.widget.RecyclerView}
    +-object recycles them or reuses them. The
    +-cost can also be higher if a {@link android.view.View} object needs to consider
    +-resizing to main its constraints: For example, if your app calls
    +-{@link android.widget.TextView#setText(char[], int, int) SetText()} on a
    +-{@link android.view.View} object that wraps text, the
    +-{@link android.view.View} may need to resize.
    +-</p>
    +-
    +-<p>
    +-If cases like these take too long, they can prevent a frame from rendering
    +-within the allowed 16ms, so that frames are dropped, and animation becomes
    +-janky.
    +-</p>
    +-
    +-<p>
    +-Because you cannot move these operations to a worker thread&mdash;your app must
    +-process them on the main thread&mdash;your best bet is to optimize them so that
    +-they can take as little time as possible.
    +-</p>
    +-
    +-<h3 id="managing">Managing complexity: layouts matter</h3>
    +-
    +-<p>
    +-Android <a
    +-href="{@docRoot}guide/topics/ui/declaring-layout.html">Layouts</a>
    +-allow you to nest UI objects in the view hierarchy. This nesting can also impose
    +-a layout cost. When your app processes an object for layout, the app performs
    +-the same process on all children of the layout as well. For a complicated
    +-layout, sometimes a cost only arises the first time the system computes the
    +-layout. For instance, when your app recycles a complex list item in a
    +-{@link android.support.v7.widget.RecyclerView} object, the
    +-system needs to lay out all of the objects. In another example, trivial changes
    +-can propagate up the chain toward the parent
    +-until they reach an object that doesn’t affect the size of the parent.
    +-</p>
    +-
    +-<p>
    +-The most common case in which layout takes an especially long time is when
    +-hierarchies of {@link android.view.View} objects are nested within one another. Each nested layout
    +-object adds cost to the layout stage. The flatter your hierarchy, the less
    +-time that it takes for the layout stage to complete.
    +-</p>
    +-
    +-<p>
    +-If you are using the {@link android.widget.RelativeLayout} class, you may be able to achieve the same
    +-effect, at lower cost, by using nested, unweighted
    +-{@link android.widget.LinearLayout} views instead. Additionally, if your app
    +-targets Android N (API level 24), it is likely that
    +-you can use a special layout editor to create a <a
    +-href="http://tools.android.com/tech-docs/layout-editor">{@code ConstraintLayout}</a>
    +-object instead of {@link android.widget.RelativeLayout}. Doing so allows you
    +-to avoid many of the issues this section
    +-describes. The <a
    +-href="http://tools.android.com/tech-docs/layout-editor">{@code ConstraintLayout}</a>
    +-class offers similar layout control, but
    +-with much-improved performance. This class uses its own constraint-solving
    +-system to resolve relationships between views in a very different way from
    +-standard layouts.
    +-</p>
    +-
    +-<h3 id="double">Double Taxation</h3>
    +-
    +-<p>
    +-Typically, the framework executes the <a
    +-href="{@docRoot}guide/topics/ui/declaring-layout.html">layout</a>
    +-or measure stage in a single pass and quite quickly. However, with some more
    +-complicated layout cases, the framework may have to iterate multiple times on
    +-the layout or measure stage before ultimately positioning the elements. Having
    +-to perform more than one layout-and-measure iteration is referred to as
    +-<em>double taxation.</em>
    +-</p>
    +-
    +-<p>
    +-For example, when you use the {@link android.widget.RelativeLayout} container, which allows you to
    +-position {@link android.view.View} objects with respect to the positions of other {@link android.view.View} objects, the
    +-framework performs the following actions:
    +-</p>
    +-
    +-<ol style="1">
    +-   <li>Executes a layout-and-measure pass, during which the framework calculates
    +-each child object’s position and size, based on each child’s request.
    +-   <li>Uses this data, also taking object weights into account, to figure out the
    +-proper position of correlated views.
    +-   <li>Performs a second layout pass to finalize the objects’ positions.
    +-   <li>Goes on to the next stage of the rendering process.</li></ol>
    +-
    +-<p>
    +-The more levels your view hierarchy has, the greater the potential performance
    +-penalty.
    +-</p>
    +-
    +-<p>
    +-Containers other than {@link android.widget.RelativeLayout} may also give rise to double taxation. For
    +-example:
    +-</p>
    +-
    +-<ul>
    +-   <li>A {@link android.widget.LinearLayout} view
    +-could result in a double layout-and-measure pass if you make it horizontal.
    +-A double layout-and-measure pass may also occur in a vertical orientation if you
    +-add <a
    +-href="{@docRoot}reference/android/widget/LinearLayout.html#attr_android:measureWithLargestChild">measureWithLargestChild</a>,
    +-in which case the framework may need to do a second pass to resolve the proper
    +-sizes of objects.
    +-   <li>The {@link android.widget.GridLayout}
    +-has a similar issue. While this container also allows relative positioning, it
    +-normally avoids double taxation by pre-processing the positional relationships
    +-among child views. However, if the layout uses weights or fill with the
    +-{@link android.view.Gravity} class, the
    +-benefit of that preprocessing is lost, and the framework may have to perform
    +-multiple passes if it the container were a {@link android.widget.RelativeLayout}.</li>
    +-</ul>
    +-<p>
    +-Multiple layout-and-measure passes are not, in themselves, a performance burden.
    +-But they can become so if they’re in the wrong spot. You should be wary of
    +-situations where one of the following conditions applies to your container:
    +-</p>
    +-
    +-<ul>
    +-   <li>It is a root element in your view hierarchy.
    +-   <li>It has a deep view hierarchy beneath it.
    +-   <li>It is nested.
    +-   <li>There are many instances of it populating the screen, similar to children
    +-   in a {@link android.widget.ListView} object.</li>
    +-</ul>
    +-
    +-<h2 id="dx">Diagnosing View Hierarchy Issues</h2>
    +-
    +-<p>
    +-Layout performance is a complex problem with many facets. There are a couple of
    +-tools that can give you solid indications about where performance bottlenecks
    +-are occurring. A few other tools provide less definitive information, but can
    +-also provide helpful hints.
    +-</p>
    +-
    +-<p>
    +-<h3 id="systrace">Systrace</h3>
    +-</p>
    +-
    +-<p>
    +-One tool that provides excellent data about performance is <a
    +-href="{@docRoot}studio/profile/systrace.html">Systrace</a>,
    +-which is built into Android Studio. The Systrace tool allows you to collect and
    +-inspect timing information across an entire Android device, allowing you to see
    +-specifically where performance bottlenecks arise. For more information about
    +-Systrace, see <a href=”{docRoot}<a href="{@docRoot}studio/profile/systrace.html">
    +-Analyze UI Performance with Systrace</a>.
    +-</p>
    +-
    +-<h3 id="profile">Profile GPU rendering</h3>
    +-
    +-<p>
    +-The other tool most likely to provide you with concrete information about
    +-performance bottlenecks is the on-device <a
    +-href="{@docRoot}studio/profile/dev-options-rendering.html">
    +-Profile GPU rendering</a> tool, available on devices powered by Android 6.0 (API
    +-level 23) and later.  This tool allows you to see how long the layout-and-measurestage is
    +- taking for <a href="https://youtu.be/erGJw8WDV74">each frame
    +-of rendering</a>. This data can help you diagnose runtime performance issues,
    +-and help you determine what, if any layout-and-measure issues you need to
    +-address.
    +-</p>
    +-
    +-<p>
    +-In its graphical representation of the data it captures, <a
    +-href="{@docRoot}studio/profile/dev-options-rendering.html">Profile
    +-GPU rendering</a> uses the color blue to represent layout time. For more
    +-information about how to use this tool, see <a
    +-href="{@docRoot}studio/profile/dev-options-rendering.html">Profile
    +-GPU Rendering Walkthrough.</a>
    +-</p>
    +-
    +-<h3 id="lint">Lint</h3>
    +-
    +-<p>
    +-Android Studio’s <a
    +-href="{@docRoot}studio/write/lint.html">Lint</a> tool can
    +-help you gain a sense of inefficiencies in the view hierarchy. To use this tool,
    +-select <strong>Analyze > Inspect Code</strong>, as shown in Figure 1.
    +-</p>
    +-
    +-  <img src="{@docRoot}topic/performance/images/lint-inspect-code.png">
    +-  <p class="img-caption">
    +-    <strong>Figure 1.</strong> Locating <strong>Inspect Code</strong> in the
    +-Android Studio.
    +-  </p>
    +-
    +-<p>
    +-Information about various layout items appears under
    +-<em>Android > Lint > Performance</em>. To see more detail,
    +-you can click on each item to expand it, and see more
    +-information in the pane on the right side of the screen.
    +-Figure 2 shows an example of such a display.
    +-</p>
    +-
    +-  <img src="{@docRoot}topic/performance/images/lint-display.png">
    +-  <p class="img-caption">
    +-    <strong>Figure 2.</strong> Viewing information about specific
    +-issues that the lint tool has identified.
    +-  </p>
    +-
    +-
    +-<p>
    +-Clicking on one of these items reveals, in the pane to the right, the problem
    +-associated with that item.
    +-</p>
    +-
    +-<p>
    +-To understand more about specific topics and issues in this area, see the <a
    +-href="{@docRoot}studio/write/lint.html">Lint
    +-</a>documentation.
    +-</p>
    +-
    +-<h3 id="hv">Hierarchy Viewer</h3>
    +-
    +-<p>
    +-Android Studio’s <a
    +-href="{@docRoot}studio/profile/hierarchy-viewer.html">Hierarchy
    +-Viewer</a> tool provides a visual representation of your app’s view hierarchy.
    +-It is a good way to navigate the hierarchy of your app, providing a clear visual
    +-representation of a particular view’s parent chain, and allowing you to inspect
    +-the layouts that your app constructs.
    +-</p>
    +-
    +-<p>
    +-The views that Hierarchy Viewer presents can also help identify performance
    +-problems arising from double taxation. It can also provide an easy way for you
    +-to identify deep chains of nested layouts, or layout areas with a large amount
    +-of nested children, another potential source of performance costs. In these
    +-scenarios, the layout-and-measure stages can be particularly costly,
    +-resulting in performance issues.
    +-</p>
    +-
    +-<p>
    +-You can also can get a sense of relative time taken by layout-and-measure
    +-operations by clicking the “profile node” button.
    +-</p>
    +-
    +-<p>
    +-For more information about Hierarchy Viewer, see <a
    +-href="{@docRoot}studio/profile/optimize-ui.html#HierarchyViewer">Optimizing
    +-Your UI</a>.
    +-</p>
    +-
    +-<h2 id="solving">Solving View Hierarchy Issues</h2>
    +-
    +-<p>
    +-The fundamental concept behind solving performance problems that arise from view
    +-hierarchies is simple in concept, but more difficult in practice. Preventing
    +-view hierarchies from imposing performance penalties encompasses the dual goals
    +-of flattening your view hierarchy and reducing double taxation. This section
    +-discusses some strategies for pursuing these goals.
    +-</p>
    +-
    +-<h3 id="removing">Removing redundant nested layouts</h3>
    +-
    +-<p>
    +-Developers often use more nested layouts than necessary. For example, a
    +-{@link android.widget.RelativeLayout} container might contain a single child that is also a
    +-{@link android.widget.RelativeLayout} container. This nesting amounts to redundancy, and adds
    +-unnecessary cost to the view hierarchy.
    +-</p>
    +-
    +-<p>
    +-Lint can often flag this problem for you, reducing debugging time.
    +-</p>
    +-
    +-<h3>Adopting Merge/Include </h3>
    +-<p>
    +-One frequent cause of redundant nested layouts is the <a
    +-href="{@docRoot}training/improving-layouts/reusing-layouts.html">
    +-&lt;include&gt;
    +-tag</a>. For example, you may define a re-usable layout as follows:
    +-</p>
    +-
    +-<pre class="prettyprint">
    +-&lt;LinearLayout&gt;
    +-    &lt;!-- some stuff here --&gt;
    +-&lt;/LinearLayout&gt;
    +-&lt;/pre&gt;
    +-</pre>
    +-
    +-<p>
    +-And then an include tag to add this item to the parent container:
    +-</p>
    +-
    +-<pre class="prettyprint">
    +-&lt;LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    +-    android:orientation="vertical"
    +-    android:layout_width="match_parent"
    +-    android:layout_height="match_parent"
    +-    android:background="@color/app_bg"
    +-    android:gravity="center_horizontal"&gt;
    +-
    +-    &lt;include layout="@layout/titlebar"/&gt;
    +-
    +-    &lt;TextView android:layout_width="match_parent"
    +-              android:layout_height="wrap_content"
    +-              android:text="@string/hello"
    +-              android:padding="10dp" /&gt;
    +-
    +-    ...
    +-
    +-&lt;/LinearLayout&gt;
    +-</pre>
    +-
    +-<p>
    +-The include unnecessarily nests the first layout within the second layout.
    +-</p>
    +-
    +-<p>
    +-The <a
    +-href="{@docRoot}training/improving-layouts/reusing-layouts.html#Merge">merge
    +-</a>tag can help prevent this issue. For information about this tag, see <a
    +-href="{@docRoot}training/improving-layouts/reusing-layouts.html#Merge">Re-using
    +-Layouts with &lt;include&gt;</a>.
    +-</p>
    +-
    +-<h3 id="cheaper">Adopting a cheaper layout</h3>
    +-
    +-<p>
    +-You may not be able to adjust your existing layout scheme so that it doesn’t
    +-contain redundant layouts. In certain cases, the only solution may be to flatten
    +-your hierarchy by switching over to an entirely different layout type.
    +-</p>
    +-
    +-<p>
    +-For example, you may find that a {@link android.widget.TableLayout}
    +-provides the same functionality as a more complex layout with many
    +-positional dependencies. In the N release of Android, the
    +-<a
    +-href="http://tools.android.com/tech-docs/layout-editor">{@code ConstraintLayout}</a> class provides similar functionality to
    +-{@link android.widget.RelativeLayout}, but at a significantly lower cost.
    +-</p>
    +diff --git a/docs/html/topic/performance/power/battery-historian.jd b/docs/html/topic/performance/power/battery-historian.jd
    +new file mode 100644
    +index 0000000..79ea59d
    +--- /dev/null
    ++++ b/docs/html/topic/performance/power/battery-historian.jd
    +@@ -0,0 +1,247 @@
    ++page.title=Analyzing Power Use with Battery Historian
    ++page.metaDescription=Improve network performance by optimizing image size.
    ++
    ++meta.tags="power"
    ++page.tags="power"
    ++
    ++@jd:body
    ++
    ++<div id="qv-wrapper">
    ++<div id="qv">
    ++
    ++<h2>In this document</h2>
    ++    <ol>
    ++      <li>
    ++        <a href="#sv">System-wide View</a>
    ++      </li>
    ++      <li>
    ++        <a href="#asd">App-Specific Data</a>
    ++      </li>
    ++      <li>
    ++        <a href="#usecases">Other Cases Where Battery Historian Can Help</a>
    ++      </li>
    ++    </ol>
    ++<h2>See also</h2>
    ++   <ol>
    ++      <li>
    ++      <a href="https://github.com/google/battery-historian">Battery Historian
    ++      on GitHub</a>
    ++      </li>
    ++
    ++      <li>
    ++      <a href="https://developer.android.com/studio/profile/battery-historian.html">
    ++      Batterystats and Battery Historian Walkthrough
    ++      </li>
    ++
    ++      <li>
    ++      <a href="https://youtu.be/VC2Hlb22mZM?list=PLOU2XLYxmsILe6_eGvDN3GyiodoV3qNSC&t=2063"
    ++      target="_blank">
    ++      Battery Historian talk at Google I/O 2016</a>
    ++      </li>
    ++    </ol>
    ++  </div>
    ++</div>
    ++
    ++<p>
    ++The Battery Historian tool provides insight into a device’s battery consumption
    ++over time. At a system-wide level, the tool visualizes power-related events from
    ++the system logs in an HTML representation. At an app-specific level, the tool
    ++provides a variety of data that can help you identify battery-draining app
    ++behavior.
    ++</p>
    ++
    ++<p>
    ++This document describes some of the ways you can use Battery Historian
    ++to learn about battery-consumption patterns. The document begins by explaining
    ++how to read the system-wide data that Battery Historian reports. Then,
    ++it presents ways in which you can use Battery Historian to diagnose
    ++and troubleshoot your own app's behavior related to battery consumption.
    ++Last, it offers several tips on scenarios in which Battery Historian may be
    ++particularly useful.
    ++</p>
    ++
    ++<h2 id="sv">System-wide View</h2>
    ++
    ++<p>
    ++The Battery Historian tool provides a system-wide visualization of various
    ++app and system behaviors, along with their correlation against battery
    ++consumption over time. This view, shown in Figure 1, can help you
    ++diagnose and identify power use issues with your app.
    ++</p>
    ++
    ++  <img src="{@docRoot}topic/performance/images/generic-timeline.png">
    ++  <p class="img-caption">
    ++<strong>Figure 1.</strong>
    ++Battery Historian’s display of system-wide events affecting power
    ++consumption.
    ++  </p>
    ++
    ++<p>
    ++Of particular interest in this figure is the black, horizontal, downward trend
    ++line representing Battery Level, measured on the y-axis. For example, at the
    ++very beginning of the Battery Level line, at approximately 6:50 AM, the
    ++visualization shows a relatively steep drop in battery level.
    ++</p>
    ++
    ++<p>
    ++Figure 2 provides a close-up of that part of the display.
    ++</p>
    ++
    ++  <img src="{@docRoot}topic/performance/images/s-generic-closeup.png">
    ++  <p class="img-caption">
    ++<strong>Figure 2.</strong>
    ++A close-up of the Battery Historian timeline from roughly 6:50 AM to 7:20 AM.
    ++  </p>
    ++
    ++<p>
    ++At the very beginning of the Battery Level line, as battery decline steeply,
    ++the display shows three things happening: The CPU is running, an app has
    ++acquired a wakelock, and the screen is on. In this way, Battery Historian helps
    ++you understand what events are happening when battery consumption is high. You
    ++can then target these behaviors in your app and investigate whether there are
    ++related optimizations you can make.
    ++</p>
    ++
    ++<p>
    ++The system-wide visualization can provide other clues, as well. For instance, if
    ++it shows that the mobile radio is frequently being turned off and on, there may
    ++be an opportunity to optimize this behavior through <a href=”intelligent
    ++scheduling page”>intelligent scheduling APIs</a> such as JobScheduler or
    ++Firebase Job Dispatcher.
    ++</p>
    ++
    ++<p>
    ++The next section explains how to investigate behavior and events specific to
    ++your own app.
    ++</p>
    ++
    ++<p>
    ++<h2 id="asd">App-Specific Data</h2>
    ++</p>
    ++
    ++<p>
    ++In addition to the macro-level data provided by the system-wide view, Battery
    ++Historian also provides tables and some visualization of data specific to each
    ++app running on your device. The tabular data includes:
    ++</p>
    ++
    ++<ul>
    ++   <li>The app’s estimated power use on the device.</li>
    ++   <li>Network information.</li>
    ++   <li>Wakelocks.</li>
    ++   <li>Services.</li>
    ++   <li>Process info.</li>
    ++</ul>
    ++
    ++<p>
    ++The tables provide two dimensions of data about your app. First, you can look
    ++up where your app’s power usage ranks compared to other apps. To do so, click
    ++<em>Device Power Estimates</em> table under <em>Tables</em>. This example
    ++examines a fictional app called Pug Power.
    ++</p>
    ++
    ++  <img src="{@docRoot}topic/performance/images/app-rankings.png">
    ++  <p class="img-caption">
    ++<strong>Figure 3.</strong> Investigating which apps consume the most power.
    ++  </p>
    ++
    ++<p>
    ++The table in Figure 3 reveals that Pug Power is the ninth biggest consumer of
    ++battery power on this device, and the third biggest app that is not part of the
    ++OS. This data suggests that this app bears deeper investigation.
    ++</p>
    ++
    ++<p>
    ++To look up the data for a specific app, enter its package name into the lower
    ++of the two dropdown menus under <em>App Selection</em>, located under the left
    ++side of the visualization.
    ++</p>
    ++
    ++  <img src="{@docRoot}topic/performance/images/dropdown.png">
    ++  <p class="img-caption">
    ++<strong>Figure 4.</strong> Entering a specific app whose data to view.
    ++  </p>
    ++
    ++<p>
    ++When you select a specific app, the following data visualization categories
    ++change to display app-specific data instead of system-wide data:
    ++</p>
    ++
    ++<ul>
    ++   <li>SyncManager.</li>
    ++   <li>Foreground process.</li>
    ++   <li>Userspace Wakelock.</li>
    ++   <li>Top app.</li>
    ++   <li>JobScheduler.</li>
    ++   <li>Activity Manager Proc.</li>
    ++</ul>
    ++
    ++The SyncManager and JobScheduler visualizations immediately make it obvious if
    ++your app performs syncs and executes jobs more frequently than necessary. In
    ++doing so, they can quickly reveal an opportunity to optimize your app’s
    ++behavior for improved battery performance.
    ++
    ++<p>
    ++You can also obtain one more piece of app-specific visualization data,
    ++<em>Userspace Wakelock</em>. To include this information in the bug report,
    ++enter the following command in your terminal window:
    ++</p>
    ++
    ++<pre>
    ++$ adb shell dumpsys batterystats --enable full-wake-history
    ++</pre>
    ++
    ++<p class="note">
    ++<strong>Note:</strong> From Android 6.0 (API level 23), the platform includes
    ++Doze functionality, which imposes certain optimizations on apps. For example,
    ++Doze batches jobs to take place during brief maintenance windows, regardless of
    ++how JobScheduler has scheduled them.
    ++</p>
    ++
    ++<p>
    ++Figures 5 and 6 show data for Pug Power: Figure 5
    ++shows the visualization of
    ++the app-specific data, and Figure 6 shows the corresponding tabular data.
    ++</p>
    ++
    ++  <img src="{@docRoot}topic/performance/images/pug-visualization.png">
    ++  <p class="img-caption">
    ++<strong>Figure 5.</strong> Visualization of data for fictional app Pug Power.
    ++  </p>
    ++
    ++  <img src="{@docRoot}topic/performance/images/pugspecificdata.png">
    ++  <p class="img-caption">
    ++<strong>Figure 6.</strong> Tabular data for the fictional Pug Power app.
    ++  </p>
    ++
    ++<p>
    ++A look at the visualization does not show anything immediately obvious.
    ++The JobScheduler line shows that the app has no jobs scheduled. The SyncManager
    ++line shows that the app has not performed any syncs.
    ++</p>
    ++
    ++<p>
    ++However, examination of the <em>Wakelocks</em> segment of the tabular data
    ++reveals that Pug Power acquires wakelocks totaling over an hour. This unusual
    ++and costly behavior can account for the app’s high level of power consumption.
    ++This piece of information helps the developer target an area where optimization
    ++is likely to greatly help. In this case, why does the app acquire so much
    ++wakelock time, and how can the developer ameliorate this behavior?
    ++</p>
    ++
    ++<h2 id="usecases">Other Cases Where Battery Historian Can Help</h2>
    ++
    ++<p>
    ++There are many other cases in which Battery Historian can help you diagnose
    ++opportunities for improving battery behavior. For example, Battery Historian
    ++can tell you if your app is:
    ++</p>
    ++
    ++<ul>
    ++   <li>Firing wakeup alarms overly frequently (every 10 seconds or less).</li>
    ++   <li>Continuously holding a GPS lock.</li>
    ++   <li>Scheduling jobs every 30 seconds or less.</li>
    ++   <li>Scheduling syncs every 30 seconds or less.</li>
    ++   <li>Using the cellular radio more frequently than you expect.</li>
    ++</ul>
    ++
    +diff --git a/docs/html/topic/performance/power/index.jd b/docs/html/topic/performance/power/index.jd
    +new file mode 100644
    +index 0000000..88addce
    +--- /dev/null
    ++++ b/docs/html/topic/performance/power/index.jd
    +@@ -0,0 +1,125 @@
    ++page.title=Optimizing for Battery Life
    ++page.metaDescription=Learn how to help your app go easier on the battery.
    ++
    ++meta.tags="performance"
    ++page.tags="performance"
    ++
    ++@jd:body
    ++
    ++<div id="qv-wrapper">
    ++  <div id="qv">
    ++    <h2>
    ++      In this document
    ++    </h2>
    ++    <ol>
    ++      <li>
    ++        <a href="#lazy">Lazy First</a>
    ++      </li>
    ++      <li>
    ++        <a href="#features">Platform Features</a>
    ++      </li>
    ++      <li>
    ++        <a href="#toolery">Tooling</a>
    ++      </li>
    ++    </ol>
    ++  </div>
    ++</div>
    ++
    ++<p>Battery life is the single most important aspect of the mobile user
    ++experience. A device without power offers no functionality at all.
    ++For this reason, it is critically important that apps be as respectful of
    ++battery life as possible.</p>
    ++
    ++<p>There are three important things to keep in mind in keeping your app
    ++power-thrifty:</p>
    ++<ul>
    ++<li>Make your apps <em>Lazy First</em>.</li>
    ++<li>Take advantage of platform features that can help manage your app's battery
    ++consumption.</li>
    ++<li>Use tools that can help you identify battery-draining culprits.</li>
    ++</ul>
    ++
    ++<h2 id="lazy">Lazy First</h2>
    ++
    ++<p>Making your app Lazy First means looking for ways to reduce and optimize
    ++operations that are particularly battery-intensive. The core questions
    ++underpinning Lazy First design are:
    ++
    ++<ul>
    ++
    ++   <li><strong>Reduce:</strong> Are there redundant operations your app can cut
    ++out? For example, can it cache downloaded data instead of repeatedly waking
    ++   up the radio to re-download the data?</li>
    ++
    ++   <li><strong>Defer:</strong> Does an app need to perform an action right
    ++   away? For example,
    ++    can it wait until the device is charging before it backs data up to the
    ++    cloud?</li>
    ++
    ++   <li><strong>Coalesce:</strong> Can work be batched, instead of putting the
    ++   device
    ++   into an active state many times? For example, is it really necessary for
    ++   several dozen apps to each turn on the radio at separate times to send
    ++   their messages? Can the messages instead be transmitted during a
    ++   single awakening of the radio?</li>
    ++</ul>
    ++
    ++<p>
    ++You should ask these questions when it comes to using the CPU,
    ++the radio, and the screen. Lazy First design is often a good way
    ++to tame these battery killers.
    ++</p>
    ++
    ++<p>
    ++To help you achieve these and other efficiencies, the Android platform
    ++provides a number of features to help maximize battery life.
    ++</p>
    ++
    ++<h2 id="features">Platform Features</h2>
    ++
    ++<p>
    ++Broadly speaking, the Android platform provides two categories of help
    ++for you to optimize your app's battery use. First, it provides several
    ++APIs that you can implement in your app. You can learn more about these APIs in
    ++<a href="/topic/performance/scheduling.html">Intelligent Job Scheduling</a>
    ++and <a href="/performance/power/network/index.html">
    ++Network Use and Battery Consumption</a>.
    ++</p>
    ++
    ++<p>
    ++There are also internal mechanisms in the platform to help conserve
    ++battery life. While they are not APIs that you implement programmatically,
    ++you should still be aware of them so that your app can leverage them
    ++successfully. For more information, see
    ++<a href="/training/monitoring-device-state/doze-standby.html">Doze and
    ++App Standby</a>.</p>
    ++
    ++<p>
    ++You can get even more benefit out of these features by using the tools
    ++available for the platform to discover the parts of your app that consume
    ++the most power. Finding what to target is a big step toward
    ++successful optimization.
    ++</p>
    ++
    ++<h2 id ="toolery">Tooling</h2>
    ++
    ++<p>There are tools for Android, including
    ++<a href="/studio/profile/dev-options-rendering.html">Profile GPU Rendering</a>
    ++and <a class="external-link"
    ++href="https://github.com/google/battery-historian">Battery Historian</a>
    ++to help you identify areas that you can optimize for better battery life.
    ++Take advantage of these tools to target areas where you can apply the
    ++principles of Lazy First.
    ++</p>
    ++
    ++<section class="dac-section dac-small" id="latest-games"><div class="wrap">
    ++  <h2 class="norule" style="margin:0 0">More resources</h2>
    ++  <div class="resource-widget resource-flow-layout col-16"
    ++       data-query="collection:develop/performance/landing"
    ++       data-sortOrder="random"
    ++       data-cardSizes="6x6"
    ++       data-maxResults="24"
    ++       data-items-per-page="24"
    ++       data-initial-results="3"></div>
    ++  </div>
    ++</section>
    +diff --git a/docs/html/topic/performance/rendering/index.jd b/docs/html/topic/performance/rendering/index.jd
    +new file mode 100644
    +index 0000000..1b16df0
    +--- /dev/null
    ++++ b/docs/html/topic/performance/rendering/index.jd
    +@@ -0,0 +1,60 @@
    ++page.title=Rendering
    ++page.article=true
    ++
    ++page.tags=battery
    ++page.metaDescription=Learn how to optimize your app's rendering performance.
    ++
    ++@jd:body
    ++
    ++
    ++<iframe width="448" height="252"
    ++    src="//www.youtube.com/embed/wIy8g8yNhNk?autohide=1&amp;showinfo=0"
    ++    frameborder="0" allowfullscreen=""
    ++    style="float: right; margin: 0 0 20px 20px;"></iframe>
    ++
    ++<p>
    ++  A key aspect of your app that influences your users' perception of quality is
    ++  the smoothness with which it renders images and text to the screen. It is
    ++  important to avoid jank and sluggish responsiveness when your app is drawing
    ++  to the screen.
    ++</p>
    ++
    ++<p>
    ++  This section helps you learn several ways to optimize your app's rendering
    ++  performance: reducing overdraw, optimizing view hierarchies, and taking
    ++  advantage of the Profile GPU tool.
    ++</p>
    ++
    ++<h2>Rendering Actions</h2>
    ++
    ++<dl>
    ++  <dt>
    ++    <strong><a href="overdraw.html">
    ++        Reducing Overdraw</a></strong>
    ++  </dt>
    ++  <dd>
    ++    Minimize the number of times you app redraws the same pixel in a single
    ++    frame.
    ++  </dd>
    ++
    ++  <dt>
    ++    <strong><a href="optimizing-view-hierarchies.html">
    ++        Performance and View Hierarchies</a></strong>
    ++  </dt>
    ++  <dd>
    ++    Make sure your layout and measurement are executing efficiently, and
    ++    avoid double taxation.
    ++  </dd>
    ++
    ++
    ++  <dt>
    ++    <strong><a href="profile-gpu.html">
    ++        Analyzing with Profile GPU Rendering</a></strong>
    ++  </dt>
    ++  <dd>
    ++    Take advantage of this on-device tool to identify bottlenecks that
    ++    may be slowing your app's rendering down.
    ++  </dd>
    ++
    ++
    ++</dl>
    +diff --git a/docs/html/topic/performance/rendering/optimizing-view-hierarchies.jd b/docs/html/topic/performance/rendering/optimizing-view-hierarchies.jd
    +new file mode 100644
    +index 0000000..27d3d16
    +--- /dev/null
    ++++ b/docs/html/topic/performance/rendering/optimizing-view-hierarchies.jd
    +@@ -0,0 +1,388 @@
    ++page.title=Performance and View Hierarchies
    ++@jd:body
    ++
    ++<div id="qv-wrapper">
    ++<div id="qv">
    ++
    ++<h2>In this document</h2>
    ++<ol>
    ++<li><a href="#lmp">Layout-and-Measure Performance</a>
    ++  <ol>
    ++    <li><a href="#managing">Managing complexity: layouts matter</a></li>
    ++    <li><a href="#double">Double taxation</a></li>
    ++  </ol>
    ++</li>
    ++<li><a href="#dx">Diagnosing View Hierarchy Issues</a>
    ++  <ol>
    ++    <li><a href="#systrace">Systrace</a></li>
    ++    <li><a href="#profile">Profile GPU rendering</a></li>
    ++    <li><a href="#lint">Lint</a></li>
    ++    <li><a href="#hv">Hierarchy Viewer</a></li>
    ++  </ol>
    ++</li>
    ++<li><a href="#solving">Solving View Hierarchy Issues</a>
    ++   <ol>
    ++      <li><a href="#removing">Removing redundant nested layouts</a></li>
    ++      <li><a href="#cheaper">Adopting a cheaper layout</a></li>
    ++   </ol>
    ++      </li>
    ++</ol>
    ++</div>
    ++</div>
    ++
    ++
    ++<p>
    ++The way you manage the hierarchy of your {@link android.view.View} objects can
    ++have a substantial impact on your app’s performance. This page describes how to
    ++assess whether your view hierarchy is slowing your app down, and offers some
    ++strategies for addressing issues that may arise.
    ++</p>
    ++
    ++<h2 id="lmp">Layout and Measure Performance</h2>
    ++<p>
    ++The rendering pipeline includes a <em>layout-and-measure</em>
    ++stage, during which the system appropriately positions the relevant items in
    ++your view hierarchy. The measure part of this stage determines the sizes and
    ++boundaries of {@link android.view.View} objects. The layout part determines where on the screen to
    ++position the {@link android.view.View} objects.
    ++</p>
    ++
    ++<p>
    ++Both of these pipeline stages incur some small cost per view or layout that they
    ++process. Most of the time, this cost is minimal and doesn’t noticeably affect
    ++performance. However, it can be greater when an app adds or removes View
    ++objects, such as when a {@link android.support.v7.widget.RecyclerView}
    ++object recycles them or reuses them. The
    ++cost can also be higher if a {@link android.view.View} object needs to consider
    ++resizing to main its constraints: For example, if your app calls
    ++{@link android.widget.TextView#setText(char[], int, int) SetText()} on a
    ++{@link android.view.View} object that wraps text, the
    ++{@link android.view.View} may need to resize.
    ++</p>
    ++
    ++<p>
    ++If cases like these take too long, they can prevent a frame from rendering
    ++within the allowed 16ms, so that frames are dropped, and animation becomes
    ++janky.
    ++</p>
    ++
    ++<p>
    ++Because you cannot move these operations to a worker thread&mdash;your app must
    ++process them on the main thread&mdash;your best bet is to optimize them so that
    ++they can take as little time as possible.
    ++</p>
    ++
    ++<h3 id="managing">Managing complexity: layouts matter</h3>
    ++
    ++<p>
    ++Android <a
    ++href="{@docRoot}guide/topics/ui/declaring-layout.html">Layouts</a>
    ++allow you to nest UI objects in the view hierarchy. This nesting can also impose
    ++a layout cost. When your app processes an object for layout, the app performs
    ++the same process on all children of the layout as well. For a complicated
    ++layout, sometimes a cost only arises the first time the system computes the
    ++layout. For instance, when your app recycles a complex list item in a
    ++{@link android.support.v7.widget.RecyclerView} object, the
    ++system needs to lay out all of the objects. In another example, trivial changes
    ++can propagate up the chain toward the parent
    ++until they reach an object that doesn’t affect the size of the parent.
    ++</p>
    ++
    ++<p>
    ++The most common case in which layout takes an especially long time is when
    ++hierarchies of {@link android.view.View} objects are nested within one another. Each nested layout
    ++object adds cost to the layout stage. The flatter your hierarchy, the less
    ++time that it takes for the layout stage to complete.
    ++</p>
    ++
    ++<p>
    ++If you are using the {@link android.widget.RelativeLayout} class, you may be able to achieve the same
    ++effect, at lower cost, by using nested, unweighted
    ++{@link android.widget.LinearLayout} views instead. Additionally, if your app
    ++targets Android N (API level 24), it is likely that
    ++you can use a special layout editor to create a <a
    ++href="http://tools.android.com/tech-docs/layout-editor">{@code ConstraintLayout}</a>
    ++object instead of {@link android.widget.RelativeLayout}. Doing so allows you
    ++to avoid many of the issues this section
    ++describes. The <a
    ++href="http://tools.android.com/tech-docs/layout-editor">{@code ConstraintLayout}</a>
    ++class offers similar layout control, but
    ++with much-improved performance. This class uses its own constraint-solving
    ++system to resolve relationships between views in a very different way from
    ++standard layouts.
    ++</p>
    ++
    ++<h3 id="double">Double Taxation</h3>
    ++
    ++<p>
    ++Typically, the framework executes the <a
    ++href="{@docRoot}guide/topics/ui/declaring-layout.html">layout</a>
    ++or measure stage in a single pass and quite quickly. However, with some more
    ++complicated layout cases, the framework may have to iterate multiple times on
    ++the layout or measure stage before ultimately positioning the elements. Having
    ++to perform more than one layout-and-measure iteration is referred to as
    ++<em>double taxation.</em>
    ++</p>
    ++
    ++<p>
    ++For example, when you use the {@link android.widget.RelativeLayout} container, which allows you to
    ++position {@link android.view.View} objects with respect to the positions of other {@link android.view.View} objects, the
    ++framework performs the following actions:
    ++</p>
    ++
    ++<ol style="1">
    ++   <li>Executes a layout-and-measure pass, during which the framework calculates
    ++each child object’s position and size, based on each child’s request.
    ++   <li>Uses this data, also taking object weights into account, to figure out the
    ++proper position of correlated views.
    ++   <li>Performs a second layout pass to finalize the objects’ positions.
    ++   <li>Goes on to the next stage of the rendering process.</li></ol>
    ++
    ++<p>
    ++The more levels your view hierarchy has, the greater the potential performance
    ++penalty.
    ++</p>
    ++
    ++<p>
    ++Containers other than {@link android.widget.RelativeLayout} may also give rise to double taxation. For
    ++example:
    ++</p>
    ++
    ++<ul>
    ++   <li>A {@link android.widget.LinearLayout} view
    ++could result in a double layout-and-measure pass if you make it horizontal.
    ++A double layout-and-measure pass may also occur in a vertical orientation if you
    ++add <a
    ++href="{@docRoot}reference/android/widget/LinearLayout.html#attr_android:measureWithLargestChild">measureWithLargestChild</a>,
    ++in which case the framework may need to do a second pass to resolve the proper
    ++sizes of objects.
    ++   <li>The {@link android.widget.GridLayout}
    ++has a similar issue. While this container also allows relative positioning, it
    ++normally avoids double taxation by pre-processing the positional relationships
    ++among child views. However, if the layout uses weights or fill with the
    ++{@link android.view.Gravity} class, the
    ++benefit of that preprocessing is lost, and the framework may have to perform
    ++multiple passes if it the container were a {@link android.widget.RelativeLayout}.</li>
    ++</ul>
    ++<p>
    ++Multiple layout-and-measure passes are not, in themselves, a performance burden.
    ++But they can become so if they’re in the wrong spot. You should be wary of
    ++situations where one of the following conditions applies to your container:
    ++</p>
    ++
    ++<ul>
    ++   <li>It is a root element in your view hierarchy.
    ++   <li>It has a deep view hierarchy beneath it.
    ++   <li>It is nested.
    ++   <li>There are many instances of it populating the screen, similar to children
    ++   in a {@link android.widget.ListView} object.</li>
    ++</ul>
    ++
    ++<h2 id="dx">Diagnosing View Hierarchy Issues</h2>
    ++
    ++<p>
    ++Layout performance is a complex problem with many facets. There are a couple of
    ++tools that can give you solid indications about where performance bottlenecks
    ++are occurring. A few other tools provide less definitive information, but can
    ++also provide helpful hints.
    ++</p>
    ++
    ++<p>
    ++<h3 id="systrace">Systrace</h3>
    ++</p>
    ++
    ++<p>
    ++One tool that provides excellent data about performance is <a
    ++href="{@docRoot}studio/profile/systrace.html">Systrace</a>,
    ++which is built into Android Studio. The Systrace tool allows you to collect and
    ++inspect timing information across an entire Android device, allowing you to see
    ++specifically where performance bottlenecks arise. For more information about
    ++Systrace, see <a href=”{docRoot}<a href="{@docRoot}studio/profile/systrace.html">
    ++Analyze UI Performance with Systrace</a>.
    ++</p>
    ++
    ++<h3 id="profile">Profile GPU rendering</h3>
    ++
    ++<p>
    ++The other tool most likely to provide you with concrete information about
    ++performance bottlenecks is the on-device <a
    ++href="{@docRoot}studio/profile/dev-options-rendering.html">
    ++Profile GPU rendering</a> tool, available on devices powered by Android 6.0 (API
    ++level 23) and later.  This tool allows you to see how long the layout-and-measurestage is
    ++ taking for <a href="https://youtu.be/erGJw8WDV74">each frame
    ++of rendering</a>. This data can help you diagnose runtime performance issues,
    ++and help you determine what, if any layout-and-measure issues you need to
    ++address.
    ++</p>
    ++
    ++<p>
    ++In its graphical representation of the data it captures, <a
    ++href="{@docRoot}studio/profile/dev-options-rendering.html">Profile
    ++GPU rendering</a> uses the color blue to represent layout time. For more
    ++information about how to use this tool, see <a
    ++href="{@docRoot}studio/profile/dev-options-rendering.html">Profile
    ++GPU Rendering Walkthrough.</a>
    ++</p>
    ++
    ++<h3 id="lint">Lint</h3>
    ++
    ++<p>
    ++Android Studio’s <a
    ++href="{@docRoot}studio/write/lint.html">Lint</a> tool can
    ++help you gain a sense of inefficiencies in the view hierarchy. To use this tool,
    ++select <strong>Analyze > Inspect Code</strong>, as shown in Figure 1.
    ++</p>
    ++
    ++  <img src="{@docRoot}topic/performance/images/lint-inspect-code.png">
    ++  <p class="img-caption">
    ++    <strong>Figure 1.</strong> Locating <strong>Inspect Code</strong> in the
    ++Android Studio.
    ++  </p>
    ++
    ++<p>
    ++Information about various layout items appears under
    ++<em>Android > Lint > Performance</em>. To see more detail,
    ++you can click on each item to expand it, and see more
    ++information in the pane on the right side of the screen.
    ++Figure 2 shows an example of such a display.
    ++</p>
    ++
    ++  <img src="{@docRoot}topic/performance/images/lint-display.png">
    ++  <p class="img-caption">
    ++    <strong>Figure 2.</strong> Viewing information about specific
    ++issues that the lint tool has identified.
    ++  </p>
    ++
    ++
    ++<p>
    ++Clicking on one of these items reveals, in the pane to the right, the problem
    ++associated with that item.
    ++</p>
    ++
    ++<p>
    ++To understand more about specific topics and issues in this area, see the <a
    ++href="{@docRoot}studio/write/lint.html">Lint
    ++</a>documentation.
    ++</p>
    ++
    ++<h3 id="hv">Hierarchy Viewer</h3>
    ++
    ++<p>
    ++Android Studio’s <a
    ++href="{@docRoot}studio/profile/hierarchy-viewer.html">Hierarchy
    ++Viewer</a> tool provides a visual representation of your app’s view hierarchy.
    ++It is a good way to navigate the hierarchy of your app, providing a clear visual
    ++representation of a particular view’s parent chain, and allowing you to inspect
    ++the layouts that your app constructs.
    ++</p>
    ++
    ++<p>
    ++The views that Hierarchy Viewer presents can also help identify performance
    ++problems arising from double taxation. It can also provide an easy way for you
    ++to identify deep chains of nested layouts, or layout areas with a large amount
    ++of nested children, another potential source of performance costs. In these
    ++scenarios, the layout-and-measure stages can be particularly costly,
    ++resulting in performance issues.
    ++</p>
    ++
    ++<p>
    ++You can also can get a sense of relative time taken by layout-and-measure
    ++operations by clicking the “profile node” button.
    ++</p>
    ++
    ++<p>
    ++For more information about Hierarchy Viewer, see <a
    ++href="{@docRoot}studio/profile/optimize-ui.html#HierarchyViewer">Optimizing
    ++Your UI</a>.
    ++</p>
    ++
    ++<h2 id="solving">Solving View Hierarchy Issues</h2>
    ++
    ++<p>
    ++The fundamental concept behind solving performance problems that arise from view
    ++hierarchies is simple in concept, but more difficult in practice. Preventing
    ++view hierarchies from imposing performance penalties encompasses the dual goals
    ++of flattening your view hierarchy and reducing double taxation. This section
    ++discusses some strategies for pursuing these goals.
    ++</p>
    ++
    ++<h3 id="removing">Removing redundant nested layouts</h3>
    ++
    ++<p>
    ++Developers often use more nested layouts than necessary. For example, a
    ++{@link android.widget.RelativeLayout} container might contain a single child that is also a
    ++{@link android.widget.RelativeLayout} container. This nesting amounts to redundancy, and adds
    ++unnecessary cost to the view hierarchy.
    ++</p>
    ++
    ++<p>
    ++Lint can often flag this problem for you, reducing debugging time.
    ++</p>
    ++
    ++<h3>Adopting Merge/Include </h3>
    ++<p>
    ++One frequent cause of redundant nested layouts is the <a
    ++href="{@docRoot}training/improving-layouts/reusing-layouts.html">
    ++&lt;include&gt;
    ++tag</a>. For example, you may define a re-usable layout as follows:
    ++</p>
    ++
    ++<pre class="prettyprint">
    ++&lt;LinearLayout&gt;
    ++    &lt;!-- some stuff here --&gt;
    ++&lt;/LinearLayout&gt;
    ++&lt;/pre&gt;
    ++</pre>
    ++
    ++<p>
    ++And then an include tag to add this item to the parent container:
    ++</p>
    ++
    ++<pre class="prettyprint">
    ++&lt;LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    ++    android:orientation="vertical"
    ++    android:layout_width="match_parent"
    ++    android:layout_height="match_parent"
    ++    android:background="@color/app_bg"
    ++    android:gravity="center_horizontal"&gt;
    ++
    ++    &lt;include layout="@layout/titlebar"/&gt;
    ++
    ++    &lt;TextView android:layout_width="match_parent"
    ++              android:layout_height="wrap_content"
    ++              android:text="@string/hello"
    ++              android:padding="10dp" /&gt;
    ++
    ++    ...
    ++
    ++&lt;/LinearLayout&gt;
    ++</pre>
    ++
    ++<p>
    ++The include unnecessarily nests the first layout within the second layout.
    ++</p>
    ++
    ++<p>
    ++The <a
    ++href="{@docRoot}training/improving-layouts/reusing-layouts.html#Merge">merge
    ++</a>tag can help prevent this issue. For information about this tag, see <a
    ++href="{@docRoot}training/improving-layouts/reusing-layouts.html#Merge">Re-using
    ++Layouts with &lt;include&gt;</a>.
    ++</p>
    ++
    ++<h3 id="cheaper">Adopting a cheaper layout</h3>
    ++
    ++<p>
    ++You may not be able to adjust your existing layout scheme so that it doesn’t
    ++contain redundant layouts. In certain cases, the only solution may be to flatten
    ++your hierarchy by switching over to an entirely different layout type.
    ++</p>
    ++
    ++<p>
    ++For example, you may find that a {@link android.widget.TableLayout}
    ++provides the same functionality as a more complex layout with many
    ++positional dependencies. In the N release of Android, the
    ++<a
    ++href="http://tools.android.com/tech-docs/layout-editor">{@code ConstraintLayout}</a> class provides similar functionality to
    ++{@link android.widget.RelativeLayout}, but at a significantly lower cost.
    ++</p>
    +diff --git a/docs/html/topic/performance/rendering/overdraw.jd b/docs/html/topic/performance/rendering/overdraw.jd
    +new file mode 100644
    +index 0000000..c1feff5
    +--- /dev/null
    ++++ b/docs/html/topic/performance/rendering/overdraw.jd
    +@@ -0,0 +1,197 @@
    ++page.title=Reducing Overdraw
    ++page.metaDescription=Improve performance by reducing unnecessary rendering.
    ++
    ++meta.tags="performance"
    ++page.tags="performance"
    ++
    ++@jd:body
    ++
    ++<div id="qv-wrapper">
    ++<div id="qv">
    ++
    ++<h2>In this document</h2>
    ++    <ol>
    ++
    ++      <li>
    ++        <a href="#understanding">Understanding Overdraw</a>
    ++      </li>
    ++      <li>
    ++        <a href="#finding">Finding Overdraw Problems</a>
    ++      </li>
    ++      <li>
    ++        <a href="#fixing">Fixing Overdraw</a>
    ++      </li>
    ++    </ol>
    ++  </div>
    ++</div>
    ++
    ++<p>
    ++An app may draw the same pixel more than once within a single frame, an event
    ++called <em>overdraw</em>. Overdraw is usually unnecessary, and best
    ++eliminated. It manifests itself as a performance problem by wasting GPU time to
    ++render pixels that don't contribute to what the user sees on the screen.
    ++</p>
    ++
    ++<p>
    ++This document explains overdraw: what it is, how to diagnose it, and actions you
    ++can take to eliminate or mitigate it.
    ++</p>
    ++
    ++<h2 name="understanding">Understanding Overdraw</h2>
    ++
    ++<p>
    ++Overdraw refers to the system's drawing a pixel on the screen multiple times
    ++in a single frame of rendering. For example, if we have a bunch of stacked UI
    ++cards, each card hides a portion of the one below it.
    ++</p>
    ++
    ++<p>
    ++However, the system still needs to draw even the hidden portions of the cards
    ++in the stack. This is because stacked cards are rendered according to the
    ++<a class="external-link"
    ++href="https://en.wikipedia.org/wiki/Painter%27s_algorithm">painter's
    ++algorithm</a>: that is, in back-to-front order.
    ++This sequence of rendering allows the system to apply proper alpha blending to
    ++translucent objects such as shadows.
    ++</p>
    ++
    ++<h2 name="finding">Finding Overdraw Problems</h2>
    ++
    ++<p>
    ++The platform offers several tools to help you determine if overdraw is
    ++affecting your app's performance. These tools are available right on the device,
    ++and accessible by turning on <strong>Developer Settings</strong></a> under
    ++<em>Settings</em>. For more information about device developer settings, see
    ++<a href="/studio/run/device.html#developer-device-options">Run Apps on a
    ++Hardware Device</a>.
    ++</p>
    ++
    ++<h3 id="dgot">Debug GPU overdraw tool</h3>
    ++
    ++<p>
    ++The Debug GPU Overdraw tool uses color-coding to show the number of times your
    ++app draws each pixel on the screen. The higher this count, the
    ++more likely it is that overdraw affects your app's performance.
    ++</p>
    ++
    ++<p>
    ++For more information on how to use the tool, refer to the related
    ++<a href="/studio/profile/dev-options-overdraw.html">walkthrough</a>
    ++and
    ++<a href="https://io2015codelabs.appspot.com/codelabs/android-performance-debug-gpu-overdraw#1">
    ++codelab</a>.
    ++</p>
    ++
    ++<h3 id="pgrt">Profile GPU rendering tool</h3>
    ++
    ++<p>
    ++The Profile GPU Rendering tool displays, as a scrolling histogram, the time
    ++each stage of the rendering pipeline takes to display a single frame. The
    ++<em>Process</em> part of each bar, indicated in orange, shows when the system
    ++is swapping buffers; this metric provides important clues about overdraw.
    ++</p>
    ++
    ++<p>
    ++On less performant GPUs, available fill-rate (the speed at which the GPU can
    ++fill the frame buffer) can be quite low. As the number of
    ++pixels required to draw a frame increases, the GPU may take longer to process
    ++new commands, and ask the rest of the system to wait until it can catch up.
    ++The <em>Process</em> bar shows that this spike happens as the GPU gets
    ++overwhelmed trying to draw pixels as fast as possible. Issues other than
    ++raw numbers of pixels may also cause this metric to spike. For example,
    ++if the Debug GPU Overdraw tool shows heavy overdraw and <em>Process</em> spikes,
    ++there's likely an issue with overdraw.
    ++</p>
    ++
    ++<p class="note"><strong>Note: </strong>The
    ++<a href="https://developer.android.com/studio/profile/dev-options-rendering.html">
    ++Profile GPU Rendering</a> tool does not
    ++work with apps that use the NDK. This is because the system pushes framework
    ++messages to the background whenever OpenGL takes a full-screen context. In
    ++such cases, you may find a profiling tool provided by the GPU manufacturer
    ++helpful.</p>
    ++
    ++<h2 name="fixing">Fixing Overdraw</h2>
    ++
    ++<p>
    ++There are several strategies you can pursue to reduce or eliminate overdraw:
    ++</p>
    ++
    ++<ul>
    ++   <li>Removing unneeded backgrounds in layouts.</li>
    ++   <li>Flattening the view hierarchy.</li>
    ++   <li>Reducing transparency.</li>
    ++</ul>
    ++
    ++<p>
    ++This section provides information about each of these approaches.
    ++</p>
    ++
    ++<h3 id="rubil">Removing unneeded backgrounds in layouts</h3>
    ++
    ++<p>
    ++By default, a layout does not have a background, which means it does not render
    ++anything directly by itself. When layouts do have backgrounds, however, they may
    ++contribute to overdraw.
    ++</p>
    ++
    ++<p>
    ++Removing unnecessary backgrounds is a quick way of improving rendering
    ++performance. An unnecessary background may never be visible because it's
    ++completely covered by everything else the app is drawing on top of that
    ++view. For example, the system may entirely cover up a parent's
    ++background when it draws child views on top of it.
    ++</p>
    ++
    ++<p>
    ++To find out why you're overdrawing, walk through the hierarchy in
    ++the <a href="/studio/profile/hierarchy-viewer.html">Hierarchy Viewer</a> tool.
    ++As you do so, look out for any backgrounds you can eliminate because
    ++they are not visible to the user. Cases where many containers share a
    ++common background color offer another opportunity to eliminate unneeded
    ++backgrounds: You can set the window background to the main background color
    ++of your app, and leave all of the containers above it with no background values
    ++defined.
    ++</p>
    ++
    ++<h3 id="fvh">Flattening view hierarchy</h3>
    ++
    ++<p>
    ++Modern layouts make it easy to stack and layer views to produce beautiful
    ++design. However, doing so can degrade performance by resulting in overdraw,
    ++especially in scenarios where each stacked view object is opaque, requiring the
    ++drawing of both seen and unseen pixels to the screen.
    ++</p>
    ++
    ++<p>
    ++If you encounter this sort of issue, you may be able to improve performance by
    ++optimizing your view hierarchy to reduce the number of overlapping UI objects.
    ++For more information about how to accomplish this, see
    ++<a href="/topic/performance/optimizing-view-hierarchies.html">Optimizing View
    ++Hierarchies</a>.
    ++</p>
    ++
    ++<h3 id="rt">Reducing transparency</h3>
    ++
    ++<p>
    ++Rendering of transparent pixels on screen, known as alpha rendering, is a key
    ++contributor to overdraw. Unlike standard overdraw,
    ++in which the system completely hides existing drawn pixels by drawing
    ++opaque pixels on top of them, transparent
    ++objects require existing pixels to be drawn first, so that the right blending
    ++equation can occur.  Visual effects like transparent animations, fade-outs, and
    ++drop shadows all involve some sort of transparency, and can therefore contribute
    ++significantly to overdraw. You can improve overdraw in these situations by
    ++reducing the number of transparent objects you render. For example, you can get
    ++gray text by drawing black text in a {@link android.widget.TextView} with a
    ++translucent alpha value set on it. But you can get the same effect with far
    ++better performance by simply drawing the text in gray.
    ++</p>
    ++
    ++<p>
    ++To learn more about performance costs that transparency imposes throughout the
    ++entire drawing pipeline, watch the video
    ++<a href="https://www.youtube.com/watch?v=wIy8g8yNhNk&index=46&list=PLWz5rJ2EKKc9CBxr3BVjPTPoDPLdPIFCE">
    ++Hidden Costs of Transparency</a>.
    ++</p>
    ++
    +diff --git a/docs/html/topic/performance/rendering/profile-gpu.jd b/docs/html/topic/performance/rendering/profile-gpu.jd
    +new file mode 100644
    +index 0000000..fc98777
    +--- /dev/null
    ++++ b/docs/html/topic/performance/rendering/profile-gpu.jd
    +@@ -0,0 +1,406 @@
    ++page.title=Analyzing with Profile GPU Rendering
    ++page.metaDescription=Use the Profile GPU tool to help you optimize your app's rendering performance.
    ++
    ++meta.tags="power"
    ++page.tags="power"
    ++
    ++@jd:body
    ++
    ++<div id="qv-wrapper">
    ++<div id="qv">
    ++
    ++<h2>In this document</h2>
    ++    <ol>
    ++      <li>
    ++        <a href="#visrep">Visual Representation</a></li>
    ++      </li>
    ++
    ++      <li>
    ++       <a href="#sam">Stages and Their Meanings</a>
    ++      
    ++      <ul>
    ++         <li>
    ++           <a href="#sv">Input Handling</a>
    ++         </li>
    ++         <li>
    ++           <a href="#asd">Animation</a>
    ++         </li>
    ++         <li>
    ++           <a href="#asd">Measurement/Layout</a>
    ++         </li>
    ++         <li>
    ++           <a href="#asd">Drawing</a>
    ++         </li>
    ++         </li>
    ++         <li>
    ++           <a href="#asd">Sync/Upload</a>
    ++         </li>
    ++         <li>
    ++           <a href="#asd">Issuing Commands</a>
    ++         </li>
    ++         <li>
    ++           <a href="#asd">Processing/Swapping Buffer</a>
    ++         </li>
    ++         <li>
    ++           <a href="#asd">Miscellaneous</a>
    ++         </li>
    ++      </ul>
    ++      </li>     
    ++     </ol>
    ++  </div>
    ++</div>
    ++
    ++<p>
    ++The <a href="/studio/profile/dev-options-rendering.html">
    ++Profile GPU Rendering</a> tool indicates the relative time that each stage of
    ++the rendering pipeline takes to render the previous frame. This knowledge
    ++can help you identify bottlenecks in the pipeline, so that you
    ++can know what to optimize to improve your app's rendering performance.
    ++</p>
    ++
    ++<p>
    ++This page briefly explains what happens during each pipeline stage, and
    ++discusses issues that can cause bottlenecks there. Before reading
    ++this page, you should be familiar with the information presented in the
    ++<a href="/studio/profile/dev-options-rendering.html">Profile GPU
    ++Rendering Walkthrough</a>. In addition, to understand how all of the
    ++stages fit together, it may be helpful to review
    ++<a href="https://www.youtube.com/watch?v=we6poP0kw6E&index=64&list=PLWz5rJ2EKKc9CBxr3BVjPTPoDPLdPIFCE">
    ++how the rendering pipeline works.</a>
    ++</p>
    ++
    ++<h2 id="#visrep">Visual Representation</h2>
    ++
    ++<p>
    ++The Profile GPU Rendering tool displays stages and their relative times in the
    ++form of a graph: a color-coded histogram. Figure 1 shows an example of
    ++such a display.
    ++</p>
    ++
    ++  <img src="{@docRoot}topic/performance/images/bars.png">
    ++  <p class="img-caption">
    ++<strong>Figure 1.</strong> Profile GPU Rendering Graph
    ++  </p>
    ++
    ++</p>
    ++
    ++<p>
    ++Each segment of each vertical bar displayed in the Profile GPU Rendering
    ++graph represents a stage of the pipeline and is highlighted using a specific
    ++color in
    ++the bar graph. Figure 2 shows a key to the meaning of each displayed color.
    ++</p>
    ++
    ++  <img src="{@docRoot}topic/performance/images/s-profiler-legend.png">
    ++  <p class="img-caption">
    ++<strong>Figure 2.</strong> Profile GPU Rendering Graph Legend
    ++  </p>
    ++
    ++<p>
    ++Once you understand what each color signfiies,
    ++you can target specific aspects of your
    ++app to try to optimize its rendering performance.
    ++</p>
    ++
    ++<h2 id="sam">Stages and Their Meanings</a></h2>
    ++
    ++<p>
    ++This section explains what happens during each stage corresponding
    ++to a color in Figure 2, as well as bottleneck causes to look out for.
    ++</p>
    ++
    ++
    ++<h3 id="ih">Input Handling</h3>
    ++
    ++<p>
    ++The input handling stage of the pipeline measures how long the app
    ++spent handling input events. This metric indicates how long the app
    ++spent executing code called as a result of input event callbacks.
    ++</p>
    ++
    ++<h4>When this segment is large</h4>
    ++
    ++<p>
    ++High values in this area are typically a result of too much work, or
    ++too-complex work, occurring inside the input-handler event callbacks.
    ++Since these callbacks always occur on the main thread, solutions to this
    ++problem focus on optimizing the work directly, or offloading the work to a
    ++different thread.
    ++</p>
    ++
    ++<p>
    ++It’s also worth noting that {@link android.support.v7.widget.RecyclerView}
    ++scrolling can appear in this phase.
    ++{@link android.support.v7.widget.RecyclerView} scrolls immediately when it
    ++consumes the touch event. As a result,
    ++it can inflate or populate new item views. For this reason, it’s important to
    ++make this operation as fast as possible. Profiling tools like Traceview or
    ++Systrace can help you investigate further.
    ++</p>
    ++
    ++<h3 id="at">Animation</h3>
    ++
    ++<p>
    ++The Animations phase shows you just how long it took to evaluate all the
    ++animators that were running in that frame. The most common animators are
    ++{@link android.animation.ObjectAnimator},
    ++{@link android.view.ViewPropertyAnimator}, and
    ++<a href="/training/transitions/overview.html">Transitions</a>.
    ++</p>
    ++
    ++<h4>When this segment is large</h4>
    ++
    ++<p>
    ++High values in this area are typically a result of work that’s executing due
    ++to some property change of the animation. For example, a fling animation,
    ++which scrolls your {@link android.widget.ListView} or
    ++{@link android.support.v7.widget.RecyclerView}, causes large amounts of view
    ++inflation and population.
    ++</p>
    ++
    ++<h3 id="ml">Measurement/Layout</h3>
    ++
    ++<p>
    ++In order for Android to draw your view items on the screen, it executes
    ++two specific operations across layouts and views in your view hierarchy.
    ++</p>
    ++
    ++<p>
    ++First, the system measures the view items. Every view and layout has
    ++specific data that describes the size of the object on the screen. Some views
    ++can have a specific size; others have a size that adapts to the size
    ++of the parent layout container
    ++</p>
    ++
    ++<p>
    ++Second, the system lays out the view items. Once the system calculates
    ++the sizes of children views, the system can proceed with layout, sizing
    ++and positioning the views on the screen.
    ++</p>
    ++
    ++<p>
    ++The system performs measurement and layout not only for the views to be drawn,
    ++but also for the parent hierarchies of those views, all the way up to the root
    ++view.
    ++</p>
    ++
    ++<h4>When this segment is large</h4>
    ++
    ++<p>
    ++If your app spends a lot of time per frame in this area, it is
    ++usually either because of the sheer volume of views that need to be
    ++laid out, or problems such as
    ++<a href="/topic/performance/optimizing-view-hierarchies.html#double">
    ++double taxation</a> at the wrong spot in your
    ++hierarchy. In either of these cases, addressing performance involves
    ++<a href="/topic/performance/optimizing-view-hierarchies.html">improving
    ++the performance of your view hierarchies</a>.
    ++</p>
    ++
    ++<p>
    ++Code that you’ve added to
    ++{@link android.view.View#onLayout(boolean, int, int, int, int)} or
    ++{@link android.view.View#onMeasure(int, int)}
    ++can also cause performance
    ++issues. <a href="/studio/profile/traceview.html">Traceview</a> and
    ++<a href="/studio/profile/systrace.html">Systrace</a> can help you examine
    ++the callstacks to identify problems your code may have.
    ++</p>
    ++
    ++<h3 id="draw">Drawing</h3>
    ++
    ++<p>
    ++The draw stage translates a view’s rendering operations, such as drawing
    ++a background or drawing text, into a sequence of native drawing commands.
    ++The system captures these commands into a display list.
    ++</p>
    ++
    ++<p>
    ++The Draw bar records how much time it takes to complete capturing the commands
    ++into the display list, for all the views that needed to be updated on the screen
    ++this frame. The measured time applies to any code that you have added to the UI
    ++objects in your app. Examples of such code may be the
    ++{@link android.view.View#onDraw(android.graphics.Canvas) onDraw()},
    ++{@link android.view.View#dispatchDraw(android.graphics.Canvas) dispatchDraw()},
    ++and the various <code>draw ()methods</code> belonging to the subclasses of the
    ++{@link android.graphics.drawable.Drawable} class.
    ++</p>
    ++
    ++<h4>When this segment is large</h4>
    ++
    ++<p>
    ++In simplified terms, you can understand this metric as showing how long it took
    ++to run all of the calls to
    ++{@link android.view.View#onDraw(android.graphics.Canvas) onDraw()}
    ++for each invalidated view. This
    ++measurement includes any time spent dispatching draw commands to children and
    ++drawables that may be present. For this reason, when you see this bar spike, the
    ++cause could be that a bunch of views suddenly became invalidated. Invalidation
    ++makes it necessary to regenerate views' display lists. Alternatively, a
    ++lengthy time may be the result of a few custom views that have some extremely
    ++complex logic in their
    ++{@link android.view.View#onDraw(android.graphics.Canvas) onDraw()} methods.
    ++</p>
    ++
    ++<h3 id="su">Sync/Upload</h3>
    ++
    ++<p>
    ++The Sync & Upload metric represents the time it takes to transfer
    ++bitmap objects from CPU memory to GPU memory during the current frame.
    ++</p>
    ++
    ++<p>
    ++As different processors, the CPU and the GPU have different RAM areas
    ++dedicated to processing. When you draw a bitmap on Android, the system
    ++transfers the bitmap to GPU memory before the GPU can render it to the
    ++screen. Then, the GPU caches the bitmap so that the system doesn’t need to
    ++transfer the data again unless the texture gets evicted from the GPU texture
    ++cache.
    ++</p>
    ++
    ++<p class="note"><strong>Note:</strong> On Lollipop devices, this stage is
    ++purple.
    ++</p>
    ++
    ++<h4>When this segment is large</h4>
    ++
    ++<p>
    ++All resources for a frame need to reside in GPU memory before they can be
    ++used to draw a frame. This means that a high value for this metric could mean
    ++either a large number of small resource loads or a small number of very large
    ++resources. A common case is when an app displays a single bitmap that’s
    ++close to the size of the screen. Another case is when an app displays a
    ++large number of thumbnails.
    ++</p>
    ++
    ++<p>
    ++To shrink this bar, you can employ techniques such as:
    ++</p>
    ++
    ++<ul>
    ++   <li>
    ++Ensuring your bitmap resolutions are not much larger than the size at which they
    ++will be displayed. For example, your app should avoid displaying a 1024x1024
    ++image as a 48x48 image.
    ++   </li>
    ++
    ++   <li>
    ++Taking advantage of {@link android.graphics.Bitmap#prepareToDraw()}
    ++to asynchronously pre-upload a bitmap before the next sync phase.
    ++   </li>
    ++</ul>
    ++
    ++<h3 id="ic">Issuing Commands</h3>
    ++
    ++<p>
    ++The <em>Issue Commands</em> segment represents the time it takes to issue all
    ++of the commands necessary for drawing display lists to the screen.
    ++</p>
    ++
    ++<p>
    ++For the system to draw display lists to the screen, it sends the
    ++necessary commands to the GPU. Typically, it performs this action through the
    ++<a href="/guide/topics/graphics/opengl.html">OpenGL ES</a> API.
    ++</p>
    ++
    ++<p>
    ++This process takes some time, as the system performs final transformation
    ++and clipping for each command before sending the command to the GPU. Additional
    ++overhead then arises on the GPU side, which computes the final commands. These
    ++commands include final transformations, and additional clipping.
    ++</p>
    ++
    ++<h4>When this segment is large</h4>
    ++
    ++<p>
    ++The time spent in this stage is a direct measure of the complexity and
    ++quantity of display lists that the system renders in a given
    ++frame. For example, having many draw operations, especially in cases where
    ++there's a small inherent cost to each draw primitive, could inflate this time.
    ++For example:
    ++</p>
    ++
    ++<pre>
    ++for (int i = 0; i < 1000; i++)
    ++canvas.drawPoint()
    ++</pre>
    ++
    ++<p>
    ++is a lot more expensive to issue than:
    ++</p>
    ++
    ++<pre>
    ++canvas.drawPoints(mThousandPointArray);
    ++</pre>
    ++
    ++<p>
    ++There isn’t always a 1:1 correlation between issuing commands and
    ++actually drawing display lists. Unlike <em>Issue Commands</em>,
    ++which captures the time it takes to send drawing commands to the GPU,
    ++the <em>Draw</em> metric represents the time that it took to capture the issued
    ++commands into the display list.
    ++</p>
    ++
    ++<p>
    ++This difference arises because the display lists are cached by
    ++the system wherever possible. As a result, there are situations where a
    ++scroll, transform, or animation requires the system to re-send a display
    ++list, but not have to actually rebuild it&mdash;recapture the drawing
    ++commands&mdash;from scratch. As a result, you can see a high “Issue
    ++commands” bar without seeing a high <em>Draw commands</em> bar.
    ++</p>
    ++
    ++<h3 id="psb">Processing/Swapping Buffers</h3>
    ++
    ++<p>
    ++Once Android finishes submitting all its display list to the GPU,
    ++the system issues one final command to tell the graphics driver that it's
    ++done with the current frame. At this point, the driver can finally present
    ++the updated image to the screen.
    ++</p>
    ++
    ++<h4>When this segment is large</h4>
    ++
    ++<p>
    ++It’s important to understand that the GPU executes work in parallel with the
    ++CPU. The Android system issues draw commands to the GPU, and then moves on to
    ++the next task. The GPU reads those draw commands from a queue and processes
    ++them.
    ++</p>
    ++
    ++<p>
    ++In situations where the CPU issues commands faster than the GPU
    ++consumes them, the communications queue between the processors can become
    ++full. When this occurs, the CPU blocks, and waits until there is space in the
    ++queue to place the next command. This full-queue state arises often during the
    ++<em>Swap Buffers</em> stage, because at that point, a whole frame’s worth of
    ++commands have been submitted.
    ++</p>
    ++
    ++</p>
    ++The key to mitigating this problem is to reduce the complexity of work occurring
    ++on the GPU, in similar fashion to what you would do for the “Issue Commands”
    ++phase.
    ++</p>
    ++
    ++
    ++<h3 id="mt">Miscellaneous</h3>
    ++
    ++<p>
    ++In addition to the time it takes the rendering system to perform its work,
    ++there’s an additional set of work that occurs on the main thread and has
    ++nothing to do with rendering. Time that this work consumes is reported as
    ++<em>misc time</em>. Misc time generally represents work that might be occurring
    ++on the UI thread between two consecutive frames of rendering.
    ++</p>
    ++
    ++<h4>When this segment is large</h4>
    ++
    ++<p>
    ++If this value is high, it is likely that your app has callbacks, intents, or
    ++other work that should be happening on another thread. Tools such as
    ++<a href="/studio/profile/traceview.html">Method
    ++Tracing</a> or <a href="/studio/profile/systrace.html">Systrace</a> can provide
    ++visibility into the tasks that are running on
    ++the main thread. This information can help you target performance improvements.
    ++</p>
    +diff --git a/docs/html/training/_book.yaml b/docs/html/training/_book.yaml
    +index 891574f..47862e2 100644
    +--- a/docs/html/training/_book.yaml
    ++++ b/docs/html/training/_book.yaml
    +@@ -438,16 +438,6 @@ toc:
    +       path: /training/efficient-downloads/redundant_redundant.html
    +     - title: Modifying Patterns Based on the Connectivity Type
    +       path: /training/efficient-downloads/connectivity_patterns.html
    +-  - title: Backing up App Data to the Cloud
    +-    path: /training/backup/index.html
    +-    path_attributes:
    +-    - name: description
    +-      value: How to sync and back up app and user data to remote web services in the cloud and how to restore the data back to multiple devices.
    +-    section:
    +-    - title: Configuring Auto Backup
    +-      path: /training/backup/autosyncapi.html
    +-    - title: Using the Backup API
    +-      path: /training/backup/backupapi.html
    +   - title: Resolving Cloud Save Conflicts
    +     path: /training/cloudsave/conflict-res.html
    +     path_attributes:
    +@@ -695,6 +685,8 @@ toc:
    +         value: 再生中カードを表示する
    +     - title: Adding a Guided Step
    +       path: /training/tv/playback/guided-step.html
    ++    - title: Introducing First-time Users to Your App
    ++      path: /training/tv/playback/onboarding.html
    +     - title: Enabling Background Playback
    +       path: /training/tv/playback/options.html
    +     - title: Adding Picture-in-picture
    +@@ -898,6 +890,11 @@ toc:
    +         value: 順応性のある UI フローの実装
    +       - name: zh-cn-lang
    +         value: 实施自适应用户界面流程
    ++  - title: Build a Responsive UI with ConstraintLayout
    ++    path: /training/constraint-layout/index.html
    ++    path_attributes:
    ++    - name: description
    ++      value: How to build a layout using ConstraintLayout and the Android Studio Layout Editor.
    +   - title: Adding the App Bar
    +     path: /training/appbar/index.html
    +     path_attributes:
    +@@ -1149,6 +1146,8 @@ toc:
    +         value: 维护兼容性
    +       - name: zh-tw-lang
    +         value: 維持相容性
    ++    - title: Selecting Colors with the Palette API
    ++      path: /training/material/palette-colors.html
    + 
    + - title: Best Practices for User Input
    +   path: /training/best-user-input.html
    +@@ -1233,15 +1232,9 @@ toc:
    +       path: /training/scheduling/wakelock.html
    +     - title: Scheduling Repeating Alarms
    +       path: /training/scheduling/alarms.html
    +-
    + - title: Best Practices for Performance
    +   path: /training/best-performance.html
    +   section:
    +-  - title: Managing Your App's Memory
    +-    path: /training/articles/memory.html
    +-    path_attributes:
    +-    - name: description
    +-      value: How to keep your app's memory footprint small in order to improve performance on a variety of mobile devices.
    +   - title: Performance Tips
    +     path: /training/articles/perf-tips.html
    +     path_attributes:
    +@@ -1273,23 +1266,6 @@ toc:
    +     - name: description
    +       value: How to minimize the amount of power your app requires by adapting to current power conditions and performing power-hungry tasks at proper intervals.
    +     section:
    +-    - title: Reducing Network Battery Drain
    +-      path: /training/performance/battery/network/index.html
    +-      section:
    +-      - title: Collecting Network Traffic Data
    +-        path: /training/performance/battery/network/gather-data.html
    +-      - title: Analyzing Network Traffic Data
    +-        path: /training/performance/battery/network/analyze-data.html
    +-      - title: Optimizing User-Initiated Network Use
    +-        path: /training/performance/battery/network/action-user-traffic.html
    +-      - title: Optimizing App-Initiated Network Use
    +-        path: /training/performance/battery/network/action-app-traffic.html
    +-      - title: Optimizing Server-Initiated Network Use
    +-        path: /training/performance/battery/network/action-server-traffic.html
    +-      - title: Optimizing General Network Use
    +-        path: /training/performance/battery/network/action-any-traffic.html
    +-    - title: Optimizing for Doze and App Standby
    +-      path: /training/monitoring-device-state/doze-standby.html
    +     - title: Monitoring the Battery Level and Charging State
    +       path: /training/monitoring-device-state/battery-monitoring.html
    +       path_attributes:
    +diff --git a/docs/html/training/accessibility/service.jd b/docs/html/training/accessibility/service.jd
    +index de00db7..c034145 100755
    +--- a/docs/html/training/accessibility/service.jd
    ++++ b/docs/html/training/accessibility/service.jd
    +@@ -17,7 +17,7 @@ previous.link=accessible-app.html
    +   <li><a href="#create">Create Your Accessibility Service</a></li>
    +   <li><a href="#configure">Configure Your Accessibility Service</a></li>
    +   <li><a href="#events">Respond to AccessibilityEvents</a></li>
    +-  <li><a href="#query">Query the View Heirarchy for More Context</a></li>
    ++  <li><a href="#query">Query the View Hierarchy for More Context</a></li>
    + </ol>
    + 
    + <h2>You should also read</h2>
    +@@ -174,7 +174,7 @@ android.accessibilityservice.AccessibilityService#onAccessibilityEvent} method.
    + In that method, use {@link
    + android.view.accessibility.AccessibilityEvent#getEventType} to determine the
    + type of event, and {@link
    +-android.view.accessibility.AccessibilityRecord#getContentDescription} to extract
    ++android.view.accessibility.AccessibilityEvent#getContentDescription} to extract
    + any label text associated with the view that fired the event.</pre>
    + 
    + <pre>
    +@@ -200,7 +200,7 @@ public void onAccessibilityEvent(AccessibilityEvent event) {
    + }
    + </pre>
    + 
    +-<h2 id="query">Query the View Heirarchy for More Context</h2>
    ++<h2 id="query">Query the View Hierarchy for More Context</h2>
    + <p>This step is optional, but highly useful. The Android platform provides the ability for an
    + {@link android.accessibilityservice.AccessibilityService} to query the view
    + hierarchy, collecting information about the UI component that generated an event, and
    +@@ -211,7 +211,7 @@ android:canRetrieveWindowContent="true"
    + </pre>
    + <p>Once that's done, get an {@link
    + android.view.accessibility.AccessibilityNodeInfo} object using {@link
    +-android.view.accessibility.AccessibilityRecord#getSource}.  This call only
    ++android.view.accessibility.AccessibilityEvent#getSource}.  This call only
    + returns an object if the window where the event originated is still the active
    + window.  If not, it will return null, so <em>behave accordingly</em>.  The
    + following example is a snippet of code that, when it receives an event, does
    +diff --git a/docs/html/training/articles/memory.jd b/docs/html/training/articles/memory.jd
    +deleted file mode 100644
    +index de7af58..0000000
    +--- a/docs/html/training/articles/memory.jd
    ++++ /dev/null
    +@@ -1,740 +0,0 @@
    +-page.title=Managing Your App's Memory
    +-page.tags=ram,low memory,OutOfMemoryError,onTrimMemory
    +-page.article=true
    +-@jd:body
    +-
    +-
    +-<div id="tb-wrapper">
    +-<div id="tb">
    +-
    +-<h2>In this document</h2>
    +-<ol class="nolist">
    +-  <li><a href="#Android">How Android Manages Memory</a>
    +-    <ol>
    +-      <li><a href="#SharingRAM">Sharing Memory</a></li>
    +-      <li><a href="#AllocatingRAM">Allocating and Reclaiming App Memory</a></li>
    +-      <li><a href="#RestrictingMemory">Restricting App Memory</a></li>
    +-      <li><a href="#SwitchingApps">Switching Apps</a></li>
    +-    </ol>
    +-  </li>
    +-  <li><a href="#YourApp">How Your App Should Manage Memory</a>
    +-    <ol>
    +-      <li><a href="#Services">Use services sparingly</a></li>
    +-      <li><a href="#ReleaseMemoryAsUiGone">Release memory when your user interface becomes hidden</a></li>
    +-      <li><a href="#ReleaseMemoryAsTight">Release memory as memory becomes tight</a></li>
    +-      <li><a href="#CheckHowMuchMemory">Check how much memory you should use</a></li>
    +-      <li><a href="#Bitmaps">Avoid wasting memory with bitmaps</a></li>
    +-      <li><a href="#DataContainers">Use optimized data containers</a></li>
    +-      <li><a href="#Overhead">Be aware of memory overhead</a></li>
    +-      <li><a href="#Abstractions">Be careful with code abstractions</a></li>
    +-      <li><a href="#NanoProto">Use nano protobufs for serialized data</a></li>
    +-      <li><a href="#DependencyInjection">Avoid dependency injection frameworks</a></li>
    +-      <li><a href="#ExternalLibs">Be careful about using external libraries</a></li>
    +-      <li><a href="#OverallPerf">Optimize overall performance</a></li>
    +-      <li><a href="#Proguard">Use ProGuard to strip out any unneeded code</a></li>
    +-      <li><a href="#Zipalign">Use zipalign on your final APK</a></li>
    +-      <li><a href="#AnalyzeRam">Analyze your RAM usage</a></li>
    +-      <li><a href="#MultipleProcesses">Use multiple processes</a></li>
    +-    </ol>
    +-  </li>
    +-</ol>
    +-<h2>See Also</h2>
    +-<ul>
    +-  <li><a href="{@docRoot}tools/debugging/debugging-memory.html">Investigating Your RAM Usage</a>
    +-  </li>
    +-</ul>
    +-
    +-</div>
    +-</div>
    +-
    +-
    +-<p>Random-access memory (RAM) is a valuable resource in any software development environment, but
    +-it's even more valuable on a mobile operating system where physical memory is often constrained.
    +-Although Android's Dalvik virtual machine performs routine garbage collection, this doesn't allow
    +-you to ignore when and where your app allocates and releases memory.</p>
    +-
    +-<p>In order for the garbage collector to reclaim memory from your app, you need to avoid
    +-introducing memory leaks (usually caused by holding onto object references in global members) and
    +-release any {@link java.lang.ref.Reference} objects at the appropriate time (as defined by
    +-lifecycle callbacks discussed further below). For most apps, the Dalvik garbage collector takes
    +-care of the rest: the system reclaims your memory allocations when the corresponding objects leave
    +-the scope of your app's active threads.</p>
    +-
    +-<p>This document explains how Android manages app processes and memory allocation, and how you can
    +-proactively reduce memory usage while developing for Android. For more information about general
    +-practices to clean up your resources when programming in Java, refer to other books or online
    +-documentation about managing resource references. If you’re looking for information about how to
    +-analyze your app’s memory once you’ve already built it, read <a
    +-href="{@docRoot}tools/debugging/debugging-memory.html">Investigating Your RAM Usage</a>.</p>
    +-
    +-
    +-
    +-
    +-<h2 id="Android">How Android Manages Memory</h2>
    +-
    +-<p>Android does not offer swap space for memory, but it does use <a href=
    +-"http://en.wikipedia.org/wiki/Paging" class="external-link">paging</a> and <a href=
    +-"http://en.wikipedia.org/wiki/Memory-mapped_files" class="external-link">memory-mapping</a>
    +-(mmapping) to manage memory. This means that any memory you modify&mdash;whether by allocating
    +-new objects or touching mmapped pages&mdash;remains resident in RAM and cannot be paged out.
    +-So the only way to completely release memory from your app is to release object references you may
    +-be holding, making the memory available to the garbage collector. That is with one exception:
    +-any files mmapped in without modification, such as code, can be paged out of RAM if the system
    +-wants to use that memory elsewhere.</p>
    +-
    +-
    +-<h3 id="SharingRAM">Sharing Memory</h3>
    +-
    +-<p>In order to fit everything it needs in RAM, Android tries to share RAM pages across processes. It
    +-can do so in the following ways:</p>
    +-<ul>
    +-<li>Each app process is forked from an existing process called Zygote.
    +-The Zygote process starts when the system boots and loads common framework code and resources
    +-(such as activity themes). To start a new app process, the system forks the Zygote process then
    +-loads and runs the app's code in the new process. This allows most of the RAM pages allocated for
    +-framework code and resources to be shared across all app processes.</li>
    +-
    +-<li>Most static data is mmapped into a process. This not only allows that same data to be shared
    +-between processes but also allows it to be paged out when needed. Example static data include:
    +-Dalvik code (by placing it in a pre-linked {@code .odex} file for direct mmapping), app resources
    +-(by designing the resource table to be a structure that can be mmapped and by aligning the zip
    +-entries of the APK), and traditional project elements like native code in {@code .so} files.</li>
    +-
    +-<li>In many places, Android shares the same dynamic RAM across processes using explicitly allocated
    +-shared memory regions (either with ashmem or gralloc). For example, window surfaces use shared
    +-memory between the app and screen compositor, and cursor buffers use shared memory between the
    +-content provider and client.</li>
    +-</ul>
    +-
    +-<p>Due to the extensive use of shared memory, determining how much memory your app is using requires
    +-care. Techniques to properly determine your app's memory use are discussed in <a
    +-href="{@docRoot}tools/debugging/debugging-memory.html">Investigating Your RAM Usage</a>.</p>
    +-
    +-
    +-<h3 id="AllocatingRAM">Allocating and Reclaiming App Memory</h3>
    +-
    +-<p>Here are some facts about how Android allocates then reclaims memory from your app:</p>
    +-
    +-<ul>
    +-<li>The Dalvik heap for each process is constrained to a single virtual memory range. This defines
    +-the logical heap size, which can grow as it needs to (but only up to a limit that the system defines
    +-for each app).</li>
    +-
    +-<li>The logical size of the heap is not the same as the amount of physical memory used by the heap.
    +-When inspecting your app's heap, Android computes a value called the Proportional Set Size (PSS),
    +-which accounts for both dirty and clean pages that are shared with other processes&mdash;but only in an
    +-amount that's proportional to how many apps share that RAM. This (PSS) total is what the system
    +-considers to be your physical memory footprint. For more information about PSS, see the <a
    +-href="{@docRoot}tools/debugging/debugging-memory.html#ViewingAllocations">Investigating Your
    +-RAM Usage</a> guide.</li>
    +-
    +-<li>The Dalvik heap does not compact the logical size of the heap, meaning that Android does not
    +-defragment the heap to close up space. Android can only shrink the logical heap size when there
    +-is unused space at the end of the heap. But this doesn't mean the physical memory used by the heap
    +-can't shrink. After garbage collection, Dalvik walks the heap and finds unused pages, then returns
    +-those pages to the kernel using madvise. So, paired allocations and deallocations of large
    +-chunks should result in reclaiming all (or nearly all) the physical memory used. However,
    +-reclaiming memory from small allocations can be much less efficient because the page used
    +-for a small allocation may still be shared with something else that has not yet been freed.</li>
    +-</ul>
    +-
    +-
    +-<h3 id="RestrictingMemory">Restricting App Memory</h3>
    +-
    +-<p>To maintain a functional multi-tasking environment, Android sets a hard limit on the heap size
    +-for each app. The exact heap size limit varies between devices based on how much RAM the device
    +-has available overall. If your app has reached the heap capacity and tries to allocate more
    +-memory, it will receive an {@link java.lang.OutOfMemoryError}.</p>
    +-
    +-<p>In some cases, you might want to query the system to determine exactly how much heap space you
    +-have available on the current device&mdash;for example, to determine how much data is safe to keep in a
    +-cache. You can query the system for this figure by calling {@link
    +-android.app.ActivityManager#getMemoryClass()}. This returns an integer indicating the number of
    +-megabytes available for your app's heap. This is discussed further below, under
    +-<a href="#CheckHowMuchMemory">Check how much memory you should use</a>.</p>
    +-
    +-
    +-<h3 id="SwitchingApps">Switching Apps</h3>
    +-
    +-<p>Instead of using swap space when the user switches between apps, Android keeps processes that
    +-are not hosting a foreground ("user visible") app component in a least-recently used (LRU) cache.
    +-For example, when the user first launches an app, a process is created for it, but when the user
    +-leaves the app, that process does <em>not</em> quit. The system keeps the process cached, so if
    +-the user later returns to the app, the process is reused for faster app switching.</p>
    +-
    +-<p>If your app has a cached process and it retains memory that it currently does not need,
    +-then your app&mdash;even while the user is not using it&mdash;is constraining the system's
    +-overall performance. So, as the system runs low on memory, it may kill processes in the LRU cache
    +-beginning with the process least recently used, but also giving some consideration toward
    +-which processes are most memory intensive. To keep your process cached as long as possible, follow
    +-the advice in the following sections about when to release your references.</p>
    +-
    +-<p>More information about how processes are cached while not running in the foreground and how
    +-Android decides which ones
    +-can be killed is available in the <a href="{@docRoot}guide/components/processes-and-threads.html"
    +->Processes and Threads</a> guide.</p>
    +-
    +-
    +-
    +-
    +-<h2 id="YourApp">How Your App Should Manage Memory</h2>
    +-
    +-<p>You should consider RAM constraints throughout all phases of development, including during app
    +-design (before you begin development). There are many
    +-ways you can design and write code that lead to more efficient results, through aggregation of the
    +-same techniques applied over and over.</p>
    +-
    +-<p>You should apply the following techniques while designing and implementing your app to make it
    +-more memory efficient.</p>
    +-
    +-
    +-<h3 id="Services">Use services sparingly</h3>
    +-
    +-<p>If your app needs a <a href="{@docRoot}guide/components/services.html">service</a>
    +-to perform work in the background, do not keep it running unless
    +-it's actively performing a job. Also be careful to never leak your service by failing to stop it
    +-when its work is done.</p>
    +-
    +-<p>When you start a service, the system prefers to always keep the process for that service
    +-running. This makes the process very expensive because the RAM used by the service can’t be used by
    +-anything else or paged out. This reduces the number of cached processes that the system can keep in
    +-the LRU cache, making app switching less efficient. It can even lead to thrashing in the system
    +-when memory is tight and the system can’t maintain enough processes to host all the services
    +-currently running.</p>
    +-
    +-<p>The best way to limit the lifespan of your service is to use an {@link
    +-android.app.IntentService}, which finishes
    +-itself as soon as it's done handling the intent that started it. For more information, read
    +-<a href="{@docRoot}training/run-background-service/index.html">Running in a Background Service</a>
    +-.</p>
    +-
    +-<p>Leaving a service running when it’s not needed is <strong>one of the worst memory-management
    +-mistakes</strong> an Android app can make. So don’t be greedy by keeping a service for your app
    +-running. Not only will it increase the risk of your app performing poorly due to RAM constraints,
    +-but users will discover such misbehaving apps and uninstall them.</p>
    +-
    +-
    +-<h3 id="ReleaseMemoryAsUiGone">Release memory when your user interface becomes hidden</h3>
    +-
    +-<p>When the user navigates to a different app and your UI is no longer visible, you should
    +-release any resources that are used by only your UI. Releasing UI resources at this time can
    +-significantly increase the system's capacity for cached processes, which has a direct impact on the
    +-quality of the user experience.</p>
    +-
    +-<p>To be notified when the user exits your UI, implement the {@link
    +-android.content.ComponentCallbacks2#onTrimMemory onTrimMemory()} callback in your {@link
    +-android.app.Activity} classes. You should use this
    +-method to listen for the {@link android.content.ComponentCallbacks2#TRIM_MEMORY_UI_HIDDEN} level,
    +-which indicates your UI is now hidden from view and you should free resources that only your UI
    +-uses.</p>
    +-
    +-
    +-<p>Notice that your app receives the {@link android.content.ComponentCallbacks2#onTrimMemory
    +-onTrimMemory()} callback with {@link android.content.ComponentCallbacks2#TRIM_MEMORY_UI_HIDDEN}
    +-only when <em>all the UI components</em> of your app process become hidden from the user.
    +-This is distinct
    +-from the {@link android.app.Activity#onStop onStop()} callback, which is called when an {@link
    +-android.app.Activity} instance becomes hidden, which occurs even when the user moves to
    +-another activity in your app. So although you should implement {@link android.app.Activity#onStop
    +-onStop()} to release activity resources such as a network connection or to unregister broadcast
    +-receivers, you usually should not release your UI resources until you receive {@link
    +-android.content.ComponentCallbacks2#onTrimMemory onTrimMemory(TRIM_MEMORY_UI_HIDDEN)}. This ensures
    +-that if the user navigates <em>back</em> from another activity in your app, your UI resources are
    +-still available to resume the activity quickly.</p>
    +-
    +-
    +-
    +-<h3 id="ReleaseMemoryAsTight">Release memory as memory becomes tight</h3>
    +-
    +-<p>During any stage of your app's lifecycle, the {@link
    +-android.content.ComponentCallbacks2#onTrimMemory onTrimMemory()} callback also tells you when
    +-the overall device memory is getting low. You should respond by further releasing resources based
    +-on the following memory levels delivered by {@link android.content.ComponentCallbacks2#onTrimMemory
    +-onTrimMemory()}:</p>
    +-
    +-<ul>
    +-<li>{@link android.content.ComponentCallbacks2#TRIM_MEMORY_RUNNING_MODERATE}
    +-<p>Your app is running and not considered killable, but the device is running low on memory and the
    +-system is actively killing processes in the LRU cache.</p>
    +-</li>
    +-
    +-<li>{@link android.content.ComponentCallbacks2#TRIM_MEMORY_RUNNING_LOW}
    +-<p>Your app is running and not considered killable, but the device is running much lower on
    +-memory so you should release unused resources to improve system performance (which directly
    +-impacts your app's performance).</p>
    +-</li>
    +-
    +-<li>{@link android.content.ComponentCallbacks2#TRIM_MEMORY_RUNNING_CRITICAL}
    +-<p>Your app is still running, but the system has already killed most of the processes in the
    +-LRU cache, so you should release all non-critical resources now. If the system cannot reclaim
    +-sufficient amounts of RAM, it will clear all of the LRU cache and begin killing processes that
    +-the system prefers to keep alive, such as those hosting a running service.</p>
    +-</li>
    +-</ul>
    +-
    +-<p>Also, when your app process is currently cached, you may receive one of the following
    +-levels from {@link android.content.ComponentCallbacks2#onTrimMemory onTrimMemory()}:</p>
    +-<ul>
    +-<li>{@link android.content.ComponentCallbacks2#TRIM_MEMORY_BACKGROUND}
    +-<p>The system is running low on memory and your process is near the beginning of the LRU list.
    +-Although your app process is not at a high risk of being killed, the system may already be killing
    +-processes in the LRU cache. You should release resources that are easy to recover so your process
    +-will remain in the list and resume quickly when the user returns to your app.</p>
    +-</li>
    +-
    +-<li>{@link android.content.ComponentCallbacks2#TRIM_MEMORY_MODERATE}
    +-<p>The system is running low on memory and your process is near the middle of the LRU list. If the
    +-system becomes further constrained for memory, there's a chance your process will be killed.</p>
    +-</li>
    +-
    +-<li>{@link android.content.ComponentCallbacks2#TRIM_MEMORY_COMPLETE}
    +-<p>The system is running low on memory and your process is one of the first to be killed if the
    +-system does not recover memory now. You should release everything that's not critical to
    +-resuming your app state.</p>
    +-
    +-</li>
    +-</ul>
    +-
    +-<p>Because the {@link android.content.ComponentCallbacks2#onTrimMemory onTrimMemory()} callback was
    +-added in API level 14, you can use the {@link android.content.ComponentCallbacks#onLowMemory()}
    +-callback as a fallback for older versions, which is roughly equivalent to the {@link
    +-android.content.ComponentCallbacks2#TRIM_MEMORY_COMPLETE} event.</p>
    +-
    +-<p class="note"><strong>Note:</strong> When the system begins killing processes in the LRU cache,
    +-although it primarily works bottom-up, it does give some consideration to which processes are
    +-consuming more memory and will thus provide the system more memory gain if killed.
    +-So the less memory you consume while in the LRU list overall, the better your chances are
    +-to remain in the list and be able to quickly resume.</p>
    +-
    +-
    +-
    +-<h3 id="CheckHowMuchMemory">Check how much memory you should use</h3>
    +-
    +-<p>As mentioned earlier, each Android-powered device has a different amount of RAM available to the
    +-system and thus provides a different heap limit for each app. You can call {@link
    +-android.app.ActivityManager#getMemoryClass()} to get an estimate of your app's available heap in
    +-megabytes. If your app tries to allocate more memory than is available here, it will receive an
    +-{@link java.lang.OutOfMemoryError}.</p>
    +-
    +-<p>In very special situations, you can request a larger heap size by setting the <a
    +-href="{@docRoot}guide/topics/manifest/application-element.html#largeHeap">{@code largeHeap}</a>
    +-attribute to "true" in the manifest <a
    +-href="{@docRoot}guide/topics/manifest/application-element.html">{@code <application>}</a>
    +-tag. If you do so, you can call {@link
    +-android.app.ActivityManager#getLargeMemoryClass()} to get an estimate of the large heap size.</p>
    +-
    +-<p>However, the ability to request a large heap is intended only for a small set of apps that can
    +-justify the need to consume more RAM (such as a large photo editing app). <strong>Never request a
    +-large heap simply because you've run out of memory</strong> and you need a quick fix&mdash;you
    +-should use it only when you know exactly where all your memory is being allocated and why it must
    +-be retained. Yet, even when you're confident your app can justify the large heap, you should avoid
    +-requesting it to whatever extent possible. Using the extra memory will increasingly be to the
    +-detriment of the overall user experience because garbage collection will take longer and system
    +-performance may be slower when task switching or performing other common operations.</p>
    +-
    +-<p>Additionally, the large heap size is not the same on all devices and, when running on
    +-devices that have limited RAM, the large heap size may be exactly the same as the regular heap
    +-size. So even if you do request the large heap size, you should call {@link
    +-android.app.ActivityManager#getMemoryClass()} to check the regular heap size and strive to always
    +-stay below that limit.</p>
    +-
    +-
    +-<h3 id="Bitmaps">Avoid wasting memory with bitmaps</h3>
    +-
    +-<p>When you load a bitmap, keep it in RAM only at the resolution you need for the current device's
    +-screen, scaling it down if the original bitmap is a higher resolution. Keep in mind that an
    +-increase in bitmap resolution results in a corresponding (increase<sup>2</sup>) in memory needed,
    +-because both the X and Y dimensions increase.</p>
    +-
    +-<p class="note"><strong>Note:</strong> On Android 2.3.x (API level 10) and below, bitmap objects
    +-always appear as the same size in your app heap regardless of the image resolution (the actual
    +-pixel data is stored separately in native memory). This makes it more difficult to debug the bitmap
    +-memory allocation because most heap analysis tools do not see the native allocation. However,
    +-beginning in Android 3.0 (API level 11), the bitmap pixel data is allocated in your app's Dalvik
    +-heap, improving garbage collection and debuggability. So if your app uses bitmaps and you're having
    +-trouble discovering why your app is using some memory on an older device, switch to a device
    +-running Android 3.0 or higher to debug it.</p>
    +-
    +-<p>For more tips about working with bitmaps, read <a
    +-href="{@docRoot}training/displaying-bitmaps/manage-memory.html">Managing Bitmap Memory</a>.</p>
    +-
    +-
    +-<h3 id="DataContainers">Use optimized data containers</h3>
    +-
    +-<p>Take advantage of optimized containers in the Android framework, such as {@link
    +-android.util.SparseArray}, {@link android.util.SparseBooleanArray}, and {@link
    +-android.support.v4.util.LongSparseArray}. The generic {@link java.util.HashMap}
    +-implementation can be quite memory
    +-inefficient because it needs a separate entry object for every mapping. Additionally, the {@link
    +-android.util.SparseArray} classes are more efficient because they avoid the system's need
    +-to <acronym title=
    +-"Automatic conversion from primitive types to object classes (such as int to Integer)"
    +->autobox</acronym>
    +-the key and sometimes value (which creates yet another object or two per entry). And don't be
    +-afraid of dropping down to raw arrays when that makes sense.</p>
    +-
    +-
    +-
    +-<h3 id="Overhead">Be aware of memory overhead</h3>
    +-
    +-<p>Be knowledgeable about the cost and overhead of the language and libraries you are using, and
    +-keep this information in mind when you design your app, from start to finish. Often, things on the
    +-surface that look innocuous may in fact have a large amount of overhead. Examples include:</p>
    +-<ul>
    +-<li>Enums often require more than twice as much memory as static constants. You should strictly
    +-avoid using enums on Android.</li>
    +-
    +-<li>Every class in Java (including anonymous inner classes) uses about 500 bytes of code.</li>
    +-
    +-<li>Every class instance has 12-16 bytes of RAM overhead.</li>
    +-
    +-<li>Putting a single entry into a {@link java.util.HashMap} requires the allocation of an
    +-additional entry object that takes 32 bytes (see the previous section about <a
    +-href="#DataContainers">optimized data containers</a>).</li>
    +-</ul>
    +-
    +-<p>A few bytes here and there quickly add up—app designs that are class- or object-heavy will suffer
    +-from this overhead. That can leave you in the difficult position of looking at a heap analysis and
    +-realizing your problem is a lot of small objects using up your RAM.</p>
    +-
    +-
    +-<h3 id="Abstractions">Be careful with code abstractions</h3>
    +-
    +-<p>Often, developers use abstractions simply as a "good programming practice," because abstractions
    +-can improve code flexibility and maintenance. However, abstractions come at a significant cost:
    +-generally they require a fair amount more code that needs to be executed, requiring more time and
    +-more RAM for that code to be mapped into memory. So if your abstractions aren't supplying a
    +-significant benefit, you should avoid them.</p>
    +-
    +-
    +-<h3 id="NanoProto">Use nano protobufs for serialized data</h3>
    +-
    +-<p><a href="https://developers.google.com/protocol-buffers/docs/overview">Protocol
    +-buffers</a> are a language-neutral, platform-neutral, extensible mechanism designed by Google for
    +-serializing structured data&mdash;think XML, but smaller, faster, and simpler. If you decide to use
    +-protobufs for your data, you should always use nano protobufs in your client-side code. Regular
    +-protobufs generate extremely verbose code, which will cause many kinds of problems in your app:
    +-increased RAM use, significant APK size increase, slower execution, and quickly hitting the DEX
    +-symbol limit.</p>
    +-
    +-<p>For more information, see the "Nano version" section in the <a
    +-href="https://android.googlesource.com/platform/external/protobuf/+/master/java/README.txt"
    +-class="external-link">protobuf readme</a>.</p>
    +-
    +-
    +-
    +-<h3 id="DependencyInjection">Avoid dependency injection frameworks</h3>
    +-
    +-<p>Using a dependency injection framework such as <a
    +-href="https://code.google.com/p/google-guice/" class="external-link">Guice</a> or
    +-<a href="https://github.com/roboguice/roboguice" class="external-link">RoboGuice</a> may be
    +-attractive because they can simplify the code you write and provide an adaptive environment
    +-that's useful for testing and other configuration changes. However, these frameworks tend to perform
    +-a lot of process initialization by scanning your code for annotations, which can require significant
    +-amounts of your code to be mapped into RAM even though you don't need it. These mapped pages are
    +-allocated into clean memory so Android can drop them, but that won't happen until the pages have
    +-been left in memory for a long period of time.</p>
    +-
    +-
    +-<h3 id="ExternalLibs">Be careful about using external libraries</h3>
    +-
    +-<p>External library code is often not written for mobile environments and can be inefficient when used
    +-for work on a mobile client. At the very least, when you decide to use an external library, you
    +-should assume you are taking on a significant porting and maintenance burden to optimize the
    +-library for mobile. Plan for that work up-front and analyze the library in terms of code size and
    +-RAM footprint before deciding to use it at all.</p>
    +-
    +-<p>Even libraries supposedly designed for use on Android are potentially dangerous because each
    +-library may do things differently. For example, one library may use nano protobufs while another
    +-uses micro protobufs. Now you have two different protobuf implementations in your app. This can and
    +-will also happen with different implementations of logging, analytics, image loading frameworks,
    +-caching, and all kinds of other things you don't expect. <a
    +-href="{@docRoot}tools/help/proguard.html">ProGuard</a> won't save you here because these
    +-will all be lower-level dependencies that are required by the features for which you want the
    +-library. This becomes especially problematic when you use an {@link android.app.Activity}
    +-subclass from a library (which
    +-will tend to have wide swaths of dependencies), when libraries use reflection (which is common and
    +-means you need to spend a lot of time manually tweaking ProGuard to get it to work), and so on.</p>
    +-
    +-<p>Also be careful not to fall into the trap of using a shared library for one or two features out of
    +-dozens of other things it does; you don't want to pull in a large amount of code and overhead that
    +-you don't even use. At the end of the day, if there isn't an existing implementation that is a
    +-strong match for what you need to do, it may be best if you create your own implementation.</p>
    +-
    +-
    +-<h3 id="OverallPerf">Optimize overall performance</h3>
    +-
    +-<p>A variety of information about optimizing your app's overall performance is available
    +-in other documents listed in <a href="{@docRoot}training/best-performance.html">Best Practices
    +-for Performance</a>. Many of these documents include optimizations tips for CPU performance, but
    +-many of these tips also help optimize your app's memory use, such as by reducing the number of
    +-layout objects required by your UI.</p>
    +-
    +-<p>You should also read about <a href="{@docRoot}tools/debugging/debugging-ui.html">optimizing
    +-your UI</a> with the layout debugging tools and take advantage of
    +-the optimization suggestions provided by the <a
    +-href="{@docRoot}tools/debugging/improving-w-lint.html">lint tool</a>.</p>
    +-
    +-
    +-<h3 id="Proguard">Use ProGuard to strip out any unneeded code</h3>
    +-
    +-<p>The <a href="{@docRoot}tools/help/proguard.html">ProGuard</a> tool shrinks,
    +-optimizes, and obfuscates your code by removing unused code and renaming classes, fields, and
    +-methods with semantically obscure names. Using ProGuard can make your code more compact, requiring
    +-fewer RAM pages to be mapped.</p>
    +-
    +-
    +-<h3 id="Zipalign">Use zipalign on your final APK</h3>
    +-
    +-<p>If you do any post-processing of an APK generated by a build system (including signing it
    +-with your final production certificate), then you must run <a
    +-href="{@docRoot}tools/help/zipalign.html">zipalign</a> on it to have it re-aligned.
    +-Failing to do so can cause your app to require significantly more RAM, because things like
    +-resources can no longer be mmapped from the APK.</p>
    +-
    +-<p class="note"><strong>Note:</strong> Google Play Store does not accept APK files that
    +-are not zipaligned.</p>
    +-
    +-
    +-<h3 id="AnalyzeRam">Analyze your RAM usage</h3>
    +-
    +-<p>Once you achieve a relatively stable build, begin analyzing how much RAM your app is using
    +-throughout all stages of its lifecycle. For information about how to analyze your app, read <a
    +-href="{@docRoot}tools/debugging/debugging-memory.html">Investigating Your RAM Usage</a>.</p>
    +-
    +-
    +-
    +-
    +-<h3 id="MultipleProcesses">Use multiple processes</h3>
    +-
    +-<p>If it's appropriate for your app, an advanced technique that may help you manage your app's
    +-memory is dividing components of your app into multiple processes. This technique must always be
    +-used carefully and <strong>most apps should not run multiple processes</strong>, as it can easily
    +-increase&mdash;rather than decrease&mdash;your RAM footprint if done incorrectly. It is primarily
    +-useful to apps that may run significant work in the background as well as the foreground and can
    +-manage those operations separately.</p>
    +-
    +-
    +-<p>An example of when multiple processes may be appropriate is when building a music player that
    +-plays music from a service for long period of time. If
    +-the entire app runs in one process, then many of the allocations performed for its activity UI must
    +-be kept around as long as it is playing music, even if the user is currently in another app and the
    +-service is controlling the playback. An app like this may be split into two process: one for its
    +-UI, and the other for the work that continues running in the background service.</p>
    +-
    +-<p>You can specify a separate process for each app component by declaring the <a href=
    +-"{@docRoot}guide/topics/manifest/service-element.html#proc">{@code android:process}</a> attribute
    +-for each component in the manifest file. For example, you can specify that your service should run
    +-in a process separate from your app's main process by declaring a new process named "background"
    +-(but you can name the process anything you like):</p>
    +-
    +-<pre>
    +-&lt;service android:name=".PlaybackService"
    +-         android:process=":background" />
    +-</pre>
    +-
    +-<p>Your process name should begin with a colon (':') to ensure that the process remains private to
    +-your app.</p>
    +-
    +-<p>Before you decide to create a new process, you need to understand the memory implications.
    +-To illustrate the consequences of each process, consider that an empty process doing basically
    +-nothing has an extra memory footprint of about 1.4MB, as shown by the memory information
    +-dump below.</p>
    +-
    +-<pre class="no-pretty-print">
    +-adb shell dumpsys meminfo com.example.android.apis:empty
    +-
    +-** MEMINFO in pid 10172 [com.example.android.apis:empty] **
    +-                Pss     Pss  Shared Private  Shared Private    Heap    Heap    Heap
    +-              Total   Clean   Dirty   Dirty   Clean   Clean    Size   Alloc    Free
    +-             ------  ------  ------  ------  ------  ------  ------  ------  ------
    +-  Native Heap     0       0       0       0       0       0    1864    1800      63
    +-  Dalvik Heap   764       0    5228     316       0       0    5584    5499      85
    +- Dalvik Other   619       0    3784     448       0       0
    +-        Stack    28       0       8      28       0       0
    +-    Other dev     4       0      12       0       0       4
    +-     .so mmap   287       0    2840     212     972       0
    +-    .apk mmap    54       0       0       0     136       0
    +-    .dex mmap   250     148       0       0    3704     148
    +-   Other mmap     8       0       8       8      20       0
    +-      Unknown   403       0     600     380       0       0
    +-        TOTAL  2417     148   12480    1392    4832     152    7448    7299     148
    +-</pre>
    +-
    +-<p class="note"><strong>Note:</strong> More information about how to read this output is provided
    +-in <a href="{@docRoot}tools/debugging/debugging-memory.html#ViewingAllocations">Investigating
    +-Your RAM Usage</a>. The key data here is the <em>Private Dirty</em> and <em>Private
    +-Clean</em> memory, which shows that this process is using almost 1.4MB of non-pageable RAM
    +-(distributed across the Dalvik heap, native allocations, book-keeping, and library-loading),
    +-and another 150K of RAM for code that has been mapped in to execute.</p>
    +-
    +-<p>This memory footprint for an empty process is fairly significant and it can quickly
    +-grow as you start doing work in that process. For
    +-example, here is the memory use of a process that is created only to show an activity with some
    +-text in it:</p>
    +-
    +-<pre class="no-pretty-print">
    +-** MEMINFO in pid 10226 [com.example.android.helloactivity] **
    +-                Pss     Pss  Shared Private  Shared Private    Heap    Heap    Heap
    +-              Total   Clean   Dirty   Dirty   Clean   Clean    Size   Alloc    Free
    +-             ------  ------  ------  ------  ------  ------  ------  ------  ------
    +-  Native Heap     0       0       0       0       0       0    3000    2951      48
    +-  Dalvik Heap  1074       0    4928     776       0       0    5744    5658      86
    +- Dalvik Other   802       0    3612     664       0       0
    +-        Stack    28       0       8      28       0       0
    +-       Ashmem     6       0      16       0       0       0
    +-    Other dev   108       0      24     104       0       4
    +-     .so mmap  2166       0    2824    1828    3756       0
    +-    .apk mmap    48       0       0       0     632       0
    +-    .ttf mmap     3       0       0       0      24       0
    +-    .dex mmap   292       4       0       0    5672       4
    +-   Other mmap    10       0       8       8      68       0
    +-      Unknown   632       0     412     624       0       0
    +-        TOTAL  5169       4   11832    4032   10152       8    8744    8609     134
    +-</pre>
    +-
    +-<p>The process has now almost tripled in size, to 4MB, simply by showing some text in the UI. This
    +-leads to an important conclusion: If you are going to split your app into multiple processes, only
    +-one process should be responsible for UI. Other processes should avoid any UI, as this will quickly
    +-increase the RAM required by the process (especially once you start loading bitmap assets and other
    +-resources). It may then be hard or impossible to reduce the memory usage once the UI is drawn.</p>
    +-
    +-<p>Additionally, when running more than one process, it's more important than ever that you keep your
    +-code as lean as possible, because any unnecessary RAM overhead for common implementations are now
    +-replicated in each process. For example, if you are using enums (though <a
    +-href="#Overhead">you should not use enums</a>), all of
    +-the RAM needed to create and initialize those constants is duplicated in each process, and any
    +-abstractions you have with adapters and temporaries or other overhead will likewise be replicated.</p>
    +-
    +-<p>Another concern with multiple processes is the dependencies that exist between them. For example,
    +-if your app has a content provider that you have running in the default process which also hosts
    +-your UI, then code in a background process that uses that content provider will also require that
    +-your UI process remain in RAM. If your goal is to have a background process that can run
    +-independently of a heavy-weight UI process, it can't have dependencies on content providers or
    +-services that execute in the UI process.</p>
    +-
    +-
    +-
    +-
    +-
    +-
    +-
    +-
    +-
    +-
    +-<!-- THE FOLLOWING IS OVERWHELMING AND NOT NECESSARY FOR MOST APPS, LEAVING OUT FOR NOW
    +-
    +-
    +-<p>You can examine the dependencies between your processes with the command:</p>
    +-
    +-<pre class="no-pretty-print">
    +-adb shell dumpsys activity
    +-</pre>
    +-
    +-<p>This dumps various information about the Activity Manager's state, ending with a list of all
    +-processes in their memory management order, including the reason each process is at its given
    +-level. For example, below is a dump with the Music app in the foreground.</p>
    +-
    +-<pre class="no-pretty-print">
    +-ACTIVITY MANAGER RUNNING PROCESSES (dumpsys activity processes)
    +-  Process LRU list (sorted by oom_adj):
    +-    PERS # 4: adj=sys  /F  trm= 0 20674:system/1000 (fixed)
    +-    PERS #39: adj=pers /F  trm= 0 20964:com.android.nfc/1027 (fixed)
    +-    PERS # 2: adj=pers /F  trm= 0 20959:com.android.phone/1001 (fixed)
    +-    PERS # 1: adj=pers /F  trm= 0 20779:com.android.systemui/u0a10057 (fixed)
    +-    Proc #11: adj=fore /FA trm= 0 8663:com.google.android.music:ui/u0a10043 (top-activity)
    +-    Proc #10: adj=fore /F  trm= 0 30881:com.google.android.music:main/u0a10043 (provider)
    +-        com.google.android.music/.store.MusicContentProvider<=Proc{8663:com.google.android.music:ui/u0a10043}
    +-    Proc # 6: adj=fore /F  trm= 0 21014:com.google.process.gapps/u0a10023 (provider)
    +-        com.google.android.gsf/.settings.GoogleSettingsProvider<=Proc{20935:com.google.process.location/u0a10023}
    +-    Proc #38: adj=vis  /F  trm= 0 21028:com.android.nfc:handover/1027 (service)
    +-        com.android.nfc/.handover.HandoverService<=Proc{20964:com.android.nfc/1027}
    +-    Proc # 7: adj=vis  /B  trm= 0 20935:com.google.process.location/u0a10023 (service)
    +-        com.google.android.location/.GeocodeService<=Proc{20674:system/1000}
    +-    Proc # 3: adj=vis  /F  trm= 0 21225:com.android.bluetooth/1002 (service)
    +-        com.android.bluetooth/.hfp.HeadsetService<=Proc{20674:system/1000}
    +-    Proc # 0: adj=vis  /F  trm= 0 20908:com.google.android.inputmethod.latin/u0a10035 (service)
    +-        com.google.android.inputmethod.latin/com.android.inputmethod.latin.LatinIME<=Proc{20674:system/1000}
    +-    Proc #34: adj=svc  /B  trm= 0 16765:com.google.android.apps.currents/u0a10012 (started-services)
    +-    Proc #14: adj=svc  /B  trm= 0 21148:com.google.android.gms/u0a10023 (started-services)
    +-    Proc #12: adj=home /B  trm= 0 20989:com.android.launcher/u0a10036 (home)
    +-    Proc #37: adj=svcb /B  trm= 0 15194:com.google.android.apps.googlevoice/u0a10089 (started-services)
    +-    Proc #17: adj=svcb /B  trm= 0 24537:android.process.media/u0a10016 (started-services)
    +-    Proc #35: adj=bak  /B  trm= 0 16087:com.android.defcontainer/u0a10013 (service)
    +-        com.android.defcontainer/.DefaultContainerService<=Proc{16050:com.android.settings/1000}
    +-    Proc #16: adj=bak  /B  trm= 0 7334:com.google.android.gm/u0a10022 (bg-act)
    +-    Proc #15: adj=bak  /B  trm= 0 22499:com.google.android.googlequicksearchbox/u0a10060 (bg-act)
    +-    Proc # 9: adj=bak  /B  trm= 0 20856:com.google.android.gsf.login/u0a10023 (bg-empty)
    +-    Proc #26: adj=bak+1/B  trm= 0 9923:com.android.mms/u0a10042 (bg-act)
    +-    Proc #23: adj=bak+1/B  trm= 0 16721:com.android.chrome/u0a10010 (bg-act)
    +-    Proc #22: adj=bak+1/B  trm= 0 17596:com.android.chrome:sandboxed_process0/u0a10010i33 (service)
    +-        com.android.chrome/org.chromium.content.app.SandboxedProcessService0<=Proc{16721:com.android.chrome/u0a10010}
    +-    Proc #19: adj=bak+1/B  trm= 0 17442:com.google.android.youtube/u0a10067 (bg-services)
    +-    Proc #18: adj=bak+2/B  trm= 0 16740:com.google.android.apps.plus/u0a10052 (bg-empty)
    +-    Proc #13: adj=bak+2/B  trm= 0 7707:com.android.musicfx/u0a10044 (bg-empty)
    +-    Proc #36: adj=bak+3/B  trm= 0 16050:com.android.settings/1000 (bg-act)
    +-    Proc #33: adj=bak+3/B  trm= 0 16863:com.android.dialer/u0a10015 (bg-act)
    +-</pre>
    +-
    +-
    +-<p class="note"><strong>Note:</strong> The exact details of what is shown here will vary across
    +-platform versions as process management policies are tweaked and improved.</p>
    +-
    +-
    +-<p>Details on the highlighted sections are:</p>
    +-
    +-<ol>
    +-<li>Foreground app: This is the current app running in the foreground -- it is in the "fore" memory
    +-class because it is the top activity on the activity stack.</li>
    +-
    +-<li>Persistent processes: These are processes that are part of the core system that must always be
    +-running.</li>
    +-
    +-<li>Dependent process: This shows how the Music app is using two processes. Its UI process has a
    +-dependency on the "main" process (through a content provider). So while the UI process is in use,
    +-the main process must also be kept around. This means the app's memory footprint is actually the
    +-sum of both processes. You will have this kind of connection on a content provider any time you
    +-have active calls into it or have unclosed cursors or file streams that came from it.</li>
    +-
    +-<li>Visible processes: These are processes that count in some way as "visible" to the user. This
    +-generally means that it is either something the user can literally see (such as a process hosting a
    +-paused but visible activity that is behind a non-full-screen dialog) or is something the user might
    +-notice if the process disappeared (such as a foreground service playing music). You should be
    +-certain that any process you have running at the "visible" level is indeed critical to the user,
    +-because they are very expensive to the overall RAM load.</li>
    +-
    +-<li>Service processes: These are processes running long-term jobs in a service. This level of the
    +-list is the start of less-critical processes, which the system has some freedom to kill if RAM is
    +-needed elsewhere. These services are still quite expensive because they can be killed only
    +-temporarily and the system tries to keep them running whenever possible.</li>
    +-
    +-<li>Home process: A special slot for the process that hosts the current Home activity, to try to
    +-prevent it from being killed as much as possible. Killing this process is much more damaging to the
    +-user experience than killing other cached processes, because so much user interaction goes through
    +-home.</li>
    +-
    +-<li>Secondary service processes: These are services that have been running for a relatively long time
    +-and so should be killed more aggressively when RAM is needed elsewhere.</li>
    +-
    +-<li>Cached processes: These are cached processes held in the LRU cache, which allow for fast app
    +-switching and component launching. These processes are not required and the system will kill them
    +-as needed to reclaim memory. You will often see a process hosting a running service here—this is
    +-part of a platform policy of allowing very long-running services to drop down into the LRU list and
    +-eventually be killed. If the service should continue running (as defined by the {@link
    +-android.app.Service#onStartCommand onStartCommand()} return value, such as {@link
    +-android.app.Service#START_STICKY}), the the system eventually restarts it. This avoids issues with
    +-such services having memory leaks that over time reduce the number of regular cached processes that
    +-can be kept.</li>
    +-
    +-</ol>
    +-
    +-<p>This numbered list of processes is essentially the LRU list of processes that the framework
    +-provides to the kernel to help it determine which processes it should kill as it needs more RAM.
    +-The kernel's out of memory killer will generally begin from the bottom of this list, killing the
    +-last process and working its way up. It may not do it in exactly this order, as it can also take
    +-into consideration other factors such as the relative RAM footprint of processes to some degree.</p>
    +-
    +-<p>There are many other options you can use with the activity command to analyze further details of
    +-your app's state&mdash;use <code>adb shell dumpsys activity -h</code> for help on its use.</p>
    +-
    +--->
    +diff --git a/docs/html/training/articles/perf-anr.jd b/docs/html/training/articles/perf-anr.jd
    +index 8848354..58db3e2 100644
    +--- a/docs/html/training/articles/perf-anr.jd
    ++++ b/docs/html/training/articles/perf-anr.jd
    +@@ -14,6 +14,14 @@ page.article=true
    +   <li><a href="#Reinforcing">Reinforcing Responsiveness</a></li>
    + </ol>
    + 
    ++<h2>You should also read</h2>
    ++<ul>
    ++  <li><a href="/topic/performance/background-optimization.html">Background Optimizations</a>
    ++  <li><a href="/topic/performance/scheduling.html">Intelligent Job-Scheduling</a>
    ++  <li><a href="/training/monitoring-device-state/manifest-receivers.html">Manipulating Broadcast Receivers On Demand</a>
    ++  <li><a href="/guide/components/intents-filters.html">Intents and Intent Filters</a>
    ++</ul>
    ++
    + </div>
    + </div>
    + 
    +@@ -146,7 +154,7 @@ as the UI thread by default.</p>
    + 
    + <p>If you implement {@link java.lang.Thread} or {@link android.os.HandlerThread},
    + be sure that your UI thread does not block while waiting for the worker thread to
    +-complete&mdash;do not call {@link java.lang.Object#wait Thread.wait()} or
    ++complete&mdash;do not call {@link java.lang.Thread#wait Thread.wait()} or
    + {@link java.lang.Thread#sleep Thread.sleep()}. Instead of blocking while waiting for a worker
    + thread to complete, your main thread should provide a {@link
    + android.os.Handler} for the other threads to post back to upon completion.
    +@@ -165,6 +173,16 @@ application should start an {@link android.app.IntentService} if a
    + potentially long running action needs to be taken in response to an intent
    + broadcast.</p>
    + 
    ++<p>
    ++  Another common issue with {@link android.content.BroadcastReceiver} objects
    ++  occurs when they execute too frequently. Frequent background execution can
    ++  reduce the amount of memory available to other apps.
    ++  For more information about how to enable and disable
    ++  {@link android.content.BroadcastReceiver} objects efficiently, see
    ++  <a href="/training/monitoring-device-state/manifest-receivers.html">Manipulating
    ++    Broadcast Receivers on Demand</a>.
    ++</p>
    ++
    + <p class="note"><strong>Tip:</strong>
    + You can use {@link android.os.StrictMode} to help find potentially
    + long running operations such as network or database operations that
    +diff --git a/docs/html/training/articles/perf-tips.jd b/docs/html/training/articles/perf-tips.jd
    +index 82de69a..30cab14 100644
    +--- a/docs/html/training/articles/perf-tips.jd
    ++++ b/docs/html/training/articles/perf-tips.jd
    +@@ -28,7 +28,8 @@ when combined, but it's unlikely that these changes will result in dramatic
    + performance effects. Choosing the right algorithms and data structures should always be your
    + priority, but is outside the scope of this document. You should use the tips in this document
    + as general coding practices that you can incorporate into your habits for general code
    +-efficiency.</p>
    ++efficiency.
    ++</p>
    + 
    + <p>There are two basic rules for writing efficient code:</p>
    + <ul>
    +@@ -49,8 +50,7 @@ code for a device with a JIT is not always the best code for a device
    + without.</p>
    + 
    + <p>To ensure your app performs well across a wide variety of devices, ensure
    +-your code is efficient at all levels and agressively optimize your performance.</p>
    +-
    ++your code is efficient at all levels and aggressively optimize your performance.</p>
    + 
    + <h2 id="ObjectCreation">Avoid Creating Unnecessary Objects</h2>
    + 
    +diff --git a/docs/html/training/articles/security-tips.jd b/docs/html/training/articles/security-tips.jd
    +index abf6711..9796d9a 100644
    +--- a/docs/html/training/articles/security-tips.jd
    ++++ b/docs/html/training/articles/security-tips.jd
    +@@ -6,34 +6,32 @@ page.article=true
    + <div id="tb">
    + <h2>In this document</h2>
    + <ol class="nolist">
    +-  <li><a href="#StoringData">Storing Data</a></li>
    +-  <li><a href="#Permissions">Using Permissions</a></li>
    +-  <li><a href="#Networking">Using Networking</a></li>
    +-  <li><a href="#InputValidation">Performing Input Validation</a></li>
    +-  <li><a href="#UserData">Handling User Data</a></li>
    ++  <li><a href="#StoringData">Storing data</a></li>
    ++  <li><a href="#Permissions">Using permissions</a></li>
    ++  <li><a href="#Networking">Using networking</a></li>
    ++  <li><a href="#InputValidation">Performing input validation</a></li>
    ++  <li><a href="#UserData">Handling user data</a></li>
    +   <li><a href="#WebView">Using WebView</a></li>
    +-  <li><a href="#Crypto">Using Cryptography</a></li>
    +-  <li><a href="#IPC">Using Interprocess Communication</a></li>
    +-  <li><a href="#DynamicCode">Dynamically Loading Code</a></li>
    +-  <li><a href="#Dalvik">Security in a Virtual Machine</a></li>
    +-  <li><a href="#Native">Security in Native Code</a></li>
    ++  <li><a href="#Crypto">Using cryptography</a></li>
    ++  <li><a href="#IPC">Using interprocess communication</a></li>
    ++  <li><a href="#DynamicCode">Dynamically loading code</a></li>
    ++  <li><a href="#Dalvik">Security in a virtual machine</a></li>
    ++  <li><a href="#Native">Security in native code</a></li>
    + </ol>
    + <h2>See also</h2>
    + <ul>
    + <li><a href="http://source.android.com/tech/security/index.html">Android
    +-Security Overview</a></li>
    ++  Security Overview</a></li>
    + <li><a href="{@docRoot}guide/topics/security/permissions.html">Permissions</a></li>
    + </ul>
    + </div></div>
    + 
    + 
    +-<p>Android has security features built
    +-into the operating system that significantly reduce the frequency and impact of
    +-application security issues. The system is designed so you can typically build your apps with
    +-default system and file permissions and avoid difficult decisions about security.</p>
    ++<p>Android has built-in security features that significantly reduce the frequency and impact of
    ++application security issues. The system is designed so that you can typically build your apps with
    ++the default system and file permissions and avoid difficult decisions about security.</p>
    + 
    +-<p>Some of the core security features that help you build secure apps
    +-include:
    ++<p>The following core security features help you build secure apps:
    + <ul>
    + <li>The Android Application Sandbox, which isolates your app data and code execution
    + from other apps.</li>
    +@@ -43,47 +41,54 @@ security functionality such as cryptography, permissions, and secure
    + <li>Technologies like ASLR, NX, ProPolice, safe_iop, OpenBSD dlmalloc, OpenBSD
    + calloc, and Linux mmap_min_addr to mitigate risks associated with common memory
    + management errors.</li>
    +-<li>An encrypted filesystem that can be enabled to protect data on lost or
    ++<li>An encrypted file system that can be enabled to protect data on lost or
    + stolen devices.</li>
    + <li>User-granted permissions to restrict access to system features and user data.</li>
    + <li>Application-defined permissions to control application data on a per-app basis.</li>
    + </ul>
    + 
    +-<p>Nevertheless, it is important that you be familiar with the Android
    ++<p>It is important that you be familiar with the Android
    + security best practices in this document. Following these practices as general coding habits
    +-will reduce the likelihood of inadvertently introducing security issues that
    ++ reduces the likelihood of inadvertently introducing security issues that
    + adversely affect your users.</p>
    + 
    + 
    + 
    +-<h2 id="StoringData">Storing Data</h2>
    ++<h2 id="StoringData">Storing data</h2>
    + 
    + <p>The most common security concern for an application on Android is whether the data
    + that you save on the device is accessible to other apps. There are three fundamental
    + ways to save data on the device:</p>
    + 
    ++<ul>
    ++<li>Internal storage.</li>
    ++<li>External storage.</li>
    ++<li>Content providers.</li>
    ++</ul>
    ++
    ++The following paragraphs describe the security issues associated with each approach.
    ++
    + <h3 id="InternalStorage">Using internal storage</h3>
    + 
    + <p>By default, files that you create on <a
    + href="{@docRoot}guide/topics/data/data-storage.html#filesInternal">internal
    +-storage</a> are accessible only to your app. This
    +-protection is implemented by Android and is sufficient for most
    +-applications.</p>
    ++storage</a> are accessible only to your app.
    ++ Android implements this protection, and it's sufficient for most applications.</p>
    + 
    +-<p>You should generally avoid using the {@link android.content.Context#MODE_WORLD_WRITEABLE} or
    ++<p>Generally, avoid the {@link android.content.Context#MODE_WORLD_WRITEABLE} or
    + {@link android.content.Context#MODE_WORLD_READABLE} modes for
    + <acronym title="Interprocess Communication">IPC</acronym> files because they do not provide
    + the ability to limit data access to particular applications, nor do they
    +-provide any control on data format. If you want to share your data with other
    +-app processes, you might instead consider using a
    ++provide any control of data format. If you want to share your data with other
    ++app processes, instead consider using a
    + <a href="{@docRoot}guide/topics/providers/content-providers.html">content provider</a>, which
    + offers read and write permissions to other apps and can make
    + dynamic permission grants on a case-by-case basis.</p>
    + 
    +-<p>To provide additional protection for sensitive data, you might
    +-choose to encrypt local files using a key that is not directly accessible to the
    +-application. For example, a key can be placed in a {@link java.security.KeyStore}
    +-and protected with a user password that is not stored on the device.  While this
    ++<p>To provide additional protection for sensitive data, you can
    ++ encrypt local files using a key that is not directly accessible to the
    ++application. For example, you can place a key in a {@link java.security.KeyStore}
    ++and protect it with a user password that is not stored on the device.  While this
    + does not protect data from a root compromise that can monitor the user
    + inputting the password,  it can provide protection for a lost device without <a
    + href="http://source.android.com/tech/encryption/index.html">file system
    +@@ -94,14 +99,14 @@ encryption</a>.</p>
    + 
    + <p>Files created on <a
    + href="{@docRoot}guide/topics/data/data-storage.html#filesExternal">external
    +-storage</a>, such as SD Cards, are globally readable and writable.  Because
    ++storage</a>, such as SD cards, are globally readable and writable. Because
    + external storage can be removed by the user and also modified by any
    +-application,  you should not store sensitive information using
    ++application, don't store sensitive information using
    + external storage.</p>
    + 
    +-<p>As with data from any untrusted source, you should <a href="#InputValidation">perform input
    +-validation</a> when handling data from external storage.
    +-We strongly recommend that you not store executables or
    ++<p>You should <a href="#InputValidation">Perform input validation</a> when handling
    ++data from external storage as you would with data from any untrusted source.
    ++You should not store executables or
    + class files on external storage prior to dynamic loading.  If your app
    + does retrieve executable files from external storage, the files should be signed and
    + cryptographically verified prior to dynamic loading.</p>
    +@@ -117,22 +122,22 @@ applications with access to your {@link android.content.ContentProvider}, mark t
    + href="{@docRoot}guide/topics/manifest/provider-element.html#exported">
    + android:exported=false</a></code> in the application manifest. Otherwise, set the <code><a
    + href="{@docRoot}guide/topics/manifest/provider-element.html#exported">android:exported</a></code>
    +-attribute {@code "true"} to allow other apps to access the stored data.
    ++attribute to {@code true} to allow other apps to access the stored data.
    + </p>
    + 
    + <p>When creating a {@link android.content.ContentProvider}
    +-that will be exported for use by other applications, you can specify a single
    ++that is exported for use by other applications, you can specify a single
    + <a href="{@docRoot}guide/topics/manifest/provider-element.html#prmsn">permission
    +-</a> for reading and writing, or distinct permissions for reading and writing
    +-within the manifest. We recommend that you limit your permissions to those
    ++</a> for reading and writing, or you can specify distinct permissions for reading and writing.
    ++You should limit your permissions to those
    + required to accomplish the task at hand. Keep in mind that it’s usually
    + easier to add permissions later to expose new functionality than it is to take
    +-them away and break existing users.</p>
    ++them away and impact existing users.</p>
    + 
    + <p>If you are using a content provider
    + for sharing data between only your own apps, it is preferable to use the
    + <a href="{@docRoot}guide/topics/manifest/permission-element.html#plevel">{@code
    +-android:protectionLevel}</a> attribute set to {@code "signature"} protection.
    ++android:protectionLevel}</a> attribute set to {@code signature} protection.
    + Signature permissions do not require user confirmation,
    + so they provide a better user experience and more controlled access to the
    + content provider data when the apps accessing the data are
    +@@ -148,7 +153,7 @@ android.content.Intent#FLAG_GRANT_WRITE_URI_PERMISSION} flags in the
    + that activates the component.  The scope of these permissions can be further
    + limited by the <code><a
    + href="{@docRoot}guide/topics/manifest/grant-uri-permission-element.html">
    +-&lt;grant-uri-permission element&gt;</a></code>.</p>
    ++&lt;grant-uri-permission&gt;</a></code> element.</p>
    + 
    + <p>When accessing a content provider, use parameterized query methods such as
    + {@link android.content.ContentProvider#query(Uri,String[],String,String[],String) query()},
    +@@ -158,11 +163,11 @@ potential SQL injection from untrusted sources. Note that using parameterized me
    + sufficient if the <code>selection</code> argument is built by concatenating user data
    + prior to submitting it to the method.</p>
    + 
    +-<p>Do not have a false sense of security about the write permission.  Consider
    +-that the write permission allows SQL statements which make it possible for some
    ++<p>Don't have a false sense of security about the write permission.
    ++ The write permission allows SQL statements that make it possible for some
    + data to be confirmed using creative <code>WHERE</code> clauses and parsing the
    +-results. For example, an attacker might probe for presence of a specific phone
    +-number in a call-log by modifying a row only if that phone number already
    ++results. For example, an attacker might probe for the presence of a specific phone
    ++number in a call log by modifying a row only if that phone number already
    + exists. If the content provider data has predictable structure, the write
    + permission may be equivalent to providing both reading and writing.</p>
    + 
    +@@ -172,7 +177,7 @@ permission may be equivalent to providing both reading and writing.</p>
    + 
    + 
    + 
    +-<h2 id="Permissions">Using Permissions</h2>
    ++<h2 id="Permissions">Using permissions</h2>
    + 
    + <p>Because Android sandboxes applications from each other, applications must explicitly
    + share resources and data. They do this by declaring the permissions they need for additional
    +@@ -180,25 +185,25 @@ capabilities not provided by the basic sandbox, including access to device featu
    + the camera.</p>
    + 
    + 
    +-<h3 id="RequestingPermissions">Requesting Permissions</h3>
    ++<h3 id="RequestingPermissions">Requesting permissions</h3>
    + 
    +-<p>We recommend minimizing the number of permissions that your app requests.
    +-Not having access to sensitive permissions reduces the risk of
    +-inadvertently misusing those permissions, can improve user adoption, and makes
    ++<p>You should minimize the number of permissions that your app requests.
    ++Restricting access to sensitive permissions reduces the risk of
    ++inadvertently misusing those permissions, improves user adoption, and makes
    + your app less vulnerable for attackers. Generally,
    +-if a permission is not required for your app to function, do not request it.</p>
    ++if a permission is not required for your app to function, don't request it.</p>
    + 
    + <p>If it's possible to design your application in a way that does not require
    + any permissions, that is preferable.  For example, rather than requesting access
    + to device information to create a unique identifier, create a <a
    + href="{@docRoot}reference/java/util/UUID.html">GUID</a> for your application
    +-(see the section about <a href="#UserData">Handling User Data</a>). Or, rather than
    ++(see the section about <a href="#UserData">Handling user data</a>). Or, rather than
    + using external storage (which requires permission), store data
    + on the internal storage.</p>
    + 
    + <p>In addition to requesting permissions, your application can use the <a
    +-href="{@docRoot}guide/topics/manifest/permission-element.html">{@code <permissions>}</a>
    +-to protect IPC that is security sensitive and will be exposed to other
    ++href="{@docRoot}guide/topics/manifest/permission-element.html">{@code &lt;permission&gt;}</a>
    ++ element to protect IPC that is security sensitive and is exposed to other
    + applications, such as a {@link android.content.ContentProvider}.
    + In general, we recommend using access controls
    + other than user confirmed permissions where possible because permissions can
    +@@ -211,13 +216,14 @@ provided by a single developer.</p>
    + data over IPC that is available only because your app has permission to access
    + that data. The clients of your app's IPC interface may not have that same
    + data-access permission. More details on the frequency and potential effects
    +-of this issue appear in <a class="external-link"
    +-href="https://www.usenix.org/legacy/event/sec11/tech/full_papers/Felt.pdf"> this
    +-research paper</a>, published at USENIX.
    ++of this issue appear in the research paper <a
    ++href="https://www.usenix.org/legacy/event/sec11/tech/full_papers/Felt.pdf" class="external-link">
    ++Permission Re-Delegation: Attacks and Defenses
    ++</a>, published at USENIX.
    + 
    + 
    + 
    +-<h3 id="CreatingPermissions">Creating Permissions</h3>
    ++<h3 id="CreatingPermissions">Creating permissions</h3>
    + 
    + <p>Generally, you should strive to define as few permissions as possible while
    + satisfying your security requirements.  Creating a new permission is relatively
    +@@ -228,18 +234,18 @@ perform access checks using existing permissions.</p>
    + 
    + <p>If you must create a new permission, consider whether you can accomplish
    + your task with a <a
    +-href="{@docRoot}guide/topics/manifest/permission-element.html#plevel">"signature"
    ++href="{@docRoot}guide/topics/manifest/permission-element.html#plevel">signature
    + protection level</a>.  Signature permissions are transparent
    +-to the user and only allow access by applications signed by the same developer
    +-as application performing the permission check.</p>
    ++to the user and allow access only by applications signed by the same developer
    ++as the application performing the permission check.</p>
    + 
    + <p>If you create a permission with the <a
    +-href="{@docRoot}guide/topics/manifest/permission-element.html#plevel">"dangerous"
    ++href="{@docRoot}guide/topics/manifest/permission-element.html#plevel">dangerous
    + protection level</a>, there are a number of complexities
    + that you need to consider:
    + <ul>
    + <li>The permission must have a string that concisely expresses to a user the
    +-security decision they will be required to make.</li>
    ++security decision they are required to make.</li>
    + <li>The permission string must be localized to many different languages.</li>
    + <li>Users may choose not to install an application because a permission is
    + confusing or perceived as risky.</li>
    +@@ -247,28 +253,28 @@ confusing or perceived as risky.</li>
    + has not been installed.</li>
    + </ul>
    + 
    +-<p>Each of these poses a significant non-technical challenge for you as the developer
    ++<p>Each of these poses a significant nontechnical challenge for you as the developer
    + while also confusing your users,
    +-which is why we discourage the use of the "dangerous" permission level.</p>
    ++which is why we discourages the use of the <em>dangerous</em> permission level.</p>
    + 
    + 
    + 
    + 
    + 
    +-<h2 id="Networking">Using Networking</h2>
    ++<h2 id="Networking">Using networking</h2>
    + 
    +-<p>Network transactions are inherently risky for security, because it involves transmitting
    ++<p>Network transactions are inherently risky for security, because they involve transmitting
    + data that is potentially private to the user. People are increasingly aware of the privacy
    + concerns of a mobile device, especially when the device performs network transactions,
    + so it's very important that your app implement all best practices toward keeping the user's
    + data secure at all times.</p>
    + 
    +-<h3 id="IPNetworking">Using IP Networking</h3>
    ++<h3 id="IPNetworking">Using IP networking</h3>
    + 
    + <p>Networking on Android is not significantly different from other Linux
    + environments.  The key consideration is making sure that appropriate protocols
    + are used for sensitive data, such as {@link javax.net.ssl.HttpsURLConnection} for
    +-secure web traffic.   We prefer use of HTTPS over HTTP anywhere that HTTPS is
    ++secure web traffic. You should use HTTPS over HTTP anywhere that HTTPS is
    + supported on the server, because mobile devices frequently connect on networks
    + that are not secured, such as public Wi-Fi hotspots.</p>
    + 
    +@@ -278,32 +284,32 @@ class.  Given the frequency with which Android devices connect to unsecured
    + wireless networks using Wi-Fi, the use of secure networking is strongly
    + encouraged for all applications that communicate over the network.</p>
    + 
    +-<p>We have seen some applications use <a
    +-href="http://en.wikipedia.org/wiki/Localhost">localhost</a> network ports for
    +-handling sensitive IPC.  We discourage this approach since these interfaces are
    +-accessible by other applications on the device.  Instead, you should use an Android IPC
    +-mechanism where authentication is possible such as with a {@link android.app.Service}.  (Even
    +-worse than using loopback is to bind to INADDR_ANY since then your application
    +-may receive requests from anywhere.)</p>
    ++<p>Some applications use <a
    ++href="http://en.wikipedia.org/wiki/Localhost" class="external-link">localhost</a> network ports for
    ++handling sensitive IPC.  You should not use this approach because these interfaces are
    ++accessible by other applications on the device. Instead, use an Android IPC
    ++mechanism where authentication is possible, such as with a {@link android.app.Service}.
    ++Binding to INADDR_ANY is worse than using loopback because then your application
    ++may receive requests from anywhere.</p>
    + 
    +-<p>Also, one common issue that warrants repeating is to make sure that you do
    +-not trust data downloaded from HTTP or other insecure protocols.  This includes
    ++<p>Make sure that you don't
    ++ trust data downloaded from HTTP or other insecure protocols.  This includes
    + validation of input in {@link android.webkit.WebView} and
    + any responses to intents issued against HTTP.</p>
    + 
    + 
    +-<h3>Using Telephony Networking</h3>
    ++<h3>Using telephony networking</h3>
    + 
    + <p>The <acronym title="Short Message Service">SMS</acronym> protocol was primarily designed for
    + user-to-user communication and is not well-suited for apps that want to transfer data.
    +-Due to the limitations of SMS, we strongly recommend the use of <a
    ++Due to the limitations of SMS, you should use <a
    + href="{@docRoot}google/gcm/index.html">Google Cloud Messaging</a> (GCM)
    + and IP networking for sending data messages from a web server to your app on a user device.</p>
    + 
    + <p>Beware that SMS is neither encrypted nor strongly
    +-authenticated on either the network or the device.  In particular, any SMS receiver
    +-should expect that a malicious user may have sent the SMS to your application&mdash;Do
    +-not rely on unauthenticated SMS data to perform sensitive commands.
    ++authenticated on either the network or the device. In particular, any SMS receiver
    ++should expect that a malicious user may have sent the SMS to your application. Don't
    ++ rely on unauthenticated SMS data to perform sensitive commands.
    + Also, you should be aware that SMS may be subject to spoofing and/or
    + interception on the network.  On the Android-powered device itself, SMS
    + messages are transmitted as broadcast intents, so they may be read or captured
    +@@ -314,32 +320,32 @@ permission.</p>
    + 
    + 
    + 
    +-<h2 id="InputValidation">Performing Input Validation</h2>
    ++<h2 id="InputValidation">Performing input validation</h2>
    + 
    + <p>Insufficient input validation is one of the most common security problems
    +-affecting applications, regardless of what platform they run on. Android does
    +-have platform-level countermeasures that reduce the exposure of applications to
    +-input validation issues and you should use those features where possible. Also
    +-note that selection of type-safe languages tends to reduce the likelihood of
    ++affecting applications, regardless of what platform they run on. Android
    ++has platform-level countermeasures that reduce the exposure of applications to
    ++input validation issues, and you should use those features where possible. Also
    ++note that the selection of type-safe languages tends to reduce the likelihood of
    + input validation issues.</p>
    + 
    +-<p>If you are using native code, then any data read from files, received over
    ++<p>If you are using native code, any data read from files, received over
    + the network, or received from an IPC has the potential to introduce a security
    + issue.  The most common problems are <a
    +-href="http://en.wikipedia.org/wiki/Buffer_overflow">buffer overflows</a>, <a
    +-href="http://en.wikipedia.org/wiki/Double_free#Use_after_free">use after
    ++href="http://en.wikipedia.org/wiki/Buffer_overflow" class="external-link">buffer overflows</a>, <a
    ++href="http://en.wikipedia.org/wiki/Double_free#Use_after_free" class="external-link">use after
    + free</a>, and <a
    +-href="http://en.wikipedia.org/wiki/Off-by-one_error">off-by-one errors</a>.
    ++href="http://en.wikipedia.org/wiki/Off-by-one_error" class="external-link">off-by-one errors</a>.
    + Android provides a number of technologies like <acronym
    + title="Address Space Layout Randomization">ASLR</acronym> and <acronym
    + title="Data Execution Prevention">DEP</acronym> that reduce the
    +-exploitability of these errors, but they do not solve the underlying problem.
    +-You can prevent these vulneratbilities by careful handling pointers and managing
    ++exploitability of these errors, but they don't solve the underlying problem.
    ++You can prevent these vulnerabilities by carefully handling pointers and managing
    + buffers.</p>
    + 
    +-<p>Dynamic, string based languages such as JavaScript and SQL are also subject
    ++<p>Dynamic, string-based languages such as JavaScript and SQL are also subject
    + to input validation problems due to escape characters and <a
    +-href="http://en.wikipedia.org/wiki/Code_injection">script injection</a>.</p>
    ++href="http://en.wikipedia.org/wiki/Code_injection" class="external-link">script injection</a>.</p>
    + 
    + <p>If you are using data within queries that are submitted to an SQL database or a
    + content provider, SQL injection may be an issue.  The best defense is to use
    +@@ -348,60 +354,59 @@ href="#ContentProviders">content providers</a>.
    + Limiting permissions to read-only or write-only can also reduce the potential
    + for harm related to SQL injection.</p>
    + 
    +-<p>If you cannot use the security features above, we strongly recommend the use
    +-of well-structured data formats and verifying that the data conforms to the
    ++<p>If you can't use the security features above, you should make sure to use
    ++well-structured data formats and verify that the data conforms to the
    + expected format. While blacklisting of characters or character-replacement can
    +-be an effective strategy, these techniques are error-prone in practice and
    ++be an effective strategy, these techniques are error prone in practice and
    + should be avoided when possible.</p>
    + 
    + 
    + 
    + 
    + 
    +-<h2 id="UserData">Handling User Data</h2>
    ++<h2 id="UserData">Handling user data</h2>
    + 
    + <p>In general, the best approach for user data security is to minimize the use of APIs that access
    + sensitive or personal user data. If you have access to user data and can avoid
    +-storing or transmitting the information, do not store or transmit the data.
    +-Finally, consider if there is a way that your application logic can be
    ++storing or transmitting it, don't store or transmit the data.
    ++Consider if there is a way that your application logic can be
    + implemented using a hash or non-reversible form of the data.  For example, your
    +-application might use the hash of an an email address as a primary key, to
    ++application might use the hash of an email address as a primary key to
    + avoid transmitting or storing the email address.  This reduces the chances of
    + inadvertently exposing data, and it also reduces the chance of attackers
    + attempting to exploit your application.</p>
    + 
    + <p>If your application accesses personal information such as passwords or
    +-usernames, keep in mind that some jurisdictions may require you to provide a
    +-privacy policy explaining your use and storage of that data.  So following the
    ++user names, keep in mind that some jurisdictions may require you to provide a
    ++privacy policy explaining your use and storage of that data. Following the
    + security best practice of minimizing access to user data may also simplify
    + compliance.</p>
    + 
    + <p>You should also consider whether your application might be inadvertently
    + exposing personal information to other parties such as third-party components
    + for advertising or third-party services used by your application. If you don't
    +-know why a component or service requires a personal information, don’t
    ++know why a component or service requires personal information, don’t
    + provide it.  In general, reducing the access to personal information by your
    +-application will reduce the potential for problems in this area.</p>
    +-
    +-<p>If access to sensitive data is required, evaluate whether that information
    +-must be transmitted to a server, or whether the operation can be performed on
    +-the client.  Consider running any code using sensitive data on the client to
    +-avoid transmitting user data.</p>
    +-
    +-<p>Also, make sure that you do not inadvertently expose user data to other
    +-application on the device through overly permissive IPC, world writable files,
    +-or network sockets. This is a special case of leaking permission-protected data,
    ++application reduces the potential for problems in this area.</p>
    ++
    ++<p>If your app requires access to sensitive data, evaluate whether you need to
    ++ transmit it to a server or you can run the operation on
    ++the client. Consider running any code using sensitive data on the client to
    ++avoid transmitting user data. Also, make sure that you do not inadvertently expose user
    ++ data to other
    ++applications on the device through overly permissive IPC, world-writable files,
    ++or network sockets. Overly permissive IPC is a special case of leaking permission-protected data,
    + discussed in the <a href="#RequestingPermissions">Requesting Permissions</a> section.</p>
    + 
    + <p>If a <acronym title="Globally Unique Identifier">GUID</acronym>
    +-is required, create a large, unique number and store it.  Do not
    +-use phone identifiers such as the phone number or IMEI which may be associated
    ++is required, create a large, unique number and store it.  Don't
    ++use phone identifiers such as the phone number or IMEI, which may be associated
    + with personal information.  This topic is discussed in more detail in the <a
    +-href="http://android-developers.blogspot.com/2011/03/identifying-app-installations.html">Android
    +-Developer Blog</a>.</p>
    ++href="http://android-developers.blogspot.com/2011/03/identifying-app-installations.html"
    ++>Android Developer Blog</a>.</p>
    + 
    + <p>Be careful when writing to on-device logs.
    +-In Android, logs are a shared resource, and are available
    ++In Android, logs are a shared resource and are available
    + to an application with the {@link android.Manifest.permission#READ_LOGS} permission.
    + Even though the phone log data
    + is temporary and erased on reboot, inappropriate logging of user information
    +@@ -414,19 +419,23 @@ could inadvertently leak user data to other applications.</p>
    + 
    + <h2 id="WebView">Using WebView</h2>
    + 
    +-<p>Because {@link android.webkit.WebView} consumes web content that can include HTML and JavaScript,
    ++<p>Because {@link android.webkit.WebView} consumes web content that can include HTML
    ++ and JavaScript,
    + improper use can introduce common web security issues such as <a
    +-href="http://en.wikipedia.org/wiki/Cross_site_scripting">cross-site-scripting</a>
    ++href="http://en.wikipedia.org/wiki/Cross_site_scripting" class="external-link">
    ++cross-site-scripting</a>
    + (JavaScript injection).  Android includes a number of mechanisms to reduce
    +-the scope of these potential issues by limiting the capability of {@link android.webkit.WebView} to
    ++the scope of these potential issues by limiting the capability of
    ++ {@link android.webkit.WebView} to
    + the minimum functionality required by your application.</p>
    + 
    +-<p>If your application does not directly use JavaScript within a {@link android.webkit.WebView}, do
    +-<em>not</em> call {@link android.webkit.WebSettings#setJavaScriptEnabled setJavaScriptEnabled()}.
    ++<p>If your application doesn't directly use JavaScript within a {@link android.webkit.WebView},
    ++ <em>do not</em> call
    ++ {@link android.webkit.WebSettings#setJavaScriptEnabled setJavaScriptEnabled()}.
    + Some sample code uses this method, which you might repurpose in production
    + application, so remove that method call if it's not required. By default,
    + {@link android.webkit.WebView} does
    +-not execute JavaScript so cross-site-scripting is not possible.</p>
    ++not execute JavaScript, so cross-site-scripting is not possible.</p>
    + 
    + <p>Use {@link android.webkit.WebView#addJavascriptInterface
    + addJavaScriptInterface()} with
    +@@ -441,55 +450,55 @@ addJavaScriptInterface()} only to JavaScript that is contained within your appli
    + <p>If your application accesses sensitive data with a
    + {@link android.webkit.WebView}, you may want to use the
    + {@link android.webkit.WebView#clearCache clearCache()} method to delete any files stored
    +-locally. Server-side
    +-headers like <code>no-cache</code> can also be used to indicate that an application should
    ++locally. You can also use server-side
    ++headers such as <code>no-cache</code> to indicate that an application should
    + not cache particular content.</p>
    + 
    + <p>Devices running platforms older than Android 4.4 (API level 19)
    + use a version of {@link android.webkit webkit} that has a number of security issues.
    + As a workaround, if your app is running on these devices, it
    +-should confirm that {@link android.webkit.WebView} objects display only trusted
    +-content. You should also use the updatable security {@link
    +-java.security.Provider Provider} object to make sure your app isn’t exposed to
    +-potential vulnerabilities in SSL, as described in <a
    ++must confirm that {@link android.webkit.WebView} objects display only trusted
    ++content. To make sure your app isn’t exposed to
    ++potential vulnerabilities in SSL, use the updatable security {@link
    ++java.security.Provider Provider} object as described in <a
    + href="{@docRoot}training/articles/security-gms-provider.html">Updating Your
    + Security Provider to Protect Against SSL Exploits</a>. If your application must
    + render content from the open web, consider providing your own renderer so
    + you can keep it up to date with the latest security patches.</p>
    + 
    + 
    +-<h3 id="Credentials">Handling Credentials</h3>
    ++<h3 id="Credentials">Handling credentials</h3>
    + 
    +-<p>In general, we recommend minimizing the frequency of asking for user
    +-credentials&mdash;to make phishing attacks more conspicuous, and less likely to be
    +-successful.  Instead use an authorization token and refresh it.</p>
    ++<p>To make phishing attacks more conspicuous and less likely to be
    ++successful, minimize the frequency of asking for user
    ++credentials. Instead use an authorization token and refresh it.</p>
    + 
    +-<p>Where possible, username and password should not be stored on the device.
    +-Instead, perform initial authentication using the username and password
    +-supplied by the user, and then use a short-lived, service-specific
    ++<p>Where possible, don't store user names and passwords on the device.
    ++Instead, perform initial authentication using the user name and password
    ++ supplied by the user, and then use a short-lived, service-specific
    + authorization token.</p>
    + 
    +-<p>Services that will be accessible to multiple applications should be accessed
    ++<p>Services that are accessible to multiple applications should be accessed
    + using {@link android.accounts.AccountManager}. If possible, use the
    +-{@link android.accounts.AccountManager} class to invoke a cloud-based service and do not store
    ++{@link android.accounts.AccountManager} class to invoke a cloud-based service and don't store
    + passwords on the device.</p>
    + 
    + <p>After using {@link android.accounts.AccountManager} to retrieve an
    +-{@link android.accounts.Account}, {@link android.accounts.Account#CREATOR}
    +-before passing in any credentials, so that you do not inadvertently pass
    ++{@link android.accounts.Account}, use {@link android.accounts.Account#CREATOR}
    ++before passing in any credentials so that you do not inadvertently pass
    + credentials to the wrong application.</p>
    + 
    +-<p>If credentials are to be used only by applications that you create, then you
    +-can verify the application which accesses the {@link android.accounts.AccountManager} using
    ++<p>If credentials are used only by applications that you create, you
    ++can verify the application that accesses the {@link android.accounts.AccountManager} using
    + {@link android.content.pm.PackageManager#checkSignatures checkSignature()}.
    +-Alternatively, if only one application will use the credential, you might use a
    ++Alternatively, if only one application uses the credential, you might use a
    + {@link java.security.KeyStore} for storage.</p>
    + 
    + 
    + 
    + 
    + 
    +-<h2 id="Crypto">Using Cryptography</h2>
    ++<h2 id="Crypto">Using cryptography</h2>
    + 
    + <p>In addition to providing data isolation, supporting full-filesystem
    + encryption, and providing secure communications channels, Android provides a
    +@@ -500,21 +509,21 @@ implementation that can  support your use case.  If you need to securely
    + retrieve a file from a known location, a simple HTTPS URI may be adequate and
    + requires no knowledge of cryptography.  If you need a secure
    + tunnel, consider using {@link javax.net.ssl.HttpsURLConnection} or
    +-{@link javax.net.ssl.SSLSocket}, rather than writing your own protocol.</p>
    ++{@link javax.net.ssl.SSLSocket} rather than writing your own protocol.</p>
    + 
    +-<p>If you do find yourself needing to implement your own protocol, we strongly
    +-recommend that you <em>not</em> implement your own cryptographic algorithms. Use
    ++<p>If you do need to implement your own protocol, you should <em>not</em>
    ++implement your own cryptographic algorithms. Use
    + existing cryptographic algorithms such as those in the implementation of AES or
    + RSA provided in the {@link javax.crypto.Cipher} class.</p>
    + 
    + <p>Use a secure random number generator, {@link java.security.SecureRandom},
    +-to initialize any cryptographic keys, {@link javax.crypto.KeyGenerator}.
    ++to initialize any cryptographic keys generated by {@link javax.crypto.KeyGenerator}.
    + Use of a key that is not generated with a secure random
    +-number generator significantly weakens the strength of the algorithm, and may
    ++number generator significantly weakens the strength of the algorithm and may
    + allow offline attacks.</p>
    + 
    +-<p>If you need to store a key for repeated use, use a mechanism like
    +-  {@link java.security.KeyStore} that
    ++<p>If you need to store a key for repeated use, use a mechanism, such as
    ++  {@link java.security.KeyStore}, that
    + provides a mechanism for long term storage and retrieval of cryptographic
    + keys.</p>
    + 
    +@@ -522,10 +531,10 @@ keys.</p>
    + 
    + 
    + 
    +-<h2 id="IPC">Using Interprocess Communication</h2>
    ++<h2 id="IPC">Using interprocess communication</h2>
    + 
    + <p>Some apps attempt to implement IPC using traditional Linux
    +-techniques such as network sockets and shared files.  We strongly encourage you to instead
    ++techniques such as network sockets and shared files. However, you should instead
    + use Android system functionality for IPC such as {@link android.content.Intent},
    + {@link android.os.Binder} or {@link android.os.Messenger} with a {@link
    + android.app.Service}, and {@link android.content.BroadcastReceiver}.
    +@@ -535,19 +544,19 @@ mechanism.</p>
    + 
    + <p>Many of the security elements are shared across IPC mechanisms.
    + If your IPC mechanism is not intended for use by other applications, set the
    +-{@code android:exported} attribute to {@code "false"} in the component's manifest element,
    ++{@code android:exported} attribute to {@code false} in the component's manifest element,
    + such as for the <a
    +-href="{@docRoot}guide/topics/manifest/service-element.html#exported">{@code <service>}</a>
    ++href="{@docRoot}guide/topics/manifest/service-element.html#exported">{@code &lt;service&gt;}</a>
    + element.  This is useful for applications that consist of multiple processes
    +-within the same UID, or if you decide late in development that you do not
    +-actually want to expose functionality as IPC but you don’t want to rewrite
    ++within the same UID or if you decide late in development that you don't
    ++actually want to expose functionality as IPC, but you don’t want to rewrite
    + the code.</p>
    + 
    +-<p>If your IPC is intended to be accessible to other applications, you can
    ++<p>If your IPC is accessible to other applications, you can
    + apply a security policy by using the <a
    +-href="{@docRoot}guide/topics/manifest/permission-element.html">{@code <permission>}</a>
    ++href="{@docRoot}guide/topics/manifest/permission-element.html">{@code &lt;permission>}</a>
    + element. If IPC is between your own separate apps that are signed with the same key,
    +-it is preferable to use {@code "signature"} level permission in the <a
    ++it is preferable to use {@code signature} level permission in the <a
    + href="{@docRoot}guide/topics/manifest/permission-element.html#plevel">{@code
    + android:protectionLevel}</a>.</p>
    + 
    +@@ -556,31 +565,42 @@ android:protectionLevel}</a>.</p>
    + 
    + <h3>Using intents</h3>
    + 
    +-<p>Intents are the preferred mechanism for asynchronous IPC in Android.
    ++<p>For activities and broadcast receivers, intents are the preferred mechanism for
    ++ asynchronous IPC in Android.
    + Depending on your application requirements, you might use {@link
    + android.content.Context#sendBroadcast sendBroadcast()}, {@link
    + android.content.Context#sendOrderedBroadcast sendOrderedBroadcast()},
    + or an explicit intent to a specific application component.</p>
    + 
    +-<p>Note that ordered broadcasts can be “consumed” by a recipient, so they
    ++<p class="caution"><strong>Caution:</strong> If you use an intent to bind to a
    ++ {@link android.app.Service}, ensure that your app is secure by using an
    ++ <a href="{@docRoot}guide/components/intents-filters.html#Types">explicit</a>
    ++intent. Using an implicit intent to start a service is a
    ++security hazard because you can't be certain what service will respond to the intent,
    ++and the user can't see which service starts. Beginning with Android 5.0 (API level 21),
    ++ the system
    ++throws an exception if you call {@link android.content.Context#bindService bindService()}
    ++with an implicit intent.</p>
    ++
    ++<p>Note that ordered broadcasts can be <em>consumed</em> by a recipient, so they
    + may not be delivered to all applications.  If you are sending an intent that must be delivered
    +-to a specific receiver, then you must use an explicit intent that declares the receiver
    +-by nameintent.</p>
    ++to a specific receiver, you must use an explicit intent that declares the receiver
    ++by name.</p>
    + 
    +-<p>Senders of an intent can verify that the recipient has a permission
    +-specifying a non-Null permission with the method call.  Only applications with that
    +-permission will receive the intent.  If data within a broadcast intent may be
    ++<p>Senders of an intent can verify that the recipient has permission
    ++ by specifying a non-null permission with the method call.  Only applications with that
    ++permission receive the intent. If data within a broadcast intent may be
    + sensitive, you should consider applying a permission to make sure that
    +-malicious applications cannot register to receive those messages without
    +-appropriate permissions.  In those circumstances, you may also consider
    ++malicious applications can't register to receive those messages without
    ++appropriate permissions. In those circumstances, you may also consider
    + invoking the receiver directly, rather than raising a broadcast.</p>
    + 
    + <p class="note"><strong>Note:</strong> Intent filters should not be considered
    +-a security feature&mdash;components
    ++a security feature. Components
    + can be invoked with explicit intents and may not have data that would conform to the intent
    +-filter. You should perform input validation within your intent receiver to
    ++filter. To
    + confirm that it is properly formatted for the invoked receiver, service, or
    +-activity.</p>
    ++activity, perform input validation within your intent receiver.</p>
    + 
    + 
    + 
    +@@ -589,26 +609,32 @@ activity.</p>
    + 
    + <p>A {@link android.app.Service} is often used to supply functionality for other applications to
    + use. Each service class must have a corresponding <a
    +-href="{@docRoot}guide/topics/manifest/service-element.html">{@code <service>}</a> declaration in its
    ++href="{@docRoot}guide/topics/manifest/service-element.html">{@code <service>}</a>
    ++ declaration in its
    + manifest file.</p>
    + 
    + <p>By default, services are not exported and cannot be invoked by any other
    +-application. However, if you add any intent filters to the service declaration, then it is exported
    ++application. However, if you add any intent filters to the service declaration, it is exported
    + by default. It's best if you explicitly declare the <a
    + href="{@docRoot}guide/topics/manifest/service-element.html#exported">{@code
    + android:exported}</a> attribute to be sure it behaves as you'd like.
    + Services can also be protected using the <a
    + href="{@docRoot}guide/topics/manifest/service-element.html#prmsn">{@code android:permission}</a>
    +-attribute. By doing so, other applications will need to declare
    ++attribute. By doing so, other applications need to declare
    + a corresponding <code><a
    + href="{@docRoot}guide/topics/manifest/uses-permission-element.html">&lt;uses-permission&gt;</a>
    + </code> element in their own manifest to be
    + able to start, stop, or bind to the service.</p>
    + 
    ++<p class="note"><strong>Note:</strong> If your app targets Android 5.0 (API level 21) or later,
    ++ you should use the {@link android.app.job.JobScheduler} to execute background
    ++ services. For more information about {@link android.app.job.JobScheduler}, see its
    ++ {@link android.app.job.JobScheduler API-reference documentation}.</p>
    ++
    + <p>A service can protect individual IPC calls into it with permissions, by
    + calling {@link android.content.Context#checkCallingPermission
    + checkCallingPermission()} before executing
    +-the implementation of that call.  We generally recommend using the
    ++the implementation of that call. You should use the
    + declarative permissions in the manifest, since those are less prone to
    + oversight.</p>
    + 
    +@@ -620,24 +646,24 @@ oversight.</p>
    + preferred mechanism for RPC-style IPC in Android. They provide a well-defined
    + interface that enables mutual authentication of the endpoints, if required.</p>
    + 
    +-<p>We strongly encourage designing interfaces in a manner that does not require
    +-interface specific permission checks. {@link android.os.Binder} and
    ++<p>You should design your app interfaces in a manner that does not require
    ++interface-specific permission checks. {@link android.os.Binder} and
    + {@link android.os.Messenger} objects are not declared within the
    + application manifest, and therefore you cannot apply declarative permissions
    + directly to them.  They generally inherit permissions declared in the
    + application manifest for the {@link android.app.Service} or {@link
    + android.app.Activity} within which they are
    + implemented.  If you are creating an interface that requires authentication
    +-and/or access controls, those controls must be
    +-explicitly added as code in the {@link android.os.Binder} or {@link android.os.Messenger}
    ++and/or access controls, you must explicitly add those controls
    ++ as code in the {@link android.os.Binder} or {@link android.os.Messenger}
    + interface.</p>
    + 
    +-<p>If providing an interface that does require access controls, use {@link
    ++<p>If you are providing an interface that does require access controls, use {@link
    + android.content.Context#checkCallingPermission checkCallingPermission()}
    + to verify whether the
    + caller has a required permission. This is especially important
    + before accessing a service on behalf of the caller, as the identify of your
    +-application is passed to other interfaces.  If invoking an interface provided
    ++application is passed to other interfaces.  If you are invoking an interface provided
    + by a {@link android.app.Service}, the {@link
    + android.content.Context#bindService bindService()}
    +  invocation may fail if you do not have permission to access the given service.
    +@@ -660,8 +686,8 @@ application. If your {@link android.content.BroadcastReceiver}
    + is intended for use by other applications, you
    + may want to apply security permissions to receivers using the <code><a
    + href="{@docRoot}guide/topics/manifest/receiver-element.html">
    +-&lt;receiver&gt;</a></code> element within the application manifest.  This will
    +-prevent applications without appropriate permissions from sending an intent to
    ++&lt;receiver&gt;</a></code> element within the application manifest.  This
    ++prevents applications without appropriate permissions from sending an intent to
    + the {@link android.content.BroadcastReceiver}.</p>
    + 
    + 
    +@@ -671,57 +697,58 @@ the {@link android.content.BroadcastReceiver}.</p>
    + 
    + 
    + 
    +-<h2 id="DynamicCode">Dynamically Loading Code</h2>
    ++<h2 id="DynamicCode">Dynamically loading code</h2>
    + 
    + <p>We strongly discourage loading code from outside of your application APK.
    + Doing so significantly increases the likelihood of application compromise due
    +-to code injection or code tampering.  It also adds complexity around version
    +-management and application testing.  Finally, it can make it impossible to
    ++to code injection or code tampering. It also adds complexity around version
    ++management and application testing. It can also make it impossible to
    + verify the behavior of an application, so it may be prohibited in some
    + environments.</p>
    + 
    + <p>If your application does dynamically load code, the most important thing to
    +-keep in mind about dynamically loaded code is that it runs with the same
    +-security permissions as the application APK.  The user made a decision to
    +-install your application based on your identity, and they are expecting that
    ++keep in mind about dynamically-loaded code is that it runs with the same
    ++security permissions as the application APK.  The user makes a decision to
    ++install your application based on your identity, and the user expects that
    + you provide any code run within the application, including code that is
    + dynamically loaded.</p>
    + 
    + <p>The major security risk associated with dynamically loading code is that the
    + code needs to come from a verifiable source. If the modules are included
    +-directly within your APK, then they cannot be modified by other applications.
    ++directly within your APK, they cannot be modified by other applications.
    + This is true whether the code is a native library or a class being loaded using
    +-{@link dalvik.system.DexClassLoader}.  We have seen many instances of applications
    +-attempting to load code from insecure locations, such as downloaded from the
    +-network over unencrypted protocols or from world writable locations such as
    ++{@link dalvik.system.DexClassLoader}.  Many applications
    ++attempt to load code from insecure locations, such as downloaded from the
    ++network over unencrypted protocols or from world-writable locations such as
    + external storage. These locations could allow someone on the network to modify
    +-the content in transit, or another application on a users device to modify the
    +-content on the device, respectively.</p>
    ++the content in transit or another application on a user's device to modify the
    ++content on the device.</p>
    + 
    + 
    + 
    + 
    + 
    +-<h2 id="Dalvik">Security in a Virtual Machine</h2>
    ++<h2 id="Dalvik">Security in a virtual machine</h2>
    + 
    + <p>Dalvik is Android's runtime virtual machine (VM). Dalvik was built specifically for Android,
    + but many of the concerns regarding secure code in other virtual machines also apply to Android.
    + In general, you shouldn't concern yourself with security issues relating to the virtual machine.
    +-Your application runs in a secure sandbox environment, so other processes on the system cannnot
    ++Your application runs in a secure sandbox environment, so other processes on the system can't
    + access your code or private data.</p>
    + 
    +-<p>If you're interested in diving deeper on the subject of virtual machine security,
    +-we recommend that you familiarize yourself with some
    ++<p>If you're interested in learning more about virtual machine security,
    ++ familiarize yourself with some
    + existing literature on the subject. Two of the more popular resources are:
    + <ul>
    +-<li><a href="http://www.securingjava.com/toc.html">
    +-http://www.securingjava.com/toc.html</a></li>
    ++<li><a href="http://www.securingjava.com/toc.html" class="external-link">
    ++Securing Java</a></li>
    + <li><a
    +-href="https://www.owasp.org/index.php/Java_Security_Resources">
    +-https://www.owasp.org/index.php/Java_Security_Resources</a></li>
    ++href="https://www.owasp.org/index.php/Category:Java#tab=Related_3rd_Party_Projects"
    ++ class="external-link">
    ++Related 3rd party Projects</a></li>
    + </ul></p>
    + 
    +-<p>This document is focused on the areas which are Android specific or
    ++<p>This document focuses on areas that are Android specific or
    + different from other VM environments.  For developers experienced with VM
    + programming in other environments, there are two broad issues that may be
    + different about writing apps for Android:
    +@@ -742,21 +769,19 @@ because that code might be modified to include malicious behavior.</li>
    + 
    + 
    + 
    +-<h2 id="Native">Security in Native Code</h2>
    ++<h2 id="Native">Security in native code</h2>
    + 
    +-<p>In general, we encourage developers to use the Android SDK for
    ++<p>In general, you should use the Android SDK for
    + application development, rather than using native code with the
    + <a href="{@docRoot}tools/sdk/ndk/index.html">Android NDK</a>.  Applications built
    + with native code are more complex, less portable, and more like to include
    +-common memory corruption errors such as buffer overflows.</p>
    ++common memory-corruption errors such as buffer overflows.</p>
    + 
    +-<p>Android is built using the Linux kernel and being familiar with Linux
    +-development security best practices is especially useful if you are going to
    +-use native code. Linux security practices are beyond the scope of this document,
    +-but one of the most popular resources is “Secure Programming for
    +-Linux and Unix HOWTO”, available at <a
    +-href="http://www.dwheeler.com/secure-programs">
    +-http://www.dwheeler.com/secure-programs</a>.</p>
    ++<p>Android is built using the Linux kernel, and being familiar with Linux
    ++development security best practices is especially useful if you are
    ++using native code. Linux security practices are beyond the scope of this document,
    ++but one of the most popular resources is <a href="http://www.dwheeler.com/secure-programs"
    ++ class="external-link">Secure Programming HOWTO - Creating Secure Software</a>.</p>
    + 
    + <p>An important difference between Android and most Linux environments is the
    + Application Sandbox.  On Android, all applications run in the Application
    +@@ -765,6 +790,5 @@ good way to think about it for developers familiar with Linux is to know that
    + every application is given a unique <acronym title="User Identifier">UID</acronym>
    + with very limited permissions. This is discussed in more detail in the <a
    + href="http://source.android.com/tech/security/index.html">Android Security
    +-Overview</a> and you should be familiar with application permissions even if
    ++Overview</a>, and you should be familiar with application permissions even if
    + you are using native code.</p>
    +-
    +diff --git a/docs/html/training/auto/audio/index.jd b/docs/html/training/auto/audio/index.jd
    +index 3a1b1e8..6588367 100644
    +--- a/docs/html/training/auto/audio/index.jd
    ++++ b/docs/html/training/auto/audio/index.jd
    +@@ -596,7 +596,7 @@ href="https://www.youtube.com/watch?v=xc2HZSwPcwM">
    + </a>
    + <h2 id="support_voice">Support Voice Actions</h2>
    + 
    +-<p>To reduce driver distractions, you can add voice actions in your audio playback app. With voice
    ++<p>To reduce driver distractions, you must add voice actions in your audio playback app. With voice
    + action support, users can launch your app and play audio by providing voice input on Auto screens.
    + If your audio playback app is already active and the user says
    + <i>“Play a song”</i>, the system starts playing music without requiring the user to look at or touch
    +diff --git a/docs/html/training/backup/autosyncapi.jd b/docs/html/training/backup/autosyncapi.jd
    +deleted file mode 100644
    +index e0df7bb..0000000
    +--- a/docs/html/training/backup/autosyncapi.jd
    ++++ /dev/null
    +@@ -1,370 +0,0 @@
    +-page.title=Configuring Auto Backup for Apps
    +-page.tags=backup, marshmallow, androidm
    +-page.keywords=backup, autobackup
    +-page.image=images/cards/card-auto-backup_2x.png
    +-
    +-@jd:body
    +-
    +-<div id="tb-wrapper">
    +-<div id="tb">
    +-<h2>This lesson teaches you to</h2>
    +-<ol>
    +-        <li><a href="#configuring">Configure Data Backup</a></li>
    +-        <li><a href="#previous-androids">Support Lower Versions of Android</a></li>
    +-        <li><a href="#testing">Test Backup Configuration</a></li>
    +-        <li><a href="#issues">Handle Google Cloud Messaging</a></li>
    +-</ol>
    +-    <h2>You should also read</h2>
    +-    <ul>
    +-      <li><a href="{@docRoot}guide/topics/data/backup.html">Data Backup</a></li>
    +-      <li><a href="{@docRoot}training/backup/backupapi.html">Using the Backup API</a>
    +-      </li>
    +-    </ul>
    +-
    +-</div>
    +-</div>
    +-
    +-<p>
    +-  Users frequently invest time and effort to configure apps just the way they like them. Switching
    +-  to a new device can cancel out all that careful configuration. For apps whose <a href=
    +-  "{@docRoot}guide/topics/manifest/uses-sdk-element.html#target">target SDK version</a>
    +-  is Android 6.0 (API level 23) and higher, devices running Android 6.0 and higher automatically
    +-  back up app data to the cloud. The system performs this automatic backup
    +-  for nearly all app data by default, and does so without your having to write any additional app
    +-  code.
    +-</p>
    +-
    +-<p class="note">
    +-<strong>Note:</strong> To protect user privacy, the device user must have opted in to Google
    +-services for Auto Backup to work. The Google services opt-in dialog appears when the user goes
    +-through the Setup Wizard or configures the first Google account on the device.
    +-</p>
    +-
    +-<p>
    +-  When a user installs your app on
    +-  a new device, or reinstalls your app on one (for example, after a factory reset), the system
    +-  automatically restores the app data from the cloud. This lesson provides information about how to
    +-  configure the Auto Backup for Apps feature, explaining its default behavior and how to
    +-  exclude data that you don't want the system to back up.
    +-</p>
    +-
    +-<p>
    +-  The automatic backup feature preserves the data your app creates on a user device by uploading it
    +-  to the user’s Google Drive account and encrypting it. There is no charge to you or the user for
    +-  data storage, and the saved data does not count towards the user's personal Google Drive quota.
    +-  Each app can store up to 25MB. Once its backed-up data reaches 25MB, the app no longer sends
    +-  data to the cloud. If the system performs a data restore, it uses the last data snapshot that
    +-  the app had sent to the cloud.
    +-</p>
    +-
    +-<p>Automatic backups occur when the following conditions are met:</p>
    +-  <ul>
    +-     <li>The device is idle.</li>
    +-     <li>The device is charging.</li>
    +-     <li>The device is connected to a Wi-Fi network.</li>
    +-     <li>At least 24 hours have elapsed since the last backup.</li>
    +-  </ul>
    +-</p>
    +-
    +-<h2 id="configuring">Configure Data Backup</h2>
    +-
    +-<p>
    +-  On devices running Android 6.0 (API level 23) or higher, the default system behavior is to back up
    +-  almost all data that an app creates. The exception is <a href="#auto-exclude">
    +-  automatically excluded data files</a>. This section explains how you can use settings in
    +-  your app <a href="{@docRoot}guide/topics/manifest/manifest-intro.html">manifest</a> to further
    +-  limit and configure what data the system backs up.
    +-</p>
    +-
    +-<h3 id="include-exclude">Including or excluding data</h3>
    +-
    +-<p>
    +-  Depending on what data your app needs and how you save it, you may need to set specific
    +-  rules for including or excluding certain files or directories. Auto Backup for Apps
    +-  lets you set these backup rules through the app manifest, in which you specify a backup scheme
    +-  configuration XML file. For example:
    +-</p>
    +-
    +-<pre>
    +-&lt;?xml version="1.0" encoding="utf-8"?&gt;
    +-&lt;manifest xmlns:android="http://schemas.android.com/apk/res/android"
    +-        xmlns:tools="http://schemas.android.com/tools"
    +-        package="com.my.appexample"&gt;
    +-    &lt;uses-sdk android:minSdkVersion="23"/&gt;
    +-    &lt;uses-sdk android:targetSdkVersion="23"/&gt;
    +-    &lt;application ...
    +-<strong>        android:fullBackupContent="&#64;xml/mybackupscheme"&gt;</strong>
    +-    &lt;/app&gt;
    +-    ...
    +-&lt;/manifest&gt;
    +-</pre>
    +-
    +-<p>
    +-  In this example, the <code>android:fullBackupContent</code> attribute specifies an XML file
    +-  called {@code mybackupscheme.xml}, which resides in the <code>res/xml/</code> directory of your
    +-  app development project. This configuration file contains rules controlling which files are backed
    +-  up. The following example code shows a configuration file that excludes a specific file,
    +-  {@code device_info.db}:
    +-</p>
    +-
    +-<pre>
    +-&lt;?xml version="1.0" encoding="utf-8"?&gt;
    +-&lt;full-backup-content&gt;
    +-    &lt;exclude domain="database" path="device_info.db"/&gt;
    +-&lt;/full-backup-content&gt;
    +-</pre>
    +-
    +-<h3 id="auto-exclude">Automatically excluded data files</h3>
    +-
    +-<p>
    +-  Most apps do not need to, and in fact should not, back up all data. For example, the system
    +-  should not back up temporary files and caches. For this reason, the automatic backup
    +-  service excludes certain data files by default:
    +-</p>
    +-
    +-<ul>
    +-  <li>Files in the directories to which the
    +-  {@link android.content.Context#getCacheDir getCacheDir()} and
    +-  {@link android.content.Context#getCodeCacheDir getCodeCacheDir()} methods refer.
    +-  </li>
    +-
    +-  <li>Files located on external storage, unless they reside in the directory to which the
    +-    {@link android.content.Context#getExternalFilesDir getExternalFilesDir()} method refers.
    +-  </li>
    +-
    +-  <li>Files located in the directory to which the
    +-    {@link android.content.Context#getNoBackupFilesDir getNoBackupFilesDir()} method refers.
    +-  </li>
    +-</ul>
    +-<h3>Backup Configuration Syntax</h3>
    +-
    +-<p>
    +-  The backup service configuration allows you to specify what files to include or exclude from
    +-  backup. The syntax for the data backup configuration XML file is as follows:
    +-</p>
    +-
    +-<pre>
    +-&lt;full-backup-content&gt;
    +-    &lt;include domain=["file" | "database" | "sharedpref" | "external" | "root"]
    +-    path="string" /&gt;
    +-    &lt;exclude domain=["file" | "database" | "sharedpref" | "external" | "root"]
    +-    path="string" /&gt;
    +-&lt;/full-backup-content&gt;
    +-</pre>
    +-
    +-<p>
    +-  The following elements and attributes allow you to specify the files to include in, and exclude
    +-  from, backup:
    +-</p>
    +-
    +-<ul>
    +-  <li>
    +-  <code>&lt;include&gt;</code>: Specifies a set of resources to
    +-  back up, instead of having the system back up all data in your app by default. If you specify
    +-  an <code>&lt;include&gt;</code> element, the system backs up <em>only the resources specified</em>
    +-  with this element. You can specify multiple sets of resources to back up by using multiple
    +-  <code>&lt;include&gt;</code> elements
    +-  </li>
    +-
    +-  <li>
    +-  <code>&lt;exclude&gt;</code>: Specifies any data you want the system to exclude
    +-  when it does a full backup. If you target the same set of resources with both the
    +-  <code>&lt;include&gt;</code> and <code>&lt;exclude&gt;</code> elements,
    +-  <code>&lt;exclude&gt;</code> takes precedence.
    +-  </li>
    +-
    +-  <li>
    +-  <code>domain</code>: Specifies the type of resource you want to include in,
    +-  or exclude from, backup. Valid values for this attribute include:
    +-
    +-
    +-
    +-  <ul>
    +-    <li>
    +-    <code>root</code>: Specifies that the resource is in the app’s root directory.
    +-    </li>
    +-
    +-    <li>
    +-    <code>file</code>: Specifies a resource in the directory returned by the
    +-    {@link android.content.Context#getFilesDir getFilesDir()} method.
    +-    </li>
    +-
    +-    <li>
    +-    <code>database</code>: Specifies a database that the
    +-    {@link android.content.Context#getDatabasePath getDatabasePath()} method returns, or that
    +-    the app interacts with via the {@link android.database.sqlite.SQLiteOpenHelper} class.
    +-    </li>
    +-
    +-    <li>
    +-    <code>sharedpref</code>: Specifies a {@link android.content.SharedPreferences} object
    +-    that the {@link android.content.Context#getSharedPreferences getSharedPreferences()}
    +-    method returns.
    +-    </li>
    +-
    +-    <li>
    +-    <code>external</code>: Specifies that the resource is in external storage, and corresponds
    +-    to a file in the directory that the
    +-    {@link android.content.Context#getExternalFilesDir getExternalFilesDir()} method returns.
    +-    </li>
    +-  </ul>
    +-  </li>
    +-    <li>
    +-    <code>path</code>: Specifies the file path to a resource that you want to include in, or
    +-    exclude from, backup.
    +-    </li>
    +-
    +-  </li>
    +-</ul>
    +-
    +-
    +-<h3 id="disabling">Disabling data backups</h3>
    +-
    +-<p>
    +-  You can choose to prevent automatic backups of any of your app data by setting the
    +-  <code>android:allowBackup</code> attribute to <code>false</code> in the {@code app} element of
    +-  your manifest. This setting is illustrated in the following example:
    +-</p>
    +-
    +-<pre>
    +-&lt;?xml version="1.0" encoding="utf-8"?&gt;
    +-&lt;manifest xmlns:android="http://schemas.android.com/apk/res/android"
    +-        xmlns:tools="http://schemas.android.com/tools"
    +-        package="com.my.appexample"&gt;
    +-    &lt;uses-sdk android:minSdkVersion="23"/&gt;
    +-    &lt;uses-sdk android:targetSdkVersion="23"/&gt;
    +-    &lt;application ...
    +-<strong>        android:allowBackup="false"&gt;</strong>
    +-    &lt;/application&gt;
    +-    ...
    +-&lt;/manifest&gt;
    +-</pre>
    +-
    +-<h2 id="previous-androids">Support Lower Versions of Android</h2>
    +-
    +-<p>There are two scenarios in which you may also need to support versions of Android lower
    +-than 6.0 (API level 23): You may be updating your existing app to take advantage of the
    +-new auto backup functionality in Android 6.0, while wanting
    +-to continue supporting earlier versions of Android. Or you may be releasing a new app, but
    +-want to make sure devices running on versions of Android predating 6.0 also have backup
    +-functionality.</p>
    +-
    +-<h3 id="updating">Updating an existing app to support auto backup</h3>
    +-
    +-<p>Earlier versions of Android supported a key/value-pair-based backup mechanism, in which the app
    +-defines a subclass of {@link android.app.backup.BackupAgent} and sets
    +-<a href="{@docRoot}guide/topics/manifest/application-element.html#agent">
    +-{@code android:backupAgent}</a> in its
    +-<a href="{@docRoot}guide/topics/manifest/application-element.html">app manifest</a>. If your app
    +-used this legacy approach, you can transition to full-data backups by adding the
    +-{@code android:fullBackupOnly="true"} attribute to the
    +-<a href="{@docRoot}guide/topics/manifest/application-element.html">{@code <application/>}</a>
    +-element in the manifest. When running on a device with Android 5.1
    +-(API level 22) or lower, your app ignores this value in the manifest, and continues performing
    +-backups in the previous manner.</p>
    +-
    +-<p>Even if you’re not using key/value backups, you can still use the approach described above to do
    +-any custom processing in {@link android.app.Activity#onCreate(android.os.Bundle) onCreate()}
    +-or {@link android.app.backup.BackupAgent#onFullBackup onFullBackup()}. You can also use that
    +-approach to receive a notification when a restore operation happens in
    +-{@link android.app.backup.BackupAgent#onRestoreFinished onRestoreFinished()}. If you want to retain
    +-the system's default implementation of
    +-<a href="#include-exclude">XML include/exclude rules handling</a>, call
    +-{@link android.app.backup.BackupAgent#onFullBackup super.onFullBackup()}.</p>
    +-
    +-<h3 id="lower-versions">Giving your new app support for lower versions of Android</h3>
    +-
    +-<p>If you are creating a new app that targets Android 6.0, but you also want to enable cloud backup
    +-for devices running on Android 5.1 (API level 22) and lower, you must also
    +-<a href="{@docRoot}training/backup/backupapi.html">implement the Backup API</a>.</p>
    +-
    +-<h2 id="testing">Test Backup Configuration</h2>
    +-
    +-<p>
    +-  Once you have created a backup configuration, you should test it to make sure your app saves data
    +-  and can restore it properly.
    +-</p>
    +-
    +-
    +-<h3>Enabling Backup Logging</h3>
    +-
    +-<p>
    +-  To help determine how the backup feature is parsing your XML file, enable logging before
    +-  performing a test backup:
    +-</p>
    +-
    +-<pre class="no-pretty-print">
    +-$ adb shell setprop log.tag.BackupXmlParserLogging VERBOSE
    +-</pre>
    +-
    +-<h3>Testing Backup</h3>
    +-
    +-<p>To manually run a backup, first initialize the Backup Manager by executing the following
    +-  command:
    +-</p>
    +-
    +-<pre class="no-pretty-print">
    +-$ adb shell bmgr run
    +-</pre>
    +-
    +-<p>
    +-  Next, manually back up your application using the following command. Use the
    +-  <code>&lt;PACKAGE&gt;</code> parameter to specify the package name for your app:
    +-</p>
    +-
    +-<pre class="no-pretty-print">
    +-$ adb shell bmgr fullbackup &lt;PACKAGE&gt;</pre>
    +-
    +-
    +-<h3>Testing restore</h3>
    +-
    +-<p>
    +-  To manually initiate a restore after the system has backed up your app data, execute the following
    +-  command, using the <code>&lt;PACKAGE&gt;</code> parameter to specify the package name for your
    +-  app:
    +-</p>
    +-
    +-<pre class="noprettyprint">
    +-$ adb shell bmgr restore &lt;PACKAGE&gt;
    +-</pre>
    +-
    +-<p class="warning">
    +-  <b>Warning:</b> This action stops your app and wipes its data before performing the restore
    +-  operation.
    +-</p>
    +-
    +-<p>
    +-  You can test automatic restore for your app by uninstalling and reinstalling your app. The app
    +-  data is automatically restored from the cloud once the app installation is complete.
    +-</p>
    +-
    +-
    +-<h3>Troubleshooting backups</h3>
    +-
    +-<p>
    +-  If backup fails, you can clear the backup data and associated metadata either by turning backup
    +-  off and on in <strong>Settings &gt; Backup</strong>, factory-resetting the device, or
    +-  executing this command:
    +-</p>
    +-
    +-<pre>$ adb shell bmgr wipe &lt;TRANSPORT&gt; &lt;PACKAGE&gt;</pre>
    +-
    +-<p>
    +-  You must prepend <code>com.google.android.gms</code> to the {@code <TRANSPORT>} value.
    +-  To get the list of <a href="{@docRoot}google/backup/index.html">transports</a>, execute the
    +-  following command:
    +-</p>
    +-
    +-<pre>$ adb shell bmgr list transports</pre>
    +-
    +-<h2 id="gcm">Handle Google Cloud Messaging</h2>
    +-
    +-  <p>
    +-  For apps that use <a href="https://developers.google.com/cloud-messaging/gcm">Google Cloud
    +-  Messaging</a> (GCM) for push notifications, backing up the registration
    +-  token that Google Cloud Messaging registration returned can cause unexpected behavior in
    +-  notifications for the restored app. This is because when a user installs your app on a new device,
    +-  the app must <a href="https://developers.google.com/cloud-messaging/android/client#sample-register">
    +-  query the GCM API for a new registration token</a>. If the old registration is present, because the
    +-  system had backed it up and restored it, the app doesn't seek the new token. To prevent this issue
    +-  from arising, exclude the registration token from the set of backed-up files.
    +-  </p>
    +diff --git a/docs/html/training/backup/backupapi.jd b/docs/html/training/backup/backupapi.jd
    +deleted file mode 100644
    +index 2f3e939..0000000
    +--- a/docs/html/training/backup/backupapi.jd
    ++++ /dev/null
    +@@ -1,200 +0,0 @@
    +-page.title=Using the Backup API
    +-parent.title=Backing up App Data to the Cloud
    +-parent.link=index.html
    +-
    +-trainingnavtop=true
    +-
    +-next.title=Making the Most of Google Cloud Messaging
    +-next.link=gcm.html
    +-
    +-@jd:body
    +-
    +-<div id="tb-wrapper">
    +-  <div id="tb">
    +-    <h2>This lesson teaches you to</h2>
    +-    <ol>
    +-      <li><a href="#register">Register for the Android Backup Service</a></li>
    +-      <li><a href="#manifest">Configure Your Manifest</a></li>
    +-      <li><a href="#agent">Write Your Backup Agent</a></li>
    +-      <li><a href="#backup">Request a Backup</a></li>
    +-      <li><a href="#restore">Restore from a Backup</a></li>
    +-    </ol>
    +-    <h2>You should also read</h2>
    +-    <ul>
    +-      <li><a href="{@docRoot}guide/topics/data/backup.html">Data Backup</a></li>
    +-      <li><a href="{@docRoot}training/backup/autosyncapi.html">Configuring Auto Backup for Apps</a>
    +-      (Android 6.0 (API level 23) and higher)</li>
    +-    </ul>
    +-  </div>
    +-</div>
    +-
    +-<p>When a user purchases a new device or resets their existing one, they might
    +-expect that when Google Play restores your app back to their device during the
    +-initial setup, the previous data associated with the app restores as well. On versions of Android
    +-prior to 6.0 (API level 23), app data is not restored by default, and all the user's accomplishments
    +-or settings in your app are lost.</p>
    +-<p>For situations where the volume of data is relatively light (less than a
    +-megabyte), like the user's preferences, notes, game high scores or other
    +-stats, the Backup API provides a lightweight solution.  This lesson walks you
    +-through integrating the Backup API into your application, and restoring data to
    +-new devices using the Backup API.
    +-
    +-<p class="note">
    +-<strong>Note:</strong> Devices running Android 6.0 and higher
    +-<a href="{@docRoot}training/backup/autosyncapi.html">automatically back up</a>
    +-nearly all data by default.
    +-</p>
    +-
    +-<h2 id="register">Register for the Android Backup Service</h2>
    +-<p>This lesson requires the use of the <a
    +-  href="{@docRoot}google/backup/index.html">Android Backup
    +-  Service</a>, which requires registration.  Go ahead and <a
    +-  href="http://code.google.com/android/backup/signup.html">register here</a>.  Once
    +-that's done, the service pre-populates an XML tag for insertion in your Android
    +-Manifest, which looks like this:</p>
    +-<pre>
    +-&lt;meta-data android:name="com.google.android.backup.api_key"
    +-android:value="ABcDe1FGHij2KlmN3oPQRs4TUvW5xYZ" /&gt;
    +-</pre>
    +-<p>Note that each backup key works with a specific package name.  If you have
    +-different applications, register separate keys for each one.</p>
    +-
    +-
    +-<h2 id="manifest">Configure Your Manifest</h2>
    +-<p>Use of the Android Backup Service requires two additions to your application
    +-manifest.  First, declare the name of the class that acts as your backup agent,
    +-then add the snippet above as a child element of the Application tag.  Assuming
    +-your backup agent is going to be called {@code TheBackupAgent}, here's an example of
    +-what the manifest looks like with this tag included:</p>
    +-
    +-<pre>
    +-&lt;application android:label="MyApp"
    +-             android:backupAgent="TheBackupAgent"&gt;
    +-    ...
    +-    &lt;meta-data android:name="com.google.android.backup.api_key"
    +-    android:value="ABcDe1FGHij2KlmN3oPQRs4TUvW5xYZ" /&gt;
    +-    ...
    +-&lt;/application&gt;
    +-</pre>
    +-<h2 id="agent">Write Your Backup Agent</h2>
    +-<p>The easiest way to create your backup agent is by extending the wrapper class
    +-{@link android.app.backup.BackupAgentHelper}.  Creating this helper class is
    +-actually a very simple process.  Just create a class with the same name as you
    +-used in the manifest in the previous step (in this example, {@code
    +-TheBackupAgent}),
    +-and extend {@code BackupAgentHelper}.  Then override the {@link
    +-android.app.backup.BackupAgent#onCreate()}.</p>
    +-
    +-<p>Inside the {@link android.app.backup.BackupAgent#onCreate()} method, create a {@link
    +-android.app.backup.BackupHelper}.  These helpers are
    +-specialized classes for backing up certain kinds of data.  The Android framework
    +-currently includes two such helpers:  {@link
    +-android.app.backup.FileBackupHelper} and {@link
    +-android.app.backup.SharedPreferencesBackupHelper}.  After you create the helper
    +-and point it at the data you want to back up, just add it to the
    +-BackupAgentHelper using the {@link android.app.backup.BackupAgentHelper#addHelper(String, BackupHelper) addHelper()}
    +-method, adding a key which is used to
    +-retrieve the data later.  In most cases the entire
    +-implementation is perhaps 10 lines of code.</p>
    +-
    +-<p>Here's an example that backs up a high scores file.</p>
    +-
    +-<pre>
    +-import android.app.backup.BackupAgentHelper;
    +-import android.app.backup.FileBackupHelper;
    +-
    +-
    +-public class TheBackupAgent extends BackupAgentHelper {
    +-  // The name of the SharedPreferences file
    +-  static final String HIGH_SCORES_FILENAME = "scores";
    +-
    +-  // A key to uniquely identify the set of backup data
    +-  static final String FILES_BACKUP_KEY = "myfiles";
    +-
    +-  // Allocate a helper and add it to the backup agent
    +-  &#64;Override
    +-  void onCreate() {
    +-      FileBackupHelper helper = new FileBackupHelper(this, HIGH_SCORES_FILENAME);
    +-      addHelper(FILES_BACKUP_KEY, helper);
    +-  }
    +-}
    +-</pre>
    +-<p>For added flexibility, {@link android.app.backup.FileBackupHelper}'s
    +-constructor can take a variable number of filenames.  You could just as easily
    +-have backed up both a high scores file and a game progress file just by adding
    +-an extra parameter, like this:</p>
    +-<pre>
    +-&#64;Override
    +-  void onCreate() {
    +-      FileBackupHelper helper = new FileBackupHelper(this, HIGH_SCORES_FILENAME, PROGRESS_FILENAME);
    +-      addHelper(FILES_BACKUP_KEY, helper);
    +-  }
    +-</pre>
    +-<p>Backing up preferences is similarly easy.  Create a {@link
    +-android.app.backup.SharedPreferencesBackupHelper}  the same way you did a {@link
    +-android.app.backup.FileBackupHelper}.  In this case, instead of adding filenames
    +-to the constructor, add the names of the shared preference groups being used by
    +-your application.  Here's an example of how your backup agent helper might look if
    +-high scores are implemented as preferences instead of a flat file:</p>
    +-
    +-<pre>
    +-import android.app.backup.BackupAgentHelper;
    +-import android.app.backup.SharedPreferencesBackupHelper;
    +-
    +-public class TheBackupAgent extends BackupAgentHelper {
    +-    // The names of the SharedPreferences groups that the application maintains.  These
    +-    // are the same strings that are passed to getSharedPreferences(String, int).
    +-    static final String PREFS_DISPLAY = "displayprefs";
    +-    static final String PREFS_SCORES = "highscores";
    +-
    +-    // An arbitrary string used within the BackupAgentHelper implementation to
    +-    // identify the SharedPreferencesBackupHelper's data.
    +-    static final String MY_PREFS_BACKUP_KEY = "myprefs";
    +-
    +-    // Simply allocate a helper and install it
    +-    void onCreate() {
    +-       SharedPreferencesBackupHelper helper =
    +-                new SharedPreferencesBackupHelper(this, PREFS_DISPLAY, PREFS_SCORES);
    +-        addHelper(MY_PREFS_BACKUP_KEY, helper);
    +-    }
    +-}
    +-</pre>
    +-
    +-<p>You can add as many backup helper instances to your backup agent helper as you
    +-like, but remember that you only need one of each type.  One {@link
    +-android.app.backup.FileBackupHelper} handles all the files that you need to back up, and one
    +-{@link android.app.backup.SharedPreferencesBackupHelper} handles all the shared
    +-preferencegroups you need backed up.
    +-</p>
    +-
    +-
    +-<h2 id="backup">Request a Backup</h2>
    +-<p>In order to request a backup, just create an instance of the {@link
    +-android.app.backup.BackupManager}, and call it's {@link
    +-android.app.backup.BackupManager#dataChanged()} method.</p>
    +-
    +-<pre>
    +-import android.app.backup.BackupManager;
    +-...
    +-
    +-public void requestBackup() {
    +-  BackupManager bm = new BackupManager(this);
    +-  bm.dataChanged();
    +-}
    +-</pre>
    +-
    +-<p>This call notifies the backup manager that there is data ready to be backed
    +-up to the cloud.  At some point in the future, the backup manager then calls
    +-your backup agent's {@link
    +-android.app.backup.BackupAgent#onBackup(ParcelFileDescriptor, BackupDataOutput,
    +-ParcelFileDescriptor) onBackup()} method.  You can make
    +-the call whenever your data has changed, without having to worry about causing
    +-excessive network activity.  If you request a backup twice before a backup
    +-occurs, the backup only occurs once.</p>
    +-
    +-
    +-<h2 id="restore">Restore from a Backup</h2>
    +-<p>Typically you shouldn't ever have to manually request a restore, as it
    +-happens automatically when your application is installed on a device.  However,
    +-if it <em>is</em> necessary to trigger a manual restore, just call the
    +-{@link android.app.backup.BackupManager#requestRestore(RestoreObserver) requestRestore()} method.</p>
    +diff --git a/docs/html/training/backup/index.jd b/docs/html/training/backup/index.jd
    +deleted file mode 100644
    +index 4449fde..0000000
    +--- a/docs/html/training/backup/index.jd
    ++++ /dev/null
    +@@ -1,47 +0,0 @@
    +-page.title=Backing up App Data to the Cloud
    +-page.tags=cloud,sync,backup
    +-
    +-trainingnavtop=true
    +-startpage=true
    +-
    +-@jd:body
    +-
    +-<div id="tb-wrapper">
    +-<div id="tb">
    +-
    +-<h2>Dependencies and prerequisites</h2>
    +-<ul>
    +-  <li>Android 2.2 (API level 8) and higher</li>
    +-</ul>
    +-</div>
    +-</div>
    +-
    +-<p>Users often invest significant time and effort creating data and setting
    +-preferences within apps. Preserving that data for users if they replace a broken
    +-device or upgrade to a new one is an important part of ensuring a great user
    +-experience.</p>
    +-
    +-<p>This class covers techniques for backing up data to the cloud so that
    +-users can restore their data when recovering from a data loss (such as a factory
    +-reset) or installing your application on a new device.</p>
    +-
    +-<p>It is important to note that the API for cloud backup changed with the
    +-release of Android 6.0 (API level 23). For your app to support backup both
    +-on devices running Android 6.0, and those running Android 5.1 (API level
    +-22) and lower, you must implement both techniques that this class explains.</p>
    +-
    +-<h2>Lessons</h2>
    +-
    +-<dl>
    +-	<dt><strong><a href="autosyncapi.html">Configuring Auto Backup for Apps</a></strong></dt>
    +-	<dd>This lesson applies to Android 6.0 (API level 23) and higher. Learn how to accomplish
    +-  seamless app data backup and restore with zero additional lines of application code.</dd>
    +-</dl>
    +-
    +-<dl>
    +-  <dt><strong><a href="backupapi.html">Using the Backup API</a></strong></dt>
    +-  <dd>This lesson applies to Android 5.1 (API level 22) and lower. Learn how to integrate the Backup
    +-  API into your Android app, so all of that  app's user data, such as preferences, notes, and high
    +-  scores, updates seamlessly across all devices linked to that Google account.</dd>
    +-</dl>
    +-
    +diff --git a/docs/html/training/basics/firstapp/building-ui.jd b/docs/html/training/basics/firstapp/building-ui.jd
    +index a680c73..6f321e9 100644
    +--- a/docs/html/training/basics/firstapp/building-ui.jd
    ++++ b/docs/html/training/basics/firstapp/building-ui.jd
    +@@ -71,17 +71,17 @@ android.view.View} objects.</p>
    + <h2 id="LinearLayout">Create a Linear Layout</h2>
    + 
    + <ol>
    +-  <li>From the <code>res/layout/</code> directory, open the
    +-    <code>activity_main.xml</code> file.
    ++  <li>In Android Studio's <b>Project</b> window, open <b>app > res >
    ++    layout > activity_main.xml</b>.
    +     <p>This XML file defines the layout of your activity. It contains the
    +       default "Hello World" text view.</p>
    +   </li>
    +   <li>When you open a layout file, you’re first shown the design editor in the
    +     <a href="/studio/write/layout-editor.html">Layout Editor</a>. For this lesson,
    +-    you work directly with the XML, so click the <b>Text</b> tab to switch to
    +-    the text editor.
    ++    you work directly with the XML, so click the <b>Text</b> tab at the bottom
    ++    of the window to switch to the text editor.
    +   </li>
    +-  <li>Replace the contents of the file with the following XML:
    ++  <li>Delete everything and insert the following XML:
    +     <pre>&lt;?xml version="1.0" encoding="utf-8"?&gt;
    + &lt;LinearLayout
    +     xmlns:android="http://schemas.android.com/apk/res/android"
    +@@ -138,6 +138,9 @@ href="{@docRoot}guide/topics/ui/declaring-layout.html">Layout</a> guide.</p>
    + &lt;/LinearLayout&gt;
    + </pre>
    + 
    ++<p>Don't worry about the error that appears for
    ++<code>&#64;string/edit_message</code>; you'll fix that soon.</p>
    ++
    + <p>Here is a description of the attributes in the
    +   {@link android.widget.EditText &lt;EditText>} you added:</p>
    + 
    +@@ -157,7 +160,7 @@ XML. It is followed by the resource type ({@code id} in this case), a slash, the
    +   <p>A resource object is a unique integer name that's associated with an app resource,
    + such as a bitmap, layout file, or string.</p>
    +   <p>Every resource has a
    +-corresponding resource object defined in your project's {@code gen/R.java} file. You can use the
    ++corresponding resource object defined in your project's {@code R.java} file. You can use the
    + object names in the {@code R} class to refer to your resources, such as when you need to specify a
    + string value for the <a
    + href="{@docRoot}reference/android/widget/TextView.html#attr_android:hint">{@code android:hint}</a>
    +@@ -174,7 +177,7 @@ href="{@docRoot}guide/topics/resources/providing-resources.html">Providing Resou
    + <p>The plus sign (<code>+</code>) before the resource type is needed only when you're defining a
    + resource ID for the first time. When you compile the app,
    + the SDK tools use the ID name to create a new resource ID in
    +-your project's {@code gen/R.java} file that refers to the {@link
    ++your project's {@code R.java} file that refers to the {@link
    + android.widget.EditText} element. With the resource ID declared once this way,
    + other references to the ID do not
    + need the plus sign. Using the plus sign is necessary only when specifying a new resource ID and not
    +@@ -211,10 +214,10 @@ the same name does not cause collisions.</p>
    + <h2 id="Strings">Add String Resources</h2>
    + 
    + <p>By default, your Android project includes a string resource file at
    +-<code>res/values/strings.xml</code>. Here, you'll add two new strings.</p>
    ++<b>res > values > strings.xml</b>. Here, you'll add two new strings.</p>
    + 
    + <ol>
    +-<li>From the <code>res/values/</code> directory, open <code>strings.xml</code>.</li>
    ++<li>From the <b>Project</b> window, open <b>res > values > strings.xml</b>.</li>
    + <li>Add two strings so that your file looks like this:
    + <pre>&lt;?xml version="1.0" encoding="utf-8"?>
    + &lt;resources>
    +@@ -340,15 +343,12 @@ android.widget.LinearLayout}.</p>
    + 
    + <h2>Run Your App</h2>
    + 
    +-<p>This layout is applied by the default {@link android.app.Activity} class
    +-that the SDK tools generated when you created the project.</p>
    +-
    +-<p>To run the app and see the results,
    +-  click <strong>Run 'app'</strong>
    ++<p>To see how the app now looks on your device or emulator,
    ++  click <strong>Run</strong>
    +     <img src="{@docRoot}images/tools/as-run.png"
    +     style="vertical-align:baseline;margin:0; max-height:1em" /> in the
    +     toolbar.</p>
    + 
    +-<p>Continue to the <a href="starting-activity.html">next
    +-lesson</a> to learn how to respond to button presses, read content
    +-from the text field, start another activity, and more.</p>
    +\ No newline at end of file
    ++<p>To add app behaviors such as responding to a button and starting
    ++another activity, continue to the <a href="starting-activity.html">next
    ++lesson</a>.</p>
    +\ No newline at end of file
    +diff --git a/docs/html/training/basics/firstapp/creating-project.jd b/docs/html/training/basics/firstapp/creating-project.jd
    +index cad32bf..60be5f6 100644
    +--- a/docs/html/training/basics/firstapp/creating-project.jd
    ++++ b/docs/html/training/basics/firstapp/creating-project.jd
    +@@ -31,129 +31,71 @@ next.link=running-app.html
    + <ol>
    +   <li>In Android Studio, create a new project:
    +     <ul>
    +-      <li>If you don't have a project opened, in the <strong>Welcome</strong> screen, click <strong>
    +-        New Project</strong>.</li>
    +-      <li>If you have a project opened, from the <strong>File</strong> menu, select <strong>New
    +-        Project</strong>. The <em>Create New Project</em> screen appears.</li>
    ++      <li>If you don't have a project opened, in the <strong>Welcome to Android Studio</strong> window, click <strong>
    ++        Start a new Android Studio project</strong>.</li>
    ++      <li>If you have a project opened, select <strong>File > New Project</strong>.</li>
    +     </ul>
    +   </li>
    +-  <li>Fill out the fields on the screen. For <strong>Application Name</strong>
    +-    use "My First App". For <strong>Company Domain</strong>, use "example.com".
    +-    For the other fields, use the default values and click <strong>Next</strong>
    +-    <p>Here's a brief explanation of each field:</p>
    ++  <li>In the <b>New Project</b> screen, enter the following values:</p>
    +     <ul>
    +-      <li><strong>Application Name</strong> is the app name that appears to users.</li>
    +-      <li><strong>Company domain</strong> provides a qualifier that will be appended to the package
    +-        name; Android Studio will remember this qualifier for each new project you create.</li>
    +-      <li><strong>Package name</strong> is the fully qualified name for the project (following the
    +-        same rules as those for naming packages in the Java programming language). Your package name
    +-        must be unique across all packages installed on the Android system. You can <strong>
    +-        Edit</strong> this value independently from the application name or the company
    +-        domain.</li>
    +-      <li><strong>Project location</strong> is the directory on your system that holds the project
    +-        files.</li>
    ++      <li><strong>Application Name</strong>: "My First App" </li>
    ++      <li><strong>Company Domain</strong>: "example.com"</li>
    +     </ul>
    ++    <p>Android Studio fills in the package name and project location for you,
    ++    but you can edit these if you'd like.
    +   </li>
    +-  <li>Under <strong>Target Android Devices</strong>, accept the default values
    +-    and click <strong>Next</strong>.
    +-    <p>The Minimum Required SDK is the earliest version of Android that your app supports,
    +-      indicated using the <a href="{@docRoot}guide/topics/manifest/uses-sdk-element.html#ApiLevels">
    ++  <li>Click <b>Next</b>.</li>
    ++  <li>In the <b>Target Android Devices</b> screen, keep the default values and
    ++    click <b>Next</b>.
    ++    <p>The <b>Minimum Required SDK</b> is the earliest version of Android that your app supports,
    ++      which is indicated by the <a href="{@docRoot}guide/topics/manifest/uses-sdk-element.html#ApiLevels">
    +       API level</a>. To support as many devices as possible, you should set this to the lowest
    +       version available that allows your app to provide its core feature set. If any feature of your
    +-      app is possible only on newer versions of Android and it's not critical to the app's core
    +-      feature set, you can enable the feature only when running on the versions that support it (as
    +-      discussed in <a href="{@docRoot}training/basics/supporting-devices/platforms.html">
    ++      app is possible only on newer versions of Android and it's not critical to the core
    ++      feature set, enable that feature only when running on the versions that support it (see
    ++      <a href="{@docRoot}training/basics/supporting-devices/platforms.html">
    +       Supporting Different Platform Versions</a>).</p>
    +     </li>
    + 
    +-  <li>Under <strong>Add an Activity to Mobile</strong>, select <strong>Empty
    ++  <li>In the <strong>Add an Activity to Mobile</strong> screen, select <strong>Empty
    +     Activity</strong> and click <strong>Next</strong>.
    +   </li>
    + 
    +-  <div class="sidebox-wrapper">
    +-    <div class="sidebox">
    +-      <h3>Activities</h3>
    +-      <p>An activity is one of the distinguishing features of the Android framework. Activities
    +-        provide the user with access to your app, and there may be many activities. An application
    +-        will usually have a main activity for when the user launches the application, another
    +-        activity for when she selects some content to view, for example, and other activities for
    +-        when she performs other tasks within the app. See <a href="{@docRoot}guide/components/activities.html">
    +-        Activities</a> for more information.</p>
    +-    </div>
    +-  </div>
    +-
    +-  <li>Under <strong>Customize the Activity</strong>, accept the default values
    ++  <li>In the <strong>Customize the Activity</strong> screen, keep the default values
    +     and click <strong>Finish</strong>.
    + </ol>
    + 
    +-<p>Your Android project is now a basic "Hello World" app that contains some default files. Take a
    +-moment to review the most important of these:</p>
    ++<p>After some processing, Android Studio opens and displays a "Hello World" app
    ++with default files. You will add functionality to some of
    ++these files in the following lessons.</p>
    ++
    ++<p>Now take a moment to review the most important files. First, be sure that
    ++the <b>Project</b> window is open (select <b>View > Tool Windows > Project</b>)
    ++and the <b>Android</b> view is selected from the drop-down list at the top.
    ++You can then see the following files:</p>
    + 
    + <dl>
    +-  <dt><code>app/src/main/java/com.example.myfirstapp/MainActivity.java</code></dt>
    ++  <dt><b>app > java > com.example.myfirstapp > MainActivity.java</b></dt>
    +   <dd>This file appears in Android Studio after the New Project wizard finishes.
    +     It contains the class definition for the activity you created earlier. When you build
    +     and run the app, the {@link android.app.Activity} starts and loads the
    +     layout file that says "Hello World!"</dd>
    + 
    +-  <dt><code>app/src/main/res/layout/activity_main.xml</code></dt>
    ++  <dt><b>app > res > layout > activity_main.xml</b></dt>
    +   <dd>This XML file defines the layout of the activity. It contains a {@code TextView}
    +     element with the text "Hello world!".</dd>
    + 
    +-  <dt><code>app/src/main/AndroidManifest.xml</code></dt>
    ++  <dt><b>app > manifests > AndroidManifest.xml</b></dt>
    +   <dd>The <a href="{@docRoot}guide/topics/manifest/manifest-intro.html">manifest file</a> describes
    +     the fundamental characteristics of the app and defines each of its components. You'll revisit
    +     this file as you follow these lessons and add more components to your app.</dd>
    +-  <dt><code>app/build.gradle</code></dt>
    ++
    ++  <dt><b>Gradle Scripts > build.gradle</b></dt>
    +   <dd>Android Studio uses Gradle to compile and build your app. There is a <code>build.gradle</code>
    +     file for each module of your project, as well as a <code>build.gradle</code> file for the entire
    +-    project. Usually, you're only interested in the <code>build.gradle</code> file for the module,
    +-    in this case the <code>app</code> or application module. This is where your app's build dependencies
    +-    are set, including the <code>defaultConfig</code> settings:
    +-    <ul>
    +-      <li><code>compiledSdkVersion</code> is the platform version against which you will compile
    +-        your app. By default, this is set to the latest version of Android available in your SDK.
    +-        By default, this is set to the latest version of Android SDK installed on your
    +-        development machine.
    +-        You can still build your app to support older versions, but setting this to the latest
    +-        version allows you to enable new features and optimize your app for a great user experience
    +-        on the latest devices.</li>
    +-      <li><code>applicationId</code> is the fully qualified package name for your application that
    +-        you specified in the New Project wizard.</li>
    +-      <li><code>minSdkVersion</code> is the Minimum SDK version you specified during the New Project
    +-        wizard. This is the earliest version of the Android SDK that your app supports.</li>
    +-      <li><code>targetSdkVersion</code> indicates the highest version of Android with which you have
    +-        tested your application. As new versions of Android become available, you should
    +-        test your app on the new version and update this value to match the latest API level and
    +-        thereby take advantage of new platform features. For more information, read
    +-        <a href="{@docRoot}training/basics/supporting-devices/platforms.html">Supporting Different
    +-          Platform Versions</a>.</li>
    +-    </ul>
    +-    <p>See <a href="{@docRoot}studio/build/index.html">Building Your Project with Gradle</a>
    +-    for more information about Gradle.</p></dd>
    +-</dl>
    +-
    +-<p>Note also the <code>/res</code> subdirectories that contain the
    +-<a href="{@docRoot}guide/topics/resources/overview.html">resources</a> for your application:</p>
    +-<dl>
    +-  <dt><code>drawable<em>-&lt;density&gt;</em>/</code></dt>
    +-    <dd>Directories for <a href="{@docRoot}guide/topics/resources/drawable-resource.html">
    +-    drawable resources</a>, other than launcher icons, designed
    +-    for various <a href="{@docRoot}training/multiscreen/screendensities.html">densities</a>.
    +-</dd>
    +-  <dt><code>layout/</code></dt>
    +-    <dd>Directory for files that define your app's user interface like {@code activity_main.xml},
    +-      discussed above, which describes a basic layout for the {@code MainActivity}
    +-      class.</dd>
    +-  <dt><code>menu/</code></dt>
    +-    <dd>Directory for files that define your app's menu items.</dd>
    +-  <dt><code>mipmap/</code></dt>
    +-    <dd>Launcher icons reside in the {@code mipmap/} folder rather than the
    +-    {@code drawable/} folders. This folder contains the {@code ic_launcher.png} image
    +-    that appears when you run the default app.</dd>
    +-  <dt><code>values/</code></dt>
    +-    <dd>Directory for other XML files that contain a collection of resources, such as
    +-      string and color definitions.</dd>
    ++    project. Usually, you're only interested in the <code>build.gradle</code> file for the module.
    ++    in this case the <code>app</code> or application module. For more information about this file,
    ++    see <a href="{@docRoot}studio/build/index.html">Building Your Project with Gradle</a>.</dd>
    + </dl>
    + 
    + <p>
    +diff --git a/docs/html/training/basics/firstapp/running-app.jd b/docs/html/training/basics/firstapp/running-app.jd
    +index e809871..085849f 100755
    +--- a/docs/html/training/basics/firstapp/running-app.jd
    ++++ b/docs/html/training/basics/firstapp/running-app.jd
    +@@ -3,9 +3,7 @@ parent.title=Building Your First App
    + parent.link=index.html
    + 
    + trainingnavtop=true
    +-
    + page.tags=emulator
    +-helpoutsWidget=true
    + 
    + @jd:body
    + 
    +@@ -18,7 +16,7 @@ helpoutsWidget=true
    + 
    + <ol>
    +   <li><a href="#RealDevice">Run on a Real Device</a></li>
    +-  <li><a href="#Emulator">Run on the Emulator</a></li>
    ++  <li><a href="#Emulator">Run on an Emulator</a></li>
    + </ol>
    + 
    + <h2>You should also read</h2>
    +@@ -34,8 +32,10 @@ helpoutsWidget=true
    + 
    + 
    + <p>In the <a href="creating-project.html">previous lesson</a>, you created an
    +-  Android project. The project contains a default app that displays
    +-  "Hello World". In this lesson, you will run the app on a device or emulator.</p>
    ++Android project that displays "Hello World." You can now run the app on a real
    ++device or on an emulator. If you don't have a real device available, skip to
    ++<a href="#Emulator">Run on an Emulator</a>.</p>
    ++
    + 
    + <h2 id="RealDevice">Run on a Real Device</h2>
    + 
    +@@ -68,7 +68,7 @@ helpoutsWidget=true
    + <p>Android Studio installs the app on your connected device and starts it.</p>
    + 
    + 
    +-<h2 id="Emulator">Run on the Emulator</h2>
    ++<h2 id="Emulator">Run on an Emulator</h2>
    + 
    + <p>Before you run your app on an emulator, you need to create an
    +   <a href="{@docRoot}tools/devices/index.html">Android Virtual Device</a> (AVD)
    +@@ -82,12 +82,14 @@ helpoutsWidget=true
    +     <strong>Tools &gt; Android &gt; AVD Manager</strong>, or by clicking
    +     the AVD Manager icon <img src="{@docRoot}images/tools/avd-manager-studio.png"
    +     style="vertical-align:bottom;margin:0;height:19px"> in the toolbar.</li>
    +-  <li>On the AVD Manager main screen, click <strong>Create Virtual Device</strong>.</li>
    +-  <li>In the Select Hardware page, select a phone device, such as Nexus 6,
    +-    then click <strong>Next</strong>.
    ++  <li>In the <b>Your Virtual Devices</b> screen, click <strong>Create Virtual Device</strong>.</li>
    ++  <li>In the <b>Select Hardware</b> screen, select a phone device, such as Nexus 6,
    ++    and then click <strong>Next</strong>.
    +   </li>
    +-  <li>In the Select Image page, choose the desired system image for the AVD and
    ++  <li>In the <b>System Image</b> screen, choose the desired system image for the AVD and
    +     click <strong>Next</strong>.
    ++    <p>If you don't have a particular system image installed,
    ++    you can get it by clicking the <b>download</b> link.</p>
    +   </li>
    +   <li>Verify the configuration settings (for your first AVD, leave all the
    +     settings as they are), and then click <strong>Finish</strong>.
    +diff --git a/docs/html/training/basics/firstapp/starting-activity.jd b/docs/html/training/basics/firstapp/starting-activity.jd
    +index ebf42cb..4385d13 100644
    +--- a/docs/html/training/basics/firstapp/starting-activity.jd
    ++++ b/docs/html/training/basics/firstapp/starting-activity.jd
    +@@ -38,7 +38,7 @@ starts a new activity when the user clicks the Send button.</p>
    + <h2 id="RespondToButton">Respond to the Send Button</h2>
    + 
    + <ol>
    +-  <li>In the file <code>res/layout/activity_main.xml</code>, add the
    ++  <li>In the file <b>res > layout > activity_main.xml</b>, add the
    +     <a href="{@docRoot}reference/android/view/View.html#attr_android:onClick">{@code android:onClick}</a>
    +     attribute to the {@link android.widget.Button &lt;Button&gt;} element as
    +     shown below:
    +@@ -52,7 +52,7 @@ starts a new activity when the user clicks the Send button.</p>
    +       method in your activity whenever a user clicks on the button.</p>
    +   </li>
    + 
    +-  <li>In the file <code>java/com.example.myfirstapp/MainActivity.java</code>,
    ++  <li>In the file <b>java > com.example.myfirstapp > MainActivity.java</b>,
    +     add the <code>sendMessage()</code> method stub as shown below:
    + 
    +     <pre>public class MainActivity extends AppCompatActivity {
    +@@ -85,7 +85,9 @@ starts a new activity when the user clicks the Send button.</p>
    + <p>Next, you’ll fill in this method to read the contents of the text field and deliver that text to
    + another activity.</p>
    + 
    ++
    + <h2 id="BuildIntent">Build an Intent</h2>
    ++
    + <p>An {@link android.content.Intent} is an object that provides runtime binding
    +   between separate components (such as two activities). The
    +   {@link android.content.Intent} represents an app’s "intent to do something."
    +@@ -113,13 +115,22 @@ another activity.</p>
    +     }
    + }</pre>
    + 
    +-<p class="note"><strong>Note: </strong>Android Studio will display
    +-  <code>Cannot resolve symbol</code> errors because the code references classes
    +-  like {@link android.content.Intent} and {@link android.widget.EditText}
    +-  that have not been imported. To import these classes, you can either 1)
    +-  use Android Studio's "import class" functionality by pressing Alt + Enter
    +-  (Option + Return on Mac) or 2) manually add import statements at the top of
    +-  the file.</p>
    ++<p>Android Studio will display <b>Cannot
    ++resolve symbol</b> errors because this code references classes that are not
    ++imported. You can solve some of these with Android Studio's "import class"
    ++functionality by pressing Alt + Enter (or Option + Return on Mac).
    ++Your imports should end up as the following:</p>
    ++<pre>
    ++import android.content.Intent;
    ++import android.support.v7.app.AppCompatActivity;
    ++import android.os.Bundle;
    ++import android.view.View;
    ++import android.widget.EditText;
    ++</pre>
    ++
    ++<p>An error remains for <code>DisplayMessageActivity</code>, but that's okay;
    ++you'll fix that in the next section.
    ++
    + 
    + <p>There’s a lot going on in <code>sendMessage()</code>, so let’s explain
    +   what's going on.</p>
    +@@ -150,6 +161,7 @@ another activity.</p>
    +   method starts an instance of the <code>DisplayMessageActivity</code> specified
    +   by the {@link android.content.Intent}. Now you need to create the class.</p>
    + 
    ++
    + <h2 id="CreateActivity">Create the Second Activity</h2>
    + 
    + <ol>
    +@@ -169,7 +181,8 @@ another activity.</p>
    +   <li>Creates the corresponding layout file <code>activity_display_message.xml</code>
    +     </li>
    +   <li>Adds the required
    +-    <a href="{@docRoot}guide/topics/manifest/activity-element.html">&lt;activity&gt;</a>
    ++    <a href="{@docRoot}guide/topics/manifest/activity-element.html"
    ++    ><code>&lt;activity&gt;</code></a>
    +     element in <code>AndroidManifest.xml</code>.
    + </ul>
    + 
    +@@ -199,7 +212,16 @@ protected void onCreate(Bundle savedInstanceState) {
    +    layout.addView(textView);
    + }</pre>
    +   </li>
    +-  <li>Press Alt + Enter (option + return on Mac) to import missing classes.</li>
    ++  <li>Press Alt + Enter (or Option + Return on Mac) to import missing classes.
    ++  Your imports should end up as the following:
    ++<pre>
    ++import android.content.Intent;
    ++import android.support.v7.app.AppCompatActivity;
    ++import android.os.Bundle;
    ++import android.view.ViewGroup;
    ++import android.widget.TextView;
    ++</pre>
    ++</li>
    + </ol>
    + 
    + <p>There’s a lot going on here, so let’s explain:</p>
    +diff --git a/docs/html/training/basics/network-ops/data-saver.jd b/docs/html/training/basics/network-ops/data-saver.jd
    +index 75b7264..babf7c6 100644
    +--- a/docs/html/training/basics/network-ops/data-saver.jd
    ++++ b/docs/html/training/basics/network-ops/data-saver.jd
    +@@ -45,7 +45,7 @@ next.link=xml.html
    + </p>
    + 
    + <p>
    +-  The N Developer Preview extends the {@link android.net.ConnectivityManager}
    ++  Android 7.0 (API level 24) extends the {@link android.net.ConnectivityManager}
    +   API to provide apps with a way to <a href="#status">retrieve the user’s Data
    +   Saver preferences</a> and <a href="#monitor-changes">monitor preference
    +   changes</a>. It is considered good practice for apps to check whether the
    +@@ -58,7 +58,7 @@ next.link=xml.html
    + </h2>
    + 
    + <p>
    +-  In the N Developer Preview, apps can use the {@link
    ++  In Android 7.0 (API level 24), apps can use the {@link
    +   android.net.ConnectivityManager} API to determine what data usage
    +   restrictions are being applied. The {@code getRestrictBackgroundStatus()}
    +   method returns one of the following values:
    +diff --git a/docs/html/training/best-performance.jd b/docs/html/training/best-performance.jd
    +index 8ea6fd5..bb88e99 100644
    +--- a/docs/html/training/best-performance.jd
    ++++ b/docs/html/training/best-performance.jd
    +@@ -5,4 +5,9 @@ page.trainingcourse=true
    + 
    + 
    + <p>These classes and articles help you build an app that's smooth, responsive,
    +-and uses as little battery as possible.</p>
    +\ No newline at end of file
    ++and uses as little battery as possible.</p>
    ++
    ++<p>Along with this section, you can find additional information about optimizing
    ++your app in the <a href="/topic/performance/index.html">Performance and
    ++Power</a> section.</p>
    ++
    +diff --git a/docs/html/training/camera/videobasics.jd b/docs/html/training/camera/videobasics.jd
    +index 6da239a..b20cfef 100644
    +--- a/docs/html/training/camera/videobasics.jd
    ++++ b/docs/html/training/camera/videobasics.jd
    +@@ -108,7 +108,7 @@ retrieves this video and displays it in a {@link android.widget.VideoView}.</p>
    + 
    + <pre>
    + &#64;Override
    +-protected void onActivityResult(int requestCode, int resultCode, Intent data) {
    ++protected void onActivityResult(int requestCode, int resultCode, Intent intent) {
    +     if (requestCode == REQUEST_VIDEO_CAPTURE && resultCode == RESULT_OK) {
    +         Uri videoUri = intent.getData();
    +         mVideoView.setVideoURI(videoUri);
    +diff --git a/docs/html/training/constraint-layout/images/alignment-constraint-offset_2x.png b/docs/html/training/constraint-layout/images/alignment-constraint-offset_2x.png
    +new file mode 100644
    +index 0000000..1e4867e
    +Binary files /dev/null and b/docs/html/training/constraint-layout/images/alignment-constraint-offset_2x.png differ
    +diff --git a/docs/html/training/constraint-layout/images/alignment-constraint_2x.png b/docs/html/training/constraint-layout/images/alignment-constraint_2x.png
    +new file mode 100644
    +index 0000000..afe7d4a
    +Binary files /dev/null and b/docs/html/training/constraint-layout/images/alignment-constraint_2x.png differ
    +diff --git a/docs/html/training/constraint-layout/images/baseline-constraint_2x.png b/docs/html/training/constraint-layout/images/baseline-constraint_2x.png
    +new file mode 100644
    +index 0000000..dfc3522
    +Binary files /dev/null and b/docs/html/training/constraint-layout/images/baseline-constraint_2x.png differ
    +diff --git a/docs/html/training/constraint-layout/images/constraint-fail-fixed_2x.png b/docs/html/training/constraint-layout/images/constraint-fail-fixed_2x.png
    +new file mode 100644
    +index 0000000..be9d54f
    +Binary files /dev/null and b/docs/html/training/constraint-layout/images/constraint-fail-fixed_2x.png differ
    +diff --git a/docs/html/training/constraint-layout/images/constraint-fail_2x.png b/docs/html/training/constraint-layout/images/constraint-fail_2x.png
    +new file mode 100644
    +index 0000000..3f28ef7
    +Binary files /dev/null and b/docs/html/training/constraint-layout/images/constraint-fail_2x.png differ
    +diff --git a/docs/html/training/constraint-layout/images/layout-editor-convert-to-constraint_2x.png b/docs/html/training/constraint-layout/images/layout-editor-convert-to-constraint_2x.png
    +new file mode 100644
    +index 0000000..ace31a6
    +Binary files /dev/null and b/docs/html/training/constraint-layout/images/layout-editor-convert-to-constraint_2x.png differ
    +diff --git a/docs/html/training/constraint-layout/images/layout-editor-margin-callout_2-2_2x.png b/docs/html/training/constraint-layout/images/layout-editor-margin-callout_2-2_2x.png
    +new file mode 100644
    +index 0000000..0768022
    +Binary files /dev/null and b/docs/html/training/constraint-layout/images/layout-editor-margin-callout_2-2_2x.png differ
    +diff --git a/docs/html/training/constraint-layout/images/layout-editor-properties-callouts_2-2_2x.png b/docs/html/training/constraint-layout/images/layout-editor-properties-callouts_2-2_2x.png
    +new file mode 100644
    +index 0000000..b4ffb2c
    +Binary files /dev/null and b/docs/html/training/constraint-layout/images/layout-editor-properties-callouts_2-2_2x.png differ
    +diff --git a/docs/html/training/constraint-layout/images/layout-editor_2-2_2x.png b/docs/html/training/constraint-layout/images/layout-editor_2-2_2x.png
    +new file mode 100644
    +index 0000000..72a4e40
    +Binary files /dev/null and b/docs/html/training/constraint-layout/images/layout-editor_2-2_2x.png differ
    +diff --git a/docs/html/training/constraint-layout/images/parent-constraint_2x.png b/docs/html/training/constraint-layout/images/parent-constraint_2x.png
    +new file mode 100644
    +index 0000000..0414f1d
    +Binary files /dev/null and b/docs/html/training/constraint-layout/images/parent-constraint_2x.png differ
    +diff --git a/docs/html/training/constraint-layout/images/position-constraint_2x.png b/docs/html/training/constraint-layout/images/position-constraint_2x.png
    +new file mode 100644
    +index 0000000..9f93e72
    +Binary files /dev/null and b/docs/html/training/constraint-layout/images/position-constraint_2x.png differ
    +diff --git a/docs/html/training/constraint-layout/images/thumbnail-add-layout-guideline_2-2.png b/docs/html/training/constraint-layout/images/thumbnail-add-layout-guideline_2-2.png
    +new file mode 100644
    +index 0000000..f863e5f
    +Binary files /dev/null and b/docs/html/training/constraint-layout/images/thumbnail-add-layout-guideline_2-2.png differ
    +diff --git a/docs/html/training/constraint-layout/images/thumbnail-adjust-constraint-bias.png b/docs/html/training/constraint-layout/images/thumbnail-adjust-constraint-bias.png
    +new file mode 100644
    +index 0000000..d61e9b2
    +Binary files /dev/null and b/docs/html/training/constraint-layout/images/thumbnail-adjust-constraint-bias.png differ
    +diff --git a/docs/html/training/constraint-layout/images/thumbnail-studio-constraint-first.png b/docs/html/training/constraint-layout/images/thumbnail-studio-constraint-first.png
    +new file mode 100644
    +index 0000000..9747102
    +Binary files /dev/null and b/docs/html/training/constraint-layout/images/thumbnail-studio-constraint-first.png differ
    +diff --git a/docs/html/training/constraint-layout/images/thumbnail-studio-constraint-second.png b/docs/html/training/constraint-layout/images/thumbnail-studio-constraint-second.png
    +new file mode 100644
    +index 0000000..940b8495
    +Binary files /dev/null and b/docs/html/training/constraint-layout/images/thumbnail-studio-constraint-second.png differ
    +diff --git a/docs/html/training/constraint-layout/index.html b/docs/html/training/constraint-layout/index.html
    +new file mode 100644
    +index 0000000..62eaf15
    +--- /dev/null
    ++++ b/docs/html/training/constraint-layout/index.html
    +@@ -0,0 +1,498 @@
    ++<html devsite>
    ++<head>
    ++  <title>Build a Responsive UI with ConstraintLayout</title>
    ++  <meta name="book_path" value="/training/_book.yaml" />
    ++  <meta name="top_category" value="develop" />
    ++  <meta name="subcategory" value="training" />
    ++</head>
    ++<body>
    ++
    ++<div id="tb-wrapper">
    ++<div id="tb">
    ++  <h2>In this document</h2>
    ++  <ol>
    ++    <li><a href="#constraints-overview">Constraints overview</a></li>
    ++    <li><a href="#add-constraintlayout-to-your-project">Add ConstraintLayout to your project</a></li>
    ++    <li><a href="#add-a-constraint">Add a constraint</a></li>
    ++    <li><a href="#use-autoconnect-and-infer-constraints">Use Autoconnect and Infer Constraints</a></li>
    ++    <li><a href="#adjust-the-view-size">Adjust the view size</a></li>
    ++    <li><a href="#adjust-the-constraint-bias">Adjust the constraint bias</a></li>
    ++    <li><a href="#adjust-the-view-margins">Adjust the view margins</a></li>
    ++  </ol>
    ++</div>
    ++</div>
    ++
    ++
    ++<p><code>ConstraintLayout</code> allows you to create large and complex layouts with a flat view
    ++hierarchy (no nested view groups). It's similar to <code>RelativeLayout</code> in that all views are
    ++layed out according to relationships between sibling views and the parent layout, but it's more
    ++flexible than <code>RelativeLayout</code> and easier to use with Android Studio's Layout Editor.
    ++</p>
    ++
    ++<p>Everything you can do with <code>ConstraintLayout</code> is available directly from the Layout Editor's visual
    ++tools, because the layout API and the Layout Editor were specially built for each other. So you can
    ++build your layout with <code>ConstraintLayout</code> entirely by drag-and-dropping instead of editing the XML.
    ++</p>
    ++
    ++<img src="/training/constraint-layout/images/layout-editor_2-2_2x.png" alt=""
    ++  width="640"/>
    ++<p class="img-caption"><b>Figure 1.</b> A <code>ConstraintLayout</code> in the Layout Editor</p>
    ++
    ++
    ++<p>
    ++<code>ConstraintLayout</code> is available in an API library that's compatible with Android
    ++2.3 (API level 9) and higher, and the new layout editor is available in Android
    ++Studio 2.2 and higher.
    ++</p>
    ++
    ++<p>
    ++This page provides a guide to building a layout with <code>ConstraintLayout</code> in Android
    ++Studio. If you'd like more information about the Layout Editor itself, see the
    ++Android Studio guide to <a href="/studio/write/layout-editor.html">Build a UI with
    ++Layout Editor</a>.
    ++</p>
    ++
    ++
    ++<h2 id="constraints-overview">Constraints overview</h2>
    ++<p>
    ++To define a view's position in <code>ConstraintLayout</code>, you must add two
    ++or more <em>constraints</em> for the view. Each constraint represents a connection or
    ++alignment to another view, the parent layout, or an invisible guideline. Each
    ++constraint defines the view's position along either the
    ++vertical or horizontal axis; so each view must have a minimum of one constraint for each
    ++axis, but often more are necessary.
    ++</p>
    ++
    ++<p>
    ++When you drop a view into the Layout Editor, it stays where you leave it even if
    ++it has no constraints. However, this is only to make editing easier; if a view has
    ++no constraints when you run your layout on a device, it is drawn at
    ++position [0,0] (the top-left corner).</p>
    ++
    ++<p>In figure 2, the layout looks good in the
    ++editor, but there's no vertical constraint on <code>TextView B</code>. When this
    ++layout draws on a device, <code>TextView B</code> horizontally aligns with the left and
    ++right edges of the <code>ImageView</code>, but appears at the top of the screen because
    ++it has no vertical constraint.
    ++</p>
    ++
    ++<div class="cols">
    ++<div class="col-1of2">
    ++<img src="/training/constraint-layout/images/constraint-fail_2x.png" width="100%" alt="" />
    ++<p class="img-caption"><strong>Figure 2.</strong> <code>TextView B</code> is missing a
    ++vertical constraint</p>
    ++</div>
    ++<div class="col-1of2">
    ++<img src="/training/constraint-layout/images/constraint-fail-fixed_2x.png" width="100%" alt="" />
    ++<p class="img-caption"><strong>Figure 3.</strong> <code>TextView B</code> is now vertically
    ++constrained to the <code>ImageView</code></p>
    ++</div>
    ++</div>
    ++
    ++<p>
    ++Although a missing constraint won't cause a compilation error, the Layout Editor
    ++indicates missing constraints as an error in the toolbar. To view the errors and
    ++other warnings, click <strong>Show Warnings and Errors</strong>
    ++<img src="/studio/images/buttons/layout-editor-errors.png" class="inline-icon" alt="" />.
    ++To help you avoid missing constraints, the Layout Editor can automatically add
    ++constraints for you with the <a
    ++href="#use-autoconnect-and-infer-constraints">Autoconnect and infer
    ++constraints</a> features.
    ++</p>
    ++
    ++
    ++<h2 id="add-constraintlayout-to-your-project">Add ConstraintLayout to your project</h2>
    ++<p>
    ++To use <code>ConstraintLayout</code> in your project, proceed as follows:
    ++</p>
    ++
    ++<ol>
    ++<li>Ensure you have the latest Constraint Layout library:
    ++<ol>
    ++ <li>Click <strong>Tools > Android > SDK Manager</strong>.
    ++ <li>Click the <strong>SDK Tools</strong> tab.
    ++ <li>Expand <strong>Support Repository</strong> and then check
    ++<b>ConstraintLayout for Android</b> and <b>Solver for ConstraintLayout</b>.
    ++Check <b>Show Package Details</b> and take note of the version you're downloading
    ++(you'll need this below).</p>
    ++ <li>Click <strong>OK</strong>.
    ++<li>Add the ConstraintLayout library as a dependency in your module-level
    ++  <code>build.gradle</code> file:
    ++<pre>
    ++dependencies {
    ++    compile 'com.android.support.constraint:constraint-layout:1.0.0-alpha8'
    ++}
    ++</pre>
    ++  <p>The library version you download may be higher, so be sure the value you specify
    ++  here matches the version from step 3.</p>
    ++</li>
    ++<li>In the toolbar or sync notification, click <strong>Sync Project with Gradle
    ++Files</strong>.</li>
    ++</ol>
    ++</li>
    ++</ol>
    ++
    ++<p>Now you're ready to build your layout with <code>ConstraintLayout</code>.</p>
    ++
    ++<h3 id="convert">Convert a layout</h3>
    ++
    ++<div class="figure" style="width:415px">
    ++<img src="/training/constraint-layout/images/layout-editor-convert-to-constraint_2x.png"
    ++  width="415" alt="" />
    ++<p class="img-caption">
    ++  <b>Figure 4.</b> The menu to convert a layout to <code>ConstraintLayout</code></p>
    ++</div>
    ++
    ++<p>To convert an existing layout to a constraint layout, follow these steps:</p>
    ++<ol>
    ++<li>Open your layout in Android Studio and click the <strong>Design</strong> tab
    ++at the bottom of the editor window.
    ++<li>In the <strong>Component Tree</strong> window, right-click the layout and
    ++click <strong>Convert <em>layout</em> to ConstraintLayout</strong>.</li>
    ++</ol>
    ++
    ++<h3 id="createNew">Create a new layout</h3>
    ++
    ++<p>To start a new constraint layout file, follow these steps:</p>
    ++<ol>
    ++<li>Click anywhere in the <strong>Project</strong> window and then select
    ++<strong>File > New > XML > Layout XML</strong>.
    ++<li>Enter a name for the layout file and enter
    ++"android.support.constraint.ConstraintLayout" for the <b>Root Tag</b>.
    ++<li>Click <strong>Finish</strong>.</li>
    ++</ol>
    ++
    ++
    ++<h2 id="add-a-constraint">Add a constraint</h2>
    ++
    ++<p>Start by dragging a view from the <b>Palette</b> window into the editor.
    ++When you add a view in a <code>ConstraintLayout</code>, it displays a bounding box with square
    ++resizing handles on each corner and circular constraint handles on each side.
    ++</p>
    ++
    ++
    ++<div class="figure" style="width:460px">
    ++<div class="video-wrapper">
    ++<video controls poster="/training/constraint-layout/images/thumbnail-studio-constraint-first.png"
    ++  onclick="this.play()" width="460">
    ++  <source src="https://storage.googleapis.com/androiddevelopers/videos/studio/studio-constraint-first.mp4" type="video/mp4">
    ++  <img src="/training/constraint-layout/images/thumbnail-studio-constraint-first" alt="" />
    ++</video>
    ++</div>
    ++<p class="img-caption">
    ++<strong>Video 1. </strong>The left side of a view is constrained to the left side of the parent
    ++</p>
    ++</div>
    ++
    ++<p>
    ++Click the view to select it. Then click-and-hold one of the
    ++constraint handles and drag the line to an available anchor point (the edge of
    ++another view, the edge of the layout, or a guideline). When you release, the
    ++constraint is made, with <a href="#adjust-the-view-margins">a default margin</a>
    ++separating the two views.
    ++</p>
    ++
    ++<p>When creating constraints, remember the following rules:</p>
    ++
    ++<ul>
    ++<li>Every view must have at least two constraints: one horizontal and one
    ++vertical.
    ++<li>You can create constraints only between a constraint handle and an anchor
    ++point that share the same plane. So a vertical plane (the left and right sides)
    ++of a view can be constrained only to another vertical plane; and baselines can
    ++constrain only to other baselines.
    ++<li>Each constraint handle can be used for just one constraint, but you can
    ++create multiple constraints (from different views) to the same anchor
    ++point.</li>
    ++</ul>
    ++
    ++
    ++
    ++<div class="figure" style="width:460px">
    ++<div class="video-wrapper">
    ++<video controls poster="/training/constraint-layout/images/thumbnail-studio-constraint-second.png"
    ++  onclick="this.play()" width="460">
    ++  <source src="https://storage.googleapis.com/androiddevelopers/videos/studio/studio-constraint-second.mp4" type="video/mp4">
    ++  <img src="/training/constraint-layout/images/thumbnail-studio-constraint-second.png" alt="" />
    ++</video>
    ++</div>
    ++<p class="img-caption">
    ++<strong>Video 2. </strong>Adding a constraint that opposes an existing one
    ++</p>
    ++</div>
    ++
    ++
    ++
    ++<p>
    ++To remove a constraint, select the view and then click the constraint handle.
    ++</p>
    ++
    ++<p>If you add opposing constraints on a view, the constraint lines become squiggly
    ++like a spring to indicate the opposing forces, as shown in video 2. The effect
    ++is most visible when the view size is set to "fixed" or "wrap content," in which
    ++case the view is centered between the constraints. If you instead
    ++want the view to stretch its size to meet the constraints, <a
    ++href="#adjust-the-view-size">switch the size to "any size"</a>; or if you want
    ++to keep the current size but move the view so that it is not centered, <a
    ++href="#adjust-the-constraint-bias">adjust the constraint bias</a>.
    ++</p>
    ++
    ++
    ++
    ++<p>
    ++There are many ways to constrain a view, but the following constraint types
    ++provide the basic building blocks.
    ++</p>
    ++
    ++
    ++
    ++
    ++<h3>Parent constraint</h3>
    ++<div class="cols">
    ++<div class="col-2of3">
    ++  <p>
    ++  Connect the side of a view to the corresponding edge of the layout.
    ++  <p>
    ++  In figure 5, the left side of a view is connected to the left edge of the
    ++  parent layout.
    ++  <p>
    ++</div>
    ++<div class="col-1of3">
    ++  <img src="/training/constraint-layout/images/parent-constraint_2x.png" width="100%" alt="">
    ++  <p class="img-caption"><strong>Figure 5. </strong>A horizontal constraint to the parent</p>
    ++</div>
    ++</div>
    ++
    ++
    ++<h3>Position constraint</h3>
    ++<div class="cols">
    ++<div class="col-2of3">
    ++<p>Define the order of appearance for two views, either vertically or horizontally.</p>
    ++<p>In figure 6, a <code>Button</code> is constrained below an <code>ImageView</code> with a 24dp
    ++margin.</p>
    ++</div>
    ++<div class="col-1of3">
    ++  <img src="/training/constraint-layout/images/position-constraint_2x.png" width="100%" alt="">
    ++  <p class="img-caption"><strong>Figure 6.</strong> A vertical position constraint</p>
    ++</div>
    ++</div>
    ++
    ++
    ++
    ++<h3>Alignment constraint</h3>
    ++<div class="cols">
    ++<div class="col-1of3">
    ++<p>Align the edge of a view to the same edge of another view.<p>
    ++<p>In figure 7, the left side of a <code>Button</code> is aligned to the left side of an
    ++<code>ImageView</code>.</p>
    ++<p>You can offset the alignment by dragging the view
    ++inward from the constraint. For example, figure 8 shows the same
    ++<code>Button</code> with a 24dp offset alignment.
    ++The offset is defined by the constrained view's margin.</p>
    ++</div>
    ++<div class="col-1of3">
    ++  <img src="/training/constraint-layout/images/alignment-constraint_2x.png" width="100%" alt="">
    ++  <p class="img-caption"><strong>Figure 7.</strong> A horizontal alignment constraint</p>
    ++</div>
    ++<div class="col-1of3">
    ++  <img src="/training/constraint-layout/images/alignment-constraint-offset_2x.png" width="100%"
    ++    alt="">
    ++  <p class="img-caption"><strong>Figure 8.</strong> An offset horizontal alignment constraint</p>
    ++</div>
    ++</div>
    ++
    ++
    ++<h3>Baseline alignment constraint</h3>
    ++<div class="cols">
    ++<div class="col-2of3">
    ++<p>Align the text baseline of a view to the text baseline of another view.</p>
    ++<p>In figure 9, the first line of a <code>TextView</code> is aligned with the text in a
    ++<code>Button</code>.</p>
    ++<p>To create a baseline constraint, hover your mouse over the baseline handle for
    ++two seconds until the handle blinks white. Then click and drag the line to
    ++another baseline.</p>
    ++</div>
    ++<div class="col-1of3">
    ++  <img src="/training/constraint-layout/images/baseline-constraint_2x.png" width="100%" alt="">
    ++  <p class="img-caption"><strong>Figure 9.</strong> A baseline alignment constraint</p>
    ++</div>
    ++</div>
    ++
    ++
    ++
    ++
    ++
    ++<h3 id="constrain-to-a-guideline">Constrain to a guideline</h3>
    ++<div class="cols">
    ++<div class="col-1of2">
    ++
    ++<p>
    ++You can add a vertical or horizontal guideline to which you can attach
    ++constraints. You can position the guideline within the layout based on either dp
    ++units or percent, relative to the layout's edge.
    ++</p>
    ++
    ++<p>
    ++To create a guideline, click <strong>Guidelines</strong>
    ++<img src="/studio/images/buttons/layout-editor-guidelines.png" class="inline-icon" alt="" />
    ++in the toolbar, and then click either <strong>Add Vertical Guideline</strong>
    ++or <strong>Add Horizontal Guideline</strong>.
    ++</p>
    ++
    ++<p>
    ++Click the circle at the edge of the guideline to toggle the measurements used to
    ++position the guideline (either percent or dp units from the layout's edge).
    ++</p>
    ++
    ++<p>
    ++Guidelines are not visible to your users.
    ++</p>
    ++</div>
    ++
    ++<div class="col-1of2">
    ++  <div class="video-wrapper">
    ++  <video controls poster="/training/constraint-layout/images/thumbnail-add-layout-guideline_2-2.png"
    ++    onclick="this.play()" width="100%">
    ++    <source src="https://storage.googleapis.com/androiddevelopers/videos/studio/add-layout-guideline_2-2.mp4" type="video/mp4">
    ++    <img src="/training/constraint-layout/images/thumbnail-add-layout-guideline_2-2.png" alt="" />
    ++  </video>
    ++  </div>
    ++  <p class="img-caption"><strong>Video 3.</strong> Adding a constraint to a guideline</p>
    ++</div>
    ++</div>
    ++
    ++
    ++<h2 id="use-autoconnect-and-infer-constraints">Use Autoconnect and Infer Constraints</h2>
    ++
    ++<div class="figure" style="width:460px">
    ++<div class="video-wrapper">
    ++<video controls poster=""
    ++  onclick="this.play()" width="460">
    ++  <source src="https://storage.googleapis.com/androiddevelopers/videos/studio/constraint-autoconnect_2-2.mp4" type="video/mp4">
    ++</video>
    ++</div>
    ++<p class="img-caption"><b>Video 4.</b> Adding a view with Autoconnect enabled</p>
    ++</div>
    ++
    ++<p>
    ++Autoconnect is a persistent mode that automatically creates two or more
    ++constraints for each view you add to the layout. Autoconnect is disabled by
    ++default. You can enable it by clicking <strong>Turn on Autoconnect</strong>
    ++<img src="/studio/images/buttons/layout-editor-autoconnect-on.png" class="inline-icon" alt="" />
    ++in the Layout Editor toolbar.
    ++</p>
    ++
    ++<p>While enabled, Autoconnect creates constraints for each view as you add them; it does not create
    ++constraints for existing views in the layout. If you drag a view once the constraints are made, the
    ++constraints do not change (though the margins do), so you must delete the constraints if you want to
    ++significantly reposition the view.</p>
    ++
    ++<p>Alternatively, you can click  <strong>Infer Constraints</strong>
    ++<img src="/studio/images/buttons/layout-editor-infer.png" class="inline-icon" alt="" />
    ++to create constraints for all views in the layout.
    ++</p>
    ++
    ++<p>Infer Constraints is a one-time action that scans the entire layout to determine the most
    ++effective set of constraints for all views, so it may create constraints between elements that are
    ++far from each other. Autoconnect, however, creates constraints only for the view you are adding, and
    ++it creates constraints to only the nearest elements. In either case, you can always modify a
    ++constraint by clicking the constraint handle to delete it, and then create a new constraint.</p>
    ++
    ++
    ++<h2 id="adjust-the-view-size">Adjust the view size</h2>
    ++
    ++<p>
    ++You can use the handles on each corner of the view to resize it, but doing so
    ++hard codes the width and height values, which you should avoid for most views
    ++because hard-coded view sizes cannot adapt to different content and screen
    ++sizes. To select from one of the dynamic sizing modes or to define more specific
    ++dimensions, click a view and open the <strong>Properties</strong>
    ++<img src="/studio/images/buttons/window-properties.png" class="inline-icon" alt="" />
    ++window on the right side of the editor. At the top of the window is the view
    ++inspector, as shown in figure 10.
    ++</p>
    ++<div class="figure" style="width:287px" >
    ++<img src="/training/constraint-layout/images/layout-editor-properties-callouts_2-2_2x.png" alt=""
    ++  width="287" />
    ++<p class="img-caption"><strong>Figure 10.</strong> The <b>Properties</b> window includes controls for
    ++<strong>(1)</strong> view size, <strong>(2)</strong> margins, and
    ++<strong>(3)</strong> constraint bias.</p>
    ++</div>
    ++
    ++<p>
    ++The grey square represents the selected view. The symbols inside the square
    ++represent the height and width settings as follows:
    ++</p>
    ++
    ++<ul>
    ++<li>
    ++<img src="/studio/images/buttons/layout-width-wrap.png" class="inline-icon" alt="" />
    ++ <strong>Wrap Content</strong>: The view expands exactly as needed to fit its
    ++contents.
    ++<li>
    ++<img src="/studio/images/buttons/layout-width-match.png" class="inline-icon" alt="" />
    ++ <strong>Any Size</strong>: The view expands exactly as needed to match the
    ++constraints. The actual value is 0dp because the view has no desired dimensions, but
    ++it resizes as needed to meet the constraints. However, if the given dimension
    ++has only one constraint, then the view expands to fit its contents. Another way
    ++to think of it is "match constraints" (instead of <code>match_parent</code>) because it
    ++expands the view as much as possible after accounting for the limits of each
    ++constraint and its margins.
    ++<li>
    ++<img src="/studio/images/buttons/layout-width-fixed.png" class="inline-icon" alt="" />
    ++ <strong>Fixed</strong>: You specify the dimension in the text box below or by
    ++resizing the view in the editor.</li>
    ++</ul>
    ++
    ++<p>To toggle between these settings, click the symbols.</p>
    ++
    ++<p class="note"><strong>Note</strong>: You should not use <code>match_parent</code> for any view
    ++in a <code>ConstraintLayout</code>. Instead use "Any Size" (<code>0dp</code>).
    ++</p>
    ++
    ++
    ++<h2 id="adjust-the-constraint-bias">Adjust the constraint bias</h2>
    ++
    ++<p>When you add a constraint to both sides of a view (and the view size for the same dimension is
    ++either "fixed" or "wrap content"), the view becomes centered between the two anchor points by
    ++default. When a view is centered, the bias is 50%. You can adjust the bias by dragging the bias
    ++slider in the <b>Properties</b> window or by dragging the view, as shown in video 5.</p>
    ++
    ++<div class="video-wrapper" style="max-width:740px">
    ++<video controls poster="/training/constraint-layout/images/thumbnail-adjust-constraint-bias.png"
    ++  onclick="this.play();$(this.parentElement).addClass('playing');">
    ++  <source src="https://storage.googleapis.com/androiddevelopers/videos/studio/adjust-constraint-bias.mp4" type="video/mp4">
    ++  <img src="/training/constraint-layout/images/thumbnail-adjust-constraint-bias.png" alt="" />
    ++</video>
    ++</div>
    ++<p class="img-caption"><b>Video 5.</b> Adjusting the constraint bias</p>
    ++
    ++<p>If you instead want the view to stretch its size to meet the constraints, <a href="#adjust-the-
    ++view-size">switch the size to "any size"</a>.</p>
    ++
    ++
    ++<h2 id="adjust-the-view-margins">Adjust the view margins</h2>
    ++
    ++<p> To ensure that all your views are evenly spaced, click <strong>Margin</strong> <img
    ++src="/studio/images/buttons/layout-editor-margin.png" class="inline-icon" alt="" /> in the toolbar
    ++to select the default margin for each view that you add to the layout. The button changes to show
    ++your current margin selection. Any change you make to the default margin applies only to the views
    ++you add from then on. </p>
    ++
    ++
    ++<img src="/training/constraint-layout/images/layout-editor-margin-callout_2-2_2x.png"
    ++ alt="" width="232"/>
    ++<p class="img-caption"><strong>Figure 11.</strong> The toolbar's <b>Margin</b> button.
    ++Click to adjust the default margin.
    ++</p>
    ++
    ++<p> You can control the margin for each view in the <strong>Properties</strong> window by clicking
    ++the number on the line that represents each constraint (in figure 10, the margins are each set to
    ++16dp). </p>
    ++
    ++<p> All margins offered by the tool are factors of 8dp to help your views align to Material Design's
    ++<a href="https://material.google.com/layout/metrics-keylines.html">8dp square grid
    ++recommendations</a>. </p>
    ++
    ++</body>
    ++</html>
    +diff --git a/docs/html/training/contacts-provider/display-contact-badge.jd b/docs/html/training/contacts-provider/display-contact-badge.jd
    +index d286440..6c9616b 100644
    +--- a/docs/html/training/contacts-provider/display-contact-badge.jd
    ++++ b/docs/html/training/contacts-provider/display-contact-badge.jd
    +@@ -113,10 +113,10 @@ trainingnavtop=true
    + <p>
    +     For Android 3.0 (API level 11) and later, include the following columns in your projection:</p>
    + <ul>
    +-    <li>{@link android.provider.BaseColumns#_ID Contacts._ID}</li>
    +-    <li>{@link android.provider.ContactsContract.ContactsColumns#LOOKUP_KEY Contacts.LOOKUP_KEY}</li>
    ++    <li>{@link android.provider.ContactsContract.Contacts#_ID Contacts._ID}</li>
    ++    <li>{@link android.provider.ContactsContract.Contacts#LOOKUP_KEY Contacts.LOOKUP_KEY}</li>
    +     <li>
    +-        {@link android.provider.ContactsContract.ContactsColumns#PHOTO_THUMBNAIL_URI
    ++        {@link android.provider.ContactsContract.Contacts#PHOTO_THUMBNAIL_URI
    +         Contacts.PHOTO_THUMBNAIL_URI}
    +     </li>
    + </ul>
    +@@ -124,8 +124,8 @@ trainingnavtop=true
    +     For Android 2.3.3 (API level 10) and earlier, use the following columns:
    + </p>
    + <ul>
    +-    <li>{@link android.provider.BaseColumns#_ID Contacts._ID}</li>
    +-    <li>{@link android.provider.ContactsContract.ContactsColumns#LOOKUP_KEY Contacts.LOOKUP_KEY}</li>
    ++    <li>{@link android.provider.ContactsContract.Contacts#_ID Contacts._ID}</li>
    ++    <li>{@link android.provider.ContactsContract.Contacts#LOOKUP_KEY Contacts.LOOKUP_KEY}</li>
    + </ul>
    + <p>
    +     The remainder of this lesson assumes that you've already loaded a
    +@@ -187,14 +187,14 @@ trainingnavtop=true
    + </p>
    + <p class="note">
    +     <strong>Note:</strong> The
    +-    {@link android.provider.ContactsContract.ContactsColumns#PHOTO_THUMBNAIL_URI} column isn't available
    ++    {@link android.provider.ContactsContract.Contacts#PHOTO_THUMBNAIL_URI} column isn't available
    +     in platform versions prior to 3.0. For those versions, you must retrieve the URI
    +     from the {@link android.provider.ContactsContract.Contacts.Photo Contacts.Photo} subtable.
    + </p>
    + <p>
    +     First, set up variables for accessing the {@link android.database.Cursor} containing the
    +-    {@link android.provider.BaseColumns#_ID Contacts._ID} and
    +-    {@link android.provider.ContactsContract.ContactsColumns#LOOKUP_KEY Contacts.LOOKUP_KEY} columns, as
    ++    {@link android.provider.ContactsContract.Contacts#_ID Contacts._ID} and
    ++    {@link android.provider.ContactsContract.Contacts#LOOKUP_KEY Contacts.LOOKUP_KEY} columns, as
    +     described previously:
    + </p>
    + <pre>
    +diff --git a/docs/html/training/contacts-provider/modify-data.jd b/docs/html/training/contacts-provider/modify-data.jd
    +index e993c56..64853ef 100644
    +--- a/docs/html/training/contacts-provider/modify-data.jd
    ++++ b/docs/html/training/contacts-provider/modify-data.jd
    +@@ -196,8 +196,8 @@ intent.putExtra(Intents.Insert.EMAIL, mEmailAddress.getText())
    +     Contacts.CONTENT_LOOKUP_URI}, call
    +     {@link android.provider.ContactsContract.Contacts#getLookupUri
    +     Contacts.getLookupUri(id, lookupkey)} with the contact's
    +-    {@link android.provider.BaseColumns#_ID Contacts._ID} and
    +-    {@link android.provider.ContactsContract.ContactsColumns#LOOKUP_KEY Contacts.LOOKUP_KEY} values as
    ++    {@link android.provider.ContactsContract.Contacts#_ID Contacts._ID} and
    ++    {@link android.provider.ContactsContract.Contacts#LOOKUP_KEY Contacts.LOOKUP_KEY} values as
    +     arguments.
    + </p>
    + <p>
    +diff --git a/docs/html/training/contacts-provider/retrieve-details.jd b/docs/html/training/contacts-provider/retrieve-details.jd
    +index a463b75..0de3b67 100644
    +--- a/docs/html/training/contacts-provider/retrieve-details.jd
    ++++ b/docs/html/training/contacts-provider/retrieve-details.jd
    +@@ -55,11 +55,11 @@ trainingnavtop=true
    + <p>
    +     To retrieve all the details for a contact, search the
    +     {@link android.provider.ContactsContract.Data} table for any rows that contain the contact's
    +-    {@link android.provider.ContactsContract.ContactsColumns#LOOKUP_KEY}. This column is available in
    ++    {@link android.provider.ContactsContract.Data#LOOKUP_KEY}. This column is available in
    +     the {@link android.provider.ContactsContract.Data} table, because the Contacts
    +     Provider makes an implicit join between the {@link android.provider.ContactsContract.Contacts}
    +     table and the {@link android.provider.ContactsContract.Data} table. The
    +-    {@link android.provider.ContactsContract.ContactsColumns#LOOKUP_KEY} column is described
    ++    {@link android.provider.ContactsContract.Contacts#LOOKUP_KEY} column is described
    +     in more detail in the <a href="retrieve-names.html">Retrieving Contact Names</a> lesson.
    + </p>
    + <p class="note">
    +@@ -85,9 +85,9 @@ trainingnavtop=true
    +     the data is in different columns depending on the data type.
    +     To ensure you get all the possible columns for all possible data types, you need to add all the
    +     column names to your projection. Always retrieve
    +-    {@link android.provider.BaseColumns#_ID Data._ID} if you're binding the result
    ++    {@link android.provider.ContactsContract.Data#_ID Data._ID} if you're binding the result
    +     {@link android.database.Cursor} to a {@link android.widget.ListView}; otherwise, the binding
    +-    won't work. Also retrieve {@link android.provider.ContactsContract.DataColumns#MIMETYPE Data.MIMETYPE}
    ++    won't work. Also retrieve {@link android.provider.ContactsContract.Data#MIMETYPE Data.MIMETYPE}
    +     so you can identify the data type of each row you retrieve. For example:
    + </p>
    + <pre>
    +@@ -128,7 +128,7 @@ trainingnavtop=true
    + <p>
    +     Define a constant for your selection clause, an array to hold selection arguments, and a
    +     variable to hold the selection value. Use
    +-    the {@link android.provider.ContactsContract.ContactsColumns#LOOKUP_KEY Contacts.LOOKUP_KEY} column to
    ++    the {@link android.provider.ContactsContract.Contacts#LOOKUP_KEY Contacts.LOOKUP_KEY} column to
    +     find the contact. For example:
    + </p>
    + <pre>
    +@@ -153,7 +153,7 @@ trainingnavtop=true
    + <p>
    +     Define the sort order you want in the resulting {@link android.database.Cursor}. To
    +     keep all rows for a particular data type together, sort by
    +-    {@link android.provider.ContactsContract.DataColumns#MIMETYPE Data.MIMETYPE}. This query argument
    ++    {@link android.provider.ContactsContract.Data#MIMETYPE Data.MIMETYPE}. This query argument
    +     groups all email rows together, all phone rows together, and so forth. For example:
    + </p>
    + <pre>
    +@@ -299,7 +299,7 @@ public class DetailsFragment extends Fragment implements
    +     </dt>
    +     <dd>
    +         Modify the selection text to search for the
    +-        {@link android.provider.ContactsContract.DataColumns#MIMETYPE MIMETYPE} value that's specific to
    ++        {@link android.provider.ContactsContract.Data#MIMETYPE MIMETYPE} value that's specific to
    +         your data type.
    +     </dd>
    +     <dt>
    +@@ -307,7 +307,7 @@ public class DetailsFragment extends Fragment implements
    +     </dt>
    +     <dd>
    +         Since you're only selecting a single detail type, don't group the returned
    +-        {@link android.database.Cursor} by {@link android.provider.ContactsContract.DataColumns#MIMETYPE
    ++        {@link android.database.Cursor} by {@link android.provider.ContactsContract.Data#MIMETYPE
    +         Data.MIMETYPE}.
    +     </dd>
    + </dl>
    +@@ -344,9 +344,9 @@ public class DetailsFragment extends Fragment implements
    + <h3>Define selection criteria</h3>
    + <p>
    +     Define a search text expression that retrieves rows for a specific contact's
    +-    {@link android.provider.ContactsContract.ContactsColumns#LOOKUP_KEY} and the
    +-    {@link android.provider.ContactsContract.DataColumns#MIMETYPE Data.MIMETYPE} of the details you
    +-    want. Enclose the {@link android.provider.ContactsContract.DataColumns#MIMETYPE MIMETYPE} value in
    ++    {@link android.provider.ContactsContract.Data#LOOKUP_KEY} and the
    ++    {@link android.provider.ContactsContract.Data#MIMETYPE Data.MIMETYPE} of the details you
    ++    want. Enclose the {@link android.provider.ContactsContract.Data#MIMETYPE MIMETYPE} value in
    +     single quotes by concatenating a "<code>'</code>" (single-quote) character to the start and end
    +     of the constant; otherwise, the provider interprets the constant as a variable name rather
    +     than as a string value. You don't need to use a placeholder for this value, because you're
    +@@ -368,10 +368,10 @@ public class DetailsFragment extends Fragment implements
    + <h3>Define a sort order</h3>
    + <p>
    +     Define a sort order for the returned {@link android.database.Cursor}. Since you're retrieving a
    +-    specific data type, omit the sort on {@link android.provider.ContactsContract.DataColumns#MIMETYPE}.
    ++    specific data type, omit the sort on {@link android.provider.ContactsContract.Data#MIMETYPE}.
    +     Instead, if the type of detail data you're searching includes a subtype, sort on it.
    +     For example, for email data you can sort on
    +-    {@link android.provider.ContactsContract.CommonDataKinds.CommonColumns#TYPE Email.TYPE}:
    ++    {@link android.provider.ContactsContract.CommonDataKinds.Email#TYPE Email.TYPE}:
    + </p>
    + <pre>
    +     private static final String SORT_ORDER = Email.TYPE + " ASC ";
    +diff --git a/docs/html/training/contacts-provider/retrieve-names.jd b/docs/html/training/contacts-provider/retrieve-names.jd
    +index 7d70ceb..49d6e95 100755
    +--- a/docs/html/training/contacts-provider/retrieve-names.jd
    ++++ b/docs/html/training/contacts-provider/retrieve-names.jd
    +@@ -227,7 +227,7 @@ public class ContactsFragment extends Fragment implements
    + </pre>
    + <p class="note">
    +     <strong>Note:</strong> Since
    +-    {@link android.provider.ContactsContract.ContactNameColumns#DISPLAY_NAME_PRIMARY
    ++    {@link android.provider.ContactsContract.Contacts#DISPLAY_NAME_PRIMARY
    +     Contacts.DISPLAY_NAME_PRIMARY} requires Android 3.0 (API version 11) or later, setting your
    +     app's <code>minSdkVersion</code> to 10 or below generates an Android Lint warning in
    +     Android Studio. To turn off this warning, add the annotation
    +@@ -261,7 +261,7 @@ public class ContactsFragment extends Fragment implements
    +     that displays the contacts, you need to call {@link android.app.Activity#findViewById
    +     Activity.findViewById()} using the parent activity of the
    +     {@link android.support.v4.app.Fragment}. Use the {@link android.content.Context} of the
    +-    parent activity when you call {@link android.widget.AdapterView#setAdapter setAdapter()}.
    ++    parent activity when you call {@link android.widget.ListView#setAdapter setAdapter()}.
    +     For example:
    + </p>
    + <pre>
    +@@ -293,7 +293,7 @@ public class ContactsFragment extends Fragment implements
    + </p>
    + <p>
    +     To continue setting up the listener, bind it to the {@link android.widget.ListView} by
    +-    calling the method {@link android.widget.AdapterView#setOnItemClickListener
    ++    calling the method {@link android.widget.ListView#setOnItemClickListener
    +     setOnItemClickListener()} in {@link android.support.v4.app.Fragment#onActivityCreated
    +     onActivityCreated()}. For example:
    + </p>
    +@@ -318,15 +318,15 @@ public class ContactsFragment extends Fragment implements
    +     the {@link android.widget.ListView} displays the contact's display name,
    +     which contains the main form of the contact's name. In Android 3.0 (API version 11) and later,
    +     the name of this column is
    +-    {@link android.provider.ContactsContract.ContactNameColumns#DISPLAY_NAME_PRIMARY
    ++    {@link android.provider.ContactsContract.Contacts#DISPLAY_NAME_PRIMARY
    +     Contacts.DISPLAY_NAME_PRIMARY}; in versions previous to that, its name is
    +-    {@link android.provider.ContactsContract.ContactsColumns#DISPLAY_NAME Contacts.DISPLAY_NAME}.
    ++    {@link android.provider.ContactsContract.Contacts#DISPLAY_NAME Contacts.DISPLAY_NAME}.
    + </p>
    + <p>
    +-    The column {@link android.provider.BaseColumns#_ID Contacts._ID} is used by the
    ++    The column {@link android.provider.ContactsContract.Contacts#_ID Contacts._ID} is used by the
    +     {@link android.support.v4.widget.SimpleCursorAdapter} binding process.
    +-    {@link android.provider.BaseColumns#_ID Contacts._ID} and
    +-    {@link android.provider.ContactsContract.ContactsColumns#LOOKUP_KEY} are used together to
    ++    {@link android.provider.ContactsContract.Contacts#_ID Contacts._ID} and
    ++    {@link android.provider.ContactsContract.Contacts#LOOKUP_KEY} are used together to
    +     construct a content URI for the contact the user selects.
    + </p>
    + <pre>
    +@@ -635,7 +635,7 @@ public class ContactsFragment extends Fragment implements
    +     </li>
    +     <li>
    +         The name of the column that contains the custom MIME type value. This name is always
    +-        {@link android.provider.ContactsContract.DataColumns#MIMETYPE Data.MIMETYPE}.
    ++        {@link android.provider.ContactsContract.Data#MIMETYPE Data.MIMETYPE}.
    +     </li>
    +     <li>
    +         The custom MIME type value for the data type. As described previously, this is the constant
    +diff --git a/docs/html/training/graphics/opengl/touch.jd b/docs/html/training/graphics/opengl/touch.jd
    +index 6a961da..089ede7 100644
    +--- a/docs/html/training/graphics/opengl/touch.jd
    ++++ b/docs/html/training/graphics/opengl/touch.jd
    +@@ -36,7 +36,7 @@ class="button">Download the sample</a>
    + getting some attention, but what if you want to have users interact with your OpenGL ES graphics?
    + The key to making your OpenGL ES application touch interactive is expanding your implementation of
    + {@link android.opengl.GLSurfaceView} to override the {@link
    +-android.view.View#onTouchEvent onTouchEvent()} to listen for touch events.</p>
    ++android.opengl.GLSurfaceView#onTouchEvent onTouchEvent()} to listen for touch events.</p>
    + 
    + <p>This lesson shows you how to listen for touch events to let users rotate an OpenGL ES object.</p>
    + 
    +@@ -44,7 +44,7 @@ android.view.View#onTouchEvent onTouchEvent()} to listen for touch events.</p>
    + <h2 id="listener">Setup a Touch Listener</h2>
    + 
    + <p>In order to make your OpenGL ES application respond to touch events, you must implement the
    +-{@link android.view.View#onTouchEvent onTouchEvent()} method in your
    ++{@link android.opengl.GLSurfaceView#onTouchEvent onTouchEvent()} method in your
    + {@link android.opengl.GLSurfaceView} class. The example implementation below shows how to listen for
    + {@link android.view.MotionEvent#ACTION_MOVE MotionEvent.ACTION_MOVE} events and translate them to
    + an angle of rotation for a shape.</p>
    +diff --git a/docs/html/training/implementing-navigation/nav-drawer.jd b/docs/html/training/implementing-navigation/nav-drawer.jd
    +index abc79b6..8aebd4b 100644
    +--- a/docs/html/training/implementing-navigation/nav-drawer.jd
    ++++ b/docs/html/training/implementing-navigation/nav-drawer.jd
    +@@ -148,7 +148,7 @@ public class MainActivity extends Activity {
    + }
    + </pre>
    + 
    +-<p>This code also calls {@link android.widget.AdapterView#setOnItemClickListener
    ++<p>This code also calls {@link android.widget.ListView#setOnItemClickListener
    + setOnItemClickListener()} to receive click events in the navigation drawer's list.
    + The next section shows how to implement this interface
    + and change the content view when the user selects an item.</p>
    +@@ -160,7 +160,7 @@ and change the content view when the user selects an item.</p>
    + <p>When the user selects an item in the drawer's list, the system calls {@link
    + android.widget.AdapterView.OnItemClickListener#onItemClick onItemClick()} on the
    + {@link android.widget.AdapterView.OnItemClickListener OnItemClickListener} given to
    +-{@link android.widget.AdapterView#setOnItemClickListener setOnItemClickListener()}.</p>
    ++{@link android.widget.ListView#setOnItemClickListener setOnItemClickListener()}.</p>
    + 
    + <p>What you do in the {@link
    + android.widget.AdapterView.OnItemClickListener#onItemClick onItemClick()} method
    +diff --git a/docs/html/training/location/display-address.jd b/docs/html/training/location/display-address.jd
    +index daa6fd3..088e926 100644
    +--- a/docs/html/training/location/display-address.jd
    ++++ b/docs/html/training/location/display-address.jd
    +@@ -7,11 +7,11 @@ trainingnavtop=true
    + 
    +     <h2>This lesson teaches you how to</h2>
    +     <ol>
    +-      <li><a href="#connect">Get a Geographic Location</a></li>
    +-      <li><a href="#fetch-address">Define an Intent Service to Fetch the
    +-        Address</a></li>
    +-      <li><a href="#start-intent">Start the Intent Service</a></li>
    +-      <li><a href="#result-receiver">Receive the Geocoding Results</a></li>
    ++      <li><a href="#connect">Get a geographic location</a></li>
    ++      <li><a href="#fetch-address">Define an intent service to fetch the
    ++        address</a></li>
    ++      <li><a href="#start-intent">Start the intent service</a></li>
    ++      <li><a href="#result-receiver">Receive the geocoding results</a></li>
    +     </ol>
    + 
    +     <h2>You should also read</h2>
    +@@ -58,7 +58,7 @@ trainingnavtop=true
    +   convert a geographic location to an address. The method returns an estimated
    +   street address corresponding to a given latitude and longitude.</p>
    + 
    +-<h2 id="connect">Get a Geographic Location</h2>
    ++<h2 id="connect">Get a geographic location</h2>
    + 
    + <p>The last known location of the device is a useful starting point for the
    +   address lookup feature. The lesson on
    +@@ -69,12 +69,12 @@ trainingnavtop=true
    +   <a href="{@docRoot}reference/com/google/android/gms/location/FusedLocationProviderApi.html">fused
    +   location provider</a> to find the latest location of the device.</p>
    + 
    +-<p>To access the fused location provider, you need to create an instance of the
    ++<p>To access the fused location provider, create an instance of the
    +   Google Play services API client. To learn how to connect your client, see
    +   <a href="{@docRoot}training/location/retrieve-current.html#play-services">Connect
    +   to Google Play Services</a>.</p>
    + 
    +-<p>In order for the fused location provider to retrieve a precise street
    ++<p>To enable the fused location provider to retrieve a precise street
    +   address, set the location permission in your app manifest to
    +   {@code ACCESS_FINE_LOCATION}, as shown in the following example:</p>
    + 
    +@@ -86,12 +86,12 @@ trainingnavtop=true
    + &lt;/manifest&gt;
    + </pre>
    + 
    +-<h2 id="fetch-address">Define an Intent Service to Fetch the Address</h2>
    ++<h2 id="fetch-address">Define an intent service to fetch the address</h2>
    + 
    + <p>The {@link android.location.Geocoder#getFromLocation getFromLocation()}
    +   method provided by the {@link android.location.Geocoder} class accepts a
    +-  latitude and longitude, and returns a list of addresses. The method is
    +-  synchronous, and may take a long time to do its work, so you should not call
    ++  latitude and longitude and returns a list of addresses. The method is
    ++  synchronous and may take a long time to do its work, so you should not call
    +   it from the main, user interface (UI) thread of your app.</p>
    + 
    + <p>The {@link android.app.IntentService IntentService} class provides a
    +@@ -100,23 +100,23 @@ trainingnavtop=true
    +   Note that the {@link android.os.AsyncTask AsyncTask} class also allows you to
    +   perform background operations, but it's designed for short operations. An
    +   {@link android.os.AsyncTask AsyncTask} shouldn't keep a reference to the UI if
    +-  the activity is recreated, for example when the device is rotated. In
    ++  the activity is re-created, such as when the device is rotated. In
    +   contrast, an {@link android.app.IntentService IntentService} doesn't need to
    +   be cancelled when the activity is rebuilt.</p>
    + 
    + <p>Define a {@code FetchAddressIntentService} class that extends
    +   {@link android.app.IntentService}. This class is your address lookup service.
    +-  The intent service handles an intent asynchronously on a worker thread, and
    ++  The intent service handles an intent asynchronously on a worker thread and
    +   stops itself when it runs out of work. The intent extras provide the data
    +   needed by the service, including a {@link android.location.Location} object
    +-  for conversion to an address, and a {@link android.os.ResultReceiver} object
    ++  for conversion to an address and a {@link android.os.ResultReceiver} object
    +   to handle the results of the address lookup. The service uses a {@link
    +-  android.location.Geocoder} to fetch the address for the location, and sends
    ++  android.location.Geocoder} to fetch the address for the location and sends
    +   the results to the {@link android.os.ResultReceiver}.</p>
    + 
    +-<h3>Define the Intent Service in your App Manifest</h3>
    ++<h3>Define the intent service in your app manifest</h3>
    + 
    +-<p>Add an entry to your app manifest defining the intent service:</p>
    ++<p>Add an entry to your app manifest that defines the intent service, as shown here:</p>
    + 
    + <pre>
    + &lt;manifest xmlns:android="http://schemas.android.com/apk/res/android"
    +@@ -131,26 +131,26 @@ trainingnavtop=true
    + &lt;/manifest&gt;
    + </pre>
    + 
    +-<p class="note"><strong>Note:</strong> The {@code <service>} element in
    +-  the manifest doesn't need to include an intent filter, because your main
    ++<p class="note"><strong>Note:</strong> The {@code &lt;service&gt;} element in
    ++  the manifest doesn't need to include an intent filter because your main
    +   activity creates an explicit intent by specifying the name of the class to use
    +   for the intent.</p>
    + 
    +-<h3>Create a Geocoder</h3>
    ++<h3>Create a geocoder</h3>
    + 
    + <p>The process of converting a geographic location to an address is called
    +-  <em>reverse geocoding</em>. To perform the main work of the intent service,
    +-  that is, your reverse geocoding request, implement
    ++  <em>reverse geocoding</em>. To perform the main work of the intent service (your reverse
    ++  geocoding request), implement
    +   {@link android.app.IntentService#onHandleIntent onHandleIntent()} within the
    +   {@code FetchAddressIntentService} class. Create a
    +   {@link android.location.Geocoder} object to handle the reverse geocoding.</p>
    + 
    + <p>A locale represents a specific geographical or linguistic region. Locale
    +-  objects are used to adjust the presentation of information, such as numbers or
    +-  dates, to suit the conventions in the region represented by the locale. Pass a
    ++  objects adjust the presentation of information, such as numbers or
    ++  dates, to suit the conventions in the region that is represented by the locale. Pass a
    +   <a href="{@docRoot}reference/java/util/Locale.html">{@code Locale}</a> object
    +-  to the {@link android.location.Geocoder} object, to ensure that the resulting
    +-  address is localized to the user's geographic region.</p>
    ++  to the {@link android.location.Geocoder} object to ensure that the resulting
    ++  address is localized to the user's geographic region. Here is an example:</p>
    + 
    + <pre>
    + &#64;Override
    +@@ -162,7 +162,7 @@ protected void onHandleIntent(Intent intent) {
    + 
    + <h3 id="retrieve-street-address">Retrieve the street address data</h3>
    + 
    +-<p>The next step is to retrieve the street address from the geocoder, handle
    ++<p>You can now retrieve the street address from the geocoder, handle
    +   any errors that may occur, and send the results back to the activity that
    +   requested the address. To report the results of the geocoding
    +   process, you need two numeric constants that indicate success or failure.
    +@@ -185,32 +185,34 @@ public final class Constants {
    + 
    + <p>To get a street address corresponding to a geographical location, call
    +   {@link android.location.Geocoder#getFromLocation getFromLocation()},
    +-  passing it the latitude and longitude from the location object, and the
    +-  maximum number of addresses you want returned. In this case, you want just one
    +-  address. The geocoder returns an array of addresses. If no addresses were
    ++  passing it the latitude and longitude from the location object and the
    ++  maximum number of addresses that you want returned. In this case, you want just one
    ++  address. The geocoder returns an array of addresses. If no addresses are
    +   found to match the given location, it returns an empty list. If there is no
    +   backend geocoding service available, the geocoder returns null.</p>
    + 
    +-<p>Check for the following errors as shown in the code sample below. If an error
    +-  occurs, place the corresponding error message in the {@code errorMessage}
    +-  variable, so you can send it back to the requesting activity:</p>
    ++<p>Check for the following errors, as shown in the code sample below:</p>
    + 
    + <ul>
    +-  <li><strong>No location data provided</strong> - The intent extras do not
    +-    include the {@link android.location.Location} object required for reverse
    ++  <li><strong>No location data provided</strong> &ndash; The intent extras do not
    ++    include the {@link android.location.Location} object that is required for reverse
    +     geocoding.</li>
    +-  <li><strong>Invalid latitude or longitude used</strong> - The latitude
    +-    and/or longitude values provided in the {@link android.location.Location}
    ++  <li><strong>Invalid latitude or longitude used</strong> &ndash; The latitude
    ++    and/or longitude values that are provided in the {@link android.location.Location}
    +     object are invalid.</li>
    +-  <li><strong>No geocoder available</strong> - The background geocoding service
    +-    is not available, due to a network error or IO exception.</li>
    +-  <li><strong>Sorry, no address found</strong> - The geocoder could not find an
    ++  <li><strong>No geocoder available</strong> &ndash; The background geocoding service
    ++    is not available due to a network error or IO exception.</li>
    ++  <li><strong>Sorry, no address found</strong> &ndash; The geocoder can't find an
    +     address for the given latitude/longitude.</li>
    + </ul>
    + 
    ++<p>If an error
    ++  occurs, place the corresponding error message in the {@code errorMessage}
    ++  variable so that you can send it back to the requesting activity.
    ++
    + <p>To get the individual lines of an address object, use the
    +   {@link android.location.Address#getAddressLine getAddressLine()}
    +-  method provided by the {@link android.location.Address} class. Then join the
    ++  method that is provided by the {@link android.location.Address} class. Join the
    +   lines into a list of address fragments ready to return to the activity that
    +   requested the address.</p>
    + 
    +@@ -220,7 +222,7 @@ public final class Constants {
    +   results consist of the previously-mentioned numeric success/failure code and
    +   a string. In the case of a successful reverse geocoding, the string contains
    +   the address. In the case of a failure, the string contains the error message,
    +-  as shown in the code sample below:</p>
    ++  as shown in this code sample:</p>
    + 
    + <pre>
    + &#64;Override
    +@@ -280,18 +282,18 @@ protected void onHandleIntent(Intent intent) {
    + 
    + <h3 id="return-address">Return the address to the requestor</h3>
    + 
    +-<p>The final thing the intent service must do is send the address back to a
    ++<p>The final action that the intent service must complete is sending the address back to a
    +   {@link android.os.ResultReceiver} in the activity that started the service.
    +   The {@link android.os.ResultReceiver} class allows you to send a
    +   numeric result code as well as a message containing the result data. The
    +   numeric code is useful for reporting the success or failure of the geocoding
    +   request. In the case of a successful reverse geocoding, the message contains
    +   the address. In the case of a failure, the message contains some text
    +-  describing the reason for failure.</p>
    ++  describing the reason for the failure.</p>
    + 
    + <p>You have already retrieved the address from the geocoder, trapped any errors
    +-  that may occur, and called the {@code deliverResultToReceiver()} method. Now
    +-  you need to define the {@code deliverResultToReceiver()} method that sends
    ++  that may occur, and called the {@code deliverResultToReceiver()} method, so now
    ++  you must define the {@code deliverResultToReceiver()} method that sends
    +   a result code and message bundle to the result receiver.</p>
    + 
    + <p>For the result code, use the value that you've passed to the
    +@@ -299,7 +301,7 @@ protected void onHandleIntent(Intent intent) {
    +   To construct the message bundle, concatenate the {@code RESULT_DATA_KEY}
    +   constant from your {@code Constants} class (defined in
    +   <a href="#retrieve-street-address">Retrieve the street address data</a>) and
    +-  the value in the {@code message} parameter passed to the
    ++  the value in the {@code message} parameter that is passed to the
    +   {@code deliverResultToReceiver()} method, as shown in the following sample:
    + </p>
    + 
    +@@ -315,26 +317,26 @@ public class FetchAddressIntentService extends IntentService {
    + }
    + </pre>
    + 
    +-<h2 id="start-intent">Start the Intent Service</h2>
    ++<h2 id="start-intent">Start the intent service</h2>
    + 
    + <p>The intent service, as defined in the previous section, runs in the
    +-  background and is responsible for fetching the address corresponding to a
    ++  background and fetches the address corresponding to a
    +   given geographic location. When you start the service, the Android framework
    +-  instantiates and starts the service if it isn't already running, and creates a
    +-  process if needed. If the service is already running then it remains running.
    ++  instantiates and starts the service if it isn't already running, and it creates a
    ++  process if needed. If the service is already running, it remains running.
    +   Because the service extends {@link android.app.IntentService IntentService},
    +-  it shuts down automatically when all intents have been processed.</p>
    ++  it shuts down automatically after all intents are processed.</p>
    + 
    +-<p>Start the service from your app's main activity,
    ++<p>Start the service from your app's main activity
    +   and create an {@link android.content.Intent} to pass data to the service. You
    +-  need an <em>explicit</em> intent, because you want only your service
    ++  need an <em>explicit</em> intent because you want only your service
    +   to respond to the intent. For more information, see
    +   <a href="{@docRoot}guide/components/intents-filters.html#Types">Intent
    +   Types</a>.</p>
    + 
    + <p>To create an explicit intent, specify the name of the
    +   class to use for the service: {@code FetchAddressIntentService.class}.
    +-  Pass two pieces of information in the intent extras:</p>
    ++  Pass this information in the intent extras:</p>
    + 
    + <ul>
    +   <li>A {@link android.os.ResultReceiver} to handle the results of the address
    +@@ -362,6 +364,12 @@ public class MainActivity extends ActionBarActivity implements
    + }
    + </pre>
    + 
    ++<p class="caution"><strong>Caution</strong>: To ensure that your app is secure, always use an
    ++explicit intent when starting a {@link android.app.Service} and do not declare intent filters for
    ++your services. Using an implicit intent to start a service is a security hazard because you cannot
    ++be certain of the service that will respond to the intent, and the user cannot see which service
    ++starts.</p>
    ++
    + <p>Call the above {@code startIntentService()} method when the
    +   user takes an action that requires a geocoding address lookup. For example,
    +   the user may press a <em>Fetch address</em> button on your app's UI. Before
    +@@ -391,7 +399,7 @@ public void fetchAddressButtonHandler(View view) {
    +   app's UI. The following code snippet shows the call to the
    +   {@code startIntentService()} method in the
    +   <a href="{@docRoot}reference/com/google/android/gms/common/api/GoogleApiClient.ConnectionCallbacks.html#onConnected(android.os.Bundle)">{@code onConnected()}</a>
    +-  callback provided by the Google API Client:</p>
    ++  callback that is provided by the Google API Client:</p>
    + 
    + <pre>
    + public class MainActivity extends ActionBarActivity implements
    +@@ -420,9 +428,9 @@ public class MainActivity extends ActionBarActivity implements
    + }
    + </pre>
    + 
    +-<h2 id="result-receiver">Receive the Geocoding Results</h2>
    ++<h2 id="result-receiver">Receive the geocoding results</h2>
    + 
    +-<p>The intent service has handled the geocoding request, and uses a
    ++<p>After the intent service handles the geocoding request, it uses a
    +   {@link android.os.ResultReceiver} to return the results to the activity that
    +   made the request. In the activity that makes the request, define an
    +   {@code AddressResultReceiver} that extends {@link android.os.ResultReceiver}
    +@@ -430,14 +438,14 @@ public class MainActivity extends ActionBarActivity implements
    + 
    + <p>The result includes a numeric result code (<code>resultCode</code>) as well
    +   as a message containing the result data (<code>resultData</code>). If the
    +-  reverse geocoding process was successful, the <code>resultData</code> contains
    ++  reverse geocoding process is successful, the <code>resultData</code> contains
    +   the address. In the case of a failure, the <code>resultData</code> contains
    +-  text describing the reason for failure. For details of the possible errors,
    ++  text describing the reason for the failure. For details of the possible errors,
    +   see <a href="#return-address">Return the address to the requestor</a>.</p>
    + 
    + <p>Override the
    +   {@link android.os.ResultReceiver#onReceiveResult onReceiveResult()} method
    +-  to handle the results delivered to the result receiver, as shown in the
    ++  to handle the results that are delivered to the result receiver, as shown in the
    +   following code sample:</p>
    + 
    + <pre>
    +diff --git a/docs/html/training/location/geofencing.jd b/docs/html/training/location/geofencing.jd
    +index ce6ad55..046e99e 100644
    +--- a/docs/html/training/location/geofencing.jd
    ++++ b/docs/html/training/location/geofencing.jd
    +@@ -332,22 +332,39 @@ LocationServices.GeofencingApi.removeGeofences(
    + <p>This section outlines recommendations for using geofencing with the location
    + APIs for Android.</p>
    + 
    +-<h3>Reduce power consumption</h3>
    ++<h3>
    ++  Reduce power consumption
    ++</h3>
    + 
    +-<p>You can use the following techniques to optimize power consumption in your apps that use geofencing:</p>
    ++<p>
    ++  You can use the following techniques to optimize power consumption in your
    ++  apps that use geofencing:
    ++</p>
    + 
    + <ul>
    +-<li><p>Set the <a href="{@docRoot}android/reference/com/google/android/gms/location/Geofence.Builder.html#setNotificationResponsiveness(int)">
    +-notification responsiveness</a> to a higher value. Doing so improves power consumption by
    +-increasing the latency of geofence alerts. For example, if you set a responsiveness value of five
    +-minutes your app only checks for an entrance or exit alert once every five minutes.
    +-Setting lower values does not necessarily mean that users will be notified within that time period
    +-(for example, if you set a value of 5 seconds it may take a bit longer than that to receive the
    +-alert).</p></li>
    +-<li><p>Use a larger geofence radius for locations where a user spends a significant amount of time,
    +-such as home or work. While a larger radius doesn't directly reduce power consumption, it reduces
    +-the frequency at which the app checks for entrance or exit, effectively lowering overall power
    +-consumption.</p></li>
    ++  <li>
    ++    <p>
    ++      Set the <a href=
    ++      "https://developers.google.com/android/reference/com/google/android/gms/location/Geofence.Builder.html#setNotificationResponsiveness(int)">
    ++      notification responsiveness</a> to a higher value. Doing so improves
    ++      power consumption by increasing the latency of geofence alerts. For
    ++      example, if you set a responsiveness value of five minutes your app only
    ++      checks for an entrance or exit alert once every five minutes. Setting
    ++      lower values does not necessarily mean that users will be notified
    ++      within that time period (for example, if you set a value of 5 seconds it
    ++      may take a bit longer than that to receive the alert).
    ++    </p>
    ++  </li>
    ++
    ++  <li>
    ++    <p>
    ++      Use a larger geofence radius for locations where a user spends a
    ++      significant amount of time, such as home or work. While a larger radius
    ++      doesn't directly reduce power consumption, it reduces the frequency at
    ++      which the app checks for entrance or exit, effectively lowering overall
    ++      power consumption.
    ++    </p>
    ++  </li>
    + </ul>
    + 
    + <h3>Choose the optimal radius for your geofence</h3>
    +diff --git a/docs/html/training/material/images/palette-library-color-profiles_2-1_2x.png b/docs/html/training/material/images/palette-library-color-profiles_2-1_2x.png
    +new file mode 100644
    +index 0000000..d14ec32
    +Binary files /dev/null and b/docs/html/training/material/images/palette-library-color-profiles_2-1_2x.png differ
    +diff --git a/docs/html/training/material/images/palette-library-title-text-color_2-1_2x.png b/docs/html/training/material/images/palette-library-title-text-color_2-1_2x.png
    +new file mode 100644
    +index 0000000..883adba
    +Binary files /dev/null and b/docs/html/training/material/images/palette-library-title-text-color_2-1_2x.png differ
    +diff --git a/docs/html/training/material/index.jd b/docs/html/training/material/index.jd
    +index 4001e6b..8baa065 100644
    +--- a/docs/html/training/material/index.jd
    ++++ b/docs/html/training/material/index.jd
    +@@ -3,7 +3,6 @@ page.type=design
    + page.image=images/cards/material_2x.png
    + page.metaDescription=Learn how to apply material design to your apps.
    + 
    +-
    + @jd:body
    + 
    + <div id="tb-wrapper">
    +@@ -58,6 +57,9 @@ specification</a> and use the new components and functionality available in Andr
    + 
    +   <dt><a href="{@docRoot}training/material/compatibility.html">Maintaining Compatibility</a></dt>
    +   <dd>Learn how to maintain compatibility with platform versions earlier than Android 5.0.</dd>
    ++
    ++  <dt><a href="{@docRoot}training/material/palette-colors.html">Selecting Colors with the Palette API</a></dt>
    ++  <dd>Learn how to select colors for your app using the v7 Palette library.</dd>
    + </dl>
    + 
    + <h2>Video Training</h2>
    +diff --git a/docs/html/training/material/palette-colors.html b/docs/html/training/material/palette-colors.html
    +new file mode 100644
    +index 0000000..27485d2
    +--- /dev/null
    ++++ b/docs/html/training/material/palette-colors.html
    +@@ -0,0 +1,310 @@
    ++<html devsite>
    ++<head>
    ++  <title>Selecting Colors with the Palette API</title>
    ++  <meta name="book_path" value="/training/_book.yaml" />
    ++  <meta name="top_category" value="develop" />
    ++  <meta name="subcategory" value="training" />
    ++</head>
    ++<body>
    ++
    ++<div id="tb-wrapper">
    ++  <div id="tb">
    ++    <h2>This lesson teaches you to</h2>
    ++    <ol>
    ++      <li><a href="#set-up-the-library">Set up the library</a></li>
    ++      <li><a href="#create-a-palette">Create a palette</a>
    ++        <ol>
    ++          <li><a href="#generate-a-palette-instance">Generate a Palette instance</a></li>
    ++          <li><a href="#customize-your-palette">Customize your palette</a></li>
    ++        </ol>
    ++      </li>
    ++      <li><a href="#extract-color-profiles">Extract color profiles</a>
    ++        <ol>
    ++          <li><a href="#use-swatches">Use swatches to create color schemes</a></li>
    ++        </ol>
    ++      </li>
    ++    </ol>
    ++    <h2>You should also read</h2>
    ++    <ul>
    ++      <li><a href="http://www.google.com/design/spec">Material design specification</a></li>
    ++      <li><a href="/design/material/index.html">Material design on Android</a></li>
    ++    </ul>
    ++  </div>
    ++</div>
    ++
    ++<p>Good visual design is essential for a successful app, and color schemes are a primary component of design. The palette library is a
    ++<a href="/topic/libraries/support-library/features.html#v7-palette">support library</a>
    ++that extracts prominent colors from images to help you create visually engaging apps.</p>
    ++
    ++<p>You can use the palette library to design layout
    ++<a href="/guide/topics/ui/themes.html">themes</a> and apply custom colors to visual elements in your app.
    ++For example, you can use a palette to create a color-coordinated title 
    ++card for a song based on its album cover or to adjust an app’s toolbar color when its 
    ++background image changes. The <code><a 
    ++href="/reference/android/support/v7/graphics/Palette.html">Palette</a></code> object gives 
    ++you access to the colors in a <code><a
    ++href="/reference/android/graphics/Bitmap.html">Bitmap</a></code> 
    ++image while also providing six main color profiles from the bitmap to help
    ++inform your <a href="http://material.google.com">design choices</a>.</p>
    ++
    ++<h2 id="set-up-the-library">Set up the library</h2>
    ++
    ++<p>To use the palette library, install or update the <a
    ++href="/topic/libraries/support-library/index.html">Android
    ++Support Library</a> to version 24.0.0 or higher and follow the instructions for <a
    ++href="/topic/libraries/support-library/setup.html#add-library">Adding
    ++Support Libraries</a> to add the palette library to your app development project.</p>
    ++
    ++<p>Make sure that the version specified in your dependency identifier matches your
    ++app’s <code>compileSdkVersion</code>, set in the <code>build.gradle</code>
    ++file:</p>
    ++
    ++<pre class="prettyprint">
    ++android {
    ++  compileSdkVersion 24
    ++  ...
    ++}
    ++
    ++dependencies {
    ++  ...
    ++  compile 'com.android.support:palette-v7:24.2.1'
    ++}
    ++</pre>
    ++
    ++<p>For more information about adding the palette dependency, read about the palette
    ++feature in the <a
    ++href="/topic/libraries/support-library/features.html#v7-palette">support
    ++library documentation</a>.</p>
    ++
    ++<h2 id="create-a-palette">Create a palette</h2>
    ++
    ++<p>A <code>Palette</code> object gives you access to the primary colors in an
    ++image, as well as the corresponding colors for overlaid text. Use palettes to design
    ++your app’s style and to dynamically change your app’s color scheme based on a
    ++given source image.</p>
    ++
    ++<p>To create a palette, first instantiate a <code><a
    ++href="https://developer.android.com/reference/android/support/v7/graphics/Palette.Builder.html">Palette.Builder</a></code>
    ++from a <code>Bitmap</code>. You can then use the
    ++<code>Palette.Builder</code> to customize the palette before generating it. This
    ++section will describe palette generation and customization from a bitmap
    ++image.</p>
    ++
    ++<h3 id="generate-a-palette-instance">Generate a Palette instance</h3>
    ++
    ++<p>Generate a <code>Palette</code> instance using <code>Palette</code>’s
    ++<code><a
    ++href="/reference/android/support/v7/graphics/Palette.html#from(android.graphics.Bitmap)">from(Bitmap
    ++bitmap)</a></code> method to first create a <code>Palette.Builder</code>
    ++from a <code>Bitmap</code>. The builder can then generate the palette either
    ++synchronously or asynchronously.</p>
    ++
    ++<p>Use synchronous palette generation if you want to create the palette on
    ++the same thread as the method being called. If you generate the palette
    ++asynchronously on a different thread, use the <code><a
    ++href="/reference/android/support/v7/graphics/Palette.PaletteAsyncListener.html#onGenerated(android.support.v7.graphics.Palette)">onGenerated()</a></code>
    ++method to access the palette immediately after it has been created.</p>
    ++
    ++<p>The following code snippet provides example methods for both types of palette generation:</p>
    ++
    ++<pre class="prettyprint">
    ++// Generate palette synchronously and return it
    ++public Palette createPaletteSync(Bitmap bitmap) {
    ++  Palette p = Palette.from(bitmap).generate();
    ++  return p;
    ++}
    ++
    ++// Generate palette asynchronously and use it on a different
    ++// thread using onGenerated()
    ++public void createPaletteAsync(Bitmap bitmap) {
    ++  Palette.from(bitmap).generate(new PaletteAsyncListener() {
    ++    public void onGenerated(Palette p) {
    ++      // Use generated instance
    ++    }
    ++  });
    ++}
    ++</pre>
    ++
    ++<p>If you need to continuously generate palettes for a sorted list of images
    ++or objects, consider <a
    ++href="/reference/android/util/LruCache.html">caching</a>
    ++the <code>Palette</code> instances to prevent slow UI performance. You also
    ++should not create the palettes on your <a href="/training/articles/perf-anr.html">main thread</a>.</p>
    ++
    ++<h3 id="customize-your-palette">Customize your palette</h3>
    ++
    ++<p>The <code>Palette.Builder</code> allows you to customize your palette by
    ++choosing how many colors are in the resulting palette, what area of your
    ++image the builder uses to generate the palette, and what colors are allowed in the
    ++palette. For example, you can filter out the color black or ensure that the
    ++builder only uses the top half of an image to generate your palette.</p>
    ++
    ++<p>Fine-tune your palette’s size and colors with the following methods from
    ++the <code>Palette.Builder</code> class:</p>
    ++
    ++<dl>
    ++
    ++  <dt><code><a 
    ++  href="/reference/android/support/v7/graphics/Palette.Builder.html#addFilter(android.support.v7.graphics.Palette.Filter)">addFilter()</a></code></dt>
    ++  <dd>This method adds a filter that indicates what colors are allowed in the
    ++  resulting palette. Pass in your own<code> <a
    ++  href="/reference/android/support/v7/graphics/Palette.Filter.html">Palette.Filter</a></code>
    ++  and modify its <code>isAllowed()</code> method to determine which colors are
    ++  filtered from the palette.</dd>
    ++
    ++  <dt><code><a
    ++  href="/reference/android/support/v7/graphics/Palette.Builder.html#maximumColorCount(int)">maximumColorCount()</a></code></dt>
    ++  <dd>This method sets the maximum number of colors in your palette. The
    ++  default value is 16, and the optimal value depends on the source image. 
    ++  For landscapes, optimal values range from 8-16 while pictures with faces 
    ++  usually have values that fall between 24-32. The
    ++  <code>Palette.Builder</code> takes longer to generate palettes with more
    ++  colors.</dd>
    ++
    ++  <dt><code><a 
    ++  href="/reference/android/support/v7/graphics/Palette.Builder.html#setRegion(int,%20int,%20int,%20int)">setRegion()</a></code></dt>
    ++  <dd>This method indicates what area of the bitmap the builder uses when
    ++  creating the palette. You can only use this method when generating the palette from
    ++  a bitmap, and it does not affect the original image.</dd>
    ++
    ++  <dt><code><a
    ++  href="/reference/android/support/v7/graphics/Palette.Builder.html#addTarget(android.support.v7.graphics.Target)">addTarget()</a></code></dt>
    ++  <dd>This method allows you to perform your own color matching by adding a
    ++  <code><a
    ++  href="/reference/android/support/v7/graphics/Target.html">Target</a></code>
    ++  color profile to the builder. If the default <code>Target</code>s are not
    ++  sufficient, advanced developers can create their own <code>Target</code>s
    ++  using a <code><a
    ++  href="/reference/android/support/v7/graphics/Target.Builder.html">Target.Builder</a></code>.</dd>
    ++
    ++</dl>
    ++
    ++<h2 id="extract-color-profiles">Extract color profiles</h2>
    ++
    ++<p>Based on the <a
    ++href="https://material.google.com/style/color.html#">standards
    ++of material design</a>, the palette library extracts commonly used color
    ++profiles from an image. Each profile is defined by a <code><a
    ++href="/reference/android/support/v7/graphics/Target.html">Target</a></code>,
    ++and colors extracted from the bitmap image are scored against each profile
    ++based on saturation, luminance, and population (number of pixels in the bitmap
    ++represented by the color). For each profile, the color with the best score
    ++defines that color profile for the given image.</p>
    ++
    ++<p>By default, a <code>Palette</code> object contains 16 primary colors from
    ++a given image. When generating your palette, you can <a
    ++href="#customize-your-palette">customize</a> its number of colors using the
    ++<code>Palette.Builder</code>. Extracting more colors provides more potential
    ++matches for each color profile but also causes <code>Palette.Builder</code> to
    ++take longer when generating the palette.</p>
    ++
    ++<p>The palette library attempts to extract the following six color
    ++profiles:</p>
    ++
    ++<ul>
    ++  <li>Light Vibrant</li>
    ++  <li>Vibrant</li>
    ++  <li>Dark Vibrant</li>
    ++  <li>Light Muted</li>
    ++  <li>Muted</li>
    ++  <li>Dark Muted</li>
    ++</ul>
    ++
    ++<p>Each of <code>Palette</code>’s <code>get&lt;<em>Profile</em>&gt;Color()</code>
    ++methods returns the color in the palette associated with that particular profile,
    ++where <code>&lt;<em>Profile</em>&gt;</code> is replaced by the name of one of the six
    ++color profiles. For example, the method to get the Dark Vibrant color profile is <code><a
    ++href="/reference/android/support/v7/graphics/Palette.html#getDarkVibrantColor(int)">getDarkVibrantColor()</a></code>.
    ++Since not all images will contain all color profiles, you must also provide
    ++a default color to return.</p>
    ++
    ++<p>Figure 1 displays a photo and its corresponding color
    ++profiles from the <code>get&lt;<em>Profile</em>&gt;Color()</code> methods.</p>
    ++
    ++<img src="/training/material/images/palette-library-color-profiles_2-1_2x.png" alt="" width="624"/>
    ++
    ++<p class="img-caption"><strong>Figure 1.</strong> An example image and its
    ++extracted color profiles given the default maximum color count (16) for the palette.</p>
    ++
    ++<h3 id="use-swatches">Use swatches to create color schemes</h3>
    ++
    ++<p>The <code>Palette</code> class also generates <code><a 
    ++href="/reference/android/support/v7/graphics/Palette.Swatch.html">Palette.Swatch</a></code>
    ++objects for each color profile. <code>Palette.Swatch</code>
    ++objects contain the associated color for that profile, as well as the
    ++color’s population in pixels.</p>
    ++
    ++<p>Swatches have additional methods for accessing more information about the color
    ++profile, such as HSL values and pixel population. You can use swatches to help
    ++create more comprehensive color schemes and app themes using the <code><a
    ++href="/reference/android/support/v7/graphics/Palette.Swatch.html#getBodyTextColor()">getBodyTextColor()</a></code>
    ++and <code><a
    ++href="/reference/android/support/v7/graphics/Palette.Swatch.html#getTitleTextColor()">getTitleTextColor()</a></code>
    ++methods. These methods return colors appropriate for use over the swatch’s
    ++color.</p>
    ++
    ++<p>Each of <code>Palette</code>’s <code>get&lt;<em>Profile</em>&gt;Swatch()</code>
    ++methods returns the swatch associated with that particular profile,
    ++where <code>&lt;<em>Profile</em>&gt;</code> is replaced by the name of one of the six
    ++color profiles. Although the palette’s <code>get&lt;<em>Profile</em>&gt;Swatch()</code> methods
    ++do not require default value parameters, they return <code>null</code> if that
    ++particular profile does not exist in the image. Therefore, you should check that
    ++a swatch is not null before using it. For example, the following method 
    ++returns the Vibrant swatch from a palette if the swatch is not null:</p>
    ++
    ++<pre class="prettyprint">
    ++// Return a palette's vibrant swatch after checking that it exists
    ++private Palette.Swatch checkVibrantSwatch(Palette p) {
    ++  Palette.Swatch vibrant = p.getVibrantSwatch();
    ++  if (vibrant != null) {
    ++    return vibrant;
    ++  }
    ++  // Throw error
    ++}
    ++</pre>
    ++
    ++<p>To access all colors in a palette, the <code><a
    ++href="/reference/android/support/v7/graphics/Palette.html#getSwatches()">getSwatches()</a></code>
    ++method returns a list of all swatches generated from an
    ++image, including the standard six color profiles.</p>
    ++
    ++<p>The following snippet of code uses the methods from the above code snippets to
    ++synchronously generate a palette, get its vibrant swatch, and change the colors of a
    ++toolbar to match the bitmap image. Figure 2 displays the resulting image and toolbar.</p>
    ++
    ++<div class="cols">
    ++
    ++  <div class="col-2of3">
    ++
    ++<pre class="prettyprint">
    ++// Set the background and text colors of a toolbar given a
    ++// bitmap image to match
    ++public void setToolbarColor(Bitmap bitmap) {
    ++  // Generate the palette and get the vibrant swatch
    ++  // See the createPaletteSync() and checkVibrantSwatch() methods
    ++  // from the code snippets above
    ++  Palette p = createPaletteSync(bitmap);
    ++  Palette.Swatch vibrantSwatch = checkVibrantSwatch(p);
    ++  
    ++  // Set the toolbar background and text colors
    ++  Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
    ++  toolbar.setBackgroundColor(vibrantSwatch.getRgb());
    ++  toolbar.setTitleTextColor(vibrantSwatch.getTitleTextColor());
    ++}
    ++</pre>
    ++
    ++  </div>
    ++
    ++  <div class="col-1of3">
    ++
    ++    <img src="/training/material/images/palette-library-title-text-color_2-1_2x.png" alt="" width="400"/>
    ++
    ++    <p class="img-caption"><strong>Figure 2.</strong> An example image with its
    ++    vibrant-colored toolbar and corresponding title text color.</p>
    ++
    ++  </div>
    ++
    ++</div>
    ++
    ++</body>
    ++</html>
    +diff --git a/docs/html/training/monitoring-device-state/battery-monitoring.jd b/docs/html/training/monitoring-device-state/battery-monitoring.jd
    +index db75aaf..bab9c9c 100644
    +--- a/docs/html/training/monitoring-device-state/battery-monitoring.jd
    ++++ b/docs/html/training/monitoring-device-state/battery-monitoring.jd
    +@@ -141,10 +141,11 @@ receiver. The receiver is triggered whenever the device battery becomes low or e
    + condition by listening for {@link android.content.Intent#ACTION_BATTERY_LOW} and {@link
    + android.content.Intent#ACTION_BATTERY_OKAY}.</p>
    + 
    +-<pre>&lt;receiver android:name=".BatteryLevelReceiver">
    +-&lt;intent-filter>
    +-  &lt;action android:name="android.intent.action.ACTION_BATTERY_LOW"/>
    +-  &lt;action android:name="android.intent.action.ACTION_BATTERY_OKAY"/>
    ++<pre>
    ++&lt;receiver android:name=".BatteryLevelReceiver">
    ++  &lt;intent-filter>
    ++    &lt;action android:name="android.intent.action.BATTERY_LOW"/>
    ++    &lt;action android:name="android.intent.action.BATTERY_OKAY"/>
    +   &lt;/intent-filter>
    + &lt;/receiver></pre>
    + 
    +diff --git a/docs/html/training/monitoring-device-state/connectivity-monitoring.jd b/docs/html/training/monitoring-device-state/connectivity-monitoring.jd
    +index 2dd904f..c63822b 100644
    +--- a/docs/html/training/monitoring-device-state/connectivity-monitoring.jd
    ++++ b/docs/html/training/monitoring-device-state/connectivity-monitoring.jd
    +@@ -33,7 +33,7 @@ next.link=manifest-receivers.html
    + <p>Some of the most common uses for repeating alarms and background services is to schedule regular
    + updates of application data from Internet resources, cache data, or execute long running downloads.
    + But if you aren't connected to the Internet, or the connection is too slow to complete your
    +-download, why both waking the device to schedule the update at all?</p>
    ++download, why bother waking the device to schedule the update at all?</p>
    + 
    + <p>You can use the {@link android.net.ConnectivityManager} to check that you're actually
    + connected to the Internet, and if so, what type of connection is in place.</p>
    +diff --git a/docs/html/training/monitoring-device-state/manifest-receivers.jd b/docs/html/training/monitoring-device-state/manifest-receivers.jd
    +index 3e36dba..5efa2fa 100644
    +--- a/docs/html/training/monitoring-device-state/manifest-receivers.jd
    ++++ b/docs/html/training/monitoring-device-state/manifest-receivers.jd
    +@@ -21,7 +21,10 @@ Efficiency</a></li>
    + 
    + <h2>You should also read</h2>
    + <ul>
    +-  <li><a href="{@docRoot}guide/components/intents-filters.html">Intents and Intent Filters</a>
    ++  <li><a href="/topic/performance/background-optimization.html">Background Optimizations</a>
    ++  <li><a href="/topic/performance/scheduling.html">Intelligent Job-Scheduling</a>
    ++  <li><a href="/training/articles/perf-anr.html">Keeping Your App Responsive</a>
    ++  <li><a href="/guide/components/intents-filters.html">Intents and Intent Filters</a>
    + </ul>
    + 
    + </div>
    +@@ -32,13 +35,22 @@ android.content.BroadcastReceiver} for each state you're monitoring and register
    + your application manifest. Then within each of these receivers you simply reschedule your recurring
    + alarms based on the current device state.</p>
    + 
    +-<p>A side-effect of this approach is that your app will wake the device each time any of these
    +-receivers is triggered&mdash;potentially much more frequently than required.</p>
    +-
    + <p>A better approach is to disable or enable the broadcast receivers at runtime. That way you can
    + use the receivers you declared in the manifest as passive alarms that are triggered by system events
    + only when necessary.</p>
    + 
    ++<p class="warning">
    ++    <strong>Warning:</strong> Limit how many broadcast
    ++    receivers you set in your app. Instead of using broadcast receivers,
    ++    consider using other APIs for
    ++    performing background work. For example, in Android 5.0 (API level 21) and
    ++    higher, you can use the {@link android.app.job.JobScheduler} class for
    ++    assigning work to be completed in the background.
    ++    For more information about APIs you can use instead of the
    ++    {@link android.content.BroadcastReceiver} class for scheduling background
    ++    work, see
    ++    <a href="{@docRoot}topic/performance/background-optimization.html">Background Optimizations</a>.
    ++</p>
    + 
    + <h2 id="ToggleReceivers">Toggle and Cascade State Change Receivers to Improve Efficiency </h2>
    + 
    +diff --git a/docs/html/training/notify-user/build-notification.jd b/docs/html/training/notify-user/build-notification.jd
    +index 7df2787..baa1074 100644
    +--- a/docs/html/training/notify-user/build-notification.jd
    ++++ b/docs/html/training/notify-user/build-notification.jd
    +@@ -134,8 +134,8 @@ mBuilder.setContentIntent(resultPendingIntent);</pre>
    + <ul>
    + <li>Get an instance of {@link android.app.NotificationManager}.</li>
    + 
    +-<li>Use the {@link android.app.NotificationManager#notify(String, int, Notification)} method to issue the
    +-notification. When you call {@link android.app.NotificationManager#notify(String, int, Notification)}, specify a notification ID.
    ++<li>Use the {@link android.app.NotificationManager#notify notify()} method to issue the
    ++notification. When you call {@link android.app.NotificationManager#notify notify()}, specify a notification ID.
    + You can use this ID to update the notification later on. This is described in more detail in
    + <a href="managing.html">Managing Notifications</a>.</li>
    + 
    +diff --git a/docs/html/training/run-background-service/index.jd b/docs/html/training/run-background-service/index.jd
    +index 22f3fc8..c48c681 100644
    +--- a/docs/html/training/run-background-service/index.jd
    ++++ b/docs/html/training/run-background-service/index.jd
    +@@ -35,16 +35,22 @@ startpage=true
    + <!-- ------------------------------------------------------------------------------------------- -->
    + <p>
    +     Unless you specify otherwise, most of the operations you do in an app run in the foreground on
    +-    a special thread called the UI thread. This can cause problems, because long-running operations
    +-    will interfere with the responsiveness of your user interface. This annoys your users, and can
    ++    a special thread called the UI thread. Long-running foreground operations can cause problems
    ++    and interfere with the responsiveness of your user interface, which annoys your users and can
    +     even cause system errors. To avoid this, the Android framework offers several classes that
    +-    help you off-load operations onto a separate thread running in the background. The most useful
    +-    of these is {@link android.app.IntentService}.
    ++    help you off-load operations onto a separate thread that runs in the background. The most
    ++    useful of these is {@link android.app.IntentService}.
    + </p>
    + <p>
    +     This class describes how to implement an {@link android.app.IntentService}, send it work
    +     requests, and report its results to other components.
    + </p>
    ++
    ++<p class="note"><strong>Note:</strong> If your app targets Android 5.0 (API level 21),
    ++    you should use {@link android.app.job.JobScheduler} to execute background
    ++    services. For more information about this class,
    ++    see the {@link android.app.job.JobScheduler} reference documentation.</p>
    ++
    + <h2>Lessons</h2>
    + <dl>
    +     <dt>
    +diff --git a/docs/html/training/testing/ui-testing/espresso-testing.jd b/docs/html/training/testing/ui-testing/espresso-testing.jd
    +index d3d31de..3d2bca7 100644
    +--- a/docs/html/training/testing/ui-testing/espresso-testing.jd
    ++++ b/docs/html/training/testing/ui-testing/espresso-testing.jd
    +@@ -24,17 +24,11 @@ trainingnavtop=true
    +         </h2>
    + 
    +         <ol>
    +-          <li>
    +-            <a href="#setup">Set Up Espresso</a>
    +-          </li>
    ++          <li><a href="#setup">Set Up Espresso</a></li>
    + 
    +-          <li>
    +-            <a href="#build">Create an Espresso Test Class</a>
    +-          </li>
    ++          <li><a href="#build">Create an Espresso Test Class</a></li>
    + 
    +-          <li>
    +-            <a href="#run">Run Espresso Tests on a Device or Emulator</a>
    +-          </li>
    ++          <li><a href="#run">Run Espresso Tests on a Device or Emulator</a></li>
    +         </ol>
    + 
    +         <h2>
    +@@ -59,31 +53,40 @@ trainingnavtop=true
    +             class="external-link">Android Testing Codelab</a></li>
    +         </ul>
    +       </div>
    +-    </div>
    ++</div>
    + 
    +     <p>
    +       Testing user interactions
    +       within a single app helps to ensure that users do not
    +-      encounter unexpected results or have a poor experience when interacting with your app.
    +-      You should get into the habit of creating user interface (UI) tests if you need to verify
    ++      encounter unexpected results or have a poor
    ++      experience when interacting with your app.
    ++      You should get into the habit of creating
    ++      user interface (UI) tests if you need to verify
    +       that the UI of your app is functioning correctly.
    +     </p>
    + 
    +     <p>
    +       The Espresso testing framework, provided by the
    +       <a href="{@docRoot}tools/testing-support-library/index.html">Android Testing Support Library</a>,
    +-      provides APIs for writing UI tests to simulate user interactions within a
    +-      single target app. Espresso tests can run on devices running Android 2.2 (API level 8) and
    +-      higher. A key benefit of using Espresso is that it provides automatic synchronization of test
    +-      actions with the UI of the app you are testing. Espresso detects when the main thread is idle,
    +-      so it is able to run your test commands at the appropriate time, improving the reliability of
    +-      your tests. This capability also relieves you from having to adding any timing workarounds,
    +-      such as a sleep period, in your test code.
    ++      provides APIs for writing UI tests to simulate
    ++      user interactions within a
    ++      single target app. Espresso tests can run on
    ++      devices running Android 2.3.3 (API level 10) and
    ++      higher. A key benefit of using Espresso is
    ++      that it provides automatic synchronization of test
    ++      actions with the UI of the app you are testing.
    ++      Espresso detects when the main thread is idle,
    ++      so it is able to run your test commands
    ++      at the appropriate time, improving the reliability of
    ++      your tests. This capability also relieves you
    ++      from having to add any timing workarounds,
    ++      such as {@link java.lang.Thread#sleep(long) Thread.sleep()}
    ++      in your test code.
    +     </p>
    + 
    +     <p>
    +-      The Espresso testing framework is an instrumentation-based API and works
    +-      with the
    ++      The Espresso testing framework is
    ++      an instrumentation-based API and works with the
    +       <a href="{@docRoot}reference/android/support/test/runner/AndroidJUnitRunner.html">{@code
    +       AndroidJUnitRunner}</a> test runner.
    +     </p>
    +@@ -92,105 +95,139 @@ trainingnavtop=true
    +       Set Up Espresso
    +     </h2>
    + 
    +-<p>Before building your UI test with Espresso, make sure to configure your test source code
    +-location and project dependencies, as described in
    +-<a href="{@docRoot}training/testing/start/index.html#config-instrumented-tests">
    +-Getting Started with Testing</a>.</p>
    ++<p>
    ++  Before building your UI test with Espresso,
    ++  make sure to configure your test source code
    ++  location and project dependencies, as described in
    ++  <a href="{@docRoot}training/testing/start/index.html#config-instrumented-tests">Getting Started with Testing</a>.
    ++</p>
    + 
    +-<p>In the {@code build.gradle} file of your Android app module, you must set a dependency
    +-  reference to the Espresso library:</p>
    ++<p>
    ++  In the {@code build.gradle} file of your Android app
    ++  module, you must set a dependency
    ++  reference to the Espresso library:
    ++</p>
    + 
    + <pre>
    + dependencies {
    +-    ...
    +-    androidTestCompile 'com.android.support.test.espresso:espresso-core:2.2.1'
    ++    // Other dependencies ...
    ++    androidTestCompile 'com.android.support.test.espresso:espresso-core:2.2.2'
    + }
    + </pre>
    + 
    +-<p>Turn off animations on your test device &mdash; leaving system animations turned on in the test
    +-device might cause unexpected results or may lead your test to fail. Turn off animations from
    +-<em>Settings</em> by opening <em>Developing Options</em> and turning all the following options off:
    ++<p>
    ++  Turn off animations on your test device &mdash;
    ++  leaving system animations turned on in the test
    ++  device might cause unexpected results or may
    ++  lead your test to fail. Turn off animations from
    ++  <em>Settings</em> by opening <em>Developer options</em>
    ++  and turning all the following options off:
    + </p>
    +-        <ul>
    +-          <li>
    +-            <strong>Window animation scale</strong>
    +-          </li>
    + 
    +-          <li>
    +-            <strong>Transition animation scale</strong>
    +-          </li>
    ++<p>
    ++  <ul>
    ++    <li>
    ++      <strong>Window animation scale</strong>
    ++    </li>
    ++
    ++    <li>
    ++      <strong>Transition animation scale</strong>
    ++    </li>
    ++
    ++    <li>
    ++      <strong>Animator duration scale</strong>
    ++    </li>
    ++  </ul>
    ++</p>
    + 
    +-          <li>
    +-            <strong>Animator duration scale</strong>
    +-          </li>
    +-        </ul>
    +-      </li>
    +-    </ul>
    +-<p>If you want to set up your project to use Espresso features other than what the core API
    ++<p>
    ++  If you want to set up your project to use Espresso
    ++  features other than what the core API
    +   provides, see this
    +   <a href="https://google.github.io/android-testing-support-library/docs/espresso/index.html"
    +   class="external-link">resource</a>.</p>
    + 
    +-    <h2 id="build">
    +-      Create an Espresso Test Class
    +-    </h2>
    ++<!-- Section 2 -->
    + 
    +-    <p>
    +-      To create an Espresso test, create a Java class that follows this programming model:
    +-    </p>
    ++<h2 id="build">
    ++  Create an Espresso Test Class
    ++</h2>
    + 
    +-    <ol>
    +-      <li>Find the UI component you want to test in an {@link android.app.Activity} (for example, a
    +-      sign-in button in the app) by calling the
    +-      <a href="{@docRoot}reference/android/support/test/espresso/Espresso.html#onView(org.hamcrest.Matcher<android.view.View>)">
    +-        {@code onView()}</a> method, or the
    +-      <a href="{@docRoot}reference/android/support/test/espresso/Espresso.html#onData(org.hamcrest.Matcher<java.lang.Object>)">
    +-      {@code onData()}</a> method for {@link android.widget.AdapterView} controls.
    +-      </li>
    +-
    +-      <li>Simulate a specific user interaction to perform on that UI component, by calling the
    +-      <a href="{@docRoot}reference/android/support/test/espresso/ViewInteraction.html#perform(android.support.test.espresso.ViewAction...)">{@code ViewInteraction.perform()}</a>
    +-      or
    +-      <a href="{@docRoot}reference/android/support/test/espresso/DataInteraction.html#perform(android.support.test.espresso.ViewAction...)">{@code DataInteraction.perform()}</a>
    +-      method and passing in the user action (for example, click on the sign-in button). To sequence
    +-      multiple actions on the same UI component, chain them using a comma-separated list in your
    +-      method argument.
    +-      </li>
    +-
    +-      <li>Repeat the steps above as necessary, to simulate a user flow across multiple
    +-      activities in the target app.
    +-      </li>
    +-
    +-      <li>Use the
    ++<p>
    ++  To create an Espresso test, create a Java
    ++  class that follows this programming model:
    ++</p>
    ++
    ++<ol>
    ++  <li>
    ++    Find the UI component you want to test in
    ++    an {@link android.app.Activity} (for example, a
    ++    sign-in button in the app) by calling the
    ++    <a href="{@docRoot}reference/android/support/test/espresso/Espresso.html#onView(org.hamcrest.Matcher<android.view.View>)">
    ++    {@code onView()}</a> method, or the
    ++    <a href="{@docRoot}reference/android/support/test/espresso/Espresso.html#onData(org.hamcrest.Matcher<java.lang.Object>)">
    ++    {@code onData()}</a> method for {@link android.widget.AdapterView} controls.
    ++  </li>
    ++
    ++  <li>
    ++    Simulate a specific user interaction to
    ++    perform on that UI component, by calling the
    ++    <a href="{@docRoot}reference/android/support/test/espresso/ViewInteraction.html#perform(android.support.test.espresso.ViewAction...)">{@code ViewInteraction.perform()}</a>
    ++    or
    ++    <a href="{@docRoot}reference/android/support/test/espresso/DataInteraction.html#perform(android.support.test.espresso.ViewAction...)">{@code DataInteraction.perform()}</a>
    ++    method and passing in the user action
    ++    (for example, click on the sign-in button). To sequence
    ++    multiple actions on the same UI component, chain them using a comma-separated list in your
    ++    method argument.
    ++  </li>
    ++
    ++  <li>
    ++    Repeat the steps above as necessary, to simulate a user flow across multiple
    ++    activities in the target app.
    ++  </li>
    ++
    ++  <li>
    ++    Use the
    +     <a href="{@docRoot}reference/android/support/test/espresso/assertion/ViewAssertions.html">{@code ViewAssertions}</a>
    +-        methods to check that the UI reflects the expected
    +-      state or behavior, after these user interactions are performed.
    +-      </li>
    +-    </ol>
    ++    methods to check that the UI reflects the expected
    ++    state or behavior, after these user interactions are performed.
    ++  </li>
    ++</ol>
    + 
    +-    <p>
    +-      These steps are covered in more detail in the sections below.
    +-    </p>
    ++<p>
    ++  These steps are covered in more detail in the sections below.
    ++</p>
    + 
    +-    <p>
    +-      The following code snippet shows how your test class might invoke this basic workflow:
    +-    </p>
    ++<p>
    ++  The following code snippet shows how your test
    ++  class might invoke this basic workflow:
    ++</p>
    + 
    + <pre>
    + onView(withId(R.id.my_view))            // withId(R.id.my_view) is a ViewMatcher
    +         .perform(click())               // click() is a ViewAction
    +         .check(matches(isDisplayed())); // matches(isDisplayed()) is a ViewAssertion
    + </pre>
    +-<h3 id="espresso-atr">Using Espresso with ActivityTestRule</h3>
    ++
    ++<!-- Section 2.1 -->
    ++
    ++<h3 id="espresso-atr">
    ++  Using Espresso with ActivityTestRule
    ++</h3>
    ++
    + <p>
    +-The following section describes how to create a new Espresso test in the JUnit 4 style and use
    +-<a href="{@docRoot}reference/android/support/test/rule/ActivityTestRule.html">
    +-{@code ActivityTestRule}</a> to reduce the amount of boilerplate code you need to write. By using
    +-<a href="{@docRoot}reference/android/support/test/rule/ActivityTestRule.html">
    +-{@code ActivityTestRule}</a>, the testing framework launches the activity under test
    +-before each test method annotated with <code>&#64;Test</code> and before any method annotated with
    +-<code>&#64;Before</code>. The framework handles shutting down the activity after the test finishes
    +-and all methods annotated with <code>&#64;After</code> are run.</p>
    ++  The following section describes how to create a
    ++  new Espresso test in the JUnit 4 style and use
    ++  <a href="{@docRoot}reference/android/support/test/rule/ActivityTestRule.html">{@code ActivityTestRule}</a>
    ++  to reduce the amount of boilerplate code you need to write. By using
    ++  <a href="{@docRoot}reference/android/support/test/rule/ActivityTestRule.html">{@code ActivityTestRule}</a>,
    ++  the testing framework launches the activity under test
    ++  before each test method annotated with
    ++  <code>&#64;Test</code> and before any method annotated with
    ++  <code>&#64;Before</code>. The framework handles
    ++  shutting down the activity after the test finishes
    ++  and all methods annotated with <code>&#64;After</code> are run.
    ++</p>
    + 
    + <pre>
    + package com.example.android.testing.espresso.BasicSample;
    +@@ -234,103 +271,57 @@ public class ChangeTextBehaviorTest {
    + }
    + </pre>
    + 
    +-    <h3 id="espresso-aitc2">
    +-      Using Espresso with ActivityInstrumentationTestCase2
    +-    </h3>
    +-<p>The following section describes how to migrate to Espresso if you have existing test classes
    +-subclassed from {@link android.test.ActivityInstrumentationTestCase2} and you don't want to rewrite
    +-them to use JUnit4.</p>
    +-<p class="note"><strong>Note:</strong> For new UI tests, we strongly recommend that you write your
    +-test in the JUnit 4 style and use the
    +-<a href="{@docRoot}reference/android/support/test/rule/ActivityTestRule.html">
    +-{@code ActivityTestRule}</a> class, instead of
    +-{@link android.test.ActivityInstrumentationTestCase2}.</p>
    +-    <p>
    +-      If you are subclassing {@link android.test.ActivityInstrumentationTestCase2}
    +-      to create your Espresso test class, you must inject an
    +-      {@link android.app.Instrumentation} instance into your test class. This step is required in
    +-      order for your Espresso test to run with the
    +-      <a href="{@docRoot}reference/android/support/test/runner/AndroidJUnitRunner.html">{@code AndroidJUnitRunner}</a>
    +-      test runner.
    +-    </p>
    ++<!-- Section 2.2 -->
    + 
    +-    <p>
    +-      To do this, call the
    +-      {@link android.test.InstrumentationTestCase#injectInstrumentation(android.app.Instrumentation) injectInstrumentation()}
    +-      method and pass in the result of
    +-      <a href="{@docRoot}reference/android/support/test/InstrumentationRegistry.html#getInstrumentation()">
    +-      {@code InstrumentationRegistry.getInstrumentation()}</a>, as shown in the following code
    +-      example:
    +-    </p>
    +-
    +-<pre>
    +-import android.support.test.InstrumentationRegistry;
    ++<h3 id="accessing-ui-components">
    ++  Accessing UI Components
    ++</h3>
    + 
    +-public class MyEspressoTest
    +-        extends ActivityInstrumentationTestCase2&lt;MyActivity&gt; {
    +-
    +-    private MyActivity mActivity;
    +-
    +-    public MyEspressoTest() {
    +-        super(MyActivity.class);
    +-    }
    +-
    +-    &#64;Before
    +-    public void setUp() throws Exception {
    +-        super.setUp();
    +-        injectInstrumentation(InstrumentationRegistry.getInstrumentation());
    +-        mActivity = getActivity();
    +-    }
    +-
    +-   ...
    +-}
    +-</pre>
    +-
    +-<p class="note"><strong>Note:</strong> Previously, {@link android.test.InstrumentationTestRunner}
    +-would inject the {@link android.app.Instrumentation} instance, but this test runner is being
    +-deprecated.</p>
    +-
    +-    <h3 id="accessing-ui-components">
    +-      Accessing UI Components
    +-    </h3>
    +-
    +-    <p>
    +-      Before Espresso can interact with the app under test, you must first specify the UI component
    +-      or <em>view</em>. Espresso supports the use of
    +-<a href="http://hamcrest.org/" class="external-link">Hamcrest matchers</a>
    +-      for specifying views and adapters in your app.
    +-    </p>
    ++<p>
    ++  Before Espresso can interact with the app
    ++  under test, you must first specify the UI component
    ++  or <em>view</em>. Espresso supports the use of
    ++  <a href="http://hamcrest.org/" class="external-link">Hamcrest matchers</a>
    ++  for specifying views and adapters in your app.
    ++</p>
    + 
    +-    <p>
    +-      To find the view, call the <a href="{@docRoot}reference/android/support/test/espresso/Espresso.html#onView(org.hamcrest.Matcher<android.view.View>)">
    +-      {@code onView()}</a>
    +-      method and pass in a view matcher that specifies the view that you are targeting. This is
    +-      described in more detail in <a href="#specifying-view-matcher">Specifying a View Matcher</a>.
    +-      The <a href="{@docRoot}reference/android/support/test/espresso/Espresso.html#onView(org.hamcrest.Matcher<android.view.View>)">
    +-      {@code onView()}</a> method returns a
    +-      <a href="{@docRoot}reference/android/support/test/espresso/ViewInteraction.html">
    +-      {@code ViewInteraction}</a>
    +-      object that allows your test to interact with the view.
    +-      However, calling  the <a href="{@docRoot}reference/android/support/test/espresso/Espresso.html#onView(org.hamcrest.Matcher<android.view.View>)">
    +-      {@code onView()}</a> method may not work if you want to locate a view in
    +-      an {@link android.widget.AdapterView} layout. In this case, follow the instructions in
    +-      <a href="#locating-adpeterview-view">Locating a view in an AdapterView</a> instead.
    +-    </p>
    ++<p>
    ++  To find the view, call the
    ++  <a href="{@docRoot}reference/android/support/test/espresso/Espresso.html#onView(org.hamcrest.Matcher<android.view.View>)">{@code onView()}</a>
    ++  method and pass in a view matcher that
    ++  specifies the view that you are targeting. This is
    ++  described in more detail in
    ++  <a href="#specifying-view-matcher">Specifying a View Matcher</a>.
    ++  The <a href="{@docRoot}reference/android/support/test/espresso/Espresso.html#onView(org.hamcrest.Matcher<android.view.View>)">{@code onView()}</a>
    ++  method returns a
    ++  <a href="{@docRoot}reference/android/support/test/espresso/ViewInteraction.html">{@code ViewInteraction}</a>
    ++  object that allows your test to interact with the view.
    ++  However, calling the
    ++  <a href="{@docRoot}reference/android/support/test/espresso/Espresso.html#onView(org.hamcrest.Matcher<android.view.View>)">
    ++  {@code onView()}</a>
    ++  method may not work if you want to locate a view in
    ++  an {@link android.support.v7.widget.RecyclerView} layout.
    ++  In this case, follow the instructions in
    ++  <a href="#locating-adpeterview-view">Locating a view in an AdapterView</a>
    ++  instead.
    ++</p>
    + 
    +-    <p class="note">
    +-      <strong>Note</strong>: The <a href="{@docRoot}reference/android/support/test/espresso/Espresso.html#onView(org.hamcrest.Matcher<android.view.View>)">
    +-      {@code onView()}</a> method does not check if the view you specified is
    +-      valid. Instead, Espresso searches only the current view hierarchy, using the matcher provided.
    +-      If no match is found, the method throws a
    +-      <a href="{@docRoot}reference/android/support/test/espresso/NoMatchingViewException.html">
    +-      {@code NoMatchingViewException}</a>.
    +-    </p>
    ++<p class="note">
    ++  <strong>Note</strong>:
    ++  The <a href="{@docRoot}reference/android/support/test/espresso/Espresso.html#onView(org.hamcrest.Matcher<android.view.View>)">{@code onView()}</a>
    ++  method does not check if the view you specified is
    ++  valid. Instead, Espresso searches only the
    ++  current view hierarchy, using the matcher provided.
    ++  If no match is found, the method throws a
    ++  <a href="{@docRoot}reference/android/support/test/espresso/NoMatchingViewException.html">{@code NoMatchingViewException}</a>.
    ++</p>
    + 
    +-    <p>
    +-      The following code snippet shows how you might write a test that accesses an
    +-      {@link android.widget.EditText} field, enters a string of text, closes the virtual keyboard,
    +-      and then performs a button click.
    +-    </p>
    ++<p>
    ++  The following code snippet shows how you might write a test that accesses an
    ++  {@link android.widget.EditText} field,
    ++  enters a string of text, closes the virtual keyboard,
    ++  and then performs a button click.
    ++</p>
    + 
    + <pre>
    + public void testChangeText_sameActivity() {
    +@@ -344,231 +335,464 @@ public void testChangeText_sameActivity() {
    + }
    + </pre>
    + 
    +-    <h4 id="specifying-view-matcher">
    +-      Specifying a View Matcher
    +-    </h4>
    ++<!-- Section 2.2.1 -->
    ++<h4 id="specifying-view-matcher">
    ++  Specifying a View Matcher
    ++</h4>
    + 
    +-    <p>
    +-      You can specify a view matcher by using these approaches:
    +-    </p>
    ++<p>
    ++  You can specify a view matcher by using these approaches:
    ++</p>
    + 
    +-    <ul>
    +-      <li>Calling methods in the
    +-        <a href="{@docRoot}reference/android/support/test/espresso/matcher/ViewMatchers.html">
    +-        {@code ViewMatchers}</a> class. For example, to find a view by looking for a text string it
    +-        displays, you can call a method like this:
    +-        <pre>
    ++<ul>
    ++  <li>Calling methods in the
    ++    <a href="{@docRoot}reference/android/support/test/espresso/matcher/ViewMatchers.html">{@code ViewMatchers}</a>
    ++    class. For example, to find a view by looking for a text string it
    ++    displays, you can call a method like this:
    ++<pre>
    + onView(withText("Sign-in"));
    + </pre>
    + 
    +-<p>Similarly you can call
    +-<a href="{@docRoot}reference/android/support/test/espresso/matcher/ViewMatchers.html#withId(int)">
    +-{@code withId()}</a> and providing the resource ID ({@code R.id}) of the view, as shown in the
    +-following example:</p>
    ++    <p>
    ++      Similarly you can call
    ++      <a href="{@docRoot}reference/android/support/test/espresso/matcher/ViewMatchers.html#withId(int)">{@code withId()}</a>
    ++      and providing the resource ID ({@code R.id}) of the view,
    ++      as shown in the
    ++      following example:
    ++    </p>
    + 
    + <pre>
    + onView(withId(R.id.button_signin));
    + </pre>
    + 
    +     <p>
    +-      Android resource IDs are not guaranteed to be unique. If your test attempts to match to a
    ++      Android resource IDs are not guaranteed to be unique.
    ++      If your test attempts to match to a
    +       resource ID used by more than one view, Espresso throws an
    +-<a href="{@docRoot}reference/android/support/test/espresso/AmbiguousViewMatcherException.html">
    +-  {@code AmbiguousViewMatcherException}</a>.
    ++      <a href="{@docRoot}reference/android/support/test/espresso/AmbiguousViewMatcherException.html">{@code AmbiguousViewMatcherException}</a>.
    +     </p>
    +-      </li>
    +-      <li>Using the Hamcrest
    +-      <a href="http://hamcrest.org/JavaHamcrest/javadoc/1.3/org/hamcrest/Matchers.html"
    +-         class="external-link">{@code Matchers}</a> class. You can use the
    +-      {@code allOf()} methods to combine multiple matchers, such as
    +-      {@code containsString()} and {@code instanceOf()}. This approach allows you to
    +-      filter the match results more narrowly, as shown in the following example:
    ++  </li>
    ++
    ++  <li>
    ++    Using the Hamcrest
    ++    <a href="http://hamcrest.org/JavaHamcrest/javadoc/1.3/org/hamcrest/Matchers.html"
    ++    class="external-link">{@code Matchers}</a> class. You can use the
    ++    {@code allOf()} methods to combine multiple matchers, such as
    ++    {@code containsString()} and {@code instanceOf()}.
    ++    This approach allows you to
    ++    filter the match results more narrowly, as shown in the following example:
    ++
    + <pre>
    + onView(allOf(withId(R.id.button_signin), withText("Sign-in")));
    + </pre>
    +-<p>You can use the {@code not} keyword to filter for views that don't correspond to the matcher, as
    +-shown in the following example:</p>
    ++
    ++    <p>
    ++      You can use the {@code not} keyword to filter
    ++      for views that don't correspond to the matcher, as
    ++      shown in the following example:
    ++    </p>
    ++
    + <pre>
    + onView(allOf(withId(R.id.button_signin), not(withText("Sign-out"))));
    + </pre>
    +-<p>To use these methods in your test, import the {@code org.hamcrest.Matchers} package. To
    +-learn more about Hamcrest matching, see the
    +-<a href="http://hamcrest.org/" class="external-link">Hamcrest site</a>.
    +-</p>
    +-      </li>
    +-    </ul>
    + 
    +     <p>
    +-      To improve the performance of your Espresso tests, specify the minimum matching information
    +-      needed to find your target view. For example, if a view is uniquely identifiable by its
    +-      descriptive text, you do not need to specify that it is also assignable from the
    +-      {@link android.widget.TextView} instance.
    ++      To use these methods in your test,
    ++      import the {@code org.hamcrest.Matchers} package. To
    ++      learn more about Hamcrest matching, see the
    ++      <a href="http://hamcrest.org/" class="external-link">Hamcrest site</a>.
    +     </p>
    ++  </li>
    ++</ul>
    + 
    +-    <h4 id="#locating-adpeterview-view">
    +-      Locating a view in an AdapterView
    +-    </h4>
    ++<p>
    ++  To improve the performance of your Espresso tests,
    ++  specify the minimum matching information
    ++  needed to find your target view. For example,
    ++  if a view is uniquely identifiable by its
    ++  descriptive text, you do not need to specify
    ++  that it is also assignable from the
    ++  {@link android.widget.TextView} instance.
    ++</p>
    + 
    +-    <p>
    +-      In an {@link android.widget.AdapterView} widget, the view is dynamically populated with child
    +-      views at runtime. If the target view you want to test is inside an
    +-      {@link android.widget.AdapterView}
    +-      (such as a {@link android.widget.ListView}, {@link android.widget.GridView}, or
    +-      {@link android.widget.Spinner}), the
    +-<a href="{@docRoot}reference/android/support/test/espresso/Espresso.html#onView(org.hamcrest.Matcher<android.view.View>)">
    +-  {@code onView()}</a> method might not work because only a
    +-      subset of the views may be loaded in the current view hierarchy.
    +-    </p>
    ++<!-- Section 2.2.2 -->
    + 
    +-    <p>
    +-      Instead, call the <a href="{@docRoot}reference/android/support/test/espresso/Espresso.html#onData(org.hamcrest.Matcher<java.lang.Object>)">{@code onData()}</a>
    +-      method to obtain a
    +-      <a href="{@docRoot}reference/android/support/test/espresso/DataInteraction.html">
    +-      {@code DataInteraction}</a>
    +-      object to access the target view element. Espresso handles loading the target view element
    +-      into the current view hierarchy. Espresso also takes care of scrolling to the target element,
    +-      and putting the element into focus.
    +-    </p>
    ++<h4 id="#locating-adpeterview-view">
    ++  Locating a view in an AdapterView
    ++</h4>
    ++
    ++<p>
    ++  In an {@link android.widget.AdapterView} widget,
    ++  the view is dynamically populated with child
    ++  views at runtime. If the target view you want to test is inside an
    ++  {@link android.widget.AdapterView}
    ++  (such as a {@link android.widget.ListView},
    ++  {@link android.widget.GridView}, or
    ++  {@link android.widget.Spinner}), the
    ++  <a href="{@docRoot}reference/android/support/test/espresso/Espresso.html#onView(org.hamcrest.Matcher<android.view.View>)">{@code onView()}</a>
    ++  method might not work because only a
    ++  subset of the views may be loaded in the current view hierarchy.
    ++</p>
    + 
    +-    <p class="note">
    +-      <strong>Note</strong>: The
    ++<p>
    ++  Instead, call the
    +   <a href="{@docRoot}reference/android/support/test/espresso/Espresso.html#onData(org.hamcrest.Matcher<java.lang.Object>)">{@code onData()}</a>
    +-      method does not check if if the item you specified corresponds with a view. Espresso searches
    +-      only the current view hierarchy. If no match is found, the method throws a
    +-      <a href="{@docRoot}reference/android/support/test/espresso/NoMatchingViewException.html">
    +-        {@code NoMatchingViewException}</a>.
    +-    </p>
    ++  method to obtain a
    ++  <a href="{@docRoot}reference/android/support/test/espresso/DataInteraction.html">{@code DataInteraction}</a>
    ++  object to access the target view element.
    ++  Espresso handles loading the target view element
    ++  into the current view hierarchy. Espresso
    ++  also takes care of scrolling to the target element,
    ++  and putting the element into focus.
    ++</p>
    + 
    +-    <p>
    +-      The following code snippet shows how you can use the
    +-      <a href="{@docRoot}reference/android/support/test/espresso/Espresso.html#onData(org.hamcrest.Matcher<java.lang.Object>)">{@code onData()}</a>
    +-      method together
    +-      with Hamcrest matching to search for a specific row in a list that contains a given string.
    +-      In this example, the {@code LongListActivity} class contains a list of strings exposed
    +-      through a {@link android.widget.SimpleAdapter}.
    +-    </p>
    ++<p class="note">
    ++  <strong>Note</strong>: The
    ++  <a href="{@docRoot}reference/android/support/test/espresso/Espresso.html#onData(org.hamcrest.Matcher<java.lang.Object>)">{@code onData()}</a>
    ++  method does not check if the item you
    ++  specified corresponds with a view. Espresso searches
    ++  only the current view hierarchy. If no match is found, the method throws a
    ++  <a href="{@docRoot}reference/android/support/test/espresso/NoMatchingViewException.html">{@code NoMatchingViewException}</a>.
    ++</p>
    ++
    ++<p>
    ++  The following code snippet shows how you can use the
    ++  <a href="{@docRoot}reference/android/support/test/espresso/Espresso.html#onData(org.hamcrest.Matcher<java.lang.Object>)">{@code onData()}</a>
    ++  method together
    ++  with Hamcrest matching to search for a specific
    ++  row in a list that contains a given string.
    ++  In this example, the {@code LongListActivity} class
    ++  contains a list of strings exposed
    ++  through a {@link android.widget.SimpleAdapter}.
    ++</p>
    + 
    + <pre>
    + onData(allOf(is(instanceOf(Map.class)),
    +-        hasEntry(equalTo(LongListActivity.ROW_TEXT), is(str))));
    ++        hasEntry(equalTo(LongListActivity.ROW_TEXT), is("test input")));
    + </pre>
    + 
    +-    <h3 id="perform-actions">
    +-      Performing Actions
    +-    </h3>
    ++<!-- Section 2.3 -->
    + 
    +-    <p>
    +-      Call the <a href="{@docRoot}reference/android/support/test/espresso/ViewInteraction.html#perform(android.support.test.espresso.ViewAction...)">{@code ViewInteraction.perform()}</a>
    +-      or
    +-      <a href="{@docRoot}reference/android/support/test/espresso/DataInteraction.html#perform(android.support.test.espresso.ViewAction...)">{@code DataInteraction.perform()}</a>
    +-      methods to
    +-      simulate user interactions on the UI component. You must pass in one or more
    +-      <a href="{@docRoot}reference/android/support/test/espresso/ViewAction.html">{@code ViewAction}</a>
    +-      objects as arguments. Espresso fires each action in sequence according to
    +-      the given order, and executes them in the main thread.
    +-    </p>
    ++<h3 id="perform-actions">Performing Actions</h3>
    + 
    +-    <p>
    +-      The
    +-      <a href="{@docRoot}reference/android/support/test/espresso/action/ViewActions.html">{@code ViewActions}</a>
    +-      class provides a list of helper methods for specifying common actions.
    +-      You can use these methods as convenient shortcuts instead of creating and configuring
    +-      individual <a href="{@docRoot}reference/android/support/test/espresso/ViewAction.html">{@code ViewAction}</a>
    +-      objects. You can specify such actions as:
    +-    </p>
    ++<p>
    ++  Call the
    ++  <a href="{@docRoot}reference/android/support/test/espresso/ViewInteraction.html#perform(android.support.test.espresso.ViewAction...)">{@code ViewInteraction.perform()}</a>
    ++  or
    ++  <a href="{@docRoot}reference/android/support/test/espresso/DataInteraction.html#perform(android.support.test.espresso.ViewAction...)">{@code DataInteraction.perform()}</a>
    ++  methods to
    ++  simulate user interactions on the UI component. You must pass in one or more
    ++  <a href="{@docRoot}reference/android/support/test/espresso/ViewAction.html">{@code ViewAction}</a>
    ++  objects as arguments. Espresso fires each action in sequence according to
    ++  the given order, and executes them in the main thread.
    ++</p>
    + 
    +-    <ul>
    +-      <li>
    +-       <a href="{@docRoot}reference/android/support/test/espresso/action/ViewActions.html#click()">{@code ViewActions.click()}</a>:
    +-       Clicks on the view.
    +-      </li>
    +-
    +-      <li>
    +-       <a href="{@docRoot}reference/android/support/test/espresso/action/ViewActions.html#typeText(java.lang.String)">{@code ViewActions.typeText()}</a>:
    +-       Clicks on a view and enters a specified string.
    +-      </li>
    +-
    +-      <li>
    +-       <a href="{@docRoot}reference/android/support/test/espresso/action/ViewActions.html#scrollTo()">{@code ViewActions.scrollTo()}</a>:
    +-       Scrolls to the view. The
    +-        target view must be subclassed from {@link android.widget.ScrollView}
    +-        and the value of its
    +-        <a href="http://developer.android.com/reference/android/view/View.html#attr_android:visibility">{@code android:visibility}</a>
    +-        property must be {@link android.view.View#VISIBLE}. For views that extend
    +-        {@link android.widget.AdapterView} (for example,
    +-        {@link android.widget.ListView}),
    +-        the
    +-        <a href="{@docRoot}reference/android/support/test/espresso/Espresso.html#onData(org.hamcrest.Matcher<java.lang.Object>)">{@code onData()}</a>
    +-        method takes care of scrolling for you.
    +-      </li>
    +-
    +-      <li>
    +-       <a href="{@docRoot}reference/android/support/test/espresso/action/ViewActions.html#pressKey(int)">{@code ViewActions.pressKey()}</a>:
    +-       Performs a key press using a specified keycode.
    +-      </li>
    +-
    +-      <li>
    +-      <a href="{@docRoot}reference/android/support/test/espresso/action/ViewActions.html#clearText()">{@code ViewActions.clearText()}</a>:
    +-      Clears the text in the target view.
    +-      </li>
    +-    </ul>
    ++<p>
    ++  The
    ++  <a href="{@docRoot}reference/android/support/test/espresso/action/ViewActions.html">{@code ViewActions}</a>
    ++  class provides a list of helper methods for specifying common actions.
    ++  You can use these methods as convenient shortcuts
    ++  instead of creating and configuring individual
    ++  <a href="{@docRoot}reference/android/support/test/espresso/ViewAction.html">{@code ViewAction}</a>
    ++  objects. You can specify such actions as:
    ++</p>
    + 
    +-    <p>
    +-      If the target view is inside a {@link android.widget.ScrollView}, perform the
    +-      <a href="{@docRoot}reference/android/support/test/espresso/action/ViewActions.html#scrollTo()">{@code ViewActions.scrollTo()}</a>
    +-      action first to display the view in the screen before other proceeding
    +-      with other actions. The
    +-      <a href="{@docRoot}reference/android/support/test/espresso/action/ViewActions.html#scrollTo()">{@code ViewActions.scrollTo()}</a>
    +-      action will have no effect if the view is already displayed.
    +-    </p>
    ++<ul>
    ++  <li>
    ++   <a href="{@docRoot}reference/android/support/test/espresso/action/ViewActions.html#click()">{@code ViewActions.click()}</a>:
    ++   Clicks on the view.
    ++  </li>
    ++
    ++  <li>
    ++   <a href="{@docRoot}reference/android/support/test/espresso/action/ViewActions.html#typeText(java.lang.String)">{@code ViewActions.typeText()}</a>:
    ++   Clicks on a view and enters a specified string.
    ++  </li>
    ++
    ++  <li>
    ++    <a href="{@docRoot}reference/android/support/test/espresso/action/ViewActions.html#scrollTo()">{@code ViewActions.scrollTo()}</a>:
    ++    Scrolls to the view. The
    ++    target view must be subclassed from {@link android.widget.ScrollView}
    ++    and the value of its
    ++    <a href="http://developer.android.com/reference/android/view/View.html#attr_android:visibility">{@code android:visibility}</a>
    ++    property must be {@link android.view.View#VISIBLE}. For views that extend
    ++    {@link android.widget.AdapterView} (for example,
    ++    {@link android.widget.ListView}), the
    ++    <a href="{@docRoot}reference/android/support/test/espresso/Espresso.html#onData(org.hamcrest.Matcher<java.lang.Object>)">{@code onData()}</a>
    ++    method takes care of scrolling for you.
    ++  </li>
    ++
    ++  <li>
    ++    <a href="{@docRoot}reference/android/support/test/espresso/action/ViewActions.html#pressKey(int)">{@code ViewActions.pressKey()}</a>:
    ++    Performs a key press using a specified keycode.
    ++  </li>
    ++
    ++  <li>
    ++    <a href="{@docRoot}reference/android/support/test/espresso/action/ViewActions.html#clearText()">{@code ViewActions.clearText()}</a>:
    ++  Clears the text in the target view.
    ++  </li>
    ++</ul>
    + 
    +-    <h3 id="verify-results">
    +-      Verifying Results
    +-    </h3>
    ++<p>
    ++  If the target view is inside a {@link android.widget.ScrollView},
    ++  perform the
    ++  <a href="{@docRoot}reference/android/support/test/espresso/action/ViewActions.html#scrollTo()">{@code ViewActions.scrollTo()}</a>
    ++  action first to display the view in the screen before other proceeding
    ++  with other actions. The
    ++  <a href="{@docRoot}reference/android/support/test/espresso/action/ViewActions.html#scrollTo()">{@code ViewActions.scrollTo()}</a>
    ++  action will have no effect if the view is already displayed.
    ++</p>
    + 
    +-    <p>
    +-      Call the
    +-      <a href="{@docRoot}reference/android/support/test/espresso/ViewInteraction.html#check(android.support.test.espresso.ViewAssertion)">{@code ViewInteraction.check()}</a>
    +-      or
    +-      <a href="{@docRoot}reference/android/support/test/espresso/DataInteraction.html#check(android.support.test.espresso.ViewAssertion)">{@code DataInteraction.check()}</a>
    +-      method to assert
    +-      that the view in the UI matches some expected state. You must pass in a
    +-      <a href="{@docRoot}reference/android/support/test/espresso/ViewAssertion.html">
    +-      {@code ViewAssertion}</a> object as the argument. If the assertion fails, Espresso throws
    +-      an {@link junit.framework.AssertionFailedError}.
    +-    </p>
    ++<!-- Section 2.4 -->
    + 
    +-    <p>
    +-      The
    ++<h3 id="intents">
    ++  Test your activities in isolation with Espresso Intents
    ++</h3>
    ++
    ++<p>
    ++  <a href="https://google.github.io/android-testing-support-library/docs/espresso/intents/index.html" class="external-link">Espresso Intents</a>
    ++  enables validation and stubbing of intents sent out by an app.
    ++  With Espresso Intents, you can test an app, activity, or service in isolation
    ++  by intercepting outgoing intents, stubbing the result, and sending it back to
    ++  the component under test.
    ++</p>
    ++
    ++<p>
    ++  To begin testing with Espresso Intents, you need
    ++  to add the following line to your app's build.gradle file:
    ++</p>
    ++
    ++<pre>
    ++dependencies {
    ++  // Other dependencies ...
    ++  androidTestCompile 'com.android.support.test.espresso:espresso-intents:2.2.2'
    ++}
    ++</pre>
    ++
    ++<p>
    ++  To test an intent, you need to create an instance of the
    ++  <a href="{@docRoot}reference/android/support/test/espresso/intent/rule/IntentsTestRule.html">IntentsTestRule</a>
    ++  class, which is very similar to the
    ++  <a href="{@docRoot}reference/android/support/test/rule/ActivityTestRule.html">ActivityTestRule</a>
    ++  class.
    ++  The
    ++  <a href="{@docRoot}reference/android/support/test/espresso/intent/rule/IntentsTestRule.html">IntentsTestRule</a>
    ++  class initializes Espresso Intents before each test,
    ++  terminates the host activity,
    ++  and releases Espresso Intents after each test.
    ++</p>
    ++
    ++<p>
    ++  The test class shown in the following codes snippet provides a simple
    ++  test for an explicit intent. It tests the activities and intents created in the
    ++  <a href="{@docRoot}training/basics/firstapp/index.html">Building Your First App</a>
    ++  tutorial.
    ++</p>
    ++
    ++<pre>
    ++&#64;Large
    ++&#64;RunWith(AndroidJUnit4.class)
    ++public class SimpleIntentTest {
    ++
    ++    private static final String MESSAGE = "This is a test";
    ++    private static final String PACKAGE_NAME = "com.example.myfirstapp";
    ++
    ++    /* Instantiate an IntentsTestRule object. */
    ++    &#64;Rule
    ++    public IntentsTestRule&lg;MainActivity&gt; mIntentsRule =
    ++      new IntentsTestRule&lg;&gt;(MainActivity.class);
    ++
    ++    &#64;Test
    ++    public void verifyMessageSentToMessageActivity() {
    ++
    ++        // Types a message into a EditText element.
    ++        onView(withId(R.id.edit_message))
    ++                .perform(typeText(MESSAGE), closeSoftKeyboard());
    ++
    ++        // Clicks a button to send the message to another
    ++        // activity through an explicit intent.
    ++        onView(withId(R.id.send_message)).perform(click());
    ++
    ++        // Verifies that the DisplayMessageActivity received an intent
    ++        // with the correct package name and message.
    ++        intended(allOf(
    ++                hasComponent(hasShortClassName(".DisplayMessageActivity")),
    ++                toPackage(PACKAGE_NAME),
    ++                hasExtra(MainActivity.EXTRA_MESSAGE, MESSAGE)));
    ++
    ++    }
    ++}
    ++</pre>
    ++
    ++<p>
    ++  For more information about Espresso Intents, see the
    ++  <a href="https://google.github.io/android-testing-support-library/docs/espresso/intents/index.html"
    ++  class="external-link">Espresso Intents
    ++  documentation on the Android Testing Support Library site</a>.
    ++  You can also download the
    ++  <a href="https://github.com/googlesamples/android-testing/tree/master/ui/espresso/IntentsBasicSample"
    ++  class="external-link">IntentsBasicSample</a> and
    ++  <a href="https://github.com/googlesamples/android-testing/tree/master/ui/espresso/IntentsAdvancedSample"
    ++  class="external-link">IntentsAdvancedSample</a>
    ++  code samples.
    ++</p>
    ++
    ++<!-- Section 2.5 -->
    ++
    ++<h3 id="webviews">
    ++  Testing WebViews with Espresso Web
    ++</h3>
    ++
    ++<p>
    ++  Espresso Web allows you to test {@link android.webkit.WebView} components
    ++  contained within an activity. It uses the
    ++  <a href="http://docs.seleniumhq.org/docs/03_webdriver.jsp"
    ++  class="external-link">WebDriver API</a> to inspect and control the
    ++  behavior of a {@link android.webkit.WebView}.
    ++</p>
    ++
    ++<p>
    ++  To begin testing with Espresso Web, you need
    ++  to add the following line to your app's build.gradle file:
    ++</p>
    ++
    ++<pre>
    ++dependencies {
    ++  // Other dependencies ...
    ++  androidTestCompile 'com.android.support.test.espresso:espresso-web:2.2.2'
    ++}
    ++</pre>
    ++
    ++<p>
    ++  When creating a test using Espresso Web, you need to enable
    ++  JavaScript on the {@link android.webkit.WebView} when you instantiate the
    ++  <a href="{@docRoot}reference/android/support/test/rule/ActivityTestRule.html">ActivityTestRule</a>
    ++  object to test the activity. In the tests, you can select
    ++  HTML elements displayed in the
    ++  {@link android.webkit.WebView} and simulate user interactions, like
    ++  entering text into a text box and then clicking a button. After the actions
    ++  are completed, you can then verify that the results on the
    ++  Web page match the results that you expect.
    ++</p>
    ++
    ++<p>
    ++  In the following code snippet, the class tests
    ++  a {@link android.webkit.WebView} component with the id value 'webview'
    ++  in the activity being tested.
    ++  The <code>verifyValidInputYieldsSuccesfulSubmission()</code> test selects an
    ++  <code>&lt;input&gt;</code> element on the
    ++  Web page, enters some text, and checks text that appears in
    ++  another element.
    ++</p>
    ++
    ++<pre>
    ++&#64;LargeTest
    ++&#64;RunWith(AndroidJUnit4.class)
    ++public class WebViewActivityTest {
    ++
    ++    private static final String MACCHIATO = "Macchiato";
    ++    private static final String DOPPIO = "Doppio";
    ++
    ++    &#64;Rule
    ++    public ActivityTestRule<WebViewActivity> mActivityRule =
    ++        new ActivityTestRule<WebViewActivity>(WebViewActivity.class,
    ++            false /* Initial touch mode */, false /*  launch activity */) {
    ++
    ++        &#64;Override
    ++        protected void afterActivityLaunched() {
    ++            // Enable JavaScript.
    ++            onWebView().forceJavascriptEnabled();
    ++        }
    ++    }
    ++
    ++    &#64;Test
    ++    public void typeTextInInput_clickButton_SubmitsForm() {
    ++       // Lazily launch the Activity with a custom start Intent per test
    ++       mActivityRule.launchActivity(withWebFormIntent());
    ++
    ++       // Selects the WebView in your layout.
    ++       // If you have multiple WebViews you can also use a
    ++       // matcher to select a given WebView, onWebView(withId(R.id.web_view)).
    ++       onWebView()
    ++           // Find the input element by ID
    ++           .withElement(findElement(Locator.ID, "text_input"))
    ++           // Clear previous input
    ++           .perform(clearElement())
    ++           // Enter text into the input element
    ++           .perform(DriverAtoms.webKeys(MACCHIATO))
    ++           // Find the submit button
    ++           .withElement(findElement(Locator.ID, "submitBtn"))
    ++           // Simulate a click via JavaScript
    ++           .perform(webClick())
    ++           // Find the response element by ID
    ++           .withElement(findElement(Locator.ID, "response"))
    ++           // Verify that the response page contains the entered text
    ++           .check(webMatches(getText(), containsString(MACCHIATO)));
    ++    }
    ++}
    ++</pre>
    ++
    ++<p>
    ++  For more information about Espresso Web, see the
    ++  <a href="https://google.github.io/android-testing-support-library/docs/espresso/web/index.html"
    ++  class="external-link">Espresso
    ++  Web documentation on the Android Testing Support Library site.</a>.
    ++  You can also download this code snippet as part of the
    ++  <a href="https://github.com/googlesamples/android-testing/tree/master/ui/espresso/WebBasicSample"
    ++  class="external-link">Espresso Web code sample</a>.
    ++</p>
    ++
    ++<!-- Section 2.6 -->
    ++
    ++<h3 id="verify-results">
    ++  Verifying Results
    ++</h3>
    ++
    ++<p>
    ++  Call the
    ++  <a href="{@docRoot}reference/android/support/test/espresso/ViewInteraction.html#check(android.support.test.espresso.ViewAssertion)">{@code ViewInteraction.check()}</a>
    ++  or
    ++  <a href="{@docRoot}reference/android/support/test/espresso/DataInteraction.html#check(android.support.test.espresso.ViewAssertion)">{@code DataInteraction.check()}</a>
    ++  method to assert
    ++  that the view in the UI matches some expected state. You must pass in a
    ++  <a href="{@docRoot}reference/android/support/test/espresso/ViewAssertion.html">{@code ViewAssertion}</a>
    ++  object as the argument. If the assertion fails, Espresso throws
    ++  an {@link junit.framework.AssertionFailedError}.
    ++</p>
    ++
    ++<p>
    ++  The
    +   <a href="{@docRoot}reference/android/support/test/espresso/assertion/ViewAssertions.html">{@code ViewAssertions}</a>
    +-      class provides a list of helper methods for specifying common
    +-      assertions. The assertions you can use include:
    +-    </p>
    ++  class provides a list of helper methods for specifying common
    ++  assertions. The assertions you can use include:
    ++</p>
    + 
    +-    <ul>
    +-      <li>
    +-        <a href="{@docRoot}reference/android/support/test/espresso/assertion/ViewAssertions.html#doesNotExist()">{@code doesNotExist}</a>:
    +-Asserts that there is no view matching the specified criteria in the current view hierarchy.
    +-      </li>
    +-
    +-      <li>
    +-        <a href="{@docRoot}reference/android/support/test/espresso/assertion/ViewAssertions.html#matches(org.hamcrest.Matcher&lt;? super android.view.View&gt;)">{@code matches}</a>:
    +-        Asserts that the specified view exists in the current view hierarchy
    +-        and its state matches some given Hamcrest matcher.
    +-      </li>
    +-
    +-      <li>
    +-       <a href="{@docRoot}reference/android/support/test/espresso/assertion/ViewAssertions.html#selectedDescendantsMatch(org.hamcrest.Matcher&lt;android.view.View&gt;, org.hamcrest.Matcher&lt;android.view.View&gt;)">{@code selectedDescendentsMatch}</a>
    +-       : Asserts that the specified children views for a
    +-        parent view exist, and their state matches some given Hamcrest matcher.
    +-      </li>
    +-    </ul>
    ++<ul>
    ++  <li>
    ++    <a href="{@docRoot}reference/android/support/test/espresso/assertion/ViewAssertions.html#doesNotExist()">{@code doesNotExist}</a>:
    ++    Asserts that there is no view matching the specified
    ++    criteria in the current view hierarchy.
    ++  </li>
    ++
    ++  <li>
    ++    <a href="{@docRoot}reference/android/support/test/espresso/assertion/ViewAssertions.html#matches(org.hamcrest.Matcher&lt;? super android.view.View&gt;)">{@code matches}</a>:
    ++    Asserts that the specified view exists in the current view hierarchy
    ++    and its state matches some given Hamcrest matcher.
    ++  </li>
    ++
    ++  <li>
    ++    <a href="{@docRoot}reference/android/support/test/espresso/assertion/ViewAssertions.html#selectedDescendantsMatch(org.hamcrest.Matcher&lt;android.view.View&gt;, org.hamcrest.Matcher&lt;android.view.View&gt;)">{@code selectedDescendentsMatch}</a>:
    ++    Asserts that the specified children views for a
    ++    parent view exist, and their state matches some given Hamcrest matcher.
    ++  </li>
    ++</ul>
    ++
    ++<p>
    ++  The following code snippet shows how you might
    ++  check that the text displayed in the UI has
    ++  the same value as the text previously entered in the
    ++  {@link android.widget.EditText} field.
    ++</p>
    + 
    +-    <p>
    +-      The following code snippet shows how you might check that the text displayed in the UI has
    +-      the same value as the text previously entered in the
    +-      {@link android.widget.EditText} field.
    +-    </p>
    + <pre>
    + public void testChangeText_sameActivity() {
    +     // Type text and then press the button.
    +@@ -580,14 +804,22 @@ public void testChangeText_sameActivity() {
    + }
    + </pre>
    + 
    +-<h2 id="run">Run Espresso Tests on a Device or Emulator</h2>
    ++<!-- Section 3 -->
    ++
    ++<h2 id="run">
    ++  Run Espresso Tests on a Device or Emulator
    ++</h2>
    ++
    + <p>
    +-You can run Espresso tests from <a href="{@docRoot}studio/index.html">Android Studio</a> or
    +-from the command-line. Make sure to specify
    +-<a href="{@docRoot}reference/android/support/test/runner/AndroidJUnitRunner.html">
    +-  {@code AndroidJUnitRunner}</a> as the default instrumentation runner in your project.
    ++  You can run Espresso tests from
    ++  <a href="{@docRoot}studio/index.html">Android Studio</a> or
    ++  from the command-line. Make sure to specify
    ++  <a href="{@docRoot}reference/android/support/test/runner/AndroidJUnitRunner.html">{@code AndroidJUnitRunner}</a>
    ++  as the default instrumentation runner in your project.
    + </p>
    ++
    + <p>
    +-To run your Espresso test, follow the steps for running instrumented tests
    +-described in <a href="{@docRoot}training/testing/start/index.html#run-instrumented-tests">
    +-Getting Started with Testing</a>.</p>
    ++  To run your Espresso test, follow the steps for running instrumented tests
    ++  described in
    ++  <a href="{@docRoot}training/testing/start/index.html#run-instrumented-tests">Getting Started with Testing</a>.
    ++</p>
    +diff --git a/docs/html/training/testing/unit-testing/instrumented-unit-tests.jd b/docs/html/training/testing/unit-testing/instrumented-unit-tests.jd
    +index 8fc4dca..dc94bdf 100644
    +--- a/docs/html/training/testing/unit-testing/instrumented-unit-tests.jd
    ++++ b/docs/html/training/testing/unit-testing/instrumented-unit-tests.jd
    +@@ -53,8 +53,9 @@ you choose, to simulate any dependency relationships.</p>
    + 
    + <p>In your Android Studio project, you must store the source files for
    + instrumented tests at
    +-<code><var>module-name</var>/src/androidTests/java/</code>. This directory
    +-already exists when you create a new project.</p>
    ++<code><var>module-name</var>/src/androidTest/java/</code>. This directory
    ++already exists when you create a new project and contains an example
    ++instrumented test.</p>
    + 
    + <p>Before you begin, you should
    +   <a href="{@docRoot}tools/testing-support-library/index.html#setup">download
    +@@ -292,23 +293,21 @@ from the command line. Test results provide test logs and include the details
    + of any app failures.</p>
    + 
    + <p>
    +-  Before you can start using Firebase Test Lab, you need to:
    ++  Before you can start using Firebase Test Lab, you need to do the following
    ++unless you already have a Google account and a Firebase project with the Blaze
    ++billing plan enabled:
    + </p>
    + 
    + <ol>
    +-  <li>
    +-    <a href="https://console.developers.google.com/freetrial">Create a
    +-    Google Cloud Platform account</a> to use with active billing.
    +-  </li>
    +-
    +-  <li>
    +-    <a href="https://support.google.com/cloud/answer/6251787">Create a Google
    +-    Cloud project</a> for your app.
    +-  </li>
    +-
    +-  <li>
    +-    <a href="https://support.google.com/cloud/answer/6288653">Set up an active
    +-    billing account</a> and associate it with the project you just created.
    ++  <li><a href="https://accounts.google.com/">Create a Google account</a>,
    ++  if you don't have one already.</li>
    ++  <li>In the <a href="https://console.firebase.google.com/">Firebase
    ++  console</a>, click <b>Create New Project</b>.</li>
    ++  <li>In the Firebase console, click <b>Upgrade</b>, and then click <b>Select
    ++Plan</b> in the <b>Blaze</b> plan column.
    ++    <p class="note"><b>Note</b>: To learn about billing,
    ++see <a href="https://firebase.google.com/docs/test-lab/overview#billing">Test
    ++Lab billing</a>.</p>
    +   </li>
    + </ol>
    + 
    +@@ -318,10 +317,10 @@ Configure a test matrix and run a test
    + </h4>
    + 
    + <p>
    +-  Android Studio provides integrated tools that allow you to configure how you
    +- want to deploy your tests to Firebase Test Lab. After you have created a Google
    +-  Cloud project with active billing, you can create a test configuration and
    +-  run your tests:
    ++Android Studio provides integrated tools that allow you to configure how you
    ++want to deploy your tests to Firebase Test Lab. After you have created a
    ++Firebase project with Blaze plan billing, you can create a test configuration
    ++and run your tests:
    + </p>
    + 
    + <ol>
    +@@ -329,7 +328,8 @@ Configure a test matrix and run a test
    +   the main menu.
    +   </li>
    + 
    +-  <li>Click <strong>Add New Configuration (+)</strong> and select
    ++  <li>Click <strong>Add New Configuration</strong> <img
    ++src="/studio/images/buttons/ic_plus.png" alt="" class="inline-icon"/> and select
    +   <strong>Android Tests</strong>.
    +   </li>
    + 
    +@@ -340,7 +340,7 @@ Configure a test matrix and run a test
    +       </li>
    + 
    +       <li>From the <em>Target</em> drop-down menu under <em>Deployment Target
    +-      Options</em>, select <strong>Cloud Test Lab Device Matrix</strong>.
    ++      Options</em>, select <strong>Firebase Test Lab Device Matrix</strong>.
    +       </li>
    + 
    +       <li>If you are not logged in, click <strong>Connect to Google Cloud
    +@@ -348,9 +348,9 @@ Configure a test matrix and run a test
    +       </li>
    + 
    +       <li>Next to <em>Cloud Project</em>, click the <img src=
    +-      "{@docRoot}images/tools/as-wrench.png" alt="wrench and nut" style=
    +-      "vertical-align:bottom;margin:0;"> button and select your Google Cloud
    +-      Platform project from the list.
    ++      "{@docRoot}images/tools/as-wrench.png" alt="" class="inline-icon"/>
    ++      button and select your Firebase
    ++      project from the list.
    +       </li>
    +     </ol>
    +   </li>
    +@@ -359,7 +359,7 @@ Configure a test matrix and run a test
    +     <ol type="a">
    +       <li>Next to the <em>Matrix Configuration</em> drop-down list, click <strong>
    +         Open Dialog</strong> <img src="{@docRoot}images/tools/as-launchavdm.png"
    +-        alt="ellipses button" style="vertical-align:bottom;margin:0;">.
    ++        alt="" class="inline-icon">.
    +       </li>
    + 
    +       <li>Click <strong>Add New Configuration (+)</strong>.
    +@@ -385,8 +385,7 @@ Configure a test matrix and run a test
    +   </li>
    + 
    +   <li>Run your tests by clicking <strong>Run</strong> <img src=
    +-  "{@docRoot}images/tools/as-run.png" alt="" style=
    +-  "vertical-align:bottom;margin:0;">.
    ++  "{@docRoot}images/tools/as-run.png" alt="" class="inline-icon"/>.
    +   </li>
    + </ol>
    + 
    +@@ -404,7 +403,7 @@ Configure a test matrix and run a test
    +   When Firebase Test Lab completes running your tests, the <em>Run</em> window
    +   will open to show the results, as shown in figure 2. You may need to click
    +   <strong>Show Passed</strong> <img src="{@docRoot}images/tools/as-ok.png" alt=
    +-  "" style="vertical-align:bottom;margin:0;"> to see all your executed tests.
    ++  "" class="inline-icon"/> to see all your executed tests.
    + </p>
    + 
    + <img src="{@docRoot}images/training/ctl-test-results.png" alt="">
    +@@ -416,15 +415,7 @@ Configure a test matrix and run a test
    + 
    + <p>
    +   You can also analyze your tests on the web by following the link displayed at
    +-  the beginning of the test execution log in the <em>Run</em> window, as shown
    +-  in figure 3.
    +-</p>
    +-
    +-<img src="{@docRoot}images/training/ctl-exec-log.png" alt="">
    +-
    +-<p class="img-caption">
    +-  <strong>Figure 3.</strong> Click the link to view detailed test results on
    +-  the web.
    ++  the beginning of the test execution log in the <em>Run</em> window.
    + </p>
    + 
    + <p>
    +diff --git a/docs/html/training/training_toc.cs b/docs/html/training/training_toc.cs
    +index d0dccba..d2bf881 100644
    +--- a/docs/html/training/training_toc.cs
    ++++ b/docs/html/training/training_toc.cs
    +@@ -649,25 +649,7 @@
    +           </li>
    +         </ul>
    +       </li>
    +-
    +       <li class="nav-section">
    +-        <div class="nav-section-header">
    +-          <a href="<?cs var:toroot ?>training/backup/index.html"
    +-             description=
    +-             "How to sync and back up app and user data to remote web services in the
    +-              cloud and how to restore the data back to multiple devices."
    +-            >Backing up App Data to the Cloud</a>
    +-        </div>
    +-        <ul>
    +-          <li><a href="<?cs var:toroot ?>training/backup/autosyncapi.html">
    +-            Configuring Auto Backup
    +-          </a>
    +-          </li>
    +-          <li><a href="<?cs var:toroot ?>training/backup/backupapi.html">
    +-            Using the Backup API
    +-          </a>
    +-          </li>
    +-        </ul>
    +         <li><a href="<?cs var:toroot ?>training/cloudsave/conflict-res.html"
    +            description=
    +            "How to design a robust conflict resolution strategy for apps that save data to the cloud."
    +@@ -1888,6 +1870,12 @@ results."
    +           >Managing Your App's Memory</a>
    +       </li>
    +       <li>
    ++        <a href="<?cs var:toroot ?>training/articles/memory-overview.html"
    ++          description=
    ++          "How Android manages app process and memory allocation."
    ++          >Overview of Android Memory Management</a>
    ++      </li>
    ++      <li>
    +         <a href="<?cs var:toroot ?>training/articles/perf-tips.html"
    +            description=
    +            "How to optimize your app's performance in various ways to improve its
    +diff --git a/docs/html/training/tv/playback/card.jd b/docs/html/training/tv/playback/card.jd
    +index a3a9872..2391185 100644
    +--- a/docs/html/training/tv/playback/card.jd
    ++++ b/docs/html/training/tv/playback/card.jd
    +@@ -43,7 +43,7 @@ Leanback sample app</a> image card view when selected.</p>
    + on demand. In the browse fragment where your app presents its content to the user, you create a
    + {@link android.support.v17.leanback.widget.Presenter} for the content cards and pass it to the adapter
    + that adds the content to the screen. In the following code, the <code>CardPresenter</code> is created
    +-in the {@link android.support.v4.app.LoaderManager.LoaderCallbacks#onLoadFinished(android.support.v4.content.Loader, java.lang.Object) onLoadFinished()}
    ++in the {@link android.support.v4.app.LoaderManager.LoaderCallbacks#onLoadFinished onLoadFinished()}
    + callback of the {@link android.support.v4.app.LoaderManager}.</p>
    + 
    + <pre>
    +diff --git a/docs/html/training/tv/playback/index.jd b/docs/html/training/tv/playback/index.jd
    +index d5e4e67..34c6287 100644
    +--- a/docs/html/training/tv/playback/index.jd
    ++++ b/docs/html/training/tv/playback/index.jd
    +@@ -69,6 +69,10 @@ startpage=true
    +     <dd>Learn how to use the Leanback support library to guide a user through a series of
    +     decisions.</dd>
    + 
    ++  <dt><b><a href="onboarding.html">Introducing First-time Users to Your App</a></b></dt>
    ++    <dd>Learn how to use the Leanback support library to show first-time users
    ++    how to get the most out of your app.</dd>
    ++
    +   <dt><b><a href="options.html">Enabling Background Playback</a></b></dt>
    +     <dd>Learn how to continue playback when the user clicks on <strong>Home</strong>.</dd>
    + </dl>
    +diff --git a/docs/html/training/tv/playback/onboarding.jd b/docs/html/training/tv/playback/onboarding.jd
    +new file mode 100644
    +index 0000000..bb41bec
    +--- /dev/null
    ++++ b/docs/html/training/tv/playback/onboarding.jd
    +@@ -0,0 +1,377 @@
    ++page.title=Introducing First-time Users to Your App
    ++page.tags=tv,onboarding,OnboardingFragment
    ++page.keywords=tv,onboarding,OnboardingFragment
    ++helpoutsWidget=true
    ++
    ++trainingnavtop=true
    ++
    ++@jd:body
    ++
    ++<div id="tb-wrapper">
    ++<div id="tb">
    ++  <h2>This lesson teaches you to</h2>
    ++  <ol>
    ++    <li><a href="#addFragment">Add an OnboardingFragment</a></li>
    ++    <li><a href="#pageContent">Add OnboardingFragment Pages</a></li>
    ++    <li><a href="#logoScreen">Add an Initial Logo Screen</a></li>
    ++    <li><a href="#pageAnimations">Customize Page Animations</a></li>
    ++    <li><a href="#themes">Customize Themes</a></li>
    ++  </ol>
    ++  <h2>Try it out</h2>
    ++  <ul>
    ++    <li><a class="external-link" href="https://github.com/googlesamples/androidtv-Leanback">Android
    ++    Leanback sample app</a></li>
    ++  </ul>
    ++</div>
    ++</div>
    ++
    ++<p>
    ++To show a first-time user how to get the most from your app, present
    ++onboarding information at app startup. Here are some examples of onboarding
    ++information:
    ++</p>
    ++
    ++<ul>
    ++<li>Present detailed information on which channels are available when a user
    ++first accesses a channel app.</li>
    ++<li>Call attention to noteworthy features in your app.</li>
    ++<li>Illustrate any required or recommended steps that users should take when
    ++using the app for the first time.</li>
    ++</ul>
    ++
    ++<p>The <a href=
    ++"{@docRoot}tools/support-library/features.html#v17-leanback">v17 Leanback
    ++support library</a> provides the
    ++{@link android.support.v17.leanback.app.OnboardingFragment} class for
    ++presenting first-time user information. This lesson describes how to use the
    ++{@link android.support.v17.leanback.app.OnboardingFragment} class to present
    ++introductory information that is shown when the app launches for the first
    ++time. {@link android.support.v17.leanback.app.OnboardingFragment} uses TV UI
    ++best practices to present the information in a way that matches TV UI styles,
    ++and is easy to navigate on TV devices.</p>
    ++
    ++<img src="{@docRoot}images/training/tv/playback/onboarding-fragment.png"
    ++srcset="{@docRoot}images/training/tv/playback/onboarding-fragment.png 1x,
    ++{@docRoot}images/training/tv/playback/onboarding-fragment_2x.png 2x" />
    ++<p class="img-caption"><strong>Figure 1.</strong> An example
    ++OnboardingFragment.</p>
    ++
    ++<p>Your {@link android.support.v17.leanback.app.OnboardingFragment} should
    ++not contain UI elements that require user input, such as buttons and fields.
    ++Similarly, it should not be used as a UI element for a task the user will do
    ++regularly. If you need to present a multi-page UI that requires
    ++user input, consider using a
    ++{@link android.support.v17.leanback.app.GuidedStepFragment}.</p>
    ++
    ++<h2 id="addFragment">Add an OnboardingFragment</h2>
    ++
    ++<p>To add an {@link android.support.v17.leanback.app.OnboardingFragment}
    ++to your app, implement a class that extends
    ++the {@link android.support.v17.leanback.app.OnboardingFragment} class. Add
    ++this fragment to an activity, either via the activity's layout XML, or
    ++programmatically. Make sure the activity or
    ++fragment is using a theme derived from
    ++{@link android.support.v17.leanback.R.style#Theme_Leanback_Onboarding},
    ++as described in <a href="#themes">Customize Themes</a>.</p>
    ++
    ++<p>In the {@link android.app.Activity#onCreate onCreate()} method of your
    ++app's main activity, call
    ++{@link android.app.Activity#startActivity startActivity()}
    ++with an {@link android.content.Intent} that points to your
    ++{@link android.support.v17.leanback.app.OnboardingFragment OnboardingFragment's}
    ++parent activity. This ensures that your
    ++{@link android.support.v17.leanback.app.OnboardingFragment} appears as
    ++soon as your app starts.<p>
    ++
    ++<p>To ensure that the
    ++{@link android.support.v17.leanback.app.OnboardingFragment} only appears the
    ++first time that the user starts your app, use a
    ++{@link android.content.SharedPreferences} object
    ++to track whether the user has already viewed the
    ++{@link android.support.v17.leanback.app.OnboardingFragment}. Define a boolean
    ++value that changes to true when the user finishes viewing the
    ++{@link android.support.v17.leanback.app.OnboardingFragment}. Check
    ++this value in your main activity’s
    ++{@link android.app.Activity#onCreate onCreate()}, and only start the
    ++{@link android.support.v17.leanback.app.OnboardingFragment} parent activity if
    ++the value is false. The following example shows an override of
    ++{@link android.app.Activity#onCreate onCreate()} that checks for a
    ++{@link android.content.SharedPreferences} value and, if not set to true, calls
    ++{@link android.app.Activity#startActivity startActivity()} to
    ++show the {@link android.support.v17.leanback.app.OnboardingFragment}:</p>
    ++
    ++<pre>
    ++&#64;Override
    ++protected void onCreate(Bundle savedInstanceState) {
    ++    super.onCreate(savedInstanceState);
    ++    setContentView(R.layout.activity_main);
    ++    SharedPreferences sharedPreferences =
    ++            PreferenceManager.getDefaultSharedPreferences(this);
    ++    // Check if we need to display our OnboardingFragment
    ++    if (!sharedPreferences.getBoolean(
    ++            MyOnboardingFragment.COMPLETED_ONBOARDING_PREF_NAME, false)) {
    ++        // The user hasn't seen the OnboardingFragment yet, so show it
    ++        startActivity(new Intent(this, OnboardingActivity.class));
    ++    }
    ++}
    ++</pre>
    ++
    ++<p>After the user views the
    ++{@link android.support.v17.leanback.app.OnboardingFragment}, mark it as viewed
    ++using the {@link android.content.SharedPreferences} object. To do this, in your
    ++{@link android.support.v17.leanback.app.OnboardingFragment}, override
    ++{@link android.support.v17.leanback.app.OnboardingFragment#onFinishFragment
    ++onFinishFragment()} and set your {@link android.content.SharedPreferences} value
    ++to true, as shown in the following example:
    ++
    ++<pre>
    ++&#64;Override
    ++protected void onFinishFragment() {
    ++    super.onFinishFragment();
    ++    // User has seen OnboardingFragment, so mark our SharedPreferences
    ++    // flag as completed so that we don't show our OnboardingFragment
    ++    // the next time the user launches the app.
    ++    SharedPreferences.Editor sharedPreferencesEditor =
    ++            PreferenceManager.getDefaultSharedPreferences(getContext()).edit();
    ++    sharedPreferencesEditor.putBoolean(
    ++            COMPLETED_ONBOARDING_PREF_NAME, true);
    ++    sharedPreferencesEditor.apply();
    ++}
    ++</pre>
    ++
    ++<h2 id="pageContent">Add OnboardingFragment Pages</h2>
    ++
    ++<p>After you add your
    ++{@link android.support.v17.leanback.app.OnboardingFragment}, you need to define
    ++the onboarding pages. An
    ++{@link android.support.v17.leanback.app.OnboardingFragment} displays content
    ++in a series of ordered pages. Each page can have a title, description, and
    ++several sub-views that can contain images or animations.</p>
    ++
    ++<img src="{@docRoot}images/training/tv/playback/onboarding-fragment-diagram.png"
    ++/><p class="img-caption"><strong>Figure 2.</strong> OnboardingFragment
    ++page elements.
    ++</p>
    ++
    ++<p>Figure 2 shows an example page with callouts marking customizable page
    ++elements that your {@link android.support.v17.leanback.app.OnboardingFragment}
    ++can provide. The page elements are:</p>
    ++
    ++<ol>
    ++<li>The page title.</li>
    ++<li>The page description.</li>
    ++<li>The page content view, in this case a simple green checkmark in a grey box.
    ++This view is optional. Use this view to illustrate page details such as a
    ++screenshot that highlights the app feature that the page describes.</li>
    ++<li>The page background view, in this case a simple blue gradient. This view
    ++always renders behind other views on the page. This view is optional.</li>
    ++<li>The page foreground view, in this case a logo. This view always renders
    ++in front of all other views on the page. This view is optional.</li>
    ++</ol>
    ++
    ++<p>Initialize page information when your
    ++{@link android.support.v17.leanback.app.OnboardingFragment} is first created
    ++or attached to the parent activity, as the system requests page
    ++information when it creates the fragment's view. You can initialize page
    ++information in your class constructor or in an override of
    ++{@link android.app.Fragment#onAttach onAttach()}.</p>
    ++
    ++<p>Override each of the following methods that provide page information
    ++to the system:</p>
    ++
    ++<ul>
    ++<li>{@link android.support.v17.leanback.app.OnboardingFragment#getPageCount
    ++getPageCount()} returns the number of pages in your
    ++{@link android.support.v17.leanback.app.OnboardingFragment}.</li>
    ++<li>{@link android.support.v17.leanback.app.OnboardingFragment#getPageTitle
    ++getPageTitle()} returns the title for the requested page number.</li>
    ++<li>{@link android.support.v17.leanback.app.OnboardingFragment#getPageDescription
    ++getPagedescription()} returns the description for the requested page
    ++number.</li>
    ++</ul>
    ++
    ++<p>Override each of the following methods to provide optional sub-views used
    ++to display images or animations:</p>
    ++
    ++<ul>
    ++<li>{@link android.support.v17.leanback.app.OnboardingFragment#onCreateBackgroundView
    ++onCreateBackgroundView()} returns a {@link android.view.View} that you
    ++create to act as the background view, or null if no background view is needed.
    ++<li>{@link android.support.v17.leanback.app.OnboardingFragment#onCreateContentView
    ++onCreateContentView()} returns a {@link android.view.View} that you
    ++create to act as the content view, or null if no content view is needed.
    ++<li>{@link android.support.v17.leanback.app.OnboardingFragment#onCreateForegroundView
    ++onCreateForegroundView()} returns a {@link android.view.View} that you
    ++create to act as the foreground view, or null if no foreground view is needed.
    ++</ul>
    ++
    ++<p>The system adds the {@link android.view.View} that you create to the page
    ++layout. The following example overrides
    ++{@link android.support.v17.leanback.app.OnboardingFragment#onCreateContentView
    ++onCreateContentView()} and returns an {@link android.widget.ImageView}:</p>
    ++
    ++<pre>
    ++private ImageView mContentView;
    ++...
    ++&#64;Override
    ++protected View onCreateContentView(LayoutInflater inflater, ViewGroup container) {
    ++    mContentView = new ImageView(getContext());
    ++    mContentView.setScaleType(ImageView.ScaleType.CENTER_INSIDE);
    ++    mContentView.setImageResource(R.drawable.onboarding_content_view);
    ++    mContentView.setPadding(0, 32, 0, 32);
    ++    return mContentView;
    ++}
    ++</pre>
    ++
    ++<h2 id="logoScreen">Add an Initial Logo Screen</h2>
    ++
    ++<p>Your {@link android.support.v17.leanback.app.OnboardingFragment} can start
    ++with an optional logo screen that introduces your app. If you want to display
    ++a {@link android.graphics.drawable.Drawable} as your logo screen, in your
    ++{@link android.support.v17.leanback.app.OnboardingFragment OnboardingFragment's}
    ++{@link android.app.Fragment#onCreate onCreate()} method, call
    ++{@link android.support.v17.leanback.app.OnboardingFragment#setLogoResourceId
    ++setLogoResourceId()} with the ID of your
    ++{@link android.graphics.drawable.Drawable}. The
    ++system will fade in and briefly display this
    ++{@link android.graphics.drawable.Drawable}, and then fade out the
    ++{@link android.graphics.drawable.Drawable}
    ++before displaying the first page of your
    ++{@link android.support.v17.leanback.app.OnboardingFragment}.</p>
    ++
    ++<p>If you want to provide a custom animation for your logo screen, instead of
    ++calling
    ++{@link android.support.v17.leanback.app.OnboardingFragment#setLogoResourceId
    ++setLogoResourceId()}, override
    ++{@link android.support.v17.leanback.app.OnboardingFragment#onCreateLogoAnimation
    ++onCreateLogoAnimation()} and return an {@link android.animation.Animator}
    ++object that renders your custom animation, as shown in the following example:
    ++</p>
    ++
    ++<pre>
    ++&#64;Override
    ++public Animator onCreateLogoAnimation() {
    ++    return AnimatorInflater.loadAnimator(mContext,
    ++            R.animator.onboarding_logo_screen_animation);
    ++}
    ++</pre>
    ++
    ++<h2 id="pageAnimations">Customize Page Animations</h2>
    ++
    ++<p>The system uses default animations when displaying the first page of your
    ++{@link android.support.v17.leanback.app.OnboardingFragment} and when the user
    ++navigates to a different page. You can customize these animations by
    ++overriding methods in your
    ++{@link android.support.v17.leanback.app.OnboardingFragment}.</p>
    ++
    ++<p>To customize the animation that appears on your first page,
    ++override
    ++{@link android.support.v17.leanback.app.OnboardingFragment#onCreateEnterAnimation
    ++onCreateEnterAnimation()} and return an {@link android.animation.Animator}.
    ++The following example creates an
    ++{@link android.animation.Animator} that scales the content view
    ++horizontally:</p>
    ++
    ++<pre>
    ++&#64;Override
    ++protected Animator onCreateEnterAnimation() {
    ++    Animator startAnimator = ObjectAnimator.ofFloat(mContentView,
    ++            View.SCALE_X, 0.2f, 1.0f).setDuration(ANIMATION_DURATION);
    ++    return startAnimator;
    ++}
    ++</pre>
    ++
    ++<p>To customize the animation used when the user navigates to a different page,
    ++override
    ++{@link android.support.v17.leanback.app.OnboardingFragment#onPageChanged
    ++onPageChanged()}. In your
    ++{@link android.support.v17.leanback.app.OnboardingFragment#onPageChanged
    ++onPageChanged()} method, create {@link android.animation.Animator Animators}
    ++that remove the previous page and display the next page, add these to an
    ++{@link android.animation.AnimatorSet}, and play the set. The following
    ++example uses a fade-out animation to remove the previous page, updates the
    ++content view image, and uses a fade-in animation to display the next page:</p>
    ++
    ++<pre>
    ++&#64;Override
    ++protected void onPageChanged(final int newPage, int previousPage) {
    ++    // Create a fade-out animation used to fade out previousPage and, once
    ++    // done, swaps the contentView image with the next page's image.
    ++    Animator fadeOut = ObjectAnimator.ofFloat(mContentView,
    ++            View.ALPHA, 1.0f, 0.0f).setDuration(ANIMATION_DURATION);
    ++    fadeOut.addListener(new AnimatorListenerAdapter() {
    ++        &#64;Override
    ++        public void onAnimationEnd(Animator animation) {
    ++            mContentView.setImageResource(pageImages[newPage]);
    ++        }
    ++    });
    ++    // Create a fade-in animation used to fade in nextPage
    ++    Animator fadeIn = ObjectAnimator.ofFloat(mContentView,
    ++            View.ALPHA, 0.0f, 1.0f).setDuration(ANIMATION_DURATION);
    ++    // Create AnimatorSet with our fade-out and fade-in animators, and start it
    ++    AnimatorSet set = new AnimatorSet();
    ++    set.playSequentially(fadeOut, fadeIn);
    ++    set.start();
    ++}
    ++</pre>
    ++
    ++<p>For more details about how to create
    ++{@link android.animation.Animator Animators} and
    ++{@link android.animation.AnimatorSet AnimatorSets}, see
    ++<a href="https://developer.android.com/guide/topics/graphics/prop-animation.html">
    ++Property Animations</a>.</p>
    ++
    ++<h2 id="themes">Customize Themes</h2>
    ++
    ++<p>Any {@link android.support.v17.leanback.app.OnboardingFragment}
    ++implementation must use either the
    ++{@link android.support.v17.leanback.R.style#Theme_Leanback_Onboarding} theme
    ++or a theme that inherits from
    ++{@link android.support.v17.leanback.R.style#Theme_Leanback_Onboarding}. Set the
    ++theme for your {@link android.support.v17.leanback.app.OnboardingFragment} by
    ++doing one of the following:</p>
    ++
    ++<ul>
    ++<li>Set the {@link android.support.v17.leanback.app.OnboardingFragment
    ++OnboardingFragment's} parent activity to use the desired theme. The following
    ++example shows how to set an activity to use
    ++{@link android.support.v17.leanback.R.style#Theme_Leanback_Onboarding} in the
    ++app manifest:
    ++<pre>
    ++&lt;activity
    ++   android:name=".OnboardingActivity"
    ++   android:enabled="true"
    ++   android:exported="true"
    ++   android:theme="&#64;style/Theme.Leanback.Onboarding"&gt;
    ++&lt;/activity&gt;
    ++</pre>
    ++</li>
    ++<li>
    ++Set the theme in the parent activity by using the
    ++{@link android.support.v17.leanback.R.styleable#LeanbackOnboardingTheme_onboardingTheme}
    ++attribute in a custom activity theme. Point this attribute to another
    ++custom theme that only the
    ++{@link android.support.v17.leanback.app.OnboardingFragment}
    ++objects in your activity use. Use this approach if your activity already uses
    ++a custom theme and you don't want to apply
    ++{@link android.support.v17.leanback.app.OnboardingFragment} styles to other
    ++views in the activity.
    ++</li>
    ++<li>Override
    ++{@link android.support.v17.leanback.app.OnboardingFragment#onProvideTheme
    ++onProvideTheme()} and return the desired theme. Use this approach if
    ++multiple activities use your
    ++{@link android.support.v17.leanback.app.OnboardingFragment}
    ++or if the parent activity can't use the desired theme.
    ++The following example overrides
    ++{@link android.support.v17.leanback.app.OnboardingFragment#onProvideTheme
    ++onProvideTheme()} and returns
    ++{@link android.support.v17.leanback.R.style#Theme_Leanback_Onboarding}:
    ++<pre>
    ++&#64;Override
    ++public int onProvideTheme() {
    ++   return R.style.Theme_Leanback_Onboarding;
    ++}
    ++</pre>
    ++</li>
    ++</ul>
    +\ No newline at end of file
    +diff --git a/docs/html/training/tv/start/hardware.jd b/docs/html/training/tv/start/hardware.jd
    +index 97cf7ff..0639871 100644
    +--- a/docs/html/training/tv/start/hardware.jd
    ++++ b/docs/html/training/tv/start/hardware.jd
    +@@ -227,13 +227,19 @@ if (uiModeManager.getCurrentModeType() == Configuration.UI_MODE_TYPE_TELEVISION)
    +   </tr>
    +   <tr>
    +     <td>{@link android.Manifest.permission#ACCESS_COARSE_LOCATION}</td>
    +-    <td>{@code android.hardware.location} <em>and</em> <br>
    +-      {@code android.hardware.location.network}</td>
    ++    <td>
    ++      <p>{@code android.hardware.location}</p>
    ++      <p>{@code android.hardware.location.network} (Target API level 20 or lower
    ++      only.)</p>
    ++    </td>
    +   </tr>
    +   <tr>
    +     <td>{@link android.Manifest.permission#ACCESS_FINE_LOCATION}</td>
    +-    <td>{@code android.hardware.location} <em>and</em> <br>
    +-      {@code android.hardware.location.gps}</td>
    ++    <td>
    ++      <p>{@code android.hardware.location}</p>
    ++      <p>{@code android.hardware.location.gps} (Target API level 20 or lower
    ++      only.)</p>
    ++    </td>
    +   </tr>
    + </table>
    + 
    +@@ -246,6 +252,13 @@ if (uiModeManager.getCurrentModeType() == Configuration.UI_MODE_TYPE_TELEVISION)
    +   required ({@code android:required="false"}).
    + </p>
    + 
    ++<p class="note">
    ++  <strong>Note:</strong> If your app targets Android 5.0 (API level 21) or
    ++  higher and uses the <code>ACCESS_COARSE_LOCATION</code> or
    ++  <code>ACCESS_FINE_LOCATION</code> permission, users can still install your
    ++  app on a TV device, even if the TV device doesn't have a network card or a GPS
    ++  receiver.
    ++</p>
    + 
    + <h3 id="check-features">Checking for hardware features</h2>
    + 
    +diff --git a/docs/html/training/tv/tif/tvinput.jd b/docs/html/training/tv/tif/tvinput.jd
    +index 1a53398..2153ef8 100644
    +--- a/docs/html/training/tv/tif/tvinput.jd
    ++++ b/docs/html/training/tv/tif/tvinput.jd
    +@@ -10,9 +10,8 @@ trainingnavtop=true
    + <div id="tb">
    +   <h2>This lesson teaches you to</h2>
    +   <ol>
    +-    <li><a href="#manifest">Declare Your TV Input Service in the Manifest</a></li>
    +-    <li><a href="#tvinput">Define Your TV Input Service</a></li>
    +-    <li><a href="#setup">Define Your Setup Activity</a></li>
    ++    <li><a href="#TIFCompanion">Create a TV Input Service Using the TIF Companion Library</a></li>
    ++    <li><a href="#NoTIFCompanion">Create a TV Input Service Using the TIF Framework</a></li>
    +   </ol>
    +   <h2>You should also read</h2>
    +   <ul>
    +@@ -30,14 +29,253 @@ trainingnavtop=true
    + </div>
    + 
    + <p>A TV input service represents a media stream source, and lets you present your media content in a
    +-linear, broadcast TV fashion as channels and programs. With the TV input service, you can provide
    ++linear, broadcast TV fashion as channels and programs. With a TV input service, you can provide
    + parental controls, program guide information, and content ratings. The TV input service works
    +-with the Android system TV app, developed for the device and immutable by third-party apps, which
    +-ultimately controls and presents content on the TV. See
    ++with the Android system TV app. This app ultimately controls and presents channel content
    ++on the TV. The system TV app is developed specifically for the device and immutable
    ++by third-party apps. For more information about the TV Input Framework (TIF)
    ++architecture and its components, see
    + <a class="external-link" href="http://source.android.com/devices/tv/index.html">
    +-TV Input Framework</a> for more information about the framework architecture and its components.</p>
    ++TV Input Framework</a>.</p>
    + 
    +-<p>To develop a TV input service, you implement the following components:</p>
    ++<h2 id="TIFCompanion">Create a TV Input Service Using the TIF Companion Library</h2>
    ++
    ++<p>
    ++The TIF Companion Library is a framework that provides extensible
    ++implementations of common TV input service features. Use the TIF Companion
    ++Library to quickly and easily create your own TV input service that follows
    ++best practices for Android TV.
    ++</p>
    ++
    ++<h3 id="build">Update your build.gradle file</h3>
    ++
    ++<p>
    ++To get started using the TIF Companion Library, add the following line to your
    ++app's <code>build.gradle</code> file:
    ++</p>
    ++
    ++<pre>
    ++compile 'com.google.android.media.tv.companionlibrary:1.0.0'
    ++</pre>
    ++
    ++<p>The TIF Companion Library is not currently part of the Android
    ++framework. It is distributed as part of the <a class="external-link"
    ++href="https://github.com/googlesamples/androidtv-sample-inputs">
    ++TV Input Service sample app</a>, and not with the Android SDK.
    ++</p>
    ++
    ++<h3 id="manifest">Declare your TV input service in the manifest</h3>
    ++
    ++<p>Your app must provide a {@link android.media.tv.TvInputService}-compatible
    ++service that the system uses to access your app. The TIF
    ++Companion Library provides the <code>BaseTvInputService</code> class, which
    ++provides a default implementation of {@link android.media.tv.TvInputService}
    ++that you can customize. Create a subclass of <code>BaseTvInputService</code>,
    ++and declare the subclass in your manifest as a service.</p>
    ++
    ++<p>Within the manifest declaration, specify the
    ++{@link android.Manifest.permission#BIND_TV_INPUT} permission to allow the
    ++service to connect the TV input to the system. A system service
    ++performs the binding and has the
    ++{@link android.Manifest.permission#BIND_TV_INPUT} permission.
    ++The system TV app sends requests to TV input services
    ++via the {@link android.media.tv.TvInputManager} interface.</p>
    ++
    ++<p>In your service declaration, include an intent filter that specifies
    ++{@link android.media.tv.TvInputService} as the action to perform with the
    ++intent. Also declare the service metadata as a separate XML resource. The
    ++service declaration, intent filter, and service metadata declaration are shown
    ++in the following example:</p>
    ++
    ++<pre>
    ++&lt;service android:name=".rich.RichTvInputService"
    ++    android:label="@string/rich_input_label"
    ++    android:permission="android.permission.BIND_TV_INPUT"&gt;
    ++    &lt;!-- Required filter used by the system to launch our account service. --&gt;
    ++    &lt;intent-filter&gt;
    ++        &lt;action android:name="android.media.tv.TvInputService" /&gt;
    ++    &lt;/intent-filter&gt;
    ++    &lt;!-- An XML file which describes this input. This provides pointers to
    ++    the RichTvInputSetupActivity to the system/TV app. --&gt;
    ++    &lt;meta-data
    ++        android:name="android.media.tv.input"
    ++        android:resource="@xml/richtvinputservice" /&gt;
    ++&lt;/service&gt;
    ++</pre>
    ++
    ++<p>Define the service metadata in a separate XML file. The service
    ++metadata XML file must include a setup interface that describes the TV input's
    ++initial configuration and channel scan. The metadata file should also contain a
    ++flag stating whether or not users are able to record content. For more
    ++information on how to support recording content in your app, see
    ++<a href="{@docRoot}preview/features/tv-recording-api.html">TV Recording</a>.
    ++</p>
    ++
    ++<p>The service metadata file is located in the XML resources directory
    ++for your app and must match the name of the resource you declared in the
    ++manifest. Using the manifest entries from the previous example, you would
    ++create the XML file at <code>res/xml/richtvinputservice.xml</code>, with the
    ++following contents:</p>
    ++
    ++<pre>
    ++&lt;?xml version="1.0" encoding="utf-8"?&gt;
    ++&lt;tv-input xmlns:android="http://schemas.android.com/apk/res/android"
    ++  android:canRecord="true"
    ++  android:setupActivity="com.example.android.sampletvinput.rich.RichTvInputSetupActivity" /&gt;
    ++</pre>
    ++
    ++<h3 id="setup">Define channels and create your setup activity</h3>
    ++
    ++<p>Your TV input service must define at least one channel that users
    ++access via the system TV app. You should register your channels
    ++in the system database, and provide a setup activity that the system
    ++invokes when it cannot find a channel for your app.</p>
    ++
    ++<p>First, enable your app to read from and write to the system Electronic
    ++Programming Guide (EPG), whose data includes channels and programs available
    ++to the user. To enable your app to perform these actions, and sync with the
    ++EPG after device restart, add the following elements to your app manifest:</p>
    ++
    ++<pre>
    ++&lt;uses-permission android:name="com.android.providers.tv.permission.READ_EPG_DATA" /&gt;
    ++&lt;uses-permission android:name="com.android.providers.tv.permission.WRITE_EPG_DATA" /&gt;
    ++&lt;uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED "/&gt;
    ++</pre>
    ++
    ++<p>Add the following element to ensure that your app shows up in the
    ++Google Play Store as an app that provides content channels in Android TV:</p>
    ++
    ++<pre>
    ++&lt;uses-feature
    ++    android:name="android.software.live_tv"
    ++    android:required="true" /&gt;
    ++</pre>
    ++
    ++<p>Next, create a class which extends the <code>EpgSyncJobService</code>
    ++class. This abstract class makes it easy to create a job service that
    ++creates and updates channels in the system database.</p>
    ++
    ++<p>In your subclass, create and return your full list of channels in
    ++<code>getChannels()</code>. If your channels come from an XMLTV file,
    ++use the <code>XmlTvParser</code> class. Otherwise generate
    ++channels programmatically using the <code>Channel.Builder</code> class.
    ++</p>
    ++
    ++<p>For each channel, the system calls <code>getProgramsForChannel()</code>
    ++when it needs a list of programs that can be viewed within a given time window
    ++on the channel. Return a list of <code>Program</code> objects for the
    ++channel. Use the <code>XmlTvParser</code> class to obtain programs from an
    ++XMLTV file, or generate them programmatically using the
    ++<code>Program.Builder</code> class.</p>
    ++
    ++<p>For each <code>Program</code> object, use an
    ++<code>InternalProviderData</code> object to set program information such as the
    ++program's video type. If you only have a limited number of programs that you
    ++want the channel to repeat in a loop, use the
    ++<code>InternalProviderData.setRepeatable()</code> method with a value of
    ++<code>true</code> when setting information about your program.</p>
    ++
    ++<p>After you've implemented the job service, add it to your app manifest:</p>
    ++
    ++<pre>
    ++&lt;service
    ++    android:name=".sync.SampleJobService"
    ++    android:permission="android.permission.BIND_JOB_SERVICE"
    ++    android:exported="true" /&gt;
    ++</pre>
    ++
    ++<p>Finally, create a setup activity. Your setup activity should provide a way
    ++to sync channel and program data. One way to do this is for the user to do it
    ++via the UI in the activity. You might also have the app do it automatically
    ++when the activity starts. When the setup activity needs to sync channel and
    ++program info, the app should start the job service:</p>
    ++
    ++<pre>
    ++String inputId = getActivity().getIntent().getStringExtra(TvInputInfo.EXTRA_INPUT_ID);
    ++EpgSyncJobService.cancelAllSyncRequests(getActivity());
    ++EpgSyncJobService.requestImmediateSync(getActivity(), inputId,
    ++        new ComponentName(getActivity(), SampleJobService.class));
    ++</pre>
    ++
    ++<p>Use the <code>requestImmediateSync()</code> method to sync
    ++the job service. The user must wait for the sync to finish, so you should
    ++keep your request period relatively short.</p>
    ++
    ++<p>Use the <code>setUpPeriodicSync()</code> method to have the job service
    ++periodically sync channel and program data in the background:</p>
    ++
    ++<pre>
    ++EpgSyncJobService.setUpPeriodicSync(context, inputId,
    ++        new ComponentName(context, SampleJobService.class));
    ++</pre>
    ++
    ++<p>The TIF Companion Library provides an additional overloaded method of
    ++<code>requestImmediateSync()</code> that lets you specify the duration of
    ++channel data to sync in milliseconds. The default method syncs one hour's
    ++worth of channel data.
    ++</p>
    ++
    ++<p>The TIF Companion Library also provides an additional overloaded method of
    ++<code>setUpPeriodicSync()</code> that lets you specify the duration of
    ++channel data to sync, and how often the periodic sync should occur. The
    ++default method syncs 48 hours of channel data every 12 hours.
    ++</p>
    ++
    ++<p>For more details about channel data and the EPG, see
    ++<a href="{@docRoot}training/tv/tif/channel.html"> Working with Channel Data</a>.
    ++</p>
    ++
    ++<h3 id="playback">Handle tuning requests and media playback</h3>
    ++
    ++<p>When a user selects a specific channel, the system TV app uses a
    ++<code>Session</code>, created by your app, to tune to the requested channel
    ++and play content. The TIF Companion Library provides several
    ++classes you can extend to handle channel and session calls from the system.</p>
    ++
    ++<p>Your <code>BaseTvInputService</code> subclass creates sessions which handle
    ++tuning requests. Override the
    ++<code>onCreateSession()</code> method, create a session extended from
    ++the <code>BaseTvInputService.Session</code> class, and call
    ++<code>super.sessionCreated()</code> with your new session. In the following
    ++example, <code>onCreateSession()</code> returns a
    ++<code>RichTvInputSessionImpl</code> object that extends
    ++<code>BaseTvInputService.Session</code>:</p>
    ++
    ++<pre>
    ++&#64;Override
    ++public final Session onCreateSession(String inputId) {
    ++    RichTvInputSessionImpl session = new RichTvInputSessionImpl(this, inputId);
    ++    session.setOverlayViewEnabled(true);
    ++    return super.sessionCreated(session);
    ++}
    ++</pre>
    ++
    ++<p>When the user uses the system TV app to start viewing one of your channels,
    ++the system calls your session's <code>onPlayChannel()</code> method. Override
    ++this method if you need to do any special channel initialization before the
    ++program starts playing.</p>
    ++
    ++<p>The system then obtains the currently scheduled program and calls your
    ++session's <code>onPlayProgram()</code> method, specifying the program
    ++information and start time in milliseconds. Use the
    ++<code>TvPlayer</code> interface to start playing the program.</p>
    ++
    ++<p>Your media player code should implement <code>TvPlayer</code> to handle
    ++specific playback events. The <code>TvPlayer</code> class handles features
    ++like time-shifting controls without adding complexity to your
    ++<code>BaseTvInputService</code> implementation.</p>
    ++
    ++<p>In your session's <code>getTvPlayer()</code> method, return
    ++your media player that implements <code>TvPlayer</code>. The
    ++<a class="external-link"
    ++href="https://github.com/googlesamples/androidtv-sample-inputs">
    ++TV Input Service sample app</a> implements a media player that uses
    ++<a href="{@docRoot}guide/topics/media/exoplayer.html">ExoPlayer</a>.</p>
    ++
    ++<h2 id="NoTIFCompanion">Create a TV Input Service Using the TIF Framework</h2>
    ++
    ++<p>If your TV input service can't use the TIF Companion Library, you need
    ++to implement the following components:</p>
    + 
    + <ul>
    +   <li>{@link android.media.tv.TvInputService} provides long-running and background availability for
    +@@ -56,43 +294,18 @@ TV Input Framework</a> for more information about the framework architecture and
    +   the interaction with TV inputs and apps</li>
    + </ul>
    + 
    +-<h2 id="manifest">Declare Your TV Input Service in the Manifest</h2>
    +-
    +-<p>Your app manifest must declare your {@link android.media.tv.TvInputService}. Within that
    +-declaration, specify the {@link android.Manifest.permission#BIND_TV_INPUT} permission to allow the
    +-service to connect the TV input to the system. A system service (<code>TvInputManagerService</code>)
    +-performs the binding and has that permission. The system TV app sends requests to TV input services
    +-via the {@link android.media.tv.TvInputManager} interface. The service declaration must also
    +-include an intent filter that specifies the {@link android.media.tv.TvInputService}
    +-as the action to perform with the intent. Also within the service declaration, declare the service
    +-meta data in a separate XML resource. The service declaration, the intent filter and the service
    +-meta data are described in the following example.</p>
    +-
    +-<pre>
    +-&lt;service android:name="com.example.sampletvinput.SampleTvInput"
    +-    android:label="@string/sample_tv_input_label"
    +-    android:permission="android.permission.BIND_TV_INPUT"&gt;
    +-    &lt;intent-filter&gt;
    +-        &lt;action android:name="android.media.tv.TvInputService" /&gt;
    +-    &lt;/intent-filter&gt;
    +-    &lt;meta-data android:name="android.media.tv.input"
    +-      android:resource="@xml/sample_tv_input" /&gt;
    +-&lt;/service&gt;
    +-</pre>
    +-
    +-<p>Define the service meta data in separate XML file, as shown in the following example. The service
    +-meta data must include a setup interface that describes the TV input's initial configuration and
    +-channel scan. The service meta data file is located in the XML resources directory
    +-for your application and must match the name of the resource in the manifest. Using the example
    +-manifest entries above, you would create an XML file in the location
    +-<code>res/xml/sample_tv_input.xml</code>, with the following contents:</p>
    ++<p>You also need to do the following:</p>
    + 
    +-<pre>
    +-&lt;tv-input xmlns:android="http://schemas.android.com/apk/res/android"
    +-  android:setupActivity="com.example.sampletvinput.SampleTvInputSetupActivity" /&gt;
    +-</pre>
    ++<ol>
    ++<li>Declare your TV input service in the manifest, as
    ++described in <a href="#manifest">Declare your TV input service in the
    ++manifest</a>.</li>
    ++<li>Create the service metadata file.</li>
    ++<li>Create and register your channel and program information.</li>
    ++<li>Create your setup activity.</li>
    ++</ol>
    + 
    +-<h2 id="tvinput">Define Your TV Input Service</h2>
    ++<h3 id="tvinput">Define your TV input service</h3>
    + 
    + <div class="figure">
    + <img id="tvinputlife" src="{@docRoot}images/tv/tvinput-life.png" alt=""/>
    +@@ -102,7 +315,7 @@ manifest entries above, you would create an XML file in the location
    + <p>For your service, you extend the {@link android.media.tv.TvInputService} class. A
    + {@link android.media.tv.TvInputService} implementation is a
    + <a href="{@docRoot}guide/components/bound-services.html">bound service</a> where the system service
    +-(<code>TvInputManagerService</code>) is the client that binds to it. The service life cycle methods
    ++is the client that binds to it. The service life cycle methods
    + you need to implement are illustrated in figure 1.</p>
    + 
    + <p>The {@link android.app.Service#onCreate()} method initializes and starts the
    +@@ -145,7 +358,8 @@ you may want to handle in your TV input service.</p>
    + 
    + <p>The {@link android.media.tv.TvInputService} creates a
    + {@link android.media.tv.TvInputService.Session} that implements {@link android.os.Handler.Callback}
    +-to handle player state changes. With {@link android.media.tv.TvInputService.Session#onSetSurface(android.view.Surface) onSetSurface()},
    ++to handle player state changes. With
    ++{@link android.media.tv.TvInputService.Session#onSetSurface(android.view.Surface) onSetSurface()},
    + the {@link android.media.tv.TvInputService.Session} sets the {@link android.view.Surface} with the
    + video content. See <a href="{@docRoot}training/tv/tif/ui.html#surface">Integrate Player with Surface</a>
    + for more information about working with {@link android.view.Surface} to render video.</p>
    +@@ -153,16 +367,16 @@ for more information about working with {@link android.view.Surface} to render v
    + <p>The {@link android.media.tv.TvInputService.Session} handles the
    + {@link android.media.tv.TvInputService.Session#onTune(android.net.Uri) onTune()}
    + event when the user selects a channel, and notifies the system TV app for changes in the content and
    +-content meta data. These <code>notify()</code> methods are described in
    ++content metadata. These <code>notify()</code> methods are described in
    + <a href="{@docRoot}training/tv/tif/ui.html#control">
    + Control Content</a> and <a href="{@docRoot}training/tv/tif/ui.html#track">Handle Track Selection</a>
    + further in this training.</p>
    + 
    +-<h2 id="setup">Define Your Setup Activity</h2>
    ++<h3 id="setup">Define your setup activity</h3>
    + 
    + <p>The system TV app works with the setup activity you define for your TV input. The
    + setup activity is required and must provide at least one channel record for the system database. The
    +-system TV app will invoke the setup activity when it cannot find a channel for the TV input.
    ++system TV app invokes the setup activity when it cannot find a channel for the TV input.
    + <p>The setup activity describes to the system TV app the channels made available through the TV
    + input, as demonstrated in the next lesson, <a href="{@docRoot}training/tv/tif/channel.html">Creating
    +-and Updating Channel Data</a>.</p>
    ++and Updating Channel Data</a>.</p>
    +\ No newline at end of file
    +diff --git a/docs/html/training/volley/index.jd b/docs/html/training/volley/index.jd
    +index a8c4b84..d3645d9 100755
    +--- a/docs/html/training/volley/index.jd
    ++++ b/docs/html/training/volley/index.jd
    +@@ -42,7 +42,7 @@ faster. Volley is available through the open
    + <li>Automatic scheduling of network requests.</li>
    + <li>Multiple concurrent network connections.</li>
    + <li>Transparent disk and memory response caching with standard HTTP
    +-<a href=http://en.wikipedia.org/wiki/Cache_coherence">cache coherence</a>.</li>
    ++<a href="http://en.wikipedia.org/wiki/Cache_coherence">cache coherence</a>.</li>
    + <li>Support for request prioritization.</li>
    + <li>Cancellation request API. You can cancel a single request, or you can set blocks or
    + scopes of requests to cancel.</li>
    +@@ -66,13 +66,22 @@ alternative like {@link android.app.DownloadManager}.</p>
    + <a href="https://android.googlesource.com/platform/frameworks/volley">AOSP</a>
    + repository at {@code frameworks/volley} and contains the main request dispatch pipeline
    + as well as a set of commonly applicable utilities, available in the Volley "toolbox." The
    +-easiest way to add Volley to your project is to clone the Volley repository and set it as
    +-a library project:</p>
    ++easiest way to add Volley to your project is to add the following dependency to your app's
    ++build.gradle file:
    ++
    ++<pre class="no-pretty-print">
    ++dependencies {
    ++    ...
    ++    compile 'com.android.volley:volley:1.0.0'
    ++}
    ++</pre>
    ++
    ++You can also clone the Volley repository and set it as a library project:</p>
    + 
    + <ol>
    + <li>Git clone the repository by typing the following at the command line:
    + 
    +-<pre>
    ++<pre class="no-pretty-print">
    + git clone https://android.googlesource.com/platform/frameworks/volley
    + </pre>
    + </li>
    +diff --git a/docs/html/training/wearables/data-layer/messages.jd b/docs/html/training/wearables/data-layer/messages.jd
    +index ef9bfb1..8c4b730 100644
    +--- a/docs/html/training/wearables/data-layer/messages.jd
    ++++ b/docs/html/training/wearables/data-layer/messages.jd
    +@@ -10,12 +10,6 @@ page.title=Sending and Receiving Messages
    +   <li><a href="#SendMessage">Send a Message</a></li>
    +   <li><a href="#ReceiveMessage">Receive a Message</a></li>
    + </ol>
    +-<h2>Try it out</h2>
    +-<ul>
    +-  <li>
    +-    <a href="https://github.com/googlesamples/android-FindMyPhone/" class="external-link">FindMyPhone</a>
    +-  </li>
    +-</ul>
    + </div>
    + </div>
    + 
    +@@ -27,6 +21,7 @@ and attach the following items to the message:</p>
    +   <li>An arbitrary payload (optional)</li>
    +   <li>A path that uniquely identifies the message's action</li>
    + </ul>
    ++
    + <p>
    + Unlike with data items, there is no syncing between the handheld and wearable apps.
    + Messages are a one-way communication mechanism that's good for remote procedure calls (RPC),
    +@@ -149,11 +144,9 @@ If you create a service that extends
    + <a href="{@docRoot}reference/com/google/android/gms/wearable/WearableListenerService.html"><code>WearableListenerService</code></a>
    + to detect capability changes, you may want to override the
    + <a href="{@docRoot}reference/com/google/android/gms/wearable/WearableListenerService.html#onConnectedNodes(java.util.List<com.google.android.gms.wearable.Node>)"><code>onConnectedNodes()</code></a>
    +-method to listen to finer-grained connectivity details, such as when a wearable device switches
    +-from Wi-Fi to a Bluetooth connection to the handset. For an example implementation, see the
    +-<code>DisconnectListenerService</code> class in the
    +-<a href="https://github.com/googlesamples/android-FindMyPhone/" class="external-link">FindMyPhone</a>
    +-sample. For more information on how to listen for important events, see
    ++method to listen to finer-grained connectivity details, such as when a wearable
    ++device switches from Wi-Fi to a Bluetooth connection to the handset.
    ++For more information on how to listen for important events, see
    + <a href="{@docRoot}training/wearables/data-layer/events.html#Listen">Listen for Data Layer Events</a>.
    + </p>
    + 
    +diff --git a/docs/html/training/wearables/notifications/creating.jd b/docs/html/training/wearables/notifications/creating.jd
    +index 35bb2bd..5663b58 100644
    +--- a/docs/html/training/wearables/notifications/creating.jd
    ++++ b/docs/html/training/wearables/notifications/creating.jd
    +@@ -58,7 +58,7 @@ such as action buttons and large icons, while remaining compatible with Android
    + 
    + <p>To create a notification with the support library, you create an instance of
    + {@link android.support.v4.app.NotificationCompat.Builder} and issue the notification by
    +-passing it to {@link android.support.v4.app.NotificationManagerCompat#notify(int, android.app.Notification) notify()}. For example:
    ++passing it to {@link android.support.v4.app.NotificationManagerCompat#notify notify()}. For example:
    + </p>
    + 
    + <pre>
    +diff --git a/docs/html/training/wearables/notifications/stacks.jd b/docs/html/training/wearables/notifications/stacks.jd
    +index c3f43a7..8056fc8 100644
    +--- a/docs/html/training/wearables/notifications/stacks.jd
    ++++ b/docs/html/training/wearables/notifications/stacks.jd
    +@@ -37,7 +37,7 @@ possible while allowing you to still provide only one summary notification on th
    + 
    + <p>To create a stack, call {@link android.support.v4.app.NotificationCompat.Builder#setGroup setGroup()}
    + for each notification you want in the stack and specify a
    +-group key. Then call {@link android.support.v4.app.NotificationManagerCompat#notify(int, android.app.Notification) notify()}
    ++group key. Then call {@link android.support.v4.app.NotificationManagerCompat#notify notify()}
    + to send it to the wearable.</p>
    + 
    + <pre style="clear:right">
    +@@ -59,7 +59,7 @@ notificationManager.notify(notificationId1, notif);
    + 
    + <p>Later on, when you create another notification, specify
    + the same group key. When you call
    +-{@link android.support.v4.app.NotificationManagerCompat#notify(int, android.app.Notification) notify()},
    ++{@link android.support.v4.app.NotificationManagerCompat#notify notify()},
    + this notification appears in the same stack as the previous notification,
    + instead of as a new card:</p>
    + 
    +diff --git a/docs/html/tv/_project.yaml b/docs/html/tv/_project.yaml
    +new file mode 100644
    +index 0000000..d2d41e1
    +--- /dev/null
    ++++ b/docs/html/tv/_project.yaml
    +@@ -0,0 +1,6 @@
    ++name: "TV"
    ++home_url: /tv/
    ++description: "Bring your apps, games, and content to the biggest screen in the house."
    ++content_license: cc3-apache2
    ++buganizer_id: 30209417
    ++parent_project_metadata_path: /about/_project.yaml
    +diff --git a/docs/html/tv/index.jd b/docs/html/tv/index.jd
    +index 7c958c0..6ecc1ea 100644
    +--- a/docs/html/tv/index.jd
    ++++ b/docs/html/tv/index.jd
    +@@ -13,7 +13,7 @@ nonavpage=true
    + 
    + <style>
    + .fullpage>#footer,
    +-#jd-content>.content-footer.wrap {
    ++#body-content>.content-footer.wrap {
    +   display:none;
    + }
    + </style>
    +diff --git a/docs/html/wear/_project.yaml b/docs/html/wear/_project.yaml
    +index 2a94274..114cc5b 100644
    +--- a/docs/html/wear/_project.yaml
    ++++ b/docs/html/wear/_project.yaml
    +@@ -3,3 +3,4 @@ home_url: /wear/
    + description: "Small, powerful devices, worn on the body. Useful information when you need it most."
    + content_license: cc3-apache2
    + buganizer_id: 30209417
    ++parent_project_metadata_path: /about/_project.yaml
    +diff --git a/docs/html/wear/images/partners/mkors.png b/docs/html/wear/images/partners/mkors.png
    +new file mode 100644
    +index 0000000..2f1e8ec
    +Binary files /dev/null and b/docs/html/wear/images/partners/mkors.png differ
    +diff --git a/docs/html/wear/images/partners/nixon.png b/docs/html/wear/images/partners/nixon.png
    +new file mode 100644
    +index 0000000..8674da2
    +Binary files /dev/null and b/docs/html/wear/images/partners/nixon.png differ
    +diff --git a/docs/html/wear/images/partners/polar.png b/docs/html/wear/images/partners/polar.png
    +new file mode 100644
    +index 0000000..2faeb06
    +Binary files /dev/null and b/docs/html/wear/images/partners/polar.png differ
    +diff --git a/docs/html/wear/index.jd b/docs/html/wear/index.jd
    +index f5e9e87..1eb08be 100644
    +--- a/docs/html/wear/index.jd
    ++++ b/docs/html/wear/index.jd
    +@@ -9,7 +9,7 @@ nonavpage=true
    + 
    + <style>
    + .fullpage>#footer,
    +-#jd-content>.content-footer.wrap {
    ++#body-content>.content-footer.wrap {
    +   display:none;
    + }
    + </style>
    +@@ -267,6 +267,9 @@ nonavpage=true
    +             <div class="col-4">
    +               <img src="/wear/images/partners/mips.png" alt="MIPS">
    +             </div>
    ++            <div class="col-4">
    ++              <img src="/wear/images/partners/mkors.png" alt=Michael Kors">
    ++            </div>
    +              <div class="col-4">
    +               <img src="/wear/images/partners/mobvoi.png" alt="Mobvoi">
    +             </div>
    +@@ -277,6 +280,12 @@ nonavpage=true
    +               <img src="/wear/images/partners/nb.png" alt="New Balance">
    +             </div>
    +             <div class="col-4">
    ++              <img src="/wear/images/partners/nixon.png" alt="Nixon">
    ++            </div>
    ++            <div class="col-4">
    ++              <img src="/wear/images/partners/polar.png" alt="Polar">
    ++            </div>
    ++            <div class="col-4">
    +               <img src="/wear/images/partners/qualcomm.png" alt="Qualcomm">
    +             </div>
    +             <div class="col-4">
    +diff --git a/docs/html/wear/preview/_book.yaml b/docs/html/wear/preview/_book.yaml
    +index a231fb5..54d5442 100644
    +--- a/docs/html/wear/preview/_book.yaml
    ++++ b/docs/html/wear/preview/_book.yaml
    +@@ -8,18 +8,24 @@ toc:
    + - title: API Overview
    +   path: /wear/preview/api-overview.html
    +   section:
    +-  - title: Notification Improvements
    +-    path: /wear/preview/features/notifications.html
    +-  - title: Input Method Framework
    +-    path: /wear/preview/features/ime.html
    +   - title: Complications
    +     path: /wear/preview/features/complications.html
    +   - title: Navigation and Actions
    +     path: /wear/preview/features/ui-nav-actions.html
    ++  - title: Curved Layout
    ++    path: /wear/preview/features/wearable-recycler-view.html
    ++  - title: Notification Improvements
    ++    path: /wear/preview/features/notifications.html
    +   - title: Bridging for Notifications
    +     path: /wear/preview/features/bridger.html
    ++  - title: Input Method Framework
    ++    path: /wear/preview/features/ime.html
    +   - title: Wrist Gestures
    +     path: /wear/preview/features/gestures.html
    ++  - title: Standalone apps
    ++    path: /wear/preview/features/standalone-apps.html
    ++  - title: App Distribution
    ++    path: /wear/preview/features/app-distribution.html
    + 
    + - title: Get Started
    +   path: /wear/preview/start.html
    +diff --git a/docs/html/wear/preview/_project.yaml b/docs/html/wear/preview/_project.yaml
    +new file mode 100644
    +index 0000000..4f7083e
    +--- /dev/null
    ++++ b/docs/html/wear/preview/_project.yaml
    +@@ -0,0 +1,6 @@
    ++name: "Wear Preview"
    ++home_url: /wear/preview/
    ++description: "Small, powerful devices, worn on the body. Useful information when you need it most."
    ++content_license: cc3-apache2
    ++buganizer_id: 30209417
    ++parent_project_metadata_path: /wear/_project.yaml
    +diff --git a/docs/html/wear/preview/api-overview.jd b/docs/html/wear/preview/api-overview.jd
    +index 0b3ac6b..f4612a2 100644
    +--- a/docs/html/wear/preview/api-overview.jd
    ++++ b/docs/html/wear/preview/api-overview.jd
    +@@ -13,15 +13,16 @@ page.image=images/cards/card-n-apis_2x.png
    +           <ol>
    +             <li><a href="#complications">Complications</a></li>
    +             <li><a href="#drawers">Navigation and Action Drawers</a></li>
    ++            <li><a href="#wrv">Curved Layout</a></li>
    +           </ol>
    +         </li>
    + 
    +         <li><a href="#notify">Notifications and Input</a>
    +           <ol>
    +-            <li><a href="#expanded">Expanded Notification</a></li>
    +-            <li><a href="#messaging">Messaging Style Notification</a></li>
    ++            <li><a href="#expanded">Expanded Notifications</a></li>
    ++            <li><a href="#messaging">Messaging Style Notifications</a></li>
    ++            <li><a href="#inline-action">Inline Action</a></li>
    +             <li><a href="#smart-replies">Smart Reply</a></li>
    +-            <li><a href="#content-action">Notification Content Action</a>
    +             <li><a href="#remote-input">Remote Input</a></li>
    +             <li><a href="#bridging">Bridging Mode</a></li>
    +             <li><a href="#imf">Input Method Framework</a></li>
    +@@ -40,308 +41,447 @@ page.image=images/cards/card-n-apis_2x.png
    + </div>
    + </div>
    + 
    +-
    +-
    +-<p>
    +-  The Android Wear Preview API is still in active development, but you can try
    +-  it now as part of the Wear 2.0 Developer Preview. The sections below
    +-  highlight some of the new features for Android Wear developers.
    +-</p>
    +-
    +-
    +-<h2 id="ui">User Interface Improvements</h2>
    +-
    +-<p>
    +-  The preview introduces powerful additions to the user interface, opening up
    +-  exciting possibilities to developers. A complication
    +-  is any feature in a watch face that displays more than hours and
    +-  minutes. With the Complications API, watch faces can display extra information
    +-  and separate apps can expose complication data. The navigation and action
    +-  drawers provide users with new ways to interact with apps.
    +-</p>
    +-
    +-
    +-<h3 id="complications">Complications</h3>
    +-<img src="{@docRoot}wear/preview/images/complications-main-image.png"
    +-  height="320" style="float:right;margin:10px 0 0 40px" />
    +-
    +-<p>
    +-  A <a href=
    +-  "https://en.wikipedia.org/wiki/Complication_(horology)">complication</a> is a
    +-  feature of a watch face that displays more than hours and minutes, such as a
    +-  battery indicator or a step counter. The Complications API thus helps watch face
    +-  developers create visual features and the data connections they
    +-  require.
    +-</p>
    +-
    +-<p>
    +-  Watch faces that use this API can display extra information without needing
    +-  code for getting the underlying data. Data providers can supply data to any
    +-  watch face using the API.
    +-</p>
    +-
    +-<p>For information about this API,
    +-see <a href="{@docRoot}wear/preview/features/complications.html">
    +- Watch Face Complications</a>.
    +-</p>
    +-
    +-<h3 id="drawers">Navigation and Action drawers</h3>
    +-
    +-<p>Wear 2.0 introduces two new widgets, navigation drawer and action drawer. These
    +- widgets give your users new ways to interact with your app. The navigation drawer
    +-  appears at the top of the screen and allows users to navigate between app views.
    +-   The  action drawer appears at the bottom of the screen and allows users to choose
    +-    from a list of actions associated with the current usage context.  These drawers
    +-     are accessible to users when they edge swipe from the top or bottom of the
    +-     screen; they peek when users scroll in an opposite direction.
    +-</p>
    +-
    +-<div class="cols">
    +-  <div class="col-2of6">
    +-    <img src="{@docRoot}wear/preview/images/nav_drawer.gif"
    +-      height="240" alt="" style="padding:.5em">
    +-  </div>
    +-  <div class="col-2of6">
    +-    <img src="{@docRoot}wear/preview/images/action_drawer.gif"
    +-      height="240" alt="" style="padding:.5em;">
    +-  </div>
    +-</div>
    +-
    +-<p>
    +-  To learn how to add these widgets to your app, see
    +-  <a href="{@docRoot}wear/preview/features/ui-nav-actions.html">
    +-  Wear Navigation and Actions</a>.
    +-</p>
    +-
    +-
    +-<h2 id="notify">Notifications and Input</h2>
    +-
    +-<p>In Wear 2.0, we’ve redesigned the key experiences on the watch to be even more
    +- intuitive and provide users new ways to respond to messages. Some of the highlights
    +-  are below; for a complete list of changes, see
    +-  <a href="{@docRoot}wear/preview/features/notifications.html">Notification Changes in Wear 2.0</a>.
    +-
    +-
    +-<img src="{@docRoot}wear/preview/images/expanded_diagram.png" height="340"
    +-  style="float:left;margin:10px 20px 0 0" />
    +-<h3 id="expanded">Expanded notifications</h3>
    +-
    +-<p>
    +-  When a user taps on a notification that is bridged from the phone to the
    +-  watch or that lacks a
    +-  <a href="{@docRoot}reference/android/support/v4/app/NotificationCompat.Builder.html#setContentIntent(android.app.PendingIntent)">
    +-  {@code contentIntent}</a>, the user will be taken to the expanded view of
    +-  that notification. When you <a href=
    +-  "{@docRoot}training/wearables/notifications/pages.html">specify additional
    +-  content pages</a> and actions for a notification, those are available to the
    +-  user within the expanded notification. Each expanded notification follows
    +-  <a href="https://google.com/design/spec-wear">Material Design for Android
    +-  Wear</a>, so the user gets an app-like experience.
    +-</p>
    +-
    +-
    +-<h3 id="messaging">Messaging Style notification</h3>
    +-<p> If you have a chat messaging app, your notifications should use
    +-{@code Notification.MessagingStyle}, which is new in Android 6.0. Wear 2.0 uses
    +-the chat messages included in a
    +-<a href="{@docRoot}preview/features/notification-updates.html#style">{@code MessagingStyle}</a>
    +- notification
    +-(see {@code addMessage()}) to provide a rich chat app-like experience in the
    +-expanded notification.
    +-</p>
    +-
    +-
    +-<h3 id="smart-replies">Smart Reply</h3>
    +-
    +-<p>Android Wear 2.0 introduces support for Smart Reply in
    +-<a href="{@docRoot}wear/preview/features/notifications.html#messaging">{@code MessagingStyle}</a>
    +- notifications. Smart Reply provides the user with contextually relevant,
    +- touchable choices in the expanded notification and in
    +- <a href="{@docRoot}reference/android/app/RemoteInput.html">{@code RemoteInput}</a>.
    +-</p>
    +-
    +-<p>By enabling Smart Reply for your {@code MessagingStyle} notifications, you provide
    +-users a fast (single tap), discreet (no speaking aloud), and reliable way to respond
    +- to chat messages they receive.
    +- </p>
    +-
    +-
    +-<img src="{@docRoot}wear/preview/images/remoteinput.png" height="350"
    +-  style="float:right;margin:10px 0 0 40px" />
    +-
    +-<h3 id="remote-input">Remote Input</h3>
    +-
    +-<p>Wear 2.0 users can choose between various input options from
    +-<a href="{@docRoot}reference/android/app/RemoteInput.html">Remote Input</a>.
    +- These options include:
    +-</p>
    +-<ul>
    +-<li>Dictation</li>
    +-<li>Emoji</li>
    +-<li>Canned responses</li>
    +-<li>Smart Reply</i>
    +-<li>Default IME </i>
    +-</ul>
    +-
    +-<p>
    +-For messaging notifications with Smart Reply, the system-generated Smart Reply
    +- appears within <a href="{@docRoot}reference/android/app/RemoteInput.html">{@code RemoteInput}</a>
    +-  above the developer-provided list of canned responses.
    +-  You can also use the
    +-  <a href="{@docRoot}reference/android/app/RemoteInput.Builder.html#setChoices(java.lang.CharSequence[])">setChoices()</a>
    +-   method in the {@code RemoteInput} API to enable users to select from a list
    +-   of canned responses.
    +-</p>
    +-
    +-<h3 id="bridging"> Bridging Mode </h3>
    +-<p>By default, notifications are
    +-<a href="{@docRoot}training/wearables/notifications/index.html">
    +-bridged</a> (shared) from an app on a companion phone
    +-to the watch. Since a phone app and a standalone watch app may be sources of the
    +- same notifications, the Android Wear 2.0 Preview includes a Bridging mode feature.
    +-  Developers can begin planning to change the behavior of notifications with the
    +-  following:
    +-</p>
    +-
    +-<ul>
    +-<li>Specifying in the standalone app's Android manifest file that notifications from
    +- the corresponding phone app should not be bridged to the watch. </li>
    +-<li>Setting a dismissal ID so notification dismissals (by users) are synced across
    +-devices.</li>
    +-</ul>
    +-
    +-<p>For an example of how to use this feature, see <a href="{@docRoot}wear/preview/features/bridger.html">
    +-Bridging Mode for Notifications</a>.</p>
    +-
    +-<h3 id="imf">Input Method Framework</h3>
    +-
    +-<p>Wear 2.0 extends the Android input method framework (IMF) to Android Wear.
    +-This allows users to enter text on Wear using the system default IME or third party
    +- IMEs.  The Wear IME lets the user enter text via gesture typing as well as tapping
    +-  individual keys. The IMF APIs used for Wear devices are the same as other form
    +-  factors, though usage is slightly different due to limited screen real estate.
    +-</p>
    +-
    +-<p>Wear provides user settings on the watch that let the user:</p>
    +-<ul>
    +-<li>Enable multiple IMEs from the list of installed IMEs.</li>
    +-<li>Set a single default IME from the list of enabled IMEs.</li>
    +-<li>Change languages for various IMEs.</li>
    +-</ul>
    +-
    +-<p>To learn how to create an IME for Wear, see <a href="{@docRoot}wear/preview/features/ime.html">
    +-Input Method Framework</a>.
    +-</p>
    +-
    +-<h3 id="wrist-gestures">Wrist Gestures</h3>
    +-
    +-<p>
    +-  Wrist gestures can enable quick, one-handed interactions with your app
    +-  when use of a touch screen is inconvenient. The following
    +-  <a href="https://support.google.com/androidwear/answer/6312406">wrist gestures</a>
    +-  are available for use by apps:
    +-</p>
    +-
    +-<ul>
    +-  <li>Flick wrist out</li>
    +-  <li>Flick wrist in</li>
    +-</ul>
    +-
    +-<p>For more information, see
    +-<a href="{@docRoot}wear/preview/features/gestures.html">
    +- Wrist Gestures</a>.
    +-</p>
    +-
    +-<h2 id="stand-alone">Standalone Devices</h2>
    +-
    +-<p>Standalone watches will enable Android Wear apps to work independently of phone
    +- apps. This means your app can continue to offer full functionality even if the
    +- paired phone is far away or turned off. </p>
    +-
    +-<h3 id="wear-apk">Wear-Specific APKs</h3>
    +-
    +-<p>For delivery to a watch, an Android Wear app is currently embedded in its corresponding
    +-phone app. This delivery method can result in an increased download size for users,
    +- regardless of whether they have an Android Wear device.
    +-</p>
    +-
    +-<p>With standalone devices, the
    +-<a href ="{@docRoot}google/play/publishing/multiple-apks.html">Multi-APK</a>
    +- delivery method will be used. Developers will have the ability to release Android
    +-  Wear apps independently of the corresponding phone apps. Please stay tuned for
    +-   more information about this change.
    +-</p>
    +-
    +-<h3 id="network">Network Access</h3>
    +-
    +-<p>Since Android Wear apps will work independently of phone apps, Android Wear's
    +- network access will no longer require the
    +- <a href="{@docRoot}training/wearables/data-layer/index.html">
    +- Wearable Data Layer API</a>. Android Wear apps will have the ability to make
    +- their own network requests. Additionally, they will be able to directly use
    +- Google Cloud Messaging.
    +-</p>
    +-
    +-<p>No APIs for network access or GCM are specific to Android Wear; refer to the
    +-existing documentation about
    +-<a href="{@docRoot}training/basics/network-ops/connecting.html">
    +-Connecting to the Network</a> and
    +-<a href="https://developers.google.com/cloud-messaging/">Cloud Messaging</a>.
    +-</p>
    +-
    +-<p>We recommend using the following libraries:</p>
    +-<ul>
    +-<li><a href="{@docRoot}reference/android/app/job/JobScheduler.html">
    +-JobScheduler</a> for asynchronous jobs, including polling at regular intervals
    +-</li>
    +-<li>Multi-networking APIs if you need to connect to specific network types; see
    +-the <a href="{@docRoot}about/versions/android-5.0.html#Wireless">
    +-Multiple Network Connections</a>
    +-</li>
    +-</ul>
    +-
    +-<p>You will still be able to use the
    +-<a href="{@docRoot}training/wearables/data-layer/index.html">
    +- Wearable Data Layer API</a> to communicate with a phone app.
    +- However, use of this API to connect to a network will be discouraged.
    +- </p>
    +-
    +-
    +-<h3 id="auth">Authentication</h3>
    +-
    +-<p>Since Android Wear apps will work independently of phone apps, Android Wear's
    +- authentication capabilities will be more powerful; apps will have new ways to
    +- authenticate.</p>
    +-
    +-<h4>Users can enter a username and password on a watch</h4>
    +-
    +-<p>Google Keyboard will be standard on Android Wear, allowing for direct text
    +-entry. This feature will work as expected with standard
    +-<a href="{@docRoot}reference/android/widget/EditText.html">EditText widgets</a>.
    +-For passwords, the {@code textPassword} attribute will be used.</p>
    +-
    +-<h4>Utilizing Account Manager</h4>
    +-
    +-<p>Android Wear will include the
    +-<a href="{@docRoot}reference/android/accounts/AccountManager.html">
    +-AccountManager</a>, which will be accessible for syncing and storing account
    +-data, as it is on an Android phone.</p>
    +-
    +-<h4>Authentication tokens can be passed over the Wearable Data Layer</h4>
    +-
    +-<p>For Android-paired watches (only), a phone securely
    +-transfers authentication credentials to a watch app via the
    +-<a href="{@docRoot}training/wearables/data-layer/index.html">
    +-Wearable Data Layer API</a>. The credentials can be transferred as
    +-messages or data items.</p>
    +-
    +-<p>If your watch app needs to determine if your phone app is installed, you can
    +-advertise a capability on the phone app and retrieve the capability on the
    +-watch. For more information, see the following sections of
    +-<a href="{@docRoot}training/wearables/data-layer/messages.html">
    +-Sending and Receiving Messages</a>:</p>
    +-
    +-<ul>
    +-  <li>Advertise Capabilities</li>
    +-  <li>Retrieve the Nodes with the Required Capabilities</li>
    +-</ul>
    ++    <p>
    ++      Wear 2.0 is still in active development, but you can try it as part of
    ++      the Wear 2.0 Developer Preview. The sections below highlight some of the
    ++      new features for developers.
    ++    </p>
    ++
    ++    <h2 id="ui">
    ++      User Interface Improvements
    ++    </h2>
    ++
    ++    <p>
    ++      The preview introduces powerful additions to the user interface, opening
    ++      up exciting possibilities to developers.
    ++    </p>
    ++
    ++    <h3 id="complications">
    ++      Complications
    ++    </h3>
    ++
    ++    <img src="{@docRoot}wear/preview/images/complications-main-image.png"
    ++    height="320" style="float:right;margin:10px 0 0 40px">
    ++    <p>
    ++      A <a href=
    ++      "https://en.wikipedia.org/wiki/Complication_(horology)">complication</a>
    ++      is a feature of a watch face that displays more than hours and minutes,
    ++      such as a battery indicator or a step counter. The Complications API thus
    ++      helps watch face developers create visual features and the data
    ++      connections they require.
    ++    </p>
    ++
    ++    <p>
    ++      Watch faces that use this API can display extra information without
    ++      needing code for getting the underlying data. Data providers can supply
    ++      data to any watch face using the API.
    ++    </p>
    ++
    ++    <p>
    ++      For information about this API, see <a href=
    ++      "{@docRoot}wear/preview/features/complications.html">Watch Face
    ++      Complications</a>.
    ++    </p>
    ++
    ++    <h3 id="drawers">
    ++      Navigation and Action Drawers
    ++    </h3>
    ++
    ++    <p>
    ++      Wear 2.0 introduces two new widgets, navigation drawer and action drawer.
    ++      These widgets give your users new ways to interact with your app. The
    ++      navigation drawer appears at the top of the screen and allows users to
    ++      navigate between app views. The action drawer appears at the bottom of
    ++      the screen and allows users to choose from a list of actions associated
    ++      with the current usage context. These drawers are accessible to users
    ++      when they edge swipe from the top or bottom of the screen; they peek when
    ++      users scroll in an opposite direction.
    ++    </p>
    ++
    ++    <div class="cols">
    ++      <div class="col-2of6">
    ++        <img src="{@docRoot}wear/preview/images/nav_drawer.gif" height="240"
    ++        alt="" style="padding:.5em">
    ++      </div>
    ++
    ++      <div class="col-2of6">
    ++        <img src="{@docRoot}wear/preview/images/action_drawer.gif" height="240"
    ++        alt="" style="padding:.5em;">
    ++      </div>
    ++    </div>
    ++
    ++    <p>
    ++      To learn how to add these widgets to your app, see <a href=
    ++      "{@docRoot}wear/preview/features/ui-nav-actions.html">Wear Navigation and
    ++      Actions</a>.
    ++    </p>
    ++
    ++    <h3 id="wrv">
    ++      Curved Layout
    ++    </h3>
    ++
    ++    <p>
    ++      Wear 2.0 introduces the <code>WearableRecyclerView</code> class for
    ++      displaying and manipulating a vertical list of items,
    ++      optimized for round displays.
    ++    </p>
    ++
    ++    <p>
    ++      The key features include the following:
    ++    </p>
    ++
    ++    <ul>
    ++      <li>A curved layout on round devices
    ++      </li>
    ++
    ++      <li>A circular scrolling gesture, which can be toggled on and off
    ++      </li>
    ++    </ul>
    ++
    ++    <p>
    ++      To learn how to create a curved layout optimized for round devices, see
    ++      <a href=
    ++      "https://developer.android.com/wear/preview/features/wearable-recycler-view.html">
    ++      Curved Layout</a>.
    ++    </p>
    ++
    ++    <h2 id="notify">
    ++      Notifications and Input
    ++    </h2>
    ++
    ++    <p>
    ++      In Wear 2.0, we’ve redesigned the key experiences on the watch to be even
    ++      more intuitive and provide users new ways to respond to messages. Some of
    ++      the highlights are below; for a complete list of changes, see <a href=
    ++      "{@docRoot}wear/preview/features/notifications.html">Notification Changes
    ++      in Wear 2.0</a>. <img src=
    ++      "{@docRoot}wear/preview/images/expanded_diagram.png" height="340" style=
    ++      "float:left;margin:10px 20px 0 0">
    ++    </p>
    ++
    ++    <h3 id="expanded">
    ++      Expanded Notifications
    ++    </h3>
    ++
    ++    <p>
    ++      When a user taps on a notification that is bridged from the phone to the
    ++      watch or that lacks a <a href=
    ++      "{@docRoot}reference/android/support/v4/app/NotificationCompat.Builder.html#setContentIntent(android.app.PendingIntent)">
    ++      {@code contentIntent}</a>, the user will be taken to the expanded view of
    ++      that notification. When you <a href=
    ++      "{@docRoot}training/wearables/notifications/pages.html">specify
    ++      additional content pages</a> and actions for a notification, those are
    ++      available to the user within the expanded notification. Each expanded
    ++      notification follows <a href=
    ++      "https://google.com/design/spec-wear">Material Design for Android
    ++      Wear</a>, so the user gets an app-like experience.
    ++    </p>
    ++
    ++    <h3 id="messaging">
    ++      Messaging Style Notifications
    ++    </h3>
    ++
    ++    <p>
    ++      If you have a chat messaging app, your notifications should use {@code
    ++      Notification.MessagingStyle}, which is new in Android 6.0. Wear 2.0 uses
    ++      the chat messages included in a <a href=
    ++      "{@docRoot}preview/features/notification-updates.html#style">{@code
    ++      MessagingStyle}</a> notification (see {@code addMessage()}) to provide a
    ++      rich chat, app-like experience in the expanded notification.
    ++    </p>
    ++
    ++    <h3 id="inline-action">
    ++      Inline Action
    ++    </h3>
    ++
    ++    <p>
    ++      Wear 2.0 enables you to add an inline action within the notification
    ++      stream so that users can quickly take an action on a notification.
    ++      Examples of good use cases for an inline action within a notification stream
    ++      include replying to a text message, stopping a fitness activity, or
    ++      archiving an email message.
    ++    </p>
    ++
    ++    <p>
    ++      To learn how to add an inline action to your notification stream, see
    ++      <a href=
    ++      "https://developer.android.com/wear/preview/features/notifications.html#inline">
    ++      Inline Action</a>.
    ++    </p>
    ++
    ++    <h3 id="smart-replies">
    ++      Smart Reply
    ++    </h3>
    ++
    ++    <p>
    ++      Android Wear 2.0 introduces support for Smart Reply in <a href=
    ++      "{@docRoot}wear/preview/features/notifications.html#messaging">{@code
    ++      MessagingStyle}</a> notifications. Smart Reply provides the user with
    ++      contextually relevant, touchable choices in the expanded notification and
    ++      in <a href="{@docRoot}reference/android/app/RemoteInput.html">{@code
    ++      RemoteInput}</a>.
    ++    </p>
    ++
    ++    <p>
    ++      By enabling Smart Reply for your {@code MessagingStyle} notifications,
    ++      you provide users a fast (single tap), discreet (no speaking aloud), and
    ++      reliable way to respond to chat messages they receive.
    ++    </p>
    ++
    ++    <img src="{@docRoot}wear/preview/images/remoteinput.png" height="350"
    ++    style="float:right;margin:10px 0 0 40px">
    ++
    ++    <h3 id="remote-input">
    ++      Remote Input
    ++    </h3>
    ++
    ++    <p>
    ++      Wear 2.0 users can choose between various input options from <a href=
    ++      "{@docRoot}reference/android/app/RemoteInput.html">Remote Input</a>.
    ++      These options include:
    ++    </p>
    ++
    ++    <ul>
    ++      <li>Dictation
    ++      </li>
    ++
    ++      <li>Emoji
    ++      </li>
    ++
    ++      <li>Canned responses
    ++      </li>
    ++
    ++      <li>Smart Reply
    ++      </li>
    ++
    ++      <li>Default IME
    ++      </li>
    ++    </ul>
    ++
    ++    <p>
    ++      For messaging notifications with Smart Reply, the system-generated Smart
    ++      Reply appears within <a href=
    ++      "{@docRoot}reference/android/app/RemoteInput.html">{@code
    ++      RemoteInput}</a> above the developer-provided list of canned responses.
    ++      You can also use the <a href=
    ++      "{@docRoot}reference/android/app/RemoteInput.Builder.html#setChoices(java.lang.CharSequence[])">
    ++      setChoices()</a> method in the {@code RemoteInput} API to enable users to
    ++      select from a list of canned responses.
    ++    </p>
    ++
    ++    <h3 id="bridging">
    ++      Bridging Mode
    ++    </h3>
    ++
    ++    <p>
    ++      By default, notifications are <a href=
    ++      "{@docRoot}training/wearables/notifications/index.html">bridged</a>
    ++      (shared) from an app on a companion phone to the watch. Since a phone app
    ++      and a standalone watch app may be sources of the same notifications, the
    ++      Android Wear 2.0 Preview includes a Bridging mode feature.
    ++    </p>
    ++
    ++    <p>
    ++      For information about this feature, see <a href=
    ++      "{@docRoot}wear/preview/features/bridger.html">Bridging Mode for
    ++      Notifications</a>.
    ++    </p>
    ++
    ++    <h3 id="imf">
    ++      Input Method Framework
    ++    </h3>
    ++
    ++    <p>
    ++      Wear 2.0 extends the Android input method framework (IMF) to Android
    ++      Wear. This allows users to enter text on Wear using the system default
    ++      IME or third party IMEs. The Wear IME lets the user enter text via
    ++      gesture typing as well as tapping individual keys. The IMF APIs used for
    ++      Wear devices are the same as other form factors, though usage is slightly
    ++      different due to limited screen real estate.
    ++    </p>
    ++
    ++    <p>
    ++      Wear provides user settings on the watch that let the user:
    ++    </p>
    ++
    ++    <ul>
    ++      <li>Enable multiple IMEs from the list of installed IMEs.
    ++      </li>
    ++
    ++      <li>Set a single default IME from the list of enabled IMEs.
    ++      </li>
    ++
    ++      <li>Change languages for various IMEs.
    ++      </li>
    ++    </ul>
    ++
    ++    <p>
    ++      To learn how to create an IME for Wear, see <a href=
    ++      "{@docRoot}wear/preview/features/ime.html">Input Method Framework</a>.
    ++    </p>
    ++
    ++    <h3 id="wrist-gestures">
    ++      Wrist Gestures
    ++    </h3>
    ++
    ++    <p>
    ++      Wrist gestures can enable quick, one-handed interactions with your app
    ++      when use of a touch screen is inconvenient. The following <a href=
    ++      "https://support.google.com/androidwear/answer/6312406">wrist
    ++      gestures</a> are available for use by apps:
    ++    </p>
    ++
    ++    <ul>
    ++      <li>Flick wrist out
    ++      </li>
    ++
    ++      <li>Flick wrist in
    ++      </li>
    ++    </ul>
    ++
    ++    <p>
    ++      For more information, see <a href=
    ++      "{@docRoot}wear/preview/features/gestures.html">Wrist Gestures</a>.
    ++    </p>
    ++
    ++    <h2 id="stand-alone">
    ++      Standalone Devices
    ++    </h2>
    ++
    ++    <p>
    ++      Standalone watches enable Android Wear apps to work independently of
    ++      phone apps. This means your app can continue to offer full functionality
    ++      even if the paired phone is far away or turned off.
    ++    </p>
    ++
    ++    <h3 id="wear-apk">
    ++      Wear-Specific APKs
    ++    </h3>
    ++
    ++    <p>
    ++      For delivery to a watch, an Android Wear app is currently embedded in its
    ++      corresponding phone app. This delivery method can result in an increased
    ++      download size for users, regardless of whether they have an Android Wear
    ++      device.
    ++    </p>
    ++
    ++    <p>
    ++      For information about planning and building your standalone app
    ++      for Wear 2.0, see <a href=
    ++      "https://developer.android.com/wear/preview/features/standalone-apps.html">
    ++      Standalone Apps</a>.
    ++    </p>
    ++
    ++    <p>
    ++      For information about distributing your app, see <a href=
    ++      "https://developer.android.com/wear/preview/features/app-distribution.html">
    ++      App Distribution</a>.
    ++    </p>
    ++
    ++    <h3 id="network">
    ++      Network Access
    ++    </h3>
    ++
    ++    <p>
    ++      Since Android Wear apps will work independently of phone apps, Android
    ++      Wear's network access will no longer require the <a href=
    ++      "{@docRoot}training/wearables/data-layer/index.html">Wearable Data Layer
    ++      API</a>. Android Wear apps will have the ability to make their own
    ++      network requests. Additionally, they will be able to directly use Google
    ++      Cloud Messaging. For more information, see
    ++      <a href=
    ++      "https://developer.android.com/wear/preview/features/standalone-apps.html#network_access">
    ++      Network Access and Cloud Messaging</a>.
    ++    </p>
    ++
    ++    <p>
    ++      No APIs for network access or GCM are specific to Android Wear; refer to
    ++      the existing documentation about <a href=
    ++      "{@docRoot}training/basics/network-ops/connecting.html">Connecting to the
    ++      Network</a> and <a href=
    ++      "https://developers.google.com/cloud-messaging/">Cloud Messaging</a>.
    ++    </p>
    ++
    ++    <p>
    ++      We recommend using the following libraries:
    ++    </p>
    ++
    ++    <ul>
    ++      <li>
    ++        <a href=
    ++        "{@docRoot}reference/android/app/job/JobScheduler.html">JobScheduler</a>
    ++        for asynchronous jobs, including polling at regular intervals
    ++      </li>
    ++
    ++      <li>Multi-networking APIs, to connect to specific network
    ++      types; see <a href=
    ++      "{@docRoot}about/versions/android-5.0.html#Wireless">Multiple Network
    ++      Connections</a>
    ++      </li>
    ++    </ul>
    ++
    ++    <p>
    ++      The <a href=
    ++      "{@docRoot}training/wearables/data-layer/index.html">Wearable Data Layer
    ++      API</a> is available to communicate with a phone app.
    ++      However, use of this API to connect to a network will be discouraged.
    ++    </p>
    ++
    ++    <h3 id="auth">
    ++      Authentication
    ++    </h3>
    ++
    ++    <p>
    ++      Since Android Wear apps will work independently of phone apps, Android
    ++      Wear's authentication capabilities will be more powerful; apps will have
    ++      new ways to authenticate.
    ++    </p>
    ++
    ++    <h4>
    ++      Users can enter a username and password on a watch
    ++    </h4>
    ++
    ++    <p>
    ++      Google Keyboard will be standard on Android Wear, allowing for direct
    ++      text entry. This feature will work as expected with standard <a href=
    ++      "{@docRoot}reference/android/widget/EditText.html">EditText widgets</a>.
    ++      For passwords, the {@code textPassword} attribute will be used.
    ++    </p>
    ++
    ++    <h4>
    ++      Utilizing Account Manager
    ++    </h4>
    ++
    ++    <p>
    ++      Android Wear will include the <a href=
    ++      "{@docRoot}reference/android/accounts/AccountManager.html">AccountManager</a>,
    ++      which will be accessible for syncing and storing account data, as it is
    ++      on an Android phone.
    ++    </p>
    ++
    ++    <h4>
    ++      Authentication tokens can be passed over the Wearable Data Layer
    ++    </h4>
    ++
    ++    <p>
    ++      For Android-paired watches (only), a phone securely transfers
    ++      authentication credentials to a watch app via the <a href=
    ++      "{@docRoot}training/wearables/data-layer/index.html">Wearable Data Layer
    ++      API</a>. The credentials can be transferred as messages or data items.
    ++    </p>
    ++
    ++    <p>
    ++      If your watch app needs to determine if your phone app is installed, you
    ++      can advertise a capability on the phone app and retrieve the capability
    ++      on the watch. For more information, see the following sections of
    ++      <a href="{@docRoot}training/wearables/data-layer/messages.html">Sending
    ++      and Receiving Messages</a>:
    ++    </p>
    ++
    ++    <ul>
    ++      <li>Advertise Capabilities
    ++      </li>
    ++
    ++      <li>Retrieve the Nodes with the Required Capabilities
    ++      </li>
    ++    </ul>
    +diff --git a/docs/html/wear/preview/behavior-changes.jd b/docs/html/wear/preview/behavior-changes.jd
    +index 0214622..c93d337 100644
    +--- a/docs/html/wear/preview/behavior-changes.jd
    ++++ b/docs/html/wear/preview/behavior-changes.jd
    +@@ -22,6 +22,8 @@ page.tags="preview", "developer preview"
    + 
    + <ul>
    +   <li><a href="#activity-dismissal">Activity Dismissal</a></li>
    ++  <li><a href="#invalid-fields">Invalid Fields for a Complication Type</a></li>
    ++  <li><a href="#empty">Complication Types for Empty Data</a></li>
    + </ul>
    + 
    + </div>
    +@@ -61,3 +63,44 @@ page.tags="preview", "developer preview"
    +   <a href="{@docRoot}wear/preview/features/ui-nav-actions.html">navigation
    +   drawers</a>.
    + </p>
    ++
    ++<h2 id="invalid-fields">Invalid Fields for a Complication Type</h2>
    ++
    ++<p>
    ++  When a watch face uses the <a href="{@docRoot}wear/preview/features/complications.html">
    ++  Complications API</a>, the watch face requests data from a chosen provider.
    ++  A <code>ComplicationData</code> object, which contains
    ++  complication types, is returned.
    ++</p>
    ++
    ++<p>
    ++  A complication type determines the
    ++  kinds of data that a watch face can render. This section describes
    ++  a behavior change related to the <code>ComplicationData</code> object.
    ++</p>
    ++
    ++<p>
    ++  Starting with
    ++  <a href="https://developer.android.com/wear/preview/support.html#dp3">
    ++  Developer Preview 3</a>, when a watch face requests a field that is invalid
    ++  for a complication type, a default value for the field is returned.
    ++  For example, if a watch face tries to access a <code>Long text</code>
    ++  field in a <code>SHORT_TEXT</code> type, the default value for the
    ++  <code>Long text</code> field is returned.
    ++  In previous releases, such a request for an invalid field
    ++  (for a type) resulted in an exception.
    ++</p>
    ++
    ++<h2 id="empty">Complication Types for Empty Data</h2>
    ++
    ++<p>
    ++  Starting with
    ++  <a href="https://developer.android.com/wear/preview/support.html#dp3">
    ++  Developer Preview 3</a>, the complication types used for "empty" data are
    ++  changed. Apps that use the Complications API
    ++  may need to be updated to use
    ++  <code>TYPE_NO_DATA</code>. See the information
    ++  about <code>TYPE_NO_DATA</code> in the
    ++  <a href="{@docRoot}wear/preview/features/complications.html#types_and_fields">
    ++  Types and fields</a> section.
    ++</p>
    +diff --git a/docs/html/wear/preview/downloads.jd b/docs/html/wear/preview/downloads.jd
    +index 4bc401b..bfa384b 100644
    +--- a/docs/html/wear/preview/downloads.jd
    ++++ b/docs/html/wear/preview/downloads.jd
    +@@ -171,7 +171,9 @@ This is the Android Wear SDK Preview License Agreement (the “License Agreement
    +           <li>
    +             <a href="#set_up_a_watch">Set Up a Watch</a>
    +           </li>
    +-
    ++          <li>
    ++            <a href="#set_up_a_phone">Set Up a Phone</a>
    ++          </li>
    +           <li>
    +             <a href="#set_up_an_emulator">Set Up an Emulator</a>
    +           </li>
    +@@ -180,7 +182,7 @@ This is the Android Wear SDK Preview License Agreement (the “License Agreement
    +     </div>
    + 
    +     <p>
    +-      You can run and test your app with the Android Wear 2.0 Developer Preview
    ++      You can run and test your app with the Android Wear 2.0 Preview
    +       in either of these ways:
    +     </p>
    + 
    +@@ -237,6 +239,13 @@ This is the Android Wear SDK Preview License Agreement (the “License Agreement
    +       following tables and flash it to the corresponding device.
    +     </p>
    + 
    ++    <p class="caution"><strong>Caution:</strong>
    ++      After you flash an image to a watch, follow the steps for
    ++      <a href="#set_up_a_phone">setting up a phone</a> with the beta version of
    ++      the Android Wear companion app. To use a Wear 2.0 image on a watch,
    ++      you must have the beta companion app on a paired phone.
    ++    </p>
    ++
    +     <p>
    +       To restore your device to its original state during the preview,
    +       you can flash the appropriate retail system image, below, to the device.
    +@@ -266,9 +275,9 @@ This is the Android Wear SDK Preview License Agreement (the “License Agreement
    +         <td>
    +           Preview image for testing
    +         </td>
    +-        <td><a href="#top" onclick="onDownload(this)">nemo-nvd83h-factory-48ac950c.tgz</a><br>
    +-          MD5: dd351884cce9fb5bf1bdec0a8e5f56e3<br>
    +-          SHA-1: 48ac950c48faef96a7770e3c1acb56d23a28d859
    ++        <td><a href="#top" onclick="onDownload(this)">nemo-nve68j-factory-302a33ea.tgz</a><br>
    ++          MD5: ddfccc3e050c7e2db8d657c82f7d6291<br>
    ++          SHA-1: 302a33eac348c401fcb165bad4b9aaa40c7beb2b
    +         </td>
    +       </tr>
    + 
    +@@ -276,9 +285,9 @@ This is the Android Wear SDK Preview License Agreement (the “License Agreement
    +         <td>
    +           Non-preview image (for after testing)
    +         </td>
    +-        <td><a href="#top" onclick="onDownload(this)">nemo-mnc40x-factory-fa528bec.tgz</a><br>
    +-          MD5: 0b8ba3653d5a93cb854f4d7409d7b6c9<br>
    +-          SHA-1: fa528bec8aba3bf6c7d901ba63cd6ea0a08dbeb0
    ++        <td><a href="#top" onclick="onDownload(this)">nemo-mfd18l-factory-3faf6f2d.tgz</a><br>
    ++          MD5: f3a0090c0e99da82ad095b5d2a9acc6d<br>
    ++          SHA-1: 3faf6f2d7f422a17a5f6c54cf5e1d2c5622689b0
    +         </td>
    +       </tr>
    + 
    +@@ -307,18 +316,18 @@ This is the Android Wear SDK Preview License Agreement (the “License Agreement
    +         <td>
    +           Preview image for testing
    +         </td>
    +-        <td><a href="#top" onclick="onDownload(this)">sturgeon-nvd83h-factory-cb5a11ab.tgz</a><br>
    +-          MD5: 38c1047992b1d28f6833d9f6c8470cdc<br>
    +-          SHA-1: cb5a11ab0260ea3ca7da5894e73e41f70357da6b
    ++        <td><a href="#top" onclick="onDownload(this)">sturgeon-nve68j-factory-6607cd31.tgz</a><br>
    ++          MD5: f78ac6ba8bb84038d163cc2d7ca85040<br>
    ++          SHA-1: 6607cd31858af1bfd50b905c68f7cf1f0b6e570e
    +         </td>
    +       </tr>
    +       <tr id="sturgeon-non-preview">
    +         <td>
    +           Non-preview image (for after testing)
    +         </td>
    +-        <td><a href="#top" onclick="onDownload(this)">sturgeon-mec23l-factory-48003078.tgz</a><br>
    +-          MD5: 417b5cbddb29a2262bce133e283d2732<br>
    +-          SHA-1: 4800307843580f818557dd7c43d8ba2161e289b2
    ++        <td><a href="#top" onclick="onDownload(this)">sturgeon-m6e69f-factory-e659286a.tgz</a><br>
    ++          MD5: 12ce6cb0b0e43b67ea46a886eae052ae<br>
    ++          SHA-1: e659286aa9004f4555a476ede4e8b690f56cfefd
    +         </td>
    +       </tr>
    +     </table>
    +@@ -337,7 +346,8 @@ This is the Android Wear SDK Preview License Agreement (the “License Agreement
    +     </p>
    + 
    +     <p class="warning">
    +-      <strong>Warning:</strong> Installing a system image on a watch removes all data from the
    ++      <strong>Warning:</strong> Installing a system image on a watch
    ++      removes all data from the
    +       watch, so you should back up your data first.
    +     </p>
    + 
    +@@ -346,8 +356,7 @@ This is the Android Wear SDK Preview License Agreement (the “License Agreement
    +     </h4>
    + 
    +     <p>
    +-      From the phone, unpair ("Forget") the watch.
    +-      Then on the watch, enable the Developer Options menu and ADB debugging as
    ++      On the watch, enable the Developer Options menu and ADB debugging as
    +       follows:
    +     </p>
    + 
    +@@ -356,14 +365,14 @@ This is the Android Wear SDK Preview License Agreement (the “License Agreement
    +       </li>
    + 
    +       <li>Scroll to the bottom of the menu. If no <strong>Developer
    +-      Options</strong> item is provided, tap <strong>About</strong>.
    ++      Options</strong> item is provided, tap <strong>System</strong>
    ++      and then <strong>About</strong>.
    +       </li>
    + 
    +       <li>Tap the build number 7 times.
    +       </li>
    + 
    +-      <li>From the Settings menu, tap the <strong>Developer Options</strong>
    +-      item.
    ++      <li>From the Settings menu, tap <strong>Developer Options</strong>.
    +       </li>
    + 
    +       <li>Enable ADB debugging.
    +@@ -409,7 +418,9 @@ This is the Android Wear SDK Preview License Agreement (the “License Agreement
    +       </li>
    + 
    +       <li>Use the following <a href="{@docRoot}tools/help/adb.html">adb
    +-      command</a> to confirm that the watch is available for flashing:
    ++      command</a> to confirm that the watch is recognized.
    ++      You may need to turn ADB debugging off and then on for the watch to
    ++      be recognized:
    +       <code>adb devices</code>
    +       </li>
    + 
    +@@ -423,11 +434,11 @@ This is the Android Wear SDK Preview License Agreement (the “License Agreement
    +       devices, <code>fastboot oem unlock</code>
    +       </li>
    + 
    +-      <li>On the watch, select the <strong>Unlock</strong> option.
    ++      <li>On the watch, select the option to unlock the bootloader.
    +       </li>
    + 
    +-      <li>Navigate to the directory where you unzipped the system image in Step
    +-      1. At the top level of that directory,
    ++      <li>On your computer, navigate to the directory where you unzipped the
    ++      system image in Step 1. At the top level of that directory,
    +       execute the <code>flash-all</code> script by typing
    +       <code>flash-all.sh</code> or, in the case of Windows,
    +       <code>flash-all.bat</code>. The following may need to
    +@@ -437,18 +448,19 @@ This is the Android Wear SDK Preview License Agreement (the “License Agreement
    + 
    + 
    +     <h4 id="set_up_watch">
    +-      Set up the watch and begin testing
    ++      Set up the watch
    +     </h4>
    + 
    +-      <p>
    +-        After the <code>flash-all</code> script finishes, your watch reboots.
    +-        Pair the watch with a phone or tablet. The preview now is available
    +-        for testing on the watch. Before installing an app, perform the
    +-        following steps on the watch to re-secure the watch's bootloader:
    ++    <p>
    ++      After the <code>flash-all</code> script finishes, the watch reboots.
    ++      Only pair the watch with a phone (so you can begin testing the preview)
    ++      by using the instructions in <a href="#set_up_a_phone">Set Up a Phone</a>.
    ++      Additionally, before installing an app, perform the
    ++      following steps on the watch to re-secure the watch's bootloader:
    +     </p>
    + 
    +     <ol>
    +-      <li>Open the Settings menu (on the watch).
    ++      <li>Open the Settings menu by long-pressing the physical button.
    +       </li>
    + 
    +       <li>Scroll to the bottom of the menu and tap <strong>About</strong>.
    +@@ -457,15 +469,16 @@ This is the Android Wear SDK Preview License Agreement (the “License Agreement
    +       <li>Tap the build number 7 times.
    +       </li>
    + 
    +-      <li>From the Settings menu, tap the <strong>Developer Options</strong>
    +-      item.
    ++      <li>From the Settings menu, tap <strong>Developer Options</strong>.
    +       </li>
    + 
    +       <li>Enable ADB debugging.
    +       </li>
    + 
    +       <li>Connect the watch to your computer and tap <strong>Always allow from
    +-      this computer</strong>.
    ++      this computer</strong>. (You may need to turn ADB debugging off
    ++      and then on, to be prompted to always allow ADB debugging from
    ++      the connected computer.)
    +       </li>
    + 
    +       <li>Use the following adb command to start the device in fastboot mode:
    +@@ -477,13 +490,18 @@ This is the Android Wear SDK Preview License Agreement (the “License Agreement
    +       devices, <code>fastboot oem lock</code>
    +       </li>
    + 
    +-      <li>On the watch, continue the boot by choosing
    +-      <strong>Start</strong> and touching <strong>'0'</strong>.
    ++      <li>On the watch, continue the boot as follows:
    ++      On an LGE Watch Urbane 2nd Edition, choose
    ++      <strong>Start</strong> and touch <strong>'0'</strong>.
    ++      On a Huawei Watch, confirm that <strong>Reboot</strong> is chosen and
    ++      long-press the physical button.
    +       </li>
    +     </ol>
    + 
    +     <p>
    +-      Your watch is ready for you to <a href=
    ++      After you follow the instructions in
    ++      <a href="#set_up_a_phone">Set Up a Phone</a>,
    ++      your watch will be ready for you to <a href=
    +       "{@docRoot}training/wearables/apps/creating.html#Install">install and run
    +       your app</a>:
    +     </p>
    +@@ -539,13 +557,116 @@ This is the Android Wear SDK Preview License Agreement (the “License Agreement
    +       device reset and removes all user data on the device.
    +     </p>
    + 
    ++    <h2 id="set_up_a_phone">
    ++      Set Up a Phone
    ++    </h2>
    ++
    ++    <p>
    ++      On a phone, follow the instructions in this section to install the beta
    ++      version of the Android Wear companion app. The beta version cannot be run
    ++      on a phone at the same time as the non-beta version. Additionally, the
    ++      beta version is English-only.
    ++    </p>
    ++
    ++    <p>
    ++      <p class="caution"><strong>Caution:</strong> If you have an existing
    ++      pairing of the phone to a Wear 1.x
    ++      watch, installation of the beta companion app will cause a loss of that
    ++      pairing.
    ++    </p>
    ++
    ++    <h3 id="join-the-wear-2-0-preview-group">
    ++      Join the Wear 2.0 preview group
    ++    </h3>
    ++
    ++    <p>
    ++      To access the beta companion app, you must <a href=
    ++      "https://groups.google.com/forum/#!forum/android-wear-developer-preview">join
    ++      the preview group in Google Groups</a>.
    ++    </p>
    ++
    ++    <h3>
    ++      Opt in for beta testing
    ++    </h3>
    ++
    ++    <p>
    ++      On the <a href=
    ++      "https://play.google.com/apps/testing/com.google.android.wearable.app">Testing
    ++      Opt-in</a> page, select <strong>Become a Tester</strong>.
    ++    </p>
    ++
    ++    <h3 id="download-and-install-the-beta-version-of-the-companion-app">
    ++      Download and install the beta version of the companion app
    ++    </h3>
    ++
    ++    <p>
    ++      On the Play Store on your phone, go to the <a href=
    ++      "https://play.google.com/store/apps/details?id=com.google.android.wearable.app">
    ++      Android Wear app listing</a>. Tap <strong>Update</strong> to download and
    ++      install the beta version of the app. After installation, confirm that
    ++      <strong>Auto-update</strong> is selected for the app (see
    ++      the "Set up automatic updates for specific apps" section of <a href=
    ++      "https://support.google.com/googleplay/answer/113412">Update downloaded
    ++      apps</a>). Tap <strong>Open</strong> to start the app.
    ++    </p>
    ++
    ++    <h3 id="pairing">
    ++      Pair the phone to the watch
    ++    </h3>
    ++
    ++    <p>
    ++      After you install the beta version of the companion app on a phone,
    ++      unpair ("Forget") any obsolete watch pairings, if necessary.
    ++      Then you can pair the phone to a newly-imaged watch:
    ++    </p>
    ++
    ++    <ol>
    ++      <li>On the phone, select your device name from the list of devices.
    ++      A pairing code is displayed on the phone and on the watch.
    ++      Ensure that the codes match.
    ++      </li>
    ++
    ++      <li>Tap <strong>Pair</strong> to
    ++      continue the pairing process. When the watch is connected to
    ++      the phone, a confirmation message is displayed.
    ++      On the phone, a screen is displayed that lists
    ++      the accounts on the phone.
    ++      </li>
    ++
    ++      <li>Choose a Google Account to add and sync to your watch.
    ++      </li>
    ++
    ++      <li>Confirm the screen lock and enter the password to start the copying of
    ++      the account from the phone to the watch.
    ++      </li>
    ++
    ++      <li>Follow the instructions in the wizard to finish the
    ++      pairing process.
    ++      </li>
    ++    </ol>
    ++
    ++    <p>
    ++      You can begin testing your app with the preview.
    ++    </p>
    ++
    +     <h2 id="set_up_an_emulator">
    +       Set Up an Emulator
    +     </h2>
    + 
    +     <p>
    +-      To test with the Android Emulator, create a virtual device in Android
    +-      Studio as follows:
    ++      To test with the Android Emulator,
    ++      confirm that you have the latest version of the <strong>Android SDK
    ++      Platform-tools</strong> from the <a href=
    ++      "{@docRoot}studio/intro/update.html#sdk-manager">SDK Manager</a>.
    ++    </p>
    ++
    ++    <p>
    ++      After you create a virtual device as described below, follow the steps for
    ++      <a href="#set_up_a_phone">setting up a phone</a> with the beta version of
    ++      the Android Wear companion app.
    ++    </p>
    ++
    ++    <p>Create a new virtual device in Android Studio as follows:
    +     </p>
    + 
    +     <ol>
    +@@ -556,19 +677,19 @@ This is the Android Wear SDK Preview License Agreement (the “License Agreement
    +       <li>Click <strong>Create Virtual Device</strong>.
    +       </li>
    + 
    +-      <li>In the <strong>Category</strong> pane, select Wear and
    +-       choose a hardware profile.
    ++      <li>In the <strong>Category</strong> pane, select <strong>Wear</strong>
    ++       and choose a hardware profile.
    +        The Android Wear 2.0 Developer Preview
    +        is only optimized for round devices currently, so we recommend not
    +        using the square or chin profiles for now.
    +        Click <strong>Next</strong>.
    +       </li>
    + 
    +-      <li>Select an <strong>N</strong> image to download. The images may be on
    ++      <li>Select a <strong>Nougat</strong> image to download. The images may be on
    +       the <strong>x86</strong> tab instead of the <strong>Recommended</strong>
    +       tab, until installed. For example, select the image with the
    +-      <strong>Release Name</strong> of N, the <strong>API Level</strong> of N,
    +-      and the <strong>Target</strong> of "Android 6.X (with Android Wear)".
    ++      <strong>Release Name</strong> of Nougat, the <strong>API Level</strong> of 24,
    ++      and the <strong>Target</strong> of "Android 7.0 (with Android Wear)".
    +       When the download and installation are complete, click
    +       <strong>Finish</strong> and then click <strong>Next</strong>.
    +       </li>
    +@@ -576,16 +697,68 @@ This is the Android Wear SDK Preview License Agreement (the “License Agreement
    +       <li>Verify the configuration of the Android Virtual Device (AVD) and
    +       click <strong>Finish</strong>.
    +       </li>
    ++
    ++      <li>Start the emulator by selecting the new virtual device, clicking the
    ++      <strong>Play</strong> button, and waiting until
    ++      the emulator initializes and shows the Android Wear home screen.
    ++      </li>
    +     </ol>
    + 
    +     <p>
    +-      You can now test an application with a virtual preview device
    ++      Pair the phone with the emulator, and sync a Google Account, as follows:
    ++    </p>
    ++
    ++    <ol>
    ++      <li>Follow the steps for
    ++      <a href="#set_up_a_phone">setting up a phone</a> with the beta version of
    ++      the Android Wear companion app.
    ++      </li>
    ++
    ++      <li>On the phone, enable Developer Options and USB Debugging.
    ++      </li>
    ++
    ++      <li>Connect the phone to your computer through USB.
    ++      </li>
    ++
    ++      <li>Forward the AVD's communication port to the connected handheld device
    ++      (each time the phone is connected):<br>
    ++      <code>adb -d forward tcp:5601 tcp:5601</code>
    ++      </li>
    ++
    ++      <li>On the phone, in the Android Wear app, begin the standard pairing
    ++      process. For example, on the Welcome screen, tap the
    ++      <strong>Set It Up</strong> button.
    ++      Alternatively, if an existing watch already is paired, in the upper-left
    ++      drop-down, tap <strong>Add a New Watch</strong>.
    ++      </li>
    ++
    ++      <li>On the phone, in the Android Wear app, tap the
    ++      Overflow button, and then tap
    ++      <strong>Pair with Emulator</strong>.
    ++      </li>
    ++
    ++      <li>Tap the Settings icon.
    ++      </li>
    ++
    ++      <li>Under Device Settings, tap <strong>Emulator</strong>.
    ++      </li>
    ++
    ++      <li>Tap <strong>Accounts</strong> and select a Google Account,
    ++      and follow the steps in the wizard to
    ++      sync the account with the emulator. If necessary, type the screen-lock
    ++      device password, and Google Account password, to start the account sync.
    ++      </li>
    ++    </ol>
    ++
    ++    <p>
    ++      You can now test an app with a virtual preview device
    +       in the <a href=
    +       "{@docRoot}tools/devices/emulator.html">Android Emulator</a>. For more
    +       information about using virtual devices, see <a href=
    +-      "{@docRoot}tools/devices/managing-avds.html">Managing AVDs with the AVD
    +-      Manager</a>.
    ++      "{@docRoot}studio/run/managing-avds.html">
    ++      Create and Manage Virtual Devices</a>.
    +     </p>
    ++
    +  </div><!-- landing -->
    + 
    + </div><!-- relative wrapper -->
    +diff --git a/docs/html/wear/preview/features/app-distribution.jd b/docs/html/wear/preview/features/app-distribution.jd
    +new file mode 100644
    +index 0000000..afc9516
    +--- /dev/null
    ++++ b/docs/html/wear/preview/features/app-distribution.jd
    +@@ -0,0 +1,329 @@
    ++page.title=App Distribution
    ++meta.keywords="wear-preview"
    ++page.tags="wear-preview"
    ++page.image=images/cards/card-n-sdk_2x.png
    ++@jd:body
    ++
    ++<div id="qv-wrapper">
    ++<div id="qv">
    ++
    ++<h2>In this document</h2>
    ++
    ++  <ul>
    ++    <li><a href="#publish">Publish Your APKs</a></li>
    ++    <li><a href="#targeting">Setting Up Targeting for a Watch</a></li>
    ++    <li><a href="#console">Using the Play Developer Console</a></li>
    ++  </ul>
    ++
    ++</div>
    ++</div>
    ++
    ++    <p>
    ++      With Android Wear 2.0, a user can visit the Play Store on a watch and
    ++      download a Wear app directly to the watch.
    ++    </p>
    ++
    ++    <p>
    ++      Generally, a Wear 2.0 app in the Play Store needs
    ++      a minimum and target API level of 24 or higher in
    ++      the Android manifest file. The minimum SDK level can be 23
    ++      only if you are using the same APK
    ++      for Wear 1.0 and 2.0 (and thus have an embedded Wear 1.0 APK).
    ++    </p>
    ++
    ++    <h2 id="publish">
    ++      Publish Your APKs
    ++    </h2>
    ++
    ++    <p>
    ++      To make your app appear in the on-watch Play Store, upload
    ++      the watch APK in the Play Developer Console just as you would any other
    ++      APK. If you only have a watch APK and no phone APK, no other steps
    ++      are required.
    ++    </p>
    ++
    ++    <p>
    ++      If you have a phone APK in addition to a watch APK, you must use the
    ++      <a href="https://developer.android.com/google/play/publishing/multiple-apks.html">Multi-APK delivery method</a>.
    ++    </p>
    ++
    ++    <p>
    ++      <a href=
    ++      "https://developer.android.com/training/permissions/requesting.html">Run-time
    ++      permissions</a> are required.
    ++    </p>
    ++
    ++    <p>
    ++      Also see
    ++      <a href="{@docRoot}wear/preview/features/standalone-apps.html">
    ++      Standalone Apps</a>.
    ++    </p>
    ++
    ++    <h3>
    ++      Distribution to Wear 2.0 watches
    ++    </h3>
    ++
    ++    <p>
    ++      If you only want your app to be distributed to Wear 2.0 watches,
    ++      it is unnecessary to embed the watch APK inside the the phone APK.
    ++    </p>
    ++
    ++    <p>
    ++      If you want your app to
    ++      be distributed to Wear 1.0 watches, you need to embed the
    ++      watch APK inside the phone APK, as described directly below.
    ++    </p>
    ++
    ++    <h3>
    ++      Distribution to Wear 1.0 and 2.0 watches
    ++    </h3>
    ++
    ++    <p>
    ++      If you are already distributing your app to Wear 1.0 watches,
    ++      follow these steps:
    ++    </p>
    ++
    ++    <ol>
    ++      <li>Provide a Wear 2.0 (standalone) version of your watch APK that can be made
    ++      available in the Play Store on Wear.
    ++      </li>
    ++
    ++      <li>Continue embedding a Wear 1.0 APK in your phone APK,
    ++      for use by watches that do not have Wear 2.0.
    ++      </li>
    ++    </ol>
    ++
    ++    <h3>
    ++      Specifying a version code
    ++    </h3>
    ++
    ++    <p>
    ++      To ensure that a standalone APK acts as an upgrade to an embedded Wear APK, the
    ++      standalone Wear APK's <a href=
    ++      "https://developer.android.com/google/play/publishing/multiple-apks.html#VersionCodes">
    ++      version code</a> generally should be higher than the embedded Wear APK's version code.
    ++      (A phone APK's version code scheme can be independent from that of a watch
    ++      APK, although they must be unique.) However, the version codes
    ++      of the standalone APK and the embedded Wear APK can be the same if
    ++      the APKs are equivalent. If the APKs are not equivalent,
    ++      but the version code is the same, then when a watch updates from Wear 1.0
    ++      to 2.0, the watch may get the new APK only after waiting for a
    ++      longer-than-expected period of time.
    ++    </p>
    ++
    ++    <p>
    ++      Note that it currently is not possible to create a single APK that works
    ++      on a phone and watch.
    ++    </p>
    ++
    ++    <h3>
    ++      Support in the Gradle file
    ++    </h3>
    ++
    ++    <p>
    ++      If you have a Wear app that is intended for both Wear 1.0 and Wear 2.0,
    ++      consider using <a href=
    ++      "https://developer.android.com/studio/build/build-variants.html#product-flavors">
    ++      product flavors</a>. For example,
    ++      if you want to target both SDK version 23 and version 24,
    ++      update your Wear module's <code>build.gradle</code> file to include
    ++      the following if an existing embedded app has a minimum SDK version of 23:
    ++    </p>
    ++
    ++<pre>
    ++android {
    ++    // Allows you to reference product flavors in your
    ++    // phone module's build.gradle file
    ++    publishNonDefault true
    ++    ...
    ++    defaultConfig
    ++    {
    ++       // This is the minSdkVersion of the Wear 1.0 embedded app
    ++       minSdkVersion 23
    ++       ...
    ++    }
    ++    buildTypes {...}
    ++    productFlavors {
    ++        wear1 {
    ++          // Use the defaultConfig value
    ++        }
    ++        wear2 {
    ++            minSdkVersion 24
    ++        }
    ++    }
    ++}
    ++</pre>
    ++
    ++    <p>
    ++      Then update your phone module’s <code>build.gradle</code> file, replacing
    ++      <code>wearApp</code> as follows:
    ++    </p>
    ++
    ++<pre>
    ++dependencies {
    ++    ...
    ++    wearApp project(path: ':wear', configuration: 'wear1Release')
    ++}
    ++</pre>
    ++
    ++    <p>
    ++      A <a href=
    ++      "https://developer.android.com/studio/build/build-variants.html#product-flavors">
    ++      build variant</a> is a combination of the product flavor and build type.
    ++      In Android Studio, select the appropriate build variant when
    ++      debugging or publishing your app. For example, if <code>wear2</code> is a
    ++      product flavor, select <strong>wear2Release</strong> as the
    ++      release build variant.
    ++    </p>
    ++
    ++    <p>
    ++      For purposes of code that is Wear 2.0-specific or Wear 1.0-specific,
    ++      consider <a href=
    ++      "https://developer.android.com/studio/build/build-variants.html#sourcesets">
    ++      source sets for build variants</a>.
    ++    </p>
    ++
    ++
    ++    <h2 id="targeting">
    ++      Setting Up Targeting for a Watch
    ++    </h2>
    ++
    ++    <p>
    ++      In your Android Manifest file, you must specify the following feature
    ++      restriction: the <code>uses-feature</code> element is set to
    ++      <code>android.hardware.type.watch</code>. Do not set
    ++      the <code>required</code> attribute to <code>false</code>.
    ++      A single APK for Wear and non-Wear devices presently is not supported.
    ++    </p>
    ++
    ++    <p>
    ++      Thus, if an APK has the following setting, Google Play provides the APK
    ++      to watches only:
    ++    </p>
    ++
    ++<pre>
    ++&lt;manifest package=&quot;com.example.standalone&quot;
    ++    xmlns:android=&quot;http://schemas.android.com/apk/res/android&quot;&gt;
    ++    &lt;uses-feature
    ++        android:name=&quot;android.hardware.type.watch&quot;
    ++    ...
    ++&lt;/manifest&gt;
    ++</pre>
    ++
    ++    <p>
    ++      The <code>android.hardware.type.watch</code> setting above can be
    ++      combined with other criteria such as SDK version, screen resolution, and
    ++      CPU architecture. Thus, different Wear APKs can target different hardware
    ++      configurations.
    ++    </p>
    ++
    ++    <h2 id="console">
    ++      Using the Play Developer Console
    ++    </h2>
    ++
    ++    <p>
    ++      Below is an introduction to <a href=
    ++      "https://support.google.com/googleplay/android-developer/answer/113469">uploading</a>
    ++      a standalone Wear APK to an application listing using the Play Developer
    ++      Console.
    ++    </p>
    ++
    ++    <p>
    ++      If your app supports both Wear 1.0 and Wear 2.0, continue embedding the
    ++      Wear 1.0 APK (minimum SDK version of 20, 21, or 22, or 23) in the phone
    ++      APK and upload the phone APK. In addition, upload your standalone Wear
    ++      2.0 APK (which has a minimum SDK version of 24).
    ++    </p>
    ++
    ++    <p>
    ++      Also see <a href=
    ++      "https://developer.android.com/google/play/publishing/multiple-apks.html">
    ++      Multiple APK Support</a> and <a href=
    ++      "https://developer.android.com/distribute/googleplay/developer-console.html#manage">
    ++      Manage Your App</a>.
    ++      Before uploading an APK as described below, the APK
    ++      must be <a href=
    ++      "https://developer.android.com/studio/publish/app-signing.html#release-mode">
    ++      signed</a>.
    ++    </p>
    ++
    ++     <h3  id="uploading-apk">
    ++      Uploading your APK
    ++    </h3>
    ++
    ++    <p>
    ++      Go to the <a href="https://play.google.com/apps/publish">Play Developer
    ++      Console</a>, navigate to your application listing, and select
    ++      <strong>APK</strong> in the left-navigation panel. An APK screen similar to
    ++      the following is displayed:
    ++    </p>
    ++    <img src="../images/apk-tabs.png" width="" alt="alt_text">
    ++
    ++    <p>
    ++      You may need to use advanced mode for uploads, as follows:
    ++    </p>
    ++
    ++    <ul>
    ++      <li>Advanced mode is unnecessary if you only have a Wear 2.0 app and no
    ++      phone app. Instead of advanced mode, use simple mode.</li>
    ++
    ++      <li>Use advanced mode if you support Wear 1.0 or have a phone app.</li>
    ++    </ul>
    ++
    ++    <p>
    ++      Therefore, on the above APK screen, to determine whether to click
    ++      the <strong>Switch to advanced mode</strong>
    ++      button, consider the following:
    ++    </p>
    ++
    ++    <ul>
    ++      <li>If your app does not support Wear 1.0, and only has a watch APK,
    ++      upload it using simple mode.
    ++      </li>
    ++
    ++      <li>If your app does not support Wear 1.0 and has both a watch APK and a
    ++      phone APK, click <strong>Switch to advanced mode</strong>
    ++      to upload the watch and phone APKs.
    ++      </li>
    ++    </ul>
    ++
    ++    <p>
    ++      See <a href=
    ++      "https://developer.android.com/google/play/publishing/multiple-apks.html#SimpleAndAdvanced">
    ++      Simple mode and advanced mode</a> for more information about toggling
    ++      between modes.
    ++    </p>
    ++
    ++    <p>
    ++      Select the appropriate tab (<strong>Production</strong>, <strong>Beta
    ++      Testing</strong>, or <strong>Alpha Testing</strong>) for your upload.
    ++      Then click
    ++      the <strong>Upload New APK</strong> button and select your standalone
    ++      Wear APK for upload.
    ++    </p>
    ++
    ++    <h3>
    ++      Reviewing and publishing
    ++    </h3>
    ++
    ++    <p>
    ++      After you upload your standalone Wear APK and scroll down the resulting
    ++      page, the APK is shown in the <strong>Current APK</strong> table, with a
    ++      version number, in a similar way to the following:
    ++    </p>
    ++    <img src="../images/current-apk.png" width="" alt="alt_text">
    ++
    ++    <p>
    ++      Finally, in the <strong>Current APK</strong> table above, click the line
    ++      with the <strong>Version</strong> to review the APK. The <strong>APK
    ++      Details</strong> panel is displayed. You can verify, for example, that
    ++      the number in the <strong>Supported Android Devices</strong> line is far
    ++      fewer than the number would be for a typical phone APK:
    ++    </p>
    ++    <img src="../images/apk-details.png" width="" alt="alt_text">
    ++
    ++    <p>
    ++      When you are ready, <a href=
    ++      "https://support.google.com/googleplay/android-developer/answer/6334282">publish</a>
    ++      your app.
    ++    </p>
    +diff --git a/docs/html/wear/preview/features/bridger.jd b/docs/html/wear/preview/features/bridger.jd
    +index b7be093..2d879ca 100644
    +--- a/docs/html/wear/preview/features/bridger.jd
    ++++ b/docs/html/wear/preview/features/bridger.jd
    +@@ -6,19 +6,26 @@ page.tags="wear-preview"
    + 
    +     <div id="qv-wrapper">
    +       <div id="qv">
    +-        <ol>
    ++        <ul>
    +           <li>
    +             <a href=
    +-            "#preventing_bridging_with_the_bridging_mode_feature">Preventing
    +-            Bridging with the Bridging Mode Feature</a>
    ++            "#using-an-entry-in-the-manifest-file">Specifying a Bridging Configuration in the Manifest File</a>
    +           </li>
    + 
    +           <li>
    +             <a href=
    +-            "#using_a_dismissal_id_to_sync_notification_dismissals">Using a
    +-            Dismissal ID to Sync Notification Dismissals</a>
    ++            "#specifying-a-bridging-configuration-at-runtime">Specifying a Bridging Configuration at Runtime</a>
    +           </li>
    +-        </ol>
    ++          <li>
    ++            <a href=
    ++            "#existing-method-of-preventing-bridging">Existing Method of Preventing Bridging</a>
    ++          </li>
    ++
    ++          <li>
    ++            <a href=
    ++            "#using_a_dismissal_id_to_sync_notification_dismissals">Using a Dismissal ID to Sync Notification Dismissals</a>
    ++          </li>
    ++        </ul>
    +       </div>
    +     </div>
    + 
    +@@ -27,19 +34,20 @@ page.tags="wear-preview"
    +       "{@docRoot}training/wearables/notifications/index.html">are bridged
    +       (shared)</a> from an app on a companion phone to the watch. If you build
    +       a standalone watch app and have a companion phone app, they may duplicate
    +-      notifications. The Android Wear 2.0 Preview includes a Bridging mode
    +-      feature to handle this problem of repeated notifications.
    ++      notifications. The Android Wear 2.0 Preview includes
    ++      features to handle this problem of repeated notifications.
    +     </p>
    + 
    +     <p>
    +-      With the Android Wear 2.0 Preview, developers can change the
    +-      behavior of notifications with the following:
    ++      With the Android Wear 2.0 Preview, developers can change the behavior of
    ++      notifications with one or more of the following:
    +     </p>
    + 
    +     <ul>
    +-      <li>Specifying in the standalone app's Android manifest file that
    +-      notifications from the corresponding phone app should not be
    +-      bridged to the watch
    ++      <li>Specifying a bridging configuration in the manifest file
    ++      </li>
    ++
    ++      <li>Specifying a bridging configuration at runtime
    +       </li>
    + 
    +       <li>Setting a dismissal ID so notification dismissals are synced across
    +@@ -47,43 +55,201 @@ page.tags="wear-preview"
    +       </li>
    +     </ul>
    + 
    +-    <h2 id="preventing_bridging_with_the_bridging_mode_feature">
    +-      Preventing Bridging with the Bridging Mode Feature
    ++    <h2 id="using-an-entry-in-the-manifest-file">
    ++      Specifying a Bridging Configuration in the Manifest File
    +     </h2>
    + 
    +     <p>
    +-      To prevent bridging of notifications from a phone app, you can use an
    ++      An app's Android manifest file can indicate that notifications from the
    ++      corresponding phone app should not be bridged to the watch. Specifically,
    ++      to prevent bridging of notifications from a phone app, you can use a
    ++      <code>&lt;meta-data&gt;</code>
    +       entry in the manifest file of the watch app (e.g. the standalone watch
    +       app), as follows:
    +     </p>
    + 
    +-    <pre>
    ++<pre>
    + com.google.android.wearable.notificationBridgeMode
    +-    </pre>
    ++</pre>
    + 
    +     <p>
    +       Setting that entry to <code>NO_BRIDGING</code> will prevent bridging:
    +     </p>
    + 
    +-    <pre>
    +-&lt;meta-data android:name="com.google.android.wearable.notificationBridgeMode"
    +-                   android:value="NO_BRIDGING" /&gt;
    ++<pre>
    ++&lt;meta-data android:name=&quot;com.google.android.wearable.notificationBridgeMode&quot;
    ++                   android:value=&quot;NO_BRIDGING&quot; /&gt;
    + </pre>
    ++
    +     <p>
    +-      The default bridging behavior occurs if you do not include the entry or
    ++      The default bridging behavior occurs if you do not
    ++      include the <code>&lt;meta-data&gt;</code> entry or
    +       if you specify a value of <code>BRIDGING</code> instead of
    +       <code>NO_BRIDGING</code>.
    +     </p>
    + 
    +-    <h3 id="existing_method_of_preventing_bridging">
    +-      Existing method of preventing bridging
    ++    <p>
    ++      For an existing app, if you are using
    ++      Google Cloud Messaging (GCM) or Firebase Cloud
    ++      Messaging (FCM) to send notification alerts to devices,
    ++      you may already have disabled bridging in case a phone is not
    ++      connected at the time of receiving an alert.
    ++      In this case, you may still want to dismiss the notification
    ++      across other devices when it is dismissed in a watch app.
    ++    </p>
    ++
    ++    <p>
    ++      The bridging configuration that is set in the manifest takes effect as
    ++      soon as a watch app is installed.
    ++    </p>
    ++
    ++    <h2 id="specifying-a-bridging-configuration-at-runtime">
    ++      Specifying a Bridging Configuration at Runtime
    ++    </h2>
    ++
    ++    <p>
    ++      This section describes how to specify a bridging configuration at runtime
    ++      using the <code>BridgingManager</code> class
    ++      <code>(android.support.wearable.notifications.BridgingManager)</code>.
    ++    </p>
    ++
    ++    <p>
    ++      You can set a bridging mode, and optionally set tags for notifications
    ++      that are exempt from the bridging mode, using a
    ++      <code>BridgingManager</code> object. Specifically, create a
    ++      <code>BridgingConfig</code> object and set it as shown in this section,
    ++      optionally using the <code>setBridgingEnabled</code> method. If you
    ++      specify a bridging configuration at runtime, then if the
    ++      <code>setBridgingEnabled</code> method is not set, bridging is enabled by
    ++      default.
    ++    </p>
    ++
    ++    <p>
    ++      Specifying a bridging configuration at runtime overrides a
    ++      bridging-related setting in the Android manifest file.
    ++    </p>
    ++
    ++    <h3 id="disable-bridging-for-all-notifications">
    ++      Disable bridging for all notifications
    ++    </h3>
    ++
    ++    <p>
    ++      You can use the <code>setBridgingEnabled</code> method, as follows:
    ++    </p>
    ++
    ++<pre>
    ++BridgingManager.setConfig(context,
    ++  new BridgingConfig.Builder(context)
    ++    .setBridgingEnabled(false)
    ++    .build());
    ++</pre>
    ++    <p>
    ++      If the above setter is not called, the bridging mode defaults to true.
    ++      Here is an example of setting tags without using the
    ++      <code>setBridgingEnabled</code> method, excluding notifications with a
    ++      tag of <code>foo</code> or <code>bar</code>:
    ++    </p>
    ++
    ++<pre>
    ++BridgingManager.setConfig(context,
    ++  new BridgingConfig.Builder(context)
    ++    .addExcludedTag("foo")
    ++    .addExcludedTag("bar")
    ++    .build());
    ++</pre>
    ++    <h3 id="exempt-notifications-that-are-tagged">
    ++      Exempt notifications that are tagged
    +     </h3>
    + 
    +     <p>
    ++      You can disable bridging for all notifications except those with certain
    ++      tags.
    ++    </p>
    ++
    ++    <p>
    ++      For example, you can disable bridging, except for notifications tagged as
    ++      <code>foo</code> or <code>bar,</code> with the following:
    ++    </p>
    ++
    ++<pre>
    ++BridgingManager.setConfig(context,
    ++  new BridgingConfig.Builder(context)
    ++    .setBridgingEnabled(false)
    ++    .addExcludedTag("foo")
    ++    .addExcludedTag("bar")
    ++    .build());
    ++</pre>
    ++
    ++    <p>
    ++      As another example, you can disable bridging for all notifications except
    ++      for notifications tagged as <code>foo</code>, <code>bar</code> or
    ++      <code>baz</code>.
    ++    </p>
    ++
    ++    <pre>
    ++BridgingManager.setConfig(context,
    ++  new BridgingConfig.Builder(context)
    ++    .setBridgingEnabled(false)
    ++    .addExcludedTags(Arrays.asList("foo", "bar", "baz"))
    ++    .build());
    ++</pre>
    ++    <h3 id="enable-bridging-except-for-notifications-with-certain-tags">
    ++      Enable bridging except for notifications with certain tags
    ++    </h3>
    ++
    ++    <p>
    ++      You can enable bridging for all notifications except those with certain
    ++      tags.
    ++    </p>
    ++
    ++    <p>
    ++      For example, you can enable bridging for all notifications, except for
    ++      notifications tagged as <code>foo</code> or <code>bar</code>, with the
    ++      following:
    ++    </p>
    ++
    ++<pre>
    ++BridgingManager.setConfig(context,
    ++  new BridgingConfig.Builder(context)
    ++    .setBridgingEnabled(true)
    ++    .addExcludedTag("foo")
    ++    .addExcludedTag("bar")
    ++    .build());
    ++</pre>
    ++
    ++    <h3 id="setting-a-bridge-tag">
    ++      Setting a bridge tag
    ++    </h3>
    ++
    ++    <p>
    ++      A bridge tag can be set on a notification by calling the
    ++      <code>setNotificationBridgeTag</code> method as follows:
    ++    </p>
    ++
    ++<pre>
    ++BridgingManager.setNotificationBridgeTag(&lt;NotificationCompat.Builder&gt;, &lt;String&gt;);
    ++</pre>
    ++
    ++    <p>
    ++      For example:
    ++    </p>
    ++
    ++<pre>
    ++NotificationCompat.Builder builder = new NotificationCompat.Builder(context)
    ++&lt;set other fields&gt;;
    ++BridgingManager.setNotificationBridgeTag(builder, &quot;foo&quot;);
    ++Notification notification =  builder.build();
    ++</pre>
    ++
    ++    <h2 id="existing-method-of-preventing-bridging">
    ++      Existing Method of Preventing Bridging
    ++    </h2>
    ++
    ++    <p>
    +       An existing way to prevent bridging is with the
    +       <code>Notification.Builder</code> class; specify <code>true</code> in the
    +       <a href=
    +-      "{@docRoot}reference/android/app/Notification.Builder.html#setLocalOnly(boolean)">
    ++      "http://developer.android.com/reference/android/app/Notification.Builder.html#setLocalOnly(boolean)">
    +       setLocalOnly</a> method.
    +     </p>
    + 
    +@@ -95,12 +261,6 @@ com.google.android.wearable.notificationBridgeMode
    +       the watch app may not be installed on all of them.
    +     </p>
    + 
    +-    <p>
    +-      Thus, if bridging should be prevented when the watch app
    +-      is installed, use the <a href=
    +-      "#preventing_bridging_with_the_bridging_mode_feature">Bridging mode
    +-      feature</a>.
    +-    </p>
    + 
    +     <h2 id="using_a_dismissal_id_to_sync_notification_dismissals">
    +       Using a Dismissal ID to Sync Notification Dismissals
    +@@ -110,7 +270,7 @@ com.google.android.wearable.notificationBridgeMode
    +       If you prevent bridging with the Bridging mode feature, dismissals
    +       (cancellations) of notifications are not synced across a user's devices.
    +       However, the following methods of the <a href=
    +-      "{@docRoot}reference/android/support/v4/app/NotificationCompat.WearableExtender.html">
    ++      "http://developer.android.com/reference/android/support/v4/app/NotificationCompat.WearableExtender.html">
    +       NotificationCompat.WearableExtender</a> class enable you to use dismissal
    +       IDs:
    +     </p>
    +@@ -118,7 +278,7 @@ com.google.android.wearable.notificationBridgeMode
    +     <pre>
    + public WearableExtender setDismissalId(String dismissalId)
    + public String getDismissalId()
    +-    </pre>
    ++</pre>
    +     <p>
    +       To enable a dismissal to be synced, use the <code>setDismissalId()</code>
    +       method. For each notification, pass a globally unique ID, as a string,
    +@@ -135,12 +295,12 @@ public String getDismissalId()
    + 
    +     <pre>
    + NotificationCompat.WearableExtender wearableExtender =
    +-new NotificationCompat.WearableExtender().setDismissalId(“abc123”);
    ++new NotificationCompat.WearableExtender().setDismissalId("abc123");
    + Notification notification = new NotificationCompat.Builder(context)
    + &lt;set other fields&gt;
    + .extend(wearableExtender)
    + .build();
    +-    </pre>
    ++</pre>
    +     <p>
    +       Dismissal IDs work if a watch is paired to an Android phone, but not if a
    +       watch is paired to an iPhone.
    +diff --git a/docs/html/wear/preview/features/complications.jd b/docs/html/wear/preview/features/complications.jd
    +index 3334cb7..c866118 100644
    +--- a/docs/html/wear/preview/features/complications.jd
    ++++ b/docs/html/wear/preview/features/complications.jd
    +@@ -13,6 +13,13 @@ page.image=/wear/preview/images/complications-main-image.png
    +             Complications to a Watch Face</a>
    +           </li>
    +           <li>
    ++            <a href="#permissions-for-complication-data">Permissions
    ++            for Complication Data</a>
    ++          </li>
    ++          <li>
    ++            <a href="#default-providers">Default Providers for Watch Faces</a>
    ++          </li>
    ++          <li>
    +             <a href="#exposing_data_to_complications">Exposing Data to
    +             Complications</a>
    +           </li>
    +@@ -27,12 +34,14 @@ page.image=/wear/preview/images/complications-main-image.png
    +             <a href="#api_additions">API Additions</a>
    +           </li>
    +       </ol>
    ++
    +     <h2>See Also</h2>
    +       <ol>
    +         <li><a class="external-link"
    +           href="https://github.com/googlesamples/android-WatchFace">Watch
    +           Face sample app with complications</a></li>
    +       </ol>
    ++
    +       </div>
    +     </div>
    + 
    +@@ -56,9 +65,12 @@ page.image=/wear/preview/images/complications-main-image.png
    +     </p>
    + 
    +     <p>
    +-      Along with reviewing this page, download the Android Wear 2.0 Preview
    +-      Reference (see the Complications API <a href=
    +-      "#api_additions">additions</a>) and review the Javadoc for complications.
    ++      You can review the Javadoc for complications by downloading
    ++      the Android Wear 2.0 Preview
    ++      Reference. Also see the <a href="#api_additions">API additions for
    ++      complications</a> and the
    ++      <a href="https://developer.android.com/wear/preview/behavior-changes.html">
    ++      behavior changes</a> for Wear 2.0.
    +     </p>
    + 
    +     <p>
    +@@ -117,8 +129,8 @@ page.image=/wear/preview/images/complications-main-image.png
    +       <code>WatchFaceService.Engine</code> class, with a list of watch face
    +       complication IDs. A watch face creates these IDs to uniquely identify
    +       slots on the watch face where complications can appear, and passes them
    +-      to the <code>createProviderChooserIntent</code> method (of the
    +-      <code>ProviderChooserIntent</code> class) to allow the user to decide
    ++      to the <code>createProviderChooserIntent</code> method
    ++      to allow the user to decide
    +       which complication should go in which slot.
    +     </p>
    + 
    +@@ -186,6 +198,406 @@ page.image=/wear/preview/images/complications-main-image.png
    +       where possible.
    +     </p>
    + 
    ++    <h2 id="permissions-for-complication-data">
    ++      Permissions for Complication Data
    ++    </h2>
    ++
    ++    <p>
    ++      A watch face must have the following <a href=
    ++      "https://developer.android.com/training/permissions/requesting.html">permission</a>
    ++      to receive complication data and open the provider chooser:
    ++    </p>
    ++
    ++<pre>
    ++com.google.android.wearable.permission.RECEIVE_COMPLICATION_DATA
    ++</pre>
    ++
    ++    <h3 id="opening-the-provider-chooser">
    ++      Opening the provider chooser
    ++    </h3>
    ++
    ++    <p>
    ++      A watch face that was not granted the above permission will be unable to
    ++      start the provider chooser.
    ++    </p>
    ++
    ++    <p>
    ++      To make it easier to request the permission and start the chooser, the
    ++      <code>ComplicationHelperActivity</code> class is available in the
    ++      wearable support library. This class should be used instead of
    ++      <code>ProviderChooserIntent</code> to start the chooser in almost all
    ++      cases.
    ++    </p>
    ++
    ++    <h4 id="requesting-the-necessary-permission">
    ++      Requesting the necessary permission
    ++    </h4>
    ++
    ++    <p>
    ++      To use <code>ComplicationHelperActivity</code>, add it to the watch face
    ++      in the <a href=
    ++      "https://developer.android.com/guide/topics/manifest/manifest-intro.html">
    ++      manifest file</a>:
    ++    </p>
    ++
    ++<pre>
    ++&lt;activity android:name=&quot;android.support.wearable.complications.ComplicationHelperActivity&quot;/&gt;
    ++</pre>
    ++
    ++    <p>
    ++      To start the provider chooser, call the
    ++      <code>ComplicationHelperActivity.createProviderChooserHelperIntent</code>
    ++      method, to obtain an intent.
    ++    </p>
    ++
    ++    <p>
    ++      The new intent can be used with either <code>startActivity</code> or
    ++      <code>startActivityForResult</code> to launch the chooser.
    ++    </p>
    ++
    ++    <p>
    ++      Here is an example of using the new intent with
    ++      <code>startActivityForResult</code>:
    ++    </p>
    ++
    ++    <pre>
    ++startActivityForResult(
    ++  ComplicationHelperActivity.createProviderChooserHelperIntent(
    ++     getActivity(),
    ++     watchFace,
    ++     complicationId,
    ++     ComplicationData.TYPE_LARGE_IMAGE),
    ++  PROVIDER_CHOOSER_REQUEST_CODE);
    ++</pre>
    ++    <p>
    ++      When the helper activity is started, the helper activity checks if the
    ++      permission was granted. If the permission was not granted, the helper
    ++      activity makes a runtime permission request. If the permission request is
    ++      accepted (or is unneeded), the provider chooser is shown.
    ++    </p>
    ++
    ++    <p>
    ++      If <code>startActivityForResult</code> was used with the intent, the
    ++      result delivered back to the calling Activity will have a result code of
    ++      <code>RESULT_OK</code> if a provider was successfully set, or a result
    ++      code of <code>RESULT_CANCELLED</code> if no provider was set.
    ++    </p>
    ++
    ++    <p>
    ++      In the case where a provider was set,
    ++      <code>ComplicationProviderInfo</code> for the chosen provider will be
    ++      included in the data intent of the result, as an extra with the key
    ++      <code>ProviderChooserIntent#EXTRA_PROVIDER_INFO</code>.
    ++    </p>
    ++
    ++    <h3 id="receiving-complication-data">
    ++      Receiving complication data
    ++    </h3>
    ++
    ++    <p>
    ++      In general, watch faces need the above permission in order to receive
    ++      complication data, but there are some exceptions. Specifically, a watch
    ++      face can only receive data from a provider if one of the following is
    ++      true:
    ++    </p>
    ++
    ++    <ul>
    ++      <li>The provider is a "safe" system provider,
    ++      </li>
    ++
    ++      <li>The provider and watch face are from the same app,
    ++      </li>
    ++
    ++      <li>The provider whitelists the watch face as a "safe" watch face, or
    ++      </li>
    ++
    ++      <li>The watch face has the permission
    ++      </li>
    ++    </ul>
    ++
    ++    <h4 id="lack-of-appropriate-permission">
    ++      Lack of appropriate permission
    ++    </h4>
    ++
    ++    <p>
    ++      If none of the above is true, then when <code>ComplicationData</code>
    ++      normally would be sent by a provider to a watch face, the system instead
    ++      sends data of the type <code>TYPE_NO_PERMISSION</code>. This type
    ++      includes an icon (an exclamation mark) and short text ("--") to allow it
    ++      to be rendered as if it were of the short text type or icon type, for
    ++      convenience.
    ++    </p>
    ++
    ++    <p>
    ++      When a watch face receives data of <code>TYPE_NO_PERMISSION</code>, the
    ++      watch face should render this appropriately, so the user can see that
    ++      action is needed for the complication to work. If possible, a tap on a
    ++      complication in this state should launch a permission request. This can
    ++      be done using
    ++      <code>ComplicationHelperActivity.createPermissionRequestHelperIntent</code>,
    ++      if the helper activity was added to the watch face app.
    ++    </p>
    ++
    ++    <p>
    ++      If a user accepts the permission request created by the helper activity,
    ++      updates are requested for all the active complications on the watch face
    ++      automatically, allowing the <code>TYPE_NO_PERMISSION</code> data to be
    ++      replaced by real data.
    ++    </p>
    ++
    ++    <h4 id="safe-providers">
    ++      Safe providers
    ++    </h4>
    ++
    ++    <p>
    ++      Some system providers are considered "safe", because they only supply
    ++      information that the watch face already could obtain itself.
    ++    </p>
    ++
    ++    <p>
    ++      These providers are listed in the new <code>SystemProviders</code> class
    ++      in the wearable support library. Whether a system provider is safe is
    ++      stated in the Javadoc (in the Android Wear 2.0 Preview Reference). Also
    ++      see <a href="#system-providers">System providers</a> for a list.
    ++    </p>
    ++
    ++    <h4 id="provider-specified-safe-watch-faces">
    ++      Provider-specified safe watch faces
    ++    </h4>
    ++
    ++    <p>
    ++      Providers can specify certain watch faces as "safe" to receive their
    ++      data. This is intended to be used only when the watch face will attempt
    ++      to use the provider as a default (see below),
    ++      and the provider trusts the watch face app.
    ++    </p>
    ++
    ++    <p>
    ++      To declare watch faces as safe, the provider adds metadata with a key of
    ++      <code>android.support.wearable.complications.SAFE_WATCH_FACES</code>. The
    ++      metadata value should be a comma-separated list (whitespace is ignored).
    ++      Entries in the list can be component names (of
    ++      <code>WatchFaceServices</code>, given as if
    ++      <code>ComponentName.flattenToString()</code> had been called), or they
    ++      can be package names (of apps, in which case every watch face within a
    ++      specified app is considered safe).
    ++    </p>
    ++
    ++    <p>
    ++      For example:
    ++    </p>
    ++
    ++<pre>
    ++&lt;meta-data
    ++       android:name=&quot;android.support.wearable.complications.SAFE_WATCH_FACES&quot;
    ++        android:value=&quot;
    ++          com.app.watchface/com.app.watchface.MyWatchFaceService,
    ++          com.anotherapp.anotherwatchface/com.something.WatchFaceService,
    ++          com.something.text
    ++        &quot;/&gt;
    ++</pre>
    ++
    ++  <h2 id="default-providers">
    ++      Default Providers for Watch Faces
    ++  </h2>
    ++
    ++    <p>
    ++      Watch faces can specify default providers that are used until a user
    ++      selects a provider.
    ++    </p>
    ++
    ++    <h3 id="setting-default-providers">
    ++      Setting default providers
    ++    </h3>
    ++
    ++    <p>
    ++      Set default providers using the
    ++      <code>setDefaultComplicationProvider</code> method in
    ++      <code>WatchFaceService.Engine</code>. This method may be called at any
    ++      time, but it does nothing if the user already chose a provider for the
    ++      given complication.
    ++    </p>
    ++
    ++    <h3 id="safe-providers2">
    ++      Safe providers
    ++    </h3>
    ++
    ++    <p>
    ++      For most providers, the <code>RECEIVE_COMPLICATION_DATA</code> permission
    ++      must be granted to a watch face before data can flow to it. However, some
    ++      system providers are considered "safe", and do not require the watch face
    ++      to have the permission for data to be sent (see <a href=
    ++      "#safe-providers">Safe Providers</a> and <a href=
    ++      "#system-providers">System providers</a>). These providers may be
    ++      preferable to use as defaults, as they can supply data immediately.
    ++    </p>
    ++
    ++    <p>
    ++      Alternatively, if a watch face has a partnership with a certain provider
    ++      and wishes to use it as a default, it can request that the provider list
    ++      it as a safe watch face (see <a href=
    ++      "#provider-specified-safe-watch-faces">Provider-specified safe watch
    ++      faces</a>).
    ++    </p>
    ++
    ++    <h3 id="system-providers">
    ++      System providers
    ++    </h3>
    ++
    ++    <p>
    ++      The system includes providers that can be used as defaults. These are
    ++      listed in the <code>SystemProviders</code> class in the wearable support
    ++      library.
    ++    </p>
    ++
    ++    <p>
    ++      The following table has details about providers that are considered safe:
    ++    </p>
    ++
    ++    <table>
    ++      <tr>
    ++        <th>
    ++          Method name in the SystemProviders class
    ++        </th>
    ++        <th>
    ++          Safety
    ++        </th>
    ++        <th>
    ++          Can be the default
    ++        </th>
    ++        <th>
    ++          Notes
    ++        </th>
    ++      </tr>
    ++
    ++      <tr>
    ++        <td>
    ++          <code>dateProvider()</code>
    ++        </td>
    ++        <td>
    ++          Yes
    ++        </td>
    ++        <td>
    ++          Yes
    ++        </td>
    ++        <td>
    ++          The standard system date provider. Tapping opens the standard Agenda
    ++          app.
    ++        </td>
    ++      </tr>
    ++
    ++      <tr>
    ++        <td>
    ++          <code>currentTimeProvider()</code>
    ++        </td>
    ++        <td>
    ++          Yes
    ++        </td>
    ++        <td>
    ++          Yes
    ++        </td>
    ++        <td>
    ++          The standard system "time and date" provider. No tap action.
    ++        </td>
    ++      </tr>
    ++
    ++      <tr>
    ++        <td>
    ++          <code>batteryProvider()</code>
    ++        </td>
    ++        <td>
    ++          Yes
    ++        </td>
    ++        <td>
    ++          Yes
    ++        </td>
    ++        <td>
    ++          The standard system battery provider. No tap action.
    ++        </td>
    ++      </tr>
    ++
    ++      <tr>
    ++        <td>
    ++          <code>stepCountProvider()</code>
    ++        </td>
    ++        <td>
    ++          Yes
    ++        </td>
    ++        <td>
    ++          Yes
    ++        </td>
    ++        <td>
    ++          Shows a daily total of steps, as reported by
    ++          <code>readDailyTotal</code>.
    ++        </td>
    ++      </tr>
    ++
    ++      <tr>
    ++        <td>
    ++          <code>unreadCountProvider()</code>
    ++        </td>
    ++        <td>
    ++          Yes
    ++        </td>
    ++        <td>
    ++          Yes
    ++        </td>
    ++        <td>
    ++          Shows the number of unread notifications in the stream.
    ++        </td>
    ++      </tr>
    ++
    ++      <tr>
    ++        <td>
    ++          <code>worldClockProvider()</code>
    ++        </td>
    ++        <td>
    ++          Yes
    ++        </td>
    ++        <td>
    ++          Yes
    ++        </td>
    ++        <td>
    ++          Will default to London or New York. Can be tapped to change the time
    ++          zone.
    ++        </td>
    ++      </tr>
    ++
    ++      <tr>
    ++        <td>
    ++          <code>appsProvider()</code>
    ++        </td>
    ++        <td>
    ++          Yes
    ++        </td>
    ++        <td>
    ++          Yes
    ++        </td>
    ++        <td>
    ++          Will show an "apps" icon at first, which can be tapped to choose an
    ++          app.
    ++        </td>
    ++      </tr>
    ++
    ++      <tr>
    ++        <td>
    ++          <code>nextEventProvider()</code>
    ++        </td>
    ++        <td>
    ++          No
    ++        </td>
    ++        <td>
    ++          Yes (but not a safe provider)
    ++        </td>
    ++        <td>
    ++          The standard system "next event" provider. Tapping opens
    ++            the standard Agenda app.
    ++          </p>
    ++        </td>
    ++      </tr>
    ++    </table>
    ++
    ++
    +     <h2 id="exposing_data_to_complications">
    +       Exposing Data to Complications
    +     </h2>
    +@@ -203,6 +615,11 @@ page.image=/wear/preview/images/complications-main-image.png
    +       be used to send data back to the system.
    +     </p>
    + 
    ++    <p class="note"><strong>Note:</strong> When you provide data as a
    ++    complication data provider, the watch face receives the raw values
    ++    you send so it can draw them on the watch face.
    ++    </p>
    ++
    +     <p>
    +       In your app's manifest, declare the service and add an intent filter for
    +       the following:
    +@@ -210,7 +627,8 @@ page.image=/wear/preview/images/complications-main-image.png
    + 
    +     <pre>
    + android.support.wearable.complications.ACTION_COMPLICATION_UPDATE_REQUEST
    +-</pre>
    ++    </pre>
    ++
    +     <p>
    +       The service's manifest entry should also include an
    +       <code>android:icon</code> attribute. The provided icon should be a
    +@@ -227,6 +645,21 @@ android.support.wearable.complications.ACTION_COMPLICATION_UPDATE_REQUEST
    +       <a href="#api_additions">API Additions</a>).
    +     </p>
    + 
    ++    <p>
    ++      Additionally, a permission for provider services ensures that only the Android Wear system
    ++      can bind to provider services. Only the Android Wear system can have this
    ++      permission.
    ++    </p>
    ++
    ++    <p>
    ++      Provider services should add the following to their service declarations
    ++      in the manifest:
    ++    </p>
    ++
    ++<pre>
    ++android:permission="com.google.android.wearable.permission.BIND_COMPLICATION_PROVIDER"
    ++</pre>
    ++
    +     <h3 id="update_period">
    +       Update period
    +     </h3>
    +@@ -371,6 +804,11 @@ METADATA_KEY_PROVIDER_CONFIG_ACTION
    +     <p>
    +       The following table describes the types and fields of the
    +       <code>ComplicationData</code> object.
    ++      If a watch face requests a field that is invalid for a complication type,
    ++      a default value for the field is returned.
    ++      For example, if a watch face tries to access a <code>Long text</code>
    ++      field in a <code>SHORT_TEXT</code> type, the default value for the
    ++      <code>Long text</code> field is returned.
    +     </p>
    + 
    +     <table>
    +@@ -489,56 +927,80 @@ METADATA_KEY_PROVIDER_CONFIG_ACTION
    +     </table>
    + 
    +     <p>
    +-      In addition, the following two types have no fields. These two types may
    +-      be sent for any complication slot and do not need to be included in a
    +-      list of supported types:
    ++      In addition, the types in the table below are for empty data and
    ++      may be sent for any complication slot. These types have no fields
    ++      and do not need to be included in a
    ++      list of supported types. These types enable watch
    ++      faces to differentiate among the following three cases:
    ++    </p>
    ++
    ++    <ul>
    ++      <li>No provider was chosen
    ++      </li>
    ++
    ++      <li>The user has selected "empty" for a slot
    ++      </li>
    ++
    ++      <li>A provider has no data to send
    ++      </li>
    ++    </ul>
    ++
    ++    <p>
    ++      Providers should not send <code>TYPE_EMPTY</code> in response to
    ++      update requests. Providers should send <code>TYPE_NO_DATA</code> instead.
    ++    </p>
    ++
    ++    <p>
    ++      Details on the complication types for "empty" data are in the
    ++      following table:
    +     </p>
    + 
    +     <table>
    +       <tr>
    +-        <th style="width:175px">
    +-          Type
    +-        </th>
    +-        <th style="width:175px">
    +-          Required fields
    ++        <th>Complication type
    +         </th>
    +-        <th style="width:175px">
    +-          Optional fields
    +-        </th>
    +-        <th>
    +-          Notes
    ++        <th>Description
    +         </th>
    +       </tr>
    + 
    +       <tr>
    +         <td>
    +-          NOT_CONFIGURED
    +-        </td>
    +-        <td>
    +-          None
    +-        </td>
    +-        <td>
    +-          None
    ++          <code>TYPE_NOT_CONFIGURED</code>
    +         </td>
    +         <td>
    +-          Sent when a provider has not yet been chosen for a complication.
    ++          Sent by the system when a complication is activated but the user has
    ++          not selected a provider, and no default was set.
    ++          <p>
    ++            Cannot be sent by providers.
    ++          </p>
    +         </td>
    +       </tr>
    + 
    +       <tr>
    +         <td>
    +-          EMPTY
    ++          <code>TYPE_EMPTY</code>
    +         </td>
    +         <td>
    +-          None
    ++          Sent by the system when a complication is activated and the user has
    ++          chosen "empty" instead of a provider, or when the watch face has
    ++          chosen no provider, and this type, as the default.
    ++          <p>
    ++            Cannot be sent by providers.
    ++          </p>
    +         </td>
    ++      </tr>
    ++
    ++      <tr>
    +         <td>
    +-          None
    ++          <code>TYPE_NO_DATA</code>
    +         </td>
    +         <td>
    +-          Sent by a provider when there is no data to display in a
    +-          complication, or sent by the system when nothing should be shown in a
    +-          complication.
    ++          Sent by the system when a complication (that has a provider) is
    ++          activated, to clear the complication before actual data is received
    ++          from the provider.
    ++          <p>
    ++            Should be sent by providers if they have no actual data to send.
    ++          </p>
    +         </td>
    +       </tr>
    +     </table>
    +@@ -700,8 +1162,8 @@ METADATA_KEY_PROVIDER_CONFIG_ACTION
    +     </h2>
    + 
    +     <p>
    +-      The Complications API includes new classes in the Wearable Support
    +-      Library. For more information, download the <a href=
    ++      The Complications API includes new classes in the wearable support
    ++      library. For more information, download the <a href=
    +       "{@docRoot}wear/preview/start.html#get_the_preview_reference_documentation">
    +       Android Wear 2.0 Preview Reference</a>.
    +     </p>
    +@@ -722,14 +1184,26 @@ METADATA_KEY_PROVIDER_CONFIG_ACTION
    +       </li>
    + 
    +       <li>
    +-        <code>ComplicationText</code>
    ++        <code>ComplicationHelperActivity</code>
    +         <ul>
    +-          <li>Used to supply text-based values in a
    +-          <code>ComplicationData</code> object
    ++          <li>Used to request the following permission: <br>
    ++<code>com.google.android.wearable.permission.RECEIVE_COMPLICATION_DATA</code>
    +           </li>
    + 
    +-          <li>Includes options for time-dependent values, whose text value
    +-          depends on the current time
    ++          <li>Used instead of <code>ProviderChooserIntent</code>
    ++          to start the chooser in almost all cases
    ++          </li>
    ++        </ul>
    ++      </li>
    ++
    ++      <li>
    ++        <code>ComplicationManager</code>
    ++        <ul>
    ++          <li>A wrapper for the complication manager service, for use by
    ++          providers
    ++          </li>
    ++
    ++          <li>Allows providers to send complication data to the system
    +           </li>
    +         </ul>
    +       </li>
    +@@ -747,13 +1221,14 @@ METADATA_KEY_PROVIDER_CONFIG_ACTION
    +       </li>
    + 
    +       <li>
    +-        <code>ComplicationManager</code>
    ++        <code>ComplicationText</code>
    +         <ul>
    +-          <li>A wrapper for the complication manager service, for use by
    +-          providers
    ++          <li>Used to supply text-based values in a
    ++          <code>ComplicationData</code> object
    +           </li>
    + 
    +-          <li>Allows providers to send complication data to the system
    ++          <li>Includes options for time-dependent values, whose text value
    ++          depends on the current time
    +           </li>
    +         </ul>
    +       </li>
    +@@ -761,11 +1236,8 @@ METADATA_KEY_PROVIDER_CONFIG_ACTION
    +       <li>
    +         <code>ProviderChooserIntent</code>
    +         <ul>
    +-          <li>Non-instantiable utility class
    +-          </li>
    +-
    +-          <li>Includes a method that a watch face can call for starting a
    +-          provider chooser (to allow a user to configure complications)
    ++          <li>Non-instantiable utility class that is not commonly used; use
    ++          <code>ComplicationHelperActivity</code> instead
    +           </li>
    +         </ul>
    +       </li>
    +@@ -789,6 +1261,16 @@ METADATA_KEY_PROVIDER_CONFIG_ACTION
    +           </li>
    +         </ul>
    +       </li>
    ++
    ++      <li>
    ++        <code>SystemProviders</code>
    ++        <ul>
    ++          <li>Lists system providers that are considered "safe",
    ++          because they only supply information that the watch face
    ++          already could obtain itself
    ++          </li>
    ++        </ul>
    ++      </li>
    +     </ul>
    + 
    +     <p>
    +diff --git a/docs/html/wear/preview/features/notifications.jd b/docs/html/wear/preview/features/notifications.jd
    +index dcc0970..b546978 100644
    +--- a/docs/html/wear/preview/features/notifications.jd
    ++++ b/docs/html/wear/preview/features/notifications.jd
    +@@ -1,6 +1,5 @@
    + page.title=Notification Changes in Android Wear 2.0
    +-meta.tags="wear", "wear-preview", "notifications"
    +-page.tags="wear"
    ++meta.tags="wear", "wear-preview", "notifications" page.tags="wear"
    + page.image=/wear/preview/images/expanded_diagram.png
    + 
    + 
    +@@ -12,6 +11,7 @@ page.image=/wear/preview/images/expanded_diagram.png
    +     <h2>This document includes</h2>
    +     <ol>
    +       <li><a href="#visual">Visual Updates</a></li>
    ++      <li><a href="#inline">Inline Action</a></li>
    +       <li><a href="#expanded">Expanded Notifications</a></li>
    +       <li><a href="#messaging">MessagingStyle</a></li>
    +     </ol>
    +@@ -67,7 +67,8 @@ material design</a> visual changes.
    +   We recommended that you don't set color for bridged notifications.
    + 
    +   When Wear apps post local notifications, you can work around this by checking
    +-  <a href="{@docRoot}training/basics/supporting-devices/platforms.html#version-codes">the API level of the device</a> they're running on and using an appropriate color
    ++  <a href="{@docRoot}training/basics/supporting-devices/platforms.html#version-codes">the API level of the device</a>
    ++   they're running on and using an appropriate color
    +   for Wear 1.x and a different color for Wear 2.0.
    + </li>
    + 
    +@@ -77,6 +78,85 @@ material design</a> visual changes.
    +   you must update the text of your notification.
    + </li>
    + </ul>
    ++
    ++<h2 id="inline">Inline Action</h3>
    ++
    ++<img src="{@docRoot}wear/preview/images/inline_action.png" style="float:right;margin:10px 20px 0 0">
    ++<p>
    ++  Wear 2.0 now supports inline action, which allows users to take actions on a
    ++  notification from within the notification stream card.  On Wear, the inline
    ++  action appears as an additional button displayed at the bottom of the notification.
    ++</p>
    ++<p>
    ++  Inline actions are optional but recommended for cases in which users are likely
    ++  to take an action on a notification after viewing the contents in the
    ++  notification stream card (without going to the
    ++  <a href= "{@docRoot}wear/preview/features/notifications.html#expanded">expanded notification</a>).
    ++  Examples of good use cases for inline action on a notification include: replying to a
    ++  text message, stopping a fitness activity, and archiving an email message.
    ++</p>
    ++
    ++<p>
    ++  A notification can provide only one inline action.
    ++  To display the inline action as an additional button in the notification, set
    ++  the <a href="https://developer.android.com/reference/android/support/v4/app/NotificationCompat.Action.WearableExtender.html#setHintDisplayActionInline(boolean)">{@code setHintDisplayActionInline()}</a>
    ++  method to true. When a user taps the inline action, the system invokes
    ++  the intent that you specified in the notification action.
    ++</p>
    ++
    ++<h3>Adding an inline action</h3>
    ++<p>
    ++  The following code example shows how to create a notification with an inline
    ++  reply action:
    ++</p>
    ++
    ++<ol>
    ++  <li>Create an instance of
    ++    <a href="https://developer.android.com/reference/android/support/v4/app/RemoteInput.Builder.html">{@code RemoteInput.Builder}</a></code>
    ++    that you can add to your notification action. This class's constructor accepts a
    ++    string that the system uses as the key for the text input. Later, your app
    ++    uses that key to retrieve the text of the input.
    ++
    ++<pre>
    ++String[] choices = context.getResources().getStringArray(R.array.notification_reply_choices);
    ++    choices = WearUtil.addEmojisToCannedResponse(choices);
    ++  RemoteInput remoteInput = new RemoteInput.Builder(Intent.EXTRA_TEXT)
    ++        .setLabel(context.getString(R.string.notification_prompt_reply))
    ++        .setChoices(choices)
    ++        .build();
    ++</pre>
    ++
    ++  </li>
    ++
    ++  <li>
    ++    Use the <a href="https://developer.android.com/reference/android/support/v4/app/NotificationCompat.Action.Builder.html#addRemoteInput(android.support.v4.app.RemoteInput)">{@code addRemoteInput()}</a>
    ++    method to attach the <ahref="https://developer.android.com/reference/android/support/v4/app/RemoteInput.html">{@code RemoteInput}</a>
    ++    object to an action.
    ++
    ++<pre>
    ++NotificationCompat.Action.Builder actionBuilder = new NotificationCompat.Action.Builder(
    ++        R.drawable.ic_full_reply, R.string.notification_reply, replyPendingIntent);
    ++    actionBuilder.addRemoteInput(remoteInput);
    ++    actionBuilder.setAllowGeneratedReplies(true);
    ++</pre>
    ++  </li>
    ++
    ++  <li>
    ++    Add a hint to display the reply action inline, and use the
    ++    <a href="https://developer.android.com/reference/android/support/v4/app/NotificationCompat.WearableExtender.html#addAction(android.support.v4.app.NotificationCompat.Action)">{@code addAction}</a>
    ++    method to add this action to the notification.
    ++
    ++<pre>
    ++// Android Wear 2.0 requires a hint to display the reply action inline.
    ++    Action.WearableExtender actionExtender =
    ++        new Action.WearableExtender()
    ++            .setHintLaunchesActivity(true)
    ++            .setHintDisplayActionInline(true);
    ++    wearableExtender.addAction(actionBuilder.extend(actionExtender).build());
    ++</pre>
    ++  </li>
    ++</ol>
    ++
    + <h2 id="expanded">Expanded Notifications</h2>
    + <p>Android Wear 2.0 introduces <i>expanded notifications</i>, which provide
    +   substantial additional content and actions for each notification.
    +@@ -152,51 +232,52 @@ action in the notification unless a different action is specified using
    + </p>
    + <h2 id="messaging">MessagingStyle</h2>
    + 
    +-<p>If you have a chat messaging app, your notifications should use
    +-<a href="{@docRoot}preview/features/notification-updates.html#style">{@code Notification.MessagingStyle}</a>,
    +- which is new in Android N. Wear 2.0 uses the chat messages included
    +-  in a <a href="{@docRoot}preview/features/notification-updates.html#style">{@code MessagingStyle}</a> notification
    +-
    +-  (see <a href="{@docRoot}preview/features/notification-updates.html#style">{@code addMessage()}</a>) to provide
    +-  a rich chat app-like experience in the expanded notification.
    ++<p>
    ++  If you have a chat messaging app, your notifications should use
    ++  <a href="https://developer.android.com/reference/android/support/v4/app/NotificationCompat.MessagingStyle.html">{@code NotificationCompat.MessagingStyle}</a>,
    ++  which is new in Android 7.0. Wear 2.0 uses the chat messages included in a
    ++  {@code MessagingStyle} notification
    ++  (see <a href="https://developer.android.com/reference/android/support/v4/app/NotificationCompat.MessagingStyle.html#addMessage(android.support.v4.app.NotificationCompat.MessagingStyle.Message)">{@code addMessage()}</a>)
    ++  to provide a rich chat app-like experience in the expanded notification.
    + </p>
    + 
    +-<p class="note">Note: <a href="{@docRoot}preview/features/notification-updates.html#style">{@code MessagingStyle}</a>
    ++<p class="note">Note: <a href="https://developer.android.com/reference/android/support/v4/app/NotificationCompat.MessagingStyle.html">{@code MessagingStyle}</a>
    + expanded notifications require that you have at least version 1.5.0.2861804 of the
    +   <a href="https://play.google.com/store/apps/details?id=com.google.android.wearable.app">Android Wear app</a>
    +-  on your paired Android phone. That version will be available within the next
    +-  few weeks in the Play Store.
    ++  on your paired Android phone.
    + </p>
    + 
    + <h3 id="smart-reply">Smart Reply</h3>
    + <img src="{@docRoot}wear/preview/images/messaging_style.png" height="420"
    +   style="float:right;margin:10px 20px 0 0" />
    +-<p>Wear 2.0 also introduces <i>Smart Reply</i>
    +-for <a href="{@docRoot}preview/features/notification-updates.html#style">{@code MessagingStyle}</a> notifications.
    ++<p>Wear 2.0 also introduces <i>Smart Reply</i> for
    ++  <a href="https://developer.android.com/reference/android/support/v4/app/NotificationCompat.MessagingStyle.html">{@code MessagingStyle}</a> notifications.
    +   Smart Reply provides the user with contextually relevant, touchable choices in
    +   the expanded notification and in {@code RemoteInput}. These augment the fixed
    +   list of choices that the developer provides in
    +-   <a href="http://developer.android.com/reference/android/support/v4/app/RemoteInput.html">{@code RemoteInput}</a>
    +-    using the
    +-    <a href="{@docRoot}reference/android/support/v4/app/RemoteInput.Builder.html#setChoices(java.lang.CharSequence[])">{@code setChoices()}</a> method.
    ++  <a href="http://developer.android.com/reference/android/support/v4/app/RemoteInput.html">{@code RemoteInput}</a>
    ++  using the
    ++  <a href="{@docRoot}reference/android/support/v4/app/RemoteInput.Builder.html#setChoices(java.lang.CharSequence[])">{@code setChoices()}</a> method.
    + </p>
    +-<p>By enabling Smart Reply for your MessagingStyle notifications,
    +-  you provide users with a fast (single tap), discreet (no speaking aloud), and
    +-  reliable way to respond to chat messages.
    ++<p> Smart Reply provides users with a fast (single tap), discreet (no speaking aloud),
    ++  private (messages received by a user never leave the watch), and reliable (no
    ++  internet connection needed) way to respond to chat messages.
    + </p>
    + 
    +-<p>Responses generated by Smart Reply are shown in addition to those set using the
    +-  <a href="{@docRoot}reference/android/support/v4/app/RemoteInput.Builder.html#setChoices(java.lang.CharSequence[])">{@code setChoices()}</a> method.
    ++<p>
    ++  Smart Reply responses are generated by an entirely on-watch machine learning
    ++  model using the context provided by the MessagingStyle notification. No user
    ++  notification data is sent to Google servers to generate Smart Reply responses.
    + </p>
    ++
    + <p>To enable Smart Reply for your notification action, you need to do the
    + following:
    + </p>
    + <ol>
    +-  <li>Use <a href="{@docRoot}preview/features/notification-updates.html#style">{@code Notification.MessagingStyle}</a>.
    ++  <li>Use <a href="https://developer.android.com/reference/android/support/v4/app/NotificationCompat.MessagingStyle.html">{@code NotificationCompat.MessagingStyle}</a>.
    +   </li>
    +-  <li>Call the method {@code setAllowGeneratedReplies()} for the notification action.
    +-  For more information, see the downloadable
    +-  <a href="{@docRoot}preview/setup-sdk.html#docs-dl">API reference</a>.
    ++  <li>Call the method <a href="https://developer.android.com/reference/android/support/v4/app/NotificationCompat.Action.Builder.html#setAllowGeneratedReplies(boolean)">{@code setAllowGeneratedReplies(true)}</a>
    ++   for the notification action.
    +   </li>
    +   <li>Ensure that the notification action has a
    +     <a href="{@docRoot}reference/android/app/RemoteInput.html">{@code RemoteInput}</a>
    +@@ -236,3 +317,29 @@ Notification noti = new NotificationCompat.Builder()
    + // 3) add an action with RemoteInput
    + .extend(new WearableExtender().addAction(action)).build();
    + </pre>
    ++
    ++<h3 id="images">Adding images to a MessagingStyle notification</h3>
    ++<p>
    ++  You can add images to a notification message  by setting the appropriate MIME
    ++  type and placing the URI to the image in {@code NotificationCompat.MessagingStyle.Message.}
    ++  <a href="https://developer.android.com/reference/android/support/v4/app/NotificationCompat.MessagingStyle.Message.html#setData(java.lang.String, android.net.Uri)">{@code setData()}</a> method.
    ++</p>
    ++<p>
    ++  Here is the code snippet to set data of type image in a notification:
    ++</p>
    ++<pre>
    ++NotificationCompat.MessagingStyle.Message message = new Message("sticker", 1, "Jeff")
    ++                      .setData("image/png", stickerUri);
    ++
    ++  NotificationCompat notification = new NotificationCompat.Builder()
    ++             .setStyle(new NotificationComapt.MessagingStyle("Me")
    ++             .addMessage(message)
    ++             .build());
    ++
    ++</pre>
    ++<p>
    ++  In the above code snippet the variable <code>stickerUri </code>is a Uri that
    ++  points to a publicly-accessible location, as described <a
    ++  href="https://developer.android.com/reference/android/support/v4/app/NotificationCompat.MessagingStyle.Message.html">here
    ++  </a>.
    ++</p>
    +\ No newline at end of file
    +diff --git a/docs/html/wear/preview/features/standalone-apps.jd b/docs/html/wear/preview/features/standalone-apps.jd
    +new file mode 100644
    +index 0000000..5c1930d
    +--- /dev/null
    ++++ b/docs/html/wear/preview/features/standalone-apps.jd
    +@@ -0,0 +1,499 @@
    ++page.title=Standalone Apps
    ++meta.keywords="wear-preview"
    ++page.tags="wear-preview"
    ++page.image=images/cards/card-n-sdk_2x.png
    ++
    ++@jd:body
    ++
    ++<div id="qv-wrapper">
    ++<div id="qv">
    ++
    ++<h2>In this document</h2>
    ++
    ++  <ul>
    ++    <li><a href="#planning_apps">Planning Your Phone and Watch Apps</a></li>
    ++    <li><a href="#network_access">Network Access and Cloud Messaging</a></li>
    ++    <li><a href="#background_services">Using Background Services</a></li>
    ++    <li><a href="#fcm">Cloud Notifications Using FCM</a></li>
    ++    <li><a href="#fcm-phone">Notifications from a Companion Phone</a></li>
    ++  </ul>
    ++
    ++</div>
    ++</div>
    ++
    ++    <p>
    ++      In Android Wear 2.0, apps can work independently of a phone. Users can
    ++      complete more tasks on a watch, without access to an Android or iOS
    ++      phone.
    ++    </p>
    ++
    ++    <h2 id="planning_apps">
    ++      Planning Your Phone and Watch Apps
    ++    </h2>
    ++
    ++    <p>
    ++      A watch APK targeting Wear 2.0 should not be embedded in a phone APK.
    ++      For more information, see
    ++      <a href="{@docRoot}wear/preview/features/app-distribution.html">
    ++      App Distribution</a>.
    ++    </p>
    ++
    ++    <p>
    ++      Generally, the minimum and target API level for a standalone app, and
    ++      for Wear 2.0, is level 24. The minimum SDK level can be 23
    ++      only if you are using the same APK
    ++      for Wear 1.0 and 2.0 (and thus have an embedded Wear 1.0 APK).
    ++    </p>
    ++
    ++    <p>
    ++      If you build a standalone Wear 2.0 APK and will continue to have a
    ++      Wear 1.0 APK, please do both of the following:
    ++    </p>
    ++
    ++    <ul>
    ++      <li>Provide a standalone version of the Wear APK, and
    ++      </li>
    ++
    ++      <li>Continue embedding a version of the Wear APK in your phone APK
    ++      </li>
    ++    </ul>
    ++
    ++    <p>
    ++      <strong>Caution</strong>: For the Wear 2.0 Developer Preview, if you
    ++      publish an update to your production phone APK that has removed an embedded
    ++      Wear APK, production users who update the phone APK before installing
    ++      your standalone Wear APK will lose their existing Wear app and its data.
    ++      Therefore, it's important that you continue to embed
    ++      your watch APK into your phone APK.
    ++    </p>
    ++
    ++    <p>
    ++      <a href=
    ++      "https://developer.android.com/training/articles/wear-permissions.html">
    ++      Run-time permissions</a> are required for standalone apps.
    ++    </p>
    ++
    ++    <h3>
    ++      Shared code and data storage
    ++    </h3>
    ++
    ++    <p>
    ++      Code can be shared between a Wear app and a phone app. Optionally, code
    ++      that is specific to a form factor can be in a separate module.
    ++    </p>
    ++
    ++    <p>
    ++      For example, common code for networking can be in a shared library.
    ++    </p>
    ++
    ++    <p>
    ++      You can use standard Android storage APIs to store data locally.
    ++      For example, you can use
    ++      the <a href=
    ++      "https://developer.android.com/reference/android/content/SharedPreferences.html">
    ++      SharedPreferences APIs</a>, SQLite, or internal storage (as you would in
    ++      the case of a phone).
    ++    </p>
    ++
    ++    <h3>
    ++      Detecting your phone app or watch app
    ++    </h3>
    ++
    ++    <p>
    ++      If a user of your watch app needs your phone app, your watch app can
    ++      detect if the phone app is available. Using the <a href=
    ++      "https://developers.google.com/android/reference/com/google/android/gms/wearable/CapabilityApi">
    ++      CapabilityApi</a>, your phone app or watch app can advertise its presence
    ++      to a paired device. It can do so statically and dynamically. When an app
    ++      is on a node in a user's Wear network (i.e., on a phone, paired watch, or
    ++      in the cloud), the <code>CapabilityApi</code> enables another
    ++      app to detect if it is installed. For more information, see <a href=
    ++      "https://developer.android.com/training/wearables/data-layer/messages.html#AdvertiseCapabilities">
    ++      Advertise capabilities</a>.
    ++    </p>
    ++
    ++    <p>
    ++      If your phone app is unavailable, your can check if the Play Store is
    ++      available on the phone, as described below, before directing the user to
    ++      go to the Play Store (to install your phone app).
    ++    </p>
    ++
    ++    <h4>
    ++      Checking for Play Store availability on a phone
    ++    </h4>
    ++
    ++    <p>
    ++      iPhones and some Android phones lack the Play Store. A standalone Wear
    ++      app can check if the paired phone has the Play Store, before directing a
    ++      user to go there to install your phone app. The
    ++      <code>PlayStoreAvailability</code> class contains a
    ++      <code>getPlayStoreAvailabilityOnPhone()</code> method that enables your
    ++      Wear app to check if a companion phone has the Play Store.
    ++    </p>
    ++
    ++    <p>
    ++      More information about the <code>PlayStoreAvailability</code> class is
    ++      available when you <a href=
    ++      "https://developer.android.com/wear/preview/start.html#get_the_preview_reference_documentation">
    ++      download the Android Wear 2.0 Preview Reference</a>. Here is a snippet
    ++      that uses the <code>getPlayStoreAvailabilityOnPhone()</code> method to
    ++      determine if the paired phone has the Play Store:
    ++    </p>
    ++
    ++<pre>
    ++int playStoreAvailabilityOnPhone =
    ++PlayStoreAvailability.getPlayStoreAvailabilityOnPhone(context);
    ++</pre>
    ++
    ++    <p>
    ++      The value returned by the <code>getPlayStoreAvailabilityOnPhone()</code>
    ++      method is one of the following:
    ++    </p>
    ++
    ++    <table>
    ++      <tr>
    ++        <th>
    ++          <strong>Return value</strong>
    ++        </th>
    ++        <th>
    ++          <strong>Description</strong>
    ++        </th>
    ++      </tr>
    ++
    ++      <tr>
    ++        <td>
    ++          <code>PLAY_STORE_ON_PHONE_AVAILABLE</code>
    ++        </td>
    ++        <td>
    ++          The Play Store is available on the companion phone.
    ++        </td>
    ++      </tr>
    ++
    ++      <tr>
    ++        <td>
    ++          <code>PLAY_STORE_ON_PHONE_UNAVAILABLE</code>
    ++        </td>
    ++        <td>
    ++          The Play Store is not available on the companion phone.
    ++        </td>
    ++      </tr>
    ++
    ++      <tr>
    ++        <td>
    ++          <code>PLAY_STORE_ON_PHONE_ERROR_UNKNOWN</code>
    ++        </td>
    ++        <td>
    ++          An error occurred in the check for the Play Store; another check
    ++          should be made later.
    ++        </td>
    ++      </tr>
    ++    </table>
    ++
    ++    <h2 id="network_access">
    ++      Network Access and Cloud Messaging
    ++    </h2>
    ++
    ++    <p>
    ++      Android Wear apps can make their own network requests. When a watch has a
    ++      Bluetooth connection to a phone, the watch's network traffic is proxied
    ++      through the phone. When a phone is unavailable, Wi-Fi and cellular
    ++      networks are used, depending on the hardware. The Wear platform handles
    ++      transitions between networks. A watch's network access thus does not
    ++      require the <a href=
    ++      "https://developer.android.com/training/wearables/data-layer/index.html">
    ++      Wearable Data Layer API</a>.
    ++    </p>
    ++
    ++    <p>
    ++      For sending notifications, apps can directly use Firebase Cloud Messaging
    ++      (FCM), which replaces Google Cloud Messaging, or continue to use GCM.
    ++    </p>
    ++
    ++    <p>
    ++      No APIs for network access or FCM are specific to Android Wear.
    ++      Refer to the existing documentation about <a href=
    ++      "https://developer.android.com/training/basics/network-ops/connecting.html">
    ++      connecting to a network</a> and <a href=
    ++      "https://developers.google.com/cloud-messaging/">cloud messaging</a>.
    ++    </p>
    ++
    ++    <p>
    ++      You can use protocols such as HTTP, TCP, and UDP. However,
    ++      the <a href="https://developer.android.com/reference/android/webkit/package-summary.html">
    ++      android.webkit</a> APIs are not available. Therefore,
    ++      use of cookies is available by reading and writing headers on
    ++      requests and responses, but the <a href=
    ++      "https://developer.androidcom/reference/android/webkit/CookieManager.html">
    ++      CookieManager</a> class is not available.
    ++    </p>
    ++
    ++    <p>
    ++      FCM works well with
    ++      <a href="https://developer.android.com/training/monitoring-device-state/doze-standby.html">
    ++      Doze</a>.
    ++    </p>
    ++
    ++    <p>
    ++      Additionally, we recommend using the following:
    ++    </p>
    ++
    ++    <ul>
    ++      <li>The <a href=
    ++      "https://developer.android.com/reference/android/app/job/JobScheduler.html">
    ++        JobScheduler</a> API for asynchronous jobs, including polling at
    ++        regular intervals (described below)
    ++      </li>
    ++
    ++      <li>Multi-networking APIs if you need to connect to specific network
    ++      types; see <a href=
    ++      "https://developer.android.com/about/versions/android-5.0.html#Wireless">
    ++        Multiple Network Connections</a>
    ++      </li>
    ++    </ul>
    ++
    ++    <p>
    ++      For foreground use cases, we currently recommend that you make a
    ++      request for an unmetered network. Here is an example of using
    ++      the multi-networking APIs to request an unmetered network:
    ++    </p>
    ++
    ++<pre>
    ++ConnectivityManager.NetworkCallback networkCallback =
    ++  new ConnectivityManager.NetworkCallback() {
    ++    &#64;Override
    ++    public void onAvailable(Network network) {
    ++      // access network
    ++      }
    ++    };
    ++ConnectivityManager connectivityManager =
    ++  (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
    ++
    ++connectivityManager.requestNetwork(new NetworkRequest.Builder()
    ++  .addCapability(NET_CAPABILITY_NOT_METERED)
    ++  .build(), networkCallback);
    ++</pre>
    ++
    ++    <p>
    ++      We also recommend setting a timer for frontend scenarios
    ++      to prevent a user from potentially waiting for a long time.
    ++      When the network is no longer needed, or if the timer fires,
    ++      the network callback needs to be unregistered:
    ++    </p>
    ++
    ++<pre>
    ++connectivityManager.unregisterNetworkCallback(networkCallback):
    ++</pre>
    ++
    ++    <p>
    ++      A Wear app can communicate with a phone app using the <a href=
    ++      "https://developer.android.com/training/wearables/data-layer/index.html">Wearable
    ++      Data Layer API</a>, but connecting to a network using that API is
    ++      discouraged.
    ++    </p>
    ++
    ++    <h3 id="necessary_data">
    ++      Obtaining only the necessary data
    ++    </h3>
    ++
    ++    <p>
    ++      When obtaining data from the cloud, get only the necessary data.
    ++      Otherwise, you may introduce unnecessary latency, memory use, and battery
    ++      use.
    ++    </p>
    ++
    ++    <p>
    ++      When a watch is connected over a Bluetooth LE connection, your app may
    ++      have access to a bandwidth of only 10 kilobytes per second. Therefore,
    ++      the following steps are recommended:
    ++    </p>
    ++
    ++    <ul>
    ++      <li>Audit your network requests and responses for extra data that only is
    ++      for a phone app
    ++      </li>
    ++
    ++      <li>Shrink large images before sending them over a network to a watch
    ++      </li>
    ++    </ul>
    ++
    ++    <h2 id="background_services">
    ++      Using Background Services
    ++    </h2>
    ++
    ++    <p>
    ++      To ensure that background tasks are correctly executed, they must account
    ++      for <a href=
    ++      "https://developer.android.com/training/monitoring-device-state/doze-standby.html">
    ++      Doze</a>. In Android 6.0, Doze and App Standby resulted in significant
    ++      improvements to battery life by allowing devices to enter deep sleep when
    ++      idle and stationary.
    ++    </p>
    ++
    ++    <p>
    ++      Doze is <a href=
    ++      "https://developer.android.com/preview/behavior-changes.html#doze">enhanced</a>
    ++      in Android Nougat and Android Wear 2.0. When a screen turns off or enters
    ++      ambient mode for a long enough time, a subset of Doze can occur and
    ++      background tasks may be deferred for certain periods. Later, when a
    ++      device is stationary for an extended time, regular Doze occurs.
    ++    </p>
    ++
    ++    <p>
    ++      You should schedule jobs with the <a href=
    ++      "https://developer.android.com/reference/android/app/job/JobScheduler.html">
    ++      JobScheduler</a> API, which enables your app to register for Doze-safe
    ++      code execution. When scheduling jobs, you can select constraints such as
    ++      periodic execution and the need for connectivity or device charging.
    ++      It is important to configure jobs in a way that does not adversely
    ++      impact battery life. Jobs should use a
    ++      <a href="https://developer.android.com/reference/android/app/job/JobInfo.Builder.html">
    ++      JobInfo.Builder</a> object to provide constraints and metadata, e.g. with
    ++      one or more of the following methods for a task:
    ++    </p>
    ++
    ++    <ul>
    ++      <li>To schedule a task that requires networking, use
    ++      <code>setRequiredNetworkType(int networkType)</code>, specifying
    ++      <code>NETWORK_TYPE_ANY</code> or <code>NETWORK_TYPE_UNMETERED</code>;
    ++      note that <code>NETWORK_TYPE_UNMETERED</code> is for large data transfers
    ++      while <code>NETWORK_TYPE_ANY</code> is for small transfers
    ++      </li>
    ++
    ++      <li>To schedule a task while charging, use
    ++      <code>setRequiresCharging(boolean requiresCharging)</code>
    ++      </li>
    ++
    ++      <li>For specifying that a device is idle for a task, use
    ++      <code>setRequiresDeviceIdle(boolean requiresDeviceIdle)</code>; this
    ++      method can be useful for lower-priority background work or
    ++      synchronization, especially when used with
    ++      <code>setRequiresCharging</code>
    ++      </li>
    ++    </ul>
    ++
    ++    <p>
    ++      Note that some low-bandwidth networks, such as Bluetooth LE, are
    ++      considered metered.
    ++    </p>
    ++
    ++    <h3>
    ++      Scheduling with constraints
    ++    </h3>
    ++
    ++    <p>
    ++      You can schedule a task that requires constraints. In the example below,
    ++      a <code>JobScheduler</code> object activates <code>MyJobService</code>
    ++      when the following constraints are met:
    ++    </p>
    ++
    ++    <ul>
    ++      <li>Unmetered networking
    ++      </li>
    ++
    ++      <li>Device charging
    ++      </li>
    ++    </ul>
    ++
    ++    <p>
    ++      You can use the builder method <code>setExtras</code> to attach a bundle
    ++      of app-specific metadata to the job request. When your job executes, this
    ++      bundle is provided to your job service. Note the <code>MY_JOB_ID</code>
    ++      value passed to the <code>JobInfo.Builder</code> constructor. This
    ++      <code>MY_JOB_ID</code> value is an app-provided identifier. Subsequent
    ++      calls to cancel, and subsequent jobs created with that same value, will
    ++      update the existing job:
    ++    </p>
    ++
    ++<pre>
    ++JobInfo jobInfo = new JobInfo.Builder(MY_JOB_ID,
    ++        new ComponentName(this, MyJobService.class))
    ++        .setRequiredNetworkType(JobInfo.NETWORK_TYPE_UNMETERED)
    ++        .setRequiresCharging(true)
    ++        .setExtras(extras)
    ++        .build();
    ++((JobScheduler) getSystemService(JOB_SCHEDULER_SERVICE))
    ++        .schedule(jobInfo);
    ++</pre>
    ++
    ++    <p>
    ++      Below is an implementation of <a href=
    ++      "https://developer.android.com/reference/android/app/job/JobService.html">
    ++      JobService</a> to handle the job above. When the job executes, a
    ++      <code>JobParameters</code> object is passed into the
    ++      <code>onStartJob</code> method. The <code>JobParameters</code> object
    ++      enables you to get the job ID value along with any extras bundle provided
    ++      when scheduling the job. The <code>onStartJob</code> method is called on
    ++      the main application thread, and therefore any expensive logic should be
    ++      run from a separate thread. In the example, an <code>AsyncTask</code> is
    ++      used to run code in the background. When work is complete, you would call
    ++      the <code>jobFinished</code> method to notify <code>JobScheduler</code>
    ++      that the task is done:
    ++    </p>
    ++
    ++<pre>
    ++public class MyJobService extends JobService {
    ++    &#64;Override public boolean onStartJob(JobParameters params) {
    ++        new JobAsyncTask().execute(params);
    ++        return true;
    ++    }
    ++
    ++    private class JobAsyncTask extends AsyncTask
    ++</pre>
    ++
    ++    <h2 id="fcm">
    ++      Cloud Notifications Using FCM
    ++    </h2>
    ++
    ++    <p>
    ++      FCM is the recommended way to send notifications to a watch.
    ++    </p>
    ++
    ++    <p>
    ++      Provide for messages from FCM by collecting a registration token for a
    ++      device when your Wear app runs. Then include the token as part of the
    ++      destination when your server sends messages to the FCM REST endpoint. FCM
    ++      sends messages to the device identified by the token.
    ++    </p>
    ++
    ++    <p>
    ++      An FCM message is in JSON format and can include one or both of the
    ++      following payloads:
    ++    </p>
    ++
    ++    <ul>
    ++      <li>
    ++        <strong>Notification payload.</strong> When a notification payload is
    ++        received by a watch, the data is displayed to a user directly in the
    ++        notification stream. When the user taps the notification, your app is
    ++        launched.
    ++      </li>
    ++
    ++      <li>
    ++        <strong>Data payload</strong>. The payload has a set of custom
    ++        key/value pairs. The payload and is delivered as data to your Wear app.
    ++      </li>
    ++    </ul>
    ++
    ++    <p>
    ++      For more information and examples of payloads, see <a href=
    ++      "https://firebase.google.com/docs/cloud-messaging/concept-options">About
    ++      FCM Messages</a>.
    ++    </p>
    ++
    ++    <h2 id="fcm-phone">
    ++      Notifications from a Companion Phone
    ++    </h2>
    ++
    ++    <p>
    ++      By default, notifications are bridged (shared) from a phone app to a
    ++      watch. If you have a standalone Wear app and a corresponding phone app,
    ++      duplicate notifications can occur. For example, the same notification
    ++      from FCM, received by both a phone and a watch, could be
    ++      displayed by both devices independently.
    ++    </p>
    ++
    ++    <p>
    ++      For information about preventing duplicate notifications, see <a href=
    ++      "https://developer.android.com/wear/preview/features/bridger.html">Bridging
    ++      Mode for Notifications</a>.
    ++    </p>
    +diff --git a/docs/html/wear/preview/features/wearable-recycler-view.jd b/docs/html/wear/preview/features/wearable-recycler-view.jd
    +new file mode 100644
    +index 0000000..f28a472
    +--- /dev/null
    ++++ b/docs/html/wear/preview/features/wearable-recycler-view.jd
    +@@ -0,0 +1,223 @@
    ++
    ++page.title=Curved Layout
    ++meta.tags="wear", "wear-preview", "RecyclerView"
    ++page.tags="wear"
    ++
    ++@jd:body
    ++
    ++
    ++<div id="qv-wrapper">
    ++<div id="qv">
    ++
    ++    <h2>In this document</h2>
    ++    <ol>
    ++      <li><a href="#creating">Creating a Curved Layout</a></li>
    ++      <li><a href="#adding">Adding a Circular Scrolling Gesture</a></li>
    ++      <li><a href="#aligning">Anchoring Children to the Curve</a></li>
    ++    </ol>
    ++
    ++</div>
    ++</div>
    ++
    ++
    ++<p>
    ++  Wear 2.0 introduces the {@code WearableRecyclerView} class for displaying
    ++  and manipulating a vertical list of items optimized for round displays.
    ++  {@code WearableRecyclerView} extends the existing
    ++  <a href="{@docRoot}reference/android/support/v7/widget/RecyclerView.html">{@code RecyclerView}</a>
    ++  class to provide a curved layout and a circular scrolling gesture in wearable apps.
    ++</p>
    ++<img src="https://android-dot-devsite.googleplex.com/wear/preview/images/wrv_new.png"
    ++      style="float:right;margin:10px 20px 0 0">
    ++
    ++<p>
    ++  You can adapt to this interface in your wearable app by creating a new
    ++  {@code WearableRecyclerView} container.
    ++</p>
    ++
    ++<p>
    ++  You should decide whether to use a {@code WearableRecyclerView}, based on
    ++  the kind of user experience you want to provide. We recommend using the
    ++  {@code WearableRecyclerView} for a simple, long list of items, such as an
    ++  application launcher, or a list contacts. Each item might have a short string
    ++  and an associated icon. Alternatively, each item might have only a string or
    ++  an icon. We do not recommend using a {@code WearableRecyclerView} for short
    ++  or complex lists.
    ++</p>
    ++
    ++<p>
    ++  This document describes how to create a curved layout for your scrollable items
    ++  and properly align them along the curve.
    ++</p>
    ++
    ++
    ++<h2 id="creating">Creating a Curved Layout</h2>
    ++<p>To create a curved layout for scrollable items in your wearable app:
    ++</p>
    ++<ul>
    ++  <li>Use {@code WearableRecyclerView} as your main container in the relevant
    ++      xml layout.
    ++  </li>
    ++
    ++  <li>By default, {@code WearableRecyclerView} uses the {@code
    ++    DefaultOffsettingHelper} class to offset items in a curved layout on round
    ++    devices. If you wish to implement your own offsetting logic, you can extend the
    ++    abstract {@code WearableRecyclerView.OffsettingHelper} class and attach it to
    ++    the {@code WearableRecyclerView} using {@code
    ++    WearableRecyclerView.setOffsettingHelper} method.
    ++
    ++    <pre>
    ++      CircularOffsettingHelper circularHelper = new CircularOffsettingHelper();
    ++      mRecyclerView.setOffsettingHelper(circularHelper);
    ++    </pre>
    ++
    ++    <pre>
    ++      public class CircularOffsettingHelper extends OffsettingHelper {
    ++
    ++        &#64;Override
    ++        public void updateChild(View child, WearableRecyclerView parent) {
    ++          int progress = child.getTop() / parent.getHeight();
    ++          child.setTranslationX(-child.getHeight() * progress);
    ++         }
    ++      }
    ++    </pre>
    ++
    ++  </li>
    ++
    ++</ul>
    ++
    ++<p class="note">
    ++  <strong>Note:</strong> {@code DefaultOffsettingHelper} class
    ++  offsets the child items
    ++  along a predefined UX curve, but the operation can cut off part of the child
    ++  view if it is not scaled down accordingly. This is because the default curve
    ++  attempts to fit 5 items on the screen, regardless of their size.
    ++  If you do not wish to scale your items, you should consider additional padding.
    ++</p>
    ++
    ++<h3>Examples</h3>
    ++<p>
    ++  The following code example demonstrates how to add {@code WearableRecyclerView}
    ++   to a layout:
    ++</p>
    ++<pre>
    ++&lt;android.support.wearable.view.WearableRecyclerView
    ++   xmlns:android="http://schemas.android.com/apk/res/android"
    ++   xmlns:tools="http://schemas.android.com/tools"
    ++   android:id="&#64;+id/recycler_launcher_view"
    ++   android:layout_width="match_parent"
    ++   android:layout_height="match_parent"
    ++   android:scrollbars="vertical" /&gt;
    ++ </pre>
    ++
    ++
    ++<p>
    ++  To customize the appearance of the children while scrolling (for example,
    ++  scale the icons and text while the items scroll away from the center),  extend
    ++  the  {@code DefaultOffsettingHelper} and override the {@code updateChild }
    ++  method. It is important to call the {@code super.updateChild(child, parent)} to
    ++  offset the children along the curve. However, if for any particular child you do
    ++  not wish them to follow a curve, you can chose not to call the super method for
    ++  that particular child.
    ++</p>
    ++
    ++<pre>
    ++
    ++public class MyOffsettingHelper extends DefaultOffsettingHelper {
    ++
    ++   /** How much should we scale the icon at most. */
    ++   private static final float MAX_ICON_PROGRESS = 0.65f;
    ++
    ++   private float mProgressToCenter;
    ++
    ++   public OffsettingHelper() {}
    ++
    ++   &#64;Override
    ++
    ++   public void updateChild(View child,  WearableRecyclerView parent) {
    ++       super.updateChild(child, parent);
    ++
    ++
    ++       // Figure out % progress from top to bottom
    ++       float centerOffset = ((float) child.getHeight() / 2.0f) /  (float) mParentView.getHeight();
    ++       float yRelativeToCenterOffset = (child.getY() / mParentView.getHeight()) + centerOffset;
    ++
    ++       // Normalize for center
    ++       mProgressToCenter = Math.abs(0.5f - yRelativeToCenterOffset);
    ++       // Adjust to the maximum scale
    ++       mProgressToCenter = Math.min(mProgressToCenter, MAX_ICON_PROGRESS);
    ++
    ++       child.setScaleX(1 - mProgressToCenter);
    ++       child.setScaleY(1 - mProgressToCenter);
    ++   }
    ++}
    ++
    ++
    ++</pre>
    ++
    ++
    ++<h2 id="adding">Adding a Circular Scrolling Gesture</h2>
    ++
    ++<p>
    ++  By default, circular scrolling is disabled in the {@code
    ++  WearableRecyclerView}. If you want to enable circular scrolling gesture
    ++  in your child view, use the  {@code WearavleRecyclerView}’s {@code
    ++  setCircularScrollingGestureEnabled()} method.  You can also customize the
    ++  circular scrolling gesture by defining one or both of the following:
    ++</p>
    ++
    ++<ul>
    ++  <li>How many degrees the user has to rotate by to scroll through one screen height.
    ++    This effectively influences the speed of the scolling -
    ++    {@code setScrollDegreesPerScreen} - the default value is set at 180 degrees.
    ++  </li>
    ++
    ++  <li>
    ++    The width of a virtual ‘bezel’ near the the edge of the screen in which the
    ++    gesture will be recognized - {@code setBezelWidth} - the default value is set
    ++    at 1. This is expressed as a fraction of the radius of the view.
    ++</ul>
    ++
    ++
    ++<p>The following code snippet shows how to set these methods:</p>
    ++
    ++<pre>
    ++  setCircularScrollingGestureEnabled(true);
    ++  setBezelWidth(0.5f);
    ++  setScrollDegreesPerScreen(90);
    ++</pre>
    ++
    ++<h2 id="aligning"> Anchoring Children to the Curve </h2>
    ++
    ++<p>
    ++  To ensure that the layout for WearableRecyclerView is adaptable to different
    ++  types of child views, the WearableRecyclerView class, by default, chooses the
    ++  middle left edge (X=0, Y=Half the child height) as the anchor coordinates for
    ++  the child item. Using the default anchor coordinates can result in offsetting
    ++  the child items from the left edge of the watch face. To customize the anchor
    ++  coordinates of your child view along the curve, you can overwrite the
    ++  {@code adjustAnchorOffsetXY()} method. You can calculate the X (horizontal)
    ++  and Y (vertical) offset of the child item, and set it using the
    ++  {@code adjustAnchorOffsetXY()} method to properly align items
    ++  along the curve. The coordinates should be with relation to the child view.
    ++</p>
    ++
    ++<p><img src="{@docRoot}wear/preview/images/alignment.png"/></p>
    ++<p><b>Figure 1</b>. Imaginary UX curve and anchor points on the curve.</p>
    ++
    ++<p>
    ++  The code snippet below, calculates the X offset for a child item in which the
    ++  width of the icon is same as the height of the child item. In this case, the
    ++  anchor coordinates for the child item are at the center of the icon.
    ++
    ++</p>
    ++<img src="{@docRoot}wear/preview/images/center_align.png" style="float:left;margin:10px 20px 0 0"/>
    ++
    ++<pre>
    ++ &#64;Override
    ++  protected void adjustAnchorOffsetXY(View child, float[] anchorOffsetXY) {
    ++    anchorOffsetXY[0] = child.getHeight() / 2.0f;
    ++  }
    ++</pre>
    ++
    ++
    +diff --git a/docs/html/wear/preview/images/alignment.png b/docs/html/wear/preview/images/alignment.png
    +new file mode 100644
    +index 0000000..525b334
    +Binary files /dev/null and b/docs/html/wear/preview/images/alignment.png differ
    +diff --git a/docs/html/wear/preview/images/apk-details.png b/docs/html/wear/preview/images/apk-details.png
    +new file mode 100644
    +index 0000000..eb3b859
    +Binary files /dev/null and b/docs/html/wear/preview/images/apk-details.png differ
    +diff --git a/docs/html/wear/preview/images/apk-tabs.png b/docs/html/wear/preview/images/apk-tabs.png
    +new file mode 100644
    +index 0000000..949b98f
    +Binary files /dev/null and b/docs/html/wear/preview/images/apk-tabs.png differ
    +diff --git a/docs/html/wear/preview/images/center_align.png b/docs/html/wear/preview/images/center_align.png
    +new file mode 100644
    +index 0000000..ca88ad7
    +Binary files /dev/null and b/docs/html/wear/preview/images/center_align.png differ
    +diff --git a/docs/html/wear/preview/images/current-apk.png b/docs/html/wear/preview/images/current-apk.png
    +new file mode 100644
    +index 0000000..2545f92
    +Binary files /dev/null and b/docs/html/wear/preview/images/current-apk.png differ
    +diff --git a/docs/html/wear/preview/images/inline_action.png b/docs/html/wear/preview/images/inline_action.png
    +new file mode 100644
    +index 0000000..7ecaafe
    +Binary files /dev/null and b/docs/html/wear/preview/images/inline_action.png differ
    +diff --git a/docs/html/wear/preview/images/wrv_new.png b/docs/html/wear/preview/images/wrv_new.png
    +new file mode 100644
    +index 0000000..c413c59
    +Binary files /dev/null and b/docs/html/wear/preview/images/wrv_new.png differ
    +diff --git a/docs/html/wear/preview/index.jd b/docs/html/wear/preview/index.jd
    +index 4b3c1f2..6292577 100644
    +--- a/docs/html/wear/preview/index.jd
    ++++ b/docs/html/wear/preview/index.jd
    +@@ -7,16 +7,6 @@ header.hide=1
    + footer.hide=1
    + @jd:body
    + 
    +-<script>
    +-  $(document).ready(function() {
    +-    if (useUpdatedTemplates) {
    +-      $("#useUpdatedTemplates").css("display","block");
    +-    } else {
    +-      $("#useOldTemplates").css("display","block");
    +-    }
    +-  })
    +-</script>
    +-
    + <section class="dac-expand dac-hero dac-light" style="background-color:#FFFFFF">
    +   <div class="wrap" style="max-width:1100px;margin-top:0">
    +     <div class="cols dac-hero-content" style="padding-bottom:1em;">
    +@@ -55,7 +45,7 @@ footer.hide=1
    +   </div>
    + </section>
    + 
    +-<div id="useUpdatedTemplates" style="display:none" class="dac-section dac-slim dac-gray dac-expand">
    ++<div class="dac-section dac-slim dac-gray dac-expand">
    +   <div class="wrap dac-offset-parent">
    +     <a class="dac-fab dac-scroll-button" data-scroll-button href="#build-apps">
    +       <i class="dac-sprite dac-arrow-down-gray"></i>
    +@@ -77,22 +67,6 @@ footer.hide=1
    +   </div><!-- end .wrap -->
    + </div><!-- end .dac-actions -->
    + 
    +-<div id="useOldTemplates" style="display:none;color:black" class="actions-bar dac-expand dac-invert">
    +-  <div class="wrap dac-offset-parent">
    +-
    +-    <div class="actions">
    +-      <div><a href="{@docRoot}wear/preview/bug">
    +-        <span class="dac-sprite dac-auto-chevron-large"></span>
    +-        Report an issue
    +-      </a></div>
    +-      <div><a href="http://g.co/androidweardev">
    +-        <span class="dac-sprite dac-auto-chevron-large"></span>
    +-        Join developer community
    +-      </a></div>
    +-    </div><!-- end .actions -->
    +-  </div><!-- end .wrap -->
    +-</div>
    +-
    + <section class="dac-section dac-light"><div class="wrap">
    +   <h1 class="dac-section-title">Resources</h1>
    +   <div class="dac-section-subtitle">
    +diff --git a/docs/html/wear/preview/program.jd b/docs/html/wear/preview/program.jd
    +index e2bf92f..4f2fb5c 100644
    +--- a/docs/html/wear/preview/program.jd
    ++++ b/docs/html/wear/preview/program.jd
    +@@ -143,8 +143,9 @@ page.image=images/cards/card-n-sdk_2x.png
    +     <p>
    +       At milestone 4, you'll have access to the final Android Wear 2.0
    +       APIs and SDK to develop with, as well as near-final system images to test
    +-      system behaviors and features. Android Wear 2.0 will use the Android N
    +-      API level at this time. You can begin final compatibility testing of your
    ++      system behaviors and features. Android Wear 2.0 will use the
    ++      Android 7.0 API level at this time.
    ++      You can begin final compatibility testing of your
    +       legacy apps and refine any new code that is using the Android Wear 2.0
    +       APIs or features.
    +     </p>
    +diff --git a/docs/html/wear/preview/start.jd b/docs/html/wear/preview/start.jd
    +index 8fccdc8..c9720dc 100644
    +--- a/docs/html/wear/preview/start.jd
    ++++ b/docs/html/wear/preview/start.jd
    +@@ -29,7 +29,7 @@ page.image=images/cards/card-n-sdk_2x.png
    + 
    +     <p>
    +       If you want an environment for basic compatibility
    +-      testing of your app, you can use your current APK and a
    ++      testing, you can use your current APK and a
    +       supported watch or an emulator. You don't necessarily need to update your
    +       full development environment to do basic testing. To simply test your
    +       app's compatibility with a preview system image, see <a href=
    +@@ -48,10 +48,8 @@ page.image=images/cards/card-n-sdk_2x.png
    +     </h2>
    + 
    +     <p>
    +-      1. For compatibility with the <a href="{@docRoot}preview/overview.html">N
    +-      Developer Preview</a>, follow the <a href=
    +-      "{@docRoot}preview/setup-sdk.html">setup instructions</a> for installing
    +-      the latest version of Android Studio.
    ++      1. For compatibility with Android 7.0, install the latest version of
    ++      <a href="https://developer.android.com/studio/index.html">Android Studio</a>.
    +     </p>
    + 
    +     <p>
    +@@ -63,7 +61,7 @@ page.image=images/cards/card-n-sdk_2x.png
    +     <ul>
    +       <li>Under the <strong>SDK Platforms tab</strong>:
    +         <ul>
    +-          <li>Android N Preview
    ++          <li>Android 7.0 (Nougat)
    +           </li>
    +         </ul>
    +       </li>
    +@@ -107,10 +105,10 @@ page.image=images/cards/card-n-sdk_2x.png
    + 
    +       <tr>
    +         <td>
    +-          <a href="http://storage.googleapis.com/androiddevelopers/shareables/wear-preview/wearable-support-preview-2-docs.zip">wearable-support-preview-2-docs.zip</a>
    ++          <a href="http://storage.googleapis.com/androiddevelopers/shareables/wear-preview/wearable-support-preview-3-docs.zip">wearable-support-preview-3-docs.zip</a>
    +         </td>
    +-        <td>MD5: afb770c9c5c0431bbcbdde186f1eae06<br>
    +-            SHA-1: 81d681e61cee01f222ea82e83297d23c4e55b8f3
    ++        <td>MD5: 22bae00e473e39e320aae8ea09a001a5<br>
    ++            SHA-1: 474502cc7092bcf0bd671441b8654aa8d6c155ed
    +         </td>
    +       </tr>
    +     </table>
    +@@ -163,7 +161,7 @@ page.image=images/cards/card-n-sdk_2x.png
    +       following, which requires that your the Google Repository <a href=
    +       "#install_android_studio_and_the_latest_packages">is the latest
    +       version</a>:
    +-      <code>compile 'com.google.android.support:wearable:2.0.0-alpha2'</code>
    ++      <code>compile 'com.google.android.support:wearable:2.0.0-alpha3'</code>
    +         </li>
    +       </ul>
    +       </li>
    +@@ -190,12 +188,12 @@ page.image=images/cards/card-n-sdk_2x.png
    +       </li>
    + 
    +       <li>Optionally, select the <strong>Phone and Tablet</strong> option. If
    +-      you plan to use N Preview APIs in a phone app, then the Minimum SDK
    +-      option list, select <strong>API N: Android 6.x (N Preview)</strong>.
    ++      you plan to use Android 7.0 APIs in a phone app, then the Minimum SDK
    ++      option list, select <strong>API 24: Android 7.0 (Nougat)</strong>.
    +       </li>
    + 
    +       <li>Select the <strong>Wear</strong> option, and in the Minimum SDK
    +-      option list, select the latest available (<strong>N Preview</strong>)
    ++      option list, select the latest available (<strong>API Nougat</strong>)
    +       option. Click <strong>Next</strong> until you exit the Create New Project
    +       wizard.
    +       </li>
    +@@ -215,7 +213,7 @@ page.image=images/cards/card-n-sdk_2x.png
    +       following, which requires that your the Google Repository <a href=
    +       "#install_android_studio_and_the_latest_packages">is the latest
    +       version</a>:
    +-      <code>compile 'com.google.android.support:wearable:2.0.0-alpha2'</code>
    ++      <code>compile 'com.google.android.support:wearable:2.0.0-alpha3'</code>
    +         </li>
    +       </ul>
    +       </li>
    +diff --git a/docs/html/wear/preview/support.jd b/docs/html/wear/preview/support.jd
    +index 78b4e4b..6006627 100644
    +--- a/docs/html/wear/preview/support.jd
    ++++ b/docs/html/wear/preview/support.jd
    +@@ -23,7 +23,9 @@ page.tags="preview", "developer preview"
    + 
    + <ul>
    +   <li><a href="#general">General Advisories</a></li>
    ++  <li><a href="#platform-version">Platform API Version</a></li>
    +   <li><a href="#deprecations">Deprecations</a></li>
    ++  <li><a href="#dp3">Developer Preview 3</a></li>
    +   <li><a href="#dp2">Developer Preview 2</a></li>
    +   <li><a href="#dp1">Developer Preview 1</a></li>
    + </ul>
    +@@ -46,10 +48,25 @@ page.tags="preview", "developer preview"
    +     panics and crashes.
    +   </li>
    +   <li>Some apps <strong>may not function as expected</strong> on the new
    +-  platform version. This includes Google’s apps and other apps.
    ++  platform version. This includes Google's apps and other apps.
    +   </li>
    + </ul>
    + 
    ++<h2 id="platform-version">
    ++  Platform API Version
    ++</h2>
    ++
    ++<p>
    ++  The Android Platform API version is incremented to 24 to match Android 7.0.
    ++  You can update the following in your Android Wear 2.0 Preview project
    ++  to <strong>24</strong>:
    ++</p>
    ++
    ++<ul>
    ++  <li><code>compileSdkVersion</code></li>
    ++  <li><code>targetSdkVersion</code></li>
    ++</ul>
    ++
    + <h2 id="deprecations">Deprecations</h2>
    + 
    + <p>The following fields are deprecated in the preview:</p>
    +@@ -64,6 +81,291 @@ page.tags="preview", "developer preview"
    +   </li>
    + </ul>
    + 
    ++<h2 id="dp3">Developer Preview 3</h2>
    ++
    ++<div class="wrap">
    ++  <div class="cols">
    ++    <div class="col-6of12">
    ++      <p><em>Date: September 2016<br />
    ++      Builds: Wearable Support 2.0.0-alpha3, NVE68J<br/>
    ++      Emulator support: x86 & ARM (32-bit)<br/>
    ++      </em></p>
    ++    </div>
    ++  </div>
    ++</div>
    ++
    ++<h3 id="new-in-fdp3">
    ++  New in Preview 3
    ++</h3>
    ++
    ++    <p>
    ++      For access to system images and the companion app for Preview 3, see
    ++      <a href="https://developer.android.com/wear/preview/downloads.html">
    ++      Download and Test with a Device</a>.
    ++    </p>
    ++
    ++    <h4>
    ++      Additions for standalone apps and the Play Store on Wear
    ++    </h4>
    ++
    ++    <p>
    ++      For information about planning your Wear 2.0 app, see <a href=
    ++      "https://developer.android.com/wear/preview/features/standalone-apps.html">
    ++      Standalone Apps</a>.
    ++    </p>
    ++
    ++    <p>
    ++      Generally, the minimum and target SDK level for Wear 2.0, and for a
    ++      standalone APK, is level 24. The minimum SDK level can be 23
    ++      only if you are using the same APK
    ++      for Wear 1.0 and 2.0 (and thus have an embedded Wear 1.0 APK).
    ++    </p>
    ++
    ++    <p>
    ++      Run-time permissions are required.
    ++    </p>
    ++
    ++    <p>
    ++      For information about distributing your Wear 2.0 app, see <a href=
    ++      "https://developer.android.com/wear/preview/features/app-distribution.html">
    ++      App Distribution</a>.
    ++    </p>
    ++
    ++    <h4 id="additions-to-the-complications-api">
    ++      Complications API additions
    ++    </h4>
    ++
    ++    <p>
    ++      For Preview 3, additions and changes have been made to the Complications
    ++      API. The <a href=
    ++      "https://developer.android.com/wear/preview/features/complications.html">documentation</a>
    ++      includes information about the following additions and changes:
    ++    </p>
    ++
    ++    <ul>
    ++      <li>To receive complication data and open the provider chooser, a watch
    ++      face must have the <code>RECEIVE_COMPLICATION_DATA</code> permission.
    ++      </li>
    ++
    ++      <li>To ease a request for the new permission and the starting of the
    ++      chooser, the <code>ComplicationHelperActivity</code> class is available
    ++      in the wearable support library. This class should be used instead of
    ++      <code>ProviderChooserIntent</code> to start the chooser in almost all
    ++      cases.
    ++      </li>
    ++
    ++      <li>Watch faces can specify default providers that are used until a user
    ++      selects a provider.
    ++      </li>
    ++
    ++      <li>The complication types used for "empty" data are changed.
    ++      </li>
    ++
    ++      <li>A new permission was added to ensure that only the Android Wear
    ++      system can bind to provider services.
    ++      </li>
    ++    </ul>
    ++
    ++    <p>
    ++      For changes related to the <code>ComplicationData</code> object, see
    ++      <a href=
    ++      "https://developer.android.com/wear/preview/behavior-changes.html">Behavior
    ++      Changes</a>.
    ++    </p>
    ++
    ++    <h4 id="wearable-recycler-view-api">
    ++      Curved Layout
    ++    </h4>
    ++
    ++    <p>
    ++      For information about creating a curved layout using
    ++      the <code>WearableRecyclerView</code> API in your Wear 2.0 app, see
    ++      <a href="https://developer.android.com/wear/preview/features/wearable-recycler-view.html">
    ++      Curved Layout</a>.
    ++    </p>
    ++
    ++    <h4 id="notifications-features-fdp3">
    ++      Notifications features
    ++    </h4>
    ++
    ++    <p>
    ++      To learn about adding an inline action to a notification,
    ++      see <a href="https://developer.android.com/wear/preview/notifications.html#inline">Inline
    ++      Action</a>.
    ++    </p>
    ++
    ++    <p>
    ++      To learn about adding images to a notification, see
    ++      <a href=
    ++      "https://developer.android.com/wear/preview/notifications.html#images">Adding
    ++      images to a notification</a>.
    ++    </p>
    ++
    ++    <p>
    ++      For additions related to the bridging of notifications from a companion
    ++      app to a watch, see <a href=
    ++      "https://developer.android.com/wear/preview/features/bridger.html">Bridging
    ++      Mode for Notifications</a>.
    ++    </p>
    ++
    ++    <h4 id="additions-for-smart-reply">
    ++      Smart Reply additions
    ++    </h4>
    ++
    ++    <p>
    ++      Smart Reply responses are generated by an entirely on-watch,
    ++      machine-learning model using the context provided by <a href=
    ++      "https://developer.android.com/wear/preview/features/notifications.html#messaging">
    ++      MessagingStyle</a> notifications. Use the <a href=
    ++      "https://developer.android.com/reference/android/support/v4/app/NotificationCompat.Action.Builder.html#setAllowGeneratedReplies(boolean)">
    ++      setAllowGeneratedReplies(boolean)</a> method to enable Smart Reply for
    ++      your <code>MessagingStyle</code> notification.
    ++    </p>
    ++
    ++    <h3 id="known-issues-3">
    ++      Known Issues
    ++    </h3>
    ++
    ++    <h4 id="notifications">
    ++      Notifications
    ++    </h4>
    ++
    ++    <ul>
    ++      <li>The <code>MessagingStyle</code> <a href=
    ++      "https://developer.android.com/wear/preview/features/notifications.html#images">
    ++        notifications with images</a> posted by standalone apps don't show
    ++        images in the notification (i.e., bridged notifications show images,
    ++        but standalone notifications don't).
    ++      </li>
    ++
    ++      <li>This preview release does not include support for notification
    ++      groups.
    ++      </li>
    ++
    ++      <li>With Wear 2.0, a watch can receive notifications directly from
    ++      Firebase Cloud Messaging (FCM), which replaces Google Cloud Messaging
    ++      (GCM). However, in Preview 3 of Wear 2.0, FCM does not function with
    ++      iOS-paired watches.
    ++      </li>
    ++
    ++      <li>Smart Reply responses are only shown in <code>RemoteInput</code> when
    ++      <code>RemoteInput</code> is called from a <code>MessagingStyle</code>
    ++      expanded notification. Smart Reply responses are not shown in
    ++      <code>RemoteInput</code> when <code>RemoteInput</code> is called from an
    ++      <a href=
    ++      "https://developer.android.com/wear/preview/features/notifications.html#inline">
    ++        inline action</a> within the stream&#8212;an action set with the <a href=
    ++        "https://developer.android.com/reference/android/support/v4/app/NotificationCompat.Action.WearableExtender.html#setHintDisplayActionInline(boolean)">
    ++        setHintDisplayActionInline(true)</a> method.
    ++      </li>
    ++    </ul>
    ++
    ++    <h4 id="companion-app">
    ++      Companion app
    ++    </h4>
    ++
    ++    <ul>
    ++      <li>The preview companion app is not compatible with Android 4.3
    ++      (Jelly Bean MR2), which has an SDK build version code of:
    ++      <code>JELLY_BEAN_MR2</code></li>
    ++    </ul>
    ++
    ++    <ul>
    ++      <li>In permission screens in the preview companion app:
    ++      If you deny a permission, you cannot
    ++      proceed. Instead of denying a permission, tap <strong>Skip</strong>.
    ++      </li>
    ++    </ul>
    ++
    ++
    ++    <h4 id="developer-console">
    ++      Developer Console
    ++    </h4>
    ++
    ++    <ul>
    ++      <li>If you set a minimum SDK version of 24, the Play Developer Console
    ++      states that there are few supported devices.
    ++      </li>
    ++    </ul>
    ++
    ++    <h4 id="system-user-interface">
    ++      System user interface and apps
    ++    </h4>
    ++
    ++    <ul>
    ++      <li>Dismissing multiple notifications can cause an app to forcibly close.
    ++      </li>
    ++
    ++      <li>The "Ok Google" detection and voice transcription may not work
    ++      reliably.
    ++      </li>
    ++
    ++      <li>Google Fit is not available with Preview 3.
    ++      </li>
    ++
    ++      <li>Syncing for embedded apps is not enabled for the preview. Therefore,
    ++      to test an app on a device, add it to the Play Store or side-load it
    ++      onto a watch. Some existing Wear apps, e.g. Google Maps, are only
    ++      using the embedded apps mechanism currently, and are therefore not
    ++      installable on the preview (and therefore do not appear on the watch).
    ++      </li>
    ++
    ++      <li>In Play Store search results on the watch,
    ++      results other than apps sometimes appear.
    ++      </li>
    ++
    ++      <li>Media controls/notifications are not bridged
    ++      to the watch from an Android KitKat phone.
    ++      </li>
    ++    </ul>
    ++
    ++    <h4 id="account">
    ++      Account sync
    ++    </h4>
    ++
    ++    <ul>
    ++      <li>Account sync initiated from watch settings may not work reliably.
    ++      Instead, add accounts from the setup flow of the Android Wear app, or using
    ++      the Accounts settings for a device from the Android Wear app.
    ++      </li>
    ++
    ++      <li>The list of accounts that can be synced is the same as the list of accounts
    ++      on the phone. So to add a new account, use the Android settings on the phone,
    ++      and then proceed to Android Wear app to sync that account.
    ++      </li>
    ++    </ul>
    ++
    ++    <h4 id="devices">
    ++      Devices
    ++    </h4>
    ++
    ++    <ul>
    ++      <li>In Android Wear emulators, the Play Store app requires that an
    ++      account is synced to the device before the app can be opened.
    ++      </li>
    ++
    ++      <li>On the Huawei Watch, selecting the language, followed by multiple
    ++      acknowledgement dialogues, results in a black screen.
    ++      </li>
    ++
    ++      <li>On the LG Watch Urbane 2nd Edition, when answering a call from the
    ++      watch, the watch does not provide audio from the caller.
    ++      </li>
    ++    </ul>
    ++
    ++    <h4 id="smart-reply">
    ++      Smart Reply
    ++    </h4>
    ++
    ++    <ul>
    ++      <li>Smart Reply is only available if your watch's system language is
    ++      English.
    ++      </li>
    ++
    ++      <li>Smart Reply responses are not generated for all messages.
    ++      </li>
    ++    </ul>
    ++
    + <h2 id="dp2">Developer Preview 2</h2>
    + 
    + <div class="wrap">
    +@@ -78,24 +380,9 @@ page.tags="preview", "developer preview"
    + </div>
    + 
    + <h3 id="new-in-fdp2">
    +-  <strong>New in Preview 2</strong>
    ++  New in Preview 2
    + </h3>
    + 
    +-<h4 id="platform-version-24">
    +-  Platform API Version
    +-</h4>
    +-
    +-<p>
    +-  The Android Platform API version is incremented to 24 to match Android Nougat.
    +-  You can update the following in your Android Wear 2.0 Preview project
    +-  to <strong>24</strong>:
    +-</p>
    +-
    +-<ul>
    +-  <li><code>compileSdkVersion</code></li>
    +-  <li><code>targetSdkVersion</code></li>
    +-</ul>
    +-
    + <h4 id="wearable-drawers">
    +   Wearable drawers
    + </h4>
    +@@ -174,7 +461,7 @@ page.tags="preview", "developer preview"
    + </p>
    + 
    + <h3 id="known-issues-2">
    +-  <strong>Known Issues</strong>
    ++  Known Issues
    + </h3>
    + 
    + <h4 id="notifications-2">
    +@@ -239,6 +526,10 @@ page.tags="preview", "developer preview"
    + 
    +   <li>Unable to turn off the Wi-Fi on a wearable.
    +   </li>
    ++
    ++  <li>After music is played on a companion phone,
    ++  music card notifications are not mirrored to the watch.
    ++  </li>
    + </ul>
    + 
    + <h4 id="companion-app-2">
    +diff --git a/docs/html/work/managed-configurations.jd b/docs/html/work/managed-configurations.jd
    +index 76ca82f..6de4d8b 100644
    +--- a/docs/html/work/managed-configurations.jd
    ++++ b/docs/html/work/managed-configurations.jd
    +@@ -349,7 +349,7 @@ enterprise administrator to:</p>
    + <p>
    +   To get a {@link android.content.RestrictionsManager} object, get the current
    +   activity with {@link android.app.Fragment#getActivity getActivity()}, then
    +-  call that activity's {@link android.app.Activity#getSystemService(java.lang.String)
    ++  call that activity's {@link android.app.Activity#getSystemService
    +   Activity.getSystemService()} method:
    + </p>
    + 
    +@@ -399,9 +399,9 @@ enterprise administrator to:</p>
    +   <code>String</code>, and <code>String[]</code>. Once you have the
    +   managed configurations {@link android.os.Bundle}, you can check the current
    +   configuration settings with the standard {@link android.os.Bundle} methods for
    +-  those data types, such as {@link android.os.BaseBundle#getBoolean getBoolean()}
    ++  those data types, such as {@link android.os.Bundle#getBoolean getBoolean()}
    +   or
    +-  {@link android.os.BaseBundle#getString getString()}.
    ++  {@link android.os.Bundle#getString getString()}.
    + </p>
    + 
    + <p class="note">
    +diff --git a/docs/image_sources/brand/android_logo_no.graffle/data.plist b/docs/image_sources/brand/android_logo_no.graffle/data.plist
    +new file mode 100644
    +index 0000000..1132a59
    +Binary files /dev/null and b/docs/image_sources/brand/android_logo_no.graffle/data.plist differ
    +diff --git a/docs/image_sources/brand/android_logo_no.graffle/image1.jpg b/docs/image_sources/brand/android_logo_no.graffle/image1.jpg
    +new file mode 100644
    +index 0000000..ff29599
    +Binary files /dev/null and b/docs/image_sources/brand/android_logo_no.graffle/image1.jpg differ
    +diff --git a/docs/image_sources/training/tv/playback/onboarding-fragment-diagram.graffle.zip b/docs/image_sources/training/tv/playback/onboarding-fragment-diagram.graffle.zip
    +new file mode 100644
    +index 0000000..89a799b
    +Binary files /dev/null and b/docs/image_sources/training/tv/playback/onboarding-fragment-diagram.graffle.zip differ
    +diff --git a/docs/source.properties b/docs/source.properties
    +new file mode 100644
    +index 0000000..77a760b
    +--- /dev/null
    ++++ b/docs/source.properties
    +@@ -0,0 +1,3 @@
    ++Pkg.Revision=24.0
    ++Pkg.Desc=Android offline API reference
    ++Pkg.Path=docs
    +\ No newline at end of file
    +diff --git a/graphics/java/android/graphics/SurfaceTexture.java b/graphics/java/android/graphics/SurfaceTexture.java
    +index 5c54324..c386108 100644
    +--- a/graphics/java/android/graphics/SurfaceTexture.java
    ++++ b/graphics/java/android/graphics/SurfaceTexture.java
    +@@ -77,6 +77,8 @@ public class SurfaceTexture {
    +     private long mProducer;
    +     private long mFrameAvailableListener;
    + 
    ++    private boolean mIsSingleBuffered;
    ++
    +     /**
    +      * Callback interface for being notified that a new stream frame is available.
    +      */
    +@@ -130,6 +132,7 @@ public class SurfaceTexture {
    +      */
    +     public SurfaceTexture(int texName, boolean singleBufferMode) {
    +         mCreatorLooper = Looper.myLooper();
    ++        mIsSingleBuffered = singleBufferMode;
    +         nativeInit(false, texName, singleBufferMode, new WeakReference<SurfaceTexture>(this));
    +     }
    + 
    +@@ -157,6 +160,7 @@ public class SurfaceTexture {
    +      */
    +     public SurfaceTexture(boolean singleBufferMode) {
    +         mCreatorLooper = Looper.myLooper();
    ++        mIsSingleBuffered = singleBufferMode;
    +         nativeInit(true, 0, singleBufferMode, new WeakReference<SurfaceTexture>(this));
    +     }
    + 
    +@@ -378,6 +382,14 @@ public class SurfaceTexture {
    +         }
    +     }
    + 
    ++    /**
    ++     * Returns true if the SurfaceTexture is single-buffered
    ++     * @hide
    ++     */
    ++    public boolean isSingleBuffered() {
    ++        return mIsSingleBuffered;
    ++    }
    ++
    +     private native void nativeInit(boolean isDetached, int texName,
    +             boolean singleBufferMode, WeakReference<SurfaceTexture> weakSelf)
    +             throws Surface.OutOfResourcesException;
    +diff --git a/graphics/java/android/graphics/drawable/AnimatedVectorDrawable.java b/graphics/java/android/graphics/drawable/AnimatedVectorDrawable.java
    +index c836204..c24d313 100644
    +--- a/graphics/java/android/graphics/drawable/AnimatedVectorDrawable.java
    ++++ b/graphics/java/android/graphics/drawable/AnimatedVectorDrawable.java
    +@@ -65,19 +65,36 @@ import java.lang.ref.WeakReference;
    + import java.util.ArrayList;
    + 
    + /**
    +- * This class uses {@link android.animation.ObjectAnimator} and
    +- * {@link android.animation.AnimatorSet} to animate the properties of a
    +- * {@link android.graphics.drawable.VectorDrawable} to create an animated drawable.
    ++ * This class animates properties of a {@link android.graphics.drawable.VectorDrawable} with
    ++ * animations defined using {@link android.animation.ObjectAnimator} or
    ++ * {@link android.animation.AnimatorSet}.
    +  * <p>
    +- * AnimatedVectorDrawable are normally defined as 3 separate XML files.
    ++ * Starting from API 25, AnimatedVectorDrawable runs on RenderThread (as opposed to on UI thread for
    ++ * earlier APIs). This means animations in AnimatedVectorDrawable can remain smooth even when there
    ++ * is heavy workload on the UI thread. Note: If the UI thread is unresponsive, RenderThread may
    ++ * continue animating until the UI thread is capable of pushing another frame. Therefore, it is not
    ++ * possible to precisely coordinate a RenderThread-enabled AnimatedVectorDrawable with UI thread
    ++ * animations. Additionally,
    ++ * {@link android.graphics.drawable.Animatable2.AnimationCallback#onAnimationEnd(Drawable)} will be
    ++ * called the frame after the AnimatedVectorDrawable finishes on the RenderThread.
    +  * </p>
    +  * <p>
    +- * First is the XML file for {@link android.graphics.drawable.VectorDrawable}.
    +- * Note that we allow the animation to happen on the group's attributes and path's
    +- * attributes, which requires they are uniquely named in this XML file. Groups
    +- * and paths without animations do not need names.
    ++ * AnimatedVectorDrawable can be defined in either <a href="#ThreeXML">three separate XML files</a>,
    ++ * or <a href="#OneXML">one XML</a>.
    +  * </p>
    +- * <li>Here is a simple VectorDrawable in this vectordrawable.xml file.
    ++ * <a name="ThreeXML"></a>
    ++ * <h3>Define an AnimatedVectorDrawable in three separate XML files</h3>
    ++ * <ul>
    ++ * <a name="VDExample"></a>
    ++ * <li><h4>XML for the VectorDrawable containing properties to be animated</h4>
    ++ * <p>
    ++ * Animations can be performed on both group and path attributes, which requires groups and paths to
    ++ * have unique names in the same VectorDrawable. Groups and paths without animations do not need to
    ++ * be named.
    ++ * </p>
    ++ * Below is an example of a VectorDrawable defined in vectordrawable.xml. This VectorDrawable is
    ++ * referred to by its file name (not including file suffix) in the
    ++ * <a href="AVDExample">AnimatedVectorDrawable XML example</a>.
    +  * <pre>
    +  * &lt;vector xmlns:android=&quot;http://schemas.android.com/apk/res/android&quot;
    +  *     android:height=&quot;64dp&quot;
    +@@ -96,17 +113,20 @@ import java.util.ArrayList;
    +  *     &lt;/group&gt;
    +  * &lt;/vector&gt;
    +  * </pre></li>
    ++ *
    ++ * <a name="AVDExample"></a>
    ++ * <li><h4>XML for AnimatedVectorDrawable</h4>
    +  * <p>
    +- * Second is the AnimatedVectorDrawable's XML file, which defines the target
    +- * VectorDrawable, the target paths and groups to animate, the properties of the
    +- * path and group to animate and the animations defined as the ObjectAnimators
    +- * or AnimatorSets.
    ++ * An AnimatedVectorDrawable element has a VectorDrawable attribute, and one or more target
    ++ * element(s). The target elements can be the path or group to be animated. Each target element
    ++ * contains a name attribute that references a property (of a path or a group) to animate, and an
    ++ * animation attribute that points to an ObjectAnimator or an AnimatorSet.
    +  * </p>
    +- * <li>Here is a simple AnimatedVectorDrawable defined in this avd.xml file.
    +- * Note how we use the names to refer to the groups and paths in the vectordrawable.xml.
    ++ * The following code sample defines an AnimatedVectorDrawable. Note that the names refer to the
    ++ * groups and paths in the <a href="#VDExample">VectorDrawable XML above</a>.
    +  * <pre>
    +  * &lt;animated-vector xmlns:android=&quot;http://schemas.android.com/apk/res/android&quot;
    +- *   android:drawable=&quot;@drawable/vectordrawable&quot; &gt;
    ++ *     android:drawable=&quot;@drawable/vectordrawable&quot; &gt;
    +  *     &lt;target
    +  *         android:name=&quot;rotationGroup&quot;
    +  *         android:animation=&quot;@anim/rotation&quot; /&gt;
    +@@ -114,36 +134,89 @@ import java.util.ArrayList;
    +  *         android:name=&quot;v&quot;
    +  *         android:animation=&quot;@anim/path_morph&quot; /&gt;
    +  * &lt;/animated-vector&gt;
    +- * </pre></li>
    ++ * </pre>
    ++ * </li>
    ++ *
    ++ * <li><h4>XML for Animations defined using ObjectAnimator or AnimatorSet</h4>
    +  * <p>
    +- * Last is the Animator XML file, which is the same as a normal ObjectAnimator
    +- * or AnimatorSet.
    +- * To complete this example, here are the 2 animator files used in avd.xml:
    +- * rotation.xml and path_morph.xml.
    ++ * From the previous <a href="#AVDExample">example of AnimatedVectorDrawable</a>, two animations
    ++ * were used: rotation.xml and path_morph.xml.
    +  * </p>
    +- * <li>Here is the rotation.xml, which will rotate the target group for 360 degrees.
    ++ * rotation.xml rotates the target group from 0 degree to 360 degrees over 6000ms:
    +  * <pre>
    +  * &lt;objectAnimator
    +  *     android:duration=&quot;6000&quot;
    +  *     android:propertyName=&quot;rotation&quot;
    +  *     android:valueFrom=&quot;0&quot;
    +  *     android:valueTo=&quot;360&quot; /&gt;
    +- * </pre></li>
    +- * <li>Here is the path_morph.xml, which will morph the path from one shape to
    +- * the other. Note that the paths must be compatible for morphing.
    +- * In more details, the paths should have exact same length of commands , and
    +- * exact same length of parameters for each commands.
    +- * Note that the path strings are better stored in strings.xml for reusing.
    ++ * </pre>
    ++ *
    ++ * path_morph.xml morphs the path from one shape into the other. Note that the paths must be
    ++ * compatible for morphing. Specifically, the paths must have the same commands, in the same order,
    ++ * and must have the same number of parameters for each command. It is recommended to store path
    ++ * strings as string resources for reuse.
    +  * <pre>
    +  * &lt;set xmlns:android=&quot;http://schemas.android.com/apk/res/android&quot;&gt;
    +  *     &lt;objectAnimator
    +  *         android:duration=&quot;3000&quot;
    +  *         android:propertyName=&quot;pathData&quot;
    +- *         android:valueFrom=&quot;M300,70 l 0,-70 70,70 0,0   -70,70z&quot;
    ++ *         android:valueFrom=&quot;M300,70 l 0,-70 70,70 0,0 -70,70z&quot;
    +  *         android:valueTo=&quot;M300,70 l 0,-70 70,0  0,140 -70,0 z&quot;
    +  *         android:valueType=&quot;pathType&quot;/&gt;
    +  * &lt;/set&gt;
    +- * </pre></li>
    ++ * </pre>
    ++ * </ul>
    ++ * <a name="OneXML"></a>
    ++ * <h3>Define an AnimatedVectorDrawable all in one XML file</h3>
    ++ * <p>
    ++ * Since the AAPT tool supports a new format that bundles several related XML files together, we can
    ++ * merge the XML files from the previous examples into one XML file:
    ++ * </p>
    ++ * <pre>
    ++ * &lt;animated-vector xmlns:android=&quot;http://schemas.android.com/apk/res/android&quot; &gt;
    ++ *     &lt;aapt:attr name="android:drawable"&gt;
    ++ *         &lt;vector
    ++ *             android:height=&quot;64dp&quot;
    ++ *             android:width=&quot;64dp&quot;
    ++ *             android:viewportHeight=&quot;600&quot;
    ++ *             android:viewportWidth=&quot;600&quot; &gt;
    ++ *             &lt;group
    ++ *                 android:name=&quot;rotationGroup&quot;
    ++ *                 android:pivotX=&quot;300.0&quot;
    ++ *                 android:pivotY=&quot;300.0&quot;
    ++ *                 android:rotation=&quot;45.0&quot; &gt;
    ++ *                 &lt;path
    ++ *                     android:name=&quot;v&quot;
    ++ *                     android:fillColor=&quot;#000000&quot;
    ++ *                     android:pathData=&quot;M300,70 l 0,-70 70,70 0,0 -70,70z&quot; /&gt;
    ++ *             &lt;/group&gt;
    ++ *         &lt;/vector&gt;
    ++ *     &lt;/aapt:attr&gt;
    ++ *
    ++ *     &lt;target android:name=&quot;rotationGroup&quot;&gt; *
    ++ *         &lt;aapt:attr name="android:animation"&gt;
    ++ *             &lt;objectAnimator
    ++ *             android:duration=&quot;6000&quot;
    ++ *             android:propertyName=&quot;rotation&quot;
    ++ *             android:valueFrom=&quot;0&quot;
    ++ *             android:valueTo=&quot;360&quot; /&gt;
    ++ *         &lt;/aapt:attr&gt;
    ++ *     &lt;/target&gt;
    ++ *
    ++ *     &lt;target android:name=&quot;v&quot; &gt;
    ++ *         &lt;aapt:attr name="android:animation"&gt;
    ++ *             &lt;set&gt;
    ++ *                 &lt;objectAnimator
    ++ *                     android:duration=&quot;3000&quot;
    ++ *                     android:propertyName=&quot;pathData&quot;
    ++ *                     android:valueFrom=&quot;M300,70 l 0,-70 70,70 0,0 -70,70z&quot;
    ++ *                     android:valueTo=&quot;M300,70 l 0,-70 70,0  0,140 -70,0 z&quot;
    ++ *                     android:valueType=&quot;pathType&quot;/&gt;
    ++ *             &lt;/set&gt;
    ++ *         &lt;/aapt:attr&gt;
    ++ *      &lt;/target&gt;
    ++ * &lt;/animated-vector&gt;
    ++ * </pre>
    +  *
    +  * @attr ref android.R.styleable#AnimatedVectorDrawable_drawable
    +  * @attr ref android.R.styleable#AnimatedVectorDrawableTarget_name
    +@@ -237,6 +310,17 @@ public class AnimatedVectorDrawable extends Drawable implements Animatable2 {
    +         return super.getChangingConfigurations() | mAnimatedVectorState.getChangingConfigurations();
    +     }
    + 
    ++    /**
    ++     * Draws the AnimatedVectorDrawable into the given canvas.
    ++     * <p>
    ++     * <strong>Note:</strong> Calling this method with a software canvas when the
    ++     * AnimatedVectorDrawable is being animated on RenderThread (for API 25 and later) may yield
    ++     * outdated result, as the UI thread is not guaranteed to be in sync with RenderThread on
    ++     * VectorDrawable's property changes during RenderThread animations.
    ++     * </p>
    ++     *
    ++     * @param canvas The canvas to draw into
    ++     */
    +     @Override
    +     public void draw(Canvas canvas) {
    +         if (!canvas.isHardwareAccelerated() && mAnimatorSet instanceof VectorDrawableAnimatorRT) {
    +@@ -272,9 +356,9 @@ public class AnimatedVectorDrawable extends Drawable implements Animatable2 {
    +     }
    + 
    +     /**
    +-     * AnimatedVectorDrawable is running on render thread now. Therefore, if the root alpha is being
    +-     * animated, then the root alpha value we get from this call could be out of sync with alpha
    +-     * value used in the render thread. Otherwise, the root alpha should be always the same value.
    ++     * For API 25 and later, AnimatedVectorDrawable runs on RenderThread. Therefore, when the
    ++     * root alpha is being animated, this getter does not guarantee to return an up-to-date alpha
    ++     * value.
    +      *
    +      * @return the containing vector drawable's root alpha value.
    +      */
    +@@ -371,7 +455,11 @@ public class AnimatedVectorDrawable extends Drawable implements Animatable2 {
    + 
    +         int eventType = parser.getEventType();
    +         float pathErrorScale = 1;
    +-        while (eventType != XmlPullParser.END_DOCUMENT) {
    ++        final int innerDepth = parser.getDepth() + 1;
    ++
    ++        // Parse everything until the end of the animated-vector element.
    ++        while (eventType != XmlPullParser.END_DOCUMENT
    ++                && (parser.getDepth() >= innerDepth || eventType != XmlPullParser.END_TAG)) {
    +             if (eventType == XmlPullParser.START_TAG) {
    +                 final String tagName = parser.getName();
    +                 if (ANIMATED_VECTOR.equals(tagName)) {
    +@@ -1446,7 +1534,6 @@ public class AnimatedVectorDrawable extends Drawable implements Animatable2 {
    +             } else {
    +                 addPendingAction(START_ANIMATION);
    +             }
    +-
    +         }
    + 
    +         @Override
    +diff --git a/graphics/java/android/graphics/drawable/BitmapDrawable.java b/graphics/java/android/graphics/drawable/BitmapDrawable.java
    +index 9d8ede0..df107f5 100644
    +--- a/graphics/java/android/graphics/drawable/BitmapDrawable.java
    ++++ b/graphics/java/android/graphics/drawable/BitmapDrawable.java
    +@@ -463,31 +463,14 @@ public class BitmapDrawable extends Drawable {
    +         return isAutoMirrored() && getLayoutDirection() == LayoutDirection.RTL;
    +     }
    + 
    +-    private void updateMirrorMatrix(float dx) {
    +-        if (mMirrorMatrix == null) {
    +-            mMirrorMatrix = new Matrix();
    +-        }
    +-        mMirrorMatrix.setTranslate(dx, 0);
    +-        mMirrorMatrix.preScale(-1.0f, 1.0f);
    +-    }
    +-
    +     @Override
    +     protected void onBoundsChange(Rect bounds) {
    +         mDstRectAndInsetsDirty = true;
    + 
    ++        final Bitmap bitmap = mBitmapState.mBitmap;
    +         final Shader shader = mBitmapState.mPaint.getShader();
    +-        if (shader != null) {
    +-            if (needMirroring()) {
    +-                updateMirrorMatrix(bounds.right - bounds.left);
    +-                shader.setLocalMatrix(mMirrorMatrix);
    +-                mBitmapState.mPaint.setShader(shader);
    +-            } else {
    +-                if (mMirrorMatrix != null) {
    +-                    mMirrorMatrix = null;
    +-                    shader.setLocalMatrix(Matrix.IDENTITY_MATRIX);
    +-                    mBitmapState.mPaint.setShader(shader);
    +-                }
    +-            }
    ++        if (bitmap != null && shader != null) {
    ++            updateShaderMatrix(bitmap, mBitmapState.mPaint, shader, needMirroring());
    +         }
    +     }
    + 
    +@@ -548,19 +531,7 @@ public class BitmapDrawable extends Drawable {
    +                 canvas.restore();
    +             }
    +         } else {
    +-            if (needMirroring) {
    +-                // Mirror the bitmap
    +-                updateMirrorMatrix(mDstRect.right - mDstRect.left);
    +-                shader.setLocalMatrix(mMirrorMatrix);
    +-                paint.setShader(shader);
    +-            } else {
    +-                if (mMirrorMatrix != null) {
    +-                    mMirrorMatrix = null;
    +-                    shader.setLocalMatrix(Matrix.IDENTITY_MATRIX);
    +-                    paint.setShader(shader);
    +-                }
    +-            }
    +-
    ++            updateShaderMatrix(bitmap, paint, shader, needMirroring);
    +             canvas.drawRect(mDstRect, paint);
    +         }
    + 
    +@@ -573,6 +544,51 @@ public class BitmapDrawable extends Drawable {
    +         }
    +     }
    + 
    ++    /**
    ++     * Updates the {@code paint}'s shader matrix to be consistent with the
    ++     * destination size and layout direction.
    ++     *
    ++     * @param bitmap the bitmap to be drawn
    ++     * @param paint the paint used to draw the bitmap
    ++     * @param shader the shader to set on the paint
    ++     * @param needMirroring whether the bitmap should be mirrored
    ++     */
    ++    private void updateShaderMatrix(@NonNull Bitmap bitmap, @NonNull Paint paint,
    ++            @NonNull Shader shader, boolean needMirroring) {
    ++        final int sourceDensity = bitmap.getDensity();
    ++        final int targetDensity = mTargetDensity;
    ++        final boolean needScaling = sourceDensity != 0 && sourceDensity != targetDensity;
    ++        if (needScaling || needMirroring) {
    ++            final Matrix matrix = getOrCreateMirrorMatrix();
    ++            matrix.reset();
    ++
    ++            if (needMirroring) {
    ++                final int dx = mDstRect.right - mDstRect.left;
    ++                matrix.setTranslate(dx, 0);
    ++                matrix.setScale(-1, 1);
    ++            }
    ++
    ++            if (needScaling) {
    ++                final float densityScale = targetDensity / (float) sourceDensity;
    ++                matrix.postScale(densityScale, densityScale);
    ++            }
    ++
    ++            shader.setLocalMatrix(matrix);
    ++        } else {
    ++            mMirrorMatrix = null;
    ++            shader.setLocalMatrix(Matrix.IDENTITY_MATRIX);
    ++        }
    ++
    ++        paint.setShader(shader);
    ++    }
    ++
    ++    private Matrix getOrCreateMirrorMatrix() {
    ++        if (mMirrorMatrix == null) {
    ++            mMirrorMatrix = new Matrix();
    ++        }
    ++        return mMirrorMatrix;
    ++    }
    ++
    +     private void updateDstRectAndInsetsIfDirty() {
    +         if (mDstRectAndInsetsDirty) {
    +             if (mBitmapState.mTileModeX == null && mBitmapState.mTileModeY == null) {
    +diff --git a/graphics/java/android/graphics/drawable/Drawable.java b/graphics/java/android/graphics/drawable/Drawable.java
    +index 7f3a437..c2e302e 100644
    +--- a/graphics/java/android/graphics/drawable/Drawable.java
    ++++ b/graphics/java/android/graphics/drawable/Drawable.java
    +@@ -109,6 +109,9 @@ import java.util.Collection;
    +  *     <li> <b>Nine Patch</b>: an extension to the PNG format allows it to
    +  *     specify information about how to stretch it and place things inside of
    +  *     it.
    ++ *     <li><b>Vector</b>: a drawable defined in an XML file as a set of points,
    ++ *     lines, and curves along with its associated color information. This type
    ++ *     of drawable can be scaled without loss of display quality.
    +  *     <li> <b>Shape</b>: contains simple drawing commands instead of a raw
    +  *     bitmap, allowing it to resize better in some cases.
    +  *     <li> <b>Layers</b>: a compound drawable, which draws multiple underlying
    +@@ -1422,9 +1425,10 @@ public abstract class Drawable {
    +     /**
    +      * Obtains styled attributes from the theme, if available, or unstyled
    +      * resources if the theme is null.
    ++     * @hide
    +      */
    +-    static @NonNull TypedArray obtainAttributes(@NonNull Resources res, @Nullable Theme theme,
    +-            @NonNull AttributeSet set, @NonNull int[] attrs) {
    ++    protected static @NonNull TypedArray obtainAttributes(@NonNull Resources res,
    ++            @Nullable Theme theme, @NonNull AttributeSet set, @NonNull int[] attrs) {
    +         if (theme == null) {
    +             return res.obtainAttributes(set, attrs);
    +         }
    +diff --git a/graphics/java/android/graphics/drawable/DrawableContainer.java b/graphics/java/android/graphics/drawable/DrawableContainer.java
    +index cc7f5c7..c7a3c75 100644
    +--- a/graphics/java/android/graphics/drawable/DrawableContainer.java
    ++++ b/graphics/java/android/graphics/drawable/DrawableContainer.java
    +@@ -27,8 +27,8 @@ import android.graphics.ColorFilter;
    + import android.graphics.Insets;
    + import android.graphics.Outline;
    + import android.graphics.PixelFormat;
    +-import android.graphics.Rect;
    + import android.graphics.PorterDuff.Mode;
    ++import android.graphics.Rect;
    + import android.os.SystemClock;
    + import android.util.DisplayMetrics;
    + import android.util.LayoutDirection;
    +@@ -601,8 +601,9 @@ public class DrawableContainer extends Drawable implements Drawable.Callback {
    +      * during inflation.
    +      *
    +      * @param res the resources used to inflate density-dependent values
    ++     * @hide
    +      */
    +-    final void updateDensity(Resources res) {
    ++    protected final void updateDensity(Resources res) {
    +         mDrawableContainerState.updateDensity(res);
    +     }
    + 
    +@@ -711,7 +712,10 @@ public class DrawableContainer extends Drawable implements Drawable.Callback {
    +         boolean mHasTintList;
    +         boolean mHasTintMode;
    + 
    +-        DrawableContainerState(DrawableContainerState orig, DrawableContainer owner,
    ++        /**
    ++         * @hide
    ++         */
    ++        protected DrawableContainerState(DrawableContainerState orig, DrawableContainer owner,
    +                 Resources res) {
    +             mOwner = owner;
    +             mSourceRes = res != null ? res : (orig != null ? orig.mSourceRes : null);
    +diff --git a/graphics/java/android/graphics/drawable/GradientDrawable.java b/graphics/java/android/graphics/drawable/GradientDrawable.java
    +index 3dbd2a9..8c633b0 100644
    +--- a/graphics/java/android/graphics/drawable/GradientDrawable.java
    ++++ b/graphics/java/android/graphics/drawable/GradientDrawable.java
    +@@ -475,16 +475,17 @@ public class GradientDrawable extends Drawable {
    +     }
    + 
    +     /**
    +-     * Sets the center location in pixels of the gradient. The radius is
    +-     * honored only when the gradient type is set to {@link #RADIAL_GRADIENT}
    +-     * or {@link #SWEEP_GRADIENT}.
    ++     * Sets the position of the center of the gradient as a fraction of the
    ++     * width and height.
    ++     * <p>
    ++     * The default value is (0.5, 0.5).
    +      * <p>
    +      * <strong>Note</strong>: changing this property will affect all instances
    +      * of a drawable loaded from a resource. It is recommended to invoke
    +      * {@link #mutate()} before changing this property.
    +      *
    +-     * @param x the x coordinate of the gradient's center in pixels
    +-     * @param y the y coordinate of the gradient's center in pixels
    ++     * @param x the X-position of the center of the gradient
    ++     * @param y the Y-position of the center of the gradient
    +      *
    +      * @see #mutate()
    +      * @see #setGradientType(int)
    +@@ -498,9 +499,10 @@ public class GradientDrawable extends Drawable {
    +     }
    + 
    +     /**
    +-     * Returns the center X location of this gradient in pixels.
    ++     * Returns the X-position of the center of the gradient as a fraction of
    ++     * the width.
    +      *
    +-     * @return the center X location of this gradient in pixels
    ++     * @return the X-position of the center of the gradient
    +      * @see #setGradientCenter(float, float)
    +      */
    +     public float getGradientCenterX() {
    +@@ -508,9 +510,10 @@ public class GradientDrawable extends Drawable {
    +     }
    + 
    +     /**
    +-     * Returns the center Y location of this gradient in pixels.
    ++     * Returns the Y-position of the center of this gradient as a fraction of
    ++     * the height.
    +      *
    +-     * @return the center Y location of this gradient in pixels
    ++     * @return the Y-position of the center of the gradient
    +      * @see #setGradientCenter(float, float)
    +      */
    +     public float getGradientCenterY() {
    +@@ -554,19 +557,43 @@ public class GradientDrawable extends Drawable {
    +     }
    + 
    +     /**
    +-     * Sets whether or not this drawable will honor its {@code level} property.
    ++     * Sets whether this drawable's {@code level} property will be used to
    ++     * scale the gradient. If a gradient is not used, this property has no
    ++     * effect.
    +      * <p>
    +-     * <strong>Note</strong>: changing this property will affect all instances
    ++     * Scaling behavior varies based on gradient type:
    ++     * <ul>
    ++     *     <li>{@link #LINEAR_GRADIENT} adjusts the ending position along the
    ++     *         gradient's axis of orientation (see {@link #getOrientation()})
    ++     *     <li>{@link #RADIAL_GRADIENT} adjusts the outer radius
    ++     *     <li>{@link #SWEEP_GRADIENT} adjusts the ending angle
    ++     * <ul>
    ++     * <p>
    ++     * The default value for this property is {@code false}.
    ++     * <p>
    ++     * <strong>Note</strong>: This property corresponds to the
    ++     * {@code android:useLevel} attribute on the inner {@code &lt;gradient&gt;}
    ++     * tag, NOT the {@code android:useLevel} attribute on the outer
    ++     * {@code &lt;shape&gt;} tag. For example,
    ++     * <pre>{@code
    ++     * <shape ...>
    ++     *     <gradient
    ++     *         ...
    ++     *         android:useLevel="true" />
    ++     * </shape>
    ++     * }</pre><p>
    ++     * <strong>Note</strong>: Changing this property will affect all instances
    +      * of a drawable loaded from a resource. It is recommended to invoke
    +      * {@link #mutate()} before changing this property.
    +      *
    +-     * @param useLevel {@code true} if this drawable should honor its level,
    +-     *                 {@code false} otherwise
    ++     * @param useLevel {@code true} if the gradient should be scaled based on
    ++     *                 level, {@code false} otherwise
    +      *
    +      * @see #mutate()
    +      * @see #setLevel(int)
    +      * @see #getLevel()
    +      * @see #getUseLevel()
    ++     * @attr ref android.R.styleable#GradientDrawableGradient_useLevel
    +      */
    +     public void setUseLevel(boolean useLevel) {
    +         mGradientState.mUseLevel = useLevel;
    +@@ -575,12 +602,13 @@ public class GradientDrawable extends Drawable {
    +     }
    + 
    +     /**
    +-     * Returns whether or not this drawable will honor its {@code level}
    +-     * property.
    ++     * Returns whether this drawable's {@code level} property will be used to
    ++     * scale the gradient.
    +      *
    +-     * @return {@code true} if this drawable should honor its level,
    ++     * @return {@code true} if the gradient should be scaled based on level,
    +      *         {@code false} otherwise
    +      * @see #setUseLevel(boolean)
    ++     * @attr ref android.R.styleable#GradientDrawableGradient_useLevel
    +      */
    +     public boolean getUseLevel() {
    +         return mGradientState.mUseLevel;
    +diff --git a/graphics/java/android/graphics/drawable/LayerDrawable.java b/graphics/java/android/graphics/drawable/LayerDrawable.java
    +index 1864206..c30c4c2 100644
    +--- a/graphics/java/android/graphics/drawable/LayerDrawable.java
    ++++ b/graphics/java/android/graphics/drawable/LayerDrawable.java
    +@@ -269,7 +269,8 @@ public class LayerDrawable extends Drawable implements Drawable.Callback {
    + 
    +             // If the layer doesn't have a drawable or unresolved theme
    +             // attribute for a drawable, attempt to parse one from the child
    +-            // element.
    ++            // element. If multiple child elements exist, we'll only use the
    ++            // first one.
    +             if (layer.mDrawable == null && (layer.mThemeAttrs == null ||
    +                     layer.mThemeAttrs[R.styleable.LayerDrawableItem_drawable] == 0)) {
    +                 while ((type = parser.next()) == XmlPullParser.TEXT) {
    +@@ -279,13 +280,12 @@ public class LayerDrawable extends Drawable implements Drawable.Callback {
    +                             + ": <item> tag requires a 'drawable' attribute or "
    +                             + "child tag defining a drawable");
    +                 }
    +-                layer.mDrawable = Drawable.createFromXmlInner(r, parser, attrs, theme);
    +-            }
    + 
    +-            if (layer.mDrawable != null) {
    ++                // We found a child drawable. Take ownership.
    ++                layer.mDrawable = Drawable.createFromXmlInner(r, parser, attrs, theme);
    ++                layer.mDrawable.setCallback(this);
    +                 state.mChildrenChangingConfigurations |=
    +                         layer.mDrawable.getChangingConfigurations();
    +-                layer.mDrawable.setCallback(this);
    +             }
    + 
    +             addLayer(layer);
    +@@ -387,7 +387,19 @@ public class LayerDrawable extends Drawable implements Drawable.Callback {
    + 
    +         final Drawable dr = a.getDrawable(R.styleable.LayerDrawableItem_drawable);
    +         if (dr != null) {
    ++            if (layer.mDrawable != null) {
    ++                // It's possible that a drawable was already set, in which case
    ++                // we should clear the callback. We may have also integrated the
    ++                // drawable's changing configurations, but we don't have enough
    ++                // information to revert that change.
    ++                layer.mDrawable.setCallback(null);
    ++            }
    ++
    ++            // Take ownership of the new drawable.
    +             layer.mDrawable = dr;
    ++            layer.mDrawable.setCallback(this);
    ++            state.mChildrenChangingConfigurations |=
    ++                    layer.mDrawable.getChangingConfigurations();
    +         }
    +     }
    + 
    +diff --git a/graphics/java/android/graphics/drawable/VectorDrawable.java b/graphics/java/android/graphics/drawable/VectorDrawable.java
    +index dc1d18f..1ca1552 100644
    +--- a/graphics/java/android/graphics/drawable/VectorDrawable.java
    ++++ b/graphics/java/android/graphics/drawable/VectorDrawable.java
    +@@ -27,9 +27,9 @@ import android.graphics.Canvas;
    + import android.graphics.ColorFilter;
    + import android.graphics.Insets;
    + import android.graphics.PixelFormat;
    ++import android.graphics.PorterDuff.Mode;
    + import android.graphics.PorterDuffColorFilter;
    + import android.graphics.Rect;
    +-import android.graphics.PorterDuff.Mode;
    + import android.graphics.Shader;
    + import android.util.ArrayMap;
    + import android.util.AttributeSet;
    +@@ -76,27 +76,36 @@ import dalvik.system.VMRuntime;
    +  * <dl>
    +  * <dt><code>android:name</code></dt>
    +  * <dd>Defines the name of this vector drawable.</dd>
    ++ * <dd>Animatable : No.</dd>
    +  * <dt><code>android:width</code></dt>
    +  * <dd>Used to define the intrinsic width of the drawable.
    +  * This support all the dimension units, normally specified with dp.</dd>
    ++ * <dd>Animatable : No.</dd>
    +  * <dt><code>android:height</code></dt>
    +  * <dd>Used to define the intrinsic height the drawable.
    +  * This support all the dimension units, normally specified with dp.</dd>
    ++ * <dd>Animatable : No.</dd>
    +  * <dt><code>android:viewportWidth</code></dt>
    +  * <dd>Used to define the width of the viewport space. Viewport is basically
    +  * the virtual canvas where the paths are drawn on.</dd>
    ++ * <dd>Animatable : No.</dd>
    +  * <dt><code>android:viewportHeight</code></dt>
    +  * <dd>Used to define the height of the viewport space. Viewport is basically
    +  * the virtual canvas where the paths are drawn on.</dd>
    ++ * <dd>Animatable : No.</dd>
    +  * <dt><code>android:tint</code></dt>
    +  * <dd>The color to apply to the drawable as a tint. By default, no tint is applied.</dd>
    ++ * <dd>Animatable : No.</dd>
    +  * <dt><code>android:tintMode</code></dt>
    +  * <dd>The Porter-Duff blending mode for the tint color. The default value is src_in.</dd>
    ++ * <dd>Animatable : No.</dd>
    +  * <dt><code>android:autoMirrored</code></dt>
    +  * <dd>Indicates if the drawable needs to be mirrored when its layout direction is
    +  * RTL (right-to-left).</dd>
    ++ * <dd>Animatable : No.</dd>
    +  * <dt><code>android:alpha</code></dt>
    +  * <dd>The opacity of this drawable.</dd>
    ++ * <dd>Animatable : Yes.</dd>
    +  * </dl></dd>
    +  * </dl>
    +  *
    +@@ -108,24 +117,32 @@ import dalvik.system.VMRuntime;
    +  * <dl>
    +  * <dt><code>android:name</code></dt>
    +  * <dd>Defines the name of the group.</dd>
    ++ * <dd>Animatable : No.</dd>
    +  * <dt><code>android:rotation</code></dt>
    +  * <dd>The degrees of rotation of the group.</dd>
    ++ * <dd>Animatable : Yes.</dd>
    +  * <dt><code>android:pivotX</code></dt>
    +  * <dd>The X coordinate of the pivot for the scale and rotation of the group.
    +  * This is defined in the viewport space.</dd>
    ++ * <dd>Animatable : Yes.</dd>
    +  * <dt><code>android:pivotY</code></dt>
    +  * <dd>The Y coordinate of the pivot for the scale and rotation of the group.
    +  * This is defined in the viewport space.</dd>
    ++ * <dd>Animatable : Yes.</dd>
    +  * <dt><code>android:scaleX</code></dt>
    +  * <dd>The amount of scale on the X Coordinate.</dd>
    ++ * <dd>Animatable : Yes.</dd>
    +  * <dt><code>android:scaleY</code></dt>
    +  * <dd>The amount of scale on the Y coordinate.</dd>
    ++ * <dd>Animatable : Yes.</dd>
    +  * <dt><code>android:translateX</code></dt>
    +  * <dd>The amount of translation on the X coordinate.
    +  * This is defined in the viewport space.</dd>
    ++ * <dd>Animatable : Yes.</dd>
    +  * <dt><code>android:translateY</code></dt>
    +  * <dd>The amount of translation on the Y coordinate.
    +  * This is defined in the viewport space.</dd>
    ++ * <dd>Animatable : Yes.</dd>
    +  * </dl></dd>
    +  * </dl>
    +  *
    +@@ -135,40 +152,60 @@ import dalvik.system.VMRuntime;
    +  * <dl>
    +  * <dt><code>android:name</code></dt>
    +  * <dd>Defines the name of the path.</dd>
    ++ * <dd>Animatable : No.</dd>
    +  * <dt><code>android:pathData</code></dt>
    +  * <dd>Defines path data using exactly same format as "d" attribute
    +  * in the SVG's path data. This is defined in the viewport space.</dd>
    ++ * <dd>Animatable : Yes.</dd>
    +  * <dt><code>android:fillColor</code></dt>
    +  * <dd>Specifies the color used to fill the path. May be a color or, for SDK 24+, a color state list
    +- * or a gradient color. If this property is animated, any value set by the animation will
    +- * override the original value. No path fill is drawn if this property is not specified.</dd>
    ++ * or a gradient color (See {@link android.R.styleable#GradientColor}
    ++ * and {@link android.R.styleable#GradientColorItem}).
    ++ * If this property is animated, any value set by the animation will override the original value.
    ++ * No path fill is drawn if this property is not specified.</dd>
    ++ * <dd>Animatable : Yes.</dd>
    +  * <dt><code>android:strokeColor</code></dt>
    +  * <dd>Specifies the color used to draw the path outline. May be a color or, for SDK 24+, a color
    +- * state list or a gradient color. If this property is animated, any value set by the animation will
    +- * override the original value. No path outline is drawn if this property is not specified.</dd>
    ++ * state list or a gradient color (See {@link android.R.styleable#GradientColor}
    ++ * and {@link android.R.styleable#GradientColorItem}).
    ++ * If this property is animated, any value set by the animation will override the original value.
    ++ * No path outline is drawn if this property is not specified.</dd>
    ++ * <dd>Animatable : Yes.</dd>
    +  * <dt><code>android:strokeWidth</code></dt>
    +  * <dd>The width a path stroke.</dd>
    ++ * <dd>Animatable : Yes.</dd>
    +  * <dt><code>android:strokeAlpha</code></dt>
    +  * <dd>The opacity of a path stroke.</dd>
    ++ * <dd>Animatable : Yes.</dd>
    +  * <dt><code>android:fillAlpha</code></dt>
    +  * <dd>The opacity to fill the path with.</dd>
    ++ * <dd>Animatable : Yes.</dd>
    +  * <dt><code>android:trimPathStart</code></dt>
    +  * <dd>The fraction of the path to trim from the start, in the range from 0 to 1.</dd>
    ++ * <dd>Animatable : Yes.</dd>
    +  * <dt><code>android:trimPathEnd</code></dt>
    +  * <dd>The fraction of the path to trim from the end, in the range from 0 to 1.</dd>
    ++ * <dd>Animatable : Yes.</dd>
    +  * <dt><code>android:trimPathOffset</code></dt>
    +  * <dd>Shift trim region (allows showed region to include the start and end), in the range
    +  * from 0 to 1.</dd>
    ++ * <dd>Animatable : Yes.</dd>
    +  * <dt><code>android:strokeLineCap</code></dt>
    +  * <dd>Sets the linecap for a stroked path: butt, round, square.</dd>
    ++ * <dd>Animatable : No.</dd>
    +  * <dt><code>android:strokeLineJoin</code></dt>
    +  * <dd>Sets the lineJoin for a stroked path: miter,round,bevel.</dd>
    ++ * <dd>Animatable : No.</dd>
    +  * <dt><code>android:strokeMiterLimit</code></dt>
    +  * <dd>Sets the Miter limit for a stroked path.</dd>
    ++ * <dd>Animatable : No.</dd>
    +  * <dt><code>android:fillType</code></dt>
    +- * <dd>Sets the fillType for a path. It is the same as SVG's "fill-rule" properties.
    +- * For more details, see https://www.w3.org/TR/SVG/painting.html#FillRuleProperty</dd>
    ++ * <dd>Sets the fillType for a path. The types can be either "evenOdd" or "nonZero". They behave the
    ++ * same as SVG's "fill-rule" properties. For more details, see
    ++ * <a href="https://www.w3.org/TR/SVG/painting.html#FillRuleProperty">FillRuleProperty</a></dd>
    ++ * <dd>Animatable : No.</dd>
    +  * </dl></dd>
    ++ *
    +  * </dl>
    +  *
    +  * <dl>
    +@@ -178,9 +215,11 @@ import dalvik.system.VMRuntime;
    +  * <dl>
    +  * <dt><code>android:name</code></dt>
    +  * <dd>Defines the name of the clip path.</dd>
    ++ * <dd>Animatable : No.</dd>
    +  * <dt><code>android:pathData</code></dt>
    +  * <dd>Defines clip path using the same format as "d" attribute
    +  * in the SVG's path data.</dd>
    ++ * <dd>Animatable : Yes.</dd>
    +  * </dl></dd>
    +  * </dl>
    +  * <li>Here is a simple VectorDrawable in this vectordrawable.xml file.
    +@@ -201,7 +240,26 @@ import dalvik.system.VMRuntime;
    +  *             android:pathData=&quot;M300,70 l 0,-70 70,70 0,0 -70,70z&quot; /&gt;
    +  *     &lt;/group&gt;
    +  * &lt;/vector&gt;
    +- * </pre></li>
    ++ * </pre>
    ++ * </li>
    ++ * <li>And here is an example of linear gradient color, which is supported in SDK 24+.
    ++ * See more details in {@link android.R.styleable#GradientColor} and
    ++ * {@link android.R.styleable#GradientColorItem}.
    ++ * <pre>
    ++ * &lt;gradient xmlns:android="http://schemas.android.com/apk/res/android"
    ++ *     android:angle="90"
    ++ *     android:startColor="?android:attr/colorPrimary"
    ++ *     android:endColor="?android:attr/colorControlActivated"
    ++ *     android:centerColor="#f00"
    ++ *     android:startX="0"
    ++ *     android:startY="0"
    ++ *     android:endX="100"
    ++ *     android:endY="100"
    ++ *     android:type="linear"&gt;
    ++ * &lt;/gradient&gt;
    ++ * </pre>
    ++ * </li>
    ++ *
    +  */
    + 
    + public class VectorDrawable extends Drawable {
    +@@ -686,7 +744,11 @@ public class VectorDrawable extends Drawable {
    +         groupStack.push(state.mRootGroup);
    + 
    +         int eventType = parser.getEventType();
    +-        while (eventType != XmlPullParser.END_DOCUMENT) {
    ++        final int innerDepth = parser.getDepth() + 1;
    ++
    ++        // Parse everything until the end of the vector element.
    ++        while (eventType != XmlPullParser.END_DOCUMENT
    ++                && (parser.getDepth() >= innerDepth || eventType != XmlPullParser.END_TAG)) {
    +             if (eventType == XmlPullParser.START_TAG) {
    +                 final String tagName = parser.getName();
    +                 final VGroup currentGroup = groupStack.peek();
    +diff --git a/graphics/java/android/graphics/pdf/PdfEditor.java b/graphics/java/android/graphics/pdf/PdfEditor.java
    +index 2b70b6a..cd1f8de 100644
    +--- a/graphics/java/android/graphics/pdf/PdfEditor.java
    ++++ b/graphics/java/android/graphics/pdf/PdfEditor.java
    +@@ -79,8 +79,12 @@ public final class PdfEditor {
    +         }
    + 
    +         mInput = input;
    +-        mNativeDocument = nativeOpen(mInput.getFd(), size);
    +-        mPageCount = nativeGetPageCount(mNativeDocument);
    ++
    ++        synchronized (PdfRenderer.sPdfiumLock) {
    ++            mNativeDocument = nativeOpen(mInput.getFd(), size);
    ++            mPageCount = nativeGetPageCount(mNativeDocument);
    ++        }
    ++
    +         mCloseGuard.open("close");
    +     }
    + 
    +@@ -102,7 +106,10 @@ public final class PdfEditor {
    +     public void removePage(int pageIndex) {
    +         throwIfClosed();
    +         throwIfPageNotInDocument(pageIndex);
    +-        mPageCount = nativeRemovePage(mNativeDocument, pageIndex);
    ++
    ++        synchronized (PdfRenderer.sPdfiumLock) {
    ++            mPageCount = nativeRemovePage(mNativeDocument, pageIndex);
    ++        }
    +     }
    + 
    +     /**
    +@@ -125,11 +132,16 @@ public final class PdfEditor {
    +         if (clip == null) {
    +             Point size = new Point();
    +             getPageSize(pageIndex, size);
    +-            nativeSetTransformAndClip(mNativeDocument, pageIndex, transform.native_instance,
    +-                    0, 0, size.x, size.y);
    ++
    ++            synchronized (PdfRenderer.sPdfiumLock) {
    ++                nativeSetTransformAndClip(mNativeDocument, pageIndex, transform.native_instance,
    ++                        0, 0, size.x, size.y);
    ++            }
    +         } else {
    +-            nativeSetTransformAndClip(mNativeDocument, pageIndex, transform.native_instance,
    +-                    clip.left, clip.top, clip.right, clip.bottom);
    ++            synchronized (PdfRenderer.sPdfiumLock) {
    ++                nativeSetTransformAndClip(mNativeDocument, pageIndex, transform.native_instance,
    ++                        clip.left, clip.top, clip.right, clip.bottom);
    ++            }
    +         }
    +     }
    + 
    +@@ -143,7 +155,10 @@ public final class PdfEditor {
    +         throwIfClosed();
    +         throwIfOutSizeNull(outSize);
    +         throwIfPageNotInDocument(pageIndex);
    +-        nativeGetPageSize(mNativeDocument, pageIndex, outSize);
    ++
    ++        synchronized (PdfRenderer.sPdfiumLock) {
    ++            nativeGetPageSize(mNativeDocument, pageIndex, outSize);
    ++        }
    +     }
    + 
    +     /**
    +@@ -156,7 +171,10 @@ public final class PdfEditor {
    +         throwIfClosed();
    +         throwIfOutMediaBoxNull(outMediaBox);
    +         throwIfPageNotInDocument(pageIndex);
    +-        return nativeGetPageMediaBox(mNativeDocument, pageIndex, outMediaBox);
    ++
    ++        synchronized (PdfRenderer.sPdfiumLock) {
    ++            return nativeGetPageMediaBox(mNativeDocument, pageIndex, outMediaBox);
    ++        }
    +     }
    + 
    +     /**
    +@@ -169,7 +187,10 @@ public final class PdfEditor {
    +         throwIfClosed();
    +         throwIfMediaBoxNull(mediaBox);
    +         throwIfPageNotInDocument(pageIndex);
    +-        nativeSetPageMediaBox(mNativeDocument, pageIndex, mediaBox);
    ++
    ++        synchronized (PdfRenderer.sPdfiumLock) {
    ++            nativeSetPageMediaBox(mNativeDocument, pageIndex, mediaBox);
    ++        }
    +     }
    + 
    +     /**
    +@@ -182,7 +203,10 @@ public final class PdfEditor {
    +         throwIfClosed();
    +         throwIfOutCropBoxNull(outCropBox);
    +         throwIfPageNotInDocument(pageIndex);
    +-        return nativeGetPageCropBox(mNativeDocument, pageIndex, outCropBox);
    ++
    ++        synchronized (PdfRenderer.sPdfiumLock) {
    ++            return nativeGetPageCropBox(mNativeDocument, pageIndex, outCropBox);
    ++        }
    +     }
    + 
    +     /**
    +@@ -195,7 +219,10 @@ public final class PdfEditor {
    +         throwIfClosed();
    +         throwIfCropBoxNull(cropBox);
    +         throwIfPageNotInDocument(pageIndex);
    +-        nativeSetPageCropBox(mNativeDocument, pageIndex, cropBox);
    ++
    ++        synchronized (PdfRenderer.sPdfiumLock) {
    ++            nativeSetPageCropBox(mNativeDocument, pageIndex, cropBox);
    ++        }
    +     }
    + 
    +     /**
    +@@ -205,7 +232,10 @@ public final class PdfEditor {
    +      */
    +     public boolean shouldScaleForPrinting() {
    +         throwIfClosed();
    +-        return nativeScaleForPrinting(mNativeDocument);
    ++
    ++        synchronized (PdfRenderer.sPdfiumLock) {
    ++            return nativeScaleForPrinting(mNativeDocument);
    ++        }
    +     }
    + 
    +     /**
    +@@ -219,7 +249,10 @@ public final class PdfEditor {
    +     public void write(ParcelFileDescriptor output) throws IOException {
    +         try {
    +             throwIfClosed();
    +-            nativeWrite(mNativeDocument, output.getFd());
    ++
    ++            synchronized (PdfRenderer.sPdfiumLock) {
    ++                nativeWrite(mNativeDocument, output.getFd());
    ++            }
    +         } finally {
    +             IoUtils.closeQuietly(output);
    +         }
    +@@ -247,7 +280,9 @@ public final class PdfEditor {
    +     }
    + 
    +     private void doClose() {
    +-        nativeClose(mNativeDocument);
    ++        synchronized (PdfRenderer.sPdfiumLock) {
    ++            nativeClose(mNativeDocument);
    ++        }
    +         IoUtils.closeQuietly(mInput);
    +         mInput = null;
    +         mCloseGuard.close();
    +diff --git a/graphics/java/android/graphics/pdf/PdfRenderer.java b/graphics/java/android/graphics/pdf/PdfRenderer.java
    +index 520ebe5..cfc1309 100644
    +--- a/graphics/java/android/graphics/pdf/PdfRenderer.java
    ++++ b/graphics/java/android/graphics/pdf/PdfRenderer.java
    +@@ -99,6 +99,12 @@ import java.lang.annotation.RetentionPolicy;
    +  * @see #close()
    +  */
    + public final class PdfRenderer implements AutoCloseable {
    ++    /**
    ++     * Any call the native pdfium code has to be single threaded as the library does not support
    ++     * parallel use.
    ++     */
    ++    final static Object sPdfiumLock = new Object();
    ++
    +     private final CloseGuard mCloseGuard = CloseGuard.get();
    + 
    +     private final Point mTempPoint = new Point();
    +@@ -154,8 +160,12 @@ public final class PdfRenderer implements AutoCloseable {
    +         }
    + 
    +         mInput = input;
    +-        mNativeDocument = nativeCreate(mInput.getFd(), size);
    +-        mPageCount = nativeGetPageCount(mNativeDocument);
    ++
    ++        synchronized (sPdfiumLock) {
    ++            mNativeDocument = nativeCreate(mInput.getFd(), size);
    ++            mPageCount = nativeGetPageCount(mNativeDocument);
    ++        }
    ++
    +         mCloseGuard.open("close");
    +     }
    + 
    +@@ -189,7 +199,10 @@ public final class PdfRenderer implements AutoCloseable {
    +      */
    +     public boolean shouldScaleForPrinting() {
    +         throwIfClosed();
    +-        return nativeScaleForPrinting(mNativeDocument);
    ++
    ++        synchronized (sPdfiumLock) {
    ++            return nativeScaleForPrinting(mNativeDocument);
    ++        }
    +     }
    + 
    +     /**
    +@@ -224,7 +237,9 @@ public final class PdfRenderer implements AutoCloseable {
    +         if (mCurrentPage != null) {
    +             mCurrentPage.close();
    +         }
    +-        nativeClose(mNativeDocument);
    ++        synchronized (sPdfiumLock) {
    ++            nativeClose(mNativeDocument);
    ++        }
    +         try {
    +             mInput.close();
    +         } catch (IOException ioe) {
    +@@ -277,7 +292,9 @@ public final class PdfRenderer implements AutoCloseable {
    + 
    +         private Page(int index) {
    +             Point size = mTempPoint;
    +-            mNativePage = nativeOpenPageAndGetSize(mNativeDocument, index, size);
    ++            synchronized (sPdfiumLock) {
    ++                mNativePage = nativeOpenPageAndGetSize(mNativeDocument, index, size);
    ++            }
    +             mIndex = index;
    +             mWidth = size.x;
    +             mHeight = size.y;
    +@@ -384,8 +401,10 @@ public final class PdfRenderer implements AutoCloseable {
    + 
    +             final long transformPtr = (transform != null) ? transform.native_instance : 0;
    + 
    +-            nativeRenderPage(mNativeDocument, mNativePage, destination, contentLeft,
    +-                    contentTop, contentRight, contentBottom, transformPtr, renderMode);
    ++            synchronized (sPdfiumLock) {
    ++                nativeRenderPage(mNativeDocument, mNativePage, destination, contentLeft,
    ++                        contentTop, contentRight, contentBottom, transformPtr, renderMode);
    ++            }
    +         }
    + 
    +         /**
    +@@ -412,7 +431,9 @@ public final class PdfRenderer implements AutoCloseable {
    +         }
    + 
    +         private void doClose() {
    +-            nativeClosePage(mNativePage);
    ++            synchronized (sPdfiumLock) {
    ++                nativeClosePage(mNativePage);
    ++            }
    +             mNativePage = 0;
    +             mCloseGuard.close();
    +             mCurrentPage = null;
    +diff --git a/include/androidfw/Asset.h b/include/androidfw/Asset.h
    +index ee77e97..52c8637 100644
    +--- a/include/androidfw/Asset.h
    ++++ b/include/androidfw/Asset.h
    +@@ -44,7 +44,7 @@ namespace android {
    +  */
    + class Asset {
    + public:
    +-    virtual ~Asset(void);
    ++    virtual ~Asset(void) = default;
    + 
    +     static int32_t getGlobalCount();
    +     static String8 getAssetAllocations();
    +@@ -119,6 +119,19 @@ public:
    +     const char* getAssetSource(void) const { return mAssetSource.string(); }
    + 
    + protected:
    ++    /*
    ++     * Adds this Asset to the global Asset list for debugging and
    ++     * accounting.
    ++     * Concrete subclasses must call this in their constructor.
    ++     */
    ++    static void registerAsset(Asset* asset);
    ++
    ++    /*
    ++     * Removes this Asset from the global Asset list.
    ++     * Concrete subclasses must call this in their destructor.
    ++     */
    ++    static void unregisterAsset(Asset* asset);
    ++
    +     Asset(void);        // constructor; only invoked indirectly
    + 
    +     /* handle common seek() housekeeping */
    +diff --git a/keystore/java/android/security/KeyChain.java b/keystore/java/android/security/KeyChain.java
    +index cce58c2..a96ca39 100644
    +--- a/keystore/java/android/security/KeyChain.java
    ++++ b/keystore/java/android/security/KeyChain.java
    +@@ -20,6 +20,7 @@ import android.annotation.Nullable;
    + import android.annotation.WorkerThread;
    + import android.app.Activity;
    + import android.app.PendingIntent;
    ++import android.app.Service;
    + import android.content.ComponentName;
    + import android.content.Context;
    + import android.content.Intent;
    +@@ -356,6 +357,9 @@ public final class KeyChain {
    +      *
    +      * <p> This method may block while waiting for a connection to another process, and must never
    +      * be called from the main thread.
    ++     * <p> As {@link Activity} and {@link Service} contexts are short-lived and can be destroyed
    ++     * at any time from the main thread, it is safer to rely on a long-lived context such as one
    ++     * returned from {@link Context#getApplicationContext()}.
    +      *
    +      * @param alias The alias of the desired private key, typically returned via
    +      *              {@link KeyChainAliasCallback#alias}.
    +@@ -368,7 +372,7 @@ public final class KeyChain {
    +         if (alias == null) {
    +             throw new NullPointerException("alias == null");
    +         }
    +-        KeyChainConnection keyChainConnection = bind(context);
    ++        KeyChainConnection keyChainConnection = bind(context.getApplicationContext());
    +         try {
    +             final IKeyChainService keyChainService = keyChainConnection.getService();
    +             final String keyId = keyChainService.requestPrivateKey(alias);
    +@@ -400,6 +404,9 @@ public final class KeyChain {
    +      *
    +      * <p> This method may block while waiting for a connection to another process, and must never
    +      * be called from the main thread.
    ++     * <p> As {@link Activity} and {@link Service} contexts are short-lived and can be destroyed
    ++     * at any time from the main thread, it is safer to rely on a long-lived context such as one
    ++     * returned from {@link Context#getApplicationContext()}.
    +      *
    +      * @param alias The alias of the desired certificate chain, typically
    +      * returned via {@link KeyChainAliasCallback#alias}.
    +@@ -412,7 +419,7 @@ public final class KeyChain {
    +         if (alias == null) {
    +             throw new NullPointerException("alias == null");
    +         }
    +-        KeyChainConnection keyChainConnection = bind(context);
    ++        KeyChainConnection keyChainConnection = bind(context.getApplicationContext());
    +         try {
    +             IKeyChainService keyChainService = keyChainConnection.getService();
    + 
    +diff --git a/keystore/java/android/security/KeyPairGeneratorSpec.java b/keystore/java/android/security/KeyPairGeneratorSpec.java
    +index d849317..d023866 100644
    +--- a/keystore/java/android/security/KeyPairGeneratorSpec.java
    ++++ b/keystore/java/android/security/KeyPairGeneratorSpec.java
    +@@ -251,8 +251,9 @@ public final class KeyPairGeneratorSpec implements AlgorithmParameterSpec {
    +     /**
    +      * Builder class for {@link KeyPairGeneratorSpec} objects.
    +      * <p>
    +-     * This will build a parameter spec for use with the <a href="{@docRoot}
    +-     * training/articles/keystore.html">Android KeyStore facility</a>.
    ++     * This will build a parameter spec for use with the
    ++     * <a href="{@docRoot}training/articles/keystore.html">Android KeyStore
    ++     * facility</a>.
    +      * <p>
    +      * The required fields must be filled in with the builder.
    +      * <p>
    +diff --git a/libs/androidfw/Asset.cpp b/libs/androidfw/Asset.cpp
    +index 4e14b13..6ae39d5 100644
    +--- a/libs/androidfw/Asset.cpp
    ++++ b/libs/androidfw/Asset.cpp
    +@@ -52,6 +52,47 @@ static int32_t gCount = 0;
    + static Asset* gHead = NULL;
    + static Asset* gTail = NULL;
    + 
    ++void Asset::registerAsset(Asset* asset)
    ++{
    ++    AutoMutex _l(gAssetLock);
    ++    gCount++;
    ++    asset->mNext = asset->mPrev = NULL;
    ++    if (gTail == NULL) {
    ++        gHead = gTail = asset;
    ++    } else {
    ++        asset->mPrev = gTail;
    ++        gTail->mNext = asset;
    ++        gTail = asset;
    ++    }
    ++
    ++    if (kIsDebug) {
    ++        ALOGI("Creating Asset %p #%d\n", asset, gCount);
    ++    }
    ++}
    ++
    ++void Asset::unregisterAsset(Asset* asset)
    ++{
    ++    AutoMutex _l(gAssetLock);
    ++    gCount--;
    ++    if (gHead == asset) {
    ++        gHead = asset->mNext;
    ++    }
    ++    if (gTail == asset) {
    ++        gTail = asset->mPrev;
    ++    }
    ++    if (asset->mNext != NULL) {
    ++        asset->mNext->mPrev = asset->mPrev;
    ++    }
    ++    if (asset->mPrev != NULL) {
    ++        asset->mPrev->mNext = asset->mNext;
    ++    }
    ++    asset->mNext = asset->mPrev = NULL;
    ++
    ++    if (kIsDebug) {
    ++        ALOGI("Destroying Asset in %p #%d\n", asset, gCount);
    ++    }
    ++}
    ++
    + int32_t Asset::getGlobalCount()
    + {
    +     AutoMutex _l(gAssetLock);
    +@@ -79,43 +120,8 @@ String8 Asset::getAssetAllocations()
    + }
    + 
    + Asset::Asset(void)
    +-    : mAccessMode(ACCESS_UNKNOWN)
    ++    : mAccessMode(ACCESS_UNKNOWN), mNext(NULL), mPrev(NULL)
    + {
    +-    AutoMutex _l(gAssetLock);
    +-    gCount++;
    +-    mNext = mPrev = NULL;
    +-    if (gTail == NULL) {
    +-        gHead = gTail = this;
    +-    } else {
    +-        mPrev = gTail;
    +-        gTail->mNext = this;
    +-        gTail = this;
    +-    }
    +-    if (kIsDebug) {
    +-        ALOGI("Creating Asset %p #%d\n", this, gCount);
    +-    }
    +-}
    +-
    +-Asset::~Asset(void)
    +-{
    +-    AutoMutex _l(gAssetLock);
    +-    gCount--;
    +-    if (gHead == this) {
    +-        gHead = mNext;
    +-    }
    +-    if (gTail == this) {
    +-        gTail = mPrev;
    +-    }
    +-    if (mNext != NULL) {
    +-        mNext->mPrev = mPrev;
    +-    }
    +-    if (mPrev != NULL) {
    +-        mPrev->mNext = mNext;
    +-    }
    +-    mNext = mPrev = NULL;
    +-    if (kIsDebug) {
    +-        ALOGI("Destroying Asset in %p #%d\n", this, gCount);
    +-    }
    + }
    + 
    + /*
    +@@ -361,6 +367,9 @@ off64_t Asset::handleSeek(off64_t offset, int whence, off64_t curPosn, off64_t m
    + _FileAsset::_FileAsset(void)
    +     : mStart(0), mLength(0), mOffset(0), mFp(NULL), mFileName(NULL), mMap(NULL), mBuf(NULL)
    + {
    ++    // Register the Asset with the global list here after it is fully constructed and its
    ++    // vtable pointer points to this concrete type. b/31113965
    ++    registerAsset(this);
    + }
    + 
    + /*
    +@@ -369,6 +378,10 @@ _FileAsset::_FileAsset(void)
    + _FileAsset::~_FileAsset(void)
    + {
    +     close();
    ++
    ++    // Unregister the Asset from the global list here before it is destructed and while its vtable
    ++    // pointer still points to this concrete type. b/31113965
    ++    unregisterAsset(this);
    + }
    + 
    + /*
    +@@ -685,6 +698,9 @@ _CompressedAsset::_CompressedAsset(void)
    +     : mStart(0), mCompressedLen(0), mUncompressedLen(0), mOffset(0),
    +       mMap(NULL), mFd(-1), mZipInflater(NULL), mBuf(NULL)
    + {
    ++    // Register the Asset with the global list here after it is fully constructed and its
    ++    // vtable pointer points to this concrete type. b/31113965
    ++    registerAsset(this);
    + }
    + 
    + /*
    +@@ -693,6 +709,10 @@ _CompressedAsset::_CompressedAsset(void)
    + _CompressedAsset::~_CompressedAsset(void)
    + {
    +     close();
    ++
    ++    // Unregister the Asset from the global list here before it is destructed and while its vtable
    ++    // pointer still points to this concrete type. b/31113965
    ++    unregisterAsset(this);
    + }
    + 
    + /*
    +diff --git a/libs/androidfw/AssetManager.cpp b/libs/androidfw/AssetManager.cpp
    +index f50cff4..07044d0 100644
    +--- a/libs/androidfw/AssetManager.cpp
    ++++ b/libs/androidfw/AssetManager.cpp
    +@@ -35,6 +35,9 @@
    + #include <utils/threads.h>
    + #include <utils/Timers.h>
    + #include <utils/Trace.h>
    ++#ifndef _WIN32
    ++#include <sys/file.h>
    ++#endif
    + 
    + #include <assert.h>
    + #include <dirent.h>
    +@@ -767,6 +770,12 @@ void AssetManager::addSystemOverlays(const char* pathOverlaysList,
    +         return;
    +     }
    + 
    ++#ifndef _WIN32
    ++    if (TEMP_FAILURE_RETRY(flock(fileno(fin), LOCK_SH)) != 0) {
    ++        fclose(fin);
    ++        return;
    ++    }
    ++#endif
    +     char buf[1024];
    +     while (fgets(buf, sizeof(buf), fin)) {
    +         // format of each line:
    +@@ -797,6 +806,10 @@ void AssetManager::addSystemOverlays(const char* pathOverlaysList,
    +             const_cast<AssetManager*>(this)->mZipSet.addOverlay(targetPackagePath, oap);
    +         }
    +     }
    ++
    ++#ifndef _WIN32
    ++    TEMP_FAILURE_RETRY(flock(fileno(fin), LOCK_UN));
    ++#endif
    +     fclose(fin);
    + }
    + 
    +@@ -1892,6 +1905,7 @@ ZipFileRO* AssetManager::SharedZip::getZip()
    + 
    + Asset* AssetManager::SharedZip::getResourceTableAsset()
    + {
    ++    AutoMutex _l(gLock);
    +     ALOGV("Getting from SharedZip %p resource asset %p\n", this, mResourceTableAsset);
    +     return mResourceTableAsset;
    + }
    +@@ -1901,10 +1915,10 @@ Asset* AssetManager::SharedZip::setResourceTableAsset(Asset* asset)
    +     {
    +         AutoMutex _l(gLock);
    +         if (mResourceTableAsset == NULL) {
    +-            mResourceTableAsset = asset;
    +             // This is not thread safe the first time it is called, so
    +             // do it here with the global lock held.
    +             asset->getBuffer(true);
    ++            mResourceTableAsset = asset;
    +             return asset;
    +         }
    +     }
    +diff --git a/libs/androidfw/tests/Android.mk b/libs/androidfw/tests/Android.mk
    +index 2bc026b..1fe1773 100644
    +--- a/libs/androidfw/tests/Android.mk
    ++++ b/libs/androidfw/tests/Android.mk
    +@@ -22,6 +22,7 @@ LOCAL_PATH:= $(call my-dir)
    + 
    + testFiles := \
    +     AppAsLib_test.cpp \
    ++    Asset_test.cpp \
    +     AttributeFinder_test.cpp \
    +     ByteBucketArray_test.cpp \
    +     Config_test.cpp \
    +diff --git a/libs/androidfw/tests/Asset_test.cpp b/libs/androidfw/tests/Asset_test.cpp
    +new file mode 100644
    +index 0000000..45c8cef
    +--- /dev/null
    ++++ b/libs/androidfw/tests/Asset_test.cpp
    +@@ -0,0 +1,37 @@
    ++/*
    ++ * Copyright (C) 2016 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.
    ++ */
    ++
    ++#include <androidfw/Asset.h>
    ++
    ++#include <gtest/gtest.h>
    ++
    ++using namespace android;
    ++
    ++TEST(AssetTest, FileAssetRegistersItself) {
    ++    const int32_t count = Asset::getGlobalCount();
    ++    Asset* asset = new _FileAsset();
    ++    EXPECT_EQ(count + 1, Asset::getGlobalCount());
    ++    delete asset;
    ++    EXPECT_EQ(count, Asset::getGlobalCount());
    ++}
    ++
    ++TEST(AssetTest, CompressedAssetRegistersItself) {
    ++    const int32_t count = Asset::getGlobalCount();
    ++    Asset* asset = new _CompressedAsset();
    ++    EXPECT_EQ(count + 1, Asset::getGlobalCount());
    ++    delete asset;
    ++    EXPECT_EQ(count, Asset::getGlobalCount());
    ++}
    +diff --git a/libs/hwui/Android.mk b/libs/hwui/Android.mk
    +index 366ef71..0b177b9 100644
    +--- a/libs/hwui/Android.mk
    ++++ b/libs/hwui/Android.mk
    +@@ -3,6 +3,7 @@ include $(CLEAR_VARS)
    + LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
    + 
    + HWUI_NEW_OPS := true
    ++BUGREPORT_FONT_CACHE_USAGE := false
    + 
    + # Enables fine-grained GLES error checking
    + # If set to true, every GLES call is wrapped & error checked
    +@@ -135,13 +136,20 @@ ifeq (true, $(HWUI_NEW_OPS))
    + 
    + endif
    + 
    ++ifeq (true, $(BUGREPORT_FONT_CACHE_USAGE))
    ++    hwui_src_files += \
    ++        font/FontCacheHistoryTracker.cpp
    ++    hwui_cflags += -DBUGREPORT_FONT_CACHE_USAGE
    ++endif
    ++
    ++
    + ifndef HWUI_COMPILE_SYMBOLS
    +     hwui_cflags += -fvisibility=hidden
    + endif
    + 
    + ifdef HWUI_COMPILE_FOR_PERF
    +     # TODO: Non-arm?
    +-    hwui_cflags += -fno-omit-frame-pointer -marm -mapcs
    ++    hwui_cflags += -fno-omit-frame-pointer -marm 
    + endif
    + 
    + # This has to be lazy-resolved because it depends on the LOCAL_MODULE_CLASS
    +diff --git a/libs/hwui/Caches.cpp b/libs/hwui/Caches.cpp
    +index 949ad45..a8ced9b 100644
    +--- a/libs/hwui/Caches.cpp
    ++++ b/libs/hwui/Caches.cpp
    +@@ -21,6 +21,9 @@
    + #include "Properties.h"
    + #include "renderstate/RenderState.h"
    + #include "ShadowTessellator.h"
    ++#ifdef BUGREPORT_FONT_CACHE_USAGE
    ++#include "font/FontCacheHistoryTracker.h"
    ++#endif
    + #include "utils/GLUtils.h"
    + 
    + #include <cutils/properties.h>
    +@@ -195,12 +198,7 @@ void Caches::dumpMemoryUsage(String8 &log) {
    +     log.appendFormat("  PatchCache           %8d / %8d\n",
    +             patchCache.getSize(), patchCache.getMaxSize());
    + 
    +-    const uint32_t sizeA8 = fontRenderer.getFontRendererSize(GL_ALPHA);
    +-    const uint32_t sizeRGBA = fontRenderer.getFontRendererSize(GL_RGBA);
    +-    log.appendFormat("  FontRenderer A8    %8d / %8d\n", sizeA8, sizeA8);
    +-    log.appendFormat("  FontRenderer RGBA  %8d / %8d\n", sizeRGBA, sizeRGBA);
    +-    log.appendFormat("  FontRenderer total %8d / %8d\n", sizeA8 + sizeRGBA,
    +-            sizeA8 + sizeRGBA);
    ++    fontRenderer.dumpMemoryUsage(log);
    + 
    +     log.appendFormat("Other:\n");
    +     log.appendFormat("  FboCache             %8d / %8d\n",
    +@@ -213,11 +211,14 @@ void Caches::dumpMemoryUsage(String8 &log) {
    +     total += tessellationCache.getSize();
    +     total += dropShadowCache.getSize();
    +     total += patchCache.getSize();
    +-    total += fontRenderer.getFontRendererSize(GL_ALPHA);
    +-    total += fontRenderer.getFontRendererSize(GL_RGBA);
    ++    total += fontRenderer.getSize();
    + 
    +     log.appendFormat("Total memory usage:\n");
    +     log.appendFormat("  %d bytes, %.2f MB\n", total, total / 1024.0f / 1024.0f);
    ++
    ++#ifdef BUGREPORT_FONT_CACHE_USAGE
    ++    fontRenderer.getFontRenderer().historyTracker().dump(log);
    ++#endif
    + }
    + 
    + ///////////////////////////////////////////////////////////////////////////////
    +diff --git a/libs/hwui/FontRenderer.cpp b/libs/hwui/FontRenderer.cpp
    +index 276c18d..681cf55 100644
    +--- a/libs/hwui/FontRenderer.cpp
    ++++ b/libs/hwui/FontRenderer.cpp
    +@@ -168,10 +168,17 @@ void FontRenderer::flushAllAndInvalidate() {
    + 
    +     for (uint32_t i = 0; i < mACacheTextures.size(); i++) {
    +         mACacheTextures[i]->init();
    ++
    ++#ifdef BUGREPORT_FONT_CACHE_USAGE
    ++        mHistoryTracker.glyphsCleared(mACacheTextures[i]);
    ++#endif
    +     }
    + 
    +     for (uint32_t i = 0; i < mRGBACacheTextures.size(); i++) {
    +         mRGBACacheTextures[i]->init();
    ++#ifdef BUGREPORT_FONT_CACHE_USAGE
    ++        mHistoryTracker.glyphsCleared(mRGBACacheTextures[i]);
    ++#endif
    +     }
    + 
    +     mDrawn = false;
    +@@ -183,6 +190,9 @@ void FontRenderer::flushLargeCaches(std::vector<CacheTexture*>& cacheTextures) {
    +         CacheTexture* cacheTexture = cacheTextures[i];
    +         if (cacheTexture->getPixelBuffer()) {
    +             cacheTexture->init();
    ++#ifdef BUGREPORT_FONT_CACHE_USAGE
    ++            mHistoryTracker.glyphsCleared(cacheTexture);
    ++#endif
    +             LruCache<Font::FontDescription, Font*>::Iterator it(mActiveFonts);
    +             while (it.next()) {
    +                 it.value()->invalidateTextureCache(cacheTexture);
    +@@ -385,6 +395,10 @@ void FontRenderer::cacheBitmap(const SkGlyph& glyph, CachedGlyphInfo* cachedGlyp
    +     }
    + 
    +     cachedGlyph->mIsValid = true;
    ++
    ++#ifdef BUGREPORT_FONT_CACHE_USAGE
    ++    mHistoryTracker.glyphUploaded(cacheTexture, startX, startY, glyph.fWidth, glyph.fHeight);
    ++#endif
    + }
    + 
    + CacheTexture* FontRenderer::createCacheTexture(int width, int height, GLenum format,
    +@@ -747,19 +761,68 @@ static uint32_t calculateCacheSize(const std::vector<CacheTexture*>& cacheTextur
    +     return size;
    + }
    + 
    +-uint32_t FontRenderer::getCacheSize(GLenum format) const {
    ++static uint32_t calculateFreeCacheSize(const std::vector<CacheTexture*>& cacheTextures) {
    ++    uint32_t size = 0;
    ++    for (uint32_t i = 0; i < cacheTextures.size(); i++) {
    ++        CacheTexture* cacheTexture = cacheTextures[i];
    ++        if (cacheTexture && cacheTexture->getPixelBuffer()) {
    ++            size += cacheTexture->calculateFreeMemory();
    ++        }
    ++    }
    ++    return size;
    ++}
    ++
    ++const std::vector<CacheTexture*>& FontRenderer::cacheTexturesForFormat(GLenum format) const {
    +     switch (format) {
    +         case GL_ALPHA: {
    +-            return calculateCacheSize(mACacheTextures);
    ++            return mACacheTextures;
    +         }
    +         case GL_RGBA: {
    +-            return calculateCacheSize(mRGBACacheTextures);
    ++            return mRGBACacheTextures;
    +         }
    +         default: {
    +-            return 0;
    ++            LOG_ALWAYS_FATAL("Unsupported format: %d", format);
    ++            // Impossible to hit this, but the compiler doesn't know that
    ++            return *(new std::vector<CacheTexture*>());
    +         }
    +     }
    + }
    + 
    ++static void dumpTextures(String8& log, const char* tag,
    ++        const std::vector<CacheTexture*>& cacheTextures) {
    ++    for (uint32_t i = 0; i < cacheTextures.size(); i++) {
    ++        CacheTexture* cacheTexture = cacheTextures[i];
    ++        if (cacheTexture && cacheTexture->getPixelBuffer()) {
    ++            uint32_t free = cacheTexture->calculateFreeMemory();
    ++            uint32_t total = cacheTexture->getPixelBuffer()->getSize();
    ++            log.appendFormat("    %-4s texture %d     %8d / %8d\n", tag, i, total - free, total);
    ++        }
    ++    }
    ++}
    ++
    ++void FontRenderer::dumpMemoryUsage(String8& log) const {
    ++    const uint32_t sizeA8 = getCacheSize(GL_ALPHA);
    ++    const uint32_t usedA8 = sizeA8 - getFreeCacheSize(GL_ALPHA);
    ++    const uint32_t sizeRGBA = getCacheSize(GL_RGBA);
    ++    const uint32_t usedRGBA = sizeRGBA - getFreeCacheSize(GL_RGBA);
    ++    log.appendFormat("  FontRenderer A8      %8d / %8d\n", usedA8, sizeA8);
    ++    dumpTextures(log, "A8", cacheTexturesForFormat(GL_ALPHA));
    ++    log.appendFormat("  FontRenderer RGBA    %8d / %8d\n", usedRGBA, sizeRGBA);
    ++    dumpTextures(log, "RGBA", cacheTexturesForFormat(GL_RGBA));
    ++    log.appendFormat("  FontRenderer total   %8d / %8d\n", usedA8 + usedRGBA, sizeA8 + sizeRGBA);
    ++}
    ++
    ++uint32_t FontRenderer::getCacheSize(GLenum format) const {
    ++    return calculateCacheSize(cacheTexturesForFormat(format));
    ++}
    ++
    ++uint32_t FontRenderer::getFreeCacheSize(GLenum format) const {
    ++    return calculateFreeCacheSize(cacheTexturesForFormat(format));
    ++}
    ++
    ++uint32_t FontRenderer::getSize() const {
    ++    return getCacheSize(GL_ALPHA) + getCacheSize(GL_RGBA);
    ++}
    ++
    + }; // namespace uirenderer
    + }; // namespace android
    +diff --git a/libs/hwui/FontRenderer.h b/libs/hwui/FontRenderer.h
    +index e10a81b..504dce8 100644
    +--- a/libs/hwui/FontRenderer.h
    ++++ b/libs/hwui/FontRenderer.h
    +@@ -21,8 +21,12 @@
    + #include "font/CacheTexture.h"
    + #include "font/CachedGlyphInfo.h"
    + #include "font/Font.h"
    ++#ifdef BUGREPORT_FONT_CACHE_USAGE
    ++#include "font/FontCacheHistoryTracker.h"
    ++#endif
    + 
    + #include <utils/LruCache.h>
    ++#include <utils/String8.h>
    + #include <utils/StrongPointer.h>
    + 
    + #include <SkPaint.h>
    +@@ -132,7 +136,12 @@ public:
    +         mLinearFiltering = linearFiltering;
    +     }
    + 
    +-    uint32_t getCacheSize(GLenum format) const;
    ++    uint32_t getSize() const;
    ++    void dumpMemoryUsage(String8& log) const;
    ++
    ++#ifdef BUGREPORT_FONT_CACHE_USAGE
    ++    FontCacheHistoryTracker& historyTracker() { return mHistoryTracker; }
    ++#endif
    + 
    + private:
    +     friend class Font;
    +@@ -175,6 +184,10 @@ private:
    +         mUploadTexture = true;
    +     }
    + 
    ++    const std::vector<CacheTexture*>& cacheTexturesForFormat(GLenum format) const;
    ++    uint32_t getCacheSize(GLenum format) const;
    ++    uint32_t getFreeCacheSize(GLenum format) const;
    ++
    +     uint32_t mSmallCacheWidth;
    +     uint32_t mSmallCacheHeight;
    +     uint32_t mLargeCacheWidth;
    +@@ -199,6 +212,10 @@ private:
    + 
    +     bool mLinearFiltering;
    + 
    ++#ifdef BUGREPORT_FONT_CACHE_USAGE
    ++    FontCacheHistoryTracker mHistoryTracker;
    ++#endif
    ++
    + #ifdef ANDROID_ENABLE_RENDERSCRIPT
    +     // RS constructs
    +     RSC::sp<RSC::RS> mRs;
    +diff --git a/libs/hwui/FrameBuilder.cpp b/libs/hwui/FrameBuilder.cpp
    +index 37d9d0e..7524ba0 100644
    +--- a/libs/hwui/FrameBuilder.cpp
    ++++ b/libs/hwui/FrameBuilder.cpp
    +@@ -591,7 +591,7 @@ void FrameBuilder::deferArcOp(const ArcOp& op) {
    + }
    + 
    + static bool hasMergeableClip(const BakedOpState& state) {
    +-    return state.computedState.clipState
    ++    return !state.computedState.clipState
    +             || state.computedState.clipState->mode == ClipMode::Rectangle;
    + }
    + 
    +diff --git a/libs/hwui/GammaFontRenderer.h b/libs/hwui/GammaFontRenderer.h
    +index 5813e7f..bd27a1a 100644
    +--- a/libs/hwui/GammaFontRenderer.h
    ++++ b/libs/hwui/GammaFontRenderer.h
    +@@ -22,6 +22,8 @@
    + 
    + #include <SkPaint.h>
    + 
    ++#include <utils/String8.h>
    ++
    + namespace android {
    + namespace uirenderer {
    + 
    +@@ -46,8 +48,16 @@ public:
    +         return *mRenderer;
    +     }
    + 
    +-    uint32_t getFontRendererSize(GLenum format) const {
    +-        return mRenderer ? mRenderer->getCacheSize(format) : 0;
    ++    void dumpMemoryUsage(String8& log) const {
    ++        if (mRenderer) {
    ++            mRenderer->dumpMemoryUsage(log);
    ++        } else {
    ++            log.appendFormat("FontRenderer doesn't exist.\n");
    ++        }
    ++    }
    ++
    ++    uint32_t getSize() const {
    ++        return mRenderer ? mRenderer->getSize() : 0;
    +     }
    + 
    +     void endPrecaching();
    +diff --git a/libs/hwui/PropertyValuesAnimatorSet.cpp b/libs/hwui/PropertyValuesAnimatorSet.cpp
    +index 38fb70a..e3258e3 100644
    +--- a/libs/hwui/PropertyValuesAnimatorSet.cpp
    ++++ b/libs/hwui/PropertyValuesAnimatorSet.cpp
    +@@ -46,8 +46,17 @@ PropertyValuesAnimatorSet::PropertyValuesAnimatorSet()
    + 
    + void PropertyValuesAnimatorSet::onFinished(BaseRenderNodeAnimator* animator) {
    +     if (mOneShotListener.get()) {
    +-        mOneShotListener->onAnimationFinished(animator);
    ++        sp<AnimationListener> listener = std::move(mOneShotListener);
    ++        // Set the listener to nullptr before the onAnimationFinished callback, rather than after,
    ++        // for two reasons:
    ++        // 1) We need to prevent changes to mOneShotListener during the onAnimationFinished
    ++        // callback (specifically in AnimationListenerBridge::onAnimationFinished(...) from
    ++        // triggering dtor of the bridge and potentially unsafely re-entering
    ++        // AnimationListenerBridge::onAnimationFinished(...).
    ++        // 2) It's possible that there are changes to the listener during the callback, therefore
    ++        // we need to reset the listener before the callback rather than afterwards.
    +         mOneShotListener = nullptr;
    ++        listener->onAnimationFinished(animator);
    +     }
    + }
    + 
    +diff --git a/libs/hwui/Readback.cpp b/libs/hwui/Readback.cpp
    +index 55f823d..0ab247d 100644
    +--- a/libs/hwui/Readback.cpp
    ++++ b/libs/hwui/Readback.cpp
    +@@ -136,7 +136,7 @@ CopyResult Readback::copySurfaceInto(renderthread::RenderThread& renderThread,
    +             EGL_NATIVE_BUFFER_ANDROID, clientBuffer, attrs);
    + 
    +     if (sourceImage == EGL_NO_IMAGE_KHR) {
    +-        ALOGW("Error creating image (%#x)", eglGetError());
    ++        ALOGW("eglCreateImageKHR failed (%#x)", eglGetError());
    +         return CopyResult::UnknownError;
    +     }
    +     GLuint sourceTexId;
    +@@ -147,7 +147,8 @@ CopyResult Readback::copySurfaceInto(renderthread::RenderThread& renderThread,
    + 
    +     GLenum status = GL_NO_ERROR;
    +     while ((status = glGetError()) != GL_NO_ERROR) {
    +-        ALOGW("Error creating image (%#x)", status);
    ++        ALOGW("glEGLImageTargetTexture2DOES failed (%#x)", status);
    ++        eglDestroyImageKHR(display, sourceImage);
    +         return CopyResult::UnknownError;
    +     }
    + 
    +@@ -183,6 +184,13 @@ CopyResult Readback::copySurfaceInto(renderthread::RenderThread& renderThread,
    +     caches.textureState().deleteTexture(texture);
    +     renderState.deleteFramebuffer(fbo);
    + 
    ++    sourceTexture.deleteTexture();
    ++    // All we're flushing & finishing is the deletion of the texture since
    ++    // copyTextureInto already did a major flush & finish as an implicit
    ++    // part of glReadPixels, so this shouldn't pose any major stalls.
    ++    glFinish();
    ++    eglDestroyImageKHR(display, sourceImage);
    ++
    +     GL_CHECKPOINT(MODERATE);
    + 
    +     return CopyResult::Success;
    +diff --git a/libs/hwui/SkiaCanvas.cpp b/libs/hwui/SkiaCanvas.cpp
    +index ce67554..c7289fc 100644
    +--- a/libs/hwui/SkiaCanvas.cpp
    ++++ b/libs/hwui/SkiaCanvas.cpp
    +@@ -329,9 +329,10 @@ void SkiaCanvas::restoreToCount(int restoreCount) {
    + static inline SkCanvas::SaveLayerFlags layerFlags(SaveFlags::Flags flags) {
    +     SkCanvas::SaveLayerFlags layerFlags = 0;
    + 
    +-    if (!(flags & SaveFlags::HasAlphaLayer)) {
    +-        layerFlags |= SkCanvas::kIsOpaque_SaveLayerFlag;
    +-    }
    ++    // We intentionally ignore the SaveFlags::HasAlphaLayer and
    ++    // SkCanvas::kIsOpaque_SaveLayerFlag flags because HWUI ignores it
    ++    // and our Android client may use it incorrectly.
    ++    // In Skia, this flag is purely for performance optimization.
    + 
    +     if (!(flags & SaveFlags::ClipToLayer)) {
    +         layerFlags |= SkCanvas::kDontClipToLayer_Legacy_SaveLayerFlag;
    +diff --git a/libs/hwui/Snapshot.cpp b/libs/hwui/Snapshot.cpp
    +index 2c9c9d9..7c187fb 100644
    +--- a/libs/hwui/Snapshot.cpp
    ++++ b/libs/hwui/Snapshot.cpp
    +@@ -38,6 +38,7 @@ Snapshot::Snapshot()
    +         , mClipArea(&mClipAreaRoot) {
    +     transform = &mTransformRoot;
    +     region = nullptr;
    ++    mRelativeLightCenter.x = mRelativeLightCenter.y = mRelativeLightCenter.z = 0;
    + }
    + 
    + /**
    +diff --git a/libs/hwui/SpotShadow.cpp b/libs/hwui/SpotShadow.cpp
    +index 760d814..cc96a13 100644
    +--- a/libs/hwui/SpotShadow.cpp
    ++++ b/libs/hwui/SpotShadow.cpp
    +@@ -942,9 +942,13 @@ void SpotShadow::generateTriangleStrip(bool isCasterOpaque, float shadowStrength
    +         AlphaVertex::set(&shadowVertices[vertexBufferIndex++], newPenumbra[i].x,
    +                 newPenumbra[i].y, PENUMBRA_ALPHA);
    +     }
    ++    // Since the umbra can be a faked one when the occluder is too high, the umbra should be lighter
    ++    // in this case.
    ++    float scaledUmbraAlpha = UMBRA_ALPHA * shadowStrengthScale;
    ++
    +     for (int i = 0; i < umbraLength; i++) {
    +         AlphaVertex::set(&shadowVertices[vertexBufferIndex++], umbra[i].x, umbra[i].y,
    +-                UMBRA_ALPHA);
    ++                scaledUmbraAlpha);
    +     }
    + 
    +     for (int i = 0; i < verticesPairIndex; i++) {
    +@@ -984,14 +988,14 @@ void SpotShadow::generateTriangleStrip(bool isCasterOpaque, float shadowStrength
    +             indexBuffer[indexBufferIndex++] = newPenumbraLength + i;
    +             indexBuffer[indexBufferIndex++] = vertexBufferIndex;
    +             AlphaVertex::set(&shadowVertices[vertexBufferIndex++],
    +-                    closerVertex.x, closerVertex.y, UMBRA_ALPHA);
    ++                    closerVertex.x, closerVertex.y, scaledUmbraAlpha);
    +         }
    +     } else {
    +         // If there is no occluded umbra at all, then draw the triangle fan
    +         // starting from the centroid to all umbra vertices.
    +         int lastCentroidIndex = vertexBufferIndex;
    +         AlphaVertex::set(&shadowVertices[vertexBufferIndex++], centroid.x,
    +-                centroid.y, UMBRA_ALPHA);
    ++                centroid.y, scaledUmbraAlpha);
    +         for (int i = 0; i < umbraLength; i++) {
    +             indexBuffer[indexBufferIndex++] = newPenumbraLength + i;
    +             indexBuffer[indexBufferIndex++] = lastCentroidIndex;
    +diff --git a/libs/hwui/VectorDrawable.cpp b/libs/hwui/VectorDrawable.cpp
    +index 2b79941..aeee661 100644
    +--- a/libs/hwui/VectorDrawable.cpp
    ++++ b/libs/hwui/VectorDrawable.cpp
    +@@ -202,7 +202,9 @@ void FullPath::drawPath(SkCanvas* outCanvas, SkPath& renderPath, float strokeSca
    +     if (properties.getFillGradient() != nullptr) {
    +         paint.setColor(applyAlpha(SK_ColorBLACK, properties.getFillAlpha()));
    +         SkShader* newShader = properties.getFillGradient()->newWithLocalMatrix(matrix);
    +-        paint.setShader(newShader);
    ++        // newWithLocalMatrix(...) creates a new SkShader and returns a bare pointer. We need to
    ++        // remove the extra ref so that the ref count is correctly managed.
    ++        paint.setShader(newShader)->unref();
    +         needsFill = true;
    +     } else if (properties.getFillColor() != SK_ColorTRANSPARENT) {
    +         paint.setColor(applyAlpha(properties.getFillColor(), properties.getFillAlpha()));
    +@@ -222,7 +224,9 @@ void FullPath::drawPath(SkCanvas* outCanvas, SkPath& renderPath, float strokeSca
    +     if (properties.getStrokeGradient() != nullptr) {
    +         paint.setColor(applyAlpha(SK_ColorBLACK, properties.getStrokeAlpha()));
    +         SkShader* newShader = properties.getStrokeGradient()->newWithLocalMatrix(matrix);
    +-        paint.setShader(newShader);
    ++        // newWithLocalMatrix(...) creates a new SkShader and returns a bare pointer. We need to
    ++        // remove the extra ref so that the ref count is correctly managed.
    ++        paint.setShader(newShader)->unref();
    +         needsStroke = true;
    +     } else if (properties.getStrokeColor() != SK_ColorTRANSPARENT) {
    +         paint.setColor(applyAlpha(properties.getStrokeColor(), properties.getStrokeAlpha()));
    +diff --git a/libs/hwui/font/CacheTexture.cpp b/libs/hwui/font/CacheTexture.cpp
    +index 8ba4761..4b13814 100644
    +--- a/libs/hwui/font/CacheTexture.cpp
    ++++ b/libs/hwui/font/CacheTexture.cpp
    +@@ -324,5 +324,17 @@ bool CacheTexture::fitBitmap(const SkGlyph& glyph, uint32_t* retOriginX, uint32_
    +     return false;
    + }
    + 
    ++uint32_t CacheTexture::calculateFreeMemory() const {
    ++    CacheBlock* cacheBlock = mCacheBlocks;
    ++    uint32_t free = 0;
    ++    // currently only two formats are supported: GL_ALPHA or GL_RGBA;
    ++    uint32_t bpp = mFormat == GL_RGBA ? 4 : 1;
    ++    while (cacheBlock) {
    ++        free += bpp * cacheBlock->mWidth * cacheBlock->mHeight;
    ++        cacheBlock = cacheBlock->mNext;
    ++    }
    ++    return free;
    ++}
    ++
    + }; // namespace uirenderer
    + }; // namespace android
    +diff --git a/libs/hwui/font/CacheTexture.h b/libs/hwui/font/CacheTexture.h
    +index 4dfb41d..6750a8a 100644
    +--- a/libs/hwui/font/CacheTexture.h
    ++++ b/libs/hwui/font/CacheTexture.h
    +@@ -178,6 +178,8 @@ public:
    +         return mCurrentQuad == mMaxQuadCount;
    +     }
    + 
    ++    uint32_t calculateFreeMemory() const;
    ++
    + private:
    +     void setDirty(bool dirty);
    + 
    +diff --git a/libs/hwui/font/Font.cpp b/libs/hwui/font/Font.cpp
    +index 8e04c87..a95454a 100644
    +--- a/libs/hwui/font/Font.cpp
    ++++ b/libs/hwui/font/Font.cpp
    +@@ -408,9 +408,15 @@ void Font::render(const SkPaint* paint, const glyph_t* glyphs,
    +         if (cachedGlyph->mIsValid && cachedGlyph->mCacheTexture) {
    +             int penX = x + (int) roundf(positions[(glyphsCount << 1)]);
    +             int penY = y + (int) roundf(positions[(glyphsCount << 1) + 1]);
    +-
    ++#ifdef BUGREPORT_FONT_CACHE_USAGE
    ++            mState->historyTracker().glyphRendered(cachedGlyph, penX, penY);
    ++#endif
    +             (*this.*render)(cachedGlyph, penX, penY,
    +                     bitmap, bitmapW, bitmapH, bounds, positions);
    ++        } else {
    ++#ifdef BUGREPORT_FONT_CACHE_USAGE
    ++            mState->historyTracker().glyphRendered(cachedGlyph, -1, -1);
    ++#endif
    +         }
    + 
    +         glyphsCount++;
    +diff --git a/libs/hwui/font/FontCacheHistoryTracker.cpp b/libs/hwui/font/FontCacheHistoryTracker.cpp
    +new file mode 100644
    +index 0000000..a2bfb27
    +--- /dev/null
    ++++ b/libs/hwui/font/FontCacheHistoryTracker.cpp
    +@@ -0,0 +1,100 @@
    ++/*
    ++ * Copyright (C) 2016 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.
    ++ */
    ++
    ++#include "FontCacheHistoryTracker.h"
    ++
    ++#include "CachedGlyphInfo.h"
    ++#include "CacheTexture.h"
    ++
    ++namespace android {
    ++namespace uirenderer {
    ++
    ++void FontCacheHistoryTracker::dumpCachedGlyph(String8& log, const CachedGlyph& glyph) {
    ++    log.appendFormat("glyph (texture %p, position: (%d, %d), size: %dx%d, gen: %d)", glyph.texture,
    ++            glyph.startX, glyph.startY, glyph.bitmapW, glyph.bitmapH, glyph.generation);
    ++}
    ++
    ++void FontCacheHistoryTracker::dumpRenderEntry(String8& log, const RenderEntry& entry) {
    ++    if (entry.penX == -1 && entry.penY == -1) {
    ++        log.appendFormat("      glyph skipped in gen: %d\n", entry.glyph.generation);
    ++    } else {
    ++        log.appendFormat("      rendered ");
    ++        dumpCachedGlyph(log, entry.glyph);
    ++        log.appendFormat(" at (%d, %d)\n", entry.penX, entry.penY);
    ++    }
    ++}
    ++
    ++void FontCacheHistoryTracker::dumpUploadEntry(String8& log, const CachedGlyph& glyph) {
    ++    if (glyph.bitmapW == 0 && glyph.bitmapH == 0) {
    ++        log.appendFormat("      cleared cachetexture %p in gen %d\n", glyph.texture,
    ++                glyph.generation);
    ++    } else {
    ++        log.appendFormat("      uploaded ");
    ++        dumpCachedGlyph(log, glyph);
    ++        log.appendFormat("\n");
    ++    }
    ++}
    ++
    ++void FontCacheHistoryTracker::dump(String8& log) const {
    ++    log.appendFormat("FontCacheHistory: \n");
    ++    log.appendFormat("  Upload history: \n");
    ++    for (size_t i = 0; i < mUploadHistory.size(); i++) {
    ++        dumpUploadEntry(log, mUploadHistory[i]);
    ++    }
    ++    log.appendFormat("  Render history: \n");
    ++    for (size_t i = 0; i < mRenderHistory.size(); i++) {
    ++        dumpRenderEntry(log, mRenderHistory[i]);
    ++    }
    ++}
    ++
    ++void FontCacheHistoryTracker::glyphRendered(CachedGlyphInfo* glyphInfo, int penX, int penY) {
    ++    RenderEntry& entry = mRenderHistory.next();
    ++    entry.glyph.generation = generation;
    ++    entry.glyph.texture = glyphInfo->mCacheTexture;
    ++    entry.glyph.startX = glyphInfo->mStartX;
    ++    entry.glyph.startY = glyphInfo->mStartY;
    ++    entry.glyph.bitmapW = glyphInfo->mBitmapWidth;
    ++    entry.glyph.bitmapH = glyphInfo->mBitmapHeight;
    ++    entry.penX = penX;
    ++    entry.penY = penY;
    ++}
    ++
    ++void FontCacheHistoryTracker::glyphUploaded(CacheTexture* texture, uint32_t x, uint32_t y,
    ++        uint16_t glyphW, uint16_t glyphH) {
    ++    CachedGlyph& glyph = mUploadHistory.next();
    ++    glyph.generation = generation;
    ++    glyph.texture = texture;
    ++    glyph.startX = x;
    ++    glyph.startY = y;
    ++    glyph.bitmapW = glyphW;
    ++    glyph.bitmapH = glyphH;
    ++}
    ++
    ++void FontCacheHistoryTracker::glyphsCleared(CacheTexture* texture) {
    ++    CachedGlyph& glyph = mUploadHistory.next();
    ++    glyph.generation = generation;
    ++    glyph.texture = texture;
    ++    glyph.startX = 0;
    ++    glyph.startY = 0;
    ++    glyph.bitmapW = 0;
    ++    glyph.bitmapH = 0;
    ++}
    ++
    ++void FontCacheHistoryTracker::frameCompleted() {
    ++    generation++;
    ++}
    ++}; // namespace uirenderer
    ++}; // namespace android
    +diff --git a/libs/hwui/font/FontCacheHistoryTracker.h b/libs/hwui/font/FontCacheHistoryTracker.h
    +new file mode 100644
    +index 0000000..f1d9b9f
    +--- /dev/null
    ++++ b/libs/hwui/font/FontCacheHistoryTracker.h
    +@@ -0,0 +1,64 @@
    ++/*
    ++ * Copyright (C) 2016 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.
    ++ */
    ++
    ++#pragma once
    ++#include "../utils/RingBuffer.h"
    ++
    ++#include <utils/String8.h>
    ++
    ++namespace android {
    ++namespace uirenderer {
    ++
    ++class CacheTexture;
    ++struct CachedGlyphInfo;
    ++
    ++// Tracks glyph uploads and recent rendered/skipped glyphs, so it can give an idea
    ++// what a missing character is: skipped glyph, wrong coordinates in cache texture etc.
    ++class FontCacheHistoryTracker {
    ++public:
    ++    void glyphRendered(CachedGlyphInfo*, int penX, int penY);
    ++    void glyphUploaded(CacheTexture*, uint32_t x, uint32_t y, uint16_t glyphW, uint16_t glyphH);
    ++    void glyphsCleared(CacheTexture*);
    ++    void frameCompleted();
    ++
    ++    void dump(String8& log) const;
    ++private:
    ++    struct CachedGlyph {
    ++        void* texture;
    ++        uint16_t generation;
    ++        uint16_t startX;
    ++        uint16_t startY;
    ++        uint16_t bitmapW;
    ++        uint16_t bitmapH;
    ++    };
    ++
    ++    struct RenderEntry {
    ++        CachedGlyph glyph;
    ++        int penX;
    ++        int penY;
    ++    };
    ++
    ++    static void dumpCachedGlyph(String8& log, const CachedGlyph& glyph);
    ++    static void dumpRenderEntry(String8& log, const RenderEntry& entry);
    ++    static void dumpUploadEntry(String8& log, const CachedGlyph& glyph);
    ++
    ++    RingBuffer<RenderEntry, 300> mRenderHistory;
    ++    RingBuffer<CachedGlyph, 120> mUploadHistory;
    ++    uint16_t generation = 0;
    ++};
    ++
    ++}; // namespace uirenderer
    ++}; // namespace android
    +\ No newline at end of file
    +diff --git a/libs/hwui/renderthread/CanvasContext.cpp b/libs/hwui/renderthread/CanvasContext.cpp
    +index dcaec42..975ac83 100644
    +--- a/libs/hwui/renderthread/CanvasContext.cpp
    ++++ b/libs/hwui/renderthread/CanvasContext.cpp
    +@@ -608,6 +608,10 @@ void CanvasContext::draw() {
    +     }
    + 
    +     GpuMemoryTracker::onFrameCompleted();
    ++#ifdef BUGREPORT_FONT_CACHE_USAGE
    ++    caches.fontRenderer.getFontRenderer().historyTracker().frameCompleted();
    ++#endif
    ++
    + }
    + 
    + // Called by choreographer to do an RT-driven animation
    +@@ -633,6 +637,9 @@ void CanvasContext::prepareAndDraw(RenderNode* node) {
    +     prepareTree(info, frameInfo, systemTime(CLOCK_MONOTONIC), node);
    +     if (info.out.canDrawThisFrame) {
    +         draw();
    ++    } else {
    ++        // wait on fences so tasks don't overlap next frame
    ++        waitOnFences();
    +     }
    + }
    + 
    +diff --git a/libs/hwui/renderthread/CanvasContext.h b/libs/hwui/renderthread/CanvasContext.h
    +index 3eef29b..e182175 100644
    +--- a/libs/hwui/renderthread/CanvasContext.h
    ++++ b/libs/hwui/renderthread/CanvasContext.h
    +@@ -168,6 +168,8 @@ public:
    + 
    +     ANDROID_API int64_t getFrameNumber();
    + 
    ++    void waitOnFences();
    ++
    + private:
    +     friend class RegisterFrameCallbackTask;
    +     // TODO: Replace with something better for layer & other GL object
    +@@ -178,8 +180,6 @@ private:
    + 
    +     void freePrefetchedLayers(TreeObserver* observer);
    + 
    +-    void waitOnFences();
    +-
    +     bool isSwapChainStuffed();
    + 
    +     EGLint mLastFrameWidth = 0;
    +diff --git a/libs/hwui/renderthread/DrawFrameTask.cpp b/libs/hwui/renderthread/DrawFrameTask.cpp
    +index c9c07b3..e3b6dc6 100644
    +--- a/libs/hwui/renderthread/DrawFrameTask.cpp
    ++++ b/libs/hwui/renderthread/DrawFrameTask.cpp
    +@@ -104,6 +104,9 @@ void DrawFrameTask::run() {
    + 
    +     if (CC_LIKELY(canDrawThisFrame)) {
    +         context->draw();
    ++    } else {
    ++        // wait on fences so tasks don't overlap next frame
    ++        context->waitOnFences();
    +     }
    + 
    +     if (!canUnblockUiThread) {
    +diff --git a/libs/hwui/tests/unit/FrameBuilderTests.cpp b/libs/hwui/tests/unit/FrameBuilderTests.cpp
    +index 53dbede..e2dc3a0 100644
    +--- a/libs/hwui/tests/unit/FrameBuilderTests.cpp
    ++++ b/libs/hwui/tests/unit/FrameBuilderTests.cpp
    +@@ -477,6 +477,35 @@ RENDERTHREAD_TEST(FrameBuilder, clippedMerging) {
    +     EXPECT_EQ(4, renderer.getIndex());
    + }
    + 
    ++RENDERTHREAD_TEST(FrameBuilder, regionClipStopsMerge) {
    ++    class RegionClipStopsMergeTestRenderer : public TestRendererBase {
    ++    public:
    ++        void onTextOp(const TextOp& op, const BakedOpState& state) override { mIndex++; }
    ++    };
    ++    auto node = TestUtils::createNode(0, 0, 400, 400,
    ++            [](RenderProperties& props, TestCanvas& canvas) {
    ++        SkPath path;
    ++        path.addCircle(200, 200, 200, SkPath::kCW_Direction);
    ++        canvas.save(SaveFlags::MatrixClip);
    ++        canvas.clipPath(&path, SkRegion::kIntersect_Op);
    ++        SkPaint paint;
    ++        paint.setTextEncoding(SkPaint::kGlyphID_TextEncoding);
    ++        paint.setAntiAlias(true);
    ++        paint.setTextSize(50);
    ++        TestUtils::drawUtf8ToCanvas(&canvas, "Test string1", paint, 100, 100);
    ++        TestUtils::drawUtf8ToCanvas(&canvas, "Test string1", paint, 100, 200);
    ++        canvas.restore();
    ++    });
    ++
    ++    FrameBuilder frameBuilder(SkRect::MakeWH(400, 400), 400, 400,
    ++            sLightGeometry, Caches::getInstance());
    ++    frameBuilder.deferRenderNode(*TestUtils::getSyncedNode(node));
    ++
    ++    RegionClipStopsMergeTestRenderer renderer;
    ++    frameBuilder.replayBakedOps<TestDispatcher>(renderer);
    ++    EXPECT_EQ(2, renderer.getIndex());
    ++}
    ++
    + RENDERTHREAD_TEST(FrameBuilder, textMerging) {
    +     class TextMergingTestRenderer : public TestRendererBase {
    +     public:
    +diff --git a/libs/hwui/tests/unit/VectorDrawableTests.cpp b/libs/hwui/tests/unit/VectorDrawableTests.cpp
    +index 83b485f..8e0d3ee 100644
    +--- a/libs/hwui/tests/unit/VectorDrawableTests.cpp
    ++++ b/libs/hwui/tests/unit/VectorDrawableTests.cpp
    +@@ -426,5 +426,49 @@ TEST(VectorDrawable, groupProperties) {
    +     EXPECT_EQ(1.0f, properties->getPivotY());
    + 
    + }
    ++
    ++static SkShader* createShader(bool* isDestroyed) {
    ++    class TestShader : public SkShader {
    ++    public:
    ++        TestShader(bool* isDestroyed) : SkShader(), mDestroyed(isDestroyed) {
    ++        }
    ++        ~TestShader() {
    ++            *mDestroyed = true;
    ++        }
    ++
    ++        Factory getFactory() const override { return nullptr; }
    ++    private:
    ++        bool* mDestroyed;
    ++    };
    ++    return new TestShader(isDestroyed);
    ++}
    ++
    ++TEST(VectorDrawable, drawPathWithoutIncrementingShaderRefCount) {
    ++    VectorDrawable::FullPath path("m1 1", 4);
    ++    SkBitmap bitmap;
    ++    SkImageInfo info = SkImageInfo::Make(5, 5, kN32_SkColorType, kPremul_SkAlphaType);
    ++    bitmap.setInfo(info);
    ++    bitmap.allocPixels(info);
    ++    SkCanvas canvas(bitmap);
    ++
    ++    bool shaderIsDestroyed = false;
    ++
    ++    // Initial ref count is 1
    ++    SkShader* shader = createShader(&shaderIsDestroyed);
    ++
    ++    // Setting the fill gradient increments the ref count of the shader by 1
    ++    path.mutateStagingProperties()->setFillGradient(shader);
    ++    path.draw(&canvas, SkMatrix::I(), 1.0f, 1.0f, true);
    ++    // Resetting the fill gradient decrements the ref count of the shader by 1
    ++    path.mutateStagingProperties()->setFillGradient(nullptr);
    ++
    ++    // Expect ref count to be 1 again, i.e. nothing else to have a ref to the shader now. Unref()
    ++    // again should bring the ref count to zero and consequently trigger detor.
    ++    shader->unref();
    ++
    ++    // Verify that detor is called.
    ++    EXPECT_TRUE(shaderIsDestroyed);
    ++}
    ++
    + }; // namespace uirenderer
    + }; // namespace android
    +diff --git a/libs/input/PointerController.cpp b/libs/input/PointerController.cpp
    +index 27193b7..abef66f 100644
    +--- a/libs/input/PointerController.cpp
    ++++ b/libs/input/PointerController.cpp
    +@@ -36,6 +36,29 @@
    + 
    + namespace android {
    + 
    ++// --- WeakLooperCallback ---
    ++
    ++class WeakLooperCallback: public LooperCallback {
    ++protected:
    ++    virtual ~WeakLooperCallback() { }
    ++
    ++public:
    ++    WeakLooperCallback(const wp<LooperCallback>& callback) :
    ++        mCallback(callback) {
    ++    }
    ++
    ++    virtual int handleEvent(int fd, int events, void* data) {
    ++        sp<LooperCallback> callback = mCallback.promote();
    ++        if (callback != NULL) {
    ++            return callback->handleEvent(fd, events, data);
    ++        }
    ++        return 0; // the client is gone, remove the callback
    ++    }
    ++
    ++private:
    ++    wp<LooperCallback> mCallback;
    ++};
    ++
    + // --- PointerController ---
    + 
    + // Time to wait before starting the fade when the pointer is inactive.
    +@@ -57,10 +80,11 @@ PointerController::PointerController(const sp<PointerControllerPolicyInterface>&
    +         const sp<Looper>& looper, const sp<SpriteController>& spriteController) :
    +         mPolicy(policy), mLooper(looper), mSpriteController(spriteController) {
    +     mHandler = new WeakMessageHandler(this);
    ++    mCallback = new WeakLooperCallback(this);
    + 
    +     if (mDisplayEventReceiver.initCheck() == NO_ERROR) {
    +         mLooper->addFd(mDisplayEventReceiver.getFd(), Looper::POLL_CALLBACK,
    +-                       Looper::EVENT_INPUT, this, nullptr);
    ++                       Looper::EVENT_INPUT, mCallback, nullptr);
    +     } else {
    +         ALOGE("Failed to initialize DisplayEventReceiver.");
    +     }
    +diff --git a/libs/input/PointerController.h b/libs/input/PointerController.h
    +index 99292d7..4794f3d 100644
    +--- a/libs/input/PointerController.h
    ++++ b/libs/input/PointerController.h
    +@@ -144,6 +144,7 @@ private:
    +     sp<Looper> mLooper;
    +     sp<SpriteController> mSpriteController;
    +     sp<WeakMessageHandler> mHandler;
    ++    sp<LooperCallback> mCallback;
    + 
    +     DisplayEventReceiver mDisplayEventReceiver;
    + 
    +diff --git a/location/java/android/location/Address.java b/location/java/android/location/Address.java
    +index b152f48..335ad5e 100644
    +--- a/location/java/android/location/Address.java
    ++++ b/location/java/android/location/Address.java
    +@@ -28,7 +28,7 @@ import android.os.Parcelable;
    + /**
    +  * A class representing an Address, i.e, a set of Strings describing a location.
    +  *
    +- * The addres format is a simplified version of xAL (eXtensible Address Language)
    ++ * The address format is a simplified version of xAL (eXtensible Address Language)
    +  * http://www.oasis-open.org/committees/ciq/ciq.html#6
    +  */
    + public class Address implements Parcelable {
    +diff --git a/location/java/android/location/LocationManager.java b/location/java/android/location/LocationManager.java
    +index 2b3ed87..da0e515 100644
    +--- a/location/java/android/location/LocationManager.java
    ++++ b/location/java/android/location/LocationManager.java
    +@@ -1465,7 +1465,7 @@ public class LocationManager {
    +             mGpsNmeaListener = null;
    +             mNmeaBuffer = null;
    +             mOldGnssCallback = null;
    +-            mGnssCallback = new GnssStatus.Callback() {
    ++            mGnssCallback = mGpsListener != null ? new GnssStatus.Callback() {
    +                 @Override
    +                 public void onStarted() {
    +                     mGpsListener.onGpsStatusChanged(GpsStatus.GPS_EVENT_STARTED);
    +@@ -1485,7 +1485,7 @@ public class LocationManager {
    +                 public void onSatelliteStatusChanged(GnssStatus status) {
    +                     mGpsListener.onGpsStatusChanged(GpsStatus.GPS_EVENT_SATELLITE_STATUS);
    +                 }
    +-            };
    ++            } : null;
    +             mOldGnssNmeaListener = null;
    +             mGnssNmeaListener = null;
    +         }
    +@@ -1502,12 +1502,12 @@ public class LocationManager {
    +             mOldGnssCallback = null;
    +             mGnssCallback = null;
    +             mOldGnssNmeaListener = null;
    +-            mGnssNmeaListener = new OnNmeaMessageListener() {
    ++            mGnssNmeaListener = mGpsNmeaListener != null ? new OnNmeaMessageListener() {
    +                 @Override
    +                 public void onNmeaMessage(String nmea, long timestamp) {
    +                     mGpsNmeaListener.onNmeaReceived(timestamp, nmea);
    +                 }
    +-            };
    ++            } : null;
    +         }
    + 
    +         GnssStatusListenerTransport(GnssStatusCallback callback) {
    +@@ -1516,7 +1516,7 @@ public class LocationManager {
    + 
    +         GnssStatusListenerTransport(GnssStatusCallback callback, Handler handler) {
    +             mOldGnssCallback = callback;
    +-            mGnssCallback = new GnssStatus.Callback() {
    ++            mGnssCallback = mOldGnssCallback != null ? new GnssStatus.Callback() {
    +                 @Override
    +                 public void onStarted() {
    +                     mOldGnssCallback.onStarted();
    +@@ -1536,7 +1536,7 @@ public class LocationManager {
    +                 public void onSatelliteStatusChanged(GnssStatus status) {
    +                     mOldGnssCallback.onSatelliteStatusChanged(status);
    +                 }
    +-            };
    ++            } : null;
    +             mGnssHandler = new GnssHandler(handler);
    +             mOldGnssNmeaListener = null;
    +             mGnssNmeaListener = null;
    +@@ -1569,12 +1569,12 @@ public class LocationManager {
    +             mOldGnssCallback = null;
    +             mGnssHandler = new GnssHandler(handler);
    +             mOldGnssNmeaListener = listener;
    +-            mGnssNmeaListener = new OnNmeaMessageListener() {
    ++            mGnssNmeaListener = mOldGnssNmeaListener != null ? new OnNmeaMessageListener() {
    +                 @Override
    +                 public void onNmeaMessage(String message, long timestamp) {
    +                     mOldGnssNmeaListener.onNmeaReceived(timestamp, message);
    +                 }
    +-            };
    ++            } : null;
    +             mGpsListener = null;
    +             mGpsNmeaListener = null;
    +             mNmeaBuffer = new ArrayList<Nmea>();
    +@@ -1597,7 +1597,7 @@ public class LocationManager {
    + 
    +         @Override
    +         public void onGnssStarted() {
    +-            if (mGpsListener != null) {
    ++            if (mGnssCallback != null) {
    +                 Message msg = Message.obtain();
    +                 msg.what = GpsStatus.GPS_EVENT_STARTED;
    +                 mGnssHandler.sendMessage(msg);
    +@@ -1606,7 +1606,7 @@ public class LocationManager {
    + 
    +         @Override
    +         public void onGnssStopped() {
    +-            if (mGpsListener != null) {
    ++            if (mGnssCallback != null) {
    +                 Message msg = Message.obtain();
    +                 msg.what = GpsStatus.GPS_EVENT_STOPPED;
    +                 mGnssHandler.sendMessage(msg);
    +@@ -1615,7 +1615,7 @@ public class LocationManager {
    + 
    +         @Override
    +         public void onFirstFix(int ttff) {
    +-            if (mGpsListener != null) {
    ++            if (mGnssCallback != null) {
    +                 mTimeToFirstFix = ttff;
    +                 Message msg = Message.obtain();
    +                 msg.what = GpsStatus.GPS_EVENT_FIRST_FIX;
    +diff --git a/media/java/android/media/AudioAttributes.java b/media/java/android/media/AudioAttributes.java
    +index 5286f8f..89709ee 100644
    +--- a/media/java/android/media/AudioAttributes.java
    ++++ b/media/java/android/media/AudioAttributes.java
    +@@ -24,6 +24,7 @@ import android.os.Parcel;
    + import android.os.Parcelable;
    + import android.text.TextUtils;
    + import android.util.Log;
    ++import android.util.SparseIntArray;
    + 
    + import java.lang.annotation.Retention;
    + import java.lang.annotation.RetentionPolicy;
    +@@ -170,6 +171,66 @@ public final class AudioAttributes implements Parcelable {
    +     public final static int USAGE_VIRTUAL_SOURCE = 15;
    + 
    +     /**
    ++     * IMPORTANT: when adding new usage types, add them to SDK_USAGES and update SUPPRESSIBLE_USAGES
    ++     *            if applicable.
    ++     */
    ++
    ++    /**
    ++     * @hide
    ++     * Denotes a usage for notifications that do not expect immediate intervention from the user,
    ++     * will be muted when the Zen mode disables notifications
    ++     * @see #SUPPRESSIBLE_USAGES
    ++     */
    ++    public final static int SUPPRESSIBLE_NOTIFICATION = 1;
    ++    /**
    ++     * @hide
    ++     * Denotes a usage for notifications that do expect immediate intervention from the user,
    ++     * will be muted when the Zen mode disables calls
    ++     * @see #SUPPRESSIBLE_USAGES
    ++     */
    ++    public final static int SUPPRESSIBLE_CALL = 2;
    ++
    ++    /**
    ++     * @hide
    ++     * Array of all usage types for calls and notifications to assign the suppression behavior,
    ++     * used by the Zen mode restrictions.
    ++     * @see com.android.server.notification.ZenModeHelper
    ++     */
    ++    public static final SparseIntArray SUPPRESSIBLE_USAGES;
    ++
    ++    static {
    ++        SUPPRESSIBLE_USAGES = new SparseIntArray();
    ++        SUPPRESSIBLE_USAGES.put(USAGE_NOTIFICATION,                      SUPPRESSIBLE_NOTIFICATION);
    ++        SUPPRESSIBLE_USAGES.put(USAGE_NOTIFICATION_RINGTONE,             SUPPRESSIBLE_CALL);
    ++        SUPPRESSIBLE_USAGES.put(USAGE_NOTIFICATION_COMMUNICATION_REQUEST,SUPPRESSIBLE_CALL);
    ++        SUPPRESSIBLE_USAGES.put(USAGE_NOTIFICATION_COMMUNICATION_INSTANT,SUPPRESSIBLE_NOTIFICATION);
    ++        SUPPRESSIBLE_USAGES.put(USAGE_NOTIFICATION_COMMUNICATION_DELAYED,SUPPRESSIBLE_NOTIFICATION);
    ++        SUPPRESSIBLE_USAGES.put(USAGE_NOTIFICATION_EVENT,                SUPPRESSIBLE_NOTIFICATION);
    ++    }
    ++
    ++    /**
    ++     * @hide
    ++     * Array of all usage types exposed in the SDK that applications can use.
    ++     */
    ++    public final static int[] SDK_USAGES = {
    ++            USAGE_UNKNOWN,
    ++            USAGE_MEDIA,
    ++            USAGE_VOICE_COMMUNICATION,
    ++            USAGE_VOICE_COMMUNICATION_SIGNALLING,
    ++            USAGE_ALARM,
    ++            USAGE_NOTIFICATION,
    ++            USAGE_NOTIFICATION_RINGTONE,
    ++            USAGE_NOTIFICATION_COMMUNICATION_REQUEST,
    ++            USAGE_NOTIFICATION_COMMUNICATION_INSTANT,
    ++            USAGE_NOTIFICATION_COMMUNICATION_DELAYED,
    ++            USAGE_NOTIFICATION_EVENT,
    ++            USAGE_ASSISTANCE_ACCESSIBILITY,
    ++            USAGE_ASSISTANCE_NAVIGATION_GUIDANCE,
    ++            USAGE_ASSISTANCE_SONIFICATION,
    ++            USAGE_GAME
    ++    };
    ++
    ++    /**
    +      * Flag defining a behavior where the audibility of the sound will be ensured by the system.
    +      */
    +     public final static int FLAG_AUDIBILITY_ENFORCED = 0x1 << 0;
    +diff --git a/media/java/android/media/ExifInterface.java b/media/java/android/media/ExifInterface.java
    +index 56af57a..6f24f76 100644
    +--- a/media/java/android/media/ExifInterface.java
    ++++ b/media/java/android/media/ExifInterface.java
    +@@ -1554,14 +1554,16 @@ public class ExifInterface {
    +      * copying all the data from one file to another and deleting the old file and renaming the
    +      * other. It's best to use {@link #setAttribute(String,String)} to set all attributes to write
    +      * and make a single call rather than multiple calls for each attribute.
    ++     * <p>
    ++     * This method is only supported for JPEG files.
    ++     * </p>
    +      */
    +     public void saveAttributes() throws IOException {
    +         if (!mIsSupportedFile || mIsRaw) {
    +-            throw new UnsupportedOperationException(
    +-                    "ExifInterface only supports saving attributes on JPEG formats.");
    ++            throw new IOException("ExifInterface only supports saving attributes on JPEG formats.");
    +         }
    +         if (mIsInputStream || (mSeekableFileDescriptor == null && mFilename == null)) {
    +-            throw new UnsupportedOperationException(
    ++            throw new IOException(
    +                     "ExifInterface does not support saving attributes for the current input.");
    +         }
    + 
    +diff --git a/media/java/android/media/ImageReader.java b/media/java/android/media/ImageReader.java
    +index 2cbeb3a..ed71849 100644
    +--- a/media/java/android/media/ImageReader.java
    ++++ b/media/java/android/media/ImageReader.java
    +@@ -241,6 +241,10 @@ public class ImageReader implements AutoCloseable {
    +      * same {@link Surface} can be reused with a different API once the first source is
    +      * disconnected from the {@link Surface}.</p>
    +      *
    ++     * <p>Please note that holding on to the Surface object returned by this method is not enough
    ++     * to keep its parent ImageReader from being reclaimed. In that sense, a Surface acts like a
    ++     * {@link java.lang.ref.WeakReference weak reference} to the ImageReader that provides it.</p>
    ++     *
    +      * @return A {@link Surface} to use for a drawing target for various APIs.
    +      */
    +     public Surface getSurface() {
    +diff --git a/media/java/android/media/MediaExtractor.java b/media/java/android/media/MediaExtractor.java
    +index 6f5199b..c8aedd0 100644
    +--- a/media/java/android/media/MediaExtractor.java
    ++++ b/media/java/android/media/MediaExtractor.java
    +@@ -496,6 +496,11 @@ final public class MediaExtractor {
    +     /**
    +      * Advance to the next sample. Returns false if no more sample data
    +      * is available (end of stream).
    ++     *
    ++     * When extracting a local file, the behaviors of {@link #advance} and
    ++     * {@link #readSampleData} are undefined in presence of concurrent
    ++     * writes to the same local file; more specifically, end of stream
    ++     * could be signalled earlier than expected.
    +      */
    +     public native boolean advance();
    + 
    +diff --git a/media/java/android/media/MediaPlayer.java b/media/java/android/media/MediaPlayer.java
    +index 31c7a32..e5f7527 100644
    +--- a/media/java/android/media/MediaPlayer.java
    ++++ b/media/java/android/media/MediaPlayer.java
    +@@ -1641,7 +1641,8 @@ public class MediaPlayer extends PlayerBase
    +      * (i.e. reaches the end of the stream).
    +      * The media framework will attempt to transition from this player to
    +      * the next as seamlessly as possible. The next player can be set at
    +-     * any time before completion. The next player must be prepared by the
    ++     * any time before completion, but shall be after setDataSource has been
    ++     * called successfully. The next player must be prepared by the
    +      * app, and the application should not call start() on it.
    +      * The next MediaPlayer must be different from 'this'. An exception
    +      * will be thrown if next == this.
    +diff --git a/media/java/android/media/MediaRouter.java b/media/java/android/media/MediaRouter.java
    +index 101facd..79195d6 100644
    +--- a/media/java/android/media/MediaRouter.java
    ++++ b/media/java/android/media/MediaRouter.java
    +@@ -220,8 +220,7 @@ public class MediaRouter {
    + 
    +             if (mBluetoothA2dpRoute != null) {
    +                 final boolean a2dpEnabled = isBluetoothA2dpOn();
    +-                if (mainType != AudioRoutesInfo.MAIN_SPEAKER &&
    +-                        mSelectedRoute == mBluetoothA2dpRoute && !a2dpEnabled) {
    ++                if (mSelectedRoute == mBluetoothA2dpRoute && !a2dpEnabled) {
    +                     selectRouteStatic(ROUTE_TYPE_LIVE_AUDIO, mDefaultAudioVideo, false);
    +                 } else if ((mSelectedRoute == mDefaultAudioVideo || mSelectedRoute == null) &&
    +                         a2dpEnabled) {
    +diff --git a/media/java/android/media/MediaScanner.java b/media/java/android/media/MediaScanner.java
    +index c8ab5f9..0fafe4b 100644
    +--- a/media/java/android/media/MediaScanner.java
    ++++ b/media/java/android/media/MediaScanner.java
    +@@ -21,12 +21,14 @@ import android.content.ContentResolver;
    + import android.content.ContentUris;
    + import android.content.ContentValues;
    + import android.content.Context;
    ++import android.content.SharedPreferences;
    + import android.database.Cursor;
    + import android.database.SQLException;
    + import android.drm.DrmManagerClient;
    + import android.graphics.BitmapFactory;
    + import android.mtp.MtpConstants;
    + import android.net.Uri;
    ++import android.os.Build;
    + import android.os.Environment;
    + import android.os.RemoteException;
    + import android.os.SystemProperties;
    +@@ -153,6 +155,11 @@ public class MediaScanner implements AutoCloseable {
    +     private static final String MUSIC_DIR = "/music/";
    +     private static final String PODCAST_DIR = "/podcasts/";
    + 
    ++    public static final String SCANNED_BUILD_PREFS_NAME = "MediaScanBuild";
    ++    public static final String LAST_INTERNAL_SCAN_FINGERPRINT = "lastScanFingerprint";
    ++    private static final String SYSTEM_SOUNDS_DIR = "/system/media/audio";
    ++    private static String sLastInternalScanFingerprint;
    ++
    +     private static final String[] ID3_GENRES = {
    +         // ID3v1 Genres
    +         "Blues",
    +@@ -402,6 +409,13 @@ public class MediaScanner implements AutoCloseable {
    +         mMediaProvider = mContext.getContentResolver()
    +                 .acquireContentProviderClient(MediaStore.AUTHORITY);
    + 
    ++        if (sLastInternalScanFingerprint == null) {
    ++            final SharedPreferences scanSettings =
    ++                    mContext.getSharedPreferences(SCANNED_BUILD_PREFS_NAME, Context.MODE_PRIVATE);
    ++            sLastInternalScanFingerprint =
    ++                    scanSettings.getString(LAST_INTERNAL_SCAN_FINGERPRINT, new String());
    ++        }
    ++
    +         mAudioUri = Audio.Media.getContentUri(volumeName);
    +         mVideoUri = Video.Media.getContentUri(volumeName);
    +         mImagesUri = Images.Media.getContentUri(volumeName);
    +@@ -585,16 +599,24 @@ public class MediaScanner implements AutoCloseable {
    +                     entry.mRowId = 0;
    +                 }
    + 
    +-                if (entry.mPath != null &&
    +-                        ((!mDefaultNotificationSet &&
    ++                if (entry.mPath != null) {
    ++                    if (((!mDefaultNotificationSet &&
    +                                 doesPathHaveFilename(entry.mPath, mDefaultNotificationFilename))
    +                         || (!mDefaultRingtoneSet &&
    +                                 doesPathHaveFilename(entry.mPath, mDefaultRingtoneFilename))
    +                         || (!mDefaultAlarmSet &&
    +                                 doesPathHaveFilename(entry.mPath, mDefaultAlarmAlertFilename)))) {
    +-                    Log.w(TAG, "forcing rescan of " + entry.mPath +
    +-                            "since ringtone setting didn't finish");
    +-                    scanAlways = true;
    ++                        Log.w(TAG, "forcing rescan of " + entry.mPath +
    ++                                "since ringtone setting didn't finish");
    ++                        scanAlways = true;
    ++                    } else if (isSystemSoundWithMetadata(entry.mPath)
    ++                            && !Build.FINGERPRINT.equals(sLastInternalScanFingerprint)) {
    ++                        // file is located on the system partition where the date cannot be trusted:
    ++                        // rescan if the build fingerprint has changed since the last scan.
    ++                        Log.i(TAG, "forcing rescan of " + entry.mPath
    ++                                + " since build fingerprint changed");
    ++                        scanAlways = true;
    ++                    }
    +                 }
    + 
    +                 // rescan for metadata if file was modified since last scan
    +@@ -1128,6 +1150,15 @@ public class MediaScanner implements AutoCloseable {
    + 
    +     }; // end of anonymous MediaScannerClient instance
    + 
    ++    private static boolean isSystemSoundWithMetadata(String path) {
    ++        if (path.startsWith(SYSTEM_SOUNDS_DIR + ALARMS_DIR)
    ++                || path.startsWith(SYSTEM_SOUNDS_DIR + RINGTONES_DIR)
    ++                || path.startsWith(SYSTEM_SOUNDS_DIR + NOTIFICATIONS_DIR)) {
    ++            return true;
    ++        }
    ++        return false;
    ++    }
    ++
    +     private String settingSetIndicatorName(String base) {
    +         return base + "_set";
    +     }
    +@@ -1252,16 +1283,6 @@ public class MediaScanner implements AutoCloseable {
    +         }
    +     }
    + 
    +-    private boolean inScanDirectory(String path, String[] directories) {
    +-        for (int i = 0; i < directories.length; i++) {
    +-            String directory = directories[i];
    +-            if (path.startsWith(directory)) {
    +-                return true;
    +-            }
    +-        }
    +-        return false;
    +-    }
    +-
    +     private void pruneDeadThumbnailFiles() {
    +         HashSet<String> existingFiles = new HashSet<String>();
    +         String directory = "/sdcard/DCIM/.thumbnails";
    +diff --git a/media/java/android/media/MediaScannerConnection.java b/media/java/android/media/MediaScannerConnection.java
    +index d714672..471fa2c 100644
    +--- a/media/java/android/media/MediaScannerConnection.java
    ++++ b/media/java/android/media/MediaScannerConnection.java
    +@@ -133,6 +133,10 @@ public class MediaScannerConnection implements ServiceConnection {
    +                 }
    +                 try {
    +                     mContext.unbindService(this);
    ++                    if (mClient instanceof ClientProxy) {
    ++                        mClient = null;
    ++                    }
    ++                    mService = null;
    +                 } catch (IllegalArgumentException ex) {
    +                     if (false) {
    +                         Log.v(TAG, "disconnect failed: " + ex);
    +@@ -205,6 +209,7 @@ public class MediaScannerConnection implements ServiceConnection {
    +         void scanNextPath() {
    +             if (mNextPath >= mPaths.length) {
    +                 mConnection.disconnect();
    ++                mConnection = null;
    +                 return;
    +             }
    +             String mimeType = mMimeTypes != null ? mMimeTypes[mNextPath] : null;
    +diff --git a/media/java/android/media/Ringtone.java b/media/java/android/media/Ringtone.java
    +index c2bcd93..79412d4 100644
    +--- a/media/java/android/media/Ringtone.java
    ++++ b/media/java/android/media/Ringtone.java
    +@@ -469,6 +469,7 @@ public class Ringtone {
    +             synchronized (sActiveRingtones) {
    +                 sActiveRingtones.remove(Ringtone.this);
    +             }
    ++            mp.setOnCompletionListener(null); // Help the Java GC: break the refcount cycle.
    +         }
    +     }
    + }
    +diff --git a/media/java/android/mtp/MtpDevice.java b/media/java/android/mtp/MtpDevice.java
    +index 4082778..e7ea1a5 100644
    +--- a/media/java/android/mtp/MtpDevice.java
    ++++ b/media/java/android/mtp/MtpDevice.java
    +@@ -18,11 +18,13 @@ package android.mtp;
    + 
    + import android.annotation.NonNull;
    + import android.annotation.Nullable;
    ++import android.content.Context;
    + import android.hardware.usb.UsbDevice;
    + import android.hardware.usb.UsbDeviceConnection;
    + import android.os.CancellationSignal;
    + import android.os.ParcelFileDescriptor;
    + 
    ++import android.os.UserManager;
    + import com.android.internal.util.Preconditions;
    + 
    + import java.io.IOException;
    +@@ -62,7 +64,17 @@ public final class MtpDevice {
    +      * @return true if the device was successfully opened.
    +      */
    +     public boolean open(UsbDeviceConnection connection) {
    +-        boolean result = native_open(mDevice.getDeviceName(), connection.getFileDescriptor());
    ++        boolean result = false;
    ++
    ++        Context context = connection.getContext();
    ++        if (context != null) {
    ++            UserManager userManager = (UserManager) context.getSystemService(Context.USER_SERVICE);
    ++
    ++            if (!userManager.hasUserRestriction(UserManager.DISALLOW_USB_FILE_TRANSFER)) {
    ++                result = native_open(mDevice.getDeviceName(), connection.getFileDescriptor());
    ++            }
    ++        }
    ++
    +         if (!result) {
    +             connection.close();
    +         }
    +diff --git a/media/jni/audioeffect/android_media_Visualizer.cpp b/media/jni/audioeffect/android_media_Visualizer.cpp
    +index f1a8c6f..aec31f0 100644
    +--- a/media/jni/audioeffect/android_media_Visualizer.cpp
    ++++ b/media/jni/audioeffect/android_media_Visualizer.cpp
    +@@ -435,11 +435,12 @@ setup_failure:
    + 
    + // ----------------------------------------------------------------------------
    + static void android_media_visualizer_native_release(JNIEnv *env,  jobject thiz) {
    +-    sp<Visualizer> lpVisualizer = setVisualizer(env, thiz, 0);
    +-    if (lpVisualizer == 0) {
    +-        return;
    ++    { //limit scope so that lpVisualizer is deleted before JNI storage data.
    ++        sp<Visualizer> lpVisualizer = setVisualizer(env, thiz, 0);
    ++        if (lpVisualizer == 0) {
    ++            return;
    ++        }
    +     }
    +-
    +     // delete the JNI data
    +     VisualizerJniStorage* lpJniStorage =
    +         (VisualizerJniStorage *)env->GetLongField(thiz, fields.fidJniData);
    +diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/ExifInterfaceTest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/ExifInterfaceTest.java
    +index db326ba..012041f 100644
    +--- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/ExifInterfaceTest.java
    ++++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/ExifInterfaceTest.java
    +@@ -416,7 +416,7 @@ public class ExifInterfaceTest extends AndroidTestCase {
    +             in = getContext().getAssets().open(imageFile.getName());
    +             ExifInterface exifInterface = new ExifInterface(in);
    +             exifInterface.saveAttributes();
    +-        } catch (UnsupportedOperationException e) {
    ++        } catch (IOException e) {
    +             // Expected. saveAttributes is not supported with an ExifInterface object which was
    +             // created with InputStream.
    +             return;
    +diff --git a/obex/javax/obex/ClientOperation.java b/obex/javax/obex/ClientOperation.java
    +index 883c8c6..b65598c 100644
    +--- a/obex/javax/obex/ClientOperation.java
    ++++ b/obex/javax/obex/ClientOperation.java
    +@@ -207,7 +207,6 @@ public final class ClientOperation implements Operation, BaseStream {
    +      *         object
    +      */
    +     public synchronized int getResponseCode() throws IOException {
    +-        //avoid dup validateConnection
    +         if ((mReplyHeader.responseCode == -1)
    +                 || (mReplyHeader.responseCode == ResponseCodes.OBEX_HTTP_CONTINUE)) {
    +             validateConnection();
    +@@ -423,8 +422,9 @@ public final class ClientOperation implements Operation, BaseStream {
    +     private void validateConnection() throws IOException {
    +         ensureOpen();
    + 
    +-        // to sure only one privateInput object exist.
    +-        if (mPrivateInput == null) {
    ++        // Make sure that a response has been recieved from remote
    ++        // before continuing
    ++        if (mPrivateInput == null || mReplyHeader.responseCode == -1) {
    +             startProcessing();
    +         }
    +     }
    +diff --git a/packages/CaptivePortalLogin/res/values-bn-rBD/strings.xml b/packages/CaptivePortalLogin/res/values-bn-rBD/strings.xml
    +index 20173b0..24cbfbd 100644
    +--- a/packages/CaptivePortalLogin/res/values-bn-rBD/strings.xml
    ++++ b/packages/CaptivePortalLogin/res/values-bn-rBD/strings.xml
    +@@ -4,7 +4,7 @@
    +     <string name="app_name" msgid="5934709770924185752">"CaptivePortalLogin"</string>
    +     <string name="action_use_network" msgid="6076184727448466030">"যেভাবে আছে সেভাবেই এই নেটওয়ার্ক ব্যবহার করুন"</string>
    +     <string name="action_do_not_use_network" msgid="4577366536956516683">"এই নেটওয়ার্ক ব্যবহার করবেন না"</string>
    +-    <string name="action_bar_label" msgid="917235635415966620">"নেটওয়ার্কে প্রবেশ করুন করুন"</string>
    ++    <string name="action_bar_label" msgid="917235635415966620">"নেটওয়ার্কে প্রবেশ করুন"</string>
    +     <string name="ssl_error_warning" msgid="6653188881418638872">"আপনি যে নেটওয়ার্কে যোগ দেওয়ার চেষ্টা করছেন তাতে নিরাপত্তার সমস্যা আছে।"</string>
    +     <string name="ssl_error_example" msgid="647898534624078900">"উদাহরণস্বরূপ, লগইন পৃষ্ঠাটি প্রদর্শিত প্রতিষ্ঠানের অন্তর্গত নাও হতে পারে৷"</string>
    +     <string name="ssl_error_continue" msgid="6492718244923937110">"যাই হোক না কেন ব্রাউজারের মাধ্যমে অবিরত রাখুন"</string>
    +diff --git a/packages/CaptivePortalLogin/src/com/android/captiveportallogin/CaptivePortalLoginActivity.java b/packages/CaptivePortalLogin/src/com/android/captiveportallogin/CaptivePortalLoginActivity.java
    +index b58c87a..bb8eb2c 100644
    +--- a/packages/CaptivePortalLogin/src/com/android/captiveportallogin/CaptivePortalLoginActivity.java
    ++++ b/packages/CaptivePortalLogin/src/com/android/captiveportallogin/CaptivePortalLoginActivity.java
    +@@ -115,6 +115,7 @@ public class CaptivePortalLoginActivity extends Activity {
    +         myWebView.clearCache(true);
    +         WebSettings webSettings = myWebView.getSettings();
    +         webSettings.setJavaScriptEnabled(true);
    ++        webSettings.setMixedContentMode(WebSettings.MIXED_CONTENT_COMPATIBILITY_MODE);
    +         mWebViewClient = new MyWebViewClient();
    +         myWebView.setWebViewClient(mWebViewClient);
    +         myWebView.setWebChromeClient(new MyWebChromeClient());
    +diff --git a/packages/DocumentsUI/src/com/android/documentsui/BaseActivity.java b/packages/DocumentsUI/src/com/android/documentsui/BaseActivity.java
    +index 1922773..46e7fe0 100644
    +--- a/packages/DocumentsUI/src/com/android/documentsui/BaseActivity.java
    ++++ b/packages/DocumentsUI/src/com/android/documentsui/BaseActivity.java
    +@@ -612,23 +612,13 @@ public abstract class BaseActivity extends Activity
    +             return;
    +         }
    + 
    +-        if (!mState.hasLocationChanged()) {
    +-            super.onBackPressed();
    +-            return;
    +-        }
    +-
    +-        if (onBeforePopDir() || popDir()) {
    ++        if (popDir()) {
    +             return;
    +         }
    + 
    +         super.onBackPressed();
    +     }
    + 
    +-    boolean onBeforePopDir() {
    +-        // Files app overrides this with some fancy logic.
    +-        return false;
    +-    }
    +-
    +     public void onStackPicked(DocumentStack stack) {
    +         try {
    +             // Update the restored stack to ensure we have freshest data
    +diff --git a/packages/DocumentsUI/src/com/android/documentsui/Events.java b/packages/DocumentsUI/src/com/android/documentsui/Events.java
    +index 14d4e2d..02a9127 100644
    +--- a/packages/DocumentsUI/src/com/android/documentsui/Events.java
    ++++ b/packages/DocumentsUI/src/com/android/documentsui/Events.java
    +@@ -53,7 +53,8 @@ public final class Events {
    +      */
    +     public static boolean isTouchType(int toolType) {
    +         return toolType == MotionEvent.TOOL_TYPE_FINGER
    +-                || toolType == MotionEvent.TOOL_TYPE_STYLUS;
    ++                || toolType == MotionEvent.TOOL_TYPE_STYLUS
    ++                || toolType == MotionEvent.TOOL_TYPE_UNKNOWN;
    +     }
    + 
    +     /**
    +diff --git a/packages/DocumentsUI/src/com/android/documentsui/FilesActivity.java b/packages/DocumentsUI/src/com/android/documentsui/FilesActivity.java
    +index b82f8dd..3b1ca77 100644
    +--- a/packages/DocumentsUI/src/com/android/documentsui/FilesActivity.java
    ++++ b/packages/DocumentsUI/src/com/android/documentsui/FilesActivity.java
    +@@ -60,12 +60,6 @@ public class FilesActivity extends BaseActivity {
    + 
    +     public static final String TAG = "FilesActivity";
    + 
    +-    // See comments where this const is referenced for details.
    +-    private static final int DRAWER_NO_FIDDLE_DELAY = 1500;
    +-
    +-    // Track the time we opened the drawer in response to back being pressed.
    +-    // We use the time gap to figure out whether to close app or reopen the drawer.
    +-    private long mDrawerLastFiddled;
    +     private DocumentClipper mClipper;
    + 
    +     public FilesActivity() {
    +@@ -341,8 +335,18 @@ public class FilesActivity extends BaseActivity {
    + 
    +         // Fall back to traditional VIEW action...
    +         intent = new Intent(Intent.ACTION_VIEW);
    +-        intent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
    +-        intent.setData(doc.derivedUri);
    ++        intent.setDataAndType(doc.derivedUri, doc.mimeType);
    ++
    ++        // Downloads has traditionally added the WRITE permission
    ++        // in the TrampolineActivity. Since this behavior is long
    ++        // established, we set the same permission for non-managed files
    ++        // This ensures consistent behavior between the Downloads root
    ++        // and other roots.
    ++        int flags = Intent.FLAG_GRANT_READ_URI_PERMISSION;
    ++        if (doc.isWriteSupported()) {
    ++            flags |= Intent.FLAG_GRANT_WRITE_URI_PERMISSION;
    ++        }
    ++        intent.setFlags(flags);
    + 
    +         if (DEBUG && intent.getClipData() != null) {
    +             Log.d(TAG, "Starting intent w/ clip data: " + intent.getClipData());
    +@@ -385,34 +389,6 @@ public class FilesActivity extends BaseActivity {
    +         }
    +     }
    + 
    +-    // Do some "do what a I want" drawer fiddling, but don't
    +-    // do it if user already hit back recently and we recently
    +-    // did some fiddling.
    +-    @Override
    +-    boolean onBeforePopDir() {
    +-        int size = mState.stack.size();
    +-
    +-        if (mDrawer.isPresent()
    +-                && (System.currentTimeMillis() - mDrawerLastFiddled) > DRAWER_NO_FIDDLE_DELAY) {
    +-            // Close drawer if it is open.
    +-            if (mDrawer.isOpen()) {
    +-                mDrawer.setOpen(false);
    +-                mDrawerLastFiddled = System.currentTimeMillis();
    +-                return true;
    +-            }
    +-
    +-            // Open the Close drawer if it is closed and we're at the top of a root.
    +-            if (size <= 1) {
    +-                mDrawer.setOpen(true);
    +-                // Remember so we don't just close it again if back is pressed again.
    +-                mDrawerLastFiddled = System.currentTimeMillis();
    +-                return true;
    +-            }
    +-        }
    +-
    +-        return false;
    +-    }
    +-
    +     // Turns out only DocumentsActivity was ever calling saveStackBlocking.
    +     // There may be a  case where we want to contribute entries from
    +     // Behavior here in FilesActivity, but it isn't yet obvious.
    +diff --git a/packages/DocumentsUI/src/com/android/documentsui/IconUtils.java b/packages/DocumentsUI/src/com/android/documentsui/IconUtils.java
    +index 177ba0d..d87bc11 100644
    +--- a/packages/DocumentsUI/src/com/android/documentsui/IconUtils.java
    ++++ b/packages/DocumentsUI/src/com/android/documentsui/IconUtils.java
    +@@ -42,12 +42,6 @@ public class IconUtils {
    +     public static Drawable loadMimeIcon(
    +             Context context, String mimeType, String authority, String docId, int mode) {
    +         if (Document.MIME_TYPE_DIR.equals(mimeType)) {
    +-            // TODO: eventually move these hacky assets into that package
    +-            if ("com.android.providers.media.documents".equals(authority)
    +-                    && docId.startsWith("album")) {
    +-                return context.getDrawable(R.drawable.ic_doc_album);
    +-            }
    +-
    +             if (mode == State.MODE_GRID) {
    +                 return context.getDrawable(R.drawable.ic_grid_folder);
    +             } else {
    +diff --git a/packages/DocumentsUI/src/com/android/documentsui/LocalPreferences.java b/packages/DocumentsUI/src/com/android/documentsui/LocalPreferences.java
    +index d2e9885..b3db037 100644
    +--- a/packages/DocumentsUI/src/com/android/documentsui/LocalPreferences.java
    ++++ b/packages/DocumentsUI/src/com/android/documentsui/LocalPreferences.java
    +@@ -22,6 +22,7 @@ import android.annotation.IntDef;
    + import android.annotation.Nullable;
    + import android.content.Context;
    + import android.content.SharedPreferences;
    ++import android.content.SharedPreferences.Editor;
    + import android.os.UserHandle;
    + import android.preference.PreferenceManager;
    + 
    +@@ -85,6 +86,15 @@ public class LocalPreferences {
    +     public @interface PermissionStatus {}
    + 
    +     /**
    ++     * Clears all preferences associated with a given package.
    ++     *
    ++     * <p>Typically called when a package is removed or when user asked to clear its data.
    ++     */
    ++    static void clearPackagePreferences(Context context, String packageName) {
    ++        clearScopedAccessPreferences(context, packageName);
    ++    }
    ++
    ++    /**
    +      * Methods below are used to keep track of denied user requests on scoped directory access so
    +      * the dialog is not offered when user checked the 'Do not ask again' box
    +      *
    +@@ -108,6 +118,23 @@ public class LocalPreferences {
    +       getPrefs(context).edit().putInt(key, status).apply();
    +     }
    + 
    ++    private static void clearScopedAccessPreferences(Context context, String packageName) {
    ++        final String keySubstring = "|" + packageName + "|";
    ++        final SharedPreferences prefs = getPrefs(context);
    ++        Editor editor = null;
    ++        for (final String key : prefs.getAll().keySet()) {
    ++            if (key.contains(keySubstring)) {
    ++                if (editor == null) {
    ++                    editor = prefs.edit();
    ++                }
    ++                editor.remove(key);
    ++            }
    ++        }
    ++        if (editor != null) {
    ++            editor.apply();
    ++        }
    ++    }
    ++
    +     private static String getScopedAccessDenialsKey(String packageName, String uuid,
    +             String directory) {
    +         final int userId = UserHandle.myUserId();
    +diff --git a/packages/DocumentsUI/src/com/android/documentsui/PackageReceiver.java b/packages/DocumentsUI/src/com/android/documentsui/PackageReceiver.java
    +index aef63af..fd1183f 100644
    +--- a/packages/DocumentsUI/src/com/android/documentsui/PackageReceiver.java
    ++++ b/packages/DocumentsUI/src/com/android/documentsui/PackageReceiver.java
    +@@ -23,7 +23,7 @@ import android.content.Intent;
    + import android.net.Uri;
    + 
    + /**
    +- * Clean up {@link RecentsProvider} when packages are removed.
    ++ * Cleans up {@link RecentsProvider} and {@link LocalPreferences} when packages are removed.
    +  */
    + public class PackageReceiver extends BroadcastReceiver {
    +     @Override
    +@@ -31,15 +31,19 @@ public class PackageReceiver extends BroadcastReceiver {
    +         final ContentResolver resolver = context.getContentResolver();
    + 
    +         final String action = intent.getAction();
    ++        final Uri data = intent.getData();
    ++        final String packageName = data == null ? null : data.getSchemeSpecificPart();
    ++
    +         if (Intent.ACTION_PACKAGE_FULLY_REMOVED.equals(action)) {
    +             resolver.call(RecentsProvider.buildRecent(), RecentsProvider.METHOD_PURGE, null, null);
    +-
    ++            if (packageName != null) {
    ++                LocalPreferences.clearPackagePreferences(context, packageName);
    ++            }
    +         } else if (Intent.ACTION_PACKAGE_DATA_CLEARED.equals(action)) {
    +-            final Uri data = intent.getData();
    +-            if (data != null) {
    +-                final String packageName = data.getSchemeSpecificPart();
    ++            if (packageName != null) {
    +                 resolver.call(RecentsProvider.buildRecent(), RecentsProvider.METHOD_PURGE_PACKAGE,
    +                         packageName, null);
    ++                LocalPreferences.clearPackagePreferences(context, packageName);
    +             }
    +         }
    +     }
    +diff --git a/packages/DocumentsUI/src/com/android/documentsui/RecentsLoader.java b/packages/DocumentsUI/src/com/android/documentsui/RecentsLoader.java
    +index cebc9b0..557a2f6 100644
    +--- a/packages/DocumentsUI/src/com/android/documentsui/RecentsLoader.java
    ++++ b/packages/DocumentsUI/src/com/android/documentsui/RecentsLoader.java
    +@@ -157,6 +157,9 @@ public class RecentsLoader extends AsyncTaskLoader<DirectoryResult> {
    +                     throw new RuntimeException(e);
    +                 } catch (ExecutionException e) {
    +                     // We already logged on other side
    ++                } catch (Exception e) {
    ++                    Log.e(TAG, "Failed to query Recents for authority: " + task.authority
    ++                        + ". Skip this authority in Recents.", e);
    +                 }
    +             } else {
    +                 allDone = false;
    +diff --git a/packages/DocumentsUI/src/com/android/documentsui/dirlist/DirectoryFragment.java b/packages/DocumentsUI/src/com/android/documentsui/dirlist/DirectoryFragment.java
    +index b7c0a9c..8a6723f 100644
    +--- a/packages/DocumentsUI/src/com/android/documentsui/dirlist/DirectoryFragment.java
    ++++ b/packages/DocumentsUI/src/com/android/documentsui/dirlist/DirectoryFragment.java
    +@@ -53,10 +53,13 @@ import android.provider.DocumentsContract.Document;
    + import android.support.annotation.Nullable;
    + import android.support.design.widget.Snackbar;
    + import android.support.v13.view.DragStartHelper;
    ++import android.support.v4.view.accessibility.AccessibilityNodeInfoCompat;
    ++import android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat;
    + import android.support.v7.widget.GridLayoutManager;
    + import android.support.v7.widget.GridLayoutManager.SpanSizeLookup;
    + import android.support.v7.widget.RecyclerView;
    + import android.support.v7.widget.RecyclerView.OnItemTouchListener;
    ++import android.support.v7.widget.RecyclerView.Recycler;
    + import android.support.v7.widget.RecyclerView.RecyclerListener;
    + import android.support.v7.widget.RecyclerView.ViewHolder;
    + import android.text.BidiFormatter;
    +@@ -243,7 +246,40 @@ public class DirectoryFragment extends Fragment
    + 
    +         mRecView.setAdapter(mAdapter);
    + 
    +-        mLayout = new GridLayoutManager(getContext(), mColumnCount);
    ++        // Switch Access Accessibility API needs an {@link AccessibilityDelegate} to know the proper
    ++        // route when user selects an UI element. It usually guesses this if the element has an
    ++        // {@link OnClickListener}, but since we do not have one for itemView, we will need to
    ++        // manually route it to the right behavior. RecyclerView has its own AccessibilityDelegate,
    ++        // and routes it to its LayoutManager; so we must override the LayoutManager's accessibility
    ++        // methods to route clicks correctly.
    ++        mLayout = new GridLayoutManager(getContext(), mColumnCount) {
    ++            @Override
    ++            public void onInitializeAccessibilityNodeInfoForItem(
    ++                    RecyclerView.Recycler recycler, RecyclerView.State state,
    ++                    View host, AccessibilityNodeInfoCompat info) {
    ++                super.onInitializeAccessibilityNodeInfoForItem(recycler, state, host, info);
    ++                info.addAction(AccessibilityActionCompat.ACTION_CLICK);
    ++            }
    ++
    ++            @Override
    ++            public boolean performAccessibilityActionForItem(
    ++                    RecyclerView.Recycler recycler, RecyclerView.State state, View view,
    ++                    int action, Bundle args) {
    ++                // We are only handling click events; route all other to default implementation
    ++                if (action == AccessibilityNodeInfoCompat.ACTION_CLICK) {
    ++                    RecyclerView.ViewHolder vh = mRecView.getChildViewHolder(view);
    ++                    if (vh instanceof DocumentHolder) {
    ++                        DocumentHolder dh = (DocumentHolder) vh;
    ++                        if (dh.mEventListener != null) {
    ++                            dh.mEventListener.onActivate(dh);
    ++                            return true;
    ++                        }
    ++                    }
    ++                }
    ++                return super.performAccessibilityActionForItem(recycler, state, view, action,
    ++                        args);
    ++            }
    ++        };
    +         SpanSizeLookup lookup = mAdapter.createSpanSizeLookup();
    +         if (lookup != null) {
    +             mLayout.setSpanSizeLookup(lookup);
    +@@ -717,63 +753,57 @@ public class DirectoryFragment extends Fragment
    +     private void openDocuments(final Selection selected) {
    +         Metrics.logUserAction(getContext(), Metrics.USER_ACTION_OPEN);
    + 
    +-        new GetDocumentsTask() {
    +-            @Override
    +-            void onDocumentsReady(List<DocumentInfo> docs) {
    +-                // TODO: Implement support in Files activity for opening multiple docs.
    +-                BaseActivity.get(DirectoryFragment.this).onDocumentsPicked(docs);
    +-            }
    +-        }.execute(selected);
    ++        // Model must be accessed in UI thread, since underlying cursor is not threadsafe.
    ++        List<DocumentInfo> docs = mModel.getDocuments(selected);
    ++        // TODO: Implement support in Files activity for opening multiple docs.
    ++        BaseActivity.get(DirectoryFragment.this).onDocumentsPicked(docs);
    +     }
    + 
    +     private void shareDocuments(final Selection selected) {
    +         Metrics.logUserAction(getContext(), Metrics.USER_ACTION_SHARE);
    + 
    +-        new GetDocumentsTask() {
    +-            @Override
    +-            void onDocumentsReady(List<DocumentInfo> docs) {
    +-                Intent intent;
    +-
    +-                // Filter out directories and virtual files - those can't be shared.
    +-                List<DocumentInfo> docsForSend = new ArrayList<>();
    +-                for (DocumentInfo doc: docs) {
    +-                    if (!doc.isDirectory() && !doc.isVirtualDocument()) {
    +-                        docsForSend.add(doc);
    +-                    }
    +-                }
    ++        // Model must be accessed in UI thread, since underlying cursor is not threadsafe.
    ++        List<DocumentInfo> docs = mModel.getDocuments(selected);
    ++        Intent intent;
    + 
    +-                if (docsForSend.size() == 1) {
    +-                    final DocumentInfo doc = docsForSend.get(0);
    +-
    +-                    intent = new Intent(Intent.ACTION_SEND);
    +-                    intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
    +-                    intent.addCategory(Intent.CATEGORY_DEFAULT);
    +-                    intent.setType(doc.mimeType);
    +-                    intent.putExtra(Intent.EXTRA_STREAM, doc.derivedUri);
    +-
    +-                } else if (docsForSend.size() > 1) {
    +-                    intent = new Intent(Intent.ACTION_SEND_MULTIPLE);
    +-                    intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
    +-                    intent.addCategory(Intent.CATEGORY_DEFAULT);
    +-
    +-                    final ArrayList<String> mimeTypes = new ArrayList<>();
    +-                    final ArrayList<Uri> uris = new ArrayList<>();
    +-                    for (DocumentInfo doc : docsForSend) {
    +-                        mimeTypes.add(doc.mimeType);
    +-                        uris.add(doc.derivedUri);
    +-                    }
    ++        // Filter out directories and virtual files - those can't be shared.
    ++        List<DocumentInfo> docsForSend = new ArrayList<>();
    ++        for (DocumentInfo doc: docs) {
    ++            if (!doc.isDirectory() && !doc.isVirtualDocument()) {
    ++                docsForSend.add(doc);
    ++            }
    ++        }
    + 
    +-                    intent.setType(findCommonMimeType(mimeTypes));
    +-                    intent.putParcelableArrayListExtra(Intent.EXTRA_STREAM, uris);
    ++        if (docsForSend.size() == 1) {
    ++            final DocumentInfo doc = docsForSend.get(0);
    + 
    +-                } else {
    +-                    return;
    +-                }
    ++            intent = new Intent(Intent.ACTION_SEND);
    ++            intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
    ++            intent.addCategory(Intent.CATEGORY_DEFAULT);
    ++            intent.setType(doc.mimeType);
    ++            intent.putExtra(Intent.EXTRA_STREAM, doc.derivedUri);
    ++
    ++        } else if (docsForSend.size() > 1) {
    ++            intent = new Intent(Intent.ACTION_SEND_MULTIPLE);
    ++            intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
    ++            intent.addCategory(Intent.CATEGORY_DEFAULT);
    + 
    +-                intent = Intent.createChooser(intent, getActivity().getText(R.string.share_via));
    +-                startActivity(intent);
    ++            final ArrayList<String> mimeTypes = new ArrayList<>();
    ++            final ArrayList<Uri> uris = new ArrayList<>();
    ++            for (DocumentInfo doc : docsForSend) {
    ++                mimeTypes.add(doc.mimeType);
    ++                uris.add(doc.derivedUri);
    +             }
    +-        }.execute(selected);
    ++
    ++            intent.setType(findCommonMimeType(mimeTypes));
    ++            intent.putParcelableArrayListExtra(Intent.EXTRA_STREAM, uris);
    ++
    ++        } else {
    ++            return;
    ++        }
    ++
    ++        intent = Intent.createChooser(intent, getActivity().getText(R.string.share_via));
    ++        startActivity(intent);
    +     }
    + 
    +     private String generateDeleteMessage(final List<DocumentInfo> docs) {
    +@@ -819,52 +849,51 @@ public class DirectoryFragment extends Fragment
    +         assert(!selected.isEmpty());
    + 
    +         final DocumentInfo srcParent = getDisplayState().stack.peek();
    +-        new GetDocumentsTask() {
    +-            @Override
    +-            void onDocumentsReady(final List<DocumentInfo> docs) {
    +-
    +-                TextView message =
    +-                        (TextView) mInflater.inflate(R.layout.dialog_delete_confirmation, null);
    +-                message.setText(generateDeleteMessage(docs));
    +-
    +-                // This "insta-hides" files that are being deleted, because
    +-                // the delete operation may be not execute immediately (it
    +-                // may be queued up on the FileOperationService.)
    +-                // To hide the files locally, we call the hide method on the adapter
    +-                // ...which a live object...cannot be parceled.
    +-                // For that reason, for now, we implement this dialog NOT
    +-                // as a fragment (which can survive rotation and have its own state),
    +-                // but as a simple runtime dialog. So rotating a device with an
    +-                // active delete dialog...results in that dialog disappearing.
    +-                // We can do better, but don't have cycles for it now.
    +-                new AlertDialog.Builder(getActivity())
    +-                    .setView(message)
    +-                    .setPositiveButton(
    +-                         android.R.string.yes,
    +-                         new DialogInterface.OnClickListener() {
    +-                            public void onClick(DialogInterface dialog, int id) {
    +-                                // Finish selection mode first which clears selection so we
    +-                                // don't end up trying to deselect deleted documents.
    +-                                // This is done here, rather in the onActionItemClicked
    +-                                // so we can avoid de-selecting items in the case where
    +-                                // the user cancels the delete.
    +-                                if (mActionMode != null) {
    +-                                    mActionMode.finish();
    +-                                } else {
    +-                                    Log.w(TAG, "Action mode is null before deleting documents.");
    +-                                }
    +-                                // Hide the files in the UI...since the operation
    +-                                // might be queued up on FileOperationService.
    +-                                // We're walking a line here.
    +-                                mAdapter.hide(selected.getAll());
    +-                                FileOperations.delete(
    +-                                        getActivity(), docs, srcParent, getDisplayState().stack);
    +-                            }
    +-                        })
    +-                    .setNegativeButton(android.R.string.no, null)
    +-                    .show();
    +-            }
    +-        }.execute(selected);
    ++
    ++        // Model must be accessed in UI thread, since underlying cursor is not threadsafe.
    ++        List<DocumentInfo> docs = mModel.getDocuments(selected);
    ++
    ++        TextView message =
    ++                (TextView) mInflater.inflate(R.layout.dialog_delete_confirmation, null);
    ++        message.setText(generateDeleteMessage(docs));
    ++
    ++        // This "insta-hides" files that are being deleted, because
    ++        // the delete operation may be not execute immediately (it
    ++        // may be queued up on the FileOperationService.)
    ++        // To hide the files locally, we call the hide method on the adapter
    ++        // ...which a live object...cannot be parceled.
    ++        // For that reason, for now, we implement this dialog NOT
    ++        // as a fragment (which can survive rotation and have its own state),
    ++        // but as a simple runtime dialog. So rotating a device with an
    ++        // active delete dialog...results in that dialog disappearing.
    ++        // We can do better, but don't have cycles for it now.
    ++        new AlertDialog.Builder(getActivity())
    ++            .setView(message)
    ++            .setPositiveButton(
    ++                 android.R.string.yes,
    ++                 new DialogInterface.OnClickListener() {
    ++                    @Override
    ++                    public void onClick(DialogInterface dialog, int id) {
    ++                        // Finish selection mode first which clears selection so we
    ++                        // don't end up trying to deselect deleted documents.
    ++                        // This is done here, rather in the onActionItemClicked
    ++                        // so we can avoid de-selecting items in the case where
    ++                        // the user cancels the delete.
    ++                        if (mActionMode != null) {
    ++                            mActionMode.finish();
    ++                        } else {
    ++                            Log.w(TAG, "Action mode is null before deleting documents.");
    ++                        }
    ++                        // Hide the files in the UI...since the operation
    ++                        // might be queued up on FileOperationService.
    ++                        // We're walking a line here.
    ++                        mAdapter.hide(selected.getAll());
    ++                        FileOperations.delete(
    ++                                getActivity(), docs, srcParent, getDisplayState().stack);
    ++                    }
    ++                })
    ++            .setNegativeButton(android.R.string.no, null)
    ++            .show();
    +     }
    + 
    +     private void transferDocuments(final Selection selected, final @OpType int mode) {
    +@@ -898,25 +927,21 @@ public class DirectoryFragment extends Fragment
    +                 ? R.string.menu_move : R.string.menu_copy;
    +         intent.putExtra(DocumentsContract.EXTRA_PROMPT, getResources().getString(drawerTitleId));
    + 
    +-        new GetDocumentsTask() {
    +-            @Override
    +-            void onDocumentsReady(List<DocumentInfo> docs) {
    +-                // TODO: Can this move to Fragment bundle state?
    +-                getDisplayState().selectedDocumentsForCopy = docs;
    +-
    +-                // Determine if there is a directory in the set of documents
    +-                // to be copied? Why? Directory creation isn't supported by some roots
    +-                // (like Downloads). This informs DocumentsActivity (the "picker")
    +-                // to restrict available roots to just those with support.
    +-                intent.putExtra(Shared.EXTRA_DIRECTORY_COPY, hasDirectory(docs));
    +-                intent.putExtra(FileOperationService.EXTRA_OPERATION, mode);
    +-
    +-                // This just identifies the type of request...we'll check it
    +-                // when we reveive a response.
    +-                startActivityForResult(intent, REQUEST_COPY_DESTINATION);
    +-            }
    ++        // Model must be accessed in UI thread, since underlying cursor is not threadsafe.
    ++        List<DocumentInfo> docs = mModel.getDocuments(selected);
    ++        // TODO: Can this move to Fragment bundle state?
    ++        getDisplayState().selectedDocumentsForCopy = docs;
    ++
    ++        // Determine if there is a directory in the set of documents
    ++        // to be copied? Why? Directory creation isn't supported by some roots
    ++        // (like Downloads). This informs DocumentsActivity (the "picker")
    ++        // to restrict available roots to just those with support.
    ++        intent.putExtra(Shared.EXTRA_DIRECTORY_COPY, hasDirectory(docs));
    ++        intent.putExtra(FileOperationService.EXTRA_OPERATION, mode);
    + 
    +-        }.execute(selected);
    ++        // This just identifies the type of request...we'll check it
    ++        // when we reveive a response.
    ++        startActivityForResult(intent, REQUEST_COPY_DESTINATION);
    +     }
    + 
    +     private static boolean hasDirectory(List<DocumentInfo> docs) {
    +@@ -935,12 +960,9 @@ public class DirectoryFragment extends Fragment
    +         // Rename option is only available in menu when 1 document selected
    +         assert(selected.size() == 1);
    + 
    +-        new GetDocumentsTask() {
    +-            @Override
    +-            void onDocumentsReady(List<DocumentInfo> docs) {
    +-                RenameDocumentFragment.show(getFragmentManager(), docs.get(0));
    +-            }
    +-        }.execute(selected);
    ++        // Model must be accessed in UI thread, since underlying cursor is not threadsafe.
    ++        List<DocumentInfo> docs = mModel.getDocuments(selected);
    ++        RenameDocumentFragment.show(getFragmentManager(), docs.get(0));
    +     }
    + 
    +     @Override
    +@@ -1099,19 +1121,17 @@ public class DirectoryFragment extends Fragment
    +         }
    +     }
    + 
    +-    void copySelectionToClipboard(Selection selection) {
    +-        assert(!selection.isEmpty());
    +-        new GetDocumentsTask() {
    +-            @Override
    +-            void onDocumentsReady(List<DocumentInfo> docs) {
    +-                mClipper.clipDocuments(docs);
    +-                Activity activity = getActivity();
    +-                Snackbars.makeSnackbar(activity,
    +-                        activity.getResources().getQuantityString(
    +-                                R.plurals.clipboard_files_clipped, docs.size(), docs.size()),
    +-                        Snackbar.LENGTH_SHORT).show();
    +-            }
    +-        }.execute(selection);
    ++    void copySelectionToClipboard(Selection selected) {
    ++        assert(!selected.isEmpty());
    ++
    ++        // Model must be accessed in UI thread, since underlying cursor is not threadsafe.
    ++        List<DocumentInfo> docs = mModel.getDocuments(selected);
    ++        mClipper.clipDocuments(docs);
    ++        Activity activity = getActivity();
    ++        Snackbars.makeSnackbar(activity,
    ++                activity.getResources().getQuantityString(
    ++                        R.plurals.clipboard_files_clipped, docs.size(), docs.size()),
    ++                Snackbar.LENGTH_SHORT).show();
    +     }
    + 
    +     public void pasteFromClipboard() {
    +@@ -1420,25 +1440,6 @@ public class DirectoryFragment extends Fragment
    +             mShadowView.draw(canvas);
    +         }
    +     }
    +-    /**
    +-     * Abstract task providing support for loading documents *off*
    +-     * the main thread. And if it isn't obvious, creating a list
    +-     * of documents (especially large lists) can be pretty expensive.
    +-     */
    +-    private abstract class GetDocumentsTask
    +-            extends AsyncTask<Selection, Void, List<DocumentInfo>> {
    +-        @Override
    +-        protected final List<DocumentInfo> doInBackground(Selection... selected) {
    +-            return mModel.getDocuments(selected[0]);
    +-        }
    +-
    +-        @Override
    +-        protected final void onPostExecute(List<DocumentInfo> docs) {
    +-            onDocumentsReady(docs);
    +-        }
    +-
    +-        abstract void onDocumentsReady(List<DocumentInfo> docs);
    +-    }
    + 
    +     @Override
    +     public boolean isSelected(String modelId) {
    +diff --git a/packages/DocumentsUI/src/com/android/documentsui/dirlist/Model.java b/packages/DocumentsUI/src/com/android/documentsui/dirlist/Model.java
    +index 0a2960f..94b8277 100644
    +--- a/packages/DocumentsUI/src/com/android/documentsui/dirlist/Model.java
    ++++ b/packages/DocumentsUI/src/com/android/documentsui/dirlist/Model.java
    +@@ -107,7 +107,13 @@ public class Model {
    +         mSortOrder = result.sortOrder;
    +         doc = result.doc;
    + 
    +-        updateModelData();
    ++        try {
    ++            updateModelData();
    ++        } catch (Exception e) {
    ++            Log.e(TAG, "Error while accessing cursors", e);
    ++            notifyUpdateListeners(e);
    ++            return;
    ++        }
    + 
    +         final Bundle extras = mCursor.getExtras();
    +         if (extras != null) {
    +diff --git a/packages/DocumentsUI/src/com/android/documentsui/model/DocumentInfo.java b/packages/DocumentsUI/src/com/android/documentsui/model/DocumentInfo.java
    +index 3a86a51..63f66de 100644
    +--- a/packages/DocumentsUI/src/com/android/documentsui/model/DocumentInfo.java
    ++++ b/packages/DocumentsUI/src/com/android/documentsui/model/DocumentInfo.java
    +@@ -235,6 +235,10 @@ public class DocumentInfo implements Durable, Parcelable {
    +         return (flags & Document.FLAG_DIR_PREFERS_GRID) != 0;
    +     }
    + 
    ++    public boolean isWriteSupported() {
    ++        return (flags & Document.FLAG_SUPPORTS_WRITE) != 0;
    ++    }
    ++
    +     public boolean isDeleteSupported() {
    +         return (flags & Document.FLAG_SUPPORTS_DELETE) != 0;
    +     }
    +diff --git a/packages/DocumentsUI/src/com/android/documentsui/services/MoveJob.java b/packages/DocumentsUI/src/com/android/documentsui/services/MoveJob.java
    +index 1118171..1de3bbc 100644
    +--- a/packages/DocumentsUI/src/com/android/documentsui/services/MoveJob.java
    ++++ b/packages/DocumentsUI/src/com/android/documentsui/services/MoveJob.java
    +@@ -117,7 +117,9 @@ final class MoveJob extends CopyJob {
    +         byteCopyDocument(src, dest);
    + 
    +         // Remove the source document.
    +-        deleteDocument(src, srcParent);
    ++        if(!isCanceled()) {
    ++            deleteDocument(src, srcParent);
    ++        }
    +     }
    + 
    +     @Override
    +diff --git a/packages/EasterEgg/src/com/android/egg/neko/NekoService.java b/packages/EasterEgg/src/com/android/egg/neko/NekoService.java
    +index 32e3358..808ec36 100644
    +--- a/packages/EasterEgg/src/com/android/egg/neko/NekoService.java
    ++++ b/packages/EasterEgg/src/com/android/egg/neko/NekoService.java
    +@@ -102,6 +102,14 @@ public class NekoService extends JobService {
    +         return false;
    +     }
    + 
    ++    public static void registerJobIfNeeded(Context context, long intervalMinutes) {
    ++        JobScheduler jss = context.getSystemService(JobScheduler.class);
    ++        JobInfo info = jss.getPendingJob(JOB_ID);
    ++        if (info == null) {
    ++            registerJob(context, intervalMinutes);
    ++        }
    ++    }
    ++
    +     public static void registerJob(Context context, long intervalMinutes) {
    +         JobScheduler jss = context.getSystemService(JobScheduler.class);
    +         jss.cancel(JOB_ID);
    +diff --git a/packages/EasterEgg/src/com/android/egg/neko/NekoTile.java b/packages/EasterEgg/src/com/android/egg/neko/NekoTile.java
    +index 8a3ec8f..159b40a 100644
    +--- a/packages/EasterEgg/src/com/android/egg/neko/NekoTile.java
    ++++ b/packages/EasterEgg/src/com/android/egg/neko/NekoTile.java
    +@@ -68,6 +68,9 @@ public class NekoTile extends TileService implements PrefsListener {
    +         Tile tile = getQsTile();
    +         int foodState = mPrefs.getFoodState();
    +         Food food = new Food(foodState);
    ++        if (foodState != 0) {
    ++            NekoService.registerJobIfNeeded(this, food.getInterval(this));
    ++        }
    +         tile.setIcon(food.getIcon(this));
    +         tile.setLabel(food.getName(this));
    +         tile.setState(foodState != 0 ? Tile.STATE_ACTIVE : Tile.STATE_INACTIVE);
    +diff --git a/packages/EasterEgg/src/com/android/egg/neko/PrefState.java b/packages/EasterEgg/src/com/android/egg/neko/PrefState.java
    +index 5f54180..bf71b19 100644
    +--- a/packages/EasterEgg/src/com/android/egg/neko/PrefState.java
    ++++ b/packages/EasterEgg/src/com/android/egg/neko/PrefState.java
    +@@ -43,13 +43,11 @@ public class PrefState implements OnSharedPreferenceChangeListener {
    +     public void addCat(Cat cat) {
    +         mPrefs.edit()
    +               .putString(CAT_KEY_PREFIX + String.valueOf(cat.getSeed()), cat.getName())
    +-              .commit();
    ++              .apply();
    +     }
    + 
    +     public void removeCat(Cat cat) {
    +-        mPrefs.edit()
    +-                .remove(CAT_KEY_PREFIX + String.valueOf(cat.getSeed()))
    +-                .commit();
    ++        mPrefs.edit().remove(CAT_KEY_PREFIX + String.valueOf(cat.getSeed())).apply();
    +     }
    + 
    +     public List<Cat> getCats() {
    +@@ -71,7 +69,7 @@ public class PrefState implements OnSharedPreferenceChangeListener {
    +     }
    + 
    +     public void setFoodState(int foodState) {
    +-        mPrefs.edit().putInt(FOOD_STATE, foodState).commit();
    ++        mPrefs.edit().putInt(FOOD_STATE, foodState).apply();
    +     }
    + 
    +     public void setListener(PrefsListener listener) {
    +diff --git a/packages/ExternalStorageProvider/src/com/android/externalstorage/ExternalStorageProvider.java b/packages/ExternalStorageProvider/src/com/android/externalstorage/ExternalStorageProvider.java
    +index 78b9927..3ef9b8e 100644
    +--- a/packages/ExternalStorageProvider/src/com/android/externalstorage/ExternalStorageProvider.java
    ++++ b/packages/ExternalStorageProvider/src/com/android/externalstorage/ExternalStorageProvider.java
    +@@ -466,10 +466,7 @@ public class ExternalStorageProvider extends DocumentsProvider {
    +         displayName = FileUtils.buildValidFatFilename(displayName);
    + 
    +         final File before = getFileForDocId(docId);
    +-        final File after = new File(before.getParentFile(), displayName);
    +-        if (after.exists()) {
    +-            throw new IllegalStateException("Already exists " + after);
    +-        }
    ++        final File after = FileUtils.buildUniqueFile(before.getParentFile(), displayName);
    +         if (!before.renameTo(after)) {
    +             throw new IllegalStateException("Failed to rename to " + after);
    +         }
    +@@ -566,6 +563,7 @@ public class ExternalStorageProvider extends DocumentsProvider {
    +             throws FileNotFoundException {
    +         final MatrixCursor result = new MatrixCursor(resolveDocumentProjection(projection));
    + 
    ++        query = query.toLowerCase();
    +         final File parent;
    +         synchronized (mRootsLock) {
    +             parent = mRoots.get(rootId).path;
    +diff --git a/packages/Keyguard/src/com/android/keyguard/EmergencyButton.java b/packages/Keyguard/src/com/android/keyguard/EmergencyButton.java
    +index 8d41145..0474df7 100644
    +--- a/packages/Keyguard/src/com/android/keyguard/EmergencyButton.java
    ++++ b/packages/Keyguard/src/com/android/keyguard/EmergencyButton.java
    +@@ -28,13 +28,16 @@ import android.os.UserHandle;
    + import android.telecom.TelecomManager;
    + import android.util.AttributeSet;
    + import android.util.Slog;
    ++import android.view.MotionEvent;
    + import android.view.View;
    ++import android.view.ViewConfiguration;
    + import android.widget.Button;
    + 
    + import com.android.internal.logging.MetricsLogger;
    + import com.android.internal.logging.MetricsProto.MetricsEvent;
    + import com.android.internal.telephony.IccCardConstants.State;
    + import com.android.internal.widget.LockPatternUtils;
    ++import com.android.internal.policy.EmergencyAffordanceManager;
    + 
    + /**
    +  * This class implements a smart emergency button that updates itself based
    +@@ -51,7 +54,10 @@ public class EmergencyButton extends Button {
    +                     | Intent.FLAG_ACTIVITY_CLEAR_TOP);
    + 
    +     private static final String LOG_TAG = "EmergencyButton";
    ++    private final EmergencyAffordanceManager mEmergencyAffordanceManager;
    + 
    ++    private int mDownX;
    ++    private int mDownY;
    +     KeyguardUpdateMonitorCallback mInfoCallback = new KeyguardUpdateMonitorCallback() {
    + 
    +         @Override
    +@@ -64,6 +70,7 @@ public class EmergencyButton extends Button {
    +             updateEmergencyCallButton();
    +         }
    +     };
    ++    private boolean mLongPressWasDragged;
    + 
    +     public interface EmergencyButtonCallback {
    +         public void onEmergencyButtonClickedWhenInCall();
    +@@ -86,6 +93,7 @@ public class EmergencyButton extends Button {
    +                 com.android.internal.R.bool.config_voice_capable);
    +         mEnableEmergencyCallWhileSimLocked = mContext.getResources().getBoolean(
    +                 com.android.internal.R.bool.config_enable_emergency_call_while_sim_locked);
    ++        mEmergencyAffordanceManager = new EmergencyAffordanceManager(context);
    +     }
    + 
    +     @Override
    +@@ -110,10 +118,45 @@ public class EmergencyButton extends Button {
    +                 takeEmergencyCallAction();
    +             }
    +         });
    ++        setOnLongClickListener(new OnLongClickListener() {
    ++            @Override
    ++            public boolean onLongClick(View v) {
    ++                if (!mLongPressWasDragged
    ++                        && mEmergencyAffordanceManager.needsEmergencyAffordance()) {
    ++                    mEmergencyAffordanceManager.performEmergencyCall();
    ++                    return true;
    ++                }
    ++                return false;
    ++            }
    ++        });
    +         updateEmergencyCallButton();
    +     }
    + 
    +     @Override
    ++    public boolean onTouchEvent(MotionEvent event) {
    ++        final int x = (int) event.getX();
    ++        final int y = (int) event.getY();
    ++        if (event.getActionMasked() == MotionEvent.ACTION_DOWN) {
    ++            mDownX = x;
    ++            mDownY = y;
    ++            mLongPressWasDragged = false;
    ++        } else {
    ++            final int xDiff = Math.abs(x - mDownX);
    ++            final int yDiff = Math.abs(y - mDownY);
    ++            int touchSlop = ViewConfiguration.get(mContext).getScaledTouchSlop();
    ++            if (Math.abs(yDiff) > touchSlop || Math.abs(xDiff) > touchSlop) {
    ++                mLongPressWasDragged = true;
    ++            }
    ++        }
    ++        return super.onTouchEvent(event);
    ++    }
    ++
    ++    @Override
    ++    public boolean performLongClick() {
    ++        return super.performLongClick();
    ++    }
    ++
    ++    @Override
    +     protected void onConfigurationChanged(Configuration newConfig) {
    +         super.onConfigurationChanged(newConfig);
    +         updateEmergencyCallButton();
    +diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardPINView.java b/packages/Keyguard/src/com/android/keyguard/KeyguardPINView.java
    +index 4f5152a..285b1ae 100644
    +--- a/packages/Keyguard/src/com/android/keyguard/KeyguardPINView.java
    ++++ b/packages/Keyguard/src/com/android/keyguard/KeyguardPINView.java
    +@@ -16,12 +16,8 @@
    + 
    + package com.android.keyguard;
    + 
    +-import android.animation.Animator;
    +-import android.animation.ObjectAnimator;
    + import android.content.Context;
    + import android.util.AttributeSet;
    +-import android.view.RenderNode;
    +-import android.view.RenderNodeAnimator;
    + import android.view.View;
    + import android.view.ViewGroup;
    + import android.view.animation.AnimationUtils;
    +@@ -144,9 +140,10 @@ public class KeyguardPINView extends KeyguardPinBasedInputView {
    +         setTranslationY(0);
    +         AppearAnimationUtils.startTranslationYAnimation(this, 0 /* delay */, 280 /* duration */,
    +                 mDisappearYTranslation, mDisappearAnimationUtils.getInterpolator());
    +-        DisappearAnimationUtils disappearAnimationUtils = mKeyguardUpdateMonitor.isUserUnlocked()
    +-                ? mDisappearAnimationUtils
    +-                : mDisappearAnimationUtilsLocked;
    ++        DisappearAnimationUtils disappearAnimationUtils = mKeyguardUpdateMonitor
    ++                .needsSlowUnlockTransition()
    ++                        ? mDisappearAnimationUtilsLocked
    ++                        : mDisappearAnimationUtils;
    +         disappearAnimationUtils.startAnimation2d(mViews,
    +                 new Runnable() {
    +                     @Override
    +diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardPatternView.java b/packages/Keyguard/src/com/android/keyguard/KeyguardPatternView.java
    +index 84b90c4..506f77d 100644
    +--- a/packages/Keyguard/src/com/android/keyguard/KeyguardPatternView.java
    ++++ b/packages/Keyguard/src/com/android/keyguard/KeyguardPatternView.java
    +@@ -408,9 +408,9 @@ public class KeyguardPatternView extends LinearLayout implements KeyguardSecurit
    + 
    +     @Override
    +     public boolean startDisappearAnimation(final Runnable finishRunnable) {
    +-        float durationMultiplier = mKeyguardUpdateMonitor.isUserUnlocked()
    +-                ? 1f
    +-                : DISAPPEAR_MULTIPLIER_LOCKED;
    ++        float durationMultiplier = mKeyguardUpdateMonitor.needsSlowUnlockTransition()
    ++                ? DISAPPEAR_MULTIPLIER_LOCKED
    ++                : 1f;
    +         mLockPatternView.clearPattern();
    +         enableClipping(false);
    +         setTranslationY(0);
    +@@ -419,9 +419,10 @@ public class KeyguardPatternView extends LinearLayout implements KeyguardSecurit
    +                 -mDisappearAnimationUtils.getStartTranslation(),
    +                 mDisappearAnimationUtils.getInterpolator());
    + 
    +-        DisappearAnimationUtils disappearAnimationUtils = mKeyguardUpdateMonitor.isUserUnlocked()
    +-                ? mDisappearAnimationUtils
    +-                : mDisappearAnimationUtilsLocked;
    ++        DisappearAnimationUtils disappearAnimationUtils = mKeyguardUpdateMonitor
    ++                .needsSlowUnlockTransition()
    ++                        ? mDisappearAnimationUtilsLocked
    ++                        : mDisappearAnimationUtils;
    +         disappearAnimationUtils.startAnimation2d(mLockPatternView.getCellStates(),
    +                 () -> {
    +                     enableClipping(true);
    +diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitor.java b/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitor.java
    +index 56f3741..a9f6dc9 100644
    +--- a/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitor.java
    ++++ b/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitor.java
    +@@ -16,6 +16,7 @@
    + 
    + package com.android.keyguard;
    + 
    ++import static android.content.Intent.ACTION_USER_UNLOCKED;
    + import static android.os.BatteryManager.BATTERY_HEALTH_UNKNOWN;
    + import static android.os.BatteryManager.BATTERY_STATUS_FULL;
    + import static android.os.BatteryManager.BATTERY_STATUS_UNKNOWN;
    +@@ -34,9 +35,12 @@ import android.app.PendingIntent;
    + import android.app.admin.DevicePolicyManager;
    + import android.app.trust.TrustManager;
    + import android.content.BroadcastReceiver;
    ++import android.content.ComponentName;
    + import android.content.Context;
    + import android.content.Intent;
    + import android.content.IntentFilter;
    ++import android.content.pm.PackageManager;
    ++import android.content.pm.ResolveInfo;
    + import android.database.ContentObserver;
    + import android.graphics.Bitmap;
    + import android.hardware.fingerprint.FingerprintManager;
    +@@ -108,12 +112,6 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener {
    + 
    +     private static final String PERMISSION_SELF = "com.android.systemui.permission.SELF";
    + 
    +-    /**
    +-     * Milliseconds after unlocking with fingerprint times out, i.e. the user has to use a
    +-     * strong auth method like password, PIN or pattern.
    +-     */
    +-    private static final long FINGERPRINT_UNLOCK_TIMEOUT_MS = 72 * 60 * 60 * 1000;
    +-
    +     // Callback messages
    +     private static final int MSG_TIME_UPDATE = 301;
    +     private static final int MSG_BATTERY_UPDATE = 302;
    +@@ -138,6 +136,8 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener {
    +     private static final int MSG_SERVICE_STATE_CHANGE = 330;
    +     private static final int MSG_SCREEN_TURNED_ON = 331;
    +     private static final int MSG_SCREEN_TURNED_OFF = 332;
    ++    private static final int MSG_DREAMING_STATE_CHANGED = 333;
    ++    private static final int MSG_USER_UNLOCKED = 334;
    + 
    +     /** Fingerprint state: Not listening to fingerprint. */
    +     private static final int FINGERPRINT_STATE_STOPPED = 0;
    +@@ -159,6 +159,9 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener {
    + 
    +     private static final int DEFAULT_CHARGING_VOLTAGE_MICRO_VOLT = 5000000;
    + 
    ++    private static final ComponentName FALLBACK_HOME_COMPONENT = new ComponentName(
    ++            "com.android.settings", "com.android.settings.FallbackHome");
    ++
    +     private static KeyguardUpdateMonitor sInstance;
    + 
    +     private final Context mContext;
    +@@ -177,7 +180,7 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener {
    +     private boolean mGoingToSleep;
    +     private boolean mBouncer;
    +     private boolean mBootCompleted;
    +-    private boolean mUserUnlocked;
    ++    private boolean mNeedsSlowUnlockTransition;
    +     private boolean mHasLockscreenWallpaper;
    + 
    +     // Device provisioning state
    +@@ -287,6 +290,12 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener {
    +                     handleScreenTurnedOff();
    +                     Trace.endSection();
    +                     break;
    ++                case MSG_DREAMING_STATE_CHANGED:
    ++                    handleDreamingStateChanged(msg.arg1);
    ++                    break;
    ++                case MSG_USER_UNLOCKED:
    ++                    handleUserUnlocked();
    ++                    break;
    +             }
    +         }
    +     };
    +@@ -380,7 +389,7 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener {
    +     }
    + 
    +     /** @return List of SubscriptionInfo records, maybe empty but never null */
    +-    List<SubscriptionInfo> getSubscriptionInfo(boolean forceReload) {
    ++    public List<SubscriptionInfo> getSubscriptionInfo(boolean forceReload) {
    +         List<SubscriptionInfo> sil = mSubscriptionInfo;
    +         if (sil == null || forceReload) {
    +             sil = mSubscriptionManager.getActiveSubscriptionInfoList();
    +@@ -572,8 +581,8 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener {
    +                 && !hasFingerprintUnlockTimedOut(sCurrentUser);
    +     }
    + 
    +-    public boolean isUserUnlocked() {
    +-        return mUserUnlocked;
    ++    public boolean needsSlowUnlockTransition() {
    ++        return mNeedsSlowUnlockTransition;
    +     }
    + 
    +     public StrongAuthTracker getStrongAuthTracker() {
    +@@ -598,7 +607,10 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener {
    +     }
    + 
    +     private void scheduleStrongAuthTimeout() {
    +-        long when = SystemClock.elapsedRealtime() + FINGERPRINT_UNLOCK_TIMEOUT_MS;
    ++        final DevicePolicyManager dpm =
    ++                (DevicePolicyManager) mContext.getSystemService(Context.DEVICE_POLICY_SERVICE);
    ++        long when = SystemClock.elapsedRealtime() + dpm.getRequiredStrongAuthTimeout(null,
    ++                sCurrentUser);
    +         Intent intent = new Intent(ACTION_STRONG_AUTH_TIMEOUT);
    +         intent.putExtra(USER_ID, sCurrentUser);
    +         PendingIntent sender = PendingIntent.getBroadcast(mContext,
    +@@ -716,6 +728,8 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener {
    +             } else if (DevicePolicyManager.ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED
    +                     .equals(action)) {
    +                 mHandler.sendEmptyMessage(MSG_DPM_STATE_CHANGED);
    ++            } else if (ACTION_USER_UNLOCKED.equals(action)) {
    ++                mHandler.sendEmptyMessage(MSG_USER_UNLOCKED);
    +             }
    +         }
    +     };
    +@@ -984,6 +998,17 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener {
    +         }
    +     }
    + 
    ++    private void handleDreamingStateChanged(int dreamStart) {
    ++        final int count = mCallbacks.size();
    ++        boolean showingDream = dreamStart == 1;
    ++        for (int i = 0; i < count; i++) {
    ++            KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get();
    ++            if (cb != null) {
    ++                cb.onDreamingStateChanged(showingDream);
    ++            }
    ++        }
    ++    }
    ++
    +     /**
    +      * IMPORTANT: Must be called from UI thread.
    +      */
    +@@ -1007,6 +1032,16 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener {
    +         }
    +     }
    + 
    ++    private void handleUserUnlocked() {
    ++        mNeedsSlowUnlockTransition = resolveNeedsSlowUnlockTransition();
    ++        for (int i = 0; i < mCallbacks.size(); i++) {
    ++            KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get();
    ++            if (cb != null) {
    ++                cb.onUserUnlocked();
    ++            }
    ++        }
    ++    }
    ++
    +     private KeyguardUpdateMonitor(Context context) {
    +         mContext = context;
    +         mSubscriptionManager = SubscriptionManager.from(context);
    +@@ -1047,6 +1082,7 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener {
    +         allUserFilter.addAction(ACTION_FACE_UNLOCK_STARTED);
    +         allUserFilter.addAction(ACTION_FACE_UNLOCK_STOPPED);
    +         allUserFilter.addAction(DevicePolicyManager.ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED);
    ++        allUserFilter.addAction(ACTION_USER_UNLOCKED);
    +         context.registerReceiverAsUser(mBroadcastAllReceiver, UserHandle.ALL, allUserFilter,
    +                 null, null);
    + 
    +@@ -1444,7 +1480,18 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener {
    +     private void handleKeyguardReset() {
    +         if (DEBUG) Log.d(TAG, "handleKeyguardReset");
    +         updateFingerprintListeningState();
    +-        mUserUnlocked = mUserManager.isUserUnlocked(getCurrentUser());
    ++        mNeedsSlowUnlockTransition = resolveNeedsSlowUnlockTransition();
    ++    }
    ++
    ++    private boolean resolveNeedsSlowUnlockTransition() {
    ++        if (mUserManager.isUserUnlocked(getCurrentUser())) {
    ++            return false;
    ++        }
    ++        Intent homeIntent = new Intent(Intent.ACTION_MAIN)
    ++                .addCategory(Intent.CATEGORY_HOME);
    ++        ResolveInfo resolveInfo = mContext.getPackageManager().resolveActivity(homeIntent,
    ++                0 /* flags */);
    ++        return FALLBACK_HOME_COMPONENT.equals(resolveInfo.getComponentInfo().getComponentName());
    +     }
    + 
    +     /**
    +@@ -1719,6 +1766,14 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener {
    +         mHandler.sendEmptyMessage(MSG_SCREEN_TURNED_OFF);
    +     }
    + 
    ++    public void dispatchDreamingStarted() {
    ++        mHandler.sendMessage(mHandler.obtainMessage(MSG_DREAMING_STATE_CHANGED, 1, 0));
    ++    }
    ++
    ++    public void dispatchDreamingStopped() {
    ++        mHandler.sendMessage(mHandler.obtainMessage(MSG_DREAMING_STATE_CHANGED, 0, 0));
    ++    }
    ++
    +     public boolean isDeviceInteractive() {
    +         return mDeviceInteractive;
    +     }
    +diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitorCallback.java b/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitorCallback.java
    +index 4a2d356..14d6b59 100644
    +--- a/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitorCallback.java
    ++++ b/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitorCallback.java
    +@@ -128,6 +128,11 @@ public class KeyguardUpdateMonitorCallback {
    +     public void onUserInfoChanged(int userId) { }
    + 
    +     /**
    ++     * Called when a user got unlocked.
    ++     */
    ++    public void onUserUnlocked() { }
    ++
    ++    /**
    +      * Called when boot completed.
    +      *
    +      * Note, this callback will only be received if boot complete occurs after registering with
    +@@ -245,4 +250,10 @@ public class KeyguardUpdateMonitorCallback {
    +      * Called when the state whether we have a lockscreen wallpaper has changed.
    +      */
    +     public void onHasLockscreenWallpaperChanged(boolean hasLockscreenWallpaper) { }
    ++
    ++    /**
    ++     * Called when the dream's window state is changed.
    ++     * @param dreaming true if the dream's window has been created and is visible
    ++     */
    ++    public void onDreamingStateChanged(boolean dreaming) { }
    + }
    +diff --git a/packages/MtpDocumentsProvider/src/com/android/mtp/MtpDatabase.java b/packages/MtpDocumentsProvider/src/com/android/mtp/MtpDatabase.java
    +index cce619e..4950af3 100644
    +--- a/packages/MtpDocumentsProvider/src/com/android/mtp/MtpDatabase.java
    ++++ b/packages/MtpDocumentsProvider/src/com/android/mtp/MtpDatabase.java
    +@@ -873,7 +873,7 @@ class MtpDatabase {
    +     }
    + 
    +     private static int getRootFlags(int[] operationsSupported) {
    +-        int rootFlag = Root.FLAG_SUPPORTS_IS_CHILD;
    ++        int rootFlag = Root.FLAG_SUPPORTS_IS_CHILD | Root.FLAG_LOCAL_ONLY;
    +         if (MtpDeviceRecord.isWritingSupported(operationsSupported)) {
    +             rootFlag |= Root.FLAG_SUPPORTS_CREATE;
    +         }
    +diff --git a/packages/MtpDocumentsProvider/src/com/android/mtp/MtpManager.java b/packages/MtpDocumentsProvider/src/com/android/mtp/MtpManager.java
    +index 90dd440..8f254e9 100644
    +--- a/packages/MtpDocumentsProvider/src/com/android/mtp/MtpManager.java
    ++++ b/packages/MtpDocumentsProvider/src/com/android/mtp/MtpManager.java
    +@@ -282,8 +282,8 @@ class MtpManager {
    +             }
    +             final MtpDeviceInfo info = mtpDevice.getDeviceInfo();
    +             if (info != null) {
    +-                operationsSupported = mtpDevice.getDeviceInfo().getOperationsSupported();
    +-                eventsSupported = mtpDevice.getDeviceInfo().getEventsSupported();
    ++                operationsSupported = info.getOperationsSupported();
    ++                eventsSupported = info.getEventsSupported();
    +             }
    +         } else {
    +             roots = new MtpRoot[0];
    +diff --git a/packages/MtpDocumentsProvider/tests/src/com/android/mtp/MtpDatabaseTest.java b/packages/MtpDocumentsProvider/tests/src/com/android/mtp/MtpDatabaseTest.java
    +index 404047b..8c13c81 100644
    +--- a/packages/MtpDocumentsProvider/tests/src/com/android/mtp/MtpDatabaseTest.java
    ++++ b/packages/MtpDocumentsProvider/tests/src/com/android/mtp/MtpDatabaseTest.java
    +@@ -128,7 +128,7 @@ public class MtpDatabaseTest extends AndroidTestCase {
    +             cursor.moveToNext();
    +             assertEquals(1, getInt(cursor, Root.COLUMN_ROOT_ID));
    +             assertEquals(
    +-                    Root.FLAG_SUPPORTS_IS_CHILD | Root.FLAG_SUPPORTS_CREATE,
    ++                    Root.FLAG_SUPPORTS_IS_CHILD | Root.FLAG_SUPPORTS_CREATE | Root.FLAG_LOCAL_ONLY,
    +                     getInt(cursor, Root.COLUMN_FLAGS));
    +             assertEquals(R.drawable.ic_root_mtp, getInt(cursor, Root.COLUMN_ICON));
    +             assertEquals("Device Storage", getString(cursor, Root.COLUMN_TITLE));
    +diff --git a/packages/MtpDocumentsProvider/tests/src/com/android/mtp/MtpDocumentsProviderTest.java b/packages/MtpDocumentsProvider/tests/src/com/android/mtp/MtpDocumentsProviderTest.java
    +index 9ed15c8..d19b460 100644
    +--- a/packages/MtpDocumentsProvider/tests/src/com/android/mtp/MtpDocumentsProviderTest.java
    ++++ b/packages/MtpDocumentsProvider/tests/src/com/android/mtp/MtpDocumentsProviderTest.java
    +@@ -210,7 +210,11 @@ public class MtpDocumentsProviderTest extends AndroidTestCase {
    +             assertEquals(2, cursor.getCount());
    +             cursor.moveToNext();
    +             assertEquals("1", cursor.getString(0));
    +-            assertEquals(Root.FLAG_SUPPORTS_IS_CHILD | Root.FLAG_SUPPORTS_CREATE, cursor.getInt(1));
    ++            assertEquals(
    ++                    Root.FLAG_SUPPORTS_IS_CHILD |
    ++                    Root.FLAG_SUPPORTS_CREATE |
    ++                    Root.FLAG_LOCAL_ONLY,
    ++                    cursor.getInt(1));
    +             assertEquals(R.drawable.ic_root_mtp, cursor.getInt(2));
    +             assertEquals("Device A Storage A", cursor.getString(3));
    +             assertEquals("1", cursor.getString(4));
    +@@ -225,7 +229,8 @@ public class MtpDocumentsProviderTest extends AndroidTestCase {
    +             cursor.moveToNext();
    +             cursor.moveToNext();
    +             assertEquals("2", cursor.getString(0));
    +-            assertEquals(Root.FLAG_SUPPORTS_IS_CHILD, cursor.getInt(1));
    ++            assertEquals(
    ++                    Root.FLAG_SUPPORTS_IS_CHILD | Root.FLAG_LOCAL_ONLY, cursor.getInt(1));
    +             assertEquals(R.drawable.ic_root_mtp, cursor.getInt(2));
    +             assertEquals("Device B Storage B", cursor.getString(3));
    +             assertEquals("2", cursor.getString(4));
    +@@ -271,7 +276,9 @@ public class MtpDocumentsProviderTest extends AndroidTestCase {
    + 
    +             cursor.moveToNext();
    +             assertEquals("1", cursor.getString(0));
    +-            assertEquals(Root.FLAG_SUPPORTS_IS_CHILD | Root.FLAG_SUPPORTS_CREATE, cursor.getInt(1));
    ++            assertEquals(
    ++                    Root.FLAG_SUPPORTS_IS_CHILD | Root.FLAG_SUPPORTS_CREATE | Root.FLAG_LOCAL_ONLY,
    ++                    cursor.getInt(1));
    +             assertEquals(R.drawable.ic_root_mtp, cursor.getInt(2));
    +             assertEquals("Device A", cursor.getString(3));
    +             assertEquals("1", cursor.getString(4));
    +@@ -279,7 +286,9 @@ public class MtpDocumentsProviderTest extends AndroidTestCase {
    + 
    +             cursor.moveToNext();
    +             assertEquals("2", cursor.getString(0));
    +-            assertEquals(Root.FLAG_SUPPORTS_IS_CHILD | Root.FLAG_SUPPORTS_CREATE, cursor.getInt(1));
    ++            assertEquals(
    ++                    Root.FLAG_SUPPORTS_IS_CHILD | Root.FLAG_SUPPORTS_CREATE | Root.FLAG_LOCAL_ONLY,
    ++                    cursor.getInt(1));
    +             assertEquals(R.drawable.ic_root_mtp, cursor.getInt(2));
    +             assertEquals("Device B Storage B", cursor.getString(3));
    +             assertEquals("2", cursor.getString(4));
    +diff --git a/packages/PrintSpooler/res/layout/print_activity.xml b/packages/PrintSpooler/res/layout/print_activity.xml
    +index 2db6fb0..31a776c 100644
    +--- a/packages/PrintSpooler/res/layout/print_activity.xml
    ++++ b/packages/PrintSpooler/res/layout/print_activity.xml
    +@@ -16,7 +16,6 @@
    + 
    + <com.android.printspooler.widget.PrintContentView
    +         xmlns:android="http://schemas.android.com/apk/res/android"
    +-        xmlns:printspooler="http://schemas.android.com/apk/res/com.android.printspooler"
    +     android:id="@+id/options_content"
    +     android:layout_width="fill_parent"
    +     android:layout_height="fill_parent">
    +@@ -28,12 +27,14 @@
    +         android:layout_width="fill_parent"
    +         android:layout_height="wrap_content"
    +         android:paddingStart="8dip"
    ++        android:layout_marginEnd="16dp"
    +         android:elevation="@dimen/preview_controls_elevation"
    +         android:background="?android:attr/colorPrimary">
    + 
    +         <Spinner
    +             android:id="@+id/destination_spinner"
    +-            android:layout_width="@dimen/preview_destination_spinner_width"
    ++            android:layout_width="wrap_content"
    ++            android:minWidth="@dimen/preview_destination_spinner_width"
    +             android:layout_height="wrap_content"
    +             android:layout_marginTop="4dip"
    +             android:dropDownWidth="wrap_content"
    +diff --git a/packages/PrintSpooler/res/layout/printer_dropdown_item.xml b/packages/PrintSpooler/res/layout/printer_dropdown_item.xml
    +index 103c157..0d8a90a 100644
    +--- a/packages/PrintSpooler/res/layout/printer_dropdown_item.xml
    ++++ b/packages/PrintSpooler/res/layout/printer_dropdown_item.xml
    +@@ -16,7 +16,8 @@
    + 
    + <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    +       android:layout_width="fill_parent"
    +-      android:layout_height="?android:attr/listPreferredItemHeightSmall"
    ++      android:layout_height="wrap_content"
    ++      android:minHeight="?android:attr/listPreferredItemHeightSmall"
    +       style="?android:attr/spinnerItemStyle"
    +       android:orientation="horizontal"
    +       android:gravity="start|center_vertical">
    +diff --git a/packages/PrintSpooler/res/values-zh-rCN/strings.xml b/packages/PrintSpooler/res/values-zh-rCN/strings.xml
    +index 3debf8e..d4e7963 100644
    +--- a/packages/PrintSpooler/res/values-zh-rCN/strings.xml
    ++++ b/packages/PrintSpooler/res/values-zh-rCN/strings.xml
    +@@ -60,7 +60,7 @@
    +       <item quantity="one">找到 <xliff:g id="COUNT_0">%1$s</xliff:g> 台打印机</item>
    +     </plurals>
    +     <string name="printer_extended_description_template" msgid="1366699227703381874">"<xliff:g id="PRINT_SERVICE_LABEL">%1$s</xliff:g> - <xliff:g id="PRINTER_DESCRIPTION">%2$s</xliff:g>"</string>
    +-    <string name="printer_info_desc" msgid="7181988788991581654">"关于此打印机的更多信息"</string>
    ++    <string name="printer_info_desc" msgid="7181988788991581654">"此打印机的详细信息"</string>
    +     <string name="could_not_create_file" msgid="3425025039427448443">"无法创建文件"</string>
    +     <string name="print_services_disabled_toast" msgid="9089060734685174685">"部分打印服务已停用"</string>
    +     <string name="print_searching_for_printers" msgid="6550424555079932867">"正在搜索打印机"</string>
    +diff --git a/packages/SettingsLib/res/values-af/strings.xml b/packages/SettingsLib/res/values-af/strings.xml
    +index c16e08a..66f2f87 100644
    +--- a/packages/SettingsLib/res/values-af/strings.xml
    ++++ b/packages/SettingsLib/res/values-af/strings.xml
    +@@ -28,7 +28,8 @@
    +     <string name="wifi_disabled_wifi_failure" msgid="3081668066612876581">"WiFi-verbinding het misluk"</string>
    +     <string name="wifi_disabled_password_failure" msgid="8659805351763133575">"Stawingsprobleem"</string>
    +     <string name="wifi_not_in_range" msgid="1136191511238508967">"Nie binne ontvangs nie"</string>
    +-    <string name="wifi_no_internet" msgid="9151470775868728896">"Geen internettoegang bespeur nie, sal nie outomaties herkoppel nie."</string>
    ++    <string name="wifi_no_internet_no_reconnect" msgid="2211781637653149657">"Geen internettoegang word bespeur nie, sal nie outomaties herkoppel nie."</string>
    ++    <string name="wifi_no_internet" msgid="5011955173375805204">"Geen internettoegang nie."</string>
    +     <string name="saved_network" msgid="4352716707126620811">"Gestoor deur <xliff:g id="NAME">%1$s</xliff:g>"</string>
    +     <string name="connected_via_wfa" msgid="3805736726317410714">"Gekoppel via Wi-Fi-assistent"</string>
    +     <string name="connected_via_passpoint" msgid="2826205693803088747">"Gekoppel via %1$s"</string>
    +@@ -233,8 +234,6 @@
    +     <string name="debug_layout_summary" msgid="2001775315258637682">"Wys snitgrense, kantlyne, ens."</string>
    +     <string name="force_rtl_layout_all_locales" msgid="2259906643093138978">"Dwing RTL-uitlegrigting"</string>
    +     <string name="force_rtl_layout_all_locales_summary" msgid="9192797796616132534">"Dwing skermuitlegrigting na RTL vir alle locales"</string>
    +-    <string name="show_cpu_usage" msgid="2389212910758076024">"Wys CPU-verbruik"</string>
    +-    <string name="show_cpu_usage_summary" msgid="2113341923988958266">"Skermlaag wys huidige CPU-gebruik"</string>
    +     <string name="force_hw_ui" msgid="6426383462520888732">"Forseer GPU-lewering"</string>
    +     <string name="force_hw_ui_summary" msgid="5535991166074861515">"Dwing gebruik van GPU vir 2D-tekening"</string>
    +     <string name="force_msaa" msgid="7920323238677284387">"Dwing 4x MSAA"</string>
    +@@ -341,4 +340,5 @@
    +     <string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"Grootste"</string>
    +     <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Gepasmaak (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
    +     <string name="help_feedback_label" msgid="6815040660801785649">"Hulp en terugvoer"</string>
    ++    <string name="content_description_menu_button" msgid="8182594799812351266">"Kieslys"</string>
    + </resources>
    +diff --git a/packages/SettingsLib/res/values-am/strings.xml b/packages/SettingsLib/res/values-am/strings.xml
    +index 6e9dcd7..cfda4ab 100644
    +--- a/packages/SettingsLib/res/values-am/strings.xml
    ++++ b/packages/SettingsLib/res/values-am/strings.xml
    +@@ -28,7 +28,8 @@
    +     <string name="wifi_disabled_wifi_failure" msgid="3081668066612876581">"የWiFi ግንኙነት መሰናከል"</string>
    +     <string name="wifi_disabled_password_failure" msgid="8659805351763133575">"የማረጋገጫ ችግር"</string>
    +     <string name="wifi_not_in_range" msgid="1136191511238508967">"በክልል ውስጥ የለም"</string>
    +-    <string name="wifi_no_internet" msgid="9151470775868728896">"ምንም የበይነ መረብ መዳረሻ ተፈልጎ አልተገኘም፣ በራስ-ሰር እንደገና እንዲገናኝ አይደረግም።"</string>
    ++    <string name="wifi_no_internet_no_reconnect" msgid="2211781637653149657">"ምንም የበይነ መረብ መዳረሻ አልተገኘም፣ በራስ-ሰር እንደገና እንዲገናኝ አይደረግም።"</string>
    ++    <string name="wifi_no_internet" msgid="5011955173375805204">"ምንም የበይነመረብ መዳረሻ የለም።"</string>
    +     <string name="saved_network" msgid="4352716707126620811">"የተቀመጠው በ<xliff:g id="NAME">%1$s</xliff:g>"</string>
    +     <string name="connected_via_wfa" msgid="3805736726317410714">"በWi‑Fi ረዳት አማካኝነት ተገናኝቷል"</string>
    +     <string name="connected_via_passpoint" msgid="2826205693803088747">"በ%1$s በኩል መገናኘት"</string>
    +@@ -233,8 +234,6 @@
    +     <string name="debug_layout_summary" msgid="2001775315258637682">"የቅንጥብ ገደቦች፣ ጠርዞች፣ ወዘተ አሳይ"</string>
    +     <string name="force_rtl_layout_all_locales" msgid="2259906643093138978">"የቀኝ-ወደ-ግራ አቀማመጥ አቅጣጫ አስገድድ"</string>
    +     <string name="force_rtl_layout_all_locales_summary" msgid="9192797796616132534">"ለሁሉም አካባቢዎች የማያ ገጽ አቀማመጥ ከቀኝ-ወደ-ግራ እንዲሆን አስገድድ"</string>
    +-    <string name="show_cpu_usage" msgid="2389212910758076024">"የCPU አጠቃቀም አሳይ"</string>
    +-    <string name="show_cpu_usage_summary" msgid="2113341923988958266">"የማያ ተደራቢ የአሁኑን የCPU አጠቃቀም  እያሳየ ነው።"</string>
    +     <string name="force_hw_ui" msgid="6426383462520888732">"GPU ምላሽ መስጠትን አስገድድ"</string>
    +     <string name="force_hw_ui_summary" msgid="5535991166074861515">"ለ2-ልኬት መሳል የGPU ስራ አስገድድ"</string>
    +     <string name="force_msaa" msgid="7920323238677284387">"4x MSAA አስገድድ"</string>
    +@@ -341,4 +340,5 @@
    +     <string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"በጣም ተለቅ ያለ"</string>
    +     <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"ብጁ (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
    +     <string name="help_feedback_label" msgid="6815040660801785649">"እገዛ እና ግብረመልስ"</string>
    ++    <string name="content_description_menu_button" msgid="8182594799812351266">"ምናሌ"</string>
    + </resources>
    +diff --git a/packages/SettingsLib/res/values-ar/strings.xml b/packages/SettingsLib/res/values-ar/strings.xml
    +index ee579dc..e65feff 100644
    +--- a/packages/SettingsLib/res/values-ar/strings.xml
    ++++ b/packages/SettingsLib/res/values-ar/strings.xml
    +@@ -28,7 +28,8 @@
    +     <string name="wifi_disabled_wifi_failure" msgid="3081668066612876581">"‏أخفق اتصال WiFi"</string>
    +     <string name="wifi_disabled_password_failure" msgid="8659805351763133575">"حدثت مشكلة في المصادقة"</string>
    +     <string name="wifi_not_in_range" msgid="1136191511238508967">"ليست في النطاق"</string>
    +-    <string name="wifi_no_internet" msgid="9151470775868728896">"لم يتم اكتشاف اتصال بالإنترنت."</string>
    ++    <string name="wifi_no_internet_no_reconnect" msgid="2211781637653149657">"لم يتم اكتشاف اتصال بالإنترنت، ولن تتم إعادة الاتصال تلقائيًا."</string>
    ++    <string name="wifi_no_internet" msgid="5011955173375805204">"لا يتوفر اتصال بالإنترنت."</string>
    +     <string name="saved_network" msgid="4352716707126620811">"تم الحفظ بواسطة <xliff:g id="NAME">%1$s</xliff:g>"</string>
    +     <string name="connected_via_wfa" msgid="3805736726317410714">"‏تم التوصيل عبر مساعد Wi-Fi"</string>
    +     <string name="connected_via_passpoint" msgid="2826205693803088747">"‏تم الاتصال عبر %1$s"</string>
    +@@ -233,8 +234,6 @@
    +     <string name="debug_layout_summary" msgid="2001775315258637682">"عرض حدود وهوامش المقطع وما إلى ذلك."</string>
    +     <string name="force_rtl_layout_all_locales" msgid="2259906643093138978">"فرض اتجاه التنسيق ليكون من اليمين إلى اليسار"</string>
    +     <string name="force_rtl_layout_all_locales_summary" msgid="9192797796616132534">"فرض اتجاه تنسيق الشاشة ليكون من اليمين إلى اليسار لجميع اللغات"</string>
    +-    <string name="show_cpu_usage" msgid="2389212910758076024">"‏عرض استخدام CPU"</string>
    +-    <string name="show_cpu_usage_summary" msgid="2113341923988958266">"‏عرض تراكب الشاشة لاستخدام CPU الحالي"</string>
    +     <string name="force_hw_ui" msgid="6426383462520888732">"‏فرض عرض رسومات GPU"</string>
    +     <string name="force_hw_ui_summary" msgid="5535991166074861515">"فرض استخدام وحدة معالجة الرسومات للرسم ثنائي الأبعاد"</string>
    +     <string name="force_msaa" msgid="7920323238677284387">"‏فرض 4x MSAA"</string>
    +@@ -329,7 +328,7 @@
    +     <string name="home" msgid="3256884684164448244">"الشاشة الرئيسية للإعدادات"</string>
    +   <string-array name="battery_labels">
    +     <item msgid="8494684293649631252">"٠‏٪"</item>
    +-    <item msgid="8934126114226089439">"٪۵۰"</item>
    ++    <item msgid="8934126114226089439">"٥٠٪"</item>
    +     <item msgid="1286113608943010849">"٪۱۰۰"</item>
    +   </string-array>
    +     <string name="charge_length_format" msgid="8978516217024434156">"قبل <xliff:g id="ID_1">%1$s</xliff:g>"</string>
    +@@ -341,4 +340,5 @@
    +     <string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"أكبر مستوى"</string>
    +     <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"مخصص (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
    +     <string name="help_feedback_label" msgid="6815040660801785649">"المساعدة والتعليقات"</string>
    ++    <string name="content_description_menu_button" msgid="8182594799812351266">"القائمة"</string>
    + </resources>
    +diff --git a/packages/SettingsLib/res/values-az-rAZ/strings.xml b/packages/SettingsLib/res/values-az-rAZ/strings.xml
    +index 60d0169..5aac49e 100644
    +--- a/packages/SettingsLib/res/values-az-rAZ/strings.xml
    ++++ b/packages/SettingsLib/res/values-az-rAZ/strings.xml
    +@@ -28,7 +28,8 @@
    +     <string name="wifi_disabled_wifi_failure" msgid="3081668066612876581">"WiFi Bağlantı Uğursuzluğu"</string>
    +     <string name="wifi_disabled_password_failure" msgid="8659805351763133575">"Autentifikasiya problemi"</string>
    +     <string name="wifi_not_in_range" msgid="1136191511238508967">"Diapazonda deyil"</string>
    +-    <string name="wifi_no_internet" msgid="9151470775868728896">"İnternet bağlantısı tapılmadı, avtomatik olaraq yenidən qoşulmayacaq."</string>
    ++    <string name="wifi_no_internet_no_reconnect" msgid="2211781637653149657">"İnternet bağlantısı tapılmadı, avtomatik olaraq yenidən qoşulmayacaq."</string>
    ++    <string name="wifi_no_internet" msgid="5011955173375805204">"İnternet girişi yoxdur."</string>
    +     <string name="saved_network" msgid="4352716707126620811">"<xliff:g id="NAME">%1$s</xliff:g> tərəfindən saxlandı"</string>
    +     <string name="connected_via_wfa" msgid="3805736726317410714">"Wi‑Fi köməkçisi vasitəsilə qoşulub"</string>
    +     <string name="connected_via_passpoint" msgid="2826205693803088747">"%1$s vasitəsilə qoşuludur"</string>
    +@@ -233,8 +234,6 @@
    +     <string name="debug_layout_summary" msgid="2001775315258637682">"Klip sərhədləri, boşluqları və s. göstər"</string>
    +     <string name="force_rtl_layout_all_locales" msgid="2259906643093138978">"RTL düzən istiqamətinə məcbur edin"</string>
    +     <string name="force_rtl_layout_all_locales_summary" msgid="9192797796616132534">"Ekran düzən istiqamətini RTL üzərinə bütün yerli variantlar üçün məcbur edin"</string>
    +-    <string name="show_cpu_usage" msgid="2389212910758076024">"CPU istifadəsini göstər"</string>
    +-    <string name="show_cpu_usage_summary" msgid="2113341923988958266">"Ekran örtüşməsi cari CPU istifadəsini göstərir"</string>
    +     <string name="force_hw_ui" msgid="6426383462520888732">"GPU renderə məcbur edin"</string>
    +     <string name="force_hw_ui_summary" msgid="5535991166074861515">"2d rəsm üçün GPU məcburi istifadə"</string>
    +     <string name="force_msaa" msgid="7920323238677284387">"4x MSAA məcbur edin"</string>
    +@@ -341,4 +340,5 @@
    +     <string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"Ən böyük"</string>
    +     <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Fərdi (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
    +     <string name="help_feedback_label" msgid="6815040660801785649">"Yardım və rəy"</string>
    ++    <string name="content_description_menu_button" msgid="8182594799812351266">"Menyu"</string>
    + </resources>
    +diff --git a/packages/SettingsLib/res/values-b+sr+Latn/strings.xml b/packages/SettingsLib/res/values-b+sr+Latn/strings.xml
    +index 060a5fb..345c0bb 100644
    +--- a/packages/SettingsLib/res/values-b+sr+Latn/strings.xml
    ++++ b/packages/SettingsLib/res/values-b+sr+Latn/strings.xml
    +@@ -28,7 +28,8 @@
    +     <string name="wifi_disabled_wifi_failure" msgid="3081668066612876581">"Wi-Fi veza je otkazala"</string>
    +     <string name="wifi_disabled_password_failure" msgid="8659805351763133575">"Problem sa potvrdom autentičnosti"</string>
    +     <string name="wifi_not_in_range" msgid="1136191511238508967">"Nije u opsegu"</string>
    +-    <string name="wifi_no_internet" msgid="9151470775868728896">"Pristup internetu nije otkriven, automatsko povezivanje nije moguće."</string>
    ++    <string name="wifi_no_internet_no_reconnect" msgid="2211781637653149657">"Pristup internetu nije otkriven, automatsko povezivanje nije moguće."</string>
    ++    <string name="wifi_no_internet" msgid="5011955173375805204">"Nema pristupa internetu."</string>
    +     <string name="saved_network" msgid="4352716707126620811">"Sačuvao/la je <xliff:g id="NAME">%1$s</xliff:g>"</string>
    +     <string name="connected_via_wfa" msgid="3805736726317410714">"Povezano preko Wi‑Fi pomoćnika"</string>
    +     <string name="connected_via_passpoint" msgid="2826205693803088747">"Veza je uspostavljena preko pristupne tačke %1$s"</string>
    +@@ -233,8 +234,6 @@
    +     <string name="debug_layout_summary" msgid="2001775315258637682">"Prikaži granice klipa, margine itd."</string>
    +     <string name="force_rtl_layout_all_locales" msgid="2259906643093138978">"Nametni smer rasporeda zdesna nalevo"</string>
    +     <string name="force_rtl_layout_all_locales_summary" msgid="9192797796616132534">"Nametni smer rasporeda ekrana zdesna nalevo za sve lokalitete"</string>
    +-    <string name="show_cpu_usage" msgid="2389212910758076024">"Prik. upotrebu procesora"</string>
    +-    <string name="show_cpu_usage_summary" msgid="2113341923988958266">"Postav. element sa trenutnom upotrebom procesora"</string>
    +     <string name="force_hw_ui" msgid="6426383462520888732">"Prinudni prikaz pom. GPU"</string>
    +     <string name="force_hw_ui_summary" msgid="5535991166074861515">"Prinudno koristi GPU za 2D crtanje"</string>
    +     <string name="force_msaa" msgid="7920323238677284387">"Nametni 4x MSAA"</string>
    +@@ -282,7 +281,7 @@
    +     <string name="enable_webview_multiprocess_desc" msgid="2485604010404197724">"Pokrećite WebView prikazivače zasebno"</string>
    +     <string name="select_webview_provider_title" msgid="4628592979751918907">"Primena WebView-a"</string>
    +     <string name="select_webview_provider_dialog_title" msgid="4370551378720004872">"Podesite primenu WebView-a"</string>
    +-    <string name="select_webview_provider_toast_text" msgid="5466970498308266359">"Ovaj izbor više nije važeći. Pokušajte ponovo."</string>
    ++    <string name="select_webview_provider_toast_text" msgid="5466970498308266359">"Ovaj izbor više nije važeći. Probajte ponovo."</string>
    +     <string name="convert_to_file_encryption" msgid="3060156730651061223">"Konvertuj u šifrovanje datoteka"</string>
    +     <string name="convert_to_file_encryption_enabled" msgid="2861258671151428346">"Konvertuj..."</string>
    +     <string name="convert_to_file_encryption_done" msgid="7859766358000523953">"Već se koristi šifrovanje datoteka"</string>
    +@@ -341,4 +340,5 @@
    +     <string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"Najveći"</string>
    +     <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Prilagođeni (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
    +     <string name="help_feedback_label" msgid="6815040660801785649">"Pomoć i povratne informacije"</string>
    ++    <string name="content_description_menu_button" msgid="8182594799812351266">"Meni"</string>
    + </resources>
    +diff --git a/packages/SettingsLib/res/values-be-rBY/strings.xml b/packages/SettingsLib/res/values-be-rBY/strings.xml
    +index 03de8ba..52077fb 100644
    +--- a/packages/SettingsLib/res/values-be-rBY/strings.xml
    ++++ b/packages/SettingsLib/res/values-be-rBY/strings.xml
    +@@ -28,7 +28,8 @@
    +     <string name="wifi_disabled_wifi_failure" msgid="3081668066612876581">"Збой падлучэння Wi-Fi"</string>
    +     <string name="wifi_disabled_password_failure" msgid="8659805351763133575">"Праблема аўтэнтыфікацыі"</string>
    +     <string name="wifi_not_in_range" msgid="1136191511238508967">"Не ў зоне дасягальнасці"</string>
    +-    <string name="wifi_no_internet" msgid="9151470775868728896">"Доступ да інтэрнэту не выяўлены, аўтаматычнае перападлучэнне не адбудзецца."</string>
    ++    <string name="wifi_no_internet_no_reconnect" msgid="2211781637653149657">"Доступ да інтэрнэту не выяўлены, аўтаматычнае перападключэнне не адбудзецца."</string>
    ++    <string name="wifi_no_internet" msgid="5011955173375805204">"Няма доступу да інтэрнэту."</string>
    +     <string name="saved_network" msgid="4352716707126620811">"Хто захаваў: <xliff:g id="NAME">%1$s</xliff:g>"</string>
    +     <string name="connected_via_wfa" msgid="3805736726317410714">"Падлучана праз памочніка Wi‑Fi"</string>
    +     <string name="connected_via_passpoint" msgid="2826205693803088747">"Падлучана праз %1$s"</string>
    +@@ -233,8 +234,6 @@
    +     <string name="debug_layout_summary" msgid="2001775315258637682">"Паказаць межы кліпу, палі і г. д."</string>
    +     <string name="force_rtl_layout_all_locales" msgid="2259906643093138978">"Прымусовая раскладка справа налева"</string>
    +     <string name="force_rtl_layout_all_locales_summary" msgid="9192797796616132534">"Прымусовая раскладка экрана справа налева для ўсіх рэгіянальных налад"</string>
    +-    <string name="show_cpu_usage" msgid="2389212910758076024">"Паказаць выкарыстанне ЦП"</string>
    +-    <string name="show_cpu_usage_summary" msgid="2113341923988958266">"Наклад на экран з бягучым выкарыстаннем працэсара"</string>
    +     <string name="force_hw_ui" msgid="6426383462520888732">"Прымусовае адлюстраванне GPU"</string>
    +     <string name="force_hw_ui_summary" msgid="5535991166074861515">"Прымусовае выкарыстанне GPU для 2-мерных чарцяжоў"</string>
    +     <string name="force_msaa" msgid="7920323238677284387">"Прымусовае выкананне 4x MSAA"</string>
    +@@ -341,4 +340,5 @@
    +     <string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"Найвялікшы"</string>
    +     <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Карыстальніцкі (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
    +     <string name="help_feedback_label" msgid="6815040660801785649">"Даведка і водгукі"</string>
    ++    <string name="content_description_menu_button" msgid="8182594799812351266">"Меню"</string>
    + </resources>
    +diff --git a/packages/SettingsLib/res/values-bg/strings.xml b/packages/SettingsLib/res/values-bg/strings.xml
    +index f6596dc..eba51b3 100644
    +--- a/packages/SettingsLib/res/values-bg/strings.xml
    ++++ b/packages/SettingsLib/res/values-bg/strings.xml
    +@@ -28,7 +28,8 @@
    +     <string name="wifi_disabled_wifi_failure" msgid="3081668066612876581">"Неуспешна връзка с Wi-Fi"</string>
    +     <string name="wifi_disabled_password_failure" msgid="8659805351763133575">"Проблем при удостоверяването"</string>
    +     <string name="wifi_not_in_range" msgid="1136191511238508967">"Извън обхват"</string>
    +-    <string name="wifi_no_internet" msgid="9151470775868728896">"Не е открит достъп до интернет. Няма да се свърже отново автоматично."</string>
    ++    <string name="wifi_no_internet_no_reconnect" msgid="2211781637653149657">"Не е открит достъп до интернет. Връзката няма да се възобнови автоматично."</string>
    ++    <string name="wifi_no_internet" msgid="5011955173375805204">"Няма достъп до интернет."</string>
    +     <string name="saved_network" msgid="4352716707126620811">"Запазено от <xliff:g id="NAME">%1$s</xliff:g>"</string>
    +     <string name="connected_via_wfa" msgid="3805736726317410714">"Установена е връзка чрез помощника за Wi-Fi"</string>
    +     <string name="connected_via_passpoint" msgid="2826205693803088747">"Установена е връзка през „%1$s“"</string>
    +@@ -233,8 +234,6 @@
    +     <string name="debug_layout_summary" msgid="2001775315258637682">"Показв. на границите на изрязване, полетата и др."</string>
    +     <string name="force_rtl_layout_all_locales" msgid="2259906643093138978">"Принуд. оформл. отдясно наляво"</string>
    +     <string name="force_rtl_layout_all_locales_summary" msgid="9192797796616132534">"Принуд. оформл. на екрана отдясно наляво за вс. локали"</string>
    +-    <string name="show_cpu_usage" msgid="2389212910758076024">"Употреба на процесора"</string>
    +-    <string name="show_cpu_usage_summary" msgid="2113341923988958266">"Наслагване на екрана показва употр. на процесора"</string>
    +     <string name="force_hw_ui" msgid="6426383462520888732">"Принудително изобразяване"</string>
    +     <string name="force_hw_ui_summary" msgid="5535991166074861515">"Принуд. използв. на GPU за двуизмерно начертаване"</string>
    +     <string name="force_msaa" msgid="7920323238677284387">"Задаване на 4x MSAA"</string>
    +@@ -341,4 +340,5 @@
    +     <string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"Най-голямо"</string>
    +     <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Персонализирано (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
    +     <string name="help_feedback_label" msgid="6815040660801785649">"Помощ и отзиви"</string>
    ++    <string name="content_description_menu_button" msgid="8182594799812351266">"Меню"</string>
    + </resources>
    +diff --git a/packages/SettingsLib/res/values-bn-rBD/strings.xml b/packages/SettingsLib/res/values-bn-rBD/strings.xml
    +index 4a11198..4ad361b 100644
    +--- a/packages/SettingsLib/res/values-bn-rBD/strings.xml
    ++++ b/packages/SettingsLib/res/values-bn-rBD/strings.xml
    +@@ -28,7 +28,8 @@
    +     <string name="wifi_disabled_wifi_failure" msgid="3081668066612876581">"WiFi সংযোগের ব্যর্থতা"</string>
    +     <string name="wifi_disabled_password_failure" msgid="8659805351763133575">"প্রমাণীকরণ সমস্যা"</string>
    +     <string name="wifi_not_in_range" msgid="1136191511238508967">"পরিসরের মধ্যে নয়"</string>
    +-    <string name="wifi_no_internet" msgid="9151470775868728896">"কোনো ইন্টারনেট অ্যাক্সেস শনাক্ত হয়নি, স্বয়ংক্রিয়ভাবে পুনরায় সংযোগ স্থাপন করবে না৷"</string>
    ++    <string name="wifi_no_internet_no_reconnect" msgid="2211781637653149657">"কোনো ইন্টারনেট অ্যাক্সেস শনাক্ত হয়নি, স্বয়ংক্রিয়ভাবে পুনরায় সংযোগ স্থাপন করবে না৷"</string>
    ++    <string name="wifi_no_internet" msgid="5011955173375805204">"কোনো ইন্টারনেট অ্যাক্সেস নেই৷"</string>
    +     <string name="saved_network" msgid="4352716707126620811">"<xliff:g id="NAME">%1$s</xliff:g> দ্বারা সংরক্ষিত"</string>
    +     <string name="connected_via_wfa" msgid="3805736726317410714">"ওয়াই-ফাই সহায়ক-এর মাধ্যমে সংযুক্ত হয়েছে"</string>
    +     <string name="connected_via_passpoint" msgid="2826205693803088747">"%1$s মাধ্যমে সংযুক্ত হয়েছে"</string>
    +@@ -233,8 +234,6 @@
    +     <string name="debug_layout_summary" msgid="2001775315258637682">"ক্লিপ বাউন্ড, মার্জিন ইত্যাদি দেখান"</string>
    +     <string name="force_rtl_layout_all_locales" msgid="2259906643093138978">"RTL লেআউট দিকনির্দেশ জোর দিন"</string>
    +     <string name="force_rtl_layout_all_locales_summary" msgid="9192797796616132534">"সমস্ত স্থানের জন্য RTL এ স্ক্রীন লেআউট দিকনির্দেশে জোর দেয়"</string>
    +-    <string name="show_cpu_usage" msgid="2389212910758076024">"CPU এর ব্যবহার দেখান"</string>
    +-    <string name="show_cpu_usage_summary" msgid="2113341923988958266">"স্ক্রীন ওভারলে বর্তমান CPU ব্যবহার দেখাচ্ছে"</string>
    +     <string name="force_hw_ui" msgid="6426383462520888732">"জোর করে GPU রেন্ডারিং করুন"</string>
    +     <string name="force_hw_ui_summary" msgid="5535991166074861515">"2D অঙ্কনের জন্য GPU-এর ব্যবহারে জোর দিন"</string>
    +     <string name="force_msaa" msgid="7920323238677284387">"4x MSAA এ জোর দিন"</string>
    +@@ -341,4 +340,5 @@
    +     <string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"বৃহত্তম"</string>
    +     <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"কাস্টম (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
    +     <string name="help_feedback_label" msgid="6815040660801785649">"সহায়তা ও মতামত"</string>
    ++    <string name="content_description_menu_button" msgid="8182594799812351266">"মেনু"</string>
    + </resources>
    +diff --git a/packages/SettingsLib/res/values-bs-rBA/strings.xml b/packages/SettingsLib/res/values-bs-rBA/strings.xml
    +index 40a3630..8c7c4e0 100644
    +--- a/packages/SettingsLib/res/values-bs-rBA/strings.xml
    ++++ b/packages/SettingsLib/res/values-bs-rBA/strings.xml
    +@@ -28,7 +28,8 @@
    +     <string name="wifi_disabled_wifi_failure" msgid="3081668066612876581">"Greška pri povezivanju na Wi-Fi"</string>
    +     <string name="wifi_disabled_password_failure" msgid="8659805351763133575">"Problem pri provjeri vjerodostojnosti."</string>
    +     <string name="wifi_not_in_range" msgid="1136191511238508967">"Nije u dometu"</string>
    +-    <string name="wifi_no_internet" msgid="9151470775868728896">"Pristup internetu nije pronađen. Neće se ponovo povezivati automatski."</string>
    ++    <string name="wifi_no_internet_no_reconnect" msgid="2211781637653149657">"Pristup internetu nije pronađen. Neće se ponovo povezivati automatski."</string>
    ++    <string name="wifi_no_internet" msgid="5011955173375805204">"Nema pristupa internetu."</string>
    +     <string name="saved_network" msgid="4352716707126620811">"Sačuvao <xliff:g id="NAME">%1$s</xliff:g>"</string>
    +     <string name="connected_via_wfa" msgid="3805736726317410714">"Povezani preko Wi-Fi pomoćnika"</string>
    +     <string name="connected_via_passpoint" msgid="2826205693803088747">"Povezani preko %1$s"</string>
    +@@ -233,8 +234,6 @@
    +     <string name="debug_layout_summary" msgid="2001775315258637682">"Prikaži granice isječka, margine itd."</string>
    +     <string name="force_rtl_layout_all_locales" msgid="2259906643093138978">"Prisilno postavi raspored s desna u lijevo"</string>
    +     <string name="force_rtl_layout_all_locales_summary" msgid="9192797796616132534">"Prisilno postavi raspored ekrana s desna u lijevo za sve regije"</string>
    +-    <string name="show_cpu_usage" msgid="2389212910758076024">"Prikaži korištenje CPU-a"</string>
    +-    <string name="show_cpu_usage_summary" msgid="2113341923988958266">"Trenutno korištenje CPU-a prikazuje se u nadsloju preko ekrana"</string>
    +     <string name="force_hw_ui" msgid="6426383462520888732">"Prisili GPU iscrtavanje"</string>
    +     <string name="force_hw_ui_summary" msgid="5535991166074861515">"Prisilno koristite GPU za 2d crtanje"</string>
    +     <string name="force_msaa" msgid="7920323238677284387">"Prinudno primjeni 4x MSAA"</string>
    +@@ -341,4 +340,5 @@
    +     <string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"Najveće"</string>
    +     <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Prilagodi (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
    +     <string name="help_feedback_label" msgid="6815040660801785649">"Pomoć i povratne informacije"</string>
    ++    <string name="content_description_menu_button" msgid="8182594799812351266">"Meni"</string>
    + </resources>
    +diff --git a/packages/SettingsLib/res/values-ca/strings.xml b/packages/SettingsLib/res/values-ca/strings.xml
    +index 99850a5..20ae6b0 100644
    +--- a/packages/SettingsLib/res/values-ca/strings.xml
    ++++ b/packages/SettingsLib/res/values-ca/strings.xml
    +@@ -28,7 +28,8 @@
    +     <string name="wifi_disabled_wifi_failure" msgid="3081668066612876581">"Error de connexió Wi-Fi"</string>
    +     <string name="wifi_disabled_password_failure" msgid="8659805351763133575">"Problema d\'autenticació"</string>
    +     <string name="wifi_not_in_range" msgid="1136191511238508967">"Fora de l\'abast"</string>
    +-    <string name="wifi_no_internet" msgid="9151470775868728896">"No s\'ha detectat accés a Internet, no s\'hi tornarà a connectar automàticament."</string>
    ++    <string name="wifi_no_internet_no_reconnect" msgid="2211781637653149657">"No s\'ha detectat accés a Internet; no s\'hi tornarà a connectar automàticament."</string>
    ++    <string name="wifi_no_internet" msgid="5011955173375805204">"No hi ha accés a Internet."</string>
    +     <string name="saved_network" msgid="4352716707126620811">"Desat per <xliff:g id="NAME">%1$s</xliff:g>"</string>
    +     <string name="connected_via_wfa" msgid="3805736726317410714">"Connectat mitjançant l\'assistent de Wi‑Fi"</string>
    +     <string name="connected_via_passpoint" msgid="2826205693803088747">"Connectada mitjançant %1$s"</string>
    +@@ -233,8 +234,6 @@
    +     <string name="debug_layout_summary" msgid="2001775315258637682">"Mostra els límits de clips, els marges, etc."</string>
    +     <string name="force_rtl_layout_all_locales" msgid="2259906643093138978">"Força direcció dreta-esquerra"</string>
    +     <string name="force_rtl_layout_all_locales_summary" msgid="9192797796616132534">"Força direcció de pantalla dreta-esquerra en totes les llengües"</string>
    +-    <string name="show_cpu_usage" msgid="2389212910758076024">"Mostra l\'ús de la CPU"</string>
    +-    <string name="show_cpu_usage_summary" msgid="2113341923988958266">"Superposa l\'ús de la CPU a la pantalla"</string>
    +     <string name="force_hw_ui" msgid="6426383462520888732">"Força acceleració GPU"</string>
    +     <string name="force_hw_ui_summary" msgid="5535991166074861515">"Força l\'ús de GPU per a dibuixos en 2D"</string>
    +     <string name="force_msaa" msgid="7920323238677284387">"Força MSAA  4x"</string>
    +@@ -341,4 +340,5 @@
    +     <string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"Màxim"</string>
    +     <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Personalitzat (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
    +     <string name="help_feedback_label" msgid="6815040660801785649">"Ajuda i suggeriments"</string>
    ++    <string name="content_description_menu_button" msgid="8182594799812351266">"Menú"</string>
    + </resources>
    +diff --git a/packages/SettingsLib/res/values-cs/strings.xml b/packages/SettingsLib/res/values-cs/strings.xml
    +index 361ba1f..bbc1266 100644
    +--- a/packages/SettingsLib/res/values-cs/strings.xml
    ++++ b/packages/SettingsLib/res/values-cs/strings.xml
    +@@ -28,7 +28,8 @@
    +     <string name="wifi_disabled_wifi_failure" msgid="3081668066612876581">"Selhání připojení Wi-Fi"</string>
    +     <string name="wifi_disabled_password_failure" msgid="8659805351763133575">"Problém s ověřením"</string>
    +     <string name="wifi_not_in_range" msgid="1136191511238508967">"Mimo dosah"</string>
    +-    <string name="wifi_no_internet" msgid="9151470775868728896">"Nebyl zjištěn žádný přístup k internetu, připojení nebude automaticky obnoveno."</string>
    ++    <string name="wifi_no_internet_no_reconnect" msgid="2211781637653149657">"Nebyl zjištěn žádný přístup k internetu, připojení nebude automaticky obnoveno."</string>
    ++    <string name="wifi_no_internet" msgid="5011955173375805204">"Není k dispozici přístup k internetu."</string>
    +     <string name="saved_network" msgid="4352716707126620811">"Uloženo uživatelem <xliff:g id="NAME">%1$s</xliff:g>"</string>
    +     <string name="connected_via_wfa" msgid="3805736726317410714">"Připojeno pomocí asistenta připojení Wi-Fi"</string>
    +     <string name="connected_via_passpoint" msgid="2826205693803088747">"Připojeno prostřednictvím %1$s"</string>
    +@@ -233,8 +234,6 @@
    +     <string name="debug_layout_summary" msgid="2001775315258637682">"Zobrazit u výstřižku ohraničení, okraje atd."</string>
    +     <string name="force_rtl_layout_all_locales" msgid="2259906643093138978">"Vynutit rozvržení zprava doleva"</string>
    +     <string name="force_rtl_layout_all_locales_summary" msgid="9192797796616132534">"Vynutit ve všech jazycích rozvržení obrazovky zprava doleva"</string>
    +-    <string name="show_cpu_usage" msgid="2389212910758076024">"Zobrazit využití CPU"</string>
    +-    <string name="show_cpu_usage_summary" msgid="2113341923988958266">"Překryvná vrstva s aktuálním využitím procesoru"</string>
    +     <string name="force_hw_ui" msgid="6426383462520888732">"Vykreslování pomocí GPU"</string>
    +     <string name="force_hw_ui_summary" msgid="5535991166074861515">"Vynutit použití GPU pro 2D vykreslování"</string>
    +     <string name="force_msaa" msgid="7920323238677284387">"Vynutit 4x MSAA"</string>
    +@@ -341,4 +340,5 @@
    +     <string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"Největší"</string>
    +     <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Vlastní (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
    +     <string name="help_feedback_label" msgid="6815040660801785649">"Nápověda a zpětná vazba"</string>
    ++    <string name="content_description_menu_button" msgid="8182594799812351266">"Nabídka"</string>
    + </resources>
    +diff --git a/packages/SettingsLib/res/values-da/strings.xml b/packages/SettingsLib/res/values-da/strings.xml
    +index 98f41fc..108d8dc 100644
    +--- a/packages/SettingsLib/res/values-da/strings.xml
    ++++ b/packages/SettingsLib/res/values-da/strings.xml
    +@@ -28,7 +28,8 @@
    +     <string name="wifi_disabled_wifi_failure" msgid="3081668066612876581">"Wi-Fi-forbindelsesfejl"</string>
    +     <string name="wifi_disabled_password_failure" msgid="8659805351763133575">"Problem med godkendelse"</string>
    +     <string name="wifi_not_in_range" msgid="1136191511238508967">"Ikke inden for rækkevidde"</string>
    +-    <string name="wifi_no_internet" msgid="9151470775868728896">"Der blev ikke fundet nogen internetadgang. Forbindelsen bliver ikke automatisk genoprettet."</string>
    ++    <string name="wifi_no_internet_no_reconnect" msgid="2211781637653149657">"Der blev ikke fundet nogen internetadgang. Forbindelsen bliver ikke automatisk genoprettet."</string>
    ++    <string name="wifi_no_internet" msgid="5011955173375805204">"Ingen internetadgang."</string>
    +     <string name="saved_network" msgid="4352716707126620811">"Gemt af <xliff:g id="NAME">%1$s</xliff:g>"</string>
    +     <string name="connected_via_wfa" msgid="3805736726317410714">"Forbindelse via Wi-Fi-assistent"</string>
    +     <string name="connected_via_passpoint" msgid="2826205693803088747">"Tilsluttet via %1$s"</string>
    +@@ -151,7 +152,7 @@
    +     <string name="clear_adb_keys" msgid="4038889221503122743">"Tilbagekald tilladelser for USB-fejlfinding"</string>
    +     <string name="bugreport_in_power" msgid="7923901846375587241">"Genvej til fejlrapporting"</string>
    +     <string name="bugreport_in_power_summary" msgid="1778455732762984579">"Vis en knap til oprettelse af fejlrapporter i menu for slukknap"</string>
    +-    <string name="keep_screen_on" msgid="1146389631208760344">"Undgå dvale"</string>
    ++    <string name="keep_screen_on" msgid="1146389631208760344">"Lås ikke"</string>
    +     <string name="keep_screen_on_summary" msgid="2173114350754293009">"Skærmen går ikke i dvale under opladning"</string>
    +     <string name="bt_hci_snoop_log" msgid="3340699311158865670">"Aktivér Bluetooth HCI snoop log"</string>
    +     <string name="bt_hci_snoop_log_summary" msgid="730247028210113851">"Gem alle Bluetooth HCI-pakker i en fil"</string>
    +@@ -233,8 +234,6 @@
    +     <string name="debug_layout_summary" msgid="2001775315258637682">"Vis grænser for klip, margener osv."</string>
    +     <string name="force_rtl_layout_all_locales" msgid="2259906643093138978">"Tving læsning mod venstre"</string>
    +     <string name="force_rtl_layout_all_locales_summary" msgid="9192797796616132534">"Tving til højre mod venstre-layout for alle sprog"</string>
    +-    <string name="show_cpu_usage" msgid="2389212910758076024">"Vis CPU-forbrug"</string>
    +-    <string name="show_cpu_usage_summary" msgid="2113341923988958266">"Skærmoverlejring viser det aktuelle CPU-forbrug"</string>
    +     <string name="force_hw_ui" msgid="6426383462520888732">"Tving gengivelse af GPU"</string>
    +     <string name="force_hw_ui_summary" msgid="5535991166074861515">"Gennemtving brug af GPU til 2D-tegning"</string>
    +     <string name="force_msaa" msgid="7920323238677284387">"Tving 4x MSAA"</string>
    +@@ -341,4 +340,5 @@
    +     <string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"Størst"</string>
    +     <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Tilpasset (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
    +     <string name="help_feedback_label" msgid="6815040660801785649">"Hjælp og feedback"</string>
    ++    <string name="content_description_menu_button" msgid="8182594799812351266">"Menu"</string>
    + </resources>
    +diff --git a/packages/SettingsLib/res/values-de/strings.xml b/packages/SettingsLib/res/values-de/strings.xml
    +index c9da6c9..d93dbac 100644
    +--- a/packages/SettingsLib/res/values-de/strings.xml
    ++++ b/packages/SettingsLib/res/values-de/strings.xml
    +@@ -28,7 +28,8 @@
    +     <string name="wifi_disabled_wifi_failure" msgid="3081668066612876581">"WLAN-Verbindungsfehler"</string>
    +     <string name="wifi_disabled_password_failure" msgid="8659805351763133575">"Authentifizierungsproblem"</string>
    +     <string name="wifi_not_in_range" msgid="1136191511238508967">"Nicht in Reichweite"</string>
    +-    <string name="wifi_no_internet" msgid="9151470775868728896">"Keine Internetverbindung erkannt, es kann nicht automatisch eine Verbindung hergestellt werden."</string>
    ++    <string name="wifi_no_internet_no_reconnect" msgid="2211781637653149657">"Keine Internetverbindung erkannt. Es kann nicht automatisch eine Verbindung hergestellt werden."</string>
    ++    <string name="wifi_no_internet" msgid="5011955173375805204">"Kein Internetzugriff."</string>
    +     <string name="saved_network" msgid="4352716707126620811">"Gespeichert von <xliff:g id="NAME">%1$s</xliff:g>"</string>
    +     <string name="connected_via_wfa" msgid="3805736726317410714">"Über WLAN-Assistenten verbunden"</string>
    +     <string name="connected_via_passpoint" msgid="2826205693803088747">"Über %1$s verbunden"</string>
    +@@ -38,7 +39,7 @@
    +     <string name="bluetooth_disconnecting" msgid="8913264760027764974">"Verbindung wird getrennt..."</string>
    +     <string name="bluetooth_connecting" msgid="8555009514614320497">"Verbindung wird hergestellt..."</string>
    +     <string name="bluetooth_connected" msgid="6038755206916626419">"Verbunden"</string>
    +-    <string name="bluetooth_pairing" msgid="1426882272690346242">"Pairing läuft…"</string>
    ++    <string name="bluetooth_pairing" msgid="1426882272690346242">"Kopplung läuft…"</string>
    +     <string name="bluetooth_connected_no_headset" msgid="2866994875046035609">"Verbunden (kein Telefon)"</string>
    +     <string name="bluetooth_connected_no_a2dp" msgid="4576188601581440337">"Verbunden (außer Audiomedien)"</string>
    +     <string name="bluetooth_connected_no_map" msgid="6504436917057479986">"Verbunden (ohne Nachrichtenzugriff)"</string>
    +@@ -69,12 +70,12 @@
    +     <string name="bluetooth_headset_profile_summary_use_for" msgid="8705753622443862627">"Für Audiosystem des Telefons verwenden"</string>
    +     <string name="bluetooth_opp_profile_summary_use_for" msgid="1255674547144769756">"Für Dateiübertragung verwenden"</string>
    +     <string name="bluetooth_hid_profile_summary_use_for" msgid="232727040453645139">"Für Eingabe verwenden"</string>
    +-    <string name="bluetooth_pairing_accept" msgid="6163520056536604875">"Pairing durchführen"</string>
    +-    <string name="bluetooth_pairing_accept_all_caps" msgid="6061699265220789149">"Pairing durchführen"</string>
    ++    <string name="bluetooth_pairing_accept" msgid="6163520056536604875">"Koppeln"</string>
    ++    <string name="bluetooth_pairing_accept_all_caps" msgid="6061699265220789149">"KOPPELN"</string>
    +     <string name="bluetooth_pairing_decline" msgid="4185420413578948140">"Abbrechen"</string>
    +-    <string name="bluetooth_pairing_will_share_phonebook" msgid="4982239145676394429">"Über das Pairing kann auf deine Kontakte und auf deinen Anrufverlauf zugegriffen werden, wenn eine Verbindung besteht."</string>
    +-    <string name="bluetooth_pairing_error_message" msgid="3748157733635947087">"Pairing mit <xliff:g id="DEVICE_NAME">%1$s</xliff:g> war nicht möglich."</string>
    +-    <string name="bluetooth_pairing_pin_error_message" msgid="8337234855188925274">"Pairing mit <xliff:g id="DEVICE_NAME">%1$s</xliff:g> war nicht möglich, weil die eingegebene PIN oder der Zugangscode falsch ist."</string>
    ++    <string name="bluetooth_pairing_will_share_phonebook" msgid="4982239145676394429">"Über die Kopplung kann auf deine Kontakte und auf deinen Anrufverlauf zugegriffen werden, wenn eine Verbindung besteht."</string>
    ++    <string name="bluetooth_pairing_error_message" msgid="3748157733635947087">"Kopplung mit <xliff:g id="DEVICE_NAME">%1$s</xliff:g> war nicht möglich."</string>
    ++    <string name="bluetooth_pairing_pin_error_message" msgid="8337234855188925274">"Kopplung mit <xliff:g id="DEVICE_NAME">%1$s</xliff:g> war nicht möglich, weil die eingegebene PIN oder der Zugangscode falsch ist."</string>
    +     <string name="bluetooth_pairing_device_down_error_message" msgid="7870998403045801381">"Kommunikation mit <xliff:g id="DEVICE_NAME">%1$s</xliff:g> ist nicht möglich."</string>
    +     <string name="bluetooth_pairing_rejected_error_message" msgid="1648157108520832454">"Verbindung wurde von <xliff:g id="DEVICE_NAME">%1$s</xliff:g> abgelehnt."</string>
    +     <string name="accessibility_wifi_off" msgid="1166761729660614716">"WLAN: aus"</string>
    +@@ -233,8 +234,6 @@
    +     <string name="debug_layout_summary" msgid="2001775315258637682">"Clip-Begrenzungen, Ränder usw. anzeigen"</string>
    +     <string name="force_rtl_layout_all_locales" msgid="2259906643093138978">"RTL-Layout erzwingen"</string>
    +     <string name="force_rtl_layout_all_locales_summary" msgid="9192797796616132534">"RTL-Bildschirmlayout für alle Sprachen erzwingen"</string>
    +-    <string name="show_cpu_usage" msgid="2389212910758076024">"CPU-Auslastung anzeigen"</string>
    +-    <string name="show_cpu_usage_summary" msgid="2113341923988958266">"Bildschirm-Overlay mit aktueller CPU-Auslastung"</string>
    +     <string name="force_hw_ui" msgid="6426383462520888732">"GPU-Rendering erzwingen"</string>
    +     <string name="force_hw_ui_summary" msgid="5535991166074861515">"Einsatz von GPU für 2D-Zeichnung erzwingen"</string>
    +     <string name="force_msaa" msgid="7920323238677284387">"4x MSAA erzwingen"</string>
    +@@ -341,4 +340,5 @@
    +     <string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"Am größten"</string>
    +     <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Benutzerdefiniert (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
    +     <string name="help_feedback_label" msgid="6815040660801785649">"Hilfe &amp; Feedback"</string>
    ++    <string name="content_description_menu_button" msgid="8182594799812351266">"Menü"</string>
    + </resources>
    +diff --git a/packages/SettingsLib/res/values-el/strings.xml b/packages/SettingsLib/res/values-el/strings.xml
    +index 05e4e64..6bbc11c 100644
    +--- a/packages/SettingsLib/res/values-el/strings.xml
    ++++ b/packages/SettingsLib/res/values-el/strings.xml
    +@@ -28,7 +28,8 @@
    +     <string name="wifi_disabled_wifi_failure" msgid="3081668066612876581">"Αποτυχία σύνδεσης Wi-Fi"</string>
    +     <string name="wifi_disabled_password_failure" msgid="8659805351763133575">"Πρόβλημα ελέγχου ταυτότητας"</string>
    +     <string name="wifi_not_in_range" msgid="1136191511238508967">"Εκτός εμβέλειας"</string>
    +-    <string name="wifi_no_internet" msgid="9151470775868728896">"Δεν εντοπίστηκε καμία πρόσβαση στο διαδίκτυο, δεν θα γίνει αυτόματη επανασύνδεση."</string>
    ++    <string name="wifi_no_internet_no_reconnect" msgid="2211781637653149657">"Δεν εντοπίστηκε πρόσβαση στο διαδίκτυο. Δεν θα πραγματοποιηθεί αυτόματη επανασύνδεση."</string>
    ++    <string name="wifi_no_internet" msgid="5011955173375805204">"Δεν υπάρχει πρόσβαση στο διαδίκτυο."</string>
    +     <string name="saved_network" msgid="4352716707126620811">"Αποθηκεύτηκε από <xliff:g id="NAME">%1$s</xliff:g>"</string>
    +     <string name="connected_via_wfa" msgid="3805736726317410714">"Σύνδεση μέσω βοηθού Wi‑Fi"</string>
    +     <string name="connected_via_passpoint" msgid="2826205693803088747">"Συνδέθηκε μέσω %1$s"</string>
    +@@ -233,8 +234,6 @@
    +     <string name="debug_layout_summary" msgid="2001775315258637682">"Εμφάνιση ορίων κλιπ, περιθωρίων, κλπ."</string>
    +     <string name="force_rtl_layout_all_locales" msgid="2259906643093138978">"Επιβολή κατ. διάταξης RTL"</string>
    +     <string name="force_rtl_layout_all_locales_summary" msgid="9192797796616132534">"Επιβολή διάταξης οθόν. RTL για όλες τις τοπ. ρυθμ."</string>
    +-    <string name="show_cpu_usage" msgid="2389212910758076024">"Προβολή χρήσης CPU"</string>
    +-    <string name="show_cpu_usage_summary" msgid="2113341923988958266">"Επικάλυψη οθόνης για προβολή τρέχουσας χρήσης CPU"</string>
    +     <string name="force_hw_ui" msgid="6426383462520888732">"Αναγκαστική απόδοση GPU"</string>
    +     <string name="force_hw_ui_summary" msgid="5535991166074861515">"Αναγκαστική χρήση του GPU για σχέδιο 2D"</string>
    +     <string name="force_msaa" msgid="7920323238677284387">"Αναγκαστικά 4x MSAA"</string>
    +@@ -287,8 +286,8 @@
    +     <string name="convert_to_file_encryption_enabled" msgid="2861258671151428346">"Μετατροπή…"</string>
    +     <string name="convert_to_file_encryption_done" msgid="7859766358000523953">"Με κρυπτογράφηση αρχείου"</string>
    +     <string name="title_convert_fbe" msgid="1263622876196444453">"Μετατροπή σε κρυπτογράφηση βάσει αρχείου…"</string>
    +-    <string name="convert_to_fbe_warning" msgid="6139067817148865527">"Μετατροπή τμήματος δεδομένων σε κρυπτογράφηση βάσει αρχείου.\n !!Προσοχή!! Με αυτήν την ενέργεια, θα διαγραφούν όλα τα δεδομένα σας.\n Αυτή η λειτουργία βρίσκεται σε δοκιμαστικό στάδιο alpha και ενδέχεται να μην λειτουργεί σωστά.\n Πατήστε \"Εκκαθάριση και μετατροπή…\" για να συνεχίσετε."</string>
    +-    <string name="button_convert_fbe" msgid="5152671181309826405">"Εκκαθάριση και μετατροπή…"</string>
    ++    <string name="convert_to_fbe_warning" msgid="6139067817148865527">"Μετατροπή τμήματος δεδομένων σε κρυπτογράφηση βάσει αρχείου.\n !!Προσοχή!! Με αυτήν την ενέργεια, θα διαγραφούν όλα τα δεδομένα σας.\n Αυτή η λειτουργία βρίσκεται σε δοκιμαστικό στάδιο alpha και ενδέχεται να μην λειτουργεί σωστά.\n Πατήστε \"Διαγραφή και μετατροπή…\" για να συνεχίσετε."</string>
    ++    <string name="button_convert_fbe" msgid="5152671181309826405">"Διαγραφή και μετατροπή…"</string>
    +     <string name="picture_color_mode" msgid="4560755008730283695">"Λειτουργία χρώματος εικόνας"</string>
    +     <string name="picture_color_mode_desc" msgid="1141891467675548590">"Χρήση sRGB"</string>
    +     <string name="daltonizer_mode_disabled" msgid="7482661936053801862">"Απενεργοποιημένο"</string>
    +@@ -341,4 +340,5 @@
    +     <string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"Μεγαλύτερα"</string>
    +     <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Προσαρμοσμένη (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
    +     <string name="help_feedback_label" msgid="6815040660801785649">"Βοήθεια και σχόλια"</string>
    ++    <string name="content_description_menu_button" msgid="8182594799812351266">"Μενού"</string>
    + </resources>
    +diff --git a/packages/SettingsLib/res/values-en-rAU/strings.xml b/packages/SettingsLib/res/values-en-rAU/strings.xml
    +index 799802b..a571aff 100644
    +--- a/packages/SettingsLib/res/values-en-rAU/strings.xml
    ++++ b/packages/SettingsLib/res/values-en-rAU/strings.xml
    +@@ -28,7 +28,8 @@
    +     <string name="wifi_disabled_wifi_failure" msgid="3081668066612876581">"Wi-Fi Connection Failure"</string>
    +     <string name="wifi_disabled_password_failure" msgid="8659805351763133575">"Authentication problem"</string>
    +     <string name="wifi_not_in_range" msgid="1136191511238508967">"Not in range"</string>
    +-    <string name="wifi_no_internet" msgid="9151470775868728896">"No Internet Access Detected, won\'t automatically reconnect."</string>
    ++    <string name="wifi_no_internet_no_reconnect" msgid="2211781637653149657">"No Internet access detected, won\'t automatically reconnect."</string>
    ++    <string name="wifi_no_internet" msgid="5011955173375805204">"No Internet Access."</string>
    +     <string name="saved_network" msgid="4352716707126620811">"Saved by <xliff:g id="NAME">%1$s</xliff:g>"</string>
    +     <string name="connected_via_wfa" msgid="3805736726317410714">"Connected via Wi‑Fi assistant"</string>
    +     <string name="connected_via_passpoint" msgid="2826205693803088747">"Connected via %1$s"</string>
    +@@ -233,8 +234,6 @@
    +     <string name="debug_layout_summary" msgid="2001775315258637682">"Show clip bounds, margins, etc."</string>
    +     <string name="force_rtl_layout_all_locales" msgid="2259906643093138978">"Force RTL layout direction"</string>
    +     <string name="force_rtl_layout_all_locales_summary" msgid="9192797796616132534">"Force screen layout direction to RTL for all locales"</string>
    +-    <string name="show_cpu_usage" msgid="2389212910758076024">"Show CPU usage"</string>
    +-    <string name="show_cpu_usage_summary" msgid="2113341923988958266">"Screen overlay showing current CPU usage"</string>
    +     <string name="force_hw_ui" msgid="6426383462520888732">"Force GPU rendering"</string>
    +     <string name="force_hw_ui_summary" msgid="5535991166074861515">"Force use of GPU for 2D drawing"</string>
    +     <string name="force_msaa" msgid="7920323238677284387">"Force 4x MSAA"</string>
    +@@ -341,4 +340,5 @@
    +     <string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"Largest"</string>
    +     <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Custom (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
    +     <string name="help_feedback_label" msgid="6815040660801785649">"Help &amp; feedback"</string>
    ++    <string name="content_description_menu_button" msgid="8182594799812351266">"Menu"</string>
    + </resources>
    +diff --git a/packages/SettingsLib/res/values-en-rGB/strings.xml b/packages/SettingsLib/res/values-en-rGB/strings.xml
    +index 799802b..a571aff 100644
    +--- a/packages/SettingsLib/res/values-en-rGB/strings.xml
    ++++ b/packages/SettingsLib/res/values-en-rGB/strings.xml
    +@@ -28,7 +28,8 @@
    +     <string name="wifi_disabled_wifi_failure" msgid="3081668066612876581">"Wi-Fi Connection Failure"</string>
    +     <string name="wifi_disabled_password_failure" msgid="8659805351763133575">"Authentication problem"</string>
    +     <string name="wifi_not_in_range" msgid="1136191511238508967">"Not in range"</string>
    +-    <string name="wifi_no_internet" msgid="9151470775868728896">"No Internet Access Detected, won\'t automatically reconnect."</string>
    ++    <string name="wifi_no_internet_no_reconnect" msgid="2211781637653149657">"No Internet access detected, won\'t automatically reconnect."</string>
    ++    <string name="wifi_no_internet" msgid="5011955173375805204">"No Internet Access."</string>
    +     <string name="saved_network" msgid="4352716707126620811">"Saved by <xliff:g id="NAME">%1$s</xliff:g>"</string>
    +     <string name="connected_via_wfa" msgid="3805736726317410714">"Connected via Wi‑Fi assistant"</string>
    +     <string name="connected_via_passpoint" msgid="2826205693803088747">"Connected via %1$s"</string>
    +@@ -233,8 +234,6 @@
    +     <string name="debug_layout_summary" msgid="2001775315258637682">"Show clip bounds, margins, etc."</string>
    +     <string name="force_rtl_layout_all_locales" msgid="2259906643093138978">"Force RTL layout direction"</string>
    +     <string name="force_rtl_layout_all_locales_summary" msgid="9192797796616132534">"Force screen layout direction to RTL for all locales"</string>
    +-    <string name="show_cpu_usage" msgid="2389212910758076024">"Show CPU usage"</string>
    +-    <string name="show_cpu_usage_summary" msgid="2113341923988958266">"Screen overlay showing current CPU usage"</string>
    +     <string name="force_hw_ui" msgid="6426383462520888732">"Force GPU rendering"</string>
    +     <string name="force_hw_ui_summary" msgid="5535991166074861515">"Force use of GPU for 2D drawing"</string>
    +     <string name="force_msaa" msgid="7920323238677284387">"Force 4x MSAA"</string>
    +@@ -341,4 +340,5 @@
    +     <string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"Largest"</string>
    +     <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Custom (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
    +     <string name="help_feedback_label" msgid="6815040660801785649">"Help &amp; feedback"</string>
    ++    <string name="content_description_menu_button" msgid="8182594799812351266">"Menu"</string>
    + </resources>
    +diff --git a/packages/SettingsLib/res/values-en-rIN/strings.xml b/packages/SettingsLib/res/values-en-rIN/strings.xml
    +index 799802b..a571aff 100644
    +--- a/packages/SettingsLib/res/values-en-rIN/strings.xml
    ++++ b/packages/SettingsLib/res/values-en-rIN/strings.xml
    +@@ -28,7 +28,8 @@
    +     <string name="wifi_disabled_wifi_failure" msgid="3081668066612876581">"Wi-Fi Connection Failure"</string>
    +     <string name="wifi_disabled_password_failure" msgid="8659805351763133575">"Authentication problem"</string>
    +     <string name="wifi_not_in_range" msgid="1136191511238508967">"Not in range"</string>
    +-    <string name="wifi_no_internet" msgid="9151470775868728896">"No Internet Access Detected, won\'t automatically reconnect."</string>
    ++    <string name="wifi_no_internet_no_reconnect" msgid="2211781637653149657">"No Internet access detected, won\'t automatically reconnect."</string>
    ++    <string name="wifi_no_internet" msgid="5011955173375805204">"No Internet Access."</string>
    +     <string name="saved_network" msgid="4352716707126620811">"Saved by <xliff:g id="NAME">%1$s</xliff:g>"</string>
    +     <string name="connected_via_wfa" msgid="3805736726317410714">"Connected via Wi‑Fi assistant"</string>
    +     <string name="connected_via_passpoint" msgid="2826205693803088747">"Connected via %1$s"</string>
    +@@ -233,8 +234,6 @@
    +     <string name="debug_layout_summary" msgid="2001775315258637682">"Show clip bounds, margins, etc."</string>
    +     <string name="force_rtl_layout_all_locales" msgid="2259906643093138978">"Force RTL layout direction"</string>
    +     <string name="force_rtl_layout_all_locales_summary" msgid="9192797796616132534">"Force screen layout direction to RTL for all locales"</string>
    +-    <string name="show_cpu_usage" msgid="2389212910758076024">"Show CPU usage"</string>
    +-    <string name="show_cpu_usage_summary" msgid="2113341923988958266">"Screen overlay showing current CPU usage"</string>
    +     <string name="force_hw_ui" msgid="6426383462520888732">"Force GPU rendering"</string>
    +     <string name="force_hw_ui_summary" msgid="5535991166074861515">"Force use of GPU for 2D drawing"</string>
    +     <string name="force_msaa" msgid="7920323238677284387">"Force 4x MSAA"</string>
    +@@ -341,4 +340,5 @@
    +     <string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"Largest"</string>
    +     <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Custom (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
    +     <string name="help_feedback_label" msgid="6815040660801785649">"Help &amp; feedback"</string>
    ++    <string name="content_description_menu_button" msgid="8182594799812351266">"Menu"</string>
    + </resources>
    +diff --git a/packages/SettingsLib/res/values-es-rUS/strings.xml b/packages/SettingsLib/res/values-es-rUS/strings.xml
    +index 08e739a..924c18a 100644
    +--- a/packages/SettingsLib/res/values-es-rUS/strings.xml
    ++++ b/packages/SettingsLib/res/values-es-rUS/strings.xml
    +@@ -28,7 +28,8 @@
    +     <string name="wifi_disabled_wifi_failure" msgid="3081668066612876581">"Error de conexión Wi-Fi"</string>
    +     <string name="wifi_disabled_password_failure" msgid="8659805351763133575">"Problema de autenticación"</string>
    +     <string name="wifi_not_in_range" msgid="1136191511238508967">"Fuera de alcance"</string>
    +-    <string name="wifi_no_internet" msgid="9151470775868728896">"No se detectó el acceso a Internet. No se volverá a conectar de forma automática."</string>
    ++    <string name="wifi_no_internet_no_reconnect" msgid="2211781637653149657">"No se detectó el acceso a Internet. No se volverá a conectar de forma automática."</string>
    ++    <string name="wifi_no_internet" msgid="5011955173375805204">"No se detectó el acceso a Internet."</string>
    +     <string name="saved_network" msgid="4352716707126620811">"Guardadas por <xliff:g id="NAME">%1$s</xliff:g>"</string>
    +     <string name="connected_via_wfa" msgid="3805736726317410714">"Conexión por asistente de Wi-Fi"</string>
    +     <string name="connected_via_passpoint" msgid="2826205693803088747">"Conexión a través de %1$s"</string>
    +@@ -233,8 +234,6 @@
    +     <string name="debug_layout_summary" msgid="2001775315258637682">"Mostrar límites de recortes, márgenes, etc."</string>
    +     <string name="force_rtl_layout_all_locales" msgid="2259906643093138978">"Forzar diseño der. a izq."</string>
    +     <string name="force_rtl_layout_all_locales_summary" msgid="9192797796616132534">"Forzar diseño pantalla der.&gt;izq., cualquier idioma"</string>
    +-    <string name="show_cpu_usage" msgid="2389212910758076024">"Mostrar el uso de CPU"</string>
    +-    <string name="show_cpu_usage_summary" msgid="2113341923988958266">"Mostrar superposición en pantalla con uso actual de la CPU"</string>
    +     <string name="force_hw_ui" msgid="6426383462520888732">"Forzar representación GPU"</string>
    +     <string name="force_hw_ui_summary" msgid="5535991166074861515">"Forzar uso de GPU para dibujar en 2d"</string>
    +     <string name="force_msaa" msgid="7920323238677284387">"Forzar MSAA 4x"</string>
    +@@ -341,4 +340,5 @@
    +     <string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"Máximo"</string>
    +     <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Personalizado (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
    +     <string name="help_feedback_label" msgid="6815040660801785649">"Ayuda y comentarios"</string>
    ++    <string name="content_description_menu_button" msgid="8182594799812351266">"Menú"</string>
    + </resources>
    +diff --git a/packages/SettingsLib/res/values-es/strings.xml b/packages/SettingsLib/res/values-es/strings.xml
    +index 3d2f6c1..7824949 100644
    +--- a/packages/SettingsLib/res/values-es/strings.xml
    ++++ b/packages/SettingsLib/res/values-es/strings.xml
    +@@ -28,7 +28,8 @@
    +     <string name="wifi_disabled_wifi_failure" msgid="3081668066612876581">"Error de conexión Wi-Fi"</string>
    +     <string name="wifi_disabled_password_failure" msgid="8659805351763133575">"Error de autenticación"</string>
    +     <string name="wifi_not_in_range" msgid="1136191511238508967">"Fuera de rango"</string>
    +-    <string name="wifi_no_internet" msgid="9151470775868728896">"No se ha detectado acceso a Internet, no se volverá a conectar automáticamente."</string>
    ++    <string name="wifi_no_internet_no_reconnect" msgid="2211781637653149657">"No se ha detectado acceso a Internet, por lo que no se volverá a conectar automáticamente."</string>
    ++    <string name="wifi_no_internet" msgid="5011955173375805204">"No se ha detectado acceso a Internet."</string>
    +     <string name="saved_network" msgid="4352716707126620811">"Guardadas por <xliff:g id="NAME">%1$s</xliff:g>"</string>
    +     <string name="connected_via_wfa" msgid="3805736726317410714">"Conectado a través de asistente Wi‑Fi"</string>
    +     <string name="connected_via_passpoint" msgid="2826205693803088747">"Conectado a través de %1$s"</string>
    +@@ -173,7 +174,7 @@
    +     <string name="wifi_verbose_logging_summary" msgid="6615071616111731958">"Aumentar el nivel de logging de Wi-Fi, mostrar por SSID RSSI en el selector Wi-Fi"</string>
    +     <string name="wifi_aggressive_handover_summary" msgid="6328455667642570371">"Si está habilitada, la conexión Wi‑Fi será más agresiva al transferir la conexión de datos al móvil (si la señal Wi‑Fi no es estable)"</string>
    +     <string name="wifi_allow_scan_with_traffic_summary" msgid="2575101424972686310">"Permitir/No permitir búsquedas de Wi-Fi basadas en la cantidad de tráfico de datos presente en la interfaz"</string>
    +-    <string name="select_logd_size_title" msgid="7433137108348553508">"Tamaños del búfer de Logger"</string>
    ++    <string name="select_logd_size_title" msgid="7433137108348553508">"Tamaños de búfer de registrador"</string>
    +     <string name="select_logd_size_dialog_title" msgid="1206769310236476760">"Elige el tamaño del Logger por búfer"</string>
    +     <string name="dev_logpersist_clear_warning_title" msgid="684806692440237967">"¿Borrar almacenamiento continuo del registrador?"</string>
    +     <string name="dev_logpersist_clear_warning_message" msgid="2256582531342994562">"Cuando ya no supervisamos la actividad con el registrador de forma continua, estamos obligados a borrar los datos del registrador almacenados en el dispositivo."</string>
    +@@ -233,8 +234,6 @@
    +     <string name="debug_layout_summary" msgid="2001775315258637682">"Mostrar límites de vídeo, márgenes, etc."</string>
    +     <string name="force_rtl_layout_all_locales" msgid="2259906643093138978">"Forzar dirección diseño RTL"</string>
    +     <string name="force_rtl_layout_all_locales_summary" msgid="9192797796616132534">"Forzar dirección (RTL) para todas configuraciones"</string>
    +-    <string name="show_cpu_usage" msgid="2389212910758076024">"Mostrar uso de la CPU"</string>
    +-    <string name="show_cpu_usage_summary" msgid="2113341923988958266">"Suporponer el uso de la CPU en la pantalla"</string>
    +     <string name="force_hw_ui" msgid="6426383462520888732">"Forzar aceleración GPU"</string>
    +     <string name="force_hw_ui_summary" msgid="5535991166074861515">"Forzar uso de GPU para dibujos en 2D"</string>
    +     <string name="force_msaa" msgid="7920323238677284387">"Forzar MSAA 4x"</string>
    +@@ -341,4 +340,5 @@
    +     <string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"Lo más grande posible"</string>
    +     <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Personalizado (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
    +     <string name="help_feedback_label" msgid="6815040660801785649">"Ayuda y sugerencias"</string>
    ++    <string name="content_description_menu_button" msgid="8182594799812351266">"Menú"</string>
    + </resources>
    +diff --git a/packages/SettingsLib/res/values-et-rEE/strings.xml b/packages/SettingsLib/res/values-et-rEE/strings.xml
    +index a7b0f64..5f76b9f 100644
    +--- a/packages/SettingsLib/res/values-et-rEE/strings.xml
    ++++ b/packages/SettingsLib/res/values-et-rEE/strings.xml
    +@@ -28,7 +28,8 @@
    +     <string name="wifi_disabled_wifi_failure" msgid="3081668066612876581">"WiFi-ühenduse viga"</string>
    +     <string name="wifi_disabled_password_failure" msgid="8659805351763133575">"Autentimise probleem"</string>
    +     <string name="wifi_not_in_range" msgid="1136191511238508967">"Pole vahemikus"</string>
    +-    <string name="wifi_no_internet" msgid="9151470775868728896">"Interneti-ühendust ei tuvastatud, seadet ei ühendata automaatselt."</string>
    ++    <string name="wifi_no_internet_no_reconnect" msgid="2211781637653149657">"Interneti-ühendust ei tuvastatud, seadet ei ühendata automaatselt uuesti."</string>
    ++    <string name="wifi_no_internet" msgid="5011955173375805204">"Interneti-ühendus puudub."</string>
    +     <string name="saved_network" msgid="4352716707126620811">"Salvestas: <xliff:g id="NAME">%1$s</xliff:g>"</string>
    +     <string name="connected_via_wfa" msgid="3805736726317410714">"Ühendatud WiFi-abi kaudu"</string>
    +     <string name="connected_via_passpoint" msgid="2826205693803088747">"Ühendatud üksuse %1$s kaudu"</string>
    +@@ -233,8 +234,6 @@
    +     <string name="debug_layout_summary" msgid="2001775315258637682">"Kuva klipi piirid, veerised jms"</string>
    +     <string name="force_rtl_layout_all_locales" msgid="2259906643093138978">"Paremalt vasakule paig."</string>
    +     <string name="force_rtl_layout_all_locales_summary" msgid="9192797796616132534">"Määra lokaatides ekraanipaig. paremalt vasakule"</string>
    +-    <string name="show_cpu_usage" msgid="2389212910758076024">"CPU-kasutuse kuvamine"</string>
    +-    <string name="show_cpu_usage_summary" msgid="2113341923988958266">"Praegust CPU-kasutust kuvav ekraani ülekate"</string>
    +     <string name="force_hw_ui" msgid="6426383462520888732">"Jõusta GPU renderdamine"</string>
    +     <string name="force_hw_ui_summary" msgid="5535991166074861515">"Jõusta GPU kasutam. kahemõõtmeliste jooniste puhul"</string>
    +     <string name="force_msaa" msgid="7920323238677284387">"Jõusta 4x MSAA"</string>
    +@@ -341,4 +340,5 @@
    +     <string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"Suurim"</string>
    +     <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Kohandatud (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
    +     <string name="help_feedback_label" msgid="6815040660801785649">"Abi ja tagasiside"</string>
    ++    <string name="content_description_menu_button" msgid="8182594799812351266">"Menüü"</string>
    + </resources>
    +diff --git a/packages/SettingsLib/res/values-eu-rES/strings.xml b/packages/SettingsLib/res/values-eu-rES/strings.xml
    +index f476511..abcf282 100644
    +--- a/packages/SettingsLib/res/values-eu-rES/strings.xml
    ++++ b/packages/SettingsLib/res/values-eu-rES/strings.xml
    +@@ -28,7 +28,8 @@
    +     <string name="wifi_disabled_wifi_failure" msgid="3081668066612876581">"Ezin izan da konektatu Wi-Fi sarera"</string>
    +     <string name="wifi_disabled_password_failure" msgid="8659805351763133575">"Autentifikazio-arazoa"</string>
    +     <string name="wifi_not_in_range" msgid="1136191511238508967">"Urrunegi"</string>
    +-    <string name="wifi_no_internet" msgid="9151470775868728896">"Ez da hauteman Interneterako sarbiderik. Ez da automatikoki berriro konektatuko."</string>
    ++    <string name="wifi_no_internet_no_reconnect" msgid="2211781637653149657">"Ez da hauteman Interneterako sarbiderik. Ez da automatikoki berriro konektatuko."</string>
    ++    <string name="wifi_no_internet" msgid="5011955173375805204">"Ezin da konektatu Internetera."</string>
    +     <string name="saved_network" msgid="4352716707126620811">"<xliff:g id="NAME">%1$s</xliff:g> aplikazioak gorde du"</string>
    +     <string name="connected_via_wfa" msgid="3805736726317410714">"Wi‑Fi laguntzailearen bidez konektatuta"</string>
    +     <string name="connected_via_passpoint" msgid="2826205693803088747">"%1$s bidez konektatuta"</string>
    +@@ -233,8 +234,6 @@
    +     <string name="debug_layout_summary" msgid="2001775315258637682">"Erakutsi kliparen mugak, marjinak, etab."</string>
    +     <string name="force_rtl_layout_all_locales" msgid="2259906643093138978">"Behartu eskuin-ezker norabidea."</string>
    +     <string name="force_rtl_layout_all_locales_summary" msgid="9192797796616132534">"Behartu pantaila-diseinuaren norabidea eskuin-ezker izatera eskualdeko ezarpen guztiekin."</string>
    +-    <string name="show_cpu_usage" msgid="2389212910758076024">"Erakutsi PUZ erabilera"</string>
    +-    <string name="show_cpu_usage_summary" msgid="2113341923988958266">"PUZ erabilera erakusten duen pantaila-gainjartzea"</string>
    +     <string name="force_hw_ui" msgid="6426383462520888732">"Behartu GPU errendatzea"</string>
    +     <string name="force_hw_ui_summary" msgid="5535991166074861515">"Behartu GPUa erabiltzera 2 dimentsioko marrazkietan."</string>
    +     <string name="force_msaa" msgid="7920323238677284387">"Behartu 4x MSAA"</string>
    +@@ -341,4 +340,5 @@
    +     <string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"Handiena"</string>
    +     <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Pertsonalizatua (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
    +     <string name="help_feedback_label" msgid="6815040660801785649">"Laguntza eta iritziak"</string>
    ++    <string name="content_description_menu_button" msgid="8182594799812351266">"Menua"</string>
    + </resources>
    +diff --git a/packages/SettingsLib/res/values-fa/strings.xml b/packages/SettingsLib/res/values-fa/strings.xml
    +index 4491851..c573b68 100644
    +--- a/packages/SettingsLib/res/values-fa/strings.xml
    ++++ b/packages/SettingsLib/res/values-fa/strings.xml
    +@@ -28,7 +28,8 @@
    +     <string name="wifi_disabled_wifi_failure" msgid="3081668066612876581">"‏اتصال Wi-Fi برقرار نشد"</string>
    +     <string name="wifi_disabled_password_failure" msgid="8659805351763133575">"مشکل احراز هویت"</string>
    +     <string name="wifi_not_in_range" msgid="1136191511238508967">"در محدوده نیست"</string>
    +-    <string name="wifi_no_internet" msgid="9151470775868728896">"دسترسی به اینترنت شناسایی نشد، به صورت خودکار وصل نمی‌شود."</string>
    ++    <string name="wifi_no_internet_no_reconnect" msgid="2211781637653149657">"دسترسی به اینترنت شناسایی نشد، به‌صورت خودکار وصل نمی‌شود."</string>
    ++    <string name="wifi_no_internet" msgid="5011955173375805204">"دسترسی به اینترنت وجود ندارد."</string>
    +     <string name="saved_network" msgid="4352716707126620811">"ذخیره‌شده توسط <xliff:g id="NAME">%1$s</xliff:g>"</string>
    +     <string name="connected_via_wfa" msgid="3805736726317410714">"‏متصل شده از طریق دستیار Wi-Fi"</string>
    +     <string name="connected_via_passpoint" msgid="2826205693803088747">"‏متصل از طریق %1$s"</string>
    +@@ -183,7 +184,7 @@
    +     <string name="select_usb_configuration_dialog_title" msgid="6385564442851599963">"‏انتخاب پیکربندی USB"</string>
    +     <string name="allow_mock_location" msgid="2787962564578664888">"مکان‌های کاذب مجاز هستند"</string>
    +     <string name="allow_mock_location_summary" msgid="317615105156345626">"مکان‌های کاذب مجاز هستند"</string>
    +-    <string name="debug_view_attributes" msgid="6485448367803310384">"فعال کردن بازبینی ویژگی بازدید"</string>
    ++    <string name="debug_view_attributes" msgid="6485448367803310384">"فعال کردن نمایش بازبینی ویژگی"</string>
    +     <string name="mobile_data_always_on_summary" msgid="8149773901431697910">"‏داده سلولی همیشه فعال نگه داشته می‌شود، حتی وقتی Wi-Fi فعال است (برای جابه‌جایی سریع شبکه)."</string>
    +     <string name="adb_warning_title" msgid="6234463310896563253">"‏اشکال‌زدایی USB انجام شود؟"</string>
    +     <string name="adb_warning_message" msgid="7316799925425402244">"‏اشکال‌زدایی USB فقط برای اهداف برنامه‌نویسی در نظر گرفته شده است. از آن برای رونوشت‌برداری داده بین رایانه و دستگاهتان، نصب برنامه‌ها در دستگاهتان بدون اعلان و خواندن داده‌های گزارش استفاده کنید."</string>
    +@@ -233,8 +234,6 @@
    +     <string name="debug_layout_summary" msgid="2001775315258637682">"نمایش مرزها، حاشیه‌ها و ویژگی‌های دیگر کلیپ."</string>
    +     <string name="force_rtl_layout_all_locales" msgid="2259906643093138978">"‏اجباری کردن چیدمان RTL"</string>
    +     <string name="force_rtl_layout_all_locales_summary" msgid="9192797796616132534">"‏اجباری کردن چیدمان RTL صفحه برای همه زبان‌ها"</string>
    +-    <string name="show_cpu_usage" msgid="2389212910758076024">"‏نمایش میزان استفاده از CPU"</string>
    +-    <string name="show_cpu_usage_summary" msgid="2113341923988958266">"‏هم‌پوشانی صفحه‌نمایش میزان استفاده از CPU فعلی"</string>
    +     <string name="force_hw_ui" msgid="6426383462520888732">"‏پردازش اجباری GPU"</string>
    +     <string name="force_hw_ui_summary" msgid="5535991166074861515">"‏استفاده اجباری از GPU برای طراحی دوم"</string>
    +     <string name="force_msaa" msgid="7920323238677284387">"‏اجبار 4x MSAA"</string>
    +@@ -341,4 +340,5 @@
    +     <string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"بزرگ‌ترین"</string>
    +     <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"سفارشی (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
    +     <string name="help_feedback_label" msgid="6815040660801785649">"راهنما و بازخورد"</string>
    ++    <string name="content_description_menu_button" msgid="8182594799812351266">"منو"</string>
    + </resources>
    +diff --git a/packages/SettingsLib/res/values-fi/strings.xml b/packages/SettingsLib/res/values-fi/strings.xml
    +index cdef968..05f786a 100644
    +--- a/packages/SettingsLib/res/values-fi/strings.xml
    ++++ b/packages/SettingsLib/res/values-fi/strings.xml
    +@@ -28,7 +28,8 @@
    +     <string name="wifi_disabled_wifi_failure" msgid="3081668066612876581">"Wi-Fi-yhteysvirhe"</string>
    +     <string name="wifi_disabled_password_failure" msgid="8659805351763133575">"Todennusvirhe"</string>
    +     <string name="wifi_not_in_range" msgid="1136191511238508967">"Ei kantoalueella"</string>
    +-    <string name="wifi_no_internet" msgid="9151470775868728896">"Internetyhteyttä ei havaittu, yhteyttä ei muodosteta automaattisesti uudelleen."</string>
    ++    <string name="wifi_no_internet_no_reconnect" msgid="2211781637653149657">"Internetyhteyttä ei havaittu. Yhteyttä ei muodosteta automaattisesti uudelleen."</string>
    ++    <string name="wifi_no_internet" msgid="5011955173375805204">"Ei internetyhteyttä"</string>
    +     <string name="saved_network" msgid="4352716707126620811">"Tallentaja: <xliff:g id="NAME">%1$s</xliff:g>"</string>
    +     <string name="connected_via_wfa" msgid="3805736726317410714">"Yhteys muodostettu Wi‑Fi-apurin kautta"</string>
    +     <string name="connected_via_passpoint" msgid="2826205693803088747">"Yhdistetty seuraavan kautta: %1$s"</string>
    +@@ -233,8 +234,6 @@
    +     <string name="debug_layout_summary" msgid="2001775315258637682">"Näytä leikkeiden rajat, marginaalit jne."</string>
    +     <string name="force_rtl_layout_all_locales" msgid="2259906643093138978">"Pakota RTL-ulkoasun suunta"</string>
    +     <string name="force_rtl_layout_all_locales_summary" msgid="9192797796616132534">"Pakota kaikkien kielten näytön ulkoasun suunnaksi RTL"</string>
    +-    <string name="show_cpu_usage" msgid="2389212910758076024">"Näytä suorittimen käyttö"</string>
    +-    <string name="show_cpu_usage_summary" msgid="2113341923988958266">"Näytön peittokuva näyttää nykyisen suoritinkäytön"</string>
    +     <string name="force_hw_ui" msgid="6426383462520888732">"Pakota GPU-hahmonnus"</string>
    +     <string name="force_hw_ui_summary" msgid="5535991166074861515">"Käytä GPU:ta 2d-piirtämiseen"</string>
    +     <string name="force_msaa" msgid="7920323238677284387">"Pakota 4x MSAA"</string>
    +@@ -341,4 +340,5 @@
    +     <string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"Suurin"</string>
    +     <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Muokattu (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
    +     <string name="help_feedback_label" msgid="6815040660801785649">"Ohje ja palaute"</string>
    ++    <string name="content_description_menu_button" msgid="8182594799812351266">"Valikko"</string>
    + </resources>
    +diff --git a/packages/SettingsLib/res/values-fr-rCA/strings.xml b/packages/SettingsLib/res/values-fr-rCA/strings.xml
    +index 958b8fd..2538443 100644
    +--- a/packages/SettingsLib/res/values-fr-rCA/strings.xml
    ++++ b/packages/SettingsLib/res/values-fr-rCA/strings.xml
    +@@ -28,7 +28,8 @@
    +     <string name="wifi_disabled_wifi_failure" msgid="3081668066612876581">"Échec de connexion Wi-Fi"</string>
    +     <string name="wifi_disabled_password_failure" msgid="8659805351763133575">"Problème d\'authentification"</string>
    +     <string name="wifi_not_in_range" msgid="1136191511238508967">"Hors de portée"</string>
    +-    <string name="wifi_no_internet" msgid="9151470775868728896">"Aucun accès à Internet détecté, reconnexion automatique impossible"</string>
    ++    <string name="wifi_no_internet_no_reconnect" msgid="2211781637653149657">"Aucun accès à Internet détecté, reconnexion automatique impossible."</string>
    ++    <string name="wifi_no_internet" msgid="5011955173375805204">"Aucun accès à Internet."</string>
    +     <string name="saved_network" msgid="4352716707126620811">"Enregistrés par <xliff:g id="NAME">%1$s</xliff:g>"</string>
    +     <string name="connected_via_wfa" msgid="3805736726317410714">"Connecté à l\'aide de l\'assistant Wi-Fi"</string>
    +     <string name="connected_via_passpoint" msgid="2826205693803088747">"Connecté par %1$s"</string>
    +@@ -233,8 +234,6 @@
    +     <string name="debug_layout_summary" msgid="2001775315258637682">"Afficher les limites, les marges de clip, etc."</string>
    +     <string name="force_rtl_layout_all_locales" msgid="2259906643093138978">"Forcer orient. : g. à d."</string>
    +     <string name="force_rtl_layout_all_locales_summary" msgid="9192797796616132534">"Forcer l\'orientation: g. à droite (toutes langues)"</string>
    +-    <string name="show_cpu_usage" msgid="2389212910758076024">"Afficher mém. CPU utilisée"</string>
    +-    <string name="show_cpu_usage_summary" msgid="2113341923988958266">"Superposition écran indiquant mémoire CPU utilisée"</string>
    +     <string name="force_hw_ui" msgid="6426383462520888732">"Forcer le rendu GPU"</string>
    +     <string name="force_hw_ui_summary" msgid="5535991166074861515">"Forcer l\'utilisation du GPU pour le dessin 2D"</string>
    +     <string name="force_msaa" msgid="7920323238677284387">"Forcer MSAA 4x"</string>
    +@@ -341,4 +340,5 @@
    +     <string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"La plus grande"</string>
    +     <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Personnalisée (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
    +     <string name="help_feedback_label" msgid="6815040660801785649">"Aide et commentaires"</string>
    ++    <string name="content_description_menu_button" msgid="8182594799812351266">"Menu"</string>
    + </resources>
    +diff --git a/packages/SettingsLib/res/values-fr/strings.xml b/packages/SettingsLib/res/values-fr/strings.xml
    +index cf08f3b..3b5491f 100644
    +--- a/packages/SettingsLib/res/values-fr/strings.xml
    ++++ b/packages/SettingsLib/res/values-fr/strings.xml
    +@@ -28,7 +28,8 @@
    +     <string name="wifi_disabled_wifi_failure" msgid="3081668066612876581">"Échec de la connexion Wi-Fi"</string>
    +     <string name="wifi_disabled_password_failure" msgid="8659805351763133575">"Problème d\'authentification."</string>
    +     <string name="wifi_not_in_range" msgid="1136191511238508967">"Hors de portée"</string>
    +-    <string name="wifi_no_internet" msgid="9151470775868728896">"Aucun accès à Internet détecté, reconnexion automatique impossible"</string>
    ++    <string name="wifi_no_internet_no_reconnect" msgid="2211781637653149657">"Aucun accès à Internet détecté. Reconnexion automatique impossible."</string>
    ++    <string name="wifi_no_internet" msgid="5011955173375805204">"Aucun accès à Internet"</string>
    +     <string name="saved_network" msgid="4352716707126620811">"Enregistré par <xliff:g id="NAME">%1$s</xliff:g>"</string>
    +     <string name="connected_via_wfa" msgid="3805736726317410714">"Connecté via l\'assistant Wi‑Fi"</string>
    +     <string name="connected_via_passpoint" msgid="2826205693803088747">"Connecté via %1$s"</string>
    +@@ -233,8 +234,6 @@
    +     <string name="debug_layout_summary" msgid="2001775315258637682">"Afficher les limites de coupe, les marges, etc."</string>
    +     <string name="force_rtl_layout_all_locales" msgid="2259906643093138978">"Forcer droite à gauche"</string>
    +     <string name="force_rtl_layout_all_locales_summary" msgid="9192797796616132534">"Forcer orient. droite à gauche pour toutes langues"</string>
    +-    <string name="show_cpu_usage" msgid="2389212910758076024">"Afficher mém. CPU utilisée"</string>
    +-    <string name="show_cpu_usage_summary" msgid="2113341923988958266">"Superposition écran indiquant mémoire CPU utilisée"</string>
    +     <string name="force_hw_ui" msgid="6426383462520888732">"Forcer le rendu GPU"</string>
    +     <string name="force_hw_ui_summary" msgid="5535991166074861515">"Forcer l\'utilisation du GPU pour le dessin 2D"</string>
    +     <string name="force_msaa" msgid="7920323238677284387">"Forcer MSAA 4x"</string>
    +@@ -341,4 +340,5 @@
    +     <string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"Le plus grand"</string>
    +     <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Personnalisé (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
    +     <string name="help_feedback_label" msgid="6815040660801785649">"Aide et commentaires"</string>
    ++    <string name="content_description_menu_button" msgid="8182594799812351266">"Menu"</string>
    + </resources>
    +diff --git a/packages/SettingsLib/res/values-gl-rES/strings.xml b/packages/SettingsLib/res/values-gl-rES/strings.xml
    +index cdc4581..dcd45a8 100644
    +--- a/packages/SettingsLib/res/values-gl-rES/strings.xml
    ++++ b/packages/SettingsLib/res/values-gl-rES/strings.xml
    +@@ -28,7 +28,8 @@
    +     <string name="wifi_disabled_wifi_failure" msgid="3081668066612876581">"Erro na conexión wifi"</string>
    +     <string name="wifi_disabled_password_failure" msgid="8659805351763133575">"Problema de autenticación"</string>
    +     <string name="wifi_not_in_range" msgid="1136191511238508967">"Non está dentro da zona de cobertura"</string>
    +-    <string name="wifi_no_internet" msgid="9151470775868728896">"Non se detectou acceso a Internet e non se volverá conectar automaticamente."</string>
    ++    <string name="wifi_no_internet_no_reconnect" msgid="2211781637653149657">"Non se detectou acceso a Internet e non se volverá establecer conexión automaticamente."</string>
    ++    <string name="wifi_no_internet" msgid="5011955173375805204">"Non hai acceso a Internet."</string>
    +     <string name="saved_network" msgid="4352716707126620811">"Redes gardadas por <xliff:g id="NAME">%1$s</xliff:g>"</string>
    +     <string name="connected_via_wfa" msgid="3805736726317410714">"Conectado ao asistente de wifi"</string>
    +     <string name="connected_via_passpoint" msgid="2826205693803088747">"Conectado a través de %1$s"</string>
    +@@ -233,8 +234,6 @@
    +     <string name="debug_layout_summary" msgid="2001775315258637682">"Mostra os límites dos clips, as marxes, etc."</string>
    +     <string name="force_rtl_layout_all_locales" msgid="2259906643093138978">"Forzar dirección do deseño RTL"</string>
    +     <string name="force_rtl_layout_all_locales_summary" msgid="9192797796616132534">"Forza a dirección de pantalla a RTL (dereita a esquerda) para todas as configuración rexionais"</string>
    +-    <string name="show_cpu_usage" msgid="2389212910758076024">"Mostrar uso da CPU"</string>
    +-    <string name="show_cpu_usage_summary" msgid="2113341923988958266">"Superpoñer o uso da CPU na pantalla"</string>
    +     <string name="force_hw_ui" msgid="6426383462520888732">"Forzar procesamento GPU"</string>
    +     <string name="force_hw_ui_summary" msgid="5535991166074861515">"Forzar o uso de GPU para o debuxo en 2D"</string>
    +     <string name="force_msaa" msgid="7920323238677284387">"Forzar MSAA 4x"</string>
    +@@ -341,4 +340,5 @@
    +     <string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"O máis grande"</string>
    +     <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Personalizado (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
    +     <string name="help_feedback_label" msgid="6815040660801785649">"Axuda e suxestións"</string>
    ++    <string name="content_description_menu_button" msgid="8182594799812351266">"Menú"</string>
    + </resources>
    +diff --git a/packages/SettingsLib/res/values-gu-rIN/strings.xml b/packages/SettingsLib/res/values-gu-rIN/strings.xml
    +index 1b40e01..554ca40 100644
    +--- a/packages/SettingsLib/res/values-gu-rIN/strings.xml
    ++++ b/packages/SettingsLib/res/values-gu-rIN/strings.xml
    +@@ -28,7 +28,8 @@
    +     <string name="wifi_disabled_wifi_failure" msgid="3081668066612876581">"WiFi કનેક્શન નિષ્ફળ"</string>
    +     <string name="wifi_disabled_password_failure" msgid="8659805351763133575">"પ્રમાણીકરણ સમસ્યા"</string>
    +     <string name="wifi_not_in_range" msgid="1136191511238508967">"રેન્જમાં નથી"</string>
    +-    <string name="wifi_no_internet" msgid="9151470775868728896">"કોઈ ઇન્ટરનેટ અ‍ૅક્સેસ શોધાયું નથી, આપમેળે ફરીથી કનેક્ટ કરશે નહીં."</string>
    ++    <string name="wifi_no_internet_no_reconnect" msgid="2211781637653149657">"કોઈ ઇન્ટરનેટ અ‍ૅક્સેસ મળી નથી, આપમેળે ફરીથી કનેક્ટ કરશે નહીં."</string>
    ++    <string name="wifi_no_internet" msgid="5011955173375805204">"કોઈ ઇન્ટરનેટ ઍક્સેસ નથી."</string>
    +     <string name="saved_network" msgid="4352716707126620811">"<xliff:g id="NAME">%1$s</xliff:g> દ્વારા સચવાયું"</string>
    +     <string name="connected_via_wfa" msgid="3805736726317410714">"Wi-Fi સહાયક દ્વારા કનેક્ટ થયું"</string>
    +     <string name="connected_via_passpoint" msgid="2826205693803088747">"%1$s દ્વારા કનેક્ટ થયેલ"</string>
    +@@ -233,8 +234,6 @@
    +     <string name="debug_layout_summary" msgid="2001775315258637682">"ક્લિપ બાઉન્ડ્સ, હાંસિયાં વગેરે બતાવો."</string>
    +     <string name="force_rtl_layout_all_locales" msgid="2259906643093138978">"RTL લેઆઉટ દિશા નિર્દેશની ફરજ પાડો"</string>
    +     <string name="force_rtl_layout_all_locales_summary" msgid="9192797796616132534">"તમામ લૉકેલ્સ માટે સ્ક્રીન લેઆઉટ દિશા નિર્દેશને RTL ની ફરજ પાડો"</string>
    +-    <string name="show_cpu_usage" msgid="2389212910758076024">"CPU સંગ્રહ બતાવો"</string>
    +-    <string name="show_cpu_usage_summary" msgid="2113341923988958266">"વર્તમાન CPU વપરાશ દર્શાવતું સ્ક્રીન ઓવરલે"</string>
    +     <string name="force_hw_ui" msgid="6426383462520888732">"GPU રેન્ડરિંગની ફરજ પાડો"</string>
    +     <string name="force_hw_ui_summary" msgid="5535991166074861515">"2જા રેખાંકન માટે GPU ના ઉપયોગની ફરજ પાડો"</string>
    +     <string name="force_msaa" msgid="7920323238677284387">"4x MSAA ને ફરજ પાડો"</string>
    +@@ -341,4 +340,5 @@
    +     <string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"સૌથી મોટું"</string>
    +     <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"કસ્ટમ (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
    +     <string name="help_feedback_label" msgid="6815040660801785649">"સહાય અને પ્રતિસાદ"</string>
    ++    <string name="content_description_menu_button" msgid="8182594799812351266">"મેનુ"</string>
    + </resources>
    +diff --git a/packages/SettingsLib/res/values-hi/strings.xml b/packages/SettingsLib/res/values-hi/strings.xml
    +index 8dfbb4a..fb6f181 100644
    +--- a/packages/SettingsLib/res/values-hi/strings.xml
    ++++ b/packages/SettingsLib/res/values-hi/strings.xml
    +@@ -28,7 +28,8 @@
    +     <string name="wifi_disabled_wifi_failure" msgid="3081668066612876581">"वाईफ़ाई कनेक्‍शन विफलता"</string>
    +     <string name="wifi_disabled_password_failure" msgid="8659805351763133575">"प्रमाणीकरण समस्या"</string>
    +     <string name="wifi_not_in_range" msgid="1136191511238508967">"रेंज में नहीं"</string>
    +-    <string name="wifi_no_internet" msgid="9151470775868728896">"किसी इंटरनेट कनेक्‍शन का पता नहीं चला, अपने आप पुन: कनेक्‍ट नहीं हो सकता."</string>
    ++    <string name="wifi_no_internet_no_reconnect" msgid="2211781637653149657">"किसी इंटरनेट कनेक्‍शन का पता नहीं चला, अपने आप फिर से कनेक्‍ट नहीं हो सकता."</string>
    ++    <string name="wifi_no_internet" msgid="5011955173375805204">"कोई इंटरनेट एक्सेस नहीं."</string>
    +     <string name="saved_network" msgid="4352716707126620811">"<xliff:g id="NAME">%1$s</xliff:g> के द्वारा सहेजा गया"</string>
    +     <string name="connected_via_wfa" msgid="3805736726317410714">"वाई-फ़ाई सहायक के द्वारा कनेक्‍ट है"</string>
    +     <string name="connected_via_passpoint" msgid="2826205693803088747">"%1$s के द्वारा उपलब्ध"</string>
    +@@ -233,8 +234,6 @@
    +     <string name="debug_layout_summary" msgid="2001775315258637682">"क्लिप सीमाएं, मार्जिन, आदि दिखाएं."</string>
    +     <string name="force_rtl_layout_all_locales" msgid="2259906643093138978">"RTL लेआउट दिशा लागू करें"</string>
    +     <string name="force_rtl_layout_all_locales_summary" msgid="9192797796616132534">"सभी भाषाओं के लिए स्क्रीन लेआउट दिशा को RTL रखें"</string>
    +-    <string name="show_cpu_usage" msgid="2389212910758076024">"CPU उपयोग दिखाएं"</string>
    +-    <string name="show_cpu_usage_summary" msgid="2113341923988958266">"स्‍क्रीन ओवरले वर्तमान CPU उपयोग को दिखा रहा है"</string>
    +     <string name="force_hw_ui" msgid="6426383462520888732">"बलपूर्वक GPU रेंडर करें"</string>
    +     <string name="force_hw_ui_summary" msgid="5535991166074861515">"2d ड्रॉइंग के लिए GPU का बलपूर्वक उपयोग करें"</string>
    +     <string name="force_msaa" msgid="7920323238677284387">"4x MSAA को बाध्य करें"</string>
    +@@ -341,4 +340,5 @@
    +     <string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"सबसे बड़ा"</string>
    +     <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"कस्टम (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
    +     <string name="help_feedback_label" msgid="6815040660801785649">"सहायता और फ़ीडबैक"</string>
    ++    <string name="content_description_menu_button" msgid="8182594799812351266">"मेनू"</string>
    + </resources>
    +diff --git a/packages/SettingsLib/res/values-hr/strings.xml b/packages/SettingsLib/res/values-hr/strings.xml
    +index 07e4925..619826d 100644
    +--- a/packages/SettingsLib/res/values-hr/strings.xml
    ++++ b/packages/SettingsLib/res/values-hr/strings.xml
    +@@ -28,7 +28,8 @@
    +     <string name="wifi_disabled_wifi_failure" msgid="3081668066612876581">"Povezivanje s Wi-Fi-jem nije uspjelo"</string>
    +     <string name="wifi_disabled_password_failure" msgid="8659805351763133575">"Problem u autentifikaciji"</string>
    +     <string name="wifi_not_in_range" msgid="1136191511238508967">"Nije u rasponu"</string>
    +-    <string name="wifi_no_internet" msgid="9151470775868728896">"Pristup internetu nije otkriven. Nema automatskog ponovnog povezivanja."</string>
    ++    <string name="wifi_no_internet_no_reconnect" msgid="2211781637653149657">"Pristup internetu nije otkriven. Nema automatskog ponovnog povezivanja."</string>
    ++    <string name="wifi_no_internet" msgid="5011955173375805204">"Nema pristupa internetu."</string>
    +     <string name="saved_network" msgid="4352716707126620811">"Spremljeno: <xliff:g id="NAME">%1$s</xliff:g>"</string>
    +     <string name="connected_via_wfa" msgid="3805736726317410714">"Povezani putem pomoćnika za Wi-Fi"</string>
    +     <string name="connected_via_passpoint" msgid="2826205693803088747">"Povezano putem %1$s"</string>
    +@@ -233,8 +234,6 @@
    +     <string name="debug_layout_summary" msgid="2001775315258637682">"Prikazuju se obrubi, margine itd. isječaka."</string>
    +     <string name="force_rtl_layout_all_locales" msgid="2259906643093138978">"Nametni zdesna ulijevo"</string>
    +     <string name="force_rtl_layout_all_locales_summary" msgid="9192797796616132534">"Nametni smjer zdesna ulijevo za sve zemlje/jezike"</string>
    +-    <string name="show_cpu_usage" msgid="2389212910758076024">"Prikaži upotrebu procesora"</string>
    +-    <string name="show_cpu_usage_summary" msgid="2113341923988958266">"Na zaslonu se prikazuje iskorištenost procesora."</string>
    +     <string name="force_hw_ui" msgid="6426383462520888732">"Nametni GPU renderiranje"</string>
    +     <string name="force_hw_ui_summary" msgid="5535991166074861515">"Nametni upotrebu GPU-a za 2D crteže"</string>
    +     <string name="force_msaa" msgid="7920323238677284387">"Nametni 4x MSAA"</string>
    +@@ -341,4 +340,5 @@
    +     <string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"Najveće"</string>
    +     <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Prilagođeno (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
    +     <string name="help_feedback_label" msgid="6815040660801785649">"Pomoć i povratne informacije"</string>
    ++    <string name="content_description_menu_button" msgid="8182594799812351266">"Izbornik"</string>
    + </resources>
    +diff --git a/packages/SettingsLib/res/values-hu/strings.xml b/packages/SettingsLib/res/values-hu/strings.xml
    +index 0d8ec26..e389c00 100644
    +--- a/packages/SettingsLib/res/values-hu/strings.xml
    ++++ b/packages/SettingsLib/res/values-hu/strings.xml
    +@@ -28,7 +28,8 @@
    +     <string name="wifi_disabled_wifi_failure" msgid="3081668066612876581">"Wi-Fi-kapcsolati hiba"</string>
    +     <string name="wifi_disabled_password_failure" msgid="8659805351763133575">"Azonosítási probléma"</string>
    +     <string name="wifi_not_in_range" msgid="1136191511238508967">"Hatókörön kívül"</string>
    +-    <string name="wifi_no_internet" msgid="9151470775868728896">"Nincs érzékelhető internet-hozzáférés, ezért nem kapcsolódik újra automatikusan."</string>
    ++    <string name="wifi_no_internet_no_reconnect" msgid="2211781637653149657">"Nincs érzékelhető internet-hozzáférés, ezért nem kapcsolódik újra automatikusan."</string>
    ++    <string name="wifi_no_internet" msgid="5011955173375805204">"Nincs internet-hozzáférés."</string>
    +     <string name="saved_network" msgid="4352716707126620811">"Mentette: <xliff:g id="NAME">%1$s</xliff:g>"</string>
    +     <string name="connected_via_wfa" msgid="3805736726317410714">"Csatlakozva Wi‑Fi-segéddel"</string>
    +     <string name="connected_via_passpoint" msgid="2826205693803088747">"Csatlakozva a következőn keresztül: %1$s"</string>
    +@@ -233,8 +234,6 @@
    +     <string name="debug_layout_summary" msgid="2001775315258637682">"Kliphatárok, margók stb. megjelenítése."</string>
    +     <string name="force_rtl_layout_all_locales" msgid="2259906643093138978">"Elrendezés jobbról balra"</string>
    +     <string name="force_rtl_layout_all_locales_summary" msgid="9192797796616132534">"Elrendezés jobbról balra minden nyelvnél"</string>
    +-    <string name="show_cpu_usage" msgid="2389212910758076024">"CPU-használat mutatása"</string>
    +-    <string name="show_cpu_usage_summary" msgid="2113341923988958266">"Képernyőfedvény a jelenlegi CPU-használattal"</string>
    +     <string name="force_hw_ui" msgid="6426383462520888732">"GPU-megjelenítés"</string>
    +     <string name="force_hw_ui_summary" msgid="5535991166074861515">"GPU használatának kényszerítése 2D rajzhoz"</string>
    +     <string name="force_msaa" msgid="7920323238677284387">"4x MSAA kényszerítése"</string>
    +@@ -341,4 +340,5 @@
    +     <string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"Legnagyobb"</string>
    +     <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Egyéni (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
    +     <string name="help_feedback_label" msgid="6815040660801785649">"Súgó és visszajelzés"</string>
    ++    <string name="content_description_menu_button" msgid="8182594799812351266">"Menü"</string>
    + </resources>
    +diff --git a/packages/SettingsLib/res/values-hy-rAM/strings.xml b/packages/SettingsLib/res/values-hy-rAM/strings.xml
    +index cb12fbf..8d2d78e 100644
    +--- a/packages/SettingsLib/res/values-hy-rAM/strings.xml
    ++++ b/packages/SettingsLib/res/values-hy-rAM/strings.xml
    +@@ -28,7 +28,8 @@
    +     <string name="wifi_disabled_wifi_failure" msgid="3081668066612876581">"WiFi կապի ձախողում"</string>
    +     <string name="wifi_disabled_password_failure" msgid="8659805351763133575">"Նույնականացման խնդիր"</string>
    +     <string name="wifi_not_in_range" msgid="1136191511238508967">"Ընդգրկույթից դուրս է"</string>
    +-    <string name="wifi_no_internet" msgid="9151470775868728896">"Ինտերնետի հասանելիություն չկա. ավտոմատ կերպով կրկին չի միանա:"</string>
    ++    <string name="wifi_no_internet_no_reconnect" msgid="2211781637653149657">"Ինտերնետ կապ չկա, ինչի պատճառով ավտոմատ վերամիացում չի կատարվի:"</string>
    ++    <string name="wifi_no_internet" msgid="5011955173375805204">"Ինտերնետ կապ չկա:"</string>
    +     <string name="saved_network" msgid="4352716707126620811">"Պահել է հետևյալ օգտվողը՝ <xliff:g id="NAME">%1$s</xliff:g>"</string>
    +     <string name="connected_via_wfa" msgid="3805736726317410714">"Կապակցված է Wi‑Fi Օգնականի միջոցով"</string>
    +     <string name="connected_via_passpoint" msgid="2826205693803088747">"Կապակցված է %1$s-ի միջոցով"</string>
    +@@ -38,7 +39,7 @@
    +     <string name="bluetooth_disconnecting" msgid="8913264760027764974">"Անջատվում է..."</string>
    +     <string name="bluetooth_connecting" msgid="8555009514614320497">"Միանում է..."</string>
    +     <string name="bluetooth_connected" msgid="6038755206916626419">"Միացված է"</string>
    +-    <string name="bluetooth_pairing" msgid="1426882272690346242">"Զուգավորում..."</string>
    ++    <string name="bluetooth_pairing" msgid="1426882272690346242">"Զուգակցում..."</string>
    +     <string name="bluetooth_connected_no_headset" msgid="2866994875046035609">"Միացված (առանց հեռախոսի)"</string>
    +     <string name="bluetooth_connected_no_a2dp" msgid="4576188601581440337">"Միացված է (առանց մեդիա)"</string>
    +     <string name="bluetooth_connected_no_map" msgid="6504436917057479986">"Միացված է (հաղորդագրությանը մուտք չկա)"</string>
    +@@ -72,7 +73,7 @@
    +     <string name="bluetooth_pairing_accept" msgid="6163520056536604875">"Զուգավորել"</string>
    +     <string name="bluetooth_pairing_accept_all_caps" msgid="6061699265220789149">"Զուգավորել"</string>
    +     <string name="bluetooth_pairing_decline" msgid="4185420413578948140">"Չեղարկել"</string>
    +-    <string name="bluetooth_pairing_will_share_phonebook" msgid="4982239145676394429">"Զուգավորում է մուտքի թույլտվությունը դեպի ձեր կոնտակտները և զանգերի պատմությունը, երբ միացված է:"</string>
    ++    <string name="bluetooth_pairing_will_share_phonebook" msgid="4982239145676394429">"Զուգակցում է մուտքի թույլտվությունը դեպի ձեր կոնտակտները և զանգերի պատմությունը, երբ միացված է:"</string>
    +     <string name="bluetooth_pairing_error_message" msgid="3748157733635947087">"Չհաջողվեց զուգավորել <xliff:g id="DEVICE_NAME">%1$s</xliff:g>-ի հետ:"</string>
    +     <string name="bluetooth_pairing_pin_error_message" msgid="8337234855188925274">"Հնարավոր չեղավ զուգավորվել <xliff:g id="DEVICE_NAME">%1$s</xliff:g>-ի հետ սխալ PIN-ի կամ անցաբառի պատճառով:."</string>
    +     <string name="bluetooth_pairing_device_down_error_message" msgid="7870998403045801381">"Հնարավոր չէ կապ հաստատել  <xliff:g id="DEVICE_NAME">%1$s</xliff:g>-ի հետ:"</string>
    +@@ -233,8 +234,6 @@
    +     <string name="debug_layout_summary" msgid="2001775315258637682">"Ցույց տալ կտրվածքի սահմանները, լուսանցքները և այլն"</string>
    +     <string name="force_rtl_layout_all_locales" msgid="2259906643093138978">"Փոխել RTL-ի դասավորության ուղղությունը"</string>
    +     <string name="force_rtl_layout_all_locales_summary" msgid="9192797796616132534">"Դարձնել էկրանի դասավորության ուղղությունը դեպի RTL բոլոր լեզուների համար"</string>
    +-    <string name="show_cpu_usage" msgid="2389212910758076024">"Ցույց տալ CPU-ի աշխատանքը"</string>
    +-    <string name="show_cpu_usage_summary" msgid="2113341923988958266">"Էկրանի վերադրումը ցույց է տալիս ընթացիկ CPU օգտագործումը"</string>
    +     <string name="force_hw_ui" msgid="6426383462520888732">"Ստիպել GPU-ին մատուցել"</string>
    +     <string name="force_hw_ui_summary" msgid="5535991166074861515">"Ստիպողաբար GPU-ի օգտագործում 2-րդ պատկերի համար"</string>
    +     <string name="force_msaa" msgid="7920323238677284387">"Ստիպել  4x MSAA"</string>
    +@@ -341,4 +340,5 @@
    +     <string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"Ամենամեծ"</string>
    +     <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Հատուկ (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
    +     <string name="help_feedback_label" msgid="6815040660801785649">"Օգնություն և հետադարձ կապ"</string>
    ++    <string name="content_description_menu_button" msgid="8182594799812351266">"Ընտրացանկ"</string>
    + </resources>
    +diff --git a/packages/SettingsLib/res/values-in/strings.xml b/packages/SettingsLib/res/values-in/strings.xml
    +index ffdb607..0e0d32f 100644
    +--- a/packages/SettingsLib/res/values-in/strings.xml
    ++++ b/packages/SettingsLib/res/values-in/strings.xml
    +@@ -28,7 +28,8 @@
    +     <string name="wifi_disabled_wifi_failure" msgid="3081668066612876581">"Kegagalan Sambungan Wi-Fi"</string>
    +     <string name="wifi_disabled_password_failure" msgid="8659805351763133575">"Masalah autentikasi"</string>
    +     <string name="wifi_not_in_range" msgid="1136191511238508967">"Tidak dalam jangkauan"</string>
    +-    <string name="wifi_no_internet" msgid="9151470775868728896">"Akses Internet Tidak Terdeteksi, tidak akan menyambung ulang secara otomatis."</string>
    ++    <string name="wifi_no_internet_no_reconnect" msgid="2211781637653149657">"Akses Internet Tidak Terdeteksi, tidak akan menyambung ulang secara otomatis."</string>
    ++    <string name="wifi_no_internet" msgid="5011955173375805204">"Tidak Ada Akses Internet."</string>
    +     <string name="saved_network" msgid="4352716707126620811">"Disimpan oleh <xliff:g id="NAME">%1$s</xliff:g>"</string>
    +     <string name="connected_via_wfa" msgid="3805736726317410714">"Terhubung melalui Asisten Wi-Fi"</string>
    +     <string name="connected_via_passpoint" msgid="2826205693803088747">"Terhubung melalui %1$s"</string>
    +@@ -233,8 +234,6 @@
    +     <string name="debug_layout_summary" msgid="2001775315258637682">"Tampilkan batas klip, margin, dll."</string>
    +     <string name="force_rtl_layout_all_locales" msgid="2259906643093138978">"Paksa arah tata letak RTL"</string>
    +     <string name="force_rtl_layout_all_locales_summary" msgid="9192797796616132534">"Paksa arah tata letak layar RTL untuk semua lokal"</string>
    +-    <string name="show_cpu_usage" msgid="2389212910758076024">"Tampilkan penggunaan CPU"</string>
    +-    <string name="show_cpu_usage_summary" msgid="2113341923988958266">"Hamparan layar menampilkan penggunaan CPU saat ini"</string>
    +     <string name="force_hw_ui" msgid="6426383462520888732">"Paksa perenderan GPU"</string>
    +     <string name="force_hw_ui_summary" msgid="5535991166074861515">"Paksa penggunaan GPU untuk gambar 2d"</string>
    +     <string name="force_msaa" msgid="7920323238677284387">"Force 4x MSAA"</string>
    +@@ -341,4 +340,5 @@
    +     <string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"Terbesar"</string>
    +     <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"(<xliff:g id="DENSITYDPI">%d</xliff:g>) khusus"</string>
    +     <string name="help_feedback_label" msgid="6815040660801785649">"Bantuan &amp; masukan"</string>
    ++    <string name="content_description_menu_button" msgid="8182594799812351266">"Menu"</string>
    + </resources>
    +diff --git a/packages/SettingsLib/res/values-is-rIS/strings.xml b/packages/SettingsLib/res/values-is-rIS/strings.xml
    +index 25e13a4..d1c177b 100644
    +--- a/packages/SettingsLib/res/values-is-rIS/strings.xml
    ++++ b/packages/SettingsLib/res/values-is-rIS/strings.xml
    +@@ -28,7 +28,8 @@
    +     <string name="wifi_disabled_wifi_failure" msgid="3081668066612876581">"WiFi-tengingarvilla"</string>
    +     <string name="wifi_disabled_password_failure" msgid="8659805351763133575">"Vandamál við auðkenningu"</string>
    +     <string name="wifi_not_in_range" msgid="1136191511238508967">"Ekkert samband"</string>
    +-    <string name="wifi_no_internet" msgid="9151470775868728896">"Enginn netaðgangur fannst; endurtengist ekki sjálfkrafa."</string>
    ++    <string name="wifi_no_internet_no_reconnect" msgid="2211781637653149657">"Enginn netaðgangur fannst, endurtengist ekki sjálfkrafa."</string>
    ++    <string name="wifi_no_internet" msgid="5011955173375805204">"Enginn netaðgangur."</string>
    +     <string name="saved_network" msgid="4352716707126620811">"<xliff:g id="NAME">%1$s</xliff:g> vistaði"</string>
    +     <string name="connected_via_wfa" msgid="3805736726317410714">"Tengt í gegnum Wi-Fi aðstoð"</string>
    +     <string name="connected_via_passpoint" msgid="2826205693803088747">"Tengt í gegnum %1$s"</string>
    +@@ -233,8 +234,6 @@
    +     <string name="debug_layout_summary" msgid="2001775315258637682">"Sýna skurðlínur, spássíur o.s.frv."</string>
    +     <string name="force_rtl_layout_all_locales" msgid="2259906643093138978">"Þvinga umbrot frá hægri til vinstri"</string>
    +     <string name="force_rtl_layout_all_locales_summary" msgid="9192797796616132534">"Þvinga umbrot skjás frá hægri til vinstri fyrir alla tungumálskóða"</string>
    +-    <string name="show_cpu_usage" msgid="2389212910758076024">"Sýna örgjörvanotkun"</string>
    +-    <string name="show_cpu_usage_summary" msgid="2113341923988958266">"Skjáyfirlögn sem sýnir núverandi örgjörvanotkun"</string>
    +     <string name="force_hw_ui" msgid="6426383462520888732">"Þvinga skjákortsteiknun"</string>
    +     <string name="force_hw_ui_summary" msgid="5535991166074861515">"Þvinga notkun skjákorts fyrir tvívíða teikningu"</string>
    +     <string name="force_msaa" msgid="7920323238677284387">"Þvinga 4x MSAA"</string>
    +@@ -341,4 +340,5 @@
    +     <string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"Stærst"</string>
    +     <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Sérsniðið (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
    +     <string name="help_feedback_label" msgid="6815040660801785649">"Hjálp og ábendingar"</string>
    ++    <string name="content_description_menu_button" msgid="8182594799812351266">"Valmynd"</string>
    + </resources>
    +diff --git a/packages/SettingsLib/res/values-it/strings.xml b/packages/SettingsLib/res/values-it/strings.xml
    +index cb323a2..c566e79 100644
    +--- a/packages/SettingsLib/res/values-it/strings.xml
    ++++ b/packages/SettingsLib/res/values-it/strings.xml
    +@@ -28,7 +28,8 @@
    +     <string name="wifi_disabled_wifi_failure" msgid="3081668066612876581">"Errore connessione Wi-Fi"</string>
    +     <string name="wifi_disabled_password_failure" msgid="8659805351763133575">"Problema di autenticazione"</string>
    +     <string name="wifi_not_in_range" msgid="1136191511238508967">"Fuori portata"</string>
    +-    <string name="wifi_no_internet" msgid="9151470775868728896">"Nessun accesso a Internet rilevato, non verrà eseguita la riconnessione automatica."</string>
    ++    <string name="wifi_no_internet_no_reconnect" msgid="2211781637653149657">"Nessun accesso a Internet rilevato. Non verrà eseguita la riconnessione automatica."</string>
    ++    <string name="wifi_no_internet" msgid="5011955173375805204">"Nessun accesso a Internet."</string>
    +     <string name="saved_network" msgid="4352716707126620811">"Salvata da <xliff:g id="NAME">%1$s</xliff:g>"</string>
    +     <string name="connected_via_wfa" msgid="3805736726317410714">"Connesso tramite assistente Wi‑Fi"</string>
    +     <string name="connected_via_passpoint" msgid="2826205693803088747">"Collegato tramite %1$s"</string>
    +@@ -191,7 +192,7 @@
    +     <string name="dev_settings_warning_title" msgid="7244607768088540165">"Consentire impostazioni di sviluppo?"</string>
    +     <string name="dev_settings_warning_message" msgid="2298337781139097964">"Queste impostazioni sono utilizzabili solo a scopo di sviluppo. Possono causare l\'arresto o il comportamento anomalo del dispositivo e delle applicazioni su di esso."</string>
    +     <string name="verify_apps_over_usb_title" msgid="4177086489869041953">"Verifica app tramite USB"</string>
    +-    <string name="verify_apps_over_usb_summary" msgid="9164096969924529200">"Controlla che le applicazioni installate tramite ADB/ADT non abbiano un comportamento dannoso."</string>
    ++    <string name="verify_apps_over_usb_summary" msgid="9164096969924529200">"Controlla che le app installate tramite ADB/ADT non abbiano un comportamento dannoso."</string>
    +     <string name="bluetooth_disable_absolute_volume_summary" msgid="6031284410786545957">"Consente di disattivare la funzione del volume assoluto Bluetooth in caso di problemi con il volume dei dispositivi remoti, ad esempio un volume troppo alto o la mancanza di controllo."</string>
    +     <string name="enable_terminal_title" msgid="95572094356054120">"Terminale locale"</string>
    +     <string name="enable_terminal_summary" msgid="67667852659359206">"Abilita l\'app Terminale che offre l\'accesso alla shell locale"</string>
    +@@ -233,8 +234,6 @@
    +     <string name="debug_layout_summary" msgid="2001775315258637682">"Mostra limiti, margini dei clip e così via"</string>
    +     <string name="force_rtl_layout_all_locales" msgid="2259906643093138978">"Forza direzione layout RTL"</string>
    +     <string name="force_rtl_layout_all_locales_summary" msgid="9192797796616132534">"Direzione layout schermo RTL per tutte le lingue"</string>
    +-    <string name="show_cpu_usage" msgid="2389212910758076024">"Mostra utilizzo CPU"</string>
    +-    <string name="show_cpu_usage_summary" msgid="2113341923988958266">"Overlay schermo che mostra l\'uso corrente della CPU"</string>
    +     <string name="force_hw_ui" msgid="6426383462520888732">"Forza rendering GPU"</string>
    +     <string name="force_hw_ui_summary" msgid="5535991166074861515">"Forza l\'uso della GPU per i disegni 2D"</string>
    +     <string name="force_msaa" msgid="7920323238677284387">"Forza MSAA 4x"</string>
    +@@ -329,8 +328,8 @@
    +     <string name="home" msgid="3256884684164448244">"Home page Impostazioni"</string>
    +   <string-array name="battery_labels">
    +     <item msgid="8494684293649631252">"0%"</item>
    +-    <item msgid="8934126114226089439">"50%%"</item>
    +-    <item msgid="1286113608943010849">"100%%"</item>
    ++    <item msgid="8934126114226089439">"50%"</item>
    ++    <item msgid="1286113608943010849">"100%"</item>
    +   </string-array>
    +     <string name="charge_length_format" msgid="8978516217024434156">"<xliff:g id="ID_1">%1$s</xliff:g> fa"</string>
    +     <string name="remaining_length_format" msgid="7886337596669190587">"<xliff:g id="ID_1">%1$s</xliff:g> rimanenti"</string>
    +@@ -341,4 +340,5 @@
    +     <string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"Massimo"</string>
    +     <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Personalizzato (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
    +     <string name="help_feedback_label" msgid="6815040660801785649">"Guida e feedback"</string>
    ++    <string name="content_description_menu_button" msgid="8182594799812351266">"Menu"</string>
    + </resources>
    +diff --git a/packages/SettingsLib/res/values-iw/strings.xml b/packages/SettingsLib/res/values-iw/strings.xml
    +index 7c16e42..4523380 100644
    +--- a/packages/SettingsLib/res/values-iw/strings.xml
    ++++ b/packages/SettingsLib/res/values-iw/strings.xml
    +@@ -28,7 +28,8 @@
    +     <string name="wifi_disabled_wifi_failure" msgid="3081668066612876581">"‏כשל בחיבור Wi-Fi"</string>
    +     <string name="wifi_disabled_password_failure" msgid="8659805351763133575">"בעיית אימות"</string>
    +     <string name="wifi_not_in_range" msgid="1136191511238508967">"מחוץ לטווח"</string>
    +-    <string name="wifi_no_internet" msgid="9151470775868728896">"אין גישה לאינטרנט. לא יתבצע חיבור מחדש באופן אוטומטי."</string>
    ++    <string name="wifi_no_internet_no_reconnect" msgid="2211781637653149657">"אין גישה לאינטרנט. לא יתבצע חיבור מחדש באופן אוטומטי."</string>
    ++    <string name="wifi_no_internet" msgid="5011955173375805204">"אין גישה לאינטרנט."</string>
    +     <string name="saved_network" msgid="4352716707126620811">"נשמר על ידי <xliff:g id="NAME">%1$s</xliff:g>"</string>
    +     <string name="connected_via_wfa" msgid="3805736726317410714">"‏מחובר באמצעות אסיסטנט ה-Wi-Fi"</string>
    +     <string name="connected_via_passpoint" msgid="2826205693803088747">"‏מחובר דרך %1$s"</string>
    +@@ -233,8 +234,6 @@
    +     <string name="debug_layout_summary" msgid="2001775315258637682">"הצג גבולות קליפ, שוליים וכו\'"</string>
    +     <string name="force_rtl_layout_all_locales" msgid="2259906643093138978">"אלץ כיוון פריסה מימין לשמאל"</string>
    +     <string name="force_rtl_layout_all_locales_summary" msgid="9192797796616132534">"אלץ כיוון פריסת מסך מימין לשמאל עבור כל השפות בכל המקומות"</string>
    +-    <string name="show_cpu_usage" msgid="2389212910758076024">"‏הצג את השימוש ב-CPU"</string>
    +-    <string name="show_cpu_usage_summary" msgid="2113341923988958266">"‏שכבת-על של מסך שמציגה את השימוש הנוכחי ב-CPU"</string>
    +     <string name="force_hw_ui" msgid="6426383462520888732">"‏אלץ עיבוד ב-GPU"</string>
    +     <string name="force_hw_ui_summary" msgid="5535991166074861515">"‏אכוף שימוש ב-GPU לשרטוט דו-מימדי"</string>
    +     <string name="force_msaa" msgid="7920323238677284387">"‏אלץ הפעלת 4x MSAA"</string>
    +@@ -341,4 +340,5 @@
    +     <string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"הכי גדול"</string>
    +     <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"מותאם אישית (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
    +     <string name="help_feedback_label" msgid="6815040660801785649">"עזרה ומשוב"</string>
    ++    <string name="content_description_menu_button" msgid="8182594799812351266">"תפריט"</string>
    + </resources>
    +diff --git a/packages/SettingsLib/res/values-ja/strings.xml b/packages/SettingsLib/res/values-ja/strings.xml
    +index 25f4152..1761adb 100644
    +--- a/packages/SettingsLib/res/values-ja/strings.xml
    ++++ b/packages/SettingsLib/res/values-ja/strings.xml
    +@@ -28,7 +28,8 @@
    +     <string name="wifi_disabled_wifi_failure" msgid="3081668066612876581">"WiFi接続エラー"</string>
    +     <string name="wifi_disabled_password_failure" msgid="8659805351763133575">"認証に問題"</string>
    +     <string name="wifi_not_in_range" msgid="1136191511238508967">"圏外"</string>
    +-    <string name="wifi_no_internet" msgid="9151470775868728896">"インターネットアクセスを検出できないため、自動的に再接続されません。"</string>
    ++    <string name="wifi_no_internet_no_reconnect" msgid="2211781637653149657">"インターネット アクセスを検出できないため、自動的に再接続されません。"</string>
    ++    <string name="wifi_no_internet" msgid="5011955173375805204">"インターネットに接続していません。"</string>
    +     <string name="saved_network" msgid="4352716707126620811">"<xliff:g id="NAME">%1$s</xliff:g>で保存"</string>
    +     <string name="connected_via_wfa" msgid="3805736726317410714">"Wi‑Fiアシスタント経由で接続"</string>
    +     <string name="connected_via_passpoint" msgid="2826205693803088747">"%1$s経由で接続"</string>
    +@@ -233,8 +234,6 @@
    +     <string name="debug_layout_summary" msgid="2001775315258637682">"クリップの境界線、マージンなどを表示"</string>
    +     <string name="force_rtl_layout_all_locales" msgid="2259906643093138978">"RTLレイアウト方向を使用"</string>
    +     <string name="force_rtl_layout_all_locales_summary" msgid="9192797796616132534">"すべての言語/地域で画面レイアウト方向をRTLに設定"</string>
    +-    <string name="show_cpu_usage" msgid="2389212910758076024">"CPU使用状況を表示"</string>
    +-    <string name="show_cpu_usage_summary" msgid="2113341923988958266">"現在のCPU使用状況をオーバーレイ表示する"</string>
    +     <string name="force_hw_ui" msgid="6426383462520888732">"GPUレンダリングを使用"</string>
    +     <string name="force_hw_ui_summary" msgid="5535991166074861515">"2D描画にGPUを常に使用する"</string>
    +     <string name="force_msaa" msgid="7920323238677284387">"4x MSAAを適用"</string>
    +@@ -343,4 +342,5 @@
    +     <string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"最大"</string>
    +     <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"カスタム(<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
    +     <string name="help_feedback_label" msgid="6815040660801785649">"ヘルプとフィードバック"</string>
    ++    <string name="content_description_menu_button" msgid="8182594799812351266">"メニュー"</string>
    + </resources>
    +diff --git a/packages/SettingsLib/res/values-ka-rGE/strings.xml b/packages/SettingsLib/res/values-ka-rGE/strings.xml
    +index ffe194a..a39d4b2 100644
    +--- a/packages/SettingsLib/res/values-ka-rGE/strings.xml
    ++++ b/packages/SettingsLib/res/values-ka-rGE/strings.xml
    +@@ -28,7 +28,8 @@
    +     <string name="wifi_disabled_wifi_failure" msgid="3081668066612876581">"WiFi კავშირის შეფერხება"</string>
    +     <string name="wifi_disabled_password_failure" msgid="8659805351763133575">"ავთენტიკაციის პრობლემა"</string>
    +     <string name="wifi_not_in_range" msgid="1136191511238508967">"არ არის დიაპაზონში"</string>
    +-    <string name="wifi_no_internet" msgid="9151470775868728896">"ინტერნეტთან წვდომის ამოცნობა ვერ მოხერხდა. ავტომატურად ხელახლა დაკავშირება არ განხორციელდება."</string>
    ++    <string name="wifi_no_internet_no_reconnect" msgid="2211781637653149657">"ინტერნეტთან კავშირის ამოცნობა ვერ მოხერხდა. ავტომატურად ხელახლა დაკავშირება არ განხორციელდება."</string>
    ++    <string name="wifi_no_internet" msgid="5011955173375805204">"ინტერნეტთან კავშირი არ არის."</string>
    +     <string name="saved_network" msgid="4352716707126620811">"შენახული <xliff:g id="NAME">%1$s</xliff:g>-ის მიერ"</string>
    +     <string name="connected_via_wfa" msgid="3805736726317410714">"დაკავშირებულია Wi-Fi თანაშემწით"</string>
    +     <string name="connected_via_passpoint" msgid="2826205693803088747">"%1$s-ით დაკავშირებული"</string>
    +@@ -233,8 +234,6 @@
    +     <string name="debug_layout_summary" msgid="2001775315258637682">"კლიპის საზღვრების, მინდვრების ჩვენება და ა.შ."</string>
    +     <string name="force_rtl_layout_all_locales" msgid="2259906643093138978">"მარჯვნიდან მარცხნივ განლაგების მიმართულების იძულება"</string>
    +     <string name="force_rtl_layout_all_locales_summary" msgid="9192797796616132534">"ეკრანის RTL მიმართულებაზე იძულება ყველა ლოკალისათვის"</string>
    +-    <string name="show_cpu_usage" msgid="2389212910758076024">"ცენტრალური პროცესორის ჩატვირთვის ჩვენება"</string>
    +-    <string name="show_cpu_usage_summary" msgid="2113341923988958266">"ეკრანის გადაფარვა აჩვენებს CPU ამჟამინდელ გამოყენებას"</string>
    +     <string name="force_hw_ui" msgid="6426383462520888732">"GPU-აჩქარება"</string>
    +     <string name="force_hw_ui_summary" msgid="5535991166074861515">"GPU-ის ძალით გამოყენება 2d drawing-თვის"</string>
    +     <string name="force_msaa" msgid="7920323238677284387">"4x MSAA-ს ჩართვა"</string>
    +@@ -341,4 +340,5 @@
    +     <string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"უდიდესი"</string>
    +     <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"მორგებული (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
    +     <string name="help_feedback_label" msgid="6815040660801785649">"დახმარება და გამოხმაურება"</string>
    ++    <string name="content_description_menu_button" msgid="8182594799812351266">"მენიუ"</string>
    + </resources>
    +diff --git a/packages/SettingsLib/res/values-kk-rKZ/strings.xml b/packages/SettingsLib/res/values-kk-rKZ/strings.xml
    +index 3dcc7eb..c636feb 100644
    +--- a/packages/SettingsLib/res/values-kk-rKZ/strings.xml
    ++++ b/packages/SettingsLib/res/values-kk-rKZ/strings.xml
    +@@ -28,7 +28,8 @@
    +     <string name="wifi_disabled_wifi_failure" msgid="3081668066612876581">"Wi-Fi байланысының қатесі"</string>
    +     <string name="wifi_disabled_password_failure" msgid="8659805351763133575">"Растау мәселесі"</string>
    +     <string name="wifi_not_in_range" msgid="1136191511238508967">"Аумақта жоқ"</string>
    +-    <string name="wifi_no_internet" msgid="9151470775868728896">"Интернетке қатынас анықталмады, автоматты түрде қайта қосылу орындалмайды."</string>
    ++    <string name="wifi_no_internet_no_reconnect" msgid="2211781637653149657">"Интернетпен байланыс жоқ, автоматты түрде қайта қосылмайды."</string>
    ++    <string name="wifi_no_internet" msgid="5011955173375805204">"Интернетпен байланыс жоқ."</string>
    +     <string name="saved_network" msgid="4352716707126620811">"<xliff:g id="NAME">%1$s</xliff:g> сақтаған"</string>
    +     <string name="connected_via_wfa" msgid="3805736726317410714">"Wi‑Fi көмекшісі арқылы қосылу орындалды"</string>
    +     <string name="connected_via_passpoint" msgid="2826205693803088747">"%1$s арқылы қосылған"</string>
    +@@ -233,8 +234,6 @@
    +     <string name="debug_layout_summary" msgid="2001775315258637682">"Қию шектерін, жиектерін, т.б көрсету."</string>
    +     <string name="force_rtl_layout_all_locales" msgid="2259906643093138978">"Оңнан солға орналасу бағытына реттеу"</string>
    +     <string name="force_rtl_layout_all_locales_summary" msgid="9192797796616132534">"Экранның орналасу бағытын барлық тілдер үшін оңнан солға қарату"</string>
    +-    <string name="show_cpu_usage" msgid="2389212910758076024">"CPU (орталық өңдеу бірлігі) қолданысы"</string>
    +-    <string name="show_cpu_usage_summary" msgid="2113341923988958266">"Экран бетіне ағымдағы CPU қолданысы көрсетіледі"</string>
    +     <string name="force_hw_ui" msgid="6426383462520888732">"GPU рендерингін жылдамдату"</string>
    +     <string name="force_hw_ui_summary" msgid="5535991166074861515">"Графикалық процессорды 2d сызбаларына қолдану"</string>
    +     <string name="force_msaa" msgid="7920323238677284387">"4x MSAA қолдану"</string>
    +@@ -341,4 +340,5 @@
    +     <string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"Ең үлкен"</string>
    +     <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Арнаулы (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
    +     <string name="help_feedback_label" msgid="6815040660801785649">"Анықтама және пікір"</string>
    ++    <string name="content_description_menu_button" msgid="8182594799812351266">"Mәзір"</string>
    + </resources>
    +diff --git a/packages/SettingsLib/res/values-km-rKH/strings.xml b/packages/SettingsLib/res/values-km-rKH/strings.xml
    +index aa0ce24..94ce5f1 100644
    +--- a/packages/SettingsLib/res/values-km-rKH/strings.xml
    ++++ b/packages/SettingsLib/res/values-km-rKH/strings.xml
    +@@ -28,7 +28,8 @@
    +     <string name="wifi_disabled_wifi_failure" msgid="3081668066612876581">"ការ​ភ្ជាប់​ WiFi បរាជ័យ"</string>
    +     <string name="wifi_disabled_password_failure" msgid="8659805351763133575">"បញ្ហា​ក្នុង​ការ​ផ្ទៀងផ្ទាត់"</string>
    +     <string name="wifi_not_in_range" msgid="1136191511238508967">"នៅ​ក្រៅ​តំបន់"</string>
    +-    <string name="wifi_no_internet" msgid="9151470775868728896">"រក​មិន​ឃើញ​ការ​ចូល​ដំណើរការ​អ៊ីនធឺណិត, នឹង​មិន​ភ្ជាប់​ឡើង​វិញ​ដោយ​ស្វ័យ​ប្រវត្តិ​ទេ។"</string>
    ++    <string name="wifi_no_internet_no_reconnect" msgid="2211781637653149657">"រកមិនឃើញការតភ្ជាប់អ៊ីនធឺណិតទេ វានឹងមិនភ្ជាប់ឡើងវិញដោយស្វ័យប្រវត្តិទេ។"</string>
    ++    <string name="wifi_no_internet" msgid="5011955173375805204">"គ្មានការតភ្ជាប់អ៊ីនធឺណិតទេ"</string>
    +     <string name="saved_network" msgid="4352716707126620811">"បានរក្សាទុកដោយ <xliff:g id="NAME">%1$s</xliff:g>"</string>
    +     <string name="connected_via_wfa" msgid="3805736726317410714">"បានភ្ជាប់តាមរយៈជំនួយការ Wi‑Fi"</string>
    +     <string name="connected_via_passpoint" msgid="2826205693803088747">"បានភ្ជាប់តាមរយៈ %1$s"</string>
    +@@ -233,8 +234,6 @@
    +     <string name="debug_layout_summary" msgid="2001775315258637682">"បង្ហាញ​ការ​ភ្ជាប់​អត្ថបទ​សម្រង់ រឹម ។ល។"</string>
    +     <string name="force_rtl_layout_all_locales" msgid="2259906643093138978">"បង្ខំ​ទិស​ប្លង់ RTL"</string>
    +     <string name="force_rtl_layout_all_locales_summary" msgid="9192797796616132534">"បង្ខំ​ទិស​ប្លង់​អេក្រង់​ទៅកាន់ RTL សម្រាប់​មូលដ្ឋាន​ទាំងអស់"</string>
    +-    <string name="show_cpu_usage" msgid="2389212910758076024">"បង្ហាញ​​ការ​ប្រើ CPU"</string>
    +-    <string name="show_cpu_usage_summary" msgid="2113341923988958266">"អេក្រង់​ត្រួត​គ្នា​បង្ហាញ​​ការ​ប្រើ CPU បច្ចុប្បន្ន"</string>
    +     <string name="force_hw_ui" msgid="6426383462520888732">"បង្ខំ​ឲ្យ​បង្ហាញ GPU"</string>
    +     <string name="force_hw_ui_summary" msgid="5535991166074861515">"បង្ខំ​ប្រើ GPU សម្រាប់​ការ​គូរ​លើក​ទី​ពីរ"</string>
    +     <string name="force_msaa" msgid="7920323238677284387">"បង្ខំ 4x MSAA"</string>
    +@@ -341,4 +340,5 @@
    +     <string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"ធំបំផុត"</string>
    +     <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"ផ្ទាល់ខ្លួន (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
    +     <string name="help_feedback_label" msgid="6815040660801785649">"ជំនួយ និងមតិស្ថាបនា"</string>
    ++    <string name="content_description_menu_button" msgid="8182594799812351266">"ម៉ឺនុយ"</string>
    + </resources>
    +diff --git a/packages/SettingsLib/res/values-kn-rIN/strings.xml b/packages/SettingsLib/res/values-kn-rIN/strings.xml
    +index 643875f..ce10d35 100644
    +--- a/packages/SettingsLib/res/values-kn-rIN/strings.xml
    ++++ b/packages/SettingsLib/res/values-kn-rIN/strings.xml
    +@@ -28,7 +28,8 @@
    +     <string name="wifi_disabled_wifi_failure" msgid="3081668066612876581">"WiFi ಸಂಪರ್ಕ ವಿಫಲತೆ"</string>
    +     <string name="wifi_disabled_password_failure" msgid="8659805351763133575">"ಪ್ರಮಾಣೀಕರಣ ಸಮಸ್ಯೆ"</string>
    +     <string name="wifi_not_in_range" msgid="1136191511238508967">"ವ್ಯಾಪ್ತಿಯಲ್ಲಿಲ್ಲ"</string>
    +-    <string name="wifi_no_internet" msgid="9151470775868728896">"ಯಾವುದೇ ಇಂಟರ್ನೆಟ್‌ ಪ್ರವೇಶ ಪತ್ತೆಯಾಗಿಲ್ಲ, ಸ್ವಯಂಚಾಲಿತವಾಗಿ ಮರುಸಂಪರ್ಕಿಸಲು ಸಾಧ್ಯವಿಲ್ಲ."</string>
    ++    <string name="wifi_no_internet_no_reconnect" msgid="2211781637653149657">"ಯಾವುದೇ ಇಂಟರ್ನೆಟ್‌ ಪ್ರವೇಶ ಪತ್ತೆಯಾಗಿಲ್ಲ, ಸ್ವಯಂಚಾಲಿತವಾಗಿ ಮರುಸಂಪರ್ಕಿಸಲು ಸಾಧ್ಯವಿಲ್ಲ."</string>
    ++    <string name="wifi_no_internet" msgid="5011955173375805204">"ಯಾವುದೇ ಇಂಟರ್ನೆಟ್ ಪ್ರವೇಶವಿಲ್ಲ."</string>
    +     <string name="saved_network" msgid="4352716707126620811">"<xliff:g id="NAME">%1$s</xliff:g> ರಿಂದ ಉಳಿಸಲಾಗಿದೆ"</string>
    +     <string name="connected_via_wfa" msgid="3805736726317410714">"Wi‑Fi ಸಹಾಯಕದ ಮೂಲಕ ಸಂಪರ್ಕಿತಗೊಳಿಸಲಾಗಿದೆ"</string>
    +     <string name="connected_via_passpoint" msgid="2826205693803088747">"%1$s ಮೂಲಕ ಸಂಪರ್ಕಗೊಂಡಿದೆ"</string>
    +@@ -93,7 +94,7 @@
    +     <string name="tether_settings_title_all" msgid="8356136101061143841">"ಟೆಥರಿಂಗ್ &amp; ಪೋರ್ಟಬಲ್ ಹಾಟ್‌ಸ್ಪಾಟ್"</string>
    +     <string name="managed_user_title" msgid="8109605045406748842">"ಎಲ್ಲ ಕೆಲಸದ ಅಪ್ಲಿಕೇಶನ್‌ಗಳು"</string>
    +     <string name="user_guest" msgid="8475274842845401871">"ಅತಿಥಿ"</string>
    +-    <string name="unknown" msgid="1592123443519355854">"ಅಜ್ಞಾತ"</string>
    ++    <string name="unknown" msgid="1592123443519355854">"ಅಪರಿಚಿತ"</string>
    +     <string name="running_process_item_user_label" msgid="3129887865552025943">"ಬಳಕೆದಾರ: <xliff:g id="USER_NAME">%1$s</xliff:g>"</string>
    +     <string name="launch_defaults_some" msgid="313159469856372621">"ಕೆಲವು ಡೀಫಾಲ್ಟ್‌ಗಳನ್ನು ಹೊಂದಿಸಲಾಗಿದೆ"</string>
    +     <string name="launch_defaults_none" msgid="4241129108140034876">"ಡೀಫಾಲ್ಟ್‌ಗಳನ್ನು ಹೊಂದಿಸಲಾಗಿಲ್ಲ"</string>
    +@@ -233,8 +234,6 @@
    +     <string name="debug_layout_summary" msgid="2001775315258637682">"ಕ್ಲಿಪ್‌ನ ಗಡಿಗಳು, ಅಂಚುಗಳು, ಇತ್ಯಾದಿ ತೋರಿಸು."</string>
    +     <string name="force_rtl_layout_all_locales" msgid="2259906643093138978">"RTL ಲೇಔಟ್‌ ಪರಿಮಿತಿ ಬಲಗೊಳಿಸಿ"</string>
    +     <string name="force_rtl_layout_all_locales_summary" msgid="9192797796616132534">"ಎಲ್ಲ ಸ್ಥಳಗಳಿಗಾಗಿ RTL ಗೆ ಸ್ಕ್ರೀನ್‌ ಲೇಔಟ್‌ ದಿಕ್ಕನ್ನು ಪ್ರಬಲಗೊಳಿಸಿ"</string>
    +-    <string name="show_cpu_usage" msgid="2389212910758076024">"CPU ಬಳಕೆಯನ್ನು ತೋರಿಸು"</string>
    +-    <string name="show_cpu_usage_summary" msgid="2113341923988958266">"ಪ್ರಸ್ತುತ CPU ಬಳಕೆಯನ್ನು ತೋರಿಸುತ್ತಿರುವ ಪರದೆಯ ಓವರ್‌ಲೇ"</string>
    +     <string name="force_hw_ui" msgid="6426383462520888732">"GPU ನೀಡುವಿಕೆ ಬಲಗೊಳಿಸು"</string>
    +     <string name="force_hw_ui_summary" msgid="5535991166074861515">"2d ಚಿತ್ರಕಲೆಗಾಗಿ GPU ಬಳಕೆ ಬಲಗೊಳಿಸಿ"</string>
    +     <string name="force_msaa" msgid="7920323238677284387">"4x MSAA ಪ್ರಬಲಗೊಳಿಸಿ"</string>
    +@@ -312,7 +311,7 @@
    +     <string name="power_charging_duration_usb_short" msgid="941854728040426399">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g>"</string>
    +     <string name="power_charging_duration_wireless" msgid="1829295708243159464">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> ವೈರ್‌‌ಲೆಸ್‌ನಿಂದ ಪೂರ್ಣವಾಗುವವರೆಗೆ"</string>
    +     <string name="power_charging_duration_wireless_short" msgid="1642664799869599476">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g>"</string>
    +-    <string name="battery_info_status_unknown" msgid="196130600938058547">"ಅಜ್ಞಾತ"</string>
    ++    <string name="battery_info_status_unknown" msgid="196130600938058547">"ಅಪರಿಚಿತ"</string>
    +     <string name="battery_info_status_charging" msgid="1705179948350365604">"ಚಾರ್ಜ್ ಆಗುತ್ತಿದೆ"</string>
    +     <string name="battery_info_status_charging_ac" msgid="2909861890674399949">"AC ನಲ್ಲಿ ಚಾರ್ಜ್‌"</string>
    +     <string name="battery_info_status_charging_ac_short" msgid="7431401092096415502">"ಚಾರ್ಜ್ ಆಗುತ್ತಿದೆ"</string>
    +@@ -341,4 +340,5 @@
    +     <string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"ದೊಡ್ಡ"</string>
    +     <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"ಕಸ್ಟಮ್ (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
    +     <string name="help_feedback_label" msgid="6815040660801785649">"ಸಹಾಯ ಮತ್ತು ಪ್ರತಿಕ್ರಿಯೆ"</string>
    ++    <string name="content_description_menu_button" msgid="8182594799812351266">"ಮೆನು"</string>
    + </resources>
    +diff --git a/packages/SettingsLib/res/values-ko/strings.xml b/packages/SettingsLib/res/values-ko/strings.xml
    +index 4617681..6910b37 100644
    +--- a/packages/SettingsLib/res/values-ko/strings.xml
    ++++ b/packages/SettingsLib/res/values-ko/strings.xml
    +@@ -28,7 +28,8 @@
    +     <string name="wifi_disabled_wifi_failure" msgid="3081668066612876581">"Wi-Fi 연결 실패"</string>
    +     <string name="wifi_disabled_password_failure" msgid="8659805351763133575">"인증 문제"</string>
    +     <string name="wifi_not_in_range" msgid="1136191511238508967">"범위 내에 없음"</string>
    +-    <string name="wifi_no_internet" msgid="9151470775868728896">"감지된 인터넷 액세스가 없으며 자동으로 다시 연결되지 않습니다."</string>
    ++    <string name="wifi_no_internet_no_reconnect" msgid="2211781637653149657">"감지된 인터넷 액세스가 없으며 자동으로 다시 연결되지 않습니다."</string>
    ++    <string name="wifi_no_internet" msgid="5011955173375805204">"인터넷에 연결되어 있지 않습니다."</string>
    +     <string name="saved_network" msgid="4352716707126620811">"<xliff:g id="NAME">%1$s</xliff:g>(으)로 저장됨"</string>
    +     <string name="connected_via_wfa" msgid="3805736726317410714">"Wi‑Fi 도우미를 통해 연결됨"</string>
    +     <string name="connected_via_passpoint" msgid="2826205693803088747">"%1$s을(를) 통해 연결됨"</string>
    +@@ -233,8 +234,6 @@
    +     <string name="debug_layout_summary" msgid="2001775315258637682">"클립 경계, 여백 등을 표시"</string>
    +     <string name="force_rtl_layout_all_locales" msgid="2259906643093138978">"RTL 레이아웃 방향 강제 적용"</string>
    +     <string name="force_rtl_layout_all_locales_summary" msgid="9192797796616132534">"모든 언어에 대해 화면 레이아웃 방향을 RTL로 강제 적용"</string>
    +-    <string name="show_cpu_usage" msgid="2389212910758076024">"CPU 사용량 표시"</string>
    +-    <string name="show_cpu_usage_summary" msgid="2113341923988958266">"현재 CPU 사용량 오버레이 표시"</string>
    +     <string name="force_hw_ui" msgid="6426383462520888732">"GPU 렌더링 강제 설정"</string>
    +     <string name="force_hw_ui_summary" msgid="5535991166074861515">"2D 드로잉용으로 GPU 강제 사용"</string>
    +     <string name="force_msaa" msgid="7920323238677284387">"4x MSAA 강제 사용"</string>
    +@@ -341,4 +340,5 @@
    +     <string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"가장 크게"</string>
    +     <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"맞춤(<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
    +     <string name="help_feedback_label" msgid="6815040660801785649">"고객센터"</string>
    ++    <string name="content_description_menu_button" msgid="8182594799812351266">"메뉴"</string>
    + </resources>
    +diff --git a/packages/SettingsLib/res/values-ky-rKG/strings.xml b/packages/SettingsLib/res/values-ky-rKG/strings.xml
    +index 96c1ec0..711551b 100644
    +--- a/packages/SettingsLib/res/values-ky-rKG/strings.xml
    ++++ b/packages/SettingsLib/res/values-ky-rKG/strings.xml
    +@@ -28,7 +28,8 @@
    +     <string name="wifi_disabled_wifi_failure" msgid="3081668066612876581">"WiFi туташуусу бузулду"</string>
    +     <string name="wifi_disabled_password_failure" msgid="8659805351763133575">"Аутентификация маселеси бар"</string>
    +     <string name="wifi_not_in_range" msgid="1136191511238508967">"Тейлөө аймагында эмес"</string>
    +-    <string name="wifi_no_internet" msgid="9151470775868728896">"Интернетке кирүү мүмкүнчүлүгү табылган жок, андыктан автоматтык түрдө кайра туташпайт."</string>
    ++    <string name="wifi_no_internet_no_reconnect" msgid="2211781637653149657">"Интернетке кирүү мүмкүнчүлүгү жок, андыктан автоматтык түрдө кайра туташпайт."</string>
    ++    <string name="wifi_no_internet" msgid="5011955173375805204">"Интернетке туташпай турат."</string>
    +     <string name="saved_network" msgid="4352716707126620811">"<xliff:g id="NAME">%1$s</xliff:g> тарабынан сакталды"</string>
    +     <string name="connected_via_wfa" msgid="3805736726317410714">"Wi‑Fi жардамчысы аркылуу туташып турат"</string>
    +     <string name="connected_via_passpoint" msgid="2826205693803088747">"%1$s аркылуу жеткиликтүү"</string>
    +@@ -233,8 +234,6 @@
    +     <string name="debug_layout_summary" msgid="2001775315258637682">"Клиптин чектерин, талааларын ж.б. көргөзүү"</string>
    +     <string name="force_rtl_layout_all_locales" msgid="2259906643093138978">"Солдон оңго багытына мажбурлоо"</string>
    +     <string name="force_rtl_layout_all_locales_summary" msgid="9192797796616132534">"Экрандын жайгашуу багытын бардык тилдер үчүн Оңдон-солго кылуу"</string>
    +-    <string name="show_cpu_usage" msgid="2389212910758076024">"CPU колдонулушун көрсөтүү"</string>
    +-    <string name="show_cpu_usage_summary" msgid="2113341923988958266">"Учурдагы CPU колдонулушун көрсөтүүчү экран катмары"</string>
    +     <string name="force_hw_ui" msgid="6426383462520888732">"GPU иштетүүсүн мажбурлоо"</string>
    +     <string name="force_hw_ui_summary" msgid="5535991166074861515">"2d тартуу үчүн GPU\'ну колдонууга мажбурлоо"</string>
    +     <string name="force_msaa" msgid="7920323238677284387">"4x MSAA мажбурлоо"</string>
    +@@ -341,4 +340,5 @@
    +     <string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"Эң чоң"</string>
    +     <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Ыңгайлаштырылган (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
    +     <string name="help_feedback_label" msgid="6815040660801785649">"Жардам жана жооп пикир"</string>
    ++    <string name="content_description_menu_button" msgid="8182594799812351266">"Меню"</string>
    + </resources>
    +diff --git a/packages/SettingsLib/res/values-lo-rLA/strings.xml b/packages/SettingsLib/res/values-lo-rLA/strings.xml
    +index 24f0c16..abf36e3 100644
    +--- a/packages/SettingsLib/res/values-lo-rLA/strings.xml
    ++++ b/packages/SettingsLib/res/values-lo-rLA/strings.xml
    +@@ -28,7 +28,8 @@
    +     <string name="wifi_disabled_wifi_failure" msgid="3081668066612876581">"​ການ​ເຊື່ອມ​ຕໍ່ WiFi ລົ້ມ​ເຫຼວ"</string>
    +     <string name="wifi_disabled_password_failure" msgid="8659805351763133575">"ບັນຫາການພິສູດຢືນຢັນ"</string>
    +     <string name="wifi_not_in_range" msgid="1136191511238508967">"ບໍ່ຢູ່ໃນໄລຍະທີ່ເຊື່ອມຕໍ່ໄດ້"</string>
    +-    <string name="wifi_no_internet" msgid="9151470775868728896">"​ບໍ່​ພົບ​ການ​ເຊື່ອມ​ຕໍ່​ອິນ​ເຕີ​ເນັດ​, ຈະ​ບໍ່​ຖືກ​ເຊື່ອມ​ຕໍ່​ໃໝ່​ໂດຍ​ອັດ​ຕະ​ໂນ​ມັດ."</string>
    ++    <string name="wifi_no_internet_no_reconnect" msgid="2211781637653149657">"ບໍ່ພົບການເຊື່ອມຕໍ່ອິນເຕີເນັດ, ຈະບໍ່ເຊື່ອມຕໍ່ໃໝ່ໂດຍອັດຕະໂນມັດ."</string>
    ++    <string name="wifi_no_internet" msgid="5011955173375805204">"ບໍ່ມີການເຊື່ອມຕໍ່ອິນເຕີເນັດ."</string>
    +     <string name="saved_network" msgid="4352716707126620811">"ບັນທຶກ​​​ໂດຍ <xliff:g id="NAME">%1$s</xliff:g>"</string>
    +     <string name="connected_via_wfa" msgid="3805736726317410714">"ເຊື່ອມ​ຕໍ່​ຜ່ານ Wi‑Fi ຕົວ​ຊ່ວຍ​ແລ້ວ"</string>
    +     <string name="connected_via_passpoint" msgid="2826205693803088747">"​ເຊື່ອມຕໍ່​ຜ່ານ %1$s ​ແລ້ວ"</string>
    +@@ -233,8 +234,6 @@
    +     <string name="debug_layout_summary" msgid="2001775315258637682">"ສະແດງໜ້າປົກຄລິບ, ຂອບ ແລະອື່ນໆ."</string>
    +     <string name="force_rtl_layout_all_locales" msgid="2259906643093138978">"ບັງ​ຄັບ​ໃຫ້ຮູບຮ່າງຂຽນຈາກຂວາຫາຊ້າຍ"</string>
    +     <string name="force_rtl_layout_all_locales_summary" msgid="9192797796616132534">"ບັງຄັບໃຫ້ຮູບຮ່າງໜ້າຈໍ ຂຽນຈາກຂວາໄປຊ້າຍ ສຳລັບທຸກພາສາ"</string>
    +-    <string name="show_cpu_usage" msgid="2389212910758076024">"ສະແດງການນຳໃຊ້ CPU"</string>
    +-    <string name="show_cpu_usage_summary" msgid="2113341923988958266">"ການວາງຊ້ອນໜ້າຈໍທີ່ສະແດງການນຳໃຊ້ CPU ໃນປັດຈຸບັນ"</string>
    +     <string name="force_hw_ui" msgid="6426383462520888732">"ບັງຄັບໃຊ້ GPU ປະມວນພາບ"</string>
    +     <string name="force_hw_ui_summary" msgid="5535991166074861515">"ບັງຄັບໃຊ້ GPU ເພື່ອການແຕ້ມພາບ 2 ມິຕິ"</string>
    +     <string name="force_msaa" msgid="7920323238677284387">"ບັງຄັບໃຊ້ 4x MSAA"</string>
    +@@ -341,4 +340,5 @@
    +     <string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"ໃຫຍ່ທີ່ສຸດ"</string>
    +     <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"ປັບແຕ່ງເອງ (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
    +     <string name="help_feedback_label" msgid="6815040660801785649">"ຊ່ວຍເຫຼືອ &amp; ຄຳຕິຊົມ"</string>
    ++    <string name="content_description_menu_button" msgid="8182594799812351266">"ເມນູ"</string>
    + </resources>
    +diff --git a/packages/SettingsLib/res/values-lt/strings.xml b/packages/SettingsLib/res/values-lt/strings.xml
    +index 4b8890d..cab29de 100644
    +--- a/packages/SettingsLib/res/values-lt/strings.xml
    ++++ b/packages/SettingsLib/res/values-lt/strings.xml
    +@@ -28,7 +28,8 @@
    +     <string name="wifi_disabled_wifi_failure" msgid="3081668066612876581">"„Wi-Fi“ ryšio triktis"</string>
    +     <string name="wifi_disabled_password_failure" msgid="8659805351763133575">"Autentifikavimo problema"</string>
    +     <string name="wifi_not_in_range" msgid="1136191511238508967">"Ne diapazone"</string>
    +-    <string name="wifi_no_internet" msgid="9151470775868728896">"Neaptikta jokia prieiga prie interneto, nebus automatiškai iš naujo prisijungta."</string>
    ++    <string name="wifi_no_internet_no_reconnect" msgid="2211781637653149657">"Neaptikta jokia prieiga prie interneto, nebus automatiškai iš naujo prisijungta."</string>
    ++    <string name="wifi_no_internet" msgid="5011955173375805204">"Nėra prieigos prie interneto."</string>
    +     <string name="saved_network" msgid="4352716707126620811">"Išsaugojo <xliff:g id="NAME">%1$s</xliff:g>"</string>
    +     <string name="connected_via_wfa" msgid="3805736726317410714">"Prisijungta naudojant „Wi‑Fi“ pagelbiklį"</string>
    +     <string name="connected_via_passpoint" msgid="2826205693803088747">"Prisijungta naudojant „%1$s“"</string>
    +@@ -233,8 +234,6 @@
    +     <string name="debug_layout_summary" msgid="2001775315258637682">"Rodyti iškarpų ribas, kraštines ir t. t."</string>
    +     <string name="force_rtl_layout_all_locales" msgid="2259906643093138978">"Išdėst. iš dešin. į kairę"</string>
    +     <string name="force_rtl_layout_all_locales_summary" msgid="9192797796616132534">"Nust. visų lokalių ekran. išdėst. iš deš. į kairę"</string>
    +-    <string name="show_cpu_usage" msgid="2389212910758076024">"Rodyti centr. proc. naud."</string>
    +-    <string name="show_cpu_usage_summary" msgid="2113341923988958266">"Ekrano perdanga rodo dabartinį centr. proc. naud."</string>
    +     <string name="force_hw_ui" msgid="6426383462520888732">"Priverst. GPU atvaizd."</string>
    +     <string name="force_hw_ui_summary" msgid="5535991166074861515">"Priverstinai naudoti GPU atvaizduojant 2D formatą"</string>
    +     <string name="force_msaa" msgid="7920323238677284387">"Priverst. vykdyti 4x MSAA"</string>
    +@@ -341,4 +340,5 @@
    +     <string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"Didžiausias"</string>
    +     <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Tinkintas (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
    +     <string name="help_feedback_label" msgid="6815040660801785649">"Pagalba ir atsiliepimai"</string>
    ++    <string name="content_description_menu_button" msgid="8182594799812351266">"Meniu"</string>
    + </resources>
    +diff --git a/packages/SettingsLib/res/values-lv/strings.xml b/packages/SettingsLib/res/values-lv/strings.xml
    +index 4d76adc..90bf867 100644
    +--- a/packages/SettingsLib/res/values-lv/strings.xml
    ++++ b/packages/SettingsLib/res/values-lv/strings.xml
    +@@ -28,7 +28,8 @@
    +     <string name="wifi_disabled_wifi_failure" msgid="3081668066612876581">"Wi-Fi savienojuma kļūme"</string>
    +     <string name="wifi_disabled_password_failure" msgid="8659805351763133575">"Autentificēšanas problēma"</string>
    +     <string name="wifi_not_in_range" msgid="1136191511238508967">"Nav diapazona ietvaros"</string>
    +-    <string name="wifi_no_internet" msgid="9151470775868728896">"Nevar noteikt interneta savienojumu. Savienojums netiks izveidots vēlreiz automātiski."</string>
    ++    <string name="wifi_no_internet_no_reconnect" msgid="2211781637653149657">"Nevar noteikt interneta savienojumu. Savienojums netiks izveidots vēlreiz automātiski."</string>
    ++    <string name="wifi_no_internet" msgid="5011955173375805204">"Nav piekļuves internetam."</string>
    +     <string name="saved_network" msgid="4352716707126620811">"Saglabāja: <xliff:g id="NAME">%1$s</xliff:g>"</string>
    +     <string name="connected_via_wfa" msgid="3805736726317410714">"Izveidots savienojums ar Wi‑Fi palīgu"</string>
    +     <string name="connected_via_passpoint" msgid="2826205693803088747">"Savienots, izmantojot %1$s"</string>
    +@@ -233,8 +234,6 @@
    +     <string name="debug_layout_summary" msgid="2001775315258637682">"Rādīt klipu robežas, malas utt."</string>
    +     <string name="force_rtl_layout_all_locales" msgid="2259906643093138978">"Virziens no labās uz kreiso (Obligāts) WL: 295"</string>
    +     <string name="force_rtl_layout_all_locales_summary" msgid="9192797796616132534">"Obl. izkārt. virz. no labās uz kr. pusi visām lok."</string>
    +-    <string name="show_cpu_usage" msgid="2389212910758076024">"Rādīt CPU lietojumu"</string>
    +-    <string name="show_cpu_usage_summary" msgid="2113341923988958266">"Ekrāna pārklājums ar aktuālo CPU lietojumu"</string>
    +     <string name="force_hw_ui" msgid="6426383462520888732">"Piespiedu GPU render."</string>
    +     <string name="force_hw_ui_summary" msgid="5535991166074861515">"Izmantot GPU atveidi divdimensiju zīmējumiem"</string>
    +     <string name="force_msaa" msgid="7920323238677284387">"4x MSAA piespiedu palaiš."</string>
    +@@ -341,4 +340,5 @@
    +     <string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"Vislielākais"</string>
    +     <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Pielāgots (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
    +     <string name="help_feedback_label" msgid="6815040660801785649">"Palīdzība un atsauksmes"</string>
    ++    <string name="content_description_menu_button" msgid="8182594799812351266">"Izvēlne"</string>
    + </resources>
    +diff --git a/packages/SettingsLib/res/values-mk-rMK/strings.xml b/packages/SettingsLib/res/values-mk-rMK/strings.xml
    +index 953360a..725a39d 100644
    +--- a/packages/SettingsLib/res/values-mk-rMK/strings.xml
    ++++ b/packages/SettingsLib/res/values-mk-rMK/strings.xml
    +@@ -28,7 +28,8 @@
    +     <string name="wifi_disabled_wifi_failure" msgid="3081668066612876581">"Поврзувањето преку Wi-Fi не успеа"</string>
    +     <string name="wifi_disabled_password_failure" msgid="8659805351763133575">"Проблем со автентикација"</string>
    +     <string name="wifi_not_in_range" msgid="1136191511238508967">"Надвор од опсег"</string>
    +-    <string name="wifi_no_internet" msgid="9151470775868728896">"Не е откриен пристап до интернет, нема автоматски повторно да се поврзете."</string>
    ++    <string name="wifi_no_internet_no_reconnect" msgid="2211781637653149657">"Не е откриен пристап до Интернет, нема автоматски повторно да се поврзете."</string>
    ++    <string name="wifi_no_internet" msgid="5011955173375805204">"Нема пристап до Интернет."</string>
    +     <string name="saved_network" msgid="4352716707126620811">"Зачувано од <xliff:g id="NAME">%1$s</xliff:g>"</string>
    +     <string name="connected_via_wfa" msgid="3805736726317410714">"Поврзано преку помошник за Wi-Fismile"</string>
    +     <string name="connected_via_passpoint" msgid="2826205693803088747">"Поврзано преку %1$s"</string>
    +@@ -233,8 +234,6 @@
    +     <string name="debug_layout_summary" msgid="2001775315258637682">"Прикажи граници на клип, маргини, итн."</string>
    +     <string name="force_rtl_layout_all_locales" msgid="2259906643093138978">"Сила на RTL за насока на слој"</string>
    +     <string name="force_rtl_layout_all_locales_summary" msgid="9192797796616132534">"Присилно постави насока на распоред на екран во РТЛ за сите локални стандарди"</string>
    +-    <string name="show_cpu_usage" msgid="2389212910758076024">"Прикажи употреба на ЦПУ"</string>
    +-    <string name="show_cpu_usage_summary" msgid="2113341923988958266">"Прекривка на екран прикаж. употреба на тековен ЦПУ"</string>
    +     <string name="force_hw_ui" msgid="6426383462520888732">"Присили рендерирање на GPU"</string>
    +     <string name="force_hw_ui_summary" msgid="5535991166074861515">"Присилно користење на GPU за цртеж 2D"</string>
    +     <string name="force_msaa" msgid="7920323238677284387">"Сила 4x MSAA"</string>
    +@@ -341,4 +340,5 @@
    +     <string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"Најголем"</string>
    +     <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Приспособен (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
    +     <string name="help_feedback_label" msgid="6815040660801785649">"Помош и повратни информации"</string>
    ++    <string name="content_description_menu_button" msgid="8182594799812351266">"Мени"</string>
    + </resources>
    +diff --git a/packages/SettingsLib/res/values-ml-rIN/strings.xml b/packages/SettingsLib/res/values-ml-rIN/strings.xml
    +index 92c0448..01565ac 100644
    +--- a/packages/SettingsLib/res/values-ml-rIN/strings.xml
    ++++ b/packages/SettingsLib/res/values-ml-rIN/strings.xml
    +@@ -28,7 +28,8 @@
    +     <string name="wifi_disabled_wifi_failure" msgid="3081668066612876581">"WiFi കണക്ഷൻ പരാജയം"</string>
    +     <string name="wifi_disabled_password_failure" msgid="8659805351763133575">"ആധികാരികമാക്കുന്നതിലെ പ്രശ്‌നം"</string>
    +     <string name="wifi_not_in_range" msgid="1136191511238508967">"പരിധിയിലില്ല"</string>
    +-    <string name="wifi_no_internet" msgid="9151470775868728896">"ഇന്റർനെറ്റ് ആക്സസ്സൊന്നും കണ്ടെത്താത്തതിനാൽ സ്വയം വീണ്ടും കണക്‌റ്റുചെയ്യില്ല."</string>
    ++    <string name="wifi_no_internet_no_reconnect" msgid="2211781637653149657">"ഇന്റർനെറ്റ് ആക്സസ്സൊന്നും കണ്ടെത്താത്തതിനാൽ സ്വയം വീണ്ടും കണക്‌റ്റുചെയ്യില്ല."</string>
    ++    <string name="wifi_no_internet" msgid="5011955173375805204">"ഇന്റർനെറ്റ് ആക്‌സസ്സ് ഇല്ല."</string>
    +     <string name="saved_network" msgid="4352716707126620811">"<xliff:g id="NAME">%1$s</xliff:g> സംരക്ഷിച്ചത്"</string>
    +     <string name="connected_via_wfa" msgid="3805736726317410714">"വൈഫൈ അസിസ്റ്റന്റ് മുഖേന കണക്‌റ്റുചെയ്തു"</string>
    +     <string name="connected_via_passpoint" msgid="2826205693803088747">"%1$s വഴി ബന്ധിപ്പിച്ചു"</string>
    +@@ -233,8 +234,6 @@
    +     <string name="debug_layout_summary" msgid="2001775315258637682">"ക്ലിപ്പ് ബൗണ്ടുകൾ, മാർജിനുകൾ തുടങ്ങിയവ ദൃശ്യമാക്കുക"</string>
    +     <string name="force_rtl_layout_all_locales" msgid="2259906643093138978">"RTL ലേഔട്ട് ഡയറക്ഷൻ നിർബന്ധമാക്കുക"</string>
    +     <string name="force_rtl_layout_all_locales_summary" msgid="9192797796616132534">"എല്ലാ ഭാഷകൾക്കുമായി സ്‌ക്രീൻ ലേഔട്ട് ഡയറക്ഷൻ RTL-ലേക്ക് നിർബന്ധമാക്കുക"</string>
    +-    <string name="show_cpu_usage" msgid="2389212910758076024">"CPU ഉപയോഗം ദൃശ്യമാക്കുക"</string>
    +-    <string name="show_cpu_usage_summary" msgid="2113341923988958266">"സ്ക്രീൻ ഓവർലേ നിലവിലെ CPU ഉപയോഗം ദൃശ്യമാക്കുന്നു"</string>
    +     <string name="force_hw_ui" msgid="6426383462520888732">"GPU റെൻഡറിംഗ് ഫോഴ്സ്ചെയ്യുക"</string>
    +     <string name="force_hw_ui_summary" msgid="5535991166074861515">"2d ഡ്രോയിംഗിനായുള്ള നിരബന്ധിത GPU ഉപയോഗം"</string>
    +     <string name="force_msaa" msgid="7920323238677284387">"4x MSAA നിർബന്ധമാക്കുക"</string>
    +@@ -341,4 +340,5 @@
    +     <string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"ഏറ്റവും വലുത്"</string>
    +     <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"ഇഷ്ടാനുസൃതം ( <xliff:g id="DENSITYDPI">%d</xliff:g> )"</string>
    +     <string name="help_feedback_label" msgid="6815040660801785649">"സഹായവും പ്രതികരണവും"</string>
    ++    <string name="content_description_menu_button" msgid="8182594799812351266">"മെനു"</string>
    + </resources>
    +diff --git a/packages/SettingsLib/res/values-mn-rMN/strings.xml b/packages/SettingsLib/res/values-mn-rMN/strings.xml
    +index 4c98c04..5121f44 100644
    +--- a/packages/SettingsLib/res/values-mn-rMN/strings.xml
    ++++ b/packages/SettingsLib/res/values-mn-rMN/strings.xml
    +@@ -28,7 +28,8 @@
    +     <string name="wifi_disabled_wifi_failure" msgid="3081668066612876581">"WiFi холболт амжилтгүй"</string>
    +     <string name="wifi_disabled_password_failure" msgid="8659805351763133575">"Гэрчлэлийн асуудал"</string>
    +     <string name="wifi_not_in_range" msgid="1136191511238508967">"Хүрээнд байхгүй"</string>
    +-    <string name="wifi_no_internet" msgid="9151470775868728896">"Интернэт холболт илэрсэнгүй, автоматаар дахин холболт хийгдэхгүй"</string>
    ++    <string name="wifi_no_internet_no_reconnect" msgid="2211781637653149657">"Интернэт хандалт олдсонгүй тул автоматаар дахин холбогдохгүй."</string>
    ++    <string name="wifi_no_internet" msgid="5011955173375805204">"Интернэт хандалт алга"</string>
    +     <string name="saved_network" msgid="4352716707126620811">"<xliff:g id="NAME">%1$s</xliff:g> хадгалсан"</string>
    +     <string name="connected_via_wfa" msgid="3805736726317410714">"Wi-Fi туслагчаар дамжуулан холбогдлоо"</string>
    +     <string name="connected_via_passpoint" msgid="2826205693803088747">"%1$s-р холбогдсон"</string>
    +@@ -233,8 +234,6 @@
    +     <string name="debug_layout_summary" msgid="2001775315258637682">"Клипийн зах, хязгаар зэргийг харуулах"</string>
    +     <string name="force_rtl_layout_all_locales" msgid="2259906643093138978">"RTL байрлалын чиглэлийг хүчээр тогтоох"</string>
    +     <string name="force_rtl_layout_all_locales_summary" msgid="9192797796616132534">"Бүх локалын хувьд дэлгэцийн байрлалын чиглэлийг хүчээр RTL болгох"</string>
    +-    <string name="show_cpu_usage" msgid="2389212910758076024">"CPU ашиглалтыг харуулах"</string>
    +-    <string name="show_cpu_usage_summary" msgid="2113341923988958266">"Дэлгэцийн давхцалаар одоогийн CPU ашиглалтыг харуулж байна"</string>
    +     <string name="force_hw_ui" msgid="6426383462520888732">"Хүчээр GPU ашиглах"</string>
    +     <string name="force_hw_ui_summary" msgid="5535991166074861515">"GPU-г 2d зурагт хүчээр ашиглах"</string>
    +     <string name="force_msaa" msgid="7920323238677284387">"Хүчээр 4x MSAA ашиглах"</string>
    +@@ -341,4 +340,5 @@
    +     <string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"Хамгийн том"</string>
    +     <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Тогтмол утга (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
    +     <string name="help_feedback_label" msgid="6815040660801785649">"Тусламж, санал хүсэлт"</string>
    ++    <string name="content_description_menu_button" msgid="8182594799812351266">"Цэс"</string>
    + </resources>
    +diff --git a/packages/SettingsLib/res/values-mr-rIN/strings.xml b/packages/SettingsLib/res/values-mr-rIN/strings.xml
    +index e3a7cc4..5ee18d5 100644
    +--- a/packages/SettingsLib/res/values-mr-rIN/strings.xml
    ++++ b/packages/SettingsLib/res/values-mr-rIN/strings.xml
    +@@ -28,7 +28,8 @@
    +     <string name="wifi_disabled_wifi_failure" msgid="3081668066612876581">"WiFi कनेक्शन अयशस्वी"</string>
    +     <string name="wifi_disabled_password_failure" msgid="8659805351763133575">"प्रमाणीकरण समस्या"</string>
    +     <string name="wifi_not_in_range" msgid="1136191511238508967">"परिक्षेत्रामध्ये नाही"</string>
    +-    <string name="wifi_no_internet" msgid="9151470775868728896">"कोणताही इंटरनेट प्रवेश आढळला नाही, स्वयंचलितपणे रीकनेक्ट करणार नाही."</string>
    ++    <string name="wifi_no_internet_no_reconnect" msgid="2211781637653149657">"कोणताही इंटरनेट प्रवेश आढळला नाही, स्वयंचलितपणे पुन्हा कनेक्ट करणार नाही."</string>
    ++    <string name="wifi_no_internet" msgid="5011955173375805204">"इंटरनेट प्रवेश नाही."</string>
    +     <string name="saved_network" msgid="4352716707126620811">"<xliff:g id="NAME">%1$s</xliff:g> द्वारे जतन केले"</string>
    +     <string name="connected_via_wfa" msgid="3805736726317410714">"Wi‑Fi सहाय्यक द्वारे कनेक्ट केले"</string>
    +     <string name="connected_via_passpoint" msgid="2826205693803088747">"%1$s द्वारे कनेक्‍ट केले"</string>
    +@@ -233,8 +234,6 @@
    +     <string name="debug_layout_summary" msgid="2001775315258637682">"क्लिप सीमा, समास इत्यादी दर्शवा."</string>
    +     <string name="force_rtl_layout_all_locales" msgid="2259906643093138978">"RTL लेआउट दिशानिर्देशाची सक्ती करा"</string>
    +     <string name="force_rtl_layout_all_locales_summary" msgid="9192797796616132534">"सर्व लोकॅलसाठी RTL स्क्रीन लेआउट दिशानिर्देशाची सक्ती करा"</string>
    +-    <string name="show_cpu_usage" msgid="2389212910758076024">"CPU वापर दर्शवा"</string>
    +-    <string name="show_cpu_usage_summary" msgid="2113341923988958266">"वर्तमान CPU वापर दर्शविणारे स्क्रीन आच्छादन"</string>
    +     <string name="force_hw_ui" msgid="6426383462520888732">"GPU प्रस्तुतीस सक्ती करा"</string>
    +     <string name="force_hw_ui_summary" msgid="5535991166074861515">"2d रेखांकनासाठी GPU च्या वापराची सक्ती करा"</string>
    +     <string name="force_msaa" msgid="7920323238677284387">"4x MSAA ची सक्ती करा"</string>
    +@@ -341,4 +340,5 @@
    +     <string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"सर्वात मोठा"</string>
    +     <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"सानुकूल करा (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
    +     <string name="help_feedback_label" msgid="6815040660801785649">"मदत आणि अभिप्राय"</string>
    ++    <string name="content_description_menu_button" msgid="8182594799812351266">"मेनू"</string>
    + </resources>
    +diff --git a/packages/SettingsLib/res/values-ms-rMY/strings.xml b/packages/SettingsLib/res/values-ms-rMY/strings.xml
    +index a1caa2a..fabfd63 100644
    +--- a/packages/SettingsLib/res/values-ms-rMY/strings.xml
    ++++ b/packages/SettingsLib/res/values-ms-rMY/strings.xml
    +@@ -28,7 +28,8 @@
    +     <string name="wifi_disabled_wifi_failure" msgid="3081668066612876581">"Kegagalan Sambungan WiFi"</string>
    +     <string name="wifi_disabled_password_failure" msgid="8659805351763133575">"Masalah pengesahan"</string>
    +     <string name="wifi_not_in_range" msgid="1136191511238508967">"Tidak dalam liputan"</string>
    +-    <string name="wifi_no_internet" msgid="9151470775868728896">"Tiada Akses Internet Dikesan, tidak akan menyambung secara automatik."</string>
    ++    <string name="wifi_no_internet_no_reconnect" msgid="2211781637653149657">"Tiada Akses Internet Dikesan, tidak akan menyambung secara automatik."</string>
    ++    <string name="wifi_no_internet" msgid="5011955173375805204">"Tiada Akses Internet."</string>
    +     <string name="saved_network" msgid="4352716707126620811">"Diselamatkan oleh <xliff:g id="NAME">%1$s</xliff:g>"</string>
    +     <string name="connected_via_wfa" msgid="3805736726317410714">"Disambungkan melalui Pembantu Wi-Fi"</string>
    +     <string name="connected_via_passpoint" msgid="2826205693803088747">"Disambungkan melalui %1$s"</string>
    +@@ -233,8 +234,6 @@
    +     <string name="debug_layout_summary" msgid="2001775315258637682">"Tunjukkan batas klip, margin dll."</string>
    +     <string name="force_rtl_layout_all_locales" msgid="2259906643093138978">"Paksa arah reka letak RTL"</string>
    +     <string name="force_rtl_layout_all_locales_summary" msgid="9192797796616132534">"Paksa arah reka letak skrin RTL bagi semua tempat peristiwa"</string>
    +-    <string name="show_cpu_usage" msgid="2389212910758076024">"Tunjukkan penggunaan CPU"</string>
    +-    <string name="show_cpu_usage_summary" msgid="2113341923988958266">"Tindihan skrin menunjukkan penggunaan semasa CPU"</string>
    +     <string name="force_hw_ui" msgid="6426383462520888732">"Paksa pemaparan GPU"</string>
    +     <string name="force_hw_ui_summary" msgid="5535991166074861515">"Paksa penggunaan GPU untuk lukisan 2d"</string>
    +     <string name="force_msaa" msgid="7920323238677284387">"Paksa 4x MSAA"</string>
    +@@ -341,4 +340,5 @@
    +     <string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"Terbesar"</string>
    +     <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Tersuai (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
    +     <string name="help_feedback_label" msgid="6815040660801785649">"Bantuan &amp; maklum balas"</string>
    ++    <string name="content_description_menu_button" msgid="8182594799812351266">"Menu"</string>
    + </resources>
    +diff --git a/packages/SettingsLib/res/values-my-rMM/strings.xml b/packages/SettingsLib/res/values-my-rMM/strings.xml
    +index 6a1c331..571a931 100644
    +--- a/packages/SettingsLib/res/values-my-rMM/strings.xml
    ++++ b/packages/SettingsLib/res/values-my-rMM/strings.xml
    +@@ -28,7 +28,8 @@
    +     <string name="wifi_disabled_wifi_failure" msgid="3081668066612876581">"WiFi ချိတ်ဆက်မှု မအောင်မြင်ပါ"</string>
    +     <string name="wifi_disabled_password_failure" msgid="8659805351763133575">"စစ်မှန်ကြောင်းအတည်ပြုရန်၌ ပြသနာရှိခြင်း"</string>
    +     <string name="wifi_not_in_range" msgid="1136191511238508967">"စက်ကွင်းထဲတွင် မဟုတ်ပါ"</string>
    +-    <string name="wifi_no_internet" msgid="9151470775868728896">"မည်သည့် အင်တာနက်မျှမရှိပါ၊ အလိုအလျောက် ပြန်လည်မချိတ်ဆက်ပါ။"</string>
    ++    <string name="wifi_no_internet_no_reconnect" msgid="2211781637653149657">"အင်တာနက်ချိတ်ဆက်မှု ရှာမတွေ့ပါ၊ အလိုအလျောက် ပြန်လည်ချိတ်ဆက်မည် မဟုတ်ပါ။"</string>
    ++    <string name="wifi_no_internet" msgid="5011955173375805204">"အင်တာနက် ချိတ်ဆက်မှု မရှိပါ။"</string>
    +     <string name="saved_network" msgid="4352716707126620811">"<xliff:g id="NAME">%1$s</xliff:g> မှသိမ်းဆည်းခဲ့သည်"</string>
    +     <string name="connected_via_wfa" msgid="3805736726317410714">"ကြိုးမဲ့ကူညီသူမှတဆင့် ချိတ်ဆက်၏"</string>
    +     <string name="connected_via_passpoint" msgid="2826205693803088747">"%1$s မှတစ်ဆင့် ချိတ်ဆက်ထားသည်"</string>
    +@@ -233,8 +234,6 @@
    +     <string name="debug_layout_summary" msgid="2001775315258637682">"ဖြတ်ပိုင်းအနားသတ်များ၊ အနားများ စသဖြင့် ပြပါ။"</string>
    +     <string name="force_rtl_layout_all_locales" msgid="2259906643093138978">"RTL ဖွဲ့စည်းပုံအညွှန်း မဖြစ်မနေလုပ်ပါ"</string>
    +     <string name="force_rtl_layout_all_locales_summary" msgid="9192797796616132534">"လိုကယ်လ်အားလုံးအတွက် မျက်နှာပြင် ဖွဲ့စည်းပုံအညွှန်း မဖြစ်မနေလုပ်ရန်"</string>
    +-    <string name="show_cpu_usage" msgid="2389212910758076024">"CPUအသုံးပြုမှုအား ပြသရန်"</string>
    +-    <string name="show_cpu_usage_summary" msgid="2113341923988958266">"လက်ရှိCPUအသုံးပြုမှုအားလုံး မျက်နှာပြင်တွင်ပြသမှု"</string>
    +     <string name="force_hw_ui" msgid="6426383462520888732">"GPUအား အတင်းအကျပ်ဖြစ်စေမည်"</string>
    +     <string name="force_hw_ui_summary" msgid="5535991166074861515">"GPUကို ၂ဖက်မြင်ပုံဆွဲခြင်းအတွက် မဖြစ်မနေအသုံးပြုစေရန်"</string>
    +     <string name="force_msaa" msgid="7920323238677284387">"တွန်းအား ၄× MSAA"</string>
    +@@ -341,4 +340,5 @@
    +     <string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"အကြီးဆုံး"</string>
    +     <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"စိတ်ကြိုက် (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
    +     <string name="help_feedback_label" msgid="6815040660801785649">"အကူအညီနှင့် အကြံပြုချက်"</string>
    ++    <string name="content_description_menu_button" msgid="8182594799812351266">"မီနူး"</string>
    + </resources>
    +diff --git a/packages/SettingsLib/res/values-nb/strings.xml b/packages/SettingsLib/res/values-nb/strings.xml
    +index 5d8ae55..834c849 100644
    +--- a/packages/SettingsLib/res/values-nb/strings.xml
    ++++ b/packages/SettingsLib/res/values-nb/strings.xml
    +@@ -28,7 +28,8 @@
    +     <string name="wifi_disabled_wifi_failure" msgid="3081668066612876581">"Wi-Fi-tilkoblingsfeil"</string>
    +     <string name="wifi_disabled_password_failure" msgid="8659805351763133575">"Autentiseringsproblem"</string>
    +     <string name="wifi_not_in_range" msgid="1136191511238508967">"Utenfor område"</string>
    +-    <string name="wifi_no_internet" msgid="9151470775868728896">"Ingen Internett-tilgang ble funnet. Kan ikke koble til på nytt automatisk."</string>
    ++    <string name="wifi_no_internet_no_reconnect" msgid="2211781637653149657">"Fant ingen Internett-tilgang. Kan ikke automatisk koble til på nytt."</string>
    ++    <string name="wifi_no_internet" msgid="5011955173375805204">"Ingen Internett-tilgang."</string>
    +     <string name="saved_network" msgid="4352716707126620811">"Lagret av <xliff:g id="NAME">%1$s</xliff:g>"</string>
    +     <string name="connected_via_wfa" msgid="3805736726317410714">"Koblet til via en Wi-Fi-assistent"</string>
    +     <string name="connected_via_passpoint" msgid="2826205693803088747">"Tilkoblet via %1$s"</string>
    +@@ -233,8 +234,6 @@
    +     <string name="debug_layout_summary" msgid="2001775315258637682">"Vis kanter, marger osv."</string>
    +     <string name="force_rtl_layout_all_locales" msgid="2259906643093138978">"Tving layoutretning for RTL"</string>
    +     <string name="force_rtl_layout_all_locales_summary" msgid="9192797796616132534">"Tving RTL-retning på skjermen for alle språk"</string>
    +-    <string name="show_cpu_usage" msgid="2389212910758076024">"Vis CPU-bruk"</string>
    +-    <string name="show_cpu_usage_summary" msgid="2113341923988958266">"Skjermoverlegg viser gjeldende CPU-bruk"</string>
    +     <string name="force_hw_ui" msgid="6426383462520888732">"Tving GPU-gjengivelse"</string>
    +     <string name="force_hw_ui_summary" msgid="5535991166074861515">"Tving bruk av GPU for 2D-tegning"</string>
    +     <string name="force_msaa" msgid="7920323238677284387">"Tving 4x MSAA"</string>
    +@@ -341,4 +340,5 @@
    +     <string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"Størst"</string>
    +     <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Egendefinert (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
    +     <string name="help_feedback_label" msgid="6815040660801785649">"Hjelp og tilbakemelding"</string>
    ++    <string name="content_description_menu_button" msgid="8182594799812351266">"Meny"</string>
    + </resources>
    +diff --git a/packages/SettingsLib/res/values-ne-rNP/strings.xml b/packages/SettingsLib/res/values-ne-rNP/strings.xml
    +index 15cc8ea..01b39a0 100644
    +--- a/packages/SettingsLib/res/values-ne-rNP/strings.xml
    ++++ b/packages/SettingsLib/res/values-ne-rNP/strings.xml
    +@@ -28,7 +28,8 @@
    +     <string name="wifi_disabled_wifi_failure" msgid="3081668066612876581">"वाईफाई जडान असफल"</string>
    +     <string name="wifi_disabled_password_failure" msgid="8659805351763133575">"प्रमाणीकरण समस्या"</string>
    +     <string name="wifi_not_in_range" msgid="1136191511238508967">"दायराभित्र छैन"</string>
    +-    <string name="wifi_no_internet" msgid="9151470775868728896">"कुनै इन्टरनेट पहुँच पाईएन, स्वचालित रूपमा पुन: जडान छैन।"</string>
    ++    <string name="wifi_no_internet_no_reconnect" msgid="2211781637653149657">"इन्टरनेट माथिको पहुँच पत्ता लागेन, स्वतः पुनः जडान हुने छैन।"</string>
    ++    <string name="wifi_no_internet" msgid="5011955173375805204">"इन्टरनेट माथिको पहुँच छैन।"</string>
    +     <string name="saved_network" msgid="4352716707126620811">"<xliff:g id="NAME">%1$s</xliff:g> द्वारा सुरक्षित गरियो"</string>
    +     <string name="connected_via_wfa" msgid="3805736726317410714">"Wi-Fi सहायक द्वारा जोडिएको"</string>
    +     <string name="connected_via_passpoint" msgid="2826205693803088747">"%1$s मार्फत जडित"</string>
    +@@ -233,8 +234,6 @@
    +     <string name="debug_layout_summary" msgid="2001775315258637682">"क्लिप सीमा, मार्जिन, इत्यादि देखाउनुहोस्।"</string>
    +     <string name="force_rtl_layout_all_locales" msgid="2259906643093138978">"RTL लेआउट दिशामा जबर्जस्ती गर्नुहोस्"</string>
    +     <string name="force_rtl_layout_all_locales_summary" msgid="9192797796616132534">"सबै लोकेलहरूको लागि RTLमा स्क्रिन लेआउट दिशामा जबर्जस्ती गर्नुहोस्"</string>
    +-    <string name="show_cpu_usage" msgid="2389212910758076024">"CPU उपयोग देखाउनुहोस्"</string>
    +-    <string name="show_cpu_usage_summary" msgid="2113341923988958266">"स्क्रिन ओभरले वर्तमान CPU प्रयोग देखाउँदै"</string>
    +     <string name="force_hw_ui" msgid="6426383462520888732">"GPU रेन्डर गर्न जोड गर्नुहोस्"</string>
    +     <string name="force_hw_ui_summary" msgid="5535991166074861515">"2d चित्र कोर्नका लागि GPU को प्रयोगलाई जोड दिनुहोस्"</string>
    +     <string name="force_msaa" msgid="7920323238677284387">"4x MSAA जोड गर्नुहोस्"</string>
    +@@ -341,4 +340,5 @@
    +     <string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"सबैभन्दा ठूलो"</string>
    +     <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"अनुकूलन (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
    +     <string name="help_feedback_label" msgid="6815040660801785649">"मद्दत र प्रतिक्रिया"</string>
    ++    <string name="content_description_menu_button" msgid="8182594799812351266">"मेनु"</string>
    + </resources>
    +diff --git a/packages/SettingsLib/res/values-nl/strings.xml b/packages/SettingsLib/res/values-nl/strings.xml
    +index 12bdb4f..feb78df 100644
    +--- a/packages/SettingsLib/res/values-nl/strings.xml
    ++++ b/packages/SettingsLib/res/values-nl/strings.xml
    +@@ -28,7 +28,8 @@
    +     <string name="wifi_disabled_wifi_failure" msgid="3081668066612876581">"Wifi-verbinding mislukt"</string>
    +     <string name="wifi_disabled_password_failure" msgid="8659805351763133575">"Authenticatieprobleem"</string>
    +     <string name="wifi_not_in_range" msgid="1136191511238508967">"Niet binnen bereik"</string>
    +-    <string name="wifi_no_internet" msgid="9151470775868728896">"Geen internettoegang gevonden. Er wordt niet automatisch opnieuw verbinding gemaakt."</string>
    ++    <string name="wifi_no_internet_no_reconnect" msgid="2211781637653149657">"Geen internettoegang gevonden. Er wordt niet automatisch opnieuw verbinding gemaakt."</string>
    ++    <string name="wifi_no_internet" msgid="5011955173375805204">"Geen internettoegang."</string>
    +     <string name="saved_network" msgid="4352716707126620811">"Opgeslagen door <xliff:g id="NAME">%1$s</xliff:g>"</string>
    +     <string name="connected_via_wfa" msgid="3805736726317410714">"Verbonden via wifi-assistent"</string>
    +     <string name="connected_via_passpoint" msgid="2826205693803088747">"Verbonden via %1$s"</string>
    +@@ -233,8 +234,6 @@
    +     <string name="debug_layout_summary" msgid="2001775315258637682">"Clipgrenzen, marges en meer weergeven"</string>
    +     <string name="force_rtl_layout_all_locales" msgid="2259906643093138978">"V.r.n.l.-indelingsrichting afdwingen"</string>
    +     <string name="force_rtl_layout_all_locales_summary" msgid="9192797796616132534">"Schermindelingsrichting geforceerd instellen op v.r.n.l. voor alle talen"</string>
    +-    <string name="show_cpu_usage" msgid="2389212910758076024">"CPU-gebruik weergeven"</string>
    +-    <string name="show_cpu_usage_summary" msgid="2113341923988958266">"Schermoverlay met huidig CPU-gebruik"</string>
    +     <string name="force_hw_ui" msgid="6426383462520888732">"GPU-rendering afdwingen"</string>
    +     <string name="force_hw_ui_summary" msgid="5535991166074861515">"Gebruik van GPU voor 2D-tekening forceren"</string>
    +     <string name="force_msaa" msgid="7920323238677284387">"4x MSAA forceren"</string>
    +@@ -341,4 +340,5 @@
    +     <string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"Grootst"</string>
    +     <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Aangepast (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
    +     <string name="help_feedback_label" msgid="6815040660801785649">"Help en feedback"</string>
    ++    <string name="content_description_menu_button" msgid="8182594799812351266">"Menu"</string>
    + </resources>
    +diff --git a/packages/SettingsLib/res/values-pa-rIN/strings.xml b/packages/SettingsLib/res/values-pa-rIN/strings.xml
    +index 21d11b0..f21ee6d 100644
    +--- a/packages/SettingsLib/res/values-pa-rIN/strings.xml
    ++++ b/packages/SettingsLib/res/values-pa-rIN/strings.xml
    +@@ -28,7 +28,8 @@
    +     <string name="wifi_disabled_wifi_failure" msgid="3081668066612876581">"WiFi ਕਨੈਕਸ਼ਨ ਅਸਫਲਤਾ"</string>
    +     <string name="wifi_disabled_password_failure" msgid="8659805351763133575">"ਪ੍ਰਮਾਣੀਕਰਨ ਸਮੱਸਿਆ"</string>
    +     <string name="wifi_not_in_range" msgid="1136191511238508967">"ਰੇਂਜ ਵਿੱਚ ਨਹੀਂ ਹੈ"</string>
    +-    <string name="wifi_no_internet" msgid="9151470775868728896">"ਕੋਈ ਇੰਟਰਨੈਟ ਪਹੁੰਚ ਨਹੀਂ ਮਿਲੀ, ਆਟੋਮੈਟਿਕਲੀ ਰੀਕਨੈਕਟ ਨਹੀਂ ਕੀਤਾ ਜਾਏਗਾ।"</string>
    ++    <string name="wifi_no_internet_no_reconnect" msgid="2211781637653149657">"ਕੋਈ ਇੰਟਰਨੈੱਟ ਪਹੁੰਚ ਨਹੀਂ ਮਿਲੀ, ਸਵੈਚਲਿਤ ਤੌਰ \'ਤੇ ਮੁੜ-ਕਨੈਕਟ ਨਹੀਂ ਕੀਤਾ ਜਾਵੇਗਾ।"</string>
    ++    <string name="wifi_no_internet" msgid="5011955173375805204">"ਕੋਈ ਇੰਟਰਨੈੱਟ ਪਹੁੰਚ ਨਹੀਂ।"</string>
    +     <string name="saved_network" msgid="4352716707126620811">"<xliff:g id="NAME">%1$s</xliff:g> ਵੱਲੋਂ ਸੁਰੱਖਿਅਤ ਕੀਤਾ"</string>
    +     <string name="connected_via_wfa" msgid="3805736726317410714">"Wi‑Fi ਸਹਾਇਕ ਰਾਹੀਂ ਕਨੈਕਟ ਕੀਤਾ"</string>
    +     <string name="connected_via_passpoint" msgid="2826205693803088747">"%1$s ਰਾਹੀਂ ਕਨੈਕਟ ਕੀਤਾ"</string>
    +@@ -233,8 +234,6 @@
    +     <string name="debug_layout_summary" msgid="2001775315258637682">"ਕਲਿਪ ਬਾਊਂਡਸ, ਮਾਰਜਿਨ ਆਦਿ ਦਿਖਾਓ"</string>
    +     <string name="force_rtl_layout_all_locales" msgid="2259906643093138978">"RTL ਲੇਆਉਟ ਦਿਸ਼ਾ ਤੇ ਜ਼ੋਰ ਪਾਓ"</string>
    +     <string name="force_rtl_layout_all_locales_summary" msgid="9192797796616132534">"ਸਾਰੇ ਸਥਾਨਾਂ ਲਈ RTL ਵੱਲ ਸਕ੍ਰੀਨ ਲੇਆਉਟ ਦਿਸ਼ਾ ਤੇ ਜ਼ੋਰ ਪਾਓ"</string>
    +-    <string name="show_cpu_usage" msgid="2389212910758076024">"CPU ਵਰਤੋਂ ਦਿਖਾਓ"</string>
    +-    <string name="show_cpu_usage_summary" msgid="2113341923988958266">"ਸਕ੍ਰੀਨ ਓਵਰਲੇ ਵਰਤਮਾਨ CPU ਵਰਤੋਂ ਦਿਖਾ ਰਿਹਾ ਹੈ"</string>
    +     <string name="force_hw_ui" msgid="6426383462520888732">"GPU ਪ੍ਰਗਟਾਅ ਤੇ ਜ਼ੋਰ ਪਾਓ"</string>
    +     <string name="force_hw_ui_summary" msgid="5535991166074861515">"2d ਡ੍ਰਾਇੰਗ ਲਈ GPU ਦੀ ਵਰਤੋਂ ਤੇ ਜ਼ੋਰ ਪਾਓ"</string>
    +     <string name="force_msaa" msgid="7920323238677284387">"4x MSAA ਤੇ ਜ਼ੋਰ ਪਾਓ"</string>
    +@@ -341,4 +340,5 @@
    +     <string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"ਸਭ ਤੋਂ ਵੱਡਾ"</string>
    +     <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"ਵਿਸ਼ੇਸ਼-ਵਿਉਂਤਬੱਧ (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
    +     <string name="help_feedback_label" msgid="6815040660801785649">"ਮਦਦ ਅਤੇ ਪ੍ਰਤੀਕਰਮ"</string>
    ++    <string name="content_description_menu_button" msgid="8182594799812351266">"ਮੀਨੂ"</string>
    + </resources>
    +diff --git a/packages/SettingsLib/res/values-pl/strings.xml b/packages/SettingsLib/res/values-pl/strings.xml
    +index d5116a2..bcdf812 100644
    +--- a/packages/SettingsLib/res/values-pl/strings.xml
    ++++ b/packages/SettingsLib/res/values-pl/strings.xml
    +@@ -28,7 +28,8 @@
    +     <string name="wifi_disabled_wifi_failure" msgid="3081668066612876581">"Błąd połączenia Wi-Fi"</string>
    +     <string name="wifi_disabled_password_failure" msgid="8659805351763133575">"Problem z uwierzytelnianiem"</string>
    +     <string name="wifi_not_in_range" msgid="1136191511238508967">"Poza zasięgiem"</string>
    +-    <string name="wifi_no_internet" msgid="9151470775868728896">"Nie wykryto dostępu do internetu. Nie można automatycznie przywrócić połączenia."</string>
    ++    <string name="wifi_no_internet_no_reconnect" msgid="2211781637653149657">"Nie wykryto dostępu do internetu. Nie można automatycznie przywrócić połączenia."</string>
    ++    <string name="wifi_no_internet" msgid="5011955173375805204">"Brak dostępu do internetu."</string>
    +     <string name="saved_network" msgid="4352716707126620811">"Zapisane przez: <xliff:g id="NAME">%1$s</xliff:g>"</string>
    +     <string name="connected_via_wfa" msgid="3805736726317410714">"Połączono przez Asystenta Wi‑Fi"</string>
    +     <string name="connected_via_passpoint" msgid="2826205693803088747">"Połączono przez %1$s"</string>
    +@@ -233,8 +234,6 @@
    +     <string name="debug_layout_summary" msgid="2001775315258637682">"Pokaż granice przycięcia, marginesy itd."</string>
    +     <string name="force_rtl_layout_all_locales" msgid="2259906643093138978">"Układ od prawej do lewej"</string>
    +     <string name="force_rtl_layout_all_locales_summary" msgid="9192797796616132534">"Wymuś wszędzie układ ekranu od prawej do lewej"</string>
    +-    <string name="show_cpu_usage" msgid="2389212910758076024">"Pokaż użycie procesora"</string>
    +-    <string name="show_cpu_usage_summary" msgid="2113341923988958266">"Nakładka na ekranie pokazująca użycie procesora"</string>
    +     <string name="force_hw_ui" msgid="6426383462520888732">"Renderowanie na GPU"</string>
    +     <string name="force_hw_ui_summary" msgid="5535991166074861515">"Wymuszaj użycie GPU do rysowania 2D"</string>
    +     <string name="force_msaa" msgid="7920323238677284387">"Wymuś 4x MSAA"</string>
    +@@ -341,4 +340,5 @@
    +     <string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"Największy"</string>
    +     <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Niestandardowe (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
    +     <string name="help_feedback_label" msgid="6815040660801785649">"Pomoc i opinie"</string>
    ++    <string name="content_description_menu_button" msgid="8182594799812351266">"Menu"</string>
    + </resources>
    +diff --git a/packages/SettingsLib/res/values-pt-rBR/strings.xml b/packages/SettingsLib/res/values-pt-rBR/strings.xml
    +index f0cfa23..ef4ec77 100644
    +--- a/packages/SettingsLib/res/values-pt-rBR/strings.xml
    ++++ b/packages/SettingsLib/res/values-pt-rBR/strings.xml
    +@@ -28,7 +28,8 @@
    +     <string name="wifi_disabled_wifi_failure" msgid="3081668066612876581">"Falha de conexão Wi-Fi"</string>
    +     <string name="wifi_disabled_password_failure" msgid="8659805351763133575">"Problema de autenticação"</string>
    +     <string name="wifi_not_in_range" msgid="1136191511238508967">"Fora do alcance"</string>
    +-    <string name="wifi_no_internet" msgid="9151470775868728896">"Nenhum acesso à Internet detectado. O dispositivo não conectará automaticamente."</string>
    ++    <string name="wifi_no_internet_no_reconnect" msgid="2211781637653149657">"Nenhum acesso à Internet foi detectado. O dispositivo não será reconectado automaticamente."</string>
    ++    <string name="wifi_no_internet" msgid="5011955173375805204">"Sem acesso à Internet."</string>
    +     <string name="saved_network" msgid="4352716707126620811">"Salvas por <xliff:g id="NAME">%1$s</xliff:g>"</string>
    +     <string name="connected_via_wfa" msgid="3805736726317410714">"Conectado via assistente de Wi‑Fi"</string>
    +     <string name="connected_via_passpoint" msgid="2826205693803088747">"Conectado via %1$s"</string>
    +@@ -233,8 +234,6 @@
    +     <string name="debug_layout_summary" msgid="2001775315258637682">"Mostrar limites de corte, margens, etc."</string>
    +     <string name="force_rtl_layout_all_locales" msgid="2259906643093138978">"Forçar dir. layout (RTL)"</string>
    +     <string name="force_rtl_layout_all_locales_summary" msgid="9192797796616132534">"Forçar direção do layout (RTL) p/ todas as local."</string>
    +-    <string name="show_cpu_usage" msgid="2389212910758076024">"Mostrar o uso da CPU"</string>
    +-    <string name="show_cpu_usage_summary" msgid="2113341923988958266">"Sobreposição de tela que mostra o uso da CPU atual"</string>
    +     <string name="force_hw_ui" msgid="6426383462520888732">"Forçar renderização GPU"</string>
    +     <string name="force_hw_ui_summary" msgid="5535991166074861515">"Forçar uso da GPU para desenho em 2D"</string>
    +     <string name="force_msaa" msgid="7920323238677284387">"Forçar 4x MSAA"</string>
    +@@ -341,4 +340,5 @@
    +     <string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"Maior"</string>
    +     <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Personalizada (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
    +     <string name="help_feedback_label" msgid="6815040660801785649">"Ajuda e feedback"</string>
    ++    <string name="content_description_menu_button" msgid="8182594799812351266">"Menu"</string>
    + </resources>
    +diff --git a/packages/SettingsLib/res/values-pt-rPT/strings.xml b/packages/SettingsLib/res/values-pt-rPT/strings.xml
    +index 40dfc74..b6e9b4f 100644
    +--- a/packages/SettingsLib/res/values-pt-rPT/strings.xml
    ++++ b/packages/SettingsLib/res/values-pt-rPT/strings.xml
    +@@ -28,7 +28,8 @@
    +     <string name="wifi_disabled_wifi_failure" msgid="3081668066612876581">"Falha de ligação Wi-Fi"</string>
    +     <string name="wifi_disabled_password_failure" msgid="8659805351763133575">"Problema de autenticação"</string>
    +     <string name="wifi_not_in_range" msgid="1136191511238508967">"Fora do alcance"</string>
    +-    <string name="wifi_no_internet" msgid="9151470775868728896">"Nenhum acesso à Internet detetado; não será efetuada uma nova ligação automaticamente."</string>
    ++    <string name="wifi_no_internet_no_reconnect" msgid="2211781637653149657">"Nenhum acesso à Internet detetado. Não será efetuada uma nova ligação automaticamente."</string>
    ++    <string name="wifi_no_internet" msgid="5011955173375805204">"Sem acesso à Internet."</string>
    +     <string name="saved_network" msgid="4352716707126620811">"Guardada por <xliff:g id="NAME">%1$s</xliff:g>"</string>
    +     <string name="connected_via_wfa" msgid="3805736726317410714">"Ligado através do Assistente de Wi‑Fi"</string>
    +     <string name="connected_via_passpoint" msgid="2826205693803088747">"Ligado através de %1$s"</string>
    +@@ -233,8 +234,6 @@
    +     <string name="debug_layout_summary" msgid="2001775315258637682">"Apresentar limites de clipes, margens, etc."</string>
    +     <string name="force_rtl_layout_all_locales" msgid="2259906643093138978">"Forçar dir. do esq. RTL"</string>
    +     <string name="force_rtl_layout_all_locales_summary" msgid="9192797796616132534">"Forçar dir. do esq. do ecrã p. RTL tds os locais"</string>
    +-    <string name="show_cpu_usage" msgid="2389212910758076024">"Mostrar utilização da CPU"</string>
    +-    <string name="show_cpu_usage_summary" msgid="2113341923988958266">"Sobrep. de ecrã que mostra a utiliz. atual da CPU"</string>
    +     <string name="force_hw_ui" msgid="6426383462520888732">"Forçar composição GPU"</string>
    +     <string name="force_hw_ui_summary" msgid="5535991166074861515">"Forçar a utilização de GPU para desenho 2D"</string>
    +     <string name="force_msaa" msgid="7920323238677284387">"Forçar 4x MSAA"</string>
    +@@ -341,4 +340,5 @@
    +     <string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"O maior"</string>
    +     <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Personalizado (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
    +     <string name="help_feedback_label" msgid="6815040660801785649">"Ajuda e comentários"</string>
    ++    <string name="content_description_menu_button" msgid="8182594799812351266">"Menu"</string>
    + </resources>
    +diff --git a/packages/SettingsLib/res/values-pt/strings.xml b/packages/SettingsLib/res/values-pt/strings.xml
    +index f0cfa23..ef4ec77 100644
    +--- a/packages/SettingsLib/res/values-pt/strings.xml
    ++++ b/packages/SettingsLib/res/values-pt/strings.xml
    +@@ -28,7 +28,8 @@
    +     <string name="wifi_disabled_wifi_failure" msgid="3081668066612876581">"Falha de conexão Wi-Fi"</string>
    +     <string name="wifi_disabled_password_failure" msgid="8659805351763133575">"Problema de autenticação"</string>
    +     <string name="wifi_not_in_range" msgid="1136191511238508967">"Fora do alcance"</string>
    +-    <string name="wifi_no_internet" msgid="9151470775868728896">"Nenhum acesso à Internet detectado. O dispositivo não conectará automaticamente."</string>
    ++    <string name="wifi_no_internet_no_reconnect" msgid="2211781637653149657">"Nenhum acesso à Internet foi detectado. O dispositivo não será reconectado automaticamente."</string>
    ++    <string name="wifi_no_internet" msgid="5011955173375805204">"Sem acesso à Internet."</string>
    +     <string name="saved_network" msgid="4352716707126620811">"Salvas por <xliff:g id="NAME">%1$s</xliff:g>"</string>
    +     <string name="connected_via_wfa" msgid="3805736726317410714">"Conectado via assistente de Wi‑Fi"</string>
    +     <string name="connected_via_passpoint" msgid="2826205693803088747">"Conectado via %1$s"</string>
    +@@ -233,8 +234,6 @@
    +     <string name="debug_layout_summary" msgid="2001775315258637682">"Mostrar limites de corte, margens, etc."</string>
    +     <string name="force_rtl_layout_all_locales" msgid="2259906643093138978">"Forçar dir. layout (RTL)"</string>
    +     <string name="force_rtl_layout_all_locales_summary" msgid="9192797796616132534">"Forçar direção do layout (RTL) p/ todas as local."</string>
    +-    <string name="show_cpu_usage" msgid="2389212910758076024">"Mostrar o uso da CPU"</string>
    +-    <string name="show_cpu_usage_summary" msgid="2113341923988958266">"Sobreposição de tela que mostra o uso da CPU atual"</string>
    +     <string name="force_hw_ui" msgid="6426383462520888732">"Forçar renderização GPU"</string>
    +     <string name="force_hw_ui_summary" msgid="5535991166074861515">"Forçar uso da GPU para desenho em 2D"</string>
    +     <string name="force_msaa" msgid="7920323238677284387">"Forçar 4x MSAA"</string>
    +@@ -341,4 +340,5 @@
    +     <string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"Maior"</string>
    +     <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Personalizada (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
    +     <string name="help_feedback_label" msgid="6815040660801785649">"Ajuda e feedback"</string>
    ++    <string name="content_description_menu_button" msgid="8182594799812351266">"Menu"</string>
    + </resources>
    +diff --git a/packages/SettingsLib/res/values-ro/strings.xml b/packages/SettingsLib/res/values-ro/strings.xml
    +index 6cc0f87..a5ee78a 100644
    +--- a/packages/SettingsLib/res/values-ro/strings.xml
    ++++ b/packages/SettingsLib/res/values-ro/strings.xml
    +@@ -28,7 +28,8 @@
    +     <string name="wifi_disabled_wifi_failure" msgid="3081668066612876581">"Eroare de conexiune Wi-Fi"</string>
    +     <string name="wifi_disabled_password_failure" msgid="8659805351763133575">"Problemă la autentificare"</string>
    +     <string name="wifi_not_in_range" msgid="1136191511238508967">"În afara ariei de acoperire"</string>
    +-    <string name="wifi_no_internet" msgid="9151470775868728896">"Nu s-a detectat acces la internet, nu se va efectua reconectarea automată."</string>
    ++    <string name="wifi_no_internet_no_reconnect" msgid="2211781637653149657">"Nu s-a detectat acces la internet, nu se va reconecta automat."</string>
    ++    <string name="wifi_no_internet" msgid="5011955173375805204">"Nu există acces la internet."</string>
    +     <string name="saved_network" msgid="4352716707126620811">"Salvată de <xliff:g id="NAME">%1$s</xliff:g>"</string>
    +     <string name="connected_via_wfa" msgid="3805736726317410714">"Conexiune realizată printr-un asistent Wi-Fi"</string>
    +     <string name="connected_via_passpoint" msgid="2826205693803088747">"Conectată prin %1$s"</string>
    +@@ -233,8 +234,6 @@
    +     <string name="debug_layout_summary" msgid="2001775315258637682">"Afișați limitele clipului, marginile etc."</string>
    +     <string name="force_rtl_layout_all_locales" msgid="2259906643093138978">"Direcție aspect dreapta - stânga"</string>
    +     <string name="force_rtl_layout_all_locales_summary" msgid="9192797796616132534">"Direcție obligatorie aspect ecran dreapta - stânga"</string>
    +-    <string name="show_cpu_usage" msgid="2389212910758076024">"Afișați utiliz. procesor"</string>
    +-    <string name="show_cpu_usage_summary" msgid="2113341923988958266">"Suprapunere care indică utilizare curentă procesor"</string>
    +     <string name="force_hw_ui" msgid="6426383462520888732">"Forțați redarea cu GPU"</string>
    +     <string name="force_hw_ui_summary" msgid="5535991166074861515">"Forțați utilizarea GPU pentru desen în 2D"</string>
    +     <string name="force_msaa" msgid="7920323238677284387">"Forțați MSAA 4x"</string>
    +@@ -341,4 +340,5 @@
    +     <string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"Cel mai mare"</string>
    +     <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Personalizat (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
    +     <string name="help_feedback_label" msgid="6815040660801785649">"Ajutor și feedback"</string>
    ++    <string name="content_description_menu_button" msgid="8182594799812351266">"Meniu"</string>
    + </resources>
    +diff --git a/packages/SettingsLib/res/values-ru/strings.xml b/packages/SettingsLib/res/values-ru/strings.xml
    +index ad4db89..b24a705 100644
    +--- a/packages/SettingsLib/res/values-ru/strings.xml
    ++++ b/packages/SettingsLib/res/values-ru/strings.xml
    +@@ -28,13 +28,14 @@
    +     <string name="wifi_disabled_wifi_failure" msgid="3081668066612876581">"Ошибка подключения Wi-Fi"</string>
    +     <string name="wifi_disabled_password_failure" msgid="8659805351763133575">"Ошибка аутентификации"</string>
    +     <string name="wifi_not_in_range" msgid="1136191511238508967">"Недоступна"</string>
    +-    <string name="wifi_no_internet" msgid="9151470775868728896">"Подключение к Интернету отсутствует и не будет восстановлено автоматически."</string>
    ++    <string name="wifi_no_internet_no_reconnect" msgid="2211781637653149657">"Отсутствует интернет-соединение. Повторное подключение к сети не будет выполняться автоматически."</string>
    ++    <string name="wifi_no_internet" msgid="5011955173375805204">"Отсутствует подключение к Интернету"</string>
    +     <string name="saved_network" msgid="4352716707126620811">"Кто сохранил: <xliff:g id="NAME">%1$s</xliff:g>"</string>
    +     <string name="connected_via_wfa" msgid="3805736726317410714">"Установлено подключение через Ассистента Wi-Fi"</string>
    +     <string name="connected_via_passpoint" msgid="2826205693803088747">"Подключено к %1$s"</string>
    +     <string name="available_via_passpoint" msgid="1617440946846329613">"Доступно через %1$s"</string>
    +     <string name="wifi_connected_no_internet" msgid="3149853966840874992">"Подключено, без Интернета"</string>
    +-    <string name="bluetooth_disconnected" msgid="6557104142667339895">"Отключено"</string>
    ++    <string name="bluetooth_disconnected" msgid="6557104142667339895">"Нет подключения"</string>
    +     <string name="bluetooth_disconnecting" msgid="8913264760027764974">"Отключение..."</string>
    +     <string name="bluetooth_connecting" msgid="8555009514614320497">"Подключение..."</string>
    +     <string name="bluetooth_connected" msgid="6038755206916626419">"Подключено"</string>
    +@@ -233,8 +234,6 @@
    +     <string name="debug_layout_summary" msgid="2001775315258637682">"Показывать границы клипа, поля и т. д."</string>
    +     <string name="force_rtl_layout_all_locales" msgid="2259906643093138978">"Написание справа налево"</string>
    +     <string name="force_rtl_layout_all_locales_summary" msgid="9192797796616132534">"Включить написание справа налево для всех языков"</string>
    +-    <string name="show_cpu_usage" msgid="2389212910758076024">"Показывать загрузку ЦП"</string>
    +-    <string name="show_cpu_usage_summary" msgid="2113341923988958266">"Экран, показывающий текущую загрузку ЦП"</string>
    +     <string name="force_hw_ui" msgid="6426383462520888732">"GPU-ускорение"</string>
    +     <string name="force_hw_ui_summary" msgid="5535991166074861515">"Всегда использовать GPU для двухмерного рисования"</string>
    +     <string name="force_msaa" msgid="7920323238677284387">"Включить 4x MSAA"</string>
    +@@ -246,7 +245,7 @@
    +     <string name="animator_duration_scale_title" msgid="3406722410819934083">"Длительность анимации"</string>
    +     <string name="overlay_display_devices_title" msgid="5364176287998398539">"Эмуляция доп. экранов"</string>
    +     <string name="debug_applications_category" msgid="4206913653849771549">"Приложения"</string>
    +-    <string name="immediately_destroy_activities" msgid="1579659389568133959">"Не сохранять действия"</string>
    ++    <string name="immediately_destroy_activities" msgid="1579659389568133959">"Не сохранять активности"</string>
    +     <string name="immediately_destroy_activities_summary" msgid="3592221124808773368">"Удалять сводку действий после их завершения"</string>
    +     <string name="app_process_limit_title" msgid="4280600650253107163">"Лимит фоновых процессов"</string>
    +     <string name="show_all_anrs" msgid="28462979638729082">"Все ANR"</string>
    +@@ -341,4 +340,5 @@
    +     <string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"Максимальный"</string>
    +     <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Другой (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
    +     <string name="help_feedback_label" msgid="6815040660801785649">"Справка/отзыв"</string>
    ++    <string name="content_description_menu_button" msgid="8182594799812351266">"Меню"</string>
    + </resources>
    +diff --git a/packages/SettingsLib/res/values-si-rLK/strings.xml b/packages/SettingsLib/res/values-si-rLK/strings.xml
    +index 5efb400..e3acfae 100644
    +--- a/packages/SettingsLib/res/values-si-rLK/strings.xml
    ++++ b/packages/SettingsLib/res/values-si-rLK/strings.xml
    +@@ -28,7 +28,8 @@
    +     <string name="wifi_disabled_wifi_failure" msgid="3081668066612876581">"WiFi සම්බන්ධතාව අසාර්ථකයි"</string>
    +     <string name="wifi_disabled_password_failure" msgid="8659805351763133575">"සත්‍යාපනයේ ගැටලුවකි"</string>
    +     <string name="wifi_not_in_range" msgid="1136191511238508967">"පරාසයේ නැත"</string>
    +-    <string name="wifi_no_internet" msgid="9151470775868728896">"අන්තර්ජාල ප්‍රවේශය අනාවරණය වුයේ නැත, ස්වයංක්‍රිය නැවත සම්බන්ධ වීම වූ නැත"</string>
    ++    <string name="wifi_no_internet_no_reconnect" msgid="2211781637653149657">"අන්තර්ජාල ප්‍රවේශය නැත, ස්වයංක්‍රිය නැවත සම්බන්ධ නොවනු ඇත."</string>
    ++    <string name="wifi_no_internet" msgid="5011955173375805204">"අන්තර්ජාල ප්‍රවේශය නැත."</string>
    +     <string name="saved_network" msgid="4352716707126620811">"<xliff:g id="NAME">%1$s</xliff:g> විසින් සුරකින ලදී"</string>
    +     <string name="connected_via_wfa" msgid="3805736726317410714">"Wi‑Fi සහායක හරහා සම්බන්ධ කරන ලදි"</string>
    +     <string name="connected_via_passpoint" msgid="2826205693803088747">"%1$s හරහා සම්බන්ධ විය"</string>
    +@@ -233,8 +234,6 @@
    +     <string name="debug_layout_summary" msgid="2001775315258637682">"ක්ලිප් සීමා, මායිම්, ආදිය පෙන්වන්න."</string>
    +     <string name="force_rtl_layout_all_locales" msgid="2259906643093138978">"බල RTL පිරිසැලසුම් දිශාව"</string>
    +     <string name="force_rtl_layout_all_locales_summary" msgid="9192797796616132534">"සියලු පෙදෙසි සඳහා RTL වෙත බල තිර පිරිසැලසුම"</string>
    +-    <string name="show_cpu_usage" msgid="2389212910758076024">"CPU භාවිතය පෙන්වන්න"</string>
    +-    <string name="show_cpu_usage_summary" msgid="2113341923988958266">"තීර උඩැතිරිය වත්මන් CPU භාවිතය පෙන්නුම් කරයි"</string>
    +     <string name="force_hw_ui" msgid="6426383462520888732">"GPU විදහාපෑම බලකරන්න"</string>
    +     <string name="force_hw_ui_summary" msgid="5535991166074861515">"2d ඇඳීම් සඳහා GPU බලයෙන් භාවිතා කරන්න"</string>
    +     <string name="force_msaa" msgid="7920323238677284387">"4x MSAA බල කරන්න"</string>
    +@@ -341,4 +340,5 @@
    +     <string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"විශාලතම"</string>
    +     <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"අභිරුචි (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
    +     <string name="help_feedback_label" msgid="6815040660801785649">"උදව් සහ ප්‍රතිපෝෂණ"</string>
    ++    <string name="content_description_menu_button" msgid="8182594799812351266">"මෙනුව"</string>
    + </resources>
    +diff --git a/packages/SettingsLib/res/values-sk/strings.xml b/packages/SettingsLib/res/values-sk/strings.xml
    +index 7a7e3d4..74a2b46 100644
    +--- a/packages/SettingsLib/res/values-sk/strings.xml
    ++++ b/packages/SettingsLib/res/values-sk/strings.xml
    +@@ -28,7 +28,8 @@
    +     <string name="wifi_disabled_wifi_failure" msgid="3081668066612876581">"Zlyhanie pripojenia Wi-Fi"</string>
    +     <string name="wifi_disabled_password_failure" msgid="8659805351763133575">"Problém s overením totožnosti"</string>
    +     <string name="wifi_not_in_range" msgid="1136191511238508967">"Mimo dosah"</string>
    +-    <string name="wifi_no_internet" msgid="9151470775868728896">"Nenašiel sa žiadny prístup k internetu, preto nedôjde k automatickému opätovnému pripojeniu"</string>
    ++    <string name="wifi_no_internet_no_reconnect" msgid="2211781637653149657">"Nenašiel sa žiadny prístup k internetu, preto nedôjde k automatickému opätovnému pripojeniu."</string>
    ++    <string name="wifi_no_internet" msgid="5011955173375805204">"Žiadny prístup k internetu."</string>
    +     <string name="saved_network" msgid="4352716707126620811">"Uložil(a) <xliff:g id="NAME">%1$s</xliff:g>"</string>
    +     <string name="connected_via_wfa" msgid="3805736726317410714">"Pripojené pomocou Asistenta Wi-Fi"</string>
    +     <string name="connected_via_passpoint" msgid="2826205693803088747">"Pripojené prostredníctvom %1$s"</string>
    +@@ -173,8 +174,8 @@
    +     <string name="wifi_verbose_logging_summary" msgid="6615071616111731958">"Zvýšiť úroveň denníkov Wi-Fi, zobrazovať podľa SSID RSSI pri výbere siete Wi-Fi"</string>
    +     <string name="wifi_aggressive_handover_summary" msgid="6328455667642570371">"Keď túto možnosť zapnete, Wi-Fi bude agresívnejšie odovzdávať dát. pripoj. na mob. sieť vtedy, keď bude slabý signál Wi-Fi"</string>
    +     <string name="wifi_allow_scan_with_traffic_summary" msgid="2575101424972686310">"Povoliť alebo zakázať funkciu Wifi Roam Scans na základe objemu prenosu údajov v rozhraní"</string>
    +-    <string name="select_logd_size_title" msgid="7433137108348553508">"Veľkosti vyrovnávacej pamäte denníka"</string>
    +-    <string name="select_logd_size_dialog_title" msgid="1206769310236476760">"Veľkosť na vyrovnávaciu pamäť nástroja denníkov"</string>
    ++    <string name="select_logd_size_title" msgid="7433137108348553508">"Vyrovnávacia pamäť nástroja denníkov"</string>
    ++    <string name="select_logd_size_dialog_title" msgid="1206769310236476760">"Veľkosť vyrovnávacej pamäte nástroja denníkov"</string>
    +     <string name="dev_logpersist_clear_warning_title" msgid="684806692440237967">"Vymazať trvalé úložisko zapisovača do denníka?"</string>
    +     <string name="dev_logpersist_clear_warning_message" msgid="2256582531342994562">"Keď prestaneme monitorovať pomocou trvalého zapisovača do denníka, musíme vymazať jeho dáta, ktoré sa nachádzajú vo vašom zariadení."</string>
    +     <string name="select_logpersist_title" msgid="7530031344550073166">"Natrvalo ukladať dáta zapisovača do denníka na zariadení"</string>
    +@@ -186,8 +187,8 @@
    +     <string name="debug_view_attributes" msgid="6485448367803310384">"Kontrola atribútov zobrazenia"</string>
    +     <string name="mobile_data_always_on_summary" msgid="8149773901431697910">"Vždy ponechávať mobilné dáta aktívne, dokonca aj pri aktívnej sieti Wi‑Fi (na rýchle prepínanie sietí)"</string>
    +     <string name="adb_warning_title" msgid="6234463310896563253">"Povoliť ladenie cez USB?"</string>
    +-    <string name="adb_warning_message" msgid="7316799925425402244">"Ladenie prostredníctvom USB je určené iba na účely vývoja. Použite ho na kopírovanie dát medzi počítačom a zariadením, inštaláciu aplikácií do zariadenia bez upozornenia a čítanie údajov denníka."</string>
    +-    <string name="adb_keys_warning_message" msgid="5659849457135841625">"Chcete odvolať prístup k ladeniu cez USB zo všetkých počítačov, ktoré ste predtým autorizovali?"</string>
    ++    <string name="adb_warning_message" msgid="7316799925425402244">"Ladenie cez USB je určené iba na účely vývoja. Možno ho použiť na kopírovanie dát medzi počítačom a zariadením, inštaláciu aplikácií do zariadenia bez upozornenia a čítanie dát denníka."</string>
    ++    <string name="adb_keys_warning_message" msgid="5659849457135841625">"Chcete všetkým v minulosti autorizovaným počítačom odvolať prístup k ladeniu cez USB?"</string>
    +     <string name="dev_settings_warning_title" msgid="7244607768088540165">"Povoliť nastavenia pre vývojárov?"</string>
    +     <string name="dev_settings_warning_message" msgid="2298337781139097964">"Tieto nastavenia sú určené len pre vývojárov. Môžu spôsobiť poruchu alebo nesprávne fungovanie zariadenia a nainštalovaných aplikácií."</string>
    +     <string name="verify_apps_over_usb_title" msgid="4177086489869041953">"Overovať aplikácie z USB"</string>
    +@@ -233,8 +234,6 @@
    +     <string name="debug_layout_summary" msgid="2001775315258637682">"Zobraziť vo výstrižku ohraničenie, okraje a pod."</string>
    +     <string name="force_rtl_layout_all_locales" msgid="2259906643093138978">"Rozloženia sprava doľava"</string>
    +     <string name="force_rtl_layout_all_locales_summary" msgid="9192797796616132534">"Vynútiť pre všetky jazyky rozloženie obrazovky sprava doľava"</string>
    +-    <string name="show_cpu_usage" msgid="2389212910758076024">"Zobraziť využitie CPU"</string>
    +-    <string name="show_cpu_usage_summary" msgid="2113341923988958266">"Prekryvná vrstva s aktuálnym využitím procesora"</string>
    +     <string name="force_hw_ui" msgid="6426383462520888732">"Vykresľovat pomocou GPU"</string>
    +     <string name="force_hw_ui_summary" msgid="5535991166074861515">"Používať GPU na dvojrozmerné vykresľovanie"</string>
    +     <string name="force_msaa" msgid="7920323238677284387">"Vynútiť 4x MSAA"</string>
    +@@ -341,4 +340,5 @@
    +     <string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"Najväčšie"</string>
    +     <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Vlastné (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
    +     <string name="help_feedback_label" msgid="6815040660801785649">"Pomocník a spätná väzba"</string>
    ++    <string name="content_description_menu_button" msgid="8182594799812351266">"Ponuka"</string>
    + </resources>
    +diff --git a/packages/SettingsLib/res/values-sl/strings.xml b/packages/SettingsLib/res/values-sl/strings.xml
    +index 10bff6e..788b97c 100644
    +--- a/packages/SettingsLib/res/values-sl/strings.xml
    ++++ b/packages/SettingsLib/res/values-sl/strings.xml
    +@@ -28,7 +28,8 @@
    +     <string name="wifi_disabled_wifi_failure" msgid="3081668066612876581">"Povezava prek Wi-Fi-ja ni uspela"</string>
    +     <string name="wifi_disabled_password_failure" msgid="8659805351763133575">"Težava s preverjanjem pristnosti"</string>
    +     <string name="wifi_not_in_range" msgid="1136191511238508967">"Ni v obsegu"</string>
    +-    <string name="wifi_no_internet" msgid="9151470775868728896">"Ni zaznanega dostopa do interneta; samodejna vnovična vzpostavitev povezave se ne bo izvedla."</string>
    ++    <string name="wifi_no_internet_no_reconnect" msgid="2211781637653149657">"Ni zaznanega dostopa do interneta; samodejna vnovična vzpostavitev povezave se ne bo izvedla."</string>
    ++    <string name="wifi_no_internet" msgid="5011955173375805204">"Ni dostopa do interneta."</string>
    +     <string name="saved_network" msgid="4352716707126620811">"Shranil(-a): <xliff:g id="NAME">%1$s</xliff:g>"</string>
    +     <string name="connected_via_wfa" msgid="3805736726317410714">"Povezava vzpostavljena prek pomočnika za Wi-Fi"</string>
    +     <string name="connected_via_passpoint" msgid="2826205693803088747">"Vzpostavljena povezava prek: %1$s"</string>
    +@@ -233,8 +234,6 @@
    +     <string name="debug_layout_summary" msgid="2001775315258637682">"Pokaži meje obrezovanja, obrobe ipd."</string>
    +     <string name="force_rtl_layout_all_locales" msgid="2259906643093138978">"Vsili od desne proti levi"</string>
    +     <string name="force_rtl_layout_all_locales_summary" msgid="9192797796616132534">"Vsili smer postavitve na zaslonu od desne proti levi za vse jezike"</string>
    +-    <string name="show_cpu_usage" msgid="2389212910758076024">"Prikaži uporabo CPE-ja"</string>
    +-    <string name="show_cpu_usage_summary" msgid="2113341923988958266">"Prekrivanje zaslona prikazuje tren. uporabo CPE-ja"</string>
    +     <string name="force_hw_ui" msgid="6426383462520888732">"Vsili upodabljanje z GPE-jem"</string>
    +     <string name="force_hw_ui_summary" msgid="5535991166074861515">"Za risanje 2D vsili uporabo grafičnega procesorja"</string>
    +     <string name="force_msaa" msgid="7920323238677284387">"Vsili 4x MSAA"</string>
    +@@ -341,4 +340,5 @@
    +     <string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"Največje"</string>
    +     <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Po meri (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
    +     <string name="help_feedback_label" msgid="6815040660801785649">"Pomoč in povratne informacije"</string>
    ++    <string name="content_description_menu_button" msgid="8182594799812351266">"Meni"</string>
    + </resources>
    +diff --git a/packages/SettingsLib/res/values-sq-rAL/strings.xml b/packages/SettingsLib/res/values-sq-rAL/strings.xml
    +index e4f0eaa..d6419dd 100644
    +--- a/packages/SettingsLib/res/values-sq-rAL/strings.xml
    ++++ b/packages/SettingsLib/res/values-sq-rAL/strings.xml
    +@@ -28,7 +28,8 @@
    +     <string name="wifi_disabled_wifi_failure" msgid="3081668066612876581">"Dështim i lidhjes WiFi"</string>
    +     <string name="wifi_disabled_password_failure" msgid="8659805351763133575">"Problem me vërtetimin"</string>
    +     <string name="wifi_not_in_range" msgid="1136191511238508967">"Nuk është brenda rrezes"</string>
    +-    <string name="wifi_no_internet" msgid="9151470775868728896">"Nuk u diktua qasje në internet. Lidhja nuk do të realizohet automatikisht."</string>
    ++    <string name="wifi_no_internet_no_reconnect" msgid="2211781637653149657">"Nuk u zbulua qasje në internet. Nuk do të lidhet përsëri automatikisht."</string>
    ++    <string name="wifi_no_internet" msgid="5011955173375805204">"Nuk ka qasje në internet."</string>
    +     <string name="saved_network" msgid="4352716707126620811">"E ruajtur nga <xliff:g id="NAME">%1$s</xliff:g>"</string>
    +     <string name="connected_via_wfa" msgid="3805736726317410714">"I lidhur nëpërmjet ndihmësit të Wi‑Fi"</string>
    +     <string name="connected_via_passpoint" msgid="2826205693803088747">"E lidhur përmes %1$s"</string>
    +@@ -233,8 +234,6 @@
    +     <string name="debug_layout_summary" msgid="2001775315258637682">"Shfaq konturet e klipit, hapësirat etj."</string>
    +     <string name="force_rtl_layout_all_locales" msgid="2259906643093138978">"Detyro drejtimin e shkrimit nga e djathta në të majtë"</string>
    +     <string name="force_rtl_layout_all_locales_summary" msgid="9192797796616132534">"Ndrysho me detyrim drejtimin e planit të ekranit nga e djathta në të majtë për të gjitha vendet"</string>
    +-    <string name="show_cpu_usage" msgid="2389212910758076024">"Shfaq përdorimin e CPU-së"</string>
    +-    <string name="show_cpu_usage_summary" msgid="2113341923988958266">"Mbivendosja e ekranit tregon përdorimin e CPU-së"</string>
    +     <string name="force_hw_ui" msgid="6426383462520888732">"Detyro interpretimin e GPU-së"</string>
    +     <string name="force_hw_ui_summary" msgid="5535991166074861515">"Detyro përdorimin e GPU-së për vizatimin e dytë"</string>
    +     <string name="force_msaa" msgid="7920323238677284387">"Detyro 4x MSAA"</string>
    +@@ -341,4 +340,5 @@
    +     <string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"Më i madhi"</string>
    +     <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"I personalizuar (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
    +     <string name="help_feedback_label" msgid="6815040660801785649">"Ndihma dhe komentet"</string>
    ++    <string name="content_description_menu_button" msgid="8182594799812351266">"Menyja"</string>
    + </resources>
    +diff --git a/packages/SettingsLib/res/values-sr/strings.xml b/packages/SettingsLib/res/values-sr/strings.xml
    +index fba58c5..f8b3b4b 100644
    +--- a/packages/SettingsLib/res/values-sr/strings.xml
    ++++ b/packages/SettingsLib/res/values-sr/strings.xml
    +@@ -28,7 +28,8 @@
    +     <string name="wifi_disabled_wifi_failure" msgid="3081668066612876581">"Wi-Fi веза је отказала"</string>
    +     <string name="wifi_disabled_password_failure" msgid="8659805351763133575">"Проблем са потврдом аутентичности"</string>
    +     <string name="wifi_not_in_range" msgid="1136191511238508967">"Није у опсегу"</string>
    +-    <string name="wifi_no_internet" msgid="9151470775868728896">"Приступ интернету није откривен, аутоматско повезивање није могуће."</string>
    ++    <string name="wifi_no_internet_no_reconnect" msgid="2211781637653149657">"Приступ интернету није откривен, аутоматско повезивање није могуће."</string>
    ++    <string name="wifi_no_internet" msgid="5011955173375805204">"Нема приступа интернету."</string>
    +     <string name="saved_network" msgid="4352716707126620811">"Сачувао/ла је <xliff:g id="NAME">%1$s</xliff:g>"</string>
    +     <string name="connected_via_wfa" msgid="3805736726317410714">"Повезано преко Wi‑Fi помоћника"</string>
    +     <string name="connected_via_passpoint" msgid="2826205693803088747">"Веза је успостављена преко приступне тачке %1$s"</string>
    +@@ -233,8 +234,6 @@
    +     <string name="debug_layout_summary" msgid="2001775315258637682">"Прикажи границе клипа, маргине итд."</string>
    +     <string name="force_rtl_layout_all_locales" msgid="2259906643093138978">"Наметни смер распореда здесна налево"</string>
    +     <string name="force_rtl_layout_all_locales_summary" msgid="9192797796616132534">"Наметни смер распореда екрана здесна налево за све локалитете"</string>
    +-    <string name="show_cpu_usage" msgid="2389212910758076024">"Прик. употребу процесора"</string>
    +-    <string name="show_cpu_usage_summary" msgid="2113341923988958266">"Постав. елемент са тренутном употребом процесора"</string>
    +     <string name="force_hw_ui" msgid="6426383462520888732">"Принудни приказ пом. GPU"</string>
    +     <string name="force_hw_ui_summary" msgid="5535991166074861515">"Принудно користи GPU за 2D цртање"</string>
    +     <string name="force_msaa" msgid="7920323238677284387">"Наметни 4x MSAA"</string>
    +@@ -282,7 +281,7 @@
    +     <string name="enable_webview_multiprocess_desc" msgid="2485604010404197724">"Покрећите WebView приказиваче засебно"</string>
    +     <string name="select_webview_provider_title" msgid="4628592979751918907">"Примена WebView-а"</string>
    +     <string name="select_webview_provider_dialog_title" msgid="4370551378720004872">"Подесите примену WebView-а"</string>
    +-    <string name="select_webview_provider_toast_text" msgid="5466970498308266359">"Овај избор више није важећи. Покушајте поново."</string>
    ++    <string name="select_webview_provider_toast_text" msgid="5466970498308266359">"Овај избор више није важећи. Пробајте поново."</string>
    +     <string name="convert_to_file_encryption" msgid="3060156730651061223">"Конвертуј у шифровање датотека"</string>
    +     <string name="convert_to_file_encryption_enabled" msgid="2861258671151428346">"Конвертуј..."</string>
    +     <string name="convert_to_file_encryption_done" msgid="7859766358000523953">"Већ се користи шифровање датотека"</string>
    +@@ -341,4 +340,5 @@
    +     <string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"Највећи"</string>
    +     <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Прилагођени (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
    +     <string name="help_feedback_label" msgid="6815040660801785649">"Помоћ и повратне информације"</string>
    ++    <string name="content_description_menu_button" msgid="8182594799812351266">"Мени"</string>
    + </resources>
    +diff --git a/packages/SettingsLib/res/values-sv/strings.xml b/packages/SettingsLib/res/values-sv/strings.xml
    +index ecc728a..389e03a 100644
    +--- a/packages/SettingsLib/res/values-sv/strings.xml
    ++++ b/packages/SettingsLib/res/values-sv/strings.xml
    +@@ -28,7 +28,8 @@
    +     <string name="wifi_disabled_wifi_failure" msgid="3081668066612876581">"Wi-Fi-anslutningsfel"</string>
    +     <string name="wifi_disabled_password_failure" msgid="8659805351763133575">"Autentiseringsproblem"</string>
    +     <string name="wifi_not_in_range" msgid="1136191511238508967">"Utom räckhåll"</string>
    +-    <string name="wifi_no_internet" msgid="9151470775868728896">"Ingen internetåtkomst hittades. Det går inte att återansluta automatiskt."</string>
    ++    <string name="wifi_no_internet_no_reconnect" msgid="2211781637653149657">"Ingen internetåtkomst hittades. Det går inte att återansluta automatiskt."</string>
    ++    <string name="wifi_no_internet" msgid="5011955173375805204">"Ingen internetåtkomst"</string>
    +     <string name="saved_network" msgid="4352716707126620811">"Sparades av <xliff:g id="NAME">%1$s</xliff:g>"</string>
    +     <string name="connected_via_wfa" msgid="3805736726317410714">"Ansluten via Wi-Fi-assistent"</string>
    +     <string name="connected_via_passpoint" msgid="2826205693803088747">"Anslutet via %1$s"</string>
    +@@ -233,8 +234,6 @@
    +     <string name="debug_layout_summary" msgid="2001775315258637682">"Visa gränser för videoklipp, marginaler m.m."</string>
    +     <string name="force_rtl_layout_all_locales" msgid="2259906643093138978">"Tvinga fram RTL-layout"</string>
    +     <string name="force_rtl_layout_all_locales_summary" msgid="9192797796616132534">"Tvinga fram RTL-skärmlayout (hö–vä) för alla språk"</string>
    +-    <string name="show_cpu_usage" msgid="2389212910758076024">"Visa CPU-användning"</string>
    +-    <string name="show_cpu_usage_summary" msgid="2113341923988958266">"Överlägg på skärmen med aktuell CPU-användning"</string>
    +     <string name="force_hw_ui" msgid="6426383462520888732">"Framtvinga GPU-rendering"</string>
    +     <string name="force_hw_ui_summary" msgid="5535991166074861515">"Tvingad användning av GPU för 2D-ritning"</string>
    +     <string name="force_msaa" msgid="7920323238677284387">"Force 4x MSAA"</string>
    +@@ -341,4 +340,5 @@
    +     <string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"Störst"</string>
    +     <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Anpassad (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
    +     <string name="help_feedback_label" msgid="6815040660801785649">"Hjälp och feedback"</string>
    ++    <string name="content_description_menu_button" msgid="8182594799812351266">"Meny"</string>
    + </resources>
    +diff --git a/packages/SettingsLib/res/values-sw/strings.xml b/packages/SettingsLib/res/values-sw/strings.xml
    +index 435a1bd..ff6687c 100644
    +--- a/packages/SettingsLib/res/values-sw/strings.xml
    ++++ b/packages/SettingsLib/res/values-sw/strings.xml
    +@@ -28,7 +28,8 @@
    +     <string name="wifi_disabled_wifi_failure" msgid="3081668066612876581">"Haikuweza Kuunganisha kwenye WiFi"</string>
    +     <string name="wifi_disabled_password_failure" msgid="8659805351763133575">"Tatizo la uthibitishaji"</string>
    +     <string name="wifi_not_in_range" msgid="1136191511238508967">"Haiko karibu"</string>
    +-    <string name="wifi_no_internet" msgid="9151470775868728896">"Hakuna Ufikiaji kwa Intaneti Uliogunduliwa, haitaweza kuunganisha kiotomatiki."</string>
    ++    <string name="wifi_no_internet_no_reconnect" msgid="2211781637653149657">"Haikupata Muunganisho wa Intaneti. Haitaweza kuunganisha tena kiotomatiki."</string>
    ++    <string name="wifi_no_internet" msgid="5011955173375805204">"Hakuna Muunganisho wa Intaneti."</string>
    +     <string name="saved_network" msgid="4352716707126620811">"Ilihifadhiwa na <xliff:g id="NAME">%1$s</xliff:g>"</string>
    +     <string name="connected_via_wfa" msgid="3805736726317410714">"Imeunganishwa kupitia Kisaidizi cha Wi-Fi"</string>
    +     <string name="connected_via_passpoint" msgid="2826205693803088747">"Imeunganishwa kupitia %1$s"</string>
    +@@ -233,8 +234,6 @@
    +     <string name="debug_layout_summary" msgid="2001775315258637682">"Onyesha mipaka ya picha, kingo, nk."</string>
    +     <string name="force_rtl_layout_all_locales" msgid="2259906643093138978">"Lazimisha uelekezaji wa muundo wa RTL"</string>
    +     <string name="force_rtl_layout_all_locales_summary" msgid="9192797796616132534">"Lazimisha uelekezaji wa muundo wa skrini kwa RTL kwa lugha zote"</string>
    +-    <string name="show_cpu_usage" msgid="2389212910758076024">"Onyesha matumizi ya CPU"</string>
    +-    <string name="show_cpu_usage_summary" msgid="2113341923988958266">"Kuegeshwa kwa skrini ikionyesha matumizi ya sasa ya CPU"</string>
    +     <string name="force_hw_ui" msgid="6426383462520888732">"Lazimisha kutungiliza  GPU"</string>
    +     <string name="force_hw_ui_summary" msgid="5535991166074861515">"Lazimisha matumizi ya GPU kwa uchoraji wa 2d"</string>
    +     <string name="force_msaa" msgid="7920323238677284387">"Lazimisha 4x MSAA"</string>
    +@@ -341,4 +340,5 @@
    +     <string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"Kubwa zaidi"</string>
    +     <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Kiwango maalum (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
    +     <string name="help_feedback_label" msgid="6815040660801785649">"Usaidizi na maoni"</string>
    ++    <string name="content_description_menu_button" msgid="8182594799812351266">"Menyu"</string>
    + </resources>
    +diff --git a/packages/SettingsLib/res/values-ta-rIN/strings.xml b/packages/SettingsLib/res/values-ta-rIN/strings.xml
    +index 033955c..86f58fc 100644
    +--- a/packages/SettingsLib/res/values-ta-rIN/strings.xml
    ++++ b/packages/SettingsLib/res/values-ta-rIN/strings.xml
    +@@ -28,7 +28,8 @@
    +     <string name="wifi_disabled_wifi_failure" msgid="3081668066612876581">"வைஃபை இணைப்பில் தோல்வி"</string>
    +     <string name="wifi_disabled_password_failure" msgid="8659805351763133575">"அங்கீகரிப்புச் சிக்கல்"</string>
    +     <string name="wifi_not_in_range" msgid="1136191511238508967">"தொடர்பு எல்லையில் இல்லை"</string>
    +-    <string name="wifi_no_internet" msgid="9151470775868728896">"இணைய அணுகல் இல்லை, மீண்டும் தானாக இணையாது."</string>
    ++    <string name="wifi_no_internet_no_reconnect" msgid="2211781637653149657">"இணைய அணுகல் இல்லை, மீண்டும் தானாக இணையாது."</string>
    ++    <string name="wifi_no_internet" msgid="5011955173375805204">"இணைய அணுகல் இல்லை."</string>
    +     <string name="saved_network" msgid="4352716707126620811">"<xliff:g id="NAME">%1$s</xliff:g> சேமித்தது"</string>
    +     <string name="connected_via_wfa" msgid="3805736726317410714">"வைஃபை அசிஸ்டண்ட் மூலம் இணைக்கப்பட்டது"</string>
    +     <string name="connected_via_passpoint" msgid="2826205693803088747">"%1$s வழியாக இணைக்கப்பட்டது"</string>
    +@@ -233,8 +234,6 @@
    +     <string name="debug_layout_summary" msgid="2001775315258637682">"கிளிப் எல்லைகள், ஓரங்கள், மேலும் பலவற்றைக் காட்டு"</string>
    +     <string name="force_rtl_layout_all_locales" msgid="2259906643093138978">"RTL தளவமைப்பின் திசையை வலியுறுத்து"</string>
    +     <string name="force_rtl_layout_all_locales_summary" msgid="9192797796616132534">"எல்லா மொழிகளுக்கும் திரையின் தளவமைப்பு திசையை RTL க்கு மாற்று"</string>
    +-    <string name="show_cpu_usage" msgid="2389212910758076024">"CPU பயன்பாட்டைக் காட்டு"</string>
    +-    <string name="show_cpu_usage_summary" msgid="2113341923988958266">"தற்போதைய CPU பயன்பாட்டைக் காட்டும் திரை மேலடுக்கு"</string>
    +     <string name="force_hw_ui" msgid="6426383462520888732">"GPU காட்சியாக்கத்தை வலியுறுத்து"</string>
    +     <string name="force_hw_ui_summary" msgid="5535991166074861515">"2d வரைபடத்திற்கு GPU பயன்பாட்டை வலியுறுத்து"</string>
    +     <string name="force_msaa" msgid="7920323238677284387">"4x MSAA ஐ வலியுறுத்து"</string>
    +@@ -341,4 +340,5 @@
    +     <string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"மிகப் பெரியது"</string>
    +     <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"தனிப்பயன் (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
    +     <string name="help_feedback_label" msgid="6815040660801785649">"உதவி &amp; கருத்து"</string>
    ++    <string name="content_description_menu_button" msgid="8182594799812351266">"மெனு"</string>
    + </resources>
    +diff --git a/packages/SettingsLib/res/values-te-rIN/strings.xml b/packages/SettingsLib/res/values-te-rIN/strings.xml
    +index 5758176..1326576 100644
    +--- a/packages/SettingsLib/res/values-te-rIN/strings.xml
    ++++ b/packages/SettingsLib/res/values-te-rIN/strings.xml
    +@@ -28,7 +28,8 @@
    +     <string name="wifi_disabled_wifi_failure" msgid="3081668066612876581">"WiFi కనెక్షన్ వైఫల్యం"</string>
    +     <string name="wifi_disabled_password_failure" msgid="8659805351763133575">"ప్రామాణీకరణ సమస్య"</string>
    +     <string name="wifi_not_in_range" msgid="1136191511238508967">"పరిధిలో లేదు"</string>
    +-    <string name="wifi_no_internet" msgid="9151470775868728896">"ఇంటర్నెట్ ప్రాప్యత కనుగొనబడలేదు, స్వయంచాలకంగా మళ్లీ కనెక్ట్ చేయబడదు."</string>
    ++    <string name="wifi_no_internet_no_reconnect" msgid="2211781637653149657">"ఇంటర్నెట్ ప్రాప్యత కనుగొనబడలేదు, స్వయంచాలకంగా మళ్లీ కనెక్ట్ చేయబడదు."</string>
    ++    <string name="wifi_no_internet" msgid="5011955173375805204">"ఇంటర్నెట్ ప్రాప్యత లేదు."</string>
    +     <string name="saved_network" msgid="4352716707126620811">"<xliff:g id="NAME">%1$s</xliff:g> ద్వారా సేవ్ చేయబడింది"</string>
    +     <string name="connected_via_wfa" msgid="3805736726317410714">"Wi‑Fi సహాయకం ద్వారా కనెక్ట్ చేయబడింది"</string>
    +     <string name="connected_via_passpoint" msgid="2826205693803088747">"%1$s ద్వారా కనెక్ట్ చేయబడింది"</string>
    +@@ -233,8 +234,6 @@
    +     <string name="debug_layout_summary" msgid="2001775315258637682">"క్లిప్ సరిహద్దులు, అంచులు మొ. చూపు"</string>
    +     <string name="force_rtl_layout_all_locales" msgid="2259906643093138978">"RTL లేఅవుట్ దిశను నిర్భందం చేయండి"</string>
    +     <string name="force_rtl_layout_all_locales_summary" msgid="9192797796616132534">"అన్ని లొకేల్‌ల కోసం RTLకి స్క్రీన్ లేఅవుట్ దిశను నిర్భందించు"</string>
    +-    <string name="show_cpu_usage" msgid="2389212910758076024">"CPU వినియోగాన్ని చూపు"</string>
    +-    <string name="show_cpu_usage_summary" msgid="2113341923988958266">"ప్రస్తుత CPU వినియోగాన్ని చూపేలా స్క్రీన్ అతివ్యాప్తి చేయబడుతుంది"</string>
    +     <string name="force_hw_ui" msgid="6426383462520888732">"నిర్బంధంగా GPU భాషాంతరీకరణ"</string>
    +     <string name="force_hw_ui_summary" msgid="5535991166074861515">"2d డ్రాయింగ్ కోసం GPU నిర్భంద వినియోగం"</string>
    +     <string name="force_msaa" msgid="7920323238677284387">"నిర్భందం 4x MSAA"</string>
    +@@ -341,4 +340,5 @@
    +     <string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"అతి పెద్దగా"</string>
    +     <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"అనుకూలం (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
    +     <string name="help_feedback_label" msgid="6815040660801785649">"సహాయం &amp; అభిప్రాయం"</string>
    ++    <string name="content_description_menu_button" msgid="8182594799812351266">"మెను"</string>
    + </resources>
    +diff --git a/packages/SettingsLib/res/values-th/strings.xml b/packages/SettingsLib/res/values-th/strings.xml
    +index 4849e19..5d302d0 100644
    +--- a/packages/SettingsLib/res/values-th/strings.xml
    ++++ b/packages/SettingsLib/res/values-th/strings.xml
    +@@ -28,7 +28,8 @@
    +     <string name="wifi_disabled_wifi_failure" msgid="3081668066612876581">"การเชื่อมต่อ Wi-Fi ล้มเหลว"</string>
    +     <string name="wifi_disabled_password_failure" msgid="8659805351763133575">"ปัญหาในการตรวจสอบสิทธิ์"</string>
    +     <string name="wifi_not_in_range" msgid="1136191511238508967">"ไม่อยู่ในพื้นที่ให้บริการ"</string>
    +-    <string name="wifi_no_internet" msgid="9151470775868728896">"ไม่พบการเข้าถึงอินเทอร์เน็ต ระบบจะไม่เชื่อมต่อใหม่โดยอัตโนมัติ"</string>
    ++    <string name="wifi_no_internet_no_reconnect" msgid="2211781637653149657">"ไม่พบการเข้าถึงอินเทอร์เน็ต ระบบจะไม่เชื่อมต่อใหม่โดยอัตโนมัติ"</string>
    ++    <string name="wifi_no_internet" msgid="5011955173375805204">"ไม่สามารถเข้าถึงอินเทอร์เน็ต"</string>
    +     <string name="saved_network" msgid="4352716707126620811">"บันทึกโดย <xliff:g id="NAME">%1$s</xliff:g> แล้ว"</string>
    +     <string name="connected_via_wfa" msgid="3805736726317410714">"เชื่อมต่อผ่านตัวช่วย Wi-Fi อยู่"</string>
    +     <string name="connected_via_passpoint" msgid="2826205693803088747">"เชื่อมต่อผ่าน %1$s แล้ว"</string>
    +@@ -233,8 +234,6 @@
    +     <string name="debug_layout_summary" msgid="2001775315258637682">"แสดงหน้าปกคลิป ขอบ ฯลฯ"</string>
    +     <string name="force_rtl_layout_all_locales" msgid="2259906643093138978">"บังคับทิศทางการจัดวาง RTL"</string>
    +     <string name="force_rtl_layout_all_locales_summary" msgid="9192797796616132534">"บังคับทิศทางการจัดวางหน้าจอเป็น RTL สำหรับทุกภาษา"</string>
    +-    <string name="show_cpu_usage" msgid="2389212910758076024">"แสดงการใช้ CPU"</string>
    +-    <string name="show_cpu_usage_summary" msgid="2113341923988958266">"การวางซ้อนหน้าจอที่แสดงการใช้ CPU ในปัจจุบัน"</string>
    +     <string name="force_hw_ui" msgid="6426383462520888732">"เร่งการแสดงผลของ GPU"</string>
    +     <string name="force_hw_ui_summary" msgid="5535991166074861515">"ต้องใช้ GPU สำหรับการวาดภาพ 2 มิติ"</string>
    +     <string name="force_msaa" msgid="7920323238677284387">"บังคับใช้ 4x MSAA"</string>
    +@@ -341,4 +340,5 @@
    +     <string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"ใหญ่ที่สุด"</string>
    +     <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"กำหนดเอง (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
    +     <string name="help_feedback_label" msgid="6815040660801785649">"ความช่วยเหลือและความคิดเห็น"</string>
    ++    <string name="content_description_menu_button" msgid="8182594799812351266">"เมนู"</string>
    + </resources>
    +diff --git a/packages/SettingsLib/res/values-tl/strings.xml b/packages/SettingsLib/res/values-tl/strings.xml
    +index 24f5499..c2232ee 100644
    +--- a/packages/SettingsLib/res/values-tl/strings.xml
    ++++ b/packages/SettingsLib/res/values-tl/strings.xml
    +@@ -28,7 +28,8 @@
    +     <string name="wifi_disabled_wifi_failure" msgid="3081668066612876581">"Pagkabigo ng Koneksyon sa WiFi"</string>
    +     <string name="wifi_disabled_password_failure" msgid="8659805351763133575">"Problema sa pagpapatotoo"</string>
    +     <string name="wifi_not_in_range" msgid="1136191511238508967">"Wala sa sakop"</string>
    +-    <string name="wifi_no_internet" msgid="9151470775868728896">"Walang Natukoy na Access sa Internet, hindi awtomatikong muling kumonekta."</string>
    ++    <string name="wifi_no_internet_no_reconnect" msgid="2211781637653149657">"Walang Na-detect na Access sa Internet, hindi awtomatikong muling kokonekta."</string>
    ++    <string name="wifi_no_internet" msgid="5011955173375805204">"Walang Access sa Internet."</string>
    +     <string name="saved_network" msgid="4352716707126620811">"Na-save ni <xliff:g id="NAME">%1$s</xliff:g>"</string>
    +     <string name="connected_via_wfa" msgid="3805736726317410714">"Nakakonekta sa pamamagitan ng Wi‑Fi assistant"</string>
    +     <string name="connected_via_passpoint" msgid="2826205693803088747">"Nakakonekta sa pamamagitan ng %1$s"</string>
    +@@ -146,7 +147,7 @@
    +     <string name="vpn_settings_not_available" msgid="956841430176985598">"Hindi available ang mga setting ng VPN para sa user na ito"</string>
    +     <string name="tethering_settings_not_available" msgid="6765770438438291012">"Hindi available ang mga setting ng pagte-theter para sa user na ito"</string>
    +     <string name="apn_settings_not_available" msgid="7873729032165324000">"Hindi available ang mga setting ng Access Point Name para sa user na ito"</string>
    +-    <string name="enable_adb" msgid="7982306934419797485">"Pagde-debug ng USB"</string>
    ++    <string name="enable_adb" msgid="7982306934419797485">"Pag-debug ng USB"</string>
    +     <string name="enable_adb_summary" msgid="4881186971746056635">"Debug mode kapag nakakonekta ang USB"</string>
    +     <string name="clear_adb_keys" msgid="4038889221503122743">"Bawiin ang mga pahintulot sa pag-debug ng USB"</string>
    +     <string name="bugreport_in_power" msgid="7923901846375587241">"Shortcut ng ulat sa bug"</string>
    +@@ -186,8 +187,8 @@
    +     <string name="debug_view_attributes" msgid="6485448367803310384">"I-enable ang pagsisiyasat sa attribute na view"</string>
    +     <string name="mobile_data_always_on_summary" msgid="8149773901431697910">"Palaging panatilihing aktibo ang mobile data, kahit na aktibo ang Wi‑Fi (para sa mabilis na paglipat ng network)."</string>
    +     <string name="adb_warning_title" msgid="6234463310896563253">"Payagan ang pag-debug ng USB?"</string>
    +-    <string name="adb_warning_message" msgid="7316799925425402244">"Ang pag-debug ng USB ay nilalayon para sa mga layuning pagpapabuti lamang. Gamitin ito upang kumopya ng data sa pagitan ng iyong computer at iyong device, mag-install ng apps sa iyong device nang walang notification, at magbasa ng data ng log."</string>
    +-    <string name="adb_keys_warning_message" msgid="5659849457135841625">"Bawiin ang access sa pagde-debug ng USB mula sa lahat ng computer na dati mong pinahintulutan?"</string>
    ++    <string name="adb_warning_message" msgid="7316799925425402244">"Ang pag-debug ng USB ay para lang sa mga layuning pag-develop. Gamitin ito upang kumopya ng data sa pagitan ng iyong computer at iyong device, mag-install ng mga app sa iyong device nang walang notification, at magbasa ng data ng log."</string>
    ++    <string name="adb_keys_warning_message" msgid="5659849457135841625">"Bawiin ang access sa pag-debug ng USB mula sa lahat ng computer na dati mong pinahintulutan?"</string>
    +     <string name="dev_settings_warning_title" msgid="7244607768088540165">"Payagan ang mga setting ng pag-develop?"</string>
    +     <string name="dev_settings_warning_message" msgid="2298337781139097964">"Nilalayon ang mga setting na ito para sa paggamit sa pag-develop lamang. Maaaring magsanhi ang mga ito ng pagkasira o hindi paggana nang maayos ng iyong device at mga application na nandito."</string>
    +     <string name="verify_apps_over_usb_title" msgid="4177086489869041953">"I-verify ang mga app sa USB"</string>
    +@@ -233,8 +234,6 @@
    +     <string name="debug_layout_summary" msgid="2001775315258637682">"Ipakita ang mga hangganan ng clip, margin, atbp."</string>
    +     <string name="force_rtl_layout_all_locales" msgid="2259906643093138978">"Force RTL layout dir."</string>
    +     <string name="force_rtl_layout_all_locales_summary" msgid="9192797796616132534">"Force screen layout dir. sa RTL sa lahat ng lokal"</string>
    +-    <string name="show_cpu_usage" msgid="2389212910758076024">"Ipakita paggamit ng CPU"</string>
    +-    <string name="show_cpu_usage_summary" msgid="2113341923988958266">"Ipinapakita ng screen overlay ang paggamit ng CPU ngayon"</string>
    +     <string name="force_hw_ui" msgid="6426383462520888732">"Ipilit ang pag-render ng GPU"</string>
    +     <string name="force_hw_ui_summary" msgid="5535991166074861515">"Sapilitang paggamit sa GPU para sa 2d na pagguhit"</string>
    +     <string name="force_msaa" msgid="7920323238677284387">"Puwersahin ang 4x MSAA"</string>
    +@@ -341,4 +340,5 @@
    +     <string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"Pinakamalaki"</string>
    +     <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Custom (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
    +     <string name="help_feedback_label" msgid="6815040660801785649">"Tulong at feedback"</string>
    ++    <string name="content_description_menu_button" msgid="8182594799812351266">"Menu"</string>
    + </resources>
    +diff --git a/packages/SettingsLib/res/values-tr/strings.xml b/packages/SettingsLib/res/values-tr/strings.xml
    +index 950e322..2541a3f 100644
    +--- a/packages/SettingsLib/res/values-tr/strings.xml
    ++++ b/packages/SettingsLib/res/values-tr/strings.xml
    +@@ -28,7 +28,8 @@
    +     <string name="wifi_disabled_wifi_failure" msgid="3081668066612876581">"Kablosuz Bağlantı Hatası"</string>
    +     <string name="wifi_disabled_password_failure" msgid="8659805351763133575">"Kimlik doğrulama sorunu"</string>
    +     <string name="wifi_not_in_range" msgid="1136191511238508967">"Kapsama alanı dışında"</string>
    +-    <string name="wifi_no_internet" msgid="9151470775868728896">"İnternet Erişimi algılanmadı, otomatik olarak tekrar bağlanmayacak."</string>
    ++    <string name="wifi_no_internet_no_reconnect" msgid="2211781637653149657">"İnternet Erişimi Algılanmadı, otomatik olarak tekrar bağlanmayacak."</string>
    ++    <string name="wifi_no_internet" msgid="5011955173375805204">"İnternet Erişimi Yok."</string>
    +     <string name="saved_network" msgid="4352716707126620811">"<xliff:g id="NAME">%1$s</xliff:g> tarafından kaydedildi"</string>
    +     <string name="connected_via_wfa" msgid="3805736726317410714">"Kablosuz bağlantı yardımcısıyla bağlandı"</string>
    +     <string name="connected_via_passpoint" msgid="2826205693803088747">"%1$s üzerinden bağlı"</string>
    +@@ -233,8 +234,6 @@
    +     <string name="debug_layout_summary" msgid="2001775315258637682">"Klip sınırlarını, kenar boşluklarını vb. göster"</string>
    +     <string name="force_rtl_layout_all_locales" msgid="2259906643093138978">"Sağdan sola düzenini zorla"</string>
    +     <string name="force_rtl_layout_all_locales_summary" msgid="9192797796616132534">"Tüm yerel ayarlar için sağdan sola ekran düzenini zorlar"</string>
    +-    <string name="show_cpu_usage" msgid="2389212910758076024">"CPU kullanımını göster"</string>
    +-    <string name="show_cpu_usage_summary" msgid="2113341923988958266">"Mevcut CPU kullanımını gösteren yer paylaşımı"</string>
    +     <string name="force_hw_ui" msgid="6426383462520888732">"GPU oluşturmayı zorla"</string>
    +     <string name="force_hw_ui_summary" msgid="5535991166074861515">"2D çizimde GPU kullanımını zorla"</string>
    +     <string name="force_msaa" msgid="7920323238677284387">"4x MSAA\'yı zorla"</string>
    +@@ -341,4 +340,5 @@
    +     <string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"En büyük"</string>
    +     <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Özel (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
    +     <string name="help_feedback_label" msgid="6815040660801785649">"Yardım ve geri bildirim"</string>
    ++    <string name="content_description_menu_button" msgid="8182594799812351266">"Menü"</string>
    + </resources>
    +diff --git a/packages/SettingsLib/res/values-uk/strings.xml b/packages/SettingsLib/res/values-uk/strings.xml
    +index 6b49b14..1829677 100644
    +--- a/packages/SettingsLib/res/values-uk/strings.xml
    ++++ b/packages/SettingsLib/res/values-uk/strings.xml
    +@@ -28,7 +28,8 @@
    +     <string name="wifi_disabled_wifi_failure" msgid="3081668066612876581">"Помилка з’єднання Wi-Fi"</string>
    +     <string name="wifi_disabled_password_failure" msgid="8659805351763133575">"Проблема з автентифікацією"</string>
    +     <string name="wifi_not_in_range" msgid="1136191511238508967">"Не в діапазоні"</string>
    +-    <string name="wifi_no_internet" msgid="9151470775868728896">"Немає доступу до Інтернету. Спроба під’єднання не здійснюватиметься автоматично."</string>
    ++    <string name="wifi_no_internet_no_reconnect" msgid="2211781637653149657">"Немає доступу до Інтернету. Спроба під’єднання не здійснюватиметься автоматично."</string>
    ++    <string name="wifi_no_internet" msgid="5011955173375805204">"Немає доступу до Інтернету."</string>
    +     <string name="saved_network" msgid="4352716707126620811">"Збережено додатком <xliff:g id="NAME">%1$s</xliff:g>"</string>
    +     <string name="connected_via_wfa" msgid="3805736726317410714">"Під’єднано через Диспетчер Wi-Fi-з’єднання"</string>
    +     <string name="connected_via_passpoint" msgid="2826205693803088747">"Під’єднано через %1$s"</string>
    +@@ -233,8 +234,6 @@
    +     <string name="debug_layout_summary" msgid="2001775315258637682">"Показувати межі роликів, поля тощо"</string>
    +     <string name="force_rtl_layout_all_locales" msgid="2259906643093138978">"Макет письма справа наліво"</string>
    +     <string name="force_rtl_layout_all_locales_summary" msgid="9192797796616132534">"Застосовувати макет письма справа наліво для всіх мов"</string>
    +-    <string name="show_cpu_usage" msgid="2389212910758076024">"Показати використання ЦП"</string>
    +-    <string name="show_cpu_usage_summary" msgid="2113341923988958266">"Показувати на екрані поточне використання ЦП"</string>
    +     <string name="force_hw_ui" msgid="6426383462520888732">"Примусова візуалізація GPU"</string>
    +     <string name="force_hw_ui_summary" msgid="5535991166074861515">"Примусово використовувати GPU для 2D-малювання"</string>
    +     <string name="force_msaa" msgid="7920323238677284387">"Примус. запустити 4x MSAA"</string>
    +@@ -341,4 +340,5 @@
    +     <string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"Найбільші елементи"</string>
    +     <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Спеціальний масштаб (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
    +     <string name="help_feedback_label" msgid="6815040660801785649">"Довідка й відгуки"</string>
    ++    <string name="content_description_menu_button" msgid="8182594799812351266">"Меню"</string>
    + </resources>
    +diff --git a/packages/SettingsLib/res/values-ur-rPK/strings.xml b/packages/SettingsLib/res/values-ur-rPK/strings.xml
    +index 2ac8a61..8bcf20b 100644
    +--- a/packages/SettingsLib/res/values-ur-rPK/strings.xml
    ++++ b/packages/SettingsLib/res/values-ur-rPK/strings.xml
    +@@ -28,7 +28,8 @@
    +     <string name="wifi_disabled_wifi_failure" msgid="3081668066612876581">"‏WiFi کنکشن کی ناکامی"</string>
    +     <string name="wifi_disabled_password_failure" msgid="8659805351763133575">"توثیق کا مسئلہ"</string>
    +     <string name="wifi_not_in_range" msgid="1136191511238508967">"رینج میں نہیں ہے"</string>
    +-    <string name="wifi_no_internet" msgid="9151470775868728896">"انٹرنیٹ تک کسی رسائی کا پتہ نہیں چلا، خود بخود دوبارہ منسلک نہیں ہوگا۔"</string>
    ++    <string name="wifi_no_internet_no_reconnect" msgid="2211781637653149657">"انٹرنیٹ تک کسی رسائی کا پتہ نہیں چلا، خودکار طور پر دوبارہ منسلک نہیں ہوگا۔"</string>
    ++    <string name="wifi_no_internet" msgid="5011955173375805204">"انٹرنیٹ تک کوئی رسائی نہیں۔"</string>
    +     <string name="saved_network" msgid="4352716707126620811">"<xliff:g id="NAME">%1$s</xliff:g> کی جانب سے محفوظ کردہ"</string>
    +     <string name="connected_via_wfa" msgid="3805736726317410714">"‏Wi‑Fi اسسٹنٹ کے ذریعے منسلک ہے"</string>
    +     <string name="connected_via_passpoint" msgid="2826205693803088747">"‏منسلک بذریعہ ‎%1$s"</string>
    +@@ -233,8 +234,6 @@
    +     <string name="debug_layout_summary" msgid="2001775315258637682">"کلپ باؤنڈز، حاشیے وغیرہ دکھائیں"</string>
    +     <string name="force_rtl_layout_all_locales" msgid="2259906643093138978">"‏RTL لے آؤٹ سمت زبردستی نافذ کریں"</string>
    +     <string name="force_rtl_layout_all_locales_summary" msgid="9192797796616132534">"‏سبھی زبانوں کیلئے اسکرین لے آؤٹ کی سمت کو RTL پر مجبور کریں"</string>
    +-    <string name="show_cpu_usage" msgid="2389212910758076024">"‏CPU استعمال دکھائیں"</string>
    +-    <string name="show_cpu_usage_summary" msgid="2113341923988958266">"‏موجودہ CPU استعمال دکھانے والا اسکرین اوورلے"</string>
    +     <string name="force_hw_ui" msgid="6426383462520888732">"‏GPU رینڈرنگ زبردستی نافذ کریں"</string>
    +     <string name="force_hw_ui_summary" msgid="5535991166074861515">"‏2D ڈرائنگ کیلئے GPU کا استعمال زبردستی نافذ کریں"</string>
    +     <string name="force_msaa" msgid="7920323238677284387">"‏4x MSAA زبردستی نافذ کریں"</string>
    +@@ -341,4 +340,5 @@
    +     <string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"سب سے بڑا"</string>
    +     <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"حسب ضرورت (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
    +     <string name="help_feedback_label" msgid="6815040660801785649">"مدد اور تاثرات"</string>
    ++    <string name="content_description_menu_button" msgid="8182594799812351266">"مینو"</string>
    + </resources>
    +diff --git a/packages/SettingsLib/res/values-uz-rUZ/strings.xml b/packages/SettingsLib/res/values-uz-rUZ/strings.xml
    +index 9022ad3..a0c72a0 100644
    +--- a/packages/SettingsLib/res/values-uz-rUZ/strings.xml
    ++++ b/packages/SettingsLib/res/values-uz-rUZ/strings.xml
    +@@ -28,7 +28,8 @@
    +     <string name="wifi_disabled_wifi_failure" msgid="3081668066612876581">"Wi-Fi ulanishini o‘rnatib bo‘lmadi"</string>
    +     <string name="wifi_disabled_password_failure" msgid="8659805351763133575">"Tasdiqdan o‘tishda muammo"</string>
    +     <string name="wifi_not_in_range" msgid="1136191511238508967">"Aloqada emas"</string>
    +-    <string name="wifi_no_internet" msgid="9151470775868728896">"Internetga ulanish aniqlanmadi, avtomatik ravishda qayta ulana olmaydi."</string>
    ++    <string name="wifi_no_internet_no_reconnect" msgid="2211781637653149657">"Internetga ulanish aniqlanmadi, avtomatik ravishda qayta ulana olmaydi."</string>
    ++    <string name="wifi_no_internet" msgid="5011955173375805204">"Internet aloqasi yo‘q."</string>
    +     <string name="saved_network" msgid="4352716707126620811">"<xliff:g id="NAME">%1$s</xliff:g> tomonidan saqlangan"</string>
    +     <string name="connected_via_wfa" msgid="3805736726317410714">"Wi‑Fi yordamchisi orqali ulangan"</string>
    +     <string name="connected_via_passpoint" msgid="2826205693803088747">"%1$s orqali ulangan"</string>
    +@@ -233,8 +234,6 @@
    +     <string name="debug_layout_summary" msgid="2001775315258637682">"Klip, maydon va h.k. chegaralarini ko‘rsatish"</string>
    +     <string name="force_rtl_layout_all_locales" msgid="2259906643093138978">"O‘ngdan chapga qarab yozish"</string>
    +     <string name="force_rtl_layout_all_locales_summary" msgid="9192797796616132534">"Barcha tillarda o‘ngdan chapga qarab yozish"</string>
    +-    <string name="show_cpu_usage" msgid="2389212910758076024">"MP yuklanishini ko‘rsatish"</string>
    +-    <string name="show_cpu_usage_summary" msgid="2113341923988958266">"Joriy MP yuklanishini ko‘rsatuvchi ekran"</string>
    +     <string name="force_hw_ui" msgid="6426383462520888732">"GPU yordamida tezlatish"</string>
    +     <string name="force_hw_ui_summary" msgid="5535991166074861515">"Ikki o‘lchamli chizma uchun doim GPU ishlatilsin"</string>
    +     <string name="force_msaa" msgid="7920323238677284387">"4x MSAAni yoqish"</string>
    +@@ -341,4 +340,5 @@
    +     <string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"Eng katta"</string>
    +     <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Moslashtirilgan (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
    +     <string name="help_feedback_label" msgid="6815040660801785649">"Yordam va fikr-mulohaza"</string>
    ++    <string name="content_description_menu_button" msgid="8182594799812351266">"Menyu"</string>
    + </resources>
    +diff --git a/packages/SettingsLib/res/values-vi/strings.xml b/packages/SettingsLib/res/values-vi/strings.xml
    +index c58f849..b991177 100644
    +--- a/packages/SettingsLib/res/values-vi/strings.xml
    ++++ b/packages/SettingsLib/res/values-vi/strings.xml
    +@@ -28,7 +28,8 @@
    +     <string name="wifi_disabled_wifi_failure" msgid="3081668066612876581">"Lỗi kết nối WiFi"</string>
    +     <string name="wifi_disabled_password_failure" msgid="8659805351763133575">"Sự cố xác thực"</string>
    +     <string name="wifi_not_in_range" msgid="1136191511238508967">"Ngoài vùng phủ sóng"</string>
    +-    <string name="wifi_no_internet" msgid="9151470775868728896">"Không phát hiện thấy truy cập Internet nào, mạng sẽ không được tự động kết nối lại."</string>
    ++    <string name="wifi_no_internet_no_reconnect" msgid="2211781637653149657">"Không phát hiện thấy kết nối Internet, mạng sẽ không tự động kết nối lại."</string>
    ++    <string name="wifi_no_internet" msgid="5011955173375805204">"Không có kết nối Internet."</string>
    +     <string name="saved_network" msgid="4352716707126620811">"Được lưu bởi <xliff:g id="NAME">%1$s</xliff:g>"</string>
    +     <string name="connected_via_wfa" msgid="3805736726317410714">"Được kết nối qua trình hỗ trợ Wi‑Fi"</string>
    +     <string name="connected_via_passpoint" msgid="2826205693803088747">"Được kết nối qua %1$s"</string>
    +@@ -233,8 +234,6 @@
    +     <string name="debug_layout_summary" msgid="2001775315258637682">"Hiển thị viền đoạn video, lề, v.v.."</string>
    +     <string name="force_rtl_layout_all_locales" msgid="2259906643093138978">"Buộc hướng bố cục RTL"</string>
    +     <string name="force_rtl_layout_all_locales_summary" msgid="9192797796616132534">"Buộc hướng bố cục màn hình RTL cho tất cả ngôn ngữ"</string>
    +-    <string name="show_cpu_usage" msgid="2389212910758076024">"Hiển thị mức sử dụng CPU"</string>
    +-    <string name="show_cpu_usage_summary" msgid="2113341923988958266">"Lớp phủ màn hình hiển thị mức sử dụng CPU hiện tại"</string>
    +     <string name="force_hw_ui" msgid="6426383462520888732">"Bắt buộc kết xuất GPU"</string>
    +     <string name="force_hw_ui_summary" msgid="5535991166074861515">"Bắt buộc sử dụng GPU cho bản vẽ 2d"</string>
    +     <string name="force_msaa" msgid="7920323238677284387">"Bắt buộc 4x MSAA"</string>
    +@@ -341,4 +340,5 @@
    +     <string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"Lớn nhất"</string>
    +     <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Tùy chỉnh (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
    +     <string name="help_feedback_label" msgid="6815040660801785649">"Trợ giúp và phản hồi"</string>
    ++    <string name="content_description_menu_button" msgid="8182594799812351266">"Menu"</string>
    + </resources>
    +diff --git a/packages/SettingsLib/res/values-zh-rCN/strings.xml b/packages/SettingsLib/res/values-zh-rCN/strings.xml
    +index 18ae80e..29c4c73 100644
    +--- a/packages/SettingsLib/res/values-zh-rCN/strings.xml
    ++++ b/packages/SettingsLib/res/values-zh-rCN/strings.xml
    +@@ -28,7 +28,8 @@
    +     <string name="wifi_disabled_wifi_failure" msgid="3081668066612876581">"WLAN 连接失败"</string>
    +     <string name="wifi_disabled_password_failure" msgid="8659805351763133575">"身份验证出现问题"</string>
    +     <string name="wifi_not_in_range" msgid="1136191511238508967">"不在范围内"</string>
    +-    <string name="wifi_no_internet" msgid="9151470775868728896">"未检测到任何互联网连接,因此不会自动重新连接。"</string>
    ++    <string name="wifi_no_internet_no_reconnect" msgid="2211781637653149657">"未检测到任何互联网连接,系统无法自动为您重新连接。"</string>
    ++    <string name="wifi_no_internet" msgid="5011955173375805204">"无法连接到互联网。"</string>
    +     <string name="saved_network" msgid="4352716707126620811">"已通过<xliff:g id="NAME">%1$s</xliff:g>保存"</string>
    +     <string name="connected_via_wfa" msgid="3805736726317410714">"已连接(通过 WLAN 助手)"</string>
    +     <string name="connected_via_passpoint" msgid="2826205693803088747">"已通过%1$s连接"</string>
    +@@ -186,7 +187,7 @@
    +     <string name="debug_view_attributes" msgid="6485448367803310384">"启用视图属性检查功能"</string>
    +     <string name="mobile_data_always_on_summary" msgid="8149773901431697910">"始终开启移动数据网络,即使 WLAN 网络已开启(便于快速切换网络)。"</string>
    +     <string name="adb_warning_title" msgid="6234463310896563253">"是否允许USB调试?"</string>
    +-    <string name="adb_warning_message" msgid="7316799925425402244">"USB调试仅适用于开发工作。该功能可用于在您的计算机和设备之间复制数据、在您的设备上安装应用而不发送通知以及读取日志数据。"</string>
    ++    <string name="adb_warning_message" msgid="7316799925425402244">"USB 调试仅用于开发目的。该功能可用于在您的计算机和设备之间复制数据、在您的设备上安装应用(事先不发通知)以及读取日志数据。"</string>
    +     <string name="adb_keys_warning_message" msgid="5659849457135841625">"是否针对您之前授权的所有计算机撤消USB调试的访问权限?"</string>
    +     <string name="dev_settings_warning_title" msgid="7244607768088540165">"允许开发设置?"</string>
    +     <string name="dev_settings_warning_message" msgid="2298337781139097964">"这些设置仅适用于开发工作。一旦启用,会导致您的设备以及设备上的应用崩溃或出现异常。"</string>
    +@@ -233,8 +234,6 @@
    +     <string name="debug_layout_summary" msgid="2001775315258637682">"显示剪辑边界、边距等。"</string>
    +     <string name="force_rtl_layout_all_locales" msgid="2259906643093138978">"强制使用从右到左的布局方向"</string>
    +     <string name="force_rtl_layout_all_locales_summary" msgid="9192797796616132534">"强制将所有语言区域的屏幕布局方向改为从右到左"</string>
    +-    <string name="show_cpu_usage" msgid="2389212910758076024">"显示 CPU 使用情况"</string>
    +-    <string name="show_cpu_usage_summary" msgid="2113341923988958266">"屏幕叠加层显示当前 CPU 使用情况"</string>
    +     <string name="force_hw_ui" msgid="6426383462520888732">"强制进行 GPU 渲染"</string>
    +     <string name="force_hw_ui_summary" msgid="5535991166074861515">"强制使用 GPU 进行 2D 绘图"</string>
    +     <string name="force_msaa" msgid="7920323238677284387">"强制启用 4x MSAA"</string>
    +@@ -341,4 +340,5 @@
    +     <string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"最大"</string>
    +     <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"自定义 (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
    +     <string name="help_feedback_label" msgid="6815040660801785649">"帮助和反馈"</string>
    ++    <string name="content_description_menu_button" msgid="8182594799812351266">"菜单"</string>
    + </resources>
    +diff --git a/packages/SettingsLib/res/values-zh-rHK/strings.xml b/packages/SettingsLib/res/values-zh-rHK/strings.xml
    +index 660071d..c77b786 100644
    +--- a/packages/SettingsLib/res/values-zh-rHK/strings.xml
    ++++ b/packages/SettingsLib/res/values-zh-rHK/strings.xml
    +@@ -28,7 +28,8 @@
    +     <string name="wifi_disabled_wifi_failure" msgid="3081668066612876581">"WiFi 連線失敗"</string>
    +     <string name="wifi_disabled_password_failure" msgid="8659805351763133575">"驗證問題"</string>
    +     <string name="wifi_not_in_range" msgid="1136191511238508967">"超出可用範圍"</string>
    +-    <string name="wifi_no_internet" msgid="9151470775868728896">"未能偵測到互聯網連線,因此不會自動重新連線。"</string>
    ++    <string name="wifi_no_internet_no_reconnect" msgid="2211781637653149657">"無法偵測互聯網連線,未能自動重新連線。"</string>
    ++    <string name="wifi_no_internet" msgid="5011955173375805204">"無法偵測互聯網連線。"</string>
    +     <string name="saved_network" msgid="4352716707126620811">"<xliff:g id="NAME">%1$s</xliff:g> 的儲存"</string>
    +     <string name="connected_via_wfa" msgid="3805736726317410714">"已透過 Wi-Fi 小幫手連線"</string>
    +     <string name="connected_via_passpoint" msgid="2826205693803088747">"已透過 %1$s 連線"</string>
    +@@ -233,8 +234,6 @@
    +     <string name="debug_layout_summary" msgid="2001775315258637682">"顯示剪輯範圍、邊界等"</string>
    +     <string name="force_rtl_layout_all_locales" msgid="2259906643093138978">"強制使用從右至左的版面配置方向"</string>
    +     <string name="force_rtl_layout_all_locales_summary" msgid="9192797796616132534">"強制將所有語言代碼的畫面配置方向改為從右至左"</string>
    +-    <string name="show_cpu_usage" msgid="2389212910758076024">"顯示 CPU 使用量"</string>
    +-    <string name="show_cpu_usage_summary" msgid="2113341923988958266">"在螢幕上重疊顯示目前的 CPU 使用量"</string>
    +     <string name="force_hw_ui" msgid="6426383462520888732">"強制使用 GPU 轉譯"</string>
    +     <string name="force_hw_ui_summary" msgid="5535991166074861515">"強制使用 GPU 進行 2D 繪圖"</string>
    +     <string name="force_msaa" msgid="7920323238677284387">"強制 4x MSAA"</string>
    +@@ -341,4 +340,5 @@
    +     <string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"最大"</string>
    +     <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"自訂 (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
    +     <string name="help_feedback_label" msgid="6815040660801785649">"說明與意見反映"</string>
    ++    <string name="content_description_menu_button" msgid="8182594799812351266">"選單"</string>
    + </resources>
    +diff --git a/packages/SettingsLib/res/values-zh-rTW/strings.xml b/packages/SettingsLib/res/values-zh-rTW/strings.xml
    +index bce6f24..fb180ff 100644
    +--- a/packages/SettingsLib/res/values-zh-rTW/strings.xml
    ++++ b/packages/SettingsLib/res/values-zh-rTW/strings.xml
    +@@ -28,7 +28,8 @@
    +     <string name="wifi_disabled_wifi_failure" msgid="3081668066612876581">"WiFi 連線失敗"</string>
    +     <string name="wifi_disabled_password_failure" msgid="8659805351763133575">"驗證問題"</string>
    +     <string name="wifi_not_in_range" msgid="1136191511238508967">"不在有效範圍內"</string>
    +-    <string name="wifi_no_internet" msgid="9151470775868728896">"未偵測到可用的網際網路連線,系統無法為您自動重新連線。"</string>
    ++    <string name="wifi_no_internet_no_reconnect" msgid="2211781637653149657">"未偵測到可用的網際網路連線,系統無法為你自動重新連線。"</string>
    ++    <string name="wifi_no_internet" msgid="5011955173375805204">"沒有可用的網際網路連線。"</string>
    +     <string name="saved_network" msgid="4352716707126620811">"由<xliff:g id="NAME">%1$s</xliff:g>儲存"</string>
    +     <string name="connected_via_wfa" msgid="3805736726317410714">"已透過 Wi‑Fi 小幫手連線"</string>
    +     <string name="connected_via_passpoint" msgid="2826205693803088747">"已透過 %1$s 連線"</string>
    +@@ -233,8 +234,6 @@
    +     <string name="debug_layout_summary" msgid="2001775315258637682">"顯示剪輯範圍、邊界等。"</string>
    +     <string name="force_rtl_layout_all_locales" msgid="2259906643093138978">"強制使用從右至左版面配置方向"</string>
    +     <string name="force_rtl_layout_all_locales_summary" msgid="9192797796616132534">"強制將所有語言代碼的畫面配置方向改為從右至左"</string>
    +-    <string name="show_cpu_usage" msgid="2389212910758076024">"顯示 CPU 使用量"</string>
    +-    <string name="show_cpu_usage_summary" msgid="2113341923988958266">"在螢幕上方顯示目前的 CPU 使用量"</string>
    +     <string name="force_hw_ui" msgid="6426383462520888732">"強制使用 GPU 轉譯"</string>
    +     <string name="force_hw_ui_summary" msgid="5535991166074861515">"強制使用 GPU 進行 2D 繪圖"</string>
    +     <string name="force_msaa" msgid="7920323238677284387">"強制 4x MSAA"</string>
    +@@ -341,4 +340,5 @@
    +     <string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"最大"</string>
    +     <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"自訂 (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
    +     <string name="help_feedback_label" msgid="6815040660801785649">"說明與意見回饋"</string>
    ++    <string name="content_description_menu_button" msgid="8182594799812351266">"選單"</string>
    + </resources>
    +diff --git a/packages/SettingsLib/res/values-zu/strings.xml b/packages/SettingsLib/res/values-zu/strings.xml
    +index 07c6fce..2f9d428 100644
    +--- a/packages/SettingsLib/res/values-zu/strings.xml
    ++++ b/packages/SettingsLib/res/values-zu/strings.xml
    +@@ -28,7 +28,8 @@
    +     <string name="wifi_disabled_wifi_failure" msgid="3081668066612876581">"Ukwehlulekla koxhumo le-WiFi"</string>
    +     <string name="wifi_disabled_password_failure" msgid="8659805351763133575">"Inkinga yokufakazela ubuqiniso"</string>
    +     <string name="wifi_not_in_range" msgid="1136191511238508967">"Ayikho ebubanzini"</string>
    +-    <string name="wifi_no_internet" msgid="9151470775868728896">"Ukufinyeela okungekhona kwe-inthanethi kutholakele, ngeke kuxhumeke ngokuzenzakalelayo."</string>
    ++    <string name="wifi_no_internet_no_reconnect" msgid="2211781637653149657">"Ukufinyeela okungekhona kwe-inthanethi kutholakele, ngeke kuxhumeke ngokuzenzakalelayo."</string>
    ++    <string name="wifi_no_internet" msgid="5011955173375805204">"Akukho ukufinyelela kwe-intanethi."</string>
    +     <string name="saved_network" msgid="4352716707126620811">"Kulondolozwe ngu-<xliff:g id="NAME">%1$s</xliff:g>"</string>
    +     <string name="connected_via_wfa" msgid="3805736726317410714">"Ixhunywe ngomsizi we-Wi-FI"</string>
    +     <string name="connected_via_passpoint" msgid="2826205693803088747">"Kuxhumeke nge-%1$s"</string>
    +@@ -233,8 +234,6 @@
    +     <string name="debug_layout_summary" msgid="2001775315258637682">"Bonisa imikhawulo, imiphetho, njll, yesiqeshana."</string>
    +     <string name="force_rtl_layout_all_locales" msgid="2259906643093138978">"Phoqelela isikhombisi-ndlela sesakhiwo se-RTL"</string>
    +     <string name="force_rtl_layout_all_locales_summary" msgid="9192797796616132534">"Phoqelela isikhombisi-ndlela sesikrini ku-RTL kuzo zonke izifunda"</string>
    +-    <string name="show_cpu_usage" msgid="2389212910758076024">"Bonisa ukusebenzisa i-CPU"</string>
    +-    <string name="show_cpu_usage_summary" msgid="2113341923988958266">"Imbondela yesikrini ibonisa ukusetshenziswa kwe-CPU okwamanje"</string>
    +     <string name="force_hw_ui" msgid="6426383462520888732">"Phoqa ukunikeza i-GPU"</string>
    +     <string name="force_hw_ui_summary" msgid="5535991166074861515">"Phoqelela ukusetshenziswa kwe-GPU ngomdwebo we-2d"</string>
    +     <string name="force_msaa" msgid="7920323238677284387">"Phoqelela i-4x MSAA"</string>
    +@@ -341,4 +340,5 @@
    +     <string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"Okukhulu kakhulu"</string>
    +     <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Ngokwezifiso (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
    +     <string name="help_feedback_label" msgid="6815040660801785649">"Usizo nempendulo"</string>
    ++    <string name="content_description_menu_button" msgid="8182594799812351266">"Imenyu"</string>
    + </resources>
    +diff --git a/packages/SettingsLib/res/values/config.xml b/packages/SettingsLib/res/values/config.xml
    +index 0cf4a41..0aa76a0 100755
    +--- a/packages/SettingsLib/res/values/config.xml
    ++++ b/packages/SettingsLib/res/values/config.xml
    +@@ -23,8 +23,8 @@
    +     <!-- Default data warning level in mb -->
    +     <integer name="default_data_warning_level_mb">2048</integer>
    + 
    +-    <!-- Whether to send a custom package name with the PSD. translatable="false"-->
    +-    <bool name="config_sendPackageName">true</bool>
    ++    <!-- Whether to send a custom package name with the PSD.-->
    ++    <bool name="config_sendPackageName">false</bool>
    + 
    +     <!-- Name for the set of keys associating package names -->
    +     <string name="config_helpPackageNameKey" translatable="false"></string>
    +@@ -37,4 +37,7 @@
    + 
    +     <!-- Intent key for package name values -->
    +     <string name="config_helpIntentNameKey" translatable="false"></string>
    +-</resources>
    ++
    ++    <!-- The apps that need to be hided when they are disabled -->
    ++    <string-array name="config_hideWhenDisabled_packageNames"></string-array>
    ++</resources>
    +\ No newline at end of file
    +diff --git a/packages/SettingsLib/res/values/strings.xml b/packages/SettingsLib/res/values/strings.xml
    +index 7d42211..43b7668 100644
    +--- a/packages/SettingsLib/res/values/strings.xml
    ++++ b/packages/SettingsLib/res/values/strings.xml
    +@@ -64,8 +64,10 @@
    +     <string name="wifi_disabled_password_failure">Authentication problem</string>
    +     <!-- Summary for the remembered network but currently not in range. -->
    +     <string name="wifi_not_in_range">Not in range</string>
    ++    <!-- Summary for the network but no internet connection was detected. -->
    ++    <string name="wifi_no_internet_no_reconnect">No Internet Access Detected, won\'t automatically reconnect.</string>
    +     <!-- Summary for the remembered network but no internet connection was detected. -->
    +-    <string name="wifi_no_internet">No Internet Access Detected, won\'t automatically reconnect.</string>
    ++    <string name="wifi_no_internet">No Internet Access.</string>
    +     <!-- Summary for saved networks -->
    +     <string name="saved_network">Saved by <xliff:g id="name">%1$s</xliff:g></string>
    + 
    +@@ -580,11 +582,6 @@
    +     <!-- UI debug setting: force right to left layout summary [CHAR LIMIT=100] -->
    +     <string name="force_rtl_layout_all_locales_summary">Force screen layout direction to RTL for all locales</string>
    + 
    +-    <!-- UI debug setting: show how CPU is being used? [CHAR LIMIT=25] -->
    +-    <string name="show_cpu_usage">Show CPU usage</string>
    +-    <!-- UI debug setting: show cpu usage summary [CHAR LIMIT=50] -->
    +-    <string name="show_cpu_usage_summary">Screen overlay showing current CPU usage</string>
    +-
    +     <!-- UI debug setting: force hardware acceleration to render apps [CHAR LIMIT=25] -->
    +     <string name="force_hw_ui">Force GPU rendering</string>
    +     <!-- UI debug setting: force hardware acceleration summary [CHAR LIMIT=50] -->
    +@@ -863,4 +860,7 @@
    +     <!-- Label for Help and feedback menu item -->
    +     <string name="help_feedback_label">Help &amp; feedback</string>
    + 
    ++    <!-- Content description for drawer menu button [CHAR_LIMIT=30]-->
    ++    <string name="content_description_menu_button">Menu</string>
    ++
    + </resources>
    +diff --git a/packages/SettingsLib/src/com/android/settingslib/HelpUtils.java b/packages/SettingsLib/src/com/android/settingslib/HelpUtils.java
    +index b5295da..381f903 100644
    +--- a/packages/SettingsLib/src/com/android/settingslib/HelpUtils.java
    ++++ b/packages/SettingsLib/src/com/android/settingslib/HelpUtils.java
    +@@ -34,6 +34,8 @@ import android.util.TypedValue;
    + import android.view.Menu;
    + import android.view.MenuItem;
    + import android.view.MenuItem.OnMenuItemClickListener;
    ++import com.android.internal.logging.MetricsLogger;
    ++import com.android.internal.logging.MetricsProto.MetricsEvent;
    + 
    + import java.net.URISyntaxException;
    + import java.util.Locale;
    +@@ -112,6 +114,9 @@ public class HelpUtils {
    +                 helpMenuItem.setOnMenuItemClickListener(new OnMenuItemClickListener() {
    +                     @Override
    +                     public boolean onMenuItemClick(MenuItem item) {
    ++                        MetricsLogger.action(activity,
    ++                            MetricsEvent.ACTION_SETTING_HELP_AND_FEEDBACK,
    ++                            intent.getStringExtra(EXTRA_CONTEXT));
    +                         try {
    +                             activity.startActivityForResult(intent, 0);
    +                         } catch (ActivityNotFoundException exc) {
    +diff --git a/packages/SettingsLib/src/com/android/settingslib/applications/ApplicationsState.java b/packages/SettingsLib/src/com/android/settingslib/applications/ApplicationsState.java
    +index a22a051..f0ec107 100644
    +--- a/packages/SettingsLib/src/com/android/settingslib/applications/ApplicationsState.java
    ++++ b/packages/SettingsLib/src/com/android/settingslib/applications/ApplicationsState.java
    +@@ -47,6 +47,7 @@ import android.util.Log;
    + import android.util.SparseArray;
    + 
    + import com.android.internal.util.ArrayUtils;
    ++import com.android.settingslib.R;
    + 
    + import java.io.File;
    + import java.text.Collator;
    +@@ -621,7 +622,7 @@ public class ApplicationsState {
    +             }
    + 
    +             if (filter != null) {
    +-                filter.init();
    ++                filter.init(mContext);
    +             }
    + 
    +             List<AppEntry> apps;
    +@@ -1280,6 +1281,9 @@ public class ApplicationsState {
    + 
    +     public interface AppFilter {
    +         void init();
    ++        default void init(Context context) {
    ++            init();
    ++        }
    +         boolean filterApp(AppEntry info);
    +     }
    + 
    +@@ -1398,6 +1402,33 @@ public class ApplicationsState {
    +         }
    +     };
    + 
    ++    public static final AppFilter FILTER_NOT_HIDE = new AppFilter() {
    ++        private String[] mHidePackageNames;
    ++
    ++        public void init(Context context) {
    ++            mHidePackageNames = context.getResources()
    ++                .getStringArray(R.array.config_hideWhenDisabled_packageNames);
    ++        }
    ++
    ++        @Override
    ++        public void init() {
    ++        }
    ++
    ++        @Override
    ++        public boolean filterApp(AppEntry entry) {
    ++            if (ArrayUtils.contains(mHidePackageNames, entry.info.packageName)) {
    ++                if (!entry.info.enabled) {
    ++                    return false;
    ++                } else if (entry.info.enabledSetting ==
    ++                    PackageManager.COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED) {
    ++                    return false;
    ++                }
    ++            }
    ++
    ++            return true;
    ++        }
    ++    };
    ++
    +     public static class VolumeFilter implements AppFilter {
    +         private final String mVolumeUuid;
    + 
    +@@ -1425,6 +1456,12 @@ public class ApplicationsState {
    +         }
    + 
    +         @Override
    ++        public void init(Context context) {
    ++            mFirstFilter.init(context);
    ++            mSecondFilter.init(context);
    ++        }
    ++
    ++        @Override
    +         public void init() {
    +             mFirstFilter.init();
    +             mSecondFilter.init();
    +diff --git a/packages/SettingsLib/src/com/android/settingslib/deviceinfo/StorageMeasurement.java b/packages/SettingsLib/src/com/android/settingslib/deviceinfo/StorageMeasurement.java
    +index 0e3e0d5..5c577f8 100644
    +--- a/packages/SettingsLib/src/com/android/settingslib/deviceinfo/StorageMeasurement.java
    ++++ b/packages/SettingsLib/src/com/android/settingslib/deviceinfo/StorageMeasurement.java
    +@@ -126,6 +126,13 @@ public class StorageMeasurement {
    +          * internal storage. Key is {@link UserHandle}.
    +          */
    +         public SparseLongArray usersSize = new SparseLongArray();
    ++
    ++        @Override
    ++        public String toString() {
    ++            return "MeasurementDetails: [totalSize: " + totalSize + " availSize: " + availSize
    ++                    + " cacheSize: " + cacheSize + " mediaSize: " + mediaSize
    ++                    + " miscSize: " + miscSize + "usersSize: " + usersSize + "]";
    ++        }
    +     }
    + 
    +     public interface MeasurementReceiver {
    +@@ -435,7 +442,7 @@ public class StorageMeasurement {
    +     private static long getDirectorySize(IMediaContainerService imcs, File path) {
    +         try {
    +             final long size = imcs.calculateDirectorySize(path.toString());
    +-            Log.d(TAG, "getDirectorySize(" + path + ") returned " + size);
    ++            if (LOGV) Log.v(TAG, "getDirectorySize(" + path + ") returned " + size);
    +             return size;
    +         } catch (Exception e) {
    +             Log.w(TAG, "Could not read memory from default container service for " + path, e);
    +diff --git a/packages/SettingsLib/src/com/android/settingslib/display/DisplayDensityUtils.java b/packages/SettingsLib/src/com/android/settingslib/display/DisplayDensityUtils.java
    +index a99e668..af8fd4c 100644
    +--- a/packages/SettingsLib/src/com/android/settingslib/display/DisplayDensityUtils.java
    ++++ b/packages/SettingsLib/src/com/android/settingslib/display/DisplayDensityUtils.java
    +@@ -23,6 +23,7 @@ import android.content.res.Resources;
    + import android.hardware.display.DisplayManager;
    + import android.os.AsyncTask;
    + import android.os.RemoteException;
    ++import android.os.UserHandle;
    + import android.util.DisplayMetrics;
    + import android.util.Log;
    + import android.util.MathUtils;
    +@@ -207,39 +208,41 @@ public class DisplayDensityUtils {
    + 
    +     /**
    +      * Asynchronously applies display density changes to the specified display.
    ++     * <p>
    ++     * The change will be applied to the user specified by the value of
    ++     * {@link UserHandle#myUserId()} at the time the method is called.
    +      *
    +      * @param displayId the identifier of the display to modify
    +      */
    +     public static void clearForcedDisplayDensity(final int displayId) {
    +-        AsyncTask.execute(new Runnable() {
    +-            @Override
    +-            public void run() {
    +-                try {
    +-                    final IWindowManager wm = WindowManagerGlobal.getWindowManagerService();
    +-                    wm.clearForcedDisplayDensity(displayId);
    +-                } catch (RemoteException exc) {
    +-                    Log.w(LOG_TAG, "Unable to clear forced display density setting");
    +-                }
    ++        final int userId = UserHandle.myUserId();
    ++        AsyncTask.execute(() -> {
    ++            try {
    ++                final IWindowManager wm = WindowManagerGlobal.getWindowManagerService();
    ++                wm.clearForcedDisplayDensityForUser(displayId, userId);
    ++            } catch (RemoteException exc) {
    ++                Log.w(LOG_TAG, "Unable to clear forced display density setting");
    +             }
    +         });
    +     }
    + 
    +     /**
    +      * Asynchronously applies display density changes to the specified display.
    ++     * <p>
    ++     * The change will be applied to the user specified by the value of
    ++     * {@link UserHandle#myUserId()} at the time the method is called.
    +      *
    +      * @param displayId the identifier of the display to modify
    +      * @param density the density to force for the specified display
    +      */
    +     public static void setForcedDisplayDensity(final int displayId, final int density) {
    +-        AsyncTask.execute(new Runnable() {
    +-            @Override
    +-            public void run() {
    +-                try {
    +-                    final IWindowManager wm = WindowManagerGlobal.getWindowManagerService();
    +-                    wm.setForcedDisplayDensity(displayId, density);
    +-                } catch (RemoteException exc) {
    +-                    Log.w(LOG_TAG, "Unable to save forced display density setting");
    +-                }
    ++        final int userId = UserHandle.myUserId();
    ++        AsyncTask.execute(() -> {
    ++            try {
    ++                final IWindowManager wm = WindowManagerGlobal.getWindowManagerService();
    ++                wm.setForcedDisplayDensityForUser(displayId, density, userId);
    ++            } catch (RemoteException exc) {
    ++                Log.w(LOG_TAG, "Unable to save forced display density setting");
    +             }
    +         });
    +     }
    +diff --git a/packages/SettingsLib/src/com/android/settingslib/drawer/SettingsDrawerActivity.java b/packages/SettingsLib/src/com/android/settingslib/drawer/SettingsDrawerActivity.java
    +index 6658c14..e6e0243 100644
    +--- a/packages/SettingsLib/src/com/android/settingslib/drawer/SettingsDrawerActivity.java
    ++++ b/packages/SettingsLib/src/com/android/settingslib/drawer/SettingsDrawerActivity.java
    +@@ -28,8 +28,11 @@ import android.content.pm.PackageManager;
    + import android.content.res.TypedArray;
    + import android.os.AsyncTask;
    + import android.os.Bundle;
    ++import android.os.UserHandle;
    ++import android.os.UserManager;
    + import android.provider.Settings;
    + import android.support.v4.widget.DrawerLayout;
    ++import android.text.TextUtils;
    + import android.util.ArraySet;
    + import android.util.Log;
    + import android.util.Pair;
    +@@ -56,6 +59,7 @@ public class SettingsDrawerActivity extends Activity {
    + 
    +     protected static final boolean DEBUG_TIMING = false;
    +     private static final String TAG = "SettingsDrawerActivity";
    ++    private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
    + 
    +     public static final String EXTRA_SHOW_MENU = "show_drawer_menu";
    + 
    +@@ -73,6 +77,7 @@ public class SettingsDrawerActivity extends Activity {
    +     private FrameLayout mContentHeaderContainer;
    +     private DrawerLayout mDrawerLayout;
    +     private boolean mShowingMenu;
    ++    private UserManager mUserManager;
    + 
    +     @Override
    +     protected void onCreate(@Nullable Bundle savedInstanceState) {
    +@@ -108,8 +113,10 @@ public class SettingsDrawerActivity extends Activity {
    +             public void onItemClick(android.widget.AdapterView<?> parent, View view, int position,
    +                     long id) {
    +                 onTileClicked(mDrawerAdapter.getTile(position));
    +-            };
    ++            }
    +         });
    ++
    ++        mUserManager = UserManager.get(this);
    +         if (DEBUG_TIMING) Log.d(TAG, "onCreate took " + (System.currentTimeMillis() - startTime)
    +                 + " ms");
    +     }
    +@@ -138,8 +145,16 @@ public class SettingsDrawerActivity extends Activity {
    + 
    +             new CategoriesUpdater().execute();
    +         }
    +-        if (getIntent() != null && getIntent().getBooleanExtra(EXTRA_SHOW_MENU, false)) {
    +-            showMenuIcon();
    ++        final Intent intent = getIntent();
    ++        if (intent != null) {
    ++            if (intent.hasExtra(EXTRA_SHOW_MENU)) {
    ++                if (intent.getBooleanExtra(EXTRA_SHOW_MENU, false)) {
    ++                    // Intent explicitly set to show menu.
    ++                    showMenuIcon();
    ++                }
    ++            } else if (isTopLevelTile(intent)) {
    ++                showMenuIcon();
    ++            }
    +         }
    +     }
    + 
    +@@ -152,6 +167,30 @@ public class SettingsDrawerActivity extends Activity {
    +         super.onPause();
    +     }
    + 
    ++    private boolean isTopLevelTile(Intent intent) {
    ++        final ComponentName componentName = intent.getComponent();
    ++        if (componentName == null) {
    ++            return false;
    ++        }
    ++        // Look for a tile that has the same component as incoming intent
    ++        final List<DashboardCategory> categories = getDashboardCategories();
    ++        for (DashboardCategory category : categories) {
    ++            for (Tile tile : category.tiles) {
    ++                if (TextUtils.equals(tile.intent.getComponent().getClassName(),
    ++                        componentName.getClassName())) {
    ++                    if (DEBUG) {
    ++                        Log.d(TAG, "intent is for top level tile: " + tile.title);
    ++                    }
    ++                    return true;
    ++                }
    ++            }
    ++        }
    ++        if (DEBUG) {
    ++            Log.d(TAG, "Intent is not for top level settings " + intent);
    ++        }
    ++        return false;
    ++    }
    ++
    +     public void addCategoryListener(CategoryListener listener) {
    +         mCategoryListeners.add(listener);
    +     }
    +@@ -226,6 +265,7 @@ public class SettingsDrawerActivity extends Activity {
    +     public void showMenuIcon() {
    +         mShowingMenu = true;
    +         getActionBar().setHomeAsUpIndicator(R.drawable.ic_menu);
    ++        getActionBar().setHomeActionContentDescription(R.string.content_description_menu_button);
    +         getActionBar().setDisplayHomeAsUpEnabled(true);
    +     }
    + 
    +@@ -256,6 +296,7 @@ public class SettingsDrawerActivity extends Activity {
    +             return true;
    +         }
    +         try {
    ++            updateUserHandlesIfNeeded(tile);
    +             int numUserHandles = tile.userHandle.size();
    +             if (numUserHandles > 1) {
    +                 ProfileSelectDialog.show(getFragmentManager(), tile);
    +@@ -277,6 +318,19 @@ public class SettingsDrawerActivity extends Activity {
    +         return true;
    +     }
    + 
    ++    private void updateUserHandlesIfNeeded(Tile tile) {
    ++        List<UserHandle> userHandles = tile.userHandle;
    ++
    ++        for (int i = userHandles.size() - 1; i >= 0; i--) {
    ++            if (mUserManager.getUserInfo(userHandles.get(i).getIdentifier()) == null) {
    ++                if (DEBUG) {
    ++                    Log.d(TAG, "Delete the user: " + userHandles.get(i).getIdentifier());
    ++                }
    ++                userHandles.remove(i);
    ++            }
    ++        }
    ++    }
    ++
    +     protected void onTileClicked(Tile tile) {
    +         if (openTile(tile)) {
    +             finish();
    +diff --git a/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java b/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java
    +index 380fcd4..234ae71 100644
    +--- a/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java
    ++++ b/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java
    +@@ -356,21 +356,26 @@ public class AccessPoint implements Comparable<AccessPoint> {
    +     }
    + 
    +     public DetailedState getDetailedState() {
    +-        return mNetworkInfo != null ? mNetworkInfo.getDetailedState() : null;
    ++        if (mNetworkInfo != null) {
    ++            return mNetworkInfo.getDetailedState();
    ++        }
    ++        Log.w(TAG, "NetworkInfo is null, cannot return detailed state");
    ++        return null;
    +     }
    + 
    +     public String getSavedNetworkSummary() {
    +-        if (mConfig != null) {
    ++        WifiConfiguration config = mConfig;
    ++        if (config != null) {
    +             PackageManager pm = mContext.getPackageManager();
    +             String systemName = pm.getNameForUid(android.os.Process.SYSTEM_UID);
    +-            int userId = UserHandle.getUserId(mConfig.creatorUid);
    ++            int userId = UserHandle.getUserId(config.creatorUid);
    +             ApplicationInfo appInfo = null;
    +-            if (mConfig.creatorName != null && mConfig.creatorName.equals(systemName)) {
    ++            if (config.creatorName != null && config.creatorName.equals(systemName)) {
    +                 appInfo = mContext.getApplicationInfo();
    +             } else {
    +                 try {
    +                     IPackageManager ipm = AppGlobals.getPackageManager();
    +-                    appInfo = ipm.getApplicationInfo(mConfig.creatorName, 0 /* flags */, userId);
    ++                    appInfo = ipm.getApplicationInfo(config.creatorName, 0 /* flags */, userId);
    +                 } catch (RemoteException rex) {
    +                 }
    +             }
    +@@ -385,29 +390,36 @@ public class AccessPoint implements Comparable<AccessPoint> {
    +     }
    + 
    +     public String getSummary() {
    +-        return getSettingsSummary();
    ++        return getSettingsSummary(mConfig);
    +     }
    + 
    +     public String getSettingsSummary() {
    ++        return getSettingsSummary(mConfig);
    ++    }
    ++
    ++    private String getSettingsSummary(WifiConfiguration config) {
    +         // Update to new summary
    +         StringBuilder summary = new StringBuilder();
    + 
    +-        if (isActive() && mConfig != null && mConfig.isPasspoint()) {
    ++        if (isActive() && config != null && config.isPasspoint()) {
    +             // This is the active connection on passpoint
    +             summary.append(getSummary(mContext, getDetailedState(),
    +-                    false, mConfig.providerFriendlyName));
    ++                    false, config.providerFriendlyName));
    +         } else if (isActive()) {
    +             // This is the active connection on non-passpoint network
    +             summary.append(getSummary(mContext, getDetailedState(),
    +                     mInfo != null && mInfo.isEphemeral()));
    +-        } else if (mConfig != null && mConfig.isPasspoint()) {
    ++        } else if (config != null && config.isPasspoint()) {
    +             String format = mContext.getString(R.string.available_via_passpoint);
    +-            summary.append(String.format(format, mConfig.providerFriendlyName));
    +-        } else if (mConfig != null && mConfig.hasNoInternetAccess()) {
    +-            summary.append(mContext.getString(R.string.wifi_no_internet));
    +-        } else if (mConfig != null && !mConfig.getNetworkSelectionStatus().isNetworkEnabled()) {
    ++            summary.append(String.format(format, config.providerFriendlyName));
    ++        } else if (config != null && config.hasNoInternetAccess()) {
    ++            int messageID = config.getNetworkSelectionStatus().isNetworkPermanentlyDisabled()
    ++                    ? R.string.wifi_no_internet_no_reconnect
    ++                    : R.string.wifi_no_internet;
    ++            summary.append(mContext.getString(messageID));
    ++        } else if (config != null && !config.getNetworkSelectionStatus().isNetworkEnabled()) {
    +             WifiConfiguration.NetworkSelectionStatus networkStatus =
    +-                    mConfig.getNetworkSelectionStatus();
    ++                    config.getNetworkSelectionStatus();
    +             switch (networkStatus.getNetworkSelectionDisableReason()) {
    +                 case WifiConfiguration.NetworkSelectionStatus.DISABLED_AUTHENTICATION_FAILURE:
    +                     summary.append(mContext.getString(R.string.wifi_disabled_password_failure));
    +@@ -423,7 +435,7 @@ public class AccessPoint implements Comparable<AccessPoint> {
    +         } else if (mRssi == Integer.MAX_VALUE) { // Wifi out of range
    +             summary.append(mContext.getString(R.string.wifi_not_in_range));
    +         } else { // In range, not disabled.
    +-            if (mConfig != null) { // Is saved network
    ++            if (config != null) { // Is saved network
    +                 summary.append(mContext.getString(R.string.wifi_remembered));
    +             }
    +         }
    +@@ -435,11 +447,11 @@ public class AccessPoint implements Comparable<AccessPoint> {
    +                 summary.append(" f=" + Integer.toString(mInfo.getFrequency()));
    +             }
    +             summary.append(" " + getVisibilityStatus());
    +-            if (mConfig != null && !mConfig.getNetworkSelectionStatus().isNetworkEnabled()) {
    +-                summary.append(" (" + mConfig.getNetworkSelectionStatus().getNetworkStatusString());
    +-                if (mConfig.getNetworkSelectionStatus().getDisableTime() > 0) {
    ++            if (config != null && !config.getNetworkSelectionStatus().isNetworkEnabled()) {
    ++                summary.append(" (" + config.getNetworkSelectionStatus().getNetworkStatusString());
    ++                if (config.getNetworkSelectionStatus().getDisableTime() > 0) {
    +                     long now = System.currentTimeMillis();
    +-                    long diff = (now - mConfig.getNetworkSelectionStatus().getDisableTime()) / 1000;
    ++                    long diff = (now - config.getNetworkSelectionStatus().getDisableTime()) / 1000;
    +                     long sec = diff%60; //seconds
    +                     long min = (diff/60)%60; //minutes
    +                     long hour = (min/60)%60; //hours
    +@@ -451,9 +463,9 @@ public class AccessPoint implements Comparable<AccessPoint> {
    +                 summary.append(")");
    +             }
    + 
    +-            if (mConfig != null) {
    ++            if (config != null) {
    +                 WifiConfiguration.NetworkSelectionStatus networkStatus =
    +-                        mConfig.getNetworkSelectionStatus();
    ++                        config.getNetworkSelectionStatus();
    +                 for (int index = WifiConfiguration.NetworkSelectionStatus.NETWORK_SELECTION_ENABLE;
    +                         index < WifiConfiguration.NetworkSelectionStatus
    +                         .NETWORK_SELECTION_DISABLED_MAX; index++) {
    +@@ -790,7 +802,10 @@ public class AccessPoint implements Comparable<AccessPoint> {
    +                 return context.getString(R.string.wifi_connected_no_internet);
    +             }
    +         }
    +-
    ++        if (state == null) {
    ++            Log.w(TAG, "state is null, returning empty summary");
    ++            return "";
    ++        }
    +         String[] formats = context.getResources().getStringArray((ssid == null)
    +                 ? R.array.wifi_status : R.array.wifi_status_with_ssid);
    +         int index = state.ordinal();
    +diff --git a/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPointPreference.java b/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPointPreference.java
    +index 284827b..aae9cf6 100644
    +--- a/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPointPreference.java
    ++++ b/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPointPreference.java
    +@@ -29,7 +29,6 @@ import android.text.TextUtils;
    + import android.util.AttributeSet;
    + import android.util.SparseArray;
    + import android.widget.TextView;
    +-
    + import com.android.settingslib.R;
    + 
    + public class AccessPointPreference extends Preference {
    +@@ -44,13 +43,14 @@ public class AccessPointPreference extends Preference {
    +     private final StateListDrawable mWifiSld;
    +     private final int mBadgePadding;
    +     private final UserBadgeCache mBadgeCache;
    +-
    +     private TextView mTitleView;
    ++
    +     private boolean mForSavedNetworks = false;
    +     private AccessPoint mAccessPoint;
    +     private Drawable mBadge;
    +     private int mLevel;
    +     private CharSequence mContentDescription;
    ++    private int mDefaultIconResId;
    + 
    +     static final int[] WIFI_CONNECTION_STRENGTH = {
    +             R.string.accessibility_wifi_one_bar,
    +@@ -85,6 +85,24 @@ public class AccessPointPreference extends Preference {
    +         refresh();
    +     }
    + 
    ++    public AccessPointPreference(AccessPoint accessPoint, Context context, UserBadgeCache cache,
    ++            int iconResId, boolean forSavedNetworks) {
    ++        super(context);
    ++        mBadgeCache = cache;
    ++        mAccessPoint = accessPoint;
    ++        mForSavedNetworks = forSavedNetworks;
    ++        mAccessPoint.setTag(this);
    ++        mLevel = -1;
    ++        mDefaultIconResId = iconResId;
    ++
    ++        mWifiSld = (StateListDrawable) context.getTheme()
    ++                .obtainStyledAttributes(wifi_signal_attributes).getDrawable(0);
    ++
    ++        // Distance from the end of the title at which this AP's user badge should sit.
    ++        mBadgePadding = context.getResources()
    ++                .getDimensionPixelSize(R.dimen.wifi_preference_badge_padding);
    ++    }
    ++
    +     public AccessPoint getAccessPoint() {
    +         return mAccessPoint;
    +     }
    +@@ -112,7 +130,7 @@ public class AccessPointPreference extends Preference {
    + 
    +     protected void updateIcon(int level, Context context) {
    +         if (level == -1) {
    +-            setIcon(null);
    ++            safeSetDefaultIcon();
    +         } else {
    +             if (getIcon() == null) {
    +                 // To avoid a drawing race condition, we first set the state (SECURE/NONE) and then
    +@@ -124,16 +142,24 @@ public class AccessPointPreference extends Preference {
    +                             ? STATE_SECURED
    +                             : STATE_NONE);
    +                     Drawable drawable = mWifiSld.getCurrent();
    +-                    if (!mForSavedNetworks) {
    ++                    if (!mForSavedNetworks && drawable != null) {
    +                         setIcon(drawable);
    +-                    } else {
    +-                        setIcon(null);
    ++                        return;
    +                     }
    +                 }
    ++                safeSetDefaultIcon();
    +             }
    +         }
    +     }
    + 
    ++    private void safeSetDefaultIcon() {
    ++        if (mDefaultIconResId != 0) {
    ++            setIcon(mDefaultIconResId);
    ++        } else {
    ++            setIcon(null);
    ++        }
    ++    }
    ++
    +     protected void updateBadge(Context context) {
    +         WifiConfiguration config = mAccessPoint.getConfig();
    +         if (config != null) {
    +diff --git a/packages/SettingsProvider/res/values/defaults.xml b/packages/SettingsProvider/res/values/defaults.xml
    +index f7e9541..cd2d6b3 100644
    +--- a/packages/SettingsProvider/res/values/defaults.xml
    ++++ b/packages/SettingsProvider/res/values/defaults.xml
    +@@ -36,7 +36,7 @@
    +     <fraction name="def_window_transition_scale">100%</fraction>
    +     <bool name="def_haptic_feedback">true</bool>
    + 
    +-    <bool name="def_bluetooth_on">false</bool>
    ++    <bool name="def_bluetooth_on">true</bool>
    +     <bool name="def_wifi_display_on">false</bool>
    +     <bool name="def_install_non_market_apps">false</bool>
    +     <bool name="def_package_verifier_enable">true</bool>
    +diff --git a/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java b/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java
    +index 7338a9c..c1a1f84 100644
    +--- a/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java
    ++++ b/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java
    +@@ -1483,7 +1483,6 @@ class DatabaseHelper extends SQLiteOpenHelper {
    +                             Settings.Global.CALL_AUTO_RETRY,
    +                             Settings.Global.DEBUG_APP,
    +                             Settings.Global.WAIT_FOR_DEBUGGER,
    +-                            Settings.Global.SHOW_PROCESSES,
    +                             Settings.Global.ALWAYS_FINISH_ACTIVITIES,
    +                     };
    +                     String[] secureToGlobal = {
    +diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
    +index 0f7fe6f..d751895 100644
    +--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
    ++++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
    +@@ -114,7 +114,7 @@ import java.util.regex.Pattern;
    + public class SettingsProvider extends ContentProvider {
    +     private static final boolean DEBUG = false;
    + 
    +-    private static final boolean DROP_DATABASE_ON_MIGRATION = !Build.IS_DEBUGGABLE;
    ++    private static final boolean DROP_DATABASE_ON_MIGRATION = true;
    + 
    +     private static final String LOG_TAG = "SettingsProvider";
    + 
    +@@ -2102,7 +2102,7 @@ public class SettingsProvider extends ContentProvider {
    +         }
    + 
    +         private final class UpgradeController {
    +-            private static final int SETTINGS_VERSION = 130;
    ++            private static final int SETTINGS_VERSION = 131;
    + 
    +             private final int mUserId;
    + 
    +@@ -2142,6 +2142,12 @@ public class SettingsProvider extends ContentProvider {
    + 
    +                     // Now upgrade should work fine.
    +                     onUpgradeLocked(mUserId, oldVersion, newVersion);
    ++
    ++                    // Make a note what happened, so we don't wonder why data was lost
    ++                    String reason = "Settings rebuilt! Current version: "
    ++                            + curVersion + " while expected: " + newVersion;
    ++                    getGlobalSettingsLocked().insertSettingLocked(
    ++                            Settings.Global.DATABASE_DOWNGRADE_REASON, reason, "android");
    +                 }
    + 
    +                 // Set the global settings version if owner.
    +@@ -2410,8 +2416,23 @@ public class SettingsProvider extends ContentProvider {
    +                     currentVersion = 130;
    +                 }
    + 
    ++                if (currentVersion == 130) {
    ++                    // Split Ambient settings
    ++                    final SettingsState secureSettings = getSecureSettingsLocked(userId);
    ++                    boolean dozeExplicitlyDisabled = "0".equals(secureSettings.
    ++                            getSettingLocked(Settings.Secure.DOZE_ENABLED).getValue());
    ++
    ++                    if (dozeExplicitlyDisabled) {
    ++                        secureSettings.insertSettingLocked(Settings.Secure.DOZE_PULSE_ON_PICK_UP,
    ++                                "0", SettingsState.SYSTEM_PACKAGE_NAME);
    ++                        secureSettings.insertSettingLocked(Settings.Secure.DOZE_PULSE_ON_DOUBLE_TAP,
    ++                                "0", SettingsState.SYSTEM_PACKAGE_NAME);
    ++                    }
    ++                    currentVersion = 131;
    ++                }
    ++
    +                 if (currentVersion != newVersion) {
    +-                    Slog.w("SettingsProvider", "warning: upgrading settings database to version "
    ++                    Slog.wtf("SettingsProvider", "warning: upgrading settings database to version "
    +                             + newVersion + " left it at "
    +                             + currentVersion + " instead; this is probably a bug", new Throwable());
    +                     if (DEBUG) {
    +diff --git a/packages/Shell/Android.mk b/packages/Shell/Android.mk
    +index 73a0449..81ab2ff 100644
    +--- a/packages/Shell/Android.mk
    ++++ b/packages/Shell/Android.mk
    +@@ -12,6 +12,8 @@ LOCAL_PACKAGE_NAME := Shell
    + LOCAL_CERTIFICATE := platform
    + LOCAL_PRIVILEGED_MODULE := true
    + 
    ++LOCAL_JACK_COVERAGE_INCLUDE_FILTER := com.android.shell.*
    ++
    + include $(BUILD_PACKAGE)
    + 
    + include $(LOCAL_PATH)/tests/Android.mk
    +diff --git a/packages/Shell/AndroidManifest.xml b/packages/Shell/AndroidManifest.xml
    +index f1789ea..227d0e9 100644
    +--- a/packages/Shell/AndroidManifest.xml
    ++++ b/packages/Shell/AndroidManifest.xml
    +@@ -114,6 +114,8 @@
    +     <uses-permission android:name="android.permission.CHANGE_COMPONENT_ENABLED_STATE" />
    +     <!-- Permission needed to rename bugreport notifications (so they're not shown as Shell) -->
    +     <uses-permission android:name="android.permission.SUBSTITUTE_NOTIFICATION_APP_NAME" />
    ++    <!-- Permission needed to hold a wakelock in dumpstate.cpp (drop_root_user()) -->
    ++    <uses-permission android:name="android.permission.WAKE_LOCK" />
    + 
    +     <application android:label="@string/app_label"
    +                  android:defaultToDeviceProtectedStorage="true"
    +diff --git a/packages/Shell/src/com/android/shell/BugreportStorageProvider.java b/packages/Shell/src/com/android/shell/BugreportStorageProvider.java
    +index 8b07599..9fd80d3 100644
    +--- a/packages/Shell/src/com/android/shell/BugreportStorageProvider.java
    ++++ b/packages/Shell/src/com/android/shell/BugreportStorageProvider.java
    +@@ -132,6 +132,7 @@ public class BugreportStorageProvider extends DocumentsProvider {
    +         if (!getFileForDocId(documentId).delete()) {
    +             throw new FileNotFoundException("Failed to delete: " + documentId);
    +         }
    ++        getContext().getContentResolver().notifyChange(getNotificationUri(), null);
    +     }
    + 
    +     // This is used by BugreportProgressService so that the notification uri shared by
    +diff --git a/packages/SystemUI/AndroidManifest.xml b/packages/SystemUI/AndroidManifest.xml
    +index bdb103a..a74fbf8 100644
    +--- a/packages/SystemUI/AndroidManifest.xml
    ++++ b/packages/SystemUI/AndroidManifest.xml
    +@@ -150,9 +150,6 @@
    +     <!-- DevicePolicyManager get user restrictions -->
    +     <uses-permission android:name="android.permission.MANAGE_PROFILE_AND_DEVICE_OWNERS" />
    + 
    +-    <!-- Needed for passing extras with intent ACTION_SHOW_ADMIN_SUPPORT_DETAILS -->
    +-    <uses-permission android:name="android.permission.MANAGE_DEVICE_ADMINS" />
    +-
    +     <!-- TV picture-in-picture -->
    +     <uses-permission android:name="android.permission.RECEIVE_MEDIA_RESOURCE_USAGE" />
    + 
    +@@ -216,19 +213,10 @@
    +             </intent-filter>
    +         </receiver>
    + 
    +-        <service android:name=".LoadAverageService"
    +-                android:exported="true" />
    +-
    +         <service android:name=".ImageWallpaper"
    +                 android:permission="android.permission.BIND_WALLPAPER"
    +                 android:exported="true" />
    + 
    +-        <receiver android:name=".BootReceiver" androidprv:systemUserOnly="true">
    +-            <intent-filter android:priority="1000">
    +-                <action android:name="android.intent.action.BOOT_COMPLETED" />
    +-            </intent-filter>
    +-        </receiver>
    +-
    +         <activity android:name=".tuner.TunerActivity"
    +                   android:enabled="false"
    +                   android:icon="@drawable/tuner"
    +diff --git a/packages/SystemUI/res/drawable-nodpi/play.xml b/packages/SystemUI/res/drawable-nodpi/play.xml
    +index 747e60b..7720230 100644
    +--- a/packages/SystemUI/res/drawable-nodpi/play.xml
    ++++ b/packages/SystemUI/res/drawable-nodpi/play.xml
    +@@ -21,7 +21,4 @@ Copyright (C) 2015 The Android Open Source Project
    +     <path
    +         android:fillColor="#FF000000"
    +         android:pathData="M8.0,5.0l0.0,14.0l11.0,-7.0z"/>
    +-    <path
    +-        android:pathData="M0 0h24v24H0z"
    +-        android:fillColor="#00000000"/>
    + </vector>
    +diff --git a/packages/SystemUI/res/drawable/car_ic_arrow.xml b/packages/SystemUI/res/drawable/car_ic_arrow.xml
    +index 9d292cc..2c5ad27 100644
    +--- a/packages/SystemUI/res/drawable/car_ic_arrow.xml
    ++++ b/packages/SystemUI/res/drawable/car_ic_arrow.xml
    +@@ -21,7 +21,4 @@
    +     <path
    +         android:fillColor="#FFFFFFFF"
    +         android:pathData="M14.0,20.0l10.0,10.0 10.0,-10.0z"/>
    +-    <path
    +-        android:pathData="M0 0h48v48H0z"
    +-        android:fillColor="#00000000"/>
    + </vector>
    +diff --git a/packages/SystemUI/res/drawable/ic_fullscreen_white_24dp.xml b/packages/SystemUI/res/drawable/ic_fullscreen_white_24dp.xml
    +index 7ddb40c..314a25a 100644
    +--- a/packages/SystemUI/res/drawable/ic_fullscreen_white_24dp.xml
    ++++ b/packages/SystemUI/res/drawable/ic_fullscreen_white_24dp.xml
    +@@ -18,9 +18,6 @@ Copyright (C) 2016 The Android Open Source Project
    +     android:height="24dp"
    +     android:viewportWidth="24"
    +     android:viewportHeight="24">
    +-
    +-    <path
    +-        android:pathData="M0 0h24v24H0z" />
    +     <path
    +         android:fillColor="#FFFFFF"
    +         android:pathData="M7 14H5v5h5v-2H7v-3zm-2-4h2V7h3V5H5v5zm12 7h-3v2h5v-5h-2v3zM14 5v2h3v3h2V5h-5z" />
    +diff --git a/packages/SystemUI/res/drawable/ic_ksh_key_backspace.xml b/packages/SystemUI/res/drawable/ic_ksh_key_backspace.xml
    +index 6519673..1183203 100644
    +--- a/packages/SystemUI/res/drawable/ic_ksh_key_backspace.xml
    ++++ b/packages/SystemUI/res/drawable/ic_ksh_key_backspace.xml
    +@@ -19,7 +19,6 @@
    +         android:height="24dp"
    +         android:viewportWidth="24"
    +         android:viewportHeight="24">
    +-    <path android:pathData="M0 0h24v24H0z" />
    +     <path android:fillColor="@color/ksh_key_item_color"
    +             android:pathData="M22 3H7c-.69 0-1.23 .35 -1.59 .88 L0 12l5.41 8.11c.36 .53 .9 .89
    + 1.59 .89 h15c1.1 0 2-.9 2-2V5c0-1.1-.9-2-2-2zm-3 12.59L17.59 17 14 13.41 10.41 17 9 15.59
    +diff --git a/packages/SystemUI/res/drawable/ic_ksh_key_enter.xml b/packages/SystemUI/res/drawable/ic_ksh_key_enter.xml
    +index 599f350..66b1307 100644
    +--- a/packages/SystemUI/res/drawable/ic_ksh_key_enter.xml
    ++++ b/packages/SystemUI/res/drawable/ic_ksh_key_enter.xml
    +@@ -19,7 +19,6 @@
    +         android:height="24dp"
    +         android:viewportWidth="24"
    +         android:viewportHeight="24">
    +-    <path android:pathData="M0 0h24v24H0z" />
    +    <path android:fillColor="@color/ksh_key_item_color"
    +             android:pathData="M19 7v4H5.83l3.58-3.59L8 6l-6 6 6 6 1.41-1.41L5.83 13H21V7z" />
    + </vector>
    +diff --git a/packages/SystemUI/res/drawable/ic_ksh_key_left.xml b/packages/SystemUI/res/drawable/ic_ksh_key_left.xml
    +index 038187e..57d0423 100644
    +--- a/packages/SystemUI/res/drawable/ic_ksh_key_left.xml
    ++++ b/packages/SystemUI/res/drawable/ic_ksh_key_left.xml
    +@@ -21,5 +21,4 @@
    +         android:viewportHeight="24">
    +     <path android:fillColor="@color/ksh_key_item_color"
    +             android:pathData="M15.41 7.41L14 6l-6 6 6 6 1.41-1.41L10.83 12z" />
    +-    <path android:pathData="M0 0h24v24H0z" />
    + </vector>
    +diff --git a/packages/SystemUI/res/drawable/ic_ksh_key_meta.xml b/packages/SystemUI/res/drawable/ic_ksh_key_meta.xml
    +index 1e2195e..be8fe8c 100644
    +--- a/packages/SystemUI/res/drawable/ic_ksh_key_meta.xml
    ++++ b/packages/SystemUI/res/drawable/ic_ksh_key_meta.xml
    +@@ -24,5 +24,4 @@
    + 3 9.5 5.91 16 9.5 16c1.61 0 3.09-.59 4.23-1.57l.27 .28 v.79l5 4.99L20.49
    + 19l-4.99-5zm-6 0C7.01 14 5 11.99 5 9.5S7.01 5 9.5 5 14 7.01 14 9.5 11.99 14 9.5
    + 14z" />
    +-    <path android:pathData="M0 0h24v24H0z" />
    + </vector>
    +diff --git a/packages/SystemUI/res/drawable/ic_ksh_key_right.xml b/packages/SystemUI/res/drawable/ic_ksh_key_right.xml
    +index f2d7315..720d4e4 100644
    +--- a/packages/SystemUI/res/drawable/ic_ksh_key_right.xml
    ++++ b/packages/SystemUI/res/drawable/ic_ksh_key_right.xml
    +@@ -21,5 +21,4 @@
    +         android:viewportHeight="24">
    +     <path android:fillColor="@color/ksh_key_item_color"
    +             android:pathData="M10 6L8.59 7.41 13.17 12l-4.58 4.59L10 18l6-6z" />
    +-    <path android:pathData="M0 0h24v24H0z" />
    + </vector>
    +diff --git a/packages/SystemUI/res/drawable/ic_ksh_key_up.xml b/packages/SystemUI/res/drawable/ic_ksh_key_up.xml
    +index 36a83b1..350c994 100644
    +--- a/packages/SystemUI/res/drawable/ic_ksh_key_up.xml
    ++++ b/packages/SystemUI/res/drawable/ic_ksh_key_up.xml
    +@@ -21,5 +21,4 @@
    +         android:viewportHeight="24">
    +     <path android:fillColor="@color/ksh_key_item_color"
    +             android:pathData="M7.41 15.41L12 10.83l4.59 4.58L18 14l-6-6-6 6z" />
    +-    <path android:pathData="M0 0h24v24H0z" />
    + </vector>
    +diff --git a/packages/SystemUI/res/drawable/ic_pause_white_24dp.xml b/packages/SystemUI/res/drawable/ic_pause_white_24dp.xml
    +index d9a4f7b..5b65f10 100644
    +--- a/packages/SystemUI/res/drawable/ic_pause_white_24dp.xml
    ++++ b/packages/SystemUI/res/drawable/ic_pause_white_24dp.xml
    +@@ -22,6 +22,4 @@ Copyright (C) 2016 The Android Open Source Project
    +     <path
    +         android:fillColor="#FFFFFF"
    +         android:pathData="M6 19h4V5H6v14zm8-14v14h4V5h-4z" />
    +-    <path
    +-        android:pathData="M0 0h24v24H0z" />
    + </vector>
    +diff --git a/packages/SystemUI/res/drawable/ic_play_arrow_white_24dp.xml b/packages/SystemUI/res/drawable/ic_play_arrow_white_24dp.xml
    +index b8fa99e..ddc9e8d 100644
    +--- a/packages/SystemUI/res/drawable/ic_play_arrow_white_24dp.xml
    ++++ b/packages/SystemUI/res/drawable/ic_play_arrow_white_24dp.xml
    +@@ -22,6 +22,4 @@ Copyright (C) 2016 The Android Open Source Project
    +     <path
    +         android:fillColor="#FFFFFF"
    +         android:pathData="M8 5v14l11-7z" />
    +-    <path
    +-        android:pathData="M0 0h24v24H0z" />
    + </vector>
    +diff --git a/packages/SystemUI/res/drawable/ic_qs_data_disabled.xml b/packages/SystemUI/res/drawable/ic_qs_data_disabled.xml
    +index b4144a3..d11b6f4 100644
    +--- a/packages/SystemUI/res/drawable/ic_qs_data_disabled.xml
    ++++ b/packages/SystemUI/res/drawable/ic_qs_data_disabled.xml
    +@@ -14,8 +14,9 @@
    +     limitations under the License.
    + -->
    + <vector xmlns:android="http://schemas.android.com/apk/res/android"
    +-        android:width="24.0dp"
    +-        android:height="24.0dp"
    ++        android:autoMirrored="true"
    ++        android:width="32.0dp"
    ++        android:height="32.0dp"
    +         android:viewportWidth="40.0"
    +         android:viewportHeight="40.0">
    +     <path
    +diff --git a/packages/SystemUI/res/drawable/ic_qs_wifi_disconnected.xml b/packages/SystemUI/res/drawable/ic_qs_wifi_disconnected.xml
    +index 4d2a35e..2dcdb71 100644
    +--- a/packages/SystemUI/res/drawable/ic_qs_wifi_disconnected.xml
    ++++ b/packages/SystemUI/res/drawable/ic_qs_wifi_disconnected.xml
    +@@ -19,9 +19,6 @@
    +         android:viewportWidth="26.0"
    +         android:viewportHeight="24.0">
    +     <path
    +-        android:pathData="M0 0h26v24H0z"
    +-        android:fillColor="#00000000"/>
    +-    <path
    +         android:fillColor="#FFFFFFFF"
    +         android:pathData="M21.0,8.5
    +         c0.85,0.0 1.6,0.23 2.3,0.62l2.24,-2.79
    +diff --git a/packages/SystemUI/res/drawable/ic_send.xml b/packages/SystemUI/res/drawable/ic_send.xml
    +index 6ce3672..7cac2a4 100644
    +--- a/packages/SystemUI/res/drawable/ic_send.xml
    ++++ b/packages/SystemUI/res/drawable/ic_send.xml
    +@@ -22,7 +22,4 @@ Copyright (C) 2014 The Android Open Source Project
    +     <path
    +         android:fillColor="#FF000000"
    +         android:pathData="M4.02,42.0L46.0,24.0 4.02,6.0 4.0,20.0l30.0,4.0 -30.0,4.0z"/>
    +-    <path
    +-        android:pathData="M0 0h48v48H0z"
    +-        android:fillColor="#00000000"/>
    + </vector>
    +diff --git a/packages/SystemUI/res/drawable/stat_sys_data_disabled.xml b/packages/SystemUI/res/drawable/stat_sys_data_disabled.xml
    +index 4e2a024..694019e 100644
    +--- a/packages/SystemUI/res/drawable/stat_sys_data_disabled.xml
    ++++ b/packages/SystemUI/res/drawable/stat_sys_data_disabled.xml
    +@@ -14,9 +14,9 @@
    +     limitations under the License.
    + -->
    + <vector xmlns:android="http://schemas.android.com/apk/res/android"
    +-        android:width="17.0dp"
    ++        android:width="8.5dp"
    +         android:height="17.0dp"
    +-        android:viewportWidth="40.0"
    ++        android:viewportWidth="20.0"
    +         android:viewportHeight="40.0">
    +     <path
    +         android:fillColor="#FFFFFFFF"
    +diff --git a/packages/SystemUI/res/layout/emergency_cryptkeeper_text.xml b/packages/SystemUI/res/layout/emergency_cryptkeeper_text.xml
    +new file mode 100644
    +index 0000000..0a1730a
    +--- /dev/null
    ++++ b/packages/SystemUI/res/layout/emergency_cryptkeeper_text.xml
    +@@ -0,0 +1,28 @@
    ++<?xml version="1.0" encoding="utf-8"?>
    ++<!--
    ++  ~ Copyright (C) 2016 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
    ++  -->
    ++
    ++<com.android.systemui.statusbar.policy.EmergencyCryptkeeperText
    ++        xmlns:android="http://schemas.android.com/apk/res/android"
    ++        android:id="@+id/emergency_cryptkeeper_text"
    ++        android:layout_width="wrap_content"
    ++        android:layout_height="match_parent"
    ++        android:textAppearance="@style/TextAppearance.StatusBar.Clock"
    ++        android:paddingStart="6dp"
    ++        android:singleLine="true"
    ++        android:ellipsize="marquee"
    ++        android:gravity="center_vertical|start"
    ++        />
    +\ No newline at end of file
    +diff --git a/packages/SystemUI/res/layout/notification_guts.xml b/packages/SystemUI/res/layout/notification_guts.xml
    +index e84ed23..17bade4 100644
    +--- a/packages/SystemUI/res/layout/notification_guts.xml
    ++++ b/packages/SystemUI/res/layout/notification_guts.xml
    +@@ -91,6 +91,16 @@
    +                 style="@style/TextAppearance.NotificationGuts.Radio"
    +                 android:buttonTint="@color/notification_guts_buttons" />
    +     </RadioGroup>
    ++    <!-- When neither blocking or silencing is available -->
    ++    <TextView
    ++        android:id="@+id/cant_silence_or_block"
    ++        android:layout_width="match_parent"
    ++        android:layout_height="48dp"
    ++        android:gravity="center_vertical"
    ++        style="@style/TextAppearance.NotificationGuts.Radio"
    ++        android:text="@string/cant_silence_or_block"
    ++        android:visibility="gone"
    ++        />
    +     <!-- Importance slider -->
    +     <LinearLayout
    +             android:id="@+id/importance_slider"
    +diff --git a/packages/SystemUI/res/layout/recents_task_view.xml b/packages/SystemUI/res/layout/recents_task_view.xml
    +index 1978a93..c8e5b61 100644
    +--- a/packages/SystemUI/res/layout/recents_task_view.xml
    ++++ b/packages/SystemUI/res/layout/recents_task_view.xml
    +@@ -30,8 +30,8 @@
    +         android:id="@+id/lock_to_app_fab"
    +         android:layout_width="@dimen/recents_lock_to_app_size"
    +         android:layout_height="@dimen/recents_lock_to_app_size"
    +-        android:layout_gravity="bottom|right"
    +-        android:layout_marginRight="15dp"
    ++        android:layout_gravity="bottom|end"
    ++        android:layout_marginEnd="15dp"
    +         android:layout_marginBottom="15dp"
    +         android:translationZ="4dp"
    +         android:contentDescription="@string/recents_lock_to_app_button_label"
    +diff --git a/packages/SystemUI/res/layout/remote_input.xml b/packages/SystemUI/res/layout/remote_input.xml
    +index f0c4e59..73f26e2 100644
    +--- a/packages/SystemUI/res/layout/remote_input.xml
    ++++ b/packages/SystemUI/res/layout/remote_input.xml
    +@@ -42,7 +42,7 @@
    +             android:singleLine="true"
    +             android:ellipsize="start"
    +             android:inputType="textShortMessage|textAutoCorrect|textCapSentences"
    +-            android:imeOptions="actionNone|flagNoExtractUi" />
    ++            android:imeOptions="actionNone|flagNoExtractUi|flagNoFullscreen" />
    + 
    +     <FrameLayout
    +             android:layout_width="wrap_content"
    +diff --git a/packages/SystemUI/res/layout/status_bar.xml b/packages/SystemUI/res/layout/status_bar.xml
    +index 39c16d7..63af3e0 100644
    +--- a/packages/SystemUI/res/layout/status_bar.xml
    ++++ b/packages/SystemUI/res/layout/status_bar.xml
    +@@ -77,4 +77,11 @@
    +         </com.android.keyguard.AlphaOptimizedLinearLayout>
    +     </LinearLayout>
    + 
    ++    <ViewStub
    ++        android:id="@+id/emergency_cryptkeeper_text"
    ++        android:layout_width="wrap_content"
    ++        android:layout_height="match_parent"
    ++        android:layout="@layout/emergency_cryptkeeper_text"
    ++    />
    ++
    + </com.android.systemui.statusbar.phone.PhoneStatusBarView>
    +diff --git a/packages/SystemUI/res/values-af/strings.xml b/packages/SystemUI/res/values-af/strings.xml
    +index 546698c..fbd523f 100644
    +--- a/packages/SystemUI/res/values-af/strings.xml
    ++++ b/packages/SystemUI/res/values-af/strings.xml
    +@@ -238,7 +238,7 @@
    +     <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"4G-data is laat wag"</string>
    +     <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"Sellulêre data is onderbreek"</string>
    +     <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"Data is onderbreek"</string>
    +-    <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"Omdat die gestelde dataperk bereik is, het die toestel datagebruik vir die res van hierdie siklus onderbreek.\n\nAs dit hervat word, kan dit tot heffings deur jou diensverskaffer lei."</string>
    ++    <string name="data_usage_disabled_dialog" msgid="1841738975235283398">"Jy het die datalimiet wat jy gestel het, bereik. Jy gebruik nie meer sellulêre data nie.\n\nAs jy voortgaan, kan heffings vir datagebruik geld."</string>
    +     <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"Hervat"</string>
    +     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Geen internetverbinding nie"</string>
    +     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi gekoppel"</string>
    +@@ -404,6 +404,7 @@
    +     <string name="device_owned_footer" msgid="3802752663326030053">"Toestel kan gemonitor word"</string>
    +     <string name="profile_owned_footer" msgid="8021888108553696069">"Profiel kan gemonitor word"</string>
    +     <string name="vpn_footer" msgid="2388611096129106812">"Netwerk kan dalk gemonitor word"</string>
    ++    <string name="branded_vpn_footer" msgid="2168111859226496230">"Netwerk kan dalk gemonitor word"</string>
    +     <string name="monitoring_title_device_owned" msgid="7121079311903859610">"Toestelmonitering"</string>
    +     <string name="monitoring_title_profile_owned" msgid="6790109874733501487">"Profielmonitering"</string>
    +     <string name="monitoring_title" msgid="169206259253048106">"Netwerkmonitering"</string>
    +@@ -416,6 +417,7 @@
    +     <string name="legacy_vpn_name" msgid="6604123105765737830">"VPN"</string>
    +     <string name="monitoring_description_app" msgid="6259179342284742878">"Jy is gekoppel aan <xliff:g id="APPLICATION">%1$s</xliff:g>, wat jou netwerkaktiwiteit, insluitend e-posse, programme en webwerwe, kan monitor."</string>
    +     <string name="monitoring_description_app_personal" msgid="484599052118316268">"Jy is gekoppel aan <xliff:g id="APPLICATION">%1$s</xliff:g>, wat jou persoonlike netwerkaktiwiteit, insluitend e-posse, programme en webwerwe, kan monitor."</string>
    ++    <string name="branded_monitoring_description_app_personal" msgid="2669518213949202599">"Jy is gekoppel aan <xliff:g id="APPLICATION">%1$s</xliff:g>, wat jou persoonlike netwerkaktiwiteit, insluitend e-posse, programme en webwerwe, kan monitor."</string>
    +     <string name="monitoring_description_app_work" msgid="1754325860918060897">"Jou werkprofiel word deur <xliff:g id="ORGANIZATION">%1$s</xliff:g> bestuur. Dit is gekoppel aan <xliff:g id="APPLICATION">%2$s</xliff:g>, wat jou werknetwerkaktiwiteit, insluitend e-posse, programme en webwerwe, kan monitor.\n\nKontak jou administrateur vir meer inligting."</string>
    +     <string name="monitoring_description_app_personal_work" msgid="4946600443852045903">"Jou werkprofiel word deur <xliff:g id="ORGANIZATION">%1$s</xliff:g> bestuur. Dit is gekoppel aan <xliff:g id="APPLICATION_WORK">%2$s</xliff:g>, wat jou werknetwerkaktiwiteit, insluitend e-posse, programme en webwerwe, kan monitor.\n\nJy is ook gekoppel aan <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g>, wat jou persoonlike netwerkaktiwiteit kan monitor."</string>
    +     <string name="monitoring_description_vpn_app_device_owned" msgid="4970443827043261703">"Jou toestel word bestuur deur <xliff:g id="ORGANIZATION">%1$s</xliff:g>\n\nJou administrateur kan instelings, korporatiewe toegang, programme, data wat met jou toestel geassosieer word en jou toestel se ligginginligting monitor en bestuur.\n\nJy is gekoppel aan <xliff:g id="APPLICATION">%2$s</xliff:g>, wat jou netwerkaktiwiteit, insluitend e-posse, programme en webwerwe, kan monitor.\n\nVir meer inligting, kontak jou administrateur."</string>
    +@@ -492,8 +494,6 @@
    +     <string name="clock_seconds_desc" msgid="6282693067130470675">"Wys horlosiesekondes op die statusbalk. Sal batterylewe dalk beïnvloed."</string>
    +     <string name="qs_rearrange" msgid="8060918697551068765">"Herrangskik Kitsinstellings"</string>
    +     <string name="show_brightness" msgid="6613930842805942519">"Wys helderheid in Kitsinstellings"</string>
    +-    <string name="overview_nav_bar_gesture" msgid="8579814204727917764">"Aktiveer die verdeling van die skerm deur op te swiep"</string>
    +-    <string name="overview_nav_bar_gesture_desc" msgid="6329167382305102615">"Aktiveer gebaar om skerm te verdeel deur van die Oorsig-knoppie af op te swiep"</string>
    +     <string name="experimental" msgid="6198182315536726162">"Eksperimenteel"</string>
    +     <string name="enable_bluetooth_title" msgid="5027037706500635269">"Skakel Bluetooth aan?"</string>
    +     <string name="enable_bluetooth_message" msgid="9106595990708985385">"Jy moet Bluetooth aanskakel om jou sleutelbord aan jou tablet te koppel."</string>
    +@@ -651,4 +651,5 @@
    +     <string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"Maak <xliff:g id="ID_1">%s</xliff:g>-instellings oop."</string>
    +     <string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"Wysig volgorde van instellings."</string>
    +     <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"Bladsy <xliff:g id="ID_1">%1$d</xliff:g> van <xliff:g id="ID_2">%2$d</xliff:g>"</string>
    ++    <string name="cant_silence_or_block" msgid="999689262131488625">"Kennisgewings kan nie stilgemaak of geblokkeer word nie"</string>
    + </resources>
    +diff --git a/packages/SystemUI/res/values-am/strings.xml b/packages/SystemUI/res/values-am/strings.xml
    +index bd4afe1..98f09f4 100644
    +--- a/packages/SystemUI/res/values-am/strings.xml
    ++++ b/packages/SystemUI/res/values-am/strings.xml
    +@@ -238,7 +238,7 @@
    +     <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"4ጂ ውሂብ ላፍታ ቆሟል"</string>
    +     <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"የተንቀሳቃሽ ስልክ ውሂብ ላፍታ ቆሟል"</string>
    +     <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"ውሂብ ላፍታ ቆሟል"</string>
    +-    <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"የእርስዎ የተዋቀረው የውሂብ ገደብ ላይ ስለተደረሰ፣ የዚህን ዑደት አጠቃቀም ለማስታወስ መሣሪያው ላፍታ ቆሟል።\n\nከቆመበት ማስቀጠሉ ከእርስዎ የአገልግሎት አቅራቢ ክፍያን ሊያስጠይቅዎት ይችላል።"</string>
    ++    <string name="data_usage_disabled_dialog" msgid="1841738975235283398">"እርስዎ ያስቀመጡት የውሂብ ገደብ ላይ ተደርሷል። ከእንግዲህ ተንቀሳቃሽ ውሂብ እየተጠቀሙ አይደለም ያሉት።\n\nከቆመበት ከቀጠሉ የውሂብ አጠቃቀም ክፍያዎች ተፈጻሚ ሊሆኑ ይችላሉ።"</string>
    +     <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"ከቆመበት ቀጥል"</string>
    +     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"ምንም በይነመረብ ተያያዥ የለም።"</string>
    +     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi ተያይዟል"</string>
    +@@ -404,6 +404,7 @@
    +     <string name="device_owned_footer" msgid="3802752663326030053">"መሣሪያው ክትትል የሚደረግበት ሊሆን ይችላል"</string>
    +     <string name="profile_owned_footer" msgid="8021888108553696069">"መገለጫ ክትትል ሊደረግበት ይችላል"</string>
    +     <string name="vpn_footer" msgid="2388611096129106812">"አውታረ መረብ በክትትል እየተደረገበት ሊሆን ይችላል"</string>
    ++    <string name="branded_vpn_footer" msgid="2168111859226496230">"አውታረ መረብ ክትትል የሚደረግበት ሊሆን ይችላል"</string>
    +     <string name="monitoring_title_device_owned" msgid="7121079311903859610">"የመሣሪያ ክትትል"</string>
    +     <string name="monitoring_title_profile_owned" msgid="6790109874733501487">"መገለጫን መከታተል"</string>
    +     <string name="monitoring_title" msgid="169206259253048106">"የአውታረ መረብ ክትትል"</string>
    +@@ -416,6 +417,7 @@
    +     <string name="legacy_vpn_name" msgid="6604123105765737830">"VPN"</string>
    +     <string name="monitoring_description_app" msgid="6259179342284742878">"እርስዎ ኢሜይሎችን፣ መተግበሪያዎችን እና ድር ጣቢያዎችንም ጨምሮ የአውታረ መረብ እንቅስቃሴዎን መከታተል ከሚችለው <xliff:g id="APPLICATION">%1$s</xliff:g> ጋር ተገናኝተዋል።"</string>
    +     <string name="monitoring_description_app_personal" msgid="484599052118316268">"እርስዎ ኢሜይሎችን፣ መተግበሪያዎችን እና ድር ጣቢያዎችንም ጨምሮ የግል የአውታረ መረብ እንቅስቃሴዎን መከታተል ከሚችለው <xliff:g id="APPLICATION">%1$s</xliff:g> ጋር ተገናኝተዋል።"</string>
    ++    <string name="branded_monitoring_description_app_personal" msgid="2669518213949202599">"እርስዎ ኢሜይሎችን፣ መተግበሪያዎችን እና ድር ጣቢያዎችንም ጨምሮ የግል የአውታረ መረብ እንቅስቃሴዎን ከሚከታተለው ከ<xliff:g id="APPLICATION">%1$s</xliff:g> ጋር ተገናኝተዋል።"</string>
    +     <string name="monitoring_description_app_work" msgid="1754325860918060897">"የስራ መገለጫዎ በ<xliff:g id="ORGANIZATION">%1$s</xliff:g> ነው እየተዳደረ ያለው። ኢሜይሎችን፣ መተግበሪያዎችን እና ድር ጣቢያዎችንም ጨምሮ የአውታረ መረብ እንቅስቃሴዎን መከታተል ከሚችለው <xliff:g id="APPLICATION">%2$s</xliff:g> ጋር ተገናኝተዋል።\n\nተጨማሪ መረጃ ለማግኘት አስተዳዳሪዎን ያነጋግሩ።"</string>
    +     <string name="monitoring_description_app_personal_work" msgid="4946600443852045903">"የስራ መገለጫዎ በ<xliff:g id="ORGANIZATION">%1$s</xliff:g> ነው እየተዳደረ ያለው። ኢሜይሎችን፣ መተግበሪያዎችን እና ድር ጣቢያዎችንም ጨምሮ የአውታረ መረብ እንቅስቃሴዎን መከታተል ከሚችለው <xliff:g id="APPLICATION_WORK">%2$s</xliff:g> ጋር ተገናኝተዋል።\n\nእንዲሁም የግል አውታረ መረብ እንቅስቃሴዎን መከታተል ከሚችለው <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g> ጋርም ተገናኝተዋል።"</string>
    +     <string name="monitoring_description_vpn_app_device_owned" msgid="4970443827043261703">"የእርስዎ መሣሪያ በ<xliff:g id="ORGANIZATION">%1$s</xliff:g> ነው የሚተዳደረው።\n\nየእርስዎ አስተዳዳሪ ቅንብሮችን፣ የኮርፖሬት መዳረሻን፣ መተግበሪያዎችን፣ ከመሣሪያዎ ጋር የተጎዳኘ ውሂብን እና የመሣሪያዎ የአካባቢ መረጃን መከታተል እና ማቀናበር ይችላል።\n\nእርስዎ ኢሜይሎችን፣ መተግበሪያዎችን እና ድር ጣቢያዎችን  ጨምሮ የአውታረ መረብ እንቅስቃሴዎን መከታተል ከሚችለው <xliff:g id="APPLICATION">%2$s</xliff:g> ጋር ተገናኝተዋል።\n\nተጨማሪ መረጃ ለማግኘት አስተዳዳሪዎን ያነጋግሩ።"</string>
    +@@ -492,8 +494,6 @@
    +     <string name="clock_seconds_desc" msgid="6282693067130470675">"የሰዓት ሰከንዶችን በሁኔታ አሞሌ ውስጥ አሳይ። በባትሪ ዕድሜ ላይ ተጽዕኖ ሊኖርው ይችል ይሆናል።"</string>
    +     <string name="qs_rearrange" msgid="8060918697551068765">"ፈጣን ቅንብሮችን ዳግም ያደራጁ"</string>
    +     <string name="show_brightness" msgid="6613930842805942519">"በፈጣን ቅንብሮች ውስጥ ብሩህነትን አሳይ"</string>
    +-    <string name="overview_nav_bar_gesture" msgid="8579814204727917764">"የተከፈለ ማያ ገጽ ወደ ላይ የማንሸራተት ጣት ምልክትን ያንቁ"</string>
    +-    <string name="overview_nav_bar_gesture_desc" msgid="6329167382305102615">"ከአጠቃላይ እይታ አዝራሩ ወደ ላይ በማንሸራተት ወደ የተከፈለ ማያ ገጽ የሚገቡበትን የጣት ምልክት ያንቁ"</string>
    +     <string name="experimental" msgid="6198182315536726162">"የሙከራ"</string>
    +     <string name="enable_bluetooth_title" msgid="5027037706500635269">"ብሉቱዝ ይብራ?"</string>
    +     <string name="enable_bluetooth_message" msgid="9106595990708985385">"የቁልፍ ሰሌዳዎን ከእርስዎ ጡባዊ ጋር ለማገናኘት በመጀመሪያ ብሉቱዝን ማብራት አለብዎት።"</string>
    +@@ -651,4 +651,5 @@
    +     <string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"የ<xliff:g id="ID_1">%s</xliff:g> ቅንብሮችን ክፈት።"</string>
    +     <string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"የቅንብሮድ ቅደም-ተከተል አርትዕ።"</string>
    +     <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"ገጽ <xliff:g id="ID_1">%1$d</xliff:g> ከ <xliff:g id="ID_2">%2$d</xliff:g>"</string>
    ++    <string name="cant_silence_or_block" msgid="999689262131488625">"ማሳወቂያዎች ላይ ድምጸ-ከል ማድረግ ወይም ማገድ አይቻልም"</string>
    + </resources>
    +diff --git a/packages/SystemUI/res/values-ar/strings.xml b/packages/SystemUI/res/values-ar/strings.xml
    +index eca668e..c954e41 100644
    +--- a/packages/SystemUI/res/values-ar/strings.xml
    ++++ b/packages/SystemUI/res/values-ar/strings.xml
    +@@ -242,7 +242,7 @@
    +     <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"تم إيقاف بيانات شبكة الجيل الرابع مؤقتًا"</string>
    +     <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"تم إيقاف بيانات شبكة الجوّال مؤقتًا"</string>
    +     <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"تم إيقاف البيانات مؤقتًا"</string>
    +-    <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"نظرًا لأنك بلغت الحد الأقصى المحدد للبيانات، فقد أوقف الجهاز استخدام البيانات مؤقتًا في بقية هذه الدورة.\n\nومن الممكن أن يؤدي الاستئناف إلى تحصيل رسوم من قِبل مشغِّل شبكة الجوّال."</string>
    ++    <string name="data_usage_disabled_dialog" msgid="1841738975235283398">"تم الوصول إلى حد البيانات الذي عيَّنته، ولم يعد بإمكانك استخدام بيانات شبكة الجوّال.\n\nعند الاستئناف، قد يتم تحصيل رسوم مقابل استخدام البيانات."</string>
    +     <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"استئناف"</string>
    +     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"لا يوجد اتصال إنترنت"</string>
    +     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"‏Wi-Fi متصل"</string>
    +@@ -412,6 +412,7 @@
    +     <string name="device_owned_footer" msgid="3802752663326030053">"ربما تتم مراقبة الجهاز"</string>
    +     <string name="profile_owned_footer" msgid="8021888108553696069">"ربما تتم مراقبة الملف الشخصي"</string>
    +     <string name="vpn_footer" msgid="2388611096129106812">"قد تكون الشبكة خاضعة للمراقبة"</string>
    ++    <string name="branded_vpn_footer" msgid="2168111859226496230">"قد تكون الشبكة خاضعة للمراقبة"</string>
    +     <string name="monitoring_title_device_owned" msgid="7121079311903859610">"مراقبة الأجهزة"</string>
    +     <string name="monitoring_title_profile_owned" msgid="6790109874733501487">"مراقبة الملف الشخصي"</string>
    +     <string name="monitoring_title" msgid="169206259253048106">"مراقبة الشبكات"</string>
    +@@ -424,6 +425,7 @@
    +     <string name="legacy_vpn_name" msgid="6604123105765737830">"شبكة ظاهرية خاصة"</string>
    +     <string name="monitoring_description_app" msgid="6259179342284742878">"أنت متصل بـ <xliff:g id="APPLICATION">%1$s</xliff:g>، الذي يمكنه مراقبة أنشطتك على الشبكة، بما في ذلك الرسائل الإلكترونية والتطبيقات ومواقع الويب."</string>
    +     <string name="monitoring_description_app_personal" msgid="484599052118316268">"أنت متصل بـ <xliff:g id="APPLICATION">%1$s</xliff:g>، الذي يمكنه مراقبة أنشطتك الشخصية على الشبكة، بما في ذلك الرسائل الإلكترونية والتطبيقات ومواقع الويب."</string>
    ++    <string name="branded_monitoring_description_app_personal" msgid="2669518213949202599">"أنت متصل بـ <xliff:g id="APPLICATION">%1$s</xliff:g>، الذي يمكنه مراقبة أنشطتك الشخصية على الشبكة، بما في ذلك الرسائل الإلكترونية والتطبيقات ومواقع الويب."</string>
    +     <string name="monitoring_description_app_work" msgid="1754325860918060897">"تتم إدارة ملفك الشخصي للعمل عن طريق <xliff:g id="ORGANIZATION">%1$s</xliff:g>. وهذا الملف الشخصي للعمل متصل بـ <xliff:g id="APPLICATION">%2$s</xliff:g>، الذي يمكنه مراقبة أنشطتك على شبكة العمل، بما في ذلك الرسائل الإلكترونية والتطبيقات ومواقع الويب.\n\nللمزيد من المعلومات، اتصل بالمشرف."</string>
    +     <string name="monitoring_description_app_personal_work" msgid="4946600443852045903">"تتم إدارة ملفك الشخصي للعمل عن طريق <xliff:g id="ORGANIZATION">%1$s</xliff:g>. وهذا الملف الشخصي للعمل متصل بـ <xliff:g id="APPLICATION_WORK">%2$s</xliff:g>، الذي يمكنه مراقبة أنشطتك على شبكة العمل، بما في ذلك الرسائل الإلكترونية والتطبيقات ومواقع الويب.\n\nأنت متصل أيضًا بـ <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g>، الذي يمكنه مراقبة أنشطتك الشخصية على الشبكة."</string>
    +     <string name="monitoring_description_vpn_app_device_owned" msgid="4970443827043261703">"تتم إدارة جهازك عن طريق <xliff:g id="ORGANIZATION">%1$s</xliff:g>.\n\nيمكن للمشرف مراقبة وإدارة كل من الإعدادات والوصول إلى الشركة والتطبيقات والبيانات المرتبطة بجهازك ومعلومات الموقع لجهازك.\n\nأنت متصل بـ <xliff:g id="APPLICATION">%2$s</xliff:g>، الذي يمكنه مراقبة أنشطتك على الشبكة، بما في ذلك الرسائل الإلكترونية والتطبيقات ومواقع الويب.\n\nللمزيد من المعلومات، اتصل بالمشرف."</string>
    +@@ -500,8 +502,6 @@
    +     <string name="clock_seconds_desc" msgid="6282693067130470675">"عرض ثواني الساعة في شريط الحالة. قد يؤثر ذلك في عمر البطارية."</string>
    +     <string name="qs_rearrange" msgid="8060918697551068765">"إعادة ترتيب الإعدادات السريعة"</string>
    +     <string name="show_brightness" msgid="6613930842805942519">"عرض السطوع في الإعدادات السريعة"</string>
    +-    <string name="overview_nav_bar_gesture" msgid="8579814204727917764">"تمكين إيماءة تقسيم الشاشة بالتمرير السريع لأعلى"</string>
    +-    <string name="overview_nav_bar_gesture_desc" msgid="6329167382305102615">"تمكين الإيماء لإدخال تقسيم الشاشة من خلال التمرير السريع لأعلى من زر النظرة العامة"</string>
    +     <string name="experimental" msgid="6198182315536726162">"إعدادات تجريبية"</string>
    +     <string name="enable_bluetooth_title" msgid="5027037706500635269">"تشغيل البلوتوث؟"</string>
    +     <string name="enable_bluetooth_message" msgid="9106595990708985385">"لتوصيل لوحة المفاتيح بالجهاز اللوحي، يلزمك تشغيل بلوتوث أولاً."</string>
    +@@ -659,4 +659,5 @@
    +     <string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"فتح إعدادات <xliff:g id="ID_1">%s</xliff:g>."</string>
    +     <string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"تعديل ترتيب الإعدادات."</string>
    +     <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"الصفحة <xliff:g id="ID_1">%1$d</xliff:g> من <xliff:g id="ID_2">%2$d</xliff:g>"</string>
    ++    <string name="cant_silence_or_block" msgid="999689262131488625">"لا يمكن كتم صوت الإشعارات أو حظرها"</string>
    + </resources>
    +diff --git a/packages/SystemUI/res/values-az-rAZ/strings.xml b/packages/SystemUI/res/values-az-rAZ/strings.xml
    +index 3d9cc4a..d2f93d2 100644
    +--- a/packages/SystemUI/res/values-az-rAZ/strings.xml
    ++++ b/packages/SystemUI/res/values-az-rAZ/strings.xml
    +@@ -238,7 +238,7 @@
    +     <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"4G məlumatlarına fasilə verildi"</string>
    +     <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"Mobil məlumatlara fasilə verildi"</string>
    +     <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"Məlumatlara fasilə verildi"</string>
    +-    <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"Məlumatlar dəsti limitinizi keçdiyiniz üçün cihaz bu dövrənin qalan hissəsi üçün məlumatların istifadəsinə fasilə verib.\n\nDavam etmək operaturunuzdan xərclərə səbəb ola bilər."</string>
    ++    <string name="data_usage_disabled_dialog" msgid="1841738975235283398">"Daha limitini keçdiniz. Artıq mobil data istifadə etmirsiniz.\n\nDavam etsəniz, data istifadəsi üçün ödəniş tətbiq oluna bilər."</string>
    +     <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"Davam et"</string>
    +     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"İnternet bağlantısı yoxdur"</string>
    +     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi qoşulub"</string>
    +@@ -404,6 +404,7 @@
    +     <string name="device_owned_footer" msgid="3802752663326030053">"Cihaz nəzarət altında ola bilər"</string>
    +     <string name="profile_owned_footer" msgid="8021888108553696069">"Profil izlənə bilər"</string>
    +     <string name="vpn_footer" msgid="2388611096129106812">"Şəbəkə nəzərdən keçirilə bilər"</string>
    ++    <string name="branded_vpn_footer" msgid="2168111859226496230">"Şəbəkə nəzərdən keçirilə bilər"</string>
    +     <string name="monitoring_title_device_owned" msgid="7121079311903859610">"Cihaza nəzarət"</string>
    +     <string name="monitoring_title_profile_owned" msgid="6790109874733501487">"Profil izlənməsi"</string>
    +     <string name="monitoring_title" msgid="169206259253048106">"Şəbəkə monitorinqi"</string>
    +@@ -416,6 +417,7 @@
    +     <string name="legacy_vpn_name" msgid="6604123105765737830">"VPN (Virtual Şəxsi Şəbəkələr)"</string>
    +     <string name="monitoring_description_app" msgid="6259179342284742878">"<xliff:g id="APPLICATION">%1$s</xliff:g> tətbiqinə qoşulmusunuz və o, e-məktublar, tətbiq və veb saytlar daxil olmaqla şəbəkə fəaliyyətinizə nəzarət edə bilər."</string>
    +     <string name="monitoring_description_app_personal" msgid="484599052118316268">"<xliff:g id="APPLICATION">%1$s</xliff:g> tətbiqinə qoşulmusunuz və o, e-məktublar, tətbiq və veb saytlar daxil olmaqla şəxsi şəbəkə fəaliyyətinizə nəzarət edə bilər."</string>
    ++    <string name="branded_monitoring_description_app_personal" msgid="2669518213949202599">"<xliff:g id="APPLICATION">%1$s</xliff:g> tətbiqinə qoşulmusunuz və o, e-məktublar, tətbiq və veb saytlar daxil olmaqla şəxsi şəbəkə fəaliyyətinizə nəzarət edə bilər."</string>
    +     <string name="monitoring_description_app_work" msgid="1754325860918060897">"İş profiliniz <xliff:g id="ORGANIZATION">%1$s</xliff:g> tərəfindən idarə olunur. <xliff:g id="APPLICATION">%2$s</xliff:g> tətbiqinə qoşuludur və iş şəbəkə fəaliyyətinizə nəzarət edə bilər, bura e-məktubıar, tətbiq və veb saytlar daxildir.\n\nƏtraflı məlumat üçün administratorunuz ilə əlaqə saxlayın."</string>
    +     <string name="monitoring_description_app_personal_work" msgid="4946600443852045903">"İş profiliniz <xliff:g id="ORGANIZATION">%1$s</xliff:g> tərəfindən idarə olunur. <xliff:g id="APPLICATION_WORK">%2$s</xliff:g> tətbiqinə qoşuludur və iş şəbəkə fəaliyyətinizi idarə edə bilər, bura e-məktubıar, tətbiq və veb saytlar daxildir\n\nSiz, həmçinin, <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g> tətbiqinə də qoşulsunuz və o, şəxsi şəbəkə fəaliyyətinizə nəzarət edə bilər."</string>
    +     <string name="monitoring_description_vpn_app_device_owned" msgid="4970443827043261703">"Sizin cihaz tərəfindən idarə olunur <xliff:g id="ORGANIZATION">%1$s</xliff:g> . \n\n Sizin administrator nəzarət və parametrləri, korporativ giriş, apps, sizin cihaz ilə bağlı məlumat və cihaz yer məlumat idarə edə bilərsiniz. \n\n Siz bağlı olduğunuz <xliff:g id="APPLICATION">%2$s</xliff:g> , E-poçt, apps, və web o cümlədən, şəbəkə fəaliyyətinə nəzarət edə bilər. \n\n Daha ətraflı məlumat üçün, administratora müraciət."</string>
    +@@ -492,8 +494,6 @@
    +     <string name="clock_seconds_desc" msgid="6282693067130470675">"Saatın saniyəsini status panelində göstərin. Batareyaya təsir edə bilər."</string>
    +     <string name="qs_rearrange" msgid="8060918697551068765">"Sürətli Ayarları yenidən tənzimləyin"</string>
    +     <string name="show_brightness" msgid="6613930842805942519">"Sürətli ayarlarda parlaqlılığı göstərin"</string>
    +-    <string name="overview_nav_bar_gesture" msgid="8579814204727917764">"Bölünmüş ekran sürüşdürməsi aktiv edin"</string>
    +-    <string name="overview_nav_bar_gesture_desc" msgid="6329167382305102615">"Jestlərin icmal düyməsindən yuxarı sürüşdürərək bölünmüş ekrana daxil olmasını aktiv edin"</string>
    +     <string name="experimental" msgid="6198182315536726162">"Eksperimental"</string>
    +     <string name="enable_bluetooth_title" msgid="5027037706500635269">"Bluetooth aktivləşsin?"</string>
    +     <string name="enable_bluetooth_message" msgid="9106595990708985385">"Tabletinizlə klaviaturaya bağlanmaq üçün ilk olaraq Bluetooth\'u aktivləşdirməlisiniz."</string>
    +@@ -651,4 +651,5 @@
    +     <string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"<xliff:g id="ID_1">%s</xliff:g> ayarlarını açın."</string>
    +     <string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"Ayarların sıralanmasını redaktə edin."</string>
    +     <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"<xliff:g id="ID_2">%2$d</xliff:g> səhifədən <xliff:g id="ID_1">%1$d</xliff:g> səhifə"</string>
    ++    <string name="cant_silence_or_block" msgid="999689262131488625">"Bildirişlər susdurula və ya blok edilə bilməz"</string>
    + </resources>
    +diff --git a/packages/SystemUI/res/values-b+sr+Latn/strings.xml b/packages/SystemUI/res/values-b+sr+Latn/strings.xml
    +index f95045c..19d58d5 100644
    +--- a/packages/SystemUI/res/values-b+sr+Latn/strings.xml
    ++++ b/packages/SystemUI/res/values-b+sr+Latn/strings.xml
    +@@ -239,7 +239,7 @@
    +     <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"4G podaci su pauzirani"</string>
    +     <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"Mobilni podaci su pauzirani"</string>
    +     <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"Podaci su pauzirani"</string>
    +-    <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"Zbog toga što ste dostigli podešeno ograničenje za podatke, uređaj je pauzirao korišćenje podataka tokom ostatka ovog ciklusa.\n\nAko nastavite, mobilni operater može da vam naplati dodatne troškove."</string>
    ++    <string name="data_usage_disabled_dialog" msgid="1841738975235283398">"Ograničenje potrošnje podataka koje ste podesili je dostignuto. Više ne koristite mobilne podatke.\n\nAko nastavite, možda će biti naplaćeni troškovi za potrošnju podataka."</string>
    +     <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"Nastavi"</string>
    +     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Nema internet veze"</string>
    +     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi je povezan"</string>
    +@@ -406,6 +406,7 @@
    +     <string name="device_owned_footer" msgid="3802752663326030053">"Uređaj se možda nadgleda"</string>
    +     <string name="profile_owned_footer" msgid="8021888108553696069">"Profil se možda nadgleda"</string>
    +     <string name="vpn_footer" msgid="2388611096129106812">"Mreža se možda nadgleda"</string>
    ++    <string name="branded_vpn_footer" msgid="2168111859226496230">"Mreža se možda nadgleda"</string>
    +     <string name="monitoring_title_device_owned" msgid="7121079311903859610">"Nadgledanje uređaja"</string>
    +     <string name="monitoring_title_profile_owned" msgid="6790109874733501487">"Nadgledanje profila"</string>
    +     <string name="monitoring_title" msgid="169206259253048106">"Nadgledanje mreže"</string>
    +@@ -418,6 +419,7 @@
    +     <string name="legacy_vpn_name" msgid="6604123105765737830">"VPN"</string>
    +     <string name="monitoring_description_app" msgid="6259179342284742878">"Povezani ste sa aplikacijom <xliff:g id="APPLICATION">%1$s</xliff:g>, koja može da nadgleda aktivnosti na mreži, uključujući imejlove, aplikacije i veb-sajtove."</string>
    +     <string name="monitoring_description_app_personal" msgid="484599052118316268">"Povezani ste sa aplikacijom <xliff:g id="APPLICATION">%1$s</xliff:g>, koja može da nadgleda aktivnosti na ličnoj mreži, uključujući imejlove, aplikacije i veb-sajtove."</string>
    ++    <string name="branded_monitoring_description_app_personal" msgid="2669518213949202599">"Povezani ste sa aplikacijom <xliff:g id="APPLICATION">%1$s</xliff:g>, koja može da nadgleda aktivnosti na ličnoj mreži, uključujući imejlove, aplikacije i veb-sajtove."</string>
    +     <string name="monitoring_description_app_work" msgid="1754325860918060897">"Profilom za Work upravlja <xliff:g id="ORGANIZATION">%1$s</xliff:g>. Povezan je sa aplikacijom <xliff:g id="APPLICATION">%2$s</xliff:g>, koja može da nadgleda aktivnosti na poslovnoj mreži, uključujući imejlove, aplikacije i veb-sajtove.\n\nViše informacija potražite od administratora."</string>
    +     <string name="monitoring_description_app_personal_work" msgid="4946600443852045903">"Profilom za Work upravlja <xliff:g id="ORGANIZATION">%1$s</xliff:g>. Povezan je sa aplikacijom <xliff:g id="APPLICATION_WORK">%2$s</xliff:g>, koja može da nadgleda aktivnosti na poslovnoj mreži, uključujući imejlove, aplikacije i veb-sajtove.\n\nPovezani ste i sa aplikacijom <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g>, koja može da nadgleda aktivnosti na ličnoj mreži."</string>
    +     <string name="monitoring_description_vpn_app_device_owned" msgid="4970443827043261703">"Uređajem upravlja <xliff:g id="ORGANIZATION">%1$s</xliff:g>.\n\nAdministrator može da nadgleda podešavanja, korporativni pristup, aplikacije, podatke povezane sa uređajem i informacije o lokaciji uređaja, kao i da upravlja njima.\n\nPovezani ste sa aplikacijom <xliff:g id="APPLICATION">%2$s</xliff:g>, koja može da nadgleda aktivnosti na mreži, uključujući imejlove, aplikacije i veb-sajtove.\n\nViše informacija potražite od administratora."</string>
    +@@ -494,8 +496,6 @@
    +     <string name="clock_seconds_desc" msgid="6282693067130470675">"Sekunde na satu se prikazuju na statusnoj traci. To može da utiče na trajanje baterije."</string>
    +     <string name="qs_rearrange" msgid="8060918697551068765">"Preuredi Brza podešavanja"</string>
    +     <string name="show_brightness" msgid="6613930842805942519">"Prikaži osvetljenost u Brzim podešavanjima"</string>
    +-    <string name="overview_nav_bar_gesture" msgid="8579814204727917764">"Omogući pokret za prevlačenje nagore za podeljeni ekran"</string>
    +-    <string name="overview_nav_bar_gesture_desc" msgid="6329167382305102615">"Omogućava pokret za prelazak na podeljeni ekran prevlačenjem nagore od dugmeta Pregled"</string>
    +     <string name="experimental" msgid="6198182315536726162">"Eksperimentalno"</string>
    +     <string name="enable_bluetooth_title" msgid="5027037706500635269">"Želite li da uključite Bluetooth?"</string>
    +     <string name="enable_bluetooth_message" msgid="9106595990708985385">"Da biste povezali tastaturu sa tabletom, prvo morate da uključite Bluetooth."</string>
    +@@ -653,4 +653,5 @@
    +     <string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"Otvori podešavanja za <xliff:g id="ID_1">%s</xliff:g>."</string>
    +     <string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"Izmeni redosled podešavanja."</string>
    +     <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"<xliff:g id="ID_1">%1$d</xliff:g>. strana od <xliff:g id="ID_2">%2$d</xliff:g>"</string>
    ++    <string name="cant_silence_or_block" msgid="999689262131488625">"Zvuk obaveštenja ne može da se isključi niti ona mogu da se blokiraju"</string>
    + </resources>
    +diff --git a/packages/SystemUI/res/values-be-rBY/strings.xml b/packages/SystemUI/res/values-be-rBY/strings.xml
    +index 325d706..7538a9a 100644
    +--- a/packages/SystemUI/res/values-be-rBY/strings.xml
    ++++ b/packages/SystemUI/res/values-be-rBY/strings.xml
    +@@ -242,7 +242,7 @@
    +     <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"Перадача даных 4G прыпынена"</string>
    +     <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"Мабільная перадача даных прыпынена"</string>
    +     <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"Перадача даных прыпынена"</string>
    +-    <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"Быў дасягнуты ліміт перадачы даных, таму прылада прыпыніла перадачу даных на астатнюю частку гэтага цыкла.\n\nУзнаўленне перадачы можа прывесці да спагнання платы вашым аператарам."</string>
    ++    <string name="data_usage_disabled_dialog" msgid="1841738975235283398">"Ліміт даных, які вы задалі, быў дасягнуты. Вы больш не выкарыстоўваеце сотавую перадачу даных.\n\nКалі вы ўзновіце карыстанне, можа спаганяцца плата за выкарыстанне трафіка."</string>
    +     <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"Узнавіць"</string>
    +     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Няма падключэння да Iнтэрнэту"</string>
    +     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi падключаны"</string>
    +@@ -410,6 +410,7 @@
    +     <string name="device_owned_footer" msgid="3802752663326030053">"За прыладай могуць назіраць"</string>
    +     <string name="profile_owned_footer" msgid="8021888108553696069">"За профілем могуць назіраць"</string>
    +     <string name="vpn_footer" msgid="2388611096129106812">"За сеткай могуць назіраць"</string>
    ++    <string name="branded_vpn_footer" msgid="2168111859226496230">"За сеткай могуць назіраць"</string>
    +     <string name="monitoring_title_device_owned" msgid="7121079311903859610">"Маніторынг прылад"</string>
    +     <string name="monitoring_title_profile_owned" msgid="6790109874733501487">"Маніторынг профіляў"</string>
    +     <string name="monitoring_title" msgid="169206259253048106">"Маніторынг сеткі"</string>
    +@@ -422,6 +423,7 @@
    +     <string name="legacy_vpn_name" msgid="6604123105765737830">"VPN"</string>
    +     <string name="monitoring_description_app" msgid="6259179342284742878">"Вы падлучаны да праграмы <xliff:g id="APPLICATION">%1$s</xliff:g>, якая можа сачыць за вашай сеткавай актыўнасцю, уключаючы электронную пошту, праграмы і вэб-сайты."</string>
    +     <string name="monitoring_description_app_personal" msgid="484599052118316268">"Вы падлучаны да праграмы <xliff:g id="APPLICATION">%1$s</xliff:g>, якая сачыць за вашай асабістай сеткавай актыўнасцю, уключаючы электронную пошту, праграмы і вэб-сайты."</string>
    ++    <string name="branded_monitoring_description_app_personal" msgid="2669518213949202599">"Вы падключаны да праграмы <xliff:g id="APPLICATION">%1$s</xliff:g>, якая можа сачыць за вашай асабістай сеткавай дзейнасцю, уключаючы электронную пошту, праграмы і вэб-сайты."</string>
    +     <string name="monitoring_description_app_work" msgid="1754325860918060897">"Ваш працоўны профіль знаходзіцца пад кіраваннем <xliff:g id="ORGANIZATION">%1$s</xliff:g>. Ён падлучаны да праграмы <xliff:g id="APPLICATION">%2$s</xliff:g>, якая можа сачыць за вашай сеткавай актыўнасцю, уключаючы электронную пошту, праграмы і вэб-сайты.\n\nДля атрымання дадатковай інфармацыі звярніцеся да адміністратара."</string>
    +     <string name="monitoring_description_app_personal_work" msgid="4946600443852045903">"Ваш працоўны профіль знаходзіцца пад кіраваннем <xliff:g id="ORGANIZATION">%1$s</xliff:g>. Ён падлучаны да праграмы <xliff:g id="APPLICATION_WORK">%2$s</xliff:g>, якая можа сачыць за вашай сеткавай актыўнасцю, уключаючы электронную пошту, праграмы і вэб-сайты.\n\nВы таксама падлучаны да праграмы <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g>, якая можа сачыць за вашай асабістай сеткавай актыўнасцю."</string>
    +     <string name="monitoring_description_vpn_app_device_owned" msgid="4970443827043261703">"Ваша прылада знаходзіцца пад кіраваннем <xliff:g id="ORGANIZATION">%1$s</xliff:g>.\n\nВаш адміністратар можа сачыць і кіраваць наладамі, доступам да карпаратыўных рэсурсаў, праграмамі, данымі, звязанымі з вашай прыладай, і звесткамі пра месцазнаходжанне прылады.\n\nВы падлучаны да праграмы <xliff:g id="APPLICATION">%2$s</xliff:g>,  якая можа сачыць за вашай сеткавай актыўнасцю, уключаючы электронную пошту, праграмы і вэб-сайты.\n\nДля атрымання дадатковай інфармацыі звярніцеся да адміністратара."</string>
    +@@ -498,8 +500,6 @@
    +     <string name="clock_seconds_desc" msgid="6282693067130470675">"Паказваць секунды гадзінніка на панэлі стану. Можа паўплываць на рэсурс акумулятара."</string>
    +     <string name="qs_rearrange" msgid="8060918697551068765">"Змяніць парадак Хуткіх налад"</string>
    +     <string name="show_brightness" msgid="6613930842805942519">"Паказваць яркасць у Хуткіх наладах"</string>
    +-    <string name="overview_nav_bar_gesture" msgid="8579814204727917764">"Уключ. пераход да рэжыму дзялення экрана правядзеннем уверх"</string>
    +-    <string name="overview_nav_bar_gesture_desc" msgid="6329167382305102615">"Уключыць пераход да рэжыму дзялення экрана правядзеннем пальцам уверх ад кнопкі «Агляд»"</string>
    +     <string name="experimental" msgid="6198182315536726162">"Эксперыментальныя"</string>
    +     <string name="enable_bluetooth_title" msgid="5027037706500635269">"Уключыць Bluetooth?"</string>
    +     <string name="enable_bluetooth_message" msgid="9106595990708985385">"Для падлучэння клавіятуры да планшэта трэба спачатку ўключыць Bluetooth."</string>
    +@@ -657,4 +657,5 @@
    +     <string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"Адкрыць налады <xliff:g id="ID_1">%s</xliff:g>."</string>
    +     <string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"Змяніць парадак налад."</string>
    +     <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"Старонка <xliff:g id="ID_1">%1$d</xliff:g> з <xliff:g id="ID_2">%2$d</xliff:g>"</string>
    ++    <string name="cant_silence_or_block" msgid="999689262131488625">"Гук паведамленняў нельга адключыць, і іх нельга заблакіраваць"</string>
    + </resources>
    +diff --git a/packages/SystemUI/res/values-bg/strings.xml b/packages/SystemUI/res/values-bg/strings.xml
    +index c5817ee..b184142 100644
    +--- a/packages/SystemUI/res/values-bg/strings.xml
    ++++ b/packages/SystemUI/res/values-bg/strings.xml
    +@@ -238,7 +238,7 @@
    +     <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"Данните от 4G са поставени на пауза"</string>
    +     <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"Мобилните данни са поставени на пауза"</string>
    +     <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"Данните са поставени на пауза"</string>
    +-    <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"Тъй като зададеното от вас ограничение за данни бе достигнато, устройството постави преноса им на пауза за остатъка от този цикъл.\n\nВъзобновяването може да доведе до таксуване от оператора ви."</string>
    ++    <string name="data_usage_disabled_dialog" msgid="1841738975235283398">"Достигнахте зададеното от вас ограничение за данните. Вече не използвате мобилната мрежа.\n\nАко възобновите връзката с нея, може да бъдете таксувани за пренос на данни."</string>
    +     <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"Възобновяване"</string>
    +     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Няма връзка с интернет"</string>
    +     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi: Има връзка"</string>
    +@@ -404,6 +404,7 @@
    +     <string name="device_owned_footer" msgid="3802752663326030053">"Устройството може да се наблюдава"</string>
    +     <string name="profile_owned_footer" msgid="8021888108553696069">"Възможно е потребителският профил да се наблюдава"</string>
    +     <string name="vpn_footer" msgid="2388611096129106812">"Мрежата може да се наблюдава"</string>
    ++    <string name="branded_vpn_footer" msgid="2168111859226496230">"Мрежата може да се наблюдава"</string>
    +     <string name="monitoring_title_device_owned" msgid="7121079311903859610">"Наблюдение на устройството"</string>
    +     <string name="monitoring_title_profile_owned" msgid="6790109874733501487">"Наблюдаване на потр. профил"</string>
    +     <string name="monitoring_title" msgid="169206259253048106">"Наблюдение на мрежата"</string>
    +@@ -416,6 +417,7 @@
    +     <string name="legacy_vpn_name" msgid="6604123105765737830">"VPN"</string>
    +     <string name="monitoring_description_app" msgid="6259179342284742878">"Установена е връзка с приложението <xliff:g id="APPLICATION">%1$s</xliff:g>, което може да наблюдава активността ви в мрежата, включително имейли, приложения и уебсайтове."</string>
    +     <string name="monitoring_description_app_personal" msgid="484599052118316268">"Установена е връзка с приложението <xliff:g id="APPLICATION">%1$s</xliff:g>, което може да наблюдава личната ви активност в мрежата, включително имейли, приложения и уебсайтове."</string>
    ++    <string name="branded_monitoring_description_app_personal" msgid="2669518213949202599">"Установена е връзка с приложението <xliff:g id="APPLICATION">%1$s</xliff:g>, което може да наблюдава личната ви активност в мрежата, включително имейли, приложения и уебсайтове."</string>
    +     <string name="monitoring_description_app_work" msgid="1754325860918060897">"Служебният ви потребителски профил се управлява от <xliff:g id="ORGANIZATION">%1$s</xliff:g>. Той е свързан с приложението <xliff:g id="APPLICATION">%2$s</xliff:g>, което може да наблюдава служебната ви активност в мрежата, включително имейли, приложения и уебсайтове.\n\nЗа още информация се свържете с администратора си."</string>
    +     <string name="monitoring_description_app_personal_work" msgid="4946600443852045903">"Служебният ви потребителски профил се управлява от <xliff:g id="ORGANIZATION">%1$s</xliff:g>. Той е свързан с приложението <xliff:g id="APPLICATION_WORK">%2$s</xliff:g>, което може да наблюдава служебната ви активност в мрежата, включително имейли, приложения и уебсайтове.\n\nУстановена е връзка и с приложението <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g>, което може да наблюдава личната ви активност в мрежата."</string>
    +     <string name="monitoring_description_vpn_app_device_owned" msgid="4970443827043261703">"Устройството ви се управлява от <xliff:g id="ORGANIZATION">%1$s</xliff:g>.\n\nАдминистраторът ви може да наблюдава и управлява настройките, корпоративния достъп, приложенията и данните, свързани с устройството ви, включително информацията за местоположението му.\n\nУстановена е връзка с приложението <xliff:g id="APPLICATION">%2$s</xliff:g>, което може да наблюдава активността ви в мрежата, включително имейли, приложения и уебсайтове.\n\nЗа още информация се свържете с администратора си."</string>
    +@@ -492,8 +494,6 @@
    +     <string name="clock_seconds_desc" msgid="6282693067130470675">"Показване на секундите на часовника в лентата на състоянието. Може да се отрази на живота на батерията."</string>
    +     <string name="qs_rearrange" msgid="8060918697551068765">"Пренареждане на бързите настройки"</string>
    +     <string name="show_brightness" msgid="6613930842805942519">"Показване на яркостта от бързите настройки"</string>
    +-    <string name="overview_nav_bar_gesture" msgid="8579814204727917764">"Разделяне на екрана с прекарване на пръст нагоре: Активиране"</string>
    +-    <string name="overview_nav_bar_gesture_desc" msgid="6329167382305102615">"Активиране на жеста за влизане в режим на разделен екран чрез прокарване на пръст нагоре от бутона за общ преглед"</string>
    +     <string name="experimental" msgid="6198182315536726162">"Експериментални"</string>
    +     <string name="enable_bluetooth_title" msgid="5027037706500635269">"Да се включи ли Bluetooth?"</string>
    +     <string name="enable_bluetooth_message" msgid="9106595990708985385">"За да свържете клавиатурата с таблета си, първо трябва да включите Bluetooth."</string>
    +@@ -651,4 +651,5 @@
    +     <string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"Отваряне на настройките за <xliff:g id="ID_1">%s</xliff:g>."</string>
    +     <string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"Редактиране на подредбата на настройките."</string>
    +     <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"Страница <xliff:g id="ID_1">%1$d</xliff:g> от <xliff:g id="ID_2">%2$d</xliff:g>"</string>
    ++    <string name="cant_silence_or_block" msgid="999689262131488625">"Известията не могат да бъдат заглушавани, нито блокирани"</string>
    + </resources>
    +diff --git a/packages/SystemUI/res/values-bn-rBD/strings.xml b/packages/SystemUI/res/values-bn-rBD/strings.xml
    +index 40076e6..2cd7b04 100644
    +--- a/packages/SystemUI/res/values-bn-rBD/strings.xml
    ++++ b/packages/SystemUI/res/values-bn-rBD/strings.xml
    +@@ -238,7 +238,7 @@
    +     <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"4G ডেটা বিরতি দেওয়া হয়েছে"</string>
    +     <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"সেলুলার ডেটা বিরতি দেওয়া হয়েছে"</string>
    +     <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"ডেট বিরতি দেওয়া হয়েছে"</string>
    +-    <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"আপনার সেট ডেটার সীমা অবধি পৌঁছনোর কারনে ডিভাইস এই চক্রের অবশিষ্টাংশের জন্য ডেটা ব্যবহারে বিরতি দেওয়া হয়েছে৷ \n\nপুনরায় চালু করা হলে পরিষেবা প্রদানকারীর দ্বারা চার্জের করা হতে পারে৷"</string>
    ++    <string name="data_usage_disabled_dialog" msgid="1841738975235283398">"আপনার সেটা করা ডেটা সীমা ছাড়িয়ে গেছে৷ আপনি আর সেলুলার ডেটা ব্যবহার করতে পারবেন না৷\n\nআপনি যদি আবার ব্যবহার করতে শুরু করেন তাহলে ডেটা ব্যবহারের জন্য চার্জ লাগতে পারে৷"</string>
    +     <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"পুনঃসূচনা করুন"</string>
    +     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"কোনো ইন্টারনেট সংযোগ নেই"</string>
    +     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"ওয়াই-ফাই সংযুক্ত হয়েছে"</string>
    +@@ -404,6 +404,7 @@
    +     <string name="device_owned_footer" msgid="3802752663326030053">"ডিভাইসটি নিরীক্ষণ করা হতে পারে"</string>
    +     <string name="profile_owned_footer" msgid="8021888108553696069">"প্রোফাইল পর্যবেক্ষণ করা হতে পারে"</string>
    +     <string name="vpn_footer" msgid="2388611096129106812">"নেটওয়ার্ক নিরীক্ষণ করা হতে পারে"</string>
    ++    <string name="branded_vpn_footer" msgid="2168111859226496230">"নেটওয়ার্ক নিরীক্ষণ করা হতে পারে"</string>
    +     <string name="monitoring_title_device_owned" msgid="7121079311903859610">"ডিভাইস নিরীক্ষণ"</string>
    +     <string name="monitoring_title_profile_owned" msgid="6790109874733501487">"প্রোফাইল দেখরেখ করা"</string>
    +     <string name="monitoring_title" msgid="169206259253048106">"নেটওয়ার্ক নিরীক্ষণ"</string>
    +@@ -416,6 +417,7 @@
    +     <string name="legacy_vpn_name" msgid="6604123105765737830">"VPN"</string>
    +     <string name="monitoring_description_app" msgid="6259179342284742878">"আপনি <xliff:g id="APPLICATION">%1$s</xliff:g> -এ সংযুক্ত হয়েছেন, যা ইমেল, অ্যাপ্লিকেশান এবং ওয়েবসাইটগুলি সমেত আপনার নেটওয়ার্ক কার্যকলাপ নিরীক্ষণ করতে পারে৷"</string>
    +     <string name="monitoring_description_app_personal" msgid="484599052118316268">"আপনি <xliff:g id="APPLICATION">%1$s</xliff:g> -এ সংযুক্ত হয়েছেন, যা ইমেল, অ্যাপ্লিকেশান এবং ওয়েবসাইটগুলি সমেত আপনার ব্যক্তিগত নেটওয়ার্ক কার্যকলাপ নিরীক্ষণ করতে পারে৷"</string>
    ++    <string name="branded_monitoring_description_app_personal" msgid="2669518213949202599">"আপনি <xliff:g id="APPLICATION">%1$s</xliff:g> এর সাথে সংযুক্ত হয়েছেন, যা ইমেল, অ্যাপ এবং ওয়েবসাইটগুলি সহ আপনার ব্যক্তিগত নেটওয়ার্কের কার্যকলাপ নিরীক্ষণ করবে৷"</string>
    +     <string name="monitoring_description_app_work" msgid="1754325860918060897">"<xliff:g id="ORGANIZATION">%1$s</xliff:g> আপনার কাজের প্রোফাইল পরিচালনা করে৷ এটি <xliff:g id="APPLICATION">%2$s</xliff:g> -এ সংযুক্ত রয়েছে যা আপনার ইমেল, অ্যাপ্লিকেশান ও ওয়েবসাইটগুলি সহ আপনার কাজের নেটওয়ার্কের কার্যকলাপ নিরীক্ষণ করতে পারে৷\n\nআরো তথ্যের জন্য, আপনার প্রশাসকের সাথে যোগাযোগ করুন৷"</string>
    +     <string name="monitoring_description_app_personal_work" msgid="4946600443852045903">"<xliff:g id="ORGANIZATION">%1$s</xliff:g> আপনার কাজের প্রোফাইল পরিচালনা করে৷ এটি <xliff:g id="APPLICATION_WORK">%2$s</xliff:g> -এ সংযুক্ত রয়েছে যা আপনার ইমেল, অ্যাপ্লিকেশান ও ওয়েবসাইটগুলি সহ আপনার কাজের নেটওয়ার্কের কার্যকলাপ নিরীক্ষণ করতে পারে৷\n\nএছাড়াও আপনি <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g> এর সাথে সংযুক্ত রয়েছেন যা আপনার ব্যক্তিগত নেটওয়ার্কের কার্যকলাপ নিরীক্ষণ করতে পারে৷"</string>
    +     <string name="monitoring_description_vpn_app_device_owned" msgid="4970443827043261703">"<xliff:g id="ORGANIZATION">%1$s</xliff:g> আপনার ডিভাইস পরিচালনা করে৷\n\nআপনার প্রশাসক আপনার ডিভাইসের সাথে সম্পর্কিত সেটিংস, কর্পোরেট অ্যাক্সেস, অ্যাপ্লিকেশান ডেটা এবং ডিভাইসের অবস্থান সম্পর্কিত তথ্য নিরীক্ষণ ও পরিচালনা করতে পারেন৷\n\nআপনি <xliff:g id="APPLICATION">%2$s</xliff:g> এর সাথে সংযুক্ত রয়েছেন যা ইমেল, অ্যাপ্লিকেশান ও ওয়েবসাইটগুলি সহ আপনার নেটওয়ার্কের কার্যকলাপ নিরীক্ষণ করতে পারে৷\n\nআরো তথ্যের জন্য, আপনার প্রশাসকের সাথে যোগাযোগ করুন৷"</string>
    +@@ -492,8 +494,6 @@
    +     <string name="clock_seconds_desc" msgid="6282693067130470675">"স্থিতি দন্ডে ঘড়ির সেকেন্ড দেখায়৷ ব্যাটারি লাইফকে প্রভাবিত করতে পারে৷"</string>
    +     <string name="qs_rearrange" msgid="8060918697551068765">"দ্রুত সেটিংসে পুনরায় সাজান"</string>
    +     <string name="show_brightness" msgid="6613930842805942519">"দ্রুত সেটিংসে উজ্জ্বলতা দেখান"</string>
    +-    <string name="overview_nav_bar_gesture" msgid="8579814204727917764">"উপরের দিকে সোয়াইপ করে বিভক্ত-স্ক্রীনে প্রবেশ করার অঙ্গভঙ্গি সক্ষম করুন"</string>
    +-    <string name="overview_nav_bar_gesture_desc" msgid="6329167382305102615">"\'এক নজরে\' বোতাম থেকে উপরের দিকে সোয়াইপ করে, বিভক্ত-স্ক্রীনে প্রবেশ করতে অঙ্গভঙ্গি সক্ষম করুন"</string>
    +     <string name="experimental" msgid="6198182315536726162">"পরীক্ষামূলক"</string>
    +     <string name="enable_bluetooth_title" msgid="5027037706500635269">"ব্লুটুথ চালু করবেন?"</string>
    +     <string name="enable_bluetooth_message" msgid="9106595990708985385">"আপনার ট্যাবলেটের সাথে আপনার কীবোর্ড সংযুক্ত করতে, আপনাকে প্রথমে ব্লুটুথ চালু করতে হবে।"</string>
    +@@ -651,4 +651,5 @@
    +     <string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"<xliff:g id="ID_1">%s</xliff:g> সেটিংস খুলুন৷"</string>
    +     <string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"ক্রম বা সেটিংস সম্পাদনা করুন৷"</string>
    +     <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"<xliff:g id="ID_2">%2$d</xliff:g>টির মধ্যে <xliff:g id="ID_1">%1$d</xliff:g> নং পৃষ্ঠা"</string>
    ++    <string name="cant_silence_or_block" msgid="999689262131488625">"বিজ্ঞপ্তিগুলিকে নীরব বা অবরুদ্ধ করা যাবে না"</string>
    + </resources>
    +diff --git a/packages/SystemUI/res/values-bs-rBA-land/strings.xml b/packages/SystemUI/res/values-bs-rBA-land/strings.xml
    +index bdc652a..56a4ad2 100644
    +--- a/packages/SystemUI/res/values-bs-rBA-land/strings.xml
    ++++ b/packages/SystemUI/res/values-bs-rBA-land/strings.xml
    +@@ -19,5 +19,5 @@
    + 
    + <resources xmlns:android="http://schemas.android.com/apk/res/android"
    +     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
    +-    <string name="toast_rotation_locked" msgid="7609673011431556092">"Ekran je sada zaključan u pejzažnom prikazu."</string>
    ++    <string name="toast_rotation_locked" msgid="7609673011431556092">"Ekran je sada zaključan u vodoravnom prikazu."</string>
    + </resources>
    +diff --git a/packages/SystemUI/res/values-bs-rBA/strings.xml b/packages/SystemUI/res/values-bs-rBA/strings.xml
    +index dcba67b..3fc98fd 100644
    +--- a/packages/SystemUI/res/values-bs-rBA/strings.xml
    ++++ b/packages/SystemUI/res/values-bs-rBA/strings.xml
    +@@ -239,7 +239,7 @@
    +     <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"4G prijenos podataka je pauzirano"</string>
    +     <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"Mobilni podaci su pauzirani"</string>
    +     <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"Prijenos podataka je pauziran"</string>
    +-    <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"Dostigli ste postavljeno ograničenje prijenosa podataka pa je uređaj zaustavio prijenos podataka za preostali dio ovog ciklusa.\n\nAko nastavite, operater vam može naplatiti dodatne troškove."</string>
    ++    <string name="data_usage_disabled_dialog" msgid="1841738975235283398">"Dostigli ste ograničenje za prijenos podataka koje ste postavili. Više ne koristite mobilne podatke.\n\nUkoliko nastavite koristiti mobilne podatke, mogući su troškovi za prijenos podataka."</string>
    +     <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"Nastavi"</string>
    +     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Nema internet veze"</string>
    +     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi veza aktivna"</string>
    +@@ -314,7 +314,7 @@
    +     <string name="quick_settings_notifications_label" msgid="4818156442169154523">"Obavještenja"</string>
    +     <string name="quick_settings_flashlight_label" msgid="2133093497691661546">"Svjetiljka"</string>
    +     <string name="quick_settings_cellular_detail_title" msgid="8575062783675171695">"Mobilni podaci"</string>
    +-    <string name="quick_settings_cellular_detail_data_usage" msgid="1964260360259312002">"Korištenje podataka"</string>
    ++    <string name="quick_settings_cellular_detail_data_usage" msgid="1964260360259312002">"Prijenos podataka"</string>
    +     <string name="quick_settings_cellular_detail_remaining_data" msgid="722715415543541249">"Preostala količina podataka"</string>
    +     <string name="quick_settings_cellular_detail_over_limit" msgid="967669665390990427">"Prekoračeno"</string>
    +     <string name="quick_settings_cellular_detail_data_used" msgid="1476810587475761478">"Iskorišteno <xliff:g id="DATA_USED">%s</xliff:g>"</string>
    +@@ -406,6 +406,7 @@
    +     <string name="device_owned_footer" msgid="3802752663326030053">"Uređaj može biti nadziran"</string>
    +     <string name="profile_owned_footer" msgid="8021888108553696069">"Profil može biti nadziran"</string>
    +     <string name="vpn_footer" msgid="2388611096129106812">"Mreža može biti nadzirana"</string>
    ++    <string name="branded_vpn_footer" msgid="2168111859226496230">"Mreža može biti nadzirana"</string>
    +     <string name="monitoring_title_device_owned" msgid="7121079311903859610">"Praćenje uređaja"</string>
    +     <string name="monitoring_title_profile_owned" msgid="6790109874733501487">"Praćenje profila"</string>
    +     <string name="monitoring_title" msgid="169206259253048106">"Praćenje mreže"</string>
    +@@ -418,6 +419,7 @@
    +     <string name="legacy_vpn_name" msgid="6604123105765737830">"VPN"</string>
    +     <string name="monitoring_description_app" msgid="6259179342284742878">"Povezani ste sa aplikacijom <xliff:g id="APPLICATION">%1$s</xliff:g>, koja može pratiti vašu aktivnost na mreži, uključujući e-mailove, aplikacije i web-lokacije."</string>
    +     <string name="monitoring_description_app_personal" msgid="484599052118316268">"Povezani ste sa aplikacijom <xliff:g id="APPLICATION">%1$s</xliff:g>, koja može pratiti vašu aktivnost na privatnoj mreži, uključujući e-mailove, aplikacije i web-lokacije."</string>
    ++    <string name="branded_monitoring_description_app_personal" msgid="2669518213949202599">"Povezani ste na aplikaciju <xliff:g id="APPLICATION">%1$s</xliff:g>, koja može pratiti vaše privatne aktivnosti na mreži, uključujući e-poštu, aplikacije i web stranice."</string>
    +     <string name="monitoring_description_app_work" msgid="1754325860918060897">"Profilom za posao upravlja <xliff:g id="ORGANIZATION">%1$s</xliff:g>. Povezan je sa aplikacijom <xliff:g id="APPLICATION">%2$s</xliff:g>, koja može pratiti vašu aktivnost na radnoj mreži, uključujući e-poštu, aplikacije i web-lokacije.\n\nZa više informacija kontaktirajte svog administratora."</string>
    +     <string name="monitoring_description_app_personal_work" msgid="4946600443852045903">"Profilom za posao upravlja <xliff:g id="ORGANIZATION">%1$s</xliff:g>. Povezan je sa aplikacijom <xliff:g id="APPLICATION_WORK">%2$s</xliff:g>, koja može pratiti vašu aktivnost na radnoj mreži, uključujući e-poštu, aplikacije i web-lokacije.\n\nPovezani ste i sa aplikacijom <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g>, koja može pratiti vašu aktivnost na privatnoj mreži."</string>
    +     <string name="monitoring_description_vpn_app_device_owned" msgid="4970443827043261703">"Vašim uređajem upravlja <xliff:g id="ORGANIZATION">%1$s</xliff:g>.\n\nVaš administrator može pratiti postavke, korporativni pristup, aplikacije, podatke povezane sa vašim uređajem i informacije o lokaciji uređaja, kao i upravljati njima.\n\nPovezani ste sa aplikacijom <xliff:g id="APPLICATION">%2$s</xliff:g>, koja može pratiti vašu aktivnost na mreži, uključujući e-poštu, aplikacije i web-lokacije.\n\nZa više informacija kontaktirajte svog administratora."</string>
    +@@ -496,8 +498,6 @@
    +     <string name="clock_seconds_desc" msgid="6282693067130470675">"Prikaži sekunde na statusnoj traci. Može skratiti trajanje baterije."</string>
    +     <string name="qs_rearrange" msgid="8060918697551068765">"Preuredi \"Brze postavke\""</string>
    +     <string name="show_brightness" msgid="6613930842805942519">"Prikaži osvjetljenje u opciji \"Brze postavke\""</string>
    +-    <string name="overview_nav_bar_gesture" msgid="8579814204727917764">"Omogućiti potez za podjelu ekrana prevlačenjem prema gore"</string>
    +-    <string name="overview_nav_bar_gesture_desc" msgid="6329167382305102615">"Uključite pokrete prstima da biste ušli u podijeljeni ekran tako što ćete od dugmeta Pregled prevući prstom prema gore"</string>
    +     <string name="experimental" msgid="6198182315536726162">"Eksperimentalno"</string>
    +     <string name="enable_bluetooth_title" msgid="5027037706500635269">"Želiti li uključiti Bluetooth?"</string>
    +     <string name="enable_bluetooth_message" msgid="9106595990708985385">"Da povežete tastaturu sa tabletom, prvo morate uključiti Bluetooth."</string>
    +@@ -655,4 +655,5 @@
    +     <string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"Otvori postavke za: <xliff:g id="ID_1">%s</xliff:g>."</string>
    +     <string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"Urediti raspored postavki."</string>
    +     <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"Stranica <xliff:g id="ID_1">%1$d</xliff:g> od <xliff:g id="ID_2">%2$d</xliff:g>"</string>
    ++    <string name="cant_silence_or_block" msgid="999689262131488625">"Obavještenja nije moguće prigušiti ili blokirati"</string>
    + </resources>
    +diff --git a/packages/SystemUI/res/values-ca/strings.xml b/packages/SystemUI/res/values-ca/strings.xml
    +index 3354f92..483f766 100644
    +--- a/packages/SystemUI/res/values-ca/strings.xml
    ++++ b/packages/SystemUI/res/values-ca/strings.xml
    +@@ -238,7 +238,7 @@
    +     <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"Les dades 4G estan aturades"</string>
    +     <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"Les dades mòbils estan aturades"</string>
    +     <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"Les dades estan aturades"</string>
    +-    <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"Com que has arribat al límit de dades establert, s\'ha aturat l\'ús de dades del dispositiu per a la resta d\'aquest cicle.\n\nSi el reprens, l\'operador de telefonia mòbil pot aplicar càrrecs."</string>
    ++    <string name="data_usage_disabled_dialog" msgid="1841738975235283398">"S\'ha assolit el límit de dades establert. Ja no estàs utilitzant dades mòbils. \n\n Si reprens l\'ús de les dades, es poden aplicar càrrecs."</string>
    +     <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"Reprèn"</string>
    +     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"No hi ha connexió a Internet"</string>
    +     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi: connectada"</string>
    +@@ -404,6 +404,7 @@
    +     <string name="device_owned_footer" msgid="3802752663326030053">"És possible que el dispositiu estigui supervisat."</string>
    +     <string name="profile_owned_footer" msgid="8021888108553696069">"El perfil es pot supervisar"</string>
    +     <string name="vpn_footer" msgid="2388611096129106812">"És possible que la xarxa estigui supervisada."</string>
    ++    <string name="branded_vpn_footer" msgid="2168111859226496230">"És possible que la xarxa estigui supervisada"</string>
    +     <string name="monitoring_title_device_owned" msgid="7121079311903859610">"Supervisió del dispositiu"</string>
    +     <string name="monitoring_title_profile_owned" msgid="6790109874733501487">"Supervisió del perfil"</string>
    +     <string name="monitoring_title" msgid="169206259253048106">"Supervisió de la xarxa"</string>
    +@@ -416,6 +417,7 @@
    +     <string name="legacy_vpn_name" msgid="6604123105765737830">"VPN"</string>
    +     <string name="monitoring_description_app" msgid="6259179342284742878">"Estàs connectat a <xliff:g id="APPLICATION">%1$s</xliff:g>, que pot supervisar la teva activitat a la xarxa, com ara els correus electrònics, les aplicacions i els llocs web."</string>
    +     <string name="monitoring_description_app_personal" msgid="484599052118316268">"Estàs connectat a <xliff:g id="APPLICATION">%1$s</xliff:g>, que pot supervisar la teva activitat personal a la xarxa, com ara els correus electrònics, les aplicacions i els llocs web."</string>
    ++    <string name="branded_monitoring_description_app_personal" msgid="2669518213949202599">"Estàs connectat a <xliff:g id="APPLICATION">%1$s</xliff:g>, que pot supervisar la teva activitat personal a la xarxa, com ara els correus electrònics, les aplicacions i els llocs web."</string>
    +     <string name="monitoring_description_app_work" msgid="1754325860918060897">"<xliff:g id="ORGANIZATION">%1$s</xliff:g> gestiona el teu perfil professional. Aquest perfil està connectat a <xliff:g id="APPLICATION">%2$s</xliff:g>, que pot supervisar la teva activitat professional a la xarxa, com ara els correus electrònics, les aplicacions i els llocs web.\n\nPer obtenir més informació, contacta amb l\'administrador."</string>
    +     <string name="monitoring_description_app_personal_work" msgid="4946600443852045903">"<xliff:g id="ORGANIZATION">%1$s</xliff:g> gestiona el teu perfil professional. Aquest perfil està connectat a <xliff:g id="APPLICATION_WORK">%2$s</xliff:g>, que pot supervisar la teva activitat professional a la xarxa, com ara els correus electrònics, les aplicacions i els llocs web.\n\nA més, estàs connectat a <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g>, que també pot supervisar la teva activitat personal a la xarxa."</string>
    +     <string name="monitoring_description_vpn_app_device_owned" msgid="4970443827043261703">"<xliff:g id="ORGANIZATION">%1$s</xliff:g> gestiona el dispositiu.\n\nL\'administrador pot supervisar i gestionar el següent: configuració, accés corporatiu, aplicacions i dades associades amb el dispositiu, inclosa la informació d\'ubicació.\n\nEstàs connectat a <xliff:g id="APPLICATION">%2$s</xliff:g>, que pot supervisar l\'activitat a la xarxa, com ara els correus, les aplicacions i els llocs web.\n\nPer obtenir més informació, contacta amb l\'administrador."</string>
    +@@ -492,8 +494,6 @@
    +     <string name="clock_seconds_desc" msgid="6282693067130470675">"Mostra els segons del rellotge a la barra d\'estat. Això pot afectar la durada de la bateria."</string>
    +     <string name="qs_rearrange" msgid="8060918697551068765">"Reorganitza Configuració ràpida"</string>
    +     <string name="show_brightness" msgid="6613930842805942519">"Mostra la brillantor a Configuració ràpida"</string>
    +-    <string name="overview_nav_bar_gesture" msgid="8579814204727917764">"Activa el gest per dividir la pantalla en lliscar cap amunt"</string>
    +-    <string name="overview_nav_bar_gesture_desc" msgid="6329167382305102615">"Activa el gest per entrar al mode de pantalla dividida en lliscar cap amunt des del botó Visió general"</string>
    +     <string name="experimental" msgid="6198182315536726162">"Experimental"</string>
    +     <string name="enable_bluetooth_title" msgid="5027037706500635269">"Vols activar el Bluetooth?"</string>
    +     <string name="enable_bluetooth_message" msgid="9106595990708985385">"Per connectar el teclat amb la tauleta, primer has d\'activar el Bluetooth."</string>
    +@@ -651,4 +651,5 @@
    +     <string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"Obre la configuració per a <xliff:g id="ID_1">%s</xliff:g>."</string>
    +     <string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"Edita l\'ordre de la configuració."</string>
    +     <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"Pàgina <xliff:g id="ID_1">%1$d</xliff:g> (<xliff:g id="ID_2">%2$d</xliff:g> en total)"</string>
    ++    <string name="cant_silence_or_block" msgid="999689262131488625">"Les notificacions no es poden silenciar ni bloquejar"</string>
    + </resources>
    +diff --git a/packages/SystemUI/res/values-cs/strings.xml b/packages/SystemUI/res/values-cs/strings.xml
    +index d64e5d9..6adcde3 100644
    +--- a/packages/SystemUI/res/values-cs/strings.xml
    ++++ b/packages/SystemUI/res/values-cs/strings.xml
    +@@ -242,7 +242,7 @@
    +     <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"Data 4G jsou pozastavena"</string>
    +     <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"Mobilní data jsou pozastavena"</string>
    +     <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"Data jsou pozastavena"</string>
    +-    <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"Protože jste dosáhli nastaveného limitu dat, zařízení využití dat pro zbytek tohoto cyklu pozastavilo.\n\nObnovení může vést k poplatkům od operátora."</string>
    ++    <string name="data_usage_disabled_dialog" msgid="1841738975235283398">"Byl dosažen limit dat. Používání mobilních dat bylo vypnuto.\n\nPokud jej obnovíte, mohou vám být účtovány poplatky za využití dat."</string>
    +     <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"Pokračovat"</string>
    +     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Žádné přip. k internetu"</string>
    +     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi: připojeno"</string>
    +@@ -410,6 +410,7 @@
    +     <string name="device_owned_footer" msgid="3802752663326030053">"Zařízení může být sledováno"</string>
    +     <string name="profile_owned_footer" msgid="8021888108553696069">"Profil může být monitorován"</string>
    +     <string name="vpn_footer" msgid="2388611096129106812">"Síť může být sledována"</string>
    ++    <string name="branded_vpn_footer" msgid="2168111859226496230">"Síť může být monitorována"</string>
    +     <string name="monitoring_title_device_owned" msgid="7121079311903859610">"Sledování zařízení"</string>
    +     <string name="monitoring_title_profile_owned" msgid="6790109874733501487">"Monitoring profilu"</string>
    +     <string name="monitoring_title" msgid="169206259253048106">"Sledování sítě"</string>
    +@@ -422,6 +423,7 @@
    +     <string name="legacy_vpn_name" msgid="6604123105765737830">"VPN"</string>
    +     <string name="monitoring_description_app" msgid="6259179342284742878">"Jste připojeni k aplikaci <xliff:g id="APPLICATION">%1$s</xliff:g>, která může sledovat vaši aktivitu v síti, včetně e-mailů, aplikací a webů."</string>
    +     <string name="monitoring_description_app_personal" msgid="484599052118316268">"Jste připojeni k aplikaci <xliff:g id="APPLICATION">%1$s</xliff:g>, která může sledovat vaši osobní aktivitu v síti, včetně e-mailů, aplikací a webů."</string>
    ++    <string name="branded_monitoring_description_app_personal" msgid="2669518213949202599">"Jste připojeni k aplikaci <xliff:g id="APPLICATION">%1$s</xliff:g>, která může sledovat vaši osobní aktivitu v síti, včetně e-mailů, aplikací a webů."</string>
    +     <string name="monitoring_description_app_work" msgid="1754325860918060897">"Váš pracovní profil spravuje organizace <xliff:g id="ORGANIZATION">%1$s</xliff:g>. Je připojen k aplikaci <xliff:g id="APPLICATION">%2$s</xliff:g>, která může sledovat vaši aktivitu v síti, včetně e-mailů, aplikací a webů.\n\nO další informace požádejte svého administrátora."</string>
    +     <string name="monitoring_description_app_personal_work" msgid="4946600443852045903">"Váš pracovní profil spravuje organizace <xliff:g id="ORGANIZATION">%1$s</xliff:g>. Je připojen k aplikaci <xliff:g id="APPLICATION_WORK">%2$s</xliff:g>, která může sledovat vaši aktivitu v síti, včetně e-mailů, aplikací a webů.\n\nTaké jste připojeni k aplikaci <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g>, která může sledovat vaši osobní aktivitu v síti."</string>
    +     <string name="monitoring_description_vpn_app_device_owned" msgid="4970443827043261703">"Toto zařízení spravuje organizace <xliff:g id="ORGANIZATION">%1$s</xliff:g>.\n\nAdministrátor může sledovat a spravovat nastavení, firemní přístup, aplikace, data přidružená k tomuto zařízení a informace o jeho poloze.\n\nJste připojeni k aplikaci <xliff:g id="APPLICATION">%2$s</xliff:g>, která může sledovat vaši osobní aktivitu v síti, včetně e-mailů, aplikací a webů.\n\nO další informace požádejte svého administrátora."</string>
    +@@ -498,8 +500,6 @@
    +     <string name="clock_seconds_desc" msgid="6282693067130470675">"Na stavovém řádku se bude zobrazovat sekundová ručička. Může být ovlivněna výdrž baterie."</string>
    +     <string name="qs_rearrange" msgid="8060918697551068765">"Změnit uspořádání Rychlého nastavení"</string>
    +     <string name="show_brightness" msgid="6613930842805942519">"Zobrazit jas v Rychlém nastavení"</string>
    +-    <string name="overview_nav_bar_gesture" msgid="8579814204727917764">"Aktivovat rozdělenou obrazovku přejetím prstem nahoru"</string>
    +-    <string name="overview_nav_bar_gesture_desc" msgid="6329167382305102615">"Umožňuje aktivovat rozdělenou obrazovku přejetím prstem nahoru od tlačítka Přehled."</string>
    +     <string name="experimental" msgid="6198182315536726162">"Experimentální"</string>
    +     <string name="enable_bluetooth_title" msgid="5027037706500635269">"Zapnout Bluetooth?"</string>
    +     <string name="enable_bluetooth_message" msgid="9106595990708985385">"Chcete-li klávesnici připojit k tabletu, nejdříve musíte zapnout Bluetooth."</string>
    +@@ -657,4 +657,5 @@
    +     <string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"Otevřít nastavení aplikace <xliff:g id="ID_1">%s</xliff:g>."</string>
    +     <string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"Upravit pořadí nastavení."</string>
    +     <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"Stránka <xliff:g id="ID_1">%1$d</xliff:g> z <xliff:g id="ID_2">%2$d</xliff:g>"</string>
    ++    <string name="cant_silence_or_block" msgid="999689262131488625">"Oznámení nelze ztlumit ani blokovat"</string>
    + </resources>
    +diff --git a/packages/SystemUI/res/values-da/strings.xml b/packages/SystemUI/res/values-da/strings.xml
    +index da8daa4..7de602a 100644
    +--- a/packages/SystemUI/res/values-da/strings.xml
    ++++ b/packages/SystemUI/res/values-da/strings.xml
    +@@ -238,7 +238,7 @@
    +     <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"4G-data er sat på pause"</string>
    +     <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"Mobildata er sat på pause"</string>
    +     <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"Data er sat på pause"</string>
    +-    <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"Eftersom din fastsatte datagrænse blev nået, har enheden sat dataforbruget på pause i den resterende del af cyklussen.\n\nHvis du genaktiverer dataforbruget, kan det medføre gebyrer fra dit mobilselskab."</string>
    ++    <string name="data_usage_disabled_dialog" msgid="1841738975235283398">"Du har nået den angivne datagrænse. Du vil ikke længere bruge mobildata.\n\nHvis du fortsætter, vil du muligvis blive opkrævet betaling for dit dataforbrug."</string>
    +     <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"Genoptag"</string>
    +     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Ingen internetforb."</string>
    +     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi er forbundet"</string>
    +@@ -304,7 +304,7 @@
    +     <string name="quick_settings_inversion_label" msgid="8790919884718619648">"Byt om på farver"</string>
    +     <string name="quick_settings_color_space_label" msgid="853443689745584770">"Farvekorrigeringstilstand"</string>
    +     <string name="quick_settings_more_settings" msgid="326112621462813682">"Flere indstillinger"</string>
    +-    <string name="quick_settings_done" msgid="3402999958839153376">"Udført"</string>
    ++    <string name="quick_settings_done" msgid="3402999958839153376">"Udfør"</string>
    +     <string name="quick_settings_connected" msgid="1722253542984847487">"Tilsluttet"</string>
    +     <string name="quick_settings_connecting" msgid="47623027419264404">"Opretter forbindelse…"</string>
    +     <string name="quick_settings_tethering_label" msgid="7153452060448575549">"Netdeling"</string>
    +@@ -404,6 +404,7 @@
    +     <string name="device_owned_footer" msgid="3802752663326030053">"Enheden kan være overvåget"</string>
    +     <string name="profile_owned_footer" msgid="8021888108553696069">"Profilen kan overvåges"</string>
    +     <string name="vpn_footer" msgid="2388611096129106812">"Netværket kan være overvåget"</string>
    ++    <string name="branded_vpn_footer" msgid="2168111859226496230">"Netværket kan være overvåget"</string>
    +     <string name="monitoring_title_device_owned" msgid="7121079311903859610">"Overvågning af enhed"</string>
    +     <string name="monitoring_title_profile_owned" msgid="6790109874733501487">"Profilovervågning"</string>
    +     <string name="monitoring_title" msgid="169206259253048106">"Overvågning af netværk"</string>
    +@@ -416,6 +417,7 @@
    +     <string name="legacy_vpn_name" msgid="6604123105765737830">"VPN"</string>
    +     <string name="monitoring_description_app" msgid="6259179342284742878">"Du har forbindelse til <xliff:g id="APPLICATION">%1$s</xliff:g>, som kan overvåge din netværksaktivitet, bl.a. e-mails, apps og websites."</string>
    +     <string name="monitoring_description_app_personal" msgid="484599052118316268">"Du har forbindelse til <xliff:g id="APPLICATION">%1$s</xliff:g>, som kan overvåge din private netværksaktivitet, bl.a. e-mails, apps og websites."</string>
    ++    <string name="branded_monitoring_description_app_personal" msgid="2669518213949202599">"Du har forbindelse til <xliff:g id="APPLICATION">%1$s</xliff:g>, som kan overvåge din private netværksaktivitet, bl.a. e-mails, apps og websites."</string>
    +     <string name="monitoring_description_app_work" msgid="1754325860918060897">"Din arbejdsprofil administreres af <xliff:g id="ORGANIZATION">%1$s</xliff:g>. Den er forbundet til <xliff:g id="APPLICATION">%2$s</xliff:g>, som kan overvåge din arbejdsrelaterede netværksaktivitet, bl.a. e-mails, apps og websites.\n\nKontakt din administrator for at få flere oplysninger."</string>
    +     <string name="monitoring_description_app_personal_work" msgid="4946600443852045903">"Din arbejdsprofil administreres af <xliff:g id="ORGANIZATION">%1$s</xliff:g>. Den er forbundet til <xliff:g id="APPLICATION_WORK">%2$s</xliff:g>, som kan overvåge din arbejdsrelaterede netværksaktivitet, bl.a. e-mails, apps og websites.\n\nDu er også forbundet til <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g>, som kan overvåge din private netværksaktivitet."</string>
    +     <string name="monitoring_description_vpn_app_device_owned" msgid="4970443827043261703">"Din enhed administreres af <xliff:g id="ORGANIZATION">%1$s</xliff:g>.\n\nDin administrator kan overvåge og administrere indstillinger, virksomhedens adgang, data tilknyttet din enhed og enhedens stedoplysninger.\n\nDu er forbundet til <xliff:g id="APPLICATION">%2$s</xliff:g>, som kan overvåge din netværksaktivitet, bl.a. e-mails, apps og websites.\n\nKontakt din administrator for at få flere oplysninger."</string>
    +@@ -492,8 +494,6 @@
    +     <string name="clock_seconds_desc" msgid="6282693067130470675">"Vis sekunder i statuslinjen. Dette kan påvirke batteriets levetid."</string>
    +     <string name="qs_rearrange" msgid="8060918697551068765">"Omarranger Hurtige indstillinger"</string>
    +     <string name="show_brightness" msgid="6613930842805942519">"Vis lysstyrke i Hurtige indstillinger"</string>
    +-    <string name="overview_nav_bar_gesture" msgid="8579814204727917764">"Aktivér bevægelsen Stryg opad for at dele skærmen"</string>
    +-    <string name="overview_nav_bar_gesture_desc" msgid="6329167382305102615">"Aktivér bevægelse for at dele skærmen ved at stryge opad fra knappen Oversigt"</string>
    +     <string name="experimental" msgid="6198182315536726162">"Eksperimentel"</string>
    +     <string name="enable_bluetooth_title" msgid="5027037706500635269">"Vil du slå Bluetooth til?"</string>
    +     <string name="enable_bluetooth_message" msgid="9106595990708985385">"Bluetooth skal være slået til, før du kan knytte dit tastatur til din tablet."</string>
    +@@ -521,7 +521,7 @@
    +     <string name="notification_importance_high" msgid="1729480727023990427">"Se altid smugkig. Ingen afbrydelse af fuld skærm."</string>
    +     <string name="notification_importance_max" msgid="2508384624461849111">"Se altid smugkig, og tillad afbrydelse af fuld skærm."</string>
    +     <string name="notification_more_settings" msgid="816306283396553571">"Flere indstillinger"</string>
    +-    <string name="notification_done" msgid="5279426047273930175">"Færdig"</string>
    ++    <string name="notification_done" msgid="5279426047273930175">"Udfør"</string>
    +     <string name="notification_gear_accessibility" msgid="94429150213089611">"Kontrolelementer til underretninger for <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
    +     <string name="battery_panel_title" msgid="7944156115535366613">"Batteriforbrug"</string>
    +     <string name="battery_detail_charging_summary" msgid="1279095653533044008">"Batterisparefunktionen er ikke tilgængelig under opladning"</string>
    +@@ -651,4 +651,5 @@
    +     <string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"Åbn <xliff:g id="ID_1">%s</xliff:g>-indstillinger."</string>
    +     <string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"Rediger rækkefølgen af indstillinger."</string>
    +     <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"Side <xliff:g id="ID_1">%1$d</xliff:g> af <xliff:g id="ID_2">%2$d</xliff:g>"</string>
    ++    <string name="cant_silence_or_block" msgid="999689262131488625">"Underretninger kan ikke ignoreres eller blokeres"</string>
    + </resources>
    +diff --git a/packages/SystemUI/res/values-de/strings.xml b/packages/SystemUI/res/values-de/strings.xml
    +index 46078d9..fc6d9a0 100644
    +--- a/packages/SystemUI/res/values-de/strings.xml
    ++++ b/packages/SystemUI/res/values-de/strings.xml
    +@@ -240,7 +240,7 @@
    +     <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"4G-Daten pausiert"</string>
    +     <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"Mobilfunkdaten pausiert"</string>
    +     <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"Daten pausiert"</string>
    +-    <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"Da dein festgelegtes Datenlimit erreicht wurde, hat das Gerät die Datennutzung für den Rest dieses Zeitraums pausiert.\n\nWenn du die Nutzung fortsetzt, entstehen möglicherweise Kosten bei deinem Mobilfunkanbieter."</string>
    ++    <string name="data_usage_disabled_dialog" msgid="1841738975235283398">"Das von dir festgelegte Datenlimit wurde erreicht. Die mobile Datennutzung wurde deaktiviert.\n\nWenn du weiterhin mobile Daten nutzt, können Gebühren anfallen."</string>
    +     <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"Fortsetzen"</string>
    +     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Keine Internetverbindung"</string>
    +     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"WLAN verbunden"</string>
    +@@ -271,7 +271,7 @@
    +     <string name="quick_settings_bluetooth_label" msgid="6304190285170721401">"Bluetooth"</string>
    +     <string name="quick_settings_bluetooth_multiple_devices_label" msgid="3912245565613684735">"Bluetooth (<xliff:g id="NUMBER">%d</xliff:g> Geräte)"</string>
    +     <string name="quick_settings_bluetooth_off_label" msgid="8159652146149219937">"Bluetooth aus"</string>
    +-    <string name="quick_settings_bluetooth_detail_empty_text" msgid="4910015762433302860">"Keine Pairing-Geräte verfügbar"</string>
    ++    <string name="quick_settings_bluetooth_detail_empty_text" msgid="4910015762433302860">"Keine gekoppelten Geräte verfügbar"</string>
    +     <string name="quick_settings_brightness_label" msgid="6968372297018755815">"Helligkeit"</string>
    +     <string name="quick_settings_rotation_unlocked_label" msgid="7305323031808150099">"Automatisch drehen"</string>
    +     <string name="accessibility_quick_settings_rotation" msgid="4231661040698488779">"Bildschirm automatisch drehen"</string>
    +@@ -406,6 +406,7 @@
    +     <string name="device_owned_footer" msgid="3802752663326030053">"Aktivität auf dem Gerät kann vom Eigentümer protokolliert werden"</string>
    +     <string name="profile_owned_footer" msgid="8021888108553696069">"Profil wird möglicherweise überwacht."</string>
    +     <string name="vpn_footer" msgid="2388611096129106812">"Das Netzwerk wird möglicherweise überwacht."</string>
    ++    <string name="branded_vpn_footer" msgid="2168111859226496230">"Das Netzwerk wird möglicherweise überwacht"</string>
    +     <string name="monitoring_title_device_owned" msgid="7121079311903859610">"Geräteüberwachung"</string>
    +     <string name="monitoring_title_profile_owned" msgid="6790109874733501487">"Profilüberwachung"</string>
    +     <string name="monitoring_title" msgid="169206259253048106">"Netzwerküberwachung"</string>
    +@@ -418,6 +419,7 @@
    +     <string name="legacy_vpn_name" msgid="6604123105765737830">"VPN"</string>
    +     <string name="monitoring_description_app" msgid="6259179342284742878">"Du bist mit der App <xliff:g id="APPLICATION">%1$s</xliff:g> verbunden, die deine Netzwerkaktivität überwachen kann, einschließlich E-Mails, Apps und Websites."</string>
    +     <string name="monitoring_description_app_personal" msgid="484599052118316268">"Du bist mit der App <xliff:g id="APPLICATION">%1$s</xliff:g> verbunden, die deine persönliche Netzwerkaktivität überwachen kann, einschließlich E-Mails, Apps und Websites."</string>
    ++    <string name="branded_monitoring_description_app_personal" msgid="2669518213949202599">"Du bist mit der App \"<xliff:g id="APPLICATION">%1$s</xliff:g>\" verbunden. Diese kann deine persönlichen Netzwerkaktivitäten erfassen, einschließlich E-Mails, Apps und Websites."</string>
    +     <string name="monitoring_description_app_work" msgid="1754325860918060897">"Dein Arbeitsprofil wird von <xliff:g id="ORGANIZATION">%1$s</xliff:g> verwaltet. Das Profil ist mit der App <xliff:g id="APPLICATION">%2$s</xliff:g> verbunden, die deine geschäftlichen Netzwerkaktivitäten überwachen kann, einschließlich E-Mails, Apps und Websites.\n\nWeitere Informationen erhältst du von deinem Administrator."</string>
    +     <string name="monitoring_description_app_personal_work" msgid="4946600443852045903">"Dein Arbeitsprofil wird von <xliff:g id="ORGANIZATION">%1$s</xliff:g> verwaltet. Das Profil ist mit der App <xliff:g id="APPLICATION_WORK">%2$s</xliff:g> verbunden, die deine geschäftliche Netzwerkaktivität überwachen kann, einschließlich E-Mails, Apps und Websites.\n\nDu bist außerdem mit der App <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g> verbunden, die deine persönliche Netzwerkaktivität überwachen kann."</string>
    +     <string name="monitoring_description_vpn_app_device_owned" msgid="4970443827043261703">"Dein Gerät wird von <xliff:g id="ORGANIZATION">%1$s</xliff:g> verwaltet.\n\nDein Administrator kann die zu deinem Gerät gehörigen Einstellungen, Unternehmenszugriffsrechte, Apps und Daten überwachen und verwalten, einschließlich der Standortinformationen deines Geräts.\n\nDu bist außerdem mit der App <xliff:g id="APPLICATION">%2$s</xliff:g> verbunden, die deine persönliche Netzwerkaktivität überwachen kann, einschließlich E-Mails, Apps und Websites.\n\nWeitere Informationen erhältst du bei deinem Administrator."</string>
    +@@ -494,8 +496,6 @@
    +     <string name="clock_seconds_desc" msgid="6282693067130470675">"Uhrsekunden in der Statusleiste anzeigen. Kann sich auf die Akkulaufzeit auswirken."</string>
    +     <string name="qs_rearrange" msgid="8060918697551068765">"Schnelleinstellungen neu anordnen"</string>
    +     <string name="show_brightness" msgid="6613930842805942519">"Helligkeit in den Schnelleinstellungen anzeigen"</string>
    +-    <string name="overview_nav_bar_gesture" msgid="8579814204727917764">"Teilen des Bildschirms durch Wischen nach oben aktivieren"</string>
    +-    <string name="overview_nav_bar_gesture_desc" msgid="6329167382305102615">"Aktiviert die Bewegung zum Teilen des Bildschirms, bei der von der Schaltfläche \"Übersicht\" nach oben gewischt wird"</string>
    +     <string name="experimental" msgid="6198182315536726162">"Experimentell"</string>
    +     <string name="enable_bluetooth_title" msgid="5027037706500635269">"Bluetooth aktivieren?"</string>
    +     <string name="enable_bluetooth_message" msgid="9106595990708985385">"Zum Verbinden von Tastatur und Tablet muss Bluetooth aktiviert sein."</string>
    +@@ -653,4 +653,5 @@
    +     <string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"Einstellungen für <xliff:g id="ID_1">%s</xliff:g> öffnen."</string>
    +     <string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"Reihenfolge der Einstellungen bearbeiten."</string>
    +     <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"Seite <xliff:g id="ID_1">%1$d</xliff:g> von <xliff:g id="ID_2">%2$d</xliff:g>"</string>
    ++    <string name="cant_silence_or_block" msgid="999689262131488625">"Benachrichtigungen können nicht stummgeschaltet oder blockiert werden"</string>
    + </resources>
    +diff --git a/packages/SystemUI/res/values-el/strings.xml b/packages/SystemUI/res/values-el/strings.xml
    +index 0a327ab..a9b8bb5 100644
    +--- a/packages/SystemUI/res/values-el/strings.xml
    ++++ b/packages/SystemUI/res/values-el/strings.xml
    +@@ -163,7 +163,7 @@
    +     <string name="accessibility_battery_level_charging" msgid="1147587904439319646">"Φόρτιση μπαταρίας, <xliff:g id="BATTERY_PERCENTAGE">%d</xliff:g> τοις εκατό."</string>
    +     <string name="accessibility_settings_button" msgid="799583911231893380">"Ρυθμίσεις συστήματος."</string>
    +     <string name="accessibility_notifications_button" msgid="4498000369779421892">"Ειδοποιήσεις."</string>
    +-    <string name="accessibility_remove_notification" msgid="3603099514902182350">"Εκκαθάριση ειδοποίησης."</string>
    ++    <string name="accessibility_remove_notification" msgid="3603099514902182350">"Διαγραφή ειδοποίησης."</string>
    +     <string name="accessibility_gps_enabled" msgid="3511469499240123019">"Το GPS ενεργοποιήθηκε."</string>
    +     <string name="accessibility_gps_acquiring" msgid="8959333351058967158">"Προσδιορισμός GPS."</string>
    +     <string name="accessibility_tty_enabled" msgid="4613200365379426561">"Το TeleTypewriter ενεργοποιήθηκε."</string>
    +@@ -238,14 +238,14 @@
    +     <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"Τα δεδομένα 4G τέθηκαν σε παύση"</string>
    +     <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"Τα δεδομένα κινητής τηλεφωνίας τέθηκαν σε παύση"</string>
    +     <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"Τα δεδομένα τέθηκαν σε παύση"</string>
    +-    <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"Επειδή συμπληρώθηκε το όριο των δεδομένων που ορίστηκε για τη συσκευή σας, η χρήση δεδομένων τέθηκε σε παύση για το υπόλοιπο αυτού του κύκλου.\n\nΗ εκ νέου ενεργοποίησή τους ενδέχεται να επιφέρει χρεώσεις από την εταιρεία κινητής τηλεφωνίας σας."</string>
    ++    <string name="data_usage_disabled_dialog" msgid="1841738975235283398">"Το όριο δεδομένων που ορίσατε έχει εξαντληθεί. Δεν χρησιμοποιείτε πλέον δεδομένα κινητής τηλεφωνίας.\n\nΑν συνεχίσετε, ενδέχεται να ισχύσουν χρεώσεις για τη χρήση δεδομένων."</string>
    +     <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"Συνέχιση"</string>
    +     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Χωρ. σύνδ. στο Διαδ."</string>
    +     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi συνδεδεμένο"</string>
    +     <string name="gps_notification_searching_text" msgid="8574247005642736060">"Αναζήτηση για GPS"</string>
    +     <string name="gps_notification_found_text" msgid="4619274244146446464">"Ρύθμιση τοποθεσίας με GPS"</string>
    +     <string name="accessibility_location_active" msgid="2427290146138169014">"Τα αιτήματα τοποθεσίας έχουν ενεργοποιηθεί"</string>
    +-    <string name="accessibility_clear_all" msgid="5235938559247164925">"Εκκαθάριση όλων των ειδοποιήσεων."</string>
    ++    <string name="accessibility_clear_all" msgid="5235938559247164925">"Διαγραφή όλων των ειδοποιήσεων."</string>
    +     <string name="notification_group_overflow_indicator" msgid="1863231301642314183">"+ <xliff:g id="NUMBER">%s</xliff:g>"</string>
    +     <plurals name="notification_group_overflow_description" formatted="false" msgid="4579313201268495404">
    +       <item quantity="other"><xliff:g id="NUMBER_1">%s</xliff:g> επιπλέον ειδοποιήσεις εντός της ομάδας.</item>
    +@@ -323,7 +323,7 @@
    +     <string name="quick_settings_night_display_summary_on" msgid="1814901757887526769">"Ο Νυχτερινός φωτισμός είναι ενεργοποιημένος. Πατήστε για απενεργοποίηση."</string>
    +     <string name="quick_settings_night_display_summary_off" msgid="7892102914128777905">"Ο Νυχτερινός φωτισμός είναι απενεργοποιημένος. Πατήστε για ενεργοποίηση."</string>
    +     <string name="recents_empty_message" msgid="808480104164008572">"Δεν υπάρχουν πρόσφατα στοιχεία"</string>
    +-    <string name="recents_empty_message_dismissed_all" msgid="2791312568666558651">"Έχει γίνει εκκαθάριση όλων των στοιχείων"</string>
    ++    <string name="recents_empty_message_dismissed_all" msgid="2791312568666558651">"Έχει γίνει διαγραφή όλων των στοιχείων"</string>
    +     <string name="recents_app_info_button_label" msgid="2890317189376000030">"Πληροφορίες εφαρμογής"</string>
    +     <string name="recents_lock_to_app_button_label" msgid="6942899049072506044">"καρφίτσωμα οθόνης"</string>
    +     <string name="recents_search_bar_label" msgid="8074997400187836677">"αναζήτηση"</string>
    +@@ -404,6 +404,7 @@
    +     <string name="device_owned_footer" msgid="3802752663326030053">"Η συσκευή μπορεί να παρακολουθείται"</string>
    +     <string name="profile_owned_footer" msgid="8021888108553696069">"Το προφίλ ενδέχεται να παρακολουθείται"</string>
    +     <string name="vpn_footer" msgid="2388611096129106812">"Το δίκτυο ενδέχεται να παρακολουθείται"</string>
    ++    <string name="branded_vpn_footer" msgid="2168111859226496230">"Το δίκτυο ενδέχεται να παρακολουθείται"</string>
    +     <string name="monitoring_title_device_owned" msgid="7121079311903859610">"Παρακολούθηση συσκευής"</string>
    +     <string name="monitoring_title_profile_owned" msgid="6790109874733501487">"Παρακολούθηση προφίλ"</string>
    +     <string name="monitoring_title" msgid="169206259253048106">"Παρακολούθηση δικτύου"</string>
    +@@ -416,6 +417,7 @@
    +     <string name="legacy_vpn_name" msgid="6604123105765737830">"VPN"</string>
    +     <string name="monitoring_description_app" msgid="6259179342284742878">"Έχετε συνδεθεί στην εφαρμογή <xliff:g id="APPLICATION">%1$s</xliff:g>, η οποία μπορεί να παρακολουθεί τη δραστηριότητα του δικτύου σας, συμπεριλαμβανομένων μηνυμάτων ηλεκτρονικού ταχυδρομείου, εφαρμογών και ιστότοπων."</string>
    +     <string name="monitoring_description_app_personal" msgid="484599052118316268">"Έχετε συνδεθεί στην εφαρμογή <xliff:g id="APPLICATION">%1$s</xliff:g>, η οποία μπορεί να παρακολουθεί τη δραστηριότητα του προσωπικού σας δικτύου, συμπεριλαμβανομένων μηνυμάτων ηλεκτρονικού ταχυδρομείου, εφαρμογών και ιστότοπων."</string>
    ++    <string name="branded_monitoring_description_app_personal" msgid="2669518213949202599">"Έχετε συνδεθεί στην εφαρμογή <xliff:g id="APPLICATION">%1$s</xliff:g>, η οποία μπορεί να παρακολουθεί τη δραστηριότητα του προσωπικού σας δικτύου, συμπεριλαμβανομένων μηνυμάτων ηλεκτρονικού ταχυδρομείου, εφαρμογών και ιστοτόπων."</string>
    +     <string name="monitoring_description_app_work" msgid="1754325860918060897">"Η διαχείριση του προφίλ εργασίας γίνεται από τον οργανισμό <xliff:g id="ORGANIZATION">%1$s</xliff:g>. Είναι συνδεδεμένο στην εφαρμογή <xliff:g id="APPLICATION">%2$s</xliff:g>, η οποία μπορεί να παρακολουθεί τη δραστηριότητα του δικτύου εργασίας, συμπεριλαμβανομένων μηνυμάτων ηλεκτρονικού ταχυδρομείου, εφαρμογών και ιστότοπων.\n\nΓια περισσότερες πληροφορίες, επικοινωνήστε με το διαχειριστή."</string>
    +     <string name="monitoring_description_app_personal_work" msgid="4946600443852045903">"Η διαχείριση του προφίλ εργασίας γίνεται από τον οργανισμό <xliff:g id="ORGANIZATION">%1$s</xliff:g>. Είναι συνδεδεμένο στην εφαρμογή <xliff:g id="APPLICATION_WORK">%2$s</xliff:g>, η οποία μπορεί να παρακολουθεί τη δραστηριότητα του δικτύου εργασίας, συμπεριλαμβανομένων μηνυμάτων ηλεκτρονικού ταχυδρομείου, εφαρμογών και ιστότοπων.\n\nΕπίσης, είστε συνδεδεμένοι στην εφαρμογή <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g>, η οποία μπορεί να παρακολουθεί τη δραστηριότητα του προσωπικού σας δικτύου."</string>
    +     <string name="monitoring_description_vpn_app_device_owned" msgid="4970443827043261703">"Η διαχείριση της συσκευής γίνεται από <xliff:g id="ORGANIZATION">%1$s</xliff:g>.\n\nΟ διαχειριστής μπορεί να παρακολουθεί και να διαχειρίζεται ρυθμίσεις, εταιρική πρόσβαση, εφαρμογές, δεδομένα σχετικά με τη συσκευή και πληρ. τοποθεσίας της συσκευής.\n\nΕίστε συνδεδ. σε <xliff:g id="APPLICATION">%2$s</xliff:g> που μπορεί να παρακολουθεί τη δραστηρ. του δικτύου εργασίας, όπως μηνύματα ηλεκτρ. ταχυδρομείου, εφαρμογές και ιστότοπους.\n\nΓια περισ. πληροφορίες, επικοινωνήστε με το διαχειριστή."</string>
    +@@ -436,7 +438,7 @@
    +     <string name="quick_settings_reset_confirmation_message" msgid="2235970126803317374">"Θα εμφανιστεί ξανά την επόμενη φορά που θα το ενεργοποιήσετε στις ρυθμίσεις."</string>
    +     <string name="quick_settings_reset_confirmation_button" msgid="2660339101868367515">"Απόκρυψη"</string>
    +     <string name="volumeui_prompt_message" msgid="918680947433389110">"Η εφαρμογή <xliff:g id="APP_NAME">%1$s</xliff:g> θέλει να γίνει το παράθυρο διαλόγου ελέγχου έντασης"</string>
    +-    <string name="volumeui_prompt_allow" msgid="7954396902482228786">"Να επιτραπεί"</string>
    ++    <string name="volumeui_prompt_allow" msgid="7954396902482228786">"Να επιτρέπεται"</string>
    +     <string name="volumeui_prompt_deny" msgid="5720663643411696731">"Απόρριψη"</string>
    +     <string name="volumeui_notification_title" msgid="4906770126345910955">"Η εφαρμογή <xliff:g id="APP_NAME">%1$s</xliff:g> αποτελεί το παράθυρο διαλόγου ελέγχου έντασης"</string>
    +     <string name="volumeui_notification_text" msgid="8819536904234337445">"Πατήστε για να επαναφέρετε την αρχική μορφή της εικόνας."</string>
    +@@ -492,8 +494,6 @@
    +     <string name="clock_seconds_desc" msgid="6282693067130470675">"Εμφάνιση δευτερολέπτων ρολογιού στη γραμμή κατάστασης. Ενδέχεται να επηρεάσει τη διάρκεια ζωής της μπαταρίας."</string>
    +     <string name="qs_rearrange" msgid="8060918697551068765">"Αναδιάταξη Γρήγορων ρυθμίσεων"</string>
    +     <string name="show_brightness" msgid="6613930842805942519">"Εμφάνιση φωτεινότητας στις Γρήγορες ρυθμίσεις"</string>
    +-    <string name="overview_nav_bar_gesture" msgid="8579814204727917764">"Ενεργοποίηση κίνησης ολίσθησης επάνω για διαχωρισμό οθόνης"</string>
    +-    <string name="overview_nav_bar_gesture_desc" msgid="6329167382305102615">"Ενεργοποίηση κίνησης για μετάβαση σε διαχωρισμό οθόνης μέσω ολίσθησης επάνω από το κουμπί \"Επισκόπηση\""</string>
    +     <string name="experimental" msgid="6198182315536726162">"Σε πειραματικό στάδιο"</string>
    +     <string name="enable_bluetooth_title" msgid="5027037706500635269">"Ενεργοποίηση Bluetooth;"</string>
    +     <string name="enable_bluetooth_message" msgid="9106595990708985385">"Για να συνδέσετε το πληκτρολόγιο με το tablet σας, θα πρέπει πρώτα να ενεργοποιήσετε το Bluetooth."</string>
    +@@ -651,4 +651,5 @@
    +     <string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"Άνοιγμα ρυθμίσεων <xliff:g id="ID_1">%s</xliff:g>."</string>
    +     <string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"Επεξεργασία σειράς ρυθμίσεων."</string>
    +     <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"Σελίδα <xliff:g id="ID_1">%1$d</xliff:g> από <xliff:g id="ID_2">%2$d</xliff:g>"</string>
    ++    <string name="cant_silence_or_block" msgid="999689262131488625">"Δεν είναι δυνατή η σίγαση ή ο αποκλεισμός των ειδοποιήσεων"</string>
    + </resources>
    +diff --git a/packages/SystemUI/res/values-en-rAU/strings.xml b/packages/SystemUI/res/values-en-rAU/strings.xml
    +index 9443ad9..bed0f5c 100644
    +--- a/packages/SystemUI/res/values-en-rAU/strings.xml
    ++++ b/packages/SystemUI/res/values-en-rAU/strings.xml
    +@@ -238,7 +238,7 @@
    +     <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"4G data is paused"</string>
    +     <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"Mobile data is paused"</string>
    +     <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"Data is paused"</string>
    +-    <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"Because your set data limit was reached, the device has paused data usage for the remainder of this cycle.\n\nResuming may lead to charges from your operator."</string>
    ++    <string name="data_usage_disabled_dialog" msgid="1841738975235283398">"The data limit you have set has been reached. You are no longer using mobile data.\n\nIf you resume, charges may apply for data usage."</string>
    +     <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"Resume"</string>
    +     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"No Internet connection"</string>
    +     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi connected"</string>
    +@@ -404,6 +404,7 @@
    +     <string name="device_owned_footer" msgid="3802752663326030053">"Device may be monitored"</string>
    +     <string name="profile_owned_footer" msgid="8021888108553696069">"Profile may be monitored"</string>
    +     <string name="vpn_footer" msgid="2388611096129106812">"Network may be monitored"</string>
    ++    <string name="branded_vpn_footer" msgid="2168111859226496230">"Network may be monitored"</string>
    +     <string name="monitoring_title_device_owned" msgid="7121079311903859610">"Device monitoring"</string>
    +     <string name="monitoring_title_profile_owned" msgid="6790109874733501487">"Profile monitoring"</string>
    +     <string name="monitoring_title" msgid="169206259253048106">"Network monitoring"</string>
    +@@ -416,6 +417,7 @@
    +     <string name="legacy_vpn_name" msgid="6604123105765737830">"VPN"</string>
    +     <string name="monitoring_description_app" msgid="6259179342284742878">"You\'re connected to <xliff:g id="APPLICATION">%1$s</xliff:g>, which can monitor your network activity including emails, apps and websites."</string>
    +     <string name="monitoring_description_app_personal" msgid="484599052118316268">"You\'re connected to <xliff:g id="APPLICATION">%1$s</xliff:g>, which can monitor your personal network activity, including emails, apps and websites."</string>
    ++    <string name="branded_monitoring_description_app_personal" msgid="2669518213949202599">"You\'re connected to <xliff:g id="APPLICATION">%1$s</xliff:g>, which can monitor your personal network activity, including emails, apps and websites."</string>
    +     <string name="monitoring_description_app_work" msgid="1754325860918060897">"Your work profile is managed by <xliff:g id="ORGANIZATION">%1$s</xliff:g>. It is connected to <xliff:g id="APPLICATION">%2$s</xliff:g>, which can monitor your work network activity, including emails, apps and websites.\n\nFor more information, contact your administrator."</string>
    +     <string name="monitoring_description_app_personal_work" msgid="4946600443852045903">"Your work profile is managed by <xliff:g id="ORGANIZATION">%1$s</xliff:g>. It is connected to <xliff:g id="APPLICATION_WORK">%2$s</xliff:g>, which can monitor your work network activity, including emails, apps and websites.\n\nYou\'re also connected to <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g>, which can monitor your personal network activity."</string>
    +     <string name="monitoring_description_vpn_app_device_owned" msgid="4970443827043261703">"Your device is managed by <xliff:g id="ORGANIZATION">%1$s</xliff:g>.\n\nYour administrator can monitor and manage settings, corporate access, apps, data associated with your device, and your device\'s location information.\n\nYou\'re connected to <xliff:g id="APPLICATION">%2$s</xliff:g>, which can monitor your network activity, including emails, apps, and websites.\n\nFor more information, contact your administrator."</string>
    +@@ -492,8 +494,6 @@
    +     <string name="clock_seconds_desc" msgid="6282693067130470675">"Show clock seconds in the status bar. May impact battery life."</string>
    +     <string name="qs_rearrange" msgid="8060918697551068765">"Rearrange Quick Settings"</string>
    +     <string name="show_brightness" msgid="6613930842805942519">"Show brightness in Quick Settings"</string>
    +-    <string name="overview_nav_bar_gesture" msgid="8579814204727917764">"Enable split-screen swipe-up gesture"</string>
    +-    <string name="overview_nav_bar_gesture_desc" msgid="6329167382305102615">"Enable gesture to enter split-screen by swiping up from the Overview button"</string>
    +     <string name="experimental" msgid="6198182315536726162">"Experimental"</string>
    +     <string name="enable_bluetooth_title" msgid="5027037706500635269">"Turn on Bluetooth?"</string>
    +     <string name="enable_bluetooth_message" msgid="9106595990708985385">"To connect your keyboard with your tablet, you first have to turn on Bluetooth."</string>
    +@@ -651,4 +651,5 @@
    +     <string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"Open <xliff:g id="ID_1">%s</xliff:g> settings."</string>
    +     <string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"Edit order of settings."</string>
    +     <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"Page <xliff:g id="ID_1">%1$d</xliff:g> of <xliff:g id="ID_2">%2$d</xliff:g>"</string>
    ++    <string name="cant_silence_or_block" msgid="999689262131488625">"Notifications can\'t be silenced or blocked"</string>
    + </resources>
    +diff --git a/packages/SystemUI/res/values-en-rGB/strings.xml b/packages/SystemUI/res/values-en-rGB/strings.xml
    +index 9443ad9..bed0f5c 100644
    +--- a/packages/SystemUI/res/values-en-rGB/strings.xml
    ++++ b/packages/SystemUI/res/values-en-rGB/strings.xml
    +@@ -238,7 +238,7 @@
    +     <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"4G data is paused"</string>
    +     <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"Mobile data is paused"</string>
    +     <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"Data is paused"</string>
    +-    <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"Because your set data limit was reached, the device has paused data usage for the remainder of this cycle.\n\nResuming may lead to charges from your operator."</string>
    ++    <string name="data_usage_disabled_dialog" msgid="1841738975235283398">"The data limit you have set has been reached. You are no longer using mobile data.\n\nIf you resume, charges may apply for data usage."</string>
    +     <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"Resume"</string>
    +     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"No Internet connection"</string>
    +     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi connected"</string>
    +@@ -404,6 +404,7 @@
    +     <string name="device_owned_footer" msgid="3802752663326030053">"Device may be monitored"</string>
    +     <string name="profile_owned_footer" msgid="8021888108553696069">"Profile may be monitored"</string>
    +     <string name="vpn_footer" msgid="2388611096129106812">"Network may be monitored"</string>
    ++    <string name="branded_vpn_footer" msgid="2168111859226496230">"Network may be monitored"</string>
    +     <string name="monitoring_title_device_owned" msgid="7121079311903859610">"Device monitoring"</string>
    +     <string name="monitoring_title_profile_owned" msgid="6790109874733501487">"Profile monitoring"</string>
    +     <string name="monitoring_title" msgid="169206259253048106">"Network monitoring"</string>
    +@@ -416,6 +417,7 @@
    +     <string name="legacy_vpn_name" msgid="6604123105765737830">"VPN"</string>
    +     <string name="monitoring_description_app" msgid="6259179342284742878">"You\'re connected to <xliff:g id="APPLICATION">%1$s</xliff:g>, which can monitor your network activity including emails, apps and websites."</string>
    +     <string name="monitoring_description_app_personal" msgid="484599052118316268">"You\'re connected to <xliff:g id="APPLICATION">%1$s</xliff:g>, which can monitor your personal network activity, including emails, apps and websites."</string>
    ++    <string name="branded_monitoring_description_app_personal" msgid="2669518213949202599">"You\'re connected to <xliff:g id="APPLICATION">%1$s</xliff:g>, which can monitor your personal network activity, including emails, apps and websites."</string>
    +     <string name="monitoring_description_app_work" msgid="1754325860918060897">"Your work profile is managed by <xliff:g id="ORGANIZATION">%1$s</xliff:g>. It is connected to <xliff:g id="APPLICATION">%2$s</xliff:g>, which can monitor your work network activity, including emails, apps and websites.\n\nFor more information, contact your administrator."</string>
    +     <string name="monitoring_description_app_personal_work" msgid="4946600443852045903">"Your work profile is managed by <xliff:g id="ORGANIZATION">%1$s</xliff:g>. It is connected to <xliff:g id="APPLICATION_WORK">%2$s</xliff:g>, which can monitor your work network activity, including emails, apps and websites.\n\nYou\'re also connected to <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g>, which can monitor your personal network activity."</string>
    +     <string name="monitoring_description_vpn_app_device_owned" msgid="4970443827043261703">"Your device is managed by <xliff:g id="ORGANIZATION">%1$s</xliff:g>.\n\nYour administrator can monitor and manage settings, corporate access, apps, data associated with your device, and your device\'s location information.\n\nYou\'re connected to <xliff:g id="APPLICATION">%2$s</xliff:g>, which can monitor your network activity, including emails, apps, and websites.\n\nFor more information, contact your administrator."</string>
    +@@ -492,8 +494,6 @@
    +     <string name="clock_seconds_desc" msgid="6282693067130470675">"Show clock seconds in the status bar. May impact battery life."</string>
    +     <string name="qs_rearrange" msgid="8060918697551068765">"Rearrange Quick Settings"</string>
    +     <string name="show_brightness" msgid="6613930842805942519">"Show brightness in Quick Settings"</string>
    +-    <string name="overview_nav_bar_gesture" msgid="8579814204727917764">"Enable split-screen swipe-up gesture"</string>
    +-    <string name="overview_nav_bar_gesture_desc" msgid="6329167382305102615">"Enable gesture to enter split-screen by swiping up from the Overview button"</string>
    +     <string name="experimental" msgid="6198182315536726162">"Experimental"</string>
    +     <string name="enable_bluetooth_title" msgid="5027037706500635269">"Turn on Bluetooth?"</string>
    +     <string name="enable_bluetooth_message" msgid="9106595990708985385">"To connect your keyboard with your tablet, you first have to turn on Bluetooth."</string>
    +@@ -651,4 +651,5 @@
    +     <string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"Open <xliff:g id="ID_1">%s</xliff:g> settings."</string>
    +     <string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"Edit order of settings."</string>
    +     <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"Page <xliff:g id="ID_1">%1$d</xliff:g> of <xliff:g id="ID_2">%2$d</xliff:g>"</string>
    ++    <string name="cant_silence_or_block" msgid="999689262131488625">"Notifications can\'t be silenced or blocked"</string>
    + </resources>
    +diff --git a/packages/SystemUI/res/values-en-rIN/strings.xml b/packages/SystemUI/res/values-en-rIN/strings.xml
    +index 9443ad9..bed0f5c 100644
    +--- a/packages/SystemUI/res/values-en-rIN/strings.xml
    ++++ b/packages/SystemUI/res/values-en-rIN/strings.xml
    +@@ -238,7 +238,7 @@
    +     <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"4G data is paused"</string>
    +     <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"Mobile data is paused"</string>
    +     <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"Data is paused"</string>
    +-    <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"Because your set data limit was reached, the device has paused data usage for the remainder of this cycle.\n\nResuming may lead to charges from your operator."</string>
    ++    <string name="data_usage_disabled_dialog" msgid="1841738975235283398">"The data limit you have set has been reached. You are no longer using mobile data.\n\nIf you resume, charges may apply for data usage."</string>
    +     <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"Resume"</string>
    +     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"No Internet connection"</string>
    +     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi connected"</string>
    +@@ -404,6 +404,7 @@
    +     <string name="device_owned_footer" msgid="3802752663326030053">"Device may be monitored"</string>
    +     <string name="profile_owned_footer" msgid="8021888108553696069">"Profile may be monitored"</string>
    +     <string name="vpn_footer" msgid="2388611096129106812">"Network may be monitored"</string>
    ++    <string name="branded_vpn_footer" msgid="2168111859226496230">"Network may be monitored"</string>
    +     <string name="monitoring_title_device_owned" msgid="7121079311903859610">"Device monitoring"</string>
    +     <string name="monitoring_title_profile_owned" msgid="6790109874733501487">"Profile monitoring"</string>
    +     <string name="monitoring_title" msgid="169206259253048106">"Network monitoring"</string>
    +@@ -416,6 +417,7 @@
    +     <string name="legacy_vpn_name" msgid="6604123105765737830">"VPN"</string>
    +     <string name="monitoring_description_app" msgid="6259179342284742878">"You\'re connected to <xliff:g id="APPLICATION">%1$s</xliff:g>, which can monitor your network activity including emails, apps and websites."</string>
    +     <string name="monitoring_description_app_personal" msgid="484599052118316268">"You\'re connected to <xliff:g id="APPLICATION">%1$s</xliff:g>, which can monitor your personal network activity, including emails, apps and websites."</string>
    ++    <string name="branded_monitoring_description_app_personal" msgid="2669518213949202599">"You\'re connected to <xliff:g id="APPLICATION">%1$s</xliff:g>, which can monitor your personal network activity, including emails, apps and websites."</string>
    +     <string name="monitoring_description_app_work" msgid="1754325860918060897">"Your work profile is managed by <xliff:g id="ORGANIZATION">%1$s</xliff:g>. It is connected to <xliff:g id="APPLICATION">%2$s</xliff:g>, which can monitor your work network activity, including emails, apps and websites.\n\nFor more information, contact your administrator."</string>
    +     <string name="monitoring_description_app_personal_work" msgid="4946600443852045903">"Your work profile is managed by <xliff:g id="ORGANIZATION">%1$s</xliff:g>. It is connected to <xliff:g id="APPLICATION_WORK">%2$s</xliff:g>, which can monitor your work network activity, including emails, apps and websites.\n\nYou\'re also connected to <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g>, which can monitor your personal network activity."</string>
    +     <string name="monitoring_description_vpn_app_device_owned" msgid="4970443827043261703">"Your device is managed by <xliff:g id="ORGANIZATION">%1$s</xliff:g>.\n\nYour administrator can monitor and manage settings, corporate access, apps, data associated with your device, and your device\'s location information.\n\nYou\'re connected to <xliff:g id="APPLICATION">%2$s</xliff:g>, which can monitor your network activity, including emails, apps, and websites.\n\nFor more information, contact your administrator."</string>
    +@@ -492,8 +494,6 @@
    +     <string name="clock_seconds_desc" msgid="6282693067130470675">"Show clock seconds in the status bar. May impact battery life."</string>
    +     <string name="qs_rearrange" msgid="8060918697551068765">"Rearrange Quick Settings"</string>
    +     <string name="show_brightness" msgid="6613930842805942519">"Show brightness in Quick Settings"</string>
    +-    <string name="overview_nav_bar_gesture" msgid="8579814204727917764">"Enable split-screen swipe-up gesture"</string>
    +-    <string name="overview_nav_bar_gesture_desc" msgid="6329167382305102615">"Enable gesture to enter split-screen by swiping up from the Overview button"</string>
    +     <string name="experimental" msgid="6198182315536726162">"Experimental"</string>
    +     <string name="enable_bluetooth_title" msgid="5027037706500635269">"Turn on Bluetooth?"</string>
    +     <string name="enable_bluetooth_message" msgid="9106595990708985385">"To connect your keyboard with your tablet, you first have to turn on Bluetooth."</string>
    +@@ -651,4 +651,5 @@
    +     <string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"Open <xliff:g id="ID_1">%s</xliff:g> settings."</string>
    +     <string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"Edit order of settings."</string>
    +     <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"Page <xliff:g id="ID_1">%1$d</xliff:g> of <xliff:g id="ID_2">%2$d</xliff:g>"</string>
    ++    <string name="cant_silence_or_block" msgid="999689262131488625">"Notifications can\'t be silenced or blocked"</string>
    + </resources>
    +diff --git a/packages/SystemUI/res/values-es-rUS/strings.xml b/packages/SystemUI/res/values-es-rUS/strings.xml
    +index 602d6b2..485d2e0 100644
    +--- a/packages/SystemUI/res/values-es-rUS/strings.xml
    ++++ b/packages/SystemUI/res/values-es-rUS/strings.xml
    +@@ -240,7 +240,7 @@
    +     <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"Datos 4G pausados"</string>
    +     <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"Datos móviles pausados"</string>
    +     <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"Datos pausados"</string>
    +-    <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"Debido que se alcanzó el límite de datos establecido, el dispositivo pausó el uso de datos para el resto de este ciclo.\n\nLa reanudación podría tener como resultado cargos del proveedor."</string>
    ++    <string name="data_usage_disabled_dialog" msgid="1841738975235283398">"Se alcanzó el límite de datos que estableciste. Ya no estás usando datos móviles.\n\nSi reanudas el uso de datos, es posible que se apliquen cargos."</string>
    +     <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"Reanudar"</string>
    +     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Sin conexión a Internet"</string>
    +     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi conectado"</string>
    +@@ -406,6 +406,7 @@
    +     <string name="device_owned_footer" msgid="3802752663326030053">"Es posible que el dispositivo esté supervisado."</string>
    +     <string name="profile_owned_footer" msgid="8021888108553696069">"Es posible que se supervise el perfil."</string>
    +     <string name="vpn_footer" msgid="2388611096129106812">"Es posible que la red esté supervisada."</string>
    ++    <string name="branded_vpn_footer" msgid="2168111859226496230">"Es posible que la red esté supervisada"</string>
    +     <string name="monitoring_title_device_owned" msgid="7121079311903859610">"Supervisión del dispositivo"</string>
    +     <string name="monitoring_title_profile_owned" msgid="6790109874733501487">"Supervisión del perfil"</string>
    +     <string name="monitoring_title" msgid="169206259253048106">"Supervisión de red"</string>
    +@@ -418,6 +419,7 @@
    +     <string name="legacy_vpn_name" msgid="6604123105765737830">"VPN"</string>
    +     <string name="monitoring_description_app" msgid="6259179342284742878">"Tienes conexión a la aplicación <xliff:g id="APPLICATION">%1$s</xliff:g>, que puede supervisar la actividad de la red, incluidos los correos electrónicos, las aplicaciones y los sitios web."</string>
    +     <string name="monitoring_description_app_personal" msgid="484599052118316268">"Tienes conexión a la aplicación <xliff:g id="APPLICATION">%1$s</xliff:g>, que puede supervisar la actividad de la red personal, incluidos los correos electrónicos, las aplicaciones y los sitios web."</string>
    ++    <string name="branded_monitoring_description_app_personal" msgid="2669518213949202599">"Te conectaste a <xliff:g id="APPLICATION">%1$s</xliff:g>, que puede supervisar la actividad de tu red personal, incluidos los correos electrónicos, las apps y los sitios web."</string>
    +     <string name="monitoring_description_app_work" msgid="1754325860918060897">"<xliff:g id="ORGANIZATION">%1$s</xliff:g> administra tu perfil de trabajo. Tiene conexión a <xliff:g id="APPLICATION">%2$s</xliff:g>, que puede supervisar la actividad de tu red de trabajo, incluidos los correos electrónicos, las aplicaciones y los sitios web.\n\nPara obtener más información, comunícate con el administrador."</string>
    +     <string name="monitoring_description_app_personal_work" msgid="4946600443852045903">"<xliff:g id="ORGANIZATION">%1$s</xliff:g> administra tu perfil de trabajo. Tiene conexión a <xliff:g id="APPLICATION_WORK">%2$s</xliff:g>, que puede supervisar la actividad de tu red de trabajo, incluidos los correos electrónicos, las aplicaciones y los sitios web.\n\nTambién tienes conexión a <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g>, que puede supervisar la actividad de la red personal."</string>
    +     <string name="monitoring_description_vpn_app_device_owned" msgid="4970443827043261703">"<xliff:g id="ORGANIZATION">%1$s</xliff:g> administra tu dispositivo.\n\nEl administrador puede supervisar y administrar la configuración, el acceso corporativo, las aplicaciones, los datos asociados al dispositivo y la información de la ubicación.\n\nTienes conexión a <xliff:g id="APPLICATION">%2$s</xliff:g>, que puede supervisar la actividad de la red, incluidos los correos electrónicos, las aplicaciones y los sitios web.\n\nPara obtener más información, comunícate con el administrador."</string>
    +@@ -494,8 +496,6 @@
    +     <string name="clock_seconds_desc" msgid="6282693067130470675">"Muestra los segundos del reloj en la barra de estado. Puede afectar la duración de la batería."</string>
    +     <string name="qs_rearrange" msgid="8060918697551068765">"Reorganizar la Configuración rápida"</string>
    +     <string name="show_brightness" msgid="6613930842805942519">"Mostrar el brillo en la Configuración rápida"</string>
    +-    <string name="overview_nav_bar_gesture" msgid="8579814204727917764">"Habilitar gesto de dedo hacia arriba para dividir pantalla"</string>
    +-    <string name="overview_nav_bar_gesture_desc" msgid="6329167382305102615">"Habilita el gesto de deslizar el dedo hacia arriba desde el botón Recientes para acceder al modo de pantalla dividida"</string>
    +     <string name="experimental" msgid="6198182315536726162">"Experimental"</string>
    +     <string name="enable_bluetooth_title" msgid="5027037706500635269">"¿Activar Bluetooth?"</string>
    +     <string name="enable_bluetooth_message" msgid="9106595990708985385">"Para conectar el teclado con la tablet, primero debes activar Bluetooth."</string>
    +@@ -653,4 +653,5 @@
    +     <string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"Abrir configuración de <xliff:g id="ID_1">%s</xliff:g>"</string>
    +     <string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"Editar orden de configuración"</string>
    +     <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"Página <xliff:g id="ID_1">%1$d</xliff:g> de <xliff:g id="ID_2">%2$d</xliff:g>"</string>
    ++    <string name="cant_silence_or_block" msgid="999689262131488625">"Las notificaciones no se pueden silenciar ni bloquear"</string>
    + </resources>
    +diff --git a/packages/SystemUI/res/values-es/strings.xml b/packages/SystemUI/res/values-es/strings.xml
    +index ba11d6f..0e0f412 100644
    +--- a/packages/SystemUI/res/values-es/strings.xml
    ++++ b/packages/SystemUI/res/values-es/strings.xml
    +@@ -233,14 +233,14 @@
    +     <string name="accessibility_quick_settings_work_mode_on" msgid="7650588553988014341">"Modo de trabajo activado."</string>
    +     <string name="accessibility_quick_settings_work_mode_changed_off" msgid="5605534876107300711">"Modo de trabajo desactivado."</string>
    +     <string name="accessibility_quick_settings_work_mode_changed_on" msgid="249840330756998612">"Modo de trabajo activado."</string>
    +-    <string name="accessibility_quick_settings_data_saver_changed_off" msgid="650231949881093289">"Economizador de Datos desactivado."</string>
    +-    <string name="accessibility_quick_settings_data_saver_changed_on" msgid="4218725402373934151">"Economizador de Datos activado."</string>
    ++    <string name="accessibility_quick_settings_data_saver_changed_off" msgid="650231949881093289">"Ahorro de datos desactivado."</string>
    ++    <string name="accessibility_quick_settings_data_saver_changed_on" msgid="4218725402373934151">"Ahorro de datos activado."</string>
    +     <string name="accessibility_brightness" msgid="8003681285547803095">"Brillo de la pantalla"</string>
    +     <string name="data_usage_disabled_dialog_3g_title" msgid="5281770593459841889">"Datos 2G-3G pausados"</string>
    +     <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"Datos 4G pausados"</string>
    +     <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"Datos móviles pausados"</string>
    +     <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"Datos pausados"</string>
    +-    <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"Has alcanzado el límite de datos establecido, por lo que el dispositivo ha pausado el uso de datos para el resto de este ciclo.\n\nSi lo reanudas, el operador puede facturar cargos."</string>
    ++    <string name="data_usage_disabled_dialog" msgid="1841738975235283398">"Se ha alcanzado el límite de datos establecido. Ya no estás utilizando datos móviles.\n\nSi vuelves a activar el uso de datos, es posible que se apliquen cargos."</string>
    +     <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"Reanudar"</string>
    +     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Sin conexión a Internet"</string>
    +     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Con conexión Wi-Fi"</string>
    +@@ -406,6 +406,7 @@
    +     <string name="device_owned_footer" msgid="3802752663326030053">"Es posible que este dispositivo esté supervisado"</string>
    +     <string name="profile_owned_footer" msgid="8021888108553696069">"Es posible que se supervise el perfil"</string>
    +     <string name="vpn_footer" msgid="2388611096129106812">"Puede que la red esté supervisada"</string>
    ++    <string name="branded_vpn_footer" msgid="2168111859226496230">"Puede que la red esté supervisada"</string>
    +     <string name="monitoring_title_device_owned" msgid="7121079311903859610">"Supervisión de dispositivo"</string>
    +     <string name="monitoring_title_profile_owned" msgid="6790109874733501487">"Supervisión del perfil"</string>
    +     <string name="monitoring_title" msgid="169206259253048106">"Supervisión de red"</string>
    +@@ -418,6 +419,7 @@
    +     <string name="legacy_vpn_name" msgid="6604123105765737830">"VPN"</string>
    +     <string name="monitoring_description_app" msgid="6259179342284742878">"Estás conectado a <xliff:g id="APPLICATION">%1$s</xliff:g>, que puede controlar tu actividad de red, como correos electrónicos, aplicaciones y sitios web."</string>
    +     <string name="monitoring_description_app_personal" msgid="484599052118316268">"Estas conectado a <xliff:g id="APPLICATION">%1$s</xliff:g>, que puede controlar tu actividad de red personal, como correos electrónicos, aplicaciones y sitios web."</string>
    ++    <string name="branded_monitoring_description_app_personal" msgid="2669518213949202599">"Estas conectado a <xliff:g id="APPLICATION">%1$s</xliff:g>, que puede controlar tu actividad de red personal, como correos electrónicos, aplicaciones y sitios web."</string>
    +     <string name="monitoring_description_app_work" msgid="1754325860918060897">"El administrador de tu perfil de trabajo es <xliff:g id="ORGANIZATION">%1$s</xliff:g> y está conectado a <xliff:g id="APPLICATION">%2$s</xliff:g>, que puede controlar tu actividad de red del trabajo, como correos electrónicos, aplicaciones y sitios web.\n\nPara obtener más información, ponte en contacto con el administrador."</string>
    +     <string name="monitoring_description_app_personal_work" msgid="4946600443852045903">"El administrador de tu perfil de trabajo es <xliff:g id="ORGANIZATION">%1$s</xliff:g> y está conectado a <xliff:g id="APPLICATION_WORK">%2$s</xliff:g>, que puede controlar tu actividad de red, como correos electrónicos, aplicaciones y sitios web.\n\nTú también estás conectado a <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g>, que puede controlar tu actividad de red personal."</string>
    +     <string name="monitoring_description_vpn_app_device_owned" msgid="4970443827043261703">"El administrador de tu dispositivo es <xliff:g id="ORGANIZATION">%1$s</xliff:g>.\n\nTu administrador puede supervisar y administrar los ajustes, el acceso corporativo, las aplicaciones, los datos asociados al dispositivo e información de su ubicación.\n\nEstás conectado a <xliff:g id="APPLICATION">%2$s</xliff:g>, que puede supervisar tu actividad de red, como correos electrónicos, aplicaciones y sitios web.\n\nPara obtener más información, ponte en contacto con tu administrador."</string>
    +@@ -494,8 +496,6 @@
    +     <string name="clock_seconds_desc" msgid="6282693067130470675">"Muestra los segundos del reloj en la barra de estado. Puede afectar a la duración de la batería."</string>
    +     <string name="qs_rearrange" msgid="8060918697551068765">"Reorganizar Ajustes rápidos"</string>
    +     <string name="show_brightness" msgid="6613930842805942519">"Mostrar brillo en Ajustes rápidos"</string>
    +-    <string name="overview_nav_bar_gesture" msgid="8579814204727917764">"Habilitar deslizar dedo hacia arriba para dividir pantalla"</string>
    +-    <string name="overview_nav_bar_gesture_desc" msgid="6329167382305102615">"Habilita el gesto de deslizar el dedo hacia arriba desde el botón Aplicaciones recientes para acceder al modo de pantalla dividida"</string>
    +     <string name="experimental" msgid="6198182315536726162">"Experimental"</string>
    +     <string name="enable_bluetooth_title" msgid="5027037706500635269">"¿Activar Bluetooth?"</string>
    +     <string name="enable_bluetooth_message" msgid="9106595990708985385">"Para poder conectar tu teclado a tu tablet, debes activar el Bluetooth."</string>
    +@@ -580,9 +580,9 @@
    +     <string name="headset" msgid="4534219457597457353">"Auriculares"</string>
    +     <string name="accessibility_status_bar_headphones" msgid="9156307120060559989">"Auriculares conectados"</string>
    +     <string name="accessibility_status_bar_headset" msgid="8666419213072449202">"Auriculares conectados"</string>
    +-    <string name="data_saver" msgid="5037565123367048522">"Economizador de Datos"</string>
    +-    <string name="accessibility_data_saver_on" msgid="8454111686783887148">"Economizador de Datos activado"</string>
    +-    <string name="accessibility_data_saver_off" msgid="8841582529453005337">"Economizador de Datos desactivado"</string>
    ++    <string name="data_saver" msgid="5037565123367048522">"Ahorro de datos"</string>
    ++    <string name="accessibility_data_saver_on" msgid="8454111686783887148">"Ahorro de datos activado"</string>
    ++    <string name="accessibility_data_saver_off" msgid="8841582529453005337">"Ahorro de datos desactivado"</string>
    +     <string name="switch_bar_on" msgid="1142437840752794229">"Sí"</string>
    +     <string name="switch_bar_off" msgid="8803270596930432874">"No"</string>
    +     <string name="nav_bar" msgid="1993221402773877607">"Barra de navegación"</string>
    +@@ -653,4 +653,5 @@
    +     <string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"Abrir ajustes de <xliff:g id="ID_1">%s</xliff:g>."</string>
    +     <string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"Cambiar el orden de los ajustes."</string>
    +     <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"Página <xliff:g id="ID_1">%1$d</xliff:g> de <xliff:g id="ID_2">%2$d</xliff:g>"</string>
    ++    <string name="cant_silence_or_block" msgid="999689262131488625">"Las notificaciones no se pueden silenciar ni bloquear"</string>
    + </resources>
    +diff --git a/packages/SystemUI/res/values-et-rEE/strings.xml b/packages/SystemUI/res/values-et-rEE/strings.xml
    +index bfc55e9..0cdf8d2 100644
    +--- a/packages/SystemUI/res/values-et-rEE/strings.xml
    ++++ b/packages/SystemUI/res/values-et-rEE/strings.xml
    +@@ -47,7 +47,7 @@
    +     <string name="status_bar_settings_auto_rotation" msgid="3790482541357798421">"Pööra ekraani automaatselt"</string>
    +     <string name="status_bar_settings_mute_label" msgid="554682549917429396">"SUMMUTA"</string>
    +     <string name="status_bar_settings_auto_brightness_label" msgid="511453614962324674">"AUTO"</string>
    +-    <string name="status_bar_settings_notifications" msgid="397146176280905137">"Teatised"</string>
    ++    <string name="status_bar_settings_notifications" msgid="397146176280905137">"Märguanded"</string>
    +     <string name="bluetooth_tethered" msgid="7094101612161133267">"Bluetooth on jagatud"</string>
    +     <string name="status_bar_input_method_settings_configure_input_methods" msgid="3504292471512317827">"Seadista sisestusmeetodeid"</string>
    +     <string name="status_bar_use_physical_keyboard" msgid="7551903084416057810">"Füüsiline klaviatuur"</string>
    +@@ -164,7 +164,7 @@
    +     <!-- no translation found for accessibility_battery_level_charging (1147587904439319646) -->
    +     <skip />
    +     <string name="accessibility_settings_button" msgid="799583911231893380">"Süsteemiseaded"</string>
    +-    <string name="accessibility_notifications_button" msgid="4498000369779421892">"Teatised"</string>
    ++    <string name="accessibility_notifications_button" msgid="4498000369779421892">"Märguanded"</string>
    +     <string name="accessibility_remove_notification" msgid="3603099514902182350">"Märguande eemaldamine."</string>
    +     <string name="accessibility_gps_enabled" msgid="3511469499240123019">"GPS on lubatud."</string>
    +     <string name="accessibility_gps_acquiring" msgid="8959333351058967158">"GPS-signaali otsimine."</string>
    +@@ -240,7 +240,7 @@
    +     <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"4G andmekasutus on peatatud"</string>
    +     <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"Mobiilse andmeside kasutus on peatatud"</string>
    +     <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"Andmekasutus on peatatud"</string>
    +-    <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"Kuna jõudsite andmemahu määratud piirini, peatas seade andmekasutuse ülejäänud tsükliks.\n\nJätkamisel võivad lisanduda operaatoritasud."</string>
    ++    <string name="data_usage_disabled_dialog" msgid="1841738975235283398">"Olete jõudnud enda määratud andmemahupiiranguni. Te ei kasuta enam mobiilset andmesidet.\n\nKui jätkate, võivad rakenduda andmekasutustasud."</string>
    +     <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"Jätka"</string>
    +     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Interneti-ühendus puudub"</string>
    +     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"WiFi on ühendatud"</string>
    +@@ -406,6 +406,7 @@
    +     <string name="device_owned_footer" msgid="3802752663326030053">"Seadet võidakse jälgida"</string>
    +     <string name="profile_owned_footer" msgid="8021888108553696069">"Profiili võidakse jälgida"</string>
    +     <string name="vpn_footer" msgid="2388611096129106812">"Võrku võidakse jälgida"</string>
    ++    <string name="branded_vpn_footer" msgid="2168111859226496230">"Võrku võidakse jälgida"</string>
    +     <string name="monitoring_title_device_owned" msgid="7121079311903859610">"Seadme jälgimine"</string>
    +     <string name="monitoring_title_profile_owned" msgid="6790109874733501487">"Profiili jälgimine"</string>
    +     <string name="monitoring_title" msgid="169206259253048106">"Võrgu jälgimine"</string>
    +@@ -418,6 +419,7 @@
    +     <string name="legacy_vpn_name" msgid="6604123105765737830">"VPN"</string>
    +     <string name="monitoring_description_app" msgid="6259179342284742878">"Teie seade on ühendatud rakendusega <xliff:g id="APPLICATION">%1$s</xliff:g>, mis võib jälgida teie võrgutegevusi, sh meile, rakendusi ja veebisaite."</string>
    +     <string name="monitoring_description_app_personal" msgid="484599052118316268">"Teie seade on ühendatud rakendusega <xliff:g id="APPLICATION">%1$s</xliff:g>, mis võib jälgida teie isiklikke võrgutegevusi, sh meile, rakendusi ja veebisaite."</string>
    ++    <string name="branded_monitoring_description_app_personal" msgid="2669518213949202599">"Olete ühendatud rakendusega <xliff:g id="APPLICATION">%1$s</xliff:g>, mis võib jälgida teie isiklikke võrgutegevusi, sh meile, rakendusi ja veebisaite."</string>
    +     <string name="monitoring_description_app_work" msgid="1754325860918060897">"Teie tööprofiili haldab organisatsioon <xliff:g id="ORGANIZATION">%1$s</xliff:g>. See on ühendatud rakendusega <xliff:g id="APPLICATION">%2$s</xliff:g>, mis võib jälgida teie töökoha võrgutegevusi, sh meile, rakendusi ja veebisaite.\n\nLisateabe saamiseks võtke ühendust administraatoriga."</string>
    +     <string name="monitoring_description_app_personal_work" msgid="4946600443852045903">"Teie tööprofiili haldab organisatsioon <xliff:g id="ORGANIZATION">%1$s</xliff:g>. See on ühendatud rakendusega <xliff:g id="APPLICATION_WORK">%2$s</xliff:g>, mis võib jälgida teie töökoha võrgutegevusi, sh meile, rakendusi ja veebisaite.\n\nTeie seade on ühendatud ka rakendusega <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g>, mis võib jälgida teie isiklikke võrgutegevusi."</string>
    +     <string name="monitoring_description_vpn_app_device_owned" msgid="4970443827043261703">"Teie seadet haldab organisatsioon <xliff:g id="ORGANIZATION">%1$s</xliff:g>.\n\nAdministraator saab jälgida ja hallata seadeid, ettevõttesisest juurdepääsu, rakendusi, seadmega seotud andmeid ja seadme asukohateavet.\n\nOlete ühendatud rakendusega <xliff:g id="APPLICATION">%2$s</xliff:g>, mis saab jälgida teie võrgutegevusi, sh meile, rakendusi ja veebisaite.\n\nLisateabe saamiseks võtke ühendust administraatoriga."</string>
    +@@ -494,8 +496,6 @@
    +     <string name="clock_seconds_desc" msgid="6282693067130470675">"Olekuribal kella sekundite kuvamine. See võib mõjutada aku kasutusaega."</string>
    +     <string name="qs_rearrange" msgid="8060918697551068765">"Korralda kiirseaded ümber"</string>
    +     <string name="show_brightness" msgid="6613930842805942519">"Kuva kiirseadetes heledus"</string>
    +-    <string name="overview_nav_bar_gesture" msgid="8579814204727917764">"Luba ülespühkimise liigutus ekraani poolitamiseks"</string>
    +-    <string name="overview_nav_bar_gesture_desc" msgid="6329167382305102615">"Lubab žesti, mis poolitab ekraani, kui kasutaja pühib üles nupul Ülevaade."</string>
    +     <string name="experimental" msgid="6198182315536726162">"Eksperimentaalne"</string>
    +     <string name="enable_bluetooth_title" msgid="5027037706500635269">"Kas lülitada Bluetooth sisse?"</string>
    +     <string name="enable_bluetooth_message" msgid="9106595990708985385">"Klaviatuuri ühendamiseks tahvelarvutiga peate esmalt Bluetoothi sisse lülitama."</string>
    +@@ -653,4 +653,5 @@
    +     <string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"Ava teenuse <xliff:g id="ID_1">%s</xliff:g> seaded."</string>
    +     <string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"Muuda seadete järjestust."</string>
    +     <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"Leht <xliff:g id="ID_1">%1$d</xliff:g>/<xliff:g id="ID_2">%2$d</xliff:g>"</string>
    ++    <string name="cant_silence_or_block" msgid="999689262131488625">"Märguandeid ei saa vaigistada ega blokeerida"</string>
    + </resources>
    +diff --git a/packages/SystemUI/res/values-eu-rES/strings.xml b/packages/SystemUI/res/values-eu-rES/strings.xml
    +index a340b3d..9494110 100644
    +--- a/packages/SystemUI/res/values-eu-rES/strings.xml
    ++++ b/packages/SystemUI/res/values-eu-rES/strings.xml
    +@@ -240,7 +240,7 @@
    +     <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"4G datuen erabilera eten da"</string>
    +     <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"Sare mugikorreko datuen erabilera eten da"</string>
    +     <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"Datuen erabilera eten da"</string>
    +-    <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"Zehaztuta duzun datuen erabilera-mugara iritsi zarenez, gailuak datuen erabilera eten du zikloa amaitzen den arte.\n\nDatuak erabiltzen jarraitzen baduzu, gastu gehiago ordaindu beharko dizkiozu agian operadoreari."</string>
    ++    <string name="data_usage_disabled_dialog" msgid="1841738975235283398">"Gainditu egin da ezarri duzun datu-muga. Datu-konexioa erabiltzeari utzi diozu.\n\nBerriro hasten bazara erabiltzen, baliteke datuen erabileraren kostua ordaindu behar izatea."</string>
    +     <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"Jarraitu erabiltzen"</string>
    +     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Ez duzu Interneteko konexiorik"</string>
    +     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi konektatuta"</string>
    +@@ -406,6 +406,7 @@
    +     <string name="device_owned_footer" msgid="3802752663326030053">"Baliteke gailua kontrolatuta egotea"</string>
    +     <string name="profile_owned_footer" msgid="8021888108553696069">"Baliteke profila kontrolatuta egotea"</string>
    +     <string name="vpn_footer" msgid="2388611096129106812">"Baliteke sarea kontrolatuta egotea"</string>
    ++    <string name="branded_vpn_footer" msgid="2168111859226496230">"Baliteke sarea kontrolatuta egotea"</string>
    +     <string name="monitoring_title_device_owned" msgid="7121079311903859610">"Gailuen kontrola"</string>
    +     <string name="monitoring_title_profile_owned" msgid="6790109874733501487">"Profila kontrolatzeko aukera"</string>
    +     <string name="monitoring_title" msgid="169206259253048106">"Sareen kontrola"</string>
    +@@ -418,6 +419,7 @@
    +     <string name="legacy_vpn_name" msgid="6604123105765737830">"VPN konexioa"</string>
    +     <string name="monitoring_description_app" msgid="6259179342284742878">"<xliff:g id="APPLICATION">%1$s</xliff:g> aplikaziora konektatuta zaude. Aplikazio horrek sarean egiten dituzun jarduerak kontrola ditzake, mezu elektronikoak, aplikazioak eta webguneak barne."</string>
    +     <string name="monitoring_description_app_personal" msgid="484599052118316268">"<xliff:g id="APPLICATION">%1$s</xliff:g> aplikaziora konektatuta zaude. Aplikazio horrek sarean egiten dituzun jarduera pertsonalak kontrola ditzake, mezu elektronikoak, aplikazioak eta webguneak barne."</string>
    ++    <string name="branded_monitoring_description_app_personal" msgid="2669518213949202599">"<xliff:g id="APPLICATION">%1$s</xliff:g> aplikaziora konektatuta zaude. Aplikazio horrek sarean egiten dituzun jarduera pertsonalak kontrola ditzake, mezu elektronikoak, aplikazioak eta webguneak barne."</string>
    +     <string name="monitoring_description_app_work" msgid="1754325860918060897">"<xliff:g id="ORGANIZATION">%1$s</xliff:g> da laneko profilaren kudeatzailea, eta profila <xliff:g id="APPLICATION">%2$s</xliff:g> aplikaziora konektatuta dago. Aplikazio horrek sarean egiten dituzun laneko jarduerak kontrola ditzake, mezu elektronikoak, aplikazioak eta webguneak barne.\n\nInformazio gehiago lortzeko, jarri administratzailearekin harremanetan."</string>
    +     <string name="monitoring_description_app_personal_work" msgid="4946600443852045903">"<xliff:g id="ORGANIZATION">%1$s</xliff:g> da laneko profilaren kudeatzailea, eta profila <xliff:g id="APPLICATION_WORK">%2$s</xliff:g> aplikaziora konektatuta dago. Aplikazio horrek sarean egiten dituzun laneko jarduerak kontrola ditzake, mezu elektronikoak, aplikazioak eta webguneak barne.\n\nHorrez gain, sarean egiten dituzun jarduera pertsonalak kontrola ditzakeen <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g> aplikaziora konektatuta zaude."</string>
    +     <string name="monitoring_description_vpn_app_device_owned" msgid="4970443827043261703">"<xliff:g id="ORGANIZATION">%1$s</xliff:g> da gailuaren kudeatzailea.\n\nAdministratzaileak ezarpenak, enpresako sarbidea, aplikazioak, gailuarekin lotutako datuak eta gailuaren kokapenari buruzko informazioa kontrola eta kudea ditzake.\n\n<xliff:g id="APPLICATION">%2$s</xliff:g> aplikaziora konektatuta zaude. Aplikazio horrek sarean egiten dituzun jarduerak kontrola ditzake, mezu elektronikoak, aplikazioak eta webguneak barne.\n\nInformazio gehiago lortzeko, jarri administratzailearekin harremanetan."</string>
    +@@ -494,8 +496,6 @@
    +     <string name="clock_seconds_desc" msgid="6282693067130470675">"Erakutsi erlojuko segundoak egoera-barran. Baliteke bateria gehiago erabiltzea."</string>
    +     <string name="qs_rearrange" msgid="8060918697551068765">"Berrantolatu ezarpen bizkorrak"</string>
    +     <string name="show_brightness" msgid="6613930842805942519">"Erakutsi distira Ezarpen bizkorretan"</string>
    +-    <string name="overview_nav_bar_gesture" msgid="8579814204727917764">"Gaitu pantaila zatitzeko keinua hatza gora pasatuta"</string>
    +-    <string name="overview_nav_bar_gesture_desc" msgid="6329167382305102615">"Sakatu Ikuspegi nagusia botoia eta gaitu hatza gora pasatuta pantaila zatitzeko keinua"</string>
    +     <string name="experimental" msgid="6198182315536726162">"Esperimentala"</string>
    +     <string name="enable_bluetooth_title" msgid="5027037706500635269">"Bluetooth eginbidea aktibatu nahi duzu?"</string>
    +     <string name="enable_bluetooth_message" msgid="9106595990708985385">"Teklatua tabletara konektatzeko, Bluetooth eginbidea aktibatu behar duzu."</string>
    +@@ -653,4 +653,5 @@
    +     <string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"Ireki <xliff:g id="ID_1">%s</xliff:g> ezarpenak."</string>
    +     <string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"Editatu ezarpenen ordena."</string>
    +     <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"<xliff:g id="ID_1">%1$d</xliff:g>/<xliff:g id="ID_2">%2$d</xliff:g> orria"</string>
    ++    <string name="cant_silence_or_block" msgid="999689262131488625">"Jakinarazpenak ezin dira ezkutatu edo blokeatu"</string>
    + </resources>
    +diff --git a/packages/SystemUI/res/values-fa-land/strings.xml b/packages/SystemUI/res/values-fa-land/strings.xml
    +index adc2b11..fe67cf0 100644
    +--- a/packages/SystemUI/res/values-fa-land/strings.xml
    ++++ b/packages/SystemUI/res/values-fa-land/strings.xml
    +@@ -19,5 +19,5 @@
    + 
    + <resources xmlns:android="http://schemas.android.com/apk/res/android"
    +     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
    +-    <string name="toast_rotation_locked" msgid="7609673011431556092">"صفحه اکنون در جهت افقی قفل است."</string>
    ++    <string name="toast_rotation_locked" msgid="7609673011431556092">"صفحه اکنون در حالت افقی قفل است."</string>
    + </resources>
    +diff --git a/packages/SystemUI/res/values-fa/strings.xml b/packages/SystemUI/res/values-fa/strings.xml
    +index 58a5d93..abb7e1e 100644
    +--- a/packages/SystemUI/res/values-fa/strings.xml
    ++++ b/packages/SystemUI/res/values-fa/strings.xml
    +@@ -238,7 +238,7 @@
    +     <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"‏داده 4G موقتاً متوقف شده است"</string>
    +     <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"داده شبکه همراه موقتاً متوقف شده است"</string>
    +     <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"داده موقتاً متوقف شده است"</string>
    +-    <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"چون به محدودیت داده تنظیم شده رسیده‌اید، دستگاه مصرف داده را برای باقیمانده این دوره موقتاً متوقف کرده است.\n\nاگر ادامه دهید شاید موجب کسر هزینه از طرف شرکت مخابراتی شما شود."</string>
    ++    <string name="data_usage_disabled_dialog" msgid="1841738975235283398">"به حداکثر محدودیت داده‌ای که تنظیم کردید رسیدید. دیگر از داده شبکه تلفن همراه استفاده نمی‌کنید.\n\nدر صورت ازسرگیری، ممکن است مصرف داده هزینه‌هایی دربرداشته باشد."</string>
    +     <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"از سر‌گیری"</string>
    +     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"اتصال اینترنتی ندارید"</string>
    +     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"‏Wi-Fi متصل شد"</string>
    +@@ -254,10 +254,10 @@
    +     <string name="status_bar_notification_inspect_item_title" msgid="5668348142410115323">"تنظیمات اعلان"</string>
    +     <string name="status_bar_notification_app_settings_title" msgid="5525260160341558869">"تنظیمات <xliff:g id="APP_NAME">%s</xliff:g>"</string>
    +     <string name="accessibility_rotation_lock_off" msgid="4062780228931590069">"صفحه به صورت خودکار می‌چرخد."</string>
    +-    <string name="accessibility_rotation_lock_on_landscape" msgid="6731197337665366273">"صفحه اکنون در جهت افقی قفل است."</string>
    ++    <string name="accessibility_rotation_lock_on_landscape" msgid="6731197337665366273">"صفحه اکنون در حالت افقی قفل است."</string>
    +     <string name="accessibility_rotation_lock_on_portrait" msgid="5809367521644012115">"صفحه اکنون در جهت عمودی قفل است."</string>
    +     <string name="accessibility_rotation_lock_off_changed" msgid="8134601071026305153">"صفحه اکنون به صورت خودکار می‌چرخد."</string>
    +-    <string name="accessibility_rotation_lock_on_landscape_changed" msgid="3135965553707519743">"صفحه اکنون روی جهت افقی قفل شده است."</string>
    ++    <string name="accessibility_rotation_lock_on_landscape_changed" msgid="3135965553707519743">"صفحه اکنون در حالت افقی قفل است."</string>
    +     <string name="accessibility_rotation_lock_on_portrait_changed" msgid="8922481981834012126">"صفحه اکنون روی جهت عمودی قفل شده است."</string>
    +     <string name="dessert_case" msgid="1295161776223959221">"ویترین دسر"</string>
    +     <string name="start_dreams" msgid="5640361424498338327">"محافظ صفحه"</string>
    +@@ -347,8 +347,8 @@
    +     <string name="description_direction_left" msgid="7207478719805562165">"لغزاندن به چپ برای <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
    +     <string name="zen_priority_introduction" msgid="3070506961866919502">"صداها و لرزش‌هایی به جز هشدارها، یادآوری‌ها، رویدادها و تماس‌گیرنده‌هایی که مشخص می‌کنید، مزاحم شما نمی‌شوند."</string>
    +     <string name="zen_priority_customize_button" msgid="7948043278226955063">"سفارشی کردن"</string>
    +-    <string name="zen_silence_introduction_voice" msgid="2284540992298200729">"این کار «همه» صداها و لرزش‌ها از جمله هشدارها، موسیقی، ویدیوها و بازی‌ها را مسدود می‌کند. همچنان می‌توانید تماس تلفنی برقرار کنید."</string>
    +-    <string name="zen_silence_introduction" msgid="3137882381093271568">"این کار «همه» صداها و لرزش‌ها از جمله هشدارها، موسیقی، ویدیوها و بازی‌ها را مسدود می‌کند."</string>
    ++    <string name="zen_silence_introduction_voice" msgid="2284540992298200729">"این کار «همه» صداها و لرزش‌ها از جمله هشدارها، موسیقی، ویدئوها و بازی‌ها را مسدود می‌کند. همچنان می‌توانید تماس تلفنی برقرار کنید."</string>
    ++    <string name="zen_silence_introduction" msgid="3137882381093271568">"این کار «همه» صداها و لرزش‌ها از جمله هشدارها، موسیقی، ویدئوها و بازی‌ها را مسدود می‌کند."</string>
    +     <string name="keyguard_more_overflow_text" msgid="9195222469041601365">"+<xliff:g id="NUMBER_OF_NOTIFICATIONS">%d</xliff:g>"</string>
    +     <string name="speed_bump_explanation" msgid="1288875699658819755">"اعلان‌های کمتر فوری در زیر"</string>
    +     <string name="notification_tap_again" msgid="7590196980943943842">"دوباره ضربه بزنید تا باز شود"</string>
    +@@ -404,6 +404,7 @@
    +     <string name="device_owned_footer" msgid="3802752663326030053">"ممکن است دستگاه کنترل شود"</string>
    +     <string name="profile_owned_footer" msgid="8021888108553696069">"شاید نمایه کنترل شود"</string>
    +     <string name="vpn_footer" msgid="2388611096129106812">"ممکن است شبکه کنترل شود"</string>
    ++    <string name="branded_vpn_footer" msgid="2168111859226496230">"ممکن است شبکه کنترل شود"</string>
    +     <string name="monitoring_title_device_owned" msgid="7121079311903859610">"کنترل دستگاه"</string>
    +     <string name="monitoring_title_profile_owned" msgid="6790109874733501487">"کنترل نمایه"</string>
    +     <string name="monitoring_title" msgid="169206259253048106">"کنترل شبکه"</string>
    +@@ -416,6 +417,7 @@
    +     <string name="legacy_vpn_name" msgid="6604123105765737830">"VPN"</string>
    +     <string name="monitoring_description_app" msgid="6259179342284742878">"شما به <xliff:g id="APPLICATION">%1$s</xliff:g> وصل شده‌اید، که می‌تواند فعالیت شبکه شما از جمله رایانامه‌، برنامه‌ و وب‌سایت‌ها را کنترل کند."</string>
    +     <string name="monitoring_description_app_personal" msgid="484599052118316268">"شما به <xliff:g id="APPLICATION">%1$s</xliff:g> وصل شده‌اید، که می‌تواند فعالیت شبکه شخصی شما از جمله رایانامه‌، برنامه‌ و وب‌سایت‌ها را کنترل کند."</string>
    ++    <string name="branded_monitoring_description_app_personal" msgid="2669518213949202599">"به <xliff:g id="APPLICATION">%1$s</xliff:g> وصل شده‌اید، که می‌تواند فعالیت شبکه شخصی شما را (ازجمله رایانامه‌‌ها، برنامه‌‌ها و وب‌سایت‌ها) کنترل کند."</string>
    +     <string name="monitoring_description_app_work" msgid="1754325860918060897">"نمایه کاری‌تان توسط <xliff:g id="ORGANIZATION">%1$s</xliff:g> مدیریت می‌شود. این به <xliff:g id="APPLICATION">%2$s</xliff:g> وصل است که فعالیت شبکه کاری‌تان از جمله رایانامه، برنامه و وب‌سایت‌ها را کنترل می‌کند.\n\nبرای دریافت اطلاعات بیشتر، با سرپرستتان تماس بگیرید."</string>
    +     <string name="monitoring_description_app_personal_work" msgid="4946600443852045903">"نمایه کاری شما توسط <xliff:g id="ORGANIZATION">%1$s</xliff:g> مدیریت می‌شود. این به <xliff:g id="APPLICATION_WORK">%2$s</xliff:g> متصل است که می‌تواند فعالیت شبکه کاری‌تان از جمله رایانامه، برنامه و وب‌سایت‌ها را کنترل کند.\n\nشما همچنین به <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g> متصل هستید که می‌تواند فعالیت شبکه شخصی‌تان را کنترل کند."</string>
    +     <string name="monitoring_description_vpn_app_device_owned" msgid="4970443827043261703">"دستگاهتان توسط <xliff:g id="ORGANIZATION">%1$s</xliff:g> مدیریت می‌شود.\n\nسرپرستتان می‌تواند تنظیمات، دسترسی شرکت، برنامه‌ها، داده‌های مرتبط با دستگاهتان و اطلاعات مکان دستگاهتان را کنترل و مدیریت کند.\n\nشما به <xliff:g id="APPLICATION">%2$s</xliff:g> وصل هستید که می‌تواند فعالیت شبکه شما را کنترل کند، از جمله رایانامه‌، برنامه‌ و وب‌سایت‌ها.\n\nبرای دریافت اطلاعات بیشتر، با سرپرستتان تماس بگیرید."</string>
    +@@ -482,7 +484,7 @@
    +     <string name="accessibility_managed_profile" msgid="6613641363112584120">"نمایه کاری"</string>
    +     <string name="tuner_warning_title" msgid="7094689930793031682">"برای بعضی افراد سرگرم‌کننده است اما نه برای همه"</string>
    +     <string name="tuner_warning" msgid="8730648121973575701">"‏«تنظیم‌کننده واسط کاربری سیستم» روش‌های بیشتری برای تنظیم دقیق و سفارشی کردن واسط کاربری Android در اختیار شما قرار می‌دهد. ممکن است این ویژگی‌های آزمایشی تغییر کنند، خراب شوند یا در نسخه‌های آینده جود نداشته باشند. با احتیاط ادامه دهید."</string>
    +-    <string name="tuner_persistent_warning" msgid="8597333795565621795">"ممکن است این ویژگی‌های آزمایشی تغییر کنند، خراب شوند یا در نسخه‌های آینده وجود نداشته باشند. با احتیاط ادامه دهید."</string>
    ++    <string name="tuner_persistent_warning" msgid="8597333795565621795">"ممکن است این قابلیت‌های آزمایشی تغییر کنند، خراب شوند یا در نسخه‌های آینده وجود نداشته باشد. بااحتیاط ادامه دهید."</string>
    +     <string name="got_it" msgid="2239653834387972602">"متوجه شدم"</string>
    +     <string name="tuner_toast" msgid="603429811084428439">"تبریک می‌گوییم! «تنظیم‌کننده واسط کاربری سیستم» به «تنظیمات» اضافه شد"</string>
    +     <string name="remove_from_settings" msgid="8389591916603406378">"حذف از تنظیمات"</string>
    +@@ -492,8 +494,6 @@
    +     <string name="clock_seconds_desc" msgid="6282693067130470675">"ثانیه‌های ساعت را در نوار وضعیت نشان می‌دهد. ممکن است بر ماندگاری باتری تأثیر بگذارد."</string>
    +     <string name="qs_rearrange" msgid="8060918697551068765">"ترتیب مجدد در تنظیمات سریع"</string>
    +     <string name="show_brightness" msgid="6613930842805942519">"نمایش روشنایی در تنظیمات سریع"</string>
    +-    <string name="overview_nav_bar_gesture" msgid="8579814204727917764">"فعال کردن تقسیم صفحه با اشاره بالا کشیدن"</string>
    +-    <string name="overview_nav_bar_gesture_desc" msgid="6329167382305102615">"اشاره ورود به تقسیم صفحه با بالا کشیدن صفحه از دکمه نمای کلی را فعال می‌کند"</string>
    +     <string name="experimental" msgid="6198182315536726162">"آزمایشی"</string>
    +     <string name="enable_bluetooth_title" msgid="5027037706500635269">"بلوتوث روشن شود؟"</string>
    +     <string name="enable_bluetooth_message" msgid="9106595990708985385">"برای مرتبط کردن صفحه‌کلید با رایانه لوحی، ابتدا باید بلوتوث را روشن کنید."</string>
    +@@ -651,4 +651,5 @@
    +     <string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"باز کردن تنظیمات <xliff:g id="ID_1">%s</xliff:g>."</string>
    +     <string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"ویرایش ترتیب تنظیمات."</string>
    +     <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"صفحه <xliff:g id="ID_1">%1$d</xliff:g> از <xliff:g id="ID_2">%2$d</xliff:g>"</string>
    ++    <string name="cant_silence_or_block" msgid="999689262131488625">"نمی‌توان اعلان‌ها را بی‌صدا یا مسدود کرد"</string>
    + </resources>
    +diff --git a/packages/SystemUI/res/values-fa/strings_tv.xml b/packages/SystemUI/res/values-fa/strings_tv.xml
    +index 2894abb..b97a6465 100644
    +--- a/packages/SystemUI/res/values-fa/strings_tv.xml
    ++++ b/packages/SystemUI/res/values-fa/strings_tv.xml
    +@@ -25,7 +25,7 @@
    +     <string name="pip_pause" msgid="8412075640017218862">"مکث"</string>
    +     <string name="pip_hold_home" msgid="340086535668778109">"‏کنترل PIP ‏با نگه‌داشتن "<b>"HOME"</b></string>
    +     <string name="pip_onboarding_title" msgid="7850436557670253991">"تصویر در تصویر"</string>
    +-    <string name="pip_onboarding_description" msgid="4028124563309465267">"تا زمانی که ویدیوی دیگری را پخش کنید، این صفحه حالت ویدیو در ویدیوی شما را حفظ می‌کند. برای کنترل آن، دکمه "<b>"صفحه اصلی"</b>" را فشار دهید و نگه دارید."</string>
    ++    <string name="pip_onboarding_description" msgid="4028124563309465267">"تا زمانی که ویدئوی دیگری را پخش کنید، این صفحه حالت ویدئو در ویدئوی شما را حفظ می‌کند. برای کنترل آن، دکمه "<b>"صفحه اصلی"</b>" را فشار دهید و نگه دارید."</string>
    +     <string name="pip_onboarding_button" msgid="3957426748484904611">"متوجه شدم"</string>
    +     <string name="recents_tv_dismiss" msgid="3555093879593377731">"رد کردن"</string>
    +   <string-array name="recents_tv_blacklist_array">
    +diff --git a/packages/SystemUI/res/values-fi/strings.xml b/packages/SystemUI/res/values-fi/strings.xml
    +index 5ff50be..910ac29 100644
    +--- a/packages/SystemUI/res/values-fi/strings.xml
    ++++ b/packages/SystemUI/res/values-fi/strings.xml
    +@@ -238,7 +238,7 @@
    +     <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"4G-tiedonsiirto keskeytettiin"</string>
    +     <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"Mobiilitiedonsiirto keskeytettiin"</string>
    +     <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"Tiedonsiirto keskeytettiin"</string>
    +-    <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"Määrittämäsi tiedonsiirtorajoitus saavutettiin, ja laite keskeytti tiedonsiirron tämän kauden loppuajaksi.\n\nOperaattorisi voi veloittaa sinulta lisämaksun, jos jatkat tiedonsiirtoa."</string>
    ++    <string name="data_usage_disabled_dialog" msgid="1841738975235283398">"Määrittämäsi datankäyttöraja on täynnä. Mobiilidata poistettiin käytöstä.\n\nOperaattorisi voi veloittaa sinua, jos jatkat mobiilidatan käyttöä."</string>
    +     <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"Jatka"</string>
    +     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Ei internetyhteyttä"</string>
    +     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi yhdistetty"</string>
    +@@ -404,6 +404,7 @@
    +     <string name="device_owned_footer" msgid="3802752663326030053">"Laitetta voidaan valvoa"</string>
    +     <string name="profile_owned_footer" msgid="8021888108553696069">"Profiilia saatetaan valvoa"</string>
    +     <string name="vpn_footer" msgid="2388611096129106812">"Verkkoa saatetaan valvoa"</string>
    ++    <string name="branded_vpn_footer" msgid="2168111859226496230">"Verkkoa saatetaan valvoa"</string>
    +     <string name="monitoring_title_device_owned" msgid="7121079311903859610">"Laitteiden valvonta"</string>
    +     <string name="monitoring_title_profile_owned" msgid="6790109874733501487">"Profiilin valvonta"</string>
    +     <string name="monitoring_title" msgid="169206259253048106">"Verkon valvonta"</string>
    +@@ -416,6 +417,7 @@
    +     <string name="legacy_vpn_name" msgid="6604123105765737830">"VPN"</string>
    +     <string name="monitoring_description_app" msgid="6259179342284742878">"Olet muodostanut yhteyden sovellukseen <xliff:g id="APPLICATION">%1$s</xliff:g>, joka voi valvoa toimintaasi verkossa. Sovellus voi seurata esimerkiksi avaamiasi sähköposteja, sovelluksia ja verkkosivustoja."</string>
    +     <string name="monitoring_description_app_personal" msgid="484599052118316268">"Olet muodostanut yhteyden sovellukseen <xliff:g id="APPLICATION">%1$s</xliff:g>, joka voi valvoa henkilökohtaista toimintaasi verkossa. Sovellus voi seurata esimerkiksi avaamiasi sähköposteja, sovelluksia ja verkkosivustoja."</string>
    ++    <string name="branded_monitoring_description_app_personal" msgid="2669518213949202599">"Olet muodostanut yhteyden sovellukseen <xliff:g id="APPLICATION">%1$s</xliff:g>, joka voi valvoa henkilökohtaista toimintaasi verkossa. Sovellus voi esimerkiksi seurata avaamiasi sähköposteja, sovelluksia ja verkkosivustoja."</string>
    +     <string name="monitoring_description_app_work" msgid="1754325860918060897">"Työprofiiliasi hallinnoi <xliff:g id="ORGANIZATION">%1$s</xliff:g>. Se on yhteydessä sovellukseen <xliff:g id="APPLICATION">%2$s</xliff:g>, joka voi valvoa työhön liittyvää toimintaasi verkossa. Sovellus voi seurata esimerkiksi avaamiasi sähköposteja, sovelluksia ja verkkosivustoja.\n\nSaat lisätietoja järjestelmänvalvojaltasi."</string>
    +     <string name="monitoring_description_app_personal_work" msgid="4946600443852045903">"Työprofiiliasi hallinnoi <xliff:g id="ORGANIZATION">%1$s</xliff:g>. Se on yhteydessä sovellukseen <xliff:g id="APPLICATION_WORK">%2$s</xliff:g>, joka voi valvoa työhön liittyvää toimintaasi verkossa. Sovellus voi seurata esimerkiksi avaamiasi sähköposteja, sovelluksia ja verkkosivustoja.\n\nLisäksi olet yhteydessä sovellukseen <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g>, joka voi valvoa henkilökohtaista toimintaasi verkossa."</string>
    +     <string name="monitoring_description_vpn_app_device_owned" msgid="4970443827043261703">"Laitettasi hallinnoi <xliff:g id="ORGANIZATION">%1$s</xliff:g>.\n\nJärjestelmänvalvojasi voi valvoa ja hallinnoida laitteesi asetuksia, yrityskäyttöä, sovelluksia, laitteeseesi liittyviä tietoja ja laitteen sijaintitietoja.\n\nOlet yhteydessä sovellukseen <xliff:g id="APPLICATION">%2$s</xliff:g>, joka voi valvoa toimintaasi verkossa. Sovellus voi seurata esimerkiksi avaamiasi sähköposteja, sovelluksia ja verkkosivustoja.\n\nLisätietoja saat järjestelmänvalvojaltasi."</string>
    +@@ -492,8 +494,6 @@
    +     <string name="clock_seconds_desc" msgid="6282693067130470675">"Näytä sekunnit tilapalkin kellossa. Tämä voi vaikuttaa akun kestoon."</string>
    +     <string name="qs_rearrange" msgid="8060918697551068765">"Järjestä pika-asetukset uudelleen"</string>
    +     <string name="show_brightness" msgid="6613930842805942519">"Näytä kirkkaus pika-asetuksissa"</string>
    +-    <string name="overview_nav_bar_gesture" msgid="8579814204727917764">"Siirry jaetun näytön tilaan pyyhkäisemällä ylöspäin"</string>
    +-    <string name="overview_nav_bar_gesture_desc" msgid="6329167382305102615">"Voit siirtyä jaetun näytön tilaan pyyhkäisemällä Viimeisimmät-painikkeesta ylöspäin."</string>
    +     <string name="experimental" msgid="6198182315536726162">"Kokeellinen"</string>
    +     <string name="enable_bluetooth_title" msgid="5027037706500635269">"Otetaanko Bluetooth käyttöön?"</string>
    +     <string name="enable_bluetooth_message" msgid="9106595990708985385">"Jotta voit yhdistää näppäimistön tablettiisi, sinun on ensin otettava Bluetooth käyttöön."</string>
    +@@ -651,4 +651,5 @@
    +     <string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"Avaa kohteen <xliff:g id="ID_1">%s</xliff:g> asetukset."</string>
    +     <string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"Muokkaa asetusten järjestystä."</string>
    +     <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"Sivu <xliff:g id="ID_1">%1$d</xliff:g>/<xliff:g id="ID_2">%2$d</xliff:g>"</string>
    ++    <string name="cant_silence_or_block" msgid="999689262131488625">"Ilmoituksia ei voi mykistää tai estää"</string>
    + </resources>
    +diff --git a/packages/SystemUI/res/values-fr-rCA/strings.xml b/packages/SystemUI/res/values-fr-rCA/strings.xml
    +index 7d50fee..8c5e46f 100644
    +--- a/packages/SystemUI/res/values-fr-rCA/strings.xml
    ++++ b/packages/SystemUI/res/values-fr-rCA/strings.xml
    +@@ -240,7 +240,7 @@
    +     <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"Données 4G désactivées"</string>
    +     <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"Données cellulaires désactivées"</string>
    +     <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"Données désactivées"</string>
    +-    <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"Vous avez atteint le quota de données maximal. La consommation des données a donc été interrompue pour la fin de la période de facturation en cours.\n\nSi vous réactivez les données, votre fournisseur de services risque de vous facturer des frais supplémentaires."</string>
    ++    <string name="data_usage_disabled_dialog" msgid="1841738975235283398">"La limite de données que vous avez définie a été atteinte. Vous n\'utilisez plus les données cellulaires.\n\nSi vous rétablissez la connexion de données cellulaires, des frais peuvent s\'appliquer."</string>
    +     <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"Reprendre"</string>
    +     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Aucune connexion Internet"</string>
    +     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Connecté au Wi-Fi"</string>
    +@@ -406,6 +406,7 @@
    +     <string name="device_owned_footer" msgid="3802752663326030053">"Il est possible que cet appareil soit surveillé."</string>
    +     <string name="profile_owned_footer" msgid="8021888108553696069">"le profil peut être contrôlé"</string>
    +     <string name="vpn_footer" msgid="2388611096129106812">"Le réseau peut être surveillé"</string>
    ++    <string name="branded_vpn_footer" msgid="2168111859226496230">"Le réseau peut être surveillé"</string>
    +     <string name="monitoring_title_device_owned" msgid="7121079311903859610">"Surveillance d\'appareils"</string>
    +     <string name="monitoring_title_profile_owned" msgid="6790109874733501487">"Contrôle de profil"</string>
    +     <string name="monitoring_title" msgid="169206259253048106">"Surveillance réseau"</string>
    +@@ -418,6 +419,7 @@
    +     <string name="legacy_vpn_name" msgid="6604123105765737830">"RPV"</string>
    +     <string name="monitoring_description_app" msgid="6259179342284742878">"Vous êtes connecté à <xliff:g id="APPLICATION">%1$s</xliff:g>. Cette application peut contrôler votre activité sur le réseau, y compris les courriels, les applications et les sites Web."</string>
    +     <string name="monitoring_description_app_personal" msgid="484599052118316268">"Vous êtes connecté à <xliff:g id="APPLICATION">%1$s</xliff:g>. Cette application peut contrôler votre activité personnelle sur le réseau, y compris les courriels, les applications et les sites Web."</string>
    ++    <string name="branded_monitoring_description_app_personal" msgid="2669518213949202599">"Vous êtes connecté à <xliff:g id="APPLICATION">%1$s</xliff:g>. Cette application peut contrôler votre activité personnelle sur le réseau, y compris les courriels, les applications et les sites Web."</string>
    +     <string name="monitoring_description_app_work" msgid="1754325860918060897">"Votre profil professionnel est géré par <xliff:g id="ORGANIZATION">%1$s</xliff:g>. Il est connecté à <xliff:g id="APPLICATION">%2$s</xliff:g>. Cette application peut contrôler votre activité sur le réseau, y compris les courriels, les applications et les sites Web.\n\nPour en savoir plus, communiquez avec votre administrateur."</string>
    +     <string name="monitoring_description_app_personal_work" msgid="4946600443852045903">"Votre profil professionnel est géré par <xliff:g id="ORGANIZATION">%1$s</xliff:g>. Il est connecté à <xliff:g id="APPLICATION_WORK">%2$s</xliff:g>. Cette application peut contrôler votre activité sur le réseau, y compris les courriels, les applications et les sites Web.\n\nVous êtes également connecté à <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g>. Cette application peut contrôler votre activité personnelle sur le réseau."</string>
    +     <string name="monitoring_description_vpn_app_device_owned" msgid="4970443827043261703">"Votre appareil est géré par <xliff:g id="ORGANIZATION">%1$s</xliff:g>.\n\nVotre administrateur peut contrôler et gérer les paramètres, l\'accès aux contenus de l\'entreprise, les applications, les données associées à cet appareil et ses données de localisation.\n\nVous êtes connecté à <xliff:g id="APPLICATION">%2$s</xliff:g>, qui peut contrôler votre activité réseau, y compris les courriels, les applications et les  sites Web.\n\nPour en savoir plus, communiquez avec votre administrateur."</string>
    +@@ -494,8 +496,6 @@
    +     <string name="clock_seconds_desc" msgid="6282693067130470675">"Afficher les secondes sur l\'horloge dans la barre d\'état. Cela peut réduire l\'autonomie de la pile."</string>
    +     <string name="qs_rearrange" msgid="8060918697551068765">"Réorganiser les paramètres rapides"</string>
    +     <string name="show_brightness" msgid="6613930842805942519">"Afficher la luminosité dans les paramètres rapides"</string>
    +-    <string name="overview_nav_bar_gesture" msgid="8579814204727917764">"Activer le geste d\'écran partagé en balayant vers le haut"</string>
    +-    <string name="overview_nav_bar_gesture_desc" msgid="6329167382305102615">"Activer le geste permettant d\'utiliser l\'écran partagé en balayant l\'écran vers le haut à partir du bouton « Aperçu »"</string>
    +     <string name="experimental" msgid="6198182315536726162">"Fonctions expérimentales"</string>
    +     <string name="enable_bluetooth_title" msgid="5027037706500635269">"Activer Bluetooth?"</string>
    +     <string name="enable_bluetooth_message" msgid="9106595990708985385">"Pour connecter votre clavier à votre tablette, vous devez d\'abord activer la connectivité Bluetooth."</string>
    +@@ -653,4 +653,5 @@
    +     <string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"Ouvrir les paramètres <xliff:g id="ID_1">%s</xliff:g>."</string>
    +     <string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"Modifier l\'ordre des paramètres."</string>
    +     <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"Page <xliff:g id="ID_1">%1$d</xliff:g> sur <xliff:g id="ID_2">%2$d</xliff:g>"</string>
    ++    <string name="cant_silence_or_block" msgid="999689262131488625">"Impossible de désactiver ou de bloquer les notifications"</string>
    + </resources>
    +diff --git a/packages/SystemUI/res/values-fr/strings.xml b/packages/SystemUI/res/values-fr/strings.xml
    +index 447255b..4b58a6d 100644
    +--- a/packages/SystemUI/res/values-fr/strings.xml
    ++++ b/packages/SystemUI/res/values-fr/strings.xml
    +@@ -240,7 +240,7 @@
    +     <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"Données 4G désactivées"</string>
    +     <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"Données mobiles désactivées"</string>
    +     <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"Données désactivées"</string>
    +-    <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"Vous avez atteint le quota de données maximal. La consommation des données a donc été interrompue pour la fin de la période de facturation en cours.\n\nSi vous réactivez les données, votre opérateur risque de vous facturer des frais supplémentaires."</string>
    ++    <string name="data_usage_disabled_dialog" msgid="1841738975235283398">"La limite de consommation des données que vous avez définie a été atteinte. Vous n\'utilisez plus les données mobiles.\n\nSi vous les réactivez, des frais pourront être facturés."</string>
    +     <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"Réactiver"</string>
    +     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Aucune connexion Internet"</string>
    +     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Connecté au Wi-Fi"</string>
    +@@ -406,6 +406,7 @@
    +     <string name="device_owned_footer" msgid="3802752663326030053">"Il est possible que cet appareil soit surveillé."</string>
    +     <string name="profile_owned_footer" msgid="8021888108553696069">"Le profil peut être contrôlé."</string>
    +     <string name="vpn_footer" msgid="2388611096129106812">"Il est possible que le réseau soit surveillé."</string>
    ++    <string name="branded_vpn_footer" msgid="2168111859226496230">"Il est possible que le réseau soit surveillé."</string>
    +     <string name="monitoring_title_device_owned" msgid="7121079311903859610">"Contrôle des appareils"</string>
    +     <string name="monitoring_title_profile_owned" msgid="6790109874733501487">"Contrôle du profil"</string>
    +     <string name="monitoring_title" msgid="169206259253048106">"Contrôle du réseau"</string>
    +@@ -418,6 +419,7 @@
    +     <string name="legacy_vpn_name" msgid="6604123105765737830">"VPN"</string>
    +     <string name="monitoring_description_app" msgid="6259179342284742878">"Vous êtes connecté à <xliff:g id="APPLICATION">%1$s</xliff:g>. Cette application peut contrôler votre activité sur le réseau, y compris l\'activité relative aux e-mails, aux applications et aux sites Web."</string>
    +     <string name="monitoring_description_app_personal" msgid="484599052118316268">"Vous êtes connecté à <xliff:g id="APPLICATION">%1$s</xliff:g>. Cette application peut contrôler votre activité personnelle sur le réseau, y compris votre activité relative aux e-mails, aux applications et aux sites Web."</string>
    ++    <string name="branded_monitoring_description_app_personal" msgid="2669518213949202599">"Vous êtes connecté à <xliff:g id="APPLICATION">%1$s</xliff:g>. Cette application peut contrôler votre activité personnelle sur le réseau, y compris les e-mails, les applications et les sites Web."</string>
    +     <string name="monitoring_description_app_work" msgid="1754325860918060897">"Votre profil professionnel est géré par <xliff:g id="ORGANIZATION">%1$s</xliff:g>. Il est connecté à <xliff:g id="APPLICATION">%2$s</xliff:g>. Cette application peut contrôler l\'activité de ce profil sur le réseau, y compris l\'activité relative aux e-mails, aux applications et aux sites Web.\n\nPour en savoir plus, contactez votre administrateur."</string>
    +     <string name="monitoring_description_app_personal_work" msgid="4946600443852045903">"Votre profil professionnel est géré par <xliff:g id="ORGANIZATION">%1$s</xliff:g>. Il est connecté à <xliff:g id="APPLICATION_WORK">%2$s</xliff:g>. Cette application peut contrôler l\'activité de ce profil sur le réseau, y compris l\'activité relative aux e-mails, aux applications et aux sites Web.\n\nVous êtes également connecté à <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g>. Cette application peut surveiller votre activité personnelle sur le réseau."</string>
    +     <string name="monitoring_description_vpn_app_device_owned" msgid="4970443827043261703">"Votre appareil géré par <xliff:g id="ORGANIZATION">%1$s</xliff:g>.\n\nVotre administrateur peut contrôler et gérer les paramètres, l\'accès aux contenus de l\'entreprise, les applications, les données associées à cet appareil et les informations de localisation de celui-ci.\n\nVous êtes connecté à <xliff:g id="APPLICATION">%2$s</xliff:g> qui peut contrôler votre activité sur le réseau (e-mails, applications et sites Web).\n\nPour en savoir plus, contactez votre administrateur."</string>
    +@@ -446,7 +448,7 @@
    +   <string-array name="volume_stream_titles">
    +     <item msgid="5841843895402729630">"Appeler"</item>
    +     <item msgid="5997713001067658559">"Système"</item>
    +-    <item msgid="7858983209929864160">"Faire sonner"</item>
    ++    <item msgid="7858983209929864160">"Sonnerie"</item>
    +     <item msgid="1850038478268896762">"Multimédia"</item>
    +     <item msgid="8265110906352372092">"Alarme"</item>
    +     <item msgid="5339394737636839168"></item>
    +@@ -494,8 +496,6 @@
    +     <string name="clock_seconds_desc" msgid="6282693067130470675">"Afficher les secondes dans la barre d\'état. Cela risque de réduire l\'autonomie de la batterie."</string>
    +     <string name="qs_rearrange" msgid="8060918697551068765">"Réorganiser la fenêtre de configuration rapide"</string>
    +     <string name="show_brightness" msgid="6613930842805942519">"Afficher la luminosité dans fenêtre de configuration rapide"</string>
    +-    <string name="overview_nav_bar_gesture" msgid="8579814204727917764">"Activer l\'écran partagé en balayant vers le haut"</string>
    +-    <string name="overview_nav_bar_gesture_desc" msgid="6329167382305102615">"Activer le geste permettant d\'utiliser l\'écran partagé en balayant l\'écran vers le haut à partir du bouton \"Aperçu\""</string>
    +     <string name="experimental" msgid="6198182315536726162">"Paramètres expérimentaux"</string>
    +     <string name="enable_bluetooth_title" msgid="5027037706500635269">"Activer le Bluetooth ?"</string>
    +     <string name="enable_bluetooth_message" msgid="9106595990708985385">"Pour connecter un clavier à votre tablette, vous devez avoir activé le Bluetooth."</string>
    +@@ -653,4 +653,5 @@
    +     <string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"Ouvrir les paramètres <xliff:g id="ID_1">%s</xliff:g>."</string>
    +     <string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"Modifier l\'ordre des paramètres."</string>
    +     <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"Page <xliff:g id="ID_1">%1$d</xliff:g> sur <xliff:g id="ID_2">%2$d</xliff:g>"</string>
    ++    <string name="cant_silence_or_block" msgid="999689262131488625">"Impossible d\'ignorer ou de bloquer les notifications"</string>
    + </resources>
    +diff --git a/packages/SystemUI/res/values-gl-rES/strings.xml b/packages/SystemUI/res/values-gl-rES/strings.xml
    +index 6d0e366..449c747 100644
    +--- a/packages/SystemUI/res/values-gl-rES/strings.xml
    ++++ b/packages/SystemUI/res/values-gl-rES/strings.xml
    +@@ -240,7 +240,7 @@
    +     <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"Os datos 4G están en pausa"</string>
    +     <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"Os datos de móbiles están en pausa"</string>
    +     <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"Os datos están en pausa"</string>
    +-    <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"Como acadaches o límite de datos definido, o dispositivo puxo en pausa o uso de datos para o resto do ciclo.\n\nSe retomas o uso, poden aplicarse cargos do operador."</string>
    ++    <string name="data_usage_disabled_dialog" msgid="1841738975235283398">"Alcanzouse o límite de datos establecido e xa non utilizas datos móbiles.\n\nSe continúas, é posible que se apliquen cargos por uso de datos."</string>
    +     <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"Retomar"</string>
    +     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Sen Internet"</string>
    +     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi conectada"</string>
    +@@ -406,6 +406,7 @@
    +     <string name="device_owned_footer" msgid="3802752663326030053">"É posible que se supervise o dispositivo"</string>
    +     <string name="profile_owned_footer" msgid="8021888108553696069">"O perfil pódese supervisar"</string>
    +     <string name="vpn_footer" msgid="2388611096129106812">"É posible que se supervise a rede"</string>
    ++    <string name="branded_vpn_footer" msgid="2168111859226496230">"É posible que se supervise a rede"</string>
    +     <string name="monitoring_title_device_owned" msgid="7121079311903859610">"Supervisión de dispositivos"</string>
    +     <string name="monitoring_title_profile_owned" msgid="6790109874733501487">"Supervisión do perfil"</string>
    +     <string name="monitoring_title" msgid="169206259253048106">"Supervisión de rede"</string>
    +@@ -418,6 +419,7 @@
    +     <string name="legacy_vpn_name" msgid="6604123105765737830">"VPN"</string>
    +     <string name="monitoring_description_app" msgid="6259179342284742878">"Estás conectado a <xliff:g id="APPLICATION">%1$s</xliff:g>, que pode supervisar a túa actividade na rede, incluídos os correos electrónicos, as aplicacións e os sitios web."</string>
    +     <string name="monitoring_description_app_personal" msgid="484599052118316268">"Estás conectado a <xliff:g id="APPLICATION">%1$s</xliff:g>, que pode supervisar a túa actividade persoal na rede, incluídos os correos electrónicos, as aplicacións e os sitios web."</string>
    ++    <string name="branded_monitoring_description_app_personal" msgid="2669518213949202599">"Estás conectado a <xliff:g id="APPLICATION">%1$s</xliff:g>, que pode supervisar a túa actividade persoal na rede, incluídos os correos electrónicos, as aplicacións e os sitios web."</string>
    +     <string name="monitoring_description_app_work" msgid="1754325860918060897">"O teu perfil de traballo está xestionado por <xliff:g id="ORGANIZATION">%1$s</xliff:g>. Está conectado a <xliff:g id="APPLICATION">%2$s</xliff:g>, que pode supervisar a túa actividade na rede, incluídos os correos electrónicos, as aplicacións e os sitios web.\n\nPara obter máis información, ponte en contacto co teu administrador."</string>
    +     <string name="monitoring_description_app_personal_work" msgid="4946600443852045903">"O teu perfil de traballo está xestionado por <xliff:g id="ORGANIZATION">%1$s</xliff:g>. Está conectado a <xliff:g id="APPLICATION_WORK">%2$s</xliff:g>, que pode supervisar a túa actividade na rede, incluídos os correos electrónicos, as aplicacións e os sitios web.\n\nTamén estás conectado a <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g>, que pode supervisar a túa actividade persoal na rede."</string>
    +     <string name="monitoring_description_vpn_app_device_owned" msgid="4970443827043261703">"O dispositivo está xestionado por <xliff:g id="ORGANIZATION">%1$s</xliff:g>.\n\nO teu administrador pode supervisar e xestionar a configuración, o acceso corporativo, as aplicacións, os datos asociados co dispositivo e a información de localización do dispositivo.\n\nEstás conectado a <xliff:g id="APPLICATION">%2$s</xliff:g>, que pode supervisar a túa actividade na rede: os correos electrónicos, as aplicacións e os sitios web.\n\nPara obter máis información, contacta co teu administrador."</string>
    +@@ -494,8 +496,6 @@
    +     <string name="clock_seconds_desc" msgid="6282693067130470675">"Mostra os segundos do reloxo na barra de estado. Pode influír na duración da batería."</string>
    +     <string name="qs_rearrange" msgid="8060918697551068765">"Reorganizar Configuración rápida"</string>
    +     <string name="show_brightness" msgid="6613930842805942519">"Mostrar brillo en Configuración rápida"</string>
    +-    <string name="overview_nav_bar_gesture" msgid="8579814204727917764">"Activar pantalla dividida pasando o dedo cara arriba"</string>
    +-    <string name="overview_nav_bar_gesture_desc" msgid="6329167382305102615">"Activa o xesto de pasar o dedo cara arriba desde o botón Visión xeral para acceder ao modo de pantalla dividida"</string>
    +     <string name="experimental" msgid="6198182315536726162">"Experimental"</string>
    +     <string name="enable_bluetooth_title" msgid="5027037706500635269">"Queres activar o Bluetooth?"</string>
    +     <string name="enable_bluetooth_message" msgid="9106595990708985385">"Para conectar o teu teclado coa tableta, primeiro tes que activar o Bluetooth."</string>
    +@@ -653,4 +653,5 @@
    +     <string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"Abrir a configuración de <xliff:g id="ID_1">%s</xliff:g>."</string>
    +     <string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"Editar a orde das opcións de configuración."</string>
    +     <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"Páxina <xliff:g id="ID_1">%1$d</xliff:g> de <xliff:g id="ID_2">%2$d</xliff:g>"</string>
    ++    <string name="cant_silence_or_block" msgid="999689262131488625">"As notificacións non se poden silenciar nin bloquear"</string>
    + </resources>
    +diff --git a/packages/SystemUI/res/values-gu-rIN/strings.xml b/packages/SystemUI/res/values-gu-rIN/strings.xml
    +index 0663b41..5287576 100644
    +--- a/packages/SystemUI/res/values-gu-rIN/strings.xml
    ++++ b/packages/SystemUI/res/values-gu-rIN/strings.xml
    +@@ -238,7 +238,7 @@
    +     <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"4G ડેટા થોભાવ્યો છે"</string>
    +     <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"સેલ્યુલર ડેટા થોભાવ્યો છે"</string>
    +     <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"ડેટા થોભાવ્યો છે"</string>
    +-    <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"તમે સેટ કરેલ ડેટા મર્યાદા સુધી પહોંચી ગયા હોવાથી, ઉપકરણે આ ચક્રના શેષ માટે ડેટા વપરાશ થોભાવ્યો છે.\n\nફરીથી શરૂ કરવું તમારા કેરીઅર તરફથી શુલ્ક તરફ દોરી શકે છે."</string>
    ++    <string name="data_usage_disabled_dialog" msgid="1841738975235283398">"તમારા દ્વારા સેટ કરેલ ડેટા મર્યાદા પર તમે પહોંચી ગયાં છો. તમે હવે સેલ્યુલર ડેટાનો ઉપયોગ કરી રહ્યાં નથી.\n\nજો તમે ફરી શરૂ કરો છો, તો ડેટા વપરાશ માટે શુલ્ક લાગુ થઈ શકે છે."</string>
    +     <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"ફરી શરૂ કરો"</string>
    +     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"કોઈ ઇન્ટરનેટ કનેક્શન નથી"</string>
    +     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi કનેક્ટ કર્યું"</string>
    +@@ -404,6 +404,7 @@
    +     <string name="device_owned_footer" msgid="3802752663326030053">"ઉપકરણ મૉનિટર કરી શકાય છે"</string>
    +     <string name="profile_owned_footer" msgid="8021888108553696069">"પ્રોફાઇલ મૉનિટર કરી શકાય છે"</string>
    +     <string name="vpn_footer" msgid="2388611096129106812">"નેટવર્ક મૉનિટર કરી શકાય છે"</string>
    ++    <string name="branded_vpn_footer" msgid="2168111859226496230">"નેટવર્ક મૉનિટર કરવામાં આવી શકે છે"</string>
    +     <string name="monitoring_title_device_owned" msgid="7121079311903859610">"ઉપકરણ નિરીક્ષણ"</string>
    +     <string name="monitoring_title_profile_owned" msgid="6790109874733501487">"પ્રોફાઇલ નિરીક્ષણ"</string>
    +     <string name="monitoring_title" msgid="169206259253048106">"નેટવર્ક મૉનિટરિંગ"</string>
    +@@ -416,6 +417,7 @@
    +     <string name="legacy_vpn_name" msgid="6604123105765737830">"VPN"</string>
    +     <string name="monitoring_description_app" msgid="6259179342284742878">"તમે <xliff:g id="APPLICATION">%1$s</xliff:g> સાથે કનેક્ટ થયાં છો, જે ઇમેઇલ્સ, ઍપ્લિકેશનો અને વેબસાઇટ્સ સહિતની તમારી નેટવર્ક પ્રવૃત્તિને મૉનિટર કરી શકે છે."</string>
    +     <string name="monitoring_description_app_personal" msgid="484599052118316268">"તમે <xliff:g id="APPLICATION">%1$s</xliff:g> સાથે કનેક્ટ થયાં છો, જે ઇમેઇલ્સ, ઍપ્લિકેશનો અને વેબસાઇટ્સ સહિતની તમારી વ્યક્તિગત નેટવર્ક પ્રવૃત્તિને મૉનિટર કરી શકે છે."</string>
    ++    <string name="branded_monitoring_description_app_personal" msgid="2669518213949202599">"તમે <xliff:g id="APPLICATION">%1$s</xliff:g> સાથે કનેક્ટ થયાં છો, જે ઇમેઇલ્સ, ઍપ્લિકેશનો અને વેબસાઇટ્સ સહિત તમારી વ્યક્તિગત નેટવર્ક પ્રવૃત્તિને મૉનિટર કરી શકે છે."</string>
    +     <string name="monitoring_description_app_work" msgid="1754325860918060897">"તમારી કાર્ય પ્રોફાઇલ <xliff:g id="ORGANIZATION">%1$s</xliff:g> દ્વારા સંચાલિત થાય છે. તે <xliff:g id="APPLICATION">%2$s</xliff:g> સાથે કનેક્ટ થયેલ છે, જે ઇમેઇલ્સ, ઍપ્લિકેશનો અને વેબસાઇટ્સ સહિતની તમારી કાર્ય નેટવર્ક પ્રવૃત્તિને મૉનિટર કરી શકે છે.\n\nવધુ માહિતી માટે, તમારા વ્યવસ્થાપકનો સંપર્ક કરો."</string>
    +     <string name="monitoring_description_app_personal_work" msgid="4946600443852045903">"તમારી કાર્ય પ્રોફાઇલ <xliff:g id="ORGANIZATION">%1$s</xliff:g> દ્વારા સંચાલિત થાય છે. તે <xliff:g id="APPLICATION_WORK">%2$s</xliff:g> સાથે કનેક્ટ થયેલ છે, જે ઇમેઇલ્સ, ઍપ્લિકેશનો અને વેબસાઇટ્સ સહિતની તમારી કાર્ય નેટવર્ક પ્રવૃત્તિને મૉનિટર કરી શકે છે.\n\nતમે <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g> સાથે પણ કનેક્ટ થયેલ છો, જે તમારી વ્યક્તિગત નેટવર્ક પ્રવૃત્તિને મૉનિટર કરી શકે છે."</string>
    +     <string name="monitoring_description_vpn_app_device_owned" msgid="4970443827043261703">"તમારું ઉપકરણ <xliff:g id="ORGANIZATION">%1$s</xliff:g> દ્વારા સંચાલિત થાય છે.\n\nતમારા વ્યવસ્થાપક, સેટિંગ્સ, કોર્પોરેટ ઍક્સેસ, ઍપ્લિકેશનો, તમારા ઉપકરણ સાથે સંકળાયેલ ડેટા અને તમારા ઉપકરણની સ્થાન માહિતીને મૉનિટર કરી અને સંચાલિત કરી શકે છે.\n\nતમે <xliff:g id="APPLICATION">%2$s</xliff:g> સાથે કનેક્ટ થયાં છો, જે ઇમેઇલ્સ, ઍપ્લિકેશનો અને વેબસાઇટ્સ સહિતની તમારી નેટવર્ક પ્રવૃત્તિને મૉનિટર કરી શકે છે.\n\nવધુ માહિતી માટે, તમારા વ્યવસ્થાપકનો સંપર્ક કરો."</string>
    +@@ -492,8 +494,6 @@
    +     <string name="clock_seconds_desc" msgid="6282693067130470675">"ઘડિયાળ સેકન્ડ સ્થિતિ બારમાં બતાવો. બૅટરીની આવરદા પર અસર કરી શકે છે."</string>
    +     <string name="qs_rearrange" msgid="8060918697551068765">"ઝડપી સેટિંગ્સને ફરીથી ગોઠવો"</string>
    +     <string name="show_brightness" msgid="6613930842805942519">"ઝડપી સેટિંગ્સમાં તેજ બતાવો"</string>
    +-    <string name="overview_nav_bar_gesture" msgid="8579814204727917764">"સ્પ્લિટ-સ્ક્રીન સ્વાઇપ-અપ હાવભાવ સક્ષમ કરો"</string>
    +-    <string name="overview_nav_bar_gesture_desc" msgid="6329167382305102615">"વિહંગાવલોકન બટનમાંથી સ્વાઇપ કરીને સ્પ્લિટ-સ્ક્રીનમાં દાખલ થવા માટે હાવભાવ સક્ષમ કરો"</string>
    +     <string name="experimental" msgid="6198182315536726162">"પ્રાયોગિક"</string>
    +     <string name="enable_bluetooth_title" msgid="5027037706500635269">"Bluetooth ચાલુ કરવુ છે?"</string>
    +     <string name="enable_bluetooth_message" msgid="9106595990708985385">"તમારા ટેબ્લેટ સાથે કીબોર્ડ કનેક્ટ કરવા માટે, તમારે પહેલાં Bluetooth ચાલુ કરવાની જરૂર પડશે."</string>
    +@@ -651,4 +651,5 @@
    +     <string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"<xliff:g id="ID_1">%s</xliff:g> સેટિંગ્સ ખોલો."</string>
    +     <string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"સેટિંગ્સનો ક્રમ સંપાદિત કરો."</string>
    +     <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"<xliff:g id="ID_2">%2$d</xliff:g> માંથી <xliff:g id="ID_1">%1$d</xliff:g> પૃષ્ઠ"</string>
    ++    <string name="cant_silence_or_block" msgid="999689262131488625">"સૂચનાઓ શાંત અથવા અવરોધિત કરી શકાતી નથી"</string>
    + </resources>
    +diff --git a/packages/SystemUI/res/values-hi/strings.xml b/packages/SystemUI/res/values-hi/strings.xml
    +index 2924556..5c24fe2 100644
    +--- a/packages/SystemUI/res/values-hi/strings.xml
    ++++ b/packages/SystemUI/res/values-hi/strings.xml
    +@@ -238,7 +238,7 @@
    +     <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"4G डेटा रोक दिया गया है"</string>
    +     <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"सेल्युलर डेटा रोक दिया गया है"</string>
    +     <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"डेटा रोक दिया गया है"</string>
    +-    <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"चूंकि आपके निर्धारित डेटा की सीमा, सीमा पर पहुंच गई थी, इसलिए डिवाइस ने इस चक्र के रिमाइंडर के लिए डेटा उपयोग को रोक दिया है.\n\nफिर से शुरू करने से आपके वाहक की ओर से शुल्क लगाया जाता है."</string>
    ++    <string name="data_usage_disabled_dialog" msgid="1841738975235283398">"आपकी सेट की हुई डेटा सीमा समाप्त हो गई है. अब आप सेल्युलर डेटा का उपयोग नहीं कर रहे हैं.\n\nयदि आप फिर से शुरू करते हैं, तो डेटा उपयोग के लिए शुल्क लग सकता है."</string>
    +     <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"फिर से शुरू करें"</string>
    +     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"कोई इंटरनेट कनेक्शन नहीं"</string>
    +     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"वाई-फ़ाई  कनेक्‍ट किया गया"</string>
    +@@ -404,6 +404,7 @@
    +     <string name="device_owned_footer" msgid="3802752663326030053">"डिवाइस को मॉनीटर किया जा सकता है"</string>
    +     <string name="profile_owned_footer" msgid="8021888108553696069">"प्रोफ़ाइल को मॉनीटर किया जा सकता है"</string>
    +     <string name="vpn_footer" msgid="2388611096129106812">"नेटवर्क को मॉनीटर किया जा सकता है"</string>
    ++    <string name="branded_vpn_footer" msgid="2168111859226496230">"नेटवर्क को मॉनिटर किया जा सकता है"</string>
    +     <string name="monitoring_title_device_owned" msgid="7121079311903859610">"डिवाइस को मॉनीटर करना"</string>
    +     <string name="monitoring_title_profile_owned" msgid="6790109874733501487">"प्रोफ़ाइल को मॉनीटर करना"</string>
    +     <string name="monitoring_title" msgid="169206259253048106">"नेटवर्क को मॉनीटर करना"</string>
    +@@ -416,6 +417,7 @@
    +     <string name="legacy_vpn_name" msgid="6604123105765737830">"VPN"</string>
    +     <string name="monitoring_description_app" msgid="6259179342284742878">"आप <xliff:g id="APPLICATION">%1$s</xliff:g> से कनेक्‍ट हैं, जो ईमेल, ऐप्‍स और वेबसाइटों सहित आपकी नेटवर्क गतिविधि की निगरानी कर सकता है."</string>
    +     <string name="monitoring_description_app_personal" msgid="484599052118316268">"आप <xliff:g id="APPLICATION">%1$s</xliff:g> से कनेक्‍ट हैं, जो ईमेल, ऐप्‍स और वेबसाइटों सहित आपकी व्‍यक्‍तिगत नेटवर्क गतिविधि की निगरानी कर सकता है."</string>
    ++    <string name="branded_monitoring_description_app_personal" msgid="2669518213949202599">"आप <xliff:g id="APPLICATION">%1$s</xliff:g> से कनेक्‍ट हैं, जो ईमेल, ऐप्लिकेशन और वेबसाइट सहित आपकी व्‍यक्‍तिगत नेटवर्क गतिविधि को मॉनिटर कर सकता है."</string>
    +     <string name="monitoring_description_app_work" msgid="1754325860918060897">"आपकी कार्य प्रोफ़ाइल <xliff:g id="ORGANIZATION">%1$s</xliff:g> के द्वारा प्रबंधित है. वह <xliff:g id="APPLICATION">%2$s</xliff:g> से कनेक्‍ट है, जो ईमेल, ऐप्‍स और वेबसाइटों सहित आपकी कार्य नेटवर्क गतिविधि की निगरानी कर सकता है.\n\nअधिक जानकारी के लिए, अपने नियंत्रक से संपर्क करें."</string>
    +     <string name="monitoring_description_app_personal_work" msgid="4946600443852045903">"आपकी कार्य प्रोफ़ाइल <xliff:g id="ORGANIZATION">%1$s</xliff:g> के द्वारा प्रबंधित है. वह <xliff:g id="APPLICATION_WORK">%2$s</xliff:g> से कनेक्‍ट है, जो ईमेल, ऐप्‍स और वेबसाइटों सहित आपकी कार्य नेटवर्क गतिविधि की निगरानी कर सकता है.\n\nआप <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g> से भी कनेक्‍ट हैं, जो आपकी व्‍यक्‍तिगत नेटवर्क गतिविधि की निगरानी कर सकता है."</string>
    +     <string name="monitoring_description_vpn_app_device_owned" msgid="4970443827043261703">"आपका डिवाइस <xliff:g id="ORGANIZATION">%1$s</xliff:g> के द्वारा प्रबंधित है.\n\nआपका नियंत्रक सेटिंग, कॉर्पोरेट ऐक्‍सेस, ऐप्स, आपके डिवाइस से संबद्ध डेटा और आपके डिवाइस की स्‍थान जानकारी की निगरानी और उसका प्रबंधन कर सकता है.\n\nआप <xliff:g id="APPLICATION">%2$s</xliff:g> से कनेक्‍ट हैं, जो ईमेल, ऐप्‍स और वेबसाइटों सहित आपकी नेटवर्क गतिविधि की निगरानी कर सकता है.\n\nअधिक जानकारी के लिए, अपने नियंत्रक से संपर्क करें."</string>
    +@@ -492,8 +494,6 @@
    +     <string name="clock_seconds_desc" msgid="6282693067130470675">"स्थिति बार में घड़ी के सेकंड दिखाएं. इससे बैटरी के जीवनकाल पर प्रभाव पड़ सकता है."</string>
    +     <string name="qs_rearrange" msgid="8060918697551068765">"त्वरित सेटिंग को पुन: व्यवस्थित करें"</string>
    +     <string name="show_brightness" msgid="6613930842805942519">"त्वरित सेटिंग में स्क्रीन की रोशनी दिखाएं"</string>
    +-    <string name="overview_nav_bar_gesture" msgid="8579814204727917764">"ऊपर स्वाइप करके विभाजित स्क्रीन में जाने का जेस्चर सक्षम करें"</string>
    +-    <string name="overview_nav_bar_gesture_desc" msgid="6329167382305102615">"अवलोकन बटन से ऊपर स्वाइप करके स्क्रीन विभाजन में आने का हावभाव सक्षम करें"</string>
    +     <string name="experimental" msgid="6198182315536726162">"प्रयोगात्मक"</string>
    +     <string name="enable_bluetooth_title" msgid="5027037706500635269">"ब्लूटूथ चालू करें?"</string>
    +     <string name="enable_bluetooth_message" msgid="9106595990708985385">"अपने कीबोर्ड को अपने टैबलेट से कनेक्ट करने के लिए, आपको पहले ब्लूटूथ चालू करना होगा."</string>
    +@@ -651,4 +651,5 @@
    +     <string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"<xliff:g id="ID_1">%s</xliff:g> सेटिंग खोलें."</string>
    +     <string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"सेटिंग का क्रम संपादित करें."</string>
    +     <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"पृष्ठ <xliff:g id="ID_2">%2$d</xliff:g> में से <xliff:g id="ID_1">%1$d</xliff:g>"</string>
    ++    <string name="cant_silence_or_block" msgid="999689262131488625">"नोटिफ़िकेशन मौन या अवरुद्ध नहीं किए जा सकते हैं"</string>
    + </resources>
    +diff --git a/packages/SystemUI/res/values-hr/strings.xml b/packages/SystemUI/res/values-hr/strings.xml
    +index 02466d6..df3ccf1 100644
    +--- a/packages/SystemUI/res/values-hr/strings.xml
    ++++ b/packages/SystemUI/res/values-hr/strings.xml
    +@@ -239,7 +239,7 @@
    +     <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"4G podaci pauzirani"</string>
    +     <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"Mobilni podaci pauzirani"</string>
    +     <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"Podaci su pauzirani"</string>
    +-    <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"Budući da je dosegnuto postavljeno ograničenje podataka, uređaj je pauzirao upotrebu podataka za preostali dio ovog ciklusa.\n\nMobilni operater može naplatiti daljnju upotrebu."</string>
    ++    <string name="data_usage_disabled_dialog" msgid="1841738975235283398">"Dosegnuto je vaše ograničenje podataka. Više ne upotrebljavate mobilne podatke.\n\nAko nastavite, moguća je naplata za potrošnju podataka."</string>
    +     <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"Nastavi"</string>
    +     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Nema internetske veze"</string>
    +     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi povezan"</string>
    +@@ -406,6 +406,7 @@
    +     <string name="device_owned_footer" msgid="3802752663326030053">"Uređaj se možda nadzire"</string>
    +     <string name="profile_owned_footer" msgid="8021888108553696069">"Profil se možda nadzire"</string>
    +     <string name="vpn_footer" msgid="2388611096129106812">"Mreža se možda nadzire"</string>
    ++    <string name="branded_vpn_footer" msgid="2168111859226496230">"Mreža se možda nadzire"</string>
    +     <string name="monitoring_title_device_owned" msgid="7121079311903859610">"Nadzor uređaja"</string>
    +     <string name="monitoring_title_profile_owned" msgid="6790109874733501487">"Nadzor profila"</string>
    +     <string name="monitoring_title" msgid="169206259253048106">"Nadzor mreže"</string>
    +@@ -418,6 +419,7 @@
    +     <string name="legacy_vpn_name" msgid="6604123105765737830">"VPN"</string>
    +     <string name="monitoring_description_app" msgid="6259179342284742878">"Povezani ste s aplikacijom <xliff:g id="APPLICATION">%1$s</xliff:g> koja može nadzirati vašu aktivnost na mreži, uključujući e-poštu, aplikacije i web-lokacije."</string>
    +     <string name="monitoring_description_app_personal" msgid="484599052118316268">"Povezani ste s aplikacijom <xliff:g id="APPLICATION">%1$s</xliff:g> koja može nadzirati vašu osobnu aktivnost na mreži, uključujući e-poštu, aplikacije i web-lokacije."</string>
    ++    <string name="branded_monitoring_description_app_personal" msgid="2669518213949202599">"Povezani ste s aplikacijom <xliff:g id="APPLICATION">%1$s</xliff:g> koja može nadzirati vašu osobnu aktivnost na mreži, uključujući e-poštu, aplikacije i web-lokacije."</string>
    +     <string name="monitoring_description_app_work" msgid="1754325860918060897">"Vašim poslovnim profilom upravlja <xliff:g id="ORGANIZATION">%1$s</xliff:g>. Povezan je s aplikacijom <xliff:g id="APPLICATION">%2$s</xliff:g> koja može nadzirati vašu poslovnu aktivnost na mreži, uključujući e-poštu, aplikacije i web-lokacije.\n\nObratite se svojem administratoru za više informacija."</string>
    +     <string name="monitoring_description_app_personal_work" msgid="4946600443852045903">"Vašim poslovnim profilom upravlja <xliff:g id="ORGANIZATION">%1$s</xliff:g>. Povezan je s aplikacijom <xliff:g id="APPLICATION_WORK">%2$s</xliff:g> koja može nadzirati vašu poslovnu aktivnost na mreži, uključujući e-poštu, aplikacije i web-lokacije.\n\nPovezani ste i s aplikacijom <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g> koja može nadzirati vašu osobnu aktivnost na mreži."</string>
    +     <string name="monitoring_description_vpn_app_device_owned" msgid="4970443827043261703">"Vašim uređajem upravlja <xliff:g id="ORGANIZATION">%1$s</xliff:g>.\n\nVaš administrator može nadzirati postavke, poslovni pristup, aplikacije, podatke povezane s uređajem i podatke o lokaciji uređaja te upravljati njima.\n\nPovezani ste s aplikacijom <xliff:g id="APPLICATION">%2$s</xliff:g> koja može nadzirati vašu aktivnost na mreži, uključujući e-poštu, aplikacije i web-lokacije.\n\nObratite se svojem administratoru za više informacija."</string>
    +@@ -494,8 +496,6 @@
    +     <string name="clock_seconds_desc" msgid="6282693067130470675">"Prikazuju se sekunde na satu na traci statusa. Može utjecati na trajanje baterije."</string>
    +     <string name="qs_rearrange" msgid="8060918697551068765">"Promijeni raspored Brzih postavki"</string>
    +     <string name="show_brightness" msgid="6613930842805942519">"Prikaži svjetlinu u Brzim postavkama"</string>
    +-    <string name="overview_nav_bar_gesture" msgid="8579814204727917764">"Omogući pokret povlačenja prema gore za podijeljen zaslon"</string>
    +-    <string name="overview_nav_bar_gesture_desc" msgid="6329167382305102615">"Omogućivanje pokreta za otvaranje podijeljenog zaslona tako da se od gumba Pregled prstom prijeđe prema gore"</string>
    +     <string name="experimental" msgid="6198182315536726162">"Eksperimentalno"</string>
    +     <string name="enable_bluetooth_title" msgid="5027037706500635269">"Želite li uključiti Bluetooth?"</string>
    +     <string name="enable_bluetooth_message" msgid="9106595990708985385">"Da biste povezali tipkovnicu s tabletom, morate uključiti Bluetooth."</string>
    +@@ -653,4 +653,5 @@
    +     <string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"Otvaranje postavki za <xliff:g id="ID_1">%s</xliff:g>."</string>
    +     <string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"Uređivanje redoslijeda postavki."</string>
    +     <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"Stranica <xliff:g id="ID_1">%1$d</xliff:g> od <xliff:g id="ID_2">%2$d</xliff:g>"</string>
    ++    <string name="cant_silence_or_block" msgid="999689262131488625">"Obavijesti se ne mogu utišati niti blokirati"</string>
    + </resources>
    +diff --git a/packages/SystemUI/res/values-hu/strings.xml b/packages/SystemUI/res/values-hu/strings.xml
    +index b89b106..425212a 100644
    +--- a/packages/SystemUI/res/values-hu/strings.xml
    ++++ b/packages/SystemUI/res/values-hu/strings.xml
    +@@ -238,7 +238,7 @@
    +     <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"A 4G adatforgalom szünetel"</string>
    +     <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"A mobilhálózati adatforgalom szünetel"</string>
    +     <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"Az adatforgalom szünetel"</string>
    +-    <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"Mivel elérte a beállított adatkorlátot, az eszköz a ciklus fennmaradó részére felfüggesztette az adathasználatot.\n\nHa mégis használja az adatkapcsolatot, akkor szolgáltatója többletköltséget számíthat fel."</string>
    ++    <string name="data_usage_disabled_dialog" msgid="1841738975235283398">"Elérte a beállított adatkorlátot. A továbbiakban nem használ mobiladat-forgalmat.\n\nHa a folytatást választja, szolgáltatója adathasználati díjat számíthat fel."</string>
    +     <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"Folytatás"</string>
    +     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Nincs internet"</string>
    +     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi csatlakoztatva"</string>
    +@@ -404,6 +404,7 @@
    +     <string name="device_owned_footer" msgid="3802752663326030053">"Lehet, hogy az eszközt figyelik"</string>
    +     <string name="profile_owned_footer" msgid="8021888108553696069">"Profilját felügyelhetik"</string>
    +     <string name="vpn_footer" msgid="2388611096129106812">"Lehet, hogy a hálózatot figyelik"</string>
    ++    <string name="branded_vpn_footer" msgid="2168111859226496230">"Lehet, hogy a hálózat felügyelt"</string>
    +     <string name="monitoring_title_device_owned" msgid="7121079311903859610">"Eszközfigyelés"</string>
    +     <string name="monitoring_title_profile_owned" msgid="6790109874733501487">"Profilfelügyelet"</string>
    +     <string name="monitoring_title" msgid="169206259253048106">"Hálózatfigyelés"</string>
    +@@ -416,6 +417,7 @@
    +     <string name="legacy_vpn_name" msgid="6604123105765737830">"VPN"</string>
    +     <string name="monitoring_description_app" msgid="6259179342284742878">"Csatlakoztatta a(z) <xliff:g id="APPLICATION">%1$s</xliff:g> alkalmazást, amely figyelheti hálózati tevékenységét, beleértve az e-maileket, az alkalmazásokat és a webhelyeket."</string>
    +     <string name="monitoring_description_app_personal" msgid="484599052118316268">"Csatlakoztatta a(z) <xliff:g id="APPLICATION">%1$s</xliff:g> alkalmazást, amely figyelheti személyes hálózati tevékenységét, beleértve az e-maileket, az alkalmazásokat és a webhelyeket."</string>
    ++    <string name="branded_monitoring_description_app_personal" msgid="2669518213949202599">"Ön a(z) <xliff:g id="APPLICATION">%1$s</xliff:g> alkalmazáshoz csatlakozik, amely figyelheti személyes hálózati tevékenységét, beleértve az e-maileket, alkalmazásokat és webhelyeket."</string>
    +     <string name="monitoring_description_app_work" msgid="1754325860918060897">"Munkaprofilját a(z) <xliff:g id="ORGANIZATION">%1$s</xliff:g> felügyeli. Csatlakoztatva van hozzá a(z) <xliff:g id="APPLICATION">%2$s</xliff:g> alkalmazás, amely figyelheti az Ön hálózati tevékenységét, beleértve az e-maileket, az alkalmazásokat és a webhelyeket.\n\nTovábbi információért forduljon a rendszergazdájához."</string>
    +     <string name="monitoring_description_app_personal_work" msgid="4946600443852045903">"Munkaprofilját a(z) <xliff:g id="ORGANIZATION">%1$s</xliff:g> felügyeli. Csatlakoztatva van hozzá a(z) <xliff:g id="APPLICATION_WORK">%2$s</xliff:g> alkalmazás, amely figyelheti az Ön hálózati tevékenységét, beleértve az e-maileket, az alkalmazásokat és a webhelyeket.\n\nCsatlakoztatta továbbá a(z) <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g> alkalmazást, amely szintén figyelemmel kísérheti személyes hálózati tevékenységét."</string>
    +     <string name="monitoring_description_vpn_app_device_owned" msgid="4970443827043261703">"Eszközét a következő felügyeli: <xliff:g id="ORGANIZATION">%1$s</xliff:g>.\n\nA rendszergazda figyelemmel kísérheti és módosíthatja beállításait, vállalati hozzáféréseit, alkalmazásait, az eszközéhez társított adatokat és eszköze helyadatait.\n\nÖn a következőhöz csatlakozik: <xliff:g id="APPLICATION">%2$s</xliff:g>, amely (az e-mailekre, alkalmazásokra és webhelyekre is kiterjedően) figyelemmel kísérheti hálózati tevékenységét.\n\nTovábbi információért forduljon a rendszergazdához."</string>
    +@@ -481,7 +483,7 @@
    +     <string name="accessibility_status_bar_hotspot" msgid="4099381329956402865">"Hotspot"</string>
    +     <string name="accessibility_managed_profile" msgid="6613641363112584120">"Munkaprofil"</string>
    +     <string name="tuner_warning_title" msgid="7094689930793031682">"Egyeseknek tetszik, másoknak nem"</string>
    +-    <string name="tuner_warning" msgid="8730648121973575701">"A Kezelőfelület-hangoló az Android felhasználói felületének szerkesztéséhez és testreszabásához nyújt további megoldásokat. Ezek a kísérleti funkciók változhatnak vagy megsérülhetnek a későbbi kiadásokban,illetve eltűnhetnek azokból. Körültekintően járjon el."</string>
    ++    <string name="tuner_warning" msgid="8730648121973575701">"A Kezelőfelület-hangoló az Android felhasználói felületének szerkesztéséhez és testreszabásához nyújt további megoldásokat. Ezek a kísérleti funkciók változhatnak vagy megsérülhetnek a későbbi kiadásokban, illetve eltűnhetnek azokból. Körültekintően járjon el."</string>
    +     <string name="tuner_persistent_warning" msgid="8597333795565621795">"Ezek a kísérleti funkciók változhatnak vagy megsérülhetnek a későbbi kiadásokban, illetve eltűnhetnek azokból. Körültekintően járjon el."</string>
    +     <string name="got_it" msgid="2239653834387972602">"Értem"</string>
    +     <string name="tuner_toast" msgid="603429811084428439">"Gratulálunk! A Kezelőfelület-hangolót hozzáadtuk a Beállításokhoz"</string>
    +@@ -492,8 +494,6 @@
    +     <string name="clock_seconds_desc" msgid="6282693067130470675">"Másodpercek megjelenítése az állapotsor óráján. Ez hatással lehet az akkumulátor üzemidejére."</string>
    +     <string name="qs_rearrange" msgid="8060918697551068765">"Gyorsbeállítások átrendezése"</string>
    +     <string name="show_brightness" msgid="6613930842805942519">"Fényerő megjelenítése a gyorsbeállításokban"</string>
    +-    <string name="overview_nav_bar_gesture" msgid="8579814204727917764">"Képernyőfelosztó gyors felfelé csúsztatás engedélyezése"</string>
    +-    <string name="overview_nav_bar_gesture_desc" msgid="6329167382305102615">"Kézmozdulat engedélyezése osztott képernyős nézet aktiválásához, ha az Áttekintés gombról felfelé húzza az ujját"</string>
    +     <string name="experimental" msgid="6198182315536726162">"Kísérleti"</string>
    +     <string name="enable_bluetooth_title" msgid="5027037706500635269">"Engedélyezi a Bluetooth-kapcsolatot?"</string>
    +     <string name="enable_bluetooth_message" msgid="9106595990708985385">"Ha a billentyűzetet csatlakoztatni szeretné táblagépéhez, először engedélyeznie kell a Bluetooth-kapcsolatot."</string>
    +@@ -651,4 +651,5 @@
    +     <string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"A(z) <xliff:g id="ID_1">%s</xliff:g> beállításainak megnyitása."</string>
    +     <string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"Beállítások sorrendjének szerkesztése."</string>
    +     <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"<xliff:g id="ID_1">%1$d</xliff:g>. oldal, összesen: <xliff:g id="ID_2">%2$d</xliff:g>"</string>
    ++    <string name="cant_silence_or_block" msgid="999689262131488625">"Az értesítéseket nem lehet elnémítani vagy letiltani"</string>
    + </resources>
    +diff --git a/packages/SystemUI/res/values-hy-rAM/strings.xml b/packages/SystemUI/res/values-hy-rAM/strings.xml
    +index d0d6c50..77b1c82 100644
    +--- a/packages/SystemUI/res/values-hy-rAM/strings.xml
    ++++ b/packages/SystemUI/res/values-hy-rAM/strings.xml
    +@@ -32,7 +32,7 @@
    +     <string name="status_bar_no_notifications_title" msgid="4755261167193833213">"Ծանուցումներ չկան"</string>
    +     <string name="status_bar_ongoing_events_title" msgid="1682504513316879202">"Ընթացիկ"</string>
    +     <string name="status_bar_latest_events_title" msgid="6594767438577593172">"Ծանուցումներ"</string>
    +-    <string name="battery_low_title" msgid="6456385927409742437">"Մարտկոցը լիցքաթափվում է"</string>
    ++    <string name="battery_low_title" msgid="6456385927409742437">"Մարտկոցի լիցքը սպառվում է"</string>
    +     <string name="battery_low_percent_format" msgid="2900940511201380775">"Մնաց <xliff:g id="PERCENTAGE">%s</xliff:g>"</string>
    +     <string name="battery_low_percent_format_saver_started" msgid="6859235584035338833">"Մնաց <xliff:g id="PERCENTAGE">%s</xliff:g>: Մարտկոցի տնտեսումը միացված է:"</string>
    +     <string name="invalid_charger" msgid="4549105996740522523">"USB լիցքավորումը չի աջակցվում:\nՕգտվեք միայն գործող լիցքավորիչից:"</string>
    +@@ -238,7 +238,7 @@
    +     <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"4Գ տվյալների օգտագործումը դադարեցված է"</string>
    +     <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"Բջջային տվյալների օգտագործումը դադարեցված է"</string>
    +     <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"Տվյալների օգտագործումը դադարեցված է"</string>
    +-    <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"Քանի որ ձեր սահմանված տվյալների սահմանաչափը սպառվել է, սարքն այլևս չի օգտագործի տվյալները այս ցիկլի մնացած ընթացքում:\n\nԵթե վերսկսեք, հնարավոր է կիրառվեն գանձումներ ձեր օպերատորի կողմից:"</string>
    ++    <string name="data_usage_disabled_dialog" msgid="1841738975235283398">"Տվյալների օգտագործման համար նշված սահմանաչափը լրացել է: Դուք բջջային տվյալներ այլևս չեք օգտագործում:\n\nԵթե վերսկսեք բջջային տվյալների օգտագործումը, դրա համար կարող են վճարներ գանձվել:"</string>
    +     <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"Վերսկսել"</string>
    +     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Ինտերնետ կապ չկա"</string>
    +     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi-ը միացված է"</string>
    +@@ -404,6 +404,7 @@
    +     <string name="device_owned_footer" msgid="3802752663326030053">"Սարքը կարող է վերահսկվել"</string>
    +     <string name="profile_owned_footer" msgid="8021888108553696069">"Պրոֆիլը կարող է վերահսկվել"</string>
    +     <string name="vpn_footer" msgid="2388611096129106812">"Ցանցը կարող է վերահսկվել"</string>
    ++    <string name="branded_vpn_footer" msgid="2168111859226496230">"Ցանցը կարող է վերահսկվել"</string>
    +     <string name="monitoring_title_device_owned" msgid="7121079311903859610">"Սարքի մշտադիտարկում"</string>
    +     <string name="monitoring_title_profile_owned" msgid="6790109874733501487">"Պրոֆիլի վերահսկում"</string>
    +     <string name="monitoring_title" msgid="169206259253048106">"Ցանցի մշտադիտարկում"</string>
    +@@ -416,6 +417,7 @@
    +     <string name="legacy_vpn_name" msgid="6604123105765737830">"VPN"</string>
    +     <string name="monitoring_description_app" msgid="6259179342284742878">"Դուք կապակցված եք <xliff:g id="APPLICATION">%1$s</xliff:g> հավելվածին, որը կարող է վերահսկել ձեր ցանցի գործունեությունը, այդ թվում նաև էլփոստի հաշիվները, հավելվածները և կայքերը:"</string>
    +     <string name="monitoring_description_app_personal" msgid="484599052118316268">"Դուք կապակցված եք <xliff:g id="APPLICATION">%1$s</xliff:g> հավելվածին, որը կարող է վերահսկել անձնական ցանցում կատարած ձեր գործողությունները, այդ թվում նաև էլփոստի հաշիվները, հավելվածները և կայքերը:"</string>
    ++    <string name="branded_monitoring_description_app_personal" msgid="2669518213949202599">"Դուք կապակցված եք <xliff:g id="APPLICATION">%1$s</xliff:g> հավելվածին, որը կարող է վերահսկել անձնական ցանցում կատարած ձեր գործողությունները, այդ թվում նաև էլփոստի հաշիվները, հավելվածները և կայքերը:"</string>
    +     <string name="monitoring_description_app_work" msgid="1754325860918060897">"Աշխատանքային պրոֆիլի կառավարիչն է՝ <xliff:g id="ORGANIZATION">%1$s</xliff:g>: Այն կապակցված է <xliff:g id="APPLICATION">%2$s</xliff:g> հավելվածին, որը կարող է վերահսկել աշխատանքային ցանցում կատարած գործունեությունը, այդ թվում նաև էլփոստի հաշիվները, հավելվածները և կայքերը:\n\nԼրացուցիչ տեղեկությունների համար դիմեք ադմինիստրատորին:"</string>
    +     <string name="monitoring_description_app_personal_work" msgid="4946600443852045903">"Աշխատանքային պրոֆիլի կառավարիչն է՝ <xliff:g id="ORGANIZATION">%1$s</xliff:g>: Այն կապակցված է <xliff:g id="APPLICATION_WORK">%2$s</xliff:g> հավելվածին, որը կարող է վերահսկել աշխատանքային ցանցում կատարած գործունեությունը, այդ թվում նաև էլփոստի հաշիվները, հավելվածները և կայքերը:\n\nԴուք նույնպես կապակցված եք <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g> հավելվածին, որը կարող է վերահսկել անձնական ցանցում կատարած ձեր գործողությունները:"</string>
    +     <string name="monitoring_description_vpn_app_device_owned" msgid="4970443827043261703">"Սարքի կառավարիչն է՝ <xliff:g id="ORGANIZATION">%1$s</xliff:g>:\n\nԱդմինիստրատորը կարող է վերահսկել և կառավարել կարգավորումները, կորպորատիվ հաշիվը, հավելվածները, սարքի հետ առնչվող և սարքի տեղադրության տվյալները:\n\nՆաև կապակցված եք <xliff:g id="APPLICATION">%2$s</xliff:g> հավելվածին, ինչը կարող է վերահսկել ձեր ցանցի գործունեությունը, այդ թվում նաև՝ էլփոստի հաշիվները, հավելվածները և կայքերը:\n\nԼրացուցիչ տեղեկությունների համար դիմեք ադմինիստրատորին:"</string>
    +@@ -492,8 +494,6 @@
    +     <string name="clock_seconds_desc" msgid="6282693067130470675">"Ցույց տալ ժամացույցի վայրկյանները կարգավիճակի տողում: Կարող է ազդել մարտկոցի աշխատանքի ժամանակի վրա:"</string>
    +     <string name="qs_rearrange" msgid="8060918697551068765">"Վերադասավորել Արագ կարգավորումները"</string>
    +     <string name="show_brightness" msgid="6613930842805942519">"Ցույց տալ պայծառությունն Արագ կարգավորումներում"</string>
    +-    <string name="overview_nav_bar_gesture" msgid="8579814204727917764">"Ակտիվացնել մատը վերև սահեցնելով էկրանը տրոհելու ժեստը"</string>
    +-    <string name="overview_nav_bar_gesture_desc" msgid="6329167382305102615">"Միացնել Համատեսք կոճակից մատը դեպի վերև սահեցնելու միջոցով տրոհված էկրանի ռեժիմ անցնելու ժեստը"</string>
    +     <string name="experimental" msgid="6198182315536726162">"Փորձնական"</string>
    +     <string name="enable_bluetooth_title" msgid="5027037706500635269">"Միացնե՞լ Bluetooth-ը:"</string>
    +     <string name="enable_bluetooth_message" msgid="9106595990708985385">"Ստեղնաշարը ձեր պլանշետին միացնելու համար նախ անհրաժեշտ է միացնել Bluetooth-ը:"</string>
    +@@ -644,11 +644,12 @@
    +     <string name="accessibility_quick_settings_settings" msgid="6132460890024942157">"Բացել կարգավորումները:"</string>
    +     <string name="accessibility_quick_settings_expand" msgid="2375165227880477530">"Բացել արագ կարգավորումները:"</string>
    +     <string name="accessibility_quick_settings_collapse" msgid="1792625797142648105">"Փակել արագ կարգավորումները:"</string>
    +-    <string name="accessibility_quick_settings_alarm_set" msgid="1863000242431528676">"Զարթուցիչը կարգավորված է:"</string>
    ++    <string name="accessibility_quick_settings_alarm_set" msgid="1863000242431528676">"Զարթուցիչը դրված է:"</string>
    +     <string name="accessibility_quick_settings_user" msgid="1567445362870421770">"Մուտք է գործել որպես <xliff:g id="ID_1">%s</xliff:g>"</string>
    +     <string name="accessibility_quick_settings_no_internet" msgid="31890692343084075">"Ինտերնետ կապ չկա:"</string>
    +     <string name="accessibility_quick_settings_open_details" msgid="4230931801728005194">"Բացել մանրամասները:"</string>
    +     <string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"Բացել <xliff:g id="ID_1">%s</xliff:g> կարգավորումները:"</string>
    +     <string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"Խմբագրել կարգավորումների հերթականությունը:"</string>
    +     <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"Էջ <xliff:g id="ID_1">%1$d</xliff:g> / <xliff:g id="ID_2">%2$d</xliff:g>"</string>
    ++    <string name="cant_silence_or_block" msgid="999689262131488625">"Հնարավոր չէ արգելափակել ծանուցումները կամ անջատել դրանց ձայնը"</string>
    + </resources>
    +diff --git a/packages/SystemUI/res/values-in/strings.xml b/packages/SystemUI/res/values-in/strings.xml
    +index ad24d6a..d006add 100644
    +--- a/packages/SystemUI/res/values-in/strings.xml
    ++++ b/packages/SystemUI/res/values-in/strings.xml
    +@@ -238,7 +238,7 @@
    +     <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"Data 4G dijeda"</string>
    +     <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"Data seluler dijeda"</string>
    +     <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"Data dijeda"</string>
    +-    <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"Karena batas data yang disetel telah tercapai, perangkat telah menjeda penggunaan data selama sisa waktu siklus ini.\n\nMelanjutkan dapat mengakibatkan tagihan dari operator."</string>
    ++    <string name="data_usage_disabled_dialog" msgid="1841738975235283398">"Batas data yang disetel telah tercapai. Anda tidak menggunakan data seluler lagi.\n\nJika Anda melanjutkan, biaya penggunaan data mungkin berlaku."</string>
    +     <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"Lanjutkan"</string>
    +     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Tidak ada sambungan internet"</string>
    +     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi tersambung"</string>
    +@@ -404,6 +404,7 @@
    +     <string name="device_owned_footer" msgid="3802752663326030053">"Perangkat mungkin dipantau"</string>
    +     <string name="profile_owned_footer" msgid="8021888108553696069">"Profil dapat dipantau"</string>
    +     <string name="vpn_footer" msgid="2388611096129106812">"Jaringan mungkin dipantau"</string>
    ++    <string name="branded_vpn_footer" msgid="2168111859226496230">"Jaringan mungkin dipantau"</string>
    +     <string name="monitoring_title_device_owned" msgid="7121079311903859610">"Pemantauan perangkat"</string>
    +     <string name="monitoring_title_profile_owned" msgid="6790109874733501487">"Pemantauan profil"</string>
    +     <string name="monitoring_title" msgid="169206259253048106">"Pemantauan jaringan"</string>
    +@@ -416,6 +417,7 @@
    +     <string name="legacy_vpn_name" msgid="6604123105765737830">"VPN"</string>
    +     <string name="monitoring_description_app" msgid="6259179342284742878">"Anda tersambung ke <xliff:g id="APPLICATION">%1$s</xliff:g>, yang dapat memantau aktivitas jaringan, termasuk email, aplikasi, dan situs web."</string>
    +     <string name="monitoring_description_app_personal" msgid="484599052118316268">"Anda tersambung ke <xliff:g id="APPLICATION">%1$s</xliff:g>, yang dapat memantau aktivitas jaringan pribadi, termasuk email, aplikasi, dan situs web."</string>
    ++    <string name="branded_monitoring_description_app_personal" msgid="2669518213949202599">"Anda tersambung ke <xliff:g id="APPLICATION">%1$s</xliff:g>, yang dapat memantau aktivitas jaringan pribadi, termasuk email, aplikasi, dan situs web.."</string>
    +     <string name="monitoring_description_app_work" msgid="1754325860918060897">"Profil kerja dikelola oleh <xliff:g id="ORGANIZATION">%1$s</xliff:g> dan tersambung ke <xliff:g id="APPLICATION">%2$s</xliff:g>, yang dapat memantau aktivitas jaringan kerja, termasuk email, aplikasi, dan situs web.\n\nUntuk informasi selengkapnya, hubungi administrator."</string>
    +     <string name="monitoring_description_app_personal_work" msgid="4946600443852045903">"Profil kerja dikelola oleh <xliff:g id="ORGANIZATION">%1$s</xliff:g> dan tersambung ke <xliff:g id="APPLICATION_WORK">%2$s</xliff:g>, yang dapat memantau aktivitas jaringan kerja, termasuk email, aplikasi, dan situs web.\n\nAnda juga tersambung ke <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g>, yang dapat memantau aktivitas jaringan pribadi."</string>
    +     <string name="monitoring_description_vpn_app_device_owned" msgid="4970443827043261703">"Perangkat dikelola oleh <xliff:g id="ORGANIZATION">%1$s</xliff:g>.\n\nAdministrator dapat memantau dan mengelola setelan, akses perusahaan, aplikasi, data terkait perangkat, dan informasi lokasi perangkat.\n\nAnda tersambung ke <xliff:g id="APPLICATION">%2$s</xliff:g>, yang dapat memantau aktivitas jaringan, termasuk email, aplikasi, dan situs web.\n\nUntuk informasi selengkapnya, hubungi administrator."</string>
    +@@ -492,8 +494,6 @@
    +     <string name="clock_seconds_desc" msgid="6282693067130470675">"Tampilkan detik jam di bilah status. Dapat memengaruhi masa pakai baterai."</string>
    +     <string name="qs_rearrange" msgid="8060918697551068765">"Atur Ulang Setelan Cepat"</string>
    +     <string name="show_brightness" msgid="6613930842805942519">"Tampilkan kecerahan di Setelan Cepat"</string>
    +-    <string name="overview_nav_bar_gesture" msgid="8579814204727917764">"Aktifkan isyarat gesek atas untuk layar terpisah"</string>
    +-    <string name="overview_nav_bar_gesture_desc" msgid="6329167382305102615">"Aktifkan isyarat untuk masuk layar terpisah dengan menggesek tombol Ringkasan ke atas"</string>
    +     <string name="experimental" msgid="6198182315536726162">"Eksperimental"</string>
    +     <string name="enable_bluetooth_title" msgid="5027037706500635269">"Aktifkan Bluetooth?"</string>
    +     <string name="enable_bluetooth_message" msgid="9106595990708985385">"Untuk menghubungkan keyboard dengan tablet, terlebih dahulu aktifkan Bluetooth."</string>
    +@@ -651,4 +651,5 @@
    +     <string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"Buka setelan <xliff:g id="ID_1">%s</xliff:g>."</string>
    +     <string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"Edit urutan setelan."</string>
    +     <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"Halaman <xliff:g id="ID_1">%1$d</xliff:g> dari <xliff:g id="ID_2">%2$d</xliff:g>"</string>
    ++    <string name="cant_silence_or_block" msgid="999689262131488625">"Notifikasi tidak dapat disenyapkan atau diblokir"</string>
    + </resources>
    +diff --git a/packages/SystemUI/res/values-is-rIS/strings.xml b/packages/SystemUI/res/values-is-rIS/strings.xml
    +index a95e28b..26b1e74 100644
    +--- a/packages/SystemUI/res/values-is-rIS/strings.xml
    ++++ b/packages/SystemUI/res/values-is-rIS/strings.xml
    +@@ -238,7 +238,7 @@
    +     <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"Slökkt er á 4G-gögnum"</string>
    +     <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"Slökkt er á farsímagögnum"</string>
    +     <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"Slökkt er á gagnanotkun"</string>
    +-    <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"Þar sem gagnahámarkinu var náð hefur tækið slökkt á gagnanotkun það sem eftir er af þessu tímabili.\n\nEf þú heldur áfram kann það að leiða til kostnaðar frá símafyrirtækinu."</string>
    ++    <string name="data_usage_disabled_dialog" msgid="1841738975235283398">"Gagnamörkunum sem þú stilltir hefur verið náð. Þú ert ekki lengur að nota farsímagögn.\n\nEf þú heldur áfram gætu gjöld fyrir gagnanotkun átt við."</string>
    +     <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"Halda áfram"</string>
    +     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Engin nettenging"</string>
    +     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi tengt"</string>
    +@@ -404,6 +404,7 @@
    +     <string name="device_owned_footer" msgid="3802752663326030053">"Hugsanlega er fylgst með tækjum"</string>
    +     <string name="profile_owned_footer" msgid="8021888108553696069">"Hugsanlega er fylgst með þessu sniði"</string>
    +     <string name="vpn_footer" msgid="2388611096129106812">"Hugsanlega er fylgst með netinu"</string>
    ++    <string name="branded_vpn_footer" msgid="2168111859226496230">"Hugsanlega er fylgst með netinu"</string>
    +     <string name="monitoring_title_device_owned" msgid="7121079311903859610">"Tækjaeftirlit"</string>
    +     <string name="monitoring_title_profile_owned" msgid="6790109874733501487">"Fylgst með sniði"</string>
    +     <string name="monitoring_title" msgid="169206259253048106">"Neteftirlit"</string>
    +@@ -416,6 +417,7 @@
    +     <string name="legacy_vpn_name" msgid="6604123105765737830">"VPN"</string>
    +     <string name="monitoring_description_app" msgid="6259179342284742878">"Þú ert með tengingu við <xliff:g id="APPLICATION">%1$s</xliff:g>, sem getur fylgst með netnotkun þinni, þ. á m. tölvupósti, forritum og vefsvæðum."</string>
    +     <string name="monitoring_description_app_personal" msgid="484599052118316268">"Þú ert með tengingu við <xliff:g id="APPLICATION">%1$s</xliff:g>, sem getur fylgst með persónulegri netnotkun þinni, þ. á m. tölvupósti, forritum og vefsvæðum."</string>
    ++    <string name="branded_monitoring_description_app_personal" msgid="2669518213949202599">"Þú ert með tengingu við <xliff:g id="APPLICATION">%1$s</xliff:g>, sem getur fylgst með persónulegri netnotkun þinni, þ. á m. tölvupósti, forritum og vefsvæðum."</string>
    +     <string name="monitoring_description_app_work" msgid="1754325860918060897">"Vinnusniðinu þínu er stjórnað af <xliff:g id="ORGANIZATION">%1$s</xliff:g>. Það er tengt <xliff:g id="APPLICATION">%2$s</xliff:g>, sem getur fylgst með vinnutengdri netnotkun þinni, þar á meðal tölvupósti, forritum og vefsvæðum.\n\nHafðu samband við kerfisstjórann til að fá frekari upplýsingar."</string>
    +     <string name="monitoring_description_app_personal_work" msgid="4946600443852045903">"Vinnusniðinu þínu er stjórnað af <xliff:g id="ORGANIZATION">%1$s</xliff:g>. Það er tengt <xliff:g id="APPLICATION_WORK">%2$s</xliff:g>, sem getur fylgst með vinnutengdri netnotkun þinni, þar á meðal tölvupósti, forritum og vefsvæðum.\n\nÞú ert einnig með tengingu við <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g>, sem getur fylgst með persónulegri netnotkun þinni."</string>
    +     <string name="monitoring_description_vpn_app_device_owned" msgid="4970443827043261703">"Tækinu er stjórnað af <xliff:g id="ORGANIZATION">%1$s</xliff:g>.\n\nKerfisstjórinn þinn getur fylgst með og stjórnað stillingum, fyrirtækjaaðgangi, forritum, gögnum sem tengd eru tækinu og staðsetningarupplýsingum tækisins.\n\nÞú ert með tengingu við <xliff:g id="APPLICATION">%2$s</xliff:g>, sem getur fylgst með netnotkun þinni, þar á meðal tölvupósti, forritum og vefsvæðum.\n\nHafðu samband við kerfisstjórann til að fá frekari upplýsingar."</string>
    +@@ -492,8 +494,6 @@
    +     <string name="clock_seconds_desc" msgid="6282693067130470675">"Sýna sekúndur á klukku í stöðustikunni. Getur haft áhrif á endingu rafhlöðu."</string>
    +     <string name="qs_rearrange" msgid="8060918697551068765">"Endurraða flýtistillingum"</string>
    +     <string name="show_brightness" msgid="6613930842805942519">"Sýna birtustig í flýtistillingum"</string>
    +-    <string name="overview_nav_bar_gesture" msgid="8579814204727917764">"Virkja skjáskiptingu með því að strjúka upp"</string>
    +-    <string name="overview_nav_bar_gesture_desc" msgid="6329167382305102615">"Virkja skjáskiptingarbendingu með því að strjúka upp frá yfirlitshnappi"</string>
    +     <string name="experimental" msgid="6198182315536726162">"Tilraunastillingar"</string>
    +     <string name="enable_bluetooth_title" msgid="5027037706500635269">"Kveikja á Bluetooth?"</string>
    +     <string name="enable_bluetooth_message" msgid="9106595990708985385">"Til að geta tengt lyklaborðið við spjaldtölvuna þarftu fyrst að kveikja á Bluetooth."</string>
    +@@ -651,4 +651,5 @@
    +     <string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"Opna <xliff:g id="ID_1">%s</xliff:g> stillingar."</string>
    +     <string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"Breyta röð stillinga."</string>
    +     <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"Blaðsíða <xliff:g id="ID_1">%1$d</xliff:g> af <xliff:g id="ID_2">%2$d</xliff:g>"</string>
    ++    <string name="cant_silence_or_block" msgid="999689262131488625">"Ekki er hægt að þagga eða loka á tilkynningar"</string>
    + </resources>
    +diff --git a/packages/SystemUI/res/values-it/strings.xml b/packages/SystemUI/res/values-it/strings.xml
    +index d370b65..d056637 100644
    +--- a/packages/SystemUI/res/values-it/strings.xml
    ++++ b/packages/SystemUI/res/values-it/strings.xml
    +@@ -240,7 +240,7 @@
    +     <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"Dati 4G sospesi"</string>
    +     <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"Dati cellulari sospesi"</string>
    +     <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"Dati sospesi"</string>
    +-    <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"Hai raggiunto il tuo limite di dati, pertanto sul dispositivo è stato sospeso l\'utilizzo di dati per la parte rimanente del ciclo.\n\nSe riprendi a utilizzare i dati, l\'operatore potrebbe addebitarti costi."</string>
    ++    <string name="data_usage_disabled_dialog" msgid="1841738975235283398">"È stato raggiunto il limite di dati impostato. La rete dati è stata disattivata.\n\nSe la riattivi, potrebbero essere applicati costi per l\'utilizzo dei dati."</string>
    +     <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"Riprendi"</string>
    +     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Nessuna connessione"</string>
    +     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi connesso"</string>
    +@@ -347,7 +347,7 @@
    +     <string name="description_target_search" msgid="3091587249776033139">"Ricerca"</string>
    +     <string name="description_direction_up" msgid="7169032478259485180">"Su per <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
    +     <string name="description_direction_left" msgid="7207478719805562165">"A sinistra per <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
    +-    <string name="zen_priority_introduction" msgid="3070506961866919502">"Non verrai disturbato da suoni e vibrazioni, ad eccezione di sveglie, promemoria, eventi e chiamate da contatti da te specificati."</string>
    ++    <string name="zen_priority_introduction" msgid="3070506961866919502">"Non ti disturberanno: suoni e vibrazioni, ad eccezione di sveglie, promemoria, eventi e chiamate da contatti da te specificati."</string>
    +     <string name="zen_priority_customize_button" msgid="7948043278226955063">"Personalizza"</string>
    +     <string name="zen_silence_introduction_voice" msgid="2284540992298200729">"Verranno bloccati TUTTI i suoni e le vibrazioni, anche di sveglie, musica, video e giochi. Potrai ancora telefonare."</string>
    +     <string name="zen_silence_introduction" msgid="3137882381093271568">"Verranno bloccati TUTTI i suoni e le vibrazioni, anche di sveglie, musica, video e giochi."</string>
    +@@ -406,6 +406,7 @@
    +     <string name="device_owned_footer" msgid="3802752663326030053">"Il dispositivo potrebbe essere monitorato"</string>
    +     <string name="profile_owned_footer" msgid="8021888108553696069">"Il profilo potrebbe essere monitorato"</string>
    +     <string name="vpn_footer" msgid="2388611096129106812">"La rete potrebbe essere monitorata"</string>
    ++    <string name="branded_vpn_footer" msgid="2168111859226496230">"La rete potrebbe essere monitorata"</string>
    +     <string name="monitoring_title_device_owned" msgid="7121079311903859610">"Monitoraggio del dispositivo"</string>
    +     <string name="monitoring_title_profile_owned" msgid="6790109874733501487">"Monitoraggio del profilo"</string>
    +     <string name="monitoring_title" msgid="169206259253048106">"Monitoraggio rete"</string>
    +@@ -418,6 +419,7 @@
    +     <string name="legacy_vpn_name" msgid="6604123105765737830">"VPN"</string>
    +     <string name="monitoring_description_app" msgid="6259179342284742878">"Sei connesso a <xliff:g id="APPLICATION">%1$s</xliff:g>, da cui è possibile monitorare la tua attività di rete, inclusi email, app e siti web."</string>
    +     <string name="monitoring_description_app_personal" msgid="484599052118316268">"Sei connesso a <xliff:g id="APPLICATION">%1$s</xliff:g>, da cui è possibile monitorare la tua attività di rete personale, inclusi email, app e siti web."</string>
    ++    <string name="branded_monitoring_description_app_personal" msgid="2669518213949202599">"Sei collegato a <xliff:g id="APPLICATION">%1$s</xliff:g>, che consente di monitorare la tua attività di rete personale, inclusi siti web, email e app."</string>
    +     <string name="monitoring_description_app_work" msgid="1754325860918060897">"Il tuo profilo di lavoro è gestito da <xliff:g id="ORGANIZATION">%1$s</xliff:g>. È connesso a <xliff:g id="APPLICATION">%2$s</xliff:g>, da cui è possibile monitorare la tua attività di rete lavorativa, inclusi email, app e siti web.\n\nPer ulteriori informazioni, contatta il tuo amministratore."</string>
    +     <string name="monitoring_description_app_personal_work" msgid="4946600443852045903">"Il tuo profilo di lavoro è gestito da <xliff:g id="ORGANIZATION">%1$s</xliff:g>. È connesso a <xliff:g id="APPLICATION_WORK">%2$s</xliff:g>, da cui è possibile monitorare la tua attività di rete lavorativa, inclusi email, app e siti web.\n\nSei connesso anche a <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g>, da cui è possibile monitorare la tua attività di rete personale."</string>
    +     <string name="monitoring_description_vpn_app_device_owned" msgid="4970443827043261703">"Il tuo dispositivo è gestito da <xliff:g id="ORGANIZATION">%1$s</xliff:g>.\n\nL\'amministratore può monitorare e gestire impostazioni, accesso aziendale, app e dati associati al dispositivo, incluse le informazioni sulla posizione del dispositivo.\n\nSei connesso a <xliff:g id="APPLICATION">%2$s</xliff:g>, da cui è possibile monitorare la tua attività di rete, inclusi email, app e siti web.\n\nPer ulteriori informazioni, contatta l\'amministratore."</string>
    +@@ -494,8 +496,6 @@
    +     <string name="clock_seconds_desc" msgid="6282693067130470675">"Mostra i secondi nell\'orologio nella barra di stato. Ciò potrebbe ridurre la durata della carica della batteria."</string>
    +     <string name="qs_rearrange" msgid="8060918697551068765">"Riorganizza Impostazioni rapide"</string>
    +     <string name="show_brightness" msgid="6613930842805942519">"Mostra luminosità in Impostazioni rapide"</string>
    +-    <string name="overview_nav_bar_gesture" msgid="8579814204727917764">"Attiva Schermo diviso mediante scorrimento verso l\'alto"</string>
    +-    <string name="overview_nav_bar_gesture_desc" msgid="6329167382305102615">"Consente di attivare la modalità Schermo diviso scorrendo verso l\'alto dal pulsante Panoramica"</string>
    +     <string name="experimental" msgid="6198182315536726162">"Sperimentali"</string>
    +     <string name="enable_bluetooth_title" msgid="5027037706500635269">"Attivare il Bluetooth?"</string>
    +     <string name="enable_bluetooth_message" msgid="9106595990708985385">"Per connettere la tastiera al tablet, devi prima attivare il Bluetooth."</string>
    +@@ -653,4 +653,5 @@
    +     <string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"Apri le impostazioni <xliff:g id="ID_1">%s</xliff:g>."</string>
    +     <string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"Modifica l\'ordine delle impostazioni."</string>
    +     <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"Pagina <xliff:g id="ID_1">%1$d</xliff:g> di <xliff:g id="ID_2">%2$d</xliff:g>"</string>
    ++    <string name="cant_silence_or_block" msgid="999689262131488625">"Le notifiche non possono essere disattivate o bloccate"</string>
    + </resources>
    +diff --git a/packages/SystemUI/res/values-it/strings_car.xml b/packages/SystemUI/res/values-it/strings_car.xml
    +index ae26c9e..19c4e2b 100644
    +--- a/packages/SystemUI/res/values-it/strings_car.xml
    ++++ b/packages/SystemUI/res/values-it/strings_car.xml
    +@@ -20,5 +20,5 @@
    + <resources xmlns:android="http://schemas.android.com/apk/res/android"
    +     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
    +     <string name="car_lockscreen_disclaimer_title" msgid="7997539137376896441">"Guida in modo sicuro"</string>
    +-    <string name="car_lockscreen_disclaimer_text" msgid="3061224684092952864">"È necessario essere sempre pienamente coscienti delle condizioni di guida e rispettare le leggi vigenti. Le indicazioni stradali potrebbero essere imprecise, incomplete, pericolose, non adatte, vietate o implicare l\'attraversamento di confini. Anche le informazioni sulle attività commerciali potrebbero essere imprecise o incomplete. I dati non vengono forniti in tempo reale e non è possibile garantire la precisione della geolocalizzazione. Non maneggiare il dispositivo mobile e non utilizzare app non progettate per Android Auto durante la guida."</string>
    ++    <string name="car_lockscreen_disclaimer_text" msgid="3061224684092952864">"È necessario essere sempre pienamente informati sulle condizioni della strada e rispettare la legislazione vigente. Le indicazioni stradali potrebbero essere imprecise, incomplete, pericolose, inadatte, vietate o richiedere l\'attraversamento di aree amministrative. Anche le informazioni sugli esercizi commerciali potrebbero essere imprecise o incomplete. I dati forniti non sono aggiornati in tempo reale e non è possibile garantire la precisione della geolocalizzazione. Non maneggiare dispositivi mobili e app non destinate ad Android Auto durante la guida."</string>
    + </resources>
    +diff --git a/packages/SystemUI/res/values-iw/strings.xml b/packages/SystemUI/res/values-iw/strings.xml
    +index 4cf48c2..19a94a3 100644
    +--- a/packages/SystemUI/res/values-iw/strings.xml
    ++++ b/packages/SystemUI/res/values-iw/strings.xml
    +@@ -240,7 +240,7 @@
    +     <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"‏השימוש בנתוני 4G מושהה"</string>
    +     <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"השימוש בנתונים סלולריים מושהה"</string>
    +     <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"השימוש בנתונים מושהה"</string>
    +-    <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"מכיוון שהגעת למגבלת הנתונים שהגדרת, המכשיר השהה את השימוש בנתונים עד סוף התקופה.\n\nאם תמשיך, אתה עשוי לקבל חיובים מהספק."</string>
    ++    <string name="data_usage_disabled_dialog" msgid="1841738975235283398">"הגעת למגבלת הנתונים שהגדרת. אתה כבר לא משתמש בנתונים סלולריים.\n\nאם תמשיך, ייתכנו חיובים לשימוש בנתונים."</string>
    +     <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"המשך"</string>
    +     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"אין חיבור לאינטרנט"</string>
    +     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"‏Wi-Fi מחובר"</string>
    +@@ -408,6 +408,7 @@
    +     <string name="device_owned_footer" msgid="3802752663326030053">"ייתכן שהמכשיר נמצא במעקב"</string>
    +     <string name="profile_owned_footer" msgid="8021888108553696069">"ייתכן שהפרופיל נתון למעקב"</string>
    +     <string name="vpn_footer" msgid="2388611096129106812">"ייתכן שהרשת נמצאת במעקב"</string>
    ++    <string name="branded_vpn_footer" msgid="2168111859226496230">"ייתכן שהרשת מנוטרת"</string>
    +     <string name="monitoring_title_device_owned" msgid="7121079311903859610">"מעקב אחר מכשיר"</string>
    +     <string name="monitoring_title_profile_owned" msgid="6790109874733501487">"מעקב אחר פרופיל"</string>
    +     <string name="monitoring_title" msgid="169206259253048106">"מעקב אחר פעילות ברשת"</string>
    +@@ -420,6 +421,7 @@
    +     <string name="legacy_vpn_name" msgid="6604123105765737830">"VPN"</string>
    +     <string name="monitoring_description_app" msgid="6259179342284742878">"אתה מחובר לאפליקציה <xliff:g id="APPLICATION">%1$s</xliff:g>, שיכולה לעקוב אחר הפעילות שלך ברשת, כולל הודעות אימייל, אפליקציות ואתרים."</string>
    +     <string name="monitoring_description_app_personal" msgid="484599052118316268">"אתה מחובר לאפליקציה <xliff:g id="APPLICATION">%1$s</xliff:g>, שיכולה לעקוב אחר הפעילות שלך ברשת הפרטית, כולל הודעות אימייל, אפליקציות ואתרים."</string>
    ++    <string name="branded_monitoring_description_app_personal" msgid="2669518213949202599">"אתה מחובר לאפליקציה <xliff:g id="APPLICATION">%1$s</xliff:g>, שיכולה לעקוב אחר הפעילות שלך ברשת הפרטית, כולל הודעות אימייל, אפליקציות ואתרים."</string>
    +     <string name="monitoring_description_app_work" msgid="1754325860918060897">"פרופיל העבודה שלך מנוהל על ידי <xliff:g id="ORGANIZATION">%1$s</xliff:g>. הוא מחובר לאפליקציה <xliff:g id="APPLICATION">%2$s</xliff:g>, שיכולה לעקוב אחר הפעילות שלך ברשת העסקית, כולל הודעות אימייל, אפליקציות ואתרים.\n\nלמידע נוסף, פנה למנהל המערכת שלך."</string>
    +     <string name="monitoring_description_app_personal_work" msgid="4946600443852045903">"פרופיל העבודה שלך מנוהל על ידי <xliff:g id="ORGANIZATION">%1$s</xliff:g>. הוא מחובר לאפליקציה <xliff:g id="APPLICATION_WORK">%2$s</xliff:g>, שיכולה לעקוב אחר הפעילות שלך ברשת העסקית, כולל הודעות אימייל, אפליקציות ואתרים.\n\nאתה מחובר גם לאפליקציה <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g>, שיכולה לעקוב אחר הפעילות שלך ברשת הפרטית."</string>
    +     <string name="monitoring_description_vpn_app_device_owned" msgid="4970443827043261703">"המכשיר שלך מנוהל על ידי <xliff:g id="ORGANIZATION">%1$s</xliff:g>.\n\nמנהל המערכת שלך יכול לעקוב אחר הגדרות, גישה עסקית, אפליקציות, נתונים המשויכים למכשיר שלך ומידע על מיקום המכשיר, ולנהל אותם.\n\nאתה מחובר לאפליקציה <xliff:g id="APPLICATION">%2$s</xliff:g>, שיכולה לעקוב אחר הפעילות שלך ברשת, כולל הודעות אימייל, אפליקציות ואתרים.\n\nלמידע נוסף, פנה למנהל המערכת שלך."</string>
    +@@ -496,8 +498,6 @@
    +     <string name="clock_seconds_desc" msgid="6282693067130470675">"הצג שניות בשעון בשורת הסטטוס. פעולה זו עשויה להשפיע על אורך חיי הסוללה."</string>
    +     <string name="qs_rearrange" msgid="8060918697551068765">"סידור מחדש של הגדרות מהירות"</string>
    +     <string name="show_brightness" msgid="6613930842805942519">"הצג בהירות בהגדרות מהירות"</string>
    +-    <string name="overview_nav_bar_gesture" msgid="8579814204727917764">"הפעל מסך מפוצל על ידי תנועת החלקה כלפי מעלה"</string>
    +-    <string name="overview_nav_bar_gesture_desc" msgid="6329167382305102615">"הפעל את התנועה לכניסה למסך מפוצל על ידי החלקה כלפי מעלה מלחצן הסקירה"</string>
    +     <string name="experimental" msgid="6198182315536726162">"ניסיוניות"</string>
    +     <string name="enable_bluetooth_title" msgid="5027037706500635269">"‏האם להפעיל את ה-Bluetooth?"</string>
    +     <string name="enable_bluetooth_message" msgid="9106595990708985385">"‏כדי לחבר את המקלדת לטאבלט, תחילה עליך להפעיל את ה-Bluetooth."</string>
    +@@ -655,4 +655,5 @@
    +     <string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"פתיחת הגדרות של <xliff:g id="ID_1">%s</xliff:g>."</string>
    +     <string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"עריכת סדר ההגדרות."</string>
    +     <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"דף <xliff:g id="ID_1">%1$d</xliff:g> מתוך <xliff:g id="ID_2">%2$d</xliff:g>"</string>
    ++    <string name="cant_silence_or_block" msgid="999689262131488625">"לא ניתן להשתיק או לחסום הודעות"</string>
    + </resources>
    +diff --git a/packages/SystemUI/res/values-ja/strings.xml b/packages/SystemUI/res/values-ja/strings.xml
    +index c42e346..8d51fe6 100644
    +--- a/packages/SystemUI/res/values-ja/strings.xml
    ++++ b/packages/SystemUI/res/values-ja/strings.xml
    +@@ -197,13 +197,13 @@
    +     <string name="accessibility_quick_settings_airplane_on" msgid="6406141469157599296">"機内モードがONです。"</string>
    +     <string name="accessibility_quick_settings_airplane_changed_off" msgid="66846307818850664">"機内モードをOFFにしました。"</string>
    +     <string name="accessibility_quick_settings_airplane_changed_on" msgid="8983005603505087728">"機内モードをONにしました。"</string>
    +-    <string name="accessibility_quick_settings_dnd_priority_on" msgid="1448402297221249355">"[通知を非表示]はONで、優先する通知のみです。"</string>
    +-    <string name="accessibility_quick_settings_dnd_none_on" msgid="6882582132662613537">"[通知を非表示]はONで、サイレントです。"</string>
    +-    <string name="accessibility_quick_settings_dnd_alarms_on" msgid="9152834845587554157">"[通知を非表示]はONで、アラームのみです。"</string>
    +-    <string name="accessibility_quick_settings_dnd" msgid="6607873236717185815">"通知を非表示"</string>
    +-    <string name="accessibility_quick_settings_dnd_off" msgid="2371832603753738581">"[通知を非表示]はOFFです。"</string>
    +-    <string name="accessibility_quick_settings_dnd_changed_off" msgid="898107593453022935">"[通知を非表示]をOFFにしました。"</string>
    +-    <string name="accessibility_quick_settings_dnd_changed_on" msgid="4483780856613561039">"[通知を非表示]をONにしました。"</string>
    ++    <string name="accessibility_quick_settings_dnd_priority_on" msgid="1448402297221249355">"マナーモードは ON で、優先する通知のみ許可します。"</string>
    ++    <string name="accessibility_quick_settings_dnd_none_on" msgid="6882582132662613537">"マナーモードは ON で、サイレント モードです。"</string>
    ++    <string name="accessibility_quick_settings_dnd_alarms_on" msgid="9152834845587554157">"マナーモードは ON で、アラームのみ許可します。"</string>
    ++    <string name="accessibility_quick_settings_dnd" msgid="6607873236717185815">"マナーモード"</string>
    ++    <string name="accessibility_quick_settings_dnd_off" msgid="2371832603753738581">"マナーモードは OFF です。"</string>
    ++    <string name="accessibility_quick_settings_dnd_changed_off" msgid="898107593453022935">"マナーモードを OFF にしました。"</string>
    ++    <string name="accessibility_quick_settings_dnd_changed_on" msgid="4483780856613561039">"マナーモードを ON にしました。"</string>
    +     <string name="accessibility_quick_settings_bluetooth" msgid="6341675755803320038">"Bluetooth"</string>
    +     <string name="accessibility_quick_settings_bluetooth_off" msgid="2133631372372064339">"BluetoothがOFFです。"</string>
    +     <string name="accessibility_quick_settings_bluetooth_on" msgid="7681999166216621838">"BluetoothがONです。"</string>
    +@@ -240,7 +240,7 @@
    +     <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"4Gデータは一時停止中です"</string>
    +     <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"モバイルデータは一時停止中です"</string>
    +     <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"データの一時停止"</string>
    +-    <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"設定されたデータの上限に達したため、このサイクルの終了までこの端末でのデータの利用を一時停止しました。\n\n再開すると、携帯通信会社から課金される可能性があります。"</string>
    ++    <string name="data_usage_disabled_dialog" msgid="1841738975235283398">"設定されたデータの上限に達しているため、モバイルデータの使用を停止しました。\n\n再開すると、携帯通信会社からデータ使用量に応じた通信料を課金される可能性があります。"</string>
    +     <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"再開"</string>
    +     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"インターネット未接続"</string>
    +     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi接続済み"</string>
    +@@ -264,7 +264,7 @@
    +     <string name="dessert_case" msgid="1295161776223959221">"デザートケース"</string>
    +     <string name="start_dreams" msgid="5640361424498338327">"スクリーン セーバー"</string>
    +     <string name="ethernet_label" msgid="7967563676324087464">"イーサネット"</string>
    +-    <string name="quick_settings_dnd_label" msgid="8735855737575028208">"通知を非表示"</string>
    ++    <string name="quick_settings_dnd_label" msgid="8735855737575028208">"マナーモード"</string>
    +     <string name="quick_settings_dnd_priority_label" msgid="483232950670692036">"優先する通知のみ"</string>
    +     <string name="quick_settings_dnd_alarms_label" msgid="2559229444312445858">"アラームのみ"</string>
    +     <string name="quick_settings_dnd_none_label" msgid="5025477807123029478">"サイレント"</string>
    +@@ -406,6 +406,7 @@
    +     <string name="device_owned_footer" msgid="3802752663326030053">"端末が監視されている可能性があります"</string>
    +     <string name="profile_owned_footer" msgid="8021888108553696069">"プロファイルが監視されている可能性があります"</string>
    +     <string name="vpn_footer" msgid="2388611096129106812">"ネットワークが監視されている可能性があります"</string>
    ++    <string name="branded_vpn_footer" msgid="2168111859226496230">"ネットワークが監視されている可能性があります"</string>
    +     <string name="monitoring_title_device_owned" msgid="7121079311903859610">"端末の監視"</string>
    +     <string name="monitoring_title_profile_owned" msgid="6790109874733501487">"プロファイルの監視"</string>
    +     <string name="monitoring_title" msgid="169206259253048106">"ネットワーク監視"</string>
    +@@ -418,6 +419,7 @@
    +     <string name="legacy_vpn_name" msgid="6604123105765737830">"VPN"</string>
    +     <string name="monitoring_description_app" msgid="6259179342284742878">"<xliff:g id="APPLICATION">%1$s</xliff:g>に接続しています。このアプリはあなたのネットワークアクティビティ(メール、アプリ、ウェブサイトなど)を監視できます。"</string>
    +     <string name="monitoring_description_app_personal" msgid="484599052118316268">"<xliff:g id="APPLICATION">%1$s</xliff:g>に接続しています。このアプリはあなたの個人のネットワークアクティビティ(メール、アプリ、ウェブサイトなど)を監視できます。"</string>
    ++    <string name="branded_monitoring_description_app_personal" msgid="2669518213949202599">"「<xliff:g id="APPLICATION">%1$s</xliff:g>」に接続しています。このアプリはあなたの個人のネットワーク アクティビティ(メール、アプリ、ウェブサイトなど)を監視できます。"</string>
    +     <string name="monitoring_description_app_work" msgid="1754325860918060897">"この仕事用プロファイルは<xliff:g id="ORGANIZATION">%1$s</xliff:g>によって管理され、<xliff:g id="APPLICATION">%2$s</xliff:g>に接続しています。このアプリはあなたの仕事のネットワークアクティビティ(メール、アプリ、ウェブサイトなど)を監視できます。\n\n詳しくは管理者にお問い合わせください。"</string>
    +     <string name="monitoring_description_app_personal_work" msgid="4946600443852045903">"この仕事用プロファイルは<xliff:g id="ORGANIZATION">%1$s</xliff:g>によって管理され、<xliff:g id="APPLICATION_WORK">%2$s</xliff:g>に接続しています。このアプリはあなたの仕事のネットワークアクティビティ(メール、アプリ、ウェブサイトなど)を監視できます。\n\n<xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g>にも接続しているため、個人のネットワークアクティビティも監視できます。"</string>
    +     <string name="monitoring_description_vpn_app_device_owned" msgid="4970443827043261703">"この端末は<xliff:g id="ORGANIZATION">%1$s</xliff:g>によって管理されています。\n\n管理者は設定、コーポレートアクセス、アプリ、端末に関連付けられたデータ、端末の位置情報を監視、管理できます。\n\n<xliff:g id="APPLICATION">%2$s</xliff:g>に接続しているため、このアプリもネットワークアクティビティ(メール、アプリ、ウェブサイトなど)を監視できます。\n\n詳しくは管理者にお問い合わせください。"</string>
    +@@ -494,8 +496,6 @@
    +     <string name="clock_seconds_desc" msgid="6282693067130470675">"ステータスバーに時計の秒を表示します。電池使用量に影響する可能性があります。"</string>
    +     <string name="qs_rearrange" msgid="8060918697551068765">"クイック設定を並べ替え"</string>
    +     <string name="show_brightness" msgid="6613930842805942519">"クイック設定に明るさ調整バーを表示する"</string>
    +-    <string name="overview_nav_bar_gesture" msgid="8579814204727917764">"上にスワイプして分割画面に切り替える操作を有効にする"</string>
    +-    <string name="overview_nav_bar_gesture_desc" msgid="6329167382305102615">"[概要] ボタンから上にスワイプして分割画面に切り替える操作を有効にします"</string>
    +     <string name="experimental" msgid="6198182315536726162">"試験運用版"</string>
    +     <string name="enable_bluetooth_title" msgid="5027037706500635269">"BluetoothをONにしますか?"</string>
    +     <string name="enable_bluetooth_message" msgid="9106595990708985385">"タブレットでキーボードに接続するには、最初にBluetoothをONにする必要があります。"</string>
    +@@ -572,9 +572,9 @@
    +     <string name="keyboard_shortcut_group_applications_youtube" msgid="6555453761294723317">"YouTube"</string>
    +     <string name="keyboard_shortcut_group_applications_calendar" msgid="9043614299194991263">"カレンダー"</string>
    +     <string name="tuner_full_zen_title" msgid="4540823317772234308">"音量調節を表示"</string>
    +-    <string name="volume_and_do_not_disturb" msgid="3373784330208603030">"通知の非表示"</string>
    ++    <string name="volume_and_do_not_disturb" msgid="3373784330208603030">"マナーモード"</string>
    +     <string name="volume_dnd_silent" msgid="4363882330723050727">"音量ボタンのショートカット"</string>
    +-    <string name="volume_up_silent" msgid="7141255269783588286">"音量上げボタンで [通知を非表示] を OFF にする"</string>
    ++    <string name="volume_up_silent" msgid="7141255269783588286">"音量上げボタンでマナーモードを OFF にする"</string>
    +     <string name="battery" msgid="7498329822413202973">"電池"</string>
    +     <string name="clock" msgid="7416090374234785905">"時計"</string>
    +     <string name="headset" msgid="4534219457597457353">"ヘッドセット"</string>
    +@@ -653,4 +653,5 @@
    +     <string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"<xliff:g id="ID_1">%s</xliff:g> の設定を開きます。"</string>
    +     <string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"設定の順序を編集します。"</string>
    +     <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"ページ <xliff:g id="ID_1">%1$d</xliff:g>/<xliff:g id="ID_2">%2$d</xliff:g>"</string>
    ++    <string name="cant_silence_or_block" msgid="999689262131488625">"通知のサイレント設定やブロックはできません"</string>
    + </resources>
    +diff --git a/packages/SystemUI/res/values-ka-rGE/strings.xml b/packages/SystemUI/res/values-ka-rGE/strings.xml
    +index 6ddcde8..258c904 100644
    +--- a/packages/SystemUI/res/values-ka-rGE/strings.xml
    ++++ b/packages/SystemUI/res/values-ka-rGE/strings.xml
    +@@ -238,7 +238,7 @@
    +     <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"4G მონაცემები შეჩერებულია"</string>
    +     <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"ფიჭური მონაცემები შეჩერებულია"</string>
    +     <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"მონაცემები შეჩერებულია"</string>
    +-    <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"რადგან თქვენი მონაცემების ლიმიტი ამოწურულია, მოწყობილობამ შეაჭერა მონაცემების გამოყენება დარჩენილი ციკლისათვის. \n\n შეჯამაბ შეიძლება გამოიწვიოს თქვენს პროვაიდერთან დამატებითი ხარჯები."</string>
    ++    <string name="data_usage_disabled_dialog" msgid="1841738975235283398">"მიღწეულია მონაცემთა მოხმარების თქვენ მიერ მითითებული ლიმიტი. ამიტომ, მობილური ინტერნეტის გამოყენება აღარ ხდება.\n\nგანახლების შემთხვევაში, შეიძლება მობილური ინტერნეტის საფასურის გადახდა მოგიწიოთ."</string>
    +     <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"გაგრძელება"</string>
    +     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"ინტერნეტ კავშირი არ არის"</string>
    +     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi დაკავშირებულია"</string>
    +@@ -404,6 +404,7 @@
    +     <string name="device_owned_footer" msgid="3802752663326030053">"შესაძლოა მოწყობილობის მონიტორინგი არ ხორციელდება"</string>
    +     <string name="profile_owned_footer" msgid="8021888108553696069">"შესაძლოა პროფილზე ხორციელდებოდეს მონიტორინგი"</string>
    +     <string name="vpn_footer" msgid="2388611096129106812">"შესაძლოა ქსელზე ხორციელდება მონიტორინგი"</string>
    ++    <string name="branded_vpn_footer" msgid="2168111859226496230">"ქსელზე შესაძლოა მონიტორინგი ხორციელდებოდეს"</string>
    +     <string name="monitoring_title_device_owned" msgid="7121079311903859610">"მოწყობილობის მონიტორინგი"</string>
    +     <string name="monitoring_title_profile_owned" msgid="6790109874733501487">"პროფილის მონიტორინგი"</string>
    +     <string name="monitoring_title" msgid="169206259253048106">"ქსელის მონიტორინგი"</string>
    +@@ -416,6 +417,7 @@
    +     <string name="legacy_vpn_name" msgid="6604123105765737830">"VPN"</string>
    +     <string name="monitoring_description_app" msgid="6259179342284742878">"თქვენ დაუკავშირდით <xliff:g id="APPLICATION">%1$s</xliff:g>-ს, რომელსაც შეუძლია თქვენი ქსელის აქტივობის, მათ შორის, ელფოსტის, აპებისა და ვებსაიტების მონიტორინგი."</string>
    +     <string name="monitoring_description_app_personal" msgid="484599052118316268">"თქვენ დაუკავშირდით <xliff:g id="APPLICATION">%1$s</xliff:g>-ს, რომელსაც შეუძლია თქვენი პირადი ქსელის აქტივობის, მათ შორის, ელფოსტის, აპებისა და ვებსაიტების მონიტორინგი."</string>
    ++    <string name="branded_monitoring_description_app_personal" msgid="2669518213949202599">"თქვენ დაუკავშირდით <xliff:g id="APPLICATION">%1$s</xliff:g>-ს, რომელსაც თქვენი პირადი ქსელის აქტივობის მონიტორინგი შეუძლია, მათ შორის, ელფოსტის, აპებისა და ვებსაიტების."</string>
    +     <string name="monitoring_description_app_work" msgid="1754325860918060897">"თქვენი სამუშაო პროფილი <xliff:g id="ORGANIZATION">%1$s</xliff:g>-ის მიერ იმართება. ის დაკავშირებულია <xliff:g id="APPLICATION">%2$s</xliff:g>-თან, რომელსაც შეუძლია თქვენი სამსახურის ქსელის აქტივობის, მათ შორის, ელფოსტის, აპებისა და ვებსაიტების მონიტორინგი.\n\nდამატებითი ინფორმაციისთვის მიმართეთ თქვენს ადმინისტრატორს."</string>
    +     <string name="monitoring_description_app_personal_work" msgid="4946600443852045903">"თქვენი სამუშაო პროფილი <xliff:g id="ORGANIZATION">%1$s</xliff:g>-ის მიერ იმართება. ის დაკავშირებულია <xliff:g id="APPLICATION_WORK">%2$s</xliff:g>-თან, რომელსაც შეუძლია თქვენი სამსახურის ქსელის აქტივობის, მათ შორის, ელფოსტის, აპებისა და ვებსაიტების მონიტორინგი.\n\nასევე, დაკავშირებული ხართ <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g>-თან, რომელსაც შეუძლია თქვენი პირადი ქსელის აქტივობის მონიტორინგი."</string>
    +     <string name="monitoring_description_vpn_app_device_owned" msgid="4970443827043261703">"თქვენს მოწყობილობას მართავს <xliff:g id="ORGANIZATION">%1$s</xliff:g>.\n\nადმინისტრატორს შეუძლია თქვენი მოწყობილობასთან ასოცირებული პარამეტრების, კორპორატიული წვდომის, აპებისა და მონაცემების, და ასევე მოწყობილობის მდებარეობის ინფორმაციის მონიტორინგი და მართვა.\n\nთქვენ დაკავშირებული ხართ <xliff:g id="APPLICATION">%2$s</xliff:g>-თან, რომელსაც შეუძლია თქვენი ქსელის აქტივობის, მათ შორის, ელფოსტის, აპებისა და ვებ-საიტების მონიტორინგი.\n\nდამატებითი ინფორმაციისათვის, დაუკავშირდით თქვენს ადმინისტრატორს."</string>
    +@@ -492,8 +494,6 @@
    +     <string name="clock_seconds_desc" msgid="6282693067130470675">"საათის წამების ჩვენება სტატუსის ზოლში. შეიძლება გავლენა იქონიოს ბატარეაზე."</string>
    +     <string name="qs_rearrange" msgid="8060918697551068765">"სწრაფი პარამეტრების გადაწყობა"</string>
    +     <string name="show_brightness" msgid="6613930842805942519">"სიკაშკაშის ჩვენება სწრაფ პარამეტრებში"</string>
    +-    <string name="overview_nav_bar_gesture" msgid="8579814204727917764">"ზემოთ გადაფურცვლისას ეკრანის გაყოფის ჟესტის ჩართვა"</string>
    +-    <string name="overview_nav_bar_gesture_desc" msgid="6329167382305102615">"მიმოხილვის ღილაკიდან ზემოთ გადაფურცვლისას ეკრანის გაყოფის რეჟიმზე გადასვლის ჟესტის ჩართვა"</string>
    +     <string name="experimental" msgid="6198182315536726162">"ექსპერიმენტული"</string>
    +     <string name="enable_bluetooth_title" msgid="5027037706500635269">"გსურთ Bluetooth-ის ჩართვა?"</string>
    +     <string name="enable_bluetooth_message" msgid="9106595990708985385">"კლავიატურის ტაბლეტთან დასაკავშირებლად, ჯერ უნდა ჩართოთ Bluetooth."</string>
    +@@ -651,4 +651,5 @@
    +     <string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"<xliff:g id="ID_1">%s</xliff:g> პარამეტრების გახსნა."</string>
    +     <string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"პარამეტრების მიმდევრობის რედაქტირება."</string>
    +     <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"გვერდი <xliff:g id="ID_1">%1$d</xliff:g> / <xliff:g id="ID_2">%2$d</xliff:g>-დან"</string>
    ++    <string name="cant_silence_or_block" msgid="999689262131488625">"შეტყობინებების გაჩუმება ან დაბლოკვა ვერ მოხერხდება"</string>
    + </resources>
    +diff --git a/packages/SystemUI/res/values-kk-rKZ/strings.xml b/packages/SystemUI/res/values-kk-rKZ/strings.xml
    +index 2c444e4..25ede61 100644
    +--- a/packages/SystemUI/res/values-kk-rKZ/strings.xml
    ++++ b/packages/SystemUI/res/values-kk-rKZ/strings.xml
    +@@ -238,7 +238,7 @@
    +     <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"4G деректері кідіртілді"</string>
    +     <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"Ұялы деректер кідіртілді"</string>
    +     <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"Деректер кідіртілді"</string>
    +-    <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"Орнатылған деректер шегіне жеткендіктен, құрылғы осы циклдың қалған бөлігі бойы деректерді пайдалануды кідіртті.\n\nЖалғастыру оператор ақыларына әкелуі мүмкін."</string>
    ++    <string name="data_usage_disabled_dialog" msgid="1841738975235283398">"Белгіленген деректер шегіне жеттіңіз. Ұялы деректер енді пайдаланылмайды.\n\nЕгер жалғастырсаңыз, деректер трафигі үшін ақы алынуы мүмкін."</string>
    +     <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"Жалғастыру"</string>
    +     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Интернет байланысы жоқ"</string>
    +     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi қосулы"</string>
    +@@ -404,6 +404,7 @@
    +     <string name="device_owned_footer" msgid="3802752663326030053">"Құрылғы бақылануы мүмкін"</string>
    +     <string name="profile_owned_footer" msgid="8021888108553696069">"Профиль бақылануы мүмкін"</string>
    +     <string name="vpn_footer" msgid="2388611096129106812">"Желі бақылауда болуы мүмкін"</string>
    ++    <string name="branded_vpn_footer" msgid="2168111859226496230">"Желі бақылауда болуы мүмкін"</string>
    +     <string name="monitoring_title_device_owned" msgid="7121079311903859610">"Құрылғыны бақылау"</string>
    +     <string name="monitoring_title_profile_owned" msgid="6790109874733501487">"Профильді бақылау"</string>
    +     <string name="monitoring_title" msgid="169206259253048106">"Желіні бақылау"</string>
    +@@ -416,6 +417,7 @@
    +     <string name="legacy_vpn_name" msgid="6604123105765737830">"VPN"</string>
    +     <string name="monitoring_description_app" msgid="6259179342284742878">"Сіз желідегі белсенділігіңізді, соның ішінде электрондық пошталарды, қолданбаларды және веб-сайттарды бақылай алатын <xliff:g id="APPLICATION">%1$s</xliff:g> қолданбасына қосылғансыз."</string>
    +     <string name="monitoring_description_app_personal" msgid="484599052118316268">"Сіз жеке желідегі белсенділігіңізді, соның ішінде электрондық пошталарды, қолданбаларды және веб-сайттарды бақылай алатын <xliff:g id="APPLICATION">%1$s</xliff:g> қолданбасына қосылғансыз."</string>
    ++    <string name="branded_monitoring_description_app_personal" msgid="2669518213949202599">"Жеке желідегі әрекеттеріңізді, соның ішінде электрондық пошта хабарларын, қолданбаларды және вебсайттарды бақылай алатын <xliff:g id="APPLICATION">%1$s</xliff:g> қолданбасына қосылғансыз."</string>
    +     <string name="monitoring_description_app_work" msgid="1754325860918060897">"Жұмыс профиліңізді <xliff:g id="ORGANIZATION">%1$s</xliff:g> басқарады. Ол жұмыс кезінде желідегі белсенділігіңізді, соның ішінде электрондық пошталарды, қолданбаларды және веб-сайттарды бақылай алатын <xliff:g id="APPLICATION">%2$s</xliff:g> қолданбасына қосылған.\n\nҚосымша ақпарат алу үшін әкімшіге хабарласыңыз."</string>
    +     <string name="monitoring_description_app_personal_work" msgid="4946600443852045903">"Жұмыс профиліңізді <xliff:g id="ORGANIZATION">%1$s</xliff:g> басқарады. Ол желідегі белсенділігіңізді, соның ішінде электрондық пошталарды, қолданбаларды және веб-сайттарды бақылай алатын <xliff:g id="APPLICATION_WORK">%2$s</xliff:g> қолданбасына қосылған.\n\nСондай-ақ сіз желідегі жеке белсенділігіңізді бақылай алатын <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g> қолданбасына қосылғансыз."</string>
    +     <string name="monitoring_description_vpn_app_device_owned" msgid="4970443827043261703">"Құрылғыңызды <xliff:g id="ORGANIZATION">%1$s</xliff:g> басқарады.\n\nӘкімші параметрлерді, корпоративтік рұқсатты, қолданбаларды, құрылғыңызбен байланысты деректерді және құрылғының орны туралы ақпаратты бақылай және басқара алады.\n\nСіз желідегі белсенділігіңізді, соның ішінде электрондық пошталарды, қолданбаларды және евб-сайттарды бақылай алатын <xliff:g id="APPLICATION">%2$s</xliff:g> қолданбасына қосылғансыз.\n\nҚосымша ақпарат алу үшін әкімшіге хабарласыңыз."</string>
    +@@ -492,8 +494,6 @@
    +     <string name="clock_seconds_desc" msgid="6282693067130470675">"Күйін көрсету жолағында сағат секундтарын көрсету. Батареяның қызмет көрсету мерзіміне әсер етуі мүмкін."</string>
    +     <string name="qs_rearrange" msgid="8060918697551068765">"Жылдам параметрлерді қайта реттеу"</string>
    +     <string name="show_brightness" msgid="6613930842805942519">"Жылдам параметрлерде жарықтықты көрсету"</string>
    +-    <string name="overview_nav_bar_gesture" msgid="8579814204727917764">"Бөлінген экранда жоғары қарай сырғыту қимылын қосу"</string>
    +-    <string name="overview_nav_bar_gesture_desc" msgid="6329167382305102615">"\"Шолу\" түймесінен жоғары қарай жанау арқылы бөлінген экранға кіру қимылын қосу"</string>
    +     <string name="experimental" msgid="6198182315536726162">"Эксперименттік"</string>
    +     <string name="enable_bluetooth_title" msgid="5027037706500635269">"Bluetooth функциясын қосу керек пе?"</string>
    +     <string name="enable_bluetooth_message" msgid="9106595990708985385">"Пернетақтаны планшетке қосу үшін алдымен Bluetooth функциясын қосу керек."</string>
    +@@ -651,4 +651,5 @@
    +     <string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"<xliff:g id="ID_1">%s</xliff:g> параметрлерін ашу."</string>
    +     <string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"Параметрлер тәртібін өзгерту."</string>
    +     <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"<xliff:g id="ID_2">%2$d</xliff:g> ішінен <xliff:g id="ID_1">%1$d</xliff:g>"</string>
    ++    <string name="cant_silence_or_block" msgid="999689262131488625">"Хабарландыруды үнсіз режимге қою не бөгеу мүмкін емес"</string>
    + </resources>
    +diff --git a/packages/SystemUI/res/values-km-rKH/strings.xml b/packages/SystemUI/res/values-km-rKH/strings.xml
    +index 0db7abc..f839eb6 100644
    +--- a/packages/SystemUI/res/values-km-rKH/strings.xml
    ++++ b/packages/SystemUI/res/values-km-rKH/strings.xml
    +@@ -238,7 +238,7 @@
    +     <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"ទិន្នន័យ 4G ត្រូវបានផ្អាក"</string>
    +     <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"ទិន្នន័យចល័តត្រូវបានផ្អាក"</string>
    +     <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"ទិន្នន័យត្រូវបានផ្អាក"</string>
    +-    <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"ដោយសារទិន្នន័យរបស់អ្នកបានឈានដល់កំណត់ ឧបករណ៍នេះបានផ្អាកការប្រើប្រាស់ទិន្នន័យសម្រាប់ការរំលឹកនៃវគ្គនេះ។\n\nការបន្តប្រើប្រាស់អាចនាំឲ្យមានការគិតប្រាក់ពីក្រុមហ៊ុនផ្តល់សេវាកម្ម។"</string>
    ++    <string name="data_usage_disabled_dialog" msgid="1841738975235283398">"បានឈានដល់កម្រិតទិន្នន័យដែលអ្នកបានកំណត់ហើយ។ ឥឡូវ​អ្នកមិនប្រើទិន្នន័យចល័តទៀតទេ។\n\nអាចនឹងគិតថ្លៃលើការប្រើទិន្នន័យ ប្រសិនបើអ្នកបន្តប្រើឡើងវិញ។"</string>
    +     <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"បន្ត"</string>
    +     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"គ្មាន​ការ​តភ្ជាប់​អ៊ីនធឺណិត"</string>
    +     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"បាន​ភ្ជាប់​វ៉ាយហ្វាយ"</string>
    +@@ -404,6 +404,7 @@
    +     <string name="device_owned_footer" msgid="3802752663326030053">"ឧបករណ៍​អាច​ត្រូវ​បាន​ត្រួតពិនិត្យ"</string>
    +     <string name="profile_owned_footer" msgid="8021888108553696069">"ប្រវត្តិរូបអាចត្រូវបានតាមដាន"</string>
    +     <string name="vpn_footer" msgid="2388611096129106812">"បណ្ដាញ​អាច​ត្រូវ​បាន​ត្រួតពិនិត្យ"</string>
    ++    <string name="branded_vpn_footer" msgid="2168111859226496230">"បណ្ដាញអាចត្រូវបានត្រួតពិនិត្យ"</string>
    +     <string name="monitoring_title_device_owned" msgid="7121079311903859610">"ការ​ត្រួតពិនិត្យ​ឧបករណ៍"</string>
    +     <string name="monitoring_title_profile_owned" msgid="6790109874733501487">"តាមដានប្រវត្ថិរូប"</string>
    +     <string name="monitoring_title" msgid="169206259253048106">"ការ​ត្រួតពិនិត្យ​បណ្ដាញ"</string>
    +@@ -416,6 +417,7 @@
    +     <string name="legacy_vpn_name" msgid="6604123105765737830">"VPN"</string>
    +     <string name="monitoring_description_app" msgid="6259179342284742878">"អ្នកត្រូវបានតភ្ជាប់ទៅ <xliff:g id="APPLICATION">%1$s</xliff:g> ដែលអាចឃ្លាំមើលសកម្មភាពបណ្តាញរបស់អ្នក រាប់បញ្ចូលទាំងអ៊ីមែល កម្មវិធី និងគេហទំព័រ។"</string>
    +     <string name="monitoring_description_app_personal" msgid="484599052118316268">"អ្នកត្រូវបានតភ្ជាប់ទៅ <xliff:g id="APPLICATION">%1$s</xliff:g> ដែលអាចឃ្លាំមើលសកម្មភាពបណ្តាញរបស់អ្នក រាប់បញ្ចូលទាំងអ៊ីមែល កម្មវិធី និងគេហទំព័រ។"</string>
    ++    <string name="branded_monitoring_description_app_personal" msgid="2669518213949202599">"អ្នកត្រូវបានភ្ជាប់ទៅ <xliff:g id="APPLICATION">%1$s</xliff:g> ដែលអាចឃ្លាំមើលសកម្មភាពបណ្តាញរបស់អ្នក រាប់បញ្ចូលទាំងអ៊ីមែល កម្មវិធី និងគេហទំព័រ។"</string>
    +     <string name="monitoring_description_app_work" msgid="1754325860918060897">"ប្រវត្តិរូបការងាររបស់អ្នកត្រូវបានគ្រប់គ្រងដោយ <xliff:g id="ORGANIZATION">%1$s</xliff:g>។ វាត្រូវបានតភ្ជាប់ទៅនឹង <xliff:g id="APPLICATION">%2$s</xliff:g> ដែលអាចឃ្លាំមើលសកម្មភាពបណ្តាញរបស់អ្នក រាប់បញ្ចូលទាំងអ៊ីមែល កម្មវិធី គេហទំព័រ។\n\nសម្រាប់ព័ត៌មានបន្ថែម សូមទាក់ទងអ្នកគ្រប់គ្រប់របស់អ្នក។"</string>
    +     <string name="monitoring_description_app_personal_work" msgid="4946600443852045903">"ប្រវត្តិរូបការងាររបស់អ្នកត្រូវបានគ្រប់គ្រងដោយ <xliff:g id="ORGANIZATION">%1$s</xliff:g>។ វាត្រូវបានតភ្ជាប់ទៅនឹង <xliff:g id="APPLICATION_WORK">%2$s</xliff:g> ដែលអាចឃ្លាំមើលសកម្មភាពបណ្តាញរបស់អ្នក រាប់បញ្ចូលទាំងអ៊ីមែល កម្មវិធី គេហទំព័រ។\n\nអ្នកក៏ត្រូវបានតភ្ជាប់ផងដែរទៅនឹង <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g> ដែលអាចឃ្លាំមើលសកម្មភាពបណ្តាញផ្ទាល់ខ្លួនរបស់អ្នក។"</string>
    +     <string name="monitoring_description_vpn_app_device_owned" msgid="4970443827043261703">"ឧបករណ៍របស់អ្នកត្រូវបានគ្រប់គ្រងដោយ <xliff:g id="ORGANIZATION">%1$s</xliff:g>.\n\nអ្នកគ្រប់គ្រងរបស់អ្នកអាចឃ្លាំមើល និងគ្រប់គ្រងការកំណត់ ការចូលប្រើជាក្រុម កម្មវិធី ទិន្នន័យដែលជាប់ទាក់ទងនឹងឧបករណ៍របស់អ្នក និងព័ត៌មានទីតាំងនៃឧបករណ៍របស់អ្នក។\n\nអ្នកត្រូវបានភ្ជាប់ជាមួយ <xliff:g id="APPLICATION">%2$s</xliff:g> ដែលវាអាចឃ្លាំមើលសកម្មភាពបណ្តាញរបស់អ្នក រួមបញ្ចូលទាំងអ៊ីមែល កម្មវិធី និងគេហទំព័រ។\n\nសម្រាប់ព័ត៌មានបន្ថែម សូមទាក់ទងអ្នកគ្រប់គ្រងរបស់អ្នក។"</string>
    +@@ -492,8 +494,6 @@
    +     <string name="clock_seconds_desc" msgid="6282693067130470675">"បង្ហាញវិនាទីនៅលើរបារស្ថានភាពអាចនឹងប៉ះពាល់ដល់ថាមពលថ្ម។"</string>
    +     <string name="qs_rearrange" msgid="8060918697551068765">"រៀបចំការកំណត់រហ័សឡើងវិញ"</string>
    +     <string name="show_brightness" msgid="6613930842805942519">"បង្ហាញកម្រិតពន្លឺនៅក្នុងការកំណត់រហ័ស"</string>
    +-    <string name="overview_nav_bar_gesture" msgid="8579814204727917764">"បើកដំណើរការកាយវិការអូសទៅលើដើម្បីបំបែកអេក្រង់"</string>
    +-    <string name="overview_nav_bar_gesture_desc" msgid="6329167382305102615">"បើកដំណើរការកាយវិការដើម្បីបំបែកអេក្រង់ដោយអូសទៅលើចាប់ពីប៊ូតុងទិដ្ឋភាព"</string>
    +     <string name="experimental" msgid="6198182315536726162">"ពិសោធន៍"</string>
    +     <string name="enable_bluetooth_title" msgid="5027037706500635269">"បើកប៊្លូធូសឬ?"</string>
    +     <string name="enable_bluetooth_message" msgid="9106595990708985385">"ដើម្បីភ្ជាប់ក្តារចុចរបស់អ្នកជាមួយនឹងថេប្លេតរបស់អ្នក អ្នកត្រូវតែបើកប៊្លូធូសជាមុនសិន។"</string>
    +@@ -651,4 +651,5 @@
    +     <string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"បើការកំណត់ <xliff:g id="ID_1">%s</xliff:g>"</string>
    +     <string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"កែលំដាប់ការកំណត់"</string>
    +     <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"ទំព័រ <xliff:g id="ID_1">%1$d</xliff:g> នៃ <xliff:g id="ID_2">%2$d</xliff:g>"</string>
    ++    <string name="cant_silence_or_block" msgid="999689262131488625">"ការជូនដំណឹងមិនអាចបិទសំឡេង ឬរារាំងបានទេ"</string>
    + </resources>
    +diff --git a/packages/SystemUI/res/values-kn-rIN/strings.xml b/packages/SystemUI/res/values-kn-rIN/strings.xml
    +index c62a8db..8d9b2dd 100644
    +--- a/packages/SystemUI/res/values-kn-rIN/strings.xml
    ++++ b/packages/SystemUI/res/values-kn-rIN/strings.xml
    +@@ -84,7 +84,7 @@
    +     <string name="accessibility_home" msgid="8217216074895377641">"ಮುಖಪುಟ"</string>
    +     <string name="accessibility_menu" msgid="316839303324695949">"ಮೆನು"</string>
    +     <string name="accessibility_recent" msgid="5208608566793607626">"ಸಮಗ್ರ ನೋಟ"</string>
    +-    <string name="accessibility_search_light" msgid="1103867596330271848">"ಹುಡುಕು"</string>
    ++    <string name="accessibility_search_light" msgid="1103867596330271848">"ಹುಡುಕಿ"</string>
    +     <string name="accessibility_camera_button" msgid="8064671582820358152">"ಕ್ಯಾಮರಾ"</string>
    +     <string name="accessibility_phone_button" msgid="6738112589538563574">"ಫೋನ್"</string>
    +     <string name="accessibility_voice_assist_button" msgid="487611083884852965">"ಧ್ವನಿ ಸಹಾಯಕ"</string>
    +@@ -238,7 +238,7 @@
    +     <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"4G ಡೇಟಾ ವಿರಾಮಗೊಳಿಸಲಾಗಿದೆ"</string>
    +     <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"ಸೆಲ್ಯುಲಾರ್ ಡೇಟಾ ವಿರಾಮಗೊಳಿಸಲಾಗಿದೆ"</string>
    +     <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"ಡೇಟಾ ವಿರಾಮಗೊಳಿಸಲಾಗಿದೆ"</string>
    +-    <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"ಏಕೆಂದರೆ ನಿಮ್ಮ ಹೊಂದಾಣಿಕೆ ಡೇಟಾ ಮೀತಿಯನ್ನು ತಲುಪಿದೆ, ಈ ಆವರ್ತನೆಯ ಉಳಿದ ಭಾಗಕ್ಕೆ ಸಾಧನವು ಡೇಟಾ ಬಳಕೆಯನ್ನು ವಿರಾಮಗೊಳಿಸಿದೆ.\n\nಮುಂದುವರೆಯುವಿಕೆಯು ನಿಮ್ಮ ವಾಹಕದ ಶುಲ್ಕಗಳಿಗೆ ಕಾರಣವಾಗಬಹುದು."</string>
    ++    <string name="data_usage_disabled_dialog" msgid="1841738975235283398">"ನೀವು ಹೊಂದಿಸಿರುವ ಡೇಟಾ ಮಿತಿ ತಲುಪಿದೆ. ನೀವು ಎಂದಿಗೂ ಸೆಲ್ಯುಲಾರ್ ಡೇಟಾವನ್ನು ಬಳಸದೆ ಇರಬಹುದು.\n\nನೀವು ಮುಂದುವರಿಸಿದರೆ, ಡೇಟಾ ಬಳಕೆಗೆ ಶುಲ್ಕಗಳು ಅನ್ವಯವಾಗಬಹುದು."</string>
    +     <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"ಮುಂದುವರಿಸು"</string>
    +     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"ಇಂಟರ್ನೆಟ್ ಸಂಪರ್ಕವಿಲ್ಲ"</string>
    +     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"ವೈ-ಫೈ ಸಂಪರ್ಕಗೊಂಡಿದೆ"</string>
    +@@ -404,6 +404,7 @@
    +     <string name="device_owned_footer" msgid="3802752663326030053">"ಸಾಧನವನ್ನು ಪರಿವೀಕ್ಷಿಸಬಹುದಾಗಿದೆ"</string>
    +     <string name="profile_owned_footer" msgid="8021888108553696069">"ಪ್ರೊಫೈಲ್ ಅನ್ನು ಪರಿವೀಕ್ಷಿಸಬಹುದಾಗಿದೆ"</string>
    +     <string name="vpn_footer" msgid="2388611096129106812">"ನೆಟ್‌ವರ್ಕ್ ಅನ್ನು ವೀಕ್ಷಿಸಬಹುದಾಗಿ"</string>
    ++    <string name="branded_vpn_footer" msgid="2168111859226496230">"ನೆಟ್‌ವರ್ಕ್ ಅನ್ನು ವೀಕ್ಷಿಸಬಹುದಾಗಿರುತ್ತದೆ"</string>
    +     <string name="monitoring_title_device_owned" msgid="7121079311903859610">"ಸಾಧನ ಪರಿವೀಕ್ಷಣೆ"</string>
    +     <string name="monitoring_title_profile_owned" msgid="6790109874733501487">"ಪ್ರೊಫೈಲ್ ಮೇಲ್ವಿಚಾರಣೆ"</string>
    +     <string name="monitoring_title" msgid="169206259253048106">"ನೆಟ್‌ವರ್ಕ್‌ ಪರಿವೀಕ್ಷಣೆ"</string>
    +@@ -416,6 +417,7 @@
    +     <string name="legacy_vpn_name" msgid="6604123105765737830">"VPN"</string>
    +     <string name="monitoring_description_app" msgid="6259179342284742878">"ನೀವು ಇಮೇಲ್‌ಗಳು, ಅಪ್ಲಿಕೇಶನ್‌ಗಳು ಮತ್ತು ವೆಬ್‌ಸೈಟ್‌ಗಳನ್ನು ಒಳಗೊಂಡಂತೆ ನಿಮ್ಮ ನೆಟ್‌ವರ್ಕ್ ಚಟುವಟಿಕೆಯ ಮೇಲ್ವಿಚಾರಣೆ ಮಾಡಬಹುದಾದ <xliff:g id="APPLICATION">%1$s</xliff:g> ಗೆ ಸಂಪರ್ಕಗೊಂಡಿರುವಿರಿ."</string>
    +     <string name="monitoring_description_app_personal" msgid="484599052118316268">"ನೀವು ಇಮೇಲ್‌ಗಳು, ಅಪ್ಲಿಕೇಶನ್‌ಗಳು ಮತ್ತು ವೆಬ್‌ಸೈಟ್‌ಗಳು ಸೇರಿದಂತೆ ನಿಮ್ಮ ವೈಯಕ್ತಿಕ ನೆಟ್‌ವರ್ಕ್ ಚಟುವಟಿಕೆಯ ಮೇಲ್ವಿಚಾರಣೆ ಮಾಡಬಹುದಾದ <xliff:g id="APPLICATION">%1$s</xliff:g> ಗೆ ಸಂಪರ್ಕಗೊಂಡಿರುವಿರಿ."</string>
    ++    <string name="branded_monitoring_description_app_personal" msgid="2669518213949202599">"ನೀವು ಇಮೇಲ್‌ಗಳು, ಅಪ್ಲಿಕೇಶನ್‌ಗಳು, ಮತ್ತು ವೆಬ್‌ಸೈಟ್‌ಗಳನ್ನು ಒಳಗೊಂಡಂತೆ ನಿಮ್ಮ ವೈಯಕ್ತಿಕ ನೆಟ್‌ವರ್ಕ್ ಚಟುವಟಿಕೆಯ ಮೇಲ್ವಿಚಾರಣೆ ಮಾಡಬಹುದಾದ <xliff:g id="APPLICATION">%1$s</xliff:g> ಗೆ ಸಂಪರ್ಕಗೊಂಡಿರುವಿರಿ."</string>
    +     <string name="monitoring_description_app_work" msgid="1754325860918060897">"ನಿಮ್ಮ ಕೆಲಸದ ಪ್ರೊಫೈಲ್‌ ಅನ್ನು <xliff:g id="ORGANIZATION">%1$s</xliff:g> ಮೂಲಕ ನಿರ್ವಹಿಸಲಾಗುತ್ತಿದೆ. ಇದು ಇಮೇಲ್‌ಗಳು, ಅಪ್ಲಿಕೇಶನ್‌ಗಳು, ಮತ್ತು ವೆಬ್‌ಸೈಟ್‌ಗಳನ್ನು ಒಳಗೊಂಡಂತೆ ನಿಮ್ಮ ಕೆಲಸದ ನೆಟ್‌ವರ್ಕ್ ಚಟುವಟಿಕೆಯ ಮೇಲ್ವಿಚಾರಣೆ ಮಾಡಬಹುದಾದ <xliff:g id="APPLICATION">%2$s</xliff:g> ಗೆ ಸಂಪರ್ಕಗೊಂಡಿದೆ.\n\nಹೆಚ್ಚಿನ ಮಾಹಿತಿಗಾಗಿ, ನಿಮ್ಮ ನಿರ್ವಾಹಕರನ್ನು ಸಂಪರ್ಕಿಸಿ."</string>
    +     <string name="monitoring_description_app_personal_work" msgid="4946600443852045903">"ನಿಮ್ಮ ಕೆಲಸದ ಪ್ರೊಫೈಲ್‌ ಅನ್ನು <xliff:g id="ORGANIZATION">%1$s</xliff:g> ಮೂಲಕ ನಿರ್ವಹಿಸಲಾಗುತ್ತಿದೆ. ಇದು ಇಮೇಲ್‌ಗಳು, ಅಪ್ಲಿಕೇಶನ್‌ಗಳು, ಮತ್ತು ವೆಬ್‌ಸೈಟ್‌ಗಳನ್ನು ಒಳಗೊಂಡಂತೆ ನಿಮ್ಮ ಕೆಲಸದ ನೆಟ್‌ವರ್ಕ್ ಚಟುವಟಿಕೆಯ ಮೇಲ್ವಿಚಾರಣೆ ಮಾಡಬಹುದಾದ <xliff:g id="APPLICATION_WORK">%2$s</xliff:g> ಗೆ ಸಂಪರ್ಕಿತಗೊಂಡಿದೆ.\n\nನೀವು ಕೂಡಾ ವೈಯಕ್ತಿಕ ನೆಟ್‌ವರ್ಕ್ ಚಟುವಟಿಕೆಯ ಮೇಲ್ವಿಚಾರಣೆ ಮಾಡಬಹುದಾದ <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g> ಗೆ ಸಂಪರ್ಕಿತಗೊಂಡಿರುವಿರಿ."</string>
    +     <string name="monitoring_description_vpn_app_device_owned" msgid="4970443827043261703">"ನಿಮ್ಮ ಸಾಧನವನ್ನು <xliff:g id="ORGANIZATION">%1$s</xliff:g> ಮೂಲಕ ನಿರ್ವಹಿಸಲಾಗುತ್ತಿದೆ.\n\nನಿಮ್ಮ ನಿರ್ವಾಹಕರು ಸೆಟ್ಟಿಂಗ್‌ಗಳು, ಕಾರ್ಪೊರೇಟ್ ಪ್ರವೇಶ, ಅಪ್ಲಿಕೇಶನ್‌ಗಳು ಹಾಗೂ ನಿಮ್ಮ ಸಾಧನದೊಂದಿಗೆ ಸಂಬಂಧಿಸಿದ ಡೇಟಾ ಮತ್ತು ನಿಮ್ಮ ಸಾಧನದ ಸ್ಥಳ ಮಾಹಿತಿಯನ್ನು ಮೇಲ್ವಿಚಾರಣೆ ಮಾಡಬಹುದು ಮತ್ತು ನಿರ್ವಹಿಸಬಹುದು.\n\nಇಮೇಲ್‌ಗಳು, ಅಪ್ಲಿಕೇಶನ್‌ಗಳು ಮತ್ತು ವೆಬ್‌ಸೈಟ್‌ಗಳನ್ನು ಒಳಗೊಂಡಂತೆ ನಿಮ್ಮ ನೆಟ್‌ವರ್ಕ್ ಚಟುವಟಿಕೆಯನ್ನು ಮೇಲ್ವಿಚಾರಣೆ ಮಾಡಬಹುದಾದ <xliff:g id="APPLICATION">%2$s</xliff:g> ಗೆ ಸಂಪರ್ಕಿತಗೊಂಡಿರುವಿರಿ.\n\nಹೆಚ್ಚಿನ ಮಾಹಿತಿಗಾಗಿ, ನಿಮ್ಮ ನಿರ್ವಾಹಕರನ್ನು ಸಂಪರ್ಕಿಸಿ."</string>
    +@@ -492,8 +494,6 @@
    +     <string name="clock_seconds_desc" msgid="6282693067130470675">"ಸ್ಥಿತಿ ಪಟ್ಟಿಯಲ್ಲಿ ಗಡಿಯಾರ ಸೆಕೆಂಡುಗಳನ್ನು ತೋರಿಸು. ಇದಕ್ಕೆ ಬ್ಯಾಟರಿ ಬಾಳಿಕೆಯು ಪರಿಣಾಮಬೀರಬಹುದು."</string>
    +     <string name="qs_rearrange" msgid="8060918697551068765">"ತ್ವರಿತ ಸೆಟ್ಟಿಂಗ್‌‌ಗಳನ್ನು ಮರುಹೊಂದಿಸಿ"</string>
    +     <string name="show_brightness" msgid="6613930842805942519">"ತ್ವರಿತ ಸೆಟ್ಟಿಂಗ್‌‌ಗಳಲ್ಲಿ ಪ್ರಖರತೆಯನ್ನು ತೋರಿಸಿ"</string>
    +-    <string name="overview_nav_bar_gesture" msgid="8579814204727917764">"ಸ್ಪ್ಲಿಟ್-ಸ್ಕ್ರೀನ್ ಸ್ವೈಪ್-ಅಪ್ ಗೆಶ್ಚರ್ ಸಕ್ರಿಯಗೊಳಿಸಿ"</string>
    +-    <string name="overview_nav_bar_gesture_desc" msgid="6329167382305102615">"ಸಮಗ್ರ ನೋಟದ ಬಟನ್‌ನಿಂದ ಮೇಲಕ್ಕೆ ಸ್ವೈಪ್ ಮಾಡಿ ಸ್ಪ್ಲಿಟ್‌-ಸ್ಕ್ರೀನ್ ನಮೂದಿಸಲು ಗೆಸ್ಚರ್‌ ಸಕ್ರಿಯಗೊಳಿಸಿ"</string>
    +     <string name="experimental" msgid="6198182315536726162">"ಪ್ರಾಯೋಗಿಕ"</string>
    +     <string name="enable_bluetooth_title" msgid="5027037706500635269">"ಬ್ಲೂಟೂತ್ ಆನ್ ಮಾಡುವುದೇ?"</string>
    +     <string name="enable_bluetooth_message" msgid="9106595990708985385">"ನಿಮ್ಮ ಕೀಬೋರ್ಡ್ ಅನ್ನು ಟ್ಯಾಬ್ಲೆಟ್‌ಗೆ ಸಂಪರ್ಕಿಸಲು, ನೀವು ಮೊದಲು ಬ್ಲೂಟೂತ್ ಆನ್ ಮಾಡಬೇಕಾಗುತ್ತದೆ."</string>
    +@@ -593,8 +593,8 @@
    +     <string name="add_button" msgid="4134946063432258161">"ಬಟನ್ ಸೇರಿಸು"</string>
    +     <string name="save" msgid="2311877285724540644">"ಉಳಿಸು"</string>
    +     <string name="reset" msgid="2448168080964209908">"ಮರುಹೊಂದಿಸು"</string>
    +-    <string name="no_home_title" msgid="1563808595146071549">"ಯಾವುದೇ ಹೋಮ್ ಬಟನ್ ಕಂಡುಬಂದಿಲ್ಲ"</string>
    +-    <string name="no_home_message" msgid="5408485011659260911">"ಈ ಸಾಧನವನ್ನು ನ್ಯಾವಿಗೇಟ್ ಮಾಡಲು ಹೋಮ್ ಬಟನ್ ಅಗತ್ಯವಿರುತ್ತದೆ. ಉಳಿಸುವ ಮೊದಲು ದಯವಿಟ್ಟು ಹೋಮ್ ಬಟನ್ ಸೇರಿಸಿ."</string>
    ++    <string name="no_home_title" msgid="1563808595146071549">"ಯಾವುದೇ ಮುಖಪುಟ ಬಟನ್ ಕಂಡುಬಂದಿಲ್ಲ"</string>
    ++    <string name="no_home_message" msgid="5408485011659260911">"ಈ ಸಾಧನವನ್ನು ನ್ಯಾವಿಗೇಟ್ ಮಾಡಲು ಮುಖಪುಟ ಬಟನ್ ಅಗತ್ಯವಿರುತ್ತದೆ. ಉಳಿಸುವ ಮೊದಲು ದಯವಿಟ್ಟು ಮುಖಪುಟ ಬಟನ್ ಸೇರಿಸಿ."</string>
    +     <string name="adjust_button_width" msgid="6138616087197632947">"ಬಟನ್ ಅಳತೆ ಹೊಂದಿಸು"</string>
    +     <string name="clipboard" msgid="1313879395099896312">"ಕ್ಲಿಪ್‌ಬೋರ್ಡ್"</string>
    +     <string name="clipboard_description" msgid="3819919243940546364">"ಐಟಂಗಳನ್ನು ನೇರವಾಗಿ ಕ್ಲಿಪ್‌ಬೋರ್ಡ್‌ಗೆ ಡ್ರ್ಯಾಗ್ ಮಾಡಲು ಕ್ಲಿಪ್‌ಬೋರ್ಡ್ ಅನುಮತಿಸುತ್ತದೆ. ಐಟಂಗಳು ಅಸ್ತಿತ್ವದಲ್ಲಿರುವಾಗ ಅವುಗಳನ್ನು ಕ್ಲಿಪ್‌ಬೋರ್ಡ್‌ನಿಂದ ನೇರವಾಗಿ ಹೊರಗೆ ಹಾಕಬಹುದಾಗಿರುತ್ತದೆ."</string>
    +@@ -651,4 +651,5 @@
    +     <string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"<xliff:g id="ID_1">%s</xliff:g> ಸೆಟ್ಟಿಂಗ್‌ಗಳನ್ನು ತೆರೆಯಿರಿ."</string>
    +     <string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"ಸೆಟ್ಟಿಂಗ್‌ಗಳ ಕ್ರಮವನ್ನು ಎಡಿಟ್ ಮಾಡಿ."</string>
    +     <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"<xliff:g id="ID_2">%2$d</xliff:g> ರಲ್ಲಿ <xliff:g id="ID_1">%1$d</xliff:g> ಪುಟ"</string>
    ++    <string name="cant_silence_or_block" msgid="999689262131488625">"ಸೂಚನೆಗಳನ್ನು ಮೌನವಾಗಿಸಲಾಗುವುದಿಲ್ಲ ಅಥವಾ ತಡೆಹಿಡಿಯಲಾಗುವುದಿಲ್ಲ"</string>
    + </resources>
    +diff --git a/packages/SystemUI/res/values-kn-rIN/strings_tv.xml b/packages/SystemUI/res/values-kn-rIN/strings_tv.xml
    +index 5afb322..edaa8e6 100644
    +--- a/packages/SystemUI/res/values-kn-rIN/strings_tv.xml
    ++++ b/packages/SystemUI/res/values-kn-rIN/strings_tv.xml
    +@@ -25,7 +25,7 @@
    +     <string name="pip_pause" msgid="8412075640017218862">"ವಿರಾಮ"</string>
    +     <string name="pip_hold_home" msgid="340086535668778109">"PIP ನಿಯಂತ್ರಿಸಲು "<b>"HOME"</b>" ಕೀಯನ್ನು ಹಿಡಿದುಕೊಳ್ಳಿ"</string>
    +     <string name="pip_onboarding_title" msgid="7850436557670253991">"ಚಿತ್ರದಲ್ಲಿ ಚಿತ್ರ"</string>
    +-    <string name="pip_onboarding_description" msgid="4028124563309465267">"ನೀವು ಮತ್ತೊಂದನ್ನು ಪ್ಲೇ ಮಾಡುವ ತನಕ ಇದು ನಿಮ್ಮ ವೀಡಿಯೋವನ್ನು ವೀಕ್ಷಣೆಯಲ್ಲಿರಿಸುತ್ತದೆ. ಅದನ್ನು ನಿಯಂತ್ರಿಸಲು "<b>"ಹೋಮ್"</b>" ಅನ್ನು ಒತ್ತಿ ಹಿಡಿಯಿರಿ."</string>
    ++    <string name="pip_onboarding_description" msgid="4028124563309465267">"ನೀವು ಮತ್ತೊಂದನ್ನು ಪ್ಲೇ ಮಾಡುವ ತನಕ ಇದು ನಿಮ್ಮ ವೀಡಿಯೋವನ್ನು ವೀಕ್ಷಣೆಯಲ್ಲಿರಿಸುತ್ತದೆ. ಅದನ್ನು ನಿಯಂತ್ರಿಸಲು "<b>"ಮುಖಪುಟ"</b>" ಅನ್ನು ಒತ್ತಿ ಹಿಡಿಯಿರಿ."</string>
    +     <string name="pip_onboarding_button" msgid="3957426748484904611">"ಅರ್ಥವಾಯಿತು"</string>
    +     <string name="recents_tv_dismiss" msgid="3555093879593377731">"ವಜಾಗೊಳಿಸಿ"</string>
    +   <string-array name="recents_tv_blacklist_array">
    +diff --git a/packages/SystemUI/res/values-ko/strings.xml b/packages/SystemUI/res/values-ko/strings.xml
    +index 3c08e92..b3f121c 100644
    +--- a/packages/SystemUI/res/values-ko/strings.xml
    ++++ b/packages/SystemUI/res/values-ko/strings.xml
    +@@ -240,7 +240,7 @@
    +     <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"4G 데이터 사용 중지됨"</string>
    +     <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"모바일 데이터 사용 중지됨"</string>
    +     <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"데이터 사용 중지됨"</string>
    +-    <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"설정된 데이터 한도에 도달했기 때문에 기기에서 사이클의 나머지 기간 동안 데이터 사용을 일시 중지했습니다. \n\n데이터 사용을 재개하면 이동통신사 요금이 청구될 수 있습니다."</string>
    ++    <string name="data_usage_disabled_dialog" msgid="1841738975235283398">"설정한 데이터 한도에 도달했습니다. 더 이상 모바일 데이터를 사용하지 않습니다.\n\n계속 사용하면 데이터 사용 요금이 부과될 수 있습니다."</string>
    +     <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"재개"</string>
    +     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"인터넷에 연결되지 않음"</string>
    +     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi 연결됨"</string>
    +@@ -406,6 +406,7 @@
    +     <string name="device_owned_footer" msgid="3802752663326030053">"기기가 모니터링될 수 있음"</string>
    +     <string name="profile_owned_footer" msgid="8021888108553696069">"프로필이 모니터링될 수 있음"</string>
    +     <string name="vpn_footer" msgid="2388611096129106812">"네트워크가 모니터링될 수 있음"</string>
    ++    <string name="branded_vpn_footer" msgid="2168111859226496230">"네트워크가 모니터링될 수 있음"</string>
    +     <string name="monitoring_title_device_owned" msgid="7121079311903859610">"기기 모니터링"</string>
    +     <string name="monitoring_title_profile_owned" msgid="6790109874733501487">"프로필 모니터링"</string>
    +     <string name="monitoring_title" msgid="169206259253048106">"네트워크 모니터링"</string>
    +@@ -418,6 +419,7 @@
    +     <string name="legacy_vpn_name" msgid="6604123105765737830">"VPN"</string>
    +     <string name="monitoring_description_app" msgid="6259179342284742878">"<xliff:g id="APPLICATION">%1$s</xliff:g>에 연결되었습니다. 이 앱은 이메일, 앱, 웹사이트와 같은 내 네트워크 활동을 모니터링할 수 있습니다."</string>
    +     <string name="monitoring_description_app_personal" msgid="484599052118316268">"<xliff:g id="APPLICATION">%1$s</xliff:g>에 연결되었습니다. 이 앱은 이메일, 앱, 웹사이트와 같은 내 네트워크 활동을 모니터링할 수 있습니다."</string>
    ++    <string name="branded_monitoring_description_app_personal" msgid="2669518213949202599">"<xliff:g id="APPLICATION">%1$s</xliff:g>에 연결되었습니다. 이 앱은 이메일, 앱, 웹사이트와 같은 내 개인 네트워크 활동을 모니터링할 수 있습니다."</string>
    +     <string name="monitoring_description_app_work" msgid="1754325860918060897">"직장 프로필은 <xliff:g id="ORGANIZATION">%1$s</xliff:g>에서 관리합니다. 이는 <xliff:g id="APPLICATION">%2$s</xliff:g>에 연결되어 있으며 여기에서 이메일, 앱, 웹사이트와 같은 직장 네트워크 활동을 모니터링할 수 있습니다.\n\n자세한 내용은 관리자에게 문의하세요."</string>
    +     <string name="monitoring_description_app_personal_work" msgid="4946600443852045903">"직장 프로필은 <xliff:g id="ORGANIZATION">%1$s</xliff:g>에서 관리합니다. 이는 <xliff:g id="APPLICATION_WORK">%2$s</xliff:g>에 연결되어 있으며 여기에서 이메일, 앱, 웹사이트와 같은 직장 네트워크 활동을 모니터링할 수 있습니다.\n\n또한 <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g>에 연결되어 있으며, 여기에서 내 개인 네트워크 활동을 모니터링할 수 있습니다."</string>
    +     <string name="monitoring_description_vpn_app_device_owned" msgid="4970443827043261703">"<xliff:g id="ORGANIZATION">%1$s</xliff:g>에서 기기를 관리합니다.\n\n관리자는 설정, 기업 액세스, 앱, 기기와 연결된 데이터, 기기의 위치 정보를 모니터링하고 관리할 수 있습니다.\n\n<xliff:g id="APPLICATION">%2$s</xliff:g>에 연결되어 있으며 여기에서 이메일, 앱, 웹사이트와 같은 내 네트워크 활동을 모니터링할 수 있습니다.\n\n자세한 내용은 관리자에게 문의하세요."</string>
    +@@ -465,7 +467,7 @@
    +     <string name="show_battery_percentage_summary" msgid="3215025775576786037">"충전 중이 아닌 경우 상태 표시줄 아이콘 내에 배터리 잔량 비율 표시"</string>
    +     <string name="quick_settings" msgid="10042998191725428">"빠른 설정"</string>
    +     <string name="status_bar" msgid="4877645476959324760">"상태 표시줄"</string>
    +-    <string name="overview" msgid="4018602013895926956">"개요"</string>
    ++    <string name="overview" msgid="4018602013895926956">"최근 사용"</string>
    +     <string name="demo_mode" msgid="2389163018533514619">"데모 모드"</string>
    +     <string name="enable_demo_mode" msgid="4844205668718636518">"데모 모드 사용"</string>
    +     <string name="show_demo_mode" msgid="2018336697782464029">"데모 모드 표시"</string>
    +@@ -494,8 +496,6 @@
    +     <string name="clock_seconds_desc" msgid="6282693067130470675">"상태 표시줄에 시계 초 단위를 표시합니다. 배터리 수명에 영향을 줄 수도 있습니다."</string>
    +     <string name="qs_rearrange" msgid="8060918697551068765">"빠른 설정 재정렬"</string>
    +     <string name="show_brightness" msgid="6613930842805942519">"빠른 설정에서 밝기 표시"</string>
    +-    <string name="overview_nav_bar_gesture" msgid="8579814204727917764">"화면 분할 위로 스와이프 동작 사용"</string>
    +-    <string name="overview_nav_bar_gesture_desc" msgid="6329167382305102615">"최근 사용 버튼에서 위로 스와이프하기 동작으로 창 분할 모드를 사용 설정합니다."</string>
    +     <string name="experimental" msgid="6198182315536726162">"베타"</string>
    +     <string name="enable_bluetooth_title" msgid="5027037706500635269">"블루투스를 켜시겠습니까?"</string>
    +     <string name="enable_bluetooth_message" msgid="9106595990708985385">"키보드를 태블릿에 연결하려면 먼저 블루투스를 켜야 합니다."</string>
    +@@ -653,4 +653,5 @@
    +     <string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"<xliff:g id="ID_1">%s</xliff:g> 설정 열기"</string>
    +     <string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"설정 순서 수정"</string>
    +     <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"<xliff:g id="ID_2">%2$d</xliff:g>페이지 중 <xliff:g id="ID_1">%1$d</xliff:g>페이지"</string>
    ++    <string name="cant_silence_or_block" msgid="999689262131488625">"알림을 무음으로 설정하거나 차단할 수 없습니다."</string>
    + </resources>
    +diff --git a/packages/SystemUI/res/values-ky-rKG/strings.xml b/packages/SystemUI/res/values-ky-rKG/strings.xml
    +index 7645b93..cb404cb 100644
    +--- a/packages/SystemUI/res/values-ky-rKG/strings.xml
    ++++ b/packages/SystemUI/res/values-ky-rKG/strings.xml
    +@@ -238,7 +238,7 @@
    +     <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"4G дайындары тындырылды"</string>
    +     <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"Уюлдук дайындар тындырылды"</string>
    +     <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"Дайындар тындырылды"</string>
    +-    <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"Киргизиле турган дайындар белгиленген эң жогорку чекке жеткендиктен, ушул мерчимдин калган бөлүгүндө түзмөгүңүздө дайындардын колдонулушу тындырылды.\n\nУлантсаңыз, байланыш операторуңузга акы төлөп калышыңыз мүмкүн."</string>
    ++    <string name="data_usage_disabled_dialog" msgid="1841738975235283398">"Трафик сиз койгон чекке жетти. Эми мобилдик дайындарды колдоно албайсыз.\n\nЭгер улантсаңыз, мобилдик дайындарды колдонгонуңуз үчүн акы алынышы мүмкүн."</string>
    +     <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"Улантуу"</string>
    +     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Интернет байланыш жок"</string>
    +     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi байланышта"</string>
    +@@ -404,6 +404,7 @@
    +     <string name="device_owned_footer" msgid="3802752663326030053">"Түзмөктү көзөмөлдөсө болот"</string>
    +     <string name="profile_owned_footer" msgid="8021888108553696069">"Профилди көзөмөлдөсө болот"</string>
    +     <string name="vpn_footer" msgid="2388611096129106812">"Тармак көзөмөлдөнүшү мүмкүн"</string>
    ++    <string name="branded_vpn_footer" msgid="2168111859226496230">"Тармак көзөмөлдөнүшү мүмкүн"</string>
    +     <string name="monitoring_title_device_owned" msgid="7121079311903859610">"Түзмөккө көз салуу"</string>
    +     <string name="monitoring_title_profile_owned" msgid="6790109874733501487">"Профилди көзөмөлдөө"</string>
    +     <string name="monitoring_title" msgid="169206259253048106">"Тармакка көз салуу"</string>
    +@@ -416,6 +417,7 @@
    +     <string name="legacy_vpn_name" msgid="6604123105765737830">"VPN"</string>
    +     <string name="monitoring_description_app" msgid="6259179342284742878">"Электрондук почта, колдонмолор жана вебсайттар сыяктуу тармактык аракеттерди көзөмөлдөй турган <xliff:g id="APPLICATION">%1$s</xliff:g> колдонмосуна туташып турасыз."</string>
    +     <string name="monitoring_description_app_personal" msgid="484599052118316268">"Электрондук почта, колдонмолор жана вебсайттар сыяктуу тармактагы жеке аракеттериңизди көзөмөлдөй турган <xliff:g id="APPLICATION">%1$s</xliff:g> колдонмосуна туташып турасыз."</string>
    ++    <string name="branded_monitoring_description_app_personal" msgid="2669518213949202599">"Электрондук почта, колдонмолор жана вебсайттар сыяктуу тармактагы жеке аракеттериңизди тескей турган <xliff:g id="APPLICATION">%1$s</xliff:g> колдонмосуна туташып турасыз."</string>
    +     <string name="monitoring_description_app_work" msgid="1754325860918060897">"Жумуш профилиңизди <xliff:g id="ORGANIZATION">%1$s</xliff:g> башкарат. Ал электрондук почта, колдонмолор жана вебсайттар сыяктуу жумуш тармагыңыздагы аракеттерди көзөмөлдөй турган <xliff:g id="APPLICATION">%2$s</xliff:g> менен туташкан.\n\nКөбүрөөк маалымат алуу үчүн администраторуңузга кайрылыңыз."</string>
    +     <string name="monitoring_description_app_personal_work" msgid="4946600443852045903">"Жумуш профилиңизди <xliff:g id="ORGANIZATION">%1$s</xliff:g> башкарат. Ал электрондук почта, колдонмолор жана вебсайттар сыяктуу жумуш тармагыңыздагы аракеттерди көзөмөлдөй турган <xliff:g id="APPLICATION_WORK">%2$s</xliff:g> менен туташкан.\n\nМындан тышкары, тармактагы жеке аракеттериңизди көзөмөлдөгөн <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g> колдонмосуна туташып турасыз."</string>
    +     <string name="monitoring_description_vpn_app_device_owned" msgid="4970443827043261703">"Түзмөгүңүздү <xliff:g id="ORGANIZATION">%1$s</xliff:g> башкарат.\nАдминистраторуңуз түзмөгүңүздөгү жөндөөлөрдү, корпоративдик мүмкүнчүлүктү, колдонмолорду, дайындарды, ошону менен катар жайгашкан жер дайындарын башкарып, тийиштүү маалыматты карай алат.\n\nСиз электрондук почталар, колдонмолор жана вебсайттар сыяктуу тармактагы аракеттериңизди тармактагы аракетиңизди тескей турган APPLICATION колдонмосуна туташып турасыз.\n<xliff:g id="APPLICATION">%2$s</xliff:g>Көбүрөөк маалымат алуу үчүн, администраторуңузга кайрылыңыз.\n\n"</string>
    +@@ -492,8 +494,6 @@
    +     <string name="clock_seconds_desc" msgid="6282693067130470675">"Абал тилкесинен сааттын секунддары көрсөтүлсүн. Батареянын кубаты көбүрөөк сарпталышы мүмкүн."</string>
    +     <string name="qs_rearrange" msgid="8060918697551068765">"Ыкчам жөндөөлөрдү кайра коюу"</string>
    +     <string name="show_brightness" msgid="6613930842805942519">"Ыкчам жөндөөлөрдөн жарык деңгээлин көрсөтүү"</string>
    +-    <string name="overview_nav_bar_gesture" msgid="8579814204727917764">"Өйдө серпип экранды бөлүү жаңсоосун иштетүү"</string>
    +-    <string name="overview_nav_bar_gesture_desc" msgid="6329167382305102615">"Сереп баскычынан өйдө серпип, экранды бөлүү режимин киргизүү үчүн жаңсоону иштетиңиз"</string>
    +     <string name="experimental" msgid="6198182315536726162">"Сынамык"</string>
    +     <string name="enable_bluetooth_title" msgid="5027037706500635269">"Bluetooth күйгүзүлсүнбү?"</string>
    +     <string name="enable_bluetooth_message" msgid="9106595990708985385">"Баскычтобуңузду планшетиңизге туташтыруу үчүн, адегенде Bluetooth\'ту күйгүзүшүңүз керек."</string>
    +@@ -651,4 +651,5 @@
    +     <string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"<xliff:g id="ID_1">%s</xliff:g> жөндөөлөрүн ачуу."</string>
    +     <string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"Жөндөөлөрдүн иретин өзгөртүү."</string>
    +     <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"<xliff:g id="ID_2">%2$d</xliff:g> ичинен <xliff:g id="ID_1">%1$d</xliff:g>-бет"</string>
    ++    <string name="cant_silence_or_block" msgid="999689262131488625">"Эскертмелердин үнүн басууга же бөгөттөөгө болбойт"</string>
    + </resources>
    +diff --git a/packages/SystemUI/res/values-lo-rLA/strings.xml b/packages/SystemUI/res/values-lo-rLA/strings.xml
    +index 6b1fca8..76350cc 100644
    +--- a/packages/SystemUI/res/values-lo-rLA/strings.xml
    ++++ b/packages/SystemUI/res/values-lo-rLA/strings.xml
    +@@ -238,7 +238,7 @@
    +     <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"ຂໍ້​ມູນ 4G ຢຸດ​ຊົ່ວ​ຄາວແລ້ວ"</string>
    +     <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"ຂໍ້​ມູນເຊວ​ລູ​ລາຢຸດ​ຊົ່ວ​ຄາວແລ້ວ"</string>
    +     <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"ຂໍ້​ມູນ​ຢຸດ​ຊົ່ວ​ຄາວແລ້ວ"</string>
    +-    <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"ເນື່ອງ​ຈາກວ່າ​ຮອດ​ຂີດ​ຈຳ​ກັດ​ຂໍ້​ມູນ​ທີ່​ຕັ້ງ​ໄວ້​ຂອ​ງ​ທ່ານ​ແລ້ວ, ອຸ​ປະ​ກອນ​ຢຸດ​ການ​ນຳ​ໃຊ້​ຂໍ້​ມູນ​ສຳ​ລັບ​ສ່ວນ​ທີ່​ຍັງ​ເຫຼືອ​ຂອງ​ຮອບ​ວຽນ​ນີ້.\n\nການ​ເລີ່ມ​ຕໍ່​ອາດ​ຈະ​ນຳ​ໄປ​ສູ່​ການ​ປ່ຽນ​ແປງ​ຈາກ​ຜູ້​ໃຫ້​ບໍ​ລິ​ການ​ເຄືອ​ຂ່າຍ​ຂອງ​ທ່ານ."</string>
    ++    <string name="data_usage_disabled_dialog" msgid="1841738975235283398">"ທ່ານໃຊ້ອິນເຕີເນັດຮອດຈຳນວນທີ່ທ່ານຈຳກັດປະລິມານໄວ້ແລ້ວ. ທ່ານຈະບໍ່ນຳໃຊ້ການເຊື່ອມຕໍ່ຜ່ານເຄືອຂ່າຍມືຖືອີກຕໍ່ໄປ.\n\nຫາກທ່ານສືບຕໍ່ໃຊ້ໄປອີກ, ທ່ານອາດຖືກຮຽກເກັບເງິນຄ່າບໍລິການໄດ້."</string>
    +     <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"ເລີ່ມຕໍ່"</string>
    +     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"ບໍ່ມີການເຊື່ອມຕໍ່ອິນເຕີເນັດ"</string>
    +     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"ເຊື່ອມ​ຕໍ່ Wi-​-Fi ແລ້ວ"</string>
    +@@ -404,6 +404,7 @@
    +     <string name="device_owned_footer" msgid="3802752663326030053">"ອຸ​ປະ​ກອນ​ອາດ​ມີ​ການ​ເຝົ້າ​ຕິດ​ຕາມ"</string>
    +     <string name="profile_owned_footer" msgid="8021888108553696069">"ໂປຣ​ໄຟລ໌​ອາດ​ຖືກ​ເຝົ້າ​ຕິດ​ຕາມ​ຢູ່"</string>
    +     <string name="vpn_footer" msgid="2388611096129106812">"​ເຄືອ​ຂ່າຍ​ອາດ​ມີ​ການ​ເຝົ້າ​ຕິດ​ຕາມ"</string>
    ++    <string name="branded_vpn_footer" msgid="2168111859226496230">"ການນຳໃຊ້ເຄືອຂ່າຍອາດມີການກວດສອບຕິດຕາມ"</string>
    +     <string name="monitoring_title_device_owned" msgid="7121079311903859610">"ການກວດ​ສອບ​ຕິດ​ຕາມ​ອຸ​ປະ​ກອນ"</string>
    +     <string name="monitoring_title_profile_owned" msgid="6790109874733501487">"ການ​ຕິດ​ຕາມ​ໂປຣ​ໄຟລ໌"</string>
    +     <string name="monitoring_title" msgid="169206259253048106">"ການກວດ​ສອບ​ຕິດ​ຕາມ​ເຄືອ​ຂ່າຍ"</string>
    +@@ -416,6 +417,7 @@
    +     <string name="legacy_vpn_name" msgid="6604123105765737830">"VPN"</string>
    +     <string name="monitoring_description_app" msgid="6259179342284742878">"ທ່ານເຊື່ອມຕໍ່ກັບ <xliff:g id="APPLICATION">%1$s</xliff:g>, ເຊິ່ງສາມາດຕິດຕາມການເຄື່ອນໄຫວເຄືອຂ່າຍຂອງທ່ານ ລວມທັງອີເມວ, ​ແອັບ ແລະເວັບໄຊທ໌."</string>
    +     <string name="monitoring_description_app_personal" msgid="484599052118316268">"ທ່ານເຊື່ອມຕໍ່ກັບ <xliff:g id="APPLICATION">%1$s</xliff:g>, ເຊິ່ງສາມາດຕິດຕາມການເຄື່ອນໄຫວເຄືອຂ່າຍສ່ວນຕົວຂອງທ່ານ ລວມທັງອີເມວ, ​ແອັບ ແລະເວັບໄຊທ໌."</string>
    ++    <string name="branded_monitoring_description_app_personal" msgid="2669518213949202599">"ທ່ານເຊື່ອມຕໍ່ກັບ <xliff:g id="APPLICATION">%1$s</xliff:g> ແລ້ວ, ເຊິ່ງສາມາດຕິດຕາມການເຄື່ອນໄຫວເຄືອຂ່າຍສ່ວນຕົວຂອງທ່ານ ຮວມທັງອີເມວ, ​ແອັບ ແລະເວັບໄຊໄດ້."</string>
    +     <string name="monitoring_description_app_work" msgid="1754325860918060897">"ໂປຣໄຟລ໌ບ່ອນເຮັດວຽກຂອງທ່ານຖືກຄວບຄຸມໂດຍ <xliff:g id="ORGANIZATION">%1$s</xliff:g>. ມັນຖືກເຊື່ອມຕໍ່ກັບ <xliff:g id="APPLICATION">%2$s</xliff:g>, ເຊິ່ງສາມາດຕິດຕາມການເຄື່ອນໄຫວເຄືອຂ່າຍບ່ອນເຮັດວຽກຂອງທ່ານ ລວມທັງອີເມວ,​ ແອັບ ແລະເວັບໄຊທ໌.\n\nສຳລັບຂໍ້ມູນເພີ່ມເຕີມ, ໃຫ້ຕິດຕໍ່ຜູ້ບໍລິຫານຂອງທ່ານ."</string>
    +     <string name="monitoring_description_app_personal_work" msgid="4946600443852045903">"ໂປຣໄຟລ໌ບ່ອນເຮັດວຽກຂອງທ່ານຖືກຈັດການໂດຍ <xliff:g id="ORGANIZATION">%1$s</xliff:g>. ມັນເຊື່ອມຕໍ່ກັບ <xliff:g id="APPLICATION_WORK">%2$s</xliff:g>, ເຊິ່ງສາມາດຕິດຕາມການເຄື່ອນໄຫວເຄືອຂ່າຍບ່ອນເຮັດວຽກຂອງທ່ານ ລວມທັງອີເມວ, ແອັບ ແລະເວັບໄຊທ໌.\n\nທ່ານເຊື່ອມຕໍ່ກັບ <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g>, ເຊິ່ງສາມາດຕິດຕາມການເຄື່ອນໄຫວເຄືອຂ່າຍສ່ວນຕົວຂອງທ່ານ."</string>
    +     <string name="monitoring_description_vpn_app_device_owned" msgid="4970443827043261703">"ອຸ​ປະ​ກອນ​ຂອງ​ທ່ານ​ຖືກ​ຄຸ້ມ​ຄອງ​ໂດຍ <xliff:g id="ORGANIZATION">%1$s</xliff:g>.\n\nຜູ້​ຄວບ​ຄຸມຂອງ​ທ່ານ​ສາ​ມາດ​ຕິດ​ຕາມ​ກວດ​ກາ ​ແລະ​ການ​ຄຸ້ມ​ຄອງ​ການຕັ້ງ​ຄ່າ, ແອັບ​ການ​ເຂົ້າ​ຫາ​ບໍ​ລິ​ສັດ, ຂໍ້​ມູນ​ທີ່​ກ່ຽວ​ຂ້ອງ​ກັບ​ອຸ​ປະ​ກອນ​ຂອງ​ທ່ານ, ແລະ​ຂໍ້​ມູນທີ່​ຕັ້ງ​ຂອງອຸ​ປະ​ກອນ​ຂອງ​ທ່ານ.\n\nທ່ານ​ເຊື່ອມ​ຕໍ່​ກັບ <xliff:g id="APPLICATION">%2$s</xliff:g> ແລ້ວ, ເຊິ່ງ​ສາ​ມາດ​ຕິດ​ຕາມການ​ເຄື່ອນ​ໄຫວ​ເຄືອ​ຂ່າຍ​ຂອງ​ທ່ານ, ລວມ​ທັງ​ອີ​ເມວ, ແອັບ, ແລະ​ເວັບ​ໄຊ​ທ໌.\n\nສຳ​ລັບ​ຂໍ້​ມູນ​ເພີ່ມ​ເຕີມ, ຕິດ​ຕໍ່​ຜູ້​ຄວບ​ຄຸມ​ຂອງ​ທ່ານ."</string>
    +@@ -492,8 +494,6 @@
    +     <string name="clock_seconds_desc" msgid="6282693067130470675">"ສະ​ແດງວິ​ນາ​ທີ​ໂມງ​ຢູ່​ໃນ​ແຖບ​ສະ​ຖາ​ນະ. ອາດ​ຈະ​ມີ​ຜົນ​ກະ​ທົບ​ຕໍ່​ອາ​ຍຸ​ແບັດ​ເຕີ​ຣີ."</string>
    +     <string name="qs_rearrange" msgid="8060918697551068765">"ຈັດ​ວາງ​ການ​ຕັ້ງ​ຄ່າ​ດ່ວນ​ຄືນ​ໃໝ່"</string>
    +     <string name="show_brightness" msgid="6613930842805942519">"ສະ​ແດງ​ຄວາມ​ແຈ້ງ​ຢູ່​ໃນ​ການ​ຕັ້ງ​ຄ່າ​ດ່ວນ"</string>
    +-    <string name="overview_nav_bar_gesture" msgid="8579814204727917764">"ເປີດໃຊ້ທ່າທາງການປັດຂຶ້ນເພື່ອເຂົ້າສູ່ໜ້າຈໍແບບແຍກກັນ"</string>
    +-    <string name="overview_nav_bar_gesture_desc" msgid="6329167382305102615">"ເປີດໃຊ້ທ່າທາງເພື່ອເຂົ້າສູ່ໜ້າຈໍແບບແຍກກັນ ໂດຍການປັດຂຶ້ນຈາກປຸ່ມພາບຮວມ"</string>
    +     <string name="experimental" msgid="6198182315536726162">"ຍັງຢູ່ໃນການທົດລອງ"</string>
    +     <string name="enable_bluetooth_title" msgid="5027037706500635269">"ເປີດ​ໃຊ້ Bluetooth ບໍ່?"</string>
    +     <string name="enable_bluetooth_message" msgid="9106595990708985385">"ເພື່ອ​ເຊື່ອມ​ຕໍ່​ແປ້ນ​ພິມ​ຂອງ​ທ່ານ​ກັບ​ແທັບ​ເລັດ​ຂອງ​ທ່ານ, ກ່ອນ​ອື່ນ​ໝົດ​ທ່ານ​ຕ້ອງ​ເປີດ Bluetooth."</string>
    +@@ -651,4 +651,5 @@
    +     <string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"ເປີດການຕັ້ງຄ່າ <xliff:g id="ID_1">%s</xliff:g>."</string>
    +     <string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"ແກ້ໄຂລຳດັບການຕັ້ງຄ່າ."</string>
    +     <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"<xliff:g id="ID_1">%1$d</xliff:g> ຈາກທັງໝົດ <xliff:g id="ID_2">%2$d</xliff:g>"</string>
    ++    <string name="cant_silence_or_block" msgid="999689262131488625">"ບໍ່ສາມາດປິດສຽງ ຫຼື ບລັອກການແຈ້ງເຕືອນໄດ້"</string>
    + </resources>
    +diff --git a/packages/SystemUI/res/values-lt/strings.xml b/packages/SystemUI/res/values-lt/strings.xml
    +index 46e50fb..480d88a 100644
    +--- a/packages/SystemUI/res/values-lt/strings.xml
    ++++ b/packages/SystemUI/res/values-lt/strings.xml
    +@@ -240,7 +240,7 @@
    +     <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"4G duomenys pristabdyti"</string>
    +     <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"Korinio ryšio duomenys pristabdyti"</string>
    +     <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"Duomenys pristabdyti"</string>
    +-    <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"Kadangi buvo pasiektas nustatytas duomenų limitas, įrenginys pristabdė duomenų naudojimą likusį šio ciklo laikotarpį.\n\nAtnaujinus gali būti taikomi operatoriaus mokesčiai."</string>
    ++    <string name="data_usage_disabled_dialog" msgid="1841738975235283398">"Pasiektas nustatytas duomenų apribojimas. Nebenaudojate mobiliojo ryšio duomenų.\n\nJei atnaujinsite, gali būti taikomi mokesčiai už duomenų naudojimą."</string>
    +     <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"Atnaujinti"</string>
    +     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Nėra interneto ryš."</string>
    +     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Prisij. prie „Wi-Fi“"</string>
    +@@ -275,10 +275,10 @@
    +     <string name="quick_settings_bluetooth_off_label" msgid="8159652146149219937">"„Bluetooth“ išjungta"</string>
    +     <string name="quick_settings_bluetooth_detail_empty_text" msgid="4910015762433302860">"Nėra pasiekiamų susietų įrenginių"</string>
    +     <string name="quick_settings_brightness_label" msgid="6968372297018755815">"Šviesumas"</string>
    +-    <string name="quick_settings_rotation_unlocked_label" msgid="7305323031808150099">"Automatinis kaitaliojimas"</string>
    ++    <string name="quick_settings_rotation_unlocked_label" msgid="7305323031808150099">"Automatinis pasukimas"</string>
    +     <string name="accessibility_quick_settings_rotation" msgid="4231661040698488779">"Automatiškai sukti ekraną"</string>
    +     <string name="accessibility_quick_settings_rotation_value" msgid="1428962304214992318">"Nustatyti kaip <xliff:g id="ID_1">%s</xliff:g>"</string>
    +-    <string name="quick_settings_rotation_locked_label" msgid="6359205706154282377">"Kaitaliojimas užrakintas"</string>
    ++    <string name="quick_settings_rotation_locked_label" msgid="6359205706154282377">"Pasukimas užrakintas"</string>
    +     <string name="quick_settings_rotation_locked_portrait_label" msgid="5102691921442135053">"Stačias"</string>
    +     <string name="quick_settings_rotation_locked_landscape_label" msgid="8553157770061178719">"Gulsčias"</string>
    +     <string name="quick_settings_ime_label" msgid="7073463064369468429">"Įvesties metodas"</string>
    +@@ -408,6 +408,7 @@
    +     <string name="device_owned_footer" msgid="3802752663326030053">"Įrenginys gali būti stebimas"</string>
    +     <string name="profile_owned_footer" msgid="8021888108553696069">"Profilis gali būti stebimas"</string>
    +     <string name="vpn_footer" msgid="2388611096129106812">"Tinklas gali būti stebimas"</string>
    ++    <string name="branded_vpn_footer" msgid="2168111859226496230">"Tinklas gali būti stebimas"</string>
    +     <string name="monitoring_title_device_owned" msgid="7121079311903859610">"Įrenginio stebėjimas"</string>
    +     <string name="monitoring_title_profile_owned" msgid="6790109874733501487">"Profilio stebėjimas"</string>
    +     <string name="monitoring_title" msgid="169206259253048106">"Tinklo stebėjimas"</string>
    +@@ -420,6 +421,7 @@
    +     <string name="legacy_vpn_name" msgid="6604123105765737830">"VPN"</string>
    +     <string name="monitoring_description_app" msgid="6259179342284742878">"Esate prisijungę prie programos „<xliff:g id="APPLICATION">%1$s</xliff:g>“, kuri gali stebėti tinklo veiklą, įskaitant el. laiškus, programas ir svetaines."</string>
    +     <string name="monitoring_description_app_personal" msgid="484599052118316268">"Esate prisijungę prie programos „<xliff:g id="APPLICATION">%1$s</xliff:g>“, kuri gali stebėti asmeninio profilio tinklo veiklą, įskaitant el. laiškus, programas ir svetaines."</string>
    ++    <string name="branded_monitoring_description_app_personal" msgid="2669518213949202599">"Esate prisijungę prie programos „<xliff:g id="APPLICATION">%1$s</xliff:g>“, kuri gali stebėti asmeninio tinklo veiklą, įskaitant el. laiškus, programas ir svetaines."</string>
    +     <string name="monitoring_description_app_work" msgid="1754325860918060897">"Darbo profilį tvarko „<xliff:g id="ORGANIZATION">%1$s</xliff:g>“. Jis susietas su programa „<xliff:g id="APPLICATION">%2$s</xliff:g>“, kuri gali stebėti darbo profilio tinklo veiklą, įskaitant el. laiškus, programas ir svetaines.\n\nDaugiau informacijos galite gauti susisiekę su administratoriumi."</string>
    +     <string name="monitoring_description_app_personal_work" msgid="4946600443852045903">"Darbo profilį tvarko „<xliff:g id="ORGANIZATION">%1$s</xliff:g>“. Jis susietas su programa „<xliff:g id="APPLICATION_WORK">%2$s</xliff:g>“, kuri gali stebėti darbo profilio tinklo veiklą, įskaitant el. laiškus, programas ir svetaines.\n\nTaip pat esate prisijungę prie programos „<xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g>“, kuri gali stebėti asmeninio profilio tinklo veiklą."</string>
    +     <string name="monitoring_description_vpn_app_device_owned" msgid="4970443827043261703">"Jūsų įrenginį tvarko „<xliff:g id="ORGANIZATION">%1$s</xliff:g>“.\n\nAdministratorius gali stebėti ir tvarkyti nustatymus, įmonės informacijos pasiekiamumo nustatymus, programas, su įrenginiu susietus duomenis ir įrenginio vietovės informaciją.\n\nEsate prisijungę prie programos „<xliff:g id="APPLICATION">%2$s</xliff:g>“, kuri gali stebėti tinklo veiklą, įskaitant el. laiškus, programas ir svetaines.\n\nDaugiau informacijos galite gauti susisiekę su administratoriumi."</string>
    +@@ -496,8 +498,6 @@
    +     <string name="clock_seconds_desc" msgid="6282693067130470675">"Rodyti laikrodžio sekundes būsenos juostoje. Tai gali paveikti akumuliatoriaus naudojimo laiką."</string>
    +     <string name="qs_rearrange" msgid="8060918697551068765">"Pertvarkyti sparčiuosius nustatymus"</string>
    +     <string name="show_brightness" msgid="6613930842805942519">"Rodyti skaistį sparčiuosiuose nustatymuose"</string>
    +-    <string name="overview_nav_bar_gesture" msgid="8579814204727917764">"Įgalinti ekrano skaidymo perbraukimo aukštyn gestą"</string>
    +-    <string name="overview_nav_bar_gesture_desc" msgid="6329167382305102615">"Įgalinti gestą, kuriuo galima įjungti skaidytą ekraną, perbraukiant aukštyn nuo apžvalgos mygtuko"</string>
    +     <string name="experimental" msgid="6198182315536726162">"Eksperimentinė versija"</string>
    +     <string name="enable_bluetooth_title" msgid="5027037706500635269">"Įjungti „Bluetooth“?"</string>
    +     <string name="enable_bluetooth_message" msgid="9106595990708985385">"Kad galėtumėte prijungti klaviatūrą prie planšetinio kompiuterio, pirmiausia turite įjungti „Bluetooth“."</string>
    +@@ -655,4 +655,5 @@
    +     <string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"Atidaryti „<xliff:g id="ID_1">%s</xliff:g>“ nustatymus."</string>
    +     <string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"Redaguoti nustatymų tvarką."</string>
    +     <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"<xliff:g id="ID_1">%1$d</xliff:g> psl. iš <xliff:g id="ID_2">%2$d</xliff:g>"</string>
    ++    <string name="cant_silence_or_block" msgid="999689262131488625">"Pranešimų negalima nutildyti arba užblokuoti"</string>
    + </resources>
    +diff --git a/packages/SystemUI/res/values-lv/strings.xml b/packages/SystemUI/res/values-lv/strings.xml
    +index 9efad2e..564a29c 100644
    +--- a/packages/SystemUI/res/values-lv/strings.xml
    ++++ b/packages/SystemUI/res/values-lv/strings.xml
    +@@ -239,7 +239,7 @@
    +     <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"4G datu lietojums ir apturēts"</string>
    +     <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"Mobilo datu lietojums ir apturēts"</string>
    +     <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"Datu lietojums ir apturēts"</string>
    +-    <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"Tika sasniegts iestatītais datu lietojuma ierobežojums, tādēļ ierīcē ir apturēts datu lietojums cikla atlikušajā periodā.\n\nJa atsāksiet lietot datus, iespējams, jūsu mobilo sakaru operators iekasēs maksu."</string>
    ++    <string name="data_usage_disabled_dialog" msgid="1841738975235283398">"Ir sasniegts jūsu iestatītais datu ierobežojums. Jūs vairs neizmantojat mobilos datus.\n\nJa atsāksiet, var tikt piemērota maksa par datu lietojumu."</string>
    +     <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"Atsākt"</string>
    +     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Nav interneta sav."</string>
    +     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Izv. sav. ar Wi-Fi"</string>
    +@@ -406,6 +406,7 @@
    +     <string name="device_owned_footer" msgid="3802752663326030053">"Ierīci var pārraudzīt"</string>
    +     <string name="profile_owned_footer" msgid="8021888108553696069">"Profilu var pārraudzīt"</string>
    +     <string name="vpn_footer" msgid="2388611096129106812">"Iespējams, tīklā veiktās darbības tiek pārraudzītas."</string>
    ++    <string name="branded_vpn_footer" msgid="2168111859226496230">"Var tikt pārraudzītas tīklā veiktās darbības."</string>
    +     <string name="monitoring_title_device_owned" msgid="7121079311903859610">"Ierīces pārraudzība"</string>
    +     <string name="monitoring_title_profile_owned" msgid="6790109874733501487">"Profila pārraudzība"</string>
    +     <string name="monitoring_title" msgid="169206259253048106">"Tīkla pārraudzība"</string>
    +@@ -418,6 +419,7 @@
    +     <string name="legacy_vpn_name" msgid="6604123105765737830">"VPN"</string>
    +     <string name="monitoring_description_app" msgid="6259179342284742878">"Ir izveidots savienojums ar lietotni <xliff:g id="APPLICATION">%1$s</xliff:g>, kura var pārraudzīt jūsu tīklā veiktās darbības, tostarp e-pasta ziņojumus, lietotnes un vietnes."</string>
    +     <string name="monitoring_description_app_personal" msgid="484599052118316268">"Ir izveidots savienojums ar lietotni <xliff:g id="APPLICATION">%1$s</xliff:g>, kura var pārraudzīt jūsu tīklā veiktās privātās darbības, tostarp e-pasta ziņojumus, lietotnes un vietnes."</string>
    ++    <string name="branded_monitoring_description_app_personal" msgid="2669518213949202599">"Ir izveidots savienojums ar lietotni <xliff:g id="APPLICATION">%1$s</xliff:g>, kas var pārraudzīt jūsu tīklā veiktās privātās darbības, tostarp e-pasta ziņojumus, lietotnes un vietnes."</string>
    +     <string name="monitoring_description_app_work" msgid="1754325860918060897">"Jūsu darba profilu pārvalda <xliff:g id="ORGANIZATION">%1$s</xliff:g>. Tas ir saistīts ar lietojumprogrammu <xliff:g id="APPLICATION">%2$s</xliff:g>, kura var pārraudzīt jūsu tīklā veiktās darbības, tostarp e-pasta ziņojumus, lietotnes un vietnes.\n\nLai iegūtu plašāku informāciju, sazinieties ar administratoru."</string>
    +     <string name="monitoring_description_app_personal_work" msgid="4946600443852045903">"Jūsu darba profilu pārvalda <xliff:g id="ORGANIZATION">%1$s</xliff:g>. Tas ir saistīts ar lietojumprogrammu <xliff:g id="APPLICATION_WORK">%2$s</xliff:g>, kura var pārraudzīt jūsu tīklā veiktās darbības, tostarp e-pasta ziņojumus, lietotnes un vietnes.\n\nIr piesaistīta arī lietojumprogramma <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g>, kas var pārraudzīt jūsu tīklā veiktās privātās darbības."</string>
    +     <string name="monitoring_description_vpn_app_device_owned" msgid="4970443827043261703">"Jūsu ierīci pārvalda <xliff:g id="ORGANIZATION">%1$s</xliff:g>.\n\nJūsu administrators var pārraudzīt un pārvaldīt iestatījumus, korporatīvo piekļuvi, lietotnes un datus, kas ir saistīti ar šo ierīci, kā arī informāciju par jūsu ierīces atrašanās vietu.\n\nIr piesaistīta lietojumprogramma <xliff:g id="APPLICATION">%2$s</xliff:g>, kas var pārraudzīt jūsu tīklā veiktās darbības, tostarp e-pasta ziņojumus, lietotnes un vietnes.\n\nLai iegūtu plašāku informāciju, sazinieties ar administratoru."</string>
    +@@ -494,8 +496,6 @@
    +     <string name="clock_seconds_desc" msgid="6282693067130470675">"Statusa joslā rādīt pulksteņa sekundes. Var ietekmēt akumulatora darbības laiku."</string>
    +     <string name="qs_rearrange" msgid="8060918697551068765">"Pārkārtot ātros iestatījumus"</string>
    +     <string name="show_brightness" msgid="6613930842805942519">"Rādīt spilgtumu ātrajos iestatījumos"</string>
    +-    <string name="overview_nav_bar_gesture" msgid="8579814204727917764">"Iespējot vilkšanu augšup, lai sadalītu ekrānu"</string>
    +-    <string name="overview_nav_bar_gesture_desc" msgid="6329167382305102615">"Iespējot žestu ekrāna sadalīšanai, velkot augšup no pogas Pārskats"</string>
    +     <string name="experimental" msgid="6198182315536726162">"Eksperimentāli"</string>
    +     <string name="enable_bluetooth_title" msgid="5027037706500635269">"Vai ieslēgt Bluetooth savienojumu?"</string>
    +     <string name="enable_bluetooth_message" msgid="9106595990708985385">"Lai pievienotu tastatūru planšetdatoram, vispirms ir jāieslēdz Bluetooth savienojums."</string>
    +@@ -653,4 +653,5 @@
    +     <string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"Atvērt <xliff:g id="ID_1">%s</xliff:g> iestatījumus."</string>
    +     <string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"Rediģēt iestatījumu secību."</string>
    +     <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"<xliff:g id="ID_1">%1$d</xliff:g>. lpp. no <xliff:g id="ID_2">%2$d</xliff:g>"</string>
    ++    <string name="cant_silence_or_block" msgid="999689262131488625">"Nevar izslēgt paziņojumu signālu vai tos bloķēt"</string>
    + </resources>
    +diff --git a/packages/SystemUI/res/values-mk-rMK/strings.xml b/packages/SystemUI/res/values-mk-rMK/strings.xml
    +index 549543d..602fdc9 100644
    +--- a/packages/SystemUI/res/values-mk-rMK/strings.xml
    ++++ b/packages/SystemUI/res/values-mk-rMK/strings.xml
    +@@ -238,7 +238,7 @@
    +     <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"Податоците 4G се паузирани"</string>
    +     <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"Мобилните податоци се паузирани"</string>
    +     <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"Податоците се паузирани"</string>
    +-    <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"Поради тоа што го достигнавте поставеното ограничување на податоци, уредот го паузираше користењето податоци до крајот на циклусот.\n\nОператорот може да ви наплати ако продолжите."</string>
    ++    <string name="data_usage_disabled_dialog" msgid="1841738975235283398">"Го достигнавте ограничувањето за сообраќај на податоци што сте го поставиле. Веќе не користите мобилен интернет.\n\nДоколку продолжите, ќе ви биде наплатено за потрошениот сообраќај."</string>
    +     <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"Продолжи"</string>
    +     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Нема интернет"</string>
    +     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Поврзано на Wi-Fi"</string>
    +@@ -404,6 +404,7 @@
    +     <string name="device_owned_footer" msgid="3802752663326030053">"Уредот може да се следи"</string>
    +     <string name="profile_owned_footer" msgid="8021888108553696069">"Профилот можеби се следи"</string>
    +     <string name="vpn_footer" msgid="2388611096129106812">"Мрежата може да се следи"</string>
    ++    <string name="branded_vpn_footer" msgid="2168111859226496230">"Мрежата може да се следи"</string>
    +     <string name="monitoring_title_device_owned" msgid="7121079311903859610">"Следење на уредот"</string>
    +     <string name="monitoring_title_profile_owned" msgid="6790109874733501487">"Следење профил"</string>
    +     <string name="monitoring_title" msgid="169206259253048106">"Следење на мрежата"</string>
    +@@ -416,6 +417,7 @@
    +     <string name="legacy_vpn_name" msgid="6604123105765737830">"ВПН"</string>
    +     <string name="monitoring_description_app" msgid="6259179342284742878">"Поврзани сте на <xliff:g id="APPLICATION">%1$s</xliff:g>, којашто може да ја следи вашата активност на мрежата, вклучувајќи ги е-пораките, апликациите и веб-локациите."</string>
    +     <string name="monitoring_description_app_personal" msgid="484599052118316268">"Поврзани сте на <xliff:g id="APPLICATION">%1$s</xliff:g>, којашто може да ја следи вашата лична активност на мрежата, вклучувајќи ги е-пораките, апликациите и веб-локациите."</string>
    ++    <string name="branded_monitoring_description_app_personal" msgid="2669518213949202599">"Поврзани сте на <xliff:g id="APPLICATION">%1$s</xliff:g>, којашто може да ја следи вашата лична активност на мрежата, вклучувајќи ги е-пораките, апликациите и веб-локациите."</string>
    +     <string name="monitoring_description_app_work" msgid="1754325860918060897">"<xliff:g id="ORGANIZATION">%1$s</xliff:g> управува со вашиот работен профил. Истиот е поврзан на <xliff:g id="APPLICATION">%2$s</xliff:g>, којашто може да ја следи вашата работна активност на мрежата, вклучувајќи ги е-пораките, апликациите и веб-локациите.\n\nЗа повеќе информации, контактирајте со администраторот."</string>
    +     <string name="monitoring_description_app_personal_work" msgid="4946600443852045903">"<xliff:g id="ORGANIZATION">%1$s</xliff:g> управува со вашиот работен профил. Истиот е поврзан на <xliff:g id="APPLICATION_WORK">%2$s</xliff:g>, којашто може да ја следи вашата работна активност на мрежата, вклучувајќи ги е-пораките, апликациите и веб-локациите.\n\nВие исто така сте поврзани на <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g>, којашто може да ја следи вашата лична активност на мрежата."</string>
    +     <string name="monitoring_description_vpn_app_device_owned" msgid="4970443827043261703">"<xliff:g id="ORGANIZATION">%1$s</xliff:g> управува со вашиот уред.\n\nВашиот администратор може да ги следи и да управува со параметрите, корпоративниот пристап, апликациите, податоците поврзани со уредот и информациите за локацијата на уредот.\n\nПоврзани сте на <xliff:g id="APPLICATION">%2$s</xliff:g>, којашто може да ја следи вашата активност на мрежата, вклучувајќи ги е-пораките, апликациите и веб-локациите.\n\nЗа повеќе информации, контактирајте со администраторот."</string>
    +@@ -492,8 +494,6 @@
    +     <string name="clock_seconds_desc" msgid="6282693067130470675">"Прикажи ги секундите на часовникот на статусната лента. Може да влијае на траењето на батеријата."</string>
    +     <string name="qs_rearrange" msgid="8060918697551068765">"Преуредете ги Брзи поставки"</string>
    +     <string name="show_brightness" msgid="6613930842805942519">"Прикажете ја осветленоста во Брзи поставки"</string>
    +-    <string name="overview_nav_bar_gesture" msgid="8579814204727917764">"Овозможи го гестот повлекување нагоре за поделен екран"</string>
    +-    <string name="overview_nav_bar_gesture_desc" msgid="6329167382305102615">"Овозможете гест за отворање поделен екран со повлекување нагоре од копчето Краток преглед"</string>
    +     <string name="experimental" msgid="6198182315536726162">"Експериментално"</string>
    +     <string name="enable_bluetooth_title" msgid="5027037706500635269">"Да се вклучи Bluetooth?"</string>
    +     <string name="enable_bluetooth_message" msgid="9106595990708985385">"За да ја поврзете тастатурата со таблетот, најпрво треба да вклучите Bluetooth."</string>
    +@@ -651,4 +651,5 @@
    +     <string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"Отворете ги поставките на <xliff:g id="ID_1">%s</xliff:g>."</string>
    +     <string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"Уредете го редоследот на поставките."</string>
    +     <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"Страница <xliff:g id="ID_1">%1$d</xliff:g> од <xliff:g id="ID_2">%2$d</xliff:g>"</string>
    ++    <string name="cant_silence_or_block" msgid="999689262131488625">"Известувања не може да се стишат или блокираат"</string>
    + </resources>
    +diff --git a/packages/SystemUI/res/values-ml-rIN/strings.xml b/packages/SystemUI/res/values-ml-rIN/strings.xml
    +index 9f596b8..ddabf90 100644
    +--- a/packages/SystemUI/res/values-ml-rIN/strings.xml
    ++++ b/packages/SystemUI/res/values-ml-rIN/strings.xml
    +@@ -238,7 +238,7 @@
    +     <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"4G ഡാറ്റ താൽക്കാലികമായി നിർത്തി"</string>
    +     <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"സെല്ലുലാർ ഡാറ്റ താൽക്കാലികമായി നിർത്തി"</string>
    +     <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"ഡാറ്റ താൽക്കാലികമായി നിർത്തി"</string>
    +-    <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"നിങ്ങൾ നേരത്തെ ക്രമീകരിച്ച ഡാറ്റ പരിധിയിലെത്തിയതിനാൽ, ഈ സൈക്കിളിന്റെ അവശേഷിക്കുന്ന ഡാറ്റ ഉപയോഗം, ഉപകരണം താൽക്കാലികമായി നിർത്തി.\n\nപുനരാരംഭിക്കുന്നത്, നിങ്ങളുടെ കാരിയറിൽ നിന്ന് നിരക്കുകൾക്ക് ഇടയാക്കാം."</string>
    ++    <string name="data_usage_disabled_dialog" msgid="1841738975235283398">"നിങ്ങൾ സജ്ജമാക്കിയ ഡാറ്റ പരിധി എത്തിക്കഴിഞ്ഞു. ഇനിയങ്ങോട്ട് നിങ്ങൾ സെല്ലുലാർ ഡാറ്റ ഉപയോഗിക്കില്ല.\n\nതുടരുകയാണെങ്കിൽ, ഡാറ്റാ ഉപയോഗത്തിന് നിരക്കുകൾ ബാധകമായേക്കാം."</string>
    +     <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"പുനരാരംഭിക്കുക"</string>
    +     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"ഇന്റർനെറ്റ് കണക്ഷൻ ഇല്ല"</string>
    +     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"വൈഫൈ കണക്‌റ്റുചെയ്‌തു"</string>
    +@@ -404,6 +404,7 @@
    +     <string name="device_owned_footer" msgid="3802752663326030053">"ഉപകരണം നിരീക്ഷിക്കപ്പെടാം"</string>
    +     <string name="profile_owned_footer" msgid="8021888108553696069">"പ്രൊഫൈൽ നിരീക്ഷിക്കപ്പെടാം"</string>
    +     <string name="vpn_footer" msgid="2388611096129106812">"നെറ്റ്‌വർക്ക് നിരീക്ഷിക്കപ്പെടാം"</string>
    ++    <string name="branded_vpn_footer" msgid="2168111859226496230">"നെറ്റ്‌വർക്ക് നിരീക്ഷിക്കപ്പെടാം"</string>
    +     <string name="monitoring_title_device_owned" msgid="7121079311903859610">"ഉപകരണം നിരീക്ഷിക്കൽ"</string>
    +     <string name="monitoring_title_profile_owned" msgid="6790109874733501487">"പ്രൊഫൈൽ നിരീക്ഷിക്കൽ"</string>
    +     <string name="monitoring_title" msgid="169206259253048106">"നെറ്റ്‌വർക്ക് നിരീക്ഷിക്കൽ"</string>
    +@@ -416,6 +417,7 @@
    +     <string name="legacy_vpn_name" msgid="6604123105765737830">"VPN"</string>
    +     <string name="monitoring_description_app" msgid="6259179342284742878">"നിങ്ങൾ <xliff:g id="APPLICATION">%1$s</xliff:g> എന്നതിലേക്ക് കണക്റ്റുചെയ്‌തിരിക്കുന്നു, അതിന് ഇമെയിലുകൾ, ആപ്സ്, വെബ്‌സൈറ്റുകൾ എന്നിവ ഉൾപ്പെടെ നിങ്ങളുടെ നെറ്റ്‌വർക്ക് പ്രവർത്തനം നിരീക്ഷിക്കാനാകും."</string>
    +     <string name="monitoring_description_app_personal" msgid="484599052118316268">"നിങ്ങൾ <xliff:g id="APPLICATION">%1$s</xliff:g> എന്നതിലേക്ക് കണക്റ്റുചെയ്‌തിരിക്കുന്നു, അതിന് ഇമെയിലുകൾ, ആപ്സ്, വെബ്‌സൈറ്റുകൾ എന്നിവ ഉൾപ്പെടെ നിങ്ങളുടെ സ്വകാര്യ നെറ്റ്‌വർക്ക് പ്രവർത്തനം നിരീക്ഷിക്കാനാകും."</string>
    ++    <string name="branded_monitoring_description_app_personal" msgid="2669518213949202599">"നിങ്ങൾ <xliff:g id="APPLICATION">%1$s</xliff:g> ആപ്പിലേക്ക് കണക്റ്റുചെയ്‌തിരിക്കുന്നു, ഇമെയിലുകൾ, ആപ്‌സ്, വെബ്‌സൈറ്റുകൾ എന്നിവ ഉൾപ്പെടെ നെറ്റ്‌വർക്ക് ആക്റ്റിവിറ്റി നിരീക്ഷിക്കാൻ ഈ ആപ്പിന് കഴിയും."</string>
    +     <string name="monitoring_description_app_work" msgid="1754325860918060897">"നിങ്ങളുടെ ഔദ്യോഗിക പ്രൊഫൈൽ നിയന്ത്രിക്കുന്നത് <xliff:g id="ORGANIZATION">%1$s</xliff:g> ആണ്. നിങ്ങൾ <xliff:g id="APPLICATION">%2$s</xliff:g> എന്നതിലേക്ക് കണക്റ്റുചെയ്‌തിരിക്കുന്നു, അതിന് ഇമെയിലുകൾ, ആപ്സ്, വെബ്‌സൈറ്റുകൾ എന്നിവ ഉൾപ്പെടെ നിങ്ങളുടെ ഔദ്യോഗിക നെറ്റ്‌വർക്ക് പ്രവർത്തനം നിരീക്ഷിക്കാനാകും.\n\nകൂടുതൽ വിവരങ്ങൾക്ക്, നിങ്ങളുടെ അഡ്‌മിനിസ്‌ട്രേറ്ററെ ബന്ധപ്പെടുക."</string>
    +     <string name="monitoring_description_app_personal_work" msgid="4946600443852045903">"നിങ്ങളുടെ ഔദ്യോഗിക പ്രൊഫൈൽ നിയന്ത്രിക്കുന്നത് <xliff:g id="ORGANIZATION">%1$s</xliff:g> ആണ്. നിങ്ങൾ <xliff:g id="APPLICATION_WORK">%2$s</xliff:g> എന്നതിലേക്ക് കണക്റ്റുചെയ്‌തിരിക്കുന്നു, അതിന് ഇമെയിലുകൾ, ആപ്സ്, വെബ്‌സൈറ്റുകൾ എന്നിവ ഉൾപ്പെടെ നിങ്ങളുടെ ഔദ്യോഗിക നെറ്റ്‌വർക്ക് പ്രവർത്തനം നിരീക്ഷിക്കാനാകും.\n\nനിങ്ങൾ <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g> എന്നതിലേക്കും കണക്റ്റുചെയ്‌തിരിക്കുന്നു, അതിന് നിങ്ങളുടെ സ്വകാര്യ നെറ്റ്‌വർക്ക് പ്രവർത്തനം നിരീക്ഷിക്കാനാകും."</string>
    +     <string name="monitoring_description_vpn_app_device_owned" msgid="4970443827043261703">"നിങ്ങളുടെ ഉപകരണം നിയന്ത്രിക്കുന്നത് <xliff:g id="ORGANIZATION">%1$s</xliff:g> ആണ്.\n\nനിങ്ങളുടെ അഡ്‌മിനിസ്‌ട്രേറ്റർക്ക്, ഉപകരണവുമായി ബന്ധപ്പെട്ട ക്രമീകരണവും കോർപ്പറേറ്റ് ആക്‌സസ്സും അപ്ലിക്കേഷനുകളും വിവരവും ഒപ്പം ഉപകരണത്തിന്റെ ലൊക്കേഷൻ വിവരവും നിരീക്ഷിച്ച് നിയന്ത്രിക്കാനാകും.\n\nഇമെയിലുകളും അപ്ലിക്കേഷനുകളും വെബ്‌സൈറ്റുകളും ഉൾപ്പെടെയുള്ള നെറ്റ്‌വർക്ക് പ്രവർത്തനം നിരീക്ഷിക്കാനാകുന്ന ഒരു <xliff:g id="APPLICATION">%2$s</xliff:g> എന്നതിലേക്കും നിങ്ങൾ കണക്റ്റുചെയ്തിരിക്കുന്നു.\n\nകൂടുതൽ വിവരങ്ങൾക്ക്, അഡ്‌മിനിസ്ട്രേറ്ററെ ബന്ധപ്പെടുക."</string>
    +@@ -492,8 +494,6 @@
    +     <string name="clock_seconds_desc" msgid="6282693067130470675">"സ്റ്റാറ്റസ് ബാറിൽ ക്ലോക്ക് സെക്കൻഡ് കാണിക്കുന്നത് ബാറ്ററിയുടെ ലൈഫിനെ ബാധിക്കാം."</string>
    +     <string name="qs_rearrange" msgid="8060918697551068765">"ദ്രുത ക്രമീകരണം പുനഃസജ്ജീകരിക്കുക"</string>
    +     <string name="show_brightness" msgid="6613930842805942519">"ദ്രുത ക്രമീകരണത്തിൽ തെളിച്ചം കാണിക്കുക"</string>
    +-    <string name="overview_nav_bar_gesture" msgid="8579814204727917764">"സ്പ്ലിറ്റ്-സ്ക്രീൻ സ്വൈപ്പ്-അപ്പ് ജെസ്റ്റർ പ്രവർത്തനക്ഷമമാക്കുക"</string>
    +-    <string name="overview_nav_bar_gesture_desc" msgid="6329167382305102615">"ചുരുക്കവിവരണ ബട്ടണിൽ നിന്ന് മുകളിലേക്ക് സ്വൈപ്പുചെയ്തുകൊണ്ട് സ്പ്ലിറ്റ്-സ്ക്രീനിലേക്ക് പ്രവേശിക്കാൻ ജെസ്‌റ്റർ പ്രവർത്തനക്ഷമമാക്കുക"</string>
    +     <string name="experimental" msgid="6198182315536726162">"പരീക്ഷണാത്മകം!"</string>
    +     <string name="enable_bluetooth_title" msgid="5027037706500635269">"Bluetooth ഓണാക്കണോ?"</string>
    +     <string name="enable_bluetooth_message" msgid="9106595990708985385">"നിങ്ങളുടെ ടാബ്‌ലെറ്റുമായി കീബോർഡ് കണക്റ്റുചെയ്യുന്നതിന്, ആദ്യം Bluetooth ഓണാക്കേണ്ടതുണ്ട്."</string>
    +@@ -651,4 +651,5 @@
    +     <string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"<xliff:g id="ID_1">%s</xliff:g> ക്രമീകരണം തുറക്കുക."</string>
    +     <string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"ക്രമീകരണ ക്രമം എഡിറ്റുചെയ്യുക."</string>
    +     <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"പേജ് <xliff:g id="ID_1">%1$d</xliff:g> / <xliff:g id="ID_2">%2$d</xliff:g>"</string>
    ++    <string name="cant_silence_or_block" msgid="999689262131488625">"അറിയിപ്പുകൾ നിശബ്ദമാക്കാനോ ബ്ലോക്കുചെയ്യാനോ കഴിയില്ല"</string>
    + </resources>
    +diff --git a/packages/SystemUI/res/values-mn-rMN/strings.xml b/packages/SystemUI/res/values-mn-rMN/strings.xml
    +index f3a2f08..df9e799 100644
    +--- a/packages/SystemUI/res/values-mn-rMN/strings.xml
    ++++ b/packages/SystemUI/res/values-mn-rMN/strings.xml
    +@@ -236,7 +236,7 @@
    +     <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"4G дата-г түр зогсоосон байна"</string>
    +     <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"Гар утасны дата-г түр зогсоосон байна"</string>
    +     <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"Дата-г түр зогсоосон байна"</string>
    +-    <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"Таны багц дата эрхийн дээд хэмжээнд хүрсэн байгаа тул төхөөрөмж нь үлдсэн хэсэгт дата хэрэглээг түр зогсоосон байна.\n\nТа үйлдлийг үргэлжлүүлэхийг хүсвэл үйлчилгээ үзүүлж буй үүрэн холбооны газраас нэмж дата эрх авна уу."</string>
    ++    <string name="data_usage_disabled_dialog" msgid="1841738975235283398">"Таны тогтоосон дата хэмжээний хязгаарт хүрсэн байна. Та одоогоор мобайл датаг ашиглаагүй байна.\n\nҮргэлжлүүлсэн тохиолдолд төлбөр гарах болно."</string>
    +     <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"Үргэлжлүүлэх"</string>
    +     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Интернет холболт байхгүй"</string>
    +     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi холбогдсон"</string>
    +@@ -402,6 +402,7 @@
    +     <string name="device_owned_footer" msgid="3802752663326030053">"Төхөөрөмжийг хянах боломжтой"</string>
    +     <string name="profile_owned_footer" msgid="8021888108553696069">"Профайлыг хянаж байж болзошгүй"</string>
    +     <string name="vpn_footer" msgid="2388611096129106812">"Сүлжээ хянагдаж байж болзошгүй"</string>
    ++    <string name="branded_vpn_footer" msgid="2168111859226496230">"Сүлжээг хянаж байж болзошгүй"</string>
    +     <string name="monitoring_title_device_owned" msgid="7121079311903859610">"Төхөөрөмжийн хяналт"</string>
    +     <string name="monitoring_title_profile_owned" msgid="6790109874733501487">"Профайл хяналт"</string>
    +     <string name="monitoring_title" msgid="169206259253048106">"Сүлжээний хяналт"</string>
    +@@ -414,6 +415,7 @@
    +     <string name="legacy_vpn_name" msgid="6604123105765737830">"VPN"</string>
    +     <string name="monitoring_description_app" msgid="6259179342284742878">"Та <xliff:g id="APPLICATION">%1$s</xliff:g>-д холбогдсон бөгөөд энэ нь таны имэйл, апп, вебсайт зэрэг сүлжээний үйл ажиллагааг хянах боломжтой."</string>
    +     <string name="monitoring_description_app_personal" msgid="484599052118316268">"Та <xliff:g id="APPLICATION">%1$s</xliff:g>-д холбогдсон бөгөөд энэ нь таны имэйл, апп, вебсайт зэрэг сүлжээний хувийн үйл ажиллагааг хянах боломжтой."</string>
    ++    <string name="branded_monitoring_description_app_personal" msgid="2669518213949202599">"Та имэйл, апп, вэб хуудас зэрэг хувийн сүлжээнийхээ үйл ажиллагааг хянах боломжтой <xliff:g id="APPLICATION">%1$s</xliff:g>-д холбогдсон байна."</string>
    +     <string name="monitoring_description_app_work" msgid="1754325860918060897">"Таны ажлын профайлыг <xliff:g id="ORGANIZATION">%1$s</xliff:g> удирддаг. Энэ нь <xliff:g id="APPLICATION">%2$s</xliff:g>-тэй холбогдсон бөгөөд таны  имэйл, апп, вебсайт зэрэг сүлжээний үйл ажиллагааг хянах боломжтой.\n\nДэлгэрэнгүй мэдээлэл авахыг хүсвэл админтайгаа холбогдоно уу."</string>
    +     <string name="monitoring_description_app_personal_work" msgid="4946600443852045903">"Таны ажлын профайлыг <xliff:g id="ORGANIZATION">%1$s</xliff:g> удирддаг. Энэ нь <xliff:g id="APPLICATION_WORK">%2$s</xliff:g>-тай холбогдсон бөгөөд таны имэйл, апп, вебсайт зэрэг ажлын сүлжээний үйл ажиллагааг хянах боломжтой.\n\nМөн та <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g>-д холбогдсон бөгөөд энэ нь таны сүлжээний хувийн үйл ажиллагааг хянаж чадна."</string>
    +     <string name="monitoring_description_vpn_app_device_owned" msgid="4970443827043261703">"Таны төхөөрөмжийг <xliff:g id="ORGANIZATION">%1$s</xliff:g> удирддаг.\n\n Танай админ төхөөрөмж, төхөөрөмжийн байршилтай холбоотой өгөгдлийг холбох, тохиргоог өөрчлөх болон хяналт тавих боломжтой.\n\nТа <xliff:g id="APPLICATION">%2$s</xliff:g>-тай холбогдсон бөгөөд ингэснээр таны имэйл,апп, аюулгүй вебсайт зэрэг сүлжээний үйл ажиллагаагаа хянах боломжтой.\n\n Дэлгэрэнгүй мэдээлэл авахыг хүсвэл админтайгаа холбогдоно уу."</string>
    +@@ -492,8 +494,6 @@
    +     <string name="clock_seconds_desc" msgid="6282693067130470675">"Статус талбарт цагийн секундыг харуулах. Энэ нь тэжээлийн цэнэгт нөлөөлж болно."</string>
    +     <string name="qs_rearrange" msgid="8060918697551068765">"Түргэн тохиргоог дахин засварлах"</string>
    +     <string name="show_brightness" msgid="6613930842805942519">"Түргэн тохиргоонд гэрэлтүүлэг харах"</string>
    +-    <string name="overview_nav_bar_gesture" msgid="8579814204727917764">"Дэлгэц хуваах дээш шудрах дохиог идэвхжүүлэх"</string>
    +-    <string name="overview_nav_bar_gesture_desc" msgid="6329167382305102615">"Тойм товчлуурыг дээш шударч, хуваагдсан дэлгэцэд зангаагаар орох тохиргоог идэвхжүүлэх"</string>
    +     <string name="experimental" msgid="6198182315536726162">"Туршилтын"</string>
    +     <string name="enable_bluetooth_title" msgid="5027037706500635269">"Bluetooth-г асаах уу?"</string>
    +     <string name="enable_bluetooth_message" msgid="9106595990708985385">"Компьютерийн гараа таблетад холбохын тулд эхлээд Bluetooth-г асаана уу."</string>
    +@@ -505,14 +505,14 @@
    +     <string name="tuner_full_importance_settings" msgid="3207312268609236827">"Тэжээлийн мэдэгдлийн удирдлага"</string>
    +     <string name="tuner_full_importance_settings_on" msgid="7545060756610299966">"Идэвхтэй"</string>
    +     <string name="tuner_full_importance_settings_off" msgid="8208165412614935229">"Идэвхгүй"</string>
    +-    <string name="power_notification_controls_description" msgid="4372459941671353358">"Тэжээлийн мэдэгдлийн удирдлагын тусламжтайгаар та апп-н мэдэгдэлд 0-5 хүртэлх ач холбогдлын төвшин тогтоох боломжтой. \n\n"<b>"5-р төвшин"</b>" \n- Мэдэгдлийн жагсаалтын хамгийн дээр харуулна \n- Бүтэн дэлгэцэд саад болно \n- Дэлгэцэд тогтмол гарч ирнэ \n\n"<b>"4-р төвшин"</b>" \n- Бүтэн дэлгэцэд саад болохоос сэргийлнэ \n- Дэлгэцэд тогтмол гарч ирнэ \n\n"<b>"3-р төвшин"</b>" \n- Бүтэн дэлгэцэд саад болохоос сэргийлнэ \n- Дэлгэцэд хэзээ ч гарч ирэхгүй \n\n"<b>"2-р төвшин"</b>" \n- Бүтэн дэлгэцэд саад болохоос сэргийлнэ \n- Дэлгэцэд хэзээ ч гарч ирэхгүй \n- Дуу болон чичиргээ хэзээ ч гаргахгүй \n\n"<b>"1-р төвшин"</b>" \n- Бүтэн дэлгэцэд саад болохоос сэргийлнэ \n- Дэлгэцэд хэзээ ч гарч ирэхгүй \n- Дуу болон чичиргээ хэзээ ч гаргахгүй \n- Түгжигдсэн дэлгэц болон статусын самбараас нууна \n- Мэдэгдлийн жагсаалтын доор харуулна \n\n"<b>"0-р төвшин"</b>" \n- Энэ апп-н бүх мэдэгдлийг блоклоно"</string>
    ++    <string name="power_notification_controls_description" msgid="4372459941671353358">"Тэжээлийн мэдэгдлийн удирдлагын тусламжтайгаар та апп-н мэдэгдэлд 0-5 хүртэлх ач холбогдлын түвшин тогтоох боломжтой. \n\n"<b>"5-р түвшин"</b>" \n- Мэдэгдлийн жагсаалтын хамгийн дээр харуулна \n- Бүтэн дэлгэцэд саад болно \n- Дэлгэцэд тогтмол гарч ирнэ \n\n"<b>"4-р түвшин"</b>" \n- Бүтэн дэлгэцэд саад болохоос сэргийлнэ \n- Дэлгэцэд тогтмол гарч ирнэ \n\n"<b>"3-р түвшин"</b>" \n- Бүтэн дэлгэцэд саад болохоос сэргийлнэ \n- Дэлгэцэд хэзээ ч гарч ирэхгүй \n\n"<b>"2-р түвшин"</b>" \n- Бүтэн дэлгэцэд саад болохоос сэргийлнэ \n- Дэлгэцэд хэзээ ч гарч ирэхгүй \n- Дуу болон чичиргээ хэзээ ч гаргахгүй \n\n"<b>"1-р түвшин"</b>" \n- Бүтэн дэлгэцэд саад болохоос сэргийлнэ \n- Дэлгэцэд хэзээ ч гарч ирэхгүй \n- Дуу болон чичиргээ хэзээ ч гаргахгүй \n- Түгжигдсэн дэлгэц болон статусын самбараас нууна \n- Мэдэгдлийн жагсаалтын доор харуулна \n\n"<b>"0-р түвшин"</b>" \n- Энэ апп-н бүх мэдэгдлийг блоклоно"</string>
    +     <string name="user_unspecified_importance" msgid="361613856933432117">"Ач холбогдол: Автомат"</string>
    +-    <string name="blocked_importance" msgid="5035073235408414397">"Ач холбогдол: 0-р төвшин"</string>
    +-    <string name="min_importance" msgid="560779348928574878">"Ач холбогдол: 1-р төвшин"</string>
    +-    <string name="low_importance" msgid="7571498511534140">"Ач холбогдол: 2-р төвшин"</string>
    +-    <string name="default_importance" msgid="7609889614553354702">"Ач холбогдол: 3-р төвшин"</string>
    +-    <string name="high_importance" msgid="3441537905162782568">"Ач холбогдол: 4-р төвшин"</string>
    +-    <string name="max_importance" msgid="4880179829869865275">"Ач холбогдол: 5-р төвшин"</string>
    ++    <string name="blocked_importance" msgid="5035073235408414397">"Ач холбогдол: 0-р түвшин"</string>
    ++    <string name="min_importance" msgid="560779348928574878">"Ач холбогдол: 1-р түвшин"</string>
    ++    <string name="low_importance" msgid="7571498511534140">"Ач холбогдол: 2-р түвшин"</string>
    ++    <string name="default_importance" msgid="7609889614553354702">"Ач холбогдол: 3-р түвшин"</string>
    ++    <string name="high_importance" msgid="3441537905162782568">"Ач холбогдол: 4-р түвшин"</string>
    ++    <string name="max_importance" msgid="4880179829869865275">"Ач холбогдол: 5-р түвшин"</string>
    +     <string name="notification_importance_user_unspecified" msgid="2868359605125272874">"Апп нь мэдэгдэл бүрийн ач холбогдлыг тодорхойлдог."</string>
    +     <string name="notification_importance_blocked" msgid="4237497046867398057">"Энэ апп-н мэдэгдлийг хэзээ ч бүү харуул."</string>
    +     <string name="notification_importance_min" msgid="7844224511187027155">"Бүтэн дэлгэцэд саадгүй, гарч ирэхгүй, дуугүй, чичиргээгүй. Түгжигдсэн дэлгэц, статусын хэсгээс нуух."</string>
    +@@ -651,4 +651,5 @@
    +     <string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"<xliff:g id="ID_1">%s</xliff:g> тохиргоог нээнэ үү."</string>
    +     <string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"Тохиргооны дарааллыг өөрчилнө үү."</string>
    +     <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"<xliff:g id="ID_2">%2$d</xliff:g>-н <xliff:g id="ID_1">%1$d</xliff:g>-р хуудас"</string>
    ++    <string name="cant_silence_or_block" msgid="999689262131488625">"Мэдэгдлийн дууг хаах, эсвэл блоклох боломжгүй"</string>
    + </resources>
    +diff --git a/packages/SystemUI/res/values-mr-rIN/strings.xml b/packages/SystemUI/res/values-mr-rIN/strings.xml
    +index e5c6410..006b9bb 100644
    +--- a/packages/SystemUI/res/values-mr-rIN/strings.xml
    ++++ b/packages/SystemUI/res/values-mr-rIN/strings.xml
    +@@ -238,7 +238,7 @@
    +     <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"4G डेटास विराम दिला आहे"</string>
    +     <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"सेल्युलर डेटास विराम दिला आहे"</string>
    +     <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"डेटास विराम दिला आहे"</string>
    +-    <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"आपली सेट केलेली डेटा मर्यादा गाठल्यामुळे, डिव्हाइसने या चक्राच्या उर्वरित डेटा वापरास विराम दिला आहे.\n\nपुन्हा सुरु करण्यामुळे आपल्या वाहकाकडून शुल्क आकारले जाऊ शकते."</string>
    ++    <string name="data_usage_disabled_dialog" msgid="1841738975235283398">"आपण सेट केलेली डेटा मर्यादा गाठली आहे. आपण यापुढे मोबाइल डेटा वापरणार नाही.\n\nआपण पुन: सुरु केल्यास, डेटा वापरासाठी शुल्क आकारले जाऊ शकतात."</string>
    +     <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"पुन्हा सुरु करा"</string>
    +     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"इंटरनेट कनेक्शन नाही"</string>
    +     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"वाय-फाय कनेक्ट केले"</string>
    +@@ -404,6 +404,7 @@
    +     <string name="device_owned_footer" msgid="3802752663326030053">"डिव्हाइसचे परीक्षण केले जाऊ शकते"</string>
    +     <string name="profile_owned_footer" msgid="8021888108553696069">"प्रोफाईलचे परीक्षण केले जाऊ शकते"</string>
    +     <string name="vpn_footer" msgid="2388611096129106812">"नेटवर्कचे परीक्षण केले जाऊ शकते"</string>
    ++    <string name="branded_vpn_footer" msgid="2168111859226496230">"नेटवर्कचे परीक्षण केले जाऊ शकते"</string>
    +     <string name="monitoring_title_device_owned" msgid="7121079311903859610">"डिव्हाइस परीक्षण"</string>
    +     <string name="monitoring_title_profile_owned" msgid="6790109874733501487">"प्रोफाईल परीक्षण"</string>
    +     <string name="monitoring_title" msgid="169206259253048106">"नेटवर्क परीक्षण"</string>
    +@@ -416,6 +417,7 @@
    +     <string name="legacy_vpn_name" msgid="6604123105765737830">"VPN"</string>
    +     <string name="monitoring_description_app" msgid="6259179342284742878">"आपण <xliff:g id="APPLICATION">%1$s</xliff:g> शी कनेक्‍ट केले आहे, जो ईमेल, अ‍ॅप्स आणि वेबसाइटसह आपल्‍या नेटवर्क क्रियाकलापाचे परीक्षण करू शकतो."</string>
    +     <string name="monitoring_description_app_personal" msgid="484599052118316268">"आपण <xliff:g id="APPLICATION">%1$s</xliff:g> शी कनेक्‍ट केले आहे, जो ईमेल, अ‍ॅप्स आणि वेबसाइटसह आपल्‍या वैयक्तिक नेटवर्क क्रियाकलापाचे परीक्षण करू शकतो."</string>
    ++    <string name="branded_monitoring_description_app_personal" msgid="2669518213949202599">"आपण <xliff:g id="APPLICATION">%1$s</xliff:g> शी कनेक्‍ट केले आहे, जो ईमेल, अ‍ॅप्स आणि वेबसाइटसह आपल्‍या वैयक्तिक नेटवर्क क्रियाकलापाचे परीक्षण करू शकतो."</string>
    +     <string name="monitoring_description_app_work" msgid="1754325860918060897">"आपले कार्य प्रोफाईल <xliff:g id="ORGANIZATION">%1$s</xliff:g> द्वारे व्यवस्थापित केले आहे. ते <xliff:g id="APPLICATION">%2$s</xliff:g> शी कनेक्ट केले आहे, जो ईमेल, अ‍ॅप्स आणि वेबसाइटसह आपल्‍या कार्य नेटवर्क क्रियाकलापाचे परीक्षण करू शकतो.\n\nअधिक माहितीसाठी, आपल्‍या प्रशासकाशी संपर्क साधा."</string>
    +     <string name="monitoring_description_app_personal_work" msgid="4946600443852045903">"आपले कार्य प्रोफाईल <xliff:g id="ORGANIZATION">%1$s</xliff:g> द्वारे व्यवस्थापित केले आहे. ते <xliff:g id="APPLICATION_WORK">%2$s</xliff:g> शी कनेक्ट केले आहे, जे ईमेल, अ‍ॅप्स आणि वेबसाइटसह आपल्‍या कार्य नेटवर्क क्रियाकलापाचे परीक्षण करू शकते.\n\nआपण <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g> शी देखील कनेक्‍ट केले आहे, जे आपल्‍या वैयक्तिक नेटवर्क क्रियाकलापाचे परीक्षण करू शकते."</string>
    +     <string name="monitoring_description_vpn_app_device_owned" msgid="4970443827043261703">"आपले डिव्हाइस <xliff:g id="ORGANIZATION">%1$s</xliff:g> द्वारे व्यवस्थापित केले आहे.\n\nआपला प्रशासक आपल्या डिव्हाइसशी संबद्ध सेटिंग्ज, कॉर्पोरेट प्रवेश, अ‍ॅप्स, डेटा आणि आपल्या डिव्हाइसच्या स्थान माहितीचे परीक्षण करू शकतो आणि व्‍यवस्थापित करू शकतो.\n\nआपण <xliff:g id="APPLICATION">%2$s</xliff:g> शी कनेक्ट केले आहे, जो ईमेल, अ‍ॅप्स आणि वेबसाइटसह आपल्या नेटवर्क क्रियाकलापाचे परीक्षण करू शकतो.\n\nअधिक माहितीसाठी, आपल्या प्रशासकाशी संपर्क साधा."</string>
    +@@ -492,8 +494,6 @@
    +     <string name="clock_seconds_desc" msgid="6282693067130470675">"स्टेटस बारमध्‍ये घड्‍याळ सेकंद दर्शवा. कदाचित बॅटरी आयुष्‍य प्रभावित होऊ शकते."</string>
    +     <string name="qs_rearrange" msgid="8060918697551068765">"द्रुत सेटिंग्जची पुनर्रचना करा"</string>
    +     <string name="show_brightness" msgid="6613930842805942519">"द्रुत सेटिंग्जमध्‍ये चमक दर्शवा"</string>
    +-    <string name="overview_nav_bar_gesture" msgid="8579814204727917764">"विभाजित-स्क्रीन स्वाइप-अप जेश्चर सक्षम करा"</string>
    +-    <string name="overview_nav_bar_gesture_desc" msgid="6329167382305102615">"विहंगावलोकन बटणावरून वर स्वाइप करून विभाजित-स्क्रीन प्रविष्ट करण्यासाठी जेश्चर सक्षम करा"</string>
    +     <string name="experimental" msgid="6198182315536726162">"प्रायोगिक"</string>
    +     <string name="enable_bluetooth_title" msgid="5027037706500635269">"ब्लूटुथ सुरू करायचे?"</string>
    +     <string name="enable_bluetooth_message" msgid="9106595990708985385">"आपला कीबोर्ड आपल्या टॅब्लेटसह कनेक्ट करण्यासाठी, आपल्याला प्रथम ब्लूटुथ चालू करणे आवश्यक आहे."</string>
    +@@ -651,4 +651,5 @@
    +     <string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"<xliff:g id="ID_1">%s</xliff:g> सेटिंग्ज उघडा."</string>
    +     <string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"सेटिंग्जचा क्रम संपादित करा."</string>
    +     <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"पृष्ठ <xliff:g id="ID_2">%2$d</xliff:g> पैकी <xliff:g id="ID_1">%1$d</xliff:g>"</string>
    ++    <string name="cant_silence_or_block" msgid="999689262131488625">"सूचना शांत किंवा अवरोधित केल्या जाऊ शकत नाहीत"</string>
    + </resources>
    +diff --git a/packages/SystemUI/res/values-ms-rMY/strings.xml b/packages/SystemUI/res/values-ms-rMY/strings.xml
    +index 7c543a6..df0faeb 100644
    +--- a/packages/SystemUI/res/values-ms-rMY/strings.xml
    ++++ b/packages/SystemUI/res/values-ms-rMY/strings.xml
    +@@ -238,7 +238,7 @@
    +     <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"Data 4G dijeda"</string>
    +     <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"Data selular dijeda"</string>
    +     <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"Data dijeda"</string>
    +-    <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"Oleh kerana had data tetap anda telah dicapai, peranti telah menjeda penggunaan data bagi baki kitaran ini.\n\nMenyambung semula boleh menyebabkan anda dikenakan bayaran daripada pembawa anda."</string>
    ++    <string name="data_usage_disabled_dialog" msgid="1841738975235283398">"Had data yang anda tetapkan telah dicapai. Anda tidak lagi menggunakan data selular.\n\nJika anda menyambung semula, caj mungkin dikenakan untuk penggunaan data."</string>
    +     <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"Sambung semula"</string>
    +     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Tiada smbg Internet"</string>
    +     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi disambungkan"</string>
    +@@ -404,6 +404,7 @@
    +     <string name="device_owned_footer" msgid="3802752663326030053">"Peranti mungkin dipantau"</string>
    +     <string name="profile_owned_footer" msgid="8021888108553696069">"Profil mungkin dipantau"</string>
    +     <string name="vpn_footer" msgid="2388611096129106812">"Rangkaian mungkin dipantau"</string>
    ++    <string name="branded_vpn_footer" msgid="2168111859226496230">"Rangkaian mungkin dipantau"</string>
    +     <string name="monitoring_title_device_owned" msgid="7121079311903859610">"Pemantauan peranti"</string>
    +     <string name="monitoring_title_profile_owned" msgid="6790109874733501487">"Pemantauan profil"</string>
    +     <string name="monitoring_title" msgid="169206259253048106">"Pemantauan rangkaian"</string>
    +@@ -416,6 +417,7 @@
    +     <string name="legacy_vpn_name" msgid="6604123105765737830">"VPN"</string>
    +     <string name="monitoring_description_app" msgid="6259179342284742878">"Anda disambungkan ke <xliff:g id="APPLICATION">%1$s</xliff:g>, yang boleh memantau aktiviti rangkaian anda, termasuk e-mel, apl dan tapak web."</string>
    +     <string name="monitoring_description_app_personal" msgid="484599052118316268">"Anda disambungkan ke <xliff:g id="APPLICATION">%1$s</xliff:g>, yang boleh memantau aktiviti rangkaian peribadi anda, termasuk e-mel, apl dan tapak web."</string>
    ++    <string name="branded_monitoring_description_app_personal" msgid="2669518213949202599">"Anda disambungkan ke <xliff:g id="APPLICATION">%1$s</xliff:g>, yang boleh memantau aktiviti rangkaian peribadi anda, termasuk e-mel, apl dan tapak web."</string>
    +     <string name="monitoring_description_app_work" msgid="1754325860918060897">"Profil kerja anda diurus oleh <xliff:g id="ORGANIZATION">%1$s</xliff:g>. Profil ini disambungkan ke <xliff:g id="APPLICATION">%2$s</xliff:g>, yang boleh memantau aktiviti rangkaian kerja anda, termasuk e-mel, apl dan tapak web.\n\nUntuk mendapatkan maklumat lanjut, sila hubungi pentadbir anda."</string>
    +     <string name="monitoring_description_app_personal_work" msgid="4946600443852045903">"Profil kerja anda diurus oleh <xliff:g id="ORGANIZATION">%1$s</xliff:g>. Profil disambungkan ke <xliff:g id="APPLICATION_WORK">%2$s</xliff:g>, yang boleh memantau aktiviti rangkaian kerja anda, termasuk e-mel, apl dan tapak web.\n\nAnda turut disambungkan ke <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g>, yang boleh memantau aktiviti rangkaian peribadi anda."</string>
    +     <string name="monitoring_description_vpn_app_device_owned" msgid="4970443827043261703">"Peranti anda diurus oleh <xliff:g id="ORGANIZATION">%1$s</xliff:g>.\n\nPentadbir anda boleh memantau dan mengurus tetapan, akses korporat, apl, data yang dikaitkan dengan peranti anda serta maklumat lokasi peranti anda.\n\nAnda disambungkan ke <xliff:g id="APPLICATION">%2$s</xliff:g>, yang boleh memantau aktiviti rangkaian anda, termasuk e-mel, apl dan tapak web.\n\nUntuk mendapatkan maklumat lanjut, hubungi pentadbir anda."</string>
    +@@ -492,8 +494,6 @@
    +     <string name="clock_seconds_desc" msgid="6282693067130470675">"Tunjukkan saat jam dalam bar status. Mungkin menjejaskan hayat bateri."</string>
    +     <string name="qs_rearrange" msgid="8060918697551068765">"Susun Semula Tetapan Pantas"</string>
    +     <string name="show_brightness" msgid="6613930842805942519">"Tunjukkan kecerahan dalam Tetapan Pantas"</string>
    +-    <string name="overview_nav_bar_gesture" msgid="8579814204727917764">"Dayakan gerak isyarat leret ke atas utk masuk skrin terpisah"</string>
    +-    <string name="overview_nav_bar_gesture_desc" msgid="6329167382305102615">"Dayakan gerak isyarat untuk memasuki skrin terpisah dengan meleret ke atas daripada butang Ikhtisar"</string>
    +     <string name="experimental" msgid="6198182315536726162">"Percubaan"</string>
    +     <string name="enable_bluetooth_title" msgid="5027037706500635269">"Hidupkan Bluetooth?"</string>
    +     <string name="enable_bluetooth_message" msgid="9106595990708985385">"Untuk menyambungkan papan kekunci anda dengan tablet, anda perlu menghidupkan Bluetooth terlebih dahulu."</string>
    +@@ -651,4 +651,5 @@
    +     <string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"Buka tetapan <xliff:g id="ID_1">%s</xliff:g>."</string>
    +     <string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"Edit susunan tetapan."</string>
    +     <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"Halaman <xliff:g id="ID_1">%1$d</xliff:g> daripada <xliff:g id="ID_2">%2$d</xliff:g>"</string>
    ++    <string name="cant_silence_or_block" msgid="999689262131488625">"Pemberitahuan tidak boleh disenyapkan atau disekat"</string>
    + </resources>
    +diff --git a/packages/SystemUI/res/values-my-rMM/strings.xml b/packages/SystemUI/res/values-my-rMM/strings.xml
    +index 56a7249..92ee06e 100644
    +--- a/packages/SystemUI/res/values-my-rMM/strings.xml
    ++++ b/packages/SystemUI/res/values-my-rMM/strings.xml
    +@@ -238,7 +238,7 @@
    +     <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"4G data ခေတ္တရပ်တန့်သည်"</string>
    +     <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"cellular data ခေတ္တရပ်တန့်သည်"</string>
    +     <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"ဒေတာ ခေတ္တရပ်တန့်သည်"</string>
    +-    <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"သင့် ဒေတာ အသုံးပြုမှု သတ်မှတ်ထားချက်သို့ ရောက်ရှိသောကြောင့်၊ ဤကာလအတွက် ကျန်ရှိသည့် ဒေတာအသုံးပြုမှုအား စက်ပစ္စည်းမှ ရပ်တန့်ထားသည်။\n\nဆက်လက်သွားပါက သင့်ဖုန်းဝန်ဆောင်မှုမှ သင့်အား ကုန်ကျစရိတ်တောင်းခံလိမ့်မည်။"</string>
    ++    <string name="data_usage_disabled_dialog" msgid="1841738975235283398">"သင်သတ်မှတ်ထားသော ဒေတာကန့်သတ်ချက်သို့ ရောက်နေပါပြီ။ သင်သည် ဆယ်လူလာဒေတာကို အသုံးမပြုတော့ပါ။\n\nသင်ဆက်လုပ်မည်ဆိုလျှင် ဒေတာသုံးစွဲမှုအတွက် အခငွေ ကျသင့်မှုရှိနိုင်ပါသည်။"</string>
    +     <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"ပြန်ဆက်လုပ်ရန်"</string>
    +     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"အင်တာနက်မရှိ"</string>
    +     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"ကြိုးမဲ့ဆက်သွယ်မှု"</string>
    +@@ -404,6 +404,7 @@
    +     <string name="device_owned_footer" msgid="3802752663326030053">"ကိရိယာကို စောင့်ကြပ် နိုင်ပါသည်"</string>
    +     <string name="profile_owned_footer" msgid="8021888108553696069">"ပရိုဖိုင်ကို စောင့်ကြပ်နိုင်သည်"</string>
    +     <string name="vpn_footer" msgid="2388611096129106812">"ကွန်ရက်ကို ကို စောင့်ကြပ် နိုင်ပါသည်"</string>
    ++    <string name="branded_vpn_footer" msgid="2168111859226496230">"ကွန်ရက်ကို စောင့်ကြည့်စစ်ဆေးမှု ရှိနိုင်ပါသည်"</string>
    +     <string name="monitoring_title_device_owned" msgid="7121079311903859610">"ကိရိယာကို စောင့်ကြပ်ခြင်း"</string>
    +     <string name="monitoring_title_profile_owned" msgid="6790109874733501487">"ပရိုဖိုင် စောင့်ကြပ်မှု"</string>
    +     <string name="monitoring_title" msgid="169206259253048106">"ကွန်ရက်ကို စောင့်ကြပ်ခြင်း"</string>
    +@@ -416,6 +417,7 @@
    +     <string name="legacy_vpn_name" msgid="6604123105765737830">"VPN"</string>
    +     <string name="monitoring_description_app" msgid="6259179342284742878">"သင်သည် <xliff:g id="APPLICATION">%1$s</xliff:g> သို့ ချိတ်ဆက်ထားသည်၊ ၎င်းသည် အီးမေးများ၊ အက်ပ်များနှင့် ဝဘ်ဆိုက်များအပါအဝင် သင့်ကွန်ရက်လုပ်ဆောင်ချက်များကို စောင့်ကြည့်နိုင်သည်။"</string>
    +     <string name="monitoring_description_app_personal" msgid="484599052118316268">"သင်သည် <xliff:g id="APPLICATION">%1$s</xliff:g> သို့ ချိတ်ဆက်ထားသည်။ ၎င်းသည် အီးမေးလ်များ၊ အက်ပ်များနှင့် ဝဘ်ဆိုက်များအပါအဝင် သင့်ကွန်ရက်လုပ်ဆောင်ချက်ကို စောင့်ကြည့်နိုင်သည်။"</string>
    ++    <string name="branded_monitoring_description_app_personal" msgid="2669518213949202599">"သင်သည် အီးမေးလ်၊ အက်ပ်နှင့် ဝဘ်ဆိုက်များအပါအဝင် သင့်ကိုယ်ရေးကိုယ်တာ ကွန်ရက်အသုံးပြုမှုကို စောင့်ကြည့်နိုင်သည့် <xliff:g id="APPLICATION">%1$s</xliff:g> သို့ ချိတ်ဆက်ထားပါသည်။"</string>
    +     <string name="monitoring_description_app_work" msgid="1754325860918060897">"သင့်အလုပ်ပရိုဖိုင်ကို <xliff:g id="ORGANIZATION">%1$s</xliff:g> မှစီမံခန့်ခွဲသည်။ ၎င်းကို <xliff:g id="APPLICATION">%2$s</xliff:g> သို့ ချိတ်ဆက်ထားသည်၊ ၎င်းသည် အီးမေးလ်များ၊ အက်ပ်များနှင့် ဝဘ်ဆိုက်များအပါအဝင် သင့်အလုပ်ကွန်ရက်လုပ်ဆောင်ချက်ကို စောင့်ကြည့်နိုင်သည်။ \n\nအချက်အလက်များ ပိုမိုရယူရန် သင်၏ စီမံခန့်ခွဲသူကို ဆက်သွယ်ပါ။"</string>
    +     <string name="monitoring_description_app_personal_work" msgid="4946600443852045903">"သင့်အလုပ် ပရိုဖိုင်ကို <xliff:g id="ORGANIZATION">%1$s</xliff:g> မှစီမံခန့်ခွဲသည်။ ၎င်းကို <xliff:g id="APPLICATION_WORK">%2$s</xliff:g> သို့ ချိတ်ဆက်ထားသည်၊ ၎င်းသည် အီးမေးလ်များ၊ အက်ပ်များနှင့် ဝဘ်ဆိုက်များအပါအဝင် သင့်အလုပ်ကွန်ရက်လုပ်ဆောင်ချက်ကို စောင့်ကြည့်နိုင်သည်။ \n\n သင်သည်<xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g> ကိုလည်း ချိတ်ဆက်ထားသည်၊ ၎င်းသည် သင့်ကိုယ်ပိုင်ကွန်ရက်လုပ်ဆောင်ချက်များကို စောင့်ကြည့်နိုင်သည်။"</string>
    +     <string name="monitoring_description_vpn_app_device_owned" msgid="4970443827043261703">"သင့်စက်ကိရိယာကို <xliff:g id="ORGANIZATION">%1$s</xliff:g> မှစီမံခန့်ခွဲပါသည်။ \n\n စီမံခန့်ခွဲသူသည် ကြိုတင်ပြင်ဆင်မှုများ၊ စုပေါင်းဝင်ရောက်ခွင့်၊ အက်ပ်များ၊ သင့်ကိရိယာနှင့်သက်ဆိုင်သော ဒေတာနှင့် သင့်ကိရိယာ၏ တည်နေရာအချက်အလက်များကို စောင့်ကြည့်ပြီး စီမံခန့်ခွဲနိုင်သည်။ \n\nသင်သည် <xliff:g id="APPLICATION">%2$s</xliff:g> သို့ချိတ်ဆက်ထားသည်၊ ၎င်းသည် အီးမေးလ်များ၊ အက်ပ်များ၊ နှင့် ဝဘ်ဆိုက်များအပါအဝင် သင့်ကွန်ရက်လုပ်ဆောင်ချက်ကို စောင့်ကြည့်နိုင်သည်။ \n\nအချက်အလက်များ ပိုမိုရယူရန် သင်၏ စီမံခန့်ခွဲသူကို ဆက်သွယ်ပါ။"</string>
    +@@ -492,8 +494,6 @@
    +     <string name="clock_seconds_desc" msgid="6282693067130470675">"အခြေအနေပြနေရာမှာ နာရီ စက္ကန့်များကို ပြပါ။ ဘက်ထရီ သက်တမ်းကို အကျိုးသက်ရောက်နိုင်တယ်။"</string>
    +     <string name="qs_rearrange" msgid="8060918697551068765">"အမြန် ဆက်တင်များကို ပြန်စီစဉ်ရန်"</string>
    +     <string name="show_brightness" msgid="6613930842805942519">"အမြန် ဆက်တင်များထဲက တောက်ပမှုကို ပြရန်"</string>
    +-    <string name="overview_nav_bar_gesture" msgid="8579814204727917764">"မျက်နှာပြင်ခွဲကြည့်ရန် အပေါ်သို့ပွတ်ဆွဲခြင်း အမူအရာကိုဖွင့်ပါ"</string>
    +-    <string name="overview_nav_bar_gesture_desc" msgid="6329167382305102615">"ခြုံကြည့်သည့်ခလုတ်မှ အပေါ်သို့ပွတ်ဆွဲခြင်းဖြင့် မျက်နှာပြင်ခွဲကြည့်ရန် လက်ဟန်ကိုဖွင့်ပါ"</string>
    +     <string name="experimental" msgid="6198182315536726162">"စမ်းသပ်ရေး"</string>
    +     <string name="enable_bluetooth_title" msgid="5027037706500635269">"ဘလူးတုသ် ဖွင့်ရမလား။"</string>
    +     <string name="enable_bluetooth_message" msgid="9106595990708985385">"ကီးဘုတ်ကို တပ်ဘလက်နှင့် ချိတ်ဆက်ရန်၊ ပမထဦးစွာ ဘလူးတုသ်ကို ဖွင့်ပါ။"</string>
    +@@ -588,7 +588,7 @@
    +     <string name="center" msgid="4327473927066010960">"ဌာန"</string>
    +     <string name="end" msgid="125797972524818282">"ပြီးပါပြီ"</string>
    +     <string name="space" msgid="804232271282109749">"နေရာလွတ်ခြားစနစ်"</string>
    +-    <string name="menu_ime" msgid="4943221416525250684">"မန်နယူး / ကီးဘုတ်ပြောင်းစနစ်"</string>
    ++    <string name="menu_ime" msgid="4943221416525250684">"မီနူး / ကီးဘုတ်ပြောင်းစနစ်"</string>
    +     <string name="select_button" msgid="1597989540662710653">"ပေါင်းထည့်ရန် ခလုတ်ကိုရွေးပါ"</string>
    +     <string name="add_button" msgid="4134946063432258161">"ခလုတ်ပေါင်းထည့်ပါ"</string>
    +     <string name="save" msgid="2311877285724540644">"သိမ်းရန်"</string>
    +@@ -651,4 +651,5 @@
    +     <string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"<xliff:g id="ID_1">%s</xliff:g> ဆက်တင်များကို ဖွင့်ပါ။"</string>
    +     <string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"ဆက်တင်များ၏ အစီအစဉ်ကို တည်းဖြတ်ပါ။"</string>
    +     <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"စာမျက်နှာ <xliff:g id="ID_2">%2$d</xliff:g> အနက်မှ စာမျက်နှာ <xliff:g id="ID_1">%1$d</xliff:g>"</string>
    ++    <string name="cant_silence_or_block" msgid="999689262131488625">"အကြောင်းကြားချက်များကို အသံတိတ်ခြင်း သို့မဟုတ် ပိတ်ဆို့ခြင်းများ ပြုလုပ်၍ မရပါ"</string>
    + </resources>
    +diff --git a/packages/SystemUI/res/values-nb/strings.xml b/packages/SystemUI/res/values-nb/strings.xml
    +index 3efdd3e..02cb082 100644
    +--- a/packages/SystemUI/res/values-nb/strings.xml
    ++++ b/packages/SystemUI/res/values-nb/strings.xml
    +@@ -238,7 +238,7 @@
    +     <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"4G-data er satt på pause"</string>
    +     <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"Mobildata er satt på pause"</string>
    +     <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"Data er satt på pause"</string>
    +-    <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"Fordi den angitte datagrensen ble nådd, har enheten satt databruk på pause for resten av denne syklusen. \n\nHvis du gjenopptar bruken, kan det føre til avgifter fra operatøren din."</string>
    ++    <string name="data_usage_disabled_dialog" msgid="1841738975235283398">"Datagrensen du satte, er nådd. Du bruker ikke mobildata lenger.\n\nHvis du gjenopptar bruk av mobildata, kan gebyrer for databruk påløpe."</string>
    +     <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"Gjenoppta"</string>
    +     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Ingen Internett-forbindelse"</string>
    +     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi tilkoblet"</string>
    +@@ -404,6 +404,7 @@
    +     <string name="device_owned_footer" msgid="3802752663326030053">"Enheten kan være overvåket"</string>
    +     <string name="profile_owned_footer" msgid="8021888108553696069">"Profilen kan overvåkes"</string>
    +     <string name="vpn_footer" msgid="2388611096129106812">"Nettverket kan være overvåket"</string>
    ++    <string name="branded_vpn_footer" msgid="2168111859226496230">"Nettverket kan bli overvåket"</string>
    +     <string name="monitoring_title_device_owned" msgid="7121079311903859610">"Enhetsovervåking"</string>
    +     <string name="monitoring_title_profile_owned" msgid="6790109874733501487">"Profilovervåking"</string>
    +     <string name="monitoring_title" msgid="169206259253048106">"Nettverksovervåking"</string>
    +@@ -416,6 +417,7 @@
    +     <string name="legacy_vpn_name" msgid="6604123105765737830">"VPN"</string>
    +     <string name="monitoring_description_app" msgid="6259179342284742878">"Enheten er koblet til <xliff:g id="APPLICATION">%1$s</xliff:g>, som kan overvåke nettverksaktiviteten din, inkludert e-post, apper og nettsteder."</string>
    +     <string name="monitoring_description_app_personal" msgid="484599052118316268">"Enheten er koblet til <xliff:g id="APPLICATION">%1$s</xliff:g>, som kan overvåke den personlige nettverksaktiviteten din, inkludert e-post, apper og nettsteder."</string>
    ++    <string name="branded_monitoring_description_app_personal" msgid="2669518213949202599">"Enheten er koblet til <xliff:g id="APPLICATION">%1$s</xliff:g>, som kan overvåke den personlige nettverksaktiviteten din, inkludert e-post, apper og nettsteder."</string>
    +     <string name="monitoring_description_app_work" msgid="1754325860918060897">"Work-profilen din administreres av <xliff:g id="ORGANIZATION">%1$s</xliff:g>. Den er koblet til <xliff:g id="APPLICATION">%2$s</xliff:g>, som kan overvåke nettverksaktiviteten din på jobben, inkludert e-post, apper og nettsteder.\n\nFor å få mer informasjon, ta kontakt med administratoren."</string>
    +     <string name="monitoring_description_app_personal_work" msgid="4946600443852045903">"Work-profilen din administreres av <xliff:g id="ORGANIZATION">%1$s</xliff:g>. Den er koblet til <xliff:g id="APPLICATION_WORK">%2$s</xliff:g>, som kan overvåke nettverksaktiviteten din på jobben, inkludert e-post, apper og nettsteder.\n\nDu er også koblet til <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g>, som kan overvåke den personlige nettverksaktiviteten din."</string>
    +     <string name="monitoring_description_vpn_app_device_owned" msgid="4970443827043261703">"Enheten din administreres av <xliff:g id="ORGANIZATION">%1$s</xliff:g>.\n\nAdministratoren din kan overvåke og administrere innstillinger, bedriftstilgang, apper, data tilknyttet enheten din og enhetens posisjonsinformasjon.\n\nDu er koblet til <xliff:g id="APPLICATION">%2$s</xliff:g>, som kan overvåke nettverksaktiviteten din, inkludert e-post, apper og nettsteder.\n\nFor mer informasjon, ta kontakt med administratoren."</string>
    +@@ -492,8 +494,6 @@
    +     <string name="clock_seconds_desc" msgid="6282693067130470675">"Vis sekunder i statusfeltet på klokken. Det kan påvirke batteritiden."</string>
    +     <string name="qs_rearrange" msgid="8060918697551068765">"Omorganiser hurtiginnstillingene"</string>
    +     <string name="show_brightness" msgid="6613930842805942519">"Vis lysstyrke i hurtiginnstillingene"</string>
    +-    <string name="overview_nav_bar_gesture" msgid="8579814204727917764">"Slå på delt skjerm ved å sveipe opp"</string>
    +-    <string name="overview_nav_bar_gesture_desc" msgid="6329167382305102615">"Slå på bevegelsen for å åpne delt skjerm ved å sveipe opp fra Oversikt-knappen"</string>
    +     <string name="experimental" msgid="6198182315536726162">"På forsøksstadiet"</string>
    +     <string name="enable_bluetooth_title" msgid="5027037706500635269">"Vil du slå på Bluetooth?"</string>
    +     <string name="enable_bluetooth_message" msgid="9106595990708985385">"For å koble tastaturet til nettbrettet ditt må du først slå på Bluetooth."</string>
    +@@ -651,4 +651,5 @@
    +     <string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"Åpne <xliff:g id="ID_1">%s</xliff:g>-innstillingene."</string>
    +     <string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"Endre rekkefølgen på innstillingene."</string>
    +     <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"Side <xliff:g id="ID_1">%1$d</xliff:g> av <xliff:g id="ID_2">%2$d</xliff:g>"</string>
    ++    <string name="cant_silence_or_block" msgid="999689262131488625">"Varslinger kan ikke ignoreres eller blokkeres"</string>
    + </resources>
    +diff --git a/packages/SystemUI/res/values-ne-rNP/strings.xml b/packages/SystemUI/res/values-ne-rNP/strings.xml
    +index 07d0795..79d4b84 100644
    +--- a/packages/SystemUI/res/values-ne-rNP/strings.xml
    ++++ b/packages/SystemUI/res/values-ne-rNP/strings.xml
    +@@ -238,7 +238,7 @@
    +     <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"4G डेटा रोकिएको छ"</string>
    +     <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"सेल्यूलर डेटा रोकिएको छ"</string>
    +     <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"डेटा रोकिएको छ"</string>
    +-    <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"तपाईंले सेट गर्नुभएको डेटाको सीमा पुगेकाले, यन्त्रले यस चक्रको बाँकी भागका लागि डेटाको प्रयोग रोकेको छ।\n\nपुन: सुरू गर्दा तपाईंको क्यारियरले शुल्कहरू लिन सक्छ।"</string>
    ++    <string name="data_usage_disabled_dialog" msgid="1841738975235283398">"तपाईँले सेट गर्नुभएको डेटाको सीमामा पुगिएको छ। अबदेखि तपाईँ सेलुलर डेटाको प्रयोग गर्नुहुने छैन। \n\nतपाईँले प्रयोग जारी राख्नुभयो भने डेटा प्रयोगका शुल्कहरू लाग्न सक्छन्।"</string>
    +     <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"पुनः सुरु गर्नुहोस्"</string>
    +     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"इन्टरनेट जडान छैन"</string>
    +     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi जडित"</string>
    +@@ -404,6 +404,7 @@
    +     <string name="device_owned_footer" msgid="3802752663326030053">"उपकरण अनुगमन हुन सक्छ"</string>
    +     <string name="profile_owned_footer" msgid="8021888108553696069">"प्रोफाइल अनुगमन हुन सक्छ"</string>
    +     <string name="vpn_footer" msgid="2388611096129106812">"सञ्जाल अनुगमित हुन सक्छ"</string>
    ++    <string name="branded_vpn_footer" msgid="2168111859226496230">"नेटवर्कको अनुगमन गरिने सम्भावना छ"</string>
    +     <string name="monitoring_title_device_owned" msgid="7121079311903859610">"उपकरण अनुगमन"</string>
    +     <string name="monitoring_title_profile_owned" msgid="6790109874733501487">"प्रोफाइल अनुगमन गर्दै"</string>
    +     <string name="monitoring_title" msgid="169206259253048106">"सञ्जाल अनुगमन"</string>
    +@@ -416,6 +417,7 @@
    +     <string name="legacy_vpn_name" msgid="6604123105765737830">"VPN"</string>
    +     <string name="monitoring_description_app" msgid="6259179342284742878">"तपाईँ <xliff:g id="APPLICATION">%1$s</xliff:g> सँग जडित हुनुहुन्छ जसले इ-मेल, अनुप्रयोगहरू र वेबसाइट लगायतका तपाईँका नेटवर्क गतिविधिको अनुगमन गर्न सक्छ।"</string>
    +     <string name="monitoring_description_app_personal" msgid="484599052118316268">"तपाईँ <xliff:g id="APPLICATION">%1$s</xliff:g> सँग जडित हुनुहुन्छ जसले इ-मेल, अनुप्रयोगहरू र वेबसाइट लगायतका तपाईँको निजी नेटवर्क गतिविधिका अनुगमन गर्न सक्छ।"</string>
    ++    <string name="branded_monitoring_description_app_personal" msgid="2669518213949202599">"तपाईं <xliff:g id="APPLICATION">%1$s</xliff:g> मा जोडिनुभएको छ जसले इमेल, अनुप्रयोग र वेबसाइटहरू लगायतको तपाईंको  व्यक्तिगत नेटवर्क सम्बन्धी गतिविधिको अनुगमन गर्न सक्छ।"</string>
    +     <string name="monitoring_description_app_work" msgid="1754325860918060897">"तपाईँको कार्य प्रोफाइल <xliff:g id="ORGANIZATION">%1$s</xliff:g> द्वारा व्यवस्थापन गरिन्छ। यो <xliff:g id="APPLICATION">%2$s</xliff:g> सँग जोडिएको छ जसले इमेल, अनुप्रयोगहरू, र वेबसाइटहरू लगायतका तपाईँका नेटवर्क गतिविधि अनुगमन गर्न सक्छ।\n\nथप जानकारीको लागि, आफ्नो प्रशासकलाई सम्पर्क गर्नुहोस्।"</string>
    +     <string name="monitoring_description_app_personal_work" msgid="4946600443852045903">"तपाईँको कार्य प्रोफाइल <xliff:g id="ORGANIZATION">%1$s</xliff:g> द्वारा व्यवस्थापन गरिन्छ। यो <xliff:g id="APPLICATION_WORK">%2$s</xliff:g> सँग जोडिएको छ जसले इमेल, अनुप्रयोगहरू, र वेबसाइटहरू लगायतका तपाईँका नेटवर्क गतिविधि अनुगमन गर्न सक्छ।\n\nतपाईँ <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g> सँग पनि जडित हुनुहुन्छ, जसले तपाईँको व्यक्तिगत नेटवर्क गतिविधि अनुगमन गर्न सक्छ।"</string>
    +     <string name="monitoring_description_vpn_app_device_owned" msgid="4970443827043261703">"तपाईँको उपकरण <xliff:g id="ORGANIZATION">%1$s</xliff:g> द्वारा व्यवस्थित गरिन्छ।\n\nतपाईँको प्रशासकले तपाईँको यन्त्र र त्यसको स्थान जानकारीमार्फत सेटिङहरू,  कर्पोरेट पहुँच, अनुप्रयोगहरू, तपाईँको यन्त्रसँग सम्बद्ध डेटा  र तपाईँको यन्त्रको स्थान जानकारीको अनुगमन र व्यवस्थापन गर्न सक्छ।\n\nतपाईँ <xliff:g id="APPLICATION">%2$s</xliff:g> सँग जडित हुनुहुन्छ जसले इमेल, अनुप्रयोगहरू, र वेबसाइटहरू लगायतका तपाईँका नेटवर्क गतिविधिका अनुगमन गर्न सक्छ।\n\nथप जानकारीको लागि तपाईको प्रशासकलाई सम्पर्क गर्नुहोस्।"</string>
    +@@ -492,8 +494,6 @@
    +     <string name="clock_seconds_desc" msgid="6282693067130470675">"वस्तुस्थिति पट्टीको घडीमा सेकेन्ड देखाउनुहोस्। ब्याट्री आयु प्रभावित हुन सक्छ।"</string>
    +     <string name="qs_rearrange" msgid="8060918697551068765">"द्रुत सेटिङहरू पुनः व्यवस्थित गर्नुहोस्"</string>
    +     <string name="show_brightness" msgid="6613930842805942519">"द्रुत सेटिङहरूमा उज्यालो देखाउनुहोस्"</string>
    +-    <string name="overview_nav_bar_gesture" msgid="8579814204727917764">"विभाजित-स्क्रिन स्वाइप-अप इशारा सक्षम गर्नुहोस्"</string>
    +-    <string name="overview_nav_bar_gesture_desc" msgid="6329167382305102615">"परिदृश्य बटनदेखि माथि स्वाइप गरी विभाजित-स्क्रिन प्रविष्ट गर्न इसारालाई सक्रिय गर्नुहोस्"</string>
    +     <string name="experimental" msgid="6198182315536726162">"प्रयोगात्मक"</string>
    +     <string name="enable_bluetooth_title" msgid="5027037706500635269">"ब्लुटुथ सक्रिय पार्ने हो?"</string>
    +     <string name="enable_bluetooth_message" msgid="9106595990708985385">"आफ्नो ट्याब्लेटसँग किबोर्ड जोड्न, पहिले तपाईँले ब्लुटुथ सक्रिय गर्नुपर्छ।"</string>
    +@@ -651,4 +651,5 @@
    +     <string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"<xliff:g id="ID_1">%s</xliff:g> सम्बन्धी सेटिङहरूलाई खोल्नुहोस्।"</string>
    +     <string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"सेटिङहरूको क्रमलाई सम्पादन गर्नुहोस्।"</string>
    +     <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"<xliff:g id="ID_2">%2$d</xliff:g> मध्ये पृष्ठ <xliff:g id="ID_1">%1$d</xliff:g>"</string>
    ++    <string name="cant_silence_or_block" msgid="999689262131488625">"सूचनाहरूलाई मौन गर्न वा यसमाथि रोक लगाउन मिल्दैन"</string>
    + </resources>
    +diff --git a/packages/SystemUI/res/values-nl/strings.xml b/packages/SystemUI/res/values-nl/strings.xml
    +index 9509229..a2a4365 100644
    +--- a/packages/SystemUI/res/values-nl/strings.xml
    ++++ b/packages/SystemUI/res/values-nl/strings.xml
    +@@ -238,7 +238,7 @@
    +     <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"4G-data zijn onderbroken"</string>
    +     <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"Mobiele gegevens zijn onderbroken"</string>
    +     <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"Gegevens zijn onderbroken"</string>
    +-    <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"Omdat de ingestelde gegevenslimiet is bereikt, heeft het apparaat het gegevensverbruik onderbroken voor de rest van deze cyclus.\n\nAls u het gegevensverbruik hervat, kan je provider kosten in rekening brengen."</string>
    ++    <string name="data_usage_disabled_dialog" msgid="1841738975235283398">"De ingestelde datalimiet is bereikt. Je gebruikt geen mobiele data meer.\n\nAls je hervat, kunnen er kosten voor datagebruik in rekening worden gebracht."</string>
    +     <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"Hervatten"</string>
    +     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Geen internetverbinding"</string>
    +     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Verbonden via wifi"</string>
    +@@ -404,6 +404,7 @@
    +     <string name="device_owned_footer" msgid="3802752663326030053">"Apparaat wordt mogelijk gecontroleerd"</string>
    +     <string name="profile_owned_footer" msgid="8021888108553696069">"Profiel kan worden gecontroleerd"</string>
    +     <string name="vpn_footer" msgid="2388611096129106812">"Netwerk kan worden gecontroleerd"</string>
    ++    <string name="branded_vpn_footer" msgid="2168111859226496230">"Netwerk kan worden gecontroleerd"</string>
    +     <string name="monitoring_title_device_owned" msgid="7121079311903859610">"Apparaatcontrole"</string>
    +     <string name="monitoring_title_profile_owned" msgid="6790109874733501487">"Profielcontrole"</string>
    +     <string name="monitoring_title" msgid="169206259253048106">"Netwerkcontrole"</string>
    +@@ -416,6 +417,7 @@
    +     <string name="legacy_vpn_name" msgid="6604123105765737830">"VPN"</string>
    +     <string name="monitoring_description_app" msgid="6259179342284742878">"U bent verbonden met <xliff:g id="APPLICATION">%1$s</xliff:g>, waarmee je netwerkactiviteit kan worden gecontroleerd, inclusief e-mails, apps en websites."</string>
    +     <string name="monitoring_description_app_personal" msgid="484599052118316268">"U bent verbonden met <xliff:g id="APPLICATION">%1$s</xliff:g>, waarmee je persoonlijke netwerkactiviteit kan worden gecontroleerd, inclusief e-mails, apps en websites."</string>
    ++    <string name="branded_monitoring_description_app_personal" msgid="2669518213949202599">"Je bent verbonden met <xliff:g id="APPLICATION">%1$s</xliff:g>, waarmee je persoonlijke netwerkactiviteit kan worden gecontroleerd, inclusief e-mails, apps en websites."</string>
    +     <string name="monitoring_description_app_work" msgid="1754325860918060897">"Je werkprofiel wordt beheerd door <xliff:g id="ORGANIZATION">%1$s</xliff:g>. Deze is verbonden met <xliff:g id="APPLICATION">%2$s</xliff:g>, waarmee je werkgerelateerde netwerkactiviteit kan worden gecontroleerd, inclusief e-mails, apps en websites.\n\nNeem contact op met je beheerder voor meer informatie."</string>
    +     <string name="monitoring_description_app_personal_work" msgid="4946600443852045903">"Je werkprofiel wordt beheerd door <xliff:g id="ORGANIZATION">%1$s</xliff:g>. Deze is verbonden met <xliff:g id="APPLICATION_WORK">%2$s</xliff:g>, waarmee je werkgerelateerde netwerkactiviteit kan worden gecontroleerd, inclusief e-mails, apps en websites.\n\nU bent ook verbonden met <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g>, waarmee je persoonlijke netwerkactiviteit kan worden gecontroleerd."</string>
    +     <string name="monitoring_description_vpn_app_device_owned" msgid="4970443827043261703">"Je apparaat wordt beheerd door <xliff:g id="ORGANIZATION">%1$s</xliff:g>.\n\nJe beheerder kan instellingen, zakelijke toegang, apps, gekoppelde apparaatgegevens en locatiegegevens voor je apparaat controleren en beheren.\n\nU bent verbonden met <xliff:g id="APPLICATION">%2$s</xliff:g> waarmee je netwerkactiviteit kan worden gecontroleerd, inclusief e-mails, apps en websites.\n\nNeem contact op met je beheerder voor meer informatie."</string>
    +@@ -492,8 +494,6 @@
    +     <string name="clock_seconds_desc" msgid="6282693067130470675">"Klokseconden op de statusbalk weergeven. Kan van invloed zijn op de accuduur."</string>
    +     <string name="qs_rearrange" msgid="8060918697551068765">"Snelle instellingen opnieuw indelen"</string>
    +     <string name="show_brightness" msgid="6613930842805942519">"Helderheid weergeven in Snelle instellingen"</string>
    +-    <string name="overview_nav_bar_gesture" msgid="8579814204727917764">"Omhoog vegen voor gesplitst scherm inschakelen"</string>
    +-    <string name="overview_nav_bar_gesture_desc" msgid="6329167382305102615">"Gebaar inschakelen om gesplitst scherm te openen door vanaf de knop Overzicht omhoog te vegen"</string>
    +     <string name="experimental" msgid="6198182315536726162">"Experimenteel"</string>
    +     <string name="enable_bluetooth_title" msgid="5027037706500635269">"Bluetooth inschakelen?"</string>
    +     <string name="enable_bluetooth_message" msgid="9106595990708985385">"Als je je toetsenbord wilt verbinden met je tablet, moet je eerst Bluetooth inschakelen."</string>
    +@@ -651,4 +651,5 @@
    +     <string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"<xliff:g id="ID_1">%s</xliff:g>-instellingen openen."</string>
    +     <string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"Volgorde van instellingen bewerken."</string>
    +     <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"Pagina <xliff:g id="ID_1">%1$d</xliff:g> van <xliff:g id="ID_2">%2$d</xliff:g>"</string>
    ++    <string name="cant_silence_or_block" msgid="999689262131488625">"Meldingen kunnen niet op stil worden gezet of worden geblokkeerd"</string>
    + </resources>
    +diff --git a/packages/SystemUI/res/values-pa-rIN/strings.xml b/packages/SystemUI/res/values-pa-rIN/strings.xml
    +index 17c1261..e000541 100644
    +--- a/packages/SystemUI/res/values-pa-rIN/strings.xml
    ++++ b/packages/SystemUI/res/values-pa-rIN/strings.xml
    +@@ -238,7 +238,7 @@
    +     <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"4G ਡੈਟਾ ਰੁਕ ਗਿਆ ਹੈ"</string>
    +     <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"ਸੈਲਿਊਲਰ ਡੈਟਾ ਰੁਕ ਗਿਆ ਹੈ"</string>
    +     <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"ਡੈਟਾ ਰੁਕ ਗਿਆ ਹੈ"</string>
    +-    <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"ਕਿਉਂਕਿ ਤੁਹਾਡੀ ਸੈਟ ਡੈਟਾ ਸੀਮਾ ਪੂਰੀ ਹੋ ਗਈ ਸੀ,  ਡੀਵਾਈਸ ਨੇ ਇਸ ਬਾਕੀ ਚੱਕਰ ਲਈ ਡੈਟਾ ਉਪਯੋਗ ਰੋਕ ਦਿੱਤਾ ਹੈ।\n\nਇਸਨੂੰ ਦੁਬਾਰਾ ਸ਼ੁਰੂ ਕਰਨ ਨਾਲ ਤੁਹਾਡੇ ਕੈਰੀਅਰ ਵੱਲੋਂ ਖ਼ਰਚੇ ਪਾਏ ਜਾ ਸਕਦੇ ਹਨ।"</string>
    ++    <string name="data_usage_disabled_dialog" msgid="1841738975235283398">"ਤੁਸੀਂ ਤੁਹਾਡੇ ਵੱਲੋਂ ਸੈੱਟ ਕੀਤੀ ਗਈ ਡੈਟਾ ਸੀਮਾ \'ਤੇ ਪਹੁੰਚ ਚੁੱਕੇ ਹੋ। ਤੁਸੀਂ ਹੁਣ ਸੈਲਿਊਲਰ ਡੈਟੇ ਦੀ ਵਰਤੋਂ ਨਹੀਂ ਕਰ ਰਹੇ ਹੋ।\n\nਜੇਕਰ ਤੁਸੀਂ ਮੁੜ-ਸ਼ੁਰੂ ਕਰਦੇ ਹੋ, ਤਾਂ ਡੈਟਾ ਵਰਤੋਂ ਲਈ ਖਰਚੇ ਲਾਗੂ ਹੋ ਸਕਦੇ ਹਨ।"</string>
    +     <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"ਦੁਬਾਰਾ ਸ਼ੁਰੂ ਕਰੋ"</string>
    +     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"ਕੋਈ ਇੰਟਰਨੈਟ ਕਨੈਕਸ਼ਨ ਨਹੀਂ"</string>
    +     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi ਕਨੈਕਟ ਕੀਤਾ"</string>
    +@@ -404,6 +404,7 @@
    +     <string name="device_owned_footer" msgid="3802752663326030053">"ਡੀਵਾਈਸ ਦਾ ਨਿਰੀਖਣ ਕੀਤਾ ਜਾ ਸਕਦਾ ਹੈ"</string>
    +     <string name="profile_owned_footer" msgid="8021888108553696069">"ਪ੍ਰੋਫਾਈਲ ਦਾ ਨਿਰੀਖਣ ਕੀਤਾ ਜਾ ਸਕਦਾ ਹੈ"</string>
    +     <string name="vpn_footer" msgid="2388611096129106812">"ਨੈੱਟਵਰਕ ਦਾ ਨਿਰੀਖਣ ਕੀਤਾ ਜਾ ਸਕਦਾ ਹੈ"</string>
    ++    <string name="branded_vpn_footer" msgid="2168111859226496230">"ਹੋ ਸਕਦਾ ਹੈ ਨੈੱਟਵਰਕ ਦੀ ਨਿਗਰਾਨੀ ਹੋ ਰਹੀ ਹੋਵੇ"</string>
    +     <string name="monitoring_title_device_owned" msgid="7121079311903859610">"ਡੀਵਾਈਸ ਦਾ ਨਿਰੀਖਣ ਕਰਨਾ"</string>
    +     <string name="monitoring_title_profile_owned" msgid="6790109874733501487">"ਪ੍ਰੋਫਾਈਲ ਦਾ ਨਿਰੀਖਣ ਕਰਨਾ"</string>
    +     <string name="monitoring_title" msgid="169206259253048106">"ਨੈੱਟਵਰਕ ਨਿਰੀਖਣ ਕਰ ਰਿਹਾ ਹੈ"</string>
    +@@ -416,6 +417,7 @@
    +     <string name="legacy_vpn_name" msgid="6604123105765737830">"VPN"</string>
    +     <string name="monitoring_description_app" msgid="6259179342284742878">"ਤੁਸੀਂ <xliff:g id="APPLICATION">%1$s</xliff:g> ਨਾਲ ਕਨੈਕਟ ਹੋ, ਜੋ ਈਮੇਲ, ਐਪਸ ਅਤੇ ਵੈਬਸਫ਼ਿਆਂ ਸਮੇਤ ਤੁਹਾਡੀ ਨੈੱਟਵਰਕ ਗਤੀਵਿਧੀ ਦਾ ਨਿਰੀਖਣ ਕਰ ਸਕਦੀ ਹੈ।"</string>
    +     <string name="monitoring_description_app_personal" msgid="484599052118316268">"ਤੁਸੀਂ <xliff:g id="APPLICATION">%1$s</xliff:g> ਨਾਲ ਕਨੈਕਟ ਹੋ, ਜੋ ਈਮੇਲ, ਐਪਸ ਅਤੇ ਵੈਬਸਫ਼ਿਆਂ ਸਮੇਤ ਤੁਹਾਡੀ ਨੈੱਟਵਰਕ ਗਤੀਵਿਧੀ ਦਾ ਨਿਰੀਖਣ ਕਰ ਸਕਦੀ ਹੈ।"</string>
    ++    <string name="branded_monitoring_description_app_personal" msgid="2669518213949202599">"ਤੁਸੀਂ <xliff:g id="APPLICATION">%1$s</xliff:g> ਨਾਲ ਕਨੈਕਟ ਹੋ, ਜੋ ਈਮੇਲਾਂ, ਐਪਾਂ, ਅਤੇ ਵੈੱਬਸਾਈਟਾਂ ਸਮੇਤ ਤੁਹਾਡੀ ਨਿੱਜੀ ਨੈੱਟਵਰਕ ਸਰਗਰਮੀ ਦੀ ਨਿਗਰਾਨੀ ਕਰ ਸਕਦੀ ਹੈ।"</string>
    +     <string name="monitoring_description_app_work" msgid="1754325860918060897">"ਤੁਹਾਡੀ ਕਾਰਜ ਪ੍ਰੋਫ਼ਾਈਲ <xliff:g id="ORGANIZATION">%1$s</xliff:g> ਦੁਆਰਾ ਵਿਵਸਥਿਤ ਕੀਤੀ ਜਾਂਦੀ ਹੈ। ਇਹ <xliff:g id="APPLICATION">%2$s</xliff:g> ਨਾਲ ਕਨੈਕਟ ਹੈ, ਜੋ ਈਮੇਲ, ਐਪਸ ਅਤੇ ਵੈਬਸਫ਼ਿਆਂ ਸਮੇਤ ਤੁਹਾਡੀ ਨੈੱਟਵਰਕ ਗਤੀਵਿਧੀ ਦਾ ਨਿਰੀਖਣ ਕਰ ਸਕਦੀ ਹੈ।\n\nਹੋਰ ਜਾਣਕਾਰੀ ਲਈ, ਆਪਣੇ ਪ੍ਰਬੰਧਕ ਨੂੰ ਸੰਪਰਕ ਕਰੋ।"</string>
    +     <string name="monitoring_description_app_personal_work" msgid="4946600443852045903">"ਤੁਹਾਡੀ ਕਾਰਜ ਪ੍ਰੋਫ਼ਾਈਲ <xliff:g id="ORGANIZATION">%1$s</xliff:g> ਦੁਆਰਾ ਵਿਵਸਥਿਤ ਕੀਤੀ ਜਾਂਦੀ ਹੈ। ਇਹ <xliff:g id="APPLICATION_WORK">%2$s</xliff:g> ਨਾਲ ਕਨੈਕਟ ਹੈ, ਜੋ ਈਮੇਲ, ਐਪਸ ਅਤੇ ਵੈਬਸਫ਼ਿਆਂ ਸਮੇਤ ਤੁਹਾਡੀ ਨੈੱਟਵਰਕ ਗਤੀਵਿਧੀ ਦਾ ਨਿਰੀਖਣ ਕਰ ਸਕਦੀ ਹੈ।\n\nਤੁਸੀਂ <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g> ਨਾਲ ਵੀ ਕਨੈਕਟ ਹੋ, ਜੋ ਤੁਹਾਡੀ ਨਿੱਜੀ ਨੈੱਟਵਰਕ ਗਤੀਵਿਧੀ ਦਾ ਨਿਰੀਖਣ ਕਰ ਸਕਦਾ ਹੈ।"</string>
    +     <string name="monitoring_description_vpn_app_device_owned" msgid="4970443827043261703">"ਤੁਹਾਡੀ ਡੀਵਾਈਸ <xliff:g id="ORGANIZATION">%1$s</xliff:g> ਦੁਆਰਾ ਵਿਵਸਥਿਤ ਕੀਤੀ ਜਾਂਦੀ ਹੈ।\n\nਪ੍ਰਬੰਧਕ ਸੈਟਿੰਗਾਂ, ਕਾਰਪੋਰੇਟ ਪਹੁੰਚ, ਐਪਸ, ਤੁਹਾਡੀ ਡੀਵਾਈਸ ਨਾਲ ਸੰਬੰਧਿਤ ਡੈਟਾ ਅਤੇ ਤੁਹਾਡੀ ਡੀਵਾਈਸ ਦੀ ਨਿਰਧਾਰਿਤ ਸਥਾਨ ਜਾਣਕਾਰੀ ਦਾ ਨਿਰੀਖਣ ਅਤੇ ਉਸਨੂੰ ਵਿਵਸਥਿਤ ਕਰ ਸਕਦਾ ਹੈ।\n\nਤੁਸੀਂ ਇੱਕ <xliff:g id="APPLICATION">%2$s</xliff:g> ਨਾਲ ਕਨੈਕਟ ਹੋ, ਜੋ ਈਮੇਲ, ਐਪਸ ਅਤੇ ਵੈੱਬਪੰਨੇ ਸਮੇਤ ਤੁਹਾਡੀ ਨੈੱਟਵਰਕ ਗਤੀਵਿਧੀ ਦੀ ਨਿਗਰਾਨੀ ਕਰ ਸਕਦਾ ਹੈ।\n\nਹੋਰ ਜਾਣਕਾਰੀ ਲਈ, ਆਪਣੇ ਪ੍ਰਬੰਧਕ ਨੂੰ ਸੰਪਰਕ ਕਰੋ।"</string>
    +@@ -492,8 +494,6 @@
    +     <string name="clock_seconds_desc" msgid="6282693067130470675">"ਸਥਿਤੀ ਬਾਰ ਵਿੱਚ ਘੜੀ ਸਕਿੰਟ ਦਿਖਾਓ। ਬੈਟਰੀ ਸਮਰੱਥਾ ਤੇ ਅਸਰ ਪੈ ਸਕਦਾ ਹੈ।"</string>
    +     <string name="qs_rearrange" msgid="8060918697551068765">"ਤਤਕਾਲ ਸੈਟਿੰਗਾਂ ਨੂੰ ਦੁਬਾਰਾ ਕ੍ਰਮ ਦਿਓ"</string>
    +     <string name="show_brightness" msgid="6613930842805942519">"ਤਤਕਾਲ ਸੈਟਿੰਗਾਂ ਵਿੱਚ ਚਮਕ ਦਿਖਾਓ"</string>
    +-    <string name="overview_nav_bar_gesture" msgid="8579814204727917764">"ਸਪਲਿਟ-ਸਕ੍ਰੀਨ ਸਵਾਈਪ-ਅੱਪ ਸੰਕੇਤ ਨੂੰ ਯੋਗ ਬਣਾਓ"</string>
    +-    <string name="overview_nav_bar_gesture_desc" msgid="6329167382305102615">"ਰੂਪ-ਰੇਖਾ ਬਟਨ ਤੋਂ ਉੱਪਰ ਵੱਲ ਸਵਾਈਪ ਕਰਨ ਦੁਆਰਾ ਸਪਲਿਟ-ਸਕ੍ਰੀਨ ਵਿੱਚ ਦਾਖਲ ਹੋਣ ਲਈ ਸੰਕੇਤ ਨੂੰ ਯੋਗ ਬਣਾਓ"</string>
    +     <string name="experimental" msgid="6198182315536726162">"ਪ੍ਰਯੋਗਾਤਮਿਕ"</string>
    +     <string name="enable_bluetooth_title" msgid="5027037706500635269">"Bluetooth ਚਾਲੂ ਕਰੋ?"</string>
    +     <string name="enable_bluetooth_message" msgid="9106595990708985385">"ਆਪਣੇ ਟੈਬਲੇਟ ਨਾਲ ਆਪਣਾ ਕੀ-ਬੋਰਡ ਕਨੈਕਟ ਕਰਨ ਲਈ, ਤੁਹਾਨੂੰ ਪਹਿਲਾਂ Bluetooth ਚਾਲੂ ਕਰਨ ਦੀ ਜ਼ਰੂਰਤ ਹੈ।"</string>
    +@@ -651,4 +651,5 @@
    +     <string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"<xliff:g id="ID_1">%s</xliff:g> ਸੈਟਿੰਗਾਂ ਖੋਲ੍ਹੋ।"</string>
    +     <string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"ਸੈਟਿੰਗਾਂ ਦੇ ਕ੍ਰਮ ਦਾ ਸੰਪਾਦਨ ਕਰੋ।"</string>
    +     <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"<xliff:g id="ID_2">%2$d</xliff:g> ਦਾ <xliff:g id="ID_1">%1$d</xliff:g> ਪੰਨਾ"</string>
    ++    <string name="cant_silence_or_block" msgid="999689262131488625">"ਸੂਚਨਾਵਾਂ ਨੂੰ ਖਾਮੋਸ਼ ਜਾਂ ਬਲੌਕ ਨਹੀਂ ਕੀਤਾ ਜਾ ਸਕਦਾ"</string>
    + </resources>
    +diff --git a/packages/SystemUI/res/values-pl/strings.xml b/packages/SystemUI/res/values-pl/strings.xml
    +index c86d26c..46ab85b 100644
    +--- a/packages/SystemUI/res/values-pl/strings.xml
    ++++ b/packages/SystemUI/res/values-pl/strings.xml
    +@@ -240,7 +240,7 @@
    +     <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"Transmisja danych 4G została wstrzymana"</string>
    +     <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"Komórkowa transmisja danych została wstrzymana"</string>
    +     <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"Transmisja danych została wstrzymana"</string>
    +-    <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"Ponieważ został osiągnięty ustawiony przez Ciebie limit danych, urządzenie wstrzymało użycie danych na pozostałą część tego cyklu.\n\nWznowienie może spowodować naliczenie opłat przez operatora."</string>
    ++    <string name="data_usage_disabled_dialog" msgid="1841738975235283398">"Osiągnięto ustawiony limit danych. Nie korzystasz już z komórkowej transmisji danych.\n\nJeśli włączysz ją ponownie, może zostać naliczona opłata za transmisję danych."</string>
    +     <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"Wznów"</string>
    +     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Brak internetu"</string>
    +     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi: połączono"</string>
    +@@ -408,6 +408,7 @@
    +     <string name="device_owned_footer" msgid="3802752663326030053">"Urządzenie może być monitorowane"</string>
    +     <string name="profile_owned_footer" msgid="8021888108553696069">"Profil może być monitorowany"</string>
    +     <string name="vpn_footer" msgid="2388611096129106812">"Sieć może być monitorowana"</string>
    ++    <string name="branded_vpn_footer" msgid="2168111859226496230">"Sieć może być monitorowana"</string>
    +     <string name="monitoring_title_device_owned" msgid="7121079311903859610">"Monitorowanie urządzeń"</string>
    +     <string name="monitoring_title_profile_owned" msgid="6790109874733501487">"Monitorowanie profilu"</string>
    +     <string name="monitoring_title" msgid="169206259253048106">"Monitorowanie sieci"</string>
    +@@ -420,6 +421,7 @@
    +     <string name="legacy_vpn_name" msgid="6604123105765737830">"VPN"</string>
    +     <string name="monitoring_description_app" msgid="6259179342284742878">"Masz połączenie z aplikacją <xliff:g id="APPLICATION">%1$s</xliff:g>, która może monitorować Twoją aktywność w sieci, w tym e-maile, aplikacje i strony internetowe."</string>
    +     <string name="monitoring_description_app_personal" msgid="484599052118316268">"Masz połączenie z aplikacją <xliff:g id="APPLICATION">%1$s</xliff:g>, która może monitorować Twoją prywatną aktywność w sieci, w tym e-maile, aplikacje i strony internetowe."</string>
    ++    <string name="branded_monitoring_description_app_personal" msgid="2669518213949202599">"Masz połączenie z aplikacją <xliff:g id="APPLICATION">%1$s</xliff:g>, która może monitorować Twoją prywatną aktywność w sieci, w tym e-maile, aplikacje i strony internetowe."</string>
    +     <string name="monitoring_description_app_work" msgid="1754325860918060897">"Twoim profilem do pracy zarządza <xliff:g id="ORGANIZATION">%1$s</xliff:g>. Profil jest połączony z aplikacją <xliff:g id="APPLICATION">%2$s</xliff:g>, która może monitorować Twoją aktywność w sieci związaną z pracą, w tym e-maile, aplikacje i strony internetowe.\n\nAby dowiedzieć się więcej, skontaktuj się z administratorem."</string>
    +     <string name="monitoring_description_app_personal_work" msgid="4946600443852045903">"Twoim profilem do pracy zarządza <xliff:g id="ORGANIZATION">%1$s</xliff:g>. Profil jest połączony z aplikacją <xliff:g id="APPLICATION_WORK">%2$s</xliff:g>, która może monitorować Twoją aktywność w sieci związaną z pracą, w tym e-maile, aplikacje i strony internetowe.\n\nMasz też połączenie z aplikacją <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g>, która może monitorować Twoją prywatną aktywność w sieci."</string>
    +     <string name="monitoring_description_vpn_app_device_owned" msgid="4970443827043261703">"Twoim urządzeniem zarządza <xliff:g id="ORGANIZATION">%1$s</xliff:g>.\n\nAdministrator może monitorować ustawienia, firmowe uprawnienia dostępu, aplikacje, dane powiązane z urządzeniem i informacje o jego lokalizacji oraz nimi zarządzać.\n\nMasz połączenie z aplikacją <xliff:g id="APPLICATION">%2$s</xliff:g>, która może monitorować Twoją aktywność w sieci, w tym e-maile, aplikacje i strony internetowe.\n\nAby dowiedzieć się więcej, skontaktuj się z administratorem."</string>
    +@@ -496,8 +498,6 @@
    +     <string name="clock_seconds_desc" msgid="6282693067130470675">"Pokaż sekundy na zegarku na pasku stanu. Może mieć wpływ na czas pracy baterii."</string>
    +     <string name="qs_rearrange" msgid="8060918697551068765">"Uporządkuj Szybkie ustawienia"</string>
    +     <string name="show_brightness" msgid="6613930842805942519">"Pokaż jasność w Szybkich ustawieniach"</string>
    +-    <string name="overview_nav_bar_gesture" msgid="8579814204727917764">"Włącz dzielenie ekranu gestem przesunięcia w górę"</string>
    +-    <string name="overview_nav_bar_gesture_desc" msgid="6329167382305102615">"Włącz dzielenie ekranu po wykonaniu gestu przesunięcia palcem w górę od przycisku Przegląd"</string>
    +     <string name="experimental" msgid="6198182315536726162">"Eksperymentalne"</string>
    +     <string name="enable_bluetooth_title" msgid="5027037706500635269">"Włączyć Bluetooth?"</string>
    +     <string name="enable_bluetooth_message" msgid="9106595990708985385">"Aby połączyć klawiaturę z tabletem, musisz najpierw włączyć Bluetooth."</string>
    +@@ -655,4 +655,5 @@
    +     <string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"Otwórz ustawienia: <xliff:g id="ID_1">%s</xliff:g>."</string>
    +     <string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"Edytuj kolejność ustawień."</string>
    +     <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"Strona <xliff:g id="ID_1">%1$d</xliff:g> z <xliff:g id="ID_2">%2$d</xliff:g>"</string>
    ++    <string name="cant_silence_or_block" msgid="999689262131488625">"Nie można wyciszyć ani zablokować powiadomień"</string>
    + </resources>
    +diff --git a/packages/SystemUI/res/values-pt-rBR/strings.xml b/packages/SystemUI/res/values-pt-rBR/strings.xml
    +index 199dbad..25aeb5f 100644
    +--- a/packages/SystemUI/res/values-pt-rBR/strings.xml
    ++++ b/packages/SystemUI/res/values-pt-rBR/strings.xml
    +@@ -240,7 +240,7 @@
    +     <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"Os dados 4G foram pausados"</string>
    +     <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"Os dados da rede celular foram pausados"</string>
    +     <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"Os dados foram pausados"</string>
    +-    <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"Como seu limite de dados definido foi atingido, o dispositivo pausou o uso de dados para o restante deste ciclo.\n\nA retomada pode gerar cobranças por parte da sua operadora."</string>
    ++    <string name="data_usage_disabled_dialog" msgid="1841738975235283398">"O limite de dados que você definiu foi atingido. Você não está mais usando os dados da rede celular.\n\nSe retomar o uso de dados, cobranças poderão ser aplicadas."</string>
    +     <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"Retomar"</string>
    +     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Sem conexão à Internet"</string>
    +     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi conectado"</string>
    +@@ -406,6 +406,7 @@
    +     <string name="device_owned_footer" msgid="3802752663326030053">"O dispositivo pode ser monitorado"</string>
    +     <string name="profile_owned_footer" msgid="8021888108553696069">"O perfil pode ser monitorado"</string>
    +     <string name="vpn_footer" msgid="2388611096129106812">"A rede pode ser monitorada"</string>
    ++    <string name="branded_vpn_footer" msgid="2168111859226496230">"A rede pode ser monitorada"</string>
    +     <string name="monitoring_title_device_owned" msgid="7121079311903859610">"Monitoramento de dispositivos"</string>
    +     <string name="monitoring_title_profile_owned" msgid="6790109874733501487">"Monitoramento de perfis"</string>
    +     <string name="monitoring_title" msgid="169206259253048106">"Monitoramento de rede"</string>
    +@@ -418,6 +419,7 @@
    +     <string name="legacy_vpn_name" msgid="6604123105765737830">"VPN"</string>
    +     <string name="monitoring_description_app" msgid="6259179342284742878">"Você está conectado a <xliff:g id="APPLICATION">%1$s</xliff:g>, que pode monitorar sua atividade na rede, incluindo e-mails, apps e websites."</string>
    +     <string name="monitoring_description_app_personal" msgid="484599052118316268">"Você está conectado a <xliff:g id="APPLICATION">%1$s</xliff:g>, que pode monitorar sua atividade pessoal na rede, incluindo e-mails, apps e websites."</string>
    ++    <string name="branded_monitoring_description_app_personal" msgid="2669518213949202599">"Você está conectado a <xliff:g id="APPLICATION">%1$s</xliff:g>, que pode monitorar sua atividade pessoal na rede, incluindo e-mails, apps e websites."</string>
    +     <string name="monitoring_description_app_work" msgid="1754325860918060897">"Seu perfil de trabalho é gerenciado por <xliff:g id="ORGANIZATION">%1$s</xliff:g>. Ele está conectado a <xliff:g id="APPLICATION">%2$s</xliff:g>, que pode monitorar sua atividade profissional na rede, incluindo e-mails, apps e websites.\n\nPara ver mais informações, entre em contato com seu administrador."</string>
    +     <string name="monitoring_description_app_personal_work" msgid="4946600443852045903">"Seu perfil de trabalho é gerenciado por <xliff:g id="ORGANIZATION">%1$s</xliff:g>. Ele está conectado a <xliff:g id="APPLICATION_WORK">%2$s</xliff:g>, que pode monitorar sua atividade profissional na rede, incluindo e-mails, apps e websites.\n\nVocê também está conectado a <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g>, que pode monitorar sua atividade pessoal na rede."</string>
    +     <string name="monitoring_description_vpn_app_device_owned" msgid="4970443827043261703">"Seu dispositivo é gerenciado por <xliff:g id="ORGANIZATION">%1$s</xliff:g>.\n\nSeu administrador pode monitorar e gerenciar configurações, acesso corporativo, apps, dados associados ao seu dispositivo e informações sobre localização do dispositivo.\n\nVocê está conectado a <xliff:g id="APPLICATION">%2$s</xliff:g>, que pode monitorar suas atividades de rede, incluindo e-mails, apps e websites.\n\nPara ver mais informações, entre em contato com seu administrador."</string>
    +@@ -494,8 +496,6 @@
    +     <string name="clock_seconds_desc" msgid="6282693067130470675">"Mostrar segundos do relógio na barra de status. Pode afetar a duração da bateria."</string>
    +     <string name="qs_rearrange" msgid="8060918697551068765">"Reorganizar \"Configurações rápidas\""</string>
    +     <string name="show_brightness" msgid="6613930842805942519">"Mostrar brilho nas \"Configurações rápidas\""</string>
    +-    <string name="overview_nav_bar_gesture" msgid="8579814204727917764">"Ativar gesto para dividir a tela ao deslizar para cima"</string>
    +-    <string name="overview_nav_bar_gesture_desc" msgid="6329167382305102615">"Ativa o gesto para entrar no modo de tela dividida deslizando a partir do botão \"Visão geral\""</string>
    +     <string name="experimental" msgid="6198182315536726162">"Experimentais"</string>
    +     <string name="enable_bluetooth_title" msgid="5027037706500635269">"Ativar o Bluetooth?"</string>
    +     <string name="enable_bluetooth_message" msgid="9106595990708985385">"Para conectar o teclado ao tablet, é preciso primeiro ativar o Bluetooth."</string>
    +@@ -653,4 +653,5 @@
    +     <string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"Abrir configurações de <xliff:g id="ID_1">%s</xliff:g>."</string>
    +     <string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"Editar ordem das configurações."</string>
    +     <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"Página <xliff:g id="ID_1">%1$d</xliff:g> de <xliff:g id="ID_2">%2$d</xliff:g>"</string>
    ++    <string name="cant_silence_or_block" msgid="999689262131488625">"Não é possível silenciar ou bloquear as notificações"</string>
    + </resources>
    +diff --git a/packages/SystemUI/res/values-pt-rPT/strings.xml b/packages/SystemUI/res/values-pt-rPT/strings.xml
    +index d3d7f24..79f1c7d 100644
    +--- a/packages/SystemUI/res/values-pt-rPT/strings.xml
    ++++ b/packages/SystemUI/res/values-pt-rPT/strings.xml
    +@@ -238,7 +238,7 @@
    +     <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"Dados 4G em pausa"</string>
    +     <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"Dados de redes móveis em pausa"</string>
    +     <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"Dados em pausa"</string>
    +-    <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"Uma vez que foi atingido o limite de dados definido, foi interrompida a utilização de dados no seu dispositivo durante o tempo restante deste ciclo.\n\nSe retomar a utilização, o seu operador pode efetuar cobranças."</string>
    ++    <string name="data_usage_disabled_dialog" msgid="1841738975235283398">"O limite de dados definido foi atingido. Já não está a utilizar dados móveis.\n\nSe retomar, podem aplicar-se custos relativos à utilização de dados."</string>
    +     <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"Retomar"</string>
    +     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Sem ligação internet"</string>
    +     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi ligado"</string>
    +@@ -404,6 +404,7 @@
    +     <string name="device_owned_footer" msgid="3802752663326030053">"O dispositivo pode ser monitorizado"</string>
    +     <string name="profile_owned_footer" msgid="8021888108553696069">"O perfil pode ser monitorizado"</string>
    +     <string name="vpn_footer" msgid="2388611096129106812">"A rede pode ser monitorizada"</string>
    ++    <string name="branded_vpn_footer" msgid="2168111859226496230">"A rede pode ser monitorizada"</string>
    +     <string name="monitoring_title_device_owned" msgid="7121079311903859610">"Monitorização de dispositivos"</string>
    +     <string name="monitoring_title_profile_owned" msgid="6790109874733501487">"Monitorização de perfis"</string>
    +     <string name="monitoring_title" msgid="169206259253048106">"Monitorização da rede"</string>
    +@@ -416,6 +417,7 @@
    +     <string name="legacy_vpn_name" msgid="6604123105765737830">"VPN"</string>
    +     <string name="monitoring_description_app" msgid="6259179342284742878">"Está ligado a <xliff:g id="APPLICATION">%1$s</xliff:g>, que pode monitorizar a atividade da rede, incluindo emails, aplicações e Websites."</string>
    +     <string name="monitoring_description_app_personal" msgid="484599052118316268">"Está ligado a <xliff:g id="APPLICATION">%1$s</xliff:g>, que pode monitorizar a atividade da rede pessoal, incluindo emails, aplicações e Websites."</string>
    ++    <string name="branded_monitoring_description_app_personal" msgid="2669518213949202599">"Está ligado ao <xliff:g id="APPLICATION">%1$s</xliff:g>, que pode monitorizar a atividade da rede pessoal, incluindo emails, aplicações e Websites."</string>
    +     <string name="monitoring_description_app_work" msgid="1754325860918060897">"O seu perfil de trabalho é gerido por <xliff:g id="ORGANIZATION">%1$s</xliff:g>. Está ligado a <xliff:g id="APPLICATION">%2$s</xliff:g>, que pode monitorizar a atividade da rede de trabalho, incluindo emails, aplicações e Websites.\n\nPara obter mais informações, contacte o administrador."</string>
    +     <string name="monitoring_description_app_personal_work" msgid="4946600443852045903">"O seu perfil de trabalho é gerido por <xliff:g id="ORGANIZATION">%1$s</xliff:g>. Está ligado a <xliff:g id="APPLICATION_WORK">%2$s</xliff:g>, que pode monitorizar a atividade da rede de trabalho, incluindo emails, aplicações e Websites.\n\nTambém está ligado a <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g>, que pode monitorizar a atividade da rede pessoal."</string>
    +     <string name="monitoring_description_vpn_app_device_owned" msgid="4970443827043261703">"O seu dispositivo é gerido por <xliff:g id="ORGANIZATION">%1$s</xliff:g>.\n\nO seu administrador pode monitorizar e gerir as definições, o acesso empresarial, as aplicações, os dados associados ao dispositivo e as informações de localização do dispositivo.\n\nEstá ligado a <xliff:g id="APPLICATION">%2$s</xliff:g>, que pode monitorizar a atividade da rede, incluindo emails, aplicações e Websites.\n\nPara obter mais informações, contacte o administrador."</string>
    +@@ -492,8 +494,6 @@
    +     <string name="clock_seconds_desc" msgid="6282693067130470675">"Mostrar segundos do relógio na barra de estado. Pode afetar a autonomia da bateria."</string>
    +     <string name="qs_rearrange" msgid="8060918697551068765">"Reorganizar as Definições rápidas"</string>
    +     <string name="show_brightness" msgid="6613930842805942519">"Mostrar luminosidade nas Definições rápidas"</string>
    +-    <string name="overview_nav_bar_gesture" msgid="8579814204727917764">"Ativar gesto de deslize rápido para cima do ecrã dividido"</string>
    +-    <string name="overview_nav_bar_gesture_desc" msgid="6329167382305102615">"Ativar o gesto para aceder ao ecrã dividido ao deslizar rapidamente para cima a partir do botão Vista geral"</string>
    +     <string name="experimental" msgid="6198182315536726162">"Experimental"</string>
    +     <string name="enable_bluetooth_title" msgid="5027037706500635269">"Pretende ativar o Bluetooth?"</string>
    +     <string name="enable_bluetooth_message" msgid="9106595990708985385">"Para ligar o teclado ao tablet, tem de ativar primeiro o Bluetooth."</string>
    +@@ -651,4 +651,5 @@
    +     <string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"Abrir as definições de <xliff:g id="ID_1">%s</xliff:g>."</string>
    +     <string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"Editar a ordem das definições."</string>
    +     <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"Página <xliff:g id="ID_1">%1$d</xliff:g> de <xliff:g id="ID_2">%2$d</xliff:g>"</string>
    ++    <string name="cant_silence_or_block" msgid="999689262131488625">"Não é possível silenciar ou bloquear as notificações"</string>
    + </resources>
    +diff --git a/packages/SystemUI/res/values-pt/strings.xml b/packages/SystemUI/res/values-pt/strings.xml
    +index 199dbad..25aeb5f 100644
    +--- a/packages/SystemUI/res/values-pt/strings.xml
    ++++ b/packages/SystemUI/res/values-pt/strings.xml
    +@@ -240,7 +240,7 @@
    +     <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"Os dados 4G foram pausados"</string>
    +     <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"Os dados da rede celular foram pausados"</string>
    +     <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"Os dados foram pausados"</string>
    +-    <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"Como seu limite de dados definido foi atingido, o dispositivo pausou o uso de dados para o restante deste ciclo.\n\nA retomada pode gerar cobranças por parte da sua operadora."</string>
    ++    <string name="data_usage_disabled_dialog" msgid="1841738975235283398">"O limite de dados que você definiu foi atingido. Você não está mais usando os dados da rede celular.\n\nSe retomar o uso de dados, cobranças poderão ser aplicadas."</string>
    +     <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"Retomar"</string>
    +     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Sem conexão à Internet"</string>
    +     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi conectado"</string>
    +@@ -406,6 +406,7 @@
    +     <string name="device_owned_footer" msgid="3802752663326030053">"O dispositivo pode ser monitorado"</string>
    +     <string name="profile_owned_footer" msgid="8021888108553696069">"O perfil pode ser monitorado"</string>
    +     <string name="vpn_footer" msgid="2388611096129106812">"A rede pode ser monitorada"</string>
    ++    <string name="branded_vpn_footer" msgid="2168111859226496230">"A rede pode ser monitorada"</string>
    +     <string name="monitoring_title_device_owned" msgid="7121079311903859610">"Monitoramento de dispositivos"</string>
    +     <string name="monitoring_title_profile_owned" msgid="6790109874733501487">"Monitoramento de perfis"</string>
    +     <string name="monitoring_title" msgid="169206259253048106">"Monitoramento de rede"</string>
    +@@ -418,6 +419,7 @@
    +     <string name="legacy_vpn_name" msgid="6604123105765737830">"VPN"</string>
    +     <string name="monitoring_description_app" msgid="6259179342284742878">"Você está conectado a <xliff:g id="APPLICATION">%1$s</xliff:g>, que pode monitorar sua atividade na rede, incluindo e-mails, apps e websites."</string>
    +     <string name="monitoring_description_app_personal" msgid="484599052118316268">"Você está conectado a <xliff:g id="APPLICATION">%1$s</xliff:g>, que pode monitorar sua atividade pessoal na rede, incluindo e-mails, apps e websites."</string>
    ++    <string name="branded_monitoring_description_app_personal" msgid="2669518213949202599">"Você está conectado a <xliff:g id="APPLICATION">%1$s</xliff:g>, que pode monitorar sua atividade pessoal na rede, incluindo e-mails, apps e websites."</string>
    +     <string name="monitoring_description_app_work" msgid="1754325860918060897">"Seu perfil de trabalho é gerenciado por <xliff:g id="ORGANIZATION">%1$s</xliff:g>. Ele está conectado a <xliff:g id="APPLICATION">%2$s</xliff:g>, que pode monitorar sua atividade profissional na rede, incluindo e-mails, apps e websites.\n\nPara ver mais informações, entre em contato com seu administrador."</string>
    +     <string name="monitoring_description_app_personal_work" msgid="4946600443852045903">"Seu perfil de trabalho é gerenciado por <xliff:g id="ORGANIZATION">%1$s</xliff:g>. Ele está conectado a <xliff:g id="APPLICATION_WORK">%2$s</xliff:g>, que pode monitorar sua atividade profissional na rede, incluindo e-mails, apps e websites.\n\nVocê também está conectado a <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g>, que pode monitorar sua atividade pessoal na rede."</string>
    +     <string name="monitoring_description_vpn_app_device_owned" msgid="4970443827043261703">"Seu dispositivo é gerenciado por <xliff:g id="ORGANIZATION">%1$s</xliff:g>.\n\nSeu administrador pode monitorar e gerenciar configurações, acesso corporativo, apps, dados associados ao seu dispositivo e informações sobre localização do dispositivo.\n\nVocê está conectado a <xliff:g id="APPLICATION">%2$s</xliff:g>, que pode monitorar suas atividades de rede, incluindo e-mails, apps e websites.\n\nPara ver mais informações, entre em contato com seu administrador."</string>
    +@@ -494,8 +496,6 @@
    +     <string name="clock_seconds_desc" msgid="6282693067130470675">"Mostrar segundos do relógio na barra de status. Pode afetar a duração da bateria."</string>
    +     <string name="qs_rearrange" msgid="8060918697551068765">"Reorganizar \"Configurações rápidas\""</string>
    +     <string name="show_brightness" msgid="6613930842805942519">"Mostrar brilho nas \"Configurações rápidas\""</string>
    +-    <string name="overview_nav_bar_gesture" msgid="8579814204727917764">"Ativar gesto para dividir a tela ao deslizar para cima"</string>
    +-    <string name="overview_nav_bar_gesture_desc" msgid="6329167382305102615">"Ativa o gesto para entrar no modo de tela dividida deslizando a partir do botão \"Visão geral\""</string>
    +     <string name="experimental" msgid="6198182315536726162">"Experimentais"</string>
    +     <string name="enable_bluetooth_title" msgid="5027037706500635269">"Ativar o Bluetooth?"</string>
    +     <string name="enable_bluetooth_message" msgid="9106595990708985385">"Para conectar o teclado ao tablet, é preciso primeiro ativar o Bluetooth."</string>
    +@@ -653,4 +653,5 @@
    +     <string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"Abrir configurações de <xliff:g id="ID_1">%s</xliff:g>."</string>
    +     <string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"Editar ordem das configurações."</string>
    +     <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"Página <xliff:g id="ID_1">%1$d</xliff:g> de <xliff:g id="ID_2">%2$d</xliff:g>"</string>
    ++    <string name="cant_silence_or_block" msgid="999689262131488625">"Não é possível silenciar ou bloquear as notificações"</string>
    + </resources>
    +diff --git a/packages/SystemUI/res/values-ro/strings.xml b/packages/SystemUI/res/values-ro/strings.xml
    +index f59721a..408edf3 100644
    +--- a/packages/SystemUI/res/values-ro/strings.xml
    ++++ b/packages/SystemUI/res/values-ro/strings.xml
    +@@ -241,7 +241,7 @@
    +     <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"Conexiunea de date 4G este întreruptă"</string>
    +     <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"Conexiunea de date mobile este întreruptă"</string>
    +     <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"Conexiunea de date este întreruptă"</string>
    +-    <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"Deoarece limita setată pentru date a fost atinsă, dispozitivul a întrerupt utilizarea datelor pentru restul acestui ciclu.\n\nReluarea utilizării de date poate genera aplicarea de taxe de către operator."</string>
    ++    <string name="data_usage_disabled_dialog" msgid="1841738975235283398">"A fost atinsă limita de date setată. Datele mobile nu mai sunt folosite \n\nDacă reluați, este posibil să se aplice taxe pentru utilizarea datelor."</string>
    +     <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"Reluați"</string>
    +     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Fără conex. internet"</string>
    +     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi conectat"</string>
    +@@ -329,7 +329,7 @@
    +     <string name="recents_empty_message" msgid="808480104164008572">"Niciun element recent"</string>
    +     <string name="recents_empty_message_dismissed_all" msgid="2791312568666558651">"Ați șters tot"</string>
    +     <string name="recents_app_info_button_label" msgid="2890317189376000030">"Informații despre aplicație"</string>
    +-    <string name="recents_lock_to_app_button_label" msgid="6942899049072506044">"fixare pe ecran"</string>
    ++    <string name="recents_lock_to_app_button_label" msgid="6942899049072506044">"fixarea ecranului"</string>
    +     <string name="recents_search_bar_label" msgid="8074997400187836677">"căutare"</string>
    +     <string name="recents_launch_error_message" msgid="2969287838120550506">"<xliff:g id="APP">%s</xliff:g> nu a putut porni."</string>
    +     <string name="recents_launch_disabled_message" msgid="1624523193008871793">"Aplicația <xliff:g id="APP">%s</xliff:g> este dezactivată în modul sigur."</string>
    +@@ -408,6 +408,7 @@
    +     <string name="device_owned_footer" msgid="3802752663326030053">"Dispozitivul poate fi monitorizat"</string>
    +     <string name="profile_owned_footer" msgid="8021888108553696069">"Profilul poate fi monitorizat"</string>
    +     <string name="vpn_footer" msgid="2388611096129106812">"Rețeaua poate fi monitorizată"</string>
    ++    <string name="branded_vpn_footer" msgid="2168111859226496230">"Este posibil ca rețeaua să fie monitorizată"</string>
    +     <string name="monitoring_title_device_owned" msgid="7121079311903859610">"Monitorizarea dispozitivului"</string>
    +     <string name="monitoring_title_profile_owned" msgid="6790109874733501487">"Monitorizarea profilului"</string>
    +     <string name="monitoring_title" msgid="169206259253048106">"Monitorizarea rețelei"</string>
    +@@ -420,6 +421,7 @@
    +     <string name="legacy_vpn_name" msgid="6604123105765737830">"VPN"</string>
    +     <string name="monitoring_description_app" msgid="6259179342284742878">"Sunteți conectat(ă) la <xliff:g id="APPLICATION">%1$s</xliff:g>, care vă poate monitoriza activitatea în rețea, inclusiv e-mailurile, aplicațiile și site-urile."</string>
    +     <string name="monitoring_description_app_personal" msgid="484599052118316268">"Sunteți conectat(ă) la <xliff:g id="APPLICATION">%1$s</xliff:g>, care vă poate monitoriza activitatea în rețeaua personală, inclusiv e-mailurile, aplicațiile și site-urile."</string>
    ++    <string name="branded_monitoring_description_app_personal" msgid="2669518213949202599">"V-ați conectat la aplicația <xliff:g id="APPLICATION">%1$s</xliff:g>, care vă poate monitoriza activitatea personală în rețea, inclusiv e-mailurile, aplicațiile și site-urile accesate."</string>
    +     <string name="monitoring_description_app_work" msgid="1754325860918060897">"Profilul de serviciu este gestionat de <xliff:g id="ORGANIZATION">%1$s</xliff:g>. Este conectat la <xliff:g id="APPLICATION">%2$s</xliff:g>, care vă poate monitoriza activitatea în rețeaua de serviciu, inclusiv e-mailurile, aplicațiile și site-urile.\n\nPentru mai multe informații, contactați administratorul."</string>
    +     <string name="monitoring_description_app_personal_work" msgid="4946600443852045903">"Profilul de serviciu este gestionat de <xliff:g id="ORGANIZATION">%1$s</xliff:g>. Este conectat la <xliff:g id="APPLICATION_WORK">%2$s</xliff:g>, care vă poate monitoriza activitatea în rețeaua de serviciu, inclusiv e-mailurile, aplicațiile și site-urile.\n\nDe asemenea, sunteți conectat(ă) la <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g>, care vă poate monitoriza activitatea în rețeaua personală."</string>
    +     <string name="monitoring_description_vpn_app_device_owned" msgid="4970443827043261703">"Dispozitivul este gestionat de <xliff:g id="ORGANIZATION">%1$s</xliff:g>.\n\nAdministratorul poate monitoriza și gestiona setările, accesul la rețeaua companiei, aplicațiile, datele asociate cu dispozitivul și informațiile privind locația dispozitivului.\n\nSunteți conectat(ă) la <xliff:g id="APPLICATION">%2$s</xliff:g>, care vă poate monitoriza activitatea în rețea, inclusiv e-mailurile, aplicațiile și site-urile.\n\nPentru mai multe informații, contactați administratorul."</string>
    +@@ -496,8 +498,6 @@
    +     <string name="clock_seconds_desc" msgid="6282693067130470675">"Afișează secundele pe ceas în bara de stare. Poate afecta autonomia bateriei."</string>
    +     <string name="qs_rearrange" msgid="8060918697551068765">"Rearanjați Setările rapide"</string>
    +     <string name="show_brightness" msgid="6613930842805942519">"Afișați luminozitatea în Setările rapide"</string>
    +-    <string name="overview_nav_bar_gesture" msgid="8579814204727917764">"Activați gestul de accesare a ecranului împărțit prin glisare în sus"</string>
    +-    <string name="overview_nav_bar_gesture_desc" msgid="6329167382305102615">"Activați gestul de accesare a ecranului împărțit prin glisarea în sus de la butonul Recente"</string>
    +     <string name="experimental" msgid="6198182315536726162">"Experimentale"</string>
    +     <string name="enable_bluetooth_title" msgid="5027037706500635269">"Activați Bluetooth?"</string>
    +     <string name="enable_bluetooth_message" msgid="9106595990708985385">"Pentru a conecta tastatura la tabletă, mai întâi trebuie să activați Bluetooth."</string>
    +@@ -655,4 +655,5 @@
    +     <string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"Deschideți setările <xliff:g id="ID_1">%s</xliff:g>."</string>
    +     <string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"Editați ordinea setărilor."</string>
    +     <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"Pagina <xliff:g id="ID_1">%1$d</xliff:g> din <xliff:g id="ID_2">%2$d</xliff:g>"</string>
    ++    <string name="cant_silence_or_block" msgid="999689262131488625">"Notificările nu pot fi dezactivate sau blocate"</string>
    + </resources>
    +diff --git a/packages/SystemUI/res/values-ru/strings.xml b/packages/SystemUI/res/values-ru/strings.xml
    +index bee7eed..7efd8fa 100644
    +--- a/packages/SystemUI/res/values-ru/strings.xml
    ++++ b/packages/SystemUI/res/values-ru/strings.xml
    +@@ -242,7 +242,7 @@
    +     <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"Передача данных 4G приостановлена"</string>
    +     <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"Передача мобильных данных приостановлена"</string>
    +     <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"Передача данных приостановлена"</string>
    +-    <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"Передача данных выключена до конца цикла, поскольку достигнут установленный вами лимит.\n\nЕсли вы возобновите ее, оператор может взимать плату за дополнительный расход трафика."</string>
    ++    <string name="data_usage_disabled_dialog" msgid="1841738975235283398">"Достигнут установленный вами лимит на передачу мобильных данных.\n\nЕсли вы продолжите, может взиматься дополнительная плата."</string>
    +     <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"Возобновить"</string>
    +     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Нет интернет-подключения"</string>
    +     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi подключено"</string>
    +@@ -410,6 +410,7 @@
    +     <string name="device_owned_footer" msgid="3802752663326030053">"Устройство может контролироваться"</string>
    +     <string name="profile_owned_footer" msgid="8021888108553696069">"Действия в профиле могут отслеживаться"</string>
    +     <string name="vpn_footer" msgid="2388611096129106812">"Сеть может отслеживаться"</string>
    ++    <string name="branded_vpn_footer" msgid="2168111859226496230">"Сеть может отслеживаться"</string>
    +     <string name="monitoring_title_device_owned" msgid="7121079311903859610">"Отслеживание устройств"</string>
    +     <string name="monitoring_title_profile_owned" msgid="6790109874733501487">"Мониторинг профиля"</string>
    +     <string name="monitoring_title" msgid="169206259253048106">"Отслеживание сетей"</string>
    +@@ -422,6 +423,7 @@
    +     <string name="legacy_vpn_name" msgid="6604123105765737830">"Сеть VPN"</string>
    +     <string name="monitoring_description_app" msgid="6259179342284742878">"Запущено приложение \"<xliff:g id="APPLICATION">%1$s</xliff:g>\", которое может отслеживать ваши действия в Интернете, включая работу с электронной почтой, приложениями и веб-сайтами."</string>
    +     <string name="monitoring_description_app_personal" msgid="484599052118316268">"Запущено приложение \"<xliff:g id="APPLICATION">%1$s</xliff:g>\", которое может отслеживать ваши действия в Интернете (выполняемые в личном профиле), включая работу с электронной почтой, приложениями и веб-сайтами."</string>
    ++    <string name="branded_monitoring_description_app_personal" msgid="2669518213949202599">"Запущено приложение \"<xliff:g id="APPLICATION">%1$s</xliff:g>\", которое может отслеживать ваши действия в сети, включая работу с электронной почтой, приложениями и веб-сайтами."</string>
    +     <string name="monitoring_description_app_work" msgid="1754325860918060897">"Вашим рабочим профилем управляет \"<xliff:g id="ORGANIZATION">%1$s</xliff:g>\". Приложение \"<xliff:g id="APPLICATION">%2$s</xliff:g>\" может отслеживать ваши действия в Интернете, включая работу с электронной почтой, приложениями и веб-сайтами.\n\nЗа дополнительной информацией обратитесь к своему администратору."</string>
    +     <string name="monitoring_description_app_personal_work" msgid="4946600443852045903">"Вашим рабочим профилем управляет \"<xliff:g id="ORGANIZATION">%1$s</xliff:g>\". Приложение \"<xliff:g id="APPLICATION_WORK">%2$s</xliff:g>\" может отслеживать ваши действия в Интернете, включая работу с электронной почтой, приложениями и веб-сайтами.\n\nПриложение \"<xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g>\" может отслеживать ваши действия в Интернете, выполняемые в личном профиле."</string>
    +     <string name="monitoring_description_vpn_app_device_owned" msgid="4970443827043261703">"Вашим корпоративным профилем управляет <xliff:g id="ORGANIZATION">%1$s</xliff:g>.\n\nАдминистратор может управлять настройками, корпоративным доступом, приложениями, данными на вашем устройстве, в том числе геоданными, а также просматривать соответствующие сведения.\n\nПриложение <xliff:g id="APPLICATION">%2$s</xliff:g> также может отслеживать ваши действия в сети, включая работу с электронной почтой, приложениями и веб-сайтами.\n\nЗа подробностями обратитесь к своему администратору."</string>
    +@@ -498,8 +500,6 @@
    +     <string name="clock_seconds_desc" msgid="6282693067130470675">"Показывать в строке состояния время с точностью до секунды (заряд батареи может расходоваться быстрее)."</string>
    +     <string name="qs_rearrange" msgid="8060918697551068765">"Изменить порядок Быстрых настроек"</string>
    +     <string name="show_brightness" msgid="6613930842805942519">"Добавить яркость в Быстрые настройки"</string>
    +-    <string name="overview_nav_bar_gesture" msgid="8579814204727917764">"Разделять экран пролистыванием вверх"</string>
    +-    <string name="overview_nav_bar_gesture_desc" msgid="6329167382305102615">"Включить разделение экрана пролистыванием вверх с кнопки \"Обзор\""</string>
    +     <string name="experimental" msgid="6198182315536726162">"Экспериментальная функция"</string>
    +     <string name="enable_bluetooth_title" msgid="5027037706500635269">"Подключение по Bluetooth"</string>
    +     <string name="enable_bluetooth_message" msgid="9106595990708985385">"Чтобы подключить клавиатуру к планшету, включите Bluetooth."</string>
    +@@ -657,4 +657,5 @@
    +     <string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"Открыть настройки <xliff:g id="ID_1">%s</xliff:g>."</string>
    +     <string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"Изменить порядок быстрых настроек."</string>
    +     <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"Страница <xliff:g id="ID_1">%1$d</xliff:g> из <xliff:g id="ID_2">%2$d</xliff:g>"</string>
    ++    <string name="cant_silence_or_block" msgid="999689262131488625">"Уведомления нельзя блокировать и показывать без звука"</string>
    + </resources>
    +diff --git a/packages/SystemUI/res/values-si-rLK/strings.xml b/packages/SystemUI/res/values-si-rLK/strings.xml
    +index 0811f5e..749231d 100644
    +--- a/packages/SystemUI/res/values-si-rLK/strings.xml
    ++++ b/packages/SystemUI/res/values-si-rLK/strings.xml
    +@@ -238,7 +238,7 @@
    +     <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"4G දත්ත විරාම කර ඇත"</string>
    +     <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"සෙලියුලර් දත්ත විරාම කර ඇත"</string>
    +     <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"දත්ත විරාම කර ඇත"</string>
    +-    <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"ඔබ සකසා ඇති දත්ත සීමාවට ළඟා වූ නිසා, උපාංගය මගින් මෙම චක්‍රයේ ඉතිරිය සඳහා දත්ත භාවිතය විරාම කර ඇත. \n\nනැවත පටන් ගැනීමෙන් ඔබගේ වාහකයෙන් අය කිරීම් වලට පොළඹවනු ඇත."</string>
    ++    <string name="data_usage_disabled_dialog" msgid="1841738975235283398">"ඔබ සැකසූ දත්ත සීමාව ළඟා වී ඇත. ඔබ තවදුරටත් සෙලියුලර් දත්ත භාවිත නොකරයි. \n\nඔබ නැවත ආරම්භ කළහොත්, දත්ත භාවිතය සඳහා ගාස්තු අදාළ විය හැකිය."</string>
    +     <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"නැවත පටන්ගන්න"</string>
    +     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"අන්තර්ජාල සම්බන්ධතාවයක් නැත"</string>
    +     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi සම්බන්ධිතයි"</string>
    +@@ -404,6 +404,7 @@
    +     <string name="device_owned_footer" msgid="3802752663326030053">"ඇතැම් විට උපාංගය නිරීක්ෂණය විය හැක"</string>
    +     <string name="profile_owned_footer" msgid="8021888108553696069">"ඇතැම් විට පැතිකඩ නිරීක්ෂණය කරන ලදි"</string>
    +     <string name="vpn_footer" msgid="2388611096129106812">"ඇතැම් විට ජාලය නිරීක්ෂණය විය හැක"</string>
    ++    <string name="branded_vpn_footer" msgid="2168111859226496230">"ඇතැම් විට ජාලය නිරීක්ෂණය විය හැක"</string>
    +     <string name="monitoring_title_device_owned" msgid="7121079311903859610">"උපාංගය නිරීක්ෂණය"</string>
    +     <string name="monitoring_title_profile_owned" msgid="6790109874733501487">"පැතිකඩ නිරීක්ෂණය කිරීම"</string>
    +     <string name="monitoring_title" msgid="169206259253048106">"ජාල නිරීක්ෂණය"</string>
    +@@ -416,6 +417,7 @@
    +     <string name="legacy_vpn_name" msgid="6604123105765737830">"VPN"</string>
    +     <string name="monitoring_description_app" msgid="6259179342284742878">"ඊ-තැපැල්, යෙදුම් සහ වෙබ් අඩවි ඇතුළු ඔබේ ජාල ක්‍රියාකාරකම් නිරීක්ෂණය කළ හැකි, <xliff:g id="APPLICATION">%1$s</xliff:g> වෙත ඔබ සම්බන්ධ වී ඇත."</string>
    +     <string name="monitoring_description_app_personal" msgid="484599052118316268">"ඊ-තැපැල්, යෙදුම් සහ වෙබ් අඩවි ඇතුළු ඔබේ පෞද්ගලික ජාල ක්‍රියාකාරකම් නිරීක්ෂණය කළ හැකි, <xliff:g id="APPLICATION">%1$s</xliff:g> වෙත ඔබ සම්බන්ධ වී ඇත."</string>
    ++    <string name="branded_monitoring_description_app_personal" msgid="2669518213949202599">"ඊ-තැපැල්, යෙදුම් සහ වෙබ් අඩවි ඇතුළු ඔබේ පෞද්ගලික ජාල ක්‍රියාකාරකම් නිරීක්ෂණය කළ හැකි, <xliff:g id="APPLICATION">%1$s</xliff:g> වෙත ඔබ සම්බන්ධ වී ඇත."</string>
    +     <string name="monitoring_description_app_work" msgid="1754325860918060897">"ඔබේ කාර්යාල පැතිකඩ කළමනාකරණය කරන්නේ <xliff:g id="ORGANIZATION">%1$s</xliff:g> විසිනි. එය ඊ-තැපැල්, යෙදුම් සහ වෙබ් අඩවි ඇතුළු ඔබේ කාර්යාල ජාල ක්‍රියාකාරකම් නිරීක්ෂණය කළ හැකි, <xliff:g id="APPLICATION">%2$s</xliff:g> වෙත ඔබ සම්බන්ධ වී ඇත.\n\nවැඩිදුර විස්තර සඳහා, ඔබේ පරිපාලක අමතන්න."</string>
    +     <string name="monitoring_description_app_personal_work" msgid="4946600443852045903">"ඔබේ කාර්යාල පැතිකඩ කළමනාකරණය කරන්නේ <xliff:g id="ORGANIZATION">%1$s</xliff:g> විසිනි. එය ඊ-තැපැල්, යෙදුම් සහ වෙබ් අඩවි ඇතුළු ඔබේ කාර්යාල ජාල ක්‍රියාකාරකම් නිරීක්ෂණය කළ හැකි, <xliff:g id="APPLICATION_WORK">%2$s</xliff:g>, වෙත ඔබ සම්බන්ධ වී ඇත.\n\nඔබ ඔබේ පෞද්ගලික ජාල ක්‍රියාකාරකම් නිරීක්ෂණය කළ හැකි, <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g> වෙතද සම්බන්ධ වී ඇත."</string>
    +     <string name="monitoring_description_vpn_app_device_owned" msgid="4970443827043261703">"ඔබේ උපාංගය කළමනාකරණය කරන්නේ <xliff:g id="ORGANIZATION">%1$s</xliff:g> විසිනි.\n\nඔබේ පරිපාලකට ඔබේ උපාංගය හා සම්බන්ධිත සැකසීම්, ආයතනික ප්‍රවේශය, යෙදුම්, දත්ත සහ ඔබේ උපාංගය තිබෙන ස්ථානයේ තොරතුරු නිරීක්ෂණය කිරීමට සහ කළමනාකරණය කිරීමට හැකිය.\n\nඔබ ඊ-තැපැල්, යෙදුම්, සහ වෙබ් අඩවි ඇතුළු ඔබේ ජාල ක්‍රියාකාරකම් නිරීක්ෂණය කිරීමට හැකි <xliff:g id="APPLICATION">%2$s</xliff:g>, වෙතද සම්බන්ධව ඇත.\n\nවැඩිදුර තොරතුරු සඳහා, ඔබගේ පරිපාලක අමතන්න."</string>
    +@@ -492,8 +494,6 @@
    +     <string name="clock_seconds_desc" msgid="6282693067130470675">"තත්ත්ව තීරුවෙහි ඔරලෝසු තත්පර පෙන්වන්න. බැටරි ආයු කාලයට බලපෑමට හැකිය."</string>
    +     <string name="qs_rearrange" msgid="8060918697551068765">"ඉක්මන් සැකසීම් යළි පිළිවෙළට සකසන්න"</string>
    +     <string name="show_brightness" msgid="6613930842805942519">"ඉක්මන් සැකසීම්වල දීප්තිය පෙන්වන්න"</string>
    +-    <string name="overview_nav_bar_gesture" msgid="8579814204727917764">"බෙදුම්-තිරය ඉහළට-ස්වයිප් කිරීමේ අභිනය සබල කරන්න"</string>
    +-    <string name="overview_nav_bar_gesture_desc" msgid="6329167382305102615">"දළ විශ්ලේෂණ බොත්තම හරහා ඉහළට ස්වයිප් කිරීමෙන් බෙදුම් තිරයට ඇතුළු වීමට ඉඟිය සබල කිරීම"</string>
    +     <string name="experimental" msgid="6198182315536726162">"පරීක්ෂණාත්මක"</string>
    +     <string name="enable_bluetooth_title" msgid="5027037706500635269">"බ්ලූටූත් ක්‍රියාත්මක කරන්නද?"</string>
    +     <string name="enable_bluetooth_message" msgid="9106595990708985385">"ඔබේ යතුරු පුවරුව ඔබේ ටැබ්ලට් පරිගණකයට සම්බන්ධ කිරීමට, ඔබ පළමුව බ්ලූටූත් ක්‍රියාත්මක කළ යුතුය."</string>
    +@@ -651,4 +651,5 @@
    +     <string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"<xliff:g id="ID_1">%s</xliff:g> සැකසීම් විවෘත කරන්න."</string>
    +     <string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"සැකසීම්වල අනුපිළිවෙළ සංංස්කරණය කරන්න."</string>
    +     <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"<xliff:g id="ID_2">%2$d</xliff:g> න් <xliff:g id="ID_1">%1$d</xliff:g>"</string>
    ++    <string name="cant_silence_or_block" msgid="999689262131488625">"දැනුම්දීම් නිහඬ හෝ අවහිර කළ නොහැකිය"</string>
    + </resources>
    +diff --git a/packages/SystemUI/res/values-sk/strings.xml b/packages/SystemUI/res/values-sk/strings.xml
    +index 304c9a0..8dd2569 100644
    +--- a/packages/SystemUI/res/values-sk/strings.xml
    ++++ b/packages/SystemUI/res/values-sk/strings.xml
    +@@ -242,7 +242,7 @@
    +     <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"Dátové prenosy 4G sú pozastavené"</string>
    +     <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"Mobilné dáta sú pozastavené"</string>
    +     <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"Dáta sú pozastavené"</string>
    +-    <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"Keďže ste dosiahli nastavený limit pre mobilné dáta, na zariadení bola pre zvyšok tohto cyklu pozastavená spotreba dát.\n\nJej opätovné spustenie môže mať za následok účtovanie poplatkov vaším operátorom."</string>
    ++    <string name="data_usage_disabled_dialog" msgid="1841738975235283398">"Dosiahli ste nastavený limit dát. Už nepoužívate mobilné dátové pripojenie.\n\nAk ho však obnovíte, môžu vám byť účtované poplatky za spotrebu dát."</string>
    +     <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"Znova spustiť"</string>
    +     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Bez prip. na Internet"</string>
    +     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi: pripojené"</string>
    +@@ -410,6 +410,7 @@
    +     <string name="device_owned_footer" msgid="3802752663326030053">"Zariadenie môže byť sledované"</string>
    +     <string name="profile_owned_footer" msgid="8021888108553696069">"Profil môže byť monitorovaný"</string>
    +     <string name="vpn_footer" msgid="2388611096129106812">"Sieť môže byť sledovaná"</string>
    ++    <string name="branded_vpn_footer" msgid="2168111859226496230">"Sieť môže byť monitorovaná"</string>
    +     <string name="monitoring_title_device_owned" msgid="7121079311903859610">"Sledovanie zariadenia"</string>
    +     <string name="monitoring_title_profile_owned" msgid="6790109874733501487">"Monitorovanie profilu"</string>
    +     <string name="monitoring_title" msgid="169206259253048106">"Sledovanie siete"</string>
    +@@ -422,6 +423,7 @@
    +     <string name="legacy_vpn_name" msgid="6604123105765737830">"VPN"</string>
    +     <string name="monitoring_description_app" msgid="6259179342284742878">"Ste pripojený/-á k aplikácii <xliff:g id="APPLICATION">%1$s</xliff:g>, ktorá môže sledovať vašu aktivitu v sieti vrátane e-mailových správ, aplikácií a webových stránok."</string>
    +     <string name="monitoring_description_app_personal" msgid="484599052118316268">"Ste pripojený/-á k aplikácii <xliff:g id="APPLICATION">%1$s</xliff:g>, ktorá môže sledovať vašu osobnú aktivitu v sieti vrátane e-mailových správ, aplikácií a webových stránok."</string>
    ++    <string name="branded_monitoring_description_app_personal" msgid="2669518213949202599">"Ste pripojený/-á k aplikácii <xliff:g id="APPLICATION">%1$s</xliff:g>, ktorá môže sledovať vašu osobnú aktivitu v sieti vrátane e-mailových správ, aplikácií a webových stránok."</string>
    +     <string name="monitoring_description_app_work" msgid="1754325860918060897">"Váš pracovný profil spravuje organizácia <xliff:g id="ORGANIZATION">%1$s</xliff:g>. Je pripojený k aplikácii <xliff:g id="APPLICATION">%2$s</xliff:g>, ktorá môže sledovať vašu pracovnú aktivitu v sieti vrátane e-mailových správ, aplikácií a webových stránok.\n\nĎalšie informácie získate od svojho správcu."</string>
    +     <string name="monitoring_description_app_personal_work" msgid="4946600443852045903">"Váš pracovný profil spravuje organizácia <xliff:g id="ORGANIZATION">%1$s</xliff:g>. Je pripojený k aplikácii <xliff:g id="APPLICATION_WORK">%2$s</xliff:g>, ktorá môže sledovať vašu pracovnú aktivitu v sieti vrátane e-mailových správ, aplikácií a webových stránok.\n\nSte tiež pripojený/-á k aplikácii <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g>, ktorá môže sledovať vašu osobnú aktivitu v sieti."</string>
    +     <string name="monitoring_description_vpn_app_device_owned" msgid="4970443827043261703">"Vaše zariadenie spravuje organizácia <xliff:g id="ORGANIZATION">%1$s</xliff:g>.\n\nSprávca môže sledovať a spravovať nastavenia, podnikový prístup, aplikácie a údaje priradené k vášmu účtu, ako aj informácie o polohe zariadenia.\n\nSte pripojený/-á k aplikácii <xliff:g id="APPLICATION">%2$s</xliff:g>, ktorá môže sledovať vašu aktivitu v sieti vrátane e-mailových správ, aplikácii a webových stránok.\n\nĎalšie informácie získate od svojho správcu."</string>
    +@@ -498,8 +500,6 @@
    +     <string name="clock_seconds_desc" msgid="6282693067130470675">"Zobrazí sekundy v stavovom riadku. Môže to ovplyvňovať výdrž batérie."</string>
    +     <string name="qs_rearrange" msgid="8060918697551068765">"Zmeniť usporiadanie Rýchlych nastavení"</string>
    +     <string name="show_brightness" msgid="6613930842805942519">"Zobraziť jas v Rýchlych nastaveniach"</string>
    +-    <string name="overview_nav_bar_gesture" msgid="8579814204727917764">"Aktivovať rozdelenú obrazovku prejdením prstom"</string>
    +-    <string name="overview_nav_bar_gesture_desc" msgid="6329167382305102615">"Umožňuje aktivovať rozdelenú obrazovku prejdením prstom nahor od tlačidla Prehľad"</string>
    +     <string name="experimental" msgid="6198182315536726162">"Experimentálne"</string>
    +     <string name="enable_bluetooth_title" msgid="5027037706500635269">"Zapnúť Bluetooth?"</string>
    +     <string name="enable_bluetooth_message" msgid="9106595990708985385">"Ak chcete klávesnicu pripojiť k tabletu, najprv musíte zapnúť Bluetooth."</string>
    +@@ -571,7 +571,7 @@
    +     <string name="keyboard_shortcut_group_applications_browser" msgid="6465985474000766533">"Prehliadač"</string>
    +     <string name="keyboard_shortcut_group_applications_contacts" msgid="2064197111278436375">"Kontakty"</string>
    +     <string name="keyboard_shortcut_group_applications_email" msgid="6257036897441939004">"E-mail"</string>
    +-    <string name="keyboard_shortcut_group_applications_im" msgid="1892749399083161405">"Okamžité správy"</string>
    ++    <string name="keyboard_shortcut_group_applications_im" msgid="1892749399083161405">"Čet"</string>
    +     <string name="keyboard_shortcut_group_applications_music" msgid="4775559515850922780">"Hudba"</string>
    +     <string name="keyboard_shortcut_group_applications_youtube" msgid="6555453761294723317">"YouTube"</string>
    +     <string name="keyboard_shortcut_group_applications_calendar" msgid="9043614299194991263">"Kalendár"</string>
    +@@ -657,4 +657,5 @@
    +     <string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"Otvoriť nastavenia <xliff:g id="ID_1">%s</xliff:g>"</string>
    +     <string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"Upraviť poradie nastavení"</string>
    +     <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"Strana <xliff:g id="ID_1">%1$d</xliff:g> z <xliff:g id="ID_2">%2$d</xliff:g>"</string>
    ++    <string name="cant_silence_or_block" msgid="999689262131488625">"Upozornenia nie je možné stlmiť ani blokovať"</string>
    + </resources>
    +diff --git a/packages/SystemUI/res/values-sl/strings.xml b/packages/SystemUI/res/values-sl/strings.xml
    +index a8bc3d1..fc81a23 100644
    +--- a/packages/SystemUI/res/values-sl/strings.xml
    ++++ b/packages/SystemUI/res/values-sl/strings.xml
    +@@ -242,7 +242,7 @@
    +     <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"Prenos podatkov v omrežju 4G je zaustavljen"</string>
    +     <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"Prenos mobilnih podatkov je zaustavljen"</string>
    +     <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"Prenos podatkov je zaustavljen"</string>
    +-    <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"Dosegli ste nastavljeno omejitev količine prenesenih podatkov, zato je naprava zaustavila porabo podatkov za preostanek cikla.\n\nČe nadaljujete s porabo, boste morda morali plačati stroške operaterju."</string>
    ++    <string name="data_usage_disabled_dialog" msgid="1841738975235283398">"Dosegli ste nastavljeno omejitev porabe podatkov. Prenosa podatkov v mobilnih omrežjih ne uporabljate več.\n\nČe nadaljujete, lahko nastanejo stroški prenosa podatkov."</string>
    +     <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"Nadaljuj"</string>
    +     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Ni internetne povez."</string>
    +     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi povezan"</string>
    +@@ -410,6 +410,7 @@
    +     <string name="device_owned_footer" msgid="3802752663326030053">"Naprava je morda nadzorovana"</string>
    +     <string name="profile_owned_footer" msgid="8021888108553696069">"Profil je morda nadziran"</string>
    +     <string name="vpn_footer" msgid="2388611096129106812">"Omrežje je lahko nadzorovano"</string>
    ++    <string name="branded_vpn_footer" msgid="2168111859226496230">"Omrežje je morda nadzorovano"</string>
    +     <string name="monitoring_title_device_owned" msgid="7121079311903859610">"Nadzor naprave"</string>
    +     <string name="monitoring_title_profile_owned" msgid="6790109874733501487">"Nadzor nad profilom"</string>
    +     <string name="monitoring_title" msgid="169206259253048106">"Nadzor omrežja"</string>
    +@@ -422,6 +423,7 @@
    +     <string name="legacy_vpn_name" msgid="6604123105765737830">"VPN"</string>
    +     <string name="monitoring_description_app" msgid="6259179342284742878">"Povezani ste z aplikacijo <xliff:g id="APPLICATION">%1$s</xliff:g>, ki lahko nadzira omrežno dejavnost, vključno z e-pošto, aplikacijami in spletnimi mesti."</string>
    +     <string name="monitoring_description_app_personal" msgid="484599052118316268">"Povezani ste z aplikacijo <xliff:g id="APPLICATION">%1$s</xliff:g>, ki lahko nadzira vašo osebno omrežno dejavnost, vključno z e-pošto, aplikacijami in spletnimi mesti."</string>
    ++    <string name="branded_monitoring_description_app_personal" msgid="2669518213949202599">"Povezani ste z aplikacijo <xliff:g id="APPLICATION">%1$s</xliff:g>, ki lahko nadzira vašo osebno omrežno dejavnost, vključno z e-pošto, aplikacijami in spletnimi mesti."</string>
    +     <string name="monitoring_description_app_work" msgid="1754325860918060897">"Delovni profil upravlja organizacija <xliff:g id="ORGANIZATION">%1$s</xliff:g>. Povezan je z aplikacijo <xliff:g id="APPLICATION">%2$s</xliff:g>, ki lahko nadzira vašo delovno omrežno dejavnost, vključno z e-pošto, aplikacijami in spletnimi mesti.\n\nČe želite več informacij, se obrnite na skrbnika."</string>
    +     <string name="monitoring_description_app_personal_work" msgid="4946600443852045903">"Delovni profil upravlja organizacija <xliff:g id="ORGANIZATION">%1$s</xliff:g>. Povezan je z aplikacijo <xliff:g id="APPLICATION_WORK">%2$s</xliff:g>, ki lahko nadzira vašo delovno omrežno dejavnost, vključno z e-pošto, aplikacijami in spletnimi mesti.\n\nPovezani ste tudi z aplikacijo <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g>, ki lahko nadzira vašo osebno omrežno dejavnost."</string>
    +     <string name="monitoring_description_vpn_app_device_owned" msgid="4970443827043261703">"Napravo upravlja organizcija <xliff:g id="ORGANIZATION">%1$s</xliff:g>.\n\nSkrbnik lahko nadzira in upravlja nastavitve, dostop za podjetje, aplikacije, podatke, povezane z napravo, in podatke o lokaciji naprave.\n\nPovezani ste z aplikacijo <xliff:g id="APPLICATION">%2$s</xliff:g>, ki lahko nadzira omrežno dejavnost, vključno z e-pošto, aplikacijami in spletnimi mesti.\n\nČe želite več informacij, se obrnite na skrbnika."</string>
    +@@ -498,8 +500,6 @@
    +     <string name="clock_seconds_desc" msgid="6282693067130470675">"Prikaže sekunde pri uri v vrstici stanja. To lahko vpliva na čas delovanja pri akumulatorskem napajanju."</string>
    +     <string name="qs_rearrange" msgid="8060918697551068765">"Preuredi hitre nastavitve"</string>
    +     <string name="show_brightness" msgid="6613930842805942519">"Prikaz svetlosti v hitrih nastavitvah"</string>
    +-    <string name="overview_nav_bar_gesture" msgid="8579814204727917764">"Omogočanje poteze za razdeljen zaslon z vlečenjem navzgor"</string>
    +-    <string name="overview_nav_bar_gesture_desc" msgid="6329167382305102615">"Omogočanje poteze za vklop razdeljenega zaslona, tako da uporabnik od gumba za pregled povleče s prstom navzgor"</string>
    +     <string name="experimental" msgid="6198182315536726162">"Poskusno"</string>
    +     <string name="enable_bluetooth_title" msgid="5027037706500635269">"Želite vklopiti Bluetooth?"</string>
    +     <string name="enable_bluetooth_message" msgid="9106595990708985385">"Če želite povezati tipkovnico in tablični računalnik, vklopite Bluetooth."</string>
    +@@ -657,4 +657,5 @@
    +     <string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"Odpri nastavitve za <xliff:g id="ID_1">%s</xliff:g>."</string>
    +     <string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"Uredi vrstni red nastavitev."</string>
    +     <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"<xliff:g id="ID_1">%1$d</xliff:g>. stran od <xliff:g id="ID_2">%2$d</xliff:g>"</string>
    ++    <string name="cant_silence_or_block" msgid="999689262131488625">"Obvestil ni mogoče utišati ali blokirati"</string>
    + </resources>
    +diff --git a/packages/SystemUI/res/values-sq-rAL/strings.xml b/packages/SystemUI/res/values-sq-rAL/strings.xml
    +index 4bc29aa..68f5685 100644
    +--- a/packages/SystemUI/res/values-sq-rAL/strings.xml
    ++++ b/packages/SystemUI/res/values-sq-rAL/strings.xml
    +@@ -238,7 +238,7 @@
    +     <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"Të dhënat 4G janë ndërprerë"</string>
    +     <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"Të dhënat celulare janë ndërprerë"</string>
    +     <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"Të dhënat janë ndërprerë"</string>
    +-    <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"Pajisja jote ka ndërprerë përdorimin e të dhënave për pjesën e mbetur të ciklit sepse është arritur kufiri i caktuar i të dhënave.\n\nVazhdimi mund të sjellë tarifa nga operatori celular."</string>
    ++    <string name="data_usage_disabled_dialog" msgid="1841738975235283398">"Kufiri i të dhënave që ke caktuar është arritur. Nuk po përdor më të dhënat celulare.\n\nNëse vazhdon, mund të zbatohen tarifa për përdorimin e të dhënave."</string>
    +     <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"Rifillo"</string>
    +     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Nuk ka lidhje interneti"</string>
    +     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi është i lidhur"</string>
    +@@ -404,6 +404,7 @@
    +     <string name="device_owned_footer" msgid="3802752663326030053">"Pajisja mund të monitorohet"</string>
    +     <string name="profile_owned_footer" msgid="8021888108553696069">"Profili mund të monitorohet"</string>
    +     <string name="vpn_footer" msgid="2388611096129106812">"Rrjeti mund të jetë i monitoruar"</string>
    ++    <string name="branded_vpn_footer" msgid="2168111859226496230">"Rrjeti mund të jetë i monitoruar"</string>
    +     <string name="monitoring_title_device_owned" msgid="7121079311903859610">"Monitorimi i pajisjes"</string>
    +     <string name="monitoring_title_profile_owned" msgid="6790109874733501487">"Monitorimi i profilit"</string>
    +     <string name="monitoring_title" msgid="169206259253048106">"Monitorimi i rrjetit"</string>
    +@@ -416,6 +417,7 @@
    +     <string name="legacy_vpn_name" msgid="6604123105765737830">"VPN"</string>
    +     <string name="monitoring_description_app" msgid="6259179342284742878">"Je i lidhur me aplikacionin <xliff:g id="APPLICATION">%1$s</xliff:g>, i cili mund të monitorojë aktivitetin tënd në rrjet përfshirë mailet, aplikacionet dhe sajtet e uebit."</string>
    +     <string name="monitoring_description_app_personal" msgid="484599052118316268">"Je i lidhur me aplikacionin <xliff:g id="APPLICATION">%1$s</xliff:g>, i cili mund të monitorojë aktivitetin tënd personal në rrjet, përfshirë mailet, aplikacionet dhe sajtet e uebit."</string>
    ++    <string name="branded_monitoring_description_app_personal" msgid="2669518213949202599">"Je i lidhur me aplikacionin <xliff:g id="APPLICATION">%1$s</xliff:g>, i cili mund të monitorojë aktivitetin tënd personal në rrjet, përfshirë mailet, aplikacionet dhe sajtet e uebit."</string>
    +     <string name="monitoring_description_app_work" msgid="1754325860918060897">"Profili yt i punës menaxhohet nga <xliff:g id="ORGANIZATION">%1$s</xliff:g>. Ai është i lidhur me <xliff:g id="APPLICATION">%2$s</xliff:g>, i cili mund të monitorojë aktivitetin tënd të punës në rrjet, përfshirë mailet, aplikacionet dhe sajtet e uebit.\n\nPër më shumë informacione, kontakto me administratorin tënd."</string>
    +     <string name="monitoring_description_app_personal_work" msgid="4946600443852045903">"Profili yt i punës menaxhohet nga <xliff:g id="ORGANIZATION">%1$s</xliff:g>. Ai është i lidhur me <xliff:g id="APPLICATION_WORK">%2$s</xliff:g>, i cili mund të monitorojë aktivitetin tënd të punës në rrjet, përfshirë mailet, aplikacionet dhe sajtet e uebit.\n\nJe lidhur gjithashtu edhe me <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g>, i cili mund të monitorojë aktivitetin tënd personal në rrjet."</string>
    +     <string name="monitoring_description_vpn_app_device_owned" msgid="4970443827043261703">"Pajisja jote menaxhohet nga <xliff:g id="ORGANIZATION">%1$s</xliff:g>.\n\nAdministratori mund të monitorojë dhe menaxhojë cilësimet, qasjen e korporatës, aplikacionet, të dhënat që shoqërojnë pajisjen tënde si dhe informacionin e vendndodhjes së pajisjes.\n\nJe i lidhur me <xliff:g id="APPLICATION">%2$s</xliff:g>, që mund të monitorojë aktivitetin tënd të punës në rrjet përfshirë mail-at, aplikacionet dhe faqet e internetit.\n\nPër më shumë informacion, kontakto me administratorin tënd."</string>
    +@@ -492,8 +494,6 @@
    +     <string name="clock_seconds_desc" msgid="6282693067130470675">"Trego sekondat e orës në shiritin e statusit. Mund të ndikojë te jeta e baterisë."</string>
    +     <string name="qs_rearrange" msgid="8060918697551068765">"Risistemo Cilësimet e shpejta"</string>
    +     <string name="show_brightness" msgid="6613930842805942519">"Shfaq ndriçimin te Cilësimet e shpejta"</string>
    +-    <string name="overview_nav_bar_gesture" msgid="8579814204727917764">"Aktivizo gjestin e rrëshqitjes lart për ekranin e ndarë"</string>
    +-    <string name="overview_nav_bar_gesture_desc" msgid="6329167382305102615">"Aktivizo gjestin për të hyrë tek ekrani i ndarë duke rrëshqitur lart nga butoni \"Përmbledhja\""</string>
    +     <string name="experimental" msgid="6198182315536726162">"Eksperimentale"</string>
    +     <string name="enable_bluetooth_title" msgid="5027037706500635269">"Të aktivizohet \"bluetooth-i\"?"</string>
    +     <string name="enable_bluetooth_message" msgid="9106595990708985385">"Për të lidhur tastierën me tabletin, në fillim duhet të aktivizosh \"bluetooth-in\"."</string>
    +@@ -651,4 +651,5 @@
    +     <string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"Hap cilësimet e <xliff:g id="ID_1">%s</xliff:g>."</string>
    +     <string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"Modifiko rendin e cilësimeve."</string>
    +     <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"Faqja <xliff:g id="ID_1">%1$d</xliff:g> nga <xliff:g id="ID_2">%2$d</xliff:g>"</string>
    ++    <string name="cant_silence_or_block" msgid="999689262131488625">"Njoftimet nuk mund të vendosen në heshtje ose të bllokohen"</string>
    + </resources>
    +diff --git a/packages/SystemUI/res/values-sr/strings.xml b/packages/SystemUI/res/values-sr/strings.xml
    +index 16ae7e2..d313054 100644
    +--- a/packages/SystemUI/res/values-sr/strings.xml
    ++++ b/packages/SystemUI/res/values-sr/strings.xml
    +@@ -239,7 +239,7 @@
    +     <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"4G подаци су паузирани"</string>
    +     <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"Мобилни подаци су паузирани"</string>
    +     <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"Подаци су паузирани"</string>
    +-    <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"Због тога што сте достигли подешено ограничење за податке, уређај је паузирао коришћење података током остатка овог циклуса.\n\nАко наставите, мобилни оператер може да вам наплати додатне трошкове."</string>
    ++    <string name="data_usage_disabled_dialog" msgid="1841738975235283398">"Ограничење потрошње података које сте подесили је достигнуто. Више не користите мобилне податке.\n\nАко наставите, можда ће бити наплаћени трошкови за потрошњу података."</string>
    +     <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"Настави"</string>
    +     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Нема интернет везе"</string>
    +     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi је повезан"</string>
    +@@ -406,6 +406,7 @@
    +     <string name="device_owned_footer" msgid="3802752663326030053">"Уређај се можда надгледа"</string>
    +     <string name="profile_owned_footer" msgid="8021888108553696069">"Профил се можда надгледа"</string>
    +     <string name="vpn_footer" msgid="2388611096129106812">"Мрежа се можда надгледа"</string>
    ++    <string name="branded_vpn_footer" msgid="2168111859226496230">"Мрежа се можда надгледа"</string>
    +     <string name="monitoring_title_device_owned" msgid="7121079311903859610">"Надгледање уређаја"</string>
    +     <string name="monitoring_title_profile_owned" msgid="6790109874733501487">"Надгледање профила"</string>
    +     <string name="monitoring_title" msgid="169206259253048106">"Надгледање мреже"</string>
    +@@ -418,6 +419,7 @@
    +     <string name="legacy_vpn_name" msgid="6604123105765737830">"VPN"</string>
    +     <string name="monitoring_description_app" msgid="6259179342284742878">"Повезани сте са апликацијом <xliff:g id="APPLICATION">%1$s</xliff:g>, која може да надгледа активности на мрежи, укључујући имејлове, апликације и веб-сајтове."</string>
    +     <string name="monitoring_description_app_personal" msgid="484599052118316268">"Повезани сте са апликацијом <xliff:g id="APPLICATION">%1$s</xliff:g>, која може да надгледа активности на личној мрежи, укључујући имејлове, апликације и веб-сајтове."</string>
    ++    <string name="branded_monitoring_description_app_personal" msgid="2669518213949202599">"Повезани сте са апликацијом <xliff:g id="APPLICATION">%1$s</xliff:g>, која може да надгледа активности на личној мрежи, укључујући имејлове, апликације и веб-сајтове."</string>
    +     <string name="monitoring_description_app_work" msgid="1754325860918060897">"Профилом за Work управља <xliff:g id="ORGANIZATION">%1$s</xliff:g>. Повезан је са апликацијом <xliff:g id="APPLICATION">%2$s</xliff:g>, која може да надгледа активности на пословној мрежи, укључујући имејлове, апликације и веб-сајтове.\n\nВише информација потражите од администратора."</string>
    +     <string name="monitoring_description_app_personal_work" msgid="4946600443852045903">"Профилом за Work управља <xliff:g id="ORGANIZATION">%1$s</xliff:g>. Повезан је са апликацијом <xliff:g id="APPLICATION_WORK">%2$s</xliff:g>, која може да надгледа активности на пословној мрежи, укључујући имејлове, апликације и веб-сајтове.\n\nПовезани сте и са апликацијом <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g>, која може да надгледа активности на личној мрежи."</string>
    +     <string name="monitoring_description_vpn_app_device_owned" msgid="4970443827043261703">"Уређајем управља <xliff:g id="ORGANIZATION">%1$s</xliff:g>.\n\nАдминистратор може да надгледа подешавања, корпоративни приступ, апликације, податке повезане са уређајем и информације о локацији уређаја, као и да управља њима.\n\nПовезани сте са апликацијом <xliff:g id="APPLICATION">%2$s</xliff:g>, која може да надгледа активности на мрежи, укључујући имејлове, апликације и веб-сајтове.\n\nВише информација потражите од администратора."</string>
    +@@ -494,8 +496,6 @@
    +     <string name="clock_seconds_desc" msgid="6282693067130470675">"Секунде на сату се приказују на статусној траци. То може да утиче на трајање батерије."</string>
    +     <string name="qs_rearrange" msgid="8060918697551068765">"Преуреди Брза подешавања"</string>
    +     <string name="show_brightness" msgid="6613930842805942519">"Прикажи осветљеност у Брзим подешавањима"</string>
    +-    <string name="overview_nav_bar_gesture" msgid="8579814204727917764">"Омогући покрет за превлачење нагоре за подељени екран"</string>
    +-    <string name="overview_nav_bar_gesture_desc" msgid="6329167382305102615">"Омогућава покрет за прелазак на подељени екран превлачењем нагоре од дугмета Преглед"</string>
    +     <string name="experimental" msgid="6198182315536726162">"Експериментално"</string>
    +     <string name="enable_bluetooth_title" msgid="5027037706500635269">"Желите ли да укључите Bluetooth?"</string>
    +     <string name="enable_bluetooth_message" msgid="9106595990708985385">"Да бисте повезали тастатуру са таблетом, прво морате да укључите Bluetooth."</string>
    +@@ -653,4 +653,5 @@
    +     <string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"Отвори подешавања за <xliff:g id="ID_1">%s</xliff:g>."</string>
    +     <string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"Измени редослед подешавања."</string>
    +     <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"<xliff:g id="ID_1">%1$d</xliff:g>. страна од <xliff:g id="ID_2">%2$d</xliff:g>"</string>
    ++    <string name="cant_silence_or_block" msgid="999689262131488625">"Звук обавештења не може да се искључи нити она могу да се блокирају"</string>
    + </resources>
    +diff --git a/packages/SystemUI/res/values-sv/strings.xml b/packages/SystemUI/res/values-sv/strings.xml
    +index e6988d7..8176422 100644
    +--- a/packages/SystemUI/res/values-sv/strings.xml
    ++++ b/packages/SystemUI/res/values-sv/strings.xml
    +@@ -238,7 +238,7 @@
    +     <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"4G-data har pausats"</string>
    +     <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"Mobildata har pausats"</string>
    +     <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"Dataanvändningen har pausats"</string>
    +-    <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"Eftersom du har nått den angivna datagränsen har dataanvändningen pausats under resten av perioden.\n\nOm du återupptar dataanvändningen kan avgifter från operatören tillkomma."</string>
    ++    <string name="data_usage_disabled_dialog" msgid="1841738975235283398">"Den angivna datagränsen har uppnåtts. Du använder inte längre mobildata.\n\nOm du fortsätter kan avgifter för dataanvändning tillkomma."</string>
    +     <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"Återuppta"</string>
    +     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Ingen anslutning"</string>
    +     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi-ansluten"</string>
    +@@ -331,7 +331,7 @@
    +     <string name="recents_launch_disabled_message" msgid="1624523193008871793">"<xliff:g id="APP">%s</xliff:g> är inaktiverad i säkert läge."</string>
    +     <string name="recents_stack_action_button_label" msgid="6593727103310426253">"Rensa alla"</string>
    +     <string name="recents_incompatible_app_message" msgid="5075812958564082451">"Appen har inte stöd för delad skärm."</string>
    +-    <string name="recents_drag_hint_message" msgid="2649739267073203985">"Dra här om du vill dela upp skärmen"</string>
    ++    <string name="recents_drag_hint_message" msgid="2649739267073203985">"Dra hit för att dela upp skärmen"</string>
    +     <string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"Dela horisontellt"</string>
    +     <string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"Dela vertikalt"</string>
    +     <string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"Dela anpassad"</string>
    +@@ -352,7 +352,7 @@
    +     <string name="keyguard_more_overflow_text" msgid="9195222469041601365">"+<xliff:g id="NUMBER_OF_NOTIFICATIONS">%d</xliff:g>"</string>
    +     <string name="speed_bump_explanation" msgid="1288875699658819755">"Mindre brådskande aviseringar nedan"</string>
    +     <string name="notification_tap_again" msgid="7590196980943943842">"Tryck igen för att öppna"</string>
    +-    <string name="keyguard_unlock" msgid="8043466894212841998">"Svep uppåt om du vill låsa upp"</string>
    ++    <string name="keyguard_unlock" msgid="8043466894212841998">"Svep uppåt för att låsa upp"</string>
    +     <string name="phone_hint" msgid="4872890986869209950">"Svep från ikonen och öppna telefonen"</string>
    +     <string name="voice_hint" msgid="8939888732119726665">"Svep från ikonen och öppna röstassistenten"</string>
    +     <string name="camera_hint" msgid="7939688436797157483">"Svep från ikonen och öppna kameran"</string>
    +@@ -404,6 +404,7 @@
    +     <string name="device_owned_footer" msgid="3802752663326030053">"Enheten kan övervakas"</string>
    +     <string name="profile_owned_footer" msgid="8021888108553696069">"Det kan hända att profilen övervakas"</string>
    +     <string name="vpn_footer" msgid="2388611096129106812">"Nätverket kan vara övervakat"</string>
    ++    <string name="branded_vpn_footer" msgid="2168111859226496230">"Nätverket kan vara övervakat"</string>
    +     <string name="monitoring_title_device_owned" msgid="7121079311903859610">"Enhetsövervakning"</string>
    +     <string name="monitoring_title_profile_owned" msgid="6790109874733501487">"Profilövervakning"</string>
    +     <string name="monitoring_title" msgid="169206259253048106">"Nätverksövervakning"</string>
    +@@ -416,6 +417,7 @@
    +     <string name="legacy_vpn_name" msgid="6604123105765737830">"VPN"</string>
    +     <string name="monitoring_description_app" msgid="6259179342284742878">"Du är ansluten till <xliff:g id="APPLICATION">%1$s</xliff:g>, som kan bevaka aktivitet på nätverket, inklusive e-post, appar och webbplatser."</string>
    +     <string name="monitoring_description_app_personal" msgid="484599052118316268">"Du är ansluten till <xliff:g id="APPLICATION">%1$s</xliff:g>, som kan bevaka din privata aktivitet på nätverket, inklusive e-post, appar och webbplatser."</string>
    ++    <string name="branded_monitoring_description_app_personal" msgid="2669518213949202599">"Du är ansluten till <xliff:g id="APPLICATION">%1$s</xliff:g> som kan övervaka din privata aktivitet på nätverket, inklusive e-postmeddelanden, appar och webbplatser."</string>
    +     <string name="monitoring_description_app_work" msgid="1754325860918060897">"Jobbprofilen hanteras av <xliff:g id="ORGANIZATION">%1$s</xliff:g>. Den är ansluten till <xliff:g id="APPLICATION">%2$s</xliff:g>, som kan hantera aktivitet på arbetsplatsens nätverk, inklusive e-post, appar och webbplatser.\n\nKontakta administratören för mer information."</string>
    +     <string name="monitoring_description_app_personal_work" msgid="4946600443852045903">"Jobbprofilen hanteras av <xliff:g id="ORGANIZATION">%1$s</xliff:g>. Den är ansluten till <xliff:g id="APPLICATION_WORK">%2$s</xliff:g>, som kan hantera aktivitet på arbetsplatsens nätverk, inklusive e-post, appar och webbplatser.\n\nDu är även ansluten till <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g>, som kan hantera privat aktivitet på nätverket."</string>
    +     <string name="monitoring_description_vpn_app_device_owned" msgid="4970443827043261703">"Enheten hanteras av <xliff:g id="ORGANIZATION">%1$s</xliff:g>.\n\nAdministratören kan bevaka och hantera inställningar, företagsåtkomst, appar, data som är kopplad till enheten och enhetens platsuppgifter.\n\nDu är ansluten till <xliff:g id="APPLICATION">%2$s</xliff:g>, som kan övervaka aktivitet på nätverket, inklusive e-post. appar och webbplatser .\n\nKontakta administratören för mer information."</string>
    +@@ -492,8 +494,6 @@
    +     <string name="clock_seconds_desc" msgid="6282693067130470675">"Visa klocksekunder i statusfältet. Detta kan påverka batteritiden."</string>
    +     <string name="qs_rearrange" msgid="8060918697551068765">"Ordna snabbinställningarna"</string>
    +     <string name="show_brightness" msgid="6613930842805942519">"Visa ljusstyrka i snabbinställningarna"</string>
    +-    <string name="overview_nav_bar_gesture" msgid="8579814204727917764">"Aktivera delad skärm när du sveper uppåt"</string>
    +-    <string name="overview_nav_bar_gesture_desc" msgid="6329167382305102615">"Aktivera en rörelse som delar skärmen när du sveper uppåt från knappen Översikt"</string>
    +     <string name="experimental" msgid="6198182315536726162">"Experimentella"</string>
    +     <string name="enable_bluetooth_title" msgid="5027037706500635269">"Vill du aktivera Bluetooth?"</string>
    +     <string name="enable_bluetooth_message" msgid="9106595990708985385">"Om du vill ansluta tangentbordet till surfplattan måste du först aktivera Bluetooth."</string>
    +@@ -651,4 +651,5 @@
    +     <string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"Öppna <xliff:g id="ID_1">%s</xliff:g>-inställningarna."</string>
    +     <string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"Ändra ordning på inställningarna."</string>
    +     <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"Sida <xliff:g id="ID_1">%1$d</xliff:g> av <xliff:g id="ID_2">%2$d</xliff:g>"</string>
    ++    <string name="cant_silence_or_block" msgid="999689262131488625">"Det går inte att tysta eller blockera aviseringar"</string>
    + </resources>
    +diff --git a/packages/SystemUI/res/values-sw/strings.xml b/packages/SystemUI/res/values-sw/strings.xml
    +index 50c6685..f8b825a 100644
    +--- a/packages/SystemUI/res/values-sw/strings.xml
    ++++ b/packages/SystemUI/res/values-sw/strings.xml
    +@@ -238,7 +238,7 @@
    +     <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"Data ya 4G imesitishwa"</string>
    +     <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"Data ya simu ya mkononi imesitishwa"</string>
    +     <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"Data imesitishwa"</string>
    +-    <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"Kwa sababu ulifikia kiwango cha juu cha data kilichowekwa, kifaa kimesitisha matumizi ya data katika awamu hii iliyosalia.\n\n Kuendelea kunaweza kusababisha malipo kwa mtoa huduma wako."</string>
    ++    <string name="data_usage_disabled_dialog" msgid="1841738975235283398">"Umefikia kikomo cha data ulichoweka. Hutaweza kutumia tena data ya simu ya mkononi.\n\nIkiwa utaendelea, huenda ukatozwa ada za matumizi ya data."</string>
    +     <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"Endelea"</string>
    +     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Hakuna muunganisho wa mtandao"</string>
    +     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Mtandao-hewa umeunganishwa"</string>
    +@@ -404,6 +404,7 @@
    +     <string name="device_owned_footer" msgid="3802752663326030053">"Huenda kifaa kinafuatiliwa"</string>
    +     <string name="profile_owned_footer" msgid="8021888108553696069">"Huenda wasifu ukafuatiliwa"</string>
    +     <string name="vpn_footer" msgid="2388611096129106812">"Huenda mtandao unafuatiliwa"</string>
    ++    <string name="branded_vpn_footer" msgid="2168111859226496230">"Huenda mtandao unafuatiliwa"</string>
    +     <string name="monitoring_title_device_owned" msgid="7121079311903859610">"Ufuatiliaji wa kifaa"</string>
    +     <string name="monitoring_title_profile_owned" msgid="6790109874733501487">"Ufuatiliaji wasifu"</string>
    +     <string name="monitoring_title" msgid="169206259253048106">"Ufuatiliaji wa mtandao"</string>
    +@@ -416,6 +417,7 @@
    +     <string name="legacy_vpn_name" msgid="6604123105765737830">"VPN"</string>
    +     <string name="monitoring_description_app" msgid="6259179342284742878">"Umeunganishwa kwenye <xliff:g id="APPLICATION">%1$s</xliff:g>, ambayo inaweza kufuatilia shughuli za mtandao wako, ikiwa ni pamoja na barua pepe, programu na tovuti."</string>
    +     <string name="monitoring_description_app_personal" msgid="484599052118316268">"Umeunganishwa kwenye <xliff:g id="APPLICATION">%1$s</xliff:g>, ambayo inaweza kufuatilia shughuli za mtandao wako, ikiwa ni pamoja na barua pepe, programu na tovuti."</string>
    ++    <string name="branded_monitoring_description_app_personal" msgid="2669518213949202599">"Umeunganishwa kwenye <xliff:g id="APPLICATION">%1$s</xliff:g>, ambayo inaweza kufuatilia shughuli za mtandao wako, ikiwa ni pamoja na barua pepe, programu na tovuti."</string>
    +     <string name="monitoring_description_app_work" msgid="1754325860918060897">"Wasifu wako wa kazini unasimamiwa na <xliff:g id="ORGANIZATION">%1$s</xliff:g>. Wasifu huu umeunganishwa kwenye <xliff:g id="APPLICATION">%2$s</xliff:g>, ambayo inaweza kufuatilia shughuli za mtandao wako, ikiwa ni pamoja na barua pepe, programu, na tovuti. \n\nKwa maelezo zaidi, wasiliana na msimamizi wako."</string>
    +     <string name="monitoring_description_app_personal_work" msgid="4946600443852045903">"Wasifu wako wa kazini unasimamiwa na <xliff:g id="ORGANIZATION">%1$s</xliff:g>. Wasifu huu umeunganishwa kwenye <xliff:g id="APPLICATION_WORK">%2$s</xliff:g>, ambayo inaweza kufuatilia mtandao wako wa kazini, ikiwa ni pamoja na barua pepe, programu na tovuti. \n\n Wewe pia umeunganishwa kwenye <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g>, ambayo inaweza kufuatilia shughuli za mtandao wako kibinafsi."</string>
    +     <string name="monitoring_description_vpn_app_device_owned" msgid="4970443827043261703">"Kifaa chako kinasimamiwa na <xliff:g id="ORGANIZATION">%1$s</xliff:g>. \n\nMsimamizi wako anaweza kufuatilia na kudhibiti mipangilio, ufikiaji wa kampuni, programu, data inayohusiana na kifaa chako, na maelezo ya mahali kilipo kifaa chako. \n\n Umeuganishwa kwenye <xliff:g id="APPLICATION">%2$s</xliff:g>, ambayo inaweza kufuatilia shughuli ya mtandao wako, ikiwa ni pamoja na barua pepe, programu, na tovuti. \n\n Kwa maelezo zaidi, wasiliana na msimamizi wako."</string>
    +@@ -492,8 +494,6 @@
    +     <string name="clock_seconds_desc" msgid="6282693067130470675">"Onyesha sekunde za saa katika sehemu ya arifa. Inaweza kuathiri muda wa matumizi ya betri."</string>
    +     <string name="qs_rearrange" msgid="8060918697551068765">"Panga Upya Mipangilio ya Haraka"</string>
    +     <string name="show_brightness" msgid="6613930842805942519">"Onyesha unga\'avu katika Mipangilio ya Haraka"</string>
    +-    <string name="overview_nav_bar_gesture" msgid="8579814204727917764">"Ruhusu kugawanya skrini kwa ishara ya kutelezesha kidole juu"</string>
    +-    <string name="overview_nav_bar_gesture_desc" msgid="6329167382305102615">"Washa kipengele cha ishara ili utumie skrini iliyogawanywa kwa kutelezesha kidole juu kutoka kitufe cha Muhtasari"</string>
    +     <string name="experimental" msgid="6198182315536726162">"Ya majaribio"</string>
    +     <string name="enable_bluetooth_title" msgid="5027037706500635269">"Je, ungependa kuwasha Bluetooth?"</string>
    +     <string name="enable_bluetooth_message" msgid="9106595990708985385">"Ili uunganishe Kibodi yako kwenye kompyuta yako kibao, lazima kwanza uwashe Bluetooth."</string>
    +@@ -651,4 +651,5 @@
    +     <string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"Fungua mipangilio ya <xliff:g id="ID_1">%s</xliff:g>."</string>
    +     <string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"Badilisha orodha ya mipangilio."</string>
    +     <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"Ukurasa wa <xliff:g id="ID_1">%1$d</xliff:g> kati ya <xliff:g id="ID_2">%2$d</xliff:g>"</string>
    ++    <string name="cant_silence_or_block" msgid="999689262131488625">"Huwezi kuzima wala kuzuia arifa"</string>
    + </resources>
    +diff --git a/packages/SystemUI/res/values-ta-rIN/strings.xml b/packages/SystemUI/res/values-ta-rIN/strings.xml
    +index f0cb530..0080f8e 100644
    +--- a/packages/SystemUI/res/values-ta-rIN/strings.xml
    ++++ b/packages/SystemUI/res/values-ta-rIN/strings.xml
    +@@ -238,7 +238,7 @@
    +     <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"4G டேட்டா இடைநிறுத்தப்பட்டது"</string>
    +     <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"செல்லுலார் தரவு இடைநிறுத்தப்பட்டது"</string>
    +     <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"தரவு இடைநிறுத்தப்பட்டது"</string>
    +-    <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"அமைக்கப்பட்ட தரவின் வரம்பை அடைந்துவிட்டதால், இந்தச் சுழற்சியின் மீதமுள்ள நாட்களுக்கான தரவுப் பயன்பாட்டைச் சாதனம் இடைநிறுத்தியுள்ளது.\n\nமீண்டும் தொடங்குவது, மொபைல் நிறுவனக் கட்டணங்களுக்கு உட்படுத்தலாம்."</string>
    ++    <string name="data_usage_disabled_dialog" msgid="1841738975235283398">"நீங்கள் அமைத்த தரவு வரம்பை அடைந்துவிட்டீர்கள். இப்போது செல்லுலார் தரவைப் பயன்படுத்த முடியாது.\n\nமீண்டும் தொடங்கினால், தரவுப் பயன்பாட்டிற்குக் கட்டணங்கள் விதிக்கப்படலாம்."</string>
    +     <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"மீண்டும் தொடங்கு"</string>
    +     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"இணைய இணைப்பு இல்லை"</string>
    +     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"வைஃபை இணைக்கப்பட்டது"</string>
    +@@ -404,6 +404,7 @@
    +     <string name="device_owned_footer" msgid="3802752663326030053">"சாதனம் கண்காணிக்கப்படலாம்"</string>
    +     <string name="profile_owned_footer" msgid="8021888108553696069">"சுயவிவரம் கண்காணிக்கப்படலாம்"</string>
    +     <string name="vpn_footer" msgid="2388611096129106812">"நெட்வொர்க் கண்காணிக்கப்படலாம்"</string>
    ++    <string name="branded_vpn_footer" msgid="2168111859226496230">"நெட்வொர்க் கண்காணிக்கப்படலாம்"</string>
    +     <string name="monitoring_title_device_owned" msgid="7121079311903859610">"சாதனத்தைக் கண்காணித்தல்"</string>
    +     <string name="monitoring_title_profile_owned" msgid="6790109874733501487">"சுயவிவரத்தைக் கண்காணித்தல்"</string>
    +     <string name="monitoring_title" msgid="169206259253048106">"நெட்வொர்க்கைக் கண்காணித்தல்"</string>
    +@@ -416,6 +417,7 @@
    +     <string name="legacy_vpn_name" msgid="6604123105765737830">"VPN"</string>
    +     <string name="monitoring_description_app" msgid="6259179342284742878">"<xliff:g id="APPLICATION">%1$s</xliff:g> உடன் இணைக்கப்பட்டுள்ளீர்கள். இந்தப் பயன்பாட்டால், மின்னஞ்சல்கள், பயன்பாடுகள் மற்றும் இணையதளங்கள் உட்பட உங்கள் நெட்வொர்க் செயல்பாட்டைக் கண்காணிக்க முடியும்."</string>
    +     <string name="monitoring_description_app_personal" msgid="484599052118316268">"<xliff:g id="APPLICATION">%1$s</xliff:g> உடன் இணைக்கப்பட்டுள்ளீர்கள். இந்தப் பயன்பாட்டால், மின்னஞ்சல்கள், பயன்பாடுகள் மற்றும் இணையதளங்கள் உட்பட உங்கள் தனிப்பட்ட நெட்வொர்க் செயல்பாட்டைக் கண்காணிக்க முடியும்."</string>
    ++    <string name="branded_monitoring_description_app_personal" msgid="2669518213949202599">"<xliff:g id="APPLICATION">%1$s</xliff:g> உடன் இணைக்கப்பட்டுள்ளீர்கள். இந்தப் பயன்பாட்டால் மின்னஞ்சல்கள், பயன்பாடுகள், இணையதளங்கள் உட்பட உங்கள் தனிப்பட்ட நெட்வொர்க் செயல்பாட்டைக் கண்காணிக்க முடியும்."</string>
    +     <string name="monitoring_description_app_work" msgid="1754325860918060897">"உங்கள் பணி சுயவிவரத்தை <xliff:g id="ORGANIZATION">%1$s</xliff:g> நிர்வகிக்கிறது. <xliff:g id="APPLICATION">%2$s</xliff:g> உடன் இணைக்கப்பட்டதால், மின்னஞ்சல்கள், பயன்பாடுகள் மற்றும் இணையதளங்கள் உட்பட உங்கள் பணியிட நெட்வொர்க் செயல்பாட்டை அதனால் கண்காணிக்க முடியும்.\n\nகூடுதல் தகவலுக்கு, நிர்வாகியைத் தொடர்புகொள்ளவும்."</string>
    +     <string name="monitoring_description_app_personal_work" msgid="4946600443852045903">"உங்கள் பணி சுயவிவரத்தை <xliff:g id="ORGANIZATION">%1$s</xliff:g> நிர்வகிக்கிறது. <xliff:g id="APPLICATION_WORK">%2$s</xliff:g> உடன் இணைக்கப்பட்டுள்ளதால், மின்னஞ்சல்கள், பயன்பாடுகள் மற்றும் இணையதளங்கள் உட்பட உங்கள் பணியிட நெட்வொர்க் செயல்பாட்டை அதனால் கண்காணிக்க முடியும்.\n\nமேலும் <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g> உடன் இணைக்கப்பட்டுள்ளதால், உங்கள் தனிப்பட்ட நெட்வொர்க் செயல்பாட்டையும் அதனால் கண்காணிக்க முடியும்."</string>
    +     <string name="monitoring_description_vpn_app_device_owned" msgid="4970443827043261703">"சாதனத்தை நிர்வகிப்பது: <xliff:g id="ORGANIZATION">%1$s</xliff:g>.\n\nஉங்கள் நிர்வாகியால் அமைப்புகள், நிறுவன அணுகல், பயன்பாடுகள், சாதனத்துடன் தொடர்புடைய தரவு மற்றும் சாதனத்தின் இருப்பிடத் தகவல் ஆகியவற்றைக் கண்காணிக்கவும் நிர்வகிக்கவும் முடியும்.\n\n<xliff:g id="APPLICATION">%2$s</xliff:g> உடன் இணைக்கப்பட்டதால், மின்னஞ்சல்கள், பயன்பாடுகள் மற்றும் இணையதளங்கள் உட்பட உங்கள் நெட்வொர்க் செயல்பாட்டை அதனால் கண்காணிக்க முடியும்.\n\nகூடுதல் தகவலுக்கு, நிர்வாகியைத் தொடர்புகொள்ளவும்."</string>
    +@@ -492,8 +494,6 @@
    +     <string name="clock_seconds_desc" msgid="6282693067130470675">"நிலைப் பட்டியில் கடிகார வினாடிகளைக் காட்டும். பேட்டரியின் ஆயுளைக் குறைக்கலாம்."</string>
    +     <string name="qs_rearrange" msgid="8060918697551068765">"விரைவு அமைப்புகளை மறுவரிசைப்படுத்து"</string>
    +     <string name="show_brightness" msgid="6613930842805942519">"விரைவு அமைப்புகளில் ஒளிர்வுப் பட்டியைக் காட்டு"</string>
    +-    <string name="overview_nav_bar_gesture" msgid="8579814204727917764">"மேலே ஸ்வைப் செய்வதன் மூலம் திரையைப் பிரிக்கும் சைகையை இயக்கு"</string>
    +-    <string name="overview_nav_bar_gesture_desc" msgid="6329167382305102615">"மேலோட்டப் பார்வை பொத்தானிலிருந்து மேலே ஸ்வைப் செய்வதன் மூலம், திரைப் பிரிப்பைச் செயலாக்குவதற்கான சைகையை இயக்கும்"</string>
    +     <string name="experimental" msgid="6198182315536726162">"சோதனை முயற்சி"</string>
    +     <string name="enable_bluetooth_title" msgid="5027037706500635269">"புளூடூத்தை இயக்கவா?"</string>
    +     <string name="enable_bluetooth_message" msgid="9106595990708985385">"உங்கள் டேப்லெட்டுடன் விசைப்பலகையை இணைக்க, முதலில் புளூடூத்தை இயக்க வேண்டும்."</string>
    +@@ -651,4 +651,5 @@
    +     <string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"<xliff:g id="ID_1">%s</xliff:g> அமைப்புகளைத் திற."</string>
    +     <string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"அமைப்புகளின் வரிசை முறையைத் திருத்து."</string>
    +     <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"பக்கம் <xliff:g id="ID_1">%1$d</xliff:g> / <xliff:g id="ID_2">%2$d</xliff:g>"</string>
    ++    <string name="cant_silence_or_block" msgid="999689262131488625">"அறிவிப்புகளை ஒலியடக்க அல்லது தடுக்க முடியவில்லை"</string>
    + </resources>
    +diff --git a/packages/SystemUI/res/values-te-rIN/strings.xml b/packages/SystemUI/res/values-te-rIN/strings.xml
    +index e50d47a..a1a85fc 100644
    +--- a/packages/SystemUI/res/values-te-rIN/strings.xml
    ++++ b/packages/SystemUI/res/values-te-rIN/strings.xml
    +@@ -238,7 +238,7 @@
    +     <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"4G డేటా పాజ్ చేయబడింది"</string>
    +     <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"సెల్యులార్ డేటా పాజ్ చేయబడింది"</string>
    +     <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"డేటా పాజ్ చేయబడింది"</string>
    +-    <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"మీ సెట్ చేయబడిన డేటా పరిమితిని చేరుకున్నందున పరికరం ఈ సైకిల్‌లో మిగిలిన భాగానికి డేటా వినియోగాన్ని పాజ్ చేసింది.\n\nపునఃప్రారంభించడం వలన మీ క్యారియర్ ఛార్జీలు విధించవచ్చు."</string>
    ++    <string name="data_usage_disabled_dialog" msgid="1841738975235283398">"మీరు సెట్ చేసిన డేటా పరిమితిని చేరుకున్నారు. మీరు ఇప్పుడు సెల్యులార్ డేటాను ఉపయోగించడం లేదు.\n\nమీరు పునఃప్రారంభిస్తే, డేటా వినియోగానికి ఛార్జీలు వర్తించవచ్చు."</string>
    +     <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"పునఃప్రారంభించు"</string>
    +     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"ఇంటర్నెట్ కనెక్షన్ లేదు"</string>
    +     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi కనెక్ట్ చేయబడింది"</string>
    +@@ -404,6 +404,7 @@
    +     <string name="device_owned_footer" msgid="3802752663326030053">"పరికరం పర్యవేక్షించబడవచ్చు"</string>
    +     <string name="profile_owned_footer" msgid="8021888108553696069">"ప్రొఫైల్‌ని పర్యవేక్షించవచ్చు"</string>
    +     <string name="vpn_footer" msgid="2388611096129106812">"నెట్‌వర్క్ పర్యవేక్షించబడవచ్చు"</string>
    ++    <string name="branded_vpn_footer" msgid="2168111859226496230">"నెట్‌వర్క్ పర్యవేక్షించబడవచ్చు"</string>
    +     <string name="monitoring_title_device_owned" msgid="7121079311903859610">"పరికర పర్యవేక్షణ"</string>
    +     <string name="monitoring_title_profile_owned" msgid="6790109874733501487">"ప్రొఫైల్ పర్యవేక్షణ"</string>
    +     <string name="monitoring_title" msgid="169206259253048106">"నెట్‌వర్క్ పర్యవేక్షణ"</string>
    +@@ -416,6 +417,7 @@
    +     <string name="legacy_vpn_name" msgid="6604123105765737830">"VPN"</string>
    +     <string name="monitoring_description_app" msgid="6259179342284742878">"మీరు <xliff:g id="APPLICATION">%1$s</xliff:g>కి కనెక్ట్ చేయబడ్డారు, ఇది ఇమెయిల్‌లు, అనువర్తనాలు మరియు వెబ్‌సైట్‌లతో సహా మీ నెట్‌వర్క్ కార్యాచరణను పర్యవేక్షించగలదు."</string>
    +     <string name="monitoring_description_app_personal" msgid="484599052118316268">"మీరు <xliff:g id="APPLICATION">%1$s</xliff:g>కి కనెక్ట్ చేయబడ్డారు, ఇది ఇమెయిల్‌లు, అనువర్తనాలు మరియు వెబ్‌‍సైట్‌లతో సహా మీ వ్యక్తిగత నెట్‌వర్క్ కార్యాచరణను పర్యవేక్షించగలదు."</string>
    ++    <string name="branded_monitoring_description_app_personal" msgid="2669518213949202599">"మీరు <xliff:g id="APPLICATION">%1$s</xliff:g>కి కనెక్ట్ చేయబడ్డారు, ఇది ఇమెయిల్‌లు, అనువర్తనాలు మరియు వెబ్‌సైట్‌లతో సహా మీ వ్యక్తిగత నెట్‌వర్క్ కార్యాచరణను పర్యవేక్షించగలదు."</string>
    +     <string name="monitoring_description_app_work" msgid="1754325860918060897">"మీ కార్యాలయ ప్రొఫైల్‌ను <xliff:g id="ORGANIZATION">%1$s</xliff:g> నిర్వహిస్తోంది. అలాగే, మీ కార్యాలయ ప్రొఫైల్ <xliff:g id="APPLICATION">%2$s</xliff:g>కి కనెక్ట్ చేయబడింది, ఇది ఇమెయిల్‌లు, అనువర్తనాలు మరియు వెబ్‌సైట్‌లతో సహా మీ కార్యాలయ నెట్‌వర్క్ కార్యాచరణను పర్యవేక్షించగలదు.\n\nమరింత సమాచారం కోసం, మీ నిర్వాహకుడిని సంప్రదించండి."</string>
    +     <string name="monitoring_description_app_personal_work" msgid="4946600443852045903">"మీ కార్యాలయ ప్రొఫైల్‌ను <xliff:g id="ORGANIZATION">%1$s</xliff:g> నిర్వహిస్తోంది. అలాగే, మీ కార్యాలయ ప్రొఫైల్ <xliff:g id="APPLICATION_WORK">%2$s</xliff:g>కి కనెక్ట్ చేయబడింది, ఇది ఇమెయిల్‌లు, అనువర్తనాలు మరియు వెబ్‌సైట్‌లతో సహా మీ కార్యాలయ నెట్‌వర్క్ కార్యాచరణను పర్యవేక్షించగలదు.\n\nమీరు <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g>కి కూడా కనెక్ట్ చేయబడ్డారు, ఇది మీ వ్యక్తిగత నెట్‌వర్క్ కార్యాచరణను పర్యవేక్షించగలదు."</string>
    +     <string name="monitoring_description_vpn_app_device_owned" msgid="4970443827043261703">"మీ పరికరాన్ని <xliff:g id="ORGANIZATION">%1$s</xliff:g> నిర్వహిస్తోంది.\n\nమీ నిర్వాహకుడు సెట్టింగ్‌లను, కార్పొరేట్ ప్రాప్యతను, అనువర్తనాలను, మీ పరికరంతో అనుబంధించిన డేటాను మరియు మీ పరికర స్థాన సమాచారాన్ని పర్యవేక్షించగలరు మరియు నిర్వహించగలరు.\n\nమీరు <xliff:g id="APPLICATION">%2$s</xliff:g>కి కనెక్ట్ చేయబడ్డారు, ఇది ఇమెయిల్‌లు, అనువర్తనాలు మరియు వెబ్‌సైట్‌లతో సహా మీ నెట్‌వర్క్ కార్యాచరణను పర్యవేక్షించగలదు.\n\nమరింత సమాచారం కోసం, మీ నిర్వాహకుడిని సంప్రదించండి."</string>
    +@@ -492,8 +494,6 @@
    +     <string name="clock_seconds_desc" msgid="6282693067130470675">"స్థితి పట్టీలో గడియారం సెకన్లు చూపుతుంది. బ్యాటరీ శక్తి ప్రభావితం చేయవచ్చు."</string>
    +     <string name="qs_rearrange" msgid="8060918697551068765">"శీఘ్ర సెట్టింగ్‌ల ఏర్పాటు క్రమం మార్చు"</string>
    +     <string name="show_brightness" msgid="6613930842805942519">"శీఘ్ర సెట్టింగ్‌ల్లో ప్రకాశం చూపు"</string>
    +-    <string name="overview_nav_bar_gesture" msgid="8579814204727917764">"పైకి స్వైప్ చేయడం ద్వారా స్క్రీన్ విభజన సంజ్ఞను ప్రారంభించు"</string>
    +-    <string name="overview_nav_bar_gesture_desc" msgid="6329167382305102615">"స్థూలదృష్టి బటన్ నుండి పైకి స్వైప్ చేయడం ద్వారా స్క్రీన్ విభజనలోకి ప్రవేశించడానికి సంజ్ఞను ప్రారంభిస్తుంది"</string>
    +     <string name="experimental" msgid="6198182315536726162">"ప్రయోగాత్మకం"</string>
    +     <string name="enable_bluetooth_title" msgid="5027037706500635269">"బ్లూటూత్ ఆన్ చేయాలా?"</string>
    +     <string name="enable_bluetooth_message" msgid="9106595990708985385">"మీ కీబోర్డ్‌ను మీ టాబ్లెట్‌తో కనెక్ట్ చేయడానికి, మీరు ముందుగా బ్లూటూత్ ఆన్ చేయాలి."</string>
    +@@ -651,4 +651,5 @@
    +     <string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"<xliff:g id="ID_1">%s</xliff:g> సెట్టింగ్‌లను తెరవండి."</string>
    +     <string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"సెట్టింగ్‌ల క్రమాన్ని సవరించండి."</string>
    +     <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"<xliff:g id="ID_2">%2$d</xliff:g>లో <xliff:g id="ID_1">%1$d</xliff:g>వ పేజీ"</string>
    ++    <string name="cant_silence_or_block" msgid="999689262131488625">"నోటిఫికేషన్‌లను నిశ్శబ్దంగా ఉంచలేరు లేదా బ్లాక్ చేయలేరు"</string>
    + </resources>
    +diff --git a/packages/SystemUI/res/values-th/strings.xml b/packages/SystemUI/res/values-th/strings.xml
    +index 7eb227e..805431d 100644
    +--- a/packages/SystemUI/res/values-th/strings.xml
    ++++ b/packages/SystemUI/res/values-th/strings.xml
    +@@ -238,7 +238,7 @@
    +     <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"หยุดการใช้ข้อมูล 4G ชั่วคราวแล้ว"</string>
    +     <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"หยุดการใช้ข้อมูลมือถือชั่วคราวแล้ว"</string>
    +     <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"หยุดการใช้ข้อมูลชั่วคราวแล้ว"</string>
    +-    <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"เนื่องจากใช้งานข้อมูลถึงขีดจำกัดที่กำหนดไว้แล้ว อุปกรณ์จึงหยุดการใช้งานข้อมูลไว้ชั่วคราวตลอดระยะเวลาที่เหลือของรอบนี้\n\nการทำให้กลับมาทำงานอีกครั้งอาจทำให้เกิดค่าใช้จ่ายจากผู้ให้บริการ"</string>
    ++    <string name="data_usage_disabled_dialog" msgid="1841738975235283398">"คุณใช้อินเทอร์เน็ตเกินปริมาณที่กำหนดไว้ ระบบจะไม่ใช้เครือข่ายมือถือต่อไป\n\nหากใช้ต่อ อาจมีค่าบริการตามปริมาณการใช้อินเทอร์เน็ต"</string>
    +     <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"ทำต่อ"</string>
    +     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"ไม่มีอินเทอร์เน็ต"</string>
    +     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"เชื่อมต่อ WiFi แล้ว"</string>
    +@@ -404,6 +404,7 @@
    +     <string name="device_owned_footer" msgid="3802752663326030053">"อาจมีการตรวจสอบอุปกรณ์"</string>
    +     <string name="profile_owned_footer" msgid="8021888108553696069">"อาจมีการตรวจสอบโปรไฟล์"</string>
    +     <string name="vpn_footer" msgid="2388611096129106812">"เครือข่ายอาจได้รับการตรวจสอบ"</string>
    ++    <string name="branded_vpn_footer" msgid="2168111859226496230">"เครือข่ายอาจถูกตรวจสอบ"</string>
    +     <string name="monitoring_title_device_owned" msgid="7121079311903859610">"การตรวจสอบอุปกรณ์"</string>
    +     <string name="monitoring_title_profile_owned" msgid="6790109874733501487">"การตรวจสอบโปรไฟล์"</string>
    +     <string name="monitoring_title" msgid="169206259253048106">"การตรวจสอบเครือข่าย"</string>
    +@@ -416,6 +417,7 @@
    +     <string name="legacy_vpn_name" msgid="6604123105765737830">"VPN"</string>
    +     <string name="monitoring_description_app" msgid="6259179342284742878">"คุณเชื่อมต่อกับ <xliff:g id="APPLICATION">%1$s</xliff:g> ซึ่งสามารถตรวจสอบกิจกรรมในเครือข่ายของคุณ รวมถึงอีเมล แอป และเว็บไซต์ได้"</string>
    +     <string name="monitoring_description_app_personal" msgid="484599052118316268">"คุณเชื่อมต่อกับ <xliff:g id="APPLICATION">%1$s</xliff:g> ซึ่งสามารถตรวจสอบกิจกรรมในเครือข่ายส่วนตัวของคุณ รวมถึงอีเมล แอป และเว็บไซต์ได้"</string>
    ++    <string name="branded_monitoring_description_app_personal" msgid="2669518213949202599">"คุณเชื่อมต่อกับ <xliff:g id="APPLICATION">%1$s</xliff:g> ซึ่งสามารถตรวจสอบกิจกรรมในเครือข่ายส่วนตัวของคุณ รวมถึงอีเมล แอป และเว็บไซต์ได้"</string>
    +     <string name="monitoring_description_app_work" msgid="1754325860918060897">"โปรไฟล์งานได้รับการจัดการโดย <xliff:g id="ORGANIZATION">%1$s</xliff:g> โดยมีการเชื่อมต่อกับ <xliff:g id="APPLICATION">%2$s</xliff:g> ซึ่งสามารถตรวจสอบกิจกรรมในเครือข่าย รวมถึงอีเมล แอป และเว็บไซต์ได้\n\nสำหรับข้อมูลเพิ่มเติม โปรดติดต่อผู้ดูแลระบบ"</string>
    +     <string name="monitoring_description_app_personal_work" msgid="4946600443852045903">"โปรไฟล์งานได้รับการจัดการโดย <xliff:g id="ORGANIZATION">%1$s</xliff:g> โดยมีการเชื่อมต่อกับ <xliff:g id="APPLICATION_WORK">%2$s</xliff:g> ซึ่งสามารถตรวจสอบกิจกรรมในเครือข่าย รวมถึงอีเมล แอป และเว็บไซต์ได้\n\nนอกจากนี้ คุณยังเชื่อมต่อกับ <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g> ซึ่งสามารถตรวจสอบกิจกรรมในเครือข่ายส่วนตัวได้"</string>
    +     <string name="monitoring_description_vpn_app_device_owned" msgid="4970443827043261703">"อุปกรณ์ได้รับการจัดการโดย <xliff:g id="ORGANIZATION">%1$s</xliff:g>\n\nผู้ดูและรบบของคุณสามารถตรวจสอบและจัดการการตั้งค่า การเข้าถึงของบริษัท แอป ข้อมูลที่เชื่อมโยงกับอุปกรณ์ และข้อมูลตำแหน่งของอุปกรณ์ได้\n\nคุณมีการเชื่อมต่อกับ <xliff:g id="APPLICATION">%2$s</xliff:g> ซึ่งสามารถตรวจสอบกิจกรรมในเครือข่ายรวมถึงอีเมล แอป และเว็บไซต์ได้\n\nสำหรับข้อมูลเพิ่มเติม โปรดติดต่อผู้ดูแลระบบ"</string>
    +@@ -492,8 +494,6 @@
    +     <string name="clock_seconds_desc" msgid="6282693067130470675">"แสดงวินาทีของนาฬิกาในแถบสถานะ อาจส่งผลต่ออายุแบตเตอรี"</string>
    +     <string name="qs_rearrange" msgid="8060918697551068765">"จัดเรียงการตั้งค่าด่วนใหม่"</string>
    +     <string name="show_brightness" msgid="6613930842805942519">"แสดงความสว่างในการตั้งค่าด่วน"</string>
    +-    <string name="overview_nav_bar_gesture" msgid="8579814204727917764">"เปิดใช้ท่าทางสัมผัสการเลื่อนขึ้นเพื่อแยกหน้าจอ"</string>
    +-    <string name="overview_nav_bar_gesture_desc" msgid="6329167382305102615">"เปิดใช้ท่าทางสัมผัสเพื่อเข้าสู่โหมดแยกหน้าจอโดยเลื่อนขึ้นจากปุ่มภาพรวม"</string>
    +     <string name="experimental" msgid="6198182315536726162">"ทดสอบ"</string>
    +     <string name="enable_bluetooth_title" msgid="5027037706500635269">"เปิดบลูทูธไหม"</string>
    +     <string name="enable_bluetooth_message" msgid="9106595990708985385">"หากต้องการเชื่อมต่อแป้นพิมพ์กับแท็บเล็ต คุณต้องเปิดบลูทูธก่อน"</string>
    +@@ -651,4 +651,5 @@
    +     <string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"เปิดการตั้งค่า <xliff:g id="ID_1">%s</xliff:g>"</string>
    +     <string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"แก้ไขลำดับการตั้งค่า"</string>
    +     <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"หน้า <xliff:g id="ID_1">%1$d</xliff:g> จาก <xliff:g id="ID_2">%2$d</xliff:g>"</string>
    ++    <string name="cant_silence_or_block" msgid="999689262131488625">"ไม่สามารถปิดเสียงหรือบล็อกการแจ้งเตือน"</string>
    + </resources>
    +diff --git a/packages/SystemUI/res/values-tl/strings.xml b/packages/SystemUI/res/values-tl/strings.xml
    +index ed6830e..89af189 100644
    +--- a/packages/SystemUI/res/values-tl/strings.xml
    ++++ b/packages/SystemUI/res/values-tl/strings.xml
    +@@ -238,7 +238,7 @@
    +     <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"Naka-pause ang 4G data"</string>
    +     <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"Naka-pause ang cellular data"</string>
    +     <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"Naka-pause ang data"</string>
    +-    <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"Dahil naabot ang iyong nakatakdang limitasyon sa data, na-pause ng device ang paggamit ng data para sa nalalabing bahagi ng cycle na ito.\n\nMaaaring makakuha ng mga singilin mula sa iyong carrier ang pagpapatuloy."</string>
    ++    <string name="data_usage_disabled_dialog" msgid="1841738975235283398">"Naabot na ang limitasyon sa data na itinakda mo. Hindi ka na gumagamit ng cellular data.\n\nKung magpapatuloy ka, maaari kang masingil para sa paggamit ng data."</string>
    +     <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"Ipagpatuloy"</string>
    +     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Walang koneksyon sa Internet"</string>
    +     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"nakakonekta ang Wi-Fi"</string>
    +@@ -404,6 +404,7 @@
    +     <string name="device_owned_footer" msgid="3802752663326030053">"Maaaring subaybayan ang device"</string>
    +     <string name="profile_owned_footer" msgid="8021888108553696069">"Maaaring subaybayan ang profile"</string>
    +     <string name="vpn_footer" msgid="2388611096129106812">"Maaaring sinusubaybayan ang network"</string>
    ++    <string name="branded_vpn_footer" msgid="2168111859226496230">"Maaaring sinusubaybayan ang network"</string>
    +     <string name="monitoring_title_device_owned" msgid="7121079311903859610">"Pagsubaybay sa device"</string>
    +     <string name="monitoring_title_profile_owned" msgid="6790109874733501487">"Pagsubaybay sa Profile"</string>
    +     <string name="monitoring_title" msgid="169206259253048106">"Pagsubaybay sa network"</string>
    +@@ -416,6 +417,7 @@
    +     <string name="legacy_vpn_name" msgid="6604123105765737830">"VPN"</string>
    +     <string name="monitoring_description_app" msgid="6259179342284742878">"Nakakonekta ka sa <xliff:g id="APPLICATION">%1$s</xliff:g>, na maaaring sumubaybay sa iyong aktibidad sa network kabilang ang mga email, app at website."</string>
    +     <string name="monitoring_description_app_personal" msgid="484599052118316268">"Nakakonekta ka sa <xliff:g id="APPLICATION">%1$s</xliff:g>, na maaaring sumubaybay sa iyong personal na aktibidad sa network, kabilang ang mga email, app at website."</string>
    ++    <string name="branded_monitoring_description_app_personal" msgid="2669518213949202599">"Nakakonekta ka sa <xliff:g id="APPLICATION">%1$s</xliff:g>, na maaaring sumubaybay sa aktibidad sa iyong personal na network, kabilang ang mga email, app at website."</string>
    +     <string name="monitoring_description_app_work" msgid="1754325860918060897">"Ang iyong profile sa trabaho ay pinapamahalaan ng <xliff:g id="ORGANIZATION">%1$s</xliff:g>. Nakakonekta ito sa <xliff:g id="APPLICATION">%2$s</xliff:g>, na maaaring sumubaybay sa iyong aktibidad sa network, kabilang ang mga email, app at website.\n\nPara sa higit pang impormasyon, makipag-ugnayan sa iyong administrator."</string>
    +     <string name="monitoring_description_app_personal_work" msgid="4946600443852045903">"Ang iyong profile sa trabaho ay pinapamahalaan ng <xliff:g id="ORGANIZATION">%1$s</xliff:g>. Nakakonekta ito sa <xliff:g id="APPLICATION_WORK">%2$s</xliff:g>, na maaaring sumubaybay sa iyong aktibidad sa network, kabilang ang mga email, app at website.\n\nNakakonekta ka rin sa <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g>, na maaaring sumubaybay sa iyong personal na aktibidad sa network."</string>
    +     <string name="monitoring_description_vpn_app_device_owned" msgid="4970443827043261703">"Pinapamahalaan ang iyong device ng <xliff:g id="ORGANIZATION">%1$s</xliff:g>.\n\nMaaaring subaybayan at pamahalaan ng iyong administrator ang mga setting, corporate na access, app, data na nauugnay sa iyong device at ang impormasyon ng lokasyon ng iyong device.\n\nNakakonekta ka sa <xliff:g id="APPLICATION">%2$s</xliff:g>, na maaaring subaybayan ang iyong aktibidad sa network, kabilang ang mga email, app at website.\n\nPara sa higit pang impormasyon, makipag-ugnayan sa iyong administrator."</string>
    +@@ -492,8 +494,6 @@
    +     <string name="clock_seconds_desc" msgid="6282693067130470675">"Ipakita ang mga segundo ng orasan sa status bar. Maaaring makaapekto sa tagal ng baterya."</string>
    +     <string name="qs_rearrange" msgid="8060918697551068765">"Ayusing Muli ang Mga Mabilisang Setting"</string>
    +     <string name="show_brightness" msgid="6613930842805942519">"Ipakita ang liwanag sa Mga Mabilisang Setting"</string>
    +-    <string name="overview_nav_bar_gesture" msgid="8579814204727917764">"I-enable ang pag-swipe pataas na galaw para sa split-screen"</string>
    +-    <string name="overview_nav_bar_gesture_desc" msgid="6329167382305102615">"I-enable ang gesture upang makapasok sa split-screen sa pamamagitan ng pagsa-swipe pataas mula sa button ng Pangkalahatang-ideya"</string>
    +     <string name="experimental" msgid="6198182315536726162">"Pang-eksperimento"</string>
    +     <string name="enable_bluetooth_title" msgid="5027037706500635269">"I-on ang Bluetooth?"</string>
    +     <string name="enable_bluetooth_message" msgid="9106595990708985385">"Upang ikonekta ang iyong keyboard sa iyong tablet, kailangan mo munang i-on ang Bluetooth."</string>
    +@@ -651,4 +651,5 @@
    +     <string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"Buksan ang mga setting ng <xliff:g id="ID_1">%s</xliff:g>."</string>
    +     <string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"I-edit ang pagkakasunud-sunod ng mga setting."</string>
    +     <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"Page <xliff:g id="ID_1">%1$d</xliff:g> ng <xliff:g id="ID_2">%2$d</xliff:g>"</string>
    ++    <string name="cant_silence_or_block" msgid="999689262131488625">"Hindi maaaring i-silent o i-block ang mga notification"</string>
    + </resources>
    +diff --git a/packages/SystemUI/res/values-tr/strings.xml b/packages/SystemUI/res/values-tr/strings.xml
    +index 8fae7975..c17e9fc 100644
    +--- a/packages/SystemUI/res/values-tr/strings.xml
    ++++ b/packages/SystemUI/res/values-tr/strings.xml
    +@@ -238,7 +238,7 @@
    +     <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"4G veri kullanımı duraklatıldı"</string>
    +     <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"Hücresel veri kullanımı duraklatıldı"</string>
    +     <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"Veri kullanımı duraklatıldı"</string>
    +-    <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"Ayarlanmış olan veri sınırınıza ulaşıldığından, bu dönemin kalan süresi için cihazda veri kullanımı duraklatıldı.\n\nVeri kullanımını devam ettirmek, operatörünüzün sizden ödeme almasına neden olabilir."</string>
    ++    <string name="data_usage_disabled_dialog" msgid="1841738975235283398">"Ayarladığınız veri limitine ulaşıldı. Artık hücresel verilerinizi kullanmıyorsunuz.\n\nHücresel veri kullanımını devam ettirirseniz veri kullanım ücretleri ödemeniz gerekebilir."</string>
    +     <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"Devam ettir"</string>
    +     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"İnternet bağlantısı yok"</string>
    +     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Kablosuz bağlandı"</string>
    +@@ -404,6 +404,7 @@
    +     <string name="device_owned_footer" msgid="3802752663326030053">"Cihaz izlenebilir"</string>
    +     <string name="profile_owned_footer" msgid="8021888108553696069">"Profil izlenebilir"</string>
    +     <string name="vpn_footer" msgid="2388611096129106812">"Ağ etkinliği izlenebilir"</string>
    ++    <string name="branded_vpn_footer" msgid="2168111859226496230">"Ağ etkinliği izlenebilir"</string>
    +     <string name="monitoring_title_device_owned" msgid="7121079311903859610">"Cihaz izleme"</string>
    +     <string name="monitoring_title_profile_owned" msgid="6790109874733501487">"Profil izleme"</string>
    +     <string name="monitoring_title" msgid="169206259253048106">"Ağ izleme"</string>
    +@@ -416,6 +417,7 @@
    +     <string name="legacy_vpn_name" msgid="6604123105765737830">"VPN"</string>
    +     <string name="monitoring_description_app" msgid="6259179342284742878">"E-postalarınız, uygulamalarınız ve web siteleriniz dahil olmak üzere ağ etkinliğinizi izleyebilen <xliff:g id="APPLICATION">%1$s</xliff:g> uygulamasına bağlısınız."</string>
    +     <string name="monitoring_description_app_personal" msgid="484599052118316268">"E-postalarınız, uygulamalarınız ve web siteleriniz dahil olmak üzere kişisel ağ etkinliğinizi izleyebilen <xliff:g id="APPLICATION">%1$s</xliff:g> uygulamasına bağlısınız."</string>
    ++    <string name="branded_monitoring_description_app_personal" msgid="2669518213949202599">"E-postalarınız, uygulamalarınız ve web siteleriniz dahil olmak üzere kişisel ağ etkinliğinizi izleyebilen <xliff:g id="APPLICATION">%1$s</xliff:g> uygulamasına bağlısınız."</string>
    +     <string name="monitoring_description_app_work" msgid="1754325860918060897">"İş profiliniz <xliff:g id="ORGANIZATION">%1$s</xliff:g> tarafından yönetiliyor. E-postalarınız, uygulamalarınız ve web siteleriniz dahil olmak üzere ağ etkinliğinizi izleyebilen <xliff:g id="APPLICATION">%2$s</xliff:g> uygulamasına bağlı.\n\nDaha fazla bilgi için yöneticinizle iletişim kurun."</string>
    +     <string name="monitoring_description_app_personal_work" msgid="4946600443852045903">"İş profiliniz <xliff:g id="ORGANIZATION">%1$s</xliff:g> tarafından yönetiliyor. E-postalarınız, uygulamalarınız ve web siteleriniz dahil olmak üzere ağ etkinliğinizi izleyebilen <xliff:g id="APPLICATION_WORK">%2$s</xliff:g> uygulamasına bağlı.\n\n Ayrıca kişisel ağ etkinliğinizi izleyebilen <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g> uygulamasına bağlısınız."</string>
    +     <string name="monitoring_description_vpn_app_device_owned" msgid="4970443827043261703">"Cihazınız <xliff:g id="ORGANIZATION">%1$s</xliff:g> tarafından yönetiliyor.\n\nYöneticiniz; ayarları, şirket erişimini, uygulamaları, cihazınızla ilişkilendirilmiş verileri ve cihazınızın konum bilgilerini izleyebilir ve yönetebilir.\n\nE-postalarınız, uygulamalarınız ve web siteleriniz dahil olmak üzere ağ etkinliğinizi izleyebilen <xliff:g id="APPLICATION">%2$s</xliff:g> uygulamasına bağlısınız.\n\nDaha fazla bilgi edinmek için yöneticinizle iletişim kurun."</string>
    +@@ -492,8 +494,6 @@
    +     <string name="clock_seconds_desc" msgid="6282693067130470675">"Durum çubuğunda saatin saniyelerini gösterir. Pil ömrünü etkileyebilir."</string>
    +     <string name="qs_rearrange" msgid="8060918697551068765">"Hızlı Ayarlar\'ı Yeniden Düzenle"</string>
    +     <string name="show_brightness" msgid="6613930842805942519">"Hızlı Ayarlar\'da parlaklığı göster"</string>
    +-    <string name="overview_nav_bar_gesture" msgid="8579814204727917764">"Hızlıca yukarı kaydırma hareketiyle ekran bölm. etkinleştir"</string>
    +-    <string name="overview_nav_bar_gesture_desc" msgid="6329167382305102615">"Genel bakış düğmesinden yukarı hızlıca kaydırarak bölünmüş ekrana geçme hareketini etkinleştir"</string>
    +     <string name="experimental" msgid="6198182315536726162">"Deneysel"</string>
    +     <string name="enable_bluetooth_title" msgid="5027037706500635269">"Bluetooth açılsın mı?"</string>
    +     <string name="enable_bluetooth_message" msgid="9106595990708985385">"Klavyenizi tabletinize bağlamak için önce Bluetooth\'u açmanız gerekir."</string>
    +@@ -651,4 +651,5 @@
    +     <string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"<xliff:g id="ID_1">%s</xliff:g> ayarlarını aç."</string>
    +     <string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"Ayarların sırasını düzenle."</string>
    +     <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"Sayfa <xliff:g id="ID_1">%1$d</xliff:g> / <xliff:g id="ID_2">%2$d</xliff:g>"</string>
    ++    <string name="cant_silence_or_block" msgid="999689262131488625">"Bildirimler engellenemez veya sesi kapatılamaz"</string>
    + </resources>
    +diff --git a/packages/SystemUI/res/values-uk/strings.xml b/packages/SystemUI/res/values-uk/strings.xml
    +index 7eaf0db..92f1372 100644
    +--- a/packages/SystemUI/res/values-uk/strings.xml
    ++++ b/packages/SystemUI/res/values-uk/strings.xml
    +@@ -242,7 +242,7 @@
    +     <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"Передавання даних 4G призупинено"</string>
    +     <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"Передавання мобільних даних призупинено"</string>
    +     <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"Передавання даних призупинено"</string>
    +-    <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"Пристрій призупинив передавання даних до кінця цього циклу, оскільки ваш ліміт перевищено.\n\nЯкщо ви відновите передавання даних, оператор може стягувати додаткову плату."</string>
    ++    <string name="data_usage_disabled_dialog" msgid="1841738975235283398">"Ви досягнули вказаного ліміту даних. Мобільний трафік вимкнено.\n\nЯкщо продовжите, може стягуватися плата за використання трафіку."</string>
    +     <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"Відновити"</string>
    +     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Немає з’єднання"</string>
    +     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi під’єднано"</string>
    +@@ -410,6 +410,7 @@
    +     <string name="device_owned_footer" msgid="3802752663326030053">"Дії на пристрої можуть відстежуватися"</string>
    +     <string name="profile_owned_footer" msgid="8021888108553696069">"Профіль може відстежуватись"</string>
    +     <string name="vpn_footer" msgid="2388611096129106812">"Дії в мережі можуть відстежуватися"</string>
    ++    <string name="branded_vpn_footer" msgid="2168111859226496230">"Мережа може відстежуватися"</string>
    +     <string name="monitoring_title_device_owned" msgid="7121079311903859610">"Відстеження дій на пристрої"</string>
    +     <string name="monitoring_title_profile_owned" msgid="6790109874733501487">"Відстеження профілю"</string>
    +     <string name="monitoring_title" msgid="169206259253048106">"Відстеження дій у мережі"</string>
    +@@ -422,6 +423,7 @@
    +     <string name="legacy_vpn_name" msgid="6604123105765737830">"VPN"</string>
    +     <string name="monitoring_description_app" msgid="6259179342284742878">"Ваш профіль під’єднано до додатка <xliff:g id="APPLICATION">%1$s</xliff:g>, який може відстежувати вашу активність у мережі, зокрема в електронній пошті, додатках і на веб-сайтах."</string>
    +     <string name="monitoring_description_app_personal" msgid="484599052118316268">"Ваш профіль під’єднано до додатка <xliff:g id="APPLICATION">%1$s</xliff:g>, який може відстежувати вашу особисту активність у мережі, зокрема в електронній пошті, додатках і на веб-сайтах."</string>
    ++    <string name="branded_monitoring_description_app_personal" msgid="2669518213949202599">"Ваш профіль під’єднано до додатка <xliff:g id="APPLICATION">%1$s</xliff:g>, який може відстежувати вашу особисту активність у мережі, зокрема доступ до електронної пошти, додатків і веб-сайтів."</string>
    +     <string name="monitoring_description_app_work" msgid="1754325860918060897">"Вашим робочим профілем керує <xliff:g id="ORGANIZATION">%1$s</xliff:g>. Профіль під’єднано до додатка <xliff:g id="APPLICATION">%2$s</xliff:g>, який може відстежувати вашу робочу активність у мережі, зокрема в електронній пошті, додатках і на веб-сайтах.\n\nЗв’яжіться з адміністратором, щоб дізнатися більше."</string>
    +     <string name="monitoring_description_app_personal_work" msgid="4946600443852045903">"Вашим робочим профілем керує <xliff:g id="ORGANIZATION">%1$s</xliff:g>. Профіль під’єднано до додатка <xliff:g id="APPLICATION_WORK">%2$s</xliff:g>, який може відстежувати вашу робочу активність у мережі, зокрема в електронній пошті, додатках і на веб-сайтах.\n\nВаш профіль також під’єднано до додатка <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g>, який може відстежувати вашу особисту активність у мережі."</string>
    +     <string name="monitoring_description_vpn_app_device_owned" msgid="4970443827043261703">"Вашим пристроєм керує організація <xliff:g id="ORGANIZATION">%1$s</xliff:g>.\n\nАдміністратор може відстежувати та контролювати налаштування, корпоративний доступ, додатки, геодані й інші дані, пов’язані з вашим пристроєм.\n\nВаш профіль під’єднано до додатка <xliff:g id="APPLICATION">%2$s</xliff:g>, який може відстежувати вашу активність у мережі, зокрема в електронній пошті, додатках і на веб-сайтах.\n\nЗв’яжіться з адміністратором, щоб дізнатися більше."</string>
    +@@ -498,8 +500,6 @@
    +     <string name="clock_seconds_desc" msgid="6282693067130470675">"Показувати секунди на годиннику в рядку стану. Акумулятор може розряджатися швидше."</string>
    +     <string name="qs_rearrange" msgid="8060918697551068765">"Упорядкувати швидкі налаштування"</string>
    +     <string name="show_brightness" msgid="6613930842805942519">"Показувати панель яскравості у швидких налаштуваннях"</string>
    +-    <string name="overview_nav_bar_gesture" msgid="8579814204727917764">"Увімкнути розділення екрана рухом пальця вгору"</string>
    +-    <string name="overview_nav_bar_gesture_desc" msgid="6329167382305102615">"Увімкнути жест розділення екрана рухом пальця вгору від кнопки \"Огляд\""</string>
    +     <string name="experimental" msgid="6198182315536726162">"Експериментальні налаштування"</string>
    +     <string name="enable_bluetooth_title" msgid="5027037706500635269">"Увімкнути Bluetooth?"</string>
    +     <string name="enable_bluetooth_message" msgid="9106595990708985385">"Щоб під’єднати клавіатуру до планшета, спершу потрібно ввімкнути Bluetooth."</string>
    +@@ -657,4 +657,5 @@
    +     <string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"Відкрити налаштування <xliff:g id="ID_1">%s</xliff:g>."</string>
    +     <string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"Змінити порядок налаштувань."</string>
    +     <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"Сторінка <xliff:g id="ID_1">%1$d</xliff:g> з <xliff:g id="ID_2">%2$d</xliff:g>"</string>
    ++    <string name="cant_silence_or_block" msgid="999689262131488625">"Сповіщення не можна вимкнути або заблокувати"</string>
    + </resources>
    +diff --git a/packages/SystemUI/res/values-ur-rPK/strings.xml b/packages/SystemUI/res/values-ur-rPK/strings.xml
    +index 5c0ed18..b7b87eb 100644
    +--- a/packages/SystemUI/res/values-ur-rPK/strings.xml
    ++++ b/packages/SystemUI/res/values-ur-rPK/strings.xml
    +@@ -238,7 +238,7 @@
    +     <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"‏4G ڈیٹا موقوف کر دیا گیا"</string>
    +     <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"سیلولر ڈیٹا موقوف کر دیا گیا"</string>
    +     <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"ڈیٹا موقوف کر دیا گیا"</string>
    +-    <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"چونکہ آپ کی سیٹ کردہ ڈیٹا کی حد تک پہنچ گیا، لہذا آلہ نے اس سائیکل کے بقیہ حصے کیلئے ڈیٹا کے استعمال کو موقوف کر دیا ہے۔\n\nدوبارہ شروع کرنے سے آپ کے کیریئر سے چارجز لگ سکتے ہیں۔"</string>
    ++    <string name="data_usage_disabled_dialog" msgid="1841738975235283398">"آپ کی سیٹ کردہ ڈیٹا کی حد پوری ہو گئی ہے۔ آپ اب سیلولر ڈیٹا استعمال نہیں کر رہے۔\n\nاگر آپ دوبارہ شروع کرتے ہیں تو ڈیٹا کے استعمال کے چارجز لاگو ہو سکتے ہیں۔"</string>
    +     <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"دوبارہ شروع کریں"</string>
    +     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"کوئی انٹرنیٹ کنکشن نہیں"</string>
    +     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"‏Wi-Fi مربوط ہے"</string>
    +@@ -404,6 +404,7 @@
    +     <string name="device_owned_footer" msgid="3802752663326030053">"آلہ کو مانیٹر کیا جا سکتا ہے"</string>
    +     <string name="profile_owned_footer" msgid="8021888108553696069">"پروفائل کو مانیٹر کیا جا سکتا ہے"</string>
    +     <string name="vpn_footer" msgid="2388611096129106812">"نیٹ ورک کو مانیٹر کیا جا سکتا ہے"</string>
    ++    <string name="branded_vpn_footer" msgid="2168111859226496230">"نیٹ ورک کو شاید مانیٹر کیا جائے"</string>
    +     <string name="monitoring_title_device_owned" msgid="7121079311903859610">"آلہ کو مانیٹر کرنا"</string>
    +     <string name="monitoring_title_profile_owned" msgid="6790109874733501487">"پروفائل کو مانیٹر کرنا"</string>
    +     <string name="monitoring_title" msgid="169206259253048106">"نیٹ ورک کو مانیٹر کرنا"</string>
    +@@ -416,6 +417,7 @@
    +     <string name="legacy_vpn_name" msgid="6604123105765737830">"VPN"</string>
    +     <string name="monitoring_description_app" msgid="6259179342284742878">"آپ <xliff:g id="APPLICATION">%1$s</xliff:g> سے منسلک ہیں، جو ای میلز، ایپس اور ویب سائٹس سمیت آپ کے نیٹ ورک کی سرگرمی مانیٹر کر سکتی ہے۔"</string>
    +     <string name="monitoring_description_app_personal" msgid="484599052118316268">"آپ <xliff:g id="APPLICATION">%1$s</xliff:g> سے منسلک ہیں، جو آپ کے نجی نیٹ ورک کی سرگرمی سمیت ای میلز، ایپس اور ویب سائٹس مانیٹر کر سکتی ہے۔"</string>
    ++    <string name="branded_monitoring_description_app_personal" msgid="2669518213949202599">"آپ <xliff:g id="APPLICATION">%1$s</xliff:g> سے منسلک ہیں، جو ای میلز، ایپس اور ویب سائٹس سمیت آپ کے نجی نیٹ ورک کی سرگرمی مانیٹر کر سکتی ہے۔"</string>
    +     <string name="monitoring_description_app_work" msgid="1754325860918060897">"آپ کا دفتری پروفائل <xliff:g id="ORGANIZATION">%1$s</xliff:g> کے زیر انتظام ہے۔ یہ <xliff:g id="APPLICATION">%2$s</xliff:g> سے منسلک ہے، جو ای میلز، ایپس اور ویب سائٹس سمیت آپ کے نیٹ ورک کی سرگرمی مانیٹر کر سکتی ہے۔\n\nمزید معلومات کیلئے اپنے منتظم سے رابطہ کریں۔"</string>
    +     <string name="monitoring_description_app_personal_work" msgid="4946600443852045903">"آپ کا دفتری پروفائل <xliff:g id="ORGANIZATION">%1$s</xliff:g> کے زیر انتظام ہے۔ یہ <xliff:g id="APPLICATION_WORK">%2$s</xliff:g> سے منسلک ہے، جو ای میلز، ایپس اور ویب سائٹس سمیت آپ کے نیٹ ورک کی سرگرمی مانیٹر کر سکتی ہے۔\n\nآپ <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g> سے بھی منسلک ہیں، جو آپ کے نجی نیٹ ورک کی سرگرمی کو مانیٹر کر سکتی ہے۔"</string>
    +     <string name="monitoring_description_vpn_app_device_owned" msgid="4970443827043261703">"آپ کا آلہ <xliff:g id="ORGANIZATION">%1$s</xliff:g> کے زیر انتظام ہے۔\n\nآپ کا منتظم ترتیبات، کارپوریٹ رسائی، ایپس، آپ کے آلہ سے وابستہ ڈیٹا اور آپ کے آلہ کے مقام کی معلومات کو مانیٹر اور ان کا نظم کر سکتا ہے۔\n\nآپ <xliff:g id="APPLICATION">%2$s</xliff:g> سے منسلک ہیں، جو ای میلز، ایپس اور ویب سائٹس سمیت آپ کے نیٹ ورک کی سرگرمی مانیٹر کر سکتی ہے۔\n\nمزید معلومات کیلئے اپنے منتظم سے رابطہ کریں۔"</string>
    +@@ -492,8 +494,6 @@
    +     <string name="clock_seconds_desc" msgid="6282693067130470675">"گھڑی کے سیکنڈز اسٹیٹس بار میں دکھائیں۔ اس کا بیٹری کی زندگی پر اثر پڑ سکتا ہے۔"</string>
    +     <string name="qs_rearrange" msgid="8060918697551068765">"فوری ترتیبات کو دوبارہ ترتیب دیں"</string>
    +     <string name="show_brightness" msgid="6613930842805942519">"فوری ترتیبات میں چمکیلا پن دکھائیں"</string>
    +-    <string name="overview_nav_bar_gesture" msgid="8579814204727917764">"سپلٹ اسکرین کیلئے سوائپ اپ اشارہ فعال کریں"</string>
    +-    <string name="overview_nav_bar_gesture_desc" msgid="6329167382305102615">"مجموعی جائزہ بٹن سے سوائپ اپ کرکے سپلٹ اسکرین میں داخل ہونے کیلئے اشارہ فعال کریں"</string>
    +     <string name="experimental" msgid="6198182315536726162">"تجرباتی"</string>
    +     <string name="enable_bluetooth_title" msgid="5027037706500635269">"بلوٹوتھ آن کریں؟"</string>
    +     <string name="enable_bluetooth_message" msgid="9106595990708985385">"اپنے کی بورڈ کو اپنے ٹیبلٹ کے ساتھ منسلک کرنے کیلئے پہلے آپ کو اپنا بلو ٹوتھ آن کرنا ہو گا۔"</string>
    +@@ -651,4 +651,5 @@
    +     <string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"<xliff:g id="ID_1">%s</xliff:g> ترتیبات کھولیں۔"</string>
    +     <string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"ترتیبات کی ترتیب میں ترمیم کریں۔"</string>
    +     <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"صفحہ <xliff:g id="ID_1">%1$d</xliff:g> از <xliff:g id="ID_2">%2$d</xliff:g>"</string>
    ++    <string name="cant_silence_or_block" msgid="999689262131488625">"اطلاعات کو خاموش یا مسدود نہیں کیا جا سکتا"</string>
    + </resources>
    +diff --git a/packages/SystemUI/res/values-uz-rUZ/strings.xml b/packages/SystemUI/res/values-uz-rUZ/strings.xml
    +index ac6194f..61195c5 100644
    +--- a/packages/SystemUI/res/values-uz-rUZ/strings.xml
    ++++ b/packages/SystemUI/res/values-uz-rUZ/strings.xml
    +@@ -240,7 +240,7 @@
    +     <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"4G internet to‘xtatib qo‘yildi"</string>
    +     <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"Mobil internetdan foydalanish to‘xtatib qo‘yildi"</string>
    +     <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"Internetdan foydalanish to‘xtatib qo‘yildi"</string>
    +-    <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"Siz o‘rnatgan mobil internet chekloviga yetgani bois joriy hisob-kitob davrining qolgan muddati uchun mobil internetdan foydalanish vaqtinchalik to‘xtatib qo‘yildi.\n\nAgar internetdan foydalanishni davom ettirsangiz, buning uchun uyali aloqa operatoringiz ortiqcha haq talab qilishi mumkin."</string>
    ++    <string name="data_usage_disabled_dialog" msgid="1841738975235283398">"O‘rnatilgan trafik sarflab bo‘lindi. Endi mobil internetdan foydalana olmaysiz.\n\nDavom ettiradigan bo‘lsangiz, trafik uchun to‘lov olinishi mumkin."</string>
    +     <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"Davom etish"</string>
    +     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Internetga ulanmagan"</string>
    +     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi ulandi"</string>
    +@@ -406,6 +406,7 @@
    +     <string name="device_owned_footer" msgid="3802752663326030053">"Qurilma kuzatilishi mumkin"</string>
    +     <string name="profile_owned_footer" msgid="8021888108553696069">"Profil kuzatilishi mumkin"</string>
    +     <string name="vpn_footer" msgid="2388611096129106812">"Tarmoqni kuzatish mumkin"</string>
    ++    <string name="branded_vpn_footer" msgid="2168111859226496230">"Tarmoq kuzatilishi mumkin"</string>
    +     <string name="monitoring_title_device_owned" msgid="7121079311903859610">"Qurilmalarni kuzatish"</string>
    +     <string name="monitoring_title_profile_owned" msgid="6790109874733501487">"Profilni kuzatish"</string>
    +     <string name="monitoring_title" msgid="169206259253048106">"Tarmoqlarni kuzatish"</string>
    +@@ -418,6 +419,7 @@
    +     <string name="legacy_vpn_name" msgid="6604123105765737830">"VPN"</string>
    +     <string name="monitoring_description_app" msgid="6259179342284742878">"<xliff:g id="APPLICATION">%1$s</xliff:g> ilovasi ishga tushirilgan. U internetdagi harakatlaringiz, jumladan, e-pochta, ilova va veb-saytlardagi xatti-harakatlaringizni kuzatishi mumkin."</string>
    +     <string name="monitoring_description_app_personal" msgid="484599052118316268">"<xliff:g id="APPLICATION">%1$s</xliff:g> ilovasi ishga tushirilgan. U internetdagi harakatlaringiz, jumladan, e-pochta, ilova va veb-saytlardagi xatti-harakatlaringizni kuzatishi mumkin."</string>
    ++    <string name="branded_monitoring_description_app_personal" msgid="2669518213949202599">"<xliff:g id="APPLICATION">%1$s</xliff:g> ilovasi ishga tushirilgan. U internetdagi harakatlaringiz, jumladan, e-pochta, ilova va veb-saytlardagi xatti-harakatlaringizni kuzatishi mumkin."</string>
    +     <string name="monitoring_description_app_work" msgid="1754325860918060897">"Sizning ishchi profilingiz <xliff:g id="ORGANIZATION">%1$s</xliff:g> tomonidan boshqariladi. <xliff:g id="APPLICATION">%2$s</xliff:g> ilovasi ish tarmog‘idagi harakatlaringizni, jumladan, e-pochta, ilova va veb-saytlardagi xatti-harakatlaringizni kuzatishi mumkin.\n\nBatafsil ma’lumot olish uchun administrator bilan bog‘laning."</string>
    +     <string name="monitoring_description_app_personal_work" msgid="4946600443852045903">"Sizning ishchi profilingiz <xliff:g id="ORGANIZATION">%1$s</xliff:g> tomonidan boshqariladi. <xliff:g id="APPLICATION_WORK">%2$s</xliff:g> ilovasi ish tarmog‘idagi harakatlaringizni, jumladan, e-pochta, ilova va veb-saytlardagi xatti-harakatlaringizni kuzatishi mumkin.\n\nShuningdek, <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g> ilovasi ham shaxsiy tarmoqdagi harakatlaringizni kuzatishi mumkin."</string>
    +     <string name="monitoring_description_vpn_app_device_owned" msgid="4970443827043261703">"Qurilmangiz <xliff:g id="ORGANIZATION">%1$s</xliff:g> tomonidan boshqariladi.\n\nAdministrator sozlamalar, korporativ kirish huquqi, ilovalar, qurilmangizdagi ma’lumotlar, jumladan, joylashuv ma’lumotlarini boshqarishi mumkin.\n\nShuningdek, siz <xliff:g id="APPLICATION">%2$s</xliff:g> ilovasiga ham ulangansiz. Ushbu ilova internetdagi harakatlaringizni, jumladan, e-pochta, ilovalar va veb-saytlar bilan ishlashingizni kuzata oladi.\n\nBatafsil ma’lumot olish uchun administrator bilan bog‘laning."</string>
    +@@ -494,8 +496,6 @@
    +     <string name="clock_seconds_desc" msgid="6282693067130470675">"Holat panelida soat soniyalari ko‘rsatilsin. Bu batareya resursiga ta’sir qilishi mumkin."</string>
    +     <string name="qs_rearrange" msgid="8060918697551068765">"Tezkor sozlamalarni qayta tartiblash"</string>
    +     <string name="show_brightness" msgid="6613930842805942519">"Tezkor sozlamalarda yorqinlikni ko‘rsatish"</string>
    +-    <string name="overview_nav_bar_gesture" msgid="8579814204727917764">"Tepaga surish orqali ekranni ikkiga bo‘lish"</string>
    +-    <string name="overview_nav_bar_gesture_desc" msgid="6329167382305102615">"Umumiy ma’lumot tugmasini tepaga surish orqali ekranni bo‘lish ishorasini yoqish"</string>
    +     <string name="experimental" msgid="6198182315536726162">"Tajribaviy"</string>
    +     <string name="enable_bluetooth_title" msgid="5027037706500635269">"Bluetooth yoqilsinmi?"</string>
    +     <string name="enable_bluetooth_message" msgid="9106595990708985385">"Klaviaturani planshetingizga ulash uchun Bluetooth xizmatini yoqishingiz kerak."</string>
    +@@ -653,4 +653,5 @@
    +     <string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"<xliff:g id="ID_1">%s</xliff:g> sozlamalarini ochish."</string>
    +     <string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"Sozlamalar tartibini o‘zgartirish."</string>
    +     <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"<xliff:g id="ID_1">%1$d</xliff:g>-sahifa, jami: <xliff:g id="ID_2">%2$d</xliff:g> ta sahifa"</string>
    ++    <string name="cant_silence_or_block" msgid="999689262131488625">"Bildirishnomalarni bloklab yoki ovozsiz ko‘rinadigan qilib bo‘lmaydi"</string>
    + </resources>
    +diff --git a/packages/SystemUI/res/values-vi/strings.xml b/packages/SystemUI/res/values-vi/strings.xml
    +index 930eebe..6aaab66 100644
    +--- a/packages/SystemUI/res/values-vi/strings.xml
    ++++ b/packages/SystemUI/res/values-vi/strings.xml
    +@@ -238,7 +238,7 @@
    +     <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"Đã tạm dừng dữ liệu 4G"</string>
    +     <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"Đã tạm dừng dữ liệu di động"</string>
    +     <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"Đã tạm dừng dữ liệu"</string>
    +-    <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"Vì bạn đã đạt tới giới hạn dữ liệu thiết lập nên thiết bị đã tạm dừng sử dụng dữ liệu cho phần còn lại của chu kỳ này.\n\nTiếp tục có thể dẫn tới nhà cung cấp dịch vụ của bạn sẽ tính phí."</string>
    ++    <string name="data_usage_disabled_dialog" msgid="1841738975235283398">"Đã đạt đến giới hạn dữ liệu mà bạn đặt. Bạn hiện không còn sử dụng dữ liệu di động.\n\nNếu tiếp tục, bạn có thể bị tính phí khi sử dụng dữ liệu."</string>
    +     <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"Tiếp tục"</string>
    +     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Ko có k.nối Internet"</string>
    +     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Đã kết nối Wi-Fi"</string>
    +@@ -404,6 +404,7 @@
    +     <string name="device_owned_footer" msgid="3802752663326030053">"Thiết bị có thể được giám sát"</string>
    +     <string name="profile_owned_footer" msgid="8021888108553696069">"Hồ sơ có thể được giám sát"</string>
    +     <string name="vpn_footer" msgid="2388611096129106812">"Mạng có thể được giám sát"</string>
    ++    <string name="branded_vpn_footer" msgid="2168111859226496230">"Mạng có thể được giám sát"</string>
    +     <string name="monitoring_title_device_owned" msgid="7121079311903859610">"Giám sát thiết bị"</string>
    +     <string name="monitoring_title_profile_owned" msgid="6790109874733501487">"Giám sát hồ sơ"</string>
    +     <string name="monitoring_title" msgid="169206259253048106">"Giám sát mạng"</string>
    +@@ -416,6 +417,7 @@
    +     <string name="legacy_vpn_name" msgid="6604123105765737830">"VPN"</string>
    +     <string name="monitoring_description_app" msgid="6259179342284742878">"Bạn đang kết nối với <xliff:g id="APPLICATION">%1$s</xliff:g>. Ứng dụng này có thể giám sát hoạt động mạng của bạn bao gồm email, ứng dụng và trang web."</string>
    +     <string name="monitoring_description_app_personal" msgid="484599052118316268">"Bạn đang kết nối với <xliff:g id="APPLICATION">%1$s</xliff:g>. Ứng dụng này có thể giám sát hoạt động mạng cá nhân của bạn bao gồm email, ứng dụng và trang web."</string>
    ++    <string name="branded_monitoring_description_app_personal" msgid="2669518213949202599">"Bạn đang kết nối với <xliff:g id="APPLICATION">%1$s</xliff:g>. Ứng dụng này có thể giám sát hoạt động mạng cá nhân của bạn bao gồm email, ứng dụng và trang web."</string>
    +     <string name="monitoring_description_app_work" msgid="1754325860918060897">"Hồ sơ công việc của bạn được quản lý bởi <xliff:g id="ORGANIZATION">%1$s</xliff:g>. Hồ sơ được kết nối với <xliff:g id="APPLICATION">%2$s</xliff:g>, ứng dụng này có thể giám sát hoạt động mạng cơ quan của bạn, bao gồm email, ứng dụng và trang web.\n\nĐể biết thêm thông tin, hãy liên hệ với quản trị viên của bạn."</string>
    +     <string name="monitoring_description_app_personal_work" msgid="4946600443852045903">"Hồ sơ công việc của bạn được quản lý bởi <xliff:g id="ORGANIZATION">%1$s</xliff:g>. Hồ sơ được kết nối với <xliff:g id="APPLICATION_WORK">%2$s</xliff:g>, ứng dụng này có thể giám sát hoạt động mạng cơ quan của bạn, bao gồm email, ứng dụng và trang web.\n\nBạn cũng được kết nối với <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g>, có thể giám sát hoạt động mạng cá nhân của bạn."</string>
    +     <string name="monitoring_description_vpn_app_device_owned" msgid="4970443827043261703">"Thiết bị của bạn được quản lý bởi <xliff:g id="ORGANIZATION">%1$s</xliff:g>.\n\nQuản trị viên có thể giám sát và quản lý cài đặt, quyền truy cập của công ty, ứng dụng, dữ liệu được liên kết với thiết bị của bạn và thông tin về vị trí của thiết bị.\n\nBạn được kết nối với <xliff:g id="APPLICATION">%2$s</xliff:g>. Ứng dụng này có thể giám sát hoạt động mạng của bạn, bao gồm email, ứng dụng và trang web.\n\nĐể biết thêm thông tin, hãy liên hệ với quản trị viên của bạn."</string>
    +@@ -494,8 +496,6 @@
    +     <string name="clock_seconds_desc" msgid="6282693067130470675">"Hiển thị giây đồng hồ trong thanh trạng thái. Có thể ảnh hưởng đến thời lượng pin."</string>
    +     <string name="qs_rearrange" msgid="8060918697551068765">"Sắp xếp lại Cài đặt nhanh"</string>
    +     <string name="show_brightness" msgid="6613930842805942519">"Hiển thị độ sáng trong Cài đặt nhanh"</string>
    +-    <string name="overview_nav_bar_gesture" msgid="8579814204727917764">"Bật cử chỉ vuốt lên ở chế độ chia đôi màn hình"</string>
    +-    <string name="overview_nav_bar_gesture_desc" msgid="6329167382305102615">"Cho phép cử chỉ truy cập chế độ chia đôi màn hình bằng cách vuốt lên từ nút Tổng quan"</string>
    +     <string name="experimental" msgid="6198182315536726162">"Thử nghiệm"</string>
    +     <string name="enable_bluetooth_title" msgid="5027037706500635269">"Bật Bluetooth?"</string>
    +     <string name="enable_bluetooth_message" msgid="9106595990708985385">"Để kết nối bàn phím với máy tính bảng, trước tiên, bạn phải bật Bluetooth."</string>
    +@@ -653,4 +653,5 @@
    +     <string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"Mở cài đặt <xliff:g id="ID_1">%s</xliff:g>."</string>
    +     <string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"Chỉnh sửa thứ tự cài đặt."</string>
    +     <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"Trang <xliff:g id="ID_1">%1$d</xliff:g> / <xliff:g id="ID_2">%2$d</xliff:g>"</string>
    ++    <string name="cant_silence_or_block" msgid="999689262131488625">"Không thể chặn hoặc tắt tiếng thông báo"</string>
    + </resources>
    +diff --git a/packages/SystemUI/res/values-zh-rCN/strings.xml b/packages/SystemUI/res/values-zh-rCN/strings.xml
    +index 2548c4b..f10d538 100644
    +--- a/packages/SystemUI/res/values-zh-rCN/strings.xml
    ++++ b/packages/SystemUI/res/values-zh-rCN/strings.xml
    +@@ -238,7 +238,7 @@
    +     <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"4G 数据网络已暂停使用"</string>
    +     <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"移动数据网络已暂停使用"</string>
    +     <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"数据网络已暂停使用"</string>
    +-    <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"由于使用的数据流量已达到您所设置的上限,因此您的设备已暂停在此周期的剩余时间内使用数据流量。\n\n如果恢复数据流量使用,您的运营商可能会向您收取相应费用。"</string>
    ++    <string name="data_usage_disabled_dialog" msgid="1841738975235283398">"您的数据用量已达到设置的上限。您无法再使用移动数据网络。\n\n如果您继续操作,可能需要支付相应的数据流量费用。"</string>
    +     <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"恢复"</string>
    +     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"未连接互联网"</string>
    +     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"已连接到WLAN网络"</string>
    +@@ -404,6 +404,7 @@
    +     <string name="device_owned_footer" msgid="3802752663326030053">"设备可能会受到监控"</string>
    +     <string name="profile_owned_footer" msgid="8021888108553696069">"资料可能会受到监控"</string>
    +     <string name="vpn_footer" msgid="2388611096129106812">"网络可能会受到监控"</string>
    ++    <string name="branded_vpn_footer" msgid="2168111859226496230">"网络可能会受到监控"</string>
    +     <string name="monitoring_title_device_owned" msgid="7121079311903859610">"设备监测"</string>
    +     <string name="monitoring_title_profile_owned" msgid="6790109874733501487">"资料监控"</string>
    +     <string name="monitoring_title" msgid="169206259253048106">"网络监控"</string>
    +@@ -416,6 +417,7 @@
    +     <string name="legacy_vpn_name" msgid="6604123105765737830">"VPN"</string>
    +     <string name="monitoring_description_app" msgid="6259179342284742878">"您已连接到<xliff:g id="APPLICATION">%1$s</xliff:g>,该应用可以监控您的网络活动,包括收发电子邮件、使用应用和浏览网站。"</string>
    +     <string name="monitoring_description_app_personal" msgid="484599052118316268">"您已连接到<xliff:g id="APPLICATION">%1$s</xliff:g>,该应用可以监控您的个人网络活动,包括收发电子邮件、使用应用和浏览网站。"</string>
    ++    <string name="branded_monitoring_description_app_personal" msgid="2669518213949202599">"您已连接到<xliff:g id="APPLICATION">%1$s</xliff:g>,该应用可以监控您的个人网络活动,包括收发电子邮件、使用应用和浏览网站。"</string>
    +     <string name="monitoring_description_app_work" msgid="1754325860918060897">"您的工作资料由以下单位管理:<xliff:g id="ORGANIZATION">%1$s</xliff:g>。您已连接到<xliff:g id="APPLICATION">%2$s</xliff:g>,该应用可以监控您的工作网络活动,包括收发电子邮件、使用应用和浏览网站。\n\n若要了解详情,请与您单位的管理员联系。"</string>
    +     <string name="monitoring_description_app_personal_work" msgid="4946600443852045903">"您的工作资料由以下单位管理:<xliff:g id="ORGANIZATION">%1$s</xliff:g>。您已连接到<xliff:g id="APPLICATION_WORK">%2$s</xliff:g>,该应用可以监控您的工作网络活动,包括收发电子邮件、使用应用和浏览网站。\n\n此外,您还连接到了<xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g>,该应用可以监控您的个人网络活动。"</string>
    +     <string name="monitoring_description_vpn_app_device_owned" msgid="4970443827043261703">"您的设备由以下单位管理:<xliff:g id="ORGANIZATION">%1$s</xliff:g>。\n\n您单位的管理员可以监控和管理与此设备相关的设置、企业权限、应用、数据以及设备位置信息。\n\n您已连接到<xliff:g id="APPLICATION">%2$s</xliff:g>,该应用可以监控您的网络活动,包括收发电子邮件、使用应用和浏览网站。\n\n若要了解详情,请与您单位的管理员联系。"</string>
    +@@ -492,8 +494,6 @@
    +     <string name="clock_seconds_desc" msgid="6282693067130470675">"在状态栏中显示时钟的秒数。这可能会影响电池的续航时间。"</string>
    +     <string name="qs_rearrange" msgid="8060918697551068765">"重新排列快捷设置"</string>
    +     <string name="show_brightness" msgid="6613930842805942519">"在快捷设置中显示亮度栏"</string>
    +-    <string name="overview_nav_bar_gesture" msgid="8579814204727917764">"启用分屏上滑手势"</string>
    +-    <string name="overview_nav_bar_gesture_desc" msgid="6329167382305102615">"启用通过从“概览”按钮向上滑动的手势进入分屏模式"</string>
    +     <string name="experimental" msgid="6198182315536726162">"实验性功能"</string>
    +     <string name="enable_bluetooth_title" msgid="5027037706500635269">"要开启蓝牙吗?"</string>
    +     <string name="enable_bluetooth_message" msgid="9106595990708985385">"要将您的键盘连接到平板电脑,您必须先开启蓝牙。"</string>
    +@@ -651,4 +651,5 @@
    +     <string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"打开<xliff:g id="ID_1">%s</xliff:g>设置。"</string>
    +     <string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"修改设置顺序。"</string>
    +     <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"第 <xliff:g id="ID_1">%1$d</xliff:g> 页,共 <xliff:g id="ID_2">%2$d</xliff:g> 页"</string>
    ++    <string name="cant_silence_or_block" msgid="999689262131488625">"无法将通知静音或屏蔽"</string>
    + </resources>
    +diff --git a/packages/SystemUI/res/values-zh-rHK/strings.xml b/packages/SystemUI/res/values-zh-rHK/strings.xml
    +index c0172b1..8405fe5 100644
    +--- a/packages/SystemUI/res/values-zh-rHK/strings.xml
    ++++ b/packages/SystemUI/res/values-zh-rHK/strings.xml
    +@@ -240,7 +240,7 @@
    +     <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"已暫停 4G 數據"</string>
    +     <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"已暫停流動數據"</string>
    +     <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"已暫停使用數據"</string>
    +-    <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"由於您已達到設定的數據用量上限,裝置已暫停使用數據,直到週期結束。\n\n如恢復使用數據,流動網絡供應商可能會向您收取費用。"</string>
    ++    <string name="data_usage_disabled_dialog" msgid="1841738975235283398">"已達到您設定的數據上限。系統將停止使用流動數據網絡。\n\n如果您恢復使用流動數據網絡,可能需要支付數據費用。"</string>
    +     <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"恢復"</string>
    +     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"沒有互聯網連線"</string>
    +     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi 已連線"</string>
    +@@ -406,6 +406,7 @@
    +     <string name="device_owned_footer" msgid="3802752663326030053">"裝置可能會受到監控"</string>
    +     <string name="profile_owned_footer" msgid="8021888108553696069">"個人檔案可能受到監控"</string>
    +     <string name="vpn_footer" msgid="2388611096129106812">"網絡可能會受到監控"</string>
    ++    <string name="branded_vpn_footer" msgid="2168111859226496230">"網絡可能會受到監控"</string>
    +     <string name="monitoring_title_device_owned" msgid="7121079311903859610">"裝置監控"</string>
    +     <string name="monitoring_title_profile_owned" msgid="6790109874733501487">"個人檔案監控"</string>
    +     <string name="monitoring_title" msgid="169206259253048106">"網絡監控"</string>
    +@@ -418,6 +419,7 @@
    +     <string name="legacy_vpn_name" msgid="6604123105765737830">"VPN"</string>
    +     <string name="monitoring_description_app" msgid="6259179342284742878">"您已連結至<xliff:g id="APPLICATION">%1$s</xliff:g> ,它能夠監控您的網絡活動,包括電郵、應用程式和網站。"</string>
    +     <string name="monitoring_description_app_personal" msgid="484599052118316268">"您已連結至<xliff:g id="APPLICATION">%1$s</xliff:g>,它能夠監控您的個人網絡活動,包括電郵、應用程式和網站。"</string>
    ++    <string name="branded_monitoring_description_app_personal" msgid="2669518213949202599">"您已連接至「<xliff:g id="APPLICATION">%1$s</xliff:g>」,此應用程式可以監控您的個人網絡活動,包括電郵、應用程式及網站。"</string>
    +     <string name="monitoring_description_app_work" msgid="1754325860918060897">"您的工作設定檔由<xliff:g id="ORGANIZATION">%1$s</xliff:g>管理。它已連結至<xliff:g id="APPLICATION">%2$s</xliff:g>,能夠監控您的工作網絡活動,包括電郵、應用程式和網站。\n\n如需進一步資訊,請聯絡您的管理員。"</string>
    +     <string name="monitoring_description_app_personal_work" msgid="4946600443852045903">"您的工作設定檔由<xliff:g id="ORGANIZATION">%1$s</xliff:g>管理。它已連結至<xliff:g id="APPLICATION_WORK">%2$s</xliff:g>,能夠監控您的工作網絡活動,包括電郵、應用程式和網站。\n\n此外,您亦連結至<xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g>,因此它亦能夠監控您的個人網絡活動。"</string>
    +     <string name="monitoring_description_vpn_app_device_owned" msgid="4970443827043261703">"您的裝置由 <xliff:g id="ORGANIZATION">%1$s</xliff:g> 管理。\n\n您的管理員可以監控及管理您裝置的設定、企業存取、應用程式、資料及位置資訊。\n\n此外,您的裝置連至 <xliff:g id="APPLICATION">%2$s</xliff:g>,它能監控您的網絡活動,包括電郵、應用程式及網站。\n\n如需更多資訊,請聯絡您的管理員。"</string>
    +@@ -494,8 +496,6 @@
    +     <string name="clock_seconds_desc" msgid="6282693067130470675">"在狀態列中顯示時鐘秒數,但可能會影響電池壽命。"</string>
    +     <string name="qs_rearrange" msgid="8060918697551068765">"重新排列快速設定"</string>
    +     <string name="show_brightness" msgid="6613930842805942519">"在快速設定顯示亮度"</string>
    +-    <string name="overview_nav_bar_gesture" msgid="8579814204727917764">"啟用分割畫面向上快速滑動手勢"</string>
    +-    <string name="overview_nav_bar_gesture_desc" msgid="6329167382305102615">"從 [概覽] 按鈕向上快速滑動,即可使用手勢功能進入分割畫面模式"</string>
    +     <string name="experimental" msgid="6198182315536726162">"實驗版"</string>
    +     <string name="enable_bluetooth_title" msgid="5027037706500635269">"要開啟藍牙嗎?"</string>
    +     <string name="enable_bluetooth_message" msgid="9106595990708985385">"如要將鍵盤連接至平板電腦,請先開啟藍牙。"</string>
    +@@ -653,4 +653,5 @@
    +     <string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"開啟<xliff:g id="ID_1">%s</xliff:g>設定頁面。"</string>
    +     <string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"編輯設定次序。"</string>
    +     <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"第 <xliff:g id="ID_1">%1$d</xliff:g> 頁 (共 <xliff:g id="ID_2">%2$d</xliff:g> 頁)"</string>
    ++    <string name="cant_silence_or_block" msgid="999689262131488625">"通知無法設為靜音或封鎖"</string>
    + </resources>
    +diff --git a/packages/SystemUI/res/values-zh-rTW/strings.xml b/packages/SystemUI/res/values-zh-rTW/strings.xml
    +index 66c1264..b4f2b27 100644
    +--- a/packages/SystemUI/res/values-zh-rTW/strings.xml
    ++++ b/packages/SystemUI/res/values-zh-rTW/strings.xml
    +@@ -238,7 +238,7 @@
    +     <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"已暫停 4G 數據連線"</string>
    +     <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"已暫停行動數據連線"</string>
    +     <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"已暫停數據連線"</string>
    +-    <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"由於數據用量已達設定上限,裝置在這個週期的剩餘時間將暫停使用數據連線。\n\n如果恢復使用,行動通訊業者可能會向您收取額外的連線費用。"</string>
    ++    <string name="data_usage_disabled_dialog" msgid="1841738975235283398">"你的數據用量已達設定的用量上限,因此系統已停止使用行動數據連線。\n\n如果你繼續使用行動數據連線,可能需要支付相關的數據傳輸費用。"</string>
    +     <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"恢復連線"</string>
    +     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"沒有網際網路連線"</string>
    +     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi 已連線"</string>
    +@@ -404,6 +404,7 @@
    +     <string name="device_owned_footer" msgid="3802752663326030053">"裝置可能會受到監控"</string>
    +     <string name="profile_owned_footer" msgid="8021888108553696069">"設定檔可能會受到監控"</string>
    +     <string name="vpn_footer" msgid="2388611096129106812">"網路可能會受到監控"</string>
    ++    <string name="branded_vpn_footer" msgid="2168111859226496230">"網路可能會受到監控"</string>
    +     <string name="monitoring_title_device_owned" msgid="7121079311903859610">"裝置監控"</string>
    +     <string name="monitoring_title_profile_owned" msgid="6790109874733501487">"設定檔監控"</string>
    +     <string name="monitoring_title" msgid="169206259253048106">"網路監控"</string>
    +@@ -416,6 +417,7 @@
    +     <string name="legacy_vpn_name" msgid="6604123105765737830">"VPN"</string>
    +     <string name="monitoring_description_app" msgid="6259179342284742878">"由於您已連線至 <xliff:g id="APPLICATION">%1$s</xliff:g>,您的網路活動也會受到這個應用程式監控,包括收發電子郵件、使用應用程式和瀏覽網站。"</string>
    +     <string name="monitoring_description_app_personal" msgid="484599052118316268">"由於您已連線至 <xliff:g id="APPLICATION">%1$s</xliff:g>,您的個人網路活動也會受到這個應用程式監控,包括收發電子郵件、使用應用程式和瀏覽網站。"</string>
    ++    <string name="branded_monitoring_description_app_personal" msgid="2669518213949202599">"由於你已連結至「<xliff:g id="APPLICATION">%1$s</xliff:g>」,你的個人網路活動 (包括收發電子郵件、使用應用程式及瀏覽網站) 可能會受到這個應用程式監控。"</string>
    +     <string name="monitoring_description_app_work" msgid="1754325860918060897">"您的 Work 設定檔是由下列機構管理:<xliff:g id="ORGANIZATION">%1$s</xliff:g>。由於設定檔已連線至 <xliff:g id="APPLICATION">%2$s</xliff:g>,您的工作網路活動也會受到這個應用程式監控,包括收發電子郵件、使用應用程式和瀏覽網站。\n\n詳情請洽您的管理員。"</string>
    +     <string name="monitoring_description_app_personal_work" msgid="4946600443852045903">"您的 Work 設定檔是由下列機構管理:<xliff:g id="ORGANIZATION">%1$s</xliff:g>。由於設定檔已連線至 <xliff:g id="APPLICATION_WORK">%2$s</xliff:g>,您的工作網路活動也會受到這個應用程式監控,包括收發電子郵件、使用應用程式和瀏覽網站。\n\n同時由於您也連線至<xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g>,您的個人網路活動也會受到這個應用程式監控。"</string>
    +     <string name="monitoring_description_vpn_app_device_owned" msgid="4970443827043261703">"您的裝置由下列機構管理:<xliff:g id="ORGANIZATION">%1$s</xliff:g>。\n\n您的管理員可以監控及管理與裝置相關的設定、企業網路存取權、應用程式和資料,以及裝置的位置資訊。\n\n由於您的裝置已連線至 <xliff:g id="APPLICATION">%2$s</xliff:g>,您的網路活動也會受到這個應用程式監控,包括收發電子郵件、使用應用程式和瀏覽網站。\n\n如需詳細資訊,請洽您的管理員。"</string>
    +@@ -492,8 +494,6 @@
    +     <string name="clock_seconds_desc" msgid="6282693067130470675">"在狀態列中顯示時鐘秒數。這可能會影響電池續航力。"</string>
    +     <string name="qs_rearrange" msgid="8060918697551068765">"重新排列快速設定"</string>
    +     <string name="show_brightness" msgid="6613930842805942519">"在快速設定中顯示亮度"</string>
    +-    <string name="overview_nav_bar_gesture" msgid="8579814204727917764">"啟用分割畫面向上滑動手勢"</string>
    +-    <string name="overview_nav_bar_gesture_desc" msgid="6329167382305102615">"啟用透過從 [總覽] 按鈕向上滑動的手勢進入分割畫面"</string>
    +     <string name="experimental" msgid="6198182315536726162">"實驗性"</string>
    +     <string name="enable_bluetooth_title" msgid="5027037706500635269">"要開啟藍牙功能嗎?"</string>
    +     <string name="enable_bluetooth_message" msgid="9106595990708985385">"如要將鍵盤連線到平板電腦,您必須先開啟藍牙。"</string>
    +@@ -651,4 +651,5 @@
    +     <string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"開啟「<xliff:g id="ID_1">%s</xliff:g>」設定。"</string>
    +     <string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"編輯設定順序。"</string>
    +     <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"第 <xliff:g id="ID_1">%1$d</xliff:g> 頁,共 <xliff:g id="ID_2">%2$d</xliff:g> 頁"</string>
    ++    <string name="cant_silence_or_block" msgid="999689262131488625">"無法關閉通知音效或封鎖通知"</string>
    + </resources>
    +diff --git a/packages/SystemUI/res/values-zu/strings.xml b/packages/SystemUI/res/values-zu/strings.xml
    +index 49bf0bd..c6e4044 100644
    +--- a/packages/SystemUI/res/values-zu/strings.xml
    ++++ b/packages/SystemUI/res/values-zu/strings.xml
    +@@ -238,7 +238,7 @@
    +     <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"4G idatha imisiwe"</string>
    +     <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"Idatha yeselula imisiwe"</string>
    +     <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"Idatha imisiwe"</string>
    +-    <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"Ngoba umkhawulo wakho wedatha osethiwe ufinyelelwe, idivayisi imise kancane ukusetshenziswa kwedatha ngesikhumbuzi salo mjikelezo.\n\nUkuqhuba futhi kungaholela kuzindleko kusuka kwinkampani yakho yenethiwekhi."</string>
    ++    <string name="data_usage_disabled_dialog" msgid="1841738975235283398">"Umkhawulo wedatha owusethayo ufikiwe. Awusasebenzisi idatha yeselula.\n\nUma uqalisa kabusha, izindleko zingasebenza ekusetshenzisweni kwedatha."</string>
    +     <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"Qalisa kabusha"</string>
    +     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Alukho uxhumano lwe-Inthanethi"</string>
    +     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"I-Wi-Fi ixhunyiwe"</string>
    +@@ -404,6 +404,7 @@
    +     <string name="device_owned_footer" msgid="3802752663326030053">"Idivayisi inganganyelwa"</string>
    +     <string name="profile_owned_footer" msgid="8021888108553696069">"Iphrofayela ingaqashwa"</string>
    +     <string name="vpn_footer" msgid="2388611096129106812">"Inethiwekhi kungenzeka iqashiwe"</string>
    ++    <string name="branded_vpn_footer" msgid="2168111859226496230">"Inethiwekhi kungenzeka iqashiwe"</string>
    +     <string name="monitoring_title_device_owned" msgid="7121079311903859610">"Ukwengamela idivayisi"</string>
    +     <string name="monitoring_title_profile_owned" msgid="6790109874733501487">"Ukuqapha iphrofayela"</string>
    +     <string name="monitoring_title" msgid="169206259253048106">"Ukuqashwa kwenethiwekhi"</string>
    +@@ -416,6 +417,7 @@
    +     <string name="legacy_vpn_name" msgid="6604123105765737830">"I-VPN"</string>
    +     <string name="monitoring_description_app" msgid="6259179342284742878">"Uxhumeke ku-<xliff:g id="APPLICATION">%1$s</xliff:g>, engahlola umsebenzi wakho wenethiwekhi ofaka ama-imeyili, izinhlelo zokusebenza, namawebhusayithi."</string>
    +     <string name="monitoring_description_app_personal" msgid="484599052118316268">"Uxhumeke ku-<xliff:g id="APPLICATION">%1$s</xliff:g>, engahlola umsebenzi wenethiwekhi yakho yomuntu siqu, ofaka ama-imeyili, izinhlelo zokusebenza, namawebhusayithi."</string>
    ++    <string name="branded_monitoring_description_app_personal" msgid="2669518213949202599">"Uxhumeke ku-<xliff:g id="APPLICATION">%1$s</xliff:g>, engaqapha umsebenzi wakho womuntu siqu wenethiwekhi, ofaka ama-imeyili, izinhlelo zokusebenza, namawebhusayithi."</string>
    +     <string name="monitoring_description_app_work" msgid="1754325860918060897">"Iphrofayela yakho yomsebenzi iphethwe yi-<xliff:g id="ORGANIZATION">%1$s</xliff:g>. Ixhumeke ku-<xliff:g id="APPLICATION">%2$s</xliff:g>, engahlola umsebenzi wenethiwekhi yakho yokusebenza, ofaka ama-imeyili, izinhlelo zokusebenza, namawebhusayithi.\n\nUkuze uthole olunye ulwazi, xhumana nomqondisi wakho."</string>
    +     <string name="monitoring_description_app_personal_work" msgid="4946600443852045903">"Iphrofayela yakho yomsebenzi iphethwe yi-<xliff:g id="ORGANIZATION">%1$s</xliff:g>. Ixhumeke ku-<xliff:g id="APPLICATION_WORK">%2$s</xliff:g>, engahlola umsebenzi wenethiwekhi yakho yomsebenzi, ofaka ama-imeyili, izinhlelo zokusebenza namawebhusayithi.\n\nFuthi uxhumeke ku-<xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g>, engahlola umsebenzi wenethiwekhi yakho yomuntu siqu."</string>
    +     <string name="monitoring_description_vpn_app_device_owned" msgid="4970443827043261703">"Idivayisi yakho iphethwe yi-<xliff:g id="ORGANIZATION">%1$s</xliff:g>.\n\nUmqondisi wakho angaqaphela aphinde aphathe izilungiselelo, ukufinyelela kwezinkampani, izinhlelo zokusebenza, idatha ehlotshaniswa nedivayisi yakho, nolwazi lendawo yedivayisi yakho.\n\nUxhumeke ku-<xliff:g id="APPLICATION">%2$s</xliff:g>, engaqaphela umsebenzi wakho wenethiwekhi, ofaka ama-imeyili, izinhlelo zokusebenza namawebhusayithi.\n\nUkuze uthole olunye ulwazi, xhumana nomqondisi wakho."</string>
    +@@ -492,8 +494,6 @@
    +     <string name="clock_seconds_desc" msgid="6282693067130470675">"Bonisa amasekhondi wewashi kubha yesimo. Ingathinta impilo yebhethri."</string>
    +     <string name="qs_rearrange" msgid="8060918697551068765">"Hlela kabusha izilungiselelo ezisheshayo"</string>
    +     <string name="show_brightness" msgid="6613930842805942519">"Bonisa ukukhanya kuzilungiselelo ezisheshayo"</string>
    +-    <string name="overview_nav_bar_gesture" msgid="8579814204727917764">"Nika amandla ukuthinta kokuswayiphela phezulu ukuhlukanisa isikrini"</string>
    +-    <string name="overview_nav_bar_gesture_desc" msgid="6329167382305102615">"Nika amandla ukuthinta ukuze ungene ekuhlukaniseni isikrini ngokuswayiphela phezulu kusukela kunkinobho yokubuka konke"</string>
    +     <string name="experimental" msgid="6198182315536726162">"Okokulinga"</string>
    +     <string name="enable_bluetooth_title" msgid="5027037706500635269">"Vula i-Bluetooth?"</string>
    +     <string name="enable_bluetooth_message" msgid="9106595990708985385">"Ukuze uxhume ikhibhodi yakho nethebhulethi yakho, kufanele uqale ngokuvula i-Bluetooth."</string>
    +@@ -651,4 +651,5 @@
    +     <string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"Vula izilungiselelo ze-<xliff:g id="ID_1">%s</xliff:g>."</string>
    +     <string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"Hlela uhlelo lwezilungiselelo."</string>
    +     <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"Ikhasi <xliff:g id="ID_1">%1$d</xliff:g> kwangu-<xliff:g id="ID_2">%2$d</xliff:g>"</string>
    ++    <string name="cant_silence_or_block" msgid="999689262131488625">"Izaziso azikwazi ukuthuliswa noma ukuvinjelwa"</string>
    + </resources>
    +diff --git a/packages/SystemUI/res/values/config.xml b/packages/SystemUI/res/values/config.xml
    +index 8d44048..9eea375 100644
    +--- a/packages/SystemUI/res/values/config.xml
    ++++ b/packages/SystemUI/res/values/config.xml
    +@@ -100,7 +100,7 @@
    + 
    +     <!-- The default tiles to display in QuickSettings -->
    +     <string name="quick_settings_tiles_default" translatable="false">
    +-        wifi,cell,battery,dnd,flashlight,rotation,bt,airplane,location
    ++        wifi,cell,battery,dnd,flashlight,rotation,bt,airplane
    +     </string>
    + 
    +     <!-- Tiles native to System UI. Order should match "quick_settings_tiles_default" -->
    +@@ -209,9 +209,6 @@
    +     <!-- Doze: should the significant motion sensor be used as a pulse signal? -->
    +     <bool name="doze_pulse_on_significant_motion">false</bool>
    + 
    +-    <!-- Doze: should the pickup sensor be used as a pulse signal? -->
    +-    <bool name="doze_pulse_on_pick_up">false</bool>
    +-
    +     <!-- Doze: check proximity sensor before pulsing? -->
    +     <bool name="doze_proximity_check_before_pulse">true</bool>
    + 
    +diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
    +index 6c48b25..2ea475a 100644
    +--- a/packages/SystemUI/res/values/strings.xml
    ++++ b/packages/SystemUI/res/values/strings.xml
    +@@ -569,7 +569,7 @@
    +     <!-- Title of dialog shown when data usage has exceeded limit and has been disabled. [CHAR LIMIT=48] -->
    +     <string name="data_usage_disabled_dialog_title">Data is paused</string>
    +     <!-- Body of dialog shown when data usage has exceeded limit and has been disabled. [CHAR LIMIT=NONE] -->
    +-    <string name="data_usage_disabled_dialog">Because your set data limit was reached, the device has paused data usage for the remainder of this cycle.\n\nResuming may lead to charges from your carrier.</string>
    ++    <string name="data_usage_disabled_dialog">The data limit you set has been reached. You are no longer using cellular data.\n\nIf you resume, charges may apply for data usage.</string>
    +     <!-- Dialog button indicating that data connection should be re-enabled. [CHAR LIMIT=28] -->
    +     <string name="data_usage_disabled_dialog_enable">Resume</string>
    + 
    +@@ -1001,6 +1001,9 @@
    +     <!-- Footer vpn present text [CHAR LIMIT=50] -->
    +     <string name="vpn_footer">Network may be monitored</string>
    + 
    ++    <!-- Footer vpn present text [CHAR LIMIT=50] -->
    ++    <string name="branded_vpn_footer">Network may be monitored</string>
    ++
    +     <!-- Monitoring dialog title for device owned devices [CHAR LIMIT=35] -->
    +     <string name="monitoring_title_device_owned">Device monitoring</string>
    + 
    +@@ -1037,6 +1040,9 @@
    +     <!-- Monitoring dialog text for single app (inside personal profile) [CHAR LIMIT=400] -->
    +     <string name="monitoring_description_app_personal">You\'re connected to <xliff:g id="application">%1$s</xliff:g>, which can monitor your personal network activity, including emails, apps, and websites.</string>
    + 
    ++    <!-- Monitoring dialog text for single app (inside personal profile) [CHAR LIMIT=400] -->
    ++    <string name="branded_monitoring_description_app_personal">You\'re connected to <xliff:g id="application">%1$s</xliff:g>, which can monitor your personal network activity, including emails, apps, and websites.</string>
    ++
    +     <!-- Monitoring dialog text for single app (inside work profile) [CHAR LIMIT=400] -->
    +     <string name="monitoring_description_app_work">Your work profile is managed by <xliff:g id="organization">%1$s</xliff:g>. It is connected to <xliff:g id="application">%2$s</xliff:g>, which can monitor your work network activity, including emails, apps, and websites.\n\nFor more information, contact your administrator.</string>
    + 
    +@@ -1243,11 +1249,6 @@
    +     <!-- Option to use new paging layout in quick settings [CHAR LIMIT=60] -->
    +     <string name="qs_paging" translatable="false">Use the new Quick Settings</string>
    + 
    +-    <!-- Toggle to enable the gesture to enter split-screen by swiping up from the Overview button. [CHAR LIMIT=60]-->
    +-    <string name="overview_nav_bar_gesture">Enable split-screen swipe-up gesture</string>
    +-    <!-- Description for the toggle to enable the gesture to enter split-screen by swiping up from the Overview button. [CHAR LIMIT=NONE]-->
    +-    <string name="overview_nav_bar_gesture_desc">Enable gesture to enter split-screen by swiping up from the Overview button</string>
    +-
    +     <!-- Category in the System UI Tuner settings, where new/experimental
    +          settings are -->
    +     <string name="experimental">Experimental</string>
    +@@ -1665,7 +1666,10 @@
    +     <!-- accessibility label for button to edit quick settings [CHAR LIMIT=NONE] -->
    +     <string name="accessibility_quick_settings_edit">Edit order of settings.</string>
    + 
    +-    <!-- accessibility label for paging indicator in quick settings [CHAR LIMITi=NONE] -->
    ++    <!-- accessibility label for paging indicator in quick settings [CHAR LIMIT=NONE] -->
    +     <string name="accessibility_quick_settings_page">Page <xliff:g name="current_page" example="1">%1$d</xliff:g> of <xliff:g name="num_pages" example="2">%2$d</xliff:g></string>
    + 
    ++    <!-- Label that replaces other notification controls when the notification is from the system
    ++         and cannot be silenced (see @string/show_silently) or blocked (see @string/block) -->
    ++    <string name="cant_silence_or_block">Notifications can\'t be silenced or blocked</string>
    + </resources>
    +diff --git a/packages/SystemUI/res/values/styles.xml b/packages/SystemUI/res/values/styles.xml
    +index 1ee13e9..c659acf 100644
    +--- a/packages/SystemUI/res/values/styles.xml
    ++++ b/packages/SystemUI/res/values/styles.xml
    +@@ -42,7 +42,7 @@
    +     </style>
    + 
    +     <!-- Theme used for the activity that shows when the system forced an app to be resizable -->
    +-    <style name="ForcedResizableTheme" parent="@android:style/Theme.Translucent.NoTitleBar.Fullscreen">
    ++    <style name="ForcedResizableTheme" parent="@android:style/Theme.Translucent.NoTitleBar">
    +         <item name="android:windowBackground">@drawable/forced_resizable_background</item>
    +         <item name="android:statusBarColor">@color/transparent</item>
    +         <item name="android:windowAnimationStyle">@style/Animation.ForcedResizable</item>
    +@@ -217,7 +217,7 @@
    +     <style name="Animation.StatusBar">
    +     </style>
    + 
    +-    <style name="systemui_theme" parent="@android:style/Theme.DeviceDefault" />
    ++    <style name="systemui_theme" parent="@*android:style/Theme.DeviceDefault.Settings.Dark" />
    + 
    +     <style name="systemui_theme_remote_input" parent="@android:style/Theme.DeviceDefault.Light">
    +         <item name="android:colorAccent">@color/remote_input_accent</item>
    +diff --git a/packages/SystemUI/res/xml/other_settings.xml b/packages/SystemUI/res/xml/other_settings.xml
    +index 3c872fa..ce636cd 100644
    +--- a/packages/SystemUI/res/xml/other_settings.xml
    ++++ b/packages/SystemUI/res/xml/other_settings.xml
    +@@ -18,11 +18,6 @@
    +                   xmlns:sysui="http://schemas.android.com/apk/res-auto"
    +                   android:title="@string/other">
    + 
    +-    <com.android.systemui.tuner.TunerSwitch
    +-            android:key="overview_nav_bar_gesture"
    +-            android:title="@string/overview_nav_bar_gesture"
    +-            android:summary="@string/overview_nav_bar_gesture_desc" />
    +-
    +     <!-- importance -->
    +     <Preference
    +             android:key="power_notification_controls"
    +diff --git a/packages/SystemUI/src/com/android/systemui/BootReceiver.java b/packages/SystemUI/src/com/android/systemui/BootReceiver.java
    +deleted file mode 100644
    +index 8e24eeb..0000000
    +--- a/packages/SystemUI/src/com/android/systemui/BootReceiver.java
    ++++ /dev/null
    +@@ -1,46 +0,0 @@
    +-/*
    +- * Copyright (C) 2011 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 com.android.systemui;
    +-
    +-import android.content.BroadcastReceiver;
    +-import android.content.ContentResolver;
    +-import android.content.Context;
    +-import android.content.Intent;
    +-import android.provider.Settings;
    +-import android.util.Log;
    +-
    +-/**
    +- * Performs a number of miscellaneous, non-system-critical actions
    +- * after the system has finished booting.
    +- */
    +-public class BootReceiver extends BroadcastReceiver {
    +-    private static final String TAG = "SystemUIBootReceiver";
    +-
    +-    @Override
    +-    public void onReceive(final Context context, Intent intent) {
    +-        try {
    +-            // Start the load average overlay, if activated
    +-            ContentResolver res = context.getContentResolver();
    +-            if (Settings.Global.getInt(res, Settings.Global.SHOW_PROCESSES, 0) != 0) {
    +-                Intent loadavg = new Intent(context, com.android.systemui.LoadAverageService.class);
    +-                context.startService(loadavg);
    +-            }
    +-        } catch (Exception e) {
    +-            Log.e(TAG, "Can't start load average service", e);
    +-        }
    +-    }
    +-}
    +diff --git a/packages/SystemUI/src/com/android/systemui/LoadAverageService.java b/packages/SystemUI/src/com/android/systemui/LoadAverageService.java
    +deleted file mode 100644
    +index 59ffe03..0000000
    +--- a/packages/SystemUI/src/com/android/systemui/LoadAverageService.java
    ++++ /dev/null
    +@@ -1,315 +0,0 @@
    +-/*
    +- * Copyright (C) 2007 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 com.android.systemui;
    +-
    +-import android.app.Service;
    +-import android.content.Context;
    +-import android.content.Intent;
    +-import android.graphics.Canvas;
    +-import android.graphics.Paint;
    +-import android.graphics.PixelFormat;
    +-import android.os.Handler;
    +-import android.os.IBinder;
    +-import android.os.Message;
    +-import android.view.Gravity;
    +-import android.view.View;
    +-import android.view.WindowManager;
    +-
    +-import com.android.internal.os.ProcessCpuTracker;
    +-
    +-public class LoadAverageService extends Service {
    +-    private View mView;
    +-
    +-    private static final class CpuTracker extends ProcessCpuTracker {
    +-        String mLoadText;
    +-        int mLoadWidth;
    +-
    +-        private final Paint mPaint;
    +-
    +-        CpuTracker(Paint paint) {
    +-            super(false);
    +-            mPaint = paint;
    +-        }
    +-
    +-        @Override
    +-        public void onLoadChanged(float load1, float load5, float load15) {
    +-            mLoadText = load1 + " / " + load5 + " / " + load15;
    +-            mLoadWidth = (int)mPaint.measureText(mLoadText);
    +-        }
    +-
    +-        @Override
    +-        public int onMeasureProcessName(String name) {
    +-            return (int)mPaint.measureText(name);
    +-        }
    +-    }
    +-
    +-    private class LoadView extends View {
    +-        private Handler mHandler = new Handler() {
    +-            @Override
    +-            public void handleMessage(Message msg) {
    +-                if (msg.what == 1) {
    +-                    mStats.update();
    +-                    updateDisplay();
    +-                    Message m = obtainMessage(1);
    +-                    sendMessageDelayed(m, 2000);
    +-                }
    +-            }
    +-        };
    +-
    +-        private final CpuTracker mStats;
    +-
    +-        private Paint mLoadPaint;
    +-        private Paint mAddedPaint;
    +-        private Paint mRemovedPaint;
    +-        private Paint mShadowPaint;
    +-        private Paint mShadow2Paint;
    +-        private Paint mIrqPaint;
    +-        private Paint mSystemPaint;
    +-        private Paint mUserPaint;
    +-        private float mAscent;
    +-        private int mFH;
    +-
    +-        private int mNeededWidth;
    +-        private int mNeededHeight;
    +-
    +-        LoadView(Context c) {
    +-            super(c);
    +-
    +-            setPadding(4, 4, 4, 4);
    +-            //setBackgroundResource(com.android.internal.R.drawable.load_average_background);
    +-
    +-            // Need to scale text size by density...  but we won't do it
    +-            // linearly, because with higher dps it is nice to squeeze the
    +-            // text a bit to fit more of it.  And with lower dps, trying to
    +-            // go much smaller will result in unreadable text.
    +-            int textSize = 10;
    +-            float density = c.getResources().getDisplayMetrics().density;
    +-            if (density < 1) {
    +-                textSize = 9;
    +-            } else {
    +-                textSize = (int)(10*density);
    +-                if (textSize < 10) {
    +-                    textSize = 10;
    +-                }
    +-            }
    +-            mLoadPaint = new Paint();
    +-            mLoadPaint.setAntiAlias(true);
    +-            mLoadPaint.setTextSize(textSize);
    +-            mLoadPaint.setARGB(255, 255, 255, 255);
    +-
    +-            mAddedPaint = new Paint();
    +-            mAddedPaint.setAntiAlias(true);
    +-            mAddedPaint.setTextSize(textSize);
    +-            mAddedPaint.setARGB(255, 128, 255, 128);
    +-
    +-            mRemovedPaint = new Paint();
    +-            mRemovedPaint.setAntiAlias(true);
    +-            mRemovedPaint.setStrikeThruText(true);
    +-            mRemovedPaint.setTextSize(textSize);
    +-            mRemovedPaint.setARGB(255, 255, 128, 128);
    +-
    +-            mShadowPaint = new Paint();
    +-            mShadowPaint.setAntiAlias(true);
    +-            mShadowPaint.setTextSize(textSize);
    +-            //mShadowPaint.setFakeBoldText(true);
    +-            mShadowPaint.setARGB(192, 0, 0, 0);
    +-            mLoadPaint.setShadowLayer(4, 0, 0, 0xff000000);
    +-
    +-            mShadow2Paint = new Paint();
    +-            mShadow2Paint.setAntiAlias(true);
    +-            mShadow2Paint.setTextSize(textSize);
    +-            //mShadow2Paint.setFakeBoldText(true);
    +-            mShadow2Paint.setARGB(192, 0, 0, 0);
    +-            mLoadPaint.setShadowLayer(2, 0, 0, 0xff000000);
    +-
    +-            mIrqPaint = new Paint();
    +-            mIrqPaint.setARGB(0x80, 0, 0, 0xff);
    +-            mIrqPaint.setShadowLayer(2, 0, 0, 0xff000000);
    +-            mSystemPaint = new Paint();
    +-            mSystemPaint.setARGB(0x80, 0xff, 0, 0);
    +-            mSystemPaint.setShadowLayer(2, 0, 0, 0xff000000);
    +-            mUserPaint = new Paint();
    +-            mUserPaint.setARGB(0x80, 0, 0xff, 0);
    +-            mSystemPaint.setShadowLayer(2, 0, 0, 0xff000000);
    +-
    +-            mAscent = mLoadPaint.ascent();
    +-            float descent = mLoadPaint.descent();
    +-            mFH = (int)(descent - mAscent + .5f);
    +-
    +-            mStats = new CpuTracker(mLoadPaint);
    +-            mStats.init();
    +-            updateDisplay();
    +-        }
    +-
    +-        @Override
    +-        protected void onAttachedToWindow() {
    +-            super.onAttachedToWindow();
    +-            mHandler.sendEmptyMessage(1);
    +-        }
    +-
    +-        @Override
    +-        protected void onDetachedFromWindow() {
    +-            super.onDetachedFromWindow();
    +-            mHandler.removeMessages(1);
    +-        }
    +-
    +-        @Override
    +-        protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
    +-            setMeasuredDimension(resolveSize(mNeededWidth, widthMeasureSpec),
    +-                    resolveSize(mNeededHeight, heightMeasureSpec));
    +-        }
    +-
    +-        @Override
    +-        public void onDraw(Canvas canvas) {
    +-            super.onDraw(canvas);
    +-            final int W = mNeededWidth;
    +-            final int RIGHT = getWidth()-1;
    +-
    +-            final CpuTracker stats = mStats;
    +-            final int userTime = stats.getLastUserTime();
    +-            final int systemTime = stats.getLastSystemTime();
    +-            final int iowaitTime = stats.getLastIoWaitTime();
    +-            final int irqTime = stats.getLastIrqTime();
    +-            final int softIrqTime = stats.getLastSoftIrqTime();
    +-            final int idleTime = stats.getLastIdleTime();
    +-
    +-            final int totalTime = userTime+systemTime+iowaitTime+irqTime+softIrqTime+idleTime;
    +-            if (totalTime == 0) {
    +-                return;
    +-            }
    +-            int userW = (userTime*W)/totalTime;
    +-            int systemW = (systemTime*W)/totalTime;
    +-            int irqW = ((iowaitTime+irqTime+softIrqTime)*W)/totalTime;
    +-
    +-            int paddingRight = getPaddingRight();
    +-            int x = RIGHT - paddingRight;
    +-            int top = getPaddingTop() + 2;
    +-            int bottom = getPaddingTop() + mFH - 2;
    +-
    +-            if (irqW > 0) {
    +-                canvas.drawRect(x-irqW, top, x, bottom, mIrqPaint);
    +-                x -= irqW;
    +-            }
    +-            if (systemW > 0) {
    +-                canvas.drawRect(x-systemW, top, x, bottom, mSystemPaint);
    +-                x -= systemW;
    +-            }
    +-            if (userW > 0) {
    +-                canvas.drawRect(x-userW, top, x, bottom, mUserPaint);
    +-                x -= userW;
    +-            }
    +-
    +-            int y = getPaddingTop() - (int)mAscent;
    +-            canvas.drawText(stats.mLoadText, RIGHT-paddingRight-stats.mLoadWidth-1,
    +-                    y-1, mShadowPaint);
    +-            canvas.drawText(stats.mLoadText, RIGHT-paddingRight-stats.mLoadWidth-1,
    +-                    y+1, mShadowPaint);
    +-            canvas.drawText(stats.mLoadText, RIGHT-paddingRight-stats.mLoadWidth+1,
    +-                    y-1, mShadow2Paint);
    +-            canvas.drawText(stats.mLoadText, RIGHT-paddingRight-stats.mLoadWidth+1,
    +-                    y+1, mShadow2Paint);
    +-            canvas.drawText(stats.mLoadText, RIGHT-paddingRight-stats.mLoadWidth,
    +-                    y, mLoadPaint);
    +-
    +-            int N = stats.countWorkingStats();
    +-            for (int i=0; i<N; i++) {
    +-                CpuTracker.Stats st = stats.getWorkingStats(i);
    +-                y += mFH;
    +-                top += mFH;
    +-                bottom += mFH;
    +-
    +-                userW = (st.rel_utime*W)/totalTime;
    +-                systemW = (st.rel_stime*W)/totalTime;
    +-                x = RIGHT - paddingRight;
    +-                if (systemW > 0) {
    +-                    canvas.drawRect(x-systemW, top, x, bottom, mSystemPaint);
    +-                    x -= systemW;
    +-                }
    +-                if (userW > 0) {
    +-                    canvas.drawRect(x-userW, top, x, bottom, mUserPaint);
    +-                    x -= userW;
    +-                }
    +-
    +-                canvas.drawText(st.name, RIGHT-paddingRight-st.nameWidth-1,
    +-                        y-1, mShadowPaint);
    +-                canvas.drawText(st.name, RIGHT-paddingRight-st.nameWidth-1,
    +-                        y+1, mShadowPaint);
    +-                canvas.drawText(st.name, RIGHT-paddingRight-st.nameWidth+1,
    +-                        y-1, mShadow2Paint);
    +-                canvas.drawText(st.name, RIGHT-paddingRight-st.nameWidth+1,
    +-                        y+1, mShadow2Paint);
    +-                Paint p = mLoadPaint;
    +-                if (st.added) p = mAddedPaint;
    +-                if (st.removed) p = mRemovedPaint;
    +-                canvas.drawText(st.name, RIGHT-paddingRight-st.nameWidth, y, p);
    +-            }
    +-        }
    +-
    +-        void updateDisplay() {
    +-            final CpuTracker stats = mStats;
    +-            final int NW = stats.countWorkingStats();
    +-
    +-            int maxWidth = stats.mLoadWidth;
    +-            for (int i=0; i<NW; i++) {
    +-                CpuTracker.Stats st = stats.getWorkingStats(i);
    +-                if (st.nameWidth > maxWidth) {
    +-                    maxWidth = st.nameWidth;
    +-                }
    +-            }
    +-
    +-            int neededWidth = getPaddingLeft() + getPaddingRight() + maxWidth;
    +-            int neededHeight = getPaddingTop() + getPaddingBottom() + (mFH*(1+NW));
    +-            if (neededWidth != mNeededWidth || neededHeight != mNeededHeight) {
    +-                mNeededWidth = neededWidth;
    +-                mNeededHeight = neededHeight;
    +-                requestLayout();
    +-            } else {
    +-                invalidate();
    +-            }
    +-        }
    +-    }
    +-
    +-    @Override
    +-    public void onCreate() {
    +-        super.onCreate();
    +-        mView = new LoadView(this);
    +-        WindowManager.LayoutParams params = new WindowManager.LayoutParams(
    +-            WindowManager.LayoutParams.MATCH_PARENT,
    +-            WindowManager.LayoutParams.WRAP_CONTENT,
    +-            WindowManager.LayoutParams.TYPE_SECURE_SYSTEM_OVERLAY,
    +-            WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE|
    +-            WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE,
    +-            PixelFormat.TRANSLUCENT);
    +-        params.gravity = Gravity.END | Gravity.TOP;
    +-        params.setTitle("Load Average");
    +-        WindowManager wm = (WindowManager)getSystemService(WINDOW_SERVICE);
    +-        wm.addView(mView, params);
    +-    }
    +-
    +-    @Override
    +-    public void onDestroy() {
    +-        super.onDestroy();
    +-        ((WindowManager)getSystemService(WINDOW_SERVICE)).removeView(mView);
    +-        mView = null;
    +-    }
    +-
    +-    @Override
    +-    public IBinder onBind(Intent intent) {
    +-        return null;
    +-    }
    +-
    +-}
    +diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeLog.java b/packages/SystemUI/src/com/android/systemui/doze/DozeLog.java
    +index 874021a..b3038b9 100644
    +--- a/packages/SystemUI/src/com/android/systemui/doze/DozeLog.java
    ++++ b/packages/SystemUI/src/com/android/systemui/doze/DozeLog.java
    +@@ -35,12 +35,13 @@ public class DozeLog {
    +     private static final int SIZE = Build.IS_DEBUGGABLE ? 400 : 50;
    +     static final SimpleDateFormat FORMAT = new SimpleDateFormat("MM-dd HH:mm:ss.SSS");
    + 
    +-    private static final int PULSE_REASONS = 4;
    ++    private static final int PULSE_REASONS = 5;
    + 
    +     public static final int PULSE_REASON_INTENT = 0;
    +     public static final int PULSE_REASON_NOTIFICATION = 1;
    +     public static final int PULSE_REASON_SENSOR_SIGMOTION = 2;
    +     public static final int PULSE_REASON_SENSOR_PICKUP = 3;
    ++    public static final int PULSE_REASON_SENSOR_DOUBLE_TAP = 4;
    + 
    +     private static long[] sTimes;
    +     private static String[] sMessages;
    +@@ -167,6 +168,7 @@ public class DozeLog {
    +             case PULSE_REASON_NOTIFICATION: return "notification";
    +             case PULSE_REASON_SENSOR_SIGMOTION: return "sigmotion";
    +             case PULSE_REASON_SENSOR_PICKUP: return "pickup";
    ++            case PULSE_REASON_SENSOR_DOUBLE_TAP: return "doubletap";
    +             default: throw new IllegalArgumentException("bad reason: " + pulseReason);
    +         }
    +     }
    +diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeService.java b/packages/SystemUI/src/com/android/systemui/doze/DozeService.java
    +index ec4f447..6c35243 100644
    +--- a/packages/SystemUI/src/com/android/systemui/doze/DozeService.java
    ++++ b/packages/SystemUI/src/com/android/systemui/doze/DozeService.java
    +@@ -16,12 +16,14 @@
    + 
    + package com.android.systemui.doze;
    + 
    ++import android.app.ActivityManager;
    + import android.app.UiModeManager;
    + import android.content.BroadcastReceiver;
    + import android.content.Context;
    + import android.content.Intent;
    + import android.content.IntentFilter;
    + import android.content.res.Configuration;
    ++import android.database.ContentObserver;
    + import android.hardware.Sensor;
    + import android.hardware.SensorEvent;
    + import android.hardware.SensorEventListener;
    +@@ -29,14 +31,19 @@ import android.hardware.SensorManager;
    + import android.hardware.TriggerEvent;
    + import android.hardware.TriggerEventListener;
    + import android.media.AudioAttributes;
    ++import android.net.Uri;
    + import android.os.Handler;
    + import android.os.PowerManager;
    + import android.os.SystemClock;
    ++import android.os.UserHandle;
    + import android.os.Vibrator;
    ++import android.provider.Settings;
    + import android.service.dreams.DreamService;
    ++import android.text.TextUtils;
    + import android.util.Log;
    + import android.view.Display;
    + 
    ++import com.android.internal.hardware.AmbientDisplayConfiguration;
    + import com.android.internal.logging.MetricsLogger;
    + import com.android.internal.logging.MetricsProto.MetricsEvent;
    + import com.android.systemui.SystemUIApplication;
    +@@ -45,6 +52,7 @@ import com.android.systemui.statusbar.phone.DozeParameters;
    + import java.io.FileDescriptor;
    + import java.io.PrintWriter;
    + import java.util.Date;
    ++import java.util.List;
    + 
    + public class DozeService extends DreamService {
    +     private static final String TAG = "DozeService";
    +@@ -53,14 +61,19 @@ public class DozeService extends DreamService {
    +     private static final String ACTION_BASE = "com.android.systemui.doze";
    +     private static final String PULSE_ACTION = ACTION_BASE + ".pulse";
    + 
    ++    /**
    ++     * If true, reregisters all trigger sensors when the screen turns off.
    ++     */
    ++    private static final boolean REREGISTER_ALL_SENSORS_ON_SCREEN_OFF = true;
    ++
    +     private final String mTag = String.format(TAG + ".%08x", hashCode());
    +     private final Context mContext = this;
    +     private final DozeParameters mDozeParameters = new DozeParameters(mContext);
    +     private final Handler mHandler = new Handler();
    + 
    +     private DozeHost mHost;
    +-    private SensorManager mSensors;
    +-    private TriggerSensor mSigMotionSensor;
    ++    private SensorManager mSensorManager;
    ++    private TriggerSensor[] mSensors;
    +     private TriggerSensor mPickupSensor;
    +     private PowerManager mPowerManager;
    +     private PowerManager.WakeLock mWakeLock;
    +@@ -73,6 +86,8 @@ public class DozeService extends DreamService {
    +     private boolean mCarMode;
    +     private long mNotificationPulseTime;
    + 
    ++    private AmbientDisplayConfiguration mConfig;
    ++
    +     public DozeService() {
    +         if (DEBUG) Log.d(mTag, "new DozeService()");
    +         setDebug(DEBUG);
    +@@ -86,8 +101,10 @@ public class DozeService extends DreamService {
    +         pw.print("  mWakeLock: held="); pw.println(mWakeLock.isHeld());
    +         pw.print("  mHost: "); pw.println(mHost);
    +         pw.print("  mBroadcastReceiverRegistered: "); pw.println(mBroadcastReceiverRegistered);
    +-        pw.print("  mSigMotionSensor: "); pw.println(mSigMotionSensor);
    +-        pw.print("  mPickupSensor:"); pw.println(mPickupSensor);
    ++        for (TriggerSensor s : mSensors) {
    ++            pw.print("  sensor: ");
    ++            pw.println(s);
    ++        }
    +         pw.print("  mDisplayStateSupported: "); pw.println(mDisplayStateSupported);
    +         pw.print("  mPowerSaveActive: "); pw.println(mPowerSaveActive);
    +         pw.print("  mCarMode: "); pw.println(mCarMode);
    +@@ -110,13 +127,26 @@ public class DozeService extends DreamService {
    + 
    +         setWindowless(true);
    + 
    +-        mSensors = (SensorManager) mContext.getSystemService(Context.SENSOR_SERVICE);
    +-        mSigMotionSensor = new TriggerSensor(Sensor.TYPE_SIGNIFICANT_MOTION,
    +-                mDozeParameters.getPulseOnSigMotion(), mDozeParameters.getVibrateOnSigMotion(),
    +-                DozeLog.PULSE_REASON_SENSOR_SIGMOTION);
    +-        mPickupSensor = new TriggerSensor(Sensor.TYPE_PICK_UP_GESTURE,
    +-                mDozeParameters.getPulseOnPickup(), mDozeParameters.getVibrateOnPickup(),
    +-                DozeLog.PULSE_REASON_SENSOR_PICKUP);
    ++        mSensorManager = (SensorManager) mContext.getSystemService(Context.SENSOR_SERVICE);
    ++        mConfig = new AmbientDisplayConfiguration(mContext);
    ++        mSensors = new TriggerSensor[] {
    ++                new TriggerSensor(
    ++                        mSensorManager.getDefaultSensor(Sensor.TYPE_SIGNIFICANT_MOTION),
    ++                        null /* setting */,
    ++                        mDozeParameters.getPulseOnSigMotion(),
    ++                        mDozeParameters.getVibrateOnSigMotion(),
    ++                        DozeLog.PULSE_REASON_SENSOR_SIGMOTION),
    ++                mPickupSensor = new TriggerSensor(
    ++                        mSensorManager.getDefaultSensor(Sensor.TYPE_PICK_UP_GESTURE),
    ++                        Settings.Secure.DOZE_PULSE_ON_PICK_UP,
    ++                        mConfig.pulseOnPickupAvailable(), mDozeParameters.getVibrateOnPickup(),
    ++                        DozeLog.PULSE_REASON_SENSOR_PICKUP),
    ++                new TriggerSensor(
    ++                        findSensorWithType(mConfig.doubleTapSensorType()),
    ++                        Settings.Secure.DOZE_PULSE_ON_DOUBLE_TAP, true,
    ++                        mDozeParameters.getVibrateOnPickup(),
    ++                        DozeLog.PULSE_REASON_SENSOR_DOUBLE_TAP)
    ++        };
    +         mPowerManager = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
    +         mWakeLock = mPowerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, TAG);
    +         mWakeLock.setReferenceCounted(true);
    +@@ -159,18 +189,15 @@ public class DozeService extends DreamService {
    +         // Ask the host to get things ready to start dozing.
    +         // Once ready, we call startDozing() at which point the CPU may suspend
    +         // and we will need to acquire a wakelock to do work.
    +-        mHost.startDozing(new Runnable() {
    +-            @Override
    +-            public void run() {
    +-                if (mDreaming) {
    +-                    startDozing();
    ++        mHost.startDozing(mWakeLock.wrap(() -> {
    ++            if (mDreaming) {
    ++                startDozing();
    + 
    +-                    // From this point until onDreamingStopped we will need to hold a
    +-                    // wakelock whenever we are doing work.  Note that we never call
    +-                    // stopDozing because can we just keep dozing until the bitter end.
    +-                }
    ++                // From this point until onDreamingStopped we will need to hold a
    ++                // wakelock whenever we are doing work.  Note that we never call
    ++                // stopDozing because can we just keep dozing until the bitter end.
    +             }
    +-        });
    ++        }));
    +     }
    + 
    +     @Override
    +@@ -254,6 +281,9 @@ public class DozeService extends DreamService {
    +             public void onPulseFinished() {
    +                 if (mPulsing && mDreaming) {
    +                     mPulsing = false;
    ++                    if (REREGISTER_ALL_SENSORS_ON_SCREEN_OFF) {
    ++                        reregisterAllSensors();
    ++                    }
    +                     turnDisplayOff();
    +                 }
    +                 mWakeLock.release(); // needs to be unconditional to balance acquire
    +@@ -283,21 +313,41 @@ public class DozeService extends DreamService {
    + 
    +     private void listenForPulseSignals(boolean listen) {
    +         if (DEBUG) Log.d(mTag, "listenForPulseSignals: " + listen);
    +-        mSigMotionSensor.setListening(listen);
    +-        mPickupSensor.setListening(listen);
    ++        for (TriggerSensor s : mSensors) {
    ++            s.setListening(listen);
    ++        }
    +         listenForBroadcasts(listen);
    +         listenForNotifications(listen);
    +     }
    + 
    ++    private void reregisterAllSensors() {
    ++        for (TriggerSensor s : mSensors) {
    ++            s.setListening(false);
    ++        }
    ++        for (TriggerSensor s : mSensors) {
    ++            s.setListening(true);
    ++        }
    ++    }
    ++
    +     private void listenForBroadcasts(boolean listen) {
    +         if (listen) {
    +             final IntentFilter filter = new IntentFilter(PULSE_ACTION);
    +             filter.addAction(UiModeManager.ACTION_ENTER_CAR_MODE);
    ++            filter.addAction(Intent.ACTION_USER_SWITCHED);
    +             mContext.registerReceiver(mBroadcastReceiver, filter);
    ++
    ++            for (TriggerSensor s : mSensors) {
    ++                if (s.mConfigured && !TextUtils.isEmpty(s.mSetting)) {
    ++                    mContext.getContentResolver().registerContentObserver(
    ++                            Settings.Secure.getUriFor(s.mSetting), false /* descendants */,
    ++                            mSettingsObserver, UserHandle.USER_ALL);
    ++                }
    ++            }
    +             mBroadcastReceiverRegistered = true;
    +         } else {
    +             if (mBroadcastReceiverRegistered) {
    +                 mContext.unregisterReceiver(mBroadcastReceiver);
    ++                mContext.getContentResolver().unregisterContentObserver(mSettingsObserver);
    +             }
    +             mBroadcastReceiverRegistered = false;
    +         }
    +@@ -313,7 +363,7 @@ public class DozeService extends DreamService {
    + 
    +     private void requestNotificationPulse() {
    +         if (DEBUG) Log.d(mTag, "requestNotificationPulse");
    +-        if (!mDozeParameters.getPulseOnNotifications()) return;
    ++        if (!mConfig.pulseOnNotificationEnabled(UserHandle.USER_CURRENT)) return;
    +         mNotificationPulseTime = SystemClock.elapsedRealtime();
    +         requestPulse(DozeLog.PULSE_REASON_NOTIFICATION);
    +     }
    +@@ -344,6 +394,23 @@ public class DozeService extends DreamService {
    +                     finishForCarMode();
    +                 }
    +             }
    ++            if (Intent.ACTION_USER_SWITCHED.equals(intent.getAction())) {
    ++                for (TriggerSensor s : mSensors) {
    ++                    s.updateListener();
    ++                }
    ++            }
    ++        }
    ++    };
    ++
    ++    private final ContentObserver mSettingsObserver = new ContentObserver(mHandler) {
    ++        @Override
    ++        public void onChange(boolean selfChange, Uri uri, int userId) {
    ++            if (userId != ActivityManager.getCurrentUser()) {
    ++                return;
    ++            }
    ++            for (TriggerSensor s : mSensors) {
    ++                s.updateListener();
    ++            }
    +         }
    +     };
    + 
    +@@ -375,18 +442,34 @@ public class DozeService extends DreamService {
    +         }
    +     };
    + 
    ++    private Sensor findSensorWithType(String type) {
    ++        if (TextUtils.isEmpty(type)) {
    ++            return null;
    ++        }
    ++        List<Sensor> sensorList = mSensorManager.getSensorList(Sensor.TYPE_ALL);
    ++        for (Sensor s : sensorList) {
    ++            if (type.equals(s.getStringType())) {
    ++                return s;
    ++            }
    ++        }
    ++        return null;
    ++    }
    ++
    +     private class TriggerSensor extends TriggerEventListener {
    +-        private final Sensor mSensor;
    +-        private final boolean mConfigured;
    +-        private final boolean mDebugVibrate;
    +-        private final int mPulseReason;
    ++        final Sensor mSensor;
    ++        final boolean mConfigured;
    ++        final boolean mDebugVibrate;
    ++        final int mPulseReason;
    ++        final String mSetting;
    + 
    +         private boolean mRequested;
    +         private boolean mRegistered;
    +         private boolean mDisabled;
    + 
    +-        public TriggerSensor(int type, boolean configured, boolean debugVibrate, int pulseReason) {
    +-            mSensor = mSensors.getDefaultSensor(type);
    ++        public TriggerSensor(Sensor sensor, String setting, boolean configured,
    ++                boolean debugVibrate, int pulseReason) {
    ++            mSensor = sensor;
    ++            mSetting = setting;
    +             mConfigured = configured;
    +             mDebugVibrate = debugVibrate;
    +             mPulseReason = pulseReason;
    +@@ -404,18 +487,26 @@ public class DozeService extends DreamService {
    +             updateListener();
    +         }
    + 
    +-        private void updateListener() {
    ++        public void updateListener() {
    +             if (!mConfigured || mSensor == null) return;
    +-            if (mRequested && !mDisabled && !mRegistered) {
    +-                mRegistered = mSensors.requestTriggerSensor(this, mSensor);
    ++            if (mRequested && !mDisabled && enabledBySetting() && !mRegistered) {
    ++                mRegistered = mSensorManager.requestTriggerSensor(this, mSensor);
    +                 if (DEBUG) Log.d(mTag, "requestTriggerSensor " + mRegistered);
    +             } else if (mRegistered) {
    +-                final boolean rt = mSensors.cancelTriggerSensor(this, mSensor);
    ++                final boolean rt = mSensorManager.cancelTriggerSensor(this, mSensor);
    +                 if (DEBUG) Log.d(mTag, "cancelTriggerSensor " + rt);
    +                 mRegistered = false;
    +             }
    +         }
    + 
    ++        private boolean enabledBySetting() {
    ++            if (TextUtils.isEmpty(mSetting)) {
    ++                return true;
    ++            }
    ++            return Settings.Secure.getIntForUser(mContext.getContentResolver(), mSetting, 1,
    ++                    UserHandle.USER_CURRENT) != 0;
    ++        }
    ++
    +         @Override
    +         public String toString() {
    +             return new StringBuilder("{mRegistered=").append(mRegistered)
    +@@ -484,7 +575,7 @@ public class DozeService extends DreamService {
    + 
    +         public void check() {
    +             if (mFinished || mRegistered) return;
    +-            final Sensor sensor = mSensors.getDefaultSensor(Sensor.TYPE_PROXIMITY);
    ++            final Sensor sensor = mSensorManager.getDefaultSensor(Sensor.TYPE_PROXIMITY);
    +             if (sensor == null) {
    +                 if (DEBUG) Log.d(mTag, "No sensor found");
    +                 finishWithResult(RESULT_UNKNOWN);
    +@@ -494,7 +585,8 @@ public class DozeService extends DreamService {
    +             mPickupSensor.setDisabled(true);
    + 
    +             mMaxRange = sensor.getMaximumRange();
    +-            mSensors.registerListener(this, sensor, SensorManager.SENSOR_DELAY_NORMAL, 0, mHandler);
    ++            mSensorManager.registerListener(this, sensor, SensorManager.SENSOR_DELAY_NORMAL, 0,
    ++                    mHandler);
    +             mHandler.postDelayed(this, TIMEOUT_DELAY_MS);
    +             mRegistered = true;
    +         }
    +@@ -521,7 +613,7 @@ public class DozeService extends DreamService {
    +             if (mFinished) return;
    +             if (mRegistered) {
    +                 mHandler.removeCallbacks(this);
    +-                mSensors.unregisterListener(this);
    ++                mSensorManager.unregisterListener(this);
    +                 // we're done - reenable the pickup sensor
    +                 mPickupSensor.setDisabled(false);
    +                 mRegistered = false;
    +diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardService.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardService.java
    +index 84901ee..b393cf7 100644
    +--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardService.java
    ++++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardService.java
    +@@ -90,10 +90,10 @@ public class KeyguardService extends Service {
    +         }
    + 
    +         @Override // Binder interface
    +-        public void setOccluded(boolean isOccluded) {
    ++        public void setOccluded(boolean isOccluded, boolean animate) {
    +             Trace.beginSection("KeyguardService.mBinder#setOccluded");
    +             checkPermission();
    +-            mKeyguardViewMediator.setOccluded(isOccluded);
    ++            mKeyguardViewMediator.setOccluded(isOccluded, animate);
    +             Trace.endSection();
    +         }
    + 
    +diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
    +index de0c77b..6103355 100644
    +--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
    ++++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
    +@@ -964,6 +964,7 @@ public class KeyguardViewMediator extends SystemUI {
    +      * if there is a secure lock pattern.
    +      */
    +     public void onDreamingStarted() {
    ++        KeyguardUpdateMonitor.getInstance(mContext).dispatchDreamingStarted();
    +         synchronized (this) {
    +             if (mDeviceInteractive
    +                     && mLockPatternUtils.isSecure(KeyguardUpdateMonitor.getCurrentUser())) {
    +@@ -976,6 +977,7 @@ public class KeyguardViewMediator extends SystemUI {
    +      * A dream stopped.
    +      */
    +     public void onDreamingStopped() {
    ++        KeyguardUpdateMonitor.getInstance(mContext).dispatchDreamingStopped();
    +         synchronized (this) {
    +             if (mDeviceInteractive) {
    +                 cancelDoKeyguardLaterLocked();
    +@@ -1114,11 +1116,11 @@ public class KeyguardViewMediator extends SystemUI {
    +     /**
    +      * Notify us when the keyguard is occluded by another window
    +      */
    +-    public void setOccluded(boolean isOccluded) {
    ++    public void setOccluded(boolean isOccluded, boolean animate) {
    +         Trace.beginSection("KeyguardViewMediator#setOccluded");
    +         if (DEBUG) Log.d(TAG, "setOccluded " + isOccluded);
    +         mHandler.removeMessages(SET_OCCLUDED);
    +-        Message msg = mHandler.obtainMessage(SET_OCCLUDED, (isOccluded ? 1 : 0), 0);
    ++        Message msg = mHandler.obtainMessage(SET_OCCLUDED, isOccluded ? 1 : 0, animate ? 1 : 0);
    +         mHandler.sendMessage(msg);
    +         Trace.endSection();
    +     }
    +@@ -1126,7 +1128,7 @@ public class KeyguardViewMediator extends SystemUI {
    +     /**
    +      * Handles SET_OCCLUDED message sent by setOccluded()
    +      */
    +-    private void handleSetOccluded(boolean isOccluded) {
    ++    private void handleSetOccluded(boolean isOccluded, boolean animate) {
    +         Trace.beginSection("KeyguardViewMediator#handleSetOccluded");
    +         synchronized (KeyguardViewMediator.this) {
    +             if (mHiding && isOccluded) {
    +@@ -1137,7 +1139,7 @@ public class KeyguardViewMediator extends SystemUI {
    + 
    +             if (mOccluded != isOccluded) {
    +                 mOccluded = isOccluded;
    +-                mStatusBarKeyguardViewManager.setOccluded(isOccluded);
    ++                mStatusBarKeyguardViewManager.setOccluded(isOccluded, animate);
    +                 updateActivityLockScreenState();
    +                 adjustStatusBarLocked();
    +             }
    +@@ -1468,7 +1470,7 @@ public class KeyguardViewMediator extends SystemUI {
    +                     break;
    +                 case SET_OCCLUDED:
    +                     Trace.beginSection("KeyguardViewMediator#handleMessage SET_OCCLUDED");
    +-                    handleSetOccluded(msg.arg1 != 0);
    ++                    handleSetOccluded(msg.arg1 != 0, msg.arg2 != 0);
    +                     Trace.endSection();
    +                     break;
    +                 case KEYGUARD_TIMEOUT:
    +diff --git a/packages/SystemUI/src/com/android/systemui/qs/PagedTileLayout.java b/packages/SystemUI/src/com/android/systemui/qs/PagedTileLayout.java
    +index afedbe3..1c242e9 100644
    +--- a/packages/SystemUI/src/com/android/systemui/qs/PagedTileLayout.java
    ++++ b/packages/SystemUI/src/com/android/systemui/qs/PagedTileLayout.java
    +@@ -88,9 +88,9 @@ public class PagedTileLayout extends ViewPager implements QSTileLayout {
    +         if (mListening == listening) return;
    +         mListening = listening;
    +         if (mListening) {
    +-            mPages.get(mPosition).setListening(listening);
    ++            setPageListening(mPosition, true);
    +             if (mOffPage) {
    +-                mPages.get(mPosition + 1).setListening(listening);
    ++                setPageListening(mPosition + 1, true);
    +             }
    +         } else {
    +             // Make sure no pages are listening.
    +@@ -131,6 +131,9 @@ public class PagedTileLayout extends ViewPager implements QSTileLayout {
    + 
    +     private void setPageListening(int position, boolean listening) {
    +         if (position >= mPages.size()) return;
    ++        if (isLayoutRtl()) {
    ++            position = mPages.size() - 1 - position;
    ++        }
    +         mPages.get(position).setListening(listening);
    +     }
    + 
    +diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSAnimator.java b/packages/SystemUI/src/com/android/systemui/qs/QSAnimator.java
    +index a21408d..5c8a6e2 100644
    +--- a/packages/SystemUI/src/com/android/systemui/qs/QSAnimator.java
    ++++ b/packages/SystemUI/src/com/android/systemui/qs/QSAnimator.java
    +@@ -160,6 +160,10 @@ public class QSAnimator implements Callback, PageListener, Listener, OnLayoutCha
    + 
    +         for (QSTile<?> tile : tiles) {
    +             QSTileBaseView tileView = mQsPanel.getTileView(tile);
    ++            if (tileView == null) {
    ++                Log.e(TAG, "tileView is null " + tile.getTileSpec());
    ++                continue;
    ++            }
    +             final TextView label = ((QSTileView) tileView).getLabel();
    +             final View tileIcon = tileView.getIcon().getIconView();
    +             if (count < mNumQuickTiles && mAllowFancy) {
    +diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSContainer.java b/packages/SystemUI/src/com/android/systemui/qs/QSContainer.java
    +index 19a5d52..2b28fe6 100644
    +--- a/packages/SystemUI/src/com/android/systemui/qs/QSContainer.java
    ++++ b/packages/SystemUI/src/com/android/systemui/qs/QSContainer.java
    +@@ -320,4 +320,9 @@ public class QSContainer extends FrameLayout {
    +     public int getQsMinExpansionHeight() {
    +         return mHeader.getHeight();
    +     }
    ++
    ++    public void hideImmediately() {
    ++        animate().cancel();
    ++        setY(-mHeader.getHeight());
    ++    }
    + }
    +diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSFooter.java b/packages/SystemUI/src/com/android/systemui/qs/QSFooter.java
    +index 15ae4ad..ccb28e9 100644
    +--- a/packages/SystemUI/src/com/android/systemui/qs/QSFooter.java
    ++++ b/packages/SystemUI/src/com/android/systemui/qs/QSFooter.java
    +@@ -120,11 +120,10 @@ public class QSFooter implements OnClickListener, DialogInterface.OnClickListene
    +             mFooterTextId = R.string.device_owned_footer;
    +             mIsVisible = true;
    +         } else {
    +-            mFooterTextId = R.string.vpn_footer;
    ++            boolean isBranded = mSecurityController.isVpnBranded();
    ++            mFooterTextId = isBranded ? R.string.branded_vpn_footer : R.string.vpn_footer;
    +             // Update the VPN footer icon, if needed.
    +-            int footerIconId = (mSecurityController.isVpnBranded()
    +-                ? R.drawable.ic_qs_branded_vpn
    +-                : R.drawable.ic_qs_vpn);
    ++            int footerIconId = isBranded ? R.drawable.ic_qs_branded_vpn : R.drawable.ic_qs_vpn;
    +             if (mFooterIconId != footerIconId) {
    +                 mFooterIconId = footerIconId;
    +                 mMainHandler.post(mUpdateIcon);
    +@@ -148,11 +147,15 @@ public class QSFooter implements OnClickListener, DialogInterface.OnClickListene
    +         String primaryVpn = mSecurityController.getPrimaryVpnName();
    +         String profileVpn = mSecurityController.getProfileVpnName();
    +         boolean managed = mSecurityController.hasProfileOwner();
    ++        boolean isBranded = deviceOwner == null && mSecurityController.isVpnBranded();
    + 
    +         mDialog = new SystemUIDialog(mContext);
    +-        mDialog.setTitle(getTitle(deviceOwner));
    +-        mDialog.setMessage(getMessage(deviceOwner, profileOwner, primaryVpn, profileVpn, managed));
    +-        mDialog.setButton(DialogInterface.BUTTON_POSITIVE, getPositiveButton(), this);
    ++        if (!isBranded) {
    ++            mDialog.setTitle(getTitle(deviceOwner));
    ++        }
    ++        mDialog.setMessage(getMessage(deviceOwner, profileOwner, primaryVpn, profileVpn, managed,
    ++                isBranded));
    ++        mDialog.setButton(DialogInterface.BUTTON_POSITIVE, getPositiveButton(isBranded), this);
    +         if (mSecurityController.isVpnEnabled() && !mSecurityController.isVpnRestricted()) {
    +             mDialog.setButton(DialogInterface.BUTTON_NEGATIVE, getSettingsButton(), this);
    +         }
    +@@ -163,12 +166,12 @@ public class QSFooter implements OnClickListener, DialogInterface.OnClickListene
    +         return mContext.getString(R.string.status_bar_settings_settings_button);
    +     }
    + 
    +-    private String getPositiveButton() {
    +-        return mContext.getString(R.string.quick_settings_done);
    ++    private String getPositiveButton(boolean isBranded) {
    ++        return mContext.getString(isBranded ? android.R.string.ok : R.string.quick_settings_done);
    +     }
    + 
    +     private String getMessage(String deviceOwner, String profileOwner, String primaryVpn,
    +-            String profileVpn, boolean primaryUserIsManaged) {
    ++            String profileVpn, boolean primaryUserIsManaged, boolean isBranded) {
    +         // Show a special warning when the device has device owner, but --
    +         // TODO See b/25779452 -- device owner doesn't actually have monitoring power.
    +         if (deviceOwner != null) {
    +@@ -184,8 +187,13 @@ public class QSFooter implements OnClickListener, DialogInterface.OnClickListene
    +                 return mContext.getString(R.string.monitoring_description_app_personal_work,
    +                         profileOwner, profileVpn, primaryVpn);
    +             } else {
    +-                return mContext.getString(R.string.monitoring_description_app_personal,
    +-                        primaryVpn);
    ++                if (isBranded) {
    ++                    return mContext.getString(R.string.branded_monitoring_description_app_personal,
    ++                            primaryVpn);
    ++                } else {
    ++                    return mContext.getString(R.string.monitoring_description_app_personal,
    ++                            primaryVpn);
    ++                }
    +             }
    +         } else if (profileVpn != null) {
    +             return mContext.getString(R.string.monitoring_description_app_work,
    +diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/DataUsageDetailView.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/DataUsageDetailView.java
    +index a63eabc..c7b6aea 100644
    +--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/DataUsageDetailView.java
    ++++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/DataUsageDetailView.java
    +@@ -115,6 +115,12 @@ public class DataUsageDetailView extends LinearLayout {
    +         final TextView infoBottom = (TextView) findViewById(R.id.usage_info_bottom_text);
    +         infoBottom.setVisibility(bottom != null ? View.VISIBLE : View.GONE);
    +         infoBottom.setText(bottom);
    ++        boolean showLevel = info.warningLevel > 0 || info.limitLevel > 0;
    ++        graph.setVisibility(showLevel ? View.VISIBLE : View.GONE);
    ++        if (!showLevel) {
    ++            infoTop.setVisibility(View.GONE);
    ++        }
    ++
    +     }
    + 
    +     private String formatBytes(long bytes) {
    +diff --git a/packages/SystemUI/src/com/android/systemui/recents/IRecentsNonSystemUserCallbacks.aidl b/packages/SystemUI/src/com/android/systemui/recents/IRecentsNonSystemUserCallbacks.aidl
    +index 9403664..9214eef 100644
    +--- a/packages/SystemUI/src/com/android/systemui/recents/IRecentsNonSystemUserCallbacks.aidl
    ++++ b/packages/SystemUI/src/com/android/systemui/recents/IRecentsNonSystemUserCallbacks.aidl
    +@@ -35,4 +35,5 @@ oneway interface IRecentsNonSystemUserCallbacks {
    +             in Rect initialBounds);
    +     void onDraggingInRecents(float distanceFromTop);
    +     void onDraggingInRecentsEnded(float velocity);
    ++    void showCurrentUserToast(int msgResId, int msgLength);
    + }
    +diff --git a/packages/SystemUI/src/com/android/systemui/recents/Recents.java b/packages/SystemUI/src/com/android/systemui/recents/Recents.java
    +index e117bfe..5b25f05 100644
    +--- a/packages/SystemUI/src/com/android/systemui/recents/Recents.java
    ++++ b/packages/SystemUI/src/com/android/systemui/recents/Recents.java
    +@@ -53,6 +53,7 @@ import com.android.systemui.recents.events.activity.DockedTopTaskEvent;
    + import com.android.systemui.recents.events.activity.RecentsActivityStartingEvent;
    + import com.android.systemui.recents.events.component.RecentsVisibilityChangedEvent;
    + import com.android.systemui.recents.events.component.ScreenPinningRequestEvent;
    ++import com.android.systemui.recents.events.component.ShowUserToastEvent;
    + import com.android.systemui.recents.events.ui.RecentsDrawnEvent;
    + import com.android.systemui.recents.misc.SystemServicesProxy;
    + import com.android.systemui.recents.model.RecentsTaskLoader;
    +@@ -455,8 +456,8 @@ public class Recents extends SystemUI
    +                 mDraggingInRecentsCurrentUser = currentUser;
    +                 return true;
    +             } else {
    +-                Toast.makeText(mContext, R.string.recents_incompatible_app_message,
    +-                        Toast.LENGTH_SHORT).show();
    ++                EventBus.getDefault().send(new ShowUserToastEvent(
    ++                        R.string.recents_incompatible_app_message, Toast.LENGTH_SHORT));
    +                 return false;
    +             }
    +         } else {
    +@@ -674,6 +675,27 @@ public class Recents extends SystemUI
    +         mImpl.onConfigurationChanged();
    +     }
    + 
    ++    public final void onBusEvent(ShowUserToastEvent event) {
    ++        int currentUser = sSystemServicesProxy.getCurrentUser();
    ++        if (sSystemServicesProxy.isSystemUser(currentUser)) {
    ++            mImpl.onShowCurrentUserToast(event.msgResId, event.msgLength);
    ++        } else {
    ++            if (mSystemToUserCallbacks != null) {
    ++                IRecentsNonSystemUserCallbacks callbacks =
    ++                        mSystemToUserCallbacks.getNonSystemUserRecentsForUser(currentUser);
    ++                if (callbacks != null) {
    ++                    try {
    ++                        callbacks.showCurrentUserToast(event.msgResId, event.msgLength);
    ++                    } catch (RemoteException e) {
    ++                        Log.e(TAG, "Callback failed", e);
    ++                    }
    ++                } else {
    ++                    Log.e(TAG, "No SystemUI callbacks found for user: " + currentUser);
    ++                }
    ++            }
    ++        }
    ++    }
    ++
    +     /**
    +      * Attempts to register with the system user.
    +      */
    +diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java
    +index 7bdb1c4..70642ed 100644
    +--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java
    ++++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java
    +@@ -17,6 +17,7 @@
    + package com.android.systemui.recents;
    + 
    + import android.app.Activity;
    ++import android.app.ActivityManager;
    + import android.app.ActivityOptions;
    + import android.app.TaskStackBuilder;
    + import android.content.BroadcastReceiver;
    +@@ -87,6 +88,7 @@ import com.android.systemui.statusbar.BaseStatusBar;
    + 
    + import java.io.FileDescriptor;
    + import java.io.PrintWriter;
    ++import java.util.List;
    + 
    + /**
    +  * The main Recents activity that is started from RecentsComponent.
    +@@ -165,18 +167,39 @@ public class RecentsActivity extends Activity implements ViewTreeObserver.OnPreD
    +      */
    +     final BroadcastReceiver mSystemBroadcastReceiver = new BroadcastReceiver() {
    +         @Override
    +-        public void onReceive(Context context, Intent intent) {
    ++        public void onReceive(Context ctx, Intent intent) {
    +             String action = intent.getAction();
    +             if (action.equals(Intent.ACTION_SCREEN_OFF)) {
    +                 // When the screen turns off, dismiss Recents to Home
    +                 dismissRecentsToHomeIfVisible(false);
    +             } else if (action.equals(Intent.ACTION_TIME_CHANGED)) {
    +-                // For the time being, if the time changes, then invalidate the
    +-                // last-stack-active-time, this ensures that we will just show the last N tasks
    +-                // the next time that Recents loads, but prevents really old tasks from showing
    +-                // up if the task time is set forward.
    +-                Prefs.putLong(RecentsActivity.this, Prefs.Key.OVERVIEW_LAST_STACK_TASK_ACTIVE_TIME,
    +-                        0);
    ++                // If the time shifts but the currentTime >= lastStackActiveTime, then that boundary
    ++                // is still valid.  Otherwise, we need to reset the lastStackactiveTime to the
    ++                // currentTime and remove the old tasks in between which would not be previously
    ++                // visible, but currently would be in the new currentTime
    ++                long oldLastStackActiveTime = Prefs.getLong(RecentsActivity.this,
    ++                        Prefs.Key.OVERVIEW_LAST_STACK_TASK_ACTIVE_TIME, -1);
    ++                if (oldLastStackActiveTime != -1) {
    ++                    long currentTime = System.currentTimeMillis();
    ++                    if (currentTime < oldLastStackActiveTime) {
    ++                        // We are only removing tasks that are between the new current time
    ++                        // and the old last stack active time, they were not visible and in the
    ++                        // TaskStack so we don't need to remove any associated TaskViews but we do
    ++                        // need to load the task id's from the system
    ++                        RecentsTaskLoadPlan loadPlan = Recents.getTaskLoader().createLoadPlan(ctx);
    ++                        loadPlan.preloadRawTasks(false /* includeFrontMostExcludedTask */);
    ++                        List<ActivityManager.RecentTaskInfo> tasks = loadPlan.getRawTasks();
    ++                        for (int i = tasks.size() - 1; i >= 0; i--) {
    ++                            ActivityManager.RecentTaskInfo task = tasks.get(i);
    ++                            if (currentTime <= task.lastActiveTime && task.lastActiveTime <
    ++                                    oldLastStackActiveTime) {
    ++                                Recents.getSystemServices().removeTask(task.persistentId);
    ++                            }
    ++                        }
    ++                        Prefs.putLong(RecentsActivity.this,
    ++                                Prefs.Key.OVERVIEW_LAST_STACK_TASK_ACTIVE_TIME, currentTime);
    ++                    }
    ++                }
    +             }
    +         }
    +     };
    +diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java
    +index 2757fc4..42d1b61 100644
    +--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java
    ++++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java
    +@@ -40,6 +40,7 @@ import android.view.LayoutInflater;
    + import android.view.ViewConfiguration;
    + import android.view.WindowManager;
    + 
    ++import android.widget.Toast;
    + import com.android.internal.logging.MetricsLogger;
    + import com.android.internal.policy.DockedDividerUtils;
    + import com.android.systemui.R;
    +@@ -200,9 +201,17 @@ public class RecentsImpl implements ActivityOptions.OnAnimationFinishedListener
    +     }
    + 
    +     public void onConfigurationChanged() {
    ++        Resources res = mContext.getResources();
    +         reloadResources();
    +         mDummyStackView.reloadOnConfigurationChange();
    ++        // Update the header bar direction directly as it is not attached to anything and does not
    ++        // layout except in updateHeaderBarLayout()
    ++        mHeaderBar.setLayoutDirection(res.getConfiguration().getLayoutDirection());
    +         mHeaderBar.onConfigurationChanged();
    ++        mHeaderBar.forceLayout();
    ++        mHeaderBar.measure(
    ++                MeasureSpec.makeMeasureSpec(mHeaderBar.getMeasuredWidth(), MeasureSpec.EXACTLY),
    ++                MeasureSpec.makeMeasureSpec(mHeaderBar.getMeasuredHeight(), MeasureSpec.EXACTLY));
    +     }
    + 
    +     /**
    +@@ -211,11 +220,7 @@ public class RecentsImpl implements ActivityOptions.OnAnimationFinishedListener
    +      * {@link Recents#onBusEvent(RecentsVisibilityChangedEvent)}.
    +      */
    +     public void onVisibilityChanged(Context context, boolean visible) {
    +-        SystemUIApplication app = (SystemUIApplication) context;
    +-        PhoneStatusBar statusBar = app.getComponent(PhoneStatusBar.class);
    +-        if (statusBar != null) {
    +-            statusBar.updateRecentsVisibility(visible);
    +-        }
    ++        Recents.getSystemServices().setRecentsVisibility(visible);
    +     }
    + 
    +     /**
    +@@ -392,6 +397,10 @@ public class RecentsImpl implements ActivityOptions.OnAnimationFinishedListener
    +         EventBus.getDefault().sendOntoMainThread(new DraggingInRecentsEndedEvent(velocity));
    +     }
    + 
    ++    public void onShowCurrentUserToast(int msgResId, int msgLength) {
    ++        Toast.makeText(mContext, msgResId, msgLength).show();
    ++    }
    ++
    +     /**
    +      * Transitions to the next recent task in the stack.
    +      */
    +@@ -621,6 +630,7 @@ public class RecentsImpl implements ActivityOptions.OnAnimationFinishedListener
    +                 synchronized (mHeaderBarLock) {
    +                     if (mHeaderBar.getMeasuredWidth() != taskViewWidth ||
    +                             mHeaderBar.getMeasuredHeight() != mTaskBarHeight) {
    ++                        mHeaderBar.forceLayout();
    +                         mHeaderBar.measure(
    +                                 MeasureSpec.makeMeasureSpec(taskViewWidth, MeasureSpec.EXACTLY),
    +                                 MeasureSpec.makeMeasureSpec(mTaskBarHeight, MeasureSpec.EXACTLY));
    +diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsImplProxy.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsImplProxy.java
    +index 60bf760..ff9e89e 100644
    +--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsImplProxy.java
    ++++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsImplProxy.java
    +@@ -38,6 +38,7 @@ public class RecentsImplProxy extends IRecentsNonSystemUserCallbacks.Stub {
    +     private static final int MSG_DOCK_TOP_TASK = 7;
    +     private static final int MSG_ON_DRAGGING_IN_RECENTS = 8;
    +     private static final int MSG_ON_DRAGGING_IN_RECENTS_ENDED = 9;
    ++    private static final int MSG_SHOW_USER_TOAST = 10;
    + 
    +     private RecentsImpl mImpl;
    + 
    +@@ -109,6 +110,11 @@ public class RecentsImplProxy extends IRecentsNonSystemUserCallbacks.Stub {
    +         mHandler.sendMessage(mHandler.obtainMessage(MSG_ON_DRAGGING_IN_RECENTS_ENDED, velocity));
    +     }
    + 
    ++    @Override
    ++    public void showCurrentUserToast(int msgResId, int msgLength) {
    ++        mHandler.sendMessage(mHandler.obtainMessage(MSG_SHOW_USER_TOAST, msgResId, msgLength));
    ++    }
    ++
    +     private final Handler mHandler = new Handler() {
    + 
    +         @Override
    +@@ -147,6 +153,9 @@ public class RecentsImplProxy extends IRecentsNonSystemUserCallbacks.Stub {
    +                 case MSG_ON_DRAGGING_IN_RECENTS_ENDED:
    +                     mImpl.onDraggingInRecentsEnded((Float) msg.obj);
    +                     break;
    ++                case MSG_SHOW_USER_TOAST:
    ++                    mImpl.onShowCurrentUserToast(msg.arg1, msg.arg2);
    ++                    break;
    +                 default:
    +                     super.handleMessage(msg);
    +             }
    +diff --git a/packages/SystemUI/src/com/android/systemui/recents/events/component/ShowUserToastEvent.java b/packages/SystemUI/src/com/android/systemui/recents/events/component/ShowUserToastEvent.java
    +new file mode 100644
    +index 0000000..e2b39c3
    +--- /dev/null
    ++++ b/packages/SystemUI/src/com/android/systemui/recents/events/component/ShowUserToastEvent.java
    +@@ -0,0 +1,33 @@
    ++/*
    ++ * Copyright (C) 2016 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 com.android.systemui.recents.events.component;
    ++
    ++import com.android.systemui.recents.events.EventBus;
    ++
    ++/**
    ++ * This is sent when we want to show a toast for the current user.
    ++ */
    ++public class ShowUserToastEvent extends EventBus.Event {
    ++
    ++    public final int msgResId;
    ++    public final int msgLength;
    ++
    ++    public ShowUserToastEvent(int msgResId, int msgLength) {
    ++        this.msgResId = msgResId;
    ++        this.msgLength = msgLength;
    ++    }
    ++}
    +diff --git a/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java b/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java
    +index b896f8a..930ed79 100644
    +--- a/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java
    ++++ b/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java
    +@@ -69,6 +69,7 @@ import android.util.MutableBoolean;
    + import android.view.Display;
    + import android.view.IAppTransitionAnimationSpecsFuture;
    + import android.view.IDockedStackListener;
    ++import android.view.IWindowManager;
    + import android.view.WindowManager;
    + import android.view.WindowManager.KeyboardShortcutsReceiver;
    + import android.view.WindowManagerGlobal;
    +@@ -120,6 +121,7 @@ public class SystemServicesProxy {
    +     IPackageManager mIpm;
    +     AssistUtils mAssistUtils;
    +     WindowManager mWm;
    ++    IWindowManager mIwm;
    +     UserManager mUm;
    +     Display mDisplay;
    +     String mRecentsPackage;
    +@@ -207,6 +209,7 @@ public class SystemServicesProxy {
    +         mIpm = AppGlobals.getPackageManager();
    +         mAssistUtils = new AssistUtils(context);
    +         mWm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
    ++        mIwm = WindowManagerGlobal.getWindowManagerService();
    +         mUm = UserManager.get(context);
    +         mDisplay = mWm.getDefaultDisplay();
    +         mRecentsPackage = context.getPackageName();
    +@@ -1091,6 +1094,28 @@ public class SystemServicesProxy {
    +         }
    +     }
    + 
    ++    /**
    ++     * Updates the visibility of recents.
    ++     */
    ++    public void setRecentsVisibility(boolean visible) {
    ++        try {
    ++            mIwm.setRecentsVisibility(visible);
    ++        } catch (RemoteException e) {
    ++            Log.e(TAG, "Unable to reach window manager", e);
    ++        }
    ++    }
    ++
    ++    /**
    ++     * Updates the visibility of the picture-in-picture.
    ++     */
    ++    public void setTvPipVisibility(boolean visible) {
    ++        try {
    ++            mIwm.setTvPipVisibility(visible);
    ++        } catch (RemoteException e) {
    ++            Log.e(TAG, "Unable to reach window manager", e);
    ++        }
    ++    }
    ++
    +     private final class H extends Handler {
    +         private static final int ON_TASK_STACK_CHANGED = 1;
    +         private static final int ON_ACTIVITY_PINNED = 2;
    +diff --git a/packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoadPlan.java b/packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoadPlan.java
    +index 1278b73..9b48e4d 100644
    +--- a/packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoadPlan.java
    ++++ b/packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoadPlan.java
    +@@ -248,6 +248,13 @@ public class RecentsTaskLoadPlan {
    +         return mStack;
    +     }
    + 
    ++    /**
    ++     * Returns the raw list of recent tasks.
    ++     */
    ++    public List<ActivityManager.RecentTaskInfo> getRawTasks() {
    ++        return mRawTasks;
    ++    }
    ++
    +     /** Returns whether there are any tasks in any stacks. */
    +     public boolean hasTasks() {
    +         if (mStack != null) {
    +diff --git a/packages/SystemUI/src/com/android/systemui/recents/tv/RecentsTvImpl.java b/packages/SystemUI/src/com/android/systemui/recents/tv/RecentsTvImpl.java
    +index fca8d2d..ef9de53 100644
    +--- a/packages/SystemUI/src/com/android/systemui/recents/tv/RecentsTvImpl.java
    ++++ b/packages/SystemUI/src/com/android/systemui/recents/tv/RecentsTvImpl.java
    +@@ -140,10 +140,6 @@ public class RecentsTvImpl extends RecentsImpl{
    + 
    +     @Override
    +     public void onVisibilityChanged(Context context, boolean visible) {
    +-        SystemUIApplication app = (SystemUIApplication) context;
    +-        TvStatusBar statusBar = app.getComponent(TvStatusBar.class);
    +-        if (statusBar != null) {
    +-            statusBar.updateRecentsVisibility(visible);
    +-        }
    ++        Recents.getSystemServices().setRecentsVisibility(visible);
    +     }
    + }
    +diff --git a/packages/SystemUI/src/com/android/systemui/recents/tv/animations/HomeRecentsEnterExitAnimationHolder.java b/packages/SystemUI/src/com/android/systemui/recents/tv/animations/HomeRecentsEnterExitAnimationHolder.java
    +index 9faaa4b..a673c8c 100644
    +--- a/packages/SystemUI/src/com/android/systemui/recents/tv/animations/HomeRecentsEnterExitAnimationHolder.java
    ++++ b/packages/SystemUI/src/com/android/systemui/recents/tv/animations/HomeRecentsEnterExitAnimationHolder.java
    +@@ -47,12 +47,13 @@ public class HomeRecentsEnterExitAnimationHolder {
    +     public void startEnterAnimation(boolean isPipShown) {
    +         for(int i = 0; i < mGridView.getChildCount(); i++) {
    +             TaskCardView view = (TaskCardView) mGridView.getChildAt(i);
    ++            long delay = Math.max(mDelay * i, 0);
    +             view.setTranslationX(-mTranslationX);
    +             view.animate()
    +                     .alpha(isPipShown ? mDimAlpha : 1.0f)
    +                     .translationX(0)
    +                     .setDuration(mDuration)
    +-                    .setStartDelay(mDelay * i)
    ++                    .setStartDelay(delay)
    +                     .setInterpolator(Interpolators.FAST_OUT_SLOW_IN);
    +         }
    +     }
    +@@ -60,11 +61,12 @@ public class HomeRecentsEnterExitAnimationHolder {
    +     public void startExitAnimation(DismissRecentsToHomeAnimationStarted dismissEvent) {
    +         for(int i = mGridView.getChildCount() - 1; i >= 0; i--) {
    +             TaskCardView view = (TaskCardView) mGridView.getChildAt(i);
    ++            long delay = Math.max(mDelay * (mGridView.getChildCount() - 1 - i), 0);
    +             view.animate()
    +                     .alpha(0.0f)
    +                     .translationXBy(-mTranslationX)
    +                     .setDuration(mDuration)
    +-                    .setStartDelay(mDelay * (mGridView.getChildCount() - 1 - i))
    ++                    .setStartDelay(delay)
    +                     .setInterpolator(Interpolators.FAST_OUT_SLOW_IN);
    +             if(i == 0) {
    +                 view.animate().setListener(dismissEvent.getAnimationTrigger()
    +diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackLayoutAlgorithm.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackLayoutAlgorithm.java
    +index 702b076..fce7f9d 100644
    +--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackLayoutAlgorithm.java
    ++++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackLayoutAlgorithm.java
    +@@ -1258,7 +1258,7 @@ public class TaskStackLayoutAlgorithm {
    +         String innerPrefix = prefix + "  ";
    + 
    +         writer.print(prefix); writer.print(TAG);
    +-        writer.write(" numStackTasks="); writer.write(mNumStackTasks);
    ++        writer.write(" numStackTasks="); writer.print(mNumStackTasks);
    +         writer.println();
    + 
    +         writer.print(innerPrefix);
    +diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java
    +index 24e75ac..fc580a5 100644
    +--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java
    ++++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java
    +@@ -164,6 +164,8 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal
    +     @ViewDebug.ExportedProperty(category="recents")
    +     private boolean mAwaitingFirstLayout = true;
    +     @ViewDebug.ExportedProperty(category="recents")
    ++    private boolean mLaunchNextAfterFirstMeasure = false;
    ++    @ViewDebug.ExportedProperty(category="recents")
    +     @InitialStateAction
    +     private int mInitialState = INITIAL_STATE_UPDATE_ALL;
    +     @ViewDebug.ExportedProperty(category="recents")
    +@@ -336,6 +338,7 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal
    +         // Since we always animate to the same place in (the initial state), always reset the stack
    +         // to the initial state when resuming
    +         mAwaitingFirstLayout = true;
    ++        mLaunchNextAfterFirstMeasure = false;
    +         mInitialState = INITIAL_STATE_UPDATE_ALL;
    +         requestLayout();
    +     }
    +@@ -676,13 +679,13 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal
    +         for (int i = 0; i < taskViewCount; i++) {
    +             TaskView tv = taskViews.get(i);
    +             Task task = tv.getTask();
    +-            int taskIndex = mStack.indexOfStackTask(task);
    +-            TaskViewTransform transform = mCurrentTaskTransforms.get(taskIndex);
    + 
    +             if (mIgnoreTasks.contains(task.key)) {
    +                 continue;
    +             }
    + 
    ++            int taskIndex = mStack.indexOfStackTask(task);
    ++            TaskViewTransform transform = mCurrentTaskTransforms.get(taskIndex);
    +             if (animationOverrides != null && animationOverrides.containsKey(task)) {
    +                 animation = animationOverrides.get(task);
    +             }
    +@@ -1223,6 +1226,12 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal
    +                 mInitialState = INITIAL_STATE_UPDATE_NONE;
    +             }
    +         }
    ++        // If we got the launch-next event before the first layout pass, then re-send it after the
    ++        // initial state has been updated
    ++        if (mLaunchNextAfterFirstMeasure) {
    ++            mLaunchNextAfterFirstMeasure = false;
    ++            EventBus.getDefault().post(new LaunchNextTaskRequestEvent());
    ++        }
    + 
    +         // Rebind all the views, including the ignore ones
    +         bindVisibleTaskViews(mStackScroller.getStackScroll(), false /* ignoreTaskOverrides */);
    +@@ -1665,6 +1674,11 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal
    +     }
    + 
    +     public final void onBusEvent(LaunchNextTaskRequestEvent event) {
    ++        if (mAwaitingFirstLayout) {
    ++            mLaunchNextAfterFirstMeasure = true;
    ++            return;
    ++        }
    ++
    +         int launchTaskIndex = mStack.indexOfStackTask(mStack.getLaunchTarget());
    +         if (launchTaskIndex != -1) {
    +             launchTaskIndex = Math.max(0, launchTaskIndex - 1);
    +diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewTouchHandler.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewTouchHandler.java
    +index 67a2595..d44aa84 100644
    +--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewTouchHandler.java
    ++++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewTouchHandler.java
    +@@ -634,6 +634,12 @@ class TaskStackViewTouchHandler implements SwipeHelper.Callback {
    +             }
    + 
    +             int taskIndex = mCurrentTasks.indexOf(task);
    ++            if (taskIndex == -1) {
    ++                // If a task was added to the stack view after the start of the dismiss gesture,
    ++                // just ignore it
    ++                continue;
    ++            }
    ++
    +             TaskViewTransform fromTransform = mCurrentTaskTransforms.get(taskIndex);
    +             TaskViewTransform toTransform = mFinalTaskTransforms.get(taskIndex);
    + 
    +diff --git a/packages/SystemUI/src/com/android/systemui/stackdivider/ForcedResizableInfoActivityController.java b/packages/SystemUI/src/com/android/systemui/stackdivider/ForcedResizableInfoActivityController.java
    +index 5f083d5..5920f46 100644
    +--- a/packages/SystemUI/src/com/android/systemui/stackdivider/ForcedResizableInfoActivityController.java
    ++++ b/packages/SystemUI/src/com/android/systemui/stackdivider/ForcedResizableInfoActivityController.java
    +@@ -20,12 +20,14 @@ import android.app.ActivityOptions;
    + import android.content.Context;
    + import android.content.Intent;
    + import android.os.Handler;
    ++import android.os.UserHandle;
    + import android.util.ArraySet;
    + import android.widget.Toast;
    + 
    + import com.android.systemui.R;
    + import com.android.systemui.recents.events.EventBus;
    + import com.android.systemui.recents.events.activity.AppTransitionFinishedEvent;
    ++import com.android.systemui.recents.events.component.ShowUserToastEvent;
    + import com.android.systemui.recents.misc.SystemServicesProxy;
    + import com.android.systemui.recents.misc.SystemServicesProxy.TaskStackListener;
    + import com.android.systemui.stackdivider.events.StartedDragingEvent;
    +@@ -100,9 +102,8 @@ public class ForcedResizableInfoActivityController {
    +     }
    + 
    +     private void activityDismissingDockedStack() {
    +-        Toast toast = Toast.makeText(mContext, R.string.dock_non_resizeble_failed_to_dock_text,
    +-                Toast.LENGTH_SHORT);
    +-        toast.show();
    ++        EventBus.getDefault().send(new ShowUserToastEvent(
    ++                R.string.dock_non_resizeble_failed_to_dock_text, Toast.LENGTH_SHORT));
    +     }
    + 
    +     private void showPending() {
    +@@ -112,7 +113,7 @@ public class ForcedResizableInfoActivityController {
    +             ActivityOptions options = ActivityOptions.makeBasic();
    +             options.setLaunchTaskId(mPendingTaskIds.valueAt(i));
    +             options.setTaskOverlay(true);
    +-            mContext.startActivity(intent, options.toBundle());
    ++            mContext.startActivityAsUser(intent, options.toBundle(), UserHandle.CURRENT);
    +         }
    +         mPendingTaskIds.clear();
    +     }
    +diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/ActivatableNotificationView.java b/packages/SystemUI/src/com/android/systemui/statusbar/ActivatableNotificationView.java
    +index e35ef44..bc46548 100644
    +--- a/packages/SystemUI/src/com/android/systemui/statusbar/ActivatableNotificationView.java
    ++++ b/packages/SystemUI/src/com/android/systemui/statusbar/ActivatableNotificationView.java
    +@@ -593,6 +593,9 @@ public abstract class ActivatableNotificationView extends ExpandableOutlineView
    +             public void onAnimationEnd(Animator animation) {
    +                 updateBackground();
    +                 mBackgroundAnimator = null;
    ++                if (mFadeInFromDarkAnimator == null) {
    ++                    mDimmedBackgroundFadeInAmount = -1;
    ++                }
    +             }
    +         });
    +         mBackgroundAnimator.addUpdateListener(mBackgroundVisibilityUpdater);
    +diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
    +index a1854fa..4866fca 100644
    +--- a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
    ++++ b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
    +@@ -113,8 +113,11 @@ import com.android.systemui.statusbar.stack.NotificationStackScrollLayout;
    + import com.android.systemui.statusbar.stack.StackStateAnimator;
    + 
    + import java.util.ArrayList;
    ++import java.util.Collections;
    ++import java.util.HashSet;
    + import java.util.List;
    + import java.util.Locale;
    ++import java.util.Set;
    + 
    + import static android.service.notification.NotificationListenerService.Ranking.IMPORTANCE_HIGH;
    + 
    +@@ -268,6 +271,8 @@ public abstract class BaseStatusBar extends SystemUI implements
    + 
    +     protected boolean mVrMode;
    + 
    ++    private Set<String> mNonBlockablePkgs;
    ++
    +     @Override  // NotificationData.Environment
    +     public boolean isDeviceProvisioned() {
    +         return mDeviceProvisioned;
    +@@ -824,6 +829,9 @@ public abstract class BaseStatusBar extends SystemUI implements
    +             Slog.e(TAG, "Failed to register VR mode state listener: " + e);
    +         }
    + 
    ++        mNonBlockablePkgs = new ArraySet<String>();
    ++        Collections.addAll(mNonBlockablePkgs, mContext.getResources().getStringArray(
    ++                com.android.internal.R.array.config_nonBlockableNotificationPackages));
    +     }
    + 
    +     protected void notifyUserAboutHiddenNotifications() {
    +@@ -1104,7 +1112,8 @@ public abstract class BaseStatusBar extends SystemUI implements
    +             settingsButton.setVisibility(View.GONE);
    +         }
    + 
    +-        guts.bindImportance(pmUser, sbn, mNotificationData.getImportance(sbn.getKey()));
    ++        guts.bindImportance(pmUser, sbn, mNonBlockablePkgs,
    ++                mNotificationData.getImportance(sbn.getKey()));
    + 
    +         final TextView doneButton = (TextView) guts.findViewById(R.id.done);
    +         doneButton.setText(R.string.notification_done);
    +@@ -1697,6 +1706,23 @@ public abstract class BaseStatusBar extends SystemUI implements
    +                         sbn.getPackageContext(mContext),
    +                         contentContainerPublic, mOnClickHandler);
    +             }
    ++
    ++            if (contentViewLocal != null) {
    ++                contentViewLocal.setIsRootNamespace(true);
    ++                contentContainer.setContractedChild(contentViewLocal);
    ++            }
    ++            if (bigContentViewLocal != null) {
    ++                bigContentViewLocal.setIsRootNamespace(true);
    ++                contentContainer.setExpandedChild(bigContentViewLocal);
    ++            }
    ++            if (headsUpContentViewLocal != null) {
    ++                headsUpContentViewLocal.setIsRootNamespace(true);
    ++                contentContainer.setHeadsUpChild(headsUpContentViewLocal);
    ++            }
    ++            if (publicViewLocal != null) {
    ++                publicViewLocal.setIsRootNamespace(true);
    ++                contentContainerPublic.setContractedChild(publicViewLocal);
    ++            }
    +         }
    +         catch (RuntimeException e) {
    +             final String ident = sbn.getPackageName() + "/0x" + Integer.toHexString(sbn.getId());
    +@@ -1704,23 +1730,6 @@ public abstract class BaseStatusBar extends SystemUI implements
    +             return false;
    +         }
    + 
    +-        if (contentViewLocal != null) {
    +-            contentViewLocal.setIsRootNamespace(true);
    +-            contentContainer.setContractedChild(contentViewLocal);
    +-        }
    +-        if (bigContentViewLocal != null) {
    +-            bigContentViewLocal.setIsRootNamespace(true);
    +-            contentContainer.setExpandedChild(bigContentViewLocal);
    +-        }
    +-        if (headsUpContentViewLocal != null) {
    +-            headsUpContentViewLocal.setIsRootNamespace(true);
    +-            contentContainer.setHeadsUpChild(headsUpContentViewLocal);
    +-        }
    +-        if (publicViewLocal != null) {
    +-            publicViewLocal.setIsRootNamespace(true);
    +-            contentContainerPublic.setContractedChild(publicViewLocal);
    +-        }
    +-
    +         // Extract target SDK version.
    +         try {
    +             ApplicationInfo info = pmUser.getApplicationInfo(sbn.getPackageName(), 0);
    +@@ -1944,9 +1953,18 @@ public abstract class BaseStatusBar extends SystemUI implements
    +                                             .getIdentifier();
    +                                     if (mLockPatternUtils.isSeparateProfileChallengeEnabled(userId)
    +                                             && mKeyguardManager.isDeviceLocked(userId)) {
    +-                                        if (startWorkChallengeIfNecessary(userId,
    +-                                                intent.getIntentSender(), notificationKey)) {
    +-                                            // Show work challenge, do not run pendingintent and
    ++                                        boolean canBypass = false;
    ++                                        try {
    ++                                            canBypass = ActivityManagerNative.getDefault()
    ++                                                    .canBypassWorkChallenge(intent);
    ++                                        } catch (RemoteException e) {
    ++                                        }
    ++                                        // For direct-boot aware activities, they can be shown when
    ++                                        // the device is still locked without triggering the work
    ++                                        // challenge.
    ++                                        if ((!canBypass) && startWorkChallengeIfNecessary(userId,
    ++                                                    intent.getIntentSender(), notificationKey)) {
    ++                                            // Show work challenge, do not run PendingIntent and
    +                                             // remove notification
    +                                             return;
    +                                         }
    +diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/CrossFadeHelper.java b/packages/SystemUI/src/com/android/systemui/statusbar/CrossFadeHelper.java
    +index 123dc69..e8f0925 100644
    +--- a/packages/SystemUI/src/com/android/systemui/statusbar/CrossFadeHelper.java
    ++++ b/packages/SystemUI/src/com/android/systemui/statusbar/CrossFadeHelper.java
    +@@ -48,13 +48,30 @@ public class CrossFadeHelper {
    +     }
    + 
    +     public static void fadeOut(View view, float fadeOutAmount) {
    ++        fadeOut(view, fadeOutAmount, true /* remap */);
    ++    }
    ++
    ++    /**
    ++     * Fade out a view by a given progress amount
    ++     * @param view the view to fade out
    ++     * @param fadeOutAmount how much the view is faded out. 0 means not at all and 1 means fully
    ++     *                      faded out
    ++     * @param remap whether the fade amount should be remapped to the shorter duration
    ++     * {@link #ANIMATION_DURATION_LENGTH} from the normal fade duration
    ++     * {@link StackStateAnimator#ANIMATION_DURATION_STANDARD} in order to have a faster fading.
    ++     *
    ++     * @see #fadeIn(View, float, boolean)
    ++     */
    ++    public static void fadeOut(View view, float fadeOutAmount, boolean remap) {
    +         view.animate().cancel();
    +         if (fadeOutAmount == 1.0f) {
    +             view.setVisibility(View.INVISIBLE);
    +         } else if (view.getVisibility() == View.INVISIBLE) {
    +             view.setVisibility(View.VISIBLE);
    +         }
    +-        fadeOutAmount = mapToFadeDuration(fadeOutAmount);
    ++        if (remap) {
    ++            fadeOutAmount = mapToFadeDuration(fadeOutAmount);
    ++        }
    +         float alpha = Interpolators.ALPHA_OUT.getInterpolation(1.0f - fadeOutAmount);
    +         view.setAlpha(alpha);
    +         updateLayerType(view, alpha);
    +@@ -92,11 +109,28 @@ public class CrossFadeHelper {
    +     }
    + 
    +     public static void fadeIn(View view, float fadeInAmount) {
    ++        fadeIn(view, fadeInAmount, true /* remap */);
    ++    }
    ++
    ++    /**
    ++     * Fade in a view by a given progress amount
    ++     * @param view the view to fade in
    ++     * @param fadeInAmount how much the view is faded in. 0 means not at all and 1 means fully
    ++     *                     faded in.
    ++     * @param remap whether the fade amount should be remapped to the shorter duration
    ++     * {@link #ANIMATION_DURATION_LENGTH} from the normal fade duration
    ++     * {@link StackStateAnimator#ANIMATION_DURATION_STANDARD} in order to have a faster fading.
    ++     *
    ++     * @see #fadeOut(View, float, boolean)
    ++     */
    ++    public static void fadeIn(View view, float fadeInAmount, boolean remap) {
    +         view.animate().cancel();
    +         if (view.getVisibility() == View.INVISIBLE) {
    +             view.setVisibility(View.VISIBLE);
    +         }
    +-        fadeInAmount = mapToFadeDuration(fadeInAmount);
    ++        if (remap) {
    ++            fadeInAmount = mapToFadeDuration(fadeInAmount);
    ++        }
    +         float alpha = Interpolators.ALPHA_IN.getInterpolation(fadeInAmount);
    +         view.setAlpha(alpha);
    +         updateLayerType(view, alpha);
    +diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/DismissView.java b/packages/SystemUI/src/com/android/systemui/statusbar/DismissView.java
    +index 2045ec8..1d7bede 100644
    +--- a/packages/SystemUI/src/com/android/systemui/statusbar/DismissView.java
    ++++ b/packages/SystemUI/src/com/android/systemui/statusbar/DismissView.java
    +@@ -56,6 +56,8 @@ public class DismissView extends StackScrollerDecorView {
    +     protected void onConfigurationChanged(Configuration newConfig) {
    +         super.onConfigurationChanged(newConfig);
    +         mDismissButton.setText(R.string.clear_all_notifications_text);
    ++        mDismissButton.setContentDescription(
    ++                mContext.getString(R.string.accessibility_clear_all));
    +     }
    + 
    +     public boolean isButtonVisible() {
    +diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
    +index 02fdd3f..caf5447 100644
    +--- a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
    ++++ b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
    +@@ -507,7 +507,7 @@ public class ExpandableNotificationRow extends ActivatableNotificationView {
    +         int intrinsicHeight = getIntrinsicHeight();
    +         mIsPinned = pinned;
    +         if (intrinsicHeight != getIntrinsicHeight()) {
    +-            notifyHeightChanged(false);
    ++            notifyHeightChanged(false /* needsAnimation */);
    +         }
    +         if (pinned) {
    +             setIconAnimationRunning(true);
    +@@ -840,8 +840,6 @@ public class ExpandableNotificationRow extends ActivatableNotificationView {
    +     }
    + 
    +     public void resetHeight() {
    +-        mMaxExpandHeight = 0;
    +-        mHeadsUpHeight = 0;
    +         onHeightReset();
    +         requestLayout();
    +     }
    +@@ -907,6 +905,9 @@ public class ExpandableNotificationRow extends ActivatableNotificationView {
    +     }
    + 
    +     public void resetTranslation() {
    ++        if (mTranslateAnim != null) {
    ++            mTranslateAnim.cancel();
    ++        }
    +         if (mTranslateableViews != null) {
    +             for (int i = 0; i < mTranslateableViews.size(); i++) {
    +                 mTranslateableViews.get(i).setTranslationX(0);
    +@@ -1290,7 +1291,7 @@ public class ExpandableNotificationRow extends ActivatableNotificationView {
    +         }
    +         mHeadsUpHeight = headsUpChild.getHeight();
    +         if (intrinsicBefore != getIntrinsicHeight()) {
    +-            notifyHeightChanged(false  /* needsAnimation */);
    ++            notifyHeightChanged(true  /* needsAnimation */);
    +         }
    +     }
    + 
    +@@ -1398,7 +1399,7 @@ public class ExpandableNotificationRow extends ActivatableNotificationView {
    +         if (isChildInGroup()) {
    +             mGroupManager.setGroupExpanded(mStatusBarNotification, true);
    +         }
    +-        notifyHeightChanged(false);
    ++        notifyHeightChanged(false /* needsAnimation */);
    +     }
    + 
    +     public void setChildrenExpanded(boolean expanded, boolean animate) {
    +diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardAffordanceView.java b/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardAffordanceView.java
    +index 88f37a3..8b4225a 100644
    +--- a/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardAffordanceView.java
    ++++ b/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardAffordanceView.java
    +@@ -174,7 +174,10 @@ public class KeyguardAffordanceView extends ImageView {
    + 
    +     private void drawBackgroundCircle(Canvas canvas) {
    +         if (mCircleRadius > 0 || mFinishing) {
    +-            if (mFinishing && mSupportHardware) {
    ++            if (mFinishing && mSupportHardware && mHwCenterX != null) {
    ++                // Our hardware drawing proparties can be null if the finishing started but we have
    ++                // never drawn before. In that case we are not doing a render thread animation
    ++                // anyway, so we need to use the normal drawing.
    +                 DisplayListCanvas displayListCanvas = (DisplayListCanvas) canvas;
    +                 displayListCanvas.drawCircle(mHwCenterX, mHwCenterY, mHwCircleRadius,
    +                         mHwCirclePaint);
    +diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java b/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java
    +index 6d73ccb..0ef97152 100644
    +--- a/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java
    ++++ b/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java
    +@@ -93,7 +93,7 @@ public class KeyguardIndicationController {
    +                 ServiceManager.getService(BatteryStats.SERVICE_NAME));
    + 
    +         KeyguardUpdateMonitor.getInstance(context).registerCallback(mUpdateMonitor);
    +-        context.registerReceiverAsUser(mReceiver, UserHandle.SYSTEM,
    ++        context.registerReceiverAsUser(mTickReceiver, UserHandle.SYSTEM,
    +                 new IntentFilter(Intent.ACTION_TIME_TICK), null, null);
    +     }
    + 
    +@@ -320,9 +320,16 @@ public class KeyguardIndicationController {
    +             super.onFingerprintAuthFailed();
    +             mLastSuccessiveErrorMessage = -1;
    +         }
    ++
    ++        @Override
    ++        public void onUserUnlocked() {
    ++            if (mVisible) {
    ++                updateIndication();
    ++            }
    ++        }
    +     };
    + 
    +-    BroadcastReceiver mReceiver = new BroadcastReceiver() {
    ++    BroadcastReceiver mTickReceiver = new BroadcastReceiver() {
    +         @Override
    +         public void onReceive(Context context, Intent intent) {
    +             if (mVisible) {
    +@@ -331,6 +338,7 @@ public class KeyguardIndicationController {
    +         }
    +     };
    + 
    ++
    +     private final Handler mHandler = new Handler() {
    +         @Override
    +         public void handleMessage(Message msg) {
    +diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationContentView.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationContentView.java
    +index 9fd09d9..58d57f6 100644
    +--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationContentView.java
    ++++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationContentView.java
    +@@ -116,6 +116,8 @@ public class NotificationContentView extends FrameLayout {
    +     private boolean mForceSelectNextLayout = true;
    +     private PendingIntent mPreviousExpandedRemoteInputIntent;
    +     private PendingIntent mPreviousHeadsUpRemoteInputIntent;
    ++    private RemoteInputView mCachedExpandedRemoteInput;
    ++    private RemoteInputView mCachedHeadsUpRemoteInput;
    + 
    +     private int mContentHeightAtAnimationStart = UNDEFINED;
    +     private boolean mFocusOnVisibilityChange;
    +@@ -205,7 +207,7 @@ public class NotificationContentView extends FrameLayout {
    +                     && MeasureSpec.getMode(widthMeasureSpec) != MeasureSpec.UNSPECIFIED) {
    +                 singleLineWidthSpec = MeasureSpec.makeMeasureSpec(
    +                         width - mSingleLineWidthIndention + mSingleLineView.getPaddingEnd(),
    +-                        MeasureSpec.AT_MOST);
    ++                        MeasureSpec.EXACTLY);
    +             }
    +             mSingleLineView.measure(singleLineWidthSpec,
    +                     MeasureSpec.makeMeasureSpec(maxSize, MeasureSpec.AT_MOST));
    +@@ -298,6 +300,9 @@ public class NotificationContentView extends FrameLayout {
    +             mExpandedRemoteInput.onNotificationUpdateOrReset();
    +             if (mExpandedRemoteInput.isActive()) {
    +                 mPreviousExpandedRemoteInputIntent = mExpandedRemoteInput.getPendingIntent();
    ++                mCachedExpandedRemoteInput = mExpandedRemoteInput;
    ++                mExpandedRemoteInput.dispatchStartTemporaryDetach();
    ++                ((ViewGroup)mExpandedRemoteInput.getParent()).removeView(mExpandedRemoteInput);
    +             }
    +         }
    +         if (mExpandedChild != null) {
    +@@ -310,6 +315,9 @@ public class NotificationContentView extends FrameLayout {
    +             mHeadsUpRemoteInput.onNotificationUpdateOrReset();
    +             if (mHeadsUpRemoteInput.isActive()) {
    +                 mPreviousHeadsUpRemoteInputIntent = mHeadsUpRemoteInput.getPendingIntent();
    ++                mCachedHeadsUpRemoteInput = mHeadsUpRemoteInput;
    ++                mHeadsUpRemoteInput.dispatchStartTemporaryDetach();
    ++                ((ViewGroup)mHeadsUpRemoteInput.getParent()).removeView(mHeadsUpRemoteInput);
    +             }
    +         }
    +         if (mHeadsUpChild != null) {
    +@@ -963,22 +971,35 @@ public class NotificationContentView extends FrameLayout {
    +         View bigContentView = mExpandedChild;
    +         if (bigContentView != null) {
    +             mExpandedRemoteInput = applyRemoteInput(bigContentView, entry, hasRemoteInput,
    +-                    mPreviousExpandedRemoteInputIntent);
    ++                    mPreviousExpandedRemoteInputIntent, mCachedExpandedRemoteInput);
    +         } else {
    +             mExpandedRemoteInput = null;
    +         }
    ++        if (mCachedExpandedRemoteInput != null
    ++                && mCachedExpandedRemoteInput != mExpandedRemoteInput) {
    ++            // We had a cached remote input but didn't reuse it. Clean up required.
    ++            mCachedExpandedRemoteInput.dispatchFinishTemporaryDetach();
    ++        }
    ++        mCachedExpandedRemoteInput = null;
    + 
    +         View headsUpContentView = mHeadsUpChild;
    +         if (headsUpContentView != null) {
    +             mHeadsUpRemoteInput = applyRemoteInput(headsUpContentView, entry, hasRemoteInput,
    +-                    mPreviousHeadsUpRemoteInputIntent);
    ++                    mPreviousHeadsUpRemoteInputIntent, mCachedHeadsUpRemoteInput);
    +         } else {
    +             mHeadsUpRemoteInput = null;
    +         }
    ++        if (mCachedHeadsUpRemoteInput != null
    ++                && mCachedHeadsUpRemoteInput != mHeadsUpRemoteInput) {
    ++            // We had a cached remote input but didn't reuse it. Clean up required.
    ++            mCachedHeadsUpRemoteInput.dispatchFinishTemporaryDetach();
    ++        }
    ++        mCachedHeadsUpRemoteInput = null;
    +     }
    + 
    +     private RemoteInputView applyRemoteInput(View view, NotificationData.Entry entry,
    +-            boolean hasRemoteInput, PendingIntent existingPendingIntent) {
    ++            boolean hasRemoteInput, PendingIntent existingPendingIntent,
    ++            RemoteInputView cachedView) {
    +         View actionContainerCandidate = view.findViewById(
    +                 com.android.internal.R.id.actions_container);
    +         if (actionContainerCandidate instanceof FrameLayout) {
    +@@ -991,15 +1012,22 @@ public class NotificationContentView extends FrameLayout {
    + 
    +             if (existing == null && hasRemoteInput) {
    +                 ViewGroup actionContainer = (FrameLayout) actionContainerCandidate;
    +-                RemoteInputView riv = RemoteInputView.inflate(
    +-                        mContext, actionContainer, entry, mRemoteInputController);
    +-
    +-                riv.setVisibility(View.INVISIBLE);
    +-                actionContainer.addView(riv, new LayoutParams(
    +-                        ViewGroup.LayoutParams.MATCH_PARENT,
    +-                        ViewGroup.LayoutParams.MATCH_PARENT)
    +-                );
    +-                existing = riv;
    ++                if (cachedView == null) {
    ++                    RemoteInputView riv = RemoteInputView.inflate(
    ++                            mContext, actionContainer, entry, mRemoteInputController);
    ++
    ++                    riv.setVisibility(View.INVISIBLE);
    ++                    actionContainer.addView(riv, new LayoutParams(
    ++                            ViewGroup.LayoutParams.MATCH_PARENT,
    ++                            ViewGroup.LayoutParams.MATCH_PARENT)
    ++                    );
    ++                    existing = riv;
    ++                } else {
    ++                    actionContainer.addView(cachedView);
    ++                    cachedView.dispatchFinishTemporaryDetach();
    ++                    cachedView.requestFocus();
    ++                    existing = cachedView;
    ++                }
    +             }
    +             if (hasRemoteInput) {
    +                 int color = entry.notification.getNotification().color;
    +diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationGuts.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationGuts.java
    +index c497cfd..1829e59 100644
    +--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationGuts.java
    ++++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationGuts.java
    +@@ -50,6 +50,8 @@ import com.android.systemui.R;
    + import com.android.systemui.statusbar.stack.StackStateAnimator;
    + import com.android.systemui.tuner.TunerService;
    + 
    ++import java.util.Set;
    ++
    + /**
    +  * The guts of a notification revealed when performing a long press.
    +  */
    +@@ -173,7 +175,7 @@ public class NotificationGuts extends LinearLayout implements TunerService.Tunab
    +     }
    + 
    +     void bindImportance(final PackageManager pm, final StatusBarNotification sbn,
    +-            final int importance) {
    ++            final Set<String> nonBlockablePkgs, final int importance) {
    +         mINotificationManager = INotificationManager.Stub.asInterface(
    +                 ServiceManager.getService(Context.NOTIFICATION_SERVICE));
    +         mStartingUserImportance = NotificationListenerService.Ranking.IMPORTANCE_UNSPECIFIED;
    +@@ -182,26 +184,38 @@ public class NotificationGuts extends LinearLayout implements TunerService.Tunab
    +                     mINotificationManager.getImportance(sbn.getPackageName(), sbn.getUid());
    +         } catch (RemoteException e) {}
    +         mNotificationImportance = importance;
    +-        boolean systemApp = false;
    +-        try {
    +-            final PackageInfo info =
    +-                    pm.getPackageInfo(sbn.getPackageName(), PackageManager.GET_SIGNATURES);
    +-            systemApp = Utils.isSystemPackage(getResources(), pm, info);
    +-        } catch (PackageManager.NameNotFoundException e) {
    +-            // unlikely.
    +-        }
    + 
    +         final View importanceSlider = findViewById(R.id.importance_slider);
    +         final View importanceButtons = findViewById(R.id.importance_buttons);
    +-        if (mShowSlider) {
    +-            bindSlider(importanceSlider, systemApp);
    +-            importanceSlider.setVisibility(View.VISIBLE);
    ++        final View cantTouchThis = findViewById(R.id.cant_silence_or_block);
    ++
    ++        final boolean essentialPackage =
    ++                (nonBlockablePkgs != null && nonBlockablePkgs.contains(sbn.getPackageName()));
    ++        if (essentialPackage) {
    +             importanceButtons.setVisibility(View.GONE);
    ++            importanceSlider.setVisibility(View.GONE);
    ++            cantTouchThis.setVisibility(View.VISIBLE);
    +         } else {
    ++            cantTouchThis.setVisibility(View.GONE);
    ++
    ++            boolean nonBlockable = false;
    ++            try {
    ++                final PackageInfo info =
    ++                        pm.getPackageInfo(sbn.getPackageName(), PackageManager.GET_SIGNATURES);
    ++                nonBlockable = Utils.isSystemPackage(getResources(), pm, info);
    ++            } catch (PackageManager.NameNotFoundException e) {
    ++                // unlikely.
    ++            }
    + 
    +-            bindToggles(importanceButtons, mStartingUserImportance, systemApp);
    +-            importanceButtons.setVisibility(View.VISIBLE);
    +-            importanceSlider.setVisibility(View.GONE);
    ++            if (mShowSlider) {
    ++                bindSlider(importanceSlider, nonBlockable);
    ++                importanceSlider.setVisibility(View.VISIBLE);
    ++                importanceButtons.setVisibility(View.GONE);
    ++            } else {
    ++                bindToggles(importanceButtons, mStartingUserImportance, nonBlockable);
    ++                importanceButtons.setVisibility(View.VISIBLE);
    ++                importanceSlider.setVisibility(View.GONE);
    ++            }
    +         }
    +     }
    + 
    +@@ -221,16 +235,16 @@ public class NotificationGuts extends LinearLayout implements TunerService.Tunab
    +     }
    + 
    +     private int getSelectedImportance() {
    +-        if (mSeekBar!= null && mSeekBar.isShown()) {
    ++        if (mSeekBar != null && mSeekBar.isShown()) {
    +             if (mSeekBar.isEnabled()) {
    +                 return mSeekBar.getProgress();
    +             } else {
    +                 return Ranking.IMPORTANCE_UNSPECIFIED;
    +             }
    +         } else {
    +-            if (mBlock.isChecked()) {
    ++            if (mBlock != null && mBlock.isChecked()) {
    +                 return Ranking.IMPORTANCE_NONE;
    +-            } else if (mSilent.isChecked()) {
    ++            } else if (mSilent != null && mSilent.isChecked()) {
    +                 return Ranking.IMPORTANCE_LOW;
    +             } else {
    +                 return Ranking.IMPORTANCE_UNSPECIFIED;
    +@@ -239,7 +253,7 @@ public class NotificationGuts extends LinearLayout implements TunerService.Tunab
    +     }
    + 
    +     private void bindToggles(final View importanceButtons, final int importance,
    +-            final boolean systemApp) {
    ++            final boolean nonBlockable) {
    +         ((RadioGroup) importanceButtons).setOnCheckedChangeListener(
    +                 new RadioGroup.OnCheckedChangeListener() {
    +                     @Override
    +@@ -250,7 +264,7 @@ public class NotificationGuts extends LinearLayout implements TunerService.Tunab
    +         mBlock = (RadioButton) importanceButtons.findViewById(R.id.block_importance);
    +         mSilent = (RadioButton) importanceButtons.findViewById(R.id.silent_importance);
    +         mReset = (RadioButton) importanceButtons.findViewById(R.id.reset_importance);
    +-        if (systemApp) {
    ++        if (nonBlockable) {
    +             mBlock.setVisibility(View.GONE);
    +             mReset.setText(mContext.getString(R.string.do_not_silence));
    +         } else {
    +@@ -265,7 +279,7 @@ public class NotificationGuts extends LinearLayout implements TunerService.Tunab
    +         }
    +     }
    + 
    +-    private void bindSlider(final View importanceSlider, final boolean systemApp) {
    ++    private void bindSlider(final View importanceSlider, final boolean nonBlockable) {
    +         mActiveSliderTint = ColorStateList.valueOf(Utils.getColorAccent(mContext));
    +         mInactiveSliderTint = loadColorStateList(R.color.notification_guts_disabled_slider_color);
    + 
    +@@ -273,7 +287,7 @@ public class NotificationGuts extends LinearLayout implements TunerService.Tunab
    +         mImportanceTitle = ((TextView) importanceSlider.findViewById(R.id.title));
    +         mSeekBar = (SeekBar) importanceSlider.findViewById(R.id.seekbar);
    + 
    +-        final int minProgress = systemApp ?
    ++        final int minProgress = nonBlockable ?
    +                 NotificationListenerService.Ranking.IMPORTANCE_MIN
    +                 : NotificationListenerService.Ranking.IMPORTANCE_NONE;
    +         mSeekBar.setMax(NotificationListenerService.Ranking.IMPORTANCE_MAX);
    +diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/RemoteInputController.java b/packages/SystemUI/src/com/android/systemui/statusbar/RemoteInputController.java
    +index 6cbacea..66cc15d 100644
    +--- a/packages/SystemUI/src/com/android/systemui/statusbar/RemoteInputController.java
    ++++ b/packages/SystemUI/src/com/android/systemui/statusbar/RemoteInputController.java
    +@@ -21,7 +21,9 @@ import com.android.systemui.statusbar.phone.StatusBarWindowManager;
    + import com.android.systemui.statusbar.policy.HeadsUpManager;
    + import com.android.systemui.statusbar.policy.RemoteInputView;
    + 
    ++import android.util.ArrayMap;
    + import android.util.ArraySet;
    ++import android.util.Pair;
    + 
    + import java.lang.ref.WeakReference;
    + import java.util.ArrayList;
    +@@ -31,8 +33,9 @@ import java.util.ArrayList;
    +  */
    + public class RemoteInputController {
    + 
    +-    private final ArrayList<WeakReference<NotificationData.Entry>> mOpen = new ArrayList<>();
    +-    private final ArraySet<String> mSpinning = new ArraySet<>();
    ++    private final ArrayList<Pair<WeakReference<NotificationData.Entry>, Object>> mOpen
    ++            = new ArrayList<>();
    ++    private final ArrayMap<String, Object> mSpinning = new ArrayMap<>();
    +     private final ArrayList<Callback> mCallbacks = new ArrayList<>(3);
    +     private final HeadsUpManager mHeadsUpManager;
    + 
    +@@ -41,36 +44,72 @@ public class RemoteInputController {
    +         mHeadsUpManager = headsUpManager;
    +     }
    + 
    +-    public void addRemoteInput(NotificationData.Entry entry) {
    ++    /**
    ++     * Adds a currently active remote input.
    ++     *
    ++     * @param entry the entry for which a remote input is now active.
    ++     * @param token a token identifying the view that is managing the remote input
    ++     */
    ++    public void addRemoteInput(NotificationData.Entry entry, Object token) {
    +         Preconditions.checkNotNull(entry);
    ++        Preconditions.checkNotNull(token);
    + 
    +         boolean found = pruneWeakThenRemoveAndContains(
    +-                entry /* contains */, null /* remove */);
    ++                entry /* contains */, null /* remove */, token /* removeToken */);
    +         if (!found) {
    +-            mOpen.add(new WeakReference<>(entry));
    ++            mOpen.add(new Pair<>(new WeakReference<>(entry), token));
    +         }
    + 
    +         apply(entry);
    +     }
    + 
    +-    public void removeRemoteInput(NotificationData.Entry entry) {
    ++    /**
    ++     * Removes a currently active remote input.
    ++     *
    ++     * @param entry the entry for which a remote input should be removed.
    ++     * @param token a token identifying the view that is requesting the removal. If non-null,
    ++     *              the entry is only removed if the token matches the last added token for this
    ++     *              entry. If null, the entry is removed regardless.
    ++     */
    ++    public void removeRemoteInput(NotificationData.Entry entry, Object token) {
    +         Preconditions.checkNotNull(entry);
    + 
    +-        pruneWeakThenRemoveAndContains(null /* contains */, entry /* remove */);
    ++        pruneWeakThenRemoveAndContains(null /* contains */, entry /* remove */, token);
    + 
    +         apply(entry);
    +     }
    + 
    +-    public void addSpinning(String key) {
    +-        mSpinning.add(key);
    ++    /**
    ++     * Adds a currently spinning (i.e. sending) remote input.
    ++     *
    ++     * @param key the key of the entry that's spinning.
    ++     * @param token the token of the view managing the remote input.
    ++     */
    ++    public void addSpinning(String key, Object token) {
    ++        Preconditions.checkNotNull(key);
    ++        Preconditions.checkNotNull(token);
    ++
    ++        mSpinning.put(key, token);
    +     }
    + 
    +-    public void removeSpinning(String key) {
    +-        mSpinning.remove(key);
    ++    /**
    ++     * Removes a currently spinning remote input.
    ++     *
    ++     * @param key the key of the entry for which a remote input should be removed.
    ++     * @param token a token identifying the view that is requesting the removal. If non-null,
    ++     *              the entry is only removed if the token matches the last added token for this
    ++     *              entry. If null, the entry is removed regardless.
    ++     */
    ++    public void removeSpinning(String key, Object token) {
    ++        Preconditions.checkNotNull(key);
    ++
    ++        if (token == null || mSpinning.get(key) == token) {
    ++            mSpinning.remove(key);
    ++        }
    +     }
    + 
    +     public boolean isSpinning(String key) {
    +-        return mSpinning.contains(key);
    ++        return mSpinning.containsKey(key);
    +     }
    + 
    +     private void apply(NotificationData.Entry entry) {
    +@@ -86,14 +125,16 @@ public class RemoteInputController {
    +      * @return true if {@param entry} has an active RemoteInput
    +      */
    +     public boolean isRemoteInputActive(NotificationData.Entry entry) {
    +-        return pruneWeakThenRemoveAndContains(entry /* contains */, null /* remove */);
    ++        return pruneWeakThenRemoveAndContains(entry /* contains */, null /* remove */,
    ++                null /* removeToken */);
    +     }
    + 
    +     /**
    +      * @return true if any entry has an active RemoteInput
    +      */
    +     public boolean isRemoteInputActive() {
    +-        pruneWeakThenRemoveAndContains(null /* contains */, null /* remove */);
    ++        pruneWeakThenRemoveAndContains(null /* contains */, null /* remove */,
    ++                null /* removeToken */);
    +         return !mOpen.isEmpty();
    +     }
    + 
    +@@ -101,17 +142,27 @@ public class RemoteInputController {
    +      * Prunes dangling weak references, removes entries referring to {@param remove} and returns
    +      * whether {@param contains} is part of the array in a single loop.
    +      * @param remove if non-null, removes this entry from the active remote inputs
    ++     * @param removeToken if non-null, only removes an entry if this matches the token when the
    ++     *                    entry was added.
    +      * @return true if {@param contains} is in the set of active remote inputs
    +      */
    +     private boolean pruneWeakThenRemoveAndContains(
    +-            NotificationData.Entry contains, NotificationData.Entry remove) {
    ++            NotificationData.Entry contains, NotificationData.Entry remove, Object removeToken) {
    +         boolean found = false;
    +         for (int i = mOpen.size() - 1; i >= 0; i--) {
    +-            NotificationData.Entry item = mOpen.get(i).get();
    +-            if (item == null || item == remove) {
    ++            NotificationData.Entry item = mOpen.get(i).first.get();
    ++            Object itemToken = mOpen.get(i).second;
    ++            boolean removeTokenMatches = (removeToken == null || itemToken == removeToken);
    ++
    ++            if (item == null || (item == remove && removeTokenMatches)) {
    +                 mOpen.remove(i);
    +             } else if (item == contains) {
    +-                found = true;
    ++                if (removeToken != null && removeToken != itemToken) {
    ++                    // We need to update the token. Remove here and let caller reinsert it.
    ++                    mOpen.remove(i);
    ++                } else {
    ++                    found = true;
    ++                }
    +             }
    +         }
    +         return found;
    +@@ -138,7 +189,7 @@ public class RemoteInputController {
    +         // Make a copy because closing the remote inputs will modify mOpen.
    +         ArrayList<NotificationData.Entry> list = new ArrayList<>(mOpen.size());
    +         for (int i = mOpen.size() - 1; i >= 0; i--) {
    +-            NotificationData.Entry item = mOpen.get(i).get();
    ++            NotificationData.Entry item = mOpen.get(i).first.get();
    +             if (item != null && item.row != null) {
    +                 list.add(item);
    +             }
    +diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/ViewTransformationHelper.java b/packages/SystemUI/src/com/android/systemui/statusbar/ViewTransformationHelper.java
    +index 1ff2b13..cd6c31f 100644
    +--- a/packages/SystemUI/src/com/android/systemui/statusbar/ViewTransformationHelper.java
    ++++ b/packages/SystemUI/src/com/android/systemui/statusbar/ViewTransformationHelper.java
    +@@ -116,8 +116,7 @@ public class ViewTransformationHelper implements TransformableView {
    +                     ownState.transformViewTo(otherState, transformationAmount);
    +                     otherState.recycle();
    +                 } else {
    +-                    // there's no other view available
    +-                    CrossFadeHelper.fadeOut(mTransformedViews.get(viewType), transformationAmount);
    ++                    ownState.disappear(transformationAmount, notification);
    +                 }
    +                 ownState.recycle();
    +             }
    +@@ -174,13 +173,7 @@ public class ViewTransformationHelper implements TransformableView {
    +                     ownState.transformViewFrom(otherState, transformationAmount);
    +                     otherState.recycle();
    +                 } else {
    +-                    // There's no other view, lets fade us in
    +-                    // Certain views need to prepare the fade in and make sure its children are
    +-                    // completely visible. An example is the notification header.
    +-                    if (transformationAmount == 0.0f) {
    +-                        ownState.prepareFadeIn();
    +-                    }
    +-                    CrossFadeHelper.fadeIn(mTransformedViews.get(viewType), transformationAmount);
    ++                    ownState.appear(transformationAmount, notification);
    +                 }
    +                 ownState.recycle();
    +             }
    +diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/ImageTransformState.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/ImageTransformState.java
    +index 45027c0..e6b3fb8 100644
    +--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/ImageTransformState.java
    ++++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/ImageTransformState.java
    +@@ -21,12 +21,17 @@ import android.util.Pools;
    + import android.view.View;
    + import android.widget.ImageView;
    + 
    ++import com.android.systemui.Interpolators;
    + import com.android.systemui.R;
    ++import com.android.systemui.statusbar.CrossFadeHelper;
    ++import com.android.systemui.statusbar.TransformableView;
    ++import com.android.systemui.statusbar.stack.StackStateAnimator;
    + 
    + /**
    +  * A transform state of a image view.
    + */
    + public class ImageTransformState extends TransformState {
    ++    public static final long ANIMATION_DURATION_LENGTH = 210;
    + 
    +     public static final int ICON_TAG = R.id.image_icon_tag;
    +     private static Pools.SimplePool<ImageTransformState> sInstancePool
    +@@ -49,6 +54,52 @@ public class ImageTransformState extends TransformState {
    +         return super.sameAs(otherState);
    +     }
    + 
    ++    @Override
    ++    public void appear(float transformationAmount, TransformableView otherView) {
    ++        if (otherView instanceof HybridNotificationView) {
    ++            if (transformationAmount == 0.0f) {
    ++                mTransformedView.setPivotY(0);
    ++                mTransformedView.setPivotX(mTransformedView.getWidth() / 2);
    ++                prepareFadeIn();
    ++            }
    ++            transformationAmount = mapToDuration(transformationAmount);
    ++            CrossFadeHelper.fadeIn(mTransformedView, transformationAmount, false /* remap */);
    ++            transformationAmount = Interpolators.LINEAR_OUT_SLOW_IN.getInterpolation(
    ++                    transformationAmount);
    ++            mTransformedView.setScaleX(transformationAmount);
    ++            mTransformedView.setScaleY(transformationAmount);
    ++        } else {
    ++            super.appear(transformationAmount, otherView);
    ++        }
    ++    }
    ++
    ++    @Override
    ++    public void disappear(float transformationAmount, TransformableView otherView) {
    ++        if (otherView instanceof HybridNotificationView) {
    ++            if (transformationAmount == 0.0f) {
    ++                mTransformedView.setPivotY(0);
    ++                mTransformedView.setPivotX(mTransformedView.getWidth() / 2);
    ++            }
    ++            transformationAmount = mapToDuration(1.0f - transformationAmount);
    ++            CrossFadeHelper.fadeOut(mTransformedView, 1.0f - transformationAmount,
    ++                    false /* remap */);
    ++            transformationAmount = Interpolators.LINEAR_OUT_SLOW_IN.getInterpolation(
    ++                    transformationAmount);
    ++            mTransformedView.setScaleX(transformationAmount);
    ++            mTransformedView.setScaleY(transformationAmount);
    ++        } else {
    ++            super.disappear(transformationAmount, otherView);
    ++        }
    ++    }
    ++
    ++    private static float mapToDuration(float scaleAmount) {
    ++        // Assuming a linear interpolator, we can easily map it to our new duration
    ++        scaleAmount = (scaleAmount * StackStateAnimator.ANIMATION_DURATION_STANDARD
    ++                - (StackStateAnimator.ANIMATION_DURATION_STANDARD - ANIMATION_DURATION_LENGTH))
    ++                        / ANIMATION_DURATION_LENGTH;
    ++        return Math.max(Math.min(scaleAmount, 1.0f), 0.0f);
    ++    }
    ++
    +     public Icon getIcon() {
    +         return mIcon;
    +     }
    +diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/TransformState.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/TransformState.java
    +index f0f5c8d..770ec95 100644
    +--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/TransformState.java
    ++++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/TransformState.java
    +@@ -30,6 +30,7 @@ import com.android.systemui.Interpolators;
    + import com.android.systemui.R;
    + import com.android.systemui.statusbar.CrossFadeHelper;
    + import com.android.systemui.statusbar.ExpandableNotificationRow;
    ++import com.android.systemui.statusbar.TransformableView;
    + import com.android.systemui.statusbar.ViewTransformationHelper;
    + 
    + /**
    +@@ -357,6 +358,7 @@ public class TransformState {
    + 
    +     public int[] getLaidOutLocationOnScreen() {
    +         int[] location = getLocationOnScreen();
    ++        // remove translation
    +         location[0] -= mTransformedView.getTranslationX();
    +         location[1] -= mTransformedView.getTranslationY();
    +         return location;
    +@@ -364,6 +366,10 @@ public class TransformState {
    + 
    +     public int[] getLocationOnScreen() {
    +         mTransformedView.getLocationOnScreen(mOwnPosition);
    ++
    ++        // remove scale
    ++        mOwnPosition[0] -= (1.0f - mTransformedView.getScaleX()) * mTransformedView.getPivotX();
    ++        mOwnPosition[1] -= (1.0f - mTransformedView.getScaleY()) * mTransformedView.getPivotY();
    +         return mOwnPosition;
    +     }
    + 
    +@@ -371,6 +377,20 @@ public class TransformState {
    +         return false;
    +     }
    + 
    ++    public void appear(float transformationAmount, TransformableView otherView) {
    ++        // There's no other view, lets fade us in
    ++        // Certain views need to prepare the fade in and make sure its children are
    ++        // completely visible. An example is the notification header.
    ++        if (transformationAmount == 0.0f) {
    ++            prepareFadeIn();
    ++        }
    ++        CrossFadeHelper.fadeIn(mTransformedView, transformationAmount);
    ++    }
    ++
    ++    public void disappear(float transformationAmount, TransformableView otherView) {
    ++        CrossFadeHelper.fadeOut(mTransformedView, transformationAmount);
    ++    }
    ++
    +     public static TransformState createFrom(View view) {
    +         if (view instanceof TextView) {
    +             TextViewTransformState result = TextViewTransformState.obtain();
    +diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeParameters.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeParameters.java
    +index efceed1..9e9bdd7 100644
    +--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeParameters.java
    ++++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeParameters.java
    +@@ -18,11 +18,13 @@ package com.android.systemui.statusbar.phone;
    + 
    + import android.content.Context;
    + import android.os.SystemProperties;
    ++import android.os.UserHandle;
    + import android.text.TextUtils;
    + import android.util.Log;
    + import android.util.MathUtils;
    + import android.util.SparseBooleanArray;
    + 
    ++import com.android.internal.hardware.AmbientDisplayConfiguration;
    + import com.android.systemui.R;
    + 
    + import java.io.PrintWriter;
    +@@ -31,9 +33,6 @@ import java.util.regex.Matcher;
    + import java.util.regex.Pattern;
    + 
    + public class DozeParameters {
    +-    private static final String TAG = "DozeParameters";
    +-    private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
    +-
    +     private static final int MAX_DURATION = 60 * 1000;
    + 
    +     private final Context mContext;
    +@@ -55,10 +54,8 @@ public class DozeParameters {
    +         pw.print("    getPulseOutDuration(): "); pw.println(getPulseOutDuration());
    +         pw.print("    getPulseOnSigMotion(): "); pw.println(getPulseOnSigMotion());
    +         pw.print("    getVibrateOnSigMotion(): "); pw.println(getVibrateOnSigMotion());
    +-        pw.print("    getPulseOnPickup(): "); pw.println(getPulseOnPickup());
    +         pw.print("    getVibrateOnPickup(): "); pw.println(getVibrateOnPickup());
    +         pw.print("    getProxCheckBeforePulse(): "); pw.println(getProxCheckBeforePulse());
    +-        pw.print("    getPulseOnNotifications(): "); pw.println(getPulseOnNotifications());
    +         pw.print("    getPickupVibrationThreshold(): "); pw.println(getPickupVibrationThreshold());
    +         pw.print("    getPickupSubtypePerformsProxCheck(): ");pw.println(
    +                 dumpPickupSubtypePerformsProxCheck());
    +@@ -84,8 +81,8 @@ public class DozeParameters {
    +         return getPulseInDuration(pickup) + getPulseVisibleDuration() + getPulseOutDuration();
    +     }
    + 
    +-    public int getPulseInDuration(boolean pickup) {
    +-        return pickup
    ++    public int getPulseInDuration(boolean pickupOrDoubleTap) {
    ++        return pickupOrDoubleTap
    +                 ? getInt("doze.pulse.duration.in.pickup", R.integer.doze_pulse_duration_in_pickup)
    +                 : getInt("doze.pulse.duration.in", R.integer.doze_pulse_duration_in);
    +     }
    +@@ -106,10 +103,6 @@ public class DozeParameters {
    +         return SystemProperties.getBoolean("doze.vibrate.sigmotion", false);
    +     }
    + 
    +-    public boolean getPulseOnPickup() {
    +-        return getBoolean("doze.pulse.pickup", R.bool.doze_pulse_on_pick_up);
    +-    }
    +-
    +     public boolean getVibrateOnPickup() {
    +         return SystemProperties.getBoolean("doze.vibrate.pickup", false);
    +     }
    +@@ -118,10 +111,6 @@ public class DozeParameters {
    +         return getBoolean("doze.pulse.proxcheck", R.bool.doze_proximity_check_before_pulse);
    +     }
    + 
    +-    public boolean getPulseOnNotifications() {
    +-        return getBoolean("doze.pulse.notifications", R.bool.doze_pulse_on_notifications);
    +-    }
    +-
    +     public int getPickupVibrationThreshold() {
    +         return getInt("doze.pickup.vibration.threshold", R.integer.doze_pickup_vibration_threshold);
    +     }
    +diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeScrimController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeScrimController.java
    +index 7d4515e..b44f5f7 100644
    +--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeScrimController.java
    ++++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeScrimController.java
    +@@ -109,10 +109,11 @@ public class DozeScrimController {
    + 
    +     public void onScreenTurnedOn() {
    +         if (isPulsing()) {
    +-            final boolean pickup = mPulseReason == DozeLog.PULSE_REASON_SENSOR_PICKUP;
    ++            final boolean pickupOrDoubleTap = mPulseReason == DozeLog.PULSE_REASON_SENSOR_PICKUP
    ++                    || mPulseReason == DozeLog.PULSE_REASON_SENSOR_DOUBLE_TAP;
    +             startScrimAnimation(true /* inFront */, 0f,
    +-                    mDozeParameters.getPulseInDuration(pickup),
    +-                    pickup ? Interpolators.LINEAR_OUT_SLOW_IN : Interpolators.ALPHA_OUT,
    ++                    mDozeParameters.getPulseInDuration(pickupOrDoubleTap),
    ++                    pickupOrDoubleTap ? Interpolators.LINEAR_OUT_SLOW_IN : Interpolators.ALPHA_OUT,
    +                     mPulseInFinished);
    +         }
    +     }
    +diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java
    +index 8cabfb9..4d0e5d3 100644
    +--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java
    ++++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java
    +@@ -111,6 +111,7 @@ public class KeyguardBottomAreaView extends FrameLayout implements View.OnClickL
    +     private KeyguardIndicationController mIndicationController;
    +     private AccessibilityController mAccessibilityController;
    +     private PhoneStatusBar mPhoneStatusBar;
    ++    private KeyguardAffordanceHelper mAffordanceHelper;
    + 
    +     private boolean mUserSetupComplete;
    +     private boolean mPrewarmBound;
    +@@ -271,6 +272,10 @@ public class KeyguardBottomAreaView extends FrameLayout implements View.OnClickL
    +         updateCameraVisibility(); // in case onFinishInflate() was called too early
    +     }
    + 
    ++    public void setAffordanceHelper(KeyguardAffordanceHelper affordanceHelper) {
    ++        mAffordanceHelper = affordanceHelper;
    ++    }
    ++
    +     public void setUserSetupComplete(boolean userSetupComplete) {
    +         mUserSetupComplete = userSetupComplete;
    +         updateCameraVisibility();
    +@@ -601,6 +606,9 @@ public class KeyguardBottomAreaView extends FrameLayout implements View.OnClickL
    +             mPreviewContainer.addView(mCameraPreview);
    +             mCameraPreview.setVisibility(visibleBefore ? View.VISIBLE : View.INVISIBLE);
    +         }
    ++        if (mAffordanceHelper != null) {
    ++            mAffordanceHelper.updatePreviews();
    ++        }
    +     }
    + 
    +     private void updateLeftPreview() {
    +@@ -618,6 +626,9 @@ public class KeyguardBottomAreaView extends FrameLayout implements View.OnClickL
    +             mPreviewContainer.addView(mLeftPreview);
    +             mLeftPreview.setVisibility(View.INVISIBLE);
    +         }
    ++        if (mAffordanceHelper != null) {
    ++            mAffordanceHelper.updatePreviews();
    ++        }
    +     }
    + 
    +     public void startFinishDozeAnimation() {
    +@@ -702,6 +713,13 @@ public class KeyguardBottomAreaView extends FrameLayout implements View.OnClickL
    +         public void onStrongAuthStateChanged(int userId) {
    +             mLockIcon.update();
    +         }
    ++
    ++        @Override
    ++        public void onUserUnlocked() {
    ++            inflateCameraPreview();
    ++            updateCameraVisibility();
    ++            updateLeftAffordance();
    ++        }
    +     };
    + 
    +     public void setKeyguardIndicationController(
    +diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarView.java
    +index 93ed139..41b0bb2 100644
    +--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarView.java
    ++++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarView.java
    +@@ -308,6 +308,7 @@ public class KeyguardStatusBarView extends RelativeLayout
    +         super.setVisibility(visibility);
    +         if (visibility != View.VISIBLE) {
    +             mSystemIconsSuperContainer.animate().cancel();
    ++            mSystemIconsSuperContainer.setTranslationX(0);
    +             mMultiUserSwitch.animate().cancel();
    +             mMultiUserSwitch.setAlpha(1f);
    +         } else {
    +diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LightStatusBarController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LightStatusBarController.java
    +index f98b9e5..df4566b 100644
    +--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LightStatusBarController.java
    ++++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LightStatusBarController.java
    +@@ -27,7 +27,7 @@ import static com.android.systemui.statusbar.phone.BarTransitions.MODE_TRANSPARE
    + /**
    +  * Controls how light status bar flag applies to the icons.
    +  */
    +-public class LightStatusBarController {
    ++public class LightStatusBarController implements BatteryController.BatteryStateChangeCallback {
    + 
    +     private final StatusBarIconController mIconController;
    +     private final BatteryController mBatteryController;
    +@@ -37,6 +37,7 @@ public class LightStatusBarController {
    +     private int mDockedStackVisibility;
    +     private boolean mFullscreenLight;
    +     private boolean mDockedLight;
    ++    private int mLastStatusBarMode;
    + 
    +     private final Rect mLastFullscreenBounds = new Rect();
    +     private final Rect mLastDockedBounds = new Rect();
    +@@ -45,6 +46,7 @@ public class LightStatusBarController {
    +             BatteryController batteryController) {
    +         mIconController = iconController;
    +         mBatteryController = batteryController;
    ++        batteryController.addStateChangedCallback(this);
    +     }
    + 
    +     public void setFingerprintUnlockController(
    +@@ -73,6 +75,7 @@ public class LightStatusBarController {
    +         }
    +         mFullscreenStackVisibility = newFullscreen;
    +         mDockedStackVisibility = newDocked;
    ++        mLastStatusBarMode = statusBarMode;
    +         mLastFullscreenBounds.set(fullscreenStackBounds);
    +         mLastDockedBounds.set(dockedStackBounds);
    +     }
    +@@ -123,4 +126,16 @@ public class LightStatusBarController {
    +             mIconController.setIconsDark(true, animateChange());
    +         }
    +     }
    ++
    ++    @Override
    ++    public void onBatteryLevelChanged(int level, boolean pluggedIn, boolean charging) {
    ++
    ++    }
    ++
    ++    @Override
    ++    public void onPowerSaveChanged(boolean isPowerSave) {
    ++        onSystemUiVisibilityChanged(mFullscreenStackVisibility, mDockedStackVisibility,
    ++                0 /* mask */, mLastFullscreenBounds, mLastDockedBounds, true /* sbModeChange*/,
    ++                mLastStatusBarMode);
    ++    }
    + }
    +diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
    +index 45d51b0..0bc70b5 100644
    +--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
    ++++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
    +@@ -59,6 +59,8 @@ public class NavigationBarView extends LinearLayout {
    +     // slippery nav bar when everything is disabled, e.g. during setup
    +     final static boolean SLIPPERY_WHEN_DISABLED = true;
    + 
    ++    final static boolean ALTERNATE_CAR_MODE_UI = false;
    ++
    +     final Display mDisplay;
    +     View mCurrentView = null;
    +     View[] mRotatedViews = new View[4];
    +@@ -94,7 +96,8 @@ public class NavigationBarView extends LinearLayout {
    +     private OnVerticalChangedListener mOnVerticalChangedListener;
    +     private boolean mLayoutTransitionsEnabled = true;
    +     private boolean mWakeAndUnlocking;
    +-    private boolean mCarMode = false;
    ++    private boolean mUseCarModeUi = false;
    ++    private boolean mInCarMode = false;
    +     private boolean mDockedStackExists;
    + 
    +     private final SparseArray<ButtonDispatcher> mButtonDisatchers = new SparseArray<>();
    +@@ -290,7 +293,9 @@ public class NavigationBarView extends LinearLayout {
    +             mMenuIcon = ctx.getDrawable(R.drawable.ic_sysbar_menu);
    +             mImeIcon = ctx.getDrawable(R.drawable.ic_ime_switcher_default);
    + 
    +-            updateCarModeIcons(ctx);
    ++            if (ALTERNATE_CAR_MODE_UI) {
    ++                updateCarModeIcons(ctx);
    ++            }
    +         }
    +     }
    + 
    +@@ -341,14 +346,14 @@ public class NavigationBarView extends LinearLayout {
    +         // carmode, respectively. Recents are not available in CarMode in nav bar so change
    +         // to recent icon is not required.
    +         Drawable backIcon = (backAlt)
    +-                ? getBackIconWithAlt(mCarMode, mVertical)
    +-                : getBackIcon(mCarMode, mVertical);
    ++                ? getBackIconWithAlt(mUseCarModeUi, mVertical)
    ++                : getBackIcon(mUseCarModeUi, mVertical);
    + 
    +         getBackButton().setImageDrawable(backIcon);
    + 
    +         updateRecentsIcon();
    + 
    +-        if (mCarMode) {
    ++        if (mUseCarModeUi) {
    +             getHomeButton().setImageDrawable(mHomeCarModeIcon);
    +         } else {
    +             getHomeButton().setImageDrawable(mHomeDefaultIcon);
    +@@ -376,9 +381,9 @@ public class NavigationBarView extends LinearLayout {
    + 
    +         final boolean disableHome = ((disabledFlags & View.STATUS_BAR_DISABLE_HOME) != 0);
    + 
    +-        // Disable recents always in car mode.
    +-        boolean disableRecent = (
    +-                mCarMode || (disabledFlags & View.STATUS_BAR_DISABLE_RECENT) != 0);
    ++        // Always disable recents when alternate car mode UI is active.
    ++        boolean disableRecent = mUseCarModeUi
    ++                        || ((disabledFlags & View.STATUS_BAR_DISABLE_RECENT) != 0);
    +         final boolean disableBack = ((disabledFlags & View.STATUS_BAR_DISABLE_BACK) != 0)
    +                 && ((mNavigationIconHints & StatusBarManager.NAVIGATION_HINT_BACK_ALT) == 0);
    +         final boolean disableSearch = ((disabledFlags & View.STATUS_BAR_DISABLE_SEARCH) != 0);
    +@@ -623,14 +628,19 @@ public class NavigationBarView extends LinearLayout {
    +         boolean uiCarModeChanged = false;
    +         if (newConfig != null) {
    +             int uiMode = newConfig.uiMode & Configuration.UI_MODE_TYPE_MASK;
    +-            if (mCarMode && uiMode != Configuration.UI_MODE_TYPE_CAR) {
    +-                mCarMode = false;
    +-                uiCarModeChanged = true;
    +-                getHomeButton().setCarMode(mCarMode);
    +-            } else if (uiMode == Configuration.UI_MODE_TYPE_CAR) {
    +-                mCarMode = true;
    +-                uiCarModeChanged = true;
    +-                getHomeButton().setCarMode(mCarMode);
    ++            final boolean isCarMode = (uiMode == Configuration.UI_MODE_TYPE_CAR);
    ++
    ++            if (isCarMode != mInCarMode) {
    ++                mInCarMode = isCarMode;
    ++                getHomeButton().setCarMode(isCarMode);
    ++
    ++                if (ALTERNATE_CAR_MODE_UI) {
    ++                    mUseCarModeUi = isCarMode;
    ++                    uiCarModeChanged = true;
    ++                } else {
    ++                    // Don't use car mode behavior if ALTERNATE_CAR_MODE_UI not set.
    ++                    mUseCarModeUi = false;
    ++                }
    +             }
    +         }
    +         return uiCarModeChanged;
    +diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
    +index f4b41bb..ede6fd0 100644
    +--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
    ++++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
    +@@ -233,6 +233,7 @@ public class NotificationPanelView extends PanelView implements
    +         mKeyguardBottomArea = (KeyguardBottomAreaView) findViewById(R.id.keyguard_bottom_area);
    +         mQsNavbarScrim = findViewById(R.id.qs_navbar_scrim);
    +         mAfforanceHelper = new KeyguardAffordanceHelper(this, getContext());
    ++        mKeyguardBottomArea.setAffordanceHelper(mAfforanceHelper);
    +         mLastOrientation = getResources().getConfiguration().orientation;
    + 
    +         mQsAutoReinflateContainer =
    +@@ -328,7 +329,7 @@ public class NotificationPanelView extends PanelView implements
    +         } else if (!mQsExpanded) {
    +             setQsExpansion(mQsMinExpansionHeight + mLastOverscroll);
    +         }
    +-        updateStackHeight(getExpandedHeight());
    ++        updateExpandedHeight(getExpandedHeight());
    +         updateHeader();
    + 
    +         // If we are running a size change animation, the animation takes care of the height of
    +@@ -376,10 +377,7 @@ public class NotificationPanelView extends PanelView implements
    +         boolean animate = mNotificationStackScroller.isAddOrRemoveAnimationPending();
    +         int stackScrollerPadding;
    +         if (mStatusBarState != StatusBarState.KEYGUARD) {
    +-            int bottom = mQsContainer.getHeader().getHeight();
    +-            stackScrollerPadding = mStatusBarState == StatusBarState.SHADE
    +-                    ? bottom + mQsPeekHeight
    +-                    : mKeyguardStatusBar.getHeight();
    ++            stackScrollerPadding = mQsContainer.getHeader().getHeight() + mQsPeekHeight;
    +             mTopPaddingAdjustment = 0;
    +         } else {
    +             mClockPositionAlgorithm.setup(
    +@@ -1004,8 +1002,8 @@ public class NotificationPanelView extends PanelView implements
    +         mKeyguardShowing = keyguardShowing;
    +         mQsContainer.setKeyguardShowing(mKeyguardShowing);
    + 
    +-        if (goingToFullShade || (oldState == StatusBarState.KEYGUARD
    +-                && statusBarState == StatusBarState.SHADE_LOCKED)) {
    ++        if (oldState == StatusBarState.KEYGUARD
    ++                && (goingToFullShade || statusBarState == StatusBarState.SHADE_LOCKED)) {
    +             animateKeyguardStatusBarOut();
    +             long delay = mStatusBarState == StatusBarState.SHADE_LOCKED
    +                     ? 0 : mStatusBar.calculateGoingToFullShadeDelay();
    +@@ -1019,7 +1017,7 @@ public class NotificationPanelView extends PanelView implements
    +             mKeyguardStatusBar.setVisibility(keyguardShowing ? View.VISIBLE : View.INVISIBLE);
    +             if (keyguardShowing && oldState != mStatusBarState) {
    +                 mKeyguardBottomArea.onKeyguardShowingChanged();
    +-                mAfforanceHelper.updatePreviews();
    ++                mQsContainer.hideImmediately();
    +             }
    +         }
    +         if (keyguardShowing) {
    +@@ -1166,6 +1164,7 @@ public class NotificationPanelView extends PanelView implements
    + 
    +     private void updateQsState() {
    +         mQsContainer.setExpanded(mQsExpanded);
    ++        mNotificationStackScroller.setQsExpanded(mQsExpanded);
    +         mNotificationStackScroller.setScrollingEnabled(
    +                 mStatusBarState != StatusBarState.KEYGUARD && (!mQsExpanded
    +                         || mQsExpansionFromOverscroll));
    +@@ -1427,7 +1426,7 @@ public class NotificationPanelView extends PanelView implements
    +             setQsExpansion(mQsMinExpansionHeight
    +                     + t * (getTempQsMaxExpansion() - mQsMinExpansionHeight));
    +         }
    +-        updateStackHeight(expandedHeight);
    ++        updateExpandedHeight(expandedHeight);
    +         updateHeader();
    +         updateUnlockIcon();
    +         updateNotificationTranslucency();
    +@@ -1487,7 +1486,7 @@ public class NotificationPanelView extends PanelView implements
    +                 maxQsHeight, mStatusBarState == StatusBarState.KEYGUARD
    +                         ? mClockPositionResult.stackScrollerPadding - mTopPaddingAdjustment
    +                         : 0)
    +-                + notificationHeight;
    ++                + notificationHeight + mNotificationStackScroller.getTopPaddingOverflow();
    +         if (totalHeight > mNotificationStackScroller.getHeight()) {
    +             float fullyCollapsedHeight = maxQsHeight
    +                     + mNotificationStackScroller.getLayoutMinHeight();
    +@@ -1730,6 +1729,14 @@ public class NotificationPanelView extends PanelView implements
    +         if (view == null && mQsExpanded) {
    +             return;
    +         }
    ++        ExpandableView firstChildNotGone = mNotificationStackScroller.getFirstChildNotGone();
    ++        ExpandableNotificationRow firstRow = firstChildNotGone instanceof ExpandableNotificationRow
    ++                ? (ExpandableNotificationRow) firstChildNotGone
    ++                : null;
    ++        if (firstRow != null
    ++                && (view == firstRow || (firstRow.getNotificationParent() == firstRow))) {
    ++            requestScrollerTopPaddingUpdate(false);
    ++        }
    +         requestPanelHeightUpdate();
    +     }
    + 
    +@@ -2249,8 +2256,8 @@ public class NotificationPanelView extends PanelView implements
    +         mQsAutoReinflateContainer.setTranslationX(translation);
    +     }
    + 
    +-    protected void updateStackHeight(float stackHeight) {
    +-        mNotificationStackScroller.setStackHeight(stackHeight);
    ++    protected void updateExpandedHeight(float expandedHeight) {
    ++        mNotificationStackScroller.setExpandedHeight(expandedHeight);
    +         updateKeyguardBottomAreaAlpha();
    +     }
    + 
    +diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java
    +index af85101..a6a5742 100644
    +--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java
    ++++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java
    +@@ -92,6 +92,7 @@ public abstract class PanelView extends FrameLayout {
    +      * Whether an instant expand request is currently pending and we are just waiting for layout.
    +      */
    +     private boolean mInstantExpanding;
    ++    private boolean mAnimateAfterExpanding;
    + 
    +     PanelBar mBar;
    + 
    +@@ -656,7 +657,7 @@ public abstract class PanelView extends FrameLayout {
    +                 vel = 0;
    +             }
    +             mFlingAnimationUtils.apply(animator, mExpandedHeight, target, vel, getHeight());
    +-            if (expandBecauseOfFalsing) {
    ++            if (vel == 0) {
    +                 animator.setDuration(350);
    +             }
    +         } else {
    +@@ -870,6 +871,7 @@ public abstract class PanelView extends FrameLayout {
    +         }
    + 
    +         mInstantExpanding = true;
    ++        mAnimateAfterExpanding = animate;
    +         mUpdateFlingOnLayout = false;
    +         abortAnimations();
    +         cancelPeek();
    +@@ -894,7 +896,7 @@ public abstract class PanelView extends FrameLayout {
    +                         if (mStatusBar.getStatusBarWindow().getHeight()
    +                                 != mStatusBar.getStatusBarHeight()) {
    +                             getViewTreeObserver().removeOnGlobalLayoutListener(this);
    +-                            if (animate) {
    ++                            if (mAnimateAfterExpanding) {
    +                                 notifyExpandingStarted();
    +                                 fling(0, true /* expand */);
    +                             } else {
    +diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
    +index 96fb7a8..30613bc 100644
    +--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
    ++++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
    +@@ -174,12 +174,14 @@ import com.android.systemui.statusbar.policy.BatteryControllerImpl;
    + import com.android.systemui.statusbar.policy.BluetoothControllerImpl;
    + import com.android.systemui.statusbar.policy.BrightnessMirrorController;
    + import com.android.systemui.statusbar.policy.CastControllerImpl;
    ++import com.android.systemui.statusbar.policy.EncryptionHelper;
    + import com.android.systemui.statusbar.policy.FlashlightController;
    + import com.android.systemui.statusbar.policy.HeadsUpManager;
    + import com.android.systemui.statusbar.policy.HotspotControllerImpl;
    + import com.android.systemui.statusbar.policy.KeyguardMonitor;
    + import com.android.systemui.statusbar.policy.KeyguardUserSwitcher;
    + import com.android.systemui.statusbar.policy.LocationControllerImpl;
    ++import com.android.systemui.statusbar.policy.NetworkController;
    + import com.android.systemui.statusbar.policy.NetworkControllerImpl;
    + import com.android.systemui.statusbar.policy.NextAlarmController;
    + import com.android.systemui.statusbar.policy.PreviewInflater;
    +@@ -279,6 +281,14 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
    +      */
    +     private static final int REMOTE_INPUT_KEPT_ENTRY_AUTO_CANCEL_DELAY = 200;
    + 
    ++    /**
    ++     * Never let the alpha become zero for surfaces that draw with SRC - otherwise the RenderNode
    ++     * won't draw anything and uninitialized memory will show through
    ++     * if mScrimSrcModeEnabled. Note that 0.001 is rounded down to 0 in
    ++     * libhwui.
    ++     */
    ++    private static final float SRC_MIN_ALPHA = 0.002f;
    ++
    +     static {
    +         boolean onlyCoreApps;
    +         boolean freeformWindowManagement;
    +@@ -656,6 +666,15 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
    +     private boolean mNoAnimationOnNextBarModeChange;
    +     private FalsingManager mFalsingManager;
    + 
    ++    private KeyguardUpdateMonitorCallback mUpdateCallback = new KeyguardUpdateMonitorCallback() {
    ++        @Override
    ++        public void onDreamingStateChanged(boolean dreaming) {
    ++            if (dreaming) {
    ++                maybeEscalateHeadsUp();
    ++            }
    ++        }
    ++    };
    ++
    +     @Override
    +     public void start() {
    +         mDisplay = ((WindowManager)mContext.getSystemService(Context.WINDOW_SERVICE))
    +@@ -693,8 +712,8 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
    +         mUnlockMethodCache.addListener(this);
    +         startKeyguard();
    + 
    ++        KeyguardUpdateMonitor.getInstance(mContext).registerCallback(mUpdateCallback);
    +         mDozeServiceHost = new DozeServiceHost();
    +-        KeyguardUpdateMonitor.getInstance(mContext).registerCallback(mDozeServiceHost);
    +         putComponent(DozeHost.class, mDozeServiceHost);
    +         putComponent(PhoneStatusBar.class, this);
    + 
    +@@ -878,6 +897,7 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
    + 
    +         initSignalCluster(mStatusBarView);
    +         initSignalCluster(mKeyguardStatusBar);
    ++        initEmergencyCryptkeeperText();
    + 
    +         mFlashlightController = new FlashlightController(mContext);
    +         mKeyguardBottomArea.setFlashlightController(mFlashlightController);
    +@@ -996,6 +1016,24 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
    +         return mStatusBarView;
    +     }
    + 
    ++    private void initEmergencyCryptkeeperText() {
    ++        View emergencyViewStub = mStatusBarWindow.findViewById(R.id.emergency_cryptkeeper_text);
    ++        if (mNetworkController.hasEmergencyCryptKeeperText()) {
    ++            if (emergencyViewStub != null) {
    ++                ((ViewStub) emergencyViewStub).inflate();
    ++            }
    ++            mNetworkController.addSignalCallback(new NetworkController.SignalCallback() {
    ++                @Override
    ++                public void setIsAirplaneMode(NetworkController.IconState icon) {
    ++                    recomputeDisableFlags(true /* animate */);
    ++                }
    ++            });
    ++        } else if (emergencyViewStub != null) {
    ++            ViewGroup parent = (ViewGroup) emergencyViewStub.getParent();
    ++            parent.removeView(emergencyViewStub);
    ++        }
    ++    }
    ++
    +     protected BatteryController createBatteryController() {
    +         return new BatteryControllerImpl(mContext);
    +     }
    +@@ -1681,7 +1719,7 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
    +     protected void performRemoveNotification(StatusBarNotification n, boolean removeView) {
    +         Entry entry = mNotificationData.get(n.getKey());
    +         if (mRemoteInputController.isRemoteInputActive(entry)) {
    +-            mRemoteInputController.removeRemoteInput(entry);
    ++            mRemoteInputController.removeRemoteInput(entry, null);
    +         }
    +         super.performRemoveNotification(n, removeView);
    +     }
    +@@ -2209,17 +2247,13 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
    +             if (mBackdrop.getVisibility() != View.VISIBLE) {
    +                 mBackdrop.setVisibility(View.VISIBLE);
    +                 if (allowEnterAnimation) {
    +-                    mBackdrop.animate().alpha(1f).withEndAction(new Runnable() {
    +-                        @Override
    +-                        public void run() {
    +-                            mStatusBarWindowManager.setBackdropShowing(true);
    +-                        }
    +-                    });
    ++                    mBackdrop.setAlpha(SRC_MIN_ALPHA);
    ++                    mBackdrop.animate().alpha(1f);
    +                 } else {
    +                     mBackdrop.animate().cancel();
    +                     mBackdrop.setAlpha(1f);
    +-                    mStatusBarWindowManager.setBackdropShowing(true);
    +                 }
    ++                mStatusBarWindowManager.setBackdropShowing(true);
    +                 metaDataChanged = true;
    +                 if (DEBUG_MEDIA) {
    +                     Log.v(TAG, "DEBUG_MEDIA: Fading in album artwork");
    +@@ -2282,11 +2316,7 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
    +                 } else {
    +                     mStatusBarWindowManager.setBackdropShowing(false);
    +                     mBackdrop.animate()
    +-                            // Never let the alpha become zero - otherwise the RenderNode
    +-                            // won't draw anything and uninitialized memory will show through
    +-                            // if mScrimSrcModeEnabled. Note that 0.001 is rounded down to 0 in
    +-                            // libhwui.
    +-                            .alpha(0.002f)
    ++                            .alpha(SRC_MIN_ALPHA)
    +                             .setInterpolator(Interpolators.ACCELERATE_DECELERATE)
    +                             .setDuration(300)
    +                             .setStartDelay(0)
    +@@ -2301,7 +2331,6 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
    +                             });
    +                     if (mKeyguardFadingAway) {
    +                         mBackdrop.animate()
    +-
    +                                 // Make it disappear faster, as the focus should be on the activity
    +                                 // behind.
    +                                 .setDuration(mKeyguardFadingAwayDuration / 2)
    +@@ -2329,6 +2358,14 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
    +             state |= StatusBarManager.DISABLE_NOTIFICATION_ICONS;
    +             state |= StatusBarManager.DISABLE_SYSTEM_INFO;
    +         }
    ++        if (mNetworkController != null && EncryptionHelper.IS_DATA_ENCRYPTED) {
    ++            if (mNetworkController.hasEmergencyCryptKeeperText()) {
    ++                state |= StatusBarManager.DISABLE_NOTIFICATION_ICONS;
    ++            }
    ++            if (!mNetworkController.isRadioOn()) {
    ++                state |= StatusBarManager.DISABLE_SYSTEM_INFO;
    ++            }
    ++        }
    +         return state;
    +     }
    + 
    +@@ -2433,6 +2470,15 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
    +         }
    +     }
    + 
    ++    /**
    ++     * Reapplies the disable flags as last requested by StatusBarManager.
    ++     *
    ++     * This needs to be called if state used by {@link #adjustDisableFlags} changes.
    ++     */
    ++    private void recomputeDisableFlags(boolean animate) {
    ++        disable(mDisabledUnmodified1, mDisabledUnmodified2, animate);
    ++    }
    ++
    +     @Override
    +     protected BaseStatusBar.H createHandler() {
    +         return new PhoneStatusBar.H();
    +@@ -2621,7 +2667,7 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
    +     private void removeRemoteInputEntriesKeptUntilCollapsed() {
    +         for (int i = 0; i < mRemoteInputEntriesToRemoveOnCollapse.size(); i++) {
    +             Entry entry = mRemoteInputEntriesToRemoveOnCollapse.valueAt(i);
    +-            mRemoteInputController.removeRemoteInput(entry);
    ++            mRemoteInputController.removeRemoteInput(entry, null);
    +             removeNotification(entry.key, mLatestRankingMap);
    +         }
    +         mRemoteInputEntriesToRemoveOnCollapse.clear();
    +@@ -2685,7 +2731,7 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
    +     public void handleSystemNavigationKey(int key) {
    +         if (SPEW) Log.d(TAG, "handleSystemNavigationKey: " + key);
    +         if (!panelsEnabled() || !mKeyguardMonitor.isDeviceInteractive()
    +-                || mKeyguardMonitor.isShowing()) {
    ++                || mKeyguardMonitor.isShowing() && !mKeyguardMonitor.isOccluded()) {
    +             return;
    +         }
    + 
    +@@ -2726,7 +2772,7 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
    + 
    +         visibilityChanged(true);
    +         mWaitingForKeyguardExit = false;
    +-        disable(mDisabledUnmodified1, mDisabledUnmodified2, !force /* animate */);
    ++        recomputeDisableFlags(!force /* animate */);
    +         setInteracting(StatusBarManager.WINDOW_STATUS_BAR, true);
    +     }
    + 
    +@@ -2868,7 +2914,7 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
    +         runPostCollapseRunnables();
    +         setInteracting(StatusBarManager.WINDOW_STATUS_BAR, false);
    +         showBouncer();
    +-        disable(mDisabledUnmodified1, mDisabledUnmodified2, true /* animate */);
    ++        recomputeDisableFlags(true /* animate */);
    + 
    +         // Trimming will happen later if Keyguard is showing - doing it here might cause a jank in
    +         // the bouncer appear animation.
    +@@ -2986,10 +3032,6 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
    +                 Integer.toHexString(diff)));
    +         boolean sbModeChanged = false;
    +         if (diff != 0) {
    +-            // we never set the recents bit via this method, so save the prior state to prevent
    +-            // clobbering the bit below
    +-            final boolean wasRecentsVisible = (mSystemUiVisibility & View.RECENT_APPS_VISIBLE) > 0;
    +-
    +             mSystemUiVisibility = newVal;
    + 
    +             // update low profile
    +@@ -3040,11 +3082,6 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
    +                 mSystemUiVisibility &= ~View.NAVIGATION_BAR_UNHIDE;
    +             }
    + 
    +-            // restore the recents bit
    +-            if (wasRecentsVisible) {
    +-                mSystemUiVisibility |= View.RECENT_APPS_VISIBLE;
    +-            }
    +-
    +             // send updated sysui visibility to window manager
    +             notifyUiVisibilityChanged(mSystemUiVisibility);
    +         }
    +@@ -3368,6 +3405,9 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
    +         if (KeyguardUpdateMonitor.getInstance(mContext) != null) {
    +             KeyguardUpdateMonitor.getInstance(mContext).dump(fd, pw, args);
    +         }
    ++        if (mFlashlightController != null) {
    ++            mFlashlightController.dump(fd, pw, args);
    ++        }
    + 
    +         FalsingManager.getInstance(mContext).dump(pw);
    +         FalsingLog.dump(pw);
    +@@ -4120,6 +4160,15 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
    +     }
    + 
    +     /**
    ++     * Plays the animation when an activity that was occluding Keyguard goes away.
    ++     */
    ++    public void animateKeyguardUnoccluding() {
    ++        mScrimController.animateKeyguardUnoccluding(500);
    ++        mNotificationPanel.setExpandedFraction(0f);
    ++        animateExpandNotificationsPanel();
    ++    }
    ++
    ++    /**
    +      * Starts the timeout when we try to start the affordances on Keyguard. We usually rely that
    +      * Keyguard goes away via fadeKeyguardAfterLaunchTransition, however, that might not happen
    +      * because the launched app crashed or something else went wrong.
    +@@ -4182,7 +4231,7 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
    +         }
    +         updateKeyguardState(staying, false /* fromShadeLocked */);
    + 
    +-        if (viewToClick != null) {
    ++        if (viewToClick != null && viewToClick.isAttachedToWindow()) {
    +             viewToClick.callOnClick();
    +         }
    + 
    +@@ -4237,7 +4286,7 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
    +                 startTime + fadeoutDuration
    +                         - StatusBarIconController.DEFAULT_TINT_ANIMATION_DURATION,
    +                 StatusBarIconController.DEFAULT_TINT_ANIMATION_DURATION);
    +-        disable(mDisabledUnmodified1, mDisabledUnmodified2, fadeoutDuration > 0 /* animate */);
    ++        recomputeDisableFlags(fadeoutDuration > 0 /* animate */);
    +     }
    + 
    +     public boolean isKeyguardFadingAway() {
    +@@ -4302,7 +4351,8 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
    +         checkBarModes();
    +         updateMediaMetaData(false, mState != StatusBarState.KEYGUARD);
    +         mKeyguardMonitor.notifyKeyguardState(mStatusBarKeyguardViewManager.isShowing(),
    +-                mStatusBarKeyguardViewManager.isSecure());
    ++                mStatusBarKeyguardViewManager.isSecure(),
    ++                mStatusBarKeyguardViewManager.isOccluded());
    +         Trace.endSection();
    +     }
    + 
    +@@ -4437,6 +4487,7 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
    +         }
    +         if (state == StatusBarState.KEYGUARD) {
    +             removeRemoteInputEntriesKeptUntilCollapsed();
    ++            maybeEscalateHeadsUp();
    +         }
    +         mState = state;
    +         mGroupManager.setStatusBarState(state);
    +@@ -4721,7 +4772,7 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
    +     public void setBouncerShowing(boolean bouncerShowing) {
    +         super.setBouncerShowing(bouncerShowing);
    +         mStatusBarView.setBouncerShowing(bouncerShowing);
    +-        disable(mDisabledUnmodified1, mDisabledUnmodified2, true /* animate */);
    ++        recomputeDisableFlags(true /* animate */);
    +     }
    + 
    +     public void onStartedGoingToSleep() {
    +@@ -4798,16 +4849,6 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
    +         return false;
    +     }
    + 
    +-    public void updateRecentsVisibility(boolean visible) {
    +-        // Update the recents visibility flag
    +-        if (visible) {
    +-            mSystemUiVisibility |= View.RECENT_APPS_VISIBLE;
    +-        } else {
    +-            mSystemUiVisibility &= ~View.RECENT_APPS_VISIBLE;
    +-        }
    +-        notifyUiVisibilityChanged(mSystemUiVisibility);
    +-    }
    +-
    +     @Override
    +     public void showScreenPinningRequest(int taskId) {
    +         if (mKeyguardMonitor.isShowing()) {
    +@@ -4956,7 +4997,7 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
    +         }
    +     }
    + 
    +-    private final class DozeServiceHost extends KeyguardUpdateMonitorCallback implements DozeHost  {
    ++    private final class DozeServiceHost implements DozeHost {
    +         // Amount of time to allow to update the time shown on the screen before releasing
    +         // the wakelock.  This timeout is design to compensate for the fact that we don't
    +         // currently have a way to know when time display contents have actually been
    +diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickStatusBarHeader.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickStatusBarHeader.java
    +index 7a2ae22..e4991d5 100644
    +--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickStatusBarHeader.java
    ++++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickStatusBarHeader.java
    +@@ -343,9 +343,7 @@ public class QuickStatusBarHeader extends BaseStatusBarHeader implements
    +             }
    +         } else if (v == mAlarmStatus && mNextAlarm != null) {
    +             PendingIntent showIntent = mNextAlarm.getShowIntent();
    +-            if (showIntent != null && showIntent.isActivity()) {
    +-                mActivityStarter.startActivity(showIntent.getIntent(), true /* dismissShade */);
    +-            }
    ++            mActivityStarter.startPendingIntentDismissingKeyguard(showIntent);
    +         }
    +     }
    + 
    +diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
    +index 8b87a7f..35e084d 100644
    +--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
    ++++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
    +@@ -176,7 +176,7 @@ public class ScrimController implements ViewTreeObserver.OnPreDrawListener,
    +         mSkipFirstFrame = skipFirstFrame;
    +         mOnAnimationFinished = onAnimationFinished;
    + 
    +-        if (mKeyguardUpdateMonitor.isUserUnlocked()) {
    ++        if (!mKeyguardUpdateMonitor.needsSlowUnlockTransition()) {
    +             scheduleUpdate();
    + 
    +             // No need to wait for the next frame to be drawn for this case - onPreDraw will execute
    +@@ -196,6 +196,14 @@ public class ScrimController implements ViewTreeObserver.OnPreDrawListener,
    +         }
    +     }
    + 
    ++    public void animateKeyguardUnoccluding(long duration) {
    ++        mAnimateChange = false;
    ++        setScrimBehindColor(0f);
    ++        mAnimateChange = true;
    ++        scheduleUpdate();
    ++        mDurationOverride = duration;
    ++    }
    ++
    +     public void animateGoingToFullShade(long delay, long duration) {
    +         mDurationOverride = duration;
    +         mAnimationDelay = delay;
    +@@ -233,9 +241,9 @@ public class ScrimController implements ViewTreeObserver.OnPreDrawListener,
    +     }
    + 
    +     private float getScrimInFrontAlpha() {
    +-        return mKeyguardUpdateMonitor.isUserUnlocked()
    +-                ? SCRIM_IN_FRONT_ALPHA
    +-                : SCRIM_IN_FRONT_ALPHA_LOCKED;
    ++        return mKeyguardUpdateMonitor.needsSlowUnlockTransition()
    ++                ? SCRIM_IN_FRONT_ALPHA_LOCKED
    ++                : SCRIM_IN_FRONT_ALPHA;
    +     }
    +     private void scheduleUpdate() {
    +         if (mUpdatePending) return;
    +@@ -397,7 +405,7 @@ public class ScrimController implements ViewTreeObserver.OnPreDrawListener,
    +     }
    + 
    +     private Interpolator getInterpolator() {
    +-        if (mAnimateKeyguardFadingOut && !mKeyguardUpdateMonitor.isUserUnlocked()) {
    ++        if (mAnimateKeyguardFadingOut && mKeyguardUpdateMonitor.needsSlowUnlockTransition()) {
    +             return KEYGUARD_FADE_OUT_INTERPOLATOR_LOCKED;
    +         } else if (mAnimateKeyguardFadingOut) {
    +             return KEYGUARD_FADE_OUT_INTERPOLATOR;
    +diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
    +index c72f994..664e103 100644
    +--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
    ++++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
    +@@ -242,7 +242,7 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb
    +         return mStatusBarWindowManager.isShowingWallpaper();
    +     }
    + 
    +-    public void setOccluded(boolean occluded) {
    ++    public void setOccluded(boolean occluded, boolean animate) {
    +         if (occluded && !mOccluded && mShowing) {
    +             if (mPhoneStatusBar.isInLaunchTransition()) {
    +                 mOccluded = true;
    +@@ -258,9 +258,12 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb
    +             }
    +         }
    +         mOccluded = occluded;
    +-        mPhoneStatusBar.updateMediaMetaData(false, false);
    ++        mPhoneStatusBar.updateMediaMetaData(false, animate && !occluded);
    +         mStatusBarWindowManager.setKeyguardOccluded(occluded);
    +         reset();
    ++        if (animate && !occluded) {
    ++            mPhoneStatusBar.animateKeyguardUnoccluding();
    ++        }
    +     }
    + 
    +     public boolean isOccluded() {
    +@@ -288,7 +291,7 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb
    +     public void hide(long startTime, long fadeoutDuration) {
    +         mShowing = false;
    + 
    +-        if (!KeyguardUpdateMonitor.getInstance(mContext).isUserUnlocked()) {
    ++        if (KeyguardUpdateMonitor.getInstance(mContext).needsSlowUnlockTransition()) {
    +             fadeoutDuration = KEYGUARD_DISMISS_DURATION_LOCKED;
    +         }
    +         long uptimeMillis = SystemClock.uptimeMillis();
    +diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BatteryControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BatteryControllerImpl.java
    +index b9c7a4b..6726c92 100644
    +--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BatteryControllerImpl.java
    ++++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BatteryControllerImpl.java
    +@@ -53,6 +53,7 @@ public class BatteryControllerImpl extends BroadcastReceiver implements BatteryC
    +     protected boolean mCharged;
    +     protected boolean mPowerSave;
    +     private boolean mTestmode = false;
    ++    private boolean mHasReceivedBattery = false;
    + 
    +     public BatteryControllerImpl(Context context) {
    +         mContext = context;
    +@@ -92,6 +93,7 @@ public class BatteryControllerImpl extends BroadcastReceiver implements BatteryC
    +         synchronized (mChangeCallbacks) {
    +             mChangeCallbacks.add(cb);
    +         }
    ++        if (!mHasReceivedBattery) return;
    +         cb.onBatteryLevelChanged(mLevel, mPluggedIn, mCharging);
    +         cb.onPowerSaveChanged(mPowerSave);
    +     }
    +@@ -108,6 +110,7 @@ public class BatteryControllerImpl extends BroadcastReceiver implements BatteryC
    +         final String action = intent.getAction();
    +         if (action.equals(Intent.ACTION_BATTERY_CHANGED)) {
    +             if (mTestmode && !intent.getBooleanExtra("testmode", false)) return;
    ++            mHasReceivedBattery = true;
    +             mLevel = (int)(100f
    +                     * intent.getIntExtra(BatteryManager.EXTRA_LEVEL, 0)
    +                     / intent.getIntExtra(BatteryManager.EXTRA_SCALE, 100));
    +diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/EmergencyCryptkeeperText.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/EmergencyCryptkeeperText.java
    +new file mode 100644
    +index 0000000..8abfb89
    +--- /dev/null
    ++++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/EmergencyCryptkeeperText.java
    +@@ -0,0 +1,124 @@
    ++/*
    ++ * Copyright (C) 2016 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 com.android.systemui.statusbar.policy;
    ++
    ++import android.annotation.Nullable;
    ++import android.content.Context;
    ++import android.content.Intent;
    ++import android.content.IntentFilter;
    ++import android.net.ConnectivityManager;
    ++import android.provider.Settings;
    ++import android.telephony.ServiceState;
    ++import android.telephony.SubscriptionInfo;
    ++import android.text.TextUtils;
    ++import android.util.AttributeSet;
    ++import android.util.Log;
    ++import android.view.ViewGroup;
    ++import android.view.ViewParent;
    ++import android.widget.TextView;
    ++
    ++import com.android.internal.telephony.IccCardConstants;
    ++import com.android.internal.telephony.TelephonyIntents;
    ++import com.android.keyguard.KeyguardUpdateMonitor;
    ++import com.android.keyguard.KeyguardUpdateMonitorCallback;
    ++
    ++import java.util.List;
    ++
    ++public class EmergencyCryptkeeperText extends TextView {
    ++
    ++    private KeyguardUpdateMonitor mKeyguardUpdateMonitor;
    ++    private KeyguardUpdateMonitorCallback mCallback = new KeyguardUpdateMonitorCallback() {
    ++        @Override
    ++        public void onPhoneStateChanged(int phoneState) {
    ++            update();
    ++        }
    ++    };
    ++
    ++    public EmergencyCryptkeeperText(Context context, @Nullable AttributeSet attrs) {
    ++        super(context, attrs);
    ++        setVisibility(GONE);
    ++    }
    ++
    ++    @Override
    ++    protected void onAttachedToWindow() {
    ++        super.onAttachedToWindow();
    ++        mKeyguardUpdateMonitor = KeyguardUpdateMonitor.getInstance(mContext);
    ++        mKeyguardUpdateMonitor.registerCallback(mCallback);
    ++        update();
    ++    }
    ++
    ++    @Override
    ++    protected void onDetachedFromWindow() {
    ++        super.onDetachedFromWindow();
    ++        if (mKeyguardUpdateMonitor != null) {
    ++            mKeyguardUpdateMonitor.removeCallback(mCallback);
    ++        }
    ++    }
    ++
    ++    public void update() {
    ++        boolean hasMobile = ConnectivityManager.from(mContext)
    ++                .isNetworkSupported(ConnectivityManager.TYPE_MOBILE);
    ++        boolean airplaneMode = (Settings.Global.getInt(mContext.getContentResolver(),
    ++                Settings.Global.AIRPLANE_MODE_ON, 0) == 1);
    ++
    ++        if (!hasMobile || airplaneMode) {
    ++            setText(null);
    ++            setVisibility(GONE);
    ++            return;
    ++        }
    ++
    ++        boolean allSimsMissing = true;
    ++        CharSequence displayText = null;
    ++
    ++        List<SubscriptionInfo> subs = mKeyguardUpdateMonitor.getSubscriptionInfo(false);
    ++        final int N = subs.size();
    ++        for (int i = 0; i < N; i++) {
    ++            int subId = subs.get(i).getSubscriptionId();
    ++            IccCardConstants.State simState = mKeyguardUpdateMonitor.getSimState(subId);
    ++            CharSequence carrierName = subs.get(i).getCarrierName();
    ++            if (simState.iccCardExist() && !TextUtils.isEmpty(carrierName)) {
    ++                allSimsMissing = false;
    ++                displayText = carrierName;
    ++            }
    ++        }
    ++        if (allSimsMissing) {
    ++            if (N != 0) {
    ++                // Shows "Emergency calls only" on devices that are voice-capable.
    ++                // This depends on mPlmn containing the text "Emergency calls only" when the radio
    ++                // has some connectivity. Otherwise it should show "No service"
    ++                // Grab the first subscription, because they all should contain the emergency text,
    ++                // described above.
    ++                displayText = subs.get(0).getCarrierName();
    ++            } else {
    ++                // We don't have a SubscriptionInfo to get the emergency calls only from.
    ++                // Grab it from the old sticky broadcast if possible instead. We can use it
    ++                // here because no subscriptions are active, so we don't have
    ++                // to worry about MSIM clashing.
    ++                displayText = getContext().getText(
    ++                        com.android.internal.R.string.emergency_calls_only);
    ++                Intent i = getContext().registerReceiver(null,
    ++                        new IntentFilter(TelephonyIntents.SPN_STRINGS_UPDATED_ACTION));
    ++                if (i != null) {
    ++                    displayText = i.getStringExtra(TelephonyIntents.EXTRA_PLMN);
    ++                }
    ++            }
    ++        }
    ++
    ++        setText(displayText);
    ++        setVisibility(TextUtils.isEmpty(displayText) ? GONE : VISIBLE);
    ++    }
    ++}
    +diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/EncryptionHelper.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/EncryptionHelper.java
    +new file mode 100644
    +index 0000000..639e50c
    +--- /dev/null
    ++++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/EncryptionHelper.java
    +@@ -0,0 +1,32 @@
    ++/*
    ++ * Copyright (C) 2016 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 com.android.systemui.statusbar.policy;
    ++
    ++import android.os.SystemProperties;
    ++
    ++/**
    ++ * Helper for determining whether the phone is decrypted yet.
    ++ */
    ++public class EncryptionHelper {
    ++
    ++    public static final boolean IS_DATA_ENCRYPTED = isDataEncrypted();
    ++
    ++    private static boolean isDataEncrypted() {
    ++        String voldState = SystemProperties.get("vold.decrypt");
    ++        return "1".equals(voldState) || "trigger_restart_min_framework".equals(voldState);
    ++    }
    ++}
    +diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/FlashlightController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/FlashlightController.java
    +index 91b21ed..4e9fc76 100644
    +--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/FlashlightController.java
    ++++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/FlashlightController.java
    +@@ -27,6 +27,8 @@ import android.os.Process;
    + import android.text.TextUtils;
    + import android.util.Log;
    + 
    ++import java.io.FileDescriptor;
    ++import java.io.PrintWriter;
    + import java.lang.ref.WeakReference;
    + import java.util.ArrayList;
    + 
    +@@ -80,6 +82,7 @@ public class FlashlightController {
    +     public void setFlashlight(boolean enabled) {
    +         boolean pendingError = false;
    +         synchronized (this) {
    ++            if (mCameraId == null) return;
    +             if (mFlashlightEnabled != enabled) {
    +                 mFlashlightEnabled = enabled;
    +                 try {
    +@@ -235,6 +238,17 @@ public class FlashlightController {
    +         }
    +     };
    + 
    ++    public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
    ++        pw.println("FlashlightController state:");
    ++
    ++        pw.print("  mCameraId=");
    ++        pw.println(mCameraId);
    ++        pw.print("  mFlashlightEnabled=");
    ++        pw.println(mFlashlightEnabled);
    ++        pw.print("  mTorchAvailable=");
    ++        pw.println(mTorchAvailable);
    ++    }
    ++
    +     public interface FlashlightListener {
    + 
    +         /**
    +diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpManager.java
    +index d3ae549..f6c0942 100644
    +--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpManager.java
    ++++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpManager.java
    +@@ -381,7 +381,7 @@ public class HeadsUpManager implements ViewTreeObserver.OnComputeInternalInsetsL
    +     }
    + 
    +     public void onComputeInternalInsets(ViewTreeObserver.InternalInsetsInfo info) {
    +-        if (mIsExpanded) {
    ++        if (mIsExpanded || mBar.isBouncerShowing()) {
    +             // The touchable region is always the full area when expanded
    +             return;
    +         }
    +diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonView.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonView.java
    +index 61bac2d..e6066aa 100644
    +--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonView.java
    ++++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonView.java
    +@@ -59,6 +59,7 @@ public class KeyButtonView extends ImageView implements ButtonDispatcher.ButtonI
    +     private AudioManager mAudioManager;
    +     private boolean mGestureAborted;
    +     private boolean mLongClicked;
    ++    private OnClickListener mOnClickListener;
    + 
    +     private final Runnable mCheckLongPress = new Runnable() {
    +         public void run() {
    +@@ -109,6 +110,12 @@ public class KeyButtonView extends ImageView implements ButtonDispatcher.ButtonI
    +         mCode = code;
    +     }
    + 
    ++    @Override
    ++    public void setOnClickListener(OnClickListener onClickListener) {
    ++        super.setOnClickListener(onClickListener);
    ++        mOnClickListener = onClickListener;
    ++    }
    ++
    +     public void loadAsync(String uri) {
    +         new AsyncTask<String, Void, Drawable>() {
    +             @Override
    +@@ -190,6 +197,7 @@ public class KeyButtonView extends ImageView implements ButtonDispatcher.ButtonI
    +                     // Provide the same haptic feedback that the system offers for virtual keys.
    +                     performHapticFeedback(HapticFeedbackConstants.VIRTUAL_KEY);
    +                 }
    ++                playSoundEffect(SoundEffectConstants.CLICK);
    +                 removeCallbacks(mCheckLongPress);
    +                 postDelayed(mCheckLongPress, ViewConfiguration.getLongPressTimeout());
    +                 break;
    +@@ -215,14 +223,14 @@ public class KeyButtonView extends ImageView implements ButtonDispatcher.ButtonI
    +                     if (doIt) {
    +                         sendEvent(KeyEvent.ACTION_UP, 0);
    +                         sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_CLICKED);
    +-                        playSoundEffect(SoundEffectConstants.CLICK);
    +                     } else {
    +                         sendEvent(KeyEvent.ACTION_UP, KeyEvent.FLAG_CANCELED);
    +                     }
    +                 } else {
    +                     // no key code, just a regular ImageView
    +-                    if (doIt) {
    +-                        performClick();
    ++                    if (doIt && mOnClickListener != null) {
    ++                        mOnClickListener.onClick(this);
    ++                        sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_CLICKED);
    +                     }
    +                 }
    +                 removeCallbacks(mCheckLongPress);
    +diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardMonitor.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardMonitor.java
    +index c175180..44816f9 100644
    +--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardMonitor.java
    ++++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardMonitor.java
    +@@ -38,6 +38,7 @@ public final class KeyguardMonitor extends KeyguardUpdateMonitorCallback {
    +     private int mCurrentUser;
    +     private boolean mShowing;
    +     private boolean mSecure;
    ++    private boolean mOccluded;
    +     private boolean mCanSkipBouncer;
    + 
    +     private boolean mListening;
    +@@ -81,6 +82,10 @@ public final class KeyguardMonitor extends KeyguardUpdateMonitorCallback {
    +         return mSecure;
    +     }
    + 
    ++    public boolean isOccluded() {
    ++        return mOccluded;
    ++    }
    ++
    +     public boolean canSkipBouncer() {
    +         return mCanSkipBouncer;
    +     }
    +@@ -99,10 +104,11 @@ public final class KeyguardMonitor extends KeyguardUpdateMonitorCallback {
    +         }
    +     }
    + 
    +-    public void notifyKeyguardState(boolean showing, boolean secure) {
    +-        if (mShowing == showing && mSecure == secure) return;
    ++    public void notifyKeyguardState(boolean showing, boolean secure, boolean occluded) {
    ++        if (mShowing == showing && mSecure == secure && mOccluded == occluded) return;
    +         mShowing = showing;
    +         mSecure = secure;
    ++        mOccluded = occluded;
    +         notifyKeyguardChanged();
    +     }
    + 
    +diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkController.java
    +index 348e0b0..5f1b871 100644
    +--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkController.java
    ++++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkController.java
    +@@ -41,20 +41,20 @@ public interface NetworkController {
    +     void removeEmergencyListener(EmergencyListener listener);
    + 
    +     public interface SignalCallback {
    +-        void setWifiIndicators(boolean enabled, IconState statusIcon, IconState qsIcon,
    +-                boolean activityIn, boolean activityOut, String description);
    ++        default void setWifiIndicators(boolean enabled, IconState statusIcon, IconState qsIcon,
    ++                boolean activityIn, boolean activityOut, String description) {}
    + 
    +-        void setMobileDataIndicators(IconState statusIcon, IconState qsIcon, int statusType,
    ++        default void setMobileDataIndicators(IconState statusIcon, IconState qsIcon, int statusType,
    +                 int qsType, boolean activityIn, boolean activityOut, String typeContentDescription,
    +-                String description, boolean isWide, int subId);
    +-        void setSubs(List<SubscriptionInfo> subs);
    +-        void setNoSims(boolean show);
    ++                String description, boolean isWide, int subId) {}
    ++        default void setSubs(List<SubscriptionInfo> subs) {}
    ++        default void setNoSims(boolean show) {}
    + 
    +-        void setEthernetIndicators(IconState icon);
    ++        default void setEthernetIndicators(IconState icon) {}
    + 
    +-        void setIsAirplaneMode(IconState icon);
    ++        default void setIsAirplaneMode(IconState icon) {}
    + 
    +-        void setMobileDataEnabled(boolean enabled);
    ++        default void setMobileDataEnabled(boolean enabled) {}
    +     }
    + 
    +     public interface EmergencyListener {
    +diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java
    +index 7893a1a..37e6a2a 100644
    +--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java
    ++++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java
    +@@ -819,6 +819,14 @@ public class NetworkControllerImpl extends BroadcastReceiver
    +         return info;
    +     }
    + 
    ++    public boolean hasEmergencyCryptKeeperText() {
    ++        return EncryptionHelper.IS_DATA_ENCRYPTED;
    ++    }
    ++
    ++    public boolean isRadioOn() {
    ++        return !mAirplaneMode;
    ++    }
    ++
    +     private class SubListener extends OnSubscriptionsChangedListener {
    +         @Override
    +         public void onSubscriptionsChanged() {
    +diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputView.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputView.java
    +index cdd452f..7b1f707 100644
    +--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputView.java
    ++++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputView.java
    +@@ -38,6 +38,7 @@ import android.view.View;
    + import android.view.ViewAnimationUtils;
    + import android.view.ViewGroup;
    + import android.view.ViewParent;
    ++import android.view.accessibility.AccessibilityEvent;
    + import android.view.inputmethod.CompletionInfo;
    + import android.view.inputmethod.EditorInfo;
    + import android.view.inputmethod.InputConnection;
    +@@ -68,6 +69,8 @@ public class RemoteInputView extends LinearLayout implements View.OnClickListene
    +     // A marker object that let's us easily find views of this class.
    +     public static final Object VIEW_TAG = new Object();
    + 
    ++    public final Object mToken = new Object();
    ++
    +     private RemoteEditText mEditText;
    +     private ImageButton mSendButton;
    +     private ProgressBar mProgressBar;
    +@@ -86,6 +89,8 @@ public class RemoteInputView extends LinearLayout implements View.OnClickListene
    +     private int mRevealCy;
    +     private int mRevealR;
    + 
    ++    private boolean mResetting;
    ++
    +     public RemoteInputView(Context context, AttributeSet attrs) {
    +         super(context, attrs);
    +     }
    +@@ -137,8 +142,8 @@ public class RemoteInputView extends LinearLayout implements View.OnClickListene
    +         mSendButton.setVisibility(INVISIBLE);
    +         mProgressBar.setVisibility(VISIBLE);
    +         mEntry.remoteInputText = mEditText.getText();
    +-        mController.addSpinning(mEntry.key);
    +-        mController.removeRemoteInput(mEntry);
    ++        mController.addSpinning(mEntry.key, mToken);
    ++        mController.removeRemoteInput(mEntry, mToken);
    +         mEditText.mShowImeOnInputConnection = false;
    +         mController.remoteInputSent(mEntry);
    + 
    +@@ -190,7 +195,7 @@ public class RemoteInputView extends LinearLayout implements View.OnClickListene
    +     }
    + 
    +     private void onDefocus(boolean animate) {
    +-        mController.removeRemoteInput(mEntry);
    ++        mController.removeRemoteInput(mEntry, mToken);
    +         mEntry.remoteInputText = mEditText.getText();
    + 
    +         // During removal, we get reattached and lose focus. Not hiding in that
    +@@ -229,11 +234,11 @@ public class RemoteInputView extends LinearLayout implements View.OnClickListene
    +     @Override
    +     protected void onDetachedFromWindow() {
    +         super.onDetachedFromWindow();
    +-        if (mEntry.row.isChangingPosition()) {
    ++        if (mEntry.row.isChangingPosition() || isTemporarilyDetached()) {
    +             return;
    +         }
    +-        mController.removeRemoteInput(mEntry);
    +-        mController.removeSpinning(mEntry.key);
    ++        mController.removeRemoteInput(mEntry, mToken);
    ++        mController.removeSpinning(mEntry.key, mToken);
    +     }
    + 
    +     public void setPendingIntent(PendingIntent pendingIntent) {
    +@@ -262,7 +267,7 @@ public class RemoteInputView extends LinearLayout implements View.OnClickListene
    +                 mEntry.notification.getPackageName());
    + 
    +         setVisibility(VISIBLE);
    +-        mController.addRemoteInput(mEntry);
    ++        mController.addRemoteInput(mEntry, mToken);
    +         mEditText.setInnerFocusable(true);
    +         mEditText.mShowImeOnInputConnection = true;
    +         mEditText.setText(mEntry.remoteInputText);
    +@@ -281,13 +286,28 @@ public class RemoteInputView extends LinearLayout implements View.OnClickListene
    +     }
    + 
    +     private void reset() {
    ++        mResetting = true;
    ++
    +         mEditText.getText().clear();
    +         mEditText.setEnabled(true);
    +         mSendButton.setVisibility(VISIBLE);
    +         mProgressBar.setVisibility(INVISIBLE);
    +-        mController.removeSpinning(mEntry.key);
    ++        mController.removeSpinning(mEntry.key, mToken);
    +         updateSendButton();
    +         onDefocus(false /* animate */);
    ++
    ++        mResetting = false;
    ++    }
    ++
    ++    @Override
    ++    public boolean onRequestSendAccessibilityEvent(View child, AccessibilityEvent event) {
    ++        if (mResetting && child == mEditText) {
    ++            // Suppress text events if it happens during resetting. Ideally this would be
    ++            // suppressed by the text view not being shown, but that doesn't work here because it
    ++            // needs to stay visible for the animation.
    ++            return false;
    ++        }
    ++        return super.onRequestSendAccessibilityEvent(child, event);
    +     }
    + 
    +     private void updateSendButton() {
    +@@ -414,6 +434,24 @@ public class RemoteInputView extends LinearLayout implements View.OnClickListene
    +         mRevealR = r;
    +     }
    + 
    ++    @Override
    ++    public void dispatchStartTemporaryDetach() {
    ++        super.dispatchStartTemporaryDetach();
    ++        // Detach the EditText temporarily such that it doesn't get onDetachedFromWindow and
    ++        // won't lose IME focus.
    ++        detachViewFromParent(mEditText);
    ++    }
    ++
    ++    @Override
    ++    public void dispatchFinishTemporaryDetach() {
    ++        if (isAttachedToWindow()) {
    ++            attachViewToParent(mEditText, 0, mEditText.getLayoutParams());
    ++        } else {
    ++            removeDetachedView(mEditText, false /* animate */);
    ++        }
    ++        super.dispatchFinishTemporaryDetach();
    ++    }
    ++
    +     /**
    +      * An EditText that changes appearance based on whether it's focusable and becomes
    +      * un-focusable whenever the user navigates away from it or it becomes invisible.
    +@@ -430,7 +468,15 @@ public class RemoteInputView extends LinearLayout implements View.OnClickListene
    +         }
    + 
    +         private void defocusIfNeeded(boolean animate) {
    +-            if (mRemoteInputView != null && mRemoteInputView.mEntry.row.isChangingPosition()) {
    ++            if (mRemoteInputView != null && mRemoteInputView.mEntry.row.isChangingPosition()
    ++                    || isTemporarilyDetached()) {
    ++                if (isTemporarilyDetached()) {
    ++                    // We might get reattached but then the other one of HUN / expanded might steal
    ++                    // our focus, so we'll need to save our text here.
    ++                    if (mRemoteInputView != null) {
    ++                        mRemoteInputView.mEntry.remoteInputText = getText();
    ++                    }
    ++                }
    +                 return;
    +             }
    +             if (isFocusable() && isEnabled()) {
    +diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/AmbientState.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/AmbientState.java
    +index 50e5b88..81da672 100644
    +--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/AmbientState.java
    ++++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/AmbientState.java
    +@@ -43,6 +43,7 @@ public class AmbientState {
    +     private boolean mShadeExpanded;
    +     private float mMaxHeadsUpTranslation;
    +     private boolean mDismissAllInProgress;
    ++    private int mLayoutMinHeight;
    + 
    +     public int getScrollY() {
    +         return mScrollY;
    +@@ -137,10 +138,6 @@ public class AmbientState {
    +         mStackTranslation = stackTranslation;
    +     }
    + 
    +-    public int getLayoutHeight() {
    +-        return mLayoutHeight;
    +-    }
    +-
    +     public void setLayoutHeight(int layoutHeight) {
    +         mLayoutHeight = layoutHeight;
    +     }
    +@@ -154,7 +151,7 @@ public class AmbientState {
    +     }
    + 
    +     public int getInnerHeight() {
    +-        return mLayoutHeight - mTopPadding;
    ++        return Math.max(mLayoutHeight - mTopPadding, mLayoutMinHeight);
    +     }
    + 
    +     public boolean isShadeExpanded() {
    +@@ -180,4 +177,8 @@ public class AmbientState {
    +     public boolean isDismissAllInProgress() {
    +         return mDismissAllInProgress;
    +     }
    ++
    ++    public void setLayoutMinHeight(int layoutMinHeight) {
    ++        mLayoutMinHeight = layoutMinHeight;
    ++    }
    + }
    +diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationChildrenContainer.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationChildrenContainer.java
    +index 3c9373b..d7920a9 100644
    +--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationChildrenContainer.java
    ++++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationChildrenContainer.java
    +@@ -123,8 +123,10 @@ public class NotificationChildrenContainer extends ViewGroup {
    +             mDividers.get(i).layout(0, 0, getWidth(), mDividerHeight);
    +         }
    +         if (mOverflowNumber != null) {
    +-            mOverflowNumber.layout(getWidth() - mOverflowNumber.getMeasuredWidth(), 0, getWidth(),
    +-                    mOverflowNumber.getMeasuredHeight());
    ++            boolean isRtl = getLayoutDirection() == LAYOUT_DIRECTION_RTL;
    ++            int left = (isRtl ? 0 : getWidth() - mOverflowNumber.getMeasuredWidth());
    ++            int right = left + mOverflowNumber.getMeasuredWidth();
    ++            mOverflowNumber.layout(left, 0, right, mOverflowNumber.getMeasuredHeight());
    +         }
    +         if (mNotificationHeader != null) {
    +             mNotificationHeader.layout(0, 0, mNotificationHeader.getMeasuredWidth(),
    +diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
    +index c8c4310..a6fe438 100644
    +--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
    ++++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
    +@@ -111,11 +111,7 @@ public class NotificationStackScrollLayout extends ViewGroup
    +     private int mCurrentStackHeight = Integer.MAX_VALUE;
    +     private final Paint mBackgroundPaint = new Paint();
    + 
    +-    /**
    +-     * mCurrentStackHeight is the actual stack height, mLastSetStackHeight is the stack height set
    +-     * externally from {@link #setStackHeight}
    +-     */
    +-    private float mLastSetStackHeight;
    ++    private float mExpandedHeight;
    +     private int mOwnScrollY;
    +     private int mMaxLayoutHeight;
    + 
    +@@ -130,7 +126,7 @@ public class NotificationStackScrollLayout extends ViewGroup
    +     private boolean mIsBeingDragged;
    +     private int mLastMotionY;
    +     private int mDownX;
    +-    private int mActivePointerId;
    ++    private int mActivePointerId = INVALID_POINTER;
    +     private boolean mTouchIsClick;
    +     private float mInitialTouchX;
    +     private float mInitialTouchY;
    +@@ -216,7 +212,6 @@ public class NotificationStackScrollLayout extends ViewGroup
    +     private float mTopPaddingOverflow;
    +     private boolean mDontReportNextOverScroll;
    +     private boolean mDontClampNextScroll;
    +-    private boolean mRequestViewResizeAnimationOnLayout;
    +     private boolean mNeedViewResizeAnimation;
    +     private View mExpandedGroupView;
    +     private boolean mEverythingNeedsAnimation;
    +@@ -355,6 +350,9 @@ public class NotificationStackScrollLayout extends ViewGroup
    +                     return object.getBackgroundFadeAmount();
    +                 }
    +             };
    ++    private boolean mQsExpanded;
    ++    private boolean mForwardScrollable;
    ++    private boolean mBackwardScrollable;
    + 
    +     public NotificationStackScrollLayout(Context context) {
    +         this(context, null);
    +@@ -518,12 +516,9 @@ public class NotificationStackScrollLayout extends ViewGroup
    +         setMaxLayoutHeight(getHeight());
    +         updateContentHeight();
    +         clampScrollPosition();
    +-        if (mRequestViewResizeAnimationOnLayout) {
    +-            requestAnimationOnViewResize(null);
    +-            mRequestViewResizeAnimationOnLayout = false;
    +-        }
    +         requestChildrenUpdate();
    +         updateFirstAndLastBackgroundViews();
    ++        updateAlgorithmLayoutMinHeight();
    +     }
    + 
    +     private void requestAnimationOnViewResize(ExpandableNotificationRow row) {
    +@@ -565,9 +560,14 @@ public class NotificationStackScrollLayout extends ViewGroup
    + 
    +     private void updateAlgorithmHeightAndPadding() {
    +         mAmbientState.setLayoutHeight(getLayoutHeight());
    ++        updateAlgorithmLayoutMinHeight();
    +         mAmbientState.setTopPadding(mTopPadding);
    +     }
    + 
    ++    private void updateAlgorithmLayoutMinHeight() {
    ++        mAmbientState.setLayoutMinHeight(mQsExpanded && !onKeyguard() ? getLayoutMinHeight() : 0);
    ++    }
    ++
    +     /**
    +      * Updates the children views according to the stack scroll algorithm. Call this whenever
    +      * modifications to {@link #mOwnScrollY} are performed to reflect it in the view layout.
    +@@ -598,7 +598,7 @@ public class NotificationStackScrollLayout extends ViewGroup
    +                 if (startingPosition < mOwnScrollY) {
    +                     // This child starts off screen, so let's keep it offscreen to keep the others visible
    + 
    +-                    mOwnScrollY += childHeight;
    ++                    setOwnScrollY(mOwnScrollY + childHeight);
    +                 }
    +             }
    +         }
    +@@ -621,7 +621,7 @@ public class NotificationStackScrollLayout extends ViewGroup
    +             // Only apply the scroll if we're scrolling the view upwards, or the view is so far up
    +             // that it is not visible anymore.
    +             if (mOwnScrollY < targetScroll || outOfViewScroll < mOwnScrollY) {
    +-                mOwnScrollY = targetScroll;
    ++                setOwnScrollY(targetScroll);
    +             }
    +         }
    +     }
    +@@ -641,7 +641,7 @@ public class NotificationStackScrollLayout extends ViewGroup
    +     private void clampScrollPosition() {
    +         int scrollRange = getScrollRange();
    +         if (scrollRange < mOwnScrollY) {
    +-            mOwnScrollY = scrollRange;
    ++            setOwnScrollY(scrollRange);
    +         }
    +     }
    + 
    +@@ -664,19 +664,19 @@ public class NotificationStackScrollLayout extends ViewGroup
    +     }
    + 
    +     /**
    +-     * Update the height of the stack to a new height.
    ++     * Update the height of the panel.
    +      *
    +-     * @param height the new height of the stack
    ++     * @param height the expanded height of the panel
    +      */
    +-    public void setStackHeight(float height) {
    +-        mLastSetStackHeight = height;
    ++    public void setExpandedHeight(float height) {
    ++        mExpandedHeight = height;
    +         setIsExpanded(height > 0.0f);
    +         int stackHeight;
    +         float translationY;
    +         float appearEndPosition = getAppearEndPosition();
    +         float appearStartPosition = getAppearStartPosition();
    +         if (height >= appearEndPosition) {
    +-            translationY = mTopPaddingOverflow;
    ++            translationY = 0;
    +             stackHeight = (int) height;
    +         } else {
    +             float appearFraction = getAppearFraction(height);
    +@@ -703,8 +703,12 @@ public class NotificationStackScrollLayout extends ViewGroup
    +      *         Measured relative to the resting position.
    +      */
    +     private float getExpandTranslationStart() {
    +-        int startPosition = mTrackingHeadsUp || mHeadsUpManager.hasPinnedHeadsUp()
    +-                ? 0 : -getFirstChildIntrinsicHeight();
    ++        int startPosition = 0;
    ++        if (!mTrackingHeadsUp && !mHeadsUpManager.hasPinnedHeadsUp()) {
    ++            startPosition = - Math.min(getFirstChildIntrinsicHeight(),
    ++                    mMaxLayoutHeight - mIntrinsicPadding - mBottomStackSlowDownHeight
    ++                            - mBottomStackPeekSize);
    ++        }
    +         return startPosition - mTopPadding;
    +     }
    + 
    +@@ -727,7 +731,7 @@ public class NotificationStackScrollLayout extends ViewGroup
    +                 ? mHeadsUpManager.getTopHeadsUpPinnedHeight() + mBottomStackPeekSize
    +                         + mBottomStackSlowDownHeight
    +                 : getLayoutMinHeight();
    +-        return firstItemHeight + mTopPadding + mTopPaddingOverflow;
    ++        return firstItemHeight + (onKeyguard() ? mTopPadding : mIntrinsicPadding);
    +     }
    + 
    +     /**
    +@@ -1052,7 +1056,7 @@ public class NotificationStackScrollLayout extends ViewGroup
    +     @Override
    +     public int getMaxExpandHeight(ExpandableView view) {
    +         int maxContentHeight = view.getMaxContentHeight();
    +-        if (view.isSummaryWithChildren()) {
    ++        if (view.isSummaryWithChildren() && view.getParent() == this) {
    +             // Faking a measure with the group expanded to simulate how the group would look if
    +             // it was. Doing a calculation here would be highly non-trivial because of the
    +             // algorithm
    +@@ -1067,8 +1071,11 @@ public class NotificationStackScrollLayout extends ViewGroup
    +                     row.getStatusBarNotification());
    +             mGroupExpandedForMeasure = false;
    +             row.setForceUnlocked(false);
    +-            int height = mCurrentStackScrollState.getViewStateForView(view).height;
    +-            return Math.min(height, maxContentHeight);
    ++            StackViewState viewState = mCurrentStackScrollState.getViewStateForView(view);
    ++            if (viewState != null) {
    ++                // The view could have been removed
    ++                return Math.min(viewState.height, maxContentHeight);
    ++            }
    +         }
    +         return maxContentHeight;
    +     }
    +@@ -1157,6 +1164,10 @@ public class NotificationStackScrollLayout extends ViewGroup
    + 
    +     @Override
    +     public boolean isAntiFalsingNeeded() {
    ++        return onKeyguard();
    ++    }
    ++
    ++    private boolean onKeyguard() {
    +         return mPhoneStatusBar.getBarState() == StatusBarState.KEYGUARD;
    +     }
    + 
    +@@ -1233,7 +1244,7 @@ public class NotificationStackScrollLayout extends ViewGroup
    +         if (!isScrollingEnabled()) {
    +             return false;
    +         }
    +-        if (ev.getY() < mQsContainer.getBottom()) {
    ++        if (ev.getY() < mQsContainer.getBottom() && !mIsBeingDragged) {
    +             return false;
    +         }
    +         mForcedScroll = null;
    +@@ -1400,7 +1411,7 @@ public class NotificationStackScrollLayout extends ViewGroup
    +                         false /* onTop */,
    +                         false /* animate */);
    +             }
    +-            mOwnScrollY = range;
    ++            setOwnScrollY(range);
    +             scrollAmount = 0.0f;
    +         }
    +         return scrollAmount;
    +@@ -1431,7 +1442,7 @@ public class NotificationStackScrollLayout extends ViewGroup
    +             setOverScrolledPixels(currentTopPixels - newScrollY,
    +                     true /* onTop */,
    +                     false /* animate */);
    +-            mOwnScrollY = 0;
    ++            setOwnScrollY(0);
    +             scrollAmount = 0.0f;
    +         }
    +         return scrollAmount;
    +@@ -1646,7 +1657,7 @@ public class NotificationStackScrollLayout extends ViewGroup
    +     }
    + 
    +     private void customScrollTo(int y) {
    +-        mOwnScrollY = y;
    ++        setOwnScrollY(y);
    +         updateChildren();
    +     }
    + 
    +@@ -1657,7 +1668,7 @@ public class NotificationStackScrollLayout extends ViewGroup
    +             final int oldX = mScrollX;
    +             final int oldY = mOwnScrollY;
    +             mScrollX = scrollX;
    +-            mOwnScrollY = scrollY;
    ++            setOwnScrollY(scrollY);
    +             if (clampedY) {
    +                 springBack();
    +             } else {
    +@@ -1687,12 +1698,12 @@ public class NotificationStackScrollLayout extends ViewGroup
    +             if (overScrolledTop) {
    +                 onTop = true;
    +                 newAmount = -mOwnScrollY;
    +-                mOwnScrollY = 0;
    ++                setOwnScrollY(0);
    +                 mDontReportNextOverScroll = true;
    +             } else {
    +                 onTop = false;
    +                 newAmount = mOwnScrollY - scrollRange;
    +-                mOwnScrollY = scrollRange;
    ++                setOwnScrollY(scrollRange);
    +             }
    +             setOverScrollAmount(newAmount, onTop, false);
    +             setOverScrollAmount(0.0f, onTop, true);
    +@@ -1820,6 +1831,19 @@ public class NotificationStackScrollLayout extends ViewGroup
    +         if (scrollable != mScrollable) {
    +             mScrollable = scrollable;
    +             setFocusable(scrollable);
    ++            updateForwardAndBackwardScrollability();
    ++        }
    ++    }
    ++
    ++    private void updateForwardAndBackwardScrollability() {
    ++        boolean forwardScrollable = mScrollable && mOwnScrollY < getScrollRange();
    ++        boolean backwardsScrollable = mScrollable && mOwnScrollY > 0;
    ++        boolean changed = forwardScrollable != mForwardScrollable
    ++                || backwardsScrollable != mBackwardScrollable;
    ++        mForwardScrollable = forwardScrollable;
    ++        mBackwardScrollable = backwardsScrollable;
    ++        if (changed) {
    ++            sendAccessibilityEvent(AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED);
    +         }
    +     }
    + 
    +@@ -1829,24 +1853,34 @@ public class NotificationStackScrollLayout extends ViewGroup
    +         }
    +         updateBackgroundBounds();
    +         if (!mCurrentBounds.equals(mBackgroundBounds)) {
    +-            if (mAnimateNextBackgroundTop || mAnimateNextBackgroundBottom || areBoundsAnimating()) {
    ++            boolean animate = mAnimateNextBackgroundTop || mAnimateNextBackgroundBottom
    ++                    || areBoundsAnimating();
    ++            if (!isExpanded()) {
    ++                abortBackgroundAnimators();
    ++                animate = false;
    ++            }
    ++            if (animate) {
    +                 startBackgroundAnimation();
    +             } else {
    +                 mCurrentBounds.set(mBackgroundBounds);
    +                 applyCurrentBackgroundBounds();
    +             }
    +         } else {
    +-            if (mBottomAnimator != null) {
    +-                mBottomAnimator.cancel();
    +-            }
    +-            if (mTopAnimator != null) {
    +-                mTopAnimator.cancel();
    +-            }
    ++            abortBackgroundAnimators();
    +         }
    +         mAnimateNextBackgroundBottom = false;
    +         mAnimateNextBackgroundTop = false;
    +     }
    + 
    ++    private void abortBackgroundAnimators() {
    ++        if (mBottomAnimator != null) {
    ++            mBottomAnimator.cancel();
    ++        }
    ++        if (mTopAnimator != null) {
    ++            mTopAnimator.cancel();
    ++        }
    ++    }
    ++
    +     private boolean areBoundsAnimating() {
    +         return mBottomAnimator != null || mTopAnimator != null;
    +     }
    +@@ -1966,9 +2000,9 @@ public class NotificationStackScrollLayout extends ViewGroup
    +     }
    + 
    +     private void applyCurrentBackgroundBounds() {
    +-        if (!mFadingOut) {
    +-            mScrimController.setExcludedBackgroundArea(mCurrentBounds);
    +-        }
    ++        mScrimController.setExcludedBackgroundArea(
    ++                mFadingOut || mParentFadingOut || mAmbientState.isDark() ? null
    ++                        : mCurrentBounds);
    +         invalidate();
    +     }
    + 
    +@@ -1981,6 +2015,7 @@ public class NotificationStackScrollLayout extends ViewGroup
    +         if (!mIsExpanded) {
    +             mBackgroundBounds.top = 0;
    +             mBackgroundBounds.bottom = 0;
    ++            return;
    +         }
    +         ActivatableNotificationView firstView = mFirstVisibleBackgroundChild;
    +         int top = 0;
    +@@ -2078,13 +2113,13 @@ public class NotificationStackScrollLayout extends ViewGroup
    +             float topAmount = getCurrentOverScrollAmount(true);
    +             float bottomAmount = getCurrentOverScrollAmount(false);
    +             if (velocityY < 0 && topAmount > 0) {
    +-                mOwnScrollY -= (int) topAmount;
    ++                setOwnScrollY(mOwnScrollY - (int) topAmount);
    +                 mDontReportNextOverScroll = true;
    +                 setOverScrollAmount(0, true, false);
    +                 mMaxOverScroll = Math.abs(velocityY) / 1000f * getRubberBandFactor(true /* onTop */)
    +                         * mOverflingDistance + topAmount;
    +             } else if (velocityY > 0 && bottomAmount > 0) {
    +-                mOwnScrollY += bottomAmount;
    ++                setOwnScrollY((int) (mOwnScrollY + bottomAmount));
    +                 setOverScrollAmount(0, false, false);
    +                 mMaxOverScroll = Math.abs(velocityY) / 1000f
    +                         * getRubberBandFactor(false /* onTop */) * mOverflingDistance
    +@@ -2127,26 +2162,22 @@ public class NotificationStackScrollLayout extends ViewGroup
    +      */
    +     public void updateTopPadding(float qsHeight, boolean animate,
    +             boolean ignoreIntrinsicPadding) {
    +-        float start = qsHeight;
    +-        float stackHeight = getHeight() - start;
    ++        int topPadding = (int) qsHeight;
    +         int minStackHeight = getLayoutMinHeight();
    +-        if (stackHeight <= minStackHeight) {
    +-            float overflow = minStackHeight - stackHeight;
    +-            stackHeight = minStackHeight;
    +-            start = getHeight() - stackHeight;
    +-            mTopPaddingOverflow = overflow;
    ++        if (topPadding + minStackHeight > getHeight()) {
    ++            mTopPaddingOverflow = topPadding + minStackHeight - getHeight();
    +         } else {
    +             mTopPaddingOverflow = 0;
    +         }
    +-        setTopPadding(ignoreIntrinsicPadding ? (int) start : clampPadding((int) start),
    ++        setTopPadding(ignoreIntrinsicPadding ? topPadding : clampPadding(topPadding),
    +                 animate);
    +-        setStackHeight(mLastSetStackHeight);
    ++        setExpandedHeight(mExpandedHeight);
    +     }
    + 
    +     public int getLayoutMinHeight() {
    +         int firstChildMinHeight = getFirstChildIntrinsicHeight();
    +         return Math.min(firstChildMinHeight + mBottomStackPeekSize + mBottomStackSlowDownHeight,
    +-                mMaxLayoutHeight - mTopPadding);
    ++                mMaxLayoutHeight - mIntrinsicPadding);
    +     }
    + 
    +     public int getFirstChildIntrinsicHeight() {
    +@@ -2439,11 +2470,11 @@ public class NotificationStackScrollLayout extends ViewGroup
    +         if (endPosition <= mOwnScrollY) {
    +             // This child is fully scrolled of the top, so we have to deduct its height from the
    +             // scrollPosition
    +-            mOwnScrollY -= childHeight;
    ++            setOwnScrollY(mOwnScrollY - childHeight);
    +         } else if (startingPosition < mOwnScrollY) {
    +             // This child is currently being scrolled into, set the scroll position to the start of
    +             // this child
    +-            mOwnScrollY = startingPosition;
    ++            setOwnScrollY(startingPosition);
    +         }
    +     }
    + 
    +@@ -3024,7 +3055,7 @@ public class NotificationStackScrollLayout extends ViewGroup
    +     public void onExpansionStopped() {
    +         mIsExpansionChanging = false;
    +         if (!mIsExpanded) {
    +-            mOwnScrollY = 0;
    ++            setOwnScrollY(0);
    +             mPhoneStatusBar.resetUserExpandedStates();
    + 
    +             // lets make sure nothing is in the overlay / transient anymore
    +@@ -3057,7 +3088,7 @@ public class NotificationStackScrollLayout extends ViewGroup
    + 
    +     public void resetScrollPosition() {
    +         mScroller.abortAnimation();
    +-        mOwnScrollY = 0;
    ++        setOwnScrollY(0);
    +     }
    + 
    +     private void setIsExpanded(boolean isExpanded) {
    +@@ -3093,10 +3124,14 @@ public class NotificationStackScrollLayout extends ViewGroup
    +         updateScrollPositionOnExpandInBottom(view);
    +         clampScrollPosition();
    +         notifyHeightChangeListener(view);
    ++        ExpandableNotificationRow row = view instanceof ExpandableNotificationRow
    ++                ? (ExpandableNotificationRow) view
    ++                : null;
    ++        if (row != null && (row == mFirstVisibleBackgroundChild
    ++                || row.getNotificationParent() == mFirstVisibleBackgroundChild)) {
    ++            updateAlgorithmLayoutMinHeight();
    ++        }
    +         if (needsAnimation) {
    +-            ExpandableNotificationRow row = view instanceof ExpandableNotificationRow
    +-                    ? (ExpandableNotificationRow) view
    +-                    : null;
    +             requestAnimationOnViewResize(row);
    +         }
    +         requestChildrenUpdate();
    +@@ -3104,9 +3139,6 @@ public class NotificationStackScrollLayout extends ViewGroup
    + 
    +     @Override
    +     public void onReset(ExpandableView view) {
    +-        if (mIsExpanded && mAnimationsEnabled) {
    +-            mRequestViewResizeAnimationOnLayout = true;
    +-        }
    +         updateAnimationState(view);
    +         updateChronometerForChild(view);
    +     }
    +@@ -3125,7 +3157,7 @@ public class NotificationStackScrollLayout extends ViewGroup
    +                 }
    +                 int stackEnd = getStackEndPosition();
    +                 if (endPosition > stackEnd) {
    +-                    mOwnScrollY += endPosition - stackEnd;
    ++                    setOwnScrollY((int) (mOwnScrollY + endPosition - stackEnd));
    +                     mDisallowScrollingInThisMotion = true;
    +                 }
    +             }
    +@@ -3382,7 +3414,7 @@ public class NotificationStackScrollLayout extends ViewGroup
    +     }
    + 
    +     private int findDarkAnimationOriginIndex(@Nullable PointF screenLocation) {
    +-        if (screenLocation == null || screenLocation.y < mTopPadding + mTopPaddingOverflow) {
    ++        if (screenLocation == null || screenLocation.y < mTopPadding) {
    +             return AnimationEvent.DARK_ANIMATION_ORIGIN_INDEX_ABOVE;
    +         }
    +         if (screenLocation.y > getBottomMostNotificationBottom()) {
    +@@ -3687,15 +3719,14 @@ public class NotificationStackScrollLayout extends ViewGroup
    +     @Override
    +     public void onInitializeAccessibilityNodeInfoInternal(AccessibilityNodeInfo info) {
    +         super.onInitializeAccessibilityNodeInfoInternal(info);
    +-        final int scrollRange = getScrollRange();
    +-        if (scrollRange > 0) {
    ++        if (mScrollable) {
    +             info.setScrollable(true);
    +-            if (mScrollY > 0) {
    ++            if (mBackwardScrollable) {
    +                 info.addAction(
    +                         AccessibilityNodeInfo.AccessibilityAction.ACTION_SCROLL_BACKWARD);
    +                 info.addAction(AccessibilityNodeInfo.AccessibilityAction.ACTION_SCROLL_UP);
    +             }
    +-            if (mScrollY < scrollRange) {
    ++            if (mForwardScrollable) {
    +                 info.addAction(AccessibilityNodeInfo.AccessibilityAction.ACTION_SCROLL_FORWARD);
    +                 info.addAction(AccessibilityNodeInfo.AccessibilityAction.ACTION_SCROLL_DOWN);
    +             }
    +@@ -3847,11 +3878,7 @@ public class NotificationStackScrollLayout extends ViewGroup
    +     }
    + 
    +     private void updateFadingState() {
    +-        if (mFadingOut || mParentFadingOut || mAmbientState.isDark()) {
    +-            mScrimController.setExcludedBackgroundArea(null);
    +-        } else {
    +-            applyCurrentBackgroundBounds();
    +-        }
    ++        applyCurrentBackgroundBounds();
    +         updateSrcDrawing();
    +     }
    + 
    +@@ -3870,6 +3897,18 @@ public class NotificationStackScrollLayout extends ViewGroup
    +         mCurrentStackScrollState.removeViewStateForView(view);
    +     }
    + 
    ++    public void setQsExpanded(boolean qsExpanded) {
    ++        mQsExpanded = qsExpanded;
    ++        updateAlgorithmLayoutMinHeight();
    ++    }
    ++
    ++    public void setOwnScrollY(int ownScrollY) {
    ++        if (ownScrollY != mOwnScrollY) {
    ++            mOwnScrollY = ownScrollY;
    ++            updateForwardAndBackwardScrollability();
    ++        }
    ++    }
    ++
    +     /**
    +      * A listener that is notified when some child locations might have changed.
    +      */
    +@@ -3912,6 +3951,7 @@ public class NotificationStackScrollLayout extends ViewGroup
    +     private class NotificationSwipeHelper extends SwipeHelper {
    +         private static final long SHOW_GEAR_DELAY = 60;
    +         private static final long COVER_GEAR_DELAY = 4000;
    ++        private static final long SWIPE_GEAR_TIMING = 200;
    +         private CheckForDrag mCheckForDrag;
    +         private Runnable mFalsingCheck;
    +         private Handler mHandler;
    +@@ -4028,6 +4068,9 @@ public class NotificationStackScrollLayout extends ViewGroup
    + 
    +             boolean gestureTowardsGear = isTowardsGear(velocity, mCurrIconRow.isIconOnLeft());
    +             boolean gestureFastEnough = Math.abs(velocity) > getEscapeVelocity();
    ++            final double timeForGesture = ev.getEventTime() - ev.getDownTime();
    ++            final boolean showGearForSlowOnGoing = !canChildBeDismissed(animView)
    ++                && timeForGesture >= SWIPE_GEAR_TIMING;
    + 
    +             if (mGearSnappedTo && mCurrIconRow.isVisible()) {
    +                 if (mGearSnappedOnLeft == mCurrIconRow.isIconOnLeft()) {
    +@@ -4052,7 +4095,8 @@ public class NotificationStackScrollLayout extends ViewGroup
    +                 } else {
    +                     dismissOrSnapBack(animView, velocity, ev);
    +                 }
    +-            } else if ((!gestureFastEnough && swipedEnoughToShowGear(animView))
    ++            } else if (((!gestureFastEnough || showGearForSlowOnGoing)
    ++                    && swipedEnoughToShowGear(animView))
    +                     || gestureTowardsGear) {
    +                 // Gear has not been snapped to previously and this is gear revealing gesture
    +                 snapToGear(animView, velocity);
    +@@ -4088,7 +4132,7 @@ public class NotificationStackScrollLayout extends ViewGroup
    +             onDragCancelled(animView);
    + 
    +             // If we're on the lockscreen we want to false this.
    +-            if (mPhoneStatusBar.getBarState() == StatusBarState.KEYGUARD) {
    ++            if (isAntiFalsingNeeded()) {
    +                 mHandler.removeCallbacks(mFalsingCheck);
    +                 mHandler.postDelayed(mFalsingCheck, COVER_GEAR_DELAY);
    +             }
    +@@ -4104,13 +4148,9 @@ public class NotificationStackScrollLayout extends ViewGroup
    +             final float multiplier = canChildBeDismissed(animView) ? 0.4f : 0.2f;
    +             final float snapBackThreshold = getSpaceForGear(animView) * multiplier;
    +             final float translation = getTranslation(animView);
    +-            final boolean fromLeft = translation > 0;
    +-            final float absTrans = Math.abs(translation);
    +-            final float notiThreshold = getSize(mTranslatingParentView) * 0.4f;
    +-
    +-            return mCurrIconRow.isVisible() && (mCurrIconRow.isIconOnLeft()
    +-                    ? (translation > snapBackThreshold && translation <= notiThreshold)
    +-                    : (translation < -snapBackThreshold && translation >= -notiThreshold));
    ++            return !swipedFarEnough() && mCurrIconRow.isVisible() && (mCurrIconRow.isIconOnLeft()
    ++                    ? translation > snapBackThreshold
    ++                    : translation < -snapBackThreshold);
    +         }
    + 
    +         @Override
    +@@ -4151,13 +4191,11 @@ public class NotificationStackScrollLayout extends ViewGroup
    +                 final int rx = (int) ev.getRawX();
    +                 final int ry = (int) ev.getRawY();
    + 
    +-                getLocationOnScreen(mTempInt2);
    +-                int[] location = new int[2];
    +-                view.getLocationOnScreen(location);
    +-                final int x = location[0] - mTempInt2[0];
    +-                final int y = location[1] - mTempInt2[1];
    ++                view.getLocationOnScreen(mTempInt2);
    ++                final int x = mTempInt2[0];
    ++                final int y = mTempInt2[1];
    +                 Rect rect = new Rect(x, y, x + view.getWidth(), y + height);
    +-                if (!rect.contains((int) rx, (int) ry)) {
    ++                if (!rect.contains(rx, ry)) {
    +                     // Touch was outside visible guts / gear notification, close what's visible
    +                     mPhoneStatusBar.dismissPopups(-1, -1, true /* resetGear */, true /* animate */);
    +                 }
    +diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/tv/TvStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/tv/TvStatusBar.java
    +index 2d4900b..3c83921 100644
    +--- a/packages/SystemUI/src/com/android/systemui/statusbar/tv/TvStatusBar.java
    ++++ b/packages/SystemUI/src/com/android/systemui/statusbar/tv/TvStatusBar.java
    +@@ -19,7 +19,6 @@ package com.android.systemui.statusbar.tv;
    + import android.content.ComponentName;
    + import android.graphics.Rect;
    + import android.os.IBinder;
    +-import android.os.RemoteException;
    + import android.service.notification.NotificationListenerService.RankingMap;
    + import android.service.notification.StatusBarNotification;
    + import android.view.View;
    +@@ -36,16 +35,6 @@ import com.android.systemui.tv.pip.PipManager;
    + 
    + public class TvStatusBar extends BaseStatusBar {
    + 
    +-    /**
    +-     * Tracking calls to View.setSystemUiVisibility().
    +-     */
    +-    int mSystemUiVisibility = View.SYSTEM_UI_FLAG_VISIBLE;
    +-
    +-    /**
    +-     * Last value sent to window manager.
    +-     */
    +-    private int mLastDispatchedSystemUiVisibility = ~View.SYSTEM_UI_FLAG_VISIBLE;
    +-
    +     @Override
    +     public void setIcon(String slot, StatusBarIcon icon) {
    +     }
    +@@ -224,40 +213,6 @@ public class TvStatusBar extends BaseStatusBar {
    +         putComponent(TvStatusBar.class, this);
    +     }
    + 
    +-    /**
    +-     * Updates the visibility of the picture-in-picture.
    +-     */
    +-    public void updatePipVisibility(boolean visible) {
    +-        if (visible) {
    +-            mSystemUiVisibility |= View.TV_PICTURE_IN_PICTURE_VISIBLE;
    +-        } else {
    +-            mSystemUiVisibility &= ~View.TV_PICTURE_IN_PICTURE_VISIBLE;
    +-        }
    +-        notifyUiVisibilityChanged(mSystemUiVisibility);
    +-    }
    +-
    +-    /**
    +-     * Updates the visibility of the Recents
    +-     */
    +-    public void updateRecentsVisibility(boolean visible) {
    +-        if (visible) {
    +-            mSystemUiVisibility |= View.RECENT_APPS_VISIBLE;
    +-        } else {
    +-            mSystemUiVisibility &= ~View.RECENT_APPS_VISIBLE;
    +-        }
    +-        notifyUiVisibilityChanged(mSystemUiVisibility);
    +-    }
    +-
    +-    private void notifyUiVisibilityChanged(int vis) {
    +-        try {
    +-            if (mLastDispatchedSystemUiVisibility != vis) {
    +-                mWindowManagerService.statusBarVisibilityChanged(vis);
    +-                mLastDispatchedSystemUiVisibility = vis;
    +-            }
    +-        } catch (RemoteException ex) {
    +-        }
    +-    }
    +-
    +     @Override
    +     public void handleSystemNavigationKey(int arg1) {
    +         // Not implemented
    +diff --git a/packages/SystemUI/src/com/android/systemui/tuner/TunerFragment.java b/packages/SystemUI/src/com/android/systemui/tuner/TunerFragment.java
    +index 70f2fdc..ba50161 100644
    +--- a/packages/SystemUI/src/com/android/systemui/tuner/TunerFragment.java
    ++++ b/packages/SystemUI/src/com/android/systemui/tuner/TunerFragment.java
    +@@ -59,7 +59,10 @@ public class TunerFragment extends PreferenceFragment {
    +     @Override
    +     public void onActivityCreated(Bundle savedInstanceState) {
    +         super.onActivityCreated(savedInstanceState);
    +-        getActivity().getActionBar().setDisplayHomeAsUpEnabled(true);
    ++
    ++        if (getActivity().getActionBar() != null) {
    ++            getActivity().getActionBar().setDisplayHomeAsUpEnabled(true);
    ++        }
    +     }
    + 
    +     @Override
    +diff --git a/packages/SystemUI/src/com/android/systemui/tv/pip/PipManager.java b/packages/SystemUI/src/com/android/systemui/tv/pip/PipManager.java
    +index 5e4854c..085e003 100644
    +--- a/packages/SystemUI/src/com/android/systemui/tv/pip/PipManager.java
    ++++ b/packages/SystemUI/src/com/android/systemui/tv/pip/PipManager.java
    +@@ -78,6 +78,18 @@ public class PipManager {
    +         sSettingsPackageAndClassNamePairList.add(new Pair<String, String>(
    +                 "com.google.android.leanbacklauncher",
    +                 "com.google.android.leanbacklauncher.settings.HomeScreenSettingsActivity"));
    ++        sSettingsPackageAndClassNamePairList.add(new Pair<String, String>(
    ++                "com.google.android.apps.mediashell",
    ++                "com.google.android.apps.mediashell.settings.CastSettingsActivity"));
    ++        sSettingsPackageAndClassNamePairList.add(new Pair<String, String>(
    ++                "com.google.android.katniss",
    ++                "com.google.android.katniss.setting.SpeechSettingsActivity"));
    ++        sSettingsPackageAndClassNamePairList.add(new Pair<String, String>(
    ++                "com.google.android.katniss",
    ++                "com.google.android.katniss.setting.SearchSettingsActivity"));
    ++        sSettingsPackageAndClassNamePairList.add(new Pair<String, String>(
    ++                "com.google.android.gsf.notouch",
    ++                "com.google.android.gsf.notouch.UsageDiagnosticsSettingActivity"));
    +     }
    + 
    +     /**
    +@@ -711,10 +723,7 @@ public class PipManager {
    +         return mPipRecentsOverlayManager;
    +     }
    + 
    +-    private void updatePipVisibility(boolean visible) {
    +-        TvStatusBar statusBar = ((SystemUIApplication) mContext).getComponent(TvStatusBar.class);
    +-        if (statusBar != null) {
    +-            statusBar.updatePipVisibility(visible);
    +-        }
    ++    private void updatePipVisibility(final boolean visible) {
    ++        SystemServicesProxy.getInstance(mContext).setTvPipVisibility(visible);
    +     }
    + }
    +diff --git a/packages/SystemUI/tests/Android.mk b/packages/SystemUI/tests/Android.mk
    +index c9c5805..d122ccc 100644
    +--- a/packages/SystemUI/tests/Android.mk
    ++++ b/packages/SystemUI/tests/Android.mk
    +@@ -58,6 +58,42 @@ LOCAL_STATIC_JAVA_LIBRARIES := \
    + # UI it doesn't own. This is necessary to allow screenshots to be taken
    + LOCAL_CERTIFICATE := platform
    + 
    ++# Provide jack a list of classes to exclude from code coverage.
    ++# This is needed because the SystemUITests compile SystemUI source directly, rather than using
    ++# LOCAL_INSTRUMENTATION_FOR := SystemUI.
    ++#
    ++# We want to exclude the test classes from code coverage measurements, but they share the same
    ++# package as the rest of SystemUI so they can't be easily filtered by package name.
    ++#
    ++# Generate a comma separated list of patterns based on the test source files under src/
    ++# SystemUI classes are in ../src/ so they won't be excluded.
    ++# Example:
    ++#   Input files: src/com/android/systemui/Test.java src/com/android/systemui/AnotherTest.java
    ++#   Generated exclude list: com.android.systemui.Test*,com.android.systemui.AnotherTest*
    ++
    ++# Filter all src files under src/ to just java files
    ++local_java_files := $(filter %.java,$(call all-java-files-under, src))
    ++# Transform java file names into full class names.
    ++# This only works if the class name matches the file name and the directory structure
    ++# matches the package.
    ++local_classes := $(subst /,.,$(patsubst src/%.java,%,$(local_java_files)))
    ++local_comma := ,
    ++local_empty :=
    ++local_space := $(local_empty) $(local_empty)
    ++# Convert class name list to jacoco exclude list
    ++# This appends a * to all classes and replace the space separators with commas.
    ++jacoco_exclude := $(subst $(space),$(comma),$(patsubst %,%*,$(local_classes)))
    ++
    ++LOCAL_JACK_COVERAGE_INCLUDE_FILTER := com.android.systemui.*
    ++LOCAL_JACK_COVERAGE_EXCLUDE_FILTER := com.android.systemui.tests.*,$(jacoco_exclude)
    ++
    + include frameworks/base/packages/SettingsLib/common.mk
    + 
    + include $(BUILD_PACKAGE)
    ++
    ++# Reset variables
    ++local_java_files :=
    ++local_classes :=
    ++local_comma :=
    ++local_space :=
    ++jacoco_exclude :=
    +diff --git a/packages/VpnDialogs/res/values-ro/strings.xml b/packages/VpnDialogs/res/values-ro/strings.xml
    +index 4865e96..e2e1e44 100644
    +--- a/packages/VpnDialogs/res/values-ro/strings.xml
    ++++ b/packages/VpnDialogs/res/values-ro/strings.xml
    +@@ -25,5 +25,5 @@
    +     <string name="duration" msgid="3584782459928719435">"Durată:"</string>
    +     <string name="data_transmitted" msgid="7988167672982199061">"Trimise:"</string>
    +     <string name="data_received" msgid="4062776929376067820">"Primite:"</string>
    +-    <string name="data_value_format" msgid="2192466557826897580">"<xliff:g id="NUMBER_0">%1$s</xliff:g> (de) octeți/<xliff:g id="NUMBER_1">%2$s</xliff:g> (de) pachete"</string>
    ++    <string name="data_value_format" msgid="2192466557826897580">"<xliff:g id="NUMBER_0">%1$s</xliff:g>   octeți/<xliff:g id="NUMBER_1">%2$s</xliff:g>   pachete"</string>
    + </resources>
    +diff --git a/packages/WallpaperBackup/src/com/android/wallpaperbackup/WallpaperBackupAgent.java b/packages/WallpaperBackup/src/com/android/wallpaperbackup/WallpaperBackupAgent.java
    +index 3a82f88..ff934ef 100644
    +--- a/packages/WallpaperBackup/src/com/android/wallpaperbackup/WallpaperBackupAgent.java
    ++++ b/packages/WallpaperBackup/src/com/android/wallpaperbackup/WallpaperBackupAgent.java
    +@@ -147,11 +147,12 @@ public class WallpaperBackupAgent extends BackupAgent {
    +             }
    + 
    +             // only back up the wallpapers if we've been told they're eligible
    +-            if ((sysEligible || lockEligible) && mWallpaperInfo.exists()) {
    ++            if (mWallpaperInfo.exists()) {
    +                 if (sysChanged || lockChanged || !infoStage.exists()) {
    +                     if (DEBUG) Slog.v(TAG, "New wallpaper configuration; copying");
    +                     FileUtils.copyFileOrThrow(mWallpaperInfo, infoStage);
    +                 }
    ++                if (DEBUG) Slog.v(TAG, "Storing wallpaper metadata");
    +                 fullBackupFile(infoStage, data);
    +             }
    +             if (sysEligible && mWallpaperFile.exists()) {
    +@@ -159,6 +160,7 @@ public class WallpaperBackupAgent extends BackupAgent {
    +                     if (DEBUG) Slog.v(TAG, "New system wallpaper; copying");
    +                     FileUtils.copyFileOrThrow(mWallpaperFile, imageStage);
    +                 }
    ++                if (DEBUG) Slog.v(TAG, "Storing system wallpaper image");
    +                 fullBackupFile(imageStage, data);
    +                 prefs.edit().putInt(SYSTEM_GENERATION, sysGeneration).apply();
    +             }
    +@@ -169,6 +171,7 @@ public class WallpaperBackupAgent extends BackupAgent {
    +                     if (DEBUG) Slog.v(TAG, "New lock wallpaper; copying");
    +                     FileUtils.copyFileOrThrow(mLockWallpaperFile, lockImageStage);
    +                 }
    ++                if (DEBUG) Slog.v(TAG, "Storing lock wallpaper image");
    +                 fullBackupFile(lockImageStage, data);
    +                 prefs.edit().putInt(LOCK_GENERATION, lockGeneration).apply();
    +             }
    +diff --git a/proto/src/metrics_constants.proto b/proto/src/metrics_constants.proto
    +index 5099db7..8a0dfe5 100644
    +--- a/proto/src/metrics_constants.proto
    ++++ b/proto/src/metrics_constants.proto
    +@@ -2207,7 +2207,12 @@ message MetricsEvent {
    +     // CATEGORY: SETTINGS
    +     ACTION_AMBIENT_DISPLAY = 495;
    + 
    ++    // ACTION: Settings -> [sub settings activity] -> Options menu -> Help & Support
    ++    //   SUBTYPE: sub settings classname
    ++    ACTION_SETTING_HELP_AND_FEEDBACK = 496;
    ++
    +     // ---- End N-MR1 Constants, all N-MR1 constants go above this line ----
    ++
    +     // Add new aosp constants above this line.
    +     // END OF AOSP CONSTANTS
    +   }
    +diff --git a/rs/jni/android_renderscript_RenderScript.cpp b/rs/jni/android_renderscript_RenderScript.cpp
    +index aa2a607..37cbd31 100644
    +--- a/rs/jni/android_renderscript_RenderScript.cpp
    ++++ b/rs/jni/android_renderscript_RenderScript.cpp
    +@@ -632,7 +632,7 @@ nScriptIntrinsicBLAS_Single(JNIEnv *_env, jobject _this, jlong con, jlong id, ji
    +     in_allocs[2] = (RsAllocation)C;
    + 
    +     rsScriptForEachMulti((RsContext)con, (RsScript)id, 0,
    +-                         in_allocs, sizeof(in_allocs), nullptr,
    ++                         in_allocs, NELEM(in_allocs), nullptr,
    +                          &call, sizeof(call), nullptr, 0);
    + }
    + 
    +diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityGestureDetector.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityGestureDetector.java
    +index 562d950..582b19b 100644
    +--- a/services/accessibility/java/com/android/server/accessibility/AccessibilityGestureDetector.java
    ++++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityGestureDetector.java
    +@@ -341,6 +341,8 @@ class AccessibilityGestureDetector extends GestureDetector.SimpleOnGestureListen
    +         mDoubleTapDetected = false;
    +         mSecondFingerDoubleTap = false;
    +         mGestureStarted = false;
    ++        mGestureDetector.onTouchEvent(MotionEvent.obtain(0L, 0L, MotionEvent.ACTION_CANCEL,
    ++                0.0f, 0.0f, 0));
    +         cancelGesture();
    +     }
    + 
    +diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
    +index 695ea60..e00178f 100644
    +--- a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
    ++++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
    +@@ -2208,6 +2208,8 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub {
    + 
    +         AccessibilityServiceInfo mAccessibilityServiceInfo;
    + 
    ++        // The service that's bound to this instance. Whenever this value is non-null, this
    ++        // object is registered as a death recipient
    +         IBinder mService;
    + 
    +         IAccessibilityServiceClient mServiceInterface;
    +@@ -2342,14 +2344,14 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub {
    +                 }
    +             } else {
    +                 userState.mBindingServices.add(mComponentName);
    +-                mService = userState.mUiAutomationServiceClient.asBinder();
    +                 mMainHandler.post(new Runnable() {
    +                     @Override
    +                     public void run() {
    +                         // Simulate asynchronous connection since in onServiceConnected
    +                         // we may modify the state data in case of an error but bind is
    +                         // called while iterating over the data and bad things can happen.
    +-                        onServiceConnected(mComponentName, mService);
    ++                        onServiceConnected(mComponentName,
    ++                                userState.mUiAutomationServiceClient.asBinder());
    +                     }
    +                 });
    +                 userState.mUiAutomationService = this;
    +@@ -2441,7 +2443,19 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub {
    +         @Override
    +         public void onServiceConnected(ComponentName componentName, IBinder service) {
    +             synchronized (mLock) {
    +-                mService = service;
    ++                if (mService != service) {
    ++                    if (mService != null) {
    ++                        mService.unlinkToDeath(this, 0);
    ++                    }
    ++                    mService = service;
    ++                    try {
    ++                        mService.linkToDeath(this, 0);
    ++                    } catch (RemoteException re) {
    ++                        Slog.e(LOG_TAG, "Failed registering death link");
    ++                        binderDied();
    ++                        return;
    ++                    }
    ++                }
    +                 mServiceInterface = IAccessibilityServiceClient.Stub.asInterface(service);
    +                 UserState userState = getUserStateLocked(mUserId);
    +                 addServiceLocked(this, userState);
    +@@ -3075,7 +3089,6 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub {
    +         }
    + 
    +         public void onAdded() throws RemoteException {
    +-            linkToOwnDeathLocked();
    +             final long identity = Binder.clearCallingIdentity();
    +             try {
    +                 mWindowManagerService.addWindowToken(mOverlayWindowToken,
    +@@ -3092,17 +3105,6 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub {
    +             } finally {
    +                 Binder.restoreCallingIdentity(identity);
    +             }
    +-            unlinkToOwnDeathLocked();
    +-        }
    +-
    +-        public void linkToOwnDeathLocked() throws RemoteException {
    +-            mService.linkToDeath(this, 0);
    +-        }
    +-
    +-        public void unlinkToOwnDeathLocked() {
    +-            if (mService != null) {
    +-                mService.unlinkToDeath(this, 0);
    +-            }
    +         }
    + 
    +         public void resetLocked() {
    +@@ -3115,7 +3117,10 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub {
    +             } catch (RemoteException re) {
    +                 /* ignore */
    +             }
    +-            mService = null;
    ++            if (mService != null) {
    ++                mService.unlinkToDeath(this, 0);
    ++                mService = null;
    ++            }
    +             mServiceInterface = null;
    +         }
    + 
    +@@ -3678,13 +3683,6 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub {
    +                 Rect boundsInScreen = mTempRect;
    +                 focus.getBoundsInScreen(boundsInScreen);
    + 
    +-                // Clip to the window bounds.
    +-                Rect windowBounds = mTempRect1;
    +-                getWindowBounds(focus.getWindowId(), windowBounds);
    +-                if (!boundsInScreen.intersect(windowBounds)) {
    +-                    return false;
    +-                }
    +-
    +                 // Apply magnification if needed.
    +                 MagnificationSpec spec = getCompatibleMagnificationSpecLocked(focus.getWindowId());
    +                 if (spec != null && !spec.isNop()) {
    +@@ -3692,6 +3690,13 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub {
    +                     boundsInScreen.scale(1 / spec.scale);
    +                 }
    + 
    ++                // Clip to the window bounds.
    ++                Rect windowBounds = mTempRect1;
    ++                getWindowBounds(focus.getWindowId(), windowBounds);
    ++                if (!boundsInScreen.intersect(windowBounds)) {
    ++                    return false;
    ++                }
    ++
    +                 // Clip to the screen bounds.
    +                 Point screenSize = mTempPoint;
    +                 mDefaultDisplay.getRealSize(screenSize);
    +diff --git a/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java b/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java
    +index 9d3889b..b5fcb5c 100644
    +--- a/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java
    ++++ b/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java
    +@@ -2266,6 +2266,7 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku
    +         pw.print(info.updatePeriodMillis);
    +         pw.print(" resizeMode=");
    +         pw.print(info.resizeMode);
    ++        pw.print(" widgetCategory=");
    +         pw.print(info.widgetCategory);
    +         pw.print(" autoAdvanceViewId=");
    +         pw.print(info.autoAdvanceViewId);
    +diff --git a/services/backup/java/com/android/server/backup/BackupManagerService.java b/services/backup/java/com/android/server/backup/BackupManagerService.java
    +index 497eac9..8424b39 100644
    +--- a/services/backup/java/com/android/server/backup/BackupManagerService.java
    ++++ b/services/backup/java/com/android/server/backup/BackupManagerService.java
    +@@ -6057,7 +6057,11 @@ public class BackupManagerService {
    +                                         // the app developer's cert, so they're different on every
    +                                         // device.
    +                                         if (signaturesMatch(sigs, pkgInfo)) {
    +-                                            if (pkgInfo.versionCode >= version) {
    ++                                            if ((pkgInfo.applicationInfo.flags
    ++                                                    & ApplicationInfo.FLAG_RESTORE_ANY_VERSION) != 0) {
    ++                                                Slog.i(TAG, "Package has restoreAnyVersion; taking data");
    ++                                                policy = RestorePolicy.ACCEPT;
    ++                                            } else if (pkgInfo.versionCode >= version) {
    +                                                 Slog.i(TAG, "Sig + version match; taking data");
    +                                                 policy = RestorePolicy.ACCEPT;
    +                                             } else {
    +@@ -7479,7 +7483,11 @@ if (MORE_DEBUG) Slog.v(TAG, "   + got " + nRead + "; now wanting " + (size - soF
    +                                         // the app developer's cert, so they're different on every
    +                                         // device.
    +                                         if (signaturesMatch(sigs, pkgInfo)) {
    +-                                            if (pkgInfo.versionCode >= version) {
    ++                                            if ((pkgInfo.applicationInfo.flags
    ++                                                    & ApplicationInfo.FLAG_RESTORE_ANY_VERSION) != 0) {
    ++                                                Slog.i(TAG, "Package has restoreAnyVersion; taking data");
    ++                                                policy = RestorePolicy.ACCEPT;
    ++                                            } else if (pkgInfo.versionCode >= version) {
    +                                                 Slog.i(TAG, "Sig + version match; taking data");
    +                                                 policy = RestorePolicy.ACCEPT;
    +                                             } else {
    +diff --git a/services/core/Android.mk b/services/core/Android.mk
    +index b965ce3..3210542 100644
    +--- a/services/core/Android.mk
    ++++ b/services/core/Android.mk
    +@@ -8,6 +8,7 @@ LOCAL_AIDL_INCLUDES := system/netd/server/binder
    + 
    + LOCAL_SRC_FILES += \
    +     $(call all-java-files-under,java) \
    ++    $(call all-proto-files-under, proto) \
    +     java/com/android/server/EventLogTags.logtags \
    +     java/com/android/server/am/EventLogTags.logtags \
    +     ../../../../system/netd/server/binder/android/net/INetd.aidl \
    +@@ -18,6 +19,7 @@ LOCAL_AIDL_INCLUDES += \
    + 
    + LOCAL_JAVA_LIBRARIES := services.net telephony-common
    + LOCAL_STATIC_JAVA_LIBRARIES := tzdata_update
    ++LOCAL_PROTOC_OPTIMIZE_TYPE := nano
    + 
    + ifneq ($(INCREMENTAL_BUILDS),)
    +     LOCAL_PROGUARD_ENABLED := disabled
    +diff --git a/services/core/java/com/android/server/AppOpsService.java b/services/core/java/com/android/server/AppOpsService.java
    +index b5b0cd8..c95b9d5 100644
    +--- a/services/core/java/com/android/server/AppOpsService.java
    ++++ b/services/core/java/com/android/server/AppOpsService.java
    +@@ -597,7 +597,6 @@ public class AppOpsService extends IAppOpsService.Stub {
    +         ArrayList<Callback> repCbs = null;
    +         code = AppOpsManager.opToSwitch(code);
    +         synchronized (this) {
    +-            UidState uidState = getUidStateLocked(uid, false);
    +             Op op = getOpLocked(code, uid, packageName, true);
    +             if (op != null) {
    +                 if (op.mode != mode) {
    +@@ -875,7 +874,7 @@ public class AppOpsService extends IAppOpsService.Stub {
    +             return AppOpsManager.MODE_IGNORED;
    +         }
    +         synchronized (this) {
    +-            if (isOpRestricted(uid, code, resolvedPackageName)) {
    ++            if (isOpRestrictedLocked(uid, code, resolvedPackageName)) {
    +                 return AppOpsManager.MODE_IGNORED;
    +             }
    +             code = AppOpsManager.opToSwitch(code);
    +@@ -973,7 +972,7 @@ public class AppOpsService extends IAppOpsService.Stub {
    +     public int checkPackage(int uid, String packageName) {
    +         Preconditions.checkNotNull(packageName);
    +         synchronized (this) {
    +-            if (getOpsRawLocked(uid, packageName, true) != null) {
    ++            if (packageName != null && getOpsRawLocked(uid, packageName, true) != null) {
    +                 return AppOpsManager.MODE_ALLOWED;
    +             } else {
    +                 return AppOpsManager.MODE_ERRORED;
    +@@ -1024,7 +1023,7 @@ public class AppOpsService extends IAppOpsService.Stub {
    +                 return AppOpsManager.MODE_ERRORED;
    +             }
    +             Op op = getOpLocked(ops, code, true);
    +-            if (isOpRestricted(uid, code, packageName)) {
    ++            if (isOpRestrictedLocked(uid, code, packageName)) {
    +                 return AppOpsManager.MODE_IGNORED;
    +             }
    +             if (op.duration == -1) {
    +@@ -1082,7 +1081,7 @@ public class AppOpsService extends IAppOpsService.Stub {
    +                 return AppOpsManager.MODE_ERRORED;
    +             }
    +             Op op = getOpLocked(ops, code, true);
    +-            if (isOpRestricted(uid, code, resolvedPackageName)) {
    ++            if (isOpRestrictedLocked(uid, code, resolvedPackageName)) {
    +                 return AppOpsManager.MODE_IGNORED;
    +             }
    +             final int switchCode = AppOpsManager.opToSwitch(code);
    +@@ -1308,7 +1307,7 @@ public class AppOpsService extends IAppOpsService.Stub {
    +         return op;
    +     }
    + 
    +-    private boolean isOpRestricted(int uid, int code, String packageName) {
    ++    private boolean isOpRestrictedLocked(int uid, int code, String packageName) {
    +         int userHandle = UserHandle.getUserId(uid);
    +         final int restrictionSetCount = mOpUserRestrictions.size();
    + 
    +@@ -1533,8 +1532,6 @@ public class AppOpsService extends IAppOpsService.Stub {
    + 
    +     void writeState() {
    +         synchronized (mFile) {
    +-            List<AppOpsManager.PackageOps> allOps = getPackagesForOps(null);
    +-
    +             FileOutputStream stream;
    +             try {
    +                 stream = mFile.startWrite();
    +@@ -1543,15 +1540,33 @@ public class AppOpsService extends IAppOpsService.Stub {
    +                 return;
    +             }
    + 
    ++            SparseArray<UidState> outUidStates = null;
    ++            synchronized (this) {
    ++                final int uidStateCount = mUidStates.size();
    ++                for (int i = 0; i < uidStateCount; i++) {
    ++                    UidState uidState = mUidStates.valueAt(i);
    ++                    SparseIntArray opModes = uidState.opModes;
    ++                    if (opModes != null && opModes.size() > 0) {
    ++                        UidState outUidState = new UidState(uidState.uid);
    ++                        outUidState.opModes = opModes.clone();
    ++                        if (outUidStates == null) {
    ++                            outUidStates = new SparseArray<>();
    ++                        }
    ++                        outUidStates.put(mUidStates.keyAt(i), outUidState);
    ++                    }
    ++                }
    ++            }
    ++            List<AppOpsManager.PackageOps> allOps = getPackagesForOps(null);
    ++
    +             try {
    +                 XmlSerializer out = new FastXmlSerializer();
    +                 out.setOutput(stream, StandardCharsets.UTF_8.name());
    +                 out.startDocument(null, true);
    +                 out.startTag(null, "app-ops");
    + 
    +-                final int uidStateCount = mUidStates.size();
    ++                final int uidStateCount = outUidStates != null ? outUidStates.size() : 0;
    +                 for (int i = 0; i < uidStateCount; i++) {
    +-                    UidState uidState = mUidStates.valueAt(i);
    ++                    UidState uidState = outUidStates.valueAt(i);
    +                     if (uidState.opModes != null && uidState.opModes.size() > 0) {
    +                         out.startTag(null, "uid");
    +                         out.attribute(null, "n", Integer.toString(uidState.uid));
    +@@ -2210,24 +2225,32 @@ public class AppOpsService extends IAppOpsService.Stub {
    + 
    +     private void setUserRestrictionNoCheck(int code, boolean restricted, IBinder token,
    +             int userHandle, String[] exceptionPackages) {
    +-        ClientRestrictionState restrictionState = mOpUserRestrictions.get(token);
    ++        boolean notifyChange = false;
    + 
    +-        if (restrictionState == null) {
    +-            try {
    +-                restrictionState = new ClientRestrictionState(token);
    +-            } catch (RemoteException e) {
    +-                return;
    ++        synchronized (AppOpsService.this) {
    ++            ClientRestrictionState restrictionState = mOpUserRestrictions.get(token);
    ++
    ++            if (restrictionState == null) {
    ++                try {
    ++                    restrictionState = new ClientRestrictionState(token);
    ++                } catch (RemoteException e) {
    ++                    return;
    ++                }
    ++                mOpUserRestrictions.put(token, restrictionState);
    +             }
    +-            mOpUserRestrictions.put(token, restrictionState);
    +-        }
    + 
    +-        if (restrictionState.setRestriction(code, restricted, exceptionPackages, userHandle)) {
    +-            notifyWatchersOfChange(code);
    ++            if (restrictionState.setRestriction(code, restricted, exceptionPackages, userHandle)) {
    ++                notifyChange = true;
    ++            }
    ++
    ++            if (restrictionState.isDefault()) {
    ++                mOpUserRestrictions.remove(token);
    ++                restrictionState.destroy();
    ++            }
    +         }
    + 
    +-        if (restrictionState.isDefault()) {
    +-            mOpUserRestrictions.remove(token);
    +-            restrictionState.destroy();
    ++        if (notifyChange) {
    ++            notifyWatchersOfChange(code);
    +         }
    +     }
    + 
    +@@ -2263,10 +2286,12 @@ public class AppOpsService extends IAppOpsService.Stub {
    +     @Override
    +     public void removeUser(int userHandle) throws RemoteException {
    +         checkSystemUid("removeUser");
    +-        final int tokenCount = mOpUserRestrictions.size();
    +-        for (int i = tokenCount - 1; i >= 0; i--) {
    +-            ClientRestrictionState opRestrictions = mOpUserRestrictions.valueAt(i);
    +-            opRestrictions.removeUser(userHandle);
    ++        synchronized (AppOpsService.this) {
    ++            final int tokenCount = mOpUserRestrictions.size();
    ++            for (int i = tokenCount - 1; i >= 0; i--) {
    ++                ClientRestrictionState opRestrictions = mOpUserRestrictions.valueAt(i);
    ++                opRestrictions.removeUser(userHandle);
    ++            }
    +         }
    +     }
    + 
    +diff --git a/services/core/java/com/android/server/BluetoothManagerService.java b/services/core/java/com/android/server/BluetoothManagerService.java
    +index 8c5887f..52be811 100644
    +--- a/services/core/java/com/android/server/BluetoothManagerService.java
    ++++ b/services/core/java/com/android/server/BluetoothManagerService.java
    +@@ -203,7 +203,7 @@ class BluetoothManagerService extends IBluetoothManager.Stub {
    +                     } finally {
    +                         mBluetoothLock.readLock().unlock();
    +                     }
    +-                    Slog.d(TAG, "state" + st);
    ++                    Slog.d(TAG, "Airplane Mode change - current state: " + st);
    + 
    +                     if (isAirplaneModeOn()) {
    +                         // Clear registered LE apps to force shut-off
    +@@ -217,6 +217,7 @@ class BluetoothManagerService extends IBluetoothManager.Stub {
    +                                 mBluetoothLock.readLock().lock();
    +                                 if (mBluetooth != null) {
    +                                     mBluetooth.onBrEdrDown();
    ++                                    mEnable = false;
    +                                     mEnableExternal = false;
    +                                 }
    +                             } catch (RemoteException e) {
    +@@ -266,6 +267,7 @@ class BluetoothManagerService extends IBluetoothManager.Stub {
    +         mContext.registerReceiver(mReceiver, filter);
    +         loadStoredNameAndAddress();
    +         if (isBluetoothPersistedStateOn()) {
    ++            if (DBG) Slog.d(TAG, "Startup: Bluetooth persisted state is ON.");
    +             mEnableExternal = true;
    +         }
    + 
    +@@ -292,8 +294,10 @@ class BluetoothManagerService extends IBluetoothManager.Stub {
    +      *  Returns true if the Bluetooth saved state is "on"
    +      */
    +     private final boolean isBluetoothPersistedStateOn() {
    +-        return Settings.Global.getInt(mContentResolver,
    +-                Settings.Global.BLUETOOTH_ON, 0) != BLUETOOTH_OFF;
    ++        int state = Settings.Global.getInt(mContentResolver,
    ++                                           Settings.Global.BLUETOOTH_ON, -1);
    ++        if (DBG) Slog.d(TAG, "Bluetooth persisted state: " + state);
    ++        return state != BLUETOOTH_OFF;
    +     }
    + 
    +     /**
    +@@ -301,7 +305,7 @@ class BluetoothManagerService extends IBluetoothManager.Stub {
    +      */
    +     private final boolean isBluetoothPersistedStateOnBluetooth() {
    +         return Settings.Global.getInt(mContentResolver,
    +-                Settings.Global.BLUETOOTH_ON, 0) == BLUETOOTH_ON_BLUETOOTH;
    ++                Settings.Global.BLUETOOTH_ON, BLUETOOTH_ON_BLUETOOTH) == BLUETOOTH_ON_BLUETOOTH;
    +     }
    + 
    +     /**
    +@@ -309,6 +313,7 @@ class BluetoothManagerService extends IBluetoothManager.Stub {
    +      *
    +      */
    +     private void persistBluetoothSetting(int value) {
    ++        if (DBG) Slog.d(TAG, "Persisting Bluetooth Setting: " + value);
    +         Settings.Global.putInt(mContext.getContentResolver(),
    +                                Settings.Global.BLUETOOTH_ON,
    +                                value);
    +@@ -445,14 +450,16 @@ class BluetoothManagerService extends IBluetoothManager.Stub {
    + 
    +     class ClientDeathRecipient implements IBinder.DeathRecipient {
    +         public void binderDied() {
    +-            if (DBG) Slog.d(TAG, "Binder is dead -  unregister Ble App");
    ++            if (DBG) Slog.d(TAG, "Binder is dead - unregister Ble App");
    +             if (mBleAppCount > 0) --mBleAppCount;
    + 
    +             if (mBleAppCount == 0) {
    +                 if (DBG) Slog.d(TAG, "Disabling LE only mode after application crash");
    +                 try {
    +                     mBluetoothLock.readLock().lock();
    +-                    if (mBluetooth != null) {
    ++                    if (mBluetooth != null &&
    ++                        mBluetooth.getState() == BluetoothAdapter.STATE_BLE_ON) {
    ++                        mEnable = false;
    +                         mBluetooth.onBrEdrDown();
    +                     }
    +                 } catch (RemoteException e) {
    +@@ -469,6 +476,9 @@ class BluetoothManagerService extends IBluetoothManager.Stub {
    + 
    +     @Override
    +     public boolean isBleScanAlwaysAvailable() {
    ++        if (isAirplaneModeOn() && !mEnable) {
    ++            return false;
    ++        }
    +         try {
    +             return (Settings.Global.getInt(mContentResolver,
    +                     Settings.Global.BLE_SCAN_ALWAYS_AVAILABLE)) != 0;
    +@@ -707,6 +717,7 @@ class BluetoothManagerService extends IBluetoothManager.Stub {
    +             if (mUnbinding) return;
    +             mUnbinding = true;
    +             mHandler.removeMessages(MESSAGE_BLUETOOTH_STATE_CHANGE);
    ++            mHandler.removeMessages(MESSAGE_BIND_PROFILE_SERVICE);
    +             if (mBluetooth != null) {
    +                 //Unregister callback object
    +                 try {
    +@@ -1365,7 +1376,7 @@ class BluetoothManagerService extends IBluetoothManager.Stub {
    +                 {
    +                     int prevState = msg.arg1;
    +                     int newState = msg.arg2;
    +-                    if (DBG) Slog.d(TAG, "MESSAGE_BLUETOOTH_STATE_CHANGE: prevState = " + prevState + ", newState=" + newState);
    ++                    if (DBG) Slog.d(TAG, "MESSAGE_BLUETOOTH_STATE_CHANGE: prevState = " + prevState + ", newState =" + newState);
    +                     mState = newState;
    +                     bluetoothStateChangeHandler(prevState, newState);
    +                     // handle error state transition case from TURNING_ON to OFF
    +@@ -1677,6 +1688,7 @@ class BluetoothManagerService extends IBluetoothManager.Stub {
    + 
    +     private void bluetoothStateChangeHandler(int prevState, int newState) {
    +         boolean isStandardBroadcast = true;
    ++        if (DBG) Slog.d(TAG, "bluetoothStateChangeHandler: " + prevState + " ->  " + newState);
    +         if (prevState != newState) {
    +             //Notify all proxy objects first of adapter state change
    +             if (newState == BluetoothAdapter.STATE_BLE_ON ||
    +diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
    +index 989892f..23172a2 100644
    +--- a/services/core/java/com/android/server/ConnectivityService.java
    ++++ b/services/core/java/com/android/server/ConnectivityService.java
    +@@ -24,6 +24,7 @@ import static android.net.ConnectivityManager.TYPE_VPN;
    + import static android.net.ConnectivityManager.getNetworkTypeName;
    + import static android.net.ConnectivityManager.isNetworkTypeValid;
    + import static android.net.NetworkCapabilities.NET_CAPABILITY_CAPTIVE_PORTAL;
    ++import static android.net.NetworkCapabilities.NET_CAPABILITY_FOREGROUND;
    + import static android.net.NetworkCapabilities.NET_CAPABILITY_INTERNET;
    + import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_METERED;
    + import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED;
    +@@ -263,6 +264,11 @@ public class ConnectivityService extends IConnectivityManager.Stub
    +         DONT_REAP
    +     };
    + 
    ++    private enum UnneededFor {
    ++        LINGER,    // Determine whether this network is unneeded and should be lingered.
    ++        TEARDOWN,  // Determine whether this network is unneeded and should be torn down.
    ++    }
    ++
    +     /**
    +      * used internally to change our mobile data enabled flag
    +      */
    +@@ -700,13 +706,13 @@ public class ConnectivityService extends IConnectivityManager.Stub
    +         if (DBG) log("ConnectivityService starting up");
    + 
    +         mMetricsLog = logger;
    +-        mDefaultRequest = createInternetRequestForTransport(-1);
    ++        mDefaultRequest = createInternetRequestForTransport(-1, NetworkRequest.Type.REQUEST);
    +         NetworkRequestInfo defaultNRI = new NetworkRequestInfo(null, mDefaultRequest, new Binder());
    +         mNetworkRequests.put(mDefaultRequest, defaultNRI);
    +         mNetworkRequestInfoLogs.log("REGISTER " + defaultNRI);
    + 
    +         mDefaultMobileDataRequest = createInternetRequestForTransport(
    +-                NetworkCapabilities.TRANSPORT_CELLULAR);
    ++                NetworkCapabilities.TRANSPORT_CELLULAR, NetworkRequest.Type.BACKGROUND_REQUEST);
    + 
    +         mHandlerThread = createHandlerThread();
    +         mHandlerThread.start();
    +@@ -809,7 +815,7 @@ public class ConnectivityService extends IConnectivityManager.Stub
    +         mTestMode = SystemProperties.get("cm.test.mode").equals("true")
    +                 && SystemProperties.get("ro.build.type").equals("eng");
    + 
    +-        mTethering = new Tethering(mContext, mNetd, statsService);
    ++        mTethering = new Tethering(mContext, mNetd, statsService, mPolicyManager);
    + 
    +         mPermissionMonitor = new PermissionMonitor(mContext, mNetd);
    + 
    +@@ -860,15 +866,15 @@ public class ConnectivityService extends IConnectivityManager.Stub
    +                 mContext, mHandler, () -> rematchForAvoidBadWifiUpdate());
    +     }
    + 
    +-    private NetworkRequest createInternetRequestForTransport(int transportType) {
    ++    private NetworkRequest createInternetRequestForTransport(
    ++            int transportType, NetworkRequest.Type type) {
    +         NetworkCapabilities netCap = new NetworkCapabilities();
    +         netCap.addCapability(NET_CAPABILITY_INTERNET);
    +         netCap.addCapability(NET_CAPABILITY_NOT_RESTRICTED);
    +         if (transportType > -1) {
    +             netCap.addTransportType(transportType);
    +         }
    +-        return new NetworkRequest(netCap, TYPE_NONE, nextNetworkRequestId(),
    +-                NetworkRequest.Type.REQUEST);
    ++        return new NetworkRequest(netCap, TYPE_NONE, nextNetworkRequestId(), type);
    +     }
    + 
    +     // Used only for testing.
    +@@ -1982,8 +1988,12 @@ public class ConnectivityService extends IConnectivityManager.Stub
    +         for (NetworkAgentInfo nai : mNetworkAgentInfos.values()) {
    +             pw.println(nai.toString());
    +             pw.increaseIndent();
    +-            pw.println(String.format("Requests: %d request/%d total",
    +-                    nai.numRequestNetworkRequests(), nai.numNetworkRequests()));
    ++            pw.println(String.format(
    ++                    "Requests: REQUEST:%d LISTEN:%d BACKGROUND_REQUEST:%d total:%d",
    ++                    nai.numForegroundNetworkRequests(),
    ++                    nai.numNetworkRequests() - nai.numRequestNetworkRequests(),
    ++                    nai.numBackgroundNetworkRequests(),
    ++                    nai.numNetworkRequests()));
    +             pw.increaseIndent();
    +             for (int i = 0; i < nai.numNetworkRequests(); i++) {
    +                 pw.println(nai.requestAt(i).toString());
    +@@ -2144,14 +2154,10 @@ public class ConnectivityService extends IConnectivityManager.Stub
    +                 case NetworkAgent.EVENT_NETWORK_CAPABILITIES_CHANGED: {
    +                     final NetworkCapabilities networkCapabilities = (NetworkCapabilities) msg.obj;
    +                     if (networkCapabilities.hasCapability(NET_CAPABILITY_CAPTIVE_PORTAL) ||
    +-                            networkCapabilities.hasCapability(NET_CAPABILITY_VALIDATED)) {
    ++                            networkCapabilities.hasCapability(NET_CAPABILITY_VALIDATED) ||
    ++                            networkCapabilities.hasCapability(NET_CAPABILITY_FOREGROUND)) {
    +                         Slog.wtf(TAG, "BUG: " + nai + " has CS-managed capability.");
    +                     }
    +-                    if (nai.everConnected && !nai.networkCapabilities.equalImmutableCapabilities(
    +-                            networkCapabilities)) {
    +-                        Slog.wtf(TAG, "BUG: " + nai + " changed immutable capabilities: "
    +-                                + nai.networkCapabilities + " -> " + networkCapabilities);
    +-                    }
    +                     updateCapabilities(nai.getCurrentScore(), nai, networkCapabilities);
    +                     break;
    +                 }
    +@@ -2311,15 +2317,13 @@ public class ConnectivityService extends IConnectivityManager.Stub
    +         // 3. If this network is unneeded (which implies it is not lingering), and there is at least
    +         //    one lingered request, start lingering.
    +         nai.updateLingerTimer();
    +-        if (nai.isLingering() && nai.numRequestNetworkRequests() > 0) {
    ++        if (nai.isLingering() && nai.numForegroundNetworkRequests() > 0) {
    +             if (DBG) log("Unlingering " + nai.name());
    +             nai.unlinger();
    +             logNetworkEvent(nai, NetworkEvent.NETWORK_UNLINGER);
    +-        } else if (unneeded(nai) && nai.getLingerExpiry() > 0) {  // unneeded() calls isLingering()
    ++        } else if (unneeded(nai, UnneededFor.LINGER) && nai.getLingerExpiry() > 0) {
    +             int lingerTime = (int) (nai.getLingerExpiry() - now);
    +-            if (DBG) {
    +-                Log.d(TAG, "Lingering " + nai.name() + " for " + lingerTime + "ms");
    +-            }
    ++            if (DBG) log("Lingering " + nai.name() + " for " + lingerTime + "ms");
    +             nai.linger();
    +             logNetworkEvent(nai, NetworkEvent.NETWORK_LINGER);
    +             notifyNetworkCallbacks(nai, ConnectivityManager.CALLBACK_LOSING, lingerTime);
    +@@ -2498,15 +2502,37 @@ public class ConnectivityService extends IConnectivityManager.Stub
    +         }
    +     }
    + 
    +-    // Is nai unneeded by all NetworkRequests (and should be disconnected)?
    +-    // This is whether it is satisfying any NetworkRequests or were it to become validated,
    +-    // would it have a chance of satisfying any NetworkRequests.
    +-    private boolean unneeded(NetworkAgentInfo nai) {
    +-        if (!nai.everConnected || nai.isVPN() ||
    +-               nai.isLingering() || nai.numRequestNetworkRequests() > 0) {
    ++    // Determines whether the network is the best (or could become the best, if it validated), for
    ++    // none of a particular type of NetworkRequests. The type of NetworkRequests considered depends
    ++    // on the value of reason:
    ++    //
    ++    // - UnneededFor.TEARDOWN: non-listen NetworkRequests. If a network is unneeded for this reason,
    ++    //   then it should be torn down.
    ++    // - UnneededFor.LINGER: foreground NetworkRequests. If a network is unneeded for this reason,
    ++    //   then it should be lingered.
    ++    private boolean unneeded(NetworkAgentInfo nai, UnneededFor reason) {
    ++        final int numRequests;
    ++        switch (reason) {
    ++            case TEARDOWN:
    ++                numRequests = nai.numRequestNetworkRequests();
    ++                break;
    ++            case LINGER:
    ++                numRequests = nai.numForegroundNetworkRequests();
    ++                break;
    ++            default:
    ++                Slog.wtf(TAG, "Invalid reason. Cannot happen.");
    ++                return true;
    ++        }
    ++
    ++        if (!nai.everConnected || nai.isVPN() || nai.isLingering() || numRequests > 0) {
    +             return false;
    +         }
    +         for (NetworkRequestInfo nri : mNetworkRequests.values()) {
    ++            if (reason == UnneededFor.LINGER && nri.request.isBackgroundRequest()) {
    ++                // Background requests don't affect lingering.
    ++                continue;
    ++            }
    ++
    +             // If this Network is already the highest scoring Network for a request, or if
    +             // there is hope for it to become one if it validated, then it is needed.
    +             if (nri.request.isRequest() && nai.satisfies(nri.request) &&
    +@@ -2594,6 +2620,7 @@ public class ConnectivityService extends IConnectivityManager.Stub
    +             boolean wasKept = false;
    +             NetworkAgentInfo nai = mNetworkForRequestId.get(nri.request.requestId);
    +             if (nai != null) {
    ++                boolean wasBackgroundNetwork = nai.isBackgroundNetwork();
    +                 nai.removeRequest(nri.request.requestId);
    +                 if (VDBG) {
    +                     log(" Removing from current network " + nai.name() +
    +@@ -2602,13 +2629,17 @@ public class ConnectivityService extends IConnectivityManager.Stub
    +                 // If there are still lingered requests on this network, don't tear it down,
    +                 // but resume lingering instead.
    +                 updateLingerState(nai, SystemClock.elapsedRealtime());
    +-                if (unneeded(nai)) {
    ++                if (unneeded(nai, UnneededFor.TEARDOWN)) {
    +                     if (DBG) log("no live requests for " + nai.name() + "; disconnecting");
    +                     teardownUnneededNetwork(nai);
    +                 } else {
    +                     wasKept = true;
    +                 }
    +                 mNetworkForRequestId.remove(nri.request.requestId);
    ++                if (!wasBackgroundNetwork && nai.isBackgroundNetwork()) {
    ++                    // Went from foreground to background.
    ++                    updateCapabilities(nai.getCurrentScore(), nai, nai.networkCapabilities);
    ++                }
    +             }
    + 
    +             // TODO: remove this code once we know that the Slog.wtf is never hit.
    +@@ -4255,8 +4286,17 @@ public class ConnectivityService extends IConnectivityManager.Stub
    +             enforceAccessPermission();
    +         }
    + 
    +-        NetworkRequest networkRequest = new NetworkRequest(
    +-                new NetworkCapabilities(networkCapabilities), TYPE_NONE, nextNetworkRequestId(),
    ++        NetworkCapabilities nc = new NetworkCapabilities(networkCapabilities);
    ++        if (!ConnectivityManager.checkChangePermission(mContext)) {
    ++            // Apps without the CHANGE_NETWORK_STATE permission can't use background networks, so
    ++            // make all their listens include NET_CAPABILITY_FOREGROUND. That way, they will get
    ++            // onLost and onAvailable callbacks when networks move in and out of the background.
    ++            // There is no need to do this for requests because an app without CHANGE_NETWORK_STATE
    ++            // can't request networks.
    ++            nc.addCapability(NET_CAPABILITY_FOREGROUND);
    ++        }
    ++
    ++        NetworkRequest networkRequest = new NetworkRequest(nc, TYPE_NONE, nextNetworkRequestId(),
    +                 NetworkRequest.Type.LISTEN);
    +         NetworkRequestInfo nri = new NetworkRequestInfo(messenger, networkRequest, binder);
    +         if (VDBG) log("listenForNetwork for " + nri);
    +@@ -4571,6 +4611,17 @@ public class ConnectivityService extends IConnectivityManager.Stub
    +         mNumDnsEntries = last;
    +     }
    + 
    ++    private String getNetworkPermission(NetworkCapabilities nc) {
    ++        // TODO: make these permission strings AIDL constants instead.
    ++        if (!nc.hasCapability(NET_CAPABILITY_NOT_RESTRICTED)) {
    ++            return NetworkManagementService.PERMISSION_SYSTEM;
    ++        }
    ++        if (!nc.hasCapability(NET_CAPABILITY_FOREGROUND)) {
    ++            return NetworkManagementService.PERMISSION_NETWORK;
    ++        }
    ++        return null;
    ++    }
    ++
    +     /**
    +      * Update the NetworkCapabilities for {@code networkAgent} to {@code networkCapabilities}
    +      * augmented with any stateful capabilities implied from {@code networkAgent}
    +@@ -4583,6 +4634,12 @@ public class ConnectivityService extends IConnectivityManager.Stub
    +      */
    +     private void updateCapabilities(
    +             int oldScore, NetworkAgentInfo nai, NetworkCapabilities networkCapabilities) {
    ++        if (nai.everConnected && !nai.networkCapabilities.equalImmutableCapabilities(
    ++                networkCapabilities)) {
    ++            Slog.wtf(TAG, "BUG: " + nai + " changed immutable capabilities: "
    ++                    + nai.networkCapabilities + " -> " + networkCapabilities);
    ++        }
    ++
    +         // Don't modify caller's NetworkCapabilities.
    +         networkCapabilities = new NetworkCapabilities(networkCapabilities);
    +         if (nai.lastValidated) {
    +@@ -4595,20 +4652,38 @@ public class ConnectivityService extends IConnectivityManager.Stub
    +         } else {
    +             networkCapabilities.removeCapability(NET_CAPABILITY_CAPTIVE_PORTAL);
    +         }
    +-        if (!Objects.equals(nai.networkCapabilities, networkCapabilities)) {
    +-            if (nai.networkCapabilities.hasCapability(NET_CAPABILITY_NOT_RESTRICTED) !=
    +-                    networkCapabilities.hasCapability(NET_CAPABILITY_NOT_RESTRICTED)) {
    +-                try {
    +-                    mNetd.setNetworkPermission(nai.network.netId,
    +-                            networkCapabilities.hasCapability(NET_CAPABILITY_NOT_RESTRICTED) ?
    +-                                    null : NetworkManagementService.PERMISSION_SYSTEM);
    +-                } catch (RemoteException e) {
    +-                    loge("Exception in setNetworkPermission: " + e);
    +-                }
    +-            }
    +-            synchronized (nai) {
    +-                nai.networkCapabilities = networkCapabilities;
    ++        if (nai.isBackgroundNetwork()) {
    ++            networkCapabilities.removeCapability(NET_CAPABILITY_FOREGROUND);
    ++        } else {
    ++            networkCapabilities.addCapability(NET_CAPABILITY_FOREGROUND);
    ++        }
    ++
    ++        if (Objects.equals(nai.networkCapabilities, networkCapabilities)) return;
    ++
    ++        final String oldPermission = getNetworkPermission(nai.networkCapabilities);
    ++        final String newPermission = getNetworkPermission(networkCapabilities);
    ++        if (!Objects.equals(oldPermission, newPermission) && nai.created && !nai.isVPN()) {
    ++            try {
    ++                mNetd.setNetworkPermission(nai.network.netId, newPermission);
    ++            } catch (RemoteException e) {
    ++                loge("Exception in setNetworkPermission: " + e);
    +             }
    ++        }
    ++
    ++        final NetworkCapabilities prevNc = nai.networkCapabilities;
    ++        synchronized (nai) {
    ++            nai.networkCapabilities = networkCapabilities;
    ++        }
    ++        if (nai.getCurrentScore() == oldScore &&
    ++                networkCapabilities.equalRequestableCapabilities(prevNc)) {
    ++            // If the requestable capabilities haven't changed, and the score hasn't changed, then
    ++            // the change we're processing can't affect any requests, it can only affect the listens
    ++            // on this network. We might have been called by rematchNetworkAndRequests when a
    ++            // network changed foreground state.
    ++            processListenRequests(nai, true);
    ++        } else {
    ++            // If the requestable capabilities have changed or the score changed, we can't have been
    ++            // called by rematchNetworkAndRequests, so it's safe to start a rematch.
    +             rematchAllNetworksAndRequests(nai, oldScore);
    +             notifyNetworkCallbacks(nai, ConnectivityManager.CALLBACK_CAP_CHANGED);
    +         }
    +@@ -4731,8 +4806,13 @@ public class ConnectivityService extends IConnectivityManager.Stub
    +         // must be no other active linger timers, and we must stop lingering.
    +         oldNetwork.clearLingerState();
    + 
    +-        if (unneeded(oldNetwork)) {
    ++        if (unneeded(oldNetwork, UnneededFor.TEARDOWN)) {
    ++            // Tear the network down.
    +             teardownUnneededNetwork(oldNetwork);
    ++        } else {
    ++            // Put the network in the background.
    ++            updateCapabilities(oldNetwork.getCurrentScore(), oldNetwork,
    ++                    oldNetwork.networkCapabilities);
    +         }
    +     }
    + 
    +@@ -4750,6 +4830,31 @@ public class ConnectivityService extends IConnectivityManager.Stub
    +         setDefaultDnsSystemProperties(newNetwork.linkProperties.getDnsServers());
    +     }
    + 
    ++    private void processListenRequests(NetworkAgentInfo nai, boolean capabilitiesChanged) {
    ++        // For consistency with previous behaviour, send onLost callbacks before onAvailable.
    ++        for (NetworkRequestInfo nri : mNetworkRequests.values()) {
    ++            NetworkRequest nr = nri.request;
    ++            if (!nr.isListen()) continue;
    ++            if (nai.isSatisfyingRequest(nr.requestId) && !nai.satisfies(nr)) {
    ++                nai.removeRequest(nri.request.requestId);
    ++                callCallbackForRequest(nri, nai, ConnectivityManager.CALLBACK_LOST, 0);
    ++            }
    ++        }
    ++
    ++        if (capabilitiesChanged) {
    ++            notifyNetworkCallbacks(nai, ConnectivityManager.CALLBACK_CAP_CHANGED);
    ++        }
    ++
    ++        for (NetworkRequestInfo nri : mNetworkRequests.values()) {
    ++            NetworkRequest nr = nri.request;
    ++            if (!nr.isListen()) continue;
    ++            if (nai.satisfies(nr) && !nai.isSatisfyingRequest(nr.requestId)) {
    ++                nai.addRequest(nr);
    ++                notifyNetworkCallback(nai, nri);
    ++            }
    ++        }
    ++    }
    ++
    +     // Handles a network appearing or improving its score.
    +     //
    +     // - Evaluates all current NetworkRequests that can be
    +@@ -4783,13 +4888,25 @@ public class ConnectivityService extends IConnectivityManager.Stub
    +         boolean keep = newNetwork.isVPN();
    +         boolean isNewDefault = false;
    +         NetworkAgentInfo oldDefaultNetwork = null;
    ++
    ++        final boolean wasBackgroundNetwork = newNetwork.isBackgroundNetwork();
    ++        final int score = newNetwork.getCurrentScore();
    ++
    +         if (VDBG) log("rematching " + newNetwork.name());
    ++
    +         // Find and migrate to this Network any NetworkRequests for
    +         // which this network is now the best.
    +         ArrayList<NetworkAgentInfo> affectedNetworks = new ArrayList<NetworkAgentInfo>();
    +         ArrayList<NetworkRequestInfo> addedRequests = new ArrayList<NetworkRequestInfo>();
    +-        if (VDBG) log(" network has: " + newNetwork.networkCapabilities);
    ++        NetworkCapabilities nc = newNetwork.networkCapabilities;
    ++        if (VDBG) log(" network has: " + nc);
    +         for (NetworkRequestInfo nri : mNetworkRequests.values()) {
    ++            // Process requests in the first pass and listens in the second pass. This allows us to
    ++            // change a network's capabilities depending on which requests it has. This is only
    ++            // correct if the change in capabilities doesn't affect whether the network satisfies
    ++            // requests or not, and doesn't affect the network's score.
    ++            if (nri.request.isListen()) continue;
    ++
    +             final NetworkAgentInfo currentNetwork = mNetworkForRequestId.get(nri.request.requestId);
    +             final boolean satisfies = newNetwork.satisfies(nri.request);
    +             if (newNetwork == currentNetwork && satisfies) {
    +@@ -4816,10 +4933,9 @@ public class ConnectivityService extends IConnectivityManager.Stub
    +                 if (VDBG) {
    +                     log("currentScore = " +
    +                             (currentNetwork != null ? currentNetwork.getCurrentScore() : 0) +
    +-                            ", newScore = " + newNetwork.getCurrentScore());
    ++                            ", newScore = " + score);
    +                 }
    +-                if (currentNetwork == null ||
    +-                        currentNetwork.getCurrentScore() < newNetwork.getCurrentScore()) {
    ++                if (currentNetwork == null || currentNetwork.getCurrentScore() < score) {
    +                     if (VDBG) log("rematch for " + newNetwork.name());
    +                     if (currentNetwork != null) {
    +                         if (VDBG) log("   accepting network in place of " + currentNetwork.name());
    +@@ -4841,7 +4957,7 @@ public class ConnectivityService extends IConnectivityManager.Stub
    +                     // TODO - this could get expensive if we have alot of requests for this
    +                     // network.  Think about if there is a way to reduce this.  Push
    +                     // netid->request mapping to each factory?
    +-                    sendUpdatedScoreToFactories(nri.request, newNetwork.getCurrentScore());
    ++                    sendUpdatedScoreToFactories(nri.request, score);
    +                     if (isDefaultRequest(nri)) {
    +                         isNewDefault = true;
    +                         oldDefaultNetwork = currentNetwork;
    +@@ -4867,16 +4983,14 @@ public class ConnectivityService extends IConnectivityManager.Stub
    +                     mNetworkForRequestId.remove(nri.request.requestId);
    +                     sendUpdatedScoreToFactories(nri.request, 0);
    +                 } else {
    +-                    if (nri.request.isRequest()) {
    +-                        Slog.wtf(TAG, "BUG: Removing request " + nri.request.requestId + " from " +
    +-                                newNetwork.name() +
    +-                                " without updating mNetworkForRequestId or factories!");
    +-                    }
    ++                    Slog.wtf(TAG, "BUG: Removing request " + nri.request.requestId + " from " +
    ++                            newNetwork.name() +
    ++                            " without updating mNetworkForRequestId or factories!");
    +                 }
    +-                // TODO: technically, sending CALLBACK_LOST here is
    +-                // incorrect if nri is a request (not a listen) and there
    +-                // is a replacement network currently connected that can
    +-                // satisfy it. However, the only capability that can both
    ++                // TODO: Technically, sending CALLBACK_LOST here is
    ++                // incorrect if there is a replacement network currently
    ++                // connected that can satisfy nri, which is a request
    ++                // (not a listen). However, the only capability that can both
    +                 // a) be requested and b) change is NET_CAPABILITY_TRUSTED,
    +                 // so this code is only incorrect for a network that loses
    +                 // the TRUSTED capability, which is a rare case.
    +@@ -4901,6 +5015,28 @@ public class ConnectivityService extends IConnectivityManager.Stub
    +             }
    +         }
    + 
    ++        if (!newNetwork.networkCapabilities.equalRequestableCapabilities(nc)) {
    ++            Slog.wtf(TAG, String.format(
    ++                    "BUG: %s changed requestable capabilities during rematch: %s -> %s",
    ++                    nc, newNetwork.networkCapabilities));
    ++        }
    ++        if (newNetwork.getCurrentScore() != score) {
    ++            Slog.wtf(TAG, String.format(
    ++                    "BUG: %s changed score during rematch: %d -> %d",
    ++                    score, newNetwork.getCurrentScore()));
    ++        }
    ++
    ++        // Second pass: process all listens.
    ++        if (wasBackgroundNetwork != newNetwork.isBackgroundNetwork()) {
    ++            // If the network went from background to foreground or vice versa, we need to update
    ++            // its foreground state. It is safe to do this after rematching the requests because
    ++            // NET_CAPABILITY_FOREGROUND does not affect requests, as is not a requestable
    ++            // capability and does not affect the network's score (see the Slog.wtf call above).
    ++            updateCapabilities(score, newNetwork, newNetwork.networkCapabilities);
    ++        } else {
    ++            processListenRequests(newNetwork, false);
    ++        }
    ++
    +         // do this after the default net is switched, but
    +         // before LegacyTypeTracker sends legacy broadcasts
    +         for (NetworkRequestInfo nri : addedRequests) notifyNetworkCallback(newNetwork, nri);
    +@@ -4978,7 +5114,7 @@ public class ConnectivityService extends IConnectivityManager.Stub
    +         }
    +         if (reapUnvalidatedNetworks == ReapUnvalidatedNetworks.REAP) {
    +             for (NetworkAgentInfo nai : mNetworkAgentInfos.values()) {
    +-                if (unneeded(nai)) {
    ++                if (unneeded(nai, UnneededFor.TEARDOWN)) {
    +                     if (nai.getLingerExpiry() > 0) {
    +                         // This network has active linger timers and no requests, but is not
    +                         // lingering. Linger it.
    +@@ -5092,6 +5228,10 @@ public class ConnectivityService extends IConnectivityManager.Stub
    +         if (!networkAgent.created
    +                 && (state == NetworkInfo.State.CONNECTED
    +                 || (state == NetworkInfo.State.CONNECTING && networkAgent.isVPN()))) {
    ++
    ++            // A network that has just connected has zero requests and is thus a foreground network.
    ++            networkAgent.networkCapabilities.addCapability(NET_CAPABILITY_FOREGROUND);
    ++
    +             try {
    +                 // This should never fail.  Specifying an already in use NetID will cause failure.
    +                 if (networkAgent.isVPN()) {
    +@@ -5101,9 +5241,7 @@ public class ConnectivityService extends IConnectivityManager.Stub
    +                                 !networkAgent.networkMisc.allowBypass));
    +                 } else {
    +                     mNetd.createPhysicalNetwork(networkAgent.network.netId,
    +-                            networkAgent.networkCapabilities.hasCapability(
    +-                                    NET_CAPABILITY_NOT_RESTRICTED) ?
    +-                                    null : NetworkManagementService.PERMISSION_SYSTEM);
    ++                            getNetworkPermission(networkAgent.networkCapabilities));
    +                 }
    +             } catch (Exception e) {
    +                 loge("Error creating network " + networkAgent.network.netId + ": "
    +@@ -5253,6 +5391,8 @@ public class ConnectivityService extends IConnectivityManager.Stub
    +             NetworkRequest nr = networkAgent.requestAt(i);
    +             NetworkRequestInfo nri = mNetworkRequests.get(nr);
    +             if (VDBG) log(" sending notification for " + nr);
    ++            // TODO: if we're in the middle of a rematch, can we send a CAP_CHANGED callback for
    ++            // a network that no longer satisfies the listen?
    +             if (nri.mPendingIntent == null) {
    +                 callCallbackForRequest(nri, networkAgent, notifyType, arg1);
    +             } else {
    +@@ -5324,7 +5464,7 @@ public class ConnectivityService extends IConnectivityManager.Stub
    + 
    +     @Override
    +     public String getCaptivePortalServerUrl() {
    +-        return NetworkMonitor.getCaptivePortalServerUrl(mContext);
    ++        return NetworkMonitor.getCaptivePortalServerHttpUrl(mContext);
    +     }
    + 
    +     @Override
    +diff --git a/services/core/java/com/android/server/DeviceIdleController.java b/services/core/java/com/android/server/DeviceIdleController.java
    +index 488f0e7..4405c1b 100644
    +--- a/services/core/java/com/android/server/DeviceIdleController.java
    ++++ b/services/core/java/com/android/server/DeviceIdleController.java
    +@@ -2726,12 +2726,12 @@ public class DeviceIdleController extends SystemService
    +                 }
    +             }
    +         } else if ("whitelist".equals(cmd)) {
    +-            long token = Binder.clearCallingIdentity();
    +-            try {
    +-                String arg = shell.getNextArg();
    +-                if (arg != null) {
    +-                    getContext().enforceCallingOrSelfPermission(
    +-                            android.Manifest.permission.DEVICE_POWER, null);
    ++            String arg = shell.getNextArg();
    ++            if (arg != null) {
    ++                getContext().enforceCallingOrSelfPermission(
    ++                        android.Manifest.permission.DEVICE_POWER, null);
    ++                long token = Binder.clearCallingIdentity();
    ++                try {
    +                     do {
    +                         if (arg.length() < 1 || (arg.charAt(0) != '-'
    +                                 && arg.charAt(0) != '+' && arg.charAt(0) != '=')) {
    +@@ -2754,30 +2754,30 @@ public class DeviceIdleController extends SystemService
    +                             pw.println(getPowerSaveWhitelistAppInternal(pkg));
    +                         }
    +                     } while ((arg=shell.getNextArg()) != null);
    +-                } else {
    +-                    synchronized (this) {
    +-                        for (int j=0; j<mPowerSaveWhitelistAppsExceptIdle.size(); j++) {
    +-                            pw.print("system-excidle,");
    +-                            pw.print(mPowerSaveWhitelistAppsExceptIdle.keyAt(j));
    +-                            pw.print(",");
    +-                            pw.println(mPowerSaveWhitelistAppsExceptIdle.valueAt(j));
    +-                        }
    +-                        for (int j=0; j<mPowerSaveWhitelistApps.size(); j++) {
    +-                            pw.print("system,");
    +-                            pw.print(mPowerSaveWhitelistApps.keyAt(j));
    +-                            pw.print(",");
    +-                            pw.println(mPowerSaveWhitelistApps.valueAt(j));
    +-                        }
    +-                        for (int j=0; j<mPowerSaveWhitelistUserApps.size(); j++) {
    +-                            pw.print("user,");
    +-                            pw.print(mPowerSaveWhitelistUserApps.keyAt(j));
    +-                            pw.print(",");
    +-                            pw.println(mPowerSaveWhitelistUserApps.valueAt(j));
    +-                        }
    ++                } finally {
    ++                    Binder.restoreCallingIdentity(token);
    ++                }
    ++            } else {
    ++                synchronized (this) {
    ++                    for (int j=0; j<mPowerSaveWhitelistAppsExceptIdle.size(); j++) {
    ++                        pw.print("system-excidle,");
    ++                        pw.print(mPowerSaveWhitelistAppsExceptIdle.keyAt(j));
    ++                        pw.print(",");
    ++                        pw.println(mPowerSaveWhitelistAppsExceptIdle.valueAt(j));
    ++                    }
    ++                    for (int j=0; j<mPowerSaveWhitelistApps.size(); j++) {
    ++                        pw.print("system,");
    ++                        pw.print(mPowerSaveWhitelistApps.keyAt(j));
    ++                        pw.print(",");
    ++                        pw.println(mPowerSaveWhitelistApps.valueAt(j));
    ++                    }
    ++                    for (int j=0; j<mPowerSaveWhitelistUserApps.size(); j++) {
    ++                        pw.print("user,");
    ++                        pw.print(mPowerSaveWhitelistUserApps.keyAt(j));
    ++                        pw.print(",");
    ++                        pw.println(mPowerSaveWhitelistUserApps.valueAt(j));
    +                     }
    +                 }
    +-            } finally {
    +-                Binder.restoreCallingIdentity(token);
    +             }
    +         } else if ("tempwhitelist".equals(cmd)) {
    +             String opt;
    +diff --git a/services/core/java/com/android/server/IntentResolver.java b/services/core/java/com/android/server/IntentResolver.java
    +index 3fdcceb..83d374c 100644
    +--- a/services/core/java/com/android/server/IntentResolver.java
    ++++ b/services/core/java/com/android/server/IntentResolver.java
    +@@ -364,6 +364,7 @@ public abstract class IntentResolver<F extends IntentFilter, R extends Object> {
    +             buildResolveList(intent, categories, debug, defaultOnly,
    +                     resolvedType, scheme, listCut.get(i), resultList, userId);
    +         }
    ++        filterResults(resultList);
    +         sortResults(resultList);
    +         return resultList;
    +     }
    +@@ -457,6 +458,7 @@ public abstract class IntentResolver<F extends IntentFilter, R extends Object> {
    +             buildResolveList(intent, categories, debug, defaultOnly,
    +                     resolvedType, scheme, schemeCut, finalList, userId);
    +         }
    ++        filterResults(finalList);
    +         sortResults(finalList);
    + 
    +         if (debug) {
    +@@ -521,6 +523,12 @@ public abstract class IntentResolver<F extends IntentFilter, R extends Object> {
    +         Collections.sort(results, mResolvePrioritySorter);
    +     }
    + 
    ++    /**
    ++     * Apply filtering to the results. This happens before the results are sorted.
    ++     */
    ++    protected void filterResults(List<R> results) {
    ++    }
    ++
    +     protected void dumpFilter(PrintWriter out, String prefix, F filter) {
    +         out.print(prefix); out.println(filter);
    +     }
    +diff --git a/services/core/java/com/android/server/MountService.java b/services/core/java/com/android/server/MountService.java
    +index cdd977b..8430a0b 100644
    +--- a/services/core/java/com/android/server/MountService.java
    ++++ b/services/core/java/com/android/server/MountService.java
    +@@ -1056,6 +1056,10 @@ class MountService extends IMountService.Stub
    +                         || mForceAdoptable) {
    +                     flags |= DiskInfo.FLAG_ADOPTABLE;
    +                 }
    ++                // Adoptable storage isn't currently supported on FBE devices
    ++                if (StorageManager.isFileEncryptedNativeOnly()) {
    ++                    flags &= ~DiskInfo.FLAG_ADOPTABLE;
    ++                }
    +                 mDisks.put(id, new DiskInfo(id, flags));
    +                 break;
    +             }
    +@@ -1433,13 +1437,22 @@ class MountService extends IMountService.Stub
    +      * Decide if volume is mountable per device policies.
    +      */
    +     private boolean isMountDisallowed(VolumeInfo vol) {
    ++        UserManager userManager = mContext.getSystemService(UserManager.class);
    ++
    ++        boolean isUsbRestricted = false;
    ++        if (vol.disk != null && vol.disk.isUsb()) {
    ++            isUsbRestricted = userManager.hasUserRestriction(UserManager.DISALLOW_USB_FILE_TRANSFER,
    ++                    Binder.getCallingUserHandle());
    ++        }
    ++
    ++        boolean isTypeRestricted = false;
    +         if (vol.type == VolumeInfo.TYPE_PUBLIC || vol.type == VolumeInfo.TYPE_PRIVATE) {
    +-            final UserManager userManager = mContext.getSystemService(UserManager.class);
    +-            return userManager.hasUserRestriction(UserManager.DISALLOW_MOUNT_PHYSICAL_MEDIA,
    ++            isTypeRestricted = userManager
    ++                    .hasUserRestriction(UserManager.DISALLOW_MOUNT_PHYSICAL_MEDIA,
    +                     Binder.getCallingUserHandle());
    +-        } else {
    +-            return false;
    +         }
    ++
    ++        return isUsbRestricted || isTypeRestricted;
    +     }
    + 
    +     private void enforceAdminUser() {
    +@@ -1985,6 +1998,11 @@ class MountService extends IMountService.Stub
    +         }
    + 
    +         if ((mask & StorageManager.DEBUG_FORCE_ADOPTABLE) != 0) {
    ++            if (StorageManager.isFileEncryptedNativeOnly()) {
    ++                throw new IllegalStateException(
    ++                        "Adoptable storage not available on device with native FBE");
    ++            }
    ++
    +             synchronized (mLock) {
    +                 mForceAdoptable = (flags & StorageManager.DEBUG_FORCE_ADOPTABLE) != 0;
    + 
    +diff --git a/services/core/java/com/android/server/RecoverySystemService.java b/services/core/java/com/android/server/RecoverySystemService.java
    +index 276687f..3c8c699 100644
    +--- a/services/core/java/com/android/server/RecoverySystemService.java
    ++++ b/services/core/java/com/android/server/RecoverySystemService.java
    +@@ -21,6 +21,7 @@ import android.net.LocalSocket;
    + import android.net.LocalSocketAddress;
    + import android.os.IRecoverySystem;
    + import android.os.IRecoverySystemProgressListener;
    ++import android.os.PowerManager;
    + import android.os.RecoverySystem;
    + import android.os.RemoteException;
    + import android.os.SystemProperties;
    +@@ -50,8 +51,15 @@ public final class RecoverySystemService extends SystemService {
    +     // The socket at /dev/socket/uncrypt to communicate with uncrypt.
    +     private static final String UNCRYPT_SOCKET = "uncrypt";
    + 
    ++    // The init services that communicate with /system/bin/uncrypt.
    ++    private static final String INIT_SERVICE_UNCRYPT = "init.svc.uncrypt";
    ++    private static final String INIT_SERVICE_SETUP_BCB = "init.svc.setup-bcb";
    ++    private static final String INIT_SERVICE_CLEAR_BCB = "init.svc.clear-bcb";
    ++
    +     private static final int SOCKET_CONNECTION_MAX_RETRY = 30;
    + 
    ++    private static final Object sRequestLock = new Object();
    ++
    +     private Context mContext;
    + 
    +     public RecoverySystemService(Context context) {
    +@@ -69,95 +77,155 @@ public final class RecoverySystemService extends SystemService {
    +         public boolean uncrypt(String filename, IRecoverySystemProgressListener listener) {
    +             if (DEBUG) Slog.d(TAG, "uncrypt: " + filename);
    + 
    +-            mContext.enforceCallingOrSelfPermission(android.Manifest.permission.RECOVERY, null);
    ++            synchronized (sRequestLock) {
    ++                mContext.enforceCallingOrSelfPermission(android.Manifest.permission.RECOVERY, null);
    + 
    +-            // Write the filename into UNCRYPT_PACKAGE_FILE to be read by
    +-            // uncrypt.
    +-            RecoverySystem.UNCRYPT_PACKAGE_FILE.delete();
    ++                final boolean available = checkAndWaitForUncryptService();
    ++                if (!available) {
    ++                    Slog.e(TAG, "uncrypt service is unavailable.");
    ++                    return false;
    ++                }
    + 
    +-            try (FileWriter uncryptFile = new FileWriter(RecoverySystem.UNCRYPT_PACKAGE_FILE)) {
    +-                uncryptFile.write(filename + "\n");
    +-            } catch (IOException e) {
    +-                Slog.e(TAG, "IOException when writing \"" + RecoverySystem.UNCRYPT_PACKAGE_FILE +
    +-                        "\": ", e);
    +-                return false;
    +-            }
    ++                // Write the filename into UNCRYPT_PACKAGE_FILE to be read by
    ++                // uncrypt.
    ++                RecoverySystem.UNCRYPT_PACKAGE_FILE.delete();
    + 
    +-            // Trigger uncrypt via init.
    +-            SystemProperties.set("ctl.start", "uncrypt");
    ++                try (FileWriter uncryptFile = new FileWriter(RecoverySystem.UNCRYPT_PACKAGE_FILE)) {
    ++                    uncryptFile.write(filename + "\n");
    ++                } catch (IOException e) {
    ++                    Slog.e(TAG, "IOException when writing \"" +
    ++                            RecoverySystem.UNCRYPT_PACKAGE_FILE + "\":", e);
    ++                    return false;
    ++                }
    + 
    +-            // Connect to the uncrypt service socket.
    +-            LocalSocket socket = connectService();
    +-            if (socket == null) {
    +-                Slog.e(TAG, "Failed to connect to uncrypt socket");
    +-                return false;
    +-            }
    ++                // Trigger uncrypt via init.
    ++                SystemProperties.set("ctl.start", "uncrypt");
    + 
    +-            // Read the status from the socket.
    +-            DataInputStream dis = null;
    +-            DataOutputStream dos = null;
    +-            try {
    +-                dis = new DataInputStream(socket.getInputStream());
    +-                dos = new DataOutputStream(socket.getOutputStream());
    +-                int lastStatus = Integer.MIN_VALUE;
    +-                while (true) {
    +-                    int status = dis.readInt();
    +-                    // Avoid flooding the log with the same message.
    +-                    if (status == lastStatus && lastStatus != Integer.MIN_VALUE) {
    +-                        continue;
    +-                    }
    +-                    lastStatus = status;
    +-
    +-                    if (status >= 0 && status <= 100) {
    +-                        // Update status
    +-                        Slog.i(TAG, "uncrypt read status: " + status);
    +-                        if (listener != null) {
    +-                            try {
    +-                                listener.onProgress(status);
    +-                            } catch (RemoteException ignored) {
    +-                                Slog.w(TAG, "RemoteException when posting progress");
    +-                            }
    ++                // Connect to the uncrypt service socket.
    ++                LocalSocket socket = connectService();
    ++                if (socket == null) {
    ++                    Slog.e(TAG, "Failed to connect to uncrypt socket");
    ++                    return false;
    ++                }
    ++
    ++                // Read the status from the socket.
    ++                DataInputStream dis = null;
    ++                DataOutputStream dos = null;
    ++                try {
    ++                    dis = new DataInputStream(socket.getInputStream());
    ++                    dos = new DataOutputStream(socket.getOutputStream());
    ++                    int lastStatus = Integer.MIN_VALUE;
    ++                    while (true) {
    ++                        int status = dis.readInt();
    ++                        // Avoid flooding the log with the same message.
    ++                        if (status == lastStatus && lastStatus != Integer.MIN_VALUE) {
    ++                            continue;
    +                         }
    +-                        if (status == 100) {
    +-                            Slog.i(TAG, "uncrypt successfully finished.");
    +-                            // Ack receipt of the final status code. uncrypt
    +-                            // waits for the ack so the socket won't be
    +-                            // destroyed before we receive the code.
    ++                        lastStatus = status;
    ++
    ++                        if (status >= 0 && status <= 100) {
    ++                            // Update status
    ++                            Slog.i(TAG, "uncrypt read status: " + status);
    ++                            if (listener != null) {
    ++                                try {
    ++                                    listener.onProgress(status);
    ++                                } catch (RemoteException ignored) {
    ++                                    Slog.w(TAG, "RemoteException when posting progress");
    ++                                }
    ++                            }
    ++                            if (status == 100) {
    ++                                Slog.i(TAG, "uncrypt successfully finished.");
    ++                                // Ack receipt of the final status code. uncrypt
    ++                                // waits for the ack so the socket won't be
    ++                                // destroyed before we receive the code.
    ++                                dos.writeInt(0);
    ++                                break;
    ++                            }
    ++                        } else {
    ++                            // Error in /system/bin/uncrypt.
    ++                            Slog.e(TAG, "uncrypt failed with status: " + status);
    ++                            // Ack receipt of the final status code. uncrypt waits
    ++                            // for the ack so the socket won't be destroyed before
    ++                            // we receive the code.
    +                             dos.writeInt(0);
    +-                            break;
    ++                            return false;
    +                         }
    +-                    } else {
    +-                        // Error in /system/bin/uncrypt.
    +-                        Slog.e(TAG, "uncrypt failed with status: " + status);
    +-                        // Ack receipt of the final status code. uncrypt waits
    +-                        // for the ack so the socket won't be destroyed before
    +-                        // we receive the code.
    +-                        dos.writeInt(0);
    +-                        return false;
    +                     }
    ++                } catch (IOException e) {
    ++                    Slog.e(TAG, "IOException when reading status: ", e);
    ++                    return false;
    ++                } finally {
    ++                    IoUtils.closeQuietly(dis);
    ++                    IoUtils.closeQuietly(dos);
    ++                    IoUtils.closeQuietly(socket);
    +                 }
    +-            } catch (IOException e) {
    +-                Slog.e(TAG, "IOException when reading status: ", e);
    +-                return false;
    +-            } finally {
    +-                IoUtils.closeQuietly(dis);
    +-                IoUtils.closeQuietly(dos);
    +-                IoUtils.closeQuietly(socket);
    +-            }
    + 
    +-            return true;
    ++                return true;
    ++            }
    +         }
    + 
    +         @Override // Binder call
    +         public boolean clearBcb() {
    +             if (DEBUG) Slog.d(TAG, "clearBcb");
    +-            return setupOrClearBcb(false, null);
    ++            synchronized (sRequestLock) {
    ++                return setupOrClearBcb(false, null);
    ++            }
    +         }
    + 
    +         @Override // Binder call
    +         public boolean setupBcb(String command) {
    +             if (DEBUG) Slog.d(TAG, "setupBcb: [" + command + "]");
    +-            return setupOrClearBcb(true, command);
    ++            synchronized (sRequestLock) {
    ++                return setupOrClearBcb(true, command);
    ++            }
    ++        }
    ++
    ++        @Override // Binder call
    ++        public void rebootRecoveryWithCommand(String command) {
    ++            if (DEBUG) Slog.d(TAG, "rebootRecoveryWithCommand: [" + command + "]");
    ++            synchronized (sRequestLock) {
    ++                if (!setupOrClearBcb(true, command)) {
    ++                    return;
    ++                }
    ++
    ++                // Having set up the BCB, go ahead and reboot.
    ++                PowerManager pm = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
    ++                pm.reboot(PowerManager.REBOOT_RECOVERY);
    ++            }
    ++        }
    ++
    ++        /**
    ++         * Check if any of the init services is still running. If so, we cannot
    ++         * start a new uncrypt/setup-bcb/clear-bcb service right away; otherwise
    ++         * it may break the socket communication since init creates / deletes
    ++         * the socket (/dev/socket/uncrypt) on service start / exit.
    ++         */
    ++        private boolean checkAndWaitForUncryptService() {
    ++            for (int retry = 0; retry < SOCKET_CONNECTION_MAX_RETRY; retry++) {
    ++                final String uncryptService = SystemProperties.get(INIT_SERVICE_UNCRYPT);
    ++                final String setupBcbService = SystemProperties.get(INIT_SERVICE_SETUP_BCB);
    ++                final String clearBcbService = SystemProperties.get(INIT_SERVICE_CLEAR_BCB);
    ++                final boolean busy = "running".equals(uncryptService) ||
    ++                        "running".equals(setupBcbService) || "running".equals(clearBcbService);
    ++                if (DEBUG) {
    ++                    Slog.i(TAG, "retry: " + retry + " busy: " + busy +
    ++                            " uncrypt: [" + uncryptService + "]" +
    ++                            " setupBcb: [" + setupBcbService + "]" +
    ++                            " clearBcb: [" + clearBcbService + "]");
    ++                }
    ++
    ++                if (!busy) {
    ++                    return true;
    ++                }
    ++
    ++                try {
    ++                    Thread.sleep(1000);
    ++                } catch (InterruptedException e) {
    ++                    Slog.w(TAG, "Interrupted:", e);
    ++                }
    ++            }
    ++
    ++            return false;
    +         }
    + 
    +         private LocalSocket connectService() {
    +@@ -176,7 +244,7 @@ public final class RecoverySystemService extends SystemService {
    +                     try {
    +                         Thread.sleep(1000);
    +                     } catch (InterruptedException e) {
    +-                        Slog.w(TAG, "Interrupted: ", e);
    ++                        Slog.w(TAG, "Interrupted:", e);
    +                     }
    +                 }
    +             }
    +@@ -190,6 +258,12 @@ public final class RecoverySystemService extends SystemService {
    +         private boolean setupOrClearBcb(boolean isSetup, String command) {
    +             mContext.enforceCallingOrSelfPermission(android.Manifest.permission.RECOVERY, null);
    + 
    ++            final boolean available = checkAndWaitForUncryptService();
    ++            if (!available) {
    ++                Slog.e(TAG, "uncrypt service is unavailable.");
    ++                return false;
    ++            }
    ++
    +             if (isSetup) {
    +                 SystemProperties.set("ctl.start", "setup-bcb");
    +             } else {
    +@@ -232,7 +306,7 @@ public final class RecoverySystemService extends SystemService {
    +                     return false;
    +                 }
    +             } catch (IOException e) {
    +-                Slog.e(TAG, "IOException when communicating with uncrypt: ", e);
    ++                Slog.e(TAG, "IOException when communicating with uncrypt:", e);
    +                 return false;
    +             } finally {
    +                 IoUtils.closeQuietly(dis);
    +diff --git a/services/core/java/com/android/server/ServiceWatcher.java b/services/core/java/com/android/server/ServiceWatcher.java
    +index 383e25a..2ff036b 100644
    +--- a/services/core/java/com/android/server/ServiceWatcher.java
    ++++ b/services/core/java/com/android/server/ServiceWatcher.java
    +@@ -141,8 +141,12 @@ public class ServiceWatcher implements ServiceConnection {
    +      * <p>
    +      * Note that if there are no matching encryption-aware services, we may not
    +      * bind to a real service until after the current user is unlocked.
    ++     *
    ++     * @returns {@code true} if a potential service implementation was found.
    +      */
    +     public boolean start() {
    ++        if (isServiceMissing()) return false;
    ++
    +         synchronized (mLock) {
    +             bindBestPackageLocked(mServicePackageName, false);
    +         }
    +@@ -174,6 +178,17 @@ public class ServiceWatcher implements ServiceConnection {
    +     }
    + 
    +     /**
    ++     * Check if any instance of this service is present on the device,
    ++     * regardless of it being encryption-aware or not.
    ++     */
    ++    private boolean isServiceMissing() {
    ++        final Intent intent = new Intent(mAction);
    ++        final int flags = PackageManager.MATCH_DIRECT_BOOT_AWARE
    ++                | PackageManager.MATCH_DIRECT_BOOT_UNAWARE;
    ++        return mPm.queryIntentServicesAsUser(intent, flags, mCurrentUserId).isEmpty();
    ++    }
    ++
    ++    /**
    +      * Searches and binds to the best package, or do nothing if the best package
    +      * is already bound, unless force rebinding is requested.
    +      *
    +@@ -181,7 +196,7 @@ public class ServiceWatcher implements ServiceConnection {
    +      *            packages if it is {@code null}.
    +      * @param forceRebind Force a rebinding to the best package if it's already
    +      *            bound.
    +-     * @return {@code true} if a valid package was found to bind to.
    ++     * @returns {@code true} if a valid package was found to bind to.
    +      */
    +     private boolean bindBestPackageLocked(String justCheckThisPackage, boolean forceRebind) {
    +         Intent intent = new Intent(mAction);
    +diff --git a/services/core/java/com/android/server/TextServicesManagerService.java b/services/core/java/com/android/server/TextServicesManagerService.java
    +index 4b0d4be..4f02a23 100644
    +--- a/services/core/java/com/android/server/TextServicesManagerService.java
    ++++ b/services/core/java/com/android/server/TextServicesManagerService.java
    +@@ -459,71 +459,75 @@ public class TextServicesManagerService extends ITextServicesManager.Stub {
    +         if (!calledFromValidUser()) {
    +             return null;
    +         }
    ++        final int subtypeHashCode;
    ++        final SpellCheckerInfo sci;
    ++        final Locale systemLocale;
    +         synchronized (mSpellCheckerMap) {
    +-            final int subtypeHashCode =
    ++            subtypeHashCode =
    +                     mSettings.getSelectedSpellCheckerSubtype(SpellCheckerSubtype.SUBTYPE_ID_NONE);
    +             if (DBG) {
    +                 Slog.w(TAG, "getCurrentSpellCheckerSubtype: " + subtypeHashCode);
    +             }
    +-            final SpellCheckerInfo sci = getCurrentSpellChecker(null);
    +-            if (sci == null || sci.getSubtypeCount() == 0) {
    +-                if (DBG) {
    +-                    Slog.w(TAG, "Subtype not found.");
    ++            sci = getCurrentSpellChecker(null);
    ++            systemLocale = mContext.getResources().getConfiguration().locale;
    ++        }
    ++        if (sci == null || sci.getSubtypeCount() == 0) {
    ++            if (DBG) {
    ++                Slog.w(TAG, "Subtype not found.");
    ++            }
    ++            return null;
    ++        }
    ++        if (subtypeHashCode == SpellCheckerSubtype.SUBTYPE_ID_NONE
    ++                && !allowImplicitlySelectedSubtype) {
    ++            return null;
    ++        }
    ++        String candidateLocale = null;
    ++        if (subtypeHashCode == 0) {
    ++            // Spell checker language settings == "auto"
    ++            final InputMethodManager imm = mContext.getSystemService(InputMethodManager.class);
    ++            if (imm != null) {
    ++                final InputMethodSubtype currentInputMethodSubtype =
    ++                        imm.getCurrentInputMethodSubtype();
    ++                if (currentInputMethodSubtype != null) {
    ++                    final String localeString = currentInputMethodSubtype.getLocale();
    ++                    if (!TextUtils.isEmpty(localeString)) {
    ++                        // 1. Use keyboard locale if available in the spell checker
    ++                        candidateLocale = localeString;
    ++                    }
    +                 }
    +-                return null;
    +             }
    +-            if (subtypeHashCode == SpellCheckerSubtype.SUBTYPE_ID_NONE
    +-                    && !allowImplicitlySelectedSubtype) {
    +-                return null;
    ++            if (candidateLocale == null) {
    ++                // 2. Use System locale if available in the spell checker
    ++                candidateLocale = systemLocale.toString();
    +             }
    +-            String candidateLocale = null;
    ++        }
    ++        SpellCheckerSubtype candidate = null;
    ++        for (int i = 0; i < sci.getSubtypeCount(); ++i) {
    ++            final SpellCheckerSubtype scs = sci.getSubtypeAt(i);
    +             if (subtypeHashCode == 0) {
    +-                // Spell checker language settings == "auto"
    +-                final InputMethodManager imm = mContext.getSystemService(InputMethodManager.class);
    +-                if (imm != null) {
    +-                    final InputMethodSubtype currentInputMethodSubtype =
    +-                            imm.getCurrentInputMethodSubtype();
    +-                    if (currentInputMethodSubtype != null) {
    +-                        final String localeString = currentInputMethodSubtype.getLocale();
    +-                        if (!TextUtils.isEmpty(localeString)) {
    +-                            // 1. Use keyboard locale if available in the spell checker
    +-                            candidateLocale = localeString;
    +-                        }
    ++                final String scsLocale = scs.getLocale();
    ++                if (candidateLocale.equals(scsLocale)) {
    ++                    return scs;
    ++                } else if (candidate == null) {
    ++                    if (candidateLocale.length() >= 2 && scsLocale.length() >= 2
    ++                            && candidateLocale.startsWith(scsLocale)) {
    ++                        // Fall back to the applicable language
    ++                        candidate = scs;
    +                     }
    +                 }
    +-                if (candidateLocale == null) {
    +-                    // 2. Use System locale if available in the spell checker
    +-                    candidateLocale = mContext.getResources().getConfiguration().locale.toString();
    +-                }
    +-            }
    +-            SpellCheckerSubtype candidate = null;
    +-            for (int i = 0; i < sci.getSubtypeCount(); ++i) {
    +-                final SpellCheckerSubtype scs = sci.getSubtypeAt(i);
    +-                if (subtypeHashCode == 0) {
    +-                    final String scsLocale = scs.getLocale();
    +-                    if (candidateLocale.equals(scsLocale)) {
    +-                        return scs;
    +-                    } else if (candidate == null) {
    +-                        if (candidateLocale.length() >= 2 && scsLocale.length() >= 2
    +-                                && candidateLocale.startsWith(scsLocale)) {
    +-                            // Fall back to the applicable language
    +-                            candidate = scs;
    +-                        }
    +-                    }
    +-                } else if (scs.hashCode() == subtypeHashCode) {
    +-                    if (DBG) {
    +-                        Slog.w(TAG, "Return subtype " + scs.hashCode() + ", input= " + locale
    +-                                + ", " + scs.getLocale());
    +-                    }
    +-                    // 3. Use the user specified spell check language
    +-                    return scs;
    ++            } else if (scs.hashCode() == subtypeHashCode) {
    ++                if (DBG) {
    ++                    Slog.w(TAG, "Return subtype " + scs.hashCode() + ", input= " + locale
    ++                            + ", " + scs.getLocale());
    +                 }
    ++                // 3. Use the user specified spell check language
    ++                return scs;
    +             }
    +-            // 4. Fall back to the applicable language and return it if not null
    +-            // 5. Simply just return it even if it's null which means we could find no suitable
    +-            // spell check languages
    +-            return candidate;
    +         }
    ++        // 4. Fall back to the applicable language and return it if not null
    ++        // 5. Simply just return it even if it's null which means we could find no suitable
    ++        // spell check languages
    ++        return candidate;
    +     }
    + 
    +     @Override
    +diff --git a/services/core/java/com/android/server/accounts/AccountManagerBackupHelper.java b/services/core/java/com/android/server/accounts/AccountManagerBackupHelper.java
    +new file mode 100644
    +index 0000000..1361a31
    +--- /dev/null
    ++++ b/services/core/java/com/android/server/accounts/AccountManagerBackupHelper.java
    +@@ -0,0 +1,315 @@
    ++/*
    ++ * Copyright (C) 2016 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 com.android.server.accounts;
    ++
    ++import android.accounts.Account;
    ++import android.accounts.AccountManager;
    ++import android.accounts.AccountManagerInternal;
    ++import android.annotation.IntRange;
    ++import android.annotation.NonNull;
    ++import android.content.pm.PackageInfo;
    ++import android.content.pm.PackageManager;
    ++import android.database.Cursor;
    ++import android.database.sqlite.SQLiteDatabase;
    ++import android.os.UserHandle;
    ++import android.text.TextUtils;
    ++import android.util.Log;
    ++import android.util.PackageUtils;
    ++import android.util.Xml;
    ++import com.android.internal.annotations.GuardedBy;
    ++import com.android.internal.content.PackageMonitor;
    ++import com.android.internal.util.FastXmlSerializer;
    ++import com.android.internal.util.XmlUtils;
    ++import org.xmlpull.v1.XmlPullParser;
    ++import org.xmlpull.v1.XmlPullParserException;
    ++import org.xmlpull.v1.XmlSerializer;
    ++
    ++import java.io.ByteArrayInputStream;
    ++import java.io.ByteArrayOutputStream;
    ++import java.io.IOException;
    ++import java.nio.charset.StandardCharsets;
    ++import java.util.ArrayList;
    ++import java.util.List;
    ++
    ++/**
    ++ * Helper class for backup and restore of account access grants.
    ++ */
    ++public final class AccountManagerBackupHelper {
    ++    private static final String TAG = "AccountManagerBackupHelper";
    ++
    ++    private static final long PENDING_RESTORE_TIMEOUT_MILLIS = 60 * 60 * 1000; // 1 hour
    ++
    ++    private static final String TAG_PERMISSIONS = "permissions";
    ++    private static final String TAG_PERMISSION = "permission";
    ++    private static final String ATTR_ACCOUNT_SHA_256 = "account-sha-256";
    ++    private static final String ATTR_PACKAGE = "package";
    ++    private static final String ATTR_DIGEST = "digest";
    ++
    ++    private static final String ACCOUNT_ACCESS_GRANTS = ""
    ++            + "SELECT " + AccountManagerService.ACCOUNTS_NAME + ", "
    ++            + AccountManagerService.GRANTS_GRANTEE_UID
    ++            + " FROM " + AccountManagerService.TABLE_ACCOUNTS
    ++            + ", " + AccountManagerService.TABLE_GRANTS
    ++            + " WHERE " + AccountManagerService.GRANTS_ACCOUNTS_ID
    ++            + "=" + AccountManagerService.ACCOUNTS_ID;
    ++
    ++    private final Object mLock = new Object();
    ++
    ++    private final AccountManagerService mAccountManagerService;
    ++    private final AccountManagerInternal mAccountManagerInternal;
    ++
    ++    @GuardedBy("mLock")
    ++    private List<PendingAppPermission> mRestorePendingAppPermissions;
    ++
    ++    @GuardedBy("mLock")
    ++    private RestorePackageMonitor mRestorePackageMonitor;
    ++
    ++    @GuardedBy("mLock")
    ++    private Runnable mRestoreCancelCommand;
    ++
    ++    public AccountManagerBackupHelper(AccountManagerService accountManagerService,
    ++            AccountManagerInternal accountManagerInternal) {
    ++        mAccountManagerService = accountManagerService;
    ++        mAccountManagerInternal = accountManagerInternal;
    ++    }
    ++
    ++    private final class PendingAppPermission {
    ++        private final @NonNull String accountDigest;
    ++        private final @NonNull String packageName;
    ++        private final @NonNull String certDigest;
    ++        private final @IntRange(from = 0) int userId;
    ++
    ++        public PendingAppPermission(String accountDigest, String packageName,
    ++                String certDigest, int userId) {
    ++            this.accountDigest = accountDigest;
    ++            this.packageName = packageName;
    ++            this.certDigest = certDigest;
    ++            this.userId = userId;
    ++        }
    ++
    ++        public boolean apply(PackageManager packageManager) {
    ++            Account account = null;
    ++            AccountManagerService.UserAccounts accounts = mAccountManagerService
    ++                    .getUserAccounts(userId);
    ++            synchronized (accounts.cacheLock) {
    ++                for (Account[] accountsPerType : accounts.accountCache.values()) {
    ++                    for (Account accountPerType : accountsPerType) {
    ++                        if (accountDigest.equals(PackageUtils.computeSha256Digest(
    ++                                accountPerType.name.getBytes()))) {
    ++                            account = accountPerType;
    ++                            break;
    ++                        }
    ++                    }
    ++                    if (account != null) {
    ++                        break;
    ++                    }
    ++                }
    ++            }
    ++            if (account == null) {
    ++                return false;
    ++            }
    ++            final PackageInfo packageInfo;
    ++            try {
    ++                packageInfo = packageManager.getPackageInfoAsUser(packageName,
    ++                        PackageManager.GET_SIGNATURES, userId);
    ++            } catch (PackageManager.NameNotFoundException e) {
    ++                return false;
    ++            }
    ++            String currentCertDigest = PackageUtils.computeCertSha256Digest(
    ++                    packageInfo.signatures[0]);
    ++            if (!certDigest.equals(currentCertDigest)) {
    ++                return false;
    ++            }
    ++            final int uid = packageInfo.applicationInfo.uid;
    ++            if (!mAccountManagerInternal.hasAccountAccess(account, uid)) {
    ++                mAccountManagerService.grantAppPermission(account,
    ++                        AccountManager.ACCOUNT_ACCESS_TOKEN_TYPE, uid);
    ++            }
    ++            return true;
    ++        }
    ++    }
    ++
    ++    public byte[] backupAccountAccessPermissions(int userId) {
    ++        final AccountManagerService.UserAccounts accounts = mAccountManagerService
    ++                .getUserAccounts(userId);
    ++        synchronized (accounts.cacheLock) {
    ++            SQLiteDatabase db = accounts.openHelper.getReadableDatabase();
    ++            try (
    ++                Cursor cursor = db.rawQuery(ACCOUNT_ACCESS_GRANTS, null);
    ++            ) {
    ++                if (cursor == null || !cursor.moveToFirst()) {
    ++                    return null;
    ++                }
    ++
    ++                final int nameColumnIdx = cursor.getColumnIndex(
    ++                        AccountManagerService.ACCOUNTS_NAME);
    ++                final int uidColumnIdx = cursor.getColumnIndex(
    ++                        AccountManagerService.GRANTS_GRANTEE_UID);
    ++
    ++                ByteArrayOutputStream dataStream = new ByteArrayOutputStream();
    ++                try {
    ++                    final XmlSerializer serializer = new FastXmlSerializer();
    ++                    serializer.setOutput(dataStream, StandardCharsets.UTF_8.name());
    ++                    serializer.startDocument(null, true);
    ++                    serializer.startTag(null, TAG_PERMISSIONS);
    ++
    ++                    PackageManager packageManager = mAccountManagerService.mContext
    ++                            .getPackageManager();
    ++
    ++                    do {
    ++                        final String accountName = cursor.getString(nameColumnIdx);
    ++                        final int uid = cursor.getInt(uidColumnIdx);
    ++
    ++                        final String[] packageNames = packageManager.getPackagesForUid(uid);
    ++                        if (packageNames == null) {
    ++                            continue;
    ++                        }
    ++
    ++                        for (String packageName : packageNames) {
    ++                            String digest = PackageUtils.computePackageCertSha256Digest(
    ++                                    packageManager, packageName, userId);
    ++                            if (digest != null) {
    ++                                serializer.startTag(null, TAG_PERMISSION);
    ++                                serializer.attribute(null, ATTR_ACCOUNT_SHA_256,
    ++                                        PackageUtils.computeSha256Digest(accountName.getBytes()));
    ++                                serializer.attribute(null, ATTR_PACKAGE, packageName);
    ++                                serializer.attribute(null, ATTR_DIGEST, digest);
    ++                                serializer.endTag(null, TAG_PERMISSION);
    ++                            }
    ++                        }
    ++                    } while (cursor.moveToNext());
    ++
    ++                    serializer.endTag(null, TAG_PERMISSIONS);
    ++                    serializer.endDocument();
    ++                    serializer.flush();
    ++                } catch (IOException e) {
    ++                    Log.e(TAG, "Error backing up account access grants", e);
    ++                    return null;
    ++                }
    ++
    ++                return dataStream.toByteArray();
    ++            }
    ++        }
    ++    }
    ++
    ++    public void restoreAccountAccessPermissions(byte[] data, int userId) {
    ++        try {
    ++            ByteArrayInputStream dataStream = new ByteArrayInputStream(data);
    ++            XmlPullParser parser = Xml.newPullParser();
    ++            parser.setInput(dataStream, StandardCharsets.UTF_8.name());
    ++            PackageManager packageManager = mAccountManagerService.mContext.getPackageManager();
    ++
    ++            final int permissionsOuterDepth = parser.getDepth();
    ++            while (XmlUtils.nextElementWithin(parser, permissionsOuterDepth)) {
    ++                if (!TAG_PERMISSIONS.equals(parser.getName())) {
    ++                    continue;
    ++                }
    ++                final int permissionOuterDepth = parser.getDepth();
    ++                while (XmlUtils.nextElementWithin(parser, permissionOuterDepth)) {
    ++                    if (!TAG_PERMISSION.equals(parser.getName())) {
    ++                        continue;
    ++                    }
    ++                    String accountDigest = parser.getAttributeValue(null, ATTR_ACCOUNT_SHA_256);
    ++                    if (TextUtils.isEmpty(accountDigest)) {
    ++                        XmlUtils.skipCurrentTag(parser);
    ++                    }
    ++                    String packageName = parser.getAttributeValue(null, ATTR_PACKAGE);
    ++                    if (TextUtils.isEmpty(packageName)) {
    ++                        XmlUtils.skipCurrentTag(parser);
    ++                    }
    ++                    String digest =  parser.getAttributeValue(null, ATTR_DIGEST);
    ++                    if (TextUtils.isEmpty(digest)) {
    ++                        XmlUtils.skipCurrentTag(parser);
    ++                    }
    ++
    ++                    PendingAppPermission pendingAppPermission = new PendingAppPermission(
    ++                            accountDigest, packageName, digest, userId);
    ++
    ++                    if (!pendingAppPermission.apply(packageManager)) {
    ++                        synchronized (mLock) {
    ++                            // Start watching before add pending to avoid a missed signal
    ++                            if (mRestorePackageMonitor == null) {
    ++                                mRestorePackageMonitor = new RestorePackageMonitor();
    ++                                mRestorePackageMonitor.register(mAccountManagerService.mContext,
    ++                                        mAccountManagerService.mMessageHandler.getLooper(), true);
    ++                            }
    ++                            if (mRestorePendingAppPermissions == null) {
    ++                                mRestorePendingAppPermissions = new ArrayList<>();
    ++                            }
    ++                            mRestorePendingAppPermissions.add(pendingAppPermission);
    ++                        }
    ++                    }
    ++                }
    ++            }
    ++
    ++            // Make sure we eventually prune the in-memory pending restores
    ++            synchronized (mLock) {
    ++                mRestoreCancelCommand = new CancelRestoreCommand();
    ++            }
    ++            mAccountManagerService.mMessageHandler.postDelayed(mRestoreCancelCommand,
    ++                    PENDING_RESTORE_TIMEOUT_MILLIS);
    ++        } catch (XmlPullParserException | IOException e) {
    ++            Log.e(TAG, "Error restoring app permissions", e);
    ++        }
    ++    }
    ++
    ++    private final class RestorePackageMonitor extends PackageMonitor {
    ++        @Override
    ++        public void onPackageAdded(String packageName, int uid) {
    ++            synchronized (mLock) {
    ++                // Can happen if restore is cancelled and there is a notification in flight
    ++                if (mRestorePendingAppPermissions == null) {
    ++                    return;
    ++                }
    ++                if (UserHandle.getUserId(uid) != UserHandle.USER_SYSTEM) {
    ++                    return;
    ++                }
    ++                final int count = mRestorePendingAppPermissions.size();
    ++                for (int i = count - 1; i >= 0; i--) {
    ++                    PendingAppPermission pendingAppPermission =
    ++                            mRestorePendingAppPermissions.get(i);
    ++                    if (!pendingAppPermission.packageName.equals(packageName)) {
    ++                        continue;
    ++                    }
    ++                    if (pendingAppPermission.apply(
    ++                            mAccountManagerService.mContext.getPackageManager())) {
    ++                        mRestorePendingAppPermissions.remove(i);
    ++                    }
    ++                }
    ++                if (mRestorePendingAppPermissions.isEmpty()
    ++                        && mRestoreCancelCommand != null) {
    ++                    mAccountManagerService.mMessageHandler.removeCallbacks(mRestoreCancelCommand);
    ++                    mRestoreCancelCommand.run();
    ++                    mRestoreCancelCommand = null;
    ++                }
    ++            }
    ++        }
    ++    }
    ++
    ++    private final class CancelRestoreCommand implements Runnable {
    ++        @Override
    ++        public void run() {
    ++            synchronized (mLock) {
    ++                mRestorePendingAppPermissions = null;
    ++                if (mRestorePackageMonitor != null) {
    ++                    mRestorePackageMonitor.unregister();
    ++                    mRestorePackageMonitor = null;
    ++                }
    ++            }
    ++        }
    ++    }
    ++}
    +diff --git a/services/core/java/com/android/server/accounts/AccountManagerService.java b/services/core/java/com/android/server/accounts/AccountManagerService.java
    +index b0e8c27..a7a79cd 100644
    +--- a/services/core/java/com/android/server/accounts/AccountManagerService.java
    ++++ b/services/core/java/com/android/server/accounts/AccountManagerService.java
    +@@ -22,6 +22,7 @@ import android.accounts.Account;
    + import android.accounts.AccountAndUser;
    + import android.accounts.AccountAuthenticatorResponse;
    + import android.accounts.AccountManager;
    ++import android.accounts.AccountManagerInternal;
    + import android.accounts.AuthenticatorDescription;
    + import android.accounts.CantAddAccountActivity;
    + import android.accounts.GrantCredentialsPermissionActivity;
    +@@ -29,11 +30,15 @@ import android.accounts.IAccountAuthenticator;
    + import android.accounts.IAccountAuthenticatorResponse;
    + import android.accounts.IAccountManager;
    + import android.accounts.IAccountManagerResponse;
    ++import android.annotation.IntRange;
    + import android.annotation.NonNull;
    ++import android.annotation.Nullable;
    + import android.app.ActivityManager;
    + import android.app.ActivityManagerNative;
    ++import android.app.ActivityThread;
    + import android.app.AppGlobals;
    + import android.app.AppOpsManager;
    ++import android.app.INotificationManager;
    + import android.app.Notification;
    + import android.app.NotificationManager;
    + import android.app.PendingIntent;
    +@@ -46,9 +51,11 @@ import android.content.ContentValues;
    + import android.content.Context;
    + import android.content.Intent;
    + import android.content.IntentFilter;
    ++import android.content.IntentSender;
    + import android.content.ServiceConnection;
    + import android.content.pm.ActivityInfo;
    + import android.content.pm.ApplicationInfo;
    ++import android.content.pm.IPackageManager;
    + import android.content.pm.PackageInfo;
    + import android.content.pm.PackageManager;
    + import android.content.pm.PackageManager.NameNotFoundException;
    +@@ -72,7 +79,9 @@ import android.os.Looper;
    + import android.os.Message;
    + import android.os.Parcel;
    + import android.os.Process;
    ++import android.os.RemoteCallback;
    + import android.os.RemoteException;
    ++import android.os.ServiceManager;
    + import android.os.SystemClock;
    + import android.os.UserHandle;
    + import android.os.UserManager;
    +@@ -85,7 +94,9 @@ import android.util.SparseArray;
    + import android.util.SparseBooleanArray;
    + 
    + import com.android.internal.R;
    ++import com.android.internal.annotations.GuardedBy;
    + import com.android.internal.annotations.VisibleForTesting;
    ++import com.android.internal.content.PackageMonitor;
    + import com.android.internal.util.ArrayUtils;
    + import com.android.internal.util.IndentingPrintWriter;
    + import com.android.internal.util.Preconditions;
    +@@ -115,6 +126,9 @@ import java.util.LinkedHashMap;
    + import java.util.List;
    + import java.util.Map;
    + import java.util.Map.Entry;
    ++import java.util.Objects;
    ++import java.util.UUID;
    ++import java.util.concurrent.CopyOnWriteArrayList;
    + import java.util.concurrent.atomic.AtomicInteger;
    + import java.util.concurrent.atomic.AtomicReference;
    + 
    +@@ -145,13 +159,6 @@ public class AccountManagerService
    +         }
    + 
    +         @Override
    +-        public void onBootPhase(int phase) {
    +-            if (phase == SystemService.PHASE_ACTIVITY_MANAGER_READY) {
    +-                mService.systemReady();
    +-            }
    +-        }
    +-
    +-        @Override
    +         public void onUnlockUser(int userHandle) {
    +             mService.onUnlockUser(userHandle);
    +         }
    +@@ -164,13 +171,13 @@ public class AccountManagerService
    + 
    +     private static final int MAX_DEBUG_DB_SIZE = 64;
    + 
    +-    private final Context mContext;
    ++    final Context mContext;
    + 
    +     private final PackageManager mPackageManager;
    +     private final AppOpsManager mAppOpsManager;
    +     private UserManager mUserManager;
    + 
    +-    private final MessageHandler mMessageHandler;
    ++    final MessageHandler mMessageHandler;
    + 
    +     // Messages that can be sent on mHandler
    +     private static final int MESSAGE_TIMED_OUT = 3;
    +@@ -178,9 +185,9 @@ public class AccountManagerService
    + 
    +     private final IAccountAuthenticatorCache mAuthenticatorCache;
    + 
    +-    private static final String TABLE_ACCOUNTS = "accounts";
    +-    private static final String ACCOUNTS_ID = "_id";
    +-    private static final String ACCOUNTS_NAME = "name";
    ++    static final String TABLE_ACCOUNTS = "accounts";
    ++    static final String ACCOUNTS_ID = "_id";
    ++    static final String ACCOUNTS_NAME = "name";
    +     private static final String ACCOUNTS_TYPE = "type";
    +     private static final String ACCOUNTS_TYPE_COUNT = "count(type)";
    +     private static final String ACCOUNTS_PASSWORD = "password";
    +@@ -194,10 +201,10 @@ public class AccountManagerService
    +     private static final String AUTHTOKENS_TYPE = "type";
    +     private static final String AUTHTOKENS_AUTHTOKEN = "authtoken";
    + 
    +-    private static final String TABLE_GRANTS = "grants";
    +-    private static final String GRANTS_ACCOUNTS_ID = "accounts_id";
    ++    static final String TABLE_GRANTS = "grants";
    ++    static final String GRANTS_ACCOUNTS_ID = "accounts_id";
    +     private static final String GRANTS_AUTH_TOKEN_TYPE = "auth_token_type";
    +-    private static final String GRANTS_GRANTEE_UID = "uid";
    ++    static final String GRANTS_GRANTEE_UID = "uid";
    + 
    +     private static final String TABLE_EXTRAS = "extras";
    +     private static final String EXTRAS_ID = "_id";
    +@@ -237,6 +244,13 @@ public class AccountManagerService
    +             + " AND " + ACCOUNTS_NAME + "=?"
    +             + " AND " + ACCOUNTS_TYPE + "=?";
    + 
    ++    private static final String COUNT_OF_MATCHING_GRANTS_ANY_TOKEN = ""
    ++            + "SELECT COUNT(*) FROM " + TABLE_GRANTS + ", " + TABLE_ACCOUNTS
    ++            + " WHERE " + GRANTS_ACCOUNTS_ID + "=" + ACCOUNTS_ID
    ++            + " AND " + GRANTS_GRANTEE_UID + "=?"
    ++            + " AND " + ACCOUNTS_NAME + "=?"
    ++            + " AND " + ACCOUNTS_TYPE + "=?";
    ++
    +     private static final String SELECTION_AUTHTOKENS_BY_ACCOUNT =
    +             AUTHTOKENS_ACCOUNTS_ID + "=(select _id FROM accounts WHERE name=? AND type=?)";
    + 
    +@@ -257,16 +271,16 @@ public class AccountManagerService
    + 
    +     static class UserAccounts {
    +         private final int userId;
    +-        private final DeDatabaseHelper openHelper;
    ++        final DeDatabaseHelper openHelper;
    +         private final HashMap<Pair<Pair<Account, String>, Integer>, Integer>
    +                 credentialsPermissionNotificationIds =
    +                 new HashMap<Pair<Pair<Account, String>, Integer>, Integer>();
    +         private final HashMap<Account, Integer> signinRequiredNotificationIds =
    +                 new HashMap<Account, Integer>();
    +-        private final Object cacheLock = new Object();
    ++        final Object cacheLock = new Object();
    +         /** protected by the {@link #cacheLock} */
    +-        private final HashMap<String, Account[]> accountCache =
    +-                new LinkedHashMap<String, Account[]>();
    ++        final HashMap<String, Account[]> accountCache =
    ++                new LinkedHashMap<>();
    +         /** protected by the {@link #cacheLock} */
    +         private final HashMap<Account, HashMap<String, String>> userDataCache =
    +                 new HashMap<Account, HashMap<String, String>>();
    +@@ -305,6 +319,8 @@ public class AccountManagerService
    + 
    +     private final SparseArray<UserAccounts> mUsers = new SparseArray<>();
    +     private final SparseBooleanArray mLocalUnlockedUsers = new SparseBooleanArray();
    ++    private final CopyOnWriteArrayList<AccountManagerInternal.OnAppPermissionChangeListener>
    ++            mAppPermissionChangeListeners = new CopyOnWriteArrayList<>();
    + 
    +     private static AtomicReference<AccountManagerService> sThis = new AtomicReference<>();
    +     private static final Account[] EMPTY_ACCOUNT_ARRAY = new Account[]{};
    +@@ -376,6 +392,118 @@ public class AccountManagerService
    +                 }
    +             }
    +         }, UserHandle.ALL, userFilter, null, null);
    ++
    ++        LocalServices.addService(AccountManagerInternal.class, new AccountManagerInternalImpl());
    ++
    ++        // Need to cancel account request notifications if the update/install can access the account
    ++        new PackageMonitor() {
    ++            @Override
    ++            public void onPackageAdded(String packageName, int uid) {
    ++                // Called on a handler, and running as the system
    ++                cancelAccountAccessRequestNotificationIfNeeded(uid, true);
    ++            }
    ++
    ++            @Override
    ++            public void onPackageUpdateFinished(String packageName, int uid) {
    ++                // Called on a handler, and running as the system
    ++                cancelAccountAccessRequestNotificationIfNeeded(uid, true);
    ++            }
    ++        }.register(mContext, mMessageHandler.getLooper(), UserHandle.ALL, true);
    ++
    ++        // Cancel account request notification if an app op was preventing the account access
    ++        mAppOpsManager.startWatchingMode(AppOpsManager.OP_GET_ACCOUNTS, null,
    ++                new AppOpsManager.OnOpChangedInternalListener() {
    ++            @Override
    ++            public void onOpChanged(int op, String packageName) {
    ++                try {
    ++                    final int userId = ActivityManager.getCurrentUser();
    ++                    final int uid = mPackageManager.getPackageUidAsUser(packageName, userId);
    ++                    final int mode = mAppOpsManager.checkOpNoThrow(
    ++                            AppOpsManager.OP_GET_ACCOUNTS, uid, packageName);
    ++                    if (mode == AppOpsManager.MODE_ALLOWED) {
    ++                        final long identity = Binder.clearCallingIdentity();
    ++                        try {
    ++                            cancelAccountAccessRequestNotificationIfNeeded(packageName, uid, true);
    ++                        } finally {
    ++                            Binder.restoreCallingIdentity(identity);
    ++                        }
    ++                    }
    ++                } catch (NameNotFoundException e) {
    ++                    /* ignore */
    ++                }
    ++            }
    ++        });
    ++
    ++        // Cancel account request notification if a permission was preventing the account access
    ++        mPackageManager.addOnPermissionsChangeListener(
    ++                (int uid) -> {
    ++            Account[] accounts = null;
    ++            String[] packageNames = mPackageManager.getPackagesForUid(uid);
    ++            if (packageNames != null) {
    ++                final int userId = UserHandle.getUserId(uid);
    ++                final long identity = Binder.clearCallingIdentity();
    ++                try {
    ++                    for (String packageName : packageNames) {
    ++                        if (mContext.getPackageManager().checkPermission(
    ++                                Manifest.permission.GET_ACCOUNTS, packageName)
    ++                                        != PackageManager.PERMISSION_GRANTED) {
    ++                            continue;
    ++                        }
    ++
    ++                        if (accounts == null) {
    ++                            accounts = getAccountsAsUser(null, userId, "android");
    ++                            if (ArrayUtils.isEmpty(accounts)) {
    ++                                return;
    ++                            }
    ++                        }
    ++
    ++                        for (Account account : accounts) {
    ++                            cancelAccountAccessRequestNotificationIfNeeded(
    ++                                    account, uid, packageName, true);
    ++                        }
    ++                    }
    ++                } finally {
    ++                    Binder.restoreCallingIdentity(identity);
    ++                }
    ++            }
    ++        });
    ++    }
    ++
    ++    private void cancelAccountAccessRequestNotificationIfNeeded(int uid,
    ++            boolean checkAccess) {
    ++        Account[] accounts = getAccountsAsUser(null, UserHandle.getUserId(uid), "android");
    ++        for (Account account : accounts) {
    ++            cancelAccountAccessRequestNotificationIfNeeded(account, uid, checkAccess);
    ++        }
    ++    }
    ++
    ++    private void cancelAccountAccessRequestNotificationIfNeeded(String packageName, int uid,
    ++            boolean checkAccess) {
    ++        Account[] accounts = getAccountsAsUser(null, UserHandle.getUserId(uid), "android");
    ++        for (Account account : accounts) {
    ++            cancelAccountAccessRequestNotificationIfNeeded(account, uid, packageName, checkAccess);
    ++        }
    ++    }
    ++
    ++    private void cancelAccountAccessRequestNotificationIfNeeded(Account account, int uid,
    ++            boolean checkAccess) {
    ++        String[] packageNames = mPackageManager.getPackagesForUid(uid);
    ++        if (packageNames != null) {
    ++            for (String packageName : packageNames) {
    ++                cancelAccountAccessRequestNotificationIfNeeded(account, uid,
    ++                        packageName, checkAccess);
    ++            }
    ++        }
    ++    }
    ++
    ++    private void cancelAccountAccessRequestNotificationIfNeeded(Account account,
    ++            int uid, String packageName, boolean checkAccess) {
    ++        if (!checkAccess || hasAccountAccess(account, packageName,
    ++                UserHandle.getUserHandleForUid(uid))) {
    ++            cancelNotification(getCredentialPermissionNotificationId(account,
    ++                    AccountManager.ACCOUNT_ACCESS_TOKEN_TYPE, uid), packageName,
    ++                    UserHandle.getUserHandleForUid(uid));
    ++        }
    +     }
    + 
    +     @Override
    +@@ -393,9 +521,6 @@ public class AccountManagerService
    +         }
    +     }
    + 
    +-    public void systemReady() {
    +-    }
    +-
    +     private UserManager getUserManager() {
    +         if (mUserManager == null) {
    +             mUserManager = UserManager.get(mContext);
    +@@ -566,7 +691,8 @@ public class AccountManagerService
    +                     final ArrayList<String> accountNames = cur.getValue();
    +                     final Account[] accountsForType = new Account[accountNames.size()];
    +                     for (int i = 0; i < accountsForType.length; i++) {
    +-                        accountsForType[i] = new Account(accountNames.get(i), accountType);
    ++                        accountsForType[i] = new Account(accountNames.get(i), accountType,
    ++                                UUID.randomUUID().toString());
    +                     }
    +                     accounts.accountCache.put(accountType, accountsForType);
    +                 }
    +@@ -1376,6 +1502,8 @@ public class AccountManagerService
    +             Bundle result = new Bundle();
    +             result.putString(AccountManager.KEY_ACCOUNT_NAME, resultingAccount.name);
    +             result.putString(AccountManager.KEY_ACCOUNT_TYPE, resultingAccount.type);
    ++            result.putString(AccountManager.KEY_ACCOUNT_ACCESS_ID,
    ++                    resultingAccount.getAccessId());
    +             try {
    +                 response.onResult(result);
    +             } catch (RemoteException e) {
    +@@ -1434,8 +1562,10 @@ public class AccountManagerService
    +             /*
    +              * Database transaction was successful. Clean up cached
    +              * data associated with the account in the user profile.
    ++             * The account is now being tracked for remote access.
    +              */
    +-            insertAccountIntoCacheLocked(accounts, renamedAccount);
    ++            renamedAccount = insertAccountIntoCacheLocked(accounts, renamedAccount);
    ++
    +             /*
    +              * Extract the data and token caches before removing the
    +              * old account to preserve the user data associated with
    +@@ -1722,6 +1852,21 @@ public class AccountManagerService
    +         } finally {
    +             Binder.restoreCallingIdentity(id);
    +         }
    ++
    ++        if (isChanged) {
    ++            synchronized (accounts.credentialsPermissionNotificationIds) {
    ++                for (Pair<Pair<Account, String>, Integer> key
    ++                        : accounts.credentialsPermissionNotificationIds.keySet()) {
    ++                    if (account.equals(key.first.first)
    ++                            && AccountManager.ACCOUNT_ACCESS_TOKEN_TYPE.equals(key.first.second)) {
    ++                        final int uid = (Integer) key.second;
    ++                        mMessageHandler.post(() -> cancelAccountAccessRequestNotificationIfNeeded(
    ++                                account, uid, false));
    ++                    }
    ++                }
    ++            }
    ++        }
    ++
    +         return isChanged;
    +     }
    + 
    +@@ -2118,7 +2263,7 @@ public class AccountManagerService
    + 
    +         final int callingUid = getCallingUid();
    +         clearCallingIdentity();
    +-        if (callingUid != Process.SYSTEM_UID) {
    ++        if (UserHandle.getAppId(callingUid) != Process.SYSTEM_UID) {
    +             throw new SecurityException("can only call from system");
    +         }
    +         int userId = UserHandle.getUserId(callingUid);
    +@@ -2318,9 +2463,11 @@ public class AccountManagerService
    +                         if (result.containsKey(AccountManager.KEY_AUTH_TOKEN_LABEL)) {
    +                             Intent intent = newGrantCredentialsPermissionIntent(
    +                                     account,
    ++                                    null,
    +                                     callerUid,
    +                                     new AccountAuthenticatorResponse(this),
    +-                                    authTokenType);
    ++                                    authTokenType,
    ++                                    true);
    +                             Bundle bundle = new Bundle();
    +                             bundle.putParcelable(AccountManager.KEY_INTENT, intent);
    +                             onResult(bundle);
    +@@ -2371,7 +2518,7 @@ public class AccountManagerService
    +                                     intent);
    +                             doNotification(mAccounts,
    +                                     account, result.getString(AccountManager.KEY_AUTH_FAILED_MESSAGE),
    +-                                    intent, accounts.userId);
    ++                                    intent, "android", accounts.userId);
    +                         }
    +                     }
    +                     super.onResult(result);
    +@@ -2402,7 +2549,7 @@ public class AccountManagerService
    +     }
    + 
    +     private void createNoCredentialsPermissionNotification(Account account, Intent intent,
    +-            int userId) {
    ++            String packageName, int userId) {
    +         int uid = intent.getIntExtra(
    +                 GrantCredentialsPermissionActivity.EXTRAS_REQUESTING_UID, -1);
    +         String authTokenType = intent.getStringExtra(
    +@@ -2430,20 +2577,23 @@ public class AccountManagerService
    +                         PendingIntent.FLAG_CANCEL_CURRENT, null, user))
    +                 .build();
    +         installNotification(getCredentialPermissionNotificationId(
    +-                account, authTokenType, uid), n, user);
    ++                account, authTokenType, uid), n, packageName, user.getIdentifier());
    +     }
    + 
    +-    private Intent newGrantCredentialsPermissionIntent(Account account, int uid,
    +-            AccountAuthenticatorResponse response, String authTokenType) {
    ++    private Intent newGrantCredentialsPermissionIntent(Account account, String packageName,
    ++            int uid, AccountAuthenticatorResponse response, String authTokenType,
    ++            boolean startInNewTask) {
    + 
    +         Intent intent = new Intent(mContext, GrantCredentialsPermissionActivity.class);
    +-        // See FLAG_ACTIVITY_NEW_TASK docs for limitations and benefits of the flag.
    +-        // Since it was set in Eclair+ we can't change it without breaking apps using
    +-        // the intent from a non-Activity context.
    +-        intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
    +-        intent.addCategory(
    +-                String.valueOf(getCredentialPermissionNotificationId(account, authTokenType, uid)));
    + 
    ++        if (startInNewTask) {
    ++            // See FLAG_ACTIVITY_NEW_TASK docs for limitations and benefits of the flag.
    ++            // Since it was set in Eclair+ we can't change it without breaking apps using
    ++            // the intent from a non-Activity context. This is the default behavior.
    ++            intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
    ++        }
    ++        intent.addCategory(String.valueOf(getCredentialPermissionNotificationId(account,
    ++                authTokenType, uid) + (packageName != null ? packageName : "")));
    +         intent.putExtra(GrantCredentialsPermissionActivity.EXTRAS_ACCOUNT, account);
    +         intent.putExtra(GrantCredentialsPermissionActivity.EXTRAS_AUTH_TOKEN_TYPE, authTokenType);
    +         intent.putExtra(GrantCredentialsPermissionActivity.EXTRAS_RESPONSE, response);
    +@@ -3294,6 +3444,137 @@ public class AccountManagerService
    +     }
    + 
    +     @Override
    ++    public boolean hasAccountAccess(@NonNull Account account,  @NonNull String packageName,
    ++            @NonNull UserHandle userHandle) {
    ++        if (UserHandle.getAppId(Binder.getCallingUid()) != Process.SYSTEM_UID) {
    ++            throw new SecurityException("Can be called only by system UID");
    ++        }
    ++        Preconditions.checkNotNull(account, "account cannot be null");
    ++        Preconditions.checkNotNull(packageName, "packageName cannot be null");
    ++        Preconditions.checkNotNull(userHandle, "userHandle cannot be null");
    ++
    ++        final int userId = userHandle.getIdentifier();
    ++
    ++        Preconditions.checkArgumentInRange(userId, 0, Integer.MAX_VALUE, "user must be concrete");
    ++
    ++        try {
    ++            final int uid = mPackageManager.getPackageUidAsUser(packageName, userId);
    ++            return hasAccountAccess(account, packageName, uid);
    ++        } catch (NameNotFoundException e) {
    ++            return false;
    ++        }
    ++    }
    ++
    ++    private boolean hasAccountAccess(@NonNull Account account, @Nullable String packageName,
    ++            int uid) {
    ++        if (packageName == null) {
    ++            String[] packageNames = mPackageManager.getPackagesForUid(uid);
    ++            if (ArrayUtils.isEmpty(packageNames)) {
    ++                return false;
    ++            }
    ++            // For app op checks related to permissions all packages in the UID
    ++            // have the same app op state, so doesn't matter which one we pick.
    ++            packageName = packageNames[0];
    ++        }
    ++
    ++        // Use null token which means any token. Having a token means the package
    ++        // is trusted by the authenticator, hence it is fine to access the account.
    ++        if (permissionIsGranted(account, null, uid, UserHandle.getUserId(uid))) {
    ++            return true;
    ++        }
    ++        // In addition to the permissions required to get an auth token we also allow
    ++        // the account to be accessed by holders of the get accounts permissions.
    ++        return checkUidPermission(Manifest.permission.GET_ACCOUNTS_PRIVILEGED, uid, packageName)
    ++                || checkUidPermission(Manifest.permission.GET_ACCOUNTS, uid, packageName);
    ++    }
    ++
    ++    private boolean checkUidPermission(String permission, int uid, String opPackageName) {
    ++        final long identity = Binder.clearCallingIdentity();
    ++        try {
    ++            IPackageManager pm = ActivityThread.getPackageManager();
    ++            if (pm.checkUidPermission(permission, uid) != PackageManager.PERMISSION_GRANTED) {
    ++                return false;
    ++            }
    ++            final int opCode = AppOpsManager.permissionToOpCode(permission);
    ++            return (opCode == AppOpsManager.OP_NONE || mAppOpsManager.noteOpNoThrow(
    ++                    opCode, uid, opPackageName) == AppOpsManager.MODE_ALLOWED);
    ++        } catch (RemoteException e) {
    ++            /* ignore - local call */
    ++        } finally {
    ++            Binder.restoreCallingIdentity(identity);
    ++        }
    ++        return false;
    ++    }
    ++
    ++    @Override
    ++    public IntentSender createRequestAccountAccessIntentSenderAsUser(@NonNull Account account,
    ++            @NonNull String packageName, @NonNull UserHandle userHandle) {
    ++        if (UserHandle.getAppId(Binder.getCallingUid()) != Process.SYSTEM_UID) {
    ++            throw new SecurityException("Can be called only by system UID");
    ++        }
    ++
    ++        Preconditions.checkNotNull(account, "account cannot be null");
    ++        Preconditions.checkNotNull(packageName, "packageName cannot be null");
    ++        Preconditions.checkNotNull(userHandle, "userHandle cannot be null");
    ++
    ++        final int userId = userHandle.getIdentifier();
    ++
    ++        Preconditions.checkArgumentInRange(userId, 0, Integer.MAX_VALUE, "user must be concrete");
    ++
    ++        final int uid;
    ++        try {
    ++            uid = mPackageManager.getPackageUidAsUser(packageName, userId);
    ++        } catch (NameNotFoundException e) {
    ++            Slog.e(TAG, "Unknown package " + packageName);
    ++            return null;
    ++        }
    ++
    ++        Intent intent = newRequestAccountAccessIntent(account, packageName, uid, null);
    ++
    ++        final long identity = Binder.clearCallingIdentity();
    ++        try {
    ++            return PendingIntent.getActivityAsUser(
    ++                    mContext, 0, intent, PendingIntent.FLAG_ONE_SHOT
    ++                            | PendingIntent.FLAG_CANCEL_CURRENT | PendingIntent.FLAG_IMMUTABLE,
    ++                    null, new UserHandle(userId)).getIntentSender();
    ++        } finally {
    ++            Binder.restoreCallingIdentity(identity);
    ++        }
    ++    }
    ++
    ++    private Intent newRequestAccountAccessIntent(Account account, String packageName,
    ++            int uid, RemoteCallback callback) {
    ++        return newGrantCredentialsPermissionIntent(account, packageName, uid,
    ++                new AccountAuthenticatorResponse(new IAccountAuthenticatorResponse.Stub() {
    ++            @Override
    ++            public void onResult(Bundle value) throws RemoteException {
    ++                handleAuthenticatorResponse(true);
    ++            }
    ++
    ++            @Override
    ++            public void onRequestContinued() {
    ++                /* ignore */
    ++            }
    ++
    ++            @Override
    ++            public void onError(int errorCode, String errorMessage) throws RemoteException {
    ++                handleAuthenticatorResponse(false);
    ++            }
    ++
    ++            private void handleAuthenticatorResponse(boolean accessGranted) throws RemoteException {
    ++                cancelNotification(getCredentialPermissionNotificationId(account,
    ++                        AccountManager.ACCOUNT_ACCESS_TOKEN_TYPE, uid), packageName,
    ++                        UserHandle.getUserHandleForUid(uid));
    ++                if (callback != null) {
    ++                    Bundle result = new Bundle();
    ++                    result.putBoolean(AccountManager.KEY_BOOLEAN_RESULT, accessGranted);
    ++                    callback.sendResult(result);
    ++                }
    ++            }
    ++        }), AccountManager.ACCOUNT_ACCESS_TOKEN_TYPE, false);
    ++    }
    ++
    ++    @Override
    +     public boolean someUserHasAccount(@NonNull final Account account) {
    +         if (!UserHandle.isSameApp(Process.SYSTEM_UID, Binder.getCallingUid())) {
    +             throw new SecurityException("Only system can check for accounts across users");
    +@@ -3798,6 +4079,30 @@ public class AccountManagerService
    +         }
    +     }
    + 
    ++    @Override
    ++    public void onAccountAccessed(String token) throws RemoteException {
    ++        final int uid = Binder.getCallingUid();
    ++        if (UserHandle.getAppId(uid) == Process.SYSTEM_UID) {
    ++            return;
    ++        }
    ++        final int userId = UserHandle.getCallingUserId();
    ++        final long identity = Binder.clearCallingIdentity();
    ++        try {
    ++            for (Account account : getAccounts(userId, mContext.getOpPackageName())) {
    ++                if (Objects.equals(account.getAccessId(), token)) {
    ++                    // An app just accessed the account. At this point it knows about
    ++                    // it and there is not need to hide this account from the app.
    ++                    if (!hasAccountAccess(account, null, uid)) {
    ++                        updateAppPermission(account, AccountManager.ACCOUNT_ACCESS_TOKEN_TYPE,
    ++                                uid, true);
    ++                    }
    ++                }
    ++            }
    ++        } finally {
    ++            Binder.restoreCallingIdentity(identity);
    ++        }
    ++    }
    ++
    +     private abstract class Session extends IAccountAuthenticatorResponse.Stub
    +             implements IBinder.DeathRecipient, ServiceConnection {
    +         IAccountManagerResponse mResponse;
    +@@ -4166,7 +4471,7 @@ public class AccountManagerService
    +         }
    +     }
    + 
    +-    private class MessageHandler extends Handler {
    ++    class MessageHandler extends Handler {
    +         MessageHandler(Looper looper) {
    +             super(looper);
    +         }
    +@@ -4933,7 +5238,7 @@ public class AccountManagerService
    +     }
    + 
    +     private void doNotification(UserAccounts accounts, Account account, CharSequence message,
    +-            Intent intent, int userId) {
    ++            Intent intent, String packageName, final int userId) {
    +         long identityToken = clearCallingIdentity();
    +         try {
    +             if (Log.isLoggable(TAG, Log.VERBOSE)) {
    +@@ -4943,12 +5248,12 @@ public class AccountManagerService
    +             if (intent.getComponent() != null &&
    +                     GrantCredentialsPermissionActivity.class.getName().equals(
    +                             intent.getComponent().getClassName())) {
    +-                createNoCredentialsPermissionNotification(account, intent, userId);
    ++                createNoCredentialsPermissionNotification(account, intent, packageName, userId);
    +             } else {
    ++                Context contextForUser = getContextForUser(new UserHandle(userId));
    +                 final Integer notificationId = getSigninRequiredNotificationId(accounts, account);
    +                 intent.addCategory(String.valueOf(notificationId));
    +-                UserHandle user = new UserHandle(userId);
    +-                Context contextForUser = getContextForUser(user);
    ++
    +                 final String notificationTitleFormat =
    +                         contextForUser.getText(R.string.notification_title).toString();
    +                 Notification n = new Notification.Builder(contextForUser)
    +@@ -4960,9 +5265,9 @@ public class AccountManagerService
    +                         .setContentText(message)
    +                         .setContentIntent(PendingIntent.getActivityAsUser(
    +                                 mContext, 0, intent, PendingIntent.FLAG_CANCEL_CURRENT,
    +-                                null, user))
    ++                                null, new UserHandle(userId)))
    +                         .build();
    +-                installNotification(notificationId, n, user);
    ++                installNotification(notificationId, n, packageName, userId);
    +             }
    +         } finally {
    +             restoreCallingIdentity(identityToken);
    +@@ -4970,18 +5275,40 @@ public class AccountManagerService
    +     }
    + 
    +     @VisibleForTesting
    +-    protected void installNotification(final int notificationId, final Notification n,
    ++    protected void installNotification(int notificationId, final Notification notification,
    +             UserHandle user) {
    +-        ((NotificationManager) mContext.getSystemService(Context.NOTIFICATION_SERVICE))
    +-                .notifyAsUser(null, notificationId, n, user);
    ++        installNotification(notificationId, notification, "android", user.getIdentifier());
    ++    }
    ++
    ++    private void installNotification(int notificationId, final Notification notification,
    ++            String packageName, int userId) {
    ++        final long token = clearCallingIdentity();
    ++        try {
    ++            INotificationManager notificationManager = NotificationManager.getService();
    ++            try {
    ++                notificationManager.enqueueNotificationWithTag(packageName, packageName, null,
    ++                        notificationId, notification, new int[1], userId);
    ++            } catch (RemoteException e) {
    ++                /* ignore - local call */
    ++            }
    ++        } finally {
    ++            Binder.restoreCallingIdentity(token);
    ++        }
    +     }
    + 
    +     @VisibleForTesting
    +     protected void cancelNotification(int id, UserHandle user) {
    ++        cancelNotification(id, mContext.getPackageName(), user);
    ++    }
    ++
    ++    protected void cancelNotification(int id, String packageName, UserHandle user) {
    +         long identityToken = clearCallingIdentity();
    +         try {
    +-            ((NotificationManager) mContext.getSystemService(Context.NOTIFICATION_SERVICE))
    +-                .cancelAsUser(null, id, user);
    ++            INotificationManager service = INotificationManager.Stub.asInterface(
    ++                    ServiceManager.getService(Context.NOTIFICATION_SERVICE));
    ++            service.cancelNotificationWithTag(packageName, null, id, user.getIdentifier());
    ++        } catch (RemoteException e) {
    ++            /* ignore - local call */
    +         } finally {
    +             restoreCallingIdentity(identityToken);
    +         }
    +@@ -5042,18 +5369,40 @@ public class AccountManagerService
    + 
    +     private boolean permissionIsGranted(
    +             Account account, String authTokenType, int callerUid, int userId) {
    +-        final boolean isPrivileged = isPrivileged(callerUid);
    +-        final boolean fromAuthenticator = account != null
    +-                && isAccountManagedByCaller(account.type, callerUid, userId);
    +-        final boolean hasExplicitGrants = account != null
    +-                && hasExplicitlyGrantedPermission(account, authTokenType, callerUid);
    ++        if (UserHandle.getAppId(callerUid) == Process.SYSTEM_UID) {
    ++            if (Log.isLoggable(TAG, Log.VERBOSE)) {
    ++                Log.v(TAG, "Access to " + account + " granted calling uid is system");
    ++            }
    ++            return true;
    ++        }
    ++
    ++        if (isPrivileged(callerUid)) {
    ++            if (Log.isLoggable(TAG, Log.VERBOSE)) {
    ++                Log.v(TAG, "Access to " + account + " granted calling uid "
    ++                        + callerUid + " privileged");
    ++            }
    ++            return true;
    ++        }
    ++        if (account != null && isAccountManagedByCaller(account.type, callerUid, userId)) {
    ++            if (Log.isLoggable(TAG, Log.VERBOSE)) {
    ++                Log.v(TAG, "Access to " + account + " granted calling uid "
    ++                        + callerUid + " manages the account");
    ++            }
    ++            return true;
    ++        }
    ++        if (account != null && hasExplicitlyGrantedPermission(account, authTokenType, callerUid)) {
    ++            if (Log.isLoggable(TAG, Log.VERBOSE)) {
    ++                Log.v(TAG, "Access to " + account + " granted calling uid "
    ++                        + callerUid + " user granted access");
    ++            }
    ++            return true;
    ++        }
    ++
    +         if (Log.isLoggable(TAG, Log.VERBOSE)) {
    +-            Log.v(TAG, "checkGrantsOrCallingUidAgainstAuthenticator: caller uid "
    +-                    + callerUid + ", " + account
    +-                    + ": is authenticator? " + fromAuthenticator
    +-                    + ", has explicit permission? " + hasExplicitGrants);
    ++            Log.v(TAG, "Access to " + account + " not granted for uid " + callerUid);
    +         }
    +-        return fromAuthenticator || hasExplicitGrants || isPrivileged;
    ++
    ++        return false;
    +     }
    + 
    +     private boolean isAccountVisibleToCaller(String accountType, int callingUid, int userId,
    +@@ -5137,16 +5486,26 @@ public class AccountManagerService
    + 
    +     private boolean hasExplicitlyGrantedPermission(Account account, String authTokenType,
    +             int callerUid) {
    +-        if (callerUid == Process.SYSTEM_UID) {
    ++        if (UserHandle.getAppId(callerUid) == Process.SYSTEM_UID) {
    +             return true;
    +         }
    +-        UserAccounts accounts = getUserAccountsForCaller();
    ++        UserAccounts accounts = getUserAccounts(UserHandle.getUserId(callerUid));
    +         synchronized (accounts.cacheLock) {
    +             final SQLiteDatabase db = accounts.openHelper.getReadableDatabase();
    +-            String[] args = { String.valueOf(callerUid), authTokenType,
    +-                    account.name, account.type};
    +-            final boolean permissionGranted =
    +-                    DatabaseUtils.longForQuery(db, COUNT_OF_MATCHING_GRANTS, args) != 0;
    ++
    ++            final String query;
    ++            final String[] args;
    ++
    ++            if (authTokenType != null) {
    ++                query = COUNT_OF_MATCHING_GRANTS;
    ++                args = new String[] {String.valueOf(callerUid), authTokenType,
    ++                        account.name, account.type};
    ++            } else {
    ++                query = COUNT_OF_MATCHING_GRANTS_ANY_TOKEN;
    ++                args = new String[] {String.valueOf(callerUid), account.name,
    ++                        account.type};
    ++            }
    ++            final boolean permissionGranted = DatabaseUtils.longForQuery(db, query, args) != 0;
    +             if (!permissionGranted && ActivityManager.isRunningInTestHarness()) {
    +                 // TODO: Skip this check when running automated tests. Replace this
    +                 // with a more general solution.
    +@@ -5245,7 +5604,7 @@ public class AccountManagerService
    +             throws RemoteException {
    +         final int callingUid = getCallingUid();
    + 
    +-        if (callingUid != Process.SYSTEM_UID) {
    ++        if (UserHandle.getAppId(callingUid) != Process.SYSTEM_UID) {
    +             throw new SecurityException();
    +         }
    + 
    +@@ -5263,7 +5622,7 @@ public class AccountManagerService
    +      * which is in the system. This means we don't need to protect it with permissions.
    +      * @hide
    +      */
    +-    private void grantAppPermission(Account account, String authTokenType, int uid) {
    ++    void grantAppPermission(Account account, String authTokenType, int uid) {
    +         if (account == null || authTokenType == null) {
    +             Log.e(TAG, "grantAppPermission: called with invalid arguments", new Exception());
    +             return;
    +@@ -5287,6 +5646,14 @@ public class AccountManagerService
    +             }
    +             cancelNotification(getCredentialPermissionNotificationId(account, authTokenType, uid),
    +                     UserHandle.of(accounts.userId));
    ++
    ++            cancelAccountAccessRequestNotificationIfNeeded(account, uid, true);
    ++        }
    ++
    ++        // Listeners are a final CopyOnWriteArrayList, hence no lock needed.
    ++        for (AccountManagerInternal.OnAppPermissionChangeListener listener
    ++                : mAppPermissionChangeListeners) {
    ++            mMessageHandler.post(() -> listener.onAppPermissionChanged(account, uid));
    +         }
    +     }
    + 
    +@@ -5320,9 +5687,16 @@ public class AccountManagerService
    +             } finally {
    +                 db.endTransaction();
    +             }
    ++
    +             cancelNotification(getCredentialPermissionNotificationId(account, authTokenType, uid),
    +                     new UserHandle(accounts.userId));
    +         }
    ++
    ++        // Listeners are a final CopyOnWriteArrayList, hence no lock needed.
    ++        for (AccountManagerInternal.OnAppPermissionChangeListener listener
    ++                : mAppPermissionChangeListeners) {
    ++            mMessageHandler.post(() -> listener.onAppPermissionChanged(account, uid));
    ++        }
    +     }
    + 
    +     static final private String stringArrayToString(String[] value) {
    +@@ -5353,16 +5727,22 @@ public class AccountManagerService
    + 
    +     /**
    +      * This assumes that the caller has already checked that the account is not already present.
    ++     * IMPORTANT: The account being inserted will begin to be tracked for access in remote
    ++     * processes and if you will return this account to apps you should return the result.
    ++     * @return The inserted account which is a new instance that is being tracked.
    +      */
    +-    private void insertAccountIntoCacheLocked(UserAccounts accounts, Account account) {
    ++    private Account insertAccountIntoCacheLocked(UserAccounts accounts, Account account) {
    +         Account[] accountsForType = accounts.accountCache.get(account.type);
    +         int oldLength = (accountsForType != null) ? accountsForType.length : 0;
    +         Account[] newAccountsForType = new Account[oldLength + 1];
    +         if (accountsForType != null) {
    +             System.arraycopy(accountsForType, 0, newAccountsForType, 0, oldLength);
    +         }
    +-        newAccountsForType[oldLength] = account;
    ++        String token = account.getAccessId() != null ? account.getAccessId()
    ++                : UUID.randomUUID().toString();
    ++        newAccountsForType[oldLength] = new Account(account, token);
    +         accounts.accountCache.put(account.type, newAccountsForType);
    ++        return newAccountsForType[oldLength];
    +     }
    + 
    +     private Account[] filterSharedAccounts(UserAccounts userAccounts, Account[] unfiltered,
    +@@ -5604,4 +5984,88 @@ public class AccountManagerService
    +             }
    +         }
    +     }
    ++
    ++    private final class AccountManagerInternalImpl extends AccountManagerInternal {
    ++        private final Object mLock = new Object();
    ++
    ++        @GuardedBy("mLock")
    ++        private AccountManagerBackupHelper mBackupHelper;
    ++
    ++        @Override
    ++        public void requestAccountAccess(@NonNull Account account, @NonNull String packageName,
    ++                @IntRange(from = 0) int userId, @NonNull RemoteCallback callback) {
    ++            if (account == null) {
    ++                Slog.w(TAG, "account cannot be null");
    ++                return;
    ++            }
    ++            if (packageName == null) {
    ++                Slog.w(TAG, "packageName cannot be null");
    ++                return;
    ++            }
    ++            if (userId < UserHandle.USER_SYSTEM) {
    ++                Slog.w(TAG, "user id must be concrete");
    ++                return;
    ++            }
    ++            if (callback == null) {
    ++                Slog.w(TAG, "callback cannot be null");
    ++                return;
    ++            }
    ++
    ++            if (AccountManagerService.this.hasAccountAccess(account, packageName,
    ++                    new UserHandle(userId))) {
    ++                Bundle result = new Bundle();
    ++                result.putBoolean(AccountManager.KEY_BOOLEAN_RESULT, true);
    ++                callback.sendResult(result);
    ++                return;
    ++            }
    ++
    ++            final int uid;
    ++            try {
    ++                uid = mPackageManager.getPackageUidAsUser(packageName, userId);
    ++            } catch (NameNotFoundException e) {
    ++                Slog.e(TAG, "Unknown package " + packageName);
    ++                return;
    ++            }
    ++
    ++            Intent intent = newRequestAccountAccessIntent(account, packageName, uid, callback);
    ++            final UserAccounts userAccounts;
    ++            synchronized (mUsers) {
    ++                userAccounts = mUsers.get(userId);
    ++            }
    ++            doNotification(userAccounts, account, null, intent, packageName, userId);
    ++        }
    ++
    ++        @Override
    ++        public void addOnAppPermissionChangeListener(OnAppPermissionChangeListener listener) {
    ++            // Listeners are a final CopyOnWriteArrayList, hence no lock needed.
    ++            mAppPermissionChangeListeners.add(listener);
    ++        }
    ++
    ++        @Override
    ++        public boolean hasAccountAccess(@NonNull Account account, @IntRange(from = 0) int uid) {
    ++            return AccountManagerService.this.hasAccountAccess(account, null, uid);
    ++        }
    ++
    ++        @Override
    ++        public byte[] backupAccountAccessPermissions(int userId) {
    ++            synchronized (mLock) {
    ++                if (mBackupHelper == null) {
    ++                    mBackupHelper = new AccountManagerBackupHelper(
    ++                            AccountManagerService.this, this);
    ++                }
    ++                return mBackupHelper.backupAccountAccessPermissions(userId);
    ++            }
    ++        }
    ++
    ++        @Override
    ++        public void restoreAccountAccessPermissions(byte[] data, int userId) {
    ++            synchronized (mLock) {
    ++                if (mBackupHelper == null) {
    ++                    mBackupHelper = new AccountManagerBackupHelper(
    ++                            AccountManagerService.this, this);
    ++                }
    ++                mBackupHelper.restoreAccountAccessPermissions(data, userId);
    ++            }
    ++        }
    ++    }
    + }
    +diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
    +index 40f3608..ba10c64 100644
    +--- a/services/core/java/com/android/server/am/ActivityManagerService.java
    ++++ b/services/core/java/com/android/server/am/ActivityManagerService.java
    +@@ -641,7 +641,8 @@ public final class ActivityManagerService extends ActivityManagerNative
    +     boolean mDoingSetFocusedActivity;
    + 
    +     public boolean canShowErrorDialogs() {
    +-        return mShowDialogs && !mSleeping && !mShuttingDown;
    ++        return mShowDialogs && !mSleeping && !mShuttingDown
    ++                && mLockScreenShown != LOCK_SCREEN_SHOWN;
    +     }
    + 
    +     private static final class PriorityState {
    +@@ -1158,6 +1159,7 @@ public final class ActivityManagerService extends ActivityManagerNative
    +      * For example, references to the commonly used services.
    +      */
    +     HashMap<String, IBinder> mAppBindArgs;
    ++    HashMap<String, IBinder> mIsolatedAppBindArgs;
    + 
    +     /**
    +      * Temporary to avoid allocations.  Protected by main lock.
    +@@ -2377,22 +2379,21 @@ public final class ActivityManagerService extends ActivityManagerNative
    +                 if (memInfo != null) {
    +                     updateCpuStatsNow();
    +                     long nativeTotalPss = 0;
    ++                    final List<ProcessCpuTracker.Stats> stats;
    +                     synchronized (mProcessCpuTracker) {
    +-                        final int N = mProcessCpuTracker.countStats();
    +-                        for (int j=0; j<N; j++) {
    +-                            ProcessCpuTracker.Stats st = mProcessCpuTracker.getStats(j);
    +-                            if (st.vsize <= 0 || st.uid >= Process.FIRST_APPLICATION_UID) {
    +-                                // This is definitely an application process; skip it.
    ++                        stats = mProcessCpuTracker.getStats( (st)-> {
    ++                            return st.vsize > 0 && st.uid < Process.FIRST_APPLICATION_UID;
    ++                        });
    ++                    }
    ++                    final int N = stats.size();
    ++                    for (int j = 0; j < N; j++) {
    ++                        synchronized (mPidsSelfLocked) {
    ++                            if (mPidsSelfLocked.indexOfKey(stats.get(j).pid) >= 0) {
    ++                                // This is one of our own processes; skip it.
    +                                 continue;
    +                             }
    +-                            synchronized (mPidsSelfLocked) {
    +-                                if (mPidsSelfLocked.indexOfKey(st.pid) >= 0) {
    +-                                    // This is one of our own processes; skip it.
    +-                                    continue;
    +-                                }
    +-                            }
    +-                            nativeTotalPss += Debug.getPss(st.pid, null, null);
    +                         }
    ++                        nativeTotalPss += Debug.getPss(stats.get(j).pid, null, null);
    +                     }
    +                     memInfo.readMemInfo();
    +                     synchronized (ActivityManagerService.this) {
    +@@ -2935,18 +2936,24 @@ public final class ActivityManagerService extends ActivityManagerNative
    +      * lazily setup to make sure the services are running when they're asked for.
    +      */
    +     private HashMap<String, IBinder> getCommonServicesLocked(boolean isolated) {
    ++        // Isolated processes won't get this optimization, so that we don't
    ++        // violate the rules about which services they have access to.
    ++        if (isolated) {
    ++            if (mIsolatedAppBindArgs == null) {
    ++                mIsolatedAppBindArgs = new HashMap<>();
    ++                mIsolatedAppBindArgs.put("package", ServiceManager.getService("package"));
    ++            }
    ++            return mIsolatedAppBindArgs;
    ++        }
    ++
    +         if (mAppBindArgs == null) {
    +             mAppBindArgs = new HashMap<>();
    + 
    +-            // Isolated processes won't get this optimization, so that we don't
    +-            // violate the rules about which services they have access to.
    +-            if (!isolated) {
    +-                // Setup the application init args
    +-                mAppBindArgs.put("package", ServiceManager.getService("package"));
    +-                mAppBindArgs.put("window", ServiceManager.getService("window"));
    +-                mAppBindArgs.put(Context.ALARM_SERVICE,
    +-                        ServiceManager.getService(Context.ALARM_SERVICE));
    +-            }
    ++            // Setup the application init args
    ++            mAppBindArgs.put("package", ServiceManager.getService("package"));
    ++            mAppBindArgs.put("window", ServiceManager.getService("window"));
    ++            mAppBindArgs.put(Context.ALARM_SERVICE,
    ++                    ServiceManager.getService(Context.ALARM_SERVICE));
    +         }
    +         return mAppBindArgs;
    +     }
    +@@ -9576,7 +9583,7 @@ public final class ActivityManagerService extends ActivityManagerNative
    +         for (int i = 0; i < procsToKill.size(); i++) {
    +             ProcessRecord pr = procsToKill.get(i);
    +             if (pr.setSchedGroup == ProcessList.SCHED_GROUP_BACKGROUND
    +-                    && pr.curReceiver == null) {
    ++                    && pr.curReceivers.isEmpty()) {
    +                 pr.kill("remove task", true);
    +             } else {
    +                 // We delay killing processes that are not in the background or running a receiver.
    +@@ -13831,7 +13838,7 @@ public final class ActivityManagerService extends ActivityManagerNative
    +                     try {
    +                         java.lang.Process logcat = new ProcessBuilder(
    +                                 "/system/bin/timeout", "-k", "15s", "10s",
    +-                                "/system/bin/logcat", "-v", "time", "-b", "events", "-b", "system",
    ++                                "/system/bin/logcat", "-v", "threadtime", "-b", "events", "-b", "system",
    +                                 "-b", "main", "-b", "crash", "-t", String.valueOf(lines))
    +                                         .redirectErrorStream(true).start();
    + 
    +@@ -16521,21 +16528,24 @@ public final class ActivityManagerService extends ActivityManagerNative
    +         }
    +         updateCpuStatsNow();
    +         long[] memtrackTmp = new long[1];
    ++        final List<ProcessCpuTracker.Stats> stats;
    ++        // Get a list of Stats that have vsize > 0
    +         synchronized (mProcessCpuTracker) {
    +-            final int N = mProcessCpuTracker.countStats();
    +-            for (int i=0; i<N; i++) {
    +-                ProcessCpuTracker.Stats st = mProcessCpuTracker.getStats(i);
    +-                if (st.vsize > 0) {
    +-                    long pss = Debug.getPss(st.pid, null, memtrackTmp);
    +-                    if (pss > 0) {
    +-                        if (infoMap.indexOfKey(st.pid) < 0) {
    +-                            ProcessMemInfo mi = new ProcessMemInfo(st.name, st.pid,
    +-                                    ProcessList.NATIVE_ADJ, -1, "native", null);
    +-                            mi.pss = pss;
    +-                            mi.memtrack = memtrackTmp[0];
    +-                            memInfos.add(mi);
    +-                        }
    +-                    }
    ++            stats = mProcessCpuTracker.getStats((st) -> {
    ++                return st.vsize > 0;
    ++            });
    ++        }
    ++        final int statsCount = stats.size();
    ++        for (int i = 0; i < statsCount; i++) {
    ++            ProcessCpuTracker.Stats st = stats.get(i);
    ++            long pss = Debug.getPss(st.pid, null, memtrackTmp);
    ++            if (pss > 0) {
    ++                if (infoMap.indexOfKey(st.pid) < 0) {
    ++                    ProcessMemInfo mi = new ProcessMemInfo(st.name, st.pid,
    ++                            ProcessList.NATIVE_ADJ, -1, "native", null);
    ++                    mi.pss = pss;
    ++                    mi.memtrack = memtrackTmp[0];
    ++                    memInfos.add(mi);
    +                 }
    +             }
    +         }
    +@@ -17788,6 +17798,7 @@ public final class ActivityManagerService extends ActivityManagerNative
    +                 || Intent.ACTION_MEDIA_BUTTON.equals(action)
    +                 || Intent.ACTION_MEDIA_SCANNER_SCAN_FILE.equals(action)
    +                 || Intent.ACTION_SHOW_KEYBOARD_SHORTCUTS.equals(action)
    ++                || Intent.ACTION_MASTER_CLEAR.equals(action)
    +                 || AppWidgetManager.ACTION_APPWIDGET_CONFIGURE.equals(action)
    +                 || AppWidgetManager.ACTION_APPWIDGET_UPDATE.equals(action)
    +                 || LocationManager.HIGH_POWER_REQUEST_CHANGE_ACTION.equals(action)
    +@@ -19029,7 +19040,7 @@ public final class ActivityManagerService extends ActivityManagerNative
    +                 if ((changes&ActivityInfo.CONFIG_LOCALE) != 0) {
    +                     intent = new Intent(Intent.ACTION_LOCALE_CHANGED);
    +                     intent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
    +-                    if (!mProcessesReady) {
    ++	            if (initLocale || !mProcessesReady) {
    +                         intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
    +                     }
    +                     broadcastIntentLocked(null, null, intent,
    +@@ -19146,26 +19157,28 @@ public final class ActivityManagerService extends ActivityManagerNative
    +     // LIFETIME MANAGEMENT
    +     // =========================================================
    + 
    +-    // Returns which broadcast queue the app is the current [or imminent] receiver
    +-    // on, or 'null' if the app is not an active broadcast recipient.
    +-    private BroadcastQueue isReceivingBroadcast(ProcessRecord app) {
    +-        BroadcastRecord r = app.curReceiver;
    +-        if (r != null) {
    +-            return r.queue;
    ++    // Returns whether the app is receiving broadcast.
    ++    // If receiving, fetch all broadcast queues which the app is
    ++    // the current [or imminent] receiver on.
    ++    private boolean isReceivingBroadcastLocked(ProcessRecord app,
    ++            ArraySet<BroadcastQueue> receivingQueues) {
    ++        if (!app.curReceivers.isEmpty()) {
    ++            for (BroadcastRecord r : app.curReceivers) {
    ++                receivingQueues.add(r.queue);
    ++            }
    ++            return true;
    +         }
    + 
    +         // It's not the current receiver, but it might be starting up to become one
    +-        synchronized (this) {
    +-            for (BroadcastQueue queue : mBroadcastQueues) {
    +-                r = queue.mPendingBroadcast;
    +-                if (r != null && r.curApp == app) {
    +-                    // found it; report which queue it's in
    +-                    return queue;
    +-                }
    ++        for (BroadcastQueue queue : mBroadcastQueues) {
    ++            final BroadcastRecord r = queue.mPendingBroadcast;
    ++            if (r != null && r.curApp == app) {
    ++                // found it; report which queue it's in
    ++                receivingQueues.add(queue);
    +             }
    +         }
    + 
    +-        return null;
    ++        return !receivingQueues.isEmpty();
    +     }
    + 
    +     Association startAssociationLocked(int sourceUid, String sourceProcess, int sourceState,
    +@@ -19332,7 +19345,7 @@ public final class ActivityManagerService extends ActivityManagerNative
    +         int schedGroup;
    +         int procState;
    +         boolean foregroundActivities = false;
    +-        BroadcastQueue queue;
    ++        final ArraySet<BroadcastQueue> queues = new ArraySet<BroadcastQueue>();
    +         if (app == TOP_APP) {
    +             // The last app on the list is the foreground app.
    +             adj = ProcessList.FOREGROUND_APP_ADJ;
    +@@ -19346,13 +19359,13 @@ public final class ActivityManagerService extends ActivityManagerNative
    +             schedGroup = ProcessList.SCHED_GROUP_DEFAULT;
    +             app.adjType = "instrumentation";
    +             procState = ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE;
    +-        } else if ((queue = isReceivingBroadcast(app)) != null) {
    ++        } else if (isReceivingBroadcastLocked(app, queues)) {
    +             // An app that is currently receiving a broadcast also
    +             // counts as being in the foreground for OOM killer purposes.
    +             // It's placed in a sched group based on the nature of the
    +             // broadcast as reflected by which queue it's active in.
    +             adj = ProcessList.FOREGROUND_APP_ADJ;
    +-            schedGroup = (queue == mFgBroadcastQueue)
    ++            schedGroup = (queues.contains(mFgBroadcastQueue))
    +                     ? ProcessList.SCHED_GROUP_DEFAULT : ProcessList.SCHED_GROUP_BACKGROUND;
    +             app.adjType = "broadcast";
    +             procState = ActivityManager.PROCESS_STATE_RECEIVER;
    +@@ -20363,7 +20376,7 @@ public final class ActivityManagerService extends ActivityManagerNative
    +             if (DEBUG_SWITCH || DEBUG_OOM_ADJ) Slog.v(TAG_OOM_ADJ,
    +                     "Setting sched group of " + app.processName
    +                     + " to " + app.curSchedGroup);
    +-            if (app.waitingToKill != null && app.curReceiver == null
    ++            if (app.waitingToKill != null && app.curReceivers.isEmpty()
    +                     && app.setSchedGroup == ProcessList.SCHED_GROUP_BACKGROUND) {
    +                 app.kill(app.waitingToKill, true);
    +                 success = false;
    +@@ -20658,8 +20671,11 @@ public final class ActivityManagerService extends ActivityManagerNative
    +             final long now = SystemClock.elapsedRealtime();
    +             Long lastReported = userState.mProviderLastReportedFg.get(authority);
    +             if (lastReported == null || lastReported < now - 60 * 1000L) {
    +-                mUsageStatsService.reportContentProviderUsage(
    +-                        authority, providerPkgName, app.userId);
    ++                if (mSystemReady) {
    ++                    // Cannot touch the user stats if not system ready
    ++                    mUsageStatsService.reportContentProviderUsage(
    ++                            authority, providerPkgName, app.userId);
    ++                }
    +                 userState.mProviderLastReportedFg.put(authority, now);
    +             }
    +         }
    +@@ -20689,8 +20705,10 @@ public final class ActivityManagerService extends ActivityManagerNative
    +                 isInteraction = nowElapsed > app.fgInteractionTime + SERVICE_USAGE_INTERACTION_TIME;
    +             }
    +         } else {
    +-            isInteraction = app.curProcState
    +-                    <= ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND;
    ++            // If the app was being forced to the foreground, by say a Toast, then
    ++            // no need to treat it as an interaction
    ++            isInteraction = app.forcingToForeground == null
    ++                    && app.curProcState <= ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND;
    +             app.fgInteractionTime = 0;
    +         }
    +         if (isInteraction && (!app.reportedInteraction
    +@@ -21298,7 +21316,7 @@ public final class ActivityManagerService extends ActivityManagerNative
    +             for (i=mRemovedProcesses.size()-1; i>=0; i--) {
    +                 final ProcessRecord app = mRemovedProcesses.get(i);
    +                 if (app.activities.size() == 0
    +-                        && app.curReceiver == null && app.services.size() == 0) {
    ++                        && app.curReceivers.isEmpty() && app.services.size() == 0) {
    +                     Slog.i(
    +                         TAG, "Exiting empty application process "
    +                         + app.toShortString() + " ("
    +@@ -22190,4 +22208,22 @@ public final class ActivityManagerService extends ActivityManagerNative
    +             Binder.restoreCallingIdentity(callingId);
    +         }
    +     }
    ++
    ++    @Override
    ++    public boolean canBypassWorkChallenge(PendingIntent intent) throws RemoteException {
    ++        final int userId = intent.getCreatorUserHandle().getIdentifier();
    ++        if (!mUserController.isUserRunningLocked(userId, ActivityManager.FLAG_AND_LOCKED)) {
    ++            return false;
    ++        }
    ++        IIntentSender target = intent.getTarget();
    ++        if (!(target instanceof PendingIntentRecord)) {
    ++            return false;
    ++        }
    ++        final PendingIntentRecord record = (PendingIntentRecord) target;
    ++        final ResolveInfo rInfo = mStackSupervisor.resolveIntent(record.key.requestIntent,
    ++                record.key.requestResolvedType, userId, PackageManager.MATCH_DIRECT_BOOT_AWARE);
    ++        // For direct boot aware activities, they can be shown without triggering a work challenge
    ++        // before the profile user is unlocked.
    ++        return rInfo != null && rInfo.activityInfo != null;
    ++    }
    + }
    +diff --git a/services/core/java/com/android/server/am/ActivityRecord.java b/services/core/java/com/android/server/am/ActivityRecord.java
    +index 489eb77..3f69712 100755
    +--- a/services/core/java/com/android/server/am/ActivityRecord.java
    ++++ b/services/core/java/com/android/server/am/ActivityRecord.java
    +@@ -17,6 +17,7 @@
    + package com.android.server.am;
    + 
    + import static android.app.ActivityManager.StackId;
    ++import static android.app.ActivityManager.StackId.DOCKED_STACK_ID;
    + import static android.app.ActivityManager.StackId.FREEFORM_WORKSPACE_STACK_ID;
    + import static android.app.ActivityManager.StackId.PINNED_STACK_ID;
    + import static android.content.pm.ActivityInfo.RESIZE_MODE_CROP_WINDOWS;
    +@@ -946,21 +947,25 @@ final class ActivityRecord {
    +         // The activity now gets access to the data associated with this Intent.
    +         service.grantUriPermissionFromIntentLocked(callingUid, packageName,
    +                 intent, getUriPermissionsLocked(), userId);
    +-        // We want to immediately deliver the intent to the activity if
    +-        // it is currently the top resumed activity...  however, if the
    +-        // device is sleeping, then all activities are stopped, so in that
    +-        // case we will deliver it if this is the current top activity on its
    +-        // stack.
    +         final ReferrerIntent rintent = new ReferrerIntent(intent, referrer);
    +         boolean unsent = true;
    +-        if ((state == ActivityState.RESUMED
    +-                || (service.isSleepingLocked() && task.stack != null
    +-                    && task.stack.topRunningActivityLocked() == this))
    +-                && app != null && app.thread != null) {
    ++        final ActivityStack stack = task.stack;
    ++        final boolean isTopActivityInStack =
    ++                stack != null && stack.topRunningActivityLocked() == this;
    ++        final boolean isTopActivityWhileSleeping =
    ++                service.isSleepingLocked() && isTopActivityInStack;
    ++
    ++        // We want to immediately deliver the intent to the activity if:
    ++        // - It is currently resumed or paused. i.e. it is currently visible to the user and we want
    ++        //   the user to see the visual effects caused by the intent delivery now.
    ++        // - The device is sleeping and it is the top activity behind the lock screen (b/6700897).
    ++        if ((state == ActivityState.RESUMED || state == ActivityState.PAUSED
    ++                || isTopActivityWhileSleeping) && app != null && app.thread != null) {
    +             try {
    +                 ArrayList<ReferrerIntent> ar = new ArrayList<>(1);
    +                 ar.add(rintent);
    +-                app.thread.scheduleNewIntent(ar, appToken);
    ++                app.thread.scheduleNewIntent(
    ++                        ar, appToken, state == ActivityState.PAUSED /* andPause */);
    +                 unsent = false;
    +             } catch (RemoteException e) {
    +                 Slog.w(TAG, "Exception thrown sending new intent to " + this, e);
    +@@ -1309,8 +1314,12 @@ final class ActivityRecord {
    +                 state == ActivityState.RESUMED;
    +     }
    + 
    +-    public void setSleeping(boolean _sleeping) {
    +-        if (sleeping == _sleeping) {
    ++    void setSleeping(boolean _sleeping) {
    ++        setSleeping(_sleeping, false);
    ++    }
    ++
    ++    void setSleeping(boolean _sleeping, boolean force) {
    ++        if (!force && sleeping == _sleeping) {
    +             return;
    +         }
    +         if (app != null && app.thread != null) {
    +diff --git a/services/core/java/com/android/server/am/ActivityStack.java b/services/core/java/com/android/server/am/ActivityStack.java
    +index 8c4c0ad..de858e39 100644
    +--- a/services/core/java/com/android/server/am/ActivityStack.java
    ++++ b/services/core/java/com/android/server/am/ActivityStack.java
    +@@ -29,6 +29,7 @@ import static android.content.pm.ActivityInfo.CONFIG_SMALLEST_SCREEN_SIZE;
    + import static android.content.pm.ActivityInfo.FLAG_RESUME_WHILE_PAUSING;
    + import static android.content.pm.ActivityInfo.FLAG_SHOW_FOR_ALL_USERS;
    + import static android.content.res.Configuration.SCREENLAYOUT_UNDEFINED;
    ++import static android.view.Display.DEFAULT_DISPLAY;
    + import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_ADD_REMOVE;
    + import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_ALL;
    + import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_APP;
    +@@ -68,6 +69,7 @@ import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_VISIBILIT
    + import static com.android.server.am.ActivityManagerDebugConfig.TAG_AM;
    + import static com.android.server.am.ActivityManagerDebugConfig.TAG_WITH_CLASS_NAME;
    + import static com.android.server.am.ActivityManagerService.LOCK_SCREEN_SHOWN;
    ++import static com.android.server.am.ActivityManagerService.TAKE_FULLSCREEN_SCREENSHOTS;
    + import static com.android.server.am.ActivityRecord.APPLICATION_ACTIVITY_TYPE;
    + import static com.android.server.am.ActivityRecord.HOME_ACTIVITY_TYPE;
    + import static com.android.server.am.ActivityRecord.STARTING_WINDOW_REMOVED;
    +@@ -669,7 +671,7 @@ final class ActivityStack {
    + 
    +     final boolean isOnHomeDisplay() {
    +         return isAttached() &&
    +-                mActivityContainer.mActivityDisplay.mDisplayId == Display.DEFAULT_DISPLAY;
    ++                mActivityContainer.mActivityDisplay.mDisplayId == DEFAULT_DISPLAY;
    +     }
    + 
    +     void moveToFront(String reason) {
    +@@ -1041,22 +1043,32 @@ final class ActivityStack {
    + 
    +         int w = mService.mThumbnailWidth;
    +         int h = mService.mThumbnailHeight;
    ++
    ++        if (w <= 0) {
    ++            Slog.e(TAG, "\tInvalid thumbnail dimensions: " + w + "x" + h);
    ++            return null;
    ++        }
    ++
    ++        if (mStackId == DOCKED_STACK_ID && mStackSupervisor.mIsDockMinimized) {
    ++            // When the docked stack is minimized its app windows are cropped significantly so any
    ++            // screenshot taken will not display the apps contain. So, we avoid taking a screenshot
    ++            // in that case.
    ++            if (DEBUG_SCREENSHOTS) Slog.e(TAG, "\tIn minimized docked stack");
    ++            return null;
    ++        }
    ++
    +         float scale = 1f;
    +-        if (w > 0) {
    +-            if (DEBUG_SCREENSHOTS) Slog.d(TAG_SCREENSHOTS, "\tTaking screenshot");
    ++        if (DEBUG_SCREENSHOTS) Slog.d(TAG_SCREENSHOTS, "\tTaking screenshot");
    + 
    +-            // When this flag is set, we currently take the fullscreen screenshot of the activity
    +-            // but scaled to half the size.  This gives us a "good-enough" fullscreen thumbnail to
    +-            // use within SystemUI while keeping memory usage low.
    +-            if (ActivityManagerService.TAKE_FULLSCREEN_SCREENSHOTS) {
    +-                w = h = -1;
    +-                scale = mService.mFullscreenThumbnailScale;
    +-            }
    +-            return mWindowManager.screenshotApplications(who.appToken, Display.DEFAULT_DISPLAY,
    +-                    w, h, scale);
    ++        // When this flag is set, we currently take the fullscreen screenshot of the activity but
    ++        // scaled to half the size. This gives us a "good-enough" fullscreen thumbnail to use within
    ++        // SystemUI while keeping memory usage low.
    ++        if (TAKE_FULLSCREEN_SCREENSHOTS) {
    ++            w = h = -1;
    ++            scale = mService.mFullscreenThumbnailScale;
    +         }
    +-        Slog.e(TAG, "Invalid thumbnail dimensions: " + w + "x" + h);
    +-        return null;
    ++
    ++        return mWindowManager.screenshotApplications(who.appToken, DEFAULT_DISPLAY, w, h, scale);
    +     }
    + 
    +     /**
    +@@ -1308,7 +1320,9 @@ final class ActivityStack {
    +             // It is possible the activity was freezing the screen before it was paused.
    +             // In that case go ahead and remove the freeze this activity has on the screen
    +             // since it is no longer visible.
    +-            prev.stopFreezingScreenLocked(true /*force*/);
    ++            if (prev != null) {
    ++                prev.stopFreezingScreenLocked(true /*force*/);
    ++            }
    +             mPausingActivity = null;
    +         }
    + 
    +@@ -1591,11 +1605,6 @@ final class ActivityStack {
    +             return STACK_INVISIBLE;
    +         }
    + 
    +-        final boolean isLockscreenShown = mService.mLockScreenShown == LOCK_SCREEN_SHOWN;
    +-        if (isLockscreenShown && !StackId.isAllowedOverLockscreen(mStackId)) {
    +-            return STACK_INVISIBLE;
    +-        }
    +-
    +         final ActivityStack focusedStack = mStackSupervisor.getFocusedStack();
    +         final int focusedStackId = focusedStack.mStackId;
    + 
    +@@ -2498,7 +2507,8 @@ final class ActivityStack {
    +                             break;
    +                         }
    +                     }
    +-                    next.app.thread.scheduleNewIntent(next.newIntents, next.appToken);
    ++                    next.app.thread.scheduleNewIntent(
    ++                            next.newIntents, next.appToken, false /* andPause */);
    +                 }
    + 
    +                 // Well the app will no longer be stopped.
    +@@ -4396,7 +4406,7 @@ final class ActivityStack {
    +                     mStackSupervisor.getStack(FULLSCREEN_WORKSPACE_STACK_ID);
    +             if (fullscreenStack != null && fullscreenStack.hasVisibleBehindActivity()) {
    +                 final ActivityRecord visibleBehind = fullscreenStack.getVisibleBehindActivity();
    +-                mService.setFocusedActivityLocked(visibleBehind, "moveTaskToBack");
    ++                mService.setFocusedActivityLocked(visibleBehind, "moveHomeTaskToBack");
    +                 mStackSupervisor.resumeFocusedStackTopActivityLocked();
    +                 return true;
    +             }
    +@@ -4449,9 +4459,13 @@ final class ActivityStack {
    +             }
    +             final int taskToReturnTo = tr.getTaskToReturnTo();
    +             tr.setTaskToReturnTo(APPLICATION_ACTIVITY_TYPE);
    +-            return mStackSupervisor.resumeHomeStackTask(taskToReturnTo, null, "moveTaskToBack");
    ++            return mStackSupervisor.resumeHomeStackTask(taskToReturnTo, null,
    ++                    "moveTaskToBackAndShowHome");
    +         }
    + 
    ++        // Using currently focused activity value from service instead of mResumedActivity,
    ++        // because if this happens when device is locked the mResumedActivity will be null.
    ++        adjustFocusedActivityLocked(mService.mFocusedActivity, "moveTaskToBack");
    +         mStackSupervisor.resumeFocusedStackTopActivityLocked();
    +         return true;
    +     }
    +@@ -4517,15 +4531,6 @@ final class ActivityStack {
    +             return true;
    +         }
    + 
    +-        // TODO: We could probably make the condition below just check that the activity state is
    +-        // stopped, but also checking the sleep state for now to reduce change impact late in
    +-        // development cycle.
    +-        if (mService.isSleepingOrShuttingDownLocked() && r.state == ActivityState.STOPPED) {
    +-            if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Slog.v(TAG_CONFIGURATION,
    +-                    "Skipping config check (stopped while sleeping): " + r);
    +-            return true;
    +-        }
    +-
    +         if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Slog.v(TAG_CONFIGURATION,
    +                 "Ensuring correct configuration: " + r);
    + 
    +diff --git a/services/core/java/com/android/server/am/ActivityStackSupervisor.java b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
    +index a0087c8..c6ab918 100644
    +--- a/services/core/java/com/android/server/am/ActivityStackSupervisor.java
    ++++ b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
    +@@ -3139,11 +3139,14 @@ public final class ActivityStackSupervisor implements DisplayListener {
    +         final boolean nowVisible = allResumedActivitiesVisible();
    +         for (int activityNdx = mStoppingActivities.size() - 1; activityNdx >= 0; --activityNdx) {
    +             ActivityRecord s = mStoppingActivities.get(activityNdx);
    ++            // TODO: Remove mWaitingVisibleActivities list and just remove activity from
    ++            // mStoppingActivities when something else comes up.
    +             boolean waitingVisible = mWaitingVisibleActivities.contains(s);
    +             if (DEBUG_STATES) Slog.v(TAG, "Stopping " + s + ": nowVisible=" + nowVisible
    +                     + " waitingVisible=" + waitingVisible + " finishing=" + s.finishing);
    +             if (waitingVisible && nowVisible) {
    +                 mWaitingVisibleActivities.remove(s);
    ++                waitingVisible = false;
    +                 if (s.finishing) {
    +                     // If this activity is finishing, it is sitting on top of
    +                     // everyone else but we now know it is no longer needed...
    +@@ -3152,7 +3155,6 @@ public final class ActivityStackSupervisor implements DisplayListener {
    +                     // hidden by the activities in front of it.
    +                     if (DEBUG_STATES) Slog.v(TAG, "Before stopping, can hide: " + s);
    +                     mWindowManager.setAppVisibility(s.appToken, false);
    +-                    waitingVisible = false;
    +                 }
    +             }
    +             if ((!waitingVisible || mService.isSleepingOrShuttingDownLocked()) && remove) {
    +@@ -3765,6 +3767,12 @@ public final class ActivityStackSupervisor implements DisplayListener {
    + 
    +     void activityRelaunchedLocked(IBinder token) {
    +         mWindowManager.notifyAppRelaunchingFinished(token);
    ++        if (mService.isSleepingOrShuttingDownLocked()) {
    ++            final ActivityRecord r = ActivityRecord.isInStackLocked(token);
    ++            if (r != null) {
    ++                r.setSleeping(true, true);
    ++            }
    ++        }
    +     }
    + 
    +     void activityRelaunchingLocked(ActivityRecord r) {
    +diff --git a/services/core/java/com/android/server/am/ActivityStartInterceptor.java b/services/core/java/com/android/server/am/ActivityStartInterceptor.java
    +index f26e47e..d719c58 100644
    +--- a/services/core/java/com/android/server/am/ActivityStartInterceptor.java
    ++++ b/services/core/java/com/android/server/am/ActivityStartInterceptor.java
    +@@ -29,6 +29,7 @@ import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK;
    + import static android.content.Intent.FLAG_ACTIVITY_TASK_ON_HOME;
    + import static android.content.pm.ApplicationInfo.FLAG_SUSPENDED;
    + 
    ++import android.app.ActivityManager;
    + import android.app.ActivityOptions;
    + import android.app.KeyguardManager;
    + import android.app.admin.DevicePolicyManagerInternal;
    +@@ -210,6 +211,11 @@ class ActivityStartInterceptor {
    +         if (!mService.mUserController.shouldConfirmCredentials(userId)) {
    +             return null;
    +         }
    ++        // Allow direct boot aware activity to be displayed before the user is unlocked.
    ++        if (aInfo.directBootAware && mService.mUserController.isUserRunningLocked(userId,
    ++                ActivityManager.FLAG_AND_LOCKED)) {
    ++            return null;
    ++        }
    +         final IIntentSender target = mService.getIntentSenderLocked(
    +                 INTENT_SENDER_ACTIVITY, callingPackage,
    +                 Binder.getCallingUid(), userId, null, null, 0, new Intent[]{ intent },
    +diff --git a/services/core/java/com/android/server/am/ActivityStarter.java b/services/core/java/com/android/server/am/ActivityStarter.java
    +index bbf09e8..06d8e48 100644
    +--- a/services/core/java/com/android/server/am/ActivityStarter.java
    ++++ b/services/core/java/com/android/server/am/ActivityStarter.java
    +@@ -103,6 +103,7 @@ import android.os.Build;
    + import android.os.Bundle;
    + import android.os.IBinder;
    + import android.os.PowerManagerInternal;
    ++import android.os.Process;
    + import android.os.RemoteException;
    + import android.os.SystemClock;
    + import android.os.UserHandle;
    +@@ -132,6 +133,9 @@ class ActivityStarter {
    +     private static final String TAG_CONFIGURATION = TAG + POSTFIX_CONFIGURATION;
    +     private static final String TAG_USER_LEAVING = TAG + POSTFIX_USER_LEAVING;
    + 
    ++    // TODO b/30204367 remove when the platform fully supports ephemeral applications
    ++    private static final boolean USE_DEFAULT_EPHEMERAL_LAUNCHER = false;
    ++
    +     private final ActivityManagerService mService;
    +     private final ActivityStackSupervisor mSupervisor;
    +     private ActivityStartInterceptor mInterceptor;
    +@@ -456,39 +460,13 @@ class ActivityStarter {
    +         // starts either the intent we resolved here [on install error] or the ephemeral
    +         // app [on install success].
    +         if (rInfo != null && rInfo.ephemeralResolveInfo != null) {
    +-            // Create a pending intent to start the intent resolved here.
    +-            final IIntentSender failureTarget = mService.getIntentSenderLocked(
    +-                    ActivityManager.INTENT_SENDER_ACTIVITY, callingPackage,
    +-                    Binder.getCallingUid(), userId, null, null, 0, new Intent[]{ intent },
    +-                    new String[]{ resolvedType },
    +-                    PendingIntent.FLAG_CANCEL_CURRENT | PendingIntent.FLAG_ONE_SHOT
    +-                            | PendingIntent.FLAG_IMMUTABLE, null);
    +-
    +-            // Create a pending intent to start the ephemeral application; force it to be
    +-            // directed to the ephemeral package.
    +-            ephemeralIntent.setPackage(rInfo.ephemeralResolveInfo.getPackageName());
    +-            final IIntentSender ephemeralTarget = mService.getIntentSenderLocked(
    +-                    ActivityManager.INTENT_SENDER_ACTIVITY, callingPackage,
    +-                    Binder.getCallingUid(), userId, null, null, 0, new Intent[]{ ephemeralIntent },
    +-                    new String[]{ resolvedType },
    +-                    PendingIntent.FLAG_CANCEL_CURRENT | PendingIntent.FLAG_ONE_SHOT
    +-                            | PendingIntent.FLAG_IMMUTABLE, null);
    +-
    +-            int flags = intent.getFlags();
    +-            intent = new Intent();
    +-            intent.setFlags(flags
    +-                    | Intent.FLAG_ACTIVITY_NEW_TASK
    +-                    | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
    +-            intent.putExtra(Intent.EXTRA_PACKAGE_NAME,
    +-                    rInfo.ephemeralResolveInfo.getPackageName());
    +-            intent.putExtra(Intent.EXTRA_EPHEMERAL_FAILURE, new IntentSender(failureTarget));
    +-            intent.putExtra(Intent.EXTRA_EPHEMERAL_SUCCESS, new IntentSender(ephemeralTarget));
    +-
    ++            intent = buildEphemeralInstallerIntent(intent, ephemeralIntent,
    ++                    rInfo.ephemeralResolveInfo.getPackageName(), callingPackage, resolvedType,
    ++                    userId);
    +             resolvedType = null;
    +             callingUid = realCallingUid;
    +             callingPid = realCallingPid;
    + 
    +-            rInfo = rInfo.ephemeralInstaller;
    +             aInfo = mSupervisor.resolveActivity(intent, rInfo, startFlags, null /*profilerInfo*/);
    +         }
    + 
    +@@ -543,6 +521,58 @@ class ActivityStarter {
    +         return err;
    +     }
    + 
    ++    /**
    ++     * Builds and returns an intent to launch the ephemeral installer.
    ++     */
    ++    private Intent buildEphemeralInstallerIntent(Intent launchIntent, Intent origIntent,
    ++            String ephemeralPackage, String callingPackage, String resolvedType, int userId) {
    ++        final Intent nonEphemeralIntent = new Intent(origIntent);
    ++        nonEphemeralIntent.setFlags(nonEphemeralIntent.getFlags() | Intent.FLAG_IGNORE_EPHEMERAL);
    ++        // Intent that is launched if the ephemeral package couldn't be installed
    ++        // for any reason.
    ++        final IIntentSender failureIntentTarget = mService.getIntentSenderLocked(
    ++                ActivityManager.INTENT_SENDER_ACTIVITY, callingPackage,
    ++                Binder.getCallingUid(), userId, null /*token*/, null /*resultWho*/, 1,
    ++                new Intent[]{ nonEphemeralIntent }, new String[]{ resolvedType },
    ++                PendingIntent.FLAG_CANCEL_CURRENT | PendingIntent.FLAG_ONE_SHOT
    ++                | PendingIntent.FLAG_IMMUTABLE, null /*bOptions*/);
    ++
    ++        final Intent ephemeralIntent;
    ++        if (USE_DEFAULT_EPHEMERAL_LAUNCHER) {
    ++            // Force the intent to be directed to the ephemeral package
    ++            ephemeralIntent = new Intent(origIntent);
    ++            ephemeralIntent.setPackage(ephemeralPackage);
    ++        } else {
    ++            // Success intent goes back to the installer
    ++            ephemeralIntent = new Intent(launchIntent);
    ++        }
    ++
    ++        // Intent that is eventually launched if the ephemeral package was
    ++        // installed successfully. This will actually be launched by a platform
    ++        // broadcast receiver.
    ++        final IIntentSender successIntentTarget = mService.getIntentSenderLocked(
    ++                ActivityManager.INTENT_SENDER_ACTIVITY, callingPackage,
    ++                Binder.getCallingUid(), userId, null /*token*/, null /*resultWho*/, 0,
    ++                new Intent[]{ ephemeralIntent }, new String[]{ resolvedType },
    ++                PendingIntent.FLAG_CANCEL_CURRENT | PendingIntent.FLAG_ONE_SHOT
    ++                | PendingIntent.FLAG_IMMUTABLE, null /*bOptions*/);
    ++
    ++        // Finally build the actual intent to launch the ephemeral installer
    ++        int flags = launchIntent.getFlags();
    ++        final Intent intent = new Intent();
    ++        intent.setFlags(flags
    ++                | Intent.FLAG_ACTIVITY_NEW_TASK
    ++                | Intent.FLAG_ACTIVITY_CLEAR_TASK
    ++                | Intent.FLAG_ACTIVITY_NO_HISTORY
    ++                | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
    ++        intent.putExtra(Intent.EXTRA_PACKAGE_NAME, ephemeralPackage);
    ++        intent.putExtra(Intent.EXTRA_EPHEMERAL_FAILURE, new IntentSender(failureIntentTarget));
    ++        intent.putExtra(Intent.EXTRA_EPHEMERAL_SUCCESS, new IntentSender(successIntentTarget));
    ++        // TODO: Remove when the platform has fully implemented ephemeral apps
    ++        intent.setData(origIntent.getData().buildUpon().clearQuery().build());
    ++        return intent;
    ++    }
    ++
    +     void postStartActivityUncheckedProcessing(
    +             ActivityRecord r, int result, int prevFocusedStackId, ActivityRecord sourceRecord,
    +             ActivityStack targetStack) {
    +@@ -572,6 +602,9 @@ class ActivityStarter {
    +         // If we launched the activity from a no display activity that was launched from the home
    +         // screen, we also need to start recents to un-minimize the docked stack, since the
    +         // noDisplay activity will be finished shortly after.
    ++        // Note that some apps have trampoline activities without noDisplay being set. In that case,
    ++        // we have another heuristic in DockedStackDividerController.notifyAppTransitionStarting
    ++        // that tries to detect that case.
    +         // TODO: We should prevent noDisplay activities from affecting task/stack ordering and
    +         // visibility instead of using this flag.
    +         final boolean noDisplayActivityOverHome = sourceRecord != null
    +diff --git a/services/core/java/com/android/server/am/AppErrors.java b/services/core/java/com/android/server/am/AppErrors.java
    +index 7eff773..0c67c75 100644
    +--- a/services/core/java/com/android/server/am/AppErrors.java
    ++++ b/services/core/java/com/android/server/am/AppErrors.java
    +@@ -22,7 +22,6 @@ import com.android.internal.logging.MetricsProto;
    + import com.android.internal.os.ProcessCpuTracker;
    + import com.android.server.Watchdog;
    + 
    +-import android.app.Activity;
    + import android.app.ActivityManager;
    + import android.app.ActivityOptions;
    + import android.app.ActivityThread;
    +@@ -33,10 +32,7 @@ import android.content.ActivityNotFoundException;
    + import android.content.Context;
    + import android.content.Intent;
    + import android.content.pm.ApplicationInfo;
    +-import android.content.pm.IPackageDataObserver;
    +-import android.content.pm.PackageManager;
    + import android.os.Binder;
    +-import android.os.Bundle;
    + import android.os.Message;
    + import android.os.Process;
    + import android.os.RemoteException;
    +@@ -59,7 +55,6 @@ import java.util.ArrayList;
    + import java.util.Collections;
    + import java.util.HashMap;
    + import java.util.Set;
    +-import java.util.concurrent.Semaphore;
    + 
    + import static com.android.server.Watchdog.NATIVE_STACKS_OF_INTEREST;
    + import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_ANR;
    +@@ -359,7 +354,7 @@ class AppErrors {
    +                 return;
    +             }
    + 
    +-            Message msg = Message.obtain();
    ++            final Message msg = Message.obtain();
    +             msg.what = ActivityManagerService.SHOW_ERROR_UI_MSG;
    + 
    +             task = data.task;
    +@@ -575,6 +570,8 @@ class AppErrors {
    +     boolean handleAppCrashLocked(ProcessRecord app, String reason,
    +             String shortMsg, String longMsg, String stackTrace, AppErrorDialog.Data data) {
    +         long now = SystemClock.uptimeMillis();
    ++        boolean showBackground = Settings.Secure.getInt(mContext.getContentResolver(),
    ++                Settings.Secure.ANR_SHOW_BACKGROUND, 0) != 0;
    + 
    +         Long crashTime;
    +         Long crashTimePersistent;
    +@@ -612,7 +609,9 @@ class AppErrors {
    +                 // processes run critical code.
    +                 mService.removeProcessLocked(app, false, false, "crash");
    +                 mService.mStackSupervisor.resumeFocusedStackTopActivityLocked();
    +-                return false;
    ++                if (!showBackground) {
    ++                    return false;
    ++                }
    +             }
    +             mService.mStackSupervisor.resumeFocusedStackTopActivityLocked();
    +         } else {
    +@@ -705,7 +704,7 @@ class AppErrors {
    +             }
    +             final boolean crashSilenced = mAppsNotReportingCrashes != null &&
    +                     mAppsNotReportingCrashes.contains(proc.info.packageName);
    +-            if (mService.canShowErrorDialogs() && !crashSilenced) {
    ++            if ((mService.canShowErrorDialogs() || showBackground) && !crashSilenced) {
    +                 proc.crashDialog = new AppErrorDialog(mContext, mService, data);
    +             } else {
    +                 // The device is asleep, so just pretend that the user
    +@@ -942,7 +941,9 @@ class AppErrors {
    +                     null, null, 0, null, null, null, AppOpsManager.OP_NONE,
    +                     null, false, false, MY_PID, Process.SYSTEM_UID, 0 /* TODO: Verify */);
    + 
    +-            if (mService.canShowErrorDialogs()) {
    ++            boolean showBackground = Settings.Secure.getInt(mContext.getContentResolver(),
    ++                    Settings.Secure.ANR_SHOW_BACKGROUND, 0) != 0;
    ++            if (mService.canShowErrorDialogs() || showBackground) {
    +                 d = new AppNotRespondingDialog(mService,
    +                         mContext, proc, (ActivityRecord)data.get("activity"),
    +                         msg.arg1 != 0);
    +diff --git a/services/core/java/com/android/server/am/BroadcastQueue.java b/services/core/java/com/android/server/am/BroadcastQueue.java
    +index f78f29c..5c35419 100644
    +--- a/services/core/java/com/android/server/am/BroadcastQueue.java
    ++++ b/services/core/java/com/android/server/am/BroadcastQueue.java
    +@@ -227,7 +227,8 @@ public final class BroadcastQueue {
    + 
    +     public final boolean replaceParallelBroadcastLocked(BroadcastRecord r) {
    +         for (int i = mParallelBroadcasts.size() - 1; i >= 0; i--) {
    +-            if (r.intent.filterEquals(mParallelBroadcasts.get(i).intent)) {
    ++            final Intent curIntent = mParallelBroadcasts.get(i).intent;
    ++            if (r.intent.filterEquals(curIntent)) {
    +                 if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST,
    +                         "***** DROPPING PARALLEL ["
    +                 + mQueueName + "]: " + r.intent);
    +@@ -265,7 +266,7 @@ public final class BroadcastQueue {
    + 
    +         r.receiver = app.thread.asBinder();
    +         r.curApp = app;
    +-        app.curReceiver = r;
    ++        app.curReceivers.add(r);
    +         app.forceProcessStateUpTo(ActivityManager.PROCESS_STATE_RECEIVER);
    +         mService.updateLruProcessLocked(app, false, null);
    +         mService.updateOomAdjLocked();
    +@@ -293,7 +294,7 @@ public final class BroadcastQueue {
    +                         "Process cur broadcast " + r + ": NOT STARTED!");
    +                 r.receiver = null;
    +                 r.curApp = null;
    +-                app.curReceiver = null;
    ++                app.curReceivers.remove(r);
    +             }
    +         }
    +     }
    +@@ -394,8 +395,8 @@ public final class BroadcastQueue {
    +         }
    +         r.receiver = null;
    +         r.intent.setComponent(null);
    +-        if (r.curApp != null && r.curApp.curReceiver == r) {
    +-            r.curApp.curReceiver = null;
    ++        if (r.curApp != null && r.curApp.curReceivers.contains(r)) {
    ++            r.curApp.curReceivers.remove(r);
    +         }
    +         if (r.curFilter != null) {
    +             r.curFilter.receiverList.curBroadcast = null;
    +@@ -648,7 +649,7 @@ public final class BroadcastQueue {
    +                 // things that directly call the IActivityManager API, which
    +                 // are already core system stuff so don't matter for this.
    +                 r.curApp = filter.receiverList.app;
    +-                filter.receiverList.app.curReceiver = r;
    ++                filter.receiverList.app.curReceivers.add(r);
    +                 mService.updateOomAdjLocked(r.curApp);
    +             }
    +         }
    +@@ -676,7 +677,7 @@ public final class BroadcastQueue {
    +                 r.curFilter = null;
    +                 filter.receiverList.curBroadcast = null;
    +                 if (filter.receiverList.app != null) {
    +-                    filter.receiverList.app.curReceiver = null;
    ++                    filter.receiverList.app.curReceivers.remove(r);
    +                 }
    +             }
    +         }
    +diff --git a/services/core/java/com/android/server/am/BroadcastRecord.java b/services/core/java/com/android/server/am/BroadcastRecord.java
    +index 3437ae6..1e7911a 100644
    +--- a/services/core/java/com/android/server/am/BroadcastRecord.java
    ++++ b/services/core/java/com/android/server/am/BroadcastRecord.java
    +@@ -219,6 +219,9 @@ final class BroadcastRecord extends Binder {
    +             int _resultCode, String _resultData, Bundle _resultExtras, boolean _serialized,
    +             boolean _sticky, boolean _initialSticky,
    +             int _userId) {
    ++        if (_intent == null) {
    ++            throw new NullPointerException("Can't construct with a null intent");
    ++        }
    +         queue = _queue;
    +         intent = _intent;
    +         targetComp = _intent.getComponent();
    +diff --git a/services/core/java/com/android/server/am/PendingIntentRecord.java b/services/core/java/com/android/server/am/PendingIntentRecord.java
    +index 2467a90..9c08453 100644
    +--- a/services/core/java/com/android/server/am/PendingIntentRecord.java
    ++++ b/services/core/java/com/android/server/am/PendingIntentRecord.java
    +@@ -38,6 +38,7 @@ import com.android.server.am.ActivityStackSupervisor.ActivityContainer;
    + 
    + import java.io.PrintWriter;
    + import java.lang.ref.WeakReference;
    ++import java.util.Objects;
    + 
    + final class PendingIntentRecord extends IIntentSender.Stub {
    +     private static final String TAG = TAG_WITH_CLASS_NAME ? "PendingIntentRecord" : TAG_AM;
    +@@ -102,7 +103,7 @@ final class PendingIntentRecord extends IIntentSender.Stub {
    +             if (requestResolvedType != null) {
    +                 hash = (ODD_PRIME_NUMBER*hash) + requestResolvedType.hashCode();
    +             }
    +-            hash = (ODD_PRIME_NUMBER*hash) + _p.hashCode();
    ++            hash = (ODD_PRIME_NUMBER*hash) + (_p != null ? _p.hashCode() : 0);
    +             hash = (ODD_PRIME_NUMBER*hash) + _t;
    +             hashCode = hash;
    +             //Slog.i(ActivityManagerService.TAG, this + " hashCode=0x"
    +@@ -121,20 +122,14 @@ final class PendingIntentRecord extends IIntentSender.Stub {
    +                 if (userId != other.userId){
    +                     return false;
    +                 }
    +-                if (!packageName.equals(other.packageName)) {
    ++                if (!Objects.equals(packageName, other.packageName)) {
    +                     return false;
    +                 }
    +                 if (activity != other.activity) {
    +                     return false;
    +                 }
    +-                if (who != other.who) {
    +-                    if (who != null) {
    +-                        if (!who.equals(other.who)) {
    +-                            return false;
    +-                        }
    +-                    } else if (other.who != null) {
    +-                        return false;
    +-                    }
    ++                if (!Objects.equals(who, other.who)) {
    ++                    return false;
    +                 }
    +                 if (requestCode != other.requestCode) {
    +                     return false;
    +@@ -148,14 +143,8 @@ final class PendingIntentRecord extends IIntentSender.Stub {
    +                         return false;
    +                     }
    +                 }
    +-                if (requestResolvedType != other.requestResolvedType) {
    +-                    if (requestResolvedType != null) {
    +-                        if (!requestResolvedType.equals(other.requestResolvedType)) {
    +-                            return false;
    +-                        }
    +-                    } else if (other.requestResolvedType != null) {
    +-                        return false;
    +-                    }
    ++                if (!Objects.equals(requestResolvedType, other.requestResolvedType)) {
    ++                    return false;
    +                 }
    +                 if (flags != other.flags) {
    +                     return false;
    +diff --git a/services/core/java/com/android/server/am/ProcessRecord.java b/services/core/java/com/android/server/am/ProcessRecord.java
    +index 3fffefb..49fe79c 100644
    +--- a/services/core/java/com/android/server/am/ProcessRecord.java
    ++++ b/services/core/java/com/android/server/am/ProcessRecord.java
    +@@ -143,7 +143,7 @@ final class ProcessRecord {
    +     Bundle instrumentationArguments;// as given to us
    +     ComponentName instrumentationResultClass;// copy of instrumentationClass
    +     boolean usingWrapper;       // Set to true when process was launched with a wrapper attached
    +-    BroadcastRecord curReceiver;// receiver currently running in the app
    ++    final ArraySet<BroadcastRecord> curReceivers = new ArraySet<BroadcastRecord>();// receivers currently running in the app
    +     long lastWakeTime;          // How long proc held wake lock at last check
    +     long lastCpuTime;           // How long proc has run CPU at last check
    +     long curCpuTime;            // How long proc has run CPU most recently
    +@@ -427,8 +427,11 @@ final class ProcessRecord {
    +                 pw.print(prefix); pw.print("  - "); pw.println(conProviders.get(i).toShortString());
    +             }
    +         }
    +-        if (curReceiver != null) {
    +-            pw.print(prefix); pw.print("curReceiver="); pw.println(curReceiver);
    ++        if (!curReceivers.isEmpty()) {
    ++            pw.print(prefix); pw.println("Current Receivers:");
    ++            for (int i=0; i < curReceivers.size(); i++) {
    ++                pw.print(prefix); pw.print("  - "); pw.println(curReceivers.valueAt(i));
    ++            }
    +         }
    +         if (receivers.size() > 0) {
    +             pw.print(prefix); pw.println("Receivers:");
    +diff --git a/services/core/java/com/android/server/am/TaskPersister.java b/services/core/java/com/android/server/am/TaskPersister.java
    +index 48fecd5..43eb251 100644
    +--- a/services/core/java/com/android/server/am/TaskPersister.java
    ++++ b/services/core/java/com/android/server/am/TaskPersister.java
    +@@ -87,6 +87,8 @@ public class TaskPersister {
    +     private final RecentTasks mRecentTasks;
    +     private final SparseArray<SparseBooleanArray> mTaskIdsInFile = new SparseArray<>();
    +     private final File mTaskIdsDir;
    ++    // To lock file operations in TaskPersister
    ++    private final Object mIoLock = new Object();
    + 
    +     /**
    +      * Value determines write delay mode as follows: < 0 We are Flushing. No delays between writes
    +@@ -195,52 +197,52 @@ public class TaskPersister {
    +             return mTaskIdsInFile.get(userId).clone();
    +         }
    +         final SparseBooleanArray persistedTaskIds = new SparseBooleanArray();
    +-        BufferedReader reader = null;
    +-        String line;
    +-        try {
    +-            reader = new BufferedReader(new FileReader(getUserPersistedTaskIdsFile(userId)));
    +-            while ((line = reader.readLine()) != null) {
    +-                for (String taskIdString : line.split("\\s+")) {
    +-                    int id = Integer.parseInt(taskIdString);
    +-                    persistedTaskIds.put(id, true);
    ++        synchronized (mIoLock) {
    ++            BufferedReader reader = null;
    ++            String line;
    ++            try {
    ++                reader = new BufferedReader(new FileReader(getUserPersistedTaskIdsFile(userId)));
    ++                while ((line = reader.readLine()) != null) {
    ++                    for (String taskIdString : line.split("\\s+")) {
    ++                        int id = Integer.parseInt(taskIdString);
    ++                        persistedTaskIds.put(id, true);
    ++                    }
    +                 }
    ++            } catch (FileNotFoundException e) {
    ++                // File doesn't exist. Ignore.
    ++            } catch (Exception e) {
    ++                Slog.e(TAG, "Error while reading taskIds file for user " + userId, e);
    ++            } finally {
    ++                IoUtils.closeQuietly(reader);
    +             }
    +-        } catch (FileNotFoundException e) {
    +-            // File doesn't exist. Ignore.
    +-        } catch (Exception e) {
    +-            Slog.e(TAG, "Error while reading taskIds file for user " + userId, e);
    +-        } finally {
    +-            IoUtils.closeQuietly(reader);
    +         }
    +         mTaskIdsInFile.put(userId, persistedTaskIds);
    +         return persistedTaskIds.clone();
    +     }
    + 
    ++
    +     @VisibleForTesting
    +-    void maybeWritePersistedTaskIdsForUser(@NonNull SparseBooleanArray taskIds, int userId) {
    ++    void writePersistedTaskIdsForUser(@NonNull SparseBooleanArray taskIds, int userId) {
    +         if (userId < 0) {
    +             return;
    +         }
    +-        SparseBooleanArray persistedIdsInFile = mTaskIdsInFile.get(userId);
    +-        if (persistedIdsInFile != null && persistedIdsInFile.equals(taskIds)) {
    +-            return;
    +-        }
    +         final File persistedTaskIdsFile = getUserPersistedTaskIdsFile(userId);
    +-        BufferedWriter writer = null;
    +-        try {
    +-            writer = new BufferedWriter(new FileWriter(persistedTaskIdsFile));
    +-            for (int i = 0; i < taskIds.size(); i++) {
    +-                if (taskIds.valueAt(i)) {
    +-                    writer.write(String.valueOf(taskIds.keyAt(i)));
    +-                    writer.newLine();
    ++        synchronized (mIoLock) {
    ++            BufferedWriter writer = null;
    ++            try {
    ++                writer = new BufferedWriter(new FileWriter(persistedTaskIdsFile));
    ++                for (int i = 0; i < taskIds.size(); i++) {
    ++                    if (taskIds.valueAt(i)) {
    ++                        writer.write(String.valueOf(taskIds.keyAt(i)));
    ++                        writer.newLine();
    ++                    }
    +                 }
    ++            } catch (Exception e) {
    ++                Slog.e(TAG, "Error while writing taskIds file for user " + userId, e);
    ++            } finally {
    ++                IoUtils.closeQuietly(writer);
    +             }
    +-        } catch (Exception e) {
    +-            Slog.e(TAG, "Error while writing taskIds file for user " + userId, e);
    +-        } finally {
    +-            IoUtils.closeQuietly(writer);
    +         }
    +-        mTaskIdsInFile.put(userId, taskIds.clone());
    +     }
    + 
    +     void unloadUserDataFromMemory(int userId) {
    +@@ -543,16 +545,23 @@ public class TaskPersister {
    +     }
    + 
    +     private void writeTaskIdsFiles() {
    +-        int candidateUserIds[];
    ++        SparseArray<SparseBooleanArray> changedTaskIdsPerUser = new SparseArray<>();
    +         synchronized (mService) {
    +-            candidateUserIds = mRecentTasks.usersWithRecentsLoadedLocked();
    +-        }
    +-        SparseBooleanArray taskIdsToSave;
    +-        for (int userId : candidateUserIds) {
    +-            synchronized (mService) {
    +-                taskIdsToSave = mRecentTasks.mPersistedTaskIds.get(userId).clone();
    ++            for (int userId : mRecentTasks.usersWithRecentsLoadedLocked()) {
    ++                SparseBooleanArray taskIdsToSave = mRecentTasks.mPersistedTaskIds.get(userId);
    ++                SparseBooleanArray persistedIdsInFile = mTaskIdsInFile.get(userId);
    ++                if (persistedIdsInFile != null && persistedIdsInFile.equals(taskIdsToSave)) {
    ++                    continue;
    ++                } else {
    ++                    SparseBooleanArray taskIdsToSaveCopy = taskIdsToSave.clone();
    ++                    mTaskIdsInFile.put(userId, taskIdsToSaveCopy);
    ++                    changedTaskIdsPerUser.put(userId, taskIdsToSaveCopy);
    ++                }
    +             }
    +-            maybeWritePersistedTaskIdsForUser(taskIdsToSave, userId);
    ++        }
    ++        for (int i = 0; i < changedTaskIdsPerUser.size(); i++) {
    ++            writePersistedTaskIdsForUser(changedTaskIdsPerUser.valueAt(i),
    ++                    changedTaskIdsPerUser.keyAt(i));
    +         }
    +     }
    + 
    +diff --git a/services/core/java/com/android/server/am/UriPermission.java b/services/core/java/com/android/server/am/UriPermission.java
    +index 6e371c1..0aa54d9 100644
    +--- a/services/core/java/com/android/server/am/UriPermission.java
    ++++ b/services/core/java/com/android/server/am/UriPermission.java
    +@@ -19,6 +19,7 @@ package com.android.server.am;
    + import android.content.Intent;
    + import android.os.UserHandle;
    + import android.util.ArraySet;
    ++import android.util.Log;
    + import android.util.Slog;
    + 
    + import com.android.server.am.ActivityManagerService.GrantUri;
    +@@ -93,7 +94,16 @@ final class UriPermission {
    +     }
    + 
    +     private void updateModeFlags() {
    ++        final int oldModeFlags = modeFlags;
    +         modeFlags = ownedModeFlags | globalModeFlags | persistableModeFlags | persistedModeFlags;
    ++
    ++        if (Log.isLoggable(TAG, Log.VERBOSE) && (modeFlags != oldModeFlags)) {
    ++            Slog.d(TAG,
    ++                    "Permission for " + targetPkg + " to " + uri + " is changing from 0x"
    ++                            + Integer.toHexString(oldModeFlags) + " to 0x"
    ++                            + Integer.toHexString(modeFlags),
    ++                    new Throwable());
    ++        }
    +     }
    + 
    +     /**
    +diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java
    +index 275870e..a9277ce 100644
    +--- a/services/core/java/com/android/server/audio/AudioService.java
    ++++ b/services/core/java/com/android/server/audio/AudioService.java
    +@@ -5609,6 +5609,8 @@ public class AudioService extends IAudioService.Stub {
    +                 } else { // config == AudioSystem.FORCE_NONE
    +                     mBecomingNoisyIntentDevices |= AudioSystem.DEVICE_OUT_ALL_A2DP;
    +                 }
    ++                sendMsg(mAudioHandler, MSG_REPORT_NEW_ROUTES,
    ++                        SENDMSG_NOOP, 0, 0, null, 0);
    +                 break;
    +             case AudioSystem.FOR_DOCK:
    +                 if (config == AudioSystem.FORCE_ANALOG_DOCK) {
    +diff --git a/services/core/java/com/android/server/audio/FocusRequester.java b/services/core/java/com/android/server/audio/FocusRequester.java
    +index 49be879..cc18114 100644
    +--- a/services/core/java/com/android/server/audio/FocusRequester.java
    ++++ b/services/core/java/com/android/server/audio/FocusRequester.java
    +@@ -40,9 +40,9 @@ public class FocusRequester {
    +     private static final String TAG = "MediaFocusControl";
    +     private static final boolean DEBUG = false;
    + 
    +-    private AudioFocusDeathHandler mDeathHandler;
    +-    private final IAudioFocusDispatcher mFocusDispatcher; // may be null
    +-    private final IBinder mSourceRef;
    ++    private AudioFocusDeathHandler mDeathHandler; // may be null
    ++    private IAudioFocusDispatcher mFocusDispatcher; // may be null
    ++    private final IBinder mSourceRef; // may be null
    +     private final String mClientId;
    +     private final String mPackageName;
    +     private final int mCallingUid;
    +@@ -205,6 +205,7 @@ public class FocusRequester {
    +             if (mSourceRef != null && mDeathHandler != null) {
    +                 mSourceRef.unlinkToDeath(mDeathHandler, 0);
    +                 mDeathHandler = null;
    ++                mFocusDispatcher = null;
    +             }
    +         } catch (java.util.NoSuchElementException e) {
    +             Log.e(TAG, "FocusRequester.release() hit ", e);
    +@@ -275,12 +276,13 @@ public class FocusRequester {
    +             mFocusLossReceived = AudioManager.AUDIOFOCUS_NONE;
    +             mFocusController.notifyExtPolicyFocusGrant_syncAf(toAudioFocusInfo(),
    +                     AudioManager.AUDIOFOCUS_REQUEST_GRANTED);
    +-            if (mFocusDispatcher != null) {
    ++            final IAudioFocusDispatcher fd = mFocusDispatcher;
    ++            if (fd != null) {
    +                 if (DEBUG) {
    +                     Log.v(TAG, "dispatching " + focusChangeToString(focusGain) + " to "
    +                         + mClientId);
    +                 }
    +-                mFocusDispatcher.dispatchAudioFocusChange(focusGain, mClientId);
    ++                fd.dispatchAudioFocusChange(focusGain, mClientId);
    +             }
    +         } catch (android.os.RemoteException e) {
    +             Log.e(TAG, "Failure to signal gain of audio focus due to: ", e);
    +@@ -311,14 +313,15 @@ public class FocusRequester {
    +                             toAudioFocusInfo(), false /* wasDispatched */);
    +                     return;
    +                 }
    +-                if (mFocusDispatcher != null) {
    ++                final IAudioFocusDispatcher fd = mFocusDispatcher;
    ++                if (fd != null) {
    +                     if (DEBUG) {
    +                         Log.v(TAG, "dispatching " + focusChangeToString(mFocusLossReceived) + " to "
    +                             + mClientId);
    +                     }
    +                     mFocusController.notifyExtPolicyFocusLoss_syncAf(
    +                             toAudioFocusInfo(), true /* wasDispatched */);
    +-                    mFocusDispatcher.dispatchAudioFocusChange(mFocusLossReceived, mClientId);
    ++                    fd.dispatchAudioFocusChange(mFocusLossReceived, mClientId);
    +                 }
    +             }
    +         } catch (android.os.RemoteException e) {
    +diff --git a/services/core/java/com/android/server/audio/MediaFocusControl.java b/services/core/java/com/android/server/audio/MediaFocusControl.java
    +index 278d70b..206834e 100644
    +--- a/services/core/java/com/android/server/audio/MediaFocusControl.java
    ++++ b/services/core/java/com/android/server/audio/MediaFocusControl.java
    +@@ -160,6 +160,7 @@ public class MediaFocusControl {
    +                     Log.i(TAG, "AudioFocus  removeFocusStackEntry(): removing entry for "
    +                             + clientToRemove);
    +                     stackIterator.remove();
    ++                    // stack entry not used anymore, clear references
    +                     fr.release();
    +                 }
    +             }
    +@@ -171,7 +172,7 @@ public class MediaFocusControl {
    +      * Called synchronized on mAudioFocusLock
    +      * Remove focus listeners from the focus stack for a particular client when it has died.
    +      */
    +-    private void removeFocusStackEntryForClient(IBinder cb) {
    ++    private void removeFocusStackEntryOnDeath(IBinder cb) {
    +         // is the owner of the audio focus part of the client to remove?
    +         boolean isTopOfStackForClientToRemove = !mFocusStack.isEmpty() &&
    +                 mFocusStack.peek().hasSameBinder(cb);
    +@@ -181,9 +182,10 @@ public class MediaFocusControl {
    +         while(stackIterator.hasNext()) {
    +             FocusRequester fr = stackIterator.next();
    +             if(fr.hasSameBinder(cb)) {
    +-                Log.i(TAG, "AudioFocus  removeFocusStackEntry(): removing entry for " + cb);
    ++                Log.i(TAG, "AudioFocus  removeFocusStackEntryOnDeath(): removing entry for " + cb);
    +                 stackIterator.remove();
    +-                // the client just died, no need to unlink to its death
    ++                // stack entry not used anymore, clear references
    ++                fr.release();
    +             }
    +         }
    +         if (isTopOfStackForClientToRemove) {
    +@@ -257,14 +259,9 @@ public class MediaFocusControl {
    + 
    +         public void binderDied() {
    +             synchronized(mAudioFocusLock) {
    +-                Log.w(TAG, "  AudioFocus   audio focus client died");
    +-                removeFocusStackEntryForClient(mCb);
    ++                removeFocusStackEntryOnDeath(mCb);
    +             }
    +         }
    +-
    +-        public IBinder getBinder() {
    +-            return mCb;
    +-        }
    +     }
    + 
    +     /**
    +@@ -420,6 +417,7 @@ public class MediaFocusControl {
    +             // (premature death == death before abandoning focus)
    +             // Register for client death notification
    +             AudioFocusDeathHandler afdh = new AudioFocusDeathHandler(cb);
    ++
    +             try {
    +                 cb.linkToDeath(afdh, 0);
    +             } catch (RemoteException e) {
    +diff --git a/services/core/java/com/android/server/connectivity/IpConnectivityEventBuilder.java b/services/core/java/com/android/server/connectivity/IpConnectivityEventBuilder.java
    +new file mode 100644
    +index 0000000..f1ef947
    +--- /dev/null
    ++++ b/services/core/java/com/android/server/connectivity/IpConnectivityEventBuilder.java
    +@@ -0,0 +1,257 @@
    ++/*
    ++ * Copyright (C) 2016 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 com.android.server.connectivity;
    ++
    ++import android.net.ConnectivityMetricsEvent;
    ++import android.net.metrics.ApfProgramEvent;
    ++import android.net.metrics.ApfStats;
    ++import android.net.metrics.DefaultNetworkEvent;
    ++import android.net.metrics.DhcpClientEvent;
    ++import android.net.metrics.DhcpErrorEvent;
    ++import android.net.metrics.DnsEvent;
    ++import android.net.metrics.IpManagerEvent;
    ++import android.net.metrics.IpReachabilityEvent;
    ++import android.net.metrics.NetworkEvent;
    ++import android.net.metrics.RaEvent;
    ++import android.net.metrics.ValidationProbeEvent;
    ++import android.os.Parcelable;
    ++import com.android.server.connectivity.metrics.IpConnectivityLogClass;
    ++import java.io.IOException;
    ++import java.util.ArrayList;
    ++import java.util.List;
    ++
    ++import static com.android.server.connectivity.metrics.IpConnectivityLogClass.IpConnectivityEvent;
    ++import static com.android.server.connectivity.metrics.IpConnectivityLogClass.IpConnectivityLog;
    ++import static com.android.server.connectivity.metrics.IpConnectivityLogClass.NetworkId;
    ++
    ++/** {@hide} */
    ++final public class IpConnectivityEventBuilder {
    ++    private IpConnectivityEventBuilder() {
    ++    }
    ++
    ++    public static byte[] serialize(int dropped, List<ConnectivityMetricsEvent> events)
    ++            throws IOException {
    ++        final IpConnectivityLog log = new IpConnectivityLog();
    ++        log.events = toProto(events);
    ++        log.droppedEvents = dropped;
    ++        return IpConnectivityLog.toByteArray(log);
    ++    }
    ++
    ++    public static IpConnectivityEvent[] toProto(List<ConnectivityMetricsEvent> eventsIn) {
    ++        final ArrayList<IpConnectivityEvent> eventsOut = new ArrayList<>(eventsIn.size());
    ++        for (ConnectivityMetricsEvent in : eventsIn) {
    ++            final IpConnectivityEvent out = toProto(in);
    ++            if (out == null) {
    ++                continue;
    ++            }
    ++            eventsOut.add(out);
    ++        }
    ++        return eventsOut.toArray(new IpConnectivityEvent[eventsOut.size()]);
    ++    }
    ++
    ++    public static IpConnectivityEvent toProto(ConnectivityMetricsEvent ev) {
    ++        final IpConnectivityEvent out = new IpConnectivityEvent();
    ++        if (!setEvent(out, ev.data)) {
    ++            return null;
    ++        }
    ++        out.timeMs = ev.timestamp;
    ++        return out;
    ++    }
    ++
    ++    private static boolean setEvent(IpConnectivityEvent out, Parcelable in) {
    ++        if (in instanceof DhcpErrorEvent) {
    ++            setDhcpErrorEvent(out, (DhcpErrorEvent) in);
    ++            return true;
    ++        }
    ++
    ++        if (in instanceof DhcpClientEvent) {
    ++            setDhcpClientEvent(out, (DhcpClientEvent) in);
    ++            return true;
    ++        }
    ++
    ++        if (in instanceof DnsEvent) {
    ++            setDnsEvent(out, (DnsEvent) in);
    ++            return true;
    ++        }
    ++
    ++        if (in instanceof IpManagerEvent) {
    ++            setIpManagerEvent(out, (IpManagerEvent) in);
    ++            return true;
    ++        }
    ++
    ++        if (in instanceof IpReachabilityEvent) {
    ++            setIpReachabilityEvent(out, (IpReachabilityEvent) in);
    ++            return true;
    ++        }
    ++
    ++        if (in instanceof DefaultNetworkEvent) {
    ++            setDefaultNetworkEvent(out, (DefaultNetworkEvent) in);
    ++            return true;
    ++        }
    ++
    ++        if (in instanceof NetworkEvent) {
    ++            setNetworkEvent(out, (NetworkEvent) in);
    ++            return true;
    ++        }
    ++
    ++        if (in instanceof ValidationProbeEvent) {
    ++            setValidationProbeEvent(out, (ValidationProbeEvent) in);
    ++            return true;
    ++        }
    ++
    ++        if (in instanceof ApfProgramEvent) {
    ++            setApfProgramEvent(out, (ApfProgramEvent) in);
    ++            return true;
    ++        }
    ++
    ++        if (in instanceof ApfStats) {
    ++            setApfStats(out, (ApfStats) in);
    ++            return true;
    ++        }
    ++
    ++        if (in instanceof RaEvent) {
    ++            setRaEvent(out, (RaEvent) in);
    ++            return true;
    ++        }
    ++
    ++        return false;
    ++    }
    ++
    ++    private static void setDhcpErrorEvent(IpConnectivityEvent out, DhcpErrorEvent in) {
    ++        out.dhcpEvent = new IpConnectivityLogClass.DHCPEvent();
    ++        out.dhcpEvent.ifName = in.ifName;
    ++        out.dhcpEvent.errorCode = in.errorCode;
    ++    }
    ++
    ++    private static void setDhcpClientEvent(IpConnectivityEvent out, DhcpClientEvent in) {
    ++        out.dhcpEvent = new IpConnectivityLogClass.DHCPEvent();
    ++        out.dhcpEvent.ifName = in.ifName;
    ++        out.dhcpEvent.stateTransition = in.msg;
    ++        out.dhcpEvent.durationMs = in.durationMs;
    ++    }
    ++
    ++    private static void setDnsEvent(IpConnectivityEvent out, DnsEvent in) {
    ++        out.dnsLookupBatch = new IpConnectivityLogClass.DNSLookupBatch();
    ++        out.dnsLookupBatch.networkId = netIdOf(in.netId);
    ++        out.dnsLookupBatch.eventTypes = bytesToInts(in.eventTypes);
    ++        out.dnsLookupBatch.returnCodes = bytesToInts(in.returnCodes);
    ++        out.dnsLookupBatch.latenciesMs = in.latenciesMs;
    ++    }
    ++
    ++    private static void setIpManagerEvent(IpConnectivityEvent out, IpManagerEvent in) {
    ++        out.ipProvisioningEvent = new IpConnectivityLogClass.IpProvisioningEvent();
    ++        out.ipProvisioningEvent.ifName = in.ifName;
    ++        out.ipProvisioningEvent.eventType = in.eventType;
    ++        out.ipProvisioningEvent.latencyMs = (int) in.durationMs;
    ++    }
    ++
    ++    private static void setIpReachabilityEvent(IpConnectivityEvent out, IpReachabilityEvent in) {
    ++        out.ipReachabilityEvent = new IpConnectivityLogClass.IpReachabilityEvent();
    ++        out.ipReachabilityEvent.ifName = in.ifName;
    ++        out.ipReachabilityEvent.eventType = in.eventType;
    ++    }
    ++
    ++    private static void setDefaultNetworkEvent(IpConnectivityEvent out, DefaultNetworkEvent in) {
    ++        out.defaultNetworkEvent = new IpConnectivityLogClass.DefaultNetworkEvent();
    ++        out.defaultNetworkEvent.networkId = netIdOf(in.netId);
    ++        out.defaultNetworkEvent.previousNetworkId = netIdOf(in.prevNetId);
    ++        out.defaultNetworkEvent.transportTypes = in.transportTypes;
    ++        out.defaultNetworkEvent.previousNetworkIpSupport = ipSupportOf(in);
    ++    }
    ++
    ++    private static void setNetworkEvent(IpConnectivityEvent out, NetworkEvent in) {
    ++        out.networkEvent = new IpConnectivityLogClass.NetworkEvent();
    ++        out.networkEvent.networkId = netIdOf(in.netId);
    ++        out.networkEvent.eventType = in.eventType;
    ++        out.networkEvent.latencyMs = (int) in.durationMs;
    ++    }
    ++
    ++    private static void setValidationProbeEvent(IpConnectivityEvent out, ValidationProbeEvent in) {
    ++        out.validationProbeEvent = new IpConnectivityLogClass.ValidationProbeEvent();
    ++        out.validationProbeEvent.networkId = netIdOf(in.netId);
    ++        out.validationProbeEvent.latencyMs = (int) in.durationMs;
    ++        out.validationProbeEvent.probeType = in.probeType;
    ++        out.validationProbeEvent.probeResult = in.returnCode;
    ++    }
    ++
    ++    private static void setApfProgramEvent(IpConnectivityEvent out, ApfProgramEvent in) {
    ++        out.apfProgramEvent = new IpConnectivityLogClass.ApfProgramEvent();
    ++        out.apfProgramEvent.lifetime = in.lifetime;
    ++        out.apfProgramEvent.filteredRas = in.filteredRas;
    ++        out.apfProgramEvent.currentRas = in.currentRas;
    ++        out.apfProgramEvent.programLength = in.programLength;
    ++        if (isBitSet(in.flags, ApfProgramEvent.FLAG_MULTICAST_FILTER_ON)) {
    ++            out.apfProgramEvent.dropMulticast = true;
    ++        }
    ++        if (isBitSet(in.flags, ApfProgramEvent.FLAG_HAS_IPV4_ADDRESS)) {
    ++            out.apfProgramEvent.hasIpv4Addr = true;
    ++        }
    ++    }
    ++
    ++    private static void setApfStats(IpConnectivityEvent out, ApfStats in) {
    ++        out.apfStatistics = new IpConnectivityLogClass.ApfStatistics();
    ++        out.apfStatistics.durationMs = in.durationMs;
    ++        out.apfStatistics.receivedRas = in.receivedRas;
    ++        out.apfStatistics.matchingRas = in.matchingRas;
    ++        out.apfStatistics.droppedRas = in.droppedRas;
    ++        out.apfStatistics.zeroLifetimeRas = in.zeroLifetimeRas;
    ++        out.apfStatistics.parseErrors = in.parseErrors;
    ++        out.apfStatistics.programUpdates = in.programUpdates;
    ++        out.apfStatistics.maxProgramSize = in.maxProgramSize;
    ++    }
    ++
    ++    private static void setRaEvent(IpConnectivityEvent out, RaEvent in) {
    ++        out.raEvent = new IpConnectivityLogClass.RaEvent();
    ++        out.raEvent.routerLifetime = in.routerLifetime;
    ++        out.raEvent.prefixValidLifetime = in.prefixValidLifetime;
    ++        out.raEvent.prefixPreferredLifetime = in.prefixPreferredLifetime;
    ++        out.raEvent.routeInfoLifetime = in.routeInfoLifetime;
    ++        out.raEvent.rdnssLifetime = in.rdnssLifetime;
    ++        out.raEvent.dnsslLifetime = in.dnsslLifetime;
    ++    }
    ++
    ++    private static int[] bytesToInts(byte[] in) {
    ++        final int[] out = new int[in.length];
    ++        for (int i = 0; i < in.length; i++) {
    ++            out[i] = in[i] & 0xFF;
    ++        }
    ++        return out;
    ++    }
    ++
    ++    private static NetworkId netIdOf(int netid) {
    ++        final NetworkId ni = new NetworkId();
    ++        ni.networkId = netid;
    ++        return ni;
    ++    }
    ++
    ++    private static int ipSupportOf(DefaultNetworkEvent in) {
    ++        if (in.prevIPv4 && in.prevIPv6) {
    ++            return IpConnectivityLogClass.DefaultNetworkEvent.DUAL;
    ++        }
    ++        if (in.prevIPv6) {
    ++            return IpConnectivityLogClass.DefaultNetworkEvent.IPV6;
    ++        }
    ++        if (in.prevIPv4) {
    ++            return IpConnectivityLogClass.DefaultNetworkEvent.IPV4;
    ++        }
    ++        return IpConnectivityLogClass.DefaultNetworkEvent.NONE;
    ++    }
    ++
    ++    private static boolean isBitSet(int flags, int bit) {
    ++        return (flags & (1 << bit)) != 0;
    ++    }
    ++}
    +diff --git a/services/core/java/com/android/server/connectivity/IpConnectivityMetrics.java b/services/core/java/com/android/server/connectivity/IpConnectivityMetrics.java
    +new file mode 100644
    +index 0000000..bcbcf54
    +--- /dev/null
    ++++ b/services/core/java/com/android/server/connectivity/IpConnectivityMetrics.java
    +@@ -0,0 +1,229 @@
    ++/*
    ++ * Copyright (C) 2016 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 com.android.server.connectivity;
    ++
    ++import android.content.Context;
    ++import android.net.ConnectivityMetricsEvent;
    ++import android.net.IIpConnectivityMetrics;
    ++import android.net.metrics.IpConnectivityLog;
    ++import android.os.IBinder;
    ++import android.os.Parcelable;
    ++import android.text.TextUtils;
    ++import android.util.Base64;
    ++import android.util.Log;
    ++import com.android.internal.annotations.GuardedBy;
    ++import com.android.internal.annotations.VisibleForTesting;
    ++import com.android.server.SystemService;
    ++import java.io.FileDescriptor;
    ++import java.io.IOException;
    ++import java.io.PrintWriter;
    ++import java.util.ArrayList;
    ++
    ++import static com.android.server.connectivity.metrics.IpConnectivityLogClass.IpConnectivityEvent;
    ++
    ++/** {@hide} */
    ++final public class IpConnectivityMetrics extends SystemService {
    ++    private static final String TAG = IpConnectivityMetrics.class.getSimpleName();
    ++    private static final boolean DBG = false;
    ++
    ++    private static final String SERVICE_NAME = IpConnectivityLog.SERVICE_NAME;
    ++
    ++    // Default size of the event buffer. Once the buffer is full, incoming events are dropped.
    ++    private static final int DEFAULT_BUFFER_SIZE = 2000;
    ++
    ++    // Lock ensuring that concurrent manipulations of the event buffer are correct.
    ++    // There are three concurrent operations to synchronize:
    ++    //  - appending events to the buffer.
    ++    //  - iterating throught the buffer.
    ++    //  - flushing the buffer content and replacing it by a new buffer.
    ++    private final Object mLock = new Object();
    ++
    ++    @VisibleForTesting
    ++    public final Impl impl = new Impl();
    ++    private DnsEventListenerService mDnsListener;
    ++
    ++    @GuardedBy("mLock")
    ++    private ArrayList<ConnectivityMetricsEvent> mBuffer;
    ++    @GuardedBy("mLock")
    ++    private int mDropped;
    ++    @GuardedBy("mLock")
    ++    private int mCapacity;
    ++
    ++    public IpConnectivityMetrics(Context ctx) {
    ++        super(ctx);
    ++        initBuffer();
    ++    }
    ++
    ++    @Override
    ++    public void onStart() {
    ++        if (DBG) Log.d(TAG, "onStart");
    ++    }
    ++
    ++    @Override
    ++    public void onBootPhase(int phase) {
    ++        if (phase == SystemService.PHASE_SYSTEM_SERVICES_READY) {
    ++            if (DBG) Log.d(TAG, "onBootPhase");
    ++            mDnsListener = new DnsEventListenerService(getContext());
    ++
    ++            publishBinderService(SERVICE_NAME, impl);
    ++            publishBinderService(mDnsListener.SERVICE_NAME, mDnsListener);
    ++        }
    ++    }
    ++
    ++    @VisibleForTesting
    ++    public int bufferCapacity() {
    ++        return DEFAULT_BUFFER_SIZE; // TODO: read from config
    ++    }
    ++
    ++    private void initBuffer() {
    ++        synchronized (mLock) {
    ++            mDropped = 0;
    ++            mCapacity = bufferCapacity();
    ++            mBuffer = new ArrayList<>(mCapacity);
    ++        }
    ++    }
    ++
    ++    private int append(ConnectivityMetricsEvent event) {
    ++        if (DBG) Log.d(TAG, "logEvent: " + event);
    ++        synchronized (mLock) {
    ++            final int left = mCapacity - mBuffer.size();
    ++            if (event == null) {
    ++                return left;
    ++            }
    ++            if (left == 0) {
    ++                mDropped++;
    ++                return 0;
    ++            }
    ++            mBuffer.add(event);
    ++            return left - 1;
    ++        }
    ++    }
    ++
    ++    private String flushEncodedOutput() {
    ++        final ArrayList<ConnectivityMetricsEvent> events;
    ++        final int dropped;
    ++        synchronized (mLock) {
    ++            events = mBuffer;
    ++            dropped = mDropped;
    ++            initBuffer();
    ++        }
    ++
    ++        final byte[] data;
    ++        try {
    ++            data = IpConnectivityEventBuilder.serialize(dropped, events);
    ++        } catch (IOException e) {
    ++            Log.e(TAG, "could not serialize events", e);
    ++            return "";
    ++        }
    ++
    ++        return Base64.encodeToString(data, Base64.DEFAULT);
    ++    }
    ++
    ++    /**
    ++     * Clears the event buffer and prints its content as a protobuf serialized byte array
    ++     * inside a base64 encoded string.
    ++     */
    ++    private void cmdFlush(FileDescriptor fd, PrintWriter pw, String[] args) {
    ++        pw.print(flushEncodedOutput());
    ++    }
    ++
    ++    /**
    ++     * Prints the content of the event buffer, either using the events ASCII representation
    ++     * or using protobuf text format.
    ++     */
    ++    private void cmdList(FileDescriptor fd, PrintWriter pw, String[] args) {
    ++        final ArrayList<ConnectivityMetricsEvent> events;
    ++        synchronized (mLock) {
    ++            events = new ArrayList(mBuffer);
    ++        }
    ++
    ++        if (args.length > 1 && args[1].equals("proto")) {
    ++            for (IpConnectivityEvent ev : IpConnectivityEventBuilder.toProto(events)) {
    ++                pw.print(ev.toString());
    ++            }
    ++            return;
    ++        }
    ++
    ++        for (ConnectivityMetricsEvent ev : events) {
    ++            pw.println(ev.toString());
    ++        }
    ++    }
    ++
    ++    private void cmdStats(FileDescriptor fd, PrintWriter pw, String[] args) {
    ++        synchronized (mLock) {
    ++            pw.println("Buffered events: " + mBuffer.size());
    ++            pw.println("Buffer capacity: " + mCapacity);
    ++            pw.println("Dropped events: " + mDropped);
    ++        }
    ++        if (mDnsListener != null) {
    ++            mDnsListener.dump(pw);
    ++        }
    ++    }
    ++
    ++    private void cmdDefault(FileDescriptor fd, PrintWriter pw, String[] args) {
    ++        if (args.length == 0) {
    ++            pw.println("No command");
    ++            return;
    ++        }
    ++        pw.println("Unknown command " + TextUtils.join(" ", args));
    ++    }
    ++
    ++    public final class Impl extends IIpConnectivityMetrics.Stub {
    ++        static final String CMD_FLUSH   = "flush";
    ++        static final String CMD_LIST    = "list";
    ++        static final String CMD_STATS   = "stats";
    ++        static final String CMD_DEFAULT = CMD_STATS;
    ++
    ++        @Override
    ++        public int logEvent(ConnectivityMetricsEvent event) {
    ++            enforceConnectivityInternalPermission();
    ++            return append(event);
    ++        }
    ++
    ++        @Override
    ++        public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
    ++            enforceDumpPermission();
    ++            if (DBG) Log.d(TAG, "dumpsys " + TextUtils.join(" ", args));
    ++            final String cmd = (args.length > 0) ? args[0] : CMD_DEFAULT;
    ++            switch (cmd) {
    ++                case CMD_FLUSH:
    ++                    cmdFlush(fd, pw, args);
    ++                    return;
    ++                case CMD_LIST:
    ++                    cmdList(fd, pw, args);
    ++                    return;
    ++                case CMD_STATS:
    ++                    cmdStats(fd, pw, args);
    ++                    return;
    ++                default:
    ++                    cmdDefault(fd, pw, args);
    ++            }
    ++        }
    ++
    ++        private void enforceConnectivityInternalPermission() {
    ++            enforcePermission(android.Manifest.permission.CONNECTIVITY_INTERNAL);
    ++        }
    ++
    ++        private void enforceDumpPermission() {
    ++            enforcePermission(android.Manifest.permission.DUMP);
    ++        }
    ++
    ++        private void enforcePermission(String what) {
    ++            getContext().enforceCallingOrSelfPermission(what, "IpConnectivityMetrics");
    ++        }
    ++    };
    ++}
    +diff --git a/services/core/java/com/android/server/connectivity/MetricsLoggerService.java b/services/core/java/com/android/server/connectivity/MetricsLoggerService.java
    +index 05f1a6e..1c9feb2 100644
    +--- a/services/core/java/com/android/server/connectivity/MetricsLoggerService.java
    ++++ b/services/core/java/com/android/server/connectivity/MetricsLoggerService.java
    +@@ -56,8 +56,6 @@ public class MetricsLoggerService extends SystemService {
    +             if (DBG) Log.d(TAG, "onBootPhase: PHASE_SYSTEM_SERVICES_READY");
    +             publishBinderService(ConnectivityMetricsLogger.CONNECTIVITY_METRICS_LOGGER_SERVICE,
    +                     mBinder);
    +-            mDnsListener = new DnsEventListenerService(getContext());
    +-            publishBinderService(mDnsListener.SERVICE_NAME, mDnsListener);
    +         }
    +     }
    + 
    +@@ -86,8 +84,6 @@ public class MetricsLoggerService extends SystemService {
    + 
    +     private final ArrayDeque<ConnectivityMetricsEvent> mEvents = new ArrayDeque<>();
    + 
    +-    private DnsEventListenerService mDnsListener;
    +-
    +     private void enforceConnectivityInternalPermission() {
    +         getContext().enforceCallingOrSelfPermission(
    +                 android.Manifest.permission.CONNECTIVITY_INTERNAL,
    +@@ -219,11 +215,6 @@ public class MetricsLoggerService extends SystemService {
    +                     }
    +                 }
    +             }
    +-
    +-            pw.println();
    +-            if (mDnsListener != null) {
    +-                mDnsListener.dump(pw);
    +-            }
    +         }
    + 
    +         public long logEvent(ConnectivityMetricsEvent event) {
    +diff --git a/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java b/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java
    +index 9c48aee..2a618bc 100644
    +--- a/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java
    ++++ b/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java
    +@@ -104,14 +104,16 @@ import java.util.TreeSet;
    + // -----------------------------------------------
    + // If a network has no chance of satisfying any requests (even if it were to become validated
    + // and enter state #5), ConnectivityService will disconnect the NetworkAgent's AsyncChannel.
    +-// If the network ever for any period of time had satisfied a NetworkRequest (i.e. had been
    +-// the highest scoring that satisfied the NetworkRequest's constraints), but is no longer the
    +-// highest scoring network for any NetworkRequest, then there will be a 30s pause before
    +-// ConnectivityService disconnects the NetworkAgent's AsyncChannel.  During this pause the
    +-// network is considered "lingering".  This pause exists to allow network communication to be
    +-// wrapped up rather than abruptly terminated.  During this pause if the network begins satisfying
    +-// a NetworkRequest, ConnectivityService will cancel the future disconnection of the NetworkAgent's
    +-// AsyncChannel, and the network is no longer considered "lingering".
    ++//
    ++// If the network was satisfying a foreground NetworkRequest (i.e. had been the highest scoring that
    ++// satisfied the NetworkRequest's constraints), but is no longer the highest scoring network for any
    ++// foreground NetworkRequest, then there will be a 30s pause to allow network communication to be
    ++// wrapped up rather than abruptly terminated. During this pause the network is said to be
    ++// "lingering". During this pause if the network begins satisfying a foreground NetworkRequest,
    ++// ConnectivityService will cancel the future disconnection of the NetworkAgent's AsyncChannel, and
    ++// the network is no longer considered "lingering". After the linger timer expires, if the network
    ++// is satisfying one or more background NetworkRequests it is kept up in the background. If it is
    ++// not, ConnectivityService disconnects the NetworkAgent's AsyncChannel.
    + public class NetworkAgentInfo implements Comparable<NetworkAgentInfo> {
    + 
    +     public NetworkInfo networkInfo;
    +@@ -230,11 +232,13 @@ public class NetworkAgentInfo implements Comparable<NetworkAgentInfo> {
    + 
    +     // The list of NetworkRequests being satisfied by this Network.
    +     private final SparseArray<NetworkRequest> mNetworkRequests = new SparseArray<>();
    +-    // The list of NetworkRequests that this Network previously satisfied with the highest
    +-    // score.  A non-empty list indicates that if this Network was validated it is lingered.
    ++
    +     // How many of the satisfied requests are actual requests and not listens.
    +     private int mNumRequestNetworkRequests = 0;
    + 
    ++    // How many of the satisfied requests are of type BACKGROUND_REQUEST.
    ++    private int mNumBackgroundNetworkRequests = 0;
    ++
    +     public final Messenger messenger;
    +     public final AsyncChannel asyncChannel;
    + 
    +@@ -268,6 +272,32 @@ public class NetworkAgentInfo implements Comparable<NetworkAgentInfo> {
    +     //
    +     // These functions must only called on ConnectivityService's main thread.
    + 
    ++    private static final boolean ADD = true;
    ++    private static final boolean REMOVE = false;
    ++
    ++    private void updateRequestCounts(boolean add, NetworkRequest request) {
    ++        int delta = add ? +1 : -1;
    ++        switch (request.type) {
    ++            case REQUEST:
    ++            case TRACK_DEFAULT:
    ++                mNumRequestNetworkRequests += delta;
    ++                break;
    ++
    ++            case BACKGROUND_REQUEST:
    ++                mNumRequestNetworkRequests += delta;
    ++                mNumBackgroundNetworkRequests += delta;
    ++                break;
    ++
    ++            case LISTEN:
    ++                break;
    ++
    ++            case NONE:
    ++            default:
    ++                Log.wtf(TAG, "Unhandled request type " + request.type);
    ++                break;
    ++        }
    ++    }
    ++
    +     /**
    +      * Add {@code networkRequest} to this network as it's satisfied by this network.
    +      * @return true if {@code networkRequest} was added or false if {@code networkRequest} was
    +@@ -276,9 +306,15 @@ public class NetworkAgentInfo implements Comparable<NetworkAgentInfo> {
    +     public boolean addRequest(NetworkRequest networkRequest) {
    +         NetworkRequest existing = mNetworkRequests.get(networkRequest.requestId);
    +         if (existing == networkRequest) return false;
    +-        if (existing != null && existing.isRequest()) mNumRequestNetworkRequests--;
    ++        if (existing != null) {
    ++            // Should only happen if the requestId wraps. If that happens lots of other things will
    ++            // be broken as well.
    ++            Log.wtf(TAG, String.format("Duplicate requestId for %s and %s on %s",
    ++                    networkRequest, existing, name()));
    ++            updateRequestCounts(REMOVE, existing);
    ++        }
    +         mNetworkRequests.put(networkRequest.requestId, networkRequest);
    +-        if (networkRequest.isRequest()) mNumRequestNetworkRequests++;
    ++        updateRequestCounts(ADD, networkRequest);
    +         return true;
    +     }
    + 
    +@@ -288,9 +324,9 @@ public class NetworkAgentInfo implements Comparable<NetworkAgentInfo> {
    +     public void removeRequest(int requestId) {
    +         NetworkRequest existing = mNetworkRequests.get(requestId);
    +         if (existing == null) return;
    ++        updateRequestCounts(REMOVE, existing);
    +         mNetworkRequests.remove(requestId);
    +         if (existing.isRequest()) {
    +-            mNumRequestNetworkRequests--;
    +             unlingerRequest(existing);
    +         }
    +     }
    +@@ -319,12 +355,37 @@ public class NetworkAgentInfo implements Comparable<NetworkAgentInfo> {
    +     }
    + 
    +     /**
    ++     * Returns the number of requests currently satisfied by this network of type
    ++     * {@link android.net.NetworkRequest.Type.BACKGROUND_REQUEST}.
    ++     */
    ++    public int numBackgroundNetworkRequests() {
    ++        return mNumBackgroundNetworkRequests;
    ++    }
    ++
    ++    /**
    ++     * Returns the number of foreground requests currently satisfied by this network.
    ++     */
    ++    public int numForegroundNetworkRequests() {
    ++        return mNumRequestNetworkRequests - mNumBackgroundNetworkRequests;
    ++    }
    ++
    ++    /**
    +      * Returns the number of requests of any type currently satisfied by this network.
    +      */
    +     public int numNetworkRequests() {
    +         return mNetworkRequests.size();
    +     }
    + 
    ++    /**
    ++     * Returns whether the network is a background network. A network is a background network if it
    ++     * is satisfying no foreground requests and at least one background request. (If it did not have
    ++     * a background request, it would be a speculative network that is only being kept up because
    ++     * it might satisfy a request if it validated).
    ++     */
    ++    public boolean isBackgroundNetwork() {
    ++        return !isVPN() && numForegroundNetworkRequests() == 0 && mNumBackgroundNetworkRequests > 0;
    ++    }
    ++
    +     // Does this network satisfy request?
    +     public boolean satisfies(NetworkRequest request) {
    +         return created &&
    +diff --git a/services/core/java/com/android/server/connectivity/NetworkMonitor.java b/services/core/java/com/android/server/connectivity/NetworkMonitor.java
    +index 42d80fc..6eb89fa 100644
    +--- a/services/core/java/com/android/server/connectivity/NetworkMonitor.java
    ++++ b/services/core/java/com/android/server/connectivity/NetworkMonitor.java
    +@@ -23,7 +23,6 @@ import static android.net.CaptivePortal.APP_RETURN_WANTED_AS_IS;
    + import android.app.AlarmManager;
    + import android.app.PendingIntent;
    + import android.content.BroadcastReceiver;
    +-import android.content.ComponentName;
    + import android.content.Context;
    + import android.content.Intent;
    + import android.content.IntentFilter;
    +@@ -37,14 +36,12 @@ import android.net.Uri;
    + import android.net.metrics.IpConnectivityLog;
    + import android.net.metrics.NetworkEvent;
    + import android.net.metrics.ValidationProbeEvent;
    ++import android.net.util.Stopwatch;
    + import android.net.wifi.WifiInfo;
    + import android.net.wifi.WifiManager;
    +-import android.net.util.Stopwatch;
    + import android.os.Handler;
    + import android.os.Message;
    +-import android.os.Process;
    + import android.os.SystemClock;
    +-import android.os.SystemProperties;
    + import android.os.UserHandle;
    + import android.provider.Settings;
    + import android.telephony.CellIdentityCdma;
    +@@ -66,27 +63,39 @@ import com.android.internal.annotations.VisibleForTesting;
    + import com.android.internal.util.Protocol;
    + import com.android.internal.util.State;
    + import com.android.internal.util.StateMachine;
    +-import com.android.internal.util.WakeupMessage;
    + 
    + import java.io.IOException;
    + import java.net.HttpURLConnection;
    + import java.net.InetAddress;
    + import java.net.MalformedURLException;
    +-import java.net.UnknownHostException;
    + import java.net.URL;
    +-import java.util.concurrent.CountDownLatch;
    +-import java.util.concurrent.atomic.AtomicReference;
    ++import java.net.UnknownHostException;
    + import java.util.List;
    + import java.util.Random;
    ++import java.util.concurrent.CountDownLatch;
    ++import java.util.concurrent.TimeUnit;
    + 
    + /**
    +  * {@hide}
    +  */
    + public class NetworkMonitor extends StateMachine {
    +-    private static final boolean DBG = false;
    +     private static final String TAG = NetworkMonitor.class.getSimpleName();
    +-    private static final String DEFAULT_SERVER = "connectivitycheck.gstatic.com";
    ++    private static final boolean DBG = false;
    ++
    ++    // Default configuration values for captive portal detection probes.
    ++    // TODO: append a random length parameter to the default HTTPS url.
    ++    // TODO: randomize browser version ids in the default User-Agent String.
    ++    private static final String DEFAULT_HTTPS_URL     = "https://www.google.com/generate_204";
    ++    private static final String DEFAULT_HTTP_URL      =
    ++            "http://connectivitycheck.gstatic.com/generate_204";
    ++    private static final String DEFAULT_FALLBACK_URL  = "http://www.google.com/gen_204";
    ++    private static final String DEFAULT_USER_AGENT    = "Mozilla/5.0 (X11; Linux x86_64) "
    ++                                                      + "AppleWebKit/537.36 (KHTML, like Gecko) "
    ++                                                      + "Chrome/52.0.2743.82 Safari/537.36";
    ++
    +     private static final int SOCKET_TIMEOUT_MS = 10000;
    ++    private static final int PROBE_TIMEOUT_MS  = 3000;
    ++
    +     public static final String ACTION_NETWORK_CONDITIONS_MEASURED =
    +             "android.net.conn.NETWORK_CONDITIONS_MEASURED";
    +     public static final String EXTRA_CONNECTIVITY_TYPE = "extra_connectivity_type";
    +@@ -224,6 +233,9 @@ public class NetworkMonitor extends StateMachine {
    + 
    +     private final Stopwatch mEvaluationTimer = new Stopwatch();
    + 
    ++    // This variable is set before transitioning to the mCaptivePortalState.
    ++    private CaptivePortalProbeResult mLastPortalProbeResult = CaptivePortalProbeResult.FAILED;
    ++
    +     public NetworkMonitor(Context context, Handler handler, NetworkAgentInfo networkAgentInfo,
    +             NetworkRequest defaultRequest) {
    +         this(context, handler, networkAgentInfo, defaultRequest, new IpConnectivityLog());
    +@@ -389,6 +401,8 @@ public class NetworkMonitor extends StateMachine {
    +                                     sendMessage(CMD_CAPTIVE_PORTAL_APP_FINISHED, response);
    +                                 }
    +                             }));
    ++                    intent.putExtra(ConnectivityManager.EXTRA_CAPTIVE_PORTAL_URL,
    ++                            mLastPortalProbeResult.detectUrl);
    +                     intent.setFlags(
    +                             Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT | Intent.FLAG_ACTIVITY_NEW_TASK);
    +                     mContext.startActivityAsUser(intent, UserHandle.CURRENT);
    +@@ -412,14 +426,22 @@ public class NetworkMonitor extends StateMachine {
    +      */
    +     @VisibleForTesting
    +     public static final class CaptivePortalProbeResult {
    +-        static final CaptivePortalProbeResult FAILED = new CaptivePortalProbeResult(599, null);
    ++        static final CaptivePortalProbeResult FAILED = new CaptivePortalProbeResult(599);
    + 
    +-        final int mHttpResponseCode; // HTTP response code returned from Internet probe.
    +-        final String mRedirectUrl;   // Redirect destination returned from Internet probe.
    ++        private final int mHttpResponseCode;  // HTTP response code returned from Internet probe.
    ++        final String redirectUrl;             // Redirect destination returned from Internet probe.
    ++        final String detectUrl;               // URL where a 204 response code indicates
    ++                                              // captive portal has been appeased.
    + 
    +-        public CaptivePortalProbeResult(int httpResponseCode, String redirectUrl) {
    ++        public CaptivePortalProbeResult(
    ++                int httpResponseCode, String redirectUrl, String detectUrl) {
    +             mHttpResponseCode = httpResponseCode;
    +-            mRedirectUrl = redirectUrl;
    ++            this.redirectUrl = redirectUrl;
    ++            this.detectUrl = detectUrl;
    ++        }
    ++
    ++        public CaptivePortalProbeResult(int httpResponseCode) {
    ++            this(httpResponseCode, null, null);
    +         }
    + 
    +         boolean isSuccessful() { return mHttpResponseCode == 204; }
    +@@ -492,7 +514,8 @@ public class NetworkMonitor extends StateMachine {
    +                         transitionTo(mValidatedState);
    +                     } else if (probeResult.isPortal()) {
    +                         mConnectivityServiceHandler.sendMessage(obtainMessage(EVENT_NETWORK_TESTED,
    +-                                NETWORK_TEST_RESULT_INVALID, mNetId, probeResult.mRedirectUrl));
    ++                                NETWORK_TEST_RESULT_INVALID, mNetId, probeResult.redirectUrl));
    ++                        mLastPortalProbeResult = probeResult;
    +                         transitionTo(mCaptivePortalState);
    +                     } else {
    +                         final Message msg = obtainMessage(CMD_REEVALUATE, ++mReevaluateToken, 0);
    +@@ -500,7 +523,7 @@ public class NetworkMonitor extends StateMachine {
    +                         logNetworkEvent(NetworkEvent.NETWORK_VALIDATION_FAILED);
    +                         mConnectivityServiceHandler.sendMessage(obtainMessage(
    +                                 EVENT_NETWORK_TESTED, NETWORK_TEST_RESULT_INVALID, mNetId,
    +-                                probeResult.mRedirectUrl));
    ++                                probeResult.redirectUrl));
    +                         if (mAttempts >= BLAME_FOR_EVALUATION_ATTEMPTS) {
    +                             // Don't continue to blame UID forever.
    +                             TrafficStats.clearThreadStatsUid();
    +@@ -585,22 +608,33 @@ public class NetworkMonitor extends StateMachine {
    +         }
    +     }
    + 
    +-    private static String getCaptivePortalServerUrl(Context context, boolean isHttps) {
    +-        String server = Settings.Global.getString(context.getContentResolver(),
    +-                Settings.Global.CAPTIVE_PORTAL_SERVER);
    +-        if (server == null) server = DEFAULT_SERVER;
    +-        return (isHttps ? "https" : "http") + "://" + server + "/generate_204";
    ++    private static String getCaptivePortalServerHttpsUrl(Context context) {
    ++        return getSetting(context, Settings.Global.CAPTIVE_PORTAL_HTTPS_URL, DEFAULT_HTTPS_URL);
    ++    }
    ++
    ++    public static String getCaptivePortalServerHttpUrl(Context context) {
    ++        return getSetting(context, Settings.Global.CAPTIVE_PORTAL_HTTP_URL, DEFAULT_HTTP_URL);
    +     }
    + 
    +-    public static String getCaptivePortalServerUrl(Context context) {
    +-        return getCaptivePortalServerUrl(context, false);
    ++    private static String getCaptivePortalFallbackUrl(Context context) {
    ++        return getSetting(context,
    ++                Settings.Global.CAPTIVE_PORTAL_FALLBACK_URL, DEFAULT_FALLBACK_URL);
    ++    }
    ++
    ++    private static String getCaptivePortalUserAgent(Context context) {
    ++        return getSetting(context, Settings.Global.CAPTIVE_PORTAL_USER_AGENT, DEFAULT_USER_AGENT);
    ++    }
    ++
    ++    private static String getSetting(Context context, String symbol, String defaultValue) {
    ++        final String value = Settings.Global.getString(context.getContentResolver(), symbol);
    ++        return value != null ? value : defaultValue;
    +     }
    + 
    +     @VisibleForTesting
    +     protected CaptivePortalProbeResult isCaptivePortal() {
    +-        if (!mIsCaptivePortalCheckEnabled) return new CaptivePortalProbeResult(204, null);
    ++        if (!mIsCaptivePortalCheckEnabled) return new CaptivePortalProbeResult(204);
    + 
    +-        URL pacUrl = null, httpUrl = null, httpsUrl = null;
    ++        URL pacUrl = null, httpsUrl = null, httpUrl = null, fallbackUrl = null;
    + 
    +         // On networks with a PAC instead of fetching a URL that should result in a 204
    +         // response, we instead simply fetch the PAC script.  This is done for a few reasons:
    +@@ -621,20 +655,17 @@ public class NetworkMonitor extends StateMachine {
    +         //    results for network validation.
    +         final ProxyInfo proxyInfo = mNetworkAgentInfo.linkProperties.getHttpProxy();
    +         if (proxyInfo != null && !Uri.EMPTY.equals(proxyInfo.getPacFileUrl())) {
    +-            try {
    +-                pacUrl = new URL(proxyInfo.getPacFileUrl().toString());
    +-            } catch (MalformedURLException e) {
    +-                validationLog("Invalid PAC URL: " + proxyInfo.getPacFileUrl().toString());
    ++            pacUrl = makeURL(proxyInfo.getPacFileUrl().toString());
    ++            if (pacUrl == null) {
    +                 return CaptivePortalProbeResult.FAILED;
    +             }
    +         }
    + 
    +         if (pacUrl == null) {
    +-            try {
    +-                httpUrl = new URL(getCaptivePortalServerUrl(mContext, false));
    +-                httpsUrl = new URL(getCaptivePortalServerUrl(mContext, true));
    +-            } catch (MalformedURLException e) {
    +-                validationLog("Bad validation URL: " + getCaptivePortalServerUrl(mContext, false));
    ++            httpsUrl = makeURL(getCaptivePortalServerHttpsUrl(mContext));
    ++            httpUrl = makeURL(getCaptivePortalServerHttpUrl(mContext));
    ++            fallbackUrl = makeURL(getCaptivePortalFallbackUrl(mContext));
    ++            if (httpUrl == null || httpsUrl == null) {
    +                 return CaptivePortalProbeResult.FAILED;
    +             }
    +         }
    +@@ -680,7 +711,7 @@ public class NetworkMonitor extends StateMachine {
    +         if (pacUrl != null) {
    +             result = sendHttpProbe(pacUrl, ValidationProbeEvent.PROBE_PAC);
    +         } else if (mUseHttps) {
    +-            result = sendParallelHttpProbes(httpsUrl, httpUrl);
    ++            result = sendParallelHttpProbes(httpsUrl, httpUrl, fallbackUrl);
    +         } else {
    +             result = sendHttpProbe(httpUrl, ValidationProbeEvent.PROBE_HTTP);
    +         }
    +@@ -710,6 +741,10 @@ public class NetworkMonitor extends StateMachine {
    +             urlConnection.setConnectTimeout(SOCKET_TIMEOUT_MS);
    +             urlConnection.setReadTimeout(SOCKET_TIMEOUT_MS);
    +             urlConnection.setUseCaches(false);
    ++            final String userAgent = getCaptivePortalUserAgent(mContext);
    ++            if (userAgent != null) {
    ++               urlConnection.setRequestProperty("User-Agent", userAgent);
    ++            }
    + 
    +             // Time how long it takes to get a response to our request
    +             long requestTimestamp = SystemClock.elapsedRealtime();
    +@@ -755,28 +790,24 @@ public class NetworkMonitor extends StateMachine {
    +             }
    +         }
    +         logValidationProbe(probeTimer.stop(), probeType, httpResponseCode);
    +-        return new CaptivePortalProbeResult(httpResponseCode, redirectUrl);
    ++        return new CaptivePortalProbeResult(httpResponseCode, redirectUrl, url.toString());
    +     }
    + 
    +-    private CaptivePortalProbeResult sendParallelHttpProbes(URL httpsUrl, URL httpUrl) {
    +-        // Number of probes to wait for. We might wait for all of them, but we might also return if
    +-        // only one of them has replied. For example, we immediately return if the HTTP probe finds
    +-        // a captive portal, even if the HTTPS probe is timing out.
    ++    private CaptivePortalProbeResult sendParallelHttpProbes(
    ++            URL httpsUrl, URL httpUrl, URL fallbackUrl) {
    ++        // Number of probes to wait for. If a probe completes with a conclusive answer
    ++        // it shortcuts the latch immediately by forcing the count to 0.
    +         final CountDownLatch latch = new CountDownLatch(2);
    + 
    +-        // Which probe result we're going to use. This doesn't need to be atomic, but it does need
    +-        // to be final because otherwise we can't set it from the ProbeThreads.
    +-        final AtomicReference<CaptivePortalProbeResult> finalResult = new AtomicReference<>();
    +-
    +         final class ProbeThread extends Thread {
    +             private final boolean mIsHttps;
    +-            private volatile CaptivePortalProbeResult mResult;
    ++            private volatile CaptivePortalProbeResult mResult = CaptivePortalProbeResult.FAILED;
    + 
    +             public ProbeThread(boolean isHttps) {
    +                 mIsHttps = isHttps;
    +             }
    + 
    +-            public CaptivePortalProbeResult getResult() {
    ++            public CaptivePortalProbeResult result() {
    +                 return mResult;
    +             }
    + 
    +@@ -788,32 +819,66 @@ public class NetworkMonitor extends StateMachine {
    +                     mResult = sendHttpProbe(httpUrl, ValidationProbeEvent.PROBE_HTTP);
    +                 }
    +                 if ((mIsHttps && mResult.isSuccessful()) || (!mIsHttps && mResult.isPortal())) {
    +-                    // HTTPS succeeded, or HTTP found a portal. Don't wait for the other probe.
    +-                    finalResult.compareAndSet(null, mResult);
    +-                    latch.countDown();
    ++                    // Stop waiting immediately if https succeeds or if http finds a portal.
    ++                    while (latch.getCount() > 0) {
    ++                        latch.countDown();
    ++                    }
    +                 }
    +-                // Signal that one probe has completed. If we've already made a decision, or if this
    +-                // is the second probe, the latch will be at zero and we'll return a result.
    ++                // Signal this probe has completed.
    +                 latch.countDown();
    +             }
    +         }
    + 
    +-        ProbeThread httpsProbe = new ProbeThread(true);
    +-        ProbeThread httpProbe = new ProbeThread(false);
    +-        httpsProbe.start();
    +-        httpProbe.start();
    ++        final ProbeThread httpsProbe = new ProbeThread(true);
    ++        final ProbeThread httpProbe = new ProbeThread(false);
    + 
    +         try {
    +-            latch.await();
    ++            httpsProbe.start();
    ++            httpProbe.start();
    ++            latch.await(PROBE_TIMEOUT_MS, TimeUnit.MILLISECONDS);
    +         } catch (InterruptedException e) {
    +-            validationLog("Error: probe wait interrupted!");
    ++            validationLog("Error: probes wait interrupted!");
    +             return CaptivePortalProbeResult.FAILED;
    +         }
    + 
    +-        // If there was no deciding probe, that means that both probes completed. Return HTTPS.
    +-        finalResult.compareAndSet(null, httpsProbe.getResult());
    ++        final CaptivePortalProbeResult httpsResult = httpsProbe.result();
    ++        final CaptivePortalProbeResult httpResult = httpProbe.result();
    ++
    ++        // Look for a conclusive probe result first.
    ++        if (httpResult.isPortal()) {
    ++            return httpResult;
    ++        }
    ++        // httpsResult.isPortal() is not expected, but check it nonetheless.
    ++        if (httpsResult.isPortal() || httpsResult.isSuccessful()) {
    ++            return httpsResult;
    ++        }
    ++        // If a fallback url is specified, use a fallback probe to try again portal detection.
    ++        if (fallbackUrl != null) {
    ++            CaptivePortalProbeResult result =
    ++                    sendHttpProbe(fallbackUrl, ValidationProbeEvent.PROBE_FALLBACK);
    ++            if (result.isPortal()) {
    ++                return result;
    ++            }
    ++        }
    ++        // Otherwise wait until https probe completes and use its result.
    ++        try {
    ++            httpsProbe.join();
    ++        } catch (InterruptedException e) {
    ++            validationLog("Error: https probe wait interrupted!");
    ++            return CaptivePortalProbeResult.FAILED;
    ++        }
    ++        return httpsProbe.result();
    ++    }
    + 
    +-        return finalResult.get();
    ++    private URL makeURL(String url) {
    ++        if (url != null) {
    ++            try {
    ++                return new URL(url);
    ++            } catch (MalformedURLException e) {
    ++                validationLog("Bad URL: " + url);
    ++            }
    ++        }
    ++        return null;
    +     }
    + 
    +     /**
    +diff --git a/services/core/java/com/android/server/connectivity/Tethering.java b/services/core/java/com/android/server/connectivity/Tethering.java
    +index 927f8f9..da9c547 100644
    +--- a/services/core/java/com/android/server/connectivity/Tethering.java
    ++++ b/services/core/java/com/android/server/connectivity/Tethering.java
    +@@ -33,6 +33,7 @@ import android.content.res.Resources;
    + import android.hardware.usb.UsbManager;
    + import android.net.ConnectivityManager;
    + import android.net.ConnectivityManager.NetworkCallback;
    ++import android.net.INetworkPolicyManager;
    + import android.net.INetworkStatsService;
    + import android.net.LinkProperties;
    + import android.net.Network;
    +@@ -49,6 +50,7 @@ import android.os.INetworkManagementService;
    + import android.os.Looper;
    + import android.os.Message;
    + import android.os.Parcel;
    ++import android.os.RemoteException;
    + import android.os.ResultReceiver;
    + import android.os.SystemProperties;
    + import android.os.UserHandle;
    +@@ -123,6 +125,7 @@ public class Tethering extends BaseNetworkObserver implements IControlsTethering
    + 
    +     private final INetworkManagementService mNMService;
    +     private final INetworkStatsService mStatsService;
    ++    private final INetworkPolicyManager mPolicyManager;
    +     private final Looper mLooper;
    + 
    +     private static class TetherState {
    +@@ -177,10 +180,11 @@ public class Tethering extends BaseNetworkObserver implements IControlsTethering
    +     private boolean mWifiTetherRequested;
    + 
    +     public Tethering(Context context, INetworkManagementService nmService,
    +-            INetworkStatsService statsService) {
    ++            INetworkStatsService statsService, INetworkPolicyManager policyManager) {
    +         mContext = context;
    +         mNMService = nmService;
    +         mStatsService = statsService;
    ++        mPolicyManager = policyManager;
    + 
    +         mPublicSync = new Object();
    + 
    +@@ -401,11 +405,13 @@ public class Tethering extends BaseNetworkObserver implements IControlsTethering
    +         // Check carrier config for entitlement checks
    +         final CarrierConfigManager configManager = (CarrierConfigManager) mContext
    +              .getSystemService(Context.CARRIER_CONFIG_SERVICE);
    +-        boolean isEntitlementCheckRequired = configManager.getConfig().getBoolean(
    +-             CarrierConfigManager.KEY_REQUIRE_ENTITLEMENT_CHECKS_BOOL);
    +-
    +-        if (!isEntitlementCheckRequired) {
    +-            return false;
    ++        if (configManager != null && configManager.getConfig() != null) {
    ++            // we do have a CarrierConfigManager and it has a config.
    ++            boolean isEntitlementCheckRequired = configManager.getConfig().getBoolean(
    ++                    CarrierConfigManager.KEY_REQUIRE_ENTITLEMENT_CHECKS_BOOL);
    ++            if (!isEntitlementCheckRequired) {
    ++                return false;
    ++            }
    +         }
    +         return (provisionApp.length == 2);
    +     }
    +@@ -622,12 +628,9 @@ public class Tethering extends BaseNetworkObserver implements IControlsTethering
    +     }
    + 
    +     public void untetherAll() {
    +-        synchronized (mPublicSync) {
    +-            if (DBG) Log.d(TAG, "Untethering " + mTetherStates.keySet());
    +-            for (int i = 0; i < mTetherStates.size(); i++) {
    +-                untether(mTetherStates.keyAt(i));
    +-            }
    +-        }
    ++        stopTethering(ConnectivityManager.TETHERING_WIFI);
    ++        stopTethering(ConnectivityManager.TETHERING_USB);
    ++        stopTethering(ConnectivityManager.TETHERING_BLUETOOTH);
    +     }
    + 
    +     public int getLastTetherError(String iface) {
    +@@ -1908,6 +1911,15 @@ public class Tethering extends BaseNetworkObserver implements IControlsTethering
    +                     " with error " + error);
    +         }
    + 
    ++        try {
    ++            // Notify that we're tethering (or not) this interface.
    ++            // This is how data saver for instance knows if the user explicitly
    ++            // turned on tethering (thus keeping us from being in data saver mode).
    ++            mPolicyManager.onTetheringChanged(iface, state == IControlsTethering.STATE_TETHERED);
    ++        } catch (RemoteException e) {
    ++            // Not really very much we can do here.
    ++        }
    ++
    +         switch (state) {
    +             case IControlsTethering.STATE_UNAVAILABLE:
    +             case IControlsTethering.STATE_AVAILABLE:
    +diff --git a/services/core/java/com/android/server/connectivity/tethering/IPv6TetheringInterfaceServices.java b/services/core/java/com/android/server/connectivity/tethering/IPv6TetheringInterfaceServices.java
    +index 7525f30..c2c1a8c 100644
    +--- a/services/core/java/com/android/server/connectivity/tethering/IPv6TetheringInterfaceServices.java
    ++++ b/services/core/java/com/android/server/connectivity/tethering/IPv6TetheringInterfaceServices.java
    +@@ -25,6 +25,7 @@ import android.net.NetworkState;
    + import android.net.RouteInfo;
    + import android.net.ip.RouterAdvertisementDaemon;
    + import android.net.ip.RouterAdvertisementDaemon.RaParams;
    ++import android.net.util.NetdService;
    + import android.os.INetworkManagementService;
    + import android.os.ServiceSpecificException;
    + import android.os.RemoteException;
    +@@ -193,7 +194,7 @@ class IPv6TetheringInterfaceServices {
    + 
    +     private void configureLocalDns(
    +             HashSet<Inet6Address> deprecatedDnses, HashSet<Inet6Address> newDnses) {
    +-        INetd netd = getNetdServiceOrNull();
    ++        final INetd netd = NetdService.getInstance();
    +         if (netd == null) {
    +             if (newDnses != null) newDnses.clear();
    +             Log.e(TAG, "No netd service instance available; not setting local IPv6 addresses");
    +@@ -265,18 +266,6 @@ class IPv6TetheringInterfaceServices {
    +         return localRoutes;
    +     }
    + 
    +-    private INetd getNetdServiceOrNull() {
    +-        if (mNMService != null) {
    +-            try {
    +-                return mNMService.getNetdService();
    +-            } catch (RemoteException ignored) {
    +-                // This blocks until netd can be reached, but it can return
    +-                // null during a netd crash.
    +-            }
    +-        }
    +-        return null;
    +-    }
    +-
    +     // Given a prefix like 2001:db8::/64 return 2001:db8::1.
    +     private static Inet6Address getLocalDnsIpFor(IpPrefix localPrefix) {
    +         final byte[] dnsBytes = localPrefix.getRawAddress();
    +diff --git a/services/core/java/com/android/server/content/ContentService.java b/services/core/java/com/android/server/content/ContentService.java
    +index 01b2393..0727629 100644
    +--- a/services/core/java/com/android/server/content/ContentService.java
    ++++ b/services/core/java/com/android/server/content/ContentService.java
    +@@ -482,8 +482,7 @@ public final class ContentService extends IContentService.Stub {
    +             SyncManager syncManager = getSyncManager();
    +             if (syncManager != null) {
    +                 syncManager.scheduleSync(account, userId, uId, authority, extras,
    +-                        0 /* no delay */, 0 /* no delay */,
    +-                        false /* onlyThoseWithUnkownSyncableState */);
    ++                        SyncStorageEngine.AuthorityInfo.UNDEFINED);
    +             }
    +         } finally {
    +             restoreCallingIdentity(identityToken);
    +@@ -547,12 +546,9 @@ public final class ContentService extends IContentService.Stub {
    +                 getSyncManager().updateOrAddPeriodicSync(info, runAtTime,
    +                         flextime, extras);
    +             } else {
    +-                long beforeRuntimeMillis = (flextime) * 1000;
    +-                long runtimeMillis = runAtTime * 1000;
    +                 syncManager.scheduleSync(
    +                         request.getAccount(), userId, callerUid, request.getProvider(), extras,
    +-                        beforeRuntimeMillis, runtimeMillis,
    +-                        false /* onlyThoseWithUnknownSyncableState */);
    ++                        SyncStorageEngine.AuthorityInfo.UNDEFINED);
    +             }
    +         } finally {
    +             restoreCallingIdentity(identityToken);
    +@@ -841,8 +837,8 @@ public final class ContentService extends IContentService.Stub {
    +         try {
    +             SyncManager syncManager = getSyncManager();
    +             if (syncManager != null) {
    +-                return syncManager.getIsSyncable(
    +-                        account, userId, providerName);
    ++                return syncManager.computeSyncable(
    ++                        account, userId, providerName, false);
    +             }
    +         } finally {
    +             restoreCallingIdentity(identityToken);
    +@@ -858,6 +854,8 @@ public final class ContentService extends IContentService.Stub {
    +         mContext.enforceCallingOrSelfPermission(Manifest.permission.WRITE_SYNC_SETTINGS,
    +                 "no permission to write the sync settings");
    + 
    ++        syncable = normalizeSyncable(syncable);
    ++
    +         int userId = UserHandle.getCallingUserId();
    +         long identityToken = clearCallingIdentity();
    +         try {
    +@@ -1160,6 +1158,15 @@ public final class ContentService extends IContentService.Stub {
    +         }
    +     }
    + 
    ++    private static int normalizeSyncable(int syncable) {
    ++        if (syncable > 0) {
    ++            return SyncStorageEngine.AuthorityInfo.SYNCABLE;
    ++        } else if (syncable == 0) {
    ++            return SyncStorageEngine.AuthorityInfo.NOT_SYNCABLE;
    ++        }
    ++        return SyncStorageEngine.AuthorityInfo.UNDEFINED;
    ++    }
    ++
    +     /**
    +      * Hide this class since it is not part of api,
    +      * but current unittest framework requires it to be public
    +diff --git a/services/core/java/com/android/server/content/SyncManager.java b/services/core/java/com/android/server/content/SyncManager.java
    +index 39ddc3a..653d241 100644
    +--- a/services/core/java/com/android/server/content/SyncManager.java
    ++++ b/services/core/java/com/android/server/content/SyncManager.java
    +@@ -19,6 +19,7 @@ package com.android.server.content;
    + import android.accounts.Account;
    + import android.accounts.AccountAndUser;
    + import android.accounts.AccountManager;
    ++import android.accounts.AccountManagerInternal;
    + import android.app.ActivityManager;
    + import android.app.ActivityManagerNative;
    + import android.app.AppGlobals;
    +@@ -47,6 +48,7 @@ import android.content.pm.ApplicationInfo;
    + import android.content.pm.PackageInfo;
    + import android.content.pm.PackageManager;
    + import android.content.pm.PackageManager.NameNotFoundException;
    ++import android.content.pm.PackageManagerInternal;
    + import android.content.pm.ProviderInfo;
    + import android.content.pm.RegisteredServicesCache;
    + import android.content.pm.RegisteredServicesCacheListener;
    +@@ -64,6 +66,7 @@ import android.os.Looper;
    + import android.os.Message;
    + import android.os.Messenger;
    + import android.os.PowerManager;
    ++import android.os.RemoteCallback;
    + import android.os.RemoteException;
    + import android.os.ServiceManager;
    + import android.os.SystemClock;
    +@@ -79,6 +82,7 @@ import android.util.Log;
    + import android.util.Pair;
    + import android.util.Slog;
    + 
    ++import com.android.internal.util.ArrayUtils;
    + import com.android.server.LocalServices;
    + import com.android.server.job.JobSchedulerInternal;
    + import com.google.android.collect.Lists;
    +@@ -133,6 +137,8 @@ import java.util.Set;
    + public class SyncManager {
    +     static final String TAG = "SyncManager";
    + 
    ++    private static final boolean DEBUG_ACCOUNT_ACCESS = false;
    ++
    +     /** Delay a sync due to local changes this long. In milliseconds */
    +     private static final long LOCAL_SYNC_DELAY;
    + 
    +@@ -194,6 +200,11 @@ public class SyncManager {
    +     private static final String HANDLE_SYNC_ALARM_WAKE_LOCK = "SyncManagerHandleSyncAlarm";
    +     private static final String SYNC_LOOP_WAKE_LOCK = "SyncLoopWakeLock";
    + 
    ++
    ++    private static final int SYNC_OP_STATE_VALID = 0;
    ++    private static final int SYNC_OP_STATE_INVALID = 1;
    ++    private static final int SYNC_OP_STATE_INVALID_NO_ACCOUNT_ACCESS = 2;
    ++
    +     private Context mContext;
    + 
    +     private static final AccountAndUser[] INITIAL_ACCOUNTS_ARRAY = new AccountAndUser[0];
    +@@ -310,6 +321,12 @@ public class SyncManager {
    + 
    +     private final UserManager mUserManager;
    + 
    ++    private final AccountManager mAccountManager;
    ++
    ++    private final AccountManagerInternal mAccountManagerInternal;
    ++
    ++    private final PackageManagerInternal mPackageManagerInternal;
    ++
    +     private List<UserInfo> getAllUsers() {
    +         return mUserManager.getUsers();
    +     }
    +@@ -490,9 +507,7 @@ public class SyncManager {
    +             @Override
    +             public void onSyncRequest(SyncStorageEngine.EndPoint info, int reason, Bundle extras) {
    +                 scheduleSync(info.account, info.userId, reason, info.provider, extras,
    +-                        0 /* no flexMillis */,
    +-                        0 /* run immediately */,
    +-                        false);
    ++                        AuthorityInfo.UNDEFINED);
    +             }
    +         });
    + 
    +@@ -522,8 +537,7 @@ public class SyncManager {
    +                 if (!removed) {
    +                     scheduleSync(null, UserHandle.USER_ALL,
    +                             SyncOperation.REASON_SERVICE_CHANGED,
    +-                            type.authority, null, 0 /* no delay */, 0 /* no delay */,
    +-                            false /* onlyThoseWithUnkownSyncableState */);
    ++                            type.authority, null, AuthorityInfo.UNDEFINED);
    +                 }
    +             }
    +         }, mSyncHandler);
    +@@ -562,6 +576,19 @@ public class SyncManager {
    +         }
    +         mPowerManager = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
    +         mUserManager = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
    ++        mAccountManager = (AccountManager) mContext.getSystemService(Context.ACCOUNT_SERVICE);
    ++        mAccountManagerInternal = LocalServices.getService(AccountManagerInternal.class);
    ++        mPackageManagerInternal = LocalServices.getService(PackageManagerInternal.class);
    ++
    ++        mAccountManagerInternal.addOnAppPermissionChangeListener((Account account, int uid) -> {
    ++            // If the UID gained access to the account kick-off syncs lacking account access
    ++            if (mAccountManagerInternal.hasAccountAccess(account, uid)) {
    ++                scheduleSync(account, UserHandle.getUserId(uid),
    ++                        SyncOperation.REASON_ACCOUNTS_UPDATED,
    ++                        null, null, AuthorityInfo.SYNCABLE_NO_ACCOUNT_ACCESS);
    ++            }
    ++        });
    ++
    +         mBatteryStats = IBatteryStats.Stub.asInterface(ServiceManager.getService(
    +                 BatteryStats.SERVICE_NAME));
    + 
    +@@ -631,6 +658,37 @@ public class SyncManager {
    +                 mContext.startService(startServiceIntent);
    +             }
    +         });
    ++
    ++        // Sync adapters were able to access the synced account without the accounts
    ++        // permission which circumvents our permission model. Therefore, we require
    ++        // sync adapters that don't have access to the account to get user consent.
    ++        // This can be noisy, therefore we will white-list sync adapters installed
    ++        // before we started checking for account access because they already know
    ++        // the account (they run before) which is the genie is out of the bottle.
    ++        whiteListExistingSyncAdaptersIfNeeded();
    ++    }
    ++
    ++    private void whiteListExistingSyncAdaptersIfNeeded() {
    ++        if (!mSyncStorageEngine.shouldGrantSyncAdaptersAccountAccess()) {
    ++            return;
    ++        }
    ++        List<UserInfo> users = mUserManager.getUsers(true);
    ++        final int userCount = users.size();
    ++        for (int i = 0; i < userCount; i++) {
    ++            UserHandle userHandle = users.get(i).getUserHandle();
    ++            final int userId = userHandle.getIdentifier();
    ++            for (RegisteredServicesCache.ServiceInfo<SyncAdapterType> service
    ++                    : mSyncAdapters.getAllServices(userId)) {
    ++                String packageName = service.componentName.getPackageName();
    ++                for (Account account : mAccountManager.getAccountsByTypeAsUser(
    ++                        service.type.accountType, userHandle)) {
    ++                    if (!canAccessAccount(account, packageName, userId)) {
    ++                        mAccountManager.updateAppPermission(account,
    ++                                AccountManager.ACCOUNT_ACCESS_TOKEN_TYPE, service.uid, true);
    ++                    }
    ++                }
    ++            }
    ++        }
    +     }
    + 
    +     private boolean isDeviceProvisioned() {
    +@@ -655,7 +713,7 @@ public class SyncManager {
    +         return mSyncStorageEngine;
    +     }
    + 
    +-    public int getIsSyncable(Account account, int userId, String providerName) {
    ++    private int getIsSyncable(Account account, int userId, String providerName) {
    +         int isSyncable = mSyncStorageEngine.getIsSyncable(account, userId, providerName);
    +         UserInfo userInfo = UserManager.get(mContext).getUserInfo(userId);
    + 
    +@@ -666,22 +724,22 @@ public class SyncManager {
    +         RegisteredServicesCache.ServiceInfo<SyncAdapterType> syncAdapterInfo =
    +                 mSyncAdapters.getServiceInfo(
    +                         SyncAdapterType.newKey(providerName, account.type), userId);
    +-        if (syncAdapterInfo == null) return isSyncable;
    ++        if (syncAdapterInfo == null) return AuthorityInfo.NOT_SYNCABLE;
    + 
    +         PackageInfo pInfo = null;
    +         try {
    +             pInfo = AppGlobals.getPackageManager().getPackageInfo(
    +                     syncAdapterInfo.componentName.getPackageName(), 0, userId);
    +-            if (pInfo == null) return isSyncable;
    ++            if (pInfo == null) return AuthorityInfo.NOT_SYNCABLE;
    +         } catch (RemoteException re) {
    +             // Shouldn't happen.
    +-            return isSyncable;
    ++            return AuthorityInfo.NOT_SYNCABLE;
    +         }
    +         if (pInfo.restrictedAccountType != null
    +                 && pInfo.restrictedAccountType.equals(account.type)) {
    +             return isSyncable;
    +         } else {
    +-            return 0;
    ++            return AuthorityInfo.NOT_SYNCABLE;
    +         }
    +     }
    + 
    +@@ -733,13 +791,21 @@ public class SyncManager {
    +      * @param extras a Map of SyncAdapter-specific information to control
    +      *          syncs of a specific provider. Can be null. Is ignored
    +      *          if the url is null.
    +-     * @param beforeRuntimeMillis milliseconds before runtimeMillis that this sync can run.
    +-     * @param runtimeMillis maximum milliseconds in the future to wait before performing sync.
    +-     * @param onlyThoseWithUnkownSyncableState Only sync authorities that have unknown state.
    ++     * @param targetSyncState Only sync authorities that have the specified sync state.
    ++     *           Use {@link AuthorityInfo#UNDEFINED} to sync all authorities.
    +      */
    +     public void scheduleSync(Account requestedAccount, int userId, int reason,
    +-            String requestedAuthority, Bundle extras, long beforeRuntimeMillis,
    +-            long runtimeMillis, boolean onlyThoseWithUnkownSyncableState) {
    ++                             String requestedAuthority, Bundle extras, int targetSyncState) {
    ++        scheduleSync(requestedAccount, userId, reason, requestedAuthority, extras, targetSyncState,
    ++                0 /* min delay */);
    ++    }
    ++
    ++    /**
    ++     * @param minDelayMillis The sync can't land before this delay expires.
    ++     */
    ++    private void scheduleSync(Account requestedAccount, int userId, int reason,
    ++                             String requestedAuthority, Bundle extras, int targetSyncState,
    ++                             final long minDelayMillis) {
    +         final boolean isLoggable = Log.isLoggable(TAG, Log.VERBOSE);
    +         if (extras == null) {
    +             extras = new Bundle();
    +@@ -749,17 +815,27 @@ public class SyncManager {
    +                     + requestedAuthority);
    +         }
    + 
    +-        AccountAndUser[] accounts;
    +-        if (requestedAccount != null && userId != UserHandle.USER_ALL) {
    +-            accounts = new AccountAndUser[] { new AccountAndUser(requestedAccount, userId) };
    ++        AccountAndUser[] accounts = null;
    ++        if (requestedAccount != null) {
    ++            if (userId != UserHandle.USER_ALL) {
    ++                accounts = new AccountAndUser[]{new AccountAndUser(requestedAccount, userId)};
    ++            } else {
    ++                for (AccountAndUser runningAccount : mRunningAccounts) {
    ++                    if (requestedAccount.equals(runningAccount.account)) {
    ++                        accounts = ArrayUtils.appendElement(AccountAndUser.class,
    ++                                accounts, runningAccount);
    ++                    }
    ++                }
    ++            }
    +         } else {
    +             accounts = mRunningAccounts;
    +-            if (accounts.length == 0) {
    +-                if (isLoggable) {
    +-                    Slog.v(TAG, "scheduleSync: no accounts configured, dropping");
    +-                }
    +-                return;
    ++        }
    ++
    ++        if (ArrayUtils.isEmpty(accounts)) {
    ++            if (isLoggable) {
    ++                Slog.v(TAG, "scheduleSync: no accounts configured, dropping");
    +             }
    ++            return;
    +         }
    + 
    +         final boolean uploadOnly = extras.getBoolean(ContentResolver.SYNC_EXTRAS_UPLOAD, false);
    +@@ -808,29 +884,45 @@ public class SyncManager {
    +             }
    + 
    +             for (String authority : syncableAuthorities) {
    +-                int isSyncable = getIsSyncable(account.account, account.userId,
    +-                        authority);
    ++                int isSyncable = computeSyncable(account.account, account.userId, authority);
    ++
    +                 if (isSyncable == AuthorityInfo.NOT_SYNCABLE) {
    +                     continue;
    +                 }
    +-                final RegisteredServicesCache.ServiceInfo<SyncAdapterType> syncAdapterInfo;
    +-                syncAdapterInfo = mSyncAdapters.getServiceInfo(
    +-                        SyncAdapterType.newKey(authority, account.account.type), account.userId);
    ++
    ++                final RegisteredServicesCache.ServiceInfo<SyncAdapterType> syncAdapterInfo =
    ++                        mSyncAdapters.getServiceInfo(SyncAdapterType.newKey(authority,
    ++                                account.account.type), account.userId);
    +                 if (syncAdapterInfo == null) {
    +                     continue;
    +                 }
    ++
    +                 final int owningUid = syncAdapterInfo.uid;
    +-                final String owningPackage = syncAdapterInfo.componentName.getPackageName();
    +-                try {
    +-                    if (ActivityManagerNative.getDefault().getAppStartMode(owningUid,
    +-                            owningPackage) == ActivityManager.APP_START_MODE_DISABLED) {
    +-                        Slog.w(TAG, "Not scheduling job " + syncAdapterInfo.uid + ":"
    +-                                + syncAdapterInfo.componentName
    +-                                + " -- package not allowed to start");
    ++
    ++                if (isSyncable == AuthorityInfo.SYNCABLE_NO_ACCOUNT_ACCESS) {
    ++                    if (isLoggable) {
    ++                        Slog.v(TAG, "    Not scheduling sync operation: "
    ++                                + "isSyncable == SYNCABLE_NO_ACCOUNT_ACCESS");
    ++                    }
    ++                    Bundle finalExtras = new Bundle(extras);
    ++                    String packageName = syncAdapterInfo.componentName.getPackageName();
    ++                    // If the app did not run and has no account access, done
    ++                    if (!mPackageManagerInternal.wasPackageEverLaunched(packageName, userId)) {
    +                         continue;
    +                     }
    +-                } catch (RemoteException e) {
    ++                    mAccountManagerInternal.requestAccountAccess(account.account,
    ++                            packageName, userId,
    ++                            new RemoteCallback((Bundle result) -> {
    ++                                if (result != null
    ++                                        && result.getBoolean(AccountManager.KEY_BOOLEAN_RESULT)) {
    ++                                    scheduleSync(account.account, userId, reason, authority,
    ++                                            finalExtras, targetSyncState, minDelayMillis);
    ++                                }
    ++                            }
    ++                        ));
    ++                    continue;
    +                 }
    ++
    +                 final boolean allowParallelSyncs = syncAdapterInfo.type.allowParallelSyncs();
    +                 final boolean isAlwaysSyncable = syncAdapterInfo.type.isAlwaysSyncable();
    +                 if (isSyncable < 0 && isAlwaysSyncable) {
    +@@ -838,9 +930,11 @@ public class SyncManager {
    +                             account.account, account.userId, authority, AuthorityInfo.SYNCABLE);
    +                     isSyncable = AuthorityInfo.SYNCABLE;
    +                 }
    +-                if (onlyThoseWithUnkownSyncableState && isSyncable >= 0) {
    ++
    ++                if (targetSyncState != AuthorityInfo.UNDEFINED && targetSyncState != isSyncable) {
    +                     continue;
    +                 }
    ++
    +                 if (!syncAdapterInfo.type.supportsUploading() && uploadOnly) {
    +                     continue;
    +                 }
    +@@ -863,7 +957,10 @@ public class SyncManager {
    +                                 account.account, authority, account.userId);
    +                 long delayUntil =
    +                         mSyncStorageEngine.getDelayUntilTime(info);
    +-                if (isSyncable < 0) {
    ++
    ++                final String owningPackage = syncAdapterInfo.componentName.getPackageName();
    ++
    ++                if (isSyncable == AuthorityInfo.NOT_INITIALIZED) {
    +                     // Initialisation sync.
    +                     Bundle newExtras = new Bundle();
    +                     newExtras.putBoolean(ContentResolver.SYNC_EXTRAS_INITIALIZE, true);
    +@@ -880,15 +977,14 @@ public class SyncManager {
    +                     postScheduleSyncMessage(
    +                             new SyncOperation(account.account, account.userId,
    +                                     owningUid, owningPackage, reason, source,
    +-                                    authority, newExtras, allowParallelSyncs)
    ++                                    authority, newExtras, allowParallelSyncs),
    ++                            minDelayMillis
    +                     );
    +-                }
    +-                if (!onlyThoseWithUnkownSyncableState) {
    ++                } else if (targetSyncState == AuthorityInfo.UNDEFINED
    ++                        || targetSyncState == isSyncable) {
    +                     if (isLoggable) {
    +                         Slog.v(TAG, "scheduleSync:"
    +                                 + " delay until " + delayUntil
    +-                                + " run by " + runtimeMillis
    +-                                + " flexMillis " + beforeRuntimeMillis
    +                                 + ", source " + source
    +                                 + ", account " + account
    +                                 + ", authority " + authority
    +@@ -897,13 +993,69 @@ public class SyncManager {
    +                     postScheduleSyncMessage(
    +                             new SyncOperation(account.account, account.userId,
    +                                     owningUid, owningPackage, reason, source,
    +-                                    authority, extras, allowParallelSyncs)
    ++                                    authority, extras, allowParallelSyncs),
    ++                            minDelayMillis
    +                     );
    +                 }
    +             }
    +         }
    +     }
    + 
    ++    private int computeSyncable(Account account, int userId, String authority) {
    ++        return computeSyncable(account, userId, authority, true);
    ++    }
    ++
    ++    public int computeSyncable(Account account, int userId, String authority,
    ++            boolean checkAccountAccess) {
    ++        final int status = getIsSyncable(account, userId, authority);
    ++        if (status == AuthorityInfo.NOT_SYNCABLE) {
    ++            return AuthorityInfo.NOT_SYNCABLE;
    ++        }
    ++        final SyncAdapterType type = SyncAdapterType.newKey(authority, account.type);
    ++        final RegisteredServicesCache.ServiceInfo<SyncAdapterType> syncAdapterInfo =
    ++                mSyncAdapters.getServiceInfo(type, userId);
    ++        if (syncAdapterInfo == null) {
    ++            return AuthorityInfo.NOT_SYNCABLE;
    ++        }
    ++        final int owningUid = syncAdapterInfo.uid;
    ++        final String owningPackage = syncAdapterInfo.componentName.getPackageName();
    ++        try {
    ++            if (ActivityManagerNative.getDefault().getAppStartMode(owningUid,
    ++                    owningPackage) == ActivityManager.APP_START_MODE_DISABLED) {
    ++                Slog.w(TAG, "Not scheduling job " + syncAdapterInfo.uid + ":"
    ++                        + syncAdapterInfo.componentName
    ++                        + " -- package not allowed to start");
    ++                return AuthorityInfo.NOT_SYNCABLE;
    ++            }
    ++        } catch (RemoteException e) {
    ++            /* ignore - local call */
    ++        }
    ++        if (checkAccountAccess && !canAccessAccount(account, owningPackage, owningUid)) {
    ++            Log.w(TAG, "Access to " + account + " denied for package "
    ++                    + owningPackage + " in UID " + syncAdapterInfo.uid);
    ++            return AuthorityInfo.SYNCABLE_NO_ACCOUNT_ACCESS;
    ++        }
    ++
    ++        return status;
    ++    }
    ++
    ++    private boolean canAccessAccount(Account account, String packageName, int uid) {
    ++        if (mAccountManager.hasAccountAccess(account, packageName,
    ++                UserHandle.getUserHandleForUid(uid))) {
    ++            return true;
    ++        }
    ++        // We relax the account access rule to also include the system apps as
    ++        // they are trusted and we want to minimize the cases where the user
    ++        // involvement is required to grant access to the synced account.
    ++        try {
    ++            mContext.getPackageManager().getApplicationInfoAsUser(packageName,
    ++                    PackageManager.MATCH_SYSTEM_ONLY, UserHandle.getUserId(uid));
    ++            return true;
    ++        } catch (NameNotFoundException e) {
    ++            return false;
    ++        }
    ++    }
    ++
    +     private void removeSyncsForAuthority(EndPoint info) {
    +         verifyJobScheduler();
    +         List<SyncOperation> ops = getAllPendingSyncs();
    +@@ -953,16 +1105,14 @@ public class SyncManager {
    +     }
    + 
    +     /**
    +-     * Schedule sync based on local changes to a provider. Occurs within interval
    +-     * [LOCAL_SYNC_DELAY, 2*LOCAL_SYNC_DELAY].
    ++     * Schedule sync based on local changes to a provider. We wait for at least LOCAL_SYNC_DELAY
    ++     * ms to batch syncs.
    +      */
    +     public void scheduleLocalSync(Account account, int userId, int reason, String authority) {
    +         final Bundle extras = new Bundle();
    +         extras.putBoolean(ContentResolver.SYNC_EXTRAS_UPLOAD, true);
    +         scheduleSync(account, userId, reason, authority, extras,
    +-                LOCAL_SYNC_DELAY /* earliest run time */,
    +-                2 * LOCAL_SYNC_DELAY /* latest sync time. */,
    +-                false /* onlyThoseWithUnkownSyncableState */);
    ++                AuthorityInfo.UNDEFINED, LOCAL_SYNC_DELAY);
    +     }
    + 
    +     public SyncAdapterType[] getSyncAdapterTypes(int userId) {
    +@@ -1019,9 +1169,10 @@ public class SyncManager {
    +         mSyncHandler.sendMessageDelayed(monitorMessage, SYNC_MONITOR_WINDOW_LENGTH_MILLIS);
    +     }
    + 
    +-    private void postScheduleSyncMessage(SyncOperation syncOperation) {
    +-        mSyncHandler.obtainMessage(mSyncHandler.MESSAGE_SCHEDULE_SYNC, syncOperation)
    +-                .sendToTarget();
    ++    private void postScheduleSyncMessage(SyncOperation syncOperation, long minDelayMillis) {
    ++        ScheduleSyncMessagePayload payload =
    ++                new ScheduleSyncMessagePayload(syncOperation, minDelayMillis);
    ++        mSyncHandler.obtainMessage(mSyncHandler.MESSAGE_SCHEDULE_SYNC, payload).sendToTarget();
    +     }
    + 
    +     /**
    +@@ -1061,6 +1212,16 @@ public class SyncManager {
    +         }
    +     }
    + 
    ++    private static class ScheduleSyncMessagePayload {
    ++        final SyncOperation syncOperation;
    ++        final long minDelayMillis;
    ++
    ++        ScheduleSyncMessagePayload(SyncOperation syncOperation, long minDelayMillis) {
    ++            this.syncOperation = syncOperation;
    ++            this.minDelayMillis = minDelayMillis;
    ++        }
    ++    }
    ++
    +     private void clearBackoffSetting(EndPoint target) {
    +         Pair<Long, Long> backoff = mSyncStorageEngine.getBackoff(target);
    +         if (backoff != null && backoff.first == SyncStorageEngine.NOT_IN_BACKOFF_MODE &&
    +@@ -1129,7 +1290,7 @@ public class SyncManager {
    +             if (!op.isPeriodic && op.target.matchesSpec(target)) {
    +                 count++;
    +                 getJobScheduler().cancel(op.jobId);
    +-                postScheduleSyncMessage(op);
    ++                postScheduleSyncMessage(op, 0 /* min delay */);
    +             }
    +         }
    +         if (Log.isLoggable(TAG, Log.VERBOSE)) {
    +@@ -1421,8 +1582,7 @@ public class SyncManager {
    +                 mContext.getOpPackageName());
    +         for (Account account : accounts) {
    +             scheduleSync(account, userId, SyncOperation.REASON_USER_START, null, null,
    +-                    0 /* no delay */, 0 /* No flexMillis */,
    +-                    true /* onlyThoseWithUnknownSyncableState */);
    ++                    AuthorityInfo.NOT_INITIALIZED);
    +         }
    +     }
    + 
    +@@ -2285,8 +2445,10 @@ public class SyncManager {
    +                 mDataConnectionIsConnected = readDataConnectionState();
    +                 switch (msg.what) {
    +                     case MESSAGE_SCHEDULE_SYNC:
    +-                        SyncOperation op = (SyncOperation) msg.obj;
    +-                        scheduleSyncOperationH(op);
    ++                        ScheduleSyncMessagePayload syncPayload =
    ++                                (ScheduleSyncMessagePayload) msg.obj;
    ++                        SyncOperation op = syncPayload.syncOperation;
    ++                        scheduleSyncOperationH(op, syncPayload.minDelayMillis);
    +                         break;
    + 
    +                     case MESSAGE_START_SYNC:
    +@@ -2530,13 +2692,18 @@ public class SyncManager {
    +                 }
    +             }
    + 
    +-            if (isOperationValid(op)) {
    +-                if (!dispatchSyncOperation(op)) {
    ++            final int syncOpState = computeSyncOpState(op);
    ++            switch (syncOpState) {
    ++                case SYNC_OP_STATE_INVALID_NO_ACCOUNT_ACCESS:
    ++                case SYNC_OP_STATE_INVALID: {
    +                     mSyncJobService.callJobFinished(op.jobId, false);
    +-                }
    +-            } else {
    ++                } return;
    ++            }
    ++
    ++            if (!dispatchSyncOperation(op)) {
    +                 mSyncJobService.callJobFinished(op.jobId, false);
    +             }
    ++
    +             setAuthorityPendingState(op.target);
    +         }
    + 
    +@@ -2596,8 +2763,8 @@ public class SyncManager {
    + 
    +             if (syncTargets != null) {
    +                 scheduleSync(syncTargets.account, syncTargets.userId,
    +-                        SyncOperation.REASON_ACCOUNTS_UPDATED, syncTargets.provider, null, 0, 0,
    +-                        true);
    ++                        SyncOperation.REASON_ACCOUNTS_UPDATED, syncTargets.provider,
    ++                null, AuthorityInfo.NOT_INITIALIZED);
    +             }
    +         }
    + 
    +@@ -2665,6 +2832,31 @@ public class SyncManager {
    +                     SyncStorageEngine.SOURCE_PERIODIC, extras,
    +                     syncAdapterInfo.type.allowParallelSyncs(), true, SyncOperation.NO_JOB_ID,
    +                     pollFrequencyMillis, flexMillis);
    ++
    ++            final int syncOpState = computeSyncOpState(op);
    ++            switch (syncOpState) {
    ++                case SYNC_OP_STATE_INVALID_NO_ACCOUNT_ACCESS: {
    ++                    String packageName = op.owningPackage;
    ++                    final int userId = UserHandle.getUserId(op.owningUid);
    ++                    // If the app did not run and has no account access, done
    ++                    if (!mPackageManagerInternal.wasPackageEverLaunched(packageName, userId)) {
    ++                        return;
    ++                    }
    ++                    mAccountManagerInternal.requestAccountAccess(op.target.account,
    ++                            packageName, userId, new RemoteCallback((Bundle result) -> {
    ++                                if (result != null
    ++                                        && result.getBoolean(AccountManager.KEY_BOOLEAN_RESULT)) {
    ++                                    updateOrAddPeriodicSync(target, pollFrequency, flex, extras);
    ++                                }
    ++                            }
    ++                        ));
    ++                } return;
    ++
    ++                case SYNC_OP_STATE_INVALID: {
    ++                    return;
    ++                }
    ++            }
    ++
    +             scheduleSyncOperationH(op);
    +             mSyncStorageEngine.reportChange(ContentResolver.SYNC_OBSERVER_TYPE_SETTINGS);
    +         }
    +@@ -2725,29 +2917,38 @@ public class SyncManager {
    +         /**
    +          * Determine if a sync is no longer valid and should be dropped.
    +          */
    +-        private boolean isOperationValid(SyncOperation op) {
    ++        private int computeSyncOpState(SyncOperation op) {
    +             final boolean isLoggable = Log.isLoggable(TAG, Log.VERBOSE);
    +             int state;
    +             final EndPoint target = op.target;
    +-            boolean syncEnabled = mSyncStorageEngine.getMasterSyncAutomatically(target.userId);
    ++
    +             // Drop the sync if the account of this operation no longer exists.
    +             AccountAndUser[] accounts = mRunningAccounts;
    +             if (!containsAccountAndUser(accounts, target.account, target.userId)) {
    +                 if (isLoggable) {
    +                     Slog.v(TAG, "    Dropping sync operation: account doesn't exist.");
    +                 }
    +-                return false;
    ++                return SYNC_OP_STATE_INVALID;
    +             }
    +             // Drop this sync request if it isn't syncable.
    +-            state = getIsSyncable(target.account, target.userId, target.provider);
    +-            if (state == 0) {
    ++            state = computeSyncable(target.account, target.userId, target.provider);
    ++            if (state == AuthorityInfo.SYNCABLE_NO_ACCOUNT_ACCESS) {
    +                 if (isLoggable) {
    +-                    Slog.v(TAG, "    Dropping sync operation: isSyncable == 0.");
    ++                    Slog.v(TAG, "    Dropping sync operation: "
    ++                            + "isSyncable == SYNCABLE_NO_ACCOUNT_ACCESS");
    +                 }
    +-                return false;
    ++                return SYNC_OP_STATE_INVALID_NO_ACCOUNT_ACCESS;
    ++            }
    ++            if (state == AuthorityInfo.NOT_SYNCABLE) {
    ++                if (isLoggable) {
    ++                    Slog.v(TAG, "    Dropping sync operation: isSyncable == NOT_SYNCABLE");
    ++                }
    ++                return SYNC_OP_STATE_INVALID;
    +             }
    +-            syncEnabled = syncEnabled && mSyncStorageEngine.getSyncAutomatically(
    +-                    target.account, target.userId, target.provider);
    ++
    ++            final boolean syncEnabled = mSyncStorageEngine.getMasterSyncAutomatically(target.userId)
    ++                    && mSyncStorageEngine.getSyncAutomatically(target.account,
    ++                            target.userId, target.provider);
    + 
    +             // We ignore system settings that specify the sync is invalid if:
    +             // 1) It's manual - we try it anyway. When/if it fails it will be rescheduled.
    +@@ -2760,9 +2961,9 @@ public class SyncManager {
    +                 if (isLoggable) {
    +                     Slog.v(TAG, "    Dropping sync operation: disallowed by settings/network.");
    +                 }
    +-                return false;
    ++                return SYNC_OP_STATE_INVALID;
    +             }
    +-            return true;
    ++            return SYNC_OP_STATE_VALID;
    +         }
    + 
    +         private boolean dispatchSyncOperation(SyncOperation op) {
    +@@ -2930,7 +3131,8 @@ public class SyncManager {
    +                         maybeRescheduleSync(syncResult, syncOperation);
    +                     } else {
    +                         // create a normal sync instance that will respect adapter backoffs
    +-                        postScheduleSyncMessage(syncOperation.createOneTimeSyncOperation());
    ++                        postScheduleSyncMessage(syncOperation.createOneTimeSyncOperation(),
    ++                                0 /* min delay */);
    +                     }
    +                     historyMessage = ContentResolver.syncErrorToString(
    +                             syncResultToErrorNumber(syncResult));
    +diff --git a/services/core/java/com/android/server/content/SyncStorageEngine.java b/services/core/java/com/android/server/content/SyncStorageEngine.java
    +index bc3fc6a..069ae73 100644
    +--- a/services/core/java/com/android/server/content/SyncStorageEngine.java
    ++++ b/services/core/java/com/android/server/content/SyncStorageEngine.java
    +@@ -137,7 +137,7 @@ public class SyncStorageEngine extends Handler {
    +     private static final boolean SYNC_ENABLED_DEFAULT = false;
    + 
    +     // the version of the accounts xml file format
    +-    private static final int ACCOUNTS_VERSION = 2;
    ++    private static final int ACCOUNTS_VERSION = 3;
    + 
    +     private static HashMap<String, String> sAuthorityRenames;
    +     private static PeriodicSyncAddedListener mPeriodicSyncAddedListener;
    +@@ -211,6 +211,12 @@ public class SyncStorageEngine extends Handler {
    + 
    +     public static class AuthorityInfo {
    +         // Legal values of getIsSyncable
    ++
    ++        /**
    ++         * The syncable state is undefined.
    ++         */
    ++        public static final int UNDEFINED = -2;
    ++
    +         /**
    +          * Default state for a newly installed adapter. An uninitialized adapter will receive an
    +          * initialization sync which are governed by a different set of rules to that of regular
    +@@ -234,6 +240,12 @@ public class SyncStorageEngine extends Handler {
    +          */
    +         public static final int SYNCABLE_NOT_INITIALIZED = 2;
    + 
    ++        /**
    ++         * The adapter is syncable but does not have access to the synced account and needs a
    ++         * user access approval.
    ++         */
    ++        public static final int SYNCABLE_NO_ACCOUNT_ACCESS = 3;
    ++
    +         final EndPoint target;
    +         final int ident;
    +         boolean enabled;
    +@@ -402,6 +414,8 @@ public class SyncStorageEngine extends Handler {
    +     private OnSyncRequestListener mSyncRequestListener;
    +     private OnAuthorityRemovedListener mAuthorityRemovedListener;
    + 
    ++    private boolean mGrantSyncAdaptersAccountAccess;
    ++
    +     private SyncStorageEngine(Context context, File dataDir) {
    +         mContext = context;
    +         sSyncStorageEngine = this;
    +@@ -1404,6 +1418,10 @@ public class SyncStorageEngine extends Handler {
    +         }
    +     }
    + 
    ++    public boolean shouldGrantSyncAdaptersAccountAccess() {
    ++        return mGrantSyncAdaptersAccountAccess;
    ++    }
    ++
    +     /**
    +      * public for testing
    +      */
    +@@ -1458,6 +1476,11 @@ public class SyncStorageEngine extends Handler {
    +                 } catch (NumberFormatException e) {
    +                     version = 0;
    +                 }
    ++
    ++                if (version < 3) {
    ++                    mGrantSyncAdaptersAccountAccess = true;
    ++                }
    ++
    +                 String nextIdString = parser.getAttributeValue(null, XML_ATTR_NEXT_AUTHORITY_ID);
    +                 try {
    +                     int id = (nextIdString == null) ? 0 : Integer.parseInt(nextIdString);
    +diff --git a/services/core/java/com/android/server/display/DisplayManagerService.java b/services/core/java/com/android/server/display/DisplayManagerService.java
    +index 0abd2e7..971989b 100644
    +--- a/services/core/java/com/android/server/display/DisplayManagerService.java
    ++++ b/services/core/java/com/android/server/display/DisplayManagerService.java
    +@@ -1402,6 +1402,9 @@ public final class DisplayManagerService extends SystemService {
    +                 throw new IllegalArgumentException("width, height, and densityDpi must be "
    +                         + "greater than 0");
    +             }
    ++            if (surface != null && surface.isSingleBuffered()) {
    ++                throw new IllegalArgumentException("Surface can't be single-buffered");
    ++            }
    + 
    +             if ((flags & DisplayManager.VIRTUAL_DISPLAY_FLAG_PUBLIC) != 0) {
    +                 flags |= DisplayManager.VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR;
    +@@ -1460,6 +1463,9 @@ public final class DisplayManagerService extends SystemService {
    + 
    +         @Override // Binder call
    +         public void setVirtualDisplaySurface(IVirtualDisplayCallback callback, Surface surface) {
    ++            if (surface != null && surface.isSingleBuffered()) {
    ++                throw new IllegalArgumentException("Surface can't be single-buffered");
    ++            }
    +             final long token = Binder.clearCallingIdentity();
    +             try {
    +                 setVirtualDisplaySurfaceInternal(callback.asBinder(), surface);
    +diff --git a/services/core/java/com/android/server/display/NightDisplayService.java b/services/core/java/com/android/server/display/NightDisplayService.java
    +index 07fa2ce..0ec48b9 100644
    +--- a/services/core/java/com/android/server/display/NightDisplayService.java
    ++++ b/services/core/java/com/android/server/display/NightDisplayService.java
    +@@ -33,8 +33,11 @@ import android.net.Uri;
    + import android.opengl.Matrix;
    + import android.os.Handler;
    + import android.os.Looper;
    ++import android.os.RemoteException;
    + import android.os.UserHandle;
    + import android.provider.Settings.Secure;
    ++import android.service.vr.IVrManager;
    ++import android.service.vr.IVrStateCallbacks;
    + import android.util.MathUtils;
    + import android.util.Slog;
    + import android.view.animation.AnimationUtils;
    +@@ -44,7 +47,9 @@ import com.android.server.SystemService;
    + import com.android.server.twilight.TwilightListener;
    + import com.android.server.twilight.TwilightManager;
    + import com.android.server.twilight.TwilightState;
    ++import com.android.server.vr.VrManagerService;
    + 
    ++import java.util.concurrent.atomic.AtomicBoolean;
    + import java.util.Calendar;
    + import java.util.TimeZone;
    + 
    +@@ -83,6 +88,31 @@ public final class NightDisplayService extends SystemService
    +     private static final ColorMatrixEvaluator COLOR_MATRIX_EVALUATOR = new ColorMatrixEvaluator();
    + 
    +     private final Handler mHandler;
    ++    private final AtomicBoolean mIgnoreAllColorMatrixChanges = new AtomicBoolean();
    ++    private final IVrStateCallbacks mVrStateCallbacks = new IVrStateCallbacks.Stub() {
    ++        @Override
    ++        public void onVrStateChanged(final boolean enabled) {
    ++            // Turn off all night mode display stuff while device is in VR mode.
    ++            mIgnoreAllColorMatrixChanges.set(enabled);
    ++            mHandler.post(new Runnable() {
    ++                @Override
    ++                public void run() {
    ++                    // Cancel in-progress animations
    ++                    if (mColorMatrixAnimator != null) {
    ++                        mColorMatrixAnimator.cancel();
    ++                    }
    ++
    ++                    final DisplayTransformManager dtm =
    ++                            getLocalService(DisplayTransformManager.class);
    ++                    if (enabled) {
    ++                        dtm.setColorMatrix(LEVEL_COLOR_MATRIX_NIGHT_DISPLAY, MATRIX_IDENTITY);
    ++                    } else if (mController.isActivated()) {
    ++                        dtm.setColorMatrix(LEVEL_COLOR_MATRIX_NIGHT_DISPLAY, MATRIX_NIGHT);
    ++                    }
    ++                }
    ++            });
    ++        }
    ++    };
    + 
    +     private int mCurrentUser = UserHandle.USER_NULL;
    +     private ContentObserver mUserSetupObserver;
    +@@ -105,7 +135,17 @@ public final class NightDisplayService extends SystemService
    + 
    +     @Override
    +     public void onBootPhase(int phase) {
    +-        if (phase == PHASE_BOOT_COMPLETED) {
    ++        if (phase == PHASE_SYSTEM_SERVICES_READY) {
    ++            IVrManager vrManager =
    ++                    (IVrManager) getBinderService(VrManagerService.VR_MANAGER_BINDER_SERVICE);
    ++            if (vrManager != null) {
    ++                try {
    ++                    vrManager.registerListener(mVrStateCallbacks);
    ++                } catch (RemoteException e) {
    ++                    Slog.e(TAG, "Failed to register VR mode state listener: " + e);
    ++                }
    ++            }
    ++        } else if (phase == PHASE_BOOT_COMPLETED) {
    +             mBootCompleted = true;
    + 
    +             // Register listeners now that boot is complete.
    +@@ -182,6 +222,8 @@ public final class NightDisplayService extends SystemService
    +     }
    + 
    +     private void setUp() {
    ++        Slog.d(TAG, "setUp: currentUser=" + mCurrentUser);
    ++
    +         // Create a new controller for the current user and start listening for changes.
    +         mController = new NightDisplayController(getContext(), mCurrentUser);
    +         mController.setListener(this);
    +@@ -196,6 +238,8 @@ public final class NightDisplayService extends SystemService
    +     }
    + 
    +     private void tearDown() {
    ++        Slog.d(TAG, "tearDown: currentUser=" + mCurrentUser);
    ++
    +         if (mController != null) {
    +             mController.setListener(null);
    +             mController = null;
    +@@ -230,6 +274,11 @@ public final class NightDisplayService extends SystemService
    +                 mColorMatrixAnimator.cancel();
    +             }
    + 
    ++            // Don't do any color matrix change animations if we are ignoring them anyway.
    ++            if (mIgnoreAllColorMatrixChanges.get()) {
    ++                return;
    ++            }
    ++
    +             final DisplayTransformManager dtm = getLocalService(DisplayTransformManager.class);
    +             final float[] from = dtm.getColorMatrix(LEVEL_COLOR_MATRIX_NIGHT_DISPLAY);
    +             final float[] to = mIsActivated ? MATRIX_NIGHT : null;
    +@@ -273,6 +322,8 @@ public final class NightDisplayService extends SystemService
    + 
    +     @Override
    +     public void onAutoModeChanged(int autoMode) {
    ++        Slog.d(TAG, "onAutoModeChanged: autoMode=" + autoMode);
    ++
    +         if (mAutoMode != null) {
    +             mAutoMode.onStop();
    +             mAutoMode = null;
    +@@ -291,6 +342,8 @@ public final class NightDisplayService extends SystemService
    + 
    +     @Override
    +     public void onCustomStartTimeChanged(NightDisplayController.LocalTime startTime) {
    ++        Slog.d(TAG, "onCustomStartTimeChanged: startTime=" + startTime);
    ++
    +         if (mAutoMode != null) {
    +             mAutoMode.onCustomStartTimeChanged(startTime);
    +         }
    +@@ -298,6 +351,8 @@ public final class NightDisplayService extends SystemService
    + 
    +     @Override
    +     public void onCustomEndTimeChanged(NightDisplayController.LocalTime endTime) {
    ++        Slog.d(TAG, "onCustomEndTimeChanged: endTime=" + endTime);
    ++
    +         if (mAutoMode != null) {
    +             mAutoMode.onCustomEndTimeChanged(endTime);
    +         }
    +@@ -419,7 +474,7 @@ public final class NightDisplayService extends SystemService
    + 
    +         @Override
    +         public void onAlarm() {
    +-            if (DEBUG) Slog.d(TAG, "onAlarm");
    ++            Slog.d(TAG, "onAlarm");
    +             updateActivated();
    +         }
    +     }
    +@@ -477,7 +532,8 @@ public final class NightDisplayService extends SystemService
    + 
    +         @Override
    +         public void onTwilightStateChanged(@Nullable TwilightState state) {
    +-            if (DEBUG) Slog.d(TAG, "onTwilightStateChanged");
    ++            Slog.d(TAG, "onTwilightStateChanged: isNight="
    ++                    + (state == null ? null : state.isNight()));
    +             updateActivated(state);
    +         }
    +     }
    +diff --git a/services/core/java/com/android/server/dreams/DreamController.java b/services/core/java/com/android/server/dreams/DreamController.java
    +index a633996..3072f43 100644
    +--- a/services/core/java/com/android/server/dreams/DreamController.java
    ++++ b/services/core/java/com/android/server/dreams/DreamController.java
    +@@ -24,8 +24,11 @@ import android.content.Context;
    + import android.content.Intent;
    + import android.content.ServiceConnection;
    + import android.os.Binder;
    ++import android.os.Bundle;
    + import android.os.Handler;
    + import android.os.IBinder;
    ++import android.os.IRemoteCallback;
    ++import android.os.PowerManager;
    + import android.os.RemoteException;
    + import android.os.IBinder.DeathRecipient;
    + import android.os.SystemClock;
    +@@ -116,19 +119,19 @@ final class DreamController {
    +     }
    + 
    +     public void startDream(Binder token, ComponentName name,
    +-            boolean isTest, boolean canDoze, int userId) {
    ++            boolean isTest, boolean canDoze, int userId, PowerManager.WakeLock wakeLock) {
    +         stopDream(true /*immediate*/);
    + 
    +         Trace.traceBegin(Trace.TRACE_TAG_POWER, "startDream");
    +         try {
    +-            // Close the notification shade. Don't need to send to all, but better to be explicit.
    ++            // Close the notification shade. No need to send to all, but better to be explicit.
    +             mContext.sendBroadcastAsUser(mCloseNotificationShadeIntent, UserHandle.ALL);
    + 
    +             Slog.i(TAG, "Starting dream: name=" + name
    +                     + ", isTest=" + isTest + ", canDoze=" + canDoze
    +                     + ", userId=" + userId);
    + 
    +-            mCurrentDream = new DreamRecord(token, name, isTest, canDoze, userId);
    ++            mCurrentDream = new DreamRecord(token, name, isTest, canDoze, userId, wakeLock);
    + 
    +             mDreamStartTime = SystemClock.elapsedRealtime();
    +             MetricsLogger.visible(mContext,
    +@@ -230,6 +233,7 @@ final class DreamController {
    +             if (oldDream.mBound) {
    +                 mContext.unbindService(oldDream);
    +             }
    ++            oldDream.releaseWakeLockIfNeeded();
    + 
    +             try {
    +                 mIWindowManager.removeWindowToken(oldDream.mToken);
    +@@ -251,7 +255,8 @@ final class DreamController {
    +     private void attach(IDreamService service) {
    +         try {
    +             service.asBinder().linkToDeath(mCurrentDream, 0);
    +-            service.attach(mCurrentDream.mToken, mCurrentDream.mCanDoze);
    ++            service.attach(mCurrentDream.mToken, mCurrentDream.mCanDoze,
    ++                    mCurrentDream.mDreamingStartedCallback);
    +         } catch (RemoteException ex) {
    +             Slog.e(TAG, "The dream service died unexpectedly.", ex);
    +             stopDream(true /*immediate*/);
    +@@ -280,6 +285,7 @@ final class DreamController {
    +         public final boolean mCanDoze;
    +         public final int mUserId;
    + 
    ++        public PowerManager.WakeLock mWakeLock;
    +         public boolean mBound;
    +         public boolean mConnected;
    +         public IDreamService mService;
    +@@ -288,12 +294,17 @@ final class DreamController {
    +         public boolean mWakingGently;
    + 
    +         public DreamRecord(Binder token, ComponentName name,
    +-                boolean isTest, boolean canDoze, int userId) {
    ++                boolean isTest, boolean canDoze, int userId, PowerManager.WakeLock wakeLock) {
    +             mToken = token;
    +             mName = name;
    +             mIsTest = isTest;
    +             mCanDoze = canDoze;
    +             mUserId  = userId;
    ++            mWakeLock = wakeLock;
    ++            // Hold the lock while we're waiting for the service to connect and start dreaming.
    ++            // Released after the service has started dreaming, we stop dreaming, or it timed out.
    ++            mWakeLock.acquire();
    ++            mHandler.postDelayed(mReleaseWakeLockIfNeeded, 10000);
    +         }
    + 
    +         // May be called on any thread.
    +@@ -319,6 +330,9 @@ final class DreamController {
    +                     mConnected = true;
    +                     if (mCurrentDream == DreamRecord.this && mService == null) {
    +                         attach(IDreamService.Stub.asInterface(service));
    ++                        // Wake lock will be released once dreaming starts.
    ++                    } else {
    ++                        releaseWakeLockIfNeeded();
    +                     }
    +                 }
    +             });
    +@@ -337,5 +351,23 @@ final class DreamController {
    +                 }
    +             });
    +         }
    ++
    ++        void releaseWakeLockIfNeeded() {
    ++            if (mWakeLock != null) {
    ++                mWakeLock.release();
    ++                mWakeLock = null;
    ++                mHandler.removeCallbacks(mReleaseWakeLockIfNeeded);
    ++            }
    ++        }
    ++
    ++        final Runnable mReleaseWakeLockIfNeeded = this::releaseWakeLockIfNeeded;
    ++
    ++        final IRemoteCallback mDreamingStartedCallback = new IRemoteCallback.Stub() {
    ++            // May be called on any thread.
    ++            @Override
    ++            public void sendResult(Bundle data) throws RemoteException {
    ++                mHandler.post(mReleaseWakeLockIfNeeded);
    ++            }
    ++        };
    +     }
    + }
    +\ No newline at end of file
    +diff --git a/services/core/java/com/android/server/dreams/DreamManagerService.java b/services/core/java/com/android/server/dreams/DreamManagerService.java
    +index a783fa2..1991c00 100644
    +--- a/services/core/java/com/android/server/dreams/DreamManagerService.java
    ++++ b/services/core/java/com/android/server/dreams/DreamManagerService.java
    +@@ -18,6 +18,7 @@ package com.android.server.dreams;
    + 
    + import static android.Manifest.permission.BIND_DREAM_SERVICE;
    + 
    ++import com.android.internal.hardware.AmbientDisplayConfiguration;
    + import com.android.internal.util.DumpUtils;
    + import com.android.server.FgThread;
    + import com.android.server.LocalServices;
    +@@ -88,6 +89,8 @@ public final class DreamManagerService extends SystemService {
    +     private int mCurrentDreamDozeScreenState = Display.STATE_UNKNOWN;
    +     private int mCurrentDreamDozeScreenBrightness = PowerManager.BRIGHTNESS_DEFAULT;
    + 
    ++    private AmbientDisplayConfiguration mDozeConfig;
    ++
    +     public DreamManagerService(Context context) {
    +         super(context);
    +         mContext = context;
    +@@ -97,6 +100,7 @@ public final class DreamManagerService extends SystemService {
    +         mPowerManager = (PowerManager)context.getSystemService(Context.POWER_SERVICE);
    +         mPowerManagerInternal = getLocalService(PowerManagerInternal.class);
    +         mDozeWakeLock = mPowerManager.newWakeLock(PowerManager.DOZE_WAKE_LOCK, TAG);
    ++        mDozeConfig = new AmbientDisplayConfiguration(mContext);
    +     }
    + 
    +     @Override
    +@@ -121,7 +125,7 @@ public final class DreamManagerService extends SystemService {
    +                 }
    +             }, new IntentFilter(Intent.ACTION_USER_SWITCHED), null, mHandler);
    +             mContext.getContentResolver().registerContentObserver(
    +-                    Settings.Secure.getUriFor(Settings.Secure.DOZE_ENABLED), false,
    ++                    Settings.Secure.getUriFor(Settings.Secure.DOZE_PULSE_ON_DOUBLE_TAP), false,
    +                     mDozeEnabledObserver, UserHandle.USER_ALL);
    +             writePulseGestureEnabled();
    +         }
    +@@ -326,19 +330,12 @@ public final class DreamManagerService extends SystemService {
    +     }
    + 
    +     private ComponentName getDozeComponent(int userId) {
    +-        // Read the component from a system property to facilitate debugging.
    +-        // Note that for production devices, the dream should actually be declared in
    +-        // a config.xml resource.
    +-        String name = Build.IS_DEBUGGABLE ? SystemProperties.get("debug.doze.component") : null;
    +-        if (TextUtils.isEmpty(name)) {
    +-            // Read the component from a config.xml resource.
    +-            // The value should be specified in a resource overlay for the product.
    +-            name = mContext.getResources().getString(
    +-                    com.android.internal.R.string.config_dozeComponent);
    +-        }
    +-        boolean enabled = Settings.Secure.getIntForUser(mContext.getContentResolver(),
    +-                Settings.Secure.DOZE_ENABLED, 1, userId) != 0;
    +-        return TextUtils.isEmpty(name) || !enabled ? null : ComponentName.unflattenFromString(name);
    ++        if (mDozeConfig.enabled(userId)) {
    ++            return ComponentName.unflattenFromString(mDozeConfig.ambientDisplayComponent());
    ++        } else {
    ++            return null;
    ++        }
    ++
    +     }
    + 
    +     private ServiceInfo getServiceInfo(ComponentName name) {
    +@@ -370,12 +367,10 @@ public final class DreamManagerService extends SystemService {
    +         mCurrentDreamCanDoze = canDoze;
    +         mCurrentDreamUserId = userId;
    + 
    +-        mHandler.post(new Runnable() {
    +-            @Override
    +-            public void run() {
    +-                mController.startDream(newToken, name, isTest, canDoze, userId);
    +-            }
    +-        });
    ++        PowerManager.WakeLock wakeLock = mPowerManager
    ++                .newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "startDream");
    ++        mHandler.post(wakeLock.wrap(
    ++                () -> mController.startDream(newToken, name, isTest, canDoze, userId, wakeLock)));
    +     }
    + 
    +     private void stopDreamLocked(final boolean immediate) {
    +diff --git a/services/core/java/com/android/server/emergency/EmergencyAffordanceService.java b/services/core/java/com/android/server/emergency/EmergencyAffordanceService.java
    +new file mode 100644
    +index 0000000..353f450
    +--- /dev/null
    ++++ b/services/core/java/com/android/server/emergency/EmergencyAffordanceService.java
    +@@ -0,0 +1,318 @@
    ++/*
    ++ * Copyright (C) 2016 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 com.android.server.emergency;
    ++
    ++import android.content.BroadcastReceiver;
    ++import android.content.Context;
    ++import android.content.Intent;
    ++import android.content.IntentFilter;
    ++import android.os.Handler;
    ++import android.os.HandlerThread;
    ++import android.os.Looper;
    ++import android.os.Message;
    ++import android.provider.Settings;
    ++import android.telephony.CellInfo;
    ++import android.telephony.CellInfoGsm;
    ++import android.telephony.CellInfoLte;
    ++import android.telephony.CellInfoWcdma;
    ++import android.telephony.CellLocation;
    ++import android.telephony.PhoneStateListener;
    ++import android.telephony.SubscriptionInfo;
    ++import android.telephony.SubscriptionManager;
    ++import android.telephony.TelephonyManager;
    ++
    ++import com.android.server.SystemService;
    ++
    ++import java.util.ArrayList;
    ++import java.util.Arrays;
    ++import java.util.List;
    ++
    ++/**
    ++ * A service that listens to connectivity and SIM card changes and determines if the emergency mode
    ++ * should be enabled
    ++ */
    ++public class EmergencyAffordanceService extends SystemService {
    ++
    ++    private static final String TAG = "EmergencyAffordanceService";
    ++
    ++    private static final int NUM_SCANS_UNTIL_ABORT = 4;
    ++
    ++    private static final int INITIALIZE_STATE = 1;
    ++    private static final int CELL_INFO_STATE_CHANGED = 2;
    ++    private static final int SUBSCRIPTION_CHANGED = 3;
    ++
    ++    /**
    ++     * Global setting, whether the last scan of the sim cards reveal that a sim was inserted that
    ++     * requires the emergency affordance. The value is a boolean (1 or 0).
    ++     * @hide
    ++     */
    ++    private static final String EMERGENCY_SIM_INSERTED_SETTING = "emergency_sim_inserted_before";
    ++
    ++    private final Context mContext;
    ++    private final ArrayList<Integer> mEmergencyCallMccNumbers;
    ++
    ++    private final Object mLock = new Object();
    ++
    ++    private TelephonyManager mTelephonyManager;
    ++    private SubscriptionManager mSubscriptionManager;
    ++    private boolean mEmergencyAffordanceNeeded;
    ++    private MyHandler mHandler;
    ++    private int mScansCompleted;
    ++    private PhoneStateListener mPhoneStateListener = new PhoneStateListener() {
    ++        @Override
    ++        public void onCellInfoChanged(List<CellInfo> cellInfo) {
    ++            if (!isEmergencyAffordanceNeeded()) {
    ++                requestCellScan();
    ++            }
    ++        }
    ++
    ++        @Override
    ++        public void onCellLocationChanged(CellLocation location) {
    ++            if (!isEmergencyAffordanceNeeded()) {
    ++                requestCellScan();
    ++            }
    ++        }
    ++    };
    ++    private BroadcastReceiver mAirplaneModeReceiver = new BroadcastReceiver() {
    ++        @Override
    ++        public void onReceive(Context context, Intent intent) {
    ++            if (Settings.Global.getInt(context.getContentResolver(),
    ++                    Settings.Global.AIRPLANE_MODE_ON, 0) == 0) {
    ++                startScanning();
    ++                requestCellScan();
    ++            }
    ++        }
    ++    };
    ++    private boolean mSimNeedsEmergencyAffordance;
    ++    private boolean mNetworkNeedsEmergencyAffordance;
    ++    private boolean mVoiceCapable;
    ++
    ++    private void requestCellScan() {
    ++        mHandler.obtainMessage(CELL_INFO_STATE_CHANGED).sendToTarget();
    ++    }
    ++
    ++    private SubscriptionManager.OnSubscriptionsChangedListener mSubscriptionChangedListener
    ++            = new SubscriptionManager.OnSubscriptionsChangedListener() {
    ++        @Override
    ++        public void onSubscriptionsChanged() {
    ++            mHandler.obtainMessage(SUBSCRIPTION_CHANGED).sendToTarget();
    ++        }
    ++    };
    ++
    ++    public EmergencyAffordanceService(Context context) {
    ++        super(context);
    ++        mContext = context;
    ++        int[] numbers = context.getResources().getIntArray(
    ++                com.android.internal.R.array.config_emergency_mcc_codes);
    ++        mEmergencyCallMccNumbers = new ArrayList<>(numbers.length);
    ++        for (int i = 0; i < numbers.length; i++) {
    ++            mEmergencyCallMccNumbers.add(numbers[i]);
    ++        }
    ++    }
    ++
    ++    private void updateEmergencyAffordanceNeeded() {
    ++        synchronized (mLock) {
    ++            mEmergencyAffordanceNeeded = mVoiceCapable && (mSimNeedsEmergencyAffordance ||
    ++                    mNetworkNeedsEmergencyAffordance);
    ++            Settings.Global.putInt(mContext.getContentResolver(),
    ++                    Settings.Global.EMERGENCY_AFFORDANCE_NEEDED,
    ++                    mEmergencyAffordanceNeeded ? 1 : 0);
    ++            if (mEmergencyAffordanceNeeded) {
    ++                stopScanning();
    ++            }
    ++        }
    ++    }
    ++
    ++    private void stopScanning() {
    ++        synchronized (mLock) {
    ++            mTelephonyManager.listen(mPhoneStateListener, PhoneStateListener.LISTEN_NONE);
    ++            mScansCompleted = 0;
    ++        }
    ++    }
    ++
    ++    private boolean isEmergencyAffordanceNeeded() {
    ++        synchronized (mLock) {
    ++            return mEmergencyAffordanceNeeded;
    ++        }
    ++    }
    ++
    ++    @Override
    ++    public void onStart() {
    ++    }
    ++
    ++    @Override
    ++    public void onBootPhase(int phase) {
    ++        if (phase == PHASE_THIRD_PARTY_APPS_CAN_START) {
    ++            mTelephonyManager = mContext.getSystemService(TelephonyManager.class);
    ++            mVoiceCapable = mTelephonyManager.isVoiceCapable();
    ++            if (!mVoiceCapable) {
    ++                updateEmergencyAffordanceNeeded();
    ++                return;
    ++            }
    ++            mSubscriptionManager = SubscriptionManager.from(mContext);
    ++            HandlerThread thread = new HandlerThread(TAG);
    ++            thread.start();
    ++            mHandler = new MyHandler(thread.getLooper());
    ++            mHandler.obtainMessage(INITIALIZE_STATE).sendToTarget();
    ++            startScanning();
    ++            IntentFilter filter = new IntentFilter(Intent.ACTION_AIRPLANE_MODE_CHANGED);
    ++            mContext.registerReceiver(mAirplaneModeReceiver, filter);
    ++            mSubscriptionManager.addOnSubscriptionsChangedListener(mSubscriptionChangedListener);
    ++        }
    ++    }
    ++
    ++    private void startScanning() {
    ++        mTelephonyManager.listen(mPhoneStateListener, PhoneStateListener.LISTEN_CELL_INFO
    ++                | PhoneStateListener.LISTEN_CELL_LOCATION);
    ++    }
    ++
    ++    /** Handler to do the heavier work on */
    ++    private class MyHandler extends Handler {
    ++
    ++        public MyHandler(Looper l) {
    ++            super(l);
    ++        }
    ++
    ++        @Override
    ++        public void handleMessage(Message msg) {
    ++            switch (msg.what) {
    ++                case INITIALIZE_STATE:
    ++                    handleInitializeState();
    ++                    break;
    ++                case CELL_INFO_STATE_CHANGED:
    ++                    handleUpdateCellInfo();
    ++                    break;
    ++                case SUBSCRIPTION_CHANGED:
    ++                    handleUpdateSimSubscriptionInfo();
    ++                    break;
    ++            }
    ++        }
    ++    }
    ++
    ++    private void handleInitializeState() {
    ++        if (handleUpdateSimSubscriptionInfo()) {
    ++            return;
    ++        }
    ++        if (handleUpdateCellInfo()) {
    ++            return;
    ++        }
    ++        updateEmergencyAffordanceNeeded();
    ++    }
    ++
    ++    private boolean handleUpdateSimSubscriptionInfo() {
    ++        boolean neededBefore = simNeededAffordanceBefore();
    ++        boolean neededNow = neededBefore;
    ++        List<SubscriptionInfo> activeSubscriptionInfoList =
    ++                mSubscriptionManager.getActiveSubscriptionInfoList();
    ++        if (activeSubscriptionInfoList == null) {
    ++            return neededNow;
    ++        }
    ++        for (SubscriptionInfo info : activeSubscriptionInfoList) {
    ++            int mcc = info.getMcc();
    ++            if (mccRequiresEmergencyAffordance(mcc)) {
    ++                neededNow = true;
    ++                break;
    ++            } else if (mcc != 0 && mcc != Integer.MAX_VALUE){
    ++                // a Sim with a different mcc code was found
    ++                neededNow = false;
    ++            }
    ++            String simOperator  = mTelephonyManager.getSimOperator(info.getSubscriptionId());
    ++            mcc = 0;
    ++            if (simOperator != null && simOperator.length() >= 3) {
    ++                mcc = Integer.parseInt(simOperator.substring(0, 3));
    ++            }
    ++            if (mcc != 0) {
    ++                if (mccRequiresEmergencyAffordance(mcc)) {
    ++                    neededNow = true;
    ++                    break;
    ++                } else {
    ++                    // a Sim with a different mcc code was found
    ++                    neededNow = false;
    ++                }
    ++            }
    ++        }
    ++        if (neededNow != neededBefore) {
    ++            setSimNeedsEmergencyAffordance(neededNow);
    ++        }
    ++        return neededNow;
    ++    }
    ++
    ++    private void setSimNeedsEmergencyAffordance(boolean simNeedsEmergencyAffordance) {
    ++        mSimNeedsEmergencyAffordance = simNeedsEmergencyAffordance;
    ++        Settings.Global.putInt(mContext.getContentResolver(),
    ++                EMERGENCY_SIM_INSERTED_SETTING,
    ++                simNeedsEmergencyAffordance ? 1 : 0);
    ++        updateEmergencyAffordanceNeeded();
    ++    }
    ++
    ++    private boolean simNeededAffordanceBefore() {
    ++        return Settings.Global.getInt(mContext.getContentResolver(),
    ++                "emergency_sim_inserted_before", 0) != 0;
    ++    }
    ++
    ++    private boolean handleUpdateCellInfo() {
    ++        List<CellInfo> cellInfos = mTelephonyManager.getAllCellInfo();
    ++        if (cellInfos == null) {
    ++            return false;
    ++        }
    ++        boolean stopScanningAfterScan = false;
    ++        for (CellInfo cellInfo : cellInfos) {
    ++            int mcc = 0;
    ++            if (cellInfo instanceof CellInfoGsm) {
    ++                mcc = ((CellInfoGsm) cellInfo).getCellIdentity().getMcc();
    ++            } else if (cellInfo instanceof CellInfoLte) {
    ++                mcc = ((CellInfoLte) cellInfo).getCellIdentity().getMcc();
    ++            } else if (cellInfo instanceof CellInfoWcdma) {
    ++                mcc = ((CellInfoWcdma) cellInfo).getCellIdentity().getMcc();
    ++            }
    ++            if (mccRequiresEmergencyAffordance(mcc)) {
    ++                setNetworkNeedsEmergencyAffordance(true);
    ++                return true;
    ++            } else if (mcc != 0 && mcc != Integer.MAX_VALUE) {
    ++                // we found an mcc that isn't in the list, abort
    ++                stopScanningAfterScan = true;
    ++            }
    ++        }
    ++        if (stopScanningAfterScan) {
    ++            stopScanning();
    ++        } else {
    ++            onCellScanFinishedUnsuccessful();
    ++        }
    ++        setNetworkNeedsEmergencyAffordance(false);
    ++        return false;
    ++    }
    ++
    ++    private void setNetworkNeedsEmergencyAffordance(boolean needsAffordance) {
    ++        synchronized (mLock) {
    ++            mNetworkNeedsEmergencyAffordance = needsAffordance;
    ++            updateEmergencyAffordanceNeeded();
    ++        }
    ++    }
    ++
    ++    private void onCellScanFinishedUnsuccessful() {
    ++        synchronized (mLock) {
    ++            mScansCompleted++;
    ++            if (mScansCompleted >= NUM_SCANS_UNTIL_ABORT) {
    ++                stopScanning();
    ++            }
    ++        }
    ++    }
    ++
    ++    private boolean mccRequiresEmergencyAffordance(int mcc) {
    ++        return mEmergencyCallMccNumbers.contains(mcc);
    ++    }
    ++}
    +diff --git a/services/core/java/com/android/server/fingerprint/AuthenticationClient.java b/services/core/java/com/android/server/fingerprint/AuthenticationClient.java
    +index 87da866..5297589 100644
    +--- a/services/core/java/com/android/server/fingerprint/AuthenticationClient.java
    ++++ b/services/core/java/com/android/server/fingerprint/AuthenticationClient.java
    +@@ -115,6 +115,7 @@ public abstract class AuthenticationClient extends ClientMonitor {
    +             final int result = daemon.authenticate(mOpId, getGroupId());
    +             if (result != 0) {
    +                 Slog.w(TAG, "startAuthentication failed, result=" + result);
    ++                MetricsLogger.histogram(getContext(), "fingeprintd_auth_start_error", result);
    +                 onError(FingerprintManager.FINGERPRINT_ERROR_HW_UNAVAILABLE);
    +                 return result;
    +             }
    +diff --git a/services/core/java/com/android/server/fingerprint/EnrollClient.java b/services/core/java/com/android/server/fingerprint/EnrollClient.java
    +index 6a533c9..640a46f 100644
    +--- a/services/core/java/com/android/server/fingerprint/EnrollClient.java
    ++++ b/services/core/java/com/android/server/fingerprint/EnrollClient.java
    +@@ -88,6 +88,7 @@ public abstract class EnrollClient extends ClientMonitor {
    +             final int result = daemon.enroll(mCryptoToken, getGroupId(), timeout);
    +             if (result != 0) {
    +                 Slog.w(TAG, "startEnroll failed, result=" + result);
    ++                MetricsLogger.histogram(getContext(), "fingerprintd_enroll_start_error", result);
    +                 onError(FingerprintManager.FINGERPRINT_ERROR_HW_UNAVAILABLE);
    +                 return result;
    +             }
    +diff --git a/services/core/java/com/android/server/fingerprint/EnumerateClient.java b/services/core/java/com/android/server/fingerprint/EnumerateClient.java
    +index 52dbd5d..26b1916 100644
    +--- a/services/core/java/com/android/server/fingerprint/EnumerateClient.java
    ++++ b/services/core/java/com/android/server/fingerprint/EnumerateClient.java
    +@@ -23,6 +23,7 @@ import android.hardware.fingerprint.IFingerprintServiceReceiver;
    + import android.os.IBinder;
    + import android.os.RemoteException;
    + import android.util.Slog;
    ++import com.android.internal.logging.MetricsLogger;
    + 
    + /**
    +  * A class to keep track of the enumeration state for a given client.
    +@@ -43,6 +44,7 @@ public abstract class EnumerateClient extends ClientMonitor {
    +             if (result != 0) {
    +                 Slog.w(TAG, "start enumerate for user " + getTargetUserId()
    +                     + " failed, result=" + result);
    ++                MetricsLogger.histogram(getContext(), "fingerprintd_enum_start_error", result);
    +                 onError(FingerprintManager.FINGERPRINT_ERROR_HW_UNAVAILABLE);
    +                 return result;
    +             }
    +diff --git a/services/core/java/com/android/server/fingerprint/FingerprintService.java b/services/core/java/com/android/server/fingerprint/FingerprintService.java
    +index 73c8469..6c11794 100644
    +--- a/services/core/java/com/android/server/fingerprint/FingerprintService.java
    ++++ b/services/core/java/com/android/server/fingerprint/FingerprintService.java
    +@@ -194,7 +194,9 @@ public class FingerprintService extends SystemService implements IBinder.DeathRe
    +     @Override
    +     public void binderDied() {
    +         Slog.v(TAG, "fingerprintd died");
    ++        MetricsLogger.count(mContext, "fingerprintd_died", 1);
    +         mDaemon = null;
    ++        mCurrentUserId = UserHandle.USER_CURRENT;
    +         handleError(mHalDeviceId, FingerprintManager.FINGERPRINT_ERROR_HW_UNAVAILABLE);
    +     }
    + 
    +@@ -210,6 +212,7 @@ public class FingerprintService extends SystemService implements IBinder.DeathRe
    +                         updateActiveGroup(ActivityManager.getCurrentUser(), null);
    +                     } else {
    +                         Slog.w(TAG, "Failed to open Fingerprint HAL!");
    ++                        MetricsLogger.count(mContext, "fingerprintd_openhal_error", 1);
    +                         mDaemon = null;
    +                     }
    +                 } catch (RemoteException e) {
    +diff --git a/services/core/java/com/android/server/fingerprint/RemovalClient.java b/services/core/java/com/android/server/fingerprint/RemovalClient.java
    +index bcf2264..f939f41 100644
    +--- a/services/core/java/com/android/server/fingerprint/RemovalClient.java
    ++++ b/services/core/java/com/android/server/fingerprint/RemovalClient.java
    +@@ -24,6 +24,7 @@ import android.os.IBinder;
    + import android.os.RemoteException;
    + import android.os.UserHandle;
    + import android.util.Slog;
    ++import com.android.internal.logging.MetricsLogger;
    + 
    + /**
    +  * A class to keep track of the remove state for a given client.
    +@@ -46,6 +47,7 @@ public abstract class RemovalClient extends ClientMonitor {
    +             final int result = daemon.remove(mFingerId, getGroupId());
    +             if (result != 0) {
    +                 Slog.w(TAG, "startRemove with id = " + mFingerId + " failed, result=" + result);
    ++                MetricsLogger.histogram(getContext(), "fingerprintd_remove_start_error", result);
    +                 onError(FingerprintManager.FINGERPRINT_ERROR_HW_UNAVAILABLE);
    +                 return result;
    +             }
    +diff --git a/services/core/java/com/android/server/hdmi/HdmiControlService.java b/services/core/java/com/android/server/hdmi/HdmiControlService.java
    +index 5dc9d02..72ee218 100644
    +--- a/services/core/java/com/android/server/hdmi/HdmiControlService.java
    ++++ b/services/core/java/com/android/server/hdmi/HdmiControlService.java
    +@@ -2011,6 +2011,9 @@ public final class HdmiControlService extends SystemService {
    +     @ServiceThreadOnly
    +     void standby() {
    +         assertRunOnServiceThread();
    ++        if (!canGoToStandby()) {
    ++            return;
    ++        }
    +         mStandbyMessageReceived = true;
    +         mPowerManager.goToSleep(SystemClock.uptimeMillis(), PowerManager.GO_TO_SLEEP_REASON_HDMI, 0);
    +         // PowerManger will send the broadcast Intent.ACTION_SCREEN_OFF and after this gets
    +@@ -2038,10 +2041,13 @@ public final class HdmiControlService extends SystemService {
    +     @ServiceThreadOnly
    +     private void onStandby(final int standbyAction) {
    +         assertRunOnServiceThread();
    +-        if (!canGoToStandby()) return;
    +         mPowerStatus = HdmiControlManager.POWER_STATUS_TRANSIENT_TO_STANDBY;
    +         invokeVendorCommandListenersOnControlStateChanged(false,
    +                 HdmiControlManager.CONTROL_STATE_CHANGED_REASON_STANDBY);
    ++        if (!canGoToStandby()) {
    ++            mPowerStatus = HdmiControlManager.POWER_STATUS_STANDBY;
    ++            return;
    ++        }
    + 
    +         final List<HdmiCecLocalDevice> devices = getAllLocalDevices();
    +         disableDevices(new PendingActionClearedCallback() {
    +diff --git a/services/core/java/com/android/server/job/JobSchedulerService.java b/services/core/java/com/android/server/job/JobSchedulerService.java
    +index 9d93146..bb3e877 100644
    +--- a/services/core/java/com/android/server/job/JobSchedulerService.java
    ++++ b/services/core/java/com/android/server/job/JobSchedulerService.java
    +@@ -217,7 +217,7 @@ public final class JobSchedulerService extends com.android.server.SystemService
    +         private static final int DEFAULT_FG_JOB_COUNT = 4;
    +         private static final int DEFAULT_BG_NORMAL_JOB_COUNT = 6;
    +         private static final int DEFAULT_BG_MODERATE_JOB_COUNT = 4;
    +-        private static final int DEFAULT_BG_LOW_JOB_COUNT = 2;
    ++        private static final int DEFAULT_BG_LOW_JOB_COUNT = 1;
    +         private static final int DEFAULT_BG_CRITICAL_JOB_COUNT = 1;
    + 
    +         /**
    +@@ -429,7 +429,18 @@ public final class JobSchedulerService extends com.android.server.SystemService
    +                                         }
    +                                         cancelJobsForUid(pkgUid, true);
    +                                     }
    +-                                } catch (RemoteException e) { /* cannot happen */ }
    ++                                } catch (RemoteException|IllegalArgumentException e) {
    ++                                    /*
    ++                                     * IllegalArgumentException means that the package doesn't exist.
    ++                                     * This arises when PACKAGE_CHANGED broadcast delivery has lagged
    ++                                     * behind outright uninstall, so by the time we try to act it's gone.
    ++                                     * We don't need to act on this PACKAGE_CHANGED when this happens;
    ++                                     * we'll get a PACKAGE_REMOVED later and clean up then.
    ++                                     *
    ++                                     * RemoteException can't actually happen; the package manager is
    ++                                     * running in this same process.
    ++                                     */
    ++                                }
    +                                 break;
    +                             }
    +                         }
    +@@ -907,7 +918,11 @@ public final class JobSchedulerService extends com.android.server.SystemService
    +     private boolean isCurrentlyActiveLocked(JobStatus job) {
    +         for (int i=0; i<mActiveServices.size(); i++) {
    +             JobServiceContext serviceContext = mActiveServices.get(i);
    +-            final JobStatus running = serviceContext.getRunningJob();
    ++            // The 'unsafe' direct-internal-reference running-job inspector is okay to
    ++            // use here because we are already holding the necessary lock *and* we
    ++            // immediately discard the returned object reference, if any; we return
    ++            // only a boolean state indicator to the caller.
    ++            final JobStatus running = serviceContext.getRunningJobUnsafeLocked();
    +             if (running != null && running.matches(job.getUid(), job.getJobId())) {
    +                 return true;
    +             }
    +diff --git a/services/core/java/com/android/server/job/JobServiceContext.java b/services/core/java/com/android/server/job/JobServiceContext.java
    +index 31528e5..5e495fa 100644
    +--- a/services/core/java/com/android/server/job/JobServiceContext.java
    ++++ b/services/core/java/com/android/server/job/JobServiceContext.java
    +@@ -230,6 +230,15 @@ public class JobServiceContext extends IJobCallback.Stub implements ServiceConne
    +         return job == null ? null : new JobStatus(job);
    +     }
    + 
    ++    /**
    ++     * Internal non-cloning inspection of the currently running job, if any.  The lock
    ++     * must be held when calling this *and* for the entire lifetime of using its returned
    ++     * JobStatus object!
    ++     */
    ++    JobStatus getRunningJobUnsafeLocked() {
    ++        return mRunningJob;
    ++    }
    ++
    +     /** Called externally when a job that was scheduled for execution should be cancelled. */
    +     void cancelExecutingJob(int reason) {
    +         mCallbackHandler.obtainMessage(MSG_CANCEL, reason, 0 /* unused */).sendToTarget();
    +@@ -306,10 +315,24 @@ public class JobServiceContext extends IJobCallback.Stub implements ServiceConne
    +         this.service = IJobService.Stub.asInterface(service);
    +         final PowerManager pm =
    +                 (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
    +-        mWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, runningJob.getTag());
    +-        mWakeLock.setWorkSource(new WorkSource(runningJob.getSourceUid()));
    +-        mWakeLock.setReferenceCounted(false);
    +-        mWakeLock.acquire();
    ++        PowerManager.WakeLock wl = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK,
    ++                runningJob.getTag());
    ++        wl.setWorkSource(new WorkSource(runningJob.getSourceUid()));
    ++        wl.setReferenceCounted(false);
    ++        wl.acquire();
    ++        synchronized (mLock) {
    ++            // We use a new wakelock instance per job.  In rare cases there is a race between
    ++            // teardown following job completion/cancellation and new job service spin-up
    ++            // such that if we simply assign mWakeLock to be the new instance, we orphan
    ++            // the currently-live lock instead of cleanly replacing it.  Watch for this and
    ++            // explicitly fast-forward the release if we're in that situation.
    ++            if (mWakeLock != null) {
    ++                Slog.w(TAG, "Bound new job " + runningJob + " but live wakelock " + mWakeLock
    ++                        + " tag=" + mWakeLock.getTag());
    ++                mWakeLock.release();
    ++            }
    ++            mWakeLock = wl;
    ++        }
    +         mCallbackHandler.obtainMessage(MSG_SERVICE_BOUND).sendToTarget();
    +     }
    + 
    +diff --git a/services/core/java/com/android/server/location/GnssLocationProvider.java b/services/core/java/com/android/server/location/GnssLocationProvider.java
    +index 7580cf4..ae98077 100644
    +--- a/services/core/java/com/android/server/location/GnssLocationProvider.java
    ++++ b/services/core/java/com/android/server/location/GnssLocationProvider.java
    +@@ -452,8 +452,12 @@ public class GnssLocationProvider implements LocationProviderInterface {
    +             new ConnectivityManager.NetworkCallback() {
    +         @Override
    +         public void onAvailable(Network network) {
    +-            requestUtcTime();
    +-            xtraDownloadRequest();
    ++            if (mInjectNtpTimePending == STATE_PENDING_NETWORK) {
    ++                requestUtcTime();
    ++            }
    ++            if (mDownloadXtraDataPending == STATE_PENDING_NETWORK) {
    ++                xtraDownloadRequest();
    ++            }
    +         }
    +     };
    + 
    +@@ -1002,6 +1006,11 @@ public class GnssLocationProvider implements LocationProviderInterface {
    +     }
    + 
    +     private void handleDownloadXtraData() {
    ++        if (!mSupportsXtra) {
    ++            // native code reports xtra not supported, don't try
    ++            Log.d(TAG, "handleDownloadXtraData() called when Xtra not supported");
    ++            return;
    ++        }
    +         if (mDownloadXtraDataPending == STATE_DOWNLOADING) {
    +             // already downloading data
    +             return;
    +@@ -2125,9 +2134,7 @@ public class GnssLocationProvider implements LocationProviderInterface {
    +                     handleInjectNtpTime();
    +                     break;
    +                 case DOWNLOAD_XTRA_DATA:
    +-                    if (mSupportsXtra) {
    +-                        handleDownloadXtraData();
    +-                    }
    ++                    handleDownloadXtraData();
    +                     break;
    +                 case INJECT_NTP_TIME_FINISHED:
    +                     mInjectNtpTimePending = STATE_IDLE;
    +diff --git a/services/core/java/com/android/server/media/MediaSessionService.java b/services/core/java/com/android/server/media/MediaSessionService.java
    +index 2c53af3..34f6aa7 100644
    +--- a/services/core/java/com/android/server/media/MediaSessionService.java
    ++++ b/services/core/java/com/android/server/media/MediaSessionService.java
    +@@ -78,6 +78,8 @@ import java.util.List;
    + public class MediaSessionService extends SystemService implements Monitor {
    +     private static final String TAG = "MediaSessionService";
    +     private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
    ++    // Leave log for media key event always.
    ++    private static final boolean DEBUG_MEDIA_KEY_EVENT = DEBUG || true;
    + 
    +     private static final int WAKELOCK_TIMEOUT = 5000;
    + 
    +@@ -302,7 +304,7 @@ public class MediaSessionService extends SystemService implements Monitor {
    +      */
    +     private void destroySessionLocked(MediaSessionRecord session) {
    +         if (DEBUG) {
    +-            Log.d(TAG, "Destroying session : " + session.toString());
    ++            Log.d(TAG, "Destroying " + session);
    +         }
    +         int userId = session.getUserId();
    +         UserRecord user = mUserRecords.get(userId);
    +@@ -408,7 +410,7 @@ public class MediaSessionService extends SystemService implements Monitor {
    +                     if (component != null) {
    +                         if (compName.equals(component)) {
    +                             if (DEBUG) {
    +-                                Log.d(TAG, "ok to get sessions: " + component +
    ++                                Log.d(TAG, "ok to get sessions. " + component +
    +                                         " is authorized notification listener");
    +                             }
    +                             return true;
    +@@ -417,7 +419,7 @@ public class MediaSessionService extends SystemService implements Monitor {
    +                 }
    +             }
    +             if (DEBUG) {
    +-                Log.d(TAG, "not ok to get sessions, " + compName +
    ++                Log.d(TAG, "not ok to get sessions. " + compName +
    +                         " is not in list of ENABLED_NOTIFICATION_LISTENERS for user " + userId);
    +             }
    +         }
    +@@ -462,7 +464,7 @@ public class MediaSessionService extends SystemService implements Monitor {
    +         mHandler.post(MessageHandler.MSG_SESSIONS_CHANGED, userId, 0);
    + 
    +         if (DEBUG) {
    +-            Log.d(TAG, "Created session for package " + callerPackageName + " with tag " + tag);
    ++            Log.d(TAG, "Created session for " + callerPackageName + " with tag " + tag);
    +         }
    +         return session;
    +     }
    +@@ -888,17 +890,16 @@ public class MediaSessionService extends SystemService implements Monitor {
    + 
    +         private void dispatchAdjustVolumeLocked(int suggestedStream, int direction, int flags,
    +                 MediaSessionRecord session) {
    +-            if (DEBUG) {
    +-                String description = session == null ? null : session.toString();
    +-                Log.d(TAG, "Adjusting session " + description + " by " + direction + ". flags="
    +-                        + flags + ", suggestedStream=" + suggestedStream);
    +-
    +-            }
    +             boolean preferSuggestedStream = false;
    +             if (isValidLocalStreamType(suggestedStream)
    +                     && AudioSystem.isStreamActive(suggestedStream, 0)) {
    +                 preferSuggestedStream = true;
    +             }
    ++            if (DEBUG) {
    ++                Log.d(TAG, "Adjusting " + session + " by " + direction + ". flags="
    ++                        + flags + ", suggestedStream=" + suggestedStream
    ++                        + ", preferSuggestedStream=" + preferSuggestedStream);
    ++            }
    +             if (session == null || preferSuggestedStream) {
    +                 if ((flags & AudioManager.FLAG_ACTIVE_MEDIA_ONLY) != 0
    +                         && !AudioSystem.isStreamActive(AudioManager.STREAM_MUSIC, 0)) {
    +@@ -953,8 +954,8 @@ public class MediaSessionService extends SystemService implements Monitor {
    +         private void dispatchMediaKeyEventLocked(KeyEvent keyEvent, boolean needWakeLock,
    +                 MediaSessionRecord session) {
    +             if (session != null) {
    +-                if (DEBUG) {
    +-                    Log.d(TAG, "Sending media key to " + session.toString());
    ++                if (DEBUG_MEDIA_KEY_EVENT) {
    ++                    Log.d(TAG, "Sending " + keyEvent + " to " + session);
    +                 }
    +                 if (needWakeLock) {
    +                     mKeyEventReceiver.aquireWakeLockLocked();
    +@@ -973,11 +974,6 @@ public class MediaSessionService extends SystemService implements Monitor {
    +                             && user.mRestoredMediaButtonReceiver == null) {
    +                         continue;
    +                     }
    +-                    if (DEBUG) {
    +-                        Log.d(TAG, "Sending media key to last known PendingIntent "
    +-                                + user.mLastMediaButtonReceiver + " or restored Intent "
    +-                                + user.mRestoredMediaButtonReceiver);
    +-                    }
    +                     if (needWakeLock) {
    +                         mKeyEventReceiver.aquireWakeLockLocked();
    +                     }
    +@@ -986,10 +982,19 @@ public class MediaSessionService extends SystemService implements Monitor {
    +                     mediaButtonIntent.putExtra(Intent.EXTRA_KEY_EVENT, keyEvent);
    +                     try {
    +                         if (user.mLastMediaButtonReceiver != null) {
    ++                            if (DEBUG_MEDIA_KEY_EVENT) {
    ++                                Log.d(TAG, "Sending " + keyEvent
    ++                                        + " to the last known pendingIntent "
    ++                                        + user.mLastMediaButtonReceiver);
    ++                            }
    +                             user.mLastMediaButtonReceiver.send(getContext(),
    +                                     needWakeLock ? mKeyEventReceiver.mLastTimeoutId : -1,
    +                                     mediaButtonIntent, mKeyEventReceiver, mHandler);
    +                         } else {
    ++                            if (DEBUG_MEDIA_KEY_EVENT) {
    ++                                Log.d(TAG, "Sending " + keyEvent + " to the restored intent "
    ++                                        + user.mRestoredMediaButtonReceiver);
    ++                            }
    +                             mediaButtonIntent.setComponent(user.mRestoredMediaButtonReceiver);
    +                             getContext().sendBroadcastAsUser(mediaButtonIntent,
    +                                     UserHandle.of(userId));
    +diff --git a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
    +index f3fc676..d479bfc 100644
    +--- a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
    ++++ b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
    +@@ -90,6 +90,7 @@ import static org.xmlpull.v1.XmlPullParser.START_TAG;
    + 
    + import android.Manifest;
    + import android.annotation.IntDef;
    ++import android.annotation.Nullable;
    + import android.app.ActivityManager;
    + import android.app.AppGlobals;
    + import android.app.AppOpsManager;
    +@@ -141,6 +142,7 @@ import android.os.RemoteCallbackList;
    + import android.os.RemoteException;
    + import android.os.ResultReceiver;
    + import android.os.ServiceManager;
    ++import android.os.Trace;
    + import android.os.UserHandle;
    + import android.os.UserManager;
    + import android.provider.Settings;
    +@@ -164,7 +166,6 @@ import android.util.Xml;
    + import com.android.internal.R;
    + import com.android.internal.annotations.GuardedBy;
    + import com.android.internal.annotations.VisibleForTesting;
    +-import com.android.internal.content.PackageMonitor;
    + import com.android.internal.util.ArrayUtils;
    + import com.android.internal.util.FastXmlSerializer;
    + import com.android.internal.util.IndentingPrintWriter;
    +@@ -289,6 +290,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
    +     private static final int MSG_UPDATE_INTERFACE_QUOTA = 10;
    +     private static final int MSG_REMOVE_INTERFACE_QUOTA = 11;
    +     private static final int MSG_RESTRICT_BACKGROUND_BLACKLIST_CHANGED = 12;
    ++    private static final int MSG_SET_FIREWALL_RULES = 13;
    + 
    +     private final Context mContext;
    +     private final IActivityManager mActivityManager;
    +@@ -404,7 +406,6 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
    + 
    +     private final AppOpsManager mAppOps;
    + 
    +-    private final MyPackageMonitor mPackageMonitor;
    +     private final IPackageManager mIPm;
    + 
    + 
    +@@ -446,8 +447,6 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
    + 
    +         mAppOps = context.getSystemService(AppOpsManager.class);
    + 
    +-        mPackageMonitor = new MyPackageMonitor();
    +-
    +         // Expose private service for system components to use.
    +         LocalServices.addService(NetworkPolicyManagerInternal.class,
    +                 new NetworkPolicyManagerInternalImpl());
    +@@ -513,12 +512,13 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
    +             try {
    +                 app = pm.getApplicationInfoAsUser(pkg, PackageManager.MATCH_SYSTEM_ONLY, userId);
    +             } catch (PackageManager.NameNotFoundException e) {
    +-                // Should not happen
    +-                Slog.wtf(TAG, "No ApplicationInfo for package " + pkg);
    ++                if (LOGD) Slog.d(TAG, "No ApplicationInfo for package " + pkg);
    ++                // Ignore it - some apps on allow-in-data-usage-save are optional.
    +                 continue;
    +             }
    +             if (!app.isPrivilegedApp()) {
    +-                Slog.wtf(TAG, "pm.getApplicationInfoAsUser() returned non-privileged app: " + pkg);
    ++                Slog.e(TAG, "addDefaultRestrictBackgroundWhitelistUidsUL(): "
    ++                        + "skipping non-privileged app  " + pkg);
    +                 continue;
    +             }
    +             final int uid = UserHandle.getUid(userId, app.uid);
    +@@ -528,8 +528,9 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
    +                         + "background whitelist. Revoked status: "
    +                         + mRestrictBackgroundWhitelistRevokedUids.get(uid));
    +             if (!mRestrictBackgroundWhitelistRevokedUids.get(uid)) {
    +-                Slog.i(TAG, "adding default package " + pkg + " (uid " + uid + " for user "
    +-                        + userId + ") to restrict background whitelist");
    ++                if (LOGD)
    ++                    Slog.d(TAG, "adding default package " + pkg + " (uid " + uid + " for user "
    ++                            + userId + ") to restrict background whitelist");
    +                 mRestrictBackgroundWhitelistUids.append(uid, true);
    +                 changed = true;
    +             }
    +@@ -568,117 +569,125 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
    +     }
    + 
    +     public void systemReady() {
    +-        if (!isBandwidthControlEnabled()) {
    +-            Slog.w(TAG, "bandwidth controls disabled, unable to enforce policy");
    +-            return;
    +-        }
    +-
    +-        mUsageStats = LocalServices.getService(UsageStatsManagerInternal.class);
    ++        Trace.traceBegin(Trace.TRACE_TAG_NETWORK, "systemReady");
    ++        try {
    ++            if (!isBandwidthControlEnabled()) {
    ++                Slog.w(TAG, "bandwidth controls disabled, unable to enforce policy");
    ++                return;
    ++            }
    + 
    +-        mPackageMonitor.register(mContext, mHandler.getLooper(), UserHandle.ALL, true);
    ++            mUsageStats = LocalServices.getService(UsageStatsManagerInternal.class);
    + 
    +-        synchronized (mUidRulesFirstLock) {
    +-            synchronized (mNetworkPoliciesSecondLock) {
    +-                updatePowerSaveWhitelistUL();
    +-                mPowerManagerInternal = LocalServices.getService(PowerManagerInternal.class);
    +-                mPowerManagerInternal.registerLowPowerModeObserver(
    +-                        new PowerManagerInternal.LowPowerModeListener() {
    +-                    @Override
    +-                    public void onLowPowerModeChanged(boolean enabled) {
    +-                        if (LOGD) Slog.d(TAG, "onLowPowerModeChanged(" + enabled + ")");
    +-                        synchronized (mUidRulesFirstLock) {
    +-                            if (mRestrictPower != enabled) {
    +-                                mRestrictPower = enabled;
    +-                                updateRulesForRestrictPowerUL();
    ++            synchronized (mUidRulesFirstLock) {
    ++                synchronized (mNetworkPoliciesSecondLock) {
    ++                    updatePowerSaveWhitelistUL();
    ++                    mPowerManagerInternal = LocalServices.getService(PowerManagerInternal.class);
    ++                    mPowerManagerInternal.registerLowPowerModeObserver(
    ++                            new PowerManagerInternal.LowPowerModeListener() {
    ++                        @Override
    ++                        public void onLowPowerModeChanged(boolean enabled) {
    ++                            if (LOGD) Slog.d(TAG, "onLowPowerModeChanged(" + enabled + ")");
    ++                            synchronized (mUidRulesFirstLock) {
    ++                                if (mRestrictPower != enabled) {
    ++                                    mRestrictPower = enabled;
    ++                                    updateRulesForRestrictPowerUL();
    ++                                }
    +                             }
    +                         }
    +-                    }
    +-                });
    +-                mRestrictPower = mPowerManagerInternal.getLowPowerModeEnabled();
    ++                    });
    ++                    mRestrictPower = mPowerManagerInternal.getLowPowerModeEnabled();
    + 
    +-                mSystemReady = true;
    ++                    mSystemReady = true;
    + 
    +-                // read policy from disk
    +-                readPolicyAL();
    ++                    // read policy from disk
    ++                    readPolicyAL();
    + 
    +-                if (addDefaultRestrictBackgroundWhitelistUidsUL()) {
    +-                    writePolicyAL();
    +-                }
    ++                    if (addDefaultRestrictBackgroundWhitelistUidsUL()) {
    ++                        writePolicyAL();
    ++                    }
    + 
    +-                setRestrictBackgroundUL(mRestrictBackground);
    +-                updateRulesForGlobalChangeAL(false);
    +-                updateNotificationsNL();
    ++                    setRestrictBackgroundUL(mRestrictBackground);
    ++                    updateRulesForGlobalChangeAL(false);
    ++                    updateNotificationsNL();
    ++                }
    +             }
    +-        }
    + 
    +-        try {
    +-            mActivityManager.registerUidObserver(mUidObserver,
    +-                    ActivityManager.UID_OBSERVER_PROCSTATE|ActivityManager.UID_OBSERVER_GONE);
    +-            mNetworkManager.registerObserver(mAlertObserver);
    +-        } catch (RemoteException e) {
    +-            // ignored; both services live in system_server
    ++            try {
    ++                mActivityManager.registerUidObserver(mUidObserver,
    ++                        ActivityManager.UID_OBSERVER_PROCSTATE|ActivityManager.UID_OBSERVER_GONE);
    ++                mNetworkManager.registerObserver(mAlertObserver);
    ++            } catch (RemoteException e) {
    ++                // ignored; both services live in system_server
    ++            }
    ++
    ++            // listen for changes to power save whitelist
    ++            final IntentFilter whitelistFilter = new IntentFilter(
    ++                    PowerManager.ACTION_POWER_SAVE_WHITELIST_CHANGED);
    ++            mContext.registerReceiver(mPowerSaveWhitelistReceiver, whitelistFilter, null, mHandler);
    ++
    ++            DeviceIdleController.LocalService deviceIdleService
    ++                    = LocalServices.getService(DeviceIdleController.LocalService.class);
    ++            deviceIdleService.setNetworkPolicyTempWhitelistCallback(mTempPowerSaveChangedCallback);
    ++
    ++            // watch for network interfaces to be claimed
    ++            final IntentFilter connFilter = new IntentFilter(CONNECTIVITY_ACTION);
    ++            mContext.registerReceiver(mConnReceiver, connFilter, CONNECTIVITY_INTERNAL, mHandler);
    ++
    ++            // listen for package changes to update policy
    ++            final IntentFilter packageFilter = new IntentFilter();
    ++            packageFilter.addAction(ACTION_PACKAGE_ADDED);
    ++            packageFilter.addDataScheme("package");
    ++            mContext.registerReceiver(mPackageReceiver, packageFilter, null, mHandler);
    ++
    ++            // listen for UID changes to update policy
    ++            mContext.registerReceiver(
    ++                    mUidRemovedReceiver, new IntentFilter(ACTION_UID_REMOVED), null, mHandler);
    ++
    ++            // listen for user changes to update policy
    ++            final IntentFilter userFilter = new IntentFilter();
    ++            userFilter.addAction(ACTION_USER_ADDED);
    ++            userFilter.addAction(ACTION_USER_REMOVED);
    ++            mContext.registerReceiver(mUserReceiver, userFilter, null, mHandler);
    ++
    ++            // listen for stats update events
    ++            final IntentFilter statsFilter = new IntentFilter(ACTION_NETWORK_STATS_UPDATED);
    ++            mContext.registerReceiver(
    ++                    mStatsReceiver, statsFilter, READ_NETWORK_USAGE_HISTORY, mHandler);
    ++
    ++            // listen for restrict background changes from notifications
    ++            final IntentFilter allowFilter = new IntentFilter(ACTION_ALLOW_BACKGROUND);
    ++            mContext.registerReceiver(mAllowReceiver, allowFilter, MANAGE_NETWORK_POLICY, mHandler);
    ++
    ++            // listen for snooze warning from notifications
    ++            final IntentFilter snoozeWarningFilter = new IntentFilter(ACTION_SNOOZE_WARNING);
    ++            mContext.registerReceiver(mSnoozeWarningReceiver, snoozeWarningFilter,
    ++                    MANAGE_NETWORK_POLICY, mHandler);
    ++
    ++            // listen for configured wifi networks to be removed
    ++            final IntentFilter wifiConfigFilter =
    ++                    new IntentFilter(CONFIGURED_NETWORKS_CHANGED_ACTION);
    ++            mContext.registerReceiver(mWifiConfigReceiver, wifiConfigFilter, null, mHandler);
    ++
    ++            // listen for wifi state changes to catch metered hint
    ++            final IntentFilter wifiStateFilter = new IntentFilter(
    ++                    WifiManager.NETWORK_STATE_CHANGED_ACTION);
    ++            mContext.registerReceiver(mWifiStateReceiver, wifiStateFilter, null, mHandler);
    ++
    ++            mUsageStats.addAppIdleStateChangeListener(new AppIdleStateChangeListener());
    ++        } finally {
    ++            Trace.traceEnd(Trace.TRACE_TAG_NETWORK);
    +         }
    +-
    +-        // listen for changes to power save whitelist
    +-        final IntentFilter whitelistFilter = new IntentFilter(
    +-                PowerManager.ACTION_POWER_SAVE_WHITELIST_CHANGED);
    +-        mContext.registerReceiver(mPowerSaveWhitelistReceiver, whitelistFilter, null, mHandler);
    +-
    +-        DeviceIdleController.LocalService deviceIdleService
    +-                = LocalServices.getService(DeviceIdleController.LocalService.class);
    +-        deviceIdleService.setNetworkPolicyTempWhitelistCallback(mTempPowerSaveChangedCallback);
    +-
    +-        // watch for network interfaces to be claimed
    +-        final IntentFilter connFilter = new IntentFilter(CONNECTIVITY_ACTION);
    +-        mContext.registerReceiver(mConnReceiver, connFilter, CONNECTIVITY_INTERNAL, mHandler);
    +-
    +-        // listen for package changes to update policy
    +-        final IntentFilter packageFilter = new IntentFilter();
    +-        packageFilter.addAction(ACTION_PACKAGE_ADDED);
    +-        packageFilter.addDataScheme("package");
    +-        mContext.registerReceiver(mPackageReceiver, packageFilter, null, mHandler);
    +-
    +-        // listen for UID changes to update policy
    +-        mContext.registerReceiver(
    +-                mUidRemovedReceiver, new IntentFilter(ACTION_UID_REMOVED), null, mHandler);
    +-
    +-        // listen for user changes to update policy
    +-        final IntentFilter userFilter = new IntentFilter();
    +-        userFilter.addAction(ACTION_USER_ADDED);
    +-        userFilter.addAction(ACTION_USER_REMOVED);
    +-        mContext.registerReceiver(mUserReceiver, userFilter, null, mHandler);
    +-
    +-        // listen for stats update events
    +-        final IntentFilter statsFilter = new IntentFilter(ACTION_NETWORK_STATS_UPDATED);
    +-        mContext.registerReceiver(
    +-                mStatsReceiver, statsFilter, READ_NETWORK_USAGE_HISTORY, mHandler);
    +-
    +-        // listen for restrict background changes from notifications
    +-        final IntentFilter allowFilter = new IntentFilter(ACTION_ALLOW_BACKGROUND);
    +-        mContext.registerReceiver(mAllowReceiver, allowFilter, MANAGE_NETWORK_POLICY, mHandler);
    +-
    +-        // listen for snooze warning from notifications
    +-        final IntentFilter snoozeWarningFilter = new IntentFilter(ACTION_SNOOZE_WARNING);
    +-        mContext.registerReceiver(mSnoozeWarningReceiver, snoozeWarningFilter,
    +-                MANAGE_NETWORK_POLICY, mHandler);
    +-
    +-        // listen for configured wifi networks to be removed
    +-        final IntentFilter wifiConfigFilter = new IntentFilter(CONFIGURED_NETWORKS_CHANGED_ACTION);
    +-        mContext.registerReceiver(mWifiConfigReceiver, wifiConfigFilter, null, mHandler);
    +-
    +-        // listen for wifi state changes to catch metered hint
    +-        final IntentFilter wifiStateFilter = new IntentFilter(
    +-                WifiManager.NETWORK_STATE_CHANGED_ACTION);
    +-        mContext.registerReceiver(mWifiStateReceiver, wifiStateFilter, null, mHandler);
    +-
    +-        mUsageStats.addAppIdleStateChangeListener(new AppIdleStateChangeListener());
    +-
    +     }
    + 
    +     final private IUidObserver mUidObserver = new IUidObserver.Stub() {
    +         @Override public void onUidStateChanged(int uid, int procState) throws RemoteException {
    +-            synchronized (mUidRulesFirstLock) {
    +-                updateUidStateUL(uid, procState);
    ++            Trace.traceBegin(Trace.TRACE_TAG_NETWORK, "onUidStateChanged");
    ++            try {
    ++                synchronized (mUidRulesFirstLock) {
    ++                    updateUidStateUL(uid, procState);
    ++                }
    ++            } finally {
    ++                Trace.traceEnd(Trace.TRACE_TAG_NETWORK);
    +             }
    +         }
    + 
    +@@ -702,6 +711,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
    +             synchronized (mUidRulesFirstLock) {
    +                 updatePowerSaveWhitelistUL();
    +                 updateRulesForRestrictPowerUL();
    ++                updateRulesForAppIdleUL();
    +             }
    +         }
    +     };
    +@@ -749,6 +759,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
    +             if (LOGV) Slog.v(TAG, "ACTION_UID_REMOVED for uid=" + uid);
    +             synchronized (mUidRulesFirstLock) {
    +                 mUidPolicy.delete(uid);
    ++                removeRestrictBackgroundWhitelistedUidUL(uid, true, true);
    +                 updateRestrictionRulesForUidUL(uid);
    +                 synchronized (mNetworkPoliciesSecondLock) {
    +                     writePolicyAL();
    +@@ -1426,8 +1437,14 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
    +                 + "; generating default policy");
    + 
    +         // Build default mobile policy, and assume usage cycle starts today
    +-        final long warningBytes = mContext.getResources().getInteger(
    +-                com.android.internal.R.integer.config_networkPolicyDefaultWarning) * MB_IN_BYTES;
    ++        final int dataWarningConfig = mContext.getResources().getInteger(
    ++                com.android.internal.R.integer.config_networkPolicyDefaultWarning);
    ++        final long warningBytes;
    ++        if (dataWarningConfig == WARNING_DISABLED) {
    ++            warningBytes = WARNING_DISABLED;
    ++        } else {
    ++            warningBytes = dataWarningConfig * MB_IN_BYTES;
    ++        }
    + 
    +         final Time time = new Time();
    +         time.setToNow();
    +@@ -2044,7 +2061,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
    +         // Must whitelist foreground apps before turning data saver mode on.
    +         // TODO: there is no need to iterate through all apps here, just those in the foreground,
    +         // so it could call AM to get the UIDs of such apps, and iterate through them instead.
    +-        updateRulesForAllAppsUL(TYPE_RESTRICT_BACKGROUND);
    ++        updateRulesForRestrictBackgroundUL();
    +         try {
    +             if (!mNetworkManager.setDataSaverModeEnabled(mRestrictBackground)) {
    +                 Slog.e(TAG, "Could not change Data Saver Mode on NMS to " + mRestrictBackground);
    +@@ -2201,21 +2218,26 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
    +     @Override
    +     public void setDeviceIdleMode(boolean enabled) {
    +         mContext.enforceCallingOrSelfPermission(MANAGE_NETWORK_POLICY, TAG);
    +-
    +-        synchronized (mUidRulesFirstLock) {
    +-            if (mDeviceIdleMode != enabled) {
    ++        Trace.traceBegin(Trace.TRACE_TAG_NETWORK, "setDeviceIdleMode");
    ++        try {
    ++            synchronized (mUidRulesFirstLock) {
    ++                if (mDeviceIdleMode == enabled) {
    ++                    return;
    ++                }
    +                 mDeviceIdleMode = enabled;
    +                 if (mSystemReady) {
    +                     // Device idle change means we need to rebuild rules for all
    +                     // known apps, so do a global refresh.
    +                     updateRulesForRestrictPowerUL();
    +                 }
    +-                if (enabled) {
    +-                    EventLogTags.writeDeviceIdleOnPhase("net");
    +-                } else {
    +-                    EventLogTags.writeDeviceIdleOffPhase("net");
    +-                }
    +             }
    ++            if (enabled) {
    ++                EventLogTags.writeDeviceIdleOnPhase("net");
    ++            } else {
    ++                EventLogTags.writeDeviceIdleOffPhase("net");
    ++            }
    ++        } finally {
    ++            Trace.traceEnd(Trace.TRACE_TAG_NETWORK);
    +         }
    +     }
    + 
    +@@ -2503,25 +2525,30 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
    +      * {@link #updateRulesForPowerRestrictionsUL(int)}
    +      */
    +     private void updateUidStateUL(int uid, int uidState) {
    +-        final int oldUidState = mUidState.get(uid, ActivityManager.PROCESS_STATE_CACHED_EMPTY);
    +-        if (oldUidState != uidState) {
    +-            // state changed, push updated rules
    +-            mUidState.put(uid, uidState);
    +-            updateRestrictBackgroundRulesOnUidStatusChangedUL(uid, oldUidState, uidState);
    +-            if (isProcStateAllowedWhileIdleOrPowerSaveMode(oldUidState)
    +-                    != isProcStateAllowedWhileIdleOrPowerSaveMode(uidState) ) {
    +-                if (isUidIdle(uid)) {
    +-                    updateRuleForAppIdleUL(uid);
    +-                }
    +-                if (mDeviceIdleMode) {
    +-                    updateRuleForDeviceIdleUL(uid);
    +-                }
    +-                if (mRestrictPower) {
    +-                    updateRuleForRestrictPowerUL(uid);
    ++        Trace.traceBegin(Trace.TRACE_TAG_NETWORK, "updateUidStateUL");
    ++        try {
    ++            final int oldUidState = mUidState.get(uid, ActivityManager.PROCESS_STATE_CACHED_EMPTY);
    ++            if (oldUidState != uidState) {
    ++                // state changed, push updated rules
    ++                mUidState.put(uid, uidState);
    ++                updateRestrictBackgroundRulesOnUidStatusChangedUL(uid, oldUidState, uidState);
    ++                if (isProcStateAllowedWhileIdleOrPowerSaveMode(oldUidState)
    ++                        != isProcStateAllowedWhileIdleOrPowerSaveMode(uidState) ) {
    ++                    if (isUidIdle(uid)) {
    ++                        updateRuleForAppIdleUL(uid);
    ++                    }
    ++                    if (mDeviceIdleMode) {
    ++                        updateRuleForDeviceIdleUL(uid);
    ++                    }
    ++                    if (mRestrictPower) {
    ++                        updateRuleForRestrictPowerUL(uid);
    ++                    }
    ++                    updateRulesForPowerRestrictionsUL(uid);
    +                 }
    +-                updateRulesForPowerRestrictionsUL(uid);
    ++                updateNetworkStats(uid, isUidStateForegroundUL(uidState));
    +             }
    +-            updateNetworkStats(uid, isUidStateForegroundUL(uidState));
    ++        } finally {
    ++            Trace.traceEnd(Trace.TRACE_TAG_NETWORK);
    +         }
    +     }
    + 
    +@@ -2574,8 +2601,13 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
    +     }
    + 
    +     void updateRulesForPowerSaveUL() {
    +-        updateRulesForWhitelistedPowerSaveUL(mRestrictPower, FIREWALL_CHAIN_POWERSAVE,
    +-                mUidFirewallPowerSaveRules);
    ++        Trace.traceBegin(Trace.TRACE_TAG_NETWORK, "updateRulesForPowerSaveUL");
    ++        try {
    ++            updateRulesForWhitelistedPowerSaveUL(mRestrictPower, FIREWALL_CHAIN_POWERSAVE,
    ++                    mUidFirewallPowerSaveRules);
    ++        } finally {
    ++            Trace.traceEnd(Trace.TRACE_TAG_NETWORK);
    ++        }
    +     }
    + 
    +     void updateRuleForRestrictPowerUL(int uid) {
    +@@ -2583,8 +2615,13 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
    +     }
    + 
    +     void updateRulesForDeviceIdleUL() {
    +-        updateRulesForWhitelistedPowerSaveUL(mDeviceIdleMode, FIREWALL_CHAIN_DOZABLE,
    +-                mUidFirewallDozableRules);
    ++        Trace.traceBegin(Trace.TRACE_TAG_NETWORK, "updateRulesForDeviceIdleUL");
    ++        try {
    ++            updateRulesForWhitelistedPowerSaveUL(mDeviceIdleMode, FIREWALL_CHAIN_DOZABLE,
    ++                    mUidFirewallDozableRules);
    ++        } finally {
    ++            Trace.traceEnd(Trace.TRACE_TAG_NETWORK);
    ++        }
    +     }
    + 
    +     void updateRuleForDeviceIdleUL(int uid) {
    +@@ -2621,10 +2658,10 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
    +                     uidRules.put(mUidState.keyAt(i), FIREWALL_RULE_ALLOW);
    +                 }
    +             }
    +-            setUidFirewallRules(chain, uidRules);
    ++            setUidFirewallRulesAsync(chain, uidRules, CHAIN_TOGGLE_ENABLE);
    ++        } else {
    ++            setUidFirewallRulesAsync(chain, null, CHAIN_TOGGLE_DISABLE);
    +         }
    +-
    +-        enableFirewallChainUL(chain, enabled);
    +     }
    + 
    +     private boolean isWhitelistedBatterySaverUL(int uid) {
    +@@ -2646,27 +2683,32 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
    +     }
    + 
    +     void updateRulesForAppIdleUL() {
    +-        final SparseIntArray uidRules = mUidFirewallStandbyRules;
    +-        uidRules.clear();
    ++        Trace.traceBegin(Trace.TRACE_TAG_NETWORK, "updateRulesForAppIdleUL");
    ++        try {
    ++            final SparseIntArray uidRules = mUidFirewallStandbyRules;
    ++            uidRules.clear();
    + 
    +-        // Fully update the app idle firewall chain.
    +-        final List<UserInfo> users = mUserManager.getUsers();
    +-        for (int ui = users.size() - 1; ui >= 0; ui--) {
    +-            UserInfo user = users.get(ui);
    +-            int[] idleUids = mUsageStats.getIdleUidsForUser(user.id);
    +-            for (int uid : idleUids) {
    +-                if (!mPowerSaveTempWhitelistAppIds.get(UserHandle.getAppId(uid), false)) {
    +-                    // quick check: if this uid doesn't have INTERNET permission, it
    +-                    // doesn't have network access anyway, so it is a waste to mess
    +-                    // with it here.
    +-                    if (hasInternetPermissions(uid)) {
    +-                        uidRules.put(uid, FIREWALL_RULE_DENY);
    ++            // Fully update the app idle firewall chain.
    ++            final List<UserInfo> users = mUserManager.getUsers();
    ++            for (int ui = users.size() - 1; ui >= 0; ui--) {
    ++                UserInfo user = users.get(ui);
    ++                int[] idleUids = mUsageStats.getIdleUidsForUser(user.id);
    ++                for (int uid : idleUids) {
    ++                    if (!mPowerSaveTempWhitelistAppIds.get(UserHandle.getAppId(uid), false)) {
    ++                        // quick check: if this uid doesn't have INTERNET permission, it
    ++                        // doesn't have network access anyway, so it is a waste to mess
    ++                        // with it here.
    ++                        if (hasInternetPermissions(uid)) {
    ++                            uidRules.put(uid, FIREWALL_RULE_DENY);
    ++                        }
    +                     }
    +                 }
    +             }
    +-        }
    + 
    +-        setUidFirewallRules(FIREWALL_CHAIN_STANDBY, uidRules);
    ++            setUidFirewallRulesAsync(FIREWALL_CHAIN_STANDBY, uidRules, CHAIN_TOGGLE_NONE);
    ++        } finally {
    ++            Trace.traceEnd(Trace.TRACE_TAG_NETWORK);
    ++        }
    +     }
    + 
    +     void updateRuleForAppIdleUL(int uid) {
    +@@ -2681,9 +2723,31 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
    +         }
    +     }
    + 
    ++    /**
    ++     * Toggle the firewall standby chain and inform listeners if the uid rules have effectively
    ++     * changed.
    ++     */
    +     void updateRulesForAppIdleParoleUL() {
    +-        boolean enableChain = !mUsageStats.isAppIdleParoleOn();
    ++        boolean paroled = mUsageStats.isAppIdleParoleOn();
    ++        boolean enableChain = !paroled;
    +         enableFirewallChainUL(FIREWALL_CHAIN_STANDBY, enableChain);
    ++
    ++        int ruleCount = mUidFirewallStandbyRules.size();
    ++        for (int i = 0; i < ruleCount; i++) {
    ++            int uid = mUidFirewallStandbyRules.keyAt(i);
    ++            int oldRules = mUidRules.get(uid);
    ++            if (enableChain) {
    ++                // Chain wasn't enabled before and the other power-related
    ++                // chains are whitelists, so we can clear the
    ++                // MASK_ALL_NETWORKS part of the rules and re-inform listeners if
    ++                // the effective rules result in blocking network access.
    ++                oldRules &= MASK_METERED_NETWORKS;
    ++            } else {
    ++                // Skip if it had no restrictions to begin with
    ++                if ((oldRules & MASK_ALL_NETWORKS) == 0) continue;
    ++            }
    ++            updateRulesForPowerRestrictionsUL(uid, oldRules, paroled);
    ++        }
    +     }
    + 
    +     /**
    +@@ -2691,33 +2755,41 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
    +      * {@link #mRestrictPower}, or {@link #mDeviceIdleMode} value.
    +      */
    +     private void updateRulesForGlobalChangeAL(boolean restrictedNetworksChanged) {
    +-        long start;
    +-        if (LOGD) start = System.currentTimeMillis();
    +-
    +-        updateRulesForRestrictPowerUL();
    +-        updateRulesForRestrictBackgroundUL();
    ++        Trace.traceBegin(Trace.TRACE_TAG_NETWORK, "updateRulesForGlobalChangeAL");
    ++        try {
    ++            updateRulesForAppIdleUL();
    ++            updateRulesForRestrictPowerUL();
    ++            updateRulesForRestrictBackgroundUL();
    + 
    +-        // If the set of restricted networks may have changed, re-evaluate those.
    +-        if (restrictedNetworksChanged) {
    +-            normalizePoliciesNL();
    +-            updateNetworkRulesNL();
    +-        }
    +-        if (LOGD) {
    +-            final long delta = System.currentTimeMillis() - start;
    +-            Slog.d(TAG, "updateRulesForGlobalChangeAL(" + restrictedNetworksChanged + ") took "
    +-                    + delta + "ms");
    ++            // If the set of restricted networks may have changed, re-evaluate those.
    ++            if (restrictedNetworksChanged) {
    ++                normalizePoliciesNL();
    ++                updateNetworkRulesNL();
    ++            }
    ++        } finally {
    ++            Trace.traceEnd(Trace.TRACE_TAG_NETWORK);
    +         }
    +     }
    + 
    ++    // TODO: rename / document to make it clear these are global (not app-specific) rules
    +     private void updateRulesForRestrictPowerUL() {
    +-        updateRulesForDeviceIdleUL();
    +-        updateRulesForAppIdleUL();
    +-        updateRulesForPowerSaveUL();
    +-        updateRulesForAllAppsUL(TYPE_RESTRICT_POWER);
    ++        Trace.traceBegin(Trace.TRACE_TAG_NETWORK, "updateRulesForRestrictPowerUL");
    ++        try {
    ++            updateRulesForDeviceIdleUL();
    ++            updateRulesForPowerSaveUL();
    ++            updateRulesForAllAppsUL(TYPE_RESTRICT_POWER);
    ++        } finally {
    ++            Trace.traceEnd(Trace.TRACE_TAG_NETWORK);
    ++        }
    +     }
    + 
    +     private void updateRulesForRestrictBackgroundUL() {
    +-        updateRulesForAllAppsUL(TYPE_RESTRICT_BACKGROUND);
    ++        Trace.traceBegin(Trace.TRACE_TAG_NETWORK, "updateRulesForRestrictBackgroundUL");
    ++        try {
    ++            updateRulesForAllAppsUL(TYPE_RESTRICT_BACKGROUND);
    ++        } finally {
    ++            Trace.traceEnd(Trace.TRACE_TAG_NETWORK);
    ++        }
    +     }
    + 
    +     private static final int TYPE_RESTRICT_BACKGROUND = 1;
    +@@ -2732,33 +2804,42 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
    + 
    +     // TODO: refactor / consolidate all those updateXyz methods, there are way too many of them...
    +     private void updateRulesForAllAppsUL(@RestrictType int type) {
    +-        final PackageManager pm = mContext.getPackageManager();
    ++        if (Trace.isTagEnabled(Trace.TRACE_TAG_NETWORK)) {
    ++            Trace.traceBegin(Trace.TRACE_TAG_NETWORK, "updateRulesForRestrictPowerUL-" + type);
    ++        }
    ++        try {
    ++            final PackageManager pm = mContext.getPackageManager();
    + 
    +-        // update rules for all installed applications
    +-        final List<UserInfo> users = mUserManager.getUsers();
    +-        final List<ApplicationInfo> apps = pm.getInstalledApplications(
    +-                PackageManager.MATCH_UNINSTALLED_PACKAGES | PackageManager.MATCH_DISABLED_COMPONENTS
    +-                        | PackageManager.MATCH_DIRECT_BOOT_AWARE
    +-                        | PackageManager.MATCH_DIRECT_BOOT_UNAWARE);
    +-
    +-        final int usersSize = users.size();
    +-        final int appsSize = apps.size();
    +-        for (int i = 0; i < usersSize; i++) {
    +-            final UserInfo user = users.get(i);
    +-            for (int j = 0; j < appsSize; j++) {
    +-                final ApplicationInfo app = apps.get(j);
    +-                final int uid = UserHandle.getUid(user.id, app.uid);
    +-                switch (type) {
    +-                    case TYPE_RESTRICT_BACKGROUND:
    +-                        updateRulesForDataUsageRestrictionsUL(uid);
    +-                        break;
    +-                    case TYPE_RESTRICT_POWER:
    +-                        updateRulesForPowerRestrictionsUL(uid);
    +-                        break;
    +-                    default:
    +-                        Slog.w(TAG, "Invalid type for updateRulesForAllApps: " + type);
    ++            // update rules for all installed applications
    ++            final List<UserInfo> users = mUserManager.getUsers();
    ++            final List<ApplicationInfo> apps = pm.getInstalledApplications(
    ++                    PackageManager.MATCH_UNINSTALLED_PACKAGES | PackageManager.MATCH_DISABLED_COMPONENTS
    ++                            | PackageManager.MATCH_DIRECT_BOOT_AWARE
    ++                            | PackageManager.MATCH_DIRECT_BOOT_UNAWARE);
    ++
    ++            final int usersSize = users.size();
    ++            final int appsSize = apps.size();
    ++            for (int i = 0; i < usersSize; i++) {
    ++                final UserInfo user = users.get(i);
    ++                for (int j = 0; j < appsSize; j++) {
    ++                    final ApplicationInfo app = apps.get(j);
    ++                    final int uid = UserHandle.getUid(user.id, app.uid);
    ++                    switch (type) {
    ++                        case TYPE_RESTRICT_BACKGROUND:
    ++                            updateRulesForDataUsageRestrictionsUL(uid);
    ++                            break;
    ++                        case TYPE_RESTRICT_POWER:
    ++                            updateRulesForPowerRestrictionsUL(uid);
    ++                            break;
    ++                        default:
    ++                            Slog.w(TAG, "Invalid type for updateRulesForAllApps: " + type);
    ++                    }
    +                 }
    +             }
    ++        } finally {
    ++            if (Trace.isTagEnabled(Trace.TRACE_TAG_NETWORK)) {
    ++                Trace.traceEnd(Trace.TRACE_TAG_NETWORK);
    ++            }
    +         }
    +     }
    + 
    +@@ -3020,14 +3101,34 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
    +      * <strong>NOTE: </strong>This method does not update the firewall rules on {@code netd}.
    +      */
    +     private void updateRulesForPowerRestrictionsUL(int uid) {
    ++        final int oldUidRules = mUidRules.get(uid, RULE_NONE);
    ++
    ++        final int newUidRules = updateRulesForPowerRestrictionsUL(uid, oldUidRules, false);
    ++
    ++        if (newUidRules == RULE_NONE) {
    ++            mUidRules.delete(uid);
    ++        } else {
    ++            mUidRules.put(uid, newUidRules);
    ++        }
    ++    }
    ++
    ++    /**
    ++     * Similar to above but ignores idle state if app standby is currently disabled by parole.
    ++     *
    ++     * @param uid the uid of the app to update rules for
    ++     * @param oldUidRules the current rules for the uid, in order to determine if there's a change
    ++     * @param paroled whether to ignore idle state of apps and only look at other restrictions.
    ++     *
    ++     * @return the new computed rules for the uid
    ++     */
    ++    private int updateRulesForPowerRestrictionsUL(int uid, int oldUidRules, boolean paroled) {
    +         if (!isUidValidForBlacklistRules(uid)) {
    +             if (LOGD) Slog.d(TAG, "no need to update restrict power rules for uid " + uid);
    +-            return;
    ++            return RULE_NONE;
    +         }
    + 
    +-        final boolean isIdle = isUidIdle(uid);
    ++        final boolean isIdle = !paroled && isUidIdle(uid);
    +         final boolean restrictMode = isIdle || mRestrictPower || mDeviceIdleMode;
    +-        final int oldUidRules = mUidRules.get(uid, RULE_NONE);
    +         final boolean isForeground = isUidForegroundOnRestrictPowerUL(uid);
    + 
    +         final boolean isWhitelisted = isWhitelistedBatterySaverUL(uid);
    +@@ -3061,12 +3162,6 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
    +                     + ", oldUidRules=" + uidRulesToString(oldUidRules));
    +         }
    + 
    +-        if (newUidRules == RULE_NONE) {
    +-            mUidRules.delete(uid);
    +-        } else {
    +-            mUidRules.put(uid, newUidRules);
    +-        }
    +-
    +         // Second step: notify listeners if state changed.
    +         if (newRule != oldRule) {
    +             if (newRule == RULE_NONE || (newRule & RULE_ALLOW_ALL) != 0) {
    +@@ -3083,6 +3178,8 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
    +             }
    +             mHandler.obtainMessage(MSG_RULES_CHANGED, uid, newUidRules).sendToTarget();
    +         }
    ++
    ++        return newUidRules;
    +     }
    + 
    +     private class AppIdleStateChangeListener
    +@@ -3302,6 +3399,18 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
    +                     removeInterfaceQuota((String) msg.obj);
    +                     return true;
    +                 }
    ++                case MSG_SET_FIREWALL_RULES: {
    ++                    final int chain = msg.arg1;
    ++                    final int toggle = msg.arg2;
    ++                    final SparseIntArray uidRules = (SparseIntArray) msg.obj;
    ++                    if (uidRules != null) {
    ++                        setUidFirewallRules(chain, uidRules);
    ++                    }
    ++                    if (toggle != CHAIN_TOGGLE_NONE) {
    ++                        enableFirewallChainUL(chain, toggle == CHAIN_TOGGLE_ENABLE);
    ++                    }
    ++                    return true;
    ++                }
    +                 default: {
    +                     return false;
    +                 }
    +@@ -3351,6 +3460,31 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
    +         }
    +     }
    + 
    ++    private static final int CHAIN_TOGGLE_NONE = 0;
    ++    private static final int CHAIN_TOGGLE_ENABLE = 1;
    ++    private static final int CHAIN_TOGGLE_DISABLE = 2;
    ++    @Retention(RetentionPolicy.SOURCE)
    ++    @IntDef(flag = false, value = {
    ++            CHAIN_TOGGLE_NONE,
    ++            CHAIN_TOGGLE_ENABLE,
    ++            CHAIN_TOGGLE_DISABLE
    ++    })
    ++    public @interface ChainToggleType {
    ++    }
    ++
    ++    /**
    ++     * Calls {@link #setUidFirewallRules(int, SparseIntArray)} and
    ++     * {@link #enableFirewallChainUL(int, boolean)} asynchronously.
    ++     *
    ++     * @param chain firewall chain.
    ++     * @param uidRules new UID rules; if {@code null}, only toggles chain state.
    ++     * @param toggle whether the chain should be enabled, disabled, or not changed.
    ++     */
    ++    private void setUidFirewallRulesAsync(int chain, @Nullable SparseIntArray uidRules,
    ++            @ChainToggleType int toggle) {
    ++        mHandler.obtainMessage(MSG_SET_FIREWALL_RULES, chain, toggle, uidRules).sendToTarget();
    ++    }
    ++
    +     /**
    +      * Set uid rules on a particular firewall chain. This is going to synchronize the rules given
    +      * here to netd.  It will clean up dead rules and make sure the target chain only contains rules
    +@@ -3521,18 +3655,6 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
    +         }
    +     }
    + 
    +-    private class MyPackageMonitor extends PackageMonitor {
    +-
    +-        @Override
    +-        public void onPackageRemoved(String packageName, int uid) {
    +-            if (LOGV) Slog.v(TAG, "onPackageRemoved: " + packageName + " ->" + uid);
    +-            synchronized (mUidRulesFirstLock) {
    +-                removeRestrictBackgroundWhitelistedUidUL(uid, true, true);
    +-                updateRestrictionRulesForUidUL(uid);
    +-            }
    +-        }
    +-    }
    +-
    +     private class NetworkPolicyManagerInternalImpl extends NetworkPolicyManagerInternal {
    + 
    +         @Override
    +diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
    +index bb55240..eb85f19 100644
    +--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
    ++++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
    +@@ -58,7 +58,6 @@ import android.app.Notification;
    + import android.app.NotificationManager;
    + import android.app.NotificationManager.Policy;
    + import android.app.PendingIntent;
    +-import android.app.RemoteInput;
    + import android.app.StatusBarManager;
    + import android.app.backup.BackupManager;
    + import android.app.usage.UsageEvents;
    +@@ -93,7 +92,6 @@ import android.os.IBinder;
    + import android.os.IInterface;
    + import android.os.Looper;
    + import android.os.Message;
    +-import android.os.Parcelable;
    + import android.os.Process;
    + import android.os.RemoteException;
    + import android.os.SystemClock;
    +@@ -122,6 +120,8 @@ import android.util.Log;
    + import android.util.Slog;
    + import android.util.SparseArray;
    + import android.util.Xml;
    ++import android.view.WindowManager;
    ++import android.view.WindowManagerInternal;
    + import android.view.accessibility.AccessibilityEvent;
    + import android.view.accessibility.AccessibilityManager;
    + import android.widget.Toast;
    +@@ -138,6 +138,7 @@ import com.android.server.SystemService;
    + import com.android.server.lights.Light;
    + import com.android.server.lights.LightsManager;
    + import com.android.server.notification.ManagedServices.ManagedServiceInfo;
    ++import com.android.server.policy.PhoneWindowManager;
    + import com.android.server.statusbar.StatusBarManagerInternal;
    + import com.android.server.vr.VrManagerInternal;
    + import com.android.server.notification.ManagedServices.UserProfiles;
    +@@ -193,7 +194,7 @@ public class NotificationManagerService extends SystemService {
    +     private static final int MESSAGE_RECONSIDER_RANKING = 1000;
    +     private static final int MESSAGE_RANKING_SORT = 1001;
    + 
    +-    static final int LONG_DELAY = 3500; // 3.5 seconds
    ++    static final int LONG_DELAY = PhoneWindowManager.TOAST_WINDOW_TIMEOUT;
    +     static final int SHORT_DELAY = 2000; // 2 seconds
    + 
    +     static final long[] DEFAULT_VIBRATE_PATTERN = {0, 250, 250, 250};
    +@@ -232,6 +233,7 @@ public class NotificationManagerService extends SystemService {
    +     @Nullable StatusBarManagerInternal mStatusBar;
    +     Vibrator mVibrator;
    +     private VrManagerInternal mVrManagerInternal;
    ++    private WindowManagerInternal mWindowManagerInternal;
    + 
    +     final IBinder mForegroundToken = new Binder();
    +     private Handler mHandler;
    +@@ -452,13 +454,15 @@ public class NotificationManagerService extends SystemService {
    +         final String pkg;
    +         final ITransientNotification callback;
    +         int duration;
    ++        Binder token;
    + 
    +-        ToastRecord(int pid, String pkg, ITransientNotification callback, int duration)
    +-        {
    ++        ToastRecord(int pid, String pkg, ITransientNotification callback, int duration,
    ++                    Binder token) {
    +             this.pid = pid;
    +             this.pkg = pkg;
    +             this.callback = callback;
    +             this.duration = duration;
    ++            this.token = token;
    +         }
    + 
    +         void update(int duration) {
    +@@ -1125,6 +1129,7 @@ public class NotificationManagerService extends SystemService {
    +             mAudioManager = (AudioManager) getContext().getSystemService(Context.AUDIO_SERVICE);
    +             mAudioManagerInternal = getLocalService(AudioManagerInternal.class);
    +             mVrManagerInternal = getLocalService(VrManagerInternal.class);
    ++            mWindowManagerInternal = LocalServices.getService(WindowManagerInternal.class);
    +             mZenModeHelper.onSystemReady();
    +         } else if (phase == SystemService.PHASE_THIRD_PARTY_APPS_CAN_START) {
    +             // This observer will force an update when observe is called, causing us to
    +@@ -1325,10 +1330,13 @@ public class NotificationManagerService extends SystemService {
    +                             }
    +                         }
    + 
    +-                        record = new ToastRecord(callingPid, pkg, callback, duration);
    ++                        Binder token = new Binder();
    ++                        mWindowManagerInternal.addWindowToken(token,
    ++                                WindowManager.LayoutParams.TYPE_TOAST);
    ++                        record = new ToastRecord(callingPid, pkg, callback, duration, token);
    +                         mToastQueue.add(record);
    +                         index = mToastQueue.size() - 1;
    +-                        keepProcessAliveLocked(callingPid);
    ++                        keepProcessAliveIfNeededLocked(callingPid);
    +                     }
    +                     // If it's at index 0, it's the current toast.  It doesn't matter if it's
    +                     // new or just been updated.  Call back and tell it to show itself.
    +@@ -2991,7 +2999,7 @@ public class NotificationManagerService extends SystemService {
    +         while (record != null) {
    +             if (DBG) Slog.d(TAG, "Show pkg=" + record.pkg + " callback=" + record.callback);
    +             try {
    +-                record.callback.show();
    ++                record.callback.show(record.token);
    +                 scheduleTimeoutLocked(record);
    +                 return;
    +             } catch (RemoteException e) {
    +@@ -3002,7 +3010,7 @@ public class NotificationManagerService extends SystemService {
    +                 if (index >= 0) {
    +                     mToastQueue.remove(index);
    +                 }
    +-                keepProcessAliveLocked(record.pid);
    ++                keepProcessAliveIfNeededLocked(record.pid);
    +                 if (mToastQueue.size() > 0) {
    +                     record = mToastQueue.get(0);
    +                 } else {
    +@@ -3022,8 +3030,11 @@ public class NotificationManagerService extends SystemService {
    +             // don't worry about this, we're about to remove it from
    +             // the list anyway
    +         }
    +-        mToastQueue.remove(index);
    +-        keepProcessAliveLocked(record.pid);
    ++
    ++        ToastRecord lastToast = mToastQueue.remove(index);
    ++        mWindowManagerInternal.removeWindowToken(lastToast.token, true);
    ++
    ++        keepProcessAliveIfNeededLocked(record.pid);
    +         if (mToastQueue.size() > 0) {
    +             // Show the next one. If the callback fails, this will remove
    +             // it from the list, so don't assume that the list hasn't changed
    +@@ -3067,7 +3078,7 @@ public class NotificationManagerService extends SystemService {
    +     }
    + 
    +     // lock on mToastQueue
    +-    void keepProcessAliveLocked(int pid)
    ++    void keepProcessAliveIfNeededLocked(int pid)
    +     {
    +         int toastCount = 0; // toasts from this pid
    +         ArrayList<ToastRecord> list = mToastQueue;
    +diff --git a/services/core/java/com/android/server/notification/ZenModeConditions.java b/services/core/java/com/android/server/notification/ZenModeConditions.java
    +index 1c12a96..40b0be2 100644
    +--- a/services/core/java/com/android/server/notification/ZenModeConditions.java
    ++++ b/services/core/java/com/android/server/notification/ZenModeConditions.java
    +@@ -99,7 +99,7 @@ public class ZenModeConditions implements ConditionProviders.Callback {
    +     @Override
    +     public void onServiceAdded(ComponentName component) {
    +         if (DEBUG) Log.d(TAG, "onServiceAdded " + component);
    +-        mHelper.setConfigAsync(mHelper.getConfig(), "zmc.onServiceAdded");
    ++        mHelper.setConfig(mHelper.getConfig(), "zmc.onServiceAdded");
    +     }
    + 
    +     @Override
    +@@ -113,7 +113,7 @@ public class ZenModeConditions implements ConditionProviders.Callback {
    +             updated |= updateSnoozing(automaticRule);
    +         }
    +         if (updated) {
    +-            mHelper.setConfigAsync(config, "conditionChanged");
    ++            mHelper.setConfig(config, "conditionChanged");
    +         }
    +     }
    + 
    +diff --git a/services/core/java/com/android/server/notification/ZenModeHelper.java b/services/core/java/com/android/server/notification/ZenModeHelper.java
    +index c22bfb3..15549d2 100644
    +--- a/services/core/java/com/android/server/notification/ZenModeHelper.java
    ++++ b/services/core/java/com/android/server/notification/ZenModeHelper.java
    +@@ -35,6 +35,7 @@ import android.content.pm.ServiceInfo;
    + import android.content.res.Resources;
    + import android.content.res.XmlResourceParser;
    + import android.database.ContentObserver;
    ++import android.media.AudioAttributes;
    + import android.media.AudioManager;
    + import android.media.AudioManagerInternal;
    + import android.media.AudioSystem;
    +@@ -619,8 +620,10 @@ public class ZenModeHelper {
    +         return setConfigLocked(config, reason, true /*setRingerMode*/);
    +     }
    + 
    +-    public void setConfigAsync(ZenModeConfig config, String reason) {
    +-        mHandler.postSetConfig(config, reason);
    ++    public void setConfig(ZenModeConfig config, String reason) {
    ++        synchronized (mConfig) {
    ++            setConfigLocked(config, reason);
    ++        }
    +     }
    + 
    +     private boolean setConfigLocked(ZenModeConfig config, String reason, boolean setRingerMode) {
    +@@ -736,13 +739,14 @@ public class ZenModeHelper {
    +         // total silence restrictions
    +         final boolean muteEverything = mZenMode == Global.ZEN_MODE_NO_INTERRUPTIONS;
    + 
    +-        for (int i = USAGE_UNKNOWN; i <= USAGE_VIRTUAL_SOURCE; i++) {
    +-            if (i == USAGE_NOTIFICATION) {
    +-                applyRestrictions(muteNotifications || muteEverything, i);
    +-            } else if (i == USAGE_NOTIFICATION_RINGTONE) {
    +-                applyRestrictions(muteCalls || muteEverything, i);
    ++        for (int usage : AudioAttributes.SDK_USAGES) {
    ++            final int suppressionBehavior = AudioAttributes.SUPPRESSIBLE_USAGES.get(usage);
    ++            if (suppressionBehavior == AudioAttributes.SUPPRESSIBLE_NOTIFICATION) {
    ++                applyRestrictions(muteNotifications || muteEverything, usage);
    ++            } else if (suppressionBehavior == AudioAttributes.SUPPRESSIBLE_CALL) {
    ++                applyRestrictions(muteCalls || muteEverything, usage);
    +             } else {
    +-                applyRestrictions(muteEverything, i);
    ++                applyRestrictions(muteEverything, usage);
    +             }
    +         }
    +     }
    +@@ -1082,7 +1086,6 @@ public class ZenModeHelper {
    +     private final class H extends Handler {
    +         private static final int MSG_DISPATCH = 1;
    +         private static final int MSG_METRICS = 2;
    +-        private static final int MSG_SET_CONFIG = 3;
    +         private static final int MSG_APPLY_CONFIG = 4;
    + 
    +         private final class ConfigMessageData {
    +@@ -1090,12 +1093,6 @@ public class ZenModeHelper {
    +             public final String reason;
    +             public final boolean setRingerMode;
    + 
    +-            ConfigMessageData(ZenModeConfig config, String reason) {
    +-                this.config = config;
    +-                this.reason = reason;
    +-                this.setRingerMode = false;
    +-            }
    +-
    +             ConfigMessageData(ZenModeConfig config, String reason, boolean setRingerMode) {
    +                 this.config = config;
    +                 this.reason = reason;
    +@@ -1119,10 +1116,6 @@ public class ZenModeHelper {
    +             sendEmptyMessageDelayed(MSG_METRICS, METRICS_PERIOD_MS);
    +         }
    + 
    +-        private void postSetConfig(ZenModeConfig config, String reason) {
    +-            sendMessage(obtainMessage(MSG_SET_CONFIG, new ConfigMessageData(config, reason)));
    +-        }
    +-
    +         private void postApplyConfig(ZenModeConfig config, String reason, boolean setRingerMode) {
    +             sendMessage(obtainMessage(MSG_APPLY_CONFIG,
    +                     new ConfigMessageData(config, reason, setRingerMode)));
    +@@ -1137,12 +1130,6 @@ public class ZenModeHelper {
    +                 case MSG_METRICS:
    +                     mMetrics.emit();
    +                     break;
    +-                case MSG_SET_CONFIG:
    +-                    ConfigMessageData configData = (ConfigMessageData) msg.obj;
    +-                    synchronized (mConfig) {
    +-                        setConfigLocked(configData.config, configData.reason);
    +-                    }
    +-                    break;
    +                 case MSG_APPLY_CONFIG:
    +                     ConfigMessageData applyConfigData = (ConfigMessageData) msg.obj;
    +                     applyConfig(applyConfigData.config, applyConfigData.reason,
    +diff --git a/services/core/java/com/android/server/pm/EphemeralResolverConnection.java b/services/core/java/com/android/server/pm/EphemeralResolverConnection.java
    +index 8d926f5..a6a3774 100644
    +--- a/services/core/java/com/android/server/pm/EphemeralResolverConnection.java
    ++++ b/services/core/java/com/android/server/pm/EphemeralResolverConnection.java
    +@@ -56,11 +56,12 @@ final class EphemeralResolverConnection {
    +     /** Intent used to bind to the service */
    +     private final Intent mIntent;
    + 
    ++    private volatile boolean mBindRequested;
    +     private IEphemeralResolver mRemoteInstance;
    + 
    +     public EphemeralResolverConnection(Context context, ComponentName componentName) {
    +         mContext = context;
    +-        mIntent = new Intent().setComponent(componentName);
    ++        mIntent = new Intent(Intent.ACTION_RESOLVE_EPHEMERAL_PACKAGE).setComponent(componentName);
    +     }
    + 
    +     public final List<EphemeralResolveInfo> getEphemeralResolveInfoList(
    +@@ -111,8 +112,11 @@ final class EphemeralResolverConnection {
    +             return;
    +         }
    + 
    +-        mContext.bindServiceAsUser(mIntent, mServiceConnection,
    +-                Context.BIND_AUTO_CREATE | Context.BIND_FOREGROUND_SERVICE, UserHandle.SYSTEM);
    ++        if (!mBindRequested) {
    ++            mBindRequested = true;
    ++            mContext.bindServiceAsUser(mIntent, mServiceConnection,
    ++                    Context.BIND_AUTO_CREATE | Context.BIND_FOREGROUND_SERVICE, UserHandle.SYSTEM);
    ++        }
    + 
    +         final long startMillis = SystemClock.uptimeMillis();
    +         while (true) {
    +diff --git a/services/core/java/com/android/server/pm/Installer.java b/services/core/java/com/android/server/pm/Installer.java
    +index 72c549f..2e18b1c 100644
    +--- a/services/core/java/com/android/server/pm/Installer.java
    ++++ b/services/core/java/com/android/server/pm/Installer.java
    +@@ -230,6 +230,11 @@ public final class Installer extends SystemService {
    +         mInstaller.execute("move_ab", apkPath, instructionSet, outputPath);
    +     }
    + 
    ++    public void deleteOdex(String apkPath, String instructionSet, String outputPath)
    ++            throws InstallerException {
    ++        mInstaller.execute("delete_odex", apkPath, instructionSet, outputPath);
    ++    }
    ++
    +     private static void assertValidInstructionSet(String instructionSet)
    +             throws InstallerException {
    +         for (String abi : Build.SUPPORTED_ABIS) {
    +diff --git a/services/core/java/com/android/server/pm/LauncherAppsService.java b/services/core/java/com/android/server/pm/LauncherAppsService.java
    +index 53e328c..4387e76 100644
    +--- a/services/core/java/com/android/server/pm/LauncherAppsService.java
    ++++ b/services/core/java/com/android/server/pm/LauncherAppsService.java
    +@@ -631,17 +631,20 @@ public class LauncherAppsService extends SystemService {
    +             public void onPackageAdded(String packageName, int uid) {
    +                 UserHandle user = new UserHandle(getChangingUserId());
    +                 final int n = mListeners.beginBroadcast();
    +-                for (int i = 0; i < n; i++) {
    +-                    IOnAppsChangedListener listener = mListeners.getBroadcastItem(i);
    +-                    BroadcastCookie cookie = (BroadcastCookie) mListeners.getBroadcastCookie(i);
    +-                    if (!isEnabledProfileOf(user, cookie.user, "onPackageAdded")) continue;
    +-                    try {
    +-                        listener.onPackageAdded(user, packageName);
    +-                    } catch (RemoteException re) {
    +-                        Slog.d(TAG, "Callback failed ", re);
    ++                try {
    ++                    for (int i = 0; i < n; i++) {
    ++                        IOnAppsChangedListener listener = mListeners.getBroadcastItem(i);
    ++                        BroadcastCookie cookie = (BroadcastCookie) mListeners.getBroadcastCookie(i);
    ++                        if (!isEnabledProfileOf(user, cookie.user, "onPackageAdded")) continue;
    ++                        try {
    ++                            listener.onPackageAdded(user, packageName);
    ++                        } catch (RemoteException re) {
    ++                            Slog.d(TAG, "Callback failed ", re);
    ++                        }
    +                     }
    ++                } finally {
    ++                    mListeners.finishBroadcast();
    +                 }
    +-                mListeners.finishBroadcast();
    + 
    +                 super.onPackageAdded(packageName, uid);
    +             }
    +@@ -650,17 +653,20 @@ public class LauncherAppsService extends SystemService {
    +             public void onPackageRemoved(String packageName, int uid) {
    +                 UserHandle user = new UserHandle(getChangingUserId());
    +                 final int n = mListeners.beginBroadcast();
    +-                for (int i = 0; i < n; i++) {
    +-                    IOnAppsChangedListener listener = mListeners.getBroadcastItem(i);
    +-                    BroadcastCookie cookie = (BroadcastCookie) mListeners.getBroadcastCookie(i);
    +-                    if (!isEnabledProfileOf(user, cookie.user, "onPackageRemoved")) continue;
    +-                    try {
    +-                        listener.onPackageRemoved(user, packageName);
    +-                    } catch (RemoteException re) {
    +-                        Slog.d(TAG, "Callback failed ", re);
    ++                try {
    ++                    for (int i = 0; i < n; i++) {
    ++                        IOnAppsChangedListener listener = mListeners.getBroadcastItem(i);
    ++                        BroadcastCookie cookie = (BroadcastCookie) mListeners.getBroadcastCookie(i);
    ++                        if (!isEnabledProfileOf(user, cookie.user, "onPackageRemoved")) continue;
    ++                        try {
    ++                            listener.onPackageRemoved(user, packageName);
    ++                        } catch (RemoteException re) {
    ++                            Slog.d(TAG, "Callback failed ", re);
    ++                        }
    +                     }
    ++                } finally {
    ++                    mListeners.finishBroadcast();
    +                 }
    +-                mListeners.finishBroadcast();
    + 
    +                 super.onPackageRemoved(packageName, uid);
    +             }
    +@@ -669,17 +675,20 @@ public class LauncherAppsService extends SystemService {
    +             public void onPackageModified(String packageName) {
    +                 UserHandle user = new UserHandle(getChangingUserId());
    +                 final int n = mListeners.beginBroadcast();
    +-                for (int i = 0; i < n; i++) {
    +-                    IOnAppsChangedListener listener = mListeners.getBroadcastItem(i);
    +-                    BroadcastCookie cookie = (BroadcastCookie) mListeners.getBroadcastCookie(i);
    +-                    if (!isEnabledProfileOf(user, cookie.user, "onPackageModified")) continue;
    +-                    try {
    +-                        listener.onPackageChanged(user, packageName);
    +-                    } catch (RemoteException re) {
    +-                        Slog.d(TAG, "Callback failed ", re);
    ++                try {
    ++                    for (int i = 0; i < n; i++) {
    ++                        IOnAppsChangedListener listener = mListeners.getBroadcastItem(i);
    ++                        BroadcastCookie cookie = (BroadcastCookie) mListeners.getBroadcastCookie(i);
    ++                        if (!isEnabledProfileOf(user, cookie.user, "onPackageModified")) continue;
    ++                        try {
    ++                            listener.onPackageChanged(user, packageName);
    ++                        } catch (RemoteException re) {
    ++                            Slog.d(TAG, "Callback failed ", re);
    ++                        }
    +                     }
    ++                } finally {
    ++                    mListeners.finishBroadcast();
    +                 }
    +-                mListeners.finishBroadcast();
    + 
    +                 super.onPackageModified(packageName);
    +             }
    +@@ -688,17 +697,20 @@ public class LauncherAppsService extends SystemService {
    +             public void onPackagesAvailable(String[] packages) {
    +                 UserHandle user = new UserHandle(getChangingUserId());
    +                 final int n = mListeners.beginBroadcast();
    +-                for (int i = 0; i < n; i++) {
    +-                    IOnAppsChangedListener listener = mListeners.getBroadcastItem(i);
    +-                    BroadcastCookie cookie = (BroadcastCookie) mListeners.getBroadcastCookie(i);
    +-                    if (!isEnabledProfileOf(user, cookie.user, "onPackagesAvailable")) continue;
    +-                    try {
    +-                        listener.onPackagesAvailable(user, packages, isReplacing());
    +-                    } catch (RemoteException re) {
    +-                        Slog.d(TAG, "Callback failed ", re);
    ++                try {
    ++                    for (int i = 0; i < n; i++) {
    ++                        IOnAppsChangedListener listener = mListeners.getBroadcastItem(i);
    ++                        BroadcastCookie cookie = (BroadcastCookie) mListeners.getBroadcastCookie(i);
    ++                        if (!isEnabledProfileOf(user, cookie.user, "onPackagesAvailable")) continue;
    ++                        try {
    ++                            listener.onPackagesAvailable(user, packages, isReplacing());
    ++                        } catch (RemoteException re) {
    ++                            Slog.d(TAG, "Callback failed ", re);
    ++                        }
    +                     }
    ++                } finally {
    ++                    mListeners.finishBroadcast();
    +                 }
    +-                mListeners.finishBroadcast();
    + 
    +                 super.onPackagesAvailable(packages);
    +             }
    +@@ -707,17 +719,20 @@ public class LauncherAppsService extends SystemService {
    +             public void onPackagesUnavailable(String[] packages) {
    +                 UserHandle user = new UserHandle(getChangingUserId());
    +                 final int n = mListeners.beginBroadcast();
    +-                for (int i = 0; i < n; i++) {
    +-                    IOnAppsChangedListener listener = mListeners.getBroadcastItem(i);
    +-                    BroadcastCookie cookie = (BroadcastCookie) mListeners.getBroadcastCookie(i);
    +-                    if (!isEnabledProfileOf(user, cookie.user, "onPackagesUnavailable")) continue;
    +-                    try {
    +-                        listener.onPackagesUnavailable(user, packages, isReplacing());
    +-                    } catch (RemoteException re) {
    +-                        Slog.d(TAG, "Callback failed ", re);
    ++                try {
    ++                    for (int i = 0; i < n; i++) {
    ++                        IOnAppsChangedListener listener = mListeners.getBroadcastItem(i);
    ++                        BroadcastCookie cookie = (BroadcastCookie) mListeners.getBroadcastCookie(i);
    ++                        if (!isEnabledProfileOf(user, cookie.user, "onPackagesUnavailable")) continue;
    ++                        try {
    ++                            listener.onPackagesUnavailable(user, packages, isReplacing());
    ++                        } catch (RemoteException re) {
    ++                            Slog.d(TAG, "Callback failed ", re);
    ++                        }
    +                     }
    ++                } finally {
    ++                    mListeners.finishBroadcast();
    +                 }
    +-                mListeners.finishBroadcast();
    + 
    +                 super.onPackagesUnavailable(packages);
    +             }
    +@@ -726,17 +741,20 @@ public class LauncherAppsService extends SystemService {
    +             public void onPackagesSuspended(String[] packages) {
    +                 UserHandle user = new UserHandle(getChangingUserId());
    +                 final int n = mListeners.beginBroadcast();
    +-                for (int i = 0; i < n; i++) {
    +-                    IOnAppsChangedListener listener = mListeners.getBroadcastItem(i);
    +-                    BroadcastCookie cookie = (BroadcastCookie) mListeners.getBroadcastCookie(i);
    +-                    if (!isEnabledProfileOf(user, cookie.user, "onPackagesSuspended")) continue;
    +-                    try {
    +-                        listener.onPackagesSuspended(user, packages);
    +-                    } catch (RemoteException re) {
    +-                        Slog.d(TAG, "Callback failed ", re);
    ++                try {
    ++                    for (int i = 0; i < n; i++) {
    ++                        IOnAppsChangedListener listener = mListeners.getBroadcastItem(i);
    ++                        BroadcastCookie cookie = (BroadcastCookie) mListeners.getBroadcastCookie(i);
    ++                        if (!isEnabledProfileOf(user, cookie.user, "onPackagesSuspended")) continue;
    ++                        try {
    ++                            listener.onPackagesSuspended(user, packages);
    ++                        } catch (RemoteException re) {
    ++                            Slog.d(TAG, "Callback failed ", re);
    ++                        }
    +                     }
    ++                } finally {
    ++                    mListeners.finishBroadcast();
    +                 }
    +-                mListeners.finishBroadcast();
    + 
    +                 super.onPackagesSuspended(packages);
    +             }
    +@@ -745,17 +763,20 @@ public class LauncherAppsService extends SystemService {
    +             public void onPackagesUnsuspended(String[] packages) {
    +                 UserHandle user = new UserHandle(getChangingUserId());
    +                 final int n = mListeners.beginBroadcast();
    +-                for (int i = 0; i < n; i++) {
    +-                    IOnAppsChangedListener listener = mListeners.getBroadcastItem(i);
    +-                    BroadcastCookie cookie = (BroadcastCookie) mListeners.getBroadcastCookie(i);
    +-                    if (!isEnabledProfileOf(user, cookie.user, "onPackagesUnsuspended")) continue;
    +-                    try {
    +-                        listener.onPackagesUnsuspended(user, packages);
    +-                    } catch (RemoteException re) {
    +-                        Slog.d(TAG, "Callback failed ", re);
    ++                try {
    ++                    for (int i = 0; i < n; i++) {
    ++                        IOnAppsChangedListener listener = mListeners.getBroadcastItem(i);
    ++                        BroadcastCookie cookie = (BroadcastCookie) mListeners.getBroadcastCookie(i);
    ++                        if (!isEnabledProfileOf(user, cookie.user, "onPackagesUnsuspended")) continue;
    ++                        try {
    ++                            listener.onPackagesUnsuspended(user, packages);
    ++                        } catch (RemoteException re) {
    ++                            Slog.d(TAG, "Callback failed ", re);
    ++                        }
    +                     }
    ++                } finally {
    ++                    mListeners.finishBroadcast();
    +                 }
    +-                mListeners.finishBroadcast();
    + 
    +                 super.onPackagesUnsuspended(packages);
    +             }
    +@@ -768,10 +789,10 @@ public class LauncherAppsService extends SystemService {
    + 
    +             private void onShortcutChangedInner(@NonNull String packageName,
    +                     @UserIdInt int userId) {
    ++                final int n = mListeners.beginBroadcast();
    +                 try {
    +                     final UserHandle user = UserHandle.of(userId);
    + 
    +-                    final int n = mListeners.beginBroadcast();
    +                     for (int i = 0; i < n; i++) {
    +                         IOnAppsChangedListener listener = mListeners.getBroadcastItem(i);
    +                         BroadcastCookie cookie = (BroadcastCookie) mListeners.getBroadcastCookie(i);
    +@@ -803,10 +824,11 @@ public class LauncherAppsService extends SystemService {
    +                             Slog.d(TAG, "Callback failed ", re);
    +                         }
    +                     }
    +-                    mListeners.finishBroadcast();
    +                 } catch (RuntimeException e) {
    +                     // When the user is locked we get IllegalState, so just catch all.
    +                     Log.w(TAG, e.getMessage(), e);
    ++                } finally {
    ++                    mListeners.finishBroadcast();
    +                 }
    +             }
    +         }
    +diff --git a/services/core/java/com/android/server/pm/OtaDexoptService.java b/services/core/java/com/android/server/pm/OtaDexoptService.java
    +index bff6d2d..689917c 100644
    +--- a/services/core/java/com/android/server/pm/OtaDexoptService.java
    ++++ b/services/core/java/com/android/server/pm/OtaDexoptService.java
    +@@ -31,7 +31,7 @@ import android.os.ServiceManager;
    + import android.os.storage.StorageManager;
    + import android.util.Log;
    + import android.util.Slog;
    +-
    ++import com.android.internal.logging.MetricsLogger;
    + import com.android.internal.os.InstallerConnection;
    + import com.android.internal.os.InstallerConnection.InstallerException;
    + 
    +@@ -40,6 +40,7 @@ import java.io.FileDescriptor;
    + import java.util.ArrayList;
    + import java.util.Collection;
    + import java.util.List;
    ++import java.util.concurrent.TimeUnit;
    + 
    + /**
    +  * A service for A/B OTA dexopting.
    +@@ -53,6 +54,10 @@ public class OtaDexoptService extends IOtaDexopt.Stub {
    +     // The synthetic library dependencies denoting "no checks."
    +     private final static String[] NO_LIBRARIES = new String[] { "&" };
    + 
    ++    // The amount of "available" (free - low threshold) space necessary at the start of an OTA to
    ++    // not bulk-delete unused apps' odex files.
    ++    private final static long BULK_DELETE_THRESHOLD = 1024 * 1024 * 1024;  // 1GB.
    ++
    +     private final Context mContext;
    +     private final PackageManagerService mPackageManagerService;
    + 
    +@@ -65,6 +70,25 @@ public class OtaDexoptService extends IOtaDexopt.Stub {
    + 
    +     private int completeSize;
    + 
    ++    // MetricsLogger properties.
    ++
    ++    // Space before and after.
    ++    private long availableSpaceBefore;
    ++    private long availableSpaceAfterBulkDelete;
    ++    private long availableSpaceAfterDexopt;
    ++
    ++    // Packages.
    ++    private int importantPackageCount;
    ++    private int otherPackageCount;
    ++
    ++    // Number of dexopt commands. This may be different from the count of packages.
    ++    private int dexoptCommandCountTotal;
    ++    private int dexoptCommandCountExecuted;
    ++
    ++    // For spent time.
    ++    private long otaDexoptTimeStart;
    ++
    ++
    +     public OtaDexoptService(Context context, PackageManagerService packageManagerService) {
    +         this.mContext = context;
    +         this.mPackageManagerService = packageManagerService;
    +@@ -128,6 +152,18 @@ public class OtaDexoptService extends IOtaDexopt.Stub {
    +                     generatePackageDexopts(p, PackageManagerService.REASON_FIRST_BOOT));
    +         }
    +         completeSize = mDexoptCommands.size();
    ++
    ++        long spaceAvailable = getAvailableSpace();
    ++        if (spaceAvailable < BULK_DELETE_THRESHOLD) {
    ++            Log.i(TAG, "Low on space, deleting oat files in an attempt to free up space: "
    ++                    + PackageManagerServiceUtils.packagesToString(others));
    ++            for (PackageParser.Package pkg : others) {
    ++                deleteOatArtifactsOfPackage(pkg);
    ++            }
    ++        }
    ++        long spaceAvailableNow = getAvailableSpace();
    ++
    ++        prepareMetricsLogging(important.size(), others.size(), spaceAvailable, spaceAvailableNow);
    +     }
    + 
    +     @Override
    +@@ -136,6 +172,9 @@ public class OtaDexoptService extends IOtaDexopt.Stub {
    +             Log.i(TAG, "Cleaning up OTA Dexopt state.");
    +         }
    +         mDexoptCommands = null;
    ++        availableSpaceAfterDexopt = getAvailableSpace();
    ++
    ++        performMetricsLogging();
    +     }
    + 
    +     @Override
    +@@ -169,28 +208,67 @@ public class OtaDexoptService extends IOtaDexopt.Stub {
    + 
    +         String next = mDexoptCommands.remove(0);
    + 
    +-        if (IsFreeSpaceAvailable()) {
    ++        if (getAvailableSpace() > 0) {
    ++            dexoptCommandCountExecuted++;
    ++
    +             return next;
    +         } else {
    ++            if (DEBUG_DEXOPT) {
    ++                Log.w(TAG, "Not enough space for OTA dexopt, stopping with "
    ++                        + (mDexoptCommands.size() + 1) + " commands left.");
    ++            }
    +             mDexoptCommands.clear();
    +             return "(no free space)";
    +         }
    +     }
    + 
    +-    /**
    +-     * Check for low space. Returns true if there's space left.
    +-     */
    +-    private boolean IsFreeSpaceAvailable() {
    +-        // TODO: If apps are not installed in the internal /data partition, we should compare
    +-        //       against that storage's free capacity.
    ++    private long getMainLowSpaceThreshold() {
    +         File dataDir = Environment.getDataDirectory();
    +         @SuppressWarnings("deprecation")
    +         long lowThreshold = StorageManager.from(mContext).getStorageLowBytes(dataDir);
    +         if (lowThreshold == 0) {
    +             throw new IllegalStateException("Invalid low memory threshold");
    +         }
    ++        return lowThreshold;
    ++    }
    ++
    ++    /**
    ++     * Returns the difference of free space to the low-storage-space threshold. Positive values
    ++     * indicate free bytes.
    ++     */
    ++    private long getAvailableSpace() {
    ++        // TODO: If apps are not installed in the internal /data partition, we should compare
    ++        //       against that storage's free capacity.
    ++        long lowThreshold = getMainLowSpaceThreshold();
    ++
    ++        File dataDir = Environment.getDataDirectory();
    +         long usableSpace = dataDir.getUsableSpace();
    +-        return (usableSpace >= lowThreshold);
    ++
    ++        return usableSpace - lowThreshold;
    ++    }
    ++
    ++    private static String getOatDir(PackageParser.Package pkg) {
    ++        if (!pkg.canHaveOatDir()) {
    ++            return null;
    ++        }
    ++        File codePath = new File(pkg.codePath);
    ++        if (codePath.isDirectory()) {
    ++            return PackageDexOptimizer.getOatDir(codePath).getAbsolutePath();
    ++        }
    ++        return null;
    ++    }
    ++
    ++    private void deleteOatArtifactsOfPackage(PackageParser.Package pkg) {
    ++        String[] instructionSets = getAppDexInstructionSets(pkg.applicationInfo);
    ++        for (String codePath : pkg.getAllCodePaths()) {
    ++            for (String isa : instructionSets) {
    ++                try {
    ++                    mPackageManagerService.mInstaller.deleteOdex(codePath, isa, getOatDir(pkg));
    ++                } catch (InstallerException e) {
    ++                    Log.e(TAG, "Failed deleting oat files for " + codePath, e);
    ++                }
    ++            }
    ++        }
    +     }
    + 
    +     /**
    +@@ -271,6 +349,55 @@ public class OtaDexoptService extends IOtaDexopt.Stub {
    +         }
    +     }
    + 
    ++    /**
    ++     * Initialize logging fields.
    ++     */
    ++    private void prepareMetricsLogging(int important, int others, long spaceBegin, long spaceBulk) {
    ++        availableSpaceBefore = spaceBegin;
    ++        availableSpaceAfterBulkDelete = spaceBulk;
    ++        availableSpaceAfterDexopt = 0;
    ++
    ++        importantPackageCount = important;
    ++        otherPackageCount = others;
    ++
    ++        dexoptCommandCountTotal = mDexoptCommands.size();
    ++        dexoptCommandCountExecuted = 0;
    ++
    ++        otaDexoptTimeStart = System.nanoTime();
    ++    }
    ++
    ++    private static int inMegabytes(long value) {
    ++        long in_mega_bytes = value / (1024 * 1024);
    ++        if (in_mega_bytes > Integer.MAX_VALUE) {
    ++            Log.w(TAG, "Recording " + in_mega_bytes + "MB of free space, overflowing range");
    ++            return Integer.MAX_VALUE;
    ++        }
    ++        return (int)in_mega_bytes;
    ++    }
    ++
    ++    private void performMetricsLogging() {
    ++        long finalTime = System.nanoTime();
    ++
    ++        MetricsLogger.histogram(mContext, "ota_dexopt_available_space_before_mb",
    ++                inMegabytes(availableSpaceBefore));
    ++        MetricsLogger.histogram(mContext, "ota_dexopt_available_space_after_bulk_delete_mb",
    ++                inMegabytes(availableSpaceAfterBulkDelete));
    ++        MetricsLogger.histogram(mContext, "ota_dexopt_available_space_after_dexopt_mb",
    ++                inMegabytes(availableSpaceAfterDexopt));
    ++
    ++        MetricsLogger.histogram(mContext, "ota_dexopt_num_important_packages",
    ++                importantPackageCount);
    ++        MetricsLogger.histogram(mContext, "ota_dexopt_num_other_packages", otherPackageCount);
    ++
    ++        MetricsLogger.histogram(mContext, "ota_dexopt_num_commands", dexoptCommandCountTotal);
    ++        MetricsLogger.histogram(mContext, "ota_dexopt_num_commands_executed",
    ++                dexoptCommandCountExecuted);
    ++
    ++        final int elapsedTimeSeconds =
    ++                (int) TimeUnit.NANOSECONDS.toSeconds(finalTime - otaDexoptTimeStart);
    ++        MetricsLogger.histogram(mContext, "ota_dexopt_time_s", elapsedTimeSeconds);
    ++    }
    ++
    +     private static class OTADexoptPackageDexOptimizer extends
    +             PackageDexOptimizer.ForcedUpdatePackageDexOptimizer {
    + 
    +diff --git a/services/core/java/com/android/server/pm/PackageInstallerService.java b/services/core/java/com/android/server/pm/PackageInstallerService.java
    +index 6a56fa6..d25abbf 100644
    +--- a/services/core/java/com/android/server/pm/PackageInstallerService.java
    ++++ b/services/core/java/com/android/server/pm/PackageInstallerService.java
    +@@ -870,13 +870,8 @@ public class PackageInstallerService extends IPackageInstaller.Stub {
    +                 IntentSender statusReceiver, int userId) {
    +         final int callingUid = Binder.getCallingUid();
    +         mPm.enforceCrossUserPermission(callingUid, userId, true, true, "uninstall");
    +-        boolean allowSilentUninstall = true;
    +         if ((callingUid != Process.SHELL_UID) && (callingUid != Process.ROOT_UID)) {
    +             mAppOps.checkPackage(callingUid, callerPackageName);
    +-            final String installerPackageName = mPm.getInstallerPackageName(packageName);
    +-            allowSilentUninstall = mPm.isOrphaned(packageName) ||
    +-                    (installerPackageName != null
    +-                            && installerPackageName.equals(callerPackageName));
    +         }
    + 
    +         // Check whether the caller is device owner, in which case we do it silently.
    +@@ -887,8 +882,8 @@ public class PackageInstallerService extends IPackageInstaller.Stub {
    + 
    +         final PackageDeleteObserverAdapter adapter = new PackageDeleteObserverAdapter(mContext,
    +                 statusReceiver, packageName, isDeviceOwner, userId);
    +-        if (allowSilentUninstall && mContext.checkCallingOrSelfPermission(
    +-                android.Manifest.permission.DELETE_PACKAGES) == PackageManager.PERMISSION_GRANTED) {
    ++        if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DELETE_PACKAGES)
    ++                    == PackageManager.PERMISSION_GRANTED) {
    +             // Sweet, call straight through!
    +             mPm.deletePackage(packageName, adapter.getBinder(), userId, flags);
    +         } else if (isDeviceOwner) {
    +diff --git a/services/core/java/com/android/server/pm/PackageInstallerSession.java b/services/core/java/com/android/server/pm/PackageInstallerSession.java
    +index 6cdc40f..2ece99f 100644
    +--- a/services/core/java/com/android/server/pm/PackageInstallerSession.java
    ++++ b/services/core/java/com/android/server/pm/PackageInstallerSession.java
    +@@ -44,6 +44,7 @@ import android.content.pm.PackageParser.ApkLite;
    + import android.content.pm.PackageParser.PackageLite;
    + import android.content.pm.PackageParser.PackageParserException;
    + import android.content.pm.Signature;
    ++import android.os.Binder;
    + import android.os.Bundle;
    + import android.os.FileBridge;
    + import android.os.FileUtils;
    +@@ -109,6 +110,7 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
    +     final int installerUid;
    +     final SessionParams params;
    +     final long createdMillis;
    ++    final int defaultContainerGid;
    + 
    +     /** Staging location where client data is written. */
    +     final File stageDir;
    +@@ -199,13 +201,19 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
    +     private final Handler.Callback mHandlerCallback = new Handler.Callback() {
    +         @Override
    +         public boolean handleMessage(Message msg) {
    ++            // Cache package manager data without the lock held
    ++            final PackageInfo pkgInfo = mPm.getPackageInfo(
    ++                    params.appPackageName, PackageManager.GET_SIGNATURES /*flags*/, userId);
    ++            final ApplicationInfo appInfo = mPm.getApplicationInfo(
    ++                    params.appPackageName, 0, userId);
    ++
    +             synchronized (mLock) {
    +                 if (msg.obj != null) {
    +                     mRemoteObserver = (IPackageInstallObserver2) msg.obj;
    +                 }
    + 
    +                 try {
    +-                    commitLocked();
    ++                    commitLocked(pkgInfo, appInfo);
    +                 } catch (PackageManagerException e) {
    +                     final String completeMsg = ExceptionUtils.getCompleteMessage(e);
    +                     Slog.e(TAG, "Commit of session " + sessionId + " failed: " + completeMsg);
    +@@ -264,6 +272,14 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
    +         } else {
    +             mPermissionsAccepted = false;
    +         }
    ++        final long identity = Binder.clearCallingIdentity();
    ++        try {
    ++            final int uid = mPm.getPackageUid(PackageManagerService.DEFAULT_CONTAINER_PACKAGE,
    ++                    PackageManager.MATCH_SYSTEM_ONLY, UserHandle.USER_SYSTEM);
    ++            defaultContainerGid = UserHandle.getSharedAppGid(uid);
    ++        } finally {
    ++            Binder.restoreCallingIdentity(identity);
    ++        }
    +     }
    + 
    +     public SessionInfo generateInfo() {
    +@@ -423,7 +439,13 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
    +             if (!FileUtils.isValidExtFilename(name)) {
    +                 throw new IllegalArgumentException("Invalid name: " + name);
    +             }
    +-            final File target = new File(resolveStageDir(), name);
    ++            final File target;
    ++            final long identity = Binder.clearCallingIdentity();
    ++            try {
    ++                target = new File(resolveStageDir(), name);
    ++            } finally {
    ++                Binder.restoreCallingIdentity(identity);
    ++            }
    + 
    +             // TODO: this should delegate to DCS so the system process avoids
    +             // holding open FDs into containers.
    +@@ -520,7 +542,8 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
    +         mHandler.obtainMessage(MSG_COMMIT, adapter.getBinder()).sendToTarget();
    +     }
    + 
    +-    private void commitLocked() throws PackageManagerException {
    ++    private void commitLocked(PackageInfo pkgInfo, ApplicationInfo appInfo)
    ++            throws PackageManagerException {
    +         if (mDestroyed) {
    +             throw new PackageManagerException(INSTALL_FAILED_INTERNAL_ERROR, "Session destroyed");
    +         }
    +@@ -538,7 +561,7 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
    +         // Verify that stage looks sane with respect to existing application.
    +         // This currently only ensures packageName, versionCode, and certificate
    +         // consistency.
    +-        validateInstallLocked();
    ++        validateInstallLocked(pkgInfo, appInfo);
    + 
    +         Preconditions.checkNotNull(mPackageName);
    +         Preconditions.checkNotNull(mSignatures);
    +@@ -650,7 +673,8 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
    +      * Note that upgrade compatibility is still performed by
    +      * {@link PackageManagerService}.
    +      */
    +-    private void validateInstallLocked() throws PackageManagerException {
    ++    private void validateInstallLocked(PackageInfo pkgInfo, ApplicationInfo appInfo)
    ++            throws PackageManagerException {
    +         mPackageName = null;
    +         mVersionCode = -1;
    +         mSignatures = null;
    +@@ -729,10 +753,8 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
    + 
    +         if (removeSplitList.size() > 0) {
    +             // validate split names marked for removal
    +-            final int flags = mSignatures == null ? PackageManager.GET_SIGNATURES : 0;
    +-            final PackageInfo pkg = mPm.getPackageInfo(params.appPackageName, flags, userId);
    +             for (String splitName : removeSplitList) {
    +-                if (!ArrayUtils.contains(pkg.splitNames, splitName)) {
    ++                if (!ArrayUtils.contains(pkgInfo.splitNames, splitName)) {
    +                     throw new PackageManagerException(INSTALL_FAILED_INVALID_APK,
    +                             "Split not found: " + splitName);
    +                 }
    +@@ -740,11 +762,11 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
    + 
    +             // ensure we've got appropriate package name, version code and signatures
    +             if (mPackageName == null) {
    +-                mPackageName = pkg.packageName;
    +-                mVersionCode = pkg.versionCode;
    ++                mPackageName = pkgInfo.packageName;
    ++                mVersionCode = pkgInfo.versionCode;
    +             }
    +             if (mSignatures == null) {
    +-                mSignatures = pkg.signatures;
    ++                mSignatures = pkgInfo.signatures;
    +             }
    +         }
    + 
    +@@ -757,8 +779,7 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
    + 
    +         } else {
    +             // Partial installs must be consistent with existing install
    +-            final ApplicationInfo app = mPm.getApplicationInfo(mPackageName, 0, userId);
    +-            if (app == null) {
    ++            if (appInfo == null) {
    +                 throw new PackageManagerException(INSTALL_FAILED_INVALID_APK,
    +                         "Missing existing base package for " + mPackageName);
    +             }
    +@@ -766,8 +787,8 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
    +             final PackageLite existing;
    +             final ApkLite existingBase;
    +             try {
    +-                existing = PackageParser.parsePackageLite(new File(app.getCodePath()), 0);
    +-                existingBase = PackageParser.parseApkLite(new File(app.getBaseCodePath()),
    ++                existing = PackageParser.parsePackageLite(new File(appInfo.getCodePath()), 0);
    ++                existingBase = PackageParser.parseApkLite(new File(appInfo.getBaseCodePath()),
    +                         PackageParser.PARSE_COLLECT_CERTIFICATES);
    +             } catch (PackageParserException e) {
    +                 throw PackageManagerException.from(e);
    +@@ -777,7 +798,7 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
    + 
    +             // Inherit base if not overridden
    +             if (mResolvedBaseFile == null) {
    +-                mResolvedBaseFile = new File(app.getBaseCodePath());
    ++                mResolvedBaseFile = new File(appInfo.getBaseCodePath());
    +                 mResolvedInheritedFiles.add(mResolvedBaseFile);
    +             }
    + 
    +@@ -794,7 +815,7 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
    +             }
    + 
    +             // Inherit compiled oat directory.
    +-            final File packageInstallDir = (new File(app.getBaseCodePath())).getParentFile();
    ++            final File packageInstallDir = (new File(appInfo.getBaseCodePath())).getParentFile();
    +             mInheritedFilesBase = packageInstallDir;
    +             final File oatDir = new File(packageInstallDir, "oat");
    +             if (oatDir.exists()) {
    +@@ -822,7 +843,8 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
    +         }
    +     }
    + 
    +-    private void assertApkConsistent(String tag, ApkLite apk) throws PackageManagerException {
    ++    private void assertApkConsistent(String tag, ApkLite apk)
    ++            throws PackageManagerException {
    +         if (!mPackageName.equals(apk.packageName)) {
    +             throw new PackageManagerException(INSTALL_FAILED_INVALID_APK, tag + " package "
    +                     + apk.packageName + " inconsistent with " + mPackageName);
    +@@ -1035,10 +1057,7 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
    +                     "Failed to finalize container " + cid);
    +         }
    + 
    +-        final int uid = mPm.getPackageUid(PackageManagerService.DEFAULT_CONTAINER_PACKAGE,
    +-                PackageManager.MATCH_SYSTEM_ONLY, UserHandle.USER_SYSTEM);
    +-        final int gid = UserHandle.getSharedAppGid(uid);
    +-        if (!PackageHelper.fixSdPermissions(cid, gid, null)) {
    ++        if (!PackageHelper.fixSdPermissions(cid, defaultContainerGid, null)) {
    +             throw new PackageManagerException(INSTALL_FAILED_CONTAINER_ERROR,
    +                     "Failed to fix permissions on container " + cid);
    +         }
    +@@ -1071,7 +1090,12 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
    +                 if (stageDir != null) {
    +                     prepareStageDir(stageDir);
    +                 } else if (stageCid != null) {
    +-                    prepareExternalStageCid(stageCid, params.sizeBytes);
    ++                    final long identity = Binder.clearCallingIdentity();
    ++                    try {
    ++                        prepareExternalStageCid(stageCid, params.sizeBytes);
    ++                    } finally {
    ++                        Binder.restoreCallingIdentity(identity);
    ++                    }
    + 
    +                     // TODO: deliver more granular progress for ASEC allocation
    +                     mInternalProgress = 0.25f;
    +diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
    +index f326555..5fd9c58 100644
    +--- a/services/core/java/com/android/server/pm/PackageManagerService.java
    ++++ b/services/core/java/com/android/server/pm/PackageManagerService.java
    +@@ -109,6 +109,7 @@ import android.app.admin.SecurityLog;
    + import android.app.backup.IBackupManager;
    + import android.content.BroadcastReceiver;
    + import android.content.ComponentName;
    ++import android.content.ContentResolver;
    + import android.content.Context;
    + import android.content.IIntentReceiver;
    + import android.content.Intent;
    +@@ -177,6 +178,7 @@ import android.os.Looper;
    + import android.os.Message;
    + import android.os.Parcel;
    + import android.os.ParcelFileDescriptor;
    ++import android.os.PatternMatcher;
    + import android.os.Process;
    + import android.os.RemoteCallbackList;
    + import android.os.RemoteException;
    +@@ -196,6 +198,7 @@ import android.os.storage.StorageManager;
    + import android.os.storage.VolumeInfo;
    + import android.os.storage.VolumeRecord;
    + import android.provider.Settings.Global;
    ++import android.provider.Settings.Secure;
    + import android.security.KeyStore;
    + import android.security.SystemKeyStore;
    + import android.system.ErrnoException;
    +@@ -210,6 +213,7 @@ import android.util.ExceptionUtils;
    + import android.util.Log;
    + import android.util.LogPrinter;
    + import android.util.MathUtils;
    ++import android.util.Pair;
    + import android.util.PrintStreamPrinter;
    + import android.util.Slog;
    + import android.util.SparseArray;
    +@@ -363,7 +367,8 @@ public class PackageManagerService extends IPackageManager.Stub {
    + 
    +     static final boolean CLEAR_RUNTIME_PERMISSIONS_ON_UPGRADE = false;
    + 
    +-    private static final boolean DISABLE_EPHEMERAL_APPS = !Build.IS_DEBUGGABLE;
    ++    private static final boolean DISABLE_EPHEMERAL_APPS = false;
    ++    private static final boolean HIDE_EPHEMERAL_APIS = true;
    + 
    +     private static final int RADIO_UID = Process.PHONE_UID;
    +     private static final int LOG_UID = Process.LOG_UID;
    +@@ -455,6 +460,8 @@ public class PackageManagerService extends IPackageManager.Stub {
    + 
    +     private static final String PACKAGE_MIME_TYPE = "application/vnd.android.package-archive";
    + 
    ++    private static final String PACKAGE_SCHEME = "package";
    ++
    +     private static final String VENDOR_OVERLAY_DIR = "/vendor/overlay";
    + 
    +     private static int DEFAULT_EPHEMERAL_HASH_PREFIX_MASK = 0xFFFFF000;
    +@@ -531,6 +538,10 @@ public class PackageManagerService extends IPackageManager.Stub {
    +     final String[] mSeparateProcesses;
    +     final boolean mIsUpgrade;
    +     final boolean mIsPreNUpgrade;
    ++    final boolean mIsPreNMR1Upgrade;
    ++
    ++    @GuardedBy("mPackages")
    ++    private boolean mDexOptDialogShown;
    + 
    +     /** The location for ASEC container files on internal storage. */
    +     final String mAsecInternalPath;
    +@@ -1117,7 +1128,9 @@ public class PackageManagerService extends IPackageManager.Stub {
    + 
    +     final @Nullable String mRequiredVerifierPackage;
    +     final @NonNull String mRequiredInstallerPackage;
    ++    final @NonNull String mRequiredUninstallerPackage;
    +     final @Nullable String mSetupWizardPackage;
    ++    final @Nullable String mStorageManagerPackage;
    +     final @NonNull String mServicesSystemSharedLibraryPackageName;
    +     final @NonNull String mSharedSystemSharedLibraryPackageName;
    + 
    +@@ -2148,6 +2161,18 @@ public class PackageManagerService extends IPackageManager.Stub {
    + 
    +             mFirstBoot = !mSettings.readLPw(sUserManager.getUsers(false));
    + 
    ++            // Clean up orphaned packages for which the code path doesn't exist
    ++            // and they are an update to a system app - caused by bug/32321269
    ++            final int packageSettingCount = mSettings.mPackages.size();
    ++            for (int i = packageSettingCount - 1; i >= 0; i--) {
    ++                PackageSetting ps = mSettings.mPackages.valueAt(i);
    ++                if (!isExternal(ps) && (ps.codePath == null || !ps.codePath.exists())
    ++                        && mSettings.getDisabledSystemPkgLPr(ps.name) != null) {
    ++                    mSettings.mPackages.removeAt(i);
    ++                    mSettings.enableSystemPackageLPw(ps.name);
    ++                }
    ++            }
    ++
    +             if (mFirstBoot) {
    +                 requestCopyPreoptedFiles();
    +             }
    +@@ -2238,6 +2263,8 @@ public class PackageManagerService extends IPackageManager.Stub {
    +             // as there is no profiling data available.
    +             mIsPreNUpgrade = mIsUpgrade && ver.sdkVersion < Build.VERSION_CODES.N;
    + 
    ++            mIsPreNMR1Upgrade = mIsUpgrade && ver.sdkVersion < Build.VERSION_CODES.N_MR1;
    ++
    +             // save off the names of pre-existing system packages prior to scanning; we don't
    +             // want to automatically grant runtime permissions for new system apps
    +             if (mPromoteSystemApps) {
    +@@ -2457,6 +2484,9 @@ public class PackageManagerService extends IPackageManager.Stub {
    +             }
    +             mExpectingBetter.clear();
    + 
    ++            // Resolve the storage manager.
    ++            mStorageManagerPackage = getStorageManagerPackageName();
    ++
    +             // Resolve protected action filters. Only the setup wizard is allowed to
    +             // have a high priority filter for these actions.
    +             mSetupWizardPackage = getSetupWizardPackageName();
    +@@ -2620,6 +2650,7 @@ public class PackageManagerService extends IPackageManager.Stub {
    +             if (!mOnlyCore) {
    +                 mRequiredVerifierPackage = getRequiredButNotReallyRequiredVerifierLPr();
    +                 mRequiredInstallerPackage = getRequiredInstallerLPr();
    ++                mRequiredUninstallerPackage = getRequiredUninstallerLPr();
    +                 mIntentFilterVerifierComponent = getIntentFilterVerifierComponentNameLPr();
    +                 mIntentFilterVerifier = new IntentVerifierProxy(mContext,
    +                         mIntentFilterVerifierComponent);
    +@@ -2630,6 +2661,7 @@ public class PackageManagerService extends IPackageManager.Stub {
    +             } else {
    +                 mRequiredVerifierPackage = null;
    +                 mRequiredInstallerPackage = null;
    ++                mRequiredUninstallerPackage = null;
    +                 mIntentFilterVerifierComponent = null;
    +                 mIntentFilterVerifier = null;
    +                 mServicesSystemSharedLibraryPackageName = null;
    +@@ -2707,10 +2739,11 @@ public class PackageManagerService extends IPackageManager.Stub {
    +                 UserHandle.USER_SYSTEM);
    +         if (matches.size() == 1) {
    +             return matches.get(0).getComponentInfo().packageName;
    +-        } else {
    +-            Log.e(TAG, "There should probably be exactly one verifier; found " + matches);
    ++        } else if (matches.size() == 0) {
    ++            Log.e(TAG, "There should probably be a verifier, but, none were found");
    +             return null;
    +         }
    ++        throw new RuntimeException("There must be exactly one verifier; found " + matches);
    +     }
    + 
    +     private @NonNull String getRequiredSharedLibraryLPr(String libraryName) {
    +@@ -2742,6 +2775,22 @@ public class PackageManagerService extends IPackageManager.Stub {
    +         }
    +     }
    + 
    ++    private @NonNull String getRequiredUninstallerLPr() {
    ++        final Intent intent = new Intent(Intent.ACTION_UNINSTALL_PACKAGE);
    ++        intent.addCategory(Intent.CATEGORY_DEFAULT);
    ++        intent.setData(Uri.fromParts(PACKAGE_SCHEME, "foo.bar", null));
    ++
    ++        final ResolveInfo resolveInfo = resolveIntent(intent, null,
    ++                MATCH_SYSTEM_ONLY | MATCH_DIRECT_BOOT_AWARE | MATCH_DIRECT_BOOT_UNAWARE,
    ++                UserHandle.USER_SYSTEM);
    ++        if (resolveInfo == null ||
    ++                mResolveActivity.name.equals(resolveInfo.getComponentInfo().name)) {
    ++            throw new RuntimeException("There must be exactly one uninstaller; found "
    ++                    + resolveInfo);
    ++        }
    ++        return resolveInfo.getComponentInfo().packageName;
    ++    }
    ++
    +     private @NonNull ComponentName getIntentFilterVerifierComponentNameLPr() {
    +         final Intent intent = new Intent(Intent.ACTION_INTENT_FILTER_NEEDS_VERIFICATION);
    + 
    +@@ -3078,8 +3127,12 @@ public class PackageManagerService extends IPackageManager.Stub {
    +         flags = updateFlagsForPackage(flags, userId, packageName);
    +         enforceCrossUserPermission(Binder.getCallingUid(), userId,
    +                 false /* requireFullPermission */, false /* checkShell */, "get package info");
    ++
    +         // reader
    +         synchronized (mPackages) {
    ++            // Normalize package name to hanlde renamed packages
    ++            packageName = normalizePackageNameLPr(packageName);
    ++
    +             final boolean matchFactoryOnly = (flags & MATCH_FACTORY_ONLY) != 0;
    +             PackageParser.Package p = null;
    +             if (matchFactoryOnly) {
    +@@ -3280,8 +3333,12 @@ public class PackageManagerService extends IPackageManager.Stub {
    +         flags = updateFlagsForApplication(flags, userId, packageName);
    +         enforceCrossUserPermission(Binder.getCallingUid(), userId,
    +                 false /* requireFullPermission */, false /* checkShell */, "get application info");
    ++
    +         // writer
    +         synchronized (mPackages) {
    ++            // Normalize package name to hanlde renamed packages
    ++            packageName = normalizePackageNameLPr(packageName);
    ++
    +             PackageParser.Package p = mPackages.get(packageName);
    +             if (DEBUG_PACKAGE_INFO) Log.v(
    +                     TAG, "getApplicationInfo " + packageName
    +@@ -3303,6 +3360,11 @@ public class PackageManagerService extends IPackageManager.Stub {
    +         return null;
    +     }
    + 
    ++    private String normalizePackageNameLPr(String packageName) {
    ++        String normalizedPackageName = mSettings.mRenamedPackages.get(packageName);
    ++        return normalizedPackageName != null ? normalizedPackageName : packageName;
    ++    }
    ++
    +     @Override
    +     public void freeStorageAndNotify(final String volumeUuid, final long freeStorageSize,
    +             final IPackageDataObserver observer) {
    +@@ -4722,20 +4784,6 @@ public class PackageManagerService extends IPackageManager.Stub {
    + 
    +             final ResolveInfo bestChoice =
    +                     chooseBestActivity(intent, resolvedType, flags, query, userId);
    +-
    +-            if (isEphemeralAllowed(intent, query, userId)) {
    +-                Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "resolveEphemeral");
    +-                final EphemeralResolveInfo ai =
    +-                        getEphemeralResolveInfo(intent, resolvedType, userId);
    +-                if (ai != null) {
    +-                    if (DEBUG_EPHEMERAL) {
    +-                        Slog.v(TAG, "Returning an EphemeralResolveInfo");
    +-                    }
    +-                    bestChoice.ephemeralInstaller = mEphemeralInstallerInfo;
    +-                    bestChoice.ephemeralResolveInfo = ai;
    +-                }
    +-                Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
    +-            }
    +             return bestChoice;
    +         } finally {
    +             Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
    +@@ -4776,11 +4824,28 @@ public class PackageManagerService extends IPackageManager.Stub {
    +                 false, false, false, userId);
    +     }
    + 
    ++    private boolean isEphemeralDisabled() {
    ++        // ephemeral apps have been disabled across the board
    ++        if (DISABLE_EPHEMERAL_APPS) {
    ++            return true;
    ++        }
    ++        // system isn't up yet; can't read settings, so, assume no ephemeral apps
    ++        if (!mSystemReady) {
    ++            return true;
    ++        }
    ++        // we can't get a content resolver until the system is ready; these checks must happen last
    ++        final ContentResolver resolver = mContext.getContentResolver();
    ++        if (Global.getInt(resolver, Global.ENABLE_EPHEMERAL_FEATURE, 1) == 0) {
    ++            return true;
    ++        }
    ++        return Secure.getInt(resolver, Secure.WEB_ACTION_ENABLED, 1) == 0;
    ++    }
    + 
    +     private boolean isEphemeralAllowed(
    +-            Intent intent, List<ResolveInfo> resolvedActivites, int userId) {
    ++            Intent intent, List<ResolveInfo> resolvedActivities, int userId,
    ++            boolean skipPackageCheck) {
    +         // Short circuit and return early if possible.
    +-        if (DISABLE_EPHEMERAL_APPS) {
    ++        if (isEphemeralDisabled()) {
    +             return false;
    +         }
    +         final int callingUser = UserHandle.getCallingUserId();
    +@@ -4793,18 +4858,21 @@ public class PackageManagerService extends IPackageManager.Stub {
    +         if (intent.getComponent() != null) {
    +             return false;
    +         }
    +-        if (intent.getPackage() != null) {
    ++        if ((intent.getFlags() & Intent.FLAG_IGNORE_EPHEMERAL) != 0) {
    ++            return false;
    ++        }
    ++        if (!skipPackageCheck && intent.getPackage() != null) {
    +             return false;
    +         }
    +         final boolean isWebUri = hasWebURI(intent);
    +-        if (!isWebUri) {
    ++        if (!isWebUri || intent.getData().getHost() == null) {
    +             return false;
    +         }
    +         // Deny ephemeral apps if the user chose _ALWAYS or _ALWAYS_ASK for intent resolution.
    +         synchronized (mPackages) {
    +-            final int count = resolvedActivites.size();
    ++            final int count = (resolvedActivities == null ? 0 : resolvedActivities.size());
    +             for (int n = 0; n < count; n++) {
    +-                ResolveInfo info = resolvedActivites.get(n);
    ++                ResolveInfo info = resolvedActivities.get(n);
    +                 String packageName = info.activityInfo.packageName;
    +                 PackageSetting ps = mSettings.mPackages.get(packageName);
    +                 if (ps != null) {
    +@@ -4826,19 +4894,19 @@ public class PackageManagerService extends IPackageManager.Stub {
    +         return true;
    +     }
    + 
    +-    private EphemeralResolveInfo getEphemeralResolveInfo(Intent intent, String resolvedType,
    +-            int userId) {
    +-        final int ephemeralPrefixMask = Global.getInt(mContext.getContentResolver(),
    ++    private static EphemeralResolveInfo getEphemeralResolveInfo(
    ++            Context context, EphemeralResolverConnection resolverConnection, Intent intent,
    ++            String resolvedType, int userId, String packageName) {
    ++        final int ephemeralPrefixMask = Global.getInt(context.getContentResolver(),
    +                 Global.EPHEMERAL_HASH_PREFIX_MASK, DEFAULT_EPHEMERAL_HASH_PREFIX_MASK);
    +-        final int ephemeralPrefixCount = Global.getInt(mContext.getContentResolver(),
    ++        final int ephemeralPrefixCount = Global.getInt(context.getContentResolver(),
    +                 Global.EPHEMERAL_HASH_PREFIX_COUNT, DEFAULT_EPHEMERAL_HASH_PREFIX_COUNT);
    +         final EphemeralDigest digest = new EphemeralDigest(intent.getData(), ephemeralPrefixMask,
    +                 ephemeralPrefixCount);
    +         final int[] shaPrefix = digest.getDigestPrefix();
    +         final byte[][] digestBytes = digest.getDigestBytes();
    +         final List<EphemeralResolveInfo> ephemeralResolveInfoList =
    +-                mEphemeralResolverConnection.getEphemeralResolveInfoList(
    +-                        shaPrefix, ephemeralPrefixMask);
    ++                resolverConnection.getEphemeralResolveInfoList(shaPrefix, ephemeralPrefixMask);
    +         if (ephemeralResolveInfoList == null || ephemeralResolveInfoList.size() == 0) {
    +             // No hash prefix match; there are no ephemeral apps for this domain.
    +             return null;
    +@@ -4855,6 +4923,10 @@ public class PackageManagerService extends IPackageManager.Stub {
    +                 if (filters.isEmpty()) {
    +                     continue;
    +                 }
    ++                if (packageName != null
    ++                        && !packageName.equals(ephemeralApplication.getPackageName())) {
    ++                    continue;
    ++                }
    +                 // We have a domain match; resolve the filters to see if anything matches.
    +                 final EphemeralIntentResolver ephemeralResolver = new EphemeralIntentResolver();
    +                 for (int j = filters.size() - 1; j >= 0; --j) {
    +@@ -5258,8 +5330,12 @@ public class PackageManagerService extends IPackageManager.Stub {
    +         }
    + 
    +         // reader
    ++        boolean sortResult = false;
    ++        boolean addEphemeral = false;
    ++        boolean matchEphemeralPackage = false;
    ++        List<ResolveInfo> result;
    ++        final String pkgName = intent.getPackage();
    +         synchronized (mPackages) {
    +-            final String pkgName = intent.getPackage();
    +             if (pkgName == null) {
    +                 List<CrossProfileIntentFilter> matchingFilters =
    +                         getMatchingCrossProfileIntentFilters(intent, resolvedType, userId);
    +@@ -5267,15 +5343,16 @@ public class PackageManagerService extends IPackageManager.Stub {
    +                 ResolveInfo xpResolveInfo  = querySkipCurrentProfileIntents(matchingFilters, intent,
    +                         resolvedType, flags, userId);
    +                 if (xpResolveInfo != null) {
    +-                    List<ResolveInfo> result = new ArrayList<ResolveInfo>(1);
    +-                    result.add(xpResolveInfo);
    +-                    return filterIfNotSystemUser(result, userId);
    ++                    List<ResolveInfo> xpResult = new ArrayList<ResolveInfo>(1);
    ++                    xpResult.add(xpResolveInfo);
    ++                    return filterIfNotSystemUser(xpResult, userId);
    +                 }
    + 
    +                 // Check for results in the current profile.
    +-                List<ResolveInfo> result = mActivities.queryIntent(
    +-                        intent, resolvedType, flags, userId);
    +-                result = filterIfNotSystemUser(result, userId);
    ++                result = filterIfNotSystemUser(mActivities.queryIntent(
    ++                        intent, resolvedType, flags, userId), userId);
    ++                addEphemeral =
    ++                        isEphemeralAllowed(intent, result, userId, false /*skipPackageCheck*/);
    + 
    +                 // Check for cross profile results.
    +                 boolean hasNonNegativePriorityResult = hasNonNegativePriority(result);
    +@@ -5287,7 +5364,7 @@ public class PackageManagerService extends IPackageManager.Stub {
    +                             Collections.singletonList(xpResolveInfo), userId).size() > 0;
    +                     if (isVisibleToUser) {
    +                         result.add(xpResolveInfo);
    +-                        Collections.sort(result, mResolvePrioritySorter);
    ++                        sortResult = true;
    +                     }
    +                 }
    +                 if (hasWebURI(intent)) {
    +@@ -5303,28 +5380,61 @@ public class PackageManagerService extends IPackageManager.Stub {
    +                             // in the result.
    +                             result.remove(xpResolveInfo);
    +                         }
    +-                        if (result.size() == 0) {
    ++                        if (result.size() == 0 && !addEphemeral) {
    +                             result.add(xpDomainInfo.resolveInfo);
    +                             return result;
    +                         }
    +-                    } else if (result.size() <= 1) {
    +-                        return result;
    +                     }
    +-                    result = filterCandidatesWithDomainPreferredActivitiesLPr(intent, flags, result,
    +-                            xpDomainInfo, userId);
    +-                    Collections.sort(result, mResolvePrioritySorter);
    ++                    if (result.size() > 1 || addEphemeral) {
    ++                        result = filterCandidatesWithDomainPreferredActivitiesLPr(
    ++                                intent, flags, result, xpDomainInfo, userId);
    ++                        sortResult = true;
    ++                    }
    ++                }
    ++            } else {
    ++                final PackageParser.Package pkg = mPackages.get(pkgName);
    ++                if (pkg != null) {
    ++                    result = filterIfNotSystemUser(
    ++                            mActivities.queryIntentForPackage(
    ++                                    intent, resolvedType, flags, pkg.activities, userId),
    ++                            userId);
    ++                } else {
    ++                    // the caller wants to resolve for a particular package; however, there
    ++                    // were no installed results, so, try to find an ephemeral result
    ++                    addEphemeral = isEphemeralAllowed(
    ++                            intent, null /*result*/, userId, true /*skipPackageCheck*/);
    ++                    matchEphemeralPackage = true;
    ++                    result = new ArrayList<ResolveInfo>();
    +                 }
    +-                return result;
    +             }
    +-            final PackageParser.Package pkg = mPackages.get(pkgName);
    +-            if (pkg != null) {
    +-                return filterIfNotSystemUser(
    +-                        mActivities.queryIntentForPackage(
    +-                                intent, resolvedType, flags, pkg.activities, userId),
    +-                        userId);
    ++        }
    ++        if (addEphemeral) {
    ++            Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "resolveEphemeral");
    ++            final EphemeralResolveInfo ai = getEphemeralResolveInfo(
    ++                    mContext, mEphemeralResolverConnection, intent, resolvedType, userId,
    ++                    matchEphemeralPackage ? pkgName : null);
    ++            if (ai != null) {
    ++                if (DEBUG_EPHEMERAL) {
    ++                    Slog.v(TAG, "Adding ephemeral installer to the ResolveInfo list");
    ++                }
    ++                final ResolveInfo ephemeralInstaller = new ResolveInfo(mEphemeralInstallerInfo);
    ++                ephemeralInstaller.ephemeralResolveInfo = ai;
    ++                // make sure this resolver is the default
    ++                ephemeralInstaller.isDefault = true;
    ++                ephemeralInstaller.match = IntentFilter.MATCH_CATEGORY_SCHEME_SPECIFIC_PART
    ++                        | IntentFilter.MATCH_ADJUSTMENT_NORMAL;
    ++                // add a non-generic filter
    ++                ephemeralInstaller.filter = new IntentFilter(intent.getAction());
    ++                ephemeralInstaller.filter.addDataPath(
    ++                        intent.getData().getPath(), PatternMatcher.PATTERN_LITERAL);
    ++                result.add(ephemeralInstaller);
    +             }
    +-            return new ArrayList<ResolveInfo>();
    ++            Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
    ++        }
    ++        if (sortResult) {
    ++            Collections.sort(result, mResolvePrioritySorter);
    +         }
    ++        return result;
    +     }
    + 
    +     private static class CrossProfileDomainInfo {
    +@@ -6204,7 +6314,7 @@ public class PackageManagerService extends IPackageManager.Stub {
    + 
    +     @Override
    +     public ParceledListSlice<EphemeralApplicationInfo> getEphemeralApplications(int userId) {
    +-        if (DISABLE_EPHEMERAL_APPS) {
    ++        if (HIDE_EPHEMERAL_APIS || isEphemeralDisabled()) {
    +             return null;
    +         }
    + 
    +@@ -6228,7 +6338,7 @@ public class PackageManagerService extends IPackageManager.Stub {
    +         enforceCrossUserPermission(Binder.getCallingUid(), userId,
    +                 true /* requireFullPermission */, false /* checkShell */,
    +                 "isEphemeral");
    +-        if (DISABLE_EPHEMERAL_APPS) {
    ++        if (HIDE_EPHEMERAL_APIS || isEphemeralDisabled()) {
    +             return false;
    +         }
    + 
    +@@ -6246,7 +6356,7 @@ public class PackageManagerService extends IPackageManager.Stub {
    + 
    +     @Override
    +     public byte[] getEphemeralApplicationCookie(String packageName, int userId) {
    +-        if (DISABLE_EPHEMERAL_APPS) {
    ++        if (HIDE_EPHEMERAL_APIS || isEphemeralDisabled()) {
    +             return null;
    +         }
    + 
    +@@ -6264,7 +6374,7 @@ public class PackageManagerService extends IPackageManager.Stub {
    + 
    +     @Override
    +     public boolean setEphemeralApplicationCookie(String packageName, byte[] cookie, int userId) {
    +-        if (DISABLE_EPHEMERAL_APPS) {
    ++        if (HIDE_EPHEMERAL_APIS || isEphemeralDisabled()) {
    +             return true;
    +         }
    + 
    +@@ -6282,7 +6392,7 @@ public class PackageManagerService extends IPackageManager.Stub {
    + 
    +     @Override
    +     public Bitmap getEphemeralApplicationIcon(String packageName, int userId) {
    +-        if (DISABLE_EPHEMERAL_APPS) {
    ++        if (HIDE_EPHEMERAL_APIS || isEphemeralDisabled()) {
    +             return null;
    +         }
    + 
    +@@ -6612,9 +6722,13 @@ public class PackageManagerService extends IPackageManager.Stub {
    + 
    +     private void collectCertificatesLI(PackageSetting ps, PackageParser.Package pkg, File srcFile,
    +             final int policyFlags) throws PackageManagerException {
    ++        // When upgrading from pre-N MR1, verify the package time stamp using the package
    ++        // directory and not the APK file.
    ++        final long lastModifiedTime = mIsPreNMR1Upgrade
    ++                ? new File(pkg.codePath).lastModified() : getLastModifiedTime(pkg, srcFile);
    +         if (ps != null
    +                 && ps.codePath.equals(srcFile)
    +-                && ps.timeStamp == getLastModifiedTime(pkg, srcFile)
    ++                && ps.timeStamp == lastModifiedTime
    +                 && !isCompatSignatureUpdateNeeded(pkg)
    +                 && !isRecoverSignatureUpdateNeeded(pkg)) {
    +             long mSigningKeySetId = ps.keySetData.getProperSigningKeySet();
    +@@ -6636,7 +6750,7 @@ public class PackageManagerService extends IPackageManager.Stub {
    +             Slog.w(TAG, "PackageSetting for " + ps.name
    +                     + " is missing signatures.  Collecting certs again to recover them.");
    +         } else {
    +-            Log.i(TAG, srcFile.toString() + " changed; collecting certs");
    ++            Slog.i(TAG, srcFile.toString() + " changed; collecting certs");
    +         }
    + 
    +         try {
    +@@ -7075,7 +7189,11 @@ public class PackageManagerService extends IPackageManager.Stub {
    +                     }
    +                 }
    +                 if (doTrim) {
    +-                    if (!isFirstBoot()) {
    ++                    final boolean dexOptDialogShown;
    ++                    synchronized (mPackages) {
    ++                        dexOptDialogShown = mDexOptDialogShown;
    ++                    }
    ++                    if (!isFirstBoot() && dexOptDialogShown) {
    +                         try {
    +                             ActivityManagerNative.getDefault().showBootMessage(
    +                                     mContext.getResources().getString(
    +@@ -7169,6 +7287,9 @@ public class PackageManagerService extends IPackageManager.Stub {
    +                                     numberOfPackagesVisited, numberOfPackagesToDexopt), true);
    +                 } catch (RemoteException e) {
    +                 }
    ++                synchronized (mPackages) {
    ++                    mDexOptDialogShown = true;
    ++                }
    +             }
    + 
    +             // If the OTA updates a system app which was previously preopted to a non-preopted state
    +@@ -8366,6 +8487,10 @@ public class PackageManagerService extends IPackageManager.Stub {
    +             pkg.applicationInfo.flags |= ApplicationInfo.FLAG_FACTORY_TEST;
    +         }
    + 
    ++        if (isSystemApp(pkg)) {
    ++            pkgSetting.isOrphaned = true;
    ++        }
    ++
    +         ArrayList<PackageParser.Package> clientLibPkgs = null;
    + 
    +         if ((scanFlags & SCAN_CHECK_ONLY) != 0) {
    +@@ -8649,7 +8774,9 @@ public class PackageManagerService extends IPackageManager.Stub {
    +             for (i=0; i<N; i++) {
    +                 PackageParser.PermissionGroup pg = pkg.permissionGroups.get(i);
    +                 PackageParser.PermissionGroup cur = mPermissionGroups.get(pg.info.name);
    +-                if (cur == null) {
    ++                final String curPackageName = cur == null ? null : cur.info.packageName;
    ++                final boolean isPackageUpdate = pg.info.packageName.equals(curPackageName);
    ++                if (cur == null || isPackageUpdate) {
    +                     mPermissionGroups.put(pg.info.name, pg);
    +                     if ((policyFlags&PackageParser.PARSE_CHATTY) != 0) {
    +                         if (r == null) {
    +@@ -8657,6 +8784,9 @@ public class PackageManagerService extends IPackageManager.Stub {
    +                         } else {
    +                             r.append(' ');
    +                         }
    ++                        if (isPackageUpdate) {
    ++                            r.append("UPD:");
    ++                        }
    +                         r.append(pg.info.name);
    +                     }
    +                 } else {
    +@@ -9189,15 +9319,17 @@ public class PackageManagerService extends IPackageManager.Stub {
    +         mEphemeralInstallerActivity.packageName = pkg.applicationInfo.packageName;
    +         mEphemeralInstallerActivity.processName = pkg.applicationInfo.packageName;
    +         mEphemeralInstallerActivity.launchMode = ActivityInfo.LAUNCH_MULTIPLE;
    +-        mEphemeralInstallerActivity.flags = ActivityInfo.FLAG_EXCLUDE_FROM_RECENTS |
    +-                ActivityInfo.FLAG_FINISH_ON_CLOSE_SYSTEM_DIALOGS;
    ++        mEphemeralInstallerActivity.flags = ActivityInfo.FLAG_EXCLUDE_FROM_RECENTS
    ++                | ActivityInfo.FLAG_FINISH_ON_CLOSE_SYSTEM_DIALOGS;
    +         mEphemeralInstallerActivity.theme = 0;
    +         mEphemeralInstallerActivity.exported = true;
    +         mEphemeralInstallerActivity.enabled = true;
    +         mEphemeralInstallerInfo.activityInfo = mEphemeralInstallerActivity;
    +         mEphemeralInstallerInfo.priority = 0;
    +-        mEphemeralInstallerInfo.preferredOrder = 0;
    +-        mEphemeralInstallerInfo.match = 0;
    ++        mEphemeralInstallerInfo.preferredOrder = 1;
    ++        mEphemeralInstallerInfo.isDefault = true;
    ++        mEphemeralInstallerInfo.match = IntentFilter.MATCH_CATEGORY_SCHEME_SPECIFIC_PART
    ++                | IntentFilter.MATCH_ADJUSTMENT_NORMAL;
    + 
    +         if (DEBUG_EPHEMERAL) {
    +             Slog.d(TAG, "Set ephemeral installer activity: " + mEphemeralInstallerComponent);
    +@@ -11165,6 +11297,19 @@ public class PackageManagerService extends IPackageManager.Stub {
    + 
    +     private static final class EphemeralIntentResolver
    +             extends IntentResolver<EphemeralResolveIntentInfo, EphemeralResolveInfo> {
    ++        /**
    ++         * The result that has the highest defined order. Ordering applies on a
    ++         * per-package basis. Mapping is from package name to Pair of order and
    ++         * EphemeralResolveInfo.
    ++         * <p>
    ++         * NOTE: This is implemented as a field variable for convenience and efficiency.
    ++         * By having a field variable, we're able to track filter ordering as soon as
    ++         * a non-zero order is defined. Otherwise, multiple loops across the result set
    ++         * would be needed to apply ordering. If the intent resolver becomes re-entrant,
    ++         * this needs to be contained entirely within {@link #filterResults()}.
    ++         */
    ++        final ArrayMap<String, Pair<Integer, EphemeralResolveInfo>> mOrderResult = new ArrayMap<>();
    ++
    +         @Override
    +         protected EphemeralResolveIntentInfo[] newArray(int size) {
    +             return new EphemeralResolveIntentInfo[size];
    +@@ -11181,7 +11326,51 @@ public class PackageManagerService extends IPackageManager.Stub {
    +             if (!sUserManager.exists(userId)) {
    +                 return null;
    +             }
    +-            return info.getEphemeralResolveInfo();
    ++            final String packageName = info.getEphemeralResolveInfo().getPackageName();
    ++            final Integer order = info.getOrder();
    ++            final Pair<Integer, EphemeralResolveInfo> lastOrderResult =
    ++                    mOrderResult.get(packageName);
    ++            // ordering is enabled and this item's order isn't high enough
    ++            if (lastOrderResult != null && lastOrderResult.first >= order) {
    ++                return null;
    ++            }
    ++            final EphemeralResolveInfo res = info.getEphemeralResolveInfo();
    ++            if (order > 0) {
    ++                // non-zero order, enable ordering
    ++                mOrderResult.put(packageName, new Pair<>(order, res));
    ++            }
    ++            return res;
    ++        }
    ++
    ++        @Override
    ++        protected void filterResults(List<EphemeralResolveInfo> results) {
    ++            // only do work if ordering is enabled [most of the time it won't be]
    ++            if (mOrderResult.size() == 0) {
    ++                return;
    ++            }
    ++            int resultSize = results.size();
    ++            for (int i = 0; i < resultSize; i++) {
    ++                final EphemeralResolveInfo info = results.get(i);
    ++                final String packageName = info.getPackageName();
    ++                final Pair<Integer, EphemeralResolveInfo> savedInfo = mOrderResult.get(packageName);
    ++                if (savedInfo == null) {
    ++                    // package doesn't having ordering
    ++                    continue;
    ++                }
    ++                if (savedInfo.second == info) {
    ++                    // circled back to the highest ordered item; remove from order list
    ++                    mOrderResult.remove(savedInfo);
    ++                    if (mOrderResult.size() == 0) {
    ++                        // no more ordered items
    ++                        break;
    ++                    }
    ++                    continue;
    ++                }
    ++                // item has a worse order, remove it from the result list
    ++                results.remove(i);
    ++                resultSize--;
    ++                i--;
    ++            }
    +         }
    +     }
    + 
    +@@ -11250,7 +11439,7 @@ public class PackageManagerService extends IPackageManager.Stub {
    +                     }
    +                     for (int id : resolvedUserIds) {
    +                         final Intent intent = new Intent(action,
    +-                                pkg != null ? Uri.fromParts("package", pkg, null) : null);
    ++                                pkg != null ? Uri.fromParts(PACKAGE_SCHEME, pkg, null) : null);
    +                         if (extras != null) {
    +                             intent.putExtras(extras);
    +                         }
    +@@ -11746,6 +11935,12 @@ public class PackageManagerService extends IPackageManager.Stub {
    +             return false;
    +         }
    + 
    ++        if (packageName.equals(mRequiredUninstallerPackage)) {
    ++            Slog.w(TAG, "Cannot suspend/un-suspend package \"" + packageName
    ++                    + "\": required for package uninstallation");
    ++            return false;
    ++        }
    ++
    +         if (packageName.equals(mRequiredVerifierPackage)) {
    +             Slog.w(TAG, "Cannot suspend/un-suspend package \"" + packageName
    +                     + "\": required for package verification");
    +@@ -15310,6 +15505,17 @@ public class PackageManagerService extends IPackageManager.Stub {
    +         Preconditions.checkNotNull(packageName);
    +         Preconditions.checkNotNull(observer);
    +         final int uid = Binder.getCallingUid();
    ++        if (!isOrphaned(packageName)
    ++                && !isCallerAllowedToSilentlyUninstall(uid, packageName)) {
    ++            try {
    ++                final Intent intent = new Intent(Intent.ACTION_UNINSTALL_PACKAGE);
    ++                intent.setData(Uri.fromParts(PACKAGE_SCHEME, packageName, null));
    ++                intent.putExtra(PackageInstaller.EXTRA_CALLBACK, observer.asBinder());
    ++                observer.onUserActionRequired(intent);
    ++            } catch (RemoteException re) {
    ++            }
    ++            return;
    ++        }
    +         final boolean deleteAllUsers = (deleteFlags & PackageManager.DELETE_ALL_USERS) != 0;
    +         final int[] users = deleteAllUsers ? sUserManager.getUserIds() : new int[]{ userId };
    +         if (UserHandle.getUserId(uid) != userId || (deleteAllUsers && users.length > 1)) {
    +@@ -15378,6 +15584,37 @@ public class PackageManagerService extends IPackageManager.Stub {
    +         });
    +     }
    + 
    ++    private boolean isCallerAllowedToSilentlyUninstall(int callingUid, String pkgName) {
    ++        if (callingUid == Process.SHELL_UID || callingUid == Process.ROOT_UID
    ++              || callingUid == Process.SYSTEM_UID) {
    ++            return true;
    ++        }
    ++        final int callingUserId = UserHandle.getUserId(callingUid);
    ++        // If the caller installed the pkgName, then allow it to silently uninstall.
    ++        if (callingUid == getPackageUid(getInstallerPackageName(pkgName), 0, callingUserId)) {
    ++            return true;
    ++        }
    ++
    ++        // Allow package verifier to silently uninstall.
    ++        if (mRequiredVerifierPackage != null &&
    ++                callingUid == getPackageUid(mRequiredVerifierPackage, 0, callingUserId)) {
    ++            return true;
    ++        }
    ++
    ++        // Allow package uninstaller to silently uninstall.
    ++        if (mRequiredUninstallerPackage != null &&
    ++                callingUid == getPackageUid(mRequiredUninstallerPackage, 0, callingUserId)) {
    ++            return true;
    ++        }
    ++
    ++        // Allow storage manager to silently uninstall.
    ++        if (mStorageManagerPackage != null &&
    ++                callingUid == getPackageUid(mStorageManagerPackage, 0, callingUserId)) {
    ++            return true;
    ++        }
    ++        return false;
    ++    }
    ++
    +     private int[] getBlockUninstallForUsers(String packageName, int[] userIds) {
    +         int[] result = EMPTY_INT_ARRAY;
    +         for (int userId : userIds) {
    +@@ -17590,6 +17827,22 @@ Slog.v(TAG, ":: stepped forward, applying functor at tag " + parser.getName());
    +         }
    +     }
    + 
    ++    private @Nullable String getStorageManagerPackageName() {
    ++        final Intent intent = new Intent(StorageManager.ACTION_MANAGE_STORAGE);
    ++
    ++        final List<ResolveInfo> matches = queryIntentActivitiesInternal(intent, null,
    ++                MATCH_SYSTEM_ONLY | MATCH_DIRECT_BOOT_AWARE | MATCH_DIRECT_BOOT_UNAWARE
    ++                        | MATCH_DISABLED_COMPONENTS,
    ++                UserHandle.myUserId());
    ++        if (matches.size() == 1) {
    ++            return matches.get(0).getComponentInfo().packageName;
    ++        } else {
    ++            Slog.e(TAG, "There should probably be exactly one storage manager; found "
    ++                    + matches.size() + ": matches=" + matches);
    ++            return null;
    ++        }
    ++    }
    ++
    +     @Override
    +     public void setApplicationEnabledSetting(String appPackageName,
    +             int newState, int flags, int userId, String callingPackage) {
    +@@ -19463,6 +19716,9 @@ Slog.v(TAG, ":: stepped forward, applying functor at tag " + parser.getName());
    +     private void assertPackageKnown(String volumeUuid, String packageName)
    +             throws PackageManagerException {
    +         synchronized (mPackages) {
    ++            // Normalize package name to handle renamed packages
    ++            packageName = normalizePackageNameLPr(packageName);
    ++
    +             final PackageSetting ps = mSettings.mPackages.get(packageName);
    +             if (ps == null) {
    +                 throw new PackageManagerException("Package " + packageName + " is unknown");
    +@@ -19477,6 +19733,9 @@ Slog.v(TAG, ":: stepped forward, applying functor at tag " + parser.getName());
    +     private void assertPackageKnownAndInstalled(String volumeUuid, String packageName, int userId)
    +             throws PackageManagerException {
    +         synchronized (mPackages) {
    ++            // Normalize package name to handle renamed packages
    ++            packageName = normalizePackageNameLPr(packageName);
    ++
    +             final PackageSetting ps = mSettings.mPackages.get(packageName);
    +             if (ps == null) {
    +                 throw new PackageManagerException("Package " + packageName + " is unknown");
    +@@ -19553,8 +19812,6 @@ Slog.v(TAG, ":: stepped forward, applying functor at tag " + parser.getName());
    +         final File ceDir = Environment.getDataUserCeDirectory(volumeUuid, userId);
    +         final File deDir = Environment.getDataUserDeDirectory(volumeUuid, userId);
    + 
    +-        boolean restoreconNeeded = false;
    +-
    +         // First look for stale data that doesn't belong, and check if things
    +         // have changed since we did our last restorecon
    +         if ((flags & StorageManager.FLAG_STORAGE_CE) != 0) {
    +@@ -19565,8 +19822,6 @@ Slog.v(TAG, ":: stepped forward, applying functor at tag " + parser.getName());
    +                                 + " was still locked; this would have caused massive data loss!");
    +             }
    + 
    +-            restoreconNeeded |= SELinuxMMAC.isRestoreconNeeded(ceDir);
    +-
    +             final File[] files = FileUtils.listFilesOrEmpty(ceDir);
    +             for (File file : files) {
    +                 final String packageName = file.getName();
    +@@ -19584,8 +19839,6 @@ Slog.v(TAG, ":: stepped forward, applying functor at tag " + parser.getName());
    +             }
    +         }
    +         if ((flags & StorageManager.FLAG_STORAGE_DE) != 0) {
    +-            restoreconNeeded |= SELinuxMMAC.isRestoreconNeeded(deDir);
    +-
    +             final File[] files = FileUtils.listFilesOrEmpty(deDir);
    +             for (File file : files) {
    +                 final String packageName = file.getName();
    +@@ -19620,29 +19873,19 @@ Slog.v(TAG, ":: stepped forward, applying functor at tag " + parser.getName());
    +             }
    + 
    +             if (ps.getInstalled(userId)) {
    +-                prepareAppDataLIF(ps.pkg, userId, flags, restoreconNeeded);
    ++                prepareAppDataLIF(ps.pkg, userId, flags);
    + 
    +                 if (maybeMigrateAppDataLIF(ps.pkg, userId)) {
    +                     // We may have just shuffled around app data directories, so
    +                     // prepare them one more time
    +-                    prepareAppDataLIF(ps.pkg, userId, flags, restoreconNeeded);
    ++                    prepareAppDataLIF(ps.pkg, userId, flags);
    +                 }
    + 
    +                 preparedCount++;
    +             }
    +         }
    + 
    +-        if (restoreconNeeded) {
    +-            if ((flags & StorageManager.FLAG_STORAGE_CE) != 0) {
    +-                SELinuxMMAC.setRestoreconDone(ceDir);
    +-            }
    +-            if ((flags & StorageManager.FLAG_STORAGE_DE) != 0) {
    +-                SELinuxMMAC.setRestoreconDone(deDir);
    +-            }
    +-        }
    +-
    +-        Slog.v(TAG, "reconcileAppsData finished " + preparedCount
    +-                + " packages; restoreconNeeded was " + restoreconNeeded);
    ++        Slog.v(TAG, "reconcileAppsData finished " + preparedCount + " packages");
    +     }
    + 
    +     /**
    +@@ -19677,9 +19920,8 @@ Slog.v(TAG, ":: stepped forward, applying functor at tag " + parser.getName());
    +             }
    + 
    +             if (ps.getInstalled(user.id)) {
    +-                // Whenever an app changes, force a restorecon of its data
    +                 // TODO: when user data is locked, mark that we're still dirty
    +-                prepareAppDataLIF(pkg, user.id, flags, true);
    ++                prepareAppDataLIF(pkg, user.id, flags);
    +             }
    +         }
    +     }
    +@@ -19692,24 +19934,22 @@ Slog.v(TAG, ":: stepped forward, applying functor at tag " + parser.getName());
    +      * will try recovering system apps by wiping data; third-party app data is
    +      * left intact.
    +      */
    +-    private void prepareAppDataLIF(PackageParser.Package pkg, int userId, int flags,
    +-            boolean restoreconNeeded) {
    ++    private void prepareAppDataLIF(PackageParser.Package pkg, int userId, int flags) {
    +         if (pkg == null) {
    +             Slog.wtf(TAG, "Package was null!", new Throwable());
    +             return;
    +         }
    +-        prepareAppDataLeafLIF(pkg, userId, flags, restoreconNeeded);
    ++        prepareAppDataLeafLIF(pkg, userId, flags);
    +         final int childCount = (pkg.childPackages != null) ? pkg.childPackages.size() : 0;
    +         for (int i = 0; i < childCount; i++) {
    +-            prepareAppDataLeafLIF(pkg.childPackages.get(i), userId, flags, restoreconNeeded);
    ++            prepareAppDataLeafLIF(pkg.childPackages.get(i), userId, flags);
    +         }
    +     }
    + 
    +-    private void prepareAppDataLeafLIF(PackageParser.Package pkg, int userId, int flags,
    +-            boolean restoreconNeeded) {
    ++    private void prepareAppDataLeafLIF(PackageParser.Package pkg, int userId, int flags) {
    +         if (DEBUG_APP_DATA) {
    +             Slog.v(TAG, "prepareAppData for " + pkg.packageName + " u" + userId + " 0x"
    +-                    + Integer.toHexString(flags) + (restoreconNeeded ? " restoreconNeeded" : ""));
    ++                    + Integer.toHexString(flags));
    +         }
    + 
    +         final String volumeUuid = pkg.volumeUuid;
    +@@ -19739,15 +19979,6 @@ Slog.v(TAG, ":: stepped forward, applying functor at tag " + parser.getName());
    +             }
    +         }
    + 
    +-        if (restoreconNeeded) {
    +-            try {
    +-                mInstaller.restoreconAppData(volumeUuid, packageName, userId, flags, appId,
    +-                        app.seinfo);
    +-            } catch (InstallerException e) {
    +-                Slog.e(TAG, "Failed to restorecon for " + packageName + ": " + e);
    +-            }
    +-        }
    +-
    +         if ((flags & StorageManager.FLAG_STORAGE_CE) != 0) {
    +             try {
    +                 // CE storage is unlocked right now, so read out the inode and
    +@@ -20842,6 +21073,13 @@ Slog.v(TAG, ":: stepped forward, applying functor at tag " + parser.getName());
    +         public boolean isPackageDataProtected(int userId, String packageName) {
    +             return mProtectedPackages.isPackageDataProtected(userId, packageName);
    +         }
    ++
    ++        @Override
    ++        public boolean wasPackageEverLaunched(String packageName, int userId) {
    ++            synchronized (mPackages) {
    ++                return mSettings.wasPackageEverLaunchedLPr(packageName, userId);
    ++            }
    ++        }
    +     }
    + 
    +     @Override
    +diff --git a/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java b/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java
    +index 751c585..cfd0af7 100644
    +--- a/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java
    ++++ b/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java
    +@@ -19,6 +19,7 @@ package com.android.server.pm;
    + import static com.android.server.pm.PackageManagerService.DEBUG_DEXOPT;
    + import static com.android.server.pm.PackageManagerService.TAG;
    + 
    ++import android.annotation.NonNull;
    + import android.app.AppGlobals;
    + import android.content.Intent;
    + import android.content.pm.PackageParser;
    +@@ -35,13 +36,9 @@ import java.io.IOException;
    + import java.util.ArrayList;
    + import java.util.Collection;
    + import java.util.Collections;
    +-import java.util.Comparator;
    +-import java.util.Date;
    +-import java.util.HashSet;
    +-import java.util.Iterator;
    + import java.util.LinkedList;
    + import java.util.List;
    +-import java.util.Set;
    ++import java.util.function.Predicate;
    + 
    + /**
    +  * Class containing helper methods for the PackageManagerService.
    +@@ -67,34 +64,51 @@ public class PackageManagerServiceUtils {
    +         return pkgNames;
    +     }
    + 
    +-    private static void filterRecentlyUsedApps(Collection<PackageParser.Package> pkgs,
    +-            long estimatedPreviousSystemUseTime,
    +-            long dexOptLRUThresholdInMills) {
    +-        // Filter out packages that aren't recently used.
    +-        int total = pkgs.size();
    +-        int skipped = 0;
    +-        for (Iterator<PackageParser.Package> i = pkgs.iterator(); i.hasNext();) {
    +-            PackageParser.Package pkg = i.next();
    +-            long then = pkg.getLatestForegroundPackageUseTimeInMills();
    +-            if (then < estimatedPreviousSystemUseTime - dexOptLRUThresholdInMills) {
    +-                if (DEBUG_DEXOPT) {
    +-                    Log.i(TAG, "Skipping dexopt of " + pkg.packageName +
    +-                            " last used in foreground: " +
    +-                            ((then == 0) ? "never" : new Date(then)));
    +-                }
    +-                i.remove();
    +-                skipped++;
    +-            } else {
    +-                if (DEBUG_DEXOPT) {
    +-                    Log.i(TAG, "Will dexopt " + pkg.packageName +
    +-                            " last used in foreground: " +
    +-                            ((then == 0) ? "never" : new Date(then)));
    +-                }
    ++    // Sort a list of apps by their last usage, most recently used apps first. The order of
    ++    // packages without usage data is undefined (but they will be sorted after the packages
    ++    // that do have usage data).
    ++    public static void sortPackagesByUsageDate(List<PackageParser.Package> pkgs,
    ++            PackageManagerService packageManagerService) {
    ++        if (!packageManagerService.isHistoricalPackageUsageAvailable()) {
    ++            return;
    ++        }
    ++
    ++        Collections.sort(pkgs, (pkg1, pkg2) ->
    ++                Long.compare(pkg2.getLatestForegroundPackageUseTimeInMills(),
    ++                        pkg1.getLatestForegroundPackageUseTimeInMills()));
    ++    }
    ++
    ++    // Apply the given {@code filter} to all packages in {@code packages}. If tested positive, the
    ++    // package will be removed from {@code packages} and added to {@code result} with its
    ++    // dependencies. If usage data is available, the positive packages will be sorted by usage
    ++    // data (with {@code sortTemp} as temporary storage).
    ++    private static void applyPackageFilter(Predicate<PackageParser.Package> filter,
    ++            Collection<PackageParser.Package> result,
    ++            Collection<PackageParser.Package> packages,
    ++            @NonNull List<PackageParser.Package> sortTemp,
    ++            PackageManagerService packageManagerService) {
    ++        for (PackageParser.Package pkg : packages) {
    ++            if (filter.test(pkg)) {
    ++                sortTemp.add(pkg);
    +             }
    +         }
    +-        if (DEBUG_DEXOPT) {
    +-            Log.i(TAG, "Skipped dexopt " + skipped + " of " + total);
    ++
    ++        sortPackagesByUsageDate(sortTemp, packageManagerService);
    ++        packages.removeAll(sortTemp);
    ++
    ++        for (PackageParser.Package pkg : sortTemp) {
    ++            result.add(pkg);
    ++
    ++            Collection<PackageParser.Package> deps =
    ++                    packageManagerService.findSharedNonSystemLibraries(pkg);
    ++            if (!deps.isEmpty()) {
    ++                deps.removeAll(result);
    ++                result.addAll(deps);
    ++                packages.removeAll(deps);
    ++            }
    +         }
    ++
    ++        sortTemp.clear();
    +     }
    + 
    +     // Sort apps by importance for dexopt ordering. Important apps are given
    +@@ -104,46 +118,25 @@ public class PackageManagerServiceUtils {
    +             PackageManagerService packageManagerService) {
    +         ArrayList<PackageParser.Package> remainingPkgs = new ArrayList<>(packages);
    +         LinkedList<PackageParser.Package> result = new LinkedList<>();
    ++        ArrayList<PackageParser.Package> sortTemp = new ArrayList<>(remainingPkgs.size());
    + 
    +         // Give priority to core apps.
    +-        for (PackageParser.Package pkg : remainingPkgs) {
    +-            if (pkg.coreApp) {
    +-                if (DEBUG_DEXOPT) {
    +-                    Log.i(TAG, "Adding core app " + result.size() + ": " + pkg.packageName);
    +-                }
    +-                result.add(pkg);
    +-            }
    +-        }
    +-        remainingPkgs.removeAll(result);
    ++        applyPackageFilter((pkg) -> pkg.coreApp, result, remainingPkgs, sortTemp,
    ++                packageManagerService);
    + 
    +         // Give priority to system apps that listen for pre boot complete.
    +         Intent intent = new Intent(Intent.ACTION_PRE_BOOT_COMPLETED);
    +-        ArraySet<String> pkgNames = getPackageNamesForIntent(intent, UserHandle.USER_SYSTEM);
    +-        for (PackageParser.Package pkg : remainingPkgs) {
    +-            if (pkgNames.contains(pkg.packageName)) {
    +-                if (DEBUG_DEXOPT) {
    +-                    Log.i(TAG, "Adding pre boot system app " + result.size() + ": " +
    +-                            pkg.packageName);
    +-                }
    +-                result.add(pkg);
    +-            }
    +-        }
    +-        remainingPkgs.removeAll(result);
    ++        final ArraySet<String> pkgNames = getPackageNamesForIntent(intent, UserHandle.USER_SYSTEM);
    ++        applyPackageFilter((pkg) -> pkgNames.contains(pkg.packageName), result, remainingPkgs,
    ++                sortTemp, packageManagerService);
    + 
    +         // Give priority to apps used by other apps.
    +-        for (PackageParser.Package pkg : remainingPkgs) {
    +-            if (PackageDexOptimizer.isUsedByOtherApps(pkg)) {
    +-                if (DEBUG_DEXOPT) {
    +-                    Log.i(TAG, "Adding app used by other apps " + result.size() + ": " +
    +-                            pkg.packageName);
    +-                }
    +-                result.add(pkg);
    +-            }
    +-        }
    +-        remainingPkgs.removeAll(result);
    ++        applyPackageFilter((pkg) -> PackageDexOptimizer.isUsedByOtherApps(pkg), result,
    ++                remainingPkgs, sortTemp, packageManagerService);
    + 
    +         // Filter out packages that aren't recently used, add all remaining apps.
    +         // TODO: add a property to control this?
    ++        Predicate<PackageParser.Package> remainingPredicate;
    +         if (!remainingPkgs.isEmpty() && packageManagerService.isHistoricalPackageUsageAvailable()) {
    +             if (DEBUG_DEXOPT) {
    +                 Log.i(TAG, "Looking at historical package use");
    +@@ -159,34 +152,24 @@ public class PackageManagerServiceUtils {
    +                     lastUsed.getLatestForegroundPackageUseTimeInMills();
    +             // Be defensive if for some reason package usage has bogus data.
    +             if (estimatedPreviousSystemUseTime != 0) {
    +-                filterRecentlyUsedApps(remainingPkgs, estimatedPreviousSystemUseTime,
    +-                        SEVEN_DAYS_IN_MILLISECONDS);
    ++                final long cutoffTime = estimatedPreviousSystemUseTime - SEVEN_DAYS_IN_MILLISECONDS;
    ++                remainingPredicate =
    ++                        (pkg) -> pkg.getLatestForegroundPackageUseTimeInMills() >= cutoffTime;
    ++            } else {
    ++                // No meaningful historical info. Take all.
    ++                remainingPredicate = (pkg) -> true;
    +             }
    ++            sortPackagesByUsageDate(remainingPkgs, packageManagerService);
    ++        } else {
    ++            // No historical info. Take all.
    ++            remainingPredicate = (pkg) -> true;
    +         }
    +-        result.addAll(remainingPkgs);
    +-
    +-        // Now go ahead and also add the libraries required for these packages.
    +-        // TODO: Think about interleaving things.
    +-        Set<PackageParser.Package> dependencies = new HashSet<>();
    +-        for (PackageParser.Package p : result) {
    +-            dependencies.addAll(packageManagerService.findSharedNonSystemLibraries(p));
    +-        }
    +-        if (!dependencies.isEmpty()) {
    +-            // We might have packages already in `result` that are dependencies
    +-            // of other packages. Make sure we don't add those to the list twice.
    +-            dependencies.removeAll(result);
    +-        }
    +-        result.addAll(dependencies);
    ++        applyPackageFilter(remainingPredicate, result, remainingPkgs, sortTemp,
    ++                packageManagerService);
    + 
    +         if (DEBUG_DEXOPT) {
    +-            StringBuilder sb = new StringBuilder();
    +-            for (PackageParser.Package pkg : result) {
    +-                if (sb.length() > 0) {
    +-                    sb.append(", ");
    +-                }
    +-                sb.append(pkg.packageName);
    +-            }
    +-            Log.i(TAG, "Packages to be dexopted: " + sb.toString());
    ++            Log.i(TAG, "Packages to be dexopted: " + packagesToString(result));
    ++            Log.i(TAG, "Packages skipped from dexopt: " + packagesToString(remainingPkgs));
    +         }
    + 
    +         return result;
    +@@ -203,4 +186,15 @@ public class PackageManagerServiceUtils {
    +             throw ee.rethrowAsIOException();
    +         }
    +     }
    ++
    ++    public static String packagesToString(Collection<PackageParser.Package> c) {
    ++        StringBuilder sb = new StringBuilder();
    ++        for (PackageParser.Package pkg : c) {
    ++            if (sb.length() > 0) {
    ++                sb.append(", ");
    ++            }
    ++            sb.append(pkg.packageName);
    ++        }
    ++        return sb.toString();
    ++    }
    + }
    +diff --git a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
    +index e5ddfd0..3bfa6b8 100644
    +--- a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
    ++++ b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
    +@@ -30,6 +30,10 @@ import android.content.pm.PackageInfo;
    + import android.content.pm.PackageInstaller;
    + import android.content.pm.PackageItemInfo;
    + import android.content.pm.PackageManager;
    ++import android.content.pm.PackageParser;
    ++import android.content.pm.PackageParser.ApkLite;
    ++import android.content.pm.PackageParser.PackageLite;
    ++import android.content.pm.PackageParser.PackageParserException;
    + import android.content.pm.ParceledListSlice;
    + import android.content.pm.PermissionGroupInfo;
    + import android.content.pm.PermissionInfo;
    +@@ -48,6 +52,7 @@ import android.os.SystemProperties;
    + import android.os.UserHandle;
    + import android.text.TextUtils;
    + import android.util.PrintWriterPrinter;
    ++import com.android.internal.content.PackageHelper;
    + import com.android.internal.util.SizedInputStream;
    + 
    + import dalvik.system.DexFile;
    +@@ -137,11 +142,33 @@ class PackageManagerShellCommand extends ShellCommand {
    +     private int runInstall() throws RemoteException {
    +         final PrintWriter pw = getOutPrintWriter();
    +         final InstallParams params = makeInstallParams();
    ++        final String inPath = getNextArg();
    ++        boolean installExternal =
    ++                (params.sessionParams.installFlags & PackageManager.INSTALL_EXTERNAL) != 0;
    ++        if (params.sessionParams.sizeBytes < 0 && inPath != null) {
    ++            File file = new File(inPath);
    ++            if (file.isFile()) {
    ++                if (installExternal) {
    ++                    try {
    ++                        ApkLite baseApk = PackageParser.parseApkLite(file, 0);
    ++                        PackageLite pkgLite = new PackageLite(null, baseApk, null, null, null);
    ++                        params.sessionParams.setSize(
    ++                                PackageHelper.calculateInstalledSize(pkgLite, false,
    ++                                        params.sessionParams.abiOverride));
    ++                    } catch (PackageParserException | IOException e) {
    ++                        pw.println("Error: Failed to parse APK file : " + e);
    ++                        return 1;
    ++                    }
    ++                } else {
    ++                    params.sessionParams.setSize(file.length());
    ++                }
    ++            }
    ++        }
    ++
    +         final int sessionId = doCreateSession(params.sessionParams,
    +                 params.installerPackageName, params.userId);
    +         boolean abandonSession = true;
    +         try {
    +-            final String inPath = getNextArg();
    +             if (inPath == null && params.sessionParams.sizeBytes == 0) {
    +                 pw.println("Error: must either specify a package size or an APK file");
    +                 return 1;
    +@@ -1147,14 +1174,15 @@ class PackageManagerShellCommand extends ShellCommand {
    +     private int doWriteSplit(int sessionId, String inPath, long sizeBytes, String splitName,
    +             boolean logSuccess) throws RemoteException {
    +         final PrintWriter pw = getOutPrintWriter();
    +-        if ("-".equals(inPath)) {
    +-            inPath = null;
    +-        } else if (inPath != null) {
    +-            final File file = new File(inPath);
    +-            if (file.isFile()) {
    +-                sizeBytes = file.length();
    +-            }
    ++        if (sizeBytes <= 0) {
    ++            pw.println("Error: must specify a APK size");
    ++            return 1;
    ++        }
    ++        if (inPath != null && !"-".equals(inPath)) {
    ++            pw.println("Error: APK content must be streamed");
    ++            return 1;
    +         }
    ++        inPath = null;
    + 
    +         final SessionInfo info = mInterface.getPackageInstaller().getSessionInfo(sessionId);
    + 
    +diff --git a/services/core/java/com/android/server/pm/SELinuxMMAC.java b/services/core/java/com/android/server/pm/SELinuxMMAC.java
    +index 8970556..2176eb1 100644
    +--- a/services/core/java/com/android/server/pm/SELinuxMMAC.java
    ++++ b/services/core/java/com/android/server/pm/SELinuxMMAC.java
    +@@ -19,10 +19,6 @@ package com.android.server.pm;
    + import android.content.pm.PackageParser;
    + import android.content.pm.Signature;
    + import android.os.Environment;
    +-import android.os.SystemProperties;
    +-import android.system.ErrnoException;
    +-import android.system.Os;
    +-import android.system.OsConstants;
    + import android.util.Slog;
    + import android.util.Xml;
    + 
    +@@ -34,10 +30,7 @@ import org.xmlpull.v1.XmlPullParserException;
    + import java.io.File;
    + import java.io.FileReader;
    + import java.io.IOException;
    +-import java.security.MessageDigest;
    +-import java.security.NoSuchAlgorithmException;
    + import java.util.ArrayList;
    +-import java.util.Arrays;
    + import java.util.Collections;
    + import java.util.Comparator;
    + import java.util.HashMap;
    +@@ -65,24 +58,10 @@ public final class SELinuxMMAC {
    +     // to synchronize access during policy load and access attempts.
    +     private static List<Policy> sPolicies = new ArrayList<>();
    + 
    +-    private static final String PROP_FORCE_RESTORECON = "sys.force_restorecon";
    +-
    +-    /** Path to version on rootfs */
    +-    private static final File VERSION_FILE = new File("/selinux_version");
    +-
    +     /** Path to MAC permissions on system image */
    +     private static final File MAC_PERMISSIONS = new File(Environment.getRootDirectory(),
    +             "/etc/security/mac_permissions.xml");
    + 
    +-    /** Path to app contexts on rootfs */
    +-    private static final File SEAPP_CONTEXTS = new File("/seapp_contexts");
    +-
    +-    /** Calculated hash of {@link #SEAPP_CONTEXTS} */
    +-    private static final byte[] SEAPP_CONTEXTS_HASH = returnHash(SEAPP_CONTEXTS);
    +-
    +-    /** Attribute where {@link #SEAPP_CONTEXTS_HASH} is stored */
    +-    private static final String XATTR_SEAPP_HASH = "user.seapp_hash";
    +-
    +     // Append privapp to existing seinfo label
    +     private static final String PRIVILEGED_APP_STR = ":privapp";
    + 
    +@@ -313,66 +292,6 @@ public final class SELinuxMMAC {
    +                     "seinfo=" + pkg.applicationInfo.seinfo);
    +         }
    +     }
    +-
    +-    /**
    +-     * Determines if a recursive restorecon on the given package data directory
    +-     * is needed. It does this by comparing the SHA-1 of the seapp_contexts file
    +-     * against the stored hash in an xattr.
    +-     * <p>
    +-     * Note that the xattr isn't in the 'security' namespace, so this should
    +-     * only be run on directories owned by the system.
    +-     *
    +-     * @return Returns true if the restorecon should occur or false otherwise.
    +-     */
    +-    public static boolean isRestoreconNeeded(File file) {
    +-        // To investigate boot timing, allow a property to always force restorecon
    +-        if (SystemProperties.getBoolean(PROP_FORCE_RESTORECON, false)) {
    +-            return true;
    +-        }
    +-
    +-        try {
    +-            final byte[] buf = new byte[20];
    +-            final int len = Os.getxattr(file.getAbsolutePath(), XATTR_SEAPP_HASH, buf);
    +-            if ((len == 20) && Arrays.equals(SEAPP_CONTEXTS_HASH, buf)) {
    +-                return false;
    +-            }
    +-        } catch (ErrnoException e) {
    +-            if (e.errno != OsConstants.ENODATA) {
    +-                Slog.e(TAG, "Failed to read seapp hash for " + file, e);
    +-            }
    +-        }
    +-
    +-        return true;
    +-    }
    +-
    +-    /**
    +-     * Stores the SHA-1 of the seapp_contexts into an xattr.
    +-     * <p>
    +-     * Note that the xattr isn't in the 'security' namespace, so this should
    +-     * only be run on directories owned by the system.
    +-     */
    +-    public static void setRestoreconDone(File file) {
    +-        try {
    +-            Os.setxattr(file.getAbsolutePath(), XATTR_SEAPP_HASH, SEAPP_CONTEXTS_HASH, 0);
    +-        } catch (ErrnoException e) {
    +-            Slog.e(TAG, "Failed to persist seapp hash in " + file, e);
    +-        }
    +-    }
    +-
    +-    /**
    +-     * Return the SHA-1 of a file.
    +-     *
    +-     * @param file The path to the file given as a string.
    +-     * @return Returns the SHA-1 of the file as a byte array.
    +-     */
    +-    private static byte[] returnHash(File file) {
    +-        try {
    +-            final byte[] contents = IoUtils.readFileAsByteArray(file.getAbsolutePath());
    +-            return MessageDigest.getInstance("SHA-1").digest(contents);
    +-        } catch (IOException | NoSuchAlgorithmException e) {
    +-            throw new RuntimeException(e);
    +-        }
    +-    }
    + }
    + 
    + /**
    +diff --git a/services/core/java/com/android/server/pm/Settings.java b/services/core/java/com/android/server/pm/Settings.java
    +index 5126305..b0c536f 100644
    +--- a/services/core/java/com/android/server/pm/Settings.java
    ++++ b/services/core/java/com/android/server/pm/Settings.java
    +@@ -4154,6 +4154,14 @@ final class Settings {
    +         return pkg.getCurrentEnabledStateLPr(classNameStr, userId);
    +     }
    + 
    ++    boolean wasPackageEverLaunchedLPr(String packageName, int userId) {
    ++        final PackageSetting pkgSetting = mPackages.get(packageName);
    ++        if (pkgSetting == null) {
    ++            throw new IllegalArgumentException("Unknown package: " + packageName);
    ++        }
    ++        return !pkgSetting.getNotLaunched(userId);
    ++    }
    ++
    +     boolean setPackageStoppedStateLPw(PackageManagerService pm, String packageName,
    +             boolean stopped, boolean allowedByPermission, int uid, int userId) {
    +         int appId = UserHandle.getAppId(uid);
    +diff --git a/services/core/java/com/android/server/pm/ShortcutLauncher.java b/services/core/java/com/android/server/pm/ShortcutLauncher.java
    +index df51923..2af1bcb 100644
    +--- a/services/core/java/com/android/server/pm/ShortcutLauncher.java
    ++++ b/services/core/java/com/android/server/pm/ShortcutLauncher.java
    +@@ -17,6 +17,7 @@ package com.android.server.pm;
    + 
    + import android.annotation.NonNull;
    + import android.annotation.UserIdInt;
    ++import android.content.pm.PackageInfo;
    + import android.content.pm.ShortcutInfo;
    + import android.util.ArrayMap;
    + import android.util.ArraySet;
    +@@ -151,6 +152,16 @@ class ShortcutLauncher extends ShortcutPackageItem {
    +         return mPinnedShortcuts.remove(PackageWithUser.of(packageUserId, packageName)) != null;
    +     }
    + 
    ++    public void ensureVersionInfo() {
    ++        final PackageInfo pi = mShortcutUser.mService.getPackageInfoWithSignatures(
    ++                getPackageName(), getPackageUserId());
    ++        if (pi == null) {
    ++            Slog.w(TAG, "Package not found: " + getPackageName());
    ++            return;
    ++        }
    ++        getPackageInfo().updateVersionInfo(pi);
    ++    }
    ++
    +     /**
    +      * Persist.
    +      */
    +@@ -202,7 +213,7 @@ class ShortcutLauncher extends ShortcutPackageItem {
    +                 fromBackup ? ownerUserId
    +                 : ShortcutService.parseIntAttribute(parser, ATTR_LAUNCHER_USER_ID, ownerUserId);
    + 
    +-        final ShortcutLauncher ret = new ShortcutLauncher(shortcutUser, launcherUserId,
    ++        final ShortcutLauncher ret = new ShortcutLauncher(shortcutUser, ownerUserId,
    +                 launcherPackageName, launcherUserId);
    + 
    +         ArraySet<String> ids = null;
    +diff --git a/services/core/java/com/android/server/pm/ShortcutPackage.java b/services/core/java/com/android/server/pm/ShortcutPackage.java
    +index 827b88a..38d69ed 100644
    +--- a/services/core/java/com/android/server/pm/ShortcutPackage.java
    ++++ b/services/core/java/com/android/server/pm/ShortcutPackage.java
    +@@ -23,7 +23,6 @@ import android.content.Intent;
    + import android.content.pm.PackageInfo;
    + import android.content.pm.ShortcutInfo;
    + import android.content.res.Resources;
    +-import android.os.Bundle;
    + import android.os.PersistableBundle;
    + import android.text.format.Formatter;
    + import android.util.ArrayMap;
    +@@ -145,30 +144,6 @@ class ShortcutPackage extends ShortcutPackageItem {
    +         return mPackageUid;
    +     }
    + 
    +-    /**
    +-     * Called when a shortcut is about to be published.  At this point we know the publisher
    +-     * package
    +-     * exists (as opposed to Launcher trying to fetch shortcuts from a non-existent package), so
    +-     * we do some initialization for the package.
    +-     */
    +-    private void ensurePackageVersionInfo() {
    +-        // Make sure we have the version code for the app.  We need the version code in
    +-        // handlePackageUpdated().
    +-        if (getPackageInfo().getVersionCode() < 0) {
    +-            final ShortcutService s = mShortcutUser.mService;
    +-
    +-            final PackageInfo pi = s.getPackageInfo(getPackageName(), getOwnerUserId());
    +-            if (pi != null) {
    +-                if (ShortcutService.DEBUG) {
    +-                    Slog.d(TAG, String.format("Package %s version = %d", getPackageName(),
    +-                            pi.versionCode));
    +-                }
    +-                getPackageInfo().updateVersionInfo(pi);
    +-                s.scheduleSaveUser(getOwnerUserId());
    +-            }
    +-        }
    +-    }
    +-
    +     @Nullable
    +     public Resources getPackageResources() {
    +         return mShortcutUser.mService.injectGetResourcesForApplicationAsUser(
    +@@ -251,8 +226,6 @@ class ShortcutPackage extends ShortcutPackageItem {
    +         Preconditions.checkArgument(newShortcut.isEnabled(),
    +                 "add/setDynamicShortcuts() cannot publish disabled shortcuts");
    + 
    +-        ensurePackageVersionInfo();
    +-
    +         newShortcut.addFlags(ShortcutInfo.FLAG_DYNAMIC);
    + 
    +         final ShortcutInfo oldShortcut = mShortcuts.get(newShortcut.getId());
    +@@ -662,17 +635,32 @@ class ShortcutPackage extends ShortcutPackageItem {
    +                 return false; // Shouldn't happen.
    +             }
    + 
    +-            if (!isNewApp && !forceRescan) {
    ++            // Always scan the settings app, since its version code is the same for DR and MR1.
    ++            // TODO Fix it properly: b/32554059
    ++            final boolean isSettings = "com.android.settings".equals(getPackageName());
    ++
    ++            if (!isNewApp && !forceRescan && !isSettings) {
    +                 // Return if the package hasn't changed, ie:
    +                 // - version code hasn't change
    +                 // - lastUpdateTime hasn't change
    +                 // - all target activities are still enabled.
    ++
    ++                // Note, system apps timestamps do *not* change after OTAs.  (But they do
    ++                // after an adb sync or a local flash.)
    ++                // This means if a system app's version code doesn't change on an OTA,
    ++                // we don't notice it's updated.  But that's fine since their version code *should*
    ++                // really change on OTAs.
    +                 if ((getPackageInfo().getVersionCode() == pi.versionCode)
    +                         && (getPackageInfo().getLastUpdateTime() == pi.lastUpdateTime)
    +                         && areAllActivitiesStillEnabled()) {
    +                     return false;
    +                 }
    +             }
    ++            if (isSettings) {
    ++                if (ShortcutService.DEBUG) {
    ++                    Slog.d(TAG, "Always scan settings.");
    ++                }
    ++            }
    +         } finally {
    +             s.logDurationStat(Stats.PACKAGE_UPDATE_CHECK, start);
    +         }
    +@@ -1145,6 +1133,17 @@ class ShortcutPackage extends ShortcutPackageItem {
    +         }
    +     }
    + 
    ++    /** @return true if there's any shortcuts that are not manifest shortcuts. */
    ++    public boolean hasNonManifestShortcuts() {
    ++        for (int i = mShortcuts.size() - 1; i >= 0; i--) {
    ++            final ShortcutInfo si = mShortcuts.valueAt(i);
    ++            if (!si.isDeclaredInManifest()) {
    ++                return true;
    ++            }
    ++        }
    ++        return false;
    ++    }
    ++
    +     public void dump(@NonNull PrintWriter pw, @NonNull String prefix) {
    +         pw.println();
    + 
    +diff --git a/services/core/java/com/android/server/pm/ShortcutPackageInfo.java b/services/core/java/com/android/server/pm/ShortcutPackageInfo.java
    +index e7b66fc..4de15de 100644
    +--- a/services/core/java/com/android/server/pm/ShortcutPackageInfo.java
    ++++ b/services/core/java/com/android/server/pm/ShortcutPackageInfo.java
    +@@ -20,6 +20,7 @@ import android.annotation.UserIdInt;
    + import android.content.pm.PackageInfo;
    + import android.util.Slog;
    + 
    ++import com.android.internal.annotations.VisibleForTesting;
    + import com.android.server.backup.BackupUtils;
    + 
    + import libcore.io.Base64;
    +@@ -89,6 +90,7 @@ class ShortcutPackageInfo {
    +         return mLastUpdateTime;
    +     }
    + 
    ++    /** Set {@link #mVersionCode} and {@link #mLastUpdateTime} from a {@link PackageInfo}. */
    +     public void updateVersionInfo(@NonNull PackageInfo pi) {
    +         if (pi != null) {
    +             mVersionCode = pi.versionCode;
    +@@ -119,7 +121,8 @@ class ShortcutPackageInfo {
    +         return true;
    +     }
    + 
    +-    public static ShortcutPackageInfo generateForInstalledPackage(
    ++    @VisibleForTesting
    ++    public static ShortcutPackageInfo generateForInstalledPackageForTest(
    +             ShortcutService s, String packageName, @UserIdInt int packageUserId) {
    +         final PackageInfo pi = s.getPackageInfoWithSignatures(packageName, packageUserId);
    +         if (pi.signatures == null || pi.signatures.length == 0) {
    +@@ -132,7 +135,7 @@ class ShortcutPackageInfo {
    +         return ret;
    +     }
    + 
    +-    public void refresh(ShortcutService s, ShortcutPackageItem pkg) {
    ++    public void refreshSignature(ShortcutService s, ShortcutPackageItem pkg) {
    +         if (mIsShadow) {
    +             s.wtf("Attempted to refresh package info for shadow package " + pkg.getPackageName()
    +                     + ", user=" + pkg.getOwnerUserId());
    +@@ -145,8 +148,6 @@ class ShortcutPackageInfo {
    +             Slog.w(TAG, "Package not found: " + pkg.getPackageName());
    +             return;
    +         }
    +-        mVersionCode = pi.versionCode;
    +-        mLastUpdateTime = pi.lastUpdateTime;
    +         mSigHashes = BackupUtils.hashSignatureArray(pi.signatures);
    +     }
    + 
    +diff --git a/services/core/java/com/android/server/pm/ShortcutPackageItem.java b/services/core/java/com/android/server/pm/ShortcutPackageItem.java
    +index 79b5c4e..1f195a7 100644
    +--- a/services/core/java/com/android/server/pm/ShortcutPackageItem.java
    ++++ b/services/core/java/com/android/server/pm/ShortcutPackageItem.java
    +@@ -40,7 +40,7 @@ abstract class ShortcutPackageItem {
    + 
    +     private final ShortcutPackageInfo mPackageInfo;
    + 
    +-    protected final ShortcutUser mShortcutUser;
    ++    protected ShortcutUser mShortcutUser;
    + 
    +     protected ShortcutPackageItem(@NonNull ShortcutUser shortcutUser,
    +             int packageUserId, @NonNull String packageName,
    +@@ -51,6 +51,13 @@ abstract class ShortcutPackageItem {
    +         mPackageInfo = Preconditions.checkNotNull(packageInfo);
    +     }
    + 
    ++    /**
    ++     * Change the parent {@link ShortcutUser}.  Need it in the restore code.
    ++     */
    ++    public void replaceUser(ShortcutUser user) {
    ++        mShortcutUser = user;
    ++    }
    ++
    +     public ShortcutUser getUser() {
    +         return mShortcutUser;
    +     }
    +@@ -58,8 +65,7 @@ abstract class ShortcutPackageItem {
    +     /**
    +      * ID of the user who actually has this package running on.  For {@link ShortcutPackage},
    +      * this is the same thing as {@link #getOwnerUserId}, but if it's a {@link ShortcutLauncher} and
    +-     * {@link #getOwnerUserId} is of a work profile, then this ID could be the user who owns the
    +-     * profile.
    ++     * {@link #getOwnerUserId} is of work profile, then this ID is of the primary user.
    +      */
    +     public int getPackageUserId() {
    +         return mPackageUserId;
    +@@ -79,12 +85,12 @@ abstract class ShortcutPackageItem {
    +         return mPackageInfo;
    +     }
    + 
    +-    public void refreshPackageInfoAndSave() {
    ++    public void refreshPackageSignatureAndSave() {
    +         if (mPackageInfo.isShadow()) {
    +             return; // Don't refresh for shadow user.
    +         }
    +         final ShortcutService s = mShortcutUser.mService;
    +-        mPackageInfo.refresh(s, this);
    ++        mPackageInfo.refreshSignature(s, this);
    +         s.scheduleSaveUser(getOwnerUserId());
    +     }
    + 
    +diff --git a/services/core/java/com/android/server/pm/ShortcutService.java b/services/core/java/com/android/server/pm/ShortcutService.java
    +index c1fc7f1..13f558e 100644
    +--- a/services/core/java/com/android/server/pm/ShortcutService.java
    ++++ b/services/core/java/com/android/server/pm/ShortcutService.java
    +@@ -54,6 +54,7 @@ import android.graphics.RectF;
    + import android.graphics.drawable.Icon;
    + import android.net.Uri;
    + import android.os.Binder;
    ++import android.os.Build;
    + import android.os.Environment;
    + import android.os.FileUtils;
    + import android.os.Handler;
    +@@ -324,9 +325,29 @@ public class ShortcutService extends IShortcutService.Stub {
    +         int CHECK_LAUNCHER_ACTIVITY = 12;
    +         int IS_ACTIVITY_ENABLED = 13;
    +         int PACKAGE_UPDATE_CHECK = 14;
    +-
    +-        int COUNT = PACKAGE_UPDATE_CHECK + 1;
    +-    }
    ++        int ASYNC_PRELOAD_USER_DELAY = 15;
    ++
    ++        int COUNT = ASYNC_PRELOAD_USER_DELAY + 1;
    ++    }
    ++
    ++    private static final String[] STAT_LABELS = {
    ++            "getHomeActivities()",
    ++            "Launcher permission check",
    ++            "getPackageInfo()",
    ++            "getPackageInfo(SIG)",
    ++            "getApplicationInfo",
    ++            "cleanupDanglingBitmaps",
    ++            "getActivity+metadata",
    ++            "getInstalledPackages",
    ++            "checkPackageChanges",
    ++            "getApplicationResources",
    ++            "resourceNameLookup",
    ++            "getLauncherActivity",
    ++            "checkLauncherActivity",
    ++            "isActivityEnabled",
    ++            "packageUpdateCheck",
    ++            "asyncPreloadUserDelay"
    ++    };
    + 
    +     final Object mStatLock = new Object();
    + 
    +@@ -359,6 +380,12 @@ public class ShortcutService extends IShortcutService.Stub {
    +     @GuardedBy("mLock")
    +     private Exception mLastWtfStacktrace;
    + 
    ++    static class InvalidFileFormatException extends Exception {
    ++        public InvalidFileFormatException(String message, Throwable cause) {
    ++            super(message, cause);
    ++        }
    ++    }
    ++
    +     public ShortcutService(Context context) {
    +         this(context, BackgroundThread.get().getLooper(), /*onyForPackgeManagerApis*/ false);
    +     }
    +@@ -533,19 +560,26 @@ public class ShortcutService extends IShortcutService.Stub {
    +     /** lifecycle event */
    +     void handleUnlockUser(int userId) {
    +         if (DEBUG) {
    +-            Slog.d(TAG, "handleUnlockUser: user=" + userId);
    ++        Slog.d(TAG, "handleUnlockUser: user=" + userId);
    +         }
    +         synchronized (mLock) {
    +             mUnlockedUsers.put(userId, true);
    +-
    +-            // Preload the user's shortcuts.
    +-            // Also see if the locale has changed.
    +-            // Note as of nyc, the locale is per-user, so the locale shouldn't change
    +-            // when the user is locked.  However due to b/30119489 it still happens.
    +-            getUserShortcutsLocked(userId).detectLocaleChange();
    +-
    +-            checkPackageChanges(userId);
    +         }
    ++
    ++        // Preload the user data.
    ++        // Note, we don't use mHandler here but instead just start a new thread.
    ++        // This is because mHandler (which uses com.android.internal.os.BackgroundThread) is very
    ++        // busy at this point and this could take hundreds of milliseconds, which would be too
    ++        // late since the launcher would already have started.
    ++        // So we just create a new thread.  This code runs rarely, so we don't use a thread pool
    ++        // or anything.
    ++        final long start = injectElapsedRealtime();
    ++        injectRunOnNewThread(() -> {
    ++            synchronized (mLock) {
    ++                logDurationStat(Stats.ASYNC_PRELOAD_USER_DELAY, start);
    ++                getUserShortcutsLocked(userId);
    ++            }
    ++        });
    +     }
    + 
    +     /** lifecycle event */
    +@@ -933,7 +967,7 @@ public class ShortcutService extends IShortcutService.Stub {
    +         try {
    +             final ShortcutUser ret = loadUserInternal(userId, in, /* forBackup= */ false);
    +             return ret;
    +-        } catch (IOException | XmlPullParserException e) {
    ++        } catch (IOException | XmlPullParserException | InvalidFileFormatException e) {
    +             Slog.e(TAG, "Failed to read file " + file.getBaseFile(), e);
    +             return null;
    +         } finally {
    +@@ -942,7 +976,8 @@ public class ShortcutService extends IShortcutService.Stub {
    +     }
    + 
    +     private ShortcutUser loadUserInternal(@UserIdInt int userId, InputStream is,
    +-            boolean fromBackup) throws XmlPullParserException, IOException {
    ++            boolean fromBackup) throws XmlPullParserException, IOException,
    ++            InvalidFileFormatException {
    + 
    +         final BufferedInputStream bis = new BufferedInputStream(is);
    + 
    +@@ -1110,6 +1145,9 @@ public class ShortcutService extends IShortcutService.Stub {
    +                 userPackages = new ShortcutUser(this, userId);
    +             }
    +             mUsers.put(userId, userPackages);
    ++
    ++            // Also when a user's data is first accessed, scan all packages.
    ++            checkPackageChanges(userId);
    +         }
    +         return userPackages;
    +     }
    +@@ -1120,7 +1158,10 @@ public class ShortcutService extends IShortcutService.Stub {
    +         }
    +     }
    + 
    +-    /** Return the per-user per-package state. */
    ++    /**
    ++     * Return the per-user per-package state.  If the caller is a publisher, use
    ++     * {@link #getPackageShortcutsForPublisherLocked} instead.
    ++     */
    +     @GuardedBy("mLock")
    +     @NonNull
    +     ShortcutPackage getPackageShortcutsLocked(
    +@@ -1128,6 +1169,16 @@ public class ShortcutService extends IShortcutService.Stub {
    +         return getUserShortcutsLocked(userId).getPackageShortcuts(packageName);
    +     }
    + 
    ++    /** Return the per-user per-package state.  Use this when the caller is a publisher. */
    ++    @GuardedBy("mLock")
    ++    @NonNull
    ++    ShortcutPackage getPackageShortcutsForPublisherLocked(
    ++            @NonNull String packageName, @UserIdInt int userId) {
    ++        final ShortcutPackage ret = getUserShortcutsLocked(userId).getPackageShortcuts(packageName);
    ++        ret.getUser().onCalledByPublisher(packageName);
    ++        return ret;
    ++    }
    ++
    +     @GuardedBy("mLock")
    +     @NonNull
    +     ShortcutLauncher getLauncherShortcutsLocked(
    +@@ -1468,6 +1519,10 @@ public class ShortcutService extends IShortcutService.Stub {
    +         mHandler.post(r);
    +     }
    + 
    ++    void injectRunOnNewThread(Runnable r) {
    ++        new Thread(r).start();
    ++    }
    ++
    +     /**
    +      * @throws IllegalArgumentException if {@code numShortcuts} is bigger than
    +      *                                  {@link #getMaxActivityShortcuts()}.
    +@@ -1592,8 +1647,7 @@ public class ShortcutService extends IShortcutService.Stub {
    +         synchronized (mLock) {
    +             throwIfUserLockedL(userId);
    + 
    +-            final ShortcutPackage ps = getPackageShortcutsLocked(packageName, userId);
    +-            ps.getUser().onCalledByPublisher(packageName);
    ++            final ShortcutPackage ps = getPackageShortcutsForPublisherLocked(packageName, userId);
    + 
    +             ps.ensureImmutableShortcutsNotIncluded(newShortcuts);
    + 
    +@@ -1644,8 +1698,7 @@ public class ShortcutService extends IShortcutService.Stub {
    +         synchronized (mLock) {
    +             throwIfUserLockedL(userId);
    + 
    +-            final ShortcutPackage ps = getPackageShortcutsLocked(packageName, userId);
    +-            ps.getUser().onCalledByPublisher(packageName);
    ++            final ShortcutPackage ps = getPackageShortcutsForPublisherLocked(packageName, userId);
    + 
    +             ps.ensureImmutableShortcutsNotIncluded(newShortcuts);
    + 
    +@@ -1725,8 +1778,7 @@ public class ShortcutService extends IShortcutService.Stub {
    +         synchronized (mLock) {
    +             throwIfUserLockedL(userId);
    + 
    +-            final ShortcutPackage ps = getPackageShortcutsLocked(packageName, userId);
    +-            ps.getUser().onCalledByPublisher(packageName);
    ++            final ShortcutPackage ps = getPackageShortcutsForPublisherLocked(packageName, userId);
    + 
    +             ps.ensureImmutableShortcutsNotIncluded(newShortcuts);
    + 
    +@@ -1775,8 +1827,7 @@ public class ShortcutService extends IShortcutService.Stub {
    +         synchronized (mLock) {
    +             throwIfUserLockedL(userId);
    + 
    +-            final ShortcutPackage ps = getPackageShortcutsLocked(packageName, userId);
    +-            ps.getUser().onCalledByPublisher(packageName);
    ++            final ShortcutPackage ps = getPackageShortcutsForPublisherLocked(packageName, userId);
    + 
    +             ps.ensureImmutableShortcutsNotIncludedWithIds((List<String>) shortcutIds);
    + 
    +@@ -1805,8 +1856,7 @@ public class ShortcutService extends IShortcutService.Stub {
    +         synchronized (mLock) {
    +             throwIfUserLockedL(userId);
    + 
    +-            final ShortcutPackage ps = getPackageShortcutsLocked(packageName, userId);
    +-            ps.getUser().onCalledByPublisher(packageName);
    ++            final ShortcutPackage ps = getPackageShortcutsForPublisherLocked(packageName, userId);
    + 
    +             ps.ensureImmutableShortcutsNotIncludedWithIds((List<String>) shortcutIds);
    + 
    +@@ -1828,8 +1878,7 @@ public class ShortcutService extends IShortcutService.Stub {
    +         synchronized (mLock) {
    +             throwIfUserLockedL(userId);
    + 
    +-            final ShortcutPackage ps = getPackageShortcutsLocked(packageName, userId);
    +-            ps.getUser().onCalledByPublisher(packageName);
    ++            final ShortcutPackage ps = getPackageShortcutsForPublisherLocked(packageName, userId);
    + 
    +             ps.ensureImmutableShortcutsNotIncludedWithIds((List<String>) shortcutIds);
    + 
    +@@ -1853,8 +1902,7 @@ public class ShortcutService extends IShortcutService.Stub {
    +         synchronized (mLock) {
    +             throwIfUserLockedL(userId);
    + 
    +-            final ShortcutPackage ps = getPackageShortcutsLocked(packageName, userId);
    +-            ps.getUser().onCalledByPublisher(packageName);
    ++            final ShortcutPackage ps = getPackageShortcutsForPublisherLocked(packageName, userId);
    +             ps.deleteAllDynamicShortcuts();
    +         }
    +         packageShortcutsChanged(packageName, userId);
    +@@ -1909,8 +1957,7 @@ public class ShortcutService extends IShortcutService.Stub {
    + 
    +         final ArrayList<ShortcutInfo> ret = new ArrayList<>();
    + 
    +-        final ShortcutPackage ps = getPackageShortcutsLocked(packageName, userId);
    +-        ps.getUser().onCalledByPublisher(packageName);
    ++        final ShortcutPackage ps = getPackageShortcutsForPublisherLocked(packageName, userId);
    +         ps.findAll(ret, query, cloneFlags);
    + 
    +         return new ParceledListSlice<>(ret);
    +@@ -1931,8 +1978,7 @@ public class ShortcutService extends IShortcutService.Stub {
    +         synchronized (mLock) {
    +             throwIfUserLockedL(userId);
    + 
    +-            final ShortcutPackage ps = getPackageShortcutsLocked(packageName, userId);
    +-            ps.getUser().onCalledByPublisher(packageName);
    ++            final ShortcutPackage ps = getPackageShortcutsForPublisherLocked(packageName, userId);
    +             return mMaxUpdatesPerInterval - ps.getApiCallCount();
    +         }
    +     }
    +@@ -1971,8 +2017,7 @@ public class ShortcutService extends IShortcutService.Stub {
    +         synchronized (mLock) {
    +             throwIfUserLockedL(userId);
    + 
    +-            final ShortcutPackage ps = getPackageShortcutsLocked(packageName, userId);
    +-            ps.getUser().onCalledByPublisher(packageName);
    ++            final ShortcutPackage ps = getPackageShortcutsForPublisherLocked(packageName, userId);
    + 
    +             if (ps.findShortcutById(shortcutId) == null) {
    +                 Log.w(TAG, String.format("reportShortcutUsed: package %s doesn't have shortcut %s",
    +@@ -2625,10 +2670,14 @@ public class ShortcutService extends IShortcutService.Stub {
    +             boolean forceRescan) {
    +         final ShortcutUser user = getUserShortcutsLocked(userId);
    + 
    ++        // Note after each OTA, we'll need to rescan all system apps, as their lastUpdateTime
    ++        // is not reliable.
    +         final long now = injectCurrentTimeMillis();
    ++        final boolean afterOta =
    ++                !injectBuildFingerprint().equals(user.getLastAppScanOsFingerprint());
    + 
    +         // Then for each installed app, publish manifest shortcuts when needed.
    +-        forUpdatedPackages(userId, lastScanTime, ai -> {
    ++        forUpdatedPackages(userId, lastScanTime, afterOta, ai -> {
    +             user.attemptToRestoreIfNeededAndSave(this, ai.packageName, userId);
    +             user.rescanPackageIfNeeded(ai.packageName, forceRescan);
    +         });
    +@@ -2636,6 +2685,7 @@ public class ShortcutService extends IShortcutService.Stub {
    +         // Write the time just before the scan, because there may be apps that have just
    +         // been updated, and we want to catch them in the next time.
    +         user.setLastAppScanTime(now);
    ++        user.setLastAppScanOsFingerprint(injectBuildFingerprint());
    +         scheduleSaveUser(userId);
    +     }
    + 
    +@@ -2874,7 +2924,7 @@ public class ShortcutService extends IShortcutService.Stub {
    +         return parceledList.getList();
    +     }
    + 
    +-    private void forUpdatedPackages(@UserIdInt int userId, long lastScanTime,
    ++    private void forUpdatedPackages(@UserIdInt int userId, long lastScanTime, boolean afterOta,
    +             Consumer<ApplicationInfo> callback) {
    +         if (DEBUG) {
    +             Slog.d(TAG, "forUpdatedPackages for user " + userId + ", lastScanTime=" + lastScanTime);
    +@@ -2886,7 +2936,8 @@ public class ShortcutService extends IShortcutService.Stub {
    +             // If the package has been updated since the last scan time, then scan it.
    +             // Also if it's a system app with no update, lastUpdateTime is not reliable, so
    +             // just scan it.
    +-            if (pi.lastUpdateTime >= lastScanTime || isPureSystemApp(pi.applicationInfo)) {
    ++            if (pi.lastUpdateTime >= lastScanTime
    ++                    || (afterOta && isPureSystemApp(pi.applicationInfo))) {
    +                 if (DEBUG) {
    +                     Slog.d(TAG, "Found updated package " + pi.packageName);
    +                 }
    +@@ -3103,9 +3154,19 @@ public class ShortcutService extends IShortcutService.Stub {
    +                 return null;
    +             }
    + 
    +-            user.forAllPackageItems(spi -> spi.refreshPackageInfoAndSave());
    ++            // Update the signatures for all packages.
    ++            user.forAllPackageItems(spi -> spi.refreshPackageSignatureAndSave());
    + 
    +-            // Then save.
    ++            // Set the version code for the launchers.
    ++            // We shouldn't do this for publisher packages, because we don't want to update the
    ++            // version code without rescanning the manifest.
    ++            user.forAllLaunchers(launcher -> launcher.ensureVersionInfo());
    ++
    ++            // Save to the filesystem.
    ++            scheduleSaveUser(userId);
    ++            saveDirtyInfo();
    ++
    ++            // Then create the backup payload.
    +             final ByteArrayOutputStream os = new ByteArrayOutputStream(32 * 1024);
    +             try {
    +                 saveUserInternalLocked(userId, os, /* forBackup */ true);
    +@@ -3129,15 +3190,16 @@ public class ShortcutService extends IShortcutService.Stub {
    +                 wtf("Can't restore: user " + userId + " is locked or not running");
    +                 return;
    +             }
    +-            final ShortcutUser user;
    ++            // Actually do restore.
    ++            final ShortcutUser restored;
    +             final ByteArrayInputStream is = new ByteArrayInputStream(payload);
    +             try {
    +-                user = loadUserInternal(userId, is, /* fromBackup */ true);
    +-            } catch (XmlPullParserException | IOException e) {
    ++                restored = loadUserInternal(userId, is, /* fromBackup */ true);
    ++            } catch (XmlPullParserException | IOException | InvalidFileFormatException e) {
    +                 Slog.w(TAG, "Restoration failed.", e);
    +                 return;
    +             }
    +-            mUsers.put(userId, user);
    ++            getUserShortcutsLocked(userId).mergeRestoredFile(restored);
    + 
    +             // Rescan all packages to re-publish manifest shortcuts and do other checks.
    +             rescanUpdatedPackagesLocked(userId,
    +@@ -3218,23 +3280,9 @@ public class ShortcutService extends IShortcutService.Stub {
    + 
    +             pw.println("  Stats:");
    +             synchronized (mStatLock) {
    +-                final String p = "    ";
    +-                dumpStatLS(pw, p, Stats.GET_DEFAULT_HOME, "getHomeActivities()");
    +-                dumpStatLS(pw, p, Stats.LAUNCHER_PERMISSION_CHECK, "Launcher permission check");
    +-
    +-                dumpStatLS(pw, p, Stats.GET_PACKAGE_INFO, "getPackageInfo()");
    +-                dumpStatLS(pw, p, Stats.GET_PACKAGE_INFO_WITH_SIG, "getPackageInfo(SIG)");
    +-                dumpStatLS(pw, p, Stats.GET_APPLICATION_INFO, "getApplicationInfo");
    +-                dumpStatLS(pw, p, Stats.CLEANUP_DANGLING_BITMAPS, "cleanupDanglingBitmaps");
    +-                dumpStatLS(pw, p, Stats.GET_ACTIVITY_WITH_METADATA, "getActivity+metadata");
    +-                dumpStatLS(pw, p, Stats.GET_INSTALLED_PACKAGES, "getInstalledPackages");
    +-                dumpStatLS(pw, p, Stats.CHECK_PACKAGE_CHANGES, "checkPackageChanges");
    +-                dumpStatLS(pw, p, Stats.GET_APPLICATION_RESOURCES, "getApplicationResources");
    +-                dumpStatLS(pw, p, Stats.RESOURCE_NAME_LOOKUP, "resourceNameLookup");
    +-                dumpStatLS(pw, p, Stats.GET_LAUNCHER_ACTIVITY, "getLauncherActivity");
    +-                dumpStatLS(pw, p, Stats.CHECK_LAUNCHER_ACTIVITY, "checkLauncherActivity");
    +-                dumpStatLS(pw, p, Stats.IS_ACTIVITY_ENABLED, "isActivityEnabled");
    +-                dumpStatLS(pw, p, Stats.PACKAGE_UPDATE_CHECK, "packageUpdateCheck");
    ++                for (int i = 0; i < Stats.COUNT; i++) {
    ++                    dumpStatLS(pw, "    ", i);
    ++                }
    +             }
    + 
    +             pw.println();
    +@@ -3277,12 +3325,12 @@ public class ShortcutService extends IShortcutService.Stub {
    +         return tobj.format("%Y-%m-%d %H:%M:%S");
    +     }
    + 
    +-    private void dumpStatLS(PrintWriter pw, String prefix, int statId, String label) {
    ++    private void dumpStatLS(PrintWriter pw, String prefix, int statId) {
    +         pw.print(prefix);
    +         final int count = mCountStats[statId];
    +         final long dur = mDurationStats[statId];
    +         pw.println(String.format("%s: count=%d, total=%dms, avg=%.1fms",
    +-                label, count, dur,
    ++                STAT_LABELS[statId], count, dur,
    +                 (count == 0 ? 0 : ((double) dur) / count)));
    +     }
    + 
    +@@ -3578,6 +3626,12 @@ public class ShortcutService extends IShortcutService.Stub {
    +         Binder.restoreCallingIdentity(token);
    +     }
    + 
    ++    // Injection point.
    ++    @VisibleForTesting
    ++    String injectBuildFingerprint() {
    ++        return Build.FINGERPRINT;
    ++    }
    ++
    +     final void wtf(String message) {
    +         wtf(message, /* exception= */ null);
    +     }
    +diff --git a/services/core/java/com/android/server/pm/ShortcutUser.java b/services/core/java/com/android/server/pm/ShortcutUser.java
    +index ce3ed9c..5d4bfa4 100644
    +--- a/services/core/java/com/android/server/pm/ShortcutUser.java
    ++++ b/services/core/java/com/android/server/pm/ShortcutUser.java
    +@@ -23,12 +23,14 @@ import android.content.pm.ShortcutManager;
    + import android.text.TextUtils;
    + import android.text.format.Formatter;
    + import android.util.ArrayMap;
    ++import android.util.Log;
    + import android.util.Slog;
    + import android.util.SparseArray;
    + 
    + import com.android.internal.annotations.GuardedBy;
    + import com.android.internal.annotations.VisibleForTesting;
    + import com.android.internal.util.Preconditions;
    ++import com.android.server.pm.ShortcutService.InvalidFileFormatException;
    + 
    + import libcore.util.Objects;
    + 
    +@@ -60,6 +62,7 @@ class ShortcutUser {
    + 
    +     // Suffix "2" was added to force rescan all packages after the next OTA.
    +     private static final String ATTR_LAST_APP_SCAN_TIME = "last-app-scan-time2";
    ++    private static final String ATTR_LAST_APP_SCAN_OS_FINGERPRINT = "last-app-scan-fp";
    +     private static final String KEY_USER_ID = "userId";
    +     private static final String KEY_LAUNCHERS = "launchers";
    +     private static final String KEY_PACKAGES = "packages";
    +@@ -125,6 +128,8 @@ class ShortcutUser {
    + 
    +     private long mLastAppScanTime;
    + 
    ++    private String mLastAppScanOsFingerprint;
    ++
    +     public ShortcutUser(ShortcutService service, int userId) {
    +         mService = service;
    +         mUserId = userId;
    +@@ -142,6 +147,14 @@ class ShortcutUser {
    +         mLastAppScanTime = lastAppScanTime;
    +     }
    + 
    ++    public String getLastAppScanOsFingerprint() {
    ++        return mLastAppScanOsFingerprint;
    ++    }
    ++
    ++    public void setLastAppScanOsFingerprint(String lastAppScanOsFingerprint) {
    ++        mLastAppScanOsFingerprint = lastAppScanOsFingerprint;
    ++    }
    ++
    +     // We don't expose this directly to non-test code because only ShortcutUser should add to/
    +     // remove from it.
    +     @VisibleForTesting
    +@@ -153,6 +166,11 @@ class ShortcutUser {
    +         return mPackages.containsKey(packageName);
    +     }
    + 
    ++    private void addPackage(@NonNull ShortcutPackage p) {
    ++        p.replaceUser(this);
    ++        mPackages.put(p.getPackageName(), p);
    ++    }
    ++
    +     public ShortcutPackage removePackage(@NonNull String packageName) {
    +         final ShortcutPackage removed = mPackages.remove(packageName);
    + 
    +@@ -168,7 +186,8 @@ class ShortcutUser {
    +         return mLaunchers;
    +     }
    + 
    +-    public void addLauncher(ShortcutLauncher launcher) {
    ++    private void addLauncher(ShortcutLauncher launcher) {
    ++        launcher.replaceUser(this);
    +         mLaunchers.put(PackageWithUser.of(launcher.getPackageUserId(),
    +                 launcher.getPackageName()), launcher);
    +     }
    +@@ -315,11 +334,16 @@ class ShortcutUser {
    +             throws IOException, XmlPullParserException {
    +         out.startTag(null, TAG_ROOT);
    + 
    +-        ShortcutService.writeAttr(out, ATTR_KNOWN_LOCALES, mKnownLocales);
    +-        ShortcutService.writeAttr(out, ATTR_LAST_APP_SCAN_TIME,
    +-                mLastAppScanTime);
    ++        if (!forBackup) {
    ++            // Don't have to back them up.
    ++            ShortcutService.writeAttr(out, ATTR_KNOWN_LOCALES, mKnownLocales);
    ++            ShortcutService.writeAttr(out, ATTR_LAST_APP_SCAN_TIME,
    ++                    mLastAppScanTime);
    ++            ShortcutService.writeAttr(out, ATTR_LAST_APP_SCAN_OS_FINGERPRINT,
    ++                    mLastAppScanOsFingerprint);
    + 
    +-        ShortcutService.writeTagValue(out, TAG_LAUNCHER, mLastKnownLauncher);
    ++            ShortcutService.writeTagValue(out, TAG_LAUNCHER, mLastKnownLauncher);
    ++        }
    + 
    +         // Can't use forEachPackageItem due to the checked exceptions.
    +         {
    +@@ -352,53 +376,59 @@ class ShortcutUser {
    +     }
    + 
    +     public static ShortcutUser loadFromXml(ShortcutService s, XmlPullParser parser, int userId,
    +-            boolean fromBackup) throws IOException, XmlPullParserException {
    ++            boolean fromBackup) throws IOException, XmlPullParserException, InvalidFileFormatException {
    +         final ShortcutUser ret = new ShortcutUser(s, userId);
    + 
    +-        ret.mKnownLocales = ShortcutService.parseStringAttribute(parser,
    +-                ATTR_KNOWN_LOCALES);
    +-
    +-        // If lastAppScanTime is in the future, that means the clock went backwards.
    +-        // Just scan all apps again.
    +-        final long lastAppScanTime = ShortcutService.parseLongAttribute(parser,
    +-                ATTR_LAST_APP_SCAN_TIME);
    +-        final long currentTime = s.injectCurrentTimeMillis();
    +-        ret.mLastAppScanTime = lastAppScanTime < currentTime ? lastAppScanTime : 0;
    +-
    +-        final int outerDepth = parser.getDepth();
    +-        int type;
    +-        while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
    +-                && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
    +-            if (type != XmlPullParser.START_TAG) {
    +-                continue;
    +-            }
    +-            final int depth = parser.getDepth();
    +-            final String tag = parser.getName();
    +-
    +-            if (depth == outerDepth + 1) {
    +-                switch (tag) {
    +-                    case TAG_LAUNCHER: {
    +-                        ret.mLastKnownLauncher = ShortcutService.parseComponentNameAttribute(
    +-                                parser, ATTR_VALUE);
    +-                        continue;
    +-                    }
    +-                    case ShortcutPackage.TAG_ROOT: {
    +-                        final ShortcutPackage shortcuts = ShortcutPackage.loadFromXml(
    +-                                s, ret, parser, fromBackup);
    +-
    +-                        // Don't use addShortcut(), we don't need to save the icon.
    +-                        ret.mPackages.put(shortcuts.getPackageName(), shortcuts);
    +-                        continue;
    +-                    }
    +-
    +-                    case ShortcutLauncher.TAG_ROOT: {
    +-                        ret.addLauncher(
    +-                                ShortcutLauncher.loadFromXml(parser, ret, userId, fromBackup));
    +-                        continue;
    ++        try {
    ++            ret.mKnownLocales = ShortcutService.parseStringAttribute(parser,
    ++                    ATTR_KNOWN_LOCALES);
    ++
    ++            // If lastAppScanTime is in the future, that means the clock went backwards.
    ++            // Just scan all apps again.
    ++            final long lastAppScanTime = ShortcutService.parseLongAttribute(parser,
    ++                    ATTR_LAST_APP_SCAN_TIME);
    ++            final long currentTime = s.injectCurrentTimeMillis();
    ++            ret.mLastAppScanTime = lastAppScanTime < currentTime ? lastAppScanTime : 0;
    ++            ret.mLastAppScanOsFingerprint = ShortcutService.parseStringAttribute(parser,
    ++                    ATTR_LAST_APP_SCAN_OS_FINGERPRINT);
    ++            final int outerDepth = parser.getDepth();
    ++            int type;
    ++            while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
    ++                    && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
    ++                if (type != XmlPullParser.START_TAG) {
    ++                    continue;
    ++                }
    ++                final int depth = parser.getDepth();
    ++                final String tag = parser.getName();
    ++
    ++                if (depth == outerDepth + 1) {
    ++                    switch (tag) {
    ++                        case TAG_LAUNCHER: {
    ++                            ret.mLastKnownLauncher = ShortcutService.parseComponentNameAttribute(
    ++                                    parser, ATTR_VALUE);
    ++                            continue;
    ++                        }
    ++                        case ShortcutPackage.TAG_ROOT: {
    ++                            final ShortcutPackage shortcuts = ShortcutPackage.loadFromXml(
    ++                                    s, ret, parser, fromBackup);
    ++
    ++                            // Don't use addShortcut(), we don't need to save the icon.
    ++                            ret.mPackages.put(shortcuts.getPackageName(), shortcuts);
    ++                            continue;
    ++                        }
    ++
    ++                        case ShortcutLauncher.TAG_ROOT: {
    ++                            ret.addLauncher(
    ++                                    ShortcutLauncher.loadFromXml(parser, ret, userId, fromBackup));
    ++                            continue;
    ++                        }
    +                     }
    +                 }
    ++                ShortcutService.warnForInvalidTag(depth, tag);
    +             }
    +-            ShortcutService.warnForInvalidTag(depth, tag);
    ++        } catch (RuntimeException e) {
    ++            throw new ShortcutService.InvalidFileFormatException(
    ++                    "Unable to parse file", e);
    +         }
    +         return ret;
    +     }
    +@@ -447,6 +477,51 @@ class ShortcutUser {
    +         }
    +     }
    + 
    ++    public void mergeRestoredFile(ShortcutUser restored) {
    ++        final ShortcutService s = mService;
    ++        // Note, a restore happens only at the end of setup wizard.  At this point, no apps are
    ++        // installed from Play Store yet, but it's still possible that system apps have already
    ++        // published dynamic shortcuts, since some apps do so on BOOT_COMPLETED.
    ++        // When such a system app has allowbackup=true, then we go ahead and replace all existing
    ++        // shortcuts with the restored shortcuts.  (Then we'll re-publish manifest shortcuts later
    ++        // in the call site.)
    ++        // When such a system app has allowbackup=false, then we'll keep the shortcuts that have
    ++        // already been published.  So we selectively add restored ShortcutPackages here.
    ++        //
    ++        // The same logic applies to launchers, but since launchers shouldn't pin shortcuts
    ++        // without users interaction it's really not a big deal, so we just clear existing
    ++        // ShortcutLauncher instances in mLaunchers and add all the restored ones here.
    ++
    ++        mLaunchers.clear();
    ++        restored.forAllLaunchers(sl -> {
    ++            // If the app is already installed and allowbackup = false, then ignore the restored
    ++            // data.
    ++            if (s.isPackageInstalled(sl.getPackageName(), getUserId())
    ++                    && !s.shouldBackupApp(sl.getPackageName(), getUserId())) {
    ++                return;
    ++            }
    ++            addLauncher(sl);
    ++        });
    ++        restored.forAllPackages(sp -> {
    ++            // If the app is already installed and allowbackup = false, then ignore the restored
    ++            // data.
    ++            if (s.isPackageInstalled(sp.getPackageName(), getUserId())
    ++                    && !s.shouldBackupApp(sp.getPackageName(), getUserId())) {
    ++                return;
    ++            }
    ++
    ++            final ShortcutPackage previous = getPackageShortcutsIfExists(sp.getPackageName());
    ++            if (previous != null && previous.hasNonManifestShortcuts()) {
    ++                Log.w(TAG, "Shortcuts for package " + sp.getPackageName() + " are being restored."
    ++                        + " Existing non-manifeset shortcuts will be overwritten.");
    ++            }
    ++            addPackage(sp);
    ++        });
    ++        // Empty the launchers and packages in restored to avoid accidentally using them.
    ++        restored.mLaunchers.clear();
    ++        restored.mPackages.clear();
    ++    }
    ++
    +     public void dump(@NonNull PrintWriter pw, @NonNull String prefix) {
    +         pw.print(prefix);
    +         pw.print("User: ");
    +@@ -457,6 +532,8 @@ class ShortcutUser {
    +         pw.print(mLastAppScanTime);
    +         pw.print("] ");
    +         pw.print(ShortcutService.formatTime(mLastAppScanTime));
    ++        pw.print("  Last app scan FP: ");
    ++        pw.print(mLastAppScanOsFingerprint);
    +         pw.println();
    + 
    +         prefix += prefix + "  ";
    +diff --git a/services/core/java/com/android/server/pm/UserManagerService.java b/services/core/java/com/android/server/pm/UserManagerService.java
    +index c9ad49a..af055da 100644
    +--- a/services/core/java/com/android/server/pm/UserManagerService.java
    ++++ b/services/core/java/com/android/server/pm/UserManagerService.java
    +@@ -180,7 +180,8 @@ public class UserManagerService extends IUserManager.Stub {
    +             UserInfo.FLAG_MANAGED_PROFILE
    +             | UserInfo.FLAG_EPHEMERAL
    +             | UserInfo.FLAG_RESTRICTED
    +-            | UserInfo.FLAG_GUEST;
    ++            | UserInfo.FLAG_GUEST
    ++            | UserInfo.FLAG_DEMO;
    + 
    +     private static final int MIN_USER_ID = 10;
    +     // We need to keep process uid within Integer.MAX_VALUE.
    +diff --git a/services/core/java/com/android/server/policy/GlobalActions.java b/services/core/java/com/android/server/policy/GlobalActions.java
    +index bb91f76..a8bd4d2 100644
    +--- a/services/core/java/com/android/server/policy/GlobalActions.java
    ++++ b/services/core/java/com/android/server/policy/GlobalActions.java
    +@@ -20,6 +20,7 @@ import com.android.internal.app.AlertController;
    + import com.android.internal.app.AlertController.AlertParams;
    + import com.android.internal.logging.MetricsLogger;
    + import com.android.internal.logging.MetricsProto.MetricsEvent;
    ++import com.android.internal.policy.EmergencyAffordanceManager;
    + import com.android.internal.telephony.TelephonyIntents;
    + import com.android.internal.telephony.TelephonyProperties;
    + import com.android.internal.R;
    +@@ -27,7 +28,6 @@ import com.android.internal.widget.LockPatternUtils;
    + 
    + import android.app.ActivityManager;
    + import android.app.ActivityManagerNative;
    +-import android.app.AlertDialog;
    + import android.app.Dialog;
    + import android.content.BroadcastReceiver;
    + import android.content.Context;
    +@@ -125,6 +125,7 @@ class GlobalActions implements DialogInterface.OnDismissListener, DialogInterfac
    +     private boolean mHasTelephony;
    +     private boolean mHasVibrator;
    +     private final boolean mShowSilentToggle;
    ++    private final EmergencyAffordanceManager mEmergencyAffordanceManager;
    + 
    +     /**
    +      * @param context everything needs a context :(
    +@@ -159,6 +160,8 @@ class GlobalActions implements DialogInterface.OnDismissListener, DialogInterfac
    + 
    +         mShowSilentToggle = SHOW_SILENT_TOGGLE && !mContext.getResources().getBoolean(
    +                 com.android.internal.R.bool.config_useFixedVolume);
    ++
    ++        mEmergencyAffordanceManager = new EmergencyAffordanceManager(context);
    +     }
    + 
    +     /**
    +@@ -308,6 +311,10 @@ class GlobalActions implements DialogInterface.OnDismissListener, DialogInterfac
    +             addedKeys.add(actionKey);
    +         }
    + 
    ++        if (mEmergencyAffordanceManager.needsEmergencyAffordance()) {
    ++            mItems.add(getEmergencyAction());
    ++        }
    ++
    +         mAdapter = new MyAdapter();
    + 
    +         AlertParams params = new AlertParams(mContext);
    +@@ -493,6 +500,26 @@ class GlobalActions implements DialogInterface.OnDismissListener, DialogInterfac
    +         };
    +     }
    + 
    ++    private Action getEmergencyAction() {
    ++        return new SinglePressAction(com.android.internal.R.drawable.emergency_icon,
    ++                R.string.global_action_emergency) {
    ++            @Override
    ++            public void onPress() {
    ++                mEmergencyAffordanceManager.performEmergencyCall();
    ++            }
    ++
    ++            @Override
    ++            public boolean showDuringKeyguard() {
    ++                return true;
    ++            }
    ++
    ++            @Override
    ++            public boolean showBeforeProvisioning() {
    ++                return true;
    ++            }
    ++        };
    ++    }
    ++
    +     private Action getAssistAction() {
    +         return new SinglePressAction(com.android.internal.R.drawable.ic_action_assist_focused,
    +                 R.string.global_action_assist) {
    +diff --git a/services/core/java/com/android/server/policy/ImmersiveModeConfirmation.java b/services/core/java/com/android/server/policy/ImmersiveModeConfirmation.java
    +index c764833..9bf0476 100644
    +--- a/services/core/java/com/android/server/policy/ImmersiveModeConfirmation.java
    ++++ b/services/core/java/com/android/server/policy/ImmersiveModeConfirmation.java
    +@@ -25,7 +25,9 @@ import android.content.Intent;
    + import android.content.IntentFilter;
    + import android.graphics.PixelFormat;
    + import android.graphics.drawable.ColorDrawable;
    ++import android.os.Binder;
    + import android.os.Handler;
    ++import android.os.IBinder;
    + import android.os.Message;
    + import android.os.RemoteException;
    + import android.os.ServiceManager;
    +@@ -36,7 +38,6 @@ import android.service.vr.IVrManager;
    + import android.service.vr.IVrStateCallbacks;
    + import android.util.DisplayMetrics;
    + import android.util.Slog;
    +-import android.util.SparseBooleanArray;
    + import android.view.Gravity;
    + import android.view.MotionEvent;
    + import android.view.View;
    +@@ -66,6 +67,7 @@ public class ImmersiveModeConfirmation {
    +     private final H mHandler;
    +     private final long mShowDelayMs;
    +     private final long mPanicThresholdMs;
    ++    private final IBinder mWindowToken = new Binder();
    + 
    +     private boolean mConfirmed;
    +     private ClingWindowView mClingWindow;
    +@@ -190,13 +192,13 @@ public class ImmersiveModeConfirmation {
    +                 WindowManager.LayoutParams.TYPE_STATUS_BAR_PANEL,
    +                 0
    +                         | WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN
    +-                        | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
    +                         | WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED
    +                 ,
    +                 PixelFormat.TRANSLUCENT);
    +         lp.privateFlags |= WindowManager.LayoutParams.PRIVATE_FLAG_SHOW_FOR_ALL_USERS;
    +         lp.setTitle("ImmersiveModeConfirmation");
    +         lp.windowAnimations = com.android.internal.R.style.Animation_ImmersiveModeConfirmation;
    ++        lp.token = getWindowToken();
    +         return lp;
    +     }
    + 
    +@@ -208,6 +210,13 @@ public class ImmersiveModeConfirmation {
    +                 Gravity.CENTER_HORIZONTAL | Gravity.TOP);
    +     }
    + 
    ++    /**
    ++     * @return the window token that's used by all ImmersiveModeConfirmation windows.
    ++     */
    ++    public IBinder getWindowToken() {
    ++        return mWindowToken;
    ++    }
    ++
    +     private class ClingWindowView extends FrameLayout {
    +         private static final int BGCOLOR = 0x80000000;
    +         private static final int OFFSET_DP = 96;
    +diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java
    +index a39add8..74e720f 100644
    +--- a/services/core/java/com/android/server/policy/PhoneWindowManager.java
    ++++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java
    +@@ -140,6 +140,7 @@ import android.view.animation.Animation;
    + import android.view.animation.AnimationSet;
    + import android.view.animation.AnimationUtils;
    + import com.android.internal.R;
    ++import com.android.internal.annotations.GuardedBy;
    + import com.android.internal.logging.MetricsLogger;
    + import com.android.internal.policy.PhoneWindow;
    + import com.android.internal.policy.IShortcutService;
    +@@ -176,12 +177,13 @@ public class PhoneWindowManager implements WindowManagerPolicy {
    +     static final boolean DEBUG_STARTING_WINDOW = false;
    +     static final boolean DEBUG_WAKEUP = false;
    +     static final boolean SHOW_STARTING_ANIMATIONS = true;
    +-    static final boolean SHOW_PROCESSES_ON_ALT_MENU = false;
    + 
    +     // Whether to allow dock apps with METADATA_DOCK_HOME to temporarily take over the Home key.
    +     // No longer recommended for desk docks;
    +     static final boolean ENABLE_DESK_DOCK_HOME_CAPTURE = false;
    + 
    ++    static final boolean ALTERNATE_CAR_MODE_NAV_SIZE = false;
    ++
    +     static final int SHORT_PRESS_POWER_NOTHING = 0;
    +     static final int SHORT_PRESS_POWER_GO_TO_SLEEP = 1;
    +     static final int SHORT_PRESS_POWER_REALLY_GO_TO_SLEEP = 2;
    +@@ -301,6 +303,9 @@ public class PhoneWindowManager implements WindowManagerPolicy {
    +     /** Amount of time (in milliseconds) to wait for windows drawn before powering on. */
    +     static final int WAITING_FOR_DRAWN_TIMEOUT = 1000;
    + 
    ++    /** Amount of time (in milliseconds) a toast window can be shown. */
    ++    public static final int TOAST_WINDOW_TIMEOUT = 3500; // 3.5 seconds
    ++
    +     /**
    +      * Lock protecting internal state.  Must not call out into window
    +      * manager with lock held.  (This lock will be acquired in places
    +@@ -585,6 +590,13 @@ public class PhoneWindowManager implements WindowManagerPolicy {
    +     private static final int DISMISS_KEYGUARD_CONTINUE = 2; // Keyguard has been dismissed.
    +     int mDismissKeyguard = DISMISS_KEYGUARD_NONE;
    + 
    ++    /**
    ++     * Indicates that we asked the Keyguard to be dismissed and we just wait for the Keyguard to
    ++     * dismiss itself.
    ++     */
    ++    @GuardedBy("Lw")
    ++    private boolean mCurrentlyDismissingKeyguard;
    ++
    +     /** The window that is currently dismissing the keyguard. Dismissing the keyguard must only
    +      * be done once per window. */
    +     private WindowState mWinDismissingKeyguard;
    +@@ -2229,9 +2241,22 @@ public class PhoneWindowManager implements WindowManagerPolicy {
    +                     attrs.privateFlags &= ~WindowManager.LayoutParams.PRIVATE_FLAG_KEYGUARD;
    +                 }
    +                 break;
    ++
    +             case TYPE_SCREENSHOT:
    +                 attrs.flags |= WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
    +                 break;
    ++
    ++            case TYPE_TOAST:
    ++                // While apps should use the dedicated toast APIs to add such windows
    ++                // it possible legacy apps to add the window directly. Therefore, we
    ++                // make windows added directly by the app behave as a toast as much
    ++                // as possible in terms of timeout and animation.
    ++                if (attrs.hideTimeoutMilliseconds < 0
    ++                        || attrs.hideTimeoutMilliseconds > TOAST_WINDOW_TIMEOUT) {
    ++                    attrs.hideTimeoutMilliseconds = TOAST_WINDOW_TIMEOUT;
    ++                }
    ++                attrs.windowAnimations = com.android.internal.R.style.Animation_Toast;
    ++                break;
    +         }
    + 
    +         if (attrs.type != TYPE_STATUS_BAR) {
    +@@ -2320,22 +2345,24 @@ public class PhoneWindowManager implements WindowManagerPolicy {
    +         mNavigationBarWidthForRotationDefault[mSeascapeRotation] =
    +                 res.getDimensionPixelSize(com.android.internal.R.dimen.navigation_bar_width);
    + 
    +-        // Height of the navigation bar when presented horizontally at bottom
    +-        mNavigationBarHeightForRotationInCarMode[mPortraitRotation] =
    +-        mNavigationBarHeightForRotationInCarMode[mUpsideDownRotation] =
    +-                res.getDimensionPixelSize(
    +-                        com.android.internal.R.dimen.navigation_bar_height_car_mode);
    +-        mNavigationBarHeightForRotationInCarMode[mLandscapeRotation] =
    +-        mNavigationBarHeightForRotationInCarMode[mSeascapeRotation] = res.getDimensionPixelSize(
    +-                com.android.internal.R.dimen.navigation_bar_height_landscape_car_mode);
    ++        if (ALTERNATE_CAR_MODE_NAV_SIZE) {
    ++            // Height of the navigation bar when presented horizontally at bottom
    ++            mNavigationBarHeightForRotationInCarMode[mPortraitRotation] =
    ++            mNavigationBarHeightForRotationInCarMode[mUpsideDownRotation] =
    ++                    res.getDimensionPixelSize(
    ++                            com.android.internal.R.dimen.navigation_bar_height_car_mode);
    ++            mNavigationBarHeightForRotationInCarMode[mLandscapeRotation] =
    ++            mNavigationBarHeightForRotationInCarMode[mSeascapeRotation] = res.getDimensionPixelSize(
    ++                    com.android.internal.R.dimen.navigation_bar_height_landscape_car_mode);
    + 
    +-        // Width of the navigation bar when presented vertically along one side
    +-        mNavigationBarWidthForRotationInCarMode[mPortraitRotation] =
    +-        mNavigationBarWidthForRotationInCarMode[mUpsideDownRotation] =
    +-        mNavigationBarWidthForRotationInCarMode[mLandscapeRotation] =
    +-        mNavigationBarWidthForRotationInCarMode[mSeascapeRotation] =
    +-                res.getDimensionPixelSize(
    +-                        com.android.internal.R.dimen.navigation_bar_width_car_mode);
    ++            // Width of the navigation bar when presented vertically along one side
    ++            mNavigationBarWidthForRotationInCarMode[mPortraitRotation] =
    ++            mNavigationBarWidthForRotationInCarMode[mUpsideDownRotation] =
    ++            mNavigationBarWidthForRotationInCarMode[mLandscapeRotation] =
    ++            mNavigationBarWidthForRotationInCarMode[mSeascapeRotation] =
    ++                    res.getDimensionPixelSize(
    ++                            com.android.internal.R.dimen.navigation_bar_width_car_mode);
    ++        }
    +     }
    + 
    +     /** {@inheritDoc} */
    +@@ -2467,7 +2494,7 @@ public class PhoneWindowManager implements WindowManagerPolicy {
    +     }
    + 
    +     private int getNavigationBarWidth(int rotation, int uiMode) {
    +-        if ((uiMode & UI_MODE_TYPE_MASK) == UI_MODE_TYPE_CAR) {
    ++        if (ALTERNATE_CAR_MODE_NAV_SIZE && (uiMode & UI_MODE_TYPE_MASK) == UI_MODE_TYPE_CAR) {
    +             return mNavigationBarWidthForRotationInCarMode[rotation];
    +         } else {
    +             return mNavigationBarWidthForRotationDefault[rotation];
    +@@ -2488,7 +2515,7 @@ public class PhoneWindowManager implements WindowManagerPolicy {
    +     }
    + 
    +     private int getNavigationBarHeight(int rotation, int uiMode) {
    +-        if ((uiMode & UI_MODE_TYPE_MASK) == UI_MODE_TYPE_CAR) {
    ++        if (ALTERNATE_CAR_MODE_NAV_SIZE && (uiMode & UI_MODE_TYPE_MASK) == UI_MODE_TYPE_CAR) {
    +             return mNavigationBarHeightForRotationInCarMode[rotation];
    +         } else {
    +             return mNavigationBarHeightForRotationDefault[rotation];
    +@@ -2805,7 +2832,11 @@ public class PhoneWindowManager implements WindowManagerPolicy {
    +             if (mNavigationBarPosition == NAV_BAR_BOTTOM) {
    +                 if (transit == TRANSIT_EXIT
    +                         || transit == TRANSIT_HIDE) {
    +-                    return R.anim.dock_bottom_exit;
    ++                    if (isKeyguardShowingAndNotOccluded()) {
    ++                        return R.anim.dock_bottom_exit_keyguard;
    ++                    } else {
    ++                        return R.anim.dock_bottom_exit;
    ++                    }
    +                 } else if (transit == TRANSIT_ENTER
    +                         || transit == TRANSIT_SHOW) {
    +                     return R.anim.dock_bottom_enter;
    +@@ -3125,21 +3156,6 @@ public class PhoneWindowManager implements WindowManagerPolicy {
    +                     mContext.sendOrderedBroadcastAsUser(intent, UserHandle.CURRENT,
    +                             null, null, null, 0, null, null);
    +                     return -1;
    +-                } else if (SHOW_PROCESSES_ON_ALT_MENU &&
    +-                        (metaState & KeyEvent.META_ALT_ON) == KeyEvent.META_ALT_ON) {
    +-                    Intent service = new Intent();
    +-                    service.setClassName(mContext, "com.android.server.LoadAverageService");
    +-                    ContentResolver res = mContext.getContentResolver();
    +-                    boolean shown = Settings.Global.getInt(
    +-                            res, Settings.Global.SHOW_PROCESSES, 0) != 0;
    +-                    if (!shown) {
    +-                        mContext.startService(service);
    +-                    } else {
    +-                        mContext.stopService(service);
    +-                    }
    +-                    Settings.Global.putInt(
    +-                            res, Settings.Global.SHOW_PROCESSES, shown ? 0 : 1);
    +-                    return -1;
    +                 }
    +             }
    +         } else if (keyCode == KeyEvent.KEYCODE_SEARCH) {
    +@@ -3566,10 +3582,11 @@ public class PhoneWindowManager implements WindowManagerPolicy {
    + 
    +     @Override
    +     public boolean canShowDismissingWindowWhileLockedLw() {
    +-        // If the keyguard is trusted, it will unlock without a challange. Therefore, windows with
    +-        // FLAG_DISMISS_KEYGUARD don't need to be force hidden, as they will unlock the phone right
    +-        // away anyways.
    +-        return mKeyguardDelegate != null && mKeyguardDelegate.isTrusted();
    ++        // If the keyguard is trusted, it will unlock without a challenge. Therefore, if we are in
    ++        // the process of dismissing Keyguard, we don't need to hide them as the phone will be
    ++        // unlocked right away in any case.
    ++        return mKeyguardDelegate != null && mKeyguardDelegate.isTrusted()
    ++                && mCurrentlyDismissingKeyguard;
    +     }
    + 
    +     private void launchAssistLongPressAction() {
    +@@ -3832,11 +3849,19 @@ public class PhoneWindowManager implements WindowManagerPolicy {
    +     };
    + 
    +     @Override
    ++    public void setRecentsVisibilityLw(boolean visible) {
    ++        mRecentsVisible = visible;
    ++    }
    ++
    ++    @Override
    ++    public void setTvPipVisibilityLw(boolean visible) {
    ++        mTvPictureInPictureVisible = visible;
    ++    }
    ++
    ++    @Override
    +     public int adjustSystemUiVisibilityLw(int visibility) {
    +         mStatusBarController.adjustSystemUiVisibilityLw(mLastSystemUiFlags, visibility);
    +         mNavigationBarController.adjustSystemUiVisibilityLw(mLastSystemUiFlags, visibility);
    +-        mRecentsVisible = (visibility & View.RECENT_APPS_VISIBLE) > 0;
    +-        mTvPictureInPictureVisible = (visibility & View.TV_PICTURE_IN_PICTURE_VISIBLE) > 0;
    + 
    +         // Reset any bits in mForceClearingStatusBarVisibility that
    +         // are now clear.
    +@@ -5268,22 +5293,30 @@ public class PhoneWindowManager implements WindowManagerPolicy {
    +                 }
    +             } else if (mDismissKeyguard != DISMISS_KEYGUARD_NONE) {
    +                 mKeyguardHidden = false;
    ++                boolean dismissKeyguard = false;
    +                 final boolean trusted = mKeyguardDelegate.isTrusted();
    +-                if (trusted) {
    +-                    // No need to un-occlude keyguard - we'll dimiss it right away anyways.
    +-                } else if (setKeyguardOccludedLw(false)) {
    +-                    changes |= FINISH_LAYOUT_REDO_LAYOUT
    +-                            | FINISH_LAYOUT_REDO_CONFIG
    +-                            | FINISH_LAYOUT_REDO_WALLPAPER;
    +-                }
    +                 if (mDismissKeyguard == DISMISS_KEYGUARD_START) {
    ++                    final boolean willDismiss = trusted && mKeyguardOccluded
    ++                            && mKeyguardDelegate != null && mKeyguardDelegate.isShowing();
    ++                    if (willDismiss) {
    ++                        mCurrentlyDismissingKeyguard = true;
    ++                    }
    ++                    dismissKeyguard = true;
    ++                }
    ++
    ++                // If we are currently dismissing Keyguard, there is no need to unocclude it.
    ++                if (!mCurrentlyDismissingKeyguard) {
    ++                    if (setKeyguardOccludedLw(false)) {
    ++                        changes |= FINISH_LAYOUT_REDO_LAYOUT
    ++                                | FINISH_LAYOUT_REDO_CONFIG
    ++                                | FINISH_LAYOUT_REDO_WALLPAPER;
    ++                    }
    ++                }
    ++
    ++                if (dismissKeyguard) {
    +                     // Only launch the next keyguard unlock window once per window.
    +-                    mHandler.post(new Runnable() {
    +-                        @Override
    +-                        public void run() {
    +-                            mKeyguardDelegate.dismiss(trusted /* allowWhileOccluded */);
    +-                        }
    +-                    });
    ++                    mHandler.post(() -> mKeyguardDelegate.dismiss(
    ++                            trusted /* allowWhileOccluded */));
    +                 }
    +             } else {
    +                 mWinDismissingKeyguard = null;
    +@@ -5318,15 +5351,18 @@ public class PhoneWindowManager implements WindowManagerPolicy {
    +         boolean showing = mKeyguardDelegate.isShowing();
    +         if (wasOccluded && !isOccluded && showing) {
    +             mKeyguardOccluded = false;
    +-            mKeyguardDelegate.setOccluded(false);
    ++            mKeyguardDelegate.setOccluded(false, true /* animate */);
    +             mStatusBar.getAttrs().privateFlags |= PRIVATE_FLAG_KEYGUARD;
    +             if (!mKeyguardDelegate.hasLockscreenWallpaper()) {
    +                 mStatusBar.getAttrs().flags |= FLAG_SHOW_WALLPAPER;
    +             }
    ++            Animation anim = AnimationUtils.loadAnimation(mContext,
    ++                    com.android.internal.R.anim.wallpaper_open_exit);
    ++            mWindowManagerFuncs.overridePlayingAppAnimationsLw(anim);
    +             return true;
    +         } else if (!wasOccluded && isOccluded && showing) {
    +             mKeyguardOccluded = true;
    +-            mKeyguardDelegate.setOccluded(true);
    ++            mKeyguardDelegate.setOccluded(true, false /* animate */);
    +             mStatusBar.getAttrs().privateFlags &= ~PRIVATE_FLAG_KEYGUARD;
    +             mStatusBar.getAttrs().flags &= ~FLAG_SHOW_WALLPAPER;
    +             return true;
    +@@ -5335,6 +5371,14 @@ public class PhoneWindowManager implements WindowManagerPolicy {
    +         }
    +     }
    + 
    ++    private void onKeyguardShowingStateChanged(boolean showing) {
    ++        if (!showing) {
    ++            synchronized (mWindowManagerFuncs.getWindowManagerLock()) {
    ++                mCurrentlyDismissingKeyguard = false;
    ++            }
    ++        }
    ++    }
    ++
    +     private boolean isStatusBarKeyguard() {
    +         return mStatusBar != null
    +                 && (mStatusBar.getAttrs().privateFlags & PRIVATE_FLAG_KEYGUARD) != 0;
    +@@ -5511,7 +5555,14 @@ public class PhoneWindowManager implements WindowManagerPolicy {
    + 
    +                 @Override
    +                 public void onServiceDisconnected(ComponentName name) {
    +-                    notifyScreenshotError();
    ++                    synchronized (mScreenshotLock) {
    ++                        if (mScreenshotConnection != null) {
    ++                            mContext.unbindService(mScreenshotConnection);
    ++                            mScreenshotConnection = null;
    ++                            mHandler.removeCallbacks(mScreenshotTimeout);
    ++                            notifyScreenshotError();
    ++                        }
    ++                    }
    +                 }
    +             };
    +             if (mContext.bindServiceAsUser(serviceIntent, conn,
    +@@ -6866,7 +6917,8 @@ public class PhoneWindowManager implements WindowManagerPolicy {
    +     /** {@inheritDoc} */
    +     @Override
    +     public void systemReady() {
    +-        mKeyguardDelegate = new KeyguardServiceDelegate(mContext);
    ++        mKeyguardDelegate = new KeyguardServiceDelegate(mContext,
    ++                this::onKeyguardShowingStateChanged);
    +         mKeyguardDelegate.onSystemReady();
    + 
    +         readCameraLensCoverState();
    +@@ -7399,11 +7451,20 @@ public class PhoneWindowManager implements WindowManagerPolicy {
    +     private int updateSystemUiVisibilityLw() {
    +         // If there is no window focused, there will be nobody to handle the events
    +         // anyway, so just hang on in whatever state we're in until things settle down.
    +-        final WindowState win = mFocusedWindow != null ? mFocusedWindow
    ++        WindowState winCandidate = mFocusedWindow != null ? mFocusedWindow
    +                 : mTopFullscreenOpaqueWindowState;
    +-        if (win == null) {
    ++        if (winCandidate == null) {
    +             return 0;
    +         }
    ++        if (winCandidate.getAttrs().token == mImmersiveModeConfirmation.getWindowToken()) {
    ++            // The immersive mode confirmation should never affect the system bar visibility,
    ++            // otherwise it will unhide the navigation bar and hide itself.
    ++            winCandidate = isStatusBarKeyguard() ? mStatusBar : mTopFullscreenOpaqueWindowState;
    ++            if (winCandidate == null) {
    ++                return 0;
    ++            }
    ++        }
    ++        final WindowState win = winCandidate;
    +         if ((win.getAttrs().privateFlags & PRIVATE_FLAG_KEYGUARD) != 0 && mHideLockScreen == true) {
    +             // We are updating at a point where the keyguard has gotten
    +             // focus, but we were last in a state where the top window is
    +@@ -7748,7 +7809,7 @@ public class PhoneWindowManager implements WindowManagerPolicy {
    +         int delta = newRotation - oldRotation;
    +         if (delta < 0) delta += 4;
    +         // Likewise we don't rotate seamlessly for 180 degree rotations
    +-        // in this case the surfaces never resize, and our logic to 
    ++        // in this case the surfaces never resize, and our logic to
    +         // revert the transformations on size change will fail. We could
    +         // fix this in the future with the "tagged" frames idea.
    +         if (delta == Surface.ROTATION_180) {
    +@@ -7938,6 +7999,7 @@ public class PhoneWindowManager implements WindowManagerPolicy {
    +                 pw.print(" mForceStatusBarFromKeyguard=");
    +                 pw.println(mForceStatusBarFromKeyguard);
    +         pw.print(prefix); pw.print("mDismissKeyguard="); pw.print(mDismissKeyguard);
    ++                pw.print(" mCurrentlyDismissingKeyguard="); pw.println(mCurrentlyDismissingKeyguard);
    +                 pw.print(" mWinDismissingKeyguard="); pw.print(mWinDismissingKeyguard);
    +                 pw.print(" mHomePressed="); pw.println(mHomePressed);
    +         pw.print(prefix); pw.print("mAllowLockscreenWhenOn="); pw.print(mAllowLockscreenWhenOn);
    +diff --git a/services/core/java/com/android/server/policy/keyguard/KeyguardServiceDelegate.java b/services/core/java/com/android/server/policy/keyguard/KeyguardServiceDelegate.java
    +index 4fce49e..29a1f07 100644
    +--- a/services/core/java/com/android/server/policy/keyguard/KeyguardServiceDelegate.java
    ++++ b/services/core/java/com/android/server/policy/keyguard/KeyguardServiceDelegate.java
    +@@ -23,6 +23,7 @@ import com.android.internal.policy.IKeyguardDrawnCallback;
    + import com.android.internal.policy.IKeyguardExitCallback;
    + import com.android.internal.policy.IKeyguardService;
    + import com.android.server.UiThread;
    ++import com.android.server.policy.keyguard.KeyguardStateMonitor.OnShowingStateChangedCallback;
    + 
    + import java.io.PrintWriter;
    + 
    +@@ -49,6 +50,7 @@ public class KeyguardServiceDelegate {
    +     private final Handler mScrimHandler;
    +     private final KeyguardState mKeyguardState = new KeyguardState();
    +     private DrawnListener mDrawnListenerWhenConnect;
    ++    private final OnShowingStateChangedCallback mShowingStateChangedCallback;
    + 
    +     private static final class KeyguardState {
    +         KeyguardState() {
    +@@ -116,9 +118,11 @@ public class KeyguardServiceDelegate {
    +         }
    +     };
    + 
    +-    public KeyguardServiceDelegate(Context context) {
    ++    public KeyguardServiceDelegate(Context context,
    ++            OnShowingStateChangedCallback showingStateChangedCallback) {
    +         mContext = context;
    +         mScrimHandler = UiThread.getHandler();
    ++        mShowingStateChangedCallback = showingStateChangedCallback;
    +         mScrim = createScrim(context, mScrimHandler);
    +     }
    + 
    +@@ -154,7 +158,7 @@ public class KeyguardServiceDelegate {
    +         public void onServiceConnected(ComponentName name, IBinder service) {
    +             if (DEBUG) Log.v(TAG, "*** Keyguard connected (yay!)");
    +             mKeyguardService = new KeyguardServiceWrapper(mContext,
    +-                    IKeyguardService.Stub.asInterface(service));
    ++                    IKeyguardService.Stub.asInterface(service), mShowingStateChangedCallback);
    +             if (mKeyguardState.systemIsReady) {
    +                 // If the system is ready, it means keyguard crashed and restarted.
    +                 mKeyguardService.onSystemReady();
    +@@ -180,7 +184,7 @@ public class KeyguardServiceDelegate {
    +                 mKeyguardService.onBootCompleted();
    +             }
    +             if (mKeyguardState.occluded) {
    +-                mKeyguardService.setOccluded(mKeyguardState.occluded);
    ++                mKeyguardService.setOccluded(mKeyguardState.occluded, false /* animate */);
    +             }
    +         }
    + 
    +@@ -232,10 +236,10 @@ public class KeyguardServiceDelegate {
    +         }
    +     }
    + 
    +-    public void setOccluded(boolean isOccluded) {
    ++    public void setOccluded(boolean isOccluded, boolean animate) {
    +         if (mKeyguardService != null) {
    +-            if (DEBUG) Log.v(TAG, "setOccluded(" + isOccluded + ")");
    +-            mKeyguardService.setOccluded(isOccluded);
    ++            if (DEBUG) Log.v(TAG, "setOccluded(" + isOccluded + ") animate=" + animate);
    ++            mKeyguardService.setOccluded(isOccluded, animate);
    +         }
    +         mKeyguardState.occluded = isOccluded;
    +     }
    +diff --git a/services/core/java/com/android/server/policy/keyguard/KeyguardServiceWrapper.java b/services/core/java/com/android/server/policy/keyguard/KeyguardServiceWrapper.java
    +index 55652fe..de906e6 100644
    +--- a/services/core/java/com/android/server/policy/keyguard/KeyguardServiceWrapper.java
    ++++ b/services/core/java/com/android/server/policy/keyguard/KeyguardServiceWrapper.java
    +@@ -26,6 +26,7 @@ import com.android.internal.policy.IKeyguardDrawnCallback;
    + import com.android.internal.policy.IKeyguardExitCallback;
    + import com.android.internal.policy.IKeyguardService;
    + import com.android.internal.policy.IKeyguardStateCallback;
    ++import com.android.server.policy.keyguard.KeyguardStateMonitor.OnShowingStateChangedCallback;
    + 
    + import java.io.PrintWriter;
    + 
    +@@ -39,9 +40,11 @@ public class KeyguardServiceWrapper implements IKeyguardService {
    +     private IKeyguardService mService;
    +     private String TAG = "KeyguardServiceWrapper";
    + 
    +-    public KeyguardServiceWrapper(Context context, IKeyguardService service) {
    ++    public KeyguardServiceWrapper(Context context, IKeyguardService service,
    ++            OnShowingStateChangedCallback showingStateChangedCallback) {
    +         mService = service;
    +-        mKeyguardStateMonitor = new KeyguardStateMonitor(context, service);
    ++        mKeyguardStateMonitor = new KeyguardStateMonitor(context, service,
    ++                showingStateChangedCallback);
    +     }
    + 
    +     @Override // Binder interface
    +@@ -63,9 +66,9 @@ public class KeyguardServiceWrapper implements IKeyguardService {
    +     }
    + 
    +     @Override // Binder interface
    +-    public void setOccluded(boolean isOccluded) {
    ++    public void setOccluded(boolean isOccluded, boolean animate) {
    +         try {
    +-            mService.setOccluded(isOccluded);
    ++            mService.setOccluded(isOccluded, animate);
    +         } catch (RemoteException e) {
    +             Slog.w(TAG , "Remote Exception", e);
    +         }
    +diff --git a/services/core/java/com/android/server/policy/keyguard/KeyguardStateMonitor.java b/services/core/java/com/android/server/policy/keyguard/KeyguardStateMonitor.java
    +index 08eaaa9..712b625 100644
    +--- a/services/core/java/com/android/server/policy/keyguard/KeyguardStateMonitor.java
    ++++ b/services/core/java/com/android/server/policy/keyguard/KeyguardStateMonitor.java
    +@@ -49,10 +49,13 @@ public class KeyguardStateMonitor extends IKeyguardStateCallback.Stub {
    +     private int mCurrentUserId;
    + 
    +     private final LockPatternUtils mLockPatternUtils;
    ++    private final OnShowingStateChangedCallback mOnShowingStateChangedCallback;
    + 
    +-    public KeyguardStateMonitor(Context context, IKeyguardService service) {
    ++    public KeyguardStateMonitor(Context context, IKeyguardService service,
    ++            OnShowingStateChangedCallback showingStateChangedCallback) {
    +         mLockPatternUtils = new LockPatternUtils(context);
    +         mCurrentUserId = ActivityManager.getCurrentUser();
    ++        mOnShowingStateChangedCallback = showingStateChangedCallback;
    +         try {
    +             service.addStateMonitorCallback(this);
    +         } catch (RemoteException e) {
    +@@ -83,6 +86,7 @@ public class KeyguardStateMonitor extends IKeyguardStateCallback.Stub {
    +     @Override // Binder interface
    +     public void onShowingStateChanged(boolean showing) {
    +         mIsShowing = showing;
    ++        mOnShowingStateChangedCallback.onShowingStateChanged(showing);
    +     }
    + 
    +     @Override // Binder interface
    +@@ -122,4 +126,8 @@ public class KeyguardStateMonitor extends IKeyguardStateCallback.Stub {
    +         pw.println(prefix + "mTrusted=" + mTrusted);
    +         pw.println(prefix + "mCurrentUserId=" + mCurrentUserId);
    +     }
    ++
    ++    public interface OnShowingStateChangedCallback {
    ++        void onShowingStateChanged(boolean showing);
    ++    }
    + }
    +\ No newline at end of file
    +diff --git a/services/core/java/com/android/server/power/PowerManagerService.java b/services/core/java/com/android/server/power/PowerManagerService.java
    +index 2824e6e..01288b8 100644
    +--- a/services/core/java/com/android/server/power/PowerManagerService.java
    ++++ b/services/core/java/com/android/server/power/PowerManagerService.java
    +@@ -808,9 +808,10 @@ public final class PowerManagerService extends SystemService
    +     }
    + 
    +     private void updateLowPowerModeLocked() {
    +-        if (mIsPowered && mLowPowerModeSetting) {
    ++        if ((mIsPowered || !mBatteryLevelLow && !mBootCompleted) && mLowPowerModeSetting) {
    +             if (DEBUG_SPEW) {
    +-                Slog.d(TAG, "updateLowPowerModeLocked: powered, turning setting off");
    ++                Slog.d(TAG, "updateLowPowerModeLocked: powered or booting with sufficient battery,"
    ++                        + " turning setting off");
    +             }
    +             // Turn setting off if powered
    +             Settings.Global.putInt(mContext.getContentResolver(),
    +@@ -2538,18 +2539,18 @@ public final class PowerManagerService extends SystemService
    + 
    +     boolean setDeviceIdleModeInternal(boolean enabled) {
    +         synchronized (mLock) {
    +-            if (mDeviceIdleMode != enabled) {
    +-                mDeviceIdleMode = enabled;
    +-                updateWakeLockDisabledStatesLocked();
    +-                if (enabled) {
    +-                    EventLogTags.writeDeviceIdleOnPhase("power");
    +-                } else {
    +-                    EventLogTags.writeDeviceIdleOffPhase("power");
    +-                }
    +-                return true;
    ++            if (mDeviceIdleMode == enabled) {
    ++                return false;
    +             }
    +-            return false;
    ++            mDeviceIdleMode = enabled;
    ++            updateWakeLockDisabledStatesLocked();
    ++        }
    ++        if (enabled) {
    ++            EventLogTags.writeDeviceIdleOnPhase("power");
    ++        } else {
    ++            EventLogTags.writeDeviceIdleOffPhase("power");
    +         }
    ++        return true;
    +     }
    + 
    +     boolean setLightDeviceIdleModeInternal(boolean enabled) {
    +diff --git a/services/core/java/com/android/server/power/ShutdownThread.java b/services/core/java/com/android/server/power/ShutdownThread.java
    +index 8ce2fd9..44894ed 100644
    +--- a/services/core/java/com/android/server/power/ShutdownThread.java
    ++++ b/services/core/java/com/android/server/power/ShutdownThread.java
    +@@ -717,6 +717,14 @@ public final class ShutdownThread extends Thread {
    +         }
    +         if (!done[0]) {
    +             Log.w(TAG, "Timed out waiting for uncrypt.");
    ++            final int uncryptTimeoutError = 100;
    ++            String timeoutMessage = String.format("uncrypt_time: %d\n" + "uncrypt_error: %d\n",
    ++                    MAX_UNCRYPT_WAIT_TIME / 1000, uncryptTimeoutError);
    ++            try {
    ++                FileUtils.stringToFile(RecoverySystem.UNCRYPT_STATUS_FILE, timeoutMessage);
    ++            } catch (IOException e) {
    ++                Log.e(TAG, "Failed to write timeout message to uncrypt status", e);
    ++            }
    +         }
    +     }
    + }
    +diff --git a/services/core/java/com/android/server/storage/DeviceStorageMonitorService.java b/services/core/java/com/android/server/storage/DeviceStorageMonitorService.java
    +index 0ae1717..90c711a 100644
    +--- a/services/core/java/com/android/server/storage/DeviceStorageMonitorService.java
    ++++ b/services/core/java/com/android/server/storage/DeviceStorageMonitorService.java
    +@@ -87,6 +87,11 @@ public class DeviceStorageMonitorService extends SystemService {
    +     private static final long DEFAULT_DISK_FREE_CHANGE_REPORTING_THRESHOLD = 2 * 1024 * 1024; // 2MB
    +     private static final long DEFAULT_CHECK_INTERVAL = MONITOR_INTERVAL*60*1000;
    + 
    ++    // com.android.internal.R.string.low_internal_storage_view_text_no_boot
    ++    // hard codes 250MB in the message as the storage space required for the
    ++    // boot image.
    ++    private static final long BOOT_IMAGE_STORAGE_REQUIREMENT = 250 * 1024 * 1024;
    ++
    +     private long mFreeMem;  // on /data
    +     private long mFreeMemAfterLastCacheClear;  // on /data
    +     private long mLastReportedFreeMem;
    +@@ -290,9 +295,10 @@ public class DeviceStorageMonitorService extends SystemService {
    +                     mLowMemFlag = false;
    +                 }
    +             }
    +-            if (!mLowMemFlag && !mIsBootImageOnDisk) {
    ++            if (!mLowMemFlag && !mIsBootImageOnDisk && mFreeMem < BOOT_IMAGE_STORAGE_REQUIREMENT) {
    +                 Slog.i(TAG, "No boot image on disk due to lack of space. Sending notification");
    +                 sendNotification();
    ++                mLowMemFlag = true;
    +             }
    +             if (mFreeMem < mMemFullThreshold) {
    +                 if (!mMemFullFlag) {
    +@@ -383,7 +389,7 @@ public class DeviceStorageMonitorService extends SystemService {
    + 
    +         @Override
    +         public boolean isMemoryLow() {
    +-            return mLowMemFlag || !mIsBootImageOnDisk;
    ++            return mLowMemFlag;
    +         }
    + 
    +         @Override
    +diff --git a/services/core/java/com/android/server/trust/TrustManagerService.java b/services/core/java/com/android/server/trust/TrustManagerService.java
    +index d9c4254..a7b9cf4 100644
    +--- a/services/core/java/com/android/server/trust/TrustManagerService.java
    ++++ b/services/core/java/com/android/server/trust/TrustManagerService.java
    +@@ -102,9 +102,8 @@ public class TrustManagerService extends SystemService {
    +     private static final int MSG_START_USER = 7;
    +     private static final int MSG_CLEANUP_USER = 8;
    +     private static final int MSG_SWITCH_USER = 9;
    +-    private static final int MSG_SET_DEVICE_LOCKED = 10;
    +-    private static final int MSG_FLUSH_TRUST_USUALLY_MANAGED = 11;
    +-    private static final int MSG_UNLOCK_USER = 12;
    ++    private static final int MSG_FLUSH_TRUST_USUALLY_MANAGED = 10;
    ++    private static final int MSG_UNLOCK_USER = 11;
    + 
    +     private static final int TRUST_USUALLY_MANAGED_FLUSH_DELAY = 2 * 60 * 1000;
    + 
    +@@ -317,20 +316,6 @@ public class TrustManagerService extends SystemService {
    +         }
    +     }
    + 
    +-    public void setDeviceLockedForUser(int userId, boolean locked) {
    +-        if (mLockPatternUtils.isSeparateProfileChallengeEnabled(userId)) {
    +-            synchronized (mDeviceLockedForUser) {
    +-                mDeviceLockedForUser.put(userId, locked);
    +-            }
    +-            if (locked) {
    +-                try {
    +-                    ActivityManagerNative.getDefault().notifyLockedProfile(userId);
    +-                } catch (RemoteException e) {
    +-                }
    +-            }
    +-        }
    +-    }
    +-
    +     boolean isDeviceLockedInner(int userId) {
    +         synchronized (mDeviceLockedForUser) {
    +             return mDeviceLockedForUser.get(userId, true);
    +@@ -838,10 +823,24 @@ public class TrustManagerService extends SystemService {
    +         }
    + 
    +         @Override
    +-        public void setDeviceLockedForUser(int userId, boolean value) {
    ++        public void setDeviceLockedForUser(int userId, boolean locked) {
    +             enforceReportPermission();
    +-            mHandler.obtainMessage(MSG_SET_DEVICE_LOCKED, value ? 1 : 0, userId)
    +-                    .sendToTarget();
    ++            final long identity = Binder.clearCallingIdentity();
    ++            try {
    ++                if (mLockPatternUtils.isSeparateProfileChallengeEnabled(userId)) {
    ++                    synchronized (mDeviceLockedForUser) {
    ++                        mDeviceLockedForUser.put(userId, locked);
    ++                    }
    ++                    if (locked) {
    ++                        try {
    ++                            ActivityManagerNative.getDefault().notifyLockedProfile(userId);
    ++                        } catch (RemoteException e) {
    ++                        }
    ++                    }
    ++                }
    ++            } finally {
    ++                Binder.restoreCallingIdentity(identity);
    ++            }
    +         }
    + 
    +         @Override
    +@@ -917,9 +916,6 @@ public class TrustManagerService extends SystemService {
    +                     mCurrentUser = msg.arg1;
    +                     refreshDeviceLockedForUser(UserHandle.USER_ALL);
    +                     break;
    +-                case MSG_SET_DEVICE_LOCKED:
    +-                    setDeviceLockedForUser(msg.arg2, msg.arg1 != 0);
    +-                    break;
    +                 case MSG_FLUSH_TRUST_USUALLY_MANAGED:
    +                     SparseBooleanArray usuallyManaged;
    +                     synchronized (mTrustUsuallyManagedForUser) {
    +diff --git a/services/core/java/com/android/server/twilight/TwilightService.java b/services/core/java/com/android/server/twilight/TwilightService.java
    +index acd6587..db7df25 100644
    +--- a/services/core/java/com/android/server/twilight/TwilightService.java
    ++++ b/services/core/java/com/android/server/twilight/TwilightService.java
    +@@ -151,7 +151,7 @@ public final class TwilightService extends SystemService
    +     }
    + 
    +     private void startListening() {
    +-        if (DEBUG) Slog.d(TAG, "startListening");
    ++        Slog.d(TAG, "startListening");
    + 
    +         // Start listening for location updates (default: low power, max 1h, min 10m).
    +         mLocationManager.requestLocationUpdates(
    +@@ -173,7 +173,7 @@ public final class TwilightService extends SystemService
    +             mTimeChangedReceiver = new BroadcastReceiver() {
    +                 @Override
    +                 public void onReceive(Context context, Intent intent) {
    +-                    if (DEBUG) Slog.d(TAG, "onReceive: " + intent);
    ++                    Slog.d(TAG, "onReceive: " + intent);
    +                     updateTwilightState();
    +                 }
    +             };
    +@@ -188,7 +188,7 @@ public final class TwilightService extends SystemService
    +     }
    + 
    +     private void stopListening() {
    +-        if (DEBUG) Slog.d(TAG, "stopListening");
    ++        Slog.d(TAG, "stopListening");
    + 
    +         if (mTimeChangedReceiver != null) {
    +             getContext().unregisterReceiver(mTimeChangedReceiver);
    +@@ -241,15 +241,20 @@ public final class TwilightService extends SystemService
    + 
    +     @Override
    +     public void onAlarm() {
    +-        if (DEBUG) Slog.d(TAG, "onAlarm");
    ++        Slog.d(TAG, "onAlarm");
    +         updateTwilightState();
    +     }
    + 
    +     @Override
    +     public void onLocationChanged(Location location) {
    +-        if (DEBUG) Slog.d(TAG, "onLocationChanged: " + location);
    +-        mLastLocation = location;
    +-        updateTwilightState();
    ++        if (location != null) {
    ++            Slog.d(TAG, "onLocationChanged:"
    ++                    + " provider=" + location.getProvider()
    ++                    + " accuracy=" + location.getAccuracy()
    ++                    + " time=" + location.getTime());
    ++            mLastLocation = location;
    ++            updateTwilightState();
    ++        }
    +     }
    + 
    +     @Override
    +diff --git a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
    +index 536e646..3720940 100644
    +--- a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
    ++++ b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
    +@@ -89,6 +89,7 @@ import com.android.internal.os.BackgroundThread;
    + import com.android.internal.util.FastXmlSerializer;
    + import com.android.internal.util.JournaledFile;
    + import com.android.server.EventLogTags;
    ++import com.android.server.FgThread;
    + import com.android.server.SystemService;
    + 
    + import libcore.io.IoUtils;
    +@@ -479,6 +480,7 @@ public class WallpaperManagerService extends IWallpaperManager.Stub {
    +     WallpaperData mLastWallpaper;
    +     IWallpaperManagerCallback mKeyguardListener;
    +     boolean mWaitingForUnlock;
    ++    boolean mShuttingDown;
    + 
    +     /**
    +      * ID of the current wallpaper, changed every time anything sets a wallpaper.
    +@@ -589,6 +591,11 @@ public class WallpaperManagerService extends IWallpaperManager.Stub {
    + 
    +     class WallpaperConnection extends IWallpaperConnection.Stub
    +             implements ServiceConnection {
    ++
    ++        /** Time in milliseconds until we expect the wallpaper to reconnect (unless we're in the
    ++         *  middle of an update). If exceeded, the wallpaper gets reset to the system default. */
    ++        private static final long WALLPAPER_RECONNECT_TIMEOUT_MS = 5000;
    ++
    +         final WallpaperInfo mInfo;
    +         final Binder mToken = new Binder();
    +         IWallpaperService mService;
    +@@ -599,6 +606,26 @@ public class WallpaperManagerService extends IWallpaperManager.Stub {
    +         boolean mDimensionsChanged = false;
    +         boolean mPaddingChanged = false;
    + 
    ++        private Runnable mResetRunnable = () -> {
    ++            synchronized (mLock) {
    ++                if (mShuttingDown) {
    ++                    // Don't expect wallpaper services to relaunch during shutdown
    ++                    if (DEBUG) {
    ++                        Slog.i(TAG, "Ignoring relaunch timeout during shutdown");
    ++                    }
    ++                    return;
    ++                }
    ++
    ++                if (!mWallpaper.wallpaperUpdating
    ++                        && mWallpaper.userId == mCurrentUserId) {
    ++                    Slog.w(TAG, "Wallpaper reconnect timed out, "
    ++                            + "reverting to built-in wallpaper!");
    ++                    clearWallpaperLocked(true, FLAG_SYSTEM, mWallpaper.userId,
    ++                            null);
    ++                }
    ++            }
    ++        };
    ++
    +         public WallpaperConnection(WallpaperInfo info, WallpaperData wallpaper) {
    +             mInfo = info;
    +             mWallpaper = wallpaper;
    +@@ -615,6 +642,7 @@ public class WallpaperManagerService extends IWallpaperManager.Stub {
    +                     // locking there and anyway we always need to be able to
    +                     // recover if there is something wrong.
    +                     saveSettingsLocked(mWallpaper.userId);
    ++                    FgThread.getHandler().removeCallbacks(mResetRunnable);
    +                 }
    +             }
    +         }
    +@@ -641,6 +669,12 @@ public class WallpaperManagerService extends IWallpaperManager.Stub {
    +                             clearWallpaperLocked(true, FLAG_SYSTEM, mWallpaper.userId, null);
    +                         } else {
    +                             mWallpaper.lastDiedTime = SystemClock.uptimeMillis();
    ++
    ++                            // If we didn't reset it right away, do so after we couldn't connect to
    ++                            // it for an extended amount of time to avoid having a black wallpaper.
    ++                            FgThread.getHandler().removeCallbacks(mResetRunnable);
    ++                            FgThread.getHandler().postDelayed(mResetRunnable,
    ++                                    WALLPAPER_RECONNECT_TIMEOUT_MS);
    +                         }
    +                         final String flattened = name.flattenToString();
    +                         EventLog.writeEvent(EventLogTags.WP_WALLPAPER_CRASHED,
    +@@ -752,6 +786,10 @@ public class WallpaperManagerService extends IWallpaperManager.Stub {
    +                     if (wallpaper.wallpaperComponent != null
    +                             && wallpaper.wallpaperComponent.getPackageName().equals(packageName)) {
    +                         wallpaper.wallpaperUpdating = true;
    ++                        if (wallpaper.connection != null) {
    ++                            FgThread.getHandler().removeCallbacks(
    ++                                    wallpaper.connection.mResetRunnable);
    ++                        }
    +                     }
    +                 }
    +             }
    +@@ -838,6 +876,7 @@ public class WallpaperManagerService extends IWallpaperManager.Stub {
    +     public WallpaperManagerService(Context context) {
    +         if (DEBUG) Slog.v(TAG, "WallpaperService startup");
    +         mContext = context;
    ++        mShuttingDown = false;
    +         mImageWallpaper = ComponentName.unflattenFromString(
    +                 context.getResources().getString(R.string.image_wallpaper_component));
    +         mIWindowManager = IWindowManager.Stub.asInterface(
    +@@ -902,6 +941,21 @@ public class WallpaperManagerService extends IWallpaperManager.Stub {
    +             }
    +         }, userFilter);
    + 
    ++        final IntentFilter shutdownFilter = new IntentFilter(Intent.ACTION_SHUTDOWN);
    ++        mContext.registerReceiver(new BroadcastReceiver() {
    ++            @Override
    ++            public void onReceive(Context context, Intent intent) {
    ++                if (Intent.ACTION_SHUTDOWN.equals(intent.getAction())) {
    ++                    if (DEBUG) {
    ++                        Slog.i(TAG, "Shutting down");
    ++                    }
    ++                    synchronized (mLock) {
    ++                        mShuttingDown = true;
    ++                    }
    ++                }
    ++            }
    ++        }, shutdownFilter);
    ++
    +         try {
    +             ActivityManagerNative.getDefault().registerUserSwitchObserver(
    +                     new IUserSwitchObserver.Stub() {
    +@@ -1433,7 +1487,7 @@ public class WallpaperManagerService extends IWallpaperManager.Stub {
    +         lockWP.cropHint.set(sysWP.cropHint);
    +         lockWP.width = sysWP.width;
    +         lockWP.height = sysWP.height;
    +-        lockWP.allowBackup = false;
    ++        lockWP.allowBackup = sysWP.allowBackup;
    + 
    +         // Migrate the bitmap files outright; no need to copy
    +         try {
    +diff --git a/services/core/java/com/android/server/wm/AccessibilityController.java b/services/core/java/com/android/server/wm/AccessibilityController.java
    +index e5e2175..66b1b3d 100644
    +--- a/services/core/java/com/android/server/wm/AccessibilityController.java
    ++++ b/services/core/java/com/android/server/wm/AccessibilityController.java
    +@@ -644,7 +644,7 @@ final class AccessibilityController {
    +                 final int windowCount = windowList.size();
    +                 for (int i = 0; i < windowCount; i++) {
    +                     WindowState windowState = windowList.get(i);
    +-                    if (windowState.isOnScreen() &&
    ++                    if (windowState.isOnScreen() && windowState.isVisibleLw() &&
    +                             !windowState.mWinAnimator.mEnterAnimationPending) {
    +                         outWindows.put(windowState.mLayer, windowState);
    +                     }
    +diff --git a/services/core/java/com/android/server/wm/AppTransition.java b/services/core/java/com/android/server/wm/AppTransition.java
    +index d4d6f32..cd46165 100644
    +--- a/services/core/java/com/android/server/wm/AppTransition.java
    ++++ b/services/core/java/com/android/server/wm/AppTransition.java
    +@@ -374,6 +374,7 @@ public class AppTransition implements Dump {
    + 
    +     void goodToGo(AppWindowAnimator topOpeningAppAnimator, AppWindowAnimator topClosingAppAnimator,
    +             ArraySet<AppWindowToken> openingApps, ArraySet<AppWindowToken> closingApps) {
    ++        int appTransition = mNextAppTransition;
    +         mNextAppTransition = TRANSIT_UNSET;
    +         mAppTransitionState = APP_STATE_RUNNING;
    +         notifyAppTransitionStartingLocked(
    +@@ -382,7 +383,7 @@ public class AppTransition implements Dump {
    +                 topOpeningAppAnimator != null ? topOpeningAppAnimator.animation : null,
    +                 topClosingAppAnimator != null ? topClosingAppAnimator.animation : null);
    +         mService.getDefaultDisplayContentLocked().getDockedDividerController()
    +-                .notifyAppTransitionStarting();
    ++                .notifyAppTransitionStarting(openingApps, appTransition);
    + 
    +         // Prolong the start for the transition when docking a task from recents, unless recents
    +         // ended it already then we don't need to wait.
    +diff --git a/services/core/java/com/android/server/wm/AppWindowToken.java b/services/core/java/com/android/server/wm/AppWindowToken.java
    +index 621e43a..b1d2edf 100644
    +--- a/services/core/java/com/android/server/wm/AppWindowToken.java
    ++++ b/services/core/java/com/android/server/wm/AppWindowToken.java
    +@@ -30,6 +30,7 @@ import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME
    + import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
    + import static com.android.server.wm.WindowManagerService.WINDOW_REPLACEMENT_TIMEOUT_DURATION;
    + import static com.android.server.wm.WindowManagerService.H.NOTIFY_ACTIVITY_DRAWN;
    ++import static com.android.server.wm.WindowStateAnimator.STACK_CLIP_NONE;
    + 
    + import com.android.server.input.InputApplicationHandle;
    + import com.android.server.wm.WindowManagerService.H;
    +@@ -44,6 +45,7 @@ import android.util.Slog;
    + import android.view.IApplicationToken;
    + import android.view.View;
    + import android.view.WindowManager;
    ++import android.view.animation.Animation;
    + 
    + import java.io.PrintWriter;
    + import java.util.ArrayDeque;
    +@@ -838,6 +840,21 @@ class AppWindowToken extends WindowToken {
    +         }
    +     }
    + 
    ++    /**
    ++     * See {@link WindowManagerService#overridePlayingAppAnimationsLw}
    ++     */
    ++    void overridePlayingAppAnimations(Animation a) {
    ++        if (mAppAnimator.isAnimating()) {
    ++            final WindowState win = findMainWindow();
    ++            if (win == null) {
    ++                return;
    ++            }
    ++            final int width = win.mContainingFrame.width();
    ++            final int height = win.mContainingFrame.height();
    ++            mAppAnimator.setAnimation(a, width, height, false, STACK_CLIP_NONE);
    ++        }
    ++    }
    ++
    +     @Override
    +     void dump(PrintWriter pw, String prefix) {
    +         super.dump(pw, prefix);
    +diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
    +index 1d57872..e8104c4 100644
    +--- a/services/core/java/com/android/server/wm/DisplayContent.java
    ++++ b/services/core/java/com/android/server/wm/DisplayContent.java
    +@@ -22,12 +22,15 @@ import static android.app.ActivityManager.StackId.PINNED_STACK_ID;
    + import static android.view.WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
    + import static android.view.WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE;
    + import static android.view.WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL;
    ++import static android.view.WindowManager.LayoutParams.TYPE_TOAST;
    + import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_VISIBILITY;
    + import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
    + import static com.android.server.wm.WindowState.RESIZE_HANDLE_WIDTH_IN_DP;
    + 
    + import android.app.ActivityManager.StackId;
    ++import android.graphics.Matrix;
    + import android.graphics.Rect;
    ++import android.graphics.RectF;
    + import android.graphics.Region;
    + import android.graphics.Region.Op;
    + import android.util.DisplayMetrics;
    +@@ -35,6 +38,7 @@ import android.util.Slog;
    + import android.view.Display;
    + import android.view.DisplayInfo;
    + import android.view.Surface;
    ++import android.view.animation.Animation;
    + 
    + import java.io.PrintWriter;
    + import java.util.ArrayList;
    +@@ -100,6 +104,8 @@ class DisplayContent {
    +     /** Save allocating when calculating rects */
    +     private final Rect mTmpRect = new Rect();
    +     private final Rect mTmpRect2 = new Rect();
    ++    private final RectF mTmpRectF = new RectF();
    ++    private final Matrix mTmpMatrix = new Matrix();
    +     private final Region mTmpRegion = new Region();
    + 
    +     /** For gathering Task objects in order. */
    +@@ -236,6 +242,20 @@ class DisplayContent {
    +         out.set(left, top, left + width, top + height);
    +     }
    + 
    ++    private void getLogicalDisplayRect(Rect out, int orientation) {
    ++        getLogicalDisplayRect(out);
    ++
    ++        // Rotate the Rect if needed.
    ++        final int currentRotation = mDisplayInfo.rotation;
    ++        final int rotationDelta = deltaRotation(currentRotation, orientation);
    ++        if (rotationDelta == Surface.ROTATION_90 || rotationDelta == Surface.ROTATION_270) {
    ++            createRotationMatrix(rotationDelta, mBaseDisplayWidth, mBaseDisplayHeight, mTmpMatrix);
    ++            mTmpRectF.set(out);
    ++            mTmpMatrix.mapRect(mTmpRectF);
    ++            mTmpRectF.round(out);
    ++        }
    ++    }
    ++
    +     void getContentRect(Rect out) {
    +         out.set(mContentRect);
    +     }
    +@@ -530,38 +550,51 @@ class DisplayContent {
    +     }
    + 
    +     void rotateBounds(int oldRotation, int newRotation, Rect bounds) {
    +-        final int rotationDelta = DisplayContent.deltaRotation(oldRotation, newRotation);
    +-        getLogicalDisplayRect(mTmpRect);
    +-        switch (rotationDelta) {
    ++        getLogicalDisplayRect(mTmpRect, newRotation);
    ++
    ++        // Compute a transform matrix to undo the coordinate space transformation,
    ++        // and present the window at the same physical position it previously occupied.
    ++        final int deltaRotation = deltaRotation(newRotation, oldRotation);
    ++        createRotationMatrix(deltaRotation, mTmpRect.width(), mTmpRect.height(), mTmpMatrix);
    ++
    ++        mTmpRectF.set(bounds);
    ++        mTmpMatrix.mapRect(mTmpRectF);
    ++        mTmpRectF.round(bounds);
    ++    }
    ++
    ++    static int deltaRotation(int oldRotation, int newRotation) {
    ++        int delta = newRotation - oldRotation;
    ++        if (delta < 0) delta += 4;
    ++        return delta;
    ++    }
    ++
    ++    static void createRotationMatrix(int rotation, float displayWidth, float displayHeight,
    ++            Matrix outMatrix) {
    ++        // For rotations without Z-ordering we don't need the target rectangle's position.
    ++        createRotationMatrix(rotation, 0 /* rectLeft */, 0 /* rectTop */, displayWidth,
    ++                displayHeight, outMatrix);
    ++    }
    ++
    ++    static void createRotationMatrix(int rotation, float rectLeft, float rectTop,
    ++            float displayWidth, float displayHeight, Matrix outMatrix) {
    ++        switch (rotation) {
    +             case Surface.ROTATION_0:
    +-                mTmpRect2.set(bounds);
    ++                outMatrix.reset();
    +                 break;
    +-            case Surface.ROTATION_90:
    +-                mTmpRect2.top = mTmpRect.bottom - bounds.right;
    +-                mTmpRect2.left = bounds.top;
    +-                mTmpRect2.right = mTmpRect2.left + bounds.height();
    +-                mTmpRect2.bottom = mTmpRect2.top + bounds.width();
    ++            case Surface.ROTATION_270:
    ++                outMatrix.setRotate(270, 0, 0);
    ++                outMatrix.postTranslate(0, displayHeight);
    ++                outMatrix.postTranslate(rectTop, 0);
    +                 break;
    +             case Surface.ROTATION_180:
    +-                mTmpRect2.top = mTmpRect.bottom - bounds.bottom;
    +-                mTmpRect2.left = mTmpRect.right - bounds.right;
    +-                mTmpRect2.right = mTmpRect2.left + bounds.width();
    +-                mTmpRect2.bottom = mTmpRect2.top + bounds.height();
    ++                outMatrix.reset();
    +                 break;
    +-            case Surface.ROTATION_270:
    +-                mTmpRect2.top = bounds.left;
    +-                mTmpRect2.left = mTmpRect.right - bounds.bottom;
    +-                mTmpRect2.right = mTmpRect2.left + bounds.height();
    +-                mTmpRect2.bottom = mTmpRect2.top + bounds.width();
    ++            case Surface.ROTATION_90:
    ++                outMatrix.setRotate(90, 0, 0);
    ++                outMatrix.postTranslate(displayWidth, 0);
    ++                outMatrix.postTranslate(-rectTop, rectLeft);
    +                 break;
    +         }
    +-        bounds.set(mTmpRect2);
    +-    }
    +-
    +-    static int deltaRotation(int oldRotation, int newRotation) {
    +-        int delta = newRotation - oldRotation;
    +-        if (delta < 0) delta += 4;
    +-        return delta;
    +     }
    + 
    +     public void dump(String prefix, PrintWriter pw) {
    +@@ -637,7 +670,7 @@ class DisplayContent {
    +      */
    +     TaskStack getDockedStackVisibleForUserLocked() {
    +         final TaskStack stack = mService.mStackIdToStack.get(DOCKED_STACK_ID);
    +-        return (stack != null && stack.isVisibleForUserLocked()) ? stack : null;
    ++        return (stack != null && stack.isVisibleLocked(true /* ignoreKeyguard */)) ? stack : null;
    +     }
    + 
    +     /**
    +@@ -674,4 +707,48 @@ class DisplayContent {
    + 
    +         return touchedWin;
    +     }
    ++
    ++    /**
    ++     * See {@link WindowManagerService#overridePlayingAppAnimationsLw}.
    ++     */
    ++    void overridePlayingAppAnimationsLw(Animation a) {
    ++        for (int i = mStacks.size() - 1; i >= 0; i--) {
    ++            mStacks.get(i).overridePlayingAppAnimations(a);
    ++        }
    ++    }
    ++
    ++    boolean canAddToastWindowForUid(int uid) {
    ++        // We allow one toast window per UID being shown at a time.
    ++        WindowList windows = getWindowList();
    ++        final int windowCount = windows.size();
    ++        for (int i = 0; i < windowCount; i++) {
    ++            WindowState window = windows.get(i);
    ++            if (window.mAttrs.type == TYPE_TOAST && window.mOwnerUid == uid
    ++                    && !window.isRemovedOrHidden()) {
    ++                return false;
    ++            }
    ++        }
    ++        return true;
    ++    }
    ++
    ++    void scheduleToastWindowsTimeoutIfNeededLocked(WindowState oldFocus,
    ++                                                   WindowState newFocus) {
    ++        if (oldFocus == null || (newFocus != null && newFocus.mOwnerUid == oldFocus.mOwnerUid)) {
    ++            return;
    ++        }
    ++        final int lostFocusUid = oldFocus.mOwnerUid;
    ++        WindowList windows = getWindowList();
    ++        final int windowCount = windows.size();
    ++        for (int i = 0; i < windowCount; i++) {
    ++            WindowState window = windows.get(i);
    ++            if (window.mAttrs.type == TYPE_TOAST && window.mOwnerUid == lostFocusUid) {
    ++                if (!mService.mH.hasMessages(WindowManagerService.H.WINDOW_HIDE_TIMEOUT, window)) {
    ++                    mService.mH.sendMessageDelayed(
    ++                            mService.mH.obtainMessage(
    ++                                    WindowManagerService.H.WINDOW_HIDE_TIMEOUT, window),
    ++                            window.mAttrs.hideTimeoutMilliseconds);
    ++                }
    ++            }
    ++        }
    ++    }
    + }
    +diff --git a/services/core/java/com/android/server/wm/DockedStackDividerController.java b/services/core/java/com/android/server/wm/DockedStackDividerController.java
    +index f93e2ff..6f0a43a 100644
    +--- a/services/core/java/com/android/server/wm/DockedStackDividerController.java
    ++++ b/services/core/java/com/android/server/wm/DockedStackDividerController.java
    +@@ -29,6 +29,7 @@ import static android.view.WindowManager.DOCKED_RIGHT;
    + import static android.view.WindowManager.DOCKED_TOP;
    + import static com.android.server.wm.AppTransition.DEFAULT_APP_TRANSITION_DURATION;
    + import static com.android.server.wm.AppTransition.TOUCH_RESPONSE_INTERPOLATOR;
    ++import static com.android.server.wm.AppTransition.TRANSIT_NONE;
    + import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME;
    + import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
    + import static com.android.server.wm.WindowManagerService.H.NOTIFY_DOCKED_STACK_MINIMIZED_CHANGED;
    +@@ -38,6 +39,7 @@ import android.content.res.Configuration;
    + import android.graphics.Rect;
    + import android.os.RemoteCallbackList;
    + import android.os.RemoteException;
    ++import android.util.ArraySet;
    + import android.util.Slog;
    + import android.view.DisplayInfo;
    + import android.view.IDockedStackListener;
    +@@ -492,8 +494,32 @@ public class DockedStackDividerController implements DimLayerUser {
    +         checkMinimizeChanged(false /* animate */);
    +     }
    + 
    +-    void notifyAppTransitionStarting() {
    ++    void notifyAppTransitionStarting(ArraySet<AppWindowToken> openingApps, int appTransition) {
    ++        final boolean wasMinimized = mMinimizedDock;
    +         checkMinimizeChanged(true /* animate */);
    ++
    ++        // We were minimized, and now we are still minimized, but somebody is trying to launch an
    ++        // app in docked stack, better show recent apps so we actually get unminimized! This catches
    ++        // any case that was missed in ActivityStarter.postStartActivityUncheckedProcessing because
    ++        // we couldn't retrace the launch of the app in the docked stack to the launch from
    ++        // homescreen.
    ++        if (wasMinimized && mMinimizedDock && containsAppInDockedStack(openingApps)
    ++                && appTransition != TRANSIT_NONE) {
    ++            mService.showRecentApps(true /* fromHome */);
    ++        }
    ++    }
    ++
    ++    /**
    ++     * @return true if {@param apps} contains an activity in the docked stack, false otherwise.
    ++     */
    ++    private boolean containsAppInDockedStack(ArraySet<AppWindowToken> apps) {
    ++        for (int i = apps.size() - 1; i >= 0; i--) {
    ++            final AppWindowToken token = apps.valueAt(i);
    ++            if (token.mTask != null && token.mTask.mStack.mStackId == DOCKED_STACK_ID) {
    ++                return true;
    ++            }
    ++        }
    ++        return false;
    +     }
    + 
    +     boolean isMinimizedDock() {
    +diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java
    +index 1dcada6..ca183010 100644
    +--- a/services/core/java/com/android/server/wm/Task.java
    ++++ b/services/core/java/com/android/server/wm/Task.java
    +@@ -38,6 +38,7 @@ import android.util.EventLog;
    + import android.util.Slog;
    + import android.view.DisplayInfo;
    + import android.view.Surface;
    ++import android.view.animation.Animation;
    + 
    + import com.android.server.EventLogTags;
    + 
    +@@ -677,19 +678,6 @@ class Task implements DimLayer.DimLayerUser {
    +         return (tokensCount != 0) && mAppTokens.get(tokensCount - 1).showForAllUsers;
    +     }
    + 
    +-    boolean isVisibleForUser() {
    +-        for (int i = mAppTokens.size() - 1; i >= 0; i--) {
    +-            final AppWindowToken appToken = mAppTokens.get(i);
    +-            for (int j = appToken.allAppWindows.size() - 1; j >= 0; j--) {
    +-                WindowState window = appToken.allAppWindows.get(j);
    +-                if (!window.isHiddenFromUserLocked()) {
    +-                    return true;
    +-                }
    +-            }
    +-        }
    +-        return false;
    +-    }
    +-
    +     boolean isVisible() {
    +         for (int i = mAppTokens.size() - 1; i >= 0; i--) {
    +             final AppWindowToken appToken = mAppTokens.get(i);
    +@@ -778,6 +766,15 @@ class Task implements DimLayer.DimLayerUser {
    +         return mStack.getDisplayContent().getDisplayInfo();
    +     }
    + 
    ++    /**
    ++     * See {@link WindowManagerService#overridePlayingAppAnimationsLw}
    ++     */
    ++    void overridePlayingAppAnimations(Animation a) {
    ++        for (int i = mAppTokens.size() - 1; i >= 0; i--) {
    ++            mAppTokens.get(i).overridePlayingAppAnimations(a);
    ++        }
    ++    }
    ++
    +     @Override
    +     public String toString() {
    +         return "{taskId=" + mTaskId + " appTokens=" + mAppTokens + " mdr=" + mDeferRemoval + "}";
    +diff --git a/services/core/java/com/android/server/wm/TaskStack.java b/services/core/java/com/android/server/wm/TaskStack.java
    +index 8be5b19..8f8f642 100644
    +--- a/services/core/java/com/android/server/wm/TaskStack.java
    ++++ b/services/core/java/com/android/server/wm/TaskStack.java
    +@@ -44,6 +44,7 @@ import android.util.SparseArray;
    + import android.view.DisplayInfo;
    + import android.view.Surface;
    + import android.view.SurfaceControl;
    ++import android.view.animation.Animation;
    + 
    + import com.android.internal.policy.DividerSnapAlgorithm;
    + import com.android.internal.policy.DividerSnapAlgorithm.SnapTarget;
    +@@ -398,23 +399,21 @@ public class TaskStack implements DimLayer.DimLayerUser,
    +             return false;
    +         }
    + 
    +-        final int oldDockSide = mStackId == DOCKED_STACK_ID ? getDockSide() : DOCKED_INVALID;
    +         mTmpRect2.set(mBounds);
    +         mDisplayContent.rotateBounds(mRotation, newRotation, mTmpRect2);
    +         if (mStackId == DOCKED_STACK_ID) {
    +             repositionDockedStackAfterRotation(mTmpRect2);
    +             snapDockedStackAfterRotation(mTmpRect2);
    +             final int newDockSide = getDockSide(mTmpRect2);
    +-            if (oldDockSide != newDockSide) {
    +-                // Update the dock create mode and clear the dock create bounds, these
    +-                // might change after a rotation and the original values will be invalid.
    +-                mService.setDockedStackCreateStateLocked(
    +-                        (newDockSide == DOCKED_LEFT || newDockSide == DOCKED_TOP)
    +-                        ? DOCKED_STACK_CREATE_MODE_TOP_OR_LEFT
    +-                        : DOCKED_STACK_CREATE_MODE_BOTTOM_OR_RIGHT,
    +-                        null);
    +-                mDisplayContent.getDockedDividerController().notifyDockSideChanged(newDockSide);
    +-            }
    ++
    ++            // Update the dock create mode and clear the dock create bounds, these
    ++            // might change after a rotation and the original values will be invalid.
    ++            mService.setDockedStackCreateStateLocked(
    ++                    (newDockSide == DOCKED_LEFT || newDockSide == DOCKED_TOP)
    ++                    ? DOCKED_STACK_CREATE_MODE_TOP_OR_LEFT
    ++                    : DOCKED_STACK_CREATE_MODE_BOTTOM_OR_RIGHT,
    ++                    null);
    ++            mDisplayContent.getDockedDividerController().notifyDockSideChanged(newDockSide);
    +         }
    + 
    +         mBoundsAfterRotation.set(mTmpRect2);
    +@@ -890,7 +889,7 @@ public class TaskStack implements DimLayer.DimLayerUser,
    +             mAdjustImeAmount = adjustAmount;
    +             mAdjustDividerAmount = adjustDividerAmount;
    +             updateAdjustedBounds();
    +-            return isVisibleForUserLocked();
    ++            return isVisibleLocked(true /* ignoreKeyguard */);
    +         } else {
    +             return false;
    +         }
    +@@ -926,7 +925,7 @@ public class TaskStack implements DimLayer.DimLayerUser,
    +         if (minimizeAmount != mMinimizeAmount) {
    +             mMinimizeAmount = minimizeAmount;
    +             updateAdjustedBounds();
    +-            return isVisibleForUserLocked();
    ++            return isVisibleLocked(true /* ignoreKeyguard*/);
    +         } else {
    +             return false;
    +         }
    +@@ -943,7 +942,7 @@ public class TaskStack implements DimLayer.DimLayerUser,
    +     void beginImeAdjustAnimation() {
    +         for (int j = mTasks.size() - 1; j >= 0; j--) {
    +             final Task task = mTasks.get(j);
    +-            if (task.isVisibleForUser()) {
    ++            if (task.isVisible()) {
    +                 task.setDragResizing(true, DRAG_RESIZE_MODE_DOCKED_DIVIDER);
    +                 task.addWindowsWaitingForDrawnIfResizingChanged();
    +             }
    +@@ -1233,9 +1232,13 @@ public class TaskStack implements DimLayer.DimLayerUser,
    +     }
    + 
    +     boolean isVisibleLocked() {
    ++        return isVisibleLocked(false /* ignoreKeyguard */);
    ++    }
    ++
    ++    boolean isVisibleLocked(boolean ignoreKeyguard) {
    +         final boolean keyguardOn = mService.mPolicy.isKeyguardShowingOrOccluded()
    +                 && !mService.mAnimator.mKeyguardGoingAway;
    +-        if (keyguardOn && !StackId.isAllowedOverLockscreen(mStackId)) {
    ++        if (!ignoreKeyguard && keyguardOn && !StackId.isAllowedOverLockscreen(mStackId)) {
    +             // The keyguard is showing and the stack shouldn't show on top of the keyguard.
    +             return false;
    +         }
    +@@ -1252,20 +1255,6 @@ public class TaskStack implements DimLayer.DimLayerUser,
    +         return false;
    +     }
    + 
    +-    /**
    +-     * @return true if a the stack is visible for the current in user, ignoring any other visibility
    +-     *         aspects, and false otherwise
    +-     */
    +-    boolean isVisibleForUserLocked() {
    +-        for (int i = mTasks.size() - 1; i >= 0; i--) {
    +-            final Task task = mTasks.get(i);
    +-            if (task.isVisibleForUser()) {
    +-                return true;
    +-            }
    +-        }
    +-        return false;
    +-    }
    +-
    +     boolean isDragResizing() {
    +         return mDragResizing;
    +     }
    +@@ -1379,4 +1368,13 @@ public class TaskStack implements DimLayer.DimLayerUser,
    +     public boolean getBoundsAnimating() {
    +         return mBoundsAnimating;
    +     }
    ++
    ++    /**
    ++     * See {@link WindowManagerService#overridePlayingAppAnimationsLw}
    ++     */
    ++    void overridePlayingAppAnimations(Animation a) {
    ++        for (int i = mTasks.size() - 1; i >= 0; --i) {
    ++            mTasks.get(i).overridePlayingAppAnimations(a);
    ++        }
    ++    }
    + }
    +diff --git a/services/core/java/com/android/server/wm/WallpaperController.java b/services/core/java/com/android/server/wm/WallpaperController.java
    +index 2b66c3a..e7ceba9 100644
    +--- a/services/core/java/com/android/server/wm/WallpaperController.java
    ++++ b/services/core/java/com/android/server/wm/WallpaperController.java
    +@@ -757,14 +757,16 @@ class WallpaperController {
    +                 }
    + 
    +                 // Now stick it in. For apps over wallpaper keep the wallpaper at the bottommost
    +-                // layer. For keyguard over wallpaper put the wallpaper under the keyguard.
    ++                // layer. For keyguard over wallpaper put the wallpaper under the lowest window that
    ++                // is currently on screen, i.e. not hidden by policy.
    +                 int insertionIndex = 0;
    +                 if (visible && wallpaperTarget != null) {
    +                     final int type = wallpaperTarget.mAttrs.type;
    +                     final int privateFlags = wallpaperTarget.mAttrs.privateFlags;
    +                     if ((privateFlags & PRIVATE_FLAG_KEYGUARD) != 0
    +                             || type == TYPE_KEYGUARD_SCRIM) {
    +-                        insertionIndex = windows.indexOf(wallpaperTarget);
    ++                        insertionIndex = Math.min(windows.indexOf(wallpaperTarget),
    ++                                findLowestWindowOnScreen(windows));
    +                     }
    +                 }
    +                 if (DEBUG_WALLPAPER_LIGHT || DEBUG_WINDOW_MOVEMENT
    +@@ -781,6 +783,21 @@ class WallpaperController {
    +         return changed;
    +     }
    + 
    ++    /**
    ++     * @return The index in {@param windows} of the lowest window that is currently on screen and
    ++     *         not hidden by the policy.
    ++     */
    ++    private int findLowestWindowOnScreen(WindowList windows) {
    ++        final int size = windows.size();
    ++        for (int index = 0; index < size; index++) {
    ++            final WindowState win = windows.get(index);
    ++            if (win.isOnScreen()) {
    ++                return index;
    ++            }
    ++        }
    ++        return Integer.MAX_VALUE;
    ++    }
    ++
    +     boolean adjustWallpaperWindows() {
    +         mService.mWindowPlacerLocked.mWallpaperMayChange = false;
    + 
    +diff --git a/services/core/java/com/android/server/wm/WindowAnimator.java b/services/core/java/com/android/server/wm/WindowAnimator.java
    +index b0d357c..1ee5a22 100644
    +--- a/services/core/java/com/android/server/wm/WindowAnimator.java
    ++++ b/services/core/java/com/android/server/wm/WindowAnimator.java
    +@@ -121,6 +121,9 @@ public class WindowAnimator {
    + 
    +     private final AppTokenList mTmpExitingAppTokens = new AppTokenList();
    + 
    ++    /** The window that was previously hiding the Keyguard. */
    ++    private WindowState mLastShowWinWhenLocked;
    ++
    +     private String forceHidingToString() {
    +         switch (mForceHiding) {
    +             case KEYGUARD_NOT_SHOWN:    return "KEYGUARD_NOT_SHOWN";
    +@@ -221,13 +224,30 @@ public class WindowAnimator {
    +         }
    +     }
    + 
    ++    /**
    ++     * @return The window that is currently hiding the Keyguard, or if it was hiding the Keyguard,
    ++     *         and it's still animating.
    ++     */
    ++    private WindowState getWinShowWhenLockedOrAnimating() {
    ++        final WindowState winShowWhenLocked = (WindowState) mPolicy.getWinShowWhenLockedLw();
    ++        if (winShowWhenLocked != null) {
    ++            return winShowWhenLocked;
    ++        }
    ++        if (mLastShowWinWhenLocked != null && mLastShowWinWhenLocked.isOnScreen()
    ++                && mLastShowWinWhenLocked.isAnimatingLw()
    ++                && (mLastShowWinWhenLocked.mAttrs.flags & FLAG_SHOW_WHEN_LOCKED) != 0) {
    ++            return mLastShowWinWhenLocked;
    ++        }
    ++        return null;
    ++    }
    ++
    +     private boolean shouldForceHide(WindowState win) {
    +         final WindowState imeTarget = mService.mInputMethodTarget;
    +         final boolean showImeOverKeyguard = imeTarget != null && imeTarget.isVisibleNow() &&
    +                 ((imeTarget.getAttrs().flags & FLAG_SHOW_WHEN_LOCKED) != 0
    +                         || !mPolicy.canBeForceHidden(imeTarget, imeTarget.mAttrs));
    + 
    +-        final WindowState winShowWhenLocked = (WindowState) mPolicy.getWinShowWhenLockedLw();
    ++        final WindowState winShowWhenLocked = getWinShowWhenLockedOrAnimating();
    +         final AppWindowToken appShowWhenLocked = winShowWhenLocked == null ?
    +                 null : winShowWhenLocked.mAppToken;
    + 
    +@@ -241,7 +261,7 @@ public class WindowAnimator {
    +             allowWhenLocked |= appShowWhenLocked == win.mAppToken
    +                     // Show all SHOW_WHEN_LOCKED windows if some apps are shown over lockscreen
    +                     || (win.mAttrs.flags & FLAG_SHOW_WHEN_LOCKED) != 0
    +-                    // Show error dialogs over apps that dismiss keyguard.
    ++                    // Show error dialogs over apps that are shown on lockscreen
    +                     || (win.mAttrs.privateFlags & PRIVATE_FLAG_SYSTEM_ERROR) != 0;
    +         }
    + 
    +@@ -555,6 +575,11 @@ public class WindowAnimator {
    +                 mPostKeyguardExitAnimation = null;
    +             }
    +         }
    ++
    ++        final WindowState winShowWhenLocked = (WindowState) mPolicy.getWinShowWhenLockedLw();
    ++        if (winShowWhenLocked != null) {
    ++            mLastShowWinWhenLocked = winShowWhenLocked;
    ++        }
    +     }
    + 
    +     private void updateWallpaperLocked(int displayId) {
    +diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
    +index eb9ad6c..ca2610a 100644
    +--- a/services/core/java/com/android/server/wm/WindowManagerService.java
    ++++ b/services/core/java/com/android/server/wm/WindowManagerService.java
    +@@ -21,6 +21,7 @@ import android.animation.ValueAnimator;
    + import android.annotation.IntDef;
    + import android.annotation.NonNull;
    + import android.annotation.Nullable;
    ++import android.app.ActivityManager;
    + import android.app.ActivityManagerInternal;
    + import android.app.ActivityManagerNative;
    + import android.app.AppOpsManager;
    +@@ -35,6 +36,7 @@ import android.content.Context;
    + import android.content.Intent;
    + import android.content.IntentFilter;
    + import android.content.pm.ActivityInfo;
    ++import android.content.pm.ApplicationInfo;
    + import android.content.pm.PackageManager;
    + import android.content.res.CompatibilityInfo;
    + import android.content.res.Configuration;
    +@@ -201,6 +203,7 @@ import static android.view.WindowManager.LayoutParams.TYPE_NAVIGATION_BAR;
    + import static android.view.WindowManager.LayoutParams.TYPE_PRIVATE_PRESENTATION;
    + import static android.view.WindowManager.LayoutParams.TYPE_QS_DIALOG;
    + import static android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR;
    ++import static android.view.WindowManager.LayoutParams.TYPE_TOAST;
    + import static android.view.WindowManager.LayoutParams.TYPE_VOICE_INTERACTION;
    + import static android.view.WindowManager.LayoutParams.TYPE_WALLPAPER;
    + import static android.view.WindowManagerGlobal.RELAYOUT_DEFER_SURFACE_DESTROY;
    +@@ -249,6 +252,7 @@ import static com.android.server.wm.WindowManagerDebugConfig.TAG_KEEP_SCREEN_ON;
    + import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME;
    + import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
    + import static com.android.server.wm.WindowStateAnimator.DRAW_PENDING;
    ++import static com.android.server.wm.WindowStateAnimator.STACK_CLIP_NONE;
    + 
    + /** {@hide} */
    + public class WindowManagerService extends IWindowManager.Stub
    +@@ -650,6 +654,12 @@ public class WindowManagerService extends IWindowManager.Stub
    +     WindowManagerInternal.OnHardKeyboardStatusChangeListener mHardKeyboardStatusChangeListener;
    +     SettingsObserver mSettingsObserver;
    + 
    ++    // A count of the windows which are 'seamlessly rotated', e.g. a surface
    ++    // at an old orientation is being transformed. We freeze orientation updates
    ++    // while any windows are seamlessly rotated, so we need to track when this
    ++    // hits zero so we can apply deferred orientation updates.
    ++    int mSeamlessRotationCount = 0;
    ++
    +     private final class SettingsObserver extends ContentObserver {
    +         private final Uri mDisplayInversionEnabledUri =
    +                 Settings.Secure.getUriFor(Settings.Secure.ACCESSIBILITY_DISPLAY_INVERSION_ENABLED);
    +@@ -1868,6 +1878,7 @@ public class WindowManagerService extends IWindowManager.Stub
    +         boolean reportNewConfig = false;
    +         WindowState attachedWindow = null;
    +         long origId;
    ++        final int callingUid = Binder.getCallingUid();
    +         final int type = attrs.type;
    + 
    +         synchronized(mWindowMap) {
    +@@ -1915,6 +1926,8 @@ public class WindowManagerService extends IWindowManager.Stub
    +             boolean addToken = false;
    +             WindowToken token = mTokenMap.get(attrs.token);
    +             AppWindowToken atoken = null;
    ++            boolean addToastWindowRequiresToken = false;
    ++
    +             if (token == null) {
    +                 if (type >= FIRST_APPLICATION_WINDOW && type <= LAST_APPLICATION_WINDOW) {
    +                     Slog.w(TAG_WM, "Attempted to add application window with unknown token "
    +@@ -1951,6 +1964,15 @@ public class WindowManagerService extends IWindowManager.Stub
    +                             + attrs.token + ".  Aborting.");
    +                     return WindowManagerGlobal.ADD_BAD_APP_TOKEN;
    +                 }
    ++                if (type == TYPE_TOAST) {
    ++                    // Apps targeting SDK above N MR1 cannot arbitrary add toast windows.
    ++                    if (doesAddToastWindowRequireToken(attrs.packageName, callingUid,
    ++                            attachedWindow)) {
    ++                        Slog.w(TAG_WM, "Attempted to add a toast window with unknown token "
    ++                                + attrs.token + ".  Aborting.");
    ++                        return WindowManagerGlobal.ADD_BAD_APP_TOKEN;
    ++                    }
    ++                }
    +                 token = new WindowToken(this, attrs.token, -1, false);
    +                 addToken = true;
    +             } else if (type >= FIRST_APPLICATION_WINDOW && type <= LAST_APPLICATION_WINDOW) {
    +@@ -2000,6 +2022,15 @@ public class WindowManagerService extends IWindowManager.Stub
    +                             + attrs.token + ".  Aborting.");
    +                     return WindowManagerGlobal.ADD_BAD_APP_TOKEN;
    +                 }
    ++            } else if (type == TYPE_TOAST) {
    ++                // Apps targeting SDK above N MR1 cannot arbitrary add toast windows.
    ++                addToastWindowRequiresToken = doesAddToastWindowRequireToken(attrs.packageName,
    ++                        callingUid, attachedWindow);
    ++                if (addToastWindowRequiresToken && token.windowType != TYPE_TOAST) {
    ++                    Slog.w(TAG_WM, "Attempted to add a toast window with bad token "
    ++                            + attrs.token + ".  Aborting.");
    ++                    return WindowManagerGlobal.ADD_BAD_APP_TOKEN;
    ++                }
    +             } else if (type == TYPE_QS_DIALOG) {
    +                 if (token.windowType != TYPE_QS_DIALOG) {
    +                     Slog.w(TAG_WM, "Attempted to add QS dialog window with bad token "
    +@@ -2044,6 +2075,36 @@ public class WindowManagerService extends IWindowManager.Stub
    +                 win.openInputChannel(outInputChannel);
    +             }
    + 
    ++            // If adding a toast requires a token for this app we always schedule hiding
    ++            // toast windows to make sure they don't stick around longer then necessary.
    ++            // We hide instead of remove such windows as apps aren't prepared to handle
    ++            // windows being removed under them.
    ++            //
    ++            // If the app is older it can add toasts without a token and hence overlay
    ++            // other apps. To be maximally compatible with these apps we will hide the
    ++            // window after the toast timeout only if the focused window is from another
    ++            // UID, otherwise we allow unlimited duration. When a UID looses focus we
    ++            // schedule hiding all of its toast windows.
    ++            if (type == TYPE_TOAST) {
    ++                if (!getDefaultDisplayContentLocked().canAddToastWindowForUid(callingUid)) {
    ++                    Slog.w(TAG_WM, "Adding more than one toast window for UID at a time.");
    ++                    return WindowManagerGlobal.ADD_DUPLICATE_ADD;
    ++                }
    ++                // Make sure this happens before we moved focus as one can make the
    ++                // toast focusable to force it not being hidden after the timeout.
    ++                // Focusable toasts are always timed out to prevent a focused app to
    ++                // show a focusable toasts while it has focus which will be kept on
    ++                // the screen after the activity goes away.
    ++                if (addToastWindowRequiresToken
    ++                        || (attrs.flags & LayoutParams.FLAG_NOT_FOCUSABLE) == 0
    ++                        || mCurrentFocus == null
    ++                        || mCurrentFocus.mOwnerUid != callingUid) {
    ++                    mH.sendMessageDelayed(
    ++                            mH.obtainMessage(H.WINDOW_HIDE_TIMEOUT, win),
    ++                            win.mAttrs.hideTimeoutMilliseconds);
    ++                }
    ++            }
    ++
    +             // From now on, no exceptions or errors allowed!
    + 
    +             res = WindowManagerGlobal.ADD_OKAY;
    +@@ -2182,11 +2243,6 @@ public class WindowManagerService extends IWindowManager.Stub
    +             if (win.isVisibleOrAdding() && updateOrientationFromAppTokensLocked(false)) {
    +                 reportNewConfig = true;
    +             }
    +-            if (attrs.removeTimeoutMilliseconds > 0) {
    +-                mH.sendMessageDelayed(
    +-                        mH.obtainMessage(H.WINDOW_REMOVE_TIMEOUT, win),
    +-                        attrs.removeTimeoutMilliseconds);
    +-            }
    +         }
    + 
    +         if (reportNewConfig) {
    +@@ -2198,6 +2254,32 @@ public class WindowManagerService extends IWindowManager.Stub
    +         return res;
    +     }
    + 
    ++    private boolean doesAddToastWindowRequireToken(String packageName, int callingUid,
    ++            WindowState attachedWindow) {
    ++        // Try using the target SDK of the root window
    ++        if (attachedWindow != null) {
    ++            return attachedWindow.mAppToken != null
    ++                    && attachedWindow.mAppToken.targetSdk > Build.VERSION_CODES.N_MR1;
    ++        } else {
    ++            // Otherwise, look at the package
    ++            try {
    ++                ApplicationInfo appInfo = mContext.getPackageManager()
    ++                        .getApplicationInfoAsUser(packageName, 0,
    ++                                UserHandle.getUserId(callingUid));
    ++                if (appInfo.uid != callingUid) {
    ++                    throw new SecurityException("Package " + packageName + " not in UID "
    ++                            + callingUid);
    ++                }
    ++                if (appInfo.targetSdkVersion > Build.VERSION_CODES.N_MR1) {
    ++                    return true;
    ++                }
    ++            } catch (PackageManager.NameNotFoundException e) {
    ++                /* ignore */
    ++            }
    ++        }
    ++        return false;
    ++    }
    ++
    +     /**
    +      * Returns true if we're done setting up any transitions.
    +      */
    +@@ -2908,12 +2990,11 @@ public class WindowManagerService extends IWindowManager.Stub
    +                     }
    +                     result |= RELAYOUT_RES_SURFACE_CHANGED;
    +                 }
    +-                final WindowSurfaceController surfaceController = winAnimator.mSurfaceController;
    +-                if (viewVisibility == View.VISIBLE && surfaceController != null) {
    ++                if (viewVisibility == View.VISIBLE && winAnimator.hasSurface()) {
    +                     // We already told the client to go invisible, but the message may not be
    +                     // handled yet, or it might want to draw a last frame. If we already have a
    +                     // surface, let the client use that, but don't create new surface at this point.
    +-                    surfaceController.getSurface(outSurface);
    ++                    winAnimator.mSurfaceController.getSurface(outSurface);
    +                 } else {
    +                     if (DEBUG_VISIBILITY) Slog.i(TAG_WM, "Releasing surface in: " + win);
    + 
    +@@ -3715,7 +3796,11 @@ public class WindowManagerService extends IWindowManager.Stub
    +         Configuration config = null;
    + 
    +         if (updateOrientationFromAppTokensLocked(false)) {
    +-            if (freezeThisOneIfNeeded != null) {
    ++            // If we changed the orientation but mOrientationChangeComplete is
    ++            // already true, we used seamless rotation, and we don't need
    ++            // to freeze the screen.
    ++            if (freezeThisOneIfNeeded != null &&
    ++                    !mWindowPlacerLocked.mOrientationChangeComplete) {
    +                 AppWindowToken atoken = findAppWindowToken(freezeThisOneIfNeeded);
    +                 if (atoken != null) {
    +                     startAppFreezingScreenLocked(atoken);
    +@@ -3784,6 +3869,19 @@ public class WindowManagerService extends IWindowManager.Stub
    +         }
    +     }
    + 
    ++    // If this is true we have updated our desired orientation, but not yet
    ++    // changed the real orientation our applied our screen rotation animation.
    ++    // For example, because a previous screen rotation was in progress.
    ++    boolean rotationNeedsUpdateLocked() {
    ++        int rotation = mPolicy.rotationForOrientationLw(mLastOrientation, mRotation);
    ++        boolean altOrientation = !mPolicy.rotationHasCompatibleMetricsLw(
    ++                mLastOrientation, rotation);
    ++        if (mRotation == rotation && mAltOrientation == altOrientation) {
    ++            return false;
    ++        }
    ++        return true;
    ++    }
    ++
    +     @Override
    +     public int[] setNewConfiguration(Configuration config) {
    +         if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS,
    +@@ -5212,6 +5310,11 @@ public class WindowManagerService extends IWindowManager.Stub
    +         }
    +     }
    + 
    ++    @Override
    ++    public void overridePlayingAppAnimationsLw(Animation a) {
    ++        getDefaultDisplayContentLocked().overridePlayingAppAnimationsLw(a);
    ++    }
    ++
    +     /**
    +      * Re-sizes a stack and its containing tasks.
    +      * @param stackId Id of stack to resize.
    +@@ -6710,6 +6813,13 @@ public class WindowManagerService extends IWindowManager.Stub
    +             if (DEBUG_ORIENTATION) Slog.v(TAG_WM, "Deferring rotation, animation in progress.");
    +             return false;
    +         }
    ++        if (mDisplayFrozen) {
    ++            // Even if the screen rotation animation has finished (e.g. isAnimating
    ++            // returns false), there is still some time where we haven't yet unfrozen
    ++            // the display. We also need to abort rotation here.
    ++            if (DEBUG_ORIENTATION) Slog.v(TAG_WM, "Deferring rotation, still finishing previous rotation");
    ++            return false;
    ++        }
    + 
    +         if (!mDisplayEnabled) {
    +             // No point choosing a rotation if the display is not enabled.
    +@@ -6717,12 +6827,44 @@ public class WindowManagerService extends IWindowManager.Stub
    +             return false;
    +         }
    + 
    ++        final DisplayContent displayContent = getDefaultDisplayContentLocked();
    ++        final WindowList windows = displayContent.getWindowList();
    ++
    ++        final int oldRotation = mRotation;
    ++        int rotation = mPolicy.rotationForOrientationLw(mLastOrientation, mRotation);
    ++        boolean rotateSeamlessly = mPolicy.shouldRotateSeamlessly(oldRotation, rotation);
    ++
    ++        if (rotateSeamlessly) {
    ++            for (int i = windows.size() - 1; i >= 0; i--) {
    ++                WindowState w = windows.get(i);
    ++                // We can't rotate (seamlessly or not) while waiting for the last seamless rotation
    ++                // to complete (that is, waiting for windows to redraw). It's tempting to check
    ++                // w.mSeamlessRotationCount but that could be incorrect in the case of window-removal.
    ++                if (w.mSeamlesslyRotated) {
    ++                    return false;
    ++                }
    ++                // In what can only be called an unfortunate workaround we require
    ++                // seamlessly rotated child windows to have the TRANSFORM_TO_DISPLAY_INVERSE
    ++                // flag. Due to limitations in the client API, there is no way for
    ++                // the client to set this flag in a race free fashion. If we seamlessly rotate
    ++                // a window which does not have this flag, but then gains it, we will get
    ++                // an incorrect visual result (rotated viewfinder). This means if we want to
    ++                // support seamlessly rotating windows which could gain this flag, we can't
    ++                // rotate windows without it. This limits seamless rotation in N to camera framework
    ++                // users, windows without children, and native code. This is unfortunate but
    ++                // having the camera work is our primary goal.
    ++                if (w.isChildWindow() & w.isVisibleNow() &&
    ++                        !w.mWinAnimator.mSurfaceController.getTransformToDisplayInverse()) {
    ++                    rotateSeamlessly = false;
    ++                }
    ++            }
    ++        }
    ++
    +         // TODO: Implement forced rotation changes.
    +         //       Set mAltOrientation to indicate that the application is receiving
    +         //       an orientation that has different metrics than it expected.
    +         //       eg. Portrait instead of Landscape.
    + 
    +-        int rotation = mPolicy.rotationForOrientationLw(mLastOrientation, mRotation);
    +         boolean altOrientation = !mPolicy.rotationHasCompatibleMetricsLw(
    +                 mLastOrientation, rotation);
    + 
    +@@ -6735,7 +6877,7 @@ public class WindowManagerService extends IWindowManager.Stub
    + 
    +         if (mRotation == rotation && mAltOrientation == altOrientation) {
    +             // No change.
    +-            return false;
    ++             return false;
    +         }
    + 
    +         if (DEBUG_ORIENTATION) {
    +@@ -6745,8 +6887,6 @@ public class WindowManagerService extends IWindowManager.Stub
    +                 + ", lastOrientation=" + mLastOrientation);
    +         }
    + 
    +-        int oldRotation = mRotation;
    +-
    +         mRotation = rotation;
    +         mAltOrientation = altOrientation;
    +         mPolicy.setRotationLw(mRotation);
    +@@ -6755,7 +6895,6 @@ public class WindowManagerService extends IWindowManager.Stub
    +         mH.removeMessages(H.WINDOW_FREEZE_TIMEOUT);
    +         mH.sendEmptyMessageDelayed(H.WINDOW_FREEZE_TIMEOUT, WINDOW_FREEZE_TIMEOUT_DURATION);
    +         mWaitingForConfig = true;
    +-        final DisplayContent displayContent = getDefaultDisplayContentLocked();
    +         displayContent.layoutNeeded = true;
    +         final int[] anim = new int[2];
    +         if (displayContent.isDimming()) {
    +@@ -6763,33 +6902,6 @@ public class WindowManagerService extends IWindowManager.Stub
    +         } else {
    +             mPolicy.selectRotationAnimationLw(anim);
    +         }
    +-        boolean rotateSeamlessly = mPolicy.shouldRotateSeamlessly(oldRotation, mRotation);
    +-        final WindowList windows = displayContent.getWindowList();
    +-        // We can't rotate seamlessly while an existing seamless rotation is still
    +-        // waiting on windows to finish drawing.
    +-        if (rotateSeamlessly) {
    +-            for (int i = windows.size() - 1; i >= 0; i--) {
    +-                WindowState w = windows.get(i);
    +-                if (w.mSeamlesslyRotated) {
    +-                    rotateSeamlessly = false;
    +-                    break;
    +-                }
    +-                // In what can only be called an unfortunate workaround we require
    +-                // seamlessly rotated child windows to have the TRANSFORM_TO_DISPLAY_INVERSE
    +-                // flag. Due to limitations in the client API, there is no way for
    +-                // the client to set this flag in a race free fashion. If we seamlessly rotate
    +-                // a window which does not have this flag, but then gains it, we will get
    +-                // an incorrect visual result (rotated viewfinder). This means if we want to
    +-                // support seamlessly rotating windows which could gain this flag, we can't
    +-                // rotate windows without it. This limits seamless rotation in N to camera framework
    +-                // users, windows without children, and native code. This is unfortunate but
    +-                // having the camera work is our primary goal.
    +-                if (w.isChildWindow() & w.isVisibleNow() &&
    +-                        !w.mWinAnimator.mSurfaceController.getTransformToDisplayInverse()) {
    +-                    rotateSeamlessly = false;
    +-                }
    +-            }
    +-        }
    + 
    +         if (!rotateSeamlessly) {
    +             startFreezingDisplayLocked(inTransaction, anim[0], anim[1]);
    +@@ -6802,6 +6914,10 @@ public class WindowManagerService extends IWindowManager.Stub
    +             // When we are rotating seamlessly, we allow the elements to transition
    +             // to their rotated state independently and without a freeze required.
    +             screenRotationAnimation = null;
    ++
    ++            // We have to reset this in case a window was removed before it
    ++            // finished seamless rotation.
    ++            mSeamlessRotationCount = 0;
    +         }
    + 
    +         // We need to update our screen size information to match the new rotation. If the rotation
    +@@ -8160,7 +8276,7 @@ public class WindowManagerService extends IWindowManager.Stub
    +         public static final int NOTIFY_APP_TRANSITION_FINISHED = 49;
    +         public static final int NOTIFY_STARTING_WINDOW_DRAWN = 50;
    +         public static final int UPDATE_ANIMATION_SCALE = 51;
    +-        public static final int WINDOW_REMOVE_TIMEOUT = 52;
    ++        public static final int WINDOW_HIDE_TIMEOUT = 52;
    +         public static final int NOTIFY_DOCKED_STACK_MINIMIZED_CHANGED = 53;
    +         public static final int SEAMLESS_ROTATION_TIMEOUT = 54;
    + 
    +@@ -8780,7 +8896,7 @@ public class WindowManagerService extends IWindowManager.Stub
    +                     mAmInternal.notifyStartingWindowDrawn();
    +                 }
    +                 break;
    +-                case WINDOW_REMOVE_TIMEOUT: {
    ++                case WINDOW_HIDE_TIMEOUT: {
    +                     final WindowState window = (WindowState) msg.obj;
    +                     synchronized(mWindowMap) {
    +                         // TODO: This is all about fixing b/21693547
    +@@ -8791,8 +8907,11 @@ public class WindowManagerService extends IWindowManager.Stub
    +                         // running under debugger) to crash (b/29105388). The windows will
    +                         // eventually be removed when the client process finishes.
    +                         // The best we can do for now is remove the FLAG_KEEP_SCREEN_ON
    +-                        // and prevent the symptoms of b/21693547.
    ++                        // and prevent the symptoms of b/21693547. Since apps don't
    ++                        // support windows being removed under them we hide the window
    ++                        // and it will be removed when the app dies.
    +                         window.mAttrs.flags &= ~FLAG_KEEP_SCREEN_ON;
    ++                        window.hidePermanentlyLw();
    +                         window.setDisplayLayoutNeeded();
    +                         mWindowPlacerLocked.performSurfacePlacement();
    +                     }
    +@@ -8814,8 +8933,8 @@ public class WindowManagerService extends IWindowManager.Stub
    +                             if (w.mSeamlesslyRotated) {
    +                                 layoutNeeded = true;
    +                                 w.setDisplayLayoutNeeded();
    ++                                markForSeamlessRotation(w, false);
    +                             }
    +-                            w.mSeamlesslyRotated = false;
    +                         }
    +                         if (layoutNeeded) {
    +                             mWindowPlacerLocked.performSurfacePlacement();
    +@@ -9110,7 +9229,7 @@ public class WindowManagerService extends IWindowManager.Stub
    +     }
    + 
    +     @Override
    +-    public void setForcedDisplayDensity(int displayId, int density) {
    ++    public void setForcedDisplayDensityForUser(int displayId, int density, int userId) {
    +         if (mContext.checkCallingOrSelfPermission(
    +                 android.Manifest.permission.WRITE_SECURE_SETTINGS) !=
    +                 PackageManager.PERMISSION_GRANTED) {
    +@@ -9120,16 +9239,20 @@ public class WindowManagerService extends IWindowManager.Stub
    +         if (displayId != Display.DEFAULT_DISPLAY) {
    +             throw new IllegalArgumentException("Can only set the default display");
    +         }
    ++
    ++        final int targetUserId = ActivityManager.handleIncomingUser(Binder.getCallingPid(),
    ++                Binder.getCallingUid(), userId, false, true, "setForcedDisplayDensityForUser",
    ++                null);
    +         final long ident = Binder.clearCallingIdentity();
    +         try {
    +             synchronized(mWindowMap) {
    +                 final DisplayContent displayContent = getDisplayContentLocked(displayId);
    +-                if (displayContent != null) {
    ++                if (displayContent != null && mCurrentUserId == targetUserId) {
    +                     setForcedDisplayDensityLocked(displayContent, density);
    +-                    Settings.Secure.putStringForUser(mContext.getContentResolver(),
    +-                            Settings.Secure.DISPLAY_DENSITY_FORCED,
    +-                            Integer.toString(density), mCurrentUserId);
    +                 }
    ++                Settings.Secure.putStringForUser(mContext.getContentResolver(),
    ++                        Settings.Secure.DISPLAY_DENSITY_FORCED,
    ++                        Integer.toString(density), targetUserId);
    +             }
    +         } finally {
    +             Binder.restoreCallingIdentity(ident);
    +@@ -9137,7 +9260,7 @@ public class WindowManagerService extends IWindowManager.Stub
    +     }
    + 
    +     @Override
    +-    public void clearForcedDisplayDensity(int displayId) {
    ++    public void clearForcedDisplayDensityForUser(int displayId, int userId) {
    +         if (mContext.checkCallingOrSelfPermission(
    +                 android.Manifest.permission.WRITE_SECURE_SETTINGS) !=
    +                 PackageManager.PERMISSION_GRANTED) {
    +@@ -9147,16 +9270,20 @@ public class WindowManagerService extends IWindowManager.Stub
    +         if (displayId != Display.DEFAULT_DISPLAY) {
    +             throw new IllegalArgumentException("Can only set the default display");
    +         }
    ++
    ++        final int callingUserId = ActivityManager.handleIncomingUser(Binder.getCallingPid(),
    ++                Binder.getCallingUid(), userId, false, true, "clearForcedDisplayDensityForUser",
    ++                null);
    +         final long ident = Binder.clearCallingIdentity();
    +         try {
    +             synchronized(mWindowMap) {
    +                 final DisplayContent displayContent = getDisplayContentLocked(displayId);
    +-                if (displayContent != null) {
    ++                if (displayContent != null && mCurrentUserId == callingUserId) {
    +                     setForcedDisplayDensityLocked(displayContent,
    +                             displayContent.mInitialDisplayDensity);
    +-                    Settings.Secure.putStringForUser(mContext.getContentResolver(),
    +-                            Settings.Secure.DISPLAY_DENSITY_FORCED, "", mCurrentUserId);
    +                 }
    ++                Settings.Secure.putStringForUser(mContext.getContentResolver(),
    ++                        Settings.Secure.DISPLAY_DENSITY_FORCED, "", callingUserId);
    +             }
    +         } finally {
    +             Binder.restoreCallingIdentity(ident);
    +@@ -9828,6 +9955,12 @@ public class WindowManagerService extends IWindowManager.Stub
    + 
    +             adjustForImeIfNeeded(displayContent);
    + 
    ++            // We may need to schedule some toast windows to be removed. The
    ++            // toasts for an app that does not have input focus are removed
    ++            // within a timeout to prevent apps to redress other apps' UI.
    ++            getDefaultDisplayContentLocked().scheduleToastWindowsTimeoutIfNeededLocked(
    ++                        oldFocus, newFocus);
    ++
    +             Trace.traceEnd(Trace.TRACE_TAG_WINDOW_MANAGER);
    +             return true;
    +         }
    +@@ -10130,6 +10263,32 @@ public class WindowManagerService extends IWindowManager.Stub
    +     }
    + 
    +     @Override
    ++    public void setRecentsVisibility(boolean visible) {
    ++        if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.STATUS_BAR)
    ++                != PackageManager.PERMISSION_GRANTED) {
    ++            throw new SecurityException("Caller does not hold permission "
    ++                    + android.Manifest.permission.STATUS_BAR);
    ++        }
    ++
    ++        synchronized (mWindowMap) {
    ++            mPolicy.setRecentsVisibilityLw(visible);
    ++        }
    ++    }
    ++
    ++    @Override
    ++    public void setTvPipVisibility(boolean visible) {
    ++        if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.STATUS_BAR)
    ++                != PackageManager.PERMISSION_GRANTED) {
    ++            throw new SecurityException("Caller does not hold permission "
    ++                    + android.Manifest.permission.STATUS_BAR);
    ++        }
    ++
    ++        synchronized (mWindowMap) {
    ++            mPolicy.setTvPipVisibilityLw(visible);
    ++        }
    ++    }
    ++
    ++    @Override
    +     public void statusBarVisibilityChanged(int visibility) {
    +         if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.STATUS_BAR)
    +                 != PackageManager.PERMISSION_GRANTED) {
    +@@ -11361,6 +11520,26 @@ public class WindowManagerService extends IWindowManager.Stub
    +         mPolicy.registerShortcutKey(shortcutCode, shortcutKeyReceiver);
    +     }
    + 
    ++    void markForSeamlessRotation(WindowState w, boolean seamlesslyRotated) {
    ++        if (seamlesslyRotated == w.mSeamlesslyRotated) {
    ++            return;
    ++        }
    ++        w.mSeamlesslyRotated = seamlesslyRotated;
    ++        if (seamlesslyRotated) {
    ++            mSeamlessRotationCount++;
    ++        } else {
    ++            mSeamlessRotationCount--;
    ++        }
    ++        if (mSeamlessRotationCount == 0) {
    ++            if (DEBUG_ORIENTATION) {
    ++                Slog.i(TAG, "Performing post-rotate rotation after seamless rotation");
    ++            }
    ++            if (updateRotationUncheckedLocked(false)) {
    ++                mH.sendEmptyMessage(H.SEND_NEW_CONFIGURATION);
    ++            }
    ++        }
    ++    }
    ++
    +     private final class LocalService extends WindowManagerInternal {
    +         @Override
    +         public void requestTraversalFromDisplayManager() {
    +diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
    +index 54f60ef..fbef2c6 100644
    +--- a/services/core/java/com/android/server/wm/WindowState.java
    ++++ b/services/core/java/com/android/server/wm/WindowState.java
    +@@ -166,6 +166,7 @@ final class WindowState implements WindowManagerPolicy.WindowState {
    +     boolean mPolicyVisibility = true;
    +     boolean mPolicyVisibilityAfterAnim = true;
    +     boolean mAppOpVisibility = true;
    ++    boolean mPermanentlyHidden; // the window should never be shown again
    +     boolean mAppFreezing;
    +     boolean mAttachedHidden;    // is our parent window hidden?
    +     boolean mWallpaperVisible;  // for wallpaper, what was last vis report?
    +@@ -1417,7 +1418,7 @@ final class WindowState implements WindowManagerPolicy.WindowState {
    +      */
    +     boolean hasMoved() {
    +         return mHasSurface && (mContentChanged || mMovedByResize)
    +-                && !mAnimatingExit && mService.okToDisplay()
    ++                && !mAnimatingExit
    +                 && (mFrame.top != mLastFrame.top || mFrame.left != mLastFrame.left)
    +                 && (mAttachedWindow == null || !mAttachedWindow.hasMoved());
    +     }
    +@@ -1876,6 +1877,11 @@ final class WindowState implements WindowManagerPolicy.WindowState {
    +             // Being hidden due to app op request.
    +             return false;
    +         }
    ++        if (mPermanentlyHidden) {
    ++            // Permanently hidden until the app exists as apps aren't prepared
    ++            // to handle their windows being removed from under them.
    ++            return false;
    ++        }
    +         if (mPolicyVisibility && mPolicyVisibilityAfterAnim) {
    +             // Already showing.
    +             return false;
    +@@ -1966,6 +1972,13 @@ final class WindowState implements WindowManagerPolicy.WindowState {
    +         }
    +     }
    + 
    ++    public void hidePermanentlyLw() {
    ++        if (!mPermanentlyHidden) {
    ++            mPermanentlyHidden = true;
    ++            hideLw(true, true);
    ++        }
    ++    }
    ++
    +     public void pokeDrawLockLw(long timeout) {
    +         if (isVisibleOrAdding()) {
    +             if (mDrawLock == null) {
    +@@ -2615,7 +2628,7 @@ final class WindowState implements WindowManagerPolicy.WindowState {
    +             pw.println(Integer.toHexString(mSystemUiVisibility));
    +         }
    +         if (!mPolicyVisibility || !mPolicyVisibilityAfterAnim || !mAppOpVisibility
    +-                || mAttachedHidden) {
    ++                || mAttachedHidden || mPermanentlyHidden) {
    +             pw.print(prefix); pw.print("mPolicyVisibility=");
    +                     pw.print(mPolicyVisibility);
    +                     pw.print(" mPolicyVisibilityAfterAnim=");
    +@@ -2623,6 +2636,7 @@ final class WindowState implements WindowManagerPolicy.WindowState {
    +                     pw.print(" mAppOpVisibility=");
    +                     pw.print(mAppOpVisibility);
    +                     pw.print(" mAttachedHidden="); pw.println(mAttachedHidden);
    ++                    pw.print(" mPermanentlyHidden="); pw.println(mPermanentlyHidden);
    +         }
    +         if (!mRelayoutCalled || mLayoutNeeded) {
    +             pw.print(prefix); pw.print("mRelayoutCalled="); pw.print(mRelayoutCalled);
    +@@ -2947,4 +2961,10 @@ final class WindowState implements WindowManagerPolicy.WindowState {
    +     public boolean isRtl() {
    +         return mMergedConfiguration.getLayoutDirection() == View.LAYOUT_DIRECTION_RTL;
    +     }
    ++
    ++    public boolean isRemovedOrHidden() {
    ++        return mPermanentlyHidden || mAnimatingExit
    ++                || mRemoveOnExit || mWindowRemovalAllowed
    ++                || mViewVisibility == View.GONE;
    ++    }
    + }
    +diff --git a/services/core/java/com/android/server/wm/WindowStateAnimator.java b/services/core/java/com/android/server/wm/WindowStateAnimator.java
    +index 00f4a45..aa8e781 100644
    +--- a/services/core/java/com/android/server/wm/WindowStateAnimator.java
    ++++ b/services/core/java/com/android/server/wm/WindowStateAnimator.java
    +@@ -228,8 +228,6 @@ class WindowStateAnimator {
    +     int mAttrType;
    + 
    +     static final long PENDING_TRANSACTION_FINISH_WAIT_TIME = 100;
    +-    long mDeferTransactionUntilFrame = -1;
    +-    long mDeferTransactionTime = -1;
    + 
    +     boolean mForceScaleUntilResize;
    + 
    +@@ -1433,7 +1431,7 @@ class WindowStateAnimator {
    +         // If we are undergoing seamless rotation, the surface has already
    +         // been set up to persist at it's old location. We need to freeze
    +         // updates until a resize occurs.
    +-        w.mSeamlesslyRotated = w.mSeamlesslyRotated && !mSurfaceResized;
    ++        mService.markForSeamlessRotation(w, w.mSeamlesslyRotated && !mSurfaceResized);
    + 
    +         calculateSurfaceWindowCrop(mTmpClipRect, mTmpFinalClipRect);
    + 
    +@@ -2055,35 +2053,11 @@ class WindowStateAnimator {
    +         if (!mWin.isChildWindow()) {
    +             return;
    +         }
    +-        mDeferTransactionUntilFrame = frameNumber;
    +-        mDeferTransactionTime = System.currentTimeMillis();
    +         mSurfaceController.deferTransactionUntil(
    +                 mWin.mAttachedWindow.mWinAnimator.mSurfaceController.getHandle(),
    +                 frameNumber);
    +     }
    + 
    +-    // Defer the current transaction to the frame number of the last saved transaction.
    +-    // We do this to avoid shooting through an unsynchronized transaction while something is
    +-    // pending. This is generally fine, as either we will get in on the synchronization,
    +-    // or SurfaceFlinger will see that the frame has already occured. The only
    +-    // potential problem is in frame number resets so we reset things with a timeout
    +-    // every so often to be careful.
    +-    void deferToPendingTransaction() {
    +-        if (mDeferTransactionUntilFrame < 0) {
    +-            return;
    +-        }
    +-        long time = System.currentTimeMillis();
    +-        if (time > mDeferTransactionTime + PENDING_TRANSACTION_FINISH_WAIT_TIME) {
    +-            mDeferTransactionTime = -1;
    +-            mDeferTransactionUntilFrame = -1;
    +-        } else if (mWin.mAttachedWindow != null &&
    +-                mWin.mAttachedWindow.mWinAnimator.hasSurface()) {
    +-            mSurfaceController.deferTransactionUntil(
    +-                    mWin.mAttachedWindow.mWinAnimator.mSurfaceController.getHandle(),
    +-                    mDeferTransactionUntilFrame);
    +-        }
    +-    }
    +-
    +     /**
    +      * Sometimes we need to synchronize the first frame of animation with some external event.
    +      * To achieve this, we prolong the start of the animation and keep producing the first frame of
    +@@ -2128,24 +2102,8 @@ class WindowStateAnimator {
    +         // Compute a transform matrix to undo the coordinate space transformation,
    +         // and present the window at the same physical position it previously occupied.
    +         final int deltaRotation = DisplayContent.deltaRotation(newRotation, oldRotation);
    +-        switch (deltaRotation) {
    +-        case Surface.ROTATION_0:
    +-            transform.reset();
    +-            break;
    +-        case Surface.ROTATION_270:
    +-            transform.setRotate(270, 0, 0);
    +-            transform.postTranslate(0, displayHeight);
    +-            transform.postTranslate(y, 0);
    +-            break;
    +-        case Surface.ROTATION_180:
    +-            transform.reset();
    +-            break;
    +-        case Surface.ROTATION_90:
    +-            transform.setRotate(90, 0, 0);
    +-            transform.postTranslate(displayWidth, 0);
    +-            transform.postTranslate(-y, x);
    +-            break;
    +-        }
    ++        DisplayContent.createRotationMatrix(deltaRotation, x, y, displayWidth, displayHeight,
    ++                transform);
    + 
    +         // We have two cases:
    +         //  1. Windows with NATIVE_WINDOW_TRANSFORM_INVERSE_DISPLAY:
    +@@ -2182,7 +2140,7 @@ class WindowStateAnimator {
    +             cropRect.set(0, 0, w.mRequestedWidth, w.mRequestedWidth + w.mRequestedHeight);
    +             mSurfaceController.setCropInTransaction(cropRect, false);
    +         } else {
    +-            w.mSeamlesslyRotated = true;
    ++            mService.markForSeamlessRotation(w, true);
    +             transform.getValues(mService.mTmpFloats);
    + 
    +             float DsDx = mService.mTmpFloats[Matrix.MSCALE_X];
    +diff --git a/services/core/java/com/android/server/wm/WindowSurfaceController.java b/services/core/java/com/android/server/wm/WindowSurfaceController.java
    +index c77e572..f5ed9d1 100644
    +--- a/services/core/java/com/android/server/wm/WindowSurfaceController.java
    ++++ b/services/core/java/com/android/server/wm/WindowSurfaceController.java
    +@@ -153,9 +153,9 @@ class WindowSurfaceController {
    +     }
    + 
    +     void destroyInTransaction() {
    +-        //        if (SHOW_TRANSACTIONS || SHOW_SURFACE_ALLOC) {
    +-        Slog.i(TAG, "Destroying surface " + this + " called by " + Debug.getCallers(8));
    +-        //        }
    ++        if (SHOW_TRANSACTIONS || SHOW_SURFACE_ALLOC) {
    ++            Slog.i(TAG, "Destroying surface " + this + " called by " + Debug.getCallers(8));
    ++        }
    +         try {
    +             if (mSurfaceControl != null) {
    +                 mSurfaceControl.destroy();
    +diff --git a/services/core/java/com/android/server/wm/WindowSurfacePlacer.java b/services/core/java/com/android/server/wm/WindowSurfacePlacer.java
    +index fa5e3ca..eba52f9 100644
    +--- a/services/core/java/com/android/server/wm/WindowSurfacePlacer.java
    ++++ b/services/core/java/com/android/server/wm/WindowSurfacePlacer.java
    +@@ -101,6 +101,10 @@ class WindowSurfacePlacer {
    +     static final int SET_WALLPAPER_ACTION_PENDING       = 1 << 5;
    + 
    +     boolean mWallpaperMayChange = false;
    ++    // During an orientation change, we track whether all windows have rendered
    ++    // at the new orientation, and this will be false from changing orientation until that occurs.
    ++    // For seamless rotation cases this always stays true, as the windows complete their orientation
    ++    // changes 1 by 1 without disturbing global state.
    +     boolean mOrientationChangeComplete = true;
    +     boolean mWallpaperActionPending = false;
    + 
    +@@ -717,11 +721,13 @@ class WindowSurfacePlacer {
    +                     final boolean adjustedForMinimizedDockOrIme = task != null
    +                                 && (task.mStack.isAdjustedForMinimizedDockedStack()
    +                                     || task.mStack.isAdjustedForIme());
    +-                    if ((w.mAttrs.privateFlags & PRIVATE_FLAG_NO_MOVE_ANIMATION) == 0
    +-                            && !w.isDragResizing() && !adjustedForMinimizedDockOrIme
    +-                            && (task == null || w.getTask().mStack.hasMovementAnimations())
    +-                            && !w.mWinAnimator.mLastHidden) {
    +-                        winAnimator.setMoveAnimation(left, top);
    ++                    if (mService.okToDisplay()) {
    ++                        if ((w.mAttrs.privateFlags & PRIVATE_FLAG_NO_MOVE_ANIMATION) == 0
    ++                                && !w.isDragResizing() && !adjustedForMinimizedDockOrIme
    ++                                && (task == null || w.getTask().mStack.hasMovementAnimations())
    ++                                && !w.mWinAnimator.mLastHidden) {
    ++                            winAnimator.setMoveAnimation(left, top);
    ++                        }
    +                     }
    + 
    +                     //TODO (multidisplay): Accessibility supported only for the default display.
    +@@ -742,10 +748,6 @@ class WindowSurfacePlacer {
    + 
    +                 // Moved from updateWindowsAndWallpaperLocked().
    +                 if (w.mHasSurface) {
    +-                    // If we have recently synchronized a previous transaction for this
    +-                    // window ensure we don't push through an unsynchronized one now.
    +-                    winAnimator.deferToPendingTransaction();
    +-
    +                     // Take care of the window being ready to display.
    +                     final boolean committed = winAnimator.commitFinishDrawingLocked();
    +                     if (isDefaultDisplay && committed) {
    +@@ -1357,8 +1359,25 @@ class WindowSurfacePlacer {
    +                 "Checking " + appsCount + " opening apps (frozen="
    +                         + mService.mDisplayFrozen + " timeout="
    +                         + mService.mAppTransition.isTimeout() + ")...");
    ++        final ScreenRotationAnimation screenRotationAnimation =
    ++            mService.mAnimator.getScreenRotationAnimationLocked(
    ++                    Display.DEFAULT_DISPLAY);
    ++
    +         int reason = APP_TRANSITION_TIMEOUT;
    +         if (!mService.mAppTransition.isTimeout()) {
    ++            // Imagine the case where we are changing orientation due to an app transition, but a previous
    ++            // orientation change is still in progress. We won't process the orientation change
    ++            // for our transition because we need to wait for the rotation animation to finish.
    ++            // If we start the app transition at this point, we will interrupt it halfway with a new rotation
    ++            // animation after the old one finally finishes. It's better to defer the
    ++            // app transition.
    ++            if (screenRotationAnimation != null && screenRotationAnimation.isAnimating() &&
    ++                    mService.rotationNeedsUpdateLocked()) {
    ++                if (DEBUG_APP_TRANSITIONS) {
    ++                    Slog.v(TAG, "Delaying app transition for screen rotation animation to finish");
    ++                }
    ++                return false;
    ++            }
    +             for (int i = 0; i < appsCount; i++) {
    +                 AppWindowToken wtoken = mService.mOpeningApps.valueAt(i);
    +                 if (DEBUG_APP_TRANSITIONS) Slog.v(TAG,
    +diff --git a/services/core/jni/com_android_server_location_GnssLocationProvider.cpp b/services/core/jni/com_android_server_location_GnssLocationProvider.cpp
    +index e8d4c58..25e819c 100644
    +--- a/services/core/jni/com_android_server_location_GnssLocationProvider.cpp
    ++++ b/services/core/jni/com_android_server_location_GnssLocationProvider.cpp
    +@@ -1087,6 +1087,7 @@ void JavaObject::callSetter(
    +             method_name,
    +             "([B)V");
    +     env_->CallVoidMethod(object_, method, array);
    ++    env_->DeleteLocalRef(array);
    + }
    + 
    + jobject JavaObject::get() {
    +diff --git a/services/core/proto/ipconnectivity.proto b/services/core/proto/ipconnectivity.proto
    +new file mode 100644
    +index 0000000..e0d7f09
    +--- /dev/null
    ++++ b/services/core/proto/ipconnectivity.proto
    +@@ -0,0 +1,274 @@
    ++// LINT: LEGACY_NAMES
    ++syntax = "proto2";
    ++
    ++package clearcut.connectivity;
    ++
    ++option java_package = "com.android.server.connectivity.metrics";
    ++option java_outer_classname = "IpConnectivityLogClass";
    ++
    ++// NetworkId represents the id given by the system to a physical network on the
    ++// Android device. It is used to relates events to each other for devices with
    ++// multiple networks (WiFi, 4G, ...).
    ++message NetworkId {
    ++  // Every network gets assigned a network_id on creation based on order of
    ++  // creation. Thus network_id N is assigned to the network created directly
    ++  // after network N-1. Thus there is no PII involved here. Zero means no
    ++  // network. The value 0 is never assigned to a network.
    ++  optional int32 network_id = 1;
    ++};
    ++
    ++// Logs changes in the system default network. Changes can be 1) acquiring a
    ++// default network with no previous default, 2) a switch of the system default
    ++// network to a new default network, 3) a loss of the system default network.
    ++// This message is associated to android.net.metrics.DefaultNetworkEvent.
    ++message DefaultNetworkEvent {
    ++  // A value of 0 means this is a loss of the system default network.
    ++  optional NetworkId network_id = 1;
    ++
    ++  // A value of 0 means there was no previous default network.
    ++  optional NetworkId previous_network_id = 2;
    ++
    ++  // Whether the network supports IPv4, IPv6, or both.
    ++  enum IPSupport {
    ++    NONE = 0;
    ++    IPV4 = 1;
    ++    IPV6 = 2;
    ++    DUAL = 3;
    ++  };
    ++
    ++  // Best available information about IP support of the previous network when
    ++  // disconnecting or switching to a new default network.
    ++  optional IPSupport previous_network_ip_support = 3;
    ++
    ++  // The transport types of the new default network, represented by
    ++  // TRANSPORT_* constants as defined in NetworkCapabilities.
    ++  repeated int32 transport_types = 4;
    ++};
    ++
    ++// Logs IpReachabilityMonitor probe events and NUD_FAILED events.
    ++// This message is associated to android.net.metrics.IpReachabilityEvent.
    ++message IpReachabilityEvent {
    ++  // The interface name (wlan, rmnet, lo, ...) on which the probe was sent.
    ++  optional string if_name = 1;
    ++
    ++  // The event type code of the probe, represented by constants defined in
    ++  // android.net.metrics.IpReachabilityEvent.
    ++  optional int32 event_type = 2;
    ++};
    ++
    ++// Logs NetworkMonitor and ConnectivityService events related to the state of
    ++// a network: connection, evaluation, validation, lingering, and disconnection.
    ++// This message is associated to android.net.metrics.NetworkEvent.
    ++message NetworkEvent {
    ++  // The id of the network on which this event happened.
    ++  optional NetworkId network_id = 1;
    ++
    ++  // The type of network event, represented by NETWORK_* constants defined in
    ++  // android.net.metrics.NetworkEvent.
    ++  optional int32 event_type = 2;
    ++
    ++  // Only valid after finishing evaluating a network for Internet connectivity.
    ++  // The time it took for this evaluation to complete.
    ++  optional int32 latency_ms = 3;
    ++}
    ++
    ++// Logs individual captive portal probing events that are performed when
    ++// evaluating or reevaluating networks for Internet connectivity.
    ++// This message is associated to android.net.metrics.ValidationProbeEvent.
    ++message ValidationProbeEvent {
    ++  // The id of the network for which the probe was sent.
    ++  optional NetworkId network_id = 1;
    ++
    ++  // The time it took for that probe to complete or time out.
    ++  optional int32 latency_ms = 2;
    ++
    ++  // The type of portal probe, represented by PROBE_* constants defined in
    ++  // android.net.metrics.ValidationProbeEvent.
    ++  optional int32 probe_type = 3;
    ++
    ++  // The http code result of the probe test.
    ++  optional int32 probe_result = 4;
    ++}
    ++
    ++// Logs DNS lookup latencies. Repeated fields must have the same length.
    ++// This message is associated to android.net.metrics.DnsEvent.
    ++message DNSLookupBatch {
    ++  // The id of the network on which the DNS lookups took place.
    ++  optional NetworkId network_id = 1;
    ++
    ++  // The types of the DNS lookups, as defined in android.net.metrics.DnsEvent.
    ++  repeated int32 event_types = 2;
    ++
    ++  // The return values of the DNS resolver for each DNS lookups.
    ++  repeated int32 return_codes = 3;
    ++
    ++  // The time it took for each DNS lookups to complete.
    ++  repeated int32 latencies_ms = 4;
    ++};
    ++
    ++// Represents a DHCP event on a single interface, which can be a DHCPClient
    ++// state transition or a response packet parsing error.
    ++// This message is associated to android.net.metrics.DhcpClientEvent and
    ++// android.net.metrics.DhcpErrorEvent.
    ++message DHCPEvent {
    ++  // The interface name (wlan, rmnet, lo, ...) on which the event happened.
    ++  optional string if_name = 1;
    ++
    ++  oneof value {
    ++    // The name of a state in the DhcpClient state machine, represented by
    ++    // the inner classes of android.net.dhcp.DhcpClient.
    ++    string state_transition = 2;
    ++
    ++    // The error code of a DHCP error, represented by constants defined in
    ++    // android.net.metrics.DhcpErrorEvent.
    ++    int32 error_code = 3;
    ++  }
    ++
    ++  // Lifetime duration in milliseconds of a DhcpClient state, or transition
    ++  // time in milliseconds between specific pairs of DhcpClient's states.
    ++  // Only populated when state_transition is populated.
    ++  optional int32 duration_ms = 4;
    ++}
    ++
    ++// Represents the generation of an Android Packet Filter program.
    ++message ApfProgramEvent {
    ++  // Lifetime of the program in seconds.
    ++  optional int64 lifetime = 1;
    ++
    ++  // Number of RAs filtered by the APF program.
    ++  optional int32 filtered_ras = 2;
    ++
    ++  // Total number of RAs to filter currently tracked by ApfFilter. Can be more
    ++  // than filtered_ras if all available program size was exhausted.
    ++  optional int32 current_ras = 3;
    ++
    ++  // Length of the APF program in bytes.
    ++  optional int32 program_length = 4;
    ++
    ++  // True if the APF program is dropping multicast and broadcast traffic.
    ++  optional bool drop_multicast = 5;
    ++
    ++  // True if the interface on which APF runs has an IPv4 address.
    ++  optional bool has_ipv4_addr = 6;
    ++}
    ++
    ++// Represents Router Advertisement listening statistics for an interface with
    ++// Android Packet Filter enabled.
    ++message ApfStatistics {
    ++  // The time interval in milliseconds these stastistics cover.
    ++  optional int64 duration_ms = 1;
    ++
    ++  // The total number of received RAs.
    ++  optional int32 received_ras = 2;
    ++
    ++  // The total number of received RAs that matched a known RA.
    ++  optional int32 matching_ras = 3;
    ++
    ++  // The total number of received RAs ignored due to the MAX_RAS limit.
    ++  optional int32 dropped_ras = 5;
    ++
    ++  // The total number of received RAs with an effective lifetime of 0 seconds.
    ++  // Effective lifetime for APF is the minimum of all lifetimes in a RA.
    ++  optional int32 zero_lifetime_ras = 6;
    ++
    ++  // The total number of received RAs that could not be parsed.
    ++  optional int32 parse_errors = 7;
    ++
    ++  // The total number of APF program updates triggered by an RA reception.
    ++  optional int32 program_updates = 8;
    ++
    ++  // The maximum APF program size in byte advertised by hardware.
    ++  optional int32 max_program_size = 9;
    ++}
    ++
    ++// Represents the reception of a Router Advertisement packet for an interface
    ++// with Android Packet Filter enabled.
    ++message RaEvent {
    ++  // All lifetime values are expressed in seconds. The default value for an
    ++  // option lifetime that was not present in the RA option list is -1.
    ++  // The lifetime of an option (e.g., the Prefix Information Option) is the
    ++  // minimum lifetime of all such options in the packet.
    ++
    ++  // The value of the router lifetime in the RA packet.
    ++  optional int64 router_lifetime = 1;
    ++
    ++  // Prefix valid lifetime from the prefix information option.
    ++  optional int64 prefix_valid_lifetime = 2;
    ++
    ++  // Prefix preferred lifetime from the prefix information option.
    ++  optional int64 prefix_preferred_lifetime = 3;
    ++
    ++  // Route info lifetime.
    ++  optional int64 route_info_lifetime = 4;
    ++
    ++  // Recursive DNS server lifetime.
    ++  optional int64 rdnss_lifetime = 5;
    ++
    ++  // DNS search list lifetime.
    ++  optional int64 dnssl_lifetime = 6;
    ++}
    ++
    ++// Represents an IP provisioning event in IpManager and how long the
    ++// provisioning action took.
    ++// This message is associated to android.net.metrics.IpManagerEvent.
    ++message IpProvisioningEvent {
    ++  // The interface name (wlan, rmnet, lo, ...) on which the probe was sent.
    ++  optional string if_name = 1;
    ++
    ++  // The code of the IP provisioning event, represented by constants defined in
    ++  // android.net.metrics.IpManagerEvent.
    ++  optional int32 event_type = 2;
    ++
    ++  // The duration of the provisioning action that resulted in this event.
    ++  optional int32 latency_ms = 3;
    ++}
    ++
    ++// Represents one of the IP connectivity event defined in this file.
    ++// Next tag: 12
    ++message IpConnectivityEvent {
    ++  // Time in ms when the event was recorded.
    ++  optional int64 time_ms = 1;
    ++
    ++  // Event type.
    ++  oneof event {
    ++
    ++    // An event about the system default network.
    ++    DefaultNetworkEvent default_network_event = 2;
    ++
    ++    // An IP reachability probe event.
    ++    IpReachabilityEvent ip_reachability_event = 3;
    ++
    ++    // A network lifecycle event.
    ++    NetworkEvent network_event = 4;
    ++
    ++    // A batch of DNS lookups.
    ++    DNSLookupBatch dns_lookup_batch = 5;
    ++
    ++    // A DHCP client event or DHCP receive error.
    ++    DHCPEvent dhcp_event = 6;
    ++
    ++    // An IP provisioning event.
    ++    IpProvisioningEvent ip_provisioning_event = 7;
    ++
    ++    // A network validation probe event.
    ++    ValidationProbeEvent validation_probe_event = 8;
    ++
    ++    // An Android Packet Filter program event.
    ++    ApfProgramEvent apf_program_event = 9;
    ++
    ++    // An Android Packet Filter statistics event.
    ++    ApfStatistics apf_statistics = 10;
    ++
    ++    // An RA packet reception event.
    ++    RaEvent ra_event = 11;
    ++  };
    ++};
    ++
    ++// The information about IP connectivity events.
    ++message IpConnectivityLog {
    ++  // An array of IP connectivity events.
    ++  repeated IpConnectivityEvent events = 1;
    ++
    ++  // The number of events that had to be dropped due to a full buffer.
    ++  optional int32 dropped_events = 2;
    ++};
    +diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
    +index c75b8c2..92aa1b9 100644
    +--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
    ++++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
    +@@ -29,6 +29,7 @@ import static org.xmlpull.v1.XmlPullParser.TEXT;
    + 
    + import android.Manifest.permission;
    + import android.accessibilityservice.AccessibilityServiceInfo;
    ++import android.accounts.Account;
    + import android.accounts.AccountManager;
    + import android.annotation.IntDef;
    + import android.annotation.NonNull;
    +@@ -308,6 +309,12 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
    + 
    +     private static final int DEVICE_ADMIN_DEACTIVATE_TIMEOUT = 10000;
    + 
    ++    /**
    ++     * Minimum timeout in milliseconds after which unlocking with weak auth times out,
    ++     * i.e. the user has to use a strong authentication method like password, PIN or pattern.
    ++     */
    ++    private static final long MINIMUM_STRONG_AUTH_TIMEOUT_MS = 1 * 60 * 60 * 1000; // 1h
    ++
    +     final Context mContext;
    +     final Injector mInjector;
    +     final IPackageManager mIPackageManager;
    +@@ -496,9 +503,9 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
    +                 new MonitoringCertNotificationTask().execute(userId);
    +             }
    +             if (Intent.ACTION_USER_ADDED.equals(action)) {
    +-                disableSecurityLoggingIfNotCompliant();
    ++                disableDeviceOwnerManagedSingleUserFeaturesIfNeeded();
    +             } else if (Intent.ACTION_USER_REMOVED.equals(action)) {
    +-                disableSecurityLoggingIfNotCompliant();
    ++                disableDeviceOwnerManagedSingleUserFeaturesIfNeeded();
    +                 removeUserData(userHandle);
    +             } else if (Intent.ACTION_USER_STARTED.equals(action)) {
    +                 synchronized (DevicePolicyManagerService.this) {
    +@@ -524,6 +531,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
    + 
    +     static class ActiveAdmin {
    +         private static final String TAG_DISABLE_KEYGUARD_FEATURES = "disable-keyguard-features";
    ++        private static final String TAG_TEST_ONLY_ADMIN = "test-only-admin";
    +         private static final String TAG_DISABLE_CAMERA = "disable-camera";
    +         private static final String TAG_DISABLE_CALLER_ID = "disable-caller-id";
    +         private static final String TAG_DISABLE_CONTACTS_SEARCH = "disable-contacts-search";
    +@@ -548,6 +556,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
    +         private static final String TAG_PERMITTED_IMES = "permitted-imes";
    +         private static final String TAG_MAX_FAILED_PASSWORD_WIPE = "max-failed-password-wipe";
    +         private static final String TAG_MAX_TIME_TO_UNLOCK = "max-time-to-unlock";
    ++        private static final String TAG_STRONG_AUTH_UNLOCK_TIMEOUT = "strong-auth-unlock-timeout";
    +         private static final String TAG_MIN_PASSWORD_NONLETTER = "min-password-nonletter";
    +         private static final String TAG_MIN_PASSWORD_SYMBOLS = "min-password-symbols";
    +         private static final String TAG_MIN_PASSWORD_NUMERIC = "min-password-numeric";
    +@@ -602,6 +611,8 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
    +         static final long DEF_MAXIMUM_TIME_TO_UNLOCK = 0;
    +         long maximumTimeToUnlock = DEF_MAXIMUM_TIME_TO_UNLOCK;
    + 
    ++        long strongAuthUnlockTimeout = 0; // admin doesn't participate by default
    ++
    +         static final int DEF_MAXIMUM_FAILED_PASSWORDS_FOR_WIPE = 0;
    +         int maximumFailedPasswordsForWipe = DEF_MAXIMUM_FAILED_PASSWORDS_FOR_WIPE;
    + 
    +@@ -616,6 +627,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
    +         int disabledKeyguardFeatures = DEF_KEYGUARD_FEATURES_DISABLED;
    + 
    +         boolean encryptionRequested = false;
    ++        boolean testOnlyAdmin = false;
    +         boolean disableCamera = false;
    +         boolean disableCallerId = false;
    +         boolean disableContactsSearch = false;
    +@@ -750,6 +762,11 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
    +                 out.attribute(null, ATTR_VALUE, Long.toString(maximumTimeToUnlock));
    +                 out.endTag(null, TAG_MAX_TIME_TO_UNLOCK);
    +             }
    ++            if (strongAuthUnlockTimeout != DevicePolicyManager.DEFAULT_STRONG_AUTH_TIMEOUT_MS) {
    ++                out.startTag(null, TAG_STRONG_AUTH_UNLOCK_TIMEOUT);
    ++                out.attribute(null, ATTR_VALUE, Long.toString(strongAuthUnlockTimeout));
    ++                out.endTag(null, TAG_STRONG_AUTH_UNLOCK_TIMEOUT);
    ++            }
    +             if (maximumFailedPasswordsForWipe != DEF_MAXIMUM_FAILED_PASSWORDS_FOR_WIPE) {
    +                 out.startTag(null, TAG_MAX_FAILED_PASSWORD_WIPE);
    +                 out.attribute(null, ATTR_VALUE, Integer.toString(maximumFailedPasswordsForWipe));
    +@@ -785,6 +802,11 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
    +                 out.attribute(null, ATTR_VALUE, Boolean.toString(encryptionRequested));
    +                 out.endTag(null, TAG_ENCRYPTION_REQUESTED);
    +             }
    ++            if (testOnlyAdmin) {
    ++                out.startTag(null, TAG_TEST_ONLY_ADMIN);
    ++                out.attribute(null, ATTR_VALUE, Boolean.toString(testOnlyAdmin));
    ++                out.endTag(null, TAG_TEST_ONLY_ADMIN);
    ++            }
    +             if (disableCamera) {
    +                 out.startTag(null, TAG_DISABLE_CAMERA);
    +                 out.attribute(null, ATTR_VALUE, Boolean.toString(disableCamera));
    +@@ -959,6 +981,9 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
    +                 } else if (TAG_MAX_TIME_TO_UNLOCK.equals(tag)) {
    +                     maximumTimeToUnlock = Long.parseLong(
    +                             parser.getAttributeValue(null, ATTR_VALUE));
    ++                } else if (TAG_STRONG_AUTH_UNLOCK_TIMEOUT.equals(tag)) {
    ++                    strongAuthUnlockTimeout = Long.parseLong(
    ++                            parser.getAttributeValue(null, ATTR_VALUE));
    +                 } else if (TAG_MAX_FAILED_PASSWORD_WIPE.equals(tag)) {
    +                     maximumFailedPasswordsForWipe = Integer.parseInt(
    +                             parser.getAttributeValue(null, ATTR_VALUE));
    +@@ -980,6 +1005,9 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
    +                 } else if (TAG_ENCRYPTION_REQUESTED.equals(tag)) {
    +                     encryptionRequested = Boolean.parseBoolean(
    +                             parser.getAttributeValue(null, ATTR_VALUE));
    ++                } else if (TAG_TEST_ONLY_ADMIN.equals(tag)) {
    ++                    testOnlyAdmin = Boolean.parseBoolean(
    ++                            parser.getAttributeValue(null, ATTR_VALUE));
    +                 } else if (TAG_DISABLE_CAMERA.equals(tag)) {
    +                     disableCamera = Boolean.parseBoolean(
    +                             parser.getAttributeValue(null, ATTR_VALUE));
    +@@ -1178,6 +1206,8 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
    + 
    +         void dump(String prefix, PrintWriter pw) {
    +             pw.print(prefix); pw.print("uid="); pw.println(getUid());
    ++            pw.print(prefix); pw.print("testOnlyAdmin=");
    ++            pw.println(testOnlyAdmin);
    +             pw.print(prefix); pw.println("policies:");
    +             ArrayList<DeviceAdminInfo.PolicyInfo> pols = info.getUsedPolicies();
    +             if (pols != null) {
    +@@ -1205,6 +1235,8 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
    +                     pw.println(minimumPasswordNonLetter);
    +             pw.print(prefix); pw.print("maximumTimeToUnlock=");
    +                     pw.println(maximumTimeToUnlock);
    ++            pw.print(prefix); pw.print("strongAuthUnlockTimeout=");
    ++                    pw.println(strongAuthUnlockTimeout);
    +             pw.print(prefix); pw.print("maximumFailedPasswordsForWipe=");
    +                     pw.println(maximumFailedPasswordsForWipe);
    +             pw.print(prefix); pw.print("specifiesGlobalProxy=");
    +@@ -1699,7 +1731,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
    +             if (mOwners.hasDeviceOwner()) {
    +                 mInjector.systemPropertiesSet(PROPERTY_DEVICE_OWNER_PRESENT, "true");
    +                 Slog.i(LOG_TAG, "Set ro.device_owner property to true");
    +-                disableSecurityLoggingIfNotCompliant();
    ++                disableDeviceOwnerManagedSingleUserFeaturesIfNeeded();
    +                 if (mInjector.securityLogGetLoggingEnabledProperty()) {
    +                     mSecurityLogMonitor.start();
    +                 }
    +@@ -2828,8 +2860,9 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
    +         synchronized (this) {
    +             long ident = mInjector.binderClearCallingIdentity();
    +             try {
    +-                if (!refreshing
    +-                        && getActiveAdminUncheckedLocked(adminReceiver, userHandle) != null) {
    ++                final ActiveAdmin existingAdmin
    ++                        = getActiveAdminUncheckedLocked(adminReceiver, userHandle);
    ++                if (!refreshing && existingAdmin != null) {
    +                     throw new IllegalArgumentException("Admin is already added");
    +                 }
    +                 if (policy.mRemovingAdmins.contains(adminReceiver)) {
    +@@ -2837,6 +2870,9 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
    +                             "Trying to set an admin which is being removed");
    +                 }
    +                 ActiveAdmin newAdmin = new ActiveAdmin(info, /* parent */ false);
    ++                newAdmin.testOnlyAdmin =
    ++                        (existingAdmin != null) ? existingAdmin.testOnlyAdmin
    ++                                : isPackageTestOnly(adminReceiver.getPackageName(), userHandle);
    +                 policy.mAdminMap.put(adminReceiver, newAdmin);
    +                 int replaceIndex = -1;
    +                 final int N = policy.mAdminList.size();
    +@@ -2948,23 +2984,13 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
    +         enforceShell("forceRemoveActiveAdmin");
    +         long ident = mInjector.binderClearCallingIdentity();
    +         try {
    +-            final ApplicationInfo ai;
    +-            try {
    +-                ai = mIPackageManager.getApplicationInfo(adminReceiver.getPackageName(),
    +-                        0, userHandle);
    +-            } catch (RemoteException e) {
    +-                throw new IllegalStateException(e);
    +-            }
    +-            if (ai == null) {
    +-                throw new IllegalStateException("Couldn't find package to remove admin "
    +-                        + adminReceiver.getPackageName() + " " + userHandle);
    +-            }
    +-            if ((ai.flags & ApplicationInfo.FLAG_TEST_ONLY) == 0) {
    +-                throw new SecurityException("Attempt to remove non-test admin " + adminReceiver
    +-                        + adminReceiver + " " + userHandle);
    +-            }
    +-            // If admin is a device or profile owner tidy that up first.
    +             synchronized (this)  {
    ++                if (!isAdminTestOnlyLocked(adminReceiver, userHandle)) {
    ++                    throw new SecurityException("Attempt to remove non-test admin "
    ++                            + adminReceiver + " " + userHandle);
    ++                }
    ++
    ++                // If admin is a device or profile owner tidy that up first.
    +                 if (isDeviceOwner(adminReceiver, userHandle)) {
    +                     clearDeviceOwnerLocked(getDeviceOwnerAdminLocked(), userHandle);
    +                 }
    +@@ -2976,11 +3002,47 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
    +             }
    +             // Remove the admin skipping sending the broadcast.
    +             removeAdminArtifacts(adminReceiver, userHandle);
    ++            Slog.i(LOG_TAG, "Admin " + adminReceiver + " removed from user " + userHandle);
    +         } finally {
    +             mInjector.binderRestoreCallingIdentity(ident);
    +         }
    +     }
    + 
    ++    /**
    ++     * Return if a given package has testOnly="true", in which case we'll relax certain rules
    ++     * for CTS.
    ++     *
    ++     * DO NOT use this method except in {@link #setActiveAdmin}.  Use {@link #isAdminTestOnlyLocked}
    ++     * to check wehter an active admin is test-only or not.
    ++     *
    ++     * The system allows this flag to be changed when an app is updated, which is not good
    ++     * for us.  So we persist the flag in {@link ActiveAdmin} when an admin is first installed,
    ++     * and used the persisted version in actual checks. (See b/31382361 and b/28928996)
    ++     */
    ++    private boolean isPackageTestOnly(String packageName, int userHandle) {
    ++        final ApplicationInfo ai;
    ++        try {
    ++            ai = mIPackageManager.getApplicationInfo(packageName,
    ++                    (PackageManager.MATCH_DIRECT_BOOT_AWARE
    ++                            | PackageManager.MATCH_DIRECT_BOOT_UNAWARE), userHandle);
    ++        } catch (RemoteException e) {
    ++            throw new IllegalStateException(e);
    ++        }
    ++        if (ai == null) {
    ++            throw new IllegalStateException("Couldn't find package: "
    ++                    + packageName + " on user " + userHandle);
    ++        }
    ++        return (ai.flags & ApplicationInfo.FLAG_TEST_ONLY) != 0;
    ++    }
    ++
    ++    /**
    ++     * See {@link #isPackageTestOnly}.
    ++     */
    ++    private boolean isAdminTestOnlyLocked(ComponentName who, int userHandle) {
    ++        final ActiveAdmin admin = getActiveAdminUncheckedLocked(who, userHandle);
    ++        return (admin != null) && admin.testOnlyAdmin;
    ++    }
    ++
    +     private void enforceShell(String method) {
    +         final int callingUid = Binder.getCallingUid();
    +         if (callingUid != Process.SHELL_UID && callingUid != Process.ROOT_UID) {
    +@@ -3678,12 +3740,16 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
    + 
    +     private boolean isActivePasswordSufficientForUserLocked(
    +             DevicePolicyData policy, int userHandle, boolean parent) {
    +-        if (policy.mActivePasswordQuality < getPasswordQuality(null, userHandle, parent)
    +-                || policy.mActivePasswordLength < getPasswordMinimumLength(
    ++        final int requiredPasswordQuality = getPasswordQuality(null, userHandle, parent);
    ++        if (policy.mActivePasswordQuality < requiredPasswordQuality) {
    ++            return false;
    ++        }
    ++        if (requiredPasswordQuality >= DevicePolicyManager.PASSWORD_QUALITY_NUMERIC
    ++                && policy.mActivePasswordLength < getPasswordMinimumLength(
    +                         null, userHandle, parent)) {
    +             return false;
    +         }
    +-        if (policy.mActivePasswordQuality != DevicePolicyManager.PASSWORD_QUALITY_COMPLEX) {
    ++        if (requiredPasswordQuality != DevicePolicyManager.PASSWORD_QUALITY_COMPLEX) {
    +             return true;
    +         }
    +         return policy.mActivePasswordUpperCase >= getPasswordMinimumUpperCase(
    +@@ -4176,6 +4242,65 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
    +     }
    + 
    +     @Override
    ++    public void setRequiredStrongAuthTimeout(ComponentName who, long timeoutMs,
    ++            boolean parent) {
    ++        if (!mHasFeature) {
    ++            return;
    ++        }
    ++        Preconditions.checkNotNull(who, "ComponentName is null");
    ++        Preconditions.checkArgument(timeoutMs >= 0, "Timeout must not be a negative number.");
    ++        // timeoutMs with value 0 means that the admin doesn't participate
    ++        // timeoutMs is clamped to the interval in case the internal constants change in the future
    ++        if (timeoutMs != 0 && timeoutMs < MINIMUM_STRONG_AUTH_TIMEOUT_MS) {
    ++            timeoutMs = MINIMUM_STRONG_AUTH_TIMEOUT_MS;
    ++        }
    ++        if (timeoutMs > DevicePolicyManager.DEFAULT_STRONG_AUTH_TIMEOUT_MS) {
    ++            timeoutMs = DevicePolicyManager.DEFAULT_STRONG_AUTH_TIMEOUT_MS;
    ++        }
    ++
    ++        final int userHandle = mInjector.userHandleGetCallingUserId();
    ++        synchronized (this) {
    ++            ActiveAdmin ap = getActiveAdminForCallerLocked(who,
    ++                    DeviceAdminInfo.USES_POLICY_PROFILE_OWNER, parent);
    ++            if (ap.strongAuthUnlockTimeout != timeoutMs) {
    ++                ap.strongAuthUnlockTimeout = timeoutMs;
    ++                saveSettingsLocked(userHandle);
    ++            }
    ++        }
    ++    }
    ++
    ++    /**
    ++     * Return a single admin's strong auth unlock timeout or minimum value (strictest) of all
    ++     * admins if who is null.
    ++     * Returns 0 if not configured for the provided admin.
    ++     */
    ++    @Override
    ++    public long getRequiredStrongAuthTimeout(ComponentName who, int userId, boolean parent) {
    ++        if (!mHasFeature) {
    ++            return DevicePolicyManager.DEFAULT_STRONG_AUTH_TIMEOUT_MS;
    ++        }
    ++        enforceFullCrossUsersPermission(userId);
    ++        synchronized (this) {
    ++            if (who != null) {
    ++                ActiveAdmin admin = getActiveAdminUncheckedLocked(who, userId, parent);
    ++                return admin != null ? admin.strongAuthUnlockTimeout : 0;
    ++            }
    ++
    ++            // Return the strictest policy across all participating admins.
    ++            List<ActiveAdmin> admins = getActiveAdminsForLockscreenPoliciesLocked(userId, parent);
    ++
    ++            long strongAuthUnlockTimeout = DevicePolicyManager.DEFAULT_STRONG_AUTH_TIMEOUT_MS;
    ++            for (int i = 0; i < admins.size(); i++) {
    ++                final long timeout = admins.get(i).strongAuthUnlockTimeout;
    ++                if (timeout != 0) { // take only participating admins into account
    ++                    strongAuthUnlockTimeout = Math.min(timeout, strongAuthUnlockTimeout);
    ++                }
    ++            }
    ++            return Math.max(strongAuthUnlockTimeout, MINIMUM_STRONG_AUTH_TIMEOUT_MS);
    ++        }
    ++    }
    ++
    ++    @Override
    +     public void lockNow(boolean parent) {
    +         if (!mHasFeature) {
    +             return;
    +@@ -4517,7 +4642,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
    +      * not installed and therefore not available.
    +      *
    +      * @throws SecurityException if the caller is not a profile or device owner.
    +-     * @throws UnsupportedException if the package does not support being set as always-on.
    ++     * @throws UnsupportedOperationException if the package does not support being set as always-on.
    +      */
    +     @Override
    +     public boolean setAlwaysOnVpnPackage(ComponentName admin, String vpnPackage, boolean lockdown)
    +@@ -5713,7 +5838,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
    +                     + " for device owner");
    +         }
    +         synchronized (this) {
    +-            enforceCanSetDeviceOwnerLocked(userId);
    ++            enforceCanSetDeviceOwnerLocked(admin, userId);
    +             if (getActiveAdminUncheckedLocked(admin, userId) == null
    +                     || getUserData(userId).mRemovingAdmins.contains(admin)) {
    +                 throw new IllegalArgumentException("Not active admin: " + admin);
    +@@ -5745,6 +5870,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
    +             } finally {
    +                 mInjector.binderRestoreCallingIdentity(ident);
    +             }
    ++            Slog.i(LOG_TAG, "Device owner set: " + admin + " on user " + userId);
    +             return true;
    +         }
    +     }
    +@@ -5866,6 +5992,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
    +             } finally {
    +                 mInjector.binderRestoreCallingIdentity(ident);
    +             }
    ++            Slog.i(LOG_TAG, "Device owner removed: " + deviceOwnerComponent);
    +         }
    +     }
    + 
    +@@ -5881,7 +6008,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
    +         mOwners.clearDeviceOwner();
    +         mOwners.writeDeviceOwner();
    +         updateDeviceOwnerLocked();
    +-        disableSecurityLoggingIfNotCompliant();
    ++        disableDeviceOwnerManagedSingleUserFeaturesIfNeeded();
    +         try {
    +             // Reactivate backup service.
    +             mInjector.getIBackupManager().setBackupServiceActive(UserHandle.USER_SYSTEM, true);
    +@@ -5901,7 +6028,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
    +                     + " not installed for userId:" + userHandle);
    +         }
    +         synchronized (this) {
    +-            enforceCanSetProfileOwnerLocked(userHandle);
    ++            enforceCanSetProfileOwnerLocked(who, userHandle);
    + 
    +             if (getActiveAdminUncheckedLocked(who, userHandle) == null
    +                     || getUserData(userHandle).mRemovingAdmins.contains(who)) {
    +@@ -5910,6 +6037,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
    + 
    +             mOwners.setProfileOwner(who, ownerName, userHandle);
    +             mOwners.writeProfileOwner(userHandle);
    ++            Slog.i(LOG_TAG, "Profile owner set: " + who + " on user " + userHandle);
    +             return true;
    +         }
    +     }
    +@@ -5934,6 +6062,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
    +             } finally {
    +                 mInjector.binderRestoreCallingIdentity(ident);
    +             }
    ++            Slog.i(LOG_TAG, "Profile owner " + who + " removed from user " + userId);
    +         }
    +     }
    + 
    +@@ -6210,9 +6339,9 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
    +      * The profile owner can only be set before the user setup phase has completed,
    +      * except for:
    +      * - SYSTEM_UID
    +-     * - adb if there are not accounts.
    ++     * - adb if there are no accounts. (But see {@link #hasIncompatibleAccountsLocked})
    +      */
    +-    private void enforceCanSetProfileOwnerLocked(int userHandle) {
    ++    private void enforceCanSetProfileOwnerLocked(@Nullable ComponentName owner, int userHandle) {
    +         UserInfo info = getUserInfo(userHandle);
    +         if (info == null) {
    +             // User doesn't exist.
    +@@ -6232,8 +6361,8 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
    +         }
    +         int callingUid = mInjector.binderGetCallingUid();
    +         if (callingUid == Process.SHELL_UID || callingUid == Process.ROOT_UID) {
    +-            if (hasUserSetupCompleted(userHandle) &&
    +-                    AccountManager.get(mContext).getAccountsAsUser(userHandle).length > 0) {
    ++            if (hasUserSetupCompleted(userHandle)
    ++                    && hasIncompatibleAccountsLocked(userHandle, owner)) {
    +                 throw new IllegalStateException("Not allowed to set the profile owner because "
    +                         + "there are already some accounts on the profile");
    +             }
    +@@ -6250,14 +6379,14 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
    +      * The Device owner can only be set by adb or an app with the MANAGE_PROFILE_AND_DEVICE_OWNERS
    +      * permission.
    +      */
    +-    private void enforceCanSetDeviceOwnerLocked(int userId) {
    ++    private void enforceCanSetDeviceOwnerLocked(@Nullable ComponentName owner, int userId) {
    +         int callingUid = mInjector.binderGetCallingUid();
    +         boolean isAdb = callingUid == Process.SHELL_UID || callingUid == Process.ROOT_UID;
    +         if (!isAdb) {
    +             enforceCanManageProfileAndDeviceOwners();
    +         }
    + 
    +-        final int code = checkSetDeviceOwnerPreCondition(userId, isAdb);
    ++        final int code = checkSetDeviceOwnerPreConditionLocked(owner, userId, isAdb);
    +         switch (code) {
    +             case CODE_OK:
    +                 return;
    +@@ -8474,8 +8603,8 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
    +      * The device owner can only be set before the setup phase of the primary user has completed,
    +      * except for adb command if no accounts or additional users are present on the device.
    +      */
    +-    private synchronized @DeviceOwnerPreConditionCode int checkSetDeviceOwnerPreCondition(
    +-            int deviceOwnerUserId, boolean isAdb) {
    ++    private synchronized @DeviceOwnerPreConditionCode int checkSetDeviceOwnerPreConditionLocked(
    ++            @Nullable ComponentName owner, int deviceOwnerUserId, boolean isAdb) {
    +         if (mOwners.hasDeviceOwner()) {
    +             return CODE_HAS_DEVICE_OWNER;
    +         }
    +@@ -8492,7 +8621,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
    +                     if (mUserManager.getUserCount() > 1) {
    +                         return CODE_NONSYSTEM_USER_EXISTS;
    +                     }
    +-                    if (AccountManager.get(mContext).getAccounts().length > 0) {
    ++                    if (hasIncompatibleAccountsLocked(UserHandle.USER_SYSTEM, owner)) {
    +                         return CODE_ACCOUNTS_NOT_EMPTY;
    +                     }
    +                 } else {
    +@@ -8518,7 +8647,10 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
    +     }
    + 
    +     private boolean isDeviceOwnerProvisioningAllowed(int deviceOwnerUserId) {
    +-        return CODE_OK == checkSetDeviceOwnerPreCondition(deviceOwnerUserId, /* isAdb */ false);
    ++        synchronized (this) {
    ++            return CODE_OK == checkSetDeviceOwnerPreConditionLocked(
    ++                    /* owner unknown */ null, deviceOwnerUserId, /* isAdb */ false);
    ++        }
    +     }
    + 
    +     private boolean hasFeatureManagedUsers() {
    +@@ -8850,10 +8982,14 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
    +         return false;
    +     }
    + 
    +-    private synchronized void disableSecurityLoggingIfNotCompliant() {
    ++    private synchronized void disableDeviceOwnerManagedSingleUserFeaturesIfNeeded() {
    +         if (!isDeviceOwnerManagedSingleUserDevice()) {
    +             mInjector.securityLogSetLoggingEnabledProperty(false);
    +             Slog.w(LOG_TAG, "Security logging turned off as it's no longer a single user device.");
    ++            if (mOwners.hasDeviceOwner()) {
    ++                setBackupServiceEnabledInternal(false);
    ++                Slog.w(LOG_TAG, "Backup is off as it's a managed device that has more that one user.");
    ++            }
    +         }
    +     }
    + 
    +@@ -9051,6 +9187,8 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
    +             saveSettingsLocked(userHandle);
    +             updateMaximumTimeToLockLocked(userHandle);
    +             policy.mRemovingAdmins.remove(adminReceiver);
    ++
    ++            Slog.i(LOG_TAG, "Device admin " + adminReceiver + " removed from user " + userHandle);
    +         }
    +         // The removed admin might have disabled camera, so update user
    +         // restrictions.
    +@@ -9075,4 +9213,123 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
    +             return policy.mDeviceProvisioningConfigApplied;
    +         }
    +     }
    ++
    ++    /**
    ++     * Return true if a given user has any accounts that'll prevent installing a device or profile
    ++     * owner {@code owner}.
    ++     * - If the user has no accounts, then return false.
    ++     * - Otherwise, if the owner is unknown (== null), or is not test-only, then return true.
    ++     * - Otherwise, if there's any account that does not have ..._ALLOWED, or does have
    ++     *   ..._DISALLOWED, return true.
    ++     * - Otherwise return false.
    ++     */
    ++    private boolean hasIncompatibleAccountsLocked(int userId, @Nullable ComponentName owner) {
    ++        final long token = mInjector.binderClearCallingIdentity();
    ++        try {
    ++            final AccountManager am = AccountManager.get(mContext);
    ++            final Account accounts[] = am.getAccountsAsUser(userId);
    ++            if (accounts.length == 0) {
    ++                return false;
    ++            }
    ++            final String[] feature_allow =
    ++                    { DevicePolicyManager.ACCOUNT_FEATURE_DEVICE_OR_PROFILE_OWNER_ALLOWED };
    ++            final String[] feature_disallow =
    ++                    { DevicePolicyManager.ACCOUNT_FEATURE_DEVICE_OR_PROFILE_OWNER_DISALLOWED };
    ++
    ++            // Even if we find incompatible accounts along the way, we still check all accounts
    ++            // for logging.
    ++            boolean compatible = true;
    ++            for (Account account : accounts) {
    ++                if (hasAccountFeatures(am, account, feature_disallow)) {
    ++                    Log.e(LOG_TAG, account + " has " + feature_disallow[0]);
    ++                    compatible = false;
    ++                }
    ++                if (!hasAccountFeatures(am, account, feature_allow)) {
    ++                    Log.e(LOG_TAG, account + " doesn't have " + feature_allow[0]);
    ++                    compatible = false;
    ++                }
    ++            }
    ++            if (compatible) {
    ++                Log.w(LOG_TAG, "All accounts are compatible");
    ++            } else {
    ++                Log.e(LOG_TAG, "Found incompatible accounts");
    ++            }
    ++
    ++            // Then check if the owner is test-only.
    ++            String log;
    ++            if (owner == null) {
    ++                // Owner is unknown.  Suppose it's not test-only
    ++                compatible = false;
    ++                log = "Only test-only device/profile owner can be installed with accounts";
    ++            } else if (isAdminTestOnlyLocked(owner, userId)) {
    ++                if (compatible) {
    ++                    log = "Installing test-only owner " + owner;
    ++                } else {
    ++                    log = "Can't install test-only owner " + owner + " with incompatible accounts";
    ++                }
    ++            } else {
    ++                compatible = false;
    ++                log = "Can't install non test-only owner " + owner + " with accounts";
    ++            }
    ++            if (compatible) {
    ++                Log.w(LOG_TAG, log);
    ++            } else {
    ++                Log.e(LOG_TAG, log);
    ++            }
    ++            return !compatible;
    ++        } finally {
    ++            mInjector.binderRestoreCallingIdentity(token);
    ++        }
    ++    }
    ++
    ++    private boolean hasAccountFeatures(AccountManager am, Account account, String[] features) {
    ++        try {
    ++            return am.hasFeatures(account, features, null, null).getResult();
    ++        } catch (Exception e) {
    ++            Log.w(LOG_TAG, "Failed to get account feature", e);
    ++            return false;
    ++        }
    ++    }
    ++
    ++    @Override
    ++    public void setBackupServiceEnabled(ComponentName admin, boolean enabled) {
    ++        Preconditions.checkNotNull(admin);
    ++        if (!mHasFeature) {
    ++            return;
    ++        }
    ++        ensureDeviceOwnerManagingSingleUser(admin);
    ++        setBackupServiceEnabledInternal(enabled);
    ++    }
    ++
    ++    private synchronized void setBackupServiceEnabledInternal(boolean enabled) {
    ++        long ident = mInjector.binderClearCallingIdentity();
    ++        try {
    ++            IBackupManager ibm = mInjector.getIBackupManager();
    ++            if (ibm != null) {
    ++                ibm.setBackupServiceActive(UserHandle.USER_SYSTEM, enabled);
    ++            }
    ++        } catch (RemoteException e) {
    ++            throw new IllegalStateException(
    ++                "Failed " + (enabled ? "" : "de") + "activating backup service.", e);
    ++        } finally {
    ++            mInjector.binderRestoreCallingIdentity(ident);
    ++        }
    ++    }
    ++
    ++    @Override
    ++    public boolean isBackupServiceEnabled(ComponentName admin) {
    ++        Preconditions.checkNotNull(admin);
    ++        if (!mHasFeature) {
    ++            return true;
    ++        }
    ++        synchronized (this) {
    ++            getActiveAdminForCallerLocked(admin, DeviceAdminInfo.USES_POLICY_DEVICE_OWNER);
    ++            try {
    ++                IBackupManager ibm = mInjector.getIBackupManager();
    ++                return ibm != null && ibm.isBackupServiceActive(UserHandle.USER_SYSTEM);
    ++            } catch (RemoteException e) {
    ++                throw new IllegalStateException("Failed requesting backup service state.", e);
    ++            }
    ++        }
    ++    }
    + }
    +diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
    +index 97a829e..7ebdd31 100644
    +--- a/services/java/com/android/server/SystemServer.java
    ++++ b/services/java/com/android/server/SystemServer.java
    +@@ -16,7 +16,6 @@
    + 
    + package com.android.server;
    + 
    +-import android.app.ActivityManagerNative;
    + import android.app.ActivityThread;
    + import android.app.INotificationManager;
    + import android.app.usage.UsageStatsManagerInternal;
    +@@ -32,7 +31,6 @@ import android.os.Build;
    + import android.os.Environment;
    + import android.os.FactoryTest;
    + import android.os.FileUtils;
    +-import android.os.IPowerManager;
    + import android.os.Looper;
    + import android.os.PowerManager;
    + import android.os.RemoteException;
    +@@ -55,17 +53,20 @@ import com.android.internal.app.NightDisplayController;
    + import com.android.internal.os.BinderInternal;
    + import com.android.internal.os.SamplingProfilerIntegration;
    + import com.android.internal.os.ZygoteInit;
    ++import com.android.internal.policy.EmergencyAffordanceManager;
    + import com.android.internal.widget.ILockSettings;
    + import com.android.server.accessibility.AccessibilityManagerService;
    + import com.android.server.am.ActivityManagerService;
    + import com.android.server.audio.AudioService;
    + import com.android.server.camera.CameraService;
    + import com.android.server.clipboard.ClipboardService;
    ++import com.android.server.connectivity.IpConnectivityMetrics;
    + import com.android.server.connectivity.MetricsLoggerService;
    + import com.android.server.devicepolicy.DevicePolicyManagerService;
    + import com.android.server.display.DisplayManagerService;
    + import com.android.server.display.NightDisplayService;
    + import com.android.server.dreams.DreamManagerService;
    ++import com.android.server.emergency.EmergencyAffordanceService;
    + import com.android.server.fingerprint.FingerprintService;
    + import com.android.server.hdmi.HdmiControlService;
    + import com.android.server.input.InputManagerService;
    +@@ -653,6 +654,10 @@ public final class SystemServer {
    +             mSystemServiceManager.startService(MetricsLoggerService.class);
    +             Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
    + 
    ++            traceBeginAndSlog("IpConnectivityMetrics");
    ++            mSystemServiceManager.startService(IpConnectivityMetrics.class);
    ++            Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
    ++
    +             traceBeginAndSlog("PinnerService");
    +             mSystemServiceManager.startService(PinnerService.class);
    +             Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
    +@@ -1080,6 +1085,11 @@ public final class SystemServer {
    +                 Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
    +             }
    + 
    ++            if (!disableNetwork && !disableNonCoreServices && EmergencyAffordanceManager.ENABLED) {
    ++                // EmergencyMode sevice
    ++                mSystemServiceManager.startService(EmergencyAffordanceService.class);
    ++            }
    ++
    +             if (!disableNonCoreServices) {
    +                 // Dreams (interactive idle-time views, a/k/a screen savers, and doze mode)
    +                 mSystemServiceManager.startService(DreamManagerService.class);
    +diff --git a/services/net/Android.mk b/services/net/Android.mk
    +index 336bc45..408794e 100644
    +--- a/services/net/Android.mk
    ++++ b/services/net/Android.mk
    +@@ -7,4 +7,7 @@ LOCAL_MODULE := services.net
    + LOCAL_SRC_FILES += \
    +     $(call all-java-files-under,java)
    + 
    ++LOCAL_AIDL_INCLUDES += \
    ++    system/netd/server/binder
    ++
    + include $(BUILD_STATIC_JAVA_LIBRARY)
    +diff --git a/services/net/java/android/net/apf/ApfFilter.java b/services/net/java/android/net/apf/ApfFilter.java
    +index 4bb0902..4c75452 100644
    +--- a/services/net/java/android/net/apf/ApfFilter.java
    ++++ b/services/net/java/android/net/apf/ApfFilter.java
    +@@ -19,6 +19,7 @@ package android.net.apf;
    + import static android.system.OsConstants.*;
    + 
    + import android.os.SystemClock;
    ++import android.net.LinkAddress;
    + import android.net.LinkProperties;
    + import android.net.NetworkUtils;
    + import android.net.apf.ApfGenerator;
    +@@ -44,6 +45,7 @@ import com.android.internal.util.IndentingPrintWriter;
    + import java.io.FileDescriptor;
    + import java.io.IOException;
    + import java.lang.Thread;
    ++import java.net.Inet4Address;
    + import java.net.Inet6Address;
    + import java.net.InetAddress;
    + import java.net.NetworkInterface;
    +@@ -171,8 +173,8 @@ public class ApfFilter {
    +     private static final int ETH_HEADER_LEN = 14;
    +     private static final int ETH_DEST_ADDR_OFFSET = 0;
    +     private static final int ETH_ETHERTYPE_OFFSET = 12;
    +-    private static final byte[] ETH_BROADCAST_MAC_ADDRESS = new byte[]{
    +-            (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff };
    ++    private static final byte[] ETH_BROADCAST_MAC_ADDRESS =
    ++            {(byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff };
    +     // TODO: Make these offsets relative to end of link-layer header; don't include ETH_HEADER_LEN.
    +     private static final int IPV4_FRAGMENT_OFFSET_OFFSET = ETH_HEADER_LEN + 6;
    +     // Endianness is not an issue for this constant because the APF interpreter always operates in
    +@@ -181,6 +183,7 @@ public class ApfFilter {
    +     private static final int IPV4_PROTOCOL_OFFSET = ETH_HEADER_LEN + 9;
    +     private static final int IPV4_DEST_ADDR_OFFSET = ETH_HEADER_LEN + 16;
    +     private static final int IPV4_ANY_HOST_ADDRESS = 0;
    ++    private static final int IPV4_BROADCAST_ADDRESS = -1; // 255.255.255.255
    + 
    +     private static final int IPV6_NEXT_HEADER_OFFSET = ETH_HEADER_LEN + 6;
    +     private static final int IPV6_SRC_ADDR_OFFSET = ETH_HEADER_LEN + 8;
    +@@ -188,7 +191,7 @@ public class ApfFilter {
    +     private static final int IPV6_HEADER_LEN = 40;
    +     // The IPv6 all nodes address ff02::1
    +     private static final byte[] IPV6_ALL_NODES_ADDRESS =
    +-            new byte[]{ (byte) 0xff, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 };
    ++            { (byte) 0xff, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 };
    + 
    +     private static final int ICMP6_TYPE_OFFSET = ETH_HEADER_LEN + IPV6_HEADER_LEN;
    +     private static final int ICMP6_NEIGHBOR_ANNOUNCEMENT = 136;
    +@@ -206,7 +209,7 @@ public class ApfFilter {
    +     private static final int ARP_OPCODE_OFFSET = ARP_HEADER_OFFSET + 6;
    +     private static final short ARP_OPCODE_REQUEST = 1;
    +     private static final short ARP_OPCODE_REPLY = 2;
    +-    private static final byte[] ARP_IPV4_HEADER = new byte[]{
    ++    private static final byte[] ARP_IPV4_HEADER = {
    +             0, 1, // Hardware type: Ethernet (1)
    +             8, 0, // Protocol type: IP (0x0800)
    +             6,    // Hardware size: 6
    +@@ -229,6 +232,9 @@ public class ApfFilter {
    +     // Our IPv4 address, if we have just one, otherwise null.
    +     @GuardedBy("this")
    +     private byte[] mIPv4Address;
    ++    // The subnet prefix length of our IPv4 network. Only valid if mIPv4Address is not null.
    ++    @GuardedBy("this")
    ++    private int mIPv4PrefixLength;
    + 
    +     @VisibleForTesting
    +     ApfFilter(ApfCapabilities apfCapabilities, NetworkInterface networkInterface,
    +@@ -364,26 +370,6 @@ public class ApfFilter {
    + 
    +         // Can't be static because it's in a non-static inner class.
    +         // TODO: Make this static once RA is its own class.
    +-        private int uint8(byte b) {
    +-            return b & 0xff;
    +-        }
    +-
    +-        private int uint16(short s) {
    +-            return s & 0xffff;
    +-        }
    +-
    +-        private long uint32(int i) {
    +-            return i & 0xffffffffL;
    +-        }
    +-
    +-        private long getUint16(ByteBuffer buffer, int position) {
    +-            return uint16(buffer.getShort(position));
    +-        }
    +-
    +-        private long getUint32(ByteBuffer buffer, int position) {
    +-            return uint32(buffer.getInt(position));
    +-        }
    +-
    +         private void prefixOptionToString(StringBuffer sb, int offset) {
    +             String prefix = IPv6AddresstoString(offset + 16);
    +             int length = uint8(mPacket.get(offset + 2));
    +@@ -737,39 +723,57 @@ public class ApfFilter {
    +         // Here's a basic summary of what the IPv4 filter program does:
    +         //
    +         // if filtering multicast (i.e. multicast lock not held):
    +-        //   if it's multicast:
    +-        //     drop
    +-        //   if it's not broadcast:
    ++        //   if it's DHCP destined to our MAC:
    +         //     pass
    +-        //   if it's not DHCP destined to our MAC:
    ++        //   if it's L2 broadcast:
    ++        //     drop
    ++        //   if it's IPv4 multicast:
    ++        //     drop
    ++        //   if it's IPv4 broadcast:
    +         //     drop
    +         // pass
    + 
    +         if (mMulticastFilter) {
    +-            // Check for multicast destination address range
    +-            gen.addLoad8(Register.R0, IPV4_DEST_ADDR_OFFSET);
    +-            gen.addAnd(0xf0);
    +-            gen.addJumpIfR0Equals(0xe0, gen.DROP_LABEL);
    ++            final String skipDhcpv4Filter = "skip_dhcp_v4_filter";
    + 
    +-            // Drop all broadcasts besides DHCP addressed to us
    +-            // If not a broadcast packet, pass
    +-            gen.addLoadImmediate(Register.R0, ETH_DEST_ADDR_OFFSET);
    +-            gen.addJumpIfBytesNotEqual(Register.R0, ETH_BROADCAST_MAC_ADDRESS, gen.PASS_LABEL);
    +-            // If not UDP, drop
    ++            // Pass DHCP addressed to us.
    ++            // Check it's UDP.
    +             gen.addLoad8(Register.R0, IPV4_PROTOCOL_OFFSET);
    +-            gen.addJumpIfR0NotEquals(IPPROTO_UDP, gen.DROP_LABEL);
    +-            // If fragment, drop. This matches the BPF filter installed by the DHCP client.
    ++            gen.addJumpIfR0NotEquals(IPPROTO_UDP, skipDhcpv4Filter);
    ++            // Check it's not a fragment. This matches the BPF filter installed by the DHCP client.
    +             gen.addLoad16(Register.R0, IPV4_FRAGMENT_OFFSET_OFFSET);
    +-            gen.addJumpIfR0AnyBitsSet(IPV4_FRAGMENT_OFFSET_MASK, gen.DROP_LABEL);
    +-            // If not to DHCP client port, drop
    ++            gen.addJumpIfR0AnyBitsSet(IPV4_FRAGMENT_OFFSET_MASK, skipDhcpv4Filter);
    ++            // Check it's addressed to DHCP client port.
    +             gen.addLoadFromMemory(Register.R1, gen.IPV4_HEADER_SIZE_MEMORY_SLOT);
    +             gen.addLoad16Indexed(Register.R0, UDP_DESTINATION_PORT_OFFSET);
    +-            gen.addJumpIfR0NotEquals(DHCP_CLIENT_PORT, gen.DROP_LABEL);
    +-            // If not DHCP to our MAC address, drop
    ++            gen.addJumpIfR0NotEquals(DHCP_CLIENT_PORT, skipDhcpv4Filter);
    ++            // Check it's DHCP to our MAC address.
    +             gen.addLoadImmediate(Register.R0, DHCP_CLIENT_MAC_OFFSET);
    +             // NOTE: Relies on R1 containing IPv4 header offset.
    +             gen.addAddR1();
    +-            gen.addJumpIfBytesNotEqual(Register.R0, mHardwareAddress, gen.DROP_LABEL);
    ++            gen.addJumpIfBytesNotEqual(Register.R0, mHardwareAddress, skipDhcpv4Filter);
    ++            gen.addJump(gen.PASS_LABEL);
    ++
    ++            // Drop all multicasts/broadcasts.
    ++            gen.defineLabel(skipDhcpv4Filter);
    ++
    ++            // If IPv4 destination address is in multicast range, drop.
    ++            gen.addLoad8(Register.R0, IPV4_DEST_ADDR_OFFSET);
    ++            gen.addAnd(0xf0);
    ++            gen.addJumpIfR0Equals(0xe0, gen.DROP_LABEL);
    ++
    ++            // If IPv4 broadcast packet, drop regardless of L2 (b/30231088).
    ++            gen.addLoad32(Register.R0, IPV4_DEST_ADDR_OFFSET);
    ++            gen.addJumpIfR0Equals(IPV4_BROADCAST_ADDRESS, gen.DROP_LABEL);
    ++            if (mIPv4Address != null && mIPv4PrefixLength < 31) {
    ++                int broadcastAddr = ipv4BroadcastAddress(mIPv4Address, mIPv4PrefixLength);
    ++                gen.addJumpIfR0Equals(broadcastAddr, gen.DROP_LABEL);
    ++            }
    ++
    ++            // If L2 broadcast packet, drop.
    ++            gen.addLoadImmediate(Register.R0, ETH_DEST_ADDR_OFFSET);
    ++            gen.addJumpIfBytesNotEqual(Register.R0, ETH_BROADCAST_MAC_ADDRESS, gen.PASS_LABEL);
    ++            gen.addJump(gen.DROP_LABEL);
    +         }
    + 
    +         // Otherwise, pass
    +@@ -1062,26 +1066,32 @@ public class ApfFilter {
    +         }
    +     }
    + 
    +-    // Find the single IPv4 address if there is one, otherwise return null.
    +-    private static byte[] findIPv4Address(LinkProperties lp) {
    +-        byte[] ipv4Address = null;
    +-        for (InetAddress inetAddr : lp.getAddresses()) {
    +-            byte[] addr = inetAddr.getAddress();
    +-            if (addr.length != 4) continue;
    +-            // More than one IPv4 address, abort
    +-            if (ipv4Address != null && !Arrays.equals(ipv4Address, addr)) return null;
    +-            ipv4Address = addr;
    ++    /** Find the single IPv4 LinkAddress if there is one, otherwise return null. */
    ++    private static LinkAddress findIPv4LinkAddress(LinkProperties lp) {
    ++        LinkAddress ipv4Address = null;
    ++        for (LinkAddress address : lp.getLinkAddresses()) {
    ++            if (!(address.getAddress() instanceof Inet4Address)) {
    ++                continue;
    ++            }
    ++            if (ipv4Address != null && !ipv4Address.isSameAddressAs(address)) {
    ++                // More than one IPv4 address, abort.
    ++                return null;
    ++            }
    ++            ipv4Address = address;
    +         }
    +         return ipv4Address;
    +     }
    + 
    +     public synchronized void setLinkProperties(LinkProperties lp) {
    +         // NOTE: Do not keep a copy of LinkProperties as it would further duplicate state.
    +-        byte[] ipv4Address = findIPv4Address(lp);
    +-        // If ipv4Address is the same as mIPv4Address, then there's no change, just return.
    +-        if (Arrays.equals(ipv4Address, mIPv4Address)) return;
    +-        // Otherwise update mIPv4Address and install new program.
    +-        mIPv4Address = ipv4Address;
    ++        final LinkAddress ipv4Address = findIPv4LinkAddress(lp);
    ++        final byte[] addr = (ipv4Address != null) ? ipv4Address.getAddress().getAddress() : null;
    ++        final int prefix = (ipv4Address != null) ? ipv4Address.getPrefixLength() : 0;
    ++        if ((prefix == mIPv4PrefixLength) && Arrays.equals(addr, mIPv4Address)) {
    ++            return;
    ++        }
    ++        mIPv4Address = addr;
    ++        mIPv4PrefixLength = prefix;
    +         installNewProgramLocked();
    +     }
    + 
    +@@ -1127,4 +1137,38 @@ public class ApfFilter {
    +             pw.decreaseIndent();
    +         }
    +     }
    ++
    ++    private static int uint8(byte b) {
    ++        return b & 0xff;
    ++    }
    ++
    ++    private static int uint16(short s) {
    ++        return s & 0xffff;
    ++    }
    ++
    ++    private static long uint32(int i) {
    ++        return i & 0xffffffffL;
    ++    }
    ++
    ++    private static long getUint16(ByteBuffer buffer, int position) {
    ++        return uint16(buffer.getShort(position));
    ++    }
    ++
    ++    private static long getUint32(ByteBuffer buffer, int position) {
    ++        return uint32(buffer.getInt(position));
    ++    }
    ++
    ++    // TODO: move to android.net.NetworkUtils
    ++    @VisibleForTesting
    ++    public static int ipv4BroadcastAddress(byte[] addrBytes, int prefixLength) {
    ++        return bytesToInt(addrBytes) | (int) (uint32(-1) >>> prefixLength);
    ++    }
    ++
    ++    @VisibleForTesting
    ++    public static int bytesToInt(byte[] addrBytes) {
    ++        return (uint8(addrBytes[0]) << 24)
    ++                + (uint8(addrBytes[1]) << 16)
    ++                + (uint8(addrBytes[2]) << 8)
    ++                + (uint8(addrBytes[3]));
    ++    }
    + }
    +diff --git a/services/net/java/android/net/dhcp/DhcpPacket.java b/services/net/java/android/net/dhcp/DhcpPacket.java
    +index 9aa66fe..ef4bc02 100644
    +--- a/services/net/java/android/net/dhcp/DhcpPacket.java
    ++++ b/services/net/java/android/net/dhcp/DhcpPacket.java
    +@@ -7,6 +7,7 @@ import android.net.metrics.DhcpErrorEvent;
    + import android.os.Build;
    + import android.os.SystemProperties;
    + import android.system.OsConstants;
    ++import com.android.internal.annotations.VisibleForTesting;
    + 
    + import java.io.UnsupportedEncodingException;
    + import java.net.Inet4Address;
    +@@ -14,9 +15,8 @@ import java.net.UnknownHostException;
    + import java.nio.BufferUnderflowException;
    + import java.nio.ByteBuffer;
    + import java.nio.ByteOrder;
    +-import java.nio.charset.StandardCharsets;
    + import java.nio.ShortBuffer;
    +-
    ++import java.nio.charset.StandardCharsets;
    + import java.util.ArrayList;
    + import java.util.Arrays;
    + import java.util.List;
    +@@ -725,7 +725,8 @@ abstract class DhcpPacket {
    +      * A subset of the optional parameters are parsed and are stored
    +      * in object fields.
    +      */
    +-    public static DhcpPacket decodeFullPacket(ByteBuffer packet, int pktType) throws ParseException
    ++    @VisibleForTesting
    ++    static DhcpPacket decodeFullPacket(ByteBuffer packet, int pktType) throws ParseException
    +     {
    +         // bootp parameters
    +         int transactionId;
    +@@ -894,8 +895,12 @@ abstract class DhcpPacket {
    +                         + 64    // skip server host name (64 chars)
    +                         + 128); // skip boot file name (128 chars)
    + 
    +-        int dhcpMagicCookie = packet.getInt();
    ++        // Ensure this is a DHCP packet with a magic cookie, and not BOOTP. http://b/31850211
    ++        if (packet.remaining() < 4) {
    ++            throw new ParseException(DhcpErrorEvent.DHCP_NO_COOKIE, "not a DHCP message");
    ++        }
    + 
    ++        int dhcpMagicCookie = packet.getInt();
    +         if (dhcpMagicCookie != DHCP_MAGIC_COOKIE) {
    +             throw new ParseException(DhcpErrorEvent.DHCP_BAD_MAGIC_COOKIE,
    +                     "Bad magic cookie 0x%08x, should be 0x%08x",
    +@@ -1090,7 +1095,13 @@ abstract class DhcpPacket {
    +     public static DhcpPacket decodeFullPacket(byte[] packet, int length, int pktType)
    +             throws ParseException {
    +         ByteBuffer buffer = ByteBuffer.wrap(packet, 0, length).order(ByteOrder.BIG_ENDIAN);
    +-        return decodeFullPacket(buffer, pktType);
    ++        try {
    ++            return decodeFullPacket(buffer, pktType);
    ++        } catch (ParseException e) {
    ++            throw e;
    ++        } catch (Exception e) {
    ++            throw new ParseException(DhcpErrorEvent.PARSING_ERROR, e.getMessage());
    ++        }
    +     }
    + 
    +     /**
    +diff --git a/services/net/java/android/net/ip/IpManager.java b/services/net/java/android/net/ip/IpManager.java
    +index d0ab606..01d9304 100644
    +--- a/services/net/java/android/net/ip/IpManager.java
    ++++ b/services/net/java/android/net/ip/IpManager.java
    +@@ -46,6 +46,7 @@ import android.util.SparseArray;
    + 
    + import com.android.internal.annotations.VisibleForTesting;
    + import com.android.internal.util.IndentingPrintWriter;
    ++import com.android.internal.util.IState;
    + import com.android.internal.util.State;
    + import com.android.internal.util.StateMachine;
    + import com.android.server.net.NetlinkTracker;
    +@@ -358,6 +359,7 @@ public class IpManager extends StateMachine {
    +     }
    + 
    +     public static final String DUMP_ARG = "ipmanager";
    ++    public static final String DUMP_ARG_CONFIRM = "confirm";
    + 
    +     private static final int CMD_STOP = 1;
    +     private static final int CMD_START = 2;
    +@@ -383,6 +385,7 @@ public class IpManager extends StateMachine {
    +     private final State mStoppedState = new StoppedState();
    +     private final State mStoppingState = new StoppingState();
    +     private final State mStartedState = new StartedState();
    ++    private final State mRunningState = new RunningState();
    + 
    +     private final String mTag;
    +     private final Context mContext;
    +@@ -396,6 +399,7 @@ public class IpManager extends StateMachine {
    +     private final WakeupMessage mDhcpActionTimeoutAlarm;
    +     private final AvoidBadWifiTracker mAvoidBadWifiTracker;
    +     private final LocalLog mLocalLog;
    ++    private final MessageHandlingLogger mMsgStateLogger;
    +     private final IpConnectivityLog mMetricsLog = new IpConnectivityLog();
    + 
    +     private NetworkInterface mNetworkInterface;
    +@@ -480,10 +484,12 @@ public class IpManager extends StateMachine {
    +         // Super simple StateMachine.
    +         addState(mStoppedState);
    +         addState(mStartedState);
    ++            addState(mRunningState, mStartedState);
    +         addState(mStoppingState);
    + 
    +         setInitialState(mStoppedState);
    +         mLocalLog = new LocalLog(MAX_LOG_RECORDS);
    ++        mMsgStateLogger = new MessageHandlingLogger();
    +         super.start();
    +     }
    + 
    +@@ -561,6 +567,12 @@ public class IpManager extends StateMachine {
    +     }
    + 
    +     public void dump(FileDescriptor fd, PrintWriter writer, String[] args) {
    ++        if (args.length > 0 && DUMP_ARG_CONFIRM.equals(args[0])) {
    ++            // Execute confirmConfiguration() and take no further action.
    ++            confirmConfiguration();
    ++            return;
    ++        }
    ++
    +         IndentingPrintWriter pw = new IndentingPrintWriter(writer, "  ");
    +         pw.println("APF dump:");
    +         pw.increaseIndent();
    +@@ -574,7 +586,7 @@ public class IpManager extends StateMachine {
    +         pw.decreaseIndent();
    + 
    +         pw.println();
    +-        pw.println("StateMachine dump:");
    ++        pw.println(mTag + " StateMachine dump:");
    +         pw.increaseIndent();
    +         mLocalLog.readOnlyLocalLog().dump(fd, pw, args);
    +         pw.decreaseIndent();
    +@@ -593,9 +605,9 @@ public class IpManager extends StateMachine {
    +     @Override
    +     protected String getLogRecString(Message msg) {
    +         final String logLine = String.format(
    +-                "%s/%d %d %d %s",
    ++                "%s/%d %d %d %s [%s]",
    +                 mInterfaceName, mNetworkInterface == null ? -1 : mNetworkInterface.getIndex(),
    +-                msg.arg1, msg.arg2, Objects.toString(msg.obj));
    ++                msg.arg1, msg.arg2, Objects.toString(msg.obj), mMsgStateLogger);
    + 
    +         final String richerLogLine = getWhatToString(msg.what) + " " + logLine;
    +         mLocalLog.log(richerLogLine);
    +@@ -603,6 +615,7 @@ public class IpManager extends StateMachine {
    +             Log.d(mTag, richerLogLine);
    +         }
    + 
    ++        mMsgStateLogger.reset();
    +         return logLine;
    +     }
    + 
    +@@ -611,7 +624,11 @@ public class IpManager extends StateMachine {
    +         // Don't log EVENT_NETLINK_LINKPROPERTIES_CHANGED. They can be noisy,
    +         // and we already log any LinkProperties change that results in an
    +         // invocation of IpManager.Callback#onLinkPropertiesChange().
    +-        return (msg.what != EVENT_NETLINK_LINKPROPERTIES_CHANGED);
    ++        final boolean shouldLog = (msg.what != EVENT_NETLINK_LINKPROPERTIES_CHANGED);
    ++        if (!shouldLog) {
    ++            mMsgStateLogger.reset();
    ++        }
    ++        return shouldLog;
    +     }
    + 
    +     private void getNetworkInterface() {
    +@@ -789,6 +806,11 @@ public class IpManager extends StateMachine {
    +         //         - IPv6 addresses
    +         //         - IPv6 routes
    +         //         - IPv6 DNS servers
    ++        //
    ++        // N.B.: this is fundamentally race-prone and should be fixed by
    ++        // changing NetlinkTracker from a hybrid edge/level model to an
    ++        // edge-only model, or by giving IpManager its own netlink socket(s)
    ++        // so as to track all required information directly.
    +         LinkProperties netlinkLinkProperties = mNetlinkTracker.getLinkProperties();
    +         newLp.setLinkAddresses(netlinkLinkProperties.getLinkAddresses());
    +         for (RouteInfo route : netlinkLinkProperties.getRoutes()) {
    +@@ -960,16 +982,29 @@ public class IpManager extends StateMachine {
    +         return true;
    +     }
    + 
    ++    private void stopAllIP() {
    ++        // We don't need to worry about routes, just addresses, because:
    ++        //     - disableIpv6() will clear autoconf IPv6 routes as well, and
    ++        //     - we don't get IPv4 routes from netlink
    ++        // so we neither react to nor need to wait for changes in either.
    ++
    ++        try {
    ++            mNwService.disableIpv6(mInterfaceName);
    ++        } catch (Exception e) {
    ++            Log.e(mTag, "Failed to disable IPv6" + e);
    ++        }
    ++
    ++        try {
    ++            mNwService.clearInterfaceAddresses(mInterfaceName);
    ++        } catch (Exception e) {
    ++            Log.e(mTag, "Failed to clear addresses " + e);
    ++        }
    ++    }
    + 
    +     class StoppedState extends State {
    +         @Override
    +         public void enter() {
    +-            try {
    +-                mNwService.disableIpv6(mInterfaceName);
    +-                mNwService.clearInterfaceAddresses(mInterfaceName);
    +-            } catch (Exception e) {
    +-                Log.e(mTag, "Failed to clear addresses or disable IPv6" + e);
    +-            }
    ++            stopAllIP();
    + 
    +             resetLinkProperties();
    +             if (mStartTimeMillis > 0) {
    +@@ -1015,6 +1050,8 @@ public class IpManager extends StateMachine {
    +                 default:
    +                     return NOT_HANDLED;
    +             }
    ++
    ++            mMsgStateLogger.handled(this, getCurrentState());
    +             return HANDLED;
    +         }
    +     }
    +@@ -1031,6 +1068,13 @@ public class IpManager extends StateMachine {
    +         @Override
    +         public boolean processMessage(Message msg) {
    +             switch (msg.what) {
    ++                case CMD_STOP:
    ++                    break;
    ++
    ++                case DhcpClient.CMD_CLEAR_LINKADDRESS:
    ++                    clearIPv4Address();
    ++                    break;
    ++
    +                 case DhcpClient.CMD_ON_QUIT:
    +                     mDhcpClient = null;
    +                     transitionTo(mStoppedState);
    +@@ -1039,17 +1083,80 @@ public class IpManager extends StateMachine {
    +                 default:
    +                     deferMessage(msg);
    +             }
    ++
    ++            mMsgStateLogger.handled(this, getCurrentState());
    +             return HANDLED;
    +         }
    +     }
    + 
    +     class StartedState extends State {
    +-        private boolean mDhcpActionInFlight;
    +-
    +         @Override
    +         public void enter() {
    +             mStartTimeMillis = SystemClock.elapsedRealtime();
    + 
    ++            if (mConfiguration.mProvisioningTimeoutMs > 0) {
    ++                final long alarmTime = SystemClock.elapsedRealtime() +
    ++                        mConfiguration.mProvisioningTimeoutMs;
    ++                mProvisioningTimeoutAlarm.schedule(alarmTime);
    ++            }
    ++
    ++            if (readyToProceed()) {
    ++                transitionTo(mRunningState);
    ++            } else {
    ++                // Clear all IPv4 and IPv6 before proceeding to RunningState.
    ++                // Clean up any leftover state from an abnormal exit from
    ++                // tethering or during an IpManager restart.
    ++                stopAllIP();
    ++            }
    ++        }
    ++
    ++        @Override
    ++        public void exit() {
    ++            mProvisioningTimeoutAlarm.cancel();
    ++        }
    ++
    ++        @Override
    ++        public boolean processMessage(Message msg) {
    ++            switch (msg.what) {
    ++                case CMD_STOP:
    ++                    transitionTo(mStoppingState);
    ++                    break;
    ++
    ++                case EVENT_NETLINK_LINKPROPERTIES_CHANGED:
    ++                    handleLinkPropertiesUpdate(NO_CALLBACKS);
    ++                    if (readyToProceed()) {
    ++                        transitionTo(mRunningState);
    ++                    }
    ++                    break;
    ++
    ++                case EVENT_PROVISIONING_TIMEOUT:
    ++                    handleProvisioningFailure();
    ++                    break;
    ++
    ++                default:
    ++                    // It's safe to process messages out of order because the
    ++                    // only message that can both
    ++                    //     a) be received at this time and
    ++                    //     b) affect provisioning state
    ++                    // is EVENT_NETLINK_LINKPROPERTIES_CHANGED (handled above).
    ++                    deferMessage(msg);
    ++            }
    ++
    ++            mMsgStateLogger.handled(this, getCurrentState());
    ++            return HANDLED;
    ++        }
    ++
    ++        boolean readyToProceed() {
    ++            return (!mLinkProperties.hasIPv4Address() &&
    ++                    !mLinkProperties.hasGlobalIPv6Address());
    ++        }
    ++    }
    ++
    ++    class RunningState extends State {
    ++        private boolean mDhcpActionInFlight;
    ++
    ++        @Override
    ++        public void enter() {
    +             mApfFilter = ApfFilter.maybeCreate(mConfiguration.mApfCapabilities, mNetworkInterface,
    +                     mCallback, mMulticastFiltering);
    +             // TODO: investigate the effects of any multicast filtering racing/interfering with the
    +@@ -1058,12 +1165,6 @@ public class IpManager extends StateMachine {
    +                 mCallback.setFallbackMulticastFilter(mMulticastFiltering);
    +             }
    + 
    +-            if (mConfiguration.mProvisioningTimeoutMs > 0) {
    +-                final long alarmTime = SystemClock.elapsedRealtime() +
    +-                        mConfiguration.mProvisioningTimeoutMs;
    +-                mProvisioningTimeoutAlarm.schedule(alarmTime);
    +-            }
    +-
    +             if (mConfiguration.mEnableIPv6) {
    +                 // TODO: Consider transitionTo(mStoppingState) if this fails.
    +                 startIPv6();
    +@@ -1092,7 +1193,6 @@ public class IpManager extends StateMachine {
    + 
    +         @Override
    +         public void exit() {
    +-            mProvisioningTimeoutAlarm.cancel();
    +             stopDhcpAction();
    + 
    +             if (mIpReachabilityMonitor != null) {
    +@@ -1189,10 +1289,6 @@ public class IpManager extends StateMachine {
    +                     break;
    +                 }
    + 
    +-                case EVENT_PROVISIONING_TIMEOUT:
    +-                    handleProvisioningFailure();
    +-                    break;
    +-
    +                 case EVENT_DHCPACTION_TIMEOUT:
    +                     stopDhcpAction();
    +                     break;
    +@@ -1255,7 +1351,29 @@ public class IpManager extends StateMachine {
    +                 default:
    +                     return NOT_HANDLED;
    +             }
    ++
    ++            mMsgStateLogger.handled(this, getCurrentState());
    +             return HANDLED;
    +         }
    +     }
    ++
    ++    private static class MessageHandlingLogger {
    ++        public String processedInState;
    ++        public String receivedInState;
    ++
    ++        public void reset() {
    ++            processedInState = null;
    ++            receivedInState = null;
    ++        }
    ++
    ++        public void handled(State processedIn, IState receivedIn) {
    ++            processedInState = processedIn.getClass().getSimpleName();
    ++            receivedInState = receivedIn.getName();
    ++        }
    ++
    ++        public String toString() {
    ++            return String.format("rcvd_in=%s, proc_in=%s",
    ++                                 receivedInState, processedInState);
    ++        }
    ++    }
    + }
    +diff --git a/services/net/java/android/net/util/NetdService.java b/services/net/java/android/net/util/NetdService.java
    +new file mode 100644
    +index 0000000..153cb50
    +--- /dev/null
    ++++ b/services/net/java/android/net/util/NetdService.java
    +@@ -0,0 +1,46 @@
    ++/*
    ++ * Copyright (C) 2016 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 android.net.util;
    ++
    ++import android.net.INetd;
    ++import android.os.ServiceManager;
    ++import android.util.Log;
    ++
    ++
    ++/**
    ++ * @hide
    ++ */
    ++public class NetdService {
    ++    private static final String TAG = NetdService.class.getSimpleName();
    ++    private static final String NETD_SERVICE_NAME = "netd";
    ++
    ++    /**
    ++     * It is the caller's responsibility to check for a null return value
    ++     * and to handle RemoteException errors from invocations on the returned
    ++     * interface if, for example, netd dies and is restarted.
    ++     *
    ++     * @return an INetd instance or null.
    ++     */
    ++    public static INetd getInstance() {
    ++        final INetd netdInstance = INetd.Stub.asInterface(
    ++                ServiceManager.getService(NETD_SERVICE_NAME));
    ++        if (netdInstance == null) {
    ++            Log.w(TAG, "WARNING: returning null INetd instance.");
    ++        }
    ++        return netdInstance;
    ++    }
    ++}
    +diff --git a/services/print/java/com/android/server/print/RemotePrintSpooler.java b/services/print/java/com/android/server/print/RemotePrintSpooler.java
    +index 07cc9c0..07b26e8 100644
    +--- a/services/print/java/com/android/server/print/RemotePrintSpooler.java
    ++++ b/services/print/java/com/android/server/print/RemotePrintSpooler.java
    +@@ -57,6 +57,9 @@ import java.util.concurrent.TimeoutException;
    +  * spooler if needed, to make the timed remote calls, to handle
    +  * remote exceptions, and to bind/unbind to the remote instance as
    +  * needed.
    ++ *
    ++ * The calls might be blocking and need the main thread of to be unblocked to finish. Hence do not
    ++ * call this while holding any monitors that might need to be acquired the main thread.
    +  */
    + final class RemotePrintSpooler {
    + 
    +diff --git a/services/print/java/com/android/server/print/UserState.java b/services/print/java/com/android/server/print/UserState.java
    +index 05301c1..a91cdb3 100644
    +--- a/services/print/java/com/android/server/print/UserState.java
    ++++ b/services/print/java/com/android/server/print/UserState.java
    +@@ -434,12 +434,12 @@ final class UserState implements PrintSpoolerCallbacks, PrintServiceCallbacks,
    +     }
    + 
    +     public void createPrinterDiscoverySession(@NonNull IPrinterDiscoveryObserver observer) {
    ++        mSpooler.clearCustomPrinterIconCache();
    ++
    +         synchronized (mLock) {
    +             throwIfDestroyedLocked();
    + 
    +             if (mPrinterDiscoverySession == null) {
    +-                mSpooler.clearCustomPrinterIconCache();
    +-
    +                 // If we do not have a session, tell all service to create one.
    +                 mPrinterDiscoverySession = new PrinterDiscoverySessionMediator(mContext) {
    +                     @Override
    +@@ -731,6 +731,8 @@ final class UserState implements PrintSpoolerCallbacks, PrintServiceCallbacks,
    + 
    +     @Override
    +     public void onCustomPrinterIconLoaded(PrinterId printerId, Icon icon) {
    ++        mSpooler.onCustomPrinterIconLoaded(printerId, icon);
    ++
    +         synchronized (mLock) {
    +             throwIfDestroyedLocked();
    + 
    +@@ -738,7 +740,6 @@ final class UserState implements PrintSpoolerCallbacks, PrintServiceCallbacks,
    +             if (mPrinterDiscoverySession == null) {
    +                 return;
    +             }
    +-            mSpooler.onCustomPrinterIconLoaded(printerId, icon);
    +             mPrinterDiscoverySession.onCustomPrinterIconLoadedLocked(printerId);
    +         }
    +     }
    +@@ -979,18 +980,21 @@ final class UserState implements PrintSpoolerCallbacks, PrintServiceCallbacks,
    +      * Prune persistent state if a print service was uninstalled
    +      */
    +     public void prunePrintServices() {
    ++        ArrayList<ComponentName> installedComponents;
    ++
    +         synchronized (mLock) {
    +-            ArrayList<ComponentName> installedComponents = getInstalledComponents();
    ++            installedComponents = getInstalledComponents();
    + 
    +             // Remove unnecessary entries from persistent state "disabled services"
    +             boolean disabledServicesUninstalled = mDisabledServices.retainAll(installedComponents);
    +             if (disabledServicesUninstalled) {
    +                 writeDisabledPrintServicesLocked(mDisabledServices);
    +             }
    +-
    +-            // Remove unnecessary entries from persistent state "approved services"
    +-            mSpooler.pruneApprovedPrintServices(installedComponents);
    +         }
    ++
    ++        // Remove unnecessary entries from persistent state "approved services"
    ++        mSpooler.pruneApprovedPrintServices(installedComponents);
    ++
    +     }
    + 
    +     private void onConfigurationChangedLocked() {
    +diff --git a/services/retaildemo/java/com/android/server/retaildemo/RetailDemoModeService.java b/services/retaildemo/java/com/android/server/retaildemo/RetailDemoModeService.java
    +index 6b27321..6197c42 100644
    +--- a/services/retaildemo/java/com/android/server/retaildemo/RetailDemoModeService.java
    ++++ b/services/retaildemo/java/com/android/server/retaildemo/RetailDemoModeService.java
    +@@ -44,6 +44,7 @@ import android.hardware.camera2.CameraManager;
    + import android.media.AudioManager;
    + import android.media.AudioSystem;
    + import android.net.Uri;
    ++import android.net.wifi.WifiManager;
    + import android.os.Environment;
    + import android.os.FileUtils;
    + import android.os.Handler;
    +@@ -117,6 +118,7 @@ public class RetailDemoModeService extends SystemService {
    +     private ServiceThread mHandlerThread;
    +     private PendingIntent mResetDemoPendingIntent;
    +     private CameraManager mCameraManager;
    ++    private WifiManager mWifiManager;
    +     private String[] mCameraIdsWithFlash;
    +     private Configuration mSystemUserConfiguration;
    +     private PreloadAppsInstaller mPreloadAppsInstaller;
    +@@ -491,6 +493,7 @@ public class RetailDemoModeService extends SystemService {
    +                                 PowerManager.FULL_WAKE_LOCK | PowerManager.ACQUIRE_CAUSES_WAKEUP,
    +                                 TAG);
    +                 mNm = NotificationManager.from(getContext());
    ++                mWifiManager = (WifiManager) getContext().getSystemService(Context.WIFI_SERVICE);
    +                 mCameraManager = (CameraManager) getContext()
    +                         .getSystemService(Context.CAMERA_SERVICE);
    +                 mCameraIdsWithFlash = getCameraIdsWithFlash();
    +@@ -528,6 +531,9 @@ public class RetailDemoModeService extends SystemService {
    +         mAmi.updatePersistentConfigurationForUser(getSystemUsersConfiguration(), userId);
    +         turnOffAllFlashLights();
    +         muteVolumeStreams();
    ++        if (!mWifiManager.isWifiEnabled()) {
    ++            mWifiManager.setWifiEnabled(true);
    ++        }
    +         // Disable lock screen for demo users.
    +         LockPatternUtils lockPatternUtils = new LockPatternUtils(getContext());
    +         lockPatternUtils.setLockScreenDisabled(true, userId);
    +diff --git a/services/tests/Android.mk b/services/tests/Android.mk
    +deleted file mode 100644
    +index 40369ee..0000000
    +--- a/services/tests/Android.mk
    ++++ /dev/null
    +@@ -1,3 +0,0 @@
    +-LOCAL_PATH:= $(call my-dir)
    +-
    +-include $(call all-makefiles-under, $(LOCAL_PATH))
    +diff --git a/services/tests/servicestests/Android.mk b/services/tests/servicestests/Android.mk
    +deleted file mode 100644
    +index 50e0662..0000000
    +--- a/services/tests/servicestests/Android.mk
    ++++ /dev/null
    +@@ -1,81 +0,0 @@
    +-#########################################################################
    +-# Build FrameworksServicesTests package
    +-#########################################################################
    +-
    +-LOCAL_PATH:= $(call my-dir)
    +-include $(CLEAR_VARS)
    +-
    +-# We only want this apk build for tests.
    +-LOCAL_MODULE_TAGS := tests
    +-
    +-# Include all test java files.
    +-LOCAL_SRC_FILES := $(call all-java-files-under, src)
    +-
    +-LOCAL_STATIC_JAVA_LIBRARIES := \
    +-    frameworks-base-testutils \
    +-    services.core \
    +-    services.devicepolicy \
    +-    services.net \
    +-    services.usage \
    +-    easymocklib \
    +-    guava \
    +-    android-support-test \
    +-    mockito-target \
    +-    ShortcutManagerTestUtils
    +-
    +-LOCAL_JAVA_LIBRARIES := android.test.runner
    +-
    +-LOCAL_PACKAGE_NAME := FrameworksServicesTests
    +-
    +-LOCAL_CERTIFICATE := platform
    +-
    +-# These are not normally accessible from apps so they must be explicitly included.
    +-LOCAL_JNI_SHARED_LIBRARIES := libservicestestsjni \
    +-    libbacktrace \
    +-    libbase \
    +-    libbinder \
    +-    libc++ \
    +-    libcutils \
    +-    liblog \
    +-    liblzma \
    +-    libnativehelper \
    +-    libnetdaidl \
    +-    libui \
    +-    libunwind \
    +-    libutils
    +-
    +-LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
    +-
    +-include $(BUILD_PACKAGE)
    +-
    +-#########################################################################
    +-# Build JNI Shared Library
    +-#########################################################################
    +-
    +-LOCAL_PATH:= $(LOCAL_PATH)/jni
    +-
    +-include $(CLEAR_VARS)
    +-
    +-LOCAL_MODULE_TAGS := tests
    +-
    +-LOCAL_CFLAGS := -Wall -Wextra -Werror
    +-
    +-LOCAL_C_INCLUDES := \
    +-  libpcap \
    +-  hardware/google/apf
    +-
    +-LOCAL_SRC_FILES := $(call all-cpp-files-under)
    +-
    +-LOCAL_SHARED_LIBRARIES := \
    +-  libbinder \
    +-  libcutils \
    +-  libnativehelper \
    +-  libnetdaidl
    +-
    +-LOCAL_STATIC_LIBRARIES := \
    +-  libpcap \
    +-  libapf
    +-
    +-LOCAL_MODULE := libservicestestsjni
    +-
    +-include $(BUILD_SHARED_LIBRARY)
    +diff --git a/services/tests/servicestests/AndroidManifest.xml b/services/tests/servicestests/AndroidManifest.xml
    +deleted file mode 100644
    +index b8ace28..0000000
    +--- a/services/tests/servicestests/AndroidManifest.xml
    ++++ /dev/null
    +@@ -1,164 +0,0 @@
    +-<?xml version="1.0" encoding="utf-8"?>
    +-<!-- 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.
    +--->
    +-
    +-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    +-        package="com.android.frameworks.servicestests">
    +-
    +-    <uses-permission android:name="android.permission.READ_LOGS" />
    +-    <uses-permission android:name="android.permission.WRITE_SETTINGS" />
    +-    <uses-permission android:name="android.permission.WRITE_SECURE_SETTINGS" />
    +-    <uses-permission android:name="android.permission.READ_PHONE_STATE" />
    +-    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
    +-    <uses-permission android:name="android.permission.BROADCAST_STICKY" />
    +-    <uses-permission android:name="android.permission.WRITE_SECURE_SETTINGS" />
    +-    <uses-permission android:name="android.permission.UPDATE_DEVICE_STATS" />
    +-    <uses-permission android:name="android.permission.MANAGE_APP_TOKENS" />
    +-    <uses-permission android:name="android.permission.WAKE_LOCK" />
    +-    <uses-permission android:name="android.permission.INTERACT_ACROSS_USERS" />
    +-    <uses-permission android:name="android.permission.REAL_GET_TASKS" />
    +-    <uses-permission android:name="android.permission.GET_DETAILED_TASKS" />
    +-    <uses-permission android:name="android.permission.MANAGE_NETWORK_POLICY" />
    +-    <uses-permission android:name="android.permission.READ_NETWORK_USAGE_HISTORY" />
    +-    <uses-permission android:name="android.permission.MODIFY_NETWORK_ACCOUNTING" />
    +-    <uses-permission android:name="android.permission.CONNECTIVITY_INTERNAL" />
    +-    <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
    +-    <uses-permission android:name="android.permission.MANAGE_USERS" />
    +-    <uses-permission android:name="android.permission.INTERACT_ACROSS_USERS_FULL" />
    +-    <uses-permission android:name="android.permission.MANAGE_DEVICE_ADMINS" />
    +-    <uses-permission android:name="android.permission.MODIFY_PHONE_STATE" />
    +-    <uses-permission android:name="android.permission.INTERNET" />
    +-    <uses-permission android:name="android.permission.CHANGE_NETWORK_STATE" />
    +-    <uses-permission android:name="android.permission.PACKET_KEEPALIVE_OFFLOAD" />
    +-    <uses-permission android:name="android.permission.GET_INTENT_SENDER_INTENT" />
    +-
    +-    <application>
    +-        <uses-library android:name="android.test.runner" />
    +-
    +-        <service android:name="com.android.server.AccessibilityManagerServiceTest$MyFirstMockAccessibilityService"
    +-            android:permission="android.permission.BIND_ACCESSIBILITY_SERVICE">
    +-          <intent-filter>
    +-            <action android:name="android.accessibilityservice.AccessibilityService"/>
    +-          </intent-filter>
    +-        </service>
    +-
    +-        <service android:name="com.android.server.AccessibilityManagerServiceTest$MySecondMockAccessibilityService"
    +-            android:permission="android.permission.BIND_ACCESSIBILITY_SERVICE">
    +-          <intent-filter>
    +-            <action android:name="android.accessibilityservice.AccessibilityService"/>
    +-          </intent-filter>
    +-        </service>
    +-
    +-        <receiver android:name="com.android.server.devicepolicy.ApplicationRestrictionsTest$AdminReceiver"
    +-                android:permission="android.permission.BIND_DEVICE_ADMIN">
    +-            <meta-data android:name="android.app.device_admin"
    +-                       android:resource="@xml/device_admin_sample" />
    +-            <intent-filter>
    +-                <action android:name="android.app.action.DEVICE_ADMIN_ENABLED" />
    +-            </intent-filter>
    +-        </receiver>
    +-
    +-        <receiver android:name="com.android.server.devicepolicy.DummyDeviceAdmins$Admin1"
    +-            android:permission="android.permission.BIND_DEVICE_ADMIN">
    +-            <meta-data android:name="android.app.device_admin"
    +-                android:resource="@xml/device_admin_sample" />
    +-            <intent-filter>
    +-                <action android:name="android.app.action.DEVICE_ADMIN_ENABLED" />
    +-            </intent-filter>
    +-        </receiver>
    +-
    +-        <receiver android:name="com.android.server.devicepolicy.DummyDeviceAdmins$Admin2"
    +-            android:permission="android.permission.BIND_DEVICE_ADMIN">
    +-            <meta-data android:name="android.app.device_admin"
    +-                android:resource="@xml/device_admin_sample" />
    +-            <intent-filter>
    +-                <action android:name="android.app.action.DEVICE_ADMIN_ENABLED" />
    +-            </intent-filter>
    +-        </receiver>
    +-
    +-        <receiver android:name="com.android.server.devicepolicy.DummyDeviceAdmins$Admin3"
    +-            android:permission="android.permission.BIND_DEVICE_ADMIN">
    +-            <meta-data android:name="android.app.device_admin"
    +-                android:resource="@xml/device_admin_sample" />
    +-            <intent-filter>
    +-                <action android:name="android.app.action.DEVICE_ADMIN_ENABLED" />
    +-            </intent-filter>
    +-        </receiver>
    +-
    +-        <receiver android:name="com.android.server.devicepolicy.DummyDeviceAdmins$AdminNoPerm">
    +-            <meta-data android:name="android.app.device_admin"
    +-                android:resource="@xml/device_admin_sample" />
    +-            <intent-filter>
    +-                <action android:name="android.app.action.DEVICE_ADMIN_ENABLED" />
    +-            </intent-filter>
    +-        </receiver>
    +-
    +-        <service android:name="com.android.server.job.MockPriorityJobService"
    +-                 android:permission="android.permission.BIND_JOB_SERVICE" />
    +-
    +-        <activity android:name="com.android.server.pm.BaseShortcutManagerTest$ShortcutActivity" />
    +-        <activity android:name="com.android.server.pm.BaseShortcutManagerTest$ShortcutActivity2" />
    +-        <activity android:name="com.android.server.pm.BaseShortcutManagerTest$ShortcutActivity3" />
    +-
    +-        <activity android:name="com.android.server.pm.ShortcutTestActivity"
    +-            android:enabled="true" android:exported="true" />
    +-
    +-        <activity-alias android:name="a.ShortcutEnabled"
    +-            android:targetActivity="com.android.server.pm.ShortcutTestActivity"
    +-            android:enabled="true" android:exported="true">
    +-        </activity-alias>
    +-        <activity-alias android:name="a.ShortcutDisabled"
    +-            android:targetActivity="com.android.server.pm.ShortcutTestActivity"
    +-            android:enabled="false" android:exported="true">
    +-            <meta-data android:name="android.app.shortcuts" android:resource="@xml/shortcut_5"/>
    +-        </activity-alias>
    +-        <activity-alias android:name="a.ShortcutUnexported"
    +-            android:targetActivity="com.android.server.pm.ShortcutTestActivity"
    +-            android:enabled="true" android:exported="false">
    +-            <meta-data android:name="android.app.shortcuts" android:resource="@xml/shortcut_5"/>
    +-        </activity-alias>
    +-        <activity-alias android:name="a.Shortcut1"
    +-            android:targetActivity="com.android.server.pm.ShortcutTestActivity"
    +-            android:enabled="true" android:exported="true">
    +-            <meta-data android:name="android.app.shortcuts" android:resource="@xml/shortcut_1"/>
    +-        </activity-alias>
    +-
    +-        <activity-alias android:name="a.DisabledMain"
    +-            android:targetActivity="com.android.server.pm.ShortcutTestActivity"
    +-            android:enabled="false" android:exported="true">
    +-            <intent-filter>
    +-                <action android:name="android.intent.action.MAIN" />
    +-                <category android:name="android.intent.category.DEFAULT" />
    +-                <category android:name="android.intent.category.LAUNCHER" />
    +-            </intent-filter>
    +-        </activity-alias>
    +-
    +-        <activity-alias android:name="a.UnexportedMain"
    +-            android:targetActivity="com.android.server.pm.ShortcutTestActivity"
    +-            android:enabled="true" android:exported="false">
    +-            <intent-filter>
    +-                <action android:name="android.intent.action.MAIN" />
    +-                <category android:name="android.intent.category.DEFAULT" />
    +-                <category android:name="android.intent.category.LAUNCHER" />
    +-            </intent-filter>
    +-        </activity-alias>
    +-
    +-    </application>
    +-
    +-    <instrumentation
    +-    	android:name="android.support.test.runner.AndroidJUnitRunner"
    +-    	android:targetPackage="com.android.frameworks.servicestests"
    +-    	android:label="Frameworks Services Tests" />
    +-</manifest>
    +diff --git a/services/tests/servicestests/assets/DevicePolicyManagerServiceMigrationTest/legacy_device_owner.xml b/services/tests/servicestests/assets/DevicePolicyManagerServiceMigrationTest/legacy_device_owner.xml
    +deleted file mode 100644
    +index 9564969..0000000
    +--- a/services/tests/servicestests/assets/DevicePolicyManagerServiceMigrationTest/legacy_device_owner.xml
    ++++ /dev/null
    +@@ -1,4 +0,0 @@
    +-<?xml version='1.0' encoding='utf-8' standalone='yes' ?>
    +-<device-owner package="com.android.frameworks.servicestests" />
    +-<profile-owner package="com.android.frameworks.servicestests" name="0" userId="10" component="com.android.frameworks.servicestests/com.android.server.devicepolicy.DummyDeviceAdmins$Admin2" />
    +-<profile-owner package="com.android.frameworks.servicestests" name="0" userId="11" component="com.android.frameworks.servicestests/com.android.server.devicepolicy.DummyDeviceAdmins$Admin3" />
    +diff --git a/services/tests/servicestests/assets/DevicePolicyManagerServiceMigrationTest/legacy_device_policies.xml b/services/tests/servicestests/assets/DevicePolicyManagerServiceMigrationTest/legacy_device_policies.xml
    +deleted file mode 100644
    +index 48cb814..0000000
    +--- a/services/tests/servicestests/assets/DevicePolicyManagerServiceMigrationTest/legacy_device_policies.xml
    ++++ /dev/null
    +@@ -1,7 +0,0 @@
    +-<?xml version='1.0' encoding='utf-8' standalone='yes' ?>
    +-<policies setup-complete="true">
    +-    <admin name="com.google.android.gms/com.google.android.gms.mdm.receivers.MdmDeviceAdminReceiver">
    +-    </admin>
    +-    <admin name="com.android.frameworks.servicestests/com.android.server.devicepolicy.DummyDeviceAdmins$Admin1">
    +-    </admin>
    +-</policies>
    +diff --git a/services/tests/servicestests/assets/DevicePolicyManagerServiceMigrationTest/legacy_device_policies_10.xml b/services/tests/servicestests/assets/DevicePolicyManagerServiceMigrationTest/legacy_device_policies_10.xml
    +deleted file mode 100644
    +index 6b53840..0000000
    +--- a/services/tests/servicestests/assets/DevicePolicyManagerServiceMigrationTest/legacy_device_policies_10.xml
    ++++ /dev/null
    +@@ -1,5 +0,0 @@
    +-<?xml version='1.0' encoding='utf-8' standalone='yes' ?>
    +-<policies setup-complete="true">
    +-    <admin name="com.android.frameworks.servicestests/com.android.server.devicepolicy.DummyDeviceAdmins$Admin2">
    +-    </admin>
    +-</policies>
    +diff --git a/services/tests/servicestests/assets/DevicePolicyManagerServiceMigrationTest/legacy_device_policies_11.xml b/services/tests/servicestests/assets/DevicePolicyManagerServiceMigrationTest/legacy_device_policies_11.xml
    +deleted file mode 100644
    +index 2bcc5d4..0000000
    +--- a/services/tests/servicestests/assets/DevicePolicyManagerServiceMigrationTest/legacy_device_policies_11.xml
    ++++ /dev/null
    +@@ -1,5 +0,0 @@
    +-<?xml version='1.0' encoding='utf-8' standalone='yes' ?>
    +-<policies setup-complete="true">
    +-    <admin name="com.android.frameworks.servicestests/com.android.server.devicepolicy.DummyDeviceAdmins$Admin3">
    +-    </admin>
    +-</policies>
    +diff --git a/services/tests/servicestests/assets/DevicePolicyManagerServiceMigrationTest2/legacy_device_owner.xml b/services/tests/servicestests/assets/DevicePolicyManagerServiceMigrationTest2/legacy_device_owner.xml
    +deleted file mode 100644
    +index c0977f7..0000000
    +--- a/services/tests/servicestests/assets/DevicePolicyManagerServiceMigrationTest2/legacy_device_owner.xml
    ++++ /dev/null
    +@@ -1,2 +0,0 @@
    +-<?xml version='1.0' encoding='utf-8' standalone='yes' ?>
    +-<profile-owner package="com.android.frameworks.servicestests" name="0" userId="0" component="com.android.frameworks.servicestests/com.android.server.devicepolicy.DummyDeviceAdmins$Admin2" />
    +diff --git a/services/tests/servicestests/assets/DevicePolicyManagerServiceMigrationTest2/legacy_device_policies.xml b/services/tests/servicestests/assets/DevicePolicyManagerServiceMigrationTest2/legacy_device_policies.xml
    +deleted file mode 100644
    +index 6b53840..0000000
    +--- a/services/tests/servicestests/assets/DevicePolicyManagerServiceMigrationTest2/legacy_device_policies.xml
    ++++ /dev/null
    +@@ -1,5 +0,0 @@
    +-<?xml version='1.0' encoding='utf-8' standalone='yes' ?>
    +-<policies setup-complete="true">
    +-    <admin name="com.android.frameworks.servicestests/com.android.server.devicepolicy.DummyDeviceAdmins$Admin2">
    +-    </admin>
    +-</policies>
    +diff --git a/services/tests/servicestests/assets/OwnersTest/test01/input.xml b/services/tests/servicestests/assets/OwnersTest/test01/input.xml
    +deleted file mode 100644
    +index db3e974..0000000
    +--- a/services/tests/servicestests/assets/OwnersTest/test01/input.xml
    ++++ /dev/null
    +@@ -1 +0,0 @@
    +-<?xml version='1.0' encoding='utf-8' standalone='yes' ?>
    +diff --git a/services/tests/servicestests/assets/OwnersTest/test02/input.xml b/services/tests/servicestests/assets/OwnersTest/test02/input.xml
    +deleted file mode 100644
    +index 321842b..0000000
    +--- a/services/tests/servicestests/assets/OwnersTest/test02/input.xml
    ++++ /dev/null
    +@@ -1,2 +0,0 @@
    +-<?xml version='1.0' encoding='utf-8' standalone='yes' ?>
    +-<device-owner package="com.google.android.testdpc" />
    +diff --git a/services/tests/servicestests/assets/OwnersTest/test03/input.xml b/services/tests/servicestests/assets/OwnersTest/test03/input.xml
    +deleted file mode 100644
    +index 1bbfdad..0000000
    +--- a/services/tests/servicestests/assets/OwnersTest/test03/input.xml
    ++++ /dev/null
    +@@ -1,3 +0,0 @@
    +-<?xml version='1.0' encoding='utf-8' standalone='yes' ?>
    +-<profile-owner package="com.google.android.testdpc0" name="0" userId="10" component="com.google.android.testdpc/com.google.android.testdpc.DeviceAdminReceiver0" />
    +-<profile-owner package="com.google.android.testdpc1" name="1" userId="11" />
    +diff --git a/services/tests/servicestests/assets/OwnersTest/test04/input.xml b/services/tests/servicestests/assets/OwnersTest/test04/input.xml
    +deleted file mode 100644
    +index 8be51d9..0000000
    +--- a/services/tests/servicestests/assets/OwnersTest/test04/input.xml
    ++++ /dev/null
    +@@ -1,6 +0,0 @@
    +-<?xml version='1.0' encoding='utf-8' standalone='yes' ?>
    +-<device-owner package="com.google.android.testdpc" />
    +-<profile-owner package="com.google.android.testdpc0" name="0" userId="10" component="com.google.android.testdpc/com.google.android.testdpc.DeviceAdminReceiver0" />
    +-<profile-owner package="com.google.android.testdpc1" name="1" userId="11" />
    +-<device-initializer package="com.google.android.testdpcx" name="di" component="com.google.android.testdpcx/receiver" />
    +-<system-update-policy policy_type="5" />
    +diff --git a/services/tests/servicestests/assets/OwnersTest/test05/input.xml b/services/tests/servicestests/assets/OwnersTest/test05/input.xml
    +deleted file mode 100644
    +index dbcb858..0000000
    +--- a/services/tests/servicestests/assets/OwnersTest/test05/input.xml
    ++++ /dev/null
    +@@ -1,3 +0,0 @@
    +-<?xml version='1.0' encoding='utf-8' standalone='yes' ?>
    +-<device-initializer package="com.google.android.testdpcx" name="di" component="com.google.android.testdpcx/receiver" />
    +-
    +diff --git a/services/tests/servicestests/assets/OwnersTest/test06/input.xml b/services/tests/servicestests/assets/OwnersTest/test06/input.xml
    +deleted file mode 100644
    +index 794622b..0000000
    +--- a/services/tests/servicestests/assets/OwnersTest/test06/input.xml
    ++++ /dev/null
    +@@ -1,2 +0,0 @@
    +-<?xml version='1.0' encoding='utf-8' standalone='yes' ?>
    +-<system-update-policy policy_type="5" />
    +diff --git a/services/tests/servicestests/assets/shortcut/dumpsys_expected.txt b/services/tests/servicestests/assets/shortcut/dumpsys_expected.txt
    +deleted file mode 100644
    +index eed2087..0000000
    +--- a/services/tests/servicestests/assets/shortcut/dumpsys_expected.txt
    ++++ /dev/null
    +@@ -1,105 +0,0 @@
    +-{
    +- "shortcut": [
    +-  {
    +-   "userId": 0,
    +-   "launchers": [
    +-    {
    +-     "name": "com.android.launcher.1"
    +-    },
    +-    {
    +-     "name": "com.android.launcher.2"
    +-    },
    +-    {
    +-     "name": "com.android.launcher.3"
    +-    },
    +-    {
    +-     "name": "com.android.launcher.4"
    +-    },
    +-    {
    +-     "name": "com.android.launcher.1"
    +-    }
    +-   ],
    +-   "packages": [
    +-    {
    +-     "name": "com.android.test.1",
    +-     "dynamic": 3,
    +-     "manifest": 0,
    +-     "pinned": 4,
    +-     "bitmaps": 0,
    +-     "bitmapBytes": 0
    +-    },
    +-    {
    +-     "name": "com.android.test.2",
    +-     "dynamic": 4,
    +-     "manifest": 0,
    +-     "pinned": 5,
    +-     "bitmaps": 2,
    +-     "bitmapBytes": ***BITMAP_SIZE***
    +-    },
    +-    {
    +-     "name": "com.android.test.3",
    +-     "dynamic": 3,
    +-     "manifest": 0,
    +-     "pinned": 6,
    +-     "bitmaps": 0,
    +-     "bitmapBytes": 0
    +-    },
    +-    {
    +-     "name": "com.android.test.4",
    +-     "dynamic": 0,
    +-     "manifest": 0,
    +-     "pinned": 0,
    +-     "bitmaps": 0,
    +-     "bitmapBytes": 0
    +-    }
    +-   ]
    +-  },
    +-  {
    +-   "userId": 10,
    +-   "launchers": [
    +-    {
    +-     "name": "com.android.launcher.1"
    +-    }
    +-   ],
    +-   "packages": [
    +-    {
    +-     "name": "com.android.test.1",
    +-     "dynamic": 3,
    +-     "manifest": 0,
    +-     "pinned": 2,
    +-     "bitmaps": 0,
    +-     "bitmapBytes": 0
    +-    }
    +-   ]
    +-  },
    +-  {
    +-   "userId": 20,
    +-   "launchers": [
    +-    {
    +-     "name": "com.android.launcher.1"
    +-    },
    +-    {
    +-     "name": "com.android.launcher.2"
    +-    },
    +-    {
    +-     "name": "com.android.launcher.3"
    +-    },
    +-    {
    +-     "name": "com.android.launcher.1"
    +-    }
    +-   ],
    +-   "packages": [
    +-    {
    +-     "name": "com.android.test.1",
    +-     "dynamic": 3,
    +-     "manifest": 0,
    +-     "pinned": 6,
    +-     "bitmaps": 0,
    +-     "bitmapBytes": 0
    +-    }
    +-   ]
    +-  }
    +- ],
    +- "lowRam": false,
    +- "iconSize": 128
    +-}
    +diff --git a/services/tests/servicestests/assets/shortcut/shortcut_legacy_file.xml b/services/tests/servicestests/assets/shortcut/shortcut_legacy_file.xml
    +deleted file mode 100644
    +index f7eee91..0000000
    +--- a/services/tests/servicestests/assets/shortcut/shortcut_legacy_file.xml
    ++++ /dev/null
    +@@ -1,25 +0,0 @@
    +-<?xml version='1.0' encoding='utf-8' standalone='yes' ?>
    +-<!-- Copyright (C) 2016 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.
    +--->
    +-<user locales="en-US" last-app-scan-time="3113976673">
    +-    <package name="com.android.test.1" call-count="0" last-reset="1468976368772">
    +-        <package-info version="25" last_udpate_time="1230796800000" />
    +-        <shortcut id="manifest-shortcut-storage" activity="com.android.test.1/com.android.test.1.Settings" title="Storage" intent="#Intent;action=android.settings.INTERNAL_STORAGE_SETTINGS;end" timestamp="1469050672334" flags="1" >
    +-            <intent-extras>
    +-                <int name="key" value="12345" />
    +-            </intent-extras>
    +-        </shortcut>
    +-    </package>
    +-</user>
    +diff --git a/services/tests/servicestests/jni/UidRangeTest.cpp b/services/tests/servicestests/jni/UidRangeTest.cpp
    +deleted file mode 100644
    +index 7941731..0000000
    +--- a/services/tests/servicestests/jni/UidRangeTest.cpp
    ++++ /dev/null
    +@@ -1,79 +0,0 @@
    +-/*
    +- * Copyright (C) 2016 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.
    +- */
    +-
    +-#include <memory>
    +-
    +-#include <binder/Parcel.h>
    +-
    +-#include "UidRangeTest.h"
    +-
    +-using android::net::UidRange;
    +-
    +-extern "C"
    +-JNIEXPORT jbyteArray Java_android_net_UidRangeTest_readAndWriteNative(JNIEnv* env, jclass,
    +-        jbyteArray inParcel) {
    +-    const UidRange range = unmarshall(env, inParcel);
    +-    return marshall(env, range);
    +-}
    +-
    +-extern "C"
    +-JNIEXPORT jint Java_android_net_UidRangeTest_getStart(JNIEnv* env, jclass, jbyteArray inParcel) {
    +-    const UidRange range = unmarshall(env, inParcel);
    +-    return range.getStart();
    +-}
    +-
    +-extern "C"
    +-JNIEXPORT jint Java_android_net_UidRangeTest_getStop(JNIEnv* env, jclass, jbyteArray inParcel) {
    +-    const UidRange range = unmarshall(env, inParcel);
    +-    return range.getStop();
    +-}
    +-
    +-
    +-/**
    +- * Reads exactly one UidRange from 'parcelData' assuming that it is a Parcel. Any bytes afterward
    +- * are ignored.
    +- */
    +-UidRange unmarshall(JNIEnv* env, jbyteArray parcelData) {
    +-    const int length = env->GetArrayLength(parcelData);
    +-
    +-    std::unique_ptr<uint8_t> bytes(new uint8_t[length]);
    +-    env->GetByteArrayRegion(parcelData, 0, length, reinterpret_cast<jbyte*>(bytes.get()));
    +-
    +-    android::Parcel p;
    +-    p.setData(bytes.get(), length);
    +-
    +-    UidRange range;
    +-    range.readFromParcel(&p);
    +-    return range;
    +-}
    +-
    +-/**
    +- * Creates a Java byte[] array and writes the contents of 'range' to it as a Parcel containing
    +- * exactly one object.
    +- *
    +- * Every UidRange maps to a unique parcel object, so both 'marshall(e, unmarshall(e, x))' and
    +- * 'unmarshall(e, marshall(e, x))' should be fixed points.
    +- */
    +-jbyteArray marshall(JNIEnv* env, const UidRange& range) {
    +-    android::Parcel p;
    +-    range.writeToParcel(&p);
    +-    const int length = p.dataSize();
    +-
    +-    jbyteArray parcelData = env->NewByteArray(length);
    +-    env->SetByteArrayRegion(parcelData, 0, length, reinterpret_cast<const jbyte*>(p.data()));
    +-
    +-    return parcelData;
    +-}
    +diff --git a/services/tests/servicestests/jni/UidRangeTest.h b/services/tests/servicestests/jni/UidRangeTest.h
    +deleted file mode 100644
    +index b7e7453..0000000
    +--- a/services/tests/servicestests/jni/UidRangeTest.h
    ++++ /dev/null
    +@@ -1,38 +0,0 @@
    +-/*
    +- * Copyright (C) 2016 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.
    +- */
    +-
    +-#ifndef _ANDROID_NET_UIDRANGETEST_H_
    +-#define _ANDROID_NET_UIDRANGETEST_H_
    +-
    +-#include <jni.h>
    +-
    +-#include "android/net/UidRange.h"
    +-
    +-android::net::UidRange unmarshall(JNIEnv* env, jbyteArray parcelData);
    +-
    +-jbyteArray marshall(JNIEnv* env, const android::net::UidRange& range);
    +-
    +-extern "C"
    +-JNIEXPORT jbyteArray Java_android_net_UidRangeTest_readAndWriteNative(JNIEnv* env, jclass,
    +-        jbyteArray inParcel);
    +-
    +-extern "C"
    +-JNIEXPORT jint Java_android_net_UidRangeTest_getStart(JNIEnv* env, jclass, jbyteArray inParcel);
    +-
    +-extern "C"
    +-JNIEXPORT jint Java_android_net_UidRangeTest_getStop(JNIEnv* env, jclass, jbyteArray inParcel);
    +-
    +-#endif  //  _ANDROID_NET_UIDRANGETEST_H_
    +diff --git a/services/tests/servicestests/jni/apf_jni.cpp b/services/tests/servicestests/jni/apf_jni.cpp
    +deleted file mode 100644
    +index ee43dd4..0000000
    +--- a/services/tests/servicestests/jni/apf_jni.cpp
    ++++ /dev/null
    +@@ -1,182 +0,0 @@
    +-/*
    +- * Copyright 2016, 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.
    +- */
    +-
    +-#include <JNIHelp.h>
    +-#include <ScopedUtfChars.h>
    +-#include <jni.h>
    +-#include <pcap.h>
    +-#include <stdlib.h>
    +-#include <string>
    +-#include <utils/Log.h>
    +-
    +-#include "apf_interpreter.h"
    +-
    +-#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
    +-
    +-// JNI function acting as simply call-through to native APF interpreter.
    +-static jint com_android_server_ApfTest_apfSimulate(
    +-        JNIEnv* env, jclass, jbyteArray program, jbyteArray packet, jint filter_age) {
    +-    return accept_packet(
    +-            (uint8_t*)env->GetByteArrayElements(program, NULL),
    +-            env->GetArrayLength(program),
    +-            (uint8_t*)env->GetByteArrayElements(packet, NULL),
    +-            env->GetArrayLength(packet),
    +-            filter_age);
    +-}
    +-
    +-class ScopedPcap {
    +-  public:
    +-    ScopedPcap(pcap_t* pcap) : pcap_ptr(pcap) {}
    +-    ~ScopedPcap() {
    +-        pcap_close(pcap_ptr);
    +-    }
    +-
    +-    pcap_t* get() const { return pcap_ptr; };
    +-  private:
    +-    pcap_t* const pcap_ptr;
    +-};
    +-
    +-class ScopedFILE {
    +-  public:
    +-    ScopedFILE(FILE* fp) : file(fp) {}
    +-    ~ScopedFILE() {
    +-        fclose(file);
    +-    }
    +-
    +-    FILE* get() const { return file; };
    +-  private:
    +-    FILE* const file;
    +-};
    +-
    +-static void throwException(JNIEnv* env, const std::string& error) {
    +-    jclass newExcCls = env->FindClass("java/lang/IllegalStateException");
    +-    if (newExcCls == 0) {
    +-      abort();
    +-      return;
    +-    }
    +-    env->ThrowNew(newExcCls, error.c_str());
    +-}
    +-
    +-static jstring com_android_server_ApfTest_compileToBpf(JNIEnv* env, jclass, jstring jfilter) {
    +-    ScopedUtfChars filter(env, jfilter);
    +-    std::string bpf_string;
    +-    ScopedPcap pcap(pcap_open_dead(DLT_EN10MB, 65535));
    +-    if (pcap.get() == NULL) {
    +-        throwException(env, "pcap_open_dead failed");
    +-        return NULL;
    +-    }
    +-
    +-    // Compile "filter" to a BPF program
    +-    bpf_program bpf;
    +-    if (pcap_compile(pcap.get(), &bpf, filter.c_str(), 0, PCAP_NETMASK_UNKNOWN)) {
    +-        throwException(env, "pcap_compile failed");
    +-        return NULL;
    +-    }
    +-
    +-    // Translate BPF program to human-readable format
    +-    const struct bpf_insn* insn = bpf.bf_insns;
    +-    for (uint32_t i = 0; i < bpf.bf_len; i++) {
    +-        bpf_string += bpf_image(insn++, i);
    +-        bpf_string += "\n";
    +-    }
    +-
    +-    return env->NewStringUTF(bpf_string.c_str());
    +-}
    +-
    +-static jboolean com_android_server_ApfTest_compareBpfApf(JNIEnv* env, jclass, jstring jfilter,
    +-        jstring jpcap_filename, jbyteArray japf_program) {
    +-    ScopedUtfChars filter(env, jfilter);
    +-    ScopedUtfChars pcap_filename(env, jpcap_filename);
    +-    const uint8_t* apf_program = (uint8_t*)env->GetByteArrayElements(japf_program, NULL);
    +-    const uint32_t apf_program_len = env->GetArrayLength(japf_program);
    +-
    +-    // Open pcap file for BPF filtering
    +-    ScopedFILE bpf_fp(fopen(pcap_filename.c_str(), "rb"));
    +-    char pcap_error[PCAP_ERRBUF_SIZE];
    +-    ScopedPcap bpf_pcap(pcap_fopen_offline(bpf_fp.get(), pcap_error));
    +-    if (bpf_pcap.get() == NULL) {
    +-        throwException(env, "pcap_fopen_offline failed: " + std::string(pcap_error));
    +-        return false;
    +-    }
    +-
    +-    // Open pcap file for APF filtering
    +-    ScopedFILE apf_fp(fopen(pcap_filename.c_str(), "rb"));
    +-    ScopedPcap apf_pcap(pcap_fopen_offline(apf_fp.get(), pcap_error));
    +-    if (apf_pcap.get() == NULL) {
    +-        throwException(env, "pcap_fopen_offline failed: " + std::string(pcap_error));
    +-        return false;
    +-    }
    +-
    +-    // Compile "filter" to a BPF program
    +-    bpf_program bpf;
    +-    if (pcap_compile(bpf_pcap.get(), &bpf, filter.c_str(), 0, PCAP_NETMASK_UNKNOWN)) {
    +-        throwException(env, "pcap_compile failed");
    +-        return false;
    +-    }
    +-
    +-    // Install BPF filter on bpf_pcap
    +-    if (pcap_setfilter(bpf_pcap.get(), &bpf)) {
    +-        throwException(env, "pcap_setfilter failed");
    +-        return false;
    +-    }
    +-
    +-    while (1) {
    +-        pcap_pkthdr bpf_header, apf_header;
    +-        // Run BPF filter to the next matching packet.
    +-        const uint8_t* bpf_packet = pcap_next(bpf_pcap.get(), &bpf_header);
    +-
    +-        // Run APF filter to the next matching packet.
    +-        const uint8_t* apf_packet;
    +-        do {
    +-            apf_packet = pcap_next(apf_pcap.get(), &apf_header);
    +-        } while (apf_packet != NULL && !accept_packet(
    +-                apf_program, apf_program_len, apf_packet, apf_header.len, 0));
    +-
    +-        // Make sure both filters matched the same packet.
    +-        if (apf_packet == NULL && bpf_packet == NULL)
    +-             break;
    +-        if (apf_packet == NULL || bpf_packet == NULL)
    +-             return false;
    +-        if (apf_header.len != bpf_header.len ||
    +-                apf_header.ts.tv_sec != bpf_header.ts.tv_sec ||
    +-                apf_header.ts.tv_usec != bpf_header.ts.tv_usec ||
    +-                memcmp(apf_packet, bpf_packet, apf_header.len))
    +-            return false;
    +-    }
    +-    return true;
    +-}
    +-
    +-extern "C" jint JNI_OnLoad(JavaVM* vm, void*) {
    +-    JNIEnv *env;
    +-    if (vm->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_6) != JNI_OK) {
    +-        ALOGE("ERROR: GetEnv failed");
    +-        return -1;
    +-    }
    +-
    +-    static JNINativeMethod gMethods[] = {
    +-            { "apfSimulate", "([B[BI)I",
    +-                    (void*)com_android_server_ApfTest_apfSimulate },
    +-            { "compileToBpf", "(Ljava/lang/String;)Ljava/lang/String;",
    +-                    (void*)com_android_server_ApfTest_compileToBpf },
    +-            { "compareBpfApf", "(Ljava/lang/String;Ljava/lang/String;[B)Z",
    +-                    (void*)com_android_server_ApfTest_compareBpfApf },
    +-    };
    +-
    +-    jniRegisterNativeMethods(env, "android/net/apf/ApfTest",
    +-            gMethods, ARRAY_SIZE(gMethods));
    +-
    +-    return JNI_VERSION_1_6;
    +-}
    +diff --git a/services/tests/servicestests/res/drawable-nodpi/black_1024x4096.png b/services/tests/servicestests/res/drawable-nodpi/black_1024x4096.png
    +deleted file mode 100644
    +index f700326..0000000
    +Binary files a/services/tests/servicestests/res/drawable-nodpi/black_1024x4096.png and /dev/null differ
    +diff --git a/services/tests/servicestests/res/drawable-nodpi/black_16x64.png b/services/tests/servicestests/res/drawable-nodpi/black_16x64.png
    +deleted file mode 100644
    +index 315763e..0000000
    +Binary files a/services/tests/servicestests/res/drawable-nodpi/black_16x64.png and /dev/null differ
    +diff --git a/services/tests/servicestests/res/drawable-nodpi/black_32x32.png b/services/tests/servicestests/res/drawable-nodpi/black_32x32.png
    +deleted file mode 100644
    +index 8958f6b..0000000
    +Binary files a/services/tests/servicestests/res/drawable-nodpi/black_32x32.png and /dev/null differ
    +diff --git a/services/tests/servicestests/res/drawable-nodpi/black_4096x1024.png b/services/tests/servicestests/res/drawable-nodpi/black_4096x1024.png
    +deleted file mode 100644
    +index f675030..0000000
    +Binary files a/services/tests/servicestests/res/drawable-nodpi/black_4096x1024.png and /dev/null differ
    +diff --git a/services/tests/servicestests/res/drawable-nodpi/black_4096x4096.png b/services/tests/servicestests/res/drawable-nodpi/black_4096x4096.png
    +deleted file mode 100644
    +index 999d858..0000000
    +Binary files a/services/tests/servicestests/res/drawable-nodpi/black_4096x4096.png and /dev/null differ
    +diff --git a/services/tests/servicestests/res/drawable-nodpi/black_512x512.png b/services/tests/servicestests/res/drawable-nodpi/black_512x512.png
    +deleted file mode 100644
    +index 40d1c2c..0000000
    +Binary files a/services/tests/servicestests/res/drawable-nodpi/black_512x512.png and /dev/null differ
    +diff --git a/services/tests/servicestests/res/drawable-nodpi/black_64x16.png b/services/tests/servicestests/res/drawable-nodpi/black_64x16.png
    +deleted file mode 100644
    +index 5883015..0000000
    +Binary files a/services/tests/servicestests/res/drawable-nodpi/black_64x16.png and /dev/null differ
    +diff --git a/services/tests/servicestests/res/drawable-nodpi/black_64x64.png b/services/tests/servicestests/res/drawable-nodpi/black_64x64.png
    +deleted file mode 100644
    +index 71cfafc..0000000
    +Binary files a/services/tests/servicestests/res/drawable-nodpi/black_64x64.png and /dev/null differ
    +diff --git a/services/tests/servicestests/res/drawable-nodpi/icon1.png b/services/tests/servicestests/res/drawable-nodpi/icon1.png
    +deleted file mode 100644
    +index 64eb294..0000000
    +Binary files a/services/tests/servicestests/res/drawable-nodpi/icon1.png and /dev/null differ
    +diff --git a/services/tests/servicestests/res/drawable-nodpi/icon2.png b/services/tests/servicestests/res/drawable-nodpi/icon2.png
    +deleted file mode 100644
    +index 7502484..0000000
    +Binary files a/services/tests/servicestests/res/drawable-nodpi/icon2.png and /dev/null differ
    +diff --git a/services/tests/servicestests/res/drawable/icon1.png b/services/tests/servicestests/res/drawable/icon1.png
    +deleted file mode 100644
    +index 64eb294..0000000
    +Binary files a/services/tests/servicestests/res/drawable/icon1.png and /dev/null differ
    +diff --git a/services/tests/servicestests/res/drawable/icon2.png b/services/tests/servicestests/res/drawable/icon2.png
    +deleted file mode 100644
    +index 7502484..0000000
    +Binary files a/services/tests/servicestests/res/drawable/icon2.png and /dev/null differ
    +diff --git a/services/tests/servicestests/res/drawable/icon3.png b/services/tests/servicestests/res/drawable/icon3.png
    +deleted file mode 100644
    +index 64eb294..0000000
    +Binary files a/services/tests/servicestests/res/drawable/icon3.png and /dev/null differ
    +diff --git a/services/tests/servicestests/res/raw/apf.pcap b/services/tests/servicestests/res/raw/apf.pcap
    +deleted file mode 100644
    +index 963165f..0000000
    +Binary files a/services/tests/servicestests/res/raw/apf.pcap and /dev/null differ
    +diff --git a/services/tests/servicestests/res/raw/netstats_uid_v4 b/services/tests/servicestests/res/raw/netstats_uid_v4
    +deleted file mode 100644
    +index e75fc1c..0000000
    +Binary files a/services/tests/servicestests/res/raw/netstats_uid_v4 and /dev/null differ
    +diff --git a/services/tests/servicestests/res/raw/netstats_v1 b/services/tests/servicestests/res/raw/netstats_v1
    +deleted file mode 100644
    +index e80860a..0000000
    +Binary files a/services/tests/servicestests/res/raw/netstats_v1 and /dev/null differ
    +diff --git a/services/tests/servicestests/res/raw/test1.obb b/services/tests/servicestests/res/raw/test1.obb
    +deleted file mode 100644
    +index 7d2b4f6..0000000
    +Binary files a/services/tests/servicestests/res/raw/test1.obb and /dev/null differ
    +diff --git a/services/tests/servicestests/res/raw/test1_nosig.obb b/services/tests/servicestests/res/raw/test1_nosig.obb
    +deleted file mode 100644
    +index 5c3573f7..0000000
    +Binary files a/services/tests/servicestests/res/raw/test1_nosig.obb and /dev/null differ
    +diff --git a/services/tests/servicestests/res/raw/test1_wrongpackage.obb b/services/tests/servicestests/res/raw/test1_wrongpackage.obb
    +deleted file mode 100644
    +index d0aafe1..0000000
    +Binary files a/services/tests/servicestests/res/raw/test1_wrongpackage.obb and /dev/null differ
    +diff --git a/services/tests/servicestests/res/values/strings.xml b/services/tests/servicestests/res/values/strings.xml
    +deleted file mode 100644
    +index 2f9d06c..0000000
    +--- a/services/tests/servicestests/res/values/strings.xml
    ++++ /dev/null
    +@@ -1,24 +0,0 @@
    +-<?xml version="1.0" encoding="utf-8"?>
    +-<!-- Copyright (C) 2016 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.
    +--->
    +-
    +-<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
    +-    <string name="shortcut_title1"></string>
    +-    <string name="shortcut_text1"></string>
    +-    <string name="shortcut_disabled_message1"></string>
    +-    <string name="shortcut_title2"></string>
    +-    <string name="shortcut_text2"></string>
    +-    <string name="shortcut_disabled_message2"></string>
    +-</resources>
    +diff --git a/services/tests/servicestests/res/xml/device_admin_sample.xml b/services/tests/servicestests/res/xml/device_admin_sample.xml
    +deleted file mode 100644
    +index 032debb..0000000
    +--- a/services/tests/servicestests/res/xml/device_admin_sample.xml
    ++++ /dev/null
    +@@ -1,29 +0,0 @@
    +-<?xml version="1.0" encoding="utf-8"?>
    +-<!-- Copyright (C) 2014 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.
    +--->
    +-
    +-<device-admin xmlns:android="http://schemas.android.com/apk/res/android">
    +-    <uses-policies>
    +-        <limit-password />
    +-        <watch-login />
    +-        <reset-password />
    +-        <force-lock />
    +-        <wipe-data />
    +-        <expire-password />
    +-        <encrypted-storage />
    +-        <disable-camera />
    +-        <disable-keyguard-features />
    +-    </uses-policies>
    +-</device-admin>
    +diff --git a/services/tests/servicestests/res/xml/shortcut_0.xml b/services/tests/servicestests/res/xml/shortcut_0.xml
    +deleted file mode 100644
    +index fda001e..0000000
    +--- a/services/tests/servicestests/res/xml/shortcut_0.xml
    ++++ /dev/null
    +@@ -1,2 +0,0 @@
    +-<shortcuts xmlns:android="http://schemas.android.com/apk/res/android" >
    +-</shortcuts>
    +diff --git a/services/tests/servicestests/res/xml/shortcut_1.xml b/services/tests/servicestests/res/xml/shortcut_1.xml
    +deleted file mode 100644
    +index e3f9172..0000000
    +--- a/services/tests/servicestests/res/xml/shortcut_1.xml
    ++++ /dev/null
    +@@ -1,18 +0,0 @@
    +-<shortcuts xmlns:android="http://schemas.android.com/apk/res/android" >
    +-    <shortcut
    +-        android:shortcutId="ms1"
    +-        android:enabled="true"
    +-        android:icon="@drawable/icon1"
    +-        android:shortcutShortLabel="@string/shortcut_title1"
    +-        android:shortcutLongLabel="@string/shortcut_text1"
    +-        android:shortcutDisabledMessage="@string/shortcut_disabled_message1"
    +-        >
    +-        <intent
    +-            android:action="action1"
    +-            android:data="data1"
    +-            >
    +-        </intent>
    +-        <categories android:name="android.shortcut.conversation" />
    +-        <categories android:name="android.shortcut.media" />
    +-    </shortcut>
    +-</shortcuts>
    +diff --git a/services/tests/servicestests/res/xml/shortcut_1_alt.xml b/services/tests/servicestests/res/xml/shortcut_1_alt.xml
    +deleted file mode 100644
    +index 2d5e8e7..0000000
    +--- a/services/tests/servicestests/res/xml/shortcut_1_alt.xml
    ++++ /dev/null
    +@@ -1,33 +0,0 @@
    +-<?xml version="1.0" encoding="utf-8"?>
    +-<!-- Copyright (C) 2016 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.
    +--->
    +-<shortcuts xmlns:android="http://schemas.android.com/apk/res/android" >
    +-    <shortcut
    +-        android:shortcutId="ms1-alt"
    +-        android:enabled="true"
    +-        android:icon="@drawable/icon1"
    +-        android:shortcutShortLabel="@string/shortcut_title1"
    +-        android:shortcutLongLabel="@string/shortcut_text1"
    +-        android:shortcutDisabledMessage="@string/shortcut_disabled_message1"
    +-        >
    +-        <intent
    +-            android:action="action1"
    +-            android:data="data1"
    +-        >
    +-        </intent>
    +-        <categories android:name="android.shortcut.conversation" />
    +-        <categories android:name="android.shortcut.media" />
    +-    </shortcut>
    +-</shortcuts>
    +diff --git a/services/tests/servicestests/res/xml/shortcut_1_disable.xml b/services/tests/servicestests/res/xml/shortcut_1_disable.xml
    +deleted file mode 100644
    +index e3ee3a0..0000000
    +--- a/services/tests/servicestests/res/xml/shortcut_1_disable.xml
    ++++ /dev/null
    +@@ -1,25 +0,0 @@
    +-<?xml version="1.0" encoding="utf-8"?>
    +-<!-- Copyright (C) 2016 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.
    +--->
    +-<shortcuts xmlns:android="http://schemas.android.com/apk/res/android" >
    +-    <shortcut
    +-        android:shortcutId="ms1"
    +-        android:enabled="false"
    +-        android:icon="@drawable/icon2"
    +-        android:shortcutShortLabel="@string/shortcut_title2"
    +-        android:shortcutLongLabel="@string/shortcut_text2"
    +-        android:shortcutDisabledMessage="@string/shortcut_disabled_message2"
    +-    />
    +-</shortcuts>
    +diff --git a/services/tests/servicestests/res/xml/shortcut_2.xml b/services/tests/servicestests/res/xml/shortcut_2.xml
    +deleted file mode 100644
    +index f7ea803..0000000
    +--- a/services/tests/servicestests/res/xml/shortcut_2.xml
    ++++ /dev/null
    +@@ -1,48 +0,0 @@
    +-<?xml version="1.0" encoding="utf-8"?>
    +-<!-- Copyright (C) 2016 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.
    +--->
    +-<shortcuts xmlns:android="http://schemas.android.com/apk/res/android" >
    +-    <shortcut
    +-        android:shortcutId="ms1"
    +-        android:enabled="true"
    +-        android:icon="@drawable/icon1"
    +-        android:shortcutShortLabel="@string/shortcut_title1"
    +-        android:shortcutLongLabel="@string/shortcut_text1"
    +-        android:shortcutDisabledMessage="@string/shortcut_disabled_message1"
    +-        >
    +-        <intent
    +-            android:action="action1"
    +-            android:data="http://a.b.c/"
    +-            >
    +-        </intent>
    +-        <categories android:name="android.shortcut.conversation" />
    +-        <categories android:name="android.shortcut.media" />
    +-    </shortcut>
    +-    <shortcut
    +-        android:shortcutId="ms2"
    +-        android:enabled="true"
    +-        android:icon="@drawable/icon2"
    +-        android:shortcutShortLabel="@string/shortcut_title2"
    +-        android:shortcutLongLabel="@string/shortcut_text2"
    +-        android:shortcutDisabledMessage="@string/shortcut_disabled_message2"
    +-        >
    +-        <intent
    +-            android:action="action2"
    +-            android:data="http://a.b.c/2"
    +-            >
    +-        </intent>
    +-        <categories android:name="android.shortcut.conversation" />
    +-    </shortcut>
    +-</shortcuts>
    +diff --git a/services/tests/servicestests/res/xml/shortcut_2_duplicate.xml b/services/tests/servicestests/res/xml/shortcut_2_duplicate.xml
    +deleted file mode 100644
    +index b00ec60..0000000
    +--- a/services/tests/servicestests/res/xml/shortcut_2_duplicate.xml
    ++++ /dev/null
    +@@ -1,35 +0,0 @@
    +-<?xml version="1.0" encoding="utf-8"?>
    +-<!-- Copyright (C) 2016 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.
    +--->
    +-<shortcuts xmlns:android="http://schemas.android.com/apk/res/android" >
    +-    <shortcut
    +-        android:shortcutId="ms1"
    +-        android:shortcutShortLabel="@string/shortcut_title1"
    +-        >
    +-        <intent
    +-            android:action="action1"
    +-            >
    +-        </intent>
    +-    </shortcut>
    +-    <shortcut
    +-        android:shortcutId="ms1"
    +-        android:shortcutShortLabel="@string/shortcut_title2"
    +-        >
    +-        <intent
    +-            android:action="action2"
    +-            >
    +-        </intent>
    +-    </shortcut>
    +-</shortcuts>
    +diff --git a/services/tests/servicestests/res/xml/shortcut_3.xml b/services/tests/servicestests/res/xml/shortcut_3.xml
    +deleted file mode 100644
    +index 432ca49..0000000
    +--- a/services/tests/servicestests/res/xml/shortcut_3.xml
    ++++ /dev/null
    +@@ -1,56 +0,0 @@
    +-<?xml version="1.0" encoding="utf-8"?>
    +-<!-- Copyright (C) 2016 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.
    +--->
    +-<shortcuts xmlns:android="http://schemas.android.com/apk/res/android" >
    +-    <shortcut
    +-        android:shortcutId="ms1"
    +-        android:enabled="true"
    +-        android:icon="@drawable/icon1"
    +-        android:shortcutShortLabel="@string/shortcut_title1"
    +-        android:shortcutLongLabel="@string/shortcut_text1"
    +-        android:shortcutDisabledMessage="@string/shortcut_disabled_message1"
    +-        >
    +-        <intent
    +-            android:action="action1"
    +-            android:data="http://a.b.c/"
    +-            >
    +-        </intent>
    +-        <categories android:name="android.shortcut.conversation" />
    +-        <categories android:name="android.shortcut.media" />
    +-    </shortcut>
    +-    <shortcut
    +-        android:shortcutId="ms2"
    +-        android:enabled="true"
    +-        android:icon="@drawable/icon2"
    +-        android:shortcutShortLabel="@string/shortcut_title2"
    +-        android:shortcutLongLabel="@string/shortcut_text2"
    +-        android:shortcutDisabledMessage="@string/shortcut_disabled_message2"
    +-        >
    +-        <intent
    +-            android:action="action2"
    +-            android:data="http://a.b.c/2"
    +-            >
    +-        </intent>
    +-        <categories android:name="android.shortcut.conversation" />
    +-    </shortcut>
    +-    <shortcut
    +-        android:shortcutId="ms3"
    +-        android:enabled="true"
    +-        android:icon="@drawable/icon3"
    +-        android:shortcutShortLabel="@string/shortcut_title2"
    +-        >
    +-        <intent android:action="action3" />
    +-    </shortcut>
    +-</shortcuts>
    +diff --git a/services/tests/servicestests/res/xml/shortcut_5.xml b/services/tests/servicestests/res/xml/shortcut_5.xml
    +deleted file mode 100644
    +index 9551100..0000000
    +--- a/services/tests/servicestests/res/xml/shortcut_5.xml
    ++++ /dev/null
    +@@ -1,85 +0,0 @@
    +-<?xml version="1.0" encoding="utf-8"?>
    +-<!-- Copyright (C) 2016 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.
    +--->
    +-<shortcuts xmlns:android="http://schemas.android.com/apk/res/android" >
    +-    <shortcut
    +-        android:shortcutId="ms1"
    +-        android:enabled="true"
    +-        android:icon="@drawable/icon1"
    +-        android:shortcutShortLabel="@string/shortcut_title1"
    +-        android:shortcutLongLabel="@string/shortcut_text1"
    +-        android:shortcutDisabledMessage="@string/shortcut_disabled_message1"
    +-        >
    +-        <intent
    +-            android:action="action1"
    +-            android:data="http://a.b.c/1"
    +-            >
    +-        </intent>
    +-        <categories android:name="android.shortcut.conversation" />
    +-        <categories android:name="android.shortcut.media" />
    +-    </shortcut>
    +-    <shortcut
    +-        android:shortcutId="ms2"
    +-        android:enabled="true"
    +-        android:icon="@drawable/icon2"
    +-        android:shortcutShortLabel="@string/shortcut_title2"
    +-        android:shortcutLongLabel="@string/shortcut_text2"
    +-        android:shortcutDisabledMessage="@string/shortcut_disabled_message2"
    +-        >
    +-        <intent
    +-            android:action="action2"
    +-            >
    +-        </intent>
    +-        <categories android:name="android.shortcut.conversation" />
    +-    </shortcut>
    +-    <shortcut
    +-        android:shortcutId="ms3"
    +-        android:shortcutShortLabel="@string/shortcut_title1"
    +-        >
    +-        <intent
    +-            android:action="android.intent.action.VIEW"
    +-            >
    +-        </intent>
    +-    </shortcut>
    +-    <shortcut
    +-        android:shortcutId="ms4"
    +-        android:shortcutShortLabel="@string/shortcut_title2"
    +-        >
    +-        <intent
    +-            android:action="android.intent.action.VIEW2"
    +-            >
    +-        </intent>
    +-        <categories />
    +-        <categories android:name="" />
    +-        <categories android:name="cat" />
    +-    </shortcut>
    +-    <shortcut
    +-        android:shortcutId="ms5"
    +-        android:shortcutShortLabel="@string/shortcut_title1"
    +-        >
    +-        <intent
    +-            android:action="action"
    +-            android:data="http://www/"
    +-            android:targetPackage="abc"
    +-            android:targetClass=".xyz"
    +-            android:mimeType="foo/bar"
    +-            >
    +-            <categories android:name="cat1" />
    +-            <categories android:name="cat2" />
    +-            <extra android:name="key1" android:value="value1" />
    +-            <extra android:name="key2" android:value="value2" />
    +-        </intent>
    +-    </shortcut>
    +-</shortcuts>
    +diff --git a/services/tests/servicestests/res/xml/shortcut_5_alt.xml b/services/tests/servicestests/res/xml/shortcut_5_alt.xml
    +deleted file mode 100644
    +index f79cd6f..0000000
    +--- a/services/tests/servicestests/res/xml/shortcut_5_alt.xml
    ++++ /dev/null
    +@@ -1,74 +0,0 @@
    +-<?xml version="1.0" encoding="utf-8"?>
    +-<!-- Copyright (C) 2016 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.
    +--->
    +-<shortcuts xmlns:android="http://schemas.android.com/apk/res/android" >
    +-    <shortcut
    +-        android:shortcutId="ms1_alt"
    +-        android:enabled="true"
    +-        android:icon="@drawable/icon1"
    +-        android:shortcutShortLabel="@string/shortcut_title1"
    +-        android:shortcutLongLabel="@string/shortcut_text1"
    +-        android:shortcutDisabledMessage="@string/shortcut_disabled_message1"
    +-        >
    +-        <intent
    +-            android:action="action1"
    +-            android:data="http://a.b.c/1"
    +-            >
    +-        </intent>
    +-        <categories android:name="android.shortcut.conversation" />
    +-        <categories android:name="android.shortcut.media" />
    +-    </shortcut>
    +-    <shortcut
    +-        android:shortcutId="ms2_alt"
    +-        android:enabled="true"
    +-        android:icon="@drawable/icon2"
    +-        android:shortcutShortLabel="@string/shortcut_title2"
    +-        android:shortcutLongLabel="@string/shortcut_text2"
    +-        android:shortcutDisabledMessage="@string/shortcut_disabled_message2"
    +-        >
    +-        <intent
    +-            android:action="action2"
    +-            >
    +-        </intent>
    +-        <categories android:name="android.shortcut.conversation" />
    +-    </shortcut>
    +-    <shortcut
    +-        android:shortcutId="ms3_alt"
    +-        android:shortcutShortLabel="@string/shortcut_title1"
    +-        >
    +-        <intent
    +-            android:action="android.intent.action.VIEW"
    +-            >
    +-        </intent>
    +-    </shortcut>
    +-    <shortcut
    +-        android:shortcutId="ms4_alt"
    +-        android:shortcutShortLabel="@string/shortcut_title1"
    +-        >
    +-        <intent
    +-            android:action="android.intent.action.VIEW"
    +-            >
    +-        </intent>
    +-    </shortcut>
    +-    <shortcut
    +-        android:shortcutId="ms5_alt"
    +-        android:shortcutShortLabel="@string/shortcut_title1"
    +-        >
    +-        <intent
    +-            android:action="android.intent.action.VIEW"
    +-            >
    +-        </intent>
    +-    </shortcut>
    +-</shortcuts>
    +diff --git a/services/tests/servicestests/res/xml/shortcut_5_reverse.xml b/services/tests/servicestests/res/xml/shortcut_5_reverse.xml
    +deleted file mode 100644
    +index d5b7c8f..0000000
    +--- a/services/tests/servicestests/res/xml/shortcut_5_reverse.xml
    ++++ /dev/null
    +@@ -1,78 +0,0 @@
    +-<?xml version="1.0" encoding="utf-8"?>
    +-<!-- Copyright (C) 2016 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.
    +--->
    +-<shortcuts xmlns:android="http://schemas.android.com/apk/res/android" >
    +-    <shortcut
    +-        android:shortcutId="ms5"
    +-        android:enabled="true"
    +-        android:icon="@drawable/icon1"
    +-        android:shortcutShortLabel="@string/shortcut_title1"
    +-        android:shortcutLongLabel="@string/shortcut_text1"
    +-        android:shortcutDisabledMessage="@string/shortcut_disabled_message1"
    +-        >
    +-        <intent
    +-            android:action="action1"
    +-            android:data="http://a.b.c/1"
    +-            >
    +-        </intent>
    +-        <categories android:name="android.shortcut.conversation" />
    +-        <categories android:name="android.shortcut.media" />
    +-    </shortcut>
    +-    <shortcut
    +-        android:shortcutId="ms4"
    +-        android:enabled="true"
    +-        android:icon="@drawable/icon2"
    +-        android:shortcutShortLabel="@string/shortcut_title2"
    +-        android:shortcutLongLabel="@string/shortcut_text2"
    +-        android:shortcutDisabledMessage="@string/shortcut_disabled_message2"
    +-        >
    +-        <intent
    +-            android:action="action2"
    +-            >
    +-        </intent>
    +-        <categories android:name="android.shortcut.conversation" />
    +-    </shortcut>
    +-    <shortcut
    +-        android:shortcutId="ms3"
    +-        android:shortcutShortLabel="@string/shortcut_title1"
    +-        >
    +-        <intent
    +-            android:action="android.intent.action.VIEW"
    +-            >
    +-        </intent>
    +-    </shortcut>
    +-    <shortcut
    +-        android:shortcutId="ms2"
    +-        android:shortcutShortLabel="@string/shortcut_title1"
    +-        >
    +-        <intent
    +-            android:action="android.intent.action.VIEW"
    +-            >
    +-        </intent>
    +-    </shortcut>
    +-    <shortcut
    +-        android:shortcutId="ms1"
    +-        android:shortcutShortLabel="@string/shortcut_title1"
    +-        >
    +-        <intent
    +-            android:action="action"
    +-            >
    +-            <categories android:name="cat1" />
    +-            <categories android:name="cat2" />
    +-            <extra android:name="key1" android:value="value1" />
    +-            <extra android:name="key2" android:value="value2" />
    +-        </intent>
    +-    </shortcut>
    +-</shortcuts>
    +diff --git a/services/tests/servicestests/res/xml/shortcut_error_1.xml b/services/tests/servicestests/res/xml/shortcut_error_1.xml
    +deleted file mode 100644
    +index 3990d02..0000000
    +--- a/services/tests/servicestests/res/xml/shortcut_error_1.xml
    ++++ /dev/null
    +@@ -1,34 +0,0 @@
    +-<?xml version="1.0" encoding="utf-8"?>
    +-<!-- Copyright (C) 2016 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.
    +--->
    +-<shortcuts xmlns:android="http://schemas.android.com/apk/res/android" >
    +-    <shortcut
    +-        android:shortcutShortLabel="@string/shortcut_title1"
    +-        >
    +-        <intent
    +-            android:action="android.intent.action.VIEW"
    +-            >
    +-        </intent>
    +-    </shortcut>
    +-    <shortcut
    +-        android:shortcutId="x1"
    +-        android:shortcutShortLabel="@string/shortcut_title1"
    +-        >
    +-        <intent
    +-            android:action="android.intent.action.VIEW"
    +-            >
    +-        </intent>
    +-    </shortcut>
    +-</shortcuts>
    +diff --git a/services/tests/servicestests/res/xml/shortcut_error_2.xml b/services/tests/servicestests/res/xml/shortcut_error_2.xml
    +deleted file mode 100644
    +index a6f7150..0000000
    +--- a/services/tests/servicestests/res/xml/shortcut_error_2.xml
    ++++ /dev/null
    +@@ -1,34 +0,0 @@
    +-<?xml version="1.0" encoding="utf-8"?>
    +-<!-- Copyright (C) 2016 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.
    +--->
    +-<shortcuts xmlns:android="http://schemas.android.com/apk/res/android" >
    +-    <shortcut
    +-        android:shortcutId="manifest-shortcut-3"
    +-        >
    +-        <intent
    +-            android:action="android.intent.action.VIEW"
    +-            >
    +-        </intent>
    +-    </shortcut>
    +-    <shortcut
    +-        android:shortcutId="x2"
    +-        android:shortcutShortLabel="@string/shortcut_title1"
    +-        >
    +-        <intent
    +-            android:action="android.intent.action.VIEW"
    +-            >
    +-        </intent>
    +-    </shortcut>
    +-</shortcuts>
    +diff --git a/services/tests/servicestests/res/xml/shortcut_error_3.xml b/services/tests/servicestests/res/xml/shortcut_error_3.xml
    +deleted file mode 100644
    +index 24ee024..0000000
    +--- a/services/tests/servicestests/res/xml/shortcut_error_3.xml
    ++++ /dev/null
    +@@ -1,36 +0,0 @@
    +-<?xml version="1.0" encoding="utf-8"?>
    +-<!-- Copyright (C) 2016 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.
    +--->
    +-<shortcuts xmlns:android="http://schemas.android.com/apk/res/android" >
    +-    <shortcut
    +-        android:shortcutId="manifest-shortcut-3"
    +-        android:shortcutShortLabel="@string/shortcut_title1"
    +-    />
    +-    <shortcut
    +-        android:shortcutId="@string/shortcut_title1"
    +-        android:shortcutShortLabel="@string/shortcut_title1"
    +-    />
    +-    <shortcut
    +-        android:shortcutId="x3"
    +-        android:shortcutShortLabel="@string/shortcut_title1"
    +-        >
    +-        <intent
    +-            android:action="android.intent.action.VIEW"
    +-            >
    +-        </intent>
    +-        <categories android:name="@string/shortcut_title1" />
    +-        <categories android:name="cat2" />
    +-    </shortcut>
    +-</shortcuts>
    +diff --git a/services/tests/servicestests/res/xml/shortcut_error_4.xml b/services/tests/servicestests/res/xml/shortcut_error_4.xml
    +deleted file mode 100644
    +index f680e99..0000000
    +--- a/services/tests/servicestests/res/xml/shortcut_error_4.xml
    ++++ /dev/null
    +@@ -1,70 +0,0 @@
    +-<?xml version="1.0" encoding="utf-8"?>
    +-<!-- Copyright (C) 2016 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.
    +--->
    +-<shortcuts xmlns:android="http://schemas.android.com/apk/res/android" >
    +-    <!-- This is valid -->
    +-    <shortcut
    +-        android:shortcutId="ms1"
    +-        android:shortcutShortLabel="@string/shortcut_title1"
    +-        >
    +-        <intent android:action="action1" >
    +-            <extra android:name="key1" android:value="value1" />
    +-        </intent>
    +-    </shortcut>
    +-
    +-    <!-- Invalid: no intent -->
    +-    <shortcut
    +-        android:shortcutId="ms_ignored1"
    +-        android:shortcutShortLabel="@string/shortcut_title1"
    +-        />
    +-
    +-    <!-- Valid: more than one intent -->
    +-    <shortcut
    +-        android:shortcutId="ms2"
    +-        android:shortcutShortLabel="@string/shortcut_title1"
    +-        >
    +-        <intent android:action="action2_1" >
    +-            <extra android:name="key1" android:value="value1" />
    +-        </intent>
    +-        <intent android:action="action2_2">
    +-            <extra android:name="key2" android:value="value2" />
    +-        </intent>
    +-    </shortcut>
    +-
    +-    <!-- Valid: disabled shortcut doesn't need an intent -->
    +-    <shortcut
    +-        android:shortcutId="ms3"
    +-        android:enabled="false"
    +-        android:shortcutShortLabel="@string/shortcut_title1"
    +-        />
    +-
    +-    <!-- Valid, but disabled shortcut's intent will be ignored. -->
    +-    <shortcut
    +-        android:shortcutId="ms4"
    +-        android:enabled="false"
    +-        android:shortcutShortLabel="@string/shortcut_title1"
    +-        >
    +-        <intent android:action="action4" />
    +-    </shortcut>
    +-
    +-    <!-- Invalid, no intent action (if any of the intents is invalid, the entire shortcut will be invalid.) -->
    +-    <shortcut
    +-        android:shortcutId="ms_ignored2"
    +-        android:shortcutShortLabel="@string/shortcut_title1"
    +-        >
    +-        <intent android:data="x"/>
    +-        <intent android:action="actionx"/>
    +-    </shortcut>
    +-</shortcuts>
    +diff --git a/services/tests/servicestests/src/android/net/IpUtilsTest.java b/services/tests/servicestests/src/android/net/IpUtilsTest.java
    +deleted file mode 100644
    +index c2d1608..0000000
    +--- a/services/tests/servicestests/src/android/net/IpUtilsTest.java
    ++++ /dev/null
    +@@ -1,162 +0,0 @@
    +-/*
    +- * Copyright (C) 2015 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 android.net.util;
    +-
    +-import android.net.util.IpUtils;
    +-import android.test.suitebuilder.annotation.SmallTest;
    +-
    +-import java.nio.ByteBuffer;
    +-
    +-import junit.framework.TestCase;
    +-
    +-
    +-public class IpUtilsTest extends TestCase {
    +-
    +-    private static final int IPV4_HEADER_LENGTH = 20;
    +-    private static final int IPV6_HEADER_LENGTH = 40;
    +-    private static final int TCP_HEADER_LENGTH = 20;
    +-    private static final int UDP_HEADER_LENGTH = 8;
    +-    private static final int IP_CHECKSUM_OFFSET = 10;
    +-    private static final int TCP_CHECKSUM_OFFSET = 16;
    +-    private static final int UDP_CHECKSUM_OFFSET = 6;
    +-
    +-    private int getUnsignedByte(ByteBuffer buf, int offset) {
    +-        return buf.get(offset) & 0xff;
    +-    }
    +-
    +-    private int getChecksum(ByteBuffer buf, int offset) {
    +-        return getUnsignedByte(buf, offset) * 256 + getUnsignedByte(buf, offset + 1);
    +-    }
    +-
    +-    private void assertChecksumEquals(int expected, short actual) {
    +-        assertEquals(Integer.toHexString(expected), Integer.toHexString(actual & 0xffff));
    +-    }
    +-
    +-    // Generate test packets using Python code like this::
    +-    //
    +-    // from scapy import all as scapy
    +-    //
    +-    // def JavaPacketDefinition(bytes):
    +-    //   out = "        ByteBuffer packet = ByteBuffer.wrap(new byte[] {\n            "
    +-    //   for i in xrange(len(bytes)):
    +-    //     out += "(byte) 0x%02x" % ord(bytes[i])
    +-    //     if i < len(bytes) - 1:
    +-    //       if i % 4 == 3:
    +-    //         out += ",\n            "
    +-    //       else:
    +-    //         out += ", "
    +-    //   out += "\n        });"
    +-    //   return out
    +-    //
    +-    // packet = (scapy.IPv6(src="2001:db8::1", dst="2001:db8::2") /
    +-    //           scapy.UDP(sport=12345, dport=7) /
    +-    //           "hello")
    +-    // print JavaPacketDefinition(str(packet))
    +-
    +-    @SmallTest
    +-    public void testIpv6TcpChecksum() throws Exception {
    +-        // packet = (scapy.IPv6(src="2001:db8::1", dst="2001:db8::2", tc=0x80) /
    +-        //           scapy.TCP(sport=12345, dport=7,
    +-        //                     seq=1692871236, ack=128376451, flags=16,
    +-        //                     window=32768) /
    +-        //           "hello, world")
    +-        ByteBuffer packet = ByteBuffer.wrap(new byte[] {
    +-            (byte) 0x68, (byte) 0x00, (byte) 0x00, (byte) 0x00,
    +-            (byte) 0x00, (byte) 0x20, (byte) 0x06, (byte) 0x40,
    +-            (byte) 0x20, (byte) 0x01, (byte) 0x0d, (byte) 0xb8,
    +-            (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
    +-            (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
    +-            (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x01,
    +-            (byte) 0x20, (byte) 0x01, (byte) 0x0d, (byte) 0xb8,
    +-            (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
    +-            (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
    +-            (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x02,
    +-            (byte) 0x30, (byte) 0x39, (byte) 0x00, (byte) 0x07,
    +-            (byte) 0x64, (byte) 0xe7, (byte) 0x2a, (byte) 0x44,
    +-            (byte) 0x07, (byte) 0xa6, (byte) 0xde, (byte) 0x83,
    +-            (byte) 0x50, (byte) 0x10, (byte) 0x80, (byte) 0x00,
    +-            (byte) 0xee, (byte) 0x71, (byte) 0x00, (byte) 0x00,
    +-            (byte) 0x68, (byte) 0x65, (byte) 0x6c, (byte) 0x6c,
    +-            (byte) 0x6f, (byte) 0x2c, (byte) 0x20, (byte) 0x77,
    +-            (byte) 0x6f, (byte) 0x72, (byte) 0x6c, (byte) 0x64
    +-        });
    +-
    +-        // Check that a valid packet has checksum 0.
    +-        int transportLen = packet.limit() - IPV6_HEADER_LENGTH;
    +-        assertEquals(0, IpUtils.tcpChecksum(packet, 0, IPV6_HEADER_LENGTH, transportLen));
    +-
    +-        // Check that we can calculate the checksum from scratch.
    +-        int sumOffset = IPV6_HEADER_LENGTH + TCP_CHECKSUM_OFFSET;
    +-        int sum = getUnsignedByte(packet, sumOffset) * 256 + getUnsignedByte(packet, sumOffset + 1);
    +-        assertEquals(0xee71, sum);
    +-
    +-        packet.put(sumOffset, (byte) 0);
    +-        packet.put(sumOffset + 1, (byte) 0);
    +-        assertChecksumEquals(sum, IpUtils.tcpChecksum(packet, 0, IPV6_HEADER_LENGTH, transportLen));
    +-
    +-        // Check that writing the checksum back into the packet results in a valid packet.
    +-        packet.putShort(
    +-            sumOffset,
    +-            IpUtils.tcpChecksum(packet, 0, IPV6_HEADER_LENGTH, transportLen));
    +-        assertEquals(0, IpUtils.tcpChecksum(packet, 0, IPV6_HEADER_LENGTH, transportLen));
    +-    }
    +-
    +-    @SmallTest
    +-    public void testIpv4UdpChecksum() {
    +-        // packet = (scapy.IP(src="192.0.2.1", dst="192.0.2.2", tos=0x40) /
    +-        //           scapy.UDP(sport=32012, dport=4500) /
    +-        //           "\xff")
    +-        ByteBuffer packet = ByteBuffer.wrap(new byte[] {
    +-            (byte) 0x45, (byte) 0x40, (byte) 0x00, (byte) 0x1d,
    +-            (byte) 0x00, (byte) 0x01, (byte) 0x00, (byte) 0x00,
    +-            (byte) 0x40, (byte) 0x11, (byte) 0xf6, (byte) 0x8b,
    +-            (byte) 0xc0, (byte) 0x00, (byte) 0x02, (byte) 0x01,
    +-            (byte) 0xc0, (byte) 0x00, (byte) 0x02, (byte) 0x02,
    +-            (byte) 0x7d, (byte) 0x0c, (byte) 0x11, (byte) 0x94,
    +-            (byte) 0x00, (byte) 0x09, (byte) 0xee, (byte) 0x36,
    +-            (byte) 0xff
    +-        });
    +-
    +-        // Check that a valid packet has IP checksum 0 and UDP checksum 0xffff (0 is not a valid
    +-        // UDP checksum, so the udpChecksum rewrites 0 to 0xffff).
    +-        assertEquals(0, IpUtils.ipChecksum(packet, 0));
    +-        assertEquals((short) 0xffff, IpUtils.udpChecksum(packet, 0, IPV4_HEADER_LENGTH));
    +-
    +-        // Check that we can calculate the checksums from scratch.
    +-        final int ipSumOffset = IP_CHECKSUM_OFFSET;
    +-        final int ipSum = getChecksum(packet, ipSumOffset);
    +-        assertEquals(0xf68b, ipSum);
    +-
    +-        packet.put(ipSumOffset, (byte) 0);
    +-        packet.put(ipSumOffset + 1, (byte) 0);
    +-        assertChecksumEquals(ipSum, IpUtils.ipChecksum(packet, 0));
    +-
    +-        final int udpSumOffset = IPV4_HEADER_LENGTH + UDP_CHECKSUM_OFFSET;
    +-        final int udpSum = getChecksum(packet, udpSumOffset);
    +-        assertEquals(0xee36, udpSum);
    +-
    +-        packet.put(udpSumOffset, (byte) 0);
    +-        packet.put(udpSumOffset + 1, (byte) 0);
    +-        assertChecksumEquals(udpSum, IpUtils.udpChecksum(packet, 0, IPV4_HEADER_LENGTH));
    +-
    +-        // Check that writing the checksums back into the packet results in a valid packet.
    +-        packet.putShort(ipSumOffset, IpUtils.ipChecksum(packet, 0));
    +-        packet.putShort(udpSumOffset, IpUtils.udpChecksum(packet, 0, IPV4_HEADER_LENGTH));
    +-        assertEquals(0, IpUtils.ipChecksum(packet, 0));
    +-        assertEquals((short) 0xffff, IpUtils.udpChecksum(packet, 0, IPV4_HEADER_LENGTH));
    +-    }
    +-}
    +diff --git a/services/tests/servicestests/src/android/net/UidRangeTest.java b/services/tests/servicestests/src/android/net/UidRangeTest.java
    +deleted file mode 100644
    +index 221fe0f..0000000
    +--- a/services/tests/servicestests/src/android/net/UidRangeTest.java
    ++++ /dev/null
    +@@ -1,112 +0,0 @@
    +-/*
    +- * Copyright (C) 2016 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 android.net;
    +-
    +-import android.os.Parcel;
    +-import android.test.suitebuilder.annotation.SmallTest;
    +-
    +-import junit.framework.TestCase;
    +-
    +-import static org.junit.Assert.assertArrayEquals;
    +-
    +-public class UidRangeTest extends TestCase {
    +-
    +-    static {
    +-        System.loadLibrary("servicestestsjni");
    +-    }
    +-
    +-    private static native byte[] readAndWriteNative(byte[] inParcel);
    +-    private static native int getStart(byte[] inParcel);
    +-    private static native int getStop(byte[] inParcel);
    +-
    +-    @SmallTest
    +-    public void testNativeParcelUnparcel() {
    +-        UidRange original = new UidRange(1234, Integer.MAX_VALUE);
    +-
    +-        byte[] inParcel = marshall(original);
    +-        byte[] outParcel = readAndWriteNative(inParcel);
    +-        UidRange roundTrip = unmarshall(outParcel);
    +-
    +-        assertEquals(original, roundTrip);
    +-        assertArrayEquals(inParcel, outParcel);
    +-    }
    +-
    +-    @SmallTest
    +-    public void testIndividualNativeFields() {
    +-        UidRange original = new UidRange(0x11115678, 0x22224321);
    +-        byte[] originalBytes = marshall(original);
    +-
    +-        assertEquals(original.start, getStart(originalBytes));
    +-        assertEquals(original.stop, getStop(originalBytes));
    +-    }
    +-
    +-    @SmallTest
    +-    public void testSingleItemUidRangeAllowed() {
    +-        new UidRange(123, 123);
    +-        new UidRange(0, 0);
    +-        new UidRange(Integer.MAX_VALUE, Integer.MAX_VALUE);
    +-    }
    +-
    +-    @SmallTest
    +-    public void testNegativeUidsDisallowed() {
    +-        try {
    +-            new UidRange(-2, 100);
    +-            fail("Exception not thrown for negative start UID");
    +-        } catch (IllegalArgumentException expected) {
    +-        }
    +-
    +-        try {
    +-            new UidRange(-200, -100);
    +-            fail("Exception not thrown for negative stop UID");
    +-        } catch (IllegalArgumentException expected) {
    +-        }
    +-    }
    +-
    +-    @SmallTest
    +-    public void testStopLessThanStartDisallowed() {
    +-        final int x = 4195000;
    +-        try {
    +-            new UidRange(x, x - 1);
    +-            fail("Exception not thrown for negative-length UID range");
    +-        } catch (IllegalArgumentException expected) {
    +-        }
    +-    }
    +-
    +-    /**
    +-     * Write a {@link UidRange} into an empty parcel and return the underlying data.
    +-     *
    +-     * @see unmarshall(byte[])
    +-     */
    +-    private static byte[] marshall(UidRange range) {
    +-        Parcel p = Parcel.obtain();
    +-        range.writeToParcel(p, /* flags */ 0);
    +-        p.setDataPosition(0);
    +-        return p.marshall();
    +-    }
    +-
    +-    /**
    +-     * Read raw bytes into a parcel, and read a {@link UidRange} back out of them.
    +-     *
    +-     * @see marshall(UidRange)
    +-     */
    +-    private static UidRange unmarshall(byte[] data) {
    +-        Parcel p = Parcel.obtain();
    +-        p.unmarshall(data, 0, data.length);
    +-        p.setDataPosition(0);
    +-        return UidRange.CREATOR.createFromParcel(p);
    +-    }
    +-}
    +diff --git a/services/tests/servicestests/src/android/net/apf/ApfTest.java b/services/tests/servicestests/src/android/net/apf/ApfTest.java
    +deleted file mode 100644
    +index bd76118..0000000
    +--- a/services/tests/servicestests/src/android/net/apf/ApfTest.java
    ++++ /dev/null
    +@@ -1,1092 +0,0 @@
    +-/*
    +- * Copyright (C) 2012 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 android.net.apf;
    +-
    +-import static android.system.OsConstants.*;
    +-
    +-import com.android.frameworks.servicestests.R;
    +-
    +-import android.net.apf.ApfCapabilities;
    +-import android.net.apf.ApfFilter;
    +-import android.net.apf.ApfGenerator;
    +-import android.net.apf.ApfGenerator.IllegalInstructionException;
    +-import android.net.apf.ApfGenerator.Register;
    +-import android.net.ip.IpManager;
    +-import android.net.metrics.IpConnectivityLog;
    +-import android.net.metrics.RaEvent;
    +-import android.net.LinkAddress;
    +-import android.net.LinkProperties;
    +-import android.os.ConditionVariable;
    +-import android.os.Parcelable;
    +-import android.system.ErrnoException;
    +-import android.system.Os;
    +-import android.test.AndroidTestCase;
    +-import android.test.suitebuilder.annotation.LargeTest;
    +-
    +-import org.mockito.ArgumentCaptor;
    +-import org.mockito.Mock;
    +-import org.mockito.MockitoAnnotations;
    +-import static org.mockito.Mockito.atLeastOnce;
    +-import static org.mockito.Mockito.verify;
    +-
    +-import java.io.File;
    +-import java.io.FileDescriptor;
    +-import java.io.FileOutputStream;
    +-import java.io.IOException;
    +-import java.io.InputStream;
    +-import java.io.OutputStream;
    +-import java.net.InetAddress;
    +-import java.net.NetworkInterface;
    +-import java.nio.ByteBuffer;
    +-import java.util.List;
    +-
    +-import libcore.io.IoUtils;
    +-import libcore.io.Streams;
    +-
    +-/**
    +- * Tests for APF program generator and interpreter.
    +- *
    +- * Build, install and run with:
    +- *  runtest frameworks-services -c com.android.server.ApfTest
    +- */
    +-public class ApfTest extends AndroidTestCase {
    +-    private static final int TIMEOUT_MS = 500;
    +-
    +-    @Mock IpConnectivityLog mLog;
    +-
    +-    @Override
    +-    public void setUp() throws Exception {
    +-        super.setUp();
    +-        MockitoAnnotations.initMocks(this);
    +-        // Load up native shared library containing APF interpreter exposed via JNI.
    +-        System.loadLibrary("servicestestsjni");
    +-    }
    +-
    +-    // Expected return codes from APF interpreter.
    +-    private final static int PASS = 1;
    +-    private final static int DROP = 0;
    +-    // Interpreter will just accept packets without link layer headers, so pad fake packet to at
    +-    // least the minimum packet size.
    +-    private final static int MIN_PKT_SIZE = 15;
    +-
    +-    private final static boolean DROP_MULTICAST = true;
    +-    private final static boolean ALLOW_MULTICAST = false;
    +-
    +-    private void assertVerdict(int expected, byte[] program, byte[] packet, int filterAge) {
    +-        assertEquals(expected, apfSimulate(program, packet, filterAge));
    +-    }
    +-
    +-    private void assertPass(byte[] program, byte[] packet, int filterAge) {
    +-        assertVerdict(PASS, program, packet, filterAge);
    +-    }
    +-
    +-    private void assertDrop(byte[] program, byte[] packet, int filterAge) {
    +-        assertVerdict(DROP, program, packet, filterAge);
    +-    }
    +-
    +-    private void assertVerdict(int expected, ApfGenerator gen, byte[] packet, int filterAge)
    +-            throws IllegalInstructionException {
    +-        assertEquals(expected, apfSimulate(gen.generate(), packet, filterAge));
    +-    }
    +-
    +-    private void assertPass(ApfGenerator gen, byte[] packet, int filterAge)
    +-            throws IllegalInstructionException {
    +-        assertVerdict(PASS, gen, packet, filterAge);
    +-    }
    +-
    +-    private void assertDrop(ApfGenerator gen, byte[] packet, int filterAge)
    +-            throws IllegalInstructionException {
    +-        assertVerdict(DROP, gen, packet, filterAge);
    +-    }
    +-
    +-    private void assertPass(ApfGenerator gen)
    +-            throws IllegalInstructionException {
    +-        assertVerdict(PASS, gen, new byte[MIN_PKT_SIZE], 0);
    +-    }
    +-
    +-    private void assertDrop(ApfGenerator gen)
    +-            throws IllegalInstructionException {
    +-        assertVerdict(DROP, gen, new byte[MIN_PKT_SIZE], 0);
    +-    }
    +-
    +-    /**
    +-     * Test each instruction by generating a program containing the instruction,
    +-     * generating bytecode for that program and running it through the
    +-     * interpreter to verify it functions correctly.
    +-     */
    +-    @LargeTest
    +-    public void testApfInstructions() throws IllegalInstructionException {
    +-        // Empty program should pass because having the program counter reach the
    +-        // location immediately after the program indicates the packet should be
    +-        // passed to the AP.
    +-        ApfGenerator gen = new ApfGenerator();
    +-        assertPass(gen);
    +-
    +-        // Test jumping to pass label.
    +-        gen = new ApfGenerator();
    +-        gen.addJump(gen.PASS_LABEL);
    +-        byte[] program = gen.generate();
    +-        assertEquals(1, program.length);
    +-        assertEquals((14 << 3) | (0 << 1) | 0, program[0]);
    +-        assertPass(program, new byte[MIN_PKT_SIZE], 0);
    +-
    +-        // Test jumping to drop label.
    +-        gen = new ApfGenerator();
    +-        gen.addJump(gen.DROP_LABEL);
    +-        program = gen.generate();
    +-        assertEquals(2, program.length);
    +-        assertEquals((14 << 3) | (1 << 1) | 0, program[0]);
    +-        assertEquals(1, program[1]);
    +-        assertDrop(program, new byte[15], 15);
    +-
    +-        // Test jumping if equal to 0.
    +-        gen = new ApfGenerator();
    +-        gen.addJumpIfR0Equals(0, gen.DROP_LABEL);
    +-        assertDrop(gen);
    +-
    +-        // Test jumping if not equal to 0.
    +-        gen = new ApfGenerator();
    +-        gen.addJumpIfR0NotEquals(0, gen.DROP_LABEL);
    +-        assertPass(gen);
    +-        gen = new ApfGenerator();
    +-        gen.addLoadImmediate(Register.R0, 1);
    +-        gen.addJumpIfR0NotEquals(0, gen.DROP_LABEL);
    +-        assertDrop(gen);
    +-
    +-        // Test jumping if registers equal.
    +-        gen = new ApfGenerator();
    +-        gen.addJumpIfR0EqualsR1(gen.DROP_LABEL);
    +-        assertDrop(gen);
    +-
    +-        // Test jumping if registers not equal.
    +-        gen = new ApfGenerator();
    +-        gen.addJumpIfR0NotEqualsR1(gen.DROP_LABEL);
    +-        assertPass(gen);
    +-        gen = new ApfGenerator();
    +-        gen.addLoadImmediate(Register.R0, 1);
    +-        gen.addJumpIfR0NotEqualsR1(gen.DROP_LABEL);
    +-        assertDrop(gen);
    +-
    +-        // Test load immediate.
    +-        gen = new ApfGenerator();
    +-        gen.addLoadImmediate(Register.R0, 1234567890);
    +-        gen.addJumpIfR0Equals(1234567890, gen.DROP_LABEL);
    +-        assertDrop(gen);
    +-
    +-        // Test add.
    +-        gen = new ApfGenerator();
    +-        gen.addAdd(1234567890);
    +-        gen.addJumpIfR0Equals(1234567890, gen.DROP_LABEL);
    +-        assertDrop(gen);
    +-
    +-        // Test subtract.
    +-        gen = new ApfGenerator();
    +-        gen.addAdd(-1234567890);
    +-        gen.addJumpIfR0Equals(-1234567890, gen.DROP_LABEL);
    +-        assertDrop(gen);
    +-
    +-        // Test or.
    +-        gen = new ApfGenerator();
    +-        gen.addOr(1234567890);
    +-        gen.addJumpIfR0Equals(1234567890, gen.DROP_LABEL);
    +-        assertDrop(gen);
    +-
    +-        // Test and.
    +-        gen = new ApfGenerator();
    +-        gen.addLoadImmediate(Register.R0, 1234567890);
    +-        gen.addAnd(123456789);
    +-        gen.addJumpIfR0Equals(1234567890 & 123456789, gen.DROP_LABEL);
    +-        assertDrop(gen);
    +-
    +-        // Test left shift.
    +-        gen = new ApfGenerator();
    +-        gen.addLoadImmediate(Register.R0, 1234567890);
    +-        gen.addLeftShift(1);
    +-        gen.addJumpIfR0Equals(1234567890 << 1, gen.DROP_LABEL);
    +-        assertDrop(gen);
    +-
    +-        // Test right shift.
    +-        gen = new ApfGenerator();
    +-        gen.addLoadImmediate(Register.R0, 1234567890);
    +-        gen.addRightShift(1);
    +-        gen.addJumpIfR0Equals(1234567890 >> 1, gen.DROP_LABEL);
    +-        assertDrop(gen);
    +-
    +-        // Test multiply.
    +-        gen = new ApfGenerator();
    +-        gen.addLoadImmediate(Register.R0, 1234567890);
    +-        gen.addMul(2);
    +-        gen.addJumpIfR0Equals(1234567890 * 2, gen.DROP_LABEL);
    +-        assertDrop(gen);
    +-
    +-        // Test divide.
    +-        gen = new ApfGenerator();
    +-        gen.addLoadImmediate(Register.R0, 1234567890);
    +-        gen.addDiv(2);
    +-        gen.addJumpIfR0Equals(1234567890 / 2, gen.DROP_LABEL);
    +-        assertDrop(gen);
    +-
    +-        // Test divide by zero.
    +-        gen = new ApfGenerator();
    +-        gen.addDiv(0);
    +-        gen.addJump(gen.DROP_LABEL);
    +-        assertPass(gen);
    +-
    +-        // Test add.
    +-        gen = new ApfGenerator();
    +-        gen.addLoadImmediate(Register.R1, 1234567890);
    +-        gen.addAddR1();
    +-        gen.addJumpIfR0Equals(1234567890, gen.DROP_LABEL);
    +-        assertDrop(gen);
    +-
    +-        // Test subtract.
    +-        gen = new ApfGenerator();
    +-        gen.addLoadImmediate(Register.R1, -1234567890);
    +-        gen.addAddR1();
    +-        gen.addJumpIfR0Equals(-1234567890, gen.DROP_LABEL);
    +-        assertDrop(gen);
    +-
    +-        // Test or.
    +-        gen = new ApfGenerator();
    +-        gen.addLoadImmediate(Register.R1, 1234567890);
    +-        gen.addOrR1();
    +-        gen.addJumpIfR0Equals(1234567890, gen.DROP_LABEL);
    +-        assertDrop(gen);
    +-
    +-        // Test and.
    +-        gen = new ApfGenerator();
    +-        gen.addLoadImmediate(Register.R0, 1234567890);
    +-        gen.addLoadImmediate(Register.R1, 123456789);
    +-        gen.addAndR1();
    +-        gen.addJumpIfR0Equals(1234567890 & 123456789, gen.DROP_LABEL);
    +-        assertDrop(gen);
    +-
    +-        // Test left shift.
    +-        gen = new ApfGenerator();
    +-        gen.addLoadImmediate(Register.R0, 1234567890);
    +-        gen.addLoadImmediate(Register.R1, 1);
    +-        gen.addLeftShiftR1();
    +-        gen.addJumpIfR0Equals(1234567890 << 1, gen.DROP_LABEL);
    +-        assertDrop(gen);
    +-
    +-        // Test right shift.
    +-        gen = new ApfGenerator();
    +-        gen.addLoadImmediate(Register.R0, 1234567890);
    +-        gen.addLoadImmediate(Register.R1, -1);
    +-        gen.addLeftShiftR1();
    +-        gen.addJumpIfR0Equals(1234567890 >> 1, gen.DROP_LABEL);
    +-        assertDrop(gen);
    +-
    +-        // Test multiply.
    +-        gen = new ApfGenerator();
    +-        gen.addLoadImmediate(Register.R0, 1234567890);
    +-        gen.addLoadImmediate(Register.R1, 2);
    +-        gen.addMulR1();
    +-        gen.addJumpIfR0Equals(1234567890 * 2, gen.DROP_LABEL);
    +-        assertDrop(gen);
    +-
    +-        // Test divide.
    +-        gen = new ApfGenerator();
    +-        gen.addLoadImmediate(Register.R0, 1234567890);
    +-        gen.addLoadImmediate(Register.R1, 2);
    +-        gen.addDivR1();
    +-        gen.addJumpIfR0Equals(1234567890 / 2, gen.DROP_LABEL);
    +-        assertDrop(gen);
    +-
    +-        // Test divide by zero.
    +-        gen = new ApfGenerator();
    +-        gen.addDivR1();
    +-        gen.addJump(gen.DROP_LABEL);
    +-        assertPass(gen);
    +-
    +-        // Test byte load.
    +-        gen = new ApfGenerator();
    +-        gen.addLoad8(Register.R0, 1);
    +-        gen.addJumpIfR0Equals(45, gen.DROP_LABEL);
    +-        assertDrop(gen, new byte[]{123,45,0,0,0,0,0,0,0,0,0,0,0,0,0}, 0);
    +-
    +-        // Test out of bounds load.
    +-        gen = new ApfGenerator();
    +-        gen.addLoad8(Register.R0, 16);
    +-        gen.addJumpIfR0Equals(0, gen.DROP_LABEL);
    +-        assertPass(gen, new byte[]{123,45,0,0,0,0,0,0,0,0,0,0,0,0,0}, 0);
    +-
    +-        // Test half-word load.
    +-        gen = new ApfGenerator();
    +-        gen.addLoad16(Register.R0, 1);
    +-        gen.addJumpIfR0Equals((45 << 8) | 67, gen.DROP_LABEL);
    +-        assertDrop(gen, new byte[]{123,45,67,0,0,0,0,0,0,0,0,0,0,0,0}, 0);
    +-
    +-        // Test word load.
    +-        gen = new ApfGenerator();
    +-        gen.addLoad32(Register.R0, 1);
    +-        gen.addJumpIfR0Equals((45 << 24) | (67 << 16) | (89 << 8) | 12, gen.DROP_LABEL);
    +-        assertDrop(gen, new byte[]{123,45,67,89,12,0,0,0,0,0,0,0,0,0,0}, 0);
    +-
    +-        // Test byte indexed load.
    +-        gen = new ApfGenerator();
    +-        gen.addLoadImmediate(Register.R1, 1);
    +-        gen.addLoad8Indexed(Register.R0, 0);
    +-        gen.addJumpIfR0Equals(45, gen.DROP_LABEL);
    +-        assertDrop(gen, new byte[]{123,45,0,0,0,0,0,0,0,0,0,0,0,0,0}, 0);
    +-
    +-        // Test out of bounds indexed load.
    +-        gen = new ApfGenerator();
    +-        gen.addLoadImmediate(Register.R1, 8);
    +-        gen.addLoad8Indexed(Register.R0, 8);
    +-        gen.addJumpIfR0Equals(0, gen.DROP_LABEL);
    +-        assertPass(gen, new byte[]{123,45,0,0,0,0,0,0,0,0,0,0,0,0,0}, 0);
    +-
    +-        // Test half-word indexed load.
    +-        gen = new ApfGenerator();
    +-        gen.addLoadImmediate(Register.R1, 1);
    +-        gen.addLoad16Indexed(Register.R0, 0);
    +-        gen.addJumpIfR0Equals((45 << 8) | 67, gen.DROP_LABEL);
    +-        assertDrop(gen, new byte[]{123,45,67,0,0,0,0,0,0,0,0,0,0,0,0}, 0);
    +-
    +-        // Test word indexed load.
    +-        gen = new ApfGenerator();
    +-        gen.addLoadImmediate(Register.R1, 1);
    +-        gen.addLoad32Indexed(Register.R0, 0);
    +-        gen.addJumpIfR0Equals((45 << 24) | (67 << 16) | (89 << 8) | 12, gen.DROP_LABEL);
    +-        assertDrop(gen, new byte[]{123,45,67,89,12,0,0,0,0,0,0,0,0,0,0}, 0);
    +-
    +-        // Test jumping if greater than.
    +-        gen = new ApfGenerator();
    +-        gen.addJumpIfR0GreaterThan(0, gen.DROP_LABEL);
    +-        assertPass(gen);
    +-        gen = new ApfGenerator();
    +-        gen.addLoadImmediate(Register.R0, 1);
    +-        gen.addJumpIfR0GreaterThan(0, gen.DROP_LABEL);
    +-        assertDrop(gen);
    +-
    +-        // Test jumping if less than.
    +-        gen = new ApfGenerator();
    +-        gen.addJumpIfR0LessThan(0, gen.DROP_LABEL);
    +-        assertPass(gen);
    +-        gen = new ApfGenerator();
    +-        gen.addJumpIfR0LessThan(1, gen.DROP_LABEL);
    +-        assertDrop(gen);
    +-
    +-        // Test jumping if any bits set.
    +-        gen = new ApfGenerator();
    +-        gen.addJumpIfR0AnyBitsSet(3, gen.DROP_LABEL);
    +-        assertPass(gen);
    +-        gen = new ApfGenerator();
    +-        gen.addLoadImmediate(Register.R0, 1);
    +-        gen.addJumpIfR0AnyBitsSet(3, gen.DROP_LABEL);
    +-        assertDrop(gen);
    +-        gen = new ApfGenerator();
    +-        gen.addLoadImmediate(Register.R0, 3);
    +-        gen.addJumpIfR0AnyBitsSet(3, gen.DROP_LABEL);
    +-        assertDrop(gen);
    +-
    +-        // Test jumping if register greater than.
    +-        gen = new ApfGenerator();
    +-        gen.addJumpIfR0GreaterThanR1(gen.DROP_LABEL);
    +-        assertPass(gen);
    +-        gen = new ApfGenerator();
    +-        gen.addLoadImmediate(Register.R0, 2);
    +-        gen.addLoadImmediate(Register.R1, 1);
    +-        gen.addJumpIfR0GreaterThanR1(gen.DROP_LABEL);
    +-        assertDrop(gen);
    +-
    +-        // Test jumping if register less than.
    +-        gen = new ApfGenerator();
    +-        gen.addJumpIfR0LessThanR1(gen.DROP_LABEL);
    +-        assertPass(gen);
    +-        gen = new ApfGenerator();
    +-        gen.addLoadImmediate(Register.R1, 1);
    +-        gen.addJumpIfR0LessThanR1(gen.DROP_LABEL);
    +-        assertDrop(gen);
    +-
    +-        // Test jumping if any bits set in register.
    +-        gen = new ApfGenerator();
    +-        gen.addLoadImmediate(Register.R1, 3);
    +-        gen.addJumpIfR0AnyBitsSetR1(gen.DROP_LABEL);
    +-        assertPass(gen);
    +-        gen = new ApfGenerator();
    +-        gen.addLoadImmediate(Register.R1, 3);
    +-        gen.addLoadImmediate(Register.R0, 1);
    +-        gen.addJumpIfR0AnyBitsSetR1(gen.DROP_LABEL);
    +-        assertDrop(gen);
    +-        gen = new ApfGenerator();
    +-        gen.addLoadImmediate(Register.R1, 3);
    +-        gen.addLoadImmediate(Register.R0, 3);
    +-        gen.addJumpIfR0AnyBitsSetR1(gen.DROP_LABEL);
    +-        assertDrop(gen);
    +-
    +-        // Test load from memory.
    +-        gen = new ApfGenerator();
    +-        gen.addLoadFromMemory(Register.R0, 0);
    +-        gen.addJumpIfR0Equals(0, gen.DROP_LABEL);
    +-        assertDrop(gen);
    +-
    +-        // Test store to memory.
    +-        gen = new ApfGenerator();
    +-        gen.addLoadImmediate(Register.R1, 1234567890);
    +-        gen.addStoreToMemory(Register.R1, 12);
    +-        gen.addLoadFromMemory(Register.R0, 12);
    +-        gen.addJumpIfR0Equals(1234567890, gen.DROP_LABEL);
    +-        assertDrop(gen);
    +-
    +-        // Test filter age pre-filled memory.
    +-        gen = new ApfGenerator();
    +-        gen.addLoadFromMemory(Register.R0, gen.FILTER_AGE_MEMORY_SLOT);
    +-        gen.addJumpIfR0Equals(1234567890, gen.DROP_LABEL);
    +-        assertDrop(gen, new byte[MIN_PKT_SIZE], 1234567890);
    +-
    +-        // Test packet size pre-filled memory.
    +-        gen = new ApfGenerator();
    +-        gen.addLoadFromMemory(Register.R0, gen.PACKET_SIZE_MEMORY_SLOT);
    +-        gen.addJumpIfR0Equals(MIN_PKT_SIZE, gen.DROP_LABEL);
    +-        assertDrop(gen);
    +-
    +-        // Test IPv4 header size pre-filled memory.
    +-        gen = new ApfGenerator();
    +-        gen.addLoadFromMemory(Register.R0, gen.IPV4_HEADER_SIZE_MEMORY_SLOT);
    +-        gen.addJumpIfR0Equals(20, gen.DROP_LABEL);
    +-        assertDrop(gen, new byte[]{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0x45}, 0);
    +-
    +-        // Test not.
    +-        gen = new ApfGenerator();
    +-        gen.addLoadImmediate(Register.R0, 1234567890);
    +-        gen.addNot(Register.R0);
    +-        gen.addJumpIfR0Equals(~1234567890, gen.DROP_LABEL);
    +-        assertDrop(gen);
    +-
    +-        // Test negate.
    +-        gen = new ApfGenerator();
    +-        gen.addLoadImmediate(Register.R0, 1234567890);
    +-        gen.addNeg(Register.R0);
    +-        gen.addJumpIfR0Equals(-1234567890, gen.DROP_LABEL);
    +-        assertDrop(gen);
    +-
    +-        // Test move.
    +-        gen = new ApfGenerator();
    +-        gen.addLoadImmediate(Register.R1, 1234567890);
    +-        gen.addMove(Register.R0);
    +-        gen.addJumpIfR0Equals(1234567890, gen.DROP_LABEL);
    +-        assertDrop(gen);
    +-        gen = new ApfGenerator();
    +-        gen.addLoadImmediate(Register.R0, 1234567890);
    +-        gen.addMove(Register.R1);
    +-        gen.addJumpIfR0Equals(1234567890, gen.DROP_LABEL);
    +-        assertDrop(gen);
    +-
    +-        // Test swap.
    +-        gen = new ApfGenerator();
    +-        gen.addLoadImmediate(Register.R1, 1234567890);
    +-        gen.addSwap();
    +-        gen.addJumpIfR0Equals(1234567890, gen.DROP_LABEL);
    +-        assertDrop(gen);
    +-        gen = new ApfGenerator();
    +-        gen.addLoadImmediate(Register.R0, 1234567890);
    +-        gen.addSwap();
    +-        gen.addJumpIfR0Equals(0, gen.DROP_LABEL);
    +-        assertDrop(gen);
    +-
    +-        // Test jump if bytes not equal.
    +-        gen = new ApfGenerator();
    +-        gen.addLoadImmediate(Register.R0, 1);
    +-        gen.addJumpIfBytesNotEqual(Register.R0, new byte[]{123}, gen.DROP_LABEL);
    +-        program = gen.generate();
    +-        assertEquals(6, program.length);
    +-        assertEquals((13 << 3) | (1 << 1) | 0, program[0]);
    +-        assertEquals(1, program[1]);
    +-        assertEquals(((20 << 3) | (1 << 1) | 0) - 256, program[2]);
    +-        assertEquals(1, program[3]);
    +-        assertEquals(1, program[4]);
    +-        assertEquals(123, program[5]);
    +-        assertDrop(program, new byte[MIN_PKT_SIZE], 0);
    +-        gen = new ApfGenerator();
    +-        gen.addLoadImmediate(Register.R0, 1);
    +-        gen.addJumpIfBytesNotEqual(Register.R0, new byte[]{123}, gen.DROP_LABEL);
    +-        byte[] packet123 = new byte[]{0,123,0,0,0,0,0,0,0,0,0,0,0,0,0};
    +-        assertPass(gen, packet123, 0);
    +-        gen = new ApfGenerator();
    +-        gen.addJumpIfBytesNotEqual(Register.R0, new byte[]{123}, gen.DROP_LABEL);
    +-        assertDrop(gen, packet123, 0);
    +-        gen = new ApfGenerator();
    +-        gen.addLoadImmediate(Register.R0, 1);
    +-        gen.addJumpIfBytesNotEqual(Register.R0, new byte[]{1,2,30,4,5}, gen.DROP_LABEL);
    +-        byte[] packet12345 = new byte[]{0,1,2,3,4,5,0,0,0,0,0,0,0,0,0};
    +-        assertDrop(gen, packet12345, 0);
    +-        gen = new ApfGenerator();
    +-        gen.addLoadImmediate(Register.R0, 1);
    +-        gen.addJumpIfBytesNotEqual(Register.R0, new byte[]{1,2,3,4,5}, gen.DROP_LABEL);
    +-        assertPass(gen, packet12345, 0);
    +-    }
    +-
    +-    /**
    +-     * Generate some BPF programs, translate them to APF, then run APF and BPF programs
    +-     * over packet traces and verify both programs filter out the same packets.
    +-     */
    +-    @LargeTest
    +-    public void testApfAgainstBpf() throws Exception {
    +-        String[] tcpdump_filters = new String[]{ "udp", "tcp", "icmp", "icmp6", "udp port 53",
    +-                "arp", "dst 239.255.255.250", "arp or tcp or udp port 53", "net 192.168.1.0/24",
    +-                "arp or icmp6 or portrange 53-54", "portrange 53-54 or portrange 100-50000",
    +-                "tcp[tcpflags] & (tcp-ack|tcp-fin) != 0 and (ip[2:2] > 57 or icmp)" };
    +-        String pcap_filename = stageFile(R.raw.apf);
    +-        for (String tcpdump_filter : tcpdump_filters) {
    +-            byte[] apf_program = Bpf2Apf.convert(compileToBpf(tcpdump_filter));
    +-            assertTrue("Failed to match for filter: " + tcpdump_filter,
    +-                    compareBpfApf(tcpdump_filter, pcap_filename, apf_program));
    +-        }
    +-    }
    +-
    +-    private class MockIpManagerCallback extends IpManager.Callback {
    +-        private final ConditionVariable mGotApfProgram = new ConditionVariable();
    +-        private byte[] mLastApfProgram;
    +-
    +-        @Override
    +-        public void installPacketFilter(byte[] filter) {
    +-            mLastApfProgram = filter;
    +-            mGotApfProgram.open();
    +-        }
    +-
    +-        public void resetApfProgramWait() {
    +-            mGotApfProgram.close();
    +-        }
    +-
    +-        public byte[] getApfProgram() {
    +-            assertTrue(mGotApfProgram.block(TIMEOUT_MS));
    +-            return mLastApfProgram;
    +-        }
    +-
    +-        public void assertNoProgramUpdate() {
    +-            assertFalse(mGotApfProgram.block(TIMEOUT_MS));
    +-        }
    +-    }
    +-
    +-    private static class TestApfFilter extends ApfFilter {
    +-        public final static byte[] MOCK_MAC_ADDR = new byte[]{1,2,3,4,5,6};
    +-        private FileDescriptor mWriteSocket;
    +-
    +-        public TestApfFilter(IpManager.Callback ipManagerCallback, boolean multicastFilter,
    +-                IpConnectivityLog log) throws Exception {
    +-            super(new ApfCapabilities(2, 1536, ARPHRD_ETHER), NetworkInterface.getByName("lo"),
    +-                    ipManagerCallback, multicastFilter, log);
    +-        }
    +-
    +-        // Pretend an RA packet has been received and show it to ApfFilter.
    +-        public void pretendPacketReceived(byte[] packet) throws IOException, ErrnoException {
    +-            // ApfFilter's ReceiveThread will be waiting to read this.
    +-            Os.write(mWriteSocket, packet, 0, packet.length);
    +-        }
    +-
    +-        @Override
    +-        void maybeStartFilter() {
    +-            mHardwareAddress = MOCK_MAC_ADDR;
    +-            installNewProgramLocked();
    +-
    +-            // Create two sockets, "readSocket" and "mWriteSocket" and connect them together.
    +-            FileDescriptor readSocket = new FileDescriptor();
    +-            mWriteSocket = new FileDescriptor();
    +-            try {
    +-                Os.socketpair(AF_UNIX, SOCK_STREAM, 0, mWriteSocket, readSocket);
    +-            } catch (ErrnoException e) {
    +-                fail();
    +-                return;
    +-            }
    +-            // Now pass readSocket to ReceiveThread as if it was setup to read raw RAs.
    +-            // This allows us to pretend RA packets have been recieved via pretendPacketReceived().
    +-            mReceiveThread = new ReceiveThread(readSocket);
    +-            mReceiveThread.start();
    +-        }
    +-
    +-        @Override
    +-        public void shutdown() {
    +-            super.shutdown();
    +-            IoUtils.closeQuietly(mWriteSocket);
    +-        }
    +-    }
    +-
    +-    private static final int ETH_HEADER_LEN = 14;
    +-    private static final int ETH_DEST_ADDR_OFFSET = 0;
    +-    private static final int ETH_ETHERTYPE_OFFSET = 12;
    +-    private static final byte[] ETH_BROADCAST_MAC_ADDRESS = new byte[]{
    +-        (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff };
    +-
    +-    private static final int IPV4_VERSION_IHL_OFFSET = ETH_HEADER_LEN + 0;
    +-    private static final int IPV4_PROTOCOL_OFFSET = ETH_HEADER_LEN + 9;
    +-    private static final int IPV4_DEST_ADDR_OFFSET = ETH_HEADER_LEN + 16;
    +-
    +-    private static final int IPV6_NEXT_HEADER_OFFSET = ETH_HEADER_LEN + 6;
    +-    private static final int IPV6_HEADER_LEN = 40;
    +-    private static final int IPV6_DEST_ADDR_OFFSET = ETH_HEADER_LEN + 24;
    +-    // The IPv6 all nodes address ff02::1
    +-    private static final byte[] IPV6_ALL_NODES_ADDRESS =
    +-            new byte[]{ (byte) 0xff, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 };
    +-
    +-    private static final int ICMP6_TYPE_OFFSET = ETH_HEADER_LEN + IPV6_HEADER_LEN;
    +-    private static final int ICMP6_ROUTER_ADVERTISEMENT = 134;
    +-    private static final int ICMP6_NEIGHBOR_ANNOUNCEMENT = 136;
    +-
    +-    private static final int ICMP6_RA_HEADER_LEN = 16;
    +-    private static final int ICMP6_RA_ROUTER_LIFETIME_OFFSET =
    +-            ETH_HEADER_LEN + IPV6_HEADER_LEN + 6;
    +-    private static final int ICMP6_RA_CHECKSUM_OFFSET =
    +-            ETH_HEADER_LEN + IPV6_HEADER_LEN + 2;
    +-    private static final int ICMP6_RA_OPTION_OFFSET =
    +-            ETH_HEADER_LEN + IPV6_HEADER_LEN + ICMP6_RA_HEADER_LEN;
    +-
    +-    private static final int ICMP6_PREFIX_OPTION_TYPE = 3;
    +-    private static final int ICMP6_PREFIX_OPTION_LEN = 32;
    +-    private static final int ICMP6_PREFIX_OPTION_VALID_LIFETIME_OFFSET = 4;
    +-    private static final int ICMP6_PREFIX_OPTION_PREFERRED_LIFETIME_OFFSET = 8;
    +-
    +-    // From RFC6106: Recursive DNS Server option
    +-    private static final int ICMP6_RDNSS_OPTION_TYPE = 25;
    +-    // From RFC6106: DNS Search List option
    +-    private static final int ICMP6_DNSSL_OPTION_TYPE = 31;
    +-
    +-    // From RFC4191: Route Information option
    +-    private static final int ICMP6_ROUTE_INFO_OPTION_TYPE = 24;
    +-    // Above three options all have the same format:
    +-    private static final int ICMP6_4_BYTE_OPTION_LEN = 8;
    +-    private static final int ICMP6_4_BYTE_LIFETIME_OFFSET = 4;
    +-    private static final int ICMP6_4_BYTE_LIFETIME_LEN = 4;
    +-
    +-    private static final int UDP_HEADER_LEN = 8;
    +-    private static final int UDP_DESTINATION_PORT_OFFSET = ETH_HEADER_LEN + 22;
    +-
    +-    private static final int DHCP_CLIENT_PORT = 68;
    +-    private static final int DHCP_CLIENT_MAC_OFFSET = ETH_HEADER_LEN + UDP_HEADER_LEN + 48;
    +-
    +-    private static final int ARP_HEADER_OFFSET = ETH_HEADER_LEN;
    +-    private static final byte[] ARP_IPV4_REQUEST_HEADER = new byte[]{
    +-            0, 1, // Hardware type: Ethernet (1)
    +-            8, 0, // Protocol type: IP (0x0800)
    +-            6,    // Hardware size: 6
    +-            4,    // Protocol size: 4
    +-            0, 1  // Opcode: request (1)
    +-    };
    +-    private static final byte[] ARP_IPV4_REPLY_HEADER = new byte[]{
    +-            0, 1, // Hardware type: Ethernet (1)
    +-            8, 0, // Protocol type: IP (0x0800)
    +-            6,    // Hardware size: 6
    +-            4,    // Protocol size: 4
    +-            0, 2  // Opcode: reply (2)
    +-    };
    +-    private static final int ARP_TARGET_IP_ADDRESS_OFFSET = ETH_HEADER_LEN + 24;
    +-
    +-    private static final byte[] MOCK_IPV4_ADDR = new byte[]{10, 0, 0, 1};
    +-    private static final byte[] ANOTHER_IPV4_ADDR = new byte[]{10, 0, 0, 2};
    +-    private static final byte[] IPV4_ANY_HOST_ADDR = new byte[]{0, 0, 0, 0};
    +-
    +-    @LargeTest
    +-    public void testApfFilterIPv4() throws Exception {
    +-        MockIpManagerCallback ipManagerCallback = new MockIpManagerCallback();
    +-        ApfFilter apfFilter = new TestApfFilter(ipManagerCallback, DROP_MULTICAST, mLog);
    +-        byte[] program = ipManagerCallback.getApfProgram();
    +-
    +-        // Verify empty packet of 100 zero bytes is passed
    +-        ByteBuffer packet = ByteBuffer.wrap(new byte[100]);
    +-        assertPass(program, packet.array(), 0);
    +-
    +-        // Verify unicast IPv4 packet is passed
    +-        packet.putShort(ETH_ETHERTYPE_OFFSET, (short)ETH_P_IP);
    +-        assertPass(program, packet.array(), 0);
    +-
    +-        // Verify broadcast IPv4, not DHCP to us, is dropped
    +-        packet.put(ETH_BROADCAST_MAC_ADDRESS);
    +-        assertDrop(program, packet.array(), 0);
    +-        packet.put(IPV4_VERSION_IHL_OFFSET, (byte)0x45);
    +-        assertDrop(program, packet.array(), 0);
    +-        packet.put(IPV4_PROTOCOL_OFFSET, (byte)IPPROTO_UDP);
    +-        assertDrop(program, packet.array(), 0);
    +-        packet.putShort(UDP_DESTINATION_PORT_OFFSET, (short)DHCP_CLIENT_PORT);
    +-        assertDrop(program, packet.array(), 0);
    +-
    +-        // Verify broadcast IPv4 DHCP to us is passed
    +-        packet.position(DHCP_CLIENT_MAC_OFFSET);
    +-        packet.put(TestApfFilter.MOCK_MAC_ADDR);
    +-        assertPass(program, packet.array(), 0);
    +-
    +-        apfFilter.shutdown();
    +-    }
    +-
    +-    @LargeTest
    +-    public void testApfFilterIPv6() throws Exception {
    +-        MockIpManagerCallback ipManagerCallback = new MockIpManagerCallback();
    +-        ApfFilter apfFilter = new TestApfFilter(ipManagerCallback, ALLOW_MULTICAST, mLog);
    +-        byte[] program = ipManagerCallback.getApfProgram();
    +-
    +-        // Verify empty IPv6 packet is passed
    +-        ByteBuffer packet = ByteBuffer.wrap(new byte[100]);
    +-        packet.putShort(ETH_ETHERTYPE_OFFSET, (short)ETH_P_IPV6);
    +-        assertPass(program, packet.array(), 0);
    +-
    +-        // Verify empty ICMPv6 packet is passed
    +-        packet.put(IPV6_NEXT_HEADER_OFFSET, (byte)IPPROTO_ICMPV6);
    +-        assertPass(program, packet.array(), 0);
    +-
    +-        // Verify empty ICMPv6 NA packet is passed
    +-        packet.put(ICMP6_TYPE_OFFSET, (byte)ICMP6_NEIGHBOR_ANNOUNCEMENT);
    +-        assertPass(program, packet.array(), 0);
    +-
    +-        // Verify ICMPv6 NA to ff02::1 is dropped
    +-        packet.position(IPV6_DEST_ADDR_OFFSET);
    +-        packet.put(IPV6_ALL_NODES_ADDRESS);
    +-        assertDrop(program, packet.array(), 0);
    +-
    +-        apfFilter.shutdown();
    +-    }
    +-
    +-    @LargeTest
    +-    public void testApfFilterMulticast() throws Exception {
    +-        MockIpManagerCallback ipManagerCallback = new MockIpManagerCallback();
    +-        ApfFilter apfFilter = new TestApfFilter(ipManagerCallback, ALLOW_MULTICAST, mLog);
    +-        byte[] program = ipManagerCallback.getApfProgram();
    +-
    +-        // Construct IPv4 and IPv6 multicast packets.
    +-        ByteBuffer mcastv4packet = ByteBuffer.wrap(new byte[100]);
    +-        mcastv4packet.putShort(ETH_ETHERTYPE_OFFSET, (short)ETH_P_IP);
    +-        mcastv4packet.position(IPV4_DEST_ADDR_OFFSET);
    +-        mcastv4packet.put(new byte[]{(byte)224,0,0,1});
    +-
    +-        ByteBuffer mcastv6packet = ByteBuffer.wrap(new byte[100]);
    +-        mcastv6packet.putShort(ETH_ETHERTYPE_OFFSET, (short)ETH_P_IPV6);
    +-        mcastv6packet.put(IPV6_NEXT_HEADER_OFFSET, (byte)IPPROTO_UDP);
    +-        mcastv6packet.position(IPV6_DEST_ADDR_OFFSET);
    +-        mcastv6packet.put(new byte[]{(byte)0xff,2,0,0,0,0,0,0,0,0,0,0,0,0,0,(byte)0xfb});
    +-
    +-        // Construct IPv4 broadcast packet.
    +-        ByteBuffer bcastv4packet = ByteBuffer.wrap(new byte[100]);
    +-        bcastv4packet.put(ETH_BROADCAST_MAC_ADDRESS);
    +-        bcastv4packet.putShort(ETH_ETHERTYPE_OFFSET, (short)ETH_P_IP);
    +-        bcastv4packet.position(IPV4_DEST_ADDR_OFFSET);
    +-        bcastv4packet.put(new byte[]{(byte)192,(byte)0,(byte)2,(byte)63});
    +-
    +-        // Verify initially disabled multicast filter is off
    +-        assertPass(program, bcastv4packet.array(), 0);
    +-        assertPass(program, mcastv4packet.array(), 0);
    +-        assertPass(program, mcastv6packet.array(), 0);
    +-
    +-        // Turn on multicast filter and verify it works
    +-        ipManagerCallback.resetApfProgramWait();
    +-        apfFilter.setMulticastFilter(true);
    +-        program = ipManagerCallback.getApfProgram();
    +-        assertDrop(program, bcastv4packet.array(), 0);
    +-        assertDrop(program, mcastv4packet.array(), 0);
    +-        assertDrop(program, mcastv6packet.array(), 0);
    +-
    +-        // Turn off multicast filter and verify it's off
    +-        ipManagerCallback.resetApfProgramWait();
    +-        apfFilter.setMulticastFilter(false);
    +-        program = ipManagerCallback.getApfProgram();
    +-        assertPass(program, bcastv4packet.array(), 0);
    +-        assertPass(program, mcastv4packet.array(), 0);
    +-        assertPass(program, mcastv6packet.array(), 0);
    +-
    +-        // Verify it can be initialized to on
    +-        ipManagerCallback.resetApfProgramWait();
    +-        apfFilter.shutdown();
    +-        apfFilter = new TestApfFilter(ipManagerCallback, DROP_MULTICAST, mLog);
    +-        program = ipManagerCallback.getApfProgram();
    +-        assertDrop(program, bcastv4packet.array(), 0);
    +-        assertDrop(program, mcastv4packet.array(), 0);
    +-        assertDrop(program, mcastv6packet.array(), 0);
    +-
    +-        // Verify that ICMPv6 multicast is not dropped.
    +-        mcastv6packet.put(IPV6_NEXT_HEADER_OFFSET, (byte)IPPROTO_ICMPV6);
    +-        assertPass(program, mcastv6packet.array(), 0);
    +-
    +-        apfFilter.shutdown();
    +-    }
    +-
    +-    private byte[] getProgram(MockIpManagerCallback cb, ApfFilter filter, LinkProperties lp) {
    +-        cb.resetApfProgramWait();
    +-        filter.setLinkProperties(lp);
    +-        return cb.getApfProgram();
    +-    }
    +-
    +-    private void verifyArpFilter(byte[] program, int filterResult) {
    +-        // Verify ARP request packet
    +-        assertPass(program, arpRequestBroadcast(MOCK_IPV4_ADDR), 0);
    +-        assertVerdict(filterResult, program, arpRequestBroadcast(ANOTHER_IPV4_ADDR), 0);
    +-        assertDrop(program, arpRequestBroadcast(IPV4_ANY_HOST_ADDR), 0);
    +-
    +-        // Verify unicast ARP reply packet is always accepted.
    +-        assertPass(program, arpReplyUnicast(MOCK_IPV4_ADDR), 0);
    +-        assertPass(program, arpReplyUnicast(ANOTHER_IPV4_ADDR), 0);
    +-        assertPass(program, arpReplyUnicast(IPV4_ANY_HOST_ADDR), 0);
    +-
    +-        // Verify GARP reply packets are always filtered
    +-        assertDrop(program, garpReply(), 0);
    +-    }
    +-
    +-    @LargeTest
    +-    public void testApfFilterArp() throws Exception {
    +-        MockIpManagerCallback ipManagerCallback = new MockIpManagerCallback();
    +-        ApfFilter apfFilter = new TestApfFilter(ipManagerCallback, ALLOW_MULTICAST, mLog);
    +-
    +-        // Verify initially ARP request filter is off, and GARP filter is on.
    +-        verifyArpFilter(ipManagerCallback.getApfProgram(), PASS);
    +-
    +-        // Inform ApfFilter of our address and verify ARP filtering is on
    +-        LinkAddress linkAddress = new LinkAddress(InetAddress.getByAddress(MOCK_IPV4_ADDR), 24);
    +-        LinkProperties lp = new LinkProperties();
    +-        assertTrue(lp.addLinkAddress(linkAddress));
    +-        verifyArpFilter(getProgram(ipManagerCallback, apfFilter, lp), DROP);
    +-
    +-        // Inform ApfFilter of loss of IP and verify ARP filtering is off
    +-        verifyArpFilter(getProgram(ipManagerCallback, apfFilter, new LinkProperties()), PASS);
    +-
    +-        apfFilter.shutdown();
    +-    }
    +-
    +-    private static byte[] arpRequestBroadcast(byte[] tip) {
    +-        ByteBuffer packet = ByteBuffer.wrap(new byte[100]);
    +-        packet.putShort(ETH_ETHERTYPE_OFFSET, (short)ETH_P_ARP);
    +-        packet.position(ETH_DEST_ADDR_OFFSET);
    +-        packet.put(ETH_BROADCAST_MAC_ADDRESS);
    +-        packet.position(ARP_HEADER_OFFSET);
    +-        packet.put(ARP_IPV4_REQUEST_HEADER);
    +-        packet.position(ARP_TARGET_IP_ADDRESS_OFFSET);
    +-        packet.put(tip);
    +-        return packet.array();
    +-    }
    +-
    +-    private static byte[] arpReplyUnicast(byte[] tip) {
    +-        ByteBuffer packet = ByteBuffer.wrap(new byte[100]);
    +-        packet.putShort(ETH_ETHERTYPE_OFFSET, (short)ETH_P_ARP);
    +-        packet.position(ARP_HEADER_OFFSET);
    +-        packet.put(ARP_IPV4_REPLY_HEADER);
    +-        packet.position(ARP_TARGET_IP_ADDRESS_OFFSET);
    +-        packet.put(tip);
    +-        return packet.array();
    +-    }
    +-
    +-    private static byte[] garpReply() {
    +-        ByteBuffer packet = ByteBuffer.wrap(new byte[100]);
    +-        packet.putShort(ETH_ETHERTYPE_OFFSET, (short)ETH_P_ARP);
    +-        packet.position(ETH_DEST_ADDR_OFFSET);
    +-        packet.put(ETH_BROADCAST_MAC_ADDRESS);
    +-        packet.position(ARP_HEADER_OFFSET);
    +-        packet.put(ARP_IPV4_REPLY_HEADER);
    +-        packet.position(ARP_TARGET_IP_ADDRESS_OFFSET);
    +-        packet.put(IPV4_ANY_HOST_ADDR);
    +-        return packet.array();
    +-    }
    +-
    +-    // Verify that the last program pushed to the IpManager.Callback properly filters the
    +-    // given packet for the given lifetime.
    +-    private void verifyRaLifetime(MockIpManagerCallback ipManagerCallback, ByteBuffer packet,
    +-            int lifetime) {
    +-        byte[] program = ipManagerCallback.getApfProgram();
    +-
    +-        // Verify new program should drop RA for 1/6th its lifetime
    +-        assertDrop(program, packet.array(), 0);
    +-        assertDrop(program, packet.array(), lifetime/6);
    +-        assertPass(program, packet.array(), lifetime/6 + 1);
    +-        assertPass(program, packet.array(), lifetime);
    +-
    +-        // Verify RA checksum is ignored
    +-        packet.putShort(ICMP6_RA_CHECKSUM_OFFSET, (short)12345);
    +-        assertDrop(program, packet.array(), 0);
    +-        packet.putShort(ICMP6_RA_CHECKSUM_OFFSET, (short)-12345);
    +-        assertDrop(program, packet.array(), 0);
    +-
    +-        // Verify other changes to RA make it not match filter
    +-        packet.put(0, (byte)-1);
    +-        assertPass(program, packet.array(), 0);
    +-        packet.put(0, (byte)0);
    +-        assertDrop(program, packet.array(), 0);
    +-    }
    +-
    +-    // Test that when ApfFilter is shown the given packet, it generates a program to filter it
    +-    // for the given lifetime.
    +-    private void testRaLifetime(TestApfFilter apfFilter, MockIpManagerCallback ipManagerCallback,
    +-            ByteBuffer packet, int lifetime) throws IOException, ErrnoException {
    +-        // Verify new program generated if ApfFilter witnesses RA
    +-        ipManagerCallback.resetApfProgramWait();
    +-        apfFilter.pretendPacketReceived(packet.array());
    +-        ipManagerCallback.getApfProgram();
    +-
    +-        verifyRaLifetime(ipManagerCallback, packet, lifetime);
    +-    }
    +-
    +-    private void verifyRaEvent(RaEvent expected) {
    +-        ArgumentCaptor<Parcelable> captor = ArgumentCaptor.forClass(Parcelable.class);
    +-        verify(mLog, atLeastOnce()).log(captor.capture());
    +-        RaEvent got = lastRaEvent(captor.getAllValues());
    +-        if (!raEventEquals(expected, got)) {
    +-            assertEquals(expected, got);  // fail for printing an assertion error message.
    +-        }
    +-    }
    +-
    +-    private RaEvent lastRaEvent(List<Parcelable> events) {
    +-        RaEvent got = null;
    +-        for (Parcelable ev : events) {
    +-            if (ev instanceof RaEvent) {
    +-                got = (RaEvent) ev;
    +-            }
    +-        }
    +-        return got;
    +-    }
    +-
    +-    private boolean raEventEquals(RaEvent ev1, RaEvent ev2) {
    +-        return (ev1 != null) && (ev2 != null)
    +-                && (ev1.routerLifetime == ev2.routerLifetime)
    +-                && (ev1.prefixValidLifetime == ev2.prefixValidLifetime)
    +-                && (ev1.prefixPreferredLifetime == ev2.prefixPreferredLifetime)
    +-                && (ev1.routeInfoLifetime == ev2.routeInfoLifetime)
    +-                && (ev1.rdnssLifetime == ev2.rdnssLifetime)
    +-                && (ev1.dnsslLifetime == ev2.dnsslLifetime);
    +-    }
    +-
    +-    private void assertInvalidRa(TestApfFilter apfFilter, MockIpManagerCallback ipManagerCallback,
    +-            ByteBuffer packet) throws IOException, ErrnoException {
    +-        ipManagerCallback.resetApfProgramWait();
    +-        apfFilter.pretendPacketReceived(packet.array());
    +-        ipManagerCallback.assertNoProgramUpdate();
    +-    }
    +-
    +-    @LargeTest
    +-    public void testApfFilterRa() throws Exception {
    +-        MockIpManagerCallback ipManagerCallback = new MockIpManagerCallback();
    +-        TestApfFilter apfFilter = new TestApfFilter(ipManagerCallback, DROP_MULTICAST, mLog);
    +-        byte[] program = ipManagerCallback.getApfProgram();
    +-
    +-        // Verify RA is passed the first time
    +-        ByteBuffer basePacket = ByteBuffer.wrap(new byte[ICMP6_RA_OPTION_OFFSET]);
    +-        basePacket.putShort(ETH_ETHERTYPE_OFFSET, (short)ETH_P_IPV6);
    +-        basePacket.put(IPV6_NEXT_HEADER_OFFSET, (byte)IPPROTO_ICMPV6);
    +-        basePacket.put(ICMP6_TYPE_OFFSET, (byte)ICMP6_ROUTER_ADVERTISEMENT);
    +-        basePacket.putShort(ICMP6_RA_ROUTER_LIFETIME_OFFSET, (short)1000);
    +-        basePacket.position(IPV6_DEST_ADDR_OFFSET);
    +-        basePacket.put(IPV6_ALL_NODES_ADDRESS);
    +-        assertPass(program, basePacket.array(), 0);
    +-
    +-        testRaLifetime(apfFilter, ipManagerCallback, basePacket, 1000);
    +-        verifyRaEvent(new RaEvent(1000, -1, -1, -1, -1, -1));
    +-
    +-        // Ensure zero-length options cause the packet to be silently skipped.
    +-        // Do this before we test other packets. http://b/29586253
    +-        ByteBuffer zeroLengthOptionPacket = ByteBuffer.wrap(
    +-                new byte[ICMP6_RA_OPTION_OFFSET + ICMP6_4_BYTE_OPTION_LEN]);
    +-        basePacket.clear();
    +-        zeroLengthOptionPacket.put(basePacket);
    +-        zeroLengthOptionPacket.put((byte)ICMP6_PREFIX_OPTION_TYPE);
    +-        zeroLengthOptionPacket.put((byte)0);
    +-        assertInvalidRa(apfFilter, ipManagerCallback, zeroLengthOptionPacket);
    +-
    +-        // Generate several RAs with different options and lifetimes, and verify when
    +-        // ApfFilter is shown these packets, it generates programs to filter them for the
    +-        // appropriate lifetime.
    +-        ByteBuffer prefixOptionPacket = ByteBuffer.wrap(
    +-                new byte[ICMP6_RA_OPTION_OFFSET + ICMP6_PREFIX_OPTION_LEN]);
    +-        basePacket.clear();
    +-        prefixOptionPacket.put(basePacket);
    +-        prefixOptionPacket.put((byte)ICMP6_PREFIX_OPTION_TYPE);
    +-        prefixOptionPacket.put((byte)(ICMP6_PREFIX_OPTION_LEN / 8));
    +-        prefixOptionPacket.putInt(
    +-                ICMP6_RA_OPTION_OFFSET + ICMP6_PREFIX_OPTION_PREFERRED_LIFETIME_OFFSET, 100);
    +-        prefixOptionPacket.putInt(
    +-                ICMP6_RA_OPTION_OFFSET + ICMP6_PREFIX_OPTION_VALID_LIFETIME_OFFSET, 200);
    +-        testRaLifetime(apfFilter, ipManagerCallback, prefixOptionPacket, 100);
    +-        verifyRaEvent(new RaEvent(1000, 200, 100, -1, -1, -1));
    +-
    +-        ByteBuffer rdnssOptionPacket = ByteBuffer.wrap(
    +-                new byte[ICMP6_RA_OPTION_OFFSET + ICMP6_4_BYTE_OPTION_LEN]);
    +-        basePacket.clear();
    +-        rdnssOptionPacket.put(basePacket);
    +-        rdnssOptionPacket.put((byte)ICMP6_RDNSS_OPTION_TYPE);
    +-        rdnssOptionPacket.put((byte)(ICMP6_4_BYTE_OPTION_LEN / 8));
    +-        rdnssOptionPacket.putInt(
    +-                ICMP6_RA_OPTION_OFFSET + ICMP6_4_BYTE_LIFETIME_OFFSET, 300);
    +-        testRaLifetime(apfFilter, ipManagerCallback, rdnssOptionPacket, 300);
    +-        verifyRaEvent(new RaEvent(1000, -1, -1, -1, 300, -1));
    +-
    +-        ByteBuffer routeInfoOptionPacket = ByteBuffer.wrap(
    +-                new byte[ICMP6_RA_OPTION_OFFSET + ICMP6_4_BYTE_OPTION_LEN]);
    +-        basePacket.clear();
    +-        routeInfoOptionPacket.put(basePacket);
    +-        routeInfoOptionPacket.put((byte)ICMP6_ROUTE_INFO_OPTION_TYPE);
    +-        routeInfoOptionPacket.put((byte)(ICMP6_4_BYTE_OPTION_LEN / 8));
    +-        routeInfoOptionPacket.putInt(
    +-                ICMP6_RA_OPTION_OFFSET + ICMP6_4_BYTE_LIFETIME_OFFSET, 400);
    +-        testRaLifetime(apfFilter, ipManagerCallback, routeInfoOptionPacket, 400);
    +-        verifyRaEvent(new RaEvent(1000, -1, -1, 400, -1, -1));
    +-
    +-        ByteBuffer dnsslOptionPacket = ByteBuffer.wrap(
    +-                new byte[ICMP6_RA_OPTION_OFFSET + ICMP6_4_BYTE_OPTION_LEN]);
    +-        basePacket.clear();
    +-        dnsslOptionPacket.put(basePacket);
    +-        dnsslOptionPacket.put((byte)ICMP6_DNSSL_OPTION_TYPE);
    +-        dnsslOptionPacket.put((byte)(ICMP6_4_BYTE_OPTION_LEN / 8));
    +-        dnsslOptionPacket.putInt(
    +-                ICMP6_RA_OPTION_OFFSET + ICMP6_4_BYTE_LIFETIME_OFFSET, 2000);
    +-        // Note that lifetime of 2000 will be ignored in favor of shorter
    +-        // route lifetime of 1000.
    +-        testRaLifetime(apfFilter, ipManagerCallback, dnsslOptionPacket, 1000);
    +-        verifyRaEvent(new RaEvent(1000, -1, -1, -1, -1, 2000));
    +-
    +-        // Verify that current program filters all five RAs:
    +-        verifyRaLifetime(ipManagerCallback, basePacket, 1000);
    +-        verifyRaLifetime(ipManagerCallback, prefixOptionPacket, 100);
    +-        verifyRaLifetime(ipManagerCallback, rdnssOptionPacket, 300);
    +-        verifyRaLifetime(ipManagerCallback, routeInfoOptionPacket, 400);
    +-        verifyRaLifetime(ipManagerCallback, dnsslOptionPacket, 1000);
    +-
    +-        apfFilter.shutdown();
    +-    }
    +-
    +-    /**
    +-     * Stage a file for testing, i.e. make it native accessible. Given a resource ID,
    +-     * copy that resource into the app's data directory and return the path to it.
    +-     */
    +-    private String stageFile(int rawId) throws Exception {
    +-        File file = new File(getContext().getFilesDir(), "staged_file");
    +-        new File(file.getParent()).mkdirs();
    +-        InputStream in = null;
    +-        OutputStream out = null;
    +-        try {
    +-            in = getContext().getResources().openRawResource(rawId);
    +-            out = new FileOutputStream(file);
    +-            Streams.copy(in, out);
    +-        } finally {
    +-            if (in != null) in.close();
    +-            if (out != null) out.close();
    +-        }
    +-        return file.getAbsolutePath();
    +-    }
    +-
    +-    /**
    +-     * Call the APF interpreter the run {@code program} on {@code packet} pretending the
    +-     * filter was installed {@code filter_age} seconds ago.
    +-     */
    +-    private native static int apfSimulate(byte[] program, byte[] packet, int filter_age);
    +-
    +-    /**
    +-     * Compile a tcpdump human-readable filter (e.g. "icmp" or "tcp port 54") into a BPF
    +-     * prorgam and return a human-readable dump of the BPF program identical to "tcpdump -d".
    +-     */
    +-    private native static String compileToBpf(String filter);
    +-
    +-    /**
    +-     * Open packet capture file {@code pcap_filename} and filter the packets using tcpdump
    +-     * human-readable filter (e.g. "icmp" or "tcp port 54") compiled to a BPF program and
    +-     * at the same time using APF program {@code apf_program}.  Return {@code true} if
    +-     * both APF and BPF programs filter out exactly the same packets.
    +-     */
    +-    private native static boolean compareBpfApf(String filter, String pcap_filename,
    +-            byte[] apf_program);
    +-}
    +diff --git a/services/tests/servicestests/src/android/net/apf/Bpf2Apf.java b/services/tests/servicestests/src/android/net/apf/Bpf2Apf.java
    +deleted file mode 100644
    +index 220e54d..0000000
    +--- a/services/tests/servicestests/src/android/net/apf/Bpf2Apf.java
    ++++ /dev/null
    +@@ -1,327 +0,0 @@
    +-/*
    +- * Copyright (C) 2015 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 android.net.apf;
    +-
    +-import android.net.apf.ApfGenerator;
    +-import android.net.apf.ApfGenerator.IllegalInstructionException;
    +-import android.net.apf.ApfGenerator.Register;
    +-
    +-import java.io.BufferedReader;
    +-import java.io.InputStreamReader;
    +-
    +-/**
    +- * BPF to APF translator.
    +- *
    +- * Note: This is for testing purposes only and is not guaranteed to support
    +- *       translation of all BPF programs.
    +- *
    +- * Example usage:
    +- *   javac net/java/android/net/apf/ApfGenerator.java \
    +- *         tests/servicestests/src/android/net/apf/Bpf2Apf.java
    +- *   sudo tcpdump -i em1 -d icmp | java -classpath tests/servicestests/src:net/java \
    +- *                                      android.net.apf.Bpf2Apf
    +- */
    +-public class Bpf2Apf {
    +-    private static int parseImm(String line, String arg) {
    +-        if (!arg.startsWith("#0x")) {
    +-            throw new IllegalArgumentException("Unhandled instruction: " + line);
    +-        }
    +-        final long val_long = Long.parseLong(arg.substring(3), 16);
    +-        if (val_long < 0 || val_long > Long.parseLong("ffffffff", 16)) {
    +-            throw new IllegalArgumentException("Unhandled instruction: " + line);
    +-        }
    +-        return new Long((val_long << 32) >> 32).intValue();
    +-    }
    +-
    +-    /**
    +-     * Convert a single line of "tcpdump -d" (human readable BPF program dump) {@code line} into
    +-     * APF instruction(s) and append them to {@code gen}. Here's an example line:
    +-     * (001) jeq      #0x86dd          jt 2    jf 7
    +-     */
    +-    private static void convertLine(String line, ApfGenerator gen)
    +-            throws IllegalInstructionException {
    +-        if (line.indexOf("(") != 0 || line.indexOf(")") != 4 || line.indexOf(" ") != 5) {
    +-            throw new IllegalArgumentException("Unhandled instruction: " + line);
    +-        }
    +-        int label = Integer.parseInt(line.substring(1, 4));
    +-        gen.defineLabel(Integer.toString(label));
    +-        String opcode = line.substring(6, 10).trim();
    +-        String arg = line.substring(15, Math.min(32, line.length())).trim();
    +-        switch (opcode) {
    +-            case "ld":
    +-            case "ldh":
    +-            case "ldb":
    +-            case "ldx":
    +-            case "ldxb":
    +-            case "ldxh":
    +-                Register dest = opcode.contains("x") ? Register.R1 : Register.R0;
    +-                if (arg.equals("4*([14]&0xf)")) {
    +-                    if (!opcode.equals("ldxb")) {
    +-                        throw new IllegalArgumentException("Unhandled instruction: " + line);
    +-                    }
    +-                    gen.addLoadFromMemory(dest, gen.IPV4_HEADER_SIZE_MEMORY_SLOT);
    +-                    break;
    +-                }
    +-                if (arg.equals("#pktlen")) {
    +-                    if (!opcode.equals("ld")) {
    +-                        throw new IllegalArgumentException("Unhandled instruction: " + line);
    +-                    }
    +-                    gen.addLoadFromMemory(dest, gen.PACKET_SIZE_MEMORY_SLOT);
    +-                    break;
    +-                }
    +-                if (arg.startsWith("#0x")) {
    +-                    if (!opcode.equals("ld")) {
    +-                        throw new IllegalArgumentException("Unhandled instruction: " + line);
    +-                    }
    +-                    gen.addLoadImmediate(dest, parseImm(line, arg));
    +-                    break;
    +-                }
    +-                if (arg.startsWith("M[")) {
    +-                    if (!opcode.startsWith("ld")) {
    +-                        throw new IllegalArgumentException("Unhandled instruction: " + line);
    +-                    }
    +-                    int memory_slot = Integer.parseInt(arg.substring(2, arg.length() - 1));
    +-                    if (memory_slot < 0 || memory_slot >= gen.MEMORY_SLOTS ||
    +-                            // Disallow use of pre-filled slots as BPF programs might
    +-                            // wrongfully assume they're initialized to 0.
    +-                            (memory_slot >= gen.FIRST_PREFILLED_MEMORY_SLOT &&
    +-                                    memory_slot <= gen.LAST_PREFILLED_MEMORY_SLOT)) {
    +-                        throw new IllegalArgumentException("Unhandled instruction: " + line);
    +-                    }
    +-                    gen.addLoadFromMemory(dest, memory_slot);
    +-                    break;
    +-                }
    +-                if (arg.startsWith("[x + ")) {
    +-                    int offset = Integer.parseInt(arg.substring(5, arg.length() - 1));
    +-                    switch (opcode) {
    +-                        case "ld":
    +-                        case "ldx":
    +-                            gen.addLoad32Indexed(dest, offset);
    +-                            break;
    +-                        case "ldh":
    +-                        case "ldxh":
    +-                            gen.addLoad16Indexed(dest, offset);
    +-                            break;
    +-                        case "ldb":
    +-                        case "ldxb":
    +-                            gen.addLoad8Indexed(dest, offset);
    +-                            break;
    +-                    }
    +-                } else {
    +-                    int offset = Integer.parseInt(arg.substring(1, arg.length() - 1));
    +-                    switch (opcode) {
    +-                        case "ld":
    +-                        case "ldx":
    +-                            gen.addLoad32(dest, offset);
    +-                            break;
    +-                        case "ldh":
    +-                        case "ldxh":
    +-                            gen.addLoad16(dest, offset);
    +-                            break;
    +-                        case "ldb":
    +-                        case "ldxb":
    +-                            gen.addLoad8(dest, offset);
    +-                            break;
    +-                    }
    +-                }
    +-                break;
    +-            case "st":
    +-            case "stx":
    +-                Register src = opcode.contains("x") ? Register.R1 : Register.R0;
    +-                if (!arg.startsWith("M[")) {
    +-                    throw new IllegalArgumentException("Unhandled instruction: " + line);
    +-                }
    +-                int memory_slot = Integer.parseInt(arg.substring(2, arg.length() - 1));
    +-                if (memory_slot < 0 || memory_slot >= gen.MEMORY_SLOTS ||
    +-                        // Disallow overwriting pre-filled slots
    +-                        (memory_slot >= gen.FIRST_PREFILLED_MEMORY_SLOT &&
    +-                                memory_slot <= gen.LAST_PREFILLED_MEMORY_SLOT)) {
    +-                    throw new IllegalArgumentException("Unhandled instruction: " + line);
    +-                }
    +-                gen.addStoreToMemory(src, memory_slot);
    +-                break;
    +-            case "add":
    +-            case "and":
    +-            case "or":
    +-            case "sub":
    +-                if (arg.equals("x")) {
    +-                    switch(opcode) {
    +-                        case "add":
    +-                            gen.addAddR1();
    +-                            break;
    +-                        case "and":
    +-                            gen.addAndR1();
    +-                            break;
    +-                        case "or":
    +-                            gen.addOrR1();
    +-                            break;
    +-                        case "sub":
    +-                            gen.addNeg(Register.R1);
    +-                            gen.addAddR1();
    +-                            gen.addNeg(Register.R1);
    +-                            break;
    +-                    }
    +-                } else {
    +-                    int imm = parseImm(line, arg);
    +-                    switch(opcode) {
    +-                        case "add":
    +-                            gen.addAdd(imm);
    +-                            break;
    +-                        case "and":
    +-                            gen.addAnd(imm);
    +-                            break;
    +-                        case "or":
    +-                            gen.addOr(imm);
    +-                            break;
    +-                        case "sub":
    +-                            gen.addAdd(-imm);
    +-                            break;
    +-                    }
    +-                }
    +-                break;
    +-            case "jeq":
    +-            case "jset":
    +-            case "jgt":
    +-            case "jge":
    +-                int val = 0;
    +-                boolean reg_compare;
    +-                if (arg.startsWith("x")) {
    +-                    reg_compare = true;
    +-                } else {
    +-                    reg_compare = false;
    +-                    val = parseImm(line, arg);
    +-                }
    +-                int jt_offset = line.indexOf("jt");
    +-                int jf_offset = line.indexOf("jf");
    +-                String true_label = line.substring(jt_offset + 2, jf_offset).trim();
    +-                String false_label = line.substring(jf_offset + 2).trim();
    +-                boolean true_label_is_fallthrough = Integer.parseInt(true_label) == label + 1;
    +-                boolean false_label_is_fallthrough = Integer.parseInt(false_label) == label + 1;
    +-                if (true_label_is_fallthrough && false_label_is_fallthrough)
    +-                    break;
    +-                switch (opcode) {
    +-                    case "jeq":
    +-                        if (!true_label_is_fallthrough) {
    +-                            if (reg_compare) {
    +-                                gen.addJumpIfR0EqualsR1(true_label);
    +-                            } else {
    +-                                gen.addJumpIfR0Equals(val, true_label);
    +-                            }
    +-                        }
    +-                        if (!false_label_is_fallthrough) {
    +-                            if (!true_label_is_fallthrough) {
    +-                                gen.addJump(false_label);
    +-                            } else if (reg_compare) {
    +-                                gen.addJumpIfR0NotEqualsR1(false_label);
    +-                            } else {
    +-                                gen.addJumpIfR0NotEquals(val, false_label);
    +-                            }
    +-                        }
    +-                        break;
    +-                    case "jset":
    +-                        if (reg_compare) {
    +-                            gen.addJumpIfR0AnyBitsSetR1(true_label);
    +-                        } else {
    +-                            gen.addJumpIfR0AnyBitsSet(val, true_label);
    +-                        }
    +-                        if (!false_label_is_fallthrough) {
    +-                            gen.addJump(false_label);
    +-                        }
    +-                        break;
    +-                    case "jgt":
    +-                        if (!true_label_is_fallthrough ||
    +-                                // We have no less-than-or-equal-to register to register
    +-                                // comparison instruction, so in this case we'll jump
    +-                                // around an unconditional jump.
    +-                                (!false_label_is_fallthrough && reg_compare)) {
    +-                            if (reg_compare) {
    +-                                gen.addJumpIfR0GreaterThanR1(true_label);
    +-                            } else {
    +-                                gen.addJumpIfR0GreaterThan(val, true_label);
    +-                            }
    +-                        }
    +-                        if (!false_label_is_fallthrough) {
    +-                            if (!true_label_is_fallthrough || reg_compare) {
    +-                                gen.addJump(false_label);
    +-                            } else {
    +-                                gen.addJumpIfR0LessThan(val + 1, false_label);
    +-                            }
    +-                        }
    +-                        break;
    +-                    case "jge":
    +-                        if (!false_label_is_fallthrough ||
    +-                                // We have no greater-than-or-equal-to register to register
    +-                                // comparison instruction, so in this case we'll jump
    +-                                // around an unconditional jump.
    +-                                (!true_label_is_fallthrough && reg_compare)) {
    +-                            if (reg_compare) {
    +-                                gen.addJumpIfR0LessThanR1(false_label);
    +-                            } else {
    +-                                gen.addJumpIfR0LessThan(val, false_label);
    +-                            }
    +-                        }
    +-                        if (!true_label_is_fallthrough) {
    +-                            if (!false_label_is_fallthrough || reg_compare) {
    +-                                gen.addJump(true_label);
    +-                            } else {
    +-                                gen.addJumpIfR0GreaterThan(val - 1, true_label);
    +-                            }
    +-                        }
    +-                        break;
    +-                }
    +-                break;
    +-            case "ret":
    +-                if (arg.equals("#0")) {
    +-                    gen.addJump(gen.DROP_LABEL);
    +-                } else {
    +-                    gen.addJump(gen.PASS_LABEL);
    +-                }
    +-                break;
    +-            case "tax":
    +-                gen.addMove(Register.R1);
    +-                break;
    +-            case "txa":
    +-                gen.addMove(Register.R0);
    +-                break;
    +-            default:
    +-                throw new IllegalArgumentException("Unhandled instruction: " + line);
    +-        }
    +-    }
    +-
    +-    /**
    +-     * Convert the output of "tcpdump -d" (human readable BPF program dump) {@code bpf} into an APF
    +-     * program and return it.
    +-     */
    +-    public static byte[] convert(String bpf) throws IllegalInstructionException {
    +-        ApfGenerator gen = new ApfGenerator();
    +-        for (String line : bpf.split("\\n")) convertLine(line, gen);
    +-        return gen.generate();
    +-    }
    +-
    +-    /**
    +-     * Convert the output of "tcpdump -d" (human readable BPF program dump) piped in stdin into an
    +-     * APF program and output it via stdout.
    +-     */
    +-    public static void main(String[] args) throws Exception {
    +-        BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
    +-        String line = null;
    +-        StringBuilder responseData = new StringBuilder();
    +-        ApfGenerator gen = new ApfGenerator();
    +-        while ((line = in.readLine()) != null) convertLine(line, gen);
    +-        System.out.write(gen.generate());
    +-    }
    +-}
    +diff --git a/services/tests/servicestests/src/android/net/dhcp/DhcpPacketTest.java b/services/tests/servicestests/src/android/net/dhcp/DhcpPacketTest.java
    +deleted file mode 100644
    +index f8eaf7d..0000000
    +--- a/services/tests/servicestests/src/android/net/dhcp/DhcpPacketTest.java
    ++++ /dev/null
    +@@ -1,772 +0,0 @@
    +-/*
    +- * Copyright (C) 2015 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 android.net.dhcp;
    +-
    +-import android.net.NetworkUtils;
    +-import android.net.DhcpResults;
    +-import android.net.LinkAddress;
    +-import android.system.OsConstants;
    +-import android.test.suitebuilder.annotation.SmallTest;
    +-import com.android.internal.util.HexDump;
    +-
    +-import java.net.Inet4Address;
    +-import java.nio.ByteBuffer;
    +-import java.util.ArrayList;
    +-
    +-import junit.framework.TestCase;
    +-import libcore.util.HexEncoding;
    +-import java.util.Arrays;
    +-
    +-import static android.net.dhcp.DhcpPacket.*;
    +-
    +-
    +-public class DhcpPacketTest extends TestCase {
    +-
    +-    private static Inet4Address SERVER_ADDR = v4Address("192.0.2.1");
    +-    private static Inet4Address CLIENT_ADDR = v4Address("192.0.2.234");
    +-    // Use our own empty address instead of Inet4Address.ANY or INADDR_ANY to ensure that the code
    +-    // doesn't use == instead of equals when comparing addresses.
    +-    private static Inet4Address ANY = (Inet4Address) v4Address("0.0.0.0");
    +-
    +-    private static byte[] CLIENT_MAC = new byte[] { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05 };
    +-
    +-    private static final Inet4Address v4Address(String addrString) throws IllegalArgumentException {
    +-        return (Inet4Address) NetworkUtils.numericToInetAddress(addrString);
    +-    }
    +-
    +-    public void setUp() {
    +-        DhcpPacket.testOverrideVendorId = "android-dhcp-???";
    +-        DhcpPacket.testOverrideHostname = "android-01234567890abcde";
    +-    }
    +-
    +-    class TestDhcpPacket extends DhcpPacket {
    +-        private byte mType;
    +-        // TODO: Make this a map of option numbers to bytes instead.
    +-        private byte[] mDomainBytes, mVendorInfoBytes, mLeaseTimeBytes, mNetmaskBytes;
    +-
    +-        public TestDhcpPacket(byte type, Inet4Address clientIp, Inet4Address yourIp) {
    +-            super(0xdeadbeef, (short) 0, clientIp, yourIp, INADDR_ANY, INADDR_ANY,
    +-                  CLIENT_MAC, true);
    +-            mType = type;
    +-        }
    +-
    +-        public TestDhcpPacket(byte type) {
    +-            this(type, INADDR_ANY, CLIENT_ADDR);
    +-        }
    +-
    +-        public TestDhcpPacket setDomainBytes(byte[] domainBytes) {
    +-            mDomainBytes = domainBytes;
    +-            return this;
    +-        }
    +-
    +-        public TestDhcpPacket setVendorInfoBytes(byte[] vendorInfoBytes) {
    +-            mVendorInfoBytes = vendorInfoBytes;
    +-            return this;
    +-        }
    +-
    +-        public TestDhcpPacket setLeaseTimeBytes(byte[] leaseTimeBytes) {
    +-            mLeaseTimeBytes = leaseTimeBytes;
    +-            return this;
    +-        }
    +-
    +-        public TestDhcpPacket setNetmaskBytes(byte[] netmaskBytes) {
    +-            mNetmaskBytes = netmaskBytes;
    +-            return this;
    +-        }
    +-
    +-        public ByteBuffer buildPacket(int encap, short unusedDestUdp, short unusedSrcUdp) {
    +-            ByteBuffer result = ByteBuffer.allocate(MAX_LENGTH);
    +-            fillInPacket(encap, CLIENT_ADDR, SERVER_ADDR,
    +-                         DHCP_CLIENT, DHCP_SERVER, result, DHCP_BOOTREPLY, false);
    +-            return result;
    +-        }
    +-
    +-        public void finishPacket(ByteBuffer buffer) {
    +-            addTlv(buffer, DHCP_MESSAGE_TYPE, mType);
    +-            if (mDomainBytes != null) {
    +-                addTlv(buffer, DHCP_DOMAIN_NAME, mDomainBytes);
    +-            }
    +-            if (mVendorInfoBytes != null) {
    +-                addTlv(buffer, DHCP_VENDOR_INFO, mVendorInfoBytes);
    +-            }
    +-            if (mLeaseTimeBytes != null) {
    +-                addTlv(buffer, DHCP_LEASE_TIME, mLeaseTimeBytes);
    +-            }
    +-            if (mNetmaskBytes != null) {
    +-                addTlv(buffer, DHCP_SUBNET_MASK, mNetmaskBytes);
    +-            }
    +-            addTlvEnd(buffer);
    +-        }
    +-
    +-        // Convenience method.
    +-        public ByteBuffer build() {
    +-            // ENCAP_BOOTP packets don't contain ports, so just pass in 0.
    +-            ByteBuffer pkt = buildPacket(ENCAP_BOOTP, (short) 0, (short) 0);
    +-            pkt.flip();
    +-            return pkt;
    +-        }
    +-    }
    +-
    +-    private void assertDomainAndVendorInfoParses(
    +-            String expectedDomain, byte[] domainBytes,
    +-            String expectedVendorInfo, byte[] vendorInfoBytes) throws Exception {
    +-        ByteBuffer packet = new TestDhcpPacket(DHCP_MESSAGE_TYPE_OFFER)
    +-                .setDomainBytes(domainBytes)
    +-                .setVendorInfoBytes(vendorInfoBytes)
    +-                .build();
    +-        DhcpPacket offerPacket = DhcpPacket.decodeFullPacket(packet, ENCAP_BOOTP);
    +-        assertEquals(expectedDomain, offerPacket.mDomainName);
    +-        assertEquals(expectedVendorInfo, offerPacket.mVendorInfo);
    +-    }
    +-
    +-    @SmallTest
    +-    public void testDomainName() throws Exception {
    +-        byte[] nullByte = new byte[] { 0x00 };
    +-        byte[] twoNullBytes = new byte[] { 0x00, 0x00 };
    +-        byte[] nonNullDomain = new byte[] {
    +-            (byte) 'g', (byte) 'o', (byte) 'o', (byte) '.', (byte) 'g', (byte) 'l'
    +-        };
    +-        byte[] trailingNullDomain = new byte[] {
    +-            (byte) 'g', (byte) 'o', (byte) 'o', (byte) '.', (byte) 'g', (byte) 'l', 0x00
    +-        };
    +-        byte[] embeddedNullsDomain = new byte[] {
    +-            (byte) 'g', (byte) 'o', (byte) 'o', 0x00, 0x00, (byte) 'g', (byte) 'l'
    +-        };
    +-        byte[] metered = "ANDROID_METERED".getBytes("US-ASCII");
    +-
    +-        byte[] meteredEmbeddedNull = metered.clone();
    +-        meteredEmbeddedNull[7] = (char) 0;
    +-
    +-        byte[] meteredTrailingNull = metered.clone();
    +-        meteredTrailingNull[meteredTrailingNull.length - 1] = (char) 0;
    +-
    +-        assertDomainAndVendorInfoParses("", nullByte, "\u0000", nullByte);
    +-        assertDomainAndVendorInfoParses("", twoNullBytes, "\u0000\u0000", twoNullBytes);
    +-        assertDomainAndVendorInfoParses("goo.gl", nonNullDomain, "ANDROID_METERED", metered);
    +-        assertDomainAndVendorInfoParses("goo", embeddedNullsDomain,
    +-                                        "ANDROID\u0000METERED", meteredEmbeddedNull);
    +-        assertDomainAndVendorInfoParses("goo.gl", trailingNullDomain,
    +-                                        "ANDROID_METERE\u0000", meteredTrailingNull);
    +-    }
    +-
    +-    private void assertLeaseTimeParses(boolean expectValid, Integer rawLeaseTime,
    +-            long leaseTimeMillis, byte[] leaseTimeBytes) throws Exception {
    +-        TestDhcpPacket testPacket = new TestDhcpPacket(DHCP_MESSAGE_TYPE_OFFER);
    +-        if (leaseTimeBytes != null) {
    +-            testPacket.setLeaseTimeBytes(leaseTimeBytes);
    +-        }
    +-        ByteBuffer packet = testPacket.build();
    +-        DhcpPacket offerPacket = null;
    +-
    +-        if (!expectValid) {
    +-            try {
    +-                offerPacket = DhcpPacket.decodeFullPacket(packet, ENCAP_BOOTP);
    +-                fail("Invalid packet parsed successfully: " + offerPacket);
    +-            } catch (ParseException expected) {
    +-            }
    +-            return;
    +-        }
    +-
    +-        offerPacket = DhcpPacket.decodeFullPacket(packet, ENCAP_BOOTP);
    +-        assertNotNull(offerPacket);
    +-        assertEquals(rawLeaseTime, offerPacket.mLeaseTime);
    +-        DhcpResults dhcpResults = offerPacket.toDhcpResults();  // Just check this doesn't crash.
    +-        assertEquals(leaseTimeMillis, offerPacket.getLeaseTimeMillis());
    +-    }
    +-
    +-    @SmallTest
    +-    public void testLeaseTime() throws Exception {
    +-        byte[] noLease = null;
    +-        byte[] tooShortLease = new byte[] { 0x00, 0x00 };
    +-        byte[] tooLongLease = new byte[] { 0x00, 0x00, 0x00, 60, 0x01 };
    +-        byte[] zeroLease = new byte[] { 0x00, 0x00, 0x00, 0x00 };
    +-        byte[] tenSecondLease = new byte[] { 0x00, 0x00, 0x00, 10 };
    +-        byte[] oneMinuteLease = new byte[] { 0x00, 0x00, 0x00, 60 };
    +-        byte[] fiveMinuteLease = new byte[] { 0x00, 0x00, 0x01, 0x2c };
    +-        byte[] oneDayLease = new byte[] { 0x00, 0x01, 0x51, (byte) 0x80 };
    +-        byte[] maxIntPlusOneLease = new byte[] { (byte) 0x80, 0x00, 0x00, 0x01 };
    +-        byte[] infiniteLease = new byte[] { (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff };
    +-
    +-        assertLeaseTimeParses(true, null, 0, noLease);
    +-        assertLeaseTimeParses(false, null, 0, tooShortLease);
    +-        assertLeaseTimeParses(false, null, 0, tooLongLease);
    +-        assertLeaseTimeParses(true, 0, 60 * 1000, zeroLease);
    +-        assertLeaseTimeParses(true, 10, 60 * 1000, tenSecondLease);
    +-        assertLeaseTimeParses(true, 60, 60 * 1000, oneMinuteLease);
    +-        assertLeaseTimeParses(true, 300, 300 * 1000, fiveMinuteLease);
    +-        assertLeaseTimeParses(true, 86400, 86400 * 1000, oneDayLease);
    +-        assertLeaseTimeParses(true, -2147483647, 2147483649L * 1000, maxIntPlusOneLease);
    +-        assertLeaseTimeParses(true, DhcpPacket.INFINITE_LEASE, 0, infiniteLease);
    +-    }
    +-
    +-    private void checkIpAddress(String expected, Inet4Address clientIp, Inet4Address yourIp,
    +-                                byte[] netmaskBytes) throws Exception {
    +-        checkIpAddress(expected, DHCP_MESSAGE_TYPE_OFFER, clientIp, yourIp, netmaskBytes);
    +-        checkIpAddress(expected, DHCP_MESSAGE_TYPE_ACK, clientIp, yourIp, netmaskBytes);
    +-    }
    +-
    +-    private void checkIpAddress(String expected, byte type,
    +-                                Inet4Address clientIp, Inet4Address yourIp,
    +-                                byte[] netmaskBytes) throws Exception {
    +-        ByteBuffer packet = new TestDhcpPacket(type, clientIp, yourIp)
    +-                .setNetmaskBytes(netmaskBytes)
    +-                .build();
    +-        DhcpPacket offerPacket = DhcpPacket.decodeFullPacket(packet, ENCAP_BOOTP);
    +-        DhcpResults results = offerPacket.toDhcpResults();
    +-
    +-        if (expected != null) {
    +-            LinkAddress expectedAddress = new LinkAddress(expected);
    +-            assertEquals(expectedAddress, results.ipAddress);
    +-        } else {
    +-            assertNull(results);
    +-        }
    +-    }
    +-
    +-    @SmallTest
    +-    public void testIpAddress() throws Exception {
    +-        byte[] slash11Netmask = new byte[] { (byte) 0xff, (byte) 0xe0, 0x00, 0x00 };
    +-        byte[] slash24Netmask = new byte[] { (byte) 0xff, (byte) 0xff, (byte) 0xff, 0x00 };
    +-        byte[] invalidNetmask = new byte[] { (byte) 0xff, (byte) 0xfb, (byte) 0xff, 0x00 };
    +-        Inet4Address example1 = v4Address("192.0.2.1");
    +-        Inet4Address example2 = v4Address("192.0.2.43");
    +-
    +-        // A packet without any addresses is not valid.
    +-        checkIpAddress(null, ANY, ANY, slash24Netmask);
    +-
    +-        // ClientIP is used iff YourIP is not present.
    +-        checkIpAddress("192.0.2.1/24", example2, example1, slash24Netmask);
    +-        checkIpAddress("192.0.2.43/11", example2, ANY, slash11Netmask);
    +-        checkIpAddress("192.0.2.43/11", ANY, example2, slash11Netmask);
    +-
    +-        // Invalid netmasks are ignored.
    +-        checkIpAddress(null, example2, ANY, invalidNetmask);
    +-
    +-        // If there is no netmask, implicit netmasks are used.
    +-        checkIpAddress("192.0.2.43/24", ANY, example2, null);
    +-    }
    +-
    +-    private void assertDhcpResults(String ipAddress, String gateway, String dnsServersString,
    +-            String domains, String serverAddress, String vendorInfo, int leaseDuration,
    +-            boolean hasMeteredHint, int mtu, DhcpResults dhcpResults) throws Exception {
    +-        assertEquals(new LinkAddress(ipAddress), dhcpResults.ipAddress);
    +-        assertEquals(v4Address(gateway), dhcpResults.gateway);
    +-
    +-        String[] dnsServerStrings = dnsServersString.split(",");
    +-        ArrayList dnsServers = new ArrayList();
    +-        for (String dnsServerString : dnsServerStrings) {
    +-            dnsServers.add(v4Address(dnsServerString));
    +-        }
    +-        assertEquals(dnsServers, dhcpResults.dnsServers);
    +-
    +-        assertEquals(domains, dhcpResults.domains);
    +-        assertEquals(v4Address(serverAddress), dhcpResults.serverAddress);
    +-        assertEquals(vendorInfo, dhcpResults.vendorInfo);
    +-        assertEquals(leaseDuration, dhcpResults.leaseDuration);
    +-        assertEquals(hasMeteredHint, dhcpResults.hasMeteredHint());
    +-        assertEquals(mtu, dhcpResults.mtu);
    +-    }
    +-
    +-    @SmallTest
    +-    public void testOffer1() throws Exception {
    +-        // TODO: Turn all of these into golden files. This will probably require modifying
    +-        // Android.mk appropriately, making this into an AndroidTestCase, and adding code to read
    +-        // the golden files from the test APK's assets via mContext.getAssets().
    +-        final ByteBuffer packet = ByteBuffer.wrap(HexEncoding.decode((
    +-            // IP header.
    +-            "451001480000000080118849c0a89003c0a89ff7" +
    +-            // UDP header.
    +-            "004300440134dcfa" +
    +-            // BOOTP header.
    +-            "02010600c997a63b0000000000000000c0a89ff70000000000000000" +
    +-            // MAC address.
    +-            "30766ff2a90c00000000000000000000" +
    +-            // Server name.
    +-            "0000000000000000000000000000000000000000000000000000000000000000" +
    +-            "0000000000000000000000000000000000000000000000000000000000000000" +
    +-            // File.
    +-            "0000000000000000000000000000000000000000000000000000000000000000" +
    +-            "0000000000000000000000000000000000000000000000000000000000000000" +
    +-            "0000000000000000000000000000000000000000000000000000000000000000" +
    +-            "0000000000000000000000000000000000000000000000000000000000000000" +
    +-            // Options
    +-            "638253633501023604c0a89003330400001c200104fffff0000304c0a89ffe06080808080808080404" +
    +-            "3a0400000e103b040000189cff00000000000000000000"
    +-        ).toCharArray(), false));
    +-
    +-        DhcpPacket offerPacket = DhcpPacket.decodeFullPacket(packet, ENCAP_L3);
    +-        assertTrue(offerPacket instanceof DhcpOfferPacket);  // Implicitly checks it's non-null.
    +-        DhcpResults dhcpResults = offerPacket.toDhcpResults();
    +-        assertDhcpResults("192.168.159.247/20", "192.168.159.254", "8.8.8.8,8.8.4.4",
    +-                null, "192.168.144.3", null, 7200, false, 0, dhcpResults);
    +-    }
    +-
    +-    @SmallTest
    +-    public void testOffer2() throws Exception {
    +-        final ByteBuffer packet = ByteBuffer.wrap(HexEncoding.decode((
    +-            // IP header.
    +-            "450001518d0600004011144dc0a82b01c0a82bf7" +
    +-            // UDP header.
    +-            "00430044013d9ac7" +
    +-            // BOOTP header.
    +-            "02010600dfc23d1f0002000000000000c0a82bf7c0a82b0100000000" +
    +-            // MAC address.
    +-            "30766ff2a90c00000000000000000000" +
    +-            // Server name.
    +-            "0000000000000000000000000000000000000000000000000000000000000000" +
    +-            "0000000000000000000000000000000000000000000000000000000000000000" +
    +-            // File.
    +-            "0000000000000000000000000000000000000000000000000000000000000000" +
    +-            "0000000000000000000000000000000000000000000000000000000000000000" +
    +-            "0000000000000000000000000000000000000000000000000000000000000000" +
    +-            "0000000000000000000000000000000000000000000000000000000000000000" +
    +-            // Options
    +-            "638253633501023604c0a82b01330400000e103a04000007083b0400000c4e0104ffffff00" +
    +-            "1c04c0a82bff0304c0a82b010604c0a82b012b0f414e44524f49445f4d455445524544ff"
    +-        ).toCharArray(), false));
    +-
    +-        assertEquals(337, packet.limit());
    +-        DhcpPacket offerPacket = DhcpPacket.decodeFullPacket(packet, ENCAP_L3);
    +-        assertTrue(offerPacket instanceof DhcpOfferPacket);  // Implicitly checks it's non-null.
    +-        DhcpResults dhcpResults = offerPacket.toDhcpResults();
    +-        assertDhcpResults("192.168.43.247/24", "192.168.43.1", "192.168.43.1",
    +-                null, "192.168.43.1", "ANDROID_METERED", 3600, true, 0, dhcpResults);
    +-        assertTrue(dhcpResults.hasMeteredHint());
    +-    }
    +-
    +-    private byte[] mtuBytes(int mtu) {
    +-        // 0x1a02: option 26, length 2. 0xff: no more options.
    +-        if (mtu > Short.MAX_VALUE - Short.MIN_VALUE) {
    +-            throw new IllegalArgumentException(
    +-                String.format("Invalid MTU %d, must be 16-bit unsigned", mtu));
    +-        }
    +-        String hexString = String.format("1a02%04xff", mtu);
    +-        return HexEncoding.decode(hexString.toCharArray(), false);
    +-    }
    +-
    +-    private void checkMtu(ByteBuffer packet, int expectedMtu, byte[] mtuBytes) throws Exception {
    +-        if (mtuBytes != null) {
    +-            packet.position(packet.capacity() - mtuBytes.length);
    +-            packet.put(mtuBytes);
    +-            packet.clear();
    +-        }
    +-        DhcpPacket offerPacket = DhcpPacket.decodeFullPacket(packet, ENCAP_L3);
    +-        assertTrue(offerPacket instanceof DhcpOfferPacket);  // Implicitly checks it's non-null.
    +-        DhcpResults dhcpResults = offerPacket.toDhcpResults();
    +-        assertDhcpResults("192.168.159.247/20", "192.168.159.254", "8.8.8.8,8.8.4.4",
    +-                null, "192.168.144.3", null, 7200, false, expectedMtu, dhcpResults);
    +-    }
    +-
    +-    @SmallTest
    +-    public void testMtu() throws Exception {
    +-        final ByteBuffer packet = ByteBuffer.wrap(HexEncoding.decode((
    +-            // IP header.
    +-            "451001480000000080118849c0a89003c0a89ff7" +
    +-            // UDP header.
    +-            "004300440134dcfa" +
    +-            // BOOTP header.
    +-            "02010600c997a63b0000000000000000c0a89ff70000000000000000" +
    +-            // MAC address.
    +-            "30766ff2a90c00000000000000000000" +
    +-            // Server name.
    +-            "0000000000000000000000000000000000000000000000000000000000000000" +
    +-            "0000000000000000000000000000000000000000000000000000000000000000" +
    +-            // File.
    +-            "0000000000000000000000000000000000000000000000000000000000000000" +
    +-            "0000000000000000000000000000000000000000000000000000000000000000" +
    +-            "0000000000000000000000000000000000000000000000000000000000000000" +
    +-            "0000000000000000000000000000000000000000000000000000000000000000" +
    +-            // Options
    +-            "638253633501023604c0a89003330400001c200104fffff0000304c0a89ffe06080808080808080404" +
    +-            "3a0400000e103b040000189cff00000000"
    +-        ).toCharArray(), false));
    +-
    +-        checkMtu(packet, 0, null);
    +-        checkMtu(packet, 0, mtuBytes(1501));
    +-        checkMtu(packet, 1500, mtuBytes(1500));
    +-        checkMtu(packet, 1499, mtuBytes(1499));
    +-        checkMtu(packet, 1280, mtuBytes(1280));
    +-        checkMtu(packet, 0, mtuBytes(1279));
    +-        checkMtu(packet, 0, mtuBytes(576));
    +-        checkMtu(packet, 0, mtuBytes(68));
    +-        checkMtu(packet, 0, mtuBytes(Short.MIN_VALUE));
    +-        checkMtu(packet, 0, mtuBytes(Short.MAX_VALUE + 3));
    +-        checkMtu(packet, 0, mtuBytes(-1));
    +-    }
    +-
    +-    @SmallTest
    +-    public void testBadHwaddrLength() throws Exception {
    +-        final ByteBuffer packet = ByteBuffer.wrap(HexEncoding.decode((
    +-            // IP header.
    +-            "450001518d0600004011144dc0a82b01c0a82bf7" +
    +-            // UDP header.
    +-            "00430044013d9ac7" +
    +-            // BOOTP header.
    +-            "02010600dfc23d1f0002000000000000c0a82bf7c0a82b0100000000" +
    +-            // MAC address.
    +-            "30766ff2a90c00000000000000000000" +
    +-            // Server name.
    +-            "0000000000000000000000000000000000000000000000000000000000000000" +
    +-            "0000000000000000000000000000000000000000000000000000000000000000" +
    +-            // File.
    +-            "0000000000000000000000000000000000000000000000000000000000000000" +
    +-            "0000000000000000000000000000000000000000000000000000000000000000" +
    +-            "0000000000000000000000000000000000000000000000000000000000000000" +
    +-            "0000000000000000000000000000000000000000000000000000000000000000" +
    +-            // Options
    +-            "638253633501023604c0a82b01330400000e103a04000007083b0400000c4e0104ffffff00" +
    +-            "1c04c0a82bff0304c0a82b010604c0a82b012b0f414e44524f49445f4d455445524544ff"
    +-        ).toCharArray(), false));
    +-        String expectedClientMac = "30766FF2A90C";
    +-
    +-        final int hwAddrLenOffset = 20 + 8 + 2;
    +-        assertEquals(6, packet.get(hwAddrLenOffset));
    +-
    +-        // Expect the expected.
    +-        DhcpPacket offerPacket = DhcpPacket.decodeFullPacket(packet, ENCAP_L3);
    +-        assertNotNull(offerPacket);
    +-        assertEquals(6, offerPacket.getClientMac().length);
    +-        assertEquals(expectedClientMac, HexDump.toHexString(offerPacket.getClientMac()));
    +-
    +-        // Reduce the hardware address length and verify that it shortens the client MAC.
    +-        packet.flip();
    +-        packet.put(hwAddrLenOffset, (byte) 5);
    +-        offerPacket = DhcpPacket.decodeFullPacket(packet, ENCAP_L3);
    +-        assertNotNull(offerPacket);
    +-        assertEquals(5, offerPacket.getClientMac().length);
    +-        assertEquals(expectedClientMac.substring(0, 10),
    +-                HexDump.toHexString(offerPacket.getClientMac()));
    +-
    +-        packet.flip();
    +-        packet.put(hwAddrLenOffset, (byte) 3);
    +-        offerPacket = DhcpPacket.decodeFullPacket(packet, ENCAP_L3);
    +-        assertNotNull(offerPacket);
    +-        assertEquals(3, offerPacket.getClientMac().length);
    +-        assertEquals(expectedClientMac.substring(0, 6),
    +-                HexDump.toHexString(offerPacket.getClientMac()));
    +-
    +-        // Set the the hardware address length to 0xff and verify that we a) don't treat it as -1
    +-        // and crash, and b) hardcode it to 6.
    +-        packet.flip();
    +-        packet.put(hwAddrLenOffset, (byte) -1);
    +-        offerPacket = DhcpPacket.decodeFullPacket(packet, ENCAP_L3);
    +-        assertNotNull(offerPacket);
    +-        assertEquals(6, offerPacket.getClientMac().length);
    +-        assertEquals(expectedClientMac, HexDump.toHexString(offerPacket.getClientMac()));
    +-
    +-        // Set the the hardware address length to a positive invalid value (> 16) and verify that we
    +-        // hardcode it to 6.
    +-        packet.flip();
    +-        packet.put(hwAddrLenOffset, (byte) 17);
    +-        offerPacket = DhcpPacket.decodeFullPacket(packet, ENCAP_L3);
    +-        assertNotNull(offerPacket);
    +-        assertEquals(6, offerPacket.getClientMac().length);
    +-        assertEquals(expectedClientMac, HexDump.toHexString(offerPacket.getClientMac()));
    +-    }
    +-
    +-    @SmallTest
    +-    public void testPadAndOverloadedOptionsOffer() throws Exception {
    +-        // A packet observed in the real world that is interesting for two reasons:
    +-        //
    +-        // 1. It uses pad bytes, which we previously didn't support correctly.
    +-        // 2. It uses DHCP option overloading, which we don't currently support (but it doesn't
    +-        //    store any information in the overloaded fields).
    +-        //
    +-        // For now, we just check that it parses correctly.
    +-        final ByteBuffer packet = ByteBuffer.wrap(HexEncoding.decode((
    +-            // Ethernet header.
    +-            "b4cef6000000e80462236e300800" +
    +-            // IP header.
    +-            "4500014c00000000ff11741701010101ac119876" +
    +-            // UDP header. TODO: fix invalid checksum (due to MAC address obfuscation).
    +-            "004300440138ae5a" +
    +-            // BOOTP header.
    +-            "020106000fa0059f0000000000000000ac1198760000000000000000" +
    +-            // MAC address.
    +-            "b4cef600000000000000000000000000" +
    +-            // Server name.
    +-            "ff00000000000000000000000000000000000000000000000000000000000000" +
    +-            "0000000000000000000000000000000000000000000000000000000000000000" +
    +-            // File.
    +-            "ff00000000000000000000000000000000000000000000000000000000000000" +
    +-            "0000000000000000000000000000000000000000000000000000000000000000" +
    +-            "0000000000000000000000000000000000000000000000000000000000000000" +
    +-            "0000000000000000000000000000000000000000000000000000000000000000" +
    +-            // Options
    +-            "638253633501023604010101010104ffff000033040000a8c03401030304ac1101010604ac110101" +
    +-            "0000000000000000000000000000000000000000000000ff000000"
    +-        ).toCharArray(), false));
    +-
    +-        DhcpPacket offerPacket = DhcpPacket.decodeFullPacket(packet, ENCAP_L2);
    +-        assertTrue(offerPacket instanceof DhcpOfferPacket);
    +-        DhcpResults dhcpResults = offerPacket.toDhcpResults();
    +-        assertDhcpResults("172.17.152.118/16", "172.17.1.1", "172.17.1.1",
    +-                null, "1.1.1.1", null, 43200, false, 0, dhcpResults);
    +-    }
    +-
    +-    @SmallTest
    +-    public void testBug2111() throws Exception {
    +-        final ByteBuffer packet = ByteBuffer.wrap(HexEncoding.decode((
    +-            // IP header.
    +-            "4500014c00000000ff119beac3eaf3880a3f5d04" +
    +-            // UDP header. TODO: fix invalid checksum (due to MAC address obfuscation).
    +-            "0043004401387464" +
    +-            // BOOTP header.
    +-            "0201060002554812000a0000000000000a3f5d040000000000000000" +
    +-            // MAC address.
    +-            "00904c00000000000000000000000000" +
    +-            // Server name.
    +-            "0000000000000000000000000000000000000000000000000000000000000000" +
    +-            "0000000000000000000000000000000000000000000000000000000000000000" +
    +-            // File.
    +-            "0000000000000000000000000000000000000000000000000000000000000000" +
    +-            "0000000000000000000000000000000000000000000000000000000000000000" +
    +-            "0000000000000000000000000000000000000000000000000000000000000000" +
    +-            "0000000000000000000000000000000000000000000000000000000000000000" +
    +-            // Options.
    +-            "638253633501023604c00002fe33040000bfc60104fffff00003040a3f50010608c0000201c0000202" +
    +-            "0f0f646f6d61696e3132332e636f2e756b0000000000ff00000000"
    +-        ).toCharArray(), false));
    +-
    +-        DhcpPacket offerPacket = DhcpPacket.decodeFullPacket(packet, ENCAP_L3);
    +-        assertTrue(offerPacket instanceof DhcpOfferPacket);
    +-        DhcpResults dhcpResults = offerPacket.toDhcpResults();
    +-        assertDhcpResults("10.63.93.4/20", "10.63.80.1", "192.0.2.1,192.0.2.2",
    +-                "domain123.co.uk", "192.0.2.254", null, 49094, false, 0, dhcpResults);
    +-    }
    +-
    +-    @SmallTest
    +-    public void testBug2136() throws Exception {
    +-        final ByteBuffer packet = ByteBuffer.wrap(HexEncoding.decode((
    +-            // Ethernet header.
    +-            "bcf5ac000000d0c7890000000800" +
    +-            // IP header.
    +-            "4500014c00000000ff119beac3eaf3880a3f5d04" +
    +-            // UDP header. TODO: fix invalid checksum (due to MAC address obfuscation).
    +-            "0043004401387574" +
    +-            // BOOTP header.
    +-            "0201060163339a3000050000000000000a209ecd0000000000000000" +
    +-            // MAC address.
    +-            "bcf5ac00000000000000000000000000" +
    +-            // Server name.
    +-            "0000000000000000000000000000000000000000000000000000000000000000" +
    +-            "0000000000000000000000000000000000000000000000000000000000000000" +
    +-            // File.
    +-            "0000000000000000000000000000000000000000000000000000000000000000" +
    +-            "0000000000000000000000000000000000000000000000000000000000000000" +
    +-            "0000000000000000000000000000000000000000000000000000000000000000" +
    +-            "0000000000000000000000000000000000000000000000000000000000000000" +
    +-            // Options.
    +-            "6382536335010236040a20ff80330400001c200104fffff00003040a20900106089458413494584135" +
    +-            "0f0b6c616e63732e61632e756b000000000000000000ff00000000"
    +-        ).toCharArray(), false));
    +-
    +-        DhcpPacket offerPacket = DhcpPacket.decodeFullPacket(packet, ENCAP_L2);
    +-        assertTrue(offerPacket instanceof DhcpOfferPacket);
    +-        assertEquals("BCF5AC000000", HexDump.toHexString(offerPacket.getClientMac()));
    +-        DhcpResults dhcpResults = offerPacket.toDhcpResults();
    +-        assertDhcpResults("10.32.158.205/20", "10.32.144.1", "148.88.65.52,148.88.65.53",
    +-                "lancs.ac.uk", "10.32.255.128", null, 7200, false, 0, dhcpResults);
    +-    }
    +-
    +-    @SmallTest
    +-    public void testUdpServerAnySourcePort() throws Exception {
    +-        final ByteBuffer packet = ByteBuffer.wrap(HexEncoding.decode((
    +-            // Ethernet header.
    +-            "9cd917000000001c2e0000000800" +
    +-            // IP header.
    +-            "45a00148000040003d115087d18194fb0a0f7af2" +
    +-            // UDP header. TODO: fix invalid checksum (due to MAC address obfuscation).
    +-            // NOTE: The server source port is not the canonical port 67.
    +-            "C29F004401341268" +
    +-            // BOOTP header.
    +-            "02010600d628ba8200000000000000000a0f7af2000000000a0fc818" +
    +-            // MAC address.
    +-            "9cd91700000000000000000000000000" +
    +-            // Server name.
    +-            "0000000000000000000000000000000000000000000000000000000000000000" +
    +-            "0000000000000000000000000000000000000000000000000000000000000000" +
    +-            // File.
    +-            "0000000000000000000000000000000000000000000000000000000000000000" +
    +-            "0000000000000000000000000000000000000000000000000000000000000000" +
    +-            "0000000000000000000000000000000000000000000000000000000000000000" +
    +-            "0000000000000000000000000000000000000000000000000000000000000000" +
    +-            // Options.
    +-            "6382536335010236040a0169fc3304000151800104ffff000003040a0fc817060cd1818003d1819403" +
    +-            "d18180060f0777766d2e6564751c040a0fffffff000000"
    +-        ).toCharArray(), false));
    +-
    +-        DhcpPacket offerPacket = DhcpPacket.decodeFullPacket(packet, ENCAP_L2);
    +-        assertTrue(offerPacket instanceof DhcpOfferPacket);
    +-        assertEquals("9CD917000000", HexDump.toHexString(offerPacket.getClientMac()));
    +-        DhcpResults dhcpResults = offerPacket.toDhcpResults();
    +-        assertDhcpResults("10.15.122.242/16", "10.15.200.23",
    +-                "209.129.128.3,209.129.148.3,209.129.128.6",
    +-                "wvm.edu", "10.1.105.252", null, 86400, false, 0, dhcpResults);
    +-    }
    +-
    +-    @SmallTest
    +-    public void testUdpInvalidDstPort() throws Exception {
    +-        final ByteBuffer packet = ByteBuffer.wrap(HexEncoding.decode((
    +-            // Ethernet header.
    +-            "9cd917000000001c2e0000000800" +
    +-            // IP header.
    +-            "45a00148000040003d115087d18194fb0a0f7af2" +
    +-            // UDP header. TODO: fix invalid checksum (due to MAC address obfuscation).
    +-            // NOTE: The destination port is a non-DHCP port.
    +-            "0043aaaa01341268" +
    +-            // BOOTP header.
    +-            "02010600d628ba8200000000000000000a0f7af2000000000a0fc818" +
    +-            // MAC address.
    +-            "9cd91700000000000000000000000000" +
    +-            // Server name.
    +-            "0000000000000000000000000000000000000000000000000000000000000000" +
    +-            "0000000000000000000000000000000000000000000000000000000000000000" +
    +-            // File.
    +-            "0000000000000000000000000000000000000000000000000000000000000000" +
    +-            "0000000000000000000000000000000000000000000000000000000000000000" +
    +-            "0000000000000000000000000000000000000000000000000000000000000000" +
    +-            "0000000000000000000000000000000000000000000000000000000000000000" +
    +-            // Options.
    +-            "6382536335010236040a0169fc3304000151800104ffff000003040a0fc817060cd1818003d1819403" +
    +-            "d18180060f0777766d2e6564751c040a0fffffff000000"
    +-        ).toCharArray(), false));
    +-
    +-        try {
    +-            DhcpPacket.decodeFullPacket(packet, ENCAP_L2);
    +-            fail("Packet with invalid dst port did not throw ParseException");
    +-        } catch (ParseException expected) {}
    +-    }
    +-
    +-    @SmallTest
    +-    public void testMultipleRouters() throws Exception {
    +-        final ByteBuffer packet = ByteBuffer.wrap(HexEncoding.decode((
    +-            // Ethernet header.
    +-            "fc3d93000000" + "081735000000" + "0800" +
    +-            // IP header.
    +-            "45000148c2370000ff117ac2c0a8bd02ffffffff" +
    +-            // UDP header. TODO: fix invalid checksum (due to MAC address obfuscation).
    +-            "0043004401343beb" +
    +-            // BOOTP header.
    +-            "0201060027f518e20000800000000000c0a8bd310000000000000000" +
    +-            // MAC address.
    +-            "fc3d9300000000000000000000000000" +
    +-            // Server name.
    +-            "0000000000000000000000000000000000000000000000000000000000000000" +
    +-            "0000000000000000000000000000000000000000000000000000000000000000" +
    +-            // File.
    +-            "0000000000000000000000000000000000000000000000000000000000000000" +
    +-            "0000000000000000000000000000000000000000000000000000000000000000" +
    +-            "0000000000000000000000000000000000000000000000000000000000000000" +
    +-            "0000000000000000000000000000000000000000000000000000000000000000" +
    +-            // Options.
    +-            "638253633501023604c0abbd023304000070803a04000038403b04000062700104ffffff00" +
    +-            "0308c0a8bd01ffffff0006080808080808080404ff000000000000"
    +-        ).toCharArray(), false));
    +-
    +-        DhcpPacket offerPacket = DhcpPacket.decodeFullPacket(packet, ENCAP_L2);
    +-        assertTrue(offerPacket instanceof DhcpOfferPacket);
    +-        assertEquals("FC3D93000000", HexDump.toHexString(offerPacket.getClientMac()));
    +-        DhcpResults dhcpResults = offerPacket.toDhcpResults();
    +-        assertDhcpResults("192.168.189.49/24", "192.168.189.1", "8.8.8.8,8.8.4.4",
    +-                null, "192.171.189.2", null, 28800, false, 0, dhcpResults);
    +-    }
    +-
    +-    @SmallTest
    +-    public void testDiscoverPacket() throws Exception {
    +-        short secs = 7;
    +-        int transactionId = 0xdeadbeef;
    +-        byte[] hwaddr = {
    +-                (byte) 0xda, (byte) 0x01, (byte) 0x19, (byte) 0x5b, (byte) 0xb1, (byte) 0x7a
    +-        };
    +-
    +-        ByteBuffer packet = DhcpPacket.buildDiscoverPacket(
    +-                DhcpPacket.ENCAP_L2, transactionId, secs, hwaddr,
    +-                false /* do unicast */, DhcpClient.REQUESTED_PARAMS);
    +-
    +-        byte[] headers = new byte[] {
    +-            // Ethernet header.
    +-            (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
    +-            (byte) 0xda, (byte) 0x01, (byte) 0x19, (byte) 0x5b, (byte) 0xb1, (byte) 0x7a,
    +-            (byte) 0x08, (byte) 0x00,
    +-            // IP header.
    +-            (byte) 0x45, (byte) 0x10, (byte) 0x01, (byte) 0x56,
    +-            (byte) 0x00, (byte) 0x00, (byte) 0x40, (byte) 0x00,
    +-            (byte) 0x40, (byte) 0x11, (byte) 0x39, (byte) 0x88,
    +-            (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
    +-            (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
    +-            // UDP header.
    +-            (byte) 0x00, (byte) 0x44, (byte) 0x00, (byte) 0x43,
    +-            (byte) 0x01, (byte) 0x42, (byte) 0x6a, (byte) 0x4a,
    +-            // BOOTP.
    +-            (byte) 0x01, (byte) 0x01, (byte) 0x06, (byte) 0x00,
    +-            (byte) 0xde, (byte) 0xad, (byte) 0xbe, (byte) 0xef,
    +-            (byte) 0x00, (byte) 0x07, (byte) 0x00, (byte) 0x00,
    +-            (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
    +-            (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
    +-            (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
    +-            (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
    +-            (byte) 0xda, (byte) 0x01, (byte) 0x19, (byte) 0x5b,
    +-            (byte) 0xb1, (byte) 0x7a
    +-        };
    +-        byte[] options = new byte[] {
    +-            // Magic cookie 0x63825363.
    +-            (byte) 0x63, (byte) 0x82, (byte) 0x53, (byte) 0x63,
    +-            // Message type DISCOVER.
    +-            (byte) 0x35, (byte) 0x01, (byte) 0x01,
    +-            // Client identifier Ethernet, da:01:19:5b:b1:7a.
    +-            (byte) 0x3d, (byte) 0x07,
    +-                    (byte) 0x01,
    +-                    (byte) 0xda, (byte) 0x01, (byte) 0x19, (byte) 0x5b, (byte) 0xb1, (byte) 0x7a,
    +-            // Max message size 1500.
    +-            (byte) 0x39, (byte) 0x02, (byte) 0x05, (byte) 0xdc,
    +-            // Version "android-dhcp-???".
    +-            (byte) 0x3c, (byte) 0x10,
    +-                    'a', 'n', 'd', 'r', 'o', 'i', 'd', '-', 'd', 'h', 'c', 'p', '-', '?', '?', '?',
    +-            // Hostname "android-01234567890abcde"
    +-            (byte) 0x0c, (byte) 0x18,
    +-                    'a', 'n', 'd', 'r', 'o', 'i', 'd', '-',
    +-                    '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', 'a', 'b', 'c', 'd', 'e',
    +-            // Requested parameter list.
    +-            (byte) 0x37, (byte) 0x0a,
    +-                DHCP_SUBNET_MASK,
    +-                DHCP_ROUTER,
    +-                DHCP_DNS_SERVER,
    +-                DHCP_DOMAIN_NAME,
    +-                DHCP_MTU,
    +-                DHCP_BROADCAST_ADDRESS,
    +-                DHCP_LEASE_TIME,
    +-                DHCP_RENEWAL_TIME,
    +-                DHCP_REBINDING_TIME,
    +-                DHCP_VENDOR_INFO,
    +-            // End options.
    +-            (byte) 0xff,
    +-            // Our packets are always of even length. TODO: find out why and possibly fix it.
    +-            (byte) 0x00
    +-        };
    +-        byte[] expected = new byte[DhcpPacket.MIN_PACKET_LENGTH_L2 + options.length];
    +-        assertTrue((expected.length & 1) == 0);
    +-        System.arraycopy(headers, 0, expected, 0, headers.length);
    +-        System.arraycopy(options, 0, expected, DhcpPacket.MIN_PACKET_LENGTH_L2, options.length);
    +-
    +-        byte[] actual = new byte[packet.limit()];
    +-        packet.get(actual);
    +-        String msg =
    +-                "Expected:\n  " + Arrays.toString(expected) +
    +-                "\nActual:\n  " + Arrays.toString(actual);
    +-        assertTrue(msg, Arrays.equals(expected, actual));
    +-    }
    +-}
    +diff --git a/services/tests/servicestests/src/android/net/metrics/IpConnectivityLogTest.java b/services/tests/servicestests/src/android/net/metrics/IpConnectivityLogTest.java
    +deleted file mode 100644
    +index 1433f95..0000000
    +--- a/services/tests/servicestests/src/android/net/metrics/IpConnectivityLogTest.java
    ++++ /dev/null
    +@@ -1,162 +0,0 @@
    +-/*
    +- * Copyright (C) 2016, 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 android.net.metrics;
    +-
    +-import android.os.Bundle;
    +-import android.os.Parcel;
    +-import android.net.ConnectivityMetricsEvent;
    +-import android.net.IConnectivityMetricsLogger;
    +-
    +-import junit.framework.TestCase;
    +-import org.junit.Before;
    +-import org.junit.Test;
    +-
    +-import org.mockito.ArgumentCaptor;
    +-import org.mockito.Mock;
    +-import org.mockito.MockitoAnnotations;
    +-import static org.mockito.Mockito.any;
    +-import static org.mockito.Mockito.eq;
    +-import static org.mockito.Mockito.timeout;
    +-import static org.mockito.Mockito.times;
    +-import static org.mockito.Mockito.verify;
    +-import static org.mockito.Mockito.when;
    +-
    +-import java.util.List;
    +-
    +-public class IpConnectivityLogTest extends TestCase {
    +-
    +-    // use same Parcel object everywhere for pointer equality
    +-    static final Bundle FAKE_EV = new Bundle();
    +-
    +-    @Mock IConnectivityMetricsLogger mService;
    +-    ArgumentCaptor<ConnectivityMetricsEvent> evCaptor;
    +-
    +-    IpConnectivityLog mLog;
    +-
    +-    public void setUp() {
    +-        MockitoAnnotations.initMocks(this);
    +-        evCaptor = ArgumentCaptor.forClass(ConnectivityMetricsEvent.class);
    +-        mLog = new IpConnectivityLog(mService);
    +-    }
    +-
    +-    public void testLogEvents() throws Exception {
    +-        assertTrue(mLog.log(1, FAKE_EV));
    +-        assertTrue(mLog.log(2, FAKE_EV));
    +-        assertTrue(mLog.log(3, FAKE_EV));
    +-
    +-        List<ConnectivityMetricsEvent> gotEvents = verifyEvents(3);
    +-        assertEventsEqual(expectedEvent(1), gotEvents.get(0));
    +-        assertEventsEqual(expectedEvent(2), gotEvents.get(1));
    +-        assertEventsEqual(expectedEvent(3), gotEvents.get(2));
    +-    }
    +-
    +-    public void testLogEventTriggerThrottling() throws Exception {
    +-        when(mService.logEvent(any())).thenReturn(1234L);
    +-
    +-        assertFalse(mLog.log(1, FAKE_EV));
    +-    }
    +-
    +-    public void testLogEventFails() throws Exception {
    +-        when(mService.logEvent(any())).thenReturn(-1L); // Error.
    +-
    +-        assertFalse(mLog.log(1, FAKE_EV));
    +-    }
    +-
    +-    public void testLogEventWhenThrottling() throws Exception {
    +-        when(mService.logEvent(any())).thenReturn(Long.MAX_VALUE); // Throttled
    +-
    +-        // No events are logged. The service is only called once
    +-        // After that, throttling state is maintained locally.
    +-        assertFalse(mLog.log(1, FAKE_EV));
    +-        assertFalse(mLog.log(2, FAKE_EV));
    +-
    +-        List<ConnectivityMetricsEvent> gotEvents = verifyEvents(1);
    +-        assertEventsEqual(expectedEvent(1), gotEvents.get(0));
    +-    }
    +-
    +-    public void testLogEventRecoverFromThrottling() throws Exception {
    +-        final long throttleTimeout = System.currentTimeMillis() + 50;
    +-        when(mService.logEvent(any())).thenReturn(throttleTimeout, 0L);
    +-
    +-        assertFalse(mLog.log(1, FAKE_EV));
    +-        new Thread() {
    +-            public void run() {
    +-                busySpinLog();
    +-            }
    +-        }.start();
    +-
    +-        List<ConnectivityMetricsEvent> gotEvents = verifyEvents(2, 200);
    +-        assertEventsEqual(expectedEvent(1), gotEvents.get(0));
    +-        assertEventsEqual(expectedEvent(2), gotEvents.get(1));
    +-    }
    +-
    +-    public void testLogEventRecoverFromThrottlingWithMultipleCallers() throws Exception {
    +-        final long throttleTimeout = System.currentTimeMillis() + 50;
    +-        when(mService.logEvent(any())).thenReturn(throttleTimeout, 0L);
    +-
    +-        assertFalse(mLog.log(1, FAKE_EV));
    +-        final int nCallers = 10;
    +-        for (int i = 0; i < nCallers; i++) {
    +-            new Thread() {
    +-                public void run() {
    +-                    busySpinLog();
    +-                }
    +-            }.start();
    +-        }
    +-
    +-        List<ConnectivityMetricsEvent> gotEvents = verifyEvents(1 + nCallers, 200);
    +-        assertEventsEqual(expectedEvent(1), gotEvents.get(0));
    +-        for (int i = 0; i < nCallers; i++) {
    +-            assertEventsEqual(expectedEvent(2), gotEvents.get(1 + i));
    +-        }
    +-    }
    +-
    +-    void busySpinLog() {
    +-        final long timeout = 200;
    +-        final long stop = System.currentTimeMillis() + timeout;
    +-        try {
    +-            while (System.currentTimeMillis() < stop) {
    +-                if (mLog.log(2, FAKE_EV)) {
    +-                    return;
    +-                }
    +-                Thread.sleep(10);
    +-            }
    +-        } catch (InterruptedException e) { }
    +-    }
    +-
    +-    List<ConnectivityMetricsEvent> verifyEvents(int n) throws Exception {
    +-        verify(mService, times(n)).logEvent(evCaptor.capture());
    +-        return evCaptor.getAllValues();
    +-    }
    +-
    +-    List<ConnectivityMetricsEvent> verifyEvents(int n, int timeoutMs) throws Exception {
    +-        verify(mService, timeout(timeoutMs).times(n)).logEvent(evCaptor.capture());
    +-        return evCaptor.getAllValues();
    +-    }
    +-
    +-    static ConnectivityMetricsEvent expectedEvent(int timestamp) {
    +-        return new ConnectivityMetricsEvent((long)timestamp, 0, 0, FAKE_EV);
    +-    }
    +-
    +-    /** Outer equality for ConnectivityMetricsEvent to avoid overriding equals() and hashCode(). */
    +-    static void assertEventsEqual(ConnectivityMetricsEvent expected, ConnectivityMetricsEvent got) {
    +-        assertEquals(expected.timestamp, got.timestamp);
    +-        assertEquals(expected.componentTag, got.componentTag);
    +-        assertEquals(expected.eventTag, got.eventTag);
    +-        assertEquals(expected.data, got.data);
    +-    }
    +-}
    +diff --git a/services/tests/servicestests/src/android/net/netlink/NetlinkErrorMessageTest.java b/services/tests/servicestests/src/android/net/netlink/NetlinkErrorMessageTest.java
    +deleted file mode 100644
    +index e677475..0000000
    +--- a/services/tests/servicestests/src/android/net/netlink/NetlinkErrorMessageTest.java
    ++++ /dev/null
    +@@ -1,82 +0,0 @@
    +-/*
    +- * Copyright (C) 2015 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 android.net.netlink;
    +-
    +-import static android.net.netlink.StructNlMsgHdr.NLM_F_REQUEST;
    +-import static android.net.netlink.StructNlMsgHdr.NLM_F_ACK;
    +-import static android.net.netlink.StructNlMsgHdr.NLM_F_REPLACE;
    +-
    +-import android.net.netlink.NetlinkConstants;
    +-import android.net.netlink.NetlinkErrorMessage;
    +-import android.net.netlink.NetlinkMessage;
    +-import android.net.netlink.StructNlMsgErr;
    +-import android.util.Log;
    +-import java.nio.ByteBuffer;
    +-import java.nio.ByteOrder;
    +-import junit.framework.TestCase;
    +-import libcore.util.HexEncoding;
    +-
    +-
    +-public class NetlinkErrorMessageTest extends TestCase {
    +-    private final String TAG = "NetlinkErrorMessageTest";
    +-
    +-    // Hexadecimal representation of packet capture.
    +-    public static final String NLM_ERROR_OK_HEX =
    +-            // struct nlmsghdr
    +-            "24000000" +     // length = 36
    +-            "0200"     +     // type = 2 (NLMSG_ERROR)
    +-            "0000"     +     // flags
    +-            "26350000" +     // seqno
    +-            "64100000" +     // pid = userspace process
    +-            // error integer
    +-            "00000000" +     // "errno" (0 == OK)
    +-            // struct nlmsghdr
    +-            "30000000" +     // length (48) of original request
    +-            "1C00"     +     // type = 28 (RTM_NEWNEIGH)
    +-            "0501"     +     // flags (NLM_F_REQUEST | NLM_F_ACK | NLM_F_REPLACE)
    +-            "26350000" +     // seqno
    +-            "00000000";      // pid = kernel
    +-    public static final byte[] NLM_ERROR_OK =
    +-            HexEncoding.decode(NLM_ERROR_OK_HEX.toCharArray(), false);
    +-
    +-    public void testParseNlmErrorOk() {
    +-        final ByteBuffer byteBuffer = ByteBuffer.wrap(NLM_ERROR_OK);
    +-        byteBuffer.order(ByteOrder.LITTLE_ENDIAN);  // For testing.
    +-        final NetlinkMessage msg = NetlinkMessage.parse(byteBuffer);
    +-        assertNotNull(msg);
    +-        assertTrue(msg instanceof NetlinkErrorMessage);
    +-        final NetlinkErrorMessage errorMsg = (NetlinkErrorMessage) msg;
    +-
    +-        final StructNlMsgHdr hdr = errorMsg.getHeader();
    +-        assertNotNull(hdr);
    +-        assertEquals(36, hdr.nlmsg_len);
    +-        assertEquals(NetlinkConstants.NLMSG_ERROR, hdr.nlmsg_type);
    +-        assertEquals(0, hdr.nlmsg_flags);
    +-        assertEquals(13606, hdr.nlmsg_seq);
    +-        assertEquals(4196, hdr.nlmsg_pid);
    +-
    +-        final StructNlMsgErr err = errorMsg.getNlMsgError();
    +-        assertNotNull(err);
    +-        assertEquals(0, err.error);
    +-        assertNotNull(err.msg);
    +-        assertEquals(48, err.msg.nlmsg_len);
    +-        assertEquals(NetlinkConstants.RTM_NEWNEIGH, err.msg.nlmsg_type);
    +-        assertEquals((NLM_F_REQUEST | NLM_F_ACK | NLM_F_REPLACE), err.msg.nlmsg_flags);
    +-        assertEquals(13606, err.msg.nlmsg_seq);
    +-        assertEquals(0, err.msg.nlmsg_pid);
    +-    }
    +-}
    +diff --git a/services/tests/servicestests/src/android/net/netlink/NetlinkSocketTest.java b/services/tests/servicestests/src/android/net/netlink/NetlinkSocketTest.java
    +deleted file mode 100644
    +index c599fe3..0000000
    +--- a/services/tests/servicestests/src/android/net/netlink/NetlinkSocketTest.java
    ++++ /dev/null
    +@@ -1,116 +0,0 @@
    +-/*
    +- * Copyright (C) 2015 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 android.net.netlink;
    +-
    +-import android.net.netlink.NetlinkSocket;
    +-import android.net.netlink.RtNetlinkNeighborMessage;
    +-import android.net.netlink.StructNdMsg;
    +-import android.net.netlink.StructNlMsgHdr;
    +-import android.system.ErrnoException;
    +-import android.system.NetlinkSocketAddress;
    +-import android.system.OsConstants;
    +-import android.util.Log;
    +-import java.io.InterruptedIOException;
    +-import java.nio.ByteBuffer;
    +-import java.nio.ByteOrder;
    +-import junit.framework.TestCase;
    +-
    +-
    +-public class NetlinkSocketTest extends TestCase {
    +-    private final String TAG = "NetlinkSocketTest";
    +-
    +-    public void testBasicWorkingGetNeighborsQuery() throws Exception {
    +-        NetlinkSocket s = new NetlinkSocket(OsConstants.NETLINK_ROUTE);
    +-        assertNotNull(s);
    +-
    +-        s.connectToKernel();
    +-
    +-        NetlinkSocketAddress localAddr = s.getLocalAddress();
    +-        assertNotNull(localAddr);
    +-        assertEquals(0, localAddr.getGroupsMask());
    +-        assertTrue(0 != localAddr.getPortId());
    +-
    +-        final int TEST_SEQNO = 5;
    +-        final byte[] request = RtNetlinkNeighborMessage.newGetNeighborsRequest(TEST_SEQNO);
    +-        assertNotNull(request);
    +-
    +-        final long TIMEOUT = 500;
    +-        assertTrue(s.sendMessage(request, 0, request.length, TIMEOUT));
    +-
    +-        int neighMessageCount = 0;
    +-        int doneMessageCount = 0;
    +-
    +-        while (doneMessageCount == 0) {
    +-            ByteBuffer response = null;
    +-            response = s.recvMessage(TIMEOUT);
    +-            assertNotNull(response);
    +-            assertTrue(StructNlMsgHdr.STRUCT_SIZE <= response.limit());
    +-            assertEquals(0, response.position());
    +-            assertEquals(ByteOrder.nativeOrder(), response.order());
    +-
    +-            // Verify the messages at least appears minimally reasonable.
    +-            while (response.remaining() > 0) {
    +-                final NetlinkMessage msg = NetlinkMessage.parse(response);
    +-                assertNotNull(msg);
    +-                final StructNlMsgHdr hdr = msg.getHeader();
    +-                assertNotNull(hdr);
    +-
    +-                if (hdr.nlmsg_type == NetlinkConstants.NLMSG_DONE) {
    +-                    doneMessageCount++;
    +-                    continue;
    +-                }
    +-
    +-                assertEquals(NetlinkConstants.RTM_NEWNEIGH, hdr.nlmsg_type);
    +-                assertTrue(msg instanceof RtNetlinkNeighborMessage);
    +-                assertTrue((hdr.nlmsg_flags & StructNlMsgHdr.NLM_F_MULTI) != 0);
    +-                assertEquals(TEST_SEQNO, hdr.nlmsg_seq);
    +-                assertEquals(localAddr.getPortId(), hdr.nlmsg_pid);
    +-
    +-                neighMessageCount++;
    +-            }
    +-        }
    +-
    +-        assertEquals(1, doneMessageCount);
    +-        // TODO: make sure this test passes sanely in airplane mode.
    +-        assertTrue(neighMessageCount > 0);
    +-
    +-        s.close();
    +-    }
    +-
    +-    public void testRepeatedCloseCallsAreQuiet() throws Exception {
    +-        // Create a working NetlinkSocket.
    +-        NetlinkSocket s = new NetlinkSocket(OsConstants.NETLINK_ROUTE);
    +-        assertNotNull(s);
    +-        s.connectToKernel();
    +-        NetlinkSocketAddress localAddr = s.getLocalAddress();
    +-        assertNotNull(localAddr);
    +-        assertEquals(0, localAddr.getGroupsMask());
    +-        assertTrue(0 != localAddr.getPortId());
    +-        // Close once.
    +-        s.close();
    +-        // Test that it is closed.
    +-        boolean expectedErrorSeen = false;
    +-        try {
    +-            localAddr = s.getLocalAddress();
    +-        } catch (ErrnoException e) {
    +-            expectedErrorSeen = true;
    +-        }
    +-        assertTrue(expectedErrorSeen);
    +-        // Close once more.
    +-        s.close();
    +-    }
    +-}
    +diff --git a/services/tests/servicestests/src/android/net/netlink/RtNetlinkNeighborMessageTest.java b/services/tests/servicestests/src/android/net/netlink/RtNetlinkNeighborMessageTest.java
    +deleted file mode 100644
    +index 19ee000..0000000
    +--- a/services/tests/servicestests/src/android/net/netlink/RtNetlinkNeighborMessageTest.java
    ++++ /dev/null
    +@@ -1,257 +0,0 @@
    +-/*
    +- * Copyright (C) 2015 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 android.net.netlink;
    +-
    +-import android.net.netlink.NetlinkConstants;
    +-import android.net.netlink.NetlinkMessage;
    +-import android.net.netlink.RtNetlinkNeighborMessage;
    +-import android.net.netlink.StructNdMsg;
    +-import android.net.netlink.StructNlMsgHdr;
    +-import android.system.OsConstants;
    +-import android.util.Log;
    +-import libcore.util.HexEncoding;
    +-
    +-import java.net.InetAddress;
    +-import java.net.Inet4Address;
    +-import java.net.UnknownHostException;
    +-import java.nio.ByteBuffer;
    +-import java.nio.ByteOrder;
    +-import java.util.Arrays;
    +-import junit.framework.TestCase;
    +-
    +-
    +-public class RtNetlinkNeighborMessageTest extends TestCase {
    +-    private final String TAG = "RtNetlinkNeighborMessageTest";
    +-
    +-    // Hexadecimal representation of packet capture.
    +-    public static final String RTM_DELNEIGH_HEX =
    +-            // struct nlmsghdr
    +-            "4c000000" +     // length = 76
    +-            "1d00" +         // type = 29 (RTM_DELNEIGH)
    +-            "0000" +         // flags
    +-            "00000000" +     // seqno
    +-            "00000000" +     // pid (0 == kernel)
    +-            // struct ndmsg
    +-            "02" +           // family
    +-            "00" +           // pad1
    +-            "0000" +         // pad2
    +-            "15000000" +     // interface index (21  == wlan0, on test device)
    +-            "0400" +         // NUD state (0x04 == NUD_STALE)
    +-            "00" +           // flags
    +-            "01" +           // type
    +-            // struct nlattr: NDA_DST
    +-            "0800" +         // length = 8
    +-            "0100" +         // type (1 == NDA_DST, for neighbor messages)
    +-            "c0a89ffe" +     // IPv4 address (== 192.168.159.254)
    +-            // struct nlattr: NDA_LLADDR
    +-            "0a00" +         // length = 10
    +-            "0200" +         // type (2 == NDA_LLADDR, for neighbor messages)
    +-            "00005e000164" + // MAC Address (== 00:00:5e:00:01:64)
    +-            "0000" +         // padding, for 4 byte alignment
    +-            // struct nlattr: NDA_PROBES
    +-            "0800" +         // length = 8
    +-            "0400" +         // type (4 == NDA_PROBES, for neighbor messages)
    +-            "01000000" +     // number of probes
    +-            // struct nlattr: NDA_CACHEINFO
    +-            "1400" +         // length = 20
    +-            "0300" +         // type (3 == NDA_CACHEINFO, for neighbor messages)
    +-            "05190000" +     // ndm_used, as "clock ticks ago"
    +-            "05190000" +     // ndm_confirmed, as "clock ticks ago"
    +-            "190d0000" +     // ndm_updated, as "clock ticks ago"
    +-            "00000000";      // ndm_refcnt
    +-    public static final byte[] RTM_DELNEIGH =
    +-            HexEncoding.decode(RTM_DELNEIGH_HEX.toCharArray(), false);
    +-
    +-    // Hexadecimal representation of packet capture.
    +-    public static final String RTM_NEWNEIGH_HEX =
    +-            // struct nlmsghdr
    +-            "58000000" +     // length = 88
    +-            "1c00" +         // type = 28 (RTM_NEWNEIGH)
    +-            "0000" +         // flags
    +-            "00000000" +     // seqno
    +-            "00000000" +     // pid (0 == kernel)
    +-            // struct ndmsg
    +-            "0a" +           // family
    +-            "00" +           // pad1
    +-            "0000" +         // pad2
    +-            "15000000" +     // interface index (21  == wlan0, on test device)
    +-            "0400" +         // NUD state (0x04 == NUD_STALE)
    +-            "80" +           // flags
    +-            "01" +           // type
    +-            // struct nlattr: NDA_DST
    +-            "1400" +         // length = 20
    +-            "0100" +         // type (1 == NDA_DST, for neighbor messages)
    +-            "fe8000000000000086c9b2fffe6aed4b" + // IPv6 address (== fe80::86c9:b2ff:fe6a:ed4b)
    +-            // struct nlattr: NDA_LLADDR
    +-            "0a00" +         // length = 10
    +-            "0200" +         // type (2 == NDA_LLADDR, for neighbor messages)
    +-            "84c9b26aed4b" + // MAC Address (== 84:c9:b2:6a:ed:4b)
    +-            "0000" +         // padding, for 4 byte alignment
    +-            // struct nlattr: NDA_PROBES
    +-            "0800" +         // length = 8
    +-            "0400" +         // type (4 == NDA_PROBES, for neighbor messages)
    +-            "01000000" +     // number of probes
    +-            // struct nlattr: NDA_CACHEINFO
    +-            "1400" +         // length = 20
    +-            "0300" +         // type (3 == NDA_CACHEINFO, for neighbor messages)
    +-            "eb0e0000" +     // ndm_used, as "clock ticks ago"
    +-            "861f0000" +     // ndm_confirmed, as "clock ticks ago"
    +-            "00000000" +     // ndm_updated, as "clock ticks ago"
    +-            "05000000";      // ndm_refcnt
    +-    public static final byte[] RTM_NEWNEIGH =
    +-            HexEncoding.decode(RTM_NEWNEIGH_HEX.toCharArray(), false);
    +-
    +-    // An example of the full response from an RTM_GETNEIGH query.
    +-    private static final String RTM_GETNEIGH_RESPONSE_HEX =
    +-            // <-- struct nlmsghr             -->|<-- struct ndmsg           -->|<-- struct nlattr: NDA_DST             -->|<-- NDA_LLADDR          -->|<-- NDA_PROBES -->|<-- NDA_CACHEINFO                         -->|
    +-            "58000000 1c00 0200 00000000 3e2b0000 0a 00 0000 15000000 4000 00 05 1400 0100 ff020000000000000000000000000001 0a00 0200 333300000001 0000 0800 0400 00000000 1400 0300 a2280000 32110000 32110000 01000000" +
    +-            "58000000 1c00 0200 00000000 3e2b0000 0a 00 0000 15000000 4000 00 05 1400 0100 ff0200000000000000000001ff000001 0a00 0200 3333ff000001 0000 0800 0400 00000000 1400 0300 0d280000 9d100000 9d100000 00000000" +
    +-            "58000000 1c00 0200 00000000 3e2b0000 0a 00 0000 15000000 0400 80 01 1400 0100 20010db800040ca00000000000000001 0a00 0200 84c9b26aed4b 0000 0800 0400 04000000 1400 0300 90100000 90100000 90080000 01000000" +
    +-            "58000000 1c00 0200 00000000 3e2b0000 0a 00 0000 15000000 4000 00 05 1400 0100 ff0200000000000000000001ff47da19 0a00 0200 3333ff47da19 0000 0800 0400 00000000 1400 0300 a1280000 31110000 31110000 01000000" +
    +-            "58000000 1c00 0200 00000000 3e2b0000 0a 00 0000 14000000 4000 00 05 1400 0100 ff020000000000000000000000000016 0a00 0200 333300000016 0000 0800 0400 00000000 1400 0300 912a0000 21130000 21130000 00000000" +
    +-            "58000000 1c00 0200 00000000 3e2b0000 0a 00 0000 14000000 4000 00 05 1400 0100 ff0200000000000000000001ffeace3b 0a00 0200 3333ffeace3b 0000 0800 0400 00000000 1400 0300 922a0000 22130000 22130000 00000000" +
    +-            "58000000 1c00 0200 00000000 3e2b0000 0a 00 0000 15000000 4000 00 05 1400 0100 ff0200000000000000000001ff5c2a83 0a00 0200 3333ff5c2a83 0000 0800 0400 00000000 1400 0300 391c0000 c9040000 c9040000 01000000" +
    +-            "58000000 1c00 0200 00000000 3e2b0000 0a 00 0000 01000000 4000 00 02 1400 0100 00000000000000000000000000000000 0a00 0200 000000000000 0000 0800 0400 00000000 1400 0300 cd180200 5d010200 5d010200 08000000" +
    +-            "58000000 1c00 0200 00000000 3e2b0000 0a 00 0000 15000000 4000 00 05 1400 0100 ff020000000000000000000000000002 0a00 0200 333300000002 0000 0800 0400 00000000 1400 0300 352a0000 c5120000 c5120000 00000000" +
    +-            "58000000 1c00 0200 00000000 3e2b0000 0a 00 0000 15000000 4000 00 05 1400 0100 ff020000000000000000000000000016 0a00 0200 333300000016 0000 0800 0400 00000000 1400 0300 982a0000 28130000 28130000 00000000" +
    +-            "58000000 1c00 0200 00000000 3e2b0000 0a 00 0000 15000000 0800 80 01 1400 0100 fe8000000000000086c9b2fffe6aed4b 0a00 0200 84c9b26aed4b 0000 0800 0400 00000000 1400 0300 23000000 24000000 57000000 13000000" +
    +-            "58000000 1c00 0200 00000000 3e2b0000 0a 00 0000 15000000 4000 00 05 1400 0100 ff0200000000000000000001ffeace3b 0a00 0200 3333ffeace3b 0000 0800 0400 00000000 1400 0300 992a0000 29130000 29130000 01000000" +
    +-            "58000000 1c00 0200 00000000 3e2b0000 0a 00 0000 14000000 4000 00 05 1400 0100 ff020000000000000000000000000002 0a00 0200 333300000002 0000 0800 0400 00000000 1400 0300 2e2a0000 be120000 be120000 00000000" +
    +-            "44000000 1c00 0200 00000000 3e2b0000 02 00 0000 18000000 4000 00 03 0800 0100 00000000                         0400 0200                   0800 0400 00000000 1400 0300 75280000 05110000 05110000 22000000";
    +-    public static final byte[] RTM_GETNEIGH_RESPONSE =
    +-            HexEncoding.decode(RTM_GETNEIGH_RESPONSE_HEX.replaceAll(" ", "").toCharArray(), false);
    +-
    +-    public void testParseRtmDelNeigh() {
    +-        final ByteBuffer byteBuffer = ByteBuffer.wrap(RTM_DELNEIGH);
    +-        byteBuffer.order(ByteOrder.LITTLE_ENDIAN);  // For testing.
    +-        final NetlinkMessage msg = NetlinkMessage.parse(byteBuffer);
    +-        assertNotNull(msg);
    +-        assertTrue(msg instanceof RtNetlinkNeighborMessage);
    +-        final RtNetlinkNeighborMessage neighMsg = (RtNetlinkNeighborMessage) msg;
    +-
    +-        final StructNlMsgHdr hdr = neighMsg.getHeader();
    +-        assertNotNull(hdr);
    +-        assertEquals(76, hdr.nlmsg_len);
    +-        assertEquals(NetlinkConstants.RTM_DELNEIGH, hdr.nlmsg_type);
    +-        assertEquals(0, hdr.nlmsg_flags);
    +-        assertEquals(0, hdr.nlmsg_seq);
    +-        assertEquals(0, hdr.nlmsg_pid);
    +-
    +-        final StructNdMsg ndmsgHdr = neighMsg.getNdHeader();
    +-        assertNotNull(ndmsgHdr);
    +-        assertEquals((byte) OsConstants.AF_INET, ndmsgHdr.ndm_family);
    +-        assertEquals(21, ndmsgHdr.ndm_ifindex);
    +-        assertEquals(StructNdMsg.NUD_STALE, ndmsgHdr.ndm_state);
    +-        final InetAddress destination = neighMsg.getDestination();
    +-        assertNotNull(destination);
    +-        assertEquals(InetAddress.parseNumericAddress("192.168.159.254"), destination);
    +-    }
    +-
    +-    public void testParseRtmNewNeigh() {
    +-        final ByteBuffer byteBuffer = ByteBuffer.wrap(RTM_NEWNEIGH);
    +-        byteBuffer.order(ByteOrder.LITTLE_ENDIAN);  // For testing.
    +-        final NetlinkMessage msg = NetlinkMessage.parse(byteBuffer);
    +-        assertNotNull(msg);
    +-        assertTrue(msg instanceof RtNetlinkNeighborMessage);
    +-        final RtNetlinkNeighborMessage neighMsg = (RtNetlinkNeighborMessage) msg;
    +-
    +-        final StructNlMsgHdr hdr = neighMsg.getHeader();
    +-        assertNotNull(hdr);
    +-        assertEquals(88, hdr.nlmsg_len);
    +-        assertEquals(NetlinkConstants.RTM_NEWNEIGH, hdr.nlmsg_type);
    +-        assertEquals(0, hdr.nlmsg_flags);
    +-        assertEquals(0, hdr.nlmsg_seq);
    +-        assertEquals(0, hdr.nlmsg_pid);
    +-
    +-        final StructNdMsg ndmsgHdr = neighMsg.getNdHeader();
    +-        assertNotNull(ndmsgHdr);
    +-        assertEquals((byte) OsConstants.AF_INET6, ndmsgHdr.ndm_family);
    +-        assertEquals(21, ndmsgHdr.ndm_ifindex);
    +-        assertEquals(StructNdMsg.NUD_STALE, ndmsgHdr.ndm_state);
    +-        final InetAddress destination = neighMsg.getDestination();
    +-        assertNotNull(destination);
    +-        assertEquals(InetAddress.parseNumericAddress("fe80::86c9:b2ff:fe6a:ed4b"), destination);
    +-    }
    +-
    +-    public void testParseRtmGetNeighResponse() {
    +-        final ByteBuffer byteBuffer = ByteBuffer.wrap(RTM_GETNEIGH_RESPONSE);
    +-        byteBuffer.order(ByteOrder.LITTLE_ENDIAN);  // For testing.
    +-
    +-        int messageCount = 0;
    +-        while (byteBuffer.remaining() > 0) {
    +-            final NetlinkMessage msg = NetlinkMessage.parse(byteBuffer);
    +-            assertNotNull(msg);
    +-            assertTrue(msg instanceof RtNetlinkNeighborMessage);
    +-            final RtNetlinkNeighborMessage neighMsg = (RtNetlinkNeighborMessage) msg;
    +-
    +-            final StructNlMsgHdr hdr = neighMsg.getHeader();
    +-            assertNotNull(hdr);
    +-            assertEquals(NetlinkConstants.RTM_NEWNEIGH, hdr.nlmsg_type);
    +-            assertEquals(StructNlMsgHdr.NLM_F_MULTI, hdr.nlmsg_flags);
    +-            assertEquals(0, hdr.nlmsg_seq);
    +-            assertEquals(11070, hdr.nlmsg_pid);
    +-
    +-            messageCount++;
    +-        }
    +-        // TODO: add more detailed spot checks.
    +-        assertEquals(14, messageCount);
    +-    }
    +-
    +-    public void testCreateRtmNewNeighMessage() {
    +-        final int seqNo = 2635;
    +-        final int ifIndex = 14;
    +-        final byte[] llAddr =
    +-                new byte[] { (byte) 1, (byte) 2, (byte) 3, (byte) 4, (byte) 5, (byte) 6 };
    +-
    +-        // Hexadecimal representation of our created packet.
    +-        final String expectedNewNeighHex =
    +-                // struct nlmsghdr
    +-                "30000000" +     // length = 48
    +-                "1c00" +         // type = 28 (RTM_NEWNEIGH)
    +-                "0501" +         // flags (NLM_F_REQUEST | NLM_F_ACK | NLM_F_REPLACE)
    +-                "4b0a0000" +     // seqno
    +-                "00000000" +     // pid (0 == kernel)
    +-                // struct ndmsg
    +-                "02" +           // family
    +-                "00" +           // pad1
    +-                "0000" +         // pad2
    +-                "0e000000" +     // interface index (14)
    +-                "0800" +         // NUD state (0x08 == NUD_DELAY)
    +-                "00" +           // flags
    +-                "00" +           // type
    +-                // struct nlattr: NDA_DST
    +-                "0800" +         // length = 8
    +-                "0100" +         // type (1 == NDA_DST, for neighbor messages)
    +-                "7f000001" +     // IPv4 address (== 127.0.0.1)
    +-                // struct nlattr: NDA_LLADDR
    +-                "0a00" +         // length = 10
    +-                "0200" +         // type (2 == NDA_LLADDR, for neighbor messages)
    +-                "010203040506" + // MAC Address (== 01:02:03:04:05:06)
    +-                "0000";          // padding, for 4 byte alignment
    +-        final byte[] expectedNewNeigh =
    +-                HexEncoding.decode(expectedNewNeighHex.toCharArray(), false);
    +-
    +-        final byte[] bytes = RtNetlinkNeighborMessage.newNewNeighborMessage(
    +-            seqNo, Inet4Address.LOOPBACK, StructNdMsg.NUD_DELAY, ifIndex, llAddr);
    +-        if (!Arrays.equals(expectedNewNeigh, bytes)) {
    +-            assertEquals(expectedNewNeigh.length, bytes.length);
    +-            for (int i = 0; i < Math.min(expectedNewNeigh.length, bytes.length); i++) {
    +-                assertEquals(expectedNewNeigh[i], bytes[i]);
    +-            }
    +-        }
    +-    }
    +-}
    +diff --git a/services/tests/servicestests/src/com/android/internal/util/FakeSettingsProvider.java b/services/tests/servicestests/src/com/android/internal/util/FakeSettingsProvider.java
    +deleted file mode 100644
    +index 808f4dd..0000000
    +--- a/services/tests/servicestests/src/com/android/internal/util/FakeSettingsProvider.java
    ++++ /dev/null
    +@@ -1,130 +0,0 @@
    +-/*
    +- * Copyright (C) 2016 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 com.android.internal.util;
    +-
    +-import android.net.Uri;
    +-import android.os.Bundle;
    +-import android.provider.Settings;
    +-import android.test.mock.MockContentProvider;
    +-import android.util.Log;
    +-
    +-import java.util.HashMap;
    +-
    +-/**
    +- * Fake for system settings.
    +- *
    +- * To use, ensure that the Context used by the test code returns a ContentResolver that uses this
    +- * provider for the Settings authority:
    +- *
    +- *   class MyTestContext extends MockContext {
    +- *       ...
    +- *       private final MockContentResolver mContentResolver;
    +- *       public MyTestContext(...) {
    +- *           ...
    +- *           mContentResolver = new MockContentResolver();
    +- *           mContentResolver.addProvider(Settings.AUTHORITY, new FakeSettingsProvider());
    +- *       }
    +- *       ...
    +- *       @Override
    +- *       public ContentResolver getContentResolver() {
    +- *           return mContentResolver;
    +- *       }
    +- *
    +- * As long as the code under test is using the test Context, the actual code under test does not
    +- * need to be modified, and can access Settings using the normal static methods:
    +- *
    +- *   Settings.Global.getInt(cr, "my_setting", 0);  // Returns 0.
    +- *   Settings.Global.putInt(cr, "my_setting", 5);
    +- *   Settings.Global.getInt(cr, "my_setting", 0);  // Returns 5.
    +- *
    +- * Note that this class cannot be used in the same process as real settings. This is because it
    +- * works by passing an alternate ContentResolver to Settings operations. Unfortunately, the Settings
    +- * class only fetches the content provider from the passed-in ContentResolver the first time it's
    +- * used, and after that stores it in a per-process static.
    +- *
    +- * TODO: evaluate implementing settings change notifications. This would require:
    +- *
    +- * 1. Making ContentResolver#registerContentObserver non-final and overriding it in
    +- *    MockContentResolver.
    +- * 2. Making FakeSettingsProvider take a ContentResolver argument.
    +- * 3. Calling ContentResolver#notifyChange(getUriFor(table, arg), ...) on every settings change.
    +- */
    +-public class FakeSettingsProvider extends MockContentProvider {
    +-
    +-    private static final String TAG = FakeSettingsProvider.class.getSimpleName();
    +-    private static final boolean DBG = false;
    +-    private static final String[] TABLES = { "system", "secure", "global" };
    +-
    +-    private final HashMap<String, HashMap<String, String>> mTables = new HashMap<>();
    +-
    +-    public FakeSettingsProvider() {
    +-        for (int i = 0; i < TABLES.length; i++) {
    +-            mTables.put(TABLES[i], new HashMap<String, String>());
    +-        }
    +-    }
    +-
    +-    private Uri getUriFor(String table, String key) {
    +-        switch (table) {
    +-            case "system":
    +-                return Settings.System.getUriFor(key);
    +-            case "secure":
    +-                return Settings.Secure.getUriFor(key);
    +-            case "global":
    +-                return Settings.Global.getUriFor(key);
    +-            default:
    +-                throw new UnsupportedOperationException("Unknown settings table " + table);
    +-        }
    +-    }
    +-
    +-    public Bundle call(String method, String arg, Bundle extras) {
    +-        // Methods are "GET_system", "GET_global", "PUT_secure", etc.
    +-        String[] commands = method.split("_", 2);
    +-        String op = commands[0];
    +-        String table = commands[1];
    +-
    +-        Bundle out = new Bundle();
    +-        String value;
    +-        switch (op) {
    +-            case "GET":
    +-                value = mTables.get(table).get(arg);
    +-                if (value != null) {
    +-                    if (DBG) {
    +-                        Log.d(TAG, String.format("Returning fake setting %s.%s = %s",
    +-                                table, arg, value));
    +-                    }
    +-                    out.putString(Settings.NameValueTable.VALUE, value);
    +-                }
    +-                break;
    +-            case "PUT":
    +-                value = extras.getString(Settings.NameValueTable.VALUE, null);
    +-                if (DBG) {
    +-                    Log.d(TAG, String.format("Inserting fake setting %s.%s = %s",
    +-                            table, arg, value));
    +-                }
    +-                if (value != null) {
    +-                    mTables.get(table).put(arg, value);
    +-                } else {
    +-                    mTables.get(table).remove(arg);
    +-                }
    +-                break;
    +-            default:
    +-                throw new UnsupportedOperationException("Unknown command " + method);
    +-        }
    +-
    +-        return out;
    +-    }
    +-}
    +diff --git a/services/tests/servicestests/src/com/android/internal/util/FakeSettingsProviderTest.java b/services/tests/servicestests/src/com/android/internal/util/FakeSettingsProviderTest.java
    +deleted file mode 100644
    +index 05de0a5..0000000
    +--- a/services/tests/servicestests/src/com/android/internal/util/FakeSettingsProviderTest.java
    ++++ /dev/null
    +@@ -1,59 +0,0 @@
    +-/*
    +- * Copyright (C) 2016 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 com.android.internal.util;
    +-
    +-import android.content.ContentResolver;
    +-import android.database.ContentObserver;
    +-import android.net.Uri;
    +-import android.provider.Settings;
    +-import android.test.AndroidTestCase;
    +-import android.test.mock.MockContentResolver;
    +-import android.test.mock.MockContext;
    +-import android.test.suitebuilder.annotation.SmallTest;
    +-import android.test.suitebuilder.annotation.Suppress;
    +-import android.util.Log;
    +-
    +-import java.util.concurrent.CountDownLatch;
    +-import java.util.concurrent.TimeUnit;
    +-
    +-/**
    +- * Unit tests for FakeSettingsProvider.
    +- */
    +-public class FakeSettingsProviderTest extends AndroidTestCase {
    +-
    +-    private MockContentResolver mCr;
    +-
    +-    @Override
    +-    public void setUp() throws Exception {
    +-        mCr = new MockContentResolver();
    +-        mCr.addProvider(Settings.AUTHORITY, new FakeSettingsProvider());
    +-    }
    +-
    +-    @SmallTest
    +-    public void testBasicOperation() throws Exception {
    +-        String settingName = Settings.System.SCREEN_BRIGHTNESS;
    +-
    +-        try {
    +-            Settings.System.getInt(mCr, settingName);
    +-            fail("FakeSettingsProvider should start off empty.");
    +-        } catch (Settings.SettingNotFoundException expected) {}
    +-
    +-        // Check that fake settings can be written and read back.
    +-        Settings.System.putInt(mCr, settingName, 123);
    +-        assertEquals(123, Settings.System.getInt(mCr, settingName));
    +-    }
    +-}
    +diff --git a/services/tests/servicestests/src/com/android/server/AccessibilityManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/AccessibilityManagerServiceTest.java
    +deleted file mode 100644
    +index 51e14d3..0000000
    +--- a/services/tests/servicestests/src/com/android/server/AccessibilityManagerServiceTest.java
    ++++ /dev/null
    +@@ -1,757 +0,0 @@
    +-/*
    +- * Copyright (C) 2010 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 com.android.server;
    +-
    +-import android.accessibilityservice.AccessibilityService;
    +-import android.accessibilityservice.AccessibilityServiceInfo;
    +-import android.content.ComponentName;
    +-import android.content.Context;
    +-import android.content.pm.ServiceInfo;
    +-import android.os.IBinder;
    +-import android.os.Message;
    +-import android.os.ServiceManager;
    +-import android.os.SystemClock;
    +-import android.os.UserHandle;
    +-import android.provider.Settings;
    +-import android.test.AndroidTestCase;
    +-import android.test.suitebuilder.annotation.LargeTest;
    +-import android.view.accessibility.AccessibilityEvent;
    +-import android.view.accessibility.AccessibilityManager;
    +-import android.view.accessibility.IAccessibilityManager;
    +-import android.view.accessibility.IAccessibilityManagerClient;
    +-
    +-/**
    +- * This test exercises the
    +- * {@link com.android.server.accessibility.AccessibilityManagerService} by mocking the
    +- * {@link android.view.accessibility.AccessibilityManager} which talks to to the
    +- * service. The service itself is interacting with the platform. Note: Testing
    +- * the service in full isolation would require significant amount of work for
    +- * mocking all system interactions. It would also require a lot of mocking code.
    +- */
    +-public class AccessibilityManagerServiceTest extends AndroidTestCase {
    +-
    +-    /**
    +-     * Timeout required for pending Binder calls or event processing to
    +-     * complete.
    +-     */
    +-    private static final long TIMEOUT_BINDER_CALL = 100;
    +-
    +-    /**
    +-     * Timeout in which we are waiting for the system to start the mock
    +-     * accessibility services.
    +-     */
    +-    private static final long TIMEOUT_START_MOCK_ACCESSIBILITY_SERVICES = 1000;
    +-
    +-    /**
    +-     * Timeout used for testing that a service is notified only upon a
    +-     * notification timeout.
    +-     */
    +-    private static final long TIMEOUT_TEST_NOTIFICATION_TIMEOUT = 300;
    +-
    +-    /**
    +-     * The interface used to talk to the tested service.
    +-     */
    +-    private IAccessibilityManager mManagerService;
    +-
    +-    @Override
    +-    protected void setUp() throws Exception {
    +-        // Reset the state.
    +-        ensureOnlyMockServicesEnabled(getContext(), false, false);
    +-    }
    +-
    +-    @Override
    +-    public void setContext(Context context) {
    +-        super.setContext(context);
    +-        if (MyFirstMockAccessibilityService.sComponentName == null) {
    +-            MyFirstMockAccessibilityService.sComponentName = new ComponentName(
    +-                    context.getPackageName(), MyFirstMockAccessibilityService.class.getName())
    +-                    .flattenToShortString();
    +-        }
    +-        if (MySecondMockAccessibilityService.sComponentName == null) {
    +-            MySecondMockAccessibilityService.sComponentName = new ComponentName(
    +-                    context.getPackageName(), MySecondMockAccessibilityService.class.getName())
    +-                    .flattenToShortString();
    +-        }
    +-    }
    +-
    +-    /**
    +-     * Creates a new instance.
    +-     */
    +-    public AccessibilityManagerServiceTest() {
    +-        IBinder iBinder = ServiceManager.getService(Context.ACCESSIBILITY_SERVICE);
    +-        mManagerService = IAccessibilityManager.Stub.asInterface(iBinder);
    +-    }
    +-
    +-    @LargeTest
    +-    public void testAddClient_AccessibilityDisabledThenEnabled() throws Exception {
    +-        // at least some service must be enabled, otherwise accessibility will always be disabled.
    +-        ensureOnlyMockServicesEnabled(mContext, true, false);
    +-
    +-        // make sure accessibility is disabled
    +-        ensureAccessibilityEnabled(mContext, false);
    +-
    +-        // create a client mock instance
    +-        MyMockAccessibilityManagerClient mockClient = new MyMockAccessibilityManagerClient();
    +-
    +-        // invoke the method under test
    +-        final int stateFlagsDisabled =
    +-                mManagerService.addClient(mockClient, UserHandle.USER_CURRENT);
    +-        boolean enabledAccessibilityDisabled =
    +-            (stateFlagsDisabled & AccessibilityManager.STATE_FLAG_ACCESSIBILITY_ENABLED) != 0;
    +-
    +-        // check expected result
    +-        assertFalse("The client must be disabled since accessibility is disabled.",
    +-                enabledAccessibilityDisabled);
    +-
    +-        // enable accessibility
    +-        ensureAccessibilityEnabled(mContext, true);
    +-
    +-        // invoke the method under test
    +-        final int stateFlagsEnabled =
    +-                mManagerService.addClient(mockClient, UserHandle.USER_CURRENT);
    +-        boolean enabledAccessibilityEnabled =
    +-            (stateFlagsEnabled & AccessibilityManager.STATE_FLAG_ACCESSIBILITY_ENABLED) != 0;
    +-
    +-        // check expected result
    +-        assertTrue("The client must be enabled since accessibility is enabled.",
    +-                enabledAccessibilityEnabled);
    +-    }
    +-
    +-    @LargeTest
    +-    public void testAddClient_AccessibilityEnabledThenDisabled() throws Exception {
    +-        // at least some service must be enabled, otherwise accessibility will always be disabled.
    +-        ensureOnlyMockServicesEnabled(mContext, true, false);
    +-
    +-        // enable accessibility before registering the client
    +-        ensureAccessibilityEnabled(mContext, true);
    +-
    +-        // create a client mock instance
    +-        MyMockAccessibilityManagerClient mockClient = new MyMockAccessibilityManagerClient();
    +-
    +-        // invoke the method under test
    +-        final int stateFlagsEnabled =
    +-                mManagerService.addClient(mockClient, UserHandle.USER_CURRENT);
    +-        boolean enabledAccessibilityEnabled =
    +-            (stateFlagsEnabled & AccessibilityManager.STATE_FLAG_ACCESSIBILITY_ENABLED) != 0;
    +-
    +-        // check expected result
    +-        assertTrue("The client must be enabled since accessibility is enabled.",
    +-                enabledAccessibilityEnabled);
    +-
    +-        // disable accessibility
    +-        ensureAccessibilityEnabled(mContext, false);
    +-
    +-        // invoke the method under test
    +-        final int stateFlagsDisabled =
    +-                mManagerService.addClient(mockClient, UserHandle.USER_CURRENT);
    +-        boolean enabledAccessibilityDisabled =
    +-            (stateFlagsDisabled & AccessibilityManager.STATE_FLAG_ACCESSIBILITY_ENABLED) != 0;
    +-
    +-        // check expected result
    +-        assertFalse("The client must be disabled since accessibility is disabled.",
    +-                enabledAccessibilityDisabled);
    +-    }
    +-
    +-    @LargeTest
    +-    public void testGetAccessibilityServicesList() throws Exception {
    +-        boolean firstMockServiceInstalled = false;
    +-        boolean secondMockServiceInstalled = false;
    +-
    +-        String packageName = getContext().getPackageName();
    +-        String firstMockServiceClassName = MyFirstMockAccessibilityService.class.getName();
    +-        String secondMockServiceClassName = MySecondMockAccessibilityService.class.getName();
    +-
    +-        // look for the two mock services
    +-        for (AccessibilityServiceInfo info : mManagerService.getInstalledAccessibilityServiceList(
    +-                UserHandle.USER_CURRENT)) {
    +-            ServiceInfo serviceInfo = info.getResolveInfo().serviceInfo;
    +-            if (packageName.equals(serviceInfo.packageName)) {
    +-                if (firstMockServiceClassName.equals(serviceInfo.name)) {
    +-                    firstMockServiceInstalled = true;
    +-                } else if (secondMockServiceClassName.equals(serviceInfo.name)) {
    +-                    secondMockServiceInstalled = true;
    +-                }
    +-            }
    +-        }
    +-
    +-        // check expected result
    +-        assertTrue("First mock service must be installed", firstMockServiceInstalled);
    +-        assertTrue("Second mock service must be installed", secondMockServiceInstalled);
    +-    }
    +-
    +-    @LargeTest
    +-    public void testSendAccessibilityEvent_OneService_MatchingPackageAndEventType()
    +-            throws Exception {
    +-        // enable the mock accessibility service
    +-        ensureOnlyMockServicesEnabled(mContext, true, false);
    +-
    +-        // set the accessibility setting value
    +-        ensureAccessibilityEnabled(mContext, true);
    +-
    +-        // configure the mock service
    +-        MockAccessibilityService service = MyFirstMockAccessibilityService.sInstance;
    +-        service.setServiceInfo(MockAccessibilityService.createDefaultInfo());
    +-
    +-        // wait for the binder call to #setService to complete
    +-        Thread.sleep(TIMEOUT_BINDER_CALL);
    +-
    +-        // create and populate an event to be sent
    +-        AccessibilityEvent sentEvent = AccessibilityEvent.obtain();
    +-        fullyPopulateDefaultAccessibilityEvent(sentEvent);
    +-
    +-        // set expectations
    +-        service.expectEvent(sentEvent);
    +-        service.replay();
    +-
    +-        // send the event
    +-        mManagerService.sendAccessibilityEvent(sentEvent, UserHandle.USER_CURRENT);
    +-
    +-        // verify if all expected methods have been called
    +-        assertMockServiceVerifiedWithinTimeout(service);
    +-    }
    +-
    +-    @LargeTest
    +-    public void testSendAccessibilityEvent_OneService_NotMatchingPackage() throws Exception {
    +-        // enable the mock accessibility service
    +-        ensureOnlyMockServicesEnabled(mContext, true, false);
    +-
    +-        // set the accessibility setting value
    +-        ensureAccessibilityEnabled(mContext, true);
    +-
    +-        // configure the mock service
    +-        MockAccessibilityService service = MyFirstMockAccessibilityService.sInstance;
    +-        service.setServiceInfo(MockAccessibilityService.createDefaultInfo());
    +-
    +-        // wait for the binder call to #setService to complete
    +-        Thread.sleep(TIMEOUT_BINDER_CALL);
    +-
    +-        // create and populate an event to be sent
    +-        AccessibilityEvent sentEvent = AccessibilityEvent.obtain();
    +-        fullyPopulateDefaultAccessibilityEvent(sentEvent);
    +-        sentEvent.setPackageName("no.service.registered.for.this.package");
    +-
    +-        // set expectations
    +-        service.replay();
    +-
    +-        // send the event
    +-        mManagerService.sendAccessibilityEvent(sentEvent, UserHandle.USER_CURRENT);
    +-
    +-        // verify if all expected methods have been called
    +-        assertMockServiceVerifiedWithinTimeout(service);
    +-    }
    +-
    +-    @LargeTest
    +-    public void testSendAccessibilityEvent_OneService_NotMatchingEventType() throws Exception {
    +-        // enable the mock accessibility service
    +-        ensureOnlyMockServicesEnabled(mContext, true, false);
    +-
    +-        // set the accessibility setting value
    +-        ensureAccessibilityEnabled(mContext, true);
    +-
    +-        // configure the mock service
    +-        MockAccessibilityService service = MyFirstMockAccessibilityService.sInstance;
    +-        service.setServiceInfo(MockAccessibilityService.createDefaultInfo());
    +-
    +-        // wait for the binder call to #setService to complete
    +-        Thread.sleep(TIMEOUT_BINDER_CALL);
    +-
    +-        // create and populate an event to be sent
    +-        AccessibilityEvent sentEvent = AccessibilityEvent.obtain();
    +-        fullyPopulateDefaultAccessibilityEvent(sentEvent);
    +-        sentEvent.setEventType(AccessibilityEvent.TYPE_NOTIFICATION_STATE_CHANGED);
    +-
    +-        // set expectations
    +-        service.replay();
    +-
    +-        // send the event
    +-        mManagerService.sendAccessibilityEvent(sentEvent, UserHandle.USER_CURRENT);
    +-
    +-        // verify if all expected methods have been called
    +-        assertMockServiceVerifiedWithinTimeout(service);
    +-    }
    +-
    +-    @LargeTest
    +-    public void testSendAccessibilityEvent_OneService_NotifivationAfterTimeout() throws Exception {
    +-        // enable the mock accessibility service
    +-        ensureOnlyMockServicesEnabled(mContext, true, false);
    +-
    +-        // set the accessibility setting value
    +-        ensureAccessibilityEnabled(mContext, true);
    +-
    +-        // configure the mock service
    +-        MockAccessibilityService service = MyFirstMockAccessibilityService.sInstance;
    +-        AccessibilityServiceInfo info = MockAccessibilityService.createDefaultInfo();
    +-        info.notificationTimeout = TIMEOUT_TEST_NOTIFICATION_TIMEOUT;
    +-        service.setServiceInfo(info);
    +-
    +-        // wait for the binder call to #setService to complete
    +-        Thread.sleep(TIMEOUT_BINDER_CALL);
    +-
    +-        // create and populate the first event to be sent
    +-        AccessibilityEvent firstEvent = AccessibilityEvent.obtain();
    +-        fullyPopulateDefaultAccessibilityEvent(firstEvent);
    +-
    +-        // create and populate the second event to be sent
    +-        AccessibilityEvent secondEvent = AccessibilityEvent.obtain();
    +-        fullyPopulateDefaultAccessibilityEvent(secondEvent);
    +-
    +-        // set expectations
    +-        service.expectEvent(secondEvent);
    +-        service.replay();
    +-
    +-        // send the events
    +-        mManagerService.sendAccessibilityEvent(firstEvent, UserHandle.USER_CURRENT);
    +-        mManagerService.sendAccessibilityEvent(secondEvent, UserHandle.USER_CURRENT);
    +-
    +-        // wait for #sendAccessibilityEvent to reach the backing service
    +-        Thread.sleep(TIMEOUT_BINDER_CALL);
    +-
    +-        try {
    +-            service.verify();
    +-            fail("No events must be dispatched before the expiration of the notification timeout.");
    +-        } catch (IllegalStateException ise) {
    +-            /* expected */
    +-        }
    +-
    +-        // wait for the configured notification timeout to expire
    +-        Thread.sleep(TIMEOUT_TEST_NOTIFICATION_TIMEOUT);
    +-
    +-        // verify if all expected methods have been called
    +-        assertMockServiceVerifiedWithinTimeout(service);
    +-    }
    +-
    +-    @LargeTest
    +-    public void testSendAccessibilityEvent_TwoServices_MatchingPackageAndEventType_DiffFeedback()
    +-            throws Exception {
    +-        // enable the mock accessibility services
    +-        ensureOnlyMockServicesEnabled(mContext, true, true);
    +-
    +-        // set the accessibility setting value
    +-        ensureAccessibilityEnabled(mContext, true);
    +-
    +-        // configure the first mock service
    +-        MockAccessibilityService firstService = MyFirstMockAccessibilityService.sInstance;
    +-        AccessibilityServiceInfo firstInfo = MockAccessibilityService.createDefaultInfo();
    +-        firstInfo.feedbackType = AccessibilityServiceInfo.FEEDBACK_AUDIBLE;
    +-        firstService.setServiceInfo(firstInfo);
    +-
    +-        // configure the second mock service
    +-        MockAccessibilityService secondService = MySecondMockAccessibilityService.sInstance;
    +-        AccessibilityServiceInfo secondInfo = MockAccessibilityService.createDefaultInfo();
    +-        secondInfo.feedbackType = AccessibilityServiceInfo.FEEDBACK_HAPTIC;
    +-        secondService.setServiceInfo(secondInfo);
    +-
    +-        // wait for the binder calls to #setService to complete
    +-        Thread.sleep(TIMEOUT_BINDER_CALL);
    +-
    +-        // create and populate an event to be sent
    +-        AccessibilityEvent sentEvent = AccessibilityEvent.obtain();
    +-        fullyPopulateDefaultAccessibilityEvent(sentEvent);
    +-
    +-        // set expectations for the first mock service
    +-        firstService.expectEvent(sentEvent);
    +-        firstService.replay();
    +-
    +-        // set expectations for the second mock service
    +-        secondService.expectEvent(sentEvent);
    +-        secondService.replay();
    +-
    +-        // send the event
    +-        mManagerService.sendAccessibilityEvent(sentEvent, UserHandle.USER_CURRENT);
    +-
    +-        // verify if all expected methods have been called
    +-        assertMockServiceVerifiedWithinTimeout(firstService);
    +-        assertMockServiceVerifiedWithinTimeout(secondService);
    +-    }
    +-
    +-    @LargeTest
    +-    public void testSendAccessibilityEvent_TwoServices_MatchingPackageAndEventType()
    +-            throws Exception {
    +-        // enable the mock accessibility services
    +-        ensureOnlyMockServicesEnabled(mContext, true, true);
    +-
    +-        // set the accessibility setting value
    +-        ensureAccessibilityEnabled(mContext, true);
    +-
    +-        // configure the first mock service
    +-        MockAccessibilityService firstService = MyFirstMockAccessibilityService.sInstance;
    +-        firstService.setServiceInfo(MockAccessibilityService.createDefaultInfo());
    +-
    +-        // configure the second mock service
    +-        MockAccessibilityService secondService = MySecondMockAccessibilityService.sInstance;
    +-        secondService.setServiceInfo(MockAccessibilityService.createDefaultInfo());
    +-
    +-        // wait for the binder calls to #setService to complete
    +-        Thread.sleep(TIMEOUT_BINDER_CALL);
    +-
    +-        // create and populate an event to be sent
    +-        AccessibilityEvent sentEvent = AccessibilityEvent.obtain();
    +-        fullyPopulateDefaultAccessibilityEvent(sentEvent);
    +-
    +-        // set expectations for the first mock service
    +-        firstService.expectEvent(sentEvent);
    +-        firstService.replay();
    +-
    +-        // set expectations for the second mock service
    +-        secondService.replay();
    +-
    +-        // send the event
    +-        mManagerService.sendAccessibilityEvent(sentEvent, UserHandle.USER_CURRENT);
    +-
    +-        // verify if all expected methods have been called
    +-        assertMockServiceVerifiedWithinTimeout(firstService);
    +-        assertMockServiceVerifiedWithinTimeout(secondService);
    +-    }
    +-
    +-    @LargeTest
    +-    public void testSendAccessibilityEvent_TwoServices_MatchingPackageAndEventType_OneDefault()
    +-            throws Exception {
    +-        // enable the mock accessibility services
    +-        ensureOnlyMockServicesEnabled(mContext, true, true);
    +-
    +-        // set the accessibility setting value
    +-        ensureAccessibilityEnabled(mContext, true);
    +-
    +-        // configure the first mock service
    +-        MockAccessibilityService firstService = MyFirstMockAccessibilityService.sInstance;
    +-        AccessibilityServiceInfo firstInfo = MyFirstMockAccessibilityService.createDefaultInfo();
    +-        firstInfo.flags = AccessibilityServiceInfo.DEFAULT;
    +-        firstService.setServiceInfo(firstInfo);
    +-
    +-        // configure the second mock service
    +-        MockAccessibilityService secondService = MySecondMockAccessibilityService.sInstance;
    +-        secondService.setServiceInfo(MySecondMockAccessibilityService.createDefaultInfo());
    +-
    +-        // wait for the binder calls to #setService to complete
    +-        Thread.sleep(TIMEOUT_BINDER_CALL);
    +-
    +-        // create and populate an event to be sent
    +-        AccessibilityEvent sentEvent = AccessibilityEvent.obtain();
    +-        fullyPopulateDefaultAccessibilityEvent(sentEvent);
    +-
    +-        // set expectations for the first mock service
    +-        firstService.replay();
    +-
    +-        // set expectations for the second mock service
    +-        secondService.expectEvent(sentEvent);
    +-        secondService.replay();
    +-
    +-        // send the event
    +-        mManagerService.sendAccessibilityEvent(sentEvent, UserHandle.USER_CURRENT);
    +-
    +-        // verify if all expected methods have been called
    +-        assertMockServiceVerifiedWithinTimeout(firstService);
    +-        assertMockServiceVerifiedWithinTimeout(secondService);
    +-    }
    +-
    +-    @LargeTest
    +-    public void testSendAccessibilityEvent_TwoServices_MatchingPackageAndEventType_TwoDefault()
    +-            throws Exception {
    +-        // enable the mock accessibility services
    +-        ensureOnlyMockServicesEnabled(mContext, true, true);
    +-
    +-        // set the accessibility setting value
    +-        ensureAccessibilityEnabled(mContext, true);
    +-
    +-        // configure the first mock service
    +-        MockAccessibilityService firstService = MyFirstMockAccessibilityService.sInstance;
    +-        AccessibilityServiceInfo firstInfo = MyFirstMockAccessibilityService.createDefaultInfo();
    +-        firstInfo.flags = AccessibilityServiceInfo.DEFAULT;
    +-        firstService.setServiceInfo(firstInfo);
    +-
    +-        // configure the second mock service
    +-        MockAccessibilityService secondService = MySecondMockAccessibilityService.sInstance;
    +-        AccessibilityServiceInfo secondInfo = MyFirstMockAccessibilityService.createDefaultInfo();
    +-        secondInfo.flags = AccessibilityServiceInfo.DEFAULT;
    +-        secondService.setServiceInfo(firstInfo);
    +-
    +-        // wait for the binder calls to #setService to complete
    +-        Thread.sleep(TIMEOUT_BINDER_CALL);
    +-
    +-        // create and populate an event to be sent
    +-        AccessibilityEvent sentEvent = AccessibilityEvent.obtain();
    +-        fullyPopulateDefaultAccessibilityEvent(sentEvent);
    +-
    +-        // set expectations for the first mock service
    +-        firstService.expectEvent(sentEvent);
    +-        firstService.replay();
    +-
    +-        // set expectations for the second mock service
    +-        secondService.replay();
    +-
    +-        // send the event
    +-        mManagerService.sendAccessibilityEvent(sentEvent, UserHandle.USER_CURRENT);
    +-
    +-        // verify if all expected methods have been called
    +-        assertMockServiceVerifiedWithinTimeout(firstService);
    +-        assertMockServiceVerifiedWithinTimeout(secondService);
    +-    }
    +-
    +-    @LargeTest
    +-    public void testInterrupt() throws Exception {
    +-        // enable the mock accessibility services
    +-        ensureOnlyMockServicesEnabled(mContext, true, true);
    +-
    +-        // set the accessibility setting value
    +-        ensureAccessibilityEnabled(mContext, true);
    +-
    +-        // configure the first mock service
    +-        MockAccessibilityService firstService = MyFirstMockAccessibilityService.sInstance;
    +-        firstService.setServiceInfo(MockAccessibilityService.createDefaultInfo());
    +-
    +-        // configure the second mock service
    +-        MockAccessibilityService secondService = MySecondMockAccessibilityService.sInstance;
    +-        secondService.setServiceInfo(MockAccessibilityService.createDefaultInfo());
    +-
    +-        // wait for the binder calls to #setService to complete
    +-        Thread.sleep(TIMEOUT_BINDER_CALL);
    +-
    +-        // set expectations for the first mock service
    +-        firstService.expectInterrupt();
    +-        firstService.replay();
    +-
    +-        // set expectations for the second mock service
    +-        secondService.expectInterrupt();
    +-        secondService.replay();
    +-
    +-        // call the method under test
    +-        mManagerService.interrupt(UserHandle.USER_CURRENT);
    +-
    +-        // verify if all expected methods have been called
    +-        assertMockServiceVerifiedWithinTimeout(firstService);
    +-        assertMockServiceVerifiedWithinTimeout(secondService);
    +-    }
    +-
    +-    /**
    +-     * Fully populates the {@link AccessibilityEvent} to marshal.
    +-     *
    +-     * @param sentEvent The event to populate.
    +-     */
    +-    private void fullyPopulateDefaultAccessibilityEvent(AccessibilityEvent sentEvent) {
    +-        sentEvent.setAddedCount(1);
    +-        sentEvent.setBeforeText("BeforeText");
    +-        sentEvent.setChecked(true);
    +-        sentEvent.setClassName("foo.bar.baz.Class");
    +-        sentEvent.setContentDescription("ContentDescription");
    +-        sentEvent.setCurrentItemIndex(1);
    +-        sentEvent.setEnabled(true);
    +-        sentEvent.setEventType(AccessibilityEvent.TYPE_ANNOUNCEMENT);
    +-        sentEvent.setEventTime(1000);
    +-        sentEvent.setFromIndex(1);
    +-        sentEvent.setFullScreen(true);
    +-        sentEvent.setItemCount(1);
    +-        sentEvent.setPackageName("foo.bar.baz");
    +-        sentEvent.setParcelableData(Message.obtain(null, 1, null));
    +-        sentEvent.setPassword(true);
    +-        sentEvent.setRemovedCount(1);
    +-    }
    +-
    +-    /**
    +-     * This class is a mock {@link IAccessibilityManagerClient}.
    +-     */
    +-    public class MyMockAccessibilityManagerClient extends IAccessibilityManagerClient.Stub {
    +-        int mState;
    +-
    +-        public void setState(int state) {
    +-            mState = state;
    +-        }
    +-
    +-        public void setTouchExplorationEnabled(boolean enabled) {
    +-        }
    +-    }
    +-
    +-    /**
    +-     * Ensures accessibility is in a given state by writing the state to the
    +-     * settings and waiting until the accessibility manager service pick it up.
    +-     *
    +-     * @param context A context handle to access the settings.
    +-     * @param enabled The accessibility state to write to the settings.
    +-     * @throws Exception If any error occurs.
    +-     */
    +-    private void ensureAccessibilityEnabled(Context context, boolean enabled) throws Exception {
    +-        boolean isEnabled = Settings.Secure.getInt(context.getContentResolver(),
    +-                Settings.Secure.ACCESSIBILITY_ENABLED, 0) == 1;
    +-
    +-        if (isEnabled == enabled) {
    +-            return;
    +-        }
    +-
    +-        Settings.Secure.putInt(context.getContentResolver(), Settings.Secure.ACCESSIBILITY_ENABLED,
    +-                enabled ? 1 : 0);
    +-
    +-        // wait the accessibility manager service to pick the change up
    +-        Thread.sleep(TIMEOUT_BINDER_CALL);
    +-    }
    +-
    +-    /**
    +-     * Ensures the only {@link MockAccessibilityService}s with given component
    +-     * names are enabled by writing to the system settings and waiting until the
    +-     * accessibility manager service picks that up or the
    +-     * {@link #TIMEOUT_START_MOCK_ACCESSIBILITY_SERVICES} is exceeded.
    +-     *
    +-     * @param context A context handle to access the settings.
    +-     * @param firstMockServiceEnabled If the first mock accessibility service is enabled.
    +-     * @param secondMockServiceEnabled If the second mock accessibility service is enabled.
    +-     * @throws IllegalStateException If some of the requested for enabling mock services
    +-     *         is not properly started.
    +-     * @throws Exception Exception If any error occurs.
    +-     */
    +-    private void ensureOnlyMockServicesEnabled(Context context, boolean firstMockServiceEnabled,
    +-            boolean secondMockServiceEnabled) throws Exception {
    +-        String enabledServices = Settings.Secure.getString(context.getContentResolver(),
    +-                Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES);
    +-
    +-        StringBuilder servicesToEnable = new StringBuilder();
    +-        if (firstMockServiceEnabled) {
    +-            servicesToEnable.append(MyFirstMockAccessibilityService.sComponentName).append(":");
    +-        }
    +-        if (secondMockServiceEnabled) {
    +-            servicesToEnable.append(MySecondMockAccessibilityService.sComponentName).append(":");
    +-        }
    +-
    +-        Settings.Secure.putString(context.getContentResolver(),
    +-                Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES, servicesToEnable.toString());
    +-
    +-        // Optimization. If things will not change, we don't have to do anything.
    +-        if (servicesToEnable.equals(enabledServices)) {
    +-            return;
    +-        }
    +-
    +-        // we have enabled the services of interest and need to wait until they
    +-        // are instantiated and started (if needed) and the system binds to them
    +-        boolean firstMockServiceOK = false;
    +-        boolean secondMockServiceOK = false;
    +-        long start = SystemClock.uptimeMillis();
    +-        long pollingInterval = TIMEOUT_START_MOCK_ACCESSIBILITY_SERVICES / 6;
    +-
    +-        while (SystemClock.uptimeMillis() - start < TIMEOUT_START_MOCK_ACCESSIBILITY_SERVICES)  {
    +-            firstMockServiceOK = !firstMockServiceEnabled
    +-                    || (MyFirstMockAccessibilityService.sInstance != null
    +-                    && MyFirstMockAccessibilityService.sInstance.isSystemBoundAsClient());
    +-
    +-            secondMockServiceOK = !secondMockServiceEnabled
    +-                    || (MySecondMockAccessibilityService.sInstance != null
    +-                    && MySecondMockAccessibilityService.sInstance.isSystemBoundAsClient());
    +-
    +-            if (firstMockServiceOK && secondMockServiceOK) {
    +-                return;
    +-            }
    +-
    +-            Thread.sleep(pollingInterval);
    +-        }
    +-
    +-        StringBuilder message = new StringBuilder();
    +-        message.append("Mock accessibility services not started or system not bound as a client: ");
    +-        if (!firstMockServiceOK) {
    +-            message.append(MyFirstMockAccessibilityService.sComponentName);
    +-            message.append(" ");
    +-        }
    +-        if (!secondMockServiceOK) {
    +-            message.append(MySecondMockAccessibilityService.sComponentName);
    +-        }
    +-        throw new IllegalStateException(message.toString());
    +-    }
    +-
    +-    /**
    +-     * Asserts the the mock accessibility service has been successfully verified
    +-     * (which is it has received the expected method calls with expected
    +-     * arguments) within the {@link #TIMEOUT_BINDER_CALL}. The verified state is
    +-     * checked by polling upon small intervals.
    +-     *
    +-     * @param service The service to verify.
    +-     * @throws Exception If the verification has failed with exception after the
    +-     *             {@link #TIMEOUT_BINDER_CALL}.
    +-     */
    +-    private void assertMockServiceVerifiedWithinTimeout(MockAccessibilityService service)
    +-            throws Exception {
    +-        Exception lastVerifyException = null;
    +-        long beginTime = SystemClock.uptimeMillis();
    +-        long pollTimeout = TIMEOUT_BINDER_CALL / 5;
    +-
    +-        // poll until the timeout has elapsed
    +-        while (SystemClock.uptimeMillis() - beginTime < TIMEOUT_BINDER_CALL) {
    +-            // sleep first since immediate call will always fail
    +-            try {
    +-                Thread.sleep(pollTimeout);
    +-            } catch (InterruptedException ie) {
    +-                /* ignore */
    +-            }
    +-            // poll for verification and if this fails save the exception and
    +-            // keep polling
    +-            try {
    +-                service.verify();
    +-                // reset so it does not accept more events
    +-                service.reset();
    +-                return;
    +-            } catch (Exception e) {
    +-                lastVerifyException = e;
    +-            }
    +-        }
    +-
    +-        // reset, we have already failed
    +-        service.reset();
    +-
    +-        // always not null
    +-        throw lastVerifyException;
    +-    }
    +-
    +-    /**
    +-     * This class is the first mock {@link AccessibilityService}.
    +-     */
    +-    public static class MyFirstMockAccessibilityService extends MockAccessibilityService {
    +-
    +-        /**
    +-         * The service {@link ComponentName} flattened as a string.
    +-         */
    +-        static String sComponentName;
    +-
    +-        /**
    +-         * Handle to the service instance.
    +-         */
    +-        static MyFirstMockAccessibilityService sInstance;
    +-
    +-        /**
    +-         * Creates a new instance.
    +-         */
    +-        public MyFirstMockAccessibilityService() {
    +-            sInstance = this;
    +-        }
    +-    }
    +-
    +-    /**
    +-     * This class is the first mock {@link AccessibilityService}.
    +-     */
    +-    public static class MySecondMockAccessibilityService extends MockAccessibilityService {
    +-
    +-        /**
    +-         * The service {@link ComponentName} flattened as a string.
    +-         */
    +-        static String sComponentName;
    +-
    +-        /**
    +-         * Handle to the service instance.
    +-         */
    +-        static MySecondMockAccessibilityService sInstance;
    +-
    +-        /**
    +-         * Creates a new instance.
    +-         */
    +-        public MySecondMockAccessibilityService() {
    +-            sInstance = this;
    +-        }
    +-    }
    +-}
    +diff --git a/services/tests/servicestests/src/com/android/server/AccessibilityManagerTest.java b/services/tests/servicestests/src/com/android/server/AccessibilityManagerTest.java
    +deleted file mode 100644
    +index 026a2ad..0000000
    +--- a/services/tests/servicestests/src/com/android/server/AccessibilityManagerTest.java
    ++++ /dev/null
    +@@ -1,162 +0,0 @@
    +-/*
    +- * Copyright (C) 2010 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 com.android.server;
    +-
    +-import static org.mockito.Matchers.any;
    +-import static org.mockito.Matchers.anyInt;
    +-import static org.mockito.Matchers.eq;
    +-import static org.mockito.Mockito.verify;
    +-import static org.mockito.Mockito.when;
    +-
    +-import android.accessibilityservice.AccessibilityServiceInfo;
    +-import android.os.UserHandle;
    +-import android.test.AndroidTestCase;
    +-import android.test.suitebuilder.annotation.LargeTest;
    +-import android.test.suitebuilder.annotation.MediumTest;
    +-import android.view.accessibility.AccessibilityEvent;
    +-import android.view.accessibility.AccessibilityManager;
    +-import android.view.accessibility.IAccessibilityManager;
    +-import android.view.accessibility.IAccessibilityManagerClient;
    +-
    +-import org.mockito.Mock;
    +-import org.mockito.MockitoAnnotations;
    +-
    +-import java.util.ArrayList;
    +-import java.util.List;
    +-
    +-/**
    +- * Tests for the AccessibilityManager which mocking the backing service.
    +- */
    +-public class AccessibilityManagerTest extends AndroidTestCase {
    +-
    +-    /**
    +-     * Timeout required for pending Binder calls or event processing to
    +-     * complete.
    +-     */
    +-    public static final long TIMEOUT_BINDER_CALL = 50;
    +-
    +-    @Mock
    +-    private IAccessibilityManager mMockService;
    +-
    +-    @Override
    +-    public void setUp() throws Exception {
    +-        MockitoAnnotations.initMocks(this);
    +-    }
    +-
    +-    private AccessibilityManager createManager(boolean enabled) throws Exception {
    +-        if (enabled) {
    +-            when(mMockService.addClient(any(IAccessibilityManagerClient.class), anyInt()))
    +-                    .thenReturn(AccessibilityManager.STATE_FLAG_ACCESSIBILITY_ENABLED);
    +-        } else {
    +-            when(mMockService.addClient(any(IAccessibilityManagerClient.class), anyInt()))
    +-                    .thenReturn(0);
    +-        }
    +-
    +-        AccessibilityManager manager =
    +-                new AccessibilityManager(mContext, mMockService, UserHandle.USER_CURRENT);
    +-
    +-        verify(mMockService).addClient(any(IAccessibilityManagerClient.class), anyInt());
    +-
    +-        return manager;
    +-    }
    +-
    +-    @MediumTest
    +-    public void testGetAccessibilityServiceList() throws Exception {
    +-        // create a list of installed accessibility services the mock service returns
    +-        List<AccessibilityServiceInfo> expectedServices = new ArrayList<>();
    +-        AccessibilityServiceInfo accessibilityServiceInfo = new AccessibilityServiceInfo();
    +-        accessibilityServiceInfo.packageNames = new String[] { "foo.bar" };
    +-        expectedServices.add(accessibilityServiceInfo);
    +-
    +-        // configure the mock service behavior
    +-        when(mMockService.getInstalledAccessibilityServiceList(anyInt()))
    +-                .thenReturn(expectedServices);
    +-
    +-        // invoke the method under test
    +-        AccessibilityManager manager = createManager(true);
    +-        List<AccessibilityServiceInfo> receivedServices =
    +-                manager.getInstalledAccessibilityServiceList();
    +-
    +-        verify(mMockService).getInstalledAccessibilityServiceList(UserHandle.USER_CURRENT);
    +-        // check expected result (list equals() compares it contents as well)
    +-        assertEquals("All expected services must be returned", expectedServices, receivedServices);
    +-    }
    +-
    +-    @MediumTest
    +-    public void testInterrupt() throws Exception {
    +-        AccessibilityManager manager = createManager(true);
    +-        manager.interrupt();
    +-
    +-        verify(mMockService).interrupt(UserHandle.USER_CURRENT);
    +-    }
    +-
    +-    @LargeTest
    +-    public void testIsEnabled() throws Exception {
    +-        // invoke the method under test
    +-        AccessibilityManager manager = createManager(true);
    +-        boolean isEnabledServiceEnabled = manager.isEnabled();
    +-
    +-        // check expected result
    +-        assertTrue("Must be enabled since the mock service is enabled", isEnabledServiceEnabled);
    +-
    +-        // disable accessibility
    +-        manager.getClient().setState(0);
    +-
    +-        // wait for the asynchronous IBinder call to complete
    +-        Thread.sleep(TIMEOUT_BINDER_CALL);
    +-
    +-        // invoke the method under test
    +-        boolean isEnabledServcieDisabled = manager.isEnabled();
    +-
    +-        // check expected result
    +-        assertFalse("Must be disabled since the mock service is disabled",
    +-                isEnabledServcieDisabled);
    +-    }
    +-
    +-    @MediumTest
    +-    public void testSendAccessibilityEvent_AccessibilityEnabled() throws Exception {
    +-        AccessibilityEvent sentEvent = AccessibilityEvent.obtain();
    +-
    +-        when(mMockService.sendAccessibilityEvent(eq(sentEvent), anyInt()))
    +-                .thenReturn(true  /* should recycle event object */)
    +-                .thenReturn(false /* should not recycle event object */);
    +-
    +-        AccessibilityManager manager = createManager(true);
    +-        manager.sendAccessibilityEvent(sentEvent);
    +-
    +-        assertSame("The event should be recycled.", sentEvent, AccessibilityEvent.obtain());
    +-
    +-        manager.sendAccessibilityEvent(sentEvent);
    +-
    +-        assertNotSame("The event should not be recycled.", sentEvent, AccessibilityEvent.obtain());
    +-    }
    +-
    +-    @MediumTest
    +-    public void testSendAccessibilityEvent_AccessibilityDisabled() throws Exception {
    +-        AccessibilityEvent sentEvent = AccessibilityEvent.obtain();
    +-
    +-        AccessibilityManager manager = createManager(false  /* disabled */);
    +-
    +-        try {
    +-            manager.sendAccessibilityEvent(sentEvent);
    +-            fail("No accessibility events are sent if accessibility is disabled");
    +-        } catch (IllegalStateException ise) {
    +-            // check expected result
    +-            assertEquals("Accessibility off. Did you forget to check that?", ise.getMessage());
    +-        }
    +-    }
    +-}
    +diff --git a/services/tests/servicestests/src/com/android/server/BroadcastInterceptingContext.java b/services/tests/servicestests/src/com/android/server/BroadcastInterceptingContext.java
    +deleted file mode 100644
    +index 13657ab..0000000
    +--- a/services/tests/servicestests/src/com/android/server/BroadcastInterceptingContext.java
    ++++ /dev/null
    +@@ -1,177 +0,0 @@
    +-/*
    +- * Copyright (C) 2011 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 com.android.server;
    +-
    +-import android.content.BroadcastReceiver;
    +-import android.content.Context;
    +-import android.content.ContextWrapper;
    +-import android.content.Intent;
    +-import android.content.IntentFilter;
    +-import android.os.Bundle;
    +-import android.os.Handler;
    +-import android.os.UserHandle;
    +-
    +-import com.google.common.collect.Lists;
    +-import com.google.common.util.concurrent.AbstractFuture;
    +-
    +-import java.util.Iterator;
    +-import java.util.List;
    +-import java.util.concurrent.ExecutionException;
    +-import java.util.concurrent.Future;
    +-import java.util.concurrent.TimeUnit;
    +-import java.util.concurrent.TimeoutException;
    +-
    +-/**
    +- * {@link ContextWrapper} that can attach listeners for upcoming
    +- * {@link Context#sendBroadcast(Intent)}.
    +- */
    +-public class BroadcastInterceptingContext extends ContextWrapper {
    +-    private static final String TAG = "WatchingContext";
    +-
    +-    private final List<BroadcastInterceptor> mInterceptors = Lists.newArrayList();
    +-
    +-    public class BroadcastInterceptor extends AbstractFuture<Intent> {
    +-        private final BroadcastReceiver mReceiver;
    +-        private final IntentFilter mFilter;
    +-
    +-        public BroadcastInterceptor(BroadcastReceiver receiver, IntentFilter filter) {
    +-            mReceiver = receiver;
    +-            mFilter = filter;
    +-        }
    +-
    +-        public boolean dispatchBroadcast(Intent intent) {
    +-            if (mFilter.match(getContentResolver(), intent, false, TAG) > 0) {
    +-                if (mReceiver != null) {
    +-                    final Context context = BroadcastInterceptingContext.this;
    +-                    mReceiver.onReceive(context, intent);
    +-                    return false;
    +-                } else {
    +-                    set(intent);
    +-                    return true;
    +-                }
    +-            } else {
    +-                return false;
    +-            }
    +-        }
    +-
    +-        @Override
    +-        public Intent get() throws InterruptedException, ExecutionException {
    +-            try {
    +-                return get(5, TimeUnit.SECONDS);
    +-            } catch (TimeoutException e) {
    +-                throw new RuntimeException(e);
    +-            }
    +-        }
    +-    }
    +-
    +-    public BroadcastInterceptingContext(Context base) {
    +-        super(base);
    +-    }
    +-
    +-    public Future<Intent> nextBroadcastIntent(String action) {
    +-        return nextBroadcastIntent(new IntentFilter(action));
    +-    }
    +-
    +-    public Future<Intent> nextBroadcastIntent(IntentFilter filter) {
    +-        final BroadcastInterceptor interceptor = new BroadcastInterceptor(null, filter);
    +-        synchronized (mInterceptors) {
    +-            mInterceptors.add(interceptor);
    +-        }
    +-        return interceptor;
    +-    }
    +-
    +-    @Override
    +-    public Intent registerReceiver(BroadcastReceiver receiver, IntentFilter filter) {
    +-        synchronized (mInterceptors) {
    +-            mInterceptors.add(new BroadcastInterceptor(receiver, filter));
    +-        }
    +-        return null;
    +-    }
    +-
    +-    @Override
    +-    public Intent registerReceiver(BroadcastReceiver receiver, IntentFilter filter,
    +-            String broadcastPermission, Handler scheduler) {
    +-        return registerReceiver(receiver, filter);
    +-    }
    +-
    +-    @Override
    +-    public void unregisterReceiver(BroadcastReceiver receiver) {
    +-        synchronized (mInterceptors) {
    +-            final Iterator<BroadcastInterceptor> i = mInterceptors.iterator();
    +-            while (i.hasNext()) {
    +-                final BroadcastInterceptor interceptor = i.next();
    +-                if (receiver.equals(interceptor.mReceiver)) {
    +-                    i.remove();
    +-                }
    +-            }
    +-        }
    +-    }
    +-
    +-    @Override
    +-    public void sendBroadcast(Intent intent) {
    +-        synchronized (mInterceptors) {
    +-            final Iterator<BroadcastInterceptor> i = mInterceptors.iterator();
    +-            while (i.hasNext()) {
    +-                final BroadcastInterceptor interceptor = i.next();
    +-                if (interceptor.dispatchBroadcast(intent)) {
    +-                    i.remove();
    +-                }
    +-            }
    +-        }
    +-    }
    +-
    +-    @Override
    +-    public void sendBroadcast(Intent intent, String receiverPermission) {
    +-        sendBroadcast(intent);
    +-    }
    +-
    +-    @Override
    +-    public void sendBroadcastMultiplePermissions(Intent intent, String[] receiverPermissions) {
    +-        sendBroadcast(intent);
    +-    }
    +-
    +-    @Override
    +-    public void sendBroadcastAsUser(Intent intent, UserHandle user) {
    +-        sendBroadcast(intent);
    +-    }
    +-
    +-    @Override
    +-    public void sendBroadcastAsUser(Intent intent, UserHandle user,
    +-            String receiverPermission) {
    +-        sendBroadcast(intent);
    +-    }
    +-
    +-    @Override
    +-    public void sendStickyBroadcast(Intent intent) {
    +-        sendBroadcast(intent);
    +-    }
    +-
    +-    @Override
    +-    public void sendStickyBroadcastAsUser(Intent intent, UserHandle user) {
    +-        sendBroadcast(intent);
    +-    }
    +-
    +-    @Override
    +-    public void sendStickyBroadcastAsUser(Intent intent, UserHandle user, Bundle options) {
    +-        sendBroadcast(intent);
    +-    }
    +-
    +-    @Override
    +-    public void removeStickyBroadcast(Intent intent) {
    +-        // ignored
    +-    }
    +-}
    +diff --git a/services/tests/servicestests/src/com/android/server/CertBlacklisterTest.java b/services/tests/servicestests/src/com/android/server/CertBlacklisterTest.java
    +deleted file mode 100644
    +index 10b9e7c..0000000
    +--- a/services/tests/servicestests/src/com/android/server/CertBlacklisterTest.java
    ++++ /dev/null
    +@@ -1,169 +0,0 @@
    +-/*
    +- * Copyright (C) 2012 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 com.android.server;
    +-
    +-import android.content.Context;
    +-import android.content.Intent;
    +-import android.test.AndroidTestCase;
    +-import android.provider.Settings;
    +-import android.util.Log;
    +-
    +-import java.io.File;
    +-import java.io.FileInputStream;
    +-import java.io.IOException;
    +-import java.util.HashSet;
    +-
    +-import libcore.io.IoUtils;
    +-
    +-/**
    +- * Tests for {@link com.android.server.CertBlacklister}
    +- */
    +-public class CertBlacklisterTest extends AndroidTestCase {
    +-
    +-    private static final String BLACKLIST_ROOT = System.getenv("ANDROID_DATA") + "/misc/keychain/";
    +-
    +-    public static final String PUBKEY_PATH = BLACKLIST_ROOT + "pubkey_blacklist.txt";
    +-    public static final String SERIAL_PATH = BLACKLIST_ROOT + "serial_blacklist.txt";
    +-
    +-    public static final String PUBKEY_KEY = "pubkey_blacklist";
    +-    public static final String SERIAL_KEY = "serial_blacklist";
    +-
    +-    private void overrideSettings(String key, String value) throws Exception {
    +-        Settings.Secure.putString(mContext.getContentResolver(), key, value);
    +-        Thread.sleep(1000);
    +-    }
    +-
    +-    public void testClearBlacklistPubkey() throws Exception {
    +-        // clear the gservices setting for a clean slate
    +-        overrideSettings(PUBKEY_KEY, "");
    +-        // read the contents of the pubkey blacklist
    +-        String blacklist = IoUtils.readFileAsString(PUBKEY_PATH);
    +-        // Verify that it's empty
    +-        assertEquals("", blacklist);
    +-    }
    +-
    +-    public void testSetBlacklistPubkey() throws Exception {
    +-        // build a new thing to blacklist
    +-        String badPubkey = "7ccabd7db47e94a5759901b6a7dfd45d1c091ccc";
    +-        // add the gservices override
    +-        overrideSettings(PUBKEY_KEY, badPubkey);
    +-        // check the contents again
    +-        String blacklist = IoUtils.readFileAsString(PUBKEY_PATH);
    +-        // make sure that we're equal to the string we sent out
    +-        assertEquals(badPubkey, blacklist);
    +-    }
    +-
    +-    public void testChangeBlacklistPubkey() throws Exception {
    +-        String badPubkey = "6ccabd7db47e94a5759901b6a7dfd45d1c091ccc";
    +-        overrideSettings(PUBKEY_KEY, badPubkey);
    +-        badPubkey = "6ccabd7db47e94a5759901b6a7dfd45d1c091cce";
    +-        overrideSettings(PUBKEY_KEY, badPubkey);
    +-        String blacklist = IoUtils.readFileAsString(PUBKEY_PATH);
    +-        assertEquals(badPubkey, blacklist);
    +-    }
    +-
    +-    public void testMultiBlacklistPubkey() throws Exception {
    +-        String badPubkey = "6ccabd7db47e94a5759901b6a7dfd45d1c091ccc,6ccabd7db47e94a5759901b6a7dfd45d1c091ccd";
    +-        overrideSettings(PUBKEY_KEY, badPubkey);
    +-        String blacklist = IoUtils.readFileAsString(PUBKEY_PATH);
    +-        assertEquals(badPubkey, blacklist);
    +-    }
    +-
    +-    public void testInvalidMultiBlacklistPubkey() throws Exception {
    +-        String badPubkey = "6ccabd7db47e94a5759901b6a7dfd45d1c091ccc,ZZZZZ,6ccabd7db47e94a5759901b6a7dfd45d1c091ccd";
    +-        overrideSettings(PUBKEY_KEY, badPubkey);
    +-        String blacklist = IoUtils.readFileAsString(PUBKEY_PATH);
    +-        assertEquals(badPubkey, blacklist);
    +-    }
    +-
    +-    public void testInvalidCharsBlacklistPubkey() throws Exception {
    +-        String badPubkey = "\n6ccabd7db47e94a5759901b6a7dfd45d1c091ccc,-ZZZZZ,+6ccabd7db47e94a5759901b6a7dfd45d1c091ccd";
    +-        overrideSettings(PUBKEY_KEY, badPubkey);
    +-        String blacklist = IoUtils.readFileAsString(PUBKEY_PATH);
    +-        assertEquals(badPubkey, blacklist);
    +-    }
    +-
    +-    public void testLotsOfBlacklistedPubkeys() throws Exception {
    +-        StringBuilder bl = new StringBuilder();
    +-        for (int i=0; i < 1000; i++) {
    +-            bl.append("6ccabd7db47e94a5759901b6a7dfd45d1c091ccc,");
    +-        }
    +-        overrideSettings(PUBKEY_KEY, bl.toString());
    +-        String blacklist = IoUtils.readFileAsString(PUBKEY_PATH);
    +-        assertEquals(bl.toString(), blacklist);
    +-    }
    +-
    +-    public void testClearBlacklistSerial() throws Exception {
    +-        // clear the gservices setting for a clean slate
    +-        overrideSettings(SERIAL_KEY, "");
    +-        // read the contents of the pubkey blacklist
    +-        String blacklist = IoUtils.readFileAsString(SERIAL_PATH);
    +-        // Verify that it's empty
    +-        assertEquals("", blacklist);
    +-    }
    +-
    +-    public void testSetBlacklistSerial() throws Exception {
    +-        // build a new thing to blacklist
    +-        String badSerial = "22e514121e61c643b1e9b06bd4b9f7d0";
    +-        // add the gservices override
    +-        overrideSettings(SERIAL_KEY, badSerial);
    +-        // check the contents again
    +-        String blacklist = IoUtils.readFileAsString(SERIAL_PATH);
    +-        // make sure that we're equal to the string we sent out
    +-        assertEquals(badSerial, blacklist);
    +-    }
    +-
    +-    public void testChangeBlacklistSerial() throws Exception {
    +-        String badSerial = "22e514121e61c643b1e9b06bd4b9f7d0";
    +-        overrideSettings(SERIAL_KEY, badSerial);
    +-        badSerial = "22e514121e61c643b1e9b06bd4b9f7d1";
    +-        overrideSettings(SERIAL_KEY, badSerial);
    +-        String blacklist = IoUtils.readFileAsString(SERIAL_PATH);
    +-        assertEquals(badSerial, blacklist);
    +-    }
    +-
    +-    public void testMultiBlacklistSerial() throws Exception {
    +-        String badSerial = "22e514121e61c643b1e9b06bd4b9f7d0,22e514121e61c643b1e9b06bd4b9f7d1";
    +-        overrideSettings(SERIAL_KEY, badSerial);
    +-        String blacklist = IoUtils.readFileAsString(SERIAL_PATH);
    +-        assertEquals(badSerial, blacklist);
    +-    }
    +-
    +-    public void testInvalidMultiBlacklistSerial() throws Exception {
    +-        String badSerial = "22e514121e61c643b1e9b06bd4b9f7d0,ZZZZ,22e514121e61c643b1e9b06bd4b9f7d1";
    +-        overrideSettings(SERIAL_KEY, badSerial);
    +-        String blacklist = IoUtils.readFileAsString(SERIAL_PATH);
    +-        assertEquals(badSerial, blacklist);
    +-    }
    +-
    +-    public void testInvalidCharsBlacklistSerial() throws Exception {
    +-        String badSerial = "\n22e514121e61c643b1e9b06bd4b9f7d0,-ZZZZ,+22e514121e61c643b1e9b06bd4b9f7d1";
    +-        overrideSettings(SERIAL_KEY, badSerial);
    +-        String blacklist = IoUtils.readFileAsString(SERIAL_PATH);
    +-        assertEquals(badSerial, blacklist);
    +-    }
    +-
    +-    public void testLotsOfBlacklistedSerials() throws Exception {
    +-        StringBuilder bl = new StringBuilder();
    +-        for (int i=0; i < 1000; i++) {
    +-            bl.append("22e514121e61c643b1e9b06bd4b9f7d0,");
    +-        }
    +-        overrideSettings(SERIAL_KEY, bl.toString());
    +-        String blacklist = IoUtils.readFileAsString(SERIAL_PATH);
    +-        assertEquals(bl.toString(), blacklist);
    +-    }
    +-}
    +diff --git a/services/tests/servicestests/src/com/android/server/ConnectivityServiceTest.java b/services/tests/servicestests/src/com/android/server/ConnectivityServiceTest.java
    +index a656acc..c2c6e21 100644
    +--- a/services/tests/servicestests/src/com/android/server/ConnectivityServiceTest.java
    ++++ b/services/tests/servicestests/src/com/android/server/ConnectivityServiceTest.java
    +@@ -597,7 +597,20 @@ public class ConnectivityServiceTest extends AndroidTestCase {
    + 
    +         @Override
    +         protected CaptivePortalProbeResult isCaptivePortal() {
    +-            return new CaptivePortalProbeResult(gen204ProbeResult, gen204ProbeRedirectUrl);
    ++            return new CaptivePortalProbeResult(gen204ProbeResult, gen204ProbeRedirectUrl, null);
    ++        }
    ++    }
    ++
    ++    private class WrappedAvoidBadWifiTracker extends AvoidBadWifiTracker {
    ++        public boolean configRestrictsAvoidBadWifi;
    ++
    ++        public WrappedAvoidBadWifiTracker(Context c, Handler h, Runnable r) {
    ++            super(c, h, r);
    ++        }
    ++
    ++        @Override
    ++        public boolean configRestrictsAvoidBadWifi() {
    ++            return configRestrictsAvoidBadWifi;
    +         }
    +     }
    + 
    +@@ -746,6 +759,7 @@ public class ConnectivityServiceTest extends AndroidTestCase {
    +     }
    + 
    +     public void tearDown() throws Exception {
    ++        setMobileDataAlwaysOn(false);
    +         if (mCellNetworkAgent != null) { mCellNetworkAgent.disconnect(); }
    +         if (mWiFiNetworkAgent != null) { mWiFiNetworkAgent.disconnect(); }
    +         mCellNetworkAgent = mWiFiNetworkAgent = null;
    +@@ -1843,6 +1857,85 @@ public class ConnectivityServiceTest extends AndroidTestCase {
    +         mCm.unregisterNetworkCallback(cellNetworkCallback);
    +     }
    + 
    ++    private void setMobileDataAlwaysOn(boolean enable) {
    ++        ContentResolver cr = mServiceContext.getContentResolver();
    ++        Settings.Global.putInt(cr, Settings.Global.MOBILE_DATA_ALWAYS_ON, enable ? 1 : 0);
    ++        mService.updateMobileDataAlwaysOn();
    ++        mService.waitForIdle();
    ++    }
    ++
    ++    private boolean isForegroundNetwork(MockNetworkAgent network) {
    ++        NetworkCapabilities nc = mCm.getNetworkCapabilities(network.getNetwork());
    ++        assertNotNull(nc);
    ++        return nc.hasCapability(NET_CAPABILITY_FOREGROUND);
    ++    }
    ++
    ++    @SmallTest
    ++    public void testBackgroundNetworks() throws Exception {
    ++        // Create a background request. We can't do this ourselves because ConnectivityService
    ++        // doesn't have an API for it. So just turn on mobile data always on.
    ++        setMobileDataAlwaysOn(true);
    ++        final NetworkRequest request = new NetworkRequest.Builder().build();
    ++        final NetworkRequest fgRequest = new NetworkRequest.Builder()
    ++                .addCapability(NET_CAPABILITY_FOREGROUND).build();
    ++        final TestNetworkCallback callback = new TestNetworkCallback();
    ++        final TestNetworkCallback fgCallback = new TestNetworkCallback();
    ++        mCm.registerNetworkCallback(request, callback);
    ++        mCm.registerNetworkCallback(fgRequest, fgCallback);
    ++
    ++        mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR);
    ++        mCellNetworkAgent.connect(true);
    ++        callback.expectCallback(CallbackState.AVAILABLE, mCellNetworkAgent);
    ++        fgCallback.expectCallback(CallbackState.AVAILABLE, mCellNetworkAgent);
    ++        assertTrue(isForegroundNetwork(mCellNetworkAgent));
    ++
    ++        mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
    ++        mWiFiNetworkAgent.connect(true);
    ++
    ++        // When wifi connects, cell lingers.
    ++        callback.expectCallback(CallbackState.AVAILABLE, mWiFiNetworkAgent);
    ++        fgCallback.expectCallback(CallbackState.AVAILABLE, mWiFiNetworkAgent);
    ++        callback.expectCallback(CallbackState.LOSING, mCellNetworkAgent);
    ++        fgCallback.expectCallback(CallbackState.LOSING, mCellNetworkAgent);
    ++        assertTrue(isForegroundNetwork(mCellNetworkAgent));
    ++        assertTrue(isForegroundNetwork(mWiFiNetworkAgent));
    ++
    ++        // When lingering is complete, cell is still there but is now in the background.
    ++        fgCallback.expectCallback(CallbackState.LOST, mCellNetworkAgent, TEST_LINGER_DELAY_MS);
    ++        callback.assertNoCallback();
    ++        assertFalse(isForegroundNetwork(mCellNetworkAgent));
    ++        assertTrue(isForegroundNetwork(mWiFiNetworkAgent));
    ++
    ++        // File a cell request and check that cell comes into the foreground.
    ++        final NetworkRequest cellRequest = new NetworkRequest.Builder()
    ++                .addTransportType(TRANSPORT_CELLULAR).build();
    ++        final TestNetworkCallback cellCallback = new TestNetworkCallback();
    ++        mCm.requestNetwork(cellRequest, cellCallback);
    ++        cellCallback.expectCallback(CallbackState.AVAILABLE, mCellNetworkAgent);
    ++        fgCallback.expectCallback(CallbackState.AVAILABLE, mCellNetworkAgent);
    ++        callback.assertNoCallback();  // Because the network is already up.
    ++        assertTrue(isForegroundNetwork(mCellNetworkAgent));
    ++        assertTrue(isForegroundNetwork(mWiFiNetworkAgent));
    ++
    ++        // Release the request. The network immediately goes into the background, since it was not
    ++        // lingering.
    ++        mCm.unregisterNetworkCallback(cellCallback);
    ++        fgCallback.expectCallback(CallbackState.LOST, mCellNetworkAgent);
    ++        callback.assertNoCallback();
    ++        assertFalse(isForegroundNetwork(mCellNetworkAgent));
    ++        assertTrue(isForegroundNetwork(mWiFiNetworkAgent));
    ++
    ++        // Disconnect wifi and check that cell is foreground again.
    ++        mWiFiNetworkAgent.disconnect();
    ++        callback.expectCallback(CallbackState.LOST, mWiFiNetworkAgent);
    ++        fgCallback.expectCallback(CallbackState.LOST, mWiFiNetworkAgent);
    ++        fgCallback.expectCallback(CallbackState.AVAILABLE, mCellNetworkAgent);
    ++        assertTrue(isForegroundNetwork(mCellNetworkAgent));
    ++
    ++        mCm.unregisterNetworkCallback(callback);
    ++        mCm.unregisterNetworkCallback(fgCallback);
    ++    }
    ++
    +     @SmallTest
    +     public void testRequestBenchmark() throws Exception {
    +         // Benchmarks connecting and switching performance in the presence of a large number of
    +@@ -1948,8 +2041,7 @@ public class ConnectivityServiceTest extends AndroidTestCase {
    + 
    +         // Turn on mobile data always on. The factory starts looking again.
    +         testFactory.expectAddRequests(1);
    +-        Settings.Global.putInt(cr, Settings.Global.MOBILE_DATA_ALWAYS_ON, 1);
    +-        mService.updateMobileDataAlwaysOn();
    ++        setMobileDataAlwaysOn(true);
    +         testFactory.waitForNetworkRequests(2);
    +         assertTrue(testFactory.getMyStartRequested());
    + 
    +@@ -1969,8 +2061,7 @@ public class ConnectivityServiceTest extends AndroidTestCase {
    + 
    +         // Turn off mobile data always on and expect the request to disappear...
    +         testFactory.expectRemoveRequests(1);
    +-        Settings.Global.putInt(cr, Settings.Global.MOBILE_DATA_ALWAYS_ON, 0);
    +-        mService.updateMobileDataAlwaysOn();
    ++        setMobileDataAlwaysOn(false);
    +         testFactory.waitForNetworkRequests(1);
    + 
    +         // ...  and cell data to be torn down.
    +diff --git a/services/tests/servicestests/src/com/android/server/CountryDetectorServiceTest.java b/services/tests/servicestests/src/com/android/server/CountryDetectorServiceTest.java
    +deleted file mode 100644
    +index 192c50c..0000000
    +--- a/services/tests/servicestests/src/com/android/server/CountryDetectorServiceTest.java
    ++++ /dev/null
    +@@ -1,109 +0,0 @@
    +-/*
    +- * Copyright (C) 2010 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 com.android.server;
    +-
    +-import android.content.Context;
    +-import android.location.Country;
    +-import android.location.CountryListener;
    +-import android.location.ICountryListener;
    +-import android.os.RemoteException;
    +-import android.test.AndroidTestCase;
    +-
    +-public class CountryDetectorServiceTest extends AndroidTestCase {
    +-    private class CountryListenerTester extends ICountryListener.Stub {
    +-        private Country mCountry;
    +-
    +-        @Override
    +-        public void onCountryDetected(Country country) throws RemoteException {
    +-            mCountry = country;
    +-        }
    +-
    +-        public Country getCountry() {
    +-            return mCountry;
    +-        }
    +-
    +-        public boolean isNotified() {
    +-            return mCountry != null;
    +-        }
    +-    }
    +-
    +-    private class CountryDetectorServiceTester extends CountryDetectorService {
    +-
    +-        private CountryListener mListener;
    +-
    +-        public CountryDetectorServiceTester(Context context) {
    +-            super(context);
    +-        }
    +-
    +-        @Override
    +-        public void notifyReceivers(Country country) {
    +-            super.notifyReceivers(country);
    +-        }
    +-
    +-        @Override
    +-        protected void setCountryListener(final CountryListener listener) {
    +-            mListener = listener;
    +-        }
    +-
    +-        public boolean isListenerSet() {
    +-            return mListener != null;
    +-        }
    +-    }
    +-
    +-    public void testAddRemoveListener() throws RemoteException {
    +-        CountryDetectorServiceTester serviceTester = new CountryDetectorServiceTester(getContext());
    +-        serviceTester.systemRunning();
    +-        waitForSystemReady(serviceTester);
    +-        CountryListenerTester listenerTester = new CountryListenerTester();
    +-        serviceTester.addCountryListener(listenerTester);
    +-        assertTrue(serviceTester.isListenerSet());
    +-        serviceTester.removeCountryListener(listenerTester);
    +-        assertFalse(serviceTester.isListenerSet());
    +-    }
    +-
    +-    public void testNotifyListeners() throws RemoteException {
    +-        CountryDetectorServiceTester serviceTester = new CountryDetectorServiceTester(getContext());
    +-        CountryListenerTester listenerTesterA = new CountryListenerTester();
    +-        CountryListenerTester listenerTesterB = new CountryListenerTester();
    +-        Country country = new Country("US", Country.COUNTRY_SOURCE_NETWORK);
    +-        serviceTester.systemRunning();
    +-        waitForSystemReady(serviceTester);
    +-        serviceTester.addCountryListener(listenerTesterA);
    +-        serviceTester.addCountryListener(listenerTesterB);
    +-        serviceTester.notifyReceivers(country);
    +-        assertTrue(serviceTester.isListenerSet());
    +-        assertTrue(listenerTesterA.isNotified());
    +-        assertTrue(listenerTesterB.isNotified());
    +-        serviceTester.removeCountryListener(listenerTesterA);
    +-        serviceTester.removeCountryListener(listenerTesterB);
    +-        assertFalse(serviceTester.isListenerSet());
    +-    }
    +-
    +-    private void waitForSystemReady(CountryDetectorService service) {
    +-        int count = 5;
    +-        while (count-- > 0) {
    +-            try {
    +-                Thread.sleep(500);
    +-            } catch (Exception e) {
    +-            }
    +-            if (service.isSystemReady()) {
    +-                return;
    +-            }
    +-        }
    +-        throw new RuntimeException("Wait System Ready timeout");
    +-    }
    +-}
    +diff --git a/services/tests/servicestests/src/com/android/server/DropBoxTest.java b/services/tests/servicestests/src/com/android/server/DropBoxTest.java
    +deleted file mode 100644
    +index 7f28d44..0000000
    +--- a/services/tests/servicestests/src/com/android/server/DropBoxTest.java
    ++++ /dev/null
    +@@ -1,775 +0,0 @@
    +-/*
    +- * Copyright (C) 2009 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 com.android.server;
    +-
    +-import android.content.ContentResolver;
    +-import android.content.Context;
    +-import android.content.Intent;
    +-import android.os.DropBoxManager;
    +-import android.os.Parcel;
    +-import android.os.Parcelable;
    +-import android.os.ParcelFileDescriptor;
    +-import android.os.Process;
    +-import android.os.ServiceManager;
    +-import android.os.StatFs;
    +-import android.provider.Settings;
    +-import android.test.AndroidTestCase;
    +-
    +-import com.android.server.DropBoxManagerService;
    +-
    +-import java.io.BufferedReader;
    +-import java.io.File;
    +-import java.io.FileOutputStream;
    +-import java.io.FileWriter;
    +-import java.io.IOException;
    +-import java.io.InputStream;
    +-import java.io.InputStreamReader;
    +-import java.util.Random;
    +-import java.util.zip.GZIPOutputStream;
    +-
    +-/** Test {@link DropBoxManager} functionality. */
    +-public class DropBoxTest extends AndroidTestCase {
    +-    public void tearDown() throws Exception {
    +-        ContentResolver cr = getContext().getContentResolver();
    +-        Settings.Global.putString(cr, Settings.Global.DROPBOX_AGE_SECONDS, "");
    +-        Settings.Global.putString(cr, Settings.Global.DROPBOX_MAX_FILES, "");
    +-        Settings.Global.putString(cr, Settings.Global.DROPBOX_QUOTA_KB, "");
    +-        Settings.Global.putString(cr, Settings.Global.DROPBOX_TAG_PREFIX + "DropBoxTest", "");
    +-    }
    +-
    +-    public void testAddText() throws Exception {
    +-        File dir = getEmptyDir("testAddText");
    +-        DropBoxManagerService service = new DropBoxManagerService(getContext(), dir);
    +-        DropBoxManager dropbox = new DropBoxManager(getContext(), service.getServiceStub());
    +-
    +-        long before = System.currentTimeMillis();
    +-        Thread.sleep(5);
    +-        dropbox.addText("DropBoxTest", "TEST0");
    +-        Thread.sleep(5);
    +-        long between = System.currentTimeMillis();
    +-        Thread.sleep(5);
    +-        dropbox.addText("DropBoxTest", "TEST1");
    +-        dropbox.addText("DropBoxTest", "TEST2");
    +-        Thread.sleep(5);
    +-        long after = System.currentTimeMillis();
    +-
    +-        DropBoxManager.Entry e0 = dropbox.getNextEntry("DropBoxTest", before);
    +-        DropBoxManager.Entry e1 = dropbox.getNextEntry("DropBoxTest", e0.getTimeMillis());
    +-        DropBoxManager.Entry e2 = dropbox.getNextEntry("DropBoxTest", e1.getTimeMillis());
    +-        assertTrue(null == dropbox.getNextEntry("DropBoxTest", e2.getTimeMillis()));
    +-
    +-        assertTrue(e0.getTimeMillis() > before);
    +-        assertTrue(e0.getTimeMillis() < between);
    +-        assertTrue(e1.getTimeMillis() > between);
    +-        assertTrue(e1.getTimeMillis() < e2.getTimeMillis());
    +-        assertTrue(e2.getTimeMillis() < after);
    +-
    +-        assertEquals("TEST0", e0.getText(80));
    +-        assertEquals("TEST1", e1.getText(80));
    +-        assertEquals("TES", e2.getText(3));
    +-
    +-        e0.close();
    +-        e1.close();
    +-        e2.close();
    +-    }
    +-
    +-    public void testAddData() throws Exception {
    +-        File dir = getEmptyDir("testAddData");
    +-        DropBoxManagerService service = new DropBoxManagerService(getContext(), dir);
    +-        DropBoxManager dropbox = new DropBoxManager(getContext(), service.getServiceStub());
    +-
    +-        long before = System.currentTimeMillis();
    +-        dropbox.addData("DropBoxTest", "TEST".getBytes(), 0);
    +-        long after = System.currentTimeMillis();
    +-
    +-        DropBoxManager.Entry e = dropbox.getNextEntry("DropBoxTest", before);
    +-        assertTrue(null == dropbox.getNextEntry("DropBoxTest", e.getTimeMillis()));
    +-
    +-        assertEquals("DropBoxTest", e.getTag());
    +-        assertTrue(e.getTimeMillis() >= before);
    +-        assertEquals(0, e.getFlags());
    +-        assertTrue(null == e.getText(80));
    +-
    +-        byte[] buf = new byte[80];
    +-        assertEquals("TEST", new String(buf, 0, e.getInputStream().read(buf)));
    +-
    +-        e.close();
    +-    }
    +-
    +-    public void testAddFile() throws Exception {
    +-        File dir = getEmptyDir("testAddFile");
    +-        long before = System.currentTimeMillis();
    +-
    +-        File f0 = new File(dir, "f0.txt");
    +-        File f1 = new File(dir, "f1.txt.gz");
    +-        File f2 = new File(dir, "f2.dat");
    +-        File f3 = new File(dir, "f2.dat.gz");
    +-
    +-        FileWriter w0 = new FileWriter(f0);
    +-        GZIPOutputStream gz1 = new GZIPOutputStream(new FileOutputStream(f1));
    +-        FileOutputStream os2 = new FileOutputStream(f2);
    +-        GZIPOutputStream gz3 = new GZIPOutputStream(new FileOutputStream(f3));
    +-
    +-        w0.write("FILE0");
    +-        gz1.write("FILE1".getBytes());
    +-        os2.write("DATA2".getBytes());
    +-        gz3.write("DATA3".getBytes());
    +-
    +-        w0.close();
    +-        gz1.close();
    +-        os2.close();
    +-        gz3.close();
    +-
    +-        DropBoxManagerService service = new DropBoxManagerService(getContext(), dir);
    +-        DropBoxManager dropbox = new DropBoxManager(getContext(), service.getServiceStub());
    +-
    +-        dropbox.addFile("DropBoxTest", f0, DropBoxManager.IS_TEXT);
    +-        dropbox.addFile("DropBoxTest", f1, DropBoxManager.IS_TEXT | DropBoxManager.IS_GZIPPED);
    +-        dropbox.addFile("DropBoxTest", f2, 0);
    +-        dropbox.addFile("DropBoxTest", f3, DropBoxManager.IS_GZIPPED);
    +-
    +-        DropBoxManager.Entry e0 = dropbox.getNextEntry("DropBoxTest", before);
    +-        DropBoxManager.Entry e1 = dropbox.getNextEntry("DropBoxTest", e0.getTimeMillis());
    +-        DropBoxManager.Entry e2 = dropbox.getNextEntry("DropBoxTest", e1.getTimeMillis());
    +-        DropBoxManager.Entry e3 = dropbox.getNextEntry("DropBoxTest", e2.getTimeMillis());
    +-        assertTrue(null == dropbox.getNextEntry("DropBoxTest", e3.getTimeMillis()));
    +-
    +-        assertTrue(e0.getTimeMillis() > before);
    +-        assertTrue(e1.getTimeMillis() > e0.getTimeMillis());
    +-        assertTrue(e2.getTimeMillis() > e1.getTimeMillis());
    +-        assertTrue(e3.getTimeMillis() > e2.getTimeMillis());
    +-
    +-        assertEquals(DropBoxManager.IS_TEXT, e0.getFlags());
    +-        assertEquals(DropBoxManager.IS_TEXT, e1.getFlags());
    +-        assertEquals(0, e2.getFlags());
    +-        assertEquals(0, e3.getFlags());
    +-
    +-        assertEquals("FILE0", e0.getText(80));
    +-
    +-        byte[] buf1 = new byte[80];
    +-        assertEquals("FILE1", new String(buf1, 0, e1.getInputStream().read(buf1)));
    +-
    +-        assertTrue(null == e2.getText(80));
    +-        byte[] buf2 = new byte[80];
    +-        assertEquals("DATA2", new String(buf2, 0, e2.getInputStream().read(buf2)));
    +-
    +-        assertTrue(null == e3.getText(80));
    +-        byte[] buf3 = new byte[80];
    +-        assertEquals("DATA3", new String(buf3, 0, e3.getInputStream().read(buf3)));
    +-
    +-        e0.close();
    +-        e1.close();
    +-        e2.close();
    +-        e3.close();
    +-    }
    +-
    +-    public void testAddEntriesInTheFuture() throws Exception {
    +-        File dir = getEmptyDir("testAddEntriesInTheFuture");
    +-        long before = System.currentTimeMillis();
    +-
    +-        // Near future: should be allowed to persist
    +-        FileWriter w0 = new FileWriter(new File(dir, "DropBoxTest@" + (before + 5000) + ".txt"));
    +-        w0.write("FUTURE0");
    +-        w0.close();
    +-
    +-        // Far future: should be collapsed
    +-        FileWriter w1 = new FileWriter(new File(dir, "DropBoxTest@" + (before + 100000) + ".txt"));
    +-        w1.write("FUTURE1");
    +-        w1.close();
    +-
    +-        // Another far future item, this one gzipped
    +-        File f2 = new File(dir, "DropBoxTest@" + (before + 100001) + ".txt.gz");
    +-        GZIPOutputStream gz2 = new GZIPOutputStream(new FileOutputStream(f2));
    +-        gz2.write("FUTURE2".getBytes());
    +-        gz2.close();
    +-
    +-        // Tombstone in the far future
    +-        new FileOutputStream(new File(dir, "DropBoxTest@" + (before + 100002) + ".lost")).close();
    +-
    +-        DropBoxManagerService service = new DropBoxManagerService(getContext(), dir);
    +-        DropBoxManager dropbox = new DropBoxManager(getContext(), service.getServiceStub());
    +-
    +-        // Until a write, the timestamps are taken at face value
    +-        DropBoxManager.Entry e0 = dropbox.getNextEntry(null, before);
    +-        DropBoxManager.Entry e1 = dropbox.getNextEntry(null, e0.getTimeMillis());
    +-        DropBoxManager.Entry e2 = dropbox.getNextEntry(null, e1.getTimeMillis());
    +-        DropBoxManager.Entry e3 = dropbox.getNextEntry(null, e2.getTimeMillis());
    +-        assertTrue(null == dropbox.getNextEntry(null, e3.getTimeMillis()));
    +-
    +-        assertEquals("FUTURE0", e0.getText(80));
    +-        assertEquals("FUTURE1", e1.getText(80));
    +-        assertEquals("FUTURE2", e2.getText(80));
    +-        assertEquals(null, e3.getText(80));
    +-
    +-        assertEquals(before + 5000, e0.getTimeMillis());
    +-        assertEquals(before + 100000, e1.getTimeMillis());
    +-        assertEquals(before + 100001, e2.getTimeMillis());
    +-        assertEquals(before + 100002, e3.getTimeMillis());
    +-
    +-        e0.close();
    +-        e1.close();
    +-        e2.close();
    +-        e3.close();
    +-
    +-        // Write something to force a collapse
    +-        dropbox.addText("NotDropBoxTest", "FUTURE");
    +-        e0 = dropbox.getNextEntry(null, before);
    +-        e1 = dropbox.getNextEntry(null, e0.getTimeMillis());
    +-        e2 = dropbox.getNextEntry(null, e1.getTimeMillis());
    +-        e3 = dropbox.getNextEntry(null, e2.getTimeMillis());
    +-        assertTrue(null == dropbox.getNextEntry("DropBoxTest", e3.getTimeMillis()));
    +-
    +-        assertEquals("FUTURE0", e0.getText(80));
    +-        assertEquals("FUTURE1", e1.getText(80));
    +-        assertEquals("FUTURE2", e2.getText(80));
    +-        assertEquals(null, e3.getText(80));
    +-
    +-        assertEquals(before + 5000, e0.getTimeMillis());
    +-        assertEquals(before + 5001, e1.getTimeMillis());
    +-        assertEquals(before + 5002, e2.getTimeMillis());
    +-        assertEquals(before + 5003, e3.getTimeMillis());
    +-
    +-        e0.close();
    +-        e1.close();
    +-        e2.close();
    +-        e3.close();
    +-    }
    +-
    +-    public void testIsTagEnabled() throws Exception {
    +-        File dir = getEmptyDir("testIsTagEnabled");
    +-        DropBoxManagerService service = new DropBoxManagerService(getContext(), dir);
    +-        DropBoxManager dropbox = new DropBoxManager(getContext(), service.getServiceStub());
    +-
    +-        long before = System.currentTimeMillis();
    +-        dropbox.addText("DropBoxTest", "TEST-ENABLED");
    +-        assertTrue(dropbox.isTagEnabled("DropBoxTest"));
    +-
    +-        ContentResolver cr = getContext().getContentResolver();
    +-        Settings.Global.putString(cr, Settings.Global.DROPBOX_TAG_PREFIX + "DropBoxTest",
    +-                                  "disabled");
    +-
    +-        dropbox.addText("DropBoxTest", "TEST-DISABLED");
    +-        assertFalse(dropbox.isTagEnabled("DropBoxTest"));
    +-
    +-        Settings.Global.putString(cr, Settings.Global.DROPBOX_TAG_PREFIX + "DropBoxTest",
    +-                                  "");
    +-
    +-        dropbox.addText("DropBoxTest", "TEST-ENABLED-AGAIN");
    +-        assertTrue(dropbox.isTagEnabled("DropBoxTest"));
    +-
    +-        DropBoxManager.Entry e0 = dropbox.getNextEntry("DropBoxTest", before);
    +-        DropBoxManager.Entry e1 = dropbox.getNextEntry("DropBoxTest", e0.getTimeMillis());
    +-        assertTrue(null == dropbox.getNextEntry("DropBoxTest", e1.getTimeMillis()));
    +-
    +-        assertEquals("TEST-ENABLED", e0.getText(80));
    +-        assertEquals("TEST-ENABLED-AGAIN", e1.getText(80));
    +-
    +-        e0.close();
    +-        e1.close();
    +-    }
    +-
    +-    public void testGetNextEntry() throws Exception {
    +-        File dir = getEmptyDir("testGetNextEntry");
    +-        DropBoxManagerService service = new DropBoxManagerService(getContext(), dir);
    +-        DropBoxManager dropbox = new DropBoxManager(getContext(), service.getServiceStub());
    +-
    +-        long before = System.currentTimeMillis();
    +-        dropbox.addText("DropBoxTest.A", "A0");
    +-        dropbox.addText("DropBoxTest.B", "B0");
    +-        dropbox.addText("DropBoxTest.A", "A1");
    +-
    +-        DropBoxManager.Entry a0 = dropbox.getNextEntry("DropBoxTest.A", before);
    +-        DropBoxManager.Entry a1 = dropbox.getNextEntry("DropBoxTest.A", a0.getTimeMillis());
    +-        assertTrue(null == dropbox.getNextEntry("DropBoxTest.A", a1.getTimeMillis()));
    +-
    +-        DropBoxManager.Entry b0 = dropbox.getNextEntry("DropBoxTest.B", before);
    +-        assertTrue(null == dropbox.getNextEntry("DropBoxTest.B", b0.getTimeMillis()));
    +-
    +-        DropBoxManager.Entry x0 = dropbox.getNextEntry(null, before);
    +-        DropBoxManager.Entry x1 = dropbox.getNextEntry(null, x0.getTimeMillis());
    +-        DropBoxManager.Entry x2 = dropbox.getNextEntry(null, x1.getTimeMillis());
    +-        assertTrue(null == dropbox.getNextEntry(null, x2.getTimeMillis()));
    +-
    +-        assertEquals("DropBoxTest.A", a0.getTag());
    +-        assertEquals("DropBoxTest.A", a1.getTag());
    +-        assertEquals("A0", a0.getText(80));
    +-        assertEquals("A1", a1.getText(80));
    +-
    +-        assertEquals("DropBoxTest.B", b0.getTag());
    +-        assertEquals("B0", b0.getText(80));
    +-
    +-        assertEquals("DropBoxTest.A", x0.getTag());
    +-        assertEquals("DropBoxTest.B", x1.getTag());
    +-        assertEquals("DropBoxTest.A", x2.getTag());
    +-        assertEquals("A0", x0.getText(80));
    +-        assertEquals("B0", x1.getText(80));
    +-        assertEquals("A1", x2.getText(80));
    +-
    +-        a0.close();
    +-        a1.close();
    +-        b0.close();
    +-        x0.close();
    +-        x1.close();
    +-        x2.close();
    +-    }
    +-
    +-    public void testSizeLimits() throws Exception {
    +-        File dir = getEmptyDir("testSizeLimits");
    +-        int blockSize =  new StatFs(dir.getPath()).getBlockSize();
    +-
    +-        // Limit storage to 10 blocks
    +-        int kb = blockSize * 10 / 1024;
    +-        ContentResolver cr = getContext().getContentResolver();
    +-        Settings.Global.putString(cr, Settings.Global.DROPBOX_QUOTA_KB, Integer.toString(kb));
    +-
    +-        // Three tags using a total of 12 blocks:
    +-        // DropBoxTest0 [ ][ ]
    +-        // DropBoxTest1 [x][ ][    ][ ][xxx(20 blocks)xxx]
    +-        // DropBoxTest2 [xxxxxxxxxx][ ][ ]
    +-        //
    +-        // The blocks marked "x" will be removed due to storage restrictions.
    +-        // Use random fill (so it doesn't compress), subtract a little for gzip overhead
    +-
    +-        final int overhead = 64;
    +-        long before = System.currentTimeMillis();
    +-        DropBoxManagerService service = new DropBoxManagerService(getContext(), dir);
    +-        DropBoxManager dropbox = new DropBoxManager(getContext(), service.getServiceStub());
    +-
    +-        addRandomEntry(dropbox, "DropBoxTest0", blockSize - overhead);
    +-        addRandomEntry(dropbox, "DropBoxTest0", blockSize - overhead);
    +-
    +-        addRandomEntry(dropbox, "DropBoxTest1", blockSize - overhead);
    +-        addRandomEntry(dropbox, "DropBoxTest1", blockSize - overhead);
    +-        addRandomEntry(dropbox, "DropBoxTest1", blockSize * 2 - overhead);
    +-        addRandomEntry(dropbox, "DropBoxTest1", blockSize - overhead);
    +-        addRandomEntry(dropbox, "DropBoxTest1", blockSize * 20 - overhead);
    +-
    +-        addRandomEntry(dropbox, "DropBoxTest2", blockSize * 4 - overhead);
    +-        addRandomEntry(dropbox, "DropBoxTest2", blockSize - overhead);
    +-        addRandomEntry(dropbox, "DropBoxTest2", blockSize - overhead);
    +-
    +-        DropBoxManager.Entry e0 = dropbox.getNextEntry(null, before);
    +-        DropBoxManager.Entry e1 = dropbox.getNextEntry(null, e0.getTimeMillis());
    +-        DropBoxManager.Entry e2 = dropbox.getNextEntry(null, e1.getTimeMillis());
    +-        DropBoxManager.Entry e3 = dropbox.getNextEntry(null, e2.getTimeMillis());
    +-        DropBoxManager.Entry e4 = dropbox.getNextEntry(null, e3.getTimeMillis());
    +-        DropBoxManager.Entry e5 = dropbox.getNextEntry(null, e4.getTimeMillis());
    +-        DropBoxManager.Entry e6 = dropbox.getNextEntry(null, e5.getTimeMillis());
    +-        DropBoxManager.Entry e7 = dropbox.getNextEntry(null, e6.getTimeMillis());
    +-        DropBoxManager.Entry e8 = dropbox.getNextEntry(null, e7.getTimeMillis());
    +-        DropBoxManager.Entry e9 = dropbox.getNextEntry(null, e8.getTimeMillis());
    +-        assertTrue(null == dropbox.getNextEntry(null, e9.getTimeMillis()));
    +-
    +-        assertEquals("DropBoxTest0", e0.getTag());
    +-        assertEquals("DropBoxTest0", e1.getTag());
    +-        assertEquals(blockSize - overhead, getEntrySize(e0));
    +-        assertEquals(blockSize - overhead, getEntrySize(e1));
    +-
    +-        assertEquals("DropBoxTest1", e2.getTag());
    +-        assertEquals("DropBoxTest1", e3.getTag());
    +-        assertEquals("DropBoxTest1", e4.getTag());
    +-        assertEquals("DropBoxTest1", e5.getTag());
    +-        assertEquals("DropBoxTest1", e6.getTag());
    +-        assertEquals(-1, getEntrySize(e2));  // Tombstone
    +-        assertEquals(blockSize - overhead, getEntrySize(e3));
    +-        assertEquals(blockSize * 2 - overhead, getEntrySize(e4));
    +-        assertEquals(blockSize - overhead, getEntrySize(e5));
    +-        assertEquals(-1, getEntrySize(e6));
    +-
    +-        assertEquals("DropBoxTest2", e7.getTag());
    +-        assertEquals("DropBoxTest2", e8.getTag());
    +-        assertEquals("DropBoxTest2", e9.getTag());
    +-        assertEquals(-1, getEntrySize(e7));  // Tombstone
    +-        assertEquals(blockSize - overhead, getEntrySize(e8));
    +-        assertEquals(blockSize - overhead, getEntrySize(e9));
    +-
    +-        e0.close();
    +-        e1.close();
    +-        e2.close();
    +-        e3.close();
    +-        e4.close();
    +-        e5.close();
    +-        e6.close();
    +-        e7.close();
    +-        e8.close();
    +-        e9.close();
    +-
    +-        // Specifying a tag name skips tombstone records.
    +-
    +-        DropBoxManager.Entry t0 = dropbox.getNextEntry("DropBoxTest1", before);
    +-        DropBoxManager.Entry t1 = dropbox.getNextEntry("DropBoxTest1", t0.getTimeMillis());
    +-        DropBoxManager.Entry t2 = dropbox.getNextEntry("DropBoxTest1", t1.getTimeMillis());
    +-        assertTrue(null == dropbox.getNextEntry("DropBoxTest1", t2.getTimeMillis()));
    +-
    +-        assertEquals("DropBoxTest1", t0.getTag());
    +-        assertEquals("DropBoxTest1", t1.getTag());
    +-        assertEquals("DropBoxTest1", t2.getTag());
    +-
    +-        assertEquals(blockSize - overhead, getEntrySize(t0));
    +-        assertEquals(blockSize * 2 - overhead, getEntrySize(t1));
    +-        assertEquals(blockSize - overhead, getEntrySize(t2));
    +-
    +-        t0.close();
    +-        t1.close();
    +-        t2.close();
    +-    }
    +-
    +-    public void testAgeLimits() throws Exception {
    +-        File dir = getEmptyDir("testAgeLimits");
    +-        int blockSize = new StatFs(dir.getPath()).getBlockSize();
    +-
    +-        // Limit storage to 10 blocks with an expiration of 1 second
    +-        int kb = blockSize * 10 / 1024;
    +-        ContentResolver cr = getContext().getContentResolver();
    +-        Settings.Global.putString(cr, Settings.Global.DROPBOX_AGE_SECONDS, "1");
    +-        Settings.Global.putString(cr, Settings.Global.DROPBOX_QUOTA_KB, Integer.toString(kb));
    +-
    +-        // Write one normal entry and another so big that it is instantly tombstoned
    +-        long before = System.currentTimeMillis();
    +-        DropBoxManagerService service = new DropBoxManagerService(getContext(), dir);
    +-        DropBoxManager dropbox = new DropBoxManager(getContext(), service.getServiceStub());
    +-
    +-        dropbox.addText("DropBoxTest", "TEST");
    +-        addRandomEntry(dropbox, "DropBoxTest", blockSize * 20);
    +-
    +-        // Verify that things are as expected
    +-        DropBoxManager.Entry e0 = dropbox.getNextEntry(null, before);
    +-        DropBoxManager.Entry e1 = dropbox.getNextEntry(null, e0.getTimeMillis());
    +-        assertTrue(null == dropbox.getNextEntry(null, e1.getTimeMillis()));
    +-
    +-        assertEquals("TEST", e0.getText(80));
    +-        assertEquals(null, e1.getText(80));
    +-        assertEquals(-1, getEntrySize(e1));
    +-
    +-        e0.close();
    +-        e1.close();
    +-
    +-        // Wait a second and write another entry -- old ones should be expunged
    +-        Thread.sleep(2000);
    +-        dropbox.addText("DropBoxTest", "TEST1");
    +-
    +-        e0 = dropbox.getNextEntry(null, before);
    +-        assertTrue(null == dropbox.getNextEntry(null, e0.getTimeMillis()));
    +-        assertEquals("TEST1", e0.getText(80));
    +-        e0.close();
    +-    }
    +-
    +-    public void testFileCountLimits() throws Exception {
    +-        File dir = getEmptyDir("testFileCountLimits");
    +-
    +-        DropBoxManagerService service = new DropBoxManagerService(getContext(), dir);
    +-        DropBoxManager dropbox = new DropBoxManager(getContext(), service.getServiceStub());
    +-        dropbox.addText("DropBoxTest", "TEST0");
    +-        dropbox.addText("DropBoxTest", "TEST1");
    +-        dropbox.addText("DropBoxTest", "TEST2");
    +-        dropbox.addText("DropBoxTest", "TEST3");
    +-        dropbox.addText("DropBoxTest", "TEST4");
    +-        dropbox.addText("DropBoxTest", "TEST5");
    +-
    +-        // Verify 6 files added
    +-        DropBoxManager.Entry e0 = dropbox.getNextEntry(null, 0);
    +-        DropBoxManager.Entry e1 = dropbox.getNextEntry(null, e0.getTimeMillis());
    +-        DropBoxManager.Entry e2 = dropbox.getNextEntry(null, e1.getTimeMillis());
    +-        DropBoxManager.Entry e3 = dropbox.getNextEntry(null, e2.getTimeMillis());
    +-        DropBoxManager.Entry e4 = dropbox.getNextEntry(null, e3.getTimeMillis());
    +-        DropBoxManager.Entry e5 = dropbox.getNextEntry(null, e4.getTimeMillis());
    +-        assertTrue(null == dropbox.getNextEntry(null, e5.getTimeMillis()));
    +-        assertEquals("TEST0", e0.getText(80));
    +-        assertEquals("TEST5", e5.getText(80));
    +-
    +-        e0.close();
    +-        e1.close();
    +-        e2.close();
    +-        e3.close();
    +-        e4.close();
    +-        e5.close();
    +-
    +-        // Limit to 3 files and add one more entry
    +-        ContentResolver cr = getContext().getContentResolver();
    +-        Settings.Global.putString(cr, Settings.Global.DROPBOX_MAX_FILES, "3");
    +-        dropbox.addText("DropBoxTest", "TEST6");
    +-
    +-        // Verify only 3 files left
    +-        DropBoxManager.Entry f0 = dropbox.getNextEntry(null, 0);
    +-        DropBoxManager.Entry f1 = dropbox.getNextEntry(null, f0.getTimeMillis());
    +-        DropBoxManager.Entry f2 = dropbox.getNextEntry(null, f1.getTimeMillis());
    +-        assertTrue(null == dropbox.getNextEntry(null, f2.getTimeMillis()));
    +-        assertEquals("TEST4", f0.getText(80));
    +-        assertEquals("TEST5", f1.getText(80));
    +-        assertEquals("TEST6", f2.getText(80));
    +-
    +-        f0.close();
    +-        f1.close();
    +-        f2.close();
    +-    }
    +-
    +-    public void testCreateDropBoxManagerWithInvalidDirectory() throws Exception {
    +-        // If created with an invalid directory, the DropBoxManager should suffer quietly
    +-        // and fail all operations (this is how it survives a full disk).
    +-        // Once the directory becomes possible to create, it will start working.
    +-
    +-        File dir = new File(getEmptyDir("testCreateDropBoxManagerWith"), "InvalidDirectory");
    +-        new FileOutputStream(dir).close();  // Create an empty file
    +-        DropBoxManagerService service = new DropBoxManagerService(getContext(), dir);
    +-        DropBoxManager dropbox = new DropBoxManager(getContext(), service.getServiceStub());
    +-
    +-        dropbox.addText("DropBoxTest", "should be ignored");
    +-        dropbox.addData("DropBoxTest", "should be ignored".getBytes(), 0);
    +-        assertTrue(null == dropbox.getNextEntry("DropBoxTest", 0));
    +-
    +-        dir.delete();  // Remove the file so a directory can be created
    +-        dropbox.addText("DropBoxTest", "TEST");
    +-        DropBoxManager.Entry e = dropbox.getNextEntry("DropBoxTest", 0);
    +-        assertTrue(null == dropbox.getNextEntry("DropBoxTest", e.getTimeMillis()));
    +-        assertEquals("DropBoxTest", e.getTag());
    +-        assertEquals("TEST", e.getText(80));
    +-        e.close();
    +-    }
    +-
    +-    public void testDropBoxEntrySerialization() throws Exception {
    +-        // Make sure DropBoxManager.Entry can be serialized to a Parcel and back
    +-        // under a variety of conditions.
    +-
    +-        Parcel parcel = Parcel.obtain();
    +-        File dir = getEmptyDir("testDropBoxEntrySerialization");
    +-
    +-        new DropBoxManager.Entry("empty", 1000000).writeToParcel(parcel, 0);
    +-        new DropBoxManager.Entry("string", 2000000, "String Value").writeToParcel(parcel, 0);
    +-        new DropBoxManager.Entry("bytes", 3000000, "Bytes Value".getBytes(),
    +-                DropBoxManager.IS_TEXT).writeToParcel(parcel, 0);
    +-        new DropBoxManager.Entry("zerobytes", 4000000, new byte[0], 0).writeToParcel(parcel, 0);
    +-        new DropBoxManager.Entry("emptybytes", 5000000, (byte[]) null,
    +-                DropBoxManager.IS_EMPTY).writeToParcel(parcel, 0);
    +-
    +-        try {
    +-            new DropBoxManager.Entry("badbytes", 99999,
    +-                    "Bad Bytes Value".getBytes(),
    +-                    DropBoxManager.IS_EMPTY).writeToParcel(parcel, 0);
    +-            fail("IllegalArgumentException expected for non-null byte[] and IS_EMPTY flags");
    +-        } catch (IllegalArgumentException e) {
    +-            // expected
    +-        }
    +-
    +-        try {
    +-            new DropBoxManager.Entry("badbytes", 99999, (byte[]) null, 0).writeToParcel(parcel, 0);
    +-            fail("IllegalArgumentException expected for null byte[] and non-IS_EMPTY flags");
    +-        } catch (IllegalArgumentException e) {
    +-            // expected
    +-        }
    +-
    +-        File f = new File(dir, "file.dat");
    +-        FileOutputStream os = new FileOutputStream(f);
    +-        os.write("File Value".getBytes());
    +-        os.close();
    +-
    +-        new DropBoxManager.Entry("file", 6000000, f, DropBoxManager.IS_TEXT).writeToParcel(
    +-                parcel, Parcelable.PARCELABLE_WRITE_RETURN_VALUE);
    +-        new DropBoxManager.Entry("binfile", 7000000, f, 0).writeToParcel(
    +-                parcel, Parcelable.PARCELABLE_WRITE_RETURN_VALUE);
    +-        new DropBoxManager.Entry("emptyfile", 8000000, (ParcelFileDescriptor) null,
    +-                DropBoxManager.IS_EMPTY).writeToParcel(parcel, 0);
    +-
    +-        try {
    +-            new DropBoxManager.Entry("badfile", 99999, new File(dir, "nonexist.dat"), 0);
    +-            fail("IOException expected for nonexistent file");
    +-        } catch (IOException e) {
    +-            // expected
    +-        }
    +-
    +-        try {
    +-            new DropBoxManager.Entry("badfile", 99999, f, DropBoxManager.IS_EMPTY).writeToParcel(
    +-                    parcel, 0);
    +-            fail("IllegalArgumentException expected for non-null file and IS_EMPTY flags");
    +-        } catch (IllegalArgumentException e) {
    +-            // expected
    +-        }
    +-
    +-        try {
    +-            new DropBoxManager.Entry("badfile", 99999, (ParcelFileDescriptor) null, 0);
    +-            fail("IllegalArgumentException expected for null PFD and non-IS_EMPTY flags");
    +-        } catch (IllegalArgumentException e) {
    +-            // expected
    +-        }
    +-
    +-        File gz = new File(dir, "file.gz");
    +-        GZIPOutputStream gzout = new GZIPOutputStream(new FileOutputStream(gz));
    +-        gzout.write("Gzip File Value".getBytes());
    +-        gzout.close();
    +-
    +-        new DropBoxManager.Entry("gzipfile", 9000000, gz,
    +-                DropBoxManager.IS_TEXT | DropBoxManager.IS_GZIPPED).writeToParcel(
    +-                    parcel, Parcelable.PARCELABLE_WRITE_RETURN_VALUE);
    +-        new DropBoxManager.Entry("gzipbinfile", 10000000, gz,
    +-                DropBoxManager.IS_GZIPPED).writeToParcel(
    +-                    parcel, Parcelable.PARCELABLE_WRITE_RETURN_VALUE);
    +-
    +-        //
    +-        // Switch from writing to reading
    +-        //
    +-
    +-        parcel.setDataPosition(0);
    +-        DropBoxManager.Entry e;
    +-
    +-        e = DropBoxManager.Entry.CREATOR.createFromParcel(parcel);
    +-        assertEquals("empty", e.getTag());
    +-        assertEquals(1000000, e.getTimeMillis());
    +-        assertEquals(DropBoxManager.IS_EMPTY, e.getFlags());
    +-        assertEquals(null, e.getText(100));
    +-        assertEquals(null, e.getInputStream());
    +-        e.close();
    +-
    +-        e = DropBoxManager.Entry.CREATOR.createFromParcel(parcel);
    +-        assertEquals("string", e.getTag());
    +-        assertEquals(2000000, e.getTimeMillis());
    +-        assertEquals(DropBoxManager.IS_TEXT, e.getFlags());
    +-        assertEquals("String Value", e.getText(100));
    +-        assertEquals("String Value",
    +-                new BufferedReader(new InputStreamReader(e.getInputStream())).readLine());
    +-        e.close();
    +-
    +-        e = DropBoxManager.Entry.CREATOR.createFromParcel(parcel);
    +-        assertEquals("bytes", e.getTag());
    +-        assertEquals(3000000, e.getTimeMillis());
    +-        assertEquals(DropBoxManager.IS_TEXT, e.getFlags());
    +-        assertEquals("Bytes Value", e.getText(100));
    +-        e.close();
    +-
    +-        e = DropBoxManager.Entry.CREATOR.createFromParcel(parcel);
    +-        assertEquals("zerobytes", e.getTag());
    +-        assertEquals(4000000, e.getTimeMillis());
    +-        assertEquals(0, e.getFlags());
    +-        assertEquals(null, e.getText(100));
    +-        assertEquals(null,
    +-                new BufferedReader(new InputStreamReader(e.getInputStream())).readLine());
    +-        e.close();
    +-
    +-        e = DropBoxManager.Entry.CREATOR.createFromParcel(parcel);
    +-        assertEquals("emptybytes", e.getTag());
    +-        assertEquals(5000000, e.getTimeMillis());
    +-        assertEquals(DropBoxManager.IS_EMPTY, e.getFlags());
    +-        assertEquals(null, e.getText(100));
    +-        assertEquals(null, e.getInputStream());
    +-        e.close();
    +-
    +-        e = DropBoxManager.Entry.CREATOR.createFromParcel(parcel);
    +-        assertEquals("file", e.getTag());
    +-        assertEquals(6000000, e.getTimeMillis());
    +-        assertEquals(DropBoxManager.IS_TEXT, e.getFlags());
    +-        assertEquals("File Value", e.getText(100));
    +-        e.close();
    +-
    +-        e = DropBoxManager.Entry.CREATOR.createFromParcel(parcel);
    +-        assertEquals("binfile", e.getTag());
    +-        assertEquals(7000000, e.getTimeMillis());
    +-        assertEquals(0, e.getFlags());
    +-        assertEquals(null, e.getText(100));
    +-        assertEquals("File Value",
    +-                new BufferedReader(new InputStreamReader(e.getInputStream())).readLine());
    +-        e.close();
    +-        e = DropBoxManager.Entry.CREATOR.createFromParcel(parcel);
    +-        assertEquals("emptyfile", e.getTag());
    +-        assertEquals(8000000, e.getTimeMillis());
    +-        assertEquals(DropBoxManager.IS_EMPTY, e.getFlags());
    +-        assertEquals(null, e.getText(100));
    +-        assertEquals(null, e.getInputStream());
    +-        e.close();
    +-
    +-        e = DropBoxManager.Entry.CREATOR.createFromParcel(parcel);
    +-        assertEquals("gzipfile", e.getTag());
    +-        assertEquals(9000000, e.getTimeMillis());
    +-        assertEquals(DropBoxManager.IS_TEXT, e.getFlags());
    +-        assertEquals("Gzip File Value", e.getText(100));
    +-        e.close();
    +-
    +-        e = DropBoxManager.Entry.CREATOR.createFromParcel(parcel);
    +-        assertEquals("gzipbinfile", e.getTag());
    +-        assertEquals(10000000, e.getTimeMillis());
    +-        assertEquals(0, e.getFlags());
    +-        assertEquals(null, e.getText(100));
    +-        assertEquals("Gzip File Value",
    +-                new BufferedReader(new InputStreamReader(e.getInputStream())).readLine());
    +-        e.close();
    +-        assertEquals(0, parcel.dataAvail());
    +-        parcel.recycle();
    +-    }
    +-
    +-    public void testDropBoxEntrySerializationDoesntLeakFileDescriptors() throws Exception {
    +-        File dir = getEmptyDir("testDropBoxEntrySerialization");
    +-        File f = new File(dir, "file.dat");
    +-        FileOutputStream os = new FileOutputStream(f);
    +-        os.write("File Value".getBytes());
    +-        os.close();
    +-
    +-        int before = countOpenFiles();
    +-        assertTrue(before > 0);
    +-
    +-        for (int i = 0; i < 1000; i++) {
    +-            Parcel parcel = Parcel.obtain();
    +-            new DropBoxManager.Entry("file", 1000000, f, 0).writeToParcel(
    +-                    parcel, Parcelable.PARCELABLE_WRITE_RETURN_VALUE);
    +-
    +-            parcel.setDataPosition(0);
    +-            DropBoxManager.Entry e = DropBoxManager.Entry.CREATOR.createFromParcel(parcel);
    +-            assertEquals("file", e.getTag());
    +-            e.close();
    +-
    +-            parcel.recycle();
    +-        }
    +-
    +-        int after = countOpenFiles();
    +-        assertTrue(after > 0);
    +-        assertTrue(after < before + 20);
    +-    }
    +-
    +-    private void addRandomEntry(DropBoxManager dropbox, String tag, int size) throws Exception {
    +-        byte[] bytes = new byte[size];
    +-        new Random(System.currentTimeMillis()).nextBytes(bytes);
    +-
    +-        File f = new File(getEmptyDir("addRandomEntry"), "random.dat");
    +-        FileOutputStream os = new FileOutputStream(f);
    +-        os.write(bytes);
    +-        os.close();
    +-
    +-        dropbox.addFile(tag, f, 0);
    +-    }
    +-
    +-    private int getEntrySize(DropBoxManager.Entry e) throws Exception {
    +-        InputStream is = e.getInputStream();
    +-        if (is == null) return -1;
    +-        int length = 0;
    +-        while (is.read() != -1) length++;
    +-        return length;
    +-    }
    +-
    +-    private void recursiveDelete(File file) {
    +-        if (!file.delete() && file.isDirectory()) {
    +-            for (File f : file.listFiles()) recursiveDelete(f);
    +-            file.delete();
    +-        }
    +-    }
    +-
    +-    private File getEmptyDir(String name) {
    +-        File dir = getContext().getDir("DropBoxTest." + name, 0);
    +-        for (File f : dir.listFiles()) recursiveDelete(f);
    +-        assertTrue(dir.listFiles().length == 0);
    +-        return dir;
    +-    }
    +-
    +-    private int countOpenFiles() {
    +-        return new File("/proc/" + Process.myPid() + "/fd").listFiles().length;
    +-    }
    +-}
    +diff --git a/services/tests/servicestests/src/com/android/server/EntropyMixerTest.java b/services/tests/servicestests/src/com/android/server/EntropyMixerTest.java
    +deleted file mode 100644
    +index 50e7a03..0000000
    +--- a/services/tests/servicestests/src/com/android/server/EntropyMixerTest.java
    ++++ /dev/null
    +@@ -1,41 +0,0 @@
    +-/*
    +- * Copyright (C) 2010 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 com.android.server;
    +-
    +-import android.content.Context;
    +-import android.os.FileUtils;
    +-import android.test.AndroidTestCase;
    +-
    +-import java.io.File;
    +-
    +-/**
    +- * Tests for {@link com.android.server.EntropyMixer}
    +- */
    +-public class EntropyMixerTest extends AndroidTestCase {
    +-
    +-    public void testInitialWrite() throws Exception {
    +-        File dir = getContext().getDir("testInitialWrite", Context.MODE_PRIVATE);
    +-        File file = File.createTempFile("testInitialWrite", "dat", dir);
    +-        file.deleteOnExit();
    +-        assertEquals(0, FileUtils.readTextFile(file, 0, null).length());
    +-
    +-        // The constructor has the side effect of writing to file
    +-        new EntropyMixer(getContext(), "/dev/null", file.getCanonicalPath(), "/dev/null");
    +-
    +-        assertTrue(FileUtils.readTextFile(file, 0, null).length() > 0);
    +-    }
    +-}
    +diff --git a/services/tests/servicestests/src/com/android/server/LockSettingsStorageTests.java b/services/tests/servicestests/src/com/android/server/LockSettingsStorageTests.java
    +deleted file mode 100644
    +index 7d28e39..0000000
    +--- a/services/tests/servicestests/src/com/android/server/LockSettingsStorageTests.java
    ++++ /dev/null
    +@@ -1,357 +0,0 @@
    +-/*
    +- * Copyright (C) 2014 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 com.android.server;
    +-
    +-import android.content.Context;
    +-import android.content.ContextWrapper;
    +-import android.content.pm.UserInfo;
    +-import android.database.sqlite.SQLiteDatabase;
    +-import android.os.FileUtils;
    +-import android.os.UserManager;
    +-import android.test.AndroidTestCase;
    +-
    +-import java.io.File;
    +-import java.util.ArrayList;
    +-import java.util.Arrays;
    +-import java.util.List;
    +-import java.util.concurrent.CountDownLatch;
    +-
    +-public class LockSettingsStorageTests extends AndroidTestCase {
    +-    LockSettingsStorage mStorage;
    +-    File mStorageDir;
    +-
    +-    private File mDb;
    +-
    +-    @Override
    +-    protected void setUp() throws Exception {
    +-        super.setUp();
    +-        mStorageDir = new File(getContext().getFilesDir(), "locksettings");
    +-        mDb = getContext().getDatabasePath("locksettings.db");
    +-
    +-        assertTrue(mStorageDir.exists() || mStorageDir.mkdirs());
    +-        assertTrue(FileUtils.deleteContents(mStorageDir));
    +-        assertTrue(!mDb.exists() || mDb.delete());
    +-
    +-        final Context ctx = getContext();
    +-        setContext(new ContextWrapper(ctx) {
    +-            @Override
    +-            public Object getSystemService(String name) {
    +-                if (USER_SERVICE.equals(name)) {
    +-                    return new UserManager(ctx, null) {
    +-                        @Override
    +-                        public UserInfo getProfileParent(int userHandle) {
    +-                            if (userHandle == 2) {
    +-                                // User 2 is a profile of user 1.
    +-                                return new UserInfo(1, "name", 0);
    +-                            }
    +-                            if (userHandle == 3) {
    +-                                // User 3 is a profile of user 0.
    +-                                return new UserInfo(0, "name", 0);
    +-                            }
    +-                            return null;
    +-                        }
    +-                    };
    +-                }
    +-                return super.getSystemService(name);
    +-            }
    +-        });
    +-
    +-        mStorage = new LockSettingsStorage(getContext(), new LockSettingsStorage.Callback() {
    +-            @Override
    +-            public void initialize(SQLiteDatabase db) {
    +-                mStorage.writeKeyValue(db, "initializedKey", "initialValue", 0);
    +-            }
    +-        }) {
    +-            @Override
    +-            String getLockPatternFilename(int userId) {
    +-                return new File(mStorageDir,
    +-                        super.getLockPatternFilename(userId).replace('/', '-')).getAbsolutePath();
    +-            }
    +-
    +-            @Override
    +-            String getLockPasswordFilename(int userId) {
    +-                return new File(mStorageDir,
    +-                        super.getLockPasswordFilename(userId).replace('/', '-')).getAbsolutePath();
    +-            }
    +-
    +-            @Override
    +-            String getChildProfileLockFile(int userId) {
    +-                return new File(mStorageDir,
    +-                        super.getChildProfileLockFile(userId).replace('/', '-')).getAbsolutePath();
    +-            }
    +-        };
    +-    }
    +-
    +-    @Override
    +-    protected void tearDown() throws Exception {
    +-        super.tearDown();
    +-        mStorage.closeDatabase();
    +-    }
    +-
    +-    public void testKeyValue_InitializeWorked() {
    +-        assertEquals("initialValue", mStorage.readKeyValue("initializedKey", "default", 0));
    +-        mStorage.clearCache();
    +-        assertEquals("initialValue", mStorage.readKeyValue("initializedKey", "default", 0));
    +-    }
    +-
    +-    public void testKeyValue_WriteThenRead() {
    +-        mStorage.writeKeyValue("key", "value", 0);
    +-        assertEquals("value", mStorage.readKeyValue("key", "default", 0));
    +-        mStorage.clearCache();
    +-        assertEquals("value", mStorage.readKeyValue("key", "default", 0));
    +-    }
    +-
    +-    public void testKeyValue_DefaultValue() {
    +-        assertEquals("default", mStorage.readKeyValue("unititialized key", "default", 0));
    +-        assertEquals("default2", mStorage.readKeyValue("unititialized key", "default2", 0));
    +-    }
    +-
    +-    public void testKeyValue_Concurrency() {
    +-        final Object monitor = new Object();
    +-        List<Thread> threads = new ArrayList<>();
    +-        for (int i = 0; i < 100; i++) {
    +-            final int threadId = i;
    +-            threads.add(new Thread() {
    +-                @Override
    +-                public void run() {
    +-                    synchronized (monitor) {
    +-                        try {
    +-                            monitor.wait();
    +-                        } catch (InterruptedException e) {
    +-                            return;
    +-                        }
    +-                        mStorage.writeKeyValue("key", "1 from thread " + threadId, 0);
    +-                        mStorage.readKeyValue("key", "default", 0);
    +-                        mStorage.writeKeyValue("key", "2 from thread " + threadId, 0);
    +-                        mStorage.readKeyValue("key", "default", 0);
    +-                        mStorage.writeKeyValue("key", "3 from thread " + threadId, 0);
    +-                        mStorage.readKeyValue("key", "default", 0);
    +-                        mStorage.writeKeyValue("key", "4 from thread " + threadId, 0);
    +-                        mStorage.readKeyValue("key", "default", 0);
    +-                        mStorage.writeKeyValue("key", "5 from thread " + threadId, 0);
    +-                        mStorage.readKeyValue("key", "default", 0);
    +-                    }
    +-                }
    +-            });
    +-            threads.get(i).start();
    +-        }
    +-        mStorage.writeKeyValue("key", "initalValue", 0);
    +-        synchronized (monitor) {
    +-            monitor.notifyAll();
    +-        }
    +-        for (int i = 0; i < threads.size(); i++) {
    +-            try {
    +-                threads.get(i).join();
    +-            } catch (InterruptedException e) {
    +-            }
    +-        }
    +-        assertEquals('5', mStorage.readKeyValue("key", "default", 0).charAt(0));
    +-        mStorage.clearCache();
    +-        assertEquals('5', mStorage.readKeyValue("key", "default", 0).charAt(0));
    +-    }
    +-
    +-    public void testKeyValue_CacheStarvedWriter() {
    +-        final CountDownLatch latch = new CountDownLatch(1);
    +-        List<Thread> threads = new ArrayList<>();
    +-        for (int i = 0; i < 100; i++) {
    +-            final int threadId = i;
    +-            threads.add(new Thread() {
    +-                @Override
    +-                public void run() {
    +-                    try {
    +-                        latch.await();
    +-                    } catch (InterruptedException e) {
    +-                        return;
    +-                    }
    +-                    if (threadId == 50) {
    +-                        mStorage.writeKeyValue("starvedWriterKey", "value", 0);
    +-                    } else {
    +-                        mStorage.readKeyValue("starvedWriterKey", "default", 0);
    +-                    }
    +-                }
    +-            });
    +-            threads.get(i).start();
    +-        }
    +-        latch.countDown();
    +-        for (int i = 0; i < threads.size(); i++) {
    +-            try {
    +-                threads.get(i).join();
    +-            } catch (InterruptedException e) {
    +-            }
    +-        }
    +-        String cached = mStorage.readKeyValue("key", "default", 0);
    +-        mStorage.clearCache();
    +-        String storage = mStorage.readKeyValue("key", "default", 0);
    +-        assertEquals("Cached value didn't match stored value", storage, cached);
    +-    }
    +-
    +-    public void testRemoveUser() {
    +-        mStorage.writeKeyValue("key", "value", 0);
    +-        mStorage.writePasswordHash(new byte[]{1}, 0);
    +-        mStorage.writePatternHash(new byte[]{2}, 0);
    +-
    +-        mStorage.writeKeyValue("key", "value", 1);
    +-        mStorage.writePasswordHash(new byte[]{1}, 1);
    +-        mStorage.writePatternHash(new byte[]{2}, 1);
    +-
    +-        mStorage.removeUser(0);
    +-
    +-        assertEquals("value", mStorage.readKeyValue("key", "default", 1));
    +-        assertEquals("default", mStorage.readKeyValue("key", "default", 0));
    +-        assertNotNull(mStorage.readPasswordHash(1));
    +-        assertNull(mStorage.readPasswordHash(0));
    +-        assertNotNull(mStorage.readPatternHash(1));
    +-        assertNull(mStorage.readPatternHash(0));
    +-    }
    +-
    +-    public void testPassword_Default() {
    +-        assertNull(mStorage.readPasswordHash(0));
    +-    }
    +-
    +-    public void testPassword_Write() {
    +-        mStorage.writePasswordHash("thepassword".getBytes(), 0);
    +-
    +-        assertArrayEquals("thepassword".getBytes(), mStorage.readPasswordHash(0).hash);
    +-        mStorage.clearCache();
    +-        assertArrayEquals("thepassword".getBytes(), mStorage.readPasswordHash(0).hash);
    +-    }
    +-
    +-    public void testPassword_WriteProfileWritesParent() {
    +-        mStorage.writePasswordHash("parentpasswordd".getBytes(), 1);
    +-        mStorage.writePasswordHash("profilepassword".getBytes(), 2);
    +-
    +-        assertArrayEquals("profilepassword".getBytes(), mStorage.readPasswordHash(1).hash);
    +-        assertArrayEquals("profilepassword".getBytes(), mStorage.readPasswordHash(2).hash);
    +-        mStorage.clearCache();
    +-        assertArrayEquals("profilepassword".getBytes(), mStorage.readPasswordHash(1).hash);
    +-        assertArrayEquals("profilepassword".getBytes(), mStorage.readPasswordHash(2).hash);
    +-    }
    +-
    +-    public void testLockType_WriteProfileWritesParent() {
    +-        mStorage.writePasswordHash("parentpassword".getBytes(), 10);
    +-        mStorage.writePatternHash("12345678".getBytes(), 20);
    +-
    +-        assertEquals(2, mStorage.getStoredCredentialType(10));
    +-        assertEquals(1, mStorage.getStoredCredentialType(20));
    +-        mStorage.clearCache();
    +-        assertEquals(2, mStorage.getStoredCredentialType(10));
    +-        assertEquals(1, mStorage.getStoredCredentialType(20));
    +-    }
    +-
    +-    public void testProfileLock_ReadWriteChildProfileLock() {
    +-        assertFalse(mStorage.hasChildProfileLock(20));
    +-        mStorage.writeChildProfileLock(20, "profilepassword".getBytes());
    +-        assertArrayEquals("profilepassword".getBytes(), mStorage.readChildProfileLock(20));
    +-        assertTrue(mStorage.hasChildProfileLock(20));
    +-        mStorage.clearCache();
    +-        assertArrayEquals("profilepassword".getBytes(), mStorage.readChildProfileLock(20));
    +-        assertTrue(mStorage.hasChildProfileLock(20));
    +-    }
    +-
    +-    public void testPassword_WriteParentWritesProfile() {
    +-        mStorage.writePasswordHash("profilepassword".getBytes(), 2);
    +-        mStorage.writePasswordHash("parentpasswordd".getBytes(), 1);
    +-
    +-        assertArrayEquals("parentpasswordd".getBytes(), mStorage.readPasswordHash(1).hash);
    +-        assertArrayEquals("parentpasswordd".getBytes(), mStorage.readPasswordHash(2).hash);
    +-        mStorage.clearCache();
    +-        assertArrayEquals("parentpasswordd".getBytes(), mStorage.readPasswordHash(1).hash);
    +-        assertArrayEquals("parentpasswordd".getBytes(), mStorage.readPasswordHash(2).hash);
    +-    }
    +-
    +-    public void testPattern_Default() {
    +-        assertNull(mStorage.readPasswordHash(0));
    +-    }
    +-
    +-    public void testPattern_Write() {
    +-        mStorage.writePatternHash("thepattern".getBytes(), 0);
    +-
    +-        assertArrayEquals("thepattern".getBytes(), mStorage.readPatternHash(0).hash);
    +-        mStorage.clearCache();
    +-        assertArrayEquals("thepattern".getBytes(), mStorage.readPatternHash(0).hash);
    +-    }
    +-
    +-    public void testPattern_WriteProfileWritesParent() {
    +-        mStorage.writePatternHash("parentpatternn".getBytes(), 1);
    +-        mStorage.writePatternHash("profilepattern".getBytes(), 2);
    +-
    +-        assertArrayEquals("profilepattern".getBytes(), mStorage.readPatternHash(1).hash);
    +-        assertArrayEquals("profilepattern".getBytes(), mStorage.readPatternHash(2).hash);
    +-        mStorage.clearCache();
    +-        assertArrayEquals("profilepattern".getBytes(), mStorage.readPatternHash(1).hash);
    +-        assertArrayEquals("profilepattern".getBytes(), mStorage.readPatternHash(2).hash);
    +-    }
    +-
    +-    public void testPattern_WriteParentWritesProfile() {
    +-        mStorage.writePatternHash("profilepattern".getBytes(), 2);
    +-        mStorage.writePatternHash("parentpatternn".getBytes(), 1);
    +-
    +-        assertArrayEquals("parentpatternn".getBytes(), mStorage.readPatternHash(1).hash);
    +-        assertArrayEquals("parentpatternn".getBytes(), mStorage.readPatternHash(2).hash);
    +-        mStorage.clearCache();
    +-        assertArrayEquals("parentpatternn".getBytes(), mStorage.readPatternHash(1).hash);
    +-        assertArrayEquals("parentpatternn".getBytes(), mStorage.readPatternHash(2).hash);
    +-    }
    +-
    +-    public void testPrefetch() {
    +-        mStorage.writeKeyValue("key", "toBeFetched", 0);
    +-        mStorage.writePatternHash("pattern".getBytes(), 0);
    +-        mStorage.writePasswordHash("password".getBytes(), 0);
    +-
    +-        mStorage.clearCache();
    +-        mStorage.prefetchUser(0);
    +-
    +-        assertEquals("toBeFetched", mStorage.readKeyValue("key", "default", 0));
    +-        assertArrayEquals("pattern".getBytes(), mStorage.readPatternHash(0).hash);
    +-        assertArrayEquals("password".getBytes(), mStorage.readPasswordHash(0).hash);
    +-    }
    +-
    +-    public void testFileLocation_Owner() {
    +-        LockSettingsStorage storage = new LockSettingsStorage(getContext(), null);
    +-
    +-        assertEquals("/data/system/gesture.key", storage.getLockPatternFilename(0));
    +-        assertEquals("/data/system/password.key", storage.getLockPasswordFilename(0));
    +-    }
    +-
    +-    public void testFileLocation_SecondaryUser() {
    +-        LockSettingsStorage storage = new LockSettingsStorage(getContext(), null);
    +-
    +-        assertEquals("/data/system/users/1/gesture.key", storage.getLockPatternFilename(1));
    +-        assertEquals("/data/system/users/1/password.key", storage.getLockPasswordFilename(1));
    +-    }
    +-
    +-    public void testFileLocation_ProfileToSecondary() {
    +-        LockSettingsStorage storage = new LockSettingsStorage(getContext(), null);
    +-
    +-        assertEquals("/data/system/users/1/gesture.key", storage.getLockPatternFilename(2));
    +-        assertEquals("/data/system/users/1/password.key", storage.getLockPasswordFilename(2));
    +-    }
    +-
    +-    public void testFileLocation_ProfileToOwner() {
    +-        LockSettingsStorage storage = new LockSettingsStorage(getContext(), null);
    +-
    +-        assertEquals("/data/system/gesture.key", storage.getLockPatternFilename(3));
    +-        assertEquals("/data/system/password.key", storage.getLockPasswordFilename(3));
    +-    }
    +-
    +-    private static void assertArrayEquals(byte[] expected, byte[] actual) {
    +-        if (!Arrays.equals(expected, actual)) {
    +-            fail("expected:<" + Arrays.toString(expected) +
    +-                    "> but was:<" + Arrays.toString(actual) + ">");
    +-        }
    +-    }
    +-}
    +diff --git a/services/tests/servicestests/src/com/android/server/MockAccessibilityService.java b/services/tests/servicestests/src/com/android/server/MockAccessibilityService.java
    +deleted file mode 100644
    +index e1c5cee..0000000
    +--- a/services/tests/servicestests/src/com/android/server/MockAccessibilityService.java
    ++++ /dev/null
    +@@ -1,256 +0,0 @@
    +-/*
    +- * Copyright (C) 2010 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 com.android.server;
    +-
    +-import android.accessibilityservice.AccessibilityService;
    +-import android.accessibilityservice.AccessibilityServiceInfo;
    +-import android.content.Intent;
    +-import android.os.Message;
    +-import android.view.accessibility.AccessibilityEvent;
    +-
    +-import java.util.Iterator;
    +-import java.util.LinkedList;
    +-import java.util.List;
    +-import java.util.Queue;
    +-
    +-import junit.framework.TestCase;
    +-
    +-/**
    +- * This is the base class for mock {@link AccessibilityService}s.
    +- */
    +-public abstract class MockAccessibilityService extends AccessibilityService {
    +-
    +-    /**
    +-     * The event this service expects to receive.
    +-     */
    +-    private final Queue<AccessibilityEvent> mExpectedEvents = new LinkedList<AccessibilityEvent>();
    +-
    +-    /**
    +-     * Interruption call this service expects to receive.
    +-     */
    +-    private boolean mExpectedInterrupt;
    +-
    +-    /**
    +-     * Flag if the mock is currently replaying.
    +-     */
    +-    private boolean mReplaying;
    +-
    +-    /**
    +-     * Flag if the system is bound as a client to this service.
    +-     */
    +-    private boolean mIsSystemBoundAsClient;
    +-
    +-    /**
    +-     * Creates an {@link AccessibilityServiceInfo} populated with default
    +-     * values.
    +-     *
    +-     * @return The default info.
    +-     */
    +-    public static AccessibilityServiceInfo createDefaultInfo() {
    +-        AccessibilityServiceInfo defaultInfo = new AccessibilityServiceInfo();
    +-        defaultInfo.eventTypes = AccessibilityEvent.TYPE_ANNOUNCEMENT;
    +-        defaultInfo.feedbackType = AccessibilityServiceInfo.FEEDBACK_AUDIBLE;
    +-        defaultInfo.flags = 0;
    +-        defaultInfo.notificationTimeout = 0;
    +-        defaultInfo.packageNames = new String[] {
    +-            "foo.bar.baz"
    +-        };
    +-
    +-        return defaultInfo;
    +-    }
    +-
    +-    /**
    +-     * Starts replaying the mock.
    +-     */
    +-    public void replay() {
    +-        mReplaying = true;
    +-    }
    +-
    +-    /**
    +-     * Verifies if all expected service methods have been called.
    +-     */
    +-    public void verify() {
    +-        if (!mReplaying) {
    +-            throw new IllegalStateException("Did you forget to call replay()");
    +-        }
    +-
    +-        if (mExpectedInterrupt) {
    +-            throw new IllegalStateException("Expected call to #interrupt() not received");
    +-        }
    +-        if (!mExpectedEvents.isEmpty()) {
    +-            throw new IllegalStateException("Expected a call to onAccessibilityEvent() for "
    +-                    + "events \"" + mExpectedEvents + "\" not received");
    +-        }
    +-    }
    +-
    +-    /**
    +-     * Resets this instance so it can be reused.
    +-     */
    +-    public void reset() {
    +-        mExpectedEvents.clear();
    +-        mExpectedInterrupt = false;
    +-        mReplaying = false;
    +-    }
    +-
    +-    /**
    +-     * Sets an expected call to
    +-     * {@link #onAccessibilityEvent(AccessibilityEvent)} with given event as
    +-     * argument.
    +-     *
    +-     * @param expectedEvent The expected event argument.
    +-     */
    +-    public void expectEvent(AccessibilityEvent expectedEvent) {
    +-        mExpectedEvents.add(expectedEvent);
    +-    }
    +-
    +-    /**
    +-     * Sets an expected call of {@link #onInterrupt()}.
    +-     */
    +-    public void expectInterrupt() {
    +-        mExpectedInterrupt = true;
    +-    }
    +-
    +-    @Override
    +-    public void onAccessibilityEvent(AccessibilityEvent receivedEvent) {
    +-        if (!mReplaying) {
    +-            return;
    +-        }
    +-
    +-        if (mExpectedEvents.isEmpty()) {
    +-            throw new IllegalStateException("Unexpected event: " + receivedEvent);
    +-        }
    +-
    +-        AccessibilityEvent expectedEvent = mExpectedEvents.poll();
    +-        assertEqualsAccessiblityEvent(expectedEvent, receivedEvent);
    +-    }
    +-
    +-    @Override
    +-    public void onInterrupt() {
    +-        if (!mReplaying) {
    +-            return;
    +-        }
    +-
    +-        if (!mExpectedInterrupt) {
    +-            throw new IllegalStateException("Unexpected call to onInterrupt()");
    +-        }
    +-
    +-        mExpectedInterrupt = false;
    +-    }
    +-
    +-    @Override
    +-    protected void onServiceConnected() {
    +-        mIsSystemBoundAsClient = true;
    +-    }
    +-
    +-    @Override
    +-    public boolean onUnbind(Intent intent) {
    +-        mIsSystemBoundAsClient = false;
    +-        return false;
    +-    }
    +-
    +-    /**
    +-     * Returns if the system is bound as client to this service.
    +-     *
    +-     * @return True if the system is bound, false otherwise.
    +-     */
    +-    public boolean isSystemBoundAsClient() {
    +-        return mIsSystemBoundAsClient;
    +-    }
    +-
    +-    /**
    +-     * Compares all properties of the <code>expectedEvent</code> and the
    +-     * <code>receviedEvent</code> to verify that the received event is the one
    +-     * that is expected.
    +-     */
    +-    private void assertEqualsAccessiblityEvent(AccessibilityEvent expectedEvent,
    +-            AccessibilityEvent receivedEvent) {
    +-        TestCase.assertEquals("addedCount has incorrect value", expectedEvent.getAddedCount(),
    +-                receivedEvent.getAddedCount());
    +-        TestCase.assertEquals("beforeText has incorrect value", expectedEvent.getBeforeText(),
    +-                receivedEvent.getBeforeText());
    +-        TestCase.assertEquals("checked has incorrect value", expectedEvent.isChecked(),
    +-                receivedEvent.isChecked());
    +-        TestCase.assertEquals("className has incorrect value", expectedEvent.getClassName(),
    +-                receivedEvent.getClassName());
    +-        TestCase.assertEquals("contentDescription has incorrect value", expectedEvent
    +-                .getContentDescription(), receivedEvent.getContentDescription());
    +-        TestCase.assertEquals("currentItemIndex has incorrect value", expectedEvent
    +-                .getCurrentItemIndex(), receivedEvent.getCurrentItemIndex());
    +-        TestCase.assertEquals("enabled has incorrect value", expectedEvent.isEnabled(),
    +-                receivedEvent.isEnabled());
    +-        TestCase.assertEquals("eventType has incorrect value", expectedEvent.getEventType(),
    +-                receivedEvent.getEventType());
    +-        TestCase.assertEquals("fromIndex has incorrect value", expectedEvent.getFromIndex(),
    +-                receivedEvent.getFromIndex());
    +-        TestCase.assertEquals("fullScreen has incorrect value", expectedEvent.isFullScreen(),
    +-                receivedEvent.isFullScreen());
    +-        TestCase.assertEquals("itemCount has incorrect value", expectedEvent.getItemCount(),
    +-                receivedEvent.getItemCount());
    +-        assertEqualsNotificationAsParcelableData(expectedEvent, receivedEvent);
    +-        TestCase.assertEquals("password has incorrect value", expectedEvent.isPassword(),
    +-                receivedEvent.isPassword());
    +-        TestCase.assertEquals("removedCount has incorrect value", expectedEvent.getRemovedCount(),
    +-                receivedEvent.getRemovedCount());
    +-        assertEqualsText(expectedEvent, receivedEvent);
    +-    }
    +-
    +-    /**
    +-     * Compares the {@link android.os.Parcelable} data of the
    +-     * <code>expectedEvent</code> and <code>receivedEvent</code> to verify that
    +-     * the received event is the one that is expected.
    +-     */
    +-    private void assertEqualsNotificationAsParcelableData(AccessibilityEvent expectedEvent,
    +-            AccessibilityEvent receivedEvent) {
    +-        String message = "parcelableData has incorrect value";
    +-        Message expectedMessage = (Message) expectedEvent.getParcelableData();
    +-        Message receivedMessage = (Message) receivedEvent.getParcelableData();
    +-
    +-        if (expectedMessage == null) {
    +-            if (receivedMessage == null) {
    +-                return;
    +-            }
    +-        }
    +-
    +-        TestCase.assertNotNull(message, receivedMessage);
    +-
    +-        // we do a very simple sanity check since we do not test Message
    +-        TestCase.assertEquals(message, expectedMessage.what, receivedMessage.what);
    +-    }
    +-
    +-    /**
    +-     * Compares the text of the <code>expectedEvent</code> and
    +-     * <code>receivedEvent</code> by comparing the string representation of the
    +-     * corresponding {@link CharSequence}s.
    +-     */
    +-    private void assertEqualsText(AccessibilityEvent expectedEvent,
    +-            AccessibilityEvent receivedEvent) {
    +-        String message = "text has incorrect value";
    +-        List<CharSequence> expectedText = expectedEvent.getText();
    +-        List<CharSequence> receivedText = receivedEvent.getText();
    +-
    +-        TestCase.assertEquals(message, expectedText.size(), receivedText.size());
    +-
    +-        Iterator<CharSequence> expectedTextIterator = expectedText.iterator();
    +-        Iterator<CharSequence> receivedTextIterator = receivedText.iterator();
    +-
    +-        for (int i = 0; i < expectedText.size(); i++) {
    +-            // compare the string representation
    +-            TestCase.assertEquals(message, expectedTextIterator.next().toString(),
    +-                    receivedTextIterator.next().toString());
    +-        }
    +-    }
    +-}
    +diff --git a/services/tests/servicestests/src/com/android/server/MountServiceTests.java b/services/tests/servicestests/src/com/android/server/MountServiceTests.java
    +deleted file mode 100644
    +index ecfe0db..0000000
    +--- a/services/tests/servicestests/src/com/android/server/MountServiceTests.java
    ++++ /dev/null
    +@@ -1,274 +0,0 @@
    +-/*
    +- * Copyright (C) 2010 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 com.android.server;
    +-
    +-import android.content.Context;
    +-import android.content.res.Resources;
    +-import android.content.res.Resources.NotFoundException;
    +-import android.os.FileUtils;
    +-import android.os.storage.OnObbStateChangeListener;
    +-import android.os.storage.StorageManager;
    +-import android.test.AndroidTestCase;
    +-import android.test.ComparisonFailure;
    +-import android.test.suitebuilder.annotation.LargeTest;
    +-import android.util.Log;
    +-
    +-import com.android.frameworks.servicestests.R;
    +-
    +-import java.io.File;
    +-import java.io.InputStream;
    +-
    +-public class MountServiceTests extends AndroidTestCase {
    +-    private static final String TAG = "MountServiceTests";
    +-
    +-    private static final long MAX_WAIT_TIME = 25*1000;
    +-    private static final long WAIT_TIME_INCR = 5*1000;
    +-
    +-    private static final String OBB_MOUNT_PREFIX = "/mnt/obb/";
    +-
    +-    private static void assertStartsWith(String message, String prefix, String actual) {
    +-        if (!actual.startsWith(prefix)) {
    +-            throw new ComparisonFailure(message, prefix, actual);
    +-        }
    +-    }
    +-
    +-    private static class ObbObserver extends OnObbStateChangeListener {
    +-        private String path;
    +-
    +-        public int state = -1;
    +-        boolean done = false;
    +-
    +-        @Override
    +-        public void onObbStateChange(String path, int state) {
    +-            Log.d(TAG, "Received message.  path=" + path + ", state=" + state);
    +-            synchronized (this) {
    +-                this.path = path;
    +-                this.state = state;
    +-                done = true;
    +-                notifyAll();
    +-            }
    +-        }
    +-
    +-        public String getPath() {
    +-            assertTrue("Expected ObbObserver to have received a state change.", done);
    +-            return path;
    +-        }
    +-
    +-        public int getState() {
    +-            assertTrue("Expected ObbObserver to have received a state change.", done);
    +-            return state;
    +-        }
    +-
    +-        public void reset() {
    +-            this.path = null;
    +-            this.state = -1;
    +-            done = false;
    +-        }
    +-
    +-        public boolean isDone() {
    +-            return done;
    +-        }
    +-
    +-        public boolean waitForCompletion() {
    +-            long waitTime = 0;
    +-            synchronized (this) {
    +-                while (!isDone() && waitTime < MAX_WAIT_TIME) {
    +-                    try {
    +-                        wait(WAIT_TIME_INCR);
    +-                        waitTime += WAIT_TIME_INCR;
    +-                    } catch (InterruptedException e) {
    +-                        Log.i(TAG, "Interrupted during sleep", e);
    +-                    }
    +-                }
    +-            }
    +-
    +-            return isDone();
    +-        }
    +-    }
    +-
    +-    private File getFilePath(String name) {
    +-        final File filesDir = mContext.getFilesDir();
    +-        final File outFile = new File(filesDir, name);
    +-        return outFile;
    +-    }
    +-
    +-    private void copyRawToFile(int rawResId, File outFile) {
    +-        Resources res = mContext.getResources();
    +-        InputStream is = null;
    +-        try {
    +-            is = res.openRawResource(rawResId);
    +-        } catch (NotFoundException e) {
    +-            fail("Failed to load resource with id: " + rawResId);
    +-        }
    +-        FileUtils.setPermissions(outFile.getPath(), FileUtils.S_IRWXU | FileUtils.S_IRWXG
    +-                | FileUtils.S_IRWXO, -1, -1);
    +-        assertTrue(FileUtils.copyToFile(is, outFile));
    +-        FileUtils.setPermissions(outFile.getPath(), FileUtils.S_IRWXU | FileUtils.S_IRWXG
    +-                | FileUtils.S_IRWXO, -1, -1);
    +-    }
    +-
    +-    private StorageManager getStorageManager() {
    +-        return (StorageManager) getContext().getSystemService(Context.STORAGE_SERVICE);
    +-    }
    +-
    +-    private void mountObb(StorageManager sm, final int resource, final File file,
    +-            int expectedState) {
    +-        copyRawToFile(resource, file);
    +-
    +-        final ObbObserver observer = new ObbObserver();
    +-        assertTrue("mountObb call on " + file.getPath() + " should succeed",
    +-                sm.mountObb(file.getPath(), null, observer));
    +-
    +-        assertTrue("Mount should have completed",
    +-                observer.waitForCompletion());
    +-
    +-        if (expectedState == OnObbStateChangeListener.MOUNTED) {
    +-            assertTrue("OBB should be mounted", sm.isObbMounted(file.getPath()));
    +-        }
    +-
    +-        assertEquals("Actual file and resolved file should be the same",
    +-                file.getPath(), observer.getPath());
    +-
    +-        assertEquals(expectedState, observer.getState());
    +-    }
    +-
    +-    private ObbObserver mountObbWithoutWait(final StorageManager sm, final int resource,
    +-            final File file) {
    +-        copyRawToFile(resource, file);
    +-
    +-        final ObbObserver observer = new ObbObserver();
    +-        assertTrue("mountObb call on " + file.getPath() + " should succeed", sm.mountObb(file
    +-                .getPath(), null, observer));
    +-
    +-        return observer;
    +-    }
    +-
    +-    private void waitForObbActionCompletion(final StorageManager sm, final File file,
    +-            final ObbObserver observer, int expectedState, boolean checkPath) {
    +-        assertTrue("Mount should have completed", observer.waitForCompletion());
    +-
    +-        assertTrue("OBB should be mounted", sm.isObbMounted(file.getPath()));
    +-
    +-        if (checkPath) {
    +-            assertEquals("Actual file and resolved file should be the same", file.getPath(),
    +-                    observer.getPath());
    +-        }
    +-
    +-        assertEquals(expectedState, observer.getState());
    +-    }
    +-
    +-    private String checkMountedPath(final StorageManager sm, final File file) {
    +-        final String mountPath = sm.getMountedObbPath(file.getPath());
    +-        assertStartsWith("Path should be in " + OBB_MOUNT_PREFIX,
    +-                OBB_MOUNT_PREFIX,
    +-                mountPath);
    +-        return mountPath;
    +-    }
    +-
    +-    private void unmountObb(final StorageManager sm, final File file, int expectedState) {
    +-        final ObbObserver observer = new ObbObserver();
    +-
    +-        assertTrue("unmountObb call on test1.obb should succeed",
    +-                sm.unmountObb(file.getPath(), false, observer));
    +-
    +-        assertTrue("Unmount should have completed",
    +-                observer.waitForCompletion());
    +-
    +-        assertEquals(expectedState, observer.getState());
    +-
    +-        if (expectedState == OnObbStateChangeListener.UNMOUNTED) {
    +-            assertFalse("OBB should not be mounted", sm.isObbMounted(file.getPath()));
    +-        }
    +-    }
    +-
    +-    @LargeTest
    +-    public void testMountAndUnmountObbNormal() {
    +-        StorageManager sm = getStorageManager();
    +-
    +-        final File outFile = getFilePath("test1.obb");
    +-
    +-        mountObb(sm, R.raw.test1, outFile, OnObbStateChangeListener.MOUNTED);
    +-
    +-        mountObb(sm, R.raw.test1, outFile, OnObbStateChangeListener.ERROR_ALREADY_MOUNTED);
    +-
    +-        final String mountPath = checkMountedPath(sm, outFile);
    +-        final File mountDir = new File(mountPath);
    +-
    +-        assertTrue("OBB mounted path should be a directory",
    +-                mountDir.isDirectory());
    +-
    +-        unmountObb(sm, outFile, OnObbStateChangeListener.UNMOUNTED);
    +-    }
    +-
    +-    @LargeTest
    +-    public void testAttemptMountNonObb() {
    +-        StorageManager sm = getStorageManager();
    +-
    +-        final File outFile = getFilePath("test1_nosig.obb");
    +-
    +-        mountObb(sm, R.raw.test1_nosig, outFile, OnObbStateChangeListener.ERROR_INTERNAL);
    +-
    +-        assertFalse("OBB should not be mounted",
    +-                sm.isObbMounted(outFile.getPath()));
    +-
    +-        assertNull("OBB's mounted path should be null",
    +-                sm.getMountedObbPath(outFile.getPath()));
    +-    }
    +-
    +-    @LargeTest
    +-    public void testAttemptMountObbWrongPackage() {
    +-        StorageManager sm = getStorageManager();
    +-
    +-        final File outFile = getFilePath("test1_wrongpackage.obb");
    +-
    +-        mountObb(sm, R.raw.test1_wrongpackage, outFile,
    +-                OnObbStateChangeListener.ERROR_PERMISSION_DENIED);
    +-
    +-        assertFalse("OBB should not be mounted",
    +-                sm.isObbMounted(outFile.getPath()));
    +-
    +-        assertNull("OBB's mounted path should be null",
    +-                sm.getMountedObbPath(outFile.getPath()));
    +-    }
    +-
    +-    @LargeTest
    +-    public void testMountAndUnmountTwoObbs() {
    +-        StorageManager sm = getStorageManager();
    +-
    +-        final File file1 = getFilePath("test1.obb");
    +-        final File file2 = getFilePath("test2.obb");
    +-
    +-        ObbObserver oo1 = mountObbWithoutWait(sm, R.raw.test1, file1);
    +-        ObbObserver oo2 = mountObbWithoutWait(sm, R.raw.test1, file2);
    +-
    +-        Log.d(TAG, "Waiting for OBB #1 to complete mount");
    +-        waitForObbActionCompletion(sm, file1, oo1, OnObbStateChangeListener.MOUNTED, false);
    +-        Log.d(TAG, "Waiting for OBB #2 to complete mount");
    +-        waitForObbActionCompletion(sm, file2, oo2, OnObbStateChangeListener.MOUNTED, false);
    +-
    +-        final String mountPath1 = checkMountedPath(sm, file1);
    +-        final File mountDir1 = new File(mountPath1);
    +-        assertTrue("OBB mounted path should be a directory", mountDir1.isDirectory());
    +-
    +-        final String mountPath2 = checkMountedPath(sm, file2);
    +-        final File mountDir2 = new File(mountPath2);
    +-        assertTrue("OBB mounted path should be a directory", mountDir2.isDirectory());
    +-
    +-        unmountObb(sm, file1, OnObbStateChangeListener.UNMOUNTED);
    +-        unmountObb(sm, file2, OnObbStateChangeListener.UNMOUNTED);
    +-    }
    +-}
    +diff --git a/services/tests/servicestests/src/com/android/server/NativeDaemonConnectorTest.java b/services/tests/servicestests/src/com/android/server/NativeDaemonConnectorTest.java
    +deleted file mode 100644
    +index e2253a2..0000000
    +--- a/services/tests/servicestests/src/com/android/server/NativeDaemonConnectorTest.java
    ++++ /dev/null
    +@@ -1,97 +0,0 @@
    +-/*
    +- * Copyright (C) 2011 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 com.android.server;
    +-
    +-import static com.android.server.NativeDaemonConnector.appendEscaped;
    +-import static com.android.server.NativeDaemonConnector.makeCommand;
    +-
    +-import android.test.AndroidTestCase;
    +-import android.test.suitebuilder.annotation.MediumTest;
    +-
    +-import com.android.server.NativeDaemonConnector.SensitiveArg;
    +-
    +-/**
    +- * Tests for {@link NativeDaemonConnector}.
    +- */
    +-@MediumTest
    +-public class NativeDaemonConnectorTest extends AndroidTestCase {
    +-    private static final String TAG = "NativeDaemonConnectorTest";
    +-
    +-    public void testArgumentNormal() throws Exception {
    +-        final StringBuilder builder = new StringBuilder();
    +-
    +-        builder.setLength(0);
    +-        appendEscaped(builder, "");
    +-        assertEquals("", builder.toString());
    +-
    +-        builder.setLength(0);
    +-        appendEscaped(builder, "foo");
    +-        assertEquals("foo", builder.toString());
    +-
    +-        builder.setLength(0);
    +-        appendEscaped(builder, "foo\"bar");
    +-        assertEquals("foo\\\"bar", builder.toString());
    +-
    +-        builder.setLength(0);
    +-        appendEscaped(builder, "foo\\bar\\\"baz");
    +-        assertEquals("foo\\\\bar\\\\\\\"baz", builder.toString());
    +-    }
    +-
    +-    public void testArgumentWithSpaces() throws Exception {
    +-        final StringBuilder builder = new StringBuilder();
    +-
    +-        builder.setLength(0);
    +-        appendEscaped(builder, "foo bar");
    +-        assertEquals("\"foo bar\"", builder.toString());
    +-
    +-        builder.setLength(0);
    +-        appendEscaped(builder, "foo\"bar\\baz foo");
    +-        assertEquals("\"foo\\\"bar\\\\baz foo\"", builder.toString());
    +-    }
    +-
    +-    public void testArgumentWithUtf() throws Exception {
    +-        final StringBuilder builder = new StringBuilder();
    +-
    +-        builder.setLength(0);
    +-        appendEscaped(builder, "caf\u00E9 c\u00F6ffee");
    +-        assertEquals("\"caf\u00E9 c\u00F6ffee\"", builder.toString());
    +-    }
    +-
    +-    public void testSensitiveArgs() throws Exception {
    +-        final StringBuilder rawBuilder = new StringBuilder();
    +-        final StringBuilder logBuilder = new StringBuilder();
    +-
    +-        rawBuilder.setLength(0);
    +-        logBuilder.setLength(0);
    +-        makeCommand(rawBuilder, logBuilder, 1, "foo", "bar", "baz");
    +-        assertEquals("1 foo bar baz\0", rawBuilder.toString());
    +-        assertEquals("1 foo bar baz", logBuilder.toString());
    +-
    +-        rawBuilder.setLength(0);
    +-        logBuilder.setLength(0);
    +-        makeCommand(rawBuilder, logBuilder, 1, "foo", new SensitiveArg("bar"), "baz");
    +-        assertEquals("1 foo bar baz\0", rawBuilder.toString());
    +-        assertEquals("1 foo [scrubbed] baz", logBuilder.toString());
    +-
    +-        rawBuilder.setLength(0);
    +-        logBuilder.setLength(0);
    +-        makeCommand(rawBuilder, logBuilder, 1, "foo", new SensitiveArg("foo bar"), "baz baz",
    +-                new SensitiveArg("wat"));
    +-        assertEquals("1 foo \"foo bar\" \"baz baz\" wat\0", rawBuilder.toString());
    +-        assertEquals("1 foo [scrubbed] \"baz baz\" [scrubbed]", logBuilder.toString());
    +-    }
    +-}
    +diff --git a/services/tests/servicestests/src/com/android/server/NetworkManagementServiceTest.java b/services/tests/servicestests/src/com/android/server/NetworkManagementServiceTest.java
    +deleted file mode 100644
    +index 0d5daa5..0000000
    +--- a/services/tests/servicestests/src/com/android/server/NetworkManagementServiceTest.java
    ++++ /dev/null
    +@@ -1,226 +0,0 @@
    +-/*
    +- * Copyright (C) 2012 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 com.android.server;
    +-
    +-import android.content.Context;
    +-import android.net.LinkAddress;
    +-import android.net.LocalSocket;
    +-import android.net.LocalServerSocket;
    +-import android.os.Binder;
    +-import android.test.AndroidTestCase;
    +-import android.test.suitebuilder.annotation.LargeTest;
    +-import com.android.server.net.BaseNetworkObserver;
    +-
    +-import static org.mockito.Mockito.doReturn;
    +-import static org.mockito.Mockito.mock;
    +-import static org.mockito.Mockito.reset;
    +-import static org.mockito.Mockito.timeout;
    +-import static org.mockito.Mockito.verify;
    +-import static org.mockito.Mockito.verifyNoMoreInteractions;
    +-
    +-import java.io.IOException;
    +-import java.io.OutputStream;
    +-
    +-/**
    +- * Tests for {@link NetworkManagementService}.
    +- */
    +-@LargeTest
    +-public class NetworkManagementServiceTest extends AndroidTestCase {
    +-
    +-    private static final String SOCKET_NAME = "__test__NetworkManagementServiceTest";
    +-    private NetworkManagementService mNMService;
    +-    private LocalServerSocket mServerSocket;
    +-    private LocalSocket mSocket;
    +-    private OutputStream mOutputStream;
    +-
    +-    @Override
    +-    public void setUp() throws Exception {
    +-        super.setUp();
    +-        // TODO: make this unnecessary. runtest might already make it unnecessary.
    +-        System.setProperty("dexmaker.dexcache", getContext().getCacheDir().toString());
    +-
    +-        // Set up a sheltered test environment.
    +-        BroadcastInterceptingContext context = new BroadcastInterceptingContext(getContext());
    +-        mServerSocket = new LocalServerSocket(SOCKET_NAME);
    +-
    +-        // Start the service and wait until it connects to our socket.
    +-        mNMService = NetworkManagementService.create(context, SOCKET_NAME);
    +-        mSocket = mServerSocket.accept();
    +-        mOutputStream = mSocket.getOutputStream();
    +-    }
    +-
    +-    @Override
    +-    public void tearDown() throws Exception {
    +-        if (mSocket != null) mSocket.close();
    +-        if (mServerSocket != null) mServerSocket.close();
    +-        super.tearDown();
    +-    }
    +-
    +-    /**
    +-     * Sends a message on the netd socket and gives the events some time to make it back.
    +-     */
    +-    private void sendMessage(String message) throws IOException {
    +-        // Strings are null-terminated, so add "\0" at the end.
    +-        mOutputStream.write((message + "\0").getBytes());
    +-    }
    +-
    +-    private static <T> T expectSoon(T mock) {
    +-        return verify(mock, timeout(100));
    +-    }
    +-
    +-    /**
    +-     * Tests that network observers work properly.
    +-     */
    +-    public void testNetworkObservers() throws Exception {
    +-        BaseNetworkObserver observer = mock(BaseNetworkObserver.class);
    +-        doReturn(new Binder()).when(observer).asBinder();  // Used by registerObserver.
    +-        mNMService.registerObserver(observer);
    +-
    +-        // Forget everything that happened to the mock so far, so we can explicitly verify
    +-        // everything that happens and does not happen to it from now on.
    +-        reset(observer);
    +-
    +-        // Now send NetworkManagementService messages and ensure that the observer methods are
    +-        // called. After every valid message we expect a callback soon after; to ensure that
    +-        // invalid messages don't cause any callbacks, we call verifyNoMoreInteractions at the end.
    +-
    +-        /**
    +-         * Interface changes.
    +-         */
    +-        sendMessage("600 Iface added rmnet12");
    +-        expectSoon(observer).interfaceAdded("rmnet12");
    +-
    +-        sendMessage("600 Iface removed eth1");
    +-        expectSoon(observer).interfaceRemoved("eth1");
    +-
    +-        sendMessage("607 Iface removed eth1");
    +-        // Invalid code.
    +-
    +-        sendMessage("600 Iface borked lo down");
    +-        // Invalid event.
    +-
    +-        sendMessage("600 Iface changed clat4 up again");
    +-        // Extra tokens.
    +-
    +-        sendMessage("600 Iface changed clat4 up");
    +-        expectSoon(observer).interfaceStatusChanged("clat4", true);
    +-
    +-        sendMessage("600 Iface linkstate rmnet0 down");
    +-        expectSoon(observer).interfaceLinkStateChanged("rmnet0", false);
    +-
    +-        sendMessage("600 IFACE linkstate clat4 up");
    +-        // Invalid group.
    +-
    +-        /**
    +-         * Bandwidth control events.
    +-         */
    +-        sendMessage("601 limit alert data rmnet_usb0");
    +-        expectSoon(observer).limitReached("data", "rmnet_usb0");
    +-
    +-        sendMessage("601 invalid alert data rmnet0");
    +-        // Invalid group.
    +-
    +-        sendMessage("601 limit increased data rmnet0");
    +-        // Invalid event.
    +-
    +-
    +-        /**
    +-         * Interface class activity.
    +-         */
    +-
    +-        sendMessage("613 IfaceClass active rmnet0");
    +-        expectSoon(observer).interfaceClassDataActivityChanged("rmnet0", true, 0);
    +-
    +-        sendMessage("613 IfaceClass active rmnet0 1234");
    +-        expectSoon(observer).interfaceClassDataActivityChanged("rmnet0", true, 1234);
    +-
    +-        sendMessage("613 IfaceClass idle eth0");
    +-        expectSoon(observer).interfaceClassDataActivityChanged("eth0", false, 0);
    +-
    +-        sendMessage("613 IfaceClass idle eth0 1234");
    +-        expectSoon(observer).interfaceClassDataActivityChanged("eth0", false, 1234);
    +-
    +-        sendMessage("613 IfaceClass reallyactive rmnet0 1234");
    +-        expectSoon(observer).interfaceClassDataActivityChanged("rmnet0", false, 1234);
    +-
    +-        sendMessage("613 InterfaceClass reallyactive rmnet0");
    +-        // Invalid group.
    +-
    +-
    +-        /**
    +-         * IP address changes.
    +-         */
    +-        sendMessage("614 Address updated fe80::1/64 wlan0 128 253");
    +-        expectSoon(observer).addressUpdated("wlan0", new LinkAddress("fe80::1/64", 128, 253));
    +-
    +-        // There is no "added", so we take this as "removed".
    +-        sendMessage("614 Address added fe80::1/64 wlan0 128 253");
    +-        expectSoon(observer).addressRemoved("wlan0", new LinkAddress("fe80::1/64", 128, 253));
    +-
    +-        sendMessage("614 Address removed 2001:db8::1/64 wlan0 1 0");
    +-        expectSoon(observer).addressRemoved("wlan0", new LinkAddress("2001:db8::1/64", 1, 0));
    +-
    +-        sendMessage("614 Address removed 2001:db8::1/64 wlan0 1");
    +-        // Not enough arguments.
    +-
    +-        sendMessage("666 Address removed 2001:db8::1/64 wlan0 1 0");
    +-        // Invalid code.
    +-
    +-
    +-        /**
    +-         * DNS information broadcasts.
    +-         */
    +-        sendMessage("615 DnsInfo servers rmnet_usb0 3600 2001:db8::1");
    +-        expectSoon(observer).interfaceDnsServerInfo("rmnet_usb0", 3600,
    +-                new String[]{"2001:db8::1"});
    +-
    +-        sendMessage("615 DnsInfo servers wlan0 14400 2001:db8::1,2001:db8::2");
    +-        expectSoon(observer).interfaceDnsServerInfo("wlan0", 14400,
    +-                new String[]{"2001:db8::1", "2001:db8::2"});
    +-
    +-        // We don't check for negative lifetimes, only for parse errors.
    +-        sendMessage("615 DnsInfo servers wlan0 -3600 ::1");
    +-        expectSoon(observer).interfaceDnsServerInfo("wlan0", -3600,
    +-                new String[]{"::1"});
    +-
    +-        sendMessage("615 DnsInfo servers wlan0 SIXHUNDRED ::1");
    +-        // Non-numeric lifetime.
    +-
    +-        sendMessage("615 DnsInfo servers wlan0 2001:db8::1");
    +-        // Missing lifetime.
    +-
    +-        sendMessage("615 DnsInfo servers wlan0 3600");
    +-        // No servers.
    +-
    +-        sendMessage("615 DnsInfo servers 3600 wlan0 2001:db8::1,2001:db8::2");
    +-        // Non-numeric lifetime.
    +-
    +-        sendMessage("615 DnsInfo wlan0 7200 2001:db8::1,2001:db8::2");
    +-        // Invalid tokens.
    +-
    +-        sendMessage("666 DnsInfo servers wlan0 5400 2001:db8::1");
    +-        // Invalid code.
    +-
    +-        // No syntax checking on the addresses.
    +-        sendMessage("615 DnsInfo servers wlan0 600 ,::,,foo,::1,");
    +-        expectSoon(observer).interfaceDnsServerInfo("wlan0", 600,
    +-                new String[]{"", "::", "", "foo", "::1"});
    +-
    +-        // Make sure nothing else was called.
    +-        verifyNoMoreInteractions(observer);
    +-    }
    +-}
    +diff --git a/services/tests/servicestests/src/com/android/server/NetworkPolicyManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/NetworkPolicyManagerServiceTest.java
    +deleted file mode 100644
    +index 541be3d..0000000
    +--- a/services/tests/servicestests/src/com/android/server/NetworkPolicyManagerServiceTest.java
    ++++ /dev/null
    +@@ -1,1014 +0,0 @@
    +-/*
    +- * Copyright (C) 2011 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 com.android.server;
    +-
    +-import static android.content.Intent.ACTION_UID_REMOVED;
    +-import static android.content.Intent.EXTRA_UID;
    +-import static android.net.ConnectivityManager.CONNECTIVITY_ACTION;
    +-import static android.net.ConnectivityManager.TYPE_WIFI;
    +-import static android.net.NetworkPolicy.CYCLE_NONE;
    +-import static android.net.NetworkPolicy.LIMIT_DISABLED;
    +-import static android.net.NetworkPolicy.WARNING_DISABLED;
    +-import static android.net.NetworkPolicyManager.POLICY_NONE;
    +-import static android.net.NetworkPolicyManager.POLICY_REJECT_METERED_BACKGROUND;
    +-import static android.net.NetworkPolicyManager.RULE_ALLOW_ALL;
    +-import static android.net.NetworkPolicyManager.RULE_REJECT_METERED;
    +-import static android.net.NetworkPolicyManager.computeLastCycleBoundary;
    +-import static android.net.NetworkPolicyManager.computeNextCycleBoundary;
    +-import static android.net.TrafficStats.KB_IN_BYTES;
    +-import static android.net.TrafficStats.MB_IN_BYTES;
    +-import static android.text.format.DateUtils.DAY_IN_MILLIS;
    +-import static android.text.format.DateUtils.MINUTE_IN_MILLIS;
    +-import static android.text.format.Time.TIMEZONE_UTC;
    +-import static com.android.server.net.NetworkPolicyManagerService.TYPE_LIMIT;
    +-import static com.android.server.net.NetworkPolicyManagerService.TYPE_LIMIT_SNOOZED;
    +-import static com.android.server.net.NetworkPolicyManagerService.TYPE_WARNING;
    +-import static org.easymock.EasyMock.anyInt;
    +-import static org.easymock.EasyMock.anyLong;
    +-import static org.easymock.EasyMock.aryEq;
    +-import static org.easymock.EasyMock.capture;
    +-import static org.easymock.EasyMock.createMock;
    +-import static org.easymock.EasyMock.eq;
    +-import static org.easymock.EasyMock.expect;
    +-import static org.easymock.EasyMock.expectLastCall;
    +-import static org.easymock.EasyMock.isA;
    +-
    +-import android.app.IActivityManager;
    +-import android.app.INotificationManager;
    +-import android.app.IProcessObserver;
    +-import android.app.Notification;
    +-import android.content.Intent;
    +-import android.content.pm.PackageInfo;
    +-import android.content.pm.PackageManager;
    +-import android.content.pm.Signature;
    +-import android.net.ConnectivityManager;
    +-import android.net.IConnectivityManager;
    +-import android.net.INetworkManagementEventObserver;
    +-import android.net.INetworkPolicyListener;
    +-import android.net.INetworkStatsService;
    +-import android.net.LinkProperties;
    +-import android.net.NetworkInfo;
    +-import android.net.NetworkInfo.DetailedState;
    +-import android.net.NetworkPolicy;
    +-import android.net.NetworkState;
    +-import android.net.NetworkStats;
    +-import android.net.NetworkTemplate;
    +-import android.os.Binder;
    +-import android.os.INetworkManagementService;
    +-import android.os.MessageQueue.IdleHandler;
    +-import android.os.UserHandle;
    +-import android.test.AndroidTestCase;
    +-import android.test.mock.MockPackageManager;
    +-import android.test.suitebuilder.annotation.LargeTest;
    +-import android.test.suitebuilder.annotation.Suppress;
    +-import android.text.format.Time;
    +-import android.util.TrustedTime;
    +-
    +-import com.android.server.net.NetworkPolicyManagerService;
    +-import com.google.common.util.concurrent.AbstractFuture;
    +-
    +-import org.easymock.Capture;
    +-import org.easymock.EasyMock;
    +-import org.easymock.IAnswer;
    +-
    +-import java.io.File;
    +-import java.util.Calendar;
    +-import java.util.LinkedHashSet;
    +-import java.util.TimeZone;
    +-import java.util.concurrent.ExecutionException;
    +-import java.util.concurrent.Future;
    +-import java.util.concurrent.TimeUnit;
    +-import java.util.concurrent.TimeoutException;
    +-import java.util.logging.Handler;
    +-
    +-import libcore.io.IoUtils;
    +-
    +-/**
    +- * Tests for {@link NetworkPolicyManagerService}.
    +- */
    +-@LargeTest
    +-public class NetworkPolicyManagerServiceTest extends AndroidTestCase {
    +-    private static final String TAG = "NetworkPolicyManagerServiceTest";
    +-
    +-    private static final long TEST_START = 1194220800000L;
    +-    private static final String TEST_IFACE = "test0";
    +-    private static final String TEST_SSID = "AndroidAP";
    +-
    +-    private static NetworkTemplate sTemplateWifi = NetworkTemplate.buildTemplateWifi(TEST_SSID);
    +-
    +-    private BroadcastInterceptingContext mServiceContext;
    +-    private File mPolicyDir;
    +-
    +-    private IActivityManager mActivityManager;
    +-    private INetworkStatsService mStatsService;
    +-    private INetworkManagementService mNetworkManager;
    +-    private INetworkPolicyListener mPolicyListener;
    +-    private TrustedTime mTime;
    +-    private IConnectivityManager mConnManager;
    +-    private INotificationManager mNotifManager;
    +-
    +-    private NetworkPolicyManagerService mService;
    +-    private IProcessObserver mProcessObserver;
    +-    private INetworkManagementEventObserver mNetworkObserver;
    +-
    +-    private Binder mStubBinder = new Binder();
    +-
    +-    private long mStartTime;
    +-    private long mElapsedRealtime;
    +-
    +-    private static final int USER_ID = 0;
    +-
    +-    private static final int APP_ID_A = android.os.Process.FIRST_APPLICATION_UID + 800;
    +-    private static final int APP_ID_B = android.os.Process.FIRST_APPLICATION_UID + 801;
    +-
    +-    private static final int UID_A = UserHandle.getUid(USER_ID, APP_ID_A);
    +-    private static final int UID_B = UserHandle.getUid(USER_ID, APP_ID_B);
    +-
    +-    private static final int PID_1 = 400;
    +-    private static final int PID_2 = 401;
    +-    private static final int PID_3 = 402;
    +-
    +-    public void _setUp() throws Exception {
    +-        super.setUp();
    +-
    +-        setCurrentTimeMillis(TEST_START);
    +-
    +-        // intercept various broadcasts, and pretend that uids have packages
    +-        mServiceContext = new BroadcastInterceptingContext(getContext()) {
    +-            @Override
    +-            public PackageManager getPackageManager() {
    +-                return new MockPackageManager() {
    +-                    @Override
    +-                    public String[] getPackagesForUid(int uid) {
    +-                        return new String[] { "com.example" };
    +-                    }
    +-
    +-                    @Override
    +-                    public PackageInfo getPackageInfo(String packageName, int flags) {
    +-                        final PackageInfo info = new PackageInfo();
    +-                        final Signature signature;
    +-                        if ("android".equals(packageName)) {
    +-                            signature = new Signature("F00D");
    +-                        } else {
    +-                            signature = new Signature("DEAD");
    +-                        }
    +-                        info.signatures = new Signature[] { signature };
    +-                        return info;
    +-                    }
    +-
    +-                };
    +-            }
    +-
    +-            @Override
    +-            public void startActivity(Intent intent) {
    +-                // ignored
    +-            }
    +-        };
    +-
    +-        mPolicyDir = getContext().getFilesDir();
    +-        if (mPolicyDir.exists()) {
    +-            IoUtils.deleteContents(mPolicyDir);
    +-        }
    +-
    +-        mActivityManager = createMock(IActivityManager.class);
    +-        mStatsService = createMock(INetworkStatsService.class);
    +-        mNetworkManager = createMock(INetworkManagementService.class);
    +-        mPolicyListener = createMock(INetworkPolicyListener.class);
    +-        mTime = createMock(TrustedTime.class);
    +-        mConnManager = createMock(IConnectivityManager.class);
    +-        mNotifManager = createMock(INotificationManager.class);
    +-
    +-        mService = new NetworkPolicyManagerService(mServiceContext, mActivityManager,
    +-                mStatsService, mNetworkManager, mTime, mPolicyDir, true);
    +-        mService.bindConnectivityManager(mConnManager);
    +-        mService.bindNotificationManager(mNotifManager);
    +-
    +-        // RemoteCallbackList needs a binder to use as key
    +-        expect(mPolicyListener.asBinder()).andReturn(mStubBinder).atLeastOnce();
    +-        replay();
    +-        mService.registerListener(mPolicyListener);
    +-        verifyAndReset();
    +-
    +-        // catch IProcessObserver during systemReady()
    +-        final Capture<IProcessObserver> processObserver = new Capture<IProcessObserver>();
    +-        mActivityManager.registerProcessObserver(capture(processObserver));
    +-        expectLastCall().atLeastOnce();
    +-
    +-        // catch INetworkManagementEventObserver during systemReady()
    +-        final Capture<INetworkManagementEventObserver> networkObserver = new Capture<
    +-                INetworkManagementEventObserver>();
    +-        mNetworkManager.registerObserver(capture(networkObserver));
    +-        expectLastCall().atLeastOnce();
    +-
    +-        expect(mNetworkManager.isBandwidthControlEnabled()).andReturn(true).atLeastOnce();
    +-        expectCurrentTime();
    +-
    +-        replay();
    +-        mService.systemReady();
    +-        verifyAndReset();
    +-
    +-        mProcessObserver = processObserver.getValue();
    +-        mNetworkObserver = networkObserver.getValue();
    +-
    +-    }
    +-
    +-    public void _tearDown() throws Exception {
    +-        for (File file : mPolicyDir.listFiles()) {
    +-            file.delete();
    +-        }
    +-
    +-        mServiceContext = null;
    +-        mPolicyDir = null;
    +-
    +-        mActivityManager = null;
    +-        mStatsService = null;
    +-        mPolicyListener = null;
    +-        mTime = null;
    +-
    +-        mService = null;
    +-        mProcessObserver = null;
    +-
    +-        super.tearDown();
    +-    }
    +-
    +-    @Suppress
    +-    public void testPolicyChangeTriggersBroadcast() throws Exception {
    +-        mService.setUidPolicy(APP_ID_A, POLICY_NONE);
    +-
    +-        // change background policy and expect broadcast
    +-        final Future<Intent> backgroundChanged = mServiceContext.nextBroadcastIntent(
    +-                ConnectivityManager.ACTION_BACKGROUND_DATA_SETTING_CHANGED);
    +-
    +-        mService.setUidPolicy(APP_ID_A, POLICY_REJECT_METERED_BACKGROUND);
    +-
    +-        backgroundChanged.get();
    +-    }
    +-
    +-    @Suppress
    +-    public void testPidForegroundCombined() throws Exception {
    +-        IdleFuture idle;
    +-
    +-        // push all uid into background
    +-        idle = expectIdle();
    +-        mProcessObserver.onForegroundActivitiesChanged(PID_1, UID_A, false);
    +-        mProcessObserver.onForegroundActivitiesChanged(PID_2, UID_A, false);
    +-        mProcessObserver.onForegroundActivitiesChanged(PID_3, UID_B, false);
    +-        idle.get();
    +-        assertFalse(mService.isUidForeground(UID_A));
    +-        assertFalse(mService.isUidForeground(UID_B));
    +-
    +-        // push one of the shared pids into foreground
    +-        idle = expectIdle();
    +-        mProcessObserver.onForegroundActivitiesChanged(PID_2, UID_A, true);
    +-        idle.get();
    +-        assertTrue(mService.isUidForeground(UID_A));
    +-        assertFalse(mService.isUidForeground(UID_B));
    +-
    +-        // and swap another uid into foreground
    +-        idle = expectIdle();
    +-        mProcessObserver.onForegroundActivitiesChanged(PID_2, UID_A, false);
    +-        mProcessObserver.onForegroundActivitiesChanged(PID_3, UID_B, true);
    +-        idle.get();
    +-        assertFalse(mService.isUidForeground(UID_A));
    +-        assertTrue(mService.isUidForeground(UID_B));
    +-
    +-        // push both pid into foreground
    +-        idle = expectIdle();
    +-        mProcessObserver.onForegroundActivitiesChanged(PID_1, UID_A, true);
    +-        mProcessObserver.onForegroundActivitiesChanged(PID_2, UID_A, true);
    +-        idle.get();
    +-        assertTrue(mService.isUidForeground(UID_A));
    +-
    +-        // pull one out, should still be foreground
    +-        idle = expectIdle();
    +-        mProcessObserver.onForegroundActivitiesChanged(PID_1, UID_A, false);
    +-        idle.get();
    +-        assertTrue(mService.isUidForeground(UID_A));
    +-
    +-        // pull final pid out, should now be background
    +-        idle = expectIdle();
    +-        mProcessObserver.onForegroundActivitiesChanged(PID_2, UID_A, false);
    +-        idle.get();
    +-        assertFalse(mService.isUidForeground(UID_A));
    +-    }
    +-
    +-    @Suppress
    +-    public void testPolicyNone() throws Exception {
    +-        Future<Void> future;
    +-
    +-        expectSetUidMeteredNetworkBlacklist(UID_A, false);
    +-        expectSetUidForeground(UID_A, true);
    +-        future = expectRulesChanged(UID_A, RULE_ALLOW_ALL);
    +-        replay();
    +-        mProcessObserver.onForegroundActivitiesChanged(PID_1, UID_A, true);
    +-        future.get();
    +-        verifyAndReset();
    +-
    +-        // POLICY_NONE should RULE_ALLOW in foreground
    +-        expectSetUidMeteredNetworkBlacklist(UID_A, false);
    +-        expectSetUidForeground(UID_A, true);
    +-        future = expectRulesChanged(UID_A, RULE_ALLOW_ALL);
    +-        replay();
    +-        mService.setUidPolicy(APP_ID_A, POLICY_NONE);
    +-        future.get();
    +-        verifyAndReset();
    +-
    +-        // POLICY_NONE should RULE_ALLOW in background
    +-        expectSetUidMeteredNetworkBlacklist(UID_A, false);
    +-        expectSetUidForeground(UID_A, false);
    +-        future = expectRulesChanged(UID_A, RULE_ALLOW_ALL);
    +-        replay();
    +-        mProcessObserver.onForegroundActivitiesChanged(PID_1, UID_A, false);
    +-        future.get();
    +-        verifyAndReset();
    +-    }
    +-
    +-    @Suppress
    +-    public void testPolicyReject() throws Exception {
    +-        Future<Void> future;
    +-
    +-        // POLICY_REJECT should RULE_ALLOW in background
    +-        expectSetUidMeteredNetworkBlacklist(UID_A, true);
    +-        expectSetUidForeground(UID_A, false);
    +-        future = expectRulesChanged(UID_A, RULE_REJECT_METERED);
    +-        replay();
    +-        mService.setUidPolicy(APP_ID_A, POLICY_REJECT_METERED_BACKGROUND);
    +-        future.get();
    +-        verifyAndReset();
    +-
    +-        // POLICY_REJECT should RULE_ALLOW in foreground
    +-        expectSetUidMeteredNetworkBlacklist(UID_A, false);
    +-        expectSetUidForeground(UID_A, true);
    +-        future = expectRulesChanged(UID_A, RULE_ALLOW_ALL);
    +-        replay();
    +-        mProcessObserver.onForegroundActivitiesChanged(PID_1, UID_A, true);
    +-        future.get();
    +-        verifyAndReset();
    +-
    +-        // POLICY_REJECT should RULE_REJECT in background
    +-        expectSetUidMeteredNetworkBlacklist(UID_A, true);
    +-        expectSetUidForeground(UID_A, false);
    +-        future = expectRulesChanged(UID_A, RULE_REJECT_METERED);
    +-        replay();
    +-        mProcessObserver.onForegroundActivitiesChanged(PID_1, UID_A, false);
    +-        future.get();
    +-        verifyAndReset();
    +-    }
    +-
    +-    @Suppress
    +-    public void testPolicyRejectAddRemove() throws Exception {
    +-        Future<Void> future;
    +-
    +-        // POLICY_NONE should have RULE_ALLOW in background
    +-        expectSetUidMeteredNetworkBlacklist(UID_A, false);
    +-        expectSetUidForeground(UID_A, false);
    +-        future = expectRulesChanged(UID_A, RULE_ALLOW_ALL);
    +-        replay();
    +-        mProcessObserver.onForegroundActivitiesChanged(PID_1, UID_A, false);
    +-        mService.setUidPolicy(APP_ID_A, POLICY_NONE);
    +-        future.get();
    +-        verifyAndReset();
    +-
    +-        // adding POLICY_REJECT should cause RULE_REJECT
    +-        expectSetUidMeteredNetworkBlacklist(UID_A, true);
    +-        expectSetUidForeground(UID_A, false);
    +-        future = expectRulesChanged(UID_A, RULE_REJECT_METERED);
    +-        replay();
    +-        mService.setUidPolicy(APP_ID_A, POLICY_REJECT_METERED_BACKGROUND);
    +-        future.get();
    +-        verifyAndReset();
    +-
    +-        // removing POLICY_REJECT should return us to RULE_ALLOW
    +-        expectSetUidMeteredNetworkBlacklist(UID_A, false);
    +-        expectSetUidForeground(UID_A, false);
    +-        future = expectRulesChanged(UID_A, RULE_ALLOW_ALL);
    +-        replay();
    +-        mService.setUidPolicy(APP_ID_A, POLICY_NONE);
    +-        future.get();
    +-        verifyAndReset();
    +-    }
    +-
    +-    public void testLastCycleBoundaryThisMonth() throws Exception {
    +-        // assume cycle day of "5th", which should be in same month
    +-        final long currentTime = parseTime("2007-11-14T00:00:00.000Z");
    +-        final long expectedCycle = parseTime("2007-11-05T00:00:00.000Z");
    +-
    +-        final NetworkPolicy policy = new NetworkPolicy(
    +-                sTemplateWifi, 5, TIMEZONE_UTC, 1024L, 1024L, false);
    +-        final long actualCycle = computeLastCycleBoundary(currentTime, policy);
    +-        assertTimeEquals(expectedCycle, actualCycle);
    +-    }
    +-
    +-    public void testLastCycleBoundaryLastMonth() throws Exception {
    +-        // assume cycle day of "20th", which should be in last month
    +-        final long currentTime = parseTime("2007-11-14T00:00:00.000Z");
    +-        final long expectedCycle = parseTime("2007-10-20T00:00:00.000Z");
    +-
    +-        final NetworkPolicy policy = new NetworkPolicy(
    +-                sTemplateWifi, 20, TIMEZONE_UTC, 1024L, 1024L, false);
    +-        final long actualCycle = computeLastCycleBoundary(currentTime, policy);
    +-        assertTimeEquals(expectedCycle, actualCycle);
    +-    }
    +-
    +-    public void testLastCycleBoundaryThisMonthFebruary() throws Exception {
    +-        // assume cycle day of "30th" in february; should go to january
    +-        final long currentTime = parseTime("2007-02-14T00:00:00.000Z");
    +-        final long expectedCycle = parseTime("2007-01-30T00:00:00.000Z");
    +-
    +-        final NetworkPolicy policy = new NetworkPolicy(
    +-                sTemplateWifi, 30, TIMEZONE_UTC, 1024L, 1024L, false);
    +-        final long actualCycle = computeLastCycleBoundary(currentTime, policy);
    +-        assertTimeEquals(expectedCycle, actualCycle);
    +-    }
    +-
    +-    public void testLastCycleBoundaryLastMonthFebruary() throws Exception {
    +-        // assume cycle day of "30th" in february, which should clamp
    +-        final long currentTime = parseTime("2007-03-14T00:00:00.000Z");
    +-        final long expectedCycle = parseTime("2007-02-28T23:59:59.000Z");
    +-
    +-        final NetworkPolicy policy = new NetworkPolicy(
    +-                sTemplateWifi, 30, TIMEZONE_UTC, 1024L, 1024L, false);
    +-        final long actualCycle = computeLastCycleBoundary(currentTime, policy);
    +-        assertTimeEquals(expectedCycle, actualCycle);
    +-    }
    +-
    +-    public void testCycleBoundaryLeapYear() throws Exception {
    +-        final NetworkPolicy policy = new NetworkPolicy(
    +-                sTemplateWifi, 29, TIMEZONE_UTC, 1024L, 1024L, false);
    +-
    +-        assertTimeEquals(parseTime("2012-01-29T00:00:00.000Z"),
    +-                computeNextCycleBoundary(parseTime("2012-01-14T00:00:00.000Z"), policy));
    +-        assertTimeEquals(parseTime("2012-02-29T00:00:00.000Z"),
    +-                computeNextCycleBoundary(parseTime("2012-02-14T00:00:00.000Z"), policy));
    +-        assertTimeEquals(parseTime("2012-02-29T00:00:00.000Z"),
    +-                computeLastCycleBoundary(parseTime("2012-03-14T00:00:00.000Z"), policy));
    +-        assertTimeEquals(parseTime("2012-03-29T00:00:00.000Z"),
    +-                computeNextCycleBoundary(parseTime("2012-03-14T00:00:00.000Z"), policy));
    +-
    +-        assertTimeEquals(parseTime("2007-01-29T00:00:00.000Z"),
    +-                computeNextCycleBoundary(parseTime("2007-01-14T00:00:00.000Z"), policy));
    +-        assertTimeEquals(parseTime("2007-02-28T23:59:59.000Z"),
    +-                computeNextCycleBoundary(parseTime("2007-02-14T00:00:00.000Z"), policy));
    +-        assertTimeEquals(parseTime("2007-02-28T23:59:59.000Z"),
    +-                computeLastCycleBoundary(parseTime("2007-03-14T00:00:00.000Z"), policy));
    +-        assertTimeEquals(parseTime("2007-03-29T00:00:00.000Z"),
    +-                computeNextCycleBoundary(parseTime("2007-03-14T00:00:00.000Z"), policy));
    +-    }
    +-
    +-    public void testNextCycleTimezoneAfterUtc() throws Exception {
    +-        // US/Central is UTC-6
    +-        final NetworkPolicy policy = new NetworkPolicy(
    +-                sTemplateWifi, 10, "US/Central", 1024L, 1024L, false);
    +-        assertTimeEquals(parseTime("2012-01-10T06:00:00.000Z"),
    +-                computeNextCycleBoundary(parseTime("2012-01-05T00:00:00.000Z"), policy));
    +-    }
    +-
    +-    public void testNextCycleTimezoneBeforeUtc() throws Exception {
    +-        // Israel is UTC+2
    +-        final NetworkPolicy policy = new NetworkPolicy(
    +-                sTemplateWifi, 10, "Israel", 1024L, 1024L, false);
    +-        assertTimeEquals(parseTime("2012-01-09T22:00:00.000Z"),
    +-                computeNextCycleBoundary(parseTime("2012-01-05T00:00:00.000Z"), policy));
    +-    }
    +-
    +-    public void testNextCycleSane() throws Exception {
    +-        final NetworkPolicy policy = new NetworkPolicy(
    +-                sTemplateWifi, 31, TIMEZONE_UTC, WARNING_DISABLED, LIMIT_DISABLED, false);
    +-        final LinkedHashSet<Long> seen = new LinkedHashSet<Long>();
    +-
    +-        // walk forwards, ensuring that cycle boundaries don't get stuck
    +-        long currentCycle = computeNextCycleBoundary(parseTime("2011-08-01T00:00:00.000Z"), policy);
    +-        for (int i = 0; i < 128; i++) {
    +-            long nextCycle = computeNextCycleBoundary(currentCycle, policy);
    +-            assertEqualsFuzzy(DAY_IN_MILLIS * 30, nextCycle - currentCycle, DAY_IN_MILLIS * 3);
    +-            assertUnique(seen, nextCycle);
    +-            currentCycle = nextCycle;
    +-        }
    +-    }
    +-
    +-    public void testLastCycleSane() throws Exception {
    +-        final NetworkPolicy policy = new NetworkPolicy(
    +-                sTemplateWifi, 31, TIMEZONE_UTC, WARNING_DISABLED, LIMIT_DISABLED, false);
    +-        final LinkedHashSet<Long> seen = new LinkedHashSet<Long>();
    +-
    +-        // walk backwards, ensuring that cycle boundaries look sane
    +-        long currentCycle = computeLastCycleBoundary(parseTime("2011-08-04T00:00:00.000Z"), policy);
    +-        for (int i = 0; i < 128; i++) {
    +-            long lastCycle = computeLastCycleBoundary(currentCycle, policy);
    +-            assertEqualsFuzzy(DAY_IN_MILLIS * 30, currentCycle - lastCycle, DAY_IN_MILLIS * 3);
    +-            assertUnique(seen, lastCycle);
    +-            currentCycle = lastCycle;
    +-        }
    +-    }
    +-
    +-    public void testCycleTodayJanuary() throws Exception {
    +-        final NetworkPolicy policy = new NetworkPolicy(
    +-                sTemplateWifi, 14, "US/Pacific", 1024L, 1024L, false);
    +-
    +-        assertTimeEquals(parseTime("2013-01-14T00:00:00.000-08:00"),
    +-                computeNextCycleBoundary(parseTime("2013-01-13T23:59:59.000-08:00"), policy));
    +-        assertTimeEquals(parseTime("2013-02-14T00:00:00.000-08:00"),
    +-                computeNextCycleBoundary(parseTime("2013-01-14T00:00:01.000-08:00"), policy));
    +-        assertTimeEquals(parseTime("2013-02-14T00:00:00.000-08:00"),
    +-                computeNextCycleBoundary(parseTime("2013-01-14T15:11:00.000-08:00"), policy));
    +-
    +-        assertTimeEquals(parseTime("2012-12-14T00:00:00.000-08:00"),
    +-                computeLastCycleBoundary(parseTime("2013-01-13T23:59:59.000-08:00"), policy));
    +-        assertTimeEquals(parseTime("2013-01-14T00:00:00.000-08:00"),
    +-                computeLastCycleBoundary(parseTime("2013-01-14T00:00:01.000-08:00"), policy));
    +-        assertTimeEquals(parseTime("2013-01-14T00:00:00.000-08:00"),
    +-                computeLastCycleBoundary(parseTime("2013-01-14T15:11:00.000-08:00"), policy));
    +-    }
    +-
    +-    public void testLastCycleBoundaryDST() throws Exception {
    +-        final long currentTime = parseTime("1989-01-02T07:30:00.000");
    +-        final long expectedCycle = parseTime("1988-12-03T02:00:00.000Z");
    +-
    +-        final NetworkPolicy policy = new NetworkPolicy(
    +-                sTemplateWifi, 3, "America/Argentina/Buenos_Aires", 1024L, 1024L, false);
    +-        final long actualCycle = computeLastCycleBoundary(currentTime, policy);
    +-        assertTimeEquals(expectedCycle, actualCycle);
    +-    }
    +-
    +-    @Suppress
    +-    public void testNetworkPolicyAppliedCycleLastMonth() throws Exception {
    +-        NetworkState[] state = null;
    +-        NetworkStats stats = null;
    +-        Future<Void> future;
    +-
    +-        final long TIME_FEB_15 = 1171497600000L;
    +-        final long TIME_MAR_10 = 1173484800000L;
    +-        final int CYCLE_DAY = 15;
    +-
    +-        setCurrentTimeMillis(TIME_MAR_10);
    +-
    +-        // first, pretend that wifi network comes online. no policy active,
    +-        // which means we shouldn't push limit to interface.
    +-        state = new NetworkState[] { buildWifi() };
    +-        expect(mConnManager.getAllNetworkState()).andReturn(state).atLeastOnce();
    +-        expectCurrentTime();
    +-        expectClearNotifications();
    +-        expectAdvisePersistThreshold();
    +-        future = expectMeteredIfacesChanged();
    +-
    +-        replay();
    +-        mServiceContext.sendBroadcast(new Intent(CONNECTIVITY_ACTION));
    +-        future.get();
    +-        verifyAndReset();
    +-
    +-        // now change cycle to be on 15th, and test in early march, to verify we
    +-        // pick cycle day in previous month.
    +-        expect(mConnManager.getAllNetworkState()).andReturn(state).atLeastOnce();
    +-        expectCurrentTime();
    +-
    +-        // pretend that 512 bytes total have happened
    +-        stats = new NetworkStats(getElapsedRealtime(), 1)
    +-                .addIfaceValues(TEST_IFACE, 256L, 2L, 256L, 2L);
    +-        expect(mStatsService.getNetworkTotalBytes(sTemplateWifi, TIME_FEB_15, TIME_MAR_10))
    +-                .andReturn(stats.getTotalBytes()).atLeastOnce();
    +-        expectPolicyDataEnable(TYPE_WIFI, true);
    +-
    +-        // TODO: consider making strongly ordered mock
    +-        expectRemoveInterfaceQuota(TEST_IFACE);
    +-        expectSetInterfaceQuota(TEST_IFACE, (2 * MB_IN_BYTES) - 512);
    +-
    +-        expectClearNotifications();
    +-        expectAdvisePersistThreshold();
    +-        future = expectMeteredIfacesChanged(TEST_IFACE);
    +-
    +-        replay();
    +-        setNetworkPolicies(new NetworkPolicy(
    +-                sTemplateWifi, CYCLE_DAY, TIMEZONE_UTC, 1 * MB_IN_BYTES, 2 * MB_IN_BYTES, false));
    +-        future.get();
    +-        verifyAndReset();
    +-    }
    +-
    +-    @Suppress
    +-    public void testUidRemovedPolicyCleared() throws Exception {
    +-        Future<Void> future;
    +-
    +-        // POLICY_REJECT should RULE_REJECT in background
    +-        expectSetUidMeteredNetworkBlacklist(UID_A, true);
    +-        expectSetUidForeground(UID_A, false);
    +-        future = expectRulesChanged(UID_A, RULE_REJECT_METERED);
    +-        replay();
    +-        mService.setUidPolicy(APP_ID_A, POLICY_REJECT_METERED_BACKGROUND);
    +-        future.get();
    +-        verifyAndReset();
    +-
    +-        // uninstall should clear RULE_REJECT
    +-        expectSetUidMeteredNetworkBlacklist(UID_A, false);
    +-        expectSetUidForeground(UID_A, false);
    +-        future = expectRulesChanged(UID_A, RULE_ALLOW_ALL);
    +-        replay();
    +-        final Intent intent = new Intent(ACTION_UID_REMOVED);
    +-        intent.putExtra(EXTRA_UID, UID_A);
    +-        mServiceContext.sendBroadcast(intent);
    +-        future.get();
    +-        verifyAndReset();
    +-    }
    +-
    +-    @Suppress
    +-    public void testOverWarningLimitNotification() throws Exception {
    +-        NetworkState[] state = null;
    +-        NetworkStats stats = null;
    +-        Future<Void> future;
    +-        Future<String> tagFuture;
    +-
    +-        final long TIME_FEB_15 = 1171497600000L;
    +-        final long TIME_MAR_10 = 1173484800000L;
    +-        final int CYCLE_DAY = 15;
    +-
    +-        setCurrentTimeMillis(TIME_MAR_10);
    +-
    +-        // assign wifi policy
    +-        state = new NetworkState[] {};
    +-        stats = new NetworkStats(getElapsedRealtime(), 1)
    +-                .addIfaceValues(TEST_IFACE, 0L, 0L, 0L, 0L);
    +-
    +-        {
    +-            expectCurrentTime();
    +-            expect(mConnManager.getAllNetworkState()).andReturn(state).atLeastOnce();
    +-            expect(mStatsService.getNetworkTotalBytes(sTemplateWifi, TIME_FEB_15, currentTimeMillis()))
    +-                    .andReturn(stats.getTotalBytes()).atLeastOnce();
    +-            expectPolicyDataEnable(TYPE_WIFI, true);
    +-
    +-            expectClearNotifications();
    +-            expectAdvisePersistThreshold();
    +-            future = expectMeteredIfacesChanged();
    +-
    +-            replay();
    +-            setNetworkPolicies(new NetworkPolicy(sTemplateWifi, CYCLE_DAY, TIMEZONE_UTC, 1
    +-                    * MB_IN_BYTES, 2 * MB_IN_BYTES, false));
    +-            future.get();
    +-            verifyAndReset();
    +-        }
    +-
    +-        // bring up wifi network
    +-        incrementCurrentTime(MINUTE_IN_MILLIS);
    +-        state = new NetworkState[] { buildWifi() };
    +-        stats = new NetworkStats(getElapsedRealtime(), 1)
    +-                .addIfaceValues(TEST_IFACE, 0L, 0L, 0L, 0L);
    +-
    +-        {
    +-            expectCurrentTime();
    +-            expect(mConnManager.getAllNetworkState()).andReturn(state).atLeastOnce();
    +-            expect(mStatsService.getNetworkTotalBytes(sTemplateWifi, TIME_FEB_15, currentTimeMillis()))
    +-                    .andReturn(stats.getTotalBytes()).atLeastOnce();
    +-            expectPolicyDataEnable(TYPE_WIFI, true);
    +-
    +-            expectRemoveInterfaceQuota(TEST_IFACE);
    +-            expectSetInterfaceQuota(TEST_IFACE, 2 * MB_IN_BYTES);
    +-
    +-            expectClearNotifications();
    +-            expectAdvisePersistThreshold();
    +-            future = expectMeteredIfacesChanged(TEST_IFACE);
    +-
    +-            replay();
    +-            mServiceContext.sendBroadcast(new Intent(CONNECTIVITY_ACTION));
    +-            future.get();
    +-            verifyAndReset();
    +-        }
    +-
    +-        // go over warning, which should kick notification
    +-        incrementCurrentTime(MINUTE_IN_MILLIS);
    +-        stats = new NetworkStats(getElapsedRealtime(), 1)
    +-                .addIfaceValues(TEST_IFACE, 1536 * KB_IN_BYTES, 15L, 0L, 0L);
    +-
    +-        {
    +-            expectCurrentTime();
    +-            expect(mStatsService.getNetworkTotalBytes(sTemplateWifi, TIME_FEB_15, currentTimeMillis()))
    +-                    .andReturn(stats.getTotalBytes()).atLeastOnce();
    +-            expectPolicyDataEnable(TYPE_WIFI, true);
    +-
    +-            expectForceUpdate();
    +-            expectClearNotifications();
    +-            tagFuture = expectEnqueueNotification();
    +-
    +-            replay();
    +-            mNetworkObserver.limitReached(null, TEST_IFACE);
    +-            assertNotificationType(TYPE_WARNING, tagFuture.get());
    +-            verifyAndReset();
    +-        }
    +-
    +-        // go over limit, which should kick notification and dialog
    +-        incrementCurrentTime(MINUTE_IN_MILLIS);
    +-        stats = new NetworkStats(getElapsedRealtime(), 1)
    +-                .addIfaceValues(TEST_IFACE, 5 * MB_IN_BYTES, 512L, 0L, 0L);
    +-
    +-        {
    +-            expectCurrentTime();
    +-            expect(mStatsService.getNetworkTotalBytes(sTemplateWifi, TIME_FEB_15, currentTimeMillis()))
    +-                    .andReturn(stats.getTotalBytes()).atLeastOnce();
    +-            expectPolicyDataEnable(TYPE_WIFI, false);
    +-
    +-            expectForceUpdate();
    +-            expectClearNotifications();
    +-            tagFuture = expectEnqueueNotification();
    +-
    +-            replay();
    +-            mNetworkObserver.limitReached(null, TEST_IFACE);
    +-            assertNotificationType(TYPE_LIMIT, tagFuture.get());
    +-            verifyAndReset();
    +-        }
    +-
    +-        // now snooze policy, which should remove quota
    +-        incrementCurrentTime(MINUTE_IN_MILLIS);
    +-
    +-        {
    +-            expectCurrentTime();
    +-            expect(mConnManager.getAllNetworkState()).andReturn(state).atLeastOnce();
    +-            expect(mStatsService.getNetworkTotalBytes(sTemplateWifi, TIME_FEB_15, currentTimeMillis()))
    +-                    .andReturn(stats.getTotalBytes()).atLeastOnce();
    +-            expectPolicyDataEnable(TYPE_WIFI, true);
    +-
    +-            // snoozed interface still has high quota so background data is
    +-            // still restricted.
    +-            expectRemoveInterfaceQuota(TEST_IFACE);
    +-            expectSetInterfaceQuota(TEST_IFACE, Long.MAX_VALUE);
    +-            expectAdvisePersistThreshold();
    +-            expectMeteredIfacesChanged(TEST_IFACE);
    +-
    +-            future = expectClearNotifications();
    +-            tagFuture = expectEnqueueNotification();
    +-
    +-            replay();
    +-            mService.snoozeLimit(sTemplateWifi);
    +-            assertNotificationType(TYPE_LIMIT_SNOOZED, tagFuture.get());
    +-            future.get();
    +-            verifyAndReset();
    +-        }
    +-    }
    +-
    +-    @Suppress
    +-    public void testMeteredNetworkWithoutLimit() throws Exception {
    +-        NetworkState[] state = null;
    +-        NetworkStats stats = null;
    +-        Future<Void> future;
    +-        Future<String> tagFuture;
    +-
    +-        final long TIME_FEB_15 = 1171497600000L;
    +-        final long TIME_MAR_10 = 1173484800000L;
    +-        final int CYCLE_DAY = 15;
    +-
    +-        setCurrentTimeMillis(TIME_MAR_10);
    +-
    +-        // bring up wifi network with metered policy
    +-        state = new NetworkState[] { buildWifi() };
    +-        stats = new NetworkStats(getElapsedRealtime(), 1)
    +-                .addIfaceValues(TEST_IFACE, 0L, 0L, 0L, 0L);
    +-
    +-        {
    +-            expectCurrentTime();
    +-            expect(mConnManager.getAllNetworkState()).andReturn(state).atLeastOnce();
    +-            expect(mStatsService.getNetworkTotalBytes(sTemplateWifi, TIME_FEB_15, currentTimeMillis()))
    +-                    .andReturn(stats.getTotalBytes()).atLeastOnce();
    +-            expectPolicyDataEnable(TYPE_WIFI, true);
    +-
    +-            expectRemoveInterfaceQuota(TEST_IFACE);
    +-            expectSetInterfaceQuota(TEST_IFACE, Long.MAX_VALUE);
    +-
    +-            expectClearNotifications();
    +-            expectAdvisePersistThreshold();
    +-            future = expectMeteredIfacesChanged(TEST_IFACE);
    +-
    +-            replay();
    +-            setNetworkPolicies(new NetworkPolicy(
    +-                    sTemplateWifi, CYCLE_DAY, TIMEZONE_UTC, WARNING_DISABLED, LIMIT_DISABLED,
    +-                    true));
    +-            future.get();
    +-            verifyAndReset();
    +-        }
    +-    }
    +-
    +-    private static long parseTime(String time) {
    +-        final Time result = new Time();
    +-        result.parse3339(time);
    +-        return result.toMillis(true);
    +-    }
    +-
    +-    private void setNetworkPolicies(NetworkPolicy... policies) {
    +-        mService.setNetworkPolicies(policies);
    +-    }
    +-
    +-    private static NetworkState buildWifi() {
    +-        final NetworkInfo info = new NetworkInfo(TYPE_WIFI, 0, null, null);
    +-        info.setDetailedState(DetailedState.CONNECTED, null, null);
    +-        final LinkProperties prop = new LinkProperties();
    +-        prop.setInterfaceName(TEST_IFACE);
    +-        return new NetworkState(info, prop, null, null, null, TEST_SSID);
    +-    }
    +-
    +-    private void expectCurrentTime() throws Exception {
    +-        expect(mTime.forceRefresh()).andReturn(false).anyTimes();
    +-        expect(mTime.hasCache()).andReturn(true).anyTimes();
    +-        expect(mTime.currentTimeMillis()).andReturn(currentTimeMillis()).anyTimes();
    +-        expect(mTime.getCacheAge()).andReturn(0L).anyTimes();
    +-        expect(mTime.getCacheCertainty()).andReturn(0L).anyTimes();
    +-    }
    +-
    +-    private void expectForceUpdate() throws Exception {
    +-        mStatsService.forceUpdate();
    +-        expectLastCall().atLeastOnce();
    +-    }
    +-
    +-    private Future<Void> expectClearNotifications() throws Exception {
    +-        final FutureAnswer future = new FutureAnswer();
    +-        mNotifManager.cancelNotificationWithTag(
    +-                isA(String.class), isA(String.class), anyInt(), anyInt());
    +-        expectLastCall().andAnswer(future).anyTimes();
    +-        return future;
    +-    }
    +-
    +-    private Future<String> expectEnqueueNotification() throws Exception {
    +-        final FutureCapture<String> tag = new FutureCapture<String>();
    +-        mNotifManager.enqueueNotificationWithTag(isA(String.class), isA(String.class),
    +-                capture(tag.capture), anyInt(),
    +-                isA(Notification.class), isA(int[].class), UserHandle.myUserId());
    +-        return tag;
    +-    }
    +-
    +-    private void expectSetInterfaceQuota(String iface, long quotaBytes) throws Exception {
    +-        mNetworkManager.setInterfaceQuota(iface, quotaBytes);
    +-        expectLastCall().atLeastOnce();
    +-    }
    +-
    +-    private void expectRemoveInterfaceQuota(String iface) throws Exception {
    +-        mNetworkManager.removeInterfaceQuota(iface);
    +-        expectLastCall().atLeastOnce();
    +-    }
    +-
    +-    private void expectSetInterfaceAlert(String iface, long alertBytes) throws Exception {
    +-        mNetworkManager.setInterfaceAlert(iface, alertBytes);
    +-        expectLastCall().atLeastOnce();
    +-    }
    +-
    +-    private void expectRemoveInterfaceAlert(String iface) throws Exception {
    +-        mNetworkManager.removeInterfaceAlert(iface);
    +-        expectLastCall().atLeastOnce();
    +-    }
    +-
    +-    private void expectSetUidMeteredNetworkBlacklist(int uid, boolean rejectOnQuotaInterfaces)
    +-            throws Exception {
    +-        mNetworkManager.setUidMeteredNetworkBlacklist(uid, rejectOnQuotaInterfaces);
    +-        expectLastCall().atLeastOnce();
    +-    }
    +-
    +-    private void expectSetUidForeground(int uid, boolean uidForeground) throws Exception {
    +-        mStatsService.setUidForeground(uid, uidForeground);
    +-        expectLastCall().atLeastOnce();
    +-    }
    +-
    +-    private Future<Void> expectRulesChanged(int uid, int policy) throws Exception {
    +-        final FutureAnswer future = new FutureAnswer();
    +-        mPolicyListener.onUidRulesChanged(eq(uid), eq(policy));
    +-        expectLastCall().andAnswer(future);
    +-        return future;
    +-    }
    +-
    +-    private Future<Void> expectMeteredIfacesChanged(String... ifaces) throws Exception {
    +-        final FutureAnswer future = new FutureAnswer();
    +-        mPolicyListener.onMeteredIfacesChanged(aryEq(ifaces));
    +-        expectLastCall().andAnswer(future);
    +-        return future;
    +-    }
    +-
    +-    private Future<Void> expectPolicyDataEnable(int type, boolean enabled) throws Exception {
    +-        // TODO: bring back this test
    +-        return null;
    +-    }
    +-
    +-    private void expectAdvisePersistThreshold() throws Exception {
    +-        mStatsService.advisePersistThreshold(anyLong());
    +-        expectLastCall().anyTimes();
    +-    }
    +-
    +-    private static class TestAbstractFuture<T> extends AbstractFuture<T> {
    +-        @Override
    +-        public T get() throws InterruptedException, ExecutionException {
    +-            try {
    +-                return get(5, TimeUnit.SECONDS);
    +-            } catch (TimeoutException e) {
    +-                throw new RuntimeException(e);
    +-            }
    +-        }
    +-    }
    +-
    +-    private static class FutureAnswer extends TestAbstractFuture<Void> implements IAnswer<Void> {
    +-        @Override
    +-        public Void answer() {
    +-            set(null);
    +-            return null;
    +-        }
    +-    }
    +-
    +-    private static class FutureCapture<T> extends TestAbstractFuture<T> {
    +-        public Capture<T> capture = new Capture<T>() {
    +-            @Override
    +-            public void setValue(T value) {
    +-                super.setValue(value);
    +-                set(value);
    +-            }
    +-        };
    +-    }
    +-
    +-    private static class IdleFuture extends AbstractFuture<Void> implements IdleHandler {
    +-        @Override
    +-        public Void get() throws InterruptedException, ExecutionException {
    +-            try {
    +-                return get(5, TimeUnit.SECONDS);
    +-            } catch (TimeoutException e) {
    +-                throw new RuntimeException(e);
    +-            }
    +-        }
    +-
    +-        @Override
    +-        public boolean queueIdle() {
    +-            set(null);
    +-            return false;
    +-        }
    +-    }
    +-
    +-    /**
    +-     * Wait until {@link #mService} internal {@link Handler} is idle.
    +-     */
    +-    private IdleFuture expectIdle() {
    +-        final IdleFuture future = new IdleFuture();
    +-        mService.addIdleHandler(future);
    +-        return future;
    +-    }
    +-
    +-    private static void assertTimeEquals(long expected, long actual) {
    +-        if (expected != actual) {
    +-            fail("expected " + formatTime(expected) + " but was actually " + formatTime(actual));
    +-        }
    +-    }
    +-
    +-    private static String formatTime(long millis) {
    +-        final Time time = new Time(Time.TIMEZONE_UTC);
    +-        time.set(millis);
    +-        return time.format3339(false);
    +-    }
    +-
    +-    private static void assertEqualsFuzzy(long expected, long actual, long fuzzy) {
    +-        final long low = expected - fuzzy;
    +-        final long high = expected + fuzzy;
    +-        if (actual < low || actual > high) {
    +-            fail("value " + actual + " is outside [" + low + "," + high + "]");
    +-        }
    +-    }
    +-
    +-    private static void assertUnique(LinkedHashSet<Long> seen, Long value) {
    +-        if (!seen.add(value)) {
    +-            fail("found duplicate time " + value + " in series " + seen.toString());
    +-        }
    +-    }
    +-
    +-    private static void assertNotificationType(int expected, String actualTag) {
    +-        assertEquals(
    +-                Integer.toString(expected), actualTag.substring(actualTag.lastIndexOf(':') + 1));
    +-    }
    +-
    +-    private long getElapsedRealtime() {
    +-        return mElapsedRealtime;
    +-    }
    +-
    +-    private void setCurrentTimeMillis(long currentTimeMillis) {
    +-        mStartTime = currentTimeMillis;
    +-        mElapsedRealtime = 0L;
    +-    }
    +-
    +-    private long currentTimeMillis() {
    +-        return mStartTime + mElapsedRealtime;
    +-    }
    +-
    +-    private void incrementCurrentTime(long duration) {
    +-        mElapsedRealtime += duration;
    +-    }
    +-
    +-    private void replay() {
    +-        EasyMock.replay(mActivityManager, mStatsService, mPolicyListener, mNetworkManager, mTime,
    +-                mConnManager, mNotifManager);
    +-    }
    +-
    +-    private void verifyAndReset() {
    +-        EasyMock.verify(mActivityManager, mStatsService, mPolicyListener, mNetworkManager, mTime,
    +-                mConnManager, mNotifManager);
    +-        EasyMock.reset(mActivityManager, mStatsService, mPolicyListener, mNetworkManager, mTime,
    +-                mConnManager, mNotifManager);
    +-    }
    +-}
    +diff --git a/services/tests/servicestests/src/com/android/server/Vector3Test.java b/services/tests/servicestests/src/com/android/server/Vector3Test.java
    +deleted file mode 100644
    +index 88dbe70..0000000
    +--- a/services/tests/servicestests/src/com/android/server/Vector3Test.java
    ++++ /dev/null
    +@@ -1,164 +0,0 @@
    +-/*
    +- * Copyright (C) 2016 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 com.android.server;
    +-
    +-import android.test.AndroidTestCase;
    +-
    +-import java.lang.Exception;
    +-import java.lang.Math;
    +-
    +-/**
    +- * Tests for {@link com.android.server.AnyMotionDetector.Vector3}
    +- */
    +-public class Vector3Test extends AndroidTestCase {
    +-    private static final float tolerance = 1.0f / (1 << 12);
    +-    private static final float STATIONARY_ANGLE_THRESHOLD = 0.05f;
    +-
    +-    private AnyMotionDetector.Vector3 unitXAxis;
    +-    private AnyMotionDetector.Vector3 unitYAxis;
    +-    private AnyMotionDetector.Vector3 unitZAxis;
    +-    private AnyMotionDetector.Vector3 x3;
    +-    private AnyMotionDetector.Vector3 case1A;
    +-    private AnyMotionDetector.Vector3 case1B;
    +-    private AnyMotionDetector.Vector3 case2A;
    +-    private AnyMotionDetector.Vector3 case2B;
    +-    private AnyMotionDetector.Vector3 x1y1;
    +-    private AnyMotionDetector.Vector3 xn1y1;
    +-    private AnyMotionDetector.Vector3 x1z1;
    +-    private AnyMotionDetector.Vector3 y1z1;
    +-    private AnyMotionDetector.Vector3 piOverSixUnitCircle;
    +-
    +-
    +-    private boolean nearlyEqual(float a, float b) {
    +-        return Math.abs(a - b) <= tolerance;
    +-    }
    +-
    +-    public void setUp() throws Exception {
    +-        super.setUp();
    +-        unitXAxis = new AnyMotionDetector.Vector3(0, 1, 0, 0);
    +-        unitYAxis = new AnyMotionDetector.Vector3(0, 0, 1, 0);
    +-        unitZAxis = new AnyMotionDetector.Vector3(0, 0, 0, 1);
    +-        x3 = new AnyMotionDetector.Vector3(0, 3, 0, 0);
    +-        x1y1 = new AnyMotionDetector.Vector3(0, 1, 1, 0);
    +-        xn1y1 = new AnyMotionDetector.Vector3(0, -1, 1, 0);
    +-        x1z1 = new AnyMotionDetector.Vector3(0, 1, 0, 1);
    +-        y1z1 = new AnyMotionDetector.Vector3(0, 0, 1, 1);
    +-        piOverSixUnitCircle = new AnyMotionDetector.Vector3(
    +-                0, (float)Math.sqrt(3)/2, (float)0.5, 0);
    +-
    +-        case1A = new AnyMotionDetector.Vector3(0, -9.81f, -0.02f, 0.3f);
    +-        case1B = new AnyMotionDetector.Vector3(0, -9.80f, -0.02f, 0.3f);
    +-        case2A = new AnyMotionDetector.Vector3(0, 1f, 2f, 3f);
    +-        case2B = new AnyMotionDetector.Vector3(0, 4f, 5f, 6f);
    +-    }
    +-
    +-    public void testVector3Norm() {
    +-        assertTrue(nearlyEqual(unitXAxis.norm(), 1.0f));
    +-        assertTrue(nearlyEqual(unitYAxis.norm(), 1.0f));
    +-        assertTrue(nearlyEqual(unitZAxis.norm(), 1.0f));
    +-        assertTrue(nearlyEqual(x1y1.norm(), (float)Math.sqrt(2)));
    +-    }
    +-
    +-    public void testVector3AngleBetween() {
    +-        // Zero angle.
    +-        assertTrue(nearlyEqual(unitXAxis.angleBetween(unitXAxis), 0.0f));
    +-        assertTrue(nearlyEqual(unitYAxis.angleBetween(unitYAxis), 0.0f));
    +-        assertTrue(nearlyEqual(unitZAxis.angleBetween(unitZAxis), 0.0f));
    +-
    +-        // Unit axes should be perpendicular.
    +-        assertTrue(nearlyEqual(unitXAxis.angleBetween(unitYAxis), 90.0f));
    +-        assertTrue(nearlyEqual(unitXAxis.angleBetween(unitZAxis), 90.0f));
    +-        assertTrue(nearlyEqual(unitYAxis.angleBetween(unitZAxis), 90.0f));
    +-
    +-        // 45 degree angles.
    +-        assertTrue(nearlyEqual(unitXAxis.angleBetween(x1y1), 45.0f));
    +-        assertTrue(nearlyEqual(unitYAxis.angleBetween(x1y1), 45.0f));
    +-
    +-        // 135 degree angles.
    +-        assertTrue(nearlyEqual(xn1y1.angleBetween(unitXAxis), 135.0f));
    +-
    +-        // 30 degree angles.
    +-        assertTrue(nearlyEqual(piOverSixUnitCircle.angleBetween(unitXAxis), 30.0f));
    +-
    +-        // These vectors are expected to be still.
    +-        assertTrue(case1A.angleBetween(case1A) < STATIONARY_ANGLE_THRESHOLD);
    +-        assertTrue(case1A.angleBetween(case1B) < STATIONARY_ANGLE_THRESHOLD);
    +-        assertTrue(unitXAxis.angleBetween(unitXAxis) < STATIONARY_ANGLE_THRESHOLD);
    +-        assertTrue(unitYAxis.angleBetween(unitYAxis) < STATIONARY_ANGLE_THRESHOLD);
    +-        assertTrue(unitZAxis.angleBetween(unitZAxis) < STATIONARY_ANGLE_THRESHOLD);
    +-    }
    +-
    +-    public void testVector3Normalized() {
    +-        AnyMotionDetector.Vector3 unitXAxisNormalized = unitXAxis.normalized();
    +-        assertTrue(nearlyEqual(unitXAxisNormalized.x, unitXAxis.x));
    +-        assertTrue(nearlyEqual(unitXAxisNormalized.y, unitXAxis.y));
    +-        assertTrue(nearlyEqual(unitXAxisNormalized.z, unitXAxis.z));
    +-
    +-        // Normalizing the vector created by multiplying the unit vector by 3 gets the unit vector.
    +-        AnyMotionDetector.Vector3 x3Normalized = x3.normalized();
    +-        assertTrue(nearlyEqual(x3Normalized.x, unitXAxis.x));
    +-        assertTrue(nearlyEqual(x3Normalized.y, unitXAxis.y));
    +-        assertTrue(nearlyEqual(x3Normalized.z, unitXAxis.z));
    +-    }
    +-
    +-    public void testVector3Cross() {
    +-        AnyMotionDetector.Vector3 xCrossX = unitXAxis.cross(unitXAxis);
    +-        assertTrue(nearlyEqual(xCrossX.x, 0f));
    +-        assertTrue(nearlyEqual(xCrossX.y, 0f));
    +-        assertTrue(nearlyEqual(xCrossX.z, 0f));
    +-
    +-        AnyMotionDetector.Vector3 xCrossNx = unitXAxis.cross(unitXAxis.times(-1));
    +-        assertTrue(nearlyEqual(xCrossNx.x, 0f));
    +-        assertTrue(nearlyEqual(xCrossNx.y, 0f));
    +-        assertTrue(nearlyEqual(xCrossNx.z, 0f));
    +-
    +-        AnyMotionDetector.Vector3 cross2 = case2A.cross(case2B);
    +-        assertTrue(nearlyEqual(cross2.x, -3));
    +-        assertTrue(nearlyEqual(cross2.y, 6));
    +-        assertTrue(nearlyEqual(cross2.z, -3));
    +-    }
    +-
    +-     public void testVector3Times() {
    +-         AnyMotionDetector.Vector3 yTimes2 = unitYAxis.times(2);
    +-         assertTrue(nearlyEqual(yTimes2.x, 0f));
    +-         assertTrue(nearlyEqual(yTimes2.y, 2f));
    +-         assertTrue(nearlyEqual(yTimes2.z, 0f));
    +-     }
    +-
    +-     public void testVector3Plus() {
    +-         AnyMotionDetector.Vector3 xPlusY = unitXAxis.plus(unitYAxis);
    +-         assertTrue(nearlyEqual(xPlusY.x, 1f));
    +-         assertTrue(nearlyEqual(xPlusY.y, 1f));
    +-         assertTrue(nearlyEqual(xPlusY.z, 0f));
    +-     }
    +-
    +-     public void testVector3Minus() {
    +-         AnyMotionDetector.Vector3 xMinusY = unitXAxis.minus(unitYAxis);
    +-         assertTrue(nearlyEqual(xMinusY.x, 1f));
    +-         assertTrue(nearlyEqual(xMinusY.y, -1f));
    +-         assertTrue(nearlyEqual(xMinusY.z, 0f));
    +-     }
    +-
    +-     public void testVector3DotProduct() {
    +-         float xDotX = unitXAxis.dotProduct(unitXAxis);
    +-         float xDotY = unitXAxis.dotProduct(unitYAxis);
    +-         float xDotZ = unitXAxis.dotProduct(unitZAxis);
    +-         assertTrue(nearlyEqual(xDotX, 1f));
    +-         assertTrue(nearlyEqual(xDotY, 0f));
    +-         assertTrue(nearlyEqual(xDotZ, 0f));
    +-     }
    +-}
    +diff --git a/services/tests/servicestests/src/com/android/server/accounts/AccountManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/accounts/AccountManagerServiceTest.java
    +deleted file mode 100644
    +index 404c142..0000000
    +--- a/services/tests/servicestests/src/com/android/server/accounts/AccountManagerServiceTest.java
    ++++ /dev/null
    +@@ -1,456 +0,0 @@
    +-/*
    +- * Copyright (C) 2009 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 com.android.server.accounts;
    +-
    +-import static org.mockito.Matchers.eq;
    +-import static org.mockito.Mockito.mock;
    +-import static org.mockito.Mockito.when;
    +-
    +-import android.accounts.Account;
    +-import android.accounts.AuthenticatorDescription;
    +-import android.app.AppOpsManager;
    +-import android.app.Notification;
    +-import android.content.BroadcastReceiver;
    +-import android.content.Context;
    +-import android.content.Intent;
    +-import android.content.IntentFilter;
    +-import android.content.pm.PackageManager;
    +-import android.content.pm.RegisteredServicesCache.ServiceInfo;
    +-import android.content.pm.RegisteredServicesCacheListener;
    +-import android.content.pm.UserInfo;
    +-import android.database.Cursor;
    +-import android.database.DatabaseErrorHandler;
    +-import android.database.sqlite.SQLiteDatabase;
    +-import android.os.Bundle;
    +-import android.os.Handler;
    +-import android.os.UserHandle;
    +-import android.os.UserManager;
    +-import android.test.AndroidTestCase;
    +-import android.test.mock.MockContext;
    +-import android.test.mock.MockPackageManager;
    +-import android.util.Log;
    +-
    +-import java.io.File;
    +-import java.io.FileDescriptor;
    +-import java.io.PrintWriter;
    +-import java.util.ArrayList;
    +-import java.util.Arrays;
    +-import java.util.Collection;
    +-import java.util.Comparator;
    +-
    +-public class AccountManagerServiceTest extends AndroidTestCase {
    +-    private static final String TAG = AccountManagerServiceTest.class.getSimpleName();
    +-
    +-    static final String PREN_DB = "pren.db";
    +-    static final String DE_DB = "de.db";
    +-    static final String CE_DB = "ce.db";
    +-    private AccountManagerService mAms;
    +-
    +-    @Override
    +-    protected void setUp() throws Exception {
    +-        Context realTestContext = getContext();
    +-        Context mockContext = new MyMockContext(realTestContext);
    +-        setContext(mockContext);
    +-        mAms = createAccountManagerService(mockContext, realTestContext);
    +-    }
    +-
    +-    @Override
    +-    protected void tearDown() throws Exception {
    +-        SQLiteDatabase.deleteDatabase(new File(mAms.getCeDatabaseName(UserHandle.USER_SYSTEM)));
    +-        SQLiteDatabase.deleteDatabase(new File(mAms.getDeDatabaseName(UserHandle.USER_SYSTEM)));
    +-        SQLiteDatabase.deleteDatabase(new File(mAms.getPreNDatabaseName(UserHandle.USER_SYSTEM)));
    +-        super.tearDown();
    +-    }
    +-
    +-    public class AccountSorter implements Comparator<Account> {
    +-        public int compare(Account object1, Account object2) {
    +-            if (object1 == object2) return 0;
    +-            if (object1 == null) return 1;
    +-            if (object2 == null) return -1;
    +-            int result = object1.type.compareTo(object2.type);
    +-            if (result != 0) return result;
    +-            return object1.name.compareTo(object2.name);
    +-        }
    +-    }
    +-
    +-    public void testCheckAddAccount() throws Exception {
    +-        unlockSystemUser();
    +-        Account a11 = new Account("account1", "type1");
    +-        Account a21 = new Account("account2", "type1");
    +-        Account a31 = new Account("account3", "type1");
    +-        Account a12 = new Account("account1", "type2");
    +-        Account a22 = new Account("account2", "type2");
    +-        Account a32 = new Account("account3", "type2");
    +-        mAms.addAccountExplicitly(a11, "p11", null);
    +-        mAms.addAccountExplicitly(a12, "p12", null);
    +-        mAms.addAccountExplicitly(a21, "p21", null);
    +-        mAms.addAccountExplicitly(a22, "p22", null);
    +-        mAms.addAccountExplicitly(a31, "p31", null);
    +-        mAms.addAccountExplicitly(a32, "p32", null);
    +-
    +-        Account[] accounts = mAms.getAccounts(null, mContext.getOpPackageName());
    +-        Arrays.sort(accounts, new AccountSorter());
    +-        assertEquals(6, accounts.length);
    +-        assertEquals(a11, accounts[0]);
    +-        assertEquals(a21, accounts[1]);
    +-        assertEquals(a31, accounts[2]);
    +-        assertEquals(a12, accounts[3]);
    +-        assertEquals(a22, accounts[4]);
    +-        assertEquals(a32, accounts[5]);
    +-
    +-        accounts = mAms.getAccounts("type1", mContext.getOpPackageName());
    +-        Arrays.sort(accounts, new AccountSorter());
    +-        assertEquals(3, accounts.length);
    +-        assertEquals(a11, accounts[0]);
    +-        assertEquals(a21, accounts[1]);
    +-        assertEquals(a31, accounts[2]);
    +-
    +-        mAms.removeAccountInternal(a21);
    +-
    +-        accounts = mAms.getAccounts("type1", mContext.getOpPackageName());
    +-        Arrays.sort(accounts, new AccountSorter());
    +-        assertEquals(2, accounts.length);
    +-        assertEquals(a11, accounts[0]);
    +-        assertEquals(a31, accounts[1]);
    +-    }
    +-
    +-    public void testPasswords() throws Exception {
    +-        unlockSystemUser();
    +-        Account a11 = new Account("account1", "type1");
    +-        Account a12 = new Account("account1", "type2");
    +-        mAms.addAccountExplicitly(a11, "p11", null);
    +-        mAms.addAccountExplicitly(a12, "p12", null);
    +-
    +-        assertEquals("p11", mAms.getPassword(a11));
    +-        assertEquals("p12", mAms.getPassword(a12));
    +-
    +-        mAms.setPassword(a11, "p11b");
    +-
    +-        assertEquals("p11b", mAms.getPassword(a11));
    +-        assertEquals("p12", mAms.getPassword(a12));
    +-    }
    +-
    +-    public void testUserdata() throws Exception {
    +-        unlockSystemUser();
    +-        Account a11 = new Account("account1", "type1");
    +-        Bundle u11 = new Bundle();
    +-        u11.putString("a", "a_a11");
    +-        u11.putString("b", "b_a11");
    +-        u11.putString("c", "c_a11");
    +-        Account a12 = new Account("account1", "type2");
    +-        Bundle u12 = new Bundle();
    +-        u12.putString("a", "a_a12");
    +-        u12.putString("b", "b_a12");
    +-        u12.putString("c", "c_a12");
    +-        mAms.addAccountExplicitly(a11, "p11", u11);
    +-        mAms.addAccountExplicitly(a12, "p12", u12);
    +-
    +-        assertEquals("a_a11", mAms.getUserData(a11, "a"));
    +-        assertEquals("b_a11", mAms.getUserData(a11, "b"));
    +-        assertEquals("c_a11", mAms.getUserData(a11, "c"));
    +-        assertEquals("a_a12", mAms.getUserData(a12, "a"));
    +-        assertEquals("b_a12", mAms.getUserData(a12, "b"));
    +-        assertEquals("c_a12", mAms.getUserData(a12, "c"));
    +-
    +-        mAms.setUserData(a11, "b", "b_a11b");
    +-        mAms.setUserData(a12, "c", null);
    +-
    +-        assertEquals("a_a11", mAms.getUserData(a11, "a"));
    +-        assertEquals("b_a11b", mAms.getUserData(a11, "b"));
    +-        assertEquals("c_a11", mAms.getUserData(a11, "c"));
    +-        assertEquals("a_a12", mAms.getUserData(a12, "a"));
    +-        assertEquals("b_a12", mAms.getUserData(a12, "b"));
    +-        assertNull(mAms.getUserData(a12, "c"));
    +-    }
    +-
    +-    public void testAuthtokens() throws Exception {
    +-        unlockSystemUser();
    +-        Account a11 = new Account("account1", "type1");
    +-        Account a12 = new Account("account1", "type2");
    +-        mAms.addAccountExplicitly(a11, "p11", null);
    +-        mAms.addAccountExplicitly(a12, "p12", null);
    +-
    +-        mAms.setAuthToken(a11, "att1", "a11_att1");
    +-        mAms.setAuthToken(a11, "att2", "a11_att2");
    +-        mAms.setAuthToken(a11, "att3", "a11_att3");
    +-        mAms.setAuthToken(a12, "att1", "a12_att1");
    +-        mAms.setAuthToken(a12, "att2", "a12_att2");
    +-        mAms.setAuthToken(a12, "att3", "a12_att3");
    +-
    +-        assertEquals("a11_att1", mAms.peekAuthToken(a11, "att1"));
    +-        assertEquals("a11_att2", mAms.peekAuthToken(a11, "att2"));
    +-        assertEquals("a11_att3", mAms.peekAuthToken(a11, "att3"));
    +-        assertEquals("a12_att1", mAms.peekAuthToken(a12, "att1"));
    +-        assertEquals("a12_att2", mAms.peekAuthToken(a12, "att2"));
    +-        assertEquals("a12_att3", mAms.peekAuthToken(a12, "att3"));
    +-
    +-        mAms.setAuthToken(a11, "att3", "a11_att3b");
    +-        mAms.invalidateAuthToken(a12.type, "a12_att2");
    +-
    +-        assertEquals("a11_att1", mAms.peekAuthToken(a11, "att1"));
    +-        assertEquals("a11_att2", mAms.peekAuthToken(a11, "att2"));
    +-        assertEquals("a11_att3b", mAms.peekAuthToken(a11, "att3"));
    +-        assertEquals("a12_att1", mAms.peekAuthToken(a12, "att1"));
    +-        assertNull(mAms.peekAuthToken(a12, "att2"));
    +-        assertEquals("a12_att3", mAms.peekAuthToken(a12, "att3"));
    +-
    +-        assertNull(mAms.peekAuthToken(a12, "att2"));
    +-    }
    +-
    +-    public void testRemovedAccountSync() throws Exception {
    +-        unlockSystemUser();
    +-        Account a1 = new Account("account1", "type1");
    +-        Account a2 = new Account("account2", "type2");
    +-        mAms.addAccountExplicitly(a1, "p1", null);
    +-        mAms.addAccountExplicitly(a2, "p2", null);
    +-
    +-        Context originalContext = ((MyMockContext)getContext()).mTestContext;
    +-        // create a separate instance of AMS. It initially assumes that user0 is locked
    +-        AccountManagerService ams2 = createAccountManagerService(getContext(), originalContext);
    +-
    +-        // Verify that account can be removed when user is locked
    +-        ams2.removeAccountInternal(a1);
    +-        Account[] accounts = ams2.getAccounts(UserHandle.USER_SYSTEM, mContext.getOpPackageName());
    +-        assertEquals(1, accounts.length);
    +-        assertEquals("Only a2 should be returned", a2, accounts[0]);
    +-
    +-        // Verify that CE db file is unchanged and still has 2 accounts
    +-        String ceDatabaseName = mAms.getCeDatabaseName(UserHandle.USER_SYSTEM);
    +-        int accountsNumber = readNumberOfAccountsFromDbFile(originalContext, ceDatabaseName);
    +-        assertEquals("CE database should still have 2 accounts", 2, accountsNumber);
    +-
    +-        // Unlock the user and verify that db has been updated
    +-        ams2.onUserUnlocked(newIntentForUser(UserHandle.USER_SYSTEM));
    +-        accountsNumber = readNumberOfAccountsFromDbFile(originalContext, ceDatabaseName);
    +-        assertEquals("CE database should now have 1 account", 2, accountsNumber);
    +-        accounts = ams2.getAccounts(UserHandle.USER_SYSTEM, mContext.getOpPackageName());
    +-        assertEquals(1, accounts.length);
    +-        assertEquals("Only a2 should be returned", a2, accounts[0]);
    +-    }
    +-
    +-    public void testPreNDatabaseMigration() throws Exception {
    +-        String preNDatabaseName = mAms.getPreNDatabaseName(UserHandle.USER_SYSTEM);
    +-        Context originalContext = ((MyMockContext) getContext()).mTestContext;
    +-        PreNTestDatabaseHelper.createV4Database(originalContext, preNDatabaseName);
    +-        // Assert that database was created with 1 account
    +-        int n = readNumberOfAccountsFromDbFile(originalContext, preNDatabaseName);
    +-        assertEquals("pre-N database should have 1 account", 1, n);
    +-
    +-        // Start testing
    +-        unlockSystemUser();
    +-        Account[] accounts = mAms.getAccounts(null, mContext.getOpPackageName());
    +-        assertEquals("1 account should be migrated", 1, accounts.length);
    +-        assertEquals(PreNTestDatabaseHelper.ACCOUNT_NAME, accounts[0].name);
    +-        assertEquals(PreNTestDatabaseHelper.ACCOUNT_PASSWORD, mAms.getPassword(accounts[0]));
    +-        assertEquals("Authtoken should be migrated",
    +-                PreNTestDatabaseHelper.TOKEN_STRING,
    +-                mAms.peekAuthToken(accounts[0], PreNTestDatabaseHelper.TOKEN_TYPE));
    +-
    +-        assertFalse("pre-N database file should be removed but was found at " + preNDatabaseName,
    +-                new File(preNDatabaseName).exists());
    +-
    +-        // Verify that ce/de files are present
    +-        String deDatabaseName = mAms.getDeDatabaseName(UserHandle.USER_SYSTEM);
    +-        String ceDatabaseName = mAms.getCeDatabaseName(UserHandle.USER_SYSTEM);
    +-        assertTrue("DE database file should be created at " + deDatabaseName,
    +-                new File(deDatabaseName).exists());
    +-        assertTrue("CE database file should be created at " + ceDatabaseName,
    +-                new File(ceDatabaseName).exists());
    +-    }
    +-
    +-    private int readNumberOfAccountsFromDbFile(Context context, String dbName) {
    +-        SQLiteDatabase ceDb = context.openOrCreateDatabase(dbName, 0, null);
    +-        try (Cursor cursor = ceDb.rawQuery("SELECT count(*) FROM accounts", null)) {
    +-            assertTrue(cursor.moveToNext());
    +-            return cursor.getInt(0);
    +-        }
    +-    }
    +-
    +-    private AccountManagerService createAccountManagerService(Context mockContext,
    +-            Context realContext) {
    +-        return new MyAccountManagerService(mockContext,
    +-                new MyMockPackageManager(), new MockAccountAuthenticatorCache(), realContext);
    +-    }
    +-
    +-    private void unlockSystemUser() {
    +-        mAms.onUserUnlocked(newIntentForUser(UserHandle.USER_SYSTEM));
    +-    }
    +-
    +-    private static Intent newIntentForUser(int userId) {
    +-        Intent intent = new Intent();
    +-        intent.putExtra(Intent.EXTRA_USER_HANDLE, userId);
    +-        return intent;
    +-    }
    +-
    +-    static public class MockAccountAuthenticatorCache implements IAccountAuthenticatorCache {
    +-        private ArrayList<ServiceInfo<AuthenticatorDescription>> mServices;
    +-
    +-        public MockAccountAuthenticatorCache() {
    +-            mServices = new ArrayList<>();
    +-            AuthenticatorDescription d1 = new AuthenticatorDescription("type1", "p1", 0, 0, 0, 0);
    +-            AuthenticatorDescription d2 = new AuthenticatorDescription("type2", "p2", 0, 0, 0, 0);
    +-            mServices.add(new ServiceInfo<>(d1, null, null));
    +-            mServices.add(new ServiceInfo<>(d2, null, null));
    +-        }
    +-
    +-        @Override
    +-        public ServiceInfo<AuthenticatorDescription> getServiceInfo(
    +-                AuthenticatorDescription type, int userId) {
    +-            for (ServiceInfo<AuthenticatorDescription> service : mServices) {
    +-                if (service.type.equals(type)) {
    +-                    return service;
    +-                }
    +-            }
    +-            return null;
    +-        }
    +-
    +-        @Override
    +-        public Collection<ServiceInfo<AuthenticatorDescription>> getAllServices(int userId) {
    +-            return mServices;
    +-        }
    +-
    +-        @Override
    +-        public void dump(
    +-                final FileDescriptor fd, final PrintWriter fout, final String[] args, int userId) {
    +-        }
    +-
    +-        @Override
    +-        public void setListener(
    +-                final RegisteredServicesCacheListener<AuthenticatorDescription> listener,
    +-                final Handler handler) {
    +-        }
    +-
    +-        @Override
    +-        public void invalidateCache(int userId) {
    +-        }
    +-
    +-        @Override
    +-        public void updateServices(int userId) {
    +-        }
    +-    }
    +-
    +-    static public class MyMockContext extends MockContext {
    +-        private Context mTestContext;
    +-        private AppOpsManager mAppOpsManager;
    +-        private UserManager mUserManager;
    +-        private PackageManager mPackageManager;
    +-
    +-        public MyMockContext(Context testContext) {
    +-            this.mTestContext = testContext;
    +-            this.mAppOpsManager = mock(AppOpsManager.class);
    +-            this.mUserManager = mock(UserManager.class);
    +-            this.mPackageManager = mock(PackageManager.class);
    +-            final UserInfo ui = new UserInfo(UserHandle.USER_SYSTEM, "user0", 0);
    +-            when(mUserManager.getUserInfo(eq(ui.id))).thenReturn(ui);
    +-        }
    +-
    +-        @Override
    +-        public int checkCallingOrSelfPermission(final String permission) {
    +-            return PackageManager.PERMISSION_GRANTED;
    +-        }
    +-
    +-        @Override
    +-        public PackageManager getPackageManager() {
    +-            return mPackageManager;
    +-        }
    +-
    +-        @Override
    +-        public Object getSystemService(String name) {
    +-            if (Context.APP_OPS_SERVICE.equals(name)) {
    +-                return mAppOpsManager;
    +-            } else if( Context.USER_SERVICE.equals(name)) {
    +-                return mUserManager;
    +-            }
    +-            return null;
    +-        }
    +-
    +-        @Override
    +-        public String getSystemServiceName(Class<?> serviceClass) {
    +-            if (AppOpsManager.class.equals(serviceClass)) {
    +-                return Context.APP_OPS_SERVICE;
    +-            }
    +-            return null;
    +-        }
    +-
    +-        @Override
    +-        public Intent registerReceiver(BroadcastReceiver receiver, IntentFilter filter) {
    +-            return null;
    +-        }
    +-
    +-        @Override
    +-        public Intent registerReceiverAsUser(BroadcastReceiver receiver, UserHandle user,
    +-                IntentFilter filter, String broadcastPermission, Handler scheduler) {
    +-            return null;
    +-        }
    +-
    +-        @Override
    +-        public SQLiteDatabase openOrCreateDatabase(String file, int mode,
    +-                SQLiteDatabase.CursorFactory factory, DatabaseErrorHandler errorHandler) {
    +-            Log.i(TAG, "openOrCreateDatabase " + file + " mode " + mode);
    +-            return mTestContext.openOrCreateDatabase(file, mode, factory,errorHandler);
    +-        }
    +-
    +-        @Override
    +-        public void sendBroadcastAsUser(Intent intent, UserHandle user) {
    +-            Log.i(TAG, "sendBroadcastAsUser " + intent + " " + user);
    +-        }
    +-
    +-        @Override
    +-        public String getOpPackageName() {
    +-            return null;
    +-        }
    +-    }
    +-
    +-    static public class MyMockPackageManager extends MockPackageManager {
    +-        @Override
    +-        public int checkSignatures(final int uid1, final int uid2) {
    +-            return PackageManager.SIGNATURE_MATCH;
    +-        }
    +-    }
    +-
    +-    static public class MyAccountManagerService extends AccountManagerService {
    +-        private Context mRealTestContext;
    +-        public MyAccountManagerService(Context context, PackageManager packageManager,
    +-                IAccountAuthenticatorCache authenticatorCache, Context realTestContext) {
    +-            super(context, packageManager, authenticatorCache);
    +-            this.mRealTestContext = realTestContext;
    +-        }
    +-
    +-        @Override
    +-        protected void installNotification(final int notificationId, final Notification n, UserHandle user) {
    +-        }
    +-
    +-        @Override
    +-        protected void cancelNotification(final int id, UserHandle user) {
    +-        }
    +-
    +-        @Override
    +-        protected String getCeDatabaseName(int userId) {
    +-            return new File(mRealTestContext.getCacheDir(), CE_DB).getPath();
    +-        }
    +-
    +-        @Override
    +-        protected String getDeDatabaseName(int userId) {
    +-            return new File(mRealTestContext.getCacheDir(), DE_DB).getPath();
    +-        }
    +-
    +-        @Override
    +-        String getPreNDatabaseName(int userId) {
    +-            return new File(mRealTestContext.getCacheDir(), PREN_DB).getPath();
    +-        }
    +-    }
    +-}
    +diff --git a/services/tests/servicestests/src/com/android/server/accounts/PreNTestDatabaseHelper.java b/services/tests/servicestests/src/com/android/server/accounts/PreNTestDatabaseHelper.java
    +deleted file mode 100644
    +index 97adbe6..0000000
    +--- a/services/tests/servicestests/src/com/android/server/accounts/PreNTestDatabaseHelper.java
    ++++ /dev/null
    +@@ -1,98 +0,0 @@
    +-/*
    +- * Copyright (C) 2016 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 com.android.server.accounts;
    +-
    +-import android.content.Context;
    +-import android.database.sqlite.SQLiteDatabase;
    +-import android.database.sqlite.SQLiteOpenHelper;
    +-
    +-/**
    +- * Helper class for emulating pre-N database
    +- */
    +-class PreNTestDatabaseHelper extends SQLiteOpenHelper {
    +-
    +-    public static final String TOKEN_STRING = "token-string-123";
    +-    public static final String ACCOUNT_TYPE = "type1";
    +-    public static final String ACCOUNT_NAME = "account@" + ACCOUNT_TYPE;
    +-    public static final String ACCOUNT_PASSWORD = "Password";
    +-    public static final String TOKEN_TYPE = "SID";
    +-
    +-    public PreNTestDatabaseHelper(Context context, String name) {
    +-        super(context, name, null, 4);
    +-    }
    +-
    +-    @Override
    +-    public void onCreate(SQLiteDatabase db) {
    +-        db.execSQL("CREATE TABLE accounts ( "
    +-                + "_id INTEGER PRIMARY KEY AUTOINCREMENT, "
    +-                + "name TEXT NOT NULL, "
    +-                + "type TEXT NOT NULL, "
    +-                + "password TEXT, "
    +-                + "UNIQUE(name, type))");
    +-        db.execSQL("INSERT INTO accounts (name, type, password) VALUES "
    +-                + "('" + ACCOUNT_NAME + "', '" + ACCOUNT_TYPE + "', '" + ACCOUNT_PASSWORD + "')");
    +-
    +-        db.execSQL("CREATE TABLE authtokens (  "
    +-                + "_id INTEGER PRIMARY KEY AUTOINCREMENT,  "
    +-                + "accounts_id INTEGER NOT NULL, "
    +-                + "type TEXT NOT NULL,  "
    +-                + "authtoken TEXT, "
    +-                + "UNIQUE (accounts_id, type ))");
    +-        db.execSQL("INSERT INTO authtokens (accounts_id, type, authtoken) VALUES "
    +-                + "(1, '" + TOKEN_TYPE + "', '" + TOKEN_STRING + "')");
    +-
    +-        db.execSQL("CREATE TABLE grants (  "
    +-                + "accounts_id INTEGER NOT NULL, "
    +-                + "auth_token_type STRING NOT NULL,  "
    +-                + "uid INTEGER NOT NULL,  "
    +-                + "UNIQUE (accounts_id,auth_token_type,uid))");
    +-
    +-        db.execSQL("CREATE TABLE extras ( "
    +-                + "_id INTEGER PRIMARY KEY AUTOINCREMENT, "
    +-                + "accounts_id INTEGER, "
    +-                + "key TEXT NOT NULL, "
    +-                + "value TEXT, "
    +-                + "UNIQUE(accounts_id , key))");
    +-
    +-        db.execSQL("CREATE TABLE meta ( "
    +-                + "key TEXT PRIMARY KEY NOT NULL, "
    +-                + "value TEXT)");
    +-
    +-        db.execSQL(""
    +-                + " CREATE TRIGGER accountsDelete DELETE ON accounts "
    +-                + " BEGIN"
    +-                + "   DELETE FROM authtokens"
    +-                + "     WHERE accounts_id=OLD._id;"
    +-                + "   DELETE FROM extras"
    +-                + "     WHERE accounts_id=OLD._id;"
    +-                + "   DELETE FROM grants"
    +-                + "     WHERE accounts_id=OLD._id;"
    +-                + " END");
    +-    }
    +-
    +-    @Override
    +-    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
    +-        throw new UnsupportedOperationException("Upgrade of test database is not supported");
    +-    }
    +-
    +-    public static void createV4Database(Context context, String name) {
    +-        PreNTestDatabaseHelper helper = new PreNTestDatabaseHelper(context, name);
    +-        helper.getWritableDatabase();
    +-        helper.close();
    +-    }
    +-
    +-}
    +diff --git a/services/tests/servicestests/src/com/android/server/am/ActivityManagerTest.java b/services/tests/servicestests/src/com/android/server/am/ActivityManagerTest.java
    +deleted file mode 100644
    +index bd9e6d1..0000000
    +--- a/services/tests/servicestests/src/com/android/server/am/ActivityManagerTest.java
    ++++ /dev/null
    +@@ -1,55 +0,0 @@
    +-/*
    +- * Copyright (C) 2016 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 com.android.server.am;
    +-
    +-import android.app.ActivityManager;
    +-import android.app.ActivityManagerNative;
    +-import android.app.IActivityManager;
    +-import android.os.ServiceManager;
    +-import android.os.UserHandle;
    +-import android.os.RemoteException;
    +-import android.test.AndroidTestCase;
    +-
    +-import java.util.List;
    +-
    +-public class ActivityManagerTest extends AndroidTestCase {
    +-
    +-    IActivityManager service;
    +-    @Override
    +-    public void setUp() throws Exception {
    +-        super.setUp();
    +-        service = ActivityManagerNative.getDefault();
    +-    }
    +-
    +-    public void testTaskIdsForRunningUsers() throws RemoteException {
    +-        for(int userId : service.getRunningUserIds()) {
    +-            testTaskIdsForUser(userId);
    +-        }
    +-    }
    +-
    +-    private void testTaskIdsForUser(int userId) throws RemoteException {
    +-        List<ActivityManager.RecentTaskInfo> recentTasks = service.getRecentTasks(
    +-                100, 0, userId).getList();
    +-        if(recentTasks != null) {
    +-            for(ActivityManager.RecentTaskInfo recentTask : recentTasks) {
    +-                int taskId = recentTask.persistentId;
    +-                assertEquals("The task id " + taskId + " should not belong to user " + userId,
    +-                        taskId / UserHandle.PER_USER_RANGE, userId);
    +-            }
    +-        }
    +-    }
    +-}
    +\ No newline at end of file
    +diff --git a/services/tests/servicestests/src/com/android/server/am/TaskPersisterTest.java b/services/tests/servicestests/src/com/android/server/am/TaskPersisterTest.java
    +deleted file mode 100644
    +index e440a0d..0000000
    +--- a/services/tests/servicestests/src/com/android/server/am/TaskPersisterTest.java
    ++++ /dev/null
    +@@ -1,85 +0,0 @@
    +-/*
    +- * Copyright (C) 2016 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 com.android.server.am;
    +-
    +-import android.content.pm.UserInfo;
    +-import android.os.Environment;
    +-import android.os.UserHandle;
    +-import android.os.UserManager;
    +-import android.test.AndroidTestCase;
    +-import android.util.Log;
    +-import android.util.SparseBooleanArray;
    +-
    +-import com.android.server.am.TaskPersister;
    +-
    +-import java.io.File;
    +-import java.util.Random;
    +-
    +-public class TaskPersisterTest extends AndroidTestCase {
    +-    private static final String TEST_USER_NAME = "AM-Test-User";
    +-
    +-    private TaskPersister mTaskPersister;
    +-    private int testUserId;
    +-    private UserManager mUserManager;
    +-
    +-    @Override
    +-    public void setUp() throws Exception {
    +-        super.setUp();
    +-        mUserManager = UserManager.get(getContext());
    +-        mTaskPersister = new TaskPersister(getContext().getFilesDir());
    +-        testUserId = createUser(TEST_USER_NAME, 0);
    +-    }
    +-
    +-    @Override
    +-    public void tearDown() throws Exception {
    +-        super.tearDown();
    +-        mTaskPersister.unloadUserDataFromMemory(testUserId);
    +-        removeUser(testUserId);
    +-    }
    +-
    +-    private int getRandomTaskIdForUser(int userId) {
    +-        int taskId = (int) (Math.random() * UserHandle.PER_USER_RANGE);
    +-        taskId += UserHandle.PER_USER_RANGE * userId;
    +-        return taskId;
    +-    }
    +-
    +-    public void testTaskIdsPersistence() {
    +-        SparseBooleanArray taskIdsOnFile = mTaskPersister.loadPersistedTaskIdsForUser(testUserId);
    +-        for (int i = 0; i < 100; i++) {
    +-            taskIdsOnFile.put(getRandomTaskIdForUser(testUserId), true);
    +-        }
    +-        mTaskPersister.maybeWritePersistedTaskIdsForUser(taskIdsOnFile, testUserId);
    +-        SparseBooleanArray newTaskIdsOnFile = mTaskPersister
    +-                .loadPersistedTaskIdsForUser(testUserId);
    +-        assertTrue("TaskIds written differ from TaskIds read back from file",
    +-                taskIdsOnFile.equals(newTaskIdsOnFile));
    +-    }
    +-
    +-    private int createUser(String name, int flags) {
    +-        UserInfo user = mUserManager.createUser(name, flags);
    +-        if (user == null) {
    +-            fail("Error while creating the test user: " + TEST_USER_NAME);
    +-        }
    +-        return user.id;
    +-    }
    +-
    +-    private void removeUser(int userId) {
    +-        if (!mUserManager.removeUser(userId)) {
    +-            fail("Error while removing the test user: " + TEST_USER_NAME);
    +-        }
    +-    }
    +-}
    +\ No newline at end of file
    +diff --git a/services/tests/servicestests/src/com/android/server/connectivity/DnsEventListenerServiceTest.java b/services/tests/servicestests/src/com/android/server/connectivity/DnsEventListenerServiceTest.java
    +deleted file mode 100644
    +index 033b2c9..0000000
    +--- a/services/tests/servicestests/src/com/android/server/connectivity/DnsEventListenerServiceTest.java
    ++++ /dev/null
    +@@ -1,197 +0,0 @@
    +-/*
    +- * Copyright (C) 2016, 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 com.android.server.connectivity;
    +-
    +-import android.net.ConnectivityManager.NetworkCallback;
    +-import android.net.ConnectivityManager;
    +-import android.net.Network;
    +-import android.net.metrics.DnsEvent;
    +-import android.net.metrics.IDnsEventListener;
    +-import android.net.metrics.IpConnectivityLog;
    +-
    +-import junit.framework.TestCase;
    +-import org.junit.Before;
    +-import org.junit.Test;
    +-import static org.junit.Assert.assertArrayEquals;
    +-import static org.junit.Assert.assertTrue;
    +-
    +-import org.mockito.ArgumentCaptor;
    +-import org.mockito.Mock;
    +-import org.mockito.Mockito;
    +-import org.mockito.MockitoAnnotations;
    +-import static org.mockito.Mockito.any;
    +-import static org.mockito.Mockito.anyInt;
    +-import static org.mockito.Mockito.eq;
    +-import static org.mockito.Mockito.timeout;
    +-import static org.mockito.Mockito.times;
    +-import static org.mockito.Mockito.verify;
    +-
    +-import java.io.FileOutputStream;
    +-import java.io.PrintWriter;
    +-import java.util.Arrays;
    +-import java.util.List;
    +-import java.util.OptionalInt;
    +-import java.util.stream.IntStream;
    +-
    +-public class DnsEventListenerServiceTest extends TestCase {
    +-
    +-    // TODO: read from DnsEventListenerService after this constant is read from system property
    +-    static final int BATCH_SIZE = 100;
    +-    static final int EVENT_TYPE = IDnsEventListener.EVENT_GETADDRINFO;
    +-    // TODO: read from IDnsEventListener
    +-    static final int RETURN_CODE = 1;
    +-
    +-    static final byte[] EVENT_TYPES  = new byte[BATCH_SIZE];
    +-    static final byte[] RETURN_CODES = new byte[BATCH_SIZE];
    +-    static final int[] LATENCIES     = new int[BATCH_SIZE];
    +-    static {
    +-        for (int i = 0; i < BATCH_SIZE; i++) {
    +-            EVENT_TYPES[i] = EVENT_TYPE;
    +-            RETURN_CODES[i] = RETURN_CODE;
    +-            LATENCIES[i] = i;
    +-        }
    +-    }
    +-
    +-    DnsEventListenerService mDnsService;
    +-
    +-    @Mock ConnectivityManager mCm;
    +-    @Mock IpConnectivityLog mLog;
    +-    ArgumentCaptor<NetworkCallback> mCallbackCaptor;
    +-    ArgumentCaptor<DnsEvent> mEvCaptor;
    +-
    +-    public void setUp() {
    +-        MockitoAnnotations.initMocks(this);
    +-        mCallbackCaptor = ArgumentCaptor.forClass(NetworkCallback.class);
    +-        mEvCaptor = ArgumentCaptor.forClass(DnsEvent.class);
    +-        mDnsService = new DnsEventListenerService(mCm, mLog);
    +-
    +-        verify(mCm, times(1)).registerNetworkCallback(any(), mCallbackCaptor.capture());
    +-    }
    +-
    +-    public void testOneBatch() throws Exception {
    +-        log(105, LATENCIES);
    +-        log(106, Arrays.copyOf(LATENCIES, BATCH_SIZE - 1)); // one lookup short of a batch event
    +-
    +-        verifyLoggedEvents(new DnsEvent(105, EVENT_TYPES, RETURN_CODES, LATENCIES));
    +-
    +-        log(106, Arrays.copyOfRange(LATENCIES, BATCH_SIZE - 1, BATCH_SIZE));
    +-
    +-        mEvCaptor = ArgumentCaptor.forClass(DnsEvent.class); // reset argument captor
    +-        verifyLoggedEvents(
    +-            new DnsEvent(105, EVENT_TYPES, RETURN_CODES, LATENCIES),
    +-            new DnsEvent(106, EVENT_TYPES, RETURN_CODES, LATENCIES));
    +-    }
    +-
    +-    public void testSeveralBatches() throws Exception {
    +-        log(105, LATENCIES);
    +-        log(106, LATENCIES);
    +-        log(105, LATENCIES);
    +-        log(107, LATENCIES);
    +-
    +-        verifyLoggedEvents(
    +-            new DnsEvent(105, EVENT_TYPES, RETURN_CODES, LATENCIES),
    +-            new DnsEvent(106, EVENT_TYPES, RETURN_CODES, LATENCIES),
    +-            new DnsEvent(105, EVENT_TYPES, RETURN_CODES, LATENCIES),
    +-            new DnsEvent(107, EVENT_TYPES, RETURN_CODES, LATENCIES));
    +-    }
    +-
    +-    public void testBatchAndNetworkLost() throws Exception {
    +-        byte[] eventTypes = Arrays.copyOf(EVENT_TYPES, 20);
    +-        byte[] returnCodes = Arrays.copyOf(RETURN_CODES, 20);
    +-        int[] latencies = Arrays.copyOf(LATENCIES, 20);
    +-
    +-        log(105, LATENCIES);
    +-        log(105, latencies);
    +-        mCallbackCaptor.getValue().onLost(new Network(105));
    +-        log(105, LATENCIES);
    +-
    +-        verifyLoggedEvents(
    +-            new DnsEvent(105, eventTypes, returnCodes, latencies),
    +-            new DnsEvent(105, EVENT_TYPES, RETURN_CODES, LATENCIES),
    +-            new DnsEvent(105, EVENT_TYPES, RETURN_CODES, LATENCIES));
    +-    }
    +-
    +-    public void testConcurrentBatchesAndDumps() throws Exception {
    +-        final long stop = System.currentTimeMillis() + 100;
    +-        final PrintWriter pw = new PrintWriter(new FileOutputStream("/dev/null"));
    +-        new Thread() {
    +-            public void run() {
    +-                while (System.currentTimeMillis() < stop) {
    +-                    mDnsService.dump(pw);
    +-                }
    +-            }
    +-        }.start();
    +-
    +-        logAsync(105, LATENCIES);
    +-        logAsync(106, LATENCIES);
    +-        logAsync(107, LATENCIES);
    +-
    +-        verifyLoggedEvents(500,
    +-            new DnsEvent(105, EVENT_TYPES, RETURN_CODES, LATENCIES),
    +-            new DnsEvent(106, EVENT_TYPES, RETURN_CODES, LATENCIES),
    +-            new DnsEvent(107, EVENT_TYPES, RETURN_CODES, LATENCIES));
    +-    }
    +-
    +-    public void testConcurrentBatchesAndNetworkLoss() throws Exception {
    +-        logAsync(105, LATENCIES);
    +-        Thread.sleep(10L);
    +-        // call onLost() asynchronously to logAsync's onDnsEvent() calls.
    +-        mCallbackCaptor.getValue().onLost(new Network(105));
    +-
    +-        // do not verify unpredictable batch
    +-        verify(mLog, timeout(500).times(1)).log(any());
    +-    }
    +-
    +-    void log(int netId, int[] latencies) {
    +-        for (int l : latencies) {
    +-            mDnsService.onDnsEvent(netId, EVENT_TYPE, RETURN_CODE, l);
    +-        }
    +-    }
    +-
    +-    void logAsync(int netId, int[] latencies) {
    +-        new Thread() {
    +-            public void run() {
    +-                log(netId, latencies);
    +-            }
    +-        }.start();
    +-    }
    +-
    +-    void verifyLoggedEvents(DnsEvent... expected) {
    +-        verifyLoggedEvents(0, expected);
    +-    }
    +-
    +-    void verifyLoggedEvents(int wait, DnsEvent... expectedEvents) {
    +-        verify(mLog, timeout(wait).times(expectedEvents.length)).log(mEvCaptor.capture());
    +-        for (DnsEvent got : mEvCaptor.getAllValues()) {
    +-            OptionalInt index = IntStream.range(0, expectedEvents.length)
    +-                    .filter(i -> eventsEqual(expectedEvents[i], got))
    +-                    .findFirst();
    +-            // Don't match same expected event more than once.
    +-            index.ifPresent(i -> expectedEvents[i] = null);
    +-            assertTrue(index.isPresent());
    +-        }
    +-    }
    +-
    +-    /** equality function for DnsEvent to avoid overriding equals() and hashCode(). */
    +-    static boolean eventsEqual(DnsEvent expected, DnsEvent got) {
    +-        return (expected == got) || ((expected != null) && (got != null)
    +-                && (expected.netId == got.netId)
    +-                && Arrays.equals(expected.eventTypes, got.eventTypes)
    +-                && Arrays.equals(expected.returnCodes, got.returnCodes)
    +-                && Arrays.equals(expected.latenciesMs, got.latenciesMs));
    +-    }
    +-}
    +diff --git a/services/tests/servicestests/src/com/android/server/connectivity/LingerMonitorTest.java b/services/tests/servicestests/src/com/android/server/connectivity/LingerMonitorTest.java
    +deleted file mode 100644
    +index bce5787..0000000
    +--- a/services/tests/servicestests/src/com/android/server/connectivity/LingerMonitorTest.java
    ++++ /dev/null
    +@@ -1,349 +0,0 @@
    +-/*
    +- * Copyright (C) 2016, 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 com.android.server.connectivity;
    +-
    +-import android.app.PendingIntent;
    +-import android.content.Context;
    +-import android.content.res.Resources;
    +-import android.net.ConnectivityManager;
    +-import android.net.Network;
    +-import android.net.NetworkCapabilities;
    +-import android.net.NetworkInfo;
    +-import android.net.NetworkMisc;
    +-import android.text.format.DateUtils;
    +-import com.android.internal.R;
    +-import com.android.server.ConnectivityService;
    +-import com.android.server.connectivity.NetworkNotificationManager;
    +-import com.android.server.connectivity.NetworkNotificationManager.NotificationType;
    +-import junit.framework.TestCase;
    +-import org.mockito.Mock;
    +-import org.mockito.MockitoAnnotations;
    +-
    +-import static org.mockito.Mockito.any;
    +-import static org.mockito.Mockito.anyBoolean;
    +-import static org.mockito.Mockito.anyInt;
    +-import static org.mockito.Mockito.eq;
    +-import static org.mockito.Mockito.never;
    +-import static org.mockito.Mockito.times;
    +-import static org.mockito.Mockito.verify;
    +-import static org.mockito.Mockito.when;
    +-import static org.mockito.Mockito.reset;
    +-
    +-public class LingerMonitorTest extends TestCase {
    +-    static final String CELLULAR = "CELLULAR";
    +-    static final String WIFI     = "WIFI";
    +-
    +-    static final long LOW_RATE_LIMIT = DateUtils.MINUTE_IN_MILLIS;
    +-    static final long HIGH_RATE_LIMIT = 0;
    +-
    +-    static final int LOW_DAILY_LIMIT = 2;
    +-    static final int HIGH_DAILY_LIMIT = 1000;
    +-
    +-    LingerMonitor mMonitor;
    +-
    +-    @Mock ConnectivityService mConnService;
    +-    @Mock Context mCtx;
    +-    @Mock NetworkMisc mMisc;
    +-    @Mock NetworkNotificationManager mNotifier;
    +-    @Mock Resources mResources;
    +-
    +-    public void setUp() {
    +-        MockitoAnnotations.initMocks(this);
    +-        when(mCtx.getResources()).thenReturn(mResources);
    +-        when(mCtx.getPackageName()).thenReturn("com.android.server.connectivity");
    +-        when(mConnService.createNetworkMonitor(any(), any(), any(), any())).thenReturn(null);
    +-
    +-        mMonitor = new TestableLingerMonitor(mCtx, mNotifier, HIGH_DAILY_LIMIT, HIGH_RATE_LIMIT);
    +-    }
    +-
    +-    public void testTransitions() {
    +-        setNotificationSwitch(transition(WIFI, CELLULAR));
    +-        NetworkAgentInfo nai1 = wifiNai(100);
    +-        NetworkAgentInfo nai2 = cellNai(101);
    +-
    +-        assertTrue(mMonitor.isNotificationEnabled(nai1, nai2));
    +-        assertFalse(mMonitor.isNotificationEnabled(nai2, nai1));
    +-    }
    +-
    +-    public void testNotificationOnLinger() {
    +-        setNotificationSwitch(transition(WIFI, CELLULAR));
    +-        setNotificationType(LingerMonitor.NOTIFY_TYPE_NOTIFICATION);
    +-        NetworkAgentInfo from = wifiNai(100);
    +-        NetworkAgentInfo to = cellNai(101);
    +-
    +-        mMonitor.noteLingerDefaultNetwork(from, to);
    +-        verifyNotification(from, to);
    +-    }
    +-
    +-    public void testToastOnLinger() {
    +-        setNotificationSwitch(transition(WIFI, CELLULAR));
    +-        setNotificationType(LingerMonitor.NOTIFY_TYPE_TOAST);
    +-        NetworkAgentInfo from = wifiNai(100);
    +-        NetworkAgentInfo to = cellNai(101);
    +-
    +-        mMonitor.noteLingerDefaultNetwork(from, to);
    +-        verifyToast(from, to);
    +-    }
    +-
    +-    public void testNotificationClearedAfterDisconnect() {
    +-        setNotificationSwitch(transition(WIFI, CELLULAR));
    +-        setNotificationType(LingerMonitor.NOTIFY_TYPE_NOTIFICATION);
    +-        NetworkAgentInfo from = wifiNai(100);
    +-        NetworkAgentInfo to = cellNai(101);
    +-
    +-        mMonitor.noteLingerDefaultNetwork(from, to);
    +-        verifyNotification(from, to);
    +-
    +-        mMonitor.noteDisconnect(to);
    +-        verify(mNotifier, times(1)).clearNotification(100);
    +-    }
    +-
    +-    public void testNotificationClearedAfterSwitchingBack() {
    +-        setNotificationSwitch(transition(WIFI, CELLULAR));
    +-        setNotificationType(LingerMonitor.NOTIFY_TYPE_NOTIFICATION);
    +-        NetworkAgentInfo from = wifiNai(100);
    +-        NetworkAgentInfo to = cellNai(101);
    +-
    +-        mMonitor.noteLingerDefaultNetwork(from, to);
    +-        verifyNotification(from, to);
    +-
    +-        mMonitor.noteLingerDefaultNetwork(to, from);
    +-        verify(mNotifier, times(1)).clearNotification(100);
    +-    }
    +-
    +-    public void testUniqueToast() {
    +-        setNotificationSwitch(transition(WIFI, CELLULAR));
    +-        setNotificationType(LingerMonitor.NOTIFY_TYPE_TOAST);
    +-        NetworkAgentInfo from = wifiNai(100);
    +-        NetworkAgentInfo to = cellNai(101);
    +-
    +-        mMonitor.noteLingerDefaultNetwork(from, to);
    +-        verifyToast(from, to);
    +-
    +-        mMonitor.noteLingerDefaultNetwork(to, from);
    +-        verify(mNotifier, times(1)).clearNotification(100);
    +-
    +-        reset(mNotifier);
    +-        mMonitor.noteLingerDefaultNetwork(from, to);
    +-        verifyNoNotifications();
    +-    }
    +-
    +-    public void testMultipleNotifications() {
    +-        setNotificationSwitch(transition(WIFI, CELLULAR));
    +-        setNotificationType(LingerMonitor.NOTIFY_TYPE_NOTIFICATION);
    +-        NetworkAgentInfo wifi1 = wifiNai(100);
    +-        NetworkAgentInfo wifi2 = wifiNai(101);
    +-        NetworkAgentInfo cell = cellNai(102);
    +-
    +-        mMonitor.noteLingerDefaultNetwork(wifi1, cell);
    +-        verifyNotification(wifi1, cell);
    +-
    +-        mMonitor.noteLingerDefaultNetwork(cell, wifi2);
    +-        verify(mNotifier, times(1)).clearNotification(100);
    +-
    +-        reset(mNotifier);
    +-        mMonitor.noteLingerDefaultNetwork(wifi2, cell);
    +-        verifyNotification(wifi2, cell);
    +-    }
    +-
    +-    public void testRateLimiting() throws InterruptedException {
    +-        mMonitor = new TestableLingerMonitor(mCtx, mNotifier, HIGH_DAILY_LIMIT, LOW_RATE_LIMIT);
    +-
    +-        setNotificationSwitch(transition(WIFI, CELLULAR));
    +-        setNotificationType(LingerMonitor.NOTIFY_TYPE_NOTIFICATION);
    +-        NetworkAgentInfo wifi1 = wifiNai(100);
    +-        NetworkAgentInfo wifi2 = wifiNai(101);
    +-        NetworkAgentInfo wifi3 = wifiNai(102);
    +-        NetworkAgentInfo cell = cellNai(103);
    +-
    +-        mMonitor.noteLingerDefaultNetwork(wifi1, cell);
    +-        verifyNotification(wifi1, cell);
    +-        reset(mNotifier);
    +-
    +-        Thread.sleep(50);
    +-        mMonitor.noteLingerDefaultNetwork(cell, wifi2);
    +-        mMonitor.noteLingerDefaultNetwork(wifi2, cell);
    +-        verifyNoNotifications();
    +-
    +-        Thread.sleep(50);
    +-        mMonitor.noteLingerDefaultNetwork(cell, wifi3);
    +-        mMonitor.noteLingerDefaultNetwork(wifi3, cell);
    +-        verifyNoNotifications();
    +-    }
    +-
    +-    public void testDailyLimiting() throws InterruptedException {
    +-        mMonitor = new TestableLingerMonitor(mCtx, mNotifier, LOW_DAILY_LIMIT, HIGH_RATE_LIMIT);
    +-
    +-        setNotificationSwitch(transition(WIFI, CELLULAR));
    +-        setNotificationType(LingerMonitor.NOTIFY_TYPE_NOTIFICATION);
    +-        NetworkAgentInfo wifi1 = wifiNai(100);
    +-        NetworkAgentInfo wifi2 = wifiNai(101);
    +-        NetworkAgentInfo wifi3 = wifiNai(102);
    +-        NetworkAgentInfo cell = cellNai(103);
    +-
    +-        mMonitor.noteLingerDefaultNetwork(wifi1, cell);
    +-        verifyNotification(wifi1, cell);
    +-        reset(mNotifier);
    +-
    +-        Thread.sleep(50);
    +-        mMonitor.noteLingerDefaultNetwork(cell, wifi2);
    +-        mMonitor.noteLingerDefaultNetwork(wifi2, cell);
    +-        verifyNotification(wifi2, cell);
    +-        reset(mNotifier);
    +-
    +-        Thread.sleep(50);
    +-        mMonitor.noteLingerDefaultNetwork(cell, wifi3);
    +-        mMonitor.noteLingerDefaultNetwork(wifi3, cell);
    +-        verifyNoNotifications();
    +-    }
    +-
    +-    public void testUniqueNotification() {
    +-        setNotificationSwitch(transition(WIFI, CELLULAR));
    +-        setNotificationType(LingerMonitor.NOTIFY_TYPE_NOTIFICATION);
    +-        NetworkAgentInfo from = wifiNai(100);
    +-        NetworkAgentInfo to = cellNai(101);
    +-
    +-        mMonitor.noteLingerDefaultNetwork(from, to);
    +-        verifyNotification(from, to);
    +-
    +-        mMonitor.noteLingerDefaultNetwork(to, from);
    +-        verify(mNotifier, times(1)).clearNotification(100);
    +-
    +-        mMonitor.noteLingerDefaultNetwork(from, to);
    +-        verifyNotification(from, to);
    +-    }
    +-
    +-    public void testIgnoreNeverValidatedNetworks() {
    +-        setNotificationType(LingerMonitor.NOTIFY_TYPE_TOAST);
    +-        setNotificationSwitch(transition(WIFI, CELLULAR));
    +-        NetworkAgentInfo from = wifiNai(100);
    +-        NetworkAgentInfo to = cellNai(101);
    +-        from.everValidated = false;
    +-
    +-        mMonitor.noteLingerDefaultNetwork(from, to);
    +-        verifyNoNotifications();
    +-    }
    +-
    +-    public void testIgnoreCurrentlyValidatedNetworks() {
    +-        setNotificationType(LingerMonitor.NOTIFY_TYPE_TOAST);
    +-        setNotificationSwitch(transition(WIFI, CELLULAR));
    +-        NetworkAgentInfo from = wifiNai(100);
    +-        NetworkAgentInfo to = cellNai(101);
    +-        from.lastValidated = true;
    +-
    +-        mMonitor.noteLingerDefaultNetwork(from, to);
    +-        verifyNoNotifications();
    +-    }
    +-
    +-    public void testNoNotificationType() {
    +-        setNotificationType(LingerMonitor.NOTIFY_TYPE_TOAST);
    +-        setNotificationSwitch();
    +-        NetworkAgentInfo from = wifiNai(100);
    +-        NetworkAgentInfo to = cellNai(101);
    +-
    +-        mMonitor.noteLingerDefaultNetwork(from, to);
    +-        verifyNoNotifications();
    +-    }
    +-
    +-    public void testNoTransitionToNotify() {
    +-        setNotificationType(LingerMonitor.NOTIFY_TYPE_NONE);
    +-        setNotificationSwitch(transition(WIFI, CELLULAR));
    +-        NetworkAgentInfo from = wifiNai(100);
    +-        NetworkAgentInfo to = cellNai(101);
    +-
    +-        mMonitor.noteLingerDefaultNetwork(from, to);
    +-        verifyNoNotifications();
    +-    }
    +-
    +-    public void testDifferentTransitionToNotify() {
    +-        setNotificationType(LingerMonitor.NOTIFY_TYPE_TOAST);
    +-        setNotificationSwitch(transition(CELLULAR, WIFI));
    +-        NetworkAgentInfo from = wifiNai(100);
    +-        NetworkAgentInfo to = cellNai(101);
    +-
    +-        mMonitor.noteLingerDefaultNetwork(from, to);
    +-        verifyNoNotifications();
    +-    }
    +-
    +-    void setNotificationSwitch(String... transitions) {
    +-        when(mResources.getStringArray(R.array.config_networkNotifySwitches))
    +-                .thenReturn(transitions);
    +-    }
    +-
    +-    String transition(String from, String to) {
    +-        return from + "-" + to;
    +-    }
    +-
    +-    void setNotificationType(int type) {
    +-        when(mResources.getInteger(R.integer.config_networkNotifySwitchType)).thenReturn(type);
    +-    }
    +-
    +-    void verifyNoToast() {
    +-        verify(mNotifier, never()).showToast(any(), any());
    +-    }
    +-
    +-    void verifyNoNotification() {
    +-        verify(mNotifier, never())
    +-                .showNotification(anyInt(), any(), any(), any(), any(), anyBoolean());
    +-    }
    +-
    +-    void verifyNoNotifications() {
    +-        verifyNoToast();
    +-        verifyNoNotification();
    +-    }
    +-
    +-    void verifyToast(NetworkAgentInfo from, NetworkAgentInfo to) {
    +-        verifyNoNotification();
    +-        verify(mNotifier, times(1)).showToast(from, to);
    +-    }
    +-
    +-    void verifyNotification(NetworkAgentInfo from, NetworkAgentInfo to) {
    +-        verifyNoToast();
    +-        verify(mNotifier, times(1)).showNotification(eq(from.network.netId),
    +-                eq(NotificationType.NETWORK_SWITCH), eq(from), eq(to), any(), eq(true));
    +-    }
    +-
    +-    NetworkAgentInfo nai(int netId, int transport, int networkType, String networkTypeName) {
    +-        NetworkInfo info = new NetworkInfo(networkType, 0, networkTypeName, "");
    +-        NetworkCapabilities caps = new NetworkCapabilities();
    +-        caps.addCapability(0);
    +-        caps.addTransportType(transport);
    +-        NetworkAgentInfo nai = new NetworkAgentInfo(null, null, new Network(netId), info, null,
    +-                caps, 50, mCtx, null, mMisc, null, mConnService);
    +-        nai.everValidated = true;
    +-        return nai;
    +-    }
    +-
    +-    NetworkAgentInfo wifiNai(int netId) {
    +-        return nai(netId, NetworkCapabilities.TRANSPORT_WIFI,
    +-                ConnectivityManager.TYPE_WIFI, WIFI);
    +-    }
    +-
    +-    NetworkAgentInfo cellNai(int netId) {
    +-        return nai(netId, NetworkCapabilities.TRANSPORT_CELLULAR,
    +-                ConnectivityManager.TYPE_MOBILE, CELLULAR);
    +-    }
    +-
    +-    public static class TestableLingerMonitor extends LingerMonitor {
    +-        public TestableLingerMonitor(Context c, NetworkNotificationManager n, int l, long r) {
    +-            super(c, n, l, r);
    +-        }
    +-        @Override protected PendingIntent createNotificationIntent() {
    +-            return null;
    +-        }
    +-    }
    +-}
    +diff --git a/services/tests/servicestests/src/com/android/server/connectivity/MetricsLoggerServiceTest.java b/services/tests/servicestests/src/com/android/server/connectivity/MetricsLoggerServiceTest.java
    +deleted file mode 100644
    +index 5f84ea1..0000000
    +--- a/services/tests/servicestests/src/com/android/server/connectivity/MetricsLoggerServiceTest.java
    ++++ /dev/null
    +@@ -1,181 +0,0 @@
    +-/*
    +- * Copyright (C) 2016, 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 com.android.server.connectivity;
    +-
    +-import android.content.Context;
    +-import android.net.ConnectivityMetricsEvent;
    +-import android.os.Bundle;
    +-import android.os.RemoteException;
    +-import static android.net.ConnectivityMetricsEvent.Reference;
    +-
    +-import junit.framework.TestCase;
    +-import org.junit.Before;
    +-import org.junit.Test;
    +-import static org.junit.Assert.assertEquals;
    +-import static org.junit.Assert.assertArrayEquals;
    +-
    +-import org.mockito.Mock;
    +-import org.mockito.MockitoAnnotations;
    +-
    +-import java.io.FileDescriptor;
    +-import java.io.FileOutputStream;
    +-import java.util.Arrays;
    +-import java.util.Comparator;
    +-import java.util.concurrent.CountDownLatch;
    +-import java.util.concurrent.TimeUnit;
    +-
    +-/*
    +- * TODO:
    +- *  - allow overriding MetricsLoggerService constants in tests.
    +- *  - test intents are correctly sent after the notification threshold.
    +- *  - test oldest events are correctly pushed out when internal deque is full.
    +- *  - test throttling triggers correctly.
    +- */
    +-public class MetricsLoggerServiceTest extends TestCase {
    +-
    +-    static final int COMPONENT_TAG = 1;
    +-    static final long N_EVENTS = 10L;
    +-    static final ConnectivityMetricsEvent EVENTS[] = new ConnectivityMetricsEvent[(int)N_EVENTS];
    +-    static {
    +-        for (int i = 0; i < N_EVENTS; i++) {
    +-            EVENTS[i] = new ConnectivityMetricsEvent(i, COMPONENT_TAG, i, new Bundle());
    +-        }
    +-    }
    +-
    +-    static final ConnectivityMetricsEvent NO_EVENTS[] = new ConnectivityMetricsEvent[0];
    +-
    +-    @Mock Context mContext;
    +-    MetricsLoggerService mService;
    +-
    +-    public void setUp() {
    +-        MockitoAnnotations.initMocks(this);
    +-        mService = new MetricsLoggerService(mContext);
    +-        mService.onStart();
    +-    }
    +-
    +-    public void testGetNoEvents() throws Exception {
    +-        Reference r = new Reference(0);
    +-        assertArrayEquals(NO_EVENTS, mService.mBinder.getEvents(r));
    +-        assertEquals(0, r.getValue());
    +-    }
    +-
    +-    public void testLogAndGetEvents() throws Exception {
    +-        mService.mBinder.logEvents(EVENTS);
    +-
    +-        Reference r = new Reference(0);
    +-
    +-        assertArrayEquals(EVENTS, mService.mBinder.getEvents(r));
    +-        assertEquals(N_EVENTS, r.getValue());
    +-
    +-        assertArrayEquals(NO_EVENTS, mService.mBinder.getEvents(r));
    +-        assertEquals(N_EVENTS, r.getValue());
    +-    }
    +-
    +-    public void testLogOneByOne() throws Exception {
    +-        for (ConnectivityMetricsEvent ev : EVENTS) {
    +-            mService.mBinder.logEvent(ev);
    +-        }
    +-
    +-        Reference r = new Reference(0);
    +-
    +-        assertArrayEquals(EVENTS, mService.mBinder.getEvents(r));
    +-        assertEquals(N_EVENTS, r.getValue());
    +-
    +-        assertArrayEquals(NO_EVENTS, mService.mBinder.getEvents(r));
    +-        assertEquals(N_EVENTS, r.getValue());
    +-    }
    +-
    +-    public void testInterleavedLogAndGet() throws Exception {
    +-        mService.mBinder.logEvents(Arrays.copyOfRange(EVENTS, 0, 3));
    +-
    +-        Reference r = new Reference(0);
    +-
    +-        assertArrayEquals(Arrays.copyOfRange(EVENTS, 0, 3), mService.mBinder.getEvents(r));
    +-        assertEquals(3, r.getValue());
    +-
    +-        mService.mBinder.logEvents(Arrays.copyOfRange(EVENTS, 3, 8));
    +-        mService.mBinder.logEvents(Arrays.copyOfRange(EVENTS, 8, 10));
    +-
    +-        assertArrayEquals(Arrays.copyOfRange(EVENTS, 3, 10), mService.mBinder.getEvents(r));
    +-        assertEquals(N_EVENTS, r.getValue());
    +-
    +-        assertArrayEquals(NO_EVENTS, mService.mBinder.getEvents(r));
    +-        assertEquals(N_EVENTS, r.getValue());
    +-    }
    +-
    +-    public void testMultipleGetAll() throws Exception {
    +-        mService.mBinder.logEvents(Arrays.copyOf(EVENTS, 3));
    +-
    +-        Reference r1 = new Reference(0);
    +-        assertArrayEquals(Arrays.copyOf(EVENTS, 3), mService.mBinder.getEvents(r1));
    +-        assertEquals(3, r1.getValue());
    +-
    +-        mService.mBinder.logEvents(Arrays.copyOfRange(EVENTS, 3, 10));
    +-
    +-        Reference r2 = new Reference(0);
    +-        assertArrayEquals(EVENTS, mService.mBinder.getEvents(r2));
    +-        assertEquals(N_EVENTS, r2.getValue());
    +-    }
    +-
    +-    public void testLogAndDumpConcurrently() throws Exception {
    +-        for (int i = 0; i < 50; i++) {
    +-            mContext = null;
    +-            mService = null;
    +-            setUp();
    +-            logAndDumpConcurrently();
    +-        }
    +-    }
    +-
    +-    public void logAndDumpConcurrently() throws Exception {
    +-        final CountDownLatch latch = new CountDownLatch((int)N_EVENTS);
    +-        final FileDescriptor fd = new FileOutputStream("/dev/null").getFD();
    +-
    +-        for (ConnectivityMetricsEvent ev : EVENTS) {
    +-            new Thread() {
    +-                public void run() {
    +-                    mService.mBinder.logEvent(ev);
    +-                    latch.countDown();
    +-                }
    +-            }.start();
    +-        }
    +-
    +-        new Thread() {
    +-            public void run() {
    +-                while (latch.getCount() > 0) {
    +-                    mService.mBinder.dump(fd, new String[]{"--all"});
    +-                }
    +-            }
    +-        }.start();
    +-
    +-        latch.await(100, TimeUnit.MILLISECONDS);
    +-
    +-        Reference r = new Reference(0);
    +-        ConnectivityMetricsEvent[] got = mService.mBinder.getEvents(r);
    +-        Arrays.sort(got, new EventComparator());
    +-        assertArrayEquals(EVENTS, got);
    +-        assertEquals(N_EVENTS, r.getValue());
    +-    }
    +-
    +-    static class EventComparator implements Comparator<ConnectivityMetricsEvent> {
    +-        public int compare(ConnectivityMetricsEvent ev1, ConnectivityMetricsEvent ev2) {
    +-            return Long.compare(ev1.timestamp, ev2.timestamp);
    +-        }
    +-        public boolean equal(Object o) {
    +-            return o instanceof EventComparator;
    +-        }
    +-    };
    +-}
    +diff --git a/services/tests/servicestests/src/com/android/server/connectivity/VpnTest.java b/services/tests/servicestests/src/com/android/server/connectivity/VpnTest.java
    +deleted file mode 100644
    +index 5d8b843..0000000
    +--- a/services/tests/servicestests/src/com/android/server/connectivity/VpnTest.java
    ++++ /dev/null
    +@@ -1,310 +0,0 @@
    +-/*
    +- * Copyright (C) 2016 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 com.android.server.connectivity;
    +-
    +-import static android.content.pm.UserInfo.FLAG_ADMIN;
    +-import static android.content.pm.UserInfo.FLAG_MANAGED_PROFILE;
    +-import static android.content.pm.UserInfo.FLAG_PRIMARY;
    +-import static android.content.pm.UserInfo.FLAG_RESTRICTED;
    +-import static org.mockito.AdditionalMatchers.*;
    +-import static org.mockito.Mockito.*;
    +-
    +-import android.annotation.UserIdInt;
    +-import android.app.AppOpsManager;
    +-import android.content.Context;
    +-import android.content.pm.PackageManager;
    +-import android.content.pm.UserInfo;
    +-import android.net.UidRange;
    +-import android.os.INetworkManagementService;
    +-import android.os.Looper;
    +-import android.os.UserHandle;
    +-import android.os.UserManager;
    +-import android.test.AndroidTestCase;
    +-import android.test.suitebuilder.annotation.SmallTest;
    +-import android.util.ArrayMap;
    +-import android.util.ArraySet;
    +-
    +-import java.util.ArrayList;
    +-import java.util.Arrays;
    +-import java.util.Map;
    +-import java.util.Set;
    +-
    +-import org.mockito.Mock;
    +-import org.mockito.MockitoAnnotations;
    +-
    +-/**
    +- * Tests for {@link Vpn}.
    +- *
    +- * Build, install and run with:
    +- *  runtest --path src/com/android/server/connectivity/VpnTest.java
    +- */
    +-public class VpnTest extends AndroidTestCase {
    +-    private static final String TAG = "VpnTest";
    +-
    +-    // Mock users
    +-    static final UserInfo primaryUser = new UserInfo(27, "Primary", FLAG_ADMIN | FLAG_PRIMARY);
    +-    static final UserInfo secondaryUser = new UserInfo(15, "Secondary", FLAG_ADMIN);
    +-    static final UserInfo restrictedProfileA = new UserInfo(40, "RestrictedA", FLAG_RESTRICTED);
    +-    static final UserInfo restrictedProfileB = new UserInfo(42, "RestrictedB", FLAG_RESTRICTED);
    +-    static final UserInfo managedProfileA = new UserInfo(45, "ManagedA", FLAG_MANAGED_PROFILE);
    +-    static {
    +-        restrictedProfileA.restrictedProfileParentId = primaryUser.id;
    +-        restrictedProfileB.restrictedProfileParentId = secondaryUser.id;
    +-        managedProfileA.profileGroupId = primaryUser.id;
    +-    }
    +-
    +-    /**
    +-     * Names and UIDs for some fake packages. Important points:
    +-     *  - UID is ordered increasing.
    +-     *  - One pair of packages have consecutive UIDs.
    +-     */
    +-    static final String[] PKGS = {"com.example", "org.example", "net.example", "web.vpn"};
    +-    static final int[] PKG_UIDS = {66, 77, 78, 400};
    +-
    +-    // Mock packages
    +-    static final Map<String, Integer> mPackages = new ArrayMap<>();
    +-    static {
    +-        for (int i = 0; i < PKGS.length; i++) {
    +-            mPackages.put(PKGS[i], PKG_UIDS[i]);
    +-        }
    +-    }
    +-
    +-    @Mock private Context mContext;
    +-    @Mock private UserManager mUserManager;
    +-    @Mock private PackageManager mPackageManager;
    +-    @Mock private INetworkManagementService mNetService;
    +-    @Mock private AppOpsManager mAppOps;
    +-
    +-    @Override
    +-    public void setUp() throws Exception {
    +-        MockitoAnnotations.initMocks(this);
    +-        when(mContext.getPackageManager()).thenReturn(mPackageManager);
    +-        setMockedPackages(mPackages);
    +-        when(mContext.getSystemService(eq(Context.USER_SERVICE))).thenReturn(mUserManager);
    +-        when(mContext.getSystemService(eq(Context.APP_OPS_SERVICE))).thenReturn(mAppOps);
    +-        doNothing().when(mNetService).registerObserver(any());
    +-    }
    +-
    +-    @SmallTest
    +-    public void testRestrictedProfilesAreAddedToVpn() {
    +-        setMockedUsers(primaryUser, secondaryUser, restrictedProfileA, restrictedProfileB);
    +-
    +-        final Vpn vpn = new MockVpn(primaryUser.id);
    +-        final Set<UidRange> ranges = vpn.createUserAndRestrictedProfilesRanges(primaryUser.id,
    +-                null, null);
    +-
    +-        assertEquals(new ArraySet<>(Arrays.asList(new UidRange[] {
    +-            UidRange.createForUser(primaryUser.id),
    +-            UidRange.createForUser(restrictedProfileA.id)
    +-        })), ranges);
    +-    }
    +-
    +-    @SmallTest
    +-    public void testManagedProfilesAreNotAddedToVpn() {
    +-        setMockedUsers(primaryUser, managedProfileA);
    +-
    +-        final Vpn vpn = new MockVpn(primaryUser.id);
    +-        final Set<UidRange> ranges = vpn.createUserAndRestrictedProfilesRanges(primaryUser.id,
    +-                null, null);
    +-
    +-        assertEquals(new ArraySet<>(Arrays.asList(new UidRange[] {
    +-            UidRange.createForUser(primaryUser.id)
    +-        })), ranges);
    +-    }
    +-
    +-    @SmallTest
    +-    public void testAddUserToVpnOnlyAddsOneUser() {
    +-        setMockedUsers(primaryUser, restrictedProfileA, managedProfileA);
    +-
    +-        final Vpn vpn = new MockVpn(primaryUser.id);
    +-        final Set<UidRange> ranges = new ArraySet<>();
    +-        vpn.addUserToRanges(ranges, primaryUser.id, null, null);
    +-
    +-        assertEquals(new ArraySet<>(Arrays.asList(new UidRange[] {
    +-            UidRange.createForUser(primaryUser.id)
    +-        })), ranges);
    +-    }
    +-
    +-    @SmallTest
    +-    public void testUidWhiteAndBlacklist() throws Exception {
    +-        final Vpn vpn = new MockVpn(primaryUser.id);
    +-        final UidRange user = UidRange.createForUser(primaryUser.id);
    +-        final String[] packages = {PKGS[0], PKGS[1], PKGS[2]};
    +-
    +-        // Whitelist
    +-        final Set<UidRange> allow = vpn.createUserAndRestrictedProfilesRanges(primaryUser.id,
    +-                Arrays.asList(packages), null);
    +-        assertEquals(new ArraySet<>(Arrays.asList(new UidRange[] {
    +-            new UidRange(user.start + PKG_UIDS[0], user.start + PKG_UIDS[0]),
    +-            new UidRange(user.start + PKG_UIDS[1], user.start + PKG_UIDS[2])
    +-        })), allow);
    +-
    +-        // Blacklist
    +-        final Set<UidRange> disallow = vpn.createUserAndRestrictedProfilesRanges(primaryUser.id,
    +-                null, Arrays.asList(packages));
    +-        assertEquals(new ArraySet<>(Arrays.asList(new UidRange[] {
    +-            new UidRange(user.start, user.start + PKG_UIDS[0] - 1),
    +-            new UidRange(user.start + PKG_UIDS[0] + 1, user.start + PKG_UIDS[1] - 1),
    +-            /* Empty range between UIDS[1] and UIDS[2], should be excluded, */
    +-            new UidRange(user.start + PKG_UIDS[2] + 1, user.stop)
    +-        })), disallow);
    +-    }
    +-
    +-    @SmallTest
    +-    public void testLockdownChangingPackage() throws Exception {
    +-        final MockVpn vpn = new MockVpn(primaryUser.id);
    +-        final UidRange user = UidRange.createForUser(primaryUser.id);
    +-
    +-        // Default state.
    +-        vpn.assertUnblocked(user.start + PKG_UIDS[0], user.start + PKG_UIDS[1], user.start + PKG_UIDS[2], user.start + PKG_UIDS[3]);
    +-
    +-        // Set always-on without lockdown.
    +-        assertTrue(vpn.setAlwaysOnPackage(PKGS[1], false));
    +-        vpn.assertUnblocked(user.start + PKG_UIDS[0], user.start + PKG_UIDS[1], user.start + PKG_UIDS[2], user.start + PKG_UIDS[3]);
    +-
    +-        // Set always-on with lockdown.
    +-        assertTrue(vpn.setAlwaysOnPackage(PKGS[1], true));
    +-        verify(mNetService).setAllowOnlyVpnForUids(eq(true), aryEq(new UidRange[] {
    +-            new UidRange(user.start, user.start + PKG_UIDS[1] - 1),
    +-            new UidRange(user.start + PKG_UIDS[1] + 1, user.stop)
    +-        }));
    +-        vpn.assertBlocked(user.start + PKG_UIDS[0], user.start + PKG_UIDS[2], user.start + PKG_UIDS[3]);
    +-        vpn.assertUnblocked(user.start + PKG_UIDS[1]);
    +-
    +-        // Switch to another app.
    +-        assertTrue(vpn.setAlwaysOnPackage(PKGS[3], true));
    +-        verify(mNetService).setAllowOnlyVpnForUids(eq(false), aryEq(new UidRange[] {
    +-            new UidRange(user.start, user.start + PKG_UIDS[1] - 1),
    +-            new UidRange(user.start + PKG_UIDS[1] + 1, user.stop)
    +-        }));
    +-        verify(mNetService).setAllowOnlyVpnForUids(eq(true), aryEq(new UidRange[] {
    +-            new UidRange(user.start, user.start + PKG_UIDS[3] - 1),
    +-            new UidRange(user.start + PKG_UIDS[3] + 1, user.stop)
    +-        }));
    +-        vpn.assertBlocked(user.start + PKG_UIDS[0], user.start + PKG_UIDS[1], user.start + PKG_UIDS[2]);
    +-        vpn.assertUnblocked(user.start + PKG_UIDS[3]);
    +-    }
    +-
    +-    @SmallTest
    +-    public void testLockdownAddingAProfile() throws Exception {
    +-        final MockVpn vpn = new MockVpn(primaryUser.id);
    +-        setMockedUsers(primaryUser);
    +-
    +-        // Make a copy of the restricted profile, as we're going to mark it deleted halfway through.
    +-        final UserInfo tempProfile = new UserInfo(restrictedProfileA.id, restrictedProfileA.name,
    +-                restrictedProfileA.flags);
    +-        tempProfile.restrictedProfileParentId = primaryUser.id;
    +-
    +-        final UidRange user = UidRange.createForUser(primaryUser.id);
    +-        final UidRange profile = UidRange.createForUser(tempProfile.id);
    +-
    +-        // Set lockdown.
    +-        assertTrue(vpn.setAlwaysOnPackage(PKGS[3], true));
    +-        verify(mNetService).setAllowOnlyVpnForUids(eq(true), aryEq(new UidRange[] {
    +-            new UidRange(user.start, user.start + PKG_UIDS[3] - 1),
    +-            new UidRange(user.start + PKG_UIDS[3] + 1, user.stop)
    +-        }));
    +-
    +-        // Verify restricted user isn't affected at first.
    +-        vpn.assertUnblocked(profile.start + PKG_UIDS[0]);
    +-
    +-        // Add the restricted user.
    +-        setMockedUsers(primaryUser, tempProfile);
    +-        vpn.onUserAdded(tempProfile.id);
    +-        verify(mNetService).setAllowOnlyVpnForUids(eq(true), aryEq(new UidRange[] {
    +-            new UidRange(profile.start, profile.start + PKG_UIDS[3] - 1),
    +-            new UidRange(profile.start + PKG_UIDS[3] + 1, profile.stop)
    +-        }));
    +-
    +-        // Remove the restricted user.
    +-        tempProfile.partial = true;
    +-        vpn.onUserRemoved(tempProfile.id);
    +-        verify(mNetService).setAllowOnlyVpnForUids(eq(false), aryEq(new UidRange[] {
    +-            new UidRange(profile.start, profile.start + PKG_UIDS[3] - 1),
    +-            new UidRange(profile.start + PKG_UIDS[3] + 1, profile.stop)
    +-        }));
    +-    }
    +-
    +-    /**
    +-     * A subclass of {@link Vpn} with some of the fields pre-mocked.
    +-     */
    +-    private class MockVpn extends Vpn {
    +-        public MockVpn(@UserIdInt int userId) {
    +-            super(Looper.myLooper(), mContext, mNetService, userId);
    +-        }
    +-
    +-        public void assertBlocked(int... uids) {
    +-            for (int uid : uids) {
    +-                assertTrue("Uid " + uid + " should be blocked", isBlockingUid(uid));
    +-            }
    +-        }
    +-
    +-        public void assertUnblocked(int... uids) {
    +-            for (int uid : uids) {
    +-                assertFalse("Uid " + uid + " should not be blocked", isBlockingUid(uid));
    +-            }
    +-        }
    +-    }
    +-
    +-    /**
    +-     * Populate {@link #mUserManager} with a list of fake users.
    +-     */
    +-    private void setMockedUsers(UserInfo... users) {
    +-        final Map<Integer, UserInfo> userMap = new ArrayMap<>();
    +-        for (UserInfo user : users) {
    +-            userMap.put(user.id, user);
    +-        }
    +-
    +-        /**
    +-         * @see UserManagerService#getUsers(boolean)
    +-         */
    +-        doAnswer(invocation -> {
    +-            final boolean excludeDying = (boolean) invocation.getArguments()[0];
    +-            final ArrayList<UserInfo> result = new ArrayList<>(users.length);
    +-            for (UserInfo ui : users) {
    +-                if (!excludeDying || (ui.isEnabled() && !ui.partial)) {
    +-                    result.add(ui);
    +-                }
    +-            }
    +-            return result;
    +-        }).when(mUserManager).getUsers(anyBoolean());
    +-
    +-        doAnswer(invocation -> {
    +-            final int id = (int) invocation.getArguments()[0];
    +-            return userMap.get(id);
    +-        }).when(mUserManager).getUserInfo(anyInt());
    +-
    +-        doAnswer(invocation -> {
    +-            final int id = (int) invocation.getArguments()[0];
    +-            return (userMap.get(id).flags & UserInfo.FLAG_ADMIN) != 0;
    +-        }).when(mUserManager).canHaveRestrictedProfile(anyInt());
    +-    }
    +-
    +-    /**
    +-     * Populate {@link #mPackageManager} with a fake packageName-to-UID mapping.
    +-     */
    +-    private void setMockedPackages(final Map<String, Integer> packages) {
    +-        try {
    +-            doAnswer(invocation -> {
    +-                final String appName = (String) invocation.getArguments()[0];
    +-                final int userId = (int) invocation.getArguments()[1];
    +-                return UserHandle.getUid(userId, packages.get(appName));
    +-            }).when(mPackageManager).getPackageUidAsUser(anyString(), anyInt());
    +-        } catch (Exception e) {
    +-        }
    +-    }
    +-}
    +diff --git a/services/tests/servicestests/src/com/android/server/connectivity/tethering/TetherInterfaceStateMachineTest.java b/services/tests/servicestests/src/com/android/server/connectivity/tethering/TetherInterfaceStateMachineTest.java
    +deleted file mode 100644
    +index a30b362..0000000
    +--- a/services/tests/servicestests/src/com/android/server/connectivity/tethering/TetherInterfaceStateMachineTest.java
    ++++ /dev/null
    +@@ -1,277 +0,0 @@
    +-/*
    +- * Copyright (C) 2016 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 com.android.server.connectivity.tethering;
    +-
    +-import static org.mockito.Matchers.anyString;
    +-import static org.mockito.Mockito.doThrow;
    +-import static org.mockito.Mockito.inOrder;
    +-import static org.mockito.Mockito.reset;
    +-import static org.mockito.Mockito.verify;
    +-import static org.mockito.Mockito.verifyNoMoreInteractions;
    +-import static org.mockito.Mockito.when;
    +-
    +-import static android.net.ConnectivityManager.TETHER_ERROR_ENABLE_NAT_ERROR;
    +-import static android.net.ConnectivityManager.TETHER_ERROR_NO_ERROR;
    +-import static android.net.ConnectivityManager.TETHER_ERROR_TETHER_IFACE_ERROR;
    +-import static android.net.ConnectivityManager.TETHER_ERROR_UNTETHER_IFACE_ERROR;
    +-import static com.android.server.connectivity.tethering.IControlsTethering.STATE_AVAILABLE;
    +-import static com.android.server.connectivity.tethering.IControlsTethering.STATE_TETHERED;
    +-import static com.android.server.connectivity.tethering.IControlsTethering.STATE_UNAVAILABLE;
    +-
    +-import android.net.ConnectivityManager;
    +-import android.net.INetworkStatsService;
    +-import android.net.InterfaceConfiguration;
    +-import android.os.INetworkManagementService;
    +-import android.os.RemoteException;
    +-import android.os.test.TestLooper;
    +-import android.support.test.filters.SmallTest;
    +-import android.support.test.runner.AndroidJUnit4;
    +-
    +-import org.junit.Before;
    +-import org.junit.Test;
    +-import org.junit.runner.RunWith;
    +-import org.mockito.InOrder;
    +-import org.mockito.Mock;
    +-import org.mockito.MockitoAnnotations;
    +-
    +-@RunWith(AndroidJUnit4.class)
    +-@SmallTest
    +-public class TetherInterfaceStateMachineTest {
    +-    private static final String IFACE_NAME = "testnet1";
    +-    private static final String UPSTREAM_IFACE = "upstream0";
    +-    private static final String UPSTREAM_IFACE2 = "upstream1";
    +-
    +-    @Mock private INetworkManagementService mNMService;
    +-    @Mock private INetworkStatsService mStatsService;
    +-    @Mock private IControlsTethering mTetherHelper;
    +-    @Mock private InterfaceConfiguration mInterfaceConfiguration;
    +-
    +-    private final TestLooper mLooper = new TestLooper();
    +-    private TetherInterfaceStateMachine mTestedSm;
    +-
    +-    private void initStateMachine(int interfaceType) throws Exception {
    +-        mTestedSm = new TetherInterfaceStateMachine(IFACE_NAME, mLooper.getLooper(), interfaceType,
    +-                mNMService, mStatsService, mTetherHelper);
    +-        mTestedSm.start();
    +-        // Starting the state machine always puts us in a consistent state and notifies
    +-        // the test of the world that we've changed from an unknown to available state.
    +-        mLooper.dispatchAll();
    +-        reset(mNMService, mStatsService, mTetherHelper);
    +-        when(mNMService.getInterfaceConfig(IFACE_NAME)).thenReturn(mInterfaceConfiguration);
    +-    }
    +-
    +-    private void initTetheredStateMachine(int interfaceType, String upstreamIface) throws Exception {
    +-        initStateMachine(interfaceType);
    +-        dispatchCommand(TetherInterfaceStateMachine.CMD_TETHER_REQUESTED);
    +-        if (upstreamIface != null) {
    +-            dispatchTetherConnectionChanged(upstreamIface);
    +-        }
    +-        reset(mNMService, mStatsService, mTetherHelper);
    +-        when(mNMService.getInterfaceConfig(IFACE_NAME)).thenReturn(mInterfaceConfiguration);
    +-    }
    +-
    +-    @Before public void setUp() throws Exception {
    +-        MockitoAnnotations.initMocks(this);
    +-    }
    +-
    +-    @Test
    +-    public void startsOutAvailable() {
    +-        mTestedSm = new TetherInterfaceStateMachine(IFACE_NAME, mLooper.getLooper(),
    +-                ConnectivityManager.TETHERING_BLUETOOTH, mNMService, mStatsService, mTetherHelper);
    +-        mTestedSm.start();
    +-        mLooper.dispatchAll();
    +-        verify(mTetherHelper).notifyInterfaceStateChange(
    +-                IFACE_NAME, mTestedSm, STATE_AVAILABLE, TETHER_ERROR_NO_ERROR);
    +-        verifyNoMoreInteractions(mTetherHelper, mNMService, mStatsService);
    +-    }
    +-
    +-    @Test
    +-    public void shouldDoNothingUntilRequested() throws Exception {
    +-        initStateMachine(ConnectivityManager.TETHERING_BLUETOOTH);
    +-        final int [] NOOP_COMMANDS = {
    +-            TetherInterfaceStateMachine.CMD_TETHER_UNREQUESTED,
    +-            TetherInterfaceStateMachine.CMD_IP_FORWARDING_ENABLE_ERROR,
    +-            TetherInterfaceStateMachine.CMD_IP_FORWARDING_DISABLE_ERROR,
    +-            TetherInterfaceStateMachine.CMD_START_TETHERING_ERROR,
    +-            TetherInterfaceStateMachine.CMD_STOP_TETHERING_ERROR,
    +-            TetherInterfaceStateMachine.CMD_SET_DNS_FORWARDERS_ERROR,
    +-            TetherInterfaceStateMachine.CMD_TETHER_CONNECTION_CHANGED
    +-        };
    +-        for (int command : NOOP_COMMANDS) {
    +-            // None of these commands should trigger us to request action from
    +-            // the rest of the system.
    +-            dispatchCommand(command);
    +-            verifyNoMoreInteractions(mNMService, mStatsService, mTetherHelper);
    +-        }
    +-    }
    +-
    +-    @Test
    +-    public void handlesImmediateInterfaceDown() throws Exception {
    +-        initStateMachine(ConnectivityManager.TETHERING_BLUETOOTH);
    +-
    +-        dispatchCommand(TetherInterfaceStateMachine.CMD_INTERFACE_DOWN);
    +-        verify(mTetherHelper).notifyInterfaceStateChange(
    +-                IFACE_NAME, mTestedSm, STATE_UNAVAILABLE, TETHER_ERROR_NO_ERROR);
    +-        verifyNoMoreInteractions(mNMService, mStatsService, mTetherHelper);
    +-    }
    +-
    +-    @Test
    +-    public void canBeTethered() throws Exception {
    +-        initStateMachine(ConnectivityManager.TETHERING_BLUETOOTH);
    +-
    +-        dispatchCommand(TetherInterfaceStateMachine.CMD_TETHER_REQUESTED);
    +-        InOrder inOrder = inOrder(mTetherHelper, mNMService);
    +-        inOrder.verify(mNMService).tetherInterface(IFACE_NAME);
    +-        inOrder.verify(mTetherHelper).notifyInterfaceStateChange(
    +-                IFACE_NAME, mTestedSm, STATE_TETHERED, TETHER_ERROR_NO_ERROR);
    +-        verifyNoMoreInteractions(mNMService, mStatsService, mTetherHelper);
    +-    }
    +-
    +-    @Test
    +-    public void canUnrequestTethering() throws Exception {
    +-        initTetheredStateMachine(ConnectivityManager.TETHERING_BLUETOOTH, null);
    +-
    +-        dispatchCommand(TetherInterfaceStateMachine.CMD_TETHER_UNREQUESTED);
    +-        InOrder inOrder = inOrder(mNMService, mStatsService, mTetherHelper);
    +-        inOrder.verify(mNMService).untetherInterface(IFACE_NAME);
    +-        inOrder.verify(mTetherHelper).notifyInterfaceStateChange(
    +-                IFACE_NAME, mTestedSm, STATE_AVAILABLE, TETHER_ERROR_NO_ERROR);
    +-        verifyNoMoreInteractions(mNMService, mStatsService, mTetherHelper);
    +-    }
    +-
    +-    @Test
    +-    public void canBeTetheredAsUsb() throws Exception {
    +-        initStateMachine(ConnectivityManager.TETHERING_USB);
    +-
    +-        dispatchCommand(TetherInterfaceStateMachine.CMD_TETHER_REQUESTED);
    +-        InOrder inOrder = inOrder(mTetherHelper, mNMService);
    +-        inOrder.verify(mNMService).getInterfaceConfig(IFACE_NAME);
    +-        inOrder.verify(mNMService).setInterfaceConfig(IFACE_NAME, mInterfaceConfiguration);
    +-        inOrder.verify(mNMService).tetherInterface(IFACE_NAME);
    +-        inOrder.verify(mTetherHelper).notifyInterfaceStateChange(
    +-                IFACE_NAME, mTestedSm, STATE_TETHERED, TETHER_ERROR_NO_ERROR);
    +-        verifyNoMoreInteractions(mNMService, mStatsService, mTetherHelper);
    +-    }
    +-
    +-    @Test
    +-    public void handlesFirstUpstreamChange() throws Exception {
    +-        initTetheredStateMachine(ConnectivityManager.TETHERING_BLUETOOTH, null);
    +-
    +-        // Telling the state machine about its upstream interface triggers a little more configuration.
    +-        dispatchTetherConnectionChanged(UPSTREAM_IFACE);
    +-        InOrder inOrder = inOrder(mNMService);
    +-        inOrder.verify(mNMService).enableNat(IFACE_NAME, UPSTREAM_IFACE);
    +-        inOrder.verify(mNMService).startInterfaceForwarding(IFACE_NAME, UPSTREAM_IFACE);
    +-        verifyNoMoreInteractions(mNMService, mStatsService, mTetherHelper);
    +-    }
    +-
    +-    @Test
    +-    public void handlesChangingUpstream() throws Exception {
    +-        initTetheredStateMachine(ConnectivityManager.TETHERING_BLUETOOTH, UPSTREAM_IFACE);
    +-
    +-        dispatchTetherConnectionChanged(UPSTREAM_IFACE2);
    +-        InOrder inOrder = inOrder(mNMService, mStatsService);
    +-        inOrder.verify(mStatsService).forceUpdate();
    +-        inOrder.verify(mNMService).stopInterfaceForwarding(IFACE_NAME, UPSTREAM_IFACE);
    +-        inOrder.verify(mNMService).disableNat(IFACE_NAME, UPSTREAM_IFACE);
    +-        inOrder.verify(mNMService).enableNat(IFACE_NAME, UPSTREAM_IFACE2);
    +-        inOrder.verify(mNMService).startInterfaceForwarding(IFACE_NAME, UPSTREAM_IFACE2);
    +-        verifyNoMoreInteractions(mNMService, mStatsService, mTetherHelper);
    +-    }
    +-
    +-    @Test
    +-    public void canUnrequestTetheringWithUpstream() throws Exception {
    +-        initTetheredStateMachine(ConnectivityManager.TETHERING_BLUETOOTH, UPSTREAM_IFACE);
    +-
    +-        dispatchCommand(TetherInterfaceStateMachine.CMD_TETHER_UNREQUESTED);
    +-        InOrder inOrder = inOrder(mNMService, mStatsService, mTetherHelper);
    +-        inOrder.verify(mStatsService).forceUpdate();
    +-        inOrder.verify(mNMService).stopInterfaceForwarding(IFACE_NAME, UPSTREAM_IFACE);
    +-        inOrder.verify(mNMService).disableNat(IFACE_NAME, UPSTREAM_IFACE);
    +-        inOrder.verify(mNMService).untetherInterface(IFACE_NAME);
    +-        inOrder.verify(mTetherHelper).notifyInterfaceStateChange(
    +-                IFACE_NAME, mTestedSm, STATE_AVAILABLE, TETHER_ERROR_NO_ERROR);
    +-        verifyNoMoreInteractions(mNMService, mStatsService, mTetherHelper);
    +-    }
    +-
    +-    @Test
    +-    public void interfaceDownLeadsToUnavailable() throws Exception {
    +-        for (boolean shouldThrow : new boolean[]{true, false}) {
    +-            initTetheredStateMachine(ConnectivityManager.TETHERING_USB, null);
    +-
    +-            if (shouldThrow) {
    +-                doThrow(RemoteException.class).when(mNMService).untetherInterface(IFACE_NAME);
    +-            }
    +-            dispatchCommand(TetherInterfaceStateMachine.CMD_INTERFACE_DOWN);
    +-            InOrder usbTeardownOrder = inOrder(mNMService, mInterfaceConfiguration, mTetherHelper);
    +-            usbTeardownOrder.verify(mInterfaceConfiguration).setInterfaceDown();
    +-            usbTeardownOrder.verify(mNMService).setInterfaceConfig(
    +-                    IFACE_NAME, mInterfaceConfiguration);
    +-            usbTeardownOrder.verify(mTetherHelper).notifyInterfaceStateChange(
    +-                    IFACE_NAME, mTestedSm, STATE_UNAVAILABLE, TETHER_ERROR_NO_ERROR);
    +-        }
    +-    }
    +-
    +-    @Test
    +-    public void usbShouldBeTornDownOnTetherError() throws Exception {
    +-        initStateMachine(ConnectivityManager.TETHERING_USB);
    +-
    +-        doThrow(RemoteException.class).when(mNMService).tetherInterface(IFACE_NAME);
    +-        dispatchCommand(TetherInterfaceStateMachine.CMD_TETHER_REQUESTED);
    +-        InOrder usbTeardownOrder = inOrder(mNMService, mInterfaceConfiguration, mTetherHelper);
    +-        usbTeardownOrder.verify(mInterfaceConfiguration).setInterfaceDown();
    +-        usbTeardownOrder.verify(mNMService).setInterfaceConfig(
    +-                IFACE_NAME, mInterfaceConfiguration);
    +-        usbTeardownOrder.verify(mTetherHelper).notifyInterfaceStateChange(
    +-                IFACE_NAME, mTestedSm, STATE_AVAILABLE, TETHER_ERROR_TETHER_IFACE_ERROR);
    +-    }
    +-
    +-    @Test
    +-    public void shouldTearDownUsbOnUpstreamError() throws Exception {
    +-        initTetheredStateMachine(ConnectivityManager.TETHERING_USB, null);
    +-
    +-        doThrow(RemoteException.class).when(mNMService).enableNat(anyString(), anyString());
    +-        dispatchTetherConnectionChanged(UPSTREAM_IFACE);
    +-        InOrder usbTeardownOrder = inOrder(mNMService, mInterfaceConfiguration, mTetherHelper);
    +-        usbTeardownOrder.verify(mInterfaceConfiguration).setInterfaceDown();
    +-        usbTeardownOrder.verify(mNMService).setInterfaceConfig(IFACE_NAME, mInterfaceConfiguration);
    +-        usbTeardownOrder.verify(mTetherHelper).notifyInterfaceStateChange(
    +-                IFACE_NAME, mTestedSm, STATE_AVAILABLE, TETHER_ERROR_ENABLE_NAT_ERROR);
    +-    }
    +-
    +-    /**
    +-     * Send a command to the state machine under test, and run the event loop to idle.
    +-     *
    +-     * @param command One of the TetherInterfaceStateMachine.CMD_* constants.
    +-     */
    +-    private void dispatchCommand(int command) {
    +-        mTestedSm.sendMessage(command);
    +-        mLooper.dispatchAll();
    +-    }
    +-
    +-    /**
    +-     * Special override to tell the state machine that the upstream interface has changed.
    +-     *
    +-     * @see #dispatchCommand(int)
    +-     * @param upstreamIface String name of upstream interface (or null)
    +-     */
    +-    private void dispatchTetherConnectionChanged(String upstreamIface) {
    +-        mTestedSm.sendMessage(TetherInterfaceStateMachine.CMD_TETHER_CONNECTION_CHANGED,
    +-                upstreamIface);
    +-        mLooper.dispatchAll();
    +-    }
    +-}
    +\ No newline at end of file
    +diff --git a/services/tests/servicestests/src/com/android/server/content/ObserverNodeTest.java b/services/tests/servicestests/src/com/android/server/content/ObserverNodeTest.java
    +deleted file mode 100644
    +index 07280bc..0000000
    +--- a/services/tests/servicestests/src/com/android/server/content/ObserverNodeTest.java
    ++++ /dev/null
    +@@ -1,100 +0,0 @@
    +-/*
    +- * Copyright (C) 2007 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 com.android.server.content;
    +-
    +-import java.util.ArrayList;
    +-
    +-import android.database.ContentObserver;
    +-import android.net.Uri;
    +-import android.os.Handler;
    +-import android.os.UserHandle;
    +-import android.test.AndroidTestCase;
    +-
    +-import com.android.server.content.ContentService.ObserverCall;
    +-import com.android.server.content.ContentService.ObserverNode;
    +-
    +-public class ObserverNodeTest extends AndroidTestCase {
    +-    static class TestObserver  extends ContentObserver {
    +-        public TestObserver() {
    +-            super(new Handler());
    +-        }
    +-    }
    +-
    +-    public void testUri() {
    +-        final int myUserHandle = UserHandle.myUserId();
    +-
    +-        ObserverNode root = new ObserverNode("");
    +-        Uri[] uris = new Uri[] {
    +-            Uri.parse("content://c/a/"),
    +-            Uri.parse("content://c/"),
    +-            Uri.parse("content://x/"),
    +-            Uri.parse("content://c/b/"),
    +-            Uri.parse("content://c/a/a1/1/"),
    +-            Uri.parse("content://c/a/a1/2/"),
    +-            Uri.parse("content://c/b/1/"),
    +-            Uri.parse("content://c/b/2/"),
    +-        };
    +-
    +-        int[] nums = new int[] {4, 7, 1, 4, 2, 2, 3, 3};
    +-
    +-        // special case
    +-        root.addObserverLocked(uris[0], new TestObserver().getContentObserver(), false, root,
    +-                0, 0, myUserHandle);
    +-        for(int i = 1; i < uris.length; i++) {
    +-            root.addObserverLocked(uris[i], new TestObserver().getContentObserver(), true, root,
    +-                    0, 0, myUserHandle);
    +-        }
    +-
    +-        ArrayList<ObserverCall> calls = new ArrayList<ObserverCall>();
    +-
    +-        for (int i = nums.length - 1; i >=0; --i) {
    +-            root.collectObserversLocked(uris[i], 0, null, false, 0, myUserHandle, calls);
    +-            assertEquals(nums[i], calls.size());
    +-            calls.clear();
    +-        }
    +-    }
    +-
    +-    public void testUriNotNotify() {
    +-        final int myUserHandle = UserHandle.myUserId();
    +-
    +-        ObserverNode root = new ObserverNode("");
    +-        Uri[] uris = new Uri[] {
    +-            Uri.parse("content://c/"),
    +-            Uri.parse("content://x/"),
    +-            Uri.parse("content://c/a/"),
    +-            Uri.parse("content://c/b/"),
    +-            Uri.parse("content://c/a/1/"),
    +-            Uri.parse("content://c/a/2/"),
    +-            Uri.parse("content://c/b/1/"),
    +-            Uri.parse("content://c/b/2/"),
    +-        };
    +-        int[] nums = new int[] {7, 1, 3, 3, 1, 1, 1, 1};
    +-
    +-        for(int i = 0; i < uris.length; i++) {
    +-            root.addObserverLocked(uris[i], new TestObserver().getContentObserver(), false, root,
    +-                    0, 0, myUserHandle);
    +-        }
    +-
    +-        ArrayList<ObserverCall> calls = new ArrayList<ObserverCall>();
    +-
    +-        for (int i = uris.length - 1; i >=0; --i) {
    +-            root.collectObserversLocked(uris[i], 0, null, false, 0, myUserHandle, calls);
    +-            assertEquals(nums[i], calls.size());
    +-            calls.clear();
    +-        }
    +-    }
    +-}
    +diff --git a/services/tests/servicestests/src/com/android/server/content/SyncManagerTest.java b/services/tests/servicestests/src/com/android/server/content/SyncManagerTest.java
    +deleted file mode 100644
    +index be6861c..0000000
    +--- a/services/tests/servicestests/src/com/android/server/content/SyncManagerTest.java
    ++++ /dev/null
    +@@ -1,64 +0,0 @@
    +-package com.android.server.content;
    +-
    +-import android.os.Bundle;
    +-
    +-import junit.framework.TestCase;
    +-
    +-public class SyncManagerTest extends TestCase {
    +-
    +-    final String KEY_1 = "key_1";
    +-    final String KEY_2 = "key_2";
    +-
    +-    public void testSyncExtrasEquals_WithNull() throws Exception {
    +-        Bundle b1 = new Bundle();
    +-        Bundle b2 = new Bundle();
    +-
    +-        b1.putString(KEY_1, null);
    +-        b2.putString(KEY_1, null);
    +-
    +-        assertTrue("Null extra not properly compared between bundles.",
    +-                SyncManager.syncExtrasEquals(b1, b2, false /* don't care about system extras */));
    +-    }
    +-
    +-    public void testSyncExtrasEqualsBigger_WithNull() throws Exception {
    +-        Bundle b1 = new Bundle();
    +-        Bundle b2 = new Bundle();
    +-
    +-        b1.putString(KEY_1, null);
    +-        b2.putString(KEY_1, null);
    +-
    +-        b1.putString(KEY_2, "bla");
    +-        b2.putString(KEY_2, "bla");
    +-
    +-        assertTrue("Extras not properly compared between bundles.",
    +-                SyncManager.syncExtrasEquals(b1, b2, false /* don't care about system extras */));
    +-    }
    +-
    +-    public void testSyncExtrasEqualsFails_differentValues() throws Exception {
    +-        Bundle b1 = new Bundle();
    +-        Bundle b2 = new Bundle();
    +-
    +-        b1.putString(KEY_1, null);
    +-        b2.putString(KEY_1, null);
    +-
    +-        b1.putString(KEY_2, "bla");
    +-        b2.putString(KEY_2, "ble");  // different key
    +-
    +-        assertFalse("Extras considered equal when they are different.",
    +-                SyncManager.syncExtrasEquals(b1, b2, false /* don't care about system extras */));
    +-    }
    +-
    +-    public void testSyncExtrasEqualsFails_differentNulls() throws Exception {
    +-        Bundle b1 = new Bundle();
    +-        Bundle b2 = new Bundle();
    +-
    +-        b1.putString(KEY_1, null);
    +-        b2.putString(KEY_1, "bla");  // different key
    +-
    +-        b1.putString(KEY_2, "ble");
    +-        b2.putString(KEY_2, "ble");
    +-
    +-        assertFalse("Extras considered equal when they are different.",
    +-                SyncManager.syncExtrasEquals(b1, b2, false /* don't care about system extras */));
    +-    }
    +-}
    +diff --git a/services/tests/servicestests/src/com/android/server/content/SyncOperationTest.java b/services/tests/servicestests/src/com/android/server/content/SyncOperationTest.java
    +deleted file mode 100644
    +index e45b92a..0000000
    +--- a/services/tests/servicestests/src/com/android/server/content/SyncOperationTest.java
    ++++ /dev/null
    +@@ -1,154 +0,0 @@
    +-/*
    +- * Copyright (C) 2010 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 com.android.server.content;
    +-
    +-import android.accounts.Account;
    +-import android.content.ContentResolver;
    +-import android.content.Context;
    +-import android.os.Bundle;
    +-import android.os.PersistableBundle;
    +-import android.os.SystemClock;
    +-import android.provider.Settings;
    +-import android.test.AndroidTestCase;
    +-import android.test.suitebuilder.annotation.SmallTest;
    +-
    +-/**
    +- * You can run those tests with:
    +- *
    +- * adb shell am instrument
    +- * -e debug false
    +- * -w
    +- * -e class android.content.SyncOperationTest com.android.frameworks.coretests/android.test.InstrumentationTestRunner
    +- */
    +-
    +-public class SyncOperationTest extends AndroidTestCase {
    +-
    +-    Account mDummy;
    +-    /** Indicate an unimportant long that we're not testing. */
    +-    long mUnimportantLong = 0L;
    +-    /** Empty bundle. */
    +-    Bundle mEmpty;
    +-    /** Silly authority. */
    +-    String mAuthority;
    +-
    +-    @Override
    +-    public void setUp() {
    +-        mDummy = new Account("account1", "type1");
    +-        mEmpty = new Bundle();
    +-        mAuthority = "authority1";
    +-    }
    +-
    +-    @SmallTest
    +-    public void testToKey() {
    +-        Account account1 = new Account("account1", "type1");
    +-        Account account2 = new Account("account2", "type2");
    +-
    +-        Bundle b1 = new Bundle();
    +-        Bundle b2 = new Bundle();
    +-        b2.putBoolean("b2", true);
    +-
    +-        SyncOperation op1 = new SyncOperation(account1, 0,
    +-                1, "foo", 0,
    +-                SyncOperation.REASON_PERIODIC,
    +-                "authority1",
    +-                b1,
    +-                false);
    +-
    +-        // Same as op1 but different time infos
    +-        SyncOperation op2 = new SyncOperation(account1, 0,
    +-                1, "foo", 0,
    +-                SyncOperation.REASON_PERIODIC,
    +-                "authority1",
    +-                b1,
    +-                false);
    +-
    +-        // Same as op1 but different authority
    +-        SyncOperation op3 = new SyncOperation(account1, 0,
    +-                1, "foo", 0,
    +-                SyncOperation.REASON_PERIODIC,
    +-                "authority2",
    +-                b1,
    +-                false);
    +-
    +-        // Same as op1 but different account
    +-        SyncOperation op4 = new SyncOperation(account2, 0,
    +-                1, "foo", 0,
    +-                SyncOperation.REASON_PERIODIC,
    +-                "authority1",
    +-                b1,
    +-                false);
    +-
    +-        // Same as op1 but different bundle
    +-        SyncOperation op5 = new SyncOperation(account1, 0,
    +-                1, "foo", 0,
    +-                SyncOperation.REASON_PERIODIC,
    +-                "authority1",
    +-                b2,
    +-                false);
    +-
    +-        assertEquals(op1.key, op2.key);
    +-        assertNotSame(op1.key, op3.key);
    +-        assertNotSame(op1.key, op4.key);
    +-        assertNotSame(op1.key, op5.key);
    +-    }
    +-
    +-    @SmallTest
    +-    public void testConversionToExtras() {
    +-        Account account1 = new Account("account1", "type1");
    +-        Bundle b1 = new Bundle();
    +-        b1.putParcelable("acc", account1);
    +-        b1.putString("str", "String");
    +-
    +-        SyncOperation op1 = new SyncOperation(account1, 0,
    +-                1, "foo", 0,
    +-                SyncOperation.REASON_PERIODIC,
    +-                "authority1",
    +-                b1,
    +-                false);
    +-
    +-        PersistableBundle pb = op1.toJobInfoExtras();
    +-        SyncOperation op2 = SyncOperation.maybeCreateFromJobExtras(pb);
    +-
    +-        assertTrue("Account fields in extras not persisted.",
    +-                account1.equals(op2.extras.get("acc")));
    +-        assertTrue("Fields in extras not persisted", "String".equals(op2.extras.getString("str")));
    +-    }
    +-
    +-    @SmallTest
    +-    public void testConversionFromExtras() {
    +-        PersistableBundle extras = new PersistableBundle();
    +-        SyncOperation op = SyncOperation.maybeCreateFromJobExtras(extras);
    +-        assertTrue("Non sync operation bundle falsely converted to SyncOperation.", op == null);
    +-    }
    +-
    +-    /**
    +-     * Tests whether a failed periodic sync operation is converted correctly into a one time
    +-     * sync operation, and whether the periodic sync can be re-created from the one-time operation.
    +-     */
    +-    @SmallTest
    +-    public void testFailedPeriodicConversion() {
    +-        SyncStorageEngine.EndPoint ep = new SyncStorageEngine.EndPoint(new Account("name", "type"),
    +-                "provider", 0);
    +-        Bundle extras = new Bundle();
    +-        SyncOperation periodic = new SyncOperation(ep, 0, "package", 0, 0, extras, false, true,
    +-                SyncOperation.NO_JOB_ID, 60000, 10000);
    +-        SyncOperation oneoff = periodic.createOneTimeSyncOperation();
    +-        assertFalse("Conversion to oneoff sync failed.", oneoff.isPeriodic);
    +-        assertEquals("Period not restored", periodic.periodMillis, oneoff.periodMillis);
    +-        assertEquals("Flex not restored", periodic.flexMillis, oneoff.flexMillis);
    +-    }
    +-}
    +diff --git a/services/tests/servicestests/src/com/android/server/content/SyncStorageEngineTest.java b/services/tests/servicestests/src/com/android/server/content/SyncStorageEngineTest.java
    +deleted file mode 100644
    +index 91c0de6..0000000
    +--- a/services/tests/servicestests/src/com/android/server/content/SyncStorageEngineTest.java
    ++++ /dev/null
    +@@ -1,343 +0,0 @@
    +-/*
    +- * Copyright (C) 2007 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 com.android.server.content;
    +-
    +-import android.accounts.Account;
    +-import android.content.ComponentName;
    +-import android.content.ContentResolver;
    +-import android.content.Context;
    +-import android.content.ContextWrapper;
    +-import android.content.Intent;
    +-import android.content.PeriodicSync;
    +-import android.content.res.Resources;
    +-import android.os.Bundle;
    +-import android.test.AndroidTestCase;
    +-import android.test.RenamingDelegatingContext;
    +-import android.test.mock.MockContentResolver;
    +-import android.test.mock.MockContext;
    +-import android.test.suitebuilder.annotation.LargeTest;
    +-import android.test.suitebuilder.annotation.MediumTest;
    +-import android.test.suitebuilder.annotation.SmallTest;
    +-
    +-import com.android.server.content.SyncStorageEngine.EndPoint;
    +-
    +-import com.android.internal.os.AtomicFile;
    +-
    +-import java.io.File;
    +-import java.io.FileOutputStream;
    +-import java.util.List;
    +-
    +-public class SyncStorageEngineTest extends AndroidTestCase {
    +-
    +-    protected Account account1;
    +-    protected Account account2;
    +-    protected ComponentName syncService1;
    +-    protected String authority1 = "testprovider";
    +-    protected Bundle defaultBundle;
    +-    protected final int DEFAULT_USER = 0;
    +-
    +-    /* Some default poll frequencies. */
    +-    final long dayPoll = (60 * 60 * 24);
    +-    final long dayFuzz = 60;
    +-    final long thousandSecs = 1000;
    +-    final long thousandSecsFuzz = 100;
    +-
    +-    MockContentResolver mockResolver;
    +-    SyncStorageEngine engine;
    +-
    +-    private File getSyncDir() {
    +-        return new File(new File(getContext().getFilesDir(), "system"), "sync");
    +-    }
    +-
    +-    @Override
    +-    public void setUp() {
    +-        account1 = new Account("a@example.com", "example.type");
    +-        account2 = new Account("b@example.com", "example.type");
    +-        syncService1 = new ComponentName("com.example", "SyncService");
    +-        // Default bundle.
    +-        defaultBundle = new Bundle();
    +-        defaultBundle.putInt("int_key", 0);
    +-        defaultBundle.putString("string_key", "hello");
    +-        // Set up storage engine.
    +-        mockResolver = new MockContentResolver();
    +-        engine = SyncStorageEngine.newTestInstance(
    +-                new TestContext(mockResolver, getContext()));
    +-    }
    +-
    +-    /**
    +-     * Test that we handle the case of a history row being old enough to purge before the
    +-     * corresponding sync is finished. This can happen if the clock changes while we are syncing.
    +-     *
    +-     */
    +-    // TODO: this test causes AidlTest to fail. Omit for now
    +-    // @SmallTest
    +-    public void testPurgeActiveSync() throws Exception {
    +-        final Account account = new Account("a@example.com", "example.type");
    +-        final String authority = "testprovider";
    +-
    +-        MockContentResolver mockResolver = new MockContentResolver();
    +-
    +-        SyncStorageEngine engine = SyncStorageEngine.newTestInstance(
    +-                new TestContext(mockResolver, getContext()));
    +-        long time0 = 1000;
    +-        SyncOperation op = new SyncOperation(account, 0, 0, "foo",
    +-                SyncOperation.REASON_PERIODIC,
    +-                SyncStorageEngine.SOURCE_LOCAL,
    +-                authority,
    +-                Bundle.EMPTY, true);
    +-        long historyId = engine.insertStartSyncEvent(op, time0);
    +-        long time1 = time0 + SyncStorageEngine.MILLIS_IN_4WEEKS * 2;
    +-        engine.stopSyncEvent(historyId, time1 - time0, "yay", 0, 0);
    +-    }
    +-
    +-    @LargeTest
    +-    public void testAuthorityPersistence() throws Exception {
    +-        final Account account1 = new Account("a@example.com", "example.type");
    +-        final Account account2 = new Account("b@example.com", "example.type.2");
    +-        final String authority1 = "testprovider1";
    +-        final String authority2 = "testprovider2";
    +-
    +-        engine.setMasterSyncAutomatically(false, 0);
    +-
    +-        engine.setIsSyncable(account1, 0, authority1, 1);
    +-        engine.setSyncAutomatically(account1, 0, authority1, true);
    +-
    +-        engine.setIsSyncable(account2, 0, authority1, 1);
    +-        engine.setSyncAutomatically(account2, 0, authority1, true);
    +-
    +-        engine.setIsSyncable(account1, 0, authority2, 1);
    +-        engine.setSyncAutomatically(account1, 0, authority2, false);
    +-
    +-        engine.setIsSyncable(account2, 0, authority2, 0);
    +-        engine.setSyncAutomatically(account2, 0, authority2, true);
    +-
    +-        engine.writeAllState();
    +-        engine.clearAndReadState();
    +-
    +-        assertEquals(true, engine.getSyncAutomatically(account1, 0, authority1));
    +-        assertEquals(true, engine.getSyncAutomatically(account2, 0, authority1));
    +-        assertEquals(false, engine.getSyncAutomatically(account1, 0, authority2));
    +-        assertEquals(true, engine.getSyncAutomatically(account2, 0, authority2));
    +-
    +-        assertEquals(1, engine.getIsSyncable(account1, 0, authority1));
    +-        assertEquals(1, engine.getIsSyncable(account2, 0, authority1));
    +-        assertEquals(1, engine.getIsSyncable(account1, 0, authority2));
    +-        assertEquals(0, engine.getIsSyncable(account2, 0, authority2));
    +-    }
    +-
    +-    @MediumTest
    +-    public void testListenForTicklesParsing() throws Exception {
    +-        byte[] accountsFileData = ("<?xml version='1.0' encoding='utf-8' standalone='yes' ?>\n"
    +-                + "<accounts>\n"
    +-                + "<listenForTickles user=\"0\" enabled=\"false\" />"
    +-                + "<listenForTickles user=\"1\" enabled=\"true\" />"
    +-                + "<authority id=\"0\" user=\"0\" account=\"account1\" type=\"type1\" authority=\"auth1\" />\n"
    +-                + "<authority id=\"1\" user=\"1\" account=\"account1\" type=\"type1\" authority=\"auth1\" />\n"
    +-                + "</accounts>\n").getBytes();
    +-
    +-        MockContentResolver mockResolver = new MockContentResolver();
    +-        final TestContext testContext = new TestContext(mockResolver, getContext());
    +-
    +-        File syncDir = getSyncDir();
    +-        syncDir.mkdirs();
    +-        AtomicFile accountInfoFile = new AtomicFile(new File(syncDir, "accounts.xml"));
    +-        FileOutputStream fos = accountInfoFile.startWrite();
    +-        fos.write(accountsFileData);
    +-        accountInfoFile.finishWrite(fos);
    +-
    +-        SyncStorageEngine engine = SyncStorageEngine.newTestInstance(testContext);
    +-
    +-        assertEquals(false, engine.getMasterSyncAutomatically(0));
    +-        assertEquals(true, engine.getMasterSyncAutomatically(1));
    +-        assertEquals(true, engine.getMasterSyncAutomatically(2));
    +-
    +-    }
    +-
    +-    @MediumTest
    +-    public void testAuthorityRenaming() throws Exception {
    +-        final Account account1 = new Account("acc1", "type1");
    +-        final Account account2 = new Account("acc2", "type2");
    +-        final String authorityContacts = "contacts";
    +-        final String authorityCalendar = "calendar";
    +-        final String authorityOther = "other";
    +-        final String authorityContactsNew = "com.android.contacts";
    +-        final String authorityCalendarNew = "com.android.calendar";
    +-
    +-        MockContentResolver mockResolver = new MockContentResolver();
    +-
    +-        final TestContext testContext = new TestContext(mockResolver, getContext());
    +-
    +-        byte[] accountsFileData = ("<?xml version='1.0' encoding='utf-8' standalone='yes' ?>\n"
    +-                + "<accounts>\n"
    +-                + "<authority id=\"0\" account=\"acc1\" type=\"type1\" authority=\"contacts\" />\n"
    +-                + "<authority id=\"1\" account=\"acc1\" type=\"type1\" authority=\"calendar\" />\n"
    +-                + "<authority id=\"2\" account=\"acc1\" type=\"type1\" authority=\"other\" />\n"
    +-                + "<authority id=\"3\" account=\"acc2\" type=\"type2\" authority=\"contacts\" />\n"
    +-                + "<authority id=\"4\" account=\"acc2\" type=\"type2\" authority=\"calendar\" />\n"
    +-                + "<authority id=\"5\" account=\"acc2\" type=\"type2\" authority=\"other\" />\n"
    +-                + "<authority id=\"6\" account=\"acc2\" type=\"type2\" enabled=\"false\""
    +-                + " authority=\"com.android.calendar\" />\n"
    +-                + "<authority id=\"7\" account=\"acc2\" type=\"type2\" enabled=\"false\""
    +-                + " authority=\"com.android.contacts\" />\n"
    +-                + "</accounts>\n").getBytes();
    +-
    +-        File syncDir = new File(new File(testContext.getFilesDir(), "system"), "sync");
    +-        syncDir.mkdirs();
    +-        AtomicFile accountInfoFile = new AtomicFile(new File(syncDir, "accounts.xml"));
    +-        FileOutputStream fos = accountInfoFile.startWrite();
    +-        fos.write(accountsFileData);
    +-        accountInfoFile.finishWrite(fos);
    +-
    +-        SyncStorageEngine engine = SyncStorageEngine.newTestInstance(testContext);
    +-
    +-        assertEquals(false, engine.getSyncAutomatically(account1, 0, authorityContacts));
    +-        assertEquals(false, engine.getSyncAutomatically(account1, 0, authorityCalendar));
    +-        assertEquals(true, engine.getSyncAutomatically(account1, 0, authorityOther));
    +-        assertEquals(true, engine.getSyncAutomatically(account1, 0, authorityContactsNew));
    +-        assertEquals(true, engine.getSyncAutomatically(account1, 0, authorityCalendarNew));
    +-
    +-        assertEquals(false, engine.getSyncAutomatically(account2, 0, authorityContacts));
    +-        assertEquals(false, engine.getSyncAutomatically(account2, 0, authorityCalendar));
    +-        assertEquals(true, engine.getSyncAutomatically(account2, 0, authorityOther));
    +-        assertEquals(false, engine.getSyncAutomatically(account2, 0, authorityContactsNew));
    +-        assertEquals(false, engine.getSyncAutomatically(account2, 0, authorityCalendarNew));
    +-    }
    +-
    +-    @SmallTest
    +-    public void testSyncableMigration() throws Exception {
    +-        final Account account = new Account("acc", "type");
    +-
    +-        MockContentResolver mockResolver = new MockContentResolver();
    +-
    +-        final TestContext testContext = new TestContext(mockResolver, getContext());
    +-
    +-        byte[] accountsFileData = ("<?xml version='1.0' encoding='utf-8' standalone='yes' ?>\n"
    +-                + "<accounts>\n"
    +-                + "<authority id=\"0\" account=\"acc\" authority=\"other1\" />\n"
    +-                + "<authority id=\"1\" account=\"acc\" type=\"type\" authority=\"other2\" />\n"
    +-                + "<authority id=\"2\" account=\"acc\" type=\"type\" syncable=\"false\""
    +-                + " authority=\"other3\" />\n"
    +-                + "<authority id=\"3\" account=\"acc\" type=\"type\" syncable=\"true\""
    +-                + " authority=\"other4\" />\n"
    +-                + "</accounts>\n").getBytes();
    +-
    +-        File syncDir = new File(new File(testContext.getFilesDir(), "system"), "sync");
    +-        syncDir.mkdirs();
    +-        AtomicFile accountInfoFile = new AtomicFile(new File(syncDir, "accounts.xml"));
    +-        FileOutputStream fos = accountInfoFile.startWrite();
    +-        fos.write(accountsFileData);
    +-        accountInfoFile.finishWrite(fos);
    +-
    +-        SyncStorageEngine engine = SyncStorageEngine.newTestInstance(testContext);
    +-
    +-        assertEquals(-1, engine.getIsSyncable(account, 0, "other1"));
    +-        assertEquals(1, engine.getIsSyncable(account, 0, "other2"));
    +-        assertEquals(0, engine.getIsSyncable(account, 0, "other3"));
    +-        assertEquals(1, engine.getIsSyncable(account, 0, "other4"));
    +-    }
    +-
    +-    /**
    +-     * Verify that the API cannot cause a run-time reboot by passing in the empty string as an
    +-     * authority. The problem here is that
    +-     * {@link SyncStorageEngine#getOrCreateAuthorityLocked(account, provider)} would register
    +-     * an empty authority which causes a RTE in {@link SyncManager#scheduleReadyPeriodicSyncs()}.
    +-     * This is not strictly a SSE test, but it does depend on the SSE data structures.
    +-     */
    +-    @SmallTest
    +-    public void testExpectedIllegalArguments() throws Exception {
    +-        try {
    +-            ContentResolver.setSyncAutomatically(account1, "", true);
    +-            fail("empty provider string should throw IllegalArgumentException");
    +-        } catch (IllegalArgumentException expected) {}
    +-
    +-        try {
    +-            ContentResolver.addPeriodicSync(account1, "", Bundle.EMPTY, 84000L);
    +-            fail("empty provider string should throw IllegalArgumentException");
    +-        } catch (IllegalArgumentException expected) {}
    +-
    +-        try {
    +-            ContentResolver.removePeriodicSync(account1, "", Bundle.EMPTY);
    +-            fail("empty provider string should throw IllegalArgumentException");
    +-        } catch (IllegalArgumentException expected) {}
    +-
    +-        try {
    +-            ContentResolver.cancelSync(account1, "");
    +-            fail("empty provider string should throw IllegalArgumentException");
    +-        } catch (IllegalArgumentException expected) {}
    +-
    +-        try {
    +-            ContentResolver.setIsSyncable(account1, "", 0);
    +-            fail("empty provider string should throw IllegalArgumentException");
    +-        } catch (IllegalArgumentException expected) {}
    +-
    +-        try {
    +-            ContentResolver.cancelSync(account1, "");
    +-            fail("empty provider string should throw IllegalArgumentException");
    +-        } catch (IllegalArgumentException expected) {}
    +-
    +-        try {
    +-            ContentResolver.requestSync(account1, "", Bundle.EMPTY);
    +-            fail("empty provider string should throw IllegalArgumentException");
    +-        } catch (IllegalArgumentException expected) {}
    +-
    +-        try {
    +-            ContentResolver.getSyncStatus(account1, "");
    +-            fail("empty provider string should throw IllegalArgumentException");
    +-        } catch (IllegalArgumentException expected) {}
    +-
    +-        // Make sure we aren't blocking null account/provider for those functions that use it
    +-        // to specify ALL accounts/providers.
    +-        ContentResolver.requestSync(null, null, Bundle.EMPTY);
    +-        ContentResolver.cancelSync(null, null);
    +-    }
    +-}
    +-
    +-class TestContext extends ContextWrapper {
    +-
    +-    ContentResolver mResolver;
    +-
    +-    private final Context mRealContext;
    +-
    +-    public TestContext(ContentResolver resolver, Context realContext) {
    +-        super(new RenamingDelegatingContext(new MockContext(), realContext, "test."));
    +-        mRealContext = realContext;
    +-        mResolver = resolver;
    +-    }
    +-
    +-    @Override
    +-    public Resources getResources() {
    +-        return mRealContext.getResources();
    +-    }
    +-
    +-    @Override
    +-    public File getFilesDir() {
    +-        return mRealContext.getFilesDir();
    +-    }
    +-
    +-    @Override
    +-    public void enforceCallingOrSelfPermission(String permission, String message) {
    +-    }
    +-
    +-    @Override
    +-    public void sendBroadcast(Intent intent) {
    +-    }
    +-
    +-    @Override
    +-    public ContentResolver getContentResolver() {
    +-        return mResolver;
    +-    }
    +-}
    +diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerServiceMigrationTest.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerServiceMigrationTest.java
    +deleted file mode 100644
    +index 3a6b983..0000000
    +--- a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerServiceMigrationTest.java
    ++++ /dev/null
    +@@ -1,280 +0,0 @@
    +-/*
    +- * Copyright (C) 2015 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 com.android.server.devicepolicy;
    +-
    +-import com.android.server.LocalServices;
    +-import com.android.server.SystemService;
    +-import com.android.server.devicepolicy.DevicePolicyManagerServiceTestable.OwnersTestable;
    +-
    +-import android.app.admin.DevicePolicyManager;
    +-import android.app.admin.DevicePolicyManagerInternal;
    +-import android.content.pm.PackageManager;
    +-import android.content.pm.UserInfo;
    +-import android.os.Bundle;
    +-import android.os.UserHandle;
    +-import android.os.UserManager;
    +-import android.util.Pair;
    +-
    +-import org.mockito.invocation.InvocationOnMock;
    +-import org.mockito.stubbing.Answer;
    +-
    +-import java.io.File;
    +-import java.util.HashMap;
    +-import java.util.Map;
    +-
    +-import static org.mockito.Matchers.any;
    +-import static org.mockito.Matchers.anyInt;
    +-import static org.mockito.Matchers.eq;
    +-import static org.mockito.Mockito.doAnswer;
    +-import static org.mockito.Mockito.when;
    +-
    +-public class DevicePolicyManagerServiceMigrationTest extends DpmTestBase {
    +-    private DpmMockContext mContext;
    +-
    +-    @Override
    +-    protected void setUp() throws Exception {
    +-        super.setUp();
    +-
    +-        mContext = getContext();
    +-
    +-        when(mContext.packageManager.hasSystemFeature(eq(PackageManager.FEATURE_DEVICE_ADMIN)))
    +-                .thenReturn(true);
    +-    }
    +-
    +-    public void testMigration() throws Exception {
    +-        final File user10dir = mMockContext.addUser(10, 0);
    +-        final File user11dir = mMockContext.addUser(11, UserInfo.FLAG_MANAGED_PROFILE);
    +-        final File user12dir = mMockContext.addUser(12, 0);
    +-
    +-        setUpPackageManagerForAdmin(admin1, DpmMockContext.CALLER_SYSTEM_USER_UID);
    +-        setUpPackageManagerForAdmin(admin2, UserHandle.getUid(10, 123));
    +-        setUpPackageManagerForAdmin(admin3, UserHandle.getUid(11, 456));
    +-
    +-        // Create the legacy owners & policies file.
    +-        DpmTestUtils.writeToFile(
    +-                (new File(mContext.dataDir, OwnersTestable.LEGACY_FILE)).getAbsoluteFile(),
    +-                DpmTestUtils.readAsset(mRealTestContext,
    +-                        "DevicePolicyManagerServiceMigrationTest/legacy_device_owner.xml"));
    +-
    +-        DpmTestUtils.writeToFile(
    +-                (new File(mContext.systemUserDataDir, "device_policies.xml")).getAbsoluteFile(),
    +-                DpmTestUtils.readAsset(mRealTestContext,
    +-                        "DevicePolicyManagerServiceMigrationTest/legacy_device_policies.xml"));
    +-
    +-        DpmTestUtils.writeToFile(
    +-                (new File(user10dir, "device_policies.xml")).getAbsoluteFile(),
    +-                DpmTestUtils.readAsset(mRealTestContext,
    +-                        "DevicePolicyManagerServiceMigrationTest/legacy_device_policies_10.xml"));
    +-        DpmTestUtils.writeToFile(
    +-                (new File(user11dir, "device_policies.xml")).getAbsoluteFile(),
    +-                DpmTestUtils.readAsset(mRealTestContext,
    +-                        "DevicePolicyManagerServiceMigrationTest/legacy_device_policies_11.xml"));
    +-
    +-        // Set up UserManager
    +-        when(mMockContext.userManagerInternal.getBaseUserRestrictions(
    +-                eq(UserHandle.USER_SYSTEM))).thenReturn(DpmTestUtils.newRestrictions(
    +-                UserManager.DISALLOW_ADD_USER,
    +-                UserManager.DISALLOW_RECORD_AUDIO));
    +-
    +-        when(mMockContext.userManagerInternal.getBaseUserRestrictions(
    +-                eq(10))).thenReturn(DpmTestUtils.newRestrictions(
    +-                UserManager.DISALLOW_REMOVE_USER,
    +-                UserManager.DISALLOW_ADD_USER,
    +-                UserManager.DISALLOW_SMS,
    +-                UserManager.DISALLOW_OUTGOING_CALLS,
    +-                UserManager.DISALLOW_WALLPAPER,
    +-                UserManager.DISALLOW_RECORD_AUDIO));
    +-
    +-        when(mMockContext.userManagerInternal.getBaseUserRestrictions(
    +-                eq(11))).thenReturn(DpmTestUtils.newRestrictions(
    +-                UserManager.DISALLOW_REMOVE_USER,
    +-                UserManager.DISALLOW_ADD_USER,
    +-                UserManager.DISALLOW_SMS,
    +-                UserManager.DISALLOW_OUTGOING_CALLS,
    +-                UserManager.DISALLOW_WALLPAPER,
    +-                UserManager.DISALLOW_RECORD_AUDIO));
    +-
    +-        final Map<Integer, Bundle> newBaseRestrictions = new HashMap<>();
    +-
    +-        doAnswer(new Answer<Void>() {
    +-            @Override
    +-            public Void answer(InvocationOnMock invocation) throws Throwable {
    +-                Integer userId = (Integer) invocation.getArguments()[0];
    +-                Bundle bundle = (Bundle) invocation.getArguments()[1];
    +-
    +-                newBaseRestrictions.put(userId, bundle);
    +-
    +-                return null;
    +-            }
    +-        }).when(mContext.userManagerInternal).setBaseUserRestrictionsByDpmsForMigration(
    +-                anyInt(), any(Bundle.class));
    +-
    +-        // Initialize DPM/DPMS and let it migrate the persisted information.
    +-        // (Need clearCallingIdentity() to pass permission checks.)
    +-
    +-        final DevicePolicyManagerServiceTestable dpms;
    +-
    +-        final long ident = mContext.binder.clearCallingIdentity();
    +-        try {
    +-            LocalServices.removeServiceForTest(DevicePolicyManagerInternal.class);
    +-
    +-            dpms = new DevicePolicyManagerServiceTestable(mContext, dataDir);
    +-
    +-            dpms.systemReady(SystemService.PHASE_LOCK_SETTINGS_READY);
    +-            dpms.systemReady(SystemService.PHASE_BOOT_COMPLETED);
    +-        } finally {
    +-            mContext.binder.restoreCallingIdentity(ident);
    +-        }
    +-
    +-        assertTrue(dpms.mOwners.hasDeviceOwner());
    +-        assertFalse(dpms.mOwners.hasProfileOwner(UserHandle.USER_SYSTEM));
    +-        assertTrue(dpms.mOwners.hasProfileOwner(10));
    +-        assertTrue(dpms.mOwners.hasProfileOwner(11));
    +-        assertFalse(dpms.mOwners.hasProfileOwner(12));
    +-
    +-        // Now all information should be migrated.
    +-        assertFalse(dpms.mOwners.getDeviceOwnerUserRestrictionsNeedsMigration());
    +-        assertFalse(dpms.mOwners.getProfileOwnerUserRestrictionsNeedsMigration(
    +-                UserHandle.USER_SYSTEM));
    +-        assertFalse(dpms.mOwners.getProfileOwnerUserRestrictionsNeedsMigration(10));
    +-        assertFalse(dpms.mOwners.getProfileOwnerUserRestrictionsNeedsMigration(11));
    +-        assertFalse(dpms.mOwners.getProfileOwnerUserRestrictionsNeedsMigration(12));
    +-
    +-        // Check the new base restrictions.
    +-        DpmTestUtils.assertRestrictions(
    +-                DpmTestUtils.newRestrictions(
    +-                        UserManager.DISALLOW_RECORD_AUDIO
    +-                ),
    +-                newBaseRestrictions.get(UserHandle.USER_SYSTEM));
    +-
    +-        DpmTestUtils.assertRestrictions(
    +-                DpmTestUtils.newRestrictions(
    +-                        UserManager.DISALLOW_ADD_USER,
    +-                        UserManager.DISALLOW_SMS,
    +-                        UserManager.DISALLOW_OUTGOING_CALLS,
    +-                        UserManager.DISALLOW_RECORD_AUDIO,
    +-                        UserManager.DISALLOW_WALLPAPER
    +-                ),
    +-                newBaseRestrictions.get(10));
    +-
    +-        DpmTestUtils.assertRestrictions(
    +-                DpmTestUtils.newRestrictions(
    +-                        UserManager.DISALLOW_ADD_USER,
    +-                        UserManager.DISALLOW_SMS,
    +-                        UserManager.DISALLOW_OUTGOING_CALLS,
    +-                        UserManager.DISALLOW_WALLPAPER,
    +-                        UserManager.DISALLOW_RECORD_AUDIO
    +-                ),
    +-                newBaseRestrictions.get(11));
    +-
    +-        // Check the new owner restrictions.
    +-        DpmTestUtils.assertRestrictions(
    +-                DpmTestUtils.newRestrictions(
    +-                        UserManager.DISALLOW_ADD_USER
    +-                ),
    +-                dpms.getDeviceOwnerAdminLocked().ensureUserRestrictions());
    +-
    +-        DpmTestUtils.assertRestrictions(
    +-                DpmTestUtils.newRestrictions(
    +-                        UserManager.DISALLOW_REMOVE_USER
    +-                ),
    +-                dpms.getProfileOwnerAdminLocked(10).ensureUserRestrictions());
    +-
    +-        DpmTestUtils.assertRestrictions(
    +-                DpmTestUtils.newRestrictions(
    +-                        UserManager.DISALLOW_REMOVE_USER
    +-                ),
    +-                dpms.getProfileOwnerAdminLocked(11).ensureUserRestrictions());
    +-    }
    +-
    +-    public void testMigration2_profileOwnerOnUser0() throws Exception {
    +-        setUpPackageManagerForAdmin(admin2, DpmMockContext.CALLER_SYSTEM_USER_UID);
    +-
    +-        // Create the legacy owners & policies file.
    +-        DpmTestUtils.writeToFile(
    +-                (new File(mContext.dataDir, OwnersTestable.LEGACY_FILE)).getAbsoluteFile(),
    +-                DpmTestUtils.readAsset(mRealTestContext,
    +-                        "DevicePolicyManagerServiceMigrationTest2/legacy_device_owner.xml"));
    +-
    +-        DpmTestUtils.writeToFile(
    +-                (new File(mContext.systemUserDataDir, "device_policies.xml")).getAbsoluteFile(),
    +-                DpmTestUtils.readAsset(mRealTestContext,
    +-                        "DevicePolicyManagerServiceMigrationTest2/legacy_device_policies.xml"));
    +-
    +-        // Set up UserManager
    +-        when(mMockContext.userManagerInternal.getBaseUserRestrictions(
    +-                eq(UserHandle.USER_SYSTEM))).thenReturn(DpmTestUtils.newRestrictions(
    +-                UserManager.DISALLOW_ADD_USER,
    +-                UserManager.DISALLOW_RECORD_AUDIO,
    +-                UserManager.DISALLOW_SMS,
    +-                UserManager.DISALLOW_OUTGOING_CALLS));
    +-
    +-        final Map<Integer, Bundle> newBaseRestrictions = new HashMap<>();
    +-
    +-        doAnswer(new Answer<Void>() {
    +-            @Override
    +-            public Void answer(InvocationOnMock invocation) throws Throwable {
    +-                Integer userId = (Integer) invocation.getArguments()[0];
    +-                Bundle bundle = (Bundle) invocation.getArguments()[1];
    +-
    +-                newBaseRestrictions.put(userId, bundle);
    +-
    +-                return null;
    +-            }
    +-        }).when(mContext.userManagerInternal).setBaseUserRestrictionsByDpmsForMigration(
    +-                anyInt(), any(Bundle.class));
    +-
    +-        // Initialize DPM/DPMS and let it migrate the persisted information.
    +-        // (Need clearCallingIdentity() to pass permission checks.)
    +-
    +-        final DevicePolicyManagerServiceTestable dpms;
    +-
    +-        final long ident = mContext.binder.clearCallingIdentity();
    +-        try {
    +-            LocalServices.removeServiceForTest(DevicePolicyManagerInternal.class);
    +-
    +-            dpms = new DevicePolicyManagerServiceTestable(mContext, dataDir);
    +-
    +-            dpms.systemReady(SystemService.PHASE_LOCK_SETTINGS_READY);
    +-            dpms.systemReady(SystemService.PHASE_BOOT_COMPLETED);
    +-        } finally {
    +-            mContext.binder.restoreCallingIdentity(ident);
    +-        }
    +-        assertFalse(dpms.mOwners.hasDeviceOwner());
    +-        assertTrue(dpms.mOwners.hasProfileOwner(UserHandle.USER_SYSTEM));
    +-
    +-        // Now all information should be migrated.
    +-        assertFalse(dpms.mOwners.getDeviceOwnerUserRestrictionsNeedsMigration());
    +-        assertFalse(dpms.mOwners.getProfileOwnerUserRestrictionsNeedsMigration(
    +-                UserHandle.USER_SYSTEM));
    +-
    +-        // Check the new base restrictions.
    +-        DpmTestUtils.assertRestrictions(
    +-                DpmTestUtils.newRestrictions(
    +-                        UserManager.DISALLOW_RECORD_AUDIO
    +-                ),
    +-                newBaseRestrictions.get(UserHandle.USER_SYSTEM));
    +-
    +-        // Check the new owner restrictions.
    +-        DpmTestUtils.assertRestrictions(
    +-                DpmTestUtils.newRestrictions(
    +-                        UserManager.DISALLOW_ADD_USER,
    +-                        UserManager.DISALLOW_SMS,
    +-                        UserManager.DISALLOW_OUTGOING_CALLS
    +-                ),
    +-                dpms.getProfileOwnerAdminLocked(UserHandle.USER_SYSTEM).ensureUserRestrictions());
    +-    }
    +-}
    +diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerServiceTestable.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerServiceTestable.java
    +deleted file mode 100644
    +index 6cb4a82..0000000
    +--- a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerServiceTestable.java
    ++++ /dev/null
    +@@ -1,361 +0,0 @@
    +-/*
    +- * Copyright (C) 2015 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 com.android.server.devicepolicy;
    +-
    +-import android.app.IActivityManager;
    +-import android.app.NotificationManager;
    +-import android.app.backup.IBackupManager;
    +-import android.content.pm.IPackageManager;
    +-import android.content.pm.PackageManagerInternal;
    +-import android.database.ContentObserver;
    +-import android.media.IAudioService;
    +-import android.net.Uri;
    +-import android.os.Looper;
    +-import android.os.PowerManagerInternal;
    +-import android.os.UserHandle;
    +-import android.os.UserManager;
    +-import android.os.UserManagerInternal;
    +-import android.telephony.TelephonyManager;
    +-import android.util.ArrayMap;
    +-import android.util.Pair;
    +-import android.view.IWindowManager;
    +-
    +-import com.android.internal.widget.LockPatternUtils;
    +-
    +-import java.io.File;
    +-import java.util.Map;
    +-
    +-/**
    +- * Overrides {@link #DevicePolicyManagerService} for dependency injection.
    +- */
    +-public class DevicePolicyManagerServiceTestable extends DevicePolicyManagerService {
    +-    /**
    +-     * Overrides {@link #Owners} for dependency injection.
    +-     */
    +-    public static class OwnersTestable extends Owners {
    +-        public static final String LEGACY_FILE = "legacy.xml";
    +-        public static final String DEVICE_OWNER_FILE = "device_owner2.xml";
    +-        public static final String PROFILE_OWNER_FILE_BASE = "profile_owner.xml";
    +-
    +-        private final File mLegacyFile;
    +-        private final File mDeviceOwnerFile;
    +-        private final File mProfileOwnerBase;
    +-
    +-        public OwnersTestable(DpmMockContext context) {
    +-            super(context.userManager, context.userManagerInternal, context.packageManagerInternal);
    +-            mLegacyFile = new File(context.dataDir, LEGACY_FILE);
    +-            mDeviceOwnerFile = new File(context.dataDir, DEVICE_OWNER_FILE);
    +-            mProfileOwnerBase = new File(context.dataDir, PROFILE_OWNER_FILE_BASE);
    +-        }
    +-
    +-        @Override
    +-        File getLegacyConfigFileWithTestOverride() {
    +-            return mLegacyFile;
    +-        }
    +-
    +-        @Override
    +-        File getDeviceOwnerFileWithTestOverride() {
    +-            return mDeviceOwnerFile;
    +-        }
    +-
    +-        @Override
    +-        File getProfileOwnerFileWithTestOverride(int userId) {
    +-            return new File(mDeviceOwnerFile.getAbsoluteFile() + "-" + userId);
    +-        }
    +-    }
    +-
    +-    public final DpmMockContext context;
    +-    private final MockInjector mMockInjector;
    +-
    +-    public DevicePolicyManagerServiceTestable(DpmMockContext context, File dataDir) {
    +-        this(new MockInjector(context, dataDir));
    +-    }
    +-
    +-    private DevicePolicyManagerServiceTestable(MockInjector injector) {
    +-        super(injector);
    +-        mMockInjector = injector;
    +-        this.context = injector.context;
    +-    }
    +-
    +-
    +-    public void notifyChangeToContentObserver(Uri uri, int userHandle) {
    +-        ContentObserver co = mMockInjector.mContentObservers
    +-                .get(new Pair<Uri, Integer>(uri, userHandle));
    +-        if (co != null) {
    +-            co.onChange(false, uri, userHandle); // notify synchronously
    +-        }
    +-
    +-        // Notify USER_ALL observer too.
    +-        co = mMockInjector.mContentObservers
    +-                .get(new Pair<Uri, Integer>(uri, UserHandle.USER_ALL));
    +-        if (co != null) {
    +-            co.onChange(false, uri, userHandle); // notify synchronously
    +-        }
    +-    }
    +-
    +-
    +-    private static class MockInjector extends Injector {
    +-
    +-        public final DpmMockContext context;
    +-
    +-        public final File dataDir;
    +-
    +-        // Key is a pair of uri and userId
    +-        private final Map<Pair<Uri, Integer>, ContentObserver> mContentObservers = new ArrayMap<>();
    +-
    +-        private MockInjector(DpmMockContext context, File dataDir) {
    +-            super(context);
    +-            this.context = context;
    +-            this.dataDir = dataDir;
    +-        }
    +-
    +-        @Override
    +-        Owners newOwners() {
    +-            return new OwnersTestable(context);
    +-        }
    +-
    +-        @Override
    +-        UserManager getUserManager() {
    +-            return context.userManager;
    +-        }
    +-
    +-        @Override
    +-        UserManagerInternal getUserManagerInternal() {
    +-            return context.userManagerInternal;
    +-        }
    +-
    +-        @Override
    +-        PackageManagerInternal getPackageManagerInternal() {
    +-            return context.packageManagerInternal;
    +-        }
    +-
    +-        @Override
    +-        PowerManagerInternal getPowerManagerInternal() {
    +-            return context.powerManagerInternal;
    +-        }
    +-
    +-        @Override
    +-        NotificationManager getNotificationManager() {
    +-            return context.notificationManager;
    +-        }
    +-
    +-        @Override
    +-        IWindowManager getIWindowManager() {
    +-            return context.iwindowManager;
    +-        }
    +-
    +-        @Override
    +-        IActivityManager getIActivityManager() {
    +-            return context.iactivityManager;
    +-        }
    +-
    +-        @Override
    +-        IPackageManager getIPackageManager() {
    +-            return context.ipackageManager;
    +-        }
    +-
    +-        @Override
    +-        IBackupManager getIBackupManager() {
    +-            return context.ibackupManager;
    +-        }
    +-
    +-        @Override
    +-        IAudioService getIAudioService() {
    +-            return context.iaudioService;
    +-        }
    +-
    +-        @Override
    +-        Looper getMyLooper() {
    +-            return Looper.getMainLooper();
    +-        }
    +-
    +-        @Override
    +-        LockPatternUtils newLockPatternUtils() {
    +-            return context.lockPatternUtils;
    +-        }
    +-
    +-        @Override
    +-        boolean storageManagerIsFileBasedEncryptionEnabled() {
    +-            return context.storageManager.isFileBasedEncryptionEnabled();
    +-        }
    +-
    +-        @Override
    +-        boolean storageManagerIsNonDefaultBlockEncrypted() {
    +-            return context.storageManager.isNonDefaultBlockEncrypted();
    +-        }
    +-
    +-        @Override
    +-        boolean storageManagerIsEncrypted() {
    +-            return context.storageManager.isEncrypted();
    +-        }
    +-
    +-        @Override
    +-        boolean storageManagerIsEncryptable() {
    +-            return context.storageManager.isEncryptable();
    +-        }
    +-
    +-        @Override
    +-        String getDevicePolicyFilePathForSystemUser() {
    +-            return context.systemUserDataDir.getAbsolutePath() + "/";
    +-        }
    +-
    +-        @Override
    +-        long binderClearCallingIdentity() {
    +-            return context.binder.clearCallingIdentity();
    +-        }
    +-
    +-        @Override
    +-        void binderRestoreCallingIdentity(long token) {
    +-            context.binder.restoreCallingIdentity(token);
    +-        }
    +-
    +-        @Override
    +-        int binderGetCallingUid() {
    +-            return context.binder.getCallingUid();
    +-        }
    +-
    +-        @Override
    +-        int binderGetCallingPid() {
    +-            return context.binder.getCallingPid();
    +-        }
    +-
    +-        @Override
    +-        UserHandle binderGetCallingUserHandle() {
    +-            return context.binder.getCallingUserHandle();
    +-        }
    +-
    +-        @Override
    +-        boolean binderIsCallingUidMyUid() {
    +-            return context.binder.isCallerUidMyUid();
    +-        }
    +-
    +-        @Override
    +-        File environmentGetUserSystemDirectory(int userId) {
    +-            return context.environment.getUserSystemDirectory(userId);
    +-        }
    +-
    +-        @Override
    +-        void powerManagerGoToSleep(long time, int reason, int flags) {
    +-            context.powerManager.goToSleep(time, reason, flags);
    +-        }
    +-
    +-        @Override
    +-        void powerManagerReboot(String reason) {
    +-            context.powerManager.reboot(reason);
    +-        }
    +-
    +-        @Override
    +-        boolean systemPropertiesGetBoolean(String key, boolean def) {
    +-            return context.systemProperties.getBoolean(key, def);
    +-        }
    +-
    +-        @Override
    +-        long systemPropertiesGetLong(String key, long def) {
    +-            return context.systemProperties.getLong(key, def);
    +-        }
    +-
    +-        @Override
    +-        String systemPropertiesGet(String key, String def) {
    +-            return context.systemProperties.get(key, def);
    +-        }
    +-
    +-        @Override
    +-        String systemPropertiesGet(String key) {
    +-            return context.systemProperties.get(key);
    +-        }
    +-
    +-        @Override
    +-        void systemPropertiesSet(String key, String value) {
    +-            context.systemProperties.set(key, value);
    +-        }
    +-
    +-        @Override
    +-        boolean userManagerIsSplitSystemUser() {
    +-            return context.userManagerForMock.isSplitSystemUser();
    +-        }
    +-
    +-        @Override
    +-        void registerContentObserver(Uri uri, boolean notifyForDescendents,
    +-                ContentObserver observer, int userHandle) {
    +-            mContentObservers.put(new Pair<Uri, Integer>(uri, userHandle), observer);
    +-        }
    +-
    +-        @Override
    +-        int settingsSecureGetIntForUser(String name, int def, int userHandle) {
    +-            return context.settings.settingsSecureGetIntForUser(name, def, userHandle);
    +-        }
    +-
    +-        @Override
    +-        void settingsSecurePutIntForUser(String name, int value, int userHandle) {
    +-            context.settings.settingsSecurePutIntForUser(name, value, userHandle);
    +-        }
    +-
    +-        @Override
    +-        void settingsSecurePutStringForUser(String name, String value, int userHandle) {
    +-            context.settings.settingsSecurePutStringForUser(name, value, userHandle);
    +-        }
    +-
    +-        @Override
    +-        void settingsGlobalPutStringForUser(String name, String value, int userHandle) {
    +-            context.settings.settingsGlobalPutStringForUser(name, value, userHandle);
    +-        }
    +-
    +-        @Override
    +-        void settingsSecurePutInt(String name, int value) {
    +-            context.settings.settingsSecurePutInt(name, value);
    +-        }
    +-
    +-        @Override
    +-        void settingsGlobalPutInt(String name, int value) {
    +-            context.settings.settingsGlobalPutInt(name, value);
    +-        }
    +-
    +-        @Override
    +-        void settingsSecurePutString(String name, String value) {
    +-            context.settings.settingsSecurePutString(name, value);
    +-        }
    +-
    +-        @Override
    +-        void settingsGlobalPutString(String name, String value) {
    +-            context.settings.settingsGlobalPutString(name, value);
    +-        }
    +-
    +-        @Override
    +-        int settingsGlobalGetInt(String name, int def) {
    +-            return context.settings.settingsGlobalGetInt(name, def);
    +-        }
    +-
    +-        @Override
    +-        void securityLogSetLoggingEnabledProperty(boolean enabled) {
    +-            context.settings.securityLogSetLoggingEnabledProperty(enabled);
    +-        }
    +-
    +-        @Override
    +-        boolean securityLogGetLoggingEnabledProperty() {
    +-            return context.settings.securityLogGetLoggingEnabledProperty();
    +-        }
    +-
    +-        @Override
    +-        boolean securityLogIsLoggingEnabled() {
    +-            return context.settings.securityLogIsLoggingEnabled();
    +-        }
    +-
    +-        @Override
    +-        TelephonyManager getTelephonyManager() {
    +-            return context.telephonyManager;
    +-        }
    +-    }
    +-}
    +diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
    +deleted file mode 100644
    +index 2d96bff..0000000
    +--- a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
    ++++ /dev/null
    +@@ -1,2131 +0,0 @@
    +-/*
    +- * Copyright (C) 2015 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 com.android.server.devicepolicy;
    +-
    +-import android.Manifest.permission;
    +-import android.app.Activity;
    +-import android.app.admin.DeviceAdminReceiver;
    +-import android.app.admin.DevicePolicyManager;
    +-import android.app.admin.DevicePolicyManagerInternal;
    +-import android.content.BroadcastReceiver;
    +-import android.content.ComponentName;
    +-import android.content.pm.ApplicationInfo;
    +-import android.content.pm.PackageInfo;
    +-import android.content.pm.PackageManager;
    +-import android.net.wifi.WifiInfo;
    +-import android.os.Build.VERSION_CODES;
    +-import android.os.Bundle;
    +-import android.os.Process;
    +-import android.os.UserHandle;
    +-import android.os.UserManager;
    +-import android.provider.Settings;
    +-import android.telephony.TelephonyManager;
    +-import android.test.MoreAsserts;
    +-import android.test.suitebuilder.annotation.SmallTest;
    +-import android.util.ArraySet;
    +-import android.util.Pair;
    +-
    +-import com.android.server.LocalServices;
    +-import com.android.server.SystemService;
    +-
    +-import org.mockito.invocation.InvocationOnMock;
    +-import org.mockito.stubbing.Answer;
    +-
    +-import java.util.ArrayList;
    +-import java.util.Arrays;
    +-import java.util.HashMap;
    +-import java.util.List;
    +-import java.util.Map;
    +-import java.util.Set;
    +-
    +-import static org.mockito.Matchers.any;
    +-import static org.mockito.Matchers.anyInt;
    +-import static org.mockito.Matchers.anyString;
    +-import static org.mockito.Matchers.eq;
    +-import static org.mockito.Matchers.isNull;
    +-import static org.mockito.Mockito.doAnswer;
    +-import static org.mockito.Mockito.doReturn;
    +-import static org.mockito.Mockito.reset;
    +-import static org.mockito.Mockito.times;
    +-import static org.mockito.Mockito.verify;
    +-import static org.mockito.Mockito.when;
    +-
    +-/**
    +- * Tests for DevicePolicyManager( and DevicePolicyManagerService).
    +- *
    +- m FrameworksServicesTests &&
    +- adb install \
    +-   -r ${ANDROID_PRODUCT_OUT}/data/app/FrameworksServicesTests/FrameworksServicesTests.apk &&
    +- adb shell am instrument -e class com.android.server.devicepolicy.DevicePolicyManagerTest \
    +-   -w com.android.frameworks.servicestests/android.support.test.runner.AndroidJUnitRunner
    +-
    +- (mmma frameworks/base/services/tests/servicestests/ for non-ninja build)
    +- */
    +-@SmallTest
    +-public class DevicePolicyManagerTest extends DpmTestBase {
    +-    private static final List<String> OWNER_SETUP_PERMISSIONS = Arrays.asList(
    +-            permission.MANAGE_DEVICE_ADMINS, permission.MANAGE_PROFILE_AND_DEVICE_OWNERS,
    +-            permission.MANAGE_USERS, permission.INTERACT_ACROSS_USERS_FULL);
    +-
    +-    private DpmMockContext mContext;
    +-    public DevicePolicyManager dpm;
    +-    public DevicePolicyManagerServiceTestable dpms;
    +-
    +-    @Override
    +-    protected void setUp() throws Exception {
    +-        super.setUp();
    +-
    +-        mContext = getContext();
    +-
    +-        when(mContext.packageManager.hasSystemFeature(eq(PackageManager.FEATURE_DEVICE_ADMIN)))
    +-                .thenReturn(true);
    +-
    +-        // By default, pretend all users are running and unlocked.
    +-        when(mContext.userManager.isUserUnlocked(anyInt())).thenReturn(true);
    +-
    +-        initializeDpms();
    +-
    +-        setUpPackageManagerForAdmin(admin1, DpmMockContext.CALLER_UID);
    +-        setUpPackageManagerForAdmin(admin2, DpmMockContext.CALLER_UID);
    +-        setUpPackageManagerForAdmin(admin3, DpmMockContext.CALLER_UID);
    +-        setUpPackageManagerForAdmin(adminNoPerm, DpmMockContext.CALLER_UID);
    +-
    +-        setUpUserManager();
    +-    }
    +-
    +-    private void initializeDpms() {
    +-        // Need clearCallingIdentity() to pass permission checks.
    +-        final long ident = mContext.binder.clearCallingIdentity();
    +-        try {
    +-            LocalServices.removeServiceForTest(DevicePolicyManagerInternal.class);
    +-
    +-            dpms = new DevicePolicyManagerServiceTestable(mContext, dataDir);
    +-
    +-            dpms.systemReady(SystemService.PHASE_LOCK_SETTINGS_READY);
    +-            dpms.systemReady(SystemService.PHASE_BOOT_COMPLETED);
    +-
    +-            dpm = new DevicePolicyManagerTestable(mContext, dpms);
    +-        } finally {
    +-            mContext.binder.restoreCallingIdentity(ident);
    +-        }
    +-    }
    +-
    +-    private void setUpUserManager() {
    +-        // Emulate UserManager.set/getApplicationRestriction().
    +-        final Map<Pair<String, UserHandle>, Bundle> appRestrictions = new HashMap<>();
    +-
    +-        // UM.setApplicationRestrictions() will save to appRestrictions.
    +-        doAnswer(new Answer<Void>() {
    +-            @Override
    +-            public Void answer(InvocationOnMock invocation) throws Throwable {
    +-                String pkg = (String) invocation.getArguments()[0];
    +-                Bundle bundle = (Bundle) invocation.getArguments()[1];
    +-                UserHandle user = (UserHandle) invocation.getArguments()[2];
    +-
    +-                appRestrictions.put(Pair.create(pkg, user), bundle);
    +-
    +-                return null;
    +-            }
    +-        }).when(mContext.userManager).setApplicationRestrictions(
    +-                anyString(), any(Bundle.class), any(UserHandle.class));
    +-
    +-        // UM.getApplicationRestrictions() will read from appRestrictions.
    +-        doAnswer(new Answer<Bundle>() {
    +-            @Override
    +-            public Bundle answer(InvocationOnMock invocation) throws Throwable {
    +-                String pkg = (String) invocation.getArguments()[0];
    +-                UserHandle user = (UserHandle) invocation.getArguments()[1];
    +-
    +-                return appRestrictions.get(Pair.create(pkg, user));
    +-            }
    +-        }).when(mContext.userManager).getApplicationRestrictions(
    +-                anyString(), any(UserHandle.class));
    +-
    +-        // Add the first secondary user.
    +-        mContext.addUser(DpmMockContext.CALLER_USER_HANDLE, 0);
    +-    }
    +-
    +-    private void setAsProfileOwner(ComponentName admin) {
    +-        mContext.callerPermissions.add(permission.MANAGE_DEVICE_ADMINS);
    +-        mContext.callerPermissions.add(permission.MANAGE_PROFILE_AND_DEVICE_OWNERS);
    +-
    +-        // PO needs to be an DA.
    +-        dpm.setActiveAdmin(admin, /* replace =*/ false);
    +-
    +-        // Fire!
    +-        assertTrue(dpm.setProfileOwner(admin, "owner-name", DpmMockContext.CALLER_USER_HANDLE));
    +-
    +-        // Check
    +-        assertEquals(admin, dpm.getProfileOwnerAsUser(DpmMockContext.CALLER_USER_HANDLE));
    +-    }
    +-
    +-    public void testHasNoFeature() throws Exception {
    +-        when(mContext.packageManager.hasSystemFeature(eq(PackageManager.FEATURE_DEVICE_ADMIN)))
    +-                .thenReturn(false);
    +-
    +-        LocalServices.removeServiceForTest(DevicePolicyManagerInternal.class);
    +-        new DevicePolicyManagerServiceTestable(mContext, dataDir);
    +-
    +-        // If the device has no DPMS feature, it shouldn't register the local service.
    +-        assertNull(LocalServices.getService(DevicePolicyManagerInternal.class));
    +-    }
    +-
    +-    /**
    +-     * Caller doesn't have proper permissions.
    +-     */
    +-    public void testSetActiveAdmin_SecurityException() {
    +-        // 1. Failure cases.
    +-
    +-        // Caller doesn't have MANAGE_DEVICE_ADMINS.
    +-        try {
    +-            dpm.setActiveAdmin(admin1, false);
    +-            fail("Didn't throw SecurityException");
    +-        } catch (SecurityException expected) {
    +-        }
    +-
    +-        // Caller has MANAGE_DEVICE_ADMINS, but for different user.
    +-        mContext.callerPermissions.add(android.Manifest.permission.MANAGE_DEVICE_ADMINS);
    +-        try {
    +-            dpm.setActiveAdmin(admin1, false, DpmMockContext.CALLER_USER_HANDLE + 1);
    +-            fail("Didn't throw SecurityException");
    +-        } catch (SecurityException expected) {
    +-        }
    +-    }
    +-
    +-    /**
    +-     * Test for:
    +-     * {@link DevicePolicyManager#setActiveAdmin}
    +-     * with replace=false and replace=true
    +-     * {@link DevicePolicyManager#isAdminActive}
    +-     * {@link DevicePolicyManager#isAdminActiveAsUser}
    +-     * {@link DevicePolicyManager#getActiveAdmins}
    +-     * {@link DevicePolicyManager#getActiveAdminsAsUser}
    +-     */
    +-    public void testSetActiveAdmin() throws Exception {
    +-        // 1. Make sure the caller has proper permissions.
    +-        mContext.callerPermissions.add(android.Manifest.permission.MANAGE_DEVICE_ADMINS);
    +-
    +-        // 2. Call the API.
    +-        dpm.setActiveAdmin(admin1, /* replace =*/ false);
    +-
    +-        // 3. Verify internal calls.
    +-
    +-        // Check if the boradcast is sent.
    +-        verify(mContext.spiedContext).sendBroadcastAsUser(
    +-                MockUtils.checkIntentAction(
    +-                        DevicePolicyManager.ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED),
    +-                MockUtils.checkUserHandle(DpmMockContext.CALLER_USER_HANDLE));
    +-        verify(mContext.spiedContext).sendBroadcastAsUser(
    +-                MockUtils.checkIntentAction(
    +-                        DeviceAdminReceiver.ACTION_DEVICE_ADMIN_ENABLED),
    +-                MockUtils.checkUserHandle(DpmMockContext.CALLER_USER_HANDLE));
    +-
    +-        verify(mContext.ipackageManager, times(1)).setApplicationEnabledSetting(
    +-                eq(admin1.getPackageName()),
    +-                eq(PackageManager.COMPONENT_ENABLED_STATE_DEFAULT),
    +-                eq(PackageManager.DONT_KILL_APP),
    +-                eq(DpmMockContext.CALLER_USER_HANDLE),
    +-                anyString());
    +-
    +-        // TODO Verify other calls too.
    +-
    +-        // Make sure it's active admin1.
    +-        assertTrue(dpm.isAdminActive(admin1));
    +-        assertFalse(dpm.isAdminActive(admin2));
    +-        assertFalse(dpm.isAdminActive(admin3));
    +-
    +-        // But not admin1 for a different user.
    +-
    +-        // For this to work, caller needs android.permission.INTERACT_ACROSS_USERS_FULL.
    +-        // (Because we're checking a different user's status from CALLER_USER_HANDLE.)
    +-        mContext.callerPermissions.add("android.permission.INTERACT_ACROSS_USERS_FULL");
    +-
    +-        assertFalse(dpm.isAdminActiveAsUser(admin1, DpmMockContext.CALLER_USER_HANDLE + 1));
    +-        assertFalse(dpm.isAdminActiveAsUser(admin2, DpmMockContext.CALLER_USER_HANDLE + 1));
    +-
    +-        mContext.callerPermissions.remove("android.permission.INTERACT_ACROSS_USERS_FULL");
    +-
    +-        // Next, add one more admin.
    +-        // Before doing so, update the application info, now it's enabled.
    +-        setUpPackageManagerForAdmin(admin2, DpmMockContext.CALLER_UID,
    +-                PackageManager.COMPONENT_ENABLED_STATE_ENABLED);
    +-
    +-        dpm.setActiveAdmin(admin2, /* replace =*/ false);
    +-
    +-        // Now we have two admins.
    +-        assertTrue(dpm.isAdminActive(admin1));
    +-        assertTrue(dpm.isAdminActive(admin2));
    +-        assertFalse(dpm.isAdminActive(admin3));
    +-
    +-        // Admin2 was already enabled, so setApplicationEnabledSetting() shouldn't have called
    +-        // again.  (times(1) because it was previously called for admin1)
    +-        verify(mContext.ipackageManager, times(1)).setApplicationEnabledSetting(
    +-                eq(admin1.getPackageName()),
    +-                eq(PackageManager.COMPONENT_ENABLED_STATE_DEFAULT),
    +-                eq(PackageManager.DONT_KILL_APP),
    +-                eq(DpmMockContext.CALLER_USER_HANDLE),
    +-                anyString());
    +-
    +-        // 4. Add the same admin1 again without replace, which should throw.
    +-        try {
    +-            dpm.setActiveAdmin(admin1, /* replace =*/ false);
    +-            fail("Didn't throw");
    +-        } catch (IllegalArgumentException expected) {
    +-        }
    +-
    +-        // 5. Add the same admin1 again with replace, which should succeed.
    +-        dpm.setActiveAdmin(admin1, /* replace =*/ true);
    +-
    +-        // TODO make sure it's replaced.
    +-
    +-        // 6. Test getActiveAdmins()
    +-        List<ComponentName> admins = dpm.getActiveAdmins();
    +-        assertEquals(2, admins.size());
    +-        assertEquals(admin1, admins.get(0));
    +-        assertEquals(admin2, admins.get(1));
    +-
    +-        // Another user has no admins.
    +-        mContext.callerPermissions.add("android.permission.INTERACT_ACROSS_USERS_FULL");
    +-
    +-        assertEquals(0, DpmTestUtils.getListSizeAllowingNull(
    +-                dpm.getActiveAdminsAsUser(DpmMockContext.CALLER_USER_HANDLE + 1)));
    +-
    +-        mContext.callerPermissions.remove("android.permission.INTERACT_ACROSS_USERS_FULL");
    +-    }
    +-
    +-    public void testSetActiveAdmin_multiUsers() throws Exception {
    +-
    +-        final int ANOTHER_USER_ID = 100;
    +-        final int ANOTHER_ADMIN_UID = UserHandle.getUid(ANOTHER_USER_ID, 20456);
    +-
    +-        mMockContext.addUser(ANOTHER_USER_ID, 0); // Add one more user.
    +-
    +-        // Set up pacakge manager for the other user.
    +-        setUpPackageManagerForAdmin(admin2, ANOTHER_ADMIN_UID);
    +-
    +-        mContext.callerPermissions.add(android.Manifest.permission.MANAGE_DEVICE_ADMINS);
    +-
    +-        dpm.setActiveAdmin(admin1, /* replace =*/ false);
    +-
    +-        mMockContext.binder.callingUid = ANOTHER_ADMIN_UID;
    +-        dpm.setActiveAdmin(admin2, /* replace =*/ false);
    +-
    +-
    +-        mMockContext.binder.callingUid = DpmMockContext.CALLER_UID;
    +-        assertTrue(dpm.isAdminActive(admin1));
    +-        assertFalse(dpm.isAdminActive(admin2));
    +-
    +-        mMockContext.binder.callingUid = ANOTHER_ADMIN_UID;
    +-        assertFalse(dpm.isAdminActive(admin1));
    +-        assertTrue(dpm.isAdminActive(admin2));
    +-    }
    +-
    +-    /**
    +-     * Test for:
    +-     * {@link DevicePolicyManager#setActiveAdmin}
    +-     * with replace=false
    +-     */
    +-    public void testSetActiveAdmin_twiceWithoutReplace() throws Exception {
    +-        // 1. Make sure the caller has proper permissions.
    +-        mContext.callerPermissions.add(android.Manifest.permission.MANAGE_DEVICE_ADMINS);
    +-
    +-        dpm.setActiveAdmin(admin1, /* replace =*/ false);
    +-        assertTrue(dpm.isAdminActive(admin1));
    +-
    +-        // Add the same admin1 again without replace, which should throw.
    +-        try {
    +-            dpm.setActiveAdmin(admin1, /* replace =*/ false);
    +-            fail("Didn't throw");
    +-        } catch (IllegalArgumentException expected) {
    +-        }
    +-    }
    +-
    +-    /**
    +-     * Test for:
    +-     * {@link DevicePolicyManager#setActiveAdmin} when the admin isn't protected with
    +-     * BIND_DEVICE_ADMIN.
    +-     */
    +-    public void testSetActiveAdmin_permissionCheck() throws Exception {
    +-        // 1. Make sure the caller has proper permissions.
    +-        mContext.callerPermissions.add(android.Manifest.permission.MANAGE_DEVICE_ADMINS);
    +-
    +-        try {
    +-            dpm.setActiveAdmin(adminNoPerm, /* replace =*/ false);
    +-            fail();
    +-        } catch (IllegalArgumentException expected) {
    +-            assertTrue(expected.getMessage().contains(permission.BIND_DEVICE_ADMIN));
    +-        }
    +-        assertFalse(dpm.isAdminActive(adminNoPerm));
    +-
    +-        // Change the target API level to MNC.  Now it can be set as DA.
    +-        setUpPackageManagerForAdmin(adminNoPerm, DpmMockContext.CALLER_UID, null,
    +-                VERSION_CODES.M);
    +-        dpm.setActiveAdmin(adminNoPerm, /* replace =*/ false);
    +-        assertTrue(dpm.isAdminActive(adminNoPerm));
    +-
    +-        // TODO Test the "load from the file" case where DA will still be loaded even without
    +-        // BIND_DEVICE_ADMIN and target API is N.
    +-    }
    +-
    +-    /**
    +-     * Test for:
    +-     * {@link DevicePolicyManager#removeActiveAdmin}
    +-     */
    +-    public void testRemoveActiveAdmin_SecurityException() {
    +-        mContext.callerPermissions.add(android.Manifest.permission.MANAGE_DEVICE_ADMINS);
    +-
    +-        // Add admin.
    +-
    +-        dpm.setActiveAdmin(admin1, /* replace =*/ false);
    +-
    +-        assertTrue(dpm.isAdminActive(admin1));
    +-
    +-        assertFalse(dpm.isRemovingAdmin(admin1, DpmMockContext.CALLER_USER_HANDLE));
    +-
    +-        // Directly call the DPMS method with a different userid, which should fail.
    +-        try {
    +-            dpms.removeActiveAdmin(admin1, DpmMockContext.CALLER_USER_HANDLE + 1);
    +-            fail("Didn't throw SecurityException");
    +-        } catch (SecurityException expected) {
    +-        }
    +-
    +-        // Try to remove active admin with a different caller userid should fail too, without
    +-        // having MANAGE_DEVICE_ADMINS.
    +-        mContext.callerPermissions.clear();
    +-
    +-        // Change the caller, and call into DPMS directly with a different user-id.
    +-
    +-        mContext.binder.callingUid = 1234567;
    +-        try {
    +-            dpms.removeActiveAdmin(admin1, DpmMockContext.CALLER_USER_HANDLE);
    +-            fail("Didn't throw SecurityException");
    +-        } catch (SecurityException expected) {
    +-        }
    +-    }
    +-
    +-    /**
    +-     * {@link DevicePolicyManager#removeActiveAdmin} should fail with the user is not unlocked
    +-     * (because we can't send the remove broadcast).
    +-     */
    +-    public void testRemoveActiveAdmin_userNotRunningOrLocked() {
    +-        mContext.callerPermissions.add(android.Manifest.permission.MANAGE_DEVICE_ADMINS);
    +-
    +-        mContext.binder.callingUid = DpmMockContext.CALLER_UID;
    +-
    +-        // Add admin.
    +-
    +-        dpm.setActiveAdmin(admin1, /* replace =*/ false);
    +-
    +-        assertTrue(dpm.isAdminActive(admin1));
    +-
    +-        assertFalse(dpm.isRemovingAdmin(admin1, DpmMockContext.CALLER_USER_HANDLE));
    +-
    +-        // 1. User not unlocked.
    +-        when(mContext.userManager.isUserUnlocked(eq(DpmMockContext.CALLER_USER_HANDLE)))
    +-                .thenReturn(false);
    +-        try {
    +-            dpm.removeActiveAdmin(admin1);
    +-            fail("Didn't throw IllegalStateException");
    +-        } catch (IllegalStateException expected) {
    +-            MoreAsserts.assertContainsRegex(
    +-                    "User must be running and unlocked", expected.getMessage());
    +-        }
    +-
    +-        assertFalse(dpm.isRemovingAdmin(admin1, DpmMockContext.CALLER_USER_HANDLE));
    +-
    +-        // 2. User unlocked.
    +-        when(mContext.userManager.isUserUnlocked(eq(DpmMockContext.CALLER_USER_HANDLE)))
    +-                .thenReturn(true);
    +-
    +-        dpm.removeActiveAdmin(admin1);
    +-        assertFalse(dpm.isAdminActiveAsUser(admin1, DpmMockContext.CALLER_USER_HANDLE));
    +-    }
    +-
    +-    /**
    +-     * Test for:
    +-     * {@link DevicePolicyManager#removeActiveAdmin}
    +-     */
    +-    public void testRemoveActiveAdmin_fromDifferentUserWithINTERACT_ACROSS_USERS_FULL() {
    +-        mContext.callerPermissions.add(android.Manifest.permission.MANAGE_DEVICE_ADMINS);
    +-
    +-        // Add admin1.
    +-
    +-        dpm.setActiveAdmin(admin1, /* replace =*/ false);
    +-
    +-        assertTrue(dpm.isAdminActive(admin1));
    +-        assertFalse(dpm.isRemovingAdmin(admin1, DpmMockContext.CALLER_USER_HANDLE));
    +-
    +-        // Different user, but should work, because caller has proper permissions.
    +-        mContext.callerPermissions.add(permission.INTERACT_ACROSS_USERS_FULL);
    +-
    +-        // Change the caller, and call into DPMS directly with a different user-id.
    +-        mContext.binder.callingUid = 1234567;
    +-
    +-        dpms.removeActiveAdmin(admin1, DpmMockContext.CALLER_USER_HANDLE);
    +-        assertFalse(dpm.isAdminActiveAsUser(admin1, DpmMockContext.CALLER_USER_HANDLE));
    +-
    +-        // TODO DO Still can't be removed in this case.
    +-    }
    +-
    +-    /**
    +-     * Test for:
    +-     * {@link DevicePolicyManager#removeActiveAdmin}
    +-     */
    +-    public void testRemoveActiveAdmin_sameUserNoMANAGE_DEVICE_ADMINS() {
    +-        // Need MANAGE_DEVICE_ADMINS for setActiveAdmin.  We'll remove it later.
    +-        mContext.callerPermissions.add(android.Manifest.permission.MANAGE_DEVICE_ADMINS);
    +-
    +-        // Add admin1.
    +-
    +-        dpm.setActiveAdmin(admin1, /* replace =*/ false);
    +-
    +-        assertTrue(dpm.isAdminActive(admin1));
    +-        assertFalse(dpm.isRemovingAdmin(admin1, DpmMockContext.CALLER_USER_HANDLE));
    +-
    +-        // Broadcast from saveSettingsLocked().
    +-        verify(mContext.spiedContext, times(1)).sendBroadcastAsUser(
    +-                MockUtils.checkIntentAction(
    +-                        DevicePolicyManager.ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED),
    +-                MockUtils.checkUserHandle(DpmMockContext.CALLER_USER_HANDLE));
    +-
    +-        // Remove.  No permissions, but same user, so it'll work.
    +-        mContext.callerPermissions.clear();
    +-        dpm.removeActiveAdmin(admin1);
    +-
    +-        verify(mContext.spiedContext).sendOrderedBroadcastAsUser(
    +-                MockUtils.checkIntentAction(
    +-                        DeviceAdminReceiver.ACTION_DEVICE_ADMIN_DISABLED),
    +-                MockUtils.checkUserHandle(DpmMockContext.CALLER_USER_HANDLE),
    +-                isNull(String.class),
    +-                any(BroadcastReceiver.class),
    +-                eq(dpms.mHandler),
    +-                eq(Activity.RESULT_OK),
    +-                isNull(String.class),
    +-                isNull(Bundle.class));
    +-
    +-        assertFalse(dpm.isAdminActiveAsUser(admin1, DpmMockContext.CALLER_USER_HANDLE));
    +-
    +-        // Again broadcast from saveSettingsLocked().
    +-        verify(mContext.spiedContext, times(2)).sendBroadcastAsUser(
    +-                MockUtils.checkIntentAction(
    +-                        DevicePolicyManager.ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED),
    +-                MockUtils.checkUserHandle(DpmMockContext.CALLER_USER_HANDLE));
    +-
    +-        // TODO Check other internal calls.
    +-    }
    +-
    +-    /**
    +-     * Test for: {@link DevicePolicyManager#setDeviceOwner} DO on system user installs successfully.
    +-     */
    +-    public void testSetDeviceOwner() throws Exception {
    +-        setDeviceOwner();
    +-
    +-        // Try to set a profile owner on the same user, which should fail.
    +-        setUpPackageManagerForAdmin(admin2, DpmMockContext.CALLER_SYSTEM_USER_UID);
    +-        dpm.setActiveAdmin(admin2, /* refreshing= */ true, UserHandle.USER_SYSTEM);
    +-        try {
    +-            dpm.setProfileOwner(admin2, "owner-name", UserHandle.USER_SYSTEM);
    +-            fail("IllegalStateException not thrown");
    +-        } catch (IllegalStateException expected) {
    +-            assertTrue("Message was: " + expected.getMessage(),
    +-                    expected.getMessage().contains("already has a device owner"));
    +-        }
    +-
    +-        // DO admin can't be deactivated.
    +-        dpm.removeActiveAdmin(admin1);
    +-        assertTrue(dpm.isAdminActive(admin1));
    +-
    +-        // TODO Test getDeviceOwnerName() too. To do so, we need to change
    +-        // DPMS.getApplicationLabel() because Context.createPackageContextAsUser() is not mockable.
    +-    }
    +-
    +-    private void setDeviceOwner() throws Exception {
    +-        mContext.callerPermissions.add(permission.MANAGE_DEVICE_ADMINS);
    +-        mContext.callerPermissions.add(permission.MANAGE_USERS);
    +-        mContext.callerPermissions.add(permission.MANAGE_PROFILE_AND_DEVICE_OWNERS);
    +-        mContext.callerPermissions.add(permission.INTERACT_ACROSS_USERS_FULL);
    +-
    +-        // In this test, change the caller user to "system".
    +-        mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID;
    +-
    +-        // Make sure admin1 is installed on system user.
    +-        setUpPackageManagerForAdmin(admin1, DpmMockContext.CALLER_SYSTEM_USER_UID);
    +-
    +-        // Check various get APIs.
    +-        checkGetDeviceOwnerInfoApi(dpm, /* hasDeviceOwner =*/ false);
    +-
    +-        // DO needs to be an DA.
    +-        dpm.setActiveAdmin(admin1, /* replace =*/ false);
    +-
    +-        // Fire!
    +-        assertTrue(dpm.setDeviceOwner(admin1, "owner-name"));
    +-
    +-        // getDeviceOwnerComponent should return the admin1 component.
    +-        assertEquals(admin1, dpm.getDeviceOwnerComponentOnCallingUser());
    +-        assertEquals(admin1, dpm.getDeviceOwnerComponentOnAnyUser());
    +-
    +-        // Check various get APIs.
    +-        checkGetDeviceOwnerInfoApi(dpm, /* hasDeviceOwner =*/ true);
    +-
    +-        // getDeviceOwnerComponent should *NOT* return the admin1 component for other users.
    +-        mContext.binder.callingUid = DpmMockContext.CALLER_UID;
    +-        assertEquals(null, dpm.getDeviceOwnerComponentOnCallingUser());
    +-        assertEquals(admin1, dpm.getDeviceOwnerComponentOnAnyUser());
    +-
    +-        mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID;
    +-
    +-        // Verify internal calls.
    +-        verify(mContext.iactivityManager, times(1)).updateDeviceOwner(
    +-                eq(admin1.getPackageName()));
    +-
    +-        // TODO We should check if the caller has called clearCallerIdentity().
    +-        verify(mContext.ibackupManager, times(1)).setBackupServiceActive(
    +-                eq(UserHandle.USER_SYSTEM), eq(false));
    +-
    +-        verify(mContext.spiedContext, times(1)).sendBroadcastAsUser(
    +-                MockUtils.checkIntentAction(DevicePolicyManager.ACTION_DEVICE_OWNER_CHANGED),
    +-                MockUtils.checkUserHandle(UserHandle.USER_SYSTEM));
    +-
    +-        assertEquals(admin1, dpm.getDeviceOwnerComponentOnAnyUser());
    +-    }
    +-
    +-    private void checkGetDeviceOwnerInfoApi(DevicePolicyManager dpm, boolean hasDeviceOwner) {
    +-        final int origCallingUser = mContext.binder.callingUid;
    +-        final List origPermissions = new ArrayList(mContext.callerPermissions);
    +-        mContext.callerPermissions.clear();
    +-
    +-        mContext.callerPermissions.add(permission.MANAGE_USERS);
    +-
    +-        mContext.binder.callingUid = Process.SYSTEM_UID;
    +-
    +-        // TODO Test getDeviceOwnerName() too.  To do so, we need to change
    +-        // DPMS.getApplicationLabel() because Context.createPackageContextAsUser() is not mockable.
    +-        if (hasDeviceOwner) {
    +-            assertTrue(dpm.isDeviceOwnerApp(admin1.getPackageName()));
    +-            assertTrue(dpm.isDeviceOwnerAppOnCallingUser(admin1.getPackageName()));
    +-            assertEquals(admin1, dpm.getDeviceOwnerComponentOnCallingUser());
    +-
    +-            assertTrue(dpm.isDeviceOwnerAppOnAnyUser(admin1.getPackageName()));
    +-            assertEquals(admin1, dpm.getDeviceOwnerComponentOnAnyUser());
    +-            assertEquals(UserHandle.USER_SYSTEM, dpm.getDeviceOwnerUserId());
    +-        } else {
    +-            assertFalse(dpm.isDeviceOwnerApp(admin1.getPackageName()));
    +-            assertFalse(dpm.isDeviceOwnerAppOnCallingUser(admin1.getPackageName()));
    +-            assertEquals(null, dpm.getDeviceOwnerComponentOnCallingUser());
    +-
    +-            assertFalse(dpm.isDeviceOwnerAppOnAnyUser(admin1.getPackageName()));
    +-            assertEquals(null, dpm.getDeviceOwnerComponentOnAnyUser());
    +-            assertEquals(UserHandle.USER_NULL, dpm.getDeviceOwnerUserId());
    +-        }
    +-
    +-        mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID;
    +-        if (hasDeviceOwner) {
    +-            assertTrue(dpm.isDeviceOwnerApp(admin1.getPackageName()));
    +-            assertTrue(dpm.isDeviceOwnerAppOnCallingUser(admin1.getPackageName()));
    +-            assertEquals(admin1, dpm.getDeviceOwnerComponentOnCallingUser());
    +-
    +-            assertTrue(dpm.isDeviceOwnerAppOnAnyUser(admin1.getPackageName()));
    +-            assertEquals(admin1, dpm.getDeviceOwnerComponentOnAnyUser());
    +-            assertEquals(UserHandle.USER_SYSTEM, dpm.getDeviceOwnerUserId());
    +-        } else {
    +-            assertFalse(dpm.isDeviceOwnerApp(admin1.getPackageName()));
    +-            assertFalse(dpm.isDeviceOwnerAppOnCallingUser(admin1.getPackageName()));
    +-            assertEquals(null, dpm.getDeviceOwnerComponentOnCallingUser());
    +-
    +-            assertFalse(dpm.isDeviceOwnerAppOnAnyUser(admin1.getPackageName()));
    +-            assertEquals(null, dpm.getDeviceOwnerComponentOnAnyUser());
    +-            assertEquals(UserHandle.USER_NULL, dpm.getDeviceOwnerUserId());
    +-        }
    +-
    +-        mContext.binder.callingUid = DpmMockContext.CALLER_UID;
    +-        // Still with MANAGE_USERS.
    +-        assertFalse(dpm.isDeviceOwnerApp(admin1.getPackageName()));
    +-        assertFalse(dpm.isDeviceOwnerAppOnCallingUser(admin1.getPackageName()));
    +-        assertEquals(null, dpm.getDeviceOwnerComponentOnCallingUser());
    +-
    +-        if (hasDeviceOwner) {
    +-            assertTrue(dpm.isDeviceOwnerAppOnAnyUser(admin1.getPackageName()));
    +-            assertEquals(admin1, dpm.getDeviceOwnerComponentOnAnyUser());
    +-            assertEquals(UserHandle.USER_SYSTEM, dpm.getDeviceOwnerUserId());
    +-        } else {
    +-            assertFalse(dpm.isDeviceOwnerAppOnAnyUser(admin1.getPackageName()));
    +-            assertEquals(null, dpm.getDeviceOwnerComponentOnAnyUser());
    +-            assertEquals(UserHandle.USER_NULL, dpm.getDeviceOwnerUserId());
    +-        }
    +-
    +-        mContext.binder.callingUid = Process.SYSTEM_UID;
    +-        mContext.callerPermissions.remove(permission.MANAGE_USERS);
    +-        // System can still call "OnAnyUser" without MANAGE_USERS.
    +-        if (hasDeviceOwner) {
    +-            assertTrue(dpm.isDeviceOwnerApp(admin1.getPackageName()));
    +-            assertTrue(dpm.isDeviceOwnerAppOnCallingUser(admin1.getPackageName()));
    +-            assertEquals(admin1, dpm.getDeviceOwnerComponentOnCallingUser());
    +-
    +-            assertTrue(dpm.isDeviceOwnerAppOnAnyUser(admin1.getPackageName()));
    +-            assertEquals(admin1, dpm.getDeviceOwnerComponentOnAnyUser());
    +-            assertEquals(UserHandle.USER_SYSTEM, dpm.getDeviceOwnerUserId());
    +-        } else {
    +-            assertFalse(dpm.isDeviceOwnerApp(admin1.getPackageName()));
    +-            assertFalse(dpm.isDeviceOwnerAppOnCallingUser(admin1.getPackageName()));
    +-            assertEquals(null, dpm.getDeviceOwnerComponentOnCallingUser());
    +-
    +-            assertFalse(dpm.isDeviceOwnerAppOnAnyUser(admin1.getPackageName()));
    +-            assertEquals(null, dpm.getDeviceOwnerComponentOnAnyUser());
    +-            assertEquals(UserHandle.USER_NULL, dpm.getDeviceOwnerUserId());
    +-        }
    +-
    +-        mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID;
    +-        // Still no MANAGE_USERS.
    +-        if (hasDeviceOwner) {
    +-            assertTrue(dpm.isDeviceOwnerApp(admin1.getPackageName()));
    +-            assertTrue(dpm.isDeviceOwnerAppOnCallingUser(admin1.getPackageName()));
    +-            assertEquals(admin1, dpm.getDeviceOwnerComponentOnCallingUser());
    +-        } else {
    +-            assertFalse(dpm.isDeviceOwnerApp(admin1.getPackageName()));
    +-            assertFalse(dpm.isDeviceOwnerAppOnCallingUser(admin1.getPackageName()));
    +-            assertEquals(null, dpm.getDeviceOwnerComponentOnCallingUser());
    +-        }
    +-
    +-        try {
    +-            dpm.isDeviceOwnerAppOnAnyUser(admin1.getPackageName());
    +-            fail();
    +-        } catch (SecurityException expected) {
    +-        }
    +-        try {
    +-            dpm.getDeviceOwnerComponentOnAnyUser();
    +-            fail();
    +-        } catch (SecurityException expected) {
    +-        }
    +-        try {
    +-            dpm.getDeviceOwnerUserId();
    +-            fail();
    +-        } catch (SecurityException expected) {
    +-        }
    +-        try {
    +-            dpm.getDeviceOwnerNameOnAnyUser();
    +-            fail();
    +-        } catch (SecurityException expected) {
    +-        }
    +-
    +-        mContext.binder.callingUid = DpmMockContext.CALLER_UID;
    +-        // Still no MANAGE_USERS.
    +-        assertFalse(dpm.isDeviceOwnerApp(admin1.getPackageName()));
    +-        assertFalse(dpm.isDeviceOwnerAppOnCallingUser(admin1.getPackageName()));
    +-        assertEquals(null, dpm.getDeviceOwnerComponentOnCallingUser());
    +-
    +-        try {
    +-            dpm.isDeviceOwnerAppOnAnyUser(admin1.getPackageName());
    +-            fail();
    +-        } catch (SecurityException expected) {
    +-        }
    +-        try {
    +-            dpm.getDeviceOwnerComponentOnAnyUser();
    +-            fail();
    +-        } catch (SecurityException expected) {
    +-        }
    +-        try {
    +-            dpm.getDeviceOwnerUserId();
    +-            fail();
    +-        } catch (SecurityException expected) {
    +-        }
    +-        try {
    +-            dpm.getDeviceOwnerNameOnAnyUser();
    +-            fail();
    +-        } catch (SecurityException expected) {
    +-        }
    +-
    +-        // Restore.
    +-        mContext.binder.callingUid = origCallingUser;
    +-        mContext.callerPermissions.addAll(origPermissions);
    +-    }
    +-
    +-
    +-    /**
    +-     * Test for: {@link DevicePolicyManager#setDeviceOwner} Package doesn't exist.
    +-     */
    +-    public void testSetDeviceOwner_noSuchPackage() {
    +-        mContext.callerPermissions.add(permission.MANAGE_DEVICE_ADMINS);
    +-        mContext.callerPermissions.add(permission.MANAGE_USERS);
    +-        mContext.callerPermissions.add(permission.MANAGE_PROFILE_AND_DEVICE_OWNERS);
    +-        mContext.callerPermissions.add(permission.INTERACT_ACROSS_USERS_FULL);
    +-
    +-        // Call from a process on the system user.
    +-        mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID;
    +-
    +-        try {
    +-            dpm.setDeviceOwner(new ComponentName("a.b.c", ".def"));
    +-            fail("Didn't throw IllegalArgumentException");
    +-        } catch (IllegalArgumentException expected) {
    +-            assertTrue("Message was: " + expected.getMessage(),
    +-                    expected.getMessage().contains("Invalid component"));
    +-        }
    +-    }
    +-
    +-    public void testSetDeviceOwner_failures() throws Exception {
    +-        // TODO Test more failure cases.  Basically test all chacks in enforceCanSetDeviceOwner().
    +-    }
    +-
    +-    public void testClearDeviceOwner() throws Exception {
    +-        mContext.callerPermissions.add(permission.MANAGE_DEVICE_ADMINS);
    +-        mContext.callerPermissions.add(permission.MANAGE_USERS);
    +-        mContext.callerPermissions.add(permission.MANAGE_PROFILE_AND_DEVICE_OWNERS);
    +-        mContext.callerPermissions.add(permission.INTERACT_ACROSS_USERS_FULL);
    +-
    +-        // Set admin1 as a DA to the secondary user.
    +-        setUpPackageManagerForAdmin(admin1, DpmMockContext.CALLER_UID);
    +-
    +-        dpm.setActiveAdmin(admin1, /* replace =*/ false);
    +-
    +-        // Set admin 1 as the DO to the system user.
    +-
    +-        mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID;
    +-        setUpPackageManagerForAdmin(admin1, DpmMockContext.CALLER_SYSTEM_USER_UID);
    +-        dpm.setActiveAdmin(admin1, /* replace =*/ false);
    +-        assertTrue(dpm.setDeviceOwner(admin1, "owner-name"));
    +-
    +-        // Verify internal calls.
    +-        verify(mContext.iactivityManager, times(1)).updateDeviceOwner(
    +-                eq(admin1.getPackageName()));
    +-
    +-        assertEquals(admin1, dpm.getDeviceOwnerComponentOnAnyUser());
    +-
    +-        dpm.addUserRestriction(admin1, UserManager.DISALLOW_ADD_USER);
    +-
    +-        assertTrue(dpm.isAdminActive(admin1));
    +-        assertFalse(dpm.isRemovingAdmin(admin1, UserHandle.USER_SYSTEM));
    +-
    +-        // Set up other mocks.
    +-        when(mContext.userManager.getUserRestrictions()).thenReturn(new Bundle());
    +-
    +-        // Now call clear.
    +-        doReturn(DpmMockContext.CALLER_SYSTEM_USER_UID).when(mContext.packageManager).getPackageUidAsUser(
    +-                eq(admin1.getPackageName()),
    +-                anyInt());
    +-
    +-        // But first pretend the user is locked.  Then it should fail.
    +-        when(mContext.userManager.isUserUnlocked(anyInt())).thenReturn(false);
    +-        try {
    +-            dpm.clearDeviceOwnerApp(admin1.getPackageName());
    +-            fail("Didn't throw IllegalStateException");
    +-        } catch (IllegalStateException expected) {
    +-            MoreAsserts.assertContainsRegex(
    +-                    "User must be running and unlocked", expected.getMessage());
    +-        }
    +-
    +-        when(mContext.userManager.isUserUnlocked(anyInt())).thenReturn(true);
    +-        reset(mContext.userManagerInternal);
    +-        dpm.clearDeviceOwnerApp(admin1.getPackageName());
    +-
    +-        // Now DO shouldn't be set.
    +-        assertNull(dpm.getDeviceOwnerComponentOnAnyUser());
    +-
    +-        verify(mContext.userManagerInternal).setDevicePolicyUserRestrictions(
    +-                eq(UserHandle.USER_SYSTEM),
    +-                MockUtils.checkUserRestrictions(),
    +-                MockUtils.checkUserRestrictions()
    +-        );
    +-
    +-        assertFalse(dpm.isAdminActiveAsUser(admin1, UserHandle.USER_SYSTEM));
    +-        // TODO Check other calls.
    +-    }
    +-
    +-    public void testClearDeviceOwner_fromDifferentUser() throws Exception {
    +-        mContext.callerPermissions.add(permission.MANAGE_DEVICE_ADMINS);
    +-        mContext.callerPermissions.add(permission.MANAGE_USERS);
    +-        mContext.callerPermissions.add(permission.MANAGE_PROFILE_AND_DEVICE_OWNERS);
    +-        mContext.callerPermissions.add(permission.INTERACT_ACROSS_USERS_FULL);
    +-
    +-        // Set admin1 as a DA to the secondary user.
    +-        setUpPackageManagerForAdmin(admin1, DpmMockContext.CALLER_UID);
    +-
    +-        dpm.setActiveAdmin(admin1, /* replace =*/ false);
    +-
    +-        // Set admin 1 as the DO to the system user.
    +-
    +-        mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID;
    +-        setUpPackageManagerForAdmin(admin1, DpmMockContext.CALLER_SYSTEM_USER_UID);
    +-        dpm.setActiveAdmin(admin1, /* replace =*/ false);
    +-        assertTrue(dpm.setDeviceOwner(admin1, "owner-name"));
    +-
    +-        // Verify internal calls.
    +-        verify(mContext.iactivityManager, times(1)).updateDeviceOwner(
    +-                eq(admin1.getPackageName()));
    +-
    +-        assertEquals(admin1, dpm.getDeviceOwnerComponentOnAnyUser());
    +-
    +-        // Now call clear from the secondary user, which should throw.
    +-        mContext.binder.callingUid = DpmMockContext.CALLER_UID;
    +-
    +-        // Now call clear.
    +-        doReturn(DpmMockContext.CALLER_UID).when(mContext.packageManager).getPackageUidAsUser(
    +-                eq(admin1.getPackageName()),
    +-                anyInt());
    +-        try {
    +-            dpm.clearDeviceOwnerApp(admin1.getPackageName());
    +-            fail("Didn't throw");
    +-        } catch (SecurityException e) {
    +-            assertEquals("clearDeviceOwner can only be called by the device owner", e.getMessage());
    +-        }
    +-
    +-        // DO shouldn't be removed.
    +-        assertTrue(dpm.isDeviceManaged());
    +-    }
    +-
    +-    public void testSetProfileOwner() throws Exception {
    +-        setAsProfileOwner(admin1);
    +-
    +-        // PO admin can't be deactivated.
    +-        dpm.removeActiveAdmin(admin1);
    +-        assertTrue(dpm.isAdminActive(admin1));
    +-
    +-        // Try setting DO on the same user, which should fail.
    +-        setUpPackageManagerForAdmin(admin2, DpmMockContext.CALLER_UID);
    +-        dpm.setActiveAdmin(admin2, /* refreshing= */ true, DpmMockContext.CALLER_USER_HANDLE);
    +-        try {
    +-            dpm.setDeviceOwner(admin2, "owner-name", DpmMockContext.CALLER_USER_HANDLE);
    +-            fail("IllegalStateException not thrown");
    +-        } catch (IllegalStateException expected) {
    +-            assertTrue("Message was: " + expected.getMessage(),
    +-                    expected.getMessage().contains("already has a profile owner"));
    +-        }
    +-    }
    +-
    +-    public void testClearProfileOwner() throws Exception {
    +-        setAsProfileOwner(admin1);
    +-
    +-        mContext.binder.callingUid = DpmMockContext.CALLER_UID;
    +-
    +-        assertTrue(dpm.isProfileOwnerApp(admin1.getPackageName()));
    +-        assertFalse(dpm.isRemovingAdmin(admin1, DpmMockContext.CALLER_USER_HANDLE));
    +-
    +-        // First try when the user is locked, which should fail.
    +-        when(mContext.userManager.isUserUnlocked(anyInt()))
    +-                .thenReturn(false);
    +-        try {
    +-            dpm.clearProfileOwner(admin1);
    +-            fail("Didn't throw IllegalStateException");
    +-        } catch (IllegalStateException expected) {
    +-            MoreAsserts.assertContainsRegex(
    +-                    "User must be running and unlocked", expected.getMessage());
    +-        }
    +-        // Clear, really.
    +-        when(mContext.userManager.isUserUnlocked(anyInt()))
    +-                .thenReturn(true);
    +-        dpm.clearProfileOwner(admin1);
    +-
    +-        // Check
    +-        assertFalse(dpm.isProfileOwnerApp(admin1.getPackageName()));
    +-        assertFalse(dpm.isAdminActiveAsUser(admin1, DpmMockContext.CALLER_USER_HANDLE));
    +-    }
    +-
    +-    public void testSetProfileOwner_failures() throws Exception {
    +-        // TODO Test more failure cases.  Basically test all chacks in enforceCanSetProfileOwner().
    +-    }
    +-
    +-    public void testGetDeviceOwnerAdminLocked() throws Exception {
    +-        checkDeviceOwnerWithMultipleDeviceAdmins();
    +-    }
    +-
    +-    private void checkDeviceOwnerWithMultipleDeviceAdmins() throws Exception {
    +-        // In ths test, we use 3 users (system + 2 secondary users), set some device admins to them,
    +-        // set admin2 on CALLER_USER_HANDLE as DO, then call getDeviceOwnerAdminLocked() to
    +-        // make sure it gets the right component from the right user.
    +-
    +-        final int ANOTHER_USER_ID = 100;
    +-        final int ANOTHER_ADMIN_UID = UserHandle.getUid(ANOTHER_USER_ID, 456);
    +-
    +-        mMockContext.addUser(ANOTHER_USER_ID, 0); // Add one more user.
    +-
    +-        mContext.callerPermissions.add(permission.MANAGE_DEVICE_ADMINS);
    +-        mContext.callerPermissions.add(permission.MANAGE_USERS);
    +-        mContext.callerPermissions.add(permission.MANAGE_PROFILE_AND_DEVICE_OWNERS);
    +-        mContext.callerPermissions.add(permission.INTERACT_ACROSS_USERS_FULL);
    +-
    +-        mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID;
    +-
    +-        when(mContext.userManagerForMock.isSplitSystemUser()).thenReturn(true);
    +-
    +-        // Make sure the admin packge is installed to each user.
    +-        setUpPackageManagerForAdmin(admin1, DpmMockContext.CALLER_SYSTEM_USER_UID);
    +-        setUpPackageManagerForAdmin(admin3, DpmMockContext.CALLER_SYSTEM_USER_UID);
    +-
    +-        setUpPackageManagerForAdmin(admin1, DpmMockContext.CALLER_UID);
    +-        setUpPackageManagerForAdmin(admin2, DpmMockContext.CALLER_UID);
    +-
    +-        setUpPackageManagerForAdmin(admin2, ANOTHER_ADMIN_UID);
    +-
    +-
    +-        // Set active admins to the users.
    +-        dpm.setActiveAdmin(admin1, /* replace =*/ false);
    +-        dpm.setActiveAdmin(admin3, /* replace =*/ false);
    +-
    +-        dpm.setActiveAdmin(admin1, /* replace =*/ false, DpmMockContext.CALLER_USER_HANDLE);
    +-        dpm.setActiveAdmin(admin2, /* replace =*/ false, DpmMockContext.CALLER_USER_HANDLE);
    +-
    +-        dpm.setActiveAdmin(admin2, /* replace =*/ false, ANOTHER_USER_ID);
    +-
    +-        // Set DO on the first non-system user.
    +-        mContext.setUserRunning(DpmMockContext.CALLER_USER_HANDLE, true);
    +-        assertTrue(dpm.setDeviceOwner(admin2, "owner-name", DpmMockContext.CALLER_USER_HANDLE));
    +-
    +-        assertEquals(admin2, dpms.getDeviceOwnerComponent(/* callingUserOnly =*/ false));
    +-
    +-        // Then check getDeviceOwnerAdminLocked().
    +-        assertEquals(admin2, dpms.getDeviceOwnerAdminLocked().info.getComponent());
    +-        assertEquals(DpmMockContext.CALLER_UID, dpms.getDeviceOwnerAdminLocked().getUid());
    +-    }
    +-
    +-    /**
    +-     * This essentially tests
    +-     * {@code DevicePolicyManagerService.findOwnerComponentIfNecessaryLocked()}. (which is
    +-     * private.)
    +-     *
    +-     * We didn't use to persist the DO component class name, but now we do, and the above method
    +-     * finds the right component from a package name upon migration.
    +-     */
    +-    public void testDeviceOwnerMigration() throws Exception {
    +-        when(mContext.userManagerForMock.isSplitSystemUser()).thenReturn(true);
    +-        checkDeviceOwnerWithMultipleDeviceAdmins();
    +-
    +-        // Overwrite the device owner setting and clears the clas name.
    +-        dpms.mOwners.setDeviceOwner(
    +-                new ComponentName(admin2.getPackageName(), ""),
    +-                "owner-name", DpmMockContext.CALLER_USER_HANDLE);
    +-        dpms.mOwners.writeDeviceOwner();
    +-
    +-        // Make sure the DO component name doesn't have a class name.
    +-        assertEquals("", dpms.getDeviceOwnerComponent(/* callingUserOnly =*/ false).getClassName());
    +-
    +-        // Then create a new DPMS to have it load the settings from files.
    +-        when(mContext.userManager.getUserRestrictions(any(UserHandle.class)))
    +-                .thenReturn(new Bundle());
    +-        initializeDpms();
    +-
    +-        // Now the DO component name is a full name.
    +-        // *BUT* because both admin1 and admin2 belong to the same package, we think admin1 is the
    +-        // DO.
    +-        assertEquals(admin1, dpms.getDeviceOwnerComponent(/* callingUserOnly =*/ false));
    +-    }
    +-
    +-    public void testSetGetApplicationRestriction() {
    +-        setAsProfileOwner(admin1);
    +-
    +-        {
    +-            Bundle rest = new Bundle();
    +-            rest.putString("KEY_STRING", "Foo1");
    +-            dpm.setApplicationRestrictions(admin1, "pkg1", rest);
    +-        }
    +-
    +-        {
    +-            Bundle rest = new Bundle();
    +-            rest.putString("KEY_STRING", "Foo2");
    +-            dpm.setApplicationRestrictions(admin1, "pkg2", rest);
    +-        }
    +-
    +-        {
    +-            Bundle returned = dpm.getApplicationRestrictions(admin1, "pkg1");
    +-            assertNotNull(returned);
    +-            assertEquals(returned.size(), 1);
    +-            assertEquals(returned.get("KEY_STRING"), "Foo1");
    +-        }
    +-
    +-        {
    +-            Bundle returned = dpm.getApplicationRestrictions(admin1, "pkg2");
    +-            assertNotNull(returned);
    +-            assertEquals(returned.size(), 1);
    +-            assertEquals(returned.get("KEY_STRING"), "Foo2");
    +-        }
    +-
    +-        dpm.setApplicationRestrictions(admin1, "pkg2", new Bundle());
    +-        assertEquals(0, dpm.getApplicationRestrictions(admin1, "pkg2").size());
    +-    }
    +-
    +-    public void testApplicationRestrictionsManagingApp() throws Exception {
    +-        setAsProfileOwner(admin1);
    +-
    +-        final String nonExistAppRestrictionsManagerPackage = "com.google.app.restrictions.manager2";
    +-        final String appRestrictionsManagerPackage = "com.google.app.restrictions.manager";
    +-        final int appRestrictionsManagerAppId = 20987;
    +-        final int appRestrictionsManagerUid = UserHandle.getUid(
    +-                DpmMockContext.CALLER_USER_HANDLE, appRestrictionsManagerAppId);
    +-        doReturn(appRestrictionsManagerUid).when(mContext.packageManager).getPackageUidAsUser(
    +-                eq(appRestrictionsManagerPackage),
    +-                eq(DpmMockContext.CALLER_USER_HANDLE));
    +-        mContext.binder.callingUid = appRestrictionsManagerUid;
    +-
    +-        final PackageInfo pi = new PackageInfo();
    +-        pi.applicationInfo = new ApplicationInfo();
    +-        pi.applicationInfo.flags = ApplicationInfo.FLAG_HAS_CODE;
    +-        doReturn(pi).when(mContext.ipackageManager).getPackageInfo(
    +-                eq(appRestrictionsManagerPackage),
    +-                anyInt(),
    +-                eq(DpmMockContext.CALLER_USER_HANDLE));
    +-
    +-        // appRestrictionsManager package shouldn't be able to manage restrictions as the PO hasn't
    +-        // delegated that permission yet.
    +-        assertFalse(dpm.isCallerApplicationRestrictionsManagingPackage());
    +-        Bundle rest = new Bundle();
    +-        rest.putString("KEY_STRING", "Foo1");
    +-        try {
    +-            dpm.setApplicationRestrictions(null, "pkg1", rest);
    +-            fail("Didn't throw expected SecurityException");
    +-        } catch (SecurityException expected) {
    +-            MoreAsserts.assertContainsRegex(
    +-                    "caller cannot manage application restrictions", expected.getMessage());
    +-        }
    +-        try {
    +-            dpm.getApplicationRestrictions(null, "pkg1");
    +-            fail("Didn't throw expected SecurityException");
    +-        } catch (SecurityException expected) {
    +-            MoreAsserts.assertContainsRegex(
    +-                    "caller cannot manage application restrictions", expected.getMessage());
    +-        }
    +-
    +-        // Check via the profile owner that no restrictions were set.
    +-        mContext.binder.callingUid = DpmMockContext.CALLER_UID;
    +-        assertEquals(0, dpm.getApplicationRestrictions(admin1, "pkg1").size());
    +-
    +-        // Check the API does not allow setting a non-existent package
    +-        try {
    +-            dpm.setApplicationRestrictionsManagingPackage(admin1,
    +-                    nonExistAppRestrictionsManagerPackage);
    +-            fail("Non-existent app set as app restriction manager.");
    +-        } catch (PackageManager.NameNotFoundException expected) {
    +-            MoreAsserts.assertContainsRegex(
    +-                    nonExistAppRestrictionsManagerPackage, expected.getMessage());
    +-        }
    +-
    +-        // Let appRestrictionsManagerPackage manage app restrictions
    +-        dpm.setApplicationRestrictionsManagingPackage(admin1, appRestrictionsManagerPackage);
    +-        assertEquals(appRestrictionsManagerPackage,
    +-                dpm.getApplicationRestrictionsManagingPackage(admin1));
    +-
    +-        // Now that package should be able to set and retrieve app restrictions.
    +-        mContext.binder.callingUid = appRestrictionsManagerUid;
    +-        assertTrue(dpm.isCallerApplicationRestrictionsManagingPackage());
    +-        dpm.setApplicationRestrictions(null, "pkg1", rest);
    +-        Bundle returned = dpm.getApplicationRestrictions(null, "pkg1");
    +-        assertEquals(1, returned.size(), 1);
    +-        assertEquals("Foo1", returned.get("KEY_STRING"));
    +-
    +-        // The same app running on a separate user shouldn't be able to manage app restrictions.
    +-        mContext.binder.callingUid = UserHandle.getUid(
    +-                UserHandle.USER_SYSTEM, appRestrictionsManagerAppId);
    +-        assertFalse(dpm.isCallerApplicationRestrictionsManagingPackage());
    +-        try {
    +-            dpm.setApplicationRestrictions(null, "pkg1", rest);
    +-            fail("Didn't throw expected SecurityException");
    +-        } catch (SecurityException expected) {
    +-            MoreAsserts.assertContainsRegex(
    +-                    "caller cannot manage application restrictions", expected.getMessage());
    +-        }
    +-
    +-        // The DPM is still able to manage app restrictions, even if it allowed another app to do it
    +-        // too.
    +-        mContext.binder.callingUid = DpmMockContext.CALLER_UID;
    +-        assertEquals(returned, dpm.getApplicationRestrictions(admin1, "pkg1"));
    +-        dpm.setApplicationRestrictions(admin1, "pkg1", null);
    +-        assertEquals(0, dpm.getApplicationRestrictions(admin1, "pkg1").size());
    +-
    +-        // Removing the ability for the package to manage app restrictions.
    +-        dpm.setApplicationRestrictionsManagingPackage(admin1, null);
    +-        assertNull(dpm.getApplicationRestrictionsManagingPackage(admin1));
    +-        mContext.binder.callingUid = appRestrictionsManagerUid;
    +-        assertFalse(dpm.isCallerApplicationRestrictionsManagingPackage());
    +-        try {
    +-            dpm.setApplicationRestrictions(null, "pkg1", null);
    +-            fail("Didn't throw expected SecurityException");
    +-        } catch (SecurityException expected) {
    +-            MoreAsserts.assertContainsRegex(
    +-                    "caller cannot manage application restrictions", expected.getMessage());
    +-        }
    +-    }
    +-
    +-    public void testSetUserRestriction_asDo() throws Exception {
    +-        mContext.callerPermissions.add(permission.MANAGE_DEVICE_ADMINS);
    +-        mContext.callerPermissions.add(permission.MANAGE_USERS);
    +-        mContext.callerPermissions.add(permission.MANAGE_PROFILE_AND_DEVICE_OWNERS);
    +-        mContext.callerPermissions.add(permission.INTERACT_ACROSS_USERS_FULL);
    +-
    +-        // First, set DO.
    +-
    +-        // Call from a process on the system user.
    +-        mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID;
    +-
    +-        // Make sure admin1 is installed on system user.
    +-        setUpPackageManagerForAdmin(admin1, DpmMockContext.CALLER_SYSTEM_USER_UID);
    +-
    +-        // Call.
    +-        dpm.setActiveAdmin(admin1, /* replace =*/ false, UserHandle.USER_SYSTEM);
    +-        assertTrue(dpm.setDeviceOwner(admin1, "owner-name",
    +-                UserHandle.USER_SYSTEM));
    +-
    +-        DpmTestUtils.assertRestrictions(
    +-                DpmTestUtils.newRestrictions(),
    +-                dpms.getDeviceOwnerAdminLocked().ensureUserRestrictions()
    +-        );
    +-        DpmTestUtils.assertRestrictions(
    +-                DpmTestUtils.newRestrictions(),
    +-                dpm.getUserRestrictions(admin1)
    +-        );
    +-
    +-        reset(mContext.userManagerInternal);
    +-
    +-        dpm.addUserRestriction(admin1, UserManager.DISALLOW_ADD_USER);
    +-        verify(mContext.userManagerInternal).setDevicePolicyUserRestrictions(
    +-                eq(UserHandle.USER_SYSTEM),
    +-                MockUtils.checkUserRestrictions(),
    +-                MockUtils.checkUserRestrictions(UserManager.DISALLOW_ADD_USER)
    +-        );
    +-        reset(mContext.userManagerInternal);
    +-
    +-        dpm.addUserRestriction(admin1, UserManager.DISALLOW_OUTGOING_CALLS);
    +-        verify(mContext.userManagerInternal).setDevicePolicyUserRestrictions(
    +-                eq(UserHandle.USER_SYSTEM),
    +-                MockUtils.checkUserRestrictions(UserManager.DISALLOW_OUTGOING_CALLS),
    +-                MockUtils.checkUserRestrictions(UserManager.DISALLOW_ADD_USER)
    +-        );
    +-        reset(mContext.userManagerInternal);
    +-
    +-        DpmTestUtils.assertRestrictions(
    +-                DpmTestUtils.newRestrictions(
    +-                        UserManager.DISALLOW_ADD_USER, UserManager.DISALLOW_OUTGOING_CALLS),
    +-                dpms.getDeviceOwnerAdminLocked().ensureUserRestrictions()
    +-        );
    +-        DpmTestUtils.assertRestrictions(
    +-                DpmTestUtils.newRestrictions(
    +-                        UserManager.DISALLOW_ADD_USER, UserManager.DISALLOW_OUTGOING_CALLS),
    +-                dpm.getUserRestrictions(admin1)
    +-        );
    +-
    +-        dpm.clearUserRestriction(admin1, UserManager.DISALLOW_ADD_USER);
    +-        verify(mContext.userManagerInternal).setDevicePolicyUserRestrictions(
    +-                eq(UserHandle.USER_SYSTEM),
    +-                MockUtils.checkUserRestrictions(UserManager.DISALLOW_OUTGOING_CALLS),
    +-                MockUtils.checkUserRestrictions()
    +-        );
    +-        reset(mContext.userManagerInternal);
    +-
    +-        DpmTestUtils.assertRestrictions(
    +-                DpmTestUtils.newRestrictions(UserManager.DISALLOW_OUTGOING_CALLS),
    +-                dpms.getDeviceOwnerAdminLocked().ensureUserRestrictions()
    +-        );
    +-        DpmTestUtils.assertRestrictions(
    +-                DpmTestUtils.newRestrictions(UserManager.DISALLOW_OUTGOING_CALLS),
    +-                dpm.getUserRestrictions(admin1)
    +-        );
    +-
    +-        dpm.clearUserRestriction(admin1, UserManager.DISALLOW_OUTGOING_CALLS);
    +-        verify(mContext.userManagerInternal).setDevicePolicyUserRestrictions(
    +-                eq(UserHandle.USER_SYSTEM),
    +-                MockUtils.checkUserRestrictions(),
    +-                MockUtils.checkUserRestrictions()
    +-        );
    +-        reset(mContext.userManagerInternal);
    +-
    +-        DpmTestUtils.assertRestrictions(
    +-                DpmTestUtils.newRestrictions(),
    +-                dpms.getDeviceOwnerAdminLocked().ensureUserRestrictions()
    +-        );
    +-        DpmTestUtils.assertRestrictions(
    +-                DpmTestUtils.newRestrictions(),
    +-                dpm.getUserRestrictions(admin1)
    +-        );
    +-
    +-        // DISALLOW_ADJUST_VOLUME and DISALLOW_UNMUTE_MICROPHONE are PO restrictions, but when
    +-        // DO sets them, the scope is global.
    +-        dpm.addUserRestriction(admin1, UserManager.DISALLOW_ADJUST_VOLUME);
    +-        reset(mContext.userManagerInternal);
    +-        dpm.addUserRestriction(admin1, UserManager.DISALLOW_UNMUTE_MICROPHONE);
    +-        verify(mContext.userManagerInternal).setDevicePolicyUserRestrictions(
    +-                eq(UserHandle.USER_SYSTEM),
    +-                MockUtils.checkUserRestrictions(),
    +-                MockUtils.checkUserRestrictions(UserManager.DISALLOW_ADJUST_VOLUME,
    +-                        UserManager.DISALLOW_UNMUTE_MICROPHONE)
    +-        );
    +-        reset(mContext.userManagerInternal);
    +-
    +-        dpm.clearUserRestriction(admin1, UserManager.DISALLOW_ADJUST_VOLUME);
    +-        dpm.clearUserRestriction(admin1, UserManager.DISALLOW_UNMUTE_MICROPHONE);
    +-
    +-
    +-        // More tests.
    +-        dpm.addUserRestriction(admin1, UserManager.DISALLOW_ADD_USER);
    +-        verify(mContext.userManagerInternal).setDevicePolicyUserRestrictions(
    +-                eq(UserHandle.USER_SYSTEM),
    +-                MockUtils.checkUserRestrictions(),
    +-                MockUtils.checkUserRestrictions(UserManager.DISALLOW_ADD_USER)
    +-        );
    +-        reset(mContext.userManagerInternal);
    +-
    +-        dpm.addUserRestriction(admin1, UserManager.DISALLOW_FUN);
    +-        verify(mContext.userManagerInternal).setDevicePolicyUserRestrictions(
    +-                eq(UserHandle.USER_SYSTEM),
    +-                MockUtils.checkUserRestrictions(),
    +-                MockUtils.checkUserRestrictions(UserManager.DISALLOW_FUN,
    +-                        UserManager.DISALLOW_ADD_USER)
    +-        );
    +-        reset(mContext.userManagerInternal);
    +-
    +-        dpm.setCameraDisabled(admin1, true);
    +-        verify(mContext.userManagerInternal).setDevicePolicyUserRestrictions(
    +-                eq(UserHandle.USER_SYSTEM),
    +-                // DISALLOW_CAMERA will be applied to both local and global.
    +-                MockUtils.checkUserRestrictions(UserManager.DISALLOW_CAMERA),
    +-                MockUtils.checkUserRestrictions(UserManager.DISALLOW_FUN,
    +-                        UserManager.DISALLOW_CAMERA, UserManager.DISALLOW_ADD_USER)
    +-        );
    +-        reset(mContext.userManagerInternal);
    +-
    +-        // Set up another DA and let it disable camera.  Now DISALLOW_CAMERA will only be applied
    +-        // locally.
    +-        dpm.setCameraDisabled(admin1, false);
    +-        reset(mContext.userManagerInternal);
    +-
    +-        setUpPackageManagerForAdmin(admin2, DpmMockContext.CALLER_SYSTEM_USER_UID);
    +-        dpm.setActiveAdmin(admin2, /* replace =*/ false, UserHandle.USER_SYSTEM);
    +-        dpm.setCameraDisabled(admin2, true);
    +-
    +-        verify(mContext.userManagerInternal).setDevicePolicyUserRestrictions(
    +-                eq(UserHandle.USER_SYSTEM),
    +-                // DISALLOW_CAMERA will be applied to both local and global.
    +-                MockUtils.checkUserRestrictions(UserManager.DISALLOW_CAMERA),
    +-                MockUtils.checkUserRestrictions(UserManager.DISALLOW_FUN,
    +-                        UserManager.DISALLOW_ADD_USER)
    +-        );
    +-        reset(mContext.userManagerInternal);
    +-        // TODO Make sure restrictions are written to the file.
    +-    }
    +-
    +-    public void testSetUserRestriction_asPo() {
    +-        setAsProfileOwner(admin1);
    +-
    +-        DpmTestUtils.assertRestrictions(
    +-                DpmTestUtils.newRestrictions(),
    +-                dpms.getProfileOwnerAdminLocked(DpmMockContext.CALLER_USER_HANDLE)
    +-                        .ensureUserRestrictions()
    +-        );
    +-
    +-        dpm.addUserRestriction(admin1, UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES);
    +-        verify(mContext.userManagerInternal).setDevicePolicyUserRestrictions(
    +-                eq(DpmMockContext.CALLER_USER_HANDLE),
    +-                MockUtils.checkUserRestrictions(UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES),
    +-                isNull(Bundle.class)
    +-        );
    +-        reset(mContext.userManagerInternal);
    +-
    +-        dpm.addUserRestriction(admin1, UserManager.DISALLOW_OUTGOING_CALLS);
    +-        verify(mContext.userManagerInternal).setDevicePolicyUserRestrictions(
    +-                eq(DpmMockContext.CALLER_USER_HANDLE),
    +-                MockUtils.checkUserRestrictions(UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES,
    +-                        UserManager.DISALLOW_OUTGOING_CALLS),
    +-                isNull(Bundle.class)
    +-        );
    +-        reset(mContext.userManagerInternal);
    +-
    +-        DpmTestUtils.assertRestrictions(
    +-                DpmTestUtils.newRestrictions(
    +-                        UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES,
    +-                        UserManager.DISALLOW_OUTGOING_CALLS
    +-                ),
    +-                dpms.getProfileOwnerAdminLocked(DpmMockContext.CALLER_USER_HANDLE)
    +-                        .ensureUserRestrictions()
    +-        );
    +-        DpmTestUtils.assertRestrictions(
    +-                DpmTestUtils.newRestrictions(
    +-                        UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES,
    +-                        UserManager.DISALLOW_OUTGOING_CALLS
    +-                ),
    +-                dpm.getUserRestrictions(admin1)
    +-        );
    +-
    +-        dpm.clearUserRestriction(admin1, UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES);
    +-        verify(mContext.userManagerInternal).setDevicePolicyUserRestrictions(
    +-                eq(DpmMockContext.CALLER_USER_HANDLE),
    +-                MockUtils.checkUserRestrictions(UserManager.DISALLOW_OUTGOING_CALLS),
    +-                isNull(Bundle.class)
    +-        );
    +-        reset(mContext.userManagerInternal);
    +-
    +-        DpmTestUtils.assertRestrictions(
    +-                DpmTestUtils.newRestrictions(
    +-                        UserManager.DISALLOW_OUTGOING_CALLS
    +-                ),
    +-                dpms.getProfileOwnerAdminLocked(DpmMockContext.CALLER_USER_HANDLE)
    +-                        .ensureUserRestrictions()
    +-        );
    +-        DpmTestUtils.assertRestrictions(
    +-                DpmTestUtils.newRestrictions(
    +-                        UserManager.DISALLOW_OUTGOING_CALLS
    +-                ),
    +-                dpm.getUserRestrictions(admin1)
    +-        );
    +-
    +-        dpm.clearUserRestriction(admin1, UserManager.DISALLOW_OUTGOING_CALLS);
    +-        verify(mContext.userManagerInternal).setDevicePolicyUserRestrictions(
    +-                eq(DpmMockContext.CALLER_USER_HANDLE),
    +-                MockUtils.checkUserRestrictions(),
    +-                isNull(Bundle.class)
    +-        );
    +-        reset(mContext.userManagerInternal);
    +-
    +-        DpmTestUtils.assertRestrictions(
    +-                DpmTestUtils.newRestrictions(),
    +-                dpms.getProfileOwnerAdminLocked(DpmMockContext.CALLER_USER_HANDLE)
    +-                        .ensureUserRestrictions()
    +-        );
    +-        DpmTestUtils.assertRestrictions(
    +-                DpmTestUtils.newRestrictions(),
    +-                dpm.getUserRestrictions(admin1)
    +-        );
    +-
    +-        // DISALLOW_ADJUST_VOLUME and DISALLOW_UNMUTE_MICROPHONE can be set by PO too, even
    +-        // though when DO sets them they'll be applied globally.
    +-        dpm.addUserRestriction(admin1, UserManager.DISALLOW_ADJUST_VOLUME);
    +-        reset(mContext.userManagerInternal);
    +-        dpm.addUserRestriction(admin1, UserManager.DISALLOW_UNMUTE_MICROPHONE);
    +-        verify(mContext.userManagerInternal).setDevicePolicyUserRestrictions(
    +-                eq(DpmMockContext.CALLER_USER_HANDLE),
    +-                MockUtils.checkUserRestrictions(UserManager.DISALLOW_ADJUST_VOLUME,
    +-                        UserManager.DISALLOW_UNMUTE_MICROPHONE),
    +-                isNull(Bundle.class)
    +-        );
    +-        reset(mContext.userManagerInternal);
    +-
    +-        dpm.setCameraDisabled(admin1, true);
    +-        verify(mContext.userManagerInternal).setDevicePolicyUserRestrictions(
    +-                eq(DpmMockContext.CALLER_USER_HANDLE),
    +-                MockUtils.checkUserRestrictions(UserManager.DISALLOW_CAMERA,
    +-                        UserManager.DISALLOW_ADJUST_VOLUME,
    +-                        UserManager.DISALLOW_UNMUTE_MICROPHONE),
    +-                isNull(Bundle.class)
    +-        );
    +-        reset(mContext.userManagerInternal);
    +-
    +-        // TODO Make sure restrictions are written to the file.
    +-    }
    +-
    +-    public void testGetMacAddress() throws Exception {
    +-        mContext.callerPermissions.add(permission.MANAGE_DEVICE_ADMINS);
    +-        mContext.callerPermissions.add(permission.MANAGE_PROFILE_AND_DEVICE_OWNERS);
    +-        mContext.callerPermissions.add(permission.INTERACT_ACROSS_USERS_FULL);
    +-
    +-        // In this test, change the caller user to "system".
    +-        mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID;
    +-
    +-        // Make sure admin1 is installed on system user.
    +-        setUpPackageManagerForAdmin(admin1, DpmMockContext.CALLER_SYSTEM_USER_UID);
    +-
    +-        // Test 1. Caller doesn't have DO or DA.
    +-        try {
    +-            dpm.getWifiMacAddress(admin1);
    +-            fail();
    +-        } catch (SecurityException e) {
    +-            MoreAsserts.assertContainsRegex("No active admin", e.getMessage());
    +-        }
    +-
    +-        // DO needs to be an DA.
    +-        dpm.setActiveAdmin(admin1, /* replace =*/ false);
    +-        assertTrue(dpm.isAdminActive(admin1));
    +-
    +-        // Test 2. Caller has DA, but not DO.
    +-        try {
    +-            dpm.getWifiMacAddress(admin1);
    +-            fail();
    +-        } catch (SecurityException e) {
    +-            MoreAsserts.assertContainsRegex("does not own the device", e.getMessage());
    +-        }
    +-
    +-        // Test 3. Caller has PO, but not DO.
    +-        assertTrue(dpm.setProfileOwner(admin1, null, UserHandle.USER_SYSTEM));
    +-        try {
    +-            dpm.getWifiMacAddress(admin1);
    +-            fail();
    +-        } catch (SecurityException e) {
    +-            MoreAsserts.assertContainsRegex("does not own the device", e.getMessage());
    +-        }
    +-
    +-        // Remove PO.
    +-        dpm.clearProfileOwner(admin1);
    +-        dpm.setActiveAdmin(admin1, false);
    +-        // Test 4, Caller is DO now.
    +-        assertTrue(dpm.setDeviceOwner(admin1, null, UserHandle.USER_SYSTEM));
    +-
    +-        // 4-1.  But no WifiInfo.
    +-        assertNull(dpm.getWifiMacAddress(admin1));
    +-
    +-        // 4-2.  Returns WifiInfo, but with the default MAC.
    +-        when(mContext.wifiManager.getConnectionInfo()).thenReturn(new WifiInfo());
    +-        assertNull(dpm.getWifiMacAddress(admin1));
    +-
    +-        // 4-3. With a real MAC address.
    +-        final WifiInfo wi = new WifiInfo();
    +-        wi.setMacAddress("11:22:33:44:55:66");
    +-        when(mContext.wifiManager.getConnectionInfo()).thenReturn(wi);
    +-        assertEquals("11:22:33:44:55:66", dpm.getWifiMacAddress(admin1));
    +-    }
    +-
    +-    public void testReboot() throws Exception {
    +-        mContext.callerPermissions.add(permission.MANAGE_DEVICE_ADMINS);
    +-        mContext.callerPermissions.add(permission.MANAGE_PROFILE_AND_DEVICE_OWNERS);
    +-
    +-        // In this test, change the caller user to "system".
    +-        mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID;
    +-
    +-        // Make sure admin1 is installed on system user.
    +-        setUpPackageManagerForAdmin(admin1, DpmMockContext.CALLER_SYSTEM_USER_UID);
    +-
    +-        // Set admin1 as DA.
    +-        dpm.setActiveAdmin(admin1, false);
    +-        assertTrue(dpm.isAdminActive(admin1));
    +-        try {
    +-            dpm.reboot(admin1);
    +-            fail("DA calls DPM.reboot(), did not throw expected SecurityException");
    +-        } catch (SecurityException expected) {
    +-            MoreAsserts.assertContainsRegex("does not own the device", expected.getMessage());
    +-        }
    +-
    +-        // Set admin1 as PO.
    +-        assertTrue(dpm.setProfileOwner(admin1, null, UserHandle.USER_SYSTEM));
    +-        try {
    +-            dpm.reboot(admin1);
    +-            fail("PO calls DPM.reboot(), did not throw expected SecurityException");
    +-        } catch (SecurityException expected) {
    +-            MoreAsserts.assertContainsRegex("does not own the device", expected.getMessage());
    +-        }
    +-
    +-        // Remove PO and add DO.
    +-        dpm.clearProfileOwner(admin1);
    +-        dpm.setActiveAdmin(admin1, false);
    +-        assertTrue(dpm.setDeviceOwner(admin1, null, UserHandle.USER_SYSTEM));
    +-
    +-        // admin1 is DO.
    +-        // Set current call state of device to ringing.
    +-        when(mContext.telephonyManager.getCallState())
    +-                .thenReturn(TelephonyManager.CALL_STATE_RINGING);
    +-        try {
    +-            dpm.reboot(admin1);
    +-            fail("DPM.reboot() called when receiveing a call, should thrown IllegalStateException");
    +-        } catch (IllegalStateException expected) {
    +-            MoreAsserts.assertContainsRegex("ongoing call on the device", expected.getMessage());
    +-        }
    +-
    +-        // Set current call state of device to dialing/active.
    +-        when(mContext.telephonyManager.getCallState())
    +-                .thenReturn(TelephonyManager.CALL_STATE_OFFHOOK);
    +-        try {
    +-            dpm.reboot(admin1);
    +-            fail("DPM.reboot() called when dialing, should thrown IllegalStateException");
    +-        } catch (IllegalStateException expected) {
    +-            MoreAsserts.assertContainsRegex("ongoing call on the device", expected.getMessage());
    +-        }
    +-
    +-        // Set current call state of device to idle.
    +-        when(mContext.telephonyManager.getCallState()).thenReturn(TelephonyManager.CALL_STATE_IDLE);
    +-        dpm.reboot(admin1);
    +-    }
    +-
    +-    public void testSetGetSupportText() {
    +-        mContext.callerPermissions.add(permission.MANAGE_DEVICE_ADMINS);
    +-        dpm.setActiveAdmin(admin1, true);
    +-        dpm.setActiveAdmin(admin2, true);
    +-        mContext.callerPermissions.remove(permission.MANAGE_DEVICE_ADMINS);
    +-
    +-        // Null default support messages.
    +-        {
    +-            assertNull(dpm.getLongSupportMessage(admin1));
    +-            assertNull(dpm.getShortSupportMessage(admin1));
    +-            mContext.binder.callingUid = DpmMockContext.SYSTEM_UID;
    +-            assertNull(dpm.getShortSupportMessageForUser(admin1,
    +-                    DpmMockContext.CALLER_USER_HANDLE));
    +-            assertNull(dpm.getLongSupportMessageForUser(admin1,
    +-                    DpmMockContext.CALLER_USER_HANDLE));
    +-            mMockContext.binder.callingUid = DpmMockContext.CALLER_UID;
    +-        }
    +-
    +-        // Only system can call the per user versions.
    +-        {
    +-            try {
    +-                dpm.getShortSupportMessageForUser(admin1,
    +-                        DpmMockContext.CALLER_USER_HANDLE);
    +-                fail("Only system should be able to call getXXXForUser versions");
    +-            } catch (SecurityException expected) {
    +-                MoreAsserts.assertContainsRegex("message for user", expected.getMessage());
    +-            }
    +-            try {
    +-                dpm.getLongSupportMessageForUser(admin1,
    +-                        DpmMockContext.CALLER_USER_HANDLE);
    +-                fail("Only system should be able to call getXXXForUser versions");
    +-            } catch (SecurityException expected) {
    +-                MoreAsserts.assertContainsRegex("message for user", expected.getMessage());
    +-            }
    +-        }
    +-
    +-        // Can't set message for admin in another uid.
    +-        {
    +-            mContext.binder.callingUid = DpmMockContext.CALLER_UID + 1;
    +-            try {
    +-                dpm.setShortSupportMessage(admin1, "Some text");
    +-                fail("Admins should only be able to change their own support text.");
    +-            } catch (SecurityException expected) {
    +-                MoreAsserts.assertContainsRegex("is not owned by uid", expected.getMessage());
    +-            }
    +-            mContext.binder.callingUid = DpmMockContext.CALLER_UID;
    +-        }
    +-
    +-        // Set/Get short returns what it sets and other admins text isn't changed.
    +-        {
    +-            final String supportText = "Some text to test with.";
    +-            dpm.setShortSupportMessage(admin1, supportText);
    +-            assertEquals(supportText, dpm.getShortSupportMessage(admin1));
    +-            assertNull(dpm.getLongSupportMessage(admin1));
    +-            assertNull(dpm.getShortSupportMessage(admin2));
    +-
    +-            mContext.binder.callingUid = DpmMockContext.SYSTEM_UID;
    +-            assertEquals(supportText, dpm.getShortSupportMessageForUser(admin1,
    +-                    DpmMockContext.CALLER_USER_HANDLE));
    +-            assertNull(dpm.getShortSupportMessageForUser(admin2,
    +-                    DpmMockContext.CALLER_USER_HANDLE));
    +-            assertNull(dpm.getLongSupportMessageForUser(admin1,
    +-                    DpmMockContext.CALLER_USER_HANDLE));
    +-            mMockContext.binder.callingUid = DpmMockContext.CALLER_UID;
    +-
    +-            dpm.setShortSupportMessage(admin1, null);
    +-            assertNull(dpm.getShortSupportMessage(admin1));
    +-        }
    +-
    +-        // Set/Get long returns what it sets and other admins text isn't changed.
    +-        {
    +-            final String supportText = "Some text to test with.\nWith more text.";
    +-            dpm.setLongSupportMessage(admin1, supportText);
    +-            assertEquals(supportText, dpm.getLongSupportMessage(admin1));
    +-            assertNull(dpm.getShortSupportMessage(admin1));
    +-            assertNull(dpm.getLongSupportMessage(admin2));
    +-
    +-            mContext.binder.callingUid = DpmMockContext.SYSTEM_UID;
    +-            assertEquals(supportText, dpm.getLongSupportMessageForUser(admin1,
    +-                    DpmMockContext.CALLER_USER_HANDLE));
    +-            assertNull(dpm.getLongSupportMessageForUser(admin2,
    +-                    DpmMockContext.CALLER_USER_HANDLE));
    +-            assertNull(dpm.getShortSupportMessageForUser(admin1,
    +-                    DpmMockContext.CALLER_USER_HANDLE));
    +-            mMockContext.binder.callingUid = DpmMockContext.CALLER_UID;
    +-
    +-            dpm.setLongSupportMessage(admin1, null);
    +-            assertNull(dpm.getLongSupportMessage(admin1));
    +-        }
    +-    }
    +-
    +-    /**
    +-     * Test for:
    +-     * {@link DevicePolicyManager#setAffiliationIds}
    +-     * {@link DevicePolicyManager#isAffiliatedUser}
    +-     */
    +-    public void testUserAffiliation() throws Exception {
    +-        mContext.callerPermissions.add(permission.MANAGE_DEVICE_ADMINS);
    +-        mContext.callerPermissions.add(permission.MANAGE_PROFILE_AND_DEVICE_OWNERS);
    +-        mContext.callerPermissions.add(permission.INTERACT_ACROSS_USERS_FULL);
    +-
    +-        // Check that the system user is unaffiliated.
    +-        mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID;
    +-        assertFalse(dpm.isAffiliatedUser());
    +-
    +-        // Set a device owner on the system user. Check that the system user becomes affiliated.
    +-        setUpPackageManagerForAdmin(admin1, DpmMockContext.CALLER_SYSTEM_USER_UID);
    +-        dpm.setActiveAdmin(admin1, /* replace =*/ false);
    +-        assertTrue(dpm.setDeviceOwner(admin1, "owner-name"));
    +-        assertTrue(dpm.isAffiliatedUser());
    +-
    +-        // Install a profile owner whose package name matches the device owner on a test user. Check
    +-        // that the test user is unaffiliated.
    +-        mContext.binder.callingUid = DpmMockContext.CALLER_UID;
    +-        setAsProfileOwner(admin2);
    +-        assertFalse(dpm.isAffiliatedUser());
    +-
    +-        // Have the profile owner specify a set of affiliation ids. Check that the test user remains
    +-        // unaffiliated.
    +-        final Set<String> userAffiliationIds = new ArraySet<>();
    +-        userAffiliationIds.add("red");
    +-        userAffiliationIds.add("green");
    +-        userAffiliationIds.add("blue");
    +-        dpm.setAffiliationIds(admin2, userAffiliationIds);
    +-        assertFalse(dpm.isAffiliatedUser());
    +-
    +-        // Have the device owner specify a set of affiliation ids that do not intersect with those
    +-        // specified by the profile owner. Check that the test user remains unaffiliated.
    +-        final Set<String> deviceAffiliationIds = new ArraySet<>();
    +-        deviceAffiliationIds.add("cyan");
    +-        deviceAffiliationIds.add("yellow");
    +-        deviceAffiliationIds.add("magenta");
    +-        mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID;
    +-        dpm.setAffiliationIds(admin1, deviceAffiliationIds);
    +-        mContext.binder.callingUid = DpmMockContext.CALLER_UID;
    +-        assertFalse(dpm.isAffiliatedUser());
    +-
    +-        // Have the profile owner specify a set of affiliation ids that intersect with those
    +-        // specified by the device owner. Check that the test user becomes affiliated.
    +-        userAffiliationIds.add("yellow");
    +-        dpm.setAffiliationIds(admin2, userAffiliationIds);
    +-        assertTrue(dpm.isAffiliatedUser());
    +-
    +-        // Change the profile owner to one whose package name does not match the device owner. Check
    +-        // that the test user is not affiliated anymore.
    +-        dpm.clearProfileOwner(admin2);
    +-        final ComponentName admin = new ComponentName("test", "test");
    +-
    +-        setUpPackageManagerForFakeAdmin(admin, DpmMockContext.CALLER_UID,
    +-                /* enabledSetting =*/ PackageManager.COMPONENT_ENABLED_STATE_ENABLED,
    +-                /* appTargetSdk = */ null, admin2);
    +-
    +-        dpm.setActiveAdmin(admin, /* refreshing =*/ true, DpmMockContext.CALLER_USER_HANDLE);
    +-        assertTrue(dpm.setProfileOwner(admin, "owner-name", DpmMockContext.CALLER_USER_HANDLE));
    +-        assertFalse(dpm.isAffiliatedUser());
    +-
    +-        // Check that the system user remains affiliated.
    +-        mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID;
    +-        assertTrue(dpm.isAffiliatedUser());
    +-    }
    +-
    +-    public void testGetUserProvisioningState_defaultResult() {
    +-        assertEquals(DevicePolicyManager.STATE_USER_UNMANAGED, dpm.getUserProvisioningState());
    +-    }
    +-
    +-    public void testSetUserProvisioningState_permission() throws Exception {
    +-        setupProfileOwner();
    +-        mContext.callerPermissions.add(permission.MANAGE_PROFILE_AND_DEVICE_OWNERS);
    +-
    +-        exerciseUserProvisioningTransitions(DpmMockContext.CALLER_USER_HANDLE,
    +-                DevicePolicyManager.STATE_USER_SETUP_FINALIZED);
    +-    }
    +-
    +-    public void testSetUserProvisioningState_unprivileged() throws Exception {
    +-        setupProfileOwner();
    +-        try {
    +-            dpm.setUserProvisioningState(DevicePolicyManager.STATE_USER_SETUP_FINALIZED,
    +-                    DpmMockContext.CALLER_USER_HANDLE);
    +-            fail("Expected SecurityException");
    +-        } catch (SecurityException expected) {
    +-        }
    +-    }
    +-
    +-    public void testSetUserProvisioningState_noManagement() {
    +-        mContext.callerPermissions.add(permission.MANAGE_PROFILE_AND_DEVICE_OWNERS);
    +-        try {
    +-            dpm.setUserProvisioningState(DevicePolicyManager.STATE_USER_SETUP_FINALIZED,
    +-                    DpmMockContext.CALLER_USER_HANDLE);
    +-            fail("IllegalStateException expected");
    +-        } catch (IllegalStateException e) {
    +-            MoreAsserts.assertContainsRegex("change provisioning state unless a .* owner is set",
    +-                    e.getMessage());
    +-        }
    +-        assertEquals(DevicePolicyManager.STATE_USER_UNMANAGED, dpm.getUserProvisioningState());
    +-    }
    +-
    +-    public void testSetUserProvisioningState_deviceOwnerFromSetupWizard() throws Exception {
    +-        mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID;
    +-        setupDeviceOwner();
    +-        mContext.callerPermissions.add(permission.MANAGE_PROFILE_AND_DEVICE_OWNERS);
    +-
    +-        exerciseUserProvisioningTransitions(UserHandle.USER_SYSTEM,
    +-                DevicePolicyManager.STATE_USER_SETUP_COMPLETE,
    +-                DevicePolicyManager.STATE_USER_SETUP_FINALIZED);
    +-    }
    +-
    +-    public void testSetUserProvisioningState_deviceOwnerFromSetupWizardAlternative()
    +-            throws Exception {
    +-        mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID;
    +-        setupDeviceOwner();
    +-        mContext.callerPermissions.add(permission.MANAGE_PROFILE_AND_DEVICE_OWNERS);
    +-
    +-        exerciseUserProvisioningTransitions(UserHandle.USER_SYSTEM,
    +-                DevicePolicyManager.STATE_USER_SETUP_INCOMPLETE,
    +-                DevicePolicyManager.STATE_USER_SETUP_FINALIZED);
    +-    }
    +-
    +-    public void testSetUserProvisioningState_deviceOwnerWithoutSetupWizard() throws Exception {
    +-        mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID;
    +-        setupDeviceOwner();
    +-        mContext.callerPermissions.add(permission.MANAGE_PROFILE_AND_DEVICE_OWNERS);
    +-
    +-        exerciseUserProvisioningTransitions(UserHandle.USER_SYSTEM,
    +-                DevicePolicyManager.STATE_USER_SETUP_FINALIZED);
    +-    }
    +-
    +-    public void testSetUserProvisioningState_managedProfileFromSetupWizard_primaryUser()
    +-            throws Exception {
    +-        setupProfileOwner();
    +-        mContext.callerPermissions.add(permission.MANAGE_PROFILE_AND_DEVICE_OWNERS);
    +-
    +-        exerciseUserProvisioningTransitions(DpmMockContext.CALLER_USER_HANDLE,
    +-                DevicePolicyManager.STATE_USER_PROFILE_COMPLETE,
    +-                DevicePolicyManager.STATE_USER_UNMANAGED);
    +-    }
    +-
    +-    public void testSetUserProvisioningState_managedProfileFromSetupWizard_managedProfile()
    +-            throws Exception {
    +-        setupProfileOwner();
    +-        mContext.callerPermissions.add(permission.MANAGE_PROFILE_AND_DEVICE_OWNERS);
    +-
    +-        exerciseUserProvisioningTransitions(DpmMockContext.CALLER_USER_HANDLE,
    +-                DevicePolicyManager.STATE_USER_SETUP_COMPLETE,
    +-                DevicePolicyManager.STATE_USER_SETUP_FINALIZED);
    +-    }
    +-
    +-    public void testSetUserProvisioningState_managedProfileWithoutSetupWizard() throws Exception {
    +-        setupProfileOwner();
    +-        mContext.callerPermissions.add(permission.MANAGE_PROFILE_AND_DEVICE_OWNERS);
    +-
    +-        exerciseUserProvisioningTransitions(DpmMockContext.CALLER_USER_HANDLE,
    +-                DevicePolicyManager.STATE_USER_SETUP_FINALIZED);
    +-    }
    +-
    +-    public void testSetUserProvisioningState_illegalTransitionOutOfFinalized1() throws Exception {
    +-        setupProfileOwner();
    +-        mContext.callerPermissions.add(permission.MANAGE_PROFILE_AND_DEVICE_OWNERS);
    +-
    +-        try {
    +-            exerciseUserProvisioningTransitions(DpmMockContext.CALLER_USER_HANDLE,
    +-                    DevicePolicyManager.STATE_USER_SETUP_FINALIZED,
    +-                    DevicePolicyManager.STATE_USER_UNMANAGED);
    +-            fail("Expected IllegalStateException");
    +-        } catch (IllegalStateException e) {
    +-            MoreAsserts.assertContainsRegex("Cannot move to user provisioning state",
    +-                    e.getMessage());
    +-        }
    +-    }
    +-
    +-    public void testSetUserProvisioningState_illegalTransitionToAnotherInProgressState()
    +-            throws Exception {
    +-        setupProfileOwner();
    +-        mContext.callerPermissions.add(permission.MANAGE_PROFILE_AND_DEVICE_OWNERS);
    +-
    +-        try {
    +-            exerciseUserProvisioningTransitions(DpmMockContext.CALLER_USER_HANDLE,
    +-                    DevicePolicyManager.STATE_USER_SETUP_INCOMPLETE,
    +-                    DevicePolicyManager.STATE_USER_SETUP_COMPLETE);
    +-            fail("Expected IllegalStateException");
    +-        } catch (IllegalStateException e) {
    +-            MoreAsserts.assertContainsRegex("Cannot move to user provisioning state",
    +-                    e.getMessage());
    +-        }
    +-    }
    +-
    +-    private void exerciseUserProvisioningTransitions(int userId, int... states) {
    +-        assertEquals(DevicePolicyManager.STATE_USER_UNMANAGED, dpm.getUserProvisioningState());
    +-        for (int state : states) {
    +-            dpm.setUserProvisioningState(state, userId);
    +-            assertEquals(state, dpm.getUserProvisioningState());
    +-        }
    +-    }
    +-
    +-    private void setupProfileOwner() throws Exception {
    +-        mContext.callerPermissions.addAll(OWNER_SETUP_PERMISSIONS);
    +-
    +-        setUpPackageManagerForAdmin(admin1, DpmMockContext.CALLER_UID);
    +-        dpm.setActiveAdmin(admin1, false);
    +-        assertTrue(dpm.setProfileOwner(admin1, null, DpmMockContext.CALLER_USER_HANDLE));
    +-
    +-        mContext.callerPermissions.removeAll(OWNER_SETUP_PERMISSIONS);
    +-    }
    +-
    +-    private void setupDeviceOwner() throws Exception {
    +-        mContext.callerPermissions.addAll(OWNER_SETUP_PERMISSIONS);
    +-
    +-        setUpPackageManagerForAdmin(admin1, DpmMockContext.CALLER_SYSTEM_USER_UID);
    +-        dpm.setActiveAdmin(admin1, false);
    +-        assertTrue(dpm.setDeviceOwner(admin1, null, UserHandle.USER_SYSTEM));
    +-
    +-        mContext.callerPermissions.removeAll(OWNER_SETUP_PERMISSIONS);
    +-    }
    +-
    +-    public void testSetMaximumTimeToLock() {
    +-        mContext.callerPermissions.add(android.Manifest.permission.MANAGE_DEVICE_ADMINS);
    +-
    +-        dpm.setActiveAdmin(admin1, /* replace =*/ false);
    +-        dpm.setActiveAdmin(admin2, /* replace =*/ false);
    +-
    +-        reset(mMockContext.powerManagerInternal);
    +-        reset(mMockContext.settings);
    +-
    +-        dpm.setMaximumTimeToLock(admin1, 0);
    +-        verifyScreenTimeoutCall(null, false);
    +-        reset(mMockContext.powerManagerInternal);
    +-        reset(mMockContext.settings);
    +-
    +-        dpm.setMaximumTimeToLock(admin1, 1);
    +-        verifyScreenTimeoutCall(1, true);
    +-        reset(mMockContext.powerManagerInternal);
    +-        reset(mMockContext.settings);
    +-
    +-        dpm.setMaximumTimeToLock(admin2, 10);
    +-        verifyScreenTimeoutCall(null, false);
    +-        reset(mMockContext.powerManagerInternal);
    +-        reset(mMockContext.settings);
    +-
    +-        dpm.setMaximumTimeToLock(admin1, 5);
    +-        verifyScreenTimeoutCall(5, true);
    +-        reset(mMockContext.powerManagerInternal);
    +-        reset(mMockContext.settings);
    +-
    +-        dpm.setMaximumTimeToLock(admin2, 4);
    +-        verifyScreenTimeoutCall(4, true);
    +-        reset(mMockContext.powerManagerInternal);
    +-        reset(mMockContext.settings);
    +-
    +-        dpm.setMaximumTimeToLock(admin1, 0);
    +-        reset(mMockContext.powerManagerInternal);
    +-        reset(mMockContext.settings);
    +-
    +-        dpm.setMaximumTimeToLock(admin2, Integer.MAX_VALUE);
    +-        verifyScreenTimeoutCall(Integer.MAX_VALUE, true);
    +-        reset(mMockContext.powerManagerInternal);
    +-        reset(mMockContext.settings);
    +-
    +-        dpm.setMaximumTimeToLock(admin2, Integer.MAX_VALUE + 1);
    +-        verifyScreenTimeoutCall(Integer.MAX_VALUE, true);
    +-        reset(mMockContext.powerManagerInternal);
    +-        reset(mMockContext.settings);
    +-
    +-        dpm.setMaximumTimeToLock(admin2, 10);
    +-        verifyScreenTimeoutCall(10, true);
    +-        reset(mMockContext.powerManagerInternal);
    +-        reset(mMockContext.settings);
    +-
    +-        // There's no restriction; shold be set to MAX.
    +-        dpm.setMaximumTimeToLock(admin2, 0);
    +-        verifyScreenTimeoutCall(Integer.MAX_VALUE, false);
    +-    }
    +-
    +-    private void verifyScreenTimeoutCall(Integer expectedTimeout,
    +-            boolean shouldStayOnWhilePluggedInBeCleared) {
    +-        if (expectedTimeout == null) {
    +-            verify(mMockContext.powerManagerInternal, times(0))
    +-                    .setMaximumScreenOffTimeoutFromDeviceAdmin(anyInt());
    +-        } else {
    +-            verify(mMockContext.powerManagerInternal, times(1))
    +-                    .setMaximumScreenOffTimeoutFromDeviceAdmin(eq(expectedTimeout));
    +-        }
    +-        // TODO Verify calls to settingsGlobalPutInt.  Tried but somehow mockito threw
    +-        // UnfinishedVerificationException.
    +-    }
    +-
    +-    public void testIsProvisioningAllowed_DeviceAdminFeatureOff() throws Exception {
    +-        when(mContext.packageManager.hasSystemFeature(PackageManager.FEATURE_DEVICE_ADMIN))
    +-                .thenReturn(false);
    +-        when(mContext.ipackageManager.hasSystemFeature(PackageManager.FEATURE_MANAGED_USERS, 0))
    +-                .thenReturn(false);
    +-        initializeDpms();
    +-        when(mContext.userManagerForMock.isSplitSystemUser()).thenReturn(false);
    +-        when(mContext.userManager.canAddMoreManagedProfiles(UserHandle.USER_SYSTEM, true))
    +-                .thenReturn(true);
    +-        setUserSetupCompleteForUser(false, UserHandle.USER_SYSTEM);
    +-
    +-        mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID;
    +-
    +-        assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_DEVICE, false);
    +-        assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE, false);
    +-        assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_SHAREABLE_DEVICE,
    +-                false);
    +-        assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_USER, false);
    +-    }
    +-
    +-    public void testIsProvisioningAllowed_ManagedProfileFeatureOff() throws Exception {
    +-        when(mContext.ipackageManager.hasSystemFeature(PackageManager.FEATURE_MANAGED_USERS, 0))
    +-                .thenReturn(false);
    +-        initializeDpms();
    +-        when(mContext.userManagerForMock.isSplitSystemUser()).thenReturn(false);
    +-        when(mContext.userManager.canAddMoreManagedProfiles(UserHandle.USER_SYSTEM, true))
    +-                .thenReturn(true);
    +-        setUserSetupCompleteForUser(false, UserHandle.USER_SYSTEM);
    +-
    +-        mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID;
    +-
    +-        assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_DEVICE, true);
    +-        assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE, false);
    +-        assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_SHAREABLE_DEVICE,
    +-                false);
    +-        assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_USER, false);
    +-
    +-        // Test again when split user is on
    +-        when(mContext.userManagerForMock.isSplitSystemUser()).thenReturn(true);
    +-        assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_DEVICE, true);
    +-        assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE, false);
    +-        assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_SHAREABLE_DEVICE,
    +-                true);
    +-        assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_USER, false);
    +-    }
    +-
    +-    public void testIsProvisioningAllowed_nonSplitUser_firstBoot_primaryUser() throws Exception {
    +-        when(mContext.ipackageManager.hasSystemFeature(PackageManager.FEATURE_MANAGED_USERS, 0))
    +-                .thenReturn(true);
    +-        when(mContext.userManagerForMock.isSplitSystemUser()).thenReturn(false);
    +-        when(mContext.userManager.canAddMoreManagedProfiles(UserHandle.USER_SYSTEM, true))
    +-                .thenReturn(true);
    +-        setUserSetupCompleteForUser(false, UserHandle.USER_SYSTEM);
    +-
    +-        mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID;
    +-
    +-        assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_DEVICE, true);
    +-        assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE, true);
    +-        assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_SHAREABLE_DEVICE,
    +-                false /* because of non-split user */);
    +-        assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_USER,
    +-                false /* because of non-split user */);
    +-    }
    +-
    +-    public void testIsProvisioningAllowed_nonSplitUser_afterDeviceSetup_primaryUser()
    +-            throws Exception {
    +-        when(mContext.ipackageManager.hasSystemFeature(PackageManager.FEATURE_MANAGED_USERS, 0))
    +-                .thenReturn(true);
    +-        when(mContext.userManagerForMock.isSplitSystemUser()).thenReturn(false);
    +-        when(mContext.userManager.canAddMoreManagedProfiles(UserHandle.USER_SYSTEM, true))
    +-                .thenReturn(true);
    +-        setUserSetupCompleteForUser(true, UserHandle.USER_SYSTEM);
    +-
    +-        mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID;
    +-
    +-        assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_DEVICE,
    +-                false/* because of completed device setup */);
    +-        assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE, true);
    +-        assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_SHAREABLE_DEVICE,
    +-                false/* because of non-split user */);
    +-        assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_USER,
    +-                false/* because of non-split user */);
    +-    }
    +-
    +-    public void testIsProvisioningAllowed_splitUser_firstBoot_systemUser() throws Exception {
    +-        when(mContext.ipackageManager.hasSystemFeature(PackageManager.FEATURE_MANAGED_USERS, 0))
    +-                .thenReturn(true);
    +-        when(mContext.userManagerForMock.isSplitSystemUser()).thenReturn(true);
    +-        when(mContext.userManager.canAddMoreManagedProfiles(UserHandle.USER_SYSTEM, true))
    +-                .thenReturn(false);
    +-        setUserSetupCompleteForUser(false, UserHandle.USER_SYSTEM);
    +-
    +-        mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID;
    +-
    +-        assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_DEVICE, true);
    +-        assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE,
    +-                false /* because canAddMoreManagedProfiles returns false */);
    +-        assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_SHAREABLE_DEVICE,
    +-                true);
    +-        assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_USER,
    +-                false/* because calling uid is system user */);
    +-
    +-    }
    +-
    +-    public void testIsProvisioningAllowed_splitUser_afterDeviceSetup_systemUser() throws Exception {
    +-        when(mContext.ipackageManager.hasSystemFeature(PackageManager.FEATURE_MANAGED_USERS, 0))
    +-                .thenReturn(true);
    +-        when(mContext.userManagerForMock.isSplitSystemUser()).thenReturn(true);
    +-        when(mContext.userManager.canAddMoreManagedProfiles(UserHandle.USER_SYSTEM, true))
    +-                .thenReturn(false);
    +-        setUserSetupCompleteForUser(true, UserHandle.USER_SYSTEM);
    +-
    +-        mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID;
    +-
    +-        assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_DEVICE,
    +-                true/* it's undefined behavior. Can be changed into false in the future */);
    +-        assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE,
    +-                false /* because canAddMoreManagedProfiles returns false */);
    +-        assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_SHAREABLE_DEVICE,
    +-                true/* it's undefined behavior. Can be changed into false in the future */);
    +-        assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_USER,
    +-                false/* because calling uid is system user */);
    +-    }
    +-
    +-    public void testIsProvisioningAllowed_splitUser_firstBoot_primaryUser() throws Exception {
    +-        when(mContext.ipackageManager.hasSystemFeature(PackageManager.FEATURE_MANAGED_USERS, 0))
    +-                .thenReturn(true);
    +-        when(mContext.userManagerForMock.isSplitSystemUser()).thenReturn(true);
    +-        when(mContext.userManager.canAddMoreManagedProfiles(DpmMockContext.CALLER_USER_HANDLE,
    +-                true)).thenReturn(true);
    +-        setUserSetupCompleteForUser(false, DpmMockContext.CALLER_USER_HANDLE);
    +-
    +-        mContext.binder.callingUid = DpmMockContext.CALLER_UID;
    +-
    +-        assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_DEVICE, true);
    +-        assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE, true);
    +-        assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_SHAREABLE_DEVICE,
    +-                true);
    +-        assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_USER, true);
    +-
    +-    }
    +-
    +-    public void testIsProvisioningAllowed_splitUser_afterDeviceSetup_primaryUser()
    +-            throws Exception {
    +-        when(mContext.ipackageManager.hasSystemFeature(PackageManager.FEATURE_MANAGED_USERS, 0))
    +-                .thenReturn(true);
    +-        when(mContext.userManagerForMock.isSplitSystemUser()).thenReturn(true);
    +-        when(mContext.userManager.canAddMoreManagedProfiles(DpmMockContext.CALLER_USER_HANDLE,
    +-                true)).thenReturn(true);
    +-        setUserSetupCompleteForUser(true, DpmMockContext.CALLER_USER_HANDLE);
    +-
    +-        mContext.binder.callingUid = DpmMockContext.CALLER_UID;
    +-
    +-        assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_DEVICE,
    +-                true/* it's undefined behavior. Can be changed into false in the future */);
    +-        assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE, true);
    +-        assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_SHAREABLE_DEVICE,
    +-                true/* it's undefined behavior. Can be changed into false in the future */);
    +-        assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_USER,
    +-                false/* because user setup completed */);
    +-    }
    +-
    +-    public void testIsProvisioningAllowed_provisionManagedProfileWithDeviceOwner_systemUser()
    +-            throws Exception {
    +-        setDeviceOwner();
    +-
    +-        when(mContext.ipackageManager.hasSystemFeature(PackageManager.FEATURE_MANAGED_USERS, 0))
    +-                .thenReturn(true);
    +-        when(mContext.userManagerForMock.isSplitSystemUser()).thenReturn(true);
    +-        when(mContext.userManager.canAddMoreManagedProfiles(UserHandle.USER_SYSTEM, true))
    +-                .thenReturn(false);
    +-        setUserSetupCompleteForUser(true, UserHandle.USER_SYSTEM);
    +-
    +-        mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID;
    +-
    +-        assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE,
    +-                false /* can't provision managed profile on system user */);
    +-    }
    +-
    +-    public void testIsProvisioningAllowed_provisionManagedProfileWithDeviceOwner_primaryUser()
    +-            throws Exception {
    +-        setDeviceOwner();
    +-
    +-        when(mContext.ipackageManager.hasSystemFeature(PackageManager.FEATURE_MANAGED_USERS, 0))
    +-                .thenReturn(true);
    +-        when(mContext.userManagerForMock.isSplitSystemUser()).thenReturn(true);
    +-        when(mContext.userManager.canAddMoreManagedProfiles(DpmMockContext.CALLER_USER_HANDLE,
    +-                true)).thenReturn(true);
    +-        setUserSetupCompleteForUser(false, DpmMockContext.CALLER_USER_HANDLE);
    +-
    +-        mContext.binder.callingUid = DpmMockContext.CALLER_UID;
    +-
    +-        assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE, true);
    +-    }
    +-
    +-    private void setUserSetupCompleteForUser(boolean isUserSetupComplete, int userhandle) {
    +-        when(mContext.settings.settingsSecureGetIntForUser(Settings.Secure.USER_SETUP_COMPLETE, 0,
    +-                userhandle)).thenReturn(isUserSetupComplete ? 1 : 0);
    +-        dpms.notifyChangeToContentObserver(
    +-                Settings.Secure.getUriFor(Settings.Secure.USER_SETUP_COMPLETE), userhandle);
    +-    }
    +-
    +-    private void assertProvisioningAllowed(String action, boolean expected) {
    +-        assertEquals("isProvisioningAllowed(" + action + ") returning unexpected result", expected,
    +-                dpm.isProvisioningAllowed(action));
    +-    }
    +-}
    +diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTestable.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTestable.java
    +deleted file mode 100644
    +index 3da61d6..0000000
    +--- a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTestable.java
    ++++ /dev/null
    +@@ -1,37 +0,0 @@
    +-/*
    +- * Copyright (C) 2015 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 com.android.server.devicepolicy;
    +-
    +-import android.app.admin.DevicePolicyManager;
    +-import android.os.UserHandle;
    +-
    +-/**
    +- * Overrides {@link #DevicePolicyManager} for dependency injection.
    +- */
    +-public class DevicePolicyManagerTestable extends DevicePolicyManager {
    +-    public final DevicePolicyManagerServiceTestable dpms;
    +-
    +-    public DevicePolicyManagerTestable(DpmMockContext context,
    +-            DevicePolicyManagerServiceTestable dpms) {
    +-        super(context, dpms, /* parentInstance = */ false);
    +-        this.dpms = dpms;
    +-    }
    +-
    +-    @Override
    +-    public int myUserId() {
    +-        return UserHandle.getUserId(dpms.context.binder.callingUid);
    +-    }
    +-}
    +diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DpmMockContext.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DpmMockContext.java
    +deleted file mode 100644
    +index 0783afc..0000000
    +--- a/services/tests/servicestests/src/com/android/server/devicepolicy/DpmMockContext.java
    ++++ /dev/null
    +@@ -1,612 +0,0 @@
    +-/*
    +- * Copyright (C) 2015 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 com.android.server.devicepolicy;
    +-
    +-import com.android.internal.widget.LockPatternUtils;
    +-
    +-import android.app.IActivityManager;
    +-import android.app.NotificationManager;
    +-import android.app.backup.IBackupManager;
    +-import android.content.BroadcastReceiver;
    +-import android.content.ContentResolver;
    +-import android.content.Context;
    +-import android.content.Intent;
    +-import android.content.IntentFilter;
    +-import android.content.pm.IPackageManager;
    +-import android.content.pm.PackageManager;
    +-import android.content.pm.PackageManagerInternal;
    +-import android.content.pm.UserInfo;
    +-import android.media.IAudioService;
    +-import android.net.wifi.WifiManager;
    +-import android.os.Bundle;
    +-import android.os.Handler;
    +-import android.os.PowerManager.WakeLock;
    +-import android.os.PowerManagerInternal;
    +-import android.os.UserHandle;
    +-import android.os.UserManager;
    +-import android.os.UserManagerInternal;
    +-import android.telephony.TelephonyManager;
    +-import android.test.mock.MockContentResolver;
    +-import android.test.mock.MockContext;
    +-import android.view.IWindowManager;
    +-
    +-import org.junit.Assert;
    +-import org.mockito.invocation.InvocationOnMock;
    +-import org.mockito.stubbing.Answer;
    +-
    +-import java.io.File;
    +-import java.util.ArrayList;
    +-import java.util.List;
    +-
    +-import static org.mockito.Matchers.anyBoolean;
    +-import static org.mockito.Matchers.anyInt;
    +-import static org.mockito.Matchers.eq;
    +-import static org.mockito.Mockito.mock;
    +-import static org.mockito.Mockito.spy;
    +-import static org.mockito.Mockito.when;
    +-
    +-/**
    +- * Context used throughout DPMS tests.
    +- */
    +-public class DpmMockContext extends MockContext {
    +-    /**
    +-     * User-id of a non-system user we use throughout unit tests.
    +-     */
    +-    public static final int CALLER_USER_HANDLE = 20;
    +-
    +-    /**
    +-     * UID corresponding to {@link #CALLER_USER_HANDLE}.
    +-     */
    +-    public static final int CALLER_UID = UserHandle.getUid(CALLER_USER_HANDLE, 20123);
    +-
    +-    /**
    +-     * UID used when a caller is on the system user.
    +-     */
    +-    public static final int CALLER_SYSTEM_USER_UID = 20321;
    +-
    +-    /**
    +-     * PID of the caller.
    +-     */
    +-    public static final int CALLER_PID = 22222;
    +-
    +-    /**
    +-     * UID of the system server.
    +-     */
    +-    public static final int SYSTEM_UID = android.os.Process.SYSTEM_UID;
    +-
    +-    /**
    +-     * PID of the system server.
    +-     */
    +-    public static final int SYSTEM_PID = 11111;
    +-
    +-    public static class MockBinder {
    +-        public int callingUid = CALLER_UID;
    +-        public int callingPid = CALLER_PID;
    +-
    +-        public long clearCallingIdentity() {
    +-            final long token = (((long) callingUid) << 32) | (callingPid);
    +-            callingUid = SYSTEM_UID;
    +-            callingPid = SYSTEM_PID;
    +-            return token;
    +-        }
    +-
    +-        public void restoreCallingIdentity(long token) {
    +-            callingUid = (int) (token >> 32);
    +-            callingPid = (int) token;
    +-        }
    +-
    +-        public int getCallingUid() {
    +-            return callingUid;
    +-        }
    +-
    +-        public int getCallingPid() {
    +-            return callingPid;
    +-        }
    +-
    +-        public UserHandle getCallingUserHandle() {
    +-            return new UserHandle(UserHandle.getUserId(getCallingUid()));
    +-        }
    +-
    +-        public boolean isCallerUidMyUid() {
    +-            return callingUid == SYSTEM_UID;
    +-        }
    +-    }
    +-
    +-    public static class EnvironmentForMock {
    +-        public File getUserSystemDirectory(int userId) {
    +-            return null;
    +-        }
    +-    }
    +-
    +-    public static class PowerManagerForMock {
    +-        public WakeLock newWakeLock(int levelAndFlags, String tag) {
    +-            return null;
    +-        }
    +-
    +-        public void goToSleep(long time, int reason, int flags) {
    +-        }
    +-
    +-        public void reboot(String reason) {
    +-        }
    +-    }
    +-
    +-    public static class SystemPropertiesForMock {
    +-        public boolean getBoolean(String key, boolean def) {
    +-            return false;
    +-        }
    +-
    +-        public long getLong(String key, long def) {
    +-            return 0;
    +-        }
    +-
    +-        public String get(String key, String def) {
    +-            return null;
    +-        }
    +-
    +-        public String get(String key) {
    +-            return null;
    +-        }
    +-
    +-        public void set(String key, String value) {
    +-        }
    +-    }
    +-
    +-    public static class UserManagerForMock {
    +-        public boolean isSplitSystemUser() {
    +-            return false;
    +-        }
    +-    }
    +-
    +-    public static class SettingsForMock {
    +-        public int settingsSecureGetIntForUser(String name, int def, int userHandle) {
    +-            return 0;
    +-        }
    +-
    +-        public void settingsSecurePutIntForUser(String name, int value, int userHandle) {
    +-        }
    +-
    +-        public void settingsSecurePutStringForUser(String name, String value, int userHandle) {
    +-        }
    +-
    +-        public void settingsGlobalPutStringForUser(String name, String value, int userHandle) {
    +-        }
    +-
    +-        public void settingsSecurePutInt(String name, int value) {
    +-        }
    +-
    +-        public void settingsGlobalPutInt(String name, int value) {
    +-        }
    +-
    +-        public void settingsSecurePutString(String name, String value) {
    +-        }
    +-
    +-        public void settingsGlobalPutString(String name, String value) {
    +-        }
    +-
    +-        public int settingsGlobalGetInt(String name, int value) {
    +-            return 0;
    +-        }
    +-
    +-        public void securityLogSetLoggingEnabledProperty(boolean enabled) {
    +-        }
    +-
    +-        public boolean securityLogGetLoggingEnabledProperty() {
    +-            return false;
    +-        }
    +-
    +-        public boolean securityLogIsLoggingEnabled() {
    +-            return false;
    +-        }
    +-    }
    +-
    +-    public static class StorageManagerForMock {
    +-        public boolean isFileBasedEncryptionEnabled() {
    +-            return false;
    +-        }
    +-
    +-        public boolean isNonDefaultBlockEncrypted() {
    +-            return false;
    +-        }
    +-
    +-        public boolean isEncrypted() {
    +-            return false;
    +-        }
    +-
    +-        public boolean isEncryptable() {
    +-            return false;
    +-        }
    +-    }
    +-
    +-    public final Context realTestContext;
    +-
    +-    /**
    +-     * Use this instance to verify unimplemented methods such as {@link #sendBroadcast}.
    +-     * (Spying on {@code this} instance will confuse mockito somehow and I got weired "wrong number
    +-     * of arguments" exceptions.)
    +-     */
    +-    public final Context spiedContext;
    +-
    +-    public final File dataDir;
    +-    public final File systemUserDataDir;
    +-
    +-    public final MockBinder binder;
    +-    public final EnvironmentForMock environment;
    +-    public final SystemPropertiesForMock systemProperties;
    +-    public final UserManager userManager;
    +-    public final UserManagerInternal userManagerInternal;
    +-    public final PackageManagerInternal packageManagerInternal;
    +-    public final UserManagerForMock userManagerForMock;
    +-    public final PowerManagerForMock powerManager;
    +-    public final PowerManagerInternal powerManagerInternal;
    +-    public final NotificationManager notificationManager;
    +-    public final IWindowManager iwindowManager;
    +-    public final IActivityManager iactivityManager;
    +-    public final IPackageManager ipackageManager;
    +-    public final IBackupManager ibackupManager;
    +-    public final IAudioService iaudioService;
    +-    public final LockPatternUtils lockPatternUtils;
    +-    public final StorageManagerForMock storageManager;
    +-    public final WifiManager wifiManager;
    +-    public final SettingsForMock settings;
    +-    public final MockContentResolver contentResolver;
    +-    public final TelephonyManager telephonyManager;
    +-
    +-    /** Note this is a partial mock, not a real mock. */
    +-    public final PackageManager packageManager;
    +-
    +-    public final List<String> callerPermissions = new ArrayList<>();
    +-
    +-    private final ArrayList<UserInfo> mUserInfos = new ArrayList<>();
    +-
    +-    public DpmMockContext(Context context, File dataDir) {
    +-        realTestContext = context;
    +-
    +-        this.dataDir = dataDir;
    +-        DpmTestUtils.clearDir(dataDir);
    +-
    +-        binder = new MockBinder();
    +-        environment = mock(EnvironmentForMock.class);
    +-        systemProperties= mock(SystemPropertiesForMock.class);
    +-        userManager = mock(UserManager.class);
    +-        userManagerInternal = mock(UserManagerInternal.class);
    +-        userManagerForMock = mock(UserManagerForMock.class);
    +-        packageManagerInternal = mock(PackageManagerInternal.class);
    +-        powerManager = mock(PowerManagerForMock.class);
    +-        powerManagerInternal = mock(PowerManagerInternal.class);
    +-        notificationManager = mock(NotificationManager.class);
    +-        iwindowManager = mock(IWindowManager.class);
    +-        iactivityManager = mock(IActivityManager.class);
    +-        ipackageManager = mock(IPackageManager.class);
    +-        ibackupManager = mock(IBackupManager.class);
    +-        iaudioService = mock(IAudioService.class);
    +-        lockPatternUtils = mock(LockPatternUtils.class);
    +-        storageManager = mock(StorageManagerForMock.class);
    +-        wifiManager = mock(WifiManager.class);
    +-        settings = mock(SettingsForMock.class);
    +-        telephonyManager = mock(TelephonyManager.class);
    +-
    +-        // Package manager is huge, so we use a partial mock instead.
    +-        packageManager = spy(context.getPackageManager());
    +-
    +-        spiedContext = mock(Context.class);
    +-
    +-        contentResolver = new MockContentResolver();
    +-
    +-        // Add the system user
    +-        systemUserDataDir = addUser(UserHandle.USER_SYSTEM, UserInfo.FLAG_PRIMARY);
    +-
    +-        // System user is always running.
    +-        setUserRunning(UserHandle.USER_SYSTEM, true);
    +-    }
    +-
    +-    public File addUser(int userId, int flags) {
    +-
    +-        // Set up (default) UserInfo for CALLER_USER_HANDLE.
    +-        final UserInfo uh = new UserInfo(userId, "user" + userId, flags);
    +-        when(userManager.getUserInfo(eq(userId))).thenReturn(uh);
    +-
    +-        mUserInfos.add(uh);
    +-        when(userManager.getUsers()).thenReturn(mUserInfos);
    +-        when(userManager.getUsers(anyBoolean())).thenReturn(mUserInfos);
    +-        when(userManager.isUserRunning(eq(new UserHandle(userId)))).thenReturn(true);
    +-        when(userManager.getUserInfo(anyInt())).thenAnswer(
    +-                new Answer<UserInfo>() {
    +-                    @Override
    +-                    public UserInfo answer(InvocationOnMock invocation) throws Throwable {
    +-                        final int userId = (int) invocation.getArguments()[0];
    +-                        for (UserInfo ui : mUserInfos) {
    +-                            if (ui.id == userId) {
    +-                                return ui;
    +-                            }
    +-                        }
    +-                        return null;
    +-                    }
    +-                }
    +-        );
    +-        when(userManager.getProfiles(anyInt())).thenAnswer(
    +-                new Answer<List<UserInfo>>() {
    +-                    @Override
    +-                    public List<UserInfo> answer(InvocationOnMock invocation) throws Throwable {
    +-                        final int userId = (int) invocation.getArguments()[0];
    +-                        return getProfiles(userId);
    +-                    }
    +-                }
    +-        );
    +-        when(userManager.getProfileIdsWithDisabled(anyInt())).thenAnswer(
    +-                new Answer<int[]>() {
    +-                    @Override
    +-                    public int[] answer(InvocationOnMock invocation) throws Throwable {
    +-                        final int userId = (int) invocation.getArguments()[0];
    +-                        List<UserInfo> profiles = getProfiles(userId);
    +-                        int[] results = new int[profiles.size()];
    +-                        for (int i = 0; i < results.length; i++) {
    +-                            results[i] = profiles.get(i).id;
    +-                        }
    +-                        return results;
    +-                    }
    +-                }
    +-        );
    +-
    +-
    +-        // Create a data directory.
    +-        final File dir = new File(dataDir, "user" + userId);
    +-        DpmTestUtils.clearDir(dir);
    +-
    +-        when(environment.getUserSystemDirectory(eq(userId))).thenReturn(dir);
    +-        return dir;
    +-    }
    +-
    +-    private List<UserInfo> getProfiles(int userId) {
    +-        final ArrayList<UserInfo> ret = new ArrayList<UserInfo>();
    +-        UserInfo parent = null;
    +-        for (UserInfo ui : mUserInfos) {
    +-            if (ui.id == userId) {
    +-                parent = ui;
    +-                break;
    +-            }
    +-        }
    +-        if (parent == null) {
    +-            return ret;
    +-        }
    +-        ret.add(parent);
    +-        for (UserInfo ui : mUserInfos) {
    +-            if (ui.id == userId) {
    +-                continue;
    +-            }
    +-            if (ui.profileGroupId != UserInfo.NO_PROFILE_GROUP_ID
    +-                    && ui.profileGroupId == parent.profileGroupId) {
    +-                ret.add(ui);
    +-            }
    +-        }
    +-        return ret;
    +-    }
    +-
    +-    /**
    +-     * Add multiple users at once.  They'll all have flag 0.
    +-     */
    +-    public void addUsers(int... userIds) {
    +-        for (int userId : userIds) {
    +-            addUser(userId, 0);
    +-        }
    +-    }
    +-
    +-    public void setUserRunning(int userId, boolean isRunning) {
    +-        when(userManager.isUserRunning(MockUtils.checkUserHandle(userId)))
    +-                .thenReturn(isRunning);
    +-    }
    +-
    +-    @Override
    +-    public Object getSystemService(String name) {
    +-        switch (name) {
    +-            case Context.USER_SERVICE:
    +-                return userManager;
    +-            case Context.POWER_SERVICE:
    +-                return powerManager;
    +-            case Context.WIFI_SERVICE:
    +-                return wifiManager;
    +-        }
    +-        throw new UnsupportedOperationException();
    +-    }
    +-
    +-    @Override
    +-    public String getSystemServiceName(Class<?> serviceClass) {
    +-        return realTestContext.getSystemServiceName(serviceClass);
    +-    }
    +-
    +-    @Override
    +-    public PackageManager getPackageManager() {
    +-        return packageManager;
    +-    }
    +-
    +-    @Override
    +-    public void enforceCallingOrSelfPermission(String permission, String message) {
    +-        if (binder.getCallingUid() == SYSTEM_UID) {
    +-            return; // Assume system has all permissions.
    +-        }
    +-        if (!callerPermissions.contains(permission)) {
    +-            throw new SecurityException("Caller doesn't have " + permission + " : " + message);
    +-        }
    +-    }
    +-
    +-    @Override
    +-    public void sendBroadcast(Intent intent) {
    +-        spiedContext.sendBroadcast(intent);
    +-    }
    +-
    +-    @Override
    +-    public void sendBroadcast(Intent intent, String receiverPermission) {
    +-        spiedContext.sendBroadcast(intent, receiverPermission);
    +-    }
    +-
    +-    @Override
    +-    public void sendBroadcastMultiplePermissions(Intent intent, String[] receiverPermissions) {
    +-        spiedContext.sendBroadcastMultiplePermissions(intent, receiverPermissions);
    +-    }
    +-
    +-    @Override
    +-    public void sendBroadcast(Intent intent, String receiverPermission, Bundle options) {
    +-        spiedContext.sendBroadcast(intent, receiverPermission, options);
    +-    }
    +-
    +-    @Override
    +-    public void sendBroadcast(Intent intent, String receiverPermission, int appOp) {
    +-        spiedContext.sendBroadcast(intent, receiverPermission, appOp);
    +-    }
    +-
    +-    @Override
    +-    public void sendOrderedBroadcast(Intent intent, String receiverPermission) {
    +-        spiedContext.sendOrderedBroadcast(intent, receiverPermission);
    +-    }
    +-
    +-    @Override
    +-    public void sendOrderedBroadcast(Intent intent, String receiverPermission,
    +-            BroadcastReceiver resultReceiver, Handler scheduler, int initialCode,
    +-            String initialData, Bundle initialExtras) {
    +-        spiedContext.sendOrderedBroadcast(intent, receiverPermission, resultReceiver, scheduler,
    +-                initialCode, initialData, initialExtras);
    +-    }
    +-
    +-    @Override
    +-    public void sendOrderedBroadcast(Intent intent, String receiverPermission, Bundle options,
    +-            BroadcastReceiver resultReceiver, Handler scheduler, int initialCode,
    +-            String initialData, Bundle initialExtras) {
    +-        spiedContext.sendOrderedBroadcast(intent, receiverPermission, options, resultReceiver,
    +-                scheduler,
    +-                initialCode, initialData, initialExtras);
    +-    }
    +-
    +-    @Override
    +-    public void sendOrderedBroadcast(Intent intent, String receiverPermission, int appOp,
    +-            BroadcastReceiver resultReceiver, Handler scheduler, int initialCode,
    +-            String initialData, Bundle initialExtras) {
    +-        spiedContext.sendOrderedBroadcast(intent, receiverPermission, appOp, resultReceiver,
    +-                scheduler,
    +-                initialCode, initialData, initialExtras);
    +-    }
    +-
    +-    @Override
    +-    public void sendBroadcastAsUser(Intent intent, UserHandle user) {
    +-        if (binder.callingPid != SYSTEM_PID) {
    +-            // Unless called as the system process, can only call if the target user is the
    +-            // calling user.
    +-            // (The actual check is more complex; we may need to change it later.)
    +-            Assert.assertEquals(UserHandle.getUserId(binder.getCallingUid()), user.getIdentifier());
    +-        }
    +-
    +-        spiedContext.sendBroadcastAsUser(intent, user);
    +-    }
    +-
    +-    @Override
    +-    public void sendBroadcastAsUser(Intent intent, UserHandle user, String receiverPermission) {
    +-        spiedContext.sendBroadcastAsUser(intent, user, receiverPermission);
    +-    }
    +-
    +-    @Override
    +-    public void sendBroadcastAsUser(Intent intent, UserHandle user, String receiverPermission,
    +-            int appOp) {
    +-        spiedContext.sendBroadcastAsUser(intent, user, receiverPermission, appOp);
    +-    }
    +-
    +-    @Override
    +-    public void sendOrderedBroadcastAsUser(Intent intent, UserHandle user,
    +-            String receiverPermission, BroadcastReceiver resultReceiver, Handler scheduler,
    +-            int initialCode, String initialData, Bundle initialExtras) {
    +-        spiedContext.sendOrderedBroadcastAsUser(intent, user, receiverPermission, resultReceiver,
    +-                scheduler, initialCode, initialData, initialExtras);
    +-        resultReceiver.onReceive(spiedContext, intent);
    +-    }
    +-
    +-    @Override
    +-    public void sendOrderedBroadcastAsUser(Intent intent, UserHandle user,
    +-            String receiverPermission, int appOp, BroadcastReceiver resultReceiver,
    +-            Handler scheduler, int initialCode, String initialData, Bundle initialExtras) {
    +-        spiedContext.sendOrderedBroadcastAsUser(intent, user, receiverPermission, appOp,
    +-                resultReceiver,
    +-                scheduler, initialCode, initialData, initialExtras);
    +-    }
    +-
    +-    @Override
    +-    public void sendOrderedBroadcastAsUser(Intent intent, UserHandle user,
    +-            String receiverPermission, int appOp, Bundle options, BroadcastReceiver resultReceiver,
    +-            Handler scheduler, int initialCode, String initialData, Bundle initialExtras) {
    +-        spiedContext.sendOrderedBroadcastAsUser(intent, user, receiverPermission, appOp, options,
    +-                resultReceiver, scheduler, initialCode, initialData, initialExtras);
    +-    }
    +-
    +-    @Override
    +-    public void sendStickyBroadcast(Intent intent) {
    +-        spiedContext.sendStickyBroadcast(intent);
    +-    }
    +-
    +-    @Override
    +-    public void sendStickyOrderedBroadcast(Intent intent, BroadcastReceiver resultReceiver,
    +-            Handler scheduler, int initialCode, String initialData, Bundle initialExtras) {
    +-        spiedContext.sendStickyOrderedBroadcast(intent, resultReceiver, scheduler, initialCode,
    +-                initialData, initialExtras);
    +-    }
    +-
    +-    @Override
    +-    public void removeStickyBroadcast(Intent intent) {
    +-        spiedContext.removeStickyBroadcast(intent);
    +-    }
    +-
    +-    @Override
    +-    public void sendStickyBroadcastAsUser(Intent intent, UserHandle user) {
    +-        spiedContext.sendStickyBroadcastAsUser(intent, user);
    +-    }
    +-
    +-    @Override
    +-    public void sendStickyOrderedBroadcastAsUser(Intent intent, UserHandle user,
    +-            BroadcastReceiver resultReceiver, Handler scheduler, int initialCode,
    +-            String initialData, Bundle initialExtras) {
    +-        spiedContext.sendStickyOrderedBroadcastAsUser(intent, user, resultReceiver, scheduler, initialCode,
    +-                initialData, initialExtras);
    +-    }
    +-
    +-    @Override
    +-    public void removeStickyBroadcastAsUser(Intent intent, UserHandle user) {
    +-        spiedContext.removeStickyBroadcastAsUser(intent, user);
    +-    }
    +-
    +-    @Override
    +-    public Intent registerReceiver(BroadcastReceiver receiver, IntentFilter filter) {
    +-        return spiedContext.registerReceiver(receiver, filter);
    +-    }
    +-
    +-    @Override
    +-    public Intent registerReceiver(BroadcastReceiver receiver, IntentFilter filter,
    +-            String broadcastPermission, Handler scheduler) {
    +-        return spiedContext.registerReceiver(receiver, filter, broadcastPermission, scheduler);
    +-    }
    +-
    +-    @Override
    +-    public Intent registerReceiverAsUser(BroadcastReceiver receiver, UserHandle user,
    +-            IntentFilter filter, String broadcastPermission, Handler scheduler) {
    +-        return spiedContext.registerReceiverAsUser(receiver, user, filter, broadcastPermission,
    +-                scheduler);
    +-    }
    +-
    +-    @Override
    +-    public void unregisterReceiver(BroadcastReceiver receiver) {
    +-        spiedContext.unregisterReceiver(receiver);
    +-    }
    +-
    +-    @Override
    +-    public ContentResolver getContentResolver() {
    +-        return contentResolver;
    +-    }
    +-}
    +diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DpmTestBase.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DpmTestBase.java
    +deleted file mode 100644
    +index c80ca6c..0000000
    +--- a/services/tests/servicestests/src/com/android/server/devicepolicy/DpmTestBase.java
    ++++ /dev/null
    +@@ -1,167 +0,0 @@
    +-/*
    +- * Copyright (C) 2015 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 com.android.server.devicepolicy;
    +-
    +-import android.content.ComponentName;
    +-import android.content.Context;
    +-import android.content.Intent;
    +-import android.content.pm.ActivityInfo;
    +-import android.content.pm.ApplicationInfo;
    +-import android.content.pm.PackageInfo;
    +-import android.content.pm.PackageManager;
    +-import android.content.pm.ResolveInfo;
    +-import android.os.UserHandle;
    +-import android.test.AndroidTestCase;
    +-
    +-import java.io.File;
    +-import java.util.List;
    +-
    +-import static org.mockito.Matchers.anyInt;
    +-import static org.mockito.Matchers.eq;
    +-import static org.mockito.Mockito.doReturn;
    +-
    +-public abstract class DpmTestBase extends AndroidTestCase {
    +-    public static final String TAG = "DpmTest";
    +-
    +-    protected Context mRealTestContext;
    +-    protected DpmMockContext mMockContext;
    +-
    +-    public File dataDir;
    +-
    +-    public ComponentName admin1;
    +-    public ComponentName admin2;
    +-    public ComponentName admin3;
    +-    public ComponentName adminNoPerm;
    +-
    +-    @Override
    +-    protected void setUp() throws Exception {
    +-        super.setUp();
    +-
    +-        mRealTestContext = super.getContext();
    +-
    +-        mMockContext = new DpmMockContext(
    +-                mRealTestContext, new File(mRealTestContext.getCacheDir(), "test-data"));
    +-
    +-        admin1 = new ComponentName(mRealTestContext, DummyDeviceAdmins.Admin1.class);
    +-        admin2 = new ComponentName(mRealTestContext, DummyDeviceAdmins.Admin2.class);
    +-        admin3 = new ComponentName(mRealTestContext, DummyDeviceAdmins.Admin3.class);
    +-        adminNoPerm = new ComponentName(mRealTestContext, DummyDeviceAdmins.AdminNoPerm.class);
    +-    }
    +-
    +-    @Override
    +-    public DpmMockContext getContext() {
    +-        return mMockContext;
    +-    }
    +-
    +-    protected void markPackageAsInstalled(String packageName, ApplicationInfo ai, int userId)
    +-            throws Exception {
    +-        final PackageInfo pi = DpmTestUtils.cloneParcelable(
    +-                mRealTestContext.getPackageManager().getPackageInfo(
    +-                        mRealTestContext.getPackageName(), 0));
    +-        assertTrue(pi.applicationInfo.flags != 0);
    +-
    +-        if (ai != null) {
    +-            pi.applicationInfo = ai;
    +-        }
    +-
    +-        doReturn(pi).when(mMockContext.ipackageManager).getPackageInfo(
    +-                eq(packageName),
    +-                eq(0),
    +-                eq(userId));
    +-    }
    +-
    +-    protected void setUpPackageManagerForAdmin(ComponentName admin, int packageUid)
    +-            throws Exception {
    +-        setUpPackageManagerForAdmin(admin, packageUid,
    +-                /* enabledSetting =*/ null, /* appTargetSdk = */ null);
    +-    }
    +-
    +-    protected void setUpPackageManagerForAdmin(ComponentName admin, int packageUid,
    +-            int enabledSetting) throws Exception {
    +-        setUpPackageManagerForAdmin(admin, packageUid, enabledSetting, /* appTargetSdk = */ null);
    +-    }
    +-
    +-    protected void setUpPackageManagerForAdmin(ComponentName admin, int packageUid,
    +-            Integer enabledSetting, Integer appTargetSdk) throws Exception {
    +-        setUpPackageManagerForFakeAdmin(admin, packageUid, enabledSetting, appTargetSdk,
    +-                admin);
    +-    }
    +-
    +-    /**
    +-     * Set up a component in the mock package manager to be an active admin.
    +-     *
    +-     * @param admin ComponentName that's visible to the test code, which doesn't have to exist.
    +-     * @param copyFromAdmin package information for {@code admin} will be built based on this
    +-     *    component's information.
    +-     */
    +-    protected void setUpPackageManagerForFakeAdmin(ComponentName admin, int packageUid,
    +-            Integer enabledSetting, Integer appTargetSdk, ComponentName copyFromAdmin)
    +-            throws Exception {
    +-
    +-        // Set up getApplicationInfo().
    +-
    +-        final ApplicationInfo ai = DpmTestUtils.cloneParcelable(
    +-                mRealTestContext.getPackageManager().getApplicationInfo(
    +-                        copyFromAdmin.getPackageName(),
    +-                        PackageManager.GET_DISABLED_UNTIL_USED_COMPONENTS));
    +-
    +-        ai.enabledSetting = enabledSetting == null
    +-                ? PackageManager.COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED
    +-                : enabledSetting;
    +-        if (appTargetSdk != null) {
    +-            ai.targetSdkVersion = appTargetSdk;
    +-        }
    +-        ai.uid = packageUid;
    +-        ai.packageName = admin.getPackageName();
    +-        ai.name = admin.getClassName();
    +-
    +-        doReturn(ai).when(mMockContext.ipackageManager).getApplicationInfo(
    +-                eq(admin.getPackageName()),
    +-                eq(PackageManager.GET_DISABLED_UNTIL_USED_COMPONENTS),
    +-                eq(UserHandle.getUserId(packageUid)));
    +-
    +-        // Set up queryBroadcastReceivers().
    +-
    +-        final Intent resolveIntent = new Intent();
    +-        resolveIntent.setComponent(copyFromAdmin);
    +-        final List<ResolveInfo> realResolveInfo =
    +-                mRealTestContext.getPackageManager().queryBroadcastReceivers(
    +-                        resolveIntent,
    +-                        PackageManager.GET_META_DATA);
    +-        assertNotNull(realResolveInfo);
    +-        assertEquals(1, realResolveInfo.size());
    +-
    +-        // We need to change AI, so set a clone.
    +-        realResolveInfo.set(0, DpmTestUtils.cloneParcelable(realResolveInfo.get(0)));
    +-
    +-        // We need to rewrite the UID in the activity info.
    +-        final ActivityInfo aci = realResolveInfo.get(0).activityInfo;
    +-        aci.applicationInfo = ai;
    +-        aci.packageName = admin.getPackageName();
    +-        aci.name = admin.getClassName();
    +-
    +-        // Note we don't set up queryBroadcastReceivers.  We don't use it in DPMS.
    +-
    +-        doReturn(aci).when(mMockContext.ipackageManager).getReceiverInfo(
    +-                eq(admin),
    +-                anyInt(),
    +-                eq(UserHandle.getUserId(packageUid)));
    +-
    +-        // Set up getPackageInfo().
    +-        markPackageAsInstalled(admin.getPackageName(), ai, UserHandle.getUserId(packageUid));
    +-    }
    +-}
    +diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DpmTestUtils.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DpmTestUtils.java
    +deleted file mode 100644
    +index cceb2d2..0000000
    +--- a/services/tests/servicestests/src/com/android/server/devicepolicy/DpmTestUtils.java
    ++++ /dev/null
    +@@ -1,166 +0,0 @@
    +-/*
    +- * Copyright (C) 2015 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 com.android.server.devicepolicy;
    +-
    +-import com.google.android.collect.Lists;
    +-import com.google.android.collect.Sets;
    +-
    +-import android.content.Context;
    +-import android.os.Bundle;
    +-import android.os.FileUtils;
    +-import android.os.Parcel;
    +-import android.os.Parcelable;
    +-import android.test.AndroidTestCase;
    +-import android.util.Log;
    +-import android.util.Printer;
    +-
    +-import org.junit.Assert;
    +-
    +-import java.io.BufferedReader;
    +-import java.io.File;
    +-import java.io.FileWriter;
    +-import java.io.IOException;
    +-import java.io.InputStreamReader;
    +-import java.io.PrintWriter;
    +-import java.util.ArrayList;
    +-import java.util.Collections;
    +-import java.util.List;
    +-import java.util.Objects;
    +-import java.util.Set;
    +-
    +-import junit.framework.AssertionFailedError;
    +-
    +-public class DpmTestUtils extends AndroidTestCase {
    +-    public static void clearDir(File dir) {
    +-        if (dir.exists()) {
    +-            Assert.assertTrue("failed to delete dir", FileUtils.deleteContents(dir));
    +-        }
    +-        dir.mkdirs();
    +-        Log.i(DpmTestBase.TAG, "Created " + dir);
    +-    }
    +-
    +-    public static int getListSizeAllowingNull(List<?> list) {
    +-        return list == null ? 0 : list.size();
    +-    }
    +-
    +-    public static Bundle newRestrictions(String... restrictions) {
    +-        final Bundle ret = new Bundle();
    +-        for (String restriction : restrictions) {
    +-            ret.putBoolean(restriction, true);
    +-        }
    +-        return ret;
    +-    }
    +-
    +-    public static void assertRestrictions(Bundle expected, Bundle actual) {
    +-        final ArrayList<String> elist;
    +-        if (expected == null) {
    +-            elist = null;
    +-        } else {
    +-            elist = Lists.newArrayList();
    +-            for (String key : expected.keySet()) {
    +-                if (expected.getBoolean(key)) {
    +-                    elist.add(key);
    +-                }
    +-            }
    +-            Collections.sort(elist);
    +-        }
    +-
    +-        final ArrayList<String> alist;
    +-        if (actual == null) {
    +-            alist = null;
    +-        } else {
    +-            alist = Lists.newArrayList();
    +-            for (String key : actual.keySet()) {
    +-                if (actual.getBoolean(key)) {
    +-                    alist.add(key);
    +-                }
    +-            }
    +-            Collections.sort(alist);
    +-        }
    +-
    +-        assertEquals(elist, alist);
    +-    }
    +-
    +-    public static <T extends Parcelable> T cloneParcelable(T source) {
    +-        Parcel p = Parcel.obtain();
    +-        p.writeParcelable(source, 0);
    +-        p.setDataPosition(0);
    +-        final T clone = p.readParcelable(DpmTestUtils.class.getClassLoader());
    +-        p.recycle();
    +-        return clone;
    +-    }
    +-
    +-    public static Printer LOG_PRINTER = new Printer() {
    +-        @Override
    +-        public void println(String x) {
    +-            Log.i(DpmTestBase.TAG, x);
    +-        }
    +-    };
    +-
    +-    public static String readAsset(Context context, String assetPath) throws IOException {
    +-        final StringBuilder sb = new StringBuilder();
    +-        try (BufferedReader br = new BufferedReader(
    +-                new InputStreamReader(
    +-                        context.getResources().getAssets().open(assetPath)))) {
    +-            String line;
    +-            while ((line = br.readLine()) != null) {
    +-                sb.append(line);
    +-                sb.append(System.lineSeparator());
    +-            }
    +-        }
    +-        return sb.toString();
    +-    }
    +-
    +-    public static void writeToFile(File path, String content)
    +-            throws IOException {
    +-        path.getParentFile().mkdirs();
    +-
    +-        try (FileWriter writer = new FileWriter(path)) {
    +-            Log.i(DpmTestBase.TAG, "Writing to " + path);
    +-            Log.i(DpmTestBase.TAG, content);
    +-            writer.write(content);
    +-        }
    +-    }
    +-
    +-    private static boolean checkAssertRestrictions(Bundle a, Bundle b) {
    +-        try {
    +-            assertRestrictions(a, b);
    +-            return true;
    +-        } catch (AssertionFailedError e) {
    +-            return false;
    +-        }
    +-    }
    +-
    +-    public void testAssertRestrictions() {
    +-        final Bundle a = newRestrictions();
    +-        final Bundle b = newRestrictions("a");
    +-        final Bundle c = newRestrictions("a");
    +-        final Bundle d = newRestrictions("b", "c");
    +-        final Bundle e = newRestrictions("b", "c");
    +-
    +-        assertTrue(checkAssertRestrictions(null, null));
    +-        assertFalse(checkAssertRestrictions(null, a));
    +-        assertFalse(checkAssertRestrictions(a, null));
    +-        assertTrue(checkAssertRestrictions(a, a));
    +-
    +-        assertFalse(checkAssertRestrictions(a, b));
    +-        assertTrue(checkAssertRestrictions(b, c));
    +-
    +-        assertFalse(checkAssertRestrictions(c, d));
    +-        assertTrue(checkAssertRestrictions(d, e));
    +-    }
    +-}
    +diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DummyDeviceAdmins.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DummyDeviceAdmins.java
    +deleted file mode 100644
    +index a0f4d97..0000000
    +--- a/services/tests/servicestests/src/com/android/server/devicepolicy/DummyDeviceAdmins.java
    ++++ /dev/null
    +@@ -1,29 +0,0 @@
    +-/*
    +- * Copyright (C) 2015 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 com.android.server.devicepolicy;
    +-
    +-import android.app.admin.DeviceAdminReceiver;
    +-
    +-public class DummyDeviceAdmins {
    +-    public static class Admin1 extends DeviceAdminReceiver {
    +-    }
    +-    public static class Admin2 extends DeviceAdminReceiver {
    +-    }
    +-    public static class Admin3 extends DeviceAdminReceiver {
    +-    }
    +-    public static class AdminNoPerm extends DeviceAdminReceiver {
    +-    }
    +-}
    +diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/MockUtils.java b/services/tests/servicestests/src/com/android/server/devicepolicy/MockUtils.java
    +deleted file mode 100644
    +index 58db192..0000000
    +--- a/services/tests/servicestests/src/com/android/server/devicepolicy/MockUtils.java
    ++++ /dev/null
    +@@ -1,117 +0,0 @@
    +-/*
    +- * Copyright (C) 2015 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 com.android.server.devicepolicy;
    +-
    +-import com.google.common.base.Objects;
    +-
    +-import com.android.internal.util.Preconditions;
    +-import com.android.server.pm.UserRestrictionsUtils;
    +-
    +-import android.content.ComponentName;
    +-import android.content.Intent;
    +-import android.os.Bundle;
    +-import android.os.UserHandle;
    +-
    +-import org.hamcrest.BaseMatcher;
    +-import org.hamcrest.Description;
    +-import org.hamcrest.Matcher;
    +-import org.mockito.Mockito;
    +-
    +-public class MockUtils {
    +-    private MockUtils() {
    +-    }
    +-
    +-    public static UserHandle checkUserHandle(final int userId) {
    +-        final Matcher<UserHandle> m = new BaseMatcher<UserHandle>() {
    +-            @Override
    +-            public boolean matches(Object item) {
    +-                if (item == null) return false;
    +-                return Objects.equal(((UserHandle) item).getIdentifier(), userId);
    +-            }
    +-
    +-            @Override
    +-            public void describeTo(Description description) {
    +-                description.appendText("UserHandle: user-id= \"" + userId + "\"");
    +-            }
    +-        };
    +-        return Mockito.argThat(m);
    +-    }
    +-
    +-    public static Intent checkIntentComponent(final ComponentName component) {
    +-        final Matcher<Intent> m = new BaseMatcher<Intent>() {
    +-            @Override
    +-            public boolean matches(Object item) {
    +-                if (item == null) return false;
    +-                return Objects.equal(((Intent) item).getComponent(), component);
    +-            }
    +-
    +-            @Override
    +-            public void describeTo(Description description) {
    +-                description.appendText("Intent: component=\"" + component + "\"");
    +-            }
    +-        };
    +-        return Mockito.argThat(m);
    +-    }
    +-
    +-    public static Intent checkIntentAction(final String action) {
    +-        final Matcher<Intent> m = new BaseMatcher<Intent>() {
    +-            @Override
    +-            public boolean matches(Object item) {
    +-                if (item == null) return false;
    +-                return Objects.equal(((Intent) item).getAction(), action);
    +-            }
    +-
    +-            @Override
    +-            public void describeTo(Description description) {
    +-                description.appendText("Intent: action=\"" + action + "\"");
    +-            }
    +-        };
    +-        return Mockito.argThat(m);
    +-    }
    +-
    +-    public static Bundle checkUserRestrictions(String... keys) {
    +-        final Bundle expected = DpmTestUtils.newRestrictions(Preconditions.checkNotNull(keys));
    +-        final Matcher<Bundle> m = new BaseMatcher<Bundle>() {
    +-            @Override
    +-            public boolean matches(Object item) {
    +-                if (item == null) return false;
    +-                return UserRestrictionsUtils.areEqual((Bundle) item, expected);
    +-            }
    +-
    +-            @Override
    +-            public void describeTo(Description description) {
    +-                description.appendText("User restrictions=" + getRestrictionsAsString(expected));
    +-            }
    +-        };
    +-        return Mockito.argThat(m);
    +-    }
    +-
    +-    private static String getRestrictionsAsString(Bundle b) {
    +-        final StringBuilder sb = new StringBuilder();
    +-        sb.append("[");
    +-
    +-        if (b != null) {
    +-            String sep = "";
    +-            for (String key : b.keySet()) {
    +-                sb.append(sep);
    +-                sep = ",";
    +-                sb.append(key);
    +-            }
    +-        }
    +-        sb.append("]");
    +-        return sb.toString();
    +-    }
    +-}
    +diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/OwnersTest.java b/services/tests/servicestests/src/com/android/server/devicepolicy/OwnersTest.java
    +deleted file mode 100644
    +index 423c4d5..0000000
    +--- a/services/tests/servicestests/src/com/android/server/devicepolicy/OwnersTest.java
    ++++ /dev/null
    +@@ -1,480 +0,0 @@
    +-/*
    +- * Copyright (C) 2014 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 com.android.server.devicepolicy;
    +-
    +-import com.android.server.devicepolicy.DevicePolicyManagerServiceTestable.OwnersTestable;
    +-
    +-import android.content.ComponentName;
    +-import android.os.UserHandle;
    +-
    +-/**
    +- * Tests for the DeviceOwner object that saves & loads device and policy owner information.
    +- * run this test with:
    +- m FrameworksServicesTests &&
    +- adb install \
    +-   -r out/target/product/hammerhead/data/app/FrameworksServicesTests/FrameworksServicesTests.apk &&
    +- adb shell am instrument -e class com.android.server.devicepolicy.OwnersTest \
    +-   -w com.android.frameworks.servicestests/android.support.test.runner.AndroidJUnitRunner
    +-
    +- (mmma frameworks/base/services/tests/servicestests/ for non-ninja build)
    +- */
    +-public class OwnersTest extends DpmTestBase {
    +-    public void testUpgrade01() throws Exception {
    +-        getContext().addUsers(10, 11, 20, 21);
    +-
    +-        // First, migrate.
    +-        {
    +-            final OwnersTestable owners = new OwnersTestable(getContext());
    +-
    +-            DpmTestUtils.writeToFile(owners.getLegacyConfigFileWithTestOverride(),
    +-                    DpmTestUtils.readAsset(mRealTestContext, "OwnersTest/test01/input.xml"));
    +-
    +-            owners.load();
    +-
    +-            // The legacy file should be removed.
    +-            assertFalse(owners.getLegacyConfigFileWithTestOverride().exists());
    +-
    +-            // File was empty, so no new files should be created.
    +-            assertFalse(owners.getDeviceOwnerFileWithTestOverride().exists());
    +-
    +-            assertFalse(owners.getProfileOwnerFileWithTestOverride(10).exists());
    +-            assertFalse(owners.getProfileOwnerFileWithTestOverride(11).exists());
    +-            assertFalse(owners.getProfileOwnerFileWithTestOverride(20).exists());
    +-            assertFalse(owners.getProfileOwnerFileWithTestOverride(21).exists());
    +-
    +-            assertFalse(owners.hasDeviceOwner());
    +-            assertEquals(UserHandle.USER_NULL, owners.getDeviceOwnerUserId());
    +-            assertNull(owners.getSystemUpdatePolicy());
    +-            assertEquals(0, owners.getProfileOwnerKeys().size());
    +-
    +-            assertFalse(owners.getDeviceOwnerUserRestrictionsNeedsMigration());
    +-            assertFalse(owners.getProfileOwnerUserRestrictionsNeedsMigration(10));
    +-            assertFalse(owners.getProfileOwnerUserRestrictionsNeedsMigration(11));
    +-            assertFalse(owners.getProfileOwnerUserRestrictionsNeedsMigration(20));
    +-            assertFalse(owners.getProfileOwnerUserRestrictionsNeedsMigration(21));
    +-        }
    +-
    +-        // Then re-read and check.
    +-        {
    +-            final OwnersTestable owners = new OwnersTestable(getContext());
    +-            owners.load();
    +-
    +-            assertFalse(owners.hasDeviceOwner());
    +-            assertEquals(UserHandle.USER_NULL, owners.getDeviceOwnerUserId());
    +-            assertNull(owners.getSystemUpdatePolicy());
    +-            assertEquals(0, owners.getProfileOwnerKeys().size());
    +-
    +-            assertFalse(owners.getDeviceOwnerUserRestrictionsNeedsMigration());
    +-            assertFalse(owners.getProfileOwnerUserRestrictionsNeedsMigration(10));
    +-            assertFalse(owners.getProfileOwnerUserRestrictionsNeedsMigration(11));
    +-            assertFalse(owners.getProfileOwnerUserRestrictionsNeedsMigration(20));
    +-            assertFalse(owners.getProfileOwnerUserRestrictionsNeedsMigration(21));
    +-        }
    +-    }
    +-
    +-    public void testUpgrade02() throws Exception {
    +-        getContext().addUsers(10, 11, 20, 21);
    +-
    +-        // First, migrate.
    +-        {
    +-            final OwnersTestable owners = new OwnersTestable(getContext());
    +-
    +-            DpmTestUtils.writeToFile(owners.getLegacyConfigFileWithTestOverride(),
    +-                    DpmTestUtils.readAsset(mRealTestContext, "OwnersTest/test02/input.xml"));
    +-
    +-            owners.load();
    +-
    +-            // The legacy file should be removed.
    +-            assertFalse(owners.getLegacyConfigFileWithTestOverride().exists());
    +-
    +-            assertTrue(owners.getDeviceOwnerFileWithTestOverride().exists()); // TODO Check content
    +-
    +-            assertFalse(owners.getProfileOwnerFileWithTestOverride(10).exists());
    +-            assertFalse(owners.getProfileOwnerFileWithTestOverride(11).exists());
    +-            assertFalse(owners.getProfileOwnerFileWithTestOverride(20).exists());
    +-            assertFalse(owners.getProfileOwnerFileWithTestOverride(21).exists());
    +-
    +-            assertTrue(owners.hasDeviceOwner());
    +-            assertEquals(null, owners.getDeviceOwnerName());
    +-            assertEquals("com.google.android.testdpc", owners.getDeviceOwnerPackageName());
    +-            assertEquals(UserHandle.USER_SYSTEM, owners.getDeviceOwnerUserId());
    +-
    +-            assertNull(owners.getSystemUpdatePolicy());
    +-            assertEquals(0, owners.getProfileOwnerKeys().size());
    +-
    +-            assertTrue(owners.getDeviceOwnerUserRestrictionsNeedsMigration());
    +-            assertFalse(owners.getProfileOwnerUserRestrictionsNeedsMigration(10));
    +-            assertFalse(owners.getProfileOwnerUserRestrictionsNeedsMigration(11));
    +-            assertFalse(owners.getProfileOwnerUserRestrictionsNeedsMigration(20));
    +-            assertFalse(owners.getProfileOwnerUserRestrictionsNeedsMigration(21));
    +-        }
    +-
    +-        // Then re-read and check.
    +-        {
    +-            final OwnersTestable owners = new OwnersTestable(getContext());
    +-            owners.load();
    +-
    +-            assertTrue(owners.hasDeviceOwner());
    +-            assertEquals(null, owners.getDeviceOwnerName());
    +-            assertEquals("com.google.android.testdpc", owners.getDeviceOwnerPackageName());
    +-            assertEquals(UserHandle.USER_SYSTEM, owners.getDeviceOwnerUserId());
    +-
    +-            assertNull(owners.getSystemUpdatePolicy());
    +-            assertEquals(0, owners.getProfileOwnerKeys().size());
    +-
    +-            assertTrue(owners.getDeviceOwnerUserRestrictionsNeedsMigration());
    +-            assertFalse(owners.getProfileOwnerUserRestrictionsNeedsMigration(10));
    +-            assertFalse(owners.getProfileOwnerUserRestrictionsNeedsMigration(11));
    +-            assertFalse(owners.getProfileOwnerUserRestrictionsNeedsMigration(20));
    +-            assertFalse(owners.getProfileOwnerUserRestrictionsNeedsMigration(21));
    +-        }
    +-    }
    +-
    +-    public void testUpgrade03() throws Exception {
    +-        getContext().addUsers(10, 11, 20, 21);
    +-
    +-        // First, migrate.
    +-        {
    +-            final OwnersTestable owners = new OwnersTestable(getContext());
    +-
    +-            DpmTestUtils.writeToFile(owners.getLegacyConfigFileWithTestOverride(),
    +-                    DpmTestUtils.readAsset(mRealTestContext, "OwnersTest/test03/input.xml"));
    +-
    +-            owners.load();
    +-
    +-            // The legacy file should be removed.
    +-            assertFalse(owners.getLegacyConfigFileWithTestOverride().exists());
    +-
    +-            assertFalse(owners.getDeviceOwnerFileWithTestOverride().exists());
    +-
    +-            assertTrue(owners.getProfileOwnerFileWithTestOverride(10).exists());
    +-            assertTrue(owners.getProfileOwnerFileWithTestOverride(11).exists());
    +-            assertFalse(owners.getProfileOwnerFileWithTestOverride(20).exists());
    +-            assertFalse(owners.getProfileOwnerFileWithTestOverride(21).exists());
    +-
    +-            assertFalse(owners.hasDeviceOwner());
    +-            assertEquals(UserHandle.USER_NULL, owners.getDeviceOwnerUserId());
    +-            assertNull(owners.getSystemUpdatePolicy());
    +-
    +-            assertEquals(2, owners.getProfileOwnerKeys().size());
    +-            assertEquals(new ComponentName("com.google.android.testdpc",
    +-                            "com.google.android.testdpc.DeviceAdminReceiver0"),
    +-                    owners.getProfileOwnerComponent(10));
    +-            assertEquals("0", owners.getProfileOwnerName(10));
    +-            assertEquals("com.google.android.testdpc", owners.getProfileOwnerPackage(10));
    +-
    +-            assertEquals(new ComponentName("com.google.android.testdpc1", ""),
    +-                    owners.getProfileOwnerComponent(11));
    +-            assertEquals("1", owners.getProfileOwnerName(11));
    +-            assertEquals("com.google.android.testdpc1", owners.getProfileOwnerPackage(11));
    +-
    +-            assertFalse(owners.getDeviceOwnerUserRestrictionsNeedsMigration());
    +-            assertTrue(owners.getProfileOwnerUserRestrictionsNeedsMigration(10));
    +-            assertTrue(owners.getProfileOwnerUserRestrictionsNeedsMigration(11));
    +-            assertFalse(owners.getProfileOwnerUserRestrictionsNeedsMigration(20));
    +-            assertFalse(owners.getProfileOwnerUserRestrictionsNeedsMigration(21));
    +-        }
    +-
    +-        // Then re-read and check.
    +-        {
    +-            final OwnersTestable owners = new OwnersTestable(getContext());
    +-            owners.load();
    +-
    +-            assertFalse(owners.hasDeviceOwner());
    +-            assertEquals(UserHandle.USER_NULL, owners.getDeviceOwnerUserId());
    +-            assertNull(owners.getSystemUpdatePolicy());
    +-
    +-            assertEquals(2, owners.getProfileOwnerKeys().size());
    +-            assertEquals(new ComponentName("com.google.android.testdpc",
    +-                            "com.google.android.testdpc.DeviceAdminReceiver0"),
    +-                    owners.getProfileOwnerComponent(10));
    +-            assertEquals("0", owners.getProfileOwnerName(10));
    +-            assertEquals("com.google.android.testdpc", owners.getProfileOwnerPackage(10));
    +-
    +-            assertEquals(new ComponentName("com.google.android.testdpc1", ""),
    +-                    owners.getProfileOwnerComponent(11));
    +-            assertEquals("1", owners.getProfileOwnerName(11));
    +-            assertEquals("com.google.android.testdpc1", owners.getProfileOwnerPackage(11));
    +-
    +-            assertFalse(owners.getDeviceOwnerUserRestrictionsNeedsMigration());
    +-            assertTrue(owners.getProfileOwnerUserRestrictionsNeedsMigration(10));
    +-            assertTrue(owners.getProfileOwnerUserRestrictionsNeedsMigration(11));
    +-            assertFalse(owners.getProfileOwnerUserRestrictionsNeedsMigration(20));
    +-            assertFalse(owners.getProfileOwnerUserRestrictionsNeedsMigration(21));
    +-        }
    +-    }
    +-
    +-    /**
    +-     * Note this also tests {@link Owners#setDeviceOwnerUserRestrictionsMigrated()}
    +-     * and {@link  Owners#setProfileOwnerUserRestrictionsMigrated(int)}.
    +-     */
    +-    public void testUpgrade04() throws Exception {
    +-        getContext().addUsers(10, 11, 20, 21);
    +-
    +-        // First, migrate.
    +-        {
    +-            final OwnersTestable owners = new OwnersTestable(getContext());
    +-
    +-            DpmTestUtils.writeToFile(owners.getLegacyConfigFileWithTestOverride(),
    +-                    DpmTestUtils.readAsset(mRealTestContext, "OwnersTest/test04/input.xml"));
    +-
    +-            owners.load();
    +-
    +-            // The legacy file should be removed.
    +-            assertFalse(owners.getLegacyConfigFileWithTestOverride().exists());
    +-
    +-            assertTrue(owners.getDeviceOwnerFileWithTestOverride().exists());
    +-
    +-            assertTrue(owners.getProfileOwnerFileWithTestOverride(10).exists());
    +-            assertTrue(owners.getProfileOwnerFileWithTestOverride(11).exists());
    +-            assertFalse(owners.getProfileOwnerFileWithTestOverride(20).exists());
    +-            assertFalse(owners.getProfileOwnerFileWithTestOverride(21).exists());
    +-
    +-            assertTrue(owners.hasDeviceOwner());
    +-            assertEquals(null, owners.getDeviceOwnerName());
    +-            assertEquals("com.google.android.testdpc", owners.getDeviceOwnerPackageName());
    +-            assertEquals(UserHandle.USER_SYSTEM, owners.getDeviceOwnerUserId());
    +-
    +-            assertNotNull(owners.getSystemUpdatePolicy());
    +-            assertEquals(5, owners.getSystemUpdatePolicy().getPolicyType());
    +-
    +-            assertEquals(2, owners.getProfileOwnerKeys().size());
    +-            assertEquals(new ComponentName("com.google.android.testdpc",
    +-                            "com.google.android.testdpc.DeviceAdminReceiver0"),
    +-                    owners.getProfileOwnerComponent(10));
    +-            assertEquals("0", owners.getProfileOwnerName(10));
    +-            assertEquals("com.google.android.testdpc", owners.getProfileOwnerPackage(10));
    +-
    +-            assertEquals(new ComponentName("com.google.android.testdpc1", ""),
    +-                    owners.getProfileOwnerComponent(11));
    +-            assertEquals("1", owners.getProfileOwnerName(11));
    +-            assertEquals("com.google.android.testdpc1", owners.getProfileOwnerPackage(11));
    +-
    +-            assertTrue(owners.getDeviceOwnerUserRestrictionsNeedsMigration());
    +-            assertTrue(owners.getProfileOwnerUserRestrictionsNeedsMigration(10));
    +-            assertTrue(owners.getProfileOwnerUserRestrictionsNeedsMigration(11));
    +-            assertFalse(owners.getProfileOwnerUserRestrictionsNeedsMigration(20));
    +-            assertFalse(owners.getProfileOwnerUserRestrictionsNeedsMigration(21));
    +-        }
    +-
    +-        // Then re-read and check.
    +-        {
    +-            final OwnersTestable owners = new OwnersTestable(getContext());
    +-            owners.load();
    +-
    +-            assertTrue(owners.hasDeviceOwner());
    +-            assertEquals(null, owners.getDeviceOwnerName());
    +-            assertEquals("com.google.android.testdpc", owners.getDeviceOwnerPackageName());
    +-            assertEquals(UserHandle.USER_SYSTEM, owners.getDeviceOwnerUserId());
    +-
    +-            assertNotNull(owners.getSystemUpdatePolicy());
    +-            assertEquals(5, owners.getSystemUpdatePolicy().getPolicyType());
    +-
    +-            assertEquals(2, owners.getProfileOwnerKeys().size());
    +-            assertEquals(new ComponentName("com.google.android.testdpc",
    +-                            "com.google.android.testdpc.DeviceAdminReceiver0"),
    +-                    owners.getProfileOwnerComponent(10));
    +-            assertEquals("0", owners.getProfileOwnerName(10));
    +-            assertEquals("com.google.android.testdpc", owners.getProfileOwnerPackage(10));
    +-
    +-            assertEquals(new ComponentName("com.google.android.testdpc1", ""),
    +-                    owners.getProfileOwnerComponent(11));
    +-            assertEquals("1", owners.getProfileOwnerName(11));
    +-            assertEquals("com.google.android.testdpc1", owners.getProfileOwnerPackage(11));
    +-
    +-            assertTrue(owners.getDeviceOwnerUserRestrictionsNeedsMigration());
    +-            assertTrue(owners.getProfileOwnerUserRestrictionsNeedsMigration(10));
    +-            assertTrue(owners.getProfileOwnerUserRestrictionsNeedsMigration(11));
    +-            assertFalse(owners.getProfileOwnerUserRestrictionsNeedsMigration(20));
    +-            assertFalse(owners.getProfileOwnerUserRestrictionsNeedsMigration(21));
    +-
    +-            owners.setDeviceOwnerUserRestrictionsMigrated();
    +-        }
    +-
    +-        {
    +-            final OwnersTestable owners = new OwnersTestable(getContext());
    +-            owners.load();
    +-
    +-            assertFalse(owners.getDeviceOwnerUserRestrictionsNeedsMigration());
    +-            assertTrue(owners.getProfileOwnerUserRestrictionsNeedsMigration(10));
    +-            assertTrue(owners.getProfileOwnerUserRestrictionsNeedsMigration(11));
    +-            assertFalse(owners.getProfileOwnerUserRestrictionsNeedsMigration(20));
    +-            assertFalse(owners.getProfileOwnerUserRestrictionsNeedsMigration(21));
    +-
    +-            owners.setProfileOwnerUserRestrictionsMigrated(11);
    +-        }
    +-
    +-        {
    +-            final OwnersTestable owners = new OwnersTestable(getContext());
    +-            owners.load();
    +-
    +-            assertFalse(owners.getDeviceOwnerUserRestrictionsNeedsMigration());
    +-            assertTrue(owners.getProfileOwnerUserRestrictionsNeedsMigration(10));
    +-            assertFalse(owners.getProfileOwnerUserRestrictionsNeedsMigration(11));
    +-            assertFalse(owners.getProfileOwnerUserRestrictionsNeedsMigration(20));
    +-            assertFalse(owners.getProfileOwnerUserRestrictionsNeedsMigration(21));
    +-
    +-            owners.setProfileOwnerUserRestrictionsMigrated(11);
    +-        }
    +-    }
    +-
    +-    public void testUpgrade05() throws Exception {
    +-        getContext().addUsers(10, 11, 20, 21);
    +-
    +-        // First, migrate.
    +-        {
    +-            final OwnersTestable owners = new OwnersTestable(getContext());
    +-
    +-            DpmTestUtils.writeToFile(owners.getLegacyConfigFileWithTestOverride(),
    +-                    DpmTestUtils.readAsset(mRealTestContext, "OwnersTest/test05/input.xml"));
    +-
    +-            owners.load();
    +-
    +-            // The legacy file should be removed.
    +-            assertFalse(owners.getLegacyConfigFileWithTestOverride().exists());
    +-
    +-            // Note device initializer is no longer supported.  No need to write the DO file.
    +-            assertFalse(owners.getDeviceOwnerFileWithTestOverride().exists());
    +-
    +-            assertFalse(owners.getProfileOwnerFileWithTestOverride(10).exists());
    +-            assertFalse(owners.getProfileOwnerFileWithTestOverride(11).exists());
    +-            assertFalse(owners.getProfileOwnerFileWithTestOverride(20).exists());
    +-
    +-            assertFalse(owners.hasDeviceOwner());
    +-            assertEquals(UserHandle.USER_NULL, owners.getDeviceOwnerUserId());
    +-
    +-
    +-            assertNull(owners.getSystemUpdatePolicy());
    +-            assertEquals(0, owners.getProfileOwnerKeys().size());
    +-
    +-            assertFalse(owners.getDeviceOwnerUserRestrictionsNeedsMigration());
    +-            assertFalse(owners.getProfileOwnerUserRestrictionsNeedsMigration(10));
    +-            assertFalse(owners.getProfileOwnerUserRestrictionsNeedsMigration(11));
    +-            assertFalse(owners.getProfileOwnerUserRestrictionsNeedsMigration(20));
    +-            assertFalse(owners.getProfileOwnerUserRestrictionsNeedsMigration(21));
    +-        }
    +-
    +-        // Then re-read and check.
    +-        {
    +-            final OwnersTestable owners = new OwnersTestable(getContext());
    +-            owners.load();
    +-
    +-            assertFalse(owners.hasDeviceOwner());
    +-            assertEquals(UserHandle.USER_NULL, owners.getDeviceOwnerUserId());
    +-
    +-
    +-            assertNull(owners.getSystemUpdatePolicy());
    +-            assertEquals(0, owners.getProfileOwnerKeys().size());
    +-
    +-            assertFalse(owners.getDeviceOwnerUserRestrictionsNeedsMigration());
    +-            assertFalse(owners.getProfileOwnerUserRestrictionsNeedsMigration(10));
    +-            assertFalse(owners.getProfileOwnerUserRestrictionsNeedsMigration(11));
    +-            assertFalse(owners.getProfileOwnerUserRestrictionsNeedsMigration(20));
    +-            assertFalse(owners.getProfileOwnerUserRestrictionsNeedsMigration(21));
    +-        }
    +-    }
    +-
    +-    public void testUpgrade06() throws Exception {
    +-        getContext().addUsers(10, 11, 20, 21);
    +-
    +-        // First, migrate.
    +-        {
    +-            final OwnersTestable owners = new OwnersTestable(getContext());
    +-
    +-            DpmTestUtils.writeToFile(owners.getLegacyConfigFileWithTestOverride(),
    +-                    DpmTestUtils.readAsset(mRealTestContext, "OwnersTest/test06/input.xml"));
    +-
    +-            owners.load();
    +-
    +-            // The legacy file should be removed.
    +-            assertFalse(owners.getLegacyConfigFileWithTestOverride().exists());
    +-
    +-            assertTrue(owners.getDeviceOwnerFileWithTestOverride().exists());
    +-
    +-            assertFalse(owners.getProfileOwnerFileWithTestOverride(10).exists());
    +-            assertFalse(owners.getProfileOwnerFileWithTestOverride(11).exists());
    +-            assertFalse(owners.getProfileOwnerFileWithTestOverride(20).exists());
    +-
    +-            assertFalse(owners.hasDeviceOwner());
    +-            assertEquals(UserHandle.USER_NULL, owners.getDeviceOwnerUserId());
    +-            assertEquals(0, owners.getProfileOwnerKeys().size());
    +-
    +-            assertNotNull(owners.getSystemUpdatePolicy());
    +-            assertEquals(5, owners.getSystemUpdatePolicy().getPolicyType());
    +-
    +-            assertFalse(owners.getDeviceOwnerUserRestrictionsNeedsMigration());
    +-            assertFalse(owners.getProfileOwnerUserRestrictionsNeedsMigration(10));
    +-            assertFalse(owners.getProfileOwnerUserRestrictionsNeedsMigration(11));
    +-            assertFalse(owners.getProfileOwnerUserRestrictionsNeedsMigration(20));
    +-            assertFalse(owners.getProfileOwnerUserRestrictionsNeedsMigration(21));
    +-        }
    +-
    +-        // Then re-read and check.
    +-        {
    +-            final OwnersTestable owners = new OwnersTestable(getContext());
    +-            owners.load();
    +-
    +-            assertFalse(owners.hasDeviceOwner());
    +-            assertEquals(UserHandle.USER_NULL, owners.getDeviceOwnerUserId());
    +-            assertEquals(0, owners.getProfileOwnerKeys().size());
    +-
    +-            assertNotNull(owners.getSystemUpdatePolicy());
    +-            assertEquals(5, owners.getSystemUpdatePolicy().getPolicyType());
    +-
    +-            assertFalse(owners.getDeviceOwnerUserRestrictionsNeedsMigration());
    +-            assertFalse(owners.getProfileOwnerUserRestrictionsNeedsMigration(10));
    +-            assertFalse(owners.getProfileOwnerUserRestrictionsNeedsMigration(11));
    +-            assertFalse(owners.getProfileOwnerUserRestrictionsNeedsMigration(20));
    +-            assertFalse(owners.getProfileOwnerUserRestrictionsNeedsMigration(21));
    +-        }
    +-    }
    +-
    +-    public void testRemoveExistingFiles() throws Exception {
    +-        getContext().addUsers(10, 11, 20, 21);
    +-
    +-        final OwnersTestable owners = new OwnersTestable(getContext());
    +-
    +-        // First, migrate to create new-style config files.
    +-        DpmTestUtils.writeToFile(owners.getLegacyConfigFileWithTestOverride(),
    +-                DpmTestUtils.readAsset(mRealTestContext, "OwnersTest/test04/input.xml"));
    +-
    +-        owners.load();
    +-
    +-        assertFalse(owners.getLegacyConfigFileWithTestOverride().exists());
    +-
    +-        assertTrue(owners.getDeviceOwnerFileWithTestOverride().exists());
    +-        assertTrue(owners.getProfileOwnerFileWithTestOverride(10).exists());
    +-        assertTrue(owners.getProfileOwnerFileWithTestOverride(11).exists());
    +-
    +-        // Then clear all information and save.
    +-        owners.clearDeviceOwner();
    +-        owners.clearSystemUpdatePolicy();
    +-        owners.removeProfileOwner(10);
    +-        owners.removeProfileOwner(11);
    +-
    +-        owners.writeDeviceOwner();
    +-        owners.writeProfileOwner(10);
    +-        owners.writeProfileOwner(11);
    +-        owners.writeProfileOwner(20);
    +-        owners.writeProfileOwner(21);
    +-
    +-        // Now all files should be removed.
    +-        assertFalse(owners.getDeviceOwnerFileWithTestOverride().exists());
    +-        assertFalse(owners.getProfileOwnerFileWithTestOverride(10).exists());
    +-        assertFalse(owners.getProfileOwnerFileWithTestOverride(11).exists());
    +-    }
    +-}
    +diff --git a/services/tests/servicestests/src/com/android/server/job/JobStoreTest.java b/services/tests/servicestests/src/com/android/server/job/JobStoreTest.java
    +deleted file mode 100644
    +index edbff83..0000000
    +--- a/services/tests/servicestests/src/com/android/server/job/JobStoreTest.java
    ++++ /dev/null
    +@@ -1,312 +0,0 @@
    +-package com.android.server.job;
    +-
    +-
    +-import android.content.ComponentName;
    +-import android.content.Context;
    +-import android.app.job.JobInfo;
    +-import android.app.job.JobInfo.Builder;
    +-import android.os.PersistableBundle;
    +-import android.os.SystemClock;
    +-import android.test.AndroidTestCase;
    +-import android.test.RenamingDelegatingContext;
    +-import android.util.Log;
    +-import android.util.ArraySet;
    +-
    +-import com.android.server.job.JobStore.JobSet;
    +-import com.android.server.job.controllers.JobStatus;
    +-
    +-import java.util.Iterator;
    +-
    +-/**
    +- * Test reading and writing correctly from file.
    +- */
    +-public class JobStoreTest extends AndroidTestCase {
    +-    private static final String TAG = "TaskStoreTest";
    +-    private static final String TEST_PREFIX = "_test_";
    +-
    +-    private static final int SOME_UID = 34234;
    +-    private ComponentName mComponent;
    +-    private static final long IO_WAIT = 1000L;
    +-
    +-    JobStore mTaskStoreUnderTest;
    +-    Context mTestContext;
    +-
    +-    @Override
    +-    public void setUp() throws Exception {
    +-        mTestContext = new RenamingDelegatingContext(getContext(), TEST_PREFIX);
    +-        Log.d(TAG, "Saving tasks to '" + mTestContext.getFilesDir() + "'");
    +-        mTaskStoreUnderTest =
    +-                JobStore.initAndGetForTesting(mTestContext, mTestContext.getFilesDir());
    +-        mComponent = new ComponentName(getContext().getPackageName(), StubClass.class.getName());
    +-    }
    +-
    +-    @Override
    +-    public void tearDown() throws Exception {
    +-        mTaskStoreUnderTest.clear();
    +-    }
    +-
    +-    public void testMaybeWriteStatusToDisk() throws Exception {
    +-        int taskId = 5;
    +-        long runByMillis = 20000L; // 20s
    +-        long runFromMillis = 2000L; // 2s
    +-        long initialBackoff = 10000L; // 10s
    +-
    +-        final JobInfo task = new Builder(taskId, mComponent)
    +-                .setRequiresCharging(true)
    +-                .setRequiredNetworkType(JobInfo.NETWORK_TYPE_ANY)
    +-                .setBackoffCriteria(initialBackoff, JobInfo.BACKOFF_POLICY_EXPONENTIAL)
    +-                .setOverrideDeadline(runByMillis)
    +-                .setMinimumLatency(runFromMillis)
    +-                .setPersisted(true)
    +-                .build();
    +-        final JobStatus ts = JobStatus.createFromJobInfo(task, SOME_UID, null, -1, null);
    +-        mTaskStoreUnderTest.add(ts);
    +-        Thread.sleep(IO_WAIT);
    +-        // Manually load tasks from xml file.
    +-        final JobSet jobStatusSet = new JobSet();
    +-        mTaskStoreUnderTest.readJobMapFromDisk(jobStatusSet);
    +-
    +-        assertEquals("Didn't get expected number of persisted tasks.", 1, jobStatusSet.size());
    +-        final JobStatus loadedTaskStatus = jobStatusSet.getAllJobs().get(0);
    +-        assertTasksEqual(task, loadedTaskStatus.getJob());
    +-        assertTrue("JobStore#contains invalid.", mTaskStoreUnderTest.containsJob(ts));
    +-        assertEquals("Different uids.", SOME_UID, loadedTaskStatus.getUid());
    +-        compareTimestampsSubjectToIoLatency("Early run-times not the same after read.",
    +-                ts.getEarliestRunTime(), loadedTaskStatus.getEarliestRunTime());
    +-        compareTimestampsSubjectToIoLatency("Late run-times not the same after read.",
    +-                ts.getLatestRunTimeElapsed(), loadedTaskStatus.getLatestRunTimeElapsed());
    +-
    +-    }
    +-
    +-    public void testWritingTwoFilesToDisk() throws Exception {
    +-        final JobInfo task1 = new Builder(8, mComponent)
    +-                .setRequiresDeviceIdle(true)
    +-                .setPeriodic(10000L)
    +-                .setRequiresCharging(true)
    +-                .setPersisted(true)
    +-                .build();
    +-        final JobInfo task2 = new Builder(12, mComponent)
    +-                .setMinimumLatency(5000L)
    +-                .setBackoffCriteria(15000L, JobInfo.BACKOFF_POLICY_LINEAR)
    +-                .setOverrideDeadline(30000L)
    +-                .setRequiredNetworkType(JobInfo.NETWORK_TYPE_UNMETERED)
    +-                .setPersisted(true)
    +-                .build();
    +-        final JobStatus taskStatus1 = JobStatus.createFromJobInfo(task1, SOME_UID, null, -1, null);
    +-        final JobStatus taskStatus2 = JobStatus.createFromJobInfo(task2, SOME_UID, null, -1, null);
    +-        mTaskStoreUnderTest.add(taskStatus1);
    +-        mTaskStoreUnderTest.add(taskStatus2);
    +-        Thread.sleep(IO_WAIT);
    +-
    +-        final JobSet jobStatusSet = new JobSet();
    +-        mTaskStoreUnderTest.readJobMapFromDisk(jobStatusSet);
    +-        assertEquals("Incorrect # of persisted tasks.", 2, jobStatusSet.size());
    +-        Iterator<JobStatus> it = jobStatusSet.getAllJobs().iterator();
    +-        JobStatus loaded1 = it.next();
    +-        JobStatus loaded2 = it.next();
    +-
    +-        // Reverse them so we know which comparison to make.
    +-        if (loaded1.getJobId() != 8) {
    +-            JobStatus tmp = loaded1;
    +-            loaded1 = loaded2;
    +-            loaded2 = tmp;
    +-        }
    +-
    +-        assertTasksEqual(task1, loaded1.getJob());
    +-        assertTasksEqual(task2, loaded2.getJob());
    +-        assertTrue("JobStore#contains invalid.", mTaskStoreUnderTest.containsJob(taskStatus1));
    +-        assertTrue("JobStore#contains invalid.", mTaskStoreUnderTest.containsJob(taskStatus2));
    +-        // Check that the loaded task has the correct runtimes.
    +-        compareTimestampsSubjectToIoLatency("Early run-times not the same after read.",
    +-                taskStatus1.getEarliestRunTime(), loaded1.getEarliestRunTime());
    +-        compareTimestampsSubjectToIoLatency("Late run-times not the same after read.",
    +-                taskStatus1.getLatestRunTimeElapsed(), loaded1.getLatestRunTimeElapsed());
    +-        compareTimestampsSubjectToIoLatency("Early run-times not the same after read.",
    +-                taskStatus2.getEarliestRunTime(), loaded2.getEarliestRunTime());
    +-        compareTimestampsSubjectToIoLatency("Late run-times not the same after read.",
    +-                taskStatus2.getLatestRunTimeElapsed(), loaded2.getLatestRunTimeElapsed());
    +-
    +-    }
    +-
    +-    public void testWritingTaskWithExtras() throws Exception {
    +-        JobInfo.Builder b = new Builder(8, mComponent)
    +-                .setRequiresDeviceIdle(true)
    +-                .setPeriodic(10000L)
    +-                .setRequiresCharging(true)
    +-                .setPersisted(true);
    +-
    +-        PersistableBundle extras = new PersistableBundle();
    +-        extras.putDouble("hello", 3.2);
    +-        extras.putString("hi", "there");
    +-        extras.putInt("into", 3);
    +-        b.setExtras(extras);
    +-        final JobInfo task = b.build();
    +-        JobStatus taskStatus = JobStatus.createFromJobInfo(task, SOME_UID, null, -1, null);
    +-
    +-        mTaskStoreUnderTest.add(taskStatus);
    +-        Thread.sleep(IO_WAIT);
    +-
    +-        final JobSet jobStatusSet = new JobSet();
    +-        mTaskStoreUnderTest.readJobMapFromDisk(jobStatusSet);
    +-        assertEquals("Incorrect # of persisted tasks.", 1, jobStatusSet.size());
    +-        JobStatus loaded = jobStatusSet.getAllJobs().iterator().next();
    +-        assertTasksEqual(task, loaded.getJob());
    +-    }
    +-    public void testWritingTaskWithSourcePackage() throws Exception {
    +-        JobInfo.Builder b = new Builder(8, mComponent)
    +-                .setRequiresDeviceIdle(true)
    +-                .setPeriodic(10000L)
    +-                .setRequiresCharging(true)
    +-                .setPersisted(true);
    +-        JobStatus taskStatus = JobStatus.createFromJobInfo(b.build(), SOME_UID,
    +-                "com.google.android.gms", 0, null);
    +-
    +-        mTaskStoreUnderTest.add(taskStatus);
    +-        Thread.sleep(IO_WAIT);
    +-
    +-        final JobSet jobStatusSet = new JobSet();
    +-        mTaskStoreUnderTest.readJobMapFromDisk(jobStatusSet);
    +-        assertEquals("Incorrect # of persisted tasks.", 1, jobStatusSet.size());
    +-        JobStatus loaded = jobStatusSet.getAllJobs().iterator().next();
    +-        assertEquals("Source package not equal.", loaded.getSourcePackageName(),
    +-                taskStatus.getSourcePackageName());
    +-        assertEquals("Source user not equal.", loaded.getSourceUserId(),
    +-                taskStatus.getSourceUserId());
    +-    }
    +-
    +-    public void testWritingTaskWithFlex() throws Exception {
    +-        JobInfo.Builder b = new Builder(8, mComponent)
    +-                .setRequiresDeviceIdle(true)
    +-                .setPeriodic(5*60*60*1000, 1*60*60*1000)
    +-                .setRequiresCharging(true)
    +-                .setPersisted(true);
    +-        JobStatus taskStatus = JobStatus.createFromJobInfo(b.build(), SOME_UID, null, -1, null);
    +-
    +-        mTaskStoreUnderTest.add(taskStatus);
    +-        Thread.sleep(IO_WAIT);
    +-
    +-        final JobSet jobStatusSet = new JobSet();
    +-        mTaskStoreUnderTest.readJobMapFromDisk(jobStatusSet);
    +-        assertEquals("Incorrect # of persisted tasks.", 1, jobStatusSet.size());
    +-        JobStatus loaded = jobStatusSet.getAllJobs().iterator().next();
    +-        assertEquals("Period not equal.", loaded.getJob().getIntervalMillis(),
    +-                taskStatus.getJob().getIntervalMillis());
    +-        assertEquals("Flex not equal.", loaded.getJob().getFlexMillis(),
    +-                taskStatus.getJob().getFlexMillis());
    +-    }
    +-
    +-    public void testMassivePeriodClampedOnRead() throws Exception {
    +-        final long ONE_HOUR = 60*60*1000L; // flex
    +-        final long TWO_HOURS = 2 * ONE_HOUR; // period
    +-        JobInfo.Builder b = new Builder(8, mComponent)
    +-                .setPeriodic(TWO_HOURS, ONE_HOUR)
    +-                .setPersisted(true);
    +-        final long invalidLateRuntimeElapsedMillis =
    +-                SystemClock.elapsedRealtime() + (TWO_HOURS * ONE_HOUR) + TWO_HOURS;  // > period+flex
    +-        final long invalidEarlyRuntimeElapsedMillis =
    +-                invalidLateRuntimeElapsedMillis - TWO_HOURS;  // Early is (late - period).
    +-        final JobStatus js = new JobStatus(b.build(), SOME_UID, "somePackage",
    +-                0 /* sourceUserId */, "someTag",
    +-                invalidEarlyRuntimeElapsedMillis, invalidLateRuntimeElapsedMillis);
    +-
    +-        mTaskStoreUnderTest.add(js);
    +-        Thread.sleep(IO_WAIT);
    +-
    +-        final JobSet jobStatusSet = new JobSet();
    +-        mTaskStoreUnderTest.readJobMapFromDisk(jobStatusSet);
    +-        assertEquals("Incorrect # of persisted tasks.", 1, jobStatusSet.size());
    +-        JobStatus loaded = jobStatusSet.getAllJobs().iterator().next();
    +-
    +-        // Assert early runtime was clamped to be under now + period. We can do <= here b/c we'll
    +-        // call SystemClock.elapsedRealtime after doing the disk i/o.
    +-        final long newNowElapsed = SystemClock.elapsedRealtime();
    +-        assertTrue("Early runtime wasn't correctly clamped.",
    +-                loaded.getEarliestRunTime() <= newNowElapsed + TWO_HOURS);
    +-        // Assert late runtime was clamped to be now + period + flex.
    +-        assertTrue("Early runtime wasn't correctly clamped.",
    +-                loaded.getEarliestRunTime() <= newNowElapsed + TWO_HOURS + ONE_HOUR);
    +-    }
    +-
    +-    public void testPriorityPersisted() throws Exception {
    +-        JobInfo.Builder b = new Builder(92, mComponent)
    +-                .setOverrideDeadline(5000)
    +-                .setPriority(42)
    +-                .setPersisted(true);
    +-        final JobStatus js = JobStatus.createFromJobInfo(b.build(), SOME_UID, null, -1, null);
    +-        mTaskStoreUnderTest.add(js);
    +-        Thread.sleep(IO_WAIT);
    +-        final JobSet jobStatusSet = new JobSet();
    +-        mTaskStoreUnderTest.readJobMapFromDisk(jobStatusSet);
    +-        JobStatus loaded = jobStatusSet.getAllJobs().iterator().next();
    +-        assertEquals("Priority not correctly persisted.", 42, loaded.getPriority());
    +-    }
    +-
    +-    /**
    +-     * Test that non persisted job is not written to disk.
    +-     */
    +-    public void testNonPersistedTaskIsNotPersisted() throws Exception {
    +-        JobInfo.Builder b = new Builder(42, mComponent)
    +-                .setOverrideDeadline(10000)
    +-                .setPersisted(false);
    +-        JobStatus jsNonPersisted = JobStatus.createFromJobInfo(b.build(), SOME_UID, null, -1, null);
    +-        mTaskStoreUnderTest.add(jsNonPersisted);
    +-        b = new Builder(43, mComponent)
    +-                .setOverrideDeadline(10000)
    +-                .setPersisted(true);
    +-        JobStatus jsPersisted = JobStatus.createFromJobInfo(b.build(), SOME_UID, null, -1, null);
    +-        mTaskStoreUnderTest.add(jsPersisted);
    +-        Thread.sleep(IO_WAIT);
    +-        final JobSet jobStatusSet = new JobSet();
    +-        mTaskStoreUnderTest.readJobMapFromDisk(jobStatusSet);
    +-        assertEquals("Job count is incorrect.", 1, jobStatusSet.size());
    +-        JobStatus jobStatus = jobStatusSet.getAllJobs().iterator().next();
    +-        assertEquals("Wrong job persisted.", 43, jobStatus.getJobId());
    +-    }
    +-
    +-    /**
    +-     * Helper function to throw an error if the provided task and TaskStatus objects are not equal.
    +-     */
    +-    private void assertTasksEqual(JobInfo first, JobInfo second) {
    +-        assertEquals("Different task ids.", first.getId(), second.getId());
    +-        assertEquals("Different components.", first.getService(), second.getService());
    +-        assertEquals("Different periodic status.", first.isPeriodic(), second.isPeriodic());
    +-        assertEquals("Different period.", first.getIntervalMillis(), second.getIntervalMillis());
    +-        assertEquals("Different inital backoff.", first.getInitialBackoffMillis(),
    +-                second.getInitialBackoffMillis());
    +-        assertEquals("Different backoff policy.", first.getBackoffPolicy(),
    +-                second.getBackoffPolicy());
    +-
    +-        assertEquals("Invalid charging constraint.", first.isRequireCharging(),
    +-                second.isRequireCharging());
    +-        assertEquals("Invalid idle constraint.", first.isRequireDeviceIdle(),
    +-                second.isRequireDeviceIdle());
    +-        assertEquals("Invalid unmetered constraint.",
    +-                first.getNetworkType() == JobInfo.NETWORK_TYPE_UNMETERED,
    +-                second.getNetworkType() == JobInfo.NETWORK_TYPE_UNMETERED);
    +-        assertEquals("Invalid connectivity constraint.",
    +-                first.getNetworkType() == JobInfo.NETWORK_TYPE_ANY,
    +-                second.getNetworkType() == JobInfo.NETWORK_TYPE_ANY);
    +-        assertEquals("Invalid deadline constraint.",
    +-                first.hasLateConstraint(),
    +-                second.hasLateConstraint());
    +-        assertEquals("Invalid delay constraint.",
    +-                first.hasEarlyConstraint(),
    +-                second.hasEarlyConstraint());
    +-        assertEquals("Extras don't match",
    +-                first.getExtras().toString(), second.getExtras().toString());
    +-    }
    +-
    +-    /**
    +-     * When comparing timestamps before and after DB read/writes (to make sure we're saving/loading
    +-     * the correct values), there is some latency involved that terrorises a naive assertEquals().
    +-     * We define a <code>DELTA_MILLIS</code> as a function variable here to make this comparision
    +-     * more reasonable.
    +-     */
    +-    private void compareTimestampsSubjectToIoLatency(String error, long ts1, long ts2) {
    +-        final long DELTA_MILLIS = 700L;  // We allow up to 700ms of latency for IO read/writes.
    +-        assertTrue(error, Math.abs(ts1 - ts2) < DELTA_MILLIS + IO_WAIT);
    +-    }
    +-
    +-    private static class StubClass {}
    +-
    +-}
    +diff --git a/services/tests/servicestests/src/com/android/server/job/MockPriorityJobService.java b/services/tests/servicestests/src/com/android/server/job/MockPriorityJobService.java
    +deleted file mode 100644
    +index 3ea86f2..0000000
    +--- a/services/tests/servicestests/src/com/android/server/job/MockPriorityJobService.java
    ++++ /dev/null
    +@@ -1,106 +0,0 @@
    +-/*
    +- * Copyright (C) 2015 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 com.android.server.job;
    +-
    +-import android.annotation.TargetApi;
    +-import android.app.job.JobParameters;
    +-import android.app.job.JobService;
    +-import android.util.Log;
    +-
    +-import java.util.ArrayList;
    +-
    +-@TargetApi(24)
    +-public class MockPriorityJobService extends JobService {
    +-    private static final String TAG = "MockPriorityJobService";
    +-
    +-    @Override
    +-    public void onCreate() {
    +-        super.onCreate();
    +-        Log.e(TAG, "Created test service.");
    +-    }
    +-
    +-    @Override
    +-    public boolean onStartJob(JobParameters params) {
    +-        Log.i(TAG, "Test job executing: " + params.getJobId());
    +-        TestEnvironment.getTestEnvironment().executedEvents.add(
    +-                new TestEnvironment.Event(TestEnvironment.EVENT_START_JOB, params.getJobId()));
    +-        return true;  // Job not finished
    +-    }
    +-
    +-    @Override
    +-    public boolean onStopJob(JobParameters params) {
    +-        Log.i(TAG, "Test job stop executing: " + params.getJobId());
    +-        int reason = params.getStopReason();
    +-        int event = TestEnvironment.EVENT_STOP_JOB;
    +-        Log.d(TAG, "stop reason: " + String.valueOf(reason));
    +-        if (reason == JobParameters.REASON_PREEMPT) {
    +-            event = TestEnvironment.EVENT_PREEMPT_JOB;
    +-            Log.d(TAG, "preempted " + String.valueOf(params.getJobId()));
    +-        }
    +-        TestEnvironment.getTestEnvironment().executedEvents
    +-                .add(new TestEnvironment.Event(event, params.getJobId()));
    +-        return false;  // Do not reschedule
    +-    }
    +-
    +-    public static class TestEnvironment {
    +-
    +-        public static final int EVENT_START_JOB = 0;
    +-        public static final int EVENT_PREEMPT_JOB = 1;
    +-        public static final int EVENT_STOP_JOB = 2;
    +-
    +-        private static TestEnvironment kTestEnvironment;
    +-
    +-        private ArrayList<Event> executedEvents = new ArrayList<Event>();
    +-
    +-        public static TestEnvironment getTestEnvironment() {
    +-            if (kTestEnvironment == null) {
    +-                kTestEnvironment = new TestEnvironment();
    +-            }
    +-            return kTestEnvironment;
    +-        }
    +-
    +-        public static class Event {
    +-            public int event;
    +-            public int jobId;
    +-
    +-            public Event() {
    +-            }
    +-
    +-            public Event(int event, int jobId) {
    +-                this.event = event;
    +-                this.jobId = jobId;
    +-            }
    +-
    +-            @Override
    +-            public boolean equals(Object other) {
    +-                if (other instanceof Event) {
    +-                    Event otherEvent = (Event) other;
    +-                    return otherEvent.event == event && otherEvent.jobId == jobId;
    +-                }
    +-                return false;
    +-            }
    +-        }
    +-
    +-        public void setUp() {
    +-            executedEvents.clear();
    +-        }
    +-
    +-        public ArrayList<Event> getExecutedEvents() {
    +-            return executedEvents;
    +-        }
    +-    }
    +-}
    +diff --git a/services/tests/servicestests/src/com/android/server/job/PrioritySchedulingTest.java b/services/tests/servicestests/src/com/android/server/job/PrioritySchedulingTest.java
    +deleted file mode 100644
    +index 63bccfa..0000000
    +--- a/services/tests/servicestests/src/com/android/server/job/PrioritySchedulingTest.java
    ++++ /dev/null
    +@@ -1,119 +0,0 @@
    +-/*
    +- * Copyright (C) 2015 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 com.android.server.job;
    +-
    +-import android.annotation.TargetApi;
    +-import android.app.job.JobInfo;
    +-import android.app.job.JobScheduler;
    +-import android.content.ComponentName;
    +-import android.content.Context;
    +-import android.test.AndroidTestCase;
    +-import com.android.server.job.MockPriorityJobService.TestEnvironment;
    +-import com.android.server.job.MockPriorityJobService.TestEnvironment.Event;
    +-
    +-import java.util.ArrayList;
    +-
    +-@TargetApi(24)
    +-public class PrioritySchedulingTest extends AndroidTestCase {
    +-    /** Environment that notifies of JobScheduler callbacks. */
    +-    static TestEnvironment kTestEnvironment = TestEnvironment.getTestEnvironment();
    +-    /** Handle for the service which receives the execution callbacks from the JobScheduler. */
    +-    static ComponentName kJobServiceComponent;
    +-    JobScheduler mJobScheduler;
    +-
    +-    @Override
    +-    public void setUp() throws Exception {
    +-        super.setUp();
    +-        kTestEnvironment.setUp();
    +-        kJobServiceComponent = new ComponentName(getContext(), MockPriorityJobService.class);
    +-        mJobScheduler = (JobScheduler) getContext().getSystemService(Context.JOB_SCHEDULER_SERVICE);
    +-        mJobScheduler.cancelAll();
    +-    }
    +-
    +-    @Override
    +-    public void tearDown() throws Exception {
    +-        mJobScheduler.cancelAll();
    +-        super.tearDown();
    +-    }
    +-
    +-    public void testLowerPriorityJobPreempted() throws Exception {
    +-        JobInfo job1 = new JobInfo.Builder(111, kJobServiceComponent)
    +-                .setPriority(1)
    +-                .setOverrideDeadline(7000L)
    +-                .build();
    +-        JobInfo job2 = new JobInfo.Builder(222, kJobServiceComponent)
    +-                .setPriority(1)
    +-                .setOverrideDeadline(7000L)
    +-                .build();
    +-        JobInfo job3 = new JobInfo.Builder(333, kJobServiceComponent)
    +-                .setPriority(1)
    +-                .setOverrideDeadline(7000L)
    +-                .build();
    +-        JobInfo job4 = new JobInfo.Builder(444, kJobServiceComponent)
    +-                .setPriority(2)
    +-                .setMinimumLatency(2000L)
    +-                .setOverrideDeadline(7000L)
    +-                .build();
    +-        mJobScheduler.schedule(job1);
    +-        mJobScheduler.schedule(job2);
    +-        mJobScheduler.schedule(job3);
    +-        mJobScheduler.schedule(job4);
    +-        Thread.sleep(10000);  // Wait for job 4 to preempt one of the lower priority jobs
    +-
    +-        Event job4Execution = new Event(TestEnvironment.EVENT_START_JOB, 444);
    +-        ArrayList<Event> executedEvents = kTestEnvironment.getExecutedEvents();
    +-        boolean wasJob4Executed = executedEvents.contains(job4Execution);
    +-        boolean wasSomeJobPreempted = false;
    +-        for (Event event: executedEvents) {
    +-            if (event.event == TestEnvironment.EVENT_PREEMPT_JOB) {
    +-                wasSomeJobPreempted = true;
    +-                break;
    +-            }
    +-        }
    +-        assertTrue("No job was preempted.", wasSomeJobPreempted);
    +-        assertTrue("Lower priority jobs were not preempted.",  wasJob4Executed);
    +-    }
    +-
    +-    public void testHigherPriorityJobNotPreempted() throws Exception {
    +-        JobInfo job1 = new JobInfo.Builder(111, kJobServiceComponent)
    +-                .setPriority(2)
    +-                .setOverrideDeadline(7000L)
    +-                .build();
    +-        JobInfo job2 = new JobInfo.Builder(222, kJobServiceComponent)
    +-                .setPriority(2)
    +-                .setOverrideDeadline(7000L)
    +-                .build();
    +-        JobInfo job3 = new JobInfo.Builder(333, kJobServiceComponent)
    +-                .setPriority(2)
    +-                .setOverrideDeadline(7000L)
    +-                .build();
    +-        JobInfo job4 = new JobInfo.Builder(444, kJobServiceComponent)
    +-                .setPriority(1)
    +-                .setMinimumLatency(2000L)
    +-                .setOverrideDeadline(7000L)
    +-                .build();
    +-        mJobScheduler.schedule(job1);
    +-        mJobScheduler.schedule(job2);
    +-        mJobScheduler.schedule(job3);
    +-        mJobScheduler.schedule(job4);
    +-        Thread.sleep(10000);  // Wait for job 4 to preempt one of the higher priority jobs
    +-
    +-        Event job4Execution = new Event(TestEnvironment.EVENT_START_JOB, 444);
    +-        boolean wasJob4Executed = kTestEnvironment.getExecutedEvents().contains(job4Execution);
    +-        assertFalse("Higher priority job was preempted.", wasJob4Executed);
    +-    }
    +-}
    +diff --git a/services/tests/servicestests/src/com/android/server/location/ComprehensiveCountryDetectorTest.java b/services/tests/servicestests/src/com/android/server/location/ComprehensiveCountryDetectorTest.java
    +deleted file mode 100644
    +index 98966c0..0000000
    +--- a/services/tests/servicestests/src/com/android/server/location/ComprehensiveCountryDetectorTest.java
    ++++ /dev/null
    +@@ -1,299 +0,0 @@
    +-/*
    +- * Copyright (C) 2010 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 com.android.server.location;
    +-
    +-import android.location.Country;
    +-import android.location.CountryListener;
    +-import android.test.AndroidTestCase;
    +-
    +-public class ComprehensiveCountryDetectorTest extends AndroidTestCase {
    +-    private class TestCountryDetector extends ComprehensiveCountryDetector {
    +-        public final static String COUNTRY_ISO = "us";
    +-        private boolean mLocationBasedDetectorStarted;
    +-        private boolean mLocationBasedDetectorStopped;
    +-        protected boolean mNotified;
    +-        private boolean listenerAdded = false;
    +-
    +-        private Country mNotifiedCountry;
    +-        public TestCountryDetector() {
    +-            super(getContext());
    +-        }
    +-
    +-        public void notifyLocationBasedListener(Country country) {
    +-            mNotified = true;
    +-            mNotifiedCountry = country;
    +-            mLocationBasedCountryDetector.notifyListener(country);
    +-        }
    +-
    +-        public boolean locationBasedDetectorStarted() {
    +-            return mLocationBasedCountryDetector != null && mLocationBasedDetectorStarted;
    +-        }
    +-
    +-        public boolean locationBasedDetectorStopped() {
    +-            return mLocationBasedCountryDetector == null && mLocationBasedDetectorStopped;
    +-        }
    +-
    +-        public boolean locationRefreshStarted() {
    +-            return mLocationRefreshTimer != null;
    +-        }
    +-
    +-        public boolean locationRefreshCancelled() {
    +-            return mLocationRefreshTimer == null;
    +-        }
    +-
    +-        @Override
    +-        protected CountryDetectorBase createLocationBasedCountryDetector() {
    +-            return new CountryDetectorBase(mContext) {
    +-                @Override
    +-                public Country detectCountry() {
    +-                    mLocationBasedDetectorStarted = true;
    +-                    return null;
    +-                }
    +-
    +-                @Override
    +-                public void stop() {
    +-                    mLocationBasedDetectorStopped = true;
    +-                }
    +-            };
    +-        }
    +-
    +-        @Override
    +-        protected Country getNetworkBasedCountry() {
    +-            return null;
    +-        }
    +-
    +-        @Override
    +-        protected Country getLastKnownLocationBasedCountry() {
    +-            return mNotifiedCountry;
    +-        }
    +-
    +-        @Override
    +-        protected Country getSimBasedCountry() {
    +-            return null;
    +-        }
    +-
    +-        @Override
    +-        protected Country getLocaleCountry() {
    +-            return null;
    +-        }
    +-
    +-        @Override
    +-        protected void runAfterDetectionAsync(final Country country, final Country detectedCountry,
    +-                final boolean notifyChange, final boolean startLocationBasedDetection) {
    +-            runAfterDetection(country, detectedCountry, notifyChange, startLocationBasedDetection);
    +-        };
    +-
    +-        @Override
    +-        protected boolean isAirplaneModeOff() {
    +-            return true;
    +-        }
    +-
    +-        @Override
    +-        protected synchronized void addPhoneStateListener() {
    +-            listenerAdded = true;
    +-        }
    +-
    +-        @Override
    +-        protected synchronized void removePhoneStateListener() {
    +-            listenerAdded = false;
    +-        }
    +-
    +-        @Override
    +-        protected boolean isGeoCoderImplemented() {
    +-            return true;
    +-        }
    +-
    +-        public boolean isPhoneStateListenerAdded() {
    +-            return listenerAdded;
    +-        }
    +-    }
    +-
    +-    private class CountryListenerImpl implements CountryListener {
    +-        private boolean mNotified;
    +-        private Country mCountry;
    +-
    +-        public void onCountryDetected(Country country) {
    +-            mNotified = true;
    +-            mCountry = country;
    +-        }
    +-
    +-        public boolean notified() {
    +-            return mNotified;
    +-        }
    +-
    +-        public Country getCountry() {
    +-            return mCountry;
    +-        }
    +-    }
    +-
    +-    public void testDetectNetworkBasedCountry() {
    +-        final Country resultCountry = new Country(
    +-                TestCountryDetector.COUNTRY_ISO, Country.COUNTRY_SOURCE_NETWORK);
    +-        TestCountryDetector countryDetector = new TestCountryDetector() {
    +-            @Override
    +-            protected Country getNetworkBasedCountry() {
    +-                return resultCountry;
    +-            }
    +-        };
    +-        CountryListenerImpl listener = new CountryListenerImpl();
    +-        countryDetector.setCountryListener(listener);
    +-        Country country = countryDetector.detectCountry();
    +-        assertTrue(sameCountry(country, resultCountry));
    +-        assertFalse(listener.notified());
    +-        assertFalse(countryDetector.locationBasedDetectorStarted());
    +-        assertFalse(countryDetector.locationRefreshStarted());
    +-        countryDetector.stop();
    +-    }
    +-
    +-    public void testDetectLocationBasedCountry() {
    +-        final Country resultCountry = new Country(
    +-                TestCountryDetector.COUNTRY_ISO, Country.COUNTRY_SOURCE_SIM);
    +-        final Country locationBasedCountry = new Country(
    +-                TestCountryDetector.COUNTRY_ISO, Country.COUNTRY_SOURCE_LOCATION);
    +-        TestCountryDetector countryDetector = new TestCountryDetector() {
    +-            @Override
    +-            protected Country getSimBasedCountry() {
    +-                return resultCountry;
    +-            }
    +-        };
    +-        CountryListenerImpl listener = new CountryListenerImpl();
    +-        countryDetector.setCountryListener(listener);
    +-        Country country = countryDetector.detectCountry();
    +-        assertTrue(sameCountry(country, resultCountry));
    +-        assertTrue(countryDetector.locationBasedDetectorStarted());
    +-        countryDetector.notifyLocationBasedListener(locationBasedCountry);
    +-        assertTrue(listener.notified());
    +-        assertTrue(sameCountry(listener.getCountry(), locationBasedCountry));
    +-        assertTrue(countryDetector.locationBasedDetectorStopped());
    +-        assertTrue(countryDetector.locationRefreshStarted());
    +-        countryDetector.stop();
    +-        assertTrue(countryDetector.locationRefreshCancelled());
    +-    }
    +-
    +-    public void testLocaleBasedCountry() {
    +-        final Country resultCountry = new Country(
    +-                TestCountryDetector.COUNTRY_ISO, Country.COUNTRY_SOURCE_LOCALE);
    +-        TestCountryDetector countryDetector = new TestCountryDetector() {
    +-            @Override
    +-            protected Country getLocaleCountry() {
    +-                return resultCountry;
    +-            }
    +-        };
    +-        CountryListenerImpl listener = new CountryListenerImpl();
    +-        countryDetector.setCountryListener(listener);
    +-        Country country = countryDetector.detectCountry();
    +-        assertTrue(sameCountry(country, resultCountry));
    +-        assertFalse(listener.notified());
    +-        assertTrue(countryDetector.locationBasedDetectorStarted());
    +-        assertTrue(countryDetector.locationRefreshStarted());
    +-        countryDetector.stop();
    +-        assertTrue(countryDetector.locationRefreshCancelled());
    +-    }
    +-
    +-    public void testStoppingDetector() {
    +-        // Test stopping detector when LocationBasedCountryDetector was started
    +-        final Country resultCountry = new Country(
    +-                TestCountryDetector.COUNTRY_ISO, Country.COUNTRY_SOURCE_SIM);
    +-        TestCountryDetector countryDetector = new TestCountryDetector() {
    +-            @Override
    +-            protected Country getSimBasedCountry() {
    +-                return resultCountry;
    +-            }
    +-        };
    +-        CountryListenerImpl listener = new CountryListenerImpl();
    +-        countryDetector.setCountryListener(listener);
    +-        Country country = countryDetector.detectCountry();
    +-        assertTrue(sameCountry(country, resultCountry));
    +-        assertTrue(countryDetector.locationBasedDetectorStarted());
    +-        countryDetector.stop();
    +-        // The LocationBasedDetector should be stopped.
    +-        assertTrue(countryDetector.locationBasedDetectorStopped());
    +-        // The location refresh should not running.
    +-        assertTrue(countryDetector.locationRefreshCancelled());
    +-    }
    +-
    +-    public void testLocationBasedCountryNotFound() {
    +-        final Country resultCountry = new Country(
    +-                TestCountryDetector.COUNTRY_ISO, Country.COUNTRY_SOURCE_SIM);
    +-        TestCountryDetector countryDetector = new TestCountryDetector() {
    +-            @Override
    +-            protected Country getSimBasedCountry() {
    +-                return resultCountry;
    +-            }
    +-        };
    +-        CountryListenerImpl listener = new CountryListenerImpl();
    +-        countryDetector.setCountryListener(listener);
    +-        Country country = countryDetector.detectCountry();
    +-        assertTrue(sameCountry(country, resultCountry));
    +-        assertTrue(countryDetector.locationBasedDetectorStarted());
    +-        countryDetector.notifyLocationBasedListener(null);
    +-        assertFalse(listener.notified());
    +-        assertTrue(sameCountry(listener.getCountry(), null));
    +-        assertTrue(countryDetector.locationBasedDetectorStopped());
    +-        assertTrue(countryDetector.locationRefreshStarted());
    +-        countryDetector.stop();
    +-        assertTrue(countryDetector.locationRefreshCancelled());
    +-    }
    +-
    +-    public void testNoCountryFound() {
    +-        TestCountryDetector countryDetector = new TestCountryDetector();
    +-        CountryListenerImpl listener = new CountryListenerImpl();
    +-        countryDetector.setCountryListener(listener);
    +-        Country country = countryDetector.detectCountry();
    +-        assertTrue(sameCountry(country, null));
    +-        assertTrue(countryDetector.locationBasedDetectorStarted());
    +-        countryDetector.notifyLocationBasedListener(null);
    +-        assertFalse(listener.notified());
    +-        assertTrue(sameCountry(listener.getCountry(), null));
    +-        assertTrue(countryDetector.locationBasedDetectorStopped());
    +-        assertTrue(countryDetector.locationRefreshStarted());
    +-        countryDetector.stop();
    +-        assertTrue(countryDetector.locationRefreshCancelled());
    +-    }
    +-
    +-    public void testAddRemoveListener() {
    +-        TestCountryDetector countryDetector = new TestCountryDetector();
    +-        CountryListenerImpl listener = new CountryListenerImpl();
    +-        countryDetector.setCountryListener(listener);
    +-        assertTrue(countryDetector.isPhoneStateListenerAdded());
    +-        assertTrue(countryDetector.locationBasedDetectorStarted());
    +-        countryDetector.setCountryListener(null);
    +-        assertFalse(countryDetector.isPhoneStateListenerAdded());
    +-        assertTrue(countryDetector.locationBasedDetectorStopped());
    +-    }
    +-
    +-    public void testGeocoderNotImplemented() {
    +-        TestCountryDetector countryDetector = new TestCountryDetector() {
    +-            @Override
    +-            protected boolean isGeoCoderImplemented() {
    +-                return false;
    +-            }
    +-        };
    +-        CountryListenerImpl listener = new CountryListenerImpl();
    +-        countryDetector.setCountryListener(listener);
    +-        assertTrue(countryDetector.isPhoneStateListenerAdded());
    +-        assertFalse(countryDetector.locationBasedDetectorStarted());
    +-        countryDetector.setCountryListener(null);
    +-        assertFalse(countryDetector.isPhoneStateListenerAdded());
    +-    }
    +-
    +-    private boolean sameCountry(Country country1, Country country2) {
    +-        return country1 == null && country2 == null || country1 != null && country2 != null &&
    +-        country1.getCountryIso().equalsIgnoreCase(country2.getCountryIso()) &&
    +-        country1.getSource() == country2.getSource();
    +-    }
    +-}
    +diff --git a/services/tests/servicestests/src/com/android/server/location/LocationBasedCountryDetectorTest.java b/services/tests/servicestests/src/com/android/server/location/LocationBasedCountryDetectorTest.java
    +deleted file mode 100644
    +index 5f5d668..0000000
    +--- a/services/tests/servicestests/src/com/android/server/location/LocationBasedCountryDetectorTest.java
    ++++ /dev/null
    +@@ -1,379 +0,0 @@
    +-/*
    +- * Copyright (C) 2010 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 com.android.server.location;
    +-
    +-import android.location.Country;
    +-import android.location.CountryListener;
    +-import android.location.Location;
    +-import android.location.LocationListener;
    +-import android.location.LocationManager;
    +-import android.test.AndroidTestCase;
    +-
    +-import java.util.Arrays;
    +-import java.util.HashMap;
    +-import java.util.HashSet;
    +-import java.util.List;
    +-import java.util.Map;
    +-import java.util.Map.Entry;
    +-import java.util.Set;
    +-import java.util.Timer;
    +-
    +-public class LocationBasedCountryDetectorTest extends AndroidTestCase {
    +-    private static final List<String> sEnabledProviders = Arrays.asList(
    +-            LocationManager.GPS_PROVIDER, LocationManager.PASSIVE_PROVIDER);
    +-    private class TestCountryDetector extends LocationBasedCountryDetector {
    +-        public static final int TOTAL_PROVIDERS = 2;
    +-        protected Object countryFoundLocker = new Object();
    +-        protected boolean notifyCountry = false;
    +-        private final Location mLocation;
    +-        private final String mCountry;
    +-        private final long mQueryLocationTimeout;
    +-        private Map<String, LocationListener> mListeners;
    +-
    +-        public TestCountryDetector(String country, String provider) {
    +-            this(country, provider, 1000 * 60 * 5);
    +-        }
    +-
    +-        public TestCountryDetector(String country, String provider, long queryLocationTimeout) {
    +-            super(getContext());
    +-            mCountry = country;
    +-            mLocation = new Location(provider);
    +-            mQueryLocationTimeout = queryLocationTimeout;
    +-            mListeners = new HashMap<String, LocationListener>();
    +-        }
    +-
    +-        @Override
    +-        protected String getCountryFromLocation(Location location) {
    +-            synchronized (countryFoundLocker) {
    +-                if (!notifyCountry) {
    +-                    try {
    +-                        countryFoundLocker.wait();
    +-                    } catch (InterruptedException e) {
    +-                    }
    +-                }
    +-            }
    +-            if (mLocation.getProvider().endsWith(location.getProvider())) {
    +-                return mCountry;
    +-            } else {
    +-                return null;
    +-            }
    +-        }
    +-
    +-        @Override
    +-        protected Location getLastKnownLocation() {
    +-            return mLocation;
    +-        }
    +-
    +-        private Set<String> mAcceptableProviders;
    +-
    +-        public void setAcceptableProvider(Set<String> acceptableProviders) {
    +-            mAcceptableProviders = acceptableProviders;
    +-        }
    +-
    +-        @Override
    +-        protected boolean isAcceptableProvider(String provider) {
    +-            if (mAcceptableProviders != null) {
    +-                return mAcceptableProviders.contains(provider);
    +-            } else {
    +-                return true;
    +-            }
    +-        }
    +-
    +-        @Override
    +-        protected void registerListener(String provider, LocationListener listener) {
    +-            assertNotNull(provider);
    +-            mListeners.put(provider, listener);
    +-        }
    +-
    +-        @Override
    +-        protected void unregisterListener(LocationListener listener) {
    +-            for (Entry<String, LocationListener> entry : mListeners.entrySet()) {
    +-                if (entry.getValue().equals(listener)) {
    +-                    mListeners.remove(entry.getKey());
    +-                    return;
    +-                }
    +-            }
    +-            fail("Not registered");
    +-        }
    +-
    +-        public Map<String, LocationListener> getListeners() {
    +-            return mListeners;
    +-        }
    +-
    +-        @Override
    +-        protected long getQueryLocationTimeout() {
    +-            return mQueryLocationTimeout;
    +-        }
    +-
    +-        @Override
    +-        protected List<String> getEnabledProviders() {
    +-            return sEnabledProviders;
    +-        }
    +-
    +-        public void notifyLocationFound() {
    +-            // Listener could be removed in the notification.
    +-            LocationListener[] listeners = new LocationListener[mListeners.size()];
    +-            mLocationListeners.toArray(listeners);
    +-            for (LocationListener listener :listeners) {
    +-                listener.onLocationChanged(mLocation);
    +-            }
    +-        }
    +-
    +-        public int getListenersCount() {
    +-            return mListeners.size();
    +-        }
    +-
    +-        public void notifyCountryFound() {
    +-            synchronized (countryFoundLocker) {
    +-                notifyCountry = true;
    +-                countryFoundLocker.notify();
    +-            }
    +-        }
    +-
    +-        public Timer getTimer() {
    +-            return mTimer;
    +-        }
    +-
    +-        public Thread getQueryThread() {
    +-            return mQueryThread;
    +-        }
    +-    }
    +-
    +-    private class CountryListenerImpl implements CountryListener {
    +-        private boolean mNotified;
    +-        private String mCountryCode;
    +-        public void onCountryDetected(Country country) {
    +-            mNotified = true;
    +-            if (country != null) {
    +-                mCountryCode = country.getCountryIso();
    +-            }
    +-        }
    +-
    +-        public boolean notified() {
    +-            return mNotified;
    +-        }
    +-
    +-        public String getCountry() {
    +-            return mCountryCode;
    +-        }
    +-    }
    +-
    +-    public void testFindingCountry() {
    +-        testFindingCountryCommon(null);
    +-    }
    +-
    +-    public void testFindingCountryWithAcceptableProvider() {
    +-        testFindingCountryCommon(new HashSet<String>(Arrays.asList("passive")));
    +-    }
    +-
    +-    private void testFindingCountryCommon(Set<String> acceptableProviders) {
    +-        final String country = "us";
    +-        final String provider = "Good";
    +-        CountryListenerImpl countryListener = new CountryListenerImpl();
    +-        TestCountryDetector detector = new TestCountryDetector(country, provider);
    +-
    +-        if (acceptableProviders != null) {
    +-            detector.setAcceptableProvider(acceptableProviders);
    +-        }
    +-
    +-        detector.setCountryListener(countryListener);
    +-        detector.detectCountry();
    +-
    +-        if (acceptableProviders != null) {
    +-            assertEquals(acceptableProviders.size(), detector.getListenersCount());
    +-            Map<String, LocationListener> listeners = detector.getListeners();
    +-            for (String acceptableProvider : acceptableProviders) {
    +-                assertTrue(listeners.containsKey(acceptableProvider));
    +-            }
    +-        } else {
    +-            assertEquals(TestCountryDetector.TOTAL_PROVIDERS, detector.getListenersCount());
    +-        }
    +-
    +-        detector.notifyLocationFound();
    +-        // All listeners should be unregistered
    +-        assertEquals(0, detector.getListenersCount());
    +-        assertNull(detector.getTimer());
    +-        Thread queryThread = waitForQueryThreadLaunched(detector);
    +-        detector.notifyCountryFound();
    +-        // Wait for query thread ending
    +-        waitForThreadEnding(queryThread);
    +-        // QueryThread should be set to NULL
    +-        assertNull(detector.getQueryThread());
    +-        assertTrue(countryListener.notified());
    +-        assertEquals("us", countryListener.getCountry().toLowerCase());
    +-    }
    +-
    +-    public void testFindingCountryCancelled() {
    +-        final String country = "us";
    +-        final String provider = "Good";
    +-        CountryListenerImpl countryListener = new CountryListenerImpl();
    +-        TestCountryDetector detector = new TestCountryDetector(country, provider);
    +-        detector.setCountryListener(countryListener);
    +-        detector.detectCountry();
    +-        assertEquals(TestCountryDetector.TOTAL_PROVIDERS, detector.getListenersCount());
    +-        detector.notifyLocationFound();
    +-        // All listeners should be unregistered
    +-        assertEquals(0, detector.getListenersCount());
    +-        // The time should be stopped
    +-        assertNull(detector.getTimer());
    +-        Thread queryThread = waitForQueryThreadLaunched(detector);
    +-        detector.stop();
    +-        // There is no way to stop the thread, let's test it could be stopped, after get country
    +-        detector.notifyCountryFound();
    +-        // Wait for query thread ending
    +-        waitForThreadEnding(queryThread);
    +-        // QueryThread should be set to NULL
    +-        assertNull(detector.getQueryThread());
    +-        assertTrue(countryListener.notified());
    +-        assertEquals("us", countryListener.getCountry().toLowerCase());
    +-    }
    +-
    +-    public void testFindingLocationCancelled() {
    +-        final String country = "us";
    +-        final String provider = "Good";
    +-        CountryListenerImpl countryListener = new CountryListenerImpl();
    +-        TestCountryDetector detector = new TestCountryDetector(country, provider);
    +-        detector.setCountryListener(countryListener);
    +-        detector.detectCountry();
    +-        assertEquals(TestCountryDetector.TOTAL_PROVIDERS, detector.getListenersCount());
    +-        detector.stop();
    +-        // All listeners should be unregistered
    +-        assertEquals(0, detector.getListenersCount());
    +-        // The time should be stopped
    +-        assertNull(detector.getTimer());
    +-        // QueryThread should still be NULL
    +-        assertNull(detector.getQueryThread());
    +-        assertFalse(countryListener.notified());
    +-    }
    +-
    +-    public void testFindingLocationFailed() {
    +-        final String country = "us";
    +-        final String provider = "Good";
    +-        long timeout = 1000;
    +-        TestCountryDetector detector = new TestCountryDetector(country, provider, timeout) {
    +-            @Override
    +-            protected Location getLastKnownLocation() {
    +-                return null;
    +-            }
    +-        };
    +-        CountryListenerImpl countryListener = new CountryListenerImpl();
    +-        detector.setCountryListener(countryListener);
    +-        detector.detectCountry();
    +-        assertEquals(TestCountryDetector.TOTAL_PROVIDERS, detector.getListenersCount());
    +-        waitForTimerReset(detector);
    +-        // All listeners should be unregistered
    +-        assertEquals(0, detector.getListenersCount());
    +-        // QueryThread should still be NULL
    +-        assertNull(detector.getQueryThread());
    +-        assertTrue(countryListener.notified());
    +-        assertNull(countryListener.getCountry());
    +-    }
    +-
    +-    public void testFindingCountryFailed() {
    +-        final String country = "us";
    +-        final String provider = "Good";
    +-        TestCountryDetector detector = new TestCountryDetector(country, provider) {
    +-            @Override
    +-            protected String getCountryFromLocation(Location location) {
    +-                synchronized (countryFoundLocker) {
    +-                    if (! notifyCountry) {
    +-                        try {
    +-                            countryFoundLocker.wait();
    +-                        } catch (InterruptedException e) {
    +-                        }
    +-                    }
    +-                }
    +-                // We didn't find country.
    +-                return null;
    +-            }
    +-        };
    +-        CountryListenerImpl countryListener = new CountryListenerImpl();
    +-        detector.setCountryListener(countryListener);
    +-        detector.detectCountry();
    +-        assertEquals(TestCountryDetector.TOTAL_PROVIDERS, detector.getListenersCount());
    +-        detector.notifyLocationFound();
    +-        // All listeners should be unregistered
    +-        assertEquals(0, detector.getListenersCount());
    +-        assertNull(detector.getTimer());
    +-        Thread queryThread = waitForQueryThreadLaunched(detector);
    +-        detector.notifyCountryFound();
    +-        // Wait for query thread ending
    +-        waitForThreadEnding(queryThread);
    +-        // QueryThread should be set to NULL
    +-        assertNull(detector.getQueryThread());
    +-        // CountryListener should be notified
    +-        assertTrue(countryListener.notified());
    +-        assertNull(countryListener.getCountry());
    +-    }
    +-
    +-    public void testFindingCountryWithLastKnownLocation() {
    +-        final String country = "us";
    +-        final String provider = "Good";
    +-        long timeout = 1000;
    +-        TestCountryDetector detector = new TestCountryDetector(country, provider, timeout);
    +-        CountryListenerImpl countryListener = new CountryListenerImpl();
    +-        detector.setCountryListener(countryListener);
    +-        detector.detectCountry();
    +-        assertEquals(TestCountryDetector.TOTAL_PROVIDERS, detector.getListenersCount());
    +-        waitForTimerReset(detector);
    +-        // All listeners should be unregistered
    +-        assertEquals(0, detector.getListenersCount());
    +-        Thread queryThread = waitForQueryThreadLaunched(detector);
    +-        detector.notifyCountryFound();
    +-        // Wait for query thread ending
    +-        waitForThreadEnding(queryThread);
    +-        // QueryThread should be set to NULL
    +-        assertNull(detector.getQueryThread());
    +-        // CountryListener should be notified
    +-        assertTrue(countryListener.notified());
    +-        assertEquals("us", countryListener.getCountry().toLowerCase());
    +-    }
    +-
    +-    private void waitForTimerReset(TestCountryDetector detector) {
    +-        int count = 5;
    +-        long interval = 1000;
    +-        try {
    +-            while (count-- > 0 && detector.getTimer() != null) {
    +-                Thread.sleep(interval);
    +-            }
    +-        } catch (InterruptedException e) {
    +-        }
    +-        Timer timer = detector.getTimer();
    +-        assertTrue(timer == null);
    +-    }
    +-
    +-    private void waitForThreadEnding(Thread thread) {
    +-        try {
    +-            thread.join(5000);
    +-        } catch (InterruptedException e) {
    +-            e.printStackTrace();
    +-        }
    +-    }
    +-
    +-    private Thread waitForQueryThreadLaunched(TestCountryDetector detector) {
    +-        int count = 5;
    +-        long interval = 1000;
    +-        try {
    +-            while (count-- > 0 && detector.getQueryThread() == null) {
    +-                Thread.sleep(interval);
    +-            }
    +-        } catch (InterruptedException e) {
    +-        }
    +-        Thread thread = detector.getQueryThread();
    +-        assertTrue(thread != null);
    +-        return thread;
    +-    }
    +-}
    +diff --git a/services/tests/servicestests/src/com/android/server/location/LocationRequestStatisticsTest.java b/services/tests/servicestests/src/com/android/server/location/LocationRequestStatisticsTest.java
    +deleted file mode 100644
    +index 33f604d..0000000
    +--- a/services/tests/servicestests/src/com/android/server/location/LocationRequestStatisticsTest.java
    ++++ /dev/null
    +@@ -1,175 +0,0 @@
    +-package com.android.server.location;
    +-
    +-import com.android.server.location.LocationRequestStatistics.PackageProviderKey;
    +-import com.android.server.location.LocationRequestStatistics.PackageStatistics;
    +-
    +-import android.os.SystemClock;
    +-import android.test.AndroidTestCase;
    +-
    +-/**
    +- * Unit tests for {@link LocationRequestStatistics}.
    +- */
    +-public class LocationRequestStatisticsTest extends AndroidTestCase {
    +-    private static final String PACKAGE1 = "package1";
    +-    private static final String PACKAGE2 = "package2";
    +-    private static final String PROVIDER1 = "provider1";
    +-    private static final String PROVIDER2 = "provider2";
    +-    private static final long INTERVAL1 = 5000;
    +-    private static final long INTERVAL2 = 100000;
    +-
    +-    private LocationRequestStatistics mStatistics;
    +-    private long mStartElapsedRealtimeMs;
    +-
    +-    @Override
    +-    public void setUp() {
    +-        mStatistics = new LocationRequestStatistics();
    +-        mStartElapsedRealtimeMs = SystemClock.elapsedRealtime();
    +-    }
    +-
    +-    /**
    +-     * Tests that adding a single package works correctly.
    +-     */
    +-    public void testSinglePackage() {
    +-        mStatistics.startRequesting(PACKAGE1, PROVIDER1, INTERVAL1);
    +-
    +-        assertEquals(1, mStatistics.statistics.size());
    +-        PackageProviderKey key = mStatistics.statistics.keySet().iterator().next();
    +-        assertEquals(PACKAGE1, key.packageName);
    +-        assertEquals(PROVIDER1, key.providerName);
    +-        PackageStatistics stats = mStatistics.statistics.values().iterator().next();
    +-        verifyStatisticsTimes(stats);
    +-        assertEquals(INTERVAL1, stats.getFastestIntervalMs());
    +-        assertEquals(INTERVAL1, stats.getSlowestIntervalMs());
    +-        assertTrue(stats.isActive());
    +-    }
    +-
    +-    /**
    +-     * Tests that adding a single package works correctly when it is stopped and restarted.
    +-     */
    +-    public void testSinglePackage_stopAndRestart() {
    +-        mStatistics.startRequesting(PACKAGE1, PROVIDER1, INTERVAL1);
    +-        mStatistics.stopRequesting(PACKAGE1, PROVIDER1);
    +-        mStatistics.startRequesting(PACKAGE1, PROVIDER1, INTERVAL1);
    +-
    +-        assertEquals(1, mStatistics.statistics.size());
    +-        PackageProviderKey key = mStatistics.statistics.keySet().iterator().next();
    +-        assertEquals(PACKAGE1, key.packageName);
    +-        assertEquals(PROVIDER1, key.providerName);
    +-        PackageStatistics stats = mStatistics.statistics.values().iterator().next();
    +-        verifyStatisticsTimes(stats);
    +-        assertEquals(INTERVAL1, stats.getFastestIntervalMs());
    +-        assertEquals(INTERVAL1, stats.getSlowestIntervalMs());
    +-        assertTrue(stats.isActive());
    +-
    +-        mStatistics.stopRequesting(PACKAGE1, PROVIDER1);
    +-        assertFalse(stats.isActive());
    +-    }
    +-
    +-    /**
    +-     * Tests that adding a single package works correctly when multiple intervals are used.
    +-     */
    +-    public void testSinglePackage_multipleIntervals() {
    +-        mStatistics.startRequesting(PACKAGE1, PROVIDER1, INTERVAL1);
    +-        mStatistics.startRequesting(PACKAGE1, PROVIDER1, INTERVAL2);
    +-
    +-        assertEquals(1, mStatistics.statistics.size());
    +-        PackageProviderKey key = mStatistics.statistics.keySet().iterator().next();
    +-        assertEquals(PACKAGE1, key.packageName);
    +-        assertEquals(PROVIDER1, key.providerName);
    +-        PackageStatistics stats = mStatistics.statistics.values().iterator().next();
    +-        verifyStatisticsTimes(stats);
    +-        assertEquals(INTERVAL1, stats.getFastestIntervalMs());
    +-        assertTrue(stats.isActive());
    +-
    +-        mStatistics.stopRequesting(PACKAGE1, PROVIDER1);
    +-        assertTrue(stats.isActive());
    +-        mStatistics.stopRequesting(PACKAGE1, PROVIDER1);
    +-        assertFalse(stats.isActive());
    +-    }
    +-
    +-    /**
    +-     * Tests that adding a single package works correctly when multiple providers are used.
    +-     */
    +-    public void testSinglePackage_multipleProviders() {
    +-        mStatistics.startRequesting(PACKAGE1, PROVIDER1, INTERVAL1);
    +-        mStatistics.startRequesting(PACKAGE1, PROVIDER2, INTERVAL2);
    +-
    +-        assertEquals(2, mStatistics.statistics.size());
    +-        PackageProviderKey key1 = new PackageProviderKey(PACKAGE1, PROVIDER1);
    +-        PackageStatistics stats1 = mStatistics.statistics.get(key1);
    +-        verifyStatisticsTimes(stats1);
    +-        assertEquals(INTERVAL1, stats1.getSlowestIntervalMs());
    +-        assertEquals(INTERVAL1, stats1.getFastestIntervalMs());
    +-        assertTrue(stats1.isActive());
    +-        PackageProviderKey key2 = new PackageProviderKey(PACKAGE1, PROVIDER2);
    +-        PackageStatistics stats2 = mStatistics.statistics.get(key2);
    +-        verifyStatisticsTimes(stats2);
    +-        assertEquals(INTERVAL2, stats2.getSlowestIntervalMs());
    +-        assertEquals(INTERVAL2, stats2.getFastestIntervalMs());
    +-        assertTrue(stats2.isActive());
    +-
    +-        mStatistics.stopRequesting(PACKAGE1, PROVIDER1);
    +-        assertFalse(stats1.isActive());
    +-        assertTrue(stats2.isActive());
    +-        mStatistics.stopRequesting(PACKAGE1, PROVIDER2);
    +-        assertFalse(stats1.isActive());
    +-        assertFalse(stats2.isActive());
    +-    }
    +-
    +-    /**
    +-     * Tests that adding multiple packages works correctly.
    +-     */
    +-    public void testMultiplePackages() {
    +-        mStatistics.startRequesting(PACKAGE1, PROVIDER1, INTERVAL1);
    +-        mStatistics.startRequesting(PACKAGE1, PROVIDER2, INTERVAL1);
    +-        mStatistics.startRequesting(PACKAGE1, PROVIDER2, INTERVAL2);
    +-        mStatistics.startRequesting(PACKAGE2, PROVIDER1, INTERVAL1);
    +-
    +-        assertEquals(3, mStatistics.statistics.size());
    +-        PackageProviderKey key1 = new PackageProviderKey(PACKAGE1, PROVIDER1);
    +-        PackageStatistics stats1 = mStatistics.statistics.get(key1);
    +-        verifyStatisticsTimes(stats1);
    +-        assertEquals(INTERVAL1, stats1.getSlowestIntervalMs());
    +-        assertEquals(INTERVAL1, stats1.getFastestIntervalMs());
    +-        assertTrue(stats1.isActive());
    +-
    +-        PackageProviderKey key2 = new PackageProviderKey(PACKAGE1, PROVIDER2);
    +-        PackageStatistics stats2 = mStatistics.statistics.get(key2);
    +-        verifyStatisticsTimes(stats2);
    +-        assertEquals(INTERVAL2, stats2.getSlowestIntervalMs());
    +-        assertEquals(INTERVAL1, stats2.getFastestIntervalMs());
    +-        assertTrue(stats2.isActive());
    +-
    +-        PackageProviderKey key3 = new PackageProviderKey(PACKAGE2, PROVIDER1);
    +-        PackageStatistics stats3 = mStatistics.statistics.get(key3);
    +-        verifyStatisticsTimes(stats3);
    +-        assertEquals(INTERVAL1, stats3.getSlowestIntervalMs());
    +-        assertEquals(INTERVAL1, stats3.getFastestIntervalMs());
    +-        assertTrue(stats3.isActive());
    +-
    +-        mStatistics.stopRequesting(PACKAGE1, PROVIDER1);
    +-        assertFalse(stats1.isActive());
    +-        assertTrue(stats2.isActive());
    +-        assertTrue(stats3.isActive());
    +-
    +-        mStatistics.stopRequesting(PACKAGE1, PROVIDER2);
    +-        assertFalse(stats1.isActive());
    +-        assertTrue(stats2.isActive());
    +-        assertTrue(stats3.isActive());
    +-        mStatistics.stopRequesting(PACKAGE1, PROVIDER2);
    +-        assertFalse(stats2.isActive());
    +-
    +-        mStatistics.stopRequesting(PACKAGE2, PROVIDER1);
    +-        assertFalse(stats1.isActive());
    +-        assertFalse(stats2.isActive());
    +-        assertFalse(stats3.isActive());
    +-    }
    +-
    +-    private void verifyStatisticsTimes(PackageStatistics stats) {
    +-        long durationMs = stats.getDurationMs();
    +-        long timeSinceFirstRequestMs = stats.getTimeSinceFirstRequestMs();
    +-        long maxDeltaMs = SystemClock.elapsedRealtime() - mStartElapsedRealtimeMs;
    +-        assertTrue("Duration is too large", durationMs <= maxDeltaMs);
    +-        assertTrue("Time since first request is too large", timeSinceFirstRequestMs <= maxDeltaMs);
    +-    }
    +-}
    +diff --git a/services/tests/servicestests/src/com/android/server/net/NetworkStatsAccessTest.java b/services/tests/servicestests/src/com/android/server/net/NetworkStatsAccessTest.java
    +deleted file mode 100644
    +index bb8f9d1..0000000
    +--- a/services/tests/servicestests/src/com/android/server/net/NetworkStatsAccessTest.java
    ++++ /dev/null
    +@@ -1,178 +0,0 @@
    +-/*
    +- * Copyright (C) 2015 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 com.android.server.net;
    +-
    +-import static org.mockito.Mockito.when;
    +-
    +-import android.Manifest;
    +-import android.Manifest.permission;
    +-import android.app.AppOpsManager;
    +-import android.app.admin.DeviceAdminInfo;
    +-import android.app.admin.DevicePolicyManagerInternal;
    +-import android.content.Context;
    +-import android.content.pm.PackageManager;
    +-import android.telephony.TelephonyManager;
    +-
    +-import com.android.server.LocalServices;
    +-
    +-import junit.framework.TestCase;
    +-
    +-import org.mockito.Mock;
    +-import org.mockito.MockitoAnnotations;
    +-
    +-public class NetworkStatsAccessTest extends TestCase {
    +-    private static final String TEST_PKG = "com.example.test";
    +-    private static final int TEST_UID = 12345;
    +-
    +-    @Mock private Context mContext;
    +-    @Mock private DevicePolicyManagerInternal mDpmi;
    +-    @Mock private TelephonyManager mTm;
    +-    @Mock private AppOpsManager mAppOps;
    +-
    +-    // Hold the real service so we can restore it when tearing down the test.
    +-    private DevicePolicyManagerInternal mSystemDpmi;
    +-
    +-    @Override
    +-    public void setUp() throws Exception {
    +-        super.setUp();
    +-        MockitoAnnotations.initMocks(this);
    +-
    +-        mSystemDpmi = LocalServices.getService(DevicePolicyManagerInternal.class);
    +-        LocalServices.removeServiceForTest(DevicePolicyManagerInternal.class);
    +-        LocalServices.addService(DevicePolicyManagerInternal.class, mDpmi);
    +-
    +-        when(mContext.getSystemService(Context.TELEPHONY_SERVICE)).thenReturn(mTm);
    +-        when(mContext.getSystemService(Context.APP_OPS_SERVICE)).thenReturn(mAppOps);
    +-    }
    +-
    +-    @Override
    +-    public void tearDown() throws Exception {
    +-        LocalServices.removeServiceForTest(DevicePolicyManagerInternal.class);
    +-        LocalServices.addService(DevicePolicyManagerInternal.class, mSystemDpmi);
    +-        super.tearDown();
    +-    }
    +-
    +-    public void testCheckAccessLevel_hasCarrierPrivileges() throws Exception {
    +-        setHasCarrierPrivileges(true);
    +-        setIsDeviceOwner(false);
    +-        setIsProfileOwner(false);
    +-        setHasAppOpsPermission(AppOpsManager.MODE_DEFAULT, false);
    +-        setHasReadHistoryPermission(false);
    +-        assertEquals(NetworkStatsAccess.Level.DEVICE,
    +-                NetworkStatsAccess.checkAccessLevel(mContext, TEST_UID, TEST_PKG));
    +-    }
    +-
    +-    public void testCheckAccessLevel_isDeviceOwner() throws Exception {
    +-        setHasCarrierPrivileges(false);
    +-        setIsDeviceOwner(true);
    +-        setIsProfileOwner(false);
    +-        setHasAppOpsPermission(AppOpsManager.MODE_DEFAULT, false);
    +-        setHasReadHistoryPermission(false);
    +-        assertEquals(NetworkStatsAccess.Level.DEVICE,
    +-                NetworkStatsAccess.checkAccessLevel(mContext, TEST_UID, TEST_PKG));
    +-    }
    +-
    +-    public void testCheckAccessLevel_isProfileOwner() throws Exception {
    +-        setHasCarrierPrivileges(false);
    +-        setIsDeviceOwner(false);
    +-        setIsProfileOwner(true);
    +-        setHasAppOpsPermission(AppOpsManager.MODE_DEFAULT, false);
    +-        setHasReadHistoryPermission(false);
    +-        assertEquals(NetworkStatsAccess.Level.USER,
    +-                NetworkStatsAccess.checkAccessLevel(mContext, TEST_UID, TEST_PKG));
    +-    }
    +-
    +-    public void testCheckAccessLevel_hasAppOpsBitAllowed() throws Exception {
    +-        setHasCarrierPrivileges(false);
    +-        setIsDeviceOwner(false);
    +-        setIsProfileOwner(true);
    +-        setHasAppOpsPermission(AppOpsManager.MODE_ALLOWED, false);
    +-        setHasReadHistoryPermission(false);
    +-        assertEquals(NetworkStatsAccess.Level.USER,
    +-                NetworkStatsAccess.checkAccessLevel(mContext, TEST_UID, TEST_PKG));
    +-    }
    +-
    +-    public void testCheckAccessLevel_hasAppOpsBitDefault_grantedPermission() throws Exception {
    +-        setHasCarrierPrivileges(false);
    +-        setIsDeviceOwner(false);
    +-        setIsProfileOwner(true);
    +-        setHasAppOpsPermission(AppOpsManager.MODE_DEFAULT, true);
    +-        setHasReadHistoryPermission(false);
    +-        assertEquals(NetworkStatsAccess.Level.USER,
    +-                NetworkStatsAccess.checkAccessLevel(mContext, TEST_UID, TEST_PKG));
    +-    }
    +-
    +-    public void testCheckAccessLevel_hasReadHistoryPermission() throws Exception {
    +-        setHasCarrierPrivileges(false);
    +-        setIsDeviceOwner(false);
    +-        setIsProfileOwner(true);
    +-        setHasAppOpsPermission(AppOpsManager.MODE_DEFAULT, false);
    +-        setHasReadHistoryPermission(true);
    +-        assertEquals(NetworkStatsAccess.Level.USER,
    +-                NetworkStatsAccess.checkAccessLevel(mContext, TEST_UID, TEST_PKG));
    +-    }
    +-
    +-    public void testCheckAccessLevel_deniedAppOpsBit() throws Exception {
    +-        setHasCarrierPrivileges(false);
    +-        setIsDeviceOwner(false);
    +-        setIsProfileOwner(false);
    +-        setHasAppOpsPermission(AppOpsManager.MODE_ERRORED, true);
    +-        setHasReadHistoryPermission(false);
    +-        assertEquals(NetworkStatsAccess.Level.DEFAULT,
    +-                NetworkStatsAccess.checkAccessLevel(mContext, TEST_UID, TEST_PKG));
    +-    }
    +-
    +-    public void testCheckAccessLevel_deniedAppOpsBit_deniedPermission() throws Exception {
    +-        setHasCarrierPrivileges(false);
    +-        setIsDeviceOwner(false);
    +-        setIsProfileOwner(false);
    +-        setHasAppOpsPermission(AppOpsManager.MODE_DEFAULT, false);
    +-        setHasReadHistoryPermission(false);
    +-        assertEquals(NetworkStatsAccess.Level.DEFAULT,
    +-                NetworkStatsAccess.checkAccessLevel(mContext, TEST_UID, TEST_PKG));
    +-    }
    +-
    +-    private void setHasCarrierPrivileges(boolean hasPrivileges) {
    +-        when(mTm.checkCarrierPrivilegesForPackage(TEST_PKG)).thenReturn(
    +-                hasPrivileges ? TelephonyManager.CARRIER_PRIVILEGE_STATUS_HAS_ACCESS
    +-                        : TelephonyManager.CARRIER_PRIVILEGE_STATUS_NO_ACCESS);
    +-    }
    +-
    +-    private void setIsDeviceOwner(boolean isOwner) {
    +-        when(mDpmi.isActiveAdminWithPolicy(TEST_UID, DeviceAdminInfo.USES_POLICY_DEVICE_OWNER))
    +-                .thenReturn(isOwner);
    +-    }
    +-
    +-    private void setIsProfileOwner(boolean isOwner) {
    +-        when(mDpmi.isActiveAdminWithPolicy(TEST_UID, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER))
    +-                .thenReturn(isOwner);
    +-    }
    +-
    +-    private void setHasAppOpsPermission(int appOpsMode, boolean hasPermission) {
    +-        when(mAppOps.checkOp(AppOpsManager.OP_GET_USAGE_STATS, TEST_UID, TEST_PKG))
    +-                .thenReturn(appOpsMode);
    +-        when(mContext.checkCallingPermission(Manifest.permission.PACKAGE_USAGE_STATS)).thenReturn(
    +-                hasPermission ? PackageManager.PERMISSION_GRANTED
    +-                        : PackageManager.PERMISSION_DENIED);
    +-    }
    +-
    +-    private void setHasReadHistoryPermission(boolean hasPermission) {
    +-        when(mContext.checkCallingOrSelfPermission(permission.READ_NETWORK_USAGE_HISTORY))
    +-                .thenReturn(hasPermission ? PackageManager.PERMISSION_GRANTED
    +-                        : PackageManager.PERMISSION_DENIED);
    +-    }
    +-}
    +diff --git a/services/tests/servicestests/src/com/android/server/net/NetworkStatsCollectionTest.java b/services/tests/servicestests/src/com/android/server/net/NetworkStatsCollectionTest.java
    +deleted file mode 100644
    +index 9f53c87..0000000
    +--- a/services/tests/servicestests/src/com/android/server/net/NetworkStatsCollectionTest.java
    ++++ /dev/null
    +@@ -1,262 +0,0 @@
    +-/*
    +- * Copyright (C) 2012 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 com.android.server.net;
    +-
    +-import static android.net.ConnectivityManager.TYPE_MOBILE;
    +-import static android.net.NetworkStats.SET_DEFAULT;
    +-import static android.net.NetworkStats.TAG_NONE;
    +-import static android.net.NetworkStats.UID_ALL;
    +-import static android.net.NetworkTemplate.buildTemplateMobileAll;
    +-import static android.text.format.DateUtils.HOUR_IN_MILLIS;
    +-import static android.text.format.DateUtils.MINUTE_IN_MILLIS;
    +-
    +-import android.content.res.Resources;
    +-import android.net.NetworkIdentity;
    +-import android.net.NetworkStats;
    +-import android.net.NetworkTemplate;
    +-import android.os.Process;
    +-import android.os.UserHandle;
    +-import android.telephony.TelephonyManager;
    +-import android.test.AndroidTestCase;
    +-import android.test.MoreAsserts;
    +-import android.test.suitebuilder.annotation.MediumTest;
    +-
    +-import com.android.frameworks.servicestests.R;
    +-
    +-import java.io.ByteArrayInputStream;
    +-import java.io.ByteArrayOutputStream;
    +-import java.io.DataOutputStream;
    +-import java.io.File;
    +-import java.io.FileOutputStream;
    +-import java.io.InputStream;
    +-import java.io.OutputStream;
    +-
    +-import libcore.io.IoUtils;
    +-import libcore.io.Streams;
    +-
    +-/**
    +- * Tests for {@link NetworkStatsCollection}.
    +- */
    +-@MediumTest
    +-public class NetworkStatsCollectionTest extends AndroidTestCase {
    +-
    +-    private static final String TEST_FILE = "test.bin";
    +-    private static final String TEST_IMSI = "310260000000000";
    +-
    +-    @Override
    +-    public void setUp() throws Exception {
    +-        super.setUp();
    +-
    +-        // ignore any device overlay while testing
    +-        NetworkTemplate.forceAllNetworkTypes();
    +-    }
    +-
    +-    public void testReadLegacyNetwork() throws Exception {
    +-        final File testFile = new File(getContext().getFilesDir(), TEST_FILE);
    +-        stageFile(R.raw.netstats_v1, testFile);
    +-
    +-        final NetworkStatsCollection collection = new NetworkStatsCollection(30 * MINUTE_IN_MILLIS);
    +-        collection.readLegacyNetwork(testFile);
    +-
    +-        // verify that history read correctly
    +-        assertSummaryTotal(collection, buildTemplateMobileAll(TEST_IMSI),
    +-                636016770L, 709306L, 88038768L, 518836L, NetworkStatsAccess.Level.DEVICE);
    +-
    +-        // now export into a unified format
    +-        final ByteArrayOutputStream bos = new ByteArrayOutputStream();
    +-        collection.write(new DataOutputStream(bos));
    +-
    +-        // clear structure completely
    +-        collection.reset();
    +-        assertSummaryTotal(collection, buildTemplateMobileAll(TEST_IMSI),
    +-                0L, 0L, 0L, 0L, NetworkStatsAccess.Level.DEVICE);
    +-
    +-        // and read back into structure, verifying that totals are same
    +-        collection.read(new ByteArrayInputStream(bos.toByteArray()));
    +-        assertSummaryTotal(collection, buildTemplateMobileAll(TEST_IMSI),
    +-                636016770L, 709306L, 88038768L, 518836L, NetworkStatsAccess.Level.DEVICE);
    +-    }
    +-
    +-    public void testReadLegacyUid() throws Exception {
    +-        final File testFile = new File(getContext().getFilesDir(), TEST_FILE);
    +-        stageFile(R.raw.netstats_uid_v4, testFile);
    +-
    +-        final NetworkStatsCollection collection = new NetworkStatsCollection(30 * MINUTE_IN_MILLIS);
    +-        collection.readLegacyUid(testFile, false);
    +-
    +-        // verify that history read correctly
    +-        assertSummaryTotal(collection, buildTemplateMobileAll(TEST_IMSI),
    +-                637076152L, 711413L, 88343717L, 521022L, NetworkStatsAccess.Level.DEVICE);
    +-
    +-        // now export into a unified format
    +-        final ByteArrayOutputStream bos = new ByteArrayOutputStream();
    +-        collection.write(new DataOutputStream(bos));
    +-
    +-        // clear structure completely
    +-        collection.reset();
    +-        assertSummaryTotal(collection, buildTemplateMobileAll(TEST_IMSI),
    +-                0L, 0L, 0L, 0L, NetworkStatsAccess.Level.DEVICE);
    +-
    +-        // and read back into structure, verifying that totals are same
    +-        collection.read(new ByteArrayInputStream(bos.toByteArray()));
    +-        assertSummaryTotal(collection, buildTemplateMobileAll(TEST_IMSI),
    +-                637076152L, 711413L, 88343717L, 521022L, NetworkStatsAccess.Level.DEVICE);
    +-    }
    +-
    +-    public void testReadLegacyUidTags() throws Exception {
    +-        final File testFile = new File(getContext().getFilesDir(), TEST_FILE);
    +-        stageFile(R.raw.netstats_uid_v4, testFile);
    +-
    +-        final NetworkStatsCollection collection = new NetworkStatsCollection(30 * MINUTE_IN_MILLIS);
    +-        collection.readLegacyUid(testFile, true);
    +-
    +-        // verify that history read correctly
    +-        assertSummaryTotalIncludingTags(collection, buildTemplateMobileAll(TEST_IMSI),
    +-                77017831L, 100995L, 35436758L, 92344L);
    +-
    +-        // now export into a unified format
    +-        final ByteArrayOutputStream bos = new ByteArrayOutputStream();
    +-        collection.write(new DataOutputStream(bos));
    +-
    +-        // clear structure completely
    +-        collection.reset();
    +-        assertSummaryTotalIncludingTags(collection, buildTemplateMobileAll(TEST_IMSI),
    +-                0L, 0L, 0L, 0L);
    +-
    +-        // and read back into structure, verifying that totals are same
    +-        collection.read(new ByteArrayInputStream(bos.toByteArray()));
    +-        assertSummaryTotalIncludingTags(collection, buildTemplateMobileAll(TEST_IMSI),
    +-                77017831L, 100995L, 35436758L, 92344L);
    +-    }
    +-
    +-    public void testStartEndAtomicBuckets() throws Exception {
    +-        final NetworkStatsCollection collection = new NetworkStatsCollection(HOUR_IN_MILLIS);
    +-
    +-        // record empty data straddling between buckets
    +-        final NetworkStats.Entry entry = new NetworkStats.Entry();
    +-        entry.rxBytes = 32;
    +-        collection.recordData(null, UID_ALL, SET_DEFAULT, TAG_NONE, 30 * MINUTE_IN_MILLIS,
    +-                90 * MINUTE_IN_MILLIS, entry);
    +-
    +-        // assert that we report boundary in atomic buckets
    +-        assertEquals(0, collection.getStartMillis());
    +-        assertEquals(2 * HOUR_IN_MILLIS, collection.getEndMillis());
    +-    }
    +-
    +-    public void testAccessLevels() throws Exception {
    +-        final NetworkStatsCollection collection = new NetworkStatsCollection(HOUR_IN_MILLIS);
    +-        final NetworkStats.Entry entry = new NetworkStats.Entry();
    +-        final NetworkIdentitySet identSet = new NetworkIdentitySet();
    +-        identSet.add(new NetworkIdentity(TYPE_MOBILE, TelephonyManager.NETWORK_TYPE_UNKNOWN,
    +-                TEST_IMSI, null, false, true));
    +-
    +-        int myUid = Process.myUid();
    +-        int otherUidInSameUser = Process.myUid() + 1;
    +-        int uidInDifferentUser = Process.myUid() + UserHandle.PER_USER_RANGE;
    +-
    +-        // Record one entry for the current UID.
    +-        entry.rxBytes = 32;
    +-        collection.recordData(identSet, myUid, SET_DEFAULT, TAG_NONE, 0, 60 * MINUTE_IN_MILLIS,
    +-                entry);
    +-
    +-        // Record one entry for another UID in this user.
    +-        entry.rxBytes = 64;
    +-        collection.recordData(identSet, otherUidInSameUser, SET_DEFAULT, TAG_NONE, 0,
    +-                60 * MINUTE_IN_MILLIS, entry);
    +-
    +-        // Record one entry for the system UID.
    +-        entry.rxBytes = 128;
    +-        collection.recordData(identSet, Process.SYSTEM_UID, SET_DEFAULT, TAG_NONE, 0,
    +-                60 * MINUTE_IN_MILLIS, entry);
    +-
    +-        // Record one entry for a UID in a different user.
    +-        entry.rxBytes = 256;
    +-        collection.recordData(identSet, uidInDifferentUser, SET_DEFAULT, TAG_NONE, 0,
    +-                60 * MINUTE_IN_MILLIS, entry);
    +-
    +-        // Verify the set of relevant UIDs for each access level.
    +-        MoreAsserts.assertEquals(new int[] { myUid },
    +-                collection.getRelevantUids(NetworkStatsAccess.Level.DEFAULT));
    +-        MoreAsserts.assertEquals(new int[] { Process.SYSTEM_UID, myUid, otherUidInSameUser },
    +-                collection.getRelevantUids(NetworkStatsAccess.Level.USER));
    +-        MoreAsserts.assertEquals(
    +-                new int[] { Process.SYSTEM_UID, myUid, otherUidInSameUser, uidInDifferentUser },
    +-                collection.getRelevantUids(NetworkStatsAccess.Level.DEVICE));
    +-
    +-        // Verify security check in getHistory.
    +-        assertNotNull(collection.getHistory(buildTemplateMobileAll(TEST_IMSI), myUid, SET_DEFAULT,
    +-                TAG_NONE, 0, NetworkStatsAccess.Level.DEFAULT));
    +-        try {
    +-            collection.getHistory(buildTemplateMobileAll(TEST_IMSI), otherUidInSameUser,
    +-                    SET_DEFAULT, TAG_NONE, 0, NetworkStatsAccess.Level.DEFAULT);
    +-            fail("Should have thrown SecurityException for accessing different UID");
    +-        } catch (SecurityException e) {
    +-            // expected
    +-        }
    +-
    +-        // Verify appropriate aggregation in getSummary.
    +-        assertSummaryTotal(collection, buildTemplateMobileAll(TEST_IMSI), 32, 0, 0, 0,
    +-                NetworkStatsAccess.Level.DEFAULT);
    +-        assertSummaryTotal(collection, buildTemplateMobileAll(TEST_IMSI), 32 + 64 + 128, 0, 0, 0,
    +-                NetworkStatsAccess.Level.USER);
    +-        assertSummaryTotal(collection, buildTemplateMobileAll(TEST_IMSI), 32 + 64 + 128 + 256, 0, 0,
    +-                0, NetworkStatsAccess.Level.DEVICE);
    +-    }
    +-
    +-    /**
    +-     * Copy a {@link Resources#openRawResource(int)} into {@link File} for
    +-     * testing purposes.
    +-     */
    +-    private void stageFile(int rawId, File file) throws Exception {
    +-        new File(file.getParent()).mkdirs();
    +-        InputStream in = null;
    +-        OutputStream out = null;
    +-        try {
    +-            in = getContext().getResources().openRawResource(rawId);
    +-            out = new FileOutputStream(file);
    +-            Streams.copy(in, out);
    +-        } finally {
    +-            IoUtils.closeQuietly(in);
    +-            IoUtils.closeQuietly(out);
    +-        }
    +-    }
    +-
    +-    private static void assertSummaryTotal(NetworkStatsCollection collection,
    +-            NetworkTemplate template, long rxBytes, long rxPackets, long txBytes, long txPackets,
    +-            @NetworkStatsAccess.Level int accessLevel) {
    +-        final NetworkStats.Entry entry = collection.getSummary(
    +-                template, Long.MIN_VALUE, Long.MAX_VALUE, accessLevel)
    +-                .getTotal(null);
    +-        assertEntry(entry, rxBytes, rxPackets, txBytes, txPackets);
    +-    }
    +-
    +-    private static void assertSummaryTotalIncludingTags(NetworkStatsCollection collection,
    +-            NetworkTemplate template, long rxBytes, long rxPackets, long txBytes, long txPackets) {
    +-        final NetworkStats.Entry entry = collection.getSummary(
    +-                template, Long.MIN_VALUE, Long.MAX_VALUE, NetworkStatsAccess.Level.DEVICE)
    +-                .getTotalIncludingTags(null);
    +-        assertEntry(entry, rxBytes, rxPackets, txBytes, txPackets);
    +-    }
    +-
    +-    private static void assertEntry(
    +-            NetworkStats.Entry entry, long rxBytes, long rxPackets, long txBytes, long txPackets) {
    +-        assertEquals("unexpected rxBytes", rxBytes, entry.rxBytes);
    +-        assertEquals("unexpected rxPackets", rxPackets, entry.rxPackets);
    +-        assertEquals("unexpected txBytes", txBytes, entry.txBytes);
    +-        assertEquals("unexpected txPackets", txPackets, entry.txPackets);
    +-    }
    +-}
    +diff --git a/services/tests/servicestests/src/com/android/server/net/NetworkStatsObserversTest.java b/services/tests/servicestests/src/com/android/server/net/NetworkStatsObserversTest.java
    +deleted file mode 100644
    +index 21560ac..0000000
    +--- a/services/tests/servicestests/src/com/android/server/net/NetworkStatsObserversTest.java
    ++++ /dev/null
    +@@ -1,477 +0,0 @@
    +-/*
    +- * Copyright (C) 2016 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 com.android.server.net;
    +-
    +-import static android.net.ConnectivityManager.TYPE_MOBILE;
    +-import static android.net.ConnectivityManager.TYPE_WIFI;
    +-import static android.text.format.DateUtils.MINUTE_IN_MILLIS;
    +-import static org.mockito.Matchers.any;
    +-import static org.mockito.Matchers.anyInt;
    +-import static org.mockito.Matchers.isA;
    +-import static org.mockito.Mockito.when;
    +-
    +-import static android.net.NetworkStats.SET_DEFAULT;
    +-import static android.net.NetworkStats.ROAMING_NO;
    +-import static android.net.NetworkStats.TAG_NONE;
    +-import static android.net.NetworkTemplate.buildTemplateMobileAll;
    +-import static android.net.NetworkTemplate.buildTemplateWifiWildcard;
    +-import static android.net.TrafficStats.MB_IN_BYTES;
    +-import static android.text.format.DateUtils.MINUTE_IN_MILLIS;
    +-
    +-import android.app.usage.NetworkStatsManager;
    +-import android.net.DataUsageRequest;
    +-import android.net.NetworkIdentity;
    +-import android.net.NetworkStats;
    +-import android.net.NetworkTemplate;
    +-import android.os.Handler;
    +-import android.os.HandlerThread;
    +-import android.os.IBinder;
    +-import android.os.Process;
    +-
    +-import android.os.ConditionVariable;
    +-import android.os.Looper;
    +-import android.os.Messenger;
    +-import android.os.Message;
    +-import android.os.UserHandle;
    +-import android.telephony.TelephonyManager;
    +-import android.util.ArrayMap;
    +-
    +-import com.android.internal.net.VpnInfo;
    +-import com.android.server.net.NetworkStatsService;
    +-import com.android.server.net.NetworkStatsServiceTest.IdleableHandlerThread;
    +-import com.android.server.net.NetworkStatsServiceTest.LatchedHandler;
    +-
    +-import java.util.ArrayList;
    +-import java.util.Objects;
    +-import java.util.List;
    +-
    +-import junit.framework.TestCase;
    +-
    +-import org.mockito.Mock;
    +-import org.mockito.Mockito;
    +-import org.mockito.MockitoAnnotations;
    +-
    +-/**
    +- * Tests for {@link NetworkStatsObservers}.
    +- */
    +-public class NetworkStatsObserversTest extends TestCase {
    +-    private static final String TEST_IFACE = "test0";
    +-    private static final String TEST_IFACE2 = "test1";
    +-    private static final long TEST_START = 1194220800000L;
    +-
    +-    private static final String IMSI_1 = "310004";
    +-    private static final String IMSI_2 = "310260";
    +-    private static final String TEST_SSID = "AndroidAP";
    +-
    +-    private static NetworkTemplate sTemplateWifi = buildTemplateWifiWildcard();
    +-    private static NetworkTemplate sTemplateImsi1 = buildTemplateMobileAll(IMSI_1);
    +-    private static NetworkTemplate sTemplateImsi2 = buildTemplateMobileAll(IMSI_2);
    +-
    +-    private static final int UID_RED = UserHandle.PER_USER_RANGE + 1;
    +-    private static final int UID_BLUE = UserHandle.PER_USER_RANGE + 2;
    +-    private static final int UID_GREEN = UserHandle.PER_USER_RANGE + 3;
    +-    private static final int UID_ANOTHER_USER = 2 * UserHandle.PER_USER_RANGE + 4;
    +-
    +-    private static final long WAIT_TIMEOUT = 500;  // 1/2 sec
    +-    private static final long THRESHOLD_BYTES = 2 * MB_IN_BYTES;
    +-    private static final long BASE_BYTES = 7 * MB_IN_BYTES;
    +-    private static final int INVALID_TYPE = -1;
    +-
    +-    private static final VpnInfo[] VPN_INFO = new VpnInfo[0];
    +-
    +-    private long mElapsedRealtime;
    +-
    +-    private IdleableHandlerThread mObserverHandlerThread;
    +-    private Handler mObserverNoopHandler;
    +-
    +-    private LatchedHandler mHandler;
    +-    private ConditionVariable mCv;
    +-
    +-    private NetworkStatsObservers mStatsObservers;
    +-    private Messenger mMessenger;
    +-    private ArrayMap<String, NetworkIdentitySet> mActiveIfaces;
    +-    private ArrayMap<String, NetworkIdentitySet> mActiveUidIfaces;
    +-
    +-    @Mock private IBinder mockBinder;
    +-
    +-    @Override
    +-    public void setUp() throws Exception {
    +-        super.setUp();
    +-        MockitoAnnotations.initMocks(this);
    +-
    +-        mObserverHandlerThread = new IdleableHandlerThread("HandlerThread");
    +-        mObserverHandlerThread.start();
    +-        final Looper observerLooper = mObserverHandlerThread.getLooper();
    +-        mStatsObservers = new NetworkStatsObservers() {
    +-            @Override
    +-            protected Looper getHandlerLooperLocked() {
    +-                return observerLooper;
    +-            }
    +-        };
    +-
    +-        mCv = new ConditionVariable();
    +-        mHandler = new LatchedHandler(Looper.getMainLooper(), mCv);
    +-        mMessenger = new Messenger(mHandler);
    +-
    +-        mActiveIfaces = new ArrayMap<>();
    +-        mActiveUidIfaces = new ArrayMap<>();
    +-    }
    +-
    +-    public void testRegister_thresholdTooLow_setsDefaultThreshold() throws Exception {
    +-        long thresholdTooLowBytes = 1L;
    +-        DataUsageRequest inputRequest = new DataUsageRequest(
    +-                DataUsageRequest.REQUEST_ID_UNSET, sTemplateWifi, thresholdTooLowBytes);
    +-
    +-        DataUsageRequest request = mStatsObservers.register(inputRequest, mMessenger, mockBinder,
    +-                Process.SYSTEM_UID, NetworkStatsAccess.Level.DEVICE);
    +-        assertTrue(request.requestId > 0);
    +-        assertTrue(Objects.equals(sTemplateWifi, request.template));
    +-        assertEquals(THRESHOLD_BYTES, request.thresholdInBytes);
    +-    }
    +-
    +-    public void testRegister_highThreshold_accepted() throws Exception {
    +-        long highThresholdBytes = 2 * THRESHOLD_BYTES;
    +-        DataUsageRequest inputRequest = new DataUsageRequest(
    +-                DataUsageRequest.REQUEST_ID_UNSET, sTemplateWifi, highThresholdBytes);
    +-
    +-        DataUsageRequest request = mStatsObservers.register(inputRequest, mMessenger, mockBinder,
    +-                Process.SYSTEM_UID, NetworkStatsAccess.Level.DEVICE);
    +-        assertTrue(request.requestId > 0);
    +-        assertTrue(Objects.equals(sTemplateWifi, request.template));
    +-        assertEquals(highThresholdBytes, request.thresholdInBytes);
    +-    }
    +-
    +-    public void testRegister_twoRequests_twoIds() throws Exception {
    +-        DataUsageRequest inputRequest = new DataUsageRequest(
    +-                DataUsageRequest.REQUEST_ID_UNSET, sTemplateWifi, THRESHOLD_BYTES);
    +-
    +-        DataUsageRequest request1 = mStatsObservers.register(inputRequest, mMessenger, mockBinder,
    +-                Process.SYSTEM_UID, NetworkStatsAccess.Level.DEVICE);
    +-        assertTrue(request1.requestId > 0);
    +-        assertTrue(Objects.equals(sTemplateWifi, request1.template));
    +-        assertEquals(THRESHOLD_BYTES, request1.thresholdInBytes);
    +-
    +-        DataUsageRequest request2 = mStatsObservers.register(inputRequest, mMessenger, mockBinder,
    +-                Process.SYSTEM_UID, NetworkStatsAccess.Level.DEVICE);
    +-        assertTrue(request2.requestId > request1.requestId);
    +-        assertTrue(Objects.equals(sTemplateWifi, request2.template));
    +-        assertEquals(THRESHOLD_BYTES, request2.thresholdInBytes);
    +-    }
    +-
    +-    public void testUnregister_unknownRequest_noop() throws Exception {
    +-        DataUsageRequest unknownRequest = new DataUsageRequest(
    +-                123456 /* id */, sTemplateWifi, THRESHOLD_BYTES);
    +-
    +-        mStatsObservers.unregister(unknownRequest, UID_RED);
    +-    }
    +-
    +-    public void testUnregister_knownRequest_releasesCaller() throws Exception {
    +-        DataUsageRequest inputRequest = new DataUsageRequest(
    +-                DataUsageRequest.REQUEST_ID_UNSET, sTemplateImsi1, THRESHOLD_BYTES);
    +-
    +-        DataUsageRequest request = mStatsObservers.register(inputRequest, mMessenger, mockBinder,
    +-                Process.SYSTEM_UID, NetworkStatsAccess.Level.DEVICE);
    +-        assertTrue(request.requestId > 0);
    +-        assertTrue(Objects.equals(sTemplateImsi1, request.template));
    +-        assertEquals(THRESHOLD_BYTES, request.thresholdInBytes);
    +-        Mockito.verify(mockBinder).linkToDeath(any(IBinder.DeathRecipient.class), anyInt());
    +-
    +-        mStatsObservers.unregister(request, Process.SYSTEM_UID);
    +-        waitForObserverToIdle();
    +-
    +-        Mockito.verify(mockBinder).unlinkToDeath(any(IBinder.DeathRecipient.class), anyInt());
    +-    }
    +-
    +-    public void testUnregister_knownRequest_invalidUid_doesNotUnregister() throws Exception {
    +-        DataUsageRequest inputRequest = new DataUsageRequest(
    +-                DataUsageRequest.REQUEST_ID_UNSET, sTemplateImsi1, THRESHOLD_BYTES);
    +-
    +-        DataUsageRequest request = mStatsObservers.register(inputRequest, mMessenger, mockBinder,
    +-                UID_RED, NetworkStatsAccess.Level.DEVICE);
    +-        assertTrue(request.requestId > 0);
    +-        assertTrue(Objects.equals(sTemplateImsi1, request.template));
    +-        assertEquals(THRESHOLD_BYTES, request.thresholdInBytes);
    +-        Mockito.verify(mockBinder).linkToDeath(any(IBinder.DeathRecipient.class), anyInt());
    +-
    +-        mStatsObservers.unregister(request, UID_BLUE);
    +-        waitForObserverToIdle();
    +-
    +-        Mockito.verifyZeroInteractions(mockBinder);
    +-    }
    +-
    +-    public void testUpdateStats_initialSample_doesNotNotify() throws Exception {
    +-        DataUsageRequest inputRequest = new DataUsageRequest(
    +-                DataUsageRequest.REQUEST_ID_UNSET, sTemplateImsi1, THRESHOLD_BYTES);
    +-
    +-        DataUsageRequest request = mStatsObservers.register(inputRequest, mMessenger, mockBinder,
    +-                Process.SYSTEM_UID, NetworkStatsAccess.Level.DEVICE);
    +-        assertTrue(request.requestId > 0);
    +-        assertTrue(Objects.equals(sTemplateImsi1, request.template));
    +-        assertEquals(THRESHOLD_BYTES, request.thresholdInBytes);
    +-
    +-        NetworkIdentitySet identSet = new NetworkIdentitySet();
    +-        identSet.add(new NetworkIdentity(
    +-                TYPE_MOBILE, TelephonyManager.NETWORK_TYPE_UNKNOWN,
    +-                IMSI_1, null /* networkId */, false /* roaming */, true /* metered */));
    +-        mActiveIfaces.put(TEST_IFACE, identSet);
    +-
    +-        // Baseline
    +-        NetworkStats xtSnapshot = new NetworkStats(TEST_START, 1 /* initialSize */)
    +-                .addIfaceValues(TEST_IFACE, BASE_BYTES, 8L, BASE_BYTES, 16L);
    +-        NetworkStats uidSnapshot = null;
    +-
    +-        mStatsObservers.updateStats(
    +-                xtSnapshot, uidSnapshot, mActiveIfaces, mActiveUidIfaces,
    +-                VPN_INFO, TEST_START);
    +-        waitForObserverToIdle();
    +-
    +-        assertTrue(mCv.block(WAIT_TIMEOUT));
    +-        assertEquals(INVALID_TYPE, mHandler.mLastMessageType);
    +-    }
    +-
    +-    public void testUpdateStats_belowThreshold_doesNotNotify() throws Exception {
    +-        DataUsageRequest inputRequest = new DataUsageRequest(
    +-                DataUsageRequest.REQUEST_ID_UNSET, sTemplateImsi1, THRESHOLD_BYTES);
    +-
    +-        DataUsageRequest request = mStatsObservers.register(inputRequest, mMessenger, mockBinder,
    +-                Process.SYSTEM_UID, NetworkStatsAccess.Level.DEVICE);
    +-        assertTrue(request.requestId > 0);
    +-        assertTrue(Objects.equals(sTemplateImsi1, request.template));
    +-        assertEquals(THRESHOLD_BYTES, request.thresholdInBytes);
    +-
    +-        NetworkIdentitySet identSet = new NetworkIdentitySet();
    +-        identSet.add(new NetworkIdentity(
    +-                TYPE_MOBILE, TelephonyManager.NETWORK_TYPE_UNKNOWN,
    +-                IMSI_1, null /* networkId */, false /* roaming */, true /* metered */));
    +-        mActiveIfaces.put(TEST_IFACE, identSet);
    +-
    +-        // Baseline
    +-        NetworkStats xtSnapshot = new NetworkStats(TEST_START, 1 /* initialSize */)
    +-                .addIfaceValues(TEST_IFACE, BASE_BYTES, 8L, BASE_BYTES, 16L);
    +-        NetworkStats uidSnapshot = null;
    +-        mStatsObservers.updateStats(
    +-                xtSnapshot, uidSnapshot, mActiveIfaces, mActiveUidIfaces,
    +-                VPN_INFO, TEST_START);
    +-
    +-        // Delta
    +-        xtSnapshot = new NetworkStats(TEST_START, 1 /* initialSize */)
    +-                .addIfaceValues(TEST_IFACE, BASE_BYTES + 1024L, 10L, BASE_BYTES + 2048L, 20L);
    +-        mStatsObservers.updateStats(
    +-                xtSnapshot, uidSnapshot, mActiveIfaces, mActiveUidIfaces,
    +-                VPN_INFO, TEST_START);
    +-        waitForObserverToIdle();
    +-
    +-        assertTrue(mCv.block(WAIT_TIMEOUT));
    +-        mCv.block(WAIT_TIMEOUT);
    +-        assertEquals(INVALID_TYPE, mHandler.mLastMessageType);
    +-    }
    +-
    +-    public void testUpdateStats_deviceAccess_notifies() throws Exception {
    +-        DataUsageRequest inputRequest = new DataUsageRequest(
    +-                DataUsageRequest.REQUEST_ID_UNSET, sTemplateImsi1, THRESHOLD_BYTES);
    +-
    +-        DataUsageRequest request = mStatsObservers.register(inputRequest, mMessenger, mockBinder,
    +-                Process.SYSTEM_UID, NetworkStatsAccess.Level.DEVICE);
    +-        assertTrue(request.requestId > 0);
    +-        assertTrue(Objects.equals(sTemplateImsi1, request.template));
    +-        assertEquals(THRESHOLD_BYTES, request.thresholdInBytes);
    +-
    +-        NetworkIdentitySet identSet = new NetworkIdentitySet();
    +-        identSet.add(new NetworkIdentity(
    +-                TYPE_MOBILE, TelephonyManager.NETWORK_TYPE_UNKNOWN,
    +-                IMSI_1, null /* networkId */, false /* roaming */, true /* metered */));
    +-        mActiveIfaces.put(TEST_IFACE, identSet);
    +-
    +-        // Baseline
    +-        NetworkStats xtSnapshot = new NetworkStats(TEST_START, 1 /* initialSize */)
    +-                .addIfaceValues(TEST_IFACE, BASE_BYTES, 8L, BASE_BYTES, 16L);
    +-        NetworkStats uidSnapshot = null;
    +-        mStatsObservers.updateStats(
    +-                xtSnapshot, uidSnapshot, mActiveIfaces, mActiveUidIfaces,
    +-                VPN_INFO, TEST_START);
    +-
    +-        // Delta
    +-        xtSnapshot = new NetworkStats(TEST_START + MINUTE_IN_MILLIS, 1 /* initialSize */)
    +-                .addIfaceValues(TEST_IFACE, BASE_BYTES + THRESHOLD_BYTES, 12L,
    +-                        BASE_BYTES + THRESHOLD_BYTES, 22L);
    +-        mStatsObservers.updateStats(
    +-                xtSnapshot, uidSnapshot, mActiveIfaces, mActiveUidIfaces,
    +-                VPN_INFO, TEST_START);
    +-        waitForObserverToIdle();
    +-
    +-        assertTrue(mCv.block(WAIT_TIMEOUT));
    +-        assertEquals(NetworkStatsManager.CALLBACK_LIMIT_REACHED, mHandler.mLastMessageType);
    +-    }
    +-
    +-    public void testUpdateStats_defaultAccess_notifiesSameUid() throws Exception {
    +-        DataUsageRequest inputRequest = new DataUsageRequest(
    +-                DataUsageRequest.REQUEST_ID_UNSET, sTemplateImsi1, THRESHOLD_BYTES);
    +-
    +-        DataUsageRequest request = mStatsObservers.register(inputRequest, mMessenger, mockBinder,
    +-                UID_RED, NetworkStatsAccess.Level.DEFAULT);
    +-        assertTrue(request.requestId > 0);
    +-        assertTrue(Objects.equals(sTemplateImsi1, request.template));
    +-        assertEquals(THRESHOLD_BYTES, request.thresholdInBytes);
    +-
    +-        NetworkIdentitySet identSet = new NetworkIdentitySet();
    +-        identSet.add(new NetworkIdentity(
    +-                TYPE_MOBILE, TelephonyManager.NETWORK_TYPE_UNKNOWN,
    +-                IMSI_1, null /* networkId */, false /* roaming */, true /* metered */));
    +-        mActiveUidIfaces.put(TEST_IFACE, identSet);
    +-
    +-        // Baseline
    +-        NetworkStats xtSnapshot = null;
    +-        NetworkStats uidSnapshot = new NetworkStats(TEST_START, 2 /* initialSize */)
    +-                .addValues(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, ROAMING_NO,
    +-                        BASE_BYTES, 2L, BASE_BYTES, 2L, 0L);
    +-        mStatsObservers.updateStats(
    +-                xtSnapshot, uidSnapshot, mActiveIfaces, mActiveUidIfaces,
    +-                VPN_INFO, TEST_START);
    +-
    +-        // Delta
    +-        uidSnapshot = new NetworkStats(TEST_START + 2 * MINUTE_IN_MILLIS, 2 /* initialSize */)
    +-                .addValues(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, ROAMING_NO,
    +-                        BASE_BYTES + THRESHOLD_BYTES, 2L, BASE_BYTES + THRESHOLD_BYTES, 2L, 0L);
    +-        mStatsObservers.updateStats(
    +-                xtSnapshot, uidSnapshot, mActiveIfaces, mActiveUidIfaces,
    +-                VPN_INFO, TEST_START);
    +-        waitForObserverToIdle();
    +-
    +-        assertTrue(mCv.block(WAIT_TIMEOUT));
    +-        assertEquals(NetworkStatsManager.CALLBACK_LIMIT_REACHED, mHandler.mLastMessageType);
    +-    }
    +-
    +-    public void testUpdateStats_defaultAccess_usageOtherUid_doesNotNotify() throws Exception {
    +-        DataUsageRequest inputRequest = new DataUsageRequest(
    +-                DataUsageRequest.REQUEST_ID_UNSET, sTemplateImsi1, THRESHOLD_BYTES);
    +-
    +-        DataUsageRequest request = mStatsObservers.register(inputRequest, mMessenger, mockBinder,
    +-                UID_BLUE, NetworkStatsAccess.Level.DEFAULT);
    +-        assertTrue(request.requestId > 0);
    +-        assertTrue(Objects.equals(sTemplateImsi1, request.template));
    +-        assertEquals(THRESHOLD_BYTES, request.thresholdInBytes);
    +-
    +-        NetworkIdentitySet identSet = new NetworkIdentitySet();
    +-        identSet.add(new NetworkIdentity(
    +-                TYPE_MOBILE, TelephonyManager.NETWORK_TYPE_UNKNOWN,
    +-                IMSI_1, null /* networkId */, false /* roaming */, true /* metered */));
    +-        mActiveUidIfaces.put(TEST_IFACE, identSet);
    +-
    +-        // Baseline
    +-        NetworkStats xtSnapshot = null;
    +-        NetworkStats uidSnapshot = new NetworkStats(TEST_START, 2 /* initialSize */)
    +-                .addValues(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, ROAMING_NO,
    +-                        BASE_BYTES, 2L, BASE_BYTES, 2L, 0L);
    +-        mStatsObservers.updateStats(
    +-                xtSnapshot, uidSnapshot, mActiveIfaces, mActiveUidIfaces,
    +-                VPN_INFO, TEST_START);
    +-
    +-        // Delta
    +-        uidSnapshot = new NetworkStats(TEST_START + 2 * MINUTE_IN_MILLIS, 2 /* initialSize */)
    +-                .addValues(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, ROAMING_NO,
    +-                        BASE_BYTES + THRESHOLD_BYTES, 2L, BASE_BYTES + THRESHOLD_BYTES, 2L, 0L);
    +-        mStatsObservers.updateStats(
    +-                xtSnapshot, uidSnapshot, mActiveIfaces, mActiveUidIfaces,
    +-                VPN_INFO, TEST_START);
    +-        waitForObserverToIdle();
    +-
    +-        assertTrue(mCv.block(WAIT_TIMEOUT));
    +-        assertEquals(INVALID_TYPE, mHandler.mLastMessageType);
    +-    }
    +-
    +-    public void testUpdateStats_userAccess_usageSameUser_notifies() throws Exception {
    +-        DataUsageRequest inputRequest = new DataUsageRequest(
    +-                DataUsageRequest.REQUEST_ID_UNSET, sTemplateImsi1, THRESHOLD_BYTES);
    +-
    +-        DataUsageRequest request = mStatsObservers.register(inputRequest, mMessenger, mockBinder,
    +-                UID_BLUE, NetworkStatsAccess.Level.USER);
    +-        assertTrue(request.requestId > 0);
    +-        assertTrue(Objects.equals(sTemplateImsi1, request.template));
    +-        assertEquals(THRESHOLD_BYTES, request.thresholdInBytes);
    +-
    +-        NetworkIdentitySet identSet = new NetworkIdentitySet();
    +-        identSet.add(new NetworkIdentity(
    +-                TYPE_MOBILE, TelephonyManager.NETWORK_TYPE_UNKNOWN,
    +-                IMSI_1, null /* networkId */, false /* roaming */, true /* metered */));
    +-        mActiveUidIfaces.put(TEST_IFACE, identSet);
    +-
    +-        // Baseline
    +-        NetworkStats xtSnapshot = null;
    +-        NetworkStats uidSnapshot = new NetworkStats(TEST_START, 2 /* initialSize */)
    +-                .addValues(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, ROAMING_NO,
    +-                        BASE_BYTES, 2L, BASE_BYTES, 2L, 0L);
    +-        mStatsObservers.updateStats(
    +-                xtSnapshot, uidSnapshot, mActiveIfaces, mActiveUidIfaces,
    +-                VPN_INFO, TEST_START);
    +-
    +-        // Delta
    +-        uidSnapshot = new NetworkStats(TEST_START + 2 * MINUTE_IN_MILLIS, 2 /* initialSize */)
    +-                .addValues(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, ROAMING_NO,
    +-                        BASE_BYTES + THRESHOLD_BYTES, 2L, BASE_BYTES + THRESHOLD_BYTES, 2L, 0L);
    +-        mStatsObservers.updateStats(
    +-                xtSnapshot, uidSnapshot, mActiveIfaces, mActiveUidIfaces,
    +-                VPN_INFO, TEST_START);
    +-        waitForObserverToIdle();
    +-
    +-        assertTrue(mCv.block(WAIT_TIMEOUT));
    +-        assertEquals(NetworkStatsManager.CALLBACK_LIMIT_REACHED, mHandler.mLastMessageType);
    +-    }
    +-
    +-    public void testUpdateStats_userAccess_usageAnotherUser_doesNotNotify() throws Exception {
    +-        DataUsageRequest inputRequest = new DataUsageRequest(
    +-                DataUsageRequest.REQUEST_ID_UNSET, sTemplateImsi1, THRESHOLD_BYTES);
    +-
    +-        DataUsageRequest request = mStatsObservers.register(inputRequest, mMessenger, mockBinder,
    +-                UID_RED, NetworkStatsAccess.Level.USER);
    +-        assertTrue(request.requestId > 0);
    +-        assertTrue(Objects.equals(sTemplateImsi1, request.template));
    +-        assertEquals(THRESHOLD_BYTES, request.thresholdInBytes);
    +-
    +-        NetworkIdentitySet identSet = new NetworkIdentitySet();
    +-        identSet.add(new NetworkIdentity(
    +-                TYPE_MOBILE, TelephonyManager.NETWORK_TYPE_UNKNOWN,
    +-                IMSI_1, null /* networkId */, false /* roaming */, true /* metered */));
    +-        mActiveUidIfaces.put(TEST_IFACE, identSet);
    +-
    +-        // Baseline
    +-        NetworkStats xtSnapshot = null;
    +-        NetworkStats uidSnapshot = new NetworkStats(TEST_START, 2 /* initialSize */)
    +-                .addValues(TEST_IFACE, UID_ANOTHER_USER, SET_DEFAULT, TAG_NONE, ROAMING_NO,
    +-                        BASE_BYTES, 2L, BASE_BYTES, 2L, 0L);
    +-        mStatsObservers.updateStats(
    +-                xtSnapshot, uidSnapshot, mActiveIfaces, mActiveUidIfaces,
    +-                VPN_INFO, TEST_START);
    +-
    +-        // Delta
    +-        uidSnapshot = new NetworkStats(TEST_START + 2 * MINUTE_IN_MILLIS, 2 /* initialSize */)
    +-                .addValues(TEST_IFACE, UID_ANOTHER_USER, SET_DEFAULT, TAG_NONE, ROAMING_NO,
    +-                        BASE_BYTES + THRESHOLD_BYTES, 2L, BASE_BYTES + THRESHOLD_BYTES, 2L, 0L);
    +-        mStatsObservers.updateStats(
    +-                xtSnapshot, uidSnapshot, mActiveIfaces, mActiveUidIfaces,
    +-                VPN_INFO, TEST_START);
    +-        waitForObserverToIdle();
    +-
    +-        assertTrue(mCv.block(WAIT_TIMEOUT));
    +-        assertEquals(INVALID_TYPE, mHandler.mLastMessageType);
    +-    }
    +-
    +-    private void waitForObserverToIdle() {
    +-        // Send dummy message to make sure that any previous message has been handled
    +-        mHandler.sendMessage(mHandler.obtainMessage(-1));
    +-        mObserverHandlerThread.waitForIdle(WAIT_TIMEOUT);
    +-    }
    +-}
    +diff --git a/services/tests/servicestests/src/com/android/server/net/NetworkStatsServiceTest.java b/services/tests/servicestests/src/com/android/server/net/NetworkStatsServiceTest.java
    +deleted file mode 100644
    +index 94c6711..0000000
    +--- a/services/tests/servicestests/src/com/android/server/net/NetworkStatsServiceTest.java
    ++++ /dev/null
    +@@ -1,1324 +0,0 @@
    +-/*
    +- * Copyright (C) 2011 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 com.android.server.net;
    +-
    +-import static android.content.Intent.ACTION_UID_REMOVED;
    +-import static android.content.Intent.EXTRA_UID;
    +-import static android.net.ConnectivityManager.TYPE_MOBILE;
    +-import static android.net.ConnectivityManager.TYPE_WIFI;
    +-import static android.net.ConnectivityManager.TYPE_WIMAX;
    +-import static android.net.NetworkStats.IFACE_ALL;
    +-import static android.net.NetworkStats.ROAMING_ALL;
    +-import static android.net.NetworkStats.ROAMING_NO;
    +-import static android.net.NetworkStats.ROAMING_YES;
    +-import static android.net.NetworkStats.SET_ALL;
    +-import static android.net.NetworkStats.SET_DEFAULT;
    +-import static android.net.NetworkStats.SET_FOREGROUND;
    +-import static android.net.NetworkStats.TAG_NONE;
    +-import static android.net.NetworkStats.UID_ALL;
    +-import static android.net.NetworkStatsHistory.FIELD_ALL;
    +-import static android.net.NetworkTemplate.buildTemplateMobileAll;
    +-import static android.net.NetworkTemplate.buildTemplateWifiWildcard;
    +-import static android.net.TrafficStats.MB_IN_BYTES;
    +-import static android.net.TrafficStats.UID_REMOVED;
    +-import static android.net.TrafficStats.UID_TETHERING;
    +-import static android.text.format.DateUtils.DAY_IN_MILLIS;
    +-import static android.text.format.DateUtils.HOUR_IN_MILLIS;
    +-import static android.text.format.DateUtils.MINUTE_IN_MILLIS;
    +-import static android.text.format.DateUtils.WEEK_IN_MILLIS;
    +-import static com.android.server.net.NetworkStatsService.ACTION_NETWORK_STATS_POLL;
    +-import static org.easymock.EasyMock.anyInt;
    +-import static org.easymock.EasyMock.anyLong;
    +-import static org.easymock.EasyMock.anyObject;
    +-import static org.easymock.EasyMock.capture;
    +-import static org.easymock.EasyMock.createMock;
    +-import static org.easymock.EasyMock.eq;
    +-import static org.easymock.EasyMock.expect;
    +-import static org.easymock.EasyMock.expectLastCall;
    +-import static org.easymock.EasyMock.isA;
    +-
    +-import android.app.AlarmManager;
    +-import android.app.IAlarmListener;
    +-import android.app.IAlarmManager;
    +-import android.app.PendingIntent;
    +-import android.app.usage.NetworkStatsManager;
    +-import android.content.Context;
    +-import android.content.Intent;
    +-import android.net.DataUsageRequest;
    +-import android.net.IConnectivityManager;
    +-import android.net.INetworkManagementEventObserver;
    +-import android.net.INetworkStatsSession;
    +-import android.net.LinkProperties;
    +-import android.net.NetworkInfo;
    +-import android.net.NetworkInfo.DetailedState;
    +-import android.net.NetworkState;
    +-import android.net.NetworkStats;
    +-import android.net.NetworkStatsHistory;
    +-import android.net.NetworkTemplate;
    +-import android.os.ConditionVariable;
    +-import android.os.Handler;
    +-import android.os.HandlerThread;
    +-import android.os.INetworkManagementService;
    +-import android.os.IBinder;
    +-import android.os.Looper;
    +-import android.os.Messenger;
    +-import android.os.MessageQueue;
    +-import android.os.MessageQueue.IdleHandler;
    +-import android.os.Message;
    +-import android.os.PowerManager;
    +-import android.os.WorkSource;
    +-import android.telephony.TelephonyManager;
    +-import android.test.AndroidTestCase;
    +-import android.test.suitebuilder.annotation.LargeTest;
    +-import android.test.suitebuilder.annotation.Suppress;
    +-import android.util.TrustedTime;
    +-
    +-import com.android.internal.net.VpnInfo;
    +-import com.android.server.BroadcastInterceptingContext;
    +-import com.android.server.net.NetworkStatsService;
    +-import com.android.server.net.NetworkStatsService.NetworkStatsSettings;
    +-import com.android.server.net.NetworkStatsService.NetworkStatsSettings.Config;
    +-
    +-import libcore.io.IoUtils;
    +-
    +-import org.easymock.Capture;
    +-import org.easymock.EasyMock;
    +-
    +-import java.io.File;
    +-import java.util.ArrayList;
    +-import java.util.Objects;
    +-import java.util.List;
    +-
    +-/**
    +- * Tests for {@link NetworkStatsService}.
    +- *
    +- * TODO: This test is really brittle, largely due to overly-strict use of Easymock.
    +- * Rewrite w/ Mockito.
    +- */
    +-@LargeTest
    +-public class NetworkStatsServiceTest extends AndroidTestCase {
    +-    private static final String TAG = "NetworkStatsServiceTest";
    +-
    +-    private static final String TEST_IFACE = "test0";
    +-    private static final String TEST_IFACE2 = "test1";
    +-    private static final long TEST_START = 1194220800000L;
    +-
    +-    private static final String IMSI_1 = "310004";
    +-    private static final String IMSI_2 = "310260";
    +-    private static final String TEST_SSID = "AndroidAP";
    +-
    +-    private static NetworkTemplate sTemplateWifi = buildTemplateWifiWildcard();
    +-    private static NetworkTemplate sTemplateImsi1 = buildTemplateMobileAll(IMSI_1);
    +-    private static NetworkTemplate sTemplateImsi2 = buildTemplateMobileAll(IMSI_2);
    +-
    +-    private static final int UID_RED = 1001;
    +-    private static final int UID_BLUE = 1002;
    +-    private static final int UID_GREEN = 1003;
    +-
    +-    private static final long WAIT_TIMEOUT = 2 * 1000;  // 2 secs
    +-    private static final int INVALID_TYPE = -1;
    +-
    +-    private long mElapsedRealtime;
    +-
    +-    private BroadcastInterceptingContext mServiceContext;
    +-    private File mStatsDir;
    +-
    +-    private INetworkManagementService mNetManager;
    +-    private TrustedTime mTime;
    +-    private NetworkStatsSettings mSettings;
    +-    private IConnectivityManager mConnManager;
    +-    private IdleableHandlerThread mHandlerThread;
    +-    private Handler mHandler;
    +-
    +-    private NetworkStatsService mService;
    +-    private INetworkStatsSession mSession;
    +-    private INetworkManagementEventObserver mNetworkObserver;
    +-
    +-    @Override
    +-    public void setUp() throws Exception {
    +-        super.setUp();
    +-
    +-        mServiceContext = new BroadcastInterceptingContext(getContext());
    +-        mStatsDir = getContext().getFilesDir();
    +-        if (mStatsDir.exists()) {
    +-            IoUtils.deleteContents(mStatsDir);
    +-        }
    +-
    +-        mNetManager = createMock(INetworkManagementService.class);
    +-
    +-        // TODO: Mock AlarmManager when migrating this test to Mockito.
    +-        AlarmManager alarmManager = (AlarmManager) mServiceContext
    +-                .getSystemService(Context.ALARM_SERVICE);
    +-        mTime = createMock(TrustedTime.class);
    +-        mSettings = createMock(NetworkStatsSettings.class);
    +-        mConnManager = createMock(IConnectivityManager.class);
    +-
    +-        PowerManager powerManager = (PowerManager) mServiceContext.getSystemService(
    +-                Context.POWER_SERVICE);
    +-        PowerManager.WakeLock wakeLock =
    +-                powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, TAG);
    +-
    +-        mService = new NetworkStatsService(
    +-                mServiceContext, mNetManager, alarmManager, wakeLock, mTime,
    +-                TelephonyManager.getDefault(), mSettings, new NetworkStatsObservers(),
    +-                mStatsDir, getBaseDir(mStatsDir));
    +-        mHandlerThread = new IdleableHandlerThread("HandlerThread");
    +-        mHandlerThread.start();
    +-        Handler.Callback callback = new NetworkStatsService.HandlerCallback(mService);
    +-        mHandler = new Handler(mHandlerThread.getLooper(), callback);
    +-        mService.setHandler(mHandler, callback);
    +-        mService.bindConnectivityManager(mConnManager);
    +-
    +-        mElapsedRealtime = 0L;
    +-
    +-        expectCurrentTime();
    +-        expectDefaultSettings();
    +-        expectNetworkStatsUidDetail(buildEmptyStats());
    +-        expectSystemReady();
    +-
    +-        // catch INetworkManagementEventObserver during systemReady()
    +-        final Capture<INetworkManagementEventObserver> networkObserver = new Capture<
    +-                INetworkManagementEventObserver>();
    +-        mNetManager.registerObserver(capture(networkObserver));
    +-        expectLastCall().atLeastOnce();
    +-
    +-        replay();
    +-        mService.systemReady();
    +-        mSession = mService.openSession();
    +-        verifyAndReset();
    +-
    +-        mNetworkObserver = networkObserver.getValue();
    +-
    +-    }
    +-
    +-    @Override
    +-    public void tearDown() throws Exception {
    +-        IoUtils.deleteContents(mStatsDir);
    +-
    +-        mServiceContext = null;
    +-        mStatsDir = null;
    +-
    +-        mNetManager = null;
    +-        mTime = null;
    +-        mSettings = null;
    +-        mConnManager = null;
    +-
    +-        mSession.close();
    +-        mService = null;
    +-
    +-        super.tearDown();
    +-    }
    +-
    +-    public void testNetworkStatsWifi() throws Exception {
    +-        // pretend that wifi network comes online; service should ask about full
    +-        // network state, and poll any existing interfaces before updating.
    +-        expectCurrentTime();
    +-        expectDefaultSettings();
    +-        expectNetworkState(buildWifiState());
    +-        expectNetworkStatsSummary(buildEmptyStats());
    +-        expectNetworkStatsUidDetail(buildEmptyStats());
    +-        expectNetworkStatsPoll();
    +-        expectBandwidthControlCheck();
    +-
    +-        replay();
    +-        mService.forceUpdateIfaces();
    +-
    +-        // verify service has empty history for wifi
    +-        assertNetworkTotal(sTemplateWifi, 0L, 0L, 0L, 0L, 0);
    +-        verifyAndReset();
    +-
    +-        // modify some number on wifi, and trigger poll event
    +-        incrementCurrentTime(HOUR_IN_MILLIS);
    +-        expectCurrentTime();
    +-        expectDefaultSettings();
    +-        expectNetworkStatsSummary(new NetworkStats(getElapsedRealtime(), 1)
    +-                .addIfaceValues(TEST_IFACE, 1024L, 1L, 2048L, 2L));
    +-        expectNetworkStatsUidDetail(buildEmptyStats());
    +-        expectNetworkStatsPoll();
    +-
    +-        replay();
    +-        forcePollAndWaitForIdle();
    +-
    +-        // verify service recorded history
    +-        assertNetworkTotal(sTemplateWifi, 1024L, 1L, 2048L, 2L, 0);
    +-        verifyAndReset();
    +-
    +-        // and bump forward again, with counters going higher. this is
    +-        // important, since polling should correctly subtract last snapshot.
    +-        incrementCurrentTime(DAY_IN_MILLIS);
    +-        expectCurrentTime();
    +-        expectDefaultSettings();
    +-        expectNetworkStatsSummary(new NetworkStats(getElapsedRealtime(), 1)
    +-                .addIfaceValues(TEST_IFACE, 4096L, 4L, 8192L, 8L));
    +-        expectNetworkStatsUidDetail(buildEmptyStats());
    +-        expectNetworkStatsPoll();
    +-
    +-        replay();
    +-        forcePollAndWaitForIdle();
    +-
    +-        // verify service recorded history
    +-        assertNetworkTotal(sTemplateWifi, 4096L, 4L, 8192L, 8L, 0);
    +-        verifyAndReset();
    +-
    +-    }
    +-
    +-    public void testStatsRebootPersist() throws Exception {
    +-        assertStatsFilesExist(false);
    +-
    +-        // pretend that wifi network comes online; service should ask about full
    +-        // network state, and poll any existing interfaces before updating.
    +-        expectCurrentTime();
    +-        expectDefaultSettings();
    +-        expectNetworkState(buildWifiState());
    +-        expectNetworkStatsSummary(buildEmptyStats());
    +-        expectNetworkStatsUidDetail(buildEmptyStats());
    +-        expectNetworkStatsPoll();
    +-        expectBandwidthControlCheck();
    +-
    +-        replay();
    +-        mService.forceUpdateIfaces();
    +-
    +-        // verify service has empty history for wifi
    +-        assertNetworkTotal(sTemplateWifi, 0L, 0L, 0L, 0L, 0);
    +-        verifyAndReset();
    +-
    +-        // modify some number on wifi, and trigger poll event
    +-        incrementCurrentTime(HOUR_IN_MILLIS);
    +-        expectCurrentTime();
    +-        expectDefaultSettings();
    +-        expectNetworkStatsSummary(new NetworkStats(getElapsedRealtime(), 1)
    +-                .addIfaceValues(TEST_IFACE, 1024L, 8L, 2048L, 16L));
    +-        expectNetworkStatsUidDetail(new NetworkStats(getElapsedRealtime(), 2)
    +-                .addValues(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, 512L, 4L, 256L, 2L, 0L)
    +-                .addValues(TEST_IFACE, UID_RED, SET_DEFAULT, 0xFAAD, 256L, 2L, 128L, 1L, 0L)
    +-                .addValues(TEST_IFACE, UID_RED, SET_FOREGROUND, TAG_NONE, 512L, 4L, 256L, 2L, 0L)
    +-                .addValues(TEST_IFACE, UID_RED, SET_FOREGROUND, 0xFAAD, 256L, 2L, 128L, 1L, 0L)
    +-                .addValues(TEST_IFACE, UID_BLUE, SET_DEFAULT, TAG_NONE, 128L, 1L, 128L, 1L, 0L));
    +-        expectNetworkStatsPoll();
    +-
    +-        mService.setUidForeground(UID_RED, false);
    +-        mService.incrementOperationCount(UID_RED, 0xFAAD, 4);
    +-        mService.setUidForeground(UID_RED, true);
    +-        mService.incrementOperationCount(UID_RED, 0xFAAD, 6);
    +-
    +-        replay();
    +-        forcePollAndWaitForIdle();
    +-
    +-        // verify service recorded history
    +-        assertNetworkTotal(sTemplateWifi, 1024L, 8L, 2048L, 16L, 0);
    +-        assertUidTotal(sTemplateWifi, UID_RED, 1024L, 8L, 512L, 4L, 10);
    +-        assertUidTotal(sTemplateWifi, UID_RED, SET_DEFAULT, ROAMING_NO, 512L, 4L, 256L, 2L, 4);
    +-        assertUidTotal(sTemplateWifi, UID_RED, SET_FOREGROUND, ROAMING_NO, 512L, 4L, 256L, 2L,
    +-                6);
    +-        assertUidTotal(sTemplateWifi, UID_BLUE, 128L, 1L, 128L, 1L, 0);
    +-        verifyAndReset();
    +-
    +-        // graceful shutdown system, which should trigger persist of stats, and
    +-        // clear any values in memory.
    +-        expectCurrentTime();
    +-        expectDefaultSettings();
    +-        replay();
    +-        mServiceContext.sendBroadcast(new Intent(Intent.ACTION_SHUTDOWN));
    +-        verifyAndReset();
    +-
    +-        assertStatsFilesExist(true);
    +-
    +-        // boot through serviceReady() again
    +-        expectCurrentTime();
    +-        expectDefaultSettings();
    +-        expectNetworkStatsUidDetail(buildEmptyStats());
    +-        expectSystemReady();
    +-
    +-        // catch INetworkManagementEventObserver during systemReady()
    +-        final Capture<INetworkManagementEventObserver> networkObserver = new Capture<
    +-                INetworkManagementEventObserver>();
    +-        mNetManager.registerObserver(capture(networkObserver));
    +-        expectLastCall().atLeastOnce();
    +-
    +-        replay();
    +-        mService.systemReady();
    +-
    +-        mNetworkObserver = networkObserver.getValue();
    +-
    +-        // after systemReady(), we should have historical stats loaded again
    +-        assertNetworkTotal(sTemplateWifi, 1024L, 8L, 2048L, 16L, 0);
    +-        assertUidTotal(sTemplateWifi, UID_RED, 1024L, 8L, 512L, 4L, 10);
    +-        assertUidTotal(sTemplateWifi, UID_RED, SET_DEFAULT, ROAMING_NO, 512L, 4L, 256L, 2L, 4);
    +-        assertUidTotal(sTemplateWifi, UID_RED, SET_FOREGROUND, ROAMING_NO, 512L, 4L, 256L, 2L,
    +-                6);
    +-        assertUidTotal(sTemplateWifi, UID_BLUE, 128L, 1L, 128L, 1L, 0);
    +-        verifyAndReset();
    +-
    +-    }
    +-
    +-    // TODO: simulate reboot to test bucket resize
    +-    @Suppress
    +-    public void testStatsBucketResize() throws Exception {
    +-        NetworkStatsHistory history = null;
    +-
    +-        assertStatsFilesExist(false);
    +-
    +-        // pretend that wifi network comes online; service should ask about full
    +-        // network state, and poll any existing interfaces before updating.
    +-        expectCurrentTime();
    +-        expectSettings(0L, HOUR_IN_MILLIS, WEEK_IN_MILLIS);
    +-        expectNetworkState(buildWifiState());
    +-        expectNetworkStatsSummary(buildEmptyStats());
    +-        expectNetworkStatsUidDetail(buildEmptyStats());
    +-        expectNetworkStatsPoll();
    +-        expectBandwidthControlCheck();
    +-
    +-        replay();
    +-        mService.forceUpdateIfaces();
    +-        verifyAndReset();
    +-
    +-        // modify some number on wifi, and trigger poll event
    +-        incrementCurrentTime(2 * HOUR_IN_MILLIS);
    +-        expectCurrentTime();
    +-        expectSettings(0L, HOUR_IN_MILLIS, WEEK_IN_MILLIS);
    +-        expectNetworkStatsSummary(new NetworkStats(getElapsedRealtime(), 1)
    +-                .addIfaceValues(TEST_IFACE, 512L, 4L, 512L, 4L));
    +-        expectNetworkStatsUidDetail(buildEmptyStats());
    +-        expectNetworkStatsPoll();
    +-
    +-        replay();
    +-        forcePollAndWaitForIdle();
    +-
    +-        // verify service recorded history
    +-        history = mSession.getHistoryForNetwork(sTemplateWifi, FIELD_ALL);
    +-        assertValues(history, Long.MIN_VALUE, Long.MAX_VALUE, 512L, 4L, 512L, 4L, 0);
    +-        assertEquals(HOUR_IN_MILLIS, history.getBucketDuration());
    +-        assertEquals(2, history.size());
    +-        verifyAndReset();
    +-
    +-        // now change bucket duration setting and trigger another poll with
    +-        // exact same values, which should resize existing buckets.
    +-        expectCurrentTime();
    +-        expectSettings(0L, 30 * MINUTE_IN_MILLIS, WEEK_IN_MILLIS);
    +-        expectNetworkStatsSummary(buildEmptyStats());
    +-        expectNetworkStatsUidDetail(buildEmptyStats());
    +-        expectNetworkStatsPoll();
    +-
    +-        replay();
    +-        forcePollAndWaitForIdle();
    +-
    +-        // verify identical stats, but spread across 4 buckets now
    +-        history = mSession.getHistoryForNetwork(sTemplateWifi, FIELD_ALL);
    +-        assertValues(history, Long.MIN_VALUE, Long.MAX_VALUE, 512L, 4L, 512L, 4L, 0);
    +-        assertEquals(30 * MINUTE_IN_MILLIS, history.getBucketDuration());
    +-        assertEquals(4, history.size());
    +-        verifyAndReset();
    +-
    +-    }
    +-
    +-    public void testUidStatsAcrossNetworks() throws Exception {
    +-        // pretend first mobile network comes online
    +-        expectCurrentTime();
    +-        expectDefaultSettings();
    +-        expectNetworkState(buildMobile3gState(IMSI_1));
    +-        expectNetworkStatsSummary(buildEmptyStats());
    +-        expectNetworkStatsUidDetail(buildEmptyStats());
    +-        expectNetworkStatsPoll();
    +-        expectBandwidthControlCheck();
    +-
    +-        replay();
    +-        mService.forceUpdateIfaces();
    +-        verifyAndReset();
    +-
    +-        // create some traffic on first network
    +-        incrementCurrentTime(HOUR_IN_MILLIS);
    +-        expectCurrentTime();
    +-        expectDefaultSettings();
    +-        expectNetworkStatsSummary(new NetworkStats(getElapsedRealtime(), 1)
    +-                .addIfaceValues(TEST_IFACE, 2048L, 16L, 512L, 4L));
    +-        expectNetworkStatsUidDetail(new NetworkStats(getElapsedRealtime(), 3)
    +-                .addValues(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, 1536L, 12L, 512L, 4L, 0L)
    +-                .addValues(TEST_IFACE, UID_RED, SET_DEFAULT, 0xF00D, 512L, 4L, 512L, 4L, 0L)
    +-                .addValues(TEST_IFACE, UID_BLUE, SET_DEFAULT, TAG_NONE, 512L, 4L, 0L, 0L, 0L));
    +-        expectNetworkStatsPoll();
    +-
    +-        mService.incrementOperationCount(UID_RED, 0xF00D, 10);
    +-
    +-        replay();
    +-        forcePollAndWaitForIdle();
    +-
    +-        // verify service recorded history
    +-        assertNetworkTotal(sTemplateImsi1, 2048L, 16L, 512L, 4L, 0);
    +-        assertNetworkTotal(sTemplateWifi, 0L, 0L, 0L, 0L, 0);
    +-        assertUidTotal(sTemplateImsi1, UID_RED, 1536L, 12L, 512L, 4L, 10);
    +-        assertUidTotal(sTemplateImsi1, UID_BLUE, 512L, 4L, 0L, 0L, 0);
    +-        verifyAndReset();
    +-
    +-        // now switch networks; this also tests that we're okay with interfaces
    +-        // disappearing, to verify we don't count backwards.
    +-        incrementCurrentTime(HOUR_IN_MILLIS);
    +-        expectCurrentTime();
    +-        expectDefaultSettings();
    +-        expectNetworkState(buildMobile3gState(IMSI_2));
    +-        expectNetworkStatsSummary(new NetworkStats(getElapsedRealtime(), 1)
    +-                .addIfaceValues(TEST_IFACE, 2048L, 16L, 512L, 4L));
    +-        expectNetworkStatsUidDetail(new NetworkStats(getElapsedRealtime(), 3)
    +-                .addValues(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, 1536L, 12L, 512L, 4L, 0L)
    +-                .addValues(TEST_IFACE, UID_RED, SET_DEFAULT, 0xF00D, 512L, 4L, 512L, 4L, 0L)
    +-                .addValues(TEST_IFACE, UID_BLUE, SET_DEFAULT, TAG_NONE, 512L, 4L, 0L, 0L, 0L));
    +-        expectNetworkStatsPoll();
    +-        expectBandwidthControlCheck();
    +-
    +-        replay();
    +-        mService.forceUpdateIfaces();
    +-        forcePollAndWaitForIdle();
    +-        verifyAndReset();
    +-
    +-        // create traffic on second network
    +-        incrementCurrentTime(HOUR_IN_MILLIS);
    +-        expectCurrentTime();
    +-        expectDefaultSettings();
    +-        expectNetworkStatsSummary(new NetworkStats(getElapsedRealtime(), 1)
    +-                .addIfaceValues(TEST_IFACE, 2176L, 17L, 1536L, 12L));
    +-        expectNetworkStatsUidDetail(new NetworkStats(getElapsedRealtime(), 1)
    +-                .addValues(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, 1536L, 12L, 512L, 4L, 0L)
    +-                .addValues(TEST_IFACE, UID_RED, SET_DEFAULT, 0xF00D, 512L, 4L, 512L, 4L, 0L)
    +-                .addValues(TEST_IFACE, UID_BLUE, SET_DEFAULT, TAG_NONE, 640L, 5L, 1024L, 8L, 0L)
    +-                .addValues(TEST_IFACE, UID_BLUE, SET_DEFAULT, 0xFAAD, 128L, 1L, 1024L, 8L, 0L));
    +-        expectNetworkStatsPoll();
    +-
    +-        mService.incrementOperationCount(UID_BLUE, 0xFAAD, 10);
    +-
    +-        replay();
    +-        forcePollAndWaitForIdle();
    +-
    +-        // verify original history still intact
    +-        assertNetworkTotal(sTemplateImsi1, 2048L, 16L, 512L, 4L, 0);
    +-        assertUidTotal(sTemplateImsi1, UID_RED, 1536L, 12L, 512L, 4L, 10);
    +-        assertUidTotal(sTemplateImsi1, UID_BLUE, 512L, 4L, 0L, 0L, 0);
    +-
    +-        // and verify new history also recorded under different template, which
    +-        // verifies that we didn't cross the streams.
    +-        assertNetworkTotal(sTemplateImsi2, 128L, 1L, 1024L, 8L, 0);
    +-        assertNetworkTotal(sTemplateWifi, 0L, 0L, 0L, 0L, 0);
    +-        assertUidTotal(sTemplateImsi2, UID_BLUE, 128L, 1L, 1024L, 8L, 10);
    +-        verifyAndReset();
    +-
    +-    }
    +-
    +-    public void testUidRemovedIsMoved() throws Exception {
    +-        // pretend that network comes online
    +-        expectCurrentTime();
    +-        expectDefaultSettings();
    +-        expectNetworkState(buildWifiState());
    +-        expectNetworkStatsSummary(buildEmptyStats());
    +-        expectNetworkStatsUidDetail(buildEmptyStats());
    +-        expectNetworkStatsPoll();
    +-        expectBandwidthControlCheck();
    +-
    +-        replay();
    +-        mService.forceUpdateIfaces();
    +-        verifyAndReset();
    +-
    +-        // create some traffic
    +-        incrementCurrentTime(HOUR_IN_MILLIS);
    +-        expectCurrentTime();
    +-        expectDefaultSettings();
    +-        expectNetworkStatsSummary(new NetworkStats(getElapsedRealtime(), 1)
    +-                .addIfaceValues(TEST_IFACE, 4128L, 258L, 544L, 34L));
    +-        expectNetworkStatsUidDetail(new NetworkStats(getElapsedRealtime(), 1)
    +-                .addValues(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, 16L, 1L, 16L, 1L, 0L)
    +-                .addValues(TEST_IFACE, UID_RED, SET_DEFAULT, 0xFAAD, 16L, 1L, 16L, 1L, 0L)
    +-                .addValues(TEST_IFACE, UID_BLUE, SET_DEFAULT, TAG_NONE, 4096L, 258L, 512L, 32L, 0L)
    +-                .addValues(TEST_IFACE, UID_GREEN, SET_DEFAULT, TAG_NONE, 16L, 1L, 16L, 1L, 0L));
    +-        expectNetworkStatsPoll();
    +-
    +-        mService.incrementOperationCount(UID_RED, 0xFAAD, 10);
    +-
    +-        replay();
    +-        forcePollAndWaitForIdle();
    +-
    +-        // verify service recorded history
    +-        assertNetworkTotal(sTemplateWifi, 4128L, 258L, 544L, 34L, 0);
    +-        assertUidTotal(sTemplateWifi, UID_RED, 16L, 1L, 16L, 1L, 10);
    +-        assertUidTotal(sTemplateWifi, UID_BLUE, 4096L, 258L, 512L, 32L, 0);
    +-        assertUidTotal(sTemplateWifi, UID_GREEN, 16L, 1L, 16L, 1L, 0);
    +-        verifyAndReset();
    +-
    +-        // now pretend two UIDs are uninstalled, which should migrate stats to
    +-        // special "removed" bucket.
    +-        expectCurrentTime();
    +-        expectDefaultSettings();
    +-        expectNetworkStatsSummary(new NetworkStats(getElapsedRealtime(), 1)
    +-                .addIfaceValues(TEST_IFACE, 4128L, 258L, 544L, 34L));
    +-        expectNetworkStatsUidDetail(new NetworkStats(getElapsedRealtime(), 1)
    +-                .addValues(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, 16L, 1L, 16L, 1L, 0L)
    +-                .addValues(TEST_IFACE, UID_RED, SET_DEFAULT, 0xFAAD, 16L, 1L, 16L, 1L, 0L)
    +-                .addValues(TEST_IFACE, UID_BLUE, SET_DEFAULT, TAG_NONE, 4096L, 258L, 512L, 32L, 0L)
    +-                .addValues(TEST_IFACE, UID_GREEN, SET_DEFAULT, TAG_NONE, 16L, 1L, 16L, 1L, 0L));
    +-        expectNetworkStatsPoll();
    +-
    +-        replay();
    +-        final Intent intent = new Intent(ACTION_UID_REMOVED);
    +-        intent.putExtra(EXTRA_UID, UID_BLUE);
    +-        mServiceContext.sendBroadcast(intent);
    +-        intent.putExtra(EXTRA_UID, UID_RED);
    +-        mServiceContext.sendBroadcast(intent);
    +-
    +-        // existing uid and total should remain unchanged; but removed UID
    +-        // should be gone completely.
    +-        assertNetworkTotal(sTemplateWifi, 4128L, 258L, 544L, 34L, 0);
    +-        assertUidTotal(sTemplateWifi, UID_RED, 0L, 0L, 0L, 0L, 0);
    +-        assertUidTotal(sTemplateWifi, UID_BLUE, 0L, 0L, 0L, 0L, 0);
    +-        assertUidTotal(sTemplateWifi, UID_GREEN, 16L, 1L, 16L, 1L, 0);
    +-        assertUidTotal(sTemplateWifi, UID_REMOVED, 4112L, 259L, 528L, 33L, 10);
    +-        verifyAndReset();
    +-
    +-    }
    +-
    +-    public void testUid3g4gCombinedByTemplate() throws Exception {
    +-        // pretend that network comes online
    +-        expectCurrentTime();
    +-        expectDefaultSettings();
    +-        expectNetworkState(buildMobile3gState(IMSI_1));
    +-        expectNetworkStatsSummary(buildEmptyStats());
    +-        expectNetworkStatsUidDetail(buildEmptyStats());
    +-        expectNetworkStatsPoll();
    +-        expectBandwidthControlCheck();
    +-
    +-        replay();
    +-        mService.forceUpdateIfaces();
    +-        verifyAndReset();
    +-
    +-        // create some traffic
    +-        incrementCurrentTime(HOUR_IN_MILLIS);
    +-        expectCurrentTime();
    +-        expectDefaultSettings();
    +-        expectNetworkStatsSummary(buildEmptyStats());
    +-        expectNetworkStatsUidDetail(new NetworkStats(getElapsedRealtime(), 1)
    +-                .addValues(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, 1024L, 8L, 1024L, 8L, 0L)
    +-                .addValues(TEST_IFACE, UID_RED, SET_DEFAULT, 0xF00D, 512L, 4L, 512L, 4L, 0L));
    +-        expectNetworkStatsPoll();
    +-
    +-        mService.incrementOperationCount(UID_RED, 0xF00D, 5);
    +-
    +-        replay();
    +-        forcePollAndWaitForIdle();
    +-
    +-        // verify service recorded history
    +-        assertUidTotal(sTemplateImsi1, UID_RED, 1024L, 8L, 1024L, 8L, 5);
    +-        verifyAndReset();
    +-
    +-        // now switch over to 4g network
    +-        incrementCurrentTime(HOUR_IN_MILLIS);
    +-        expectCurrentTime();
    +-        expectDefaultSettings();
    +-        expectNetworkState(buildMobile4gState(TEST_IFACE2));
    +-        expectNetworkStatsSummary(buildEmptyStats());
    +-        expectNetworkStatsUidDetail(new NetworkStats(getElapsedRealtime(), 1)
    +-                .addValues(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, 1024L, 8L, 1024L, 8L, 0L)
    +-                .addValues(TEST_IFACE, UID_RED, SET_DEFAULT, 0xF00D, 512L, 4L, 512L, 4L, 0L));
    +-        expectNetworkStatsPoll();
    +-        expectBandwidthControlCheck();
    +-
    +-        replay();
    +-        mService.forceUpdateIfaces();
    +-        forcePollAndWaitForIdle();
    +-        verifyAndReset();
    +-
    +-        // create traffic on second network
    +-        incrementCurrentTime(HOUR_IN_MILLIS);
    +-        expectCurrentTime();
    +-        expectDefaultSettings();
    +-        expectNetworkStatsSummary(buildEmptyStats());
    +-        expectNetworkStatsUidDetail(new NetworkStats(getElapsedRealtime(), 1)
    +-                .addValues(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, 1024L, 8L, 1024L, 8L, 0L)
    +-                .addValues(TEST_IFACE, UID_RED, SET_DEFAULT, 0xF00D, 512L, 4L, 512L, 4L, 0L)
    +-                .addValues(TEST_IFACE2, UID_RED, SET_DEFAULT, TAG_NONE, 512L, 4L, 256L, 2L, 0L)
    +-                .addValues(TEST_IFACE2, UID_RED, SET_DEFAULT, 0xFAAD, 512L, 4L, 256L, 2L, 0L));
    +-        expectNetworkStatsPoll();
    +-
    +-        mService.incrementOperationCount(UID_RED, 0xFAAD, 5);
    +-
    +-        replay();
    +-        forcePollAndWaitForIdle();
    +-
    +-        // verify that ALL_MOBILE template combines both
    +-        assertUidTotal(sTemplateImsi1, UID_RED, 1536L, 12L, 1280L, 10L, 10);
    +-
    +-        verifyAndReset();
    +-    }
    +-
    +-    public void testSummaryForAllUid() throws Exception {
    +-        // pretend that network comes online
    +-        expectCurrentTime();
    +-        expectDefaultSettings();
    +-        expectNetworkState(buildWifiState());
    +-        expectNetworkStatsSummary(buildEmptyStats());
    +-        expectNetworkStatsUidDetail(buildEmptyStats());
    +-        expectNetworkStatsPoll();
    +-        expectBandwidthControlCheck();
    +-
    +-        replay();
    +-        mService.forceUpdateIfaces();
    +-        verifyAndReset();
    +-
    +-        // create some traffic for two apps
    +-        incrementCurrentTime(HOUR_IN_MILLIS);
    +-        expectCurrentTime();
    +-        expectDefaultSettings();
    +-        expectNetworkStatsSummary(buildEmptyStats());
    +-        expectNetworkStatsUidDetail(new NetworkStats(getElapsedRealtime(), 1)
    +-                .addValues(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, 50L, 5L, 50L, 5L, 0L)
    +-                .addValues(TEST_IFACE, UID_RED, SET_DEFAULT, 0xF00D, 10L, 1L, 10L, 1L, 0L)
    +-                .addValues(TEST_IFACE, UID_BLUE, SET_DEFAULT, TAG_NONE, 1024L, 8L, 512L, 4L, 0L));
    +-        expectNetworkStatsPoll();
    +-
    +-        mService.incrementOperationCount(UID_RED, 0xF00D, 1);
    +-
    +-        replay();
    +-        forcePollAndWaitForIdle();
    +-
    +-        // verify service recorded history
    +-        assertUidTotal(sTemplateWifi, UID_RED, 50L, 5L, 50L, 5L, 1);
    +-        assertUidTotal(sTemplateWifi, UID_BLUE, 1024L, 8L, 512L, 4L, 0);
    +-        verifyAndReset();
    +-
    +-        // now create more traffic in next hour, but only for one app
    +-        incrementCurrentTime(HOUR_IN_MILLIS);
    +-        expectCurrentTime();
    +-        expectDefaultSettings();
    +-        expectNetworkStatsSummary(buildEmptyStats());
    +-        expectNetworkStatsUidDetail(new NetworkStats(getElapsedRealtime(), 1)
    +-                .addValues(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, 50L, 5L, 50L, 5L, 0L)
    +-                .addValues(TEST_IFACE, UID_RED, SET_DEFAULT, 0xF00D, 10L, 1L, 10L, 1L, 0L)
    +-                .addValues(TEST_IFACE, UID_BLUE, SET_DEFAULT, TAG_NONE, 2048L, 16L, 1024L, 8L, 0L));
    +-        expectNetworkStatsPoll();
    +-
    +-        replay();
    +-        forcePollAndWaitForIdle();
    +-
    +-        // first verify entire history present
    +-        NetworkStats stats = mSession.getSummaryForAllUid(
    +-                sTemplateWifi, Long.MIN_VALUE, Long.MAX_VALUE, true);
    +-        assertEquals(3, stats.size());
    +-        assertValues(stats, IFACE_ALL, UID_RED, SET_DEFAULT, TAG_NONE, ROAMING_NO, 50L, 5L,
    +-                50L, 5L, 1);
    +-        assertValues(stats, IFACE_ALL, UID_RED, SET_DEFAULT, 0xF00D, ROAMING_NO, 10L, 1L, 10L,
    +-                1L, 1);
    +-        assertValues(stats, IFACE_ALL, UID_BLUE, SET_DEFAULT, TAG_NONE, ROAMING_NO, 2048L, 16L,
    +-                1024L, 8L, 0);
    +-
    +-        // now verify that recent history only contains one uid
    +-        final long currentTime = currentTimeMillis();
    +-        stats = mSession.getSummaryForAllUid(
    +-                sTemplateWifi, currentTime - HOUR_IN_MILLIS, currentTime, true);
    +-        assertEquals(1, stats.size());
    +-        assertValues(stats, IFACE_ALL, UID_BLUE, SET_DEFAULT, TAG_NONE, ROAMING_NO, 1024L, 8L,
    +-                512L, 4L, 0);
    +-
    +-        verifyAndReset();
    +-    }
    +-
    +-    public void testForegroundBackground() throws Exception {
    +-        // pretend that network comes online
    +-        expectCurrentTime();
    +-        expectDefaultSettings();
    +-        expectNetworkState(buildWifiState());
    +-        expectNetworkStatsSummary(buildEmptyStats());
    +-        expectNetworkStatsUidDetail(buildEmptyStats());
    +-        expectNetworkStatsPoll();
    +-        expectBandwidthControlCheck();
    +-
    +-        replay();
    +-        mService.forceUpdateIfaces();
    +-        verifyAndReset();
    +-
    +-        // create some initial traffic
    +-        incrementCurrentTime(HOUR_IN_MILLIS);
    +-        expectCurrentTime();
    +-        expectDefaultSettings();
    +-        expectNetworkStatsSummary(buildEmptyStats());
    +-        expectNetworkStatsUidDetail(new NetworkStats(getElapsedRealtime(), 1)
    +-                .addValues(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, 128L, 2L, 128L, 2L, 0L)
    +-                .addValues(TEST_IFACE, UID_RED, SET_DEFAULT, 0xF00D, 64L, 1L, 64L, 1L, 0L));
    +-        expectNetworkStatsPoll();
    +-
    +-        mService.incrementOperationCount(UID_RED, 0xF00D, 1);
    +-
    +-        replay();
    +-        forcePollAndWaitForIdle();
    +-
    +-        // verify service recorded history
    +-        assertUidTotal(sTemplateWifi, UID_RED, 128L, 2L, 128L, 2L, 1);
    +-        verifyAndReset();
    +-
    +-        // now switch to foreground
    +-        incrementCurrentTime(HOUR_IN_MILLIS);
    +-        expectCurrentTime();
    +-        expectDefaultSettings();
    +-        expectNetworkStatsSummary(buildEmptyStats());
    +-        expectNetworkStatsUidDetail(new NetworkStats(getElapsedRealtime(), 1)
    +-                .addValues(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, 128L, 2L, 128L, 2L, 0L)
    +-                .addValues(TEST_IFACE, UID_RED, SET_DEFAULT, 0xF00D, 64L, 1L, 64L, 1L, 0L)
    +-                .addValues(TEST_IFACE, UID_RED, SET_FOREGROUND, TAG_NONE, 32L, 2L, 32L, 2L, 0L)
    +-                .addValues(TEST_IFACE, UID_RED, SET_FOREGROUND, 0xFAAD, 1L, 1L, 1L, 1L, 0L));
    +-        expectNetworkStatsPoll();
    +-
    +-        mService.setUidForeground(UID_RED, true);
    +-        mService.incrementOperationCount(UID_RED, 0xFAAD, 1);
    +-
    +-        replay();
    +-        forcePollAndWaitForIdle();
    +-
    +-        // test that we combined correctly
    +-        assertUidTotal(sTemplateWifi, UID_RED, 160L, 4L, 160L, 4L, 2);
    +-
    +-        // verify entire history present
    +-        final NetworkStats stats = mSession.getSummaryForAllUid(
    +-                sTemplateWifi, Long.MIN_VALUE, Long.MAX_VALUE, true);
    +-        assertEquals(4, stats.size());
    +-        assertValues(stats, IFACE_ALL, UID_RED, SET_DEFAULT, TAG_NONE, ROAMING_NO, 128L, 2L,
    +-                128L, 2L, 1);
    +-        assertValues(stats, IFACE_ALL, UID_RED, SET_DEFAULT, 0xF00D, ROAMING_NO, 64L, 1L, 64L,
    +-                1L, 1);
    +-        assertValues(stats, IFACE_ALL, UID_RED, SET_FOREGROUND, TAG_NONE, ROAMING_NO, 32L, 2L,
    +-                32L, 2L, 1);
    +-        assertValues(stats, IFACE_ALL, UID_RED, SET_FOREGROUND, 0xFAAD, ROAMING_NO, 1L, 1L, 1L,
    +-                1L, 1);
    +-
    +-        verifyAndReset();
    +-    }
    +-
    +-    public void testRoaming() throws Exception {
    +-        // pretend that network comes online
    +-        expectCurrentTime();
    +-        expectDefaultSettings();
    +-        expectNetworkState(buildMobile3gState(IMSI_1, true /* isRoaming */));
    +-        expectNetworkStatsSummary(buildEmptyStats());
    +-        expectNetworkStatsUidDetail(buildEmptyStats());
    +-        expectNetworkStatsPoll();
    +-        expectBandwidthControlCheck();
    +-
    +-        replay();
    +-        mService.forceUpdateIfaces();
    +-        verifyAndReset();
    +-
    +-        // Create some traffic
    +-        incrementCurrentTime(HOUR_IN_MILLIS);
    +-        expectCurrentTime();
    +-        expectDefaultSettings();
    +-        expectNetworkStatsSummary(buildEmptyStats());
    +-        // Note that all traffic from NetworkManagementService is tagged as ROAMING_NO, because
    +-        // roaming isn't tracked at that layer. We layer it on top by inspecting the iface
    +-        // properties.
    +-        expectNetworkStatsUidDetail(new NetworkStats(getElapsedRealtime(), 1)
    +-                .addValues(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, ROAMING_NO, 128L, 2L,
    +-                        128L, 2L, 0L)
    +-                .addValues(TEST_IFACE, UID_RED, SET_DEFAULT, 0xF00D, ROAMING_NO, 64L, 1L, 64L,
    +-                        1L, 0L));
    +-        expectNetworkStatsPoll();
    +-
    +-        replay();
    +-        forcePollAndWaitForIdle();
    +-
    +-        // verify service recorded history
    +-        assertUidTotal(sTemplateImsi1, UID_RED, 128L, 2L, 128L, 2L, 0);
    +-
    +-        // verify entire history present
    +-        final NetworkStats stats = mSession.getSummaryForAllUid(
    +-                sTemplateImsi1, Long.MIN_VALUE, Long.MAX_VALUE, true);
    +-        assertEquals(2, stats.size());
    +-        assertValues(stats, IFACE_ALL, UID_RED, SET_DEFAULT, TAG_NONE, ROAMING_YES, 128L, 2L,
    +-                128L, 2L, 0);
    +-        assertValues(stats, IFACE_ALL, UID_RED, SET_DEFAULT, 0xF00D, ROAMING_YES, 64L, 1L, 64L,
    +-                1L, 0);
    +-
    +-        verifyAndReset();
    +-    }
    +-
    +-    public void testTethering() throws Exception {
    +-        // pretend first mobile network comes online
    +-        expectCurrentTime();
    +-        expectDefaultSettings();
    +-        expectNetworkState(buildMobile3gState(IMSI_1));
    +-        expectNetworkStatsSummary(buildEmptyStats());
    +-        expectNetworkStatsUidDetail(buildEmptyStats());
    +-        expectNetworkStatsPoll();
    +-        expectBandwidthControlCheck();
    +-
    +-        replay();
    +-        mService.forceUpdateIfaces();
    +-        verifyAndReset();
    +-
    +-        // create some tethering traffic
    +-        incrementCurrentTime(HOUR_IN_MILLIS);
    +-        expectCurrentTime();
    +-        expectDefaultSettings();
    +-        expectNetworkStatsSummary(new NetworkStats(getElapsedRealtime(), 1)
    +-                .addIfaceValues(TEST_IFACE, 2048L, 16L, 512L, 4L));
    +-
    +-        final NetworkStats uidStats = new NetworkStats(getElapsedRealtime(), 1)
    +-                .addValues(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, 128L, 2L, 128L, 2L, 0L);
    +-        final String[] tetherIfacePairs = new String[] { TEST_IFACE, "wlan0" };
    +-        final NetworkStats tetherStats = new NetworkStats(getElapsedRealtime(), 1)
    +-                .addValues(TEST_IFACE, UID_TETHERING, SET_DEFAULT, TAG_NONE, 1920L, 14L, 384L, 2L, 0L);
    +-
    +-        expectNetworkStatsUidDetail(uidStats, tetherIfacePairs, tetherStats);
    +-        expectNetworkStatsPoll();
    +-
    +-        replay();
    +-        forcePollAndWaitForIdle();
    +-
    +-        // verify service recorded history
    +-        assertNetworkTotal(sTemplateImsi1, 2048L, 16L, 512L, 4L, 0);
    +-        assertUidTotal(sTemplateImsi1, UID_RED, 128L, 2L, 128L, 2L, 0);
    +-        assertUidTotal(sTemplateImsi1, UID_TETHERING, 1920L, 14L, 384L, 2L, 0);
    +-        verifyAndReset();
    +-
    +-    }
    +-
    +-    public void testRegisterUsageCallback() throws Exception {
    +-        // pretend that wifi network comes online; service should ask about full
    +-        // network state, and poll any existing interfaces before updating.
    +-        expectCurrentTime();
    +-        expectDefaultSettings();
    +-        expectNetworkState(buildWifiState());
    +-        expectNetworkStatsSummary(buildEmptyStats());
    +-        expectNetworkStatsUidDetail(buildEmptyStats());
    +-        expectNetworkStatsPoll();
    +-        expectBandwidthControlCheck();
    +-
    +-        replay();
    +-        mService.forceUpdateIfaces();
    +-
    +-        // verify service has empty history for wifi
    +-        assertNetworkTotal(sTemplateWifi, 0L, 0L, 0L, 0L, 0);
    +-        verifyAndReset();
    +-
    +-        String callingPackage = "the.calling.package";
    +-        long thresholdInBytes = 1L;  // very small; should be overriden by framework
    +-        DataUsageRequest inputRequest = new DataUsageRequest(
    +-                DataUsageRequest.REQUEST_ID_UNSET, sTemplateWifi, thresholdInBytes);
    +-
    +-        // Create a messenger that waits for callback activity
    +-        ConditionVariable cv = new ConditionVariable(false);
    +-        LatchedHandler latchedHandler = new LatchedHandler(Looper.getMainLooper(), cv);
    +-        Messenger messenger = new Messenger(latchedHandler);
    +-
    +-        // Allow binder to connect
    +-        IBinder mockBinder = createMock(IBinder.class);
    +-        mockBinder.linkToDeath((IBinder.DeathRecipient) anyObject(), anyInt());
    +-        EasyMock.replay(mockBinder);
    +-
    +-        // Force poll
    +-        expectCurrentTime();
    +-        expectDefaultSettings();
    +-        expectNetworkStatsSummary(buildEmptyStats());
    +-        expectNetworkStatsUidDetail(buildEmptyStats());
    +-        expectNetworkStatsPoll();
    +-        replay();
    +-
    +-        // Register and verify request and that binder was called
    +-        DataUsageRequest request =
    +-                mService.registerUsageCallback(callingPackage, inputRequest,
    +-                        messenger, mockBinder);
    +-        assertTrue(request.requestId > 0);
    +-        assertTrue(Objects.equals(sTemplateWifi, request.template));
    +-        long minThresholdInBytes = 2 * 1024 * 1024; // 2 MB
    +-        assertEquals(minThresholdInBytes, request.thresholdInBytes);
    +-
    +-        // Send dummy message to make sure that any previous message has been handled
    +-        mHandler.sendMessage(mHandler.obtainMessage(-1));
    +-        mHandlerThread.waitForIdle(WAIT_TIMEOUT);
    +-
    +-        verifyAndReset();
    +-
    +-        // Make sure that the caller binder gets connected
    +-        EasyMock.verify(mockBinder);
    +-        EasyMock.reset(mockBinder);
    +-
    +-        // modify some number on wifi, and trigger poll event
    +-        // not enough traffic to call data usage callback
    +-        incrementCurrentTime(HOUR_IN_MILLIS);
    +-        expectCurrentTime();
    +-        expectDefaultSettings();
    +-        expectNetworkStatsSummary(new NetworkStats(getElapsedRealtime(), 1)
    +-                .addIfaceValues(TEST_IFACE, 1024L, 1L, 2048L, 2L));
    +-        expectNetworkStatsUidDetail(buildEmptyStats());
    +-        expectNetworkStatsPoll();
    +-
    +-        replay();
    +-        forcePollAndWaitForIdle();
    +-
    +-        // verify service recorded history
    +-        verifyAndReset();
    +-        assertNetworkTotal(sTemplateWifi, 1024L, 1L, 2048L, 2L, 0);
    +-
    +-        // make sure callback has not being called
    +-        assertEquals(INVALID_TYPE, latchedHandler.mLastMessageType);
    +-
    +-        // and bump forward again, with counters going higher. this is
    +-        // important, since it will trigger the data usage callback
    +-        incrementCurrentTime(DAY_IN_MILLIS);
    +-        expectCurrentTime();
    +-        expectDefaultSettings();
    +-        expectNetworkStatsSummary(new NetworkStats(getElapsedRealtime(), 1)
    +-                .addIfaceValues(TEST_IFACE, 4096000L, 4L, 8192000L, 8L));
    +-        expectNetworkStatsUidDetail(buildEmptyStats());
    +-        expectNetworkStatsPoll();
    +-
    +-        replay();
    +-        forcePollAndWaitForIdle();
    +-
    +-        // verify service recorded history
    +-        assertNetworkTotal(sTemplateWifi, 4096000L, 4L, 8192000L, 8L, 0);
    +-        verifyAndReset();
    +-
    +-        // Wait for the caller to ack receipt of CALLBACK_LIMIT_REACHED
    +-        assertTrue(cv.block(WAIT_TIMEOUT));
    +-        assertEquals(NetworkStatsManager.CALLBACK_LIMIT_REACHED, latchedHandler.mLastMessageType);
    +-        cv.close();
    +-
    +-        // Allow binder to disconnect
    +-        expect(mockBinder.unlinkToDeath((IBinder.DeathRecipient) anyObject(), anyInt()))
    +-                .andReturn(true);
    +-        EasyMock.replay(mockBinder);
    +-
    +-        // Unregister request
    +-        mService.unregisterUsageRequest(request);
    +-
    +-        // Wait for the caller to ack receipt of CALLBACK_RELEASED
    +-        assertTrue(cv.block(WAIT_TIMEOUT));
    +-        assertEquals(NetworkStatsManager.CALLBACK_RELEASED, latchedHandler.mLastMessageType);
    +-
    +-        // Make sure that the caller binder gets disconnected
    +-        EasyMock.verify(mockBinder);
    +-    }
    +-
    +-    public void testUnregisterUsageCallback_unknown_noop() throws Exception {
    +-        String callingPackage = "the.calling.package";
    +-        long thresholdInBytes = 10 * 1024 * 1024;  // 10 MB
    +-        DataUsageRequest unknownRequest = new DataUsageRequest(
    +-                2 /* requestId */, sTemplateImsi1, thresholdInBytes);
    +-
    +-        mService.unregisterUsageRequest(unknownRequest);
    +-    }
    +-
    +-    private static File getBaseDir(File statsDir) {
    +-        File baseDir = new File(statsDir, "netstats");
    +-        baseDir.mkdirs();
    +-        return baseDir;
    +-    }
    +-
    +-    private void assertNetworkTotal(NetworkTemplate template, long rxBytes, long rxPackets,
    +-            long txBytes, long txPackets, int operations) throws Exception {
    +-        assertNetworkTotal(template, Long.MIN_VALUE, Long.MAX_VALUE, rxBytes, rxPackets, txBytes,
    +-                txPackets, operations);
    +-    }
    +-
    +-    private void assertNetworkTotal(NetworkTemplate template, long start, long end, long rxBytes,
    +-            long rxPackets, long txBytes, long txPackets, int operations) throws Exception {
    +-        // verify history API
    +-        final NetworkStatsHistory history = mSession.getHistoryForNetwork(template, FIELD_ALL);
    +-        assertValues(history, start, end, rxBytes, rxPackets, txBytes, txPackets, operations);
    +-
    +-        // verify summary API
    +-        final NetworkStats stats = mSession.getSummaryForNetwork(template, start, end);
    +-        assertValues(stats, IFACE_ALL, UID_ALL, SET_DEFAULT, TAG_NONE, ROAMING_NO, rxBytes,
    +-                rxPackets, txBytes, txPackets, operations);
    +-    }
    +-
    +-    private void assertUidTotal(NetworkTemplate template, int uid, long rxBytes, long rxPackets,
    +-            long txBytes, long txPackets, int operations) throws Exception {
    +-        assertUidTotal(template, uid, SET_ALL, ROAMING_ALL, rxBytes, rxPackets, txBytes, txPackets,
    +-                operations);
    +-    }
    +-
    +-    private void assertUidTotal(NetworkTemplate template, int uid, int set, int roaming,
    +-            long rxBytes, long rxPackets, long txBytes, long txPackets, int operations)
    +-            throws Exception {
    +-        // verify history API
    +-        final NetworkStatsHistory history = mSession.getHistoryForUid(
    +-                template, uid, set, TAG_NONE, FIELD_ALL);
    +-        assertValues(history, Long.MIN_VALUE, Long.MAX_VALUE, rxBytes, rxPackets, txBytes,
    +-                txPackets, operations);
    +-
    +-        // verify summary API
    +-        final NetworkStats stats = mSession.getSummaryForAllUid(
    +-                template, Long.MIN_VALUE, Long.MAX_VALUE, false);
    +-        assertValues(stats, IFACE_ALL, uid, set, TAG_NONE, roaming, rxBytes, rxPackets, txBytes,
    +-                txPackets, operations);
    +-    }
    +-
    +-    private void expectSystemReady() throws Exception {
    +-        mNetManager.setGlobalAlert(anyLong());
    +-        expectLastCall().atLeastOnce();
    +-
    +-        expectNetworkStatsSummary(buildEmptyStats());
    +-        expectBandwidthControlCheck();
    +-    }
    +-
    +-    private void expectNetworkState(NetworkState... state) throws Exception {
    +-        expect(mConnManager.getAllNetworkState()).andReturn(state).atLeastOnce();
    +-
    +-        final LinkProperties linkProp = state.length > 0 ? state[0].linkProperties : null;
    +-        expect(mConnManager.getActiveLinkProperties()).andReturn(linkProp).atLeastOnce();
    +-    }
    +-
    +-    private void expectNetworkStatsSummary(NetworkStats summary) throws Exception {
    +-        expect(mConnManager.getAllVpnInfo()).andReturn(new VpnInfo[0]).atLeastOnce();
    +-
    +-        expectNetworkStatsSummaryDev(summary);
    +-        expectNetworkStatsSummaryXt(summary);
    +-    }
    +-
    +-    private void expectNetworkStatsSummaryDev(NetworkStats summary) throws Exception {
    +-        expect(mNetManager.getNetworkStatsSummaryDev()).andReturn(summary).atLeastOnce();
    +-    }
    +-
    +-    private void expectNetworkStatsSummaryXt(NetworkStats summary) throws Exception {
    +-        expect(mNetManager.getNetworkStatsSummaryXt()).andReturn(summary).atLeastOnce();
    +-    }
    +-
    +-    private void expectNetworkStatsUidDetail(NetworkStats detail) throws Exception {
    +-        expectNetworkStatsUidDetail(detail, new String[0], new NetworkStats(0L, 0));
    +-    }
    +-
    +-    private void expectNetworkStatsUidDetail(
    +-            NetworkStats detail, String[] tetherIfacePairs, NetworkStats tetherStats)
    +-            throws Exception {
    +-        expect(mNetManager.getNetworkStatsUidDetail(eq(UID_ALL))).andReturn(detail).atLeastOnce();
    +-
    +-        // also include tethering details, since they are folded into UID
    +-        expect(mNetManager.getNetworkStatsTethering())
    +-                .andReturn(tetherStats).atLeastOnce();
    +-    }
    +-
    +-    private void expectDefaultSettings() throws Exception {
    +-        expectSettings(0L, HOUR_IN_MILLIS, WEEK_IN_MILLIS);
    +-    }
    +-
    +-    private void expectSettings(long persistBytes, long bucketDuration, long deleteAge)
    +-            throws Exception {
    +-        expect(mSettings.getPollInterval()).andReturn(HOUR_IN_MILLIS).anyTimes();
    +-        expect(mSettings.getTimeCacheMaxAge()).andReturn(DAY_IN_MILLIS).anyTimes();
    +-        expect(mSettings.getSampleEnabled()).andReturn(true).anyTimes();
    +-
    +-        final Config config = new Config(bucketDuration, deleteAge, deleteAge);
    +-        expect(mSettings.getDevConfig()).andReturn(config).anyTimes();
    +-        expect(mSettings.getXtConfig()).andReturn(config).anyTimes();
    +-        expect(mSettings.getUidConfig()).andReturn(config).anyTimes();
    +-        expect(mSettings.getUidTagConfig()).andReturn(config).anyTimes();
    +-
    +-        expect(mSettings.getGlobalAlertBytes(anyLong())).andReturn(MB_IN_BYTES).anyTimes();
    +-        expect(mSettings.getDevPersistBytes(anyLong())).andReturn(MB_IN_BYTES).anyTimes();
    +-        expect(mSettings.getXtPersistBytes(anyLong())).andReturn(MB_IN_BYTES).anyTimes();
    +-        expect(mSettings.getUidPersistBytes(anyLong())).andReturn(MB_IN_BYTES).anyTimes();
    +-        expect(mSettings.getUidTagPersistBytes(anyLong())).andReturn(MB_IN_BYTES).anyTimes();
    +-    }
    +-
    +-    private void expectCurrentTime() throws Exception {
    +-        expect(mTime.forceRefresh()).andReturn(false).anyTimes();
    +-        expect(mTime.hasCache()).andReturn(true).anyTimes();
    +-        expect(mTime.currentTimeMillis()).andReturn(currentTimeMillis()).anyTimes();
    +-        expect(mTime.getCacheAge()).andReturn(0L).anyTimes();
    +-        expect(mTime.getCacheCertainty()).andReturn(0L).anyTimes();
    +-    }
    +-
    +-    private void expectNetworkStatsPoll() throws Exception {
    +-        mNetManager.setGlobalAlert(anyLong());
    +-        expectLastCall().anyTimes();
    +-    }
    +-
    +-    private void expectBandwidthControlCheck() throws Exception {
    +-        expect(mNetManager.isBandwidthControlEnabled()).andReturn(true).atLeastOnce();
    +-    }
    +-
    +-    private void assertStatsFilesExist(boolean exist) {
    +-        final File basePath = new File(mStatsDir, "netstats");
    +-        if (exist) {
    +-            assertTrue(basePath.list().length > 0);
    +-        } else {
    +-            assertTrue(basePath.list().length == 0);
    +-        }
    +-    }
    +-
    +-    private static void assertValues(NetworkStats stats, String iface, int uid, int set,
    +-            int tag, int roaming, long rxBytes, long rxPackets, long txBytes, long txPackets,
    +-            int operations) {
    +-        final NetworkStats.Entry entry = new NetworkStats.Entry();
    +-        List<Integer> sets = new ArrayList<>();
    +-        if (set == SET_DEFAULT || set == SET_ALL) {
    +-            sets.add(SET_DEFAULT);
    +-        }
    +-        if (set == SET_FOREGROUND || set == SET_ALL) {
    +-            sets.add(SET_FOREGROUND);
    +-        }
    +-
    +-        List<Integer> roamings = new ArrayList<>();
    +-        if (roaming == ROAMING_NO || roaming == ROAMING_ALL) {
    +-            roamings.add(ROAMING_NO);
    +-        }
    +-        if (roaming == ROAMING_YES || roaming == ROAMING_ALL) {
    +-            roamings.add(ROAMING_YES);
    +-        }
    +-
    +-        for (int s : sets) {
    +-            for (int r : roamings) {
    +-                final int i = stats.findIndex(iface, uid, s, tag, r);
    +-                if (i != -1) {
    +-                    entry.add(stats.getValues(i, null));
    +-                }
    +-            }
    +-        }
    +-
    +-        assertEquals("unexpected rxBytes", rxBytes, entry.rxBytes);
    +-        assertEquals("unexpected rxPackets", rxPackets, entry.rxPackets);
    +-        assertEquals("unexpected txBytes", txBytes, entry.txBytes);
    +-        assertEquals("unexpected txPackets", txPackets, entry.txPackets);
    +-        assertEquals("unexpected operations", operations, entry.operations);
    +-    }
    +-
    +-    private static void assertValues(NetworkStatsHistory stats, long start, long end, long rxBytes,
    +-            long rxPackets, long txBytes, long txPackets, int operations) {
    +-        final NetworkStatsHistory.Entry entry = stats.getValues(start, end, null);
    +-        assertEquals("unexpected rxBytes", rxBytes, entry.rxBytes);
    +-        assertEquals("unexpected rxPackets", rxPackets, entry.rxPackets);
    +-        assertEquals("unexpected txBytes", txBytes, entry.txBytes);
    +-        assertEquals("unexpected txPackets", txPackets, entry.txPackets);
    +-        assertEquals("unexpected operations", operations, entry.operations);
    +-    }
    +-
    +-    private static NetworkState buildWifiState() {
    +-        final NetworkInfo info = new NetworkInfo(TYPE_WIFI, 0, null, null);
    +-        info.setDetailedState(DetailedState.CONNECTED, null, null);
    +-        final LinkProperties prop = new LinkProperties();
    +-        prop.setInterfaceName(TEST_IFACE);
    +-        return new NetworkState(info, prop, null, null, null, TEST_SSID);
    +-    }
    +-
    +-    private static NetworkState buildMobile3gState(String subscriberId) {
    +-        return buildMobile3gState(subscriberId, false /* isRoaming */);
    +-    }
    +-
    +-    private static NetworkState buildMobile3gState(String subscriberId, boolean isRoaming) {
    +-        final NetworkInfo info = new NetworkInfo(
    +-                TYPE_MOBILE, TelephonyManager.NETWORK_TYPE_UMTS, null, null);
    +-        info.setDetailedState(DetailedState.CONNECTED, null, null);
    +-        info.setRoaming(isRoaming);
    +-        final LinkProperties prop = new LinkProperties();
    +-        prop.setInterfaceName(TEST_IFACE);
    +-        return new NetworkState(info, prop, null, null, subscriberId, null);
    +-    }
    +-
    +-    private static NetworkState buildMobile4gState(String iface) {
    +-        final NetworkInfo info = new NetworkInfo(TYPE_WIMAX, 0, null, null);
    +-        info.setDetailedState(DetailedState.CONNECTED, null, null);
    +-        final LinkProperties prop = new LinkProperties();
    +-        prop.setInterfaceName(iface);
    +-        return new NetworkState(info, prop, null, null, null, null);
    +-    }
    +-
    +-    private NetworkStats buildEmptyStats() {
    +-        return new NetworkStats(getElapsedRealtime(), 0);
    +-    }
    +-
    +-    private long getElapsedRealtime() {
    +-        return mElapsedRealtime;
    +-    }
    +-
    +-    private long startTimeMillis() {
    +-        return TEST_START;
    +-    }
    +-
    +-    private long currentTimeMillis() {
    +-        return startTimeMillis() + mElapsedRealtime;
    +-    }
    +-
    +-    private void incrementCurrentTime(long duration) {
    +-        mElapsedRealtime += duration;
    +-    }
    +-
    +-    private void replay() {
    +-        EasyMock.replay(mNetManager, mTime, mSettings, mConnManager);
    +-    }
    +-
    +-    private void verifyAndReset() {
    +-        EasyMock.verify(mNetManager, mTime, mSettings, mConnManager);
    +-        EasyMock.reset(mNetManager, mTime, mSettings, mConnManager);
    +-    }
    +-
    +-    private void forcePollAndWaitForIdle() {
    +-        mServiceContext.sendBroadcast(new Intent(ACTION_NETWORK_STATS_POLL));
    +-        // Send dummy message to make sure that any previous message has been handled
    +-        mHandler.sendMessage(mHandler.obtainMessage(-1));
    +-        mHandlerThread.waitForIdle(WAIT_TIMEOUT);
    +-    }
    +-
    +-    static class LatchedHandler extends Handler {
    +-        private final ConditionVariable mCv;
    +-        int mLastMessageType = INVALID_TYPE;
    +-
    +-        LatchedHandler(Looper looper, ConditionVariable cv) {
    +-            super(looper);
    +-            mCv = cv;
    +-        }
    +-
    +-        @Override
    +-        public void handleMessage(Message msg) {
    +-            mLastMessageType = msg.what;
    +-            mCv.open();
    +-            super.handleMessage(msg);
    +-        }
    +-    }
    +-
    +-    /**
    +-     * A subclass of HandlerThread that allows callers to wait for it to become idle. waitForIdle
    +-     * will return immediately if the handler is already idle.
    +-     */
    +-    static class IdleableHandlerThread extends HandlerThread {
    +-        private IdleHandler mIdleHandler;
    +-
    +-        public IdleableHandlerThread(String name) {
    +-            super(name);
    +-        }
    +-
    +-        public void waitForIdle(long timeoutMs) {
    +-            final ConditionVariable cv = new ConditionVariable();
    +-            final MessageQueue queue = getLooper().getQueue();
    +-
    +-            synchronized (queue) {
    +-                if (queue.isIdle()) {
    +-                    return;
    +-                }
    +-
    +-                assertNull("BUG: only one idle handler allowed", mIdleHandler);
    +-                mIdleHandler = new IdleHandler() {
    +-                    public boolean queueIdle() {
    +-                        cv.open();
    +-                        mIdleHandler = null;
    +-                        return false;  // Remove the handler.
    +-                    }
    +-                };
    +-                queue.addIdleHandler(mIdleHandler);
    +-            }
    +-
    +-            if (!cv.block(timeoutMs)) {
    +-                fail("HandlerThread " + getName() + " did not become idle after " + timeoutMs
    +-                        + " ms");
    +-                queue.removeIdleHandler(mIdleHandler);
    +-            }
    +-        }
    +-    }
    +-
    +-}
    +diff --git a/services/tests/servicestests/src/com/android/server/notification/BuzzBeepBlinkTest.java b/services/tests/servicestests/src/com/android/server/notification/BuzzBeepBlinkTest.java
    +deleted file mode 100644
    +index d51f2d8..0000000
    +--- a/services/tests/servicestests/src/com/android/server/notification/BuzzBeepBlinkTest.java
    ++++ /dev/null
    +@@ -1,542 +0,0 @@
    +-/*
    +- * Copyright (C) 2016 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 com.android.server.notification;
    +-
    +-
    +-import android.app.ActivityManager;
    +-import android.app.Notification;
    +-import android.app.Notification.Builder;
    +-import android.media.AudioAttributes;
    +-import android.media.AudioManager;
    +-import android.net.Uri;
    +-import android.os.Handler;
    +-import android.os.RemoteException;
    +-import android.os.UserHandle;
    +-import android.os.Vibrator;
    +-import android.service.notification.NotificationListenerService.Ranking;
    +-import android.service.notification.StatusBarNotification;
    +-import android.test.AndroidTestCase;
    +-import android.test.suitebuilder.annotation.SmallTest;
    +-
    +-import org.mockito.Mock;
    +-import org.mockito.Mockito;
    +-import org.mockito.MockitoAnnotations;
    +-
    +-import static org.mockito.Matchers.anyBoolean;
    +-import static org.mockito.Matchers.anyInt;
    +-import static org.mockito.Matchers.anyObject;
    +-import static org.mockito.Matchers.anyString;
    +-import static org.mockito.Matchers.eq;
    +-import static org.mockito.Mockito.never;
    +-import static org.mockito.Mockito.times;
    +-import static org.mockito.Mockito.verify;
    +-import static org.mockito.Mockito.when;
    +-
    +-public class BuzzBeepBlinkTest extends AndroidTestCase {
    +-
    +-    @Mock AudioManager mAudioManager;
    +-    @Mock Vibrator mVibrator;
    +-    @Mock android.media.IRingtonePlayer mRingtonePlayer;
    +-    @Mock Handler mHandler;
    +-
    +-    private NotificationManagerService mService;
    +-    private String mPkg = "com.android.server.notification";
    +-    private int mId = 1001;
    +-    private int mOtherId = 1002;
    +-    private String mTag = null;
    +-    private int mUid = 1000;
    +-    private int mPid = 2000;
    +-    private int mScore = 10;
    +-    private android.os.UserHandle mUser = UserHandle.of(ActivityManager.getCurrentUser());
    +-
    +-    @Override
    +-    public void setUp() {
    +-        MockitoAnnotations.initMocks(this);
    +-
    +-        when(mAudioManager.isAudioFocusExclusive()).thenReturn(false);
    +-        when(mAudioManager.getRingtonePlayer()).thenReturn(mRingtonePlayer);
    +-        when(mAudioManager.getStreamVolume(anyInt())).thenReturn(10);
    +-        when(mAudioManager.getRingerModeInternal()).thenReturn(AudioManager.RINGER_MODE_NORMAL);
    +-
    +-        mService = new NotificationManagerService(getContext());
    +-        mService.setAudioManager(mAudioManager);
    +-        mService.setVibrator(mVibrator);
    +-        mService.setSystemReady(true);
    +-        mService.setHandler(mHandler);
    +-        mService.setSystemNotificationSound("beep!");
    +-    }
    +-
    +-    //
    +-    // Convenience functions for creating notification records
    +-    //
    +-
    +-    private NotificationRecord getNoisyOtherNotification() {
    +-        return getNotificationRecord(mOtherId, false /* insistent */, false /* once */,
    +-                true /* noisy */, true /* buzzy*/);
    +-    }
    +-
    +-    private NotificationRecord getBeepyNotification() {
    +-        return getNotificationRecord(mId, false /* insistent */, false /* once */,
    +-                true /* noisy */, false /* buzzy*/);
    +-    }
    +-
    +-    private NotificationRecord getBeepyOnceNotification() {
    +-        return getNotificationRecord(mId, false /* insistent */, true /* once */,
    +-                true /* noisy */, false /* buzzy*/);
    +-    }
    +-
    +-    private NotificationRecord getQuietNotification() {
    +-        return getNotificationRecord(mId, false /* insistent */, false /* once */,
    +-                false /* noisy */, false /* buzzy*/);
    +-    }
    +-
    +-    private NotificationRecord getQuietOtherNotification() {
    +-        return getNotificationRecord(mOtherId, false /* insistent */, false /* once */,
    +-                false /* noisy */, false /* buzzy*/);
    +-    }
    +-
    +-    private NotificationRecord getQuietOnceNotification() {
    +-        return getNotificationRecord(mId, false /* insistent */, true /* once */,
    +-                false /* noisy */, false /* buzzy*/);
    +-    }
    +-
    +-    private NotificationRecord getInsistentBeepyNotification() {
    +-        return getNotificationRecord(mId, true /* insistent */, false /* once */,
    +-                true /* noisy */, false /* buzzy*/);
    +-    }
    +-
    +-    private NotificationRecord getBuzzyNotification() {
    +-        return getNotificationRecord(mId, false /* insistent */, false /* once */,
    +-                false /* noisy */, true /* buzzy*/);
    +-    }
    +-
    +-    private NotificationRecord getBuzzyOnceNotification() {
    +-        return getNotificationRecord(mId, false /* insistent */, true /* once */,
    +-                false /* noisy */, true /* buzzy*/);
    +-    }
    +-
    +-    private NotificationRecord getInsistentBuzzyNotification() {
    +-        return getNotificationRecord(mId, true /* insistent */, false /* once */,
    +-                false /* noisy */, true /* buzzy*/);
    +-    }
    +-
    +-    private NotificationRecord getNotificationRecord(int id, boolean insistent, boolean once,
    +-            boolean noisy, boolean buzzy) {
    +-        final Builder builder = new Builder(getContext())
    +-                .setContentTitle("foo")
    +-                .setSmallIcon(android.R.drawable.sym_def_app_icon)
    +-                .setPriority(Notification.PRIORITY_HIGH)
    +-                .setOnlyAlertOnce(once);
    +-
    +-        int defaults = 0;
    +-        if (noisy) {
    +-            defaults |= Notification.DEFAULT_SOUND;
    +-        }
    +-        if (buzzy) {
    +-            defaults |= Notification.DEFAULT_VIBRATE;
    +-        }
    +-        builder.setDefaults(defaults);
    +-
    +-        Notification n = builder.build();
    +-        if (insistent) {
    +-            n.flags |= Notification.FLAG_INSISTENT;
    +-        }
    +-        StatusBarNotification sbn = new StatusBarNotification(mPkg, mPkg, id, mTag, mUid, mPid,
    +-                mScore, n, mUser, System.currentTimeMillis());
    +-        return new NotificationRecord(getContext(), sbn);
    +-    }
    +-
    +-    //
    +-    // Convenience functions for interacting with mocks
    +-    //
    +-
    +-    private void verifyNeverBeep() throws RemoteException {
    +-        verify(mRingtonePlayer, never()).playAsync((Uri) anyObject(), (UserHandle) anyObject(),
    +-                anyBoolean(), (AudioAttributes) anyObject());
    +-    }
    +-
    +-    private void verifyBeep() throws RemoteException {
    +-        verify(mRingtonePlayer, times(1)).playAsync((Uri) anyObject(), (UserHandle) anyObject(),
    +-                eq(true), (AudioAttributes) anyObject());
    +-    }
    +-
    +-    private void verifyBeepLooped() throws RemoteException {
    +-        verify(mRingtonePlayer, times(1)).playAsync((Uri) anyObject(), (UserHandle) anyObject(),
    +-                eq(false), (AudioAttributes) anyObject());
    +-    }
    +-
    +-    private void verifyNeverStopAudio() throws RemoteException {
    +-        verify(mRingtonePlayer, never()).stopAsync();
    +-    }
    +-
    +-    private void verifyStopAudio() throws RemoteException {
    +-        verify(mRingtonePlayer, times(1)).stopAsync();
    +-    }
    +-
    +-    private void verifyNeverVibrate() {
    +-        verify(mVibrator, never()).vibrate(anyInt(), anyString(), (long[]) anyObject(),
    +-                anyInt(), (AudioAttributes) anyObject());
    +-    }
    +-
    +-    private void verifyVibrate() {
    +-        verify(mVibrator, times(1)).vibrate(anyInt(), anyString(), (long[]) anyObject(),
    +-                eq(-1), (AudioAttributes) anyObject());
    +-    }
    +-
    +-    private void verifyVibrateLooped() {
    +-        verify(mVibrator, times(1)).vibrate(anyInt(), anyString(), (long[]) anyObject(),
    +-                eq(0), (AudioAttributes) anyObject());
    +-    }
    +-
    +-    private void verifyStopVibrate() {
    +-        verify(mVibrator, times(1)).cancel();
    +-    }
    +-
    +-    private void verifyNeverStopVibrate() throws RemoteException {
    +-        verify(mVibrator, never()).cancel();
    +-    }
    +-
    +-    @SmallTest
    +-    public void testBeep() throws Exception {
    +-        NotificationRecord r = getBeepyNotification();
    +-
    +-        mService.buzzBeepBlinkLocked(r);
    +-
    +-        verifyBeepLooped();
    +-        verifyNeverVibrate();
    +-    }
    +-
    +-    //
    +-    // Tests
    +-    //
    +-
    +-    @SmallTest
    +-    public void testBeepInsistently() throws Exception {
    +-        NotificationRecord r = getInsistentBeepyNotification();
    +-
    +-        mService.buzzBeepBlinkLocked(r);
    +-
    +-        verifyBeep();
    +-    }
    +-
    +-    @SmallTest
    +-    public void testNoInterruptionForMin() throws Exception {
    +-        NotificationRecord r = getBeepyNotification();
    +-        r.setImportance(Ranking.IMPORTANCE_MIN, "foo");
    +-
    +-        mService.buzzBeepBlinkLocked(r);
    +-
    +-        verifyNeverBeep();
    +-        verifyNeverVibrate();
    +-    }
    +-
    +-    @SmallTest
    +-    public void testNoInterruptionForIntercepted() throws Exception {
    +-        NotificationRecord r = getBeepyNotification();
    +-        r.setIntercepted(true);
    +-
    +-        mService.buzzBeepBlinkLocked(r);
    +-
    +-        verifyNeverBeep();
    +-        verifyNeverVibrate();
    +-    }
    +-
    +-    @SmallTest
    +-    public void testBeepTwice() throws Exception {
    +-        NotificationRecord r = getBeepyNotification();
    +-
    +-        // set up internal state
    +-        mService.buzzBeepBlinkLocked(r);
    +-        Mockito.reset(mRingtonePlayer);
    +-
    +-        // update should beep
    +-        r.isUpdate = true;
    +-        mService.buzzBeepBlinkLocked(r);
    +-        verifyBeepLooped();
    +-    }
    +-
    +-    @SmallTest
    +-    public void testHonorAlertOnlyOnceForBeep() throws Exception {
    +-        NotificationRecord r = getBeepyNotification();
    +-        NotificationRecord s = getBeepyOnceNotification();
    +-        s.isUpdate = true;
    +-
    +-        // set up internal state
    +-        mService.buzzBeepBlinkLocked(r);
    +-        Mockito.reset(mRingtonePlayer);
    +-
    +-        // update should not beep
    +-        mService.buzzBeepBlinkLocked(s);
    +-        verifyNeverBeep();
    +-    }
    +-
    +-    @SmallTest
    +-    public void testNoisyUpdateDoesNotCancelAudio() throws Exception {
    +-        NotificationRecord r = getBeepyNotification();
    +-
    +-        mService.buzzBeepBlinkLocked(r);
    +-        r.isUpdate = true;
    +-        mService.buzzBeepBlinkLocked(r);
    +-
    +-        verifyNeverStopAudio();
    +-    }
    +-
    +-    @SmallTest
    +-    public void testNoisyOnceUpdateDoesNotCancelAudio() throws Exception {
    +-        NotificationRecord r = getBeepyNotification();
    +-        NotificationRecord s = getBeepyOnceNotification();
    +-        s.isUpdate = true;
    +-
    +-        mService.buzzBeepBlinkLocked(r);
    +-        mService.buzzBeepBlinkLocked(s);
    +-
    +-        verifyNeverStopAudio();
    +-    }
    +-
    +-    @SmallTest
    +-    public void testQuietUpdateDoesNotCancelAudioFromOther() throws Exception {
    +-        NotificationRecord r = getBeepyNotification();
    +-        NotificationRecord s = getQuietNotification();
    +-        s.isUpdate = true;
    +-        NotificationRecord other = getNoisyOtherNotification();
    +-
    +-        // set up internal state
    +-        mService.buzzBeepBlinkLocked(r);
    +-        mService.buzzBeepBlinkLocked(other); // this takes the audio stream
    +-        Mockito.reset(mRingtonePlayer);
    +-
    +-        // should not stop noise, since we no longer own it
    +-        mService.buzzBeepBlinkLocked(s); // this no longer owns the stream
    +-        verifyNeverStopAudio();
    +-    }
    +-
    +-    @SmallTest
    +-    public void testQuietInterloperDoesNotCancelAudio() throws Exception {
    +-        NotificationRecord r = getBeepyNotification();
    +-        NotificationRecord other = getQuietOtherNotification();
    +-
    +-        // set up internal state
    +-        mService.buzzBeepBlinkLocked(r);
    +-        Mockito.reset(mRingtonePlayer);
    +-
    +-        // should not stop noise, since it does not own it
    +-        mService.buzzBeepBlinkLocked(other);
    +-        verifyNeverStopAudio();
    +-    }
    +-
    +-    @SmallTest
    +-    public void testQuietUpdateCancelsAudio() throws Exception {
    +-        NotificationRecord r = getBeepyNotification();
    +-        NotificationRecord s = getQuietNotification();
    +-        s.isUpdate = true;
    +-
    +-        // set up internal state
    +-        mService.buzzBeepBlinkLocked(r);
    +-        Mockito.reset(mRingtonePlayer);
    +-
    +-        // quiet update should stop making noise
    +-        mService.buzzBeepBlinkLocked(s);
    +-        verifyStopAudio();
    +-    }
    +-
    +-    @SmallTest
    +-    public void testQuietOnceUpdateCancelsAudio() throws Exception {
    +-        NotificationRecord r = getBeepyNotification();
    +-        NotificationRecord s = getQuietOnceNotification();
    +-        s.isUpdate = true;
    +-
    +-        // set up internal state
    +-        mService.buzzBeepBlinkLocked(r);
    +-        Mockito.reset(mRingtonePlayer);
    +-
    +-        // stop making noise - this is a weird corner case, but quiet should override once
    +-        mService.buzzBeepBlinkLocked(s);
    +-        verifyStopAudio();
    +-    }
    +-
    +-    @SmallTest
    +-    public void testDemoteSoundToVibrate() throws Exception {
    +-        NotificationRecord r = getBeepyNotification();
    +-
    +-        // the phone is quiet
    +-        when(mAudioManager.getStreamVolume(anyInt())).thenReturn(0);
    +-        when(mAudioManager.getRingerModeInternal()).thenReturn(AudioManager.RINGER_MODE_VIBRATE);
    +-
    +-        mService.buzzBeepBlinkLocked(r);
    +-
    +-        verifyNeverBeep();
    +-        verifyVibrate();
    +-    }
    +-
    +-    @SmallTest
    +-    public void testDemotInsistenteSoundToVibrate() throws Exception {
    +-        NotificationRecord r = getInsistentBeepyNotification();
    +-
    +-        // the phone is quiet
    +-        when(mAudioManager.getStreamVolume(anyInt())).thenReturn(0);
    +-        when(mAudioManager.getRingerModeInternal()).thenReturn(AudioManager.RINGER_MODE_VIBRATE);
    +-
    +-        mService.buzzBeepBlinkLocked(r);
    +-
    +-        verifyVibrateLooped();
    +-    }
    +-
    +-    @SmallTest
    +-    public void testVibrate() throws Exception {
    +-        NotificationRecord r = getBuzzyNotification();
    +-
    +-        mService.buzzBeepBlinkLocked(r);
    +-
    +-        verifyNeverBeep();
    +-        verifyVibrate();
    +-    }
    +-
    +-    @SmallTest
    +-    public void testInsistenteVibrate() throws Exception {
    +-        NotificationRecord r = getInsistentBuzzyNotification();
    +-
    +-        mService.buzzBeepBlinkLocked(r);
    +-        verifyVibrateLooped();
    +-    }
    +-
    +-    @SmallTest
    +-    public void testVibratTwice() throws Exception {
    +-        NotificationRecord r = getBuzzyNotification();
    +-
    +-        // set up internal state
    +-        mService.buzzBeepBlinkLocked(r);
    +-        Mockito.reset(mVibrator);
    +-
    +-        // update should vibrate
    +-        r.isUpdate = true;
    +-        mService.buzzBeepBlinkLocked(r);
    +-        verifyVibrate();
    +-    }
    +-
    +-    @SmallTest
    +-    public void testHonorAlertOnlyOnceForBuzz() throws Exception {
    +-        NotificationRecord r = getBuzzyNotification();
    +-        NotificationRecord s = getBuzzyOnceNotification();
    +-        s.isUpdate = true;
    +-
    +-        // set up internal state
    +-        mService.buzzBeepBlinkLocked(r);
    +-        Mockito.reset(mVibrator);
    +-
    +-        // update should not beep
    +-        mService.buzzBeepBlinkLocked(s);
    +-        verifyNeverVibrate();
    +-    }
    +-
    +-    @SmallTest
    +-    public void testNoisyUpdateDoesNotCancelVibrate() throws Exception {
    +-        NotificationRecord r = getBuzzyNotification();
    +-
    +-        mService.buzzBeepBlinkLocked(r);
    +-        r.isUpdate = true;
    +-        mService.buzzBeepBlinkLocked(r);
    +-
    +-        verifyNeverStopVibrate();
    +-    }
    +-
    +-    @SmallTest
    +-    public void testNoisyOnceUpdateDoesNotCancelVibrate() throws Exception {
    +-        NotificationRecord r = getBuzzyNotification();
    +-        NotificationRecord s = getBuzzyOnceNotification();
    +-        s.isUpdate = true;
    +-
    +-        mService.buzzBeepBlinkLocked(r);
    +-        mService.buzzBeepBlinkLocked(s);
    +-
    +-        verifyNeverStopVibrate();
    +-    }
    +-
    +-    @SmallTest
    +-    public void testQuietUpdateDoesNotCancelVibrateFromOther() throws Exception {
    +-        NotificationRecord r = getBuzzyNotification();
    +-        NotificationRecord s = getQuietNotification();
    +-        s.isUpdate = true;
    +-        NotificationRecord other = getNoisyOtherNotification();
    +-
    +-        // set up internal state
    +-        mService.buzzBeepBlinkLocked(r);
    +-        mService.buzzBeepBlinkLocked(other); // this takes the vibrate stream
    +-        Mockito.reset(mVibrator);
    +-
    +-        // should not stop vibrate, since we no longer own it
    +-        mService.buzzBeepBlinkLocked(s); // this no longer owns the stream
    +-        verifyNeverStopVibrate();
    +-    }
    +-
    +-    @SmallTest
    +-    public void testQuietInterloperDoesNotCancelVibrate() throws Exception {
    +-        NotificationRecord r = getBuzzyNotification();
    +-        NotificationRecord other = getQuietOtherNotification();
    +-
    +-        // set up internal state
    +-        mService.buzzBeepBlinkLocked(r);
    +-        Mockito.reset(mVibrator);
    +-
    +-        // should not stop noise, since it does not own it
    +-        mService.buzzBeepBlinkLocked(other);
    +-        verifyNeverStopVibrate();
    +-    }
    +-
    +-    @SmallTest
    +-    public void testQuietUpdateCancelsVibrate() throws Exception {
    +-        NotificationRecord r = getBuzzyNotification();
    +-        NotificationRecord s = getQuietNotification();
    +-        s.isUpdate = true;
    +-
    +-        // set up internal state
    +-        mService.buzzBeepBlinkLocked(r);
    +-
    +-        // quiet update should stop making noise
    +-        mService.buzzBeepBlinkLocked(s);
    +-        verifyStopVibrate();
    +-    }
    +-
    +-    @SmallTest
    +-    public void testQuietOnceUpdateCancelsvibrate() throws Exception {
    +-        NotificationRecord r = getBuzzyNotification();
    +-        NotificationRecord s = getQuietOnceNotification();
    +-        s.isUpdate = true;
    +-
    +-        // set up internal state
    +-        mService.buzzBeepBlinkLocked(r);
    +-        Mockito.reset(mVibrator);
    +-
    +-        // stop making noise - this is a weird corner case, but quiet should override once
    +-        mService.buzzBeepBlinkLocked(s);
    +-        verifyStopVibrate();
    +-    }
    +-
    +-    @SmallTest
    +-    public void testQuietUpdateCancelsDemotedVibrate() throws Exception {
    +-        NotificationRecord r = getBeepyNotification();
    +-        NotificationRecord s = getQuietNotification();
    +-
    +-        // the phone is quiet
    +-        when(mAudioManager.getStreamVolume(anyInt())).thenReturn(0);
    +-        when(mAudioManager.getRingerModeInternal()).thenReturn(AudioManager.RINGER_MODE_VIBRATE);
    +-
    +-        mService.buzzBeepBlinkLocked(r);
    +-
    +-        // quiet update should stop making noise
    +-        mService.buzzBeepBlinkLocked(s);
    +-        verifyStopVibrate();
    +-    }
    +-}
    +diff --git a/services/tests/servicestests/src/com/android/server/notification/RankingHelperTest.java b/services/tests/servicestests/src/com/android/server/notification/RankingHelperTest.java
    +deleted file mode 100644
    +index 32501ad..0000000
    +--- a/services/tests/servicestests/src/com/android/server/notification/RankingHelperTest.java
    ++++ /dev/null
    +@@ -1,143 +0,0 @@
    +-/*
    +- * Copyright (C) 2014 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 com.android.server.notification;
    +-
    +-import org.mockito.Mock;
    +-import org.mockito.MockitoAnnotations;
    +-
    +-import android.app.Notification;
    +-import android.os.UserHandle;
    +-import android.service.notification.StatusBarNotification;
    +-import android.test.AndroidTestCase;
    +-import android.test.suitebuilder.annotation.SmallTest;
    +-
    +-import java.util.ArrayList;
    +-
    +-public class RankingHelperTest extends AndroidTestCase {
    +-    @Mock NotificationUsageStats mUsageStats;
    +-    @Mock RankingHandler handler;
    +-
    +-    private Notification mNotiGroupGSortA;
    +-    private Notification mNotiGroupGSortB;
    +-    private Notification mNotiNoGroup;
    +-    private Notification mNotiNoGroup2;
    +-    private Notification mNotiNoGroupSortA;
    +-    private NotificationRecord mRecordGroupGSortA;
    +-    private NotificationRecord mRecordGroupGSortB;
    +-    private NotificationRecord mRecordNoGroup;
    +-    private NotificationRecord mRecordNoGroup2;
    +-    private NotificationRecord mRecordNoGroupSortA;
    +-    private RankingHelper mHelper;
    +-
    +-    @Override
    +-    public void setUp() {
    +-        MockitoAnnotations.initMocks(this);
    +-        UserHandle user = UserHandle.ALL;
    +-
    +-        mHelper = new RankingHelper(getContext(), handler, mUsageStats,
    +-                new String[] {ImportanceExtractor.class.getName()});
    +-
    +-        mNotiGroupGSortA = new Notification.Builder(getContext())
    +-                .setContentTitle("A")
    +-                .setGroup("G")
    +-                .setSortKey("A")
    +-                .setWhen(1205)
    +-                .build();
    +-        mRecordGroupGSortA = new NotificationRecord(getContext(), new StatusBarNotification(
    +-                "package", "package", 1, null, 0, 0, 0, mNotiGroupGSortA, user));
    +-
    +-        mNotiGroupGSortB = new Notification.Builder(getContext())
    +-                .setContentTitle("B")
    +-                .setGroup("G")
    +-                .setSortKey("B")
    +-                .setWhen(1200)
    +-                .build();
    +-        mRecordGroupGSortB = new NotificationRecord(getContext(), new StatusBarNotification(
    +-                "package", "package", 1, null, 0, 0, 0, mNotiGroupGSortB, user));
    +-
    +-        mNotiNoGroup = new Notification.Builder(getContext())
    +-                .setContentTitle("C")
    +-                .setWhen(1201)
    +-                .build();
    +-        mRecordNoGroup = new NotificationRecord(getContext(), new StatusBarNotification(
    +-                "package", "package", 1, null, 0, 0, 0, mNotiNoGroup, user));
    +-
    +-        mNotiNoGroup2 = new Notification.Builder(getContext())
    +-                .setContentTitle("D")
    +-                .setWhen(1202)
    +-                .build();
    +-        mRecordNoGroup2 = new NotificationRecord(getContext(), new StatusBarNotification(
    +-                "package", "package", 1, null, 0, 0, 0, mNotiNoGroup2, user));
    +-
    +-        mNotiNoGroupSortA = new Notification.Builder(getContext())
    +-                .setContentTitle("E")
    +-                .setWhen(1201)
    +-                .setSortKey("A")
    +-                .build();
    +-        mRecordNoGroupSortA = new NotificationRecord(getContext(), new StatusBarNotification(
    +-                "package", "package", 1, null, 0, 0, 0, mNotiNoGroupSortA, user));
    +-    }
    +-
    +-    @SmallTest
    +-    public void testFindAfterRankingWithASplitGroup() throws Exception {
    +-        ArrayList<NotificationRecord> notificationList = new ArrayList<NotificationRecord>(3);
    +-        notificationList.add(mRecordGroupGSortA);
    +-        notificationList.add(mRecordGroupGSortB);
    +-        notificationList.add(mRecordNoGroup);
    +-        notificationList.add(mRecordNoGroupSortA);
    +-        mHelper.sort(notificationList);
    +-        assertTrue(mHelper.indexOf(notificationList, mRecordGroupGSortA) >= 0);
    +-        assertTrue(mHelper.indexOf(notificationList, mRecordGroupGSortB) >= 0);
    +-        assertTrue(mHelper.indexOf(notificationList, mRecordNoGroup) >= 0);
    +-        assertTrue(mHelper.indexOf(notificationList, mRecordNoGroupSortA) >= 0);
    +-    }
    +-
    +-    @SmallTest
    +-    public void testSortShouldNotThrowWithPlainNotifications() throws Exception {
    +-        ArrayList<NotificationRecord> notificationList = new ArrayList<NotificationRecord>(2);
    +-        notificationList.add(mRecordNoGroup);
    +-        notificationList.add(mRecordNoGroup2);
    +-        mHelper.sort(notificationList);
    +-    }
    +-
    +-    @SmallTest
    +-    public void testSortShouldNotThrowOneSorted() throws Exception {
    +-        ArrayList<NotificationRecord> notificationList = new ArrayList<NotificationRecord>(2);
    +-        notificationList.add(mRecordNoGroup);
    +-        notificationList.add(mRecordNoGroupSortA);
    +-        mHelper.sort(notificationList);
    +-    }
    +-
    +-    @SmallTest
    +-    public void testSortShouldNotThrowOneNotification() throws Exception {
    +-        ArrayList<NotificationRecord> notificationList = new ArrayList<NotificationRecord>(1);
    +-        notificationList.add(mRecordNoGroup);
    +-        mHelper.sort(notificationList);
    +-    }
    +-
    +-    @SmallTest
    +-    public void testSortShouldNotThrowOneSortKey() throws Exception {
    +-        ArrayList<NotificationRecord> notificationList = new ArrayList<NotificationRecord>(1);
    +-        notificationList.add(mRecordGroupGSortB);
    +-        mHelper.sort(notificationList);
    +-    }
    +-
    +-    @SmallTest
    +-    public void testSortShouldNotThrowOnEmptyList() throws Exception {
    +-        ArrayList<NotificationRecord> notificationList = new ArrayList<NotificationRecord>();
    +-        mHelper.sort(notificationList);
    +-    }
    +-}
    +diff --git a/services/tests/servicestests/src/com/android/server/notification/RateEstimatorTest.java b/services/tests/servicestests/src/com/android/server/notification/RateEstimatorTest.java
    +deleted file mode 100644
    +index 3278cf1..0000000
    +--- a/services/tests/servicestests/src/com/android/server/notification/RateEstimatorTest.java
    ++++ /dev/null
    +@@ -1,152 +0,0 @@
    +-/*
    +- * Copyright (C) 2016 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 com.android.server.notification;
    +-
    +-
    +-import android.test.AndroidTestCase;
    +-import android.test.suitebuilder.annotation.SmallTest;
    +-
    +-public class RateEstimatorTest extends AndroidTestCase {
    +-    private long mTestStartTime;
    +-    private RateEstimator mEstimator;
    +-
    +-    @Override
    +-    public void setUp() {
    +-        mTestStartTime = 1225731600000L;
    +-        mEstimator = new RateEstimator();
    +-    }
    +-
    +-    @SmallTest
    +-    public void testRunningTimeBackwardDoesntExplodeUpdate() throws Exception {
    +-        assertUpdateTime(mTestStartTime);
    +-        assertUpdateTime(mTestStartTime - 1000L);
    +-    }
    +-
    +-    @SmallTest
    +-    public void testRunningTimeBackwardDoesntExplodeGet() throws Exception {
    +-        assertUpdateTime(mTestStartTime);
    +-        final float rate = mEstimator.getRate(mTestStartTime - 1000L);
    +-        assertFalse(Float.isInfinite(rate));
    +-        assertFalse(Float.isNaN(rate));
    +-    }
    +-
    +-    @SmallTest
    +-    public void testInstantaneousEventsDontExplodeUpdate() throws Exception {
    +-        assertUpdateTime(mTestStartTime);
    +-        assertUpdateTime(mTestStartTime);
    +-    }
    +-
    +-    @SmallTest
    +-    public void testInstantaneousEventsDontExplodeGet() throws Exception {
    +-        assertUpdateTime(mTestStartTime);
    +-        assertUpdateTime(mTestStartTime);
    +-        final float rate = mEstimator.getRate(mTestStartTime);
    +-        assertFalse(Float.isInfinite(rate));
    +-        assertFalse(Float.isNaN(rate));
    +-    }
    +-
    +-    @SmallTest
    +-    public void testInstantaneousBurstIsEstimatedUnderTwoPercent() throws Exception {
    +-        assertUpdateTime(mTestStartTime);
    +-        long eventStart = mTestStartTime + 1000; // start event a long time after initialization
    +-        long nextEventTime = postEvents(eventStart, 0, 5); // five events at \inf
    +-        final float rate = mEstimator.getRate(nextEventTime);
    +-        assertLessThan("Rate", rate, 20f);
    +-    }
    +-
    +-    @SmallTest
    +-    public void testCompactBurstIsEstimatedUnderTwoPercent() throws Exception {
    +-        assertUpdateTime(mTestStartTime);
    +-        long eventStart = mTestStartTime + 1000; // start event a long time after initialization
    +-        long nextEventTime = postEvents(eventStart, 1, 5); // five events at 1000Hz
    +-        final float rate = mEstimator.getRate(nextEventTime);
    +-        assertLessThan("Rate", rate, 20f);
    +-    }
    +-
    +-    @SmallTest
    +-    public void testSustained1000HzBurstIsEstimatedOverNinetyPercent() throws Exception {
    +-        assertUpdateTime(mTestStartTime);
    +-        long eventStart = mTestStartTime + 1000; // start event a long time after initialization
    +-        long nextEventTime = postEvents(eventStart, 1, 100); // one hundred events at 1000Hz
    +-        final float rate = mEstimator.getRate(nextEventTime);
    +-        assertGreaterThan("Rate", rate, 900f);
    +-    }
    +-
    +-    @SmallTest
    +-    public void testSustained100HzBurstIsEstimatedOverNinetyPercent() throws Exception {
    +-        assertUpdateTime(mTestStartTime);
    +-        long eventStart = mTestStartTime + 1000; // start event a long time after initialization
    +-        long nextEventTime = postEvents(eventStart, 10, 100); // one hundred events at 100Hz
    +-        final float rate = mEstimator.getRate(nextEventTime);
    +-
    +-        assertGreaterThan("Rate", rate, 90f);
    +-    }
    +-
    +-    @SmallTest
    +-    public void testRecoverQuicklyAfterSustainedBurst() throws Exception {
    +-        assertUpdateTime(mTestStartTime);
    +-        long eventStart = mTestStartTime + 1000; // start event a long time after initialization
    +-        long nextEventTime = postEvents(eventStart, 10, 1000); // one hundred events at 100Hz
    +-        final float rate = mEstimator.getRate(nextEventTime + 5000L); // two seconds later
    +-        assertLessThan("Rate", rate, 2f);
    +-    }
    +-
    +-    @SmallTest
    +-    public void testEstimateShouldNotOvershoot() throws Exception {
    +-        assertUpdateTime(mTestStartTime);
    +-        long eventStart = mTestStartTime + 1000; // start event a long time after initialization
    +-        long nextEventTime = postEvents(eventStart, 1, 1000); // one thousand events at 1000Hz
    +-        final float rate = mEstimator.getRate(nextEventTime);
    +-        assertLessThan("Rate", rate, 1000f);
    +-    }
    +-
    +-    @SmallTest
    +-    public void testGetRateWithoutUpdate() throws Exception {
    +-        final float rate = mEstimator.getRate(mTestStartTime);
    +-        assertLessThan("Rate", rate, 0.1f);
    +-    }
    +-
    +-    @SmallTest
    +-    public void testGetRateWithOneUpdate() throws Exception {
    +-        assertUpdateTime(mTestStartTime);
    +-        final float rate = mEstimator.getRate(mTestStartTime+1);
    +-        assertLessThan("Rate", rate, 1f);
    +-    }
    +-
    +-    private void assertLessThan(String label, float a, float b)  {
    +-        assertTrue(String.format("%s was %f, but should be less than %f", label, a, b), a <= b);
    +-    }
    +-
    +-    private void assertGreaterThan(String label, float a, float b)  {
    +-        assertTrue(String.format("%s was %f, but should be more than %f", label, a, b), a >= b);
    +-    }
    +-
    +-    /** @returns the next event time. */
    +-    private long postEvents(long start, long dt, int num) {
    +-        long time = start;
    +-        for (int i = 0; i < num; i++) {
    +-            mEstimator.update(time);
    +-            time += dt;
    +-        }
    +-        return time;
    +-    }
    +-
    +-    private void assertUpdateTime(long time) {
    +-        final float rate = mEstimator.update(time);
    +-        assertFalse(Float.isInfinite(rate));
    +-        assertFalse(Float.isNaN(rate));
    +-    }
    +-}
    +diff --git a/services/tests/servicestests/src/com/android/server/notification/ValidateNotificationPeopleTest.java b/services/tests/servicestests/src/com/android/server/notification/ValidateNotificationPeopleTest.java
    +deleted file mode 100644
    +index a6fdee9..0000000
    +--- a/services/tests/servicestests/src/com/android/server/notification/ValidateNotificationPeopleTest.java
    ++++ /dev/null
    +@@ -1,152 +0,0 @@
    +-/*
    +- * Copyright (C) 2014 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 com.android.server.notification;
    +-
    +-import android.app.Notification;
    +-import android.os.Bundle;
    +-import android.test.AndroidTestCase;
    +-import android.test.suitebuilder.annotation.SmallTest;
    +-import android.text.SpannableString;
    +-
    +-import java.util.ArrayList;
    +-import java.util.Arrays;
    +-
    +-public class ValidateNotificationPeopleTest extends AndroidTestCase {
    +-
    +-    @SmallTest
    +-    public void testNoExtra() throws Exception {
    +-        Bundle bundle = new Bundle();
    +-        String[] result = ValidateNotificationPeople.getExtraPeople(bundle);
    +-        assertNull("lack of extra should return null", result);
    +-    }
    +-
    +-    @SmallTest
    +-    public void testSingleString() throws Exception {
    +-        String[] expected = { "foobar" };
    +-        Bundle bundle = new Bundle();
    +-        bundle.putString(Notification.EXTRA_PEOPLE, expected[0]);
    +-        String[] result = ValidateNotificationPeople.getExtraPeople(bundle);
    +-        assertStringArrayEquals("string should be in result[0]", expected, result);
    +-    }
    +-
    +-    @SmallTest
    +-    public void testSingleCharArray() throws Exception {
    +-        String[] expected = { "foobar" };
    +-        Bundle bundle = new Bundle();
    +-        bundle.putCharArray(Notification.EXTRA_PEOPLE, expected[0].toCharArray());
    +-        String[] result = ValidateNotificationPeople.getExtraPeople(bundle);
    +-        assertStringArrayEquals("char[] should be in result[0]", expected, result);
    +-    }
    +-
    +-    @SmallTest
    +-    public void testSingleCharSequence() throws Exception {
    +-        String[] expected = { "foobar" };
    +-        Bundle bundle = new Bundle();
    +-        bundle.putCharSequence(Notification.EXTRA_PEOPLE, new SpannableString(expected[0]));
    +-        String[] result = ValidateNotificationPeople.getExtraPeople(bundle);
    +-        assertStringArrayEquals("charSequence should be in result[0]", expected, result);
    +-    }
    +-
    +-    @SmallTest
    +-    public void testStringArraySingle() throws Exception {
    +-        Bundle bundle = new Bundle();
    +-        String[] expected = { "foobar" };
    +-        bundle.putStringArray(Notification.EXTRA_PEOPLE, expected);
    +-        String[] result = ValidateNotificationPeople.getExtraPeople(bundle);
    +-        assertStringArrayEquals("wrapped string should be in result[0]", expected, result);
    +-    }
    +-
    +-    @SmallTest
    +-    public void testStringArrayMultiple() throws Exception {
    +-        Bundle bundle = new Bundle();
    +-        String[] expected = { "foo", "bar", "baz" };
    +-        bundle.putStringArray(Notification.EXTRA_PEOPLE, expected);
    +-        String[] result = ValidateNotificationPeople.getExtraPeople(bundle);
    +-        assertStringArrayEquals("testStringArrayMultiple", expected, result);
    +-    }
    +-
    +-    @SmallTest
    +-    public void testStringArrayNulls() throws Exception {
    +-        Bundle bundle = new Bundle();
    +-        String[] expected = { "foo", null, "baz" };
    +-        bundle.putStringArray(Notification.EXTRA_PEOPLE, expected);
    +-        String[] result = ValidateNotificationPeople.getExtraPeople(bundle);
    +-        assertStringArrayEquals("testStringArrayNulls", expected, result);
    +-    }
    +-
    +-    @SmallTest
    +-    public void testCharSequenceArrayMultiple() throws Exception {
    +-        Bundle bundle = new Bundle();
    +-        String[] expected = { "foo", "bar", "baz" };
    +-        CharSequence[] charSeqArray = new CharSequence[expected.length];
    +-        for (int i = 0; i < expected.length; i++) {
    +-            charSeqArray[i] = new SpannableString(expected[i]);
    +-        }
    +-        bundle.putCharSequenceArray(Notification.EXTRA_PEOPLE, charSeqArray);
    +-        String[] result = ValidateNotificationPeople.getExtraPeople(bundle);
    +-        assertStringArrayEquals("testCharSequenceArrayMultiple", expected, result);
    +-    }
    +-
    +-    @SmallTest
    +-    public void testMixedCharSequenceArrayList() throws Exception {
    +-        Bundle bundle = new Bundle();
    +-        String[] expected = { "foo", "bar", "baz" };
    +-        CharSequence[] charSeqArray = new CharSequence[expected.length];
    +-        for (int i = 0; i < expected.length; i++) {
    +-            if (i % 2 == 0) {
    +-                charSeqArray[i] = expected[i];
    +-            } else {
    +-                charSeqArray[i] = new SpannableString(expected[i]);
    +-            }
    +-        }
    +-        bundle.putCharSequenceArray(Notification.EXTRA_PEOPLE, charSeqArray);
    +-        String[] result = ValidateNotificationPeople.getExtraPeople(bundle);
    +-        assertStringArrayEquals("testMixedCharSequenceArrayList", expected, result);
    +-    }
    +-
    +-    @SmallTest
    +-    public void testStringArrayList() throws Exception {
    +-        Bundle bundle = new Bundle();
    +-        String[] expected = { "foo", null, "baz" };
    +-        final ArrayList<String> stringArrayList = new ArrayList<String>(expected.length);
    +-        for (int i = 0; i < expected.length; i++) {
    +-            stringArrayList.add(expected[i]);
    +-        }
    +-        bundle.putStringArrayList(Notification.EXTRA_PEOPLE, stringArrayList);
    +-        String[] result = ValidateNotificationPeople.getExtraPeople(bundle);
    +-        assertStringArrayEquals("testStringArrayList", expected, result);
    +-    }
    +-
    +-    @SmallTest
    +-    public void testCharSequenceArrayList() throws Exception {
    +-        Bundle bundle = new Bundle();
    +-        String[] expected = { "foo", "bar", "baz" };
    +-        final ArrayList<CharSequence> stringArrayList =
    +-                new ArrayList<CharSequence>(expected.length);
    +-        for (int i = 0; i < expected.length; i++) {
    +-            stringArrayList.add(new SpannableString(expected[i]));
    +-        }
    +-        bundle.putCharSequenceArrayList(Notification.EXTRA_PEOPLE, stringArrayList);
    +-        String[] result = ValidateNotificationPeople.getExtraPeople(bundle);
    +-        assertStringArrayEquals("testCharSequenceArrayList", expected, result);
    +-    }
    +-
    +-    private void assertStringArrayEquals(String message, String[] expected, String[] result) {
    +-        String expectedString = Arrays.toString(expected);
    +-        String resultString = Arrays.toString(result);
    +-        assertEquals(message + ": arrays differ", expectedString, resultString);
    +-    }
    +-}
    +diff --git a/services/tests/servicestests/src/com/android/server/pm/BaseShortcutManagerTest.java b/services/tests/servicestests/src/com/android/server/pm/BaseShortcutManagerTest.java
    +deleted file mode 100644
    +index 1c7a138..0000000
    +--- a/services/tests/servicestests/src/com/android/server/pm/BaseShortcutManagerTest.java
    ++++ /dev/null
    +@@ -1,1929 +0,0 @@
    +-/*
    +- * Copyright (C) 2016 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 com.android.server.pm;
    +-
    +-import static com.android.server.pm.shortcutmanagertest.ShortcutManagerTestUtils.cloneShortcutList;
    +-import static com.android.server.pm.shortcutmanagertest.ShortcutManagerTestUtils.hashSet;
    +-import static com.android.server.pm.shortcutmanagertest.ShortcutManagerTestUtils.list;
    +-import static com.android.server.pm.shortcutmanagertest.ShortcutManagerTestUtils.makeBundle;
    +-import static com.android.server.pm.shortcutmanagertest.ShortcutManagerTestUtils.set;
    +-
    +-import static org.mockito.Matchers.any;
    +-import static org.mockito.Matchers.anyInt;
    +-import static org.mockito.Matchers.anyString;
    +-import static org.mockito.Matchers.eq;
    +-import static org.mockito.Mockito.doAnswer;
    +-import static org.mockito.Mockito.mock;
    +-import static org.mockito.Mockito.reset;
    +-import static org.mockito.Mockito.spy;
    +-import static org.mockito.Mockito.times;
    +-import static org.mockito.Mockito.verify;
    +-import static org.mockito.Mockito.when;
    +-
    +-import android.annotation.NonNull;
    +-import android.annotation.UserIdInt;
    +-import android.app.Activity;
    +-import android.app.ActivityManager;
    +-import android.app.ActivityManagerInternal;
    +-import android.app.IUidObserver;
    +-import android.app.usage.UsageStatsManagerInternal;
    +-import android.content.ActivityNotFoundException;
    +-import android.content.BroadcastReceiver;
    +-import android.content.ComponentName;
    +-import android.content.Context;
    +-import android.content.Intent;
    +-import android.content.IntentFilter;
    +-import android.content.pm.ActivityInfo;
    +-import android.content.pm.ApplicationInfo;
    +-import android.content.pm.ILauncherApps;
    +-import android.content.pm.LauncherApps;
    +-import android.content.pm.LauncherApps.ShortcutQuery;
    +-import android.content.pm.PackageInfo;
    +-import android.content.pm.PackageManager;
    +-import android.content.pm.PackageManagerInternal;
    +-import android.content.pm.ResolveInfo;
    +-import android.content.pm.ShortcutInfo;
    +-import android.content.pm.ShortcutManager;
    +-import android.content.pm.ShortcutServiceInternal;
    +-import android.content.pm.Signature;
    +-import android.content.pm.UserInfo;
    +-import android.content.res.Resources;
    +-import android.content.res.XmlResourceParser;
    +-import android.graphics.drawable.Icon;
    +-import android.net.Uri;
    +-import android.os.Bundle;
    +-import android.os.FileUtils;
    +-import android.os.Handler;
    +-import android.os.Looper;
    +-import android.os.PersistableBundle;
    +-import android.os.Process;
    +-import android.os.UserHandle;
    +-import android.os.UserManager;
    +-import android.test.InstrumentationTestCase;
    +-import android.test.mock.MockContext;
    +-import android.util.Log;
    +-import android.util.Pair;
    +-
    +-import com.android.internal.util.Preconditions;
    +-import com.android.server.LocalServices;
    +-import com.android.server.SystemService;
    +-import com.android.server.pm.LauncherAppsService.LauncherAppsImpl;
    +-import com.android.server.pm.ShortcutUser.PackageWithUser;
    +-
    +-import org.junit.Assert;
    +-import org.mockito.ArgumentCaptor;
    +-import org.mockito.invocation.InvocationOnMock;
    +-import org.mockito.stubbing.Answer;
    +-
    +-import java.io.BufferedReader;
    +-import java.io.ByteArrayOutputStream;
    +-import java.io.File;
    +-import java.io.FileReader;
    +-import java.io.IOException;
    +-import java.io.InputStreamReader;
    +-import java.io.PrintWriter;
    +-import java.util.ArrayList;
    +-import java.util.HashMap;
    +-import java.util.HashSet;
    +-import java.util.LinkedHashMap;
    +-import java.util.List;
    +-import java.util.Locale;
    +-import java.util.Map;
    +-import java.util.Set;
    +-import java.util.function.BiFunction;
    +-import java.util.function.BiPredicate;
    +-import java.util.function.Consumer;
    +-import java.util.function.Function;
    +-
    +-public abstract class BaseShortcutManagerTest extends InstrumentationTestCase {
    +-    protected static final String TAG = "ShortcutManagerTest";
    +-
    +-    protected static final boolean DUMP_IN_TEARDOWN = false; // DO NOT SUBMIT WITH true
    +-
    +-    /**
    +-     * Whether to enable dump or not.  Should be only true when debugging to avoid bugs where
    +-     * dump affecting the behavior.
    +-     */
    +-    protected static final boolean ENABLE_DUMP = false // DO NOT SUBMIT WITH true
    +-            || DUMP_IN_TEARDOWN || ShortcutService.DEBUG;
    +-
    +-    protected static final String[] EMPTY_STRINGS = new String[0]; // Just for readability.
    +-
    +-    protected static final String MAIN_ACTIVITY_CLASS = "MainActivity";
    +-
    +-    // public for mockito
    +-    public class BaseContext extends MockContext {
    +-        @Override
    +-        public Object getSystemService(String name) {
    +-            switch (name) {
    +-                case Context.USER_SERVICE:
    +-                    return mMockUserManager;
    +-            }
    +-            throw new UnsupportedOperationException();
    +-        }
    +-
    +-        @Override
    +-        public String getSystemServiceName(Class<?> serviceClass) {
    +-            return getTestContext().getSystemServiceName(serviceClass);
    +-        }
    +-
    +-        @Override
    +-        public PackageManager getPackageManager() {
    +-            return mMockPackageManager;
    +-        }
    +-
    +-        @Override
    +-        public Resources getResources() {
    +-            return getTestContext().getResources();
    +-        }
    +-
    +-        @Override
    +-        public Intent registerReceiverAsUser(BroadcastReceiver receiver, UserHandle user,
    +-                IntentFilter filter, String broadcastPermission, Handler scheduler) {
    +-            // ignore.
    +-            return null;
    +-        }
    +-
    +-        @Override
    +-        public void unregisterReceiver(BroadcastReceiver receiver) {
    +-            // ignore.
    +-        }
    +-    }
    +-
    +-    /** Context used in the client side */
    +-    public class ClientContext extends BaseContext {
    +-        @Override
    +-        public String getPackageName() {
    +-            return mInjectedClientPackage;
    +-        }
    +-
    +-        @Override
    +-        public int getUserId() {
    +-            return getCallingUserId();
    +-        }
    +-    }
    +-
    +-    /** Context used in the service side */
    +-    public class ServiceContext extends BaseContext {
    +-        long injectClearCallingIdentity() {
    +-            final int prevCallingUid = mInjectedCallingUid;
    +-            mInjectedCallingUid = Process.SYSTEM_UID;
    +-            return prevCallingUid;
    +-        }
    +-
    +-        void injectRestoreCallingIdentity(long token) {
    +-            mInjectedCallingUid = (int) token;
    +-        }
    +-
    +-        @Override
    +-        public int getUserId() {
    +-            return UserHandle.USER_SYSTEM;
    +-        }
    +-
    +-        public PackageInfo injectGetActivitiesWithMetadata(
    +-                String packageName, @UserIdInt int userId) {
    +-            return BaseShortcutManagerTest.this.injectGetActivitiesWithMetadata(packageName, userId);
    +-        }
    +-
    +-        public XmlResourceParser injectXmlMetaData(ActivityInfo activityInfo, String key) {
    +-            return BaseShortcutManagerTest.this.injectXmlMetaData(activityInfo, key);
    +-        }
    +-    }
    +-
    +-    /** ShortcutService with injection override methods. */
    +-    protected final class ShortcutServiceTestable extends ShortcutService {
    +-        final ServiceContext mContext;
    +-        IUidObserver mUidObserver;
    +-
    +-        public ShortcutServiceTestable(ServiceContext context, Looper looper) {
    +-            super(context, looper, /* onyForPackageManagerApis */ false);
    +-            mContext = context;
    +-        }
    +-
    +-        @Override
    +-        public String injectGetLocaleTagsForUser(@UserIdInt int userId) {
    +-            return mInjectedLocale.toLanguageTag();
    +-        }
    +-
    +-        @Override
    +-        boolean injectShouldPerformVerification() {
    +-            return true; // Always verify during unit tests.
    +-        }
    +-
    +-        @Override
    +-        String injectShortcutManagerConstants() {
    +-            return ConfigConstants.KEY_RESET_INTERVAL_SEC + "=" + (INTERVAL / 1000) + ","
    +-                    + ConfigConstants.KEY_MAX_SHORTCUTS + "=" + MAX_SHORTCUTS + ","
    +-                    + ConfigConstants.KEY_MAX_UPDATES_PER_INTERVAL + "="
    +-                    + MAX_UPDATES_PER_INTERVAL + ","
    +-                    + ConfigConstants.KEY_MAX_ICON_DIMENSION_DP + "=" + MAX_ICON_DIMENSION + ","
    +-                    + ConfigConstants.KEY_MAX_ICON_DIMENSION_DP_LOWRAM + "="
    +-                    + MAX_ICON_DIMENSION_LOWRAM + ","
    +-                    + ConfigConstants.KEY_ICON_FORMAT + "=PNG,"
    +-                    + ConfigConstants.KEY_ICON_QUALITY + "=100";
    +-        }
    +-
    +-        @Override
    +-        long injectClearCallingIdentity() {
    +-            return mContext.injectClearCallingIdentity();
    +-        }
    +-
    +-        @Override
    +-        void injectRestoreCallingIdentity(long token) {
    +-            mContext.injectRestoreCallingIdentity(token);
    +-        }
    +-
    +-        @Override
    +-        int injectDipToPixel(int dip) {
    +-            return dip;
    +-        }
    +-
    +-        @Override
    +-        long injectCurrentTimeMillis() {
    +-            return mInjectedCurrentTimeMillis;
    +-        }
    +-
    +-        @Override
    +-        long injectElapsedRealtime() {
    +-            // TODO This should be kept separately from mInjectedCurrentTimeMillis, since
    +-            // this should increase even if we rewind mInjectedCurrentTimeMillis in some tests.
    +-            return mInjectedCurrentTimeMillis - START_TIME;
    +-        }
    +-
    +-        @Override
    +-        int injectBinderCallingUid() {
    +-            return mInjectedCallingUid;
    +-        }
    +-
    +-        @Override
    +-        int injectGetPackageUid(String packageName, int userId) {
    +-            return getInjectedPackageInfo(packageName, userId, false).applicationInfo.uid;
    +-        }
    +-
    +-        @Override
    +-        File injectSystemDataPath() {
    +-            return new File(mInjectedFilePathRoot, "system");
    +-        }
    +-
    +-        @Override
    +-        File injectUserDataPath(@UserIdInt int userId) {
    +-            return new File(mInjectedFilePathRoot, "user-" + userId);
    +-        }
    +-
    +-        @Override
    +-        void injectValidateIconResPackage(ShortcutInfo shortcut, Icon icon) {
    +-            // Can't check
    +-        }
    +-
    +-        @Override
    +-        boolean injectIsLowRamDevice() {
    +-            return mInjectedIsLowRamDevice;
    +-        }
    +-
    +-        @Override
    +-        void injectRegisterUidObserver(IUidObserver observer, int which) {
    +-            mUidObserver = observer;
    +-        }
    +-
    +-        @Override
    +-        boolean hasShortcutHostPermission(@NonNull String callingPackage, int userId) {
    +-            return mDefaultLauncherChecker.test(callingPackage, userId);
    +-        }
    +-
    +-        @Override
    +-        PackageInfo injectPackageInfoWithUninstalled(String packageName, @UserIdInt int userId,
    +-                boolean getSignatures) {
    +-            return getInjectedPackageInfo(packageName, userId, getSignatures);
    +-        }
    +-
    +-        @Override
    +-        ApplicationInfo injectApplicationInfoWithUninstalled(
    +-                String packageName, @UserIdInt int userId) {
    +-            PackageInfo pi = injectPackageInfoWithUninstalled(
    +-                    packageName, userId, /* getSignatures= */ false);
    +-            return pi != null ? pi.applicationInfo : null;
    +-        }
    +-
    +-        @Override
    +-        List<PackageInfo> injectGetPackagesWithUninstalled(@UserIdInt int userId) {
    +-            return BaseShortcutManagerTest.this.getInstalledPackagesWithUninstalled(userId);
    +-        }
    +-
    +-        @Override
    +-        ActivityInfo injectGetActivityInfoWithMetadataWithUninstalled(ComponentName activity,
    +-                @UserIdInt int userId) {
    +-            final PackageInfo pi = mContext.injectGetActivitiesWithMetadata(
    +-                    activity.getPackageName(), userId);
    +-            if (pi == null || pi.activities == null) {
    +-                return null;
    +-            }
    +-            for (ActivityInfo ai : pi.activities) {
    +-                if (!mEnabledActivityChecker.test(ai.getComponentName(), userId)) {
    +-                    continue;
    +-                }
    +-                if (activity.equals(ai.getComponentName())) {
    +-                    return ai;
    +-                }
    +-            }
    +-            return null;
    +-        }
    +-
    +-        @Override
    +-        boolean injectIsMainActivity(@NonNull ComponentName activity, int userId) {
    +-            if (!mEnabledActivityChecker.test(activity, userId)) {
    +-                return false;
    +-            }
    +-            return mMainActivityChecker.test(activity, userId);
    +-        }
    +-
    +-        @Override
    +-        List<ResolveInfo> injectGetMainActivities(@NonNull String packageName, int userId) {
    +-            final PackageInfo pi = mContext.injectGetActivitiesWithMetadata(
    +-                    packageName, userId);
    +-            if (pi == null || pi.activities == null) {
    +-                return null;
    +-            }
    +-            final ArrayList<ResolveInfo> ret = new ArrayList<>(pi.activities.length);
    +-            for (int i = 0; i < pi.activities.length; i++) {
    +-                if (!mEnabledActivityChecker.test(pi.activities[i].getComponentName(), userId)) {
    +-                    continue;
    +-                }
    +-                final ResolveInfo ri = new ResolveInfo();
    +-                ri.activityInfo = pi.activities[i];
    +-                ret.add(ri);
    +-            }
    +-
    +-            return ret;
    +-        }
    +-
    +-        @Override
    +-        ComponentName injectGetDefaultMainActivity(@NonNull String packageName, int userId) {
    +-            return mMainActivityFetcher.apply(packageName, userId);
    +-        }
    +-
    +-        @Override
    +-        boolean injectIsActivityEnabledAndExported(ComponentName activity, @UserIdInt int userId) {
    +-            return mEnabledActivityChecker.test(activity, userId);
    +-        }
    +-
    +-        @Override
    +-        XmlResourceParser injectXmlMetaData(ActivityInfo activityInfo, String key) {
    +-            return mContext.injectXmlMetaData(activityInfo, key);
    +-        }
    +-
    +-        @Override
    +-        void injectPostToHandler(Runnable r) {
    +-            runOnHandler(r);
    +-        }
    +-
    +-        @Override
    +-        void injectEnforceCallingPermission(String permission, String message) {
    +-            if (!mCallerPermissions.contains(permission)) {
    +-                throw new SecurityException("Missing permission: " + permission);
    +-            }
    +-        }
    +-
    +-        @Override
    +-        boolean injectIsSafeModeEnabled() {
    +-            return mSafeMode;
    +-        }
    +-
    +-        @Override
    +-        void wtf(String message, Throwable th) {
    +-            // During tests, WTF is fatal.
    +-            fail(message + "  exception: " + th + "\n" + Log.getStackTraceString(th));
    +-        }
    +-    }
    +-
    +-    /** ShortcutManager with injection override methods. */
    +-    protected class ShortcutManagerTestable extends ShortcutManager {
    +-        public ShortcutManagerTestable(Context context, ShortcutServiceTestable service) {
    +-            super(context, service);
    +-        }
    +-
    +-        @Override
    +-        protected int injectMyUserId() {
    +-            return UserHandle.getUserId(mInjectedCallingUid);
    +-        }
    +-
    +-        @Override
    +-        public boolean setDynamicShortcuts(@NonNull List<ShortcutInfo> shortcutInfoList) {
    +-            // Note to simulate the binder RPC, we need to clone the incoming arguments.
    +-            // Otherwise bad things will happen because they're mutable.
    +-            return super.setDynamicShortcuts(cloneShortcutList(shortcutInfoList));
    +-        }
    +-
    +-        @Override
    +-        public boolean addDynamicShortcuts(@NonNull List<ShortcutInfo> shortcutInfoList) {
    +-            // Note to simulate the binder RPC, we need to clone the incoming arguments.
    +-            return super.addDynamicShortcuts(cloneShortcutList(shortcutInfoList));
    +-        }
    +-
    +-        @Override
    +-        public boolean updateShortcuts(List<ShortcutInfo> shortcutInfoList) {
    +-            // Note to simulate the binder RPC, we need to clone the incoming arguments.
    +-            return super.updateShortcuts(cloneShortcutList(shortcutInfoList));
    +-        }
    +-    }
    +-
    +-    protected class LauncherAppImplTestable extends LauncherAppsImpl {
    +-        final ServiceContext mContext;
    +-
    +-        public LauncherAppImplTestable(ServiceContext context) {
    +-            super(context);
    +-            mContext = context;
    +-        }
    +-
    +-        @Override
    +-        public void verifyCallingPackage(String callingPackage) {
    +-            // SKIP
    +-        }
    +-
    +-        @Override
    +-        void postToPackageMonitorHandler(Runnable r) {
    +-            runOnHandler(r);
    +-        }
    +-
    +-        @Override
    +-        int injectBinderCallingUid() {
    +-            return mInjectedCallingUid;
    +-        }
    +-
    +-        @Override
    +-        long injectClearCallingIdentity() {
    +-            final int prevCallingUid = mInjectedCallingUid;
    +-            mInjectedCallingUid = Process.SYSTEM_UID;
    +-            return prevCallingUid;
    +-        }
    +-
    +-        @Override
    +-        void injectRestoreCallingIdentity(long token) {
    +-            mInjectedCallingUid = (int) token;
    +-        }
    +-    }
    +-
    +-    protected class LauncherAppsTestable extends LauncherApps {
    +-        public LauncherAppsTestable(Context context, ILauncherApps service) {
    +-            super(context, service);
    +-        }
    +-    }
    +-
    +-    public static class ShortcutActivity extends Activity {
    +-    }
    +-
    +-    public static class ShortcutActivity2 extends Activity {
    +-    }
    +-
    +-    public static class ShortcutActivity3 extends Activity {
    +-    }
    +-
    +-    protected Looper mLooper;
    +-    protected Handler mHandler;
    +-
    +-    protected ServiceContext mServiceContext;
    +-    protected ClientContext mClientContext;
    +-
    +-    protected ShortcutServiceTestable mService;
    +-    protected ShortcutManagerTestable mManager;
    +-    protected ShortcutServiceInternal mInternal;
    +-
    +-    protected LauncherAppImplTestable mLauncherAppImpl;
    +-
    +-    // LauncherApps has per-instace state, so we need a differnt instance for each launcher.
    +-    protected final Map<Pair<Integer, String>, LauncherAppsTestable>
    +-            mLauncherAppsMap = new HashMap<>();
    +-    protected LauncherAppsTestable mLauncherApps; // Current one
    +-
    +-    protected File mInjectedFilePathRoot;
    +-
    +-    protected boolean mSafeMode;
    +-
    +-    protected long mInjectedCurrentTimeMillis;
    +-
    +-    protected boolean mInjectedIsLowRamDevice;
    +-
    +-    protected Locale mInjectedLocale = Locale.ENGLISH;
    +-
    +-    protected int mInjectedCallingUid;
    +-    protected String mInjectedClientPackage;
    +-
    +-    protected Map<String, PackageInfo> mInjectedPackages;
    +-
    +-    protected Set<PackageWithUser> mUninstalledPackages;
    +-
    +-    protected PackageManager mMockPackageManager;
    +-    protected PackageManagerInternal mMockPackageManagerInternal;
    +-    protected UserManager mMockUserManager;
    +-    protected UsageStatsManagerInternal mMockUsageStatsManagerInternal;
    +-    protected ActivityManagerInternal mMockActivityManagerInternal;
    +-
    +-    protected static final String CALLING_PACKAGE_1 = "com.android.test.1";
    +-    protected static final int CALLING_UID_1 = 10001;
    +-
    +-    protected static final String CALLING_PACKAGE_2 = "com.android.test.2";
    +-    protected static final int CALLING_UID_2 = 10002;
    +-
    +-    protected static final String CALLING_PACKAGE_3 = "com.android.test.3";
    +-    protected static final int CALLING_UID_3 = 10003;
    +-
    +-    protected static final String CALLING_PACKAGE_4 = "com.android.test.4";
    +-    protected static final int CALLING_UID_4 = 10004;
    +-
    +-    protected static final String LAUNCHER_1 = "com.android.launcher.1";
    +-    protected static final int LAUNCHER_UID_1 = 10011;
    +-
    +-    protected static final String LAUNCHER_2 = "com.android.launcher.2";
    +-    protected static final int LAUNCHER_UID_2 = 10012;
    +-
    +-    protected static final String LAUNCHER_3 = "com.android.launcher.3";
    +-    protected static final int LAUNCHER_UID_3 = 10013;
    +-
    +-    protected static final String LAUNCHER_4 = "com.android.launcher.4";
    +-    protected static final int LAUNCHER_UID_4 = 10014;
    +-
    +-    protected static final int USER_0 = UserHandle.USER_SYSTEM;
    +-    protected static final int USER_10 = 10;
    +-    protected static final int USER_11 = 11;
    +-    protected static final int USER_P0 = 20; // profile of user 0
    +-
    +-    protected static final UserHandle HANDLE_USER_0 = UserHandle.of(USER_0);
    +-    protected static final UserHandle HANDLE_USER_10 = UserHandle.of(USER_10);
    +-    protected static final UserHandle HANDLE_USER_11 = UserHandle.of(USER_11);
    +-    protected static final UserHandle HANDLE_USER_P0 = UserHandle.of(USER_P0);
    +-
    +-    protected static final UserInfo USER_INFO_0 = withProfileGroupId(
    +-            new UserInfo(USER_0, "user0",
    +-                    UserInfo.FLAG_ADMIN | UserInfo.FLAG_PRIMARY | UserInfo.FLAG_INITIALIZED), 10);
    +-
    +-    protected static final UserInfo USER_INFO_10 =
    +-            new UserInfo(USER_10, "user10", UserInfo.FLAG_INITIALIZED);
    +-
    +-    protected static final UserInfo USER_INFO_11 =
    +-            new UserInfo(USER_11, "user11", UserInfo.FLAG_INITIALIZED);
    +-
    +-    protected static final UserInfo USER_INFO_P0 = withProfileGroupId(
    +-            new UserInfo(USER_P0, "userP0",
    +-                    UserInfo.FLAG_MANAGED_PROFILE), 10);
    +-
    +-    protected BiPredicate<String, Integer> mDefaultLauncherChecker =
    +-            (callingPackage, userId) ->
    +-            LAUNCHER_1.equals(callingPackage) || LAUNCHER_2.equals(callingPackage)
    +-            || LAUNCHER_3.equals(callingPackage) || LAUNCHER_4.equals(callingPackage);
    +-
    +-    protected BiPredicate<ComponentName, Integer> mMainActivityChecker =
    +-            (activity, userId) -> true;
    +-
    +-    protected BiFunction<String, Integer, ComponentName> mMainActivityFetcher =
    +-            (packageName, userId) -> new ComponentName(packageName, MAIN_ACTIVITY_CLASS);
    +-
    +-    protected BiPredicate<ComponentName, Integer> mEnabledActivityChecker
    +-            = (activity, userId) -> true; // all activities are enabled.
    +-
    +-    protected static final long START_TIME = 1440000000101L;
    +-
    +-    protected static final long INTERVAL = 10000;
    +-
    +-    protected static final int MAX_SHORTCUTS = 10;
    +-
    +-    protected static final int MAX_UPDATES_PER_INTERVAL = 3;
    +-
    +-    protected static final int MAX_ICON_DIMENSION = 128;
    +-
    +-    protected static final int MAX_ICON_DIMENSION_LOWRAM = 32;
    +-
    +-    protected static final ShortcutQuery QUERY_ALL = new ShortcutQuery();
    +-
    +-    protected final ArrayList<String> mCallerPermissions = new ArrayList<>();
    +-
    +-    protected final HashMap<String, LinkedHashMap<ComponentName, Integer>> mActivityMetadataResId
    +-            = new HashMap<>();
    +-
    +-    protected final Map<Integer, UserInfo> mUserInfos = new HashMap<>();
    +-    protected final Map<Integer, Boolean> mRunningUsers = new HashMap<>();
    +-    protected final Map<Integer, Boolean> mUnlockedUsers = new HashMap<>();
    +-
    +-    protected static final String PACKAGE_SYSTEM_LAUNCHER = "com.android.systemlauncher";
    +-    protected static final String PACKAGE_SYSTEM_LAUNCHER_NAME = "systemlauncher_name";
    +-    protected static final int PACKAGE_SYSTEM_LAUNCHER_PRIORITY = 0;
    +-
    +-    protected static final String PACKAGE_FALLBACK_LAUNCHER = "com.android.settings";
    +-    protected static final String PACKAGE_FALLBACK_LAUNCHER_NAME = "fallback";
    +-    protected static final int PACKAGE_FALLBACK_LAUNCHER_PRIORITY = -999;
    +-
    +-    static {
    +-        QUERY_ALL.setQueryFlags(
    +-                ShortcutQuery.FLAG_GET_ALL_KINDS);
    +-    }
    +-
    +-    @Override
    +-    protected void setUp() throws Exception {
    +-        super.setUp();
    +-
    +-        mLooper = Looper.getMainLooper();
    +-        mHandler = new Handler(mLooper);
    +-
    +-        mServiceContext = spy(new ServiceContext());
    +-        mClientContext = new ClientContext();
    +-
    +-        mMockPackageManager = mock(PackageManager.class);
    +-        mMockPackageManagerInternal = mock(PackageManagerInternal.class);
    +-        mMockUserManager = mock(UserManager.class);
    +-        mMockUsageStatsManagerInternal = mock(UsageStatsManagerInternal.class);
    +-        mMockActivityManagerInternal = mock(ActivityManagerInternal.class);
    +-
    +-        LocalServices.removeServiceForTest(PackageManagerInternal.class);
    +-        LocalServices.addService(PackageManagerInternal.class, mMockPackageManagerInternal);
    +-        LocalServices.removeServiceForTest(UsageStatsManagerInternal.class);
    +-        LocalServices.addService(UsageStatsManagerInternal.class, mMockUsageStatsManagerInternal);
    +-        LocalServices.removeServiceForTest(ActivityManagerInternal.class);
    +-        LocalServices.addService(ActivityManagerInternal.class, mMockActivityManagerInternal);
    +-
    +-        // Prepare injection values.
    +-
    +-        mInjectedCurrentTimeMillis = START_TIME;
    +-
    +-        mInjectedPackages = new HashMap<>();
    +-        addPackage(CALLING_PACKAGE_1, CALLING_UID_1, 1);
    +-        addPackage(CALLING_PACKAGE_2, CALLING_UID_2, 2);
    +-        addPackage(CALLING_PACKAGE_3, CALLING_UID_3, 3);
    +-        addPackage(CALLING_PACKAGE_4, CALLING_UID_4, 10);
    +-        addPackage(LAUNCHER_1, LAUNCHER_UID_1, 4);
    +-        addPackage(LAUNCHER_2, LAUNCHER_UID_2, 5);
    +-        addPackage(LAUNCHER_3, LAUNCHER_UID_3, 6);
    +-        addPackage(LAUNCHER_4, LAUNCHER_UID_4, 10);
    +-
    +-        // CALLING_PACKAGE_3 / LAUNCHER_3 are not backup target.
    +-        updatePackageInfo(CALLING_PACKAGE_3,
    +-                pi -> pi.applicationInfo.flags &= ~ApplicationInfo.FLAG_ALLOW_BACKUP);
    +-        updatePackageInfo(LAUNCHER_3,
    +-                pi -> pi.applicationInfo.flags &= ~ApplicationInfo.FLAG_ALLOW_BACKUP);
    +-
    +-        mUninstalledPackages = new HashSet<>();
    +-
    +-        mInjectedFilePathRoot = new File(getTestContext().getCacheDir(), "test-files");
    +-
    +-        deleteAllSavedFiles();
    +-
    +-        // Set up users.
    +-        when(mMockUserManager.getUserInfo(anyInt())).thenAnswer(new AnswerWithSystemCheck<>(
    +-                inv -> mUserInfos.get((Integer) inv.getArguments()[0])));
    +-
    +-        mUserInfos.put(USER_0, USER_INFO_0);
    +-        mUserInfos.put(USER_10, USER_INFO_10);
    +-        mUserInfos.put(USER_11, USER_INFO_11);
    +-        mUserInfos.put(USER_P0, USER_INFO_P0);
    +-
    +-        // Set up isUserRunning and isUserUnlocked.
    +-        when(mMockUserManager.isUserRunning(anyInt())).thenAnswer(new AnswerWithSystemCheck<>(
    +-                        inv -> b(mRunningUsers.get((Integer) inv.getArguments()[0]))));
    +-
    +-        when(mMockUserManager.isUserUnlocked(anyInt()))
    +-                .thenAnswer(new AnswerWithSystemCheck<>(inv -> {
    +-                    final int userId = (Integer) inv.getArguments()[0];
    +-                    return b(mRunningUsers.get(userId)) && b(mUnlockedUsers.get(userId));
    +-                }));
    +-        // isUserUnlockingOrUnlocked() return the same value as isUserUnlocked().
    +-        when(mMockUserManager.isUserUnlockingOrUnlocked(anyInt()))
    +-                .thenAnswer(new AnswerWithSystemCheck<>(inv -> {
    +-                    final int userId = (Integer) inv.getArguments()[0];
    +-                    return b(mRunningUsers.get(userId)) && b(mUnlockedUsers.get(userId));
    +-                }));
    +-
    +-        when(mMockActivityManagerInternal.getUidProcessState(anyInt())).thenReturn(
    +-                ActivityManager.PROCESS_STATE_CACHED_EMPTY);
    +-
    +-        // User 0 and P0 are always running
    +-        mRunningUsers.put(USER_0, true);
    +-        mRunningUsers.put(USER_10, false);
    +-        mRunningUsers.put(USER_11, false);
    +-        mRunningUsers.put(USER_P0, true);
    +-
    +-        // Unlock all users by default.
    +-        mUnlockedUsers.put(USER_0, true);
    +-        mUnlockedUsers.put(USER_10, true);
    +-        mUnlockedUsers.put(USER_11, true);
    +-        mUnlockedUsers.put(USER_P0, true);
    +-
    +-        // Set up resources
    +-        setUpAppResources();
    +-
    +-        // Start the service.
    +-        initService();
    +-        setCaller(CALLING_PACKAGE_1);
    +-    }
    +-
    +-    private static boolean b(Boolean value) {
    +-        return (value != null && value);
    +-    }
    +-
    +-    /**
    +-     * Returns a boolean but also checks if the current UID is SYSTEM_UID.
    +-     */
    +-    protected class AnswerWithSystemCheck<T> implements Answer<T> {
    +-        private final Function<InvocationOnMock, T> mChecker;
    +-
    +-        public AnswerWithSystemCheck(Function<InvocationOnMock, T> checker) {
    +-            mChecker = checker;
    +-        }
    +-
    +-        @Override
    +-        public T answer(InvocationOnMock invocation) throws Throwable {
    +-            assertEquals("Must be called on SYSTEM UID.",
    +-                    Process.SYSTEM_UID, mInjectedCallingUid);
    +-            return mChecker.apply(invocation);
    +-        }
    +-    }
    +-
    +-    protected void setUpAppResources() throws Exception {
    +-        setUpAppResources(/* offset = */ 0);
    +-    }
    +-
    +-    protected void setUpAppResources(int ressIdOffset) throws Exception {
    +-        // ressIdOffset is used to adjust resource IDs to emulate the case where an updated app
    +-        // has resource IDs changed.
    +-
    +-        doAnswer(pmInvocation -> {
    +-            assertEquals(Process.SYSTEM_UID, mInjectedCallingUid);
    +-
    +-            final String packageName = (String) pmInvocation.getArguments()[0];
    +-            final int userId = (Integer) pmInvocation.getArguments()[1];
    +-
    +-            final Resources res = mock(Resources.class);
    +-
    +-            doAnswer(resInvocation -> {
    +-                final int argResId = (Integer) resInvocation.getArguments()[0];
    +-
    +-                return "string-" + packageName + "-user:" + userId + "-res:" + argResId
    +-                        + "/" + mInjectedLocale;
    +-            }).when(res).getString(anyInt());
    +-
    +-            doAnswer(resInvocation -> {
    +-                final int resId = (Integer) resInvocation.getArguments()[0];
    +-
    +-                // Always use the "string" resource type.  The type doesn't matter during the test.
    +-                return packageName + ":string/r" + resId;
    +-            }).when(res).getResourceName(anyInt());
    +-
    +-            doAnswer(resInvocation -> {
    +-                final String argResName = (String) resInvocation.getArguments()[0];
    +-                final String argType = (String) resInvocation.getArguments()[1];
    +-                final String argPackageName = (String) resInvocation.getArguments()[2];
    +-
    +-                // See the above code.  getResourceName() will just use "r" + res ID as the entry
    +-                // name.
    +-                String entryName = argResName;
    +-                if (entryName.contains("/")) {
    +-                    entryName = ShortcutInfo.getResourceEntryName(entryName);
    +-                }
    +-                return Integer.parseInt(entryName.substring(1)) + ressIdOffset;
    +-            }).when(res).getIdentifier(anyString(), anyString(), anyString());
    +-            return res;
    +-        }).when(mMockPackageManager).getResourcesForApplicationAsUser(anyString(), anyInt());
    +-    }
    +-
    +-    protected static UserInfo withProfileGroupId(UserInfo in, int groupId) {
    +-        in.profileGroupId = groupId;
    +-        return in;
    +-    }
    +-
    +-    @Override
    +-    protected void tearDown() throws Exception {
    +-        if (DUMP_IN_TEARDOWN) dumpsysOnLogcat("Teardown");
    +-
    +-        shutdownServices();
    +-
    +-        super.tearDown();
    +-    }
    +-
    +-    protected Context getTestContext() {
    +-        return getInstrumentation().getContext();
    +-    }
    +-
    +-    protected ShortcutManager getManager() {
    +-        return mManager;
    +-    }
    +-
    +-    protected void deleteAllSavedFiles() {
    +-        // Empty the data directory.
    +-        if (mInjectedFilePathRoot.exists()) {
    +-            Assert.assertTrue("failed to delete dir",
    +-                    FileUtils.deleteContents(mInjectedFilePathRoot));
    +-        }
    +-        mInjectedFilePathRoot.mkdirs();
    +-    }
    +-
    +-    /** (Re-) init the manager and the service. */
    +-    protected void initService() {
    +-        shutdownServices();
    +-
    +-        LocalServices.removeServiceForTest(ShortcutServiceInternal.class);
    +-
    +-        // Instantiate targets.
    +-        mService = new ShortcutServiceTestable(mServiceContext, mLooper);
    +-        mManager = new ShortcutManagerTestable(mClientContext, mService);
    +-
    +-        mInternal = LocalServices.getService(ShortcutServiceInternal.class);
    +-
    +-        mLauncherAppImpl = new LauncherAppImplTestable(mServiceContext);
    +-        mLauncherApps = null;
    +-        mLauncherAppsMap.clear();
    +-
    +-        // Send boot sequence events.
    +-        mService.onBootPhase(SystemService.PHASE_LOCK_SETTINGS_READY);
    +-
    +-        mService.onBootPhase(SystemService.PHASE_BOOT_COMPLETED);
    +-    }
    +-
    +-    protected void shutdownServices() {
    +-        if (mService != null) {
    +-            // Flush all the unsaved data from the previous instance.
    +-            mService.saveDirtyInfo();
    +-
    +-            // Make sure everything is consistent.
    +-            mService.verifyStates();
    +-        }
    +-        LocalServices.removeServiceForTest(ShortcutServiceInternal.class);
    +-
    +-        mService = null;
    +-        mManager = null;
    +-        mInternal = null;
    +-        mLauncherAppImpl = null;
    +-        mLauncherApps = null;
    +-        mLauncherAppsMap.clear();
    +-    }
    +-
    +-    protected void runOnHandler(Runnable r) {
    +-        final long token = mServiceContext.injectClearCallingIdentity();
    +-        try {
    +-            r.run();
    +-        } finally {
    +-            mServiceContext.injectRestoreCallingIdentity(token);
    +-        }
    +-    }
    +-
    +-    protected void addPackage(String packageName, int uid, int version) {
    +-        addPackage(packageName, uid, version, packageName);
    +-    }
    +-
    +-    protected Signature[] genSignatures(String... signatures) {
    +-        final Signature[] sigs = new Signature[signatures.length];
    +-        for (int i = 0; i < signatures.length; i++){
    +-            sigs[i] = new Signature(signatures[i].getBytes());
    +-        }
    +-        return sigs;
    +-    }
    +-
    +-    protected PackageInfo genPackage(String packageName, int uid, int version, String... signatures) {
    +-        final PackageInfo pi = new PackageInfo();
    +-        pi.packageName = packageName;
    +-        pi.applicationInfo = new ApplicationInfo();
    +-        pi.applicationInfo.uid = uid;
    +-        pi.applicationInfo.flags = ApplicationInfo.FLAG_INSTALLED
    +-                | ApplicationInfo.FLAG_ALLOW_BACKUP;
    +-        pi.versionCode = version;
    +-        pi.applicationInfo.versionCode = version;
    +-        pi.signatures = genSignatures(signatures);
    +-
    +-        return pi;
    +-    }
    +-
    +-    protected void addPackage(String packageName, int uid, int version, String... signatures) {
    +-        mInjectedPackages.put(packageName, genPackage(packageName, uid, version, signatures));
    +-    }
    +-
    +-    protected void updatePackageInfo(String packageName, Consumer<PackageInfo> c) {
    +-        c.accept(mInjectedPackages.get(packageName));
    +-    }
    +-
    +-    protected void updatePackageVersion(String packageName, int increment) {
    +-        updatePackageInfo(packageName, pi -> {
    +-            pi.versionCode += increment;
    +-            pi.applicationInfo.versionCode += increment;
    +-        });
    +-    }
    +-
    +-    protected void updatePackageLastUpdateTime(String packageName, long increment) {
    +-        updatePackageInfo(packageName, pi -> {
    +-            pi.lastUpdateTime += increment;
    +-        });
    +-    }
    +-
    +-    protected void uninstallPackage(int userId, String packageName) {
    +-        if (ENABLE_DUMP) {
    +-            Log.v(TAG, "Unnstall package " + packageName + " / " + userId);
    +-        }
    +-        mUninstalledPackages.add(PackageWithUser.of(userId, packageName));
    +-    }
    +-
    +-    protected void installPackage(int userId, String packageName) {
    +-        if (ENABLE_DUMP) {
    +-            Log.v(TAG, "Install package " + packageName + " / " + userId);
    +-        }
    +-        mUninstalledPackages.remove(PackageWithUser.of(userId, packageName));
    +-    }
    +-
    +-    PackageInfo getInjectedPackageInfo(String packageName, @UserIdInt int userId,
    +-            boolean getSignatures) {
    +-        final PackageInfo pi = mInjectedPackages.get(packageName);
    +-        if (pi == null) return null;
    +-
    +-        final PackageInfo ret = new PackageInfo();
    +-        ret.packageName = pi.packageName;
    +-        ret.versionCode = pi.versionCode;
    +-        ret.lastUpdateTime = pi.lastUpdateTime;
    +-
    +-        ret.applicationInfo = new ApplicationInfo(pi.applicationInfo);
    +-        ret.applicationInfo.uid = UserHandle.getUid(userId, pi.applicationInfo.uid);
    +-        ret.applicationInfo.packageName = pi.packageName;
    +-
    +-        if (mUninstalledPackages.contains(PackageWithUser.of(userId, packageName))) {
    +-            ret.applicationInfo.flags &= ~ApplicationInfo.FLAG_INSTALLED;
    +-        }
    +-
    +-        if (getSignatures) {
    +-            ret.signatures = pi.signatures;
    +-        }
    +-
    +-        return ret;
    +-    }
    +-
    +-    protected void addApplicationInfo(PackageInfo pi, List<ApplicationInfo> list) {
    +-        if (pi != null && pi.applicationInfo != null) {
    +-            list.add(pi.applicationInfo);
    +-        }
    +-    }
    +-
    +-    protected List<ApplicationInfo> getInstalledApplications(int userId) {
    +-        final ArrayList<ApplicationInfo> ret = new ArrayList<>();
    +-
    +-        addApplicationInfo(getInjectedPackageInfo(CALLING_PACKAGE_1, userId, false), ret);
    +-        addApplicationInfo(getInjectedPackageInfo(CALLING_PACKAGE_2, userId, false), ret);
    +-        addApplicationInfo(getInjectedPackageInfo(CALLING_PACKAGE_3, userId, false), ret);
    +-        addApplicationInfo(getInjectedPackageInfo(CALLING_PACKAGE_4, userId, false), ret);
    +-        addApplicationInfo(getInjectedPackageInfo(LAUNCHER_1, userId, false), ret);
    +-        addApplicationInfo(getInjectedPackageInfo(LAUNCHER_2, userId, false), ret);
    +-        addApplicationInfo(getInjectedPackageInfo(LAUNCHER_3, userId, false), ret);
    +-        addApplicationInfo(getInjectedPackageInfo(LAUNCHER_4, userId, false), ret);
    +-
    +-        return ret;
    +-    }
    +-
    +-    private void addPackageInfo(PackageInfo pi, List<PackageInfo> list) {
    +-        if (pi != null) {
    +-            list.add(pi);
    +-        }
    +-    }
    +-
    +-    private List<PackageInfo> getInstalledPackagesWithUninstalled(int userId) {
    +-        final ArrayList<PackageInfo> ret = new ArrayList<>();
    +-
    +-        addPackageInfo(getInjectedPackageInfo(CALLING_PACKAGE_1, userId, false), ret);
    +-        addPackageInfo(getInjectedPackageInfo(CALLING_PACKAGE_2, userId, false), ret);
    +-        addPackageInfo(getInjectedPackageInfo(CALLING_PACKAGE_3, userId, false), ret);
    +-        addPackageInfo(getInjectedPackageInfo(CALLING_PACKAGE_4, userId, false), ret);
    +-        addPackageInfo(getInjectedPackageInfo(LAUNCHER_1, userId, false), ret);
    +-        addPackageInfo(getInjectedPackageInfo(LAUNCHER_2, userId, false), ret);
    +-        addPackageInfo(getInjectedPackageInfo(LAUNCHER_3, userId, false), ret);
    +-        addPackageInfo(getInjectedPackageInfo(LAUNCHER_4, userId, false), ret);
    +-
    +-        return ret;
    +-    }
    +-
    +-    protected void addManifestShortcutResource(ComponentName activity, int resId) {
    +-        final String packageName = activity.getPackageName();
    +-        LinkedHashMap<ComponentName, Integer> map = mActivityMetadataResId.get(packageName);
    +-        if (map == null) {
    +-            map = new LinkedHashMap<>();
    +-            mActivityMetadataResId.put(packageName, map);
    +-        }
    +-        map.put(activity, resId);
    +-    }
    +-
    +-    protected PackageInfo injectGetActivitiesWithMetadata(String packageName, @UserIdInt int userId) {
    +-        final PackageInfo ret = getInjectedPackageInfo(packageName, userId,
    +-                /* getSignatures=*/ false);
    +-
    +-        final HashMap<ComponentName, Integer> activities = mActivityMetadataResId.get(packageName);
    +-        if (activities != null) {
    +-            final ArrayList<ActivityInfo> list = new ArrayList<>();
    +-
    +-            for (ComponentName cn : activities.keySet()) {
    +-                ActivityInfo ai = new ActivityInfo();
    +-                ai.packageName = cn.getPackageName();
    +-                ai.name = cn.getClassName();
    +-                ai.metaData = new Bundle();
    +-                ai.metaData.putInt(ShortcutParser.METADATA_KEY, activities.get(cn));
    +-                ai.applicationInfo = ret.applicationInfo;
    +-                list.add(ai);
    +-            }
    +-            ret.activities = list.toArray(new ActivityInfo[list.size()]);
    +-        }
    +-        return ret;
    +-    }
    +-
    +-    protected XmlResourceParser injectXmlMetaData(ActivityInfo activityInfo, String key) {
    +-        if (!ShortcutParser.METADATA_KEY.equals(key) || activityInfo.metaData == null) {
    +-            return null;
    +-        }
    +-        final int resId = activityInfo.metaData.getInt(key);
    +-        return getTestContext().getResources().getXml(resId);
    +-    }
    +-
    +-    /** Replace the current calling package */
    +-    protected void setCaller(String packageName, int userId) {
    +-        mInjectedClientPackage = packageName;
    +-        mInjectedCallingUid =
    +-                Preconditions.checkNotNull(getInjectedPackageInfo(packageName, userId, false),
    +-                        "Unknown package").applicationInfo.uid;
    +-
    +-        // Set up LauncherApps for this caller.
    +-        final Pair<Integer, String> key = Pair.create(userId, packageName);
    +-        if (!mLauncherAppsMap.containsKey(key)) {
    +-            mLauncherAppsMap.put(key, new LauncherAppsTestable(mClientContext, mLauncherAppImpl));
    +-        }
    +-        mLauncherApps = mLauncherAppsMap.get(key);
    +-    }
    +-
    +-    protected void setCaller(String packageName) {
    +-        setCaller(packageName, UserHandle.USER_SYSTEM);
    +-    }
    +-
    +-    protected String getCallingPackage() {
    +-        return mInjectedClientPackage;
    +-    }
    +-
    +-    protected void setDefaultLauncherChecker(BiPredicate<String, Integer> p) {
    +-        mDefaultLauncherChecker = p;
    +-    }
    +-
    +-    protected void runWithCaller(String packageName, int userId, Runnable r) {
    +-        final String previousPackage = mInjectedClientPackage;
    +-        final int previousUserId = UserHandle.getUserId(mInjectedCallingUid);
    +-
    +-        setCaller(packageName, userId);
    +-
    +-        r.run();
    +-
    +-        setCaller(previousPackage, previousUserId);
    +-    }
    +-
    +-    protected void runWithSystemUid(Runnable r) {
    +-        final int origUid = mInjectedCallingUid;
    +-        mInjectedCallingUid = Process.SYSTEM_UID;
    +-        r.run();
    +-        mInjectedCallingUid = origUid;
    +-    }
    +-
    +-    protected void lookupAndFillInResourceNames(ShortcutInfo si) {
    +-        runWithSystemUid(() -> si.lookupAndFillInResourceNames(
    +-                mService.injectGetResourcesForApplicationAsUser(si.getPackage(), si.getUserId())));
    +-    }
    +-
    +-    protected int getCallingUserId() {
    +-        return UserHandle.getUserId(mInjectedCallingUid);
    +-    }
    +-
    +-    protected UserHandle getCallingUser() {
    +-        return UserHandle.of(getCallingUserId());
    +-    }
    +-
    +-    /** For debugging */
    +-    protected void dumpsysOnLogcat() {
    +-        dumpsysOnLogcat("");
    +-    }
    +-
    +-    protected void dumpsysOnLogcat(String message) {
    +-        dumpsysOnLogcat(message, false);
    +-    }
    +-
    +-    protected void dumpsysOnLogcat(String message, boolean force) {
    +-        if (force || !ENABLE_DUMP) return;
    +-
    +-        Log.v(TAG, "Dumping ShortcutService: " + message);
    +-        for (String line : dumpsys(null).split("\n")) {
    +-            Log.v(TAG, line);
    +-        }
    +-    }
    +-
    +-    protected String dumpCheckin() {
    +-        return dumpsys(new String[]{"--checkin"});
    +-    }
    +-
    +-    private String dumpsys(String[] args) {
    +-        final ArrayList<String> origPermissions = new ArrayList<>(mCallerPermissions);
    +-        mCallerPermissions.add(android.Manifest.permission.DUMP);
    +-        try {
    +-            final ByteArrayOutputStream out = new ByteArrayOutputStream();
    +-            final PrintWriter pw = new PrintWriter(out);
    +-            mService.dump(/* fd */ null, pw, args);
    +-            pw.close();
    +-
    +-            return out.toString();
    +-        } finally {
    +-            mCallerPermissions.clear();
    +-            mCallerPermissions.addAll(origPermissions);
    +-        }
    +-    }
    +-
    +-    /**
    +-     * For debugging, dump arbitrary file on logcat.
    +-     */
    +-    protected void dumpFileOnLogcat(String path) {
    +-        dumpFileOnLogcat(path, "");
    +-    }
    +-
    +-    protected void dumpFileOnLogcat(String path, String message) {
    +-        if (!ENABLE_DUMP) return;
    +-
    +-        Log.v(TAG, "Dumping file: " + path + " " + message);
    +-        final StringBuilder sb = new StringBuilder();
    +-        try (BufferedReader br = new BufferedReader(new FileReader(path))) {
    +-            String line;
    +-            while ((line = br.readLine()) != null) {
    +-                Log.v(TAG, line);
    +-            }
    +-        } catch (Exception e) {
    +-            Log.e(TAG, "Couldn't read file", e);
    +-            fail("Exception " + e);
    +-        }
    +-    }
    +-
    +-    /**
    +-     * For debugging, dump the main state file on logcat.
    +-     */
    +-    protected void dumpBaseStateFile() {
    +-        mService.saveDirtyInfo();
    +-        dumpFileOnLogcat(mInjectedFilePathRoot.getAbsolutePath()
    +-                + "/system/" + ShortcutService.FILENAME_BASE_STATE);
    +-    }
    +-
    +-    /**
    +-     * For debugging, dump per-user state file on logcat.
    +-     */
    +-    protected void dumpUserFile(int userId) {
    +-        dumpUserFile(userId, "");
    +-    }
    +-
    +-    protected void dumpUserFile(int userId, String message) {
    +-        mService.saveDirtyInfo();
    +-        dumpFileOnLogcat(mInjectedFilePathRoot.getAbsolutePath()
    +-                + "/user-" + userId
    +-                + "/" + ShortcutService.FILENAME_USER_PACKAGES, message);
    +-    }
    +-
    +-    /**
    +-     * Make a shortcut with an ID.
    +-     */
    +-    protected ShortcutInfo makeShortcut(String id) {
    +-        return makeShortcut(
    +-                id, "Title-" + id, /* activity =*/ null, /* icon =*/ null,
    +-                makeIntent(Intent.ACTION_VIEW, ShortcutActivity.class), /* rank =*/ 0);
    +-    }
    +-
    +-    protected ShortcutInfo makeShortcutWithTitle(String id, String title) {
    +-        return makeShortcut(
    +-                id, title, /* activity =*/ null, /* icon =*/ null,
    +-                makeIntent(Intent.ACTION_VIEW, ShortcutActivity.class), /* rank =*/ 0);
    +-    }
    +-
    +-    /**
    +-     * Make a shortcut with an ID and timestamp.
    +-     */
    +-    protected ShortcutInfo makeShortcutWithTimestamp(String id, long timestamp) {
    +-        final ShortcutInfo s = makeShortcut(
    +-                id, "Title-" + id, /* activity =*/ null, /* icon =*/ null,
    +-                makeIntent(Intent.ACTION_VIEW, ShortcutActivity.class), /* rank =*/ 0);
    +-        s.setTimestamp(timestamp);
    +-        return s;
    +-    }
    +-
    +-    /**
    +-     * Make a shortcut with an ID, a timestamp and an activity component
    +-     */
    +-    protected ShortcutInfo makeShortcutWithTimestampWithActivity(String id, long timestamp,
    +-            ComponentName activity) {
    +-        final ShortcutInfo s = makeShortcut(
    +-                id, "Title-" + id, activity, /* icon =*/ null,
    +-                makeIntent(Intent.ACTION_VIEW, ShortcutActivity.class), /* rank =*/ 0);
    +-        s.setTimestamp(timestamp);
    +-        return s;
    +-    }
    +-
    +-    /**
    +-     * Make a shortcut with an ID and icon.
    +-     */
    +-    protected ShortcutInfo makeShortcutWithIcon(String id, Icon icon) {
    +-        return makeShortcut(
    +-                id, "Title-" + id, /* activity =*/ null, icon,
    +-                makeIntent(Intent.ACTION_VIEW, ShortcutActivity.class), /* rank =*/ 0);
    +-    }
    +-
    +-    protected ShortcutInfo makePackageShortcut(String packageName, String id) {
    +-        String origCaller = getCallingPackage();
    +-
    +-        setCaller(packageName);
    +-        ShortcutInfo s = makeShortcut(
    +-                id, "Title-" + id, /* activity =*/ null, /* icon =*/ null,
    +-                makeIntent(Intent.ACTION_VIEW, ShortcutActivity.class), /* rank =*/ 0);
    +-        setCaller(origCaller); // restore the caller
    +-
    +-        return s;
    +-    }
    +-
    +-    /**
    +-     * Make multiple shortcuts with IDs.
    +-     */
    +-    protected List<ShortcutInfo> makeShortcuts(String... ids) {
    +-        final ArrayList<ShortcutInfo> ret = new ArrayList();
    +-        for (String id : ids) {
    +-            ret.add(makeShortcut(id));
    +-        }
    +-        return ret;
    +-    }
    +-
    +-    protected ShortcutInfo.Builder makeShortcutBuilder() {
    +-        return new ShortcutInfo.Builder(mClientContext);
    +-    }
    +-
    +-    protected ShortcutInfo makeShortcutWithActivity(String id, ComponentName activity) {
    +-        return makeShortcut(
    +-                id, "Title-" + id, activity, /* icon =*/ null,
    +-                makeIntent(Intent.ACTION_VIEW, ShortcutActivity.class), /* rank =*/ 0);
    +-    }
    +-
    +-    protected ShortcutInfo makeShortcutWithIntent(String id, Intent intent) {
    +-        return makeShortcut(
    +-                id, "Title-" + id, /* activity =*/ null, /* icon =*/ null,
    +-                intent, /* rank =*/ 0);
    +-    }
    +-
    +-    protected ShortcutInfo makeShortcutWithActivityAndTitle(String id, ComponentName activity,
    +-            String title) {
    +-        return makeShortcut(
    +-                id, title, activity, /* icon =*/ null,
    +-                makeIntent(Intent.ACTION_VIEW, ShortcutActivity.class), /* rank =*/ 0);
    +-    }
    +-
    +-    protected ShortcutInfo makeShortcutWithActivityAndRank(String id, ComponentName activity,
    +-            int rank) {
    +-        return makeShortcut(
    +-                id, "Title-" + id, activity, /* icon =*/ null,
    +-                makeIntent(Intent.ACTION_VIEW, ShortcutActivity.class), rank);
    +-    }
    +-
    +-    /**
    +-     * Make a shortcut with details.
    +-     */
    +-    protected ShortcutInfo makeShortcut(String id, String title, ComponentName activity,
    +-            Icon icon, Intent intent, int rank) {
    +-        final ShortcutInfo.Builder  b = new ShortcutInfo.Builder(mClientContext, id)
    +-                .setActivity(new ComponentName(mClientContext.getPackageName(), "dummy"))
    +-                .setShortLabel(title)
    +-                .setRank(rank)
    +-                .setIntent(intent);
    +-        if (icon != null) {
    +-            b.setIcon(icon);
    +-        }
    +-        if (activity != null) {
    +-            b.setActivity(activity);
    +-        }
    +-        final ShortcutInfo s = b.build();
    +-
    +-        s.setTimestamp(mInjectedCurrentTimeMillis); // HACK
    +-
    +-        return s;
    +-    }
    +-
    +-    protected ShortcutInfo makeShortcutWithIntents(String id, Intent... intents) {
    +-        return makeShortcut(
    +-                id, "Title-" + id, /* activity =*/ null, /* icon =*/ null,
    +-                intents, /* rank =*/ 0);
    +-    }
    +-
    +-    /**
    +-     * Make a shortcut with details.
    +-     */
    +-    protected ShortcutInfo makeShortcut(String id, String title, ComponentName activity,
    +-            Icon icon, Intent[] intents, int rank) {
    +-        final ShortcutInfo.Builder  b = new ShortcutInfo.Builder(mClientContext, id)
    +-                .setActivity(new ComponentName(mClientContext.getPackageName(), "dummy"))
    +-                .setShortLabel(title)
    +-                .setRank(rank)
    +-                .setIntents(intents);
    +-        if (icon != null) {
    +-            b.setIcon(icon);
    +-        }
    +-        if (activity != null) {
    +-            b.setActivity(activity);
    +-        }
    +-        final ShortcutInfo s = b.build();
    +-
    +-        s.setTimestamp(mInjectedCurrentTimeMillis); // HACK
    +-
    +-        return s;
    +-    }
    +-
    +-    /**
    +-     * Make a shortcut with details.
    +-     */
    +-    protected ShortcutInfo makeShortcutWithExtras(String id, Intent intent,
    +-            PersistableBundle extras) {
    +-        final ShortcutInfo.Builder  b = new ShortcutInfo.Builder(mClientContext, id)
    +-                .setActivity(new ComponentName(mClientContext.getPackageName(), "dummy"))
    +-                .setShortLabel("title-" + id)
    +-                .setExtras(extras)
    +-                .setIntent(intent);
    +-        final ShortcutInfo s = b.build();
    +-
    +-        s.setTimestamp(mInjectedCurrentTimeMillis); // HACK
    +-
    +-        return s;
    +-    }
    +-
    +-    /**
    +-     * Make an intent.
    +-     */
    +-    protected Intent makeIntent(String action, Class<?> clazz, Object... bundleKeysAndValues) {
    +-        final Intent intent = new Intent(action);
    +-        intent.setComponent(makeComponent(clazz));
    +-        intent.replaceExtras(makeBundle(bundleKeysAndValues));
    +-        return intent;
    +-    }
    +-
    +-    /**
    +-     * Make an component name, with the client context.
    +-     */
    +-    @NonNull
    +-    protected ComponentName makeComponent(Class<?> clazz) {
    +-        return new ComponentName(mClientContext, clazz);
    +-    }
    +-
    +-    @NonNull
    +-    protected ShortcutInfo findById(List<ShortcutInfo> list, String id) {
    +-        for (ShortcutInfo s : list) {
    +-            if (s.getId().equals(id)) {
    +-                return s;
    +-            }
    +-        }
    +-        fail("Shortcut with id " + id + " not found");
    +-        return null;
    +-    }
    +-
    +-    protected void assertSystem() {
    +-        assertEquals("Caller must be system", Process.SYSTEM_UID, mInjectedCallingUid);
    +-    }
    +-
    +-    protected void assertResetTimes(long expectedLastResetTime, long expectedNextResetTime) {
    +-        assertEquals(expectedLastResetTime, mService.getLastResetTimeLocked());
    +-        assertEquals(expectedNextResetTime, mService.getNextResetTimeLocked());
    +-    }
    +-
    +-    public static List<ShortcutInfo> assertAllNotHaveIcon(
    +-            List<ShortcutInfo> actualShortcuts) {
    +-        for (ShortcutInfo s : actualShortcuts) {
    +-            assertNull("ID " + s.getId(), s.getIcon());
    +-        }
    +-        return actualShortcuts;
    +-    }
    +-
    +-    @NonNull
    +-    protected List<ShortcutInfo> assertAllHaveFlags(@NonNull List<ShortcutInfo> actualShortcuts,
    +-            int shortcutFlags) {
    +-        for (ShortcutInfo s : actualShortcuts) {
    +-            assertTrue("ID " + s.getId() + " doesn't have flags " + shortcutFlags,
    +-                    s.hasFlags(shortcutFlags));
    +-        }
    +-        return actualShortcuts;
    +-    }
    +-
    +-    protected ShortcutInfo getPackageShortcut(String packageName, String shortcutId, int userId) {
    +-        return mService.getPackageShortcutForTest(packageName, shortcutId, userId);
    +-    }
    +-
    +-    protected void assertShortcutExists(String packageName, String shortcutId, int userId) {
    +-        assertTrue(getPackageShortcut(packageName, shortcutId, userId) != null);
    +-    }
    +-
    +-    protected void assertShortcutNotExists(String packageName, String shortcutId, int userId) {
    +-        assertTrue(getPackageShortcut(packageName, shortcutId, userId) == null);
    +-    }
    +-
    +-    protected Intent[] launchShortcutAndGetIntentsInner(Runnable shortcutStarter,
    +-            @NonNull String packageName, @NonNull String shortcutId, int userId) {
    +-        reset(mMockActivityManagerInternal);
    +-        shortcutStarter.run();
    +-
    +-        final ArgumentCaptor<Intent[]> intentsCaptor = ArgumentCaptor.forClass(Intent[].class);
    +-        verify(mMockActivityManagerInternal).startActivitiesAsPackage(
    +-                eq(packageName),
    +-                eq(userId),
    +-                intentsCaptor.capture(),
    +-                any(Bundle.class));
    +-        return intentsCaptor.getValue();
    +-    }
    +-
    +-    protected Intent[] launchShortcutAndGetIntents(
    +-            @NonNull String packageName, @NonNull String shortcutId, int userId) {
    +-        return launchShortcutAndGetIntentsInner(
    +-                () -> {
    +-                    mLauncherApps.startShortcut(packageName, shortcutId, null, null,
    +-                            UserHandle.of(userId));
    +-                }, packageName, shortcutId, userId
    +-        );
    +-    }
    +-
    +-    protected Intent launchShortcutAndGetIntent(
    +-            @NonNull String packageName, @NonNull String shortcutId, int userId) {
    +-        final Intent[] intents = launchShortcutAndGetIntents(packageName, shortcutId, userId);
    +-        assertEquals(1, intents.length);
    +-        return intents[0];
    +-    }
    +-
    +-    protected Intent[] launchShortcutAndGetIntents_withShortcutInfo(
    +-            @NonNull String packageName, @NonNull String shortcutId, int userId) {
    +-        return launchShortcutAndGetIntentsInner(
    +-                () -> {
    +-                    mLauncherApps.startShortcut(
    +-                            getShortcutInfoAsLauncher(packageName, shortcutId, userId), null, null);
    +-                }, packageName, shortcutId, userId
    +-        );
    +-    }
    +-
    +-    protected Intent launchShortcutAndGetIntent_withShortcutInfo(
    +-            @NonNull String packageName, @NonNull String shortcutId, int userId) {
    +-        final Intent[] intents = launchShortcutAndGetIntents_withShortcutInfo(
    +-                packageName, shortcutId, userId);
    +-        assertEquals(1, intents.length);
    +-        return intents[0];
    +-    }
    +-
    +-    protected void assertShortcutLaunchable(@NonNull String packageName, @NonNull String shortcutId,
    +-            int userId) {
    +-        assertNotNull(launchShortcutAndGetIntent(packageName, shortcutId, userId));
    +-        assertNotNull(launchShortcutAndGetIntent_withShortcutInfo(packageName, shortcutId, userId));
    +-    }
    +-
    +-    protected void assertShortcutNotLaunched(@NonNull String packageName,
    +-            @NonNull String shortcutId, int userId) {
    +-        reset(mMockActivityManagerInternal);
    +-        try {
    +-            mLauncherApps.startShortcut(packageName, shortcutId, null, null,
    +-                    UserHandle.of(userId));
    +-            fail("ActivityNotFoundException was not thrown");
    +-        } catch (ActivityNotFoundException expected) {
    +-        }
    +-        // This shouldn't have been called.
    +-        verify(mMockActivityManagerInternal, times(0)).startActivitiesAsPackage(
    +-                anyString(),
    +-                anyInt(),
    +-                any(Intent[].class),
    +-                any(Bundle.class));
    +-    }
    +-
    +-    protected void assertStartShortcutThrowsException(@NonNull String packageName,
    +-            @NonNull String shortcutId, int userId, Class<?> expectedException) {
    +-        Exception thrown = null;
    +-        try {
    +-            mLauncherApps.startShortcut(packageName, shortcutId, null, null,
    +-                    UserHandle.of(userId));
    +-        } catch (Exception e) {
    +-            thrown = e;
    +-        }
    +-        assertNotNull("Exception was not thrown", thrown);
    +-        assertEquals("Exception type different", expectedException, thrown.getClass());
    +-    }
    +-
    +-    protected void assertBitmapDirectories(int userId, String... expectedDirectories) {
    +-        final Set<String> expected = hashSet(set(expectedDirectories));
    +-
    +-        final Set<String> actual = new HashSet<>();
    +-
    +-        final File[] files = mService.getUserBitmapFilePath(userId).listFiles();
    +-        if (files != null) {
    +-            for (File child : files) {
    +-                if (child.isDirectory()) {
    +-                    actual.add(child.getName());
    +-                }
    +-            }
    +-        }
    +-
    +-        assertEquals(expected, actual);
    +-    }
    +-
    +-    protected void assertBitmapFiles(int userId, String packageName, String... expectedFiles) {
    +-        final Set<String> expected = hashSet(set(expectedFiles));
    +-
    +-        final Set<String> actual = new HashSet<>();
    +-
    +-        final File[] files = new File(mService.getUserBitmapFilePath(userId), packageName)
    +-                .listFiles();
    +-        if (files != null) {
    +-            for (File child : files) {
    +-                if (child.isFile()) {
    +-                    actual.add(child.getName());
    +-                }
    +-            }
    +-        }
    +-
    +-        assertEquals(expected, actual);
    +-    }
    +-
    +-    protected String getBitmapFilename(int userId, String packageName, String shortcutId) {
    +-        final ShortcutInfo si = mService.getPackageShortcutForTest(packageName, shortcutId, userId);
    +-        if (si == null) {
    +-            return null;
    +-        }
    +-        return new File(si.getBitmapPath()).getName();
    +-    }
    +-
    +-    /**
    +-     * @return all shortcuts stored internally for the caller.  This reflects the *internal* view
    +-     * of shortcuts, which may be different from what {@link #getCallerVisibleShortcuts} would
    +-     * return, because getCallerVisibleShortcuts() will get shortcuts from the proper "front door"
    +-     * which performs some extra checks, like {@link ShortcutPackage#onRestored}.
    +-     */
    +-    protected List<ShortcutInfo> getCallerShortcuts() {
    +-        final ShortcutPackage p = mService.getPackageShortcutForTest(
    +-                getCallingPackage(), getCallingUserId());
    +-        return p == null ? null : p.getAllShortcutsForTest();
    +-    }
    +-
    +-    /**
    +-     * @return all shortcuts owned by caller that are actually visible via ShortcutManager.
    +-     * See also {@link #getCallerShortcuts}.
    +-     */
    +-    protected List<ShortcutInfo> getCallerVisibleShortcuts() {
    +-        final ArrayList<ShortcutInfo> ret = new ArrayList<>();
    +-        ret.addAll(mManager.getDynamicShortcuts());
    +-        ret.addAll(mManager.getPinnedShortcuts());
    +-        ret.addAll(mManager.getManifestShortcuts());
    +-        return ret;
    +-    }
    +-
    +-    protected ShortcutInfo getCallerShortcut(String shortcutId) {
    +-        return getPackageShortcut(getCallingPackage(), shortcutId, getCallingUserId());
    +-    }
    +-
    +-    protected List<ShortcutInfo> getLauncherShortcuts(String launcher, int userId, int queryFlags) {
    +-        final List<ShortcutInfo>[] ret = new List[1];
    +-        runWithCaller(launcher, userId, () -> {
    +-            final ShortcutQuery q = new ShortcutQuery();
    +-            q.setQueryFlags(queryFlags);
    +-            ret[0] = mLauncherApps.getShortcuts(q, UserHandle.of(userId));
    +-        });
    +-        return ret[0];
    +-    }
    +-
    +-    protected List<ShortcutInfo> getLauncherPinnedShortcuts(String launcher, int userId) {
    +-        return getLauncherShortcuts(launcher, userId, ShortcutQuery.FLAG_GET_PINNED);
    +-    }
    +-
    +-    protected ShortcutInfo getShortcutInfoAsLauncher(String packageName, String shortcutId,
    +-            int userId) {
    +-        final List<ShortcutInfo> infoList =
    +-                mLauncherApps.getShortcutInfo(packageName, list(shortcutId),
    +-                        UserHandle.of(userId));
    +-        assertEquals("No shortcutInfo found (or too many of them)", 1, infoList.size());
    +-        return infoList.get(0);
    +-    }
    +-
    +-    protected Intent genPackageAddIntent(String packageName, int userId) {
    +-        installPackage(userId, packageName);
    +-
    +-        Intent i = new Intent(Intent.ACTION_PACKAGE_ADDED);
    +-        i.setData(Uri.parse("package:" + packageName));
    +-        i.putExtra(Intent.EXTRA_USER_HANDLE, userId);
    +-        return i;
    +-    }
    +-
    +-    protected Intent genPackageDeleteIntent(String pakcageName, int userId) {
    +-        uninstallPackage(userId, pakcageName);
    +-
    +-        Intent i = new Intent(Intent.ACTION_PACKAGE_REMOVED);
    +-        i.setData(Uri.parse("package:" + pakcageName));
    +-        i.putExtra(Intent.EXTRA_USER_HANDLE, userId);
    +-        return i;
    +-    }
    +-
    +-    protected Intent genPackageUpdateIntent(String pakcageName, int userId) {
    +-        installPackage(userId, pakcageName);
    +-
    +-        Intent i = new Intent(Intent.ACTION_PACKAGE_ADDED);
    +-        i.setData(Uri.parse("package:" + pakcageName));
    +-        i.putExtra(Intent.EXTRA_USER_HANDLE, userId);
    +-        i.putExtra(Intent.EXTRA_REPLACING, true);
    +-        return i;
    +-    }
    +-
    +-    protected Intent genPackageChangedIntent(String pakcageName, int userId) {
    +-        Intent i = new Intent(Intent.ACTION_PACKAGE_CHANGED);
    +-        i.setData(Uri.parse("package:" + pakcageName));
    +-        i.putExtra(Intent.EXTRA_USER_HANDLE, userId);
    +-        return i;
    +-    }
    +-
    +-    protected Intent genPackageDataClear(String packageName, int userId) {
    +-        Intent i = new Intent(Intent.ACTION_PACKAGE_DATA_CLEARED);
    +-        i.setData(Uri.parse("package:" + packageName));
    +-        i.putExtra(Intent.EXTRA_USER_HANDLE, userId);
    +-        return i;
    +-    }
    +-
    +-    protected void assertExistsAndShadow(ShortcutPackageItem spi) {
    +-        assertNotNull(spi);
    +-        assertTrue(spi.getPackageInfo().isShadow());
    +-    }
    +-
    +-    protected File makeFile(File baseDirectory, String... paths) {
    +-        File ret = baseDirectory;
    +-
    +-        for (String path : paths) {
    +-            ret = new File(ret, path);
    +-        }
    +-
    +-        return ret;
    +-    }
    +-
    +-    protected boolean bitmapDirectoryExists(String packageName, int userId) {
    +-        final File path = new File(mService.getUserBitmapFilePath(userId), packageName);
    +-        return path.isDirectory();
    +-    }
    +-    protected static ShortcutQuery buildQuery(long changedSince,
    +-            String packageName, ComponentName componentName,
    +-            /* @ShortcutQuery.QueryFlags */ int flags) {
    +-        return buildQuery(changedSince, packageName, null, componentName, flags);
    +-    }
    +-
    +-    protected static ShortcutQuery buildQuery(long changedSince,
    +-            String packageName, List<String> shortcutIds, ComponentName componentName,
    +-            /* @ShortcutQuery.QueryFlags */ int flags) {
    +-        final ShortcutQuery q = new ShortcutQuery();
    +-        q.setChangedSince(changedSince);
    +-        q.setPackage(packageName);
    +-        q.setShortcutIds(shortcutIds);
    +-        q.setActivity(componentName);
    +-        q.setQueryFlags(flags);
    +-        return q;
    +-    }
    +-
    +-    protected static ShortcutQuery buildAllQuery(String packageName) {
    +-        final ShortcutQuery q = new ShortcutQuery();
    +-        q.setPackage(packageName);
    +-        q.setQueryFlags(ShortcutQuery.FLAG_GET_ALL_KINDS);
    +-        return q;
    +-    }
    +-
    +-    protected static ShortcutQuery buildPinnedQuery(String packageName) {
    +-        final ShortcutQuery q = new ShortcutQuery();
    +-        q.setPackage(packageName);
    +-        q.setQueryFlags(ShortcutQuery.FLAG_GET_PINNED);
    +-        return q;
    +-    }
    +-
    +-    protected static ShortcutQuery buildQueryWithFlags(int queryFlags) {
    +-        final ShortcutQuery q = new ShortcutQuery();
    +-        q.setQueryFlags(queryFlags);
    +-        return q;
    +-    }
    +-
    +-    protected void backupAndRestore() {
    +-        int prevUid = mInjectedCallingUid;
    +-
    +-        mInjectedCallingUid = Process.SYSTEM_UID; // Only system can call it.
    +-
    +-        dumpsysOnLogcat("Before backup");
    +-
    +-        final byte[] payload =  mService.getBackupPayload(USER_0);
    +-        if (ENABLE_DUMP) {
    +-            final String xml = new String(payload);
    +-            Log.v(TAG, "Backup payload:");
    +-            for (String line : xml.split("\n")) {
    +-                Log.v(TAG, line);
    +-            }
    +-        }
    +-
    +-        // Before doing anything else, uninstall all packages.
    +-        for (int userId : list(USER_0, USER_P0)) {
    +-            for (String pkg : list(CALLING_PACKAGE_1, CALLING_PACKAGE_2, CALLING_PACKAGE_3,
    +-                    LAUNCHER_1, LAUNCHER_2, LAUNCHER_3)) {
    +-                uninstallPackage(userId, pkg);
    +-            }
    +-        }
    +-
    +-        shutdownServices();
    +-
    +-        deleteAllSavedFiles();
    +-
    +-        initService();
    +-        mService.applyRestore(payload, USER_0);
    +-
    +-        // handleUnlockUser will perform the gone package check, but it shouldn't remove
    +-        // shadow information.
    +-        mService.handleUnlockUser(USER_0);
    +-
    +-        dumpsysOnLogcat("After restore");
    +-
    +-        mInjectedCallingUid = prevUid;
    +-    }
    +-
    +-    protected void prepareCrossProfileDataSet() {
    +-        mRunningUsers.put(USER_10, true); // this test needs user 10.
    +-
    +-        runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
    +-            assertTrue(mManager.setDynamicShortcuts(list(
    +-                    makeShortcut("s1"), makeShortcut("s2"), makeShortcut("s3"),
    +-                    makeShortcut("s4"), makeShortcut("s5"), makeShortcut("s6"))));
    +-        });
    +-        runWithCaller(CALLING_PACKAGE_2, USER_0, () -> {
    +-            assertTrue(mManager.setDynamicShortcuts(list(
    +-                    makeShortcut("s1"), makeShortcut("s2"), makeShortcut("s3"),
    +-                    makeShortcut("s4"), makeShortcut("s5"), makeShortcut("s6"))));
    +-        });
    +-        runWithCaller(CALLING_PACKAGE_3, USER_0, () -> {
    +-            assertTrue(mManager.setDynamicShortcuts(list(
    +-                    makeShortcut("s1"), makeShortcut("s2"), makeShortcut("s3"),
    +-                    makeShortcut("s4"), makeShortcut("s5"), makeShortcut("s6"))));
    +-        });
    +-        runWithCaller(CALLING_PACKAGE_4, USER_0, () -> {
    +-            assertTrue(mManager.setDynamicShortcuts(list()));
    +-        });
    +-        runWithCaller(CALLING_PACKAGE_1, USER_P0, () -> {
    +-            assertTrue(mManager.setDynamicShortcuts(list(
    +-                    makeShortcut("s1"), makeShortcut("s2"), makeShortcut("s3"),
    +-                    makeShortcut("s4"), makeShortcut("s5"), makeShortcut("s6"))));
    +-        });
    +-        runWithCaller(CALLING_PACKAGE_1, USER_10, () -> {
    +-            assertTrue(mManager.setDynamicShortcuts(list(
    +-                    makeShortcut("x1"), makeShortcut("x2"), makeShortcut("x3"),
    +-                    makeShortcut("x4"), makeShortcut("x5"), makeShortcut("x6"))));
    +-        });
    +-
    +-        runWithCaller(LAUNCHER_1, USER_0, () -> {
    +-            mLauncherApps.pinShortcuts(CALLING_PACKAGE_1, list("s1"), HANDLE_USER_0);
    +-            mLauncherApps.pinShortcuts(CALLING_PACKAGE_2, list("s1", "s2"), HANDLE_USER_0);
    +-            mLauncherApps.pinShortcuts(CALLING_PACKAGE_3, list("s1", "s2", "s3"), HANDLE_USER_0);
    +-
    +-            mLauncherApps.pinShortcuts(CALLING_PACKAGE_1, list("s1", "s4"), HANDLE_USER_P0);
    +-        });
    +-        runWithCaller(LAUNCHER_2, USER_0, () -> {
    +-            mLauncherApps.pinShortcuts(CALLING_PACKAGE_1, list("s2"), HANDLE_USER_0);
    +-            mLauncherApps.pinShortcuts(CALLING_PACKAGE_2, list("s2", "s3"), HANDLE_USER_0);
    +-            mLauncherApps.pinShortcuts(CALLING_PACKAGE_3, list("s2", "s3", "s4"), HANDLE_USER_0);
    +-
    +-            mLauncherApps.pinShortcuts(CALLING_PACKAGE_1, list("s2", "s5"), HANDLE_USER_P0);
    +-        });
    +-
    +-        // Note LAUNCHER_3 has allowBackup=false.
    +-        runWithCaller(LAUNCHER_3, USER_0, () -> {
    +-            mLauncherApps.pinShortcuts(CALLING_PACKAGE_1, list("s3"), HANDLE_USER_0);
    +-            mLauncherApps.pinShortcuts(CALLING_PACKAGE_2, list("s3", "s4"), HANDLE_USER_0);
    +-            mLauncherApps.pinShortcuts(CALLING_PACKAGE_3, list("s3", "s4", "s5"), HANDLE_USER_0);
    +-
    +-            mLauncherApps.pinShortcuts(CALLING_PACKAGE_1, list("s3", "s6"), HANDLE_USER_P0);
    +-        });
    +-        runWithCaller(LAUNCHER_4, USER_0, () -> {
    +-            mLauncherApps.pinShortcuts(CALLING_PACKAGE_1, list(), HANDLE_USER_0);
    +-            mLauncherApps.pinShortcuts(CALLING_PACKAGE_2, list(), HANDLE_USER_0);
    +-            mLauncherApps.pinShortcuts(CALLING_PACKAGE_3, list(), HANDLE_USER_0);
    +-            mLauncherApps.pinShortcuts(CALLING_PACKAGE_4, list(), HANDLE_USER_0);
    +-        });
    +-
    +-        // Launcher on a managed profile is referring ot user 0!
    +-        runWithCaller(LAUNCHER_1, USER_P0, () -> {
    +-            mLauncherApps.pinShortcuts(CALLING_PACKAGE_1, list("s3", "s4"), HANDLE_USER_0);
    +-            mLauncherApps.pinShortcuts(CALLING_PACKAGE_2, list("s3", "s4", "s5"), HANDLE_USER_0);
    +-            mLauncherApps.pinShortcuts(CALLING_PACKAGE_3, list("s3", "s4", "s5", "s6"),
    +-                    HANDLE_USER_0);
    +-
    +-            mLauncherApps.pinShortcuts(CALLING_PACKAGE_1, list("s4", "s1"), HANDLE_USER_P0);
    +-        });
    +-        runWithCaller(LAUNCHER_1, USER_10, () -> {
    +-            mLauncherApps.pinShortcuts(CALLING_PACKAGE_1, list("x4", "x5"), HANDLE_USER_10);
    +-            mLauncherApps.pinShortcuts(CALLING_PACKAGE_2, list("x4", "x5", "x6"), HANDLE_USER_10);
    +-            mLauncherApps.pinShortcuts(CALLING_PACKAGE_3, list("x4", "x5", "x6", "x1"),
    +-                    HANDLE_USER_10);
    +-        });
    +-
    +-        // Then remove some dynamic shortcuts.
    +-        runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
    +-            assertTrue(mManager.setDynamicShortcuts(list(
    +-                    makeShortcut("s1"), makeShortcut("s2"), makeShortcut("s3"))));
    +-        });
    +-        runWithCaller(CALLING_PACKAGE_2, USER_0, () -> {
    +-            assertTrue(mManager.setDynamicShortcuts(list(
    +-                    makeShortcut("s1"), makeShortcut("s2"), makeShortcut("s3"))));
    +-        });
    +-        runWithCaller(CALLING_PACKAGE_3, USER_0, () -> {
    +-            assertTrue(mManager.setDynamicShortcuts(list(
    +-                    makeShortcut("s1"), makeShortcut("s2"), makeShortcut("s3"))));
    +-        });
    +-        runWithCaller(CALLING_PACKAGE_4, USER_0, () -> {
    +-            assertTrue(mManager.setDynamicShortcuts(list()));
    +-        });
    +-        runWithCaller(CALLING_PACKAGE_1, USER_P0, () -> {
    +-            assertTrue(mManager.setDynamicShortcuts(list(
    +-                    makeShortcut("s1"), makeShortcut("s2"), makeShortcut("s3"))));
    +-        });
    +-        runWithCaller(CALLING_PACKAGE_1, USER_10, () -> {
    +-            assertTrue(mManager.setDynamicShortcuts(list(
    +-                    makeShortcut("x1"), makeShortcut("x2"), makeShortcut("x3"))));
    +-        });
    +-    }
    +-
    +-    public static List<ShortcutInfo> assertAllHaveIconResId(
    +-            List<ShortcutInfo> actualShortcuts) {
    +-        for (ShortcutInfo s : actualShortcuts) {
    +-            assertTrue("ID " + s.getId() + " not have icon res ID", s.hasIconResource());
    +-            assertFalse("ID " + s.getId() + " shouldn't have icon FD", s.hasIconFile());
    +-        }
    +-        return actualShortcuts;
    +-    }
    +-
    +-    public static List<ShortcutInfo> assertAllHaveIconFile(
    +-            List<ShortcutInfo> actualShortcuts) {
    +-        for (ShortcutInfo s : actualShortcuts) {
    +-            assertFalse("ID " + s.getId() + " shouldn't have icon res ID", s.hasIconResource());
    +-            assertTrue("ID " + s.getId() + " not have icon FD", s.hasIconFile());
    +-        }
    +-        return actualShortcuts;
    +-    }
    +-
    +-    public static List<ShortcutInfo> assertAllHaveIcon(
    +-            List<ShortcutInfo> actualShortcuts) {
    +-        for (ShortcutInfo s : actualShortcuts) {
    +-            assertTrue("ID " + s.getId() + " has no icon ", s.hasIconFile() || s.hasIconResource());
    +-        }
    +-        return actualShortcuts;
    +-    }
    +-
    +-    public static List<ShortcutInfo> assertAllStringsResolved(
    +-            List<ShortcutInfo> actualShortcuts) {
    +-        for (ShortcutInfo s : actualShortcuts) {
    +-            assertTrue("ID " + s.getId(), s.hasStringResourcesResolved());
    +-        }
    +-        return actualShortcuts;
    +-    }
    +-
    +-    public String readTestAsset(String assetPath) throws IOException {
    +-        final StringBuilder sb = new StringBuilder();
    +-        try (BufferedReader br = new BufferedReader(
    +-                new InputStreamReader(
    +-                        getTestContext().getResources().getAssets().open(assetPath)))) {
    +-            String line;
    +-            while ((line = br.readLine()) != null) {
    +-                sb.append(line);
    +-                sb.append(System.lineSeparator());
    +-            }
    +-        }
    +-        return sb.toString();
    +-    }
    +-
    +-    protected void prepareGetHomeActivitiesAsUser(ComponentName preferred,
    +-            List<ResolveInfo> candidates, int userId) {
    +-        doAnswer(inv -> {
    +-            ((List) inv.getArguments()[0]).addAll(candidates);
    +-            return preferred;
    +-        }).when(mMockPackageManagerInternal).getHomeActivitiesAsUser(any(List.class), eq(userId));
    +-    }
    +-
    +-    protected static ComponentName cn(String packageName, String name) {
    +-        return new ComponentName(packageName, name);
    +-    }
    +-
    +-    protected static ResolveInfo ri(String packageName, String name, boolean isSystem, int priority) {
    +-        final ResolveInfo ri = new ResolveInfo();
    +-        ri.activityInfo = new ActivityInfo();
    +-        ri.activityInfo.applicationInfo = new ApplicationInfo();
    +-
    +-        ri.activityInfo.packageName = packageName;
    +-        ri.activityInfo.name = name;
    +-        if (isSystem) {
    +-            ri.activityInfo.applicationInfo.flags |= ApplicationInfo.FLAG_SYSTEM;
    +-        }
    +-        ri.priority = priority;
    +-        return ri;
    +-    }
    +-
    +-    protected static ResolveInfo getSystemLauncher() {
    +-        return ri(PACKAGE_SYSTEM_LAUNCHER, PACKAGE_SYSTEM_LAUNCHER_NAME, true,
    +-                PACKAGE_SYSTEM_LAUNCHER_PRIORITY);
    +-    }
    +-
    +-    protected static ResolveInfo getFallbackLauncher() {
    +-        return ri(PACKAGE_FALLBACK_LAUNCHER, PACKAGE_FALLBACK_LAUNCHER_NAME, true,
    +-                PACKAGE_FALLBACK_LAUNCHER_PRIORITY);
    +-    }
    +-}
    +diff --git a/services/tests/servicestests/src/com/android/server/pm/KeySetManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/pm/KeySetManagerServiceTest.java
    +deleted file mode 100644
    +index ba83be1..0000000
    +--- a/services/tests/servicestests/src/com/android/server/pm/KeySetManagerServiceTest.java
    ++++ /dev/null
    +@@ -1,804 +0,0 @@
    +-/*
    +- * Copyright (C) 2015 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 com.android.server.pm;
    +-
    +-
    +-import android.content.pm.PackageParser;
    +-import android.content.pm.Signature;
    +-import android.util.ArrayMap;
    +-import android.util.ArraySet;
    +-import android.util.LongSparseArray;
    +-import com.android.internal.util.ArrayUtils;
    +-
    +-import java.io.File;
    +-import java.io.IOException;
    +-import java.security.cert.CertificateException;
    +-import java.security.PublicKey;
    +-
    +-import android.test.AndroidTestCase;
    +-
    +-public class KeySetManagerServiceTest extends AndroidTestCase {
    +-
    +-    private ArrayMap<String, PackageSetting> mPackagesMap;
    +-    private KeySetManagerService mKsms;
    +-
    +-    public PackageSetting generateFakePackageSetting(String name) {
    +-        return new PackageSetting(name, name, new File(mContext.getCacheDir(), "fakeCodePath"),
    +-                new File(mContext.getCacheDir(), "fakeResPath"), "", "", "",
    +-                "", 1, 0, 0, null, null);
    +-    }
    +-
    +-    @Override
    +-    public void setUp() throws Exception {
    +-        super.setUp();
    +-        mPackagesMap = new ArrayMap<String, PackageSetting>();
    +-        mKsms = new KeySetManagerService(mPackagesMap);
    +-    }
    +-
    +-    public void testPackageKeySetDataConstructorUnassignend() {
    +-        PackageKeySetData pksd = new PackageKeySetData();
    +-        assertEquals(PackageKeySetData.KEYSET_UNASSIGNED, pksd.getProperSigningKeySet());
    +-        assertNull(pksd.getUpgradeKeySets());
    +-        ArrayMap<String, Long> aliases = pksd.getAliases();
    +-        assertNotNull(aliases);
    +-        assertEquals(0, aliases.size());
    +-    }
    +-
    +-    /* test equivalence of PackageManager cert encoding and PackageParser manifest keys */
    +-    public void testPublicKeyCertReprEquiv() throws CertificateException {
    +-        PublicKey keyA = PackageParser.parsePublicKey(KeySetStrings.ctsKeySetPublicKeyA);
    +-        PublicKey keyB = PackageParser.parsePublicKey(KeySetStrings.ctsKeySetPublicKeyB);
    +-        PublicKey keyC = PackageParser.parsePublicKey(KeySetStrings.ctsKeySetPublicKeyC);
    +-
    +-        Signature sigA = new Signature(KeySetStrings.ctsKeySetCertA);
    +-        Signature sigB = new Signature(KeySetStrings.ctsKeySetCertB);
    +-        Signature sigC = new Signature(KeySetStrings.ctsKeySetCertC);
    +-
    +-        assertNotNull(keyA);
    +-        assertNotNull(keyB);
    +-        assertNotNull(keyC);
    +-
    +-        assertEquals(keyA, sigA.getPublicKey());
    +-        assertEquals(keyB, sigB.getPublicKey());
    +-        assertEquals(keyC, sigC.getPublicKey());
    +-
    +-        byte[] bArrayPk = keyA.getEncoded();
    +-        byte[] bArrayCert = sigA.getPublicKey().getEncoded();
    +-        assertEquals(bArrayPk.length, bArrayCert.length);
    +-        assertEquals(true, ArrayUtils.equals(bArrayPk, bArrayCert, bArrayPk.length));
    +-
    +-        bArrayPk = keyB.getEncoded();
    +-        bArrayCert = sigB.getPublicKey().getEncoded();
    +-        assertEquals(bArrayPk.length, bArrayCert.length);
    +-        assertEquals(true, ArrayUtils.equals(bArrayPk, bArrayCert, bArrayPk.length));
    +-
    +-        bArrayPk = keyC.getEncoded();
    +-        bArrayCert = sigC.getPublicKey().getEncoded();
    +-        assertEquals(bArrayPk.length, bArrayCert.length);
    +-        assertEquals(true, ArrayUtils.equals(bArrayPk, bArrayCert, bArrayPk.length));
    +-    }
    +-
    +-    public void testEncodePublicKey() throws IOException {
    +-        ArrayMap<String, PackageSetting> packagesMap = new ArrayMap<String, PackageSetting>();
    +-        KeySetManagerService ksms = new KeySetManagerService(packagesMap);
    +-
    +-        PublicKey keyA = PackageParser.parsePublicKey(KeySetStrings.ctsKeySetPublicKeyA);
    +-        PublicKey keyB = PackageParser.parsePublicKey(KeySetStrings.ctsKeySetPublicKeyB);
    +-        PublicKey keyC = PackageParser.parsePublicKey(KeySetStrings.ctsKeySetPublicKeyC);
    +-
    +-        assertEquals(ksms.encodePublicKey(keyA), KeySetStrings.ctsKeySetPublicKeyA);
    +-        assertEquals(ksms.encodePublicKey(keyB), KeySetStrings.ctsKeySetPublicKeyB);
    +-        assertEquals(ksms.encodePublicKey(keyC), KeySetStrings.ctsKeySetPublicKeyC);
    +-    }
    +-
    +-    /*
    +-     * Add the keyset information for a package to a system w/no previous keysets
    +-     */
    +-    public void testAddSigningKSToPackageEmpty() throws ReflectiveOperationException {
    +-
    +-        /* create PackageSetting and add to Settings mPackages */
    +-        PackageSetting ps = generateFakePackageSetting("packageA");
    +-        mPackagesMap.put(ps.name, ps);
    +-
    +-        /* collect signing key and add */
    +-        ArraySet<PublicKey> signingKeys = new ArraySet<PublicKey>();
    +-        PublicKey keyA = PackageParser.parsePublicKey(KeySetStrings.ctsKeySetPublicKeyA);
    +-        signingKeys.add(keyA);
    +-        mKsms.addSigningKeySetToPackageLPw(ps, signingKeys);
    +-
    +-        assertEquals(1, KeySetUtils.getKeySetRefCount(mKsms, 1));
    +-        assertEquals(1, KeySetUtils.getPubKeyRefCount(mKsms, 1));
    +-        assertEquals(keyA, KeySetUtils.getPubKey(mKsms, 1));
    +-        LongSparseArray<ArraySet<Long>> ksMapping = KeySetUtils.getKeySetMapping(mKsms);
    +-        assertEquals(1, ksMapping.size());
    +-        ArraySet<Long> mapping = ksMapping.get(1);
    +-        assertEquals(1, mapping.size());
    +-        assertTrue(mapping.contains(new Long(1)));
    +-        assertEquals(1, ps.keySetData.getProperSigningKeySet());
    +-    }
    +-
    +-    /*
    +-     * upgrade an app (same packagename) with same keyset and verify that
    +-     * nothing changed.
    +-     */
    +-    public void testAddSigningKSToPackageUpgradeSame() throws ReflectiveOperationException {
    +-
    +-        /* create PackageSetting and add to Settings mPackages */
    +-        PackageSetting ps = generateFakePackageSetting("packageA");
    +-        mPackagesMap.put(ps.name, ps);
    +-
    +-        /* collect signing key and add */
    +-        ArraySet<PublicKey> signingKeys = new ArraySet<PublicKey>();
    +-        PublicKey keyA = PackageParser.parsePublicKey(KeySetStrings.ctsKeySetPublicKeyA);
    +-        signingKeys.add(keyA);
    +-        mKsms.addSigningKeySetToPackageLPw(ps, signingKeys);
    +-
    +-        /* add again, to represent upgrade of package */
    +-        mKsms.addSigningKeySetToPackageLPw(ps, signingKeys);
    +-
    +-        assertEquals(1, KeySetUtils.getKeySetRefCount(mKsms, 1));
    +-        assertEquals(1, KeySetUtils.getPubKeyRefCount(mKsms, 1));
    +-        assertEquals(keyA, KeySetUtils.getPubKey(mKsms, 1));
    +-        LongSparseArray<ArraySet<Long>> ksMapping = KeySetUtils.getKeySetMapping(mKsms);
    +-        assertEquals(1, ksMapping.size());
    +-        ArraySet<Long> mapping = ksMapping.get(1);
    +-        assertEquals(1, mapping.size());
    +-        assertTrue(mapping.contains(new Long(1)));
    +-        assertEquals(1, ps.keySetData.getProperSigningKeySet());
    +-    }
    +-
    +-    /*
    +-     * upgrade an app (same packagename) with different unique keyset and verify
    +-     * that the old was removed.
    +-     */
    +-    public void testAddSigningKSToPackageUpgradeDiff() throws ReflectiveOperationException {
    +-
    +-        /* create PackageSetting and add to Settings mPackages */
    +-        PackageSetting ps = generateFakePackageSetting("packageA");
    +-        mPackagesMap.put(ps.name, ps);
    +-
    +-        /* collect signing key and add */
    +-        ArraySet<PublicKey> signingKeys = new ArraySet<PublicKey>();
    +-        PublicKey keyA = PackageParser.parsePublicKey(KeySetStrings.ctsKeySetPublicKeyA);
    +-        signingKeys.add(keyA);
    +-        mKsms.addSigningKeySetToPackageLPw(ps, signingKeys);
    +-
    +-        /* now upgrade with new key */
    +-        PublicKey keyB = PackageParser.parsePublicKey(KeySetStrings.ctsKeySetPublicKeyB);
    +-        signingKeys.removeAt(0);
    +-        signingKeys.add(keyB);
    +-        mKsms.addSigningKeySetToPackageLPw(ps, signingKeys);
    +-
    +-        assertEquals(0, KeySetUtils.getKeySetRefCount(mKsms, 1));
    +-        assertEquals(1, KeySetUtils.getKeySetRefCount(mKsms, 2));
    +-        assertEquals(0, KeySetUtils.getPubKeyRefCount(mKsms, 1));
    +-        assertEquals(1, KeySetUtils.getPubKeyRefCount(mKsms, 2));
    +-        assertEquals(keyB, KeySetUtils.getPubKey(mKsms, 2));
    +-        LongSparseArray<ArraySet<Long>> ksMapping = KeySetUtils.getKeySetMapping(mKsms);
    +-        assertEquals(1, ksMapping.size());
    +-        ArraySet<Long> mapping = ksMapping.get(2);
    +-        assertEquals(1, mapping.size());
    +-        assertTrue(mapping.contains(new Long(2)));
    +-        assertEquals(2, ps.keySetData.getProperSigningKeySet());
    +-    }
    +-
    +-    /*
    +-     * upgrade an app (same packagename) with different keyset and verify
    +-     * that the old had its ref count reduced due to reference by other ps.
    +-     */
    +-    public void testAddSigningKSToPackageUpgradeDiff2() throws ReflectiveOperationException {
    +-
    +-        /* create PackageSetting and add to Settings mPackages */
    +-        PackageSetting ps1 = generateFakePackageSetting("packageA");
    +-        mPackagesMap.put(ps1.name, ps1);
    +-        PackageSetting ps2 = generateFakePackageSetting("packageB");
    +-        mPackagesMap.put(ps2.name, ps2);
    +-
    +-        /* collect signing key and add */
    +-        ArraySet<PublicKey> signingKeys = new ArraySet<PublicKey>();
    +-        PublicKey keyA = PackageParser.parsePublicKey(KeySetStrings.ctsKeySetPublicKeyA);
    +-        signingKeys.add(keyA);
    +-        mKsms.addSigningKeySetToPackageLPw(ps1, signingKeys);
    +-        mKsms.addSigningKeySetToPackageLPw(ps2, signingKeys);
    +-
    +-        /* now upgrade with new key */
    +-        PublicKey keyB = PackageParser.parsePublicKey(KeySetStrings.ctsKeySetPublicKeyB);
    +-        signingKeys.removeAt(0);
    +-        signingKeys.add(keyB);
    +-        mKsms.addSigningKeySetToPackageLPw(ps1, signingKeys);
    +-
    +-        assertEquals(1, KeySetUtils.getKeySetRefCount(mKsms, 1));
    +-        assertEquals(1, KeySetUtils.getKeySetRefCount(mKsms, 2));
    +-        assertEquals(1, KeySetUtils.getPubKeyRefCount(mKsms, 1));
    +-        assertEquals(1, KeySetUtils.getPubKeyRefCount(mKsms, 2));
    +-        assertEquals(keyA, KeySetUtils.getPubKey(mKsms, 1));
    +-        assertEquals(keyB, KeySetUtils.getPubKey(mKsms, 2));
    +-        LongSparseArray<ArraySet<Long>> ksMapping = KeySetUtils.getKeySetMapping(mKsms);
    +-        assertEquals(2, ksMapping.size());
    +-        ArraySet<Long> mapping = ksMapping.get(1);
    +-        assertEquals(1, mapping.size());
    +-        assertTrue(mapping.contains(new Long(1)));
    +-        mapping = ksMapping.get(2);
    +-        assertEquals(1, mapping.size());
    +-        assertTrue(mapping.contains(new Long(2)));
    +-        assertEquals(2, ps1.keySetData.getProperSigningKeySet());
    +-        assertEquals(1, ps2.keySetData.getProperSigningKeySet());
    +-    }
    +-
    +-    /*
    +-     * Add orthoganal keyset info to system and ensure previous keysets are
    +-     * unmodified.
    +-     */
    +-    public void testAddSigningKSToPackageNewOrtho() throws ReflectiveOperationException {
    +-
    +-        /* create PackageSettings and add to Settings mPackages */
    +-        PackageSetting ps1 = generateFakePackageSetting("packageA");
    +-        mPackagesMap.put(ps1.name, ps1);
    +-        PackageSetting ps2 = generateFakePackageSetting("packageB");
    +-        mPackagesMap.put(ps2.name, ps2);
    +-
    +-        /* collect signing key and add */
    +-        ArraySet<PublicKey> signingKeys1 = new ArraySet<PublicKey>();
    +-        PublicKey keyA = PackageParser.parsePublicKey(KeySetStrings.ctsKeySetPublicKeyA);
    +-        signingKeys1.add(keyA);
    +-        mKsms.addSigningKeySetToPackageLPw(ps1, signingKeys1);
    +-
    +-        /* collect second signing key and add */
    +-        ArraySet<PublicKey> signingKeys2 = new ArraySet<PublicKey>();
    +-        PublicKey keyB = PackageParser.parsePublicKey(KeySetStrings.ctsKeySetPublicKeyB);
    +-        signingKeys2.add(keyB);
    +-        mKsms.addSigningKeySetToPackageLPw(ps2, signingKeys2);
    +-
    +-        /* verify first is unchanged */
    +-        assertEquals(1, KeySetUtils.getKeySetRefCount(mKsms, 1));
    +-        assertEquals(1, KeySetUtils.getPubKeyRefCount(mKsms, 1));
    +-        assertEquals(keyA, KeySetUtils.getPubKey(mKsms, 1));
    +-        LongSparseArray<ArraySet<Long>> ksMapping = KeySetUtils.getKeySetMapping(mKsms);
    +-        assertEquals(2, ksMapping.size());
    +-        ArraySet<Long> mapping = ksMapping.get(1);
    +-        assertEquals(1, mapping.size());
    +-        assertTrue(mapping.contains(new Long(1)));
    +-        assertEquals(1, ps1.keySetData.getProperSigningKeySet());
    +-
    +-        /* verify second */
    +-        assertEquals(1, KeySetUtils.getKeySetRefCount(mKsms, 2));
    +-        assertEquals(1, KeySetUtils.getPubKeyRefCount(mKsms, 2));
    +-        assertEquals(keyB, KeySetUtils.getPubKey(mKsms, 2));
    +-        mapping = ksMapping.get(2);
    +-        assertEquals(1, mapping.size());
    +-        assertTrue(mapping.contains(new  Long(2)));
    +-        assertEquals(2, ps2.keySetData.getProperSigningKeySet());
    +-    }
    +-
    +-    /*
    +-     * Add identical keyset info to system via new package and ensure previous
    +-     * keysets has reference count incremented
    +-     */
    +-    public void testAddSigningKSToPackageNewSame() throws ReflectiveOperationException {
    +-
    +-        /* create PackageSettings and add to Settings mPackages */
    +-        PackageSetting ps1 = generateFakePackageSetting("packageA");
    +-        mPackagesMap.put(ps1.name, ps1);
    +-        PackageSetting ps2 = generateFakePackageSetting("packageB");
    +-        mPackagesMap.put(ps2.name, ps2);
    +-
    +-        /* collect signing key and add */
    +-        ArraySet<PublicKey> signingKeys = new ArraySet<PublicKey>();
    +-        PublicKey keyA = PackageParser.parsePublicKey(KeySetStrings.ctsKeySetPublicKeyA);
    +-        signingKeys.add(keyA);
    +-        mKsms.addSigningKeySetToPackageLPw(ps1, signingKeys);
    +-
    +-        /* add again for second package */
    +-        mKsms.addSigningKeySetToPackageLPw(ps2, signingKeys);
    +-
    +-        assertEquals(2, KeySetUtils.getKeySetRefCount(mKsms, 1));
    +-        assertEquals(1, KeySetUtils.getPubKeyRefCount(mKsms, 1));
    +-        assertEquals(keyA, KeySetUtils.getPubKey(mKsms, 1));
    +-        LongSparseArray<ArraySet<Long>> ksMapping = KeySetUtils.getKeySetMapping(mKsms);
    +-        assertEquals(1, ksMapping.size());
    +-        ArraySet<Long> mapping = ksMapping.get(1);
    +-        assertEquals(1, mapping.size());
    +-        assertTrue(mapping.contains(new Long(1)));
    +-        assertEquals(1, ps1.keySetData.getProperSigningKeySet());
    +-        assertEquals(1, ps2.keySetData.getProperSigningKeySet());
    +-    }
    +-
    +-    /*
    +-     * add a package which is signed by a keyset which contains a previously seen
    +-     * public key and make sure its refernces are incremented.
    +-     */
    +-    public void testAddSigningKSToPackageSuper() throws ReflectiveOperationException {
    +-
    +-        /* create PackageSettings and add to Settings mPackages */
    +-        PackageSetting ps1 = generateFakePackageSetting("packageA");
    +-        mPackagesMap.put(ps1.name, ps1);
    +-        PackageSetting ps2 = generateFakePackageSetting("packageB");
    +-        mPackagesMap.put(ps2.name, ps2);
    +-
    +-        /* collect signing key and add */
    +-        ArraySet<PublicKey> signingKeys = new ArraySet<PublicKey>();
    +-        PublicKey keyA = PackageParser.parsePublicKey(KeySetStrings.ctsKeySetPublicKeyA);
    +-        signingKeys.add(keyA);
    +-        mKsms.addSigningKeySetToPackageLPw(ps1, signingKeys);
    +-
    +-        /* give ps2 a superset (add keyB) */
    +-        PublicKey keyB = PackageParser.parsePublicKey(KeySetStrings.ctsKeySetPublicKeyB);
    +-        signingKeys.add(keyB);
    +-        mKsms.addSigningKeySetToPackageLPw(ps2, signingKeys);
    +-
    +-        assertEquals(1, KeySetUtils.getKeySetRefCount(mKsms, 1));
    +-        assertEquals(1, KeySetUtils.getKeySetRefCount(mKsms, 2));
    +-        assertEquals(2, KeySetUtils.getPubKeyRefCount(mKsms, 1));
    +-        assertEquals(1, KeySetUtils.getPubKeyRefCount(mKsms, 2));
    +-        assertEquals(keyA, KeySetUtils.getPubKey(mKsms, 1));
    +-        assertEquals(keyB, KeySetUtils.getPubKey(mKsms, 2));
    +-        LongSparseArray<ArraySet<Long>> ksMapping = KeySetUtils.getKeySetMapping(mKsms);
    +-        assertEquals(2, ksMapping.size());
    +-        ArraySet<Long> mapping = ksMapping.get(1);
    +-        assertEquals(1, mapping.size());
    +-        assertTrue(mapping.contains(new Long(1)));
    +-        mapping = ksMapping.get(2);
    +-        assertEquals(2, mapping.size());
    +-        assertTrue(mapping.contains(new Long(1)));
    +-        assertTrue(mapping.contains(new Long(2)));
    +-        assertEquals(1, ps1.keySetData.getProperSigningKeySet());
    +-        assertEquals(2, ps2.keySetData.getProperSigningKeySet());
    +-    }
    +-
    +-    /*
    +-     * Upgrade an app (same pkgName) with different keyset which contains a public
    +-     * key from the previous keyset.  Verify old keyset removed and pub key ref
    +-     * count is accurate.
    +-     */
    +-    public void testAddSigningKSToPackageUpgradeDiffSuper() throws ReflectiveOperationException {
    +-
    +-        /* create PackageSetting and add to Settings mPackages */
    +-        PackageSetting ps = generateFakePackageSetting("packageA");
    +-        mPackagesMap.put(ps.name, ps);
    +-
    +-        /* collect signing key and add */
    +-        ArraySet<PublicKey> signingKeys = new ArraySet<PublicKey>();
    +-        PublicKey keyA = PackageParser.parsePublicKey(KeySetStrings.ctsKeySetPublicKeyA);
    +-        signingKeys.add(keyA);
    +-        mKsms.addSigningKeySetToPackageLPw(ps, signingKeys);
    +-
    +-        /* now with additional key */
    +-        PublicKey keyB = PackageParser.parsePublicKey(KeySetStrings.ctsKeySetPublicKeyB);
    +-        signingKeys.add(keyB);
    +-        mKsms.addSigningKeySetToPackageLPw(ps, signingKeys);
    +-
    +-        assertEquals(0, KeySetUtils.getKeySetRefCount(mKsms, 1));
    +-        assertEquals(1, KeySetUtils.getKeySetRefCount(mKsms, 2));
    +-        assertEquals(0, KeySetUtils.getPubKeyRefCount(mKsms, 1));
    +-        assertEquals(1, KeySetUtils.getPubKeyRefCount(mKsms, 2));
    +-        assertEquals(1, KeySetUtils.getPubKeyRefCount(mKsms, 3));
    +-
    +-        /* the pub key is removed w/prev keyset and may be either 2 or 3 */
    +-        assertTrue(keyA.equals(KeySetUtils.getPubKey(mKsms, 2)) || keyA.equals(KeySetUtils.getPubKey(mKsms, 3)));
    +-        assertTrue(keyB.equals(KeySetUtils.getPubKey(mKsms, 2)) || keyB.equals(KeySetUtils.getPubKey(mKsms, 3)));
    +-        assertFalse(KeySetUtils.getPubKey(mKsms, 2).equals(KeySetUtils.getPubKey(mKsms, 3)));
    +-        LongSparseArray<ArraySet<Long>> ksMapping = KeySetUtils.getKeySetMapping(mKsms);
    +-        assertEquals(1, ksMapping.size());
    +-        ArraySet<Long> mapping = ksMapping.get(2);
    +-        assertEquals(2, mapping.size());
    +-        assertTrue(mapping.contains(new Long(2)));
    +-        assertTrue(mapping.contains(new Long(3)));
    +-        assertEquals(2, ps.keySetData.getProperSigningKeySet());
    +-    }
    +-
    +-    /* add a defined keyset make sure it shows up */
    +-    public void testAddDefinedKSToPackageEmpty() throws ReflectiveOperationException {
    +-
    +-        /* create PackageSetting and add to Settings mPackages */
    +-        PackageSetting ps = generateFakePackageSetting("packageA");
    +-        mPackagesMap.put(ps.name, ps);
    +-
    +-        /* collect key and add */
    +-        ArrayMap<String, ArraySet<PublicKey>> definedKS = new ArrayMap<String, ArraySet<PublicKey>>();
    +-        ArraySet<PublicKey> keys = new ArraySet<PublicKey>();
    +-        PublicKey keyA = PackageParser.parsePublicKey(KeySetStrings.ctsKeySetPublicKeyA);
    +-        keys.add(keyA);
    +-        definedKS.put("aliasA", keys);
    +-        mKsms.addDefinedKeySetsToPackageLPw(ps, definedKS);
    +-
    +-        assertEquals(1, KeySetUtils.getKeySetRefCount(mKsms, 1));
    +-        assertEquals(1, KeySetUtils.getPubKeyRefCount(mKsms, 1));
    +-        assertEquals(keyA, KeySetUtils.getPubKey(mKsms, 1));
    +-        LongSparseArray<ArraySet<Long>> ksMapping = KeySetUtils.getKeySetMapping(mKsms);
    +-        assertEquals(1, ksMapping.size());
    +-        ArraySet<Long> mapping = ksMapping.get(1);
    +-        assertEquals(1, mapping.size());
    +-        assertTrue(mapping.contains(new Long(1)));
    +-        assertNotNull(ps.keySetData.getAliases().get("aliasA"));
    +-        assertEquals(new Long(1), ps.keySetData.getAliases().get("aliasA"));
    +-    }
    +-
    +-    /* add 2 defined keysets which refer to same keyset and make sure ref-ct is 2 */
    +-    public void testAddDefinedKSToPackageDoubleAlias() throws ReflectiveOperationException {
    +-
    +-        /* create PackageSetting and add to Settings mPackages */
    +-        PackageSetting ps = generateFakePackageSetting("packageA");
    +-        mPackagesMap.put(ps.name, ps);
    +-
    +-        /* collect key and add */
    +-        ArrayMap<String, ArraySet<PublicKey>> definedKS = new ArrayMap<String, ArraySet<PublicKey>>();
    +-        ArraySet<PublicKey> keys = new ArraySet<PublicKey>();
    +-        PublicKey keyA = PackageParser.parsePublicKey(KeySetStrings.ctsKeySetPublicKeyA);
    +-        keys.add(keyA);
    +-        definedKS.put("aliasA", keys);
    +-        definedKS.put("aliasA2", keys);
    +-        mKsms.addDefinedKeySetsToPackageLPw(ps, definedKS);
    +-
    +-        assertEquals(2, KeySetUtils.getKeySetRefCount(mKsms, 1));
    +-        assertEquals(1, KeySetUtils.getPubKeyRefCount(mKsms, 1));
    +-        assertEquals(keyA, KeySetUtils.getPubKey(mKsms, 1));
    +-        LongSparseArray<ArraySet<Long>> ksMapping = KeySetUtils.getKeySetMapping(mKsms);
    +-        assertEquals(1, ksMapping.size());
    +-        ArraySet<Long> mapping = ksMapping.get(1);
    +-        assertEquals(1, mapping.size());
    +-        assertTrue(mapping.contains(new Long(1)));
    +-        assertNotNull(ps.keySetData.getAliases().get("aliasA"));
    +-        assertEquals(new Long(1), ps.keySetData.getAliases().get("aliasA"));
    +-        assertNotNull(ps.keySetData.getAliases().get("aliasA2"));
    +-        assertEquals(new Long(1), ps.keySetData.getAliases().get("aliasA2"));
    +-    }
    +-
    +-    /* upgrd defined keyset ortho (make sure previous is removed for pkg) */
    +-    public void testAddDefinedKSToPackageOrthoUpgr() throws ReflectiveOperationException {
    +-
    +-        /* create PackageSetting and add to Settings mPackages */
    +-        PackageSetting ps = generateFakePackageSetting("packageA");
    +-        mPackagesMap.put(ps.name, ps);
    +-
    +-        /* collect key and add */
    +-        ArrayMap<String, ArraySet<PublicKey>> definedKS = new ArrayMap<String, ArraySet<PublicKey>>();
    +-        ArraySet<PublicKey> keys = new ArraySet<PublicKey>();
    +-        PublicKey keyA = PackageParser.parsePublicKey(KeySetStrings.ctsKeySetPublicKeyA);
    +-        keys.add(keyA);
    +-        definedKS.put("aliasA", keys);
    +-        mKsms.addDefinedKeySetsToPackageLPw(ps, definedKS);
    +-
    +-        /* now upgrade to different defined key-set */
    +-        keys = new ArraySet<PublicKey>();
    +-        PublicKey keyB = PackageParser.parsePublicKey(KeySetStrings.ctsKeySetPublicKeyB);
    +-        keys.add(keyB);
    +-        definedKS.remove("aliasA");
    +-        definedKS.put("aliasB", keys);
    +-        mKsms.addDefinedKeySetsToPackageLPw(ps, definedKS);
    +-
    +-        assertEquals(0, KeySetUtils.getKeySetRefCount(mKsms, 1));
    +-        assertEquals(0, KeySetUtils.getPubKeyRefCount(mKsms, 1));
    +-        assertEquals(1, KeySetUtils.getKeySetRefCount(mKsms, 2));
    +-        assertEquals(1, KeySetUtils.getPubKeyRefCount(mKsms, 2));
    +-        assertEquals(keyB, KeySetUtils.getPubKey(mKsms, 2));
    +-        LongSparseArray<ArraySet<Long>> ksMapping = KeySetUtils.getKeySetMapping(mKsms);
    +-        assertEquals(1, ksMapping.size());
    +-        ArraySet<Long> mapping = ksMapping.get(2);
    +-        assertEquals(1, mapping.size());
    +-        assertTrue(mapping.contains(new Long(2)));
    +-        assertNull(ps.keySetData.getAliases().get("aliasA"));
    +-        assertNotNull(ps.keySetData.getAliases().get("aliasB"));
    +-        assertEquals(new Long(2), ps.keySetData.getAliases().get("aliasB"));
    +-    }
    +-
    +-    /* upgrd defined keyset ortho but reuse alias (make sure old is removed and
    +-     * alias points to new keyset)
    +-     */
    +-    public void testAddDefinedKSToPackageOrthoUpgrAliasSame() throws ReflectiveOperationException {
    +-
    +-        /* create PackageSetting and add to Settings mPackages */
    +-        PackageSetting ps = generateFakePackageSetting("packageA");
    +-        mPackagesMap.put(ps.name, ps);
    +-
    +-        /* collect key and add */
    +-        ArrayMap<String, ArraySet<PublicKey>> definedKS = new ArrayMap<String, ArraySet<PublicKey>>();
    +-        ArraySet<PublicKey> keys = new ArraySet<PublicKey>();
    +-        PublicKey keyA = PackageParser.parsePublicKey(KeySetStrings.ctsKeySetPublicKeyA);
    +-        keys.add(keyA);
    +-        definedKS.put("aliasA", keys);
    +-        mKsms.addDefinedKeySetsToPackageLPw(ps, definedKS);
    +-
    +-        /* now upgrade to different set w/same alias as before */
    +-        keys = new ArraySet<PublicKey>();
    +-        PublicKey keyB = PackageParser.parsePublicKey(KeySetStrings.ctsKeySetPublicKeyB);
    +-        keys.add(keyB);
    +-        definedKS.put("aliasA", keys);
    +-        mKsms.addDefinedKeySetsToPackageLPw(ps, definedKS);
    +-
    +-        assertEquals(0, KeySetUtils.getKeySetRefCount(mKsms, 1));
    +-        assertEquals(0, KeySetUtils.getPubKeyRefCount(mKsms, 1));
    +-        assertEquals(1, KeySetUtils.getKeySetRefCount(mKsms, 2));
    +-        assertEquals(1, KeySetUtils.getPubKeyRefCount(mKsms, 2));
    +-        assertEquals(keyB, KeySetUtils.getPubKey(mKsms, 2));
    +-        LongSparseArray<ArraySet<Long>> ksMapping = KeySetUtils.getKeySetMapping(mKsms);
    +-        assertEquals(1, ksMapping.size());
    +-        ArraySet<Long> mapping = ksMapping.get(2);
    +-        assertEquals(1, mapping.size());
    +-        assertTrue(mapping.contains(new Long(2)));
    +-        assertNotNull(ps.keySetData.getAliases().get("aliasA"));
    +-        assertEquals(new Long(2), ps.keySetData.getAliases().get("aliasA"));
    +-    }
    +-
    +-     /* Start with defined ks of (A, B) and upgrade to (B, C).  Make sure B is
    +-      * unchanged. */
    +-    public void testAddDefinedKSToPackageOverlapUpgr() throws ReflectiveOperationException {
    +-
    +-        /* create PackageSetting and add to Settings mPackages */
    +-        PackageSetting ps = generateFakePackageSetting("packageA");
    +-        mPackagesMap.put(ps.name, ps);
    +-
    +-        /* collect keys A and B and add */
    +-        ArrayMap<String, ArraySet<PublicKey>> definedKS = new ArrayMap<String, ArraySet<PublicKey>>();
    +-        ArraySet<PublicKey> keys1 = new ArraySet<PublicKey>();
    +-        ArraySet<PublicKey> keys2 = new ArraySet<PublicKey>();
    +-        PublicKey keyA = PackageParser.parsePublicKey(KeySetStrings.ctsKeySetPublicKeyA);
    +-        PublicKey keyB = PackageParser.parsePublicKey(KeySetStrings.ctsKeySetPublicKeyB);
    +-        keys1.add(keyA);
    +-        keys2.add(keyB);
    +-        definedKS.put("aliasA", keys1);
    +-        definedKS.put("aliasB", keys2);
    +-        mKsms.addDefinedKeySetsToPackageLPw(ps, definedKS);
    +-
    +-        /* now upgrade to different set (B, C) */
    +-        keys1 = new ArraySet<PublicKey>();
    +-        PublicKey keyC = PackageParser.parsePublicKey(KeySetStrings.ctsKeySetPublicKeyC);
    +-        keys1.add(keyC);
    +-        definedKS.remove("aliasA");
    +-        definedKS.put("aliasC", keys1);
    +-        mKsms.addDefinedKeySetsToPackageLPw(ps, definedKS);
    +-
    +-        assertEquals(1, KeySetUtils.getKeySetRefCount(mKsms, 3));
    +-        assertEquals(1, KeySetUtils.getPubKeyRefCount(mKsms, 3));
    +-        assertEquals(keyC, KeySetUtils.getPubKey(mKsms, 3));
    +-        LongSparseArray<ArraySet<Long>> ksMapping = KeySetUtils.getKeySetMapping(mKsms);
    +-        assertEquals(2, ksMapping.size());
    +-        ArraySet<Long> mapping = ksMapping.get(3);
    +-        assertEquals(1, mapping.size());
    +-        assertTrue(mapping.contains(new Long(3)));
    +-        assertEquals(new Long(3), ps.keySetData.getAliases().get("aliasC"));
    +-
    +-        /* either keyset w/keyA or w/keyB was added first, address both cases */
    +-        if (1 == KeySetUtils.getKeySetRefCount(mKsms, 1)) {
    +-
    +-            /* keyB was added first and should have keyset 1 and pub-key 1 */
    +-            assertEquals(1, KeySetUtils.getPubKeyRefCount(mKsms, 1));
    +-            assertEquals(0, KeySetUtils.getKeySetRefCount(mKsms, 2));
    +-            assertEquals(0, KeySetUtils.getPubKeyRefCount(mKsms, 2));
    +-            assertEquals(keyB, KeySetUtils.getPubKey(mKsms, 1));
    +-            mapping = ksMapping.get(1);
    +-            assertEquals(1, mapping.size());
    +-            assertTrue(mapping.contains(new Long(1)));
    +-            assertEquals(new Long(1), ps.keySetData.getAliases().get("aliasB"));
    +-        } else {
    +-
    +-            /* keyA was added first and keyB has id 2 */
    +-            assertEquals(1, KeySetUtils.getKeySetRefCount(mKsms, 2));
    +-            assertEquals(1, KeySetUtils.getPubKeyRefCount(mKsms, 2));
    +-            assertEquals(0, KeySetUtils.getKeySetRefCount(mKsms, 1));
    +-            assertEquals(0, KeySetUtils.getPubKeyRefCount(mKsms, 1));
    +-            assertEquals(keyB, KeySetUtils.getPubKey(mKsms, 2));
    +-            mapping = ksMapping.get(2);
    +-            assertEquals(1, mapping.size());
    +-            assertTrue(mapping.contains(new Long(2)));
    +-            assertEquals(new Long(2), ps.keySetData.getAliases().get("aliasB"));
    +-        }
    +-        assertNull(ps.keySetData.getAliases().get("aliasA"));
    +-    }
    +-
    +-    /* add defined keyset, remove it, add again and make sure diff id. */
    +-    public void testAddDefinedKSToPackageThree() throws ReflectiveOperationException {
    +-
    +-        /* create PackageSetting and add to Settings mPackages */
    +-        PackageSetting ps = generateFakePackageSetting("packageA");
    +-        mPackagesMap.put(ps.name, ps);
    +-
    +-        /* collect key and add */
    +-        ArrayMap<String, ArraySet<PublicKey>> definedKS = new ArrayMap<String, ArraySet<PublicKey>>();
    +-        ArraySet<PublicKey> keys1 = new ArraySet<PublicKey>();
    +-        PublicKey keyA = PackageParser.parsePublicKey(KeySetStrings.ctsKeySetPublicKeyA);
    +-        keys1.add(keyA);
    +-        definedKS.put("aliasA", keys1);
    +-        mKsms.addDefinedKeySetsToPackageLPw(ps, definedKS);
    +-
    +-        /* now upgrade to different set */
    +-        ArraySet<PublicKey> keys2 = new ArraySet<PublicKey>();
    +-        PublicKey keyB = PackageParser.parsePublicKey(KeySetStrings.ctsKeySetPublicKeyB);
    +-        keys2.add(keyB);
    +-        definedKS.remove("aliasA");
    +-        definedKS.put("aliasB", keys2);
    +-        mKsms.addDefinedKeySetsToPackageLPw(ps, definedKS);
    +-
    +-        /* upgrade back to original */
    +-        definedKS.remove("aliasB");
    +-        definedKS.put("aliasA", keys1);
    +-        mKsms.addDefinedKeySetsToPackageLPw(ps, definedKS);
    +-
    +-        assertEquals(0, KeySetUtils.getKeySetRefCount(mKsms, 1));
    +-        assertEquals(0, KeySetUtils.getKeySetRefCount(mKsms, 2));
    +-        assertEquals(1, KeySetUtils.getKeySetRefCount(mKsms, 3));
    +-        assertEquals(0, KeySetUtils.getPubKeyRefCount(mKsms, 1));
    +-        assertEquals(0, KeySetUtils.getPubKeyRefCount(mKsms, 2));
    +-        assertEquals(1, KeySetUtils.getPubKeyRefCount(mKsms, 3));
    +-        assertEquals(keyA, KeySetUtils.getPubKey(mKsms, 3));
    +-        LongSparseArray<ArraySet<Long>> ksMapping = KeySetUtils.getKeySetMapping(mKsms);
    +-        assertEquals(1, ksMapping.size());
    +-        ArraySet<Long> mapping = ksMapping.get(3);
    +-        assertEquals(1, mapping.size());
    +-        assertTrue(mapping.contains(new Long(3)));
    +-        assertEquals(new Long(3), ps.keySetData.getAliases().get("aliasA"));
    +-    }
    +-
    +-    /* add upgrade keyset for existing defined keyset and check that it is recorded */
    +-    public void testAddUpgradeKSToPackageEmpty() {
    +-
    +-        /* create PackageSetting and add to Settings mPackages */
    +-        PackageSetting ps = generateFakePackageSetting("packageA");
    +-        mPackagesMap.put(ps.name, ps);
    +-
    +-        /* collect key and add, and denote as an upgrade keyset */
    +-        ArrayMap<String, ArraySet<PublicKey>> definedKS = new ArrayMap<String, ArraySet<PublicKey>>();
    +-        ArraySet<PublicKey> keys = new ArraySet<PublicKey>();
    +-        PublicKey keyA = PackageParser.parsePublicKey(KeySetStrings.ctsKeySetPublicKeyA);
    +-        keys.add(keyA);
    +-        definedKS.put("aliasA", keys);
    +-        mKsms.addDefinedKeySetsToPackageLPw(ps, definedKS);
    +-        ArraySet<String> upgradeKS = new ArraySet<String>();
    +-        upgradeKS.add("aliasA");
    +-        mKsms.addUpgradeKeySetsToPackageLPw(ps, upgradeKS);
    +-
    +-        assertEquals(1, ps.keySetData.getUpgradeKeySets().length);
    +-        assertEquals(1, ps.keySetData.getUpgradeKeySets()[0]);
    +-    }
    +-
    +-    /* add upgrade keyset for non-existing defined and check that it compains */
    +-    public void testAddUpgradeKSToPackageWrong() {
    +-
    +-        /* create PackageSetting and add to Settings mPackages */
    +-        PackageSetting ps = generateFakePackageSetting("packageA");
    +-        mPackagesMap.put(ps.name, ps);
    +-
    +-        /* collect key and add and try to specify bogus upgrade keyset */
    +-        ArrayMap<String, ArraySet<PublicKey>> definedKS = new ArrayMap<String, ArraySet<PublicKey>>();
    +-        ArraySet<PublicKey> keys = new ArraySet<PublicKey>();
    +-        PublicKey keyA = PackageParser.parsePublicKey(KeySetStrings.ctsKeySetPublicKeyA);
    +-        keys.add(keyA);
    +-        definedKS.put("aliasA", keys);
    +-        mKsms.addDefinedKeySetsToPackageLPw(ps, definedKS);
    +-        ArraySet<String> upgradeKS = new ArraySet<String>();
    +-        upgradeKS.add("aliasB");
    +-        try {
    +-            mKsms.addUpgradeKeySetsToPackageLPw(ps, upgradeKS);
    +-        } catch (IllegalArgumentException e) {
    +-
    +-            /* should have been caught in packagemanager, so exception thrown */
    +-            return;
    +-        }
    +-        fail("Expected IllegalArgumentException when adding undefined upgrade keyset!!");
    +-    }
    +-
    +-    /* upgrade from defined keysets w/upgrade to different defined keysets and
    +-     * make sure the previously specified upgrade keyset has been removed. */
    +-    public void testAddUpgradeKSToPackageDisappear() {
    +-
    +-        /* create PackageSetting and add to Settings mPackages */
    +-        PackageSetting ps = generateFakePackageSetting("packageA");
    +-        mPackagesMap.put(ps.name, ps);
    +-
    +-        /* collect key and add */
    +-        ArrayMap<String, ArraySet<PublicKey>> definedKS = new ArrayMap<String, ArraySet<PublicKey>>();
    +-        ArraySet<PublicKey> keys = new ArraySet<PublicKey>();
    +-        PublicKey keyA = PackageParser.parsePublicKey(KeySetStrings.ctsKeySetPublicKeyA);
    +-        keys.add(keyA);
    +-        definedKS.put("aliasA", keys);
    +-        mKsms.addDefinedKeySetsToPackageLPw(ps, definedKS);
    +-        ArraySet<String> upgradeKS = new ArraySet<String>();
    +-        upgradeKS.add("aliasA");
    +-        mKsms.addUpgradeKeySetsToPackageLPw(ps, upgradeKS);
    +-
    +-        keys = new ArraySet<PublicKey>();
    +-        PublicKey keyB = PackageParser.parsePublicKey(KeySetStrings.ctsKeySetPublicKeyB);
    +-        keys.add(keyB);
    +-        definedKS.remove("aliasA");
    +-        definedKS.put("aliasB", keys);
    +-        mKsms.addDefinedKeySetsToPackageLPw(ps, definedKS);
    +-        assertNull(ps.keySetData.getUpgradeKeySets());
    +-    }
    +-
    +-    /* remove package and validate that keyset and public keys are removed */
    +-    public void testRemoveAppKSDataUnique() throws ReflectiveOperationException {
    +-
    +-        /* create PackageSetting and add to Settings mPackages */
    +-        PackageSetting ps = generateFakePackageSetting("packageA");
    +-        mPackagesMap.put(ps.name, ps);
    +-
    +-        /* collect signing key and add */
    +-        ArraySet<PublicKey> signingKeys = new ArraySet<PublicKey>();
    +-        PublicKey keyA = PackageParser.parsePublicKey(KeySetStrings.ctsKeySetPublicKeyA);
    +-        signingKeys.add(keyA);
    +-        mKsms.addSigningKeySetToPackageLPw(ps, signingKeys);
    +-
    +-        /* remove its references */
    +-        mKsms.removeAppKeySetDataLPw(ps.name);
    +-        assertEquals(0, KeySetUtils.getKeySetRefCount(mKsms, 1));
    +-        assertEquals(0, KeySetUtils.getPubKeyRefCount(mKsms, 1));
    +-        LongSparseArray<ArraySet<Long>> ksMapping = KeySetUtils.getKeySetMapping(mKsms);
    +-        assertEquals(0, ksMapping.size());
    +-        assertEquals(PackageKeySetData.KEYSET_UNASSIGNED, ps.keySetData.getProperSigningKeySet());
    +-    }
    +-
    +-    /* remove package and validate that keysets remain if defined elsewhere but
    +-     * have refcounts decreased. */
    +-    public void testRemoveAppKSDataDup() throws ReflectiveOperationException {
    +-
    +-        /* create PackageSettings and add to Settings mPackages */
    +-        PackageSetting ps1 = generateFakePackageSetting("packageA");
    +-        mPackagesMap.put(ps1.name, ps1);
    +-        PackageSetting ps2 = generateFakePackageSetting("packageB");
    +-        mPackagesMap.put(ps2.name, ps2);
    +-
    +-        /* collect signing key and add for both packages */
    +-        ArraySet<PublicKey> signingKeys = new ArraySet<PublicKey>();
    +-        PublicKey keyA = PackageParser.parsePublicKey(KeySetStrings.ctsKeySetPublicKeyA);
    +-        signingKeys.add(keyA);
    +-        mKsms.addSigningKeySetToPackageLPw(ps1, signingKeys);
    +-        mKsms.addSigningKeySetToPackageLPw(ps2, signingKeys);
    +-
    +-        /* remove references from first package */
    +-        mKsms.removeAppKeySetDataLPw(ps1.name);
    +-
    +-        assertEquals(1, KeySetUtils.getKeySetRefCount(mKsms, 1));
    +-        assertEquals(1, KeySetUtils.getPubKeyRefCount(mKsms, 1));
    +-        LongSparseArray<ArraySet<Long>> ksMapping = KeySetUtils.getKeySetMapping(mKsms);
    +-        assertEquals(1, ksMapping.size());
    +-        assertEquals(PackageKeySetData.KEYSET_UNASSIGNED, ps1.keySetData.getProperSigningKeySet());
    +-        assertEquals(1, ps2.keySetData.getProperSigningKeySet());
    +-    }
    +-
    +-    /* remove package which used defined and upgrade keysets and ensure  removed */
    +-    public void testRemoveAppKSDataDefined() throws ReflectiveOperationException {
    +-
    +-        /* create PackageSetting and add to Settings mPackages */
    +-        PackageSetting ps = generateFakePackageSetting("packageA");
    +-        mPackagesMap.put(ps.name, ps);
    +-
    +-        /* collect key and add */
    +-        ArrayMap<String, ArraySet<PublicKey>> definedKS = new ArrayMap<String, ArraySet<PublicKey>>();
    +-        ArraySet<PublicKey> keys = new ArraySet<PublicKey>();
    +-        PublicKey keyA = PackageParser.parsePublicKey(KeySetStrings.ctsKeySetPublicKeyA);
    +-        keys.add(keyA);
    +-
    +-        /* removal requires signing keyset to be specified (since all apps are
    +-         * assumed to have it).  We skipped this in the defined tests, but can't
    +-         * here. */
    +-        mKsms.addSigningKeySetToPackageLPw(ps, keys);
    +-
    +-        definedKS.put("aliasA", keys);
    +-        mKsms.addDefinedKeySetsToPackageLPw(ps, definedKS);
    +-        ArraySet<String> upgradeKS = new ArraySet<String>();
    +-        upgradeKS.add("aliasA");
    +-        mKsms.addUpgradeKeySetsToPackageLPw(ps, upgradeKS);
    +-        mKsms.removeAppKeySetDataLPw(ps.name);
    +-
    +-        assertEquals(0, KeySetUtils.getKeySetRefCount(mKsms, 1));
    +-        assertEquals(0, KeySetUtils.getPubKeyRefCount(mKsms, 1));
    +-        LongSparseArray<ArraySet<Long>> ksMapping = KeySetUtils.getKeySetMapping(mKsms);
    +-        assertEquals(0, ksMapping.size());
    +-        assertEquals(PackageKeySetData.KEYSET_UNASSIGNED, ps.keySetData.getProperSigningKeySet());
    +-        assertEquals(0, ps.keySetData.getAliases().size());
    +-        assertNull(ps.keySetData.getUpgradeKeySets());
    +-    }
    +-}
    +diff --git a/services/tests/servicestests/src/com/android/server/pm/KeySetStrings.java b/services/tests/servicestests/src/com/android/server/pm/KeySetStrings.java
    +deleted file mode 100644
    +index 89d01ae..0000000
    +--- a/services/tests/servicestests/src/com/android/server/pm/KeySetStrings.java
    ++++ /dev/null
    +@@ -1,137 +0,0 @@
    +-/*
    +- * Copyright (C) 2015 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 com.android.server.pm;
    +-
    +-public class KeySetStrings {
    +-
    +-    /*
    +-     * public keys taken from:
    +-     * openssl x509 -in cts-keyset-test-${N}.x509.pem -inform PEM -pubkey
    +-     * in /platform/cts/hostsidetests/appsecurity/certs/keysets
    +-     */
    +-    public static final String ctsKeySetPublicKeyA =
    +-            "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAwf5zJblvYSB7Ym7or/7Ggg"
    +-            + "AAu7mp7RrykPJsXhod8doFhVT5s7eF3A4MCE55vvANP7HvwMw2b+T6qx7Pq0VJtb"
    +-            + "bSDtlBHBtIc47Pjq0CsDg590BUcgKp7PdJ9J6UVgtzDnV6cGEpXmSag3sY+lqiW0"
    +-            + "4ytPhCVwzYTWGdYe9+TIl47cBrveRfLOlGrcuFQe+zCTmDFqzBKCRHK9b7l5PDWv"
    +-            + "XXyg65Uu/MBUA/TZWO0fEqOlxZG/nn6DUKQLhPdmJRXWJ3WqMNMhJGD+nKtkmdX7"
    +-            + "03xRqmg4h+6g0S7M9Y3IQ2NUGyw05AYzCguHB/Mv6uVIiW659wpbyb45TgKG3UhQ"
    +-            + "IDAQAB";
    +-
    +-    public static final String ctsKeySetPublicKeyB =
    +-            "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAoeFZqMqTbZiozFTXMkXtSK"
    +-            + "JRzn2qODZgvVXAAwKTi50xYcbPcHTfKxtif8+q7OCp/50JYDH32bg6wkUunn5+dE"
    +-            + "aHkxZY8d7uw46tQtl5dNGi+6cc4MezVLCS6nkqNDusAgdvgLU6Fl6SGi02KTp1vk"
    +-            + "t6CwLO977YJP7kt9ouDRTG7ASJiq3OyRRoOqYHhD9gpsbUq4w+1bXGfuuZujA1dX"
    +-            + "yovXtvrHUGOdFIEBYOVYGfCcwh3lXPmjNJMlHtKQkurq8/LH7a1B5ocoXCGsyR8Y"
    +-            + "HdlWfrqRAfzgOB1KCnNNmWqskU9LOci3uQn9IDeMEFmAd8FqF8SwV+4Ludk/xWGQ"
    +-            + "IDAQAB";
    +-
    +-    public static final String ctsKeySetPublicKeyC =
    +-            "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEArwIJ/p9zZ6pGe7h1lBJULE"
    +-            + "5lbYbC3mh5G43OsJ+B0CebN4KzEKyVg+wmkuGSvG2xXUp1BlbipSjnTJ5bUt2iBu"
    +-            + "wB81Lvumg9GOfCpTBGtfE4a4igtfo7e2U8IbRzEYbhaZlBEmC1BDUvdTFdMRGZPu"
    +-            + "hUcMkwit4RpHkL6rttuOfaeoJwsgEjbELyzgcm+1Z49Den/JmmXNGMw1/QMibBFG"
    +-            + "vGkhu2rHg/SYiKpupclU4FIeALcOSnPkrrY6LuSATHDnYvuvK3Vhu0EBKID+rAv5"
    +-            + "j6BNvnu25SAf3GgS7PLuyVlhiE5p3hTevXn5g/7tjJlXa0FsbMlnFf53WyP9pRWw"
    +-            + "IDAQAB";
    +-
    +-    /*
    +-     * certs taken from packagemanager packages.xml output corresponding to certs in
    +-     * /platform/cts/hostsidetests/appsecurity/certs/keysets
    +-     */
    +-    public static final String ctsKeySetCertA =
    +-            "3082030b308201f3a0030201020209009d76e8a600170813300d06092a864886f7"
    +-            + "0d0101050500301c311a301806035504030c116374732d6b65797365742d7465"
    +-            + "73742d61301e170d3134303931313030343434385a170d343230313237303034"
    +-            + "3434385a301c311a301806035504030c116374732d6b65797365742d74657374"
    +-            + "2d6130820122300d06092a864886f70d01010105000382010f003082010a0282"
    +-            + "010100c1fe7325b96f61207b626ee8affec6820000bbb9a9ed1af290f26c5e1a"
    +-            + "1df1da058554f9b3b785dc0e0c084e79bef00d3fb1efc0cc366fe4faab1ecfab"
    +-            + "4549b5b6d20ed9411c1b48738ecf8ead02b03839f740547202a9ecf749f49e94"
    +-            + "560b730e757a7061295e649a837b18fa5aa25b4e32b4f842570cd84d619d61ef"
    +-            + "7e4c8978edc06bbde45f2ce946adcb8541efb309398316acc12824472bd6fb97"
    +-            + "93c35af5d7ca0eb952efcc05403f4d958ed1f12a3a5c591bf9e7e8350a40b84f"
    +-            + "7662515d62775aa30d3212460fe9cab6499d5fbd37c51aa683887eea0d12eccf"
    +-            + "58dc84363541b2c34e406330a0b8707f32feae548896eb9f70a5bc9be394e028"
    +-            + "6dd4850203010001a350304e301d0603551d0e04160414debf602e08b7573bce"
    +-            + "4816ac32eab215fb052892301f0603551d23041830168014debf602e08b7573b"
    +-            + "ce4816ac32eab215fb052892300c0603551d13040530030101ff300d06092a86"
    +-            + "4886f70d0101050500038201010092f1b8d08252d808d3051dce80780bd27eef"
    +-            + "e3f6b6d935398afb448209461b6f8b352e830d4358661e1b3e9eb9ab3937bddd"
    +-            + "581a28f533da1ebeb6838ce4a84ca64c43507c5ef9528917857e4d1c4c5996cf"
    +-            + "6b3d30823db514a715eeee709d69e38b4f0ef5dce4b08ce40fd52b39ac651311"
    +-            + "b6d1814913d922ce84748b6999256851fb583a49e35cecf79a527108df8e062d"
    +-            + "f4831addbb12a661999d41849e2545150cab74c91447dd15e55cdf3f8082dcab"
    +-            + "667c5cee3350d0f15d3970edcf3e81882e80985b0c0bf9917adb55c634de3a92"
    +-            + "e8fb5d9413b1703bec116b9ee9346b658f394acfe0c60406718be80b7110df8b"
    +-            + "44c984f001e1d16aac3831afee18";
    +-
    +-    public static final String ctsKeySetCertB =
    +-            "3082030b308201f3a003020102020900e670a5b2ec1e8a12300d06092a864886f7"
    +-            + "0d0101050500301c311a301806035504030c116374732d6b65797365742d7465"
    +-            + "73742d62301e170d3134303931313030343434315a170d343230313237303034"
    +-            + "3434315a301c311a301806035504030c116374732d6b65797365742d74657374"
    +-            + "2d6230820122300d06092a864886f70d01010105000382010f003082010a0282"
    +-            + "010100a1e159a8ca936d98a8cc54d73245ed48a251ce7daa383660bd55c00302"
    +-            + "938b9d3161c6cf7074df2b1b627fcfaaece0a9ff9d096031f7d9b83ac2452e9e"
    +-            + "7e7e744687931658f1deeec38ead42d97974d1a2fba71ce0c7b354b092ea792a"
    +-            + "343bac02076f80b53a165e921a2d36293a75be4b7a0b02cef7bed824fee4b7da"
    +-            + "2e0d14c6ec04898aadcec914683aa607843f60a6c6d4ab8c3ed5b5c67eeb99ba"
    +-            + "3035757ca8bd7b6fac750639d14810160e55819f09cc21de55cf9a33493251ed"
    +-            + "29092eaeaf3f2c7edad41e687285c21acc91f181dd9567eba9101fce0381d4a0"
    +-            + "a734d996aac914f4b39c8b7b909fd20378c10598077c16a17c4b057ee0bb9d93"
    +-            + "fc56190203010001a350304e301d0603551d0e04160414ccd4d9d47dcc18889d"
    +-            + "cba32de37e6570c88f8109301f0603551d23041830168014ccd4d9d47dcc1888"
    +-            + "9dcba32de37e6570c88f8109300c0603551d13040530030101ff300d06092a86"
    +-            + "4886f70d0101050500038201010061951cf9c9a629b30b560d53d62a72796edc"
    +-            + "97b0b210b567859311b14574abb052ef08cabb0b18cef5517597eabee9498a07"
    +-            + "a04472b8e6eee8668c05d2ff28141a36351593551f0c9d27feb4367fd0d23c76"
    +-            + "e36035f9d06d2d24b4167120fabdcfddfbe872bd127a602de8563ad6027ee19a"
    +-            + "fc21065cf02d6aaf97bf78388c3c129e72d1b31f5727896aaad7fe6773fbc285"
    +-            + "34e89194a75e1ecf64bcc5fa228e71e3be9efc78cb39bbabf60e334b403fc3e4"
    +-            + "9eb59c3407883d10efb04470a7d7d12114e7c9ddc3b381ffc43e8e8a830efa59"
    +-            + "38e47eef0d4dd39a80186c3b4236f812f52775941fe1dd73d51f6f50ab0916e3"
    +-            + "149c31feabcf38860be45d113a54";
    +-
    +-    public static final String ctsKeySetCertC =
    +-            "3082030b308201f3a0030201020209008f2e824e4e17810d300d06092a864886f7"
    +-            + "0d0101050500301c311a301806035504030c116374732d6b65797365742d7465"
    +-            + "73742d63301e170d3134303931313030343432325a170d343230313237303034"
    +-            + "3432325a301c311a301806035504030c116374732d6b65797365742d74657374"
    +-            + "2d6330820122300d06092a864886f70d01010105000382010f003082010a0282"
    +-            + "010100af0209fe9f7367aa467bb8759412542c4e656d86c2de68791b8dceb09f"
    +-            + "81d0279b3782b310ac9583ec2692e192bc6db15d4a750656e2a528e74c9e5b52"
    +-            + "dda206ec01f352efba683d18e7c2a53046b5f1386b88a0b5fa3b7b653c21b473"
    +-            + "1186e16999411260b504352f75315d3111993ee85470c9308ade11a4790beabb"
    +-            + "6db8e7da7a8270b201236c42f2ce0726fb5678f437a7fc99a65cd18cc35fd032"
    +-            + "26c1146bc6921bb6ac783f49888aa6ea5c954e0521e00b70e4a73e4aeb63a2ee"
    +-            + "4804c70e762fbaf2b7561bb41012880feac0bf98fa04dbe7bb6e5201fdc6812e"
    +-            + "cf2eec95961884e69de14debd79f983feed8c99576b416c6cc96715fe775b23f"
    +-            + "da515b0203010001a350304e301d0603551d0e041604141b8137c73974a17633"
    +-            + "686f93798a7f7b8385bded301f0603551d230418301680141b8137c73974a176"
    +-            + "33686f93798a7f7b8385bded300c0603551d13040530030101ff300d06092a86"
    +-            + "4886f70d01010505000382010100276ce2ca7b78b12aa2e432c8287075af91e5"
    +-            + "2a15a8586e23cdd7524a4c5ae04156307e95275cdfd841f2d28c0583cb36779e"
    +-            + "25d849a8b608eb48a84a50202a7825c7847e865409b1dd01303b5b1bdfafecab"
    +-            + "bfe1c6ec5f30ce1cb16b93db72ef726f77a48ca4f5ac5e12c4ad08c6df6fbf7e"
    +-            + "1548ef7ca80cf1d98abb550c0e28b246e8c0f1a975ffb624f1a4aeec11f01ba6"
    +-            + "02631d56645f5ae042dbf67b444b160711ca2629c456c5cc12e2ff56fa1332b6"
    +-            + "92483d14d2e6fb8e026246058fb5826e3958ee8f780d0fc2b840d51c2bbf0d24"
    +-            + "e9e108ef1c2d9ec13797bb4e5793349628a2ddb2a79c9d9c5736e7aea93e4552"
    +-            + "18fd162e0a42a4fbb4aa9df82b8a";
    +-}
    +diff --git a/services/tests/servicestests/src/com/android/server/pm/KeySetUtils.java b/services/tests/servicestests/src/com/android/server/pm/KeySetUtils.java
    +deleted file mode 100644
    +index 9e1a366..0000000
    +--- a/services/tests/servicestests/src/com/android/server/pm/KeySetUtils.java
    ++++ /dev/null
    +@@ -1,89 +0,0 @@
    +-/*
    +- * Copyright (C) 2015 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 com.android.server.pm;
    +-
    +-import android.util.ArraySet;
    +-import android.util.LongSparseArray;
    +-
    +-import java.lang.reflect.Field;
    +-import java.security.PublicKey;
    +-
    +-public class KeySetUtils {
    +-
    +-    public static PublicKey getPubKey(KeySetManagerService ksms, long pkId)
    +-            throws NoSuchFieldException, IllegalAccessException {
    +-        Field pkField = ksms.getClass().getDeclaredField("mPublicKeys");
    +-        pkField.setAccessible(true);
    +-        LongSparseArray<KeySetManagerService.PublicKeyHandle> mPublicKeys =
    +-            (LongSparseArray<KeySetManagerService.PublicKeyHandle>) pkField.get(ksms);
    +-        KeySetManagerService.PublicKeyHandle pkh = mPublicKeys.get(pkId);
    +-        if (pkh == null) {
    +-            return null;
    +-        } else {
    +-            return pkh.getKey();
    +-        }
    +-    }
    +-
    +-    public static int getPubKeyRefCount(KeySetManagerService ksms, long pkId)
    +-            throws NoSuchFieldException, IllegalAccessException {
    +-        Field pkField = ksms.getClass().getDeclaredField("mPublicKeys");
    +-        pkField.setAccessible(true);
    +-        LongSparseArray<KeySetManagerService.PublicKeyHandle> mPublicKeys =
    +-            (LongSparseArray<KeySetManagerService.PublicKeyHandle>) pkField.get(ksms);
    +-        KeySetManagerService.PublicKeyHandle pkh = mPublicKeys.get(pkId);
    +-        if (pkh == null) {
    +-            return 0;
    +-        } else {
    +-            return pkh.getRefCountLPr();
    +-        }
    +-    }
    +-
    +-    public static int getKeySetRefCount(KeySetManagerService ksms, long keysetId)
    +-            throws NoSuchFieldException, IllegalAccessException {
    +-        Field ksField = ksms.getClass().getDeclaredField("mKeySets");
    +-        ksField.setAccessible(true);
    +-        LongSparseArray<KeySetHandle> mKeySets =
    +-            (LongSparseArray<KeySetHandle>) ksField.get(ksms);
    +-        KeySetHandle ksh = mKeySets.get(keysetId);
    +-        if (ksh == null) {
    +-            return 0;
    +-        } else {
    +-            return ksh.getRefCountLPr();
    +-        }
    +-    }
    +-
    +-    public static LongSparseArray<ArraySet<Long>> getKeySetMapping(KeySetManagerService ksms)
    +-            throws NoSuchFieldException, IllegalAccessException {
    +-        Field ksField = ksms.getClass().getDeclaredField("mKeySetMapping");
    +-        ksField.setAccessible(true);
    +-        return (LongSparseArray<ArraySet<Long>>) ksField.get(ksms);
    +-    }
    +-
    +-    public static Long getLastIssuedKeyId(KeySetManagerService ksms)
    +-            throws NoSuchFieldException, IllegalAccessException {
    +-        Field ksField = ksms.getClass().getDeclaredField("lastIssuedKeyId");
    +-        ksField.setAccessible(true);
    +-        return (Long) ksField.get(ksms);
    +-    }
    +-
    +-    public static Long getLastIssuedKeySetId(KeySetManagerService ksms)
    +-            throws NoSuchFieldException, IllegalAccessException {
    +-        Field ksField = ksms.getClass().getDeclaredField("lastIssuedKeySetId");
    +-        ksField.setAccessible(true);
    +-        return (Long) ksField.get(ksms);
    +-    }
    +-}
    +diff --git a/services/tests/servicestests/src/com/android/server/pm/PackageManagerSettingsTests.java b/services/tests/servicestests/src/com/android/server/pm/PackageManagerSettingsTests.java
    +deleted file mode 100644
    +index bf6343f..0000000
    +--- a/services/tests/servicestests/src/com/android/server/pm/PackageManagerSettingsTests.java
    ++++ /dev/null
    +@@ -1,349 +0,0 @@
    +-/*
    +- * Copyright (C) 2012 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 com.android.server.pm;
    +-
    +-import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_DEFAULT;
    +-import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_DISABLED;
    +-import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_DISABLED_USER;
    +-import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_ENABLED;
    +-
    +-import android.annotation.NonNull;
    +-import android.content.Context;
    +-import android.content.pm.PackageParser;
    +-import android.content.pm.UserInfo;
    +-import android.os.UserHandle;
    +-import android.test.AndroidTestCase;
    +-import android.util.ArrayMap;
    +-import android.util.ArraySet;
    +-import android.util.Log;
    +-import android.util.LongSparseArray;
    +-
    +-import com.android.internal.os.AtomicFile;
    +-
    +-import java.lang.reflect.Constructor;
    +-import java.io.File;
    +-import java.io.FileOutputStream;
    +-import java.io.IOException;
    +-import java.security.PublicKey;
    +-import java.util.ArrayList;
    +-import java.util.List;
    +-
    +-public class PackageManagerSettingsTests extends AndroidTestCase {
    +-    private static final String PACKAGE_NAME_2 = "com.google.app2";
    +-    private static final String PACKAGE_NAME_3 = "com.android.app3";
    +-    private static final String PACKAGE_NAME_1 = "com.google.app1";
    +-    private static final boolean localLOGV = true;
    +-    public static final String TAG = "PackageManagerSettingsTests";
    +-    protected final String PREFIX = "android.content.pm";
    +-
    +-    private @NonNull List<UserInfo> createFakeUsers() {
    +-        ArrayList<UserInfo> users = new ArrayList<>();
    +-        users.add(new UserInfo(UserHandle.USER_SYSTEM, "test user", UserInfo.FLAG_INITIALIZED));
    +-        return users;
    +-    }
    +-
    +-    private void writeFile(File file, byte[] data) {
    +-        file.mkdirs();
    +-        try {
    +-            AtomicFile aFile = new AtomicFile(file);
    +-            FileOutputStream fos = aFile.startWrite();
    +-            fos.write(data);
    +-            aFile.finishWrite(fos);
    +-        } catch (IOException ioe) {
    +-            Log.e(TAG, "Cannot write file " + file.getPath());
    +-        }
    +-    }
    +-
    +-    private void writePackagesXml() {
    +-        writeFile(new File(getContext().getFilesDir(), "system/packages.xml"),
    +-                ("<?xml version='1.0' encoding='utf-8' standalone='yes' ?>"
    +-                + "<packages>"
    +-                + "<last-platform-version internal=\"15\" external=\"0\" fingerprint=\"foo\" />"
    +-                + "<permission-trees>"
    +-                + "<item name=\"com.google.android.permtree\" package=\"com.google.android.permpackage\" />"
    +-                + "</permission-trees>"
    +-                + "<permissions>"
    +-                + "<item name=\"android.permission.WRITE_CALL_LOG\" package=\"android\" protection=\"1\" />"
    +-                + "<item name=\"android.permission.ASEC_ACCESS\" package=\"android\" protection=\"2\" />"
    +-                + "<item name=\"android.permission.ACCESS_WIMAX_STATE\" package=\"android\" />"
    +-                + "<item name=\"android.permission.REBOOT\" package=\"android\" protection=\"18\" />"
    +-                + "</permissions>"
    +-                + "<package name=\"com.google.app1\" codePath=\"/system/app/app1.apk\" nativeLibraryPath=\"/data/data/com.google.app1/lib\" flags=\"1\" ft=\"1360e2caa70\" it=\"135f2f80d08\" ut=\"1360e2caa70\" version=\"1109\" sharedUserId=\"11000\">"
    +-                + "<sigs count=\"1\">"
    +-                + "<cert index=\"0\" key=\"" + KeySetStrings.ctsKeySetCertA + "\" />"
    +-                + "</sigs>"
    +-                + "<proper-signing-keyset identifier=\"1\" />"
    +-                + "</package>"
    +-                + "<package name=\"com.google.app2\" codePath=\"/system/app/app2.apk\" nativeLibraryPath=\"/data/data/com.google.app2/lib\" flags=\"1\" ft=\"1360e578718\" it=\"135f2f80d08\" ut=\"1360e578718\" version=\"15\" enabled=\"3\" userId=\"11001\">"
    +-                + "<sigs count=\"1\">"
    +-                + "<cert index=\"0\" />"
    +-                + "</sigs>"
    +-                + "<proper-signing-keyset identifier=\"1\" />"
    +-                + "<defined-keyset alias=\"AB\" identifier=\"4\" />"
    +-                + "</package>"
    +-                + "<package name=\"com.android.app3\" codePath=\"/system/app/app3.apk\" nativeLibraryPath=\"/data/data/com.android.app3/lib\" flags=\"1\" ft=\"1360e577b60\" it=\"135f2f80d08\" ut=\"1360e577b60\" version=\"15\" userId=\"11030\">"
    +-                + "<sigs count=\"1\">"
    +-                + "<cert index=\"1\" key=\"" + KeySetStrings.ctsKeySetCertB + "\" />"
    +-                + "</sigs>"
    +-                + "<proper-signing-keyset identifier=\"2\" />"
    +-                + "<upgrade-keyset identifier=\"3\" />"
    +-                + "<defined-keyset alias=\"C\" identifier=\"3\" />"
    +-                + "</package>"
    +-                + "<shared-user name=\"com.android.shared1\" userId=\"11000\">"
    +-                + "<sigs count=\"1\">"
    +-                + "<cert index=\"1\" />"
    +-                + "</sigs>"
    +-                + "<perms>"
    +-                + "<item name=\"android.permission.REBOOT\" />"
    +-                + "</perms>"
    +-                + "</shared-user>"
    +-                + "<keyset-settings version=\"1\">"
    +-                + "<keys>"
    +-                + "<public-key identifier=\"1\" value=\"" + KeySetStrings.ctsKeySetPublicKeyA + "\" />"
    +-                + "<public-key identifier=\"2\" value=\"" + KeySetStrings.ctsKeySetPublicKeyB + "\" />"
    +-                + "<public-key identifier=\"3\" value=\"" + KeySetStrings.ctsKeySetPublicKeyC + "\" />"
    +-                + "</keys>"
    +-                + "<keysets>"
    +-                + "<keyset identifier=\"1\">"
    +-                + "<key-id identifier=\"1\" />"
    +-                + "</keyset>"
    +-                + "<keyset identifier=\"2\">"
    +-                + "<key-id identifier=\"2\" />"
    +-                + "</keyset>"
    +-                + "<keyset identifier=\"3\">"
    +-                + "<key-id identifier=\"3\" />"
    +-                + "</keyset>"
    +-                + "<keyset identifier=\"4\">"
    +-                + "<key-id identifier=\"1\" />"
    +-                + "<key-id identifier=\"2\" />"
    +-                + "</keyset>"
    +-                + "</keysets>"
    +-                + "<lastIssuedKeyId value=\"3\" />"
    +-                + "<lastIssuedKeySetId value=\"4\" />"
    +-                + "</keyset-settings>"
    +-                + "</packages>").getBytes());
    +-    }
    +-
    +-    private void writeStoppedPackagesXml() {
    +-        writeFile(new File(getContext().getFilesDir(), "system/packages-stopped.xml"),
    +-                ( "<?xml version='1.0' encoding='utf-8' standalone='yes' ?>"
    +-                + "<stopped-packages>"
    +-                + "<pkg name=\"com.google.app1\" nl=\"1\" />"
    +-                + "<pkg name=\"com.android.app3\" nl=\"1\" />"
    +-                + "</stopped-packages>")
    +-                .getBytes());
    +-    }
    +-
    +-    private void writePackagesList() {
    +-        writeFile(new File(getContext().getFilesDir(), "system/packages.list"),
    +-                ( "com.google.app1 11000 0 /data/data/com.google.app1 seinfo1"
    +-                + "com.google.app2 11001 0 /data/data/com.google.app2 seinfo2"
    +-                + "com.android.app3 11030 0 /data/data/com.android.app3 seinfo3")
    +-                .getBytes());
    +-    }
    +-
    +-    private void deleteSystemFolder() {
    +-        File systemFolder = new File(getContext().getFilesDir(), "system");
    +-        deleteFolder(systemFolder);
    +-    }
    +-
    +-    private static void deleteFolder(File folder) {
    +-        File[] files = folder.listFiles();
    +-        if (files != null) {
    +-            for (File file : files) {
    +-                deleteFolder(file);
    +-            }
    +-        }
    +-        folder.delete();
    +-    }
    +-
    +-    private void writeOldFiles() {
    +-        deleteSystemFolder();
    +-        writePackagesXml();
    +-        writeStoppedPackagesXml();
    +-        writePackagesList();
    +-    }
    +-
    +-    private void createUserManagerServiceRef() throws ReflectiveOperationException {
    +-        Constructor<UserManagerService> umsc =
    +-                UserManagerService.class.getDeclaredConstructor(
    +-                        Context.class,
    +-                        PackageManagerService.class,
    +-                        Object.class,
    +-                        Object.class,
    +-                        File.class,
    +-                        File.class);
    +-        umsc.setAccessible(true);
    +-        UserManagerService ums = umsc.newInstance(getContext(), null,
    +-                new Object(), new Object(), getContext().getFilesDir(),
    +-                new File(getContext().getFilesDir(), "user"));
    +-    }
    +-
    +-    private void verifyKeySetMetaData(Settings settings)
    +-            throws ReflectiveOperationException, IllegalAccessException {
    +-        ArrayMap<String, PackageSetting> packages = settings.mPackages;
    +-        KeySetManagerService ksms = settings.mKeySetManagerService;
    +-
    +-        /* verify keyset and public key ref counts */
    +-        assertEquals(2, KeySetUtils.getKeySetRefCount(ksms, 1));
    +-        assertEquals(1, KeySetUtils.getKeySetRefCount(ksms, 2));
    +-        assertEquals(1, KeySetUtils.getKeySetRefCount(ksms, 3));
    +-        assertEquals(1, KeySetUtils.getKeySetRefCount(ksms, 4));
    +-        assertEquals(2, KeySetUtils.getPubKeyRefCount(ksms, 1));
    +-        assertEquals(2, KeySetUtils.getPubKeyRefCount(ksms, 2));
    +-        assertEquals(1, KeySetUtils.getPubKeyRefCount(ksms, 3));
    +-
    +-        /* verify public keys properly read */
    +-        PublicKey keyA = PackageParser.parsePublicKey(KeySetStrings.ctsKeySetPublicKeyA);
    +-        PublicKey keyB = PackageParser.parsePublicKey(KeySetStrings.ctsKeySetPublicKeyB);
    +-        PublicKey keyC = PackageParser.parsePublicKey(KeySetStrings.ctsKeySetPublicKeyC);
    +-        assertEquals(keyA, KeySetUtils.getPubKey(ksms, 1));
    +-        assertEquals(keyB, KeySetUtils.getPubKey(ksms, 2));
    +-        assertEquals(keyC, KeySetUtils.getPubKey(ksms, 3));
    +-
    +-        /* verify mapping is correct (ks -> pub keys) */
    +-        LongSparseArray<ArraySet<Long>> ksMapping = KeySetUtils.getKeySetMapping(ksms);
    +-        ArraySet<Long> mapping = ksMapping.get(1);
    +-        assertEquals(1, mapping.size());
    +-        assertTrue(mapping.contains(new Long(1)));
    +-        mapping = ksMapping.get(2);
    +-        assertEquals(1, mapping.size());
    +-        assertTrue(mapping.contains(new Long(2)));
    +-        mapping = ksMapping.get(3);
    +-        assertEquals(1, mapping.size());
    +-        assertTrue(mapping.contains(new Long(3)));
    +-        mapping = ksMapping.get(4);
    +-        assertEquals(2, mapping.size());
    +-        assertTrue(mapping.contains(new Long(1)));
    +-        assertTrue(mapping.contains(new Long(2)));
    +-
    +-        /* verify lastIssuedIds are consistent */
    +-        assertEquals(new Long(3), KeySetUtils.getLastIssuedKeyId(ksms));
    +-        assertEquals(new Long(4), KeySetUtils.getLastIssuedKeySetId(ksms));
    +-
    +-        /* verify packages have been given the appropriat information */
    +-        PackageSetting ps = packages.get("com.google.app1");
    +-        assertEquals(1, ps.keySetData.getProperSigningKeySet());
    +-        ps = packages.get("com.google.app2");
    +-        assertEquals(1, ps.keySetData.getProperSigningKeySet());
    +-        assertEquals(new Long(4), ps.keySetData.getAliases().get("AB"));
    +-        ps = packages.get("com.android.app3");
    +-        assertEquals(2, ps.keySetData.getProperSigningKeySet());
    +-        assertEquals(new Long(3), ps.keySetData.getAliases().get("C"));
    +-        assertEquals(1, ps.keySetData.getUpgradeKeySets().length);
    +-        assertEquals(3, ps.keySetData.getUpgradeKeySets()[0]);
    +-    }
    +-
    +-    /* make sure our initialized keysetmanagerservice metadata matches packages.xml */
    +-    public void testReadKeySetSettings()
    +-            throws ReflectiveOperationException, IllegalAccessException {
    +-
    +-        /* write out files and read */
    +-        writeOldFiles();
    +-        createUserManagerServiceRef();
    +-        Settings settings = new Settings(getContext().getFilesDir(), new Object());
    +-        assertEquals(true, settings.readLPw(createFakeUsers()));
    +-        verifyKeySetMetaData(settings);
    +-    }
    +-
    +-    /* read in data, write it out, and read it back in.  Verify same. */
    +-    public void testWriteKeySetSettings()
    +-            throws ReflectiveOperationException, IllegalAccessException {
    +-
    +-        /* write out files and read */
    +-        writeOldFiles();
    +-        createUserManagerServiceRef();
    +-        Settings settings = new Settings(getContext().getFilesDir(), new Object());
    +-        assertEquals(true, settings.readLPw(createFakeUsers()));
    +-
    +-        /* write out, read back in and verify the same */
    +-        settings.writeLPr();
    +-        assertEquals(true, settings.readLPw(createFakeUsers()));
    +-        verifyKeySetMetaData(settings);
    +-    }
    +-
    +-    public void testSettingsReadOld() {
    +-        // Write the package files and make sure they're parsed properly the first time
    +-        writeOldFiles();
    +-        Settings settings = new Settings(getContext().getFilesDir(), new Object());
    +-        assertEquals(true, settings.readLPw(createFakeUsers()));
    +-        assertNotNull(settings.peekPackageLPr(PACKAGE_NAME_3));
    +-        assertNotNull(settings.peekPackageLPr(PACKAGE_NAME_1));
    +-
    +-        PackageSetting ps = settings.peekPackageLPr(PACKAGE_NAME_1);
    +-        assertEquals(COMPONENT_ENABLED_STATE_DEFAULT, ps.getEnabled(0));
    +-        assertEquals(true, ps.getNotLaunched(0));
    +-
    +-        ps = settings.peekPackageLPr(PACKAGE_NAME_2);
    +-        assertEquals(false, ps.getStopped(0));
    +-        assertEquals(COMPONENT_ENABLED_STATE_DISABLED_USER, ps.getEnabled(0));
    +-        assertEquals(COMPONENT_ENABLED_STATE_DEFAULT, ps.getEnabled(1));
    +-    }
    +-
    +-    public void testNewPackageRestrictionsFile() throws ReflectiveOperationException {
    +-
    +-        // Write the package files and make sure they're parsed properly the first time
    +-        writeOldFiles();
    +-        createUserManagerServiceRef();
    +-        Settings settings = new Settings(getContext().getFilesDir(), new Object());
    +-        assertEquals(true, settings.readLPw(createFakeUsers()));
    +-        settings.writeLPr();
    +-
    +-        // Create Settings again to make it read from the new files
    +-        settings = new Settings(getContext().getFilesDir(), new Object());
    +-        assertEquals(true, settings.readLPw(createFakeUsers()));
    +-
    +-        PackageSetting ps = settings.peekPackageLPr(PACKAGE_NAME_2);
    +-        assertEquals(COMPONENT_ENABLED_STATE_DISABLED_USER, ps.getEnabled(0));
    +-        assertEquals(COMPONENT_ENABLED_STATE_DEFAULT, ps.getEnabled(1));
    +-    }
    +-
    +-    public void testEnableDisable() {
    +-        // Write the package files and make sure they're parsed properly the first time
    +-        writeOldFiles();
    +-        Settings settings = new Settings(getContext().getFilesDir(), new Object());
    +-        assertEquals(true, settings.readLPw(createFakeUsers()));
    +-
    +-        // Enable/Disable a package
    +-        PackageSetting ps = settings.peekPackageLPr(PACKAGE_NAME_1);
    +-        ps.setEnabled(COMPONENT_ENABLED_STATE_DISABLED, 0, null);
    +-        ps.setEnabled(COMPONENT_ENABLED_STATE_ENABLED, 1, null);
    +-        assertEquals(COMPONENT_ENABLED_STATE_DISABLED, ps.getEnabled(0));
    +-        assertEquals(COMPONENT_ENABLED_STATE_ENABLED, ps.getEnabled(1));
    +-
    +-        // Enable/Disable a component
    +-        ArraySet<String> components = new ArraySet<String>();
    +-        String component1 = PACKAGE_NAME_1 + "/.Component1";
    +-        components.add(component1);
    +-        ps.setDisabledComponents(components, 0);
    +-        ArraySet<String> componentsDisabled = ps.getDisabledComponents(0);
    +-        assertEquals(1, componentsDisabled.size());
    +-        assertEquals(component1, componentsDisabled.toArray()[0]);
    +-        boolean hasEnabled =
    +-                ps.getEnabledComponents(0) != null && ps.getEnabledComponents(1).size() > 0;
    +-        assertEquals(false, hasEnabled);
    +-
    +-        // User 1 should not have any disabled components
    +-        boolean hasDisabled =
    +-                ps.getDisabledComponents(1) != null && ps.getDisabledComponents(1).size() > 0;
    +-        assertEquals(false, hasDisabled);
    +-        ps.setEnabledComponents(components, 1);
    +-        assertEquals(1, ps.getEnabledComponents(1).size());
    +-        hasEnabled = ps.getEnabledComponents(0) != null && ps.getEnabledComponents(0).size() > 0;
    +-        assertEquals(false, hasEnabled);
    +-    }
    +-}
    +diff --git a/services/tests/servicestests/src/com/android/server/pm/PackageVerificationStateTest.java b/services/tests/servicestests/src/com/android/server/pm/PackageVerificationStateTest.java
    +deleted file mode 100644
    +index ebd3633..0000000
    +--- a/services/tests/servicestests/src/com/android/server/pm/PackageVerificationStateTest.java
    ++++ /dev/null
    +@@ -1,205 +0,0 @@
    +-/*
    +- * Copyright (C) 2011 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 com.android.server.pm;
    +-
    +-import android.content.pm.PackageManager;
    +-import com.android.server.pm.PackageVerificationState;
    +-
    +-import android.test.AndroidTestCase;
    +-
    +-public class PackageVerificationStateTest extends AndroidTestCase {
    +-    private static final int REQUIRED_UID = 1948;
    +-
    +-    private static final int SUFFICIENT_UID_1 = 1005;
    +-
    +-    private static final int SUFFICIENT_UID_2 = 8938;
    +-
    +-    public void testPackageVerificationState_OnlyRequiredVerifier_AllowedInstall() {
    +-        PackageVerificationState state = new PackageVerificationState(REQUIRED_UID, null);
    +-
    +-        assertFalse("Verification should not be marked as complete yet",
    +-                state.isVerificationComplete());
    +-
    +-        state.setVerifierResponse(REQUIRED_UID, PackageManager.VERIFICATION_ALLOW);
    +-
    +-        assertTrue("Verification should be considered complete now",
    +-                state.isVerificationComplete());
    +-
    +-        assertTrue("Installation should be marked as allowed",
    +-                state.isInstallAllowed());
    +-    }
    +-
    +-    public void testPackageVerificationState_OnlyRequiredVerifier_DeniedInstall() {
    +-        PackageVerificationState state = new PackageVerificationState(REQUIRED_UID, null);
    +-
    +-        assertFalse("Verification should not be marked as complete yet",
    +-                state.isVerificationComplete());
    +-
    +-        state.setVerifierResponse(REQUIRED_UID, PackageManager.VERIFICATION_REJECT);
    +-
    +-        assertTrue("Verification should be considered complete now",
    +-                state.isVerificationComplete());
    +-
    +-        assertFalse("Installation should be marked as allowed",
    +-                state.isInstallAllowed());
    +-    }
    +-
    +-    public void testPackageVerificationState_RequiredAndOneSufficient_RequiredDeniedInstall() {
    +-        PackageVerificationState state = new PackageVerificationState(REQUIRED_UID, null);
    +-
    +-        assertFalse("Verification should not be marked as complete yet",
    +-                state.isVerificationComplete());
    +-
    +-        state.addSufficientVerifier(SUFFICIENT_UID_1);
    +-
    +-        assertFalse("Verification should not be marked as complete yet",
    +-                state.isVerificationComplete());
    +-
    +-        state.setVerifierResponse(SUFFICIENT_UID_1, PackageManager.VERIFICATION_ALLOW);
    +-
    +-        assertFalse("Verification should not be marked as complete yet",
    +-                state.isVerificationComplete());
    +-
    +-        state.setVerifierResponse(REQUIRED_UID, PackageManager.VERIFICATION_REJECT);
    +-
    +-        assertTrue("Verification should be considered complete now",
    +-                state.isVerificationComplete());
    +-
    +-        assertFalse("Installation should be marked as allowed",
    +-                state.isInstallAllowed());
    +-    }
    +-
    +-    public void testPackageVerificationState_RequiredAndOneSufficient_SufficientDeniedInstall() {
    +-        PackageVerificationState state = new PackageVerificationState(REQUIRED_UID, null);
    +-
    +-        assertFalse("Verification should not be marked as complete yet",
    +-                state.isVerificationComplete());
    +-
    +-        state.addSufficientVerifier(SUFFICIENT_UID_1);
    +-
    +-        assertFalse("Verification should not be marked as complete yet",
    +-                state.isVerificationComplete());
    +-
    +-        state.setVerifierResponse(SUFFICIENT_UID_1, PackageManager.VERIFICATION_REJECT);
    +-
    +-        assertFalse("Verification should not be marked as complete yet",
    +-                state.isVerificationComplete());
    +-
    +-        state.setVerifierResponse(REQUIRED_UID, PackageManager.VERIFICATION_ALLOW);
    +-
    +-        assertTrue("Verification should be considered complete now",
    +-                state.isVerificationComplete());
    +-
    +-        assertFalse("Installation should be marked as allowed",
    +-                state.isInstallAllowed());
    +-    }
    +-
    +-    public void testPackageVerificationState_RequiredAndTwoSufficient_OneSufficientIsEnough() {
    +-        PackageVerificationState state = new PackageVerificationState(REQUIRED_UID, null);
    +-
    +-        assertFalse("Verification should not be marked as complete yet",
    +-                state.isVerificationComplete());
    +-
    +-        state.addSufficientVerifier(SUFFICIENT_UID_1);
    +-        state.addSufficientVerifier(SUFFICIENT_UID_2);
    +-
    +-        assertFalse("Verification should not be marked as complete yet",
    +-                state.isVerificationComplete());
    +-
    +-        state.setVerifierResponse(SUFFICIENT_UID_1, PackageManager.VERIFICATION_ALLOW);
    +-
    +-        assertFalse("Verification should not be marked as complete yet",
    +-                state.isVerificationComplete());
    +-
    +-        state.setVerifierResponse(REQUIRED_UID, PackageManager.VERIFICATION_ALLOW);
    +-
    +-        assertTrue("Verification should be considered complete now",
    +-                state.isVerificationComplete());
    +-
    +-        assertTrue("Installation should be marked as allowed",
    +-                state.isInstallAllowed());
    +-    }
    +-
    +-    public void testPackageVerificationState_RequiredAndTwoSufficient_SecondSufficientIsEnough() {
    +-        PackageVerificationState state = new PackageVerificationState(REQUIRED_UID, null);
    +-
    +-        assertFalse("Verification should not be marked as complete yet",
    +-                state.isVerificationComplete());
    +-
    +-        state.addSufficientVerifier(SUFFICIENT_UID_1);
    +-        state.addSufficientVerifier(SUFFICIENT_UID_2);
    +-
    +-        assertFalse("Verification should not be marked as complete yet",
    +-                state.isVerificationComplete());
    +-
    +-        state.setVerifierResponse(REQUIRED_UID, PackageManager.VERIFICATION_ALLOW);
    +-
    +-        assertFalse("Verification should not be marked as complete yet",
    +-                state.isVerificationComplete());
    +-
    +-        state.setVerifierResponse(SUFFICIENT_UID_1, PackageManager.VERIFICATION_REJECT);
    +-
    +-        assertFalse("Verification should not be marked as complete yet",
    +-                state.isVerificationComplete());
    +-
    +-        state.setVerifierResponse(SUFFICIENT_UID_2, PackageManager.VERIFICATION_ALLOW);
    +-
    +-        assertTrue("Verification should be considered complete now",
    +-                state.isVerificationComplete());
    +-
    +-        assertTrue("Installation should be marked as allowed",
    +-                state.isInstallAllowed());
    +-    }
    +-
    +-    public void testPackageVerificationState_RequiredAndTwoSufficient_RequiredOverrides() {
    +-        PackageVerificationState state = new PackageVerificationState(REQUIRED_UID, null);
    +-
    +-        assertFalse("Verification should not be marked as complete yet",
    +-                state.isVerificationComplete());
    +-
    +-        state.addSufficientVerifier(SUFFICIENT_UID_1);
    +-        state.addSufficientVerifier(SUFFICIENT_UID_2);
    +-
    +-        assertFalse("Verification should not be marked as complete yet",
    +-                state.isVerificationComplete());
    +-
    +-        state.setVerifierResponse(REQUIRED_UID,
    +-                PackageManager.VERIFICATION_ALLOW_WITHOUT_SUFFICIENT);
    +-
    +-        assertTrue("Verification should be marked as complete immediately",
    +-                state.isVerificationComplete());
    +-
    +-        assertTrue("Installation should be marked as allowed",
    +-                state.isInstallAllowed());
    +-
    +-        state.setVerifierResponse(SUFFICIENT_UID_1, PackageManager.VERIFICATION_REJECT);
    +-
    +-        assertTrue("Verification should still be marked as completed",
    +-                state.isVerificationComplete());
    +-
    +-        assertTrue("Installation should be marked as allowed still",
    +-                state.isInstallAllowed());
    +-
    +-        state.setVerifierResponse(SUFFICIENT_UID_2, PackageManager.VERIFICATION_ALLOW);
    +-
    +-        assertTrue("Verification should still be complete",
    +-                state.isVerificationComplete());
    +-
    +-        assertTrue("Installation should be marked as allowed still",
    +-                state.isInstallAllowed());
    +-    }
    +-}
    +diff --git a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest1.java b/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest1.java
    +deleted file mode 100644
    +index 253334e..0000000
    +--- a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest1.java
    ++++ /dev/null
    +@@ -1,7159 +0,0 @@
    +-/*
    +- * Copyright (C) 2016 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 com.android.server.pm;
    +-
    +-import static com.android.server.pm.shortcutmanagertest.ShortcutManagerTestUtils.assertAllDisabled;
    +-import static com.android.server.pm.shortcutmanagertest.ShortcutManagerTestUtils.assertAllDynamic;
    +-import static com.android.server.pm.shortcutmanagertest.ShortcutManagerTestUtils.assertAllDynamicOrPinned;
    +-import static com.android.server.pm.shortcutmanagertest.ShortcutManagerTestUtils.assertAllEnabled;
    +-import static com.android.server.pm.shortcutmanagertest.ShortcutManagerTestUtils.assertAllHaveIntents;
    +-import static com.android.server.pm.shortcutmanagertest.ShortcutManagerTestUtils.assertAllHaveTitle;
    +-import static com.android.server.pm.shortcutmanagertest.ShortcutManagerTestUtils.assertAllImmutable;
    +-import static com.android.server.pm.shortcutmanagertest.ShortcutManagerTestUtils.assertAllKeyFieldsOnly;
    +-import static com.android.server.pm.shortcutmanagertest.ShortcutManagerTestUtils.assertAllManifest;
    +-import static com.android.server.pm.shortcutmanagertest.ShortcutManagerTestUtils.assertAllNotHaveIntents;
    +-import static com.android.server.pm.shortcutmanagertest.ShortcutManagerTestUtils.assertAllNotHaveTitle;
    +-import static com.android.server.pm.shortcutmanagertest.ShortcutManagerTestUtils.assertAllNotKeyFieldsOnly;
    +-import static com.android.server.pm.shortcutmanagertest.ShortcutManagerTestUtils.assertAllNotManifest;
    +-import static com.android.server.pm.shortcutmanagertest.ShortcutManagerTestUtils.assertAllPinned;
    +-import static com.android.server.pm.shortcutmanagertest.ShortcutManagerTestUtils.assertAllUnique;
    +-import static com.android.server.pm.shortcutmanagertest.ShortcutManagerTestUtils.assertBitmapSize;
    +-import static com.android.server.pm.shortcutmanagertest.ShortcutManagerTestUtils.assertBundleEmpty;
    +-import static com.android.server.pm.shortcutmanagertest.ShortcutManagerTestUtils.assertCallbackNotReceived;
    +-import static com.android.server.pm.shortcutmanagertest.ShortcutManagerTestUtils.assertCallbackReceived;
    +-import static com.android.server.pm.shortcutmanagertest.ShortcutManagerTestUtils.assertCannotUpdateImmutable;
    +-import static com.android.server.pm.shortcutmanagertest.ShortcutManagerTestUtils.assertDynamicAndPinned;
    +-import static com.android.server.pm.shortcutmanagertest.ShortcutManagerTestUtils.assertDynamicOnly;
    +-import static com.android.server.pm.shortcutmanagertest.ShortcutManagerTestUtils.assertDynamicShortcutCountExceeded;
    +-import static com.android.server.pm.shortcutmanagertest.ShortcutManagerTestUtils.assertEmpty;
    +-import static com.android.server.pm.shortcutmanagertest.ShortcutManagerTestUtils.assertExpectException;
    +-import static com.android.server.pm.shortcutmanagertest.ShortcutManagerTestUtils.assertForLauncherCallback;
    +-import static com.android.server.pm.shortcutmanagertest.ShortcutManagerTestUtils.assertShortcutIds;
    +-import static com.android.server.pm.shortcutmanagertest.ShortcutManagerTestUtils.assertWith;
    +-import static com.android.server.pm.shortcutmanagertest.ShortcutManagerTestUtils.filterByActivity;
    +-import static com.android.server.pm.shortcutmanagertest.ShortcutManagerTestUtils.findShortcut;
    +-import static com.android.server.pm.shortcutmanagertest.ShortcutManagerTestUtils.hashSet;
    +-import static com.android.server.pm.shortcutmanagertest.ShortcutManagerTestUtils.list;
    +-import static com.android.server.pm.shortcutmanagertest.ShortcutManagerTestUtils.makeBundle;
    +-import static com.android.server.pm.shortcutmanagertest.ShortcutManagerTestUtils.pfdToBitmap;
    +-import static com.android.server.pm.shortcutmanagertest.ShortcutManagerTestUtils.resetAll;
    +-import static com.android.server.pm.shortcutmanagertest.ShortcutManagerTestUtils.set;
    +-import static com.android.server.pm.shortcutmanagertest.ShortcutManagerTestUtils.waitOnMainThread;
    +-
    +-import static org.mockito.Matchers.any;
    +-import static org.mockito.Matchers.anyInt;
    +-import static org.mockito.Matchers.anyString;
    +-import static org.mockito.Matchers.eq;
    +-import static org.mockito.Mockito.doReturn;
    +-import static org.mockito.Mockito.mock;
    +-import static org.mockito.Mockito.reset;
    +-import static org.mockito.Mockito.times;
    +-import static org.mockito.Mockito.verify;
    +-
    +-import android.Manifest.permission;
    +-import android.app.ActivityManager;
    +-import android.content.ActivityNotFoundException;
    +-import android.content.ComponentName;
    +-import android.content.Intent;
    +-import android.content.pm.ApplicationInfo;
    +-import android.content.pm.LauncherApps;
    +-import android.content.pm.LauncherApps.ShortcutQuery;
    +-import android.content.pm.ShortcutInfo;
    +-import android.graphics.Bitmap;
    +-import android.graphics.Bitmap.CompressFormat;
    +-import android.graphics.BitmapFactory;
    +-import android.graphics.drawable.Icon;
    +-import android.net.Uri;
    +-import android.os.Bundle;
    +-import android.os.Handler;
    +-import android.os.Looper;
    +-import android.os.Process;
    +-import android.os.UserHandle;
    +-import android.test.suitebuilder.annotation.SmallTest;
    +-import android.util.Log;
    +-import android.util.SparseArray;
    +-
    +-import com.android.frameworks.servicestests.R;
    +-import com.android.server.pm.ShortcutService.ConfigConstants;
    +-import com.android.server.pm.ShortcutService.FileOutputStreamWithPath;
    +-import com.android.server.pm.ShortcutUser.PackageWithUser;
    +-
    +-import org.mockito.ArgumentCaptor;
    +-
    +-import java.io.File;
    +-import java.io.IOException;
    +-import java.util.List;
    +-import java.util.Locale;
    +-
    +-/**
    +- * Tests for ShortcutService and ShortcutManager.
    +- *
    +- m FrameworksServicesTests &&
    +- adb install \
    +- -r -g ${ANDROID_PRODUCT_OUT}/data/app/FrameworksServicesTests/FrameworksServicesTests.apk &&
    +- adb shell am instrument -e class com.android.server.pm.ShortcutManagerTest1 \
    +- -w com.android.frameworks.servicestests/android.support.test.runner.AndroidJUnitRunner
    +- */
    +-@SmallTest
    +-public class ShortcutManagerTest1 extends BaseShortcutManagerTest {
    +-
    +-    /**
    +-     * Test for the first launch path, no settings file available.
    +-     */
    +-    public void testFirstInitialize() {
    +-        assertResetTimes(START_TIME, START_TIME + INTERVAL);
    +-    }
    +-
    +-    /**
    +-     * Test for {@link ShortcutService#getLastResetTimeLocked()} and
    +-     * {@link ShortcutService#getNextResetTimeLocked()}.
    +-     */
    +-    public void testUpdateAndGetNextResetTimeLocked() {
    +-        assertResetTimes(START_TIME, START_TIME + INTERVAL);
    +-
    +-        // Advance clock.
    +-        mInjectedCurrentTimeMillis += 100;
    +-
    +-        // Shouldn't have changed.
    +-        assertResetTimes(START_TIME, START_TIME + INTERVAL);
    +-
    +-        // Advance clock, almost the reset time.
    +-        mInjectedCurrentTimeMillis = START_TIME + INTERVAL - 1;
    +-
    +-        // Shouldn't have changed.
    +-        assertResetTimes(START_TIME, START_TIME + INTERVAL);
    +-
    +-        // Advance clock.
    +-        mInjectedCurrentTimeMillis += 1;
    +-
    +-        assertResetTimes(START_TIME + INTERVAL, START_TIME + 2 * INTERVAL);
    +-
    +-        // Advance further; 4 hours since start.
    +-        mInjectedCurrentTimeMillis = START_TIME + 4 * INTERVAL + 50;
    +-
    +-        assertResetTimes(START_TIME + 4 * INTERVAL, START_TIME + 5 * INTERVAL);
    +-    }
    +-
    +-    /**
    +-     * Test for the restoration from saved file.
    +-     */
    +-    public void testInitializeFromSavedFile() {
    +-
    +-        mInjectedCurrentTimeMillis = START_TIME + 4 * INTERVAL + 50;
    +-        assertResetTimes(START_TIME + 4 * INTERVAL, START_TIME + 5 * INTERVAL);
    +-
    +-        mService.saveBaseStateLocked();
    +-
    +-        dumpBaseStateFile();
    +-
    +-        mService.saveDirtyInfo();
    +-
    +-        // Restore.
    +-        initService();
    +-
    +-        assertResetTimes(START_TIME + 4 * INTERVAL, START_TIME + 5 * INTERVAL);
    +-    }
    +-
    +-    /**
    +-     * Test for the restoration from restored file.
    +-     */
    +-    public void testLoadFromBrokenFile() {
    +-        // TODO Add various broken cases.
    +-    }
    +-
    +-    public void testLoadConfig() {
    +-        mService.updateConfigurationLocked(
    +-                ConfigConstants.KEY_RESET_INTERVAL_SEC + "=123,"
    +-                        + ConfigConstants.KEY_MAX_SHORTCUTS + "=4,"
    +-                        + ConfigConstants.KEY_MAX_UPDATES_PER_INTERVAL + "=5,"
    +-                        + ConfigConstants.KEY_MAX_ICON_DIMENSION_DP + "=100,"
    +-                        + ConfigConstants.KEY_MAX_ICON_DIMENSION_DP_LOWRAM + "=50,"
    +-                        + ConfigConstants.KEY_ICON_FORMAT + "=WEBP,"
    +-                        + ConfigConstants.KEY_ICON_QUALITY + "=75");
    +-        assertEquals(123000, mService.getResetIntervalForTest());
    +-        assertEquals(4, mService.getMaxShortcutsForTest());
    +-        assertEquals(5, mService.getMaxUpdatesPerIntervalForTest());
    +-        assertEquals(100, mService.getMaxIconDimensionForTest());
    +-        assertEquals(CompressFormat.WEBP, mService.getIconPersistFormatForTest());
    +-        assertEquals(75, mService.getIconPersistQualityForTest());
    +-
    +-        mInjectedIsLowRamDevice = true;
    +-        mService.updateConfigurationLocked(
    +-                ConfigConstants.KEY_MAX_ICON_DIMENSION_DP + "=100,"
    +-                        + ConfigConstants.KEY_MAX_ICON_DIMENSION_DP_LOWRAM + "=50,"
    +-                        + ConfigConstants.KEY_ICON_FORMAT + "=JPEG");
    +-        assertEquals(ShortcutService.DEFAULT_RESET_INTERVAL_SEC * 1000,
    +-                mService.getResetIntervalForTest());
    +-
    +-        assertEquals(ShortcutService.DEFAULT_MAX_SHORTCUTS_PER_APP,
    +-                mService.getMaxShortcutsForTest());
    +-
    +-        assertEquals(ShortcutService.DEFAULT_MAX_UPDATES_PER_INTERVAL,
    +-                mService.getMaxUpdatesPerIntervalForTest());
    +-
    +-        assertEquals(50, mService.getMaxIconDimensionForTest());
    +-
    +-        assertEquals(CompressFormat.JPEG, mService.getIconPersistFormatForTest());
    +-
    +-        assertEquals(ShortcutService.DEFAULT_ICON_PERSIST_QUALITY,
    +-                mService.getIconPersistQualityForTest());
    +-    }
    +-
    +-    // === Test for app side APIs ===
    +-
    +-    /** Test for {@link android.content.pm.ShortcutManager#getMaxShortcutCountForActivity()} */
    +-    public void testGetMaxDynamicShortcutCount() {
    +-        assertEquals(MAX_SHORTCUTS, mManager.getMaxShortcutCountForActivity());
    +-    }
    +-
    +-    /** Test for {@link android.content.pm.ShortcutManager#getRemainingCallCount()} */
    +-    public void testGetRemainingCallCount() {
    +-        assertEquals(MAX_UPDATES_PER_INTERVAL, mManager.getRemainingCallCount());
    +-    }
    +-
    +-    public void testGetIconMaxDimensions() {
    +-        assertEquals(MAX_ICON_DIMENSION, mManager.getIconMaxWidth());
    +-        assertEquals(MAX_ICON_DIMENSION, mManager.getIconMaxHeight());
    +-    }
    +-
    +-    /** Test for {@link android.content.pm.ShortcutManager#getRateLimitResetTime()} */
    +-    public void testGetRateLimitResetTime() {
    +-        assertEquals(START_TIME + INTERVAL, mManager.getRateLimitResetTime());
    +-
    +-        mInjectedCurrentTimeMillis = START_TIME + 4 * INTERVAL + 50;
    +-
    +-        assertEquals(START_TIME + 5 * INTERVAL, mManager.getRateLimitResetTime());
    +-    }
    +-
    +-    public void testSetDynamicShortcuts() {
    +-        setCaller(CALLING_PACKAGE_1, USER_0);
    +-
    +-        final Icon icon1 = Icon.createWithResource(getTestContext(), R.drawable.icon1);
    +-        final Icon icon2 = Icon.createWithBitmap(BitmapFactory.decodeResource(
    +-                getTestContext().getResources(), R.drawable.icon2));
    +-
    +-        final ShortcutInfo si1 = makeShortcut(
    +-                "shortcut1",
    +-                "Title 1",
    +-                makeComponent(ShortcutActivity.class),
    +-                icon1,
    +-                makeIntent(Intent.ACTION_ASSIST, ShortcutActivity2.class,
    +-                        "key1", "val1", "nest", makeBundle("key", 123)),
    +-                /* weight */ 10);
    +-
    +-        final ShortcutInfo si2 = makeShortcut(
    +-                "shortcut2",
    +-                "Title 2",
    +-                /* activity */ null,
    +-                icon2,
    +-                makeIntent(Intent.ACTION_ASSIST, ShortcutActivity3.class),
    +-                /* weight */ 12);
    +-        final ShortcutInfo si3 = makeShortcut("shortcut3");
    +-
    +-        assertTrue(mManager.setDynamicShortcuts(list(si1, si2)));
    +-        assertShortcutIds(assertAllNotKeyFieldsOnly(
    +-                mManager.getDynamicShortcuts()),
    +-                "shortcut1", "shortcut2");
    +-        assertEquals(2, mManager.getRemainingCallCount());
    +-
    +-        // TODO: Check fields
    +-
    +-        assertTrue(mManager.setDynamicShortcuts(list(si1)));
    +-        assertShortcutIds(assertAllNotKeyFieldsOnly(
    +-                mManager.getDynamicShortcuts()),
    +-                "shortcut1");
    +-        assertEquals(1, mManager.getRemainingCallCount());
    +-
    +-        assertTrue(mManager.setDynamicShortcuts(list()));
    +-        assertEquals(0, mManager.getDynamicShortcuts().size());
    +-        assertEquals(0, mManager.getRemainingCallCount());
    +-
    +-        dumpsysOnLogcat();
    +-
    +-        mInjectedCurrentTimeMillis++; // Need to advance the clock for reset to work.
    +-        mService.resetThrottlingInner(UserHandle.USER_SYSTEM);
    +-
    +-        dumpsysOnLogcat();
    +-
    +-        assertTrue(mManager.setDynamicShortcuts(list(si2, si3)));
    +-        assertEquals(2, mManager.getDynamicShortcuts().size());
    +-
    +-        // TODO Check max number
    +-
    +-        mRunningUsers.put(USER_10, true);
    +-
    +-        runWithCaller(CALLING_PACKAGE_2, USER_10, () -> {
    +-            assertTrue(mManager.setDynamicShortcuts(list(makeShortcut("s1"))));
    +-        });
    +-    }
    +-
    +-    public void testAddDynamicShortcuts() {
    +-        setCaller(CALLING_PACKAGE_1, USER_0);
    +-
    +-        final ShortcutInfo si1 = makeShortcut("shortcut1");
    +-        final ShortcutInfo si2 = makeShortcut("shortcut2");
    +-        final ShortcutInfo si3 = makeShortcut("shortcut3");
    +-
    +-        assertEquals(3, mManager.getRemainingCallCount());
    +-
    +-        assertTrue(mManager.setDynamicShortcuts(list(si1)));
    +-        assertEquals(2, mManager.getRemainingCallCount());
    +-        assertShortcutIds(assertAllNotKeyFieldsOnly(
    +-                mManager.getDynamicShortcuts()),
    +-                "shortcut1");
    +-
    +-        assertTrue(mManager.addDynamicShortcuts(list(si2, si3)));
    +-        assertEquals(1, mManager.getRemainingCallCount());
    +-        assertShortcutIds(assertAllNotKeyFieldsOnly(
    +-                mManager.getDynamicShortcuts()),
    +-                "shortcut1", "shortcut2", "shortcut3");
    +-
    +-        // This should not crash.  It'll still consume the quota.
    +-        assertTrue(mManager.addDynamicShortcuts(list()));
    +-        assertEquals(0, mManager.getRemainingCallCount());
    +-        assertShortcutIds(assertAllNotKeyFieldsOnly(
    +-                mManager.getDynamicShortcuts()),
    +-                "shortcut1", "shortcut2", "shortcut3");
    +-
    +-        mInjectedCurrentTimeMillis += INTERVAL; // reset
    +-
    +-        // Add with the same ID
    +-        assertTrue(mManager.addDynamicShortcuts(list(makeShortcut("shortcut1"))));
    +-        assertEquals(2, mManager.getRemainingCallCount());
    +-        assertShortcutIds(assertAllNotKeyFieldsOnly(
    +-                mManager.getDynamicShortcuts()),
    +-                "shortcut1", "shortcut2", "shortcut3");
    +-
    +-        // TODO Check max number
    +-
    +-        // TODO Check fields.
    +-
    +-        mRunningUsers.put(USER_10, true);
    +-
    +-        runWithCaller(CALLING_PACKAGE_2, USER_10, () -> {
    +-            assertTrue(mManager.addDynamicShortcuts(list(makeShortcut("s1"))));
    +-        });
    +-    }
    +-
    +-    public void testPublishWithNoActivity() {
    +-        // If activity is not explicitly set, use the default one.
    +-
    +-        mRunningUsers.put(USER_10, true);
    +-
    +-        runWithCaller(CALLING_PACKAGE_2, USER_10, () -> {
    +-            // s1 and s3 has no activities.
    +-            final ShortcutInfo si1 = new ShortcutInfo.Builder(mClientContext, "si1")
    +-                    .setShortLabel("label1")
    +-                    .setIntent(new Intent("action1"))
    +-                    .build();
    +-            final ShortcutInfo si2 = new ShortcutInfo.Builder(mClientContext, "si2")
    +-                    .setShortLabel("label2")
    +-                    .setActivity(new ComponentName(getCallingPackage(), "abc"))
    +-                    .setIntent(new Intent("action2"))
    +-                    .build();
    +-            final ShortcutInfo si3 = new ShortcutInfo.Builder(mClientContext, "si3")
    +-                    .setShortLabel("label3")
    +-                    .setIntent(new Intent("action3"))
    +-                    .build();
    +-
    +-            // Set test 1
    +-            assertTrue(mManager.setDynamicShortcuts(list(si1)));
    +-
    +-            assertWith(getCallerShortcuts())
    +-                    .haveIds("si1")
    +-                    .forShortcutWithId("si1", si -> {
    +-                        assertEquals(new ComponentName(getCallingPackage(),
    +-                                MAIN_ACTIVITY_CLASS), si.getActivity());
    +-                    });
    +-
    +-            // Set test 2
    +-            assertTrue(mManager.setDynamicShortcuts(list(si2, si1)));
    +-
    +-            assertWith(getCallerShortcuts())
    +-                    .haveIds("si1", "si2")
    +-                    .forShortcutWithId("si1", si -> {
    +-                        assertEquals(new ComponentName(getCallingPackage(),
    +-                                MAIN_ACTIVITY_CLASS), si.getActivity());
    +-                    })
    +-                    .forShortcutWithId("si2", si -> {
    +-                        assertEquals(new ComponentName(getCallingPackage(),
    +-                                "abc"), si.getActivity());
    +-                    });
    +-
    +-
    +-            // Set test 3
    +-            assertTrue(mManager.setDynamicShortcuts(list(si3, si1)));
    +-
    +-            assertWith(getCallerShortcuts())
    +-                    .haveIds("si1", "si3")
    +-                    .forShortcutWithId("si1", si -> {
    +-                        assertEquals(new ComponentName(getCallingPackage(),
    +-                                MAIN_ACTIVITY_CLASS), si.getActivity());
    +-                    })
    +-                    .forShortcutWithId("si3", si -> {
    +-                        assertEquals(new ComponentName(getCallingPackage(),
    +-                                MAIN_ACTIVITY_CLASS), si.getActivity());
    +-                    });
    +-
    +-            mInjectedCurrentTimeMillis += INTERVAL; // reset throttling
    +-
    +-            // Add test 1
    +-            mManager.removeAllDynamicShortcuts();
    +-            assertTrue(mManager.addDynamicShortcuts(list(si1)));
    +-
    +-            assertWith(getCallerShortcuts())
    +-                    .haveIds("si1")
    +-                    .forShortcutWithId("si1", si -> {
    +-                        assertEquals(new ComponentName(getCallingPackage(),
    +-                                MAIN_ACTIVITY_CLASS), si.getActivity());
    +-                    });
    +-
    +-            // Add test 2
    +-            mManager.removeAllDynamicShortcuts();
    +-            assertTrue(mManager.addDynamicShortcuts(list(si2, si1)));
    +-
    +-            assertWith(getCallerShortcuts())
    +-                    .haveIds("si1", "si2")
    +-                    .forShortcutWithId("si1", si -> {
    +-                        assertEquals(new ComponentName(getCallingPackage(),
    +-                                MAIN_ACTIVITY_CLASS), si.getActivity());
    +-                    })
    +-                    .forShortcutWithId("si2", si -> {
    +-                        assertEquals(new ComponentName(getCallingPackage(),
    +-                                "abc"), si.getActivity());
    +-                    });
    +-
    +-
    +-            // Add test 3
    +-            mManager.removeAllDynamicShortcuts();
    +-            assertTrue(mManager.addDynamicShortcuts(list(si3, si1)));
    +-
    +-            assertWith(getCallerShortcuts())
    +-                    .haveIds("si1", "si3")
    +-                    .forShortcutWithId("si1", si -> {
    +-                        assertEquals(new ComponentName(getCallingPackage(),
    +-                                MAIN_ACTIVITY_CLASS), si.getActivity());
    +-                    })
    +-                    .forShortcutWithId("si3", si -> {
    +-                        assertEquals(new ComponentName(getCallingPackage(),
    +-                                MAIN_ACTIVITY_CLASS), si.getActivity());
    +-                    });
    +-        });
    +-    }
    +-
    +-    public void testPublishWithNoActivity_noMainActivityInPackage() {
    +-        mRunningUsers.put(USER_10, true);
    +-
    +-        runWithCaller(CALLING_PACKAGE_2, USER_10, () -> {
    +-            final ShortcutInfo si1 = new ShortcutInfo.Builder(mClientContext, "si1")
    +-                    .setShortLabel("label1")
    +-                    .setIntent(new Intent("action1"))
    +-                    .build();
    +-
    +-            // Returning null means there's no main activity in this package.
    +-            mMainActivityFetcher = (packageName, userId) -> null;
    +-
    +-            assertExpectException(
    +-                    RuntimeException.class, "Launcher activity not found for", () -> {
    +-                        assertTrue(mManager.setDynamicShortcuts(list(si1)));
    +-                    });
    +-        });
    +-    }
    +-
    +-    public void testDeleteDynamicShortcuts() {
    +-        final ShortcutInfo si1 = makeShortcut("shortcut1");
    +-        final ShortcutInfo si2 = makeShortcut("shortcut2");
    +-        final ShortcutInfo si3 = makeShortcut("shortcut3");
    +-        final ShortcutInfo si4 = makeShortcut("shortcut4");
    +-
    +-        assertTrue(mManager.setDynamicShortcuts(list(si1, si2, si3, si4)));
    +-        assertShortcutIds(assertAllNotKeyFieldsOnly(
    +-                mManager.getDynamicShortcuts()),
    +-                "shortcut1", "shortcut2", "shortcut3", "shortcut4");
    +-
    +-        assertEquals(2, mManager.getRemainingCallCount());
    +-
    +-        mManager.removeDynamicShortcuts(list("shortcut1"));
    +-        assertShortcutIds(assertAllNotKeyFieldsOnly(
    +-                mManager.getDynamicShortcuts()),
    +-                "shortcut2", "shortcut3", "shortcut4");
    +-
    +-        mManager.removeDynamicShortcuts(list("shortcut1"));
    +-        assertShortcutIds(assertAllNotKeyFieldsOnly(
    +-                mManager.getDynamicShortcuts()),
    +-                "shortcut2", "shortcut3", "shortcut4");
    +-
    +-        mManager.removeDynamicShortcuts(list("shortcutXXX"));
    +-        assertShortcutIds(assertAllNotKeyFieldsOnly(
    +-                mManager.getDynamicShortcuts()),
    +-                "shortcut2", "shortcut3", "shortcut4");
    +-
    +-        mManager.removeDynamicShortcuts(list("shortcut2", "shortcut4"));
    +-        assertShortcutIds(assertAllNotKeyFieldsOnly(
    +-                mManager.getDynamicShortcuts()),
    +-                "shortcut3");
    +-
    +-        mManager.removeDynamicShortcuts(list("shortcut3"));
    +-        assertShortcutIds(assertAllNotKeyFieldsOnly(
    +-                mManager.getDynamicShortcuts()));
    +-
    +-        // Still 2 calls left.
    +-        assertEquals(2, mManager.getRemainingCallCount());
    +-    }
    +-
    +-    public void testDeleteAllDynamicShortcuts() {
    +-        final ShortcutInfo si1 = makeShortcut("shortcut1");
    +-        final ShortcutInfo si2 = makeShortcut("shortcut2");
    +-        final ShortcutInfo si3 = makeShortcut("shortcut3");
    +-
    +-        assertTrue(mManager.setDynamicShortcuts(list(si1, si2, si3)));
    +-        assertShortcutIds(assertAllNotKeyFieldsOnly(
    +-                mManager.getDynamicShortcuts()),
    +-                "shortcut1", "shortcut2", "shortcut3");
    +-
    +-        assertEquals(2, mManager.getRemainingCallCount());
    +-
    +-        mManager.removeAllDynamicShortcuts();
    +-        assertEquals(0, mManager.getDynamicShortcuts().size());
    +-        assertEquals(2, mManager.getRemainingCallCount());
    +-
    +-        // Note delete shouldn't affect throttling, so...
    +-        assertEquals(0, mManager.getDynamicShortcuts().size());
    +-        assertEquals(0, mManager.getDynamicShortcuts().size());
    +-        assertEquals(0, mManager.getDynamicShortcuts().size());
    +-
    +-        // This should still work.
    +-        assertTrue(mManager.setDynamicShortcuts(list(si1, si2, si3)));
    +-        assertEquals(3, mManager.getDynamicShortcuts().size());
    +-
    +-        // Still 1 call left
    +-        assertEquals(1, mManager.getRemainingCallCount());
    +-    }
    +-
    +-    public void testIcons() throws IOException {
    +-        final Icon res32x32 = Icon.createWithResource(getTestContext(), R.drawable.black_32x32);
    +-        final Icon res64x64 = Icon.createWithResource(getTestContext(), R.drawable.black_64x64);
    +-        final Icon res512x512 = Icon.createWithResource(getTestContext(), R.drawable.black_512x512);
    +-
    +-        final Icon bmp32x32 = Icon.createWithBitmap(BitmapFactory.decodeResource(
    +-                getTestContext().getResources(), R.drawable.black_32x32));
    +-        final Icon bmp64x64 = Icon.createWithBitmap(BitmapFactory.decodeResource(
    +-                getTestContext().getResources(), R.drawable.black_64x64));
    +-        final Icon bmp512x512 = Icon.createWithBitmap(BitmapFactory.decodeResource(
    +-                getTestContext().getResources(), R.drawable.black_512x512));
    +-
    +-        // Set from package 1
    +-        setCaller(CALLING_PACKAGE_1);
    +-        assertTrue(mManager.setDynamicShortcuts(list(
    +-                makeShortcutWithIcon("res32x32", res32x32),
    +-                makeShortcutWithIcon("res64x64", res64x64),
    +-                makeShortcutWithIcon("bmp32x32", bmp32x32),
    +-                makeShortcutWithIcon("bmp64x64", bmp64x64),
    +-                makeShortcutWithIcon("bmp512x512", bmp512x512),
    +-                makeShortcut("none")
    +-        )));
    +-
    +-        // getDynamicShortcuts() shouldn't return icons, thus assertAllNotHaveIcon().
    +-        assertShortcutIds(assertAllNotHaveIcon(mManager.getDynamicShortcuts()),
    +-                "res32x32",
    +-                "res64x64",
    +-                "bmp32x32",
    +-                "bmp64x64",
    +-                "bmp512x512",
    +-                "none");
    +-
    +-        // Call from another caller with the same ID, just to make sure storage is per-package.
    +-        setCaller(CALLING_PACKAGE_2);
    +-        assertTrue(mManager.setDynamicShortcuts(list(
    +-                makeShortcutWithIcon("res32x32", res512x512),
    +-                makeShortcutWithIcon("res64x64", res512x512),
    +-                makeShortcutWithIcon("none", res512x512)
    +-        )));
    +-        assertShortcutIds(assertAllNotHaveIcon(mManager.getDynamicShortcuts()),
    +-                "res32x32",
    +-                "res64x64",
    +-                "none");
    +-
    +-        // Different profile.  Note the names and the contents don't match.
    +-        setCaller(CALLING_PACKAGE_1, USER_P0);
    +-        assertTrue(mManager.setDynamicShortcuts(list(
    +-                makeShortcutWithIcon("res32x32", res512x512),
    +-                makeShortcutWithIcon("bmp32x32", bmp512x512)
    +-        )));
    +-        assertShortcutIds(assertAllNotHaveIcon(mManager.getDynamicShortcuts()),
    +-                "res32x32",
    +-                "bmp32x32");
    +-
    +-        // Re-initialize and load from the files.
    +-        mService.saveDirtyInfo();
    +-        initService();
    +-
    +-        // Load from launcher.
    +-        Bitmap bmp;
    +-
    +-        setCaller(LAUNCHER_1);
    +-        // Check hasIconResource()/hasIconFile().
    +-        assertShortcutIds(assertAllHaveIconResId(
    +-                list(getShortcutInfoAsLauncher(CALLING_PACKAGE_1, "res32x32", USER_0))),
    +-                "res32x32");
    +-
    +-        assertShortcutIds(assertAllHaveIconResId(
    +-                list(getShortcutInfoAsLauncher(CALLING_PACKAGE_1, "res64x64", USER_0))),
    +-                "res64x64");
    +-
    +-        assertShortcutIds(assertAllHaveIconFile(
    +-                list(getShortcutInfoAsLauncher(CALLING_PACKAGE_1, "bmp32x32", USER_0))),
    +-                "bmp32x32");
    +-
    +-        assertShortcutIds(assertAllHaveIconFile(
    +-                list(getShortcutInfoAsLauncher(CALLING_PACKAGE_1, "bmp64x64", USER_0))),
    +-                "bmp64x64");
    +-
    +-        assertShortcutIds(assertAllHaveIconFile(
    +-                list(getShortcutInfoAsLauncher(CALLING_PACKAGE_1, "bmp512x512", USER_0))),
    +-                "bmp512x512");
    +-
    +-        assertShortcutIds(assertAllHaveIconResId(
    +-                list(getShortcutInfoAsLauncher(CALLING_PACKAGE_1, "res32x32", USER_P0))),
    +-                "res32x32");
    +-        assertShortcutIds(assertAllHaveIconFile(
    +-                list(getShortcutInfoAsLauncher(CALLING_PACKAGE_1, "bmp32x32", USER_P0))),
    +-                "bmp32x32");
    +-
    +-        // Check
    +-        assertEquals(
    +-                R.drawable.black_32x32,
    +-                mLauncherApps.getShortcutIconResId(
    +-                        getShortcutInfoAsLauncher(CALLING_PACKAGE_1, "res32x32", USER_0)));
    +-
    +-        assertEquals(
    +-                R.drawable.black_64x64,
    +-                mLauncherApps.getShortcutIconResId(
    +-                        getShortcutInfoAsLauncher(CALLING_PACKAGE_1, "res64x64", USER_0)));
    +-
    +-        assertEquals(
    +-                0, // because it's not a resource
    +-                mLauncherApps.getShortcutIconResId(
    +-                        getShortcutInfoAsLauncher(CALLING_PACKAGE_1, "bmp32x32", USER_0)));
    +-        assertEquals(
    +-                0, // because it's not a resource
    +-                mLauncherApps.getShortcutIconResId(
    +-                        getShortcutInfoAsLauncher(CALLING_PACKAGE_1, "bmp64x64", USER_0)));
    +-        assertEquals(
    +-                0, // because it's not a resource
    +-                mLauncherApps.getShortcutIconResId(
    +-                        getShortcutInfoAsLauncher(CALLING_PACKAGE_1, "bmp512x512", USER_0)));
    +-
    +-        bmp = pfdToBitmap(mLauncherApps.getShortcutIconFd(
    +-                getShortcutInfoAsLauncher(CALLING_PACKAGE_1, "bmp32x32", USER_0)));
    +-        assertBitmapSize(32, 32, bmp);
    +-
    +-        bmp = pfdToBitmap(mLauncherApps.getShortcutIconFd(
    +-                getShortcutInfoAsLauncher(CALLING_PACKAGE_1, "bmp64x64", USER_0)));
    +-        assertBitmapSize(64, 64, bmp);
    +-
    +-        bmp = pfdToBitmap(mLauncherApps.getShortcutIconFd(
    +-                getShortcutInfoAsLauncher(CALLING_PACKAGE_1, "bmp512x512", USER_0)));
    +-        assertBitmapSize(128, 128, bmp);
    +-
    +-        assertEquals(
    +-                R.drawable.black_512x512,
    +-                mLauncherApps.getShortcutIconResId(
    +-                        getShortcutInfoAsLauncher(CALLING_PACKAGE_1, "res32x32", USER_P0)));
    +-        // Should be 512x512, so shrunk.
    +-        bmp = pfdToBitmap(mLauncherApps.getShortcutIconFd(
    +-                getShortcutInfoAsLauncher(CALLING_PACKAGE_1, "bmp32x32", USER_P0)));
    +-        assertBitmapSize(128, 128, bmp);
    +-
    +-        // Also check the overload APIs too.
    +-        assertEquals(
    +-                R.drawable.black_32x32,
    +-                mLauncherApps.getShortcutIconResId(CALLING_PACKAGE_1, "res32x32", HANDLE_USER_0));
    +-        assertEquals(
    +-                R.drawable.black_64x64,
    +-                mLauncherApps.getShortcutIconResId(CALLING_PACKAGE_1, "res64x64", HANDLE_USER_0));
    +-        assertEquals(
    +-                R.drawable.black_512x512,
    +-                mLauncherApps.getShortcutIconResId(CALLING_PACKAGE_1, "res32x32", HANDLE_USER_P0));
    +-        bmp = pfdToBitmap(
    +-                mLauncherApps.getShortcutIconFd(CALLING_PACKAGE_1, "bmp32x32", HANDLE_USER_P0));
    +-        assertBitmapSize(128, 128, bmp);
    +-    }
    +-
    +-    public void testCleanupDanglingBitmaps() throws Exception {
    +-        assertBitmapDirectories(USER_0, EMPTY_STRINGS);
    +-        assertBitmapDirectories(USER_10, EMPTY_STRINGS);
    +-
    +-        // Make some shortcuts with bitmap icons.
    +-        final Icon bmp32x32 = Icon.createWithBitmap(BitmapFactory.decodeResource(
    +-                getTestContext().getResources(), R.drawable.black_32x32));
    +-
    +-        runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
    +-            mManager.setDynamicShortcuts(list(
    +-                    makeShortcutWithIcon("s1", bmp32x32),
    +-                    makeShortcutWithIcon("s2", bmp32x32),
    +-                    makeShortcutWithIcon("s3", bmp32x32)
    +-            ));
    +-        });
    +-
    +-        // Increment the time (which actually we don't have to), which is used for filenames.
    +-        mInjectedCurrentTimeMillis++;
    +-
    +-        runWithCaller(CALLING_PACKAGE_2, USER_0, () -> {
    +-            mManager.setDynamicShortcuts(list(
    +-                    makeShortcutWithIcon("s4", bmp32x32),
    +-                    makeShortcutWithIcon("s5", bmp32x32),
    +-                    makeShortcutWithIcon("s6", bmp32x32)
    +-            ));
    +-        });
    +-
    +-        // Increment the time, which is used for filenames.
    +-        mInjectedCurrentTimeMillis++;
    +-
    +-        runWithCaller(CALLING_PACKAGE_3, USER_0, () -> {
    +-            mManager.setDynamicShortcuts(list(
    +-            ));
    +-        });
    +-
    +-        // For USER-10, let's try without updating the times.
    +-        mRunningUsers.put(USER_10, true);
    +-
    +-        runWithCaller(CALLING_PACKAGE_1, USER_10, () -> {
    +-            mManager.setDynamicShortcuts(list(
    +-                    makeShortcutWithIcon("10s1", bmp32x32),
    +-                    makeShortcutWithIcon("10s2", bmp32x32),
    +-                    makeShortcutWithIcon("10s3", bmp32x32)
    +-            ));
    +-        });
    +-        runWithCaller(CALLING_PACKAGE_2, USER_10, () -> {
    +-            mManager.setDynamicShortcuts(list(
    +-                    makeShortcutWithIcon("10s4", bmp32x32),
    +-                    makeShortcutWithIcon("10s5", bmp32x32),
    +-                    makeShortcutWithIcon("10s6", bmp32x32)
    +-            ));
    +-        });
    +-        runWithCaller(CALLING_PACKAGE_3, USER_10, () -> {
    +-            mManager.setDynamicShortcuts(list(
    +-            ));
    +-        });
    +-
    +-        dumpsysOnLogcat();
    +-
    +-        // Check files and directories.
    +-        // Package 3 has no bitmaps, so we don't create a directory.
    +-        assertBitmapDirectories(USER_0, CALLING_PACKAGE_1, CALLING_PACKAGE_2);
    +-        assertBitmapDirectories(USER_10, CALLING_PACKAGE_1, CALLING_PACKAGE_2);
    +-
    +-        assertBitmapFiles(USER_0, CALLING_PACKAGE_1,
    +-                getBitmapFilename(USER_0, CALLING_PACKAGE_1, "s1"),
    +-                getBitmapFilename(USER_0, CALLING_PACKAGE_1, "s2"),
    +-                getBitmapFilename(USER_0, CALLING_PACKAGE_1, "s3")
    +-        );
    +-        assertBitmapFiles(USER_0, CALLING_PACKAGE_2,
    +-                getBitmapFilename(USER_0, CALLING_PACKAGE_2, "s4"),
    +-                getBitmapFilename(USER_0, CALLING_PACKAGE_2, "s5"),
    +-                getBitmapFilename(USER_0, CALLING_PACKAGE_2, "s6")
    +-        );
    +-        assertBitmapFiles(USER_0, CALLING_PACKAGE_3,
    +-                EMPTY_STRINGS
    +-        );
    +-        assertBitmapFiles(USER_10, CALLING_PACKAGE_1,
    +-                getBitmapFilename(USER_10, CALLING_PACKAGE_1, "10s1"),
    +-                getBitmapFilename(USER_10, CALLING_PACKAGE_1, "10s2"),
    +-                getBitmapFilename(USER_10, CALLING_PACKAGE_1, "10s3")
    +-        );
    +-        assertBitmapFiles(USER_10, CALLING_PACKAGE_2,
    +-                getBitmapFilename(USER_10, CALLING_PACKAGE_2, "10s4"),
    +-                getBitmapFilename(USER_10, CALLING_PACKAGE_2, "10s5"),
    +-                getBitmapFilename(USER_10, CALLING_PACKAGE_2, "10s6")
    +-        );
    +-        assertBitmapFiles(USER_10, CALLING_PACKAGE_3,
    +-                EMPTY_STRINGS
    +-        );
    +-
    +-        // Then create random directories and files.
    +-        makeFile(mService.getUserBitmapFilePath(USER_0), "a.b.c").mkdir();
    +-        makeFile(mService.getUserBitmapFilePath(USER_0), "d.e.f").mkdir();
    +-        makeFile(mService.getUserBitmapFilePath(USER_0), "d.e.f", "123").createNewFile();
    +-        makeFile(mService.getUserBitmapFilePath(USER_0), "d.e.f", "456").createNewFile();
    +-
    +-        makeFile(mService.getUserBitmapFilePath(USER_0), CALLING_PACKAGE_3).mkdir();
    +-
    +-        makeFile(mService.getUserBitmapFilePath(USER_0), CALLING_PACKAGE_1, "1").createNewFile();
    +-        makeFile(mService.getUserBitmapFilePath(USER_0), CALLING_PACKAGE_1, "2").createNewFile();
    +-        makeFile(mService.getUserBitmapFilePath(USER_0), CALLING_PACKAGE_1, "3").createNewFile();
    +-        makeFile(mService.getUserBitmapFilePath(USER_0), CALLING_PACKAGE_1, "4").createNewFile();
    +-
    +-        makeFile(mService.getUserBitmapFilePath(USER_10), "10a.b.c").mkdir();
    +-        makeFile(mService.getUserBitmapFilePath(USER_10), "10d.e.f").mkdir();
    +-        makeFile(mService.getUserBitmapFilePath(USER_10), "10d.e.f", "123").createNewFile();
    +-        makeFile(mService.getUserBitmapFilePath(USER_10), "10d.e.f", "456").createNewFile();
    +-
    +-        makeFile(mService.getUserBitmapFilePath(USER_10), CALLING_PACKAGE_2, "1").createNewFile();
    +-        makeFile(mService.getUserBitmapFilePath(USER_10), CALLING_PACKAGE_2, "2").createNewFile();
    +-        makeFile(mService.getUserBitmapFilePath(USER_10), CALLING_PACKAGE_2, "3").createNewFile();
    +-        makeFile(mService.getUserBitmapFilePath(USER_10), CALLING_PACKAGE_2, "4").createNewFile();
    +-
    +-        assertBitmapDirectories(USER_0, CALLING_PACKAGE_1, CALLING_PACKAGE_2, CALLING_PACKAGE_3,
    +-                "a.b.c", "d.e.f");
    +-
    +-        // Save and load.  When a user is loaded, we do the cleanup.
    +-        mService.saveDirtyInfo();
    +-        initService();
    +-
    +-        mService.handleUnlockUser(USER_0);
    +-        mService.handleUnlockUser(USER_10);
    +-        mService.handleUnlockUser(20); // Make sure the logic will still work for nonexistent user.
    +-
    +-        // The below check is the same as above, except this time USER_0 use the CALLING_PACKAGE_3
    +-        // directory.
    +-
    +-        assertBitmapDirectories(USER_0, CALLING_PACKAGE_1, CALLING_PACKAGE_2, CALLING_PACKAGE_3);
    +-        assertBitmapDirectories(USER_10, CALLING_PACKAGE_1, CALLING_PACKAGE_2);
    +-
    +-        assertBitmapFiles(USER_0, CALLING_PACKAGE_1,
    +-                getBitmapFilename(USER_0, CALLING_PACKAGE_1, "s1"),
    +-                getBitmapFilename(USER_0, CALLING_PACKAGE_1, "s2"),
    +-                getBitmapFilename(USER_0, CALLING_PACKAGE_1, "s3")
    +-        );
    +-        assertBitmapFiles(USER_0, CALLING_PACKAGE_2,
    +-                getBitmapFilename(USER_0, CALLING_PACKAGE_2, "s4"),
    +-                getBitmapFilename(USER_0, CALLING_PACKAGE_2, "s5"),
    +-                getBitmapFilename(USER_0, CALLING_PACKAGE_2, "s6")
    +-        );
    +-        assertBitmapFiles(USER_0, CALLING_PACKAGE_3,
    +-                EMPTY_STRINGS
    +-        );
    +-        assertBitmapFiles(USER_10, CALLING_PACKAGE_1,
    +-                getBitmapFilename(USER_10, CALLING_PACKAGE_1, "10s1"),
    +-                getBitmapFilename(USER_10, CALLING_PACKAGE_1, "10s2"),
    +-                getBitmapFilename(USER_10, CALLING_PACKAGE_1, "10s3")
    +-        );
    +-        assertBitmapFiles(USER_10, CALLING_PACKAGE_2,
    +-                getBitmapFilename(USER_10, CALLING_PACKAGE_2, "10s4"),
    +-                getBitmapFilename(USER_10, CALLING_PACKAGE_2, "10s5"),
    +-                getBitmapFilename(USER_10, CALLING_PACKAGE_2, "10s6")
    +-        );
    +-        assertBitmapFiles(USER_10, CALLING_PACKAGE_3,
    +-                EMPTY_STRINGS
    +-        );
    +-    }
    +-
    +-    protected void checkShrinkBitmap(int expectedWidth, int expectedHeight, int resId, int maxSize) {
    +-        assertBitmapSize(expectedWidth, expectedHeight,
    +-                ShortcutService.shrinkBitmap(BitmapFactory.decodeResource(
    +-                        getTestContext().getResources(), resId),
    +-                        maxSize));
    +-    }
    +-
    +-    public void testShrinkBitmap() {
    +-        checkShrinkBitmap(32, 32, R.drawable.black_512x512, 32);
    +-        checkShrinkBitmap(511, 511, R.drawable.black_512x512, 511);
    +-        checkShrinkBitmap(512, 512, R.drawable.black_512x512, 512);
    +-
    +-        checkShrinkBitmap(1024, 4096, R.drawable.black_1024x4096, 4096);
    +-        checkShrinkBitmap(1024, 4096, R.drawable.black_1024x4096, 4100);
    +-        checkShrinkBitmap(512, 2048, R.drawable.black_1024x4096, 2048);
    +-
    +-        checkShrinkBitmap(4096, 1024, R.drawable.black_4096x1024, 4096);
    +-        checkShrinkBitmap(4096, 1024, R.drawable.black_4096x1024, 4100);
    +-        checkShrinkBitmap(2048, 512, R.drawable.black_4096x1024, 2048);
    +-    }
    +-
    +-    protected File openIconFileForWriteAndGetPath(int userId, String packageName)
    +-            throws IOException {
    +-        // Shortcut IDs aren't used in the path, so just pass the same ID.
    +-        final FileOutputStreamWithPath out =
    +-                mService.openIconFileForWrite(userId, makePackageShortcut(packageName, "id"));
    +-        out.close();
    +-        return out.getFile();
    +-    }
    +-
    +-    public void testOpenIconFileForWrite() throws IOException {
    +-        mInjectedCurrentTimeMillis = 1000;
    +-
    +-        final File p10_1_1 = openIconFileForWriteAndGetPath(10, CALLING_PACKAGE_1);
    +-        final File p10_1_2 = openIconFileForWriteAndGetPath(10, CALLING_PACKAGE_1);
    +-
    +-        final File p10_2_1 = openIconFileForWriteAndGetPath(10, CALLING_PACKAGE_2);
    +-        final File p10_2_2 = openIconFileForWriteAndGetPath(10, CALLING_PACKAGE_2);
    +-
    +-        final File p11_1_1 = openIconFileForWriteAndGetPath(11, CALLING_PACKAGE_1);
    +-        final File p11_1_2 = openIconFileForWriteAndGetPath(11, CALLING_PACKAGE_1);
    +-
    +-        mInjectedCurrentTimeMillis++;
    +-
    +-        final File p10_1_3 = openIconFileForWriteAndGetPath(10, CALLING_PACKAGE_1);
    +-        final File p10_1_4 = openIconFileForWriteAndGetPath(10, CALLING_PACKAGE_1);
    +-        final File p10_1_5 = openIconFileForWriteAndGetPath(10, CALLING_PACKAGE_1);
    +-
    +-        final File p10_2_3 = openIconFileForWriteAndGetPath(10, CALLING_PACKAGE_2);
    +-        final File p11_1_3 = openIconFileForWriteAndGetPath(11, CALLING_PACKAGE_1);
    +-
    +-        // Make sure their paths are all unique
    +-        assertAllUnique(list(
    +-                p10_1_1,
    +-                p10_1_2,
    +-                p10_1_3,
    +-                p10_1_4,
    +-                p10_1_5,
    +-
    +-                p10_2_1,
    +-                p10_2_2,
    +-                p10_2_3,
    +-
    +-                p11_1_1,
    +-                p11_1_2,
    +-                p11_1_3
    +-        ));
    +-
    +-        // Check each set has the same parent.
    +-        assertEquals(p10_1_1.getParent(), p10_1_2.getParent());
    +-        assertEquals(p10_1_1.getParent(), p10_1_3.getParent());
    +-        assertEquals(p10_1_1.getParent(), p10_1_4.getParent());
    +-        assertEquals(p10_1_1.getParent(), p10_1_5.getParent());
    +-
    +-        assertEquals(p10_2_1.getParent(), p10_2_2.getParent());
    +-        assertEquals(p10_2_1.getParent(), p10_2_3.getParent());
    +-
    +-        assertEquals(p11_1_1.getParent(), p11_1_2.getParent());
    +-        assertEquals(p11_1_1.getParent(), p11_1_3.getParent());
    +-
    +-        // Check the parents are still unique.
    +-        assertAllUnique(list(
    +-                p10_1_1.getParent(),
    +-                p10_2_1.getParent(),
    +-                p11_1_1.getParent()
    +-        ));
    +-
    +-        // All files created at the same time for the same package/user, expcet for the first ones,
    +-        // will have "_" in the path.
    +-        assertFalse(p10_1_1.getName().contains("_"));
    +-        assertTrue(p10_1_2.getName().contains("_"));
    +-        assertFalse(p10_1_3.getName().contains("_"));
    +-        assertTrue(p10_1_4.getName().contains("_"));
    +-        assertTrue(p10_1_5.getName().contains("_"));
    +-
    +-        assertFalse(p10_2_1.getName().contains("_"));
    +-        assertTrue(p10_2_2.getName().contains("_"));
    +-        assertFalse(p10_2_3.getName().contains("_"));
    +-
    +-        assertFalse(p11_1_1.getName().contains("_"));
    +-        assertTrue(p11_1_2.getName().contains("_"));
    +-        assertFalse(p11_1_3.getName().contains("_"));
    +-    }
    +-
    +-    public void testUpdateShortcuts() {
    +-        runWithCaller(CALLING_PACKAGE_1, UserHandle.USER_SYSTEM, () -> {
    +-            assertTrue(mManager.setDynamicShortcuts(list(
    +-                    makeShortcut("s1"),
    +-                    makeShortcut("s2"),
    +-                    makeShortcut("s3"),
    +-                    makeShortcut("s4"),
    +-                    makeShortcut("s5")
    +-            )));
    +-        });
    +-        runWithCaller(CALLING_PACKAGE_2, UserHandle.USER_SYSTEM, () -> {
    +-            assertTrue(mManager.setDynamicShortcuts(list(
    +-                    makeShortcut("s1"),
    +-                    makeShortcut("s2"),
    +-                    makeShortcut("s3"),
    +-                    makeShortcut("s4"),
    +-                    makeShortcut("s5")
    +-            )));
    +-        });
    +-        runWithCaller(LAUNCHER_1, UserHandle.USER_SYSTEM, () -> {
    +-            mLauncherApps.pinShortcuts(CALLING_PACKAGE_1, list("s2", "s3"),
    +-                    getCallingUser());
    +-            mLauncherApps.pinShortcuts(CALLING_PACKAGE_2, list("s4", "s5"),
    +-                    getCallingUser());
    +-        });
    +-        runWithCaller(CALLING_PACKAGE_1, UserHandle.USER_SYSTEM, () -> {
    +-            mManager.removeDynamicShortcuts(list("s1"));
    +-            mManager.removeDynamicShortcuts(list("s2"));
    +-        });
    +-        runWithCaller(CALLING_PACKAGE_2, UserHandle.USER_SYSTEM, () -> {
    +-            mManager.removeDynamicShortcuts(list("s1"));
    +-            mManager.removeDynamicShortcuts(list("s3"));
    +-            mManager.removeDynamicShortcuts(list("s5"));
    +-        });
    +-        runWithCaller(CALLING_PACKAGE_1, UserHandle.USER_SYSTEM, () -> {
    +-            assertShortcutIds(assertAllDynamic(
    +-                    mManager.getDynamicShortcuts()),
    +-                    "s3", "s4", "s5");
    +-            assertShortcutIds(assertAllPinned(
    +-                    mManager.getPinnedShortcuts()),
    +-                    "s2", "s3");
    +-        });
    +-        runWithCaller(CALLING_PACKAGE_2, UserHandle.USER_SYSTEM, () -> {
    +-            assertShortcutIds(assertAllDynamic(
    +-                    mManager.getDynamicShortcuts()),
    +-                    "s2", "s4");
    +-            assertShortcutIds(assertAllPinned(
    +-                    mManager.getPinnedShortcuts()),
    +-                    "s4", "s5");
    +-        });
    +-
    +-        runWithCaller(CALLING_PACKAGE_1, UserHandle.USER_SYSTEM, () -> {
    +-            ShortcutInfo s2 = makeShortcutBuilder()
    +-                    .setId("s2")
    +-                    .setIcon(Icon.createWithResource(getTestContext(), R.drawable.black_32x32))
    +-                    .build();
    +-
    +-            ShortcutInfo s4 = makeShortcutBuilder()
    +-                    .setId("s4")
    +-                    .setTitle("new title")
    +-                    .build();
    +-
    +-            mManager.updateShortcuts(list(s2, s4));
    +-        });
    +-        runWithCaller(CALLING_PACKAGE_2, UserHandle.USER_SYSTEM, () -> {
    +-            ShortcutInfo s2 = makeShortcutBuilder()
    +-                    .setId("s2")
    +-                    .setIntent(makeIntent(Intent.ACTION_ANSWER, ShortcutActivity.class,
    +-                            "key1", "val1"))
    +-                    .build();
    +-
    +-            ShortcutInfo s4 = makeShortcutBuilder()
    +-                    .setId("s4")
    +-                    .setIntent(new Intent(Intent.ACTION_ALL_APPS))
    +-                    .build();
    +-
    +-            mManager.updateShortcuts(list(s2, s4));
    +-        });
    +-
    +-        runWithCaller(CALLING_PACKAGE_1, UserHandle.USER_SYSTEM, () -> {
    +-            assertShortcutIds(assertAllDynamic(
    +-                    mManager.getDynamicShortcuts()),
    +-                    "s3", "s4", "s5");
    +-            assertShortcutIds(assertAllPinned(
    +-                    mManager.getPinnedShortcuts()),
    +-                    "s2", "s3");
    +-
    +-            ShortcutInfo s = getCallerShortcut("s2");
    +-            assertTrue(s.hasIconResource());
    +-            assertEquals(R.drawable.black_32x32, s.getIconResourceId());
    +-            assertEquals("string/r" + R.drawable.black_32x32, s.getIconResName());
    +-            assertEquals("Title-s2", s.getTitle());
    +-
    +-            s = getCallerShortcut("s4");
    +-            assertFalse(s.hasIconResource());
    +-            assertEquals(0, s.getIconResourceId());
    +-            assertEquals("new title", s.getTitle());
    +-        });
    +-        runWithCaller(CALLING_PACKAGE_2, UserHandle.USER_SYSTEM, () -> {
    +-            assertShortcutIds(assertAllDynamic(
    +-                    mManager.getDynamicShortcuts()),
    +-                    "s2", "s4");
    +-            assertShortcutIds(assertAllPinned(
    +-                    mManager.getPinnedShortcuts()),
    +-                    "s4", "s5");
    +-
    +-            ShortcutInfo s = getCallerShortcut("s2");
    +-            assertFalse(s.hasIconResource());
    +-            assertEquals(0, s.getIconResourceId());
    +-            assertEquals("Title-s2", s.getTitle());
    +-            assertEquals(Intent.ACTION_ANSWER, s.getIntent().getAction());
    +-            assertEquals(1, s.getIntent().getExtras().size());
    +-
    +-            s = getCallerShortcut("s4");
    +-            assertFalse(s.hasIconResource());
    +-            assertEquals(0, s.getIconResourceId());
    +-            assertEquals("Title-s4", s.getTitle());
    +-            assertEquals(Intent.ACTION_ALL_APPS, s.getIntent().getAction());
    +-            assertBundleEmpty(s.getIntent().getExtras());
    +-        });
    +-        // TODO Check with other fields too.
    +-
    +-        // TODO Check bitmap removal too.
    +-
    +-        mRunningUsers.put(USER_11, true);
    +-
    +-        runWithCaller(CALLING_PACKAGE_2, USER_11, () -> {
    +-            mManager.updateShortcuts(list());
    +-        });
    +-    }
    +-
    +-    public void testUpdateShortcuts_icons() {
    +-        runWithCaller(CALLING_PACKAGE_1, UserHandle.USER_SYSTEM, () -> {
    +-            assertTrue(mManager.setDynamicShortcuts(list(
    +-                    makeShortcut("s1")
    +-            )));
    +-
    +-            // Set resource icon
    +-            assertTrue(mManager.updateShortcuts(list(
    +-                    new ShortcutInfo.Builder(mClientContext, "s1")
    +-                    .setIcon(Icon.createWithResource(getTestContext(), R.drawable.black_32x32))
    +-                    .build()
    +-            )));
    +-
    +-            assertWith(getCallerShortcuts())
    +-                    .forShortcutWithId("s1", si -> {
    +-                        assertTrue(si.hasIconResource());
    +-                        assertEquals(R.drawable.black_32x32, si.getIconResourceId());
    +-                    });
    +-
    +-            // Set bitmap icon
    +-            assertTrue(mManager.updateShortcuts(list(
    +-                    new ShortcutInfo.Builder(mClientContext, "s1")
    +-                    .setIcon(Icon.createWithBitmap(BitmapFactory.decodeResource(
    +-                            getTestContext().getResources(), R.drawable.black_64x64)))
    +-                    .build()
    +-            )));
    +-
    +-            assertWith(getCallerShortcuts())
    +-                    .forShortcutWithId("s1", si -> {
    +-                        assertTrue(si.hasIconFile());
    +-                    });
    +-
    +-            mInjectedCurrentTimeMillis += INTERVAL; // reset throttling
    +-
    +-            // Do it again, with the reverse order (bitmap -> icon)
    +-            assertTrue(mManager.setDynamicShortcuts(list(
    +-                    makeShortcut("s1")
    +-            )));
    +-
    +-            // Set bitmap icon
    +-            assertTrue(mManager.updateShortcuts(list(
    +-                    new ShortcutInfo.Builder(mClientContext, "s1")
    +-                            .setIcon(Icon.createWithBitmap(BitmapFactory.decodeResource(
    +-                                    getTestContext().getResources(), R.drawable.black_64x64)))
    +-                            .build()
    +-            )));
    +-
    +-            assertWith(getCallerShortcuts())
    +-                    .forShortcutWithId("s1", si -> {
    +-                        assertTrue(si.hasIconFile());
    +-                    });
    +-
    +-            // Set resource icon
    +-            assertTrue(mManager.updateShortcuts(list(
    +-                    new ShortcutInfo.Builder(mClientContext, "s1")
    +-                            .setIcon(Icon.createWithResource(getTestContext(), R.drawable.black_32x32))
    +-                            .build()
    +-            )));
    +-
    +-            assertWith(getCallerShortcuts())
    +-                    .forShortcutWithId("s1", si -> {
    +-                        assertTrue(si.hasIconResource());
    +-                        assertEquals(R.drawable.black_32x32, si.getIconResourceId());
    +-                    });
    +-        });
    +-    }
    +-
    +-    // === Test for launcher side APIs ===
    +-
    +-    public void testGetShortcuts() {
    +-
    +-        // Set up shortcuts.
    +-
    +-        setCaller(CALLING_PACKAGE_1);
    +-        final ShortcutInfo s1_1 = makeShortcut("s1");
    +-        final ShortcutInfo s1_2 = makeShortcut("s2");
    +-
    +-        assertTrue(mManager.setDynamicShortcuts(list(s1_1, s1_2)));
    +-
    +-        // Because setDynamicShortcuts will update the timestamps when ranks are changing,
    +-        // we explicitly set timestamps here.
    +-        getCallerShortcut("s1").setTimestamp(5000);
    +-        getCallerShortcut("s2").setTimestamp(1000);
    +-
    +-        setCaller(CALLING_PACKAGE_2);
    +-        final ShortcutInfo s2_2 = makeShortcut("s2");
    +-        final ShortcutInfo s2_3 = makeShortcutWithActivity("s3",
    +-                makeComponent(ShortcutActivity2.class));
    +-        final ShortcutInfo s2_4 = makeShortcutWithActivity("s4",
    +-                makeComponent(ShortcutActivity.class));
    +-        assertTrue(mManager.setDynamicShortcuts(list(s2_2, s2_3, s2_4)));
    +-
    +-        getCallerShortcut("s2").setTimestamp(1500);
    +-        getCallerShortcut("s3").setTimestamp(3000);
    +-        getCallerShortcut("s4").setTimestamp(500);
    +-
    +-        setCaller(CALLING_PACKAGE_3);
    +-        final ShortcutInfo s3_2 = makeShortcut("s3");
    +-        assertTrue(mManager.setDynamicShortcuts(list(s3_2)));
    +-
    +-        getCallerShortcut("s3").setTimestamp(START_TIME + 5000);
    +-
    +-        setCaller(LAUNCHER_1);
    +-
    +-        // Get dynamic
    +-        assertAllDynamic(assertAllHaveTitle(assertAllNotHaveIntents(assertAllStringsResolved(
    +-                assertShortcutIds(
    +-                        assertAllNotKeyFieldsOnly(
    +-                                mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_1,
    +-                        /* activity =*/ null, ShortcutQuery.FLAG_GET_DYNAMIC), getCallingUser())),
    +-                        "s1", "s2")))));
    +-
    +-        // Get pinned
    +-        assertShortcutIds(
    +-                mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_1,
    +-                        /* activity =*/ null,
    +-                        ShortcutQuery.FLAG_GET_PINNED), getCallingUser())
    +-                /* none */);
    +-
    +-        // Get both, with timestamp
    +-        assertAllDynamic(assertAllHaveTitle(assertAllNotHaveIntents(assertShortcutIds(
    +-                assertAllNotKeyFieldsOnly(mLauncherApps.getShortcuts(buildQuery(
    +-                        /* time =*/ 1000, CALLING_PACKAGE_2,
    +-                        /* activity =*/ null,
    +-                        ShortcutQuery.FLAG_GET_PINNED | ShortcutQuery.FLAG_GET_DYNAMIC),
    +-                        getCallingUser())),
    +-                "s2", "s3"))));
    +-
    +-        // FLAG_GET_KEY_FIELDS_ONLY
    +-        assertAllDynamic(assertAllNotHaveTitle(assertAllNotHaveIntents(assertShortcutIds(
    +-                assertAllKeyFieldsOnly(mLauncherApps.getShortcuts(buildQuery(
    +-                        /* time =*/ 1000, CALLING_PACKAGE_2,
    +-                        /* activity =*/ null,
    +-                        ShortcutQuery.FLAG_GET_DYNAMIC | ShortcutQuery.FLAG_GET_KEY_FIELDS_ONLY),
    +-                        getCallingUser())),
    +-                "s2", "s3"))));
    +-
    +-        // Filter by activity
    +-        assertAllDynamic(assertAllHaveTitle(assertAllNotHaveIntents(assertShortcutIds(
    +-                assertAllNotKeyFieldsOnly(mLauncherApps.getShortcuts(buildQuery(
    +-                        /* time =*/ 0, CALLING_PACKAGE_2,
    +-                        new ComponentName(CALLING_PACKAGE_2, ShortcutActivity.class.getName()),
    +-                        ShortcutQuery.FLAG_GET_PINNED | ShortcutQuery.FLAG_GET_DYNAMIC),
    +-                        getCallingUser())),
    +-                "s4"))));
    +-
    +-        // With ID.
    +-        assertAllDynamic(assertAllNotHaveTitle(assertAllNotHaveIntents(assertShortcutIds(
    +-                assertAllKeyFieldsOnly(mLauncherApps.getShortcuts(buildQuery(
    +-                        /* time =*/ 1000, CALLING_PACKAGE_2, list("s3"),
    +-                        /* activity =*/ null,
    +-                        ShortcutQuery.FLAG_GET_DYNAMIC | ShortcutQuery.FLAG_GET_KEY_FIELDS_ONLY),
    +-                        getCallingUser())),
    +-                "s3"))));
    +-        assertAllDynamic(assertAllNotHaveTitle(assertAllNotHaveIntents(assertShortcutIds(
    +-                assertAllKeyFieldsOnly(mLauncherApps.getShortcuts(buildQuery(
    +-                        /* time =*/ 1000, CALLING_PACKAGE_2, list("s3", "s2", "ss"),
    +-                        /* activity =*/ null,
    +-                        ShortcutQuery.FLAG_GET_DYNAMIC | ShortcutQuery.FLAG_GET_KEY_FIELDS_ONLY),
    +-                        getCallingUser())),
    +-                "s2", "s3"))));
    +-        assertAllDynamic(assertAllNotHaveTitle(assertAllNotHaveIntents(assertShortcutIds(
    +-                assertAllKeyFieldsOnly(mLauncherApps.getShortcuts(buildQuery(
    +-                        /* time =*/ 1000, CALLING_PACKAGE_2, list("s3x", "s2x"),
    +-                        /* activity =*/ null,
    +-                        ShortcutQuery.FLAG_GET_DYNAMIC | ShortcutQuery.FLAG_GET_KEY_FIELDS_ONLY),
    +-                        getCallingUser()))
    +-                /* empty */))));
    +-        assertAllDynamic(assertAllNotHaveTitle(assertAllNotHaveIntents(assertShortcutIds(
    +-                assertAllKeyFieldsOnly(mLauncherApps.getShortcuts(buildQuery(
    +-                        /* time =*/ 1000, CALLING_PACKAGE_2, list(),
    +-                        /* activity =*/ null,
    +-                        ShortcutQuery.FLAG_GET_DYNAMIC | ShortcutQuery.FLAG_GET_KEY_FIELDS_ONLY),
    +-                        getCallingUser()))
    +-                /* empty */))));
    +-
    +-        // Pin some shortcuts.
    +-        mLauncherApps.pinShortcuts(CALLING_PACKAGE_2,
    +-                list("s3", "s4"), getCallingUser());
    +-
    +-        // Pinned ones only
    +-        assertAllPinned(assertAllHaveTitle(assertAllNotHaveIntents(assertShortcutIds(
    +-                assertAllNotKeyFieldsOnly(mLauncherApps.getShortcuts(buildQuery(
    +-                        /* time =*/ 1000, CALLING_PACKAGE_2,
    +-                        /* activity =*/ null,
    +-                        ShortcutQuery.FLAG_GET_PINNED),
    +-                        getCallingUser())),
    +-                "s3"))));
    +-
    +-        // All packages.
    +-        assertShortcutIds(assertAllNotKeyFieldsOnly(
    +-                mLauncherApps.getShortcuts(buildQuery(
    +-                        /* time =*/ 5000, /* package= */ null,
    +-                        /* activity =*/ null,
    +-                        ShortcutQuery.FLAG_GET_DYNAMIC | ShortcutQuery.FLAG_GET_PINNED),
    +-                        getCallingUser())),
    +-                "s1", "s3");
    +-
    +-        assertExpectException(
    +-                IllegalArgumentException.class, "package name must also be set", () -> {
    +-                    mLauncherApps.getShortcuts(buildQuery(
    +-                    /* time =*/ 0, /* package= */ null, list("id"),
    +-                    /* activity =*/ null, /* flags */ 0), getCallingUser());
    +-                });
    +-
    +-        // TODO More tests: pinned but dynamic.
    +-    }
    +-
    +-    public void testGetShortcuts_shortcutKinds() throws Exception {
    +-        // Create 3 manifest and 3 dynamic shortcuts
    +-        addManifestShortcutResource(
    +-                new ComponentName(CALLING_PACKAGE_1, ShortcutActivity.class.getName()),
    +-                R.xml.shortcut_3);
    +-        updatePackageVersion(CALLING_PACKAGE_1, 1);
    +-        mService.mPackageMonitor.onReceive(getTestContext(),
    +-                genPackageAddIntent(CALLING_PACKAGE_1, USER_0));
    +-
    +-        runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
    +-            assertTrue(mManager.setDynamicShortcuts(list(
    +-                    makeShortcut("s1"), makeShortcut("s2"), makeShortcut("s3"))));
    +-        });
    +-
    +-        // Pin 2 and 3
    +-        runWithCaller(LAUNCHER_1, USER_0, () -> {
    +-            mLauncherApps.pinShortcuts(CALLING_PACKAGE_1, list("ms2", "ms3", "s2", "s3"),
    +-                    HANDLE_USER_0);
    +-        });
    +-
    +-        // Remove ms3 and s3
    +-        addManifestShortcutResource(
    +-                new ComponentName(CALLING_PACKAGE_1, ShortcutActivity.class.getName()),
    +-                R.xml.shortcut_2);
    +-        updatePackageVersion(CALLING_PACKAGE_1, 1);
    +-        mService.mPackageMonitor.onReceive(getTestContext(),
    +-                genPackageAddIntent(CALLING_PACKAGE_1, USER_0));
    +-
    +-        runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
    +-            assertTrue(mManager.setDynamicShortcuts(list(
    +-                    makeShortcut("s1"), makeShortcut("s2"))));
    +-        });
    +-
    +-        // Check their status.
    +-        runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
    +-            assertWith(getCallerShortcuts())
    +-                    .haveIds("ms1", "ms2", "ms3", "s1", "s2", "s3")
    +-
    +-                    .selectByIds("ms1", "ms2")
    +-                    .areAllManifest()
    +-                    .areAllImmutable()
    +-                    .areAllNotDynamic()
    +-
    +-                    .revertToOriginalList()
    +-                    .selectByIds("ms3")
    +-                    .areAllNotManifest()
    +-                    .areAllImmutable()
    +-                    .areAllDisabled()
    +-                    .areAllNotDynamic()
    +-
    +-                    .revertToOriginalList()
    +-                    .selectByIds("s1", "s2")
    +-                    .areAllNotManifest()
    +-                    .areAllMutable()
    +-                    .areAllDynamic()
    +-
    +-                    .revertToOriginalList()
    +-                    .selectByIds("s3")
    +-                    .areAllNotManifest()
    +-                    .areAllMutable()
    +-                    .areAllEnabled()
    +-                    .areAllNotDynamic()
    +-
    +-                    .revertToOriginalList()
    +-                    .selectByIds("s1", "ms1")
    +-                    .areAllNotPinned()
    +-
    +-                    .revertToOriginalList()
    +-                    .selectByIds("s2", "s3", "ms2", "ms3")
    +-                    .areAllPinned()
    +-            ;
    +-        });
    +-
    +-        // Finally, actual tests.
    +-        runWithCaller(LAUNCHER_1, USER_0, () -> {
    +-            assertWith(mLauncherApps.getShortcuts(
    +-                    buildQueryWithFlags(ShortcutQuery.FLAG_GET_DYNAMIC), HANDLE_USER_0))
    +-                    .haveIds("s1", "s2");
    +-            assertWith(mLauncherApps.getShortcuts(
    +-                    buildQueryWithFlags(ShortcutQuery.FLAG_GET_MANIFEST), HANDLE_USER_0))
    +-                    .haveIds("ms1", "ms2");
    +-            assertWith(mLauncherApps.getShortcuts(
    +-                    buildQueryWithFlags(ShortcutQuery.FLAG_GET_PINNED), HANDLE_USER_0))
    +-                    .haveIds("s2", "s3", "ms2", "ms3");
    +-
    +-            assertWith(mLauncherApps.getShortcuts(
    +-                    buildQueryWithFlags(
    +-                            ShortcutQuery.FLAG_GET_DYNAMIC | ShortcutQuery.FLAG_GET_PINNED
    +-                    ), HANDLE_USER_0))
    +-                    .haveIds("s1", "s2", "s3", "ms2", "ms3");
    +-
    +-            assertWith(mLauncherApps.getShortcuts(
    +-                    buildQueryWithFlags(
    +-                            ShortcutQuery.FLAG_GET_MANIFEST | ShortcutQuery.FLAG_GET_PINNED
    +-                    ), HANDLE_USER_0))
    +-                    .haveIds("ms1", "s2", "s3", "ms2", "ms3");
    +-
    +-            assertWith(mLauncherApps.getShortcuts(
    +-                    buildQueryWithFlags(
    +-                            ShortcutQuery.FLAG_GET_DYNAMIC | ShortcutQuery.FLAG_GET_MANIFEST
    +-                    ), HANDLE_USER_0))
    +-                    .haveIds("ms1", "ms2", "s1", "s2");
    +-
    +-            assertWith(mLauncherApps.getShortcuts(
    +-                    buildQueryWithFlags(
    +-                            ShortcutQuery.FLAG_GET_ALL_KINDS
    +-                    ), HANDLE_USER_0))
    +-                    .haveIds("ms1", "ms2", "ms3", "s1", "s2", "s3");
    +-        });
    +-    }
    +-
    +-    public void testGetShortcuts_resolveStrings() throws Exception {
    +-        runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
    +-            ShortcutInfo si = new ShortcutInfo.Builder(mClientContext)
    +-                    .setId("id")
    +-                    .setActivity(new ComponentName(mClientContext, "dummy"))
    +-                    .setTitleResId(10)
    +-                    .setTextResId(11)
    +-                    .setDisabledMessageResId(12)
    +-                    .setIntent(makeIntent("action", ShortcutActivity.class))
    +-                    .build();
    +-            mManager.setDynamicShortcuts(list(si));
    +-        });
    +-        runWithCaller(CALLING_PACKAGE_1, USER_P0, () -> {
    +-            ShortcutInfo si = new ShortcutInfo.Builder(mClientContext)
    +-                    .setId("id")
    +-                    .setActivity(new ComponentName(mClientContext, "dummy"))
    +-                    .setTitleResId(10)
    +-                    .setTextResId(11)
    +-                    .setDisabledMessageResId(12)
    +-                    .setIntent(makeIntent("action", ShortcutActivity.class))
    +-                    .build();
    +-            mManager.setDynamicShortcuts(list(si));
    +-        });
    +-
    +-        runWithCaller(LAUNCHER_1, USER_0, () -> {
    +-            final ShortcutQuery q = new ShortcutQuery();
    +-            q.setQueryFlags(ShortcutQuery.FLAG_GET_DYNAMIC);
    +-
    +-            // USER 0
    +-            List<ShortcutInfo> ret = assertShortcutIds(
    +-                    assertAllStringsResolved(mLauncherApps.getShortcuts(q, HANDLE_USER_0)),
    +-                    "id");
    +-            assertEquals("string-com.android.test.1-user:0-res:10/en", ret.get(0).getTitle());
    +-            assertEquals("string-com.android.test.1-user:0-res:11/en", ret.get(0).getText());
    +-            assertEquals("string-com.android.test.1-user:0-res:12/en",
    +-                    ret.get(0).getDisabledMessage());
    +-
    +-            // USER P0
    +-            ret = assertShortcutIds(
    +-                    assertAllStringsResolved(mLauncherApps.getShortcuts(q, HANDLE_USER_P0)),
    +-                    "id");
    +-            assertEquals("string-com.android.test.1-user:20-res:10/en", ret.get(0).getTitle());
    +-            assertEquals("string-com.android.test.1-user:20-res:11/en", ret.get(0).getText());
    +-            assertEquals("string-com.android.test.1-user:20-res:12/en",
    +-                    ret.get(0).getDisabledMessage());
    +-        });
    +-    }
    +-
    +-    // TODO resource
    +-    public void testGetShortcutInfo() {
    +-        // Create shortcuts.
    +-        setCaller(CALLING_PACKAGE_1);
    +-        final ShortcutInfo s1_1 = makeShortcut(
    +-                "s1",
    +-                "Title 1",
    +-                makeComponent(ShortcutActivity.class),
    +-                /* icon =*/ null,
    +-                makeIntent(Intent.ACTION_ASSIST, ShortcutActivity2.class,
    +-                        "key1", "val1", "nest", makeBundle("key", 123)),
    +-                /* weight */ 10);
    +-
    +-        final ShortcutInfo s1_2 = makeShortcut(
    +-                "s2",
    +-                "Title 2",
    +-                /* activity */ null,
    +-                /* icon =*/ null,
    +-                makeIntent(Intent.ACTION_ASSIST, ShortcutActivity3.class),
    +-                /* weight */ 12);
    +-
    +-        assertTrue(mManager.setDynamicShortcuts(list(s1_1, s1_2)));
    +-        dumpsysOnLogcat();
    +-
    +-        setCaller(CALLING_PACKAGE_2);
    +-        final ShortcutInfo s2_1 = makeShortcut(
    +-                "s1",
    +-                "ABC",
    +-                makeComponent(ShortcutActivity2.class),
    +-                /* icon =*/ null,
    +-                makeIntent(Intent.ACTION_ANSWER, ShortcutActivity2.class,
    +-                        "key1", "val1", "nest", makeBundle("key", 123)),
    +-                /* weight */ 10);
    +-        assertTrue(mManager.setDynamicShortcuts(list(s2_1)));
    +-        dumpsysOnLogcat();
    +-
    +-        // Pin some.
    +-        setCaller(LAUNCHER_1);
    +-
    +-        mLauncherApps.pinShortcuts(CALLING_PACKAGE_1,
    +-                list("s2"), getCallingUser());
    +-
    +-        dumpsysOnLogcat();
    +-
    +-        // Delete some.
    +-        setCaller(CALLING_PACKAGE_1);
    +-        assertShortcutIds(mManager.getPinnedShortcuts(), "s2");
    +-        mManager.removeDynamicShortcuts(list("s2"));
    +-        assertShortcutIds(mManager.getPinnedShortcuts(), "s2");
    +-
    +-        dumpsysOnLogcat();
    +-
    +-        setCaller(LAUNCHER_1);
    +-        List<ShortcutInfo> list;
    +-
    +-        // Note we don't guarantee the orders.
    +-        list = assertShortcutIds(assertAllHaveTitle(assertAllNotHaveIntents(
    +-                assertAllNotKeyFieldsOnly(
    +-                        mLauncherApps.getShortcutInfo(CALLING_PACKAGE_1,
    +-                                list("s2", "s1", "s3", null), getCallingUser())))),
    +-                "s1", "s2");
    +-        assertEquals("Title 1", findById(list, "s1").getTitle());
    +-        assertEquals("Title 2", findById(list, "s2").getTitle());
    +-
    +-        assertShortcutIds(assertAllHaveTitle(assertAllNotHaveIntents(
    +-                mLauncherApps.getShortcutInfo(CALLING_PACKAGE_1,
    +-                        list("s3"), getCallingUser())))
    +-                /* none */);
    +-
    +-        list = assertShortcutIds(assertAllHaveTitle(assertAllNotHaveIntents(
    +-                mLauncherApps.getShortcutInfo(CALLING_PACKAGE_2,
    +-                        list("s1", "s2", "s3"), getCallingUser()))),
    +-                "s1");
    +-        assertEquals("ABC", findById(list, "s1").getTitle());
    +-    }
    +-
    +-    public void testPinShortcutAndGetPinnedShortcuts() {
    +-        runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
    +-            final ShortcutInfo s1_1 = makeShortcutWithTimestamp("s1", 1000);
    +-            final ShortcutInfo s1_2 = makeShortcutWithTimestamp("s2", 2000);
    +-
    +-            assertTrue(mManager.setDynamicShortcuts(list(s1_1, s1_2)));
    +-        });
    +-
    +-        runWithCaller(CALLING_PACKAGE_2, USER_0, () -> {
    +-            final ShortcutInfo s2_2 = makeShortcutWithTimestamp("s2", 1500);
    +-            final ShortcutInfo s2_3 = makeShortcutWithTimestamp("s3", 3000);
    +-            final ShortcutInfo s2_4 = makeShortcutWithTimestamp("s4", 500);
    +-            assertTrue(mManager.setDynamicShortcuts(list(s2_2, s2_3, s2_4)));
    +-        });
    +-
    +-        runWithCaller(CALLING_PACKAGE_3, USER_0, () -> {
    +-            final ShortcutInfo s3_2 = makeShortcutWithTimestamp("s2", 1000);
    +-            assertTrue(mManager.setDynamicShortcuts(list(s3_2)));
    +-        });
    +-
    +-        // Pin some.
    +-        runWithCaller(LAUNCHER_1, USER_0, () -> {
    +-            mLauncherApps.pinShortcuts(CALLING_PACKAGE_1,
    +-                    list("s2", "s3"), getCallingUser());
    +-
    +-            mLauncherApps.pinShortcuts(CALLING_PACKAGE_2,
    +-                    list("s3", "s4", "s5"), getCallingUser());
    +-
    +-            mLauncherApps.pinShortcuts(CALLING_PACKAGE_3,
    +-                    list("s3"), getCallingUser());  // Note ID doesn't exist
    +-        });
    +-
    +-        // Delete some.
    +-        runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
    +-            assertShortcutIds(mManager.getPinnedShortcuts(), "s2");
    +-            mManager.removeDynamicShortcuts(list("s2"));
    +-            assertShortcutIds(mManager.getPinnedShortcuts(), "s2");
    +-
    +-            assertShortcutIds(mManager.getDynamicShortcuts(), "s1");
    +-        });
    +-
    +-        runWithCaller(CALLING_PACKAGE_2, USER_0, () -> {
    +-            assertShortcutIds(mManager.getPinnedShortcuts(), "s3", "s4");
    +-            mManager.removeDynamicShortcuts(list("s3"));
    +-            assertShortcutIds(mManager.getPinnedShortcuts(), "s3", "s4");
    +-
    +-            assertShortcutIds(mManager.getDynamicShortcuts(), "s2", "s4");
    +-        });
    +-
    +-        runWithCaller(CALLING_PACKAGE_3, USER_0, () -> {
    +-            assertShortcutIds(mManager.getPinnedShortcuts() /* none */);
    +-            mManager.removeDynamicShortcuts(list("s2"));
    +-            assertShortcutIds(mManager.getPinnedShortcuts() /* none */);
    +-
    +-            assertEmpty(mManager.getDynamicShortcuts());
    +-        });
    +-
    +-        // Get pinned shortcuts from launcher
    +-        runWithCaller(LAUNCHER_1, USER_0, () -> {
    +-            // CALLING_PACKAGE_1 deleted s2, but it's pinned, so it still exists.
    +-            assertShortcutIds(assertAllPinned(assertAllNotKeyFieldsOnly(assertAllEnabled(
    +-                    mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_1,
    +-                    /* activity =*/ null, ShortcutQuery.FLAG_GET_PINNED), getCallingUser())))),
    +-                    "s2");
    +-
    +-            assertShortcutIds(assertAllPinned(assertAllNotKeyFieldsOnly(assertAllEnabled(
    +-                    mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_2,
    +-                    /* activity =*/ null, ShortcutQuery.FLAG_GET_PINNED), getCallingUser())))),
    +-                    "s3", "s4");
    +-
    +-            assertShortcutIds(assertAllPinned(assertAllNotKeyFieldsOnly(assertAllEnabled(
    +-                    mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_3,
    +-                    /* activity =*/ null, ShortcutQuery.FLAG_GET_PINNED), getCallingUser()))))
    +-                    /* none */);
    +-        });
    +-    }
    +-
    +-    /**
    +-     * This is similar to the above test, except it used "disable" instead of "remove".  It also
    +-     * does "enable".
    +-     */
    +-    public void testDisableAndEnableShortcuts() {
    +-        runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
    +-            final ShortcutInfo s1_1 = makeShortcutWithTimestamp("s1", 1000);
    +-            final ShortcutInfo s1_2 = makeShortcutWithTimestamp("s2", 2000);
    +-
    +-            assertTrue(mManager.setDynamicShortcuts(list(s1_1, s1_2)));
    +-        });
    +-
    +-        runWithCaller(CALLING_PACKAGE_2, USER_0, () -> {
    +-            final ShortcutInfo s2_2 = makeShortcutWithTimestamp("s2", 1500);
    +-            final ShortcutInfo s2_3 = makeShortcutWithTimestamp("s3", 3000);
    +-            final ShortcutInfo s2_4 = makeShortcutWithTimestamp("s4", 500);
    +-            assertTrue(mManager.setDynamicShortcuts(list(s2_2, s2_3, s2_4)));
    +-        });
    +-
    +-        runWithCaller(CALLING_PACKAGE_3, USER_0, () -> {
    +-            final ShortcutInfo s3_2 = makeShortcutWithTimestamp("s2", 1000);
    +-            assertTrue(mManager.setDynamicShortcuts(list(s3_2)));
    +-        });
    +-
    +-        // Pin some.
    +-        runWithCaller(LAUNCHER_1, USER_0, () -> {
    +-            mLauncherApps.pinShortcuts(CALLING_PACKAGE_1,
    +-                    list("s2", "s3"), getCallingUser());
    +-
    +-            mLauncherApps.pinShortcuts(CALLING_PACKAGE_2,
    +-                    list("s3", "s4", "s5"), getCallingUser());
    +-
    +-            mLauncherApps.pinShortcuts(CALLING_PACKAGE_3,
    +-                    list("s3"), getCallingUser());  // Note ID doesn't exist
    +-        });
    +-
    +-        // Disable some.
    +-        runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
    +-            assertShortcutIds(mManager.getPinnedShortcuts(), "s2");
    +-
    +-            mManager.disableShortcuts(list("s2"));
    +-
    +-            assertShortcutIds(mManager.getPinnedShortcuts(), "s2");
    +-            assertShortcutIds(mManager.getDynamicShortcuts(), "s1");
    +-        });
    +-
    +-        runWithCaller(CALLING_PACKAGE_2, USER_0, () -> {
    +-            assertShortcutIds(mManager.getPinnedShortcuts(), "s3", "s4");
    +-
    +-            // disable should work even if a shortcut is not dynamic, so try calling "remove" first
    +-            // here.
    +-            mManager.removeDynamicShortcuts(list("s3"));
    +-            mManager.disableShortcuts(list("s3"));
    +-
    +-            assertShortcutIds(mManager.getPinnedShortcuts(), "s3", "s4");
    +-            assertShortcutIds(mManager.getDynamicShortcuts(), "s2", "s4");
    +-        });
    +-
    +-        runWithCaller(CALLING_PACKAGE_3, USER_0, () -> {
    +-            assertShortcutIds(mManager.getPinnedShortcuts() /* none */);
    +-
    +-            mManager.disableShortcuts(list("s2"));
    +-
    +-            assertShortcutIds(mManager.getPinnedShortcuts() /* none */);
    +-
    +-            assertEmpty(mManager.getDynamicShortcuts());
    +-            assertEmpty(getCallerShortcuts());
    +-        });
    +-
    +-        // Get pinned shortcuts from launcher
    +-        runWithCaller(LAUNCHER_1, USER_0, () -> {
    +-            // CALLING_PACKAGE_1 deleted s2, but it's pinned, so it still exists, and disabled.
    +-            assertWith(mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_1,
    +-                    /* activity =*/ null, ShortcutQuery.FLAG_GET_PINNED), getCallingUser()))
    +-                    .haveIds("s2")
    +-                    .areAllPinned()
    +-                    .areAllNotWithKeyFieldsOnly()
    +-                    .areAllDisabled();
    +-            assertStartShortcutThrowsException(CALLING_PACKAGE_1, "s2", USER_0,
    +-                    ActivityNotFoundException.class);
    +-
    +-            // Here, s4 is still enabled and launchable, but s3 is disabled.
    +-            assertWith(mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_2,
    +-                    /* activity =*/ null, ShortcutQuery.FLAG_GET_PINNED), getCallingUser()))
    +-                    .haveIds("s3", "s4")
    +-                    .areAllPinned()
    +-                    .areAllNotWithKeyFieldsOnly()
    +-
    +-                    .selectByIds("s3")
    +-                    .areAllDisabled()
    +-
    +-                    .revertToOriginalList()
    +-                    .selectByIds("s4")
    +-                    .areAllEnabled();
    +-
    +-            assertStartShortcutThrowsException(CALLING_PACKAGE_2, "s3", USER_0,
    +-                    ActivityNotFoundException.class);
    +-            assertShortcutLaunchable(CALLING_PACKAGE_2, "s4", USER_0);
    +-
    +-            assertShortcutIds(assertAllPinned(assertAllNotKeyFieldsOnly(assertAllEnabled(
    +-                    mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_3,
    +-                    /* activity =*/ null, ShortcutQuery.FLAG_GET_PINNED), getCallingUser()))))
    +-                    /* none */);
    +-        });
    +-
    +-        runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
    +-            mManager.enableShortcuts(list("s2"));
    +-
    +-            assertShortcutIds(mManager.getPinnedShortcuts(), "s2");
    +-            assertShortcutIds(mManager.getDynamicShortcuts(), "s1");
    +-        });
    +-        runWithCaller(LAUNCHER_1, USER_0, () -> {
    +-            // CALLING_PACKAGE_1 deleted s2, but it's pinned, so it still exists.
    +-            assertShortcutIds(assertAllPinned(assertAllNotKeyFieldsOnly(assertAllEnabled(
    +-                    mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_1,
    +-                    /* activity =*/ null, ShortcutQuery.FLAG_GET_PINNED), getCallingUser())))),
    +-                    "s2");
    +-            assertShortcutLaunchable(CALLING_PACKAGE_1, "s2", USER_0);
    +-        });
    +-    }
    +-
    +-    public void testDisableShortcuts_thenRepublish() {
    +-        runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
    +-            assertTrue(mManager.setDynamicShortcuts(list(
    +-                    makeShortcut("s1"), makeShortcut("s2"), makeShortcut("s3"))));
    +-
    +-            runWithCaller(LAUNCHER_1, USER_0, () -> {
    +-                mLauncherApps.pinShortcuts(
    +-                        CALLING_PACKAGE_1, list("s1", "s2", "s3"), HANDLE_USER_0);
    +-            });
    +-
    +-            mManager.disableShortcuts(list("s1", "s2", "s3"));
    +-
    +-            assertWith(getCallerShortcuts())
    +-                    .haveIds("s1", "s2", "s3")
    +-                    .areAllNotDynamic()
    +-                    .areAllPinned()
    +-                    .areAllDisabled();
    +-
    +-            // Make sure updateShortcuts() will not re-enable them.
    +-            assertTrue(mManager.updateShortcuts(list(
    +-                    makeShortcut("s1"), makeShortcut("s2"), makeShortcut("s3"))));
    +-
    +-            assertWith(getCallerShortcuts())
    +-                    .haveIds("s1", "s2", "s3")
    +-                    .areAllNotDynamic()
    +-                    .areAllPinned()
    +-                    .areAllDisabled();
    +-
    +-            // Re-publish s1 with setDynamicShortcuts.
    +-            mInjectedCurrentTimeMillis += INTERVAL; // reset throttling
    +-
    +-            assertTrue(mManager.setDynamicShortcuts(list(
    +-                    makeShortcut("s1"))));
    +-
    +-            assertWith(getCallerShortcuts())
    +-                    .haveIds("s1", "s2", "s3")
    +-
    +-                    .selectByIds("s1")
    +-                    .areAllDynamic()
    +-                    .areAllPinned()
    +-                    .areAllEnabled()
    +-
    +-                    .revertToOriginalList()
    +-                    .selectByIds("s2", "s3")
    +-                    .areAllNotDynamic()
    +-                    .areAllPinned()
    +-                    .areAllDisabled();
    +-
    +-            // Re-publish s2 with addDynamicShortcuts.
    +-            mInjectedCurrentTimeMillis += INTERVAL; // reset throttling
    +-
    +-            assertTrue(mManager.addDynamicShortcuts(list(
    +-                    makeShortcut("s2"))));
    +-
    +-            assertWith(getCallerShortcuts())
    +-                    .haveIds("s1", "s2", "s3")
    +-
    +-                    .selectByIds("s1", "s2")
    +-                    .areAllDynamic()
    +-                    .areAllPinned()
    +-                    .areAllEnabled()
    +-
    +-                    .revertToOriginalList()
    +-                    .selectByIds("s3")
    +-                    .areAllNotDynamic()
    +-                    .areAllPinned()
    +-                    .areAllDisabled();
    +-        });
    +-    }
    +-
    +-    public void testPinShortcutAndGetPinnedShortcuts_multi() {
    +-        // Create some shortcuts.
    +-        runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
    +-            assertTrue(mManager.setDynamicShortcuts(list(
    +-                    makeShortcut("s1"), makeShortcut("s2"), makeShortcut("s3"))));
    +-        });
    +-
    +-        runWithCaller(CALLING_PACKAGE_2, USER_0, () -> {
    +-            assertTrue(mManager.setDynamicShortcuts(list(
    +-                    makeShortcut("s1"), makeShortcut("s2"), makeShortcut("s3"))));
    +-        });
    +-
    +-        dumpsysOnLogcat();
    +-
    +-        // Pin some.
    +-        runWithCaller(LAUNCHER_1, USER_0, () -> {
    +-            mLauncherApps.pinShortcuts(CALLING_PACKAGE_1,
    +-                    list("s3", "s4"), getCallingUser());
    +-
    +-            mLauncherApps.pinShortcuts(CALLING_PACKAGE_2,
    +-                    list("s1", "s2", "s4"), getCallingUser());
    +-        });
    +-
    +-        dumpsysOnLogcat();
    +-
    +-        // Delete some.
    +-        runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
    +-            assertShortcutIds(mManager.getPinnedShortcuts(), "s3");
    +-            mManager.removeDynamicShortcuts(list("s3"));
    +-            assertShortcutIds(mManager.getPinnedShortcuts(), "s3");
    +-        });
    +-
    +-        dumpsysOnLogcat();
    +-
    +-        runWithCaller(CALLING_PACKAGE_2, USER_0, () -> {
    +-            assertShortcutIds(mManager.getPinnedShortcuts(), "s1", "s2");
    +-            mManager.removeDynamicShortcuts(list("s1"));
    +-            mManager.removeDynamicShortcuts(list("s3"));
    +-            assertShortcutIds(mManager.getPinnedShortcuts(), "s1", "s2");
    +-        });
    +-
    +-        dumpsysOnLogcat();
    +-
    +-        // Get pinned shortcuts from launcher
    +-        runWithCaller(LAUNCHER_1, USER_0, () -> {
    +-            assertShortcutIds(assertAllPinned(assertAllNotKeyFieldsOnly(
    +-                    mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_1,
    +-                    /* activity =*/ null, ShortcutQuery.FLAG_GET_PINNED), getCallingUser()))),
    +-                    "s3");
    +-
    +-            assertShortcutIds(assertAllPinned(assertAllNotKeyFieldsOnly(
    +-                    mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_2,
    +-                    /* activity =*/ null, ShortcutQuery.FLAG_GET_PINNED), getCallingUser()))),
    +-                    "s1", "s2");
    +-
    +-            assertShortcutIds(assertAllDynamicOrPinned(
    +-                    mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_1,
    +-                    /* activity =*/ null, ShortcutQuery.FLAG_GET_PINNED
    +-                                    | ShortcutQuery.FLAG_GET_DYNAMIC), getCallingUser())),
    +-                    "s1", "s2", "s3");
    +-
    +-            assertShortcutIds(assertAllDynamicOrPinned(
    +-                    mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_2,
    +-                    /* activity =*/ null, ShortcutQuery.FLAG_GET_PINNED
    +-                                    | ShortcutQuery.FLAG_GET_DYNAMIC), getCallingUser())),
    +-                    "s1", "s2");
    +-        });
    +-
    +-        dumpsysOnLogcat();
    +-
    +-        runWithCaller(LAUNCHER_2, USER_0, () -> {
    +-            // Launcher2 still has no pinned ones.
    +-            assertShortcutIds(assertAllPinned(assertAllNotKeyFieldsOnly(
    +-                    mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_1,
    +-                    /* activity =*/ null, ShortcutQuery.FLAG_GET_PINNED), getCallingUser())))
    +-                    /* none */);
    +-            assertShortcutIds(assertAllPinned(assertAllNotKeyFieldsOnly(
    +-                    mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_2,
    +-                    /* activity =*/ null, ShortcutQuery.FLAG_GET_PINNED), getCallingUser())))
    +-                    /* none */);
    +-
    +-            assertShortcutIds(assertAllDynamic(
    +-                    mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_1,
    +-                    /* activity =*/ null, ShortcutQuery.FLAG_GET_PINNED
    +-                                    | ShortcutQuery.FLAG_GET_DYNAMIC), getCallingUser())),
    +-                    "s1", "s2");
    +-            assertShortcutIds(assertAllDynamic(
    +-                    mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_2,
    +-                    /* activity =*/ null, ShortcutQuery.FLAG_GET_PINNED
    +-                                    | ShortcutQuery.FLAG_GET_DYNAMIC), getCallingUser())),
    +-                    "s2");
    +-
    +-            // Now pin some.
    +-            mLauncherApps.pinShortcuts(CALLING_PACKAGE_1,
    +-                    list("s1", "s2"), getCallingUser());
    +-
    +-            mLauncherApps.pinShortcuts(CALLING_PACKAGE_2,
    +-                    list("s1", "s2"), getCallingUser());
    +-
    +-            assertShortcutIds(assertAllDynamic(
    +-                    mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_1,
    +-                    /* activity =*/ null, ShortcutQuery.FLAG_GET_PINNED
    +-                                    | ShortcutQuery.FLAG_GET_DYNAMIC), getCallingUser())),
    +-                    "s1", "s2");
    +-
    +-            // S1 was not visible to it, so shouldn't be pinned.
    +-            assertShortcutIds(assertAllDynamic(
    +-                    mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_2,
    +-                    /* activity =*/ null, ShortcutQuery.FLAG_GET_PINNED
    +-                                    | ShortcutQuery.FLAG_GET_DYNAMIC), getCallingUser())),
    +-                    "s2");
    +-        });
    +-
    +-        // Re-initialize and load from the files.
    +-        mService.saveDirtyInfo();
    +-        initService();
    +-
    +-        // Load from file.
    +-        mService.handleUnlockUser(USER_0);
    +-
    +-        // Make sure package info is restored too.
    +-        runWithCaller(LAUNCHER_1, USER_0, () -> {
    +-            assertShortcutIds(assertAllPinned(assertAllNotKeyFieldsOnly(
    +-                    mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_1,
    +-                    /* activity =*/ null, ShortcutQuery.FLAG_GET_PINNED), getCallingUser()))),
    +-                    "s3");
    +-            assertShortcutIds(assertAllPinned(assertAllNotKeyFieldsOnly(
    +-                    mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_2,
    +-                    /* activity =*/ null, ShortcutQuery.FLAG_GET_PINNED), getCallingUser()))),
    +-                    "s1", "s2");
    +-        });
    +-        runWithCaller(LAUNCHER_2, USER_0, () -> {
    +-            assertShortcutIds(assertAllDynamic(
    +-                    mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_1,
    +-                    /* activity =*/ null, ShortcutQuery.FLAG_GET_PINNED
    +-                                    | ShortcutQuery.FLAG_GET_DYNAMIC), getCallingUser())),
    +-                    "s1", "s2");
    +-            assertShortcutIds(assertAllDynamic(
    +-                    mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_2,
    +-                    /* activity =*/ null, ShortcutQuery.FLAG_GET_PINNED
    +-                                    | ShortcutQuery.FLAG_GET_DYNAMIC), getCallingUser())),
    +-                    "s2");
    +-        });
    +-
    +-        // Delete all dynamic.
    +-        runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
    +-            mManager.removeAllDynamicShortcuts();
    +-
    +-            assertEquals(0, mManager.getDynamicShortcuts().size());
    +-            assertShortcutIds(assertAllPinned(mManager.getPinnedShortcuts()), "s1", "s2", "s3");
    +-        });
    +-        runWithCaller(CALLING_PACKAGE_2, USER_0, () -> {
    +-            mManager.removeAllDynamicShortcuts();
    +-
    +-            assertEquals(0, mManager.getDynamicShortcuts().size());
    +-            assertShortcutIds(assertAllPinned(mManager.getPinnedShortcuts()), "s2", "s1");
    +-        });
    +-
    +-        runWithCaller(LAUNCHER_1, USER_0, () -> {
    +-            assertShortcutIds(assertAllPinned(assertAllNotKeyFieldsOnly(
    +-                    mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_1,
    +-                    /* activity =*/ null, ShortcutQuery.FLAG_GET_PINNED), getCallingUser()))),
    +-                    "s3");
    +-
    +-            assertShortcutIds(assertAllPinned(assertAllNotKeyFieldsOnly(
    +-                    mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_2,
    +-                    /* activity =*/ null, ShortcutQuery.FLAG_GET_PINNED), getCallingUser()))),
    +-                    "s1", "s2");
    +-
    +-            // from all packages.
    +-            assertShortcutIds(assertAllPinned(assertAllNotKeyFieldsOnly(
    +-                    mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, null,
    +-                    /* activity =*/ null, ShortcutQuery.FLAG_GET_PINNED), getCallingUser()))),
    +-                    "s1", "s2", "s3");
    +-
    +-            // Update pined.  Note s2 and s3 are actually available, but not visible to this
    +-            // launcher, so still can't be pinned.
    +-            mLauncherApps.pinShortcuts(CALLING_PACKAGE_1, list("s1", "s2", "s3", "s4"),
    +-                    getCallingUser());
    +-
    +-            assertShortcutIds(assertAllPinned(assertAllNotKeyFieldsOnly(
    +-                    mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_1,
    +-                    /* activity =*/ null, ShortcutQuery.FLAG_GET_PINNED), getCallingUser()))),
    +-                    "s3");
    +-        });
    +-        // Re-publish s1.
    +-        runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
    +-            assertTrue(mManager.addDynamicShortcuts(list(makeShortcut("s1"))));
    +-
    +-            assertShortcutIds(assertAllDynamic(mManager.getDynamicShortcuts()), "s1");
    +-            assertShortcutIds(assertAllPinned(mManager.getPinnedShortcuts()), "s1", "s2", "s3");
    +-        });
    +-        runWithCaller(LAUNCHER_1, USER_0, () -> {
    +-            assertShortcutIds(assertAllPinned(assertAllNotKeyFieldsOnly(
    +-                    mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_1,
    +-                    /* activity =*/ null, ShortcutQuery.FLAG_GET_PINNED), getCallingUser()))),
    +-                    "s3");
    +-
    +-            // Now "s1" is visible, so can be pinned.
    +-            mLauncherApps.pinShortcuts(CALLING_PACKAGE_1, list("s1", "s2", "s3", "s4"),
    +-                    getCallingUser());
    +-
    +-            assertShortcutIds(assertAllPinned(assertAllNotKeyFieldsOnly(
    +-                    mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_1,
    +-                    /* activity =*/ null, ShortcutQuery.FLAG_GET_PINNED), getCallingUser()))),
    +-                    "s1", "s3");
    +-        });
    +-
    +-        // Now clear pinned shortcuts.  First, from launcher 1.
    +-        runWithCaller(LAUNCHER_1, USER_0, () -> {
    +-            mLauncherApps.pinShortcuts(CALLING_PACKAGE_1, list(), getCallingUser());
    +-            mLauncherApps.pinShortcuts(CALLING_PACKAGE_2, list(), getCallingUser());
    +-
    +-            assertEquals(0,
    +-                    mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_1,
    +-                    /* activity =*/ null, ShortcutQuery.FLAG_GET_PINNED), getCallingUser()).size());
    +-            assertEquals(0,
    +-                    mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_2,
    +-                    /* activity =*/ null, ShortcutQuery.FLAG_GET_PINNED), getCallingUser()).size());
    +-        });
    +-        runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
    +-            assertShortcutIds(assertAllDynamic(mManager.getDynamicShortcuts()), "s1");
    +-            assertShortcutIds(assertAllPinned(mManager.getPinnedShortcuts()), "s1", "s2");
    +-        });
    +-        runWithCaller(CALLING_PACKAGE_2, USER_0, () -> {
    +-            assertEquals(0, mManager.getDynamicShortcuts().size());
    +-            assertShortcutIds(assertAllPinned(mManager.getPinnedShortcuts()), "s2");
    +-        });
    +-
    +-        // Clear all pins from launcher 2.
    +-        runWithCaller(LAUNCHER_2, USER_0, () -> {
    +-            mLauncherApps.pinShortcuts(CALLING_PACKAGE_1, list(), getCallingUser());
    +-            mLauncherApps.pinShortcuts(CALLING_PACKAGE_2, list(), getCallingUser());
    +-
    +-            assertEquals(0,
    +-                    mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_1,
    +-                    /* activity =*/ null, ShortcutQuery.FLAG_GET_PINNED), getCallingUser()).size());
    +-            assertEquals(0,
    +-                    mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_2,
    +-                    /* activity =*/ null, ShortcutQuery.FLAG_GET_PINNED), getCallingUser()).size());
    +-        });
    +-        runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
    +-            assertShortcutIds(assertAllDynamic(mManager.getDynamicShortcuts()), "s1");
    +-            assertEquals(0, mManager.getPinnedShortcuts().size());
    +-        });
    +-        runWithCaller(CALLING_PACKAGE_2, USER_0, () -> {
    +-            assertEquals(0, mManager.getDynamicShortcuts().size());
    +-            assertEquals(0, mManager.getPinnedShortcuts().size());
    +-        });
    +-    }
    +-
    +-    public void testPinShortcutAndGetPinnedShortcuts_crossProfile_plusLaunch() {
    +-        // Create some shortcuts.
    +-        runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
    +-            assertTrue(mManager.setDynamicShortcuts(list(
    +-                    makeShortcut("s1"), makeShortcut("s2"), makeShortcut("s3"))));
    +-        });
    +-        runWithCaller(CALLING_PACKAGE_2, USER_0, () -> {
    +-            assertTrue(mManager.setDynamicShortcuts(list(
    +-                    makeShortcut("s1"), makeShortcut("s2"), makeShortcut("s3"))));
    +-        });
    +-
    +-        mRunningUsers.put(USER_10, true);
    +-
    +-        runWithCaller(CALLING_PACKAGE_1, USER_10, () -> {
    +-            assertTrue(mManager.setDynamicShortcuts(list(
    +-                    makeShortcut("s1"), makeShortcut("s2"), makeShortcut("s3"),
    +-                    makeShortcut("s4"), makeShortcut("s5"), makeShortcut("s6"))));
    +-        });
    +-
    +-        // Pin some shortcuts and see the result.
    +-
    +-        runWithCaller(LAUNCHER_1, USER_0, () -> {
    +-            mLauncherApps.pinShortcuts(CALLING_PACKAGE_1,
    +-                    list("s1"), HANDLE_USER_0);
    +-
    +-            mLauncherApps.pinShortcuts(CALLING_PACKAGE_2,
    +-                    list("s1", "s2", "s3"), HANDLE_USER_0);
    +-        });
    +-
    +-        runWithCaller(LAUNCHER_1, USER_P0, () -> {
    +-            mLauncherApps.pinShortcuts(CALLING_PACKAGE_1,
    +-                    list("s2"), HANDLE_USER_0);
    +-
    +-            mLauncherApps.pinShortcuts(CALLING_PACKAGE_2,
    +-                    list("s2", "s3"), HANDLE_USER_0);
    +-        });
    +-
    +-        runWithCaller(LAUNCHER_2, USER_P0, () -> {
    +-            mLauncherApps.pinShortcuts(CALLING_PACKAGE_1,
    +-                    list("s3"), HANDLE_USER_0);
    +-
    +-            mLauncherApps.pinShortcuts(CALLING_PACKAGE_2,
    +-                    list("s3"), HANDLE_USER_0);
    +-        });
    +-
    +-        runWithCaller(LAUNCHER_2, USER_10, () -> {
    +-            mLauncherApps.pinShortcuts(CALLING_PACKAGE_1,
    +-                    list("s1", "s2", "s3"), HANDLE_USER_10);
    +-        });
    +-
    +-        // Cross profile pinning.
    +-        final int PIN_AND_DYNAMIC = ShortcutQuery.FLAG_GET_PINNED | ShortcutQuery.FLAG_GET_DYNAMIC;
    +-
    +-        runWithCaller(LAUNCHER_1, USER_0, () -> {
    +-            assertShortcutIds(assertAllPinned(
    +-                    mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_1,
    +-                    /* activity =*/ null, ShortcutQuery.FLAG_GET_PINNED), HANDLE_USER_0)),
    +-                    "s1");
    +-            assertShortcutIds(assertAllDynamic(
    +-                    mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_1,
    +-                    /* activity =*/ null, ShortcutQuery.FLAG_GET_DYNAMIC), HANDLE_USER_0)),
    +-                    "s1", "s2", "s3");
    +-            assertShortcutIds(assertAllDynamicOrPinned(
    +-                    mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_1,
    +-                    /* activity =*/ null, PIN_AND_DYNAMIC), HANDLE_USER_0)),
    +-                    "s1", "s2", "s3");
    +-
    +-            assertShortcutIds(assertAllPinned(
    +-                    mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_2,
    +-                    /* activity =*/ null, ShortcutQuery.FLAG_GET_PINNED), HANDLE_USER_0)),
    +-                    "s1", "s2", "s3");
    +-            assertShortcutIds(assertAllDynamic(
    +-                    mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_2,
    +-                    /* activity =*/ null, ShortcutQuery.FLAG_GET_DYNAMIC), HANDLE_USER_0)),
    +-                    "s1", "s2", "s3");
    +-            assertShortcutIds(assertAllDynamicOrPinned(
    +-                    mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_2,
    +-                    /* activity =*/ null, PIN_AND_DYNAMIC), HANDLE_USER_0)),
    +-                    "s1", "s2", "s3");
    +-
    +-            assertShortcutLaunchable(CALLING_PACKAGE_1, "s1", USER_0);
    +-            assertShortcutLaunchable(CALLING_PACKAGE_1, "s2", USER_0);
    +-            assertShortcutLaunchable(CALLING_PACKAGE_1, "s3", USER_0);
    +-
    +-            assertShortcutLaunchable(CALLING_PACKAGE_2, "s1", USER_0);
    +-            assertShortcutLaunchable(CALLING_PACKAGE_2, "s2", USER_0);
    +-            assertShortcutLaunchable(CALLING_PACKAGE_2, "s3", USER_0);
    +-
    +-            assertStartShortcutThrowsException(CALLING_PACKAGE_1, "s1", USER_10,
    +-                    SecurityException.class);
    +-            assertStartShortcutThrowsException(CALLING_PACKAGE_1, "s2", USER_10,
    +-                    SecurityException.class);
    +-            assertStartShortcutThrowsException(CALLING_PACKAGE_1, "s3", USER_10,
    +-                    SecurityException.class);
    +-            assertStartShortcutThrowsException(CALLING_PACKAGE_1, "s4", USER_10,
    +-                    SecurityException.class);
    +-            assertStartShortcutThrowsException(CALLING_PACKAGE_1, "s5", USER_10,
    +-                    SecurityException.class);
    +-            assertStartShortcutThrowsException(CALLING_PACKAGE_1, "s6", USER_10,
    +-                    SecurityException.class);
    +-        });
    +-        runWithCaller(LAUNCHER_1, USER_P0, () -> {
    +-            assertShortcutIds(assertAllPinned(
    +-                    mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_1,
    +-                    /* activity =*/ null, ShortcutQuery.FLAG_GET_PINNED), HANDLE_USER_0)),
    +-                    "s2");
    +-            assertShortcutIds(assertAllDynamic(
    +-                    mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_1,
    +-                    /* activity =*/ null, ShortcutQuery.FLAG_GET_DYNAMIC), HANDLE_USER_0)),
    +-                    "s1", "s2", "s3");
    +-            assertShortcutIds(assertAllDynamicOrPinned(
    +-                    mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_1,
    +-                    /* activity =*/ null, PIN_AND_DYNAMIC), HANDLE_USER_0)),
    +-                    "s1", "s2", "s3");
    +-
    +-            assertShortcutIds(assertAllPinned(
    +-                    mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_2,
    +-                    /* activity =*/ null, ShortcutQuery.FLAG_GET_PINNED), HANDLE_USER_0)),
    +-                    "s2", "s3");
    +-            assertShortcutIds(assertAllDynamic(
    +-                    mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_2,
    +-                    /* activity =*/ null, ShortcutQuery.FLAG_GET_DYNAMIC), HANDLE_USER_0)),
    +-                    "s1", "s2", "s3");
    +-            assertShortcutIds(assertAllDynamicOrPinned(
    +-                    mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_2,
    +-                    /* activity =*/ null, PIN_AND_DYNAMIC), HANDLE_USER_0)),
    +-                    "s1", "s2", "s3");
    +-
    +-            assertShortcutLaunchable(CALLING_PACKAGE_1, "s1", USER_0);
    +-            assertShortcutLaunchable(CALLING_PACKAGE_1, "s2", USER_0);
    +-            assertShortcutLaunchable(CALLING_PACKAGE_1, "s3", USER_0);
    +-
    +-            assertShortcutLaunchable(CALLING_PACKAGE_2, "s1", USER_0);
    +-            assertShortcutLaunchable(CALLING_PACKAGE_2, "s2", USER_0);
    +-            assertShortcutLaunchable(CALLING_PACKAGE_2, "s3", USER_0);
    +-
    +-            assertStartShortcutThrowsException(CALLING_PACKAGE_1, "s1", USER_10,
    +-                    SecurityException.class);
    +-            assertStartShortcutThrowsException(CALLING_PACKAGE_1, "s2", USER_10,
    +-                    SecurityException.class);
    +-            assertStartShortcutThrowsException(CALLING_PACKAGE_1, "s3", USER_10,
    +-                    SecurityException.class);
    +-            assertStartShortcutThrowsException(CALLING_PACKAGE_1, "s4", USER_10,
    +-                    SecurityException.class);
    +-            assertStartShortcutThrowsException(CALLING_PACKAGE_1, "s5", USER_10,
    +-                    SecurityException.class);
    +-            assertStartShortcutThrowsException(CALLING_PACKAGE_1, "s6", USER_10,
    +-                    SecurityException.class);
    +-        });
    +-        runWithCaller(LAUNCHER_2, USER_P0, () -> {
    +-            assertShortcutIds(assertAllPinned(
    +-                    mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_1,
    +-                    /* activity =*/ null, ShortcutQuery.FLAG_GET_PINNED), HANDLE_USER_0)),
    +-                    "s3");
    +-            assertShortcutIds(assertAllDynamic(
    +-                    mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_1,
    +-                    /* activity =*/ null, ShortcutQuery.FLAG_GET_DYNAMIC), HANDLE_USER_0)),
    +-                    "s1", "s2", "s3");
    +-            assertShortcutIds(assertAllDynamicOrPinned(
    +-                    mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_1,
    +-                    /* activity =*/ null, PIN_AND_DYNAMIC), HANDLE_USER_0)),
    +-                    "s1", "s2", "s3");
    +-
    +-            assertShortcutIds(assertAllPinned(
    +-                    mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_2,
    +-                    /* activity =*/ null, ShortcutQuery.FLAG_GET_PINNED), HANDLE_USER_0)),
    +-                    "s3");
    +-            assertShortcutIds(assertAllDynamic(
    +-                    mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_2,
    +-                    /* activity =*/ null, ShortcutQuery.FLAG_GET_DYNAMIC), HANDLE_USER_0)),
    +-                    "s1", "s2", "s3");
    +-            assertShortcutIds(assertAllDynamicOrPinned(
    +-                    mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_2,
    +-                    /* activity =*/ null, PIN_AND_DYNAMIC), HANDLE_USER_0)),
    +-                    "s1", "s2", "s3");
    +-
    +-            assertShortcutLaunchable(CALLING_PACKAGE_1, "s1", USER_0);
    +-            assertShortcutLaunchable(CALLING_PACKAGE_1, "s2", USER_0);
    +-            assertShortcutLaunchable(CALLING_PACKAGE_1, "s3", USER_0);
    +-
    +-            assertShortcutLaunchable(CALLING_PACKAGE_2, "s1", USER_0);
    +-            assertShortcutLaunchable(CALLING_PACKAGE_2, "s2", USER_0);
    +-            assertShortcutLaunchable(CALLING_PACKAGE_2, "s3", USER_0);
    +-
    +-            assertStartShortcutThrowsException(CALLING_PACKAGE_1, "s1", USER_10,
    +-                    SecurityException.class);
    +-            assertStartShortcutThrowsException(CALLING_PACKAGE_1, "s2", USER_10,
    +-                    SecurityException.class);
    +-            assertStartShortcutThrowsException(CALLING_PACKAGE_1, "s3", USER_10,
    +-                    SecurityException.class);
    +-            assertStartShortcutThrowsException(CALLING_PACKAGE_1, "s4", USER_10,
    +-                    SecurityException.class);
    +-            assertStartShortcutThrowsException(CALLING_PACKAGE_1, "s5", USER_10,
    +-                    SecurityException.class);
    +-            assertStartShortcutThrowsException(CALLING_PACKAGE_1, "s6", USER_10,
    +-                    SecurityException.class);
    +-        });
    +-        runWithCaller(LAUNCHER_2, USER_10, () -> {
    +-            assertShortcutIds(assertAllPinned(
    +-                    mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_1,
    +-                    /* activity =*/ null, ShortcutQuery.FLAG_GET_PINNED), HANDLE_USER_10)),
    +-                    "s1", "s2", "s3");
    +-            assertShortcutIds(assertAllDynamic(
    +-                    mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_1,
    +-                    /* activity =*/ null, ShortcutQuery.FLAG_GET_DYNAMIC), HANDLE_USER_10)),
    +-                    "s1", "s2", "s3", "s4", "s5", "s6");
    +-            assertShortcutIds(assertAllDynamicOrPinned(
    +-                    mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_1,
    +-                    /* activity =*/ null, PIN_AND_DYNAMIC), HANDLE_USER_10)),
    +-                    "s1", "s2", "s3", "s4", "s5", "s6");
    +-        });
    +-
    +-        // Remove some dynamic shortcuts.
    +-
    +-        runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
    +-            assertTrue(mManager.setDynamicShortcuts(list(
    +-                    makeShortcut("s1"))));
    +-        });
    +-        runWithCaller(CALLING_PACKAGE_2, USER_0, () -> {
    +-            assertTrue(mManager.setDynamicShortcuts(list(
    +-                    makeShortcut("s1"))));
    +-        });
    +-        runWithCaller(CALLING_PACKAGE_1, USER_10, () -> {
    +-            assertTrue(mManager.setDynamicShortcuts(list(
    +-                    makeShortcut("s1"))));
    +-        });
    +-
    +-        runWithCaller(LAUNCHER_1, USER_0, () -> {
    +-            assertShortcutIds(assertAllPinned(
    +-                    mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_1,
    +-                    /* activity =*/ null, ShortcutQuery.FLAG_GET_PINNED), HANDLE_USER_0)),
    +-                    "s1");
    +-            assertShortcutIds(assertAllDynamic(
    +-                    mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_1,
    +-                    /* activity =*/ null, ShortcutQuery.FLAG_GET_DYNAMIC), HANDLE_USER_0)),
    +-                    "s1");
    +-            assertShortcutIds(assertAllDynamicOrPinned(
    +-                    mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_1,
    +-                    /* activity =*/ null, PIN_AND_DYNAMIC), HANDLE_USER_0)),
    +-                    "s1");
    +-
    +-            assertShortcutIds(assertAllPinned(
    +-                    mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_2,
    +-                    /* activity =*/ null, ShortcutQuery.FLAG_GET_PINNED), HANDLE_USER_0)),
    +-                    "s1", "s2", "s3");
    +-            assertShortcutIds(assertAllDynamic(
    +-                    mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_2,
    +-                    /* activity =*/ null, ShortcutQuery.FLAG_GET_DYNAMIC), HANDLE_USER_0)),
    +-                    "s1");
    +-            assertShortcutIds(assertAllDynamicOrPinned(
    +-                    mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_2,
    +-                    /* activity =*/ null, PIN_AND_DYNAMIC), HANDLE_USER_0)),
    +-                    "s1", "s2", "s3");
    +-
    +-            assertShortcutLaunchable(CALLING_PACKAGE_1, "s1", USER_0);
    +-            assertStartShortcutThrowsException(CALLING_PACKAGE_1, "s2", USER_0,
    +-                    ActivityNotFoundException.class);
    +-            assertStartShortcutThrowsException(CALLING_PACKAGE_1, "s3", USER_0,
    +-                    ActivityNotFoundException.class);
    +-
    +-            assertShortcutLaunchable(CALLING_PACKAGE_2, "s1", USER_0);
    +-            assertShortcutLaunchable(CALLING_PACKAGE_2, "s2", USER_0);
    +-            assertShortcutLaunchable(CALLING_PACKAGE_2, "s3", USER_0);
    +-
    +-            assertStartShortcutThrowsException(CALLING_PACKAGE_1, "s1", USER_10,
    +-                    SecurityException.class);
    +-            assertStartShortcutThrowsException(CALLING_PACKAGE_1, "s2", USER_10,
    +-                    SecurityException.class);
    +-            assertStartShortcutThrowsException(CALLING_PACKAGE_1, "s3", USER_10,
    +-                    SecurityException.class);
    +-            assertStartShortcutThrowsException(CALLING_PACKAGE_1, "s4", USER_10,
    +-                    SecurityException.class);
    +-            assertStartShortcutThrowsException(CALLING_PACKAGE_1, "s5", USER_10,
    +-                    SecurityException.class);
    +-            assertStartShortcutThrowsException(CALLING_PACKAGE_1, "s6", USER_10,
    +-                    SecurityException.class);
    +-        });
    +-        runWithCaller(LAUNCHER_1, USER_P0, () -> {
    +-            assertShortcutIds(assertAllPinned(
    +-                    mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_1,
    +-                    /* activity =*/ null, ShortcutQuery.FLAG_GET_PINNED), HANDLE_USER_0)),
    +-                    "s2");
    +-            assertShortcutIds(assertAllDynamic(
    +-                    mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_1,
    +-                    /* activity =*/ null, ShortcutQuery.FLAG_GET_DYNAMIC), HANDLE_USER_0)),
    +-                    "s1");
    +-            assertShortcutIds(assertAllDynamicOrPinned(
    +-                    mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_1,
    +-                    /* activity =*/ null, PIN_AND_DYNAMIC), HANDLE_USER_0)),
    +-                    "s1", "s2");
    +-
    +-            assertShortcutIds(assertAllPinned(
    +-                    mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_2,
    +-                    /* activity =*/ null, ShortcutQuery.FLAG_GET_PINNED), HANDLE_USER_0)),
    +-                    "s2", "s3");
    +-            assertShortcutIds(assertAllDynamic(
    +-                    mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_2,
    +-                    /* activity =*/ null, ShortcutQuery.FLAG_GET_DYNAMIC), HANDLE_USER_0)),
    +-                    "s1");
    +-            assertShortcutIds(assertAllDynamicOrPinned(
    +-                    mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_2,
    +-                    /* activity =*/ null, PIN_AND_DYNAMIC), HANDLE_USER_0)),
    +-                    "s1", "s2", "s3");
    +-
    +-            assertShortcutLaunchable(CALLING_PACKAGE_1, "s1", USER_0);
    +-            assertShortcutLaunchable(CALLING_PACKAGE_1, "s2", USER_0);
    +-            assertStartShortcutThrowsException(CALLING_PACKAGE_1, "s3", USER_0,
    +-                    ActivityNotFoundException.class);
    +-
    +-            assertShortcutLaunchable(CALLING_PACKAGE_2, "s1", USER_0);
    +-            assertShortcutLaunchable(CALLING_PACKAGE_2, "s2", USER_0);
    +-            assertShortcutLaunchable(CALLING_PACKAGE_2, "s3", USER_0);
    +-
    +-            assertStartShortcutThrowsException(CALLING_PACKAGE_1, "s1", USER_10,
    +-                    SecurityException.class);
    +-            assertStartShortcutThrowsException(CALLING_PACKAGE_1, "s2", USER_10,
    +-                    SecurityException.class);
    +-            assertStartShortcutThrowsException(CALLING_PACKAGE_1, "s3", USER_10,
    +-                    SecurityException.class);
    +-            assertStartShortcutThrowsException(CALLING_PACKAGE_1, "s4", USER_10,
    +-                    SecurityException.class);
    +-            assertStartShortcutThrowsException(CALLING_PACKAGE_1, "s5", USER_10,
    +-                    SecurityException.class);
    +-            assertStartShortcutThrowsException(CALLING_PACKAGE_1, "s6", USER_10,
    +-                    SecurityException.class);
    +-        });
    +-        runWithCaller(LAUNCHER_2, USER_P0, () -> {
    +-            assertShortcutIds(assertAllPinned(
    +-                    mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_1,
    +-                    /* activity =*/ null, ShortcutQuery.FLAG_GET_PINNED), HANDLE_USER_0)),
    +-                    "s3");
    +-            assertShortcutIds(assertAllDynamic(
    +-                    mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_1,
    +-                    /* activity =*/ null, ShortcutQuery.FLAG_GET_DYNAMIC), HANDLE_USER_0)),
    +-                    "s1");
    +-            assertShortcutIds(assertAllDynamicOrPinned(
    +-                    mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_1,
    +-                    /* activity =*/ null, PIN_AND_DYNAMIC), HANDLE_USER_0)),
    +-                    "s1", "s3");
    +-
    +-            assertShortcutIds(assertAllPinned(
    +-                    mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_2,
    +-                    /* activity =*/ null, ShortcutQuery.FLAG_GET_PINNED), HANDLE_USER_0)),
    +-                    "s3");
    +-            assertShortcutIds(assertAllDynamic(
    +-                    mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_2,
    +-                    /* activity =*/ null, ShortcutQuery.FLAG_GET_DYNAMIC), HANDLE_USER_0)),
    +-                    "s1");
    +-            assertShortcutIds(assertAllDynamicOrPinned(
    +-                    mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_2,
    +-                    /* activity =*/ null, PIN_AND_DYNAMIC), HANDLE_USER_0)),
    +-                    "s1", "s3");
    +-
    +-            assertShortcutLaunchable(CALLING_PACKAGE_1, "s1", USER_0);
    +-            assertStartShortcutThrowsException(CALLING_PACKAGE_1, "s2", USER_0,
    +-                    ActivityNotFoundException.class);
    +-            assertShortcutLaunchable(CALLING_PACKAGE_1, "s3", USER_0);
    +-
    +-            assertShortcutLaunchable(CALLING_PACKAGE_2, "s1", USER_0);
    +-            assertStartShortcutThrowsException(CALLING_PACKAGE_2, "s2", USER_0,
    +-                    ActivityNotFoundException.class);
    +-            assertShortcutLaunchable(CALLING_PACKAGE_2, "s3", USER_0);
    +-
    +-            assertStartShortcutThrowsException(CALLING_PACKAGE_1, "s1", USER_10,
    +-                    SecurityException.class);
    +-            assertStartShortcutThrowsException(CALLING_PACKAGE_1, "s2", USER_10,
    +-                    SecurityException.class);
    +-            assertStartShortcutThrowsException(CALLING_PACKAGE_1, "s3", USER_10,
    +-                    SecurityException.class);
    +-            assertStartShortcutThrowsException(CALLING_PACKAGE_1, "s4", USER_10,
    +-                    SecurityException.class);
    +-            assertStartShortcutThrowsException(CALLING_PACKAGE_1, "s5", USER_10,
    +-                    SecurityException.class);
    +-            assertStartShortcutThrowsException(CALLING_PACKAGE_1, "s6", USER_10,
    +-                    SecurityException.class);
    +-        });
    +-        runWithCaller(LAUNCHER_2, USER_10, () -> {
    +-            assertShortcutIds(assertAllPinned(
    +-                    mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_1,
    +-                    /* activity =*/ null, ShortcutQuery.FLAG_GET_PINNED), HANDLE_USER_10)),
    +-                    "s1", "s2", "s3");
    +-            assertShortcutIds(assertAllDynamic(
    +-                    mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_1,
    +-                    /* activity =*/ null, ShortcutQuery.FLAG_GET_DYNAMIC), HANDLE_USER_10)),
    +-                    "s1");
    +-            assertShortcutIds(assertAllDynamicOrPinned(
    +-                    mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_1,
    +-                    /* activity =*/ null, PIN_AND_DYNAMIC), HANDLE_USER_10)),
    +-                    "s1", "s2", "s3");
    +-
    +-            assertStartShortcutThrowsException(CALLING_PACKAGE_1, "s1", USER_0,
    +-                    SecurityException.class);
    +-            assertStartShortcutThrowsException(CALLING_PACKAGE_1, "s2", USER_0,
    +-                    SecurityException.class);
    +-            assertStartShortcutThrowsException(CALLING_PACKAGE_1, "s3", USER_0,
    +-                    SecurityException.class);
    +-
    +-            assertStartShortcutThrowsException(CALLING_PACKAGE_2, "s1", USER_0,
    +-                    SecurityException.class);
    +-            assertStartShortcutThrowsException(CALLING_PACKAGE_2, "s2", USER_0,
    +-                    SecurityException.class);
    +-            assertStartShortcutThrowsException(CALLING_PACKAGE_2, "s3", USER_0,
    +-                    SecurityException.class);
    +-
    +-            assertShortcutLaunchable(CALLING_PACKAGE_1, "s1", USER_10);
    +-            assertShortcutLaunchable(CALLING_PACKAGE_1, "s2", USER_10);
    +-            assertShortcutLaunchable(CALLING_PACKAGE_1, "s3", USER_10);
    +-            assertStartShortcutThrowsException(CALLING_PACKAGE_1, "s4", USER_10,
    +-                    ActivityNotFoundException.class);
    +-            assertStartShortcutThrowsException(CALLING_PACKAGE_1, "s5", USER_10,
    +-                    ActivityNotFoundException.class);
    +-            assertStartShortcutThrowsException(CALLING_PACKAGE_1, "s6", USER_10,
    +-                    ActivityNotFoundException.class);
    +-        });
    +-
    +-        // Save & load and make sure we still have the same information.
    +-        mService.saveDirtyInfo();
    +-        initService();
    +-        mService.handleUnlockUser(USER_0);
    +-
    +-        runWithCaller(LAUNCHER_1, USER_0, () -> {
    +-            assertShortcutIds(assertAllPinned(
    +-                    mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_1,
    +-                    /* activity =*/ null, ShortcutQuery.FLAG_GET_PINNED), HANDLE_USER_0)),
    +-                    "s1");
    +-            assertShortcutIds(assertAllDynamic(
    +-                    mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_1,
    +-                    /* activity =*/ null, ShortcutQuery.FLAG_GET_DYNAMIC), HANDLE_USER_0)),
    +-                    "s1");
    +-            assertShortcutIds(assertAllDynamicOrPinned(
    +-                    mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_1,
    +-                    /* activity =*/ null, PIN_AND_DYNAMIC), HANDLE_USER_0)),
    +-                    "s1");
    +-
    +-            assertShortcutIds(assertAllPinned(
    +-                    mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_2,
    +-                    /* activity =*/ null, ShortcutQuery.FLAG_GET_PINNED), HANDLE_USER_0)),
    +-                    "s1", "s2", "s3");
    +-            assertShortcutIds(assertAllDynamic(
    +-                    mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_2,
    +-                    /* activity =*/ null, ShortcutQuery.FLAG_GET_DYNAMIC), HANDLE_USER_0)),
    +-                    "s1");
    +-            assertShortcutIds(assertAllDynamicOrPinned(
    +-                    mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_2,
    +-                    /* activity =*/ null, PIN_AND_DYNAMIC), HANDLE_USER_0)),
    +-                    "s1", "s2", "s3");
    +-
    +-            assertShortcutLaunchable(CALLING_PACKAGE_1, "s1", USER_0);
    +-            assertStartShortcutThrowsException(CALLING_PACKAGE_1, "s2", USER_0,
    +-                    ActivityNotFoundException.class);
    +-            assertStartShortcutThrowsException(CALLING_PACKAGE_1, "s3", USER_0,
    +-                    ActivityNotFoundException.class);
    +-
    +-            assertShortcutLaunchable(CALLING_PACKAGE_2, "s1", USER_0);
    +-            assertShortcutLaunchable(CALLING_PACKAGE_2, "s2", USER_0);
    +-            assertShortcutLaunchable(CALLING_PACKAGE_2, "s3", USER_0);
    +-
    +-            assertStartShortcutThrowsException(CALLING_PACKAGE_1, "s1", USER_10,
    +-                    SecurityException.class);
    +-            assertStartShortcutThrowsException(CALLING_PACKAGE_1, "s2", USER_10,
    +-                    SecurityException.class);
    +-            assertStartShortcutThrowsException(CALLING_PACKAGE_1, "s3", USER_10,
    +-                    SecurityException.class);
    +-            assertStartShortcutThrowsException(CALLING_PACKAGE_1, "s4", USER_10,
    +-                    SecurityException.class);
    +-            assertStartShortcutThrowsException(CALLING_PACKAGE_1, "s5", USER_10,
    +-                    SecurityException.class);
    +-            assertStartShortcutThrowsException(CALLING_PACKAGE_1, "s6", USER_10,
    +-                    SecurityException.class);
    +-        });
    +-        runWithCaller(LAUNCHER_1, USER_P0, () -> {
    +-            assertShortcutIds(assertAllPinned(
    +-                    mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_1,
    +-                    /* activity =*/ null, ShortcutQuery.FLAG_GET_PINNED), HANDLE_USER_0)),
    +-                    "s2");
    +-            assertShortcutIds(assertAllDynamic(
    +-                    mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_1,
    +-                    /* activity =*/ null, ShortcutQuery.FLAG_GET_DYNAMIC), HANDLE_USER_0)),
    +-                    "s1");
    +-            assertShortcutIds(assertAllDynamicOrPinned(
    +-                    mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_1,
    +-                    /* activity =*/ null, PIN_AND_DYNAMIC), HANDLE_USER_0)),
    +-                    "s1", "s2");
    +-
    +-            assertShortcutIds(assertAllPinned(
    +-                    mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_2,
    +-                    /* activity =*/ null, ShortcutQuery.FLAG_GET_PINNED), HANDLE_USER_0)),
    +-                    "s2", "s3");
    +-            assertShortcutIds(assertAllDynamic(
    +-                    mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_2,
    +-                    /* activity =*/ null, ShortcutQuery.FLAG_GET_DYNAMIC), HANDLE_USER_0)),
    +-                    "s1");
    +-            assertShortcutIds(assertAllDynamicOrPinned(
    +-                    mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_2,
    +-                    /* activity =*/ null, PIN_AND_DYNAMIC), HANDLE_USER_0)),
    +-                    "s1", "s2", "s3");
    +-
    +-            assertShortcutLaunchable(CALLING_PACKAGE_1, "s1", USER_0);
    +-            assertShortcutLaunchable(CALLING_PACKAGE_1, "s2", USER_0);
    +-            assertStartShortcutThrowsException(CALLING_PACKAGE_1, "s3", USER_0,
    +-                    ActivityNotFoundException.class);
    +-
    +-            assertShortcutLaunchable(CALLING_PACKAGE_2, "s1", USER_0);
    +-            assertShortcutLaunchable(CALLING_PACKAGE_2, "s2", USER_0);
    +-            assertShortcutLaunchable(CALLING_PACKAGE_2, "s3", USER_0);
    +-
    +-            assertStartShortcutThrowsException(CALLING_PACKAGE_1, "s1", USER_10,
    +-                    SecurityException.class);
    +-            assertStartShortcutThrowsException(CALLING_PACKAGE_1, "s2", USER_10,
    +-                    SecurityException.class);
    +-            assertStartShortcutThrowsException(CALLING_PACKAGE_1, "s3", USER_10,
    +-                    SecurityException.class);
    +-            assertStartShortcutThrowsException(CALLING_PACKAGE_1, "s4", USER_10,
    +-                    SecurityException.class);
    +-            assertStartShortcutThrowsException(CALLING_PACKAGE_1, "s5", USER_10,
    +-                    SecurityException.class);
    +-            assertStartShortcutThrowsException(CALLING_PACKAGE_1, "s6", USER_10,
    +-                    SecurityException.class);
    +-        });
    +-        runWithCaller(LAUNCHER_2, USER_P0, () -> {
    +-            assertShortcutIds(assertAllPinned(
    +-                    mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_1,
    +-                    /* activity =*/ null, ShortcutQuery.FLAG_GET_PINNED), HANDLE_USER_0)),
    +-                    "s3");
    +-            assertShortcutIds(assertAllDynamic(
    +-                    mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_1,
    +-                    /* activity =*/ null, ShortcutQuery.FLAG_GET_DYNAMIC), HANDLE_USER_0)),
    +-                    "s1");
    +-            assertShortcutIds(assertAllDynamicOrPinned(
    +-                    mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_1,
    +-                    /* activity =*/ null, PIN_AND_DYNAMIC), HANDLE_USER_0)),
    +-                    "s1", "s3");
    +-
    +-            assertShortcutIds(assertAllPinned(
    +-                    mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_2,
    +-                    /* activity =*/ null, ShortcutQuery.FLAG_GET_PINNED), HANDLE_USER_0)),
    +-                    "s3");
    +-            assertShortcutIds(assertAllDynamic(
    +-                    mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_2,
    +-                    /* activity =*/ null, ShortcutQuery.FLAG_GET_DYNAMIC), HANDLE_USER_0)),
    +-                    "s1");
    +-            assertShortcutIds(assertAllDynamicOrPinned(
    +-                    mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_2,
    +-                    /* activity =*/ null, PIN_AND_DYNAMIC), HANDLE_USER_0)),
    +-                    "s1", "s3");
    +-
    +-            assertShortcutLaunchable(CALLING_PACKAGE_1, "s1", USER_0);
    +-            assertStartShortcutThrowsException(CALLING_PACKAGE_1, "s2", USER_0,
    +-                    ActivityNotFoundException.class);
    +-            assertShortcutLaunchable(CALLING_PACKAGE_1, "s3", USER_0);
    +-
    +-            assertShortcutLaunchable(CALLING_PACKAGE_2, "s1", USER_0);
    +-            assertStartShortcutThrowsException(CALLING_PACKAGE_2, "s2", USER_0,
    +-                    ActivityNotFoundException.class);
    +-            assertShortcutLaunchable(CALLING_PACKAGE_2, "s3", USER_0);
    +-
    +-            assertStartShortcutThrowsException(CALLING_PACKAGE_1, "s1", USER_10,
    +-                    SecurityException.class);
    +-            assertStartShortcutThrowsException(CALLING_PACKAGE_1, "s2", USER_10,
    +-                    SecurityException.class);
    +-            assertStartShortcutThrowsException(CALLING_PACKAGE_1, "s3", USER_10,
    +-                    SecurityException.class);
    +-            assertStartShortcutThrowsException(CALLING_PACKAGE_1, "s4", USER_10,
    +-                    SecurityException.class);
    +-            assertStartShortcutThrowsException(CALLING_PACKAGE_1, "s5", USER_10,
    +-                    SecurityException.class);
    +-            assertStartShortcutThrowsException(CALLING_PACKAGE_1, "s6", USER_10,
    +-                    SecurityException.class);
    +-        });
    +-    }
    +-
    +-    public void testStartShortcut() {
    +-        // Create some shortcuts.
    +-        runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
    +-            final ShortcutInfo s1_1 = makeShortcut(
    +-                    "s1",
    +-                    "Title 1",
    +-                    makeComponent(ShortcutActivity.class),
    +-                    /* icon =*/ null,
    +-                    new Intent[] {makeIntent(Intent.ACTION_ASSIST, ShortcutActivity2.class,
    +-                            "key1", "val1", "nest", makeBundle("key", 123))
    +-                            .setFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK),
    +-                    new Intent("act2").setFlags(Intent.FLAG_ACTIVITY_NO_ANIMATION)},
    +-                    /* rank */ 10);
    +-
    +-            final ShortcutInfo s1_2 = makeShortcut(
    +-                    "s2",
    +-                    "Title 2",
    +-            /* activity */ null,
    +-            /* icon =*/ null,
    +-                    makeIntent(Intent.ACTION_ASSIST, ShortcutActivity3.class),
    +-            /* rank */ 12);
    +-
    +-            final ShortcutInfo s1_3 = makeShortcut("s3");
    +-
    +-            assertTrue(mManager.setDynamicShortcuts(list(s1_1, s1_2, s1_3)));
    +-        });
    +-
    +-        runWithCaller(CALLING_PACKAGE_2, USER_0, () -> {
    +-            final ShortcutInfo s2_1 = makeShortcut(
    +-                    "s1",
    +-                    "ABC",
    +-                    makeComponent(ShortcutActivity.class),
    +-                    /* icon =*/ null,
    +-                    makeIntent(Intent.ACTION_ANSWER, ShortcutActivity.class,
    +-                            "key1", "val1", "nest", makeBundle("key", 123)),
    +-                    /* weight */ 10);
    +-            assertTrue(mManager.setDynamicShortcuts(list(s2_1)));
    +-        });
    +-
    +-        // Pin some.
    +-        runWithCaller(LAUNCHER_1, USER_0, () -> {
    +-            mLauncherApps.pinShortcuts(CALLING_PACKAGE_1,
    +-                    list("s1", "s2"), getCallingUser());
    +-
    +-            mLauncherApps.pinShortcuts(CALLING_PACKAGE_2,
    +-                    list("s1"), getCallingUser());
    +-        });
    +-
    +-        // Just to make it complicated, delete some.
    +-        runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
    +-            mManager.removeDynamicShortcuts(list("s2"));
    +-        });
    +-
    +-        runWithCaller(LAUNCHER_1, USER_0, () -> {
    +-            final Intent[] intents = launchShortcutAndGetIntents(CALLING_PACKAGE_1, "s1", USER_0);
    +-            assertEquals(ShortcutActivity2.class.getName(),
    +-                    intents[0].getComponent().getClassName());
    +-            assertEquals(Intent.ACTION_ASSIST,
    +-                    intents[0].getAction());
    +-            assertEquals(Intent.FLAG_ACTIVITY_CLEAR_TASK | Intent.FLAG_ACTIVITY_NEW_TASK,
    +-                    intents[0].getFlags());
    +-
    +-            assertEquals("act2",
    +-                    intents[1].getAction());
    +-            assertEquals(Intent.FLAG_ACTIVITY_NO_ANIMATION,
    +-                    intents[1].getFlags());
    +-
    +-            assertEquals(
    +-                    ShortcutActivity3.class.getName(),
    +-                    launchShortcutAndGetIntent(CALLING_PACKAGE_1, "s2", USER_0)
    +-                            .getComponent().getClassName());
    +-            assertEquals(
    +-                    ShortcutActivity.class.getName(),
    +-                    launchShortcutAndGetIntent(CALLING_PACKAGE_2, "s1", USER_0)
    +-                            .getComponent().getClassName());
    +-
    +-            assertShortcutLaunchable(CALLING_PACKAGE_1, "s3", USER_0);
    +-
    +-            assertShortcutNotLaunched("no-such-package", "s2", USER_0);
    +-            assertShortcutNotLaunched(CALLING_PACKAGE_1, "xxxx", USER_0);
    +-        });
    +-
    +-        // LAUNCHER_1 is no longer the default launcher
    +-        setDefaultLauncherChecker((pkg, userId) -> false);
    +-
    +-        runWithCaller(LAUNCHER_1, USER_0, () -> {
    +-            // Not the default launcher, but pinned shortcuts are still lauchable.
    +-            final Intent[] intents = launchShortcutAndGetIntents(CALLING_PACKAGE_1, "s1", USER_0);
    +-            assertEquals(ShortcutActivity2.class.getName(),
    +-                    intents[0].getComponent().getClassName());
    +-            assertEquals(Intent.ACTION_ASSIST,
    +-                    intents[0].getAction());
    +-            assertEquals(Intent.FLAG_ACTIVITY_CLEAR_TASK | Intent.FLAG_ACTIVITY_NEW_TASK,
    +-                    intents[0].getFlags());
    +-
    +-            assertEquals("act2",
    +-                    intents[1].getAction());
    +-            assertEquals(Intent.FLAG_ACTIVITY_NO_ANIMATION,
    +-                    intents[1].getFlags());
    +-            assertEquals(
    +-                    ShortcutActivity3.class.getName(),
    +-                    launchShortcutAndGetIntent(CALLING_PACKAGE_1, "s2", USER_0)
    +-                            .getComponent().getClassName());
    +-            assertEquals(
    +-                    ShortcutActivity.class.getName(),
    +-                    launchShortcutAndGetIntent(CALLING_PACKAGE_2, "s1", USER_0)
    +-                            .getComponent().getClassName());
    +-
    +-            // Not pinned, so not lauchable.
    +-        });
    +-
    +-        // Test inner errors.
    +-        runWithCaller(LAUNCHER_1, USER_0, () -> {
    +-            // Not launchable.
    +-            doReturn(ActivityManager.START_CLASS_NOT_FOUND)
    +-                    .when(mMockActivityManagerInternal).startActivitiesAsPackage(
    +-                            anyString(), anyInt(), any(Intent[].class), any(Bundle.class));
    +-            assertStartShortcutThrowsException(CALLING_PACKAGE_1, "s1", USER_0,
    +-                    ActivityNotFoundException.class);
    +-
    +-            // Still not launchable.
    +-            doReturn(ActivityManager.START_CLASS_NOT_FOUND)
    +-                    .when(mMockActivityManagerInternal)
    +-                    .startActivitiesAsPackage(
    +-                            anyString(), anyInt(), any(Intent[].class), any(Bundle.class));
    +-            assertStartShortcutThrowsException(CALLING_PACKAGE_1, "s1", USER_0,
    +-                    ActivityNotFoundException.class);
    +-        });
    +-
    +-
    +-        // TODO Check extra, etc
    +-    }
    +-
    +-    public void testLauncherCallback() throws Throwable {
    +-        // Disable throttling for this test.
    +-        mService.updateConfigurationLocked(
    +-                ConfigConstants.KEY_MAX_UPDATES_PER_INTERVAL + "=99999999,"
    +-                        + ConfigConstants.KEY_MAX_SHORTCUTS + "=99999999"
    +-        );
    +-
    +-        setCaller(LAUNCHER_1, USER_0);
    +-
    +-        assertForLauncherCallback(mLauncherApps, () -> {
    +-            runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
    +-                assertTrue(mManager.setDynamicShortcuts(list(
    +-                        makeShortcut("s1"), makeShortcut("s2"), makeShortcut("s3"))));
    +-            });
    +-        }).assertCallbackCalledForPackageAndUser(CALLING_PACKAGE_1, HANDLE_USER_0)
    +-                .haveIds("s1", "s2", "s3")
    +-                .areAllWithKeyFieldsOnly()
    +-                .areAllDynamic();
    +-
    +-        // From different package.
    +-        assertForLauncherCallback(mLauncherApps, () -> {
    +-            runWithCaller(CALLING_PACKAGE_2, USER_0, () -> {
    +-                assertTrue(mManager.setDynamicShortcuts(list(
    +-                        makeShortcut("s1"), makeShortcut("s2"), makeShortcut("s3"))));
    +-            });
    +-        }).assertCallbackCalledForPackageAndUser(CALLING_PACKAGE_2, HANDLE_USER_0)
    +-                .haveIds("s1", "s2", "s3")
    +-                .areAllWithKeyFieldsOnly()
    +-                .areAllDynamic();
    +-
    +-        mRunningUsers.put(USER_10, true);
    +-
    +-        // Different user, callback shouldn't be called.
    +-        assertForLauncherCallback(mLauncherApps, () -> {
    +-            runWithCaller(CALLING_PACKAGE_1, USER_10, () -> {
    +-                assertTrue(mManager.setDynamicShortcuts(list(
    +-                        makeShortcut("s1"), makeShortcut("s2"), makeShortcut("s3"))));
    +-            });
    +-        }).assertNoCallbackCalled();
    +-
    +-
    +-        // Test for addDynamicShortcuts.
    +-        assertForLauncherCallback(mLauncherApps, () -> {
    +-            runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
    +-                assertTrue(mManager.addDynamicShortcuts(list(makeShortcut("s4"))));
    +-            });
    +-        }).assertCallbackCalledForPackageAndUser(CALLING_PACKAGE_1, HANDLE_USER_0)
    +-                .haveIds("s1", "s2", "s3", "s4")
    +-                .areAllWithKeyFieldsOnly()
    +-                .areAllDynamic();
    +-
    +-        // Test for remove
    +-        assertForLauncherCallback(mLauncherApps, () -> {
    +-            runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
    +-                mManager.removeDynamicShortcuts(list("s1"));
    +-            });
    +-        }).assertCallbackCalledForPackageAndUser(CALLING_PACKAGE_1, HANDLE_USER_0)
    +-                .haveIds("s2", "s3", "s4")
    +-                .areAllWithKeyFieldsOnly()
    +-                .areAllDynamic();
    +-
    +-        // Test for update
    +-        assertForLauncherCallback(mLauncherApps, () -> {
    +-            runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
    +-                assertTrue(mManager.updateShortcuts(list(
    +-                        makeShortcut("s1"), makeShortcut("s2"))));
    +-            });
    +-        }).assertCallbackCalledForPackageAndUser(CALLING_PACKAGE_1, HANDLE_USER_0)
    +-                // All remaining shortcuts will be passed regardless of what's been updated.
    +-                .haveIds("s2", "s3", "s4")
    +-                .areAllWithKeyFieldsOnly()
    +-                .areAllDynamic();
    +-
    +-        // Test for deleteAll
    +-        assertForLauncherCallback(mLauncherApps, () -> {
    +-            runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
    +-                mManager.removeAllDynamicShortcuts();
    +-            });
    +-        }).assertCallbackCalledForPackageAndUser(CALLING_PACKAGE_1, HANDLE_USER_0)
    +-                .isEmpty();
    +-
    +-        // Update package1 with manifest shortcuts
    +-        assertForLauncherCallback(mLauncherApps, () -> {
    +-            addManifestShortcutResource(
    +-                    new ComponentName(CALLING_PACKAGE_1, ShortcutActivity.class.getName()),
    +-                    R.xml.shortcut_2);
    +-            updatePackageVersion(CALLING_PACKAGE_1, 1);
    +-            mService.mPackageMonitor.onReceive(getTestContext(),
    +-                    genPackageAddIntent(CALLING_PACKAGE_1, USER_0));
    +-        }).assertCallbackCalledForPackageAndUser(CALLING_PACKAGE_1, HANDLE_USER_0)
    +-                .areAllManifest()
    +-                .areAllWithKeyFieldsOnly()
    +-                .haveIds("ms1", "ms2");
    +-
    +-        // Make sure pinned shortcuts are passed too.
    +-        // 1. Add dynamic shortcuts.
    +-        runWithCaller(CALLING_PACKAGE_1, UserHandle.USER_SYSTEM, () -> {
    +-            assertTrue(mManager.setDynamicShortcuts(list(
    +-                    makeShortcut("s1"), makeShortcut("s2"))));
    +-        });
    +-
    +-        // 2. Pin some.
    +-        runWithCaller(LAUNCHER_1, UserHandle.USER_SYSTEM, () -> {
    +-            mLauncherApps.pinShortcuts(CALLING_PACKAGE_1, list("ms2", "s2"), HANDLE_USER_0);
    +-        });
    +-        runWithCaller(CALLING_PACKAGE_1, UserHandle.USER_SYSTEM, () -> {
    +-            assertWith(getCallerShortcuts())
    +-                    .haveIds("ms1", "ms2", "s1", "s2")
    +-                    .areAllEnabled()
    +-
    +-                    .selectByIds("ms1", "ms2")
    +-                    .areAllManifest()
    +-
    +-                    .revertToOriginalList()
    +-                    .selectByIds("s1", "s2")
    +-                    .areAllDynamic()
    +-                    ;
    +-        });
    +-
    +-        // 3 Update the app with no manifest shortcuts.  (Pinned one will survive.)
    +-        addManifestShortcutResource(
    +-                new ComponentName(CALLING_PACKAGE_1, ShortcutActivity.class.getName()),
    +-                R.xml.shortcut_0);
    +-        updatePackageVersion(CALLING_PACKAGE_1, 1);
    +-        mService.mPackageMonitor.onReceive(getTestContext(),
    +-                genPackageAddIntent(CALLING_PACKAGE_1, USER_0));
    +-
    +-        assertForLauncherCallback(mLauncherApps, () -> {
    +-            runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
    +-                mManager.removeDynamicShortcuts(list("s2"));
    +-
    +-                assertWith(getCallerShortcuts())
    +-                        .haveIds("ms2", "s1", "s2")
    +-
    +-                        .selectByIds("ms2")
    +-                        .areAllNotManifest()
    +-                        .areAllPinned()
    +-                        .areAllImmutable()
    +-                        .areAllDisabled()
    +-
    +-                        .revertToOriginalList()
    +-                        .selectByIds("s1")
    +-                        .areAllDynamic()
    +-                        .areAllNotPinned()
    +-                        .areAllEnabled()
    +-
    +-                        .revertToOriginalList()
    +-                        .selectByIds("s2")
    +-                        .areAllNotDynamic()
    +-                        .areAllPinned()
    +-                        .areAllEnabled()
    +-                ;
    +-            });
    +-        }).assertCallbackCalledForPackageAndUser(CALLING_PACKAGE_1, HANDLE_USER_0)
    +-                .haveIds("ms2", "s1", "s2")
    +-                .areAllWithKeyFieldsOnly();
    +-
    +-        // Remove CALLING_PACKAGE_2
    +-        assertForLauncherCallback(mLauncherApps, () -> {
    +-            uninstallPackage(USER_0, CALLING_PACKAGE_2);
    +-            mService.cleanUpPackageLocked(CALLING_PACKAGE_2, USER_0, USER_0,
    +-                    /* appStillExists = */ false);
    +-        }).assertCallbackCalledForPackageAndUser(CALLING_PACKAGE_2, HANDLE_USER_0)
    +-                .isEmpty();
    +-    }
    +-
    +-    public void testLauncherCallback_crossProfile() throws Throwable {
    +-        prepareCrossProfileDataSet();
    +-
    +-        final Handler h = new Handler(Looper.getMainLooper());
    +-
    +-        final LauncherApps.Callback c0_1 = mock(LauncherApps.Callback.class);
    +-        final LauncherApps.Callback c0_2 = mock(LauncherApps.Callback.class);
    +-        final LauncherApps.Callback c0_3 = mock(LauncherApps.Callback.class);
    +-        final LauncherApps.Callback c0_4 = mock(LauncherApps.Callback.class);
    +-
    +-        final LauncherApps.Callback cP0_1 = mock(LauncherApps.Callback.class);
    +-        final LauncherApps.Callback c10_1 = mock(LauncherApps.Callback.class);
    +-        final LauncherApps.Callback c10_2 = mock(LauncherApps.Callback.class);
    +-        final LauncherApps.Callback c11_1 = mock(LauncherApps.Callback.class);
    +-
    +-        final List<LauncherApps.Callback> all =
    +-                list(c0_1, c0_2, c0_3, c0_4, cP0_1, c10_1, c11_1);
    +-
    +-        setDefaultLauncherChecker((pkg, userId) -> {
    +-            switch (userId) {
    +-                case USER_0:
    +-                    return LAUNCHER_2.equals(pkg);
    +-                case USER_P0:
    +-                    return LAUNCHER_1.equals(pkg);
    +-                case USER_10:
    +-                    return LAUNCHER_1.equals(pkg);
    +-                case USER_11:
    +-                    return LAUNCHER_1.equals(pkg);
    +-                default:
    +-                    return false;
    +-            }
    +-        });
    +-
    +-        runWithCaller(LAUNCHER_1, USER_0, () -> mLauncherApps.registerCallback(c0_1, h));
    +-        runWithCaller(LAUNCHER_2, USER_0, () -> mLauncherApps.registerCallback(c0_2, h));
    +-        runWithCaller(LAUNCHER_3, USER_0, () -> mLauncherApps.registerCallback(c0_3, h));
    +-        runWithCaller(LAUNCHER_4, USER_0, () -> mLauncherApps.registerCallback(c0_4, h));
    +-        runWithCaller(LAUNCHER_1, USER_P0, () -> mLauncherApps.registerCallback(cP0_1, h));
    +-        runWithCaller(LAUNCHER_1, USER_10, () -> mLauncherApps.registerCallback(c10_1, h));
    +-        runWithCaller(LAUNCHER_2, USER_10, () -> mLauncherApps.registerCallback(c10_2, h));
    +-        runWithCaller(LAUNCHER_1, USER_11, () -> mLauncherApps.registerCallback(c11_1, h));
    +-
    +-        // User 0.
    +-
    +-        resetAll(all);
    +-        runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
    +-            mManager.removeDynamicShortcuts(list());
    +-        });
    +-        waitOnMainThread();
    +-
    +-        assertCallbackNotReceived(c0_1);
    +-        assertCallbackNotReceived(c0_3);
    +-        assertCallbackNotReceived(c0_4);
    +-        assertCallbackNotReceived(c10_1);
    +-        assertCallbackNotReceived(c10_2);
    +-        assertCallbackNotReceived(c11_1);
    +-        assertCallbackReceived(c0_2, HANDLE_USER_0, CALLING_PACKAGE_1, "s1", "s2", "s3");
    +-        assertCallbackReceived(cP0_1, HANDLE_USER_0, CALLING_PACKAGE_1, "s1", "s2", "s3", "s4");
    +-
    +-        // User 0, different package.
    +-
    +-        resetAll(all);
    +-        runWithCaller(CALLING_PACKAGE_3, USER_0, () -> {
    +-            mManager.removeDynamicShortcuts(list());
    +-        });
    +-        waitOnMainThread();
    +-
    +-        assertCallbackNotReceived(c0_1);
    +-        assertCallbackNotReceived(c0_3);
    +-        assertCallbackNotReceived(c0_4);
    +-        assertCallbackNotReceived(c10_1);
    +-        assertCallbackNotReceived(c10_2);
    +-        assertCallbackNotReceived(c11_1);
    +-        assertCallbackReceived(c0_2, HANDLE_USER_0, CALLING_PACKAGE_3, "s1", "s2", "s3", "s4");
    +-        assertCallbackReceived(cP0_1, HANDLE_USER_0, CALLING_PACKAGE_3,
    +-                "s1", "s2", "s3", "s4", "s5", "s6");
    +-
    +-        // Work profile.
    +-        resetAll(all);
    +-        runWithCaller(CALLING_PACKAGE_1, USER_P0, () -> {
    +-            mManager.removeDynamicShortcuts(list());
    +-        });
    +-        waitOnMainThread();
    +-
    +-        assertCallbackNotReceived(c0_1);
    +-        assertCallbackNotReceived(c0_3);
    +-        assertCallbackNotReceived(c0_4);
    +-        assertCallbackNotReceived(c10_1);
    +-        assertCallbackNotReceived(c10_2);
    +-        assertCallbackNotReceived(c11_1);
    +-        assertCallbackReceived(c0_2, HANDLE_USER_P0, CALLING_PACKAGE_1, "s1", "s2", "s3", "s5");
    +-        assertCallbackReceived(cP0_1, HANDLE_USER_P0, CALLING_PACKAGE_1, "s1", "s2", "s3", "s4");
    +-
    +-        // Normal secondary user.
    +-        mRunningUsers.put(USER_10, true);
    +-
    +-        resetAll(all);
    +-        runWithCaller(CALLING_PACKAGE_1, USER_10, () -> {
    +-            mManager.removeDynamicShortcuts(list());
    +-        });
    +-        waitOnMainThread();
    +-
    +-        assertCallbackNotReceived(c0_1);
    +-        assertCallbackNotReceived(c0_2);
    +-        assertCallbackNotReceived(c0_3);
    +-        assertCallbackNotReceived(c0_4);
    +-        assertCallbackNotReceived(cP0_1);
    +-        assertCallbackNotReceived(c10_2);
    +-        assertCallbackNotReceived(c11_1);
    +-        assertCallbackReceived(c10_1, HANDLE_USER_10, CALLING_PACKAGE_1,
    +-                "x1", "x2", "x3", "x4", "x5");
    +-    }
    +-
    +-    // === Test for persisting ===
    +-
    +-    public void testSaveAndLoadUser_empty() {
    +-        assertTrue(mManager.setDynamicShortcuts(list()));
    +-
    +-        Log.i(TAG, "Saved state");
    +-        dumpsysOnLogcat();
    +-        dumpUserFile(0);
    +-
    +-        // Restore.
    +-        mService.saveDirtyInfo();
    +-        initService();
    +-
    +-        assertEquals(0, mManager.getDynamicShortcuts().size());
    +-    }
    +-
    +-    /**
    +-     * Try save and load, also stop/start the user.
    +-     */
    +-    public void testSaveAndLoadUser() {
    +-        // First, create some shortcuts and save.
    +-        runWithCaller(CALLING_PACKAGE_1, UserHandle.USER_SYSTEM, () -> {
    +-            final Icon icon1 = Icon.createWithResource(getTestContext(), R.drawable.black_64x16);
    +-            final Icon icon2 = Icon.createWithBitmap(BitmapFactory.decodeResource(
    +-                    getTestContext().getResources(), R.drawable.icon2));
    +-
    +-            final ShortcutInfo si1 = makeShortcut(
    +-                    "s1",
    +-                    "title1-1",
    +-                    makeComponent(ShortcutActivity.class),
    +-                    icon1,
    +-                    makeIntent(Intent.ACTION_ASSIST, ShortcutActivity2.class,
    +-                            "key1", "val1", "nest", makeBundle("key", 123)),
    +-                        /* weight */ 10);
    +-
    +-            final ShortcutInfo si2 = makeShortcut(
    +-                    "s2",
    +-                    "title1-2",
    +-                        /* activity */ null,
    +-                    icon2,
    +-                    makeIntent(Intent.ACTION_ASSIST, ShortcutActivity3.class),
    +-                        /* weight */ 12);
    +-
    +-            assertTrue(mManager.setDynamicShortcuts(list(si1, si2)));
    +-
    +-            assertEquals(START_TIME + INTERVAL, mManager.getRateLimitResetTime());
    +-            assertEquals(2, mManager.getRemainingCallCount());
    +-        });
    +-        runWithCaller(CALLING_PACKAGE_2, UserHandle.USER_SYSTEM, () -> {
    +-            final Icon icon1 = Icon.createWithResource(getTestContext(), R.drawable.black_16x64);
    +-            final Icon icon2 = Icon.createWithBitmap(BitmapFactory.decodeResource(
    +-                    getTestContext().getResources(), R.drawable.icon2));
    +-
    +-            final ShortcutInfo si1 = makeShortcut(
    +-                    "s1",
    +-                    "title2-1",
    +-                    makeComponent(ShortcutActivity.class),
    +-                    icon1,
    +-                    makeIntent(Intent.ACTION_ASSIST, ShortcutActivity2.class,
    +-                            "key1", "val1", "nest", makeBundle("key", 123)),
    +-                        /* weight */ 10);
    +-
    +-            final ShortcutInfo si2 = makeShortcut(
    +-                    "s2",
    +-                    "title2-2",
    +-                        /* activity */ null,
    +-                    icon2,
    +-                    makeIntent(Intent.ACTION_ASSIST, ShortcutActivity3.class),
    +-                        /* weight */ 12);
    +-
    +-            assertTrue(mManager.setDynamicShortcuts(list(si1, si2)));
    +-
    +-            assertEquals(START_TIME + INTERVAL, mManager.getRateLimitResetTime());
    +-            assertEquals(2, mManager.getRemainingCallCount());
    +-        });
    +-
    +-        mRunningUsers.put(USER_10, true);
    +-
    +-        runWithCaller(CALLING_PACKAGE_1, USER_10, () -> {
    +-            final Icon icon1 = Icon.createWithResource(getTestContext(), R.drawable.black_64x64);
    +-            final Icon icon2 = Icon.createWithBitmap(BitmapFactory.decodeResource(
    +-                    getTestContext().getResources(), R.drawable.icon2));
    +-
    +-            final ShortcutInfo si1 = makeShortcut(
    +-                    "s1",
    +-                    "title10-1-1",
    +-                    makeComponent(ShortcutActivity.class),
    +-                    icon1,
    +-                    makeIntent(Intent.ACTION_ASSIST, ShortcutActivity2.class,
    +-                            "key1", "val1", "nest", makeBundle("key", 123)),
    +-                        /* weight */ 10);
    +-
    +-            final ShortcutInfo si2 = makeShortcut(
    +-                    "s2",
    +-                    "title10-1-2",
    +-                        /* activity */ null,
    +-                    icon2,
    +-                    makeIntent(Intent.ACTION_ASSIST, ShortcutActivity3.class),
    +-                        /* weight */ 12);
    +-
    +-            assertTrue(mManager.setDynamicShortcuts(list(si1, si2)));
    +-
    +-            assertEquals(START_TIME + INTERVAL, mManager.getRateLimitResetTime());
    +-            assertEquals(2, mManager.getRemainingCallCount());
    +-        });
    +-
    +-        mService.getShortcutsForTest().get(UserHandle.USER_SYSTEM).setLauncher(
    +-                new ComponentName("pkg1", "class"));
    +-
    +-        // Restore.
    +-        mService.saveDirtyInfo();
    +-        initService();
    +-
    +-        // Before the load, the map should be empty.
    +-        assertEquals(0, mService.getShortcutsForTest().size());
    +-
    +-        // this will pre-load the per-user info.
    +-        mService.handleUnlockUser(UserHandle.USER_SYSTEM);
    +-
    +-        // Now it's loaded.
    +-        assertEquals(1, mService.getShortcutsForTest().size());
    +-
    +-        runWithCaller(CALLING_PACKAGE_1, UserHandle.USER_SYSTEM, () -> {
    +-            assertShortcutIds(assertAllDynamic(assertAllHaveIntents(assertAllHaveIcon(
    +-                    mManager.getDynamicShortcuts()))), "s1", "s2");
    +-            assertEquals(2, mManager.getRemainingCallCount());
    +-
    +-            assertEquals("title1-1", getCallerShortcut("s1").getTitle());
    +-            assertEquals("title1-2", getCallerShortcut("s2").getTitle());
    +-        });
    +-        runWithCaller(CALLING_PACKAGE_2, UserHandle.USER_SYSTEM, () -> {
    +-            assertShortcutIds(assertAllDynamic(assertAllHaveIntents(assertAllHaveIcon(
    +-                    mManager.getDynamicShortcuts()))), "s1", "s2");
    +-            assertEquals(2, mManager.getRemainingCallCount());
    +-
    +-            assertEquals("title2-1", getCallerShortcut("s1").getTitle());
    +-            assertEquals("title2-2", getCallerShortcut("s2").getTitle());
    +-        });
    +-
    +-        assertEquals("pkg1", mService.getShortcutsForTest().get(UserHandle.USER_SYSTEM)
    +-                .getLastKnownLauncher().getPackageName());
    +-
    +-        // Start another user
    +-        mService.handleUnlockUser(USER_10);
    +-
    +-        // Now the size is 2.
    +-        assertEquals(2, mService.getShortcutsForTest().size());
    +-
    +-        runWithCaller(CALLING_PACKAGE_1, USER_10, () -> {
    +-            assertShortcutIds(assertAllDynamic(assertAllHaveIntents(assertAllHaveIcon(
    +-                    mManager.getDynamicShortcuts()))), "s1", "s2");
    +-            assertEquals(2, mManager.getRemainingCallCount());
    +-
    +-            assertEquals("title10-1-1", getCallerShortcut("s1").getTitle());
    +-            assertEquals("title10-1-2", getCallerShortcut("s2").getTitle());
    +-        });
    +-        assertNull(mService.getShortcutsForTest().get(USER_10).getLastKnownLauncher());
    +-
    +-        // Try stopping the user
    +-        mService.handleCleanupUser(USER_10);
    +-
    +-        // Now it's unloaded.
    +-        assertEquals(1, mService.getShortcutsForTest().size());
    +-
    +-        // TODO Check all other fields
    +-    }
    +-
    +-    public void testCleanupPackage() {
    +-        runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
    +-            assertTrue(mManager.setDynamicShortcuts(list(
    +-                    makeShortcut("s0_1"))));
    +-        });
    +-        runWithCaller(CALLING_PACKAGE_2, USER_0, () -> {
    +-            assertTrue(mManager.setDynamicShortcuts(list(
    +-                    makeShortcut("s0_2"))));
    +-        });
    +-        runWithCaller(LAUNCHER_1, USER_0, () -> {
    +-            mLauncherApps.pinShortcuts(CALLING_PACKAGE_1, list("s0_1"),
    +-                    HANDLE_USER_0);
    +-            mLauncherApps.pinShortcuts(CALLING_PACKAGE_2, list("s0_2"),
    +-                    HANDLE_USER_0);
    +-        });
    +-        runWithCaller(LAUNCHER_2, USER_0, () -> {
    +-            mLauncherApps.pinShortcuts(CALLING_PACKAGE_1, list("s0_1"),
    +-                    HANDLE_USER_0);
    +-            mLauncherApps.pinShortcuts(CALLING_PACKAGE_2, list("s0_2"),
    +-                    HANDLE_USER_0);
    +-        });
    +-
    +-        mRunningUsers.put(USER_10, true);
    +-
    +-        runWithCaller(CALLING_PACKAGE_1, USER_10, () -> {
    +-            assertTrue(mManager.setDynamicShortcuts(list(
    +-                    makeShortcut("s10_1"))));
    +-        });
    +-        runWithCaller(CALLING_PACKAGE_2, USER_10, () -> {
    +-            assertTrue(mManager.setDynamicShortcuts(list(
    +-                    makeShortcut("s10_2"))));
    +-        });
    +-        runWithCaller(LAUNCHER_1, USER_10, () -> {
    +-            mLauncherApps.pinShortcuts(CALLING_PACKAGE_1, list("s10_1"),
    +-                    HANDLE_USER_10);
    +-            mLauncherApps.pinShortcuts(CALLING_PACKAGE_2, list("s10_2"),
    +-                    HANDLE_USER_10);
    +-        });
    +-        runWithCaller(LAUNCHER_2, USER_10, () -> {
    +-            mLauncherApps.pinShortcuts(CALLING_PACKAGE_1, list("s10_1"),
    +-                    HANDLE_USER_10);
    +-            mLauncherApps.pinShortcuts(CALLING_PACKAGE_2, list("s10_2"),
    +-                    HANDLE_USER_10);
    +-        });
    +-
    +-        // Remove all dynamic shortcuts; now all shortcuts are just pinned.
    +-        runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
    +-            mManager.removeAllDynamicShortcuts();
    +-        });
    +-        runWithCaller(CALLING_PACKAGE_2, USER_0, () -> {
    +-            mManager.removeAllDynamicShortcuts();
    +-        });
    +-        runWithCaller(CALLING_PACKAGE_1, USER_10, () -> {
    +-            mManager.removeAllDynamicShortcuts();
    +-        });
    +-        runWithCaller(CALLING_PACKAGE_2, USER_10, () -> {
    +-            mManager.removeAllDynamicShortcuts();
    +-        });
    +-
    +-
    +-        final SparseArray<ShortcutUser> users =  mService.getShortcutsForTest();
    +-        assertEquals(2, users.size());
    +-        assertEquals(USER_0, users.keyAt(0));
    +-        assertEquals(USER_10, users.keyAt(1));
    +-
    +-        final ShortcutUser user0 =  users.get(USER_0);
    +-        final ShortcutUser user10 =  users.get(USER_10);
    +-
    +-
    +-        // Check the registered packages.
    +-        dumpsysOnLogcat();
    +-        assertEquals(set(CALLING_PACKAGE_1, CALLING_PACKAGE_2),
    +-                hashSet(user0.getAllPackagesForTest().keySet()));
    +-        assertEquals(set(CALLING_PACKAGE_1, CALLING_PACKAGE_2),
    +-                hashSet(user10.getAllPackagesForTest().keySet()));
    +-        assertEquals(
    +-                set(PackageWithUser.of(USER_0, LAUNCHER_1),
    +-                        PackageWithUser.of(USER_0, LAUNCHER_2)),
    +-                hashSet(user0.getAllLaunchersForTest().keySet()));
    +-        assertEquals(
    +-                set(PackageWithUser.of(USER_10, LAUNCHER_1),
    +-                        PackageWithUser.of(USER_10, LAUNCHER_2)),
    +-                hashSet(user10.getAllLaunchersForTest().keySet()));
    +-        assertShortcutIds(getLauncherPinnedShortcuts(LAUNCHER_1, USER_0),
    +-                "s0_1", "s0_2");
    +-        assertShortcutIds(getLauncherPinnedShortcuts(LAUNCHER_2, USER_0),
    +-                "s0_1", "s0_2");
    +-        assertShortcutIds(getLauncherPinnedShortcuts(LAUNCHER_1, USER_10),
    +-                "s10_1", "s10_2");
    +-        assertShortcutIds(getLauncherPinnedShortcuts(LAUNCHER_2, USER_10),
    +-                "s10_1", "s10_2");
    +-        assertShortcutExists(CALLING_PACKAGE_1, "s0_1", USER_0);
    +-        assertShortcutExists(CALLING_PACKAGE_2, "s0_2", USER_0);
    +-        assertShortcutExists(CALLING_PACKAGE_1, "s10_1", USER_10);
    +-        assertShortcutExists(CALLING_PACKAGE_2, "s10_2", USER_10);
    +-
    +-        mService.saveDirtyInfo();
    +-
    +-        // Nonexistent package.
    +-        uninstallPackage(USER_0, "abc");
    +-        mService.cleanUpPackageLocked("abc", USER_0, USER_0, /* appStillExists = */ false);
    +-
    +-        // No changes.
    +-        assertEquals(set(CALLING_PACKAGE_1, CALLING_PACKAGE_2),
    +-                hashSet(user0.getAllPackagesForTest().keySet()));
    +-        assertEquals(set(CALLING_PACKAGE_1, CALLING_PACKAGE_2),
    +-                hashSet(user10.getAllPackagesForTest().keySet()));
    +-        assertEquals(
    +-                set(PackageWithUser.of(USER_0, LAUNCHER_1),
    +-                        PackageWithUser.of(USER_0, LAUNCHER_2)),
    +-                hashSet(user0.getAllLaunchersForTest().keySet()));
    +-        assertEquals(
    +-                set(PackageWithUser.of(USER_10, LAUNCHER_1),
    +-                        PackageWithUser.of(USER_10, LAUNCHER_2)),
    +-                hashSet(user10.getAllLaunchersForTest().keySet()));
    +-        assertShortcutIds(getLauncherPinnedShortcuts(LAUNCHER_1, USER_0),
    +-                "s0_1", "s0_2");
    +-        assertShortcutIds(getLauncherPinnedShortcuts(LAUNCHER_2, USER_0),
    +-                "s0_1", "s0_2");
    +-        assertShortcutIds(getLauncherPinnedShortcuts(LAUNCHER_1, USER_10),
    +-                "s10_1", "s10_2");
    +-        assertShortcutIds(getLauncherPinnedShortcuts(LAUNCHER_2, USER_10),
    +-                "s10_1", "s10_2");
    +-        assertShortcutExists(CALLING_PACKAGE_1, "s0_1", USER_0);
    +-        assertShortcutExists(CALLING_PACKAGE_2, "s0_2", USER_0);
    +-        assertShortcutExists(CALLING_PACKAGE_1, "s10_1", USER_10);
    +-        assertShortcutExists(CALLING_PACKAGE_2, "s10_2", USER_10);
    +-
    +-        mService.saveDirtyInfo();
    +-
    +-        // Remove a package.
    +-        uninstallPackage(USER_0, CALLING_PACKAGE_1);
    +-        mService.cleanUpPackageLocked(CALLING_PACKAGE_1, USER_0, USER_0,
    +-                /* appStillExists = */ false);
    +-
    +-        assertEquals(set(CALLING_PACKAGE_2),
    +-                hashSet(user0.getAllPackagesForTest().keySet()));
    +-        assertEquals(set(CALLING_PACKAGE_1, CALLING_PACKAGE_2),
    +-                hashSet(user10.getAllPackagesForTest().keySet()));
    +-        assertEquals(
    +-                set(PackageWithUser.of(USER_0, LAUNCHER_1),
    +-                        PackageWithUser.of(USER_0, LAUNCHER_2)),
    +-                hashSet(user0.getAllLaunchersForTest().keySet()));
    +-        assertEquals(
    +-                set(PackageWithUser.of(USER_10, LAUNCHER_1),
    +-                        PackageWithUser.of(USER_10, LAUNCHER_2)),
    +-                hashSet(user10.getAllLaunchersForTest().keySet()));
    +-        assertShortcutIds(getLauncherPinnedShortcuts(LAUNCHER_1, USER_0),
    +-                "s0_2");
    +-        assertShortcutIds(getLauncherPinnedShortcuts(LAUNCHER_2, USER_0),
    +-                "s0_2");
    +-        assertShortcutIds(getLauncherPinnedShortcuts(LAUNCHER_1, USER_10),
    +-                "s10_1", "s10_2");
    +-        assertShortcutIds(getLauncherPinnedShortcuts(LAUNCHER_2, USER_10),
    +-                "s10_1", "s10_2");
    +-        assertShortcutNotExists(CALLING_PACKAGE_1, "s0_1", USER_0);
    +-        assertShortcutExists(CALLING_PACKAGE_2, "s0_2", USER_0);
    +-        assertShortcutExists(CALLING_PACKAGE_1, "s10_1", USER_10);
    +-        assertShortcutExists(CALLING_PACKAGE_2, "s10_2", USER_10);
    +-
    +-        mService.saveDirtyInfo();
    +-
    +-        // Remove a launcher.
    +-        uninstallPackage(USER_10, LAUNCHER_1);
    +-        mService.cleanUpPackageLocked(LAUNCHER_1, USER_10, USER_10, /* appStillExists = */ false);
    +-
    +-        assertEquals(set(CALLING_PACKAGE_2),
    +-                hashSet(user0.getAllPackagesForTest().keySet()));
    +-        assertEquals(set(CALLING_PACKAGE_1, CALLING_PACKAGE_2),
    +-                hashSet(user10.getAllPackagesForTest().keySet()));
    +-        assertEquals(
    +-                set(PackageWithUser.of(USER_0, LAUNCHER_1),
    +-                        PackageWithUser.of(USER_0, LAUNCHER_2)),
    +-                hashSet(user0.getAllLaunchersForTest().keySet()));
    +-        assertEquals(
    +-                set(PackageWithUser.of(USER_10, LAUNCHER_2)),
    +-                hashSet(user10.getAllLaunchersForTest().keySet()));
    +-        assertShortcutIds(getLauncherPinnedShortcuts(LAUNCHER_1, USER_0),
    +-                "s0_2");
    +-        assertShortcutIds(getLauncherPinnedShortcuts(LAUNCHER_2, USER_0),
    +-                "s0_2");
    +-        assertShortcutIds(getLauncherPinnedShortcuts(LAUNCHER_2, USER_10),
    +-                "s10_1", "s10_2");
    +-        assertShortcutNotExists(CALLING_PACKAGE_1, "s0_1", USER_0);
    +-        assertShortcutExists(CALLING_PACKAGE_2, "s0_2", USER_0);
    +-        assertShortcutExists(CALLING_PACKAGE_1, "s10_1", USER_10);
    +-        assertShortcutExists(CALLING_PACKAGE_2, "s10_2", USER_10);
    +-
    +-        mService.saveDirtyInfo();
    +-
    +-        // Remove a package.
    +-        uninstallPackage(USER_10, CALLING_PACKAGE_2);
    +-        mService.cleanUpPackageLocked(CALLING_PACKAGE_2, USER_10, USER_10,
    +-                /* appStillExists = */ false);
    +-
    +-        assertEquals(set(CALLING_PACKAGE_2),
    +-                hashSet(user0.getAllPackagesForTest().keySet()));
    +-        assertEquals(set(CALLING_PACKAGE_1),
    +-                hashSet(user10.getAllPackagesForTest().keySet()));
    +-        assertEquals(
    +-                set(PackageWithUser.of(USER_0, LAUNCHER_1),
    +-                        PackageWithUser.of(USER_0, LAUNCHER_2)),
    +-                hashSet(user0.getAllLaunchersForTest().keySet()));
    +-        assertEquals(
    +-                set(PackageWithUser.of(USER_10, LAUNCHER_2)),
    +-                hashSet(user10.getAllLaunchersForTest().keySet()));
    +-        assertShortcutIds(getLauncherPinnedShortcuts(LAUNCHER_1, USER_0),
    +-                "s0_2");
    +-        assertShortcutIds(getLauncherPinnedShortcuts(LAUNCHER_2, USER_0),
    +-                "s0_2");
    +-        assertShortcutIds(getLauncherPinnedShortcuts(LAUNCHER_2, USER_10),
    +-                "s10_1");
    +-        assertShortcutNotExists(CALLING_PACKAGE_1, "s0_1", USER_0);
    +-        assertShortcutExists(CALLING_PACKAGE_2, "s0_2", USER_0);
    +-        assertShortcutExists(CALLING_PACKAGE_1, "s10_1", USER_10);
    +-        assertShortcutNotExists(CALLING_PACKAGE_2, "s10_2", USER_10);
    +-
    +-        mService.saveDirtyInfo();
    +-
    +-        // Remove the other launcher from user 10 too.
    +-        uninstallPackage(USER_10, LAUNCHER_2);
    +-        mService.cleanUpPackageLocked(LAUNCHER_2, USER_10, USER_10,
    +-                /* appStillExists = */ false);
    +-
    +-        assertEquals(set(CALLING_PACKAGE_2),
    +-                hashSet(user0.getAllPackagesForTest().keySet()));
    +-        assertEquals(set(CALLING_PACKAGE_1),
    +-                hashSet(user10.getAllPackagesForTest().keySet()));
    +-        assertEquals(
    +-                set(PackageWithUser.of(USER_0, LAUNCHER_1),
    +-                        PackageWithUser.of(USER_0, LAUNCHER_2)),
    +-                hashSet(user0.getAllLaunchersForTest().keySet()));
    +-        assertEquals(
    +-                set(),
    +-                hashSet(user10.getAllLaunchersForTest().keySet()));
    +-        assertShortcutIds(getLauncherPinnedShortcuts(LAUNCHER_1, USER_0),
    +-                "s0_2");
    +-        assertShortcutIds(getLauncherPinnedShortcuts(LAUNCHER_2, USER_0),
    +-                "s0_2");
    +-
    +-        // Note the pinned shortcuts on user-10 no longer referred, so they should both be removed.
    +-        assertShortcutNotExists(CALLING_PACKAGE_1, "s0_1", USER_0);
    +-        assertShortcutExists(CALLING_PACKAGE_2, "s0_2", USER_0);
    +-        assertShortcutNotExists(CALLING_PACKAGE_1, "s10_1", USER_10);
    +-        assertShortcutNotExists(CALLING_PACKAGE_2, "s10_2", USER_10);
    +-
    +-        mService.saveDirtyInfo();
    +-
    +-        // More remove.
    +-        uninstallPackage(USER_10, CALLING_PACKAGE_1);
    +-        mService.cleanUpPackageLocked(CALLING_PACKAGE_1, USER_10, USER_10,
    +-                /* appStillExists = */ false);
    +-
    +-        assertEquals(set(CALLING_PACKAGE_2),
    +-                hashSet(user0.getAllPackagesForTest().keySet()));
    +-        assertEquals(set(),
    +-                hashSet(user10.getAllPackagesForTest().keySet()));
    +-        assertEquals(
    +-                set(PackageWithUser.of(USER_0, LAUNCHER_1),
    +-                        PackageWithUser.of(USER_0, LAUNCHER_2)),
    +-                hashSet(user0.getAllLaunchersForTest().keySet()));
    +-        assertEquals(set(),
    +-                hashSet(user10.getAllLaunchersForTest().keySet()));
    +-        assertShortcutIds(getLauncherPinnedShortcuts(LAUNCHER_1, USER_0),
    +-                "s0_2");
    +-        assertShortcutIds(getLauncherPinnedShortcuts(LAUNCHER_2, USER_0),
    +-                "s0_2");
    +-
    +-        // Note the pinned shortcuts on user-10 no longer referred, so they should both be removed.
    +-        assertShortcutNotExists(CALLING_PACKAGE_1, "s0_1", USER_0);
    +-        assertShortcutExists(CALLING_PACKAGE_2, "s0_2", USER_0);
    +-        assertShortcutNotExists(CALLING_PACKAGE_1, "s10_1", USER_10);
    +-        assertShortcutNotExists(CALLING_PACKAGE_2, "s10_2", USER_10);
    +-
    +-        mService.saveDirtyInfo();
    +-    }
    +-
    +-    public void testCleanupPackage_republishManifests() {
    +-        addManifestShortcutResource(
    +-                new ComponentName(CALLING_PACKAGE_1, ShortcutActivity.class.getName()),
    +-                R.xml.shortcut_2);
    +-        updatePackageVersion(CALLING_PACKAGE_1, 1);
    +-                mService.mPackageMonitor.onReceive(getTestContext(),
    +-                genPackageAddIntent(CALLING_PACKAGE_1, USER_0));
    +-
    +-        runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
    +-            assertTrue(mManager.setDynamicShortcuts(list(
    +-                    makeShortcut("s1"), makeShortcut("s2"), makeShortcut("s3"))));
    +-        });
    +-        runWithCaller(LAUNCHER_1, USER_0, () -> {
    +-            mLauncherApps.pinShortcuts(CALLING_PACKAGE_1,
    +-                    list("s2", "s3", "ms1", "ms2"), HANDLE_USER_0);
    +-        });
    +-
    +-        // Remove ms2 from manifest.
    +-        addManifestShortcutResource(
    +-                new ComponentName(CALLING_PACKAGE_1, ShortcutActivity.class.getName()),
    +-                R.xml.shortcut_1);
    +-        updatePackageVersion(CALLING_PACKAGE_1, 1);
    +-                mService.mPackageMonitor.onReceive(getTestContext(),
    +-                genPackageAddIntent(CALLING_PACKAGE_1, USER_0));
    +-
    +-        runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
    +-            assertTrue(mManager.setDynamicShortcuts(list(
    +-                    makeShortcut("s1"), makeShortcut("s2"))));
    +-
    +-            // Make sure the shortcuts are in the intended state.
    +-            assertWith(getCallerShortcuts())
    +-                    .haveIds("ms1", "ms2", "s1", "s2", "s3")
    +-
    +-                    .selectByIds("ms1")
    +-                    .areAllManifest()
    +-                    .areAllPinned()
    +-
    +-                    .revertToOriginalList()
    +-                    .selectByIds("ms2")
    +-                    .areAllNotManifest()
    +-                    .areAllPinned()
    +-
    +-                    .revertToOriginalList()
    +-                    .selectByIds("s1")
    +-                    .areAllDynamic()
    +-                    .areAllNotPinned()
    +-
    +-                    .revertToOriginalList()
    +-                    .selectByIds("s2")
    +-                    .areAllDynamic()
    +-                    .areAllPinned()
    +-
    +-                    .revertToOriginalList()
    +-                    .selectByIds("s3")
    +-                    .areAllNotDynamic()
    +-                    .areAllPinned();
    +-        });
    +-
    +-        // Clean up + re-publish manifests.
    +-        mService.cleanUpPackageLocked(CALLING_PACKAGE_1, USER_0, USER_0,
    +-                /* appStillExists = */ true);
    +-        runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
    +-            assertWith(getCallerShortcuts())
    +-                    .haveIds("ms1")
    +-                    .areAllManifest();
    +-        });
    +-    }
    +-
    +-    public void testHandleGonePackage_crossProfile() {
    +-        // Create some shortcuts.
    +-        runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
    +-            assertTrue(mManager.setDynamicShortcuts(list(
    +-                    makeShortcut("s1"), makeShortcut("s2"), makeShortcut("s3"))));
    +-        });
    +-        runWithCaller(CALLING_PACKAGE_1, USER_P0, () -> {
    +-            assertTrue(mManager.setDynamicShortcuts(list(
    +-                    makeShortcut("s1"), makeShortcut("s2"), makeShortcut("s3"))));
    +-        });
    +-        runWithCaller(CALLING_PACKAGE_2, USER_0, () -> {
    +-            assertTrue(mManager.setDynamicShortcuts(list(
    +-                    makeShortcut("s1"), makeShortcut("s2"), makeShortcut("s3"))));
    +-        });
    +-
    +-        mRunningUsers.put(USER_10, true);
    +-
    +-        runWithCaller(CALLING_PACKAGE_1, USER_10, () -> {
    +-            assertTrue(mManager.setDynamicShortcuts(list(
    +-                    makeShortcut("s1"), makeShortcut("s2"), makeShortcut("s3"))));
    +-        });
    +-
    +-        assertDynamicOnly(getPackageShortcut(CALLING_PACKAGE_1, "s1", USER_0));
    +-        assertDynamicOnly(getPackageShortcut(CALLING_PACKAGE_1, "s2", USER_0));
    +-        assertDynamicOnly(getPackageShortcut(CALLING_PACKAGE_1, "s3", USER_0));
    +-
    +-        assertDynamicOnly(getPackageShortcut(CALLING_PACKAGE_1, "s1", USER_P0));
    +-        assertDynamicOnly(getPackageShortcut(CALLING_PACKAGE_1, "s2", USER_P0));
    +-        assertDynamicOnly(getPackageShortcut(CALLING_PACKAGE_1, "s3", USER_P0));
    +-
    +-        assertDynamicOnly(getPackageShortcut(CALLING_PACKAGE_2, "s1", USER_0));
    +-        assertDynamicOnly(getPackageShortcut(CALLING_PACKAGE_2, "s2", USER_0));
    +-        assertDynamicOnly(getPackageShortcut(CALLING_PACKAGE_2, "s3", USER_0));
    +-
    +-        assertDynamicOnly(getPackageShortcut(CALLING_PACKAGE_1, "s1", USER_10));
    +-        assertDynamicOnly(getPackageShortcut(CALLING_PACKAGE_1, "s2", USER_10));
    +-        assertDynamicOnly(getPackageShortcut(CALLING_PACKAGE_1, "s3", USER_10));
    +-
    +-        // Pin some.
    +-
    +-        runWithCaller(LAUNCHER_1, USER_0, () -> {
    +-            mLauncherApps.pinShortcuts(CALLING_PACKAGE_1,
    +-                    list("s1"), HANDLE_USER_0);
    +-
    +-            mLauncherApps.pinShortcuts(CALLING_PACKAGE_1,
    +-                    list("s2"), UserHandle.of(USER_P0));
    +-
    +-            mLauncherApps.pinShortcuts(CALLING_PACKAGE_2,
    +-                    list("s3"), HANDLE_USER_0);
    +-        });
    +-
    +-        runWithCaller(LAUNCHER_1, USER_P0, () -> {
    +-            mLauncherApps.pinShortcuts(CALLING_PACKAGE_1,
    +-                    list("s2"), HANDLE_USER_0);
    +-
    +-            mLauncherApps.pinShortcuts(CALLING_PACKAGE_1,
    +-                    list("s3"), UserHandle.of(USER_P0));
    +-
    +-            mLauncherApps.pinShortcuts(CALLING_PACKAGE_2,
    +-                    list("s1"), HANDLE_USER_0);
    +-        });
    +-
    +-        runWithCaller(LAUNCHER_1, USER_10, () -> {
    +-            mLauncherApps.pinShortcuts(CALLING_PACKAGE_1,
    +-                    list("s3"), HANDLE_USER_10);
    +-        });
    +-
    +-        // Check the state.
    +-
    +-        assertDynamicAndPinned(getPackageShortcut(CALLING_PACKAGE_1, "s1", USER_0));
    +-        assertDynamicAndPinned(getPackageShortcut(CALLING_PACKAGE_1, "s2", USER_0));
    +-        assertDynamicOnly(getPackageShortcut(CALLING_PACKAGE_1, "s3", USER_0));
    +-
    +-        assertDynamicOnly(getPackageShortcut(CALLING_PACKAGE_1, "s1", USER_P0));
    +-        assertDynamicAndPinned(getPackageShortcut(CALLING_PACKAGE_1, "s2", USER_P0));
    +-        assertDynamicAndPinned(getPackageShortcut(CALLING_PACKAGE_1, "s3", USER_P0));
    +-
    +-        assertDynamicAndPinned(getPackageShortcut(CALLING_PACKAGE_2, "s1", USER_0));
    +-        assertDynamicOnly(getPackageShortcut(CALLING_PACKAGE_2, "s2", USER_0));
    +-        assertDynamicAndPinned(getPackageShortcut(CALLING_PACKAGE_2, "s3", USER_0));
    +-
    +-        assertDynamicOnly(getPackageShortcut(CALLING_PACKAGE_1, "s1", USER_10));
    +-        assertDynamicOnly(getPackageShortcut(CALLING_PACKAGE_1, "s2", USER_10));
    +-        assertDynamicAndPinned(getPackageShortcut(CALLING_PACKAGE_1, "s3", USER_10));
    +-
    +-        // Make sure all the information is persisted.
    +-        mService.saveDirtyInfo();
    +-        initService();
    +-        mService.handleUnlockUser(USER_0);
    +-        mService.handleUnlockUser(USER_P0);
    +-        mService.handleUnlockUser(USER_10);
    +-
    +-        assertDynamicAndPinned(getPackageShortcut(CALLING_PACKAGE_1, "s1", USER_0));
    +-        assertDynamicAndPinned(getPackageShortcut(CALLING_PACKAGE_1, "s2", USER_0));
    +-        assertDynamicOnly(getPackageShortcut(CALLING_PACKAGE_1, "s3", USER_0));
    +-
    +-        assertDynamicOnly(getPackageShortcut(CALLING_PACKAGE_1, "s1", USER_P0));
    +-        assertDynamicAndPinned(getPackageShortcut(CALLING_PACKAGE_1, "s2", USER_P0));
    +-        assertDynamicAndPinned(getPackageShortcut(CALLING_PACKAGE_1, "s3", USER_P0));
    +-
    +-        assertDynamicAndPinned(getPackageShortcut(CALLING_PACKAGE_2, "s1", USER_0));
    +-        assertDynamicOnly(getPackageShortcut(CALLING_PACKAGE_2, "s2", USER_0));
    +-        assertDynamicAndPinned(getPackageShortcut(CALLING_PACKAGE_2, "s3", USER_0));
    +-
    +-        assertDynamicOnly(getPackageShortcut(CALLING_PACKAGE_1, "s1", USER_10));
    +-        assertDynamicOnly(getPackageShortcut(CALLING_PACKAGE_1, "s2", USER_10));
    +-        assertDynamicAndPinned(getPackageShortcut(CALLING_PACKAGE_1, "s3", USER_10));
    +-
    +-        // Start uninstalling.
    +-        uninstallPackage(USER_10, LAUNCHER_1);
    +-        mService.checkPackageChanges(USER_10);
    +-
    +-        assertDynamicAndPinned(getPackageShortcut(CALLING_PACKAGE_1, "s1", USER_0));
    +-        assertDynamicAndPinned(getPackageShortcut(CALLING_PACKAGE_1, "s2", USER_0));
    +-        assertDynamicOnly(getPackageShortcut(CALLING_PACKAGE_1, "s3", USER_0));
    +-
    +-        assertDynamicOnly(getPackageShortcut(CALLING_PACKAGE_1, "s1", USER_P0));
    +-        assertDynamicAndPinned(getPackageShortcut(CALLING_PACKAGE_1, "s2", USER_P0));
    +-        assertDynamicAndPinned(getPackageShortcut(CALLING_PACKAGE_1, "s3", USER_P0));
    +-
    +-        assertDynamicAndPinned(getPackageShortcut(CALLING_PACKAGE_2, "s1", USER_0));
    +-        assertDynamicOnly(getPackageShortcut(CALLING_PACKAGE_2, "s2", USER_0));
    +-        assertDynamicAndPinned(getPackageShortcut(CALLING_PACKAGE_2, "s3", USER_0));
    +-
    +-        assertDynamicOnly(getPackageShortcut(CALLING_PACKAGE_1, "s1", USER_10));
    +-        assertDynamicOnly(getPackageShortcut(CALLING_PACKAGE_1, "s2", USER_10));
    +-        assertDynamicOnly(getPackageShortcut(CALLING_PACKAGE_1, "s3", USER_10));
    +-
    +-        // Uninstall.
    +-        uninstallPackage(USER_10, CALLING_PACKAGE_1);
    +-        mService.checkPackageChanges(USER_10);
    +-
    +-        assertDynamicAndPinned(getPackageShortcut(CALLING_PACKAGE_1, "s1", USER_0));
    +-        assertDynamicAndPinned(getPackageShortcut(CALLING_PACKAGE_1, "s2", USER_0));
    +-        assertDynamicOnly(getPackageShortcut(CALLING_PACKAGE_1, "s3", USER_0));
    +-
    +-        assertDynamicOnly(getPackageShortcut(CALLING_PACKAGE_1, "s1", USER_P0));
    +-        assertDynamicAndPinned(getPackageShortcut(CALLING_PACKAGE_1, "s2", USER_P0));
    +-        assertDynamicAndPinned(getPackageShortcut(CALLING_PACKAGE_1, "s3", USER_P0));
    +-
    +-        assertDynamicAndPinned(getPackageShortcut(CALLING_PACKAGE_2, "s1", USER_0));
    +-        assertDynamicOnly(getPackageShortcut(CALLING_PACKAGE_2, "s2", USER_0));
    +-        assertDynamicAndPinned(getPackageShortcut(CALLING_PACKAGE_2, "s3", USER_0));
    +-
    +-        assertNull(getPackageShortcut(CALLING_PACKAGE_1, "s1", USER_10));
    +-        assertNull(getPackageShortcut(CALLING_PACKAGE_1, "s2", USER_10));
    +-        assertNull(getPackageShortcut(CALLING_PACKAGE_1, "s3", USER_10));
    +-
    +-        uninstallPackage(USER_P0, LAUNCHER_1);
    +-        mService.checkPackageChanges(USER_0);
    +-
    +-        assertDynamicAndPinned(getPackageShortcut(CALLING_PACKAGE_1, "s1", USER_0));
    +-        assertDynamicOnly(getPackageShortcut(CALLING_PACKAGE_1, "s2", USER_0));
    +-        assertDynamicOnly(getPackageShortcut(CALLING_PACKAGE_1, "s3", USER_0));
    +-
    +-        assertDynamicOnly(getPackageShortcut(CALLING_PACKAGE_1, "s1", USER_P0));
    +-        assertDynamicAndPinned(getPackageShortcut(CALLING_PACKAGE_1, "s2", USER_P0));
    +-        assertDynamicAndPinned(getPackageShortcut(CALLING_PACKAGE_1, "s3", USER_P0));
    +-
    +-        assertDynamicOnly(getPackageShortcut(CALLING_PACKAGE_2, "s1", USER_0));
    +-        assertDynamicOnly(getPackageShortcut(CALLING_PACKAGE_2, "s2", USER_0));
    +-        assertDynamicAndPinned(getPackageShortcut(CALLING_PACKAGE_2, "s3", USER_0));
    +-
    +-        assertNull(getPackageShortcut(CALLING_PACKAGE_1, "s1", USER_10));
    +-        assertNull(getPackageShortcut(CALLING_PACKAGE_1, "s2", USER_10));
    +-        assertNull(getPackageShortcut(CALLING_PACKAGE_1, "s3", USER_10));
    +-
    +-        mService.checkPackageChanges(USER_P0);
    +-
    +-        assertDynamicAndPinned(getPackageShortcut(CALLING_PACKAGE_1, "s1", USER_0));
    +-        assertDynamicOnly(getPackageShortcut(CALLING_PACKAGE_1, "s2", USER_0));
    +-        assertDynamicOnly(getPackageShortcut(CALLING_PACKAGE_1, "s3", USER_0));
    +-
    +-        assertDynamicOnly(getPackageShortcut(CALLING_PACKAGE_1, "s1", USER_P0));
    +-        assertDynamicAndPinned(getPackageShortcut(CALLING_PACKAGE_1, "s2", USER_P0));
    +-        assertDynamicOnly(getPackageShortcut(CALLING_PACKAGE_1, "s3", USER_P0));
    +-
    +-        assertDynamicOnly(getPackageShortcut(CALLING_PACKAGE_2, "s1", USER_0));
    +-        assertDynamicOnly(getPackageShortcut(CALLING_PACKAGE_2, "s2", USER_0));
    +-        assertDynamicAndPinned(getPackageShortcut(CALLING_PACKAGE_2, "s3", USER_0));
    +-
    +-        assertNull(getPackageShortcut(CALLING_PACKAGE_1, "s1", USER_10));
    +-        assertNull(getPackageShortcut(CALLING_PACKAGE_1, "s2", USER_10));
    +-        assertNull(getPackageShortcut(CALLING_PACKAGE_1, "s3", USER_10));
    +-
    +-        uninstallPackage(USER_P0, CALLING_PACKAGE_1);
    +-
    +-        mService.saveDirtyInfo();
    +-        initService();
    +-        mService.handleUnlockUser(USER_0);
    +-        mService.handleUnlockUser(USER_P0);
    +-        mService.handleUnlockUser(USER_10);
    +-
    +-        assertDynamicAndPinned(getPackageShortcut(CALLING_PACKAGE_1, "s1", USER_0));
    +-        assertDynamicOnly(getPackageShortcut(CALLING_PACKAGE_1, "s2", USER_0));
    +-        assertDynamicOnly(getPackageShortcut(CALLING_PACKAGE_1, "s3", USER_0));
    +-
    +-        assertNull(getPackageShortcut(CALLING_PACKAGE_1, "s1", USER_P0));
    +-        assertNull(getPackageShortcut(CALLING_PACKAGE_1, "s2", USER_P0));
    +-        assertNull(getPackageShortcut(CALLING_PACKAGE_1, "s3", USER_P0));
    +-
    +-        assertDynamicOnly(getPackageShortcut(CALLING_PACKAGE_2, "s1", USER_0));
    +-        assertDynamicOnly(getPackageShortcut(CALLING_PACKAGE_2, "s2", USER_0));
    +-        assertDynamicAndPinned(getPackageShortcut(CALLING_PACKAGE_2, "s3", USER_0));
    +-
    +-        assertNull(getPackageShortcut(CALLING_PACKAGE_1, "s1", USER_10));
    +-        assertNull(getPackageShortcut(CALLING_PACKAGE_1, "s2", USER_10));
    +-        assertNull(getPackageShortcut(CALLING_PACKAGE_1, "s3", USER_10));
    +-
    +-        // Uninstall
    +-        uninstallPackage(USER_0, LAUNCHER_1);
    +-
    +-        mService.saveDirtyInfo();
    +-        initService();
    +-        mService.handleUnlockUser(USER_0);
    +-        mService.handleUnlockUser(USER_P0);
    +-        mService.handleUnlockUser(USER_10);
    +-
    +-        assertDynamicOnly(getPackageShortcut(CALLING_PACKAGE_1, "s1", USER_0));
    +-        assertDynamicOnly(getPackageShortcut(CALLING_PACKAGE_1, "s2", USER_0));
    +-        assertDynamicOnly(getPackageShortcut(CALLING_PACKAGE_1, "s3", USER_0));
    +-
    +-        assertNull(getPackageShortcut(CALLING_PACKAGE_1, "s1", USER_P0));
    +-        assertNull(getPackageShortcut(CALLING_PACKAGE_1, "s2", USER_P0));
    +-        assertNull(getPackageShortcut(CALLING_PACKAGE_1, "s3", USER_P0));
    +-
    +-        assertDynamicOnly(getPackageShortcut(CALLING_PACKAGE_2, "s1", USER_0));
    +-        assertDynamicOnly(getPackageShortcut(CALLING_PACKAGE_2, "s2", USER_0));
    +-        assertDynamicOnly(getPackageShortcut(CALLING_PACKAGE_2, "s3", USER_0));
    +-
    +-        assertNull(getPackageShortcut(CALLING_PACKAGE_1, "s1", USER_10));
    +-        assertNull(getPackageShortcut(CALLING_PACKAGE_1, "s2", USER_10));
    +-        assertNull(getPackageShortcut(CALLING_PACKAGE_1, "s3", USER_10));
    +-
    +-        uninstallPackage(USER_0, CALLING_PACKAGE_2);
    +-
    +-        mService.saveDirtyInfo();
    +-        initService();
    +-        mService.handleUnlockUser(USER_0);
    +-        mService.handleUnlockUser(USER_P0);
    +-        mService.handleUnlockUser(USER_10);
    +-
    +-        assertDynamicOnly(getPackageShortcut(CALLING_PACKAGE_1, "s1", USER_0));
    +-        assertDynamicOnly(getPackageShortcut(CALLING_PACKAGE_1, "s2", USER_0));
    +-        assertDynamicOnly(getPackageShortcut(CALLING_PACKAGE_1, "s3", USER_0));
    +-
    +-        assertNull(getPackageShortcut(CALLING_PACKAGE_1, "s1", USER_P0));
    +-        assertNull(getPackageShortcut(CALLING_PACKAGE_1, "s2", USER_P0));
    +-        assertNull(getPackageShortcut(CALLING_PACKAGE_1, "s3", USER_P0));
    +-
    +-        assertNull(getPackageShortcut(CALLING_PACKAGE_2, "s1", USER_0));
    +-        assertNull(getPackageShortcut(CALLING_PACKAGE_2, "s2", USER_0));
    +-        assertNull(getPackageShortcut(CALLING_PACKAGE_2, "s3", USER_0));
    +-
    +-        assertNull(getPackageShortcut(CALLING_PACKAGE_1, "s1", USER_10));
    +-        assertNull(getPackageShortcut(CALLING_PACKAGE_1, "s2", USER_10));
    +-        assertNull(getPackageShortcut(CALLING_PACKAGE_1, "s3", USER_10));
    +-    }
    +-
    +-    protected void checkCanRestoreTo(boolean expected, ShortcutPackageInfo spi,
    +-            int version, String... signatures) {
    +-        assertEquals(expected, spi.canRestoreTo(mService, genPackage(
    +-                "dummy", /* uid */ 0, version, signatures)));
    +-    }
    +-
    +-    public void testCanRestoreTo() {
    +-        addPackage(CALLING_PACKAGE_1, CALLING_UID_1, 10, "sig1");
    +-        addPackage(CALLING_PACKAGE_2, CALLING_UID_1, 10, "sig1", "sig2");
    +-
    +-        final ShortcutPackageInfo spi1 = ShortcutPackageInfo.generateForInstalledPackage(
    +-                mService, CALLING_PACKAGE_1, USER_0);
    +-        final ShortcutPackageInfo spi2 = ShortcutPackageInfo.generateForInstalledPackage(
    +-                mService, CALLING_PACKAGE_2, USER_0);
    +-
    +-        checkCanRestoreTo(true, spi1, 10, "sig1");
    +-        checkCanRestoreTo(true, spi1, 10, "x", "sig1");
    +-        checkCanRestoreTo(true, spi1, 10, "sig1", "y");
    +-        checkCanRestoreTo(true, spi1, 10, "x", "sig1", "y");
    +-        checkCanRestoreTo(true, spi1, 11, "sig1");
    +-
    +-        checkCanRestoreTo(false, spi1, 10 /* empty */);
    +-        checkCanRestoreTo(false, spi1, 10, "x");
    +-        checkCanRestoreTo(false, spi1, 10, "x", "y");
    +-        checkCanRestoreTo(false, spi1, 10, "x");
    +-        checkCanRestoreTo(false, spi1, 9, "sig1");
    +-
    +-        checkCanRestoreTo(true, spi2, 10, "sig1", "sig2");
    +-        checkCanRestoreTo(true, spi2, 10, "sig2", "sig1");
    +-        checkCanRestoreTo(true, spi2, 10, "x", "sig1", "sig2");
    +-        checkCanRestoreTo(true, spi2, 10, "x", "sig2", "sig1");
    +-        checkCanRestoreTo(true, spi2, 10, "sig1", "sig2", "y");
    +-        checkCanRestoreTo(true, spi2, 10, "sig2", "sig1", "y");
    +-        checkCanRestoreTo(true, spi2, 10, "x", "sig1", "sig2", "y");
    +-        checkCanRestoreTo(true, spi2, 10, "x", "sig2", "sig1", "y");
    +-        checkCanRestoreTo(true, spi2, 11, "x", "sig2", "sig1", "y");
    +-
    +-        checkCanRestoreTo(false, spi2, 10, "sig1", "sig2x");
    +-        checkCanRestoreTo(false, spi2, 10, "sig2", "sig1x");
    +-        checkCanRestoreTo(false, spi2, 10, "x", "sig1x", "sig2");
    +-        checkCanRestoreTo(false, spi2, 10, "x", "sig2x", "sig1");
    +-        checkCanRestoreTo(false, spi2, 10, "sig1", "sig2x", "y");
    +-        checkCanRestoreTo(false, spi2, 10, "sig2", "sig1x", "y");
    +-        checkCanRestoreTo(false, spi2, 10, "x", "sig1x", "sig2", "y");
    +-        checkCanRestoreTo(false, spi2, 10, "x", "sig2x", "sig1", "y");
    +-        checkCanRestoreTo(false, spi2, 11, "x", "sig2x", "sig1", "y");
    +-    }
    +-
    +-    public void testHandlePackageDelete() {
    +-        final Icon bmp32x32 = Icon.createWithBitmap(BitmapFactory.decodeResource(
    +-                getTestContext().getResources(), R.drawable.black_32x32));
    +-        setCaller(CALLING_PACKAGE_1, USER_0);
    +-        assertTrue(mManager.addDynamicShortcuts(list(
    +-                makeShortcutWithIcon("s1", bmp32x32), makeShortcutWithIcon("s2", bmp32x32)
    +-        )));
    +-        // Also add a manifest shortcut, which should be removed too.
    +-        addManifestShortcutResource(
    +-                new ComponentName(CALLING_PACKAGE_1, ShortcutActivity.class.getName()),
    +-                R.xml.shortcut_1);
    +-        updatePackageVersion(CALLING_PACKAGE_1, 1);
    +-                mService.mPackageMonitor.onReceive(getTestContext(),
    +-                genPackageAddIntent(CALLING_PACKAGE_1, USER_0));
    +-        runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
    +-            assertWith(getCallerShortcuts())
    +-                    .haveIds("s1", "s2", "ms1")
    +-
    +-                    .selectManifest()
    +-                    .haveIds("ms1");
    +-        });
    +-
    +-        setCaller(CALLING_PACKAGE_2, USER_0);
    +-        assertTrue(mManager.addDynamicShortcuts(list(makeShortcutWithIcon("s1", bmp32x32))));
    +-
    +-        setCaller(CALLING_PACKAGE_3, USER_0);
    +-        assertTrue(mManager.addDynamicShortcuts(list(makeShortcutWithIcon("s1", bmp32x32))));
    +-
    +-        mRunningUsers.put(USER_10, true);
    +-
    +-        setCaller(CALLING_PACKAGE_1, USER_10);
    +-        assertTrue(mManager.addDynamicShortcuts(list(makeShortcutWithIcon("s1", bmp32x32))));
    +-
    +-        setCaller(CALLING_PACKAGE_2, USER_10);
    +-        assertTrue(mManager.addDynamicShortcuts(list(makeShortcutWithIcon("s1", bmp32x32))));
    +-
    +-        setCaller(CALLING_PACKAGE_3, USER_10);
    +-        assertTrue(mManager.addDynamicShortcuts(list(makeShortcutWithIcon("s1", bmp32x32))));
    +-
    +-        assertNotNull(mService.getPackageShortcutForTest(CALLING_PACKAGE_1, "s1", USER_0));
    +-        assertNotNull(mService.getPackageShortcutForTest(CALLING_PACKAGE_2, "s1", USER_0));
    +-        assertNotNull(mService.getPackageShortcutForTest(CALLING_PACKAGE_3, "s1", USER_0));
    +-        assertNotNull(mService.getPackageShortcutForTest(CALLING_PACKAGE_1, "s1", USER_10));
    +-        assertNotNull(mService.getPackageShortcutForTest(CALLING_PACKAGE_2, "s1", USER_10));
    +-        assertNotNull(mService.getPackageShortcutForTest(CALLING_PACKAGE_3, "s1", USER_10));
    +-
    +-        assertTrue(bitmapDirectoryExists(CALLING_PACKAGE_1, USER_0));
    +-        assertTrue(bitmapDirectoryExists(CALLING_PACKAGE_2, USER_0));
    +-        assertTrue(bitmapDirectoryExists(CALLING_PACKAGE_3, USER_0));
    +-        assertTrue(bitmapDirectoryExists(CALLING_PACKAGE_1, USER_10));
    +-        assertTrue(bitmapDirectoryExists(CALLING_PACKAGE_2, USER_10));
    +-        assertTrue(bitmapDirectoryExists(CALLING_PACKAGE_3, USER_10));
    +-
    +-        uninstallPackage(USER_0, CALLING_PACKAGE_1);
    +-                mService.mPackageMonitor.onReceive(getTestContext(),
    +-                genPackageDeleteIntent(CALLING_PACKAGE_1, USER_0));
    +-
    +-        assertNull(mService.getPackageShortcutForTest(CALLING_PACKAGE_1, "s1", USER_0));
    +-        assertNotNull(mService.getPackageShortcutForTest(CALLING_PACKAGE_2, "s1", USER_0));
    +-        assertNotNull(mService.getPackageShortcutForTest(CALLING_PACKAGE_3, "s1", USER_0));
    +-        assertNotNull(mService.getPackageShortcutForTest(CALLING_PACKAGE_1, "s1", USER_10));
    +-        assertNotNull(mService.getPackageShortcutForTest(CALLING_PACKAGE_2, "s1", USER_10));
    +-        assertNotNull(mService.getPackageShortcutForTest(CALLING_PACKAGE_3, "s1", USER_10));
    +-
    +-        assertFalse(bitmapDirectoryExists(CALLING_PACKAGE_1, USER_0));
    +-        assertTrue(bitmapDirectoryExists(CALLING_PACKAGE_2, USER_0));
    +-        assertTrue(bitmapDirectoryExists(CALLING_PACKAGE_3, USER_0));
    +-        assertTrue(bitmapDirectoryExists(CALLING_PACKAGE_1, USER_10));
    +-        assertTrue(bitmapDirectoryExists(CALLING_PACKAGE_2, USER_10));
    +-        assertTrue(bitmapDirectoryExists(CALLING_PACKAGE_3, USER_10));
    +-
    +-        mRunningUsers.put(USER_10, true);
    +-
    +-        uninstallPackage(USER_10, CALLING_PACKAGE_2);
    +-                mService.mPackageMonitor.onReceive(getTestContext(),
    +-                genPackageDeleteIntent(CALLING_PACKAGE_2, USER_10));
    +-
    +-        assertNull(mService.getPackageShortcutForTest(CALLING_PACKAGE_1, "s1", USER_0));
    +-        assertNotNull(mService.getPackageShortcutForTest(CALLING_PACKAGE_2, "s1", USER_0));
    +-        assertNotNull(mService.getPackageShortcutForTest(CALLING_PACKAGE_3, "s1", USER_0));
    +-        assertNotNull(mService.getPackageShortcutForTest(CALLING_PACKAGE_1, "s1", USER_10));
    +-        assertNull(mService.getPackageShortcutForTest(CALLING_PACKAGE_2, "s1", USER_10));
    +-        assertNotNull(mService.getPackageShortcutForTest(CALLING_PACKAGE_3, "s1", USER_10));
    +-
    +-        assertFalse(bitmapDirectoryExists(CALLING_PACKAGE_1, USER_0));
    +-        assertTrue(bitmapDirectoryExists(CALLING_PACKAGE_2, USER_0));
    +-        assertTrue(bitmapDirectoryExists(CALLING_PACKAGE_3, USER_0));
    +-        assertTrue(bitmapDirectoryExists(CALLING_PACKAGE_1, USER_10));
    +-        assertFalse(bitmapDirectoryExists(CALLING_PACKAGE_2, USER_10));
    +-        assertTrue(bitmapDirectoryExists(CALLING_PACKAGE_3, USER_10));
    +-
    +-        mInjectedPackages.remove(CALLING_PACKAGE_1);
    +-        mInjectedPackages.remove(CALLING_PACKAGE_3);
    +-
    +-        mService.handleUnlockUser(USER_0);
    +-
    +-        assertNull(mService.getPackageShortcutForTest(CALLING_PACKAGE_1, "s1", USER_0));
    +-        assertNotNull(mService.getPackageShortcutForTest(CALLING_PACKAGE_2, "s1", USER_0));
    +-        assertNull(mService.getPackageShortcutForTest(CALLING_PACKAGE_3, "s1", USER_0));
    +-        assertNotNull(mService.getPackageShortcutForTest(CALLING_PACKAGE_1, "s1", USER_10));
    +-        assertNull(mService.getPackageShortcutForTest(CALLING_PACKAGE_2, "s1", USER_10));
    +-        assertNotNull(mService.getPackageShortcutForTest(CALLING_PACKAGE_3, "s1", USER_10));
    +-
    +-        assertFalse(bitmapDirectoryExists(CALLING_PACKAGE_1, USER_0));
    +-        assertTrue(bitmapDirectoryExists(CALLING_PACKAGE_2, USER_0));
    +-        assertFalse(bitmapDirectoryExists(CALLING_PACKAGE_3, USER_0));
    +-        assertTrue(bitmapDirectoryExists(CALLING_PACKAGE_1, USER_10));
    +-        assertFalse(bitmapDirectoryExists(CALLING_PACKAGE_2, USER_10));
    +-        assertTrue(bitmapDirectoryExists(CALLING_PACKAGE_3, USER_10));
    +-
    +-        mService.handleUnlockUser(USER_10);
    +-
    +-        assertNull(mService.getPackageShortcutForTest(CALLING_PACKAGE_1, "s1", USER_0));
    +-        assertNotNull(mService.getPackageShortcutForTest(CALLING_PACKAGE_2, "s1", USER_0));
    +-        assertNull(mService.getPackageShortcutForTest(CALLING_PACKAGE_3, "s1", USER_0));
    +-        assertNull(mService.getPackageShortcutForTest(CALLING_PACKAGE_1, "s1", USER_10));
    +-        assertNull(mService.getPackageShortcutForTest(CALLING_PACKAGE_2, "s1", USER_10));
    +-        assertNull(mService.getPackageShortcutForTest(CALLING_PACKAGE_3, "s1", USER_10));
    +-
    +-        assertFalse(bitmapDirectoryExists(CALLING_PACKAGE_1, USER_0));
    +-        assertTrue(bitmapDirectoryExists(CALLING_PACKAGE_2, USER_0));
    +-        assertFalse(bitmapDirectoryExists(CALLING_PACKAGE_3, USER_0));
    +-        assertFalse(bitmapDirectoryExists(CALLING_PACKAGE_1, USER_10));
    +-        assertFalse(bitmapDirectoryExists(CALLING_PACKAGE_2, USER_10));
    +-        assertFalse(bitmapDirectoryExists(CALLING_PACKAGE_3, USER_10));
    +-    }
    +-
    +-    /** Almost ame as testHandlePackageDelete, except it doesn't uninstall packages. */
    +-    public void testHandlePackageClearData() {
    +-        final Icon bmp32x32 = Icon.createWithBitmap(BitmapFactory.decodeResource(
    +-                getTestContext().getResources(), R.drawable.black_32x32));
    +-        setCaller(CALLING_PACKAGE_1, USER_0);
    +-        assertTrue(mManager.addDynamicShortcuts(list(
    +-                makeShortcutWithIcon("s1", bmp32x32), makeShortcutWithIcon("s2", bmp32x32)
    +-        )));
    +-
    +-        setCaller(CALLING_PACKAGE_2, USER_0);
    +-        assertTrue(mManager.addDynamicShortcuts(list(makeShortcutWithIcon("s1", bmp32x32))));
    +-
    +-        setCaller(CALLING_PACKAGE_3, USER_0);
    +-        assertTrue(mManager.addDynamicShortcuts(list(makeShortcutWithIcon("s1", bmp32x32))));
    +-
    +-        mRunningUsers.put(USER_10, true);
    +-
    +-        setCaller(CALLING_PACKAGE_1, USER_10);
    +-        assertTrue(mManager.addDynamicShortcuts(list(makeShortcutWithIcon("s1", bmp32x32))));
    +-
    +-        setCaller(CALLING_PACKAGE_2, USER_10);
    +-        assertTrue(mManager.addDynamicShortcuts(list(makeShortcutWithIcon("s1", bmp32x32))));
    +-
    +-        setCaller(CALLING_PACKAGE_3, USER_10);
    +-        assertTrue(mManager.addDynamicShortcuts(list(makeShortcutWithIcon("s1", bmp32x32))));
    +-
    +-        assertNotNull(mService.getPackageShortcutForTest(CALLING_PACKAGE_1, "s1", USER_0));
    +-        assertNotNull(mService.getPackageShortcutForTest(CALLING_PACKAGE_2, "s1", USER_0));
    +-        assertNotNull(mService.getPackageShortcutForTest(CALLING_PACKAGE_3, "s1", USER_0));
    +-        assertNotNull(mService.getPackageShortcutForTest(CALLING_PACKAGE_1, "s1", USER_10));
    +-        assertNotNull(mService.getPackageShortcutForTest(CALLING_PACKAGE_2, "s1", USER_10));
    +-        assertNotNull(mService.getPackageShortcutForTest(CALLING_PACKAGE_3, "s1", USER_10));
    +-
    +-        assertTrue(bitmapDirectoryExists(CALLING_PACKAGE_1, USER_0));
    +-        assertTrue(bitmapDirectoryExists(CALLING_PACKAGE_2, USER_0));
    +-        assertTrue(bitmapDirectoryExists(CALLING_PACKAGE_3, USER_0));
    +-        assertTrue(bitmapDirectoryExists(CALLING_PACKAGE_1, USER_10));
    +-        assertTrue(bitmapDirectoryExists(CALLING_PACKAGE_2, USER_10));
    +-        assertTrue(bitmapDirectoryExists(CALLING_PACKAGE_3, USER_10));
    +-
    +-                mService.mPackageMonitor.onReceive(getTestContext(),
    +-                genPackageDataClear(CALLING_PACKAGE_1, USER_0));
    +-
    +-        assertNull(mService.getPackageShortcutForTest(CALLING_PACKAGE_1, "s1", USER_0));
    +-        assertNotNull(mService.getPackageShortcutForTest(CALLING_PACKAGE_2, "s1", USER_0));
    +-        assertNotNull(mService.getPackageShortcutForTest(CALLING_PACKAGE_3, "s1", USER_0));
    +-        assertNotNull(mService.getPackageShortcutForTest(CALLING_PACKAGE_1, "s1", USER_10));
    +-        assertNotNull(mService.getPackageShortcutForTest(CALLING_PACKAGE_2, "s1", USER_10));
    +-        assertNotNull(mService.getPackageShortcutForTest(CALLING_PACKAGE_3, "s1", USER_10));
    +-
    +-        assertFalse(bitmapDirectoryExists(CALLING_PACKAGE_1, USER_0));
    +-        assertTrue(bitmapDirectoryExists(CALLING_PACKAGE_2, USER_0));
    +-        assertTrue(bitmapDirectoryExists(CALLING_PACKAGE_3, USER_0));
    +-        assertTrue(bitmapDirectoryExists(CALLING_PACKAGE_1, USER_10));
    +-        assertTrue(bitmapDirectoryExists(CALLING_PACKAGE_2, USER_10));
    +-        assertTrue(bitmapDirectoryExists(CALLING_PACKAGE_3, USER_10));
    +-
    +-        mRunningUsers.put(USER_10, true);
    +-
    +-                mService.mPackageMonitor.onReceive(getTestContext(),
    +-                genPackageDataClear(CALLING_PACKAGE_2, USER_10));
    +-
    +-        assertNull(mService.getPackageShortcutForTest(CALLING_PACKAGE_1, "s1", USER_0));
    +-        assertNotNull(mService.getPackageShortcutForTest(CALLING_PACKAGE_2, "s1", USER_0));
    +-        assertNotNull(mService.getPackageShortcutForTest(CALLING_PACKAGE_3, "s1", USER_0));
    +-        assertNotNull(mService.getPackageShortcutForTest(CALLING_PACKAGE_1, "s1", USER_10));
    +-        assertNull(mService.getPackageShortcutForTest(CALLING_PACKAGE_2, "s1", USER_10));
    +-        assertNotNull(mService.getPackageShortcutForTest(CALLING_PACKAGE_3, "s1", USER_10));
    +-
    +-        assertFalse(bitmapDirectoryExists(CALLING_PACKAGE_1, USER_0));
    +-        assertTrue(bitmapDirectoryExists(CALLING_PACKAGE_2, USER_0));
    +-        assertTrue(bitmapDirectoryExists(CALLING_PACKAGE_3, USER_0));
    +-        assertTrue(bitmapDirectoryExists(CALLING_PACKAGE_1, USER_10));
    +-        assertFalse(bitmapDirectoryExists(CALLING_PACKAGE_2, USER_10));
    +-        assertTrue(bitmapDirectoryExists(CALLING_PACKAGE_3, USER_10));
    +-    }
    +-
    +-    public void testHandlePackageClearData_manifestRepublished() {
    +-
    +-        mRunningUsers.put(USER_10, true);
    +-
    +-        // Add two manifests and two dynamics.
    +-        addManifestShortcutResource(
    +-                new ComponentName(CALLING_PACKAGE_1, ShortcutActivity.class.getName()),
    +-                R.xml.shortcut_2);
    +-        updatePackageVersion(CALLING_PACKAGE_1, 1);
    +-                mService.mPackageMonitor.onReceive(getTestContext(),
    +-                genPackageAddIntent(CALLING_PACKAGE_1, USER_10));
    +-
    +-        runWithCaller(CALLING_PACKAGE_1, USER_10, () -> {
    +-            assertTrue(mManager.addDynamicShortcuts(list(
    +-                    makeShortcut("s1"), makeShortcut("s2"))));
    +-        });
    +-        runWithCaller(LAUNCHER_1, USER_10, () -> {
    +-            mLauncherApps.pinShortcuts(CALLING_PACKAGE_1, list("ms2", "s2"), HANDLE_USER_10);
    +-        });
    +-
    +-        runWithCaller(CALLING_PACKAGE_1, USER_10, () -> {
    +-            assertWith(getCallerShortcuts())
    +-                    .haveIds("ms1", "ms2", "s1", "s2")
    +-                    .areAllEnabled()
    +-
    +-                    .selectPinned()
    +-                    .haveIds("ms2", "s2");
    +-        });
    +-
    +-        // Clear data
    +-        mService.mPackageMonitor.onReceive(getTestContext(),
    +-                genPackageDataClear(CALLING_PACKAGE_1, USER_10));
    +-
    +-        // Only manifest shortcuts will remain, and are no longer pinned.
    +-        runWithCaller(CALLING_PACKAGE_1, USER_10, () -> {
    +-            assertWith(getCallerShortcuts())
    +-                    .haveIds("ms1", "ms2")
    +-                    .areAllEnabled()
    +-                    .areAllNotPinned();
    +-        });
    +-    }
    +-
    +-    public void testHandlePackageUpdate() throws Throwable {
    +-        // Set up shortcuts and launchers.
    +-
    +-        final Icon res32x32 = Icon.createWithResource(getTestContext(), R.drawable.black_32x32);
    +-        final Icon bmp32x32 = Icon.createWithBitmap(BitmapFactory.decodeResource(
    +-                getTestContext().getResources(), R.drawable.black_32x32));
    +-
    +-        runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
    +-            assertTrue(mManager.setDynamicShortcuts(list(
    +-                    makeShortcut("s1"),
    +-                    makeShortcutWithIcon("s2", res32x32),
    +-                    makeShortcutWithIcon("s3", res32x32),
    +-                    makeShortcutWithIcon("s4", bmp32x32))));
    +-        });
    +-        runWithCaller(CALLING_PACKAGE_2, USER_0, () -> {
    +-            assertTrue(mManager.setDynamicShortcuts(list(
    +-                    makeShortcut("s1"),
    +-                    makeShortcutWithIcon("s2", bmp32x32))));
    +-        });
    +-        runWithCaller(CALLING_PACKAGE_3, USER_0, () -> {
    +-            assertTrue(mManager.setDynamicShortcuts(list(
    +-                    makeShortcutWithIcon("s1", res32x32))));
    +-        });
    +-
    +-        mRunningUsers.put(USER_10, true);
    +-
    +-        runWithCaller(CALLING_PACKAGE_1, USER_10, () -> {
    +-            assertTrue(mManager.setDynamicShortcuts(list(
    +-                    makeShortcutWithIcon("s1", res32x32),
    +-                    makeShortcutWithIcon("s2", res32x32))));
    +-        });
    +-        runWithCaller(CALLING_PACKAGE_2, USER_10, () -> {
    +-            assertTrue(mManager.setDynamicShortcuts(list(
    +-                    makeShortcutWithIcon("s1", bmp32x32),
    +-                    makeShortcutWithIcon("s2", bmp32x32))));
    +-        });
    +-
    +-        LauncherApps.Callback c0 = mock(LauncherApps.Callback.class);
    +-        LauncherApps.Callback c10 = mock(LauncherApps.Callback.class);
    +-
    +-        runWithCaller(LAUNCHER_1, USER_0, () -> {
    +-            mLauncherApps.registerCallback(c0, new Handler(Looper.getMainLooper()));
    +-        });
    +-        runWithCaller(LAUNCHER_1, USER_10, () -> {
    +-            mLauncherApps.registerCallback(c10, new Handler(Looper.getMainLooper()));
    +-        });
    +-
    +-        mInjectedCurrentTimeMillis = START_TIME + 100;
    +-
    +-        ArgumentCaptor<List> shortcuts;
    +-
    +-        // Update the version info for package 1.
    +-        reset(c0);
    +-        reset(c10);
    +-        updatePackageVersion(CALLING_PACKAGE_1, 1);
    +-
    +-        // Then send the broadcast, to only user-0.
    +-                mService.mPackageMonitor.onReceive(getTestContext(),
    +-                genPackageUpdateIntent(CALLING_PACKAGE_1, USER_0));
    +-
    +-        waitOnMainThread();
    +-
    +-        // User-0 should get the notification.
    +-        shortcuts = ArgumentCaptor.forClass(List.class);
    +-        verify(c0).onShortcutsChanged(
    +-                eq(CALLING_PACKAGE_1),
    +-                shortcuts.capture(),
    +-                eq(HANDLE_USER_0));
    +-
    +-        // User-10 shouldn't yet get the notification.
    +-        verify(c10, times(0)).onShortcutsChanged(
    +-                eq(CALLING_PACKAGE_1),
    +-                any(List.class),
    +-                any(UserHandle.class));
    +-        assertShortcutIds(shortcuts.getValue(), "s1", "s2", "s3", "s4");
    +-        assertEquals(START_TIME,
    +-                findShortcut(shortcuts.getValue(), "s1").getLastChangedTimestamp());
    +-        assertEquals(START_TIME + 100,
    +-                findShortcut(shortcuts.getValue(), "s2").getLastChangedTimestamp());
    +-        assertEquals(START_TIME + 100,
    +-                findShortcut(shortcuts.getValue(), "s3").getLastChangedTimestamp());
    +-        assertEquals(START_TIME,
    +-                findShortcut(shortcuts.getValue(), "s4").getLastChangedTimestamp());
    +-
    +-        // Next, send unlock even on user-10.  Now we scan packages on this user and send a
    +-        // notification to the launcher.
    +-        mInjectedCurrentTimeMillis = START_TIME + 200;
    +-
    +-        mRunningUsers.put(USER_10, true);
    +-
    +-        reset(c0);
    +-        reset(c10);
    +-        mService.handleUnlockUser(USER_10);
    +-
    +-        waitOnMainThread();
    +-
    +-        shortcuts = ArgumentCaptor.forClass(List.class);
    +-        verify(c0, times(0)).onShortcutsChanged(
    +-                eq(CALLING_PACKAGE_1),
    +-                any(List.class),
    +-                any(UserHandle.class));
    +-
    +-        verify(c10).onShortcutsChanged(
    +-                eq(CALLING_PACKAGE_1),
    +-                shortcuts.capture(),
    +-                eq(HANDLE_USER_10));
    +-
    +-        assertShortcutIds(shortcuts.getValue(), "s1", "s2");
    +-        assertEquals(START_TIME + 200,
    +-                findShortcut(shortcuts.getValue(), "s1").getLastChangedTimestamp());
    +-        assertEquals(START_TIME + 200,
    +-                findShortcut(shortcuts.getValue(), "s2").getLastChangedTimestamp());
    +-
    +-
    +-        // Do the same thing for package 2, which doesn't have resource icons.
    +-        mInjectedCurrentTimeMillis = START_TIME + 300;
    +-
    +-        reset(c0);
    +-        reset(c10);
    +-        updatePackageVersion(CALLING_PACKAGE_2, 10);
    +-
    +-        // Then send the broadcast, to only user-0.
    +-                mService.mPackageMonitor.onReceive(getTestContext(),
    +-                genPackageUpdateIntent(CALLING_PACKAGE_2, USER_0));
    +-        mService.handleUnlockUser(USER_10);
    +-
    +-        waitOnMainThread();
    +-
    +-        verify(c0, times(0)).onShortcutsChanged(
    +-                eq(CALLING_PACKAGE_1),
    +-                any(List.class),
    +-                any(UserHandle.class));
    +-
    +-        verify(c10, times(0)).onShortcutsChanged(
    +-                eq(CALLING_PACKAGE_1),
    +-                any(List.class),
    +-                any(UserHandle.class));
    +-
    +-        // Do the same thing for package 3
    +-        mInjectedCurrentTimeMillis = START_TIME + 400;
    +-
    +-        reset(c0);
    +-        reset(c10);
    +-        updatePackageVersion(CALLING_PACKAGE_3, 100);
    +-
    +-        // Then send the broadcast, to only user-0.
    +-                mService.mPackageMonitor.onReceive(getTestContext(),
    +-                genPackageUpdateIntent(CALLING_PACKAGE_3, USER_0));
    +-        mService.handleUnlockUser(USER_10);
    +-
    +-        waitOnMainThread();
    +-
    +-        shortcuts = ArgumentCaptor.forClass(List.class);
    +-        verify(c0).onShortcutsChanged(
    +-                eq(CALLING_PACKAGE_3),
    +-                shortcuts.capture(),
    +-                eq(HANDLE_USER_0));
    +-
    +-        // User 10 doesn't have package 3, so no callback.
    +-        verify(c10, times(0)).onShortcutsChanged(
    +-                eq(CALLING_PACKAGE_3),
    +-                any(List.class),
    +-                any(UserHandle.class));
    +-
    +-        assertShortcutIds(shortcuts.getValue(), "s1");
    +-        assertEquals(START_TIME + 400,
    +-                findShortcut(shortcuts.getValue(), "s1").getLastChangedTimestamp());
    +-    }
    +-
    +-    /**
    +-     * Test the case where an updated app has resource IDs changed.
    +-     */
    +-    public void testHandlePackageUpdate_resIdChanged() throws Exception {
    +-        final Icon icon1 = Icon.createWithResource(getTestContext(), /* res ID */ 1000);
    +-        final Icon icon2 = Icon.createWithResource(getTestContext(), /* res ID */ 1001);
    +-
    +-        // Set up shortcuts.
    +-        runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
    +-            // Note resource strings are not officially supported (they're hidden), but
    +-            // should work.
    +-
    +-            final ShortcutInfo s1 = new ShortcutInfo.Builder(mClientContext)
    +-                    .setId("s1")
    +-                    .setActivity(makeComponent(ShortcutActivity.class))
    +-                    .setIntent(new Intent(Intent.ACTION_VIEW))
    +-                    .setIcon(icon1)
    +-                    .setTitleResId(10000)
    +-                    .setTextResId(10001)
    +-                    .setDisabledMessageResId(10002)
    +-                    .build();
    +-
    +-            final ShortcutInfo s2 = new ShortcutInfo.Builder(mClientContext)
    +-                    .setId("s2")
    +-                    .setActivity(makeComponent(ShortcutActivity.class))
    +-                    .setIntent(new Intent(Intent.ACTION_VIEW))
    +-                    .setIcon(icon2)
    +-                    .setTitleResId(20000)
    +-                    .build();
    +-
    +-            assertTrue(mManager.setDynamicShortcuts(list(s1, s2)));
    +-        });
    +-
    +-        // Verify.
    +-        runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
    +-            final ShortcutInfo s1 = getCallerShortcut("s1");
    +-            final ShortcutInfo s2 = getCallerShortcut("s2");
    +-
    +-            assertEquals(1000, s1.getIconResourceId());
    +-            assertEquals(10000, s1.getTitleResId());
    +-            assertEquals(10001, s1.getTextResId());
    +-            assertEquals(10002, s1.getDisabledMessageResourceId());
    +-
    +-            assertEquals(1001, s2.getIconResourceId());
    +-            assertEquals(20000, s2.getTitleResId());
    +-            assertEquals(0, s2.getTextResId());
    +-            assertEquals(0, s2.getDisabledMessageResourceId());
    +-        });
    +-
    +-        mService.saveDirtyInfo();
    +-        initService();
    +-
    +-        // Set up the mock resources again, with an "adjustment".
    +-        // When the package is updated, the service will fetch the updated res-IDs with res-names,
    +-        // and the new IDs will have this offset.
    +-        setUpAppResources(10);
    +-
    +-        // Update the package.
    +-        updatePackageVersion(CALLING_PACKAGE_1, 1);
    +-                mService.mPackageMonitor.onReceive(getTestContext(),
    +-                genPackageUpdateIntent(CALLING_PACKAGE_1, USER_0));
    +-
    +-        runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
    +-            final ShortcutInfo s1 = getCallerShortcut("s1");
    +-            final ShortcutInfo s2 = getCallerShortcut("s2");
    +-
    +-            assertEquals(1010, s1.getIconResourceId());
    +-            assertEquals(10010, s1.getTitleResId());
    +-            assertEquals(10011, s1.getTextResId());
    +-            assertEquals(10012, s1.getDisabledMessageResourceId());
    +-
    +-            assertEquals(1011, s2.getIconResourceId());
    +-            assertEquals(20010, s2.getTitleResId());
    +-            assertEquals(0, s2.getTextResId());
    +-            assertEquals(0, s2.getDisabledMessageResourceId());
    +-        });
    +-    }
    +-
    +-    public void testHandlePackageChanged() {
    +-        final ComponentName ACTIVITY1 = new ComponentName(CALLING_PACKAGE_1, "act1");
    +-        final ComponentName ACTIVITY2 = new ComponentName(CALLING_PACKAGE_1, "act2");
    +-
    +-        addManifestShortcutResource(ACTIVITY1, R.xml.shortcut_1);
    +-        addManifestShortcutResource(ACTIVITY2, R.xml.shortcut_1_alt);
    +-
    +-        mRunningUsers.put(USER_10, true);
    +-
    +-        updatePackageVersion(CALLING_PACKAGE_1, 1);
    +-                mService.mPackageMonitor.onReceive(getTestContext(),
    +-                genPackageAddIntent(CALLING_PACKAGE_1, USER_10));
    +-
    +-        runWithCaller(CALLING_PACKAGE_1, USER_10, () -> {
    +-            assertTrue(mManager.addDynamicShortcuts(list(
    +-                    makeShortcutWithActivity("s1", ACTIVITY1),
    +-                    makeShortcutWithActivity("s2", ACTIVITY2)
    +-            )));
    +-        });
    +-        runWithCaller(LAUNCHER_1, USER_10, () -> {
    +-            mLauncherApps.pinShortcuts(CALLING_PACKAGE_1, list("ms1-alt", "s2"), HANDLE_USER_10);
    +-        });
    +-
    +-        runWithCaller(CALLING_PACKAGE_1, USER_10, () -> {
    +-            assertWith(getCallerShortcuts())
    +-                    .haveIds("ms1", "ms1-alt", "s1", "s2")
    +-                    .areAllEnabled()
    +-
    +-                    .selectPinned()
    +-                    .haveIds("ms1-alt", "s2")
    +-
    +-                    .revertToOriginalList()
    +-                    .selectByIds("ms1", "s1")
    +-                    .areAllWithActivity(ACTIVITY1)
    +-
    +-                    .revertToOriginalList()
    +-                    .selectByIds("ms1-alt", "s2")
    +-                    .areAllWithActivity(ACTIVITY2)
    +-                    ;
    +-        });
    +-
    +-        // First, no changes.
    +-                mService.mPackageMonitor.onReceive(getTestContext(),
    +-                genPackageChangedIntent(CALLING_PACKAGE_1, USER_10));
    +-
    +-        runWithCaller(CALLING_PACKAGE_1, USER_10, () -> {
    +-            assertWith(getCallerShortcuts())
    +-                    .haveIds("ms1", "ms1-alt", "s1", "s2")
    +-                    .areAllEnabled()
    +-
    +-                    .selectPinned()
    +-                    .haveIds("ms1-alt", "s2")
    +-
    +-                    .revertToOriginalList()
    +-                    .selectByIds("ms1", "s1")
    +-                    .areAllWithActivity(ACTIVITY1)
    +-
    +-                    .revertToOriginalList()
    +-                    .selectByIds("ms1-alt", "s2")
    +-                    .areAllWithActivity(ACTIVITY2)
    +-            ;
    +-        });
    +-
    +-        // Disable activity 1
    +-        mEnabledActivityChecker = (activity, userId) -> !ACTIVITY1.equals(activity);
    +-                mService.mPackageMonitor.onReceive(getTestContext(),
    +-                genPackageChangedIntent(CALLING_PACKAGE_1, USER_10));
    +-
    +-        runWithCaller(CALLING_PACKAGE_1, USER_10, () -> {
    +-            assertWith(getCallerShortcuts())
    +-                    .haveIds("ms1-alt", "s2")
    +-                    .areAllEnabled()
    +-
    +-                    .selectPinned()
    +-                    .haveIds("ms1-alt", "s2")
    +-
    +-                    .revertToOriginalList()
    +-                    .selectByIds("ms1-alt", "s2")
    +-                    .areAllWithActivity(ACTIVITY2)
    +-            ;
    +-        });
    +-
    +-        // Re-enable activity 1.
    +-        // Manifest shortcuts will be re-published, but dynamic ones are not.
    +-        mEnabledActivityChecker = (activity, userId) -> true;
    +-                mService.mPackageMonitor.onReceive(getTestContext(),
    +-                genPackageChangedIntent(CALLING_PACKAGE_1, USER_10));
    +-
    +-        runWithCaller(CALLING_PACKAGE_1, USER_10, () -> {
    +-            assertWith(getCallerShortcuts())
    +-                    .haveIds("ms1", "ms1-alt", "s2")
    +-                    .areAllEnabled()
    +-
    +-                    .selectPinned()
    +-                    .haveIds("ms1-alt", "s2")
    +-
    +-                    .revertToOriginalList()
    +-                    .selectByIds("ms1")
    +-                    .areAllWithActivity(ACTIVITY1)
    +-
    +-                    .revertToOriginalList()
    +-                    .selectByIds("ms1-alt", "s2")
    +-                    .areAllWithActivity(ACTIVITY2)
    +-                    ;
    +-        });
    +-
    +-        // Disable activity 2
    +-        // Because "ms1-alt" and "s2" are both pinned, they will remain, but disabled.
    +-        mEnabledActivityChecker = (activity, userId) -> !ACTIVITY2.equals(activity);
    +-                mService.mPackageMonitor.onReceive(getTestContext(),
    +-                genPackageChangedIntent(CALLING_PACKAGE_1, USER_10));
    +-
    +-        runWithCaller(CALLING_PACKAGE_1, USER_10, () -> {
    +-            assertWith(getCallerShortcuts())
    +-                    .haveIds("ms1", "ms1-alt", "s2")
    +-
    +-                    .selectDynamic().isEmpty().revertToOriginalList() // no dynamics.
    +-
    +-                    .selectPinned()
    +-                    .haveIds("ms1-alt", "s2")
    +-                    .areAllDisabled()
    +-
    +-                    .revertToOriginalList()
    +-                    .selectByIds("ms1")
    +-                    .areAllWithActivity(ACTIVITY1)
    +-                    .areAllEnabled()
    +-            ;
    +-        });
    +-    }
    +-
    +-    public void testHandlePackageUpdate_activityNoLongerMain() throws Throwable {
    +-        runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
    +-            assertTrue(mManager.setDynamicShortcuts(list(
    +-                    makeShortcutWithActivity("s1a",
    +-                            new ComponentName(getCallingPackage(), "act1")),
    +-                    makeShortcutWithActivity("s1b",
    +-                            new ComponentName(getCallingPackage(), "act1")),
    +-                    makeShortcutWithActivity("s2a",
    +-                            new ComponentName(getCallingPackage(), "act2")),
    +-                    makeShortcutWithActivity("s2b",
    +-                            new ComponentName(getCallingPackage(), "act2")),
    +-                    makeShortcutWithActivity("s3a",
    +-                            new ComponentName(getCallingPackage(), "act3")),
    +-                    makeShortcutWithActivity("s3b",
    +-                            new ComponentName(getCallingPackage(), "act3"))
    +-            )));
    +-            assertWith(getCallerShortcuts())
    +-                    .haveIds("s1a", "s1b", "s2a", "s2b", "s3a", "s3b")
    +-                    .areAllDynamic();
    +-        });
    +-        runWithCaller(LAUNCHER_1, USER_0, () -> {
    +-            mLauncherApps.pinShortcuts(CALLING_PACKAGE_1,
    +-                    list("s1b", "s2b", "s3b"),
    +-                    HANDLE_USER_0);
    +-        });
    +-        runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
    +-            assertWith(getCallerShortcuts())
    +-                    .haveIds("s1a", "s1b", "s2a", "s2b", "s3a", "s3b")
    +-                    .areAllDynamic()
    +-
    +-                    .selectByIds("s1b", "s2b", "s3b")
    +-                    .areAllPinned();
    +-        });
    +-
    +-        // Update the app and act2 and act3 are no longer main.
    +-        mMainActivityChecker = (activity, userId) -> {
    +-            return activity.getClassName().equals("act1");
    +-        };
    +-
    +-        setCaller(LAUNCHER_1, USER_0);
    +-        assertForLauncherCallback(mLauncherApps, () -> {
    +-            updatePackageVersion(CALLING_PACKAGE_1, 1);
    +-                    mService.mPackageMonitor.onReceive(getTestContext(),
    +-                    genPackageUpdateIntent(CALLING_PACKAGE_1, USER_0));
    +-        }).assertCallbackCalledForPackageAndUser(CALLING_PACKAGE_1, HANDLE_USER_0)
    +-                // Make sure the launcher gets callbacks.
    +-                .haveIds("s1a", "s1b", "s2b", "s3b")
    +-                .areAllWithKeyFieldsOnly();
    +-
    +-        runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
    +-            // s2a and s3a are gone, but s2b and s3b will remain because they're pinned, and
    +-            // disabled.
    +-            assertWith(getCallerShortcuts())
    +-                    .haveIds("s1a", "s1b", "s2b", "s3b")
    +-
    +-                    .selectByIds("s1a", "s1b")
    +-                    .areAllDynamic()
    +-                    .areAllEnabled()
    +-
    +-                    .revertToOriginalList()
    +-                    .selectByIds("s2b", "s3b")
    +-                    .areAllNotDynamic()
    +-                    .areAllDisabled()
    +-                    .areAllPinned()
    +-                    ;
    +-        });
    +-    }
    +-
    +-    protected void prepareForBackupTest() {
    +-
    +-        prepareCrossProfileDataSet();
    +-
    +-        backupAndRestore();
    +-    }
    +-
    +-    /**
    +-     * Make sure the backup data doesn't have the following information:
    +-     * - Launchers on other users.
    +-     * - Non-backup app information.
    +-     *
    +-     * But restores all other infomation.
    +-     *
    +-     * It also omits the following pieces of information, but that's tested in
    +-     * {@link ShortcutManagerTest2#testShortcutInfoSaveAndLoad_forBackup}.
    +-     * - Unpinned dynamic shortcuts
    +-     * - Bitmaps
    +-     */
    +-    public void testBackupAndRestore() {
    +-        prepareForBackupTest();
    +-
    +-        checkBackupAndRestore_success();
    +-    }
    +-
    +-    public void testBackupAndRestore_backupRestoreTwice() {
    +-        prepareForBackupTest();
    +-
    +-        // Note doing a backup & restore again here shouldn't affect the result.
    +-        dumpsysOnLogcat("Before second backup");
    +-
    +-        backupAndRestore();
    +-
    +-        dumpsysOnLogcat("After second backup");
    +-
    +-        checkBackupAndRestore_success();
    +-    }
    +-
    +-    public void testBackupAndRestore_backupRestoreMultiple() {
    +-        prepareForBackupTest();
    +-
    +-        // Note doing a backup & restore again here shouldn't affect the result.
    +-        backupAndRestore();
    +-
    +-        // This also shouldn't affect the result.
    +-        runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
    +-            assertTrue(mManager.setDynamicShortcuts(list(
    +-                    makeShortcut("s1"), makeShortcut("s2"), makeShortcut("s3"),
    +-                    makeShortcut("s4"), makeShortcut("s5"), makeShortcut("s6"))));
    +-        });
    +-
    +-        backupAndRestore();
    +-
    +-        checkBackupAndRestore_success();
    +-    }
    +-
    +-    public void testBackupAndRestore_restoreToNewVersion() {
    +-        prepareForBackupTest();
    +-
    +-        // Note doing a backup & restore again here shouldn't affect the result.
    +-        backupAndRestore();
    +-
    +-        addPackage(CALLING_PACKAGE_1, CALLING_UID_1, 2);
    +-        addPackage(LAUNCHER_1, LAUNCHER_UID_1, 5);
    +-
    +-        checkBackupAndRestore_success();
    +-    }
    +-
    +-    public void testBackupAndRestore_restoreToSuperSetSignatures() {
    +-        prepareForBackupTest();
    +-
    +-        // Note doing a backup & restore again here shouldn't affect the result.
    +-        backupAndRestore();
    +-
    +-        // Change package signatures.
    +-        addPackage(CALLING_PACKAGE_1, CALLING_UID_1, 1, "sigx", CALLING_PACKAGE_1);
    +-        addPackage(LAUNCHER_1, LAUNCHER_UID_1, 4, LAUNCHER_1, "sigy");
    +-
    +-        checkBackupAndRestore_success();
    +-    }
    +-
    +-    protected void checkBackupAndRestore_success() {
    +-        // Make sure non-system user is not restored.
    +-        final ShortcutUser userP0 = mService.getUserShortcutsLocked(USER_P0);
    +-        assertEquals(0, userP0.getAllPackagesForTest().size());
    +-        assertEquals(0, userP0.getAllLaunchersForTest().size());
    +-
    +-        // Make sure only "allowBackup" apps are restored, and are shadow.
    +-        final ShortcutUser user0 = mService.getUserShortcutsLocked(USER_0);
    +-        assertExistsAndShadow(user0.getAllPackagesForTest().get(CALLING_PACKAGE_1));
    +-        assertExistsAndShadow(user0.getAllPackagesForTest().get(CALLING_PACKAGE_2));
    +-        assertExistsAndShadow(user0.getAllLaunchersForTest().get(
    +-                PackageWithUser.of(USER_0, LAUNCHER_1)));
    +-        assertExistsAndShadow(user0.getAllLaunchersForTest().get(
    +-                PackageWithUser.of(USER_0, LAUNCHER_2)));
    +-
    +-        assertNull(user0.getAllPackagesForTest().get(CALLING_PACKAGE_3));
    +-        assertNull(user0.getAllLaunchersForTest().get(PackageWithUser.of(USER_0, LAUNCHER_3)));
    +-        assertNull(user0.getAllLaunchersForTest().get(PackageWithUser.of(USER_P0, LAUNCHER_1)));
    +-
    +-        installPackage(USER_0, CALLING_PACKAGE_1);
    +-        runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
    +-            assertWith(getCallerVisibleShortcuts())
    +-                    .selectDynamic()
    +-                    .isEmpty()
    +-
    +-                    .revertToOriginalList()
    +-                    .selectPinned()
    +-                    .haveIds("s1", "s2");
    +-        });
    +-
    +-        installPackage(USER_0, LAUNCHER_1);
    +-        runWithCaller(LAUNCHER_1, USER_0, () -> {
    +-            assertWith(mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_1), HANDLE_USER_0))
    +-                    .areAllPinned()
    +-                    .haveIds("s1");
    +-
    +-            assertWith(mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_2), HANDLE_USER_0))
    +-                    .isEmpty();
    +-
    +-            assertWith(mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_3), HANDLE_USER_0))
    +-                    .isEmpty();
    +-
    +-            assertWith(mLauncherApps.getShortcuts(QUERY_ALL, HANDLE_USER_P0))
    +-                    .isEmpty();
    +-        });
    +-
    +-        installPackage(USER_0, CALLING_PACKAGE_2);
    +-        runWithCaller(CALLING_PACKAGE_2, USER_0, () -> {
    +-            assertWith(getCallerVisibleShortcuts())
    +-                    .selectDynamic()
    +-                    .isEmpty()
    +-
    +-                    .revertToOriginalList()
    +-                    .selectPinned()
    +-                    .haveIds("s1", "s2", "s3");
    +-        });
    +-
    +-        runWithCaller(LAUNCHER_1, USER_0, () -> {
    +-            assertWith(mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_1), HANDLE_USER_0))
    +-                    .areAllPinned()
    +-                    .haveIds("s1");
    +-
    +-            assertWith(mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_2), HANDLE_USER_0))
    +-                    .areAllPinned()
    +-                    .haveIds("s1", "s2");
    +-
    +-            assertWith(mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_3), HANDLE_USER_0))
    +-                    .isEmpty();
    +-
    +-            assertWith(mLauncherApps.getShortcuts(QUERY_ALL, HANDLE_USER_P0))
    +-                    .isEmpty();
    +-        });
    +-
    +-        // 3 shouldn't be backed up, so no pinned shortcuts.
    +-        installPackage(USER_0, CALLING_PACKAGE_3);
    +-        runWithCaller(CALLING_PACKAGE_3, USER_0, () -> {
    +-            assertWith(getCallerVisibleShortcuts())
    +-                    .isEmpty();
    +-        });
    +-
    +-        // Launcher on a different profile shouldn't be restored.
    +-        runWithCaller(LAUNCHER_1, USER_P0, () -> {
    +-            assertWith(mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_1), HANDLE_USER_0))
    +-                    .isEmpty();
    +-            assertWith(mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_2), HANDLE_USER_0))
    +-                    .isEmpty();
    +-            assertWith(mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_3), HANDLE_USER_0))
    +-                    .isEmpty();
    +-        });
    +-
    +-        // Package on a different profile, no restore.
    +-        installPackage(USER_P0, CALLING_PACKAGE_1);
    +-        runWithCaller(CALLING_PACKAGE_1, USER_P0, () -> {
    +-            assertWith(getCallerVisibleShortcuts())
    +-                    .isEmpty();
    +-        });
    +-
    +-        // Restore launcher 2 on user 0.
    +-        installPackage(USER_0, LAUNCHER_2);
    +-        runWithCaller(LAUNCHER_2, USER_0, () -> {
    +-            assertWith(mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_1), HANDLE_USER_0))
    +-                    .areAllPinned()
    +-                    .haveIds("s2");
    +-
    +-            assertWith(mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_2), HANDLE_USER_0))
    +-                    .areAllPinned()
    +-                    .haveIds("s2", "s3");
    +-
    +-            assertWith(mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_3), HANDLE_USER_0))
    +-                    .isEmpty();
    +-
    +-            assertWith(mLauncherApps.getShortcuts(QUERY_ALL, HANDLE_USER_P0))
    +-                    .isEmpty();
    +-        });
    +-
    +-
    +-        // Restoration of launcher2 shouldn't affect other packages; so do the same checks and
    +-        // make sure they still have the same result.
    +-        installPackage(USER_0, CALLING_PACKAGE_1);
    +-        runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
    +-            assertWith(getCallerVisibleShortcuts())
    +-                    .areAllPinned()
    +-                    .haveIds("s1", "s2");
    +-        });
    +-
    +-        installPackage(USER_0, LAUNCHER_1);
    +-        runWithCaller(LAUNCHER_1, USER_0, () -> {
    +-            assertWith(mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_1), HANDLE_USER_0))
    +-                    .areAllPinned()
    +-                    .haveIds("s1");
    +-
    +-            assertWith(mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_2), HANDLE_USER_0))
    +-                    .areAllPinned()
    +-                    .haveIds("s1", "s2");
    +-
    +-            assertWith(mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_3), HANDLE_USER_0))
    +-                    .isEmpty();
    +-
    +-            assertWith(mLauncherApps.getShortcuts(QUERY_ALL, HANDLE_USER_P0))
    +-                    .isEmpty();
    +-        });
    +-
    +-        installPackage(USER_0, CALLING_PACKAGE_2);
    +-        runWithCaller(CALLING_PACKAGE_2, USER_0, () -> {
    +-            assertWith(getCallerVisibleShortcuts())
    +-                    .areAllPinned()
    +-                    .haveIds("s1", "s2", "s3");
    +-        });
    +-    }
    +-
    +-    public void testBackupAndRestore_publisherLowerVersion() {
    +-        prepareForBackupTest();
    +-
    +-        // Note doing a backup & restore again here shouldn't affect the result.
    +-        backupAndRestore();
    +-
    +-        addPackage(CALLING_PACKAGE_1, CALLING_UID_1, 0); // Lower version
    +-
    +-        checkBackupAndRestore_publisherNotRestored();
    +-    }
    +-
    +-    public void testBackupAndRestore_publisherWrongSignature() {
    +-        prepareForBackupTest();
    +-
    +-        // Note doing a backup & restore again here shouldn't affect the result.
    +-        backupAndRestore();
    +-
    +-        addPackage(CALLING_PACKAGE_1, CALLING_UID_1, 10, "sigx"); // different signature
    +-
    +-        checkBackupAndRestore_publisherNotRestored();
    +-    }
    +-
    +-    public void testBackupAndRestore_publisherNoLongerBackupTarget() {
    +-        prepareForBackupTest();
    +-
    +-        // Note doing a backup & restore again here shouldn't affect the result.
    +-        backupAndRestore();
    +-
    +-        updatePackageInfo(CALLING_PACKAGE_1,
    +-                pi -> pi.applicationInfo.flags &= ~ApplicationInfo.FLAG_ALLOW_BACKUP);
    +-
    +-        checkBackupAndRestore_publisherNotRestored();
    +-    }
    +-
    +-    protected void checkBackupAndRestore_publisherNotRestored() {
    +-        installPackage(USER_0, CALLING_PACKAGE_1);
    +-        runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
    +-            assertEquals(0, mManager.getDynamicShortcuts().size());
    +-            assertEquals(0, mManager.getPinnedShortcuts().size());
    +-        });
    +-
    +-        installPackage(USER_0, CALLING_PACKAGE_2);
    +-        runWithCaller(CALLING_PACKAGE_2, USER_0, () -> {
    +-            assertEquals(0, mManager.getDynamicShortcuts().size());
    +-            assertShortcutIds(assertAllPinned(
    +-                    mManager.getPinnedShortcuts()),
    +-                    "s1", "s2", "s3");
    +-        });
    +-
    +-        installPackage(USER_0, LAUNCHER_1);
    +-        runWithCaller(LAUNCHER_1, USER_0, () -> {
    +-            assertShortcutIds(assertAllPinned(
    +-                    mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_1), HANDLE_USER_0))
    +-                    /* empty */);
    +-            assertShortcutIds(assertAllPinned(
    +-                    mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_2), HANDLE_USER_0)),
    +-                    "s1", "s2");
    +-            assertShortcutIds(assertAllPinned(
    +-                    mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_3), HANDLE_USER_0))
    +-                    /* empty */);
    +-        });
    +-        installPackage(USER_0, LAUNCHER_2);
    +-        runWithCaller(LAUNCHER_2, USER_0, () -> {
    +-            assertShortcutIds(assertAllPinned(
    +-                    mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_1), HANDLE_USER_0))
    +-                    /* empty */);
    +-            assertShortcutIds(assertAllPinned(
    +-                    mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_2), HANDLE_USER_0)),
    +-                    "s2", "s3");
    +-            assertShortcutIds(assertAllPinned(
    +-                    mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_3), HANDLE_USER_0))
    +-                    /* empty */);
    +-        });
    +-
    +-        installPackage(USER_0, CALLING_PACKAGE_3);
    +-        runWithCaller(CALLING_PACKAGE_3, USER_0, () -> {
    +-            assertEquals(0, mManager.getDynamicShortcuts().size());
    +-            assertEquals(0, mManager.getPinnedShortcuts().size());
    +-        });
    +-
    +-        runWithCaller(LAUNCHER_1, USER_0, () -> {
    +-            assertShortcutIds(assertAllPinned(
    +-                    mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_1), HANDLE_USER_0))
    +-                    /* empty */);
    +-            assertShortcutIds(assertAllPinned(
    +-                    mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_2), HANDLE_USER_0)),
    +-                    "s1", "s2");
    +-            assertShortcutIds(assertAllPinned(
    +-                    mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_3), HANDLE_USER_0))
    +-                    /* empty */);
    +-        });
    +-        runWithCaller(LAUNCHER_2, USER_0, () -> {
    +-            assertShortcutIds(assertAllPinned(
    +-                    mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_1), HANDLE_USER_0))
    +-                    /* empty */);
    +-            assertShortcutIds(assertAllPinned(
    +-                    mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_2), HANDLE_USER_0)),
    +-                    "s2", "s3");
    +-            assertShortcutIds(assertAllPinned(
    +-                    mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_3), HANDLE_USER_0))
    +-                    /* empty */);
    +-        });
    +-    }
    +-
    +-    public void testBackupAndRestore_launcherLowerVersion() {
    +-        prepareForBackupTest();
    +-
    +-        // Note doing a backup & restore again here shouldn't affect the result.
    +-        backupAndRestore();
    +-
    +-        addPackage(LAUNCHER_1, LAUNCHER_UID_1, 0); // Lower version
    +-
    +-        checkBackupAndRestore_launcherNotRestored();
    +-    }
    +-
    +-    public void testBackupAndRestore_launcherWrongSignature() {
    +-        prepareForBackupTest();
    +-
    +-        // Note doing a backup & restore again here shouldn't affect the result.
    +-        backupAndRestore();
    +-
    +-        addPackage(LAUNCHER_1, LAUNCHER_UID_1, 10, "sigx"); // different signature
    +-
    +-        checkBackupAndRestore_launcherNotRestored();
    +-    }
    +-
    +-    public void testBackupAndRestore_launcherNoLongerBackupTarget() {
    +-        prepareForBackupTest();
    +-
    +-        // Note doing a backup & restore again here shouldn't affect the result.
    +-        backupAndRestore();
    +-
    +-        updatePackageInfo(LAUNCHER_1,
    +-                pi -> pi.applicationInfo.flags &= ~ApplicationInfo.FLAG_ALLOW_BACKUP);
    +-
    +-        checkBackupAndRestore_launcherNotRestored();
    +-    }
    +-
    +-    protected void checkBackupAndRestore_launcherNotRestored() {
    +-        installPackage(USER_0, CALLING_PACKAGE_1);
    +-        runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
    +-            assertEquals(0, mManager.getDynamicShortcuts().size());
    +-
    +-            // s1 was pinned by launcher 1, which is not restored, yet, so we still see "s1" here.
    +-            assertShortcutIds(assertAllPinned(
    +-                    mManager.getPinnedShortcuts()),
    +-                    "s1", "s2");
    +-        });
    +-
    +-        installPackage(USER_0, CALLING_PACKAGE_2);
    +-        runWithCaller(CALLING_PACKAGE_2, USER_0, () -> {
    +-            assertEquals(0, mManager.getDynamicShortcuts().size());
    +-            assertShortcutIds(assertAllPinned(
    +-                    mManager.getPinnedShortcuts()),
    +-                    "s1", "s2", "s3");
    +-        });
    +-
    +-        // Now we try to restore launcher 1.  Then we realize it's not restorable, so L1 has no pinned
    +-        // shortcuts.
    +-        installPackage(USER_0, LAUNCHER_1);
    +-        runWithCaller(LAUNCHER_1, USER_0, () -> {
    +-            assertShortcutIds(assertAllPinned(
    +-                    mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_1), HANDLE_USER_0))
    +-                    /* empty */);
    +-            assertShortcutIds(assertAllPinned(
    +-                    mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_2), HANDLE_USER_0))
    +-                    /* empty */);
    +-            assertShortcutIds(assertAllPinned(
    +-                    mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_3), HANDLE_USER_0))
    +-                    /* empty */);
    +-        });
    +-
    +-        runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
    +-            assertEquals(0, mManager.getDynamicShortcuts().size());
    +-
    +-            // Now CALLING_PACKAGE_1 realizes "s1" is no longer pinned.
    +-            assertShortcutIds(assertAllPinned(
    +-                    mManager.getPinnedShortcuts()),
    +-                    "s2");
    +-        });
    +-
    +-        installPackage(USER_0, LAUNCHER_2);
    +-        runWithCaller(LAUNCHER_2, USER_0, () -> {
    +-            assertShortcutIds(assertAllPinned(
    +-                    mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_1), HANDLE_USER_0)),
    +-                    "s2");
    +-            assertShortcutIds(assertAllPinned(
    +-                    mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_2), HANDLE_USER_0)),
    +-                    "s2", "s3");
    +-            assertShortcutIds(assertAllPinned(
    +-                    mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_3), HANDLE_USER_0))
    +-                    /* empty */);
    +-        });
    +-
    +-        installPackage(USER_0, CALLING_PACKAGE_3);
    +-        runWithCaller(CALLING_PACKAGE_3, USER_0, () -> {
    +-            assertEquals(0, mManager.getDynamicShortcuts().size());
    +-            assertEquals(0, mManager.getPinnedShortcuts().size());
    +-        });
    +-
    +-        runWithCaller(LAUNCHER_1, USER_0, () -> {
    +-            assertShortcutIds(assertAllPinned(
    +-                    mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_1), HANDLE_USER_0))
    +-                    /* empty */);
    +-            assertShortcutIds(assertAllPinned(
    +-                    mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_2), HANDLE_USER_0))
    +-                    /* empty */);
    +-            assertShortcutIds(assertAllPinned(
    +-                    mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_3), HANDLE_USER_0))
    +-                    /* empty */);
    +-        });
    +-        runWithCaller(LAUNCHER_2, USER_0, () -> {
    +-            assertShortcutIds(assertAllPinned(
    +-                    mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_1), HANDLE_USER_0)),
    +-                    "s2");
    +-            assertShortcutIds(assertAllPinned(
    +-                    mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_2), HANDLE_USER_0)),
    +-                    "s2", "s3");
    +-            assertShortcutIds(assertAllPinned(
    +-                    mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_3), HANDLE_USER_0))
    +-                    /* empty */);
    +-        });
    +-    }
    +-
    +-    public void testBackupAndRestore_launcherAndPackageNoLongerBackupTarget() {
    +-        prepareForBackupTest();
    +-
    +-        // Note doing a backup & restore again here shouldn't affect the result.
    +-        backupAndRestore();
    +-
    +-        updatePackageInfo(CALLING_PACKAGE_1,
    +-                pi -> pi.applicationInfo.flags &= ~ApplicationInfo.FLAG_ALLOW_BACKUP);
    +-
    +-        updatePackageInfo(LAUNCHER_1,
    +-                pi -> pi.applicationInfo.flags &= ~ApplicationInfo.FLAG_ALLOW_BACKUP);
    +-
    +-        checkBackupAndRestore_publisherAndLauncherNotRestored();
    +-    }
    +-
    +-    protected void checkBackupAndRestore_publisherAndLauncherNotRestored() {
    +-        installPackage(USER_0, CALLING_PACKAGE_1);
    +-        runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
    +-            assertEquals(0, mManager.getDynamicShortcuts().size());
    +-            assertEquals(0, mManager.getPinnedShortcuts().size());
    +-        });
    +-
    +-        installPackage(USER_0, CALLING_PACKAGE_2);
    +-        runWithCaller(CALLING_PACKAGE_2, USER_0, () -> {
    +-            assertEquals(0, mManager.getDynamicShortcuts().size());
    +-            assertShortcutIds(assertAllPinned(
    +-                    mManager.getPinnedShortcuts()),
    +-                    "s1", "s2", "s3");
    +-        });
    +-
    +-        installPackage(USER_0, LAUNCHER_1);
    +-        runWithCaller(LAUNCHER_1, USER_0, () -> {
    +-            assertShortcutIds(assertAllPinned(
    +-                    mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_1), HANDLE_USER_0))
    +-                    /* empty */);
    +-            assertShortcutIds(assertAllPinned(
    +-                    mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_2), HANDLE_USER_0))
    +-                    /* empty */);
    +-            assertShortcutIds(assertAllPinned(
    +-                    mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_3), HANDLE_USER_0))
    +-                    /* empty */);
    +-        });
    +-        installPackage(USER_0, LAUNCHER_2);
    +-        runWithCaller(LAUNCHER_2, USER_0, () -> {
    +-            assertShortcutIds(assertAllPinned(
    +-                    mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_1), HANDLE_USER_0))
    +-                    /* empty */);
    +-            assertShortcutIds(assertAllPinned(
    +-                    mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_2), HANDLE_USER_0)),
    +-                    "s2", "s3");
    +-            assertShortcutIds(assertAllPinned(
    +-                    mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_3), HANDLE_USER_0))
    +-                    /* empty */);
    +-        });
    +-
    +-        // Because launcher 1 wasn't restored, "s1" is no longer pinned.
    +-        runWithCaller(CALLING_PACKAGE_2, USER_0, () -> {
    +-            assertEquals(0, mManager.getDynamicShortcuts().size());
    +-            assertShortcutIds(assertAllPinned(
    +-                    mManager.getPinnedShortcuts()),
    +-                    "s2", "s3");
    +-        });
    +-
    +-        installPackage(USER_0, CALLING_PACKAGE_3);
    +-        runWithCaller(CALLING_PACKAGE_3, USER_0, () -> {
    +-            assertEquals(0, mManager.getDynamicShortcuts().size());
    +-            assertEquals(0, mManager.getPinnedShortcuts().size());
    +-        });
    +-
    +-        runWithCaller(LAUNCHER_1, USER_0, () -> {
    +-            assertShortcutIds(assertAllPinned(
    +-                    mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_1), HANDLE_USER_0))
    +-                    /* empty */);
    +-            assertShortcutIds(assertAllPinned(
    +-                    mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_2), HANDLE_USER_0))
    +-                    /* empty */);
    +-            assertShortcutIds(assertAllPinned(
    +-                    mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_3), HANDLE_USER_0))
    +-                    /* empty */);
    +-        });
    +-        runWithCaller(LAUNCHER_2, USER_0, () -> {
    +-            assertShortcutIds(assertAllPinned(
    +-                    mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_1), HANDLE_USER_0))
    +-                    /* empty */);
    +-            assertShortcutIds(assertAllPinned(
    +-                    mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_2), HANDLE_USER_0)),
    +-                    "s2", "s3");
    +-            assertShortcutIds(assertAllPinned(
    +-                    mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_3), HANDLE_USER_0))
    +-                    /* empty */);
    +-        });
    +-    }
    +-
    +-    public void testBackupAndRestore_disabled() {
    +-        prepareCrossProfileDataSet();
    +-
    +-        // Before doing backup & restore, disable s1.
    +-        runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
    +-            mManager.disableShortcuts(list("s1"));
    +-        });
    +-
    +-        backupAndRestore();
    +-
    +-        // Below is copied from checkBackupAndRestore_success.
    +-
    +-        // Make sure non-system user is not restored.
    +-        final ShortcutUser userP0 = mService.getUserShortcutsLocked(USER_P0);
    +-        assertEquals(0, userP0.getAllPackagesForTest().size());
    +-        assertEquals(0, userP0.getAllLaunchersForTest().size());
    +-
    +-        // Make sure only "allowBackup" apps are restored, and are shadow.
    +-        final ShortcutUser user0 = mService.getUserShortcutsLocked(USER_0);
    +-        assertExistsAndShadow(user0.getAllPackagesForTest().get(CALLING_PACKAGE_1));
    +-        assertExistsAndShadow(user0.getAllPackagesForTest().get(CALLING_PACKAGE_2));
    +-        assertExistsAndShadow(user0.getAllLaunchersForTest().get(
    +-                PackageWithUser.of(USER_0, LAUNCHER_1)));
    +-        assertExistsAndShadow(user0.getAllLaunchersForTest().get(
    +-                PackageWithUser.of(USER_0, LAUNCHER_2)));
    +-
    +-        assertNull(user0.getAllPackagesForTest().get(CALLING_PACKAGE_3));
    +-        assertNull(user0.getAllLaunchersForTest().get(PackageWithUser.of(USER_0, LAUNCHER_3)));
    +-        assertNull(user0.getAllLaunchersForTest().get(PackageWithUser.of(USER_P0, LAUNCHER_1)));
    +-
    +-        installPackage(USER_0, CALLING_PACKAGE_1);
    +-        runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
    +-            assertWith(getCallerVisibleShortcuts())
    +-                    .areAllEnabled() // disabled shortcuts shouldn't be restored.
    +-
    +-                    .selectDynamic()
    +-                    .isEmpty()
    +-
    +-                    .revertToOriginalList()
    +-                    .selectPinned()
    +-                    // s1 is not restored.
    +-                    .haveIds("s2");
    +-        });
    +-
    +-        installPackage(USER_0, LAUNCHER_1);
    +-        runWithCaller(LAUNCHER_1, USER_0, () -> {
    +-            // Note, s1 was pinned by launcher 1, but was disabled, so isn't restored.
    +-            assertWith(mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_1), HANDLE_USER_0))
    +-                    .isEmpty();
    +-
    +-            assertWith(mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_2), HANDLE_USER_0))
    +-                    .isEmpty();
    +-
    +-            assertWith(mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_3), HANDLE_USER_0))
    +-                    .isEmpty();
    +-
    +-            assertWith(mLauncherApps.getShortcuts(QUERY_ALL, HANDLE_USER_P0))
    +-                    .isEmpty();
    +-        });
    +-    }
    +-
    +-
    +-    public void testBackupAndRestore_manifestRePublished() {
    +-        // Publish two manifest shortcuts.
    +-        addManifestShortcutResource(
    +-                new ComponentName(CALLING_PACKAGE_1, ShortcutActivity.class.getName()),
    +-                R.xml.shortcut_2);
    +-        updatePackageVersion(CALLING_PACKAGE_1, 1);
    +-        mService.mPackageMonitor.onReceive(mServiceContext,
    +-                genPackageAddIntent(CALLING_PACKAGE_1, USER_0));
    +-
    +-        runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
    +-            assertTrue(mManager.setDynamicShortcuts(list(
    +-                    makeShortcut("s1"), makeShortcut("s2"), makeShortcut("s3"))));
    +-        });
    +-
    +-        // Pin from launcher 1.
    +-        runWithCaller(LAUNCHER_1, USER_0, () -> {
    +-            mLauncherApps.pinShortcuts(CALLING_PACKAGE_1,
    +-                    list("ms1", "ms2", "s1", "s2"), HANDLE_USER_0);
    +-        });
    +-
    +-        // Update and now ms2 is gone -> disabled.
    +-        addManifestShortcutResource(
    +-                new ComponentName(CALLING_PACKAGE_1, ShortcutActivity.class.getName()),
    +-                R.xml.shortcut_1);
    +-        updatePackageVersion(CALLING_PACKAGE_1, 1);
    +-        mService.mPackageMonitor.onReceive(mServiceContext,
    +-                genPackageAddIntent(CALLING_PACKAGE_1, USER_0));
    +-
    +-        // Make sure the manifest shortcuts have been published.
    +-        runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
    +-            assertWith(getCallerShortcuts())
    +-                    .selectManifest()
    +-                    .haveIds("ms1")
    +-
    +-                    .revertToOriginalList()
    +-                    .selectDynamic()
    +-                    .haveIds("s1", "s2", "s3")
    +-
    +-                    .revertToOriginalList()
    +-                    .selectPinned()
    +-                    .haveIds("ms1", "ms2", "s1", "s2")
    +-
    +-                    .revertToOriginalList()
    +-                    .selectByIds("ms1")
    +-                    .areAllManifest()
    +-                    .areAllEnabled()
    +-
    +-                    .revertToOriginalList()
    +-                    .selectByIds("ms2")
    +-                    .areAllNotManifest()
    +-                    .areAllDisabled();
    +-        });
    +-
    +-        backupAndRestore();
    +-
    +-        // When re-installing the app, the manifest shortcut should be re-published.
    +-        mService.mPackageMonitor.onReceive(mServiceContext,
    +-                genPackageAddIntent(CALLING_PACKAGE_1, USER_0));
    +-        mService.mPackageMonitor.onReceive(mServiceContext,
    +-                genPackageAddIntent(LAUNCHER_1, USER_0));
    +-
    +-        runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
    +-            assertWith(getCallerVisibleShortcuts())
    +-                    .selectPinned()
    +-                    // ms2 was disabled, so not restored.
    +-                    .haveIds("ms1", "s1", "s2")
    +-                    .areAllEnabled()
    +-
    +-                    .revertToOriginalList()
    +-                    .selectByIds("ms1")
    +-                    .areAllManifest()
    +-
    +-                    .revertToOriginalList()
    +-                    .selectByIds("s1", "s2")
    +-                    .areAllNotDynamic()
    +-                    ;
    +-        });
    +-    }
    +-
    +-    /**
    +-     * It's the case with preintalled apps -- when applyRestore() is called, the system
    +-     * apps are already installed, so manifest shortcuts need to be re-published.
    +-     */
    +-    public void testBackupAndRestore_appAlreadyInstalledWhenRestored() {
    +-        // Pre-backup.  Same as testBackupAndRestore_manifestRePublished().
    +-
    +-        // Publish two manifest shortcuts.
    +-        addManifestShortcutResource(
    +-                new ComponentName(CALLING_PACKAGE_1, ShortcutActivity.class.getName()),
    +-                R.xml.shortcut_2);
    +-        updatePackageVersion(CALLING_PACKAGE_1, 1);
    +-        mService.mPackageMonitor.onReceive(mServiceContext,
    +-                genPackageAddIntent(CALLING_PACKAGE_1, USER_0));
    +-
    +-        runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
    +-            assertTrue(mManager.setDynamicShortcuts(list(
    +-                    makeShortcut("s1"), makeShortcut("s2"), makeShortcut("s3"))));
    +-        });
    +-
    +-        // Pin from launcher 1.
    +-        runWithCaller(LAUNCHER_1, USER_0, () -> {
    +-            mLauncherApps.pinShortcuts(CALLING_PACKAGE_1,
    +-                    list("ms1", "ms2", "s1", "s2"), HANDLE_USER_0);
    +-        });
    +-
    +-        // Update and now ms2 is gone -> disabled.
    +-        addManifestShortcutResource(
    +-                new ComponentName(CALLING_PACKAGE_1, ShortcutActivity.class.getName()),
    +-                R.xml.shortcut_1);
    +-        updatePackageVersion(CALLING_PACKAGE_1, 1);
    +-        mService.mPackageMonitor.onReceive(mServiceContext,
    +-                genPackageAddIntent(CALLING_PACKAGE_1, USER_0));
    +-
    +-        // Make sure the manifest shortcuts have been published.
    +-        runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
    +-            assertWith(getCallerShortcuts())
    +-                    .selectManifest()
    +-                    .haveIds("ms1")
    +-
    +-                    .revertToOriginalList()
    +-                    .selectDynamic()
    +-                    .haveIds("s1", "s2", "s3")
    +-
    +-                    .revertToOriginalList()
    +-                    .selectPinned()
    +-                    .haveIds("ms1", "ms2", "s1", "s2")
    +-
    +-                    .revertToOriginalList()
    +-                    .selectByIds("ms1")
    +-                    .areAllManifest()
    +-                    .areAllEnabled()
    +-
    +-                    .revertToOriginalList()
    +-                    .selectByIds("ms2")
    +-                    .areAllNotManifest()
    +-                    .areAllDisabled();
    +-        });
    +-
    +-        // Backup and *without restarting the service, just call applyRestore()*.
    +-        {
    +-            int prevUid = mInjectedCallingUid;
    +-            mInjectedCallingUid = Process.SYSTEM_UID; // Only system can call it.
    +-
    +-            dumpsysOnLogcat("Before backup");
    +-
    +-            final byte[] payload = mService.getBackupPayload(USER_0);
    +-            if (ENABLE_DUMP) {
    +-                final String xml = new String(payload);
    +-                Log.v(TAG, "Backup payload:");
    +-                for (String line : xml.split("\n")) {
    +-                    Log.v(TAG, line);
    +-                }
    +-            }
    +-            mService.applyRestore(payload, USER_0);
    +-
    +-            dumpsysOnLogcat("After restore");
    +-
    +-            mInjectedCallingUid = prevUid;
    +-        }
    +-
    +-        // The check is also the same as testBackupAndRestore_manifestRePublished().
    +-        runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
    +-            assertWith(getCallerVisibleShortcuts())
    +-                    .selectPinned()
    +-                    // ms2 was disabled, so not restored.
    +-                    .haveIds("ms1", "s1", "s2")
    +-                    .areAllEnabled()
    +-
    +-                    .revertToOriginalList()
    +-                    .selectByIds("ms1")
    +-                    .areAllManifest()
    +-
    +-                    .revertToOriginalList()
    +-                    .selectByIds("s1", "s2")
    +-                    .areAllNotDynamic()
    +-            ;
    +-        });
    +-    }
    +-
    +-    public void testSaveAndLoad_crossProfile() {
    +-        prepareCrossProfileDataSet();
    +-
    +-        dumpsysOnLogcat("Before save & load");
    +-
    +-        mService.saveDirtyInfo();
    +-        initService();
    +-
    +-        runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
    +-            assertShortcutIds(assertAllDynamic(mManager.getDynamicShortcuts()),
    +-                    "s1", "s2", "s3");
    +-            assertShortcutIds(assertAllPinned(mManager.getPinnedShortcuts()),
    +-                    "s1", "s2", "s3", "s4");
    +-        });
    +-        runWithCaller(CALLING_PACKAGE_2, USER_0, () -> {
    +-            assertShortcutIds(assertAllDynamic(mManager.getDynamicShortcuts()),
    +-                    "s1", "s2", "s3");
    +-            assertShortcutIds(assertAllPinned(mManager.getPinnedShortcuts()),
    +-                    "s1", "s2", "s3", "s4", "s5");
    +-        });
    +-        runWithCaller(CALLING_PACKAGE_3, USER_0, () -> {
    +-            assertShortcutIds(assertAllDynamic(mManager.getDynamicShortcuts()),
    +-                    "s1", "s2", "s3");
    +-            assertShortcutIds(assertAllPinned(mManager.getPinnedShortcuts()),
    +-                    "s1", "s2", "s3", "s4", "s5", "s6");
    +-        });
    +-        runWithCaller(CALLING_PACKAGE_4, USER_0, () -> {
    +-            assertShortcutIds(assertAllDynamic(mManager.getDynamicShortcuts())
    +-                    /* empty */);
    +-            assertShortcutIds(assertAllPinned(mManager.getPinnedShortcuts())
    +-                    /* empty */);
    +-        });
    +-        runWithCaller(CALLING_PACKAGE_1, USER_P0, () -> {
    +-            assertShortcutIds(assertAllDynamic(mManager.getDynamicShortcuts()),
    +-                    "s1", "s2", "s3");
    +-            assertShortcutIds(assertAllPinned(mManager.getPinnedShortcuts()),
    +-                    "s1", "s2", "s3", "s4", "s5", "s6");
    +-        });
    +-        runWithCaller(CALLING_PACKAGE_2, USER_P0, () -> {
    +-            assertShortcutIds(assertAllDynamic(mManager.getDynamicShortcuts())
    +-                    /* empty */);
    +-            assertShortcutIds(assertAllPinned(mManager.getPinnedShortcuts())
    +-                    /* empty */);
    +-        });
    +-        runWithCaller(CALLING_PACKAGE_1, USER_10, () -> {
    +-            assertShortcutIds(assertAllDynamic(mManager.getDynamicShortcuts()),
    +-                    "x1", "x2", "x3");
    +-            assertShortcutIds(assertAllPinned(mManager.getPinnedShortcuts()),
    +-                    "x4", "x5");
    +-        });
    +-        runWithCaller(LAUNCHER_1, USER_0, () -> {
    +-            assertShortcutIds(
    +-                    mLauncherApps.getShortcuts(buildPinnedQuery(CALLING_PACKAGE_1), HANDLE_USER_0),
    +-                    "s1");
    +-            assertShortcutIds(
    +-                    mLauncherApps.getShortcuts(buildPinnedQuery(CALLING_PACKAGE_2), HANDLE_USER_0),
    +-                    "s1", "s2");
    +-            assertShortcutIds(
    +-                    mLauncherApps.getShortcuts(buildPinnedQuery(CALLING_PACKAGE_3), HANDLE_USER_0),
    +-                    "s1", "s2", "s3");
    +-            assertShortcutIds(
    +-                    mLauncherApps.getShortcuts(buildPinnedQuery(CALLING_PACKAGE_4), HANDLE_USER_0)
    +-                    /* empty */);
    +-            assertShortcutIds(
    +-                    mLauncherApps.getShortcuts(buildPinnedQuery(CALLING_PACKAGE_1), HANDLE_USER_P0),
    +-                    "s1", "s4");
    +-            assertShortcutIds(
    +-                    mLauncherApps.getShortcuts(buildPinnedQuery(CALLING_PACKAGE_2), HANDLE_USER_P0)
    +-                    /* empty */);
    +-            assertExpectException(
    +-                    SecurityException.class, "", () -> {
    +-                        mLauncherApps.getShortcuts(
    +-                                buildAllQuery(CALLING_PACKAGE_1), HANDLE_USER_10);
    +-                    });
    +-        });
    +-        runWithCaller(LAUNCHER_2, USER_0, () -> {
    +-            assertShortcutIds(
    +-                    mLauncherApps.getShortcuts(buildPinnedQuery(CALLING_PACKAGE_1), HANDLE_USER_0),
    +-                    "s2");
    +-            assertShortcutIds(
    +-                    mLauncherApps.getShortcuts(buildPinnedQuery(CALLING_PACKAGE_2), HANDLE_USER_0),
    +-                    "s2", "s3");
    +-            assertShortcutIds(
    +-                    mLauncherApps.getShortcuts(buildPinnedQuery(CALLING_PACKAGE_3), HANDLE_USER_0),
    +-                    "s2", "s3", "s4");
    +-            assertShortcutIds(
    +-                    mLauncherApps.getShortcuts(buildPinnedQuery(CALLING_PACKAGE_4), HANDLE_USER_0)
    +-                    /* empty */);
    +-            assertShortcutIds(
    +-                    mLauncherApps.getShortcuts(buildPinnedQuery(CALLING_PACKAGE_1), HANDLE_USER_P0),
    +-                    "s2", "s5");
    +-            assertShortcutIds(
    +-                    mLauncherApps.getShortcuts(buildPinnedQuery(CALLING_PACKAGE_2), HANDLE_USER_P0)
    +-                    /* empty */);
    +-        });
    +-        runWithCaller(LAUNCHER_3, USER_0, () -> {
    +-            assertShortcutIds(
    +-                    mLauncherApps.getShortcuts(buildPinnedQuery(CALLING_PACKAGE_1), HANDLE_USER_0),
    +-                    "s3");
    +-            assertShortcutIds(
    +-                    mLauncherApps.getShortcuts(buildPinnedQuery(CALLING_PACKAGE_2), HANDLE_USER_0),
    +-                    "s3", "s4");
    +-            assertShortcutIds(
    +-                    mLauncherApps.getShortcuts(buildPinnedQuery(CALLING_PACKAGE_3), HANDLE_USER_0),
    +-                    "s3", "s4", "s5");
    +-            assertShortcutIds(
    +-                    mLauncherApps.getShortcuts(buildPinnedQuery(CALLING_PACKAGE_4), HANDLE_USER_0)
    +-                    /* empty */);
    +-            assertShortcutIds(
    +-                    mLauncherApps.getShortcuts(buildPinnedQuery(CALLING_PACKAGE_1), HANDLE_USER_P0),
    +-                    "s3", "s6");
    +-            assertShortcutIds(
    +-                    mLauncherApps.getShortcuts(buildPinnedQuery(CALLING_PACKAGE_2), HANDLE_USER_P0)
    +-                    /* empty */);
    +-        });
    +-        runWithCaller(LAUNCHER_4, USER_0, () -> {
    +-            assertShortcutIds(
    +-                    mLauncherApps.getShortcuts(buildPinnedQuery(CALLING_PACKAGE_1), HANDLE_USER_0)
    +-                    /* empty */);
    +-            assertShortcutIds(
    +-                    mLauncherApps.getShortcuts(buildPinnedQuery(CALLING_PACKAGE_2), HANDLE_USER_0)
    +-                    /* empty */);
    +-            assertShortcutIds(
    +-                    mLauncherApps.getShortcuts(buildPinnedQuery(CALLING_PACKAGE_3), HANDLE_USER_0)
    +-                    /* empty */);
    +-            assertShortcutIds(
    +-                    mLauncherApps.getShortcuts(buildPinnedQuery(CALLING_PACKAGE_4), HANDLE_USER_0)
    +-                    /* empty */);
    +-            assertShortcutIds(
    +-                    mLauncherApps.getShortcuts(buildPinnedQuery(CALLING_PACKAGE_1), HANDLE_USER_P0)
    +-                    /* empty */);
    +-            assertShortcutIds(
    +-                    mLauncherApps.getShortcuts(buildPinnedQuery(CALLING_PACKAGE_2), HANDLE_USER_P0)
    +-                    /* empty */);
    +-        });
    +-        runWithCaller(LAUNCHER_1, USER_P0, () -> {
    +-            assertShortcutIds(
    +-                    mLauncherApps.getShortcuts(buildPinnedQuery(CALLING_PACKAGE_1), HANDLE_USER_0),
    +-                    "s3", "s4");
    +-            assertShortcutIds(
    +-                    mLauncherApps.getShortcuts(buildPinnedQuery(CALLING_PACKAGE_2), HANDLE_USER_0),
    +-                    "s3", "s4", "s5");
    +-            assertShortcutIds(
    +-                    mLauncherApps.getShortcuts(buildPinnedQuery(CALLING_PACKAGE_3), HANDLE_USER_0),
    +-                    "s3", "s4", "s5", "s6");
    +-            assertShortcutIds(
    +-                    mLauncherApps.getShortcuts(buildPinnedQuery(CALLING_PACKAGE_1), HANDLE_USER_P0),
    +-                    "s1", "s4");
    +-            assertExpectException(
    +-                    SecurityException.class, "unrelated profile", () -> {
    +-                        mLauncherApps.getShortcuts(
    +-                                buildAllQuery(CALLING_PACKAGE_1), HANDLE_USER_10);
    +-                    });
    +-        });
    +-        runWithCaller(LAUNCHER_1, USER_10, () -> {
    +-            assertShortcutIds(
    +-                    mLauncherApps.getShortcuts(buildPinnedQuery(CALLING_PACKAGE_1), HANDLE_USER_10),
    +-                    "x4", "x5");
    +-            assertShortcutIds(
    +-                    mLauncherApps.getShortcuts(buildPinnedQuery(CALLING_PACKAGE_2), HANDLE_USER_10)
    +-                    /* empty */);
    +-            assertShortcutIds(
    +-                    mLauncherApps.getShortcuts(buildPinnedQuery(CALLING_PACKAGE_3), HANDLE_USER_10)
    +-                    /* empty */);
    +-            assertExpectException(
    +-                    SecurityException.class, "unrelated profile", () -> {
    +-                        mLauncherApps.getShortcuts(
    +-                                buildAllQuery(CALLING_PACKAGE_1), HANDLE_USER_0);
    +-                    });
    +-            assertExpectException(
    +-                    SecurityException.class, "unrelated profile", () -> {
    +-                        mLauncherApps.getShortcuts(
    +-                                buildAllQuery(CALLING_PACKAGE_1), HANDLE_USER_P0);
    +-                    });
    +-        });
    +-    }
    +-
    +-    public void testOnApplicationActive_permission() {
    +-        assertExpectException(SecurityException.class, "Missing permission", () ->
    +-                mManager.onApplicationActive(CALLING_PACKAGE_1, USER_0));
    +-
    +-        // Has permission, now it should pass.
    +-        mCallerPermissions.add(permission.RESET_SHORTCUT_MANAGER_THROTTLING);
    +-        mManager.onApplicationActive(CALLING_PACKAGE_1, USER_0);
    +-    }
    +-
    +-    public void testDumpsys_crossProfile() {
    +-        prepareCrossProfileDataSet();
    +-        dumpsysOnLogcat("test1", /* force= */ true);
    +-    }
    +-
    +-    public void testDumpsys_withIcons() throws IOException {
    +-        testIcons();
    +-        // Dump after having some icons.
    +-        dumpsysOnLogcat("test1", /* force= */ true);
    +-    }
    +-
    +-    public void testManifestShortcut_publishOnUnlockUser() {
    +-        addManifestShortcutResource(
    +-                new ComponentName(CALLING_PACKAGE_1, ShortcutActivity.class.getName()),
    +-                R.xml.shortcut_1);
    +-        addManifestShortcutResource(
    +-                new ComponentName(CALLING_PACKAGE_2, ShortcutActivity.class.getName()),
    +-                R.xml.shortcut_2);
    +-        addManifestShortcutResource(
    +-                new ComponentName(CALLING_PACKAGE_3, ShortcutActivity.class.getName()),
    +-                R.xml.shortcut_5);
    +-
    +-        // Unlock user-0.
    +-        mService.handleUnlockUser(USER_0);
    +-
    +-        runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
    +-            assertShortcutIds(assertAllManifest(assertAllImmutable(assertAllEnabled(
    +-                    mManager.getManifestShortcuts()))),
    +-                    "ms1");
    +-            assertEmpty(mManager.getPinnedShortcuts());
    +-        });
    +-
    +-        runWithCaller(CALLING_PACKAGE_2, USER_0, () -> {
    +-            assertShortcutIds(assertAllManifest(assertAllImmutable(assertAllEnabled(
    +-                    mManager.getManifestShortcuts()))),
    +-                    "ms1", "ms2");
    +-            assertEmpty(mManager.getPinnedShortcuts());
    +-        });
    +-
    +-        runWithCaller(CALLING_PACKAGE_3, USER_0, () -> {
    +-            assertShortcutIds(assertAllManifest(assertAllImmutable(assertAllEnabled(
    +-                    mManager.getManifestShortcuts()))),
    +-                    "ms1", "ms2", "ms3", "ms4", "ms5");
    +-            assertEmpty(mManager.getPinnedShortcuts());
    +-        });
    +-
    +-        // Try on another user, with some packages uninstalled.
    +-        mRunningUsers.put(USER_10, true);
    +-
    +-        uninstallPackage(USER_10, CALLING_PACKAGE_1);
    +-        uninstallPackage(USER_10, CALLING_PACKAGE_3);
    +-
    +-        mService.handleUnlockUser(USER_10);
    +-
    +-        runWithCaller(CALLING_PACKAGE_1, USER_10, () -> {
    +-            assertEmpty(mManager.getManifestShortcuts());
    +-            assertEmpty(mManager.getPinnedShortcuts());
    +-        });
    +-
    +-        runWithCaller(CALLING_PACKAGE_2, USER_10, () -> {
    +-            assertShortcutIds(assertAllManifest(assertAllImmutable(assertAllEnabled(
    +-                    mManager.getManifestShortcuts()))),
    +-                    "ms1", "ms2");
    +-            assertEmpty(mManager.getPinnedShortcuts());
    +-        });
    +-
    +-        runWithCaller(CALLING_PACKAGE_3, USER_10, () -> {
    +-            assertEmpty(mManager.getManifestShortcuts());
    +-            assertEmpty(mManager.getPinnedShortcuts());
    +-        });
    +-
    +-        // Now change the resources for package 1, and unlock again.
    +-        // But we still see *old* shortcuts, because the package version and install time
    +-        // hasn't changed.
    +-        shutdownServices();
    +-
    +-        addManifestShortcutResource(
    +-                new ComponentName(CALLING_PACKAGE_1, ShortcutActivity.class.getName()),
    +-                R.xml.shortcut_5);
    +-        addManifestShortcutResource(
    +-                new ComponentName(CALLING_PACKAGE_3, ShortcutActivity.class.getName()),
    +-                R.xml.shortcut_1);
    +-
    +-        initService();
    +-        mService.handleUnlockUser(USER_0);
    +-
    +-        runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
    +-            assertShortcutIds(assertAllManifest(assertAllImmutable(assertAllEnabled(
    +-                    mManager.getManifestShortcuts()))),
    +-                    "ms1");
    +-            assertEmpty(mManager.getPinnedShortcuts());
    +-        });
    +-
    +-        runWithCaller(CALLING_PACKAGE_2, USER_0, () -> {
    +-            assertShortcutIds(assertAllManifest(assertAllImmutable(assertAllEnabled(
    +-                    mManager.getManifestShortcuts()))),
    +-                    "ms1", "ms2");
    +-            assertEmpty(mManager.getPinnedShortcuts());
    +-        });
    +-
    +-        runWithCaller(CALLING_PACKAGE_3, USER_0, () -> {
    +-            assertShortcutIds(assertAllManifest(assertAllImmutable(assertAllEnabled(
    +-                    mManager.getManifestShortcuts()))),
    +-                    "ms1", "ms2", "ms3", "ms4", "ms5");
    +-            assertEmpty(mManager.getPinnedShortcuts());
    +-        });
    +-
    +-        // Do it again, but this time we change the app version, so we do detect the changes.
    +-        shutdownServices();
    +-
    +-        updatePackageVersion(CALLING_PACKAGE_1, 1);
    +-        updatePackageLastUpdateTime(CALLING_PACKAGE_3, 1);
    +-
    +-        initService();
    +-        mService.handleUnlockUser(USER_0);
    +-
    +-        runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
    +-            assertShortcutIds(assertAllManifest(assertAllImmutable(assertAllEnabled(
    +-                    mManager.getManifestShortcuts()))),
    +-                    "ms1", "ms2", "ms3", "ms4", "ms5");
    +-            assertEmpty(mManager.getPinnedShortcuts());
    +-        });
    +-
    +-        runWithCaller(CALLING_PACKAGE_2, USER_0, () -> {
    +-            assertShortcutIds(assertAllManifest(assertAllImmutable(assertAllEnabled(
    +-                    mManager.getManifestShortcuts()))),
    +-                    "ms1", "ms2");
    +-            assertEmpty(mManager.getPinnedShortcuts());
    +-        });
    +-
    +-        runWithCaller(CALLING_PACKAGE_3, USER_0, () -> {
    +-            assertShortcutIds(assertAllManifest(assertAllImmutable(assertAllEnabled(
    +-                    mManager.getManifestShortcuts()))),
    +-                    "ms1");
    +-            assertEmpty(mManager.getPinnedShortcuts());
    +-        });
    +-
    +-        // Next, try removing all shortcuts, with some of them pinned.
    +-        runWithCaller(LAUNCHER_1, USER_0, () -> {
    +-            mLauncherApps.pinShortcuts(CALLING_PACKAGE_1, list("ms3"), HANDLE_USER_0);
    +-            mLauncherApps.pinShortcuts(CALLING_PACKAGE_2, list("ms2"), HANDLE_USER_0);
    +-            mLauncherApps.pinShortcuts(CALLING_PACKAGE_3, list("ms1"), HANDLE_USER_0);
    +-        });
    +-        runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
    +-            assertShortcutIds(assertAllManifest(assertAllImmutable(assertAllEnabled(
    +-                    mManager.getManifestShortcuts()))),
    +-                    "ms1", "ms2", "ms3", "ms4", "ms5");
    +-            assertShortcutIds(assertAllImmutable(assertAllPinned(assertAllManifest(
    +-                    assertAllEnabled(mManager.getPinnedShortcuts())))),
    +-                    "ms3");
    +-        });
    +-
    +-        runWithCaller(CALLING_PACKAGE_2, USER_0, () -> {
    +-            assertShortcutIds(assertAllManifest(assertAllImmutable(assertAllEnabled(
    +-                    mManager.getManifestShortcuts()))),
    +-                    "ms1", "ms2");
    +-            assertShortcutIds(assertAllImmutable(assertAllPinned(assertAllManifest(
    +-                    assertAllEnabled(mManager.getPinnedShortcuts())))),
    +-                    "ms2");
    +-        });
    +-
    +-        runWithCaller(CALLING_PACKAGE_3, USER_0, () -> {
    +-            assertShortcutIds(assertAllManifest(assertAllImmutable(assertAllEnabled(
    +-                    mManager.getManifestShortcuts()))),
    +-                    "ms1");
    +-            assertShortcutIds(assertAllImmutable(assertAllPinned(assertAllManifest(
    +-                    assertAllEnabled(mManager.getPinnedShortcuts())))),
    +-                    "ms1");
    +-        });
    +-
    +-        shutdownServices();
    +-
    +-        addManifestShortcutResource(
    +-                new ComponentName(CALLING_PACKAGE_1, ShortcutActivity.class.getName()),
    +-                R.xml.shortcut_0);
    +-        addManifestShortcutResource(
    +-                new ComponentName(CALLING_PACKAGE_2, ShortcutActivity.class.getName()),
    +-                R.xml.shortcut_1);
    +-        addManifestShortcutResource(
    +-                new ComponentName(CALLING_PACKAGE_3, ShortcutActivity.class.getName()),
    +-                R.xml.shortcut_0);
    +-
    +-        updatePackageVersion(CALLING_PACKAGE_1, 1);
    +-        updatePackageVersion(CALLING_PACKAGE_2, 1);
    +-        updatePackageVersion(CALLING_PACKAGE_3, 1);
    +-
    +-        initService();
    +-        mService.handleUnlockUser(USER_0);
    +-
    +-        runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
    +-            assertEmpty(mManager.getManifestShortcuts());
    +-            assertShortcutIds(assertAllImmutable(assertAllPinned(assertAllNotManifest(
    +-                    assertAllDisabled(mManager.getPinnedShortcuts())))),
    +-                    "ms3");
    +-        });
    +-
    +-        runWithCaller(CALLING_PACKAGE_2, USER_0, () -> {
    +-            assertShortcutIds(assertAllManifest(assertAllImmutable(assertAllEnabled(
    +-                    mManager.getManifestShortcuts()))),
    +-                    "ms1");
    +-            assertShortcutIds(assertAllImmutable(assertAllPinned(assertAllNotManifest(
    +-                    assertAllDisabled(mManager.getPinnedShortcuts())))),
    +-                    "ms2");
    +-        });
    +-
    +-        runWithCaller(CALLING_PACKAGE_3, USER_0, () -> {
    +-            assertEmpty(mManager.getManifestShortcuts());
    +-            assertShortcutIds(assertAllImmutable(assertAllPinned(assertAllNotManifest(
    +-                    assertAllDisabled(mManager.getPinnedShortcuts())))),
    +-                    "ms1");
    +-        });
    +-
    +-        // Make sure we don't have ShortcutPackage for packages that don't have shortcuts.
    +-        assertNull(mService.getPackageShortcutForTest(CALLING_PACKAGE_4, USER_0));
    +-        assertNull(mService.getPackageShortcutForTest(LAUNCHER_1, USER_0));
    +-    }
    +-
    +-    public void testManifestShortcut_publishOnBroadcast() {
    +-        // First, no packages are installed.
    +-        uninstallPackage(USER_0, CALLING_PACKAGE_1);
    +-        uninstallPackage(USER_0, CALLING_PACKAGE_2);
    +-        uninstallPackage(USER_0, CALLING_PACKAGE_3);
    +-        uninstallPackage(USER_0, CALLING_PACKAGE_4);
    +-        uninstallPackage(USER_10, CALLING_PACKAGE_1);
    +-        uninstallPackage(USER_10, CALLING_PACKAGE_2);
    +-        uninstallPackage(USER_10, CALLING_PACKAGE_3);
    +-        uninstallPackage(USER_10, CALLING_PACKAGE_4);
    +-
    +-        mService.handleUnlockUser(USER_0);
    +-
    +-        mRunningUsers.put(USER_10, true);
    +-        mService.handleUnlockUser(USER_10);
    +-
    +-        // Originally no manifest shortcuts.
    +-        runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
    +-            assertEmpty(mManager.getManifestShortcuts());
    +-            assertEmpty(mManager.getPinnedShortcuts());
    +-        });
    +-
    +-        runWithCaller(CALLING_PACKAGE_2, USER_0, () -> {
    +-            assertEmpty(mManager.getManifestShortcuts());
    +-            assertEmpty(mManager.getPinnedShortcuts());
    +-        });
    +-
    +-        runWithCaller(CALLING_PACKAGE_3, USER_0, () -> {
    +-            assertEmpty(mManager.getManifestShortcuts());
    +-            assertEmpty(mManager.getPinnedShortcuts());
    +-        });
    +-
    +-        // Package 1 updated, with manifest shortcuts.
    +-        addManifestShortcutResource(
    +-                new ComponentName(CALLING_PACKAGE_1, ShortcutActivity.class.getName()),
    +-                R.xml.shortcut_1);
    +-        updatePackageVersion(CALLING_PACKAGE_1, 1);
    +-                mService.mPackageMonitor.onReceive(getTestContext(),
    +-                genPackageAddIntent(CALLING_PACKAGE_1, USER_0));
    +-
    +-        runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
    +-            assertShortcutIds(assertAllManifest(assertAllImmutable(assertAllEnabled(
    +-                    mManager.getManifestShortcuts()))),
    +-                    "ms1");
    +-            assertEmpty(mManager.getPinnedShortcuts());
    +-        });
    +-
    +-        runWithCaller(CALLING_PACKAGE_2, USER_0, () -> {
    +-            assertEmpty(mManager.getManifestShortcuts());
    +-            assertEmpty(mManager.getPinnedShortcuts());
    +-        });
    +-
    +-        // Package 2 updated, with manifest shortcuts.
    +-
    +-        addManifestShortcutResource(
    +-                new ComponentName(CALLING_PACKAGE_2, ShortcutActivity.class.getName()),
    +-                R.xml.shortcut_5);
    +-        updatePackageVersion(CALLING_PACKAGE_2, 1);
    +-                mService.mPackageMonitor.onReceive(getTestContext(),
    +-                genPackageAddIntent(CALLING_PACKAGE_2, USER_0));
    +-
    +-        runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
    +-            assertShortcutIds(assertAllManifest(assertAllImmutable(assertAllEnabled(
    +-                    mManager.getManifestShortcuts()))),
    +-                    "ms1");
    +-            assertEmpty(mManager.getPinnedShortcuts());
    +-        });
    +-
    +-        runWithCaller(CALLING_PACKAGE_2, USER_0, () -> {
    +-            assertShortcutIds(assertAllManifest(assertAllImmutable(assertAllEnabled(
    +-                    mManager.getManifestShortcuts()))),
    +-                    "ms1", "ms2", "ms3", "ms4", "ms5");
    +-            assertWith(getCallerShortcuts()).selectManifest()
    +-                    .selectByActivity(
    +-                            new ComponentName(CALLING_PACKAGE_2, ShortcutActivity.class.getName()))
    +-                    .haveRanksInOrder("ms1", "ms2", "ms3", "ms4", "ms5");
    +-            assertEmpty(mManager.getPinnedShortcuts());
    +-        });
    +-
    +-        // Package 2 updated, with less manifest shortcuts.
    +-        // This time we use updatePackageLastUpdateTime() instead of updatePackageVersion().
    +-
    +-        dumpsysOnLogcat("Before pinning");
    +-
    +-        // Also pin some.
    +-        runWithCaller(LAUNCHER_1, USER_0, () -> {
    +-            mLauncherApps.pinShortcuts(CALLING_PACKAGE_2, list("ms2", "ms3"), HANDLE_USER_0);
    +-        });
    +-
    +-        dumpsysOnLogcat("After pinning");
    +-
    +-        addManifestShortcutResource(
    +-                new ComponentName(CALLING_PACKAGE_2, ShortcutActivity.class.getName()),
    +-                R.xml.shortcut_2);
    +-        updatePackageLastUpdateTime(CALLING_PACKAGE_2, 1);
    +-                mService.mPackageMonitor.onReceive(getTestContext(),
    +-                genPackageAddIntent(CALLING_PACKAGE_2, USER_0));
    +-
    +-        runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
    +-            assertShortcutIds(assertAllManifest(assertAllImmutable(assertAllEnabled(
    +-                    mManager.getManifestShortcuts()))),
    +-                    "ms1");
    +-            assertEmpty(mManager.getPinnedShortcuts());
    +-        });
    +-
    +-        runWithCaller(CALLING_PACKAGE_2, USER_0, () -> {
    +-            assertShortcutIds(assertAllManifest(assertAllImmutable(assertAllEnabled(
    +-                    mManager.getManifestShortcuts()))),
    +-                    "ms1", "ms2");
    +-            assertWith(getCallerShortcuts()).selectManifest()
    +-                    .selectByActivity(
    +-                            new ComponentName(CALLING_PACKAGE_2, ShortcutActivity.class.getName()))
    +-                    .haveRanksInOrder("ms1", "ms2");
    +-            assertShortcutIds(assertAllImmutable(assertAllPinned(
    +-                    mManager.getPinnedShortcuts())),
    +-                    "ms2", "ms3");
    +-            // ms3 is no longer in manifest, so should be disabled.
    +-            // but ms1 and ms2 should be enabled.
    +-            assertAllEnabled(list(getCallerShortcut("ms1")));
    +-            assertAllEnabled(list(getCallerShortcut("ms2")));
    +-            assertAllDisabled(list(getCallerShortcut("ms3")));
    +-        });
    +-
    +-        // Package 2 on user 10 has no shortcuts yet.
    +-        runWithCaller(CALLING_PACKAGE_2, USER_10, () -> {
    +-            assertEmpty(mManager.getManifestShortcuts());
    +-            assertEmpty(mManager.getPinnedShortcuts());
    +-        });
    +-        // Send add broadcast, but the user is not running, so should be ignored.
    +-        mService.handleCleanupUser(USER_10);
    +-        mRunningUsers.put(USER_10, false);
    +-        mUnlockedUsers.put(USER_10, false);
    +-
    +-        mService.mPackageMonitor.onReceive(getTestContext(),
    +-                genPackageAddIntent(CALLING_PACKAGE_2, USER_10));
    +-        runWithCaller(CALLING_PACKAGE_2, USER_10, () -> {
    +-            // Don't use the mManager APIs to get shortcuts, because they'll trigger the package
    +-            // update check.
    +-            // So look the internal data directly using getCallerShortcuts().
    +-            assertEmpty(getCallerShortcuts());
    +-        });
    +-
    +-        // Try again, but the user is locked, so still ignored.
    +-        mRunningUsers.put(USER_10, true);
    +-                mService.mPackageMonitor.onReceive(getTestContext(),
    +-                genPackageAddIntent(CALLING_PACKAGE_2, USER_10));
    +-        runWithCaller(CALLING_PACKAGE_2, USER_10, () -> {
    +-            // Don't use the mManager APIs to get shortcuts, because they'll trigger the package
    +-            // update check.
    +-            // So look the internal data directly using getCallerShortcuts().
    +-            assertEmpty(getCallerShortcuts());
    +-        });
    +-
    +-        // Unlock the user, now it should work.
    +-        mUnlockedUsers.put(USER_10, true);
    +-
    +-        // Send PACKAGE_ADD broadcast to have Package 2 on user-10 publish manifest shortcuts.
    +-                mService.mPackageMonitor.onReceive(getTestContext(),
    +-                genPackageAddIntent(CALLING_PACKAGE_2, USER_10));
    +-
    +-        runWithCaller(CALLING_PACKAGE_2, USER_10, () -> {
    +-            assertShortcutIds(assertAllManifest(assertAllImmutable(assertAllEnabled(
    +-                    mManager.getManifestShortcuts()))),
    +-                    "ms1", "ms2");
    +-            assertWith(getCallerShortcuts()).selectManifest()
    +-                    .selectByActivity(
    +-                            new ComponentName(CALLING_PACKAGE_2, ShortcutActivity.class.getName()))
    +-                    .haveRanksInOrder("ms1", "ms2");
    +-            assertEmpty(mManager.getPinnedShortcuts());
    +-        });
    +-
    +-        // But it shouldn't affect user-0.
    +-        runWithCaller(CALLING_PACKAGE_2, USER_0, () -> {
    +-            assertShortcutIds(assertAllManifest(assertAllImmutable(assertAllEnabled(
    +-                    mManager.getManifestShortcuts()))),
    +-                    "ms1", "ms2");
    +-            assertWith(getCallerShortcuts()).selectManifest()
    +-                    .selectByActivity(
    +-                            new ComponentName(CALLING_PACKAGE_2, ShortcutActivity.class.getName()))
    +-                    .haveRanksInOrder("ms1", "ms2");
    +-            assertShortcutIds(assertAllImmutable(assertAllPinned(
    +-                    mManager.getPinnedShortcuts())),
    +-                    "ms2", "ms3");
    +-            assertAllEnabled(list(getCallerShortcut("ms1")));
    +-            assertAllEnabled(list(getCallerShortcut("ms2")));
    +-            assertAllDisabled(list(getCallerShortcut("ms3")));
    +-        });
    +-
    +-        // Multiple activities.
    +-        // Add shortcuts on activity 2 for package 2.
    +-        addManifestShortcutResource(
    +-                new ComponentName(CALLING_PACKAGE_2, ShortcutActivity.class.getName()),
    +-                R.xml.shortcut_5_alt);
    +-        addManifestShortcutResource(
    +-                new ComponentName(CALLING_PACKAGE_2, ShortcutActivity2.class.getName()),
    +-                R.xml.shortcut_5_reverse);
    +-
    +-        updatePackageLastUpdateTime(CALLING_PACKAGE_2, 1);
    +-                mService.mPackageMonitor.onReceive(getTestContext(),
    +-                genPackageAddIntent(CALLING_PACKAGE_2, USER_0));
    +-
    +-        runWithCaller(CALLING_PACKAGE_2, USER_0, () -> {
    +-            assertShortcutIds(assertAllManifest(assertAllImmutable(assertAllEnabled(
    +-                    mManager.getManifestShortcuts()))),
    +-                    "ms1", "ms2", "ms3", "ms4", "ms5",
    +-                    "ms1_alt", "ms2_alt", "ms3_alt", "ms4_alt", "ms5_alt");
    +-
    +-            // Make sure they have the correct ranks, regardless of their ID's alphabetical order.
    +-            assertWith(getCallerShortcuts()).selectManifest()
    +-                    .selectByActivity(
    +-                            new ComponentName(CALLING_PACKAGE_2, ShortcutActivity.class.getName()))
    +-                    .haveRanksInOrder("ms1_alt", "ms2_alt", "ms3_alt", "ms4_alt", "ms5_alt");
    +-            assertWith(getCallerShortcuts()).selectManifest()
    +-                    .selectByActivity(
    +-                            new ComponentName(CALLING_PACKAGE_2, ShortcutActivity2.class.getName()))
    +-                    .haveRanksInOrder("ms5", "ms4", "ms3", "ms2", "ms1");
    +-        });
    +-
    +-        // Package 2 now has no manifest shortcuts.
    +-        addManifestShortcutResource(
    +-                new ComponentName(CALLING_PACKAGE_2, ShortcutActivity.class.getName()),
    +-                R.xml.shortcut_0);
    +-        addManifestShortcutResource(
    +-                new ComponentName(CALLING_PACKAGE_2, ShortcutActivity2.class.getName()),
    +-                R.xml.shortcut_0);
    +-        updatePackageLastUpdateTime(CALLING_PACKAGE_2, 1);
    +-                mService.mPackageMonitor.onReceive(getTestContext(),
    +-                genPackageAddIntent(CALLING_PACKAGE_2, USER_0));
    +-
    +-        // No manifest shortcuts, and pinned ones are disabled.
    +-        runWithCaller(CALLING_PACKAGE_2, USER_0, () -> {
    +-            assertEmpty(mManager.getManifestShortcuts());
    +-            assertShortcutIds(assertAllImmutable(assertAllPinned(assertAllDisabled(
    +-                    mManager.getPinnedShortcuts()))),
    +-                    "ms2", "ms3");
    +-        });
    +-    }
    +-
    +-    public void testManifestShortcuts_missingMandatoryFields() {
    +-        // Start with no apps installed.
    +-        uninstallPackage(USER_0, CALLING_PACKAGE_1);
    +-        uninstallPackage(USER_0, CALLING_PACKAGE_2);
    +-        uninstallPackage(USER_0, CALLING_PACKAGE_3);
    +-        uninstallPackage(USER_0, CALLING_PACKAGE_4);
    +-
    +-        mService.handleUnlockUser(USER_0);
    +-
    +-        // Make sure no manifest shortcuts.
    +-        runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
    +-            assertEmpty(mManager.getManifestShortcuts());
    +-        });
    +-
    +-        // Package 1 updated, which has one valid manifest shortcut and one invalid.
    +-        addManifestShortcutResource(
    +-                new ComponentName(CALLING_PACKAGE_1, ShortcutActivity.class.getName()),
    +-                R.xml.shortcut_error_1);
    +-        updatePackageVersion(CALLING_PACKAGE_1, 1);
    +-                mService.mPackageMonitor.onReceive(getTestContext(),
    +-                genPackageAddIntent(CALLING_PACKAGE_1, USER_0));
    +-
    +-        // Only the valid one is published.
    +-        runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
    +-            assertWith(getCallerShortcuts())
    +-                    .areAllManifest()
    +-                    .areAllImmutable()
    +-                    .areAllEnabled()
    +-                    .haveIds("x1");
    +-        });
    +-
    +-        // Package 1 updated, which has one valid manifest shortcut and one invalid.
    +-        addManifestShortcutResource(
    +-                new ComponentName(CALLING_PACKAGE_1, ShortcutActivity.class.getName()),
    +-                R.xml.shortcut_error_2);
    +-        updatePackageVersion(CALLING_PACKAGE_1, 1);
    +-                mService.mPackageMonitor.onReceive(getTestContext(),
    +-                genPackageAddIntent(CALLING_PACKAGE_1, USER_0));
    +-
    +-        // Only the valid one is published.
    +-        runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
    +-            assertWith(getCallerShortcuts())
    +-                    .areAllManifest()
    +-                    .areAllImmutable()
    +-                    .areAllEnabled()
    +-                    .haveIds("x2");
    +-        });
    +-
    +-        // Package 1 updated, which has one valid manifest shortcut and one invalid.
    +-        addManifestShortcutResource(
    +-                new ComponentName(CALLING_PACKAGE_1, ShortcutActivity.class.getName()),
    +-                R.xml.shortcut_error_3);
    +-        updatePackageVersion(CALLING_PACKAGE_1, 1);
    +-                mService.mPackageMonitor.onReceive(getTestContext(),
    +-                genPackageAddIntent(CALLING_PACKAGE_1, USER_0));
    +-
    +-        // Only the valid one is published.
    +-        runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
    +-            assertWith(getCallerShortcuts())
    +-                    .areAllManifest()
    +-                    .areAllImmutable()
    +-                    .areAllEnabled()
    +-                    .haveIds("x3")
    +-                    .forShortcutWithId("x3", si -> {
    +-                        assertEquals(set("cat2"), si.getCategories());
    +-                     });
    +-        });
    +-    }
    +-
    +-    public void testManifestShortcuts_intentDefinitions() {
    +-        addManifestShortcutResource(
    +-                new ComponentName(CALLING_PACKAGE_1, ShortcutActivity.class.getName()),
    +-                R.xml.shortcut_error_4);
    +-        updatePackageVersion(CALLING_PACKAGE_1, 1);
    +-                mService.mPackageMonitor.onReceive(getTestContext(),
    +-                genPackageAddIntent(CALLING_PACKAGE_1, USER_0));
    +-
    +-        runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
    +-            // Make sure invalid ones are not published.
    +-            // Note that at this point disabled ones don't show up because they weren't pinned.
    +-            assertWith(getCallerShortcuts())
    +-                    .haveIds("ms1", "ms2")
    +-                    .areAllManifest()
    +-                    .areAllNotDynamic()
    +-                    .areAllNotPinned()
    +-                    .areAllImmutable()
    +-                    .areAllEnabled()
    +-                    .forShortcutWithId("ms1", si -> {
    +-                        assertTrue(si.isEnabled());
    +-                        assertEquals(1, si.getIntents().length);
    +-
    +-                        assertEquals("action1", si.getIntent().getAction());
    +-                        assertEquals("value1", si.getIntent().getStringExtra("key1"));
    +-                        assertEquals(Intent.FLAG_ACTIVITY_NEW_TASK |
    +-                                Intent.FLAG_ACTIVITY_CLEAR_TASK |
    +-                                Intent.FLAG_ACTIVITY_TASK_ON_HOME, si.getIntent().getFlags());
    +-
    +-                        assertEquals("action1", si.getIntents()[0].getAction());
    +-                        assertEquals("value1", si.getIntents()[0].getStringExtra("key1"));
    +-                        assertEquals(Intent.FLAG_ACTIVITY_NEW_TASK |
    +-                                Intent.FLAG_ACTIVITY_CLEAR_TASK |
    +-                                Intent.FLAG_ACTIVITY_TASK_ON_HOME, si.getIntents()[0].getFlags());
    +-                    })
    +-                    .forShortcutWithId("ms2", si -> {
    +-                        assertTrue(si.isEnabled());
    +-                        assertEquals(2, si.getIntents().length);
    +-
    +-                        // getIntent will return the last one.
    +-                        assertEquals("action2_2", si.getIntent().getAction());
    +-                        assertEquals("value2", si.getIntent().getStringExtra("key2"));
    +-                        assertEquals(0, si.getIntent().getFlags());
    +-
    +-                        final Intent i1 = si.getIntents()[0];
    +-                        final Intent i2 = si.getIntents()[1];
    +-
    +-                        assertEquals("action2_1", i1.getAction());
    +-                        assertEquals("value1", i1.getStringExtra("key1"));
    +-                        assertEquals(Intent.FLAG_ACTIVITY_NEW_TASK |
    +-                                        Intent.FLAG_ACTIVITY_CLEAR_TASK |
    +-                                        Intent.FLAG_ACTIVITY_TASK_ON_HOME, i1.getFlags());
    +-
    +-                        assertEquals("action2_2", i2.getAction());
    +-                        assertEquals("value2", i2.getStringExtra("key2"));
    +-                        assertEquals(0, i2.getFlags());
    +-                    });
    +-        });
    +-
    +-        // Publish 5 enabled to pin some, so we can later test disabled manfiest shortcuts..
    +-        addManifestShortcutResource(
    +-                new ComponentName(CALLING_PACKAGE_1, ShortcutActivity.class.getName()),
    +-                R.xml.shortcut_5);
    +-        updatePackageVersion(CALLING_PACKAGE_1, 1);
    +-                mService.mPackageMonitor.onReceive(getTestContext(),
    +-                genPackageAddIntent(CALLING_PACKAGE_1, USER_0));
    +-
    +-        runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
    +-            // Make sure 5 manifest shortcuts are published.
    +-            assertWith(getCallerShortcuts())
    +-                    .haveIds("ms1", "ms2", "ms3", "ms4", "ms5")
    +-                    .areAllManifest()
    +-                    .areAllNotDynamic()
    +-                    .areAllNotPinned()
    +-                    .areAllImmutable()
    +-                    .areAllEnabled();
    +-        });
    +-
    +-        runWithCaller(LAUNCHER_1, USER_0, () -> {
    +-            mLauncherApps.pinShortcuts(CALLING_PACKAGE_1,
    +-                    list("ms3", "ms4", "ms5"), HANDLE_USER_0);
    +-        });
    +-
    +-        // Make sure they're pinned.
    +-        runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
    +-            assertWith(getCallerShortcuts())
    +-                    .haveIds("ms1", "ms2", "ms3", "ms4", "ms5")
    +-                    .selectByIds("ms1", "ms2")
    +-                    .areAllNotPinned()
    +-                    .areAllEnabled()
    +-
    +-                    .revertToOriginalList()
    +-                    .selectByIds("ms3", "ms4", "ms5")
    +-                    .areAllPinned()
    +-                    .areAllEnabled();
    +-        });
    +-
    +-        // Update the app.
    +-        addManifestShortcutResource(
    +-                new ComponentName(CALLING_PACKAGE_1, ShortcutActivity.class.getName()),
    +-                R.xml.shortcut_error_4);
    +-        updatePackageVersion(CALLING_PACKAGE_1, 1);
    +-                mService.mPackageMonitor.onReceive(getTestContext(),
    +-                genPackageAddIntent(CALLING_PACKAGE_1, USER_0));
    +-
    +-        // Make sure 3, 4 and 5 still exist but disabled.
    +-        runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
    +-            assertWith(getCallerShortcuts())
    +-                    .haveIds("ms1", "ms2", "ms3", "ms4", "ms5")
    +-                    .areAllNotDynamic()
    +-                    .areAllImmutable()
    +-
    +-                    .selectByIds("ms1", "ms2")
    +-                    .areAllManifest()
    +-                    .areAllNotPinned()
    +-                    .areAllEnabled()
    +-
    +-                    .revertToOriginalList()
    +-                    .selectByIds("ms3", "ms4", "ms5")
    +-                    .areAllNotManifest()
    +-                    .areAllPinned()
    +-                    .areAllDisabled()
    +-
    +-                    .revertToOriginalList()
    +-                    .forShortcutWithId("ms1", si -> {
    +-                        assertEquals(si.getId(), "action1", si.getIntent().getAction());
    +-                    })
    +-                    .forShortcutWithId("ms2", si -> {
    +-                        // getIntent returns the last one.
    +-                        assertEquals(si.getId(), "action2_2", si.getIntent().getAction());
    +-                    })
    +-                    .forShortcutWithId("ms3", si -> {
    +-                        assertEquals(si.getId(), Intent.ACTION_VIEW, si.getIntent().getAction());
    +-                    })
    +-                    .forShortcutWithId("ms4", si -> {
    +-                        assertEquals(si.getId(), Intent.ACTION_VIEW, si.getIntent().getAction());
    +-                    })
    +-                    .forShortcutWithId("ms5", si -> {
    +-                        assertEquals(si.getId(), "action", si.getIntent().getAction());
    +-                    });
    +-        });
    +-    }
    +-
    +-    public void testManifestShortcuts_checkAllFields() {
    +-        mService.handleUnlockUser(USER_0);
    +-
    +-        // Package 1 updated, which has one valid manifest shortcut and one invalid.
    +-        addManifestShortcutResource(
    +-                new ComponentName(CALLING_PACKAGE_1, ShortcutActivity.class.getName()),
    +-                R.xml.shortcut_5);
    +-        updatePackageVersion(CALLING_PACKAGE_1, 1);
    +-                mService.mPackageMonitor.onReceive(getTestContext(),
    +-                genPackageAddIntent(CALLING_PACKAGE_1, USER_0));
    +-
    +-        // Only the valid one is published.
    +-        runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
    +-            assertWith(getCallerShortcuts())
    +-                    .haveIds("ms1", "ms2", "ms3", "ms4", "ms5")
    +-                    .areAllManifest()
    +-                    .areAllImmutable()
    +-                    .areAllEnabled()
    +-                    .areAllNotPinned()
    +-                    .areAllNotDynamic()
    +-
    +-                    .forShortcutWithId("ms1", si -> {
    +-                        assertEquals(R.drawable.icon1, si.getIconResourceId());
    +-                        assertEquals(new ComponentName(CALLING_PACKAGE_1,
    +-                                ShortcutActivity.class.getName()),
    +-                                si.getActivity());
    +-
    +-                        assertEquals(R.string.shortcut_title1, si.getTitleResId());
    +-                        assertEquals("r" + R.string.shortcut_title1, si.getTitleResName());
    +-                        assertEquals(R.string.shortcut_text1, si.getTextResId());
    +-                        assertEquals("r" + R.string.shortcut_text1, si.getTextResName());
    +-                        assertEquals(R.string.shortcut_disabled_message1,
    +-                                si.getDisabledMessageResourceId());
    +-                        assertEquals("r" + R.string.shortcut_disabled_message1,
    +-                                si.getDisabledMessageResName());
    +-
    +-                        assertEquals(set("android.shortcut.conversation", "android.shortcut.media"),
    +-                                si.getCategories());
    +-                        assertEquals("action1", si.getIntent().getAction());
    +-                        assertEquals(Uri.parse("http://a.b.c/1"), si.getIntent().getData());
    +-                    })
    +-
    +-                    .forShortcutWithId("ms2", si -> {
    +-                        assertEquals("ms2", si.getId());
    +-                        assertEquals(R.drawable.icon2, si.getIconResourceId());
    +-
    +-                        assertEquals(R.string.shortcut_title2, si.getTitleResId());
    +-                        assertEquals("r" + R.string.shortcut_title2, si.getTitleResName());
    +-                        assertEquals(R.string.shortcut_text2, si.getTextResId());
    +-                        assertEquals("r" + R.string.shortcut_text2, si.getTextResName());
    +-                        assertEquals(R.string.shortcut_disabled_message2,
    +-                                si.getDisabledMessageResourceId());
    +-                        assertEquals("r" + R.string.shortcut_disabled_message2,
    +-                                si.getDisabledMessageResName());
    +-
    +-                        assertEquals(set("android.shortcut.conversation"), si.getCategories());
    +-                        assertEquals("action2", si.getIntent().getAction());
    +-                        assertEquals(null, si.getIntent().getData());
    +-                    })
    +-
    +-                    .forShortcutWithId("ms3", si -> {
    +-                        assertEquals(0, si.getIconResourceId());
    +-                        assertEquals(R.string.shortcut_title1, si.getTitleResId());
    +-                        assertEquals("r" + R.string.shortcut_title1, si.getTitleResName());
    +-
    +-                        assertEquals(0, si.getTextResId());
    +-                        assertEquals(null, si.getTextResName());
    +-                        assertEquals(0, si.getDisabledMessageResourceId());
    +-                        assertEquals(null, si.getDisabledMessageResName());
    +-
    +-                        assertEmpty(si.getCategories());
    +-                        assertEquals("android.intent.action.VIEW", si.getIntent().getAction());
    +-                        assertEquals(null, si.getIntent().getData());
    +-                    })
    +-
    +-                    .forShortcutWithId("ms4", si -> {
    +-                        assertEquals(0, si.getIconResourceId());
    +-                        assertEquals(R.string.shortcut_title2, si.getTitleResId());
    +-                        assertEquals("r" + R.string.shortcut_title2, si.getTitleResName());
    +-
    +-                        assertEquals(0, si.getTextResId());
    +-                        assertEquals(null, si.getTextResName());
    +-                        assertEquals(0, si.getDisabledMessageResourceId());
    +-                        assertEquals(null, si.getDisabledMessageResName());
    +-
    +-                        assertEquals(set("cat"), si.getCategories());
    +-                        assertEquals("android.intent.action.VIEW2", si.getIntent().getAction());
    +-                        assertEquals(null, si.getIntent().getData());
    +-                    })
    +-
    +-                    .forShortcutWithId("ms5", si -> {
    +-                        si = getCallerShortcut("ms5");
    +-                        assertEquals("action", si.getIntent().getAction());
    +-                        assertEquals("http://www/", si.getIntent().getData().toString());
    +-                        assertEquals("foo/bar", si.getIntent().getType());
    +-                        assertEquals(
    +-                                new ComponentName("abc", ".xyz"), si.getIntent().getComponent());
    +-
    +-                        assertEquals(set("cat1", "cat2"), si.getIntent().getCategories());
    +-                        assertEquals("value1", si.getIntent().getStringExtra("key1"));
    +-                        assertEquals("value2", si.getIntent().getStringExtra("key2"));
    +-                    });
    +-        });
    +-    }
    +-
    +-    public void testManifestShortcuts_localeChange() throws InterruptedException {
    +-        mService.handleUnlockUser(USER_0);
    +-
    +-        // Package 1 updated, which has one valid manifest shortcut and one invalid.
    +-        addManifestShortcutResource(
    +-                new ComponentName(CALLING_PACKAGE_1, ShortcutActivity.class.getName()),
    +-                R.xml.shortcut_2);
    +-        updatePackageVersion(CALLING_PACKAGE_1, 1);
    +-                mService.mPackageMonitor.onReceive(getTestContext(),
    +-                genPackageAddIntent(CALLING_PACKAGE_1, USER_0));
    +-
    +-        runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
    +-            mManager.setDynamicShortcuts(list(makeShortcutWithTitle("s1", "title")));
    +-
    +-            assertShortcutIds(assertAllManifest(assertAllImmutable(assertAllEnabled(
    +-                    mManager.getManifestShortcuts()))),
    +-                    "ms1", "ms2");
    +-
    +-            // check first shortcut.
    +-            ShortcutInfo si = getCallerShortcut("ms1");
    +-
    +-            assertEquals("ms1", si.getId());
    +-            assertEquals("string-com.android.test.1-user:0-res:" + R.string.shortcut_title1 + "/en",
    +-                    si.getTitle());
    +-            assertEquals("string-com.android.test.1-user:0-res:" + R.string.shortcut_text1 + "/en",
    +-                    si.getText());
    +-            assertEquals("string-com.android.test.1-user:0-res:"
    +-                            + R.string.shortcut_disabled_message1 + "/en",
    +-                    si.getDisabledMessage());
    +-            assertEquals(START_TIME, si.getLastChangedTimestamp());
    +-
    +-            // check another
    +-            si = getCallerShortcut("ms2");
    +-
    +-            assertEquals("ms2", si.getId());
    +-            assertEquals("string-com.android.test.1-user:0-res:" + R.string.shortcut_title2 + "/en",
    +-                    si.getTitle());
    +-            assertEquals("string-com.android.test.1-user:0-res:" + R.string.shortcut_text2 + "/en",
    +-                    si.getText());
    +-            assertEquals("string-com.android.test.1-user:0-res:"
    +-                            + R.string.shortcut_disabled_message2 + "/en",
    +-                    si.getDisabledMessage());
    +-            assertEquals(START_TIME, si.getLastChangedTimestamp());
    +-
    +-            // Check the dynamic one.
    +-            si = getCallerShortcut("s1");
    +-
    +-            assertEquals("s1", si.getId());
    +-            assertEquals("title", si.getTitle());
    +-            assertEquals(null, si.getText());
    +-            assertEquals(null, si.getDisabledMessage());
    +-            assertEquals(START_TIME, si.getLastChangedTimestamp());
    +-        });
    +-
    +-        mInjectedCurrentTimeMillis++;
    +-
    +-        // Change the locale and send the broadcast, make sure the launcher gets a callback too.
    +-        mInjectedLocale = Locale.JAPANESE;
    +-
    +-        setCaller(LAUNCHER_1, USER_0);
    +-
    +-        assertForLauncherCallback(mLauncherApps, () -> {
    +-            mService.mReceiver.onReceive(mServiceContext, new Intent(Intent.ACTION_LOCALE_CHANGED));
    +-        }).assertCallbackCalledForPackageAndUser(CALLING_PACKAGE_1, HANDLE_USER_0)
    +-                .haveIds("ms1", "ms2", "s1");
    +-
    +-        runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
    +-            // check first shortcut.
    +-            ShortcutInfo si = getCallerShortcut("ms1");
    +-
    +-            assertEquals("ms1", si.getId());
    +-            assertEquals("string-com.android.test.1-user:0-res:" + R.string.shortcut_title1 + "/ja",
    +-                    si.getTitle());
    +-            assertEquals("string-com.android.test.1-user:0-res:" + R.string.shortcut_text1 + "/ja",
    +-                    si.getText());
    +-            assertEquals("string-com.android.test.1-user:0-res:"
    +-                            + R.string.shortcut_disabled_message1 + "/ja",
    +-                    si.getDisabledMessage());
    +-            assertEquals(START_TIME + 1, si.getLastChangedTimestamp());
    +-
    +-            // check another
    +-            si = getCallerShortcut("ms2");
    +-
    +-            assertEquals("ms2", si.getId());
    +-            assertEquals("string-com.android.test.1-user:0-res:" + R.string.shortcut_title2 + "/ja",
    +-                    si.getTitle());
    +-            assertEquals("string-com.android.test.1-user:0-res:" + R.string.shortcut_text2 + "/ja",
    +-                    si.getText());
    +-            assertEquals("string-com.android.test.1-user:0-res:"
    +-                            + R.string.shortcut_disabled_message2 + "/ja",
    +-                    si.getDisabledMessage());
    +-            assertEquals(START_TIME + 1, si.getLastChangedTimestamp());
    +-
    +-            // Check the dynamic one.  (locale change shouldn't affect.)
    +-            si = getCallerShortcut("s1");
    +-
    +-            assertEquals("s1", si.getId());
    +-            assertEquals("title", si.getTitle());
    +-            assertEquals(null, si.getText());
    +-            assertEquals(null, si.getDisabledMessage());
    +-            assertEquals(START_TIME, si.getLastChangedTimestamp()); // Not changed.
    +-        });
    +-    }
    +-
    +-    public void testManifestShortcuts_updateAndDisabled_notPinned() {
    +-        mService.handleUnlockUser(USER_0);
    +-
    +-        // First, just publish a manifest shortcut.
    +-        addManifestShortcutResource(
    +-                new ComponentName(CALLING_PACKAGE_1, ShortcutActivity.class.getName()),
    +-                R.xml.shortcut_1);
    +-        updatePackageVersion(CALLING_PACKAGE_1, 1);
    +-                mService.mPackageMonitor.onReceive(getTestContext(),
    +-                genPackageAddIntent(CALLING_PACKAGE_1, USER_0));
    +-
    +-        // Only the valid one is published.
    +-        runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
    +-            assertShortcutIds(assertAllManifest(assertAllImmutable(assertAllEnabled(
    +-                    mManager.getManifestShortcuts()))),
    +-                    "ms1");
    +-            assertEmpty(mManager.getPinnedShortcuts());
    +-
    +-            // Make sure there's no other dangling shortcuts.
    +-            assertShortcutIds(getCallerShortcuts(), "ms1");
    +-        });
    +-
    +-        // Now version up, the manifest shortcut is disabled now.
    +-        addManifestShortcutResource(
    +-                new ComponentName(CALLING_PACKAGE_1, ShortcutActivity.class.getName()),
    +-                R.xml.shortcut_1_disable);
    +-        updatePackageVersion(CALLING_PACKAGE_1, 1);
    +-                mService.mPackageMonitor.onReceive(getTestContext(),
    +-                genPackageAddIntent(CALLING_PACKAGE_1, USER_0));
    +-
    +-        // Because shortcut 1 wasn't pinned, it'll just go away.
    +-        runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
    +-            assertEmpty(mManager.getManifestShortcuts());
    +-            assertEmpty(mManager.getPinnedShortcuts());
    +-
    +-            // Make sure there's no other dangling shortcuts.
    +-            assertEmpty(getCallerShortcuts());
    +-        });
    +-    }
    +-
    +-    public void testManifestShortcuts_updateAndDisabled_pinned() {
    +-        mService.handleUnlockUser(USER_0);
    +-
    +-        // First, just publish a manifest shortcut.
    +-        addManifestShortcutResource(
    +-                new ComponentName(CALLING_PACKAGE_1, ShortcutActivity.class.getName()),
    +-                R.xml.shortcut_1);
    +-        updatePackageVersion(CALLING_PACKAGE_1, 1);
    +-                mService.mPackageMonitor.onReceive(getTestContext(),
    +-                genPackageAddIntent(CALLING_PACKAGE_1, USER_0));
    +-
    +-        // Only the valid one is published.
    +-        runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
    +-            assertShortcutIds(assertAllManifest(assertAllImmutable(assertAllEnabled(
    +-                    mManager.getManifestShortcuts()))),
    +-                    "ms1");
    +-            assertEmpty(mManager.getPinnedShortcuts());
    +-
    +-            // Make sure there's no other dangling shortcuts.
    +-            assertShortcutIds(getCallerShortcuts(), "ms1");
    +-        });
    +-
    +-        runWithCaller(LAUNCHER_1, USER_0, () -> {
    +-            mLauncherApps.pinShortcuts(CALLING_PACKAGE_1, list("ms1"), HANDLE_USER_0);
    +-        });
    +-
    +-        // Now upgrade, the manifest shortcut is disabled now.
    +-        addManifestShortcutResource(
    +-                new ComponentName(CALLING_PACKAGE_1, ShortcutActivity.class.getName()),
    +-                R.xml.shortcut_1_disable);
    +-        updatePackageVersion(CALLING_PACKAGE_1, 1);
    +-                mService.mPackageMonitor.onReceive(getTestContext(),
    +-                genPackageAddIntent(CALLING_PACKAGE_1, USER_0));
    +-
    +-        // Because shortcut 1 was pinned, it'll still exist as pinned, but disabled.
    +-        runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
    +-            assertEmpty(mManager.getManifestShortcuts());
    +-            assertShortcutIds(assertAllNotManifest(assertAllImmutable(assertAllDisabled(
    +-                    mManager.getPinnedShortcuts()))),
    +-                    "ms1");
    +-
    +-            // Make sure the fields are updated.
    +-            ShortcutInfo si = getCallerShortcut("ms1");
    +-
    +-            assertEquals("ms1", si.getId());
    +-            assertEquals(R.drawable.icon2, si.getIconResourceId());
    +-            assertEquals(R.string.shortcut_title2, si.getTitleResId());
    +-            assertEquals(R.string.shortcut_text2, si.getTextResId());
    +-            assertEquals(R.string.shortcut_disabled_message2, si.getDisabledMessageResourceId());
    +-            assertEquals(Intent.ACTION_VIEW, si.getIntent().getAction());
    +-
    +-            // Make sure there's no other dangling shortcuts.
    +-            assertShortcutIds(getCallerShortcuts(), "ms1");
    +-        });
    +-    }
    +-
    +-    public void testManifestShortcuts_duplicateInSingleActivity() {
    +-        mService.handleUnlockUser(USER_0);
    +-
    +-        // The XML has two shortcuts with the same ID.
    +-        addManifestShortcutResource(
    +-                new ComponentName(CALLING_PACKAGE_1, ShortcutActivity.class.getName()),
    +-                R.xml.shortcut_2_duplicate);
    +-        updatePackageVersion(CALLING_PACKAGE_1, 1);
    +-                mService.mPackageMonitor.onReceive(getTestContext(),
    +-                genPackageAddIntent(CALLING_PACKAGE_1, USER_0));
    +-
    +-        runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
    +-            assertShortcutIds(assertAllManifest(assertAllImmutable(assertAllEnabled(
    +-                    mManager.getManifestShortcuts()))),
    +-                    "ms1");
    +-
    +-            // Make sure the first one has survived.  (the second one has a different title.)
    +-            ShortcutInfo si = getCallerShortcut("ms1");
    +-            assertEquals(R.string.shortcut_title1, si.getTitleResId());
    +-
    +-            // Make sure there's no other dangling shortcuts.
    +-            assertShortcutIds(getCallerShortcuts(), "ms1");
    +-        });
    +-    }
    +-
    +-    public void testManifestShortcuts_duplicateInTwoActivities() {
    +-        mService.handleUnlockUser(USER_0);
    +-
    +-        // ShortcutActivity has shortcut ms1
    +-        addManifestShortcutResource(
    +-                new ComponentName(CALLING_PACKAGE_1, ShortcutActivity.class.getName()),
    +-                R.xml.shortcut_1);
    +-
    +-        // ShortcutActivity2 has two shortcuts, ms1 and ms2.
    +-        addManifestShortcutResource(
    +-                new ComponentName(CALLING_PACKAGE_1, ShortcutActivity2.class.getName()),
    +-                R.xml.shortcut_5);
    +-        updatePackageVersion(CALLING_PACKAGE_1, 1);
    +-                mService.mPackageMonitor.onReceive(getTestContext(),
    +-                genPackageAddIntent(CALLING_PACKAGE_1, USER_0));
    +-
    +-        runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
    +-            assertShortcutIds(assertAllManifest(assertAllImmutable(assertAllEnabled(
    +-                    mManager.getManifestShortcuts()))),
    +-                    "ms1", "ms2", "ms3", "ms4", "ms5");
    +-
    +-            // ms1 should belong to ShortcutActivity.
    +-            ShortcutInfo si = getCallerShortcut("ms1");
    +-            assertEquals(R.string.shortcut_title1, si.getTitleResId());
    +-            assertEquals(new ComponentName(CALLING_PACKAGE_1, ShortcutActivity.class.getName()),
    +-                    si.getActivity());
    +-            assertEquals(0, si.getRank());
    +-
    +-            // ms2 should belong to ShortcutActivity*2*.
    +-            si = getCallerShortcut("ms2");
    +-            assertEquals(R.string.shortcut_title2, si.getTitleResId());
    +-            assertEquals(new ComponentName(CALLING_PACKAGE_1, ShortcutActivity2.class.getName()),
    +-                    si.getActivity());
    +-
    +-            // Also check the ranks
    +-            assertWith(getCallerShortcuts()).selectManifest()
    +-                    .selectByActivity(
    +-                            new ComponentName(CALLING_PACKAGE_1, ShortcutActivity.class.getName()))
    +-                    .haveRanksInOrder("ms1");
    +-            assertWith(getCallerShortcuts()).selectManifest()
    +-                    .selectByActivity(
    +-                            new ComponentName(CALLING_PACKAGE_1, ShortcutActivity2.class.getName()))
    +-                    .haveRanksInOrder("ms2", "ms3", "ms4", "ms5");
    +-
    +-            // Make sure there's no other dangling shortcuts.
    +-            assertShortcutIds(getCallerShortcuts(), "ms1", "ms2", "ms3", "ms4", "ms5");
    +-        });
    +-    }
    +-
    +-    /**
    +-     * Manifest shortcuts cannot override shortcuts that were published via the APIs.
    +-     */
    +-    public void testManifestShortcuts_cannotOverrideNonManifest() {
    +-        mService.handleUnlockUser(USER_0);
    +-
    +-        // Create a non-pinned dynamic shortcut and a non-dynamic pinned shortcut.
    +-
    +-        runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
    +-            mManager.setDynamicShortcuts(list(
    +-                    makeShortcut("ms1", "title1",
    +-                            new ComponentName(CALLING_PACKAGE_1, ShortcutActivity.class.getName()),
    +-                    /* icon */ null, new Intent("action1"), /* rank */ 0),
    +-                    makeShortcut("ms2", "title2",
    +-                            new ComponentName(CALLING_PACKAGE_1, ShortcutActivity.class.getName()),
    +-                    /* icon */ null, new Intent("action1"), /* rank */ 0)));
    +-        });
    +-
    +-        runWithCaller(LAUNCHER_1, USER_0, () -> {
    +-            mLauncherApps.pinShortcuts(CALLING_PACKAGE_1, list("ms2"), HANDLE_USER_0);
    +-        });
    +-
    +-        runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
    +-            mManager.removeDynamicShortcuts(list("ms2"));
    +-
    +-            assertShortcutIds(mManager.getDynamicShortcuts(), "ms1");
    +-            assertShortcutIds(mManager.getPinnedShortcuts(), "ms2");
    +-            assertEmpty(mManager.getManifestShortcuts());
    +-        });
    +-
    +-        // Then update the app with 5 manifest shortcuts.
    +-        // Make sure "ms1" and "ms2" won't be replaced.
    +-        addManifestShortcutResource(
    +-                new ComponentName(CALLING_PACKAGE_1, ShortcutActivity.class.getName()),
    +-                R.xml.shortcut_5);
    +-        updatePackageVersion(CALLING_PACKAGE_1, 1);
    +-                mService.mPackageMonitor.onReceive(getTestContext(),
    +-                genPackageAddIntent(CALLING_PACKAGE_1, USER_0));
    +-
    +-        runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
    +-            assertShortcutIds(assertAllNotManifest(mManager.getDynamicShortcuts()), "ms1");
    +-            assertShortcutIds(assertAllNotManifest(mManager.getPinnedShortcuts()), "ms2");
    +-            assertShortcutIds(assertAllManifest(mManager.getManifestShortcuts()),
    +-                    "ms3", "ms4", "ms5");
    +-
    +-            // ms1 and ms2 shouold keep the original title.
    +-            ShortcutInfo si = getCallerShortcut("ms1");
    +-            assertEquals("title1", si.getTitle());
    +-
    +-            si = getCallerShortcut("ms2");
    +-            assertEquals("title2", si.getTitle());
    +-        });
    +-    }
    +-
    +-    protected void checkManifestShortcuts_immutable_verify() {
    +-        runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
    +-            assertShortcutIds(assertAllNotManifest(assertAllEnabled(
    +-                    mManager.getDynamicShortcuts())),
    +-                    "s1");
    +-            assertShortcutIds(assertAllManifest(assertAllEnabled(
    +-                    mManager.getManifestShortcuts())),
    +-                    "ms1");
    +-            assertShortcutIds(assertAllNotManifest(assertAllDisabled(
    +-                    mManager.getPinnedShortcuts())),
    +-                    "ms2");
    +-
    +-            assertEquals("t1", getCallerShortcut("s1").getTitle());
    +-
    +-            // Make sure there are no other shortcuts.
    +-            assertShortcutIds(getCallerShortcuts(), "s1", "ms1", "ms2");
    +-        });
    +-    }
    +-
    +-    /**
    +-     * Make sure the APIs won't work on manifest shortcuts.
    +-     */
    +-    public void testManifestShortcuts_immutable() {
    +-        mService.handleUnlockUser(USER_0);
    +-
    +-        // Create a non-pinned manifest shortcut, a pinned shortcut that was originally
    +-        // a manifest shortcut, as well as a dynamic shortcut.
    +-
    +-        addManifestShortcutResource(
    +-                new ComponentName(CALLING_PACKAGE_1, ShortcutActivity.class.getName()),
    +-                R.xml.shortcut_2);
    +-        updatePackageVersion(CALLING_PACKAGE_1, 1);
    +-                mService.mPackageMonitor.onReceive(getTestContext(),
    +-                genPackageAddIntent(CALLING_PACKAGE_1, USER_0));
    +-
    +-        runWithCaller(LAUNCHER_1, USER_0, () -> {
    +-            mLauncherApps.pinShortcuts(CALLING_PACKAGE_1, list("ms2"), HANDLE_USER_0);
    +-        });
    +-
    +-        addManifestShortcutResource(
    +-                new ComponentName(CALLING_PACKAGE_1, ShortcutActivity.class.getName()),
    +-                R.xml.shortcut_1);
    +-        updatePackageVersion(CALLING_PACKAGE_1, 1);
    +-                mService.mPackageMonitor.onReceive(getTestContext(),
    +-                genPackageAddIntent(CALLING_PACKAGE_1, USER_0));
    +-
    +-        runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
    +-            mManager.addDynamicShortcuts(list(makeShortcutWithTitle("s1", "t1")));
    +-        });
    +-
    +-        checkManifestShortcuts_immutable_verify();
    +-
    +-        // Note that even though the first argument is not immutable and only the second one
    +-        // is immutable, the first argument should not be executed either.
    +-
    +-        runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
    +-            assertCannotUpdateImmutable(() -> {
    +-                mManager.setDynamicShortcuts(list(makeShortcut("xx"), makeShortcut("ms1")));
    +-            });
    +-            assertCannotUpdateImmutable(() -> {
    +-                mManager.setDynamicShortcuts(list(makeShortcut("xx"), makeShortcut("ms2")));
    +-            });
    +-        });
    +-        checkManifestShortcuts_immutable_verify();
    +-
    +-        runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
    +-            assertCannotUpdateImmutable(() -> {
    +-                mManager.addDynamicShortcuts(list(makeShortcut("xx"), makeShortcut("ms1")));
    +-            });
    +-            assertCannotUpdateImmutable(() -> {
    +-                mManager.addDynamicShortcuts(list(makeShortcut("xx"), makeShortcut("ms2")));
    +-            });
    +-        });
    +-        checkManifestShortcuts_immutable_verify();
    +-
    +-
    +-        runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
    +-            assertCannotUpdateImmutable(() -> {
    +-                mManager.updateShortcuts(list(makeShortcut("s1"), makeShortcut("ms1")));
    +-            });
    +-            assertCannotUpdateImmutable(() -> {
    +-                mManager.updateShortcuts(list(makeShortcut("s1"), makeShortcut("ms2")));
    +-            });
    +-        });
    +-        checkManifestShortcuts_immutable_verify();
    +-
    +-        runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
    +-            assertCannotUpdateImmutable(() -> {
    +-                mManager.removeDynamicShortcuts(list("s1", "ms1"));
    +-            });
    +-            assertCannotUpdateImmutable(() -> {
    +-                mManager.removeDynamicShortcuts(list("s2", "ms2"));
    +-            });
    +-        });
    +-        checkManifestShortcuts_immutable_verify();
    +-
    +-        runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
    +-            assertCannotUpdateImmutable(() -> {
    +-                mManager.disableShortcuts(list("s1", "ms1"));
    +-            });
    +-        });
    +-        checkManifestShortcuts_immutable_verify();
    +-
    +-        runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
    +-            assertCannotUpdateImmutable(() -> {
    +-                mManager.enableShortcuts(list("s1", "ms2"));
    +-            });
    +-        });
    +-        checkManifestShortcuts_immutable_verify();
    +-    }
    +-
    +-
    +-    /**
    +-     * Make sure the APIs won't work on manifest shortcuts.
    +-     */
    +-    public void testManifestShortcuts_tooMany() {
    +-        // Change the max number of shortcuts.
    +-        mService.updateConfigurationLocked(ConfigConstants.KEY_MAX_SHORTCUTS + "=3");
    +-
    +-        mService.handleUnlockUser(USER_0);
    +-
    +-        addManifestShortcutResource(
    +-                new ComponentName(CALLING_PACKAGE_1, ShortcutActivity.class.getName()),
    +-                R.xml.shortcut_5);
    +-        updatePackageVersion(CALLING_PACKAGE_1, 1);
    +-                mService.mPackageMonitor.onReceive(getTestContext(),
    +-                genPackageAddIntent(CALLING_PACKAGE_1, USER_0));
    +-
    +-        runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
    +-            // Only the first 3 should be published.
    +-            assertShortcutIds(mManager.getManifestShortcuts(), "ms1", "ms2", "ms3");
    +-        });
    +-    }
    +-
    +-    public void testMaxShortcutCount_set() {
    +-        // Change the max number of shortcuts.
    +-        mService.updateConfigurationLocked(ConfigConstants.KEY_MAX_SHORTCUTS + "=3");
    +-
    +-        runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
    +-            final ComponentName a1 = new ComponentName(mClientContext, ShortcutActivity.class);
    +-            final ComponentName a2 = new ComponentName(mClientContext, ShortcutActivity2.class);
    +-            final ShortcutInfo s1_1 = makeShortcutWithActivity("s11", a1);
    +-            final ShortcutInfo s1_2 = makeShortcutWithActivity("s12", a1);
    +-            final ShortcutInfo s1_3 = makeShortcutWithActivity("s13", a1);
    +-            final ShortcutInfo s1_4 = makeShortcutWithActivity("s14", a1);
    +-            final ShortcutInfo s1_5 = makeShortcutWithActivity("s15", a1);
    +-            final ShortcutInfo s1_6 = makeShortcutWithActivity("s16", a1);
    +-            final ShortcutInfo s2_1 = makeShortcutWithActivity("s21", a2);
    +-            final ShortcutInfo s2_2 = makeShortcutWithActivity("s22", a2);
    +-            final ShortcutInfo s2_3 = makeShortcutWithActivity("s23", a2);
    +-            final ShortcutInfo s2_4 = makeShortcutWithActivity("s24", a2);
    +-
    +-            // 3 shortcuts for 2 activities -> okay
    +-            mManager.setDynamicShortcuts(list(s1_1, s1_2, s1_3, s2_1, s2_2, s2_3));
    +-            assertShortcutIds(mManager.getDynamicShortcuts(),
    +-                    "s11", "s12", "s13", "s21", "s22", "s23");
    +-
    +-            mManager.removeAllDynamicShortcuts();
    +-
    +-            // 4 shortcut for activity 1 -> too many.
    +-            assertDynamicShortcutCountExceeded(() -> {
    +-                mManager.setDynamicShortcuts(list(s1_1, s1_2, s1_3, s1_4, s2_1, s2_2, s2_3));
    +-            });
    +-            assertEmpty(mManager.getDynamicShortcuts());
    +-
    +-            // 4 shortcut for activity 2 -> too many.
    +-            assertDynamicShortcutCountExceeded(() -> {
    +-                mManager.setDynamicShortcuts(list(s1_1, s1_2, s1_3, s2_1, s2_2, s2_3, s2_4));
    +-            });
    +-            assertEmpty(mManager.getDynamicShortcuts());
    +-
    +-            // First, set 3.  Then set 4, which should be ignored.
    +-            mManager.setDynamicShortcuts(list(s1_1, s1_2, s1_3));
    +-            assertShortcutIds(mManager.getDynamicShortcuts(),
    +-                    "s11", "s12", "s13");
    +-            assertDynamicShortcutCountExceeded(() -> {
    +-                mManager.setDynamicShortcuts(list(s2_1, s2_2, s2_3, s2_4));
    +-            });
    +-            assertShortcutIds(mManager.getDynamicShortcuts(),
    +-                    "s11", "s12", "s13");
    +-
    +-            // Set will remove the old dynamic set, unlike add, so the following should pass.
    +-            mManager.setDynamicShortcuts(list(s1_1, s1_2, s1_3));
    +-            assertShortcutIds(mManager.getDynamicShortcuts(),
    +-                    "s11", "s12", "s13");
    +-            mManager.setDynamicShortcuts(list(s1_4, s1_5, s1_6));
    +-            assertShortcutIds(mManager.getDynamicShortcuts(),
    +-                    "s14", "s15", "s16");
    +-
    +-            // Now, test with 2 manifest shortcuts.
    +-            mManager.removeAllDynamicShortcuts();
    +-            addManifestShortcutResource(
    +-                    new ComponentName(CALLING_PACKAGE_1, ShortcutActivity.class.getName()),
    +-                    R.xml.shortcut_2);
    +-            updatePackageVersion(CALLING_PACKAGE_1, 1);
    +-                    mService.mPackageMonitor.onReceive(getTestContext(),
    +-                    genPackageAddIntent(CALLING_PACKAGE_1, USER_0));
    +-            assertEquals(2, mManager.getManifestShortcuts().size());
    +-
    +-            // Setting 1 to activity 1 will work.
    +-            mManager.setDynamicShortcuts(list(s1_1, s2_1, s2_2, s2_3));
    +-            assertShortcutIds(mManager.getDynamicShortcuts(),
    +-                    "s11", "s21", "s22", "s23");
    +-            assertEquals(2, mManager.getManifestShortcuts().size());
    +-
    +-            // But setting 2 will not.
    +-            mManager.removeAllDynamicShortcuts();
    +-            assertDynamicShortcutCountExceeded(() -> {
    +-                mManager.setDynamicShortcuts(list(s1_1, s1_2, s2_1, s2_2, s2_3));
    +-            });
    +-            assertEmpty(mManager.getDynamicShortcuts());
    +-            assertEquals(2, mManager.getManifestShortcuts().size());
    +-        });
    +-    }
    +-
    +-    public void testMaxShortcutCount_add() {
    +-        // Change the max number of shortcuts.
    +-        mService.updateConfigurationLocked(ConfigConstants.KEY_MAX_SHORTCUTS + "=3");
    +-
    +-        runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
    +-            final ComponentName a1 = new ComponentName(mClientContext, ShortcutActivity.class);
    +-            final ComponentName a2 = new ComponentName(mClientContext, ShortcutActivity2.class);
    +-            final ShortcutInfo s1_1 = makeShortcutWithActivity("s11", a1);
    +-            final ShortcutInfo s1_2 = makeShortcutWithActivity("s12", a1);
    +-            final ShortcutInfo s1_3 = makeShortcutWithActivity("s13", a1);
    +-            final ShortcutInfo s1_4 = makeShortcutWithActivity("s14", a1);
    +-            final ShortcutInfo s2_1 = makeShortcutWithActivity("s21", a2);
    +-            final ShortcutInfo s2_2 = makeShortcutWithActivity("s22", a2);
    +-            final ShortcutInfo s2_3 = makeShortcutWithActivity("s23", a2);
    +-            final ShortcutInfo s2_4 = makeShortcutWithActivity("s24", a2);
    +-
    +-            // 3 shortcuts for 2 activities -> okay
    +-            mManager.addDynamicShortcuts(list(s1_1, s1_2, s1_3, s2_1, s2_2, s2_3));
    +-            assertShortcutIds(mManager.getDynamicShortcuts(),
    +-                    "s11", "s12", "s13", "s21", "s22", "s23");
    +-
    +-            mManager.removeAllDynamicShortcuts();
    +-
    +-            // 4 shortcut for activity 1 -> too many.
    +-            assertDynamicShortcutCountExceeded(() -> {
    +-                mManager.addDynamicShortcuts(list(s1_1, s1_2, s1_3, s1_4, s2_1, s2_2, s2_3));
    +-            });
    +-            assertEmpty(mManager.getDynamicShortcuts());
    +-
    +-            // 4 shortcut for activity 2 -> too many.
    +-            assertDynamicShortcutCountExceeded(() -> {
    +-                mManager.addDynamicShortcuts(list(s1_1, s1_2, s1_3, s2_1, s2_2, s2_3, s2_4));
    +-            });
    +-            assertEmpty(mManager.getDynamicShortcuts());
    +-
    +-            // First, set 3.  Then add 1 more, which should be ignored.
    +-            mManager.setDynamicShortcuts(list(s1_1, s1_2, s1_3));
    +-            assertShortcutIds(mManager.getDynamicShortcuts(),
    +-                    "s11", "s12", "s13");
    +-            assertDynamicShortcutCountExceeded(() -> {
    +-                mManager.addDynamicShortcuts(list(s1_4, s2_1));
    +-            });
    +-            assertShortcutIds(mManager.getDynamicShortcuts(),
    +-                    "s11", "s12", "s13");
    +-
    +-            // Update existing one, which should work.
    +-            mManager.addDynamicShortcuts(list(makeShortcutWithActivityAndTitle(
    +-                    "s11", a1, "xxx"), s2_1));
    +-            assertShortcutIds(mManager.getDynamicShortcuts(),
    +-                    "s11", "s12", "s13", "s21");
    +-            assertEquals("xxx", getCallerShortcut("s11").getTitle());
    +-
    +-            // Make sure pinned shortcuts won't affect.
    +-            // - Pin s11 - s13, and remove all dynamic.
    +-            runWithCaller(LAUNCHER_1, USER_0, () -> {
    +-                mLauncherApps.pinShortcuts(CALLING_PACKAGE_1, list("s11", "s12", "s13"),
    +-                        HANDLE_USER_0);
    +-            });
    +-            mManager.removeAllDynamicShortcuts();
    +-
    +-            assertEmpty(mManager.getDynamicShortcuts());
    +-            assertShortcutIds(mManager.getPinnedShortcuts(),
    +-                    "s11", "s12", "s13");
    +-
    +-            // Then add dynamic.
    +-            mManager.addDynamicShortcuts(list(s1_4, s2_1, s2_2, s2_3));
    +-
    +-            assertShortcutIds(mManager.getDynamicShortcuts(),
    +-                    "s14", "s21", "s22", "s23");
    +-            assertShortcutIds(mManager.getPinnedShortcuts(),
    +-                    "s11", "s12", "s13");
    +-
    +-            // Adding "s11" and "s12" back, should work
    +-            mManager.addDynamicShortcuts(list(s1_1, s1_2));
    +-
    +-            assertShortcutIds(mManager.getDynamicShortcuts(),
    +-                    "s14", "s11", "s12", "s21", "s22", "s23");
    +-            assertShortcutIds(mManager.getPinnedShortcuts(),
    +-                    "s11", "s12", "s13");
    +-
    +-            // Adding back s13 doesn't work.
    +-            assertDynamicShortcutCountExceeded(() -> {
    +-                mManager.addDynamicShortcuts(list(s1_3));
    +-            });
    +-
    +-            assertShortcutIds(filterByActivity(mManager.getDynamicShortcuts(), a1),
    +-                    "s11", "s12", "s14");
    +-            assertShortcutIds(filterByActivity(mManager.getDynamicShortcuts(), a2),
    +-                    "s21", "s22", "s23");
    +-
    +-            // Now swap the activities.
    +-            mManager.updateShortcuts(list(
    +-                    makeShortcutWithActivity("s11", a2),
    +-                    makeShortcutWithActivity("s21", a1)));
    +-
    +-            assertShortcutIds(filterByActivity(mManager.getDynamicShortcuts(), a1),
    +-                    "s21", "s12", "s14");
    +-            assertShortcutIds(filterByActivity(mManager.getDynamicShortcuts(), a2),
    +-                    "s11", "s22", "s23");
    +-
    +-            // Now, test with 2 manifest shortcuts.
    +-            mManager.removeAllDynamicShortcuts();
    +-            addManifestShortcutResource(
    +-                    new ComponentName(CALLING_PACKAGE_1, ShortcutActivity.class.getName()),
    +-                    R.xml.shortcut_2);
    +-            updatePackageVersion(CALLING_PACKAGE_1, 1);
    +-                    mService.mPackageMonitor.onReceive(getTestContext(),
    +-                    genPackageAddIntent(CALLING_PACKAGE_1, USER_0));
    +-
    +-            assertEquals(2, mManager.getManifestShortcuts().size());
    +-
    +-            // Adding one shortcut to activity 1 works fine.
    +-            mManager.addDynamicShortcuts(list(s1_1, s2_1, s2_2, s2_3));
    +-            assertShortcutIds(mManager.getDynamicShortcuts(),
    +-                    "s11", "s21", "s22", "s23");
    +-            assertEquals(2, mManager.getManifestShortcuts().size());
    +-
    +-            // But adding one more doesn't.
    +-            assertDynamicShortcutCountExceeded(() -> {
    +-                mManager.addDynamicShortcuts(list(s1_4, s2_1));
    +-            });
    +-            assertShortcutIds(mManager.getDynamicShortcuts(),
    +-                    "s11", "s21", "s22", "s23");
    +-            assertEquals(2, mManager.getManifestShortcuts().size());
    +-        });
    +-    }
    +-
    +-    public void testMaxShortcutCount_update() {
    +-        // Change the max number of shortcuts.
    +-        mService.updateConfigurationLocked(ConfigConstants.KEY_MAX_SHORTCUTS + "=3");
    +-
    +-        runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
    +-            final ComponentName a1 = new ComponentName(mClientContext, ShortcutActivity.class);
    +-            final ComponentName a2 = new ComponentName(mClientContext, ShortcutActivity2.class);
    +-            final ShortcutInfo s1_1 = makeShortcutWithActivity("s11", a1);
    +-            final ShortcutInfo s1_2 = makeShortcutWithActivity("s12", a1);
    +-            final ShortcutInfo s1_3 = makeShortcutWithActivity("s13", a1);
    +-            final ShortcutInfo s1_4 = makeShortcutWithActivity("s14", a1);
    +-            final ShortcutInfo s1_5 = makeShortcutWithActivity("s15", a1);
    +-            final ShortcutInfo s2_1 = makeShortcutWithActivity("s21", a2);
    +-            final ShortcutInfo s2_2 = makeShortcutWithActivity("s22", a2);
    +-            final ShortcutInfo s2_3 = makeShortcutWithActivity("s23", a2);
    +-            final ShortcutInfo s2_4 = makeShortcutWithActivity("s24", a2);
    +-
    +-            // 3 shortcuts for 2 activities -> okay
    +-            mManager.setDynamicShortcuts(list(s1_1, s1_2, s1_3, s2_1, s2_2, s2_3));
    +-            assertShortcutIds(mManager.getDynamicShortcuts(),
    +-                    "s11", "s12", "s13", "s21", "s22", "s23");
    +-
    +-            // Trying to move s11 from a1 to a2 should fail.
    +-            assertDynamicShortcutCountExceeded(() -> {
    +-                mManager.updateShortcuts(list(makeShortcutWithActivity("s11", a2)));
    +-            });
    +-            assertShortcutIds(mManager.getDynamicShortcuts(),
    +-                    "s11", "s12", "s13", "s21", "s22", "s23");
    +-
    +-            // Trying to move s21 from a2 to a1 should also fail.
    +-            assertDynamicShortcutCountExceeded(() -> {
    +-                mManager.updateShortcuts(list(makeShortcutWithActivity("s21", a1)));
    +-            });
    +-            assertShortcutIds(mManager.getDynamicShortcuts(),
    +-                    "s11", "s12", "s13", "s21", "s22", "s23");
    +-
    +-            // But, if we do these two at the same time, it should work.
    +-            mManager.updateShortcuts(list(
    +-                    makeShortcutWithActivity("s11", a2),
    +-                    makeShortcutWithActivity("s21", a1)));
    +-            assertShortcutIds(mManager.getDynamicShortcuts(),
    +-                    "s11", "s12", "s13", "s21", "s22", "s23");
    +-            assertShortcutIds(filterByActivity(mManager.getDynamicShortcuts(), a1),
    +-                    "s21", "s12", "s13");
    +-            assertShortcutIds(filterByActivity(mManager.getDynamicShortcuts(), a2),
    +-                    "s11", "s22", "s23");
    +-
    +-            // Then reset.
    +-            mManager.setDynamicShortcuts(list(s1_1, s1_2, s1_3, s2_1, s2_2, s2_3));
    +-            assertShortcutIds(mManager.getDynamicShortcuts(),
    +-                    "s11", "s12", "s13", "s21", "s22", "s23");
    +-
    +-            // Pin some to have more shortcuts for a1.
    +-            runWithCaller(LAUNCHER_1, USER_0, () -> {
    +-                mLauncherApps.pinShortcuts(CALLING_PACKAGE_1, list("s11", "s12", "s13"),
    +-                        HANDLE_USER_0);
    +-            });
    +-            mManager.setDynamicShortcuts(list(s1_4, s1_5, s2_1, s2_2, s2_3));
    +-            assertShortcutIds(mManager.getDynamicShortcuts(),
    +-                    "s14", "s15", "s21", "s22", "s23");
    +-            assertShortcutIds(mManager.getPinnedShortcuts(),
    +-                    "s11", "s12", "s13");
    +-
    +-            // a1 already has 2 dynamic shortcuts (and 3 pinned shortcuts that used to belong on it)
    +-            // But that doesn't matter for update -- the following should still work.
    +-            mManager.updateShortcuts(list(
    +-                    makeShortcutWithActivityAndTitle("s11", a1, "xxx1"),
    +-                    makeShortcutWithActivityAndTitle("s12", a1, "xxx2"),
    +-                    makeShortcutWithActivityAndTitle("s13", a1, "xxx3"),
    +-                    makeShortcutWithActivityAndTitle("s14", a1, "xxx4"),
    +-                    makeShortcutWithActivityAndTitle("s15", a1, "xxx5")));
    +-            // All the shortcuts should still exist they all belong on same activities,
    +-            // with the updated titles.
    +-            assertShortcutIds(mManager.getDynamicShortcuts(),
    +-                    "s14", "s15", "s21", "s22", "s23");
    +-            assertShortcutIds(mManager.getPinnedShortcuts(),
    +-                    "s11", "s12", "s13");
    +-
    +-            assertShortcutIds(filterByActivity(mManager.getDynamicShortcuts(), a1),
    +-                    "s14", "s15");
    +-            assertShortcutIds(filterByActivity(mManager.getDynamicShortcuts(), a2),
    +-                    "s21", "s22", "s23");
    +-
    +-            assertEquals("xxx1", getCallerShortcut("s11").getTitle());
    +-            assertEquals("xxx2", getCallerShortcut("s12").getTitle());
    +-            assertEquals("xxx3", getCallerShortcut("s13").getTitle());
    +-            assertEquals("xxx4", getCallerShortcut("s14").getTitle());
    +-            assertEquals("xxx5", getCallerShortcut("s15").getTitle());
    +-        });
    +-    }
    +-
    +-    public void testShortcutsPushedOutByManifest() {
    +-        // Change the max number of shortcuts.
    +-        mService.updateConfigurationLocked(ConfigConstants.KEY_MAX_SHORTCUTS + "=3");
    +-
    +-        runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
    +-            final ComponentName a1 = new ComponentName(mClientContext, ShortcutActivity.class);
    +-            final ComponentName a2 = new ComponentName(mClientContext, ShortcutActivity2.class);
    +-            final ShortcutInfo s1_1 = makeShortcutWithActivityAndRank("s11", a1, 4);
    +-            final ShortcutInfo s1_2 = makeShortcutWithActivityAndRank("s12", a1, 3);
    +-            final ShortcutInfo s1_3 = makeShortcutWithActivityAndRank("s13", a1, 2);
    +-            final ShortcutInfo s1_4 = makeShortcutWithActivityAndRank("s14", a1, 1);
    +-            final ShortcutInfo s1_5 = makeShortcutWithActivityAndRank("s15", a1, 0);
    +-            final ShortcutInfo s2_1 = makeShortcutWithActivityAndRank("s21", a2, 0);
    +-            final ShortcutInfo s2_2 = makeShortcutWithActivityAndRank("s22", a2, 1);
    +-            final ShortcutInfo s2_3 = makeShortcutWithActivityAndRank("s23", a2, 2);
    +-            final ShortcutInfo s2_4 = makeShortcutWithActivityAndRank("s24", a2, 3);
    +-            final ShortcutInfo s2_5 = makeShortcutWithActivityAndRank("s25", a2, 4);
    +-
    +-            // Initial state.
    +-            mManager.setDynamicShortcuts(list(s1_1, s1_2, s1_3, s2_1, s2_2, s2_3));
    +-            runWithCaller(LAUNCHER_1, USER_0, () -> {
    +-                mLauncherApps.pinShortcuts(CALLING_PACKAGE_1, list("s11", "s12", "s21", "s22"),
    +-                        HANDLE_USER_0);
    +-            });
    +-            mManager.setDynamicShortcuts(list(s1_2, s1_3, s1_4, s2_2, s2_3, s2_4));
    +-            assertShortcutIds(assertAllEnabled(mManager.getDynamicShortcuts()),
    +-                    "s12", "s13", "s14",
    +-                    "s22", "s23", "s24");
    +-            assertShortcutIds(assertAllEnabled(mManager.getPinnedShortcuts()),
    +-                    "s11", "s12",
    +-                    "s21", "s22");
    +-
    +-            // Add 1 manifest shortcut to a1.
    +-            addManifestShortcutResource(
    +-                    new ComponentName(CALLING_PACKAGE_1, ShortcutActivity.class.getName()),
    +-                    R.xml.shortcut_1);
    +-            updatePackageVersion(CALLING_PACKAGE_1, 1);
    +-                    mService.mPackageMonitor.onReceive(getTestContext(),
    +-                    genPackageAddIntent(CALLING_PACKAGE_1, USER_0));
    +-            assertEquals(1, mManager.getManifestShortcuts().size());
    +-
    +-            // s12 removed.
    +-            assertShortcutIds(assertAllEnabled(mManager.getDynamicShortcuts()),
    +-                    "s13", "s14",
    +-                    "s22", "s23", "s24");
    +-            assertShortcutIds(assertAllEnabled(mManager.getPinnedShortcuts()),
    +-                    "s11", "s12",
    +-                    "s21", "s22");
    +-
    +-            // Add more manifest shortcuts.
    +-            addManifestShortcutResource(
    +-                    new ComponentName(CALLING_PACKAGE_1, ShortcutActivity.class.getName()),
    +-                    R.xml.shortcut_2);
    +-            addManifestShortcutResource(
    +-                    new ComponentName(CALLING_PACKAGE_1, ShortcutActivity2.class.getName()),
    +-                    R.xml.shortcut_1_alt);
    +-            updatePackageVersion(CALLING_PACKAGE_1, 1);
    +-                    mService.mPackageMonitor.onReceive(getTestContext(),
    +-                    genPackageAddIntent(CALLING_PACKAGE_1, USER_0));
    +-            assertEquals(3, mManager.getManifestShortcuts().size());
    +-
    +-            // Note the ones with the highest rank values (== least important) will be removed.
    +-            assertShortcutIds(assertAllEnabled(mManager.getDynamicShortcuts()),
    +-                    "s14",
    +-                    "s22", "s23");
    +-            assertShortcutIds(assertAllEnabled(mManager.getPinnedShortcuts()),
    +-                    "s11", "s12",
    +-                    "s21", "s22");
    +-
    +-            // Add more manifest shortcuts.
    +-            addManifestShortcutResource(
    +-                    new ComponentName(CALLING_PACKAGE_1, ShortcutActivity.class.getName()),
    +-                    R.xml.shortcut_2);
    +-            addManifestShortcutResource(
    +-                    new ComponentName(CALLING_PACKAGE_1, ShortcutActivity2.class.getName()),
    +-                    R.xml.shortcut_5_alt); // manifest has 5, but max is 3, so a2 will have 3.
    +-            updatePackageVersion(CALLING_PACKAGE_1, 1);
    +-                    mService.mPackageMonitor.onReceive(getTestContext(),
    +-                    genPackageAddIntent(CALLING_PACKAGE_1, USER_0));
    +-            assertEquals(5, mManager.getManifestShortcuts().size());
    +-
    +-            assertShortcutIds(assertAllEnabled(mManager.getDynamicShortcuts()),
    +-                    "s14" // a1 has 1 dynamic
    +-            ); // a2 has no dynamic
    +-            assertShortcutIds(assertAllEnabled(mManager.getPinnedShortcuts()),
    +-                    "s11", "s12",
    +-                    "s21", "s22");
    +-
    +-            // Update, no manifest shortucts.  This doesn't affect anything.
    +-            addManifestShortcutResource(
    +-                    new ComponentName(CALLING_PACKAGE_1, ShortcutActivity.class.getName()),
    +-                    R.xml.shortcut_0);
    +-            addManifestShortcutResource(
    +-                    new ComponentName(CALLING_PACKAGE_1, ShortcutActivity2.class.getName()),
    +-                    R.xml.shortcut_0);
    +-            updatePackageVersion(CALLING_PACKAGE_1, 1);
    +-                    mService.mPackageMonitor.onReceive(getTestContext(),
    +-                    genPackageAddIntent(CALLING_PACKAGE_1, USER_0));
    +-            assertEquals(0, mManager.getManifestShortcuts().size());
    +-
    +-            assertShortcutIds(assertAllEnabled(mManager.getDynamicShortcuts()),
    +-                    "s14");
    +-            assertShortcutIds(assertAllEnabled(mManager.getPinnedShortcuts()),
    +-                    "s11", "s12",
    +-                    "s21", "s22");
    +-        });
    +-    }
    +-}
    +diff --git a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest2.java b/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest2.java
    +deleted file mode 100644
    +index d25923c..0000000
    +--- a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest2.java
    ++++ /dev/null
    +@@ -1,2040 +0,0 @@
    +-/*
    +- * Copyright (C) 2016 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 com.android.server.pm;
    +-
    +-import static com.android.server.pm.shortcutmanagertest.ShortcutManagerTestUtils.assertBundlesEqual;
    +-import static com.android.server.pm.shortcutmanagertest.ShortcutManagerTestUtils.assertExpectException;
    +-import static com.android.server.pm.shortcutmanagertest.ShortcutManagerTestUtils.assertWith;
    +-import static com.android.server.pm.shortcutmanagertest.ShortcutManagerTestUtils.list;
    +-import static com.android.server.pm.shortcutmanagertest.ShortcutManagerTestUtils.makeBundle;
    +-import static com.android.server.pm.shortcutmanagertest.ShortcutManagerTestUtils.parceled;
    +-import static com.android.server.pm.shortcutmanagertest.ShortcutManagerTestUtils.set;
    +-
    +-import static org.mockito.Matchers.anyInt;
    +-import static org.mockito.Matchers.anyString;
    +-import static org.mockito.Matchers.eq;
    +-import static org.mockito.Mockito.reset;
    +-import static org.mockito.Mockito.times;
    +-import static org.mockito.Mockito.verify;
    +-
    +-import android.Manifest.permission;
    +-import android.app.ActivityManager;
    +-import android.content.ComponentName;
    +-import android.content.Intent;
    +-import android.content.pm.ShortcutInfo;
    +-import android.content.res.Resources;
    +-import android.graphics.BitmapFactory;
    +-import android.graphics.drawable.Icon;
    +-import android.net.Uri;
    +-import android.os.PersistableBundle;
    +-import android.os.UserHandle;
    +-import android.test.MoreAsserts;
    +-import android.test.suitebuilder.annotation.SmallTest;
    +-
    +-import com.android.frameworks.servicestests.R;
    +-import com.android.server.pm.ShortcutService.ConfigConstants;
    +-
    +-import java.io.File;
    +-import java.io.FileWriter;
    +-import java.io.IOException;
    +-import java.io.PrintWriter;
    +-import java.io.StringWriter;
    +-import java.io.Writer;
    +-import java.util.Locale;
    +-
    +-/**
    +- * Tests for ShortcutService and ShortcutManager.
    +- *
    +- m FrameworksServicesTests &&
    +- adb install \
    +- -r -g ${ANDROID_PRODUCT_OUT}/data/app/FrameworksServicesTests/FrameworksServicesTests.apk &&
    +- adb shell am instrument -e class com.android.server.pm.ShortcutManagerTest2 \
    +- -w com.android.frameworks.servicestests/android.support.test.runner.AndroidJUnitRunner
    +- */
    +-@SmallTest
    +-public class ShortcutManagerTest2 extends BaseShortcutManagerTest {
    +-    // ShortcutInfo tests
    +-
    +-    public void testShortcutInfoMissingMandatoryFields() {
    +-        // Disable throttling.
    +-        mService.updateConfigurationLocked(
    +-                ShortcutService.ConfigConstants.KEY_MAX_UPDATES_PER_INTERVAL + "=99999999,"
    +-                + ShortcutService.ConfigConstants.KEY_MAX_SHORTCUTS + "=99999999"
    +-        );
    +-
    +-        assertExpectException(
    +-                IllegalArgumentException.class,
    +-                "ID must be provided",
    +-                () -> new ShortcutInfo.Builder(getTestContext()).build());
    +-
    +-        assertExpectException(
    +-                RuntimeException.class,
    +-                "id cannot be empty",
    +-                () -> new ShortcutInfo.Builder(getTestContext(), null));
    +-
    +-        assertExpectException(
    +-                RuntimeException.class,
    +-                "id cannot be empty",
    +-                () -> new ShortcutInfo.Builder(getTestContext(), ""));
    +-
    +-        assertExpectException(
    +-                RuntimeException.class,
    +-                "intents cannot contain null",
    +-                () -> new ShortcutInfo.Builder(getTestContext(), "id").setIntent(null));
    +-
    +-        assertExpectException(
    +-                RuntimeException.class,
    +-                "action must be set",
    +-                () -> new ShortcutInfo.Builder(getTestContext(), "id").setIntent(new Intent()));
    +-
    +-        assertExpectException(
    +-                RuntimeException.class,
    +-                "action must be set",
    +-                () -> new ShortcutInfo.Builder(getTestContext(), "id")
    +-                        .setIntents(new Intent[]{new Intent("action"), new Intent()}));
    +-
    +-        assertExpectException(
    +-                RuntimeException.class,
    +-                "activity cannot be null",
    +-                () -> new ShortcutInfo.Builder(getTestContext(), "id").setActivity(null));
    +-
    +-        assertExpectException(
    +-                RuntimeException.class,
    +-                "shortLabel cannot be empty",
    +-                () -> new ShortcutInfo.Builder(getTestContext(), "id").setShortLabel(null));
    +-
    +-        assertExpectException(
    +-                RuntimeException.class,
    +-                "shortLabel cannot be empty",
    +-                () -> new ShortcutInfo.Builder(getTestContext(), "id").setShortLabel(""));
    +-
    +-        assertExpectException(
    +-                RuntimeException.class,
    +-                "longLabel cannot be empty",
    +-                () -> new ShortcutInfo.Builder(getTestContext(), "id").setLongLabel(null));
    +-
    +-        assertExpectException(
    +-                RuntimeException.class,
    +-                "longLabel cannot be empty",
    +-                () -> new ShortcutInfo.Builder(getTestContext(), "id").setLongLabel(""));
    +-
    +-        assertExpectException(
    +-                RuntimeException.class,
    +-                "disabledMessage cannot be empty",
    +-                () -> new ShortcutInfo.Builder(getTestContext(), "id").setDisabledMessage(null));
    +-
    +-        assertExpectException(
    +-                RuntimeException.class,
    +-                "disabledMessage cannot be empty",
    +-                () -> new ShortcutInfo.Builder(getTestContext(), "id").setDisabledMessage(""));
    +-
    +-        assertExpectException(NullPointerException.class, "action must be set",
    +-                () -> new ShortcutInfo.Builder(getTestContext(), "id").setIntent(new Intent()));
    +-
    +-        assertExpectException(
    +-                IllegalArgumentException.class, "Short label must be provided", () -> {
    +-            ShortcutInfo si = new ShortcutInfo.Builder(getTestContext(), "id")
    +-                    .setActivity(new ComponentName(getTestContext().getPackageName(), "s"))
    +-                    .build();
    +-            assertTrue(getManager().setDynamicShortcuts(list(si)));
    +-        });
    +-
    +-        // same for add.
    +-        assertExpectException(
    +-                IllegalArgumentException.class, "Short label must be provided", () -> {
    +-            ShortcutInfo si = new ShortcutInfo.Builder(getTestContext(), "id")
    +-                    .setActivity(new ComponentName(getTestContext().getPackageName(), "s"))
    +-                    .build();
    +-            assertTrue(getManager().addDynamicShortcuts(list(si)));
    +-        });
    +-
    +-        assertExpectException(NullPointerException.class, "Intent must be provided", () -> {
    +-            ShortcutInfo si = new ShortcutInfo.Builder(getTestContext(), "id")
    +-                    .setActivity(new ComponentName(getTestContext().getPackageName(), "s"))
    +-                    .setShortLabel("x")
    +-                    .build();
    +-            assertTrue(getManager().setDynamicShortcuts(list(si)));
    +-        });
    +-
    +-        // same for add.
    +-        assertExpectException(NullPointerException.class, "Intent must be provided", () -> {
    +-            ShortcutInfo si = new ShortcutInfo.Builder(getTestContext(), "id")
    +-                    .setActivity(new ComponentName(getTestContext().getPackageName(), "s"))
    +-                    .setShortLabel("x")
    +-                    .build();
    +-            assertTrue(getManager().addDynamicShortcuts(list(si)));
    +-        });
    +-
    +-        assertExpectException(
    +-                IllegalStateException.class, "does not belong to package", () -> {
    +-            ShortcutInfo si = new ShortcutInfo.Builder(getTestContext(), "id")
    +-                    .setActivity(new ComponentName("xxx", "s"))
    +-                    .build();
    +-            assertTrue(getManager().setDynamicShortcuts(list(si)));
    +-        });
    +-
    +-        // same for add.
    +-        assertExpectException(
    +-                IllegalStateException.class, "does not belong to package", () -> {
    +-            ShortcutInfo si = new ShortcutInfo.Builder(getTestContext(), "id")
    +-                    .setActivity(new ComponentName("xxx", "s"))
    +-                    .build();
    +-            assertTrue(getManager().addDynamicShortcuts(list(si)));
    +-        });
    +-
    +-        // Now all activities are not main.
    +-        mMainActivityChecker = (component, userId) -> false;
    +-
    +-        assertExpectException(
    +-                IllegalStateException.class, "is not main", () -> {
    +-                    ShortcutInfo si = new ShortcutInfo.Builder(getTestContext(), "id")
    +-                            .setActivity(new ComponentName(getTestContext(), "s"))
    +-                            .build();
    +-                    assertTrue(getManager().setDynamicShortcuts(list(si)));
    +-                });
    +-        // For add
    +-        assertExpectException(
    +-                IllegalStateException.class, "is not main", () -> {
    +-                    ShortcutInfo si = new ShortcutInfo.Builder(getTestContext(), "id")
    +-                            .setActivity(new ComponentName(getTestContext(), "s"))
    +-                            .build();
    +-                    assertTrue(getManager().addDynamicShortcuts(list(si)));
    +-                });
    +-        // For update
    +-        assertExpectException(
    +-                IllegalStateException.class, "is not main", () -> {
    +-                    ShortcutInfo si = new ShortcutInfo.Builder(getTestContext(), "id")
    +-                            .setActivity(new ComponentName(getTestContext(), "s"))
    +-                            .build();
    +-                    assertTrue(getManager().updateShortcuts(list(si)));
    +-                });
    +-    }
    +-
    +-    public void testShortcutInfoParcel() {
    +-        setCaller(CALLING_PACKAGE_1, USER_10);
    +-        ShortcutInfo si = parceled(new ShortcutInfo.Builder(mClientContext)
    +-                .setId("id")
    +-                .setTitle("title")
    +-                .setIntent(makeIntent("action", ShortcutActivity.class))
    +-                .build());
    +-        assertEquals(mClientContext.getPackageName(), si.getPackage());
    +-        assertEquals(USER_10, si.getUserId());
    +-        assertEquals(HANDLE_USER_10, si.getUserHandle());
    +-        assertEquals("id", si.getId());
    +-        assertEquals("title", si.getTitle());
    +-        assertEquals("action", si.getIntent().getAction());
    +-
    +-        PersistableBundle pb = new PersistableBundle();
    +-        pb.putInt("k", 1);
    +-
    +-        si = new ShortcutInfo.Builder(getTestContext())
    +-                .setId("id")
    +-                .setActivity(new ComponentName("a", "b"))
    +-                .setIcon(Icon.createWithResource(mClientContext, 123))
    +-                .setTitle("title")
    +-                .setText("text")
    +-                .setDisabledMessage("dismes")
    +-                .setIntent(makeIntent("action", ShortcutActivity.class, "key", "val"))
    +-                .setCategories(set(ShortcutInfo.SHORTCUT_CATEGORY_CONVERSATION, "xyz"))
    +-                .setRank(123)
    +-                .setExtras(pb)
    +-                .build();
    +-        si.addFlags(ShortcutInfo.FLAG_PINNED);
    +-        si.setBitmapPath("abc");
    +-        si.setIconResourceId(456);
    +-
    +-        si = parceled(si);
    +-
    +-        assertEquals(getTestContext().getPackageName(), si.getPackage());
    +-        assertEquals("id", si.getId());
    +-        assertEquals(new ComponentName("a", "b"), si.getActivity());
    +-        assertEquals(123, si.getIcon().getResId());
    +-        assertEquals("title", si.getTitle());
    +-        assertEquals("text", si.getText());
    +-        assertEquals("dismes", si.getDisabledMessage());
    +-        assertEquals(set(ShortcutInfo.SHORTCUT_CATEGORY_CONVERSATION, "xyz"), si.getCategories());
    +-        assertEquals("action", si.getIntent().getAction());
    +-        assertEquals("val", si.getIntent().getStringExtra("key"));
    +-        assertEquals(123, si.getRank());
    +-        assertEquals(1, si.getExtras().getInt("k"));
    +-
    +-        assertEquals(ShortcutInfo.FLAG_PINNED, si.getFlags());
    +-        assertEquals("abc", si.getBitmapPath());
    +-        assertEquals(456, si.getIconResourceId());
    +-
    +-        assertEquals(0, si.getTitleResId());
    +-        assertEquals(null, si.getTitleResName());
    +-        assertEquals(0, si.getTextResId());
    +-        assertEquals(null, si.getTextResName());
    +-        assertEquals(0, si.getDisabledMessageResourceId());
    +-        assertEquals(null, si.getDisabledMessageResName());
    +-    }
    +-
    +-    public void testShortcutInfoParcel_resId() {
    +-        setCaller(CALLING_PACKAGE_1, USER_10);
    +-        ShortcutInfo si;
    +-
    +-        PersistableBundle pb = new PersistableBundle();
    +-        pb.putInt("k", 1);
    +-
    +-        si = new ShortcutInfo.Builder(getTestContext())
    +-                .setId("id")
    +-                .setActivity(new ComponentName("a", "b"))
    +-                .setIcon(Icon.createWithResource(mClientContext, 123))
    +-                .setTitleResId(10)
    +-                .setTextResId(11)
    +-                .setDisabledMessageResId(12)
    +-                .setIntent(makeIntent("action", ShortcutActivity.class, "key", "val"))
    +-                .setCategories(set(ShortcutInfo.SHORTCUT_CATEGORY_CONVERSATION, "xyz"))
    +-                .setRank(123)
    +-                .setExtras(pb)
    +-                .build();
    +-        si.addFlags(ShortcutInfo.FLAG_PINNED);
    +-        si.setBitmapPath("abc");
    +-        si.setIconResourceId(456);
    +-
    +-        lookupAndFillInResourceNames(si);
    +-
    +-        si = parceled(si);
    +-
    +-        assertEquals(getTestContext().getPackageName(), si.getPackage());
    +-        assertEquals("id", si.getId());
    +-        assertEquals(new ComponentName("a", "b"), si.getActivity());
    +-        assertEquals(123, si.getIcon().getResId());
    +-        assertEquals(10, si.getTitleResId());
    +-        assertEquals("r10", si.getTitleResName());
    +-        assertEquals(11, si.getTextResId());
    +-        assertEquals("r11", si.getTextResName());
    +-        assertEquals(12, si.getDisabledMessageResourceId());
    +-        assertEquals("r12", si.getDisabledMessageResName());
    +-        assertEquals(set(ShortcutInfo.SHORTCUT_CATEGORY_CONVERSATION, "xyz"), si.getCategories());
    +-        assertEquals("action", si.getIntent().getAction());
    +-        assertEquals("val", si.getIntent().getStringExtra("key"));
    +-        assertEquals(123, si.getRank());
    +-        assertEquals(1, si.getExtras().getInt("k"));
    +-
    +-        assertEquals(ShortcutInfo.FLAG_PINNED, si.getFlags());
    +-        assertEquals("abc", si.getBitmapPath());
    +-        assertEquals(456, si.getIconResourceId());
    +-        assertEquals("string/r456", si.getIconResName());
    +-    }
    +-
    +-    public void testShortcutInfoClone() {
    +-        setCaller(CALLING_PACKAGE_1, USER_11);
    +-
    +-        PersistableBundle pb = new PersistableBundle();
    +-        pb.putInt("k", 1);
    +-        ShortcutInfo sorig = new ShortcutInfo.Builder(mClientContext)
    +-                .setId("id")
    +-                .setActivity(new ComponentName("a", "b"))
    +-                .setIcon(Icon.createWithResource(mClientContext, 123))
    +-                .setTitle("title")
    +-                .setText("text")
    +-                .setDisabledMessage("dismes")
    +-                .setCategories(set(ShortcutInfo.SHORTCUT_CATEGORY_CONVERSATION, "xyz"))
    +-                .setIntent(makeIntent("action", ShortcutActivity.class, "key", "val"))
    +-                .setRank(123)
    +-                .setExtras(pb)
    +-                .build();
    +-        sorig.addFlags(ShortcutInfo.FLAG_PINNED);
    +-        sorig.setBitmapPath("abc");
    +-        sorig.setIconResourceId(456);
    +-
    +-        lookupAndFillInResourceNames(sorig);
    +-
    +-        ShortcutInfo si = sorig.clone(/* clone flags*/ 0);
    +-
    +-        assertEquals(USER_11, si.getUserId());
    +-        assertEquals(HANDLE_USER_11, si.getUserHandle());
    +-        assertEquals(mClientContext.getPackageName(), si.getPackage());
    +-        assertEquals("id", si.getId());
    +-        assertEquals(new ComponentName("a", "b"), si.getActivity());
    +-        assertEquals(123, si.getIcon().getResId());
    +-        assertEquals("title", si.getTitle());
    +-        assertEquals("text", si.getText());
    +-        assertEquals("dismes", si.getDisabledMessage());
    +-        assertEquals(set(ShortcutInfo.SHORTCUT_CATEGORY_CONVERSATION, "xyz"), si.getCategories());
    +-        assertEquals("action", si.getIntent().getAction());
    +-        assertEquals("val", si.getIntent().getStringExtra("key"));
    +-        assertEquals(123, si.getRank());
    +-        assertEquals(1, si.getExtras().getInt("k"));
    +-
    +-        assertEquals(ShortcutInfo.FLAG_PINNED, si.getFlags());
    +-        assertEquals("abc", si.getBitmapPath());
    +-        assertEquals(456, si.getIconResourceId());
    +-        assertEquals("string/r456", si.getIconResName());
    +-
    +-        si = sorig.clone(ShortcutInfo.CLONE_REMOVE_FOR_CREATOR);
    +-
    +-        assertEquals(mClientContext.getPackageName(), si.getPackage());
    +-        assertEquals("id", si.getId());
    +-        assertEquals(new ComponentName("a", "b"), si.getActivity());
    +-        assertEquals(null, si.getIcon());
    +-        assertEquals("title", si.getTitle());
    +-        assertEquals("text", si.getText());
    +-        assertEquals("dismes", si.getDisabledMessage());
    +-        assertEquals(set(ShortcutInfo.SHORTCUT_CATEGORY_CONVERSATION, "xyz"), si.getCategories());
    +-        assertEquals("action", si.getIntent().getAction());
    +-        assertEquals("val", si.getIntent().getStringExtra("key"));
    +-        assertEquals(123, si.getRank());
    +-        assertEquals(1, si.getExtras().getInt("k"));
    +-
    +-        assertEquals(ShortcutInfo.FLAG_PINNED, si.getFlags());
    +-        assertEquals(null, si.getBitmapPath());
    +-
    +-        assertEquals(456, si.getIconResourceId());
    +-        assertEquals(null, si.getIconResName());
    +-
    +-        si = sorig.clone(ShortcutInfo.CLONE_REMOVE_FOR_LAUNCHER);
    +-
    +-        assertEquals(mClientContext.getPackageName(), si.getPackage());
    +-        assertEquals("id", si.getId());
    +-        assertEquals(new ComponentName("a", "b"), si.getActivity());
    +-        assertEquals(null, si.getIcon());
    +-        assertEquals("title", si.getTitle());
    +-        assertEquals("text", si.getText());
    +-        assertEquals("dismes", si.getDisabledMessage());
    +-        assertEquals(set(ShortcutInfo.SHORTCUT_CATEGORY_CONVERSATION, "xyz"), si.getCategories());
    +-        assertEquals(null, si.getIntent());
    +-        assertEquals(123, si.getRank());
    +-        assertEquals(1, si.getExtras().getInt("k"));
    +-
    +-        assertEquals(ShortcutInfo.FLAG_PINNED, si.getFlags());
    +-        assertEquals(null, si.getBitmapPath());
    +-
    +-        assertEquals(456, si.getIconResourceId());
    +-        assertEquals(null, si.getIconResName());
    +-
    +-        si = sorig.clone(ShortcutInfo.CLONE_REMOVE_NON_KEY_INFO);
    +-
    +-        assertEquals(mClientContext.getPackageName(), si.getPackage());
    +-        assertEquals("id", si.getId());
    +-        assertEquals(new ComponentName("a", "b"), si.getActivity());
    +-        assertEquals(null, si.getIcon());
    +-        assertEquals(null, si.getTitle());
    +-        assertEquals(null, si.getText());
    +-        assertEquals(null, si.getDisabledMessage());
    +-        assertEquals(null, si.getCategories());
    +-        assertEquals(null, si.getIntent());
    +-        assertEquals(0, si.getRank());
    +-        assertEquals(null, si.getExtras());
    +-
    +-        assertEquals(ShortcutInfo.FLAG_PINNED | ShortcutInfo.FLAG_KEY_FIELDS_ONLY, si.getFlags());
    +-        assertEquals(null, si.getBitmapPath());
    +-
    +-        assertEquals(456, si.getIconResourceId());
    +-        assertEquals(null, si.getIconResName());
    +-    }
    +-
    +-    public void testShortcutInfoClone_resId() {
    +-        setCaller(CALLING_PACKAGE_1, USER_11);
    +-
    +-        PersistableBundle pb = new PersistableBundle();
    +-        pb.putInt("k", 1);
    +-        ShortcutInfo sorig = new ShortcutInfo.Builder(mClientContext)
    +-                .setId("id")
    +-                .setActivity(new ComponentName("a", "b"))
    +-                .setIcon(Icon.createWithResource(mClientContext, 123))
    +-                .setTitleResId(10)
    +-                .setTextResId(11)
    +-                .setDisabledMessageResId(12)
    +-                .setCategories(set(ShortcutInfo.SHORTCUT_CATEGORY_CONVERSATION, "xyz"))
    +-                .setIntent(makeIntent("action", ShortcutActivity.class, "key", "val"))
    +-                .setRank(123)
    +-                .setExtras(pb)
    +-                .build();
    +-        sorig.addFlags(ShortcutInfo.FLAG_PINNED);
    +-        sorig.setBitmapPath("abc");
    +-        sorig.setIconResourceId(456);
    +-
    +-        lookupAndFillInResourceNames(sorig);
    +-
    +-        ShortcutInfo si = sorig.clone(/* clone flags*/ 0);
    +-
    +-        assertEquals(USER_11, si.getUserId());
    +-        assertEquals(HANDLE_USER_11, si.getUserHandle());
    +-        assertEquals(mClientContext.getPackageName(), si.getPackage());
    +-        assertEquals("id", si.getId());
    +-        assertEquals(new ComponentName("a", "b"), si.getActivity());
    +-        assertEquals(123, si.getIcon().getResId());
    +-        assertEquals(10, si.getTitleResId());
    +-        assertEquals("r10", si.getTitleResName());
    +-        assertEquals(11, si.getTextResId());
    +-        assertEquals("r11", si.getTextResName());
    +-        assertEquals(12, si.getDisabledMessageResourceId());
    +-        assertEquals("r12", si.getDisabledMessageResName());
    +-        assertEquals(set(ShortcutInfo.SHORTCUT_CATEGORY_CONVERSATION, "xyz"), si.getCategories());
    +-        assertEquals("action", si.getIntent().getAction());
    +-        assertEquals("val", si.getIntent().getStringExtra("key"));
    +-        assertEquals(123, si.getRank());
    +-        assertEquals(1, si.getExtras().getInt("k"));
    +-
    +-        assertEquals(ShortcutInfo.FLAG_PINNED, si.getFlags());
    +-        assertEquals("abc", si.getBitmapPath());
    +-        assertEquals(456, si.getIconResourceId());
    +-        assertEquals("string/r456", si.getIconResName());
    +-
    +-        si = sorig.clone(ShortcutInfo.CLONE_REMOVE_FOR_CREATOR);
    +-
    +-        assertEquals(mClientContext.getPackageName(), si.getPackage());
    +-        assertEquals("id", si.getId());
    +-        assertEquals(new ComponentName("a", "b"), si.getActivity());
    +-        assertEquals(null, si.getIcon());
    +-        assertEquals(10, si.getTitleResId());
    +-        assertEquals(null, si.getTitleResName());
    +-        assertEquals(11, si.getTextResId());
    +-        assertEquals(null, si.getTextResName());
    +-        assertEquals(12, si.getDisabledMessageResourceId());
    +-        assertEquals(null, si.getDisabledMessageResName());
    +-        assertEquals(set(ShortcutInfo.SHORTCUT_CATEGORY_CONVERSATION, "xyz"), si.getCategories());
    +-        assertEquals("action", si.getIntent().getAction());
    +-        assertEquals("val", si.getIntent().getStringExtra("key"));
    +-        assertEquals(123, si.getRank());
    +-        assertEquals(1, si.getExtras().getInt("k"));
    +-
    +-        assertEquals(ShortcutInfo.FLAG_PINNED, si.getFlags());
    +-        assertEquals(null, si.getBitmapPath());
    +-
    +-        assertEquals(456, si.getIconResourceId());
    +-        assertEquals(null, si.getIconResName());
    +-
    +-        si = sorig.clone(ShortcutInfo.CLONE_REMOVE_FOR_LAUNCHER);
    +-
    +-        assertEquals(mClientContext.getPackageName(), si.getPackage());
    +-        assertEquals("id", si.getId());
    +-        assertEquals(new ComponentName("a", "b"), si.getActivity());
    +-        assertEquals(null, si.getIcon());
    +-        assertEquals(10, si.getTitleResId());
    +-        assertEquals(null, si.getTitleResName());
    +-        assertEquals(11, si.getTextResId());
    +-        assertEquals(null, si.getTextResName());
    +-        assertEquals(12, si.getDisabledMessageResourceId());
    +-        assertEquals(null, si.getDisabledMessageResName());
    +-        assertEquals(set(ShortcutInfo.SHORTCUT_CATEGORY_CONVERSATION, "xyz"), si.getCategories());
    +-        assertEquals(null, si.getIntent());
    +-        assertEquals(123, si.getRank());
    +-        assertEquals(1, si.getExtras().getInt("k"));
    +-
    +-        assertEquals(ShortcutInfo.FLAG_PINNED, si.getFlags());
    +-        assertEquals(null, si.getBitmapPath());
    +-
    +-        assertEquals(456, si.getIconResourceId());
    +-        assertEquals(null, si.getIconResName());
    +-
    +-        si = sorig.clone(ShortcutInfo.CLONE_REMOVE_NON_KEY_INFO);
    +-
    +-        assertEquals(mClientContext.getPackageName(), si.getPackage());
    +-        assertEquals("id", si.getId());
    +-        assertEquals(new ComponentName("a", "b"), si.getActivity());
    +-        assertEquals(null, si.getIcon());
    +-        assertEquals(0, si.getTitleResId());
    +-        assertEquals(null, si.getTitleResName());
    +-        assertEquals(0, si.getTextResId());
    +-        assertEquals(null, si.getTextResName());
    +-        assertEquals(0, si.getDisabledMessageResourceId());
    +-        assertEquals(null, si.getDisabledMessageResName());
    +-        assertEquals(null, si.getCategories());
    +-        assertEquals(null, si.getIntent());
    +-        assertEquals(0, si.getRank());
    +-        assertEquals(null, si.getExtras());
    +-
    +-        assertEquals(ShortcutInfo.FLAG_PINNED | ShortcutInfo.FLAG_KEY_FIELDS_ONLY, si.getFlags());
    +-        assertEquals(null, si.getBitmapPath());
    +-
    +-        assertEquals(456, si.getIconResourceId());
    +-        assertEquals(null, si.getIconResName());
    +-    }
    +-
    +-    public void testShortcutInfoClone_minimum() {
    +-        PersistableBundle pb = new PersistableBundle();
    +-        pb.putInt("k", 1);
    +-        ShortcutInfo sorig = new ShortcutInfo.Builder(getTestContext())
    +-                .setId("id")
    +-                .setTitle("title")
    +-                .setIntent(makeIntent("action", ShortcutActivity.class))
    +-                .build();
    +-        ShortcutInfo si = sorig.clone(/* clone flags*/ 0);
    +-
    +-        assertEquals(getTestContext().getPackageName(), si.getPackage());
    +-        assertEquals("id", si.getId());
    +-        assertEquals("title", si.getTitle());
    +-        assertEquals("action", si.getIntent().getAction());
    +-        assertEquals(null, si.getCategories());
    +-
    +-        si = sorig.clone(ShortcutInfo.CLONE_REMOVE_FOR_CREATOR);
    +-
    +-        assertEquals(getTestContext().getPackageName(), si.getPackage());
    +-        assertEquals("id", si.getId());
    +-        assertEquals("title", si.getTitle());
    +-        assertEquals("action", si.getIntent().getAction());
    +-        assertEquals(null, si.getCategories());
    +-
    +-        si = sorig.clone(ShortcutInfo.CLONE_REMOVE_FOR_LAUNCHER);
    +-
    +-        assertEquals(getTestContext().getPackageName(), si.getPackage());
    +-        assertEquals("id", si.getId());
    +-        assertEquals("title", si.getTitle());
    +-        assertEquals(null, si.getIntent());
    +-        assertEquals(null, si.getCategories());
    +-
    +-        si = sorig.clone(ShortcutInfo.CLONE_REMOVE_NON_KEY_INFO);
    +-
    +-        assertEquals(getTestContext().getPackageName(), si.getPackage());
    +-        assertEquals("id", si.getId());
    +-        assertEquals(null, si.getTitle());
    +-        assertEquals(null, si.getIntent());
    +-        assertEquals(null, si.getCategories());
    +-    }
    +-
    +-    public void testShortcutInfoCopyNonNullFieldsFrom() throws InterruptedException {
    +-        PersistableBundle pb = new PersistableBundle();
    +-        pb.putInt("k", 1);
    +-        ShortcutInfo sorig = new ShortcutInfo.Builder(getTestContext())
    +-                .setId("id")
    +-                .setActivity(new ComponentName("a", "b"))
    +-                .setIcon(Icon.createWithResource(mClientContext, 123))
    +-                .setTitle("title")
    +-                .setText("text")
    +-                .setDisabledMessage("dismes")
    +-                .setCategories(set(ShortcutInfo.SHORTCUT_CATEGORY_CONVERSATION, "xyz"))
    +-                .setIntent(makeIntent("action", ShortcutActivity.class, "key", "val"))
    +-                .setRank(123)
    +-                .setExtras(pb)
    +-                .build();
    +-        sorig.addFlags(ShortcutInfo.FLAG_PINNED);
    +-        sorig.setBitmapPath("abc");
    +-        sorig.setIconResourceId(456);
    +-
    +-        lookupAndFillInResourceNames(sorig);
    +-
    +-        ShortcutInfo si;
    +-
    +-        si = sorig.clone(/* flags=*/ 0);
    +-        si.copyNonNullFieldsFrom(new ShortcutInfo.Builder(getTestContext()).setId("id")
    +-                .setActivity(new ComponentName("x", "y")).build());
    +-        assertEquals("text", si.getText());
    +-        assertEquals(123, si.getRank());
    +-        assertEquals(new ComponentName("x", "y"), si.getActivity());
    +-
    +-        si = sorig.clone(/* flags=*/ 0);
    +-        si.copyNonNullFieldsFrom(new ShortcutInfo.Builder(getTestContext()).setId("id")
    +-                .setIcon(Icon.createWithResource(mClientContext, 456)).build());
    +-        assertEquals("text", si.getText());
    +-        assertEquals(456, si.getIcon().getResId());
    +-        assertEquals(0, si.getIconResourceId());
    +-        assertEquals(null, si.getIconResName());
    +-        assertEquals(null, si.getBitmapPath());
    +-
    +-        si = sorig.clone(/* flags=*/ 0);
    +-        si.copyNonNullFieldsFrom(new ShortcutInfo.Builder(getTestContext()).setId("id")
    +-                .setTitle("xyz").build());
    +-        assertEquals("text", si.getText());
    +-        assertEquals("xyz", si.getTitle());
    +-        assertEquals(0, si.getTitleResId());
    +-
    +-        si = sorig.clone(/* flags=*/ 0);
    +-        si.copyNonNullFieldsFrom(new ShortcutInfo.Builder(getTestContext()).setId("id")
    +-                .setTitleResId(123).build());
    +-        assertEquals("text", si.getText());
    +-        assertEquals(null, si.getTitle());
    +-        assertEquals(123, si.getTitleResId());
    +-
    +-        si = sorig.clone(/* flags=*/ 0);
    +-        si.copyNonNullFieldsFrom(new ShortcutInfo.Builder(getTestContext()).setId("id")
    +-                .setText("xxx").build());
    +-        assertEquals(123, si.getRank());
    +-        assertEquals("xxx", si.getText());
    +-        assertEquals(0, si.getTextResId());
    +-
    +-        si = sorig.clone(/* flags=*/ 0);
    +-        si.copyNonNullFieldsFrom(new ShortcutInfo.Builder(getTestContext()).setId("id")
    +-                .setTextResId(1111).build());
    +-        assertEquals(123, si.getRank());
    +-        assertEquals(null, si.getText());
    +-        assertEquals(1111, si.getTextResId());
    +-
    +-        si = sorig.clone(/* flags=*/ 0);
    +-        si.copyNonNullFieldsFrom(new ShortcutInfo.Builder(getTestContext()).setId("id")
    +-                .setDisabledMessage("xxx").build());
    +-        assertEquals(123, si.getRank());
    +-        assertEquals("xxx", si.getDisabledMessage());
    +-        assertEquals(0, si.getDisabledMessageResourceId());
    +-
    +-        si = sorig.clone(/* flags=*/ 0);
    +-        si.copyNonNullFieldsFrom(new ShortcutInfo.Builder(getTestContext()).setId("id")
    +-                .setDisabledMessageResId(11111).build());
    +-        assertEquals(123, si.getRank());
    +-        assertEquals(null, si.getDisabledMessage());
    +-        assertEquals(11111, si.getDisabledMessageResourceId());
    +-
    +-        si = sorig.clone(/* flags=*/ 0);
    +-        si.copyNonNullFieldsFrom(new ShortcutInfo.Builder(getTestContext()).setId("id")
    +-                .setCategories(set()).build());
    +-        assertEquals("text", si.getText());
    +-        assertEquals(set(), si.getCategories());
    +-
    +-        si = sorig.clone(/* flags=*/ 0);
    +-        si.copyNonNullFieldsFrom(new ShortcutInfo.Builder(getTestContext()).setId("id")
    +-                .setCategories(set("x")).build());
    +-        assertEquals("text", si.getText());
    +-        assertEquals(set("x"), si.getCategories());
    +-
    +-        si = sorig.clone(/* flags=*/ 0);
    +-        si.copyNonNullFieldsFrom(new ShortcutInfo.Builder(getTestContext()).setId("id")
    +-                .setIntent(makeIntent("action2", ShortcutActivity.class)).build());
    +-        assertEquals("text", si.getText());
    +-        assertEquals("action2", si.getIntent().getAction());
    +-        assertEquals(null, si.getIntent().getStringExtra("key"));
    +-
    +-        si = sorig.clone(/* flags=*/ 0);
    +-        si.copyNonNullFieldsFrom(new ShortcutInfo.Builder(getTestContext()).setId("id")
    +-                .setIntent(makeIntent("action3", ShortcutActivity.class, "key", "x")).build());
    +-        assertEquals("text", si.getText());
    +-        assertEquals("action3", si.getIntent().getAction());
    +-        assertEquals("x", si.getIntent().getStringExtra("key"));
    +-
    +-        si = sorig.clone(/* flags=*/ 0);
    +-        si.copyNonNullFieldsFrom(new ShortcutInfo.Builder(getTestContext()).setId("id")
    +-                .setRank(999).build());
    +-        assertEquals("text", si.getText());
    +-        assertEquals(999, si.getRank());
    +-
    +-
    +-        PersistableBundle pb2 = new PersistableBundle();
    +-        pb2.putInt("x", 99);
    +-
    +-        si = sorig.clone(/* flags=*/ 0);
    +-        si.copyNonNullFieldsFrom(new ShortcutInfo.Builder(getTestContext()).setId("id")
    +-                .setExtras(pb2).build());
    +-        assertEquals("text", si.getText());
    +-        assertEquals(99, si.getExtras().getInt("x"));
    +-    }
    +-
    +-    public void testShortcutInfoCopyNonNullFieldsFrom_resId() throws InterruptedException {
    +-        PersistableBundle pb = new PersistableBundle();
    +-        pb.putInt("k", 1);
    +-        ShortcutInfo sorig = new ShortcutInfo.Builder(getTestContext())
    +-                .setId("id")
    +-                .setActivity(new ComponentName("a", "b"))
    +-                .setIcon(Icon.createWithResource(mClientContext, 123))
    +-                .setTitleResId(10)
    +-                .setTextResId(11)
    +-                .setDisabledMessageResId(12)
    +-                .setCategories(set(ShortcutInfo.SHORTCUT_CATEGORY_CONVERSATION, "xyz"))
    +-                .setIntent(makeIntent("action", ShortcutActivity.class, "key", "val"))
    +-                .setRank(123)
    +-                .setExtras(pb)
    +-                .build();
    +-        sorig.addFlags(ShortcutInfo.FLAG_PINNED);
    +-        sorig.setBitmapPath("abc");
    +-        sorig.setIconResourceId(456);
    +-
    +-        ShortcutInfo si;
    +-
    +-        si = sorig.clone(/* flags=*/ 0);
    +-        si.copyNonNullFieldsFrom(new ShortcutInfo.Builder(getTestContext()).setId("id")
    +-                .setActivity(new ComponentName("x", "y")).build());
    +-        assertEquals(11, si.getTextResId());
    +-        assertEquals(new ComponentName("x", "y"), si.getActivity());
    +-
    +-        si = sorig.clone(/* flags=*/ 0);
    +-        si.copyNonNullFieldsFrom(new ShortcutInfo.Builder(getTestContext()).setId("id")
    +-                .setIcon(Icon.createWithResource(mClientContext, 456)).build());
    +-        assertEquals(11, si.getTextResId());
    +-        assertEquals(456, si.getIcon().getResId());
    +-        assertEquals(0, si.getIconResourceId());
    +-        assertEquals(null, si.getIconResName());
    +-        assertEquals(null, si.getBitmapPath());
    +-
    +-        si = sorig.clone(/* flags=*/ 0);
    +-        si.copyNonNullFieldsFrom(new ShortcutInfo.Builder(getTestContext()).setId("id")
    +-                .setTitle("xyz").build());
    +-        assertEquals(11, si.getTextResId());
    +-        assertEquals("xyz", si.getTitle());
    +-        assertEquals(0, si.getTitleResId());
    +-        assertEquals(null, si.getTitleResName());
    +-
    +-        si = sorig.clone(/* flags=*/ 0);
    +-        si.copyNonNullFieldsFrom(new ShortcutInfo.Builder(getTestContext()).setId("id")
    +-                .setTitleResId(123).build());
    +-        assertEquals(11, si.getTextResId());
    +-        assertEquals(null, si.getTitle());
    +-        assertEquals(123, si.getTitleResId());
    +-        assertEquals(null, si.getTitleResName());
    +-
    +-        si = sorig.clone(/* flags=*/ 0);
    +-        si.copyNonNullFieldsFrom(new ShortcutInfo.Builder(getTestContext()).setId("id")
    +-                .setText("xxx").build());
    +-        assertEquals(123, si.getRank());
    +-        assertEquals("xxx", si.getText());
    +-        assertEquals(0, si.getTextResId());
    +-        assertEquals(null, si.getTextResName());
    +-
    +-        si = sorig.clone(/* flags=*/ 0);
    +-        si.copyNonNullFieldsFrom(new ShortcutInfo.Builder(getTestContext()).setId("id")
    +-                .setTextResId(1111).build());
    +-        assertEquals(123, si.getRank());
    +-        assertEquals(null, si.getText());
    +-        assertEquals(1111, si.getTextResId());
    +-        assertEquals(null, si.getTextResName());
    +-
    +-        si = sorig.clone(/* flags=*/ 0);
    +-        si.copyNonNullFieldsFrom(new ShortcutInfo.Builder(getTestContext()).setId("id")
    +-                .setDisabledMessage("xxx").build());
    +-        assertEquals(123, si.getRank());
    +-        assertEquals("xxx", si.getDisabledMessage());
    +-        assertEquals(0, si.getDisabledMessageResourceId());
    +-        assertEquals(null, si.getDisabledMessageResName());
    +-
    +-        si = sorig.clone(/* flags=*/ 0);
    +-        si.copyNonNullFieldsFrom(new ShortcutInfo.Builder(getTestContext()).setId("id")
    +-                .setDisabledMessageResId(11111).build());
    +-        assertEquals(123, si.getRank());
    +-        assertEquals(null, si.getDisabledMessage());
    +-        assertEquals(11111, si.getDisabledMessageResourceId());
    +-        assertEquals(null, si.getDisabledMessageResName());
    +-
    +-        si = sorig.clone(/* flags=*/ 0);
    +-        si.copyNonNullFieldsFrom(new ShortcutInfo.Builder(getTestContext()).setId("id")
    +-                .setCategories(set()).build());
    +-        assertEquals(11, si.getTextResId());
    +-        assertEquals(set(), si.getCategories());
    +-
    +-        si = sorig.clone(/* flags=*/ 0);
    +-        si.copyNonNullFieldsFrom(new ShortcutInfo.Builder(getTestContext()).setId("id")
    +-                .setCategories(set("x")).build());
    +-        assertEquals(11, si.getTextResId());
    +-        assertEquals(set("x"), si.getCategories());
    +-
    +-        si = sorig.clone(/* flags=*/ 0);
    +-        si.copyNonNullFieldsFrom(new ShortcutInfo.Builder(getTestContext()).setId("id")
    +-                .setIntent(makeIntent("action2", ShortcutActivity.class)).build());
    +-        assertEquals(11, si.getTextResId());
    +-        assertEquals("action2", si.getIntent().getAction());
    +-        assertEquals(null, si.getIntent().getStringExtra("key"));
    +-
    +-        si = sorig.clone(/* flags=*/ 0);
    +-        si.copyNonNullFieldsFrom(new ShortcutInfo.Builder(getTestContext()).setId("id")
    +-                .setIntent(makeIntent("action3", ShortcutActivity.class, "key", "x")).build());
    +-        assertEquals(11, si.getTextResId());
    +-        assertEquals("action3", si.getIntent().getAction());
    +-        assertEquals("x", si.getIntent().getStringExtra("key"));
    +-
    +-        si = sorig.clone(/* flags=*/ 0);
    +-        si.copyNonNullFieldsFrom(new ShortcutInfo.Builder(getTestContext()).setId("id")
    +-                .setRank(999).build());
    +-        assertEquals(11, si.getTextResId());
    +-        assertEquals(999, si.getRank());
    +-
    +-
    +-        PersistableBundle pb2 = new PersistableBundle();
    +-        pb2.putInt("x", 99);
    +-
    +-        si = sorig.clone(/* flags=*/ 0);
    +-        si.copyNonNullFieldsFrom(new ShortcutInfo.Builder(getTestContext()).setId("id")
    +-                .setExtras(pb2).build());
    +-        assertEquals(11, si.getTextResId());
    +-        assertEquals(99, si.getExtras().getInt("x"));
    +-    }
    +-
    +-    public void testShortcutInfoSaveAndLoad() throws InterruptedException {
    +-        mRunningUsers.put(USER_10, true);
    +-
    +-        setCaller(CALLING_PACKAGE_1, USER_10);
    +-
    +-        final Icon bmp32x32 = Icon.createWithBitmap(BitmapFactory.decodeResource(
    +-                getTestContext().getResources(), R.drawable.black_32x32));
    +-
    +-        PersistableBundle pb = new PersistableBundle();
    +-        pb.putInt("k", 1);
    +-        ShortcutInfo sorig = new ShortcutInfo.Builder(mClientContext)
    +-                .setId("id")
    +-                .setActivity(new ComponentName(mClientContext, ShortcutActivity2.class))
    +-                .setIcon(bmp32x32)
    +-                .setTitle("title")
    +-                .setText("text")
    +-                .setDisabledMessage("dismes")
    +-                .setCategories(set(ShortcutInfo.SHORTCUT_CATEGORY_CONVERSATION, "xyz"))
    +-                .setIntent(makeIntent("action", ShortcutActivity.class, "key", "val"))
    +-                .setRank(123)
    +-                .setExtras(pb)
    +-                .build();
    +-        sorig.setTimestamp(mInjectedCurrentTimeMillis);
    +-
    +-        ShortcutInfo sorig2 = new ShortcutInfo.Builder(mClientContext)
    +-                .setId("id2")
    +-                .setTitle("x")
    +-                .setActivity(new ComponentName(mClientContext, ShortcutActivity2.class))
    +-                .setIntent(makeIntent("action", ShortcutActivity.class, "key", "val"))
    +-                .setRank(456)
    +-                .build();
    +-        sorig2.setTimestamp(mInjectedCurrentTimeMillis);
    +-
    +-        mManager.addDynamicShortcuts(list(sorig, sorig2));
    +-
    +-        mInjectedCurrentTimeMillis += 1;
    +-        final long now = mInjectedCurrentTimeMillis;
    +-        mInjectedCurrentTimeMillis += 1;
    +-
    +-        dumpsysOnLogcat("before save");
    +-
    +-        // Save and load.
    +-        mService.saveDirtyInfo();
    +-        initService();
    +-        mService.handleUnlockUser(USER_10);
    +-
    +-        dumpUserFile(USER_10);
    +-        dumpsysOnLogcat("after load");
    +-
    +-        ShortcutInfo si;
    +-        si = mService.getPackageShortcutForTest(CALLING_PACKAGE_1, "id", USER_10);
    +-
    +-        assertEquals(USER_10, si.getUserId());
    +-        assertEquals(HANDLE_USER_10, si.getUserHandle());
    +-        assertEquals(CALLING_PACKAGE_1, si.getPackage());
    +-        assertEquals("id", si.getId());
    +-        assertEquals(ShortcutActivity2.class.getName(), si.getActivity().getClassName());
    +-        assertEquals(null, si.getIcon());
    +-        assertEquals("title", si.getTitle());
    +-        assertEquals("text", si.getText());
    +-        assertEquals("dismes", si.getDisabledMessage());
    +-        assertEquals(set(ShortcutInfo.SHORTCUT_CATEGORY_CONVERSATION, "xyz"), si.getCategories());
    +-        assertEquals("action", si.getIntent().getAction());
    +-        assertEquals("val", si.getIntent().getStringExtra("key"));
    +-        assertEquals(0, si.getRank());
    +-        assertEquals(1, si.getExtras().getInt("k"));
    +-
    +-        assertEquals(ShortcutInfo.FLAG_DYNAMIC | ShortcutInfo.FLAG_HAS_ICON_FILE
    +-                | ShortcutInfo.FLAG_STRINGS_RESOLVED, si.getFlags());
    +-        assertNotNull(si.getBitmapPath()); // Something should be set.
    +-        assertEquals(0, si.getIconResourceId());
    +-        assertTrue(si.getLastChangedTimestamp() < now);
    +-
    +-        // Make sure ranks are saved too.  Because of the auto-adjusting, we need two shortcuts
    +-        // to test it.
    +-        si = mService.getPackageShortcutForTest(CALLING_PACKAGE_1, "id2", USER_10);
    +-        assertEquals(1, si.getRank());
    +-
    +-        dumpUserFile(USER_10);
    +-    }
    +-
    +-    public void testShortcutInfoSaveAndLoad_resId() throws InterruptedException {
    +-        mRunningUsers.put(USER_10, true);
    +-
    +-        setCaller(CALLING_PACKAGE_1, USER_10);
    +-
    +-        final Icon res32x32 = Icon.createWithResource(mClientContext, R.drawable.black_32x32);
    +-
    +-        PersistableBundle pb = new PersistableBundle();
    +-        pb.putInt("k", 1);
    +-        ShortcutInfo sorig = new ShortcutInfo.Builder(mClientContext)
    +-                .setId("id")
    +-                .setActivity(new ComponentName(mClientContext, ShortcutActivity2.class))
    +-                .setIcon(res32x32)
    +-                .setTitleResId(10)
    +-                .setTextResId(11)
    +-                .setDisabledMessageResId(12)
    +-                .setCategories(set(ShortcutInfo.SHORTCUT_CATEGORY_CONVERSATION, "xyz"))
    +-                .setIntent(makeIntent("action", ShortcutActivity.class, "key", "val"))
    +-                .setRank(123)
    +-                .setExtras(pb)
    +-                .build();
    +-        sorig.setTimestamp(mInjectedCurrentTimeMillis);
    +-
    +-        ShortcutInfo sorig2 = new ShortcutInfo.Builder(mClientContext)
    +-                .setId("id2")
    +-                .setTitle("x")
    +-                .setActivity(new ComponentName(mClientContext, ShortcutActivity2.class))
    +-                .setIntent(makeIntent("action", ShortcutActivity.class, "key", "val"))
    +-                .setRank(456)
    +-                .build();
    +-        sorig2.setTimestamp(mInjectedCurrentTimeMillis);
    +-
    +-        mManager.addDynamicShortcuts(list(sorig, sorig2));
    +-
    +-        mInjectedCurrentTimeMillis += 1;
    +-        final long now = mInjectedCurrentTimeMillis;
    +-        mInjectedCurrentTimeMillis += 1;
    +-
    +-        // Save and load.
    +-        mService.saveDirtyInfo();
    +-        initService();
    +-        mService.handleUnlockUser(USER_10);
    +-
    +-        ShortcutInfo si;
    +-        si = mService.getPackageShortcutForTest(CALLING_PACKAGE_1, "id", USER_10);
    +-
    +-        assertEquals(USER_10, si.getUserId());
    +-        assertEquals(HANDLE_USER_10, si.getUserHandle());
    +-        assertEquals(CALLING_PACKAGE_1, si.getPackage());
    +-        assertEquals("id", si.getId());
    +-        assertEquals(ShortcutActivity2.class.getName(), si.getActivity().getClassName());
    +-        assertEquals(null, si.getIcon());
    +-        assertEquals(10, si.getTitleResId());
    +-        assertEquals("r10", si.getTitleResName());
    +-        assertEquals(11, si.getTextResId());
    +-        assertEquals("r11", si.getTextResName());
    +-        assertEquals(12, si.getDisabledMessageResourceId());
    +-        assertEquals("r12", si.getDisabledMessageResName());
    +-        assertEquals(set(ShortcutInfo.SHORTCUT_CATEGORY_CONVERSATION, "xyz"), si.getCategories());
    +-        assertEquals("action", si.getIntent().getAction());
    +-        assertEquals("val", si.getIntent().getStringExtra("key"));
    +-        assertEquals(0, si.getRank());
    +-        assertEquals(1, si.getExtras().getInt("k"));
    +-
    +-        assertEquals(ShortcutInfo.FLAG_DYNAMIC | ShortcutInfo.FLAG_HAS_ICON_RES
    +-                | ShortcutInfo.FLAG_STRINGS_RESOLVED, si.getFlags());
    +-        assertNull(si.getBitmapPath());
    +-        assertEquals(R.drawable.black_32x32, si.getIconResourceId());
    +-        assertTrue(si.getLastChangedTimestamp() < now);
    +-
    +-        // Make sure ranks are saved too.  Because of the auto-adjusting, we need two shortcuts
    +-        // to test it.
    +-        si = mService.getPackageShortcutForTest(CALLING_PACKAGE_1, "id2", USER_10);
    +-        assertEquals(1, si.getRank());
    +-    }
    +-
    +-    public void testShortcutInfoSaveAndLoad_forBackup() {
    +-        setCaller(CALLING_PACKAGE_1, USER_0);
    +-
    +-        final Icon bmp32x32 = Icon.createWithBitmap(BitmapFactory.decodeResource(
    +-                getTestContext().getResources(), R.drawable.black_32x32));
    +-
    +-        PersistableBundle pb = new PersistableBundle();
    +-        pb.putInt("k", 1);
    +-        ShortcutInfo sorig = new ShortcutInfo.Builder(mClientContext)
    +-                .setId("id")
    +-                .setActivity(new ComponentName(mClientContext, ShortcutActivity2.class))
    +-                .setIcon(bmp32x32)
    +-                .setTitle("title")
    +-                .setText("text")
    +-                .setDisabledMessage("dismes")
    +-                .setCategories(set(ShortcutInfo.SHORTCUT_CATEGORY_CONVERSATION, "xyz"))
    +-                .setIntent(makeIntent("action", ShortcutActivity.class, "key", "val"))
    +-                .setRank(123)
    +-                .setExtras(pb)
    +-                .build();
    +-
    +-        ShortcutInfo sorig2 = new ShortcutInfo.Builder(mClientContext)
    +-                .setId("id2")
    +-                .setTitle("x")
    +-                .setActivity(new ComponentName(mClientContext, ShortcutActivity2.class))
    +-                .setIntent(makeIntent("action", ShortcutActivity.class, "key", "val"))
    +-                .setRank(456)
    +-                .build();
    +-
    +-        mManager.addDynamicShortcuts(list(sorig, sorig2));
    +-
    +-        // Dynamic shortcuts won't be backed up, so we need to pin it.
    +-        setCaller(LAUNCHER_1, USER_0);
    +-        mLauncherApps.pinShortcuts(CALLING_PACKAGE_1, list("id", "id2"), HANDLE_USER_0);
    +-
    +-        // Do backup & restore.
    +-        backupAndRestore();
    +-
    +-        mService.handleUnlockUser(USER_0); // Load user-0.
    +-
    +-        ShortcutInfo si;
    +-        si = mService.getPackageShortcutForTest(CALLING_PACKAGE_1, "id", USER_0);
    +-
    +-        assertEquals(CALLING_PACKAGE_1, si.getPackage());
    +-        assertEquals("id", si.getId());
    +-        assertEquals(ShortcutActivity2.class.getName(), si.getActivity().getClassName());
    +-        assertEquals(null, si.getIcon());
    +-        assertEquals("title", si.getTitle());
    +-        assertEquals("text", si.getText());
    +-        assertEquals("dismes", si.getDisabledMessage());
    +-        assertEquals(set(ShortcutInfo.SHORTCUT_CATEGORY_CONVERSATION, "xyz"), si.getCategories());
    +-        assertEquals("action", si.getIntent().getAction());
    +-        assertEquals("val", si.getIntent().getStringExtra("key"));
    +-        assertEquals(0, si.getRank());
    +-        assertEquals(1, si.getExtras().getInt("k"));
    +-
    +-        assertEquals(ShortcutInfo.FLAG_PINNED | ShortcutInfo.FLAG_STRINGS_RESOLVED, si.getFlags());
    +-        assertNull(si.getBitmapPath()); // No icon.
    +-        assertEquals(0, si.getIconResourceId());
    +-
    +-        // Note when restored from backup, it's no longer dynamic, so shouldn't have a rank.
    +-        si = mService.getPackageShortcutForTest(CALLING_PACKAGE_1, "id2", USER_0);
    +-        assertEquals(0, si.getRank());
    +-    }
    +-
    +-    public void testShortcutInfoSaveAndLoad_forBackup_resId() {
    +-        setCaller(CALLING_PACKAGE_1, USER_0);
    +-
    +-        final Icon res32x32 = Icon.createWithResource(mClientContext, R.drawable.black_32x32);
    +-
    +-        PersistableBundle pb = new PersistableBundle();
    +-        pb.putInt("k", 1);
    +-        ShortcutInfo sorig = new ShortcutInfo.Builder(mClientContext)
    +-                .setId("id")
    +-                .setActivity(new ComponentName(mClientContext, ShortcutActivity2.class))
    +-                .setIcon(res32x32)
    +-                .setTitleResId(10)
    +-                .setTextResId(11)
    +-                .setDisabledMessageResId(12)
    +-                .setCategories(set(ShortcutInfo.SHORTCUT_CATEGORY_CONVERSATION, "xyz"))
    +-                .setIntent(makeIntent("action", ShortcutActivity.class, "key", "val"))
    +-                .setRank(123)
    +-                .setExtras(pb)
    +-                .build();
    +-
    +-        ShortcutInfo sorig2 = new ShortcutInfo.Builder(mClientContext)
    +-                .setId("id2")
    +-                .setTitle("x")
    +-                .setActivity(new ComponentName(mClientContext, ShortcutActivity2.class))
    +-                .setIntent(makeIntent("action", ShortcutActivity.class, "key", "val"))
    +-                .setRank(456)
    +-                .build();
    +-
    +-        mManager.addDynamicShortcuts(list(sorig, sorig2));
    +-
    +-        // Dynamic shortcuts won't be backed up, so we need to pin it.
    +-        setCaller(LAUNCHER_1, USER_0);
    +-        mLauncherApps.pinShortcuts(CALLING_PACKAGE_1, list("id", "id2"), HANDLE_USER_0);
    +-
    +-        // Do backup & restore.
    +-        backupAndRestore();
    +-
    +-        mService.handleUnlockUser(USER_0); // Load user-0.
    +-
    +-        ShortcutInfo si;
    +-        si = mService.getPackageShortcutForTest(CALLING_PACKAGE_1, "id", USER_0);
    +-
    +-        assertEquals(CALLING_PACKAGE_1, si.getPackage());
    +-        assertEquals("id", si.getId());
    +-        assertEquals(ShortcutActivity2.class.getName(), si.getActivity().getClassName());
    +-        assertEquals(null, si.getIcon());
    +-        assertEquals(10, si.getTitleResId());
    +-        assertEquals("r10", si.getTitleResName());
    +-        assertEquals(11, si.getTextResId());
    +-        assertEquals("r11", si.getTextResName());
    +-        assertEquals(12, si.getDisabledMessageResourceId());
    +-        assertEquals("r12", si.getDisabledMessageResName());
    +-        assertEquals(set(ShortcutInfo.SHORTCUT_CATEGORY_CONVERSATION, "xyz"), si.getCategories());
    +-        assertEquals("action", si.getIntent().getAction());
    +-        assertEquals("val", si.getIntent().getStringExtra("key"));
    +-        assertEquals(0, si.getRank());
    +-        assertEquals(1, si.getExtras().getInt("k"));
    +-
    +-        assertEquals(ShortcutInfo.FLAG_PINNED | ShortcutInfo.FLAG_STRINGS_RESOLVED, si.getFlags());
    +-        assertNull(si.getBitmapPath()); // No icon.
    +-        assertEquals(0, si.getIconResourceId());
    +-        assertEquals(null, si.getIconResName());
    +-
    +-        // Note when restored from backup, it's no longer dynamic, so shouldn't have a rank.
    +-        si = mService.getPackageShortcutForTest(CALLING_PACKAGE_1, "id2", USER_0);
    +-        assertEquals(0, si.getRank());
    +-    }
    +-
    +-    private void checkShortcutInfoSaveAndLoad_intents(Intent intent) {
    +-        assertTrue(mManager.setDynamicShortcuts(list(
    +-                makeShortcutWithIntent("s1", intent))));
    +-        initService();
    +-        mService.handleUnlockUser(USER_0);
    +-
    +-        assertWith(getCallerShortcuts())
    +-                .haveIds("s1")
    +-                .forShortcutWithId("s1", si -> {
    +-                    assertEquals(intent.getAction(), si.getIntent().getAction());
    +-                    assertEquals(intent.getData(), si.getIntent().getData());
    +-                    assertEquals(intent.getComponent(), si.getIntent().getComponent());
    +-                    assertBundlesEqual(intent.getExtras(), si.getIntent().getExtras());
    +-                });
    +-    }
    +-
    +-    private void checkShortcutInfoSaveAndLoad_intents(Intent... intents) {
    +-        assertTrue(mManager.setDynamicShortcuts(list(
    +-                makeShortcutWithIntents("s1", intents))));
    +-        initService();
    +-        mService.handleUnlockUser(USER_0);
    +-
    +-        assertWith(getCallerShortcuts())
    +-                .haveIds("s1")
    +-                .forShortcutWithId("s1", si -> {
    +-
    +-                    final Intent[] actual = si.getIntents();
    +-                    assertEquals(intents.length, actual.length);
    +-
    +-                    for (int i = 0; i < intents.length; i++) {
    +-                        assertEquals(intents[i].getAction(), actual[i].getAction());
    +-                        assertEquals(intents[i].getData(), actual[i].getData());
    +-                        assertEquals(intents[i].getComponent(), actual[i].getComponent());
    +-                        assertEquals(intents[i].getFlags(), actual[i].getFlags());
    +-                        assertBundlesEqual(intents[i].getExtras(), actual[i].getExtras());
    +-                    }
    +-                });
    +-    }
    +-
    +-    public void testShortcutInfoSaveAndLoad_intents() {
    +-        checkShortcutInfoSaveAndLoad_intents(new Intent(Intent.ACTION_VIEW));
    +-
    +-        mInjectedCurrentTimeMillis += INTERVAL; // reset throttling.
    +-
    +-        checkShortcutInfoSaveAndLoad_intents(new Intent(Intent.ACTION_MAIN));
    +-
    +-        mInjectedCurrentTimeMillis += INTERVAL; // reset throttling.
    +-
    +-        checkShortcutInfoSaveAndLoad_intents(new Intent(Intent.ACTION_VIEW,
    +-                Uri.parse("http://www.example.com/")));
    +-
    +-        mInjectedCurrentTimeMillis += INTERVAL; // reset throttling.
    +-
    +-        checkShortcutInfoSaveAndLoad_intents(new Intent(Intent.ACTION_MAIN,
    +-                Uri.parse("http://www.example.com/")));
    +-
    +-        mInjectedCurrentTimeMillis += INTERVAL; // reset throttling.
    +-
    +-        checkShortcutInfoSaveAndLoad_intents(new Intent(Intent.ACTION_VIEW)
    +-                .setComponent(new ComponentName("a", "b")));
    +-
    +-        mInjectedCurrentTimeMillis += INTERVAL; // reset throttling.
    +-
    +-        checkShortcutInfoSaveAndLoad_intents(new Intent(Intent.ACTION_MAIN)
    +-                .setComponent(new ComponentName("a", "b")));
    +-
    +-        mInjectedCurrentTimeMillis += INTERVAL; // reset throttling.
    +-
    +-        checkShortcutInfoSaveAndLoad_intents(new Intent(Intent.ACTION_VIEW)
    +-                .putExtras(makeBundle("a", "b")));
    +-
    +-        mInjectedCurrentTimeMillis += INTERVAL; // reset throttling.
    +-
    +-
    +-        checkShortcutInfoSaveAndLoad_intents(new Intent(Intent.ACTION_MAIN)
    +-                .putExtras(makeBundle("a", "b")));
    +-
    +-        mInjectedCurrentTimeMillis += INTERVAL; // reset throttling.
    +-
    +-        // Multi-intents
    +-        checkShortcutInfoSaveAndLoad_intents(
    +-                new Intent(Intent.ACTION_MAIN).setFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK),
    +-                new Intent(Intent.ACTION_VIEW).setFlags(Intent.FLAG_ACTIVITY_FORWARD_RESULT)
    +-        );
    +-
    +-        checkShortcutInfoSaveAndLoad_intents(
    +-                new Intent(Intent.ACTION_MAIN).setFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK)
    +-                        .setComponent(new ComponentName("a", "b")),
    +-                new Intent(Intent.ACTION_VIEW)
    +-                        .setComponent(new ComponentName("a", "b"))
    +-                );
    +-
    +-        checkShortcutInfoSaveAndLoad_intents(
    +-                new Intent(Intent.ACTION_MAIN)
    +-                        .setComponent(new ComponentName("a", "b")),
    +-                new Intent(Intent.ACTION_VIEW).setFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK)
    +-                        .setComponent(new ComponentName("a", "b")),
    +-                new Intent("xyz").setFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK
    +-                        | Intent.FILL_IN_COMPONENT)
    +-                        .setComponent(new ComponentName("a", "b")).putExtras(
    +-                        makeBundle("xx", "yy"))
    +-                );
    +-    }
    +-
    +-    public void testThrottling() {
    +-        final ShortcutInfo si1 = makeShortcut("shortcut1");
    +-
    +-        assertTrue(mManager.setDynamicShortcuts(list(si1)));
    +-        assertEquals(2, mManager.getRemainingCallCount());
    +-        assertEquals(START_TIME + INTERVAL, mManager.getRateLimitResetTime());
    +-
    +-        mInjectedCurrentTimeMillis++;
    +-        assertTrue(mManager.setDynamicShortcuts(list(si1)));
    +-        assertEquals(1, mManager.getRemainingCallCount());
    +-        assertEquals(START_TIME + INTERVAL, mManager.getRateLimitResetTime());
    +-
    +-        mInjectedCurrentTimeMillis++;
    +-        assertTrue(mManager.setDynamicShortcuts(list(si1)));
    +-        assertEquals(0, mManager.getRemainingCallCount());
    +-        assertEquals(START_TIME + INTERVAL, mManager.getRateLimitResetTime());
    +-
    +-        // Reached the max
    +-
    +-        mInjectedCurrentTimeMillis++;
    +-        assertFalse(mManager.setDynamicShortcuts(list(si1)));
    +-        assertEquals(0, mManager.getRemainingCallCount());
    +-        assertEquals(START_TIME + INTERVAL, mManager.getRateLimitResetTime());
    +-
    +-        // Still throttled
    +-        mInjectedCurrentTimeMillis = START_TIME + INTERVAL - 1;
    +-        assertFalse(mManager.setDynamicShortcuts(list(si1)));
    +-        assertEquals(0, mManager.getRemainingCallCount());
    +-        assertEquals(START_TIME + INTERVAL, mManager.getRateLimitResetTime());
    +-
    +-        // Now it should work.
    +-        mInjectedCurrentTimeMillis++;
    +-        assertTrue(mManager.setDynamicShortcuts(list(si1))); // fail
    +-        assertEquals(2, mManager.getRemainingCallCount());
    +-        assertEquals(START_TIME + INTERVAL * 2, mManager.getRateLimitResetTime());
    +-
    +-        mInjectedCurrentTimeMillis++;
    +-        assertTrue(mManager.setDynamicShortcuts(list(si1)));
    +-        assertEquals(1, mManager.getRemainingCallCount());
    +-        assertEquals(START_TIME + INTERVAL * 2, mManager.getRateLimitResetTime());
    +-
    +-        mInjectedCurrentTimeMillis++;
    +-        assertTrue(mManager.setDynamicShortcuts(list(si1)));
    +-        assertEquals(0, mManager.getRemainingCallCount());
    +-        assertEquals(START_TIME + INTERVAL * 2, mManager.getRateLimitResetTime());
    +-
    +-        mInjectedCurrentTimeMillis++;
    +-        assertFalse(mManager.setDynamicShortcuts(list(si1)));
    +-        assertEquals(0, mManager.getRemainingCallCount());
    +-        assertEquals(START_TIME + INTERVAL * 2, mManager.getRateLimitResetTime());
    +-
    +-        // 4 hours later...
    +-        mInjectedCurrentTimeMillis = START_TIME + 4 * INTERVAL;
    +-        assertTrue(mManager.setDynamicShortcuts(list(si1)));
    +-        assertEquals(2, mManager.getRemainingCallCount());
    +-        assertEquals(START_TIME + INTERVAL * 5, mManager.getRateLimitResetTime());
    +-
    +-        mInjectedCurrentTimeMillis++;
    +-        assertTrue(mManager.setDynamicShortcuts(list(si1)));
    +-        assertEquals(1, mManager.getRemainingCallCount());
    +-        assertEquals(START_TIME + INTERVAL * 5, mManager.getRateLimitResetTime());
    +-
    +-        // Make sure getRemainingCallCount() itself gets reset without calling setDynamicShortcuts().
    +-        mInjectedCurrentTimeMillis = START_TIME + 8 * INTERVAL;
    +-        assertEquals(3, mManager.getRemainingCallCount());
    +-        assertEquals(START_TIME + INTERVAL * 9, mManager.getRateLimitResetTime());
    +-
    +-        mInjectedCurrentTimeMillis++;
    +-        assertTrue(mManager.setDynamicShortcuts(list(si1)));
    +-        assertEquals(2, mManager.getRemainingCallCount());
    +-        assertEquals(START_TIME + INTERVAL * 9, mManager.getRateLimitResetTime());
    +-    }
    +-
    +-    public void testThrottling_rewind() {
    +-        final ShortcutInfo si1 = makeShortcut("shortcut1");
    +-
    +-        assertTrue(mManager.setDynamicShortcuts(list(si1)));
    +-        assertEquals(2, mManager.getRemainingCallCount());
    +-        assertEquals(START_TIME + INTERVAL, mManager.getRateLimitResetTime());
    +-
    +-        mInjectedCurrentTimeMillis = 12345; // Clock reset!
    +-
    +-        // Since the clock looks invalid, the counter shouldn't have reset.
    +-        assertEquals(2, mManager.getRemainingCallCount());
    +-        assertEquals(START_TIME + INTERVAL, mManager.getRateLimitResetTime());
    +-
    +-        // Forward again.  Still haven't reset yet.
    +-        mInjectedCurrentTimeMillis = START_TIME + INTERVAL - 1;
    +-        assertEquals(2, mManager.getRemainingCallCount());
    +-        assertEquals(START_TIME + INTERVAL, mManager.getRateLimitResetTime());
    +-
    +-        // Now rewind -- this will reset the counters.
    +-        mInjectedCurrentTimeMillis = START_TIME - 100000;
    +-        assertEquals(3, mManager.getRemainingCallCount());
    +-
    +-        assertTrue(mManager.setDynamicShortcuts(list(si1)));
    +-        assertEquals(2, mManager.getRemainingCallCount());
    +-
    +-        // Forward again, should be reset now.
    +-        mInjectedCurrentTimeMillis += INTERVAL;
    +-        assertEquals(3, mManager.getRemainingCallCount());
    +-    }
    +-
    +-    public void testThrottling_perPackage() {
    +-        final ShortcutInfo si1 = makeShortcut("shortcut1");
    +-
    +-        assertTrue(mManager.setDynamicShortcuts(list(si1)));
    +-        assertEquals(2, mManager.getRemainingCallCount());
    +-
    +-        mInjectedCurrentTimeMillis++;
    +-        assertTrue(mManager.setDynamicShortcuts(list(si1)));
    +-        assertEquals(1, mManager.getRemainingCallCount());
    +-
    +-        mInjectedCurrentTimeMillis++;
    +-        assertTrue(mManager.setDynamicShortcuts(list(si1)));
    +-        assertEquals(0, mManager.getRemainingCallCount());
    +-
    +-        // Reached the max
    +-
    +-        mInjectedCurrentTimeMillis++;
    +-        assertFalse(mManager.setDynamicShortcuts(list(si1)));
    +-
    +-        // Try from a different caller.
    +-        mInjectedClientPackage = CALLING_PACKAGE_2;
    +-        mInjectedCallingUid = CALLING_UID_2;
    +-
    +-        // Need to create a new one wit the updated package name.
    +-        final ShortcutInfo si2 = makeShortcut("shortcut1");
    +-
    +-        assertEquals(3, mManager.getRemainingCallCount());
    +-
    +-        assertTrue(mManager.setDynamicShortcuts(list(si2)));
    +-        assertEquals(2, mManager.getRemainingCallCount());
    +-
    +-        mInjectedCurrentTimeMillis++;
    +-        assertTrue(mManager.setDynamicShortcuts(list(si2)));
    +-        assertEquals(1, mManager.getRemainingCallCount());
    +-
    +-        // Back to the original caller, still throttled.
    +-        mInjectedClientPackage = CALLING_PACKAGE_1;
    +-        mInjectedCallingUid = CALLING_UID_1;
    +-
    +-        mInjectedCurrentTimeMillis = START_TIME + INTERVAL - 1;
    +-        assertEquals(0, mManager.getRemainingCallCount());
    +-        assertFalse(mManager.setDynamicShortcuts(list(si1)));
    +-        assertEquals(0, mManager.getRemainingCallCount());
    +-
    +-        // Now it should work.
    +-        mInjectedCurrentTimeMillis++;
    +-        assertTrue(mManager.setDynamicShortcuts(list(si1)));
    +-
    +-        mInjectedCurrentTimeMillis++;
    +-        assertTrue(mManager.setDynamicShortcuts(list(si1)));
    +-
    +-        mInjectedCurrentTimeMillis++;
    +-        assertTrue(mManager.setDynamicShortcuts(list(si1)));
    +-
    +-        mInjectedCurrentTimeMillis++;
    +-        assertFalse(mManager.setDynamicShortcuts(list(si1)));
    +-
    +-        mInjectedCurrentTimeMillis = START_TIME + 4 * INTERVAL;
    +-        assertTrue(mManager.setDynamicShortcuts(list(si1)));
    +-        assertTrue(mManager.setDynamicShortcuts(list(si1)));
    +-        assertTrue(mManager.setDynamicShortcuts(list(si1)));
    +-        assertFalse(mManager.setDynamicShortcuts(list(si1)));
    +-
    +-        mInjectedClientPackage = CALLING_PACKAGE_2;
    +-        mInjectedCallingUid = CALLING_UID_2;
    +-
    +-        assertEquals(3, mManager.getRemainingCallCount());
    +-
    +-        assertTrue(mManager.setDynamicShortcuts(list(si2)));
    +-        assertTrue(mManager.setDynamicShortcuts(list(si2)));
    +-        assertTrue(mManager.setDynamicShortcuts(list(si2)));
    +-        assertFalse(mManager.setDynamicShortcuts(list(si2)));
    +-    }
    +-
    +-    public void testThrottling_localeChanges() {
    +-        prepareCrossProfileDataSet();
    +-
    +-        dumpsysOnLogcat("Before save & load");
    +-
    +-        mService.saveDirtyInfo();
    +-        initService();
    +-
    +-        mInjectedLocale = Locale.CHINA;
    +-        mService.mReceiver.onReceive(mServiceContext, new Intent(Intent.ACTION_LOCALE_CHANGED));
    +-
    +-        // Note at this point only user-0 is loaded, and the counters are reset for this user,
    +-        // but it will work for other users too because we check the locale change at any
    +-        // API entry point.
    +-
    +-        runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
    +-            assertEquals(3, mManager.getRemainingCallCount());
    +-        });
    +-        runWithCaller(CALLING_PACKAGE_2, USER_0, () -> {
    +-            assertEquals(3, mManager.getRemainingCallCount());
    +-        });
    +-        runWithCaller(CALLING_PACKAGE_3, USER_0, () -> {
    +-            assertEquals(3, mManager.getRemainingCallCount());
    +-        });
    +-        runWithCaller(CALLING_PACKAGE_4, USER_0, () -> {
    +-            assertEquals(3, mManager.getRemainingCallCount());
    +-        });
    +-        runWithCaller(CALLING_PACKAGE_1, USER_P0, () -> {
    +-            assertEquals(3, mManager.getRemainingCallCount());
    +-        });
    +-        runWithCaller(CALLING_PACKAGE_1, USER_10, () -> {
    +-            assertEquals(3, mManager.getRemainingCallCount());
    +-        });
    +-
    +-        // Make sure even if we receive ACTION_LOCALE_CHANGED, if the locale hasn't actually
    +-        // changed, we don't reset throttling.
    +-        runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
    +-            mManager.updateShortcuts(list());
    +-            assertEquals(2, mManager.getRemainingCallCount());
    +-        });
    +-
    +-        mService.mReceiver.onReceive(mServiceContext, new Intent(Intent.ACTION_LOCALE_CHANGED));
    +-
    +-        runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
    +-            assertEquals(2, mManager.getRemainingCallCount()); // Still 2.
    +-        });
    +-
    +-        mService.saveDirtyInfo();
    +-        initService();
    +-
    +-        // The locale should be persisted, so it still shouldn't reset throttling.
    +-        mService.mReceiver.onReceive(mServiceContext, new Intent(Intent.ACTION_LOCALE_CHANGED));
    +-
    +-        runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
    +-            assertEquals(2, mManager.getRemainingCallCount()); // Still 2.
    +-        });
    +-    }
    +-
    +-    public void testThrottling_foreground() throws Exception {
    +-        prepareCrossProfileDataSet();
    +-
    +-        dumpsysOnLogcat("Before save & load");
    +-
    +-        mService.saveDirtyInfo();
    +-        initService();
    +-
    +-        // We need to update the current time from time to time, since some of the internal checks
    +-        // rely on the time being correctly incremented.
    +-        mInjectedCurrentTimeMillis++;
    +-
    +-        // First, all packages have less than 3 (== initial value) remaining calls.
    +-
    +-        runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
    +-            MoreAsserts.assertNotEqual(3, mManager.getRemainingCallCount());
    +-        });
    +-        runWithCaller(CALLING_PACKAGE_2, USER_0, () -> {
    +-            MoreAsserts.assertNotEqual(3, mManager.getRemainingCallCount());
    +-        });
    +-        runWithCaller(CALLING_PACKAGE_3, USER_0, () -> {
    +-            MoreAsserts.assertNotEqual(3, mManager.getRemainingCallCount());
    +-        });
    +-        runWithCaller(CALLING_PACKAGE_4, USER_0, () -> {
    +-            MoreAsserts.assertNotEqual(3, mManager.getRemainingCallCount());
    +-        });
    +-        runWithCaller(CALLING_PACKAGE_1, USER_P0, () -> {
    +-            MoreAsserts.assertNotEqual(3, mManager.getRemainingCallCount());
    +-        });
    +-        runWithCaller(CALLING_PACKAGE_1, USER_10, () -> {
    +-            MoreAsserts.assertNotEqual(3, mManager.getRemainingCallCount());
    +-        });
    +-
    +-        mInjectedCurrentTimeMillis++;
    +-
    +-        // State changed, but not foreground, so no resetting.
    +-        mService.mUidObserver.onUidStateChanged(
    +-                CALLING_UID_1, ActivityManager.PROCESS_STATE_TOP_SLEEPING);
    +-        runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
    +-            MoreAsserts.assertNotEqual(3, mManager.getRemainingCallCount());
    +-        });
    +-        runWithCaller(CALLING_PACKAGE_2, USER_0, () -> {
    +-            MoreAsserts.assertNotEqual(3, mManager.getRemainingCallCount());
    +-        });
    +-        runWithCaller(CALLING_PACKAGE_3, USER_0, () -> {
    +-            MoreAsserts.assertNotEqual(3, mManager.getRemainingCallCount());
    +-        });
    +-        runWithCaller(CALLING_PACKAGE_4, USER_0, () -> {
    +-            MoreAsserts.assertNotEqual(3, mManager.getRemainingCallCount());
    +-        });
    +-        runWithCaller(CALLING_PACKAGE_1, USER_P0, () -> {
    +-            MoreAsserts.assertNotEqual(3, mManager.getRemainingCallCount());
    +-        });
    +-        runWithCaller(CALLING_PACKAGE_1, USER_10, () -> {
    +-            MoreAsserts.assertNotEqual(3, mManager.getRemainingCallCount());
    +-        });
    +-
    +-        mInjectedCurrentTimeMillis++;
    +-
    +-        // State changed, package1 foreground, reset.
    +-        mService.mUidObserver.onUidStateChanged(
    +-                CALLING_UID_1, ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE);
    +-        runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
    +-            assertEquals(3, mManager.getRemainingCallCount());
    +-        });
    +-        runWithCaller(CALLING_PACKAGE_2, USER_0, () -> {
    +-            MoreAsserts.assertNotEqual(3, mManager.getRemainingCallCount());
    +-        });
    +-        runWithCaller(CALLING_PACKAGE_3, USER_0, () -> {
    +-            MoreAsserts.assertNotEqual(3, mManager.getRemainingCallCount());
    +-        });
    +-        runWithCaller(CALLING_PACKAGE_4, USER_0, () -> {
    +-            MoreAsserts.assertNotEqual(3, mManager.getRemainingCallCount());
    +-        });
    +-        runWithCaller(CALLING_PACKAGE_1, USER_P0, () -> {
    +-            MoreAsserts.assertNotEqual(3, mManager.getRemainingCallCount());
    +-        });
    +-        runWithCaller(CALLING_PACKAGE_1, USER_10, () -> {
    +-            MoreAsserts.assertNotEqual(3, mManager.getRemainingCallCount());
    +-        });
    +-        mService.mUidObserver.onUidStateChanged(
    +-                CALLING_UID_1, ActivityManager.PROCESS_STATE_TOP_SLEEPING);
    +-
    +-        mInjectedCurrentTimeMillis++;
    +-
    +-        // Different app comes to foreground briefly, and goes back to background.
    +-        // Now, make sure package 2's counter is reset, even in this case.
    +-        mService.mUidObserver.onUidStateChanged(
    +-                CALLING_UID_2, ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE);
    +-        mService.mUidObserver.onUidStateChanged(
    +-                CALLING_UID_2, ActivityManager.PROCESS_STATE_TOP_SLEEPING);
    +-
    +-        runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
    +-            assertEquals(3, mManager.getRemainingCallCount());
    +-        });
    +-        runWithCaller(CALLING_PACKAGE_2, USER_0, () -> {
    +-            assertEquals(3, mManager.getRemainingCallCount());
    +-        });
    +-        runWithCaller(CALLING_PACKAGE_3, USER_0, () -> {
    +-            MoreAsserts.assertNotEqual(3, mManager.getRemainingCallCount());
    +-        });
    +-        runWithCaller(CALLING_PACKAGE_4, USER_0, () -> {
    +-            MoreAsserts.assertNotEqual(3, mManager.getRemainingCallCount());
    +-        });
    +-        runWithCaller(CALLING_PACKAGE_1, USER_P0, () -> {
    +-            MoreAsserts.assertNotEqual(3, mManager.getRemainingCallCount());
    +-        });
    +-        runWithCaller(CALLING_PACKAGE_1, USER_10, () -> {
    +-            MoreAsserts.assertNotEqual(3, mManager.getRemainingCallCount());
    +-        });
    +-
    +-        mInjectedCurrentTimeMillis++;
    +-
    +-        // Do the same thing one more time.  This would catch the bug with mixuing up
    +-        // the current time and the elapsed time.
    +-        runWithCaller(CALLING_PACKAGE_2, USER_0, () -> {
    +-            mManager.updateShortcuts(list(makeShortcut("s")));
    +-            MoreAsserts.assertNotEqual(3, mManager.getRemainingCallCount());
    +-        });
    +-
    +-        mService.mUidObserver.onUidStateChanged(
    +-                CALLING_UID_2, ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE);
    +-        mService.mUidObserver.onUidStateChanged(
    +-                CALLING_UID_2, ActivityManager.PROCESS_STATE_TOP_SLEEPING);
    +-
    +-        runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
    +-            assertEquals(3, mManager.getRemainingCallCount());
    +-        });
    +-        runWithCaller(CALLING_PACKAGE_2, USER_0, () -> {
    +-            assertEquals(3, mManager.getRemainingCallCount());
    +-        });
    +-        runWithCaller(CALLING_PACKAGE_3, USER_0, () -> {
    +-            MoreAsserts.assertNotEqual(3, mManager.getRemainingCallCount());
    +-        });
    +-        runWithCaller(CALLING_PACKAGE_4, USER_0, () -> {
    +-            MoreAsserts.assertNotEqual(3, mManager.getRemainingCallCount());
    +-        });
    +-        runWithCaller(CALLING_PACKAGE_1, USER_P0, () -> {
    +-            MoreAsserts.assertNotEqual(3, mManager.getRemainingCallCount());
    +-        });
    +-        runWithCaller(CALLING_PACKAGE_1, USER_10, () -> {
    +-            MoreAsserts.assertNotEqual(3, mManager.getRemainingCallCount());
    +-        });
    +-
    +-        mInjectedCurrentTimeMillis++;
    +-
    +-        // Package 1 on user-10 comes to foreground.
    +-        // Now, also try calling some APIs and make sure foreground apps don't get throttled.
    +-        mService.mUidObserver.onUidStateChanged(
    +-                UserHandle.getUid(USER_10, CALLING_UID_1),
    +-                ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE);
    +-        runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
    +-            assertEquals(3, mManager.getRemainingCallCount());
    +-            assertFalse(mManager.isRateLimitingActive());
    +-
    +-            mManager.setDynamicShortcuts(list(makeShortcut("s")));
    +-
    +-            assertEquals(2, mManager.getRemainingCallCount());
    +-            assertFalse(mManager.isRateLimitingActive());
    +-
    +-            mManager.setDynamicShortcuts(list(makeShortcut("s")));
    +-
    +-            assertEquals(1, mManager.getRemainingCallCount());
    +-            assertFalse(mManager.isRateLimitingActive());
    +-
    +-            mManager.setDynamicShortcuts(list(makeShortcut("s")));
    +-
    +-            assertEquals(0, mManager.getRemainingCallCount());
    +-            assertTrue(mManager.isRateLimitingActive());
    +-        });
    +-        runWithCaller(CALLING_PACKAGE_2, USER_0, () -> {
    +-            assertEquals(3, mManager.getRemainingCallCount());
    +-
    +-            mManager.setDynamicShortcuts(list(makeShortcut("s")));
    +-            mManager.setDynamicShortcuts(list(makeShortcut("s")));
    +-            mManager.setDynamicShortcuts(list(makeShortcut("s")));
    +-
    +-            assertEquals(0, mManager.getRemainingCallCount());
    +-            assertTrue(mManager.isRateLimitingActive());
    +-        });
    +-        runWithCaller(CALLING_PACKAGE_3, USER_0, () -> {
    +-            MoreAsserts.assertNotEqual(3, mManager.getRemainingCallCount());
    +-
    +-            mManager.setDynamicShortcuts(list(makeShortcut("s")));
    +-            mManager.setDynamicShortcuts(list(makeShortcut("s")));
    +-            mManager.setDynamicShortcuts(list(makeShortcut("s")));
    +-
    +-            assertEquals(0, mManager.getRemainingCallCount());
    +-            assertTrue(mManager.isRateLimitingActive());
    +-        });
    +-        runWithCaller(CALLING_PACKAGE_4, USER_0, () -> {
    +-            MoreAsserts.assertNotEqual(3, mManager.getRemainingCallCount());
    +-
    +-            mManager.setDynamicShortcuts(list(makeShortcut("s")));
    +-            mManager.setDynamicShortcuts(list(makeShortcut("s")));
    +-            mManager.setDynamicShortcuts(list(makeShortcut("s")));
    +-
    +-            assertEquals(0, mManager.getRemainingCallCount());
    +-            assertTrue(mManager.isRateLimitingActive());
    +-        });
    +-        runWithCaller(CALLING_PACKAGE_1, USER_P0, () -> {
    +-            MoreAsserts.assertNotEqual(3, mManager.getRemainingCallCount());
    +-
    +-            mManager.setDynamicShortcuts(list(makeShortcut("s")));
    +-            mManager.setDynamicShortcuts(list(makeShortcut("s")));
    +-            mManager.setDynamicShortcuts(list(makeShortcut("s")));
    +-
    +-            assertEquals(0, mManager.getRemainingCallCount());
    +-            assertTrue(mManager.isRateLimitingActive());
    +-        });
    +-        runWithCaller(CALLING_PACKAGE_1, USER_10, () -> {
    +-            assertEquals(3, mManager.getRemainingCallCount());
    +-
    +-            mManager.setDynamicShortcuts(list(makeShortcut("s")));
    +-            mManager.setDynamicShortcuts(list(makeShortcut("s")));
    +-            mManager.setDynamicShortcuts(list(makeShortcut("s")));
    +-
    +-            assertEquals(3, mManager.getRemainingCallCount()); // Still 3!
    +-            assertFalse(mManager.isRateLimitingActive());
    +-        });
    +-    }
    +-
    +-
    +-    public void testThrottling_resetByInternalCall() throws Exception {
    +-        prepareCrossProfileDataSet();
    +-
    +-        dumpsysOnLogcat("Before save & load");
    +-
    +-        mService.saveDirtyInfo();
    +-        initService();
    +-
    +-        // First, all packages have less than 3 (== initial value) remaining calls.
    +-
    +-        runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
    +-            MoreAsserts.assertNotEqual(3, mManager.getRemainingCallCount());
    +-        });
    +-        runWithCaller(CALLING_PACKAGE_2, USER_0, () -> {
    +-            MoreAsserts.assertNotEqual(3, mManager.getRemainingCallCount());
    +-        });
    +-        runWithCaller(CALLING_PACKAGE_3, USER_0, () -> {
    +-            MoreAsserts.assertNotEqual(3, mManager.getRemainingCallCount());
    +-        });
    +-        runWithCaller(CALLING_PACKAGE_4, USER_0, () -> {
    +-            MoreAsserts.assertNotEqual(3, mManager.getRemainingCallCount());
    +-        });
    +-        runWithCaller(CALLING_PACKAGE_1, USER_P0, () -> {
    +-            MoreAsserts.assertNotEqual(3, mManager.getRemainingCallCount());
    +-        });
    +-        runWithCaller(CALLING_PACKAGE_1, USER_10, () -> {
    +-            MoreAsserts.assertNotEqual(3, mManager.getRemainingCallCount());
    +-        });
    +-
    +-        // Simulate a call from sys UI.
    +-        mCallerPermissions.add(permission.RESET_SHORTCUT_MANAGER_THROTTLING);
    +-        mManager.onApplicationActive(CALLING_PACKAGE_1, USER_0);
    +-
    +-        runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
    +-            assertEquals(3, mManager.getRemainingCallCount());
    +-        });
    +-        runWithCaller(CALLING_PACKAGE_2, USER_0, () -> {
    +-            MoreAsserts.assertNotEqual(3, mManager.getRemainingCallCount());
    +-        });
    +-        runWithCaller(CALLING_PACKAGE_3, USER_0, () -> {
    +-            MoreAsserts.assertNotEqual(3, mManager.getRemainingCallCount());
    +-        });
    +-        runWithCaller(CALLING_PACKAGE_4, USER_0, () -> {
    +-            MoreAsserts.assertNotEqual(3, mManager.getRemainingCallCount());
    +-        });
    +-        runWithCaller(CALLING_PACKAGE_1, USER_P0, () -> {
    +-            MoreAsserts.assertNotEqual(3, mManager.getRemainingCallCount());
    +-        });
    +-        runWithCaller(CALLING_PACKAGE_1, USER_10, () -> {
    +-            MoreAsserts.assertNotEqual(3, mManager.getRemainingCallCount());
    +-        });
    +-
    +-        mManager.onApplicationActive(CALLING_PACKAGE_3, USER_0);
    +-
    +-        runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
    +-            assertEquals(3, mManager.getRemainingCallCount());
    +-        });
    +-        runWithCaller(CALLING_PACKAGE_2, USER_0, () -> {
    +-            MoreAsserts.assertNotEqual(3, mManager.getRemainingCallCount());
    +-        });
    +-        runWithCaller(CALLING_PACKAGE_3, USER_0, () -> {
    +-            assertEquals(3, mManager.getRemainingCallCount());
    +-        });
    +-        runWithCaller(CALLING_PACKAGE_4, USER_0, () -> {
    +-            MoreAsserts.assertNotEqual(3, mManager.getRemainingCallCount());
    +-        });
    +-        runWithCaller(CALLING_PACKAGE_1, USER_P0, () -> {
    +-            MoreAsserts.assertNotEqual(3, mManager.getRemainingCallCount());
    +-        });
    +-        runWithCaller(CALLING_PACKAGE_1, USER_10, () -> {
    +-            MoreAsserts.assertNotEqual(3, mManager.getRemainingCallCount());
    +-        });
    +-
    +-        mManager.onApplicationActive(CALLING_PACKAGE_1, USER_10);
    +-
    +-        runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
    +-            assertEquals(3, mManager.getRemainingCallCount());
    +-        });
    +-        runWithCaller(CALLING_PACKAGE_2, USER_0, () -> {
    +-            MoreAsserts.assertNotEqual(3, mManager.getRemainingCallCount());
    +-        });
    +-        runWithCaller(CALLING_PACKAGE_3, USER_0, () -> {
    +-            assertEquals(3, mManager.getRemainingCallCount());
    +-        });
    +-        runWithCaller(CALLING_PACKAGE_4, USER_0, () -> {
    +-            MoreAsserts.assertNotEqual(3, mManager.getRemainingCallCount());
    +-        });
    +-        runWithCaller(CALLING_PACKAGE_1, USER_P0, () -> {
    +-            MoreAsserts.assertNotEqual(3, mManager.getRemainingCallCount());
    +-        });
    +-        runWithCaller(CALLING_PACKAGE_1, USER_10, () -> {
    +-            assertEquals(3, mManager.getRemainingCallCount());
    +-        });
    +-    }
    +-
    +-    public void testReportShortcutUsed() {
    +-        mRunningUsers.put(USER_10, true);
    +-
    +-        runWithCaller(CALLING_PACKAGE_1, USER_10, () -> {
    +-            reset(mMockUsageStatsManagerInternal);
    +-
    +-            // Report with an nonexistent shortcut.
    +-            mManager.reportShortcutUsed("s1");
    +-            verify(mMockUsageStatsManagerInternal, times(0)).reportShortcutUsage(
    +-                    anyString(), anyString(), anyInt());
    +-
    +-            // Publish s2, but s1 still doesn't exist.
    +-            mManager.setDynamicShortcuts(list(makeShortcut("s2")));
    +-            mManager.reportShortcutUsed("s1");
    +-            verify(mMockUsageStatsManagerInternal, times(0)).reportShortcutUsage(
    +-                    anyString(), anyString(), anyInt());
    +-
    +-            mManager.reportShortcutUsed("s2");
    +-            verify(mMockUsageStatsManagerInternal, times(1)).reportShortcutUsage(
    +-                    eq(CALLING_PACKAGE_1), eq("s2"), eq(USER_10));
    +-
    +-        });
    +-        runWithCaller(CALLING_PACKAGE_2, USER_10, () -> {
    +-            // Try with a different package.
    +-            reset(mMockUsageStatsManagerInternal);
    +-
    +-            // Report with an nonexistent shortcut.
    +-            mManager.reportShortcutUsed("s2");
    +-            verify(mMockUsageStatsManagerInternal, times(0)).reportShortcutUsage(
    +-                    anyString(), anyString(), anyInt());
    +-
    +-            // Publish s2, but s1 still doesn't exist.
    +-            mManager.setDynamicShortcuts(list(makeShortcut("s3")));
    +-            mManager.reportShortcutUsed("s2");
    +-            verify(mMockUsageStatsManagerInternal, times(0)).reportShortcutUsage(
    +-                    anyString(), anyString(), anyInt());
    +-
    +-            mManager.reportShortcutUsed("s3");
    +-            verify(mMockUsageStatsManagerInternal, times(1)).reportShortcutUsage(
    +-                    eq(CALLING_PACKAGE_2), eq("s3"), eq(USER_10));
    +-
    +-        });
    +-    }
    +-
    +-    // Test for a ShortcutInfo method.
    +-    public void testGetResourcePackageName() {
    +-        assertEquals(null, ShortcutInfo.getResourcePackageName(""));
    +-        assertEquals(null, ShortcutInfo.getResourcePackageName("abc"));
    +-        assertEquals("p", ShortcutInfo.getResourcePackageName("p:"));
    +-        assertEquals("p", ShortcutInfo.getResourcePackageName("p:xx"));
    +-        assertEquals("pac", ShortcutInfo.getResourcePackageName("pac:"));
    +-    }
    +-
    +-    // Test for a ShortcutInfo method.
    +-    public void testGetResourceTypeName() {
    +-        assertEquals(null, ShortcutInfo.getResourceTypeName(""));
    +-        assertEquals(null, ShortcutInfo.getResourceTypeName(":"));
    +-        assertEquals(null, ShortcutInfo.getResourceTypeName("/"));
    +-        assertEquals(null, ShortcutInfo.getResourceTypeName("/:"));
    +-        assertEquals("a", ShortcutInfo.getResourceTypeName(":a/"));
    +-        assertEquals("type", ShortcutInfo.getResourceTypeName("xxx:type/yyy"));
    +-    }
    +-
    +-    // Test for a ShortcutInfo method.
    +-    public void testGetResourceTypeAndEntryName() {
    +-        assertEquals(null, ShortcutInfo.getResourceTypeAndEntryName(""));
    +-        assertEquals(null, ShortcutInfo.getResourceTypeAndEntryName("abc"));
    +-        assertEquals("", ShortcutInfo.getResourceTypeAndEntryName("p:"));
    +-        assertEquals("x", ShortcutInfo.getResourceTypeAndEntryName(":x"));
    +-        assertEquals("x", ShortcutInfo.getResourceTypeAndEntryName("p:x"));
    +-        assertEquals("xyz", ShortcutInfo.getResourceTypeAndEntryName("pac:xyz"));
    +-    }
    +-
    +-    // Test for a ShortcutInfo method.
    +-    public void testGetResourceEntryName() {
    +-        assertEquals(null, ShortcutInfo.getResourceEntryName(""));
    +-        assertEquals(null, ShortcutInfo.getResourceEntryName("ab:"));
    +-        assertEquals("", ShortcutInfo.getResourceEntryName("/"));
    +-        assertEquals("abc", ShortcutInfo.getResourceEntryName("/abc"));
    +-        assertEquals("abc", ShortcutInfo.getResourceEntryName("xyz/abc"));
    +-    }
    +-
    +-    // Test for a ShortcutInfo method.
    +-    public void testLookUpResourceName_systemResources() {
    +-        // For android system resources, lookUpResourceName will simply return the value as a
    +-        // string, regardless of "withType".
    +-        final Resources res = getTestContext().getResources();
    +-
    +-        assertEquals("" + android.R.string.cancel, ShortcutInfo.lookUpResourceName(res,
    +-                android.R.string.cancel, true, getTestContext().getPackageName()));
    +-        assertEquals("" + android.R.drawable.alert_dark_frame, ShortcutInfo.lookUpResourceName(res,
    +-                android.R.drawable.alert_dark_frame, true, getTestContext().getPackageName()));
    +-        assertEquals("" + android.R.string.cancel, ShortcutInfo.lookUpResourceName(res,
    +-                android.R.string.cancel, false, getTestContext().getPackageName()));
    +-    }
    +-
    +-    public void testLookUpResourceName_appResources() {
    +-        final Resources res = getTestContext().getResources();
    +-
    +-        assertEquals("shortcut_text1", ShortcutInfo.lookUpResourceName(res,
    +-                R.string.shortcut_text1, false, getTestContext().getPackageName()));
    +-        assertEquals("string/shortcut_text1", ShortcutInfo.lookUpResourceName(res,
    +-                R.string.shortcut_text1, true, getTestContext().getPackageName()));
    +-
    +-        assertEquals("black_16x64", ShortcutInfo.lookUpResourceName(res,
    +-                R.drawable.black_16x64, false, getTestContext().getPackageName()));
    +-        assertEquals("drawable/black_16x64", ShortcutInfo.lookUpResourceName(res,
    +-                R.drawable.black_16x64, true, getTestContext().getPackageName()));
    +-    }
    +-
    +-    // Test for a ShortcutInfo method.
    +-    public void testLookUpResourceId_systemResources() {
    +-        final Resources res = getTestContext().getResources();
    +-
    +-        assertEquals(android.R.string.cancel, ShortcutInfo.lookUpResourceId(res,
    +-                "" + android.R.string.cancel, null,
    +-                getTestContext().getPackageName()));
    +-        assertEquals(android.R.drawable.alert_dark_frame, ShortcutInfo.lookUpResourceId(res,
    +-                "" + android.R.drawable.alert_dark_frame, null,
    +-                getTestContext().getPackageName()));
    +-    }
    +-
    +-    // Test for a ShortcutInfo method.
    +-    public void testLookUpResourceId_appResources() {
    +-        final Resources res = getTestContext().getResources();
    +-
    +-        assertEquals(R.string.shortcut_text1,
    +-                ShortcutInfo.lookUpResourceId(res, "shortcut_text1", "string",
    +-                        getTestContext().getPackageName()));
    +-
    +-        assertEquals(R.string.shortcut_text1,
    +-                ShortcutInfo.lookUpResourceId(res, "string/shortcut_text1", null,
    +-                        getTestContext().getPackageName()));
    +-
    +-        assertEquals(R.drawable.black_16x64,
    +-                ShortcutInfo.lookUpResourceId(res, "black_16x64", "drawable",
    +-                        getTestContext().getPackageName()));
    +-
    +-        assertEquals(R.drawable.black_16x64,
    +-                ShortcutInfo.lookUpResourceId(res, "drawable/black_16x64", null,
    +-                        getTestContext().getPackageName()));
    +-    }
    +-
    +-    public void testDumpCheckin() throws IOException {
    +-        prepareCrossProfileDataSet();
    +-
    +-        // prepareCrossProfileDataSet() doesn't set any icons, so do set here.
    +-        final Icon res32x32 = Icon.createWithResource(getTestContext(), R.drawable.black_32x32);
    +-        final Icon res64x64 = Icon.createWithResource(getTestContext(), R.drawable.black_64x64);
    +-        final Icon bmp32x32 = Icon.createWithBitmap(BitmapFactory.decodeResource(
    +-                getTestContext().getResources(), R.drawable.black_32x32));
    +-        final Icon bmp64x64 = Icon.createWithBitmap(BitmapFactory.decodeResource(
    +-                getTestContext().getResources(), R.drawable.black_64x64));
    +-
    +-        runWithCaller(CALLING_PACKAGE_2, USER_0, () -> {
    +-            assertTrue(mManager.setDynamicShortcuts(list(
    +-                    makeShortcutWithIcon("res32x32", res32x32),
    +-                    makeShortcutWithIcon("res64x64", res64x64),
    +-                    makeShortcutWithIcon("bmp32x32", bmp32x32),
    +-                    makeShortcutWithIcon("bmp64x64", bmp64x64))));
    +-        });
    +-        // We can't predict the compressed bitmap sizes, so get the real sizes here.
    +-        final long bitmapTotal =
    +-                new File(getPackageShortcut(CALLING_PACKAGE_2, "bmp32x32", USER_0)
    +-                        .getBitmapPath()).length() +
    +-                new File(getPackageShortcut(CALLING_PACKAGE_2, "bmp64x64", USER_0)
    +-                        .getBitmapPath()).length();
    +-
    +-        // Read the expected output and inject the bitmap size.
    +-        final String expected = readTestAsset("shortcut/dumpsys_expected.txt")
    +-                .replace("***BITMAP_SIZE***", String.valueOf(bitmapTotal));
    +-
    +-        assertEquals(expected, dumpCheckin());
    +-    }
    +-
    +-    public void testDumpsysNoPermission() {
    +-        assertExpectException(SecurityException.class, "android.permission.DUMP",
    +-                () -> mService.dump(null, new PrintWriter(new StringWriter()), null));
    +-
    +-        // System can call it without the permission.
    +-        runWithSystemUid(() -> {
    +-            mService.dump(null, new PrintWriter(new StringWriter()), null);
    +-        });
    +-    }
    +-
    +-    /**
    +-     * Make sure the legacy file format that only supported a single intent per shortcut
    +-     * can still be read.
    +-     */
    +-    public void testLoadLegacySavedFile() throws Exception {
    +-        final File path = mService.getUserFile(USER_0);
    +-        path.getParentFile().mkdirs();
    +-        try (Writer w = new FileWriter(path)) {
    +-            w.write(readTestAsset("shortcut/shortcut_legacy_file.xml"));
    +-        };
    +-        initService();
    +-        mService.handleUnlockUser(USER_0);
    +-
    +-        runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
    +-            assertWith(getCallerShortcuts())
    +-                    .haveIds("manifest-shortcut-storage")
    +-                    .forShortcutWithId("manifest-shortcut-storage", si -> {
    +-                        assertEquals("android.settings.INTERNAL_STORAGE_SETTINGS",
    +-                                si.getIntent().getAction());
    +-                        assertEquals(12345, si.getIntent().getIntExtra("key", 0));
    +-                    });
    +-        });
    +-    }
    +-
    +-    public void testIsUserUnlocked() {
    +-        mRunningUsers.clear();
    +-        mUnlockedUsers.clear();
    +-
    +-        assertFalse(mService.isUserUnlockedL(USER_0));
    +-        assertFalse(mService.isUserUnlockedL(USER_10));
    +-
    +-        // Start user 0, still locked.
    +-        mRunningUsers.put(USER_0, true);
    +-        assertFalse(mService.isUserUnlockedL(USER_0));
    +-        assertFalse(mService.isUserUnlockedL(USER_10));
    +-
    +-        // Unlock user.
    +-        mUnlockedUsers.put(USER_0, true);
    +-        assertTrue(mService.isUserUnlockedL(USER_0));
    +-        assertFalse(mService.isUserUnlockedL(USER_10));
    +-
    +-        // Clear again.
    +-        mRunningUsers.clear();
    +-        mUnlockedUsers.clear();
    +-
    +-        // Directly call the lifecycle event.  Now also locked.
    +-        mService.handleUnlockUser(USER_0);
    +-        assertTrue(mService.isUserUnlockedL(USER_0));
    +-        assertFalse(mService.isUserUnlockedL(USER_10));
    +-
    +-        // Directly call the stop lifecycle event.  Goes back to the initial state.
    +-        mService.handleCleanupUser(USER_0);
    +-        assertFalse(mService.isUserUnlockedL(USER_0));
    +-        assertFalse(mService.isUserUnlockedL(USER_10));
    +-    }
    +-}
    +diff --git a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest3.java b/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest3.java
    +deleted file mode 100644
    +index eb4db7a..0000000
    +--- a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest3.java
    ++++ /dev/null
    +@@ -1,505 +0,0 @@
    +-/*
    +- * Copyright (C) 2016 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 com.android.server.pm;
    +-
    +-import static com.android.server.pm.shortcutmanagertest.ShortcutManagerTestUtils.assertWith;
    +-import static com.android.server.pm.shortcutmanagertest.ShortcutManagerTestUtils.list;
    +-
    +-import android.content.ComponentName;
    +-import android.content.pm.ShortcutInfo;
    +-import android.test.suitebuilder.annotation.SmallTest;
    +-
    +-import com.android.frameworks.servicestests.R;
    +-import com.android.server.pm.ShortcutService.ConfigConstants;
    +-
    +-/**
    +- * Tests related to shortcut rank auto-adjustment.
    +- */
    +-@SmallTest
    +-public class ShortcutManagerTest3 extends BaseShortcutManagerTest {
    +-
    +-    private static final String CALLING_PACKAGE = CALLING_PACKAGE_1;
    +-
    +-    private static final ComponentName A1 = new ComponentName(CALLING_PACKAGE,
    +-            ShortcutActivity.class.getName());
    +-
    +-    private static final ComponentName A2 = new ComponentName(CALLING_PACKAGE,
    +-            ShortcutActivity2.class.getName());
    +-
    +-    private static final ComponentName A3 = new ComponentName(CALLING_PACKAGE,
    +-            ShortcutActivity3.class.getName());
    +-
    +-    private ShortcutInfo shortcut(String id, ComponentName activity, int rank) {
    +-        return makeShortcutWithActivityAndRank(id, activity, rank);
    +-    }
    +-
    +-    private ShortcutInfo shortcut(String id, ComponentName activity) {
    +-        return makeShortcutWithActivityAndRank(id, activity, ShortcutInfo.RANK_NOT_SET);
    +-    }
    +-
    +-    @Override
    +-    protected void setUp() throws Exception {
    +-        super.setUp();
    +-
    +-        // We don't need throttling during this test class, and also relax the max cap.
    +-        mService.updateConfigurationLocked(
    +-                ConfigConstants.KEY_MAX_UPDATES_PER_INTERVAL + "=99999999,"
    +-                + ConfigConstants.KEY_MAX_SHORTCUTS + "=99999999"
    +-        );
    +-
    +-        setCaller(CALLING_PACKAGE, USER_0);
    +-    }
    +-
    +-    private void publishManifestShortcuts(ComponentName activity, int resId) {
    +-        addManifestShortcutResource(activity, resId);
    +-        updatePackageVersion(CALLING_PACKAGE, 1);
    +-        mService.mPackageMonitor.onReceive(getTestContext(),
    +-                genPackageAddIntent(CALLING_PACKAGE, USER_0));
    +-    }
    +-
    +-    public void testSetDynamicShortcuts_noManifestShortcuts() {
    +-        mManager.setDynamicShortcuts(list(
    +-                shortcut("s1", A1)
    +-        ));
    +-
    +-        assertWith(getCallerShortcuts()).selectDynamic().selectByActivity(A1)
    +-                .haveRanksInOrder("s1");
    +-
    +-        assertTrue(mManager.setDynamicShortcuts(list(
    +-                shortcut("s5", A1),
    +-                shortcut("s4", A1),
    +-                shortcut("s3", A1)
    +-        )));
    +-        assertWith(getCallerShortcuts()).selectDynamic().selectByActivity(A1)
    +-                .haveRanksInOrder("s5", "s4", "s3");
    +-
    +-        // RANK_NOT_SET is always the last.
    +-        assertTrue(mManager.setDynamicShortcuts(list(
    +-                shortcut("s5", A1),
    +-                shortcut("s4", A1, 5),
    +-                shortcut("s3", A1, 3),
    +-                shortcut("s2", A1)
    +-        )));
    +-        assertWith(getCallerShortcuts()).selectDynamic().selectByActivity(A1)
    +-                .haveRanksInOrder("s3", "s4", "s5", "s2");
    +-
    +-        // Same rank, preserve the argument order.
    +-        assertTrue(mManager.setDynamicShortcuts(list(
    +-                shortcut("s5", A1, 5),
    +-                shortcut("s4", A1, 0),
    +-                shortcut("s3", A1, 5)
    +-        )));
    +-        assertWith(getCallerShortcuts()).selectDynamic().selectByActivity(A1)
    +-                .haveRanksInOrder("s4", "s5", "s3");
    +-
    +-        // Multiple activities.
    +-        assertTrue(mManager.setDynamicShortcuts(list(
    +-                shortcut("s5", A1),
    +-                shortcut("s4", A2),
    +-                shortcut("s3", A3)
    +-        )));
    +-        assertWith(getCallerShortcuts()).selectDynamic().selectByActivity(A1)
    +-                .haveRanksInOrder("s5");
    +-        assertWith(getCallerShortcuts()).selectDynamic().selectByActivity(A2)
    +-                .haveRanksInOrder("s4");
    +-        assertWith(getCallerShortcuts()).selectDynamic().selectByActivity(A3)
    +-                .haveRanksInOrder("s3");
    +-
    +-        assertTrue(mManager.setDynamicShortcuts(list(
    +-                shortcut("s5", A1, 5),
    +-                shortcut("s4", A1),
    +-                shortcut("s3", A1, 5),
    +-                shortcut("x5", A2, 5),
    +-                shortcut("x4", A2),
    +-                shortcut("x3", A2, 1)
    +-        )));
    +-        assertWith(getCallerShortcuts()).selectDynamic().selectByActivity(A1)
    +-                .haveRanksInOrder("s5", "s3", "s4");
    +-        assertWith(getCallerShortcuts()).selectDynamic().selectByActivity(A2)
    +-                .haveRanksInOrder("x3", "x5", "x4");
    +-
    +-        // Clear.  Make sure it wouldn't lead to invalid internals state.
    +-        // (ShortcutService.verifyStates() will do so internally.)
    +-        assertTrue(mManager.setDynamicShortcuts(list()));
    +-        assertWith(getCallerShortcuts()).selectDynamic().selectByActivity(A1).isEmpty();
    +-        assertWith(getCallerShortcuts()).selectDynamic().selectByActivity(A2).isEmpty();
    +-    }
    +-
    +-    private void runTestWithManifestShortcuts(Runnable r) {
    +-        publishManifestShortcuts(A1, R.xml.shortcut_5_alt);
    +-        publishManifestShortcuts(A2, R.xml.shortcut_1);
    +-
    +-        assertWith(getCallerShortcuts()).selectManifest().selectByActivity(A1)
    +-                .haveRanksInOrder("ms1_alt", "ms2_alt", "ms3_alt", "ms4_alt", "ms5_alt");
    +-
    +-        assertWith(getCallerShortcuts()).selectManifest().selectByActivity(A2)
    +-                .haveRanksInOrder("ms1");
    +-
    +-        // Existence of manifest shortcuts shouldn't affect dynamic shortcut ranks,
    +-        // so running another test here should pass.
    +-        r.run();
    +-
    +-        // And dynamic shortcut tests shouldn't affect manifest shortcuts, so repeat the
    +-        // same check.
    +-        assertWith(getCallerShortcuts()).selectManifest().selectByActivity(A1)
    +-                .haveRanksInOrder("ms1_alt", "ms2_alt", "ms3_alt", "ms4_alt", "ms5_alt");
    +-
    +-        assertWith(getCallerShortcuts()).selectManifest().selectByActivity(A2)
    +-                .haveRanksInOrder("ms1");
    +-    }
    +-
    +-    public void testSetDynamicShortcuts_withManifestShortcuts() {
    +-        runTestWithManifestShortcuts(() -> testSetDynamicShortcuts_noManifestShortcuts());
    +-    }
    +-
    +-    public void testAddDynamicShortcuts_noManifestShortcuts() {
    +-        mManager.addDynamicShortcuts(list(
    +-                shortcut("s1", A1)
    +-        ));
    +-        assertWith(getCallerShortcuts()).selectDynamic().selectByActivity(A1)
    +-                .haveRanksInOrder("s1");
    +-
    +-        //------------------------------------------------------
    +-        long lastApiTime = ++mInjectedCurrentTimeMillis;
    +-
    +-        mManager.addDynamicShortcuts(list(
    +-                shortcut("s5", A1, 0),
    +-                shortcut("s4", A1),
    +-                shortcut("s2", A1, 3),
    +-                shortcut("x1", A2),
    +-                shortcut("x3", A2, 2),
    +-                shortcut("x2", A2, 2),
    +-                shortcut("s3", A1, 0)
    +-        ));
    +-        assertWith(getCallerShortcuts()).selectDynamic().selectByActivity(A1)
    +-                .haveRanksInOrder("s5", "s3", "s1", "s2", "s4");
    +-
    +-        assertWith(getCallerShortcuts()).selectDynamic().selectByActivity(A2)
    +-                .haveRanksInOrder("x3", "x2", "x1");
    +-
    +-        assertWith(getCallerShortcuts()).selectDynamic().selectByChangedSince(lastApiTime)
    +-                .haveIds("s5", "s3", "s1", "s2", "s4", "x3", "x2", "x1");
    +-
    +-        //------------------------------------------------------
    +-        lastApiTime = ++mInjectedCurrentTimeMillis;
    +-
    +-        mManager.addDynamicShortcuts(list(
    +-                shortcut("s1", A1, 1)
    +-        ));
    +-        assertWith(getCallerShortcuts()).selectDynamic().selectByActivity(A1)
    +-                .haveRanksInOrder("s5", "s1", "s3", "s2", "s4");
    +-
    +-        assertWith(getCallerShortcuts()).selectDynamic().selectByActivity(A2)
    +-                .haveRanksInOrder("x3", "x2", "x1");
    +-
    +-        assertWith(getCallerShortcuts()).selectDynamic().selectByChangedSince(lastApiTime)
    +-                .haveIds("s1", "s3");
    +-
    +-        //------------------------------------------------------
    +-        lastApiTime = ++mInjectedCurrentTimeMillis;
    +-
    +-        mManager.addDynamicShortcuts(list(
    +-                shortcut("s1", A1, 1),
    +-
    +-                // This is add, not update, so the following means s5 will have NO_RANK,
    +-                // which puts it at the end.
    +-                shortcut("s5", A1),
    +-                shortcut("s3", A1, 0),
    +-
    +-                // s10 also has NO_RANK, so it'll be put at the end, even after "s5" as we preserve
    +-                // the argument order.
    +-                shortcut("s10", A1),
    +-
    +-                // Note we're changing the activity for x2.
    +-                shortcut("x2", A1, 0),
    +-                shortcut("x10", A2)
    +-        ));
    +-        assertWith(getCallerShortcuts()).selectDynamic().selectByActivity(A1)
    +-                .haveRanksInOrder("s3", "x2", "s1", "s2", "s4", "s5", "s10");
    +-
    +-        assertWith(getCallerShortcuts()).selectDynamic().selectByActivity(A2)
    +-                .haveRanksInOrder("x3", "x1", "x10");
    +-
    +-        assertWith(getCallerShortcuts()).selectDynamic().selectByChangedSince(lastApiTime)
    +-                .haveIds("s3", "x2", "s1", "s5", "s10", "x1", "x10");
    +-
    +-        //------------------------------------------------------
    +-        lastApiTime = ++mInjectedCurrentTimeMillis;
    +-
    +-        // Change the activities again.
    +-        mManager.addDynamicShortcuts(list(
    +-                shortcut("s1", A2),
    +-                shortcut("s2", A2, 999)
    +-        ));
    +-        assertWith(getCallerShortcuts()).selectDynamic().selectByActivity(A1)
    +-                .haveRanksInOrder("s3", "x2", "s4", "s5", "s10");
    +-
    +-        assertWith(getCallerShortcuts()).selectDynamic().selectByActivity(A2)
    +-                .haveRanksInOrder("x3", "x1", "x10", "s2", "s1");
    +-
    +-        assertWith(getCallerShortcuts()).selectDynamic().selectByChangedSince(lastApiTime)
    +-                .haveIds("s1", "s2", "s4", "s5", "s10");
    +-    }
    +-
    +-    public void testAddDynamicShortcuts_withManifestShortcuts() {
    +-        runTestWithManifestShortcuts(() -> testAddDynamicShortcuts_noManifestShortcuts());
    +-    }
    +-
    +-    public void testUpdateShortcuts_noManifestShortcuts() {
    +-        mManager.addDynamicShortcuts(list(
    +-                shortcut("s5", A1, 0),
    +-                shortcut("s4", A1),
    +-                shortcut("s2", A1, 3),
    +-                shortcut("x1", A2),
    +-                shortcut("x3", A2, 2),
    +-                shortcut("x2", A2, 2),
    +-                shortcut("s3", A1, 0)
    +-        ));
    +-        assertWith(getCallerShortcuts()).selectDynamic().selectByActivity(A1)
    +-                .haveRanksInOrder("s5", "s3", "s2", "s4");
    +-
    +-        assertWith(getCallerShortcuts()).selectDynamic().selectByActivity(A2)
    +-                .haveRanksInOrder("x3", "x2", "x1");
    +-
    +-        //------------------------------------------------------
    +-        long lastApiTime = ++mInjectedCurrentTimeMillis;
    +-
    +-        mManager.updateShortcuts(list());
    +-        // Same order.
    +-        assertWith(getCallerShortcuts()).selectDynamic().selectByActivity(A1)
    +-                .haveRanksInOrder("s5", "s3", "s2", "s4");
    +-
    +-        assertWith(getCallerShortcuts()).selectDynamic().selectByActivity(A2)
    +-                .haveRanksInOrder("x3", "x2", "x1");
    +-
    +-        assertWith(getCallerShortcuts()).selectDynamic().selectByChangedSince(lastApiTime)
    +-                .isEmpty();
    +-
    +-
    +-        runWithCaller(LAUNCHER_1, USER_0, () -> {
    +-            mLauncherApps.pinShortcuts(CALLING_PACKAGE, list("s2", "s4", "x2"), HANDLE_USER_0);
    +-        });
    +-        // Still same order.
    +-        assertWith(getCallerShortcuts()).selectDynamic().selectByActivity(A1)
    +-                .haveRanksInOrder("s5", "s3", "s2", "s4");
    +-
    +-        assertWith(getCallerShortcuts()).selectDynamic().selectByActivity(A2)
    +-                .haveRanksInOrder("x3", "x2", "x1");
    +-
    +-        //------------------------------------------------------
    +-        lastApiTime = ++mInjectedCurrentTimeMillis;
    +-
    +-        mManager.updateShortcuts(list(
    +-                shortcut("s4", A1, 1),
    +-
    +-                // Rank not changing, should keep the same positions.
    +-                // c.f. in case of addDynamicShortcuts, this means "put them at the end".
    +-                shortcut("s3", A1),
    +-                shortcut("x2", A2)
    +-        ));
    +-        assertWith(getCallerShortcuts()).selectDynamic().selectByActivity(A1)
    +-                .haveRanksInOrder("s5", "s4", "s3", "s2");
    +-
    +-        assertWith(getCallerShortcuts()).selectDynamic().selectByActivity(A2)
    +-                .haveRanksInOrder("x3", "x2", "x1");
    +-
    +-        assertWith(getCallerShortcuts()).selectDynamic().selectByChangedSince(lastApiTime)
    +-                .haveIds("s4", "s3", "s2", "x2");
    +-
    +-        //------------------------------------------------------
    +-        lastApiTime = ++mInjectedCurrentTimeMillis;
    +-
    +-        mManager.updateShortcuts(list(
    +-                shortcut("s4", A1, 0),
    +-
    +-                // Change the activity without specifying a rank -> keep the same rank.
    +-                shortcut("s5", A2),
    +-
    +-                // Change the activity without specifying a rank -> assign a new rank.
    +-                shortcut("x2", A1, 2),
    +-
    +-                // "xx" doesn't exist, so it'll be ignored.
    +-                shortcut("xx", A1, 0)
    +-        ));
    +-        assertWith(getCallerShortcuts()).selectDynamic().selectByActivity(A1)
    +-                .haveRanksInOrder("s4", "x2", "s3", "s2");
    +-
    +-        // Interesting case: both x3 and s5 originally had rank=0, and in this case s5 has moved
    +-        // to A2 without changing the rank.  So they're tie for the new rank, as well as
    +-        // the "rank changed" bit.  Also in this case, "s5" won't have an implicit order, since
    +-        // its rank isn't changing.  So we sort them by ID, thus s5 comes before x3.
    +-        assertWith(getCallerShortcuts()).selectDynamic().selectByActivity(A2)
    +-                .haveRanksInOrder("s5", "x3", "x1");
    +-
    +-        assertWith(getCallerShortcuts()).selectDynamic().selectByChangedSince(lastApiTime)
    +-                .haveIds("s4", "x2", "s5", "x3");
    +-
    +-        //------------------------------------------------------
    +-        lastApiTime = ++mInjectedCurrentTimeMillis;
    +-
    +-        mManager.updateShortcuts(list(
    +-                shortcut("s3", A3)));
    +-
    +-        assertWith(getCallerShortcuts()).selectDynamic().selectByActivity(A1)
    +-                .haveRanksInOrder("s4", "x2", "s2");
    +-        assertWith(getCallerShortcuts()).selectDynamic().selectByActivity(A2)
    +-                .haveRanksInOrder("s5", "x3", "x1");
    +-        assertWith(getCallerShortcuts()).selectDynamic().selectByActivity(A3)
    +-                .haveRanksInOrder("s3");
    +-
    +-        assertWith(getCallerShortcuts()).selectDynamic().selectByChangedSince(lastApiTime)
    +-                .haveIds("s3", "s2");
    +-    }
    +-
    +-    public void testUpdateShortcuts_withManifestShortcuts() {
    +-        runTestWithManifestShortcuts(() -> testUpdateShortcuts_noManifestShortcuts());
    +-    }
    +-
    +-    public void testDeleteDynamicShortcuts_noManifestShortcuts() {
    +-        mManager.addDynamicShortcuts(list(
    +-                shortcut("s5", A1, 0),
    +-                shortcut("s4", A1),
    +-                shortcut("s2", A1, 3),
    +-                shortcut("x1", A2),
    +-                shortcut("x3", A2, 2),
    +-                shortcut("x2", A2, 2),
    +-                shortcut("s3", A1, 0)
    +-        ));
    +-        assertWith(getCallerShortcuts()).selectDynamic().selectByActivity(A1)
    +-                .haveRanksInOrder("s5", "s3", "s2", "s4");
    +-
    +-        assertWith(getCallerShortcuts()).selectDynamic().selectByActivity(A2)
    +-                .haveRanksInOrder("x3", "x2", "x1");
    +-
    +-        //------------------------------------------------------
    +-        long lastApiTime = ++mInjectedCurrentTimeMillis;
    +-
    +-        mManager.removeDynamicShortcuts(list());
    +-
    +-        assertWith(getCallerShortcuts()).selectDynamic().selectByActivity(A1)
    +-                .haveRanksInOrder("s5", "s3", "s2", "s4");
    +-
    +-        assertWith(getCallerShortcuts()).selectDynamic().selectByActivity(A2)
    +-                .haveRanksInOrder("x3", "x2", "x1");
    +-
    +-        assertWith(getCallerShortcuts()).selectDynamic().selectByChangedSince(lastApiTime)
    +-                .isEmpty();
    +-
    +-        runWithCaller(LAUNCHER_1, USER_0, () -> {
    +-            mLauncherApps.pinShortcuts(
    +-                    CALLING_PACKAGE, list("s2", "s4", "x1", "x2"), HANDLE_USER_0);
    +-        });
    +-        // Still same order.
    +-
    +-        assertWith(getCallerShortcuts()).selectDynamic().selectByActivity(A1)
    +-                .haveRanksInOrder("s5", "s3", "s2", "s4");
    +-
    +-        assertWith(getCallerShortcuts()).selectDynamic().selectByActivity(A2)
    +-                .haveRanksInOrder("x3", "x2", "x1");
    +-
    +-        //------------------------------------------------------
    +-        lastApiTime = ++mInjectedCurrentTimeMillis;
    +-
    +-        mManager.removeDynamicShortcuts(list("s3", "x1", "xxxx"));
    +-
    +-        assertWith(getCallerShortcuts()).selectDynamic().selectByActivity(A1)
    +-                .haveRanksInOrder("s5", "s2", "s4");
    +-
    +-        assertWith(getCallerShortcuts()).selectDynamic().selectByActivity(A2)
    +-                .haveRanksInOrder("x3", "x2");
    +-
    +-        assertWith(getCallerShortcuts()).selectDynamic().selectByChangedSince(lastApiTime)
    +-                .haveIds("s2", "s4");
    +-    }
    +-
    +-    public void testDeleteDynamicShortcuts_withManifestShortcuts() {
    +-        runTestWithManifestShortcuts(() -> testDeleteDynamicShortcuts_noManifestShortcuts());
    +-    }
    +-
    +-    public void testDisableShortcuts_noManifestShortcuts() {
    +-        mManager.addDynamicShortcuts(list(
    +-                shortcut("s5", A1, 0),
    +-                shortcut("s4", A1),
    +-                shortcut("s2", A1, 3),
    +-                shortcut("x1", A2),
    +-                shortcut("x3", A2, 2),
    +-                shortcut("x2", A2, 2),
    +-                shortcut("s3", A1, 0)
    +-        ));
    +-        assertWith(getCallerShortcuts()).selectDynamic().selectByActivity(A1)
    +-                .haveRanksInOrder("s5", "s3", "s2", "s4");
    +-
    +-        assertWith(getCallerShortcuts()).selectDynamic().selectByActivity(A2)
    +-                .haveRanksInOrder("x3", "x2", "x1");
    +-
    +-        //------------------------------------------------------
    +-        long lastApiTime = ++mInjectedCurrentTimeMillis;
    +-
    +-        mManager.disableShortcuts(list());
    +-
    +-        assertWith(getCallerShortcuts()).selectDynamic().selectByActivity(A1)
    +-                .haveRanksInOrder("s5", "s3", "s2", "s4");
    +-
    +-        assertWith(getCallerShortcuts()).selectDynamic().selectByActivity(A2)
    +-                .haveRanksInOrder("x3", "x2", "x1");
    +-
    +-        assertWith(getCallerShortcuts()).selectDynamic().selectByChangedSince(lastApiTime)
    +-                .isEmpty();
    +-
    +-        //------------------------------------------------------
    +-        lastApiTime = ++mInjectedCurrentTimeMillis;
    +-
    +-        mManager.disableShortcuts(list("s3", "x1", "xxxx"));
    +-
    +-        assertWith(getCallerShortcuts()).selectDynamic().selectByActivity(A1)
    +-                .haveRanksInOrder("s5", "s2", "s4");
    +-
    +-        assertWith(getCallerShortcuts()).selectDynamic().selectByActivity(A2)
    +-                .haveRanksInOrder("x3", "x2");
    +-
    +-        assertWith(getCallerShortcuts()).selectDynamic().selectByChangedSince(lastApiTime)
    +-                .haveIds("s2", "s4");
    +-
    +-        runWithCaller(LAUNCHER_1, USER_0, () -> {
    +-            mLauncherApps.pinShortcuts(CALLING_PACKAGE, list("s2", "s4", "x2"), HANDLE_USER_0);
    +-        });
    +-        // Still same order.
    +-        assertWith(getCallerShortcuts()).selectDynamic().selectByActivity(A1)
    +-                .haveRanksInOrder("s5", "s2", "s4");
    +-
    +-        assertWith(getCallerShortcuts()).selectDynamic().selectByActivity(A2)
    +-                .haveRanksInOrder("x3", "x2");
    +-
    +-        //------------------------------------------------------
    +-        lastApiTime = ++mInjectedCurrentTimeMillis;
    +-
    +-        mManager.disableShortcuts(list("s2", "x3"));
    +-
    +-        assertWith(getCallerShortcuts()).selectDynamic().selectByActivity(A1)
    +-                .haveRanksInOrder("s5", "s4");
    +-
    +-        assertWith(getCallerShortcuts()).selectDynamic().selectByActivity(A2)
    +-                .haveRanksInOrder("x2");
    +-
    +-        assertWith(getCallerShortcuts()).selectDynamic().selectByChangedSince(lastApiTime)
    +-                .haveIds("s4", "x2");
    +-    }
    +-
    +-    public void testDisableShortcuts_withManifestShortcuts() {
    +-        runTestWithManifestShortcuts(() -> testDisableShortcuts_noManifestShortcuts());
    +-    }
    +-
    +-}
    +diff --git a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest4.java b/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest4.java
    +deleted file mode 100644
    +index 583c3d4..0000000
    +--- a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest4.java
    ++++ /dev/null
    +@@ -1,126 +0,0 @@
    +-/*
    +- * Copyright (C) 2016 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 com.android.server.pm;
    +-
    +-import static com.android.server.pm.shortcutmanagertest.ShortcutManagerTestUtils.assertBundlesEqual;
    +-import static com.android.server.pm.shortcutmanagertest.ShortcutManagerTestUtils.assertWith;
    +-import static com.android.server.pm.shortcutmanagertest.ShortcutManagerTestUtils.list;
    +-import static com.android.server.pm.shortcutmanagertest.ShortcutManagerTestUtils.makeBundle;
    +-import static com.android.server.pm.shortcutmanagertest.ShortcutManagerTestUtils.makePersistableBundle;
    +-
    +-import android.content.Intent;
    +-import android.os.Bundle;
    +-import android.os.PersistableBundle;
    +-import android.test.suitebuilder.annotation.SmallTest;
    +-
    +-@SmallTest
    +-public class ShortcutManagerTest4 extends BaseShortcutManagerTest {
    +-
    +-    private static Bundle sIntentExtras = makeBundle(
    +-            "key{\u0000}", "value{\u0000}",
    +-            "key{\u0001}", "value{\u0001}",
    +-            "key{\u001f}", "value{\u001f}",
    +-            "key{\u007f}", "value{\u007f}",
    +-
    +-            "key{\ud800\udc00}", "value{\ud800\udc00}",
    +-            "key{\ud801\udc01}", "value{\ud801\udc01}",
    +-            "key{\udbff\udfff}", "value{\udbff\udfff}",
    +-
    +-            "key{\ud801}x", 1, // broken surrogate pair
    +-            "key{\uDC01}\"x", 2, // broken surrogate pair
    +-
    +-            "x1", "value{\ud801}x", // broken surrogate pair
    +-            "x2", "value{\uDC01}\"x" // broken surrogate pair
    +-    );
    +-
    +-    // Same as above, except broken surrogate pairs are replaced with '?'s.
    +-    private static Bundle sIntentExtrasDecoded = makeBundle(
    +-            "key{\u0000}", "value{\u0000}",
    +-            "key{\u0001}", "value{\u0001}",
    +-            "key{\u001f}", "value{\u001f}",
    +-            "key{\u007f}", "value{\u007f}",
    +-
    +-            "key{\ud800\udc00}", "value{\ud800\udc00}",
    +-            "key{\ud801\udc01}", "value{\ud801\udc01}",
    +-            "key{\udbff\udfff}", "value{\udbff\udfff}",
    +-
    +-            "key{?}x", 1,
    +-            "key{?}\"x", 2,
    +-
    +-            "x1", "value{?}x",
    +-            "x2", "value{?}\"x"
    +-    );
    +-
    +-    private static PersistableBundle sShortcutExtras = makePersistableBundle(
    +-            "key{\u0000}", "value{\u0000}",
    +-            "key{\u0001}", "value{\u0001}",
    +-            "key{\u001f}", "value{\u001f}",
    +-            "key{\u007f}", "value{\u007f}",
    +-
    +-            "key{\ud800\udc00}", "value{\ud800\udc00}",
    +-            "key{\ud801\udc01}", "value{\ud801\udc01}",
    +-            "key{\udbff\udfff}", "value{\udbff\udfff}",
    +-
    +-            "key{\ud801}", 1, // broken surrogate pair
    +-            "key{\uDC01}", 2, // broken surrogate pair
    +-
    +-            "x1", "value{\ud801}", // broken surrogate pair
    +-            "x2", "value{\uDC01}" // broken surrogate pair
    +-    );
    +-
    +-    // Same as above, except broken surrogate pairs are replaced with '?'s.
    +-    private static PersistableBundle sShortcutExtrasDecoded = makePersistableBundle(
    +-            "key{\u0000}", "value{\u0000}",
    +-            "key{\u0001}", "value{\u0001}",
    +-            "key{\u001f}", "value{\u001f}",
    +-            "key{\u007f}", "value{\u007f}",
    +-
    +-            "key{\ud800\udc00}", "value{\ud800\udc00}",
    +-            "key{\ud801\udc01}", "value{\ud801\udc01}",
    +-            "key{\udbff\udfff}", "value{\udbff\udfff}",
    +-
    +-            "key{?}", 1,
    +-            "key{?}", 2,
    +-
    +-            "x1", "value{?}",
    +-            "x2", "value{?}"
    +-    );
    +-
    +-    public void testPersistingWeirdCharacters() {
    +-        final Intent intent = new Intent(Intent.ACTION_MAIN)
    +-                .putExtras(sIntentExtras);
    +-
    +-        runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
    +-            assertTrue(mManager.setDynamicShortcuts(list(
    +-                    makeShortcutWithExtras("s1", intent, sShortcutExtras),
    +-                    makeShortcut("s{\u0000}{\u0001}{\uD800\uDC00}x[\uD801][\uDC01]")
    +-            )));
    +-        });
    +-
    +-        // Make sure save & load works fine. (i.e. shouldn't crash even with invalid characters.)
    +-        initService();
    +-        mService.handleUnlockUser(USER_0);
    +-
    +-        runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
    +-            assertWith(getCallerShortcuts())
    +-                    .haveIds("s1", "s{\u0000}{\u0001}{\uD800\uDC00}x[?][?]")
    +-                    .forShortcutWithId("s1", si -> {
    +-                        assertBundlesEqual(si.getIntent().getExtras(), sIntentExtrasDecoded);
    +-                        assertBundlesEqual(si.getExtras(), sShortcutExtrasDecoded);
    +-                    });
    +-        });
    +-    }
    +-}
    +\ No newline at end of file
    +diff --git a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest5.java b/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest5.java
    +deleted file mode 100644
    +index 29c98dc..0000000
    +--- a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest5.java
    ++++ /dev/null
    +@@ -1,202 +0,0 @@
    +-/*
    +- * Copyright (C) 2016 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 com.android.server.pm;
    +-
    +-import static com.android.server.pm.shortcutmanagertest.ShortcutManagerTestUtils.set;
    +-
    +-import android.app.Activity;
    +-import android.content.ComponentName;
    +-import android.content.pm.ActivityInfo;
    +-import android.content.pm.ApplicationInfo;
    +-import android.content.pm.PackageInfo;
    +-import android.content.pm.ShortcutServiceInternal;
    +-import android.content.res.XmlResourceParser;
    +-import android.os.Looper;
    +-import android.test.suitebuilder.annotation.SmallTest;
    +-
    +-import com.android.server.LocalServices;
    +-
    +-import java.util.List;
    +-import java.util.Set;
    +-
    +-/**
    +- * Unit tests for all the IPackageManager related methods in {@link ShortcutService}.
    +- *
    +- * All the tests here actually talks to the real IPackageManager, so we can't test complicated
    +- * cases.  Instead we just make sure they all work reasonably without at least crashing.
    +- */
    +-@SmallTest
    +-public class ShortcutManagerTest5 extends BaseShortcutManagerTest {
    +-    private ShortcutService mShortcutService;
    +-
    +-    private String mMyPackage;
    +-    private int mMyUserId;
    +-
    +-    public static class ShortcutEnabled extends Activity {
    +-    }
    +-
    +-    public static class ShortcutDisabled extends Activity {
    +-    }
    +-
    +-    @Override
    +-    protected void setUp() throws Exception {
    +-        super.setUp();
    +-
    +-        LocalServices.removeServiceForTest(ShortcutServiceInternal.class);
    +-        mShortcutService = new ShortcutService(getTestContext(), Looper.getMainLooper(),
    +-                /* onyForPackageManagerApis */ true);
    +-
    +-        mMyPackage = getTestContext().getPackageName();
    +-        mMyUserId = android.os.Process.myUserHandle().getIdentifier();
    +-    }
    +-
    +-    public void testGetPackageUid() {
    +-        assertTrue(mShortcutService.injectGetPackageUid(
    +-                mMyPackage, mMyUserId) != 0);
    +-
    +-        assertEquals(-1, mShortcutService.injectGetPackageUid(
    +-                "no.such.package", mMyUserId));
    +-    }
    +-
    +-    public void testGetPackageInfo() {
    +-        PackageInfo pi = mShortcutService.getPackageInfo(
    +-                mMyPackage, mMyUserId, /*signature*/ false);
    +-        assertEquals(mMyPackage, pi.packageName);
    +-        assertNull(pi.signatures);
    +-
    +-        pi = mShortcutService.getPackageInfo(
    +-                mMyPackage, mMyUserId, /*signature*/ true);
    +-        assertEquals(mMyPackage, pi.packageName);
    +-        assertNotNull(pi.signatures);
    +-
    +-        pi = mShortcutService.getPackageInfo(
    +-                "no.such.package", mMyUserId, /*signature*/ true);
    +-        assertNull(pi);
    +-    }
    +-
    +-    public void testGetApplicationInfo() {
    +-        ApplicationInfo ai = mShortcutService.getApplicationInfo(
    +-                mMyPackage, mMyUserId);
    +-        assertEquals(mMyPackage, ai.packageName);
    +-
    +-        ai = mShortcutService.getApplicationInfo(
    +-                "no.such.package", mMyUserId);
    +-        assertNull(ai);
    +-    }
    +-
    +-    public void testGetActivityInfoWithMetadata() {
    +-        // Disabled activity
    +-        ActivityInfo ai = mShortcutService.getActivityInfoWithMetadata(
    +-                new ComponentName(mMyPackage, "ShortcutDisabled"), mMyUserId);
    +-        assertNull(ai);
    +-
    +-        // Nonexistent
    +-        ai = mShortcutService.getActivityInfoWithMetadata(
    +-                new ComponentName("no.such.package", "ShortcutDisabled"), mMyUserId);
    +-        assertNull(ai);
    +-
    +-        // Existent, with no metadata.
    +-        ai = mShortcutService.getActivityInfoWithMetadata(
    +-                new ComponentName(mMyPackage, "a.ShortcutEnabled"), mMyUserId);
    +-        assertEquals(mMyPackage, ai.packageName);
    +-        assertEquals("a.ShortcutEnabled", ai.name);
    +-        assertNull(ai.loadXmlMetaData(getTestContext().getPackageManager(),
    +-                "android.app.shortcuts"));
    +-
    +-        // Existent, with a shortcut metadata.
    +-        ai = mShortcutService.getActivityInfoWithMetadata(
    +-                new ComponentName(mMyPackage, "a.Shortcut1"), mMyUserId);
    +-        assertEquals(mMyPackage, ai.packageName);
    +-        assertEquals("a.Shortcut1", ai.name);
    +-        XmlResourceParser meta = ai.loadXmlMetaData(getTestContext().getPackageManager(),
    +-                "android.app.shortcuts");
    +-        assertNotNull(meta);
    +-        meta.close();
    +-    }
    +-
    +-    public void testGetInstalledPackages() {
    +-        List<PackageInfo> apks = mShortcutService.getInstalledPackages(mMyUserId);
    +-
    +-        Set<String> expectedPackages = set("com.android.settings", mMyPackage);
    +-        for (PackageInfo pi : apks) {
    +-            expectedPackages.remove(pi.packageName);
    +-        }
    +-        assertEquals(set(), expectedPackages);
    +-    }
    +-
    +-    public void testGetDefaultMainActivity() {
    +-        ComponentName cn = mShortcutService.injectGetDefaultMainActivity(
    +-                "com.android.settings", mMyUserId);
    +-
    +-        assertEquals(
    +-                ComponentName.unflattenFromString("com.android.settings/.Settings"),
    +-                cn);
    +-
    +-        // This package has no main activity.
    +-        assertNull(mShortcutService.injectGetDefaultMainActivity(
    +-                mMyPackage, mMyUserId));
    +-
    +-        // Nonexistent.
    +-        assertNull(mShortcutService.injectGetDefaultMainActivity(
    +-                "no.such.package", mMyUserId));
    +-    }
    +-
    +-    public void testIsMainActivity() {
    +-        assertTrue(mShortcutService.injectIsMainActivity(
    +-                ComponentName.unflattenFromString("com.android.settings/.Settings"), mMyUserId));
    +-        assertFalse(mShortcutService.injectIsMainActivity(
    +-                ComponentName.unflattenFromString("com.android.settings/.xxx"), mMyUserId));
    +-        assertFalse(mShortcutService.injectIsMainActivity(
    +-                ComponentName.unflattenFromString("no.such.package/.xxx"), mMyUserId));
    +-
    +-        assertFalse(mShortcutService.injectIsMainActivity(
    +-                new ComponentName(mMyPackage, "a.DisabledMain"), mMyUserId));
    +-        assertFalse(mShortcutService.injectIsMainActivity(
    +-                new ComponentName(mMyPackage, "a.UnexportedMain"), mMyUserId));
    +-
    +-    }
    +-
    +-    public void testGetMainActivities() {
    +-        assertEquals(1, mShortcutService.injectGetMainActivities(
    +-                "com.android.settings", mMyUserId).size());
    +-
    +-        // This APK has no main activities.
    +-        assertEquals(0, mShortcutService.injectGetMainActivities(
    +-                mMyPackage, mMyUserId).size());
    +-    }
    +-
    +-    public void testIsActivityEnabledAndExported() {
    +-        assertTrue(mShortcutService.injectIsActivityEnabledAndExported(
    +-                ComponentName.unflattenFromString("com.android.settings/.Settings"), mMyUserId));
    +-        assertFalse(mShortcutService.injectIsActivityEnabledAndExported(
    +-                ComponentName.unflattenFromString("com.android.settings/.xxx"), mMyUserId));
    +-        assertFalse(mShortcutService.injectIsActivityEnabledAndExported(
    +-                ComponentName.unflattenFromString("no.such.package/.xxx"), mMyUserId));
    +-
    +-        assertTrue(mShortcutService.injectIsActivityEnabledAndExported(
    +-                new ComponentName(mMyPackage, "com.android.server.pm.ShortcutTestActivity"),
    +-                mMyUserId));
    +-
    +-        assertTrue(mShortcutService.injectIsActivityEnabledAndExported(
    +-                new ComponentName(mMyPackage, "a.ShortcutEnabled"), mMyUserId));
    +-
    +-        assertFalse(mShortcutService.injectIsActivityEnabledAndExported(
    +-                new ComponentName(mMyPackage, "a.ShortcutDisabled"), mMyUserId));
    +-        assertFalse(mShortcutService.injectIsActivityEnabledAndExported(
    +-                new ComponentName(mMyPackage, "a.ShortcutUnexported"), mMyUserId));
    +-
    +-    }
    +-}
    +diff --git a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest6.java b/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest6.java
    +deleted file mode 100644
    +index ba4dbc1..0000000
    +--- a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest6.java
    ++++ /dev/null
    +@@ -1,281 +0,0 @@
    +-/*
    +- * Copyright (C) 2016 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 com.android.server.pm;
    +-
    +-import static com.android.server.pm.shortcutmanagertest.ShortcutManagerTestUtils.list;
    +-
    +-import static org.mockito.Matchers.any;
    +-import static org.mockito.Matchers.eq;
    +-import static org.mockito.Mockito.doAnswer;
    +-
    +-import android.content.ComponentName;
    +-import android.content.Intent;
    +-import android.content.pm.ActivityInfo;
    +-import android.content.pm.ApplicationInfo;
    +-import android.content.pm.ResolveInfo;
    +-import android.test.suitebuilder.annotation.SmallTest;
    +-
    +-import java.util.List;
    +-
    +-/**
    +- * Tests for {@link ShortcutService#hasShortcutHostPermissionInner}.
    +- */
    +-@SmallTest
    +-public class ShortcutManagerTest6 extends BaseShortcutManagerTest {
    +-    public void testHasShortcutHostPermissionInner_systemLauncherOnly() {
    +-        // Preferred isn't set, use the system launcher.
    +-        prepareGetHomeActivitiesAsUser(
    +-                /* preferred */ null,
    +-                list(getSystemLauncher(), getFallbackLauncher()),
    +-                USER_0);
    +-        assertTrue(mService.hasShortcutHostPermissionInner(PACKAGE_SYSTEM_LAUNCHER, USER_0));
    +-        assertFalse(mService.hasShortcutHostPermissionInner(PACKAGE_FALLBACK_LAUNCHER, USER_0));
    +-        assertFalse(mService.hasShortcutHostPermissionInner(CALLING_PACKAGE_1, USER_0));
    +-        assertFalse(mService.hasShortcutHostPermissionInner(CALLING_PACKAGE_2, USER_0));
    +-
    +-        // Should be cached.
    +-        assertEquals(cn(PACKAGE_SYSTEM_LAUNCHER, PACKAGE_SYSTEM_LAUNCHER_NAME),
    +-                mService.getUserShortcutsLocked(USER_0).getLastKnownLauncher());
    +-        assertEquals(cn(PACKAGE_SYSTEM_LAUNCHER, PACKAGE_SYSTEM_LAUNCHER_NAME),
    +-                mService.getUserShortcutsLocked(USER_0).getCachedLauncher());
    +-
    +-        // Also make sure the last known is saved, but the cached is not.
    +-
    +-        initService();
    +-
    +-        assertEquals(cn(PACKAGE_SYSTEM_LAUNCHER, PACKAGE_SYSTEM_LAUNCHER_NAME),
    +-                mService.getUserShortcutsLocked(USER_0).getLastKnownLauncher());
    +-        assertEquals(null,
    +-                mService.getUserShortcutsLocked(USER_0).getCachedLauncher());
    +-    }
    +-
    +-    public void testHasShortcutHostPermissionInner_with3pLauncher() {
    +-        // Preferred isn't set, still use the system launcher.
    +-        prepareGetHomeActivitiesAsUser(
    +-                /* preferred */ null,
    +-                list(getSystemLauncher(), getFallbackLauncher(),
    +-                        ri(CALLING_PACKAGE_1, "name", false, 0),
    +-                        ri(CALLING_PACKAGE_2, "name", false, 0)
    +-                ),
    +-                USER_0);
    +-        assertTrue(mService.hasShortcutHostPermissionInner(PACKAGE_SYSTEM_LAUNCHER, USER_0));
    +-        assertFalse(mService.hasShortcutHostPermissionInner(PACKAGE_FALLBACK_LAUNCHER, USER_0));
    +-        assertFalse(mService.hasShortcutHostPermissionInner(CALLING_PACKAGE_1, USER_0));
    +-        assertFalse(mService.hasShortcutHostPermissionInner(CALLING_PACKAGE_2, USER_0));
    +-
    +-        // Should be cached.
    +-        assertEquals(cn(PACKAGE_SYSTEM_LAUNCHER, PACKAGE_SYSTEM_LAUNCHER_NAME),
    +-                mService.getUserShortcutsLocked(USER_0).getLastKnownLauncher());
    +-        assertEquals(cn(PACKAGE_SYSTEM_LAUNCHER, PACKAGE_SYSTEM_LAUNCHER_NAME),
    +-                mService.getUserShortcutsLocked(USER_0).getCachedLauncher());
    +-    }
    +-
    +-    public void testHasShortcutHostPermissionInner_with3pLauncher_complicated() {
    +-        // Preferred is set.  That's the default launcher.
    +-        prepareGetHomeActivitiesAsUser(
    +-                /* preferred */ cn(CALLING_PACKAGE_2, "name"),
    +-                list(getSystemLauncher(), getFallbackLauncher(),
    +-                        ri(CALLING_PACKAGE_1, "name", false, 0),
    +-                        ri(CALLING_PACKAGE_2, "name", false, 0)
    +-                ),
    +-                USER_0);
    +-        assertFalse(mService.hasShortcutHostPermissionInner(PACKAGE_SYSTEM_LAUNCHER, USER_0));
    +-        assertFalse(mService.hasShortcutHostPermissionInner(PACKAGE_FALLBACK_LAUNCHER, USER_0));
    +-        assertFalse(mService.hasShortcutHostPermissionInner(CALLING_PACKAGE_1, USER_0));
    +-        assertTrue(mService.hasShortcutHostPermissionInner(CALLING_PACKAGE_2, USER_0));
    +-
    +-        // Should be cached.
    +-        assertEquals(cn(CALLING_PACKAGE_2, "name"),
    +-                mService.getUserShortcutsLocked(USER_0).getLastKnownLauncher());
    +-        assertEquals(cn(CALLING_PACKAGE_2, "name"),
    +-                mService.getUserShortcutsLocked(USER_0).getCachedLauncher());
    +-
    +-
    +-        // Once set, even after the preferred launcher is cleared, SM still allows it to access
    +-        // shortcuts.
    +-        prepareGetHomeActivitiesAsUser(
    +-                /* preferred */ null,
    +-                list(getSystemLauncher(), getFallbackLauncher(),
    +-                        ri(CALLING_PACKAGE_1, "name", false, 0),
    +-                        ri(CALLING_PACKAGE_2, "name", false, 0)
    +-                ),
    +-                USER_0);
    +-
    +-        assertFalse(mService.hasShortcutHostPermissionInner(PACKAGE_SYSTEM_LAUNCHER, USER_0));
    +-        assertFalse(mService.hasShortcutHostPermissionInner(PACKAGE_FALLBACK_LAUNCHER, USER_0));
    +-        assertFalse(mService.hasShortcutHostPermissionInner(CALLING_PACKAGE_1, USER_0));
    +-        assertTrue(mService.hasShortcutHostPermissionInner(CALLING_PACKAGE_2, USER_0));
    +-
    +-        // Should be cached.
    +-        assertEquals(cn(CALLING_PACKAGE_2, "name"),
    +-                mService.getUserShortcutsLocked(USER_0).getLastKnownLauncher());
    +-        assertEquals(cn(CALLING_PACKAGE_2, "name"),
    +-                mService.getUserShortcutsLocked(USER_0).getCachedLauncher());
    +-
    +-        // However, if the component has been disabled, then we'll recalculate it.
    +-        mEnabledActivityChecker = (comp, user) -> false;
    +-
    +-        assertTrue(mService.hasShortcutHostPermissionInner(PACKAGE_SYSTEM_LAUNCHER, USER_0));
    +-        assertFalse(mService.hasShortcutHostPermissionInner(PACKAGE_FALLBACK_LAUNCHER, USER_0));
    +-        assertFalse(mService.hasShortcutHostPermissionInner(CALLING_PACKAGE_1, USER_0));
    +-        assertFalse(mService.hasShortcutHostPermissionInner(CALLING_PACKAGE_2, USER_0));
    +-
    +-        mEnabledActivityChecker = (comp, user) -> true;
    +-
    +-        // Now the preferred changed.
    +-        prepareGetHomeActivitiesAsUser(
    +-                /* preferred */ cn(CALLING_PACKAGE_1, "xyz"),
    +-                list(getSystemLauncher(), getFallbackLauncher(),
    +-                        ri(CALLING_PACKAGE_1, "name", false, 0),
    +-                        ri(CALLING_PACKAGE_2, "name", false, 0)
    +-                ),
    +-                USER_0);
    +-
    +-        assertTrue(mService.hasShortcutHostPermissionInner(CALLING_PACKAGE_1, USER_0));
    +-
    +-        // Should be cached.
    +-        assertEquals(cn(CALLING_PACKAGE_1, "xyz"),
    +-                mService.getUserShortcutsLocked(USER_0).getLastKnownLauncher());
    +-        assertEquals(cn(CALLING_PACKAGE_1, "xyz"),
    +-                mService.getUserShortcutsLocked(USER_0).getCachedLauncher());
    +-
    +-
    +-        // As long as there's the cached launcher set, even if getHomeActivitiesAsUser()
    +-        // returns different values, the cached one is still the default.
    +-        prepareGetHomeActivitiesAsUser(
    +-                /* preferred */ getSystemLauncher().activityInfo.getComponentName(),
    +-                list(getSystemLauncher(), getFallbackLauncher()),
    +-                USER_0);
    +-
    +-        assertTrue(mService.hasShortcutHostPermissionInner(CALLING_PACKAGE_1, USER_0));
    +-
    +-        // Cached ones haven't changed.
    +-        assertEquals(cn(CALLING_PACKAGE_1, "xyz"),
    +-                mService.getUserShortcutsLocked(USER_0).getLastKnownLauncher());
    +-        assertEquals(cn(CALLING_PACKAGE_1, "xyz"),
    +-                mService.getUserShortcutsLocked(USER_0).getCachedLauncher());
    +-
    +-        // However, now the "real" default launcher is the system one.  So if the system
    +-        // launcher asks for shortcuts, we'll allow it.
    +-        assertTrue(mService.hasShortcutHostPermissionInner(PACKAGE_SYSTEM_LAUNCHER, USER_0));
    +-
    +-        // Since the cache is updated, CALLING_PACKAGE_1 no longer has the permission.
    +-        assertFalse(mService.hasShortcutHostPermissionInner(CALLING_PACKAGE_1, USER_0));
    +-
    +-        // Cached ones haven't changed.
    +-        assertEquals(cn(PACKAGE_SYSTEM_LAUNCHER, PACKAGE_SYSTEM_LAUNCHER_NAME),
    +-                mService.getUserShortcutsLocked(USER_0).getLastKnownLauncher());
    +-        assertEquals(cn(PACKAGE_SYSTEM_LAUNCHER, PACKAGE_SYSTEM_LAUNCHER_NAME),
    +-                mService.getUserShortcutsLocked(USER_0).getCachedLauncher());
    +-    }
    +-
    +-    public void testHasShortcutHostPermissionInner_multiUser() {
    +-        mRunningUsers.put(USER_10, true);
    +-
    +-        prepareGetHomeActivitiesAsUser(
    +-                /* preferred */ null,
    +-                list(getSystemLauncher(), getFallbackLauncher()),
    +-                USER_0);
    +-
    +-        prepareGetHomeActivitiesAsUser(
    +-                /* preferred */ cn(CALLING_PACKAGE_2, "name"),
    +-                list(getSystemLauncher(), getFallbackLauncher(),
    +-                        ri(CALLING_PACKAGE_1, "name", false, 0),
    +-                        ri(CALLING_PACKAGE_2, "name", false, 0)
    +-                ),
    +-                USER_10);
    +-
    +-        assertTrue(mService.hasShortcutHostPermissionInner(PACKAGE_SYSTEM_LAUNCHER, USER_0));
    +-        assertFalse(mService.hasShortcutHostPermissionInner(PACKAGE_FALLBACK_LAUNCHER, USER_0));
    +-        assertFalse(mService.hasShortcutHostPermissionInner(CALLING_PACKAGE_1, USER_0));
    +-        assertFalse(mService.hasShortcutHostPermissionInner(CALLING_PACKAGE_2, USER_0));
    +-
    +-        // Check the cache.
    +-        assertEquals(cn(PACKAGE_SYSTEM_LAUNCHER, PACKAGE_SYSTEM_LAUNCHER_NAME),
    +-                mService.getUserShortcutsLocked(USER_0).getLastKnownLauncher());
    +-        assertEquals(cn(PACKAGE_SYSTEM_LAUNCHER, PACKAGE_SYSTEM_LAUNCHER_NAME),
    +-                mService.getUserShortcutsLocked(USER_0).getCachedLauncher());
    +-
    +-        assertFalse(mService.hasShortcutHostPermissionInner(PACKAGE_SYSTEM_LAUNCHER, USER_10));
    +-        assertFalse(mService.hasShortcutHostPermissionInner(PACKAGE_FALLBACK_LAUNCHER, USER_10));
    +-        assertFalse(mService.hasShortcutHostPermissionInner(CALLING_PACKAGE_1, USER_10));
    +-        assertTrue(mService.hasShortcutHostPermissionInner(CALLING_PACKAGE_2, USER_10));
    +-
    +-        // Check the cache.
    +-        assertEquals(cn(CALLING_PACKAGE_2, "name"),
    +-                mService.getUserShortcutsLocked(USER_10).getLastKnownLauncher());
    +-        assertEquals(cn(CALLING_PACKAGE_2, "name"),
    +-                mService.getUserShortcutsLocked(USER_10).getCachedLauncher());
    +-    }
    +-
    +-    public void testHasShortcutHostPermissionInner_clearCache() {
    +-        mRunningUsers.put(USER_10, true);
    +-
    +-        prepareGetHomeActivitiesAsUser(
    +-                /* preferred */ null,
    +-                list(getSystemLauncher(), getFallbackLauncher()),
    +-                USER_0);
    +-
    +-        prepareGetHomeActivitiesAsUser(
    +-                /* preferred */ cn(CALLING_PACKAGE_2, "name"),
    +-                list(getSystemLauncher(), getFallbackLauncher(),
    +-                        ri(CALLING_PACKAGE_1, "name", false, 0),
    +-                        ri(CALLING_PACKAGE_2, "name", false, 0)
    +-                ),
    +-                USER_10);
    +-
    +-        assertTrue(mService.hasShortcutHostPermissionInner(PACKAGE_SYSTEM_LAUNCHER, USER_0));
    +-        assertTrue(mService.hasShortcutHostPermissionInner(CALLING_PACKAGE_2, USER_10));
    +-
    +-        assertEquals(cn(PACKAGE_SYSTEM_LAUNCHER, PACKAGE_SYSTEM_LAUNCHER_NAME),
    +-                mService.getUserShortcutsLocked(USER_0).getCachedLauncher());
    +-
    +-        assertEquals(cn(CALLING_PACKAGE_2, "name"),
    +-                mService.getUserShortcutsLocked(USER_10).getCachedLauncher());
    +-
    +-        // Test it on a non-running user.
    +-        // Send ACTION_PREFERRED_ACTIVITY_CHANGED on user 10.
    +-        // But the user is not running, so will be ignored.
    +-        mRunningUsers.put(USER_10, false);
    +-
    +-        mService.mPackageMonitor.onReceive(mServiceContext,
    +-                new Intent(Intent.ACTION_PREFERRED_ACTIVITY_CHANGED).putExtra(
    +-                        Intent.EXTRA_USER_HANDLE, USER_10));
    +-
    +-        // Need to run the user again to access the internal status.
    +-        mRunningUsers.put(USER_10, true);
    +-
    +-        assertEquals(cn(PACKAGE_SYSTEM_LAUNCHER, PACKAGE_SYSTEM_LAUNCHER_NAME),
    +-                mService.getUserShortcutsLocked(USER_0).getCachedLauncher());
    +-
    +-        assertEquals(cn(CALLING_PACKAGE_2, "name"),
    +-                mService.getUserShortcutsLocked(USER_10).getCachedLauncher());
    +-
    +-         // Send it again after starting the user.
    +-        mRunningUsers.put(USER_10, true);
    +-        mService.mPackageMonitor.onReceive(mServiceContext,
    +-                new Intent(Intent.ACTION_PREFERRED_ACTIVITY_CHANGED).putExtra(
    +-                        Intent.EXTRA_USER_HANDLE, USER_10));
    +-
    +-        assertEquals(cn(PACKAGE_SYSTEM_LAUNCHER, PACKAGE_SYSTEM_LAUNCHER_NAME),
    +-                mService.getUserShortcutsLocked(USER_0).getCachedLauncher());
    +-
    +-        // Only user-10's cache is cleared.
    +-        assertEquals(null,
    +-                mService.getUserShortcutsLocked(USER_10).getCachedLauncher());
    +-
    +-    }
    +-}
    +diff --git a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest7.java b/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest7.java
    +deleted file mode 100644
    +index 3c99174..0000000
    +--- a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest7.java
    ++++ /dev/null
    +@@ -1,339 +0,0 @@
    +-/*
    +- * Copyright (C) 2016 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 com.android.server.pm;
    +-
    +-import static com.android.server.pm.shortcutmanagertest.ShortcutManagerTestUtils.assertContains;
    +-import static com.android.server.pm.shortcutmanagertest.ShortcutManagerTestUtils.assertExpectException;
    +-import static com.android.server.pm.shortcutmanagertest.ShortcutManagerTestUtils.assertSuccess;
    +-import static com.android.server.pm.shortcutmanagertest.ShortcutManagerTestUtils.assertWith;
    +-import static com.android.server.pm.shortcutmanagertest.ShortcutManagerTestUtils.list;
    +-import static com.android.server.pm.shortcutmanagertest.ShortcutManagerTestUtils.readAll;
    +-import static com.android.server.pm.shortcutmanagertest.ShortcutManagerTestUtils.resultContains;
    +-
    +-import android.content.ComponentName;
    +-import android.os.Bundle;
    +-import android.os.ParcelFileDescriptor;
    +-import android.os.Process;
    +-import android.os.RemoteException;
    +-import android.os.ResultReceiver;
    +-import android.test.suitebuilder.annotation.SmallTest;
    +-
    +-import com.android.frameworks.servicestests.R;
    +-import com.android.server.pm.ShortcutService.ConfigConstants;
    +-
    +-import java.io.File;
    +-import java.io.IOException;
    +-import java.util.List;
    +-import java.util.concurrent.atomic.AtomicInteger;
    +-
    +-/**
    +- * Unit test for "cmd shortcut"
    +- *
    +- * Launcher related commands are tested in
    +- */
    +-@SmallTest
    +-public class ShortcutManagerTest7 extends BaseShortcutManagerTest {
    +-    private List<String> callShellCommand(String... args) throws IOException, RemoteException {
    +-
    +-        // For reset to work, the current time needs to be incrementing.
    +-        mInjectedCurrentTimeMillis++;
    +-
    +-        final AtomicInteger resultCode = new AtomicInteger(Integer.MIN_VALUE);
    +-
    +-        final ResultReceiver rr = new ResultReceiver(mHandler) {
    +-            @Override
    +-            public void send(int resultCode_, Bundle resultData) {
    +-                resultCode.set(resultCode_);
    +-            }
    +-        };
    +-        final File out = File.createTempFile("shellout-", ".tmp",
    +-                getTestContext().getCacheDir());
    +-        try {
    +-            try (final ParcelFileDescriptor fd = ParcelFileDescriptor.open(out,
    +-                    ParcelFileDescriptor.MODE_READ_WRITE)) {
    +-                mService.onShellCommand(
    +-                    /* fdin*/ null,
    +-                    /* fdout*/ fd.getFileDescriptor(),
    +-                    /* fderr*/ fd.getFileDescriptor(),
    +-                        args, rr);
    +-            }
    +-            return readAll(out);
    +-        } finally {
    +-            out.delete();
    +-        }
    +-    }
    +-
    +-    public void testNonShell() throws Exception {
    +-        mService.mMaxUpdatesPerInterval = 99;
    +-
    +-        mInjectedCallingUid = 12345;
    +-        assertExpectException(SecurityException.class, "must be shell",
    +-                () -> callShellCommand("reset-config"));
    +-
    +-        mInjectedCallingUid = Process.SYSTEM_UID;
    +-        assertExpectException(SecurityException.class, "must be shell",
    +-                () -> callShellCommand("reset-config"));
    +-
    +-        assertEquals(99, mService.mMaxUpdatesPerInterval);
    +-    }
    +-
    +-    public void testRoot() throws Exception {
    +-        mService.mMaxUpdatesPerInterval = 99;
    +-
    +-        mInjectedCallingUid = Process.ROOT_UID;
    +-        assertSuccess(callShellCommand("reset-config"));
    +-
    +-        assertEquals(3, mService.mMaxUpdatesPerInterval);
    +-    }
    +-
    +-    public void testRestConfig() throws Exception {
    +-        mService.mMaxUpdatesPerInterval = 99;
    +-
    +-        mInjectedCallingUid = Process.SHELL_UID;
    +-        assertSuccess(callShellCommand("reset-config"));
    +-
    +-        assertEquals(3, mService.mMaxUpdatesPerInterval);
    +-    }
    +-
    +-    public void testOverrideConfig() throws Exception {
    +-        mService.mMaxUpdatesPerInterval = 99;
    +-
    +-        mInjectedCallingUid = Process.SHELL_UID;
    +-        assertSuccess(callShellCommand("override-config",
    +-                ConfigConstants.KEY_MAX_UPDATES_PER_INTERVAL + "=1"));
    +-
    +-        assertEquals(1, mService.mMaxUpdatesPerInterval);
    +-    }
    +-
    +-    public void testResetThrottling() throws Exception {
    +-        prepareCrossProfileDataSet();
    +-
    +-        runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
    +-            assertTrue(mManager.getRemainingCallCount() < 3);
    +-        });
    +-        runWithCaller(CALLING_PACKAGE_1, USER_10, () -> {
    +-            assertTrue(mManager.getRemainingCallCount() < 3);
    +-        });
    +-
    +-        mInjectedCallingUid = Process.SHELL_UID;
    +-        assertSuccess(callShellCommand("reset-throttling"));
    +-
    +-        runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
    +-            assertEquals(3, mManager.getRemainingCallCount());
    +-        });
    +-        runWithCaller(CALLING_PACKAGE_1, USER_10, () -> {
    +-            assertTrue(mManager.getRemainingCallCount() < 3);
    +-        });
    +-    }
    +-
    +-    public void testResetThrottling_user_not_running() throws Exception {
    +-        prepareCrossProfileDataSet();
    +-
    +-        runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
    +-            assertTrue(mManager.getRemainingCallCount() < 3);
    +-        });
    +-        runWithCaller(CALLING_PACKAGE_1, USER_10, () -> {
    +-            assertTrue(mManager.getRemainingCallCount() < 3);
    +-        });
    +-
    +-        mInjectedCallingUid = Process.SHELL_UID;
    +-
    +-        mRunningUsers.put(USER_10, false);
    +-
    +-        assertTrue(resultContains(
    +-                callShellCommand("reset-throttling", "--user", "10"),
    +-                "User 10 is not running or locked"));
    +-
    +-        mRunningUsers.put(USER_10, true);
    +-
    +-        runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
    +-            assertTrue(mManager.getRemainingCallCount() < 3);
    +-        });
    +-        runWithCaller(CALLING_PACKAGE_1, USER_10, () -> {
    +-            assertTrue(mManager.getRemainingCallCount() < 3);
    +-        });
    +-    }
    +-
    +-    public void testResetThrottling_user_running() throws Exception {
    +-        prepareCrossProfileDataSet();
    +-
    +-        runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
    +-            assertTrue(mManager.getRemainingCallCount() < 3);
    +-        });
    +-        runWithCaller(CALLING_PACKAGE_1, USER_10, () -> {
    +-            assertTrue(mManager.getRemainingCallCount() < 3);
    +-        });
    +-
    +-        mRunningUsers.put(USER_10, true);
    +-        mUnlockedUsers.put(USER_10, true);
    +-
    +-        mInjectedCallingUid = Process.SHELL_UID;
    +-        assertSuccess(callShellCommand("reset-throttling", "--user", "10"));
    +-
    +-        runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
    +-            assertTrue(mManager.getRemainingCallCount() < 3);
    +-        });
    +-        runWithCaller(CALLING_PACKAGE_1, USER_10, () -> {
    +-            assertEquals(3, mManager.getRemainingCallCount());
    +-        });
    +-    }
    +-
    +-    public void testResetAllThrottling() throws Exception {
    +-        prepareCrossProfileDataSet();
    +-
    +-        runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
    +-            assertTrue(mManager.getRemainingCallCount() < 3);
    +-        });
    +-        runWithCaller(CALLING_PACKAGE_1, USER_10, () -> {
    +-            assertTrue(mManager.getRemainingCallCount() < 3);
    +-        });
    +-
    +-        mInjectedCallingUid = Process.SHELL_UID;
    +-        assertSuccess(callShellCommand("reset-all-throttling"));
    +-
    +-        runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
    +-            assertEquals(3, mManager.getRemainingCallCount());
    +-        });
    +-        runWithCaller(CALLING_PACKAGE_1, USER_10, () -> {
    +-            assertEquals(3, mManager.getRemainingCallCount());
    +-        });
    +-    }
    +-
    +-    public void testLauncherCommands() throws Exception {
    +-        prepareGetHomeActivitiesAsUser(
    +-                /* preferred */ null,
    +-                list(getSystemLauncher(), getFallbackLauncher()),
    +-                USER_0);
    +-
    +-        prepareGetHomeActivitiesAsUser(
    +-                /* preferred */ cn(CALLING_PACKAGE_2, "name"),
    +-                list(getSystemLauncher(), getFallbackLauncher(),
    +-                        ri(CALLING_PACKAGE_1, "name", false, 0),
    +-                        ri(CALLING_PACKAGE_2, "name", false, 0)
    +-                ),
    +-                USER_10);
    +-
    +-        assertTrue(mService.hasShortcutHostPermissionInner(PACKAGE_SYSTEM_LAUNCHER, USER_0));
    +-
    +-        // First, test "get".
    +-
    +-        mRunningUsers.put(USER_10, true);
    +-        mUnlockedUsers.put(USER_10, true);
    +-        mInjectedCallingUid = Process.SHELL_UID;
    +-        assertContains(
    +-                assertSuccess(callShellCommand("get-default-launcher")),
    +-                "Launcher: ComponentInfo{com.android.systemlauncher/systemlauncher_name}");
    +-
    +-        assertContains(
    +-                assertSuccess(callShellCommand("get-default-launcher", "--user", "10")),
    +-                "Launcher: ComponentInfo{com.android.test.2/name}");
    +-
    +-        // Next, test "clear".
    +-        assertSuccess(callShellCommand("clear-default-launcher", "--user", "10"));
    +-
    +-        // User-10's launcher should be cleared.
    +-        assertEquals(null, mService.getUserShortcutsLocked(USER_10).getLastKnownLauncher());
    +-        assertEquals(null, mService.getUserShortcutsLocked(USER_10).getCachedLauncher());
    +-
    +-        // but user'0's shouldn't.
    +-        assertEquals(cn(PACKAGE_SYSTEM_LAUNCHER, PACKAGE_SYSTEM_LAUNCHER_NAME),
    +-                mService.getUserShortcutsLocked(USER_0).getCachedLauncher());
    +-
    +-        // Change user-0's launcher.
    +-        prepareGetHomeActivitiesAsUser(
    +-                /* preferred */ cn(CALLING_PACKAGE_1, "name"),
    +-                list(
    +-                        ri(CALLING_PACKAGE_1, "name", false, 0)
    +-                ),
    +-                USER_0);
    +-        assertContains(
    +-                assertSuccess(callShellCommand("get-default-launcher")),
    +-                "Launcher: ComponentInfo{com.android.test.1/name}");
    +-    }
    +-
    +-    public void testUnloadUser() throws Exception {
    +-        prepareCrossProfileDataSet();
    +-
    +-        assertNotNull(mService.getShortcutsForTest().get(USER_10));
    +-
    +-        mRunningUsers.put(USER_10, true);
    +-        mUnlockedUsers.put(USER_10, true);
    +-
    +-        mInjectedCallingUid = Process.SHELL_UID;
    +-        assertSuccess(callShellCommand("unload-user", "--user", "10"));
    +-
    +-        assertNull(mService.getShortcutsForTest().get(USER_10));
    +-    }
    +-
    +-    public void testClearShortcuts() throws Exception {
    +-
    +-        mRunningUsers.put(USER_10, true);
    +-
    +-        // Add two manifests and two dynamics.
    +-        addManifestShortcutResource(
    +-                new ComponentName(CALLING_PACKAGE_1, ShortcutActivity.class.getName()),
    +-                R.xml.shortcut_2);
    +-        updatePackageVersion(CALLING_PACKAGE_1, 1);
    +-        mService.mPackageMonitor.onReceive(getTestContext(),
    +-                genPackageAddIntent(CALLING_PACKAGE_1, USER_10));
    +-
    +-        runWithCaller(CALLING_PACKAGE_1, USER_10, () -> {
    +-            assertTrue(mManager.addDynamicShortcuts(list(
    +-                    makeShortcut("s1"), makeShortcut("s2"))));
    +-        });
    +-        runWithCaller(LAUNCHER_1, USER_10, () -> {
    +-            mLauncherApps.pinShortcuts(CALLING_PACKAGE_1, list("ms2", "s2"), HANDLE_USER_10);
    +-        });
    +-
    +-        runWithCaller(CALLING_PACKAGE_1, USER_10, () -> {
    +-            assertWith(getCallerShortcuts())
    +-                    .haveIds("ms1", "ms2", "s1", "s2")
    +-                    .areAllEnabled()
    +-
    +-                    .selectPinned()
    +-                    .haveIds("ms2", "s2");
    +-        });
    +-
    +-        // First, call for a different package.
    +-
    +-        mRunningUsers.put(USER_10, true);
    +-        mUnlockedUsers.put(USER_10, true);
    +-
    +-        mInjectedCallingUid = Process.SHELL_UID;
    +-        assertSuccess(callShellCommand("clear-shortcuts", "--user", "10", CALLING_PACKAGE_2));
    +-
    +-        // Shouldn't be cleared yet.
    +-        runWithCaller(CALLING_PACKAGE_1, USER_10, () -> {
    +-            assertWith(getCallerShortcuts())
    +-                    .haveIds("ms1", "ms2", "s1", "s2")
    +-                    .areAllEnabled()
    +-
    +-                    .selectPinned()
    +-                    .haveIds("ms2", "s2");
    +-        });
    +-
    +-        mInjectedCallingUid = Process.SHELL_UID;
    +-        assertSuccess(callShellCommand("clear-shortcuts", "--user", "10", CALLING_PACKAGE_1));
    +-
    +-        // Only manifest shortcuts will remain, and are no longer pinned.
    +-        runWithCaller(CALLING_PACKAGE_1, USER_10, () -> {
    +-            assertWith(getCallerShortcuts())
    +-                    .haveIds("ms1", "ms2")
    +-                    .areAllEnabled()
    +-                    .areAllNotPinned();
    +-        });
    +-    }
    +-}
    +diff --git a/services/tests/servicestests/src/com/android/server/pm/ShortcutTestActivity.java b/services/tests/servicestests/src/com/android/server/pm/ShortcutTestActivity.java
    +deleted file mode 100644
    +index d82b0d5..0000000
    +--- a/services/tests/servicestests/src/com/android/server/pm/ShortcutTestActivity.java
    ++++ /dev/null
    +@@ -1,21 +0,0 @@
    +-/*
    +- * Copyright (C) 2016 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 com.android.server.pm;
    +-
    +-import android.app.Activity;
    +-
    +-public class ShortcutTestActivity extends Activity {
    +-}
    +diff --git a/services/tests/servicestests/src/com/android/server/pm/UserManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/pm/UserManagerServiceTest.java
    +deleted file mode 100644
    +index 9f77297..0000000
    +--- a/services/tests/servicestests/src/com/android/server/pm/UserManagerServiceTest.java
    ++++ /dev/null
    +@@ -1,121 +0,0 @@
    +-/*
    +- * Copyright (C) 2015 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 com.android.server.pm;
    +-
    +-import android.content.pm.UserInfo;
    +-import android.os.Bundle;
    +-import android.os.FileUtils;
    +-import android.os.Parcelable;
    +-import android.os.UserHandle;
    +-import android.os.UserManager;
    +-import android.test.AndroidTestCase;
    +-import android.test.suitebuilder.annotation.SmallTest;
    +-import android.util.AtomicFile;
    +-
    +-import java.io.File;
    +-import java.io.IOException;
    +-import java.util.Arrays;
    +-
    +-@SmallTest
    +-public class UserManagerServiceTest extends AndroidTestCase {
    +-    private static String[] STRING_ARRAY = new String[] {"<tag", "<![CDATA["};
    +-    private File restrictionsFile;
    +-    private int tempUserId = UserHandle.USER_NULL;
    +-
    +-    @Override
    +-    protected void setUp() throws Exception {
    +-        super.setUp();
    +-        restrictionsFile = new File(mContext.getCacheDir(), "restrictions.xml");
    +-        restrictionsFile.delete();
    +-    }
    +-
    +-    @Override
    +-    protected void tearDown() throws Exception {
    +-        restrictionsFile.delete();
    +-        if (tempUserId != UserHandle.USER_NULL) {
    +-            UserManager.get(mContext).removeUser(tempUserId);
    +-        }
    +-        super.tearDown();
    +-    }
    +-
    +-    public void testWriteReadApplicationRestrictions() throws IOException {
    +-        AtomicFile atomicFile = new AtomicFile(restrictionsFile);
    +-        Bundle bundle = createBundle();
    +-        UserManagerService.writeApplicationRestrictionsLP(bundle, atomicFile);
    +-        assertTrue(atomicFile.getBaseFile().exists());
    +-        String s = FileUtils.readTextFile(restrictionsFile, 10000, "");
    +-        System.out.println("restrictionsFile: " + s);
    +-        bundle = UserManagerService.readApplicationRestrictionsLP(atomicFile);
    +-        System.out.println("readApplicationRestrictionsLocked bundle: " + bundle);
    +-        assertBundle(bundle);
    +-    }
    +-
    +-    public void testAddUserWithAccount() {
    +-        UserManager um = UserManager.get(mContext);
    +-        UserInfo user = um.createUser("Test User", 0);
    +-        assertNotNull(user);
    +-        tempUserId = user.id;
    +-        String accountName = "Test Account";
    +-        um.setUserAccount(tempUserId, accountName);
    +-        assertEquals(accountName, um.getUserAccount(tempUserId));
    +-    }
    +-
    +-    private Bundle createBundle() {
    +-        Bundle result = new Bundle();
    +-        // Tests for 6 allowed types: Integer, Boolean, String, String[], Bundle and Parcelable[]
    +-        result.putBoolean("boolean_0", false);
    +-        result.putBoolean("boolean_1", true);
    +-        result.putInt("integer", 100);
    +-        result.putString("empty", "");
    +-        result.putString("string", "text");
    +-        result.putStringArray("string[]", STRING_ARRAY);
    +-
    +-        Bundle bundle = new Bundle();
    +-        bundle.putString("bundle_string", "bundle_string");
    +-        bundle.putInt("bundle_int", 1);
    +-        result.putBundle("bundle", bundle);
    +-
    +-        Bundle[] bundleArray = new Bundle[2];
    +-        bundleArray[0] = new Bundle();
    +-        bundleArray[0].putString("bundle_array_string", "bundle_array_string");
    +-        bundleArray[0].putBundle("bundle_array_bundle", bundle);
    +-        bundleArray[1] = new Bundle();
    +-        bundleArray[1].putString("bundle_array_string2", "bundle_array_string2");
    +-        result.putParcelableArray("bundle_array", bundleArray);
    +-        return result;
    +-    }
    +-
    +-    private void assertBundle(Bundle bundle) {
    +-        assertFalse(bundle.getBoolean("boolean_0"));
    +-        assertTrue(bundle.getBoolean("boolean_1"));
    +-        assertEquals(100, bundle.getInt("integer"));
    +-        assertEquals("", bundle.getString("empty"));
    +-        assertEquals("text", bundle.getString("string"));
    +-        assertEquals(Arrays.asList(STRING_ARRAY), Arrays.asList(bundle.getStringArray("string[]")));
    +-        Parcelable[] bundle_array = bundle.getParcelableArray("bundle_array");
    +-        assertEquals(2, bundle_array.length);
    +-        Bundle bundle1 = (Bundle) bundle_array[0];
    +-        assertEquals("bundle_array_string", bundle1.getString("bundle_array_string"));
    +-        assertNotNull(bundle1.getBundle("bundle_array_bundle"));
    +-        Bundle bundle2 = (Bundle) bundle_array[1];
    +-        assertEquals("bundle_array_string2", bundle2.getString("bundle_array_string2"));
    +-        Bundle childBundle = bundle.getBundle("bundle");
    +-        assertEquals("bundle_string", childBundle.getString("bundle_string"));
    +-        assertEquals(1, childBundle.getInt("bundle_int"));
    +-    }
    +-
    +-}
    +diff --git a/services/tests/servicestests/src/com/android/server/pm/UserManagerTest.java b/services/tests/servicestests/src/com/android/server/pm/UserManagerTest.java
    +deleted file mode 100644
    +index ced4980..0000000
    +--- a/services/tests/servicestests/src/com/android/server/pm/UserManagerTest.java
    ++++ /dev/null
    +@@ -1,278 +0,0 @@
    +-/*
    +- * Copyright (C) 2011 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 com.android.server.pm;
    +-
    +-import android.content.BroadcastReceiver;
    +-import android.content.Context;
    +-import android.content.Intent;
    +-import android.content.IntentFilter;
    +-import android.content.pm.UserInfo;
    +-import android.os.Bundle;
    +-import android.os.UserHandle;
    +-import android.os.UserManager;
    +-import android.test.AndroidTestCase;
    +-import android.test.suitebuilder.annotation.MediumTest;
    +-
    +-import com.android.internal.util.ArrayUtils;
    +-
    +-import java.util.ArrayList;
    +-import java.util.Arrays;
    +-import java.util.List;
    +-
    +-/** Test {@link UserManager} functionality. */
    +-@MediumTest
    +-public class UserManagerTest extends AndroidTestCase {
    +-    private static final int REMOVE_CHECK_INTERVAL = 500;
    +-    private static final int REMOVE_TIMEOUT = 60 * 1000;
    +-    private UserManager mUserManager = null;
    +-    private final Object mUserLock = new Object();
    +-    private List<Integer> usersToRemove;
    +-
    +-    @Override
    +-    public void setUp() throws Exception {
    +-        super.setUp();
    +-        mUserManager = UserManager.get(getContext());
    +-        IntentFilter filter = new IntentFilter(Intent.ACTION_USER_REMOVED);
    +-        getContext().registerReceiver(new BroadcastReceiver() {
    +-            @Override
    +-            public void onReceive(Context context, Intent intent) {
    +-                synchronized (mUserLock) {
    +-                    mUserLock.notifyAll();
    +-                }
    +-            }
    +-        }, filter);
    +-
    +-        removeExistingUsers();
    +-        usersToRemove = new ArrayList<>();
    +-    }
    +-
    +-    @Override
    +-    protected void tearDown() throws Exception {
    +-        for (Integer userId : usersToRemove) {
    +-            removeUser(userId);
    +-        }
    +-        super.tearDown();
    +-    }
    +-
    +-    private void removeExistingUsers() {
    +-        List<UserInfo> list = mUserManager.getUsers();
    +-        for (UserInfo user : list) {
    +-            // Keep system and primary user.
    +-            // We do not have to keep primary user, but in split system user mode, we need it
    +-            // until http://b/22976637 is fixed.  Right now in split system user mode, you need to
    +-            // switch to primary user and run tests under primary user.
    +-            if (user.id != UserHandle.USER_SYSTEM && !user.isPrimary()) {
    +-                removeUser(user.id);
    +-            }
    +-        }
    +-    }
    +-
    +-    public void testHasSystemUser() throws Exception {
    +-        assertTrue(findUser(UserHandle.USER_SYSTEM));
    +-    }
    +-
    +-    public void testAddUser() throws Exception {
    +-        UserInfo userInfo = createUser("Guest 1", UserInfo.FLAG_GUEST);
    +-        assertTrue(userInfo != null);
    +-
    +-        List<UserInfo> list = mUserManager.getUsers();
    +-        boolean found = false;
    +-        for (UserInfo user : list) {
    +-            if (user.id == userInfo.id && user.name.equals("Guest 1")
    +-                    && user.isGuest()
    +-                    && !user.isAdmin()
    +-                    && !user.isPrimary()) {
    +-                found = true;
    +-                Bundle restrictions = mUserManager.getUserRestrictions(user.getUserHandle());
    +-                assertTrue("Guest user should have DISALLOW_CONFIG_WIFI=true by default",
    +-                        restrictions.getBoolean(UserManager.DISALLOW_CONFIG_WIFI));
    +-            }
    +-        }
    +-        assertTrue(found);
    +-    }
    +-
    +-    public void testAdd2Users() throws Exception {
    +-        UserInfo user1 = createUser("Guest 1", UserInfo.FLAG_GUEST);
    +-        UserInfo user2 = createUser("User 2", UserInfo.FLAG_ADMIN);
    +-
    +-        assertTrue(user1 != null);
    +-        assertTrue(user2 != null);
    +-
    +-        assertTrue(findUser(0));
    +-        assertTrue(findUser(user1.id));
    +-        assertTrue(findUser(user2.id));
    +-    }
    +-
    +-    public void testRemoveUser() throws Exception {
    +-        UserInfo userInfo = createUser("Guest 1", UserInfo.FLAG_GUEST);
    +-        removeUser(userInfo.id);
    +-
    +-        assertFalse(findUser(userInfo.id));
    +-    }
    +-
    +-    public void testAddGuest() throws Exception {
    +-        UserInfo userInfo1 = createUser("Guest 1", UserInfo.FLAG_GUEST);
    +-        UserInfo userInfo2 = createUser("Guest 2", UserInfo.FLAG_GUEST);
    +-        assertNotNull(userInfo1);
    +-        assertNull(userInfo2);
    +-    }
    +-
    +-    // Make sure only one managed profile can be created
    +-    public void testAddManagedProfile() throws Exception {
    +-        final int primaryUserId = mUserManager.getPrimaryUser().id;
    +-        UserInfo userInfo1 = createProfileForUser("Managed 1",
    +-                UserInfo.FLAG_MANAGED_PROFILE, primaryUserId);
    +-        UserInfo userInfo2 = createProfileForUser("Managed 2",
    +-                UserInfo.FLAG_MANAGED_PROFILE, primaryUserId);
    +-        assertNotNull(userInfo1);
    +-        assertNull(userInfo2);
    +-        // Verify that current user is not a managed profile
    +-        assertFalse(mUserManager.isManagedProfile());
    +-    }
    +-
    +-    public void testGetUserCreationTime() throws Exception {
    +-        final int primaryUserId = mUserManager.getPrimaryUser().id;
    +-        UserInfo profile = createProfileForUser("Managed 1",
    +-                UserInfo.FLAG_MANAGED_PROFILE, primaryUserId);
    +-        assertNotNull(profile);
    +-        assertTrue("creationTime must be set when the profile is created",
    +-                profile.creationTime > 0);
    +-        assertEquals(profile.creationTime, mUserManager.getUserCreationTime(
    +-                new UserHandle(profile.id)));
    +-
    +-        long ownerCreationTime = mUserManager.getUserInfo(primaryUserId).creationTime;
    +-        assertEquals(ownerCreationTime, mUserManager.getUserCreationTime(
    +-                new UserHandle(primaryUserId)));
    +-
    +-        try {
    +-            int noSuchUserId = 100500;
    +-            mUserManager.getUserCreationTime(new UserHandle(noSuchUserId));
    +-            fail("SecurityException should be thrown for nonexistent user");
    +-        } catch (Exception e) {
    +-            assertTrue("SecurityException should be thrown for nonexistent user, but was: " + e,
    +-                    e instanceof SecurityException);
    +-        }
    +-
    +-        UserInfo user = createUser("User 1", 0);
    +-        try {
    +-            mUserManager.getUserCreationTime(new UserHandle(user.id));
    +-            fail("SecurityException should be thrown for other user");
    +-        } catch (Exception e) {
    +-            assertTrue("SecurityException should be thrown for other user, but was: " + e,
    +-                    e instanceof SecurityException);
    +-        }
    +-    }
    +-
    +-
    +-    private boolean findUser(int id) {
    +-        List<UserInfo> list = mUserManager.getUsers();
    +-
    +-        for (UserInfo user : list) {
    +-            if (user.id == id) {
    +-                return true;
    +-            }
    +-        }
    +-        return false;
    +-    }
    +-
    +-    public void testSerialNumber() {
    +-        UserInfo user1 = createUser("User 1", 0);
    +-        int serialNumber1 = user1.serialNumber;
    +-        assertEquals(serialNumber1, mUserManager.getUserSerialNumber(user1.id));
    +-        assertEquals(user1.id, mUserManager.getUserHandle(serialNumber1));
    +-        UserInfo user2 = createUser("User 2", 0);
    +-        int serialNumber2 = user2.serialNumber;
    +-        assertFalse(serialNumber1 == serialNumber2);
    +-        assertEquals(serialNumber2, mUserManager.getUserSerialNumber(user2.id));
    +-        assertEquals(user2.id, mUserManager.getUserHandle(serialNumber2));
    +-    }
    +-
    +-    public void testGetSerialNumbersOfUsers() {
    +-        UserInfo user1 = createUser("User 1", 0);
    +-        UserInfo user2 = createUser("User 2", 0);
    +-        long[] serialNumbersOfUsers = mUserManager.getSerialNumbersOfUsers(false);
    +-        String errMsg = "Array " + Arrays.toString(serialNumbersOfUsers) + " should contain ";
    +-        assertTrue(errMsg + user1.serialNumber,
    +-                ArrayUtils.contains(serialNumbersOfUsers, user1.serialNumber));
    +-        assertTrue(errMsg + user2.serialNumber,
    +-                ArrayUtils.contains(serialNumbersOfUsers, user2.serialNumber));
    +-    }
    +-
    +-    public void testMaxUsers() {
    +-        int N = UserManager.getMaxSupportedUsers();
    +-        int count = mUserManager.getUsers().size();
    +-        // Create as many users as permitted and make sure creation passes
    +-        while (count < N) {
    +-            UserInfo ui = createUser("User " + count, 0);
    +-            assertNotNull(ui);
    +-            count++;
    +-        }
    +-        // Try to create one more user and make sure it fails
    +-        UserInfo extra = createUser("One more", 0);
    +-        assertNull(extra);
    +-    }
    +-
    +-    public void testRestrictions() {
    +-        UserInfo testUser = createUser("User 1", 0);
    +-
    +-        mUserManager.setUserRestriction(
    +-                UserManager.DISALLOW_INSTALL_APPS, true, new UserHandle(testUser.id));
    +-        mUserManager.setUserRestriction(
    +-                UserManager.DISALLOW_CONFIG_WIFI, false, new UserHandle(testUser.id));
    +-
    +-        Bundle stored = mUserManager.getUserRestrictions(new UserHandle(testUser.id));
    +-        // Note this will fail if DO already sets those restrictions.
    +-        assertEquals(stored.getBoolean(UserManager.DISALLOW_CONFIG_WIFI), false);
    +-        assertEquals(stored.getBoolean(UserManager.DISALLOW_UNINSTALL_APPS), false);
    +-        assertEquals(stored.getBoolean(UserManager.DISALLOW_INSTALL_APPS), true);
    +-    }
    +-
    +-    private void removeUser(int userId) {
    +-        synchronized (mUserLock) {
    +-            mUserManager.removeUser(userId);
    +-            long time = System.currentTimeMillis();
    +-            while (mUserManager.getUserInfo(userId) != null) {
    +-                try {
    +-                    mUserLock.wait(REMOVE_CHECK_INTERVAL);
    +-                } catch (InterruptedException ie) {
    +-                    Thread.currentThread().interrupt();
    +-                    return;
    +-                }
    +-                if (System.currentTimeMillis() - time > REMOVE_TIMEOUT) {
    +-                    fail("Timeout waiting for removeUser. userId = " + userId);
    +-                }
    +-            }
    +-        }
    +-    }
    +-
    +-    private UserInfo createUser(String name, int flags) {
    +-        UserInfo user = mUserManager.createUser(name, flags);
    +-        if (user != null) {
    +-            usersToRemove.add(user.id);
    +-        }
    +-        return user;
    +-    }
    +-
    +-    private UserInfo createProfileForUser(String name, int flags, int userHandle) {
    +-        UserInfo profile = mUserManager.createProfileForUser(name, flags, userHandle);
    +-        if (profile != null) {
    +-            usersToRemove.add(profile.id);
    +-        }
    +-        return profile;
    +-    }
    +-
    +-}
    +diff --git a/services/tests/servicestests/src/com/android/server/pm/UserRestrictionsUtilsTest.java b/services/tests/servicestests/src/com/android/server/pm/UserRestrictionsUtilsTest.java
    +deleted file mode 100644
    +index 11f9ebb..0000000
    +--- a/services/tests/servicestests/src/com/android/server/pm/UserRestrictionsUtilsTest.java
    ++++ /dev/null
    +@@ -1,207 +0,0 @@
    +-/*
    +- * Copyright (C) 2015 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 com.android.server.pm;
    +-
    +-import android.os.Bundle;
    +-import android.os.UserHandle;
    +-import android.os.UserManager;
    +-import android.test.AndroidTestCase;
    +-import android.test.suitebuilder.annotation.SmallTest;
    +-
    +-import com.android.server.devicepolicy.DpmTestUtils;
    +-
    +-/**
    +- * Tests for {@link com.android.server.pm.UserRestrictionsUtils}.
    +- *
    +- * <p>Run with:<pre>
    +-   m FrameworksServicesTests &&
    +-   adb install \
    +-     -r out/target/product/hammerhead/data/app/FrameworksServicesTests/FrameworksServicesTests.apk &&
    +-   adb shell am instrument -e class com.android.server.pm.UserRestrictionsUtilsTest \
    +-     -w com.android.frameworks.servicestests/android.support.test.runner.AndroidJUnitRunner
    +- * </pre>
    +- */
    +-@SmallTest
    +-public class UserRestrictionsUtilsTest extends AndroidTestCase {
    +-    public void testNonNull() {
    +-        Bundle out = UserRestrictionsUtils.nonNull(null);
    +-        assertNotNull(out);
    +-        out.putBoolean("a", true); // Should not be Bundle.EMPTY.
    +-
    +-        Bundle in = new Bundle();
    +-        assertSame(in, UserRestrictionsUtils.nonNull(in));
    +-    }
    +-
    +-    public void testIsEmpty() {
    +-        assertTrue(UserRestrictionsUtils.isEmpty(null));
    +-        assertTrue(UserRestrictionsUtils.isEmpty(new Bundle()));
    +-        assertFalse(UserRestrictionsUtils.isEmpty(DpmTestUtils.newRestrictions("a")));
    +-    }
    +-
    +-    public void testClone() {
    +-        Bundle in = new Bundle();
    +-        Bundle out = UserRestrictionsUtils.clone(in);
    +-        assertNotSame(in, out);
    +-        DpmTestUtils.assertRestrictions(out, new Bundle());
    +-
    +-        out = UserRestrictionsUtils.clone(null);
    +-        assertNotNull(out);
    +-        out.putBoolean("a", true); // Should not be Bundle.EMPTY.
    +-    }
    +-
    +-    public void testMerge() {
    +-        Bundle a = DpmTestUtils.newRestrictions("a", "d");
    +-        Bundle b = DpmTestUtils.newRestrictions("b", "d", "e");
    +-
    +-        UserRestrictionsUtils.merge(a, b);
    +-
    +-        DpmTestUtils.assertRestrictions(DpmTestUtils.newRestrictions("a", "b", "d", "e"), a);
    +-
    +-        UserRestrictionsUtils.merge(a, null);
    +-
    +-        DpmTestUtils.assertRestrictions(DpmTestUtils.newRestrictions("a", "b", "d", "e"), a);
    +-
    +-        try {
    +-            UserRestrictionsUtils.merge(a, a);
    +-            fail();
    +-        } catch (IllegalArgumentException expected) {
    +-        }
    +-    }
    +-
    +-    public void testCanDeviceOwnerChange() {
    +-        assertFalse(UserRestrictionsUtils.canDeviceOwnerChange(UserManager.DISALLOW_RECORD_AUDIO));
    +-        assertFalse(UserRestrictionsUtils.canDeviceOwnerChange(UserManager.DISALLOW_WALLPAPER));
    +-        assertTrue(UserRestrictionsUtils.canDeviceOwnerChange(UserManager.DISALLOW_ADD_USER));
    +-    }
    +-
    +-    public void testCanProfileOwnerChange() {
    +-        int user = UserHandle.USER_SYSTEM;
    +-        assertFalse(UserRestrictionsUtils.canProfileOwnerChange(
    +-                UserManager.DISALLOW_RECORD_AUDIO, user));
    +-        assertFalse(UserRestrictionsUtils.canProfileOwnerChange(
    +-                UserManager.DISALLOW_WALLPAPER, user));
    +-        assertTrue(UserRestrictionsUtils.canProfileOwnerChange(
    +-                UserManager.DISALLOW_ADD_USER, user));
    +-        assertTrue(UserRestrictionsUtils.canProfileOwnerChange(
    +-                UserManager.DISALLOW_ADJUST_VOLUME, user));
    +-
    +-        user = 10;
    +-        assertFalse(UserRestrictionsUtils.canProfileOwnerChange(
    +-                UserManager.DISALLOW_RECORD_AUDIO, user));
    +-        assertFalse(UserRestrictionsUtils.canProfileOwnerChange(
    +-                UserManager.DISALLOW_WALLPAPER, user));
    +-        assertFalse(UserRestrictionsUtils.canProfileOwnerChange(
    +-                UserManager.DISALLOW_ADD_USER, user));
    +-        assertTrue(UserRestrictionsUtils.canProfileOwnerChange(
    +-                UserManager.DISALLOW_ADJUST_VOLUME, user));
    +-    }
    +-
    +-    public void testSortToGlobalAndLocal() {
    +-        final Bundle local = new Bundle();
    +-        final Bundle global = new Bundle();
    +-
    +-        UserRestrictionsUtils.sortToGlobalAndLocal(null, global, local);
    +-        assertEquals(0, global.size());
    +-        assertEquals(0, local.size());
    +-
    +-        UserRestrictionsUtils.sortToGlobalAndLocal(Bundle.EMPTY, global, local);
    +-        assertEquals(0, global.size());
    +-        assertEquals(0, local.size());
    +-
    +-        UserRestrictionsUtils.sortToGlobalAndLocal(DpmTestUtils.newRestrictions(
    +-                UserManager.DISALLOW_ADJUST_VOLUME,
    +-                UserManager.DISALLOW_UNMUTE_MICROPHONE,
    +-                UserManager.DISALLOW_USB_FILE_TRANSFER,
    +-                UserManager.DISALLOW_CONFIG_TETHERING,
    +-                UserManager.DISALLOW_OUTGOING_BEAM,
    +-                UserManager.DISALLOW_APPS_CONTROL
    +-        ), global, local);
    +-
    +-
    +-        DpmTestUtils.assertRestrictions(DpmTestUtils.newRestrictions(
    +-                // These can be set by PO too, but when DO sets them, they're global.
    +-                UserManager.DISALLOW_ADJUST_VOLUME,
    +-                UserManager.DISALLOW_UNMUTE_MICROPHONE,
    +-
    +-                // These can only be set by DO.
    +-                UserManager.DISALLOW_USB_FILE_TRANSFER,
    +-                UserManager.DISALLOW_CONFIG_TETHERING
    +-        ), global);
    +-
    +-        DpmTestUtils.assertRestrictions(DpmTestUtils.newRestrictions(
    +-                // They can be set by both DO/PO.
    +-                UserManager.DISALLOW_OUTGOING_BEAM,
    +-                UserManager.DISALLOW_APPS_CONTROL
    +-        ), local);
    +-    }
    +-
    +-    public void testAreEqual() {
    +-        assertTrue(UserRestrictionsUtils.areEqual(
    +-                null,
    +-                null));
    +-
    +-        assertTrue(UserRestrictionsUtils.areEqual(
    +-                null,
    +-                Bundle.EMPTY));
    +-
    +-        assertTrue(UserRestrictionsUtils.areEqual(
    +-                Bundle.EMPTY,
    +-                null));
    +-
    +-        assertTrue(UserRestrictionsUtils.areEqual(
    +-                Bundle.EMPTY,
    +-                Bundle.EMPTY));
    +-
    +-        assertTrue(UserRestrictionsUtils.areEqual(
    +-                new Bundle(),
    +-                Bundle.EMPTY));
    +-
    +-        assertFalse(UserRestrictionsUtils.areEqual(
    +-                null,
    +-                DpmTestUtils.newRestrictions("a")));
    +-
    +-        assertFalse(UserRestrictionsUtils.areEqual(
    +-                DpmTestUtils.newRestrictions("a"),
    +-                null));
    +-
    +-        assertTrue(UserRestrictionsUtils.areEqual(
    +-                DpmTestUtils.newRestrictions("a"),
    +-                DpmTestUtils.newRestrictions("a")));
    +-
    +-        assertFalse(UserRestrictionsUtils.areEqual(
    +-                DpmTestUtils.newRestrictions("a"),
    +-                DpmTestUtils.newRestrictions("a", "b")));
    +-
    +-        assertFalse(UserRestrictionsUtils.areEqual(
    +-                DpmTestUtils.newRestrictions("a", "b"),
    +-                DpmTestUtils.newRestrictions("a")));
    +-
    +-        assertFalse(UserRestrictionsUtils.areEqual(
    +-                DpmTestUtils.newRestrictions("b", "a"),
    +-                DpmTestUtils.newRestrictions("a", "a")));
    +-
    +-        // Make sure false restrictions are handled correctly.
    +-        final Bundle a = DpmTestUtils.newRestrictions("a");
    +-        a.putBoolean("b", true);
    +-
    +-        final Bundle b = DpmTestUtils.newRestrictions("a");
    +-        b.putBoolean("b", false);
    +-
    +-        assertFalse(UserRestrictionsUtils.areEqual(a, b));
    +-        assertFalse(UserRestrictionsUtils.areEqual(b, a));
    +-    }
    +-}
    +diff --git a/services/tests/servicestests/src/com/android/server/pm/backup/BackupUtilsTest.java b/services/tests/servicestests/src/com/android/server/pm/backup/BackupUtilsTest.java
    +deleted file mode 100644
    +index c016e61..0000000
    +--- a/services/tests/servicestests/src/com/android/server/pm/backup/BackupUtilsTest.java
    ++++ /dev/null
    +@@ -1,118 +0,0 @@
    +-/*
    +- * Copyright (C) 2016 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 com.android.server.pm.backup;
    +-
    +-import android.content.pm.ApplicationInfo;
    +-import android.content.pm.PackageInfo;
    +-import android.content.pm.PackageParser.Package;
    +-import android.content.pm.Signature;
    +-import android.test.AndroidTestCase;
    +-import android.test.MoreAsserts;
    +-import android.test.suitebuilder.annotation.SmallTest;
    +-
    +-import com.android.server.backup.BackupUtils;
    +-
    +-import java.util.ArrayList;
    +-import java.util.Arrays;
    +-
    +-@SmallTest
    +-public class BackupUtilsTest extends AndroidTestCase {
    +-
    +-    private Signature[] genSignatures(String... signatures) {
    +-        final Signature[] sigs = new Signature[signatures.length];
    +-        for (int i = 0; i < signatures.length; i++){
    +-            sigs[i] = new Signature(signatures[i].getBytes());
    +-        }
    +-        return sigs;
    +-    }
    +-
    +-    private PackageInfo genPackage(String... signatures) {
    +-        final PackageInfo pi = new PackageInfo();
    +-        pi.packageName = "package";
    +-        pi.applicationInfo = new ApplicationInfo();
    +-        pi.signatures = genSignatures(signatures);
    +-
    +-        return pi;
    +-    }
    +-
    +-    public void testSignaturesMatch() {
    +-        final ArrayList<byte[]> stored1 = BackupUtils.hashSignatureArray(Arrays.asList(
    +-                "abc".getBytes()));
    +-        final ArrayList<byte[]> stored2 = BackupUtils.hashSignatureArray(Arrays.asList(
    +-                "abc".getBytes(), "def".getBytes()));
    +-
    +-        PackageInfo pi;
    +-
    +-        // False for null package.
    +-        assertFalse(BackupUtils.signaturesMatch(stored1, null));
    +-
    +-        // If it's a system app, signatures don't matter.
    +-        pi = genPackage("xyz");
    +-        pi.applicationInfo.flags |= ApplicationInfo.FLAG_SYSTEM;
    +-        assertTrue(BackupUtils.signaturesMatch(stored1, pi));
    +-
    +-        // Non system apps.
    +-        assertTrue(BackupUtils.signaturesMatch(stored1, genPackage("abc")));
    +-
    +-        // Superset is okay.
    +-        assertTrue(BackupUtils.signaturesMatch(stored1, genPackage("abc", "xyz")));
    +-        assertTrue(BackupUtils.signaturesMatch(stored1, genPackage("xyz", "abc")));
    +-
    +-        assertFalse(BackupUtils.signaturesMatch(stored1, genPackage("xyz")));
    +-        assertFalse(BackupUtils.signaturesMatch(stored1, genPackage("xyz", "def")));
    +-
    +-        assertTrue(BackupUtils.signaturesMatch(stored2, genPackage("def", "abc")));
    +-        assertTrue(BackupUtils.signaturesMatch(stored2, genPackage("x", "def", "abc", "y")));
    +-
    +-        // Subset is not okay.
    +-        assertFalse(BackupUtils.signaturesMatch(stored2, genPackage("abc")));
    +-        assertFalse(BackupUtils.signaturesMatch(stored2, genPackage("def")));
    +-    }
    +-
    +-    public void testHashSignature() {
    +-        final byte[] sig1 = "abc".getBytes();
    +-        final byte[] sig2 = "def".getBytes();
    +-
    +-        final byte[] hash1a = BackupUtils.hashSignature(sig1);
    +-        final byte[] hash1b = BackupUtils.hashSignature(new Signature(sig1));
    +-
    +-        final byte[] hash2a = BackupUtils.hashSignature(sig2);
    +-        final byte[] hash2b = BackupUtils.hashSignature(new Signature(sig2));
    +-
    +-        assertEquals(32, hash1a.length);
    +-        MoreAsserts.assertEquals(hash1a, hash1b);
    +-
    +-        assertEquals(32, hash2a.length);
    +-        MoreAsserts.assertEquals(hash2a, hash2b);
    +-
    +-        assertFalse(Arrays.equals(hash1a, hash2a));
    +-
    +-        final ArrayList<byte[]> listA = BackupUtils.hashSignatureArray(Arrays.asList(
    +-                "abc".getBytes(), "def".getBytes()));
    +-
    +-        final ArrayList<byte[]> listB = BackupUtils.hashSignatureArray(new Signature[]{
    +-                new Signature("abc".getBytes()), new Signature("def".getBytes())});
    +-
    +-        assertEquals(2, listA.size());
    +-        assertEquals(2, listB.size());
    +-
    +-        MoreAsserts.assertEquals(hash1a, listA.get(0));
    +-        MoreAsserts.assertEquals(hash1a, listB.get(0));
    +-
    +-        MoreAsserts.assertEquals(hash2a, listA.get(1));
    +-        MoreAsserts.assertEquals(hash2a, listB.get(1));
    +-    }
    +-}
    +diff --git a/services/tests/servicestests/src/com/android/server/search/SearchablesTest.java b/services/tests/servicestests/src/com/android/server/search/SearchablesTest.java
    +deleted file mode 100644
    +index 0f9bf2f..0000000
    +--- a/services/tests/servicestests/src/com/android/server/search/SearchablesTest.java
    ++++ /dev/null
    +@@ -1,449 +0,0 @@
    +-/*
    +- * Copyright (C) 2009 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 com.android.server.search;
    +-
    +-import android.app.SearchManager;
    +-import android.app.SearchableInfo;
    +-import android.app.SearchableInfo.ActionKeyInfo;
    +-import android.content.ComponentName;
    +-import android.content.Context;
    +-import android.content.Intent;
    +-import android.content.pm.ActivityInfo;
    +-import android.content.pm.ApplicationInfo;
    +-import android.content.pm.PackageManager;
    +-import android.content.pm.ProviderInfo;
    +-import android.content.pm.ResolveInfo;
    +-import android.content.res.Resources;
    +-import android.content.res.XmlResourceParser;
    +-import android.os.RemoteException;
    +-import com.android.server.search.Searchables;
    +-import android.test.AndroidTestCase;
    +-import android.test.MoreAsserts;
    +-import android.test.mock.MockContext;
    +-import android.test.mock.MockPackageManager;
    +-import android.test.suitebuilder.annotation.SmallTest;
    +-import android.view.KeyEvent;
    +-
    +-import java.util.ArrayList;
    +-import java.util.List;
    +-
    +-/**
    +- * To launch this test from the command line:
    +- * 
    +- * adb shell am instrument -w \
    +- *   -e class com.android.unit_tests.SearchablesTest \
    +- *   com.android.unit_tests/android.test.InstrumentationTestRunner
    +- */
    +-@SmallTest
    +-public class SearchablesTest extends AndroidTestCase {
    +-    
    +-    /*
    +-     * SearchableInfo tests
    +-     *  Mock the context so I can provide very specific input data
    +-     *  Confirm OK with "zero" searchables
    +-     *  Confirm "good" metadata read properly
    +-     *  Confirm "bad" metadata skipped properly
    +-     *  Confirm ordering of searchables
    +-     *  Confirm "good" actionkeys
    +-     *  confirm "bad" actionkeys are rejected
    +-     *  confirm XML ordering enforced (will fail today - bug in SearchableInfo)
    +-     *  findActionKey works
    +-     *  getIcon works
    +-     */
    +-
    +-    /**
    +-     * Test that non-searchable activities return no searchable info (this would typically
    +-     * trigger the use of the default searchable e.g. contacts)
    +-     */
    +-    public void testNonSearchable() {
    +-        // test basic array & hashmap
    +-        Searchables searchables = new Searchables(mContext, 0);
    +-        searchables.updateSearchableList();
    +-
    +-        // confirm that we return null for non-searchy activities
    +-        ComponentName nonActivity = new ComponentName(
    +-                            "com.android.frameworks.coretests",
    +-                            "com.android.frameworks.coretests.activity.NO_SEARCH_ACTIVITY");
    +-        SearchableInfo si = searchables.getSearchableInfo(nonActivity);
    +-        assertNull(si);
    +-    }
    +-
    +-    /**
    +-     * This is an attempt to run the searchable info list with a mocked context.  Here are some
    +-     * things I'd like to test.
    +-     *
    +-     *  Confirm OK with "zero" searchables
    +-     *  Confirm "good" metadata read properly
    +-     *  Confirm "bad" metadata skipped properly
    +-     *  Confirm ordering of searchables
    +-     *  Confirm "good" actionkeys
    +-     *  confirm "bad" actionkeys are rejected
    +-     *  confirm XML ordering enforced (will fail today - bug in SearchableInfo)
    +-     *  findActionKey works
    +-     *  getIcon works
    +-
    +-     */
    +-    public void testSearchablesListReal() {
    +-        MyMockPackageManager mockPM = new MyMockPackageManager(mContext.getPackageManager());
    +-        MyMockContext mockContext = new MyMockContext(mContext, mockPM);
    +-
    +-        // build item list with real-world source data
    +-        mockPM.setSearchablesMode(MyMockPackageManager.SEARCHABLES_PASSTHROUGH);
    +-        Searchables searchables = new Searchables(mockContext, 0);
    +-        searchables.updateSearchableList();
    +-        // tests with "real" searchables (deprecate, this should be a unit test)
    +-        ArrayList<SearchableInfo> searchablesList = searchables.getSearchablesList();
    +-        int count = searchablesList.size();
    +-        assertTrue(count >= 1);         // this isn't really a unit test
    +-        checkSearchables(searchablesList);
    +-        ArrayList<SearchableInfo> global = searchables.getSearchablesInGlobalSearchList();
    +-        checkSearchables(global);
    +-    }
    +-
    +-    /**
    +-     * This round of tests confirms good operations with "zero" searchables found
    +-     */
    +-    public void testSearchablesListEmpty() {
    +-        MyMockPackageManager mockPM = new MyMockPackageManager(mContext.getPackageManager());
    +-        MyMockContext mockContext = new MyMockContext(mContext, mockPM);
    +-
    +-        mockPM.setSearchablesMode(MyMockPackageManager.SEARCHABLES_MOCK_ZERO);
    +-        Searchables searchables = new Searchables(mockContext, 0);
    +-        searchables.updateSearchableList();
    +-        ArrayList<SearchableInfo> searchablesList = searchables.getSearchablesList();
    +-        assertNotNull(searchablesList);
    +-        MoreAsserts.assertEmpty(searchablesList);
    +-        ArrayList<SearchableInfo> global = searchables.getSearchablesInGlobalSearchList();
    +-        MoreAsserts.assertEmpty(global);
    +-    }
    +-    
    +-    /**
    +-     * Generic health checker for an array of searchables.
    +-     * 
    +-     * This is designed to pass for any semi-legal searchable, without knowing much about
    +-     * the format of the underlying data.  It's fairly easy for a non-compliant application
    +-     * to provide meta-data that will pass here (e.g. a non-existent suggestions authority).
    +-     * 
    +-     * @param searchables The list of searchables to examine.
    +-     */
    +-    private void checkSearchables(ArrayList<SearchableInfo> searchablesList) {
    +-        assertNotNull(searchablesList);
    +-        int count = searchablesList.size();
    +-        for (int ii = 0; ii < count; ii++) {
    +-            SearchableInfo si = searchablesList.get(ii);
    +-            checkSearchable(si);
    +-        }
    +-    }
    +-    
    +-    private void checkSearchable(SearchableInfo si) {
    +-        assertNotNull(si);
    +-        assertTrue(si.getLabelId() != 0);        // This must be a useable string
    +-        assertNotEmpty(si.getSearchActivity().getClassName());
    +-        assertNotEmpty(si.getSearchActivity().getPackageName());
    +-        if (si.getSuggestAuthority() != null) {
    +-            // The suggestion fields are largely optional, so we'll just confirm basic health
    +-            assertNotEmpty(si.getSuggestAuthority());
    +-            assertNullOrNotEmpty(si.getSuggestPath());
    +-            assertNullOrNotEmpty(si.getSuggestSelection());
    +-            assertNullOrNotEmpty(si.getSuggestIntentAction());
    +-            assertNullOrNotEmpty(si.getSuggestIntentData());
    +-        }
    +-        /* Add a way to get the entire action key list, then explicitly test its elements */
    +-        /* For now, test the most common action key (CALL) */
    +-        ActionKeyInfo ai = si.findActionKey(KeyEvent.KEYCODE_CALL);
    +-        if (ai != null) {
    +-            assertEquals(ai.getKeyCode(), KeyEvent.KEYCODE_CALL);
    +-            // one of these three fields must be non-null & non-empty
    +-            boolean m1 = (ai.getQueryActionMsg() != null) && (ai.getQueryActionMsg().length() > 0);
    +-            boolean m2 = (ai.getSuggestActionMsg() != null) && (ai.getSuggestActionMsg().length() > 0);
    +-            boolean m3 = (ai.getSuggestActionMsgColumn() != null) && 
    +-                            (ai.getSuggestActionMsgColumn().length() > 0);
    +-            assertTrue(m1 || m2 || m3);
    +-        }
    +-        
    +-        /* 
    +-         * Find ways to test these:
    +-         * 
    +-         * private int mSearchMode
    +-         * private Drawable mIcon
    +-         */
    +-        
    +-        /*
    +-         * Explicitly not tested here:
    +-         * 
    +-         * Can be null, so not much to see:
    +-         * public String mSearchHint
    +-         * private String mZeroQueryBanner
    +-         * 
    +-         * To be deprecated/removed, so don't bother:
    +-         * public boolean mFilterMode
    +-         * public boolean mQuickStart
    +-         * private boolean mIconResized
    +-         * private int mIconResizeWidth
    +-         * private int mIconResizeHeight
    +-         * 
    +-         * All of these are "internal" working variables, not part of any contract
    +-         * private ActivityInfo mActivityInfo
    +-         * private Rect mTempRect
    +-         * private String mSuggestProviderPackage
    +-         * private String mCacheActivityContext
    +-         */
    +-    }
    +-    
    +-    /**
    +-     * Combo assert for "string not null and not empty"
    +-     */
    +-    private void assertNotEmpty(final String s) {
    +-        assertNotNull(s);
    +-        MoreAsserts.assertNotEqual(s, "");
    +-    }
    +-    
    +-    /**
    +-     * Combo assert for "string null or (not null and not empty)"
    +-     */
    +-    private void assertNullOrNotEmpty(final String s) {
    +-        if (s != null) {
    +-            MoreAsserts.assertNotEqual(s, "");
    +-        }
    +-    }    
    +-    
    +-    /**
    +-     * This is a mock for context.  Used to perform a true unit test on SearchableInfo.
    +-     * 
    +-     */
    +-    private class MyMockContext extends MockContext {
    +-        
    +-        protected Context mRealContext;
    +-        protected PackageManager mPackageManager;
    +-        
    +-        /**
    +-         * Constructor.
    +-         * 
    +-         * @param realContext Please pass in a real context for some pass-throughs to function.
    +-         */
    +-        MyMockContext(Context realContext, PackageManager packageManager) {
    +-            mRealContext = realContext;
    +-            mPackageManager = packageManager;
    +-        }
    +-        
    +-        /**
    +-         * Resources.  Pass through for now.
    +-         */
    +-        @Override
    +-        public Resources getResources() {
    +-            return mRealContext.getResources();
    +-        }
    +-
    +-        /**
    +-         * Package manager.  Pass through for now.
    +-         */
    +-        @Override
    +-        public PackageManager getPackageManager() {
    +-            return mPackageManager;
    +-        }
    +-
    +-        /**
    +-         * Package manager.  Pass through for now.
    +-         */
    +-        @Override
    +-        public Context createPackageContext(String packageName, int flags)
    +-                throws PackageManager.NameNotFoundException {
    +-            return mRealContext.createPackageContext(packageName, flags);
    +-        }
    +-
    +-        /**
    +-         * Message broadcast.  Pass through for now.
    +-         */
    +-        @Override
    +-        public void sendBroadcast(Intent intent) {
    +-            mRealContext.sendBroadcast(intent);
    +-        }
    +-    }
    +-
    +-/**
    +- * This is a mock for package manager.  Used to perform a true unit test on SearchableInfo.
    +- * 
    +- */
    +-    private class MyMockPackageManager extends MockPackageManager {
    +-        
    +-        public final static int SEARCHABLES_PASSTHROUGH = 0;
    +-        public final static int SEARCHABLES_MOCK_ZERO = 1;
    +-        public final static int SEARCHABLES_MOCK_ONEGOOD = 2;
    +-        public final static int SEARCHABLES_MOCK_ONEGOOD_ONEBAD = 3;
    +-        
    +-        protected PackageManager mRealPackageManager;
    +-        protected int mSearchablesMode;
    +-
    +-        public MyMockPackageManager(PackageManager realPM) {
    +-            mRealPackageManager = realPM;
    +-            mSearchablesMode = SEARCHABLES_PASSTHROUGH;
    +-        }
    +-
    +-        /**
    +-         * Set the mode for various tests.
    +-         */
    +-        public void setSearchablesMode(int newMode) {
    +-            switch (newMode) {
    +-            case SEARCHABLES_PASSTHROUGH:
    +-            case SEARCHABLES_MOCK_ZERO:
    +-                mSearchablesMode = newMode;
    +-                break;
    +-                
    +-            default:
    +-                throw new UnsupportedOperationException();       
    +-            }
    +-        }
    +-        
    +-        /**
    +-         * Find activities that support a given intent.
    +-         * 
    +-         * Retrieve all activities that can be performed for the given intent.
    +-         * 
    +-         * @param intent The desired intent as per resolveActivity().
    +-         * @param flags Additional option flags.  The most important is
    +-         *                    MATCH_DEFAULT_ONLY, to limit the resolution to only
    +-         *                    those activities that support the CATEGORY_DEFAULT.
    +-         * 
    +-         * @return A List<ResolveInfo> containing one entry for each matching
    +-         *         Activity. These are ordered from best to worst match -- that
    +-         *         is, the first item in the list is what is returned by
    +-         *         resolveActivity().  If there are no matching activities, an empty
    +-         *         list is returned.
    +-         */
    +-        @Override 
    +-        public List<ResolveInfo> queryIntentActivities(Intent intent, int flags) {
    +-            assertNotNull(intent);
    +-            assertTrue(intent.getAction().equals(Intent.ACTION_SEARCH)
    +-                    || intent.getAction().equals(Intent.ACTION_WEB_SEARCH)
    +-                    || intent.getAction().equals(SearchManager.INTENT_ACTION_GLOBAL_SEARCH));
    +-            switch (mSearchablesMode) {
    +-            case SEARCHABLES_PASSTHROUGH:
    +-                return mRealPackageManager.queryIntentActivities(intent, flags);
    +-            case SEARCHABLES_MOCK_ZERO:
    +-                return null;
    +-            default:
    +-                throw new UnsupportedOperationException();
    +-            }
    +-        }
    +-        
    +-        @Override
    +-        public ResolveInfo resolveActivity(Intent intent, int flags) {
    +-            assertNotNull(intent);
    +-            assertTrue(intent.getAction().equals(Intent.ACTION_WEB_SEARCH)
    +-                    || intent.getAction().equals(SearchManager.INTENT_ACTION_GLOBAL_SEARCH));
    +-            switch (mSearchablesMode) {
    +-            case SEARCHABLES_PASSTHROUGH:
    +-                return mRealPackageManager.resolveActivity(intent, flags);
    +-            case SEARCHABLES_MOCK_ZERO:
    +-                return null;
    +-            default:
    +-                throw new UnsupportedOperationException();
    +-            }
    +-        }
    +-
    +-        /**
    +-         * Retrieve an XML file from a package.  This is a low-level API used to
    +-         * retrieve XML meta data.
    +-         * 
    +-         * @param packageName The name of the package that this xml is coming from.
    +-         * Can not be null.
    +-         * @param resid The resource identifier of the desired xml.  Can not be 0.
    +-         * @param appInfo Overall information about <var>packageName</var>.  This
    +-         * may be null, in which case the application information will be retrieved
    +-         * for you if needed; if you already have this information around, it can
    +-         * be much more efficient to supply it here.
    +-         * 
    +-         * @return Returns an XmlPullParser allowing you to parse out the XML
    +-         * data.  Returns null if the xml resource could not be found for any
    +-         * reason.
    +-         */
    +-        @Override 
    +-        public XmlResourceParser getXml(String packageName, int resid, ApplicationInfo appInfo) {
    +-            assertNotNull(packageName);
    +-            MoreAsserts.assertNotEqual(packageName, "");
    +-            MoreAsserts.assertNotEqual(resid, 0);
    +-            switch (mSearchablesMode) {
    +-            case SEARCHABLES_PASSTHROUGH:
    +-                return mRealPackageManager.getXml(packageName, resid, appInfo);
    +-            case SEARCHABLES_MOCK_ZERO:
    +-            default:
    +-                throw new UnsupportedOperationException();
    +-            }
    +-        }
    +-        
    +-        /**
    +-         * Find a single content provider by its base path name.
    +-         * 
    +-         * @param name The name of the provider to find.
    +-         * @param flags Additional option flags.  Currently should always be 0.
    +-         * 
    +-         * @return ContentProviderInfo Information about the provider, if found,
    +-         *         else null.
    +-         */
    +-        @Override 
    +-        public ProviderInfo resolveContentProvider(String name, int flags) {
    +-            assertNotNull(name);
    +-            MoreAsserts.assertNotEqual(name, "");
    +-            assertEquals(flags, 0);
    +-            switch (mSearchablesMode) {
    +-            case SEARCHABLES_PASSTHROUGH:
    +-                return mRealPackageManager.resolveContentProvider(name, flags);
    +-            case SEARCHABLES_MOCK_ZERO:
    +-            default:
    +-                throw new UnsupportedOperationException();
    +-            }
    +-        }
    +-
    +-        /**
    +-         * Get the activity information for a particular activity.
    +-         *
    +-         * @param name The name of the activity to find.
    +-         * @param flags Additional option flags.
    +-         *
    +-         * @return ActivityInfo Information about the activity, if found, else null.
    +-         */
    +-        @Override
    +-        public ActivityInfo getActivityInfo(ComponentName name, int flags)
    +-                throws NameNotFoundException {
    +-            assertNotNull(name);
    +-            MoreAsserts.assertNotEqual(name, "");
    +-            switch (mSearchablesMode) {
    +-            case SEARCHABLES_PASSTHROUGH:
    +-                return mRealPackageManager.getActivityInfo(name, flags);
    +-            case SEARCHABLES_MOCK_ZERO:
    +-                throw new NameNotFoundException();
    +-            default:
    +-                throw new UnsupportedOperationException();
    +-            }
    +-        }
    +-
    +-        @Override
    +-        public int checkPermission(String permName, String pkgName) {
    +-            assertNotNull(permName);
    +-            assertNotNull(pkgName);
    +-            switch (mSearchablesMode) {
    +-                case SEARCHABLES_PASSTHROUGH:
    +-                    return mRealPackageManager.checkPermission(permName, pkgName);
    +-                case SEARCHABLES_MOCK_ZERO:
    +-                    return PackageManager.PERMISSION_DENIED;
    +-                default:
    +-                    throw new UnsupportedOperationException();
    +-                }
    +-        }
    +-    }
    +-}
    +-
    +diff --git a/services/tests/servicestests/src/com/android/server/testutis/TestUtils.java b/services/tests/servicestests/src/com/android/server/testutis/TestUtils.java
    +deleted file mode 100644
    +index d2a4484..0000000
    +--- a/services/tests/servicestests/src/com/android/server/testutis/TestUtils.java
    ++++ /dev/null
    +@@ -1,42 +0,0 @@
    +-/*
    +- * Copyright (C) 2016 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 com.android.server.testutis;
    +-
    +-import android.test.MoreAsserts;
    +-
    +-import junit.framework.Assert;
    +-
    +-public class TestUtils {
    +-    private TestUtils() {
    +-    }
    +-
    +-    public static void assertExpectException(Class<? extends Throwable> expectedExceptionType,
    +-            String expectedExceptionMessageRegex, Runnable r) {
    +-        try {
    +-            r.run();
    +-            Assert.fail("Expected exception type " + expectedExceptionType.getName()
    +-                    + " was not thrown");
    +-        } catch (Throwable e) {
    +-            Assert.assertTrue(
    +-                    "Expected exception type was " + expectedExceptionType.getName()
    +-                    + " but caught " + e.getClass().getName(),
    +-                    expectedExceptionType.isAssignableFrom(e.getClass()));
    +-            if (expectedExceptionMessageRegex != null) {
    +-                MoreAsserts.assertContainsRegex(expectedExceptionMessageRegex, e.getMessage());
    +-            }
    +-        }
    +-    }
    +-}
    +diff --git a/services/tests/servicestests/src/com/android/server/updates/CertPinInstallReceiverTest.java b/services/tests/servicestests/src/com/android/server/updates/CertPinInstallReceiverTest.java
    +deleted file mode 100644
    +index d798518..0000000
    +--- a/services/tests/servicestests/src/com/android/server/updates/CertPinInstallReceiverTest.java
    ++++ /dev/null
    +@@ -1,245 +0,0 @@
    +-/*
    +- * Copyright (C) 2012 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 com.android.server.updates;
    +-
    +-import com.android.internal.util.HexDump;
    +-
    +-import android.content.Context;
    +-import android.content.Intent;
    +-import android.test.AndroidTestCase;
    +-import android.provider.Settings;
    +-import android.util.Base64;
    +-import android.util.Log;
    +-
    +-import java.io.ByteArrayInputStream;
    +-import java.io.File;
    +-import java.io.FileInputStream;
    +-import java.io.FileOutputStream;
    +-import java.io.FileWriter;
    +-import java.io.IOException;
    +-import java.io.InputStream;
    +-import java.security.cert.CertificateFactory;
    +-import java.security.cert.Certificate;
    +-import java.security.cert.X509Certificate;
    +-import java.security.MessageDigest;
    +-import java.security.NoSuchAlgorithmException;
    +-import java.security.PrivateKey;
    +-import java.security.Signature;
    +-import java.security.spec.PKCS8EncodedKeySpec;
    +-import java.security.KeyFactory;
    +-import java.util.HashSet;
    +-import java.io.*;
    +-import libcore.io.IoUtils;
    +-
    +-/**
    +- * Tests for {@link com.android.server.CertPinInstallReceiver}
    +- */
    +-public class CertPinInstallReceiverTest extends AndroidTestCase {
    +-
    +-    private static final String TAG = "CertPinInstallReceiverTest";
    +-
    +-    private static final String PINLIST_ROOT = System.getenv("ANDROID_DATA") + "/misc/keychain/";
    +-
    +-    public static final String PINLIST_CONTENT_PATH = PINLIST_ROOT + "pins";
    +-    public static final String PINLIST_METADATA_PATH = PINLIST_CONTENT_PATH + "metadata";
    +-
    +-    public static final String PINLIST_CONTENT_URL_KEY = "pinlist_content_url";
    +-    public static final String PINLIST_METADATA_URL_KEY = "pinlist_metadata_url";
    +-    public static final String PINLIST_CERTIFICATE_KEY = "config_update_certificate";
    +-    public static final String PINLIST_VERSION_KEY = "pinlist_version";
    +-
    +-    private static final String EXTRA_CONTENT_PATH = "CONTENT_PATH";
    +-    private static final String EXTRA_REQUIRED_HASH = "REQUIRED_HASH";
    +-    private static final String EXTRA_SIGNATURE = "SIGNATURE";
    +-    private static final String EXTRA_VERSION_NUMBER = "VERSION";
    +-
    +-    public static final String TEST_CERT = "" +
    +-                    "MIIDsjCCAxugAwIBAgIJAPLf2gS0zYGUMA0GCSqGSIb3DQEBBQUAMIGYMQswCQYDVQQGEwJVUzET" +
    +-                    "MBEGA1UECBMKQ2FsaWZvcm5pYTEWMBQGA1UEBxMNTW91bnRhaW4gVmlldzEPMA0GA1UEChMGR29v" +
    +-                    "Z2xlMRAwDgYDVQQLEwd0ZXN0aW5nMRYwFAYDVQQDEw1HZXJlbXkgQ29uZHJhMSEwHwYJKoZIhvcN" +
    +-                    "AQkBFhJnY29uZHJhQGdvb2dsZS5jb20wHhcNMTIwNzE0MTc1MjIxWhcNMTIwODEzMTc1MjIxWjCB" +
    +-                    "mDELMAkGA1UEBhMCVVMxEzARBgNVBAgTCkNhbGlmb3JuaWExFjAUBgNVBAcTDU1vdW50YWluIFZp" +
    +-                    "ZXcxDzANBgNVBAoTBkdvb2dsZTEQMA4GA1UECxMHdGVzdGluZzEWMBQGA1UEAxMNR2VyZW15IENv" +
    +-                    "bmRyYTEhMB8GCSqGSIb3DQEJARYSZ2NvbmRyYUBnb29nbGUuY29tMIGfMA0GCSqGSIb3DQEBAQUA" +
    +-                    "A4GNADCBiQKBgQCjGGHATBYlmas+0sEECkno8LZ1KPglb/mfe6VpCT3GhSr+7br7NG/ZwGZnEhLq" +
    +-                    "E7YIH4fxltHmQC3Tz+jM1YN+kMaQgRRjo/LBCJdOKaMwUbkVynAH6OYsKevjrOPk8lfM5SFQzJMG" +
    +-                    "sA9+Tfopr5xg0BwZ1vA/+E3mE7Tr3M2UvwIDAQABo4IBADCB/TAdBgNVHQ4EFgQUhzkS9E6G+x8W" +
    +-                    "L4EsmRjDxu28tHUwgc0GA1UdIwSBxTCBwoAUhzkS9E6G+x8WL4EsmRjDxu28tHWhgZ6kgZswgZgx" +
    +-                    "CzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpDYWxpZm9ybmlhMRYwFAYDVQQHEw1Nb3VudGFpbiBWaWV3" +
    +-                    "MQ8wDQYDVQQKEwZHb29nbGUxEDAOBgNVBAsTB3Rlc3RpbmcxFjAUBgNVBAMTDUdlcmVteSBDb25k" +
    +-                    "cmExITAfBgkqhkiG9w0BCQEWEmdjb25kcmFAZ29vZ2xlLmNvbYIJAPLf2gS0zYGUMAwGA1UdEwQF" +
    +-                    "MAMBAf8wDQYJKoZIhvcNAQEFBQADgYEAYiugFDmbDOQ2U/+mqNt7o8ftlEo9SJrns6O8uTtK6AvR" +
    +-                    "orDrR1AXTXkuxwLSbmVfedMGOZy7Awh7iZa8hw5x9XmUudfNxvmrKVEwGQY2DZ9PXbrnta/dwbhK" +
    +-                    "mWfoepESVbo7CKIhJp8gRW0h1Z55ETXD57aGJRvQS4pxkP8ANhM=";
    +-
    +-
    +-    public static final String TEST_KEY = "" +
    +-                    "MIICdgIBADANBgkqhkiG9w0BAQEFAASCAmAwggJcAgEAAoGBAKMYYcBMFiWZqz7SwQQKSejwtnUo" +
    +-                    "+CVv+Z97pWkJPcaFKv7tuvs0b9nAZmcSEuoTtggfh/GW0eZALdPP6MzVg36QxpCBFGOj8sEIl04p" +
    +-                    "ozBRuRXKcAfo5iwp6+Os4+TyV8zlIVDMkwawD35N+imvnGDQHBnW8D/4TeYTtOvczZS/AgMBAAEC" +
    +-                    "gYBxwFalNSwZK3WJipq+g6KLCiBn1JxGGDQlLKrweFaSuFyFky9fd3IvkIabirqQchD612sMb+GT" +
    +-                    "0t1jptW6z4w2w6++IW0A3apDOCwoD+uvDBXrbFqI0VbyAWUNqHVdaFFIRk2IHGEE6463mGRdmILX" +
    +-                    "IlCd/85RTHReg4rl/GFqWQJBANgLAIR4pWbl5Gm+DtY18wp6Q3pJAAMkmP/lISCBIidu1zcqYIKt" +
    +-                    "PoDW4Knq9xnhxPbXrXKv4YzZWHBK8GkKhQ0CQQDBQnXufQcMew+PwiS0oJvS+eQ6YJwynuqG2ejg" +
    +-                    "WE+T7489jKtscRATpUXpZUYmDLGg9bLt7L62hFvFSj2LO2X7AkBcdrD9AWnBFWlh/G77LVHczSEu" +
    +-                    "KCoyLiqxcs5vy/TjLaQ8vw1ZQG580/qJnr+tOxyCjSJ18GK3VppsTRaBznfNAkB3nuCKNp9HTWCL" +
    +-                    "dfrsRsFMrFpk++mSt6SoxXaMbn0LL2u1CD4PCEiQMGt+lK3/3TmRTKNs+23sYS7Ahjxj0udDAkEA" +
    +-                    "p57Nj65WNaWeYiOfTwKXkLj8l29H5NbaGWxPT0XkWr4PvBOFZVH/wj0/qc3CMVGnv11+DyO+QUCN" +
    +-                    "SqBB5aRe8g==";
    +-
    +-    private void overrideSettings(String key, String value) throws Exception {
    +-        assertTrue(Settings.Secure.putString(mContext.getContentResolver(), key, value));
    +-        Thread.sleep(1000);
    +-    }
    +-
    +-    private void overrideCert(String value) throws Exception {
    +-        overrideSettings(PINLIST_CERTIFICATE_KEY, value);
    +-    }
    +-
    +-    private String readPins() throws Exception {
    +-        return IoUtils.readFileAsString(PINLIST_CONTENT_PATH);
    +-    }
    +-
    +-    private String readCurrentVersion() throws Exception {
    +-        return IoUtils.readFileAsString("/data/misc/keychain/metadata/version");
    +-    }
    +-
    +-    private String getNextVersion() throws Exception {
    +-        int currentVersion = Integer.parseInt(readCurrentVersion());
    +-        return Integer.toString(currentVersion + 1);
    +-    }
    +-
    +-    private static String getCurrentHash(String content) throws Exception {
    +-        if (content == null) {
    +-            return "0";
    +-        }
    +-        MessageDigest dgst = MessageDigest.getInstance("SHA512");
    +-        byte[] encoded = content.getBytes();
    +-        byte[] fingerprint = dgst.digest(encoded);
    +-        return HexDump.toHexString(fingerprint, false);
    +-    }
    +-
    +-    private static String getHashOfCurrentContent() throws Exception {
    +-        String content = IoUtils.readFileAsString("/data/misc/keychain/pins");
    +-        return getCurrentHash(content);
    +-    }
    +-
    +-    private PrivateKey createKey() throws Exception {
    +-        byte[] derKey = Base64.decode(TEST_KEY.getBytes(), Base64.DEFAULT);
    +-        PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(derKey);
    +-        KeyFactory keyFactory = KeyFactory.getInstance("RSA");
    +-        return (PrivateKey) keyFactory.generatePrivate(keySpec);
    +-    }
    +-
    +-    private X509Certificate createCertificate() throws Exception {
    +-        byte[] derCert = Base64.decode(TEST_CERT.getBytes(), Base64.DEFAULT);
    +-        InputStream istream = new ByteArrayInputStream(derCert);
    +-        CertificateFactory cf = CertificateFactory.getInstance("X.509");
    +-        return (X509Certificate) cf.generateCertificate(istream);
    +-    }
    +-
    +-    private String makeTemporaryContentFile(String content) throws Exception {
    +-        FileOutputStream fw = mContext.openFileOutput("content.txt", mContext.MODE_WORLD_READABLE);
    +-        fw.write(content.getBytes(), 0, content.length());
    +-        fw.close();
    +-        return mContext.getFilesDir() + "/content.txt";
    +-    }
    +-
    +-    private String createSignature(String content, String version, String requiredHash)
    +-                                   throws Exception {
    +-        Signature signer = Signature.getInstance("SHA512withRSA");
    +-        signer.initSign(createKey());
    +-        signer.update(content.trim().getBytes());
    +-        signer.update(version.trim().getBytes());
    +-        signer.update(requiredHash.getBytes());
    +-        String sig = new String(Base64.encode(signer.sign(), Base64.DEFAULT));
    +-        assertEquals(true,
    +-                     verifySignature(content, version, requiredHash, sig, createCertificate()));
    +-        return sig;
    +-    }
    +-
    +-    public boolean verifySignature(String content, String version, String requiredPrevious,
    +-                                   String signature, X509Certificate cert) throws Exception {
    +-        Signature signer = Signature.getInstance("SHA512withRSA");
    +-        signer.initVerify(cert);
    +-        signer.update(content.trim().getBytes());
    +-        signer.update(version.trim().getBytes());
    +-        signer.update(requiredPrevious.trim().getBytes());
    +-        return signer.verify(Base64.decode(signature.getBytes(), Base64.DEFAULT));
    +-    }
    +-
    +-    private void sendIntent(String contentPath, String version, String required, String sig) {
    +-        Intent i = new Intent();
    +-        i.setAction("android.intent.action.UPDATE_PINS");
    +-        i.putExtra(EXTRA_CONTENT_PATH, contentPath);
    +-        i.putExtra(EXTRA_VERSION_NUMBER, version);
    +-        i.putExtra(EXTRA_REQUIRED_HASH, required);
    +-        i.putExtra(EXTRA_SIGNATURE, sig);
    +-        mContext.sendBroadcast(i);
    +-    }
    +-
    +-    private String runTest(String cert, String content, String version, String required, String sig)
    +-                           throws Exception {
    +-        Log.e(TAG, "started test");
    +-        overrideCert(cert);
    +-        String contentPath = makeTemporaryContentFile(content);
    +-        sendIntent(contentPath, version, required, sig);
    +-        Thread.sleep(1000);
    +-        return readPins();
    +-    }
    +-
    +-    private String runTestWithoutSig(String cert, String content, String version, String required)
    +-                                     throws Exception {
    +-        String sig = createSignature(content, version, required);
    +-        return runTest(cert, content, version, required, sig);
    +-    }
    +-
    +-    public void testOverwritePinlist() throws Exception {
    +-        Log.e(TAG, "started testOverwritePinList");
    +-        assertEquals("abcde", runTestWithoutSig(TEST_CERT, "abcde", getNextVersion(), getHashOfCurrentContent()));
    +-        Log.e(TAG, "started testOverwritePinList");
    +-    }
    +-
    +-   public void testBadSignatureFails() throws Exception {
    +-        Log.e(TAG, "started testOverwritePinList");
    +-        String text = "blahblah";
    +-        runTestWithoutSig(TEST_CERT, text, getNextVersion(), getHashOfCurrentContent());
    +-        assertEquals(text, runTest(TEST_CERT, "bcdef", getNextVersion(), getCurrentHash(text), ""));
    +-        Log.e(TAG, "started testOverwritePinList");
    +-    }
    +-
    +-    public void testBadRequiredHashFails() throws Exception {
    +-        runTestWithoutSig(TEST_CERT, "blahblahblah", getNextVersion(), getHashOfCurrentContent());
    +-        assertEquals("blahblahblah", runTestWithoutSig(TEST_CERT, "cdefg", getNextVersion(), "0"));
    +-        Log.e(TAG, "started testOverwritePinList");
    +-    }
    +-
    +-    public void testBadVersionFails() throws Exception {
    +-        String text = "blahblahblahblah";
    +-        String version = getNextVersion();
    +-        runTestWithoutSig(TEST_CERT, text, version, getHashOfCurrentContent());
    +-        assertEquals(text, runTestWithoutSig(TEST_CERT, "defgh", version, getCurrentHash(text)));
    +-        Log.e(TAG, "started testOverwritePinList");
    +-    }
    +-
    +-    public void testOverrideRequiredHash() throws Exception {
    +-        runTestWithoutSig(TEST_CERT, "blahblahblah", getNextVersion(), getHashOfCurrentContent());
    +-        assertEquals("blahblahblah", runTestWithoutSig(TEST_CERT, "cdefg", "NONE", "0"));
    +-        Log.e(TAG, "started testOverwritePinList");
    +-    }
    +-
    +-}
    +diff --git a/services/tests/servicestests/src/com/android/server/usage/AppIdleHistoryTests.java b/services/tests/servicestests/src/com/android/server/usage/AppIdleHistoryTests.java
    +deleted file mode 100644
    +index 0bd014c..0000000
    +--- a/services/tests/servicestests/src/com/android/server/usage/AppIdleHistoryTests.java
    ++++ /dev/null
    +@@ -1,100 +0,0 @@
    +-/*
    +- * Copyright (C) 2016 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 com.android.server.usage;
    +-
    +-import android.os.FileUtils;
    +-import android.test.AndroidTestCase;
    +-
    +-import java.io.File;
    +-
    +-public class AppIdleHistoryTests extends AndroidTestCase {
    +-
    +-    File mStorageDir;
    +-
    +-    final static String PACKAGE_1 = "com.android.testpackage1";
    +-    final static String PACKAGE_2 = "com.android.testpackage2";
    +-
    +-    @Override
    +-    protected void setUp() throws Exception {
    +-        super.setUp();
    +-        mStorageDir = new File(getContext().getFilesDir(), "appidle");
    +-        mStorageDir.mkdirs();
    +-    }
    +-
    +-    @Override
    +-    protected void tearDown() throws Exception {
    +-        FileUtils.deleteContents(mStorageDir);
    +-        super.tearDown();
    +-    }
    +-
    +-    public void testFilesCreation() {
    +-        final int userId = 0;
    +-        AppIdleHistory aih = new AppIdleHistory(mStorageDir, 0);
    +-
    +-        aih.updateDisplayLocked(true, /* elapsedRealtime= */ 1000);
    +-        aih.updateDisplayLocked(false, /* elapsedRealtime= */ 2000);
    +-        // Screen On time file should be written right away
    +-        assertTrue(aih.getScreenOnTimeFile().exists());
    +-
    +-        aih.writeAppIdleTimesLocked(userId);
    +-        // stats file should be written now
    +-        assertTrue(new File(new File(mStorageDir, "users/" + userId),
    +-                AppIdleHistory.APP_IDLE_FILENAME).exists());
    +-    }
    +-
    +-    public void testScreenOnTime() {
    +-        AppIdleHistory aih = new AppIdleHistory(mStorageDir, 1000);
    +-        aih.updateDisplayLocked(false, 2000);
    +-        assertEquals(aih.getScreenOnTimeLocked(2000), 0);
    +-        aih.updateDisplayLocked(true, 3000);
    +-        assertEquals(aih.getScreenOnTimeLocked(4000), 1000);
    +-        assertEquals(aih.getScreenOnTimeLocked(5000), 2000);
    +-        aih.updateDisplayLocked(false, 6000);
    +-        // Screen on time should not keep progressing with screen is off
    +-        assertEquals(aih.getScreenOnTimeLocked(7000), 3000);
    +-        assertEquals(aih.getScreenOnTimeLocked(8000), 3000);
    +-        aih.writeAppIdleDurationsLocked();
    +-
    +-        // Check if the screen on time is persisted across instantiations
    +-        AppIdleHistory aih2 = new AppIdleHistory(mStorageDir, 0);
    +-        assertEquals(aih2.getScreenOnTimeLocked(11000), 3000);
    +-        aih2.updateDisplayLocked(true, 4000);
    +-        aih2.updateDisplayLocked(false, 5000);
    +-        assertEquals(aih2.getScreenOnTimeLocked(13000), 4000);
    +-    }
    +-
    +-    public void testPackageEvents() {
    +-        AppIdleHistory aih = new AppIdleHistory(mStorageDir, 1000);
    +-        aih.setThresholds(4000, 1000);
    +-        aih.updateDisplayLocked(true, 1000);
    +-        // App is not-idle by default
    +-        assertFalse(aih.isIdleLocked(PACKAGE_1, 0, 1500));
    +-        // Still not idle
    +-        assertFalse(aih.isIdleLocked(PACKAGE_1, 0, 3000));
    +-        // Idle now
    +-        assertTrue(aih.isIdleLocked(PACKAGE_1, 0, 8000));
    +-        // Not idle
    +-        assertFalse(aih.isIdleLocked(PACKAGE_2, 0, 9000));
    +-
    +-        // Screen off
    +-        aih.updateDisplayLocked(false, 9100);
    +-        // Still idle after 10 seconds because screen hasn't been on long enough
    +-        assertFalse(aih.isIdleLocked(PACKAGE_2, 0, 20000));
    +-        aih.updateDisplayLocked(true, 21000);
    +-        assertTrue(aih.isIdleLocked(PACKAGE_2, 0, 23000));
    +-    }
    +-}
    +\ No newline at end of file
    +diff --git a/services/tests/servicestests/src/com/android/server/webkit/TestSystemImpl.java b/services/tests/servicestests/src/com/android/server/webkit/TestSystemImpl.java
    +deleted file mode 100644
    +index e33be40..0000000
    +--- a/services/tests/servicestests/src/com/android/server/webkit/TestSystemImpl.java
    ++++ /dev/null
    +@@ -1,116 +0,0 @@
    +-/*
    +- * Copyright (C) 2016 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 com.android.server.webkit;
    +-
    +-import android.content.Context;
    +-import android.content.pm.PackageInfo;
    +-import android.content.pm.PackageManager.NameNotFoundException;
    +-import android.webkit.WebViewProviderInfo;
    +-
    +-import java.util.HashMap;
    +-
    +-public class TestSystemImpl implements SystemInterface {
    +-    private String mUserProvider = null;
    +-    private final WebViewProviderInfo[] mPackageConfigs;
    +-    HashMap<String, PackageInfo> mPackages = new HashMap();
    +-    private boolean mFallbackLogicEnabled;
    +-    private final int mNumRelros;
    +-    private final boolean mIsDebuggable;
    +-
    +-    public TestSystemImpl(WebViewProviderInfo[] packageConfigs, boolean fallbackLogicEnabled,
    +-            int numRelros, boolean isDebuggable) {
    +-        mPackageConfigs = packageConfigs;
    +-        mFallbackLogicEnabled = fallbackLogicEnabled;
    +-        mNumRelros = numRelros;
    +-        mIsDebuggable = isDebuggable;
    +-    }
    +-
    +-    @Override
    +-    public WebViewProviderInfo[] getWebViewPackages() {
    +-        return mPackageConfigs;
    +-    }
    +-
    +-    @Override
    +-    public int onWebViewProviderChanged(PackageInfo packageInfo) {
    +-        return mNumRelros;
    +-    }
    +-
    +-    @Override
    +-    public String getUserChosenWebViewProvider(Context context) { return mUserProvider; }
    +-
    +-    @Override
    +-    public void updateUserSetting(Context context, String newProviderName) {
    +-        mUserProvider = newProviderName;
    +-    }
    +-
    +-    @Override
    +-    public void killPackageDependents(String packageName) {}
    +-
    +-    @Override
    +-    public boolean isFallbackLogicEnabled() {
    +-        return mFallbackLogicEnabled;
    +-    }
    +-
    +-    @Override
    +-    public void enableFallbackLogic(boolean enable) {
    +-        mFallbackLogicEnabled = enable;
    +-    }
    +-
    +-    @Override
    +-    public void uninstallAndDisablePackageForAllUsers(Context context, String packageName) {
    +-        enablePackageForAllUsers(context, packageName, false);
    +-    }
    +-
    +-    @Override
    +-    public void enablePackageForAllUsers(Context context, String packageName, boolean enable) {
    +-        enablePackageForUser(packageName, enable, 0);
    +-    }
    +-
    +-    @Override
    +-    public void enablePackageForUser(String packageName, boolean enable, int userId) {
    +-        PackageInfo packageInfo = mPackages.get(packageName);
    +-        if (packageInfo == null) {
    +-            throw new IllegalArgumentException("There is no package called " + packageName);
    +-        }
    +-        packageInfo.applicationInfo.enabled = enable;
    +-        setPackageInfo(packageInfo);
    +-    }
    +-
    +-    @Override
    +-    public boolean systemIsDebuggable() { return mIsDebuggable; }
    +-
    +-    @Override
    +-    public PackageInfo getPackageInfoForProvider(WebViewProviderInfo info) throws
    +-            NameNotFoundException {
    +-        PackageInfo ret = mPackages.get(info.packageName);
    +-        if (ret == null) throw new NameNotFoundException(info.packageName);
    +-        return ret;
    +-    }
    +-
    +-    public void setPackageInfo(PackageInfo pi) {
    +-        mPackages.put(pi.packageName, pi);
    +-    }
    +-
    +-    public void removePackageInfo(String packageName) {
    +-        mPackages.remove(packageName);
    +-    }
    +-
    +-    @Override
    +-    public int getFactoryPackageVersion(String packageName) {
    +-        return 0;
    +-    }
    +-}
    +diff --git a/services/tests/servicestests/src/com/android/server/webkit/WebViewUpdateServiceTest.java b/services/tests/servicestests/src/com/android/server/webkit/WebViewUpdateServiceTest.java
    +deleted file mode 100644
    +index b737033..0000000
    +--- a/services/tests/servicestests/src/com/android/server/webkit/WebViewUpdateServiceTest.java
    ++++ /dev/null
    +@@ -1,1074 +0,0 @@
    +-/*
    +- * Copyright (C) 2016 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 com.android.server.webkit;
    +-
    +-import android.content.Context;
    +-import android.content.pm.ApplicationInfo;
    +-import android.content.pm.PackageInfo;
    +-import android.content.pm.Signature;
    +-import android.os.Bundle;
    +-import android.util.Base64;
    +-import android.test.AndroidTestCase;
    +-
    +-import android.webkit.WebViewFactory;
    +-import android.webkit.WebViewProviderInfo;
    +-import android.webkit.WebViewProviderResponse;
    +-
    +-import java.util.concurrent.CountDownLatch;
    +-
    +-import org.hamcrest.Description;
    +-
    +-import org.mockito.Mockito;
    +-import org.mockito.Matchers;
    +-import org.mockito.ArgumentMatcher;
    +-
    +-
    +-/**
    +- * Tests for WebViewUpdateService
    +- */
    +-public class WebViewUpdateServiceTest extends AndroidTestCase {
    +-    private final static String TAG = WebViewUpdateServiceTest.class.getSimpleName();
    +-
    +-    private WebViewUpdateServiceImpl mWebViewUpdateServiceImpl;
    +-    private TestSystemImpl mTestSystemImpl;
    +-
    +-    private static final String WEBVIEW_LIBRARY_FLAG = "com.android.webview.WebViewLibrary";
    +-
    +-    @Override
    +-    protected void setUp() throws Exception {
    +-        super.setUp();
    +-    }
    +-
    +-    /**
    +-     * Creates a new instance.
    +-     */
    +-    public WebViewUpdateServiceTest() {
    +-    }
    +-
    +-    private void setupWithPackages(WebViewProviderInfo[] packages) {
    +-        setupWithPackages(packages, true);
    +-    }
    +-
    +-    private void setupWithPackages(WebViewProviderInfo[] packages,
    +-            boolean fallbackLogicEnabled) {
    +-        setupWithPackages(packages, fallbackLogicEnabled, 1);
    +-    }
    +-
    +-    private void setupWithPackages(WebViewProviderInfo[] packages,
    +-            boolean fallbackLogicEnabled, int numRelros) {
    +-        setupWithPackages(packages, fallbackLogicEnabled, numRelros,
    +-                true /* isDebuggable == true -> don't check package signatures */);
    +-    }
    +-
    +-    private void setupWithPackages(WebViewProviderInfo[] packages,
    +-            boolean fallbackLogicEnabled, int numRelros, boolean isDebuggable) {
    +-        TestSystemImpl testing = new TestSystemImpl(packages, fallbackLogicEnabled, numRelros,
    +-                isDebuggable);
    +-        mTestSystemImpl = Mockito.spy(testing);
    +-        mWebViewUpdateServiceImpl =
    +-            new WebViewUpdateServiceImpl(null /*Context*/, mTestSystemImpl);
    +-    }
    +-
    +-    private void setEnabledAndValidPackageInfos(WebViewProviderInfo[] providers) {
    +-        for(WebViewProviderInfo wpi : providers) {
    +-            mTestSystemImpl.setPackageInfo(createPackageInfo(wpi.packageName, true /* enabled */,
    +-                        true /* valid */, true /* installed */));
    +-        }
    +-    }
    +-
    +-    private void checkCertainPackageUsedAfterWebViewBootPreparation(String expectedProviderName,
    +-            WebViewProviderInfo[] webviewPackages) {
    +-        checkCertainPackageUsedAfterWebViewBootPreparation(
    +-                expectedProviderName, webviewPackages, 1);
    +-    }
    +-
    +-    private void checkCertainPackageUsedAfterWebViewBootPreparation(String expectedProviderName,
    +-            WebViewProviderInfo[] webviewPackages, int numRelros) {
    +-        setupWithPackages(webviewPackages, true, numRelros);
    +-        // Add (enabled and valid) package infos for each provider
    +-        setEnabledAndValidPackageInfos(webviewPackages);
    +-
    +-        mWebViewUpdateServiceImpl.prepareWebViewInSystemServer();
    +-
    +-        Mockito.verify(mTestSystemImpl).onWebViewProviderChanged(
    +-                Mockito.argThat(new IsPackageInfoWithName(expectedProviderName)));
    +-
    +-        for (int n = 0; n < numRelros; n++) {
    +-            mWebViewUpdateServiceImpl.notifyRelroCreationCompleted();
    +-        }
    +-
    +-        WebViewProviderResponse response = mWebViewUpdateServiceImpl.waitForAndGetProvider();
    +-        assertEquals(WebViewFactory.LIBLOAD_SUCCESS, response.status);
    +-        assertEquals(expectedProviderName, response.packageInfo.packageName);
    +-    }
    +-
    +-    // For matching the package name of a PackageInfo
    +-    private class IsPackageInfoWithName extends ArgumentMatcher<PackageInfo> {
    +-        private final String mPackageName;
    +-
    +-        IsPackageInfoWithName(String name) {
    +-            mPackageName = name;
    +-        }
    +-
    +-        @Override
    +-        public boolean matches(Object p) {
    +-            return ((PackageInfo) p).packageName.equals(mPackageName);
    +-        }
    +-
    +-        // Provide a more useful description in case of mismatch
    +-        @Override
    +-        public void describeTo (Description description) {
    +-            description.appendText(String.format("PackageInfo with name '%s'", mPackageName));
    +-        }
    +-    }
    +-
    +-    private static PackageInfo createPackageInfo(
    +-            String packageName, boolean enabled, boolean valid, boolean installed) {
    +-        PackageInfo p = new PackageInfo();
    +-        p.packageName = packageName;
    +-        p.applicationInfo = new ApplicationInfo();
    +-        p.applicationInfo.enabled = enabled;
    +-        p.applicationInfo.metaData = new Bundle();
    +-        if (installed) {
    +-            p.applicationInfo.flags |= ApplicationInfo.FLAG_INSTALLED;
    +-        } else {
    +-            p.applicationInfo.flags &= ~ApplicationInfo.FLAG_INSTALLED;
    +-        }
    +-        if (valid) {
    +-            // no flag means invalid
    +-            p.applicationInfo.metaData.putString(WEBVIEW_LIBRARY_FLAG, "blah");
    +-        }
    +-        return p;
    +-    }
    +-
    +-    private static PackageInfo createPackageInfo(String packageName, boolean enabled, boolean valid,
    +-            boolean installed, Signature[] signatures, long updateTime) {
    +-        PackageInfo p = createPackageInfo(packageName, enabled, valid, installed);
    +-        p.signatures = signatures;
    +-        p.lastUpdateTime = updateTime;
    +-        return p;
    +-    }
    +-
    +-    private static PackageInfo createPackageInfo(String packageName, boolean enabled, boolean valid,
    +-            boolean installed, Signature[] signatures, long updateTime, boolean hidden) {
    +-        PackageInfo p =
    +-            createPackageInfo(packageName, enabled, valid, installed, signatures, updateTime);
    +-        if (hidden) {
    +-            p.applicationInfo.privateFlags |= ApplicationInfo.PRIVATE_FLAG_HIDDEN;
    +-        } else {
    +-            p.applicationInfo.privateFlags &= ~ApplicationInfo.PRIVATE_FLAG_HIDDEN;
    +-        }
    +-        return p;
    +-    }
    +-
    +-    private void checkPreparationPhasesForPackage(String expectedPackage, int numPreparation) {
    +-        // Verify that onWebViewProviderChanged was called for the numPreparation'th time for the
    +-        // expected package
    +-        Mockito.verify(mTestSystemImpl, Mockito.times(numPreparation)).onWebViewProviderChanged(
    +-                Mockito.argThat(new IsPackageInfoWithName(expectedPackage)));
    +-
    +-        mWebViewUpdateServiceImpl.notifyRelroCreationCompleted();
    +-
    +-        WebViewProviderResponse response = mWebViewUpdateServiceImpl.waitForAndGetProvider();
    +-        assertEquals(WebViewFactory.LIBLOAD_SUCCESS, response.status);
    +-        assertEquals(expectedPackage, response.packageInfo.packageName);
    +-    }
    +-
    +-
    +-    // ****************
    +-    // Tests
    +-    // ****************
    +-
    +-
    +-    public void testWithSinglePackage() {
    +-        String testPackageName = "test.package.name";
    +-        checkCertainPackageUsedAfterWebViewBootPreparation(testPackageName,
    +-                new WebViewProviderInfo[] {
    +-                    new WebViewProviderInfo(testPackageName, "",
    +-                            true /*default available*/, false /* fallback */, null)});
    +-    }
    +-
    +-    public void testDefaultPackageUsedOverNonDefault() {
    +-        String defaultPackage = "defaultPackage";
    +-        String nonDefaultPackage = "nonDefaultPackage";
    +-        WebViewProviderInfo[] packages = new WebViewProviderInfo[] {
    +-            new WebViewProviderInfo(nonDefaultPackage, "", false, false, null),
    +-            new WebViewProviderInfo(defaultPackage, "", true, false, null)};
    +-        checkCertainPackageUsedAfterWebViewBootPreparation(defaultPackage, packages);
    +-    }
    +-
    +-    public void testSeveralRelros() {
    +-        String singlePackage = "singlePackage";
    +-        checkCertainPackageUsedAfterWebViewBootPreparation(
    +-                singlePackage,
    +-                new WebViewProviderInfo[] {
    +-                    new WebViewProviderInfo(singlePackage, "", true /*def av*/, false, null)},
    +-                2);
    +-    }
    +-
    +-    // Ensure that package with valid signatures is chosen rather than package with invalid
    +-    // signatures.
    +-    public void testWithSignatures() {
    +-        String validPackage = "valid package";
    +-        String invalidPackage = "invalid package";
    +-
    +-        Signature validSignature = new Signature("11");
    +-        Signature invalidExpectedSignature = new Signature("22");
    +-        Signature invalidPackageSignature = new Signature("33");
    +-
    +-        WebViewProviderInfo[] packages = new WebViewProviderInfo[] {
    +-            new WebViewProviderInfo(invalidPackage, "", true, false, new String[]{
    +-                        Base64.encodeToString(
    +-                                invalidExpectedSignature.toByteArray(), Base64.DEFAULT)}),
    +-            new WebViewProviderInfo(validPackage, "", true, false, new String[]{
    +-                        Base64.encodeToString(
    +-                                validSignature.toByteArray(), Base64.DEFAULT)})
    +-        };
    +-        setupWithPackages(packages, true /* fallback logic enabled */, 1 /* numRelros */,
    +-                false /* isDebuggable */);
    +-        mTestSystemImpl.setPackageInfo(createPackageInfo(invalidPackage, true /* enabled */,
    +-                    true /* valid */, true /* installed */, new Signature[]{invalidPackageSignature}
    +-                    , 0 /* updateTime */));
    +-        mTestSystemImpl.setPackageInfo(createPackageInfo(validPackage, true /* enabled */,
    +-                    true /* valid */, true /* installed */, new Signature[]{validSignature}
    +-                    , 0 /* updateTime */));
    +-
    +-        mWebViewUpdateServiceImpl.prepareWebViewInSystemServer();
    +-
    +-
    +-        checkPreparationPhasesForPackage(validPackage, 1 /* first preparation for this package */);
    +-
    +-        WebViewProviderInfo[] validPackages = mWebViewUpdateServiceImpl.getValidWebViewPackages();
    +-        assertEquals(1, validPackages.length);
    +-        assertEquals(validPackage, validPackages[0].packageName);
    +-    }
    +-
    +-    public void testFailWaitingForRelro() {
    +-        WebViewProviderInfo[] packages = new WebViewProviderInfo[] {
    +-            new WebViewProviderInfo("packagename", "", true, true, null)};
    +-        setupWithPackages(packages);
    +-        setEnabledAndValidPackageInfos(packages);
    +-
    +-        mWebViewUpdateServiceImpl.prepareWebViewInSystemServer();
    +-
    +-        Mockito.verify(mTestSystemImpl).onWebViewProviderChanged(
    +-                Mockito.argThat(new IsPackageInfoWithName(packages[0].packageName)));
    +-
    +-        // Never call notifyRelroCreation()
    +-
    +-        WebViewProviderResponse response = mWebViewUpdateServiceImpl.waitForAndGetProvider();
    +-        assertEquals(WebViewFactory.LIBLOAD_FAILED_WAITING_FOR_RELRO, response.status);
    +-    }
    +-
    +-    public void testFailListingEmptyWebviewPackages() {
    +-        WebViewProviderInfo[] packages = new WebViewProviderInfo[0];
    +-        setupWithPackages(packages);
    +-        setEnabledAndValidPackageInfos(packages);
    +-
    +-        mWebViewUpdateServiceImpl.prepareWebViewInSystemServer();
    +-
    +-        Mockito.verify(mTestSystemImpl, Mockito.never()).onWebViewProviderChanged(
    +-                Matchers.anyObject());
    +-
    +-        WebViewProviderResponse response = mWebViewUpdateServiceImpl.waitForAndGetProvider();
    +-        assertEquals(WebViewFactory.LIBLOAD_FAILED_LISTING_WEBVIEW_PACKAGES, response.status);
    +-    }
    +-
    +-    public void testFailListingInvalidWebviewPackage() {
    +-        WebViewProviderInfo wpi = new WebViewProviderInfo("package", "", true, true, null);
    +-        WebViewProviderInfo[] packages = new WebViewProviderInfo[] {wpi};
    +-        setupWithPackages(packages);
    +-        mTestSystemImpl.setPackageInfo(
    +-                createPackageInfo(wpi.packageName, true /* enabled */, false /* valid */,
    +-                    true /* installed */));
    +-
    +-        mWebViewUpdateServiceImpl.prepareWebViewInSystemServer();
    +-
    +-        Mockito.verify(mTestSystemImpl, Mockito.never()).onWebViewProviderChanged(
    +-                Matchers.anyObject());
    +-
    +-        WebViewProviderResponse response = mWebViewUpdateServiceImpl.waitForAndGetProvider();
    +-        assertEquals(WebViewFactory.LIBLOAD_FAILED_LISTING_WEBVIEW_PACKAGES, response.status);
    +-
    +-        // Verify that we can recover from failing to list webview packages.
    +-        mTestSystemImpl.setPackageInfo(
    +-                createPackageInfo(wpi.packageName, true /* enabled */, true /* valid */,
    +-                    true /* installed */));
    +-        mWebViewUpdateServiceImpl.packageStateChanged(wpi.packageName,
    +-                WebViewUpdateService.PACKAGE_ADDED_REPLACED, 0);
    +-
    +-        checkPreparationPhasesForPackage(wpi.packageName, 1);
    +-    }
    +-
    +-    // Test that switching provider using changeProviderAndSetting works.
    +-    public void testSwitchingProvider() {
    +-        String firstPackage = "first";
    +-        String secondPackage = "second";
    +-        WebViewProviderInfo[] packages = new WebViewProviderInfo[] {
    +-            new WebViewProviderInfo(firstPackage, "", true, false, null),
    +-            new WebViewProviderInfo(secondPackage, "", true, false, null)};
    +-        checkSwitchingProvider(packages, firstPackage, secondPackage);
    +-    }
    +-
    +-    public void testSwitchingProviderToNonDefault() {
    +-        String defaultPackage = "defaultPackage";
    +-        String nonDefaultPackage = "nonDefaultPackage";
    +-        WebViewProviderInfo[] packages = new WebViewProviderInfo[] {
    +-            new WebViewProviderInfo(defaultPackage, "", true, false, null),
    +-            new WebViewProviderInfo(nonDefaultPackage, "", false, false, null)};
    +-        checkSwitchingProvider(packages, defaultPackage, nonDefaultPackage);
    +-    }
    +-
    +-    private void checkSwitchingProvider(WebViewProviderInfo[] packages, String initialPackage,
    +-            String finalPackage) {
    +-        checkCertainPackageUsedAfterWebViewBootPreparation(initialPackage, packages);
    +-
    +-        mWebViewUpdateServiceImpl.changeProviderAndSetting(finalPackage);
    +-        checkPreparationPhasesForPackage(finalPackage, 1 /* first preparation for this package */);
    +-
    +-        Mockito.verify(mTestSystemImpl).killPackageDependents(Mockito.eq(initialPackage));
    +-    }
    +-
    +-    // Change provider during relro creation by using changeProviderAndSetting
    +-    public void testSwitchingProviderDuringRelroCreation() {
    +-        checkChangingProviderDuringRelroCreation(true);
    +-    }
    +-
    +-    // Change provider during relro creation by enabling a provider
    +-    public void testChangingProviderThroughEnablingDuringRelroCreation() {
    +-        checkChangingProviderDuringRelroCreation(false);
    +-    }
    +-
    +-    private void checkChangingProviderDuringRelroCreation(boolean settingsChange) {
    +-        String firstPackage = "first";
    +-        String secondPackage = "second";
    +-        WebViewProviderInfo[] packages = new WebViewProviderInfo[] {
    +-            new WebViewProviderInfo(firstPackage, "", true, false, null),
    +-            new WebViewProviderInfo(secondPackage, "", true, false, null)};
    +-        setupWithPackages(packages);
    +-        if (settingsChange) {
    +-            // Have all packages be enabled, so that we can change provider however we want to
    +-            setEnabledAndValidPackageInfos(packages);
    +-        } else {
    +-            // Have all packages be disabled so that we can change one to enabled later
    +-            for(WebViewProviderInfo wpi : packages) {
    +-                mTestSystemImpl.setPackageInfo(createPackageInfo(wpi.packageName,
    +-                            false /* enabled */, true /* valid */, true /* installed */));
    +-            }
    +-        }
    +-
    +-        CountDownLatch countdown = new CountDownLatch(1);
    +-
    +-        mWebViewUpdateServiceImpl.prepareWebViewInSystemServer();
    +-
    +-        Mockito.verify(mTestSystemImpl).onWebViewProviderChanged(
    +-                Mockito.argThat(new IsPackageInfoWithName(firstPackage)));
    +-
    +-        assertEquals(firstPackage, mWebViewUpdateServiceImpl.getCurrentWebViewPackageName());
    +-
    +-        new Thread(new Runnable() {
    +-            @Override
    +-            public void run() {
    +-                WebViewProviderResponse threadResponse =
    +-                    mWebViewUpdateServiceImpl.waitForAndGetProvider();
    +-                assertEquals(WebViewFactory.LIBLOAD_SUCCESS, threadResponse.status);
    +-                assertEquals(secondPackage, threadResponse.packageInfo.packageName);
    +-                // Verify that we killed the first package
    +-                Mockito.verify(mTestSystemImpl).killPackageDependents(Mockito.eq(firstPackage));
    +-                countdown.countDown();
    +-            }
    +-        }).start();
    +-        try {
    +-            Thread.sleep(500); // Let the new thread run / be blocked
    +-        } catch (InterruptedException e) {
    +-        }
    +-
    +-        if (settingsChange) {
    +-            mWebViewUpdateServiceImpl.changeProviderAndSetting(secondPackage);
    +-        } else {
    +-            // Switch provider by enabling the second one
    +-            mTestSystemImpl.setPackageInfo(createPackageInfo(secondPackage, true /* enabled */,
    +-                        true /* valid */, true /* installed */));
    +-            mWebViewUpdateServiceImpl.packageStateChanged(
    +-                    secondPackage, WebViewUpdateService.PACKAGE_CHANGED, 0);
    +-        }
    +-        mWebViewUpdateServiceImpl.notifyRelroCreationCompleted();
    +-        // first package done, should start on second
    +-
    +-        Mockito.verify(mTestSystemImpl).onWebViewProviderChanged(
    +-                Mockito.argThat(new IsPackageInfoWithName(secondPackage)));
    +-
    +-        mWebViewUpdateServiceImpl.notifyRelroCreationCompleted();
    +-        // second package done, the other thread should now be unblocked
    +-        try {
    +-            countdown.await();
    +-        } catch (InterruptedException e) {
    +-        }
    +-    }
    +-
    +-    public void testRunFallbackLogicIfEnabled() {
    +-        checkFallbackLogicBeingRun(true);
    +-    }
    +-
    +-    public void testDontRunFallbackLogicIfDisabled() {
    +-        checkFallbackLogicBeingRun(false);
    +-    }
    +-
    +-    private void checkFallbackLogicBeingRun(boolean fallbackLogicEnabled) {
    +-        String primaryPackage = "primary";
    +-        String fallbackPackage = "fallback";
    +-        WebViewProviderInfo[] packages = new WebViewProviderInfo[] {
    +-            new WebViewProviderInfo(
    +-                    primaryPackage, "", true /* default available */, false /* fallback */, null),
    +-            new WebViewProviderInfo(
    +-                    fallbackPackage, "", true /* default available */, true /* fallback */, null)};
    +-        setupWithPackages(packages, fallbackLogicEnabled);
    +-        setEnabledAndValidPackageInfos(packages);
    +-
    +-        mWebViewUpdateServiceImpl.prepareWebViewInSystemServer();
    +-        // Verify that we disable the fallback package if fallback logic enabled, and don't disable
    +-        // the fallback package if that logic is disabled
    +-        if (fallbackLogicEnabled) {
    +-            Mockito.verify(mTestSystemImpl).uninstallAndDisablePackageForAllUsers(
    +-                    Matchers.anyObject(), Mockito.eq(fallbackPackage));
    +-        } else {
    +-            Mockito.verify(mTestSystemImpl, Mockito.never()).uninstallAndDisablePackageForAllUsers(
    +-                    Matchers.anyObject(), Matchers.anyObject());
    +-        }
    +-        Mockito.verify(mTestSystemImpl).onWebViewProviderChanged(
    +-                Mockito.argThat(new IsPackageInfoWithName(primaryPackage)));
    +-
    +-        // Enable fallback package
    +-        mTestSystemImpl.setPackageInfo(createPackageInfo(fallbackPackage, true /* enabled */,
    +-                        true /* valid */, true /* installed */));
    +-        mWebViewUpdateServiceImpl.packageStateChanged(
    +-                fallbackPackage, WebViewUpdateService.PACKAGE_CHANGED, 0);
    +-
    +-        if (fallbackLogicEnabled) {
    +-            // Check that we have now disabled the fallback package twice
    +-            Mockito.verify(mTestSystemImpl, Mockito.times(2)).uninstallAndDisablePackageForAllUsers(
    +-                    Matchers.anyObject(), Mockito.eq(fallbackPackage));
    +-        } else {
    +-            // Check that we still haven't disabled any package
    +-            Mockito.verify(mTestSystemImpl, Mockito.never()).uninstallAndDisablePackageForAllUsers(
    +-                    Matchers.anyObject(), Matchers.anyObject());
    +-        }
    +-    }
    +-
    +-    /**
    +-     * Scenario for installing primary package when fallback enabled.
    +-     * 1. Start with only fallback installed
    +-     * 2. Install non-fallback
    +-     * 3. Fallback should be disabled
    +-     */
    +-    public void testInstallingNonFallbackPackage() {
    +-        String primaryPackage = "primary";
    +-        String fallbackPackage = "fallback";
    +-        WebViewProviderInfo[] packages = new WebViewProviderInfo[] {
    +-            new WebViewProviderInfo(
    +-                    primaryPackage, "", true /* default available */, false /* fallback */, null),
    +-            new WebViewProviderInfo(
    +-                    fallbackPackage, "", true /* default available */, true /* fallback */, null)};
    +-        setupWithPackages(packages, true /* isFallbackLogicEnabled */);
    +-        mTestSystemImpl.setPackageInfo(
    +-                createPackageInfo(fallbackPackage, true /* enabled */ , true /* valid */,
    +-                    true /* installed */));
    +-
    +-        mWebViewUpdateServiceImpl.prepareWebViewInSystemServer();
    +-        Mockito.verify(mTestSystemImpl, Mockito.never()).uninstallAndDisablePackageForAllUsers(
    +-                Matchers.anyObject(), Matchers.anyObject());
    +-
    +-        checkPreparationPhasesForPackage(fallbackPackage,
    +-                1 /* first preparation for this package*/);
    +-
    +-        // Install primary package
    +-        mTestSystemImpl.setPackageInfo(
    +-                createPackageInfo(primaryPackage, true /* enabled */ , true /* valid */,
    +-                    true /* installed */));
    +-        mWebViewUpdateServiceImpl.packageStateChanged(primaryPackage,
    +-                WebViewUpdateService.PACKAGE_ADDED_REPLACED, 0);
    +-
    +-        // Verify fallback disabled, primary package used as provider, and fallback package killed
    +-        Mockito.verify(mTestSystemImpl).uninstallAndDisablePackageForAllUsers(
    +-                Matchers.anyObject(), Mockito.eq(fallbackPackage));
    +-        checkPreparationPhasesForPackage(primaryPackage, 1 /* first preparation for this package*/);
    +-        Mockito.verify(mTestSystemImpl).killPackageDependents(Mockito.eq(fallbackPackage));
    +-    }
    +-
    +-    public void testFallbackChangesEnabledState() {
    +-        String primaryPackage = "primary";
    +-        String fallbackPackage = "fallback";
    +-        WebViewProviderInfo[] packages = new WebViewProviderInfo[] {
    +-            new WebViewProviderInfo(
    +-                    primaryPackage, "", true /* default available */, false /* fallback */, null),
    +-            new WebViewProviderInfo(
    +-                    fallbackPackage, "", true /* default available */, true /* fallback */, null)};
    +-        setupWithPackages(packages, true /* fallbackLogicEnabled */);
    +-        setEnabledAndValidPackageInfos(packages);
    +-
    +-        mWebViewUpdateServiceImpl.prepareWebViewInSystemServer();
    +-
    +-        // Verify fallback disabled at boot when primary package enabled
    +-        Mockito.verify(mTestSystemImpl).enablePackageForUser(
    +-                Mockito.eq(fallbackPackage), Mockito.eq(false) /* enable */,
    +-                Matchers.anyInt());
    +-
    +-        checkPreparationPhasesForPackage(primaryPackage, 1);
    +-
    +-        // Disable primary package and ensure fallback becomes enabled and used
    +-        mTestSystemImpl.setPackageInfo(
    +-                createPackageInfo(primaryPackage, false /* enabled */, true /* valid */,
    +-                    true /* installed */));
    +-        mWebViewUpdateServiceImpl.packageStateChanged(primaryPackage,
    +-                WebViewUpdateService.PACKAGE_CHANGED, 0);
    +-
    +-        Mockito.verify(mTestSystemImpl).enablePackageForUser(
    +-                Mockito.eq(fallbackPackage), Mockito.eq(true) /* enable */,
    +-                Matchers.anyInt());
    +-
    +-        checkPreparationPhasesForPackage(fallbackPackage, 1);
    +-
    +-
    +-        // Again enable primary package and verify primary is used and fallback becomes disabled
    +-        mTestSystemImpl.setPackageInfo(
    +-                createPackageInfo(primaryPackage, true /* enabled */, true /* valid */,
    +-                    true /* installed */));
    +-        mWebViewUpdateServiceImpl.packageStateChanged(primaryPackage,
    +-                WebViewUpdateService.PACKAGE_CHANGED, 0);
    +-
    +-        // Verify fallback is disabled a second time when primary package becomes enabled
    +-        Mockito.verify(mTestSystemImpl, Mockito.times(2)).enablePackageForUser(
    +-                Mockito.eq(fallbackPackage), Mockito.eq(false) /* enable */,
    +-                Matchers.anyInt());
    +-
    +-        checkPreparationPhasesForPackage(primaryPackage, 2);
    +-    }
    +-
    +-    public void testAddUserWhenFallbackLogicEnabled() {
    +-        checkAddingNewUser(true);
    +-    }
    +-
    +-    public void testAddUserWhenFallbackLogicDisabled() {
    +-        checkAddingNewUser(false);
    +-    }
    +-
    +-    public void checkAddingNewUser(boolean fallbackLogicEnabled) {
    +-        String primaryPackage = "primary";
    +-        String fallbackPackage = "fallback";
    +-        WebViewProviderInfo[] packages = new WebViewProviderInfo[] {
    +-            new WebViewProviderInfo(
    +-                    primaryPackage, "", true /* default available */, false /* fallback */, null),
    +-            new WebViewProviderInfo(
    +-                    fallbackPackage, "", true /* default available */, true /* fallback */, null)};
    +-        setupWithPackages(packages, fallbackLogicEnabled);
    +-        setEnabledAndValidPackageInfos(packages);
    +-        int newUser = 100;
    +-        mWebViewUpdateServiceImpl.handleNewUser(newUser);
    +-        if (fallbackLogicEnabled) {
    +-            // Verify fallback package becomes disabled for new user
    +-            Mockito.verify(mTestSystemImpl).enablePackageForUser(
    +-                    Mockito.eq(fallbackPackage), Mockito.eq(false) /* enable */,
    +-                    Mockito.eq(newUser));
    +-        } else {
    +-            // Verify that we don't disable fallback for new user
    +-            Mockito.verify(mTestSystemImpl, Mockito.never()).enablePackageForUser(
    +-                    Mockito.anyObject(), Matchers.anyBoolean() /* enable */,
    +-                    Matchers.anyInt() /* user */);
    +-        }
    +-    }
    +-
    +-    /**
    +-     * Timing dependent test where we verify that the list of valid webview packages becoming empty
    +-     * at a certain point doesn't crash us or break our state.
    +-     */
    +-    public void testNotifyRelroDoesntCrashIfNoPackages() {
    +-        String firstPackage = "first";
    +-        String secondPackage = "second";
    +-        WebViewProviderInfo[] packages = new WebViewProviderInfo[] {
    +-            new WebViewProviderInfo(firstPackage, "", true /* default available */,
    +-                    false /* fallback */, null),
    +-            new WebViewProviderInfo(secondPackage, "", true /* default available */,
    +-                    false /* fallback */, null)};
    +-        setupWithPackages(packages);
    +-        // Add (enabled and valid) package infos for each provider
    +-        setEnabledAndValidPackageInfos(packages);
    +-
    +-        mWebViewUpdateServiceImpl.prepareWebViewInSystemServer();
    +-
    +-        Mockito.verify(mTestSystemImpl).onWebViewProviderChanged(
    +-                Mockito.argThat(new IsPackageInfoWithName(firstPackage)));
    +-
    +-        // Change provider during relro creation to enter a state where we are
    +-        // waiting for relro creation to complete just to re-run relro creation.
    +-        // (so that in next notifyRelroCreationCompleted() call we have to list webview packages)
    +-        mWebViewUpdateServiceImpl.changeProviderAndSetting(secondPackage);
    +-
    +-        // Make packages invalid to cause exception to be thrown
    +-        mTestSystemImpl.setPackageInfo(createPackageInfo(firstPackage, true /* enabled */,
    +-                    false /* valid */, true /* installed */, null /* signatures */,
    +-                    0 /* updateTime */));
    +-        mTestSystemImpl.setPackageInfo(createPackageInfo(secondPackage, true /* enabled */,
    +-                    false /* valid */, true /* installed */));
    +-
    +-        // This shouldn't throw an exception!
    +-        mWebViewUpdateServiceImpl.notifyRelroCreationCompleted();
    +-
    +-        WebViewProviderResponse response = mWebViewUpdateServiceImpl.waitForAndGetProvider();
    +-        assertEquals(WebViewFactory.LIBLOAD_FAILED_LISTING_WEBVIEW_PACKAGES, response.status);
    +-
    +-        // Now make a package valid again and verify that we can switch back to that
    +-        mTestSystemImpl.setPackageInfo(createPackageInfo(firstPackage, true /* enabled */,
    +-                    true /* valid */, true /* installed */, null /* signatures */,
    +-                    1 /* updateTime */ ));
    +-
    +-        mWebViewUpdateServiceImpl.packageStateChanged(firstPackage,
    +-                WebViewUpdateService.PACKAGE_ADDED_REPLACED, 0);
    +-
    +-        // Ensure we use firstPackage
    +-        checkPreparationPhasesForPackage(firstPackage, 2 /* second preparation for this package */);
    +-    }
    +-
    +-    /**
    +-     * Verify that even if a user-chosen package is removed temporarily we start using it again when
    +-     * it is added back.
    +-     */
    +-    public void testTempRemovePackageDoesntSwitchProviderPermanently() {
    +-        String firstPackage = "first";
    +-        String secondPackage = "second";
    +-        WebViewProviderInfo[] packages = new WebViewProviderInfo[] {
    +-            new WebViewProviderInfo(firstPackage, "", true /* default available */,
    +-                    false /* fallback */, null),
    +-            new WebViewProviderInfo(secondPackage, "", true /* default available */,
    +-                    false /* fallback */, null)};
    +-        checkCertainPackageUsedAfterWebViewBootPreparation(firstPackage, packages);
    +-
    +-        // Explicitly use the second package
    +-        mWebViewUpdateServiceImpl.changeProviderAndSetting(secondPackage);
    +-        checkPreparationPhasesForPackage(secondPackage, 1 /* first time for this package */);
    +-
    +-        // Remove second package (invalidate it) and verify that first package is used
    +-        mTestSystemImpl.setPackageInfo(createPackageInfo(secondPackage, true /* enabled */,
    +-                    false /* valid */, true /* installed */));
    +-        mWebViewUpdateServiceImpl.packageStateChanged(secondPackage,
    +-                WebViewUpdateService.PACKAGE_ADDED, 0);
    +-        checkPreparationPhasesForPackage(firstPackage, 2 /* second time for this package */);
    +-
    +-        // Now make the second package valid again and verify that it is used again
    +-        mTestSystemImpl.setPackageInfo(createPackageInfo(secondPackage, true /* enabled */,
    +-                    true /* valid */, true /* installed */));
    +-        mWebViewUpdateServiceImpl.packageStateChanged(secondPackage,
    +-                WebViewUpdateService.PACKAGE_ADDED, 0);
    +-        checkPreparationPhasesForPackage(secondPackage, 2 /* second time for this package */);
    +-    }
    +-
    +-    /**
    +-     * Ensure that we update the user-chosen setting across boots if the chosen package is no
    +-     * longer installed and valid.
    +-     */
    +-    public void testProviderSettingChangedDuringBootIfProviderNotAvailable() {
    +-        String chosenPackage = "chosenPackage";
    +-        String nonChosenPackage = "non-chosenPackage";
    +-        WebViewProviderInfo[] packages = new WebViewProviderInfo[] {
    +-            new WebViewProviderInfo(chosenPackage, "", true /* default available */,
    +-                    false /* fallback */, null),
    +-            new WebViewProviderInfo(nonChosenPackage, "", true /* default available */,
    +-                    false /* fallback */, null)};
    +-
    +-        setupWithPackages(packages);
    +-        // Only 'install' nonChosenPackage
    +-        mTestSystemImpl.setPackageInfo(
    +-                createPackageInfo(nonChosenPackage, true /* enabled */, true /* valid */, true /* installed */));
    +-
    +-        // Set user-chosen package
    +-        mTestSystemImpl.updateUserSetting(null, chosenPackage);
    +-
    +-        mWebViewUpdateServiceImpl.prepareWebViewInSystemServer();
    +-
    +-        // Verify that we switch the setting to point to the current package
    +-        Mockito.verify(mTestSystemImpl).updateUserSetting(
    +-                Mockito.anyObject(), Mockito.eq(nonChosenPackage));
    +-        assertEquals(nonChosenPackage, mTestSystemImpl.getUserChosenWebViewProvider(null));
    +-
    +-        checkPreparationPhasesForPackage(nonChosenPackage, 1);
    +-    }
    +-
    +-    public void testRecoverFailedListingWebViewPackagesSettingsChange() {
    +-        checkRecoverAfterFailListingWebviewPackages(true);
    +-    }
    +-
    +-    public void testRecoverFailedListingWebViewPackagesAddedPackage() {
    +-        checkRecoverAfterFailListingWebviewPackages(false);
    +-    }
    +-
    +-    /**
    +-     * Test that we can recover correctly from failing to list WebView packages.
    +-     * settingsChange: whether to fail during changeProviderAndSetting or packageStateChanged
    +-     */
    +-    public void checkRecoverAfterFailListingWebviewPackages(boolean settingsChange) {
    +-        String firstPackage = "first";
    +-        String secondPackage = "second";
    +-        WebViewProviderInfo[] packages = new WebViewProviderInfo[] {
    +-            new WebViewProviderInfo(firstPackage, "", true /* default available */,
    +-                    false /* fallback */, null),
    +-            new WebViewProviderInfo(secondPackage, "", true /* default available */,
    +-                    false /* fallback */, null)};
    +-        checkCertainPackageUsedAfterWebViewBootPreparation(firstPackage, packages);
    +-
    +-        // Make both packages invalid so that we fail listing WebView packages
    +-        mTestSystemImpl.setPackageInfo(createPackageInfo(firstPackage, true /* enabled */,
    +-                    false /* valid */, true /* installed */));
    +-        mTestSystemImpl.setPackageInfo(createPackageInfo(secondPackage, true /* enabled */,
    +-                    false /* valid */, true /* installed */));
    +-
    +-        // Change package to hit the webview packages listing problem.
    +-        if (settingsChange) {
    +-            mWebViewUpdateServiceImpl.changeProviderAndSetting(secondPackage);
    +-        } else {
    +-            mWebViewUpdateServiceImpl.packageStateChanged(secondPackage,
    +-                    WebViewUpdateService.PACKAGE_ADDED_REPLACED, 0);
    +-        }
    +-
    +-        WebViewProviderResponse response = mWebViewUpdateServiceImpl.waitForAndGetProvider();
    +-        assertEquals(WebViewFactory.LIBLOAD_FAILED_LISTING_WEBVIEW_PACKAGES, response.status);
    +-
    +-        // Make second package valid and verify that we can load it again
    +-        mTestSystemImpl.setPackageInfo(createPackageInfo(secondPackage, true /* enabled */,
    +-                    true /* valid */, true /* installed */));
    +-
    +-        mWebViewUpdateServiceImpl.packageStateChanged(secondPackage,
    +-                WebViewUpdateService.PACKAGE_ADDED_REPLACED, 0);
    +-
    +-
    +-        checkPreparationPhasesForPackage(secondPackage, 1);
    +-    }
    +-
    +-    public void testDontKillIfPackageReplaced() {
    +-        checkDontKillIfPackageRemoved(true);
    +-    }
    +-
    +-    public void testDontKillIfPackageRemoved() {
    +-        checkDontKillIfPackageRemoved(false);
    +-    }
    +-
    +-    public void checkDontKillIfPackageRemoved(boolean replaced) {
    +-        String firstPackage = "first";
    +-        String secondPackage = "second";
    +-        WebViewProviderInfo[] packages = new WebViewProviderInfo[] {
    +-            new WebViewProviderInfo(firstPackage, "", true /* default available */,
    +-                    false /* fallback */, null),
    +-            new WebViewProviderInfo(secondPackage, "", true /* default available */,
    +-                    false /* fallback */, null)};
    +-        checkCertainPackageUsedAfterWebViewBootPreparation(firstPackage, packages);
    +-
    +-        // Replace or remove the current webview package
    +-        if (replaced) {
    +-            mTestSystemImpl.setPackageInfo(
    +-                    createPackageInfo(firstPackage, true /* enabled */, false /* valid */,
    +-                        true /* installed */));
    +-            mWebViewUpdateServiceImpl.packageStateChanged(firstPackage,
    +-                    WebViewUpdateService.PACKAGE_ADDED_REPLACED, 0);
    +-        } else {
    +-            mTestSystemImpl.removePackageInfo(firstPackage);
    +-            mWebViewUpdateServiceImpl.packageStateChanged(firstPackage,
    +-                    WebViewUpdateService.PACKAGE_REMOVED, 0);
    +-        }
    +-
    +-        checkPreparationPhasesForPackage(secondPackage, 1);
    +-
    +-        Mockito.verify(mTestSystemImpl, Mockito.never()).killPackageDependents(
    +-                Mockito.anyObject());
    +-    }
    +-
    +-    public void testKillIfSettingChanged() {
    +-        String firstPackage = "first";
    +-        String secondPackage = "second";
    +-        WebViewProviderInfo[] packages = new WebViewProviderInfo[] {
    +-            new WebViewProviderInfo(firstPackage, "", true /* default available */,
    +-                    false /* fallback */, null),
    +-            new WebViewProviderInfo(secondPackage, "", true /* default available */,
    +-                    false /* fallback */, null)};
    +-        checkCertainPackageUsedAfterWebViewBootPreparation(firstPackage, packages);
    +-
    +-        mWebViewUpdateServiceImpl.changeProviderAndSetting(secondPackage);
    +-
    +-        checkPreparationPhasesForPackage(secondPackage, 1);
    +-
    +-        Mockito.verify(mTestSystemImpl).killPackageDependents(Mockito.eq(firstPackage));
    +-    }
    +-
    +-    /**
    +-     * Test that we kill apps using an old provider when we change the provider setting, even if the
    +-     * new provider is not the one we intended to change to.
    +-     */
    +-    public void testKillIfChangeProviderIncorrectly() {
    +-        String firstPackage = "first";
    +-        String secondPackage = "second";
    +-        String thirdPackage = "third";
    +-        WebViewProviderInfo[] packages = new WebViewProviderInfo[] {
    +-            new WebViewProviderInfo(firstPackage, "", true /* default available */,
    +-                    false /* fallback */, null),
    +-            new WebViewProviderInfo(secondPackage, "", true /* default available */,
    +-                    false /* fallback */, null),
    +-            new WebViewProviderInfo(thirdPackage, "", true /* default available */,
    +-                    false /* fallback */, null)};
    +-        setupWithPackages(packages);
    +-        setEnabledAndValidPackageInfos(packages);
    +-
    +-        // Start with the setting pointing to the third package
    +-        mTestSystemImpl.updateUserSetting(null, thirdPackage);
    +-
    +-        mWebViewUpdateServiceImpl.prepareWebViewInSystemServer();
    +-        checkPreparationPhasesForPackage(thirdPackage, 1);
    +-
    +-        mTestSystemImpl.setPackageInfo(
    +-                createPackageInfo(secondPackage, true /* enabled */, false /* valid */, true /* installed */));
    +-
    +-        // Try to switch to the invalid second package, this should result in switching to the first
    +-        // package, since that is more preferred than the third one.
    +-        assertEquals(firstPackage,
    +-                mWebViewUpdateServiceImpl.changeProviderAndSetting(secondPackage));
    +-
    +-        checkPreparationPhasesForPackage(firstPackage, 1);
    +-
    +-        Mockito.verify(mTestSystemImpl).killPackageDependents(Mockito.eq(thirdPackage));
    +-    }
    +-
    +-    // Ensure that the update service uses an uninstalled package if that is the only package
    +-    // available.
    +-    public void testWithSingleUninstalledPackage() {
    +-        String testPackageName = "test.package.name";
    +-        WebViewProviderInfo[] webviewPackages = new WebViewProviderInfo[] {
    +-                new WebViewProviderInfo(testPackageName, "",
    +-                        true /*default available*/, false /* fallback */, null)};
    +-        setupWithPackages(webviewPackages, true /* fallback logic enabled */, 1 /* numRelros */);
    +-        mTestSystemImpl.setPackageInfo(createPackageInfo(testPackageName, true /* enabled */,
    +-                    true /* valid */, false /* installed */));
    +-
    +-        mWebViewUpdateServiceImpl.prepareWebViewInSystemServer();
    +-
    +-        checkPreparationPhasesForPackage(testPackageName, 1 /* first preparation phase */);
    +-    }
    +-
    +-    public void testNonhiddenPackageUserOverHidden() {
    +-        checkVisiblePackageUserOverNonVisible(false /* true == uninstalled, false == hidden */);
    +-    }
    +-
    +-    public void testInstalledPackageUsedOverUninstalled() {
    +-        checkVisiblePackageUserOverNonVisible(true /* true == uninstalled, false == hidden */);
    +-    }
    +-
    +-    private void checkVisiblePackageUserOverNonVisible(boolean uninstalledNotHidden) {
    +-        boolean testUninstalled = uninstalledNotHidden;
    +-        boolean testHidden = !uninstalledNotHidden;
    +-        String installedPackage = "installedPackage";
    +-        String uninstalledPackage = "uninstalledPackage";
    +-        WebViewProviderInfo[] webviewPackages = new WebViewProviderInfo[] {
    +-            new WebViewProviderInfo(uninstalledPackage, "", true /* available by default */,
    +-                    false /* fallback */, null),
    +-            new WebViewProviderInfo(installedPackage, "", true /* available by default */,
    +-                    false /* fallback */, null)};
    +-
    +-        setupWithPackages(webviewPackages, true /* fallback logic enabled */, 1 /* numRelros */);
    +-        mTestSystemImpl.setPackageInfo(createPackageInfo(installedPackage, true /* enabled */,
    +-                    true /* valid */, true /* installed */));
    +-        mTestSystemImpl.setPackageInfo(createPackageInfo(uninstalledPackage, true /* enabled */,
    +-                    true /* valid */, (testUninstalled ? false : true) /* installed */,
    +-                    null /* signatures */, 0 /* updateTime */, (testHidden ? true : false)));
    +-
    +-        mWebViewUpdateServiceImpl.prepareWebViewInSystemServer();
    +-
    +-        checkPreparationPhasesForPackage(installedPackage, 1 /* first preparation phase */);
    +-    }
    +-
    +-    public void testCantSwitchToHiddenPackage () {
    +-        checkCantSwitchToNonVisiblePackage(false /* true == uninstalled, false == hidden */);
    +-    }
    +-
    +-
    +-    public void testCantSwitchToUninstalledPackage () {
    +-        checkCantSwitchToNonVisiblePackage(true /* true == uninstalled, false == hidden */);
    +-    }
    +-
    +-    /**
    +-     * Ensure that we won't prioritize an uninstalled (or hidden) package even if it is user-chosen,
    +-     * and that an uninstalled (or hidden) package is not considered valid (in the
    +-     * getValidWebViewPackages() API).
    +-     */
    +-    private void checkCantSwitchToNonVisiblePackage(boolean uninstalledNotHidden) {
    +-        boolean testUninstalled = uninstalledNotHidden;
    +-        boolean testHidden = !uninstalledNotHidden;
    +-        String installedPackage = "installedPackage";
    +-        String uninstalledPackage = "uninstalledPackage";
    +-        WebViewProviderInfo[] webviewPackages = new WebViewProviderInfo[] {
    +-            new WebViewProviderInfo(uninstalledPackage, "", true /* available by default */,
    +-                    false /* fallback */, null),
    +-            new WebViewProviderInfo(installedPackage, "", true /* available by default */,
    +-                    false /* fallback */, null)};
    +-
    +-        setupWithPackages(webviewPackages, true /* fallback logic enabled */, 1 /* numRelros */);
    +-        mTestSystemImpl.setPackageInfo(createPackageInfo(installedPackage, true /* enabled */,
    +-                    true /* valid */, true /* installed */));
    +-        mTestSystemImpl.setPackageInfo(createPackageInfo(uninstalledPackage, true /* enabled */,
    +-                    true /* valid */, (testUninstalled ? false : true) /* installed */,
    +-                    null /* signatures */, 0 /* updateTime */,
    +-                    (testHidden ? true : false) /* hidden */));
    +-
    +-        mWebViewUpdateServiceImpl.prepareWebViewInSystemServer();
    +-
    +-        checkPreparationPhasesForPackage(installedPackage, 1 /* first preparation phase */);
    +-
    +-        // Ensure that only the installed package is considered valid
    +-        WebViewProviderInfo[] validPackages = mWebViewUpdateServiceImpl.getValidWebViewPackages();
    +-        assertEquals(1, validPackages.length);
    +-        assertEquals(installedPackage, validPackages[0].packageName);
    +-
    +-        // ensure that we don't switch to the uninstalled package (it will be used if it becomes
    +-        // installed later)
    +-        assertEquals(installedPackage,
    +-                mWebViewUpdateServiceImpl.changeProviderAndSetting(uninstalledPackage));
    +-
    +-        // We should only have called onWebViewProviderChanged once (before calling
    +-        // changeProviderAndSetting
    +-        Mockito.verify(mTestSystemImpl, Mockito.times(1)).onWebViewProviderChanged(
    +-                Mockito.argThat(new IsPackageInfoWithName(installedPackage)));
    +-    }
    +-
    +-    public void testHiddenPackageNotPrioritizedEvenIfChosen() {
    +-        checkNonvisiblePackageNotPrioritizedEvenIfChosen(
    +-                false /* true == uninstalled, false == hidden */);
    +-    }
    +-
    +-    public void testUninstalledPackageNotPrioritizedEvenIfChosen() {
    +-        checkNonvisiblePackageNotPrioritizedEvenIfChosen(
    +-                true /* true == uninstalled, false == hidden */);
    +-    }
    +-
    +-    public void checkNonvisiblePackageNotPrioritizedEvenIfChosen(boolean uninstalledNotHidden) {
    +-        boolean testUninstalled = uninstalledNotHidden;
    +-        boolean testHidden = !uninstalledNotHidden;
    +-        String installedPackage = "installedPackage";
    +-        String uninstalledPackage = "uninstalledPackage";
    +-        WebViewProviderInfo[] webviewPackages = new WebViewProviderInfo[] {
    +-            new WebViewProviderInfo(uninstalledPackage, "", true /* available by default */,
    +-                    false /* fallback */, null),
    +-            new WebViewProviderInfo(installedPackage, "", true /* available by default */,
    +-                    false /* fallback */, null)};
    +-
    +-        setupWithPackages(webviewPackages, true /* fallback logic enabled */, 1 /* numRelros */);
    +-        mTestSystemImpl.setPackageInfo(createPackageInfo(installedPackage, true /* enabled */,
    +-                    true /* valid */, true /* installed */));
    +-        mTestSystemImpl.setPackageInfo(createPackageInfo(uninstalledPackage, true /* enabled */,
    +-                    true /* valid */, (testUninstalled ? false : true) /* installed */,
    +-                    null /* signatures */, 0 /* updateTime */,
    +-                    (testHidden ? true : false) /* hidden */));
    +-
    +-        // Start with the setting pointing to the uninstalled package
    +-        mTestSystemImpl.updateUserSetting(null, uninstalledPackage);
    +-
    +-        mWebViewUpdateServiceImpl.prepareWebViewInSystemServer();
    +-
    +-        checkPreparationPhasesForPackage(installedPackage, 1 /* first preparation phase */);
    +-    }
    +-
    +-    /**
    +-     * Ensures that fallback becomes enabled if the primary package is uninstalled for the current
    +-     * user.
    +-     */
    +-    public void testFallbackEnabledIfPrimaryUninstalled() {
    +-        String primaryPackage = "primary";
    +-        String fallbackPackage = "fallback";
    +-        WebViewProviderInfo[] packages = new WebViewProviderInfo[] {
    +-            new WebViewProviderInfo(
    +-                    primaryPackage, "", true /* default available */, false /* fallback */, null),
    +-            new WebViewProviderInfo(
    +-                    fallbackPackage, "", true /* default available */, true /* fallback */, null)};
    +-        setupWithPackages(packages, true /* fallback logic enabled */);
    +-        mTestSystemImpl.setPackageInfo(createPackageInfo(primaryPackage, true /* enabled */,
    +-                    true /* valid */, false /* installed */));
    +-        mTestSystemImpl.setPackageInfo(createPackageInfo(fallbackPackage, true /* enabled */,
    +-                    true /* valid */, true /* installed */));
    +-
    +-        mWebViewUpdateServiceImpl.prepareWebViewInSystemServer();
    +-        // Verify that we enable the fallback package
    +-        Mockito.verify(mTestSystemImpl).enablePackageForAllUsers(
    +-                Mockito.anyObject(), Mockito.eq(fallbackPackage), Mockito.eq(true) /* enable */);
    +-
    +-        checkPreparationPhasesForPackage(fallbackPackage, 1 /* first preparation phase */);
    +-    }
    +-
    +-    public void testPreparationRunsIffNewPackage() {
    +-        String primaryPackage = "primary";
    +-        String fallbackPackage = "fallback";
    +-        WebViewProviderInfo[] packages = new WebViewProviderInfo[] {
    +-            new WebViewProviderInfo(
    +-                    primaryPackage, "", true /* default available */, false /* fallback */, null),
    +-            new WebViewProviderInfo(
    +-                    fallbackPackage, "", true /* default available */, true /* fallback */, null)};
    +-        setupWithPackages(packages, true /* fallback logic enabled */);
    +-        mTestSystemImpl.setPackageInfo(createPackageInfo(primaryPackage, true /* enabled */,
    +-                    true /* valid */, true /* installed */, null /* signatures */,
    +-                    10 /* lastUpdateTime*/ ));
    +-        mTestSystemImpl.setPackageInfo(createPackageInfo(fallbackPackage, true /* enabled */,
    +-                    true /* valid */, true /* installed */));
    +-
    +-        mWebViewUpdateServiceImpl.prepareWebViewInSystemServer();
    +-
    +-        checkPreparationPhasesForPackage(primaryPackage, 1 /* first preparation phase */);
    +-        Mockito.verify(mTestSystemImpl, Mockito.times(1)).enablePackageForUser(
    +-                Mockito.eq(fallbackPackage), Mockito.eq(false) /* enable */,
    +-                Matchers.anyInt() /* user */);
    +-
    +-
    +-        mWebViewUpdateServiceImpl.packageStateChanged(primaryPackage,
    +-                WebViewUpdateService.PACKAGE_ADDED_REPLACED, 0 /* userId */);
    +-        mWebViewUpdateServiceImpl.packageStateChanged(primaryPackage,
    +-                WebViewUpdateService.PACKAGE_ADDED_REPLACED, 1 /* userId */);
    +-        mWebViewUpdateServiceImpl.packageStateChanged(primaryPackage,
    +-                WebViewUpdateService.PACKAGE_ADDED_REPLACED, 2 /* userId */);
    +-        // package still has the same update-time so we shouldn't run preparation here
    +-        Mockito.verify(mTestSystemImpl, Mockito.times(1)).onWebViewProviderChanged(
    +-                Mockito.argThat(new IsPackageInfoWithName(primaryPackage)));
    +-        Mockito.verify(mTestSystemImpl, Mockito.times(1)).enablePackageForUser(
    +-                Mockito.eq(fallbackPackage), Mockito.eq(false) /* enable */,
    +-                Matchers.anyInt() /* user */);
    +-
    +-        // Ensure we can still load the package
    +-        WebViewProviderResponse response = mWebViewUpdateServiceImpl.waitForAndGetProvider();
    +-        assertEquals(WebViewFactory.LIBLOAD_SUCCESS, response.status);
    +-        assertEquals(primaryPackage, response.packageInfo.packageName);
    +-
    +-
    +-        mTestSystemImpl.setPackageInfo(createPackageInfo(primaryPackage, true /* enabled */,
    +-                    true /* valid */, true /* installed */, null /* signatures */,
    +-                    20 /* lastUpdateTime*/ ));
    +-        mWebViewUpdateServiceImpl.packageStateChanged(primaryPackage,
    +-                WebViewUpdateService.PACKAGE_ADDED_REPLACED, 0);
    +-        // The package has now changed - ensure that we have run the preparation phase a second time
    +-        checkPreparationPhasesForPackage(primaryPackage, 2 /* second preparation phase */);
    +-
    +-
    +-        mTestSystemImpl.setPackageInfo(createPackageInfo(primaryPackage, true /* enabled */,
    +-                    true /* valid */, true /* installed */, null /* signatures */,
    +-                    50 /* lastUpdateTime*/ ));
    +-        // Receive intent for different user
    +-        mWebViewUpdateServiceImpl.packageStateChanged(primaryPackage,
    +-                WebViewUpdateService.PACKAGE_ADDED_REPLACED, 2);
    +-
    +-        checkPreparationPhasesForPackage(primaryPackage, 3 /* third preparation phase */);
    +-    }
    +-
    +-}
    +diff --git a/services/tests/shortcutmanagerutils/Android.mk b/services/tests/shortcutmanagerutils/Android.mk
    +deleted file mode 100644
    +index 2818457..0000000
    +--- a/services/tests/shortcutmanagerutils/Android.mk
    ++++ /dev/null
    +@@ -1,31 +0,0 @@
    +-# Copyright (C) 2016 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.
    +-
    +-LOCAL_PATH:= $(call my-dir)
    +-
    +-include $(CLEAR_VARS)
    +-
    +-LOCAL_SRC_FILES := \
    +-    $(call all-java-files-under, src)
    +-
    +-LOCAL_STATIC_JAVA_LIBRARIES := \
    +-    mockito-target
    +-
    +-LOCAL_MODULE_TAGS := optional
    +-
    +-LOCAL_MODULE := ShortcutManagerTestUtils
    +-
    +-LOCAL_SDK_VERSION := test_current
    +-
    +-include $(BUILD_STATIC_JAVA_LIBRARY)
    +diff --git a/services/tests/shortcutmanagerutils/src/com/android/server/pm/shortcutmanagertest/ShortcutManagerTestUtils.java b/services/tests/shortcutmanagerutils/src/com/android/server/pm/shortcutmanagertest/ShortcutManagerTestUtils.java
    +deleted file mode 100644
    +index 1fe5cb7..0000000
    +--- a/services/tests/shortcutmanagerutils/src/com/android/server/pm/shortcutmanagertest/ShortcutManagerTestUtils.java
    ++++ /dev/null
    +@@ -1,1073 +0,0 @@
    +-/*
    +- * Copyright (C) 2016 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 com.android.server.pm.shortcutmanagertest;
    +-
    +-import static junit.framework.Assert.assertEquals;
    +-import static junit.framework.Assert.assertFalse;
    +-import static junit.framework.Assert.assertNotNull;
    +-import static junit.framework.Assert.assertNull;
    +-import static junit.framework.Assert.assertTrue;
    +-import static junit.framework.Assert.fail;
    +-
    +-import static org.mockito.Matchers.any;
    +-import static org.mockito.Matchers.anyList;
    +-import static org.mockito.Matchers.anyString;
    +-import static org.mockito.Matchers.eq;
    +-import static org.mockito.Mockito.mock;
    +-import static org.mockito.Mockito.reset;
    +-import static org.mockito.Mockito.times;
    +-import static org.mockito.Mockito.verify;
    +-
    +-import android.app.Instrumentation;
    +-import android.content.ComponentName;
    +-import android.content.Context;
    +-import android.content.pm.LauncherApps;
    +-import android.content.pm.LauncherApps.Callback;
    +-import android.content.pm.ShortcutInfo;
    +-import android.graphics.Bitmap;
    +-import android.graphics.BitmapFactory;
    +-import android.os.BaseBundle;
    +-import android.os.Bundle;
    +-import android.os.Handler;
    +-import android.os.Looper;
    +-import android.os.Parcel;
    +-import android.os.ParcelFileDescriptor;
    +-import android.os.PersistableBundle;
    +-import android.os.UserHandle;
    +-import android.test.MoreAsserts;
    +-import android.util.Log;
    +-
    +-import junit.framework.Assert;
    +-
    +-import org.hamcrest.BaseMatcher;
    +-import org.hamcrest.Description;
    +-import org.hamcrest.Matcher;
    +-import org.json.JSONException;
    +-import org.json.JSONObject;
    +-import org.mockito.ArgumentCaptor;
    +-import org.mockito.Mockito;
    +-
    +-import java.io.BufferedReader;
    +-import java.io.File;
    +-import java.io.FileNotFoundException;
    +-import java.io.FileReader;
    +-import java.io.IOException;
    +-import java.util.ArrayList;
    +-import java.util.Arrays;
    +-import java.util.Collection;
    +-import java.util.Collections;
    +-import java.util.Comparator;
    +-import java.util.LinkedHashSet;
    +-import java.util.List;
    +-import java.util.Set;
    +-import java.util.SortedSet;
    +-import java.util.TreeSet;
    +-import java.util.concurrent.CountDownLatch;
    +-import java.util.function.BooleanSupplier;
    +-import java.util.function.Consumer;
    +-import java.util.function.Function;
    +-import java.util.function.Predicate;
    +-
    +-/**
    +- * Common utility methods for ShortcutManager tests.  This is used by both CTS and the unit tests.
    +- * Because it's used by CTS too, it can only access the public APIs.
    +- */
    +-public class ShortcutManagerTestUtils {
    +-    private static final String TAG = "ShortcutManagerUtils";
    +-
    +-    private static final boolean ENABLE_DUMPSYS = true; // DO NOT SUBMIT WITH true
    +-
    +-    private static final int STANDARD_TIMEOUT_SEC = 5;
    +-
    +-    private static final String[] EMPTY_STRINGS = new String[0];
    +-
    +-    private ShortcutManagerTestUtils() {
    +-    }
    +-
    +-    public static List<String> readAll(File file) throws FileNotFoundException {
    +-        return readAll(ParcelFileDescriptor.open(
    +-                file.getAbsoluteFile(), ParcelFileDescriptor.MODE_READ_ONLY));
    +-    }
    +-
    +-    public static List<String> readAll(ParcelFileDescriptor pfd) {
    +-        try {
    +-            try {
    +-                final ArrayList<String> ret = new ArrayList<>();
    +-                try (BufferedReader r = new BufferedReader(
    +-                        new FileReader(pfd.getFileDescriptor()))) {
    +-                    String line;
    +-                    while ((line = r.readLine()) != null) {
    +-                        ret.add(line);
    +-                    }
    +-                    r.readLine();
    +-                }
    +-                return ret;
    +-            } finally {
    +-                pfd.close();
    +-            }
    +-        } catch (IOException e) {
    +-            throw new RuntimeException(e);
    +-        }
    +-    }
    +-
    +-    public static String concatResult(List<String> result) {
    +-        final StringBuilder sb = new StringBuilder();
    +-        for (String s : result) {
    +-            sb.append(s);
    +-            sb.append("\n");
    +-        }
    +-        return sb.toString();
    +-    }
    +-
    +-    public static boolean resultContains(List<String> result, String expected) {
    +-        for (String line : result) {
    +-            if (line.contains(expected)) {
    +-                return true;
    +-            }
    +-        }
    +-        return false;
    +-    }
    +-
    +-    public static List<String> assertSuccess(List<String> result) {
    +-        if (!resultContains(result, "Success")) {
    +-            fail("Command failed.  Result was:\n" + concatResult(result));
    +-        }
    +-        return result;
    +-    }
    +-
    +-    public static List<String> assertContains(List<String> result, String expected) {
    +-        if (!resultContains(result, expected)) {
    +-            fail("Didn't contain expected string=" + expected
    +-                    + "\nActual:\n" + concatResult(result));
    +-        }
    +-        return result;
    +-    }
    +-
    +-    public static List<String> runCommand(Instrumentation instrumentation, String command) {
    +-        return runCommand(instrumentation, command, null);
    +-    }
    +-    public static List<String> runCommand(Instrumentation instrumentation, String command,
    +-            Predicate<List<String>> resultAsserter) {
    +-        Log.d(TAG, "Running command: " + command);
    +-        final List<String> result;
    +-        try {
    +-            result = readAll(
    +-                    instrumentation.getUiAutomation().executeShellCommand(command));
    +-        } catch (Exception e) {
    +-            throw new RuntimeException(e);
    +-        }
    +-        if (resultAsserter != null && !resultAsserter.test(result)) {
    +-            fail("Command '" + command + "' failed, output was:\n" + concatResult(result));
    +-        }
    +-        return result;
    +-    }
    +-
    +-    public static void runCommandForNoOutput(Instrumentation instrumentation, String command) {
    +-        runCommand(instrumentation, command, result -> result.size() == 0);
    +-    }
    +-
    +-    public static List<String> runShortcutCommand(Instrumentation instrumentation, String command,
    +-            Predicate<List<String>> resultAsserter) {
    +-        return runCommand(instrumentation, "cmd shortcut " + command, resultAsserter);
    +-    }
    +-
    +-    public static List<String> runShortcutCommandForSuccess(Instrumentation instrumentation,
    +-            String command) {
    +-        return runShortcutCommand(instrumentation, command, result -> result.contains("Success"));
    +-    }
    +-
    +-    public static String getDefaultLauncher(Instrumentation instrumentation) {
    +-        final String PREFIX = "Launcher: ComponentInfo{";
    +-        final String POSTFIX = "}";
    +-        final List<String> result = runShortcutCommandForSuccess(
    +-                instrumentation, "get-default-launcher");
    +-        for (String s : result) {
    +-            if (s.startsWith(PREFIX) && s.endsWith(POSTFIX)) {
    +-                return s.substring(PREFIX.length(), s.length() - POSTFIX.length());
    +-            }
    +-        }
    +-        fail("Default launcher not found");
    +-        return null;
    +-    }
    +-
    +-    public static void setDefaultLauncher(Instrumentation instrumentation, String component) {
    +-        runCommand(instrumentation, "cmd package set-home-activity --user "
    +-                + instrumentation.getContext().getUserId() + " " + component,
    +-                result -> result.contains("Success"));
    +-    }
    +-
    +-    public static void setDefaultLauncher(Instrumentation instrumentation, Context packageContext) {
    +-        setDefaultLauncher(instrumentation, packageContext.getPackageName()
    +-                + "/android.content.pm.cts.shortcutmanager.packages.Launcher");
    +-    }
    +-
    +-    public static void overrideConfig(Instrumentation instrumentation, String config) {
    +-        runShortcutCommandForSuccess(instrumentation, "override-config " + config);
    +-    }
    +-
    +-    public static void resetConfig(Instrumentation instrumentation) {
    +-        runShortcutCommandForSuccess(instrumentation, "reset-config");
    +-    }
    +-
    +-    public static void resetThrottling(Instrumentation instrumentation) {
    +-        runShortcutCommandForSuccess(instrumentation, "reset-throttling");
    +-    }
    +-
    +-    public static void resetAllThrottling(Instrumentation instrumentation) {
    +-        runShortcutCommandForSuccess(instrumentation, "reset-all-throttling");
    +-    }
    +-
    +-    public static void clearShortcuts(Instrumentation instrumentation, int userId,
    +-            String packageName) {
    +-        runShortcutCommandForSuccess(instrumentation, "clear-shortcuts "
    +-                + " --user " + userId + " " + packageName);
    +-    }
    +-
    +-    public static void anyContains(List<String> result, String expected) {
    +-        for (String l : result) {
    +-            if (l.contains(expected)) {
    +-                return;
    +-            }
    +-        }
    +-        fail("Result didn't contain '" + expected + "': was\n" + result);
    +-    }
    +-
    +-    public static void enableComponent(Instrumentation instrumentation, ComponentName cn,
    +-            boolean enable) {
    +-
    +-        final String word = (enable ? "enable" : "disable");
    +-        runCommand(instrumentation,
    +-                "pm " + word + " " + cn.flattenToString()
    +-                , result ->concatResult(result).contains(word));
    +-    }
    +-
    +-    public static void appOps(Instrumentation instrumentation, String packageName,
    +-            String op, String mode) {
    +-        runCommand(instrumentation, "appops set " + packageName + " " + op + " " + mode);
    +-    }
    +-
    +-    public static void dumpsysShortcut(Instrumentation instrumentation) {
    +-        if (!ENABLE_DUMPSYS) {
    +-            return;
    +-        }
    +-        Log.e(TAG, "Dumpsys shortcut");
    +-        for (String s : runCommand(instrumentation, "dumpsys shortcut")) {
    +-            Log.e(TAG, s);
    +-        }
    +-    }
    +-
    +-    public static JSONObject getCheckinDump(Instrumentation instrumentation) throws JSONException {
    +-        return new JSONObject(concatResult(runCommand(instrumentation, "dumpsys shortcut -c")));
    +-    }
    +-
    +-    public static boolean isLowRamDevice(Instrumentation instrumentation) throws JSONException {
    +-        return getCheckinDump(instrumentation).getBoolean("lowRam");
    +-    }
    +-
    +-    public static int getIconSize(Instrumentation instrumentation) throws JSONException {
    +-        return getCheckinDump(instrumentation).getInt("iconSize");
    +-    }
    +-
    +-    public static Bundle makeBundle(Object... keysAndValues) {
    +-        assertTrue((keysAndValues.length % 2) == 0);
    +-
    +-        if (keysAndValues.length == 0) {
    +-            return null;
    +-        }
    +-        final Bundle ret = new Bundle();
    +-
    +-        for (int i = keysAndValues.length - 2; i >= 0; i -= 2) {
    +-            final String key = keysAndValues[i].toString();
    +-            final Object value = keysAndValues[i + 1];
    +-
    +-            if (value == null) {
    +-                ret.putString(key, null);
    +-            } else if (value instanceof Integer) {
    +-                ret.putInt(key, (Integer) value);
    +-            } else if (value instanceof String) {
    +-                ret.putString(key, (String) value);
    +-            } else if (value instanceof Bundle) {
    +-                ret.putBundle(key, (Bundle) value);
    +-            } else {
    +-                fail("Type not supported yet: " + value.getClass().getName());
    +-            }
    +-        }
    +-        return ret;
    +-    }
    +-
    +-    public static PersistableBundle makePersistableBundle(Object... keysAndValues) {
    +-        assertTrue((keysAndValues.length % 2) == 0);
    +-
    +-        if (keysAndValues.length == 0) {
    +-            return null;
    +-        }
    +-        final PersistableBundle ret = new PersistableBundle();
    +-
    +-        for (int i = keysAndValues.length - 2; i >= 0; i -= 2) {
    +-            final String key = keysAndValues[i].toString();
    +-            final Object value = keysAndValues[i + 1];
    +-
    +-            if (value == null) {
    +-                ret.putString(key, null);
    +-            } else if (value instanceof Integer) {
    +-                ret.putInt(key, (Integer) value);
    +-            } else if (value instanceof String) {
    +-                ret.putString(key, (String) value);
    +-            } else if (value instanceof PersistableBundle) {
    +-                ret.putPersistableBundle(key, (PersistableBundle) value);
    +-            } else {
    +-                fail("Type not supported yet: " + value.getClass().getName());
    +-            }
    +-        }
    +-        return ret;
    +-    }
    +-
    +-    public static <T> List<T> list(T... array) {
    +-        return Arrays.asList(array);
    +-    }
    +-
    +-    public static <T> Set<T> hashSet(Set<T> in) {
    +-        return new LinkedHashSet<>(in);
    +-    }
    +-
    +-    public static <T> Set<T> set(T... values) {
    +-        return set(v -> v, values);
    +-    }
    +-
    +-    public static <T, V> Set<T> set(Function<V, T> converter, V... values) {
    +-        return set(converter, Arrays.asList(values));
    +-    }
    +-
    +-    public static <T, V> Set<T> set(Function<V, T> converter, List<V> values) {
    +-        final LinkedHashSet<T> ret = new LinkedHashSet<>();
    +-        for (V v : values) {
    +-            ret.add(converter.apply(v));
    +-        }
    +-        return ret;
    +-    }
    +-
    +-    public static void resetAll(Collection<?> mocks) {
    +-        for (Object o : mocks) {
    +-            reset(o);
    +-        }
    +-    }
    +-
    +-    public static <T extends Collection<?>> T assertEmpty(T collection) {
    +-        if (collection == null) {
    +-            return collection; // okay.
    +-        }
    +-        assertEquals(0, collection.size());
    +-        return collection;
    +-    }
    +-
    +-    public static List<ShortcutInfo> filter(List<ShortcutInfo> list, Predicate<ShortcutInfo> p) {
    +-        final ArrayList<ShortcutInfo> ret = new ArrayList<>(list);
    +-        ret.removeIf(si -> !p.test(si));
    +-        return ret;
    +-    }
    +-
    +-    public static List<ShortcutInfo> filterByActivity(List<ShortcutInfo> list,
    +-            ComponentName activity) {
    +-        return filter(list, si ->
    +-                (si.getActivity().equals(activity)
    +-                        && (si.isDeclaredInManifest() || si.isDynamic())));
    +-    }
    +-
    +-    public static List<ShortcutInfo> changedSince(List<ShortcutInfo> list, long time) {
    +-        return filter(list, si -> si.getLastChangedTimestamp() >= time);
    +-    }
    +-
    +-    @FunctionalInterface
    +-    public interface ExceptionRunnable {
    +-        void run() throws Exception;
    +-    }
    +-
    +-    public static void assertExpectException(Class<? extends Throwable> expectedExceptionType,
    +-            String expectedExceptionMessageRegex, ExceptionRunnable r) {
    +-        assertExpectException("", expectedExceptionType, expectedExceptionMessageRegex, r);
    +-    }
    +-
    +-    public static void assertCannotUpdateImmutable(Runnable r) {
    +-        assertExpectException(
    +-                IllegalArgumentException.class, "may not be manipulated via APIs", r::run);
    +-    }
    +-
    +-    public static void assertDynamicShortcutCountExceeded(Runnable r) {
    +-        assertExpectException(IllegalArgumentException.class,
    +-                "Max number of dynamic shortcuts exceeded", r::run);
    +-    }
    +-
    +-    public static void assertExpectException(String message,
    +-            Class<? extends Throwable> expectedExceptionType,
    +-            String expectedExceptionMessageRegex, ExceptionRunnable r) {
    +-        try {
    +-            r.run();
    +-        } catch (Throwable e) {
    +-            Assert.assertTrue(
    +-                    "Expected exception type was " + expectedExceptionType.getName()
    +-                            + " but caught " + e + " (message=" + message + ")",
    +-                    expectedExceptionType.isAssignableFrom(e.getClass()));
    +-            if (expectedExceptionMessageRegex != null) {
    +-                MoreAsserts.assertContainsRegex(expectedExceptionMessageRegex, e.getMessage());
    +-            }
    +-            return; // Pass
    +-        }
    +-        Assert.fail("Expected exception type " + expectedExceptionType.getName()
    +-                + " was not thrown");
    +-    }
    +-
    +-    public static List<ShortcutInfo> assertShortcutIds(List<ShortcutInfo> actualShortcuts,
    +-            String... expectedIds) {
    +-        final SortedSet<String> expected = new TreeSet<>(list(expectedIds));
    +-        final SortedSet<String> actual = new TreeSet<>();
    +-        for (ShortcutInfo s : actualShortcuts) {
    +-            actual.add(s.getId());
    +-        }
    +-
    +-        // Compare the sets.
    +-        assertEquals(expected, actual);
    +-        return actualShortcuts;
    +-    }
    +-
    +-    public static List<ShortcutInfo> assertShortcutIdsOrdered(List<ShortcutInfo> actualShortcuts,
    +-            String... expectedIds) {
    +-        final ArrayList<String> expected = new ArrayList<>(list(expectedIds));
    +-        final ArrayList<String> actual = new ArrayList<>();
    +-        for (ShortcutInfo s : actualShortcuts) {
    +-            actual.add(s.getId());
    +-        }
    +-        assertEquals(expected, actual);
    +-        return actualShortcuts;
    +-    }
    +-
    +-    public static List<ShortcutInfo> assertAllHaveIntents(
    +-            List<ShortcutInfo> actualShortcuts) {
    +-        for (ShortcutInfo s : actualShortcuts) {
    +-            assertNotNull("ID " + s.getId(), s.getIntent());
    +-        }
    +-        return actualShortcuts;
    +-    }
    +-
    +-    public static List<ShortcutInfo> assertAllNotHaveIntents(
    +-            List<ShortcutInfo> actualShortcuts) {
    +-        for (ShortcutInfo s : actualShortcuts) {
    +-            assertNull("ID " + s.getId(), s.getIntent());
    +-        }
    +-        return actualShortcuts;
    +-    }
    +-
    +-    public static List<ShortcutInfo> assertAllHaveTitle(
    +-            List<ShortcutInfo> actualShortcuts) {
    +-        for (ShortcutInfo s : actualShortcuts) {
    +-            assertNotNull("ID " + s.getId(), s.getShortLabel());
    +-        }
    +-        return actualShortcuts;
    +-    }
    +-
    +-    public static List<ShortcutInfo> assertAllNotHaveTitle(
    +-            List<ShortcutInfo> actualShortcuts) {
    +-        for (ShortcutInfo s : actualShortcuts) {
    +-            assertNull("ID " + s.getId(), s.getShortLabel());
    +-        }
    +-        return actualShortcuts;
    +-    }
    +-
    +-    public static List<ShortcutInfo> assertAllKeyFieldsOnly(
    +-            List<ShortcutInfo> actualShortcuts) {
    +-        for (ShortcutInfo s : actualShortcuts) {
    +-            assertTrue("ID " + s.getId(), s.hasKeyFieldsOnly());
    +-        }
    +-        return actualShortcuts;
    +-    }
    +-
    +-    public static List<ShortcutInfo> assertAllNotKeyFieldsOnly(
    +-            List<ShortcutInfo> actualShortcuts) {
    +-        for (ShortcutInfo s : actualShortcuts) {
    +-            assertFalse("ID " + s.getId(), s.hasKeyFieldsOnly());
    +-        }
    +-        return actualShortcuts;
    +-    }
    +-
    +-    public static List<ShortcutInfo> assertAllDynamic(List<ShortcutInfo> actualShortcuts) {
    +-        for (ShortcutInfo s : actualShortcuts) {
    +-            assertTrue("ID " + s.getId(), s.isDynamic());
    +-        }
    +-        return actualShortcuts;
    +-    }
    +-
    +-    public static List<ShortcutInfo> assertAllPinned(List<ShortcutInfo> actualShortcuts) {
    +-        for (ShortcutInfo s : actualShortcuts) {
    +-            assertTrue("ID " + s.getId(), s.isPinned());
    +-        }
    +-        return actualShortcuts;
    +-    }
    +-
    +-    public static List<ShortcutInfo> assertAllDynamicOrPinned(
    +-            List<ShortcutInfo> actualShortcuts) {
    +-        for (ShortcutInfo s : actualShortcuts) {
    +-            assertTrue("ID " + s.getId(), s.isDynamic() || s.isPinned());
    +-        }
    +-        return actualShortcuts;
    +-    }
    +-
    +-    public static List<ShortcutInfo> assertAllManifest(
    +-            List<ShortcutInfo> actualShortcuts) {
    +-        for (ShortcutInfo s : actualShortcuts) {
    +-            assertTrue("ID " + s.getId(), s.isDeclaredInManifest());
    +-        }
    +-        return actualShortcuts;
    +-    }
    +-
    +-    public static List<ShortcutInfo> assertAllNotManifest(
    +-            List<ShortcutInfo> actualShortcuts) {
    +-        for (ShortcutInfo s : actualShortcuts) {
    +-            assertFalse("ID " + s.getId(), s.isDeclaredInManifest());
    +-        }
    +-        return actualShortcuts;
    +-    }
    +-
    +-    public static List<ShortcutInfo> assertAllDisabled(
    +-            List<ShortcutInfo> actualShortcuts) {
    +-        for (ShortcutInfo s : actualShortcuts) {
    +-            assertTrue("ID " + s.getId(), !s.isEnabled());
    +-        }
    +-        return actualShortcuts;
    +-    }
    +-
    +-    public static List<ShortcutInfo> assertAllEnabled(
    +-            List<ShortcutInfo> actualShortcuts) {
    +-        for (ShortcutInfo s : actualShortcuts) {
    +-            assertTrue("ID " + s.getId(), s.isEnabled());
    +-        }
    +-        return actualShortcuts;
    +-    }
    +-
    +-    public static List<ShortcutInfo> assertAllImmutable(
    +-            List<ShortcutInfo> actualShortcuts) {
    +-        for (ShortcutInfo s : actualShortcuts) {
    +-            assertTrue("ID " + s.getId(), s.isImmutable());
    +-        }
    +-        return actualShortcuts;
    +-    }
    +-
    +-    public static void assertDynamicOnly(ShortcutInfo si) {
    +-        assertTrue(si.isDynamic());
    +-        assertFalse(si.isPinned());
    +-    }
    +-
    +-    public static void assertPinnedOnly(ShortcutInfo si) {
    +-        assertFalse(si.isDynamic());
    +-        assertFalse(si.isDeclaredInManifest());
    +-        assertTrue(si.isPinned());
    +-    }
    +-
    +-    public static void assertDynamicAndPinned(ShortcutInfo si) {
    +-        assertTrue(si.isDynamic());
    +-        assertTrue(si.isPinned());
    +-    }
    +-
    +-    public static void assertBitmapSize(int expectedWidth, int expectedHeight, Bitmap bitmap) {
    +-        assertEquals("width", expectedWidth, bitmap.getWidth());
    +-        assertEquals("height", expectedHeight, bitmap.getHeight());
    +-    }
    +-
    +-    public static <T> void assertAllUnique(Collection<T> list) {
    +-        final Set<Object> set = new LinkedHashSet<>();
    +-        for (T item : list) {
    +-            if (set.contains(item)) {
    +-                fail("Duplicate item found: " + item + " (in the list: " + list + ")");
    +-            }
    +-            set.add(item);
    +-        }
    +-    }
    +-
    +-    public static ShortcutInfo findShortcut(List<ShortcutInfo> list, String id) {
    +-        for (ShortcutInfo si : list) {
    +-            if (si.getId().equals(id)) {
    +-                return si;
    +-            }
    +-        }
    +-        fail("Shortcut " + id + " not found in the list");
    +-        return null;
    +-    }
    +-
    +-    public static Bitmap pfdToBitmap(ParcelFileDescriptor pfd) {
    +-        assertNotNull(pfd);
    +-        try {
    +-            try {
    +-                return BitmapFactory.decodeFileDescriptor(pfd.getFileDescriptor());
    +-            } finally {
    +-                pfd.close();
    +-            }
    +-        } catch (IOException e) {
    +-            throw new RuntimeException(e);
    +-        }
    +-    }
    +-
    +-    public static void assertBundleEmpty(BaseBundle b) {
    +-        assertTrue(b == null || b.size() == 0);
    +-    }
    +-
    +-    public static void assertCallbackNotReceived(LauncherApps.Callback mock) {
    +-        verify(mock, times(0)).onShortcutsChanged(anyString(), anyList(),
    +-                any(UserHandle.class));
    +-    }
    +-
    +-    public static void assertCallbackReceived(LauncherApps.Callback mock,
    +-            UserHandle user, String packageName, String... ids) {
    +-        verify(mock).onShortcutsChanged(eq(packageName), checkShortcutIds(ids),
    +-                eq(user));
    +-    }
    +-
    +-    public static boolean checkAssertSuccess(Runnable r) {
    +-        try {
    +-            r.run();
    +-            return true;
    +-        } catch (AssertionError e) {
    +-            return false;
    +-        }
    +-    }
    +-
    +-    public static <T> T checkArgument(Predicate<T> checker, String description,
    +-            List<T> matchedCaptor) {
    +-        final Matcher<T> m = new BaseMatcher<T>() {
    +-            @Override
    +-            public boolean matches(Object item) {
    +-                if (item == null) {
    +-                    return false;
    +-                }
    +-                final T value = (T) item;
    +-                if (!checker.test(value)) {
    +-                    return false;
    +-                }
    +-
    +-                if (matchedCaptor != null) {
    +-                    matchedCaptor.add(value);
    +-                }
    +-                return true;
    +-            }
    +-
    +-            @Override
    +-            public void describeTo(Description d) {
    +-                d.appendText(description);
    +-            }
    +-        };
    +-        return Mockito.argThat(m);
    +-    }
    +-
    +-    public static List<ShortcutInfo> checkShortcutIds(String... ids) {
    +-        return checkArgument((List<ShortcutInfo> list) -> {
    +-            final Set<String> actualSet = set(si -> si.getId(), list);
    +-            return actualSet.equals(set(ids));
    +-
    +-        }, "Shortcut IDs=[" + Arrays.toString(ids) + "]", null);
    +-    }
    +-
    +-    public static ShortcutInfo parceled(ShortcutInfo si) {
    +-        Parcel p = Parcel.obtain();
    +-        p.writeParcelable(si, 0);
    +-        p.setDataPosition(0);
    +-        ShortcutInfo si2 = p.readParcelable(ShortcutManagerTestUtils.class.getClassLoader());
    +-        p.recycle();
    +-        return si2;
    +-    }
    +-
    +-    public static List<ShortcutInfo> cloneShortcutList(List<ShortcutInfo> list) {
    +-        if (list == null) {
    +-            return null;
    +-        }
    +-        final List<ShortcutInfo> ret = new ArrayList<>(list.size());
    +-        for (ShortcutInfo si : list) {
    +-            ret.add(parceled(si));
    +-        }
    +-
    +-        return ret;
    +-    }
    +-
    +-    private static final Comparator<ShortcutInfo> sRankComparator =
    +-            (ShortcutInfo a, ShortcutInfo b) -> Integer.compare(a.getRank(), b.getRank());
    +-
    +-    public static List<ShortcutInfo> sortedByRank(List<ShortcutInfo> shortcuts) {
    +-        final ArrayList<ShortcutInfo> ret = new ArrayList<>(shortcuts);
    +-        Collections.sort(ret, sRankComparator);
    +-        return ret;
    +-    }
    +-
    +-    public static void waitUntil(String message, BooleanSupplier condition) {
    +-        waitUntil(message, condition, STANDARD_TIMEOUT_SEC);
    +-    }
    +-
    +-    public static void waitUntil(String message, BooleanSupplier condition, int timeoutSeconds) {
    +-        final long timeout = System.currentTimeMillis() + (timeoutSeconds * 1000L);
    +-        while (System.currentTimeMillis() < timeout) {
    +-            if (condition.getAsBoolean()) {
    +-                return;
    +-            }
    +-            try {
    +-                Thread.sleep(100);
    +-            } catch (InterruptedException e) {
    +-                throw new RuntimeException(e);
    +-            }
    +-        }
    +-        fail("Timed out for: " + message);
    +-    }
    +-
    +-    public static ShortcutListAsserter assertWith(List<ShortcutInfo> list) {
    +-        return new ShortcutListAsserter(list);
    +-    }
    +-
    +-    /**
    +-     * New style assertion that allows chained calls.
    +-     */
    +-    public static class ShortcutListAsserter {
    +-        private final ShortcutListAsserter mOriginal;
    +-        private final List<ShortcutInfo> mList;
    +-
    +-        ShortcutListAsserter(List<ShortcutInfo> list) {
    +-            this(null, list);
    +-        }
    +-
    +-        private ShortcutListAsserter(ShortcutListAsserter original, List<ShortcutInfo> list) {
    +-            mOriginal = (original == null) ? this : original;
    +-            mList = (list == null) ? new ArrayList<>(0) : new ArrayList<>(list);
    +-        }
    +-
    +-        public ShortcutListAsserter revertToOriginalList() {
    +-            return mOriginal;
    +-        }
    +-
    +-        public ShortcutListAsserter selectDynamic() {
    +-            return new ShortcutListAsserter(this,
    +-                    filter(mList, ShortcutInfo::isDynamic));
    +-        }
    +-
    +-        public ShortcutListAsserter selectManifest() {
    +-            return new ShortcutListAsserter(this,
    +-                    filter(mList, ShortcutInfo::isDeclaredInManifest));
    +-        }
    +-
    +-        public ShortcutListAsserter selectPinned() {
    +-            return new ShortcutListAsserter(this,
    +-                    filter(mList, ShortcutInfo::isPinned));
    +-        }
    +-
    +-        public ShortcutListAsserter selectByActivity(ComponentName activity) {
    +-            return new ShortcutListAsserter(this,
    +-                    ShortcutManagerTestUtils.filterByActivity(mList, activity));
    +-        }
    +-
    +-        public ShortcutListAsserter selectByChangedSince(long time) {
    +-            return new ShortcutListAsserter(this,
    +-                    ShortcutManagerTestUtils.changedSince(mList, time));
    +-        }
    +-
    +-        public ShortcutListAsserter selectByIds(String... ids) {
    +-            final Set<String> idSet = set(ids);
    +-            final ArrayList<ShortcutInfo> selected = new ArrayList<>();
    +-            for (ShortcutInfo si : mList) {
    +-                if (idSet.contains(si.getId())) {
    +-                    selected.add(si);
    +-                    idSet.remove(si.getId());
    +-                }
    +-            }
    +-            if (idSet.size() > 0) {
    +-                fail("Shortcuts not found for IDs=" + idSet);
    +-            }
    +-
    +-            return new ShortcutListAsserter(this, selected);
    +-        }
    +-
    +-        public ShortcutListAsserter toSortByRank() {
    +-            return new ShortcutListAsserter(this,
    +-                    ShortcutManagerTestUtils.sortedByRank(mList));
    +-        }
    +-
    +-        public ShortcutListAsserter call(Consumer<List<ShortcutInfo>> c) {
    +-            c.accept(mList);
    +-            return this;
    +-        }
    +-
    +-        public ShortcutListAsserter haveIds(String... expectedIds) {
    +-            assertShortcutIds(mList, expectedIds);
    +-            return this;
    +-        }
    +-
    +-        public ShortcutListAsserter haveIdsOrdered(String... expectedIds) {
    +-            assertShortcutIdsOrdered(mList, expectedIds);
    +-            return this;
    +-        }
    +-
    +-        private ShortcutListAsserter haveSequentialRanks() {
    +-            for (int i = 0; i < mList.size(); i++) {
    +-                final ShortcutInfo si = mList.get(i);
    +-                assertEquals("Rank not sequential: id=" + si.getId(), i, si.getRank());
    +-            }
    +-            return this;
    +-        }
    +-
    +-        public ShortcutListAsserter haveRanksInOrder(String... expectedIds) {
    +-            toSortByRank()
    +-                    .haveSequentialRanks()
    +-                    .haveIdsOrdered(expectedIds);
    +-            return this;
    +-        }
    +-
    +-        public ShortcutListAsserter isEmpty() {
    +-            assertEquals(0, mList.size());
    +-            return this;
    +-        }
    +-
    +-        public ShortcutListAsserter areAllDynamic() {
    +-            forAllShortcuts(s -> assertTrue("id=" + s.getId(), s.isDynamic()));
    +-            return this;
    +-        }
    +-
    +-        public ShortcutListAsserter areAllNotDynamic() {
    +-            forAllShortcuts(s -> assertFalse("id=" + s.getId(), s.isDynamic()));
    +-            return this;
    +-        }
    +-
    +-        public ShortcutListAsserter areAllPinned() {
    +-            forAllShortcuts(s -> assertTrue("id=" + s.getId(), s.isPinned()));
    +-            return this;
    +-        }
    +-
    +-        public ShortcutListAsserter areAllNotPinned() {
    +-            forAllShortcuts(s -> assertFalse("id=" + s.getId(), s.isPinned()));
    +-            return this;
    +-        }
    +-
    +-        public ShortcutListAsserter areAllManifest() {
    +-            forAllShortcuts(s -> assertTrue("id=" + s.getId(), s.isDeclaredInManifest()));
    +-            return this;
    +-        }
    +-
    +-        public ShortcutListAsserter areAllNotManifest() {
    +-            forAllShortcuts(s -> assertFalse("id=" + s.getId(), s.isDeclaredInManifest()));
    +-            return this;
    +-        }
    +-
    +-        public ShortcutListAsserter areAllImmutable() {
    +-            forAllShortcuts(s -> assertTrue("id=" + s.getId(), s.isImmutable()));
    +-            return this;
    +-        }
    +-
    +-        public ShortcutListAsserter areAllMutable() {
    +-            forAllShortcuts(s -> assertFalse("id=" + s.getId(), s.isImmutable()));
    +-            return this;
    +-        }
    +-
    +-        public ShortcutListAsserter areAllEnabled() {
    +-            forAllShortcuts(s -> assertTrue("id=" + s.getId(), s.isEnabled()));
    +-            return this;
    +-        }
    +-
    +-        public ShortcutListAsserter areAllDisabled() {
    +-            forAllShortcuts(s -> assertFalse("id=" + s.getId(), s.isEnabled()));
    +-            return this;
    +-        }
    +-
    +-        public ShortcutListAsserter areAllWithKeyFieldsOnly() {
    +-            forAllShortcuts(s -> assertTrue("id=" + s.getId(), s.hasKeyFieldsOnly()));
    +-            return this;
    +-        }
    +-
    +-        public ShortcutListAsserter areAllNotWithKeyFieldsOnly() {
    +-            forAllShortcuts(s -> assertFalse("id=" + s.getId(), s.hasKeyFieldsOnly()));
    +-            return this;
    +-        }
    +-
    +-        public ShortcutListAsserter areAllWithActivity(ComponentName activity) {
    +-            forAllShortcuts(s -> assertTrue("id=" + s.getId(), s.getActivity().equals(activity)));
    +-            return this;
    +-        }
    +-
    +-        public ShortcutListAsserter forAllShortcuts(Consumer<ShortcutInfo> sa) {
    +-            boolean found = false;
    +-            for (int i = 0; i < mList.size(); i++) {
    +-                final ShortcutInfo si = mList.get(i);
    +-                found = true;
    +-                sa.accept(si);
    +-            }
    +-            assertTrue("No shortcuts found.", found);
    +-            return this;
    +-        }
    +-
    +-        public ShortcutListAsserter forShortcut(Predicate<ShortcutInfo> p,
    +-                Consumer<ShortcutInfo> sa) {
    +-            boolean found = false;
    +-            for (int i = 0; i < mList.size(); i++) {
    +-                final ShortcutInfo si = mList.get(i);
    +-                if (p.test(si)) {
    +-                    found = true;
    +-                    try {
    +-                        sa.accept(si);
    +-                    } catch (Throwable e) {
    +-                        throw new AssertionError("Assertion failed for shortcut " + si.getId(), e);
    +-                    }
    +-                }
    +-            }
    +-            assertTrue("Shortcut with the given condition not found.", found);
    +-            return this;
    +-        }
    +-
    +-        public ShortcutListAsserter forShortcutWithId(String id, Consumer<ShortcutInfo> sa) {
    +-            forShortcut(si -> si.getId().equals(id), sa);
    +-
    +-            return this;
    +-        }
    +-    }
    +-
    +-    public static void assertBundlesEqual(BaseBundle b1, BaseBundle b2) {
    +-        if (b1 == null && b2 == null) {
    +-            return; // pass
    +-        }
    +-        assertNotNull("b1 is null but b2 is not", b1);
    +-        assertNotNull("b2 is null but b1 is not", b2);
    +-
    +-        // HashSet makes the error message readable.
    +-        assertEquals(set(b1.keySet()), set(b2.keySet()));
    +-
    +-        for (String key : b1.keySet()) {
    +-            final Object v1 = b1.get(key);
    +-            final Object v2 = b2.get(key);
    +-            if (v1 == null) {
    +-                if (v2 == null) {
    +-                    return;
    +-                }
    +-            }
    +-            if (v1.equals(v2)) {
    +-                return;
    +-            }
    +-
    +-            assertTrue("Only either value is null: key=" + key
    +-                    + " b1=" + b1 + " b2=" + b2, v1 != null && v2 != null);
    +-            assertEquals("Class mismatch: key=" + key, v1.getClass(), v2.getClass());
    +-
    +-            if (v1 instanceof BaseBundle) {
    +-                assertBundlesEqual((BaseBundle) v1, (BaseBundle) v2);
    +-
    +-            } else if (v1 instanceof boolean[]) {
    +-                assertTrue(Arrays.equals((boolean[]) v1, (boolean[]) v2));
    +-
    +-            } else if (v1 instanceof int[]) {
    +-                MoreAsserts.assertEquals((int[]) v1, (int[]) v2);
    +-
    +-            } else if (v1 instanceof double[]) {
    +-                MoreAsserts.assertEquals((double[]) v1, (double[]) v2);
    +-
    +-            } else if (v1 instanceof String[]) {
    +-                MoreAsserts.assertEquals((String[]) v1, (String[]) v2);
    +-
    +-            } else if (v1 instanceof Double) {
    +-                if (((Double) v1).isNaN()) {
    +-                    assertTrue(((Double) v2).isNaN());
    +-                } else {
    +-                    assertEquals(v1, v2);
    +-                }
    +-
    +-            } else {
    +-                assertEquals(v1, v2);
    +-            }
    +-        }
    +-    }
    +-
    +-    public static void waitOnMainThread() throws InterruptedException {
    +-        final CountDownLatch latch = new CountDownLatch(1);
    +-
    +-        new Handler(Looper.getMainLooper()).post(() -> latch.countDown());
    +-
    +-        latch.await();
    +-    }
    +-
    +-    public static class LauncherCallbackAsserter {
    +-        private final LauncherApps.Callback mCallback = mock(LauncherApps.Callback.class);
    +-
    +-        private Callback getMockCallback() {
    +-            return mCallback;
    +-        }
    +-
    +-        public LauncherCallbackAsserter assertNoCallbackCalled() {
    +-            verify(mCallback, times(0)).onShortcutsChanged(
    +-                    anyString(),
    +-                    any(List.class),
    +-                    any(UserHandle.class));
    +-            return this;
    +-        }
    +-
    +-        public LauncherCallbackAsserter assertNoCallbackCalledForPackage(
    +-                String publisherPackageName) {
    +-            verify(mCallback, times(0)).onShortcutsChanged(
    +-                    eq(publisherPackageName),
    +-                    any(List.class),
    +-                    any(UserHandle.class));
    +-            return this;
    +-        }
    +-
    +-        public LauncherCallbackAsserter assertNoCallbackCalledForPackageAndUser(
    +-                String publisherPackageName, UserHandle publisherUserHandle) {
    +-            verify(mCallback, times(0)).onShortcutsChanged(
    +-                    eq(publisherPackageName),
    +-                    any(List.class),
    +-                    eq(publisherUserHandle));
    +-            return this;
    +-        }
    +-
    +-        public ShortcutListAsserter assertCallbackCalledForPackageAndUser(
    +-                String publisherPackageName, UserHandle publisherUserHandle) {
    +-            final ArgumentCaptor<List> shortcuts = ArgumentCaptor.forClass(List.class);
    +-            verify(mCallback, times(1)).onShortcutsChanged(
    +-                    eq(publisherPackageName),
    +-                    shortcuts.capture(),
    +-                    eq(publisherUserHandle));
    +-            return new ShortcutListAsserter(shortcuts.getValue());
    +-        }
    +-    }
    +-
    +-    public static LauncherCallbackAsserter assertForLauncherCallback(
    +-            LauncherApps launcherApps, Runnable body) throws InterruptedException {
    +-        final LauncherCallbackAsserter asserter = new LauncherCallbackAsserter();
    +-        launcherApps.registerCallback(asserter.getMockCallback(),
    +-                new Handler(Looper.getMainLooper()));
    +-
    +-        body.run();
    +-
    +-        waitOnMainThread();
    +-
    +-        // TODO unregister doesn't work well during unit tests.  Figure out and fix it.
    +-        // launcherApps.unregisterCallback(asserter.getMockCallback());
    +-
    +-        return asserter;
    +-    }
    +-
    +-    public static void retryUntil(BooleanSupplier checker, String message) {
    +-        retryUntil(checker, message, 30);
    +-    }
    +-
    +-    public static void retryUntil(BooleanSupplier checker, String message, long timeoutSeconds) {
    +-        final long timeOut = System.currentTimeMillis() + timeoutSeconds * 1000;
    +-        while (!checker.getAsBoolean()) {
    +-            if (System.currentTimeMillis() > timeOut) {
    +-                break;
    +-            }
    +-            try {
    +-                Thread.sleep(200);
    +-            } catch (InterruptedException ignore) {
    +-            }
    +-        }
    +-        assertTrue(message, checker.getAsBoolean());
    +-    }
    +-}
    +diff --git a/services/usage/java/com/android/server/usage/UsageStatsService.java b/services/usage/java/com/android/server/usage/UsageStatsService.java
    +index 8284773..04104b5 100644
    +--- a/services/usage/java/com/android/server/usage/UsageStatsService.java
    ++++ b/services/usage/java/com/android/server/usage/UsageStatsService.java
    +@@ -94,7 +94,7 @@ public class UsageStatsService extends SystemService implements
    + 
    +     static final String TAG = "UsageStatsService";
    + 
    +-    static final boolean DEBUG = false;
    ++    static final boolean DEBUG = false; // Never submit with true
    +     static final boolean COMPRESS_TIME = false;
    + 
    +     private static final long TEN_SECONDS = 10 * 1000;
    +@@ -139,8 +139,8 @@ public class UsageStatsService extends SystemService implements
    +     long mSystemTimeSnapshot;
    + 
    +     boolean mAppIdleEnabled;
    +-    boolean mAppIdleParoled;
    +-    private boolean mScreenOn;
    ++    boolean mAppIdleTempParoled;
    ++    boolean mCharging;
    +     private long mLastAppIdleParoledTime;
    + 
    +     private volatile boolean mPendingOneTimeCheckIdleStates;
    +@@ -191,7 +191,7 @@ public class UsageStatsService extends SystemService implements
    +         mAppIdleEnabled = getContext().getResources().getBoolean(
    +                 com.android.internal.R.bool.config_enableAutoPowerModes);
    +         if (mAppIdleEnabled) {
    +-            IntentFilter deviceStates = new IntentFilter(BatteryManager.ACTION_CHARGING);
    ++            IntentFilter deviceStates = new IntentFilter(Intent.ACTION_BATTERY_CHANGED);
    +             deviceStates.addAction(BatteryManager.ACTION_DISCHARGING);
    +             deviceStates.addAction(PowerManager.ACTION_DEVICE_IDLE_MODE_CHANGED);
    +             getContext().registerReceiver(new DeviceStateReceiver(), deviceStates);
    +@@ -237,7 +237,7 @@ public class UsageStatsService extends SystemService implements
    + 
    +             mSystemServicesReady = true;
    +         } else if (phase == PHASE_BOOT_COMPLETED) {
    +-            setAppIdleParoled(getContext().getSystemService(BatteryManager.class).isCharging());
    ++            setChargingState(getContext().getSystemService(BatteryManager.class).isCharging());
    +         }
    +     }
    + 
    +@@ -284,9 +284,8 @@ public class UsageStatsService extends SystemService implements
    +         @Override
    +         public void onReceive(Context context, Intent intent) {
    +             final String action = intent.getAction();
    +-            if (BatteryManager.ACTION_CHARGING.equals(action)
    +-                    || BatteryManager.ACTION_DISCHARGING.equals(action)) {
    +-                setAppIdleParoled(BatteryManager.ACTION_CHARGING.equals(action));
    ++            if (Intent.ACTION_BATTERY_CHANGED.equals(action)) {
    ++                setChargingState(intent.getIntExtra("plugged", 0) != 0);
    +             } else if (PowerManager.ACTION_DEVICE_IDLE_MODE_CHANGED.equals(action)) {
    +                 onDeviceIdleModeChanged();
    +             }
    +@@ -376,12 +375,21 @@ public class UsageStatsService extends SystemService implements
    +         }
    +     }
    + 
    ++    void setChargingState(boolean charging) {
    ++        synchronized (mLock) {
    ++            if (mCharging != charging) {
    ++                mCharging = charging;
    ++                postParoleStateChanged();
    ++            }
    ++        }
    ++    }
    ++
    +     /** Paroled here means temporary pardon from being inactive */
    +     void setAppIdleParoled(boolean paroled) {
    +         synchronized (mLock) {
    +-            if (mAppIdleParoled != paroled) {
    +-                mAppIdleParoled = paroled;
    +-                if (DEBUG) Slog.d(TAG, "Changing paroled to " + mAppIdleParoled);
    ++            if (mAppIdleTempParoled != paroled) {
    ++                mAppIdleTempParoled = paroled;
    ++                if (DEBUG) Slog.d(TAG, "Changing paroled to " + mAppIdleTempParoled);
    +                 if (paroled) {
    +                     postParoleEndTimeout();
    +                 } else {
    +@@ -393,6 +401,12 @@ public class UsageStatsService extends SystemService implements
    +         }
    +     }
    + 
    ++    boolean isParoledOrCharging() {
    ++        synchronized (mLock) {
    ++            return mAppIdleTempParoled || mCharging;
    ++        }
    ++    }
    ++
    +     private void postNextParoleTimeout() {
    +         if (DEBUG) Slog.d(TAG, "Posting MSG_CHECK_PAROLE_TIMEOUT");
    +         mHandler.removeMessages(MSG_CHECK_PAROLE_TIMEOUT);
    +@@ -495,7 +509,7 @@ public class UsageStatsService extends SystemService implements
    +     /** Check if it's been a while since last parole and let idle apps do some work */
    +     void checkParoleTimeout() {
    +         synchronized (mLock) {
    +-            if (!mAppIdleParoled) {
    ++            if (!mAppIdleTempParoled) {
    +                 final long timeSinceLastParole = checkAndGetTimeLocked() - mLastAppIdleParoledTime;
    +                 if (timeSinceLastParole > mAppIdleParoleIntervalMillis) {
    +                     if (DEBUG) Slog.d(TAG, "Crossed default parole interval");
    +@@ -786,7 +800,7 @@ public class UsageStatsService extends SystemService implements
    +     }
    + 
    +     boolean isAppIdleFilteredOrParoled(String packageName, int userId, long elapsedRealtime) {
    +-        if (mAppIdleParoled) {
    ++        if (isParoledOrCharging()) {
    +             return false;
    +         }
    +         return isAppIdleFiltered(packageName, getAppId(packageName), userId, elapsedRealtime);
    +@@ -989,8 +1003,9 @@ public class UsageStatsService extends SystemService implements
    +     }
    + 
    +     void informParoleStateChanged() {
    ++        final boolean paroled = isParoledOrCharging();
    +         for (AppIdleStateChangeListener listener : mPackageAccessListeners) {
    +-            listener.onParoleStateChanged(mAppIdleParoled);
    ++            listener.onParoleStateChanged(paroled);
    +         }
    +     }
    + 
    +@@ -1072,9 +1087,9 @@ public class UsageStatsService extends SystemService implements
    + 
    +             pw.println();
    +             pw.print("mAppIdleEnabled="); pw.print(mAppIdleEnabled);
    +-            pw.print(" mAppIdleParoled="); pw.print(mAppIdleParoled);
    +-            pw.print(" mScreenOn="); pw.println(mScreenOn);
    +-            pw.print("mLastAppIdleParoledTime=");
    ++            pw.print(" mAppIdleTempParoled="); pw.print(mAppIdleTempParoled);
    ++            pw.print(" mCharging="); pw.print(mCharging);
    ++            pw.print(" mLastAppIdleParoledTime=");
    +             TimeUtils.formatDuration(mLastAppIdleParoledTime, pw);
    +             pw.println();
    +         }
    +@@ -1139,7 +1154,8 @@ public class UsageStatsService extends SystemService implements
    +                     break;
    + 
    +                 case MSG_PAROLE_STATE_CHANGED:
    +-                    if (DEBUG) Slog.d(TAG, "Parole state changed: " + mAppIdleParoled);
    ++                    if (DEBUG) Slog.d(TAG, "Parole state: " + mAppIdleTempParoled
    ++                            + ", Charging state:" + mCharging);
    +                     informParoleStateChanged();
    +                     break;
    + 
    +@@ -1466,7 +1482,7 @@ public class UsageStatsService extends SystemService implements
    + 
    +         @Override
    +         public boolean isAppIdleParoleOn() {
    +-            return mAppIdleParoled;
    ++            return isParoledOrCharging();
    +         }
    + 
    +         @Override
    +diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/DatabaseHelper.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/DatabaseHelper.java
    +index 0dcd152..dd7b5a8 100644
    +--- a/services/voiceinteraction/java/com/android/server/voiceinteraction/DatabaseHelper.java
    ++++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/DatabaseHelper.java
    +@@ -27,6 +27,9 @@ import android.hardware.soundtrigger.SoundTrigger.KeyphraseSoundModel;
    + import android.text.TextUtils;
    + import android.util.Slog;
    + 
    ++import java.util.ArrayList;
    ++import java.util.Arrays;
    ++import java.util.List;
    + import java.util.Locale;
    + import java.util.UUID;
    + 
    +@@ -40,7 +43,7 @@ public class DatabaseHelper extends SQLiteOpenHelper {
    +     static final boolean DBG = false;
    + 
    +     private static final String NAME = "sound_model.db";
    +-    private static final int VERSION = 5;
    ++    private static final int VERSION = 6;
    + 
    +     public static interface SoundModelContract {
    +         public static final String TABLE = "sound_model";
    +@@ -58,15 +61,19 @@ public class DatabaseHelper extends SQLiteOpenHelper {
    +     // Table Create Statement
    +     private static final String CREATE_TABLE_SOUND_MODEL = "CREATE TABLE "
    +             + SoundModelContract.TABLE + "("
    +-            + SoundModelContract.KEY_MODEL_UUID + " TEXT PRIMARY KEY,"
    +-            + SoundModelContract.KEY_VENDOR_UUID + " TEXT, "
    ++            + SoundModelContract.KEY_MODEL_UUID + " TEXT,"
    ++            + SoundModelContract.KEY_VENDOR_UUID + " TEXT,"
    +             + SoundModelContract.KEY_KEYPHRASE_ID + " INTEGER,"
    +             + SoundModelContract.KEY_TYPE + " INTEGER,"
    +             + SoundModelContract.KEY_DATA + " BLOB,"
    +             + SoundModelContract.KEY_RECOGNITION_MODES + " INTEGER,"
    +             + SoundModelContract.KEY_LOCALE + " TEXT,"
    +             + SoundModelContract.KEY_HINT_TEXT + " TEXT,"
    +-            + SoundModelContract.KEY_USERS + " TEXT" + ")";
    ++            + SoundModelContract.KEY_USERS + " TEXT,"
    ++            + "PRIMARY KEY (" + SoundModelContract.KEY_KEYPHRASE_ID + ","
    ++                              + SoundModelContract.KEY_LOCALE + ","
    ++                              + SoundModelContract.KEY_USERS + ")"
    ++            + ")";
    + 
    +     public DatabaseHelper(Context context) {
    +         super(context, NAME, null, VERSION);
    +@@ -93,6 +100,44 @@ public class DatabaseHelper extends SQLiteOpenHelper {
    +                 oldVersion++;
    +             }
    +         }
    ++        if (oldVersion == 5) {
    ++            // We need to enforce the new primary key constraint that the
    ++            // keyphrase id, locale, and users are unique. We have to first pull
    ++            // everything out of the database, remove duplicates, create the new
    ++            // table, then push everything back in.
    ++            String selectQuery = "SELECT * FROM " + SoundModelContract.TABLE;
    ++            Cursor c = db.rawQuery(selectQuery, null);
    ++            List<SoundModelRecord> old_records = new ArrayList<SoundModelRecord>();
    ++            try {
    ++                if (c.moveToFirst()) {
    ++                    do {
    ++                        try {
    ++                            old_records.add(new SoundModelRecord(5, c));
    ++                        } catch (Exception e) {
    ++                            Slog.e(TAG, "Failed to extract V5 record", e);
    ++                        }
    ++                    } while (c.moveToNext());
    ++                }
    ++            } finally {
    ++                c.close();
    ++            }
    ++            db.execSQL("DROP TABLE IF EXISTS " + SoundModelContract.TABLE);
    ++            onCreate(db);
    ++            for (SoundModelRecord record : old_records) {
    ++                if (record.ifViolatesV6PrimaryKeyIsFirstOfAnyDuplicates(old_records)) {
    ++                    try {
    ++                        long return_value = record.writeToDatabase(6, db);
    ++                        if (return_value == -1) {
    ++                            Slog.e(TAG, "Database write failed " + record.modelUuid + ": "
    ++                                    + return_value);
    ++                        }
    ++                    } catch (Exception e) {
    ++                        Slog.e(TAG, "Failed to update V6 record " + record.modelUuid, e);
    ++                    }
    ++                }
    ++            }
    ++            oldVersion++;
    ++        }
    +     }
    + 
    +     /**
    +@@ -279,4 +324,93 @@ public class DatabaseHelper extends SQLiteOpenHelper {
    +         }
    +         return users;
    +     }
    ++
    ++    private static class SoundModelRecord {
    ++        public final String modelUuid;
    ++        public final String vendorUuid;
    ++        public final int keyphraseId;
    ++        public final int type;
    ++        public final byte[] data;
    ++        public final int recognitionModes;
    ++        public final String locale;
    ++        public final String hintText;
    ++        public final String users;
    ++
    ++        public SoundModelRecord(int version, Cursor c) {
    ++            modelUuid = c.getString(c.getColumnIndex(SoundModelContract.KEY_MODEL_UUID));
    ++            if (version >= 5) {
    ++                vendorUuid = c.getString(c.getColumnIndex(SoundModelContract.KEY_VENDOR_UUID));
    ++            } else {
    ++                vendorUuid = null;
    ++            }
    ++            keyphraseId = c.getInt(c.getColumnIndex(SoundModelContract.KEY_KEYPHRASE_ID));
    ++            type = c.getInt(c.getColumnIndex(SoundModelContract.KEY_TYPE));
    ++            data = c.getBlob(c.getColumnIndex(SoundModelContract.KEY_DATA));
    ++            recognitionModes = c.getInt(c.getColumnIndex(SoundModelContract.KEY_RECOGNITION_MODES));
    ++            locale = c.getString(c.getColumnIndex(SoundModelContract.KEY_LOCALE));
    ++            hintText = c.getString(c.getColumnIndex(SoundModelContract.KEY_HINT_TEXT));
    ++            users = c.getString(c.getColumnIndex(SoundModelContract.KEY_USERS));
    ++        }
    ++
    ++        private boolean V6PrimaryKeyMatches(SoundModelRecord record) {
    ++          return keyphraseId == record.keyphraseId && stringComparisonHelper(locale, record.locale)
    ++              && stringComparisonHelper(users, record.users);
    ++        }
    ++
    ++        // Returns true if this record is a) the only record with the same V6 primary key, or b) the
    ++        // first record in the list of all records that have the same primary key and equal data.
    ++        // It will return false if a) there are any records that have the same primary key and
    ++        // different data, or b) there is a previous record in the list that has the same primary
    ++        // key and data.
    ++        // Note that 'this' object must be inside the list.
    ++        public boolean ifViolatesV6PrimaryKeyIsFirstOfAnyDuplicates(
    ++                List<SoundModelRecord> records) {
    ++            // First pass - check to see if all the records that have the same primary key have
    ++            // duplicated data.
    ++            for (SoundModelRecord record : records) {
    ++                if (this == record) {
    ++                    continue;
    ++                }
    ++                // If we have different/missing data with the same primary key, then we should drop
    ++                // everything.
    ++                if (this.V6PrimaryKeyMatches(record) && !Arrays.equals(data, record.data)) {
    ++                    return false;
    ++                }
    ++            }
    ++
    ++            // We only want to return true for the first duplicated model.
    ++            for (SoundModelRecord record : records) {
    ++                if (this.V6PrimaryKeyMatches(record)) {
    ++                    return this == record;
    ++                }
    ++            }
    ++            return true;
    ++        }
    ++
    ++        public long writeToDatabase(int version, SQLiteDatabase db) {
    ++            ContentValues values = new ContentValues();
    ++            values.put(SoundModelContract.KEY_MODEL_UUID, modelUuid);
    ++            if (version >= 5) {
    ++                values.put(SoundModelContract.KEY_VENDOR_UUID, vendorUuid);
    ++            }
    ++            values.put(SoundModelContract.KEY_KEYPHRASE_ID, keyphraseId);
    ++            values.put(SoundModelContract.KEY_TYPE, type);
    ++            values.put(SoundModelContract.KEY_DATA, data);
    ++            values.put(SoundModelContract.KEY_RECOGNITION_MODES, recognitionModes);
    ++            values.put(SoundModelContract.KEY_LOCALE, locale);
    ++            values.put(SoundModelContract.KEY_HINT_TEXT, hintText);
    ++            values.put(SoundModelContract.KEY_USERS, users);
    ++
    ++            return db.insertWithOnConflict(
    ++                       SoundModelContract.TABLE, null, values, SQLiteDatabase.CONFLICT_REPLACE);
    ++        }
    ++
    ++        // Helper for checking string equality - including the case when they are null.
    ++        static private boolean stringComparisonHelper(String a, String b) {
    ++          if (a != null) {
    ++            return a.equals(b);
    ++          }
    ++          return a == b;
    ++        }
    ++    }
    + }
    +diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java
    +index 43d2a1f..a04034e 100644
    +--- a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java
    ++++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java
    +@@ -535,6 +535,18 @@ public class VoiceInteractionManagerService extends SystemService {
    +                     + " user=" + userHandle);
    +         }
    + 
    ++        ComponentName getCurAssistant(int userHandle) {
    ++            String curAssistant = Settings.Secure.getStringForUser(
    ++                    mContext.getContentResolver(),
    ++                    Settings.Secure.ASSISTANT, userHandle);
    ++            if (TextUtils.isEmpty(curAssistant)) {
    ++                return null;
     +            }
    -             if (mSelectedItemIndex == mAccounts.size()) {
    -                 outState.putBoolean(KEY_INSTANCE_STATE_SELECTED_ADD_ACCOUNT, true);
    -             } else {
    -@@ -291,6 +295,10 @@ public class ChooseTypeAndAccountActivity extends Activity
    -         mPendingRequest = REQUEST_NULL;
    ++            if (DEBUG) Slog.d(TAG, "getCurAssistant curAssistant=" + curAssistant
    ++                    + " user=" + userHandle);
    ++            return ComponentName.unflattenFromString(curAssistant);
    ++        }
    ++
    +         void resetCurAssistant(int userHandle) {
    +             Settings.Secure.putStringForUser(mContext.getContentResolver(),
    +                     Settings.Secure.ASSISTANT, null, userHandle);
    +@@ -1178,6 +1190,7 @@ public class VoiceInteractionManagerService extends SystemService {
    +                 synchronized (VoiceInteractionManagerServiceStub.this) {
    +                     ComponentName curInteractor = getCurInteractor(userHandle);
    +                     ComponentName curRecognizer = getCurRecognizer(userHandle);
    ++                    ComponentName curAssistant = getCurAssistant(userHandle);
    +                     if (curRecognizer == null) {
    +                         // Could a new recognizer appear when we don't have one pre-installed?
    +                         if (anyPackagesAppearing()) {
    +@@ -1196,6 +1209,7 @@ public class VoiceInteractionManagerService extends SystemService {
    +                             // the default config.
    +                             setCurInteractor(null, userHandle);
    +                             setCurRecognizer(null, userHandle);
    ++                            resetCurAssistant(userHandle);
    +                             initForUser(userHandle);
    +                             return;
    +                         }
    +@@ -1212,6 +1226,20 @@ public class VoiceInteractionManagerService extends SystemService {
    +                         return;
    +                     }
      
    -         if (resultCode == RESULT_CANCELED) {
    -+            if (mAccounts == null) {
    -+                final AccountManager accountManager = AccountManager.get(this);
    -+                mAccounts = getAcceptableAccountChoices(accountManager);
    ++                    if (curAssistant != null) {
    ++                        int change = isPackageDisappearing(curAssistant.getPackageName());
    ++                        if (change == PACKAGE_PERMANENT_CHANGE) {
    ++                            // If the currently set assistant is being removed, then we should
    ++                            // reset back to the default state (which is probably that we prefer
    ++                            // to have the default full voice interactor enabled).
    ++                            setCurInteractor(null, userHandle);
    ++                            setCurRecognizer(null, userHandle);
    ++                            resetCurAssistant(userHandle);
    ++                            initForUser(userHandle);
    ++                            return;
    ++                        }
    ++                    }
    ++
    +                     // There is no interactor, so just deal with a simple recognizer.
    +                     int change = isPackageDisappearing(curRecognizer.getPackageName());
    +                     if (change == PACKAGE_PERMANENT_CHANGE
    +diff --git a/telecomm/java/android/telecom/Connection.java b/telecomm/java/android/telecom/Connection.java
    +index a093d54..8f9c758 100644
    +--- a/telecomm/java/android/telecom/Connection.java
    ++++ b/telecomm/java/android/telecom/Connection.java
    +@@ -327,7 +327,7 @@ public abstract class Connection extends Conferenceable {
    +      *
    +      * @hide
    +      */
    +-    public static final int PROPERTY_SHOW_CALLBACK_NUMBER = 1<<0;
    ++    public static final int PROPERTY_EMERGENCY_CALLBACK_MODE = 1<<0;
    + 
    +     /**
    +      * Whether the call is a generic conference, where we do not know the precise state of
    +@@ -420,6 +420,31 @@ public abstract class Connection extends Conferenceable {
    +             "android.telecom.extra.DISABLE_ADD_CALL";
    + 
    +     /**
    ++     * String connection extra key on a {@link Connection} or {@link Conference} which contains the
    ++     * original Connection ID associated with the connection.  Used in
    ++     * {@link RemoteConnectionService} to track the Connection ID which was originally assigned to a
    ++     * connection/conference added via
    ++     * {@link ConnectionService#addExistingConnection(PhoneAccountHandle, Connection)} and
    ++     * {@link ConnectionService#addConference(Conference)} APIs.  This is important to pass to
    ++     * Telecom for when it deals with RemoteConnections.  When the ConnectionManager wraps the
    ++     * {@link RemoteConnection} and {@link RemoteConference} and adds it to Telecom, there needs to
    ++     * be a way to ensure that we don't add the connection again as a duplicate.
    ++     * <p>
    ++     * For example, the TelephonyCS calls addExistingConnection for a Connection with ID
    ++     * {@code TelephonyCS@1}.  The ConnectionManager learns of this via
    ++     * {@link ConnectionService#onRemoteExistingConnectionAdded(RemoteConnection)}, and wraps this
    ++     * in a new {@link Connection} which it adds to Telecom via
    ++     * {@link ConnectionService#addExistingConnection(PhoneAccountHandle, Connection)}.  As part of
    ++     * this process, the wrapped RemoteConnection gets assigned a new ID (e.g. {@code ConnMan@1}).
    ++     * The TelephonyCS will ALSO try to add the existing connection to Telecom, except with the
    ++     * ID it originally referred to the connection as.  Thus Telecom needs to know that the
    ++     * Connection with ID {@code ConnMan@1} is really the same as {@code TelephonyCS@1}.
    ++     * @hide
    ++     */
    ++    public static final String EXTRA_ORIGINAL_CONNECTION_ID =
    ++            "android.telecom.extra.ORIGINAL_CONNECTION_ID";
    ++
    ++    /**
    +      * Connection event used to inform Telecom that it should play the on hold tone.  This is used
    +      * to play a tone when the peer puts the current call on hold.  Sent to Telecom via
    +      * {@link #sendConnectionEvent(String, Bundle)}.
    +@@ -655,8 +680,8 @@ public abstract class Connection extends Conferenceable {
    +             builder.append("Properties:");
    +         }
    + 
    +-        if (can(properties, PROPERTY_SHOW_CALLBACK_NUMBER)) {
    +-            builder.append(isLong ? " PROPERTY_SHOW_CALLBACK_NUMBER" : " clbk");
    ++        if (can(properties, PROPERTY_EMERGENCY_CALLBACK_MODE)) {
    ++            builder.append(isLong ? " PROPERTY_EMERGENCY_CALLBACK_MODE" : " ecbm");
    +         }
    + 
    +         if (can(properties, PROPERTY_HIGH_DEF_AUDIO)) {
    +@@ -733,7 +758,6 @@ public abstract class Connection extends Conferenceable {
    +      * {@link android.telecom.InCallService.VideoCall}.
    +      */
    +     public static abstract class VideoProvider {
    +-
    +         /**
    +          * Video is not being received (no protocol pause was issued).
    +          * @see #handleCallSessionEvent(int)
    +@@ -818,6 +842,14 @@ public abstract class Connection extends Conferenceable {
    +         private static final int MSG_SET_PAUSE_IMAGE = 11;
    +         private static final int MSG_REMOVE_VIDEO_CALLBACK = 12;
    + 
    ++        private static final String SESSION_EVENT_RX_PAUSE_STR = "RX_PAUSE";
    ++        private static final String SESSION_EVENT_RX_RESUME_STR = "RX_RESUME";
    ++        private static final String SESSION_EVENT_TX_START_STR = "TX_START";
    ++        private static final String SESSION_EVENT_TX_STOP_STR = "TX_STOP";
    ++        private static final String SESSION_EVENT_CAMERA_FAILURE_STR = "CAMERA_FAIL";
    ++        private static final String SESSION_EVENT_CAMERA_READY_STR = "CAMERA_READY";
    ++        private static final String SESSION_EVENT_UNKNOWN_STR = "UNKNOWN";
    ++
    +         private VideoProvider.VideoProviderHandler mMessageHandler;
    +         private final VideoProvider.VideoProviderBinder mBinder;
    + 
    +@@ -1328,6 +1360,32 @@ public abstract class Connection extends Conferenceable {
    +                 }
    +             }
    +         }
    ++
    ++        /**
    ++         * Returns a string representation of a call session event.
    ++         *
    ++         * @param event A call session event passed to {@link #handleCallSessionEvent(int)}.
    ++         * @return String representation of the call session event.
    ++         * @hide
    ++         */
    ++        public static String sessionEventToString(int event) {
    ++            switch (event) {
    ++                case SESSION_EVENT_CAMERA_FAILURE:
    ++                    return SESSION_EVENT_CAMERA_FAILURE_STR;
    ++                case SESSION_EVENT_CAMERA_READY:
    ++                    return SESSION_EVENT_CAMERA_READY_STR;
    ++                case SESSION_EVENT_RX_PAUSE:
    ++                    return SESSION_EVENT_RX_PAUSE_STR;
    ++                case SESSION_EVENT_RX_RESUME:
    ++                    return SESSION_EVENT_RX_RESUME_STR;
    ++                case SESSION_EVENT_TX_START:
    ++                    return SESSION_EVENT_TX_START_STR;
    ++                case SESSION_EVENT_TX_STOP:
    ++                    return SESSION_EVENT_TX_STOP_STR;
    ++                default:
    ++                    return SESSION_EVENT_UNKNOWN_STR + " " + event;
     +            }
    -             // if canceling out of addAccount and the original state caused us to skip this,
    -             // finish this activity
    -             if (mAccounts.isEmpty()) {
    -diff --git a/libs/hwui/Android.mk b/libs/hwui/Android.mk
    -index 366ef71..3ecd045 100644
    ---- a/libs/hwui/Android.mk
    -+++ b/libs/hwui/Android.mk
    -@@ -141,7 +141,7 @@ endif
    ++        }
    +     }
      
    - ifdef HWUI_COMPILE_FOR_PERF
    -     # TODO: Non-arm?
    --    hwui_cflags += -fno-omit-frame-pointer -marm -mapcs
    -+    hwui_cflags += -fno-omit-frame-pointer -marm 
    - endif
    +     private final Listener mConnectionDeathListener = new Listener() {
    +diff --git a/telecomm/java/android/telecom/ConnectionService.java b/telecomm/java/android/telecom/ConnectionService.java
    +index 0c75630..dd55ca9 100644
    +--- a/telecomm/java/android/telecom/ConnectionService.java
    ++++ b/telecomm/java/android/telecom/ConnectionService.java
    +@@ -1347,7 +1347,13 @@ public abstract class ConnectionService extends Service {
    +      */
    +     private String addExistingConnectionInternal(PhoneAccountHandle handle, Connection connection) {
    +         String id;
    +-        if (handle == null) {
    ++
    ++        if (connection.getExtras() != null && connection.getExtras()
    ++                .containsKey(Connection.EXTRA_ORIGINAL_CONNECTION_ID)) {
    ++            id = connection.getExtras().getString(Connection.EXTRA_ORIGINAL_CONNECTION_ID);
    ++            Log.d(this, "addExistingConnectionInternal - conn %s reusing original id %s",
    ++                    connection.getTelecomCallId(), id);
    ++        } else if (handle == null) {
    +             // If no phone account handle was provided, we cannot be sure the call ID is unique,
    +             // so just use a random UUID.
    +             id = UUID.randomUUID().toString();
    +@@ -1381,13 +1387,21 @@ public abstract class ConnectionService extends Service {
    +     }
      
    - # This has to be lazy-resolved because it depends on the LOCAL_MODULE_CLASS
    -diff --git a/libs/hwui/Snapshot.cpp b/libs/hwui/Snapshot.cpp
    -index 2c9c9d9..7c187fb 100644
    ---- a/libs/hwui/Snapshot.cpp
    -+++ b/libs/hwui/Snapshot.cpp
    -@@ -38,6 +38,7 @@ Snapshot::Snapshot()
    -         , mClipArea(&mClipAreaRoot) {
    -     transform = &mTransformRoot;
    -     region = nullptr;
    -+    mRelativeLightCenter.x = mRelativeLightCenter.y = mRelativeLightCenter.z = 0;
    +     private String addConferenceInternal(Conference conference) {
    ++        String originalId = null;
    ++        if (conference.getExtras() != null && conference.getExtras()
    ++                .containsKey(Connection.EXTRA_ORIGINAL_CONNECTION_ID)) {
    ++            originalId = conference.getExtras().getString(Connection.EXTRA_ORIGINAL_CONNECTION_ID);
    ++            Log.d(this, "addConferenceInternal: conf %s reusing original id %s",
    ++                    conference.getTelecomCallId(),
    ++                    originalId);
    ++        }
    +         if (mIdByConference.containsKey(conference)) {
    +             Log.w(this, "Re-adding an existing conference: %s.", conference);
    +         } else if (conference != null) {
    +             // Conferences do not (yet) have a PhoneAccountHandle associated with them, so we
    +             // cannot determine a ConnectionService class name to associate with the ID, so use
    +             // a unique UUID (for now).
    +-            String id = UUID.randomUUID().toString();
    ++            String id = originalId == null ? UUID.randomUUID().toString() : originalId;
    +             mConferenceById.put(id, conference);
    +             mIdByConference.put(conference, id);
    +             conference.addListener(mConferenceListener);
    +diff --git a/telecomm/java/android/telecom/RemoteConference.java b/telecomm/java/android/telecom/RemoteConference.java
    +index 943da6d..0ef9ec1 100644
    +--- a/telecomm/java/android/telecom/RemoteConference.java
    ++++ b/telecomm/java/android/telecom/RemoteConference.java
    +@@ -311,6 +311,9 @@ public final class RemoteConference {
    + 
    +     /** @hide */
    +     void putExtras(final Bundle extras) {
    ++        if (extras == null) {
    ++            return;
    ++        }
    +         if (mExtras == null) {
    +             mExtras = new Bundle();
    +         }
    +diff --git a/telecomm/java/android/telecom/RemoteConnection.java b/telecomm/java/android/telecom/RemoteConnection.java
    +index dc8eaf6..37fa374 100644
    +--- a/telecomm/java/android/telecom/RemoteConnection.java
    ++++ b/telecomm/java/android/telecom/RemoteConnection.java
    +@@ -638,7 +638,12 @@ public final class RemoteConnection {
    +         mConnectionCapabilities = connection.getConnectionCapabilities();
    +         mConnectionProperties = connection.getConnectionProperties();
    +         mVideoState = connection.getVideoState();
    +-        mVideoProvider = new RemoteConnection.VideoProvider(connection.getVideoProvider());
    ++        IVideoProvider videoProvider = connection.getVideoProvider();
    ++        if (videoProvider != null) {
    ++            mVideoProvider = new RemoteConnection.VideoProvider(videoProvider);
    ++        } else {
    ++            mVideoProvider = null;
    ++        }
    +         mIsVoipAudioMode = connection.getIsVoipAudioMode();
    +         mStatusHints = connection.getStatusHints();
    +         mAddress = connection.getHandle();
    +@@ -646,6 +651,14 @@ public final class RemoteConnection {
    +         mCallerDisplayName = connection.getCallerDisplayName();
    +         mCallerDisplayNamePresentation = connection.getCallerDisplayNamePresentation();
    +         mConference = null;
    ++        putExtras(connection.getExtras());
    ++
    ++        // Stash the original connection ID as it exists in the source ConnectionService.
    ++        // Telecom will use this to avoid adding duplicates later.
    ++        // See comments on Connection.EXTRA_ORIGINAL_CONNECTION_ID for more information.
    ++        Bundle newExtras = new Bundle();
    ++        newExtras.putString(Connection.EXTRA_ORIGINAL_CONNECTION_ID, callId);
    ++        putExtras(newExtras);
    +     }
    + 
    +     /**
    +@@ -1343,6 +1356,9 @@ public final class RemoteConnection {
    + 
    +     /** @hide */
    +     void putExtras(final Bundle extras) {
    ++        if (extras == null) {
    ++            return;
    ++        }
    +         if (mExtras == null) {
    +             mExtras = new Bundle();
    +         }
    +diff --git a/telecomm/java/android/telecom/RemoteConnectionService.java b/telecomm/java/android/telecom/RemoteConnectionService.java
    +index c4739ff..1577a0f 100644
    +--- a/telecomm/java/android/telecom/RemoteConnectionService.java
    ++++ b/telecomm/java/android/telecom/RemoteConnectionService.java
    +@@ -214,18 +214,27 @@ final class RemoteConnectionService {
    +                     conference.addConnection(c);
    +                 }
    +             }
    +-
    +             if (conference.getConnections().size() == 0) {
    +                 // A conference was created, but none of its connections are ones that have been
    +                 // created by, and therefore being tracked by, this remote connection service. It
    +                 // is of no interest to us.
    ++                Log.d(this, "addConferenceCall - skipping");
    +                 return;
    +             }
    + 
    +             conference.setState(parcel.getState());
    +             conference.setConnectionCapabilities(parcel.getConnectionCapabilities());
    +             conference.setConnectionProperties(parcel.getConnectionProperties());
    ++            conference.putExtras(parcel.getExtras());
    +             mConferenceById.put(callId, conference);
    ++
    ++            // Stash the original connection ID as it exists in the source ConnectionService.
    ++            // Telecom will use this to avoid adding duplicates later.
    ++            // See comments on Connection.EXTRA_ORIGINAL_CONNECTION_ID for more information.
    ++            Bundle newExtras = new Bundle();
    ++            newExtras.putString(Connection.EXTRA_ORIGINAL_CONNECTION_ID, callId);
    ++            conference.putExtras(newExtras);
    ++
    +             conference.registerCallback(new RemoteConference.Callback() {
    +                 @Override
    +                 public void onDestroyed(RemoteConference c) {
    +@@ -331,12 +340,18 @@ final class RemoteConnectionService {
    +         }
    + 
    +         @Override
    +-        public void addExistingConnection(String callId, ParcelableConnection connection) {
    +-            // TODO: add contents of this method
    +-            RemoteConnection remoteConnction = new RemoteConnection(callId,
    ++        public void addExistingConnection(final String callId, ParcelableConnection connection) {
    ++            RemoteConnection remoteConnection = new RemoteConnection(callId,
    +                     mOutgoingConnectionServiceRpc, connection);
    +-
    +-            mOurConnectionServiceImpl.addRemoteExistingConnection(remoteConnction);
    ++            mConnectionById.put(callId, remoteConnection);
    ++            remoteConnection.registerCallback(new RemoteConnection.Callback() {
    ++                @Override
    ++                public void onDestroyed(RemoteConnection connection) {
    ++                    mConnectionById.remove(callId);
    ++                    maybeDisconnectAdapter();
    ++                }
    ++            });
    ++            mOurConnectionServiceImpl.addRemoteExistingConnection(remoteConnection);
    +         }
    + 
    +         @Override
    +diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java
    +index dc9767c..0847788 100644
    +--- a/telephony/java/android/telephony/CarrierConfigManager.java
    ++++ b/telephony/java/android/telephony/CarrierConfigManager.java
    +@@ -286,13 +286,23 @@ public class CarrierConfigManager {
    +             "carrier_wfc_supports_wifi_only_bool";
    + 
    +     /**
    +-     * Default WFC_IMS_mode 0: WIFI_ONLY
    +-     *                      1: CELLULAR_PREFERRED
    +-     *                      2: WIFI_PREFERRED
    ++     * Default WFC_IMS_MODE for home network   0: WIFI_ONLY
    ++     *                                         1: CELLULAR_PREFERRED
    ++     *                                         2: WIFI_PREFERRED
    +      * @hide
    +      */
    +     public static final String KEY_CARRIER_DEFAULT_WFC_IMS_MODE_INT =
    +             "carrier_default_wfc_ims_mode_int";
    ++
    ++    /**
    ++     * Default WFC_IMS_MODE for roaming
    ++     * See {@link KEY_CARRIER_DEFAULT_WFC_IMS_MODE_INT} for valid values.
    ++     *
    ++     * @hide
    ++     */
    ++    public static final String KEY_CARRIER_DEFAULT_WFC_IMS_ROAMING_MODE_INT =
    ++            "carrier_default_wfc_ims_roaming_mode_int";
    ++
    +     /**
    +      * Default WFC_IMS_enabled: true VoWiFi by default is on
    +      *                          false VoWiFi by default is off
    +@@ -433,18 +443,11 @@ public class CarrierConfigManager {
    +             "disable_severe_when_extreme_disabled_bool";
    + 
    +     /**
    +-     * The data call APN retry configuration for default type APN.
    +-     * @hide
    +-     */
    +-    public static final String KEY_CARRIER_DATA_CALL_RETRY_CONFIG_DEFAULT_STRING =
    +-            "carrier_data_call_retry_config_default_string";
    +-
    +-    /**
    +-     * The data call APN retry configuration for other type APNs.
    ++     * The data call retry configuration for different types of APN.
    +      * @hide
    +      */
    +-    public static final String KEY_CARRIER_DATA_CALL_RETRY_CONFIG_OTHERS_STRING =
    +-            "carrier_data_call_retry_config_others_string";
    ++    public static final String KEY_CARRIER_DATA_CALL_RETRY_CONFIG_STRINGS =
    ++            "carrier_data_call_retry_config_strings";
    + 
    +     /**
    +      * Delay between trying APN from the pool
    +@@ -668,6 +671,20 @@ public class CarrierConfigManager {
    +     public static final String KEY_ALLOW_ADDING_APNS_BOOL = "allow_adding_apns_bool";
    + 
    +     /**
    ++     * APN types that user is not allowed to modify
    ++     * @hide
    ++     */
    ++    public static final String KEY_READ_ONLY_APN_TYPES_STRING_ARRAY =
    ++            "read_only_apn_types_string_array";
    ++
    ++    /**
    ++     * APN fields that user is not allowed to modify
    ++     * @hide
    ++     */
    ++    public static final String KEY_READ_ONLY_APN_FIELDS_STRING_ARRAY =
    ++            "read_only_apn_fields_string_array";
    ++
    ++    /**
    +      * Boolean indicating if intent for emergency call state changes should be broadcast
    +      * @hide
    +      */
    +@@ -681,6 +698,16 @@ public class CarrierConfigManager {
    +     public static final String KEY_CARRIER_ADDITIONAL_CBS_CHANNELS_STRINGS =
    +             "carrier_additional_cbs_channels_strings";
    + 
    ++    /**
    ++      * Indicates whether STK LAUNCH_BROWSER command is disabled.
    ++      * If {@code true}, then the browser will not be launched
    ++      * on UI for the LAUNCH_BROWSER STK command.
    ++      * @hide
    ++      */
    ++    public static final String KEY_STK_DISABLE_LAUNCH_BROWSER_BOOL =
    ++            "stk_disable_launch_browser_bool";
    ++
    ++
    +     // These variables are used by the MMS service and exposed through another API, {@link
    +     // SmsManager}. The variable names and string values are copied from there.
    +     public static final String KEY_MMS_ALIAS_ENABLED_BOOL = "aliasEnabled";
    +@@ -870,6 +897,11 @@ public class CarrierConfigManager {
    + 
    +     /**
    +      * Flag indicating whether the carrier supports the Hold command while in an IMS call.
    ++     * <p>
    ++     * The device configuration value {@code config_device_respects_hold_carrier_config} ultimately
    ++     * controls whether this carrier configuration option is used.  Where
    ++     * {@code config_device_respects_hold_carrier_config} is false, the value of the
    ++     * {@link #KEY_ALLOW_HOLD_IN_IMS_CALL_BOOL} carrier configuration option is ignored.
    +      * @hide
    +      */
    +     public static final String KEY_ALLOW_HOLD_IN_IMS_CALL_BOOL = "allow_hold_in_ims_call";
    +@@ -945,6 +977,18 @@ public class CarrierConfigManager {
    +      */
    +     public static final String FILTERED_CNAP_NAMES_STRING_ARRAY = "filtered_cnap_names_string_array";
    + 
    ++    /**
    ++     * Determine whether user can change Wi-Fi Calling preference in roaming.
    ++     * {@code false} - roaming preference {@link KEY_CARRIER_DEFAULT_WFC_IMS_ROAMING_MODE_INT} is
    ++     *                 the same as home preference {@link KEY_CARRIER_DEFAULT_WFC_IMS_MODE_INT}
    ++     *                 and cannot be changed.
    ++     * {@code true}  - roaming preference can be changed by user independently.
    ++     *
    ++     * @hide
    ++     */
    ++    public static final String KEY_EDITABLE_WFC_ROAMING_MODE_BOOL =
    ++            "editable_wfc_roaming_mode_bool";
    ++
    +     /** The default value for every variable. */
    +     private final static PersistableBundle sDefaults;
    + 
    +@@ -967,6 +1011,7 @@ public class CarrierConfigManager {
    +         sDefaults.putBoolean(KEY_CARRIER_DEFAULT_WFC_IMS_ROAMING_ENABLED_BOOL, false);
    +         sDefaults.putBoolean(KEY_CARRIER_PROMOTE_WFC_ON_CALL_FAIL_BOOL, false);
    +         sDefaults.putInt(KEY_CARRIER_DEFAULT_WFC_IMS_MODE_INT, 2);
    ++        sDefaults.putInt(KEY_CARRIER_DEFAULT_WFC_IMS_ROAMING_MODE_INT, 2);
    +         sDefaults.putBoolean(KEY_CARRIER_FORCE_DISABLE_ETWS_CMAS_TEST_BOOL, false);
    +         sDefaults.putBoolean(KEY_CARRIER_VOLTE_PROVISIONING_REQUIRED_BOOL, false);
    +         sDefaults.putBoolean(KEY_CARRIER_VOLTE_TTY_SUPPORTED_BOOL, true);
    +@@ -1014,14 +1059,17 @@ public class CarrierConfigManager {
    +         sDefaults.putString(KEY_CI_ACTION_ON_SYS_UPDATE_EXTRA_VAL_STRING, "");
    +         sDefaults.putBoolean(KEY_CSP_ENABLED_BOOL, false);
    +         sDefaults.putBoolean(KEY_ALLOW_ADDING_APNS_BOOL, true);
    ++        sDefaults.putStringArray(KEY_READ_ONLY_APN_TYPES_STRING_ARRAY, null);
    ++        sDefaults.putStringArray(KEY_READ_ONLY_APN_FIELDS_STRING_ARRAY, null);
    +         sDefaults.putBoolean(KEY_BROADCAST_EMERGENCY_CALL_STATE_CHANGES_BOOL, false);
    +         sDefaults.putBoolean(KEY_ALWAYS_SHOW_EMERGENCY_ALERT_ONOFF_BOOL, false);
    +         sDefaults.putBoolean(KEY_DISABLE_SEVERE_WHEN_EXTREME_DISABLED_BOOL, true);
    +-        sDefaults.putString(KEY_CARRIER_DATA_CALL_RETRY_CONFIG_DEFAULT_STRING,
    +-                "default_randomization=2000,5000,10000,20000,40000,80000:5000,160000:5000,"
    +-                        + "320000:5000,640000:5000,1280000:5000,1800000:5000");
    +-        sDefaults.putString(KEY_CARRIER_DATA_CALL_RETRY_CONFIG_OTHERS_STRING,
    +-                "max_retries=3, 5000, 5000, 5000");
    ++        sDefaults.putStringArray(KEY_CARRIER_DATA_CALL_RETRY_CONFIG_STRINGS, new String[]{
    ++                "default:default_randomization=2000,5000,10000,20000,40000,80000:5000,160000:5000,"
    ++                        + "320000:5000,640000:5000,1280000:5000,1800000:5000",
    ++                "mms:default_randomization=2000,5000,10000,20000,40000,80000:5000,160000:5000,"
    ++                        + "320000:5000,640000:5000,1280000:5000,1800000:5000",
    ++                "others:max_retries=3, 5000, 5000, 5000"});
    +         sDefaults.putLong(KEY_CARRIER_DATA_CALL_APN_DELAY_DEFAULT_LONG, 20000);
    +         sDefaults.putLong(KEY_CARRIER_DATA_CALL_APN_DELAY_FASTER_LONG, 3000);
    +         sDefaults.putString(KEY_CARRIER_ERI_FILE_NAME_STRING, "eri.xml");
    +@@ -1114,6 +1162,8 @@ public class CarrierConfigManager {
    +         sDefaults.putBoolean(KEY_ENHANCED_4G_LTE_TITLE_VARIANT_BOOL, false);
    +         sDefaults.putBoolean(KEY_NOTIFY_VT_HANDOVER_TO_WIFI_FAILURE_BOOL, false);
    +         sDefaults.putStringArray(FILTERED_CNAP_NAMES_STRING_ARRAY, null);
    ++        sDefaults.putBoolean(KEY_EDITABLE_WFC_ROAMING_MODE_BOOL, false);
    ++        sDefaults.putBoolean(KEY_STK_DISABLE_LAUNCH_BROWSER_BOOL, false);
    +     }
    + 
    +     /**
    +diff --git a/telephony/java/android/telephony/DisconnectCause.java b/telephony/java/android/telephony/DisconnectCause.java
    +index f5e422d..0334254 100644
    +--- a/telephony/java/android/telephony/DisconnectCause.java
    ++++ b/telephony/java/android/telephony/DisconnectCause.java
    +@@ -226,6 +226,13 @@ public class DisconnectCause {
    +      */
    +     public static final int DATA_LIMIT_REACHED = 55;
    + 
    ++    /**
    ++     * The emergency call was terminated because it was dialed on the wrong SIM slot.
    ++     * The call needs to be redialed the other slot.
    ++     * {@hide}
    ++     */
    ++    public static final int DIALED_ON_WRONG_SLOT = 56;
    ++
    +     //*********************************************************************************************
    +     // When adding a disconnect type:
    +     // 1) Please assign the new type the next id value below.
    +@@ -234,14 +241,14 @@ public class DisconnectCause {
    +     // 4) Update toString() with the newly added disconnect type.
    +     // 5) Update android.telecom.DisconnectCauseUtil with any mappings to a telecom.DisconnectCause.
    +     //
    +-    // NextId: 56
    ++    // NextId: 57
    +     //*********************************************************************************************
    + 
    +     /** Smallest valid value for call disconnect codes. */
    +     public static final int MINIMUM_VALID_VALUE = NOT_DISCONNECTED;
    + 
    +     /** Largest valid value for call disconnect codes. */
    +-    public static final int MAXIMUM_VALID_VALUE = DATA_LIMIT_REACHED;
    ++    public static final int MAXIMUM_VALID_VALUE = DIALED_ON_WRONG_SLOT;
    + 
    +     /** Private constructor to avoid class instantiation. */
    +     private DisconnectCause() {
    +@@ -361,6 +368,8 @@ public class DisconnectCause {
    +             return "DATA_DISABLED";
    +         case DATA_LIMIT_REACHED:
    +             return "DATA_LIMIT_REACHED";
    ++        case DIALED_ON_WRONG_SLOT:
    ++            return "DIALED_ON_WRONG_SLOT";
    +         default:
    +             return "INVALID: " + cause;
    +         }
    +diff --git a/telephony/java/android/telephony/PhoneNumberUtils.java b/telephony/java/android/telephony/PhoneNumberUtils.java
    +index 03d6d21..7350eec 100644
    +--- a/telephony/java/android/telephony/PhoneNumberUtils.java
    ++++ b/telephony/java/android/telephony/PhoneNumberUtils.java
    +@@ -24,6 +24,7 @@ import com.android.i18n.phonenumbers.ShortNumberUtil;
    + 
    + import android.content.Context;
    + import android.content.Intent;
    ++import android.content.res.Resources;
    + import android.database.Cursor;
    + import android.location.CountryDetector;
    + import android.net.Uri;
    +@@ -3021,4 +3022,79 @@ public class PhoneNumberUtils
    +         return SubscriptionManager.getDefaultVoiceSubscriptionId();
    +     }
    +     //==== End of utility methods used only in compareStrictly() =====
    ++
    ++
    ++    /*
    ++     * The config held calling number conversion map, expected to convert to emergency number.
    ++     */
    ++    private static final String[] CONVERT_TO_EMERGENCY_MAP = Resources.getSystem().getStringArray(
    ++            com.android.internal.R.array.config_convert_to_emergency_number_map);
    ++    /**
    ++     * Check whether conversion to emergency number is enabled
    ++     *
    ++     * @return {@code true} when conversion to emergency numbers is enabled,
    ++     *         {@code false} otherwise
    ++     *
    ++     * @hide
    ++     */
    ++    public static boolean isConvertToEmergencyNumberEnabled() {
    ++        return CONVERT_TO_EMERGENCY_MAP != null && CONVERT_TO_EMERGENCY_MAP.length > 0;
    ++    }
    ++
    ++    /**
    ++     * Converts to emergency number based on the conversion map.
    ++     * The conversion map is declared as config_convert_to_emergency_number_map.
    ++     *
    ++     * Make sure {@link #isConvertToEmergencyNumberEnabled} is true before calling
    ++     * this function.
    ++     *
    ++     * @return The converted emergency number if the number matches conversion map,
    ++     * otherwise original number.
    ++     *
    ++     * @hide
    ++     */
    ++    public static String convertToEmergencyNumber(String number) {
    ++        if (TextUtils.isEmpty(number)) {
    ++            return number;
    ++        }
    ++
    ++        String normalizedNumber = normalizeNumber(number);
    ++
    ++        // The number is already emergency number. Skip conversion.
    ++        if (isEmergencyNumber(normalizedNumber)) {
    ++            return number;
    ++        }
    ++
    ++        for (String convertMap : CONVERT_TO_EMERGENCY_MAP) {
    ++            if (DBG) log("convertToEmergencyNumber: " + convertMap);
    ++            String[] entry = null;
    ++            String[] filterNumbers = null;
    ++            String convertedNumber = null;
    ++            if (!TextUtils.isEmpty(convertMap)) {
    ++                entry = convertMap.split(":");
    ++            }
    ++            if (entry != null && entry.length == 2) {
    ++                convertedNumber = entry[1];
    ++                if (!TextUtils.isEmpty(entry[0])) {
    ++                    filterNumbers = entry[0].split(",");
    ++                }
    ++            }
    ++            // Skip if the format of entry is invalid
    ++            if (TextUtils.isEmpty(convertedNumber) || filterNumbers == null
    ++                    || filterNumbers.length == 0) {
    ++                continue;
    ++            }
    ++
    ++            for (String filterNumber : filterNumbers) {
    ++                if (DBG) log("convertToEmergencyNumber: filterNumber = " + filterNumber
    ++                        + ", convertedNumber = " + convertedNumber);
    ++                if (!TextUtils.isEmpty(filterNumber) && filterNumber.equals(normalizedNumber)) {
    ++                    if (DBG) log("convertToEmergencyNumber: Matched. Successfully converted to: "
    ++                            + convertedNumber);
    ++                    return convertedNumber;
    ++                }
    ++            }
    ++        }
    ++        return number;
    ++    }
      }
    +diff --git a/telephony/java/android/telephony/RadioAccessFamily.java b/telephony/java/android/telephony/RadioAccessFamily.java
    +index b530a64..d657bae 100644
    +--- a/telephony/java/android/telephony/RadioAccessFamily.java
    ++++ b/telephony/java/android/telephony/RadioAccessFamily.java
    +@@ -29,32 +29,38 @@ import com.android.internal.telephony.RILConstants;
    + public class RadioAccessFamily implements Parcelable {
    + 
    +     // Radio Access Family
    ++    // 2G
    +     public static final int RAF_UNKNOWN = (1 <<  ServiceState.RIL_RADIO_TECHNOLOGY_UNKNOWN);
    ++    public static final int RAF_GSM = (1 << ServiceState.RIL_RADIO_TECHNOLOGY_GSM);
    +     public static final int RAF_GPRS = (1 << ServiceState.RIL_RADIO_TECHNOLOGY_GPRS);
    +     public static final int RAF_EDGE = (1 << ServiceState.RIL_RADIO_TECHNOLOGY_EDGE);
    +-    public static final int RAF_UMTS = (1 << ServiceState.RIL_RADIO_TECHNOLOGY_UMTS);
    +     public static final int RAF_IS95A = (1 << ServiceState.RIL_RADIO_TECHNOLOGY_IS95A);
    +     public static final int RAF_IS95B = (1 << ServiceState.RIL_RADIO_TECHNOLOGY_IS95B);
    +     public static final int RAF_1xRTT = (1 << ServiceState.RIL_RADIO_TECHNOLOGY_1xRTT);
    ++    // 3G
    +     public static final int RAF_EVDO_0 = (1 << ServiceState.RIL_RADIO_TECHNOLOGY_EVDO_0);
    +     public static final int RAF_EVDO_A = (1 << ServiceState.RIL_RADIO_TECHNOLOGY_EVDO_A);
    +-    public static final int RAF_HSDPA = (1 << ServiceState.RIL_RADIO_TECHNOLOGY_HSDPA);
    +-    public static final int RAF_HSUPA = (1 << ServiceState.RIL_RADIO_TECHNOLOGY_HSUPA);
    +-    public static final int RAF_HSPA = (1 << ServiceState.RIL_RADIO_TECHNOLOGY_HSPA);
    +     public static final int RAF_EVDO_B = (1 << ServiceState.RIL_RADIO_TECHNOLOGY_EVDO_B);
    +     public static final int RAF_EHRPD = (1 << ServiceState.RIL_RADIO_TECHNOLOGY_EHRPD);
    +-    public static final int RAF_LTE = (1 << ServiceState.RIL_RADIO_TECHNOLOGY_LTE);
    ++    public static final int RAF_HSUPA = (1 << ServiceState.RIL_RADIO_TECHNOLOGY_HSUPA);
    ++    public static final int RAF_HSDPA = (1 << ServiceState.RIL_RADIO_TECHNOLOGY_HSDPA);
    ++    public static final int RAF_HSPA = (1 << ServiceState.RIL_RADIO_TECHNOLOGY_HSPA);
    +     public static final int RAF_HSPAP = (1 << ServiceState.RIL_RADIO_TECHNOLOGY_HSPAP);
    +-    public static final int RAF_GSM = (1 << ServiceState.RIL_RADIO_TECHNOLOGY_GSM);
    ++    public static final int RAF_UMTS = (1 << ServiceState.RIL_RADIO_TECHNOLOGY_UMTS);
    +     public static final int RAF_TD_SCDMA = (1 << ServiceState.RIL_RADIO_TECHNOLOGY_TD_SCDMA);
    ++    // 4G
    ++    public static final int RAF_LTE = (1 << ServiceState.RIL_RADIO_TECHNOLOGY_LTE);
    +     public static final int RAF_LTE_CA = (1 << ServiceState.RIL_RADIO_TECHNOLOGY_LTE_CA);
    + 
    +     // Grouping of RAFs
    ++    // 2G
    +     private static final int GSM = RAF_GSM | RAF_GPRS | RAF_EDGE;
    +-    private static final int HS = RAF_HSUPA | RAF_HSDPA | RAF_HSPA | RAF_HSPAP;
    +     private static final int CDMA = RAF_IS95A | RAF_IS95B | RAF_1xRTT;
    ++    // 3G
    +     private static final int EVDO = RAF_EVDO_0 | RAF_EVDO_A | RAF_EVDO_B | RAF_EHRPD;
    ++    private static final int HS = RAF_HSUPA | RAF_HSDPA | RAF_HSPA | RAF_HSPAP;
    +     private static final int WCDMA = HS | RAF_UMTS;
    ++    // 4G
    +     private static final int LTE = RAF_LTE | RAF_LTE_CA;
    + 
    +     /* Phone ID of phone */
    +@@ -239,6 +245,24 @@ public class RadioAccessFamily implements Parcelable {
    +         return raf;
    +     }
    + 
    ++    /**
    ++     * Returns the highest capability of the RadioAccessFamily (4G > 3G > 2G).
    ++     * @param raf The RadioAccessFamily that we wish to filter
    ++     * @return The highest radio capability
    ++     */
    ++    public static int getHighestRafCapability(int raf) {
    ++        if ((LTE & raf) > 0) {
    ++            return TelephonyManager.NETWORK_CLASS_4_G;
    ++        }
    ++        if ((EVDO|HS|WCDMA & raf) > 0) {
    ++            return TelephonyManager.NETWORK_CLASS_3_G;
    ++        }
    ++        if((GSM|CDMA & raf) > 0) {
    ++            return TelephonyManager.NETWORK_CLASS_2_G;
    ++        }
    ++        return TelephonyManager.NETWORK_CLASS_UNKNOWN;
    ++    }
    ++
    +     public static int getNetworkTypeFromRaf(int raf) {
    +         int type;
      
    +diff --git a/telephony/java/android/telephony/Rlog.java b/telephony/java/android/telephony/Rlog.java
    +index b4f400f..cd0a012 100644
    +--- a/telephony/java/android/telephony/Rlog.java
    ++++ b/telephony/java/android/telephony/Rlog.java
    +@@ -16,8 +16,15 @@
    + 
    + package android.telephony;
    + 
    ++import android.text.TextUtils;
    + import android.util.Log;
    + 
    ++import android.util.Base64;
    ++
    ++import java.security.MessageDigest;
    ++import java.security.NoSuchAlgorithmException;
    ++
    ++
      /**
    -diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationGuts.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationGuts.java
    -index c497cfd..f2140f7 100644
    ---- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationGuts.java
    -+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationGuts.java
    -@@ -221,16 +221,16 @@ public class NotificationGuts extends LinearLayout implements TunerService.Tunab
    +  * A class to log strings to the RADIO LOG.
    +  *
    +@@ -87,11 +94,52 @@ public final class Rlog {
    + 
    +     /**
    +      * Redact personally identifiable information for production users.
    +-     * If log tag is loggable in verbose mode, return the original string, otherwise return XXX.
    ++     * @param tag used to identify the source of a log message
    ++     * @param pii the personally identifiable information we want to apply secure hash on.
    ++     * @return If tag is loggable in verbose mode or pii is null, return the original input.
    ++     * otherwise return a secure Hash of input pii
    +      */
    +     public static String pii(String tag, Object pii) {
    +-        return (isLoggable(tag, Log.VERBOSE) ? String.valueOf(pii) : "XXX");
    ++        String val = String.valueOf(pii);
    ++        if (pii == null || TextUtils.isEmpty(val) || isLoggable(tag, Log.VERBOSE)) {
    ++            return val;
    ++        }
    ++        return "[" + secureHash(val.getBytes()) + "]";
          }
      
    -     private int getSelectedImportance() {
    --        if (mSeekBar!= null && mSeekBar.isShown()) {
    -+        if (mSeekBar != null && mSeekBar.isShown()) {
    -             if (mSeekBar.isEnabled()) {
    -                 return mSeekBar.getProgress();
    ++    /**
    ++     * Redact personally identifiable information for production users.
    ++     * @param enablePiiLogging set when caller explicitly want to enable sensitive logging.
    ++     * @param pii the personally identifiable information we want to apply secure hash on.
    ++     * @return If enablePiiLogging is set to true or pii is null, return the original input.
    ++     * otherwise return a secure Hash of input pii
    ++     */
    ++    public static String pii(boolean enablePiiLogging, Object pii) {
    ++        String val = String.valueOf(pii);
    ++        if (pii == null || TextUtils.isEmpty(val) || enablePiiLogging) {
    ++            return val;
    ++        }
    ++        return "[" + secureHash(val.getBytes()) + "]";
    ++    }
    ++
    ++    /**
    ++     * Returns a secure hash (using the SHA1 algorithm) of the provided input.
    ++     *
    ++     * @return the hash
    ++     * @param input the bytes for which the secure hash should be computed.
    ++     */
    ++    private static String secureHash(byte[] input) {
    ++        MessageDigest messageDigest;
    ++
    ++        try {
    ++            messageDigest = MessageDigest.getInstance("SHA-1");
    ++        } catch (NoSuchAlgorithmException e) {
    ++            return "####";
    ++        }
    ++
    ++        byte[] result = messageDigest.digest(input);
    ++        return Base64.encodeToString(
    ++                result, Base64.URL_SAFE | Base64.NO_PADDING | Base64.NO_WRAP);
    ++    }
    + }
    + 
    +diff --git a/telephony/java/android/telephony/SubscriptionInfo.java b/telephony/java/android/telephony/SubscriptionInfo.java
    +index 6229ed9..cf2d27e 100644
    +--- a/telephony/java/android/telephony/SubscriptionInfo.java
    ++++ b/telephony/java/android/telephony/SubscriptionInfo.java
    +@@ -340,7 +340,7 @@ public class SubscriptionInfo implements Parcelable {
    +         String iccIdToPrint = null;
    +         if (iccId != null) {
    +             if (iccId.length() > 9 && !Build.IS_DEBUGGABLE) {
    +-                iccIdToPrint = iccId.substring(0, 9) + "XXXXXXXXXXX";
    ++                iccIdToPrint = iccId.substring(0, 9) + Rlog.pii(false, iccId.substring(9));
                  } else {
    -                 return Ranking.IMPORTANCE_UNSPECIFIED;
    +                 iccIdToPrint = iccId;
                  }
    -         } else {
    --            if (mBlock.isChecked()) {
    -+            if (mBlock != null && mBlock.isChecked()) {
    -                 return Ranking.IMPORTANCE_NONE;
    --            } else if (mSilent.isChecked()) {
    -+            } else if (mSilent != null && mSilent.isChecked()) {
    -                 return Ranking.IMPORTANCE_LOW;
    -             } else {
    -                 return Ranking.IMPORTANCE_UNSPECIFIED;
    -diff --git a/packages/SystemUI/src/com/android/systemui/tuner/TunerFragment.java b/packages/SystemUI/src/com/android/systemui/tuner/TunerFragment.java
    -index 70f2fdc..ba50161 100644
    ---- a/packages/SystemUI/src/com/android/systemui/tuner/TunerFragment.java
    -+++ b/packages/SystemUI/src/com/android/systemui/tuner/TunerFragment.java
    -@@ -59,7 +59,10 @@ public class TunerFragment extends PreferenceFragment {
    -     @Override
    -     public void onActivityCreated(Bundle savedInstanceState) {
    -         super.onActivityCreated(savedInstanceState);
    --        getActivity().getActionBar().setDisplayHomeAsUpEnabled(true);
    +diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
    +index 6e504d1..0257334 100644
    +--- a/telephony/java/android/telephony/TelephonyManager.java
    ++++ b/telephony/java/android/telephony/TelephonyManager.java
    +@@ -1662,6 +1662,12 @@ public class TelephonyManager {
    +         }
    +     }
    + 
    ++    /**
    ++     * Network Class Definitions.
    ++     * Do not change this order, it is used for sorting during emergency calling in
    ++     * {@link TelephonyConnectionService#getFirstPhoneForEmergencyCall()}. Any newer technologies
    ++     * should be added after the current definitions.
    ++     */
    +     /** Unknown network class. {@hide} */
    +     public static final int NETWORK_CLASS_UNKNOWN = 0;
    +     /** Class of broadly defined "2G" networks. {@hide} */
    +diff --git a/telephony/java/com/android/internal/telephony/CallerInfoAsyncQuery.java b/telephony/java/com/android/internal/telephony/CallerInfoAsyncQuery.java
    +index 05cb31e..d4104bd 100644
    +--- a/telephony/java/com/android/internal/telephony/CallerInfoAsyncQuery.java
    ++++ b/telephony/java/com/android/internal/telephony/CallerInfoAsyncQuery.java
    +@@ -176,13 +176,13 @@ public class CallerInfoAsyncQuery {
    +                     // However, if there is any code that this Handler calls (such as in
    +                     // super.handleMessage) that DOES place unexpected messages on the
    +                     // queue, then we need pass these messages on.
    +-                    if (DBG) Rlog.d(LOG_TAG, "Unexpected command (CookieWrapper is null): " + msg.what +
    ++                    Rlog.i(LOG_TAG, "Unexpected command (CookieWrapper is null): " + msg.what +
    +                             " ignored by CallerInfoWorkerHandler, passing onto parent.");
    + 
    +                     super.handleMessage(msg);
    +                 } else {
    + 
    +-                    if (DBG) Rlog.d(LOG_TAG, "Processing event: " + cw.event + " token (arg1): " + msg.arg1 +
    ++                    Rlog.d(LOG_TAG, "Processing event: " + cw.event + " token (arg1): " + msg.arg1 +
    +                         " command: " + msg.what + " query URI: " + sanitizeUriToString(args.uri));
    + 
    +                     switch (cw.event) {
    +@@ -239,7 +239,7 @@ public class CallerInfoAsyncQuery {
    +          */
    +         @Override
    +         protected void onQueryComplete(int token, Object cookie, Cursor cursor) {
    +-            if (DBG) Rlog.d(LOG_TAG, "##### onQueryComplete() #####   query complete for token: " + token);
    ++            Rlog.d(LOG_TAG, "##### onQueryComplete() #####   query complete for token: " + token);
    + 
    +             //get the cookie and notify the listener.
    +             CookieWrapper cw = (CookieWrapper) cookie;
    +@@ -248,7 +248,7 @@ public class CallerInfoAsyncQuery {
    +                 // from within this code.
    +                 // However, if there is any code that calls this method, we should
    +                 // check the parameters to make sure they're viable.
    +-                if (DBG) Rlog.d(LOG_TAG, "Cookie is null, ignoring onQueryComplete() request.");
    ++                Rlog.i(LOG_TAG, "Cookie is null, ignoring onQueryComplete() request.");
    +                 if (cursor != null) {
    +                     cursor.close();
    +                 }
    +@@ -333,9 +333,11 @@ public class CallerInfoAsyncQuery {
    + 
    +             //notify the listener that the query is complete.
    +             if (cw.listener != null) {
    +-                if (DBG) Rlog.d(LOG_TAG, "notifying listener: " + cw.listener.getClass().toString() +
    ++                Rlog.d(LOG_TAG, "notifying listener: " + cw.listener.getClass().toString() +
    +                              " for token: " + token + mCallerInfo);
    +                 cw.listener.onQueryComplete(token, cw.cookie, mCallerInfo);
    ++            } else {
    ++                Rlog.w(LOG_TAG, "There is no listener to notify for this query.");
    +             }
    + 
    +             if (cursor != null) {
    +diff --git a/telephony/java/com/android/internal/telephony/PhoneConstants.java b/telephony/java/com/android/internal/telephony/PhoneConstants.java
    +index b417a1c..fdc68b9 100644
    +--- a/telephony/java/com/android/internal/telephony/PhoneConstants.java
    ++++ b/telephony/java/com/android/internal/telephony/PhoneConstants.java
    +@@ -140,6 +140,18 @@ public class PhoneConstants {
    +     /** APN type for Emergency PDN. This is not an IA apn, but is used
    +      * for access to carrier services in an emergency call situation. */
    +     public static final String APN_TYPE_EMERGENCY = "emergency";
    ++    /** Array of all APN types */
    ++    public static final String[] APN_TYPES = {APN_TYPE_DEFAULT,
    ++            APN_TYPE_MMS,
    ++            APN_TYPE_SUPL,
    ++            APN_TYPE_DUN,
    ++            APN_TYPE_HIPRI,
    ++            APN_TYPE_FOTA,
    ++            APN_TYPE_IMS,
    ++            APN_TYPE_CBS,
    ++            APN_TYPE_IA,
    ++            APN_TYPE_EMERGENCY
    ++    };
    + 
    +     public static final int RIL_CARD_MAX_APPS    = 8;
    + 
    +diff --git a/tests/Assist/res/drawable/assistant.xml b/tests/Assist/res/drawable/assistant.xml
    +index 2a89dda..56fe2de 100644
    +--- a/tests/Assist/res/drawable/assistant.xml
    ++++ b/tests/Assist/res/drawable/assistant.xml
    +@@ -19,9 +19,6 @@ Copyright (C) 2014 The Android Open Source Project
    +         android:viewportWidth="48.0"
    +         android:viewportHeight="48.0">
    +     <path
    +-        android:pathData="M0 0h48v48H0z"
    +-        android:fillColor="#00000000"/>
    +-    <path
    +         android:fillColor="#FF000000"
    +         android:pathData="M38.0,4.0L10.0,4.0C7.79,4.0 6.0,5.79 6.0,8.0l0.0,28.0c0.0,2.21 1.79,4.0 4.0,4.0l8.0,0.0l6.0,6.0 6.0,-6.0l8.0,0.0c2.21,0.0 4.0,-1.79 4.0,-4.0L36.0,8.0c0.0,-2.21 -1.79,-4.0 -4.0,-4.0zM27.75,25.75L24.0,34.0l-3.75,-8.25L12.0,22.0l8.25,-3.75L24.0,10.0l3.75,8.25L36.0,22.0l-8.25,3.75z"/>
    + </vector>
    +diff --git a/tests/UiBench/AndroidManifest.xml b/tests/UiBench/AndroidManifest.xml
    +index 95bbb21..3d3247c 100644
    +--- a/tests/UiBench/AndroidManifest.xml
    ++++ b/tests/UiBench/AndroidManifest.xml
    +@@ -85,13 +85,21 @@
    +         </activity>
    +         <activity
    +             android:name=".TrivialRecyclerViewActivity"
    +-            android:label="General/Trivial Recycler ListView" >
    ++            android:label="General/Trivial RecyclerView" >
    +             <intent-filter>
    +                 <action android:name="android.intent.action.MAIN" />
    +                 <category android:name="com.android.test.uibench.TEST" />
    +             </intent-filter>
    +         </activity>
    +         <activity
    ++            android:name=".SlowBindRecyclerViewActivity"
    ++            android:label="General/Slow Bind RecyclerView" >
    ++        <intent-filter>
    ++            <action android:name="android.intent.action.MAIN" />
    ++            <category android:name="com.android.test.uibench.TEST" />
    ++        </intent-filter>
    ++        </activity>
    ++        <activity
    +             android:name=".ActivityTransition"
    +             android:label="Transitions/Activity Transition" >
    +             <intent-filter>
    +diff --git a/tests/UiBench/src/com/android/test/uibench/SlowBindRecyclerViewActivity.java b/tests/UiBench/src/com/android/test/uibench/SlowBindRecyclerViewActivity.java
    +new file mode 100644
    +index 0000000..e32862f
    +--- /dev/null
    ++++ b/tests/UiBench/src/com/android/test/uibench/SlowBindRecyclerViewActivity.java
    +@@ -0,0 +1,55 @@
    ++/*
    ++ * Copyright (C) 2016 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 com.android.test.uibench;
    ++
    ++import android.content.Context;
    ++import android.os.Trace;
    ++import android.support.v7.widget.GridLayoutManager;
    ++import android.support.v7.widget.RecyclerView;
    ++import com.android.test.uibench.recyclerview.RvBoxAdapter;
    ++import com.android.test.uibench.recyclerview.RvCompatListActivity;
    ++
    ++import java.util.concurrent.TimeUnit;
    ++
    ++public class SlowBindRecyclerViewActivity extends RvCompatListActivity {
    ++    /**
    ++     * Spin wait. Used instead of sleeping so a core is used up for the duration, and so
    ++     * traces/sampled profiling show the sections as expensive, and not just a scheduling mistake.
    ++     */
    ++    private static void spinWaitMs(long ms) {
    ++        long start = System.nanoTime();
    ++        while (System.nanoTime() - start < TimeUnit.MILLISECONDS.toNanos(ms));
    ++    }
    ++
    ++    @Override
    ++    protected RecyclerView.LayoutManager createLayoutManager(Context context) {
    ++        return new GridLayoutManager(context, 3);
    ++    }
    ++
    ++    @Override
    ++    protected RecyclerView.Adapter createAdapter() {
    ++        return new RvBoxAdapter(this, TextUtils.buildSimpleStringList()) {
    ++            @Override
    ++            public void onBindViewHolder(ViewHolder holder, int position) {
    ++                Trace.beginSection("bind item " + position);
    ++
    ++                spinWaitMs(3);
    ++                super.onBindViewHolder(holder, position);
    ++                Trace.endSection();
    ++            }
    ++        };
    ++    }
    ++}
    +diff --git a/tests/UiBench/src/com/android/test/uibench/recyclerview/RvBoxAdapter.java b/tests/UiBench/src/com/android/test/uibench/recyclerview/RvBoxAdapter.java
    +new file mode 100644
    +index 0000000..3440f19
    +--- /dev/null
    ++++ b/tests/UiBench/src/com/android/test/uibench/recyclerview/RvBoxAdapter.java
    +@@ -0,0 +1,99 @@
    ++/*
    ++ * Copyright (C) 2016 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 com.android.test.uibench.recyclerview;
    ++
    ++import android.content.Context;
    ++import android.graphics.Color;
    ++import android.support.v7.widget.RecyclerView;
    ++import android.util.TypedValue;
    ++import android.view.ViewGroup;
    ++import android.widget.TextView;
    ++
    ++import java.util.ArrayList;
    ++import java.util.Collections;
    ++import java.util.List;
    ++
    ++public class RvBoxAdapter extends RecyclerView.Adapter<RvBoxAdapter.ViewHolder> {
    ++
    ++    private int mBackground;
    ++
    ++    private List<String> mValues;
    ++
    ++    public static class ViewHolder extends RecyclerView.ViewHolder {
    ++        public TextView mTextView;
    ++
    ++        public ViewHolder(TextView v) {
    ++            super(v);
    ++            mTextView = v;
    ++        }
    ++
    ++        @Override
    ++        public String toString() {
    ++            return super.toString() + " '" + mTextView.getText();
    ++        }
    ++    }
    ++
    ++    public RvBoxAdapter(Context context, String[] strings) {
    ++        TypedValue val = new TypedValue();
    ++        if (context.getTheme() != null) {
    ++            context.getTheme().resolveAttribute(
    ++                    android.R.attr.selectableItemBackground, val, true);
    ++        }
    ++        mBackground = val.resourceId;
    ++        mValues = new ArrayList<>();
    ++        Collections.addAll(mValues, strings);
    ++    }
    ++
    ++    @Override
    ++    public RvBoxAdapter.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
    ++        final ViewHolder h = new ViewHolder(new TextView(parent.getContext()));
    ++        h.mTextView.setMinimumHeight(128);
    ++        h.mTextView.setPadding(20, 0, 20, 0);
    ++        h.mTextView.setFocusable(true);
    ++        h.mTextView.setBackgroundResource(mBackground);
    ++        RecyclerView.LayoutParams lp = new RecyclerView.LayoutParams(
    ++                ViewGroup.LayoutParams.WRAP_CONTENT,
    ++                ViewGroup.LayoutParams.WRAP_CONTENT);
    ++        lp.leftMargin = 10;
    ++        lp.rightMargin = 5;
    ++        lp.topMargin = 20;
    ++        lp.bottomMargin = 15;
    ++        h.mTextView.setLayoutParams(lp);
    ++        return h;
    ++    }
    ++
    ++    @Override
    ++    public void onBindViewHolder(ViewHolder holder, int position) {
    ++        holder.mTextView.setText(position + ":" + mValues.get(position));
    ++        holder.mTextView.setMinHeight((200 + mValues.get(position).length() * 10));
    ++        holder.mTextView.setBackgroundColor(getBackgroundColor(position));
    ++    }
    ++
    ++    private int getBackgroundColor(int position) {
    ++        switch (position % 4) {
    ++            case 0: return Color.LTGRAY;
    ++            case 1: return Color.RED;
    ++            case 2: return Color.DKGRAY;
    ++            case 3: return Color.BLUE;
    ++        }
    ++        return Color.TRANSPARENT;
    ++    }
    ++
    ++    @Override
    ++    public int getItemCount() {
    ++        return mValues.size();
    ++    }
    ++}
    +diff --git a/tests/UiBench/src/com/android/test/uibench/recyclerview/RvCompatListActivity.java b/tests/UiBench/src/com/android/test/uibench/recyclerview/RvCompatListActivity.java
    +index e08dbc6..939b661 100644
    +--- a/tests/UiBench/src/com/android/test/uibench/recyclerview/RvCompatListActivity.java
    ++++ b/tests/UiBench/src/com/android/test/uibench/recyclerview/RvCompatListActivity.java
    +@@ -26,7 +26,6 @@ import android.support.v7.widget.RecyclerView;
    + import android.view.LayoutInflater;
    + import android.view.View;
    + import android.view.ViewGroup;
    +-import android.widget.ArrayAdapter;
    + 
    + import com.android.test.uibench.R;
    + 
    +diff --git a/tools/aapt/Command.cpp b/tools/aapt/Command.cpp
    +index 59da467..ad583a8 100644
    +--- a/tools/aapt/Command.cpp
    ++++ b/tools/aapt/Command.cpp
    +@@ -540,7 +540,7 @@ static bool hasFeature(const char* name, const FeatureGroup& grp,
    + }
    + 
    + static void addImpliedFeature(KeyedVector<String8, ImpliedFeature>* impliedFeatures,
    +-                              const char* name, const char* reason, bool sdk23) {
    ++                              const char* name, const String8& reason, bool sdk23) {
    +     String8 name8(name);
    +     ssize_t idx = impliedFeatures->indexOfKey(name8);
    +     if (idx < 0) {
    +@@ -553,7 +553,7 @@ static void addImpliedFeature(KeyedVector<String8, ImpliedFeature>* impliedFeatu
    +     if (feature->impliedBySdk23 && !sdk23) {
    +         feature->impliedBySdk23 = false;
    +     }
    +-    feature->reasons.add(String8(reason));
    ++    feature->reasons.add(reason);
    + }
    + 
    + static void printFeatureGroupImpl(const FeatureGroup& grp,
    +@@ -651,50 +651,58 @@ static void addImpliedFeaturesForPermission(const int targetSdk, const String8&
    +                                             bool impliedBySdk23Permission) {
    +     if (name == "android.permission.CAMERA") {
    +         addImpliedFeature(impliedFeatures, "android.hardware.camera",
    +-                String8::format("requested %s permission", name.string())
    +-                .string(), impliedBySdk23Permission);
    ++                          String8::format("requested %s permission", name.string()),
    ++                          impliedBySdk23Permission);
    +     } else if (name == "android.permission.ACCESS_FINE_LOCATION") {
    +-        addImpliedFeature(impliedFeatures, "android.hardware.location.gps",
    +-                String8::format("requested %s permission", name.string())
    +-                .string(), impliedBySdk23Permission);
    +-        addImpliedFeature(impliedFeatures, "android.hardware.location",
    +-                String8::format("requested %s permission", name.string())
    +-                .string(), impliedBySdk23Permission);
    +-    } else if (name == "android.permission.ACCESS_MOCK_LOCATION") {
    ++        if (targetSdk < SDK_LOLLIPOP) {
    ++            addImpliedFeature(impliedFeatures, "android.hardware.location.gps",
    ++                              String8::format("requested %s permission", name.string()),
    ++                              impliedBySdk23Permission);
    ++            addImpliedFeature(impliedFeatures, "android.hardware.location.gps",
    ++                              String8::format("targetSdkVersion < %d", SDK_LOLLIPOP),
    ++                              impliedBySdk23Permission);
    ++        }
    +         addImpliedFeature(impliedFeatures, "android.hardware.location",
    +-                String8::format("requested %s permission", name.string())
    +-                .string(), impliedBySdk23Permission);
    ++                String8::format("requested %s permission", name.string()),
    ++                impliedBySdk23Permission);
    +     } else if (name == "android.permission.ACCESS_COARSE_LOCATION") {
    +-        addImpliedFeature(impliedFeatures, "android.hardware.location.network",
    +-                String8::format("requested %s permission", name.string())
    +-                .string(), impliedBySdk23Permission);
    ++        if (targetSdk < SDK_LOLLIPOP) {
    ++            addImpliedFeature(impliedFeatures, "android.hardware.location.network",
    ++                              String8::format("requested %s permission", name.string()),
    ++                              impliedBySdk23Permission);
    ++            addImpliedFeature(impliedFeatures, "android.hardware.location.network",
    ++                              String8::format("targetSdkVersion < %d", SDK_LOLLIPOP),
    ++                              impliedBySdk23Permission);
    ++        }
    +         addImpliedFeature(impliedFeatures, "android.hardware.location",
    +-                String8::format("requested %s permission", name.string())
    +-                .string(), impliedBySdk23Permission);
    +-    } else if (name == "android.permission.ACCESS_LOCATION_EXTRA_COMMANDS" ||
    ++                          String8::format("requested %s permission", name.string()),
    ++                          impliedBySdk23Permission);
    ++    } else if (name == "android.permission.ACCESS_MOCK_LOCATION" ||
    ++               name == "android.permission.ACCESS_LOCATION_EXTRA_COMMANDS" ||
    +                name == "android.permission.INSTALL_LOCATION_PROVIDER") {
    +         addImpliedFeature(impliedFeatures, "android.hardware.location",
    +-                String8::format("requested %s permission", name.string())
    +-                .string(), impliedBySdk23Permission);
    ++                          String8::format("requested %s permission", name.string()),
    ++                          impliedBySdk23Permission);
    +     } else if (name == "android.permission.BLUETOOTH" ||
    +                name == "android.permission.BLUETOOTH_ADMIN") {
    +-        if (targetSdk > 4) {
    ++        if (targetSdk > SDK_DONUT) {
    +             addImpliedFeature(impliedFeatures, "android.hardware.bluetooth",
    +-                    String8::format("requested %s permission", name.string())
    +-                    .string(), impliedBySdk23Permission);
    ++                              String8::format("requested %s permission", name.string()),
    ++                              impliedBySdk23Permission);
    +             addImpliedFeature(impliedFeatures, "android.hardware.bluetooth",
    +-                    "targetSdkVersion > 4", impliedBySdk23Permission);
    ++                              String8::format("targetSdkVersion > %d", SDK_DONUT),
    ++                              impliedBySdk23Permission);
    +         }
    +     } else if (name == "android.permission.RECORD_AUDIO") {
    +         addImpliedFeature(impliedFeatures, "android.hardware.microphone",
    +-                String8::format("requested %s permission", name.string())
    +-                .string(), impliedBySdk23Permission);
    ++                          String8::format("requested %s permission", name.string()),
    ++                          impliedBySdk23Permission);
    +     } else if (name == "android.permission.ACCESS_WIFI_STATE" ||
    +                name == "android.permission.CHANGE_WIFI_STATE" ||
    +                name == "android.permission.CHANGE_WIFI_MULTICAST_STATE") {
    +         addImpliedFeature(impliedFeatures, "android.hardware.wifi",
    +-                String8::format("requested %s permission", name.string())
    +-                .string(), impliedBySdk23Permission);
    ++                          String8::format("requested %s permission", name.string()),
    ++                          impliedBySdk23Permission);
    +     } else if (name == "android.permission.CALL_PHONE" ||
    +                name == "android.permission.CALL_PRIVILEGED" ||
    +                name == "android.permission.MODIFY_PHONE_STATE" ||
    +@@ -707,8 +715,8 @@ static void addImpliedFeaturesForPermission(const int targetSdk, const String8&
    +                name == "android.permission.WRITE_APN_SETTINGS" ||
    +                name == "android.permission.WRITE_SMS") {
    +         addImpliedFeature(impliedFeatures, "android.hardware.telephony",
    +-                String8("requested a telephony permission").string(),
    +-                impliedBySdk23Permission);
    ++                          String8("requested a telephony permission"),
    ++                          impliedBySdk23Permission);
    +     }
    + }
    + 
    +@@ -1659,18 +1667,18 @@ int doDump(Bundle* bundle)
    +                             if (error == "") {
    +                                 if (orien == 0 || orien == 6 || orien == 8) {
    +                                     // Requests landscape, sensorLandscape, or reverseLandscape.
    +-                                    addImpliedFeature(&impliedFeatures,
    +-                                                      "android.hardware.screen.landscape",
    +-                                                      "one or more activities have specified a "
    +-                                                      "landscape orientation",
    +-                                                      false);
    ++                                    addImpliedFeature(
    ++                                            &impliedFeatures, "android.hardware.screen.landscape",
    ++                                            String8("one or more activities have specified a "
    ++                                                    "landscape orientation"),
    ++                                            false);
    +                                 } else if (orien == 1 || orien == 7 || orien == 9) {
    +                                     // Requests portrait, sensorPortrait, or reversePortrait.
    +-                                    addImpliedFeature(&impliedFeatures,
    +-                                                      "android.hardware.screen.portrait",
    +-                                                      "one or more activities have specified a "
    +-                                                      "portrait orientation",
    +-                                                      false);
    ++                                    addImpliedFeature(
    ++                                            &impliedFeatures, "android.hardware.screen.portrait",
    ++                                            String8("one or more activities have specified a "
    ++                                                    "portrait orientation"),
    ++                                            false);
    +                                 }
    +                             }
    +                         } else if (tag == "uses-library") {
    +@@ -2026,7 +2034,7 @@ int doDump(Bundle* bundle)
    +             // directly or implied, required or not), then the faketouch feature is implied.
    +             if (!hasFeature("android.hardware.touchscreen", commonFeatures, impliedFeatures)) {
    +                 addImpliedFeature(&impliedFeatures, "android.hardware.faketouch",
    +-                                  "default feature for all apps", false);
    ++                                  String8("default feature for all apps"), false);
    +             }
    + 
    +             const size_t numFeatureGroups = featureGroups.size();
    +diff --git a/tools/fonts/fontchain_lint.py b/tools/fonts/fontchain_lint.py
    +index 2956d87..7ec46a3e 100755
    +--- a/tools/fonts/fontchain_lint.py
    ++++ b/tools/fonts/fontchain_lint.py
    +@@ -256,8 +256,8 @@ def parse_fonts_xml(fonts_xml_path):
    + 
    + 
    + def check_emoji_coverage(all_emoji, equivalent_emoji):
    +-  emoji_font = get_emoji_font()
    +-  check_emoji_font_coverage(emoji_font, all_emoji, equivalent_emoji)
    ++    emoji_font = get_emoji_font()
    ++    check_emoji_font_coverage(emoji_font, all_emoji, equivalent_emoji)
    + 
    + 
    + def get_emoji_font():
    +@@ -274,15 +274,12 @@ def check_emoji_font_coverage(emoji_font, all_emoji, equivalent_emoji):
    +         assert sequence in coverage, (
    +             '%s is not supported in the emoji font.' % printable(sequence))
    + 
    +-    # disable temporarily - we cover more than this
    +-    """
    +     for sequence in coverage:
    +         if sequence in {0x0000, 0x000D, 0x0020}:
    +             # The font needs to support a few extra characters, which is OK
    +             continue
    +         assert sequence in all_emoji, (
    +             'Emoji font should not support %s.' % printable(sequence))
    +-    """
    + 
    +     for first, second in sorted(equivalent_emoji.items()):
    +         assert coverage[first] == coverage[second], (
    +@@ -290,8 +287,6 @@ def check_emoji_font_coverage(emoji_font, all_emoji, equivalent_emoji):
    +                 printable(first),
    +                 printable(second)))
    + 
    +-    # disable temporarily - some equivalent sequences we don't even know about
    +-    """
    +     for glyph in set(coverage.values()):
    +         maps_to_glyph = [seq for seq in coverage if coverage[seq] == glyph]
    +         if len(maps_to_glyph) > 1:
    +@@ -307,7 +302,7 @@ def check_emoji_font_coverage(emoji_font, all_emoji, equivalent_emoji):
    +                 'The sequences %s should not result in the same glyph %s' % (
    +                     printable(equivalent_seqs),
    +                     glyph))
    +-    """
     +
    -+        if (getActivity().getActionBar() != null) {
    -+            getActivity().getActionBar().setDisplayHomeAsUpEnabled(true);
    -+        }
    -     }
      
    -     @Override
    -diff --git a/services/core/java/com/android/server/AppOpsService.java b/services/core/java/com/android/server/AppOpsService.java
    -index b5b0cd8..a5c10fb 100644
    ---- a/services/core/java/com/android/server/AppOpsService.java
    -+++ b/services/core/java/com/android/server/AppOpsService.java
    -@@ -597,7 +597,6 @@ public class AppOpsService extends IAppOpsService.Stub {
    -         ArrayList<Callback> repCbs = null;
    -         code = AppOpsManager.opToSwitch(code);
    -         synchronized (this) {
    --            UidState uidState = getUidStateLocked(uid, false);
    -             Op op = getOpLocked(code, uid, packageName, true);
    -             if (op != null) {
    -                 if (op.mode != mode) {
    -@@ -973,7 +972,7 @@ public class AppOpsService extends IAppOpsService.Stub {
    -     public int checkPackage(int uid, String packageName) {
    -         Preconditions.checkNotNull(packageName);
    -         synchronized (this) {
    --            if (getOpsRawLocked(uid, packageName, true) != null) {
    -+            if (packageName != null && getOpsRawLocked(uid, packageName, true) != null) {
    -                 return AppOpsManager.MODE_ALLOWED;
    -             } else {
    -                 return AppOpsManager.MODE_ERRORED;
    -@@ -1533,8 +1532,6 @@ public class AppOpsService extends IAppOpsService.Stub {
    + def check_emoji_defaults(default_emoji):
    +     missing_text_chars = _emoji_properties['Emoji'] - default_emoji
    +@@ -334,15 +329,9 @@ def check_emoji_defaults(default_emoji):
    +     # Noto does not have monochrome glyphs for Unicode 7.0 wingdings and
    +     # webdings yet.
    +     missing_text_chars -= _chars_by_age['7.0']
    +-    # TODO: Remove these after b/26113320 is fixed
    +-    missing_text_chars -= {
    +-        0x263A, # WHITE SMILING FACE
    +-        0x270C, # VICTORY HAND
    +-        0x2744, # SNOWFLAKE
    +-        0x2764, # HEAVY BLACK HEART
    +-    }
    +     assert missing_text_chars == set(), (
    +-        'Text style version of some emoji characters are missing: ' + repr(missing_text_chars))
    ++        'Text style version of some emoji characters are missing: ' +
    ++            repr(missing_text_chars))
      
    -     void writeState() {
    -         synchronized (mFile) {
    --            List<AppOpsManager.PackageOps> allOps = getPackagesForOps(null);
    + 
    + # Setting reverse to true returns a dictionary that maps the values to sets of
    +@@ -362,7 +351,7 @@ def parse_unicode_datafile(file_path, reverse=False):
    +             if not line:
    +                 continue
    + 
    +-            chars, prop = line.split(';')
    ++            chars, prop = line.split(';')[:2]
    +             chars = chars.strip()
    +             prop = prop.strip()
    + 
    +@@ -423,26 +412,6 @@ def parse_ucd(ucd_path):
    +     _emoji_zwj_sequences = parse_unicode_datafile(
    +         path.join(ucd_path, 'emoji-zwj-sequences.txt'))
    + 
    +-    # filter modern pentathlon, as it seems likely to be removed from final spec
    +-    # also filter rifle
    +-    def is_excluded(n):
    +-        return n in [0x1f93b, 0x1f946]
    +-
    +-    def contains_excluded(t):
    +-        if type(t) == int:
    +-            return is_excluded(t)
    +-        return any(is_excluded(cp) for cp in t)
    +-
    +-    # filter modern pentathlon, as it seems likely to be removed from final spec
    +-    _emoji_properties['Emoji'] = set(
    +-        t for t in _emoji_properties['Emoji'] if not contains_excluded(t))
    +-    _emoji_sequences = dict(
    +-        (t, v) for (t, v) in _emoji_sequences.items() if not contains_excluded(t))
    +-
    +-    # add in UN flag
    +-    UN_seq = flag_sequence('UN')
    +-    _emoji_sequences[UN_seq] = 'Emoji_Flag_Sequence'
     -
    -             FileOutputStream stream;
    -             try {
    -                 stream = mFile.startWrite();
    -@@ -1543,15 +1540,33 @@ public class AppOpsService extends IAppOpsService.Stub {
    -                 return;
    -             }
      
    -+            SparseArray<UidState> outUidStates = null;
    -+            synchronized (this) {
    -+                final int uidStateCount = mUidStates.size();
    -+                for (int i = 0; i < uidStateCount; i++) {
    -+                    UidState uidState = mUidStates.valueAt(i);
    -+                    SparseIntArray opModes = uidState.opModes;
    -+                    if (opModes != null && opModes.size() > 0) {
    -+                        UidState outUidState = new UidState(uidState.uid);
    -+                        outUidState.opModes = opModes.clone();
    -+                        if (outUidStates == null) {
    -+                            outUidStates = new SparseArray<>();
    -+                        }
    -+                        outUidStates.put(mUidStates.keyAt(i), outUidState);
    -+                    }
    -+                }
    -+            }
    -+            List<AppOpsManager.PackageOps> allOps = getPackagesForOps(null);
    + def flag_sequence(territory_code):
    +     return tuple(0x1F1E6 + ord(ch) - ord('A') for ch in territory_code)
    +@@ -454,7 +423,8 @@ UNSUPPORTED_FLAGS = frozenset({
    +     flag_sequence('GF'), flag_sequence('GP'), flag_sequence('GS'),
    +     flag_sequence('MF'), flag_sequence('MQ'), flag_sequence('NC'),
    +     flag_sequence('PM'), flag_sequence('RE'), flag_sequence('TF'),
    +-    flag_sequence('WF'), flag_sequence('XK'), flag_sequence('YT'),
    ++    flag_sequence('UN'), flag_sequence('WF'), flag_sequence('XK'),
    ++    flag_sequence('YT'),
    + })
    + 
    + EQUIVALENT_FLAGS = {
    +@@ -467,6 +437,22 @@ EQUIVALENT_FLAGS = {
    + 
    + COMBINING_KEYCAP = 0x20E3
    + 
    ++# Characters that Android defaults to emoji style, different from the recommendations in UTR #51
    ++ANDROID_DEFAULT_EMOJI = frozenset({
    ++    0x2600, # BLACK SUN WITH RAYS
    ++    0x2601, # CLOUD
    ++    0x260E, # BLACK TELEPHONE
    ++    0x261D, # WHITE UP POINTING INDEX
    ++    0x263A, # WHITE SMILING FACE
    ++    0x2660, # BLACK SPADE SUIT
    ++    0x2663, # BLACK CLUB SUIT
    ++    0x2665, # BLACK HEART SUIT
    ++    0x2666, # BLACK DIAMOND SUIT
    ++    0x270C, # VICTORY HAND
    ++    0x2744, # SNOWFLAKE
    ++    0x2764, # HEAVY BLACK HEART
    ++})
     +
    -             try {
    -                 XmlSerializer out = new FastXmlSerializer();
    -                 out.setOutput(stream, StandardCharsets.UTF_8.name());
    -                 out.startDocument(null, true);
    -                 out.startTag(null, "app-ops");
    + LEGACY_ANDROID_EMOJI = {
    +     0xFE4E5: flag_sequence('JP'),
    +     0xFE4E6: flag_sequence('US'),
    +@@ -502,7 +488,17 @@ ZWJ_IDENTICALS = {
      
    --                final int uidStateCount = mUidStates.size();
    -+                final int uidStateCount = outUidStates != null ? outUidStates.size() : 0;
    -                 for (int i = 0; i < uidStateCount; i++) {
    --                    UidState uidState = mUidStates.valueAt(i);
    -+                    UidState uidState = outUidStates.valueAt(i);
    -                     if (uidState.opModes != null && uidState.opModes.size() > 0) {
    -                         out.startTag(null, "uid");
    -                         out.attribute(null, "n", Integer.toString(uidState.uid));
    -diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
    -index 40f3608..cf99c26 100644
    ---- a/services/core/java/com/android/server/am/ActivityManagerService.java
    -+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
    -@@ -9576,7 +9576,7 @@ public final class ActivityManagerService extends ActivityManagerNative
    -         for (int i = 0; i < procsToKill.size(); i++) {
    -             ProcessRecord pr = procsToKill.get(i);
    -             if (pr.setSchedGroup == ProcessList.SCHED_GROUP_BACKGROUND
    --                    && pr.curReceiver == null) {
    -+                    && pr.curReceivers.isEmpty()) {
    -                 pr.kill("remove task", true);
    -             } else {
    -                 // We delay killing processes that are not in the background or running a receiver.
    -@@ -19146,26 +19146,28 @@ public final class ActivityManagerService extends ActivityManagerNative
    -     // LIFETIME MANAGEMENT
    -     // =========================================================
      
    --    // Returns which broadcast queue the app is the current [or imminent] receiver
    --    // on, or 'null' if the app is not an active broadcast recipient.
    --    private BroadcastQueue isReceivingBroadcast(ProcessRecord app) {
    --        BroadcastRecord r = app.curReceiver;
    --        if (r != null) {
    --            return r.queue;
    -+    // Returns whether the app is receiving broadcast.
    -+    // If receiving, fetch all broadcast queues which the app is
    -+    // the current [or imminent] receiver on.
    -+    private boolean isReceivingBroadcastLocked(ProcessRecord app,
    -+            ArraySet<BroadcastQueue> receivingQueues) {
    -+        if (!app.curReceivers.isEmpty()) {
    -+            for (BroadcastRecord r : app.curReceivers) {
    -+                receivingQueues.add(r.queue);
    -+            }
    -+            return true;
    -         }
    + def is_fitzpatrick_modifier(cp):
    +-  return 0x1f3fb <= cp <= 0x1f3ff
    ++    return 0x1F3FB <= cp <= 0x1F3FF
    ++
    ++
    ++def reverse_emoji(seq):
    ++    rev = list(reversed(seq))
    ++    # if there are fitzpatrick modifiers in the sequence, keep them after
    ++    # the emoji they modify
    ++    for i in xrange(1, len(rev)):
    ++        if is_fitzpatrick_modifier(rev[i-1]):
    ++            rev[i], rev[i-1] = rev[i-1], rev[i]
    ++    return tuple(rev)
      
    -         // It's not the current receiver, but it might be starting up to become one
    --        synchronized (this) {
    --            for (BroadcastQueue queue : mBroadcastQueues) {
    --                r = queue.mPendingBroadcast;
    --                if (r != null && r.curApp == app) {
    --                    // found it; report which queue it's in
    --                    return queue;
    --                }
    -+        for (BroadcastQueue queue : mBroadcastQueues) {
    -+            final BroadcastRecord r = queue.mPendingBroadcast;
    -+            if (r != null && r.curApp == app) {
    -+                // found it; report which queue it's in
    -+                receivingQueues.add(queue);
    -             }
    -         }
      
    --        return null;
    -+        return !receivingQueues.isEmpty();
    + def compute_expected_emoji():
    +@@ -511,26 +507,52 @@ def compute_expected_emoji():
    +     all_sequences = set()
    +     all_sequences.update(_emoji_variation_sequences)
    + 
    ++    # add zwj sequences not in the current emoji-zwj-sequences.txt
    ++    adjusted_emoji_zwj_sequences = dict(_emoji_zwj_sequences)
    ++    adjusted_emoji_zwj_sequences.update(_emoji_zwj_sequences)
    ++    # single parent families
    ++    additional_emoji_zwj = (
    ++        (0x1F468, 0x200D, 0x1F466),
    ++        (0x1F468, 0x200D, 0x1F467),
    ++        (0x1F468, 0x200D, 0x1F466, 0x200D, 0x1F466),
    ++        (0x1F468, 0x200D, 0x1F467, 0x200D, 0x1F466),
    ++        (0x1F468, 0x200D, 0x1F467, 0x200D, 0x1F467),
    ++        (0x1F469, 0x200D, 0x1F466),
    ++        (0x1F469, 0x200D, 0x1F467),
    ++        (0x1F469, 0x200D, 0x1F466, 0x200D, 0x1F466),
    ++        (0x1F469, 0x200D, 0x1F467, 0x200D, 0x1F466),
    ++        (0x1F469, 0x200D, 0x1F467, 0x200D, 0x1F467),
    ++    )
    ++    # sequences formed from man and woman and optional fitzpatrick modifier
    ++    modified_extensions = (
    ++        0x2696,
    ++        0x2708,
    ++        0x1F3A8,
    ++        0x1F680,
    ++        0x1F692,
    ++    )
    ++    for seq in additional_emoji_zwj:
    ++        adjusted_emoji_zwj_sequences[seq] = 'Emoji_ZWJ_Sequence'
    ++    for ext in modified_extensions:
    ++        for base in (0x1F468, 0x1F469):
    ++            seq = (base, 0x200D, ext)
    ++            adjusted_emoji_zwj_sequences[seq] = 'Emoji_ZWJ_Sequence'
    ++            for modifier in range(0x1F3FB, 0x1F400):
    ++                seq = (base, modifier, 0x200D, ext)
    ++                adjusted_emoji_zwj_sequences[seq] = 'Emoji_ZWJ_Sequence'
    ++
    +     for sequence in _emoji_sequences.keys():
    +         sequence = tuple(ch for ch in sequence if ch != EMOJI_VS)
    +         all_sequences.add(sequence)
    +         sequence_pieces.update(sequence)
    + 
    +-    for sequence in _emoji_zwj_sequences.keys():
    ++    for sequence in adjusted_emoji_zwj_sequences.keys():
    +         sequence = tuple(ch for ch in sequence if ch != EMOJI_VS)
    +         all_sequences.add(sequence)
    +         sequence_pieces.update(sequence)
    +         # Add reverse of all emoji ZWJ sequences, which are added to the fonts
    +         # as a workaround to get the sequences work in RTL text.
    +-        reversed_seq = list(reversed(sequence))
    +-        # if there are fitzpatrick modifiers in the sequence, keep them after
    +-        # the emoji they modify
    +-        for i in xrange(1, len(reversed_seq)):
    +-          if is_fitzpatrick_modifier(reversed_seq[i - 1]):
    +-            tmp = reversed_seq[i]
    +-            reversed_seq[i] = reversed_seq[i-1]
    +-            reversed_seq[i-1] = tmp
    +-        reversed_seq = tuple(reversed_seq)
    ++        reversed_seq = reverse_emoji(sequence)
    +         all_sequences.add(reversed_seq)
    +         equivalent_emoji[reversed_seq] = sequence
    + 
    +@@ -549,6 +571,7 @@ def compute_expected_emoji():
    +         set(LEGACY_ANDROID_EMOJI.keys()))
    +     default_emoji = (
    +         _emoji_properties['Emoji_Presentation'] |
    ++        ANDROID_DEFAULT_EMOJI |
    +         all_sequences |
    +         set(LEGACY_ANDROID_EMOJI.keys()))
    + 
    +diff --git a/tools/layoutlib/bridge/src/android/view/IWindowManagerImpl.java b/tools/layoutlib/bridge/src/android/view/IWindowManagerImpl.java
    +index 58df301..0c3231b 100644
    +--- a/tools/layoutlib/bridge/src/android/view/IWindowManagerImpl.java
    ++++ b/tools/layoutlib/bridge/src/android/view/IWindowManagerImpl.java
    +@@ -96,7 +96,7 @@ public class IWindowManagerImpl implements IWindowManager {
          }
      
    -     Association startAssociationLocked(int sourceUid, String sourceProcess, int sourceState,
    -@@ -19332,7 +19334,7 @@ public final class ActivityManagerService extends ActivityManagerNative
    -         int schedGroup;
    -         int procState;
    -         boolean foregroundActivities = false;
    --        BroadcastQueue queue;
    -+        final ArraySet<BroadcastQueue> queues = new ArraySet<BroadcastQueue>();
    -         if (app == TOP_APP) {
    -             // The last app on the list is the foreground app.
    -             adj = ProcessList.FOREGROUND_APP_ADJ;
    -@@ -19346,13 +19348,13 @@ public final class ActivityManagerService extends ActivityManagerNative
    -             schedGroup = ProcessList.SCHED_GROUP_DEFAULT;
    -             app.adjType = "instrumentation";
    -             procState = ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE;
    --        } else if ((queue = isReceivingBroadcast(app)) != null) {
    -+        } else if (isReceivingBroadcastLocked(app, queues)) {
    -             // An app that is currently receiving a broadcast also
    -             // counts as being in the foreground for OOM killer purposes.
    -             // It's placed in a sched group based on the nature of the
    -             // broadcast as reflected by which queue it's active in.
    -             adj = ProcessList.FOREGROUND_APP_ADJ;
    --            schedGroup = (queue == mFgBroadcastQueue)
    -+            schedGroup = (queues.contains(mFgBroadcastQueue))
    -                     ? ProcessList.SCHED_GROUP_DEFAULT : ProcessList.SCHED_GROUP_BACKGROUND;
    -             app.adjType = "broadcast";
    -             procState = ActivityManager.PROCESS_STATE_RECEIVER;
    -@@ -20363,7 +20365,7 @@ public final class ActivityManagerService extends ActivityManagerNative
    -             if (DEBUG_SWITCH || DEBUG_OOM_ADJ) Slog.v(TAG_OOM_ADJ,
    -                     "Setting sched group of " + app.processName
    -                     + " to " + app.curSchedGroup);
    --            if (app.waitingToKill != null && app.curReceiver == null
    -+            if (app.waitingToKill != null && app.curReceivers.isEmpty()
    -                     && app.setSchedGroup == ProcessList.SCHED_GROUP_BACKGROUND) {
    -                 app.kill(app.waitingToKill, true);
    -                 success = false;
    -@@ -21298,7 +21300,7 @@ public final class ActivityManagerService extends ActivityManagerNative
    -             for (i=mRemovedProcesses.size()-1; i>=0; i--) {
    -                 final ProcessRecord app = mRemovedProcesses.get(i);
    -                 if (app.activities.size() == 0
    --                        && app.curReceiver == null && app.services.size() == 0) {
    -+                        && app.curReceivers.isEmpty() && app.services.size() == 0) {
    -                     Slog.i(
    -                         TAG, "Exiting empty application process "
    -                         + app.toShortString() + " ("
    -diff --git a/services/core/java/com/android/server/am/BroadcastQueue.java b/services/core/java/com/android/server/am/BroadcastQueue.java
    -index f78f29c..1536235 100644
    ---- a/services/core/java/com/android/server/am/BroadcastQueue.java
    -+++ b/services/core/java/com/android/server/am/BroadcastQueue.java
    -@@ -265,7 +265,7 @@ public final class BroadcastQueue {
    +     @Override
    +-    public void clearForcedDisplayDensity(int displayId) throws RemoteException {
    ++    public void clearForcedDisplayDensityForUser(int displayId, int userId) throws RemoteException {
    +         // TODO Auto-generated method stub
    +     }
      
    -         r.receiver = app.thread.asBinder();
    -         r.curApp = app;
    --        app.curReceiver = r;
    -+        app.curReceivers.add(r);
    -         app.forceProcessStateUpTo(ActivityManager.PROCESS_STATE_RECEIVER);
    -         mService.updateLruProcessLocked(app, false, null);
    -         mService.updateOomAdjLocked();
    -@@ -293,7 +293,7 @@ public final class BroadcastQueue {
    -                         "Process cur broadcast " + r + ": NOT STARTED!");
    -                 r.receiver = null;
    -                 r.curApp = null;
    --                app.curReceiver = null;
    -+                app.curReceivers.remove(r);
    -             }
    -         }
    +@@ -397,7 +397,8 @@ public class IWindowManagerImpl implements IWindowManager {
          }
    -@@ -394,8 +394,8 @@ public final class BroadcastQueue {
    -         }
    -         r.receiver = null;
    -         r.intent.setComponent(null);
    --        if (r.curApp != null && r.curApp.curReceiver == r) {
    --            r.curApp.curReceiver = null;
    -+        if (r.curApp != null && r.curApp.curReceivers.contains(r)) {
    -+            r.curApp.curReceivers.remove(r);
    -         }
    -         if (r.curFilter != null) {
    -             r.curFilter.receiverList.curBroadcast = null;
    -@@ -648,7 +648,7 @@ public final class BroadcastQueue {
    -                 // things that directly call the IActivityManager API, which
    -                 // are already core system stuff so don't matter for this.
    -                 r.curApp = filter.receiverList.app;
    --                filter.receiverList.app.curReceiver = r;
    -+                filter.receiverList.app.curReceivers.add(r);
    -                 mService.updateOomAdjLocked(r.curApp);
    -             }
    + 
    +     @Override
    +-    public void setForcedDisplayDensity(int displayId, int density) throws RemoteException {
    ++    public void setForcedDisplayDensityForUser(int displayId, int density, int userId)
    ++            throws RemoteException {
    +         // TODO Auto-generated method stub
    +     }
    + 
    +@@ -459,6 +460,16 @@ public class IWindowManagerImpl implements IWindowManager {
    +     }
    + 
    +     @Override
    ++    public void setRecentsVisibility(boolean visible) {
    ++        // TODO Auto-generated method stub
    ++    }
    ++
    ++    @Override
    ++    public void setTvPipVisibility(boolean visible) {
    ++        // TODO Auto-generated method stub
    ++    }
    ++
    ++    @Override
    +     public void stopAppFreezingScreen(IBinder arg0, boolean arg1) throws RemoteException {
    +         // TODO Auto-generated method stub
    +     }
    +diff --git a/wifi/java/android/net/wifi/WifiConfiguration.java b/wifi/java/android/net/wifi/WifiConfiguration.java
    +index 9d0c20c..d3d5ea0 100644
    +--- a/wifi/java/android/net/wifi/WifiConfiguration.java
    ++++ b/wifi/java/android/net/wifi/WifiConfiguration.java
    +@@ -817,6 +817,7 @@ public class WifiConfiguration implements Parcelable {
    +          */
    +         public static final int NETWORK_SELECTION_ENABLE = 0;
    +         /**
    ++         * @deprecated it is not used any more.
    +          * This network is disabled because higher layer (>2) network is bad
    +          */
    +         public static final int DISABLED_BAD_LINK = 1;
    +@@ -862,7 +863,7 @@ public class WifiConfiguration implements Parcelable {
    +          */
    +         private static final String[] QUALITY_NETWORK_SELECTION_DISABLE_REASON = {
    +                 "NETWORK_SELECTION_ENABLE",
    +-                "NETWORK_SELECTION_DISABLED_BAD_LINK",
    ++                "NETWORK_SELECTION_DISABLED_BAD_LINK", // deprecated
    +                 "NETWORK_SELECTION_DISABLED_ASSOCIATION_REJECTION ",
    +                 "NETWORK_SELECTION_DISABLED_AUTHENTICATION_FAILURE",
    +                 "NETWORK_SELECTION_DISABLED_DHCP_FAILURE",
    +diff --git a/wifi/java/android/net/wifi/WifiManager.java b/wifi/java/android/net/wifi/WifiManager.java
    +index bbc3d2f..1633bd9c9 100644
    +--- a/wifi/java/android/net/wifi/WifiManager.java
    ++++ b/wifi/java/android/net/wifi/WifiManager.java
    +@@ -49,6 +49,8 @@ import java.util.concurrent.CountDownLatch;
    +  * This class provides the primary API for managing all aspects of Wi-Fi
    +  * connectivity. Get an instance of this class by calling
    +  * {@link android.content.Context#getSystemService(String) Context.getSystemService(Context.WIFI_SERVICE)}.
    ++ * On releases before NYC, it should only be obtained from an application context, and not from
    ++ * any other derived context to avoid memory leaks within the calling process.
    + 
    +  * It deals with several categories of items:
    +  * <ul>
    +diff --git a/wifi/java/android/net/wifi/WifiScanner.java b/wifi/java/android/net/wifi/WifiScanner.java
    +index 716f1d3..3190ead 100644
    +--- a/wifi/java/android/net/wifi/WifiScanner.java
    ++++ b/wifi/java/android/net/wifi/WifiScanner.java
    +@@ -286,6 +286,12 @@ public class WifiScanner {
    +          * {@hide}
    +          */
    +         private int mBucketsScanned;
    ++        /**
    ++         * Indicates that the scan results received are as a result of a scan of all available
    ++         * channels. This should only be expected to function for single scans.
    ++         * {@hide}
    ++         */
    ++        private boolean mAllChannelsScanned;
    +         /** all scan results discovered in this scan, sorted by timestamp in ascending order */
    +         private ScanResult mResults[];
    + 
    +@@ -298,10 +304,12 @@ public class WifiScanner {
              }
    -@@ -676,7 +676,7 @@ public final class BroadcastQueue {
    -                 r.curFilter = null;
    -                 filter.receiverList.curBroadcast = null;
    -                 if (filter.receiverList.app != null) {
    --                    filter.receiverList.app.curReceiver = null;
    -+                    filter.receiverList.app.curReceivers.remove(r);
    -                 }
    -             }
    + 
    +         /** {@hide} */
    +-        public ScanData(int id, int flags, int bucketsScanned, ScanResult[] results) {
    ++        public ScanData(int id, int flags, int bucketsScanned, boolean allChannelsScanned,
    ++                ScanResult[] results) {
    +             mId = id;
    +             mFlags = flags;
    +             mBucketsScanned = bucketsScanned;
    ++            mAllChannelsScanned = allChannelsScanned;
    +             mResults = results;
              }
    -diff --git a/services/core/java/com/android/server/am/ProcessRecord.java b/services/core/java/com/android/server/am/ProcessRecord.java
    -index 3fffefb..49fe79c 100644
    ---- a/services/core/java/com/android/server/am/ProcessRecord.java
    -+++ b/services/core/java/com/android/server/am/ProcessRecord.java
    -@@ -143,7 +143,7 @@ final class ProcessRecord {
    -     Bundle instrumentationArguments;// as given to us
    -     ComponentName instrumentationResultClass;// copy of instrumentationClass
    -     boolean usingWrapper;       // Set to true when process was launched with a wrapper attached
    --    BroadcastRecord curReceiver;// receiver currently running in the app
    -+    final ArraySet<BroadcastRecord> curReceivers = new ArraySet<BroadcastRecord>();// receivers currently running in the app
    -     long lastWakeTime;          // How long proc held wake lock at last check
    -     long lastCpuTime;           // How long proc has run CPU at last check
    -     long curCpuTime;            // How long proc has run CPU most recently
    -@@ -427,8 +427,11 @@ final class ProcessRecord {
    -                 pw.print(prefix); pw.print("  - "); pw.println(conProviders.get(i).toShortString());
    -             }
    + 
    +@@ -309,6 +317,7 @@ public class WifiScanner {
    +             mId = s.mId;
    +             mFlags = s.mFlags;
    +             mBucketsScanned = s.mBucketsScanned;
    ++            mAllChannelsScanned = s.mAllChannelsScanned;
    +             mResults = new ScanResult[s.mResults.length];
    +             for (int i = 0; i < s.mResults.length; i++) {
    +                 ScanResult result = s.mResults[i];
    +@@ -330,6 +339,11 @@ public class WifiScanner {
    +             return mBucketsScanned;
              }
    --        if (curReceiver != null) {
    --            pw.print(prefix); pw.print("curReceiver="); pw.println(curReceiver);
    -+        if (!curReceivers.isEmpty()) {
    -+            pw.print(prefix); pw.println("Current Receivers:");
    -+            for (int i=0; i < curReceivers.size(); i++) {
    -+                pw.print(prefix); pw.print("  - "); pw.println(curReceivers.valueAt(i));
    -+            }
    + 
    ++        /** {@hide} */
    ++        public boolean isAllChannelsScanned() {
    ++            return mAllChannelsScanned;
    ++        }
    ++
    +         public ScanResult[] getResults() {
    +             return mResults;
              }
    -         if (receivers.size() > 0) {
    -             pw.print(prefix); pw.println("Receivers:");
    +@@ -345,6 +359,7 @@ public class WifiScanner {
    +                 dest.writeInt(mId);
    +                 dest.writeInt(mFlags);
    +                 dest.writeInt(mBucketsScanned);
    ++                dest.writeInt(mAllChannelsScanned ? 1 : 0);
    +                 dest.writeInt(mResults.length);
    +                 for (int i = 0; i < mResults.length; i++) {
    +                     ScanResult result = mResults[i];
    +@@ -362,12 +377,13 @@ public class WifiScanner {
    +                         int id = in.readInt();
    +                         int flags = in.readInt();
    +                         int bucketsScanned = in.readInt();
    ++                        boolean allChannelsScanned = in.readInt() != 0;
    +                         int n = in.readInt();
    +                         ScanResult results[] = new ScanResult[n];
    +                         for (int i = 0; i < n; i++) {
    +                             results[i] = ScanResult.CREATOR.createFromParcel(in);
    +                         }
    +-                        return new ScanData(id, flags, bucketsScanned, results);
    ++                        return new ScanData(id, flags, bucketsScanned, allChannelsScanned, results);
    +                     }
    + 
    +                     public ScanData[] newArray(int size) {
    diff --git a/frameworks_native.patch b/frameworks_native.patch
    index e73225c..d35a429 100644
    --- a/frameworks_native.patch
    +++ b/frameworks_native.patch
    @@ -1,8 +1,16 @@
     diff --git a/cmds/atrace/atrace.cpp b/cmds/atrace/atrace.cpp
    -index facf300..10f4d6e 100644
    +index facf300..86c315c 100644
     --- a/cmds/atrace/atrace.cpp
     +++ b/cmds/atrace/atrace.cpp
    -@@ -593,16 +593,30 @@ static bool verifyKernelTraceFuncs(const char* funcs)
    +@@ -102,6 +102,7 @@ static const TracingCategory k_categories[] = {
    +     { "pm",         "Package Manager",  ATRACE_TAG_PACKAGE_MANAGER, { } },
    +     { "ss",         "System Server",    ATRACE_TAG_SYSTEM_SERVER, { } },
    +     { "database",   "Database",         ATRACE_TAG_DATABASE, { } },
    ++    { "network",    "Network",          ATRACE_TAG_NETWORK, { } },
    +     { k_coreServiceCategory, "Core services", 0, { } },
    +     { "sched",      "CPU Scheduling",   0, {
    +         { REQ,      "/sys/kernel/debug/tracing/events/sched/sched_switch/enable" },
    +@@ -593,16 +594,30 @@ static bool verifyKernelTraceFuncs(const char* funcs)
              return false;
          }
      
    @@ -41,7 +49,7 @@ index facf300..10f4d6e 100644
          String8 funcList = String8::format("\n%s", buf);
      
          // Make sure that every function listed in funcs is in the list we just
    -@@ -622,8 +636,8 @@ static bool verifyKernelTraceFuncs(const char* funcs)
    +@@ -622,8 +637,8 @@ static bool verifyKernelTraceFuncs(const char* funcs)
              }
              func = strtok(NULL, ",");
          }
    @@ -51,6 +59,429 @@ index facf300..10f4d6e 100644
          return ok;
      }
      
    +diff --git a/cmds/atrace/atrace.rc b/cmds/atrace/atrace.rc
    +index c2f8891..e3cc9da 100644
    +--- a/cmds/atrace/atrace.rc
    ++++ b/cmds/atrace/atrace.rc
    +@@ -1,6 +1,6 @@
    + ## Permissions to allow system-wide tracing to the kernel trace buffer.
    + ##
    +-on boot
    ++on fs
    + 
    + # Allow writing to the kernel trace log.
    +     chmod 0222 /sys/kernel/debug/tracing/trace_marker
    +diff --git a/cmds/dumpstate/dumpstate.cpp b/cmds/dumpstate/dumpstate.cpp
    +index e9f9e57..9321a00 100644
    +--- a/cmds/dumpstate/dumpstate.cpp
    ++++ b/cmds/dumpstate/dumpstate.cpp
    +@@ -149,7 +149,7 @@ void do_mountinfo(int pid, const char *name) {
    + }
    + 
    + void add_mountinfo() {
    +-    if (!zip_writer) return;
    ++    if (!is_zipping()) return;
    +     const char *title = "MOUNT INFO";
    +     mount_points.clear();
    +     DurationReporter duration_reporter(title, NULL);
    +@@ -180,8 +180,8 @@ static void dump_dev_files(const char *title, const char *driverpath, const char
    + }
    + 
    + static void dump_systrace() {
    +-    if (!zip_writer) {
    +-        MYLOGD("Not dumping systrace because zip_writer is not set\n");
    ++    if (!is_zipping()) {
    ++        MYLOGD("Not dumping systrace because dumpstate is not zipping\n");
    +         return;
    +     }
    +     std::string systrace_path = bugreport_dir + "/systrace-" + suffix + ".txt";
    +@@ -237,7 +237,7 @@ static void dump_raft() {
    +         return;
    +     }
    + 
    +-    if (!zip_writer) {
    ++    if (!is_zipping()) {
    +         // Write compressed and encoded raft logs to stdout if not zip_writer.
    +         run_command("RAFT LOGS", 600, "logcompressor", "-r", RAFT_DIR, NULL);
    +         return;
    +@@ -575,8 +575,8 @@ static const std::set<std::string> PROBLEMATIC_FILE_EXTENSIONS = {
    + };
    + 
    + bool add_zip_entry_from_fd(const std::string& entry_name, int fd) {
    +-    if (!zip_writer) {
    +-        MYLOGD("Not adding zip entry %s from fd because zip_writer is not set\n",
    ++    if (!is_zipping()) {
    ++        MYLOGD("Not adding entry %s from fd because dumpstate is not zipping\n",
    +                 entry_name.c_str());
    +         return false;
    +     }
    +@@ -645,8 +645,8 @@ static int _add_file_from_fd(const char *title, const char *path, int fd) {
    + 
    + // TODO: move to util.cpp
    + void add_dir(const char *dir, bool recursive) {
    +-    if (!zip_writer) {
    +-        MYLOGD("Not adding dir %s because zip_writer is not set\n", dir);
    ++    if (!is_zipping()) {
    ++        MYLOGD("Not adding dir %s because dumpstate is not zipping\n", dir);
    +         return;
    +     }
    +     MYLOGD("Adding dir %s (recursive: %d)\n", dir, recursive);
    +@@ -654,10 +654,14 @@ void add_dir(const char *dir, bool recursive) {
    +     dump_files(NULL, dir, recursive ? skip_none : is_dir, _add_file_from_fd);
    + }
    + 
    ++bool is_zipping() {
    ++    return zip_writer != nullptr;
    ++}
    ++
    + /* adds a text entry entry to the existing zip file. */
    + static bool add_text_zip_entry(const std::string& entry_name, const std::string& content) {
    +-    if (!zip_writer) {
    +-        MYLOGD("Not adding text zip entry %s because zip_writer is not set\n", entry_name.c_str());
    ++    if (!is_zipping()) {
    ++        MYLOGD("Not adding text entry %s because dumpstate is not zipping\n", entry_name.c_str());
    +         return false;
    +     }
    +     MYLOGD("Adding zip text entry %s\n", entry_name.c_str());
    +@@ -687,10 +691,12 @@ static bool add_text_zip_entry(const std::string& entry_name, const std::string&
    + static void dump_iptables() {
    +     run_command("IPTABLES", 10, "iptables", "-L", "-nvx", NULL);
    +     run_command("IP6TABLES", 10, "ip6tables", "-L", "-nvx", NULL);
    +-    run_command("IPTABLE NAT", 10, "iptables", "-t", "nat", "-L", "-nvx", NULL);
    ++    run_command("IPTABLES NAT", 10, "iptables", "-t", "nat", "-L", "-nvx", NULL);
    +     /* no ip6 nat */
    +-    run_command("IPTABLE RAW", 10, "iptables", "-t", "raw", "-L", "-nvx", NULL);
    +-    run_command("IP6TABLE RAW", 10, "ip6tables", "-t", "raw", "-L", "-nvx", NULL);
    ++    run_command("IPTABLES MANGLE", 10, "iptables", "-t", "mangle", "-L", "-nvx", NULL);
    ++    run_command("IP6TABLES MANGLE", 10, "ip6tables", "-t", "mangle", "-L", "-nvx", NULL);
    ++    run_command("IPTABLES RAW", 10, "iptables", "-t", "raw", "-L", "-nvx", NULL);
    ++    run_command("IP6TABLES RAW", 10, "ip6tables", "-t", "raw", "-L", "-nvx", NULL);
    + }
    + 
    + static void dumpstate(const std::string& screenshot_path, const std::string& version) {
    +@@ -1371,6 +1377,12 @@ int main(int argc, char *argv[]) {
    +     add_mountinfo();
    +     dump_iptables();
    + 
    ++    // Capture any IPSec policies in play.  No keys are exposed here.
    ++    run_command("IP XFRM POLICY", 10, "ip", "xfrm", "policy", nullptr);
    ++
    ++    // Run ss as root so we can see socket marks.
    ++    run_command("DETAILED SOCKET STATE", 10, "ss", "-eionptu", NULL);
    ++
    +     if (!drop_root_user()) {
    +         return -1;
    +     }
    +diff --git a/cmds/dumpstate/dumpstate.h b/cmds/dumpstate/dumpstate.h
    +index 5e083cc..514af59 100644
    +--- a/cmds/dumpstate/dumpstate.h
    ++++ b/cmds/dumpstate/dumpstate.h
    +@@ -87,6 +87,9 @@ extern std::string bugreport_dir;
    + /* root dir for all files copied as-is into the bugreport. */
    + extern const std::string ZIP_ROOT_DIR;
    + 
    ++/* Checkes whether dumpstate is generating a zipped bugreport. */
    ++bool is_zipping();
    ++
    + /* adds a new entry to the existing zip file. */
    + bool add_zip_entry(const std::string& entry_name, const std::string& entry_path);
    + 
    +diff --git a/cmds/installd/commands.cpp b/cmds/installd/commands.cpp
    +index 2014e99..271c75b 100644
    +--- a/cmds/installd/commands.cpp
    ++++ b/cmds/installd/commands.cpp
    +@@ -99,23 +99,69 @@ static std::string create_primary_profile(const std::string& profile_dir) {
    +     return StringPrintf("%s/%s", profile_dir.c_str(), PRIMARY_PROFILE_NAME);
    + }
    + 
    +-static int prepare_app_dir(const std::string& path, mode_t target_mode, uid_t uid,
    +-        const char* pkgname, const char* seinfo) {
    ++/**
    ++ * Perform restorecon of the given path, but only perform recursive restorecon
    ++ * if the label of that top-level file actually changed.  This can save us
    ++ * significant time by avoiding no-op traversals of large filesystem trees.
    ++ */
    ++static int restorecon_app_data_lazy(const std::string& path, const char* seinfo, uid_t uid) {
    ++    int res = 0;
    ++    char* before = nullptr;
    ++    char* after = nullptr;
    ++
    ++    // Note that SELINUX_ANDROID_RESTORECON_DATADATA flag is set by
    ++    // libselinux. Not needed here.
    ++
    ++    if (lgetfilecon(path.c_str(), &before) < 0) {
    ++        PLOG(ERROR) << "Failed before getfilecon for " << path;
    ++        goto fail;
    ++    }
    ++    if (selinux_android_restorecon_pkgdir(path.c_str(), seinfo, uid, 0) < 0) {
    ++        PLOG(ERROR) << "Failed top-level restorecon for " << path;
    ++        goto fail;
    ++    }
    ++    if (lgetfilecon(path.c_str(), &after) < 0) {
    ++        PLOG(ERROR) << "Failed after getfilecon for " << path;
    ++        goto fail;
    ++    }
    ++
    ++    // If the initial top-level restorecon above changed the label, then go
    ++    // back and restorecon everything recursively
    ++    if (strcmp(before, after)) {
    ++        LOG(DEBUG) << "Detected label change from " << before << " to " << after << " at " << path
    ++                << "; running recursive restorecon";
    ++        if (selinux_android_restorecon_pkgdir(path.c_str(), seinfo, uid,
    ++                SELINUX_ANDROID_RESTORECON_RECURSE) < 0) {
    ++            PLOG(ERROR) << "Failed recursive restorecon for " << path;
    ++            goto fail;
    ++        }
    ++    }
    ++
    ++    goto done;
    ++fail:
    ++    res = -1;
    ++done:
    ++    free(before);
    ++    free(after);
    ++    return res;
    ++}
    ++
    ++static int restorecon_app_data_lazy(const std::string& parent, const char* name, const char* seinfo,
    ++        uid_t uid) {
    ++    return restorecon_app_data_lazy(StringPrintf("%s/%s", parent.c_str(), name), seinfo, uid);
    ++}
    ++
    ++static int prepare_app_dir(const std::string& path, mode_t target_mode, uid_t uid) {
    +     if (fs_prepare_dir_strict(path.c_str(), target_mode, uid, uid) != 0) {
    +         PLOG(ERROR) << "Failed to prepare " << path;
    +         return -1;
    +     }
    +-    if (selinux_android_setfilecon(path.c_str(), pkgname, seinfo, uid) < 0) {
    +-        PLOG(ERROR) << "Failed to setfilecon " << path;
    +-        return -1;
    +-    }
    +     return 0;
    + }
    + 
    + static int prepare_app_dir(const std::string& parent, const char* name, mode_t target_mode,
    +-        uid_t uid, const char* pkgname, const char* seinfo) {
    +-    return prepare_app_dir(StringPrintf("%s/%s", parent.c_str(), name), target_mode, uid, pkgname,
    +-            seinfo);
    ++        uid_t uid) {
    ++    return prepare_app_dir(StringPrintf("%s/%s", parent.c_str(), name), target_mode, uid);
    + }
    + 
    + int create_app_data(const char *uuid, const char *pkgname, userid_t userid, int flags,
    +@@ -124,9 +170,16 @@ int create_app_data(const char *uuid, const char *pkgname, userid_t userid, int
    +     mode_t target_mode = target_sdk_version >= MIN_RESTRICTED_HOME_SDK_VERSION ? 0700 : 0751;
    +     if (flags & FLAG_STORAGE_CE) {
    +         auto path = create_data_user_ce_package_path(uuid, userid, pkgname);
    +-        if (prepare_app_dir(path, target_mode, uid, pkgname, seinfo) ||
    +-                prepare_app_dir(path, "cache", 0771, uid, pkgname, seinfo) ||
    +-                prepare_app_dir(path, "code_cache", 0771, uid, pkgname, seinfo)) {
    ++        if (prepare_app_dir(path, target_mode, uid) ||
    ++                prepare_app_dir(path, "cache", 0771, uid) ||
    ++                prepare_app_dir(path, "code_cache", 0771, uid)) {
    ++            return -1;
    ++        }
    ++
    ++        // Consider restorecon over contents if label changed
    ++        if (restorecon_app_data_lazy(path, seinfo, uid) ||
    ++                restorecon_app_data_lazy(path, "cache", seinfo, uid) ||
    ++                restorecon_app_data_lazy(path, "code_cache", seinfo, uid)) {
    +             return -1;
    +         }
    + 
    +@@ -139,11 +192,16 @@ int create_app_data(const char *uuid, const char *pkgname, userid_t userid, int
    +     }
    +     if (flags & FLAG_STORAGE_DE) {
    +         auto path = create_data_user_de_package_path(uuid, userid, pkgname);
    +-        if (prepare_app_dir(path, target_mode, uid, pkgname, seinfo)) {
    ++        if (prepare_app_dir(path, target_mode, uid)) {
    +             // TODO: include result once 25796509 is fixed
    +             return 0;
    +         }
    + 
    ++        // Consider restorecon over contents if label changed
    ++        if (restorecon_app_data_lazy(path, seinfo, uid)) {
    ++            return -1;
    ++        }
    ++
    +         if (property_get_bool("dalvik.vm.usejitprofiles")) {
    +             const std::string profile_path = create_data_user_profile_package_path(userid, pkgname);
    +             // read-write-execute only for the app user.
    +@@ -2186,6 +2244,9 @@ int move_ab(const char* apk_path, const char* instruction_set, const char* oat_d
    +         bool art_success = true;
    +         if (!a_image_path.empty()) {
    +             art_success = move_ab_path(b_image_path, a_image_path);
    ++            if (!art_success) {
    ++                unlink(a_image_path.c_str());
    ++            }
    +         }
    + 
    +         success = art_success || kIgnoreAppImageFailure;
    +@@ -2199,5 +2260,35 @@ int move_ab(const char* apk_path, const char* instruction_set, const char* oat_d
    +     return success ? 0 : -1;
    + }
    + 
    ++bool delete_odex(const char *apk_path, const char *instruction_set, const char *oat_dir) {
    ++    // Delete the oat/odex file.
    ++    char out_path[PKG_PATH_MAX];
    ++    if (!create_oat_out_path(apk_path, instruction_set, oat_dir, out_path)) {
    ++        return false;
    ++    }
    ++
    ++    // In case of a permission failure report the issue. Otherwise just print a warning.
    ++    auto unlink_and_check = [](const char* path) -> bool {
    ++        int result = unlink(path);
    ++        if (result != 0) {
    ++            if (errno == EACCES || errno == EPERM) {
    ++                PLOG(ERROR) << "Could not unlink " << path;
    ++                return false;
    ++            }
    ++            PLOG(WARNING) << "Could not unlink " << path;
    ++        }
    ++        return true;
    ++    };
    ++
    ++    // Delete the oat/odex file.
    ++    bool return_value_oat = unlink_and_check(out_path);
    ++
    ++    // Derive and delete the app image.
    ++    bool return_value_art = unlink_and_check(create_image_filename(out_path).c_str());
    ++
    ++    // Report success.
    ++    return return_value_oat && return_value_art;
    ++}
    ++
    + }  // namespace installd
    + }  // namespace android
    +diff --git a/cmds/installd/commands.h b/cmds/installd/commands.h
    +index e990f1b..ba27517 100644
    +--- a/cmds/installd/commands.h
    ++++ b/cmds/installd/commands.h
    +@@ -85,6 +85,9 @@ int link_file(const char *relative_path, const char *from_base, const char *to_b
    + // Move a B version over to the A location. Only works for oat_dir != nullptr.
    + int move_ab(const char *apk_path, const char *instruction_set, const char* oat_dir);
    + 
    ++// Delete odex files generated by dexopt.
    ++bool delete_odex(const char *apk_path, const char *instruction_set, const char *oat_dir);
    ++
    + }  // namespace installd
    + }  // namespace android
    + 
    +diff --git a/cmds/installd/installd.cpp b/cmds/installd/installd.cpp
    +index facbc72..8f883db 100644
    +--- a/cmds/installd/installd.cpp
    ++++ b/cmds/installd/installd.cpp
    +@@ -418,6 +418,11 @@ static int do_move_ab(char **arg, char reply[REPLY_MAX] ATTRIBUTE_UNUSED) {
    +     return move_ab(arg[0], arg[1], arg[2]);
    + }
    + 
    ++static int do_delete_odex(char **arg, char reply[REPLY_MAX] ATTRIBUTE_UNUSED) {
    ++    // apk_path, instruction_set, oat_dir
    ++    return delete_odex(arg[0], arg[1], arg[2]) ? 0 : -1;
    ++}
    ++
    + struct cmdinfo {
    +     const char *name;
    +     unsigned numargs;
    +@@ -453,6 +458,7 @@ struct cmdinfo cmds[] = {
    +     { "move_ab",              3, do_move_ab },
    +     { "merge_profiles",       2, do_merge_profiles },
    +     { "dump_profiles",        3, do_dump_profiles },
    ++    { "delete_odex",          3, do_delete_odex },
    + };
    + 
    + static int readx(int s, void *_buf, int count)
    +diff --git a/data/etc/handheld_core_hardware.xml b/data/etc/handheld_core_hardware.xml
    +index 9cb4d6d..f9464e8 100644
    +--- a/data/etc/handheld_core_hardware.xml
    ++++ b/data/etc/handheld_core_hardware.xml
    +@@ -50,8 +50,8 @@
    +     <!-- Feature to specify if the device support managed users. -->
    +     <feature name="android.software.managed_users" />
    + 
    +-    <!-- Feature to specify if the device supports a VR mode. -->
    +-    <feature name="android.software.vr.mode" />
    ++    <!-- Feature to specify if the device supports a VR mode.
    ++         feature name="android.software.vr.mode" -->
    +     <!-- Devices with all optimizations required to be a "VR Ready" device that
    +          pass all CTS tests for this feature must include feature
    +          android.hardware.vr.high_performance -->
    +diff --git a/include/gui/BufferQueueCore.h b/include/gui/BufferQueueCore.h
    +index 82bc121..cc5c536 100644
    +--- a/include/gui/BufferQueueCore.h
    ++++ b/include/gui/BufferQueueCore.h
    +@@ -182,6 +182,8 @@ private:
    +     // to this BufferQueue. It defaults to NO_CONNECTED_API, and gets updated
    +     // by the connect and disconnect methods.
    +     int mConnectedApi;
    ++    // PID of the process which last successfully called connect(...)
    ++    pid_t mConnectedPid;
    + 
    +     // mConnectedProducerToken is used to set a binder death notification on
    +     // the producer.
    +diff --git a/include/gui/BufferQueueProducer.h b/include/gui/BufferQueueProducer.h
    +index 838632c..8f613ee 100644
    +--- a/include/gui/BufferQueueProducer.h
    ++++ b/include/gui/BufferQueueProducer.h
    +@@ -135,15 +135,8 @@ public:
    +     virtual status_t connect(const sp<IProducerListener>& listener,
    +             int api, bool producerControlledByApp, QueueBufferOutput* output);
    + 
    +-    // disconnect attempts to disconnect a producer API from the BufferQueue.
    +-    // Calling this method will cause any subsequent calls to other
    +-    // IGraphicBufferProducer methods to fail except for getAllocator and connect.
    +-    // Successfully calling connect after this will allow the other methods to
    +-    // succeed again.
    +-    //
    +-    // This method will fail if the the BufferQueue is not currently
    +-    // connected to the specified producer API.
    +-    virtual status_t disconnect(int api);
    ++    // See IGraphicBufferProducer::disconnect
    ++    virtual status_t disconnect(int api, DisconnectMode mode = DisconnectMode::Api);
    + 
    +     // Attaches a sideband buffer stream to the IGraphicBufferProducer.
    +     //
    +diff --git a/include/gui/IGraphicBufferProducer.h b/include/gui/IGraphicBufferProducer.h
    +index c62bc58..bf427fe 100644
    +--- a/include/gui/IGraphicBufferProducer.h
    ++++ b/include/gui/IGraphicBufferProducer.h
    +@@ -458,17 +458,24 @@ public:
    +     virtual status_t connect(const sp<IProducerListener>& listener,
    +             int api, bool producerControlledByApp, QueueBufferOutput* output) = 0;
    + 
    ++    enum class DisconnectMode {
    ++        // Disconnect only the specified API.
    ++        Api,
    ++        // Disconnect any API originally connected from the process calling disconnect.
    ++        AllLocal
    ++    };
    ++
    +     // disconnect attempts to disconnect a client API from the
    +     // IGraphicBufferProducer.  Calling this method will cause any subsequent
    +     // calls to other IGraphicBufferProducer methods to fail except for
    +     // getAllocator and connect.  Successfully calling connect after this will
    +     // allow the other methods to succeed again.
    +     //
    +-    // This method will fail if the the IGraphicBufferProducer is not currently
    +-    // connected to the specified client API.
    +-    //
    +     // The api should be one of the NATIVE_WINDOW_API_* values in <window.h>
    +     //
    ++    // Alternatively if mode is AllLocal, then the API value is ignored, and any API
    ++    // connected from the same PID calling disconnect will be disconnected.
    ++    //
    +     // Disconnecting from an abandoned IGraphicBufferProducer is legal and
    +     // is considered a no-op.
    +     //
    +@@ -477,7 +484,7 @@ public:
    +     //             * the api specified does not match the one that was connected
    +     //             * api was out of range (see above).
    +     // * DEAD_OBJECT - the token is hosted by an already-dead process
    +-    virtual status_t disconnect(int api) = 0;
    ++    virtual status_t disconnect(int api, DisconnectMode mode = DisconnectMode::Api) = 0;
    + 
    +     // Attaches a sideband buffer stream to the IGraphicBufferProducer.
    +     //
     diff --git a/include/gui/ISurfaceComposer.h b/include/gui/ISurfaceComposer.h
     index 74a4123..8dc6f6a 100644
     --- a/include/gui/ISurfaceComposer.h
    @@ -78,6 +509,44 @@ index 74a4123..8dc6f6a 100644
      
          /* Clears the frame statistics for animations.
           *
    +diff --git a/include/gui/Surface.h b/include/gui/Surface.h
    +index 8177ec6..f4a22cb 100644
    +--- a/include/gui/Surface.h
    ++++ b/include/gui/Surface.h
    +@@ -203,7 +203,6 @@ protected:
    +     virtual int lockBuffer_DEPRECATED(ANativeWindowBuffer* buffer);
    + 
    +     virtual int connect(int api);
    +-    virtual int disconnect(int api);
    +     virtual int setBufferCount(int bufferCount);
    +     virtual int setBuffersDimensions(uint32_t width, uint32_t height);
    +     virtual int setBuffersUserDimensions(uint32_t width, uint32_t height);
    +@@ -217,6 +216,10 @@ protected:
    +     virtual void setSurfaceDamage(android_native_rect_t* rects, size_t numRects);
    + 
    + public:
    ++    virtual int disconnect(int api,
    ++            IGraphicBufferProducer::DisconnectMode mode =
    ++                    IGraphicBufferProducer::DisconnectMode::Api);
    ++
    +     virtual int setMaxDequeuedBufferCount(int maxDequeuedBuffers);
    +     virtual int setAsyncMode(bool async);
    +     virtual int setSharedBufferMode(bool sharedBufferMode);
    +diff --git a/include/gui/SurfaceComposerClient.h b/include/gui/SurfaceComposerClient.h
    +index b8ee331..c4f88b6 100644
    +--- a/include/gui/SurfaceComposerClient.h
    ++++ b/include/gui/SurfaceComposerClient.h
    +@@ -166,8 +166,8 @@ public:
    +     static status_t getHdrCapabilities(const sp<IBinder>& display,
    +             HdrCapabilities* outCapabilities);
    + 
    +-    static void setDisplaySurface(const sp<IBinder>& token,
    +-            const sp<IGraphicBufferProducer>& bufferProducer);
    ++    static status_t setDisplaySurface(const sp<IBinder>& token,
    ++            sp<IGraphicBufferProducer> bufferProducer);
    +     static void setDisplayLayerStack(const sp<IBinder>& token,
    +             uint32_t layerStack);
    +     static void setDisplaySize(const sp<IBinder>& token, uint32_t width, uint32_t height);
     diff --git a/libs/binder/IPCThreadState.cpp b/libs/binder/IPCThreadState.cpp
     index d90798f..9b5f0d7 100644
     --- a/libs/binder/IPCThreadState.cpp
    @@ -122,6 +591,86 @@ index 46feb1c..1b4a9c5 100644
      
      LOCAL_MODULE := libgui
      
    +diff --git a/libs/gui/BufferQueueProducer.cpp b/libs/gui/BufferQueueProducer.cpp
    +index 47ab6f2..48b1db8 100644
    +--- a/libs/gui/BufferQueueProducer.cpp
    ++++ b/libs/gui/BufferQueueProducer.cpp
    +@@ -28,6 +28,7 @@
    + 
    + #define EGL_EGLEXT_PROTOTYPES
    + 
    ++#include <binder/IPCThreadState.h>
    + #include <gui/BufferItem.h>
    + #include <gui/BufferQueueCore.h>
    + #include <gui/BufferQueueProducer.h>
    +@@ -1130,7 +1131,7 @@ status_t BufferQueueProducer::connect(const sp<IProducerListener>& listener,
    +             status = BAD_VALUE;
    +             break;
    +     }
    +-
    ++    mCore->mConnectedPid = IPCThreadState::self()->getCallingPid();
    +     mCore->mBufferHasBeenQueued = false;
    +     mCore->mDequeueBufferCannotBlock = false;
    +     if (mDequeueTimeout < 0) {
    +@@ -1143,7 +1144,7 @@ status_t BufferQueueProducer::connect(const sp<IProducerListener>& listener,
    +     return status;
    + }
    + 
    +-status_t BufferQueueProducer::disconnect(int api) {
    ++status_t BufferQueueProducer::disconnect(int api, DisconnectMode mode) {
    +     ATRACE_CALL();
    +     BQ_LOGV("disconnect: api %d", api);
    + 
    +@@ -1151,6 +1152,14 @@ status_t BufferQueueProducer::disconnect(int api) {
    +     sp<IConsumerListener> listener;
    +     { // Autolock scope
    +         Mutex::Autolock lock(mCore->mMutex);
    ++
    ++        if (mode == DisconnectMode::AllLocal) {
    ++            if (IPCThreadState::self()->getCallingPid() != mCore->mConnectedPid) {
    ++                return NO_ERROR;
    ++            }
    ++            api = BufferQueueCore::CURRENTLY_CONNECTED_API;
    ++        }
    ++
    +         mCore->waitWhileAllocatingLocked();
    + 
    +         if (mCore->mIsAbandoned) {
    +@@ -1189,6 +1198,7 @@ status_t BufferQueueProducer::disconnect(int api) {
    +                             BufferQueueCore::INVALID_BUFFER_SLOT;
    +                     mCore->mConnectedProducerListener = NULL;
    +                     mCore->mConnectedApi = BufferQueueCore::NO_CONNECTED_API;
    ++                    mCore->mConnectedPid = -1;
    +                     mCore->mSidebandStream.clear();
    +                     mCore->mDequeueCondition.broadcast();
    +                     listener = mCore->mConsumerListener;
    +diff --git a/libs/gui/IGraphicBufferProducer.cpp b/libs/gui/IGraphicBufferProducer.cpp
    +index fbd704d..f4ba3bf 100644
    +--- a/libs/gui/IGraphicBufferProducer.cpp
    ++++ b/libs/gui/IGraphicBufferProducer.cpp
    +@@ -270,10 +270,11 @@ public:
    +         return result;
    +     }
    + 
    +-    virtual status_t disconnect(int api) {
    ++    virtual status_t disconnect(int api, DisconnectMode mode) {
    +         Parcel data, reply;
    +         data.writeInterfaceToken(IGraphicBufferProducer::getInterfaceDescriptor());
    +         data.writeInt32(api);
    ++        data.writeInt32(static_cast<int32_t>(mode));
    +         status_t result =remote()->transact(DISCONNECT, data, &reply);
    +         if (result != NO_ERROR) {
    +             return result;
    +@@ -621,7 +622,8 @@ status_t BnGraphicBufferProducer::onTransact(
    +         case DISCONNECT: {
    +             CHECK_INTERFACE(IGraphicBufferProducer, data, reply);
    +             int api = data.readInt32();
    +-            status_t res = disconnect(api);
    ++            DisconnectMode mode = static_cast<DisconnectMode>(data.readInt32());
    ++            status_t res = disconnect(api, mode);
    +             reply->writeInt32(res);
    +             return NO_ERROR;
    +         }
     diff --git a/libs/gui/ISurfaceComposer.cpp b/libs/gui/ISurfaceComposer.cpp
     index f0b0ada..3577a33 100644
     --- a/libs/gui/ISurfaceComposer.cpp
    @@ -159,6 +708,152 @@ index f0b0ada..3577a33 100644
                  reply->writeInt32(res);
                  return NO_ERROR;
              }
    +diff --git a/libs/gui/Surface.cpp b/libs/gui/Surface.cpp
    +index dbf8114..0838290 100644
    +--- a/libs/gui/Surface.cpp
    ++++ b/libs/gui/Surface.cpp
    +@@ -844,14 +844,14 @@ int Surface::connect(int api, const sp<IProducerListener>& listener) {
    + }
    + 
    + 
    +-int Surface::disconnect(int api) {
    ++int Surface::disconnect(int api, IGraphicBufferProducer::DisconnectMode mode) {
    +     ATRACE_CALL();
    +     ALOGV("Surface::disconnect");
    +     Mutex::Autolock lock(mMutex);
    +     mSharedBufferSlot = BufferItem::INVALID_BUFFER_SLOT;
    +     mSharedBufferHasBeenQueued = false;
    +     freeAllBuffers();
    +-    int err = mGraphicBufferProducer->disconnect(api);
    ++    int err = mGraphicBufferProducer->disconnect(api, mode);
    +     if (!err) {
    +         mReqFormat = 0;
    +         mReqWidth = 0;
    +@@ -1364,12 +1364,18 @@ status_t Surface::writeToParcel(Parcel* parcel, bool nameAlreadyWritten) const {
    + 
    +     status_t res = OK;
    + 
    +-    if (!nameAlreadyWritten) res = parcel->writeString16(name);
    ++    if (!nameAlreadyWritten) {
    ++        res = parcel->writeString16(name);
    ++        if (res != OK) return res;
    + 
    +-    if (res == OK) {
    +-        res = parcel->writeStrongBinder(
    +-                IGraphicBufferProducer::asBinder(graphicBufferProducer));
    ++        /* isSingleBuffered defaults to no */
    ++        res = parcel->writeInt32(0);
    ++        if (res != OK) return res;
    +     }
    ++
    ++    res = parcel->writeStrongBinder(
    ++            IGraphicBufferProducer::asBinder(graphicBufferProducer));
    ++
    +     return res;
    + }
    + 
    +@@ -1380,13 +1386,20 @@ status_t Surface::readFromParcel(const Parcel* parcel) {
    + status_t Surface::readFromParcel(const Parcel* parcel, bool nameAlreadyRead) {
    +     if (parcel == nullptr) return BAD_VALUE;
    + 
    ++    status_t res = OK;
    +     if (!nameAlreadyRead) {
    +         name = readMaybeEmptyString16(parcel);
    ++        // Discard this for now
    ++        int isSingleBuffered;
    ++        res = parcel->readInt32(&isSingleBuffered);
    ++        if (res != OK) {
    ++            return res;
    ++        }
    +     }
    + 
    +     sp<IBinder> binder;
    + 
    +-    status_t res = parcel->readStrongBinder(&binder);
    ++    res = parcel->readStrongBinder(&binder);
    +     if (res != OK) return res;
    + 
    +     graphicBufferProducer = interface_cast<IGraphicBufferProducer>(binder);
    +diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp
    +index 3df5f74..b78de2e 100644
    +--- a/libs/gui/SurfaceComposerClient.cpp
    ++++ b/libs/gui/SurfaceComposerClient.cpp
    +@@ -170,8 +170,8 @@ public:
    +     status_t setGeometryAppliesWithResize(const sp<SurfaceComposerClient>& client,
    +             const sp<IBinder>& id);
    + 
    +-    void setDisplaySurface(const sp<IBinder>& token,
    +-            const sp<IGraphicBufferProducer>& bufferProducer);
    ++    status_t setDisplaySurface(const sp<IBinder>& token,
    ++            sp<IGraphicBufferProducer> bufferProducer);
    +     void setDisplayLayerStack(const sp<IBinder>& token, uint32_t layerStack);
    +     void setDisplayProjection(const sp<IBinder>& token,
    +             uint32_t orientation,
    +@@ -473,12 +473,24 @@ DisplayState& Composer::getDisplayStateLocked(const sp<IBinder>& token) {
    +     return mDisplayStates.editItemAt(static_cast<size_t>(index));
    + }
    + 
    +-void Composer::setDisplaySurface(const sp<IBinder>& token,
    +-        const sp<IGraphicBufferProducer>& bufferProducer) {
    ++status_t Composer::setDisplaySurface(const sp<IBinder>& token,
    ++        sp<IGraphicBufferProducer> bufferProducer) {
    ++    if (bufferProducer.get() != nullptr) {
    ++        // Make sure that composition can never be stalled by a virtual display
    ++        // consumer that isn't processing buffers fast enough.
    ++        status_t err = bufferProducer->setAsyncMode(true);
    ++        if (err != NO_ERROR) {
    ++            ALOGE("Composer::setDisplaySurface Failed to enable async mode on the "
    ++                    "BufferQueue. This BufferQueue cannot be used for virtual "
    ++                    "display. (%d)", err);
    ++            return err;
    ++        }
    ++    }
    +     Mutex::Autolock _l(mLock);
    +     DisplayState& s(getDisplayStateLocked(token));
    +     s.surface = bufferProducer;
    +     s.what |= DisplayState::eSurfaceChanged;
    ++    return NO_ERROR;
    + }
    + 
    + void Composer::setDisplayLayerStack(const sp<IBinder>& token,
    +@@ -716,9 +728,9 @@ status_t SurfaceComposerClient::setGeometryAppliesWithResize(
    + 
    + // ----------------------------------------------------------------------------
    + 
    +-void SurfaceComposerClient::setDisplaySurface(const sp<IBinder>& token,
    +-        const sp<IGraphicBufferProducer>& bufferProducer) {
    +-    Composer::getInstance().setDisplaySurface(token, bufferProducer);
    ++status_t SurfaceComposerClient::setDisplaySurface(const sp<IBinder>& token,
    ++        sp<IGraphicBufferProducer> bufferProducer) {
    ++    return Composer::getInstance().setDisplaySurface(token, bufferProducer);
    + }
    + 
    + void SurfaceComposerClient::setDisplayLayerStack(const sp<IBinder>& token,
    +diff --git a/libs/gui/tests/SurfaceTextureGL_test.cpp b/libs/gui/tests/SurfaceTextureGL_test.cpp
    +index dddcf92..5311c59 100644
    +--- a/libs/gui/tests/SurfaceTextureGL_test.cpp
    ++++ b/libs/gui/tests/SurfaceTextureGL_test.cpp
    +@@ -115,13 +115,13 @@ TEST_F(SurfaceTextureGLTest, TexturingFromCpuFilledYV12BufferPow2) {
    +     EXPECT_TRUE(checkPixel(63, 63,   0, 133,   0, 255));
    +     EXPECT_TRUE(checkPixel( 0, 63, 255, 127, 255, 255));
    + 
    +-    EXPECT_TRUE(checkPixel(22, 19, 100, 255,  74, 255));
    +-    EXPECT_TRUE(checkPixel(45, 11, 100, 255,  74, 255));
    +-    EXPECT_TRUE(checkPixel(52, 12, 155,   0, 181, 255));
    +-    EXPECT_TRUE(checkPixel( 7, 32, 150, 237, 170, 255));
    +-    EXPECT_TRUE(checkPixel(31, 54,   0,  71, 117, 255));
    +-    EXPECT_TRUE(checkPixel(29, 28,   0, 133,   0, 255));
    +-    EXPECT_TRUE(checkPixel(36, 41, 100, 232, 255, 255));
    ++    EXPECT_TRUE(checkPixel(22, 19, 100, 255,  74, 255, 3));
    ++    EXPECT_TRUE(checkPixel(45, 11, 100, 255,  74, 255, 3));
    ++    EXPECT_TRUE(checkPixel(52, 12, 155,   0, 181, 255, 3));
    ++    EXPECT_TRUE(checkPixel( 7, 32, 150, 237, 170, 255, 3));
    ++    EXPECT_TRUE(checkPixel(31, 54,   0,  71, 117, 255, 3));
    ++    EXPECT_TRUE(checkPixel(29, 28,   0, 133,   0, 255, 3));
    ++    EXPECT_TRUE(checkPixel(36, 41, 100, 232, 255, 255, 3));
    + }
    + 
    + TEST_F(SurfaceTextureGLTest, TexturingFromCpuFilledYV12BufferWithCrop) {
     diff --git a/libs/ui/Region.cpp b/libs/ui/Region.cpp
     index ee152bf..9c82295 100644
     --- a/libs/ui/Region.cpp
    @@ -176,9 +871,18 @@ index ee152bf..9c82295 100644
          result.mStorage.clear();
          for (size_t r = 0; r < numRects; ++r) {
     diff --git a/opengl/libs/Android.mk b/opengl/libs/Android.mk
    -index eb86860..a512ff7 100644
    +index eb86860..038fe4d 100644
     --- a/opengl/libs/Android.mk
     +++ b/opengl/libs/Android.mk
    +@@ -31,7 +31,7 @@ LOCAL_SRC_FILES:= 	       \
    + 	EGL/Loader.cpp 	       \
    + #
    + 
    +-LOCAL_SHARED_LIBRARIES += libcutils libutils liblog libui
    ++LOCAL_SHARED_LIBRARIES += libbinder libcutils libutils liblog libui
    + LOCAL_MODULE:= libEGL
    + LOCAL_LDFLAGS += -Wl,--exclude-libs=ALL
    + LOCAL_SHARED_LIBRARIES += libdl
     @@ -77,7 +77,6 @@ LOCAL_SRC_FILES:= 		\
      	GLES_CM/gl.cpp.arm 	\
      #
    @@ -195,6 +899,129 @@ index eb86860..a512ff7 100644
      LOCAL_ARM_MODE := arm
      LOCAL_SHARED_LIBRARIES += libcutils libutils liblog libEGL
      LOCAL_MODULE:= libGLESv2
    +diff --git a/opengl/libs/EGL/eglApi.cpp b/opengl/libs/EGL/eglApi.cpp
    +index 03abc49..f41e6e2 100644
    +--- a/opengl/libs/EGL/eglApi.cpp
    ++++ b/opengl/libs/EGL/eglApi.cpp
    +@@ -33,6 +33,8 @@
    + #include <cutils/properties.h>
    + #include <cutils/memory.h>
    + 
    ++#include <gui/ISurfaceComposer.h>
    ++
    + #include <ui/GraphicBuffer.h>
    + 
    + #include <utils/KeyedVector.h>
    +@@ -40,6 +42,10 @@
    + #include <utils/String8.h>
    + #include <utils/Trace.h>
    + 
    ++#include "binder/Binder.h"
    ++#include "binder/Parcel.h"
    ++#include "binder/IServiceManager.h"
    ++
    + #include "../egl_impl.h"
    + #include "../hooks.h"
    + 
    +@@ -1872,20 +1878,77 @@ EGLClientBuffer eglCreateNativeClientBufferANDROID(const EGLint *attrib_list)
    +         return setError(EGL_BAD_PARAMETER, (EGLClientBuffer)0);
    +     }
    + 
    +-    GraphicBuffer* gBuffer = new GraphicBuffer(width, height, format, usage,
    ++#define CHECK_ERROR_CONDITION(message) \
    ++    if (err != NO_ERROR) { \
    ++        ALOGE(message); \
    ++        goto error_condition; \
    ++    }
    ++
    ++    // The holder is used to destroy the buffer if an error occurs.
    ++    GraphicBuffer* gBuffer = new GraphicBuffer();
    ++    sp<IServiceManager> sm = defaultServiceManager();
    ++    sp<IBinder> surfaceFlinger = sm->getService(String16("SurfaceFlinger"));
    ++    sp<IBinder> allocator;
    ++    Parcel sc_data, sc_reply, data, reply;
    ++    status_t err = NO_ERROR;
    ++    if (sm == NULL) {
    ++        ALOGE("Unable to connect to ServiceManager");
    ++        goto error_condition;
    ++    }
    ++
    ++    // Obtain an allocator.
    ++    if (surfaceFlinger == NULL) {
    ++        ALOGE("Unable to connect to SurfaceFlinger");
    ++        goto error_condition;
    ++    }
    ++    sc_data.writeInterfaceToken(String16("android.ui.ISurfaceComposer"));
    ++    err = surfaceFlinger->transact(
    ++            BnSurfaceComposer::CREATE_GRAPHIC_BUFFER_ALLOC, sc_data, &sc_reply);
    ++    CHECK_ERROR_CONDITION("Unable to obtain allocator from SurfaceFlinger");
    ++    allocator = sc_reply.readStrongBinder();
    ++
    ++    if (allocator == NULL) {
    ++        ALOGE("Unable to obtain an ISurfaceComposer");
    ++        goto error_condition;
    ++    }
    ++    data.writeInterfaceToken(String16("android.ui.IGraphicBufferAlloc"));
    ++    err = data.writeUint32(width);
    ++    CHECK_ERROR_CONDITION("Unable to write width");
    ++    err = data.writeUint32(height);
    ++    CHECK_ERROR_CONDITION("Unable to write height");
    ++    err = data.writeInt32(static_cast<int32_t>(format));
    ++    CHECK_ERROR_CONDITION("Unable to write format");
    ++    err = data.writeUint32(usage);
    ++    CHECK_ERROR_CONDITION("Unable to write usage");
    ++    err = data.writeUtf8AsUtf16(
    +             std::string("[eglCreateNativeClientBufferANDROID pid ") +
    +             std::to_string(getpid()) + ']');
    +-    const status_t err = gBuffer->initCheck();
    ++    CHECK_ERROR_CONDITION("Unable to write requestor name");
    ++    err = allocator->transact(IBinder::FIRST_CALL_TRANSACTION, data,
    ++            &reply);
    ++    CHECK_ERROR_CONDITION(
    ++            "Unable to request buffer allocation from surface composer");
    ++    err = reply.readInt32();
    ++    CHECK_ERROR_CONDITION("Unable to obtain buffer from surface composer");
    ++    err = reply.read(*gBuffer);
    ++    CHECK_ERROR_CONDITION("Unable to read buffer from surface composer");
    ++
    ++    err = gBuffer->initCheck();
    +     if (err != NO_ERROR) {
    +         ALOGE("Unable to create native buffer { w=%d, h=%d, f=%d, u=%#x }: %#x",
    +                 width, height, format, usage, err);
    +-        // Destroy the buffer.
    +-        sp<GraphicBuffer> holder(gBuffer);
    +-        return setError(EGL_BAD_ALLOC, (EGLClientBuffer)0);
    ++        goto error_condition;
    +     }
    +     ALOGD("Created new native buffer %p { w=%d, h=%d, f=%d, u=%#x }",
    +             gBuffer, width, height, format, usage);
    +     return static_cast<EGLClientBuffer>(gBuffer->getNativeBuffer());
    ++
    ++#undef CHECK_ERROR_CONDITION
    ++
    ++error_condition:
    ++    // Delete the buffer.
    ++    sp<GraphicBuffer> holder(gBuffer);
    ++    return setError(EGL_BAD_ALLOC, (EGLClientBuffer)0);
    + }
    + 
    + // ----------------------------------------------------------------------------
    +diff --git a/opengl/libs/EGL/egl_display.cpp b/opengl/libs/EGL/egl_display.cpp
    +index e335a6c..1e39aae 100644
    +--- a/opengl/libs/EGL/egl_display.cpp
    ++++ b/opengl/libs/EGL/egl_display.cpp
    +@@ -66,7 +66,10 @@ egl_display_t::~egl_display_t() {
    + 
    + egl_display_t* egl_display_t::get(EGLDisplay dpy) {
    +     uintptr_t index = uintptr_t(dpy)-1U;
    +-    return (index >= NUM_DISPLAYS) ? NULL : &sDisplay[index];
    ++    if (index >= NUM_DISPLAYS || !sDisplay[index].isValid()) {
    ++        return nullptr;
    ++    }
    ++    return &sDisplay[index];
    + }
    + 
    + void egl_display_t::addObject(egl_object_t* object) {
     diff --git a/opengl/libs/GLES2/gl2.cpp b/opengl/libs/GLES2/gl2.cpp
     index 6034a8e..f1feeda 100644
     --- a/opengl/libs/GLES2/gl2.cpp
    @@ -366,8 +1193,172 @@ index b9be675..4dec34b 100644
              outCount += 1;
          }
      
    +diff --git a/services/sensorservice/SensorEventConnection.cpp b/services/sensorservice/SensorEventConnection.cpp
    +index c1e1bad..f2f1444 100644
    +--- a/services/sensorservice/SensorEventConnection.cpp
    ++++ b/services/sensorservice/SensorEventConnection.cpp
    +@@ -206,7 +206,7 @@ void SensorService::SensorEventConnection::incrementPendingFlushCount(int32_t ha
    + status_t SensorService::SensorEventConnection::sendEvents(
    +         sensors_event_t const* buffer, size_t numEvents,
    +         sensors_event_t* scratch,
    +-        SensorEventConnection const * const * mapFlushEventsToConnections) {
    ++        wp<const SensorEventConnection> const * mapFlushEventsToConnections) {
    +     // filter out events not for this connection
    +     int count = 0;
    +     Mutex::Autolock _l(mConnectionLock);
    +@@ -234,7 +234,7 @@ status_t SensorService::SensorEventConnection::sendEvents(
    +             FlushInfo& flushInfo = mSensorInfo.editValueAt(index);
    +             // Check if there is a pending flush_complete event for this sensor on this connection.
    +             if (buffer[i].type == SENSOR_TYPE_META_DATA && flushInfo.mFirstFlushPending == true &&
    +-                    this == mapFlushEventsToConnections[i]) {
    ++                    mapFlushEventsToConnections[i] == this) {
    +                 flushInfo.mFirstFlushPending = false;
    +                 ALOGD_IF(DEBUG_CONNECTIONS, "First flush event for sensor==%d ",
    +                         buffer[i].meta_data.sensor);
    +@@ -255,7 +255,7 @@ status_t SensorService::SensorEventConnection::sendEvents(
    +                 // from the same sensor_handle AND the current connection is mapped to the
    +                 // corresponding flush_complete_event.
    +                 if (buffer[i].type == SENSOR_TYPE_META_DATA) {
    +-                    if (this == mapFlushEventsToConnections[i]) {
    ++                    if (mapFlushEventsToConnections[i] == this) {
    +                         scratch[count++] = buffer[i];
    +                     }
    +                     ++i;
    +diff --git a/services/sensorservice/SensorEventConnection.h b/services/sensorservice/SensorEventConnection.h
    +index b796cc0..883c16e 100644
    +--- a/services/sensorservice/SensorEventConnection.h
    ++++ b/services/sensorservice/SensorEventConnection.h
    +@@ -52,7 +52,7 @@ public:
    +                           bool isDataInjectionMode, const String16& opPackageName);
    + 
    +     status_t sendEvents(sensors_event_t const* buffer, size_t count, sensors_event_t* scratch,
    +-                        SensorEventConnection const * const * mapFlushEventsToConnections = NULL);
    ++                        wp<const SensorEventConnection> const * mapFlushEventsToConnections = NULL);
    +     bool hasSensor(int32_t handle) const;
    +     bool hasAnySensor() const;
    +     bool hasOneShotSensors() const;
    +diff --git a/services/sensorservice/SensorRecord.cpp b/services/sensorservice/SensorRecord.cpp
    +index 644cfb0..53fb9de 100644
    +--- a/services/sensorservice/SensorRecord.cpp
    ++++ b/services/sensorservice/SensorRecord.cpp
    +@@ -21,13 +21,13 @@
    + namespace android {
    + 
    + SensorService::SensorRecord::SensorRecord(
    +-        const sp<SensorEventConnection>& connection)
    ++        const sp<const SensorEventConnection>& connection)
    + {
    +     mConnections.add(connection);
    + }
    + 
    + bool SensorService::SensorRecord::addConnection(
    +-        const sp<SensorEventConnection>& connection)
    ++        const sp<const SensorEventConnection>& connection)
    + {
    +     if (mConnections.indexOf(connection) < 0) {
    +         mConnections.add(connection);
    +@@ -37,16 +37,16 @@ bool SensorService::SensorRecord::addConnection(
    + }
    + 
    + bool SensorService::SensorRecord::removeConnection(
    +-        const wp<SensorEventConnection>& connection)
    ++        const wp<const SensorEventConnection>& connection)
    + {
    +     ssize_t index = mConnections.indexOf(connection);
    +     if (index >= 0) {
    +         mConnections.removeItemsAt(index, 1);
    +     }
    +     // Remove this connections from the queue of flush() calls made on this sensor.
    +-    for (Vector< wp<SensorEventConnection> >::iterator it = mPendingFlushConnections.begin();
    ++    for (Vector< wp<const SensorEventConnection> >::iterator it = mPendingFlushConnections.begin();
    +             it != mPendingFlushConnections.end(); ) {
    +-        if (it->unsafe_get() == connection.unsafe_get()) {
    ++        if (*it == connection) {
    +             it = mPendingFlushConnections.erase(it);
    +         } else {
    +             ++it;
    +@@ -56,7 +56,7 @@ bool SensorService::SensorRecord::removeConnection(
    + }
    + 
    + void SensorService::SensorRecord::addPendingFlushConnection(
    +-        const sp<SensorEventConnection>& connection) {
    ++        const sp<const SensorEventConnection>& connection) {
    +     mPendingFlushConnections.add(connection);
    + }
    + 
    +@@ -66,10 +66,10 @@ void SensorService::SensorRecord::removeFirstPendingFlushConnection() {
    +     }
    + }
    + 
    +-SensorService::SensorEventConnection *
    ++wp<const SensorService::SensorEventConnection>
    +         SensorService::SensorRecord::getFirstPendingFlushConnection() {
    +     if (mPendingFlushConnections.size() > 0) {
    +-        return mPendingFlushConnections[0].unsafe_get();
    ++        return mPendingFlushConnections[0];
    +     }
    +     return NULL;
    + }
    +diff --git a/services/sensorservice/SensorRecord.h b/services/sensorservice/SensorRecord.h
    +index 29b970d..5a35410 100644
    +--- a/services/sensorservice/SensorRecord.h
    ++++ b/services/sensorservice/SensorRecord.h
    +@@ -25,20 +25,20 @@ class SensorService;
    + 
    + class SensorService::SensorRecord {
    + public:
    +-    SensorRecord(const sp<SensorEventConnection>& connection);
    +-    bool addConnection(const sp<SensorEventConnection>& connection);
    +-    bool removeConnection(const wp<SensorEventConnection>& connection);
    ++    SensorRecord(const sp<const SensorEventConnection>& connection);
    ++    bool addConnection(const sp<const SensorEventConnection>& connection);
    ++    bool removeConnection(const wp<const SensorEventConnection>& connection);
    +     size_t getNumConnections() const { return mConnections.size(); }
    + 
    +-    void addPendingFlushConnection(const sp<SensorEventConnection>& connection);
    ++    void addPendingFlushConnection(const sp<const SensorEventConnection>& connection);
    +     void removeFirstPendingFlushConnection();
    +-    SensorEventConnection * getFirstPendingFlushConnection();
    ++    wp<const SensorEventConnection> getFirstPendingFlushConnection();
    +     void clearAllPendingFlushConnections();
    + private:
    +-    SortedVector< wp<SensorEventConnection> > mConnections;
    ++    SortedVector< wp<const SensorEventConnection> > mConnections;
    +     // A queue of all flush() calls made on this sensor. Flush complete events
    +     // will be sent in this order.
    +-    Vector< wp<SensorEventConnection> > mPendingFlushConnections;
    ++    Vector< wp<const SensorEventConnection> > mPendingFlushConnections;
    + };
    + 
    + }
    +diff --git a/services/sensorservice/SensorService.cpp b/services/sensorservice/SensorService.cpp
    +index a24740b..dbd0624 100644
    +--- a/services/sensorservice/SensorService.cpp
    ++++ b/services/sensorservice/SensorService.cpp
    +@@ -260,7 +260,7 @@ void SensorService::onFirstRef() {
    +             const size_t minBufferSize = SensorEventQueue::MAX_RECEIVE_BUFFER_EVENT_COUNT;
    +             mSensorEventBuffer = new sensors_event_t[minBufferSize];
    +             mSensorEventScratch = new sensors_event_t[minBufferSize];
    +-            mMapFlushEventsToConnections = new SensorEventConnection const * [minBufferSize];
    ++            mMapFlushEventsToConnections = new wp<const SensorEventConnection> [minBufferSize];
    +             mCurrentOperatingMode = NORMAL;
    + 
    +             mNextSensorRegIndex = 0;
    +diff --git a/services/sensorservice/SensorService.h b/services/sensorservice/SensorService.h
    +index 1e1ea5a..4a63ef0 100644
    +--- a/services/sensorservice/SensorService.h
    ++++ b/services/sensorservice/SensorService.h
    +@@ -237,7 +237,7 @@ private:
    +     SortedVector< wp<SensorEventConnection> > mActiveConnections;
    +     bool mWakeLockAcquired;
    +     sensors_event_t *mSensorEventBuffer, *mSensorEventScratch;
    +-    SensorEventConnection const **mMapFlushEventsToConnections;
    ++    wp<const SensorEventConnection> * mMapFlushEventsToConnections;
    +     std::unordered_map<int, RecentEventLogger*> mRecentEvent;
    +     Mode mCurrentOperatingMode;
    + 
     diff --git a/services/surfaceflinger/Android.mk b/services/surfaceflinger/Android.mk
    -index dc5e97b..42ca6d9 100644
    +index dc5e97b..cb292ef 100644
     --- a/services/surfaceflinger/Android.mk
     +++ b/services/surfaceflinger/Android.mk
     @@ -56,6 +56,9 @@ else
    @@ -380,6 +1371,255 @@ index dc5e97b..42ca6d9 100644
      ifeq ($(TARGET_BOARD_PLATFORM),omap4)
          LOCAL_CFLAGS += -DHAS_CONTEXT_PRIORITY
      endif
    +@@ -79,18 +82,36 @@ ifeq ($(TARGET_RUNNING_WITHOUT_SYNC_FRAMEWORK),true)
    +     LOCAL_CFLAGS += -DRUNNING_WITHOUT_SYNC_FRAMEWORK
    + endif
    + 
    +-# See build/target/board/generic/BoardConfig.mk for a description of this setting.
    ++# The following two BoardConfig variables define (respectively):
    ++#
    ++#   - The phase offset between hardware vsync and when apps are woken up by the
    ++#     Choreographer callback
    ++#   - The phase offset between hardware vsync and when SurfaceFlinger wakes up
    ++#     to consume input
    ++#
    ++# Their values can be tuned to trade off between display pipeline latency (both
    ++# overall latency and the lengths of the app --> SF and SF --> display phases)
    ++# and frame delivery jitter (which typically manifests as "jank" or "jerkiness"
    ++# while interacting with the device). The default values should produce a
    ++# relatively low amount of jitter at the expense of roughly two frames of
    ++# app --> display latency, and unless significant testing is performed to avoid
    ++# increased display jitter (both manual investigation using systrace [1] and
    ++# automated testing using dumpsys gfxinfo [2] are recommended), they should not
    ++# be modified.
    ++#
    ++# [1] https://developer.android.com/studio/profile/systrace.html
    ++# [2] https://developer.android.com/training/testing/performance.html
    ++
    + ifneq ($(VSYNC_EVENT_PHASE_OFFSET_NS),)
    +     LOCAL_CFLAGS += -DVSYNC_EVENT_PHASE_OFFSET_NS=$(VSYNC_EVENT_PHASE_OFFSET_NS)
    + else
    +-    LOCAL_CFLAGS += -DVSYNC_EVENT_PHASE_OFFSET_NS=0
    ++    LOCAL_CFLAGS += -DVSYNC_EVENT_PHASE_OFFSET_NS=1000000
    + endif
    + 
    +-# See build/target/board/generic/BoardConfig.mk for a description of this setting.
    + ifneq ($(SF_VSYNC_EVENT_PHASE_OFFSET_NS),)
    +     LOCAL_CFLAGS += -DSF_VSYNC_EVENT_PHASE_OFFSET_NS=$(SF_VSYNC_EVENT_PHASE_OFFSET_NS)
    + else
    +-    LOCAL_CFLAGS += -DSF_VSYNC_EVENT_PHASE_OFFSET_NS=0
    ++    LOCAL_CFLAGS += -DSF_VSYNC_EVENT_PHASE_OFFSET_NS=1000000
    + endif
    + 
    + ifneq ($(PRESENT_TIME_OFFSET_FROM_VSYNC_NS),)
    +diff --git a/services/surfaceflinger/DispSync.cpp b/services/surfaceflinger/DispSync.cpp
    +index c67feb3..1a9820d 100644
    +--- a/services/surfaceflinger/DispSync.cpp
    ++++ b/services/surfaceflinger/DispSync.cpp
    +@@ -385,7 +385,7 @@ DispSync::DispSync(const char* name) :
    +     mThread->run("DispSync", PRIORITY_URGENT_DISPLAY + PRIORITY_MORE_FAVORABLE);
    +     // set DispSync to SCHED_FIFO to minimize jitter
    +     struct sched_param param = {0};
    +-    param.sched_priority = 1;
    ++    param.sched_priority = 2;
    +     if (sched_setscheduler(mThread->getTid(), SCHED_FIFO, &param) != 0) {
    +         ALOGE("Couldn't set SCHED_FIFO for DispSyncThread");
    +     }
    +diff --git a/services/surfaceflinger/DisplayHardware/HWC2On1Adapter.cpp b/services/surfaceflinger/DisplayHardware/HWC2On1Adapter.cpp
    +index 8bcee39..cc0dfb0 100644
    +--- a/services/surfaceflinger/DisplayHardware/HWC2On1Adapter.cpp
    ++++ b/services/surfaceflinger/DisplayHardware/HWC2On1Adapter.cpp
    +@@ -2305,7 +2305,14 @@ void HWC2On1Adapter::Layer::applyCompositionType(hwc_layer_1_t& hwc1Layer,
    +                 hwc1Layer.compositionType = HWC_FRAMEBUFFER;
    +                 break;
    +             case Composition::SolidColor:
    +-                hwc1Layer.compositionType = HWC_BACKGROUND;
    ++                // In theory the following line should work, but since the HWC1
    ++                // version of SurfaceFlinger never used HWC_BACKGROUND, HWC1
    ++                // devices may not work correctly. To be on the safe side, we
    ++                // fall back to client composition.
    ++                //
    ++                // hwc1Layer.compositionType = HWC_BACKGROUND;
    ++                hwc1Layer.compositionType = HWC_FRAMEBUFFER;
    ++                hwc1Layer.flags |= HWC_SKIP_LAYER;
    +                 break;
    +             case Composition::Cursor:
    +                 hwc1Layer.compositionType = HWC_FRAMEBUFFER;
    +diff --git a/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp b/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp
    +index 61bb0bd..2190466 100644
    +--- a/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp
    ++++ b/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp
    +@@ -563,8 +563,8 @@ status_t VirtualDisplaySurface::connect(const sp<IProducerListener>& listener,
    +     return result;
    + }
    + 
    +-status_t VirtualDisplaySurface::disconnect(int api) {
    +-    return mSource[SOURCE_SINK]->disconnect(api);
    ++status_t VirtualDisplaySurface::disconnect(int api, DisconnectMode mode) {
    ++    return mSource[SOURCE_SINK]->disconnect(api, mode);
    + }
    + 
    + status_t VirtualDisplaySurface::setSidebandStream(const sp<NativeHandle>& /*stream*/) {
    +diff --git a/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.h b/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.h
    +index bf9b39c..70f717f 100644
    +--- a/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.h
    ++++ b/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.h
    +@@ -115,7 +115,7 @@ private:
    +     virtual int query(int what, int* value);
    +     virtual status_t connect(const sp<IProducerListener>& listener,
    +             int api, bool producerControlledByApp, QueueBufferOutput* output);
    +-    virtual status_t disconnect(int api);
    ++    virtual status_t disconnect(int api, DisconnectMode mode);
    +     virtual status_t setSidebandStream(const sp<NativeHandle>& stream);
    +     virtual void allocateBuffers(uint32_t width, uint32_t height,
    +             PixelFormat format, uint32_t usage);
    +diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
    +index 785df1a..dfece93 100644
    +--- a/services/surfaceflinger/Layer.cpp
    ++++ b/services/surfaceflinger/Layer.cpp
    +@@ -591,19 +591,25 @@ void Layer::setGeometry(
    +     const Transform& tr(displayDevice->getTransform());
    +     Rect transformedFrame = tr.transform(frame);
    +     auto error = hwcLayer->setDisplayFrame(transformedFrame);
    +-    ALOGE_IF(error != HWC2::Error::None, "[%s] Failed to set display frame "
    +-            "[%d, %d, %d, %d]: %s (%d)", mName.string(), transformedFrame.left,
    +-            transformedFrame.top, transformedFrame.right,
    +-            transformedFrame.bottom, to_string(error).c_str(),
    +-            static_cast<int32_t>(error));
    ++    if (error != HWC2::Error::None) {
    ++        ALOGE("[%s] Failed to set display frame [%d, %d, %d, %d]: %s (%d)",
    ++                mName.string(), transformedFrame.left, transformedFrame.top,
    ++                transformedFrame.right, transformedFrame.bottom,
    ++                to_string(error).c_str(), static_cast<int32_t>(error));
    ++    } else {
    ++        hwcInfo.displayFrame = transformedFrame;
    ++    }
    + 
    +     FloatRect sourceCrop = computeCrop(displayDevice);
    +     error = hwcLayer->setSourceCrop(sourceCrop);
    +-    ALOGE_IF(error != HWC2::Error::None, "[%s] Failed to set source crop "
    +-            "[%.3f, %.3f, %.3f, %.3f]: %s (%d)", mName.string(),
    +-            sourceCrop.left, sourceCrop.top, sourceCrop.right,
    +-            sourceCrop.bottom, to_string(error).c_str(),
    +-            static_cast<int32_t>(error));
    ++    if (error != HWC2::Error::None) {
    ++        ALOGE("[%s] Failed to set source crop [%.3f, %.3f, %.3f, %.3f]: "
    ++                "%s (%d)", mName.string(), sourceCrop.left, sourceCrop.top,
    ++                sourceCrop.right, sourceCrop.bottom, to_string(error).c_str(),
    ++                static_cast<int32_t>(error));
    ++    } else {
    ++        hwcInfo.sourceCrop = sourceCrop;
    ++    }
    + 
    +     error = hwcLayer->setPlaneAlpha(s.alpha);
    +     ALOGE_IF(error != HWC2::Error::None, "[%s] Failed to set plane alpha %.3f: "
    +@@ -2235,6 +2241,54 @@ void Layer::dump(String8& result, Colorizer& colorizer) const
    +     }
    + }
    + 
    ++#ifdef USE_HWC2
    ++void Layer::miniDumpHeader(String8& result) {
    ++    result.append("----------------------------------------");
    ++    result.append("---------------------------------------\n");
    ++    result.append(" Layer name\n");
    ++    result.append("           Z | ");
    ++    result.append(" Comp Type | ");
    ++    result.append("  Disp Frame (LTRB) | ");
    ++    result.append("         Source Crop (LTRB)\n");
    ++    result.append("----------------------------------------");
    ++    result.append("---------------------------------------\n");
    ++}
    ++
    ++void Layer::miniDump(String8& result, int32_t hwcId) const {
    ++    if (mHwcLayers.count(hwcId) == 0) {
    ++        return;
    ++    }
    ++
    ++    String8 name;
    ++    if (mName.length() > 77) {
    ++        std::string shortened;
    ++        shortened.append(mName.string(), 36);
    ++        shortened.append("[...]");
    ++        shortened.append(mName.string() + (mName.length() - 36), 36);
    ++        name = shortened.c_str();
    ++    } else {
    ++        name = mName;
    ++    }
    ++
    ++    result.appendFormat(" %s\n", name.string());
    ++
    ++    const Layer::State& layerState(getDrawingState());
    ++    const HWCInfo& hwcInfo = mHwcLayers.at(hwcId);
    ++    result.appendFormat("  %10u | ", layerState.z);
    ++    result.appendFormat("%10s | ",
    ++            to_string(getCompositionType(hwcId)).c_str());
    ++    const Rect& frame = hwcInfo.displayFrame;
    ++    result.appendFormat("%4d %4d %4d %4d | ", frame.left, frame.top,
    ++            frame.right, frame.bottom);
    ++    const FloatRect& crop = hwcInfo.sourceCrop;
    ++    result.appendFormat("%6.1f %6.1f %6.1f %6.1f\n", crop.left, crop.top,
    ++            crop.right, crop.bottom);
    ++
    ++    result.append("- - - - - - - - - - - - - - - - - - - - ");
    ++    result.append("- - - - - - - - - - - - - - - - - - - -\n");
    ++}
    ++#endif
    ++
    + void Layer::dumpFrameStats(String8& result) const {
    +     mFrameTracker.dumpStats(result);
    + }
    +diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h
    +index 6533953..2ce1340 100644
    +--- a/services/surfaceflinger/Layer.h
    ++++ b/services/surfaceflinger/Layer.h
    +@@ -402,6 +402,10 @@ public:
    + 
    +     /* always call base class first */
    +     void dump(String8& result, Colorizer& colorizer) const;
    ++#ifdef USE_HWC2
    ++    static void miniDumpHeader(String8& result);
    ++    void miniDump(String8& result, int32_t hwcId) const;
    ++#endif
    +     void dumpFrameStats(String8& result) const;
    +     void clearFrameStats();
    +     void logFrameStats();
    +@@ -588,6 +592,8 @@ private:
    +         bool forceClientComposition;
    +         HWC2::Composition compositionType;
    +         bool clearClientTarget;
    ++        Rect displayFrame;
    ++        FloatRect sourceCrop;
    +     };
    +     std::unordered_map<int32_t, HWCInfo> mHwcLayers;
    + #else
    +diff --git a/services/surfaceflinger/MonitoredProducer.cpp b/services/surfaceflinger/MonitoredProducer.cpp
    +index 36cfa37..ffaee7a 100644
    +--- a/services/surfaceflinger/MonitoredProducer.cpp
    ++++ b/services/surfaceflinger/MonitoredProducer.cpp
    +@@ -102,8 +102,8 @@ status_t MonitoredProducer::connect(const sp<IProducerListener>& listener,
    +     return mProducer->connect(listener, api, producerControlledByApp, output);
    + }
    + 
    +-status_t MonitoredProducer::disconnect(int api) {
    +-    return mProducer->disconnect(api);
    ++status_t MonitoredProducer::disconnect(int api, DisconnectMode mode) {
    ++    return mProducer->disconnect(api, mode);
    + }
    + 
    + status_t MonitoredProducer::setSidebandStream(const sp<NativeHandle>& stream) {
    +diff --git a/services/surfaceflinger/MonitoredProducer.h b/services/surfaceflinger/MonitoredProducer.h
    +index f64fe51..66f6cf0 100644
    +--- a/services/surfaceflinger/MonitoredProducer.h
    ++++ b/services/surfaceflinger/MonitoredProducer.h
    +@@ -50,7 +50,7 @@ public:
    +     virtual int query(int what, int* value);
    +     virtual status_t connect(const sp<IProducerListener>& token, int api,
    +             bool producerControlledByApp, QueueBufferOutput* output);
    +-    virtual status_t disconnect(int api);
    ++    virtual status_t disconnect(int api, DisconnectMode mode);
    +     virtual status_t setSidebandStream(const sp<NativeHandle>& stream);
    +     virtual void allocateBuffers(uint32_t width, uint32_t height,
    +             PixelFormat format, uint32_t usage);
     diff --git a/services/surfaceflinger/RenderEngine/GLES11RenderEngine.cpp b/services/surfaceflinger/RenderEngine/GLES11RenderEngine.cpp
     index 847cdb3..b2821b7 100644
     --- a/services/surfaceflinger/RenderEngine/GLES11RenderEngine.cpp
    @@ -622,10 +1862,46 @@ index 0259881..5a5910a 100644
              int getStatus() const;
          };
     diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
    -index 2a67f4c..bc99e66 100644
    +index 2a67f4c..874cdc8 100644
     --- a/services/surfaceflinger/SurfaceFlinger.cpp
     +++ b/services/surfaceflinger/SurfaceFlinger.cpp
    -@@ -3418,7 +3418,8 @@ status_t SurfaceFlinger::captureScreen(const sp<IBinder>& display,
    +@@ -471,7 +471,7 @@ void SurfaceFlinger::init() {
    + 
    +         // set SFEventThread to SCHED_FIFO to minimize jitter
    +         struct sched_param param = {0};
    +-        param.sched_priority = 1;
    ++        param.sched_priority = 2;
    +         if (sched_setscheduler(mSFEventThread->getTid(), SCHED_FIFO, &param) != 0) {
    +             ALOGE("Couldn't set SCHED_FIFO for SFEventThread");
    +         }
    +@@ -3057,6 +3057,26 @@ void SurfaceFlinger::dumpAllLocked(const Vector<String16>& args, size_t& index,
    +      * VSYNC state
    +      */
    +     mEventThread->dump(result);
    ++    result.append("\n");
    ++
    ++    /*
    ++     * HWC layer minidump
    ++     */
    ++    for (size_t d = 0; d < mDisplays.size(); d++) {
    ++        const sp<const DisplayDevice>& displayDevice(mDisplays[d]);
    ++        int32_t hwcId = displayDevice->getHwcDisplayId();
    ++        if (hwcId == DisplayDevice::DISPLAY_ID_INVALID) {
    ++            continue;
    ++        }
    ++
    ++        result.appendFormat("Display %d HWC layers:\n", hwcId);
    ++        Layer::miniDumpHeader(result);
    ++        for (size_t l = 0; l < count; l++) {
    ++            const sp<Layer>& layer(currentLayers[l]);
    ++            layer->miniDump(result, hwcId);
    ++        }
    ++        result.append("\n");
    ++    }
    + 
    +     /*
    +      * Dump HWComposer state
    +@@ -3418,7 +3438,8 @@ status_t SurfaceFlinger::captureScreen(const sp<IBinder>& display,
              const sp<IGraphicBufferProducer>& producer,
              Rect sourceCrop, uint32_t reqWidth, uint32_t reqHeight,
              uint32_t minLayerZ, uint32_t maxLayerZ,
    @@ -635,7 +1911,7 @@ index 2a67f4c..bc99e66 100644
      
          if (CC_UNLIKELY(display == 0))
              return BAD_VALUE;
    -@@ -3462,6 +3463,7 @@ status_t SurfaceFlinger::captureScreen(const sp<IBinder>& display,
    +@@ -3462,6 +3483,7 @@ status_t SurfaceFlinger::captureScreen(const sp<IBinder>& display,
              bool useIdentityTransform;
              Transform::orientation_flags rotation;
              status_t result;
    @@ -643,7 +1919,7 @@ index 2a67f4c..bc99e66 100644
              bool isLocalScreenshot;
          public:
              MessageCaptureScreen(SurfaceFlinger* flinger,
    -@@ -3471,12 +3473,13 @@ status_t SurfaceFlinger::captureScreen(const sp<IBinder>& display,
    +@@ -3471,12 +3493,13 @@ status_t SurfaceFlinger::captureScreen(const sp<IBinder>& display,
                      uint32_t minLayerZ, uint32_t maxLayerZ,
                      bool useIdentityTransform,
                      Transform::orientation_flags rotation,
    @@ -658,7 +1934,7 @@ index 2a67f4c..bc99e66 100644
                    isLocalScreenshot(isLocalScreenshot)
              {
              }
    -@@ -3486,9 +3489,10 @@ status_t SurfaceFlinger::captureScreen(const sp<IBinder>& display,
    +@@ -3486,9 +3509,10 @@ status_t SurfaceFlinger::captureScreen(const sp<IBinder>& display,
              virtual bool handler() {
                  Mutex::Autolock _l(flinger->mStateLock);
                  sp<const DisplayDevice> hw(flinger->getDisplayDevice(display));
    @@ -670,7 +1946,7 @@ index 2a67f4c..bc99e66 100644
                  static_cast<GraphicProducerWrapper*>(IInterface::asBinder(producer).get())->exit(result);
                  return true;
              }
    -@@ -3504,7 +3508,7 @@ status_t SurfaceFlinger::captureScreen(const sp<IBinder>& display,
    +@@ -3504,7 +3528,7 @@ status_t SurfaceFlinger::captureScreen(const sp<IBinder>& display,
          sp<MessageBase> msg = new MessageCaptureScreen(this,
                  display, IGraphicBufferProducer::asInterface( wrapper ),
                  sourceCrop, reqWidth, reqHeight, minLayerZ, maxLayerZ,
    @@ -679,7 +1955,7 @@ index 2a67f4c..bc99e66 100644
      
          status_t res = postMessageAsync(msg);
          if (res == NO_ERROR) {
    -@@ -3587,7 +3591,7 @@ status_t SurfaceFlinger::captureScreenImplLocked(
    +@@ -3587,7 +3611,7 @@ status_t SurfaceFlinger::captureScreenImplLocked(
              Rect sourceCrop, uint32_t reqWidth, uint32_t reqHeight,
              uint32_t minLayerZ, uint32_t maxLayerZ,
              bool useIdentityTransform, Transform::orientation_flags rotation,
    @@ -688,7 +1964,7 @@ index 2a67f4c..bc99e66 100644
      {
          ATRACE_CALL();
      
    -@@ -3665,7 +3669,7 @@ status_t SurfaceFlinger::captureScreenImplLocked(
    +@@ -3665,7 +3689,7 @@ status_t SurfaceFlinger::captureScreenImplLocked(
                      if (image != EGL_NO_IMAGE_KHR) {
                          // this binds the given EGLImage as a framebuffer for the
                          // duration of this scope.
    @@ -697,7 +1973,7 @@ index 2a67f4c..bc99e66 100644
                          if (imageBond.getStatus() == NO_ERROR) {
                              // this will in fact render into our dequeued buffer
                              // via an FBO, which means we didn't have to create
    -@@ -3712,6 +3716,16 @@ status_t SurfaceFlinger::captureScreenImplLocked(
    +@@ -3712,6 +3736,16 @@ status_t SurfaceFlinger::captureScreenImplLocked(
                                      ALOGW("captureScreen: error creating EGL fence: %#x", eglGetError());
                                  }
                              }
    @@ -738,10 +2014,10 @@ index b98924b..2c3bd19 100644
          /* ------------------------------------------------------------------------
           * EGL
     diff --git a/services/surfaceflinger/SurfaceFlinger_hwc1.cpp b/services/surfaceflinger/SurfaceFlinger_hwc1.cpp
    -index 650d6b4..74fe9c8 100644
    +index 650d6b4..ca03830 100644
     --- a/services/surfaceflinger/SurfaceFlinger_hwc1.cpp
     +++ b/services/surfaceflinger/SurfaceFlinger_hwc1.cpp
    -@@ -466,13 +466,14 @@ void SurfaceFlinger::init() {
    +@@ -466,10 +466,12 @@ void SurfaceFlinger::init() {
          mEventQueue.setEventThread(mSFEventThread);
      
          // set SFEventThread to SCHED_FIFO to minimize jitter
    @@ -757,11 +2033,8 @@ index 650d6b4..74fe9c8 100644
     +        }
          }
      
    --
    -     // Initialize the H/W composer object.  There may or may not be an
    -     // actual hardware composer underneath.
    -     mHwc = new HWComposer(this,
    -@@ -635,10 +636,21 @@ status_t SurfaceFlinger::getDisplayConfigs(const sp<IBinder>& display,
    + 
    +@@ -635,10 +637,21 @@ status_t SurfaceFlinger::getDisplayConfigs(const sp<IBinder>& display,
                  info.orientation = 0;
              }
      
    @@ -787,7 +2060,7 @@ index 650d6b4..74fe9c8 100644
              info.fps = float(1e9 / hwConfig.refresh);
              info.appVsyncOffset = VSYNC_EVENT_PHASE_OFFSET_NS;
      
    -@@ -3331,7 +3343,8 @@ status_t SurfaceFlinger::captureScreen(const sp<IBinder>& display,
    +@@ -3331,7 +3344,8 @@ status_t SurfaceFlinger::captureScreen(const sp<IBinder>& display,
              const sp<IGraphicBufferProducer>& producer,
              Rect sourceCrop, uint32_t reqWidth, uint32_t reqHeight,
              uint32_t minLayerZ, uint32_t maxLayerZ,
    @@ -797,7 +2070,7 @@ index 650d6b4..74fe9c8 100644
      
          if (CC_UNLIKELY(display == 0))
              return BAD_VALUE;
    -@@ -3375,6 +3388,7 @@ status_t SurfaceFlinger::captureScreen(const sp<IBinder>& display,
    +@@ -3375,6 +3389,7 @@ status_t SurfaceFlinger::captureScreen(const sp<IBinder>& display,
              bool useIdentityTransform;
              Transform::orientation_flags rotation;
              status_t result;
    @@ -805,7 +2078,7 @@ index 650d6b4..74fe9c8 100644
              bool isLocalScreenshot;
          public:
              MessageCaptureScreen(SurfaceFlinger* flinger,
    -@@ -3384,12 +3398,13 @@ status_t SurfaceFlinger::captureScreen(const sp<IBinder>& display,
    +@@ -3384,12 +3399,13 @@ status_t SurfaceFlinger::captureScreen(const sp<IBinder>& display,
                      uint32_t minLayerZ, uint32_t maxLayerZ,
                      bool useIdentityTransform,
                      Transform::orientation_flags rotation,
    @@ -820,7 +2093,7 @@ index 650d6b4..74fe9c8 100644
                    isLocalScreenshot(isLocalScreenshot)
              {
              }
    -@@ -3399,9 +3414,10 @@ status_t SurfaceFlinger::captureScreen(const sp<IBinder>& display,
    +@@ -3399,9 +3415,10 @@ status_t SurfaceFlinger::captureScreen(const sp<IBinder>& display,
              virtual bool handler() {
                  Mutex::Autolock _l(flinger->mStateLock);
                  sp<const DisplayDevice> hw(flinger->getDisplayDevice(display));
    @@ -832,7 +2105,7 @@ index 650d6b4..74fe9c8 100644
                  static_cast<GraphicProducerWrapper*>(IInterface::asBinder(producer).get())->exit(result);
                  return true;
              }
    -@@ -3417,7 +3433,7 @@ status_t SurfaceFlinger::captureScreen(const sp<IBinder>& display,
    +@@ -3417,7 +3434,7 @@ status_t SurfaceFlinger::captureScreen(const sp<IBinder>& display,
          sp<MessageBase> msg = new MessageCaptureScreen(this,
                  display, IGraphicBufferProducer::asInterface( wrapper ),
                  sourceCrop, reqWidth, reqHeight, minLayerZ, maxLayerZ,
    @@ -841,7 +2114,7 @@ index 650d6b4..74fe9c8 100644
      
          status_t res = postMessageAsync(msg);
          if (res == NO_ERROR) {
    -@@ -3502,7 +3518,7 @@ status_t SurfaceFlinger::captureScreenImplLocked(
    +@@ -3502,7 +3519,7 @@ status_t SurfaceFlinger::captureScreenImplLocked(
              Rect sourceCrop, uint32_t reqWidth, uint32_t reqHeight,
              uint32_t minLayerZ, uint32_t maxLayerZ,
              bool useIdentityTransform, Transform::orientation_flags rotation,
    @@ -850,7 +2123,7 @@ index 650d6b4..74fe9c8 100644
      {
          ATRACE_CALL();
      
    -@@ -3572,7 +3588,7 @@ status_t SurfaceFlinger::captureScreenImplLocked(
    +@@ -3572,7 +3589,7 @@ status_t SurfaceFlinger::captureScreenImplLocked(
                      if (image != EGL_NO_IMAGE_KHR) {
                          // this binds the given EGLImage as a framebuffer for the
                          // duration of this scope.
    @@ -859,7 +2132,7 @@ index 650d6b4..74fe9c8 100644
                          if (imageBond.getStatus() == NO_ERROR) {
                              // this will in fact render into our dequeued buffer
                              // via an FBO, which means we didn't have to create
    -@@ -3619,6 +3635,16 @@ status_t SurfaceFlinger::captureScreenImplLocked(
    +@@ -3619,6 +3636,16 @@ status_t SurfaceFlinger::captureScreenImplLocked(
                                      ALOGW("captureScreen: error creating EGL fence: %#x", eglGetError());
                                  }
                              }
    @@ -876,3 +2149,3793 @@ index 650d6b4..74fe9c8 100644
                              if (DEBUG_SCREENSHOTS) {
                                  uint32_t* pixels = new uint32_t[reqWidth*reqHeight];
                                  getRenderEngine().readPixels(0, 0, reqWidth, reqHeight, pixels);
    +diff --git a/services/surfaceflinger/SurfaceFlinger_hwc1.cpp.orig b/services/surfaceflinger/SurfaceFlinger_hwc1.cpp.orig
    +new file mode 100644
    +index 0000000..709bbff
    +--- /dev/null
    ++++ b/services/surfaceflinger/SurfaceFlinger_hwc1.cpp.orig
    +@@ -0,0 +1,3784 @@
    ++/*
    ++ * Copyright (C) 2007 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.
    ++ */
    ++
    ++#define ATRACE_TAG ATRACE_TAG_GRAPHICS
    ++
    ++#include <stdint.h>
    ++#include <sys/types.h>
    ++#include <errno.h>
    ++#include <math.h>
    ++#include <dlfcn.h>
    ++#include <inttypes.h>
    ++#include <stdatomic.h>
    ++
    ++#include <EGL/egl.h>
    ++
    ++#include <cutils/log.h>
    ++#include <cutils/properties.h>
    ++
    ++#include <binder/IPCThreadState.h>
    ++#include <binder/IServiceManager.h>
    ++#include <binder/MemoryHeapBase.h>
    ++#include <binder/PermissionCache.h>
    ++
    ++#include <ui/DisplayInfo.h>
    ++#include <ui/DisplayStatInfo.h>
    ++
    ++#include <gui/BitTube.h>
    ++#include <gui/BufferQueue.h>
    ++#include <gui/GuiConfig.h>
    ++#include <gui/IDisplayEventConnection.h>
    ++#include <gui/Surface.h>
    ++#include <gui/GraphicBufferAlloc.h>
    ++
    ++#include <ui/GraphicBufferAllocator.h>
    ++#include <ui/HdrCapabilities.h>
    ++#include <ui/PixelFormat.h>
    ++#include <ui/UiConfig.h>
    ++
    ++#include <utils/misc.h>
    ++#include <utils/String8.h>
    ++#include <utils/String16.h>
    ++#include <utils/StopWatch.h>
    ++#include <utils/Timers.h>
    ++#include <utils/Trace.h>
    ++
    ++#include <private/android_filesystem_config.h>
    ++#include <private/gui/SyncFeatures.h>
    ++
    ++#include <set>
    ++
    ++#include "Client.h"
    ++#include "clz.h"
    ++#include "Colorizer.h"
    ++#include "DdmConnection.h"
    ++#include "DisplayDevice.h"
    ++#include "DispSync.h"
    ++#include "EventControlThread.h"
    ++#include "EventThread.h"
    ++#include "Layer.h"
    ++#include "LayerDim.h"
    ++#include "SurfaceFlinger.h"
    ++
    ++#include "DisplayHardware/FramebufferSurface.h"
    ++#include "DisplayHardware/HWComposer.h"
    ++#include "DisplayHardware/VirtualDisplaySurface.h"
    ++
    ++#include "Effects/Daltonizer.h"
    ++
    ++#include "RenderEngine/RenderEngine.h"
    ++#include <cutils/compiler.h>
    ++
    ++#define DISPLAY_COUNT       1
    ++
    ++/*
    ++ * DEBUG_SCREENSHOTS: set to true to check that screenshots are not all
    ++ * black pixels.
    ++ */
    ++#define DEBUG_SCREENSHOTS   false
    ++
    ++EGLAPI const char* eglQueryStringImplementationANDROID(EGLDisplay dpy, EGLint name);
    ++
    ++namespace android {
    ++
    ++// This is the phase offset in nanoseconds of the software vsync event
    ++// relative to the vsync event reported by HWComposer.  The software vsync
    ++// event is when SurfaceFlinger and Choreographer-based applications run each
    ++// frame.
    ++//
    ++// This phase offset allows adjustment of the minimum latency from application
    ++// wake-up (by Choregographer) time to the time at which the resulting window
    ++// image is displayed.  This value may be either positive (after the HW vsync)
    ++// or negative (before the HW vsync).  Setting it to 0 will result in a
    ++// minimum latency of two vsync periods because the app and SurfaceFlinger
    ++// will run just after the HW vsync.  Setting it to a positive number will
    ++// result in the minimum latency being:
    ++//
    ++//     (2 * VSYNC_PERIOD - (vsyncPhaseOffsetNs % VSYNC_PERIOD))
    ++//
    ++// Note that reducing this latency makes it more likely for the applications
    ++// to not have their window content image ready in time.  When this happens
    ++// the latency will end up being an additional vsync period, and animations
    ++// will hiccup.  Therefore, this latency should be tuned somewhat
    ++// conservatively (or at least with awareness of the trade-off being made).
    ++static const int64_t vsyncPhaseOffsetNs = VSYNC_EVENT_PHASE_OFFSET_NS;
    ++
    ++// This is the phase offset at which SurfaceFlinger's composition runs.
    ++static const int64_t sfVsyncPhaseOffsetNs = SF_VSYNC_EVENT_PHASE_OFFSET_NS;
    ++
    ++// ---------------------------------------------------------------------------
    ++
    ++const String16 sHardwareTest("android.permission.HARDWARE_TEST");
    ++const String16 sAccessSurfaceFlinger("android.permission.ACCESS_SURFACE_FLINGER");
    ++const String16 sReadFramebuffer("android.permission.READ_FRAME_BUFFER");
    ++const String16 sDump("android.permission.DUMP");
    ++
    ++// ---------------------------------------------------------------------------
    ++
    ++SurfaceFlinger::SurfaceFlinger()
    ++    :   BnSurfaceComposer(),
    ++        mTransactionFlags(0),
    ++        mTransactionPending(false),
    ++        mAnimTransactionPending(false),
    ++        mLayersRemoved(false),
    ++        mRepaintEverything(0),
    ++        mRenderEngine(NULL),
    ++        mBootTime(systemTime()),
    ++        mVisibleRegionsDirty(false),
    ++        mHwWorkListDirty(false),
    ++        mAnimCompositionPending(false),
    ++        mDebugRegion(0),
    ++        mDebugDDMS(0),
    ++        mDebugDisableHWC(0),
    ++        mDebugDisableTransformHint(0),
    ++        mDebugInSwapBuffers(0),
    ++        mLastSwapBufferTime(0),
    ++        mDebugInTransaction(0),
    ++        mLastTransactionTime(0),
    ++        mBootFinished(false),
    ++        mForceFullDamage(false),
    ++        mPrimaryDispSync("PrimaryDispSync"),
    ++        mPrimaryHWVsyncEnabled(false),
    ++        mHWVsyncAvailable(false),
    ++        mDaltonize(false),
    ++        mHasColorMatrix(false),
    ++        mHasPoweredOff(false),
    ++        mFrameBuckets(),
    ++        mTotalTime(0),
    ++        mLastSwapTime(0)
    ++{
    ++    ALOGI("SurfaceFlinger is starting");
    ++
    ++    // debugging stuff...
    ++    char value[PROPERTY_VALUE_MAX];
    ++
    ++    property_get("ro.bq.gpu_to_cpu_unsupported", value, "0");
    ++    mGpuToCpuSupported = !atoi(value);
    ++
    ++    property_get("debug.sf.showupdates", value, "0");
    ++    mDebugRegion = atoi(value);
    ++
    ++    property_get("debug.sf.ddms", value, "0");
    ++    mDebugDDMS = atoi(value);
    ++    if (mDebugDDMS) {
    ++        if (!startDdmConnection()) {
    ++            // start failed, and DDMS debugging not enabled
    ++            mDebugDDMS = 0;
    ++        }
    ++    }
    ++    ALOGI_IF(mDebugRegion, "showupdates enabled");
    ++    ALOGI_IF(mDebugDDMS, "DDMS debugging enabled");
    ++
    ++    property_get("debug.sf.disable_hwc_vds", value, "0");
    ++    mUseHwcVirtualDisplays = !atoi(value);
    ++    ALOGI_IF(!mUseHwcVirtualDisplays, "Disabling HWC virtual displays");
    ++}
    ++
    ++void SurfaceFlinger::onFirstRef()
    ++{
    ++    mEventQueue.init(this);
    ++}
    ++
    ++SurfaceFlinger::~SurfaceFlinger()
    ++{
    ++    EGLDisplay display = eglGetDisplay(EGL_DEFAULT_DISPLAY);
    ++    eglMakeCurrent(display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
    ++    eglTerminate(display);
    ++}
    ++
    ++void SurfaceFlinger::binderDied(const wp<IBinder>& /* who */)
    ++{
    ++    // the window manager died on us. prepare its eulogy.
    ++
    ++    // restore initial conditions (default device unblank, etc)
    ++    initializeDisplays();
    ++
    ++    // restart the boot-animation
    ++    startBootAnim();
    ++}
    ++
    ++sp<ISurfaceComposerClient> SurfaceFlinger::createConnection()
    ++{
    ++    sp<ISurfaceComposerClient> bclient;
    ++    sp<Client> client(new Client(this));
    ++    status_t err = client->initCheck();
    ++    if (err == NO_ERROR) {
    ++        bclient = client;
    ++    }
    ++    return bclient;
    ++}
    ++
    ++sp<IBinder> SurfaceFlinger::createDisplay(const String8& displayName,
    ++        bool secure)
    ++{
    ++    class DisplayToken : public BBinder {
    ++        sp<SurfaceFlinger> flinger;
    ++        virtual ~DisplayToken() {
    ++             // no more references, this display must be terminated
    ++             Mutex::Autolock _l(flinger->mStateLock);
    ++             flinger->mCurrentState.displays.removeItem(this);
    ++             flinger->setTransactionFlags(eDisplayTransactionNeeded);
    ++         }
    ++     public:
    ++        DisplayToken(const sp<SurfaceFlinger>& flinger)
    ++            : flinger(flinger) {
    ++        }
    ++    };
    ++
    ++    sp<BBinder> token = new DisplayToken(this);
    ++
    ++    Mutex::Autolock _l(mStateLock);
    ++    DisplayDeviceState info(DisplayDevice::DISPLAY_VIRTUAL, secure);
    ++    info.displayName = displayName;
    ++    mCurrentState.displays.add(token, info);
    ++
    ++    return token;
    ++}
    ++
    ++void SurfaceFlinger::destroyDisplay(const sp<IBinder>& display) {
    ++    Mutex::Autolock _l(mStateLock);
    ++
    ++    ssize_t idx = mCurrentState.displays.indexOfKey(display);
    ++    if (idx < 0) {
    ++        ALOGW("destroyDisplay: invalid display token");
    ++        return;
    ++    }
    ++
    ++    const DisplayDeviceState& info(mCurrentState.displays.valueAt(idx));
    ++    if (!info.isVirtualDisplay()) {
    ++        ALOGE("destroyDisplay called for non-virtual display");
    ++        return;
    ++    }
    ++
    ++    mCurrentState.displays.removeItemsAt(idx);
    ++    setTransactionFlags(eDisplayTransactionNeeded);
    ++}
    ++
    ++void SurfaceFlinger::createBuiltinDisplayLocked(DisplayDevice::DisplayType type) {
    ++    ALOGW_IF(mBuiltinDisplays[type],
    ++            "Overwriting display token for display type %d", type);
    ++    mBuiltinDisplays[type] = new BBinder();
    ++    // All non-virtual displays are currently considered secure.
    ++    DisplayDeviceState info(type, true);
    ++    mCurrentState.displays.add(mBuiltinDisplays[type], info);
    ++}
    ++
    ++sp<IBinder> SurfaceFlinger::getBuiltInDisplay(int32_t id) {
    ++    if (uint32_t(id) >= DisplayDevice::NUM_BUILTIN_DISPLAY_TYPES) {
    ++        ALOGE("getDefaultDisplay: id=%d is not a valid default display id", id);
    ++        return NULL;
    ++    }
    ++    return mBuiltinDisplays[id];
    ++}
    ++
    ++sp<IGraphicBufferAlloc> SurfaceFlinger::createGraphicBufferAlloc()
    ++{
    ++    sp<GraphicBufferAlloc> gba(new GraphicBufferAlloc());
    ++    return gba;
    ++}
    ++
    ++void SurfaceFlinger::bootFinished()
    ++{
    ++    const nsecs_t now = systemTime();
    ++    const nsecs_t duration = now - mBootTime;
    ++    ALOGI("Boot is finished (%ld ms)", long(ns2ms(duration)) );
    ++    mBootFinished = true;
    ++
    ++    // wait patiently for the window manager death
    ++    const String16 name("window");
    ++    sp<IBinder> window(defaultServiceManager()->getService(name));
    ++    if (window != 0) {
    ++        window->linkToDeath(static_cast<IBinder::DeathRecipient*>(this));
    ++    }
    ++
    ++    // stop boot animation
    ++    // formerly we would just kill the process, but we now ask it to exit so it
    ++    // can choose where to stop the animation.
    ++    property_set("service.bootanim.exit", "1");
    ++
    ++    const int LOGTAG_SF_STOP_BOOTANIM = 60110;
    ++    LOG_EVENT_LONG(LOGTAG_SF_STOP_BOOTANIM,
    ++                   ns2ms(systemTime(SYSTEM_TIME_MONOTONIC)));
    ++}
    ++
    ++void SurfaceFlinger::deleteTextureAsync(uint32_t texture) {
    ++    class MessageDestroyGLTexture : public MessageBase {
    ++        RenderEngine& engine;
    ++        uint32_t texture;
    ++    public:
    ++        MessageDestroyGLTexture(RenderEngine& engine, uint32_t texture)
    ++            : engine(engine), texture(texture) {
    ++        }
    ++        virtual bool handler() {
    ++            engine.deleteTextures(1, &texture);
    ++            return true;
    ++        }
    ++    };
    ++    postMessageAsync(new MessageDestroyGLTexture(getRenderEngine(), texture));
    ++}
    ++
    ++class DispSyncSource : public VSyncSource, private DispSync::Callback {
    ++public:
    ++    DispSyncSource(DispSync* dispSync, nsecs_t phaseOffset, bool traceVsync,
    ++        const char* name) :
    ++            mName(name),
    ++            mValue(0),
    ++            mTraceVsync(traceVsync),
    ++            mVsyncOnLabel(String8::format("VsyncOn-%s", name)),
    ++            mVsyncEventLabel(String8::format("VSYNC-%s", name)),
    ++            mDispSync(dispSync),
    ++            mCallbackMutex(),
    ++            mCallback(),
    ++            mVsyncMutex(),
    ++            mPhaseOffset(phaseOffset),
    ++            mEnabled(false) {}
    ++
    ++    virtual ~DispSyncSource() {}
    ++
    ++    virtual void setVSyncEnabled(bool enable) {
    ++        Mutex::Autolock lock(mVsyncMutex);
    ++        if (enable) {
    ++            status_t err = mDispSync->addEventListener(mName, mPhaseOffset,
    ++                    static_cast<DispSync::Callback*>(this));
    ++            if (err != NO_ERROR) {
    ++                ALOGE("error registering vsync callback: %s (%d)",
    ++                        strerror(-err), err);
    ++            }
    ++            //ATRACE_INT(mVsyncOnLabel.string(), 1);
    ++        } else {
    ++            status_t err = mDispSync->removeEventListener(
    ++                    static_cast<DispSync::Callback*>(this));
    ++            if (err != NO_ERROR) {
    ++                ALOGE("error unregistering vsync callback: %s (%d)",
    ++                        strerror(-err), err);
    ++            }
    ++            //ATRACE_INT(mVsyncOnLabel.string(), 0);
    ++        }
    ++        mEnabled = enable;
    ++    }
    ++
    ++    virtual void setCallback(const sp<VSyncSource::Callback>& callback) {
    ++        Mutex::Autolock lock(mCallbackMutex);
    ++        mCallback = callback;
    ++    }
    ++
    ++    virtual void setPhaseOffset(nsecs_t phaseOffset) {
    ++        Mutex::Autolock lock(mVsyncMutex);
    ++
    ++        // Normalize phaseOffset to [0, period)
    ++        auto period = mDispSync->getPeriod();
    ++        phaseOffset %= period;
    ++        if (phaseOffset < 0) {
    ++            // If we're here, then phaseOffset is in (-period, 0). After this
    ++            // operation, it will be in (0, period)
    ++            phaseOffset += period;
    ++        }
    ++        mPhaseOffset = phaseOffset;
    ++
    ++        // If we're not enabled, we don't need to mess with the listeners
    ++        if (!mEnabled) {
    ++            return;
    ++        }
    ++
    ++        // Remove the listener with the old offset
    ++        status_t err = mDispSync->removeEventListener(
    ++                static_cast<DispSync::Callback*>(this));
    ++        if (err != NO_ERROR) {
    ++            ALOGE("error unregistering vsync callback: %s (%d)",
    ++                    strerror(-err), err);
    ++        }
    ++
    ++        // Add a listener with the new offset
    ++        err = mDispSync->addEventListener(mName, mPhaseOffset,
    ++                static_cast<DispSync::Callback*>(this));
    ++        if (err != NO_ERROR) {
    ++            ALOGE("error registering vsync callback: %s (%d)",
    ++                    strerror(-err), err);
    ++        }
    ++    }
    ++
    ++private:
    ++    virtual void onDispSyncEvent(nsecs_t when) {
    ++        sp<VSyncSource::Callback> callback;
    ++        {
    ++            Mutex::Autolock lock(mCallbackMutex);
    ++            callback = mCallback;
    ++
    ++            if (mTraceVsync) {
    ++                mValue = (mValue + 1) % 2;
    ++                ATRACE_INT(mVsyncEventLabel.string(), mValue);
    ++            }
    ++        }
    ++
    ++        if (callback != NULL) {
    ++            callback->onVSyncEvent(when);
    ++        }
    ++    }
    ++
    ++    const char* const mName;
    ++
    ++    int mValue;
    ++
    ++    const bool mTraceVsync;
    ++    const String8 mVsyncOnLabel;
    ++    const String8 mVsyncEventLabel;
    ++
    ++    DispSync* mDispSync;
    ++
    ++    Mutex mCallbackMutex; // Protects the following
    ++    sp<VSyncSource::Callback> mCallback;
    ++
    ++    Mutex mVsyncMutex; // Protects the following
    ++    nsecs_t mPhaseOffset;
    ++    bool mEnabled;
    ++};
    ++
    ++void SurfaceFlinger::init() {
    ++    ALOGI(  "SurfaceFlinger's main thread ready to run. "
    ++            "Initializing graphics H/W...");
    ++
    ++    Mutex::Autolock _l(mStateLock);
    ++
    ++    // initialize EGL for the default display
    ++    mEGLDisplay = eglGetDisplay(EGL_DEFAULT_DISPLAY);
    ++    eglInitialize(mEGLDisplay, NULL, NULL);
    ++
    ++    // start the EventThread
    ++    sp<VSyncSource> vsyncSrc = new DispSyncSource(&mPrimaryDispSync,
    ++            vsyncPhaseOffsetNs, true, "app");
    ++    mEventThread = new EventThread(vsyncSrc, *this);
    ++    sp<VSyncSource> sfVsyncSrc = new DispSyncSource(&mPrimaryDispSync,
    ++            sfVsyncPhaseOffsetNs, true, "sf");
    ++    mSFEventThread = new EventThread(sfVsyncSrc, *this);
    ++    mEventQueue.setEventThread(mSFEventThread);
    ++
    ++    // set SFEventThread to SCHED_FIFO to minimize jitter
    ++<<<<<<< HEAD
    ++    if (mSFEventThread != NULL) {
    ++        struct sched_param param = {0};
    ++        param.sched_priority = 1;
    ++        if (sched_setscheduler(mSFEventThread->getTid(), SCHED_FIFO, &param) != 0) {
    ++            ALOGE("Couldn't set SCHED_FIFO for SFEventThread");
    ++        }
    ++=======
    ++    struct sched_param param = {0};
    ++    param.sched_priority = 2;
    ++    if (sched_setscheduler(mSFEventThread->getTid(), SCHED_FIFO, &param) != 0) {
    ++        ALOGE("Couldn't set SCHED_FIFO for SFEventThread");
    ++>>>>>>> android-7.1.1_r1
    ++    }
    ++
    ++    // Initialize the H/W composer object.  There may or may not be an
    ++    // actual hardware composer underneath.
    ++    mHwc = new HWComposer(this,
    ++            *static_cast<HWComposer::EventHandler *>(this));
    ++
    ++    // get a RenderEngine for the given display / config (can't fail)
    ++    mRenderEngine = RenderEngine::create(mEGLDisplay, mHwc->getVisualID());
    ++
    ++    // retrieve the EGL context that was selected/created
    ++    mEGLContext = mRenderEngine->getEGLContext();
    ++
    ++    LOG_ALWAYS_FATAL_IF(mEGLContext == EGL_NO_CONTEXT,
    ++            "couldn't create EGLContext");
    ++
    ++    // initialize our non-virtual displays
    ++    for (size_t i=0 ; i<DisplayDevice::NUM_BUILTIN_DISPLAY_TYPES ; i++) {
    ++        DisplayDevice::DisplayType type((DisplayDevice::DisplayType)i);
    ++        // set-up the displays that are already connected
    ++        if (mHwc->isConnected(i) || type==DisplayDevice::DISPLAY_PRIMARY) {
    ++            // All non-virtual displays are currently considered secure.
    ++            bool isSecure = true;
    ++            createBuiltinDisplayLocked(type);
    ++            wp<IBinder> token = mBuiltinDisplays[i];
    ++
    ++            sp<IGraphicBufferProducer> producer;
    ++            sp<IGraphicBufferConsumer> consumer;
    ++            BufferQueue::createBufferQueue(&producer, &consumer,
    ++                    new GraphicBufferAlloc());
    ++
    ++            sp<FramebufferSurface> fbs = new FramebufferSurface(*mHwc, i,
    ++                    consumer);
    ++            int32_t hwcId = allocateHwcDisplayId(type);
    ++            sp<DisplayDevice> hw = new DisplayDevice(this,
    ++                    type, hwcId, mHwc->getFormat(hwcId), isSecure, token,
    ++                    fbs, producer,
    ++                    mRenderEngine->getEGLConfig());
    ++            if (i > DisplayDevice::DISPLAY_PRIMARY) {
    ++                // FIXME: currently we don't get blank/unblank requests
    ++                // for displays other than the main display, so we always
    ++                // assume a connected display is unblanked.
    ++                ALOGD("marking display %zu as acquired/unblanked", i);
    ++                hw->setPowerMode(HWC_POWER_MODE_NORMAL);
    ++            }
    ++            mDisplays.add(token, hw);
    ++        }
    ++    }
    ++
    ++    // make the GLContext current so that we can create textures when creating Layers
    ++    // (which may happens before we render something)
    ++    getDefaultDisplayDevice()->makeCurrent(mEGLDisplay, mEGLContext);
    ++
    ++    mEventControlThread = new EventControlThread(this);
    ++    mEventControlThread->run("EventControl", PRIORITY_URGENT_DISPLAY);
    ++
    ++    // set a fake vsync period if there is no HWComposer
    ++    if (mHwc->initCheck() != NO_ERROR) {
    ++        mPrimaryDispSync.setPeriod(16666667);
    ++    }
    ++
    ++    // initialize our drawing state
    ++    mDrawingState = mCurrentState;
    ++
    ++    // set initial conditions (e.g. unblank default device)
    ++    initializeDisplays();
    ++
    ++    mRenderEngine->primeCache();
    ++
    ++    // start boot animation
    ++    startBootAnim();
    ++}
    ++
    ++int32_t SurfaceFlinger::allocateHwcDisplayId(DisplayDevice::DisplayType type) {
    ++    return (uint32_t(type) < DisplayDevice::NUM_BUILTIN_DISPLAY_TYPES) ?
    ++            type : mHwc->allocateDisplayId();
    ++}
    ++
    ++void SurfaceFlinger::startBootAnim() {
    ++    // start boot animation
    ++    property_set("service.bootanim.exit", "0");
    ++    property_set("ctl.start", "bootanim");
    ++}
    ++
    ++size_t SurfaceFlinger::getMaxTextureSize() const {
    ++    return mRenderEngine->getMaxTextureSize();
    ++}
    ++
    ++size_t SurfaceFlinger::getMaxViewportDims() const {
    ++    return mRenderEngine->getMaxViewportDims();
    ++}
    ++
    ++// ----------------------------------------------------------------------------
    ++
    ++bool SurfaceFlinger::authenticateSurfaceTexture(
    ++        const sp<IGraphicBufferProducer>& bufferProducer) const {
    ++    Mutex::Autolock _l(mStateLock);
    ++    sp<IBinder> surfaceTextureBinder(IInterface::asBinder(bufferProducer));
    ++    return mGraphicBufferProducerList.indexOf(surfaceTextureBinder) >= 0;
    ++}
    ++
    ++status_t SurfaceFlinger::getDisplayConfigs(const sp<IBinder>& display,
    ++        Vector<DisplayInfo>* configs) {
    ++    if ((configs == NULL) || (display.get() == NULL)) {
    ++        return BAD_VALUE;
    ++    }
    ++
    ++    int32_t type = getDisplayType(display);
    ++    if (type < 0) return type;
    ++
    ++    // TODO: Not sure if display density should handled by SF any longer
    ++    class Density {
    ++        static int getDensityFromProperty(char const* propName) {
    ++            char property[PROPERTY_VALUE_MAX];
    ++            int density = 0;
    ++            if (property_get(propName, property, NULL) > 0) {
    ++                density = atoi(property);
    ++            }
    ++            return density;
    ++        }
    ++    public:
    ++        static int getEmuDensity() {
    ++            return getDensityFromProperty("qemu.sf.lcd_density"); }
    ++        static int getBuildDensity()  {
    ++            return getDensityFromProperty("ro.sf.lcd_density"); }
    ++    };
    ++
    ++    configs->clear();
    ++
    ++    const Vector<HWComposer::DisplayConfig>& hwConfigs =
    ++            getHwComposer().getConfigs(type);
    ++    for (size_t c = 0; c < hwConfigs.size(); ++c) {
    ++        const HWComposer::DisplayConfig& hwConfig = hwConfigs[c];
    ++        DisplayInfo info = DisplayInfo();
    ++
    ++        float xdpi = hwConfig.xdpi;
    ++        float ydpi = hwConfig.ydpi;
    ++
    ++        if (type == DisplayDevice::DISPLAY_PRIMARY) {
    ++            // The density of the device is provided by a build property
    ++            float density = Density::getBuildDensity() / 160.0f;
    ++            if (density == 0) {
    ++                // the build doesn't provide a density -- this is wrong!
    ++                // use xdpi instead
    ++                ALOGE("ro.sf.lcd_density must be defined as a build property");
    ++                density = xdpi / 160.0f;
    ++            }
    ++            if (Density::getEmuDensity()) {
    ++                // if "qemu.sf.lcd_density" is specified, it overrides everything
    ++                xdpi = ydpi = density = Density::getEmuDensity();
    ++                density /= 160.0f;
    ++            }
    ++            info.density = density;
    ++
    ++            // TODO: this needs to go away (currently needed only by webkit)
    ++            sp<const DisplayDevice> hw(getDefaultDisplayDevice());
    ++            info.orientation = hw->getOrientation();
    ++        } else {
    ++            // TODO: where should this value come from?
    ++            static const int TV_DENSITY = 213;
    ++            info.density = TV_DENSITY / 160.0f;
    ++            info.orientation = 0;
    ++        }
    ++
    ++        char value[PROPERTY_VALUE_MAX];
    ++        property_get("ro.sf.hwrotation", value, "0");
    ++        int additionalRot = atoi(value) / 90;
    ++        if ((type == DisplayDevice::DISPLAY_PRIMARY) && (additionalRot & DisplayState::eOrientationSwapMask)) {
    ++            info.h = hwConfig.width;
    ++            info.w = hwConfig.height;
    ++            info.xdpi = ydpi;
    ++            info.ydpi = xdpi;
    ++        }
    ++        else {
    ++            info.w = hwConfig.width;
    ++            info.h = hwConfig.height;
    ++            info.xdpi = xdpi;
    ++            info.ydpi = ydpi;
    ++        }
    ++        info.fps = float(1e9 / hwConfig.refresh);
    ++        info.appVsyncOffset = VSYNC_EVENT_PHASE_OFFSET_NS;
    ++
    ++        // This is how far in advance a buffer must be queued for
    ++        // presentation at a given time.  If you want a buffer to appear
    ++        // on the screen at time N, you must submit the buffer before
    ++        // (N - presentationDeadline).
    ++        //
    ++        // Normally it's one full refresh period (to give SF a chance to
    ++        // latch the buffer), but this can be reduced by configuring a
    ++        // DispSync offset.  Any additional delays introduced by the hardware
    ++        // composer or panel must be accounted for here.
    ++        //
    ++        // We add an additional 1ms to allow for processing time and
    ++        // differences between the ideal and actual refresh rate.
    ++        info.presentationDeadline =
    ++                hwConfig.refresh - SF_VSYNC_EVENT_PHASE_OFFSET_NS + 1000000;
    ++
    ++        // All non-virtual displays are currently considered secure.
    ++        info.secure = true;
    ++
    ++        configs->push_back(info);
    ++    }
    ++
    ++    return NO_ERROR;
    ++}
    ++
    ++status_t SurfaceFlinger::getDisplayStats(const sp<IBinder>& /* display */,
    ++        DisplayStatInfo* stats) {
    ++    if (stats == NULL) {
    ++        return BAD_VALUE;
    ++    }
    ++
    ++    // FIXME for now we always return stats for the primary display
    ++    memset(stats, 0, sizeof(*stats));
    ++    stats->vsyncTime   = mPrimaryDispSync.computeNextRefresh(0);
    ++    stats->vsyncPeriod = mPrimaryDispSync.getPeriod();
    ++    return NO_ERROR;
    ++}
    ++
    ++int SurfaceFlinger::getActiveConfig(const sp<IBinder>& display) {
    ++    sp<DisplayDevice> device(getDisplayDevice(display));
    ++    if (device != NULL) {
    ++        return device->getActiveConfig();
    ++    }
    ++    return BAD_VALUE;
    ++}
    ++
    ++void SurfaceFlinger::setActiveConfigInternal(const sp<DisplayDevice>& hw, int mode) {
    ++    ALOGD("Set active config mode=%d, type=%d flinger=%p", mode, hw->getDisplayType(),
    ++          this);
    ++    int32_t type = hw->getDisplayType();
    ++    int currentMode = hw->getActiveConfig();
    ++
    ++    if (mode == currentMode) {
    ++        ALOGD("Screen type=%d is already mode=%d", hw->getDisplayType(), mode);
    ++        return;
    ++    }
    ++
    ++    if (type >= DisplayDevice::NUM_BUILTIN_DISPLAY_TYPES) {
    ++        ALOGW("Trying to set config for virtual display");
    ++        return;
    ++    }
    ++
    ++    hw->setActiveConfig(mode);
    ++    getHwComposer().setActiveConfig(type, mode);
    ++}
    ++
    ++status_t SurfaceFlinger::setActiveConfig(const sp<IBinder>& display, int mode) {
    ++    class MessageSetActiveConfig: public MessageBase {
    ++        SurfaceFlinger& mFlinger;
    ++        sp<IBinder> mDisplay;
    ++        int mMode;
    ++    public:
    ++        MessageSetActiveConfig(SurfaceFlinger& flinger, const sp<IBinder>& disp,
    ++                               int mode) :
    ++            mFlinger(flinger), mDisplay(disp) { mMode = mode; }
    ++        virtual bool handler() {
    ++            Vector<DisplayInfo> configs;
    ++            mFlinger.getDisplayConfigs(mDisplay, &configs);
    ++            if (mMode < 0 || mMode >= static_cast<int>(configs.size())) {
    ++                ALOGE("Attempt to set active config = %d for display with %zu configs",
    ++                        mMode, configs.size());
    ++            }
    ++            sp<DisplayDevice> hw(mFlinger.getDisplayDevice(mDisplay));
    ++            if (hw == NULL) {
    ++                ALOGE("Attempt to set active config = %d for null display %p",
    ++                        mMode, mDisplay.get());
    ++            } else if (hw->getDisplayType() >= DisplayDevice::DISPLAY_VIRTUAL) {
    ++                ALOGW("Attempt to set active config = %d for virtual display",
    ++                        mMode);
    ++            } else {
    ++                mFlinger.setActiveConfigInternal(hw, mMode);
    ++            }
    ++            return true;
    ++        }
    ++    };
    ++    sp<MessageBase> msg = new MessageSetActiveConfig(*this, display, mode);
    ++    postMessageSync(msg);
    ++    return NO_ERROR;
    ++}
    ++
    ++status_t SurfaceFlinger::getDisplayColorModes(const sp<IBinder>& display,
    ++        Vector<android_color_mode_t>* outColorModes) {
    ++    if (outColorModes == nullptr || display.get() == nullptr) {
    ++        return BAD_VALUE;
    ++    }
    ++
    ++    int32_t type = getDisplayType(display);
    ++    if (type < 0) return type;
    ++
    ++    std::set<android_color_mode_t> colorModes;
    ++    for (const HWComposer::DisplayConfig& hwConfig : getHwComposer().getConfigs(type)) {
    ++        colorModes.insert(hwConfig.colorMode);
    ++    }
    ++
    ++    outColorModes->clear();
    ++    std::copy(colorModes.cbegin(), colorModes.cend(), std::back_inserter(*outColorModes));
    ++
    ++    return NO_ERROR;
    ++}
    ++
    ++android_color_mode_t SurfaceFlinger::getActiveColorMode(const sp<IBinder>& display) {
    ++    if (display.get() == nullptr) return static_cast<android_color_mode_t>(BAD_VALUE);
    ++
    ++    int32_t type = getDisplayType(display);
    ++    if (type < 0) return static_cast<android_color_mode_t>(type);
    ++
    ++    return getHwComposer().getColorMode(type);
    ++}
    ++
    ++status_t SurfaceFlinger::setActiveColorMode(const sp<IBinder>& display,
    ++        android_color_mode_t colorMode) {
    ++    if (display.get() == nullptr || colorMode < 0) {
    ++        return BAD_VALUE;
    ++    }
    ++
    ++    int32_t type = getDisplayType(display);
    ++    if (type < 0) return type;
    ++    const Vector<HWComposer::DisplayConfig>& hwConfigs = getHwComposer().getConfigs(type);
    ++    HWComposer::DisplayConfig desiredConfig = hwConfigs[getHwComposer().getCurrentConfig(type)];
    ++    desiredConfig.colorMode = colorMode;
    ++    for (size_t c = 0; c < hwConfigs.size(); ++c) {
    ++        const HWComposer::DisplayConfig config = hwConfigs[c];
    ++        if (config == desiredConfig) {
    ++            return setActiveConfig(display, c);
    ++        }
    ++    }
    ++    return BAD_VALUE;
    ++}
    ++
    ++status_t SurfaceFlinger::clearAnimationFrameStats() {
    ++    Mutex::Autolock _l(mStateLock);
    ++    mAnimFrameTracker.clearStats();
    ++    return NO_ERROR;
    ++}
    ++
    ++status_t SurfaceFlinger::getAnimationFrameStats(FrameStats* outStats) const {
    ++    Mutex::Autolock _l(mStateLock);
    ++    mAnimFrameTracker.getStats(outStats);
    ++    return NO_ERROR;
    ++}
    ++
    ++status_t SurfaceFlinger::getHdrCapabilities(const sp<IBinder>& /*display*/,
    ++        HdrCapabilities* outCapabilities) const {
    ++    // HWC1 does not provide HDR capabilities
    ++    *outCapabilities = HdrCapabilities();
    ++    return NO_ERROR;
    ++}
    ++
    ++// ----------------------------------------------------------------------------
    ++
    ++sp<IDisplayEventConnection> SurfaceFlinger::createDisplayEventConnection() {
    ++    return mEventThread->createEventConnection();
    ++}
    ++
    ++// ----------------------------------------------------------------------------
    ++
    ++void SurfaceFlinger::waitForEvent() {
    ++    mEventQueue.waitMessage();
    ++}
    ++
    ++void SurfaceFlinger::signalTransaction() {
    ++    mEventQueue.invalidate();
    ++}
    ++
    ++void SurfaceFlinger::signalLayerUpdate() {
    ++    mEventQueue.invalidate();
    ++}
    ++
    ++void SurfaceFlinger::signalRefresh() {
    ++    mEventQueue.refresh();
    ++}
    ++
    ++status_t SurfaceFlinger::postMessageAsync(const sp<MessageBase>& msg,
    ++        nsecs_t reltime, uint32_t /* flags */) {
    ++    return mEventQueue.postMessage(msg, reltime);
    ++}
    ++
    ++status_t SurfaceFlinger::postMessageSync(const sp<MessageBase>& msg,
    ++        nsecs_t reltime, uint32_t /* flags */) {
    ++    status_t res = mEventQueue.postMessage(msg, reltime);
    ++    if (res == NO_ERROR) {
    ++        msg->wait();
    ++    }
    ++    return res;
    ++}
    ++
    ++void SurfaceFlinger::run() {
    ++    do {
    ++        waitForEvent();
    ++    } while (true);
    ++}
    ++
    ++void SurfaceFlinger::enableHardwareVsync() {
    ++    Mutex::Autolock _l(mHWVsyncLock);
    ++    if (!mPrimaryHWVsyncEnabled && mHWVsyncAvailable) {
    ++        mPrimaryDispSync.beginResync();
    ++        //eventControl(HWC_DISPLAY_PRIMARY, SurfaceFlinger::EVENT_VSYNC, true);
    ++        mEventControlThread->setVsyncEnabled(true);
    ++        mPrimaryHWVsyncEnabled = true;
    ++    }
    ++}
    ++
    ++void SurfaceFlinger::resyncToHardwareVsync(bool makeAvailable) {
    ++    Mutex::Autolock _l(mHWVsyncLock);
    ++
    ++    if (makeAvailable) {
    ++        mHWVsyncAvailable = true;
    ++    } else if (!mHWVsyncAvailable) {
    ++        // Hardware vsync is not currently available, so abort the resync
    ++        // attempt for now
    ++        return;
    ++    }
    ++
    ++    const nsecs_t period =
    ++            getHwComposer().getRefreshPeriod(HWC_DISPLAY_PRIMARY);
    ++
    ++    mPrimaryDispSync.reset();
    ++    mPrimaryDispSync.setPeriod(period);
    ++
    ++    if (!mPrimaryHWVsyncEnabled) {
    ++        mPrimaryDispSync.beginResync();
    ++        //eventControl(HWC_DISPLAY_PRIMARY, SurfaceFlinger::EVENT_VSYNC, true);
    ++        mEventControlThread->setVsyncEnabled(true);
    ++        mPrimaryHWVsyncEnabled = true;
    ++    }
    ++}
    ++
    ++void SurfaceFlinger::disableHardwareVsync(bool makeUnavailable) {
    ++    Mutex::Autolock _l(mHWVsyncLock);
    ++    if (mPrimaryHWVsyncEnabled) {
    ++        //eventControl(HWC_DISPLAY_PRIMARY, SurfaceFlinger::EVENT_VSYNC, false);
    ++        mEventControlThread->setVsyncEnabled(false);
    ++        mPrimaryDispSync.endResync();
    ++        mPrimaryHWVsyncEnabled = false;
    ++    }
    ++    if (makeUnavailable) {
    ++        mHWVsyncAvailable = false;
    ++    }
    ++}
    ++
    ++void SurfaceFlinger::resyncWithRateLimit() {
    ++    static constexpr nsecs_t kIgnoreDelay = ms2ns(500);
    ++    if (systemTime() - mLastSwapTime > kIgnoreDelay) {
    ++        resyncToHardwareVsync(false);
    ++    }
    ++}
    ++
    ++void SurfaceFlinger::onVSyncReceived(int type, nsecs_t timestamp) {
    ++    bool needsHwVsync = false;
    ++
    ++    { // Scope for the lock
    ++        Mutex::Autolock _l(mHWVsyncLock);
    ++        if (type == 0 && mPrimaryHWVsyncEnabled) {
    ++            needsHwVsync = mPrimaryDispSync.addResyncSample(timestamp);
    ++        }
    ++    }
    ++
    ++    if (needsHwVsync) {
    ++        enableHardwareVsync();
    ++    } else {
    ++        disableHardwareVsync(false);
    ++    }
    ++}
    ++
    ++void SurfaceFlinger::onHotplugReceived(int type, bool connected) {
    ++    if (mEventThread == NULL) {
    ++        // This is a temporary workaround for b/7145521.  A non-null pointer
    ++        // does not mean EventThread has finished initializing, so this
    ++        // is not a correct fix.
    ++        ALOGW("WARNING: EventThread not started, ignoring hotplug");
    ++        return;
    ++    }
    ++
    ++    if (uint32_t(type) < DisplayDevice::NUM_BUILTIN_DISPLAY_TYPES) {
    ++        Mutex::Autolock _l(mStateLock);
    ++        if (connected) {
    ++            createBuiltinDisplayLocked((DisplayDevice::DisplayType)type);
    ++        } else {
    ++            mCurrentState.displays.removeItem(mBuiltinDisplays[type]);
    ++            mBuiltinDisplays[type].clear();
    ++        }
    ++        setTransactionFlags(eDisplayTransactionNeeded);
    ++
    ++        // Defer EventThread notification until SF has updated mDisplays.
    ++    }
    ++}
    ++
    ++void SurfaceFlinger::eventControl(int disp, int event, int enabled) {
    ++    ATRACE_CALL();
    ++    getHwComposer().eventControl(disp, event, enabled);
    ++}
    ++
    ++void SurfaceFlinger::onMessageReceived(int32_t what) {
    ++    ATRACE_CALL();
    ++    switch (what) {
    ++        case MessageQueue::INVALIDATE: {
    ++            bool refreshNeeded = handleMessageTransaction();
    ++            refreshNeeded |= handleMessageInvalidate();
    ++            refreshNeeded |= mRepaintEverything;
    ++            if (refreshNeeded) {
    ++                // Signal a refresh if a transaction modified the window state,
    ++                // a new buffer was latched, or if HWC has requested a full
    ++                // repaint
    ++                signalRefresh();
    ++            }
    ++            break;
    ++        }
    ++        case MessageQueue::REFRESH: {
    ++            handleMessageRefresh();
    ++            break;
    ++        }
    ++    }
    ++}
    ++
    ++bool SurfaceFlinger::handleMessageTransaction() {
    ++    uint32_t transactionFlags = peekTransactionFlags(eTransactionMask);
    ++    if (transactionFlags) {
    ++        handleTransaction(transactionFlags);
    ++        return true;
    ++    }
    ++    return false;
    ++}
    ++
    ++bool SurfaceFlinger::handleMessageInvalidate() {
    ++    ATRACE_CALL();
    ++    return handlePageFlip();
    ++}
    ++
    ++void SurfaceFlinger::handleMessageRefresh() {
    ++    ATRACE_CALL();
    ++
    ++    nsecs_t refreshStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
    ++
    ++    preComposition();
    ++    rebuildLayerStacks();
    ++    setUpHWComposer();
    ++    doDebugFlashRegions();
    ++    doComposition();
    ++    postComposition(refreshStartTime);
    ++}
    ++
    ++void SurfaceFlinger::doDebugFlashRegions()
    ++{
    ++    // is debugging enabled
    ++    if (CC_LIKELY(!mDebugRegion))
    ++        return;
    ++
    ++    const bool repaintEverything = mRepaintEverything;
    ++    for (size_t dpy=0 ; dpy<mDisplays.size() ; dpy++) {
    ++        const sp<DisplayDevice>& hw(mDisplays[dpy]);
    ++        if (hw->isDisplayOn()) {
    ++            // transform the dirty region into this screen's coordinate space
    ++            const Region dirtyRegion(hw->getDirtyRegion(repaintEverything));
    ++            if (!dirtyRegion.isEmpty()) {
    ++                // redraw the whole screen
    ++                doComposeSurfaces(hw, Region(hw->bounds()));
    ++
    ++                // and draw the dirty region
    ++                const int32_t height = hw->getHeight();
    ++                RenderEngine& engine(getRenderEngine());
    ++                engine.fillRegionWithColor(dirtyRegion, height, 1, 0, 1, 1);
    ++
    ++                hw->compositionComplete();
    ++                hw->swapBuffers(getHwComposer());
    ++            }
    ++        }
    ++    }
    ++
    ++    postFramebuffer();
    ++
    ++    if (mDebugRegion > 1) {
    ++        usleep(mDebugRegion * 1000);
    ++    }
    ++
    ++    HWComposer& hwc(getHwComposer());
    ++    if (hwc.initCheck() == NO_ERROR) {
    ++        status_t err = hwc.prepare();
    ++        ALOGE_IF(err, "HWComposer::prepare failed (%s)", strerror(-err));
    ++    }
    ++}
    ++
    ++void SurfaceFlinger::preComposition()
    ++{
    ++    bool needExtraInvalidate = false;
    ++    const LayerVector& layers(mDrawingState.layersSortedByZ);
    ++    const size_t count = layers.size();
    ++    for (size_t i=0 ; i<count ; i++) {
    ++        if (layers[i]->onPreComposition()) {
    ++            needExtraInvalidate = true;
    ++        }
    ++    }
    ++    if (needExtraInvalidate) {
    ++        signalLayerUpdate();
    ++    }
    ++}
    ++
    ++void SurfaceFlinger::postComposition(nsecs_t refreshStartTime)
    ++{
    ++    const LayerVector& layers(mDrawingState.layersSortedByZ);
    ++    const size_t count = layers.size();
    ++    for (size_t i=0 ; i<count ; i++) {
    ++        bool frameLatched = layers[i]->onPostComposition();
    ++        if (frameLatched) {
    ++            recordBufferingStats(layers[i]->getName().string(),
    ++                    layers[i]->getOccupancyHistory(false));
    ++        }
    ++    }
    ++
    ++    const HWComposer& hwc = getHwComposer();
    ++    sp<Fence> presentFence = hwc.getDisplayFence(HWC_DISPLAY_PRIMARY);
    ++
    ++    if (presentFence->isValid()) {
    ++        if (mPrimaryDispSync.addPresentFence(presentFence)) {
    ++            enableHardwareVsync();
    ++        } else {
    ++            disableHardwareVsync(false);
    ++        }
    ++    }
    ++
    ++    const sp<const DisplayDevice> hw(getDefaultDisplayDevice());
    ++    if (kIgnorePresentFences) {
    ++        if (hw->isDisplayOn()) {
    ++            enableHardwareVsync();
    ++        }
    ++    }
    ++
    ++    mFenceTracker.addFrame(refreshStartTime, presentFence,
    ++            hw->getVisibleLayersSortedByZ(), hw->getClientTargetAcquireFence());
    ++
    ++    if (mAnimCompositionPending) {
    ++        mAnimCompositionPending = false;
    ++
    ++        if (presentFence->isValid()) {
    ++            mAnimFrameTracker.setActualPresentFence(presentFence);
    ++        } else {
    ++            // The HWC doesn't support present fences, so use the refresh
    ++            // timestamp instead.
    ++            nsecs_t presentTime = hwc.getRefreshTimestamp(HWC_DISPLAY_PRIMARY);
    ++            mAnimFrameTracker.setActualPresentTime(presentTime);
    ++        }
    ++        mAnimFrameTracker.advanceFrame();
    ++    }
    ++
    ++    if (hw->getPowerMode() == HWC_POWER_MODE_OFF) {
    ++        return;
    ++    }
    ++
    ++    nsecs_t currentTime = systemTime();
    ++    if (mHasPoweredOff) {
    ++        mHasPoweredOff = false;
    ++    } else {
    ++        nsecs_t period = mPrimaryDispSync.getPeriod();
    ++        nsecs_t elapsedTime = currentTime - mLastSwapTime;
    ++        size_t numPeriods = static_cast<size_t>(elapsedTime / period);
    ++        if (numPeriods < NUM_BUCKETS - 1) {
    ++            mFrameBuckets[numPeriods] += elapsedTime;
    ++        } else {
    ++            mFrameBuckets[NUM_BUCKETS - 1] += elapsedTime;
    ++        }
    ++        mTotalTime += elapsedTime;
    ++    }
    ++    mLastSwapTime = currentTime;
    ++}
    ++
    ++void SurfaceFlinger::rebuildLayerStacks() {
    ++    // rebuild the visible layer list per screen
    ++    if (CC_UNLIKELY(mVisibleRegionsDirty)) {
    ++        ATRACE_CALL();
    ++        mVisibleRegionsDirty = false;
    ++        invalidateHwcGeometry();
    ++
    ++        const LayerVector& layers(mDrawingState.layersSortedByZ);
    ++        for (size_t dpy=0 ; dpy<mDisplays.size() ; dpy++) {
    ++            Region opaqueRegion;
    ++            Region dirtyRegion;
    ++            Vector< sp<Layer> > layersSortedByZ;
    ++            const sp<DisplayDevice>& hw(mDisplays[dpy]);
    ++            const Transform& tr(hw->getTransform());
    ++            const Rect bounds(hw->getBounds());
    ++            if (hw->isDisplayOn()) {
    ++                SurfaceFlinger::computeVisibleRegions(layers,
    ++                        hw->getLayerStack(), dirtyRegion, opaqueRegion);
    ++
    ++                const size_t count = layers.size();
    ++                for (size_t i=0 ; i<count ; i++) {
    ++                    const sp<Layer>& layer(layers[i]);
    ++                    const Layer::State& s(layer->getDrawingState());
    ++                    if (s.layerStack == hw->getLayerStack()) {
    ++                        Region drawRegion(tr.transform(
    ++                                layer->visibleNonTransparentRegion));
    ++                        drawRegion.andSelf(bounds);
    ++                        if (!drawRegion.isEmpty()) {
    ++                            layersSortedByZ.add(layer);
    ++                        }
    ++                    }
    ++                }
    ++            }
    ++            hw->setVisibleLayersSortedByZ(layersSortedByZ);
    ++            hw->undefinedRegion.set(bounds);
    ++            hw->undefinedRegion.subtractSelf(tr.transform(opaqueRegion));
    ++            hw->dirtyRegion.orSelf(dirtyRegion);
    ++        }
    ++    }
    ++}
    ++
    ++void SurfaceFlinger::setUpHWComposer() {
    ++    for (size_t dpy=0 ; dpy<mDisplays.size() ; dpy++) {
    ++        bool dirty = !mDisplays[dpy]->getDirtyRegion(false).isEmpty();
    ++        bool empty = mDisplays[dpy]->getVisibleLayersSortedByZ().size() == 0;
    ++        bool wasEmpty = !mDisplays[dpy]->lastCompositionHadVisibleLayers;
    ++
    ++        // If nothing has changed (!dirty), don't recompose.
    ++        // If something changed, but we don't currently have any visible layers,
    ++        //   and didn't when we last did a composition, then skip it this time.
    ++        // The second rule does two things:
    ++        // - When all layers are removed from a display, we'll emit one black
    ++        //   frame, then nothing more until we get new layers.
    ++        // - When a display is created with a private layer stack, we won't
    ++        //   emit any black frames until a layer is added to the layer stack.
    ++        bool mustRecompose = dirty && !(empty && wasEmpty);
    ++
    ++        ALOGV_IF(mDisplays[dpy]->getDisplayType() == DisplayDevice::DISPLAY_VIRTUAL,
    ++                "dpy[%zu]: %s composition (%sdirty %sempty %swasEmpty)", dpy,
    ++                mustRecompose ? "doing" : "skipping",
    ++                dirty ? "+" : "-",
    ++                empty ? "+" : "-",
    ++                wasEmpty ? "+" : "-");
    ++
    ++        mDisplays[dpy]->beginFrame(mustRecompose);
    ++
    ++        if (mustRecompose) {
    ++            mDisplays[dpy]->lastCompositionHadVisibleLayers = !empty;
    ++        }
    ++    }
    ++
    ++    HWComposer& hwc(getHwComposer());
    ++    if (hwc.initCheck() == NO_ERROR) {
    ++        // build the h/w work list
    ++        if (CC_UNLIKELY(mHwWorkListDirty)) {
    ++            mHwWorkListDirty = false;
    ++            for (size_t dpy=0 ; dpy<mDisplays.size() ; dpy++) {
    ++                sp<const DisplayDevice> hw(mDisplays[dpy]);
    ++                const int32_t id = hw->getHwcDisplayId();
    ++                if (id >= 0) {
    ++                    const Vector< sp<Layer> >& currentLayers(
    ++                        hw->getVisibleLayersSortedByZ());
    ++                    const size_t count = currentLayers.size();
    ++                    if (hwc.createWorkList(id, count) == NO_ERROR) {
    ++                        HWComposer::LayerListIterator cur = hwc.begin(id);
    ++                        const HWComposer::LayerListIterator end = hwc.end(id);
    ++                        for (size_t i=0 ; cur!=end && i<count ; ++i, ++cur) {
    ++                            const sp<Layer>& layer(currentLayers[i]);
    ++                            layer->setGeometry(hw, *cur);
    ++                            if (mDebugDisableHWC || mDebugRegion || mDaltonize || mHasColorMatrix) {
    ++                                cur->setSkip(true);
    ++                            }
    ++                        }
    ++                    }
    ++                }
    ++            }
    ++        }
    ++
    ++        // set the per-frame data
    ++        for (size_t dpy=0 ; dpy<mDisplays.size() ; dpy++) {
    ++            sp<const DisplayDevice> hw(mDisplays[dpy]);
    ++            const int32_t id = hw->getHwcDisplayId();
    ++            if (id >= 0) {
    ++                const Vector< sp<Layer> >& currentLayers(
    ++                    hw->getVisibleLayersSortedByZ());
    ++                const size_t count = currentLayers.size();
    ++                HWComposer::LayerListIterator cur = hwc.begin(id);
    ++                const HWComposer::LayerListIterator end = hwc.end(id);
    ++                for (size_t i=0 ; cur!=end && i<count ; ++i, ++cur) {
    ++                    /*
    ++                     * update the per-frame h/w composer data for each layer
    ++                     * and build the transparent region of the FB
    ++                     */
    ++                    const sp<Layer>& layer(currentLayers[i]);
    ++                    layer->setPerFrameData(hw, *cur);
    ++                }
    ++            }
    ++        }
    ++
    ++        // If possible, attempt to use the cursor overlay on each display.
    ++        for (size_t dpy=0 ; dpy<mDisplays.size() ; dpy++) {
    ++            sp<const DisplayDevice> hw(mDisplays[dpy]);
    ++            const int32_t id = hw->getHwcDisplayId();
    ++            if (id >= 0) {
    ++                const Vector< sp<Layer> >& currentLayers(
    ++                    hw->getVisibleLayersSortedByZ());
    ++                const size_t count = currentLayers.size();
    ++                HWComposer::LayerListIterator cur = hwc.begin(id);
    ++                const HWComposer::LayerListIterator end = hwc.end(id);
    ++                for (size_t i=0 ; cur!=end && i<count ; ++i, ++cur) {
    ++                    const sp<Layer>& layer(currentLayers[i]);
    ++                    if (layer->isPotentialCursor()) {
    ++                        cur->setIsCursorLayerHint();
    ++                        break;
    ++                    }
    ++                }
    ++            }
    ++        }
    ++
    ++        status_t err = hwc.prepare();
    ++        ALOGE_IF(err, "HWComposer::prepare failed (%s)", strerror(-err));
    ++
    ++        for (size_t dpy=0 ; dpy<mDisplays.size() ; dpy++) {
    ++            sp<const DisplayDevice> hw(mDisplays[dpy]);
    ++            hw->prepareFrame(hwc);
    ++        }
    ++    }
    ++}
    ++
    ++void SurfaceFlinger::doComposition() {
    ++    ATRACE_CALL();
    ++    const bool repaintEverything = android_atomic_and(0, &mRepaintEverything);
    ++    for (size_t dpy=0 ; dpy<mDisplays.size() ; dpy++) {
    ++        const sp<DisplayDevice>& hw(mDisplays[dpy]);
    ++        if (hw->isDisplayOn()) {
    ++            // transform the dirty region into this screen's coordinate space
    ++            const Region dirtyRegion(hw->getDirtyRegion(repaintEverything));
    ++
    ++            // repaint the framebuffer (if needed)
    ++            doDisplayComposition(hw, dirtyRegion);
    ++
    ++            hw->dirtyRegion.clear();
    ++            hw->flip(hw->swapRegion);
    ++            hw->swapRegion.clear();
    ++        }
    ++        // inform the h/w that we're done compositing
    ++        hw->compositionComplete();
    ++    }
    ++    postFramebuffer();
    ++}
    ++
    ++void SurfaceFlinger::postFramebuffer()
    ++{
    ++    ATRACE_CALL();
    ++
    ++    const nsecs_t now = systemTime();
    ++    mDebugInSwapBuffers = now;
    ++
    ++    HWComposer& hwc(getHwComposer());
    ++    if (hwc.initCheck() == NO_ERROR) {
    ++        if (!hwc.supportsFramebufferTarget()) {
    ++            // EGL spec says:
    ++            //   "surface must be bound to the calling thread's current context,
    ++            //    for the current rendering API."
    ++            getDefaultDisplayDevice()->makeCurrent(mEGLDisplay, mEGLContext);
    ++        }
    ++        hwc.commit();
    ++    }
    ++
    ++    // make the default display current because the VirtualDisplayDevice code cannot
    ++    // deal with dequeueBuffer() being called outside of the composition loop; however
    ++    // the code below can call glFlush() which is allowed (and does in some case) call
    ++    // dequeueBuffer().
    ++    getDefaultDisplayDevice()->makeCurrent(mEGLDisplay, mEGLContext);
    ++
    ++    for (size_t dpy=0 ; dpy<mDisplays.size() ; dpy++) {
    ++        sp<const DisplayDevice> hw(mDisplays[dpy]);
    ++        const Vector< sp<Layer> >& currentLayers(hw->getVisibleLayersSortedByZ());
    ++        hw->onSwapBuffersCompleted(hwc);
    ++        const size_t count = currentLayers.size();
    ++        int32_t id = hw->getHwcDisplayId();
    ++        if (id >=0 && hwc.initCheck() == NO_ERROR) {
    ++            HWComposer::LayerListIterator cur = hwc.begin(id);
    ++            const HWComposer::LayerListIterator end = hwc.end(id);
    ++            for (size_t i = 0; cur != end && i < count; ++i, ++cur) {
    ++                currentLayers[i]->onLayerDisplayed(hw, &*cur);
    ++            }
    ++        } else {
    ++            for (size_t i = 0; i < count; i++) {
    ++                currentLayers[i]->onLayerDisplayed(hw, NULL);
    ++            }
    ++        }
    ++    }
    ++
    ++    mLastSwapBufferTime = systemTime() - now;
    ++    mDebugInSwapBuffers = 0;
    ++
    ++    uint32_t flipCount = getDefaultDisplayDevice()->getPageFlipCount();
    ++    if (flipCount % LOG_FRAME_STATS_PERIOD == 0) {
    ++        logFrameStats();
    ++    }
    ++}
    ++
    ++void SurfaceFlinger::handleTransaction(uint32_t transactionFlags)
    ++{
    ++    ATRACE_CALL();
    ++
    ++    // here we keep a copy of the drawing state (that is the state that's
    ++    // going to be overwritten by handleTransactionLocked()) outside of
    ++    // mStateLock so that the side-effects of the State assignment
    ++    // don't happen with mStateLock held (which can cause deadlocks).
    ++    State drawingState(mDrawingState);
    ++
    ++    Mutex::Autolock _l(mStateLock);
    ++    const nsecs_t now = systemTime();
    ++    mDebugInTransaction = now;
    ++
    ++    // Here we're guaranteed that some transaction flags are set
    ++    // so we can call handleTransactionLocked() unconditionally.
    ++    // We call getTransactionFlags(), which will also clear the flags,
    ++    // with mStateLock held to guarantee that mCurrentState won't change
    ++    // until the transaction is committed.
    ++
    ++    transactionFlags = getTransactionFlags(eTransactionMask);
    ++    handleTransactionLocked(transactionFlags);
    ++
    ++    mLastTransactionTime = systemTime() - now;
    ++    mDebugInTransaction = 0;
    ++    invalidateHwcGeometry();
    ++    // here the transaction has been committed
    ++}
    ++
    ++void SurfaceFlinger::handleTransactionLocked(uint32_t transactionFlags)
    ++{
    ++    const LayerVector& currentLayers(mCurrentState.layersSortedByZ);
    ++    const size_t count = currentLayers.size();
    ++
    ++    // Notify all layers of available frames
    ++    for (size_t i = 0; i < count; ++i) {
    ++        currentLayers[i]->notifyAvailableFrames();
    ++    }
    ++
    ++    /*
    ++     * Traversal of the children
    ++     * (perform the transaction for each of them if needed)
    ++     */
    ++
    ++    if (transactionFlags & eTraversalNeeded) {
    ++        for (size_t i=0 ; i<count ; i++) {
    ++            const sp<Layer>& layer(currentLayers[i]);
    ++            uint32_t trFlags = layer->getTransactionFlags(eTransactionNeeded);
    ++            if (!trFlags) continue;
    ++
    ++            const uint32_t flags = layer->doTransaction(0);
    ++            if (flags & Layer::eVisibleRegion)
    ++                mVisibleRegionsDirty = true;
    ++        }
    ++    }
    ++
    ++    /*
    ++     * Perform display own transactions if needed
    ++     */
    ++
    ++    if (transactionFlags & eDisplayTransactionNeeded) {
    ++        // here we take advantage of Vector's copy-on-write semantics to
    ++        // improve performance by skipping the transaction entirely when
    ++        // know that the lists are identical
    ++        const KeyedVector<  wp<IBinder>, DisplayDeviceState>& curr(mCurrentState.displays);
    ++        const KeyedVector<  wp<IBinder>, DisplayDeviceState>& draw(mDrawingState.displays);
    ++        if (!curr.isIdenticalTo(draw)) {
    ++            mVisibleRegionsDirty = true;
    ++            const size_t cc = curr.size();
    ++                  size_t dc = draw.size();
    ++
    ++            // find the displays that were removed
    ++            // (ie: in drawing state but not in current state)
    ++            // also handle displays that changed
    ++            // (ie: displays that are in both lists)
    ++            for (size_t i=0 ; i<dc ; i++) {
    ++                const ssize_t j = curr.indexOfKey(draw.keyAt(i));
    ++                if (j < 0) {
    ++                    // in drawing state but not in current state
    ++                    if (!draw[i].isMainDisplay()) {
    ++                        // Call makeCurrent() on the primary display so we can
    ++                        // be sure that nothing associated with this display
    ++                        // is current.
    ++                        const sp<const DisplayDevice> defaultDisplay(getDefaultDisplayDevice());
    ++                        defaultDisplay->makeCurrent(mEGLDisplay, mEGLContext);
    ++                        sp<DisplayDevice> hw(getDisplayDevice(draw.keyAt(i)));
    ++                        if (hw != NULL)
    ++                            hw->disconnect(getHwComposer());
    ++                        if (draw[i].type < DisplayDevice::NUM_BUILTIN_DISPLAY_TYPES)
    ++                            mEventThread->onHotplugReceived(draw[i].type, false);
    ++                        mDisplays.removeItem(draw.keyAt(i));
    ++                    } else {
    ++                        ALOGW("trying to remove the main display");
    ++                    }
    ++                } else {
    ++                    // this display is in both lists. see if something changed.
    ++                    const DisplayDeviceState& state(curr[j]);
    ++                    const wp<IBinder>& display(curr.keyAt(j));
    ++                    const sp<IBinder> state_binder = IInterface::asBinder(state.surface);
    ++                    const sp<IBinder> draw_binder = IInterface::asBinder(draw[i].surface);
    ++                    if (state_binder != draw_binder) {
    ++                        // changing the surface is like destroying and
    ++                        // recreating the DisplayDevice, so we just remove it
    ++                        // from the drawing state, so that it get re-added
    ++                        // below.
    ++                        sp<DisplayDevice> hw(getDisplayDevice(display));
    ++                        if (hw != NULL)
    ++                            hw->disconnect(getHwComposer());
    ++                        mDisplays.removeItem(display);
    ++                        mDrawingState.displays.removeItemsAt(i);
    ++                        dc--; i--;
    ++                        // at this point we must loop to the next item
    ++                        continue;
    ++                    }
    ++
    ++                    const sp<DisplayDevice> disp(getDisplayDevice(display));
    ++                    if (disp != NULL) {
    ++                        if (state.layerStack != draw[i].layerStack) {
    ++                            disp->setLayerStack(state.layerStack);
    ++                        }
    ++                        if ((state.orientation != draw[i].orientation)
    ++                                || (state.viewport != draw[i].viewport)
    ++                                || (state.frame != draw[i].frame))
    ++                        {
    ++                            disp->setProjection(state.orientation,
    ++                                    state.viewport, state.frame);
    ++                        }
    ++                        if (state.width != draw[i].width || state.height != draw[i].height) {
    ++                            disp->setDisplaySize(state.width, state.height);
    ++                        }
    ++                    }
    ++                }
    ++            }
    ++
    ++            // find displays that were added
    ++            // (ie: in current state but not in drawing state)
    ++            for (size_t i=0 ; i<cc ; i++) {
    ++                if (draw.indexOfKey(curr.keyAt(i)) < 0) {
    ++                    const DisplayDeviceState& state(curr[i]);
    ++
    ++                    sp<DisplaySurface> dispSurface;
    ++                    sp<IGraphicBufferProducer> producer;
    ++                    sp<IGraphicBufferProducer> bqProducer;
    ++                    sp<IGraphicBufferConsumer> bqConsumer;
    ++                    BufferQueue::createBufferQueue(&bqProducer, &bqConsumer,
    ++                            new GraphicBufferAlloc());
    ++
    ++                    int32_t hwcDisplayId = -1;
    ++                    if (state.isVirtualDisplay()) {
    ++                        // Virtual displays without a surface are dormant:
    ++                        // they have external state (layer stack, projection,
    ++                        // etc.) but no internal state (i.e. a DisplayDevice).
    ++                        if (state.surface != NULL) {
    ++
    ++                            int width = 0;
    ++                            int status = state.surface->query(
    ++                                    NATIVE_WINDOW_WIDTH, &width);
    ++                            ALOGE_IF(status != NO_ERROR,
    ++                                    "Unable to query width (%d)", status);
    ++                            int height = 0;
    ++                            status = state.surface->query(
    ++                                    NATIVE_WINDOW_HEIGHT, &height);
    ++                            ALOGE_IF(status != NO_ERROR,
    ++                                    "Unable to query height (%d)", status);
    ++                            if (mUseHwcVirtualDisplays &&
    ++                                    (MAX_VIRTUAL_DISPLAY_DIMENSION == 0 ||
    ++                                    (width <= MAX_VIRTUAL_DISPLAY_DIMENSION &&
    ++                                     height <= MAX_VIRTUAL_DISPLAY_DIMENSION))) {
    ++                                hwcDisplayId = allocateHwcDisplayId(state.type);
    ++                            }
    ++
    ++                            sp<VirtualDisplaySurface> vds = new VirtualDisplaySurface(
    ++                                    *mHwc, hwcDisplayId, state.surface,
    ++                                    bqProducer, bqConsumer, state.displayName);
    ++
    ++                            dispSurface = vds;
    ++                            producer = vds;
    ++                        }
    ++                    } else {
    ++                        ALOGE_IF(state.surface!=NULL,
    ++                                "adding a supported display, but rendering "
    ++                                "surface is provided (%p), ignoring it",
    ++                                state.surface.get());
    ++                        hwcDisplayId = allocateHwcDisplayId(state.type);
    ++                        // for supported (by hwc) displays we provide our
    ++                        // own rendering surface
    ++                        dispSurface = new FramebufferSurface(*mHwc, state.type,
    ++                                bqConsumer);
    ++                        producer = bqProducer;
    ++                    }
    ++
    ++                    const wp<IBinder>& display(curr.keyAt(i));
    ++                    if (dispSurface != NULL) {
    ++                        sp<DisplayDevice> hw = new DisplayDevice(this,
    ++                                state.type, hwcDisplayId,
    ++                                mHwc->getFormat(hwcDisplayId), state.isSecure,
    ++                                display, dispSurface, producer,
    ++                                mRenderEngine->getEGLConfig());
    ++                        hw->setLayerStack(state.layerStack);
    ++                        hw->setProjection(state.orientation,
    ++                                state.viewport, state.frame);
    ++                        hw->setDisplayName(state.displayName);
    ++                        mDisplays.add(display, hw);
    ++                        if (state.isVirtualDisplay()) {
    ++                            if (hwcDisplayId >= 0) {
    ++                                mHwc->setVirtualDisplayProperties(hwcDisplayId,
    ++                                        hw->getWidth(), hw->getHeight(),
    ++                                        hw->getFormat());
    ++                            }
    ++                        } else {
    ++                            mEventThread->onHotplugReceived(state.type, true);
    ++                        }
    ++                    }
    ++                }
    ++            }
    ++        }
    ++    }
    ++
    ++    if (transactionFlags & (eTraversalNeeded|eDisplayTransactionNeeded)) {
    ++        // The transform hint might have changed for some layers
    ++        // (either because a display has changed, or because a layer
    ++        // as changed).
    ++        //
    ++        // Walk through all the layers in currentLayers,
    ++        // and update their transform hint.
    ++        //
    ++        // If a layer is visible only on a single display, then that
    ++        // display is used to calculate the hint, otherwise we use the
    ++        // default display.
    ++        //
    ++        // NOTE: we do this here, rather than in rebuildLayerStacks() so that
    ++        // the hint is set before we acquire a buffer from the surface texture.
    ++        //
    ++        // NOTE: layer transactions have taken place already, so we use their
    ++        // drawing state. However, SurfaceFlinger's own transaction has not
    ++        // happened yet, so we must use the current state layer list
    ++        // (soon to become the drawing state list).
    ++        //
    ++        sp<const DisplayDevice> disp;
    ++        uint32_t currentlayerStack = 0;
    ++        for (size_t i=0; i<count; i++) {
    ++            // NOTE: we rely on the fact that layers are sorted by
    ++            // layerStack first (so we don't have to traverse the list
    ++            // of displays for every layer).
    ++            const sp<Layer>& layer(currentLayers[i]);
    ++            uint32_t layerStack = layer->getDrawingState().layerStack;
    ++            if (i==0 || currentlayerStack != layerStack) {
    ++                currentlayerStack = layerStack;
    ++                // figure out if this layerstack is mirrored
    ++                // (more than one display) if so, pick the default display,
    ++                // if not, pick the only display it's on.
    ++                disp.clear();
    ++                for (size_t dpy=0 ; dpy<mDisplays.size() ; dpy++) {
    ++                    sp<const DisplayDevice> hw(mDisplays[dpy]);
    ++                    if (hw->getLayerStack() == currentlayerStack) {
    ++                        if (disp == NULL) {
    ++                            disp = hw;
    ++                        } else {
    ++                            disp = NULL;
    ++                            break;
    ++                        }
    ++                    }
    ++                }
    ++            }
    ++            if (disp == NULL) {
    ++                // NOTE: TEMPORARY FIX ONLY. Real fix should cause layers to
    ++                // redraw after transform hint changes. See bug 8508397.
    ++
    ++                // could be null when this layer is using a layerStack
    ++                // that is not visible on any display. Also can occur at
    ++                // screen off/on times.
    ++                disp = getDefaultDisplayDevice();
    ++            }
    ++            layer->updateTransformHint(disp);
    ++        }
    ++    }
    ++
    ++
    ++    /*
    ++     * Perform our own transaction if needed
    ++     */
    ++
    ++    const LayerVector& layers(mDrawingState.layersSortedByZ);
    ++    if (currentLayers.size() > layers.size()) {
    ++        // layers have been added
    ++        mVisibleRegionsDirty = true;
    ++    }
    ++
    ++    // some layers might have been removed, so
    ++    // we need to update the regions they're exposing.
    ++    if (mLayersRemoved) {
    ++        mLayersRemoved = false;
    ++        mVisibleRegionsDirty = true;
    ++        const size_t count = layers.size();
    ++        for (size_t i=0 ; i<count ; i++) {
    ++            const sp<Layer>& layer(layers[i]);
    ++            if (currentLayers.indexOf(layer) < 0) {
    ++                // this layer is not visible anymore
    ++                // TODO: we could traverse the tree from front to back and
    ++                //       compute the actual visible region
    ++                // TODO: we could cache the transformed region
    ++                const Layer::State& s(layer->getDrawingState());
    ++                Region visibleReg = s.active.transform.transform(
    ++                        Region(Rect(s.active.w, s.active.h)));
    ++                invalidateLayerStack(s.layerStack, visibleReg);
    ++            }
    ++        }
    ++    }
    ++
    ++    commitTransaction();
    ++
    ++    updateCursorAsync();
    ++}
    ++
    ++void SurfaceFlinger::updateCursorAsync()
    ++{
    ++    HWComposer& hwc(getHwComposer());
    ++    for (size_t dpy=0 ; dpy<mDisplays.size() ; dpy++) {
    ++        sp<const DisplayDevice> hw(mDisplays[dpy]);
    ++        const int32_t id = hw->getHwcDisplayId();
    ++        if (id < 0) {
    ++            continue;
    ++        }
    ++        const Vector< sp<Layer> >& currentLayers(
    ++            hw->getVisibleLayersSortedByZ());
    ++        const size_t count = currentLayers.size();
    ++        HWComposer::LayerListIterator cur = hwc.begin(id);
    ++        const HWComposer::LayerListIterator end = hwc.end(id);
    ++        for (size_t i=0 ; cur!=end && i<count ; ++i, ++cur) {
    ++            if (cur->getCompositionType() != HWC_CURSOR_OVERLAY) {
    ++                continue;
    ++            }
    ++            const sp<Layer>& layer(currentLayers[i]);
    ++            Rect cursorPos = layer->getPosition(hw);
    ++            hwc.setCursorPositionAsync(id, cursorPos);
    ++            break;
    ++        }
    ++    }
    ++}
    ++
    ++void SurfaceFlinger::commitTransaction()
    ++{
    ++    if (!mLayersPendingRemoval.isEmpty()) {
    ++        // Notify removed layers now that they can't be drawn from
    ++        for (size_t i = 0; i < mLayersPendingRemoval.size(); i++) {
    ++            recordBufferingStats(mLayersPendingRemoval[i]->getName().string(),
    ++                    mLayersPendingRemoval[i]->getOccupancyHistory(true));
    ++            mLayersPendingRemoval[i]->onRemoved();
    ++        }
    ++        mLayersPendingRemoval.clear();
    ++    }
    ++
    ++    // If this transaction is part of a window animation then the next frame
    ++    // we composite should be considered an animation as well.
    ++    mAnimCompositionPending = mAnimTransactionPending;
    ++
    ++    mDrawingState = mCurrentState;
    ++    mTransactionPending = false;
    ++    mAnimTransactionPending = false;
    ++    mTransactionCV.broadcast();
    ++}
    ++
    ++void SurfaceFlinger::computeVisibleRegions(
    ++        const LayerVector& currentLayers, uint32_t layerStack,
    ++        Region& outDirtyRegion, Region& outOpaqueRegion)
    ++{
    ++    ATRACE_CALL();
    ++
    ++    Region aboveOpaqueLayers;
    ++    Region aboveCoveredLayers;
    ++    Region dirty;
    ++
    ++    outDirtyRegion.clear();
    ++
    ++    size_t i = currentLayers.size();
    ++    while (i--) {
    ++        const sp<Layer>& layer = currentLayers[i];
    ++
    ++        // start with the whole surface at its current location
    ++        const Layer::State& s(layer->getDrawingState());
    ++
    ++        // only consider the layers on the given layer stack
    ++        if (s.layerStack != layerStack)
    ++            continue;
    ++
    ++        /*
    ++         * opaqueRegion: area of a surface that is fully opaque.
    ++         */
    ++        Region opaqueRegion;
    ++
    ++        /*
    ++         * visibleRegion: area of a surface that is visible on screen
    ++         * and not fully transparent. This is essentially the layer's
    ++         * footprint minus the opaque regions above it.
    ++         * Areas covered by a translucent surface are considered visible.
    ++         */
    ++        Region visibleRegion;
    ++
    ++        /*
    ++         * coveredRegion: area of a surface that is covered by all
    ++         * visible regions above it (which includes the translucent areas).
    ++         */
    ++        Region coveredRegion;
    ++
    ++        /*
    ++         * transparentRegion: area of a surface that is hinted to be completely
    ++         * transparent. This is only used to tell when the layer has no visible
    ++         * non-transparent regions and can be removed from the layer list. It
    ++         * does not affect the visibleRegion of this layer or any layers
    ++         * beneath it. The hint may not be correct if apps don't respect the
    ++         * SurfaceView restrictions (which, sadly, some don't).
    ++         */
    ++        Region transparentRegion;
    ++
    ++
    ++        // handle hidden surfaces by setting the visible region to empty
    ++        if (CC_LIKELY(layer->isVisible())) {
    ++            const bool translucent = !layer->isOpaque(s);
    ++            Rect bounds(s.active.transform.transform(layer->computeBounds()));
    ++            visibleRegion.set(bounds);
    ++            if (!visibleRegion.isEmpty()) {
    ++                // Remove the transparent area from the visible region
    ++                if (translucent) {
    ++                    const Transform tr(s.active.transform);
    ++                    if (tr.preserveRects()) {
    ++                        // transform the transparent region
    ++                        transparentRegion = tr.transform(s.activeTransparentRegion);
    ++                    } else {
    ++                        // transformation too complex, can't do the
    ++                        // transparent region optimization.
    ++                        transparentRegion.clear();
    ++                    }
    ++                }
    ++
    ++                // compute the opaque region
    ++                const int32_t layerOrientation = s.active.transform.getOrientation();
    ++                if (s.alpha==255 && !translucent &&
    ++                        ((layerOrientation & Transform::ROT_INVALID) == false)) {
    ++                    // the opaque region is the layer's footprint
    ++                    opaqueRegion = visibleRegion;
    ++                }
    ++            }
    ++        }
    ++
    ++        // Clip the covered region to the visible region
    ++        coveredRegion = aboveCoveredLayers.intersect(visibleRegion);
    ++
    ++        // Update aboveCoveredLayers for next (lower) layer
    ++        aboveCoveredLayers.orSelf(visibleRegion);
    ++
    ++        // subtract the opaque region covered by the layers above us
    ++        visibleRegion.subtractSelf(aboveOpaqueLayers);
    ++
    ++        // compute this layer's dirty region
    ++        if (layer->contentDirty) {
    ++            // we need to invalidate the whole region
    ++            dirty = visibleRegion;
    ++            // as well, as the old visible region
    ++            dirty.orSelf(layer->visibleRegion);
    ++            layer->contentDirty = false;
    ++        } else {
    ++            /* compute the exposed region:
    ++             *   the exposed region consists of two components:
    ++             *   1) what's VISIBLE now and was COVERED before
    ++             *   2) what's EXPOSED now less what was EXPOSED before
    ++             *
    ++             * note that (1) is conservative, we start with the whole
    ++             * visible region but only keep what used to be covered by
    ++             * something -- which mean it may have been exposed.
    ++             *
    ++             * (2) handles areas that were not covered by anything but got
    ++             * exposed because of a resize.
    ++             */
    ++            const Region newExposed = visibleRegion - coveredRegion;
    ++            const Region oldVisibleRegion = layer->visibleRegion;
    ++            const Region oldCoveredRegion = layer->coveredRegion;
    ++            const Region oldExposed = oldVisibleRegion - oldCoveredRegion;
    ++            dirty = (visibleRegion&oldCoveredRegion) | (newExposed-oldExposed);
    ++        }
    ++        dirty.subtractSelf(aboveOpaqueLayers);
    ++
    ++        // accumulate to the screen dirty region
    ++        outDirtyRegion.orSelf(dirty);
    ++
    ++        // Update aboveOpaqueLayers for next (lower) layer
    ++        aboveOpaqueLayers.orSelf(opaqueRegion);
    ++
    ++        // Store the visible region in screen space
    ++        layer->setVisibleRegion(visibleRegion);
    ++        layer->setCoveredRegion(coveredRegion);
    ++        layer->setVisibleNonTransparentRegion(
    ++                visibleRegion.subtract(transparentRegion));
    ++    }
    ++
    ++    outOpaqueRegion = aboveOpaqueLayers;
    ++}
    ++
    ++void SurfaceFlinger::invalidateLayerStack(uint32_t layerStack,
    ++        const Region& dirty) {
    ++    for (size_t dpy=0 ; dpy<mDisplays.size() ; dpy++) {
    ++        const sp<DisplayDevice>& hw(mDisplays[dpy]);
    ++        if (hw->getLayerStack() == layerStack) {
    ++            hw->dirtyRegion.orSelf(dirty);
    ++        }
    ++    }
    ++}
    ++
    ++bool SurfaceFlinger::handlePageFlip()
    ++{
    ++    Region dirtyRegion;
    ++
    ++    bool visibleRegions = false;
    ++    const LayerVector& layers(mDrawingState.layersSortedByZ);
    ++    bool frameQueued = false;
    ++
    ++    // Store the set of layers that need updates. This set must not change as
    ++    // buffers are being latched, as this could result in a deadlock.
    ++    // Example: Two producers share the same command stream and:
    ++    // 1.) Layer 0 is latched
    ++    // 2.) Layer 0 gets a new frame
    ++    // 2.) Layer 1 gets a new frame
    ++    // 3.) Layer 1 is latched.
    ++    // Display is now waiting on Layer 1's frame, which is behind layer 0's
    ++    // second frame. But layer 0's second frame could be waiting on display.
    ++    Vector<Layer*> layersWithQueuedFrames;
    ++    for (size_t i = 0, count = layers.size(); i<count ; i++) {
    ++        const sp<Layer>& layer(layers[i]);
    ++        if (layer->hasQueuedFrame()) {
    ++            frameQueued = true;
    ++            if (layer->shouldPresentNow(mPrimaryDispSync)) {
    ++                layersWithQueuedFrames.push_back(layer.get());
    ++            } else {
    ++                layer->useEmptyDamage();
    ++            }
    ++        } else {
    ++            layer->useEmptyDamage();
    ++        }
    ++    }
    ++    for (size_t i = 0, count = layersWithQueuedFrames.size() ; i<count ; i++) {
    ++        Layer* layer = layersWithQueuedFrames[i];
    ++        const Region dirty(layer->latchBuffer(visibleRegions));
    ++        layer->useSurfaceDamage();
    ++        const Layer::State& s(layer->getDrawingState());
    ++        invalidateLayerStack(s.layerStack, dirty);
    ++    }
    ++
    ++    mVisibleRegionsDirty |= visibleRegions;
    ++
    ++    // If we will need to wake up at some time in the future to deal with a
    ++    // queued frame that shouldn't be displayed during this vsync period, wake
    ++    // up during the next vsync period to check again.
    ++    if (frameQueued && layersWithQueuedFrames.empty()) {
    ++        signalLayerUpdate();
    ++    }
    ++
    ++    // Only continue with the refresh if there is actually new work to do
    ++    return !layersWithQueuedFrames.empty();
    ++}
    ++
    ++void SurfaceFlinger::invalidateHwcGeometry()
    ++{
    ++    mHwWorkListDirty = true;
    ++}
    ++
    ++
    ++void SurfaceFlinger::doDisplayComposition(const sp<const DisplayDevice>& hw,
    ++        const Region& inDirtyRegion)
    ++{
    ++    // We only need to actually compose the display if:
    ++    // 1) It is being handled by hardware composer, which may need this to
    ++    //    keep its virtual display state machine in sync, or
    ++    // 2) There is work to be done (the dirty region isn't empty)
    ++    bool isHwcDisplay = hw->getHwcDisplayId() >= 0;
    ++    if (!isHwcDisplay && inDirtyRegion.isEmpty()) {
    ++        return;
    ++    }
    ++
    ++    Region dirtyRegion(inDirtyRegion);
    ++
    ++    // compute the invalid region
    ++    hw->swapRegion.orSelf(dirtyRegion);
    ++
    ++    uint32_t flags = hw->getFlags();
    ++    if (flags & DisplayDevice::SWAP_RECTANGLE) {
    ++        // we can redraw only what's dirty, but since SWAP_RECTANGLE only
    ++        // takes a rectangle, we must make sure to update that whole
    ++        // rectangle in that case
    ++        dirtyRegion.set(hw->swapRegion.bounds());
    ++    } else {
    ++        if (flags & DisplayDevice::PARTIAL_UPDATES) {
    ++            // We need to redraw the rectangle that will be updated
    ++            // (pushed to the framebuffer).
    ++            // This is needed because PARTIAL_UPDATES only takes one
    ++            // rectangle instead of a region (see DisplayDevice::flip())
    ++            dirtyRegion.set(hw->swapRegion.bounds());
    ++        } else {
    ++            // we need to redraw everything (the whole screen)
    ++            dirtyRegion.set(hw->bounds());
    ++            hw->swapRegion = dirtyRegion;
    ++        }
    ++    }
    ++
    ++    if (CC_LIKELY(!mDaltonize && !mHasColorMatrix)) {
    ++        if (!doComposeSurfaces(hw, dirtyRegion)) return;
    ++    } else {
    ++        RenderEngine& engine(getRenderEngine());
    ++        mat4 colorMatrix = mColorMatrix;
    ++        if (mDaltonize) {
    ++            colorMatrix = colorMatrix * mDaltonizer();
    ++        }
    ++        mat4 oldMatrix = engine.setupColorTransform(colorMatrix);
    ++        doComposeSurfaces(hw, dirtyRegion);
    ++        engine.setupColorTransform(oldMatrix);
    ++    }
    ++
    ++    // update the swap region and clear the dirty region
    ++    hw->swapRegion.orSelf(dirtyRegion);
    ++
    ++    // swap buffers (presentation)
    ++    hw->swapBuffers(getHwComposer());
    ++}
    ++
    ++bool SurfaceFlinger::doComposeSurfaces(const sp<const DisplayDevice>& hw, const Region& dirty)
    ++{
    ++    RenderEngine& engine(getRenderEngine());
    ++    const int32_t id = hw->getHwcDisplayId();
    ++    HWComposer& hwc(getHwComposer());
    ++    HWComposer::LayerListIterator cur = hwc.begin(id);
    ++    const HWComposer::LayerListIterator end = hwc.end(id);
    ++
    ++    bool hasGlesComposition = hwc.hasGlesComposition(id);
    ++    if (hasGlesComposition) {
    ++        if (!hw->makeCurrent(mEGLDisplay, mEGLContext)) {
    ++            ALOGW("DisplayDevice::makeCurrent failed. Aborting surface composition for display %s",
    ++                  hw->getDisplayName().string());
    ++            eglMakeCurrent(mEGLDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
    ++            if(!getDefaultDisplayDevice()->makeCurrent(mEGLDisplay, mEGLContext)) {
    ++              ALOGE("DisplayDevice::makeCurrent on default display failed. Aborting.");
    ++            }
    ++            return false;
    ++        }
    ++
    ++        // Never touch the framebuffer if we don't have any framebuffer layers
    ++        const bool hasHwcComposition = hwc.hasHwcComposition(id);
    ++        if (hasHwcComposition) {
    ++            // when using overlays, we assume a fully transparent framebuffer
    ++            // NOTE: we could reduce how much we need to clear, for instance
    ++            // remove where there are opaque FB layers. however, on some
    ++            // GPUs doing a "clean slate" clear might be more efficient.
    ++            // We'll revisit later if needed.
    ++            engine.clearWithColor(0, 0, 0, 0);
    ++        } else {
    ++            // we start with the whole screen area
    ++            const Region bounds(hw->getBounds());
    ++
    ++            // we remove the scissor part
    ++            // we're left with the letterbox region
    ++            // (common case is that letterbox ends-up being empty)
    ++            const Region letterbox(bounds.subtract(hw->getScissor()));
    ++
    ++            // compute the area to clear
    ++            Region region(hw->undefinedRegion.merge(letterbox));
    ++
    ++            // but limit it to the dirty region
    ++            region.andSelf(dirty);
    ++
    ++            // screen is already cleared here
    ++            if (!region.isEmpty()) {
    ++                // can happen with SurfaceView
    ++                drawWormhole(hw, region);
    ++            }
    ++        }
    ++
    ++        if (hw->getDisplayType() != DisplayDevice::DISPLAY_PRIMARY) {
    ++            // just to be on the safe side, we don't set the
    ++            // scissor on the main display. It should never be needed
    ++            // anyways (though in theory it could since the API allows it).
    ++            const Rect& bounds(hw->getBounds());
    ++            const Rect& scissor(hw->getScissor());
    ++            if (scissor != bounds) {
    ++                // scissor doesn't match the screen's dimensions, so we
    ++                // need to clear everything outside of it and enable
    ++                // the GL scissor so we don't draw anything where we shouldn't
    ++
    ++                // enable scissor for this frame
    ++                const uint32_t height = hw->getHeight();
    ++                engine.setScissor(scissor.left, height - scissor.bottom,
    ++                        scissor.getWidth(), scissor.getHeight());
    ++            }
    ++        }
    ++    }
    ++
    ++    /*
    ++     * and then, render the layers targeted at the framebuffer
    ++     */
    ++
    ++    const Vector< sp<Layer> >& layers(hw->getVisibleLayersSortedByZ());
    ++    const size_t count = layers.size();
    ++    const Transform& tr = hw->getTransform();
    ++    if (cur != end) {
    ++        // we're using h/w composer
    ++        for (size_t i=0 ; i<count && cur!=end ; ++i, ++cur) {
    ++            const sp<Layer>& layer(layers[i]);
    ++            const Region clip(dirty.intersect(tr.transform(layer->visibleRegion)));
    ++            if (!clip.isEmpty()) {
    ++                switch (cur->getCompositionType()) {
    ++                    case HWC_CURSOR_OVERLAY:
    ++                    case HWC_OVERLAY: {
    ++                        const Layer::State& state(layer->getDrawingState());
    ++                        if ((cur->getHints() & HWC_HINT_CLEAR_FB)
    ++                                && i
    ++                                && layer->isOpaque(state) && (state.alpha == 0xFF)
    ++                                && hasGlesComposition) {
    ++                            // never clear the very first layer since we're
    ++                            // guaranteed the FB is already cleared
    ++                            layer->clearWithOpenGL(hw, clip);
    ++                        }
    ++                        break;
    ++                    }
    ++                    case HWC_FRAMEBUFFER: {
    ++                        layer->draw(hw, clip);
    ++                        break;
    ++                    }
    ++                    case HWC_FRAMEBUFFER_TARGET: {
    ++                        // this should not happen as the iterator shouldn't
    ++                        // let us get there.
    ++                        ALOGW("HWC_FRAMEBUFFER_TARGET found in hwc list (index=%zu)", i);
    ++                        break;
    ++                    }
    ++                }
    ++            }
    ++            layer->setAcquireFence(hw, *cur);
    ++        }
    ++    } else {
    ++        // we're not using h/w composer
    ++        for (size_t i=0 ; i<count ; ++i) {
    ++            const sp<Layer>& layer(layers[i]);
    ++            const Region clip(dirty.intersect(
    ++                    tr.transform(layer->visibleRegion)));
    ++            if (!clip.isEmpty()) {
    ++                layer->draw(hw, clip);
    ++            }
    ++        }
    ++    }
    ++
    ++    // disable scissor at the end of the frame
    ++    engine.disableScissor();
    ++    return true;
    ++}
    ++
    ++void SurfaceFlinger::drawWormhole(const sp<const DisplayDevice>& hw, const Region& region) const {
    ++    const int32_t height = hw->getHeight();
    ++    RenderEngine& engine(getRenderEngine());
    ++    engine.fillRegionWithColor(region, height, 0, 0, 0, 0);
    ++}
    ++
    ++status_t SurfaceFlinger::addClientLayer(const sp<Client>& client,
    ++        const sp<IBinder>& handle,
    ++        const sp<IGraphicBufferProducer>& gbc,
    ++        const sp<Layer>& lbc)
    ++{
    ++    // add this layer to the current state list
    ++    {
    ++        Mutex::Autolock _l(mStateLock);
    ++        if (mCurrentState.layersSortedByZ.size() >= MAX_LAYERS) {
    ++            return NO_MEMORY;
    ++        }
    ++        mCurrentState.layersSortedByZ.add(lbc);
    ++        mGraphicBufferProducerList.add(IInterface::asBinder(gbc));
    ++    }
    ++
    ++    // attach this layer to the client
    ++    client->attachLayer(handle, lbc);
    ++
    ++    return NO_ERROR;
    ++}
    ++
    ++status_t SurfaceFlinger::removeLayer(const wp<Layer>& weakLayer) {
    ++    Mutex::Autolock _l(mStateLock);
    ++    sp<Layer> layer = weakLayer.promote();
    ++    if (layer == nullptr) {
    ++        // The layer has already been removed, carry on
    ++        return NO_ERROR;
    ++    }
    ++
    ++    ssize_t index = mCurrentState.layersSortedByZ.remove(layer);
    ++    if (index >= 0) {
    ++        mLayersPendingRemoval.push(layer);
    ++        mLayersRemoved = true;
    ++        setTransactionFlags(eTransactionNeeded);
    ++        return NO_ERROR;
    ++    }
    ++    return status_t(index);
    ++}
    ++
    ++uint32_t SurfaceFlinger::peekTransactionFlags(uint32_t /* flags */) {
    ++    return android_atomic_release_load(&mTransactionFlags);
    ++}
    ++
    ++uint32_t SurfaceFlinger::getTransactionFlags(uint32_t flags) {
    ++    return android_atomic_and(~flags, &mTransactionFlags) & flags;
    ++}
    ++
    ++uint32_t SurfaceFlinger::setTransactionFlags(uint32_t flags) {
    ++    uint32_t old = android_atomic_or(flags, &mTransactionFlags);
    ++    if ((old & flags)==0) { // wake the server up
    ++        signalTransaction();
    ++    }
    ++    return old;
    ++}
    ++
    ++void SurfaceFlinger::setTransactionState(
    ++        const Vector<ComposerState>& state,
    ++        const Vector<DisplayState>& displays,
    ++        uint32_t flags)
    ++{
    ++    ATRACE_CALL();
    ++    Mutex::Autolock _l(mStateLock);
    ++    uint32_t transactionFlags = 0;
    ++
    ++    if (flags & eAnimation) {
    ++        // For window updates that are part of an animation we must wait for
    ++        // previous animation "frames" to be handled.
    ++        while (mAnimTransactionPending) {
    ++            status_t err = mTransactionCV.waitRelative(mStateLock, s2ns(5));
    ++            if (CC_UNLIKELY(err != NO_ERROR)) {
    ++                // just in case something goes wrong in SF, return to the
    ++                // caller after a few seconds.
    ++                ALOGW_IF(err == TIMED_OUT, "setTransactionState timed out "
    ++                        "waiting for previous animation frame");
    ++                mAnimTransactionPending = false;
    ++                break;
    ++            }
    ++        }
    ++    }
    ++
    ++    size_t count = displays.size();
    ++    for (size_t i=0 ; i<count ; i++) {
    ++        const DisplayState& s(displays[i]);
    ++        transactionFlags |= setDisplayStateLocked(s);
    ++    }
    ++
    ++    count = state.size();
    ++    for (size_t i=0 ; i<count ; i++) {
    ++        const ComposerState& s(state[i]);
    ++        // Here we need to check that the interface we're given is indeed
    ++        // one of our own. A malicious client could give us a NULL
    ++        // IInterface, or one of its own or even one of our own but a
    ++        // different type. All these situations would cause us to crash.
    ++        //
    ++        // NOTE: it would be better to use RTTI as we could directly check
    ++        // that we have a Client*. however, RTTI is disabled in Android.
    ++        if (s.client != NULL) {
    ++            sp<IBinder> binder = IInterface::asBinder(s.client);
    ++            if (binder != NULL) {
    ++                String16 desc(binder->getInterfaceDescriptor());
    ++                if (desc == ISurfaceComposerClient::descriptor) {
    ++                    sp<Client> client( static_cast<Client *>(s.client.get()) );
    ++                    transactionFlags |= setClientStateLocked(client, s.state);
    ++                }
    ++            }
    ++        }
    ++    }
    ++
    ++    // If a synchronous transaction is explicitly requested without any changes,
    ++    // force a transaction anyway. This can be used as a flush mechanism for
    ++    // previous async transactions.
    ++    if (transactionFlags == 0 && (flags & eSynchronous)) {
    ++        transactionFlags = eTransactionNeeded;
    ++    }
    ++
    ++    if (transactionFlags) {
    ++        // this triggers the transaction
    ++        setTransactionFlags(transactionFlags);
    ++
    ++        // if this is a synchronous transaction, wait for it to take effect
    ++        // before returning.
    ++        if (flags & eSynchronous) {
    ++            mTransactionPending = true;
    ++        }
    ++        if (flags & eAnimation) {
    ++            mAnimTransactionPending = true;
    ++        }
    ++        while (mTransactionPending) {
    ++            status_t err = mTransactionCV.waitRelative(mStateLock, s2ns(5));
    ++            if (CC_UNLIKELY(err != NO_ERROR)) {
    ++                // just in case something goes wrong in SF, return to the
    ++                // called after a few seconds.
    ++                ALOGW_IF(err == TIMED_OUT, "setTransactionState timed out!");
    ++                mTransactionPending = false;
    ++                break;
    ++            }
    ++        }
    ++    }
    ++}
    ++
    ++uint32_t SurfaceFlinger::setDisplayStateLocked(const DisplayState& s)
    ++{
    ++    ssize_t dpyIdx = mCurrentState.displays.indexOfKey(s.token);
    ++    if (dpyIdx < 0)
    ++        return 0;
    ++
    ++    uint32_t flags = 0;
    ++    DisplayDeviceState& disp(mCurrentState.displays.editValueAt(dpyIdx));
    ++    if (disp.isValid()) {
    ++        const uint32_t what = s.what;
    ++        if (what & DisplayState::eSurfaceChanged) {
    ++            if (IInterface::asBinder(disp.surface) != IInterface::asBinder(s.surface)) {
    ++                disp.surface = s.surface;
    ++                flags |= eDisplayTransactionNeeded;
    ++            }
    ++        }
    ++        if (what & DisplayState::eLayerStackChanged) {
    ++            if (disp.layerStack != s.layerStack) {
    ++                disp.layerStack = s.layerStack;
    ++                flags |= eDisplayTransactionNeeded;
    ++            }
    ++        }
    ++        if (what & DisplayState::eDisplayProjectionChanged) {
    ++            if (disp.orientation != s.orientation) {
    ++                disp.orientation = s.orientation;
    ++                flags |= eDisplayTransactionNeeded;
    ++            }
    ++            if (disp.frame != s.frame) {
    ++                disp.frame = s.frame;
    ++                flags |= eDisplayTransactionNeeded;
    ++            }
    ++            if (disp.viewport != s.viewport) {
    ++                disp.viewport = s.viewport;
    ++                flags |= eDisplayTransactionNeeded;
    ++            }
    ++        }
    ++        if (what & DisplayState::eDisplaySizeChanged) {
    ++            if (disp.width != s.width) {
    ++                disp.width = s.width;
    ++                flags |= eDisplayTransactionNeeded;
    ++            }
    ++            if (disp.height != s.height) {
    ++                disp.height = s.height;
    ++                flags |= eDisplayTransactionNeeded;
    ++            }
    ++        }
    ++    }
    ++    return flags;
    ++}
    ++
    ++uint32_t SurfaceFlinger::setClientStateLocked(
    ++        const sp<Client>& client,
    ++        const layer_state_t& s)
    ++{
    ++    uint32_t flags = 0;
    ++    sp<Layer> layer(client->getLayerUser(s.surface));
    ++    if (layer != 0) {
    ++        const uint32_t what = s.what;
    ++        bool geometryAppliesWithResize =
    ++                what & layer_state_t::eGeometryAppliesWithResize;
    ++        if (what & layer_state_t::ePositionChanged) {
    ++            if (layer->setPosition(s.x, s.y, !geometryAppliesWithResize)) {
    ++                flags |= eTraversalNeeded;
    ++            }
    ++        }
    ++        if (what & layer_state_t::eLayerChanged) {
    ++            // NOTE: index needs to be calculated before we update the state
    ++            ssize_t idx = mCurrentState.layersSortedByZ.indexOf(layer);
    ++            if (layer->setLayer(s.z) && idx >= 0) {
    ++                mCurrentState.layersSortedByZ.removeAt(idx);
    ++                mCurrentState.layersSortedByZ.add(layer);
    ++                // we need traversal (state changed)
    ++                // AND transaction (list changed)
    ++                flags |= eTransactionNeeded|eTraversalNeeded;
    ++            }
    ++        }
    ++        if (what & layer_state_t::eSizeChanged) {
    ++            if (layer->setSize(s.w, s.h)) {
    ++                flags |= eTraversalNeeded;
    ++            }
    ++        }
    ++        if (what & layer_state_t::eAlphaChanged) {
    ++            if (layer->setAlpha(uint8_t(255.0f*s.alpha+0.5f)))
    ++                flags |= eTraversalNeeded;
    ++        }
    ++        if (what & layer_state_t::eMatrixChanged) {
    ++            if (layer->setMatrix(s.matrix))
    ++                flags |= eTraversalNeeded;
    ++        }
    ++        if (what & layer_state_t::eTransparentRegionChanged) {
    ++            if (layer->setTransparentRegionHint(s.transparentRegion))
    ++                flags |= eTraversalNeeded;
    ++        }
    ++        if (what & layer_state_t::eFlagsChanged) {
    ++            if (layer->setFlags(s.flags, s.mask))
    ++                flags |= eTraversalNeeded;
    ++        }
    ++        if (what & layer_state_t::eCropChanged) {
    ++            if (layer->setCrop(s.crop, !geometryAppliesWithResize))
    ++                flags |= eTraversalNeeded;
    ++        }
    ++        if (what & layer_state_t::eFinalCropChanged) {
    ++            if (layer->setFinalCrop(s.finalCrop))
    ++                flags |= eTraversalNeeded;
    ++        }
    ++        if (what & layer_state_t::eLayerStackChanged) {
    ++            // NOTE: index needs to be calculated before we update the state
    ++            ssize_t idx = mCurrentState.layersSortedByZ.indexOf(layer);
    ++            if (layer->setLayerStack(s.layerStack) && idx >= 0) {
    ++                mCurrentState.layersSortedByZ.removeAt(idx);
    ++                mCurrentState.layersSortedByZ.add(layer);
    ++                // we need traversal (state changed)
    ++                // AND transaction (list changed)
    ++                flags |= eTransactionNeeded|eTraversalNeeded;
    ++            }
    ++        }
    ++        if (what & layer_state_t::eDeferTransaction) {
    ++            layer->deferTransactionUntil(s.handle, s.frameNumber);
    ++            // We don't trigger a traversal here because if no other state is
    ++            // changed, we don't want this to cause any more work
    ++        }
    ++        if (what & layer_state_t::eOverrideScalingModeChanged) {
    ++            layer->setOverrideScalingMode(s.overrideScalingMode);
    ++            // We don't trigger a traversal here because if no other state is
    ++            // changed, we don't want this to cause any more work
    ++        }
    ++    }
    ++    return flags;
    ++}
    ++
    ++status_t SurfaceFlinger::createLayer(
    ++        const String8& name,
    ++        const sp<Client>& client,
    ++        uint32_t w, uint32_t h, PixelFormat format, uint32_t flags,
    ++        sp<IBinder>* handle, sp<IGraphicBufferProducer>* gbp)
    ++{
    ++    //ALOGD("createLayer for (%d x %d), name=%s", w, h, name.string());
    ++    if (int32_t(w|h) < 0) {
    ++        ALOGE("createLayer() failed, w or h is negative (w=%d, h=%d)",
    ++                int(w), int(h));
    ++        return BAD_VALUE;
    ++    }
    ++
    ++    status_t result = NO_ERROR;
    ++
    ++    sp<Layer> layer;
    ++
    ++    switch (flags & ISurfaceComposerClient::eFXSurfaceMask) {
    ++        case ISurfaceComposerClient::eFXSurfaceNormal:
    ++            result = createNormalLayer(client,
    ++                    name, w, h, flags, format,
    ++                    handle, gbp, &layer);
    ++            break;
    ++        case ISurfaceComposerClient::eFXSurfaceDim:
    ++            result = createDimLayer(client,
    ++                    name, w, h, flags,
    ++                    handle, gbp, &layer);
    ++            break;
    ++        default:
    ++            result = BAD_VALUE;
    ++            break;
    ++    }
    ++
    ++    if (result != NO_ERROR) {
    ++        return result;
    ++    }
    ++
    ++    result = addClientLayer(client, *handle, *gbp, layer);
    ++    if (result != NO_ERROR) {
    ++        return result;
    ++    }
    ++
    ++    setTransactionFlags(eTransactionNeeded);
    ++    return result;
    ++}
    ++
    ++status_t SurfaceFlinger::createNormalLayer(const sp<Client>& client,
    ++        const String8& name, uint32_t w, uint32_t h, uint32_t flags, PixelFormat& format,
    ++        sp<IBinder>* handle, sp<IGraphicBufferProducer>* gbp, sp<Layer>* outLayer)
    ++{
    ++    // initialize the surfaces
    ++    switch (format) {
    ++    case PIXEL_FORMAT_TRANSPARENT:
    ++    case PIXEL_FORMAT_TRANSLUCENT:
    ++        format = PIXEL_FORMAT_RGBA_8888;
    ++        break;
    ++    case PIXEL_FORMAT_OPAQUE:
    ++        format = PIXEL_FORMAT_RGBX_8888;
    ++        break;
    ++    }
    ++
    ++    *outLayer = new Layer(this, client, name, w, h, flags);
    ++    status_t err = (*outLayer)->setBuffers(w, h, format, flags);
    ++    if (err == NO_ERROR) {
    ++        *handle = (*outLayer)->getHandle();
    ++        *gbp = (*outLayer)->getProducer();
    ++    }
    ++
    ++    ALOGE_IF(err, "createNormalLayer() failed (%s)", strerror(-err));
    ++    return err;
    ++}
    ++
    ++status_t SurfaceFlinger::createDimLayer(const sp<Client>& client,
    ++        const String8& name, uint32_t w, uint32_t h, uint32_t flags,
    ++        sp<IBinder>* handle, sp<IGraphicBufferProducer>* gbp, sp<Layer>* outLayer)
    ++{
    ++    *outLayer = new LayerDim(this, client, name, w, h, flags);
    ++    *handle = (*outLayer)->getHandle();
    ++    *gbp = (*outLayer)->getProducer();
    ++    return NO_ERROR;
    ++}
    ++
    ++status_t SurfaceFlinger::onLayerRemoved(const sp<Client>& client, const sp<IBinder>& handle)
    ++{
    ++    // called by the window manager when it wants to remove a Layer
    ++    status_t err = NO_ERROR;
    ++    sp<Layer> l(client->getLayerUser(handle));
    ++    if (l != NULL) {
    ++        err = removeLayer(l);
    ++        ALOGE_IF(err<0 && err != NAME_NOT_FOUND,
    ++                "error removing layer=%p (%s)", l.get(), strerror(-err));
    ++    }
    ++    return err;
    ++}
    ++
    ++status_t SurfaceFlinger::onLayerDestroyed(const wp<Layer>& layer)
    ++{
    ++    // called by ~LayerCleaner() when all references to the IBinder (handle)
    ++    // are gone
    ++    return removeLayer(layer);
    ++}
    ++
    ++// ---------------------------------------------------------------------------
    ++
    ++void SurfaceFlinger::onInitializeDisplays() {
    ++    // reset screen orientation and use primary layer stack
    ++    Vector<ComposerState> state;
    ++    Vector<DisplayState> displays;
    ++    DisplayState d;
    ++    d.what = DisplayState::eDisplayProjectionChanged |
    ++             DisplayState::eLayerStackChanged;
    ++    d.token = mBuiltinDisplays[DisplayDevice::DISPLAY_PRIMARY];
    ++    d.layerStack = 0;
    ++    d.orientation = DisplayState::eOrientationDefault;
    ++    d.frame.makeInvalid();
    ++    d.viewport.makeInvalid();
    ++    d.width = 0;
    ++    d.height = 0;
    ++    displays.add(d);
    ++    setTransactionState(state, displays, 0);
    ++    setPowerModeInternal(getDisplayDevice(d.token), HWC_POWER_MODE_NORMAL);
    ++
    ++    const nsecs_t period =
    ++            getHwComposer().getRefreshPeriod(HWC_DISPLAY_PRIMARY);
    ++    mAnimFrameTracker.setDisplayRefreshPeriod(period);
    ++}
    ++
    ++void SurfaceFlinger::initializeDisplays() {
    ++    class MessageScreenInitialized : public MessageBase {
    ++        SurfaceFlinger* flinger;
    ++    public:
    ++        MessageScreenInitialized(SurfaceFlinger* flinger) : flinger(flinger) { }
    ++        virtual bool handler() {
    ++            flinger->onInitializeDisplays();
    ++            return true;
    ++        }
    ++    };
    ++    sp<MessageBase> msg = new MessageScreenInitialized(this);
    ++    postMessageAsync(msg);  // we may be called from main thread, use async message
    ++}
    ++
    ++void SurfaceFlinger::setPowerModeInternal(const sp<DisplayDevice>& hw,
    ++        int mode) {
    ++    ALOGD("Set power mode=%d, type=%d flinger=%p", mode, hw->getDisplayType(),
    ++            this);
    ++    int32_t type = hw->getDisplayType();
    ++    int currentMode = hw->getPowerMode();
    ++
    ++    if (mode == currentMode) {
    ++        ALOGD("Screen type=%d is already mode=%d", hw->getDisplayType(), mode);
    ++        return;
    ++    }
    ++
    ++    hw->setPowerMode(mode);
    ++    if (type >= DisplayDevice::NUM_BUILTIN_DISPLAY_TYPES) {
    ++        ALOGW("Trying to set power mode for virtual display");
    ++        return;
    ++    }
    ++
    ++    if (currentMode == HWC_POWER_MODE_OFF) {
    ++        // Turn on the display
    ++        getHwComposer().setPowerMode(type, mode);
    ++        if (type == DisplayDevice::DISPLAY_PRIMARY) {
    ++            // FIXME: eventthread only knows about the main display right now
    ++            mEventThread->onScreenAcquired();
    ++            resyncToHardwareVsync(true);
    ++        }
    ++
    ++        mVisibleRegionsDirty = true;
    ++        mHasPoweredOff = true;
    ++        repaintEverything();
    ++
    ++        struct sched_param param = {0};
    ++        param.sched_priority = 1;
    ++        if (sched_setscheduler(0, SCHED_FIFO, &param) != 0) {
    ++            ALOGW("Couldn't set SCHED_FIFO on display on");
    ++        }
    ++    } else if (mode == HWC_POWER_MODE_OFF) {
    ++        // Turn off the display
    ++        struct sched_param param = {0};
    ++        if (sched_setscheduler(0, SCHED_OTHER, &param) != 0) {
    ++            ALOGW("Couldn't set SCHED_OTHER on display off");
    ++        }
    ++
    ++        if (type == DisplayDevice::DISPLAY_PRIMARY) {
    ++            disableHardwareVsync(true); // also cancels any in-progress resync
    ++
    ++            // FIXME: eventthread only knows about the main display right now
    ++            mEventThread->onScreenReleased();
    ++        }
    ++
    ++        getHwComposer().setPowerMode(type, mode);
    ++        mVisibleRegionsDirty = true;
    ++        // from this point on, SF will stop drawing on this display
    ++    } else {
    ++        getHwComposer().setPowerMode(type, mode);
    ++    }
    ++}
    ++
    ++void SurfaceFlinger::setPowerMode(const sp<IBinder>& display, int mode) {
    ++    class MessageSetPowerMode: public MessageBase {
    ++        SurfaceFlinger& mFlinger;
    ++        sp<IBinder> mDisplay;
    ++        int mMode;
    ++    public:
    ++        MessageSetPowerMode(SurfaceFlinger& flinger,
    ++                const sp<IBinder>& disp, int mode) : mFlinger(flinger),
    ++                    mDisplay(disp) { mMode = mode; }
    ++        virtual bool handler() {
    ++            sp<DisplayDevice> hw(mFlinger.getDisplayDevice(mDisplay));
    ++            if (hw == NULL) {
    ++                ALOGE("Attempt to set power mode = %d for null display %p",
    ++                        mMode, mDisplay.get());
    ++            } else if (hw->getDisplayType() >= DisplayDevice::DISPLAY_VIRTUAL) {
    ++                ALOGW("Attempt to set power mode = %d for virtual display",
    ++                        mMode);
    ++            } else {
    ++                mFlinger.setPowerModeInternal(hw, mMode);
    ++            }
    ++            return true;
    ++        }
    ++    };
    ++    sp<MessageBase> msg = new MessageSetPowerMode(*this, display, mode);
    ++    postMessageSync(msg);
    ++}
    ++
    ++// ---------------------------------------------------------------------------
    ++
    ++status_t SurfaceFlinger::dump(int fd, const Vector<String16>& args)
    ++{
    ++    String8 result;
    ++
    ++    IPCThreadState* ipc = IPCThreadState::self();
    ++    const int pid = ipc->getCallingPid();
    ++    const int uid = ipc->getCallingUid();
    ++    if ((uid != AID_SHELL) &&
    ++            !PermissionCache::checkPermission(sDump, pid, uid)) {
    ++        result.appendFormat("Permission Denial: "
    ++                "can't dump SurfaceFlinger from pid=%d, uid=%d\n", pid, uid);
    ++    } else {
    ++        // Try to get the main lock, but give up after one second
    ++        // (this would indicate SF is stuck, but we want to be able to
    ++        // print something in dumpsys).
    ++        status_t err = mStateLock.timedLock(s2ns(1));
    ++        bool locked = (err == NO_ERROR);
    ++        if (!locked) {
    ++            result.appendFormat(
    ++                    "SurfaceFlinger appears to be unresponsive (%s [%d]), "
    ++                    "dumping anyways (no locks held)\n", strerror(-err), err);
    ++        }
    ++
    ++        bool dumpAll = true;
    ++        size_t index = 0;
    ++        size_t numArgs = args.size();
    ++        if (numArgs) {
    ++            if ((index < numArgs) &&
    ++                    (args[index] == String16("--list"))) {
    ++                index++;
    ++                listLayersLocked(args, index, result);
    ++                dumpAll = false;
    ++            }
    ++
    ++            if ((index < numArgs) &&
    ++                    (args[index] == String16("--latency"))) {
    ++                index++;
    ++                dumpStatsLocked(args, index, result);
    ++                dumpAll = false;
    ++            }
    ++
    ++            if ((index < numArgs) &&
    ++                    (args[index] == String16("--latency-clear"))) {
    ++                index++;
    ++                clearStatsLocked(args, index, result);
    ++                dumpAll = false;
    ++            }
    ++
    ++            if ((index < numArgs) &&
    ++                    (args[index] == String16("--dispsync"))) {
    ++                index++;
    ++                mPrimaryDispSync.dump(result);
    ++                dumpAll = false;
    ++            }
    ++
    ++            if ((index < numArgs) &&
    ++                    (args[index] == String16("--static-screen"))) {
    ++                index++;
    ++                dumpStaticScreenStats(result);
    ++                dumpAll = false;
    ++            }
    ++
    ++            if ((index < numArgs) &&
    ++                    (args[index] == String16("--fences"))) {
    ++                index++;
    ++                mFenceTracker.dump(&result);
    ++                dumpAll = false;
    ++            }
    ++        }
    ++
    ++        if (dumpAll) {
    ++            dumpAllLocked(args, index, result);
    ++        }
    ++
    ++        if (locked) {
    ++            mStateLock.unlock();
    ++        }
    ++    }
    ++    write(fd, result.string(), result.size());
    ++    return NO_ERROR;
    ++}
    ++
    ++void SurfaceFlinger::listLayersLocked(const Vector<String16>& /* args */,
    ++        size_t& /* index */, String8& result) const
    ++{
    ++    const LayerVector& currentLayers = mCurrentState.layersSortedByZ;
    ++    const size_t count = currentLayers.size();
    ++    for (size_t i=0 ; i<count ; i++) {
    ++        const sp<Layer>& layer(currentLayers[i]);
    ++        result.appendFormat("%s\n", layer->getName().string());
    ++    }
    ++}
    ++
    ++void SurfaceFlinger::dumpStatsLocked(const Vector<String16>& args, size_t& index,
    ++        String8& result) const
    ++{
    ++    String8 name;
    ++    if (index < args.size()) {
    ++        name = String8(args[index]);
    ++        index++;
    ++    }
    ++
    ++    const nsecs_t period =
    ++            getHwComposer().getRefreshPeriod(HWC_DISPLAY_PRIMARY);
    ++    result.appendFormat("%" PRId64 "\n", period);
    ++
    ++    if (name.isEmpty()) {
    ++        mAnimFrameTracker.dumpStats(result);
    ++    } else {
    ++        const LayerVector& currentLayers = mCurrentState.layersSortedByZ;
    ++        const size_t count = currentLayers.size();
    ++        for (size_t i=0 ; i<count ; i++) {
    ++            const sp<Layer>& layer(currentLayers[i]);
    ++            if (name == layer->getName()) {
    ++                layer->dumpFrameStats(result);
    ++            }
    ++        }
    ++    }
    ++}
    ++
    ++void SurfaceFlinger::clearStatsLocked(const Vector<String16>& args, size_t& index,
    ++        String8& /* result */)
    ++{
    ++    String8 name;
    ++    if (index < args.size()) {
    ++        name = String8(args[index]);
    ++        index++;
    ++    }
    ++
    ++    const LayerVector& currentLayers = mCurrentState.layersSortedByZ;
    ++    const size_t count = currentLayers.size();
    ++    for (size_t i=0 ; i<count ; i++) {
    ++        const sp<Layer>& layer(currentLayers[i]);
    ++        if (name.isEmpty() || (name == layer->getName())) {
    ++            layer->clearFrameStats();
    ++        }
    ++    }
    ++
    ++    mAnimFrameTracker.clearStats();
    ++}
    ++
    ++// This should only be called from the main thread.  Otherwise it would need
    ++// the lock and should use mCurrentState rather than mDrawingState.
    ++void SurfaceFlinger::logFrameStats() {
    ++    const LayerVector& drawingLayers = mDrawingState.layersSortedByZ;
    ++    const size_t count = drawingLayers.size();
    ++    for (size_t i=0 ; i<count ; i++) {
    ++        const sp<Layer>& layer(drawingLayers[i]);
    ++        layer->logFrameStats();
    ++    }
    ++
    ++    mAnimFrameTracker.logAndResetStats(String8("<win-anim>"));
    ++}
    ++
    ++/*static*/ void SurfaceFlinger::appendSfConfigString(String8& result)
    ++{
    ++    static const char* config =
    ++            " [sf"
    ++#ifdef HAS_CONTEXT_PRIORITY
    ++            " HAS_CONTEXT_PRIORITY"
    ++#endif
    ++#ifdef NEVER_DEFAULT_TO_ASYNC_MODE
    ++            " NEVER_DEFAULT_TO_ASYNC_MODE"
    ++#endif
    ++#ifdef TARGET_DISABLE_TRIPLE_BUFFERING
    ++            " TARGET_DISABLE_TRIPLE_BUFFERING"
    ++#endif
    ++            "]";
    ++    result.append(config);
    ++}
    ++
    ++void SurfaceFlinger::dumpStaticScreenStats(String8& result) const
    ++{
    ++    result.appendFormat("Static screen stats:\n");
    ++    for (size_t b = 0; b < NUM_BUCKETS - 1; ++b) {
    ++        float bucketTimeSec = mFrameBuckets[b] / 1e9;
    ++        float percent = 100.0f *
    ++                static_cast<float>(mFrameBuckets[b]) / mTotalTime;
    ++        result.appendFormat("  < %zd frames: %.3f s (%.1f%%)\n",
    ++                b + 1, bucketTimeSec, percent);
    ++    }
    ++    float bucketTimeSec = mFrameBuckets[NUM_BUCKETS - 1] / 1e9;
    ++    float percent = 100.0f *
    ++            static_cast<float>(mFrameBuckets[NUM_BUCKETS - 1]) / mTotalTime;
    ++    result.appendFormat("  %zd+ frames: %.3f s (%.1f%%)\n",
    ++            NUM_BUCKETS - 1, bucketTimeSec, percent);
    ++}
    ++
    ++void SurfaceFlinger::recordBufferingStats(const char* layerName,
    ++        std::vector<OccupancyTracker::Segment>&& history) {
    ++    Mutex::Autolock lock(mBufferingStatsMutex);
    ++    auto& stats = mBufferingStats[layerName];
    ++    for (const auto& segment : history) {
    ++        if (!segment.usedThirdBuffer) {
    ++            stats.twoBufferTime += segment.totalTime;
    ++        }
    ++        if (segment.occupancyAverage < 1.0f) {
    ++            stats.doubleBufferedTime += segment.totalTime;
    ++        } else if (segment.occupancyAverage < 2.0f) {
    ++            stats.tripleBufferedTime += segment.totalTime;
    ++        }
    ++        ++stats.numSegments;
    ++        stats.totalTime += segment.totalTime;
    ++    }
    ++}
    ++
    ++void SurfaceFlinger::dumpBufferingStats(String8& result) const {
    ++    result.append("Buffering stats:\n");
    ++    result.append("  [Layer name] <Active time> <Two buffer> "
    ++            "<Double buffered> <Triple buffered>\n");
    ++    Mutex::Autolock lock(mBufferingStatsMutex);
    ++    typedef std::tuple<std::string, float, float, float> BufferTuple;
    ++    std::map<float, BufferTuple, std::greater<float>> sorted;
    ++    for (const auto& statsPair : mBufferingStats) {
    ++        const char* name = statsPair.first.c_str();
    ++        const BufferingStats& stats = statsPair.second;
    ++        if (stats.numSegments == 0) {
    ++            continue;
    ++        }
    ++        float activeTime = ns2ms(stats.totalTime) / 1000.0f;
    ++        float twoBufferRatio = static_cast<float>(stats.twoBufferTime) /
    ++                stats.totalTime;
    ++        float doubleBufferRatio = static_cast<float>(
    ++                stats.doubleBufferedTime) / stats.totalTime;
    ++        float tripleBufferRatio = static_cast<float>(
    ++                stats.tripleBufferedTime) / stats.totalTime;
    ++        sorted.insert({activeTime, {name, twoBufferRatio,
    ++                doubleBufferRatio, tripleBufferRatio}});
    ++    }
    ++    for (const auto& sortedPair : sorted) {
    ++        float activeTime = sortedPair.first;
    ++        const BufferTuple& values = sortedPair.second;
    ++        result.appendFormat("  [%s] %.2f %.3f %.3f %.3f\n",
    ++                std::get<0>(values).c_str(), activeTime,
    ++                std::get<1>(values), std::get<2>(values),
    ++                std::get<3>(values));
    ++    }
    ++    result.append("\n");
    ++}
    ++
    ++void SurfaceFlinger::dumpAllLocked(const Vector<String16>& args, size_t& index,
    ++        String8& result) const
    ++{
    ++    bool colorize = false;
    ++    if (index < args.size()
    ++            && (args[index] == String16("--color"))) {
    ++        colorize = true;
    ++        index++;
    ++    }
    ++
    ++    Colorizer colorizer(colorize);
    ++
    ++    // figure out if we're stuck somewhere
    ++    const nsecs_t now = systemTime();
    ++    const nsecs_t inSwapBuffers(mDebugInSwapBuffers);
    ++    const nsecs_t inTransaction(mDebugInTransaction);
    ++    nsecs_t inSwapBuffersDuration = (inSwapBuffers) ? now-inSwapBuffers : 0;
    ++    nsecs_t inTransactionDuration = (inTransaction) ? now-inTransaction : 0;
    ++
    ++    /*
    ++     * Dump library configuration.
    ++     */
    ++
    ++    colorizer.bold(result);
    ++    result.append("Build configuration:");
    ++    colorizer.reset(result);
    ++    appendSfConfigString(result);
    ++    appendUiConfigString(result);
    ++    appendGuiConfigString(result);
    ++    result.append("\n");
    ++
    ++    colorizer.bold(result);
    ++    result.append("Sync configuration: ");
    ++    colorizer.reset(result);
    ++    result.append(SyncFeatures::getInstance().toString());
    ++    result.append("\n");
    ++
    ++    colorizer.bold(result);
    ++    result.append("DispSync configuration: ");
    ++    colorizer.reset(result);
    ++    result.appendFormat("app phase %" PRId64 " ns, sf phase %" PRId64 " ns, "
    ++            "present offset %d ns (refresh %" PRId64 " ns)",
    ++        vsyncPhaseOffsetNs, sfVsyncPhaseOffsetNs, PRESENT_TIME_OFFSET_FROM_VSYNC_NS,
    ++        mHwc->getRefreshPeriod(HWC_DISPLAY_PRIMARY));
    ++    result.append("\n");
    ++
    ++    // Dump static screen stats
    ++    result.append("\n");
    ++    dumpStaticScreenStats(result);
    ++    result.append("\n");
    ++
    ++    dumpBufferingStats(result);
    ++
    ++    /*
    ++     * Dump the visible layer list
    ++     */
    ++    const LayerVector& currentLayers = mCurrentState.layersSortedByZ;
    ++    const size_t count = currentLayers.size();
    ++    colorizer.bold(result);
    ++    result.appendFormat("Visible layers (count = %zu)\n", count);
    ++    colorizer.reset(result);
    ++    for (size_t i=0 ; i<count ; i++) {
    ++        const sp<Layer>& layer(currentLayers[i]);
    ++        layer->dump(result, colorizer);
    ++    }
    ++
    ++    /*
    ++     * Dump Display state
    ++     */
    ++
    ++    colorizer.bold(result);
    ++    result.appendFormat("Displays (%zu entries)\n", mDisplays.size());
    ++    colorizer.reset(result);
    ++    for (size_t dpy=0 ; dpy<mDisplays.size() ; dpy++) {
    ++        const sp<const DisplayDevice>& hw(mDisplays[dpy]);
    ++        hw->dump(result);
    ++    }
    ++
    ++    /*
    ++     * Dump SurfaceFlinger global state
    ++     */
    ++
    ++    colorizer.bold(result);
    ++    result.append("SurfaceFlinger global state:\n");
    ++    colorizer.reset(result);
    ++
    ++    HWComposer& hwc(getHwComposer());
    ++    sp<const DisplayDevice> hw(getDefaultDisplayDevice());
    ++
    ++    colorizer.bold(result);
    ++    result.appendFormat("EGL implementation : %s\n",
    ++            eglQueryStringImplementationANDROID(mEGLDisplay, EGL_VERSION));
    ++    colorizer.reset(result);
    ++    result.appendFormat("%s\n",
    ++            eglQueryStringImplementationANDROID(mEGLDisplay, EGL_EXTENSIONS));
    ++
    ++    mRenderEngine->dump(result);
    ++
    ++    hw->undefinedRegion.dump(result, "undefinedRegion");
    ++    result.appendFormat("  orientation=%d, isDisplayOn=%d\n",
    ++            hw->getOrientation(), hw->isDisplayOn());
    ++    result.appendFormat(
    ++            "  last eglSwapBuffers() time: %f us\n"
    ++            "  last transaction time     : %f us\n"
    ++            "  transaction-flags         : %08x\n"
    ++            "  refresh-rate              : %f fps\n"
    ++            "  x-dpi                     : %f\n"
    ++            "  y-dpi                     : %f\n"
    ++            "  gpu_to_cpu_unsupported    : %d\n"
    ++            ,
    ++            mLastSwapBufferTime/1000.0,
    ++            mLastTransactionTime/1000.0,
    ++            mTransactionFlags,
    ++            1e9 / hwc.getRefreshPeriod(HWC_DISPLAY_PRIMARY),
    ++            hwc.getDpiX(HWC_DISPLAY_PRIMARY),
    ++            hwc.getDpiY(HWC_DISPLAY_PRIMARY),
    ++            !mGpuToCpuSupported);
    ++
    ++    result.appendFormat("  eglSwapBuffers time: %f us\n",
    ++            inSwapBuffersDuration/1000.0);
    ++
    ++    result.appendFormat("  transaction time: %f us\n",
    ++            inTransactionDuration/1000.0);
    ++
    ++    /*
    ++     * VSYNC state
    ++     */
    ++    mEventThread->dump(result);
    ++
    ++    /*
    ++     * Dump HWComposer state
    ++     */
    ++    colorizer.bold(result);
    ++    result.append("h/w composer state:\n");
    ++    colorizer.reset(result);
    ++    result.appendFormat("  h/w composer %s and %s\n",
    ++            hwc.initCheck()==NO_ERROR ? "present" : "not present",
    ++                    (mDebugDisableHWC || mDebugRegion || mDaltonize
    ++                            || mHasColorMatrix) ? "disabled" : "enabled");
    ++    hwc.dump(result);
    ++
    ++    /*
    ++     * Dump gralloc state
    ++     */
    ++    const GraphicBufferAllocator& alloc(GraphicBufferAllocator::get());
    ++    alloc.dump(result);
    ++}
    ++
    ++const Vector< sp<Layer> >&
    ++SurfaceFlinger::getLayerSortedByZForHwcDisplay(int id) {
    ++    // Note: mStateLock is held here
    ++    wp<IBinder> dpy;
    ++    for (size_t i=0 ; i<mDisplays.size() ; i++) {
    ++        if (mDisplays.valueAt(i)->getHwcDisplayId() == id) {
    ++            dpy = mDisplays.keyAt(i);
    ++            break;
    ++        }
    ++    }
    ++    if (dpy == NULL) {
    ++        ALOGE("getLayerSortedByZForHwcDisplay: invalid hwc display id %d", id);
    ++        // Just use the primary display so we have something to return
    ++        dpy = getBuiltInDisplay(DisplayDevice::DISPLAY_PRIMARY);
    ++    }
    ++    return getDisplayDevice(dpy)->getVisibleLayersSortedByZ();
    ++}
    ++
    ++bool SurfaceFlinger::startDdmConnection()
    ++{
    ++    void* libddmconnection_dso =
    ++            dlopen("libsurfaceflinger_ddmconnection.so", RTLD_NOW);
    ++    if (!libddmconnection_dso) {
    ++        return false;
    ++    }
    ++    void (*DdmConnection_start)(const char* name);
    ++    DdmConnection_start =
    ++            (decltype(DdmConnection_start))dlsym(libddmconnection_dso, "DdmConnection_start");
    ++    if (!DdmConnection_start) {
    ++        dlclose(libddmconnection_dso);
    ++        return false;
    ++    }
    ++    (*DdmConnection_start)(getServiceName());
    ++    return true;
    ++}
    ++
    ++status_t SurfaceFlinger::onTransact(
    ++    uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
    ++{
    ++    switch (code) {
    ++        case CREATE_CONNECTION:
    ++        case CREATE_DISPLAY:
    ++        case SET_TRANSACTION_STATE:
    ++        case BOOT_FINISHED:
    ++        case CLEAR_ANIMATION_FRAME_STATS:
    ++        case GET_ANIMATION_FRAME_STATS:
    ++        case SET_POWER_MODE:
    ++        case GET_HDR_CAPABILITIES:
    ++        {
    ++            // codes that require permission check
    ++            IPCThreadState* ipc = IPCThreadState::self();
    ++            const int pid = ipc->getCallingPid();
    ++            const int uid = ipc->getCallingUid();
    ++            if ((uid != AID_GRAPHICS && uid != AID_SYSTEM) &&
    ++                    !PermissionCache::checkPermission(sAccessSurfaceFlinger, pid, uid)) {
    ++                ALOGE("Permission Denial: "
    ++                        "can't access SurfaceFlinger pid=%d, uid=%d", pid, uid);
    ++                return PERMISSION_DENIED;
    ++            }
    ++            break;
    ++        }
    ++        case CAPTURE_SCREEN:
    ++        {
    ++            // codes that require permission check
    ++            IPCThreadState* ipc = IPCThreadState::self();
    ++            const int pid = ipc->getCallingPid();
    ++            const int uid = ipc->getCallingUid();
    ++            if ((uid != AID_GRAPHICS) &&
    ++                    !PermissionCache::checkPermission(sReadFramebuffer, pid, uid)) {
    ++                ALOGE("Permission Denial: "
    ++                        "can't read framebuffer pid=%d, uid=%d", pid, uid);
    ++                return PERMISSION_DENIED;
    ++            }
    ++            break;
    ++        }
    ++    }
    ++
    ++    status_t err = BnSurfaceComposer::onTransact(code, data, reply, flags);
    ++    if (err == UNKNOWN_TRANSACTION || err == PERMISSION_DENIED) {
    ++        CHECK_INTERFACE(ISurfaceComposer, data, reply);
    ++        if (CC_UNLIKELY(!PermissionCache::checkCallingPermission(sHardwareTest))) {
    ++            IPCThreadState* ipc = IPCThreadState::self();
    ++            const int pid = ipc->getCallingPid();
    ++            const int uid = ipc->getCallingUid();
    ++            ALOGE("Permission Denial: "
    ++                    "can't access SurfaceFlinger pid=%d, uid=%d", pid, uid);
    ++            return PERMISSION_DENIED;
    ++        }
    ++        int n;
    ++        switch (code) {
    ++            case 1000: // SHOW_CPU, NOT SUPPORTED ANYMORE
    ++            case 1001: // SHOW_FPS, NOT SUPPORTED ANYMORE
    ++                return NO_ERROR;
    ++            case 1002:  // SHOW_UPDATES
    ++                n = data.readInt32();
    ++                mDebugRegion = n ? n : (mDebugRegion ? 0 : 1);
    ++                invalidateHwcGeometry();
    ++                repaintEverything();
    ++                return NO_ERROR;
    ++            case 1004:{ // repaint everything
    ++                repaintEverything();
    ++                return NO_ERROR;
    ++            }
    ++            case 1005:{ // force transaction
    ++                setTransactionFlags(
    ++                        eTransactionNeeded|
    ++                        eDisplayTransactionNeeded|
    ++                        eTraversalNeeded);
    ++                return NO_ERROR;
    ++            }
    ++            case 1006:{ // send empty update
    ++                signalRefresh();
    ++                return NO_ERROR;
    ++            }
    ++            case 1008:  // toggle use of hw composer
    ++                n = data.readInt32();
    ++                mDebugDisableHWC = n ? 1 : 0;
    ++                invalidateHwcGeometry();
    ++                repaintEverything();
    ++                return NO_ERROR;
    ++            case 1009:  // toggle use of transform hint
    ++                n = data.readInt32();
    ++                mDebugDisableTransformHint = n ? 1 : 0;
    ++                invalidateHwcGeometry();
    ++                repaintEverything();
    ++                return NO_ERROR;
    ++            case 1010:  // interrogate.
    ++                reply->writeInt32(0);
    ++                reply->writeInt32(0);
    ++                reply->writeInt32(mDebugRegion);
    ++                reply->writeInt32(0);
    ++                reply->writeInt32(mDebugDisableHWC);
    ++                return NO_ERROR;
    ++            case 1013: {
    ++                Mutex::Autolock _l(mStateLock);
    ++                sp<const DisplayDevice> hw(getDefaultDisplayDevice());
    ++                reply->writeInt32(hw->getPageFlipCount());
    ++                return NO_ERROR;
    ++            }
    ++            case 1014: {
    ++                // daltonize
    ++                n = data.readInt32();
    ++                switch (n % 10) {
    ++                    case 1:
    ++                        mDaltonizer.setType(ColorBlindnessType::Protanomaly);
    ++                        break;
    ++                    case 2:
    ++                        mDaltonizer.setType(ColorBlindnessType::Deuteranomaly);
    ++                        break;
    ++                    case 3:
    ++                        mDaltonizer.setType(ColorBlindnessType::Tritanomaly);
    ++                        break;
    ++                }
    ++                if (n >= 10) {
    ++                    mDaltonizer.setMode(ColorBlindnessMode::Correction);
    ++                } else {
    ++                    mDaltonizer.setMode(ColorBlindnessMode::Simulation);
    ++                }
    ++                mDaltonize = n > 0;
    ++                invalidateHwcGeometry();
    ++                repaintEverything();
    ++                return NO_ERROR;
    ++            }
    ++            case 1015: {
    ++                // apply a color matrix
    ++                n = data.readInt32();
    ++                mHasColorMatrix = n ? 1 : 0;
    ++                if (n) {
    ++                    // color matrix is sent as mat3 matrix followed by vec3
    ++                    // offset, then packed into a mat4 where the last row is
    ++                    // the offset and extra values are 0
    ++                    for (size_t i = 0 ; i < 4; i++) {
    ++                      for (size_t j = 0; j < 4; j++) {
    ++                          mColorMatrix[i][j] = data.readFloat();
    ++                      }
    ++                    }
    ++                } else {
    ++                    mColorMatrix = mat4();
    ++                }
    ++                invalidateHwcGeometry();
    ++                repaintEverything();
    ++                return NO_ERROR;
    ++            }
    ++            // This is an experimental interface
    ++            // Needs to be shifted to proper binder interface when we productize
    ++            case 1016: {
    ++                n = data.readInt32();
    ++                mPrimaryDispSync.setRefreshSkipCount(n);
    ++                return NO_ERROR;
    ++            }
    ++            case 1017: {
    ++                n = data.readInt32();
    ++                mForceFullDamage = static_cast<bool>(n);
    ++                return NO_ERROR;
    ++            }
    ++            case 1018: { // Modify Choreographer's phase offset
    ++                n = data.readInt32();
    ++                mEventThread->setPhaseOffset(static_cast<nsecs_t>(n));
    ++                return NO_ERROR;
    ++            }
    ++            case 1019: { // Modify SurfaceFlinger's phase offset
    ++                n = data.readInt32();
    ++                mSFEventThread->setPhaseOffset(static_cast<nsecs_t>(n));
    ++                return NO_ERROR;
    ++            }
    ++            case 1021: { // Disable HWC virtual displays
    ++                n = data.readInt32();
    ++                mUseHwcVirtualDisplays = !n;
    ++                return NO_ERROR;
    ++            }
    ++        }
    ++    }
    ++    return err;
    ++}
    ++
    ++void SurfaceFlinger::repaintEverything() {
    ++    android_atomic_or(1, &mRepaintEverything);
    ++    signalTransaction();
    ++}
    ++
    ++// ---------------------------------------------------------------------------
    ++// Capture screen into an IGraphiBufferProducer
    ++// ---------------------------------------------------------------------------
    ++
    ++/* The code below is here to handle b/8734824
    ++ *
    ++ * We create a IGraphicBufferProducer wrapper that forwards all calls
    ++ * from the surfaceflinger thread to the calling binder thread, where they
    ++ * are executed. This allows the calling thread in the calling process to be
    ++ * reused and not depend on having "enough" binder threads to handle the
    ++ * requests.
    ++ */
    ++class GraphicProducerWrapper : public BBinder, public MessageHandler {
    ++    /* Parts of GraphicProducerWrapper are run on two different threads,
    ++     * communicating by sending messages via Looper but also by shared member
    ++     * data. Coherence maintenance is subtle and in places implicit (ugh).
    ++     *
    ++     * Don't rely on Looper's sendMessage/handleMessage providing
    ++     * release/acquire semantics for any data not actually in the Message.
    ++     * Data going from surfaceflinger to binder threads needs to be
    ++     * synchronized explicitly.
    ++     *
    ++     * Barrier open/wait do provide release/acquire semantics. This provides
    ++     * implicit synchronization for data coming back from binder to
    ++     * surfaceflinger threads.
    ++     */
    ++
    ++    sp<IGraphicBufferProducer> impl;
    ++    sp<Looper> looper;
    ++    status_t result;
    ++    bool exitPending;
    ++    bool exitRequested;
    ++    Barrier barrier;
    ++    uint32_t code;
    ++    Parcel const* data;
    ++    Parcel* reply;
    ++
    ++    enum {
    ++        MSG_API_CALL,
    ++        MSG_EXIT
    ++    };
    ++
    ++    /*
    ++     * Called on surfaceflinger thread. This is called by our "fake"
    ++     * BpGraphicBufferProducer. We package the data and reply Parcel and
    ++     * forward them to the binder thread.
    ++     */
    ++    virtual status_t transact(uint32_t code,
    ++            const Parcel& data, Parcel* reply, uint32_t /* flags */) {
    ++        this->code = code;
    ++        this->data = &data;
    ++        this->reply = reply;
    ++        if (exitPending) {
    ++            // if we've exited, we run the message synchronously right here.
    ++            // note (JH): as far as I can tell from looking at the code, this
    ++            // never actually happens. if it does, i'm not sure if it happens
    ++            // on the surfaceflinger or binder thread.
    ++            handleMessage(Message(MSG_API_CALL));
    ++        } else {
    ++            barrier.close();
    ++            // Prevent stores to this->{code, data, reply} from being
    ++            // reordered later than the construction of Message.
    ++            atomic_thread_fence(memory_order_release);
    ++            looper->sendMessage(this, Message(MSG_API_CALL));
    ++            barrier.wait();
    ++        }
    ++        return result;
    ++    }
    ++
    ++    /*
    ++     * here we run on the binder thread. All we've got to do is
    ++     * call the real BpGraphicBufferProducer.
    ++     */
    ++    virtual void handleMessage(const Message& message) {
    ++        int what = message.what;
    ++        // Prevent reads below from happening before the read from Message
    ++        atomic_thread_fence(memory_order_acquire);
    ++        if (what == MSG_API_CALL) {
    ++            result = IInterface::asBinder(impl)->transact(code, data[0], reply);
    ++            barrier.open();
    ++        } else if (what == MSG_EXIT) {
    ++            exitRequested = true;
    ++        }
    ++    }
    ++
    ++public:
    ++    GraphicProducerWrapper(const sp<IGraphicBufferProducer>& impl)
    ++    :   impl(impl),
    ++        looper(new Looper(true)),
    ++        result(NO_ERROR),
    ++        exitPending(false),
    ++        exitRequested(false),
    ++        code(0),
    ++        data(NULL),
    ++        reply(NULL)
    ++    {}
    ++
    ++    // Binder thread
    ++    status_t waitForResponse() {
    ++        do {
    ++            looper->pollOnce(-1);
    ++        } while (!exitRequested);
    ++        return result;
    ++    }
    ++
    ++    // Client thread
    ++    void exit(status_t result) {
    ++        this->result = result;
    ++        exitPending = true;
    ++        // Ensure this->result is visible to the binder thread before it
    ++        // handles the message.
    ++        atomic_thread_fence(memory_order_release);
    ++        looper->sendMessage(this, Message(MSG_EXIT));
    ++    }
    ++};
    ++
    ++
    ++status_t SurfaceFlinger::captureScreen(const sp<IBinder>& display,
    ++        const sp<IGraphicBufferProducer>& producer,
    ++        Rect sourceCrop, uint32_t reqWidth, uint32_t reqHeight,
    ++        uint32_t minLayerZ, uint32_t maxLayerZ,
    ++        bool useIdentityTransform, ISurfaceComposer::Rotation rotation,
    ++        bool useReadPixels) {
    ++
    ++    if (CC_UNLIKELY(display == 0))
    ++        return BAD_VALUE;
    ++
    ++    if (CC_UNLIKELY(producer == 0))
    ++        return BAD_VALUE;
    ++
    ++    // if we have secure windows on this display, never allow the screen capture
    ++    // unless the producer interface is local (i.e.: we can take a screenshot for
    ++    // ourselves).
    ++    bool isLocalScreenshot = IInterface::asBinder(producer)->localBinder();
    ++
    ++    // Convert to surfaceflinger's internal rotation type.
    ++    Transform::orientation_flags rotationFlags;
    ++    switch (rotation) {
    ++        case ISurfaceComposer::eRotateNone:
    ++            rotationFlags = Transform::ROT_0;
    ++            break;
    ++        case ISurfaceComposer::eRotate90:
    ++            rotationFlags = Transform::ROT_90;
    ++            break;
    ++        case ISurfaceComposer::eRotate180:
    ++            rotationFlags = Transform::ROT_180;
    ++            break;
    ++        case ISurfaceComposer::eRotate270:
    ++            rotationFlags = Transform::ROT_270;
    ++            break;
    ++        default:
    ++            rotationFlags = Transform::ROT_0;
    ++            ALOGE("Invalid rotation passed to captureScreen(): %d\n", rotation);
    ++            break;
    ++    }
    ++
    ++    class MessageCaptureScreen : public MessageBase {
    ++        SurfaceFlinger* flinger;
    ++        sp<IBinder> display;
    ++        sp<IGraphicBufferProducer> producer;
    ++        Rect sourceCrop;
    ++        uint32_t reqWidth, reqHeight;
    ++        uint32_t minLayerZ,maxLayerZ;
    ++        bool useIdentityTransform;
    ++        Transform::orientation_flags rotation;
    ++        status_t result;
    ++        bool useReadPixels;
    ++        bool isLocalScreenshot;
    ++    public:
    ++        MessageCaptureScreen(SurfaceFlinger* flinger,
    ++                const sp<IBinder>& display,
    ++                const sp<IGraphicBufferProducer>& producer,
    ++                Rect sourceCrop, uint32_t reqWidth, uint32_t reqHeight,
    ++                uint32_t minLayerZ, uint32_t maxLayerZ,
    ++                bool useIdentityTransform,
    ++                Transform::orientation_flags rotation,
    ++                bool isLocalScreenshot, bool useReadPixels)
    ++            : flinger(flinger), display(display), producer(producer),
    ++              sourceCrop(sourceCrop), reqWidth(reqWidth), reqHeight(reqHeight),
    ++              minLayerZ(minLayerZ), maxLayerZ(maxLayerZ),
    ++              useIdentityTransform(useIdentityTransform),
    ++              rotation(rotation), result(PERMISSION_DENIED),
    ++              useReadPixels(useReadPixels),
    ++              isLocalScreenshot(isLocalScreenshot)
    ++        {
    ++        }
    ++        status_t getResult() const {
    ++            return result;
    ++        }
    ++        virtual bool handler() {
    ++            Mutex::Autolock _l(flinger->mStateLock);
    ++            sp<const DisplayDevice> hw(flinger->getDisplayDevice(display));
    ++            bool useReadPixels = this->useReadPixels && !flinger->mGpuToCpuSupported;
    ++            result = flinger->captureScreenImplLocked(hw, producer,
    ++                    sourceCrop, reqWidth, reqHeight, minLayerZ, maxLayerZ,
    ++                    useIdentityTransform, rotation, isLocalScreenshot, useReadPixels);
    ++            static_cast<GraphicProducerWrapper*>(IInterface::asBinder(producer).get())->exit(result);
    ++            return true;
    ++        }
    ++    };
    ++
    ++    // this creates a "fake" BBinder which will serve as a "fake" remote
    ++    // binder to receive the marshaled calls and forward them to the
    ++    // real remote (a BpGraphicBufferProducer)
    ++    sp<GraphicProducerWrapper> wrapper = new GraphicProducerWrapper(producer);
    ++
    ++    // the asInterface() call below creates our "fake" BpGraphicBufferProducer
    ++    // which does the marshaling work forwards to our "fake remote" above.
    ++    sp<MessageBase> msg = new MessageCaptureScreen(this,
    ++            display, IGraphicBufferProducer::asInterface( wrapper ),
    ++            sourceCrop, reqWidth, reqHeight, minLayerZ, maxLayerZ,
    ++            useIdentityTransform, rotationFlags, isLocalScreenshot, useReadPixels);
    ++
    ++    status_t res = postMessageAsync(msg);
    ++    if (res == NO_ERROR) {
    ++        res = wrapper->waitForResponse();
    ++    }
    ++    return res;
    ++}
    ++
    ++
    ++void SurfaceFlinger::renderScreenImplLocked(
    ++        const sp<const DisplayDevice>& hw,
    ++        Rect sourceCrop, uint32_t reqWidth, uint32_t reqHeight,
    ++        uint32_t minLayerZ, uint32_t maxLayerZ,
    ++        bool yswap, bool useIdentityTransform, Transform::orientation_flags rotation)
    ++{
    ++    ATRACE_CALL();
    ++    RenderEngine& engine(getRenderEngine());
    ++
    ++    // get screen geometry
    ++    const int32_t hw_w = hw->getWidth();
    ++    const int32_t hw_h = hw->getHeight();
    ++    const bool filtering = static_cast<int32_t>(reqWidth) != hw_w ||
    ++                           static_cast<int32_t>(reqHeight) != hw_h;
    ++
    ++    // if a default or invalid sourceCrop is passed in, set reasonable values
    ++    if (sourceCrop.width() == 0 || sourceCrop.height() == 0 ||
    ++            !sourceCrop.isValid()) {
    ++        sourceCrop.setLeftTop(Point(0, 0));
    ++        sourceCrop.setRightBottom(Point(hw_w, hw_h));
    ++    }
    ++
    ++    // ensure that sourceCrop is inside screen
    ++    if (sourceCrop.left < 0) {
    ++        ALOGE("Invalid crop rect: l = %d (< 0)", sourceCrop.left);
    ++    }
    ++    if (sourceCrop.right > hw_w) {
    ++        ALOGE("Invalid crop rect: r = %d (> %d)", sourceCrop.right, hw_w);
    ++    }
    ++    if (sourceCrop.top < 0) {
    ++        ALOGE("Invalid crop rect: t = %d (< 0)", sourceCrop.top);
    ++    }
    ++    if (sourceCrop.bottom > hw_h) {
    ++        ALOGE("Invalid crop rect: b = %d (> %d)", sourceCrop.bottom, hw_h);
    ++    }
    ++
    ++    // make sure to clear all GL error flags
    ++    engine.checkErrors();
    ++
    ++    // set-up our viewport
    ++    engine.setViewportAndProjection(
    ++        reqWidth, reqHeight, sourceCrop, hw_h, yswap, rotation);
    ++    engine.disableTexturing();
    ++
    ++    // redraw the screen entirely...
    ++    engine.clearWithColor(0, 0, 0, 1);
    ++
    ++    const LayerVector& layers( mDrawingState.layersSortedByZ );
    ++    const size_t count = layers.size();
    ++    for (size_t i=0 ; i<count ; ++i) {
    ++        const sp<Layer>& layer(layers[i]);
    ++        const Layer::State& state(layer->getDrawingState());
    ++        if (state.layerStack == hw->getLayerStack()) {
    ++            if (state.z >= minLayerZ && state.z <= maxLayerZ) {
    ++                if (layer->isVisible()) {
    ++                    if (filtering) layer->setFiltering(true);
    ++                    layer->draw(hw, useIdentityTransform);
    ++                    if (filtering) layer->setFiltering(false);
    ++                }
    ++            }
    ++        }
    ++    }
    ++
    ++    // compositionComplete is needed for older driver
    ++    hw->compositionComplete();
    ++    hw->setViewportAndProjection();
    ++}
    ++
    ++
    ++status_t SurfaceFlinger::captureScreenImplLocked(
    ++        const sp<const DisplayDevice>& hw,
    ++        const sp<IGraphicBufferProducer>& producer,
    ++        Rect sourceCrop, uint32_t reqWidth, uint32_t reqHeight,
    ++        uint32_t minLayerZ, uint32_t maxLayerZ,
    ++        bool useIdentityTransform, Transform::orientation_flags rotation,
    ++        bool isLocalScreenshot, bool useReadPixels)
    ++{
    ++    ATRACE_CALL();
    ++
    ++    // get screen geometry
    ++    uint32_t hw_w = hw->getWidth();
    ++    uint32_t hw_h = hw->getHeight();
    ++
    ++    if (rotation & Transform::ROT_90) {
    ++        std::swap(hw_w, hw_h);
    ++    }
    ++
    ++    if ((reqWidth > hw_w) || (reqHeight > hw_h)) {
    ++        ALOGE("size mismatch (%d, %d) > (%d, %d)",
    ++                reqWidth, reqHeight, hw_w, hw_h);
    ++        return BAD_VALUE;
    ++    }
    ++
    ++    reqWidth  = (!reqWidth)  ? hw_w : reqWidth;
    ++    reqHeight = (!reqHeight) ? hw_h : reqHeight;
    ++
    ++    bool secureLayerIsVisible = false;
    ++    const LayerVector& layers(mDrawingState.layersSortedByZ);
    ++    const size_t count = layers.size();
    ++    for (size_t i = 0 ; i < count ; ++i) {
    ++        const sp<Layer>& layer(layers[i]);
    ++        const Layer::State& state(layer->getDrawingState());
    ++        if (state.layerStack == hw->getLayerStack() && state.z >= minLayerZ &&
    ++                state.z <= maxLayerZ && layer->isVisible() &&
    ++                layer->isSecure()) {
    ++            secureLayerIsVisible = true;
    ++        }
    ++    }
    ++
    ++    if (!isLocalScreenshot && secureLayerIsVisible) {
    ++        ALOGW("FB is protected: PERMISSION_DENIED");
    ++        return PERMISSION_DENIED;
    ++    }
    ++
    ++    // create a surface (because we're a producer, and we need to
    ++    // dequeue/queue a buffer)
    ++    sp<Surface> sur = new Surface(producer, false);
    ++    ANativeWindow* window = sur.get();
    ++
    ++    status_t result = native_window_api_connect(window, NATIVE_WINDOW_API_EGL);
    ++    if (result == NO_ERROR) {
    ++        uint32_t usage = GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN |
    ++                        GRALLOC_USAGE_HW_RENDER | GRALLOC_USAGE_HW_TEXTURE;
    ++
    ++        int err = 0;
    ++        err = native_window_set_buffers_dimensions(window, reqWidth, reqHeight);
    ++        err |= native_window_set_scaling_mode(window, NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW);
    ++        err |= native_window_set_buffers_format(window, HAL_PIXEL_FORMAT_RGBA_8888);
    ++        err |= native_window_set_usage(window, usage);
    ++
    ++        if (err == NO_ERROR) {
    ++            ANativeWindowBuffer* buffer;
    ++            /* TODO: Once we have the sync framework everywhere this can use
    ++             * server-side waits on the fence that dequeueBuffer returns.
    ++             */
    ++            result = native_window_dequeue_buffer_and_wait(window,  &buffer);
    ++            if (result == NO_ERROR) {
    ++                int syncFd = -1;
    ++                // create an EGLImage from the buffer so we can later
    ++                // turn it into a texture
    ++                EGLImageKHR image = eglCreateImageKHR(mEGLDisplay, EGL_NO_CONTEXT,
    ++                        EGL_NATIVE_BUFFER_ANDROID, buffer, NULL);
    ++                if (image != EGL_NO_IMAGE_KHR) {
    ++                    // this binds the given EGLImage as a framebuffer for the
    ++                    // duration of this scope.
    ++                    RenderEngine::BindImageAsFramebuffer imageBond(getRenderEngine(), image, useReadPixels, reqWidth, reqHeight);
    ++                    if (imageBond.getStatus() == NO_ERROR) {
    ++                        // this will in fact render into our dequeued buffer
    ++                        // via an FBO, which means we didn't have to create
    ++                        // an EGLSurface and therefore we're not
    ++                        // dependent on the context's EGLConfig.
    ++                        renderScreenImplLocked(
    ++                            hw, sourceCrop, reqWidth, reqHeight, minLayerZ, maxLayerZ, true,
    ++                            useIdentityTransform, rotation);
    ++
    ++                        // Attempt to create a sync khr object that can produce a sync point. If that
    ++                        // isn't available, create a non-dupable sync object in the fallback path and
    ++                        // wait on it directly.
    ++                        EGLSyncKHR sync;
    ++                        if (!DEBUG_SCREENSHOTS) {
    ++                           sync = eglCreateSyncKHR(mEGLDisplay, EGL_SYNC_NATIVE_FENCE_ANDROID, NULL);
    ++                           // native fence fd will not be populated until flush() is done.
    ++                           getRenderEngine().flush();
    ++                        } else {
    ++                            sync = EGL_NO_SYNC_KHR;
    ++                        }
    ++                        if (sync != EGL_NO_SYNC_KHR) {
    ++                            // get the sync fd
    ++                            syncFd = eglDupNativeFenceFDANDROID(mEGLDisplay, sync);
    ++                            if (syncFd == EGL_NO_NATIVE_FENCE_FD_ANDROID) {
    ++                                ALOGW("captureScreen: failed to dup sync khr object");
    ++                                syncFd = -1;
    ++                            }
    ++                            eglDestroySyncKHR(mEGLDisplay, sync);
    ++                        } else {
    ++                            // fallback path
    ++                            sync = eglCreateSyncKHR(mEGLDisplay, EGL_SYNC_FENCE_KHR, NULL);
    ++                            if (sync != EGL_NO_SYNC_KHR) {
    ++                                EGLint result = eglClientWaitSyncKHR(mEGLDisplay, sync,
    ++                                    EGL_SYNC_FLUSH_COMMANDS_BIT_KHR, 2000000000 /*2 sec*/);
    ++                                EGLint eglErr = eglGetError();
    ++                                if (result == EGL_TIMEOUT_EXPIRED_KHR) {
    ++                                    ALOGW("captureScreen: fence wait timed out");
    ++                                } else {
    ++                                    ALOGW_IF(eglErr != EGL_SUCCESS,
    ++                                            "captureScreen: error waiting on EGL fence: %#x", eglErr);
    ++                                }
    ++                                eglDestroySyncKHR(mEGLDisplay, sync);
    ++                            } else {
    ++                                ALOGW("captureScreen: error creating EGL fence: %#x", eglGetError());
    ++                            }
    ++                        }
    ++
    ++                        if (useReadPixels) {
    ++                            sp<GraphicBuffer> buf = static_cast<GraphicBuffer*>(buffer);
    ++                            void* vaddr;
    ++                            if (buf->lock(GRALLOC_USAGE_SW_WRITE_OFTEN, &vaddr) == NO_ERROR) {
    ++                                getRenderEngine().readPixels(0, 0, buffer->stride, reqHeight, (uint32_t *)vaddr);
    ++                                buf->unlock();
    ++                            }
    ++                        }
    ++
    ++                        if (DEBUG_SCREENSHOTS) {
    ++                            uint32_t* pixels = new uint32_t[reqWidth*reqHeight];
    ++                            getRenderEngine().readPixels(0, 0, reqWidth, reqHeight, pixels);
    ++                            checkScreenshot(reqWidth, reqHeight, reqWidth, pixels,
    ++                                    hw, minLayerZ, maxLayerZ);
    ++                            delete [] pixels;
    ++                        }
    ++
    ++                    } else {
    ++                        ALOGE("got GL_FRAMEBUFFER_COMPLETE_OES error while taking screenshot");
    ++                        result = INVALID_OPERATION;
    ++                        window->cancelBuffer(window, buffer, syncFd);
    ++                        buffer = NULL;
    ++                    }
    ++                    // destroy our image
    ++                    eglDestroyImageKHR(mEGLDisplay, image);
    ++                } else {
    ++                    result = BAD_VALUE;
    ++                }
    ++                if (buffer) {
    ++                    // queueBuffer takes ownership of syncFd
    ++                    result = window->queueBuffer(window, buffer, syncFd);
    ++                }
    ++            }
    ++        } else {
    ++            result = BAD_VALUE;
    ++        }
    ++        native_window_api_disconnect(window, NATIVE_WINDOW_API_EGL);
    ++    }
    ++
    ++    return result;
    ++}
    ++
    ++bool SurfaceFlinger::getFrameTimestamps(const Layer& layer,
    ++        uint64_t frameNumber, FrameTimestamps* outTimestamps) {
    ++    return mFenceTracker.getFrameTimestamps(layer, frameNumber, outTimestamps);
    ++}
    ++
    ++void SurfaceFlinger::checkScreenshot(size_t w, size_t s, size_t h, void const* vaddr,
    ++        const sp<const DisplayDevice>& hw, uint32_t minLayerZ, uint32_t maxLayerZ) {
    ++    if (DEBUG_SCREENSHOTS) {
    ++        for (size_t y=0 ; y<h ; y++) {
    ++            uint32_t const * p = (uint32_t const *)vaddr + y*s;
    ++            for (size_t x=0 ; x<w ; x++) {
    ++                if (p[x] != 0xFF000000) return;
    ++            }
    ++        }
    ++        ALOGE("*** we just took a black screenshot ***\n"
    ++                "requested minz=%d, maxz=%d, layerStack=%d",
    ++                minLayerZ, maxLayerZ, hw->getLayerStack());
    ++        const LayerVector& layers( mDrawingState.layersSortedByZ );
    ++        const size_t count = layers.size();
    ++        for (size_t i=0 ; i<count ; ++i) {
    ++            const sp<Layer>& layer(layers[i]);
    ++            const Layer::State& state(layer->getDrawingState());
    ++            const bool visible = (state.layerStack == hw->getLayerStack())
    ++                                && (state.z >= minLayerZ && state.z <= maxLayerZ)
    ++                                && (layer->isVisible());
    ++            ALOGE("%c index=%zu, name=%s, layerStack=%d, z=%d, visible=%d, flags=%x, alpha=%x",
    ++                    visible ? '+' : '-',
    ++                            i, layer->getName().string(), state.layerStack, state.z,
    ++                            layer->isVisible(), state.flags, state.alpha);
    ++        }
    ++    }
    ++}
    ++
    ++// ---------------------------------------------------------------------------
    ++
    ++SurfaceFlinger::LayerVector::LayerVector() {
    ++}
    ++
    ++SurfaceFlinger::LayerVector::LayerVector(const LayerVector& rhs)
    ++    : SortedVector<sp<Layer> >(rhs) {
    ++}
    ++
    ++int SurfaceFlinger::LayerVector::do_compare(const void* lhs,
    ++    const void* rhs) const
    ++{
    ++    // sort layers per layer-stack, then by z-order and finally by sequence
    ++    const sp<Layer>& l(*reinterpret_cast<const sp<Layer>*>(lhs));
    ++    const sp<Layer>& r(*reinterpret_cast<const sp<Layer>*>(rhs));
    ++
    ++    uint32_t ls = l->getCurrentState().layerStack;
    ++    uint32_t rs = r->getCurrentState().layerStack;
    ++    if (ls != rs)
    ++        return ls - rs;
    ++
    ++    uint32_t lz = l->getCurrentState().z;
    ++    uint32_t rz = r->getCurrentState().z;
    ++    if (lz != rz)
    ++        return lz - rz;
    ++
    ++    return l->sequence - r->sequence;
    ++}
    ++
    ++// ---------------------------------------------------------------------------
    ++
    ++SurfaceFlinger::DisplayDeviceState::DisplayDeviceState()
    ++    : type(DisplayDevice::DISPLAY_ID_INVALID),
    ++      layerStack(DisplayDevice::NO_LAYER_STACK),
    ++      orientation(0),
    ++      width(0),
    ++      height(0),
    ++      isSecure(false) {
    ++}
    ++
    ++SurfaceFlinger::DisplayDeviceState::DisplayDeviceState(
    ++    DisplayDevice::DisplayType type, bool isSecure)
    ++    : type(type),
    ++      layerStack(DisplayDevice::NO_LAYER_STACK),
    ++      orientation(0),
    ++      width(0),
    ++      height(0),
    ++      isSecure(isSecure) {
    ++    viewport.makeInvalid();
    ++    frame.makeInvalid();
    ++}
    ++
    ++// ---------------------------------------------------------------------------
    ++
    ++}; // namespace android
    ++
    ++
    ++#if defined(__gl_h_)
    ++#error "don't include gl/gl.h in this file"
    ++#endif
    ++
    ++#if defined(__gl2_h_)
    ++#error "don't include gl2/gl2.h in this file"
    ++#endif
    diff --git a/hardware_ril.patch b/hardware_ril.patch
    index 4b5d125..114367f 100644
    --- a/hardware_ril.patch
    +++ b/hardware_ril.patch
    @@ -1,12 +1,54 @@
    -diff --git a/libril/ril.cpp b/libril/ril.cpp
    -index d7744c0..561ba55 100644
    ---- a/libril/ril.cpp
    -+++ b/libril/ril.cpp
    -@@ -3804,6 +3804,7 @@ static void responseSimStatusV5(Parcel &p, void *response) {
    -     p.writeInt32(p_cur->universal_pin_state);
    -     p.writeInt32(p_cur->gsm_umts_subscription_app_index);
    -     p.writeInt32(p_cur->cdma_subscription_app_index);
    -+    p.writeInt32(-1);
    - 
    -     sendSimStatusAppInfo(p, p_cur->num_applications, p_cur->applications);
    - }
    +diff --git a/include/telephony/ril.h b/include/telephony/ril.h
    +index 98aa7d3..5fcd901 100644
    +--- a/include/telephony/ril.h
    ++++ b/include/telephony/ril.h
    +@@ -1712,18 +1712,29 @@ typedef struct {
    + /* Tx Power Levels */
    + #define RIL_NUM_TX_POWER_LEVELS     5
    + 
    ++/**
    ++ * Aggregate modem activity information
    ++ */
    + typedef struct {
    + 
    +-  /* period (in ms) when modem is power collapsed */
    ++  /* total time (in ms) when modem is in a low power or
    ++   * sleep state
    ++   */
    +   uint32_t sleep_mode_time_ms;
    + 
    +-  /* period (in ms) when modem is awake and in idle mode*/
    ++  /* total time (in ms) when modem is awake but neither
    ++   * the transmitter nor receiver are active/awake */
    +   uint32_t idle_mode_time_ms;
    + 
    +-  /* period (in ms) for which Tx is active */
    ++  /* total time (in ms) during which the transmitter is active/awake,
    ++   * subdivided by manufacturer-defined device-specific
    ++   * contiguous increasing ranges of transmit power between
    ++   * 0 and the transmitter's maximum transmit power.
    ++   */
    +   uint32_t tx_mode_time_ms[RIL_NUM_TX_POWER_LEVELS];
    + 
    +-  /* period (in ms) for which Rx is active */
    ++  /* total time (in ms) for which receiver is active/awake and
    ++   * the transmitter is inactive */
    +   uint32_t rx_mode_time_ms;
    + } RIL_ActivityStatsInfo;
    + 
    +@@ -5101,11 +5112,11 @@ typedef struct {
    + /**
    +  * RIL_REQUEST_GET_ACTIVITY_INFO
    +  *
    +- * Get modem activity statisitics info.
    ++ * Get modem activity information for power consumption estimation.
    +  *
    +- * There can be multiple RIL_REQUEST_GET_ACTIVITY_INFO calls to modem.
    +- * Once the response for the request is sent modem will clear
    +- * current statistics information.
    ++ * Request clear-on-read statistics information that is used for
    ++ * estimating the per-millisecond power consumption of the cellular
    ++ * modem.
    +  *
    +  * "data" is null
    +  * "response" is const RIL_ActivityStatsInfo *
    diff --git a/system_core.patch b/system_core.patch
    index 356e39a..335d3d2 100644
    --- a/system_core.patch
    +++ b/system_core.patch
    @@ -1,3 +1,580 @@
    +diff --git a/adb/adb.h b/adb/adb.h
    +index 971b8da..b1d9896 100644
    +--- a/adb/adb.h
    ++++ b/adb/adb.h
    +@@ -160,8 +160,10 @@ int get_available_local_transport_index();
    + int  init_socket_transport(atransport *t, int s, int port, int local);
    + void init_usb_transport(atransport *t, usb_handle *usb, ConnectionState state);
    + 
    ++std::string getEmulatorSerialString(int console_port);
    + #if ADB_HOST
    + atransport* find_emulator_transport_by_adb_port(int adb_port);
    ++atransport* find_emulator_transport_by_console_port(int console_port);
    + #endif
    + 
    + int service_to_fd(const char* name, const atransport* transport);
    +diff --git a/adb/bugreport.cpp b/adb/bugreport.cpp
    +index 9ed44a7..c348dd5 100644
    +--- a/adb/bugreport.cpp
    ++++ b/adb/bugreport.cpp
    +@@ -47,7 +47,7 @@ class BugreportStandardStreamsCallback : public StandardStreamsCallbackInterface
    +           show_progress_(show_progress),
    +           status_(0),
    +           line_() {
    +-        SetLineMessage();
    ++        SetLineMessage("generating");
    +     }
    + 
    +     void OnStdout(const char* buffer, int length) {
    +@@ -97,6 +97,7 @@ class BugreportStandardStreamsCallback : public StandardStreamsCallbackInterface
    +                                                           OS_PATH_SEPARATOR, dest_file_.c_str());
    +             }
    +             std::vector<const char*> srcs{src_file_.c_str()};
    ++            SetLineMessage("pulling");
    +             status_ =
    +                 br_->DoSyncPull(srcs, destination.c_str(), true, line_message_.c_str()) ? 0 : 1;
    +             if (status_ != 0) {
    +@@ -111,9 +112,8 @@ class BugreportStandardStreamsCallback : public StandardStreamsCallbackInterface
    +     }
    + 
    +   private:
    +-    void SetLineMessage() {
    +-        line_message_ =
    +-            android::base::StringPrintf("generating %s", adb_basename(dest_file_).c_str());
    ++    void SetLineMessage(const std::string& action) {
    ++        line_message_ = action + " " + adb_basename(dest_file_);
    +     }
    + 
    +     void SetSrcFile(const std::string path) {
    +@@ -121,7 +121,7 @@ class BugreportStandardStreamsCallback : public StandardStreamsCallbackInterface
    +         if (!dest_dir_.empty()) {
    +             // Only uses device-provided name when user passed a directory.
    +             dest_file_ = adb_basename(path);
    +-            SetLineMessage();
    ++            SetLineMessage("generating");
    +         }
    +     }
    + 
    +diff --git a/adb/bugreport_test.cpp b/adb/bugreport_test.cpp
    +index 3cd2b6d..1129285 100644
    +--- a/adb/bugreport_test.cpp
    ++++ b/adb/bugreport_test.cpp
    +@@ -189,7 +189,7 @@ TEST_F(BugreportTest, NoArgumentsNDevice) {
    +         .WillOnce(DoAll(WithArg<4>(WriteOnStdout("OK:/device/da_bugreport.zip")),
    +                         WithArg<4>(ReturnCallbackDone())));
    +     EXPECT_CALL(br_, DoSyncPull(ElementsAre(StrEq("/device/da_bugreport.zip")), StrEq(dest_file),
    +-                                true, StrEq("generating da_bugreport.zip")))
    ++                                true, StrEq("pulling da_bugreport.zip")))
    +         .WillOnce(Return(true));
    + 
    +     const char* args[] = {"bugreport"};
    +@@ -209,7 +209,7 @@ TEST_F(BugreportTest, NoArgumentsPostNDevice) {
    +                         WithArg<4>(WriteOnStdout("OK:/device/da_bugreport.zip\n")),
    +                         WithArg<4>(ReturnCallbackDone())));
    +     EXPECT_CALL(br_, DoSyncPull(ElementsAre(StrEq("/device/da_bugreport.zip")), StrEq(dest_file),
    +-                                true, StrEq("generating da_bugreport.zip")))
    ++                                true, StrEq("pulling da_bugreport.zip")))
    +         .WillOnce(Return(true));
    + 
    +     const char* args[] = {"bugreport"};
    +@@ -223,7 +223,7 @@ TEST_F(BugreportTest, OkNDevice) {
    +         .WillOnce(DoAll(WithArg<4>(WriteOnStdout("OK:/device/bugreport.zip")),
    +                         WithArg<4>(ReturnCallbackDone())));
    +     EXPECT_CALL(br_, DoSyncPull(ElementsAre(StrEq("/device/bugreport.zip")), StrEq("file.zip"),
    +-                                true, StrEq("generating file.zip")))
    ++                                true, StrEq("pulling file.zip")))
    +         .WillOnce(Return(true));
    + 
    +     const char* args[] = {"bugreport", "file.zip"};
    +@@ -239,7 +239,7 @@ TEST_F(BugreportTest, OkNDeviceSplitBuffer) {
    +                         WithArg<4>(WriteOnStdout("/bugreport.zip")),
    +                         WithArg<4>(ReturnCallbackDone())));
    +     EXPECT_CALL(br_, DoSyncPull(ElementsAre(StrEq("/device/bugreport.zip")), StrEq("file.zip"),
    +-                                true, StrEq("generating file.zip")))
    ++                                true, StrEq("pulling file.zip")))
    +         .WillOnce(Return(true));
    + 
    +     const char* args[] = {"bugreport", "file.zip"};
    +@@ -275,7 +275,7 @@ TEST_F(BugreportTest, OkProgress) {
    +             WithArg<4>(ReturnCallbackDone())));
    +     // clang-format on
    +     EXPECT_CALL(br_, DoSyncPull(ElementsAre(StrEq("/device/bugreport.zip")), StrEq("file.zip"),
    +-                                true, StrEq("generating file.zip")))
    ++                                true, StrEq("pulling file.zip")))
    +         .WillOnce(Return(true));
    + 
    +     const char* args[] = {"bugreport", "file.zip"};
    +@@ -294,7 +294,7 @@ TEST_F(BugreportTest, OkDirectory) {
    +                         WithArg<4>(WriteOnStdout("OK:/device/da_bugreport.zip")),
    +                         WithArg<4>(ReturnCallbackDone())));
    +     EXPECT_CALL(br_, DoSyncPull(ElementsAre(StrEq("/device/da_bugreport.zip")), StrEq(dest_file),
    +-                                true, StrEq("generating da_bugreport.zip")))
    ++                                true, StrEq("pulling da_bugreport.zip")))
    +         .WillOnce(Return(true));
    + 
    +     const char* args[] = {"bugreport", td.path};
    +@@ -308,7 +308,7 @@ TEST_F(BugreportTest, OkNoExtension) {
    +         .WillOnce(DoAll(WithArg<4>(WriteOnStdout("OK:/device/bugreport.zip\n")),
    +                         WithArg<4>(ReturnCallbackDone())));
    +     EXPECT_CALL(br_, DoSyncPull(ElementsAre(StrEq("/device/bugreport.zip")), StrEq("file.zip"),
    +-                                true, StrEq("generating file.zip")))
    ++                                true, StrEq("pulling file.zip")))
    +         .WillOnce(Return(true));
    + 
    +     const char* args[] = {"bugreport", "file"};
    +@@ -327,7 +327,7 @@ TEST_F(BugreportTest, OkNDeviceDirectory) {
    +                         WithArg<4>(WriteOnStdout("OK:/device/da_bugreport.zip")),
    +                         WithArg<4>(ReturnCallbackDone())));
    +     EXPECT_CALL(br_, DoSyncPull(ElementsAre(StrEq("/device/da_bugreport.zip")), StrEq(dest_file),
    +-                                true, StrEq("generating da_bugreport.zip")))
    ++                                true, StrEq("pulling da_bugreport.zip")))
    +         .WillOnce(Return(true));
    + 
    +     const char* args[] = {"bugreport", td.path};
    +diff --git a/adb/commandline.cpp b/adb/commandline.cpp
    +index 23827de..51d828a 100644
    +--- a/adb/commandline.cpp
    ++++ b/adb/commandline.cpp
    +@@ -1430,6 +1430,16 @@ static bool _is_valid_ack_reply_fd(const int ack_reply_fd) {
    + #endif
    + }
    + 
    ++static bool _use_legacy_install() {
    ++    FeatureSet features;
    ++    std::string error;
    ++    if (!adb_get_feature_set(&features, &error)) {
    ++        fprintf(stderr, "error: %s\n", error.c_str());
    ++        return true;
    ++    }
    ++    return !CanUseFeature(features, kFeatureCmd);
    ++}
    ++
    + int adb_commandline(int argc, const char **argv) {
    +     int no_daemon = 0;
    +     int is_daemon = 0;
    +@@ -1797,17 +1807,10 @@ int adb_commandline(int argc, const char **argv) {
    +     }
    +     else if (!strcmp(argv[0], "install")) {
    +         if (argc < 2) return usage();
    +-        FeatureSet features;
    +-        std::string error;
    +-        if (!adb_get_feature_set(&features, &error)) {
    +-            fprintf(stderr, "error: %s\n", error.c_str());
    +-            return 1;
    ++        if (_use_legacy_install()) {
    ++            return install_app_legacy(transport_type, serial, argc, argv);
    +         }
    +-
    +-        if (CanUseFeature(features, kFeatureCmd)) {
    +-            return install_app(transport_type, serial, argc, argv);
    +-        }
    +-        return install_app_legacy(transport_type, serial, argc, argv);
    ++        return install_app(transport_type, serial, argc, argv);
    +     }
    +     else if (!strcmp(argv[0], "install-multiple")) {
    +         if (argc < 2) return usage();
    +@@ -1815,17 +1818,10 @@ int adb_commandline(int argc, const char **argv) {
    +     }
    +     else if (!strcmp(argv[0], "uninstall")) {
    +         if (argc < 2) return usage();
    +-        FeatureSet features;
    +-        std::string error;
    +-        if (!adb_get_feature_set(&features, &error)) {
    +-            fprintf(stderr, "error: %s\n", error.c_str());
    +-            return 1;
    ++        if (_use_legacy_install()) {
    ++            return uninstall_app_legacy(transport_type, serial, argc, argv);
    +         }
    +-
    +-        if (CanUseFeature(features, kFeatureCmd)) {
    +-            return uninstall_app(transport_type, serial, argc, argv);
    +-        }
    +-        return uninstall_app_legacy(transport_type, serial, argc, argv);
    ++        return uninstall_app(transport_type, serial, argc, argv);
    +     }
    +     else if (!strcmp(argv[0], "sync")) {
    +         std::string src;
    +@@ -2031,7 +2027,6 @@ static int install_multiple_app(TransportType transport, const char* serial, int
    +     int i;
    +     struct stat sb;
    +     uint64_t total_size = 0;
    +-
    +     // Find all APK arguments starting at end.
    +     // All other arguments passed through verbatim.
    +     int first_apk = -1;
    +@@ -2056,7 +2051,14 @@ static int install_multiple_app(TransportType transport, const char* serial, int
    +         return 1;
    +     }
    + 
    +-    std::string cmd = android::base::StringPrintf("exec:pm install-create -S %" PRIu64, total_size);
    ++    std::string install_cmd;
    ++    if (_use_legacy_install()) {
    ++        install_cmd = "exec:pm";
    ++    } else {
    ++        install_cmd = "exec:cmd package";
    ++    }
    ++
    ++    std::string cmd = android::base::StringPrintf("%s install-create -S %" PRIu64, install_cmd.c_str(), total_size);
    +     for (i = 1; i < first_apk; i++) {
    +         cmd += " " + escape_arg(argv[i]);
    +     }
    +@@ -2098,8 +2100,8 @@ static int install_multiple_app(TransportType transport, const char* serial, int
    +         }
    + 
    +         std::string cmd = android::base::StringPrintf(
    +-                "exec:pm install-write -S %" PRIu64 " %d %d_%s -",
    +-                static_cast<uint64_t>(sb.st_size), session_id, i, adb_basename(file).c_str());
    ++                "%s install-write -S %" PRIu64 " %d %d_%s -",
    ++                install_cmd.c_str(), static_cast<uint64_t>(sb.st_size), session_id, i, adb_basename(file).c_str());
    + 
    +         int localFd = adb_open(file, O_RDONLY);
    +         if (localFd < 0) {
    +@@ -2134,8 +2136,8 @@ static int install_multiple_app(TransportType transport, const char* serial, int
    + finalize_session:
    +     // Commit session if we streamed everything okay; otherwise abandon
    +     std::string service =
    +-            android::base::StringPrintf("exec:pm install-%s %d",
    +-                                        success ? "commit" : "abandon", session_id);
    ++            android::base::StringPrintf("%s install-%s %d",
    ++                                        install_cmd.c_str(), success ? "commit" : "abandon", session_id);
    +     fd = adb_connect(service, &error);
    +     if (fd < 0) {
    +         fprintf(stderr, "Connect error for finalize: %s\n", error.c_str());
    +diff --git a/adb/transport_local.cpp b/adb/transport_local.cpp
    +index 4f3e1f5..1f5a258 100644
    +--- a/adb/transport_local.cpp
    ++++ b/adb/transport_local.cpp
    +@@ -99,7 +99,8 @@ int local_connect_arbitrary_ports(int console_port, int adb_port, std::string* e
    +     int fd = -1;
    + 
    + #if ADB_HOST
    +-    if (find_emulator_transport_by_adb_port(adb_port) != nullptr) {
    ++    if (find_emulator_transport_by_adb_port(adb_port) != nullptr ||
    ++        find_emulator_transport_by_console_port(console_port) != nullptr) {
    +         return -1;
    +     }
    + 
    +@@ -116,7 +117,7 @@ int local_connect_arbitrary_ports(int console_port, int adb_port, std::string* e
    +         D("client: connected on remote on fd %d", fd);
    +         close_on_exec(fd);
    +         disable_tcp_nagle(fd);
    +-        std::string serial = android::base::StringPrintf("emulator-%d", console_port);
    ++        std::string serial = getEmulatorSerialString(console_port);
    +         if (register_socket_transport(fd, serial.c_str(), adb_port, 1) == 0) {
    +             return 0;
    +         }
    +@@ -360,6 +361,11 @@ atransport* find_emulator_transport_by_adb_port_locked(int adb_port)
    +     return NULL;
    + }
    + 
    ++std::string getEmulatorSerialString(int console_port)
    ++{
    ++    return android::base::StringPrintf("emulator-%d", console_port);
    ++}
    ++
    + atransport* find_emulator_transport_by_adb_port(int adb_port)
    + {
    +     adb_mutex_lock( &local_transports_lock );
    +@@ -368,6 +374,12 @@ atransport* find_emulator_transport_by_adb_port(int adb_port)
    +     return result;
    + }
    + 
    ++atransport* find_emulator_transport_by_console_port(int console_port)
    ++{
    ++    return find_transport(getEmulatorSerialString(console_port).c_str());
    ++}
    ++
    ++
    + /* Only call this function if you already hold local_transports_lock. */
    + int get_available_local_transport_index_locked()
    + {
    +diff --git a/debuggerd/tombstone.cpp b/debuggerd/tombstone.cpp
    +index fa983fa..dfdf29c 100644
    +--- a/debuggerd/tombstone.cpp
    ++++ b/debuggerd/tombstone.cpp
    +@@ -368,6 +368,7 @@ static void dump_all_maps(Backtrace* backtrace, BacktraceMap* map, log_t* log, p
    +     ALOGE("Cannot get siginfo for %d: %s\n", tid, strerror(errno));
    +   }
    + 
    ++  ScopedBacktraceMapIteratorLock lock(map);
    +   _LOG(log, logtype::MAPS, "\n");
    +   if (!print_fault_address_marker) {
    +     _LOG(log, logtype::MAPS, "memory map:\n");
    +diff --git a/fastboot/fastboot.cpp b/fastboot/fastboot.cpp
    +index c1c3174..2b6cad1 100644
    +--- a/fastboot/fastboot.cpp
    ++++ b/fastboot/fastboot.cpp
    +@@ -116,16 +116,18 @@ static struct {
    + };
    + 
    + static std::string find_item_given_name(const char* img_name, const char* product) {
    +-    char *dir;
    +-    char path[PATH_MAX + 128];
    ++    char path_c_str[PATH_MAX + 128];
    + 
    +     if(product) {
    +-        get_my_path(path);
    +-        return android::base::StringPrintf("../../../target/product/%s/%s", product, img_name);
    ++        get_my_path(path_c_str);
    ++        std::string path = path_c_str;
    ++        path.erase(path.find_last_of('/'));
    ++        return android::base::StringPrintf("%s/../../../target/product/%s/%s",
    ++                                           path.c_str(), product, img_name);
    +     }
    + 
    +-    dir = getenv("ANDROID_PRODUCT_OUT");
    +-    if((dir == 0) || (dir[0] == 0)) {
    ++    char *dir = getenv("ANDROID_PRODUCT_OUT");
    ++    if (dir == nullptr || dir[0] == '\0') {
    +         die("neither -p product specified nor ANDROID_PRODUCT_OUT set");
    +     }
    + 
    +diff --git a/fs_mgr/fs_mgr.c b/fs_mgr/fs_mgr.c
    +index 6de8817..387f708 100644
    +--- a/fs_mgr/fs_mgr.c
    ++++ b/fs_mgr/fs_mgr.c
    +@@ -489,7 +489,7 @@ static int handle_encryptable(const struct fstab_rec* rec)
    +  * first successful mount.
    +  * Returns -1 on error, and  FS_MGR_MNTALL_* otherwise.
    +  */
    +-int fs_mgr_mount_all(struct fstab *fstab)
    ++int fs_mgr_mount_all(struct fstab *fstab, int mount_mode)
    + {
    +     int i = 0;
    +     int encryptable = FS_MGR_MNTALL_DEV_NOT_ENCRYPTABLE;
    +@@ -503,8 +503,10 @@ int fs_mgr_mount_all(struct fstab *fstab)
    +     }
    + 
    +     for (i = 0; i < fstab->num_entries; i++) {
    +-        /* Don't mount entries that are managed by vold */
    +-        if (fstab->recs[i].fs_mgr_flags & (MF_VOLDMANAGED | MF_RECOVERYONLY)) {
    ++        /* Don't mount entries that are managed by vold or not for the mount mode*/
    ++        if ((fstab->recs[i].fs_mgr_flags & (MF_VOLDMANAGED | MF_RECOVERYONLY)) ||
    ++             ((mount_mode == MOUNT_MODE_LATE) && !fs_mgr_is_latemount(&fstab->recs[i])) ||
    ++             ((mount_mode == MOUNT_MODE_EARLY) && fs_mgr_is_latemount(&fstab->recs[i]))) {
    +             continue;
    +         }
    + 
    +diff --git a/fs_mgr/fs_mgr_fstab.c b/fs_mgr/fs_mgr_fstab.c
    +index 45adb34..21b4c74 100644
    +--- a/fs_mgr/fs_mgr_fstab.c
    ++++ b/fs_mgr/fs_mgr_fstab.c
    +@@ -78,6 +78,7 @@ static struct flag_list fs_mgr_flags[] = {
    +     { "formattable", MF_FORMATTABLE },
    +     { "slotselect",  MF_SLOTSELECT },
    +     { "nofail",      MF_NOFAIL },
    ++    { "latemount",   MF_LATEMOUNT },
    +     { "defaults",    0 },
    +     { 0,             0 },
    + };
    +@@ -545,3 +546,8 @@ int fs_mgr_is_nofail(struct fstab_rec *fstab)
    + {
    +     return fstab->fs_mgr_flags & MF_NOFAIL;
    + }
    ++
    ++int fs_mgr_is_latemount(struct fstab_rec *fstab)
    ++{
    ++    return fstab->fs_mgr_flags & MF_LATEMOUNT;
    ++}
    +diff --git a/fs_mgr/fs_mgr_main.c b/fs_mgr/fs_mgr_main.c
    +index e5a00d5..776c13e 100644
    +--- a/fs_mgr/fs_mgr_main.c
    ++++ b/fs_mgr/fs_mgr_main.c
    +@@ -96,7 +96,7 @@ int main(int argc, char *argv[])
    +     fstab = fs_mgr_read_fstab(fstab_file);
    + 
    +     if (a_flag) {
    +-        return fs_mgr_mount_all(fstab);
    ++        return fs_mgr_mount_all(fstab, MOUNT_MODE_DEFAULT);
    +     } else if (n_flag) {
    +         return fs_mgr_do_mount(fstab, n_name, n_blk_dev, 0);
    +     } else if (u_flag) {
    +diff --git a/fs_mgr/fs_mgr_priv.h b/fs_mgr/fs_mgr_priv.h
    +index 46975f1..6d9492b 100644
    +--- a/fs_mgr/fs_mgr_priv.h
    ++++ b/fs_mgr/fs_mgr_priv.h
    +@@ -48,7 +48,7 @@ __BEGIN_DECLS
    +  *
    +  *   <fs_mgr_options> is a comma separated list of flags that control the operation of
    +  *                     the fs_mgr program.  The list includes "wait", which will wait till
    +- *                     the <source> file exists, and "check", which requests that the fs_mgr 
    ++ *                     the <source> file exists, and "check", which requests that the fs_mgr
    +  *                     run an fscheck program on the <source> before mounting the filesystem.
    +  *                     If check is specifed on a read-only filesystem, it is ignored.
    +  *                     Also, "encryptable" means that filesystem can be encrypted.
    +@@ -83,6 +83,7 @@ __BEGIN_DECLS
    + #define MF_FORMATTABLE  0x4000
    + #define MF_SLOTSELECT   0x8000
    + #define MF_FORCEFDEORFBE 0x10000
    ++#define MF_LATEMOUNT    0x20000
    + #define MF_NOFAIL       0x40000
    + 
    + #define DM_BUF_SIZE 4096
    +diff --git a/fs_mgr/include/fs_mgr.h b/fs_mgr/include/fs_mgr.h
    +index 46d8f97..7565965 100644
    +--- a/fs_mgr/include/fs_mgr.h
    ++++ b/fs_mgr/include/fs_mgr.h
    +@@ -40,6 +40,13 @@ enum verity_mode {
    +     VERITY_MODE_DEFAULT = VERITY_MODE_RESTART
    + };
    + 
    ++// Mount modes
    ++enum mount_mode {
    ++    MOUNT_MODE_DEFAULT = 0,
    ++    MOUNT_MODE_EARLY = 1,
    ++    MOUNT_MODE_LATE = 2
    ++};
    ++
    + /*
    +  * The entries must be kept in the same order as they were seen in the fstab.
    +  * Unless explicitly requested, a lookup on mount point should always
    +@@ -82,7 +89,7 @@ void fs_mgr_free_fstab(struct fstab *fstab);
    + #define FS_MGR_MNTALL_DEV_NOT_ENCRYPTED 1
    + #define FS_MGR_MNTALL_DEV_NOT_ENCRYPTABLE 0
    + #define FS_MGR_MNTALL_FAIL -1
    +-int fs_mgr_mount_all(struct fstab *fstab);
    ++int fs_mgr_mount_all(struct fstab *fstab, int mount_mode);
    + 
    + #define FS_MGR_DOMNT_FAILED -1
    + #define FS_MGR_DOMNT_BUSY -2
    +@@ -110,6 +117,7 @@ int fs_mgr_is_noemulatedsd(const struct fstab_rec *fstab);
    + int fs_mgr_is_notrim(struct fstab_rec *fstab);
    + int fs_mgr_is_formattable(struct fstab_rec *fstab);
    + int fs_mgr_is_nofail(struct fstab_rec *fstab);
    ++int fs_mgr_is_latemount(struct fstab_rec *fstab);
    + int fs_mgr_swapon_all(struct fstab *fstab);
    + 
    + int fs_mgr_do_format(struct fstab_rec *fstab);
    +diff --git a/healthd/healthd.cpp b/healthd/healthd.cpp
    +index d9ac356..2caae78 100644
    +--- a/healthd/healthd.cpp
    ++++ b/healthd/healthd.cpp
    +@@ -136,10 +136,14 @@ static void healthd_mode_nop_battery_update(
    +     struct android::BatteryProperties* /*props*/) {
    + }
    + 
    +-int healthd_register_event(int fd, void (*handler)(uint32_t)) {
    ++int healthd_register_event(int fd, void (*handler)(uint32_t), EventWakeup wakeup) {
    +     struct epoll_event ev;
    + 
    +-    ev.events = EPOLLIN | EPOLLWAKEUP;
    ++    ev.events = EPOLLIN;
    ++
    ++    if (wakeup == EVENT_WAKEUP_FD)
    ++        ev.events |= EPOLLWAKEUP;
    ++
    +     ev.data.ptr = (void *)handler;
    +     if (epoll_ctl(epollfd, EPOLL_CTL_ADD, fd, &ev) == -1) {
    +         KLOG_ERROR(LOG_TAG,
    +@@ -245,7 +249,7 @@ static void uevent_init(void) {
    +     }
    + 
    +     fcntl(uevent_fd, F_SETFL, O_NONBLOCK);
    +-    if (healthd_register_event(uevent_fd, uevent_event))
    ++    if (healthd_register_event(uevent_fd, uevent_event, EVENT_WAKEUP_FD))
    +         KLOG_ERROR(LOG_TAG,
    +                    "register for uevent events failed\n");
    + }
    +@@ -268,7 +272,7 @@ static void wakealarm_init(void) {
    +         return;
    +     }
    + 
    +-    if (healthd_register_event(wakealarm_fd, wakealarm_event))
    ++    if (healthd_register_event(wakealarm_fd, wakealarm_event, EVENT_WAKEUP_FD))
    +         KLOG_ERROR(LOG_TAG,
    +                    "Registration of wakealarm event failed\n");
    + 
    +@@ -286,7 +290,6 @@ static void healthd_mainloop(void) {
    +         if (timeout < 0 || (mode_timeout > 0 && mode_timeout < timeout))
    +             timeout = mode_timeout;
    +         nevents = epoll_wait(epollfd, events, eventct, timeout);
    +-
    +         if (nevents == -1) {
    +             if (errno == EINTR)
    +                 continue;
    +diff --git a/healthd/healthd_mode_charger.cpp b/healthd/healthd_mode_charger.cpp
    +index 5846626..a6da704 100644
    +--- a/healthd/healthd_mode_charger.cpp
    ++++ b/healthd/healthd_mode_charger.cpp
    +@@ -686,7 +686,7 @@ void healthd_mode_charger_init(struct healthd_config* config)
    +     ret = ev_init(input_callback, charger);
    +     if (!ret) {
    +         epollfd = ev_get_epollfd();
    +-        healthd_register_event(epollfd, charger_event_handler);
    ++        healthd_register_event(epollfd, charger_event_handler, EVENT_WAKEUP_FD);
    +     }
    + 
    +     ret = res_create_display_surface("charger/battery_fail", &charger->surf_unknown);
    +diff --git a/healthd/include/healthd/healthd.h b/healthd/include/healthd/healthd.h
    +index 34ea55f..17efbd6 100644
    +--- a/healthd/include/healthd/healthd.h
    ++++ b/healthd/include/healthd/healthd.h
    +@@ -73,9 +73,14 @@ struct healthd_config {
    +     bool (*screen_on)(android::BatteryProperties *props);
    + };
    + 
    ++enum EventWakeup {
    ++    EVENT_NO_WAKEUP_FD,
    ++    EVENT_WAKEUP_FD,
    ++};
    ++
    + // Global helper functions
    + 
    +-int healthd_register_event(int fd, void (*handler)(uint32_t));
    ++int healthd_register_event(int fd, void (*handler)(uint32_t), EventWakeup wakeup = EVENT_NO_WAKEUP_FD);
    + void healthd_battery_update();
    + android::status_t healthd_get_property(int id,
    +     struct android::BatteryProperty *val);
    +diff --git a/include/backtrace/BacktraceMap.h b/include/backtrace/BacktraceMap.h
    +index 2373c45..b80045f 100644
    +--- a/include/backtrace/BacktraceMap.h
    ++++ b/include/backtrace/BacktraceMap.h
    +@@ -71,6 +71,12 @@ public:
    +   bool IsWritable(uintptr_t pc) { return GetFlags(pc) & PROT_WRITE; }
    +   bool IsExecutable(uintptr_t pc) { return GetFlags(pc) & PROT_EXEC; }
    + 
    ++  // In order to use the iterators on this object, a caller must
    ++  // call the LockIterator and UnlockIterator function to guarantee
    ++  // that the data does not change while it's being used.
    ++  virtual void LockIterator() {}
    ++  virtual void UnlockIterator() {}
    ++
    +   typedef std::deque<backtrace_map_t>::iterator iterator;
    +   iterator begin() { return maps_.begin(); }
    +   iterator end() { return maps_.end(); }
    +@@ -102,4 +108,18 @@ protected:
    +   pid_t pid_;
    + };
    + 
    ++class ScopedBacktraceMapIteratorLock {
    ++public:
    ++  explicit ScopedBacktraceMapIteratorLock(BacktraceMap* map) : map_(map) {
    ++    map->LockIterator();
    ++  }
    ++
    ++  ~ScopedBacktraceMapIteratorLock() {
    ++    map_->UnlockIterator();
    ++  }
    ++
    ++private:
    ++  BacktraceMap* map_;
    ++};
    ++
    + #endif // _BACKTRACE_BACKTRACE_MAP_H
    +diff --git a/include/cutils/trace.h b/include/cutils/trace.h
    +index c9790ad..19313af 100644
    +--- a/include/cutils/trace.h
    ++++ b/include/cutils/trace.h
    +@@ -70,7 +70,8 @@ __BEGIN_DECLS
    + #define ATRACE_TAG_PACKAGE_MANAGER  (1<<18)
    + #define ATRACE_TAG_SYSTEM_SERVER    (1<<19)
    + #define ATRACE_TAG_DATABASE         (1<<20)
    +-#define ATRACE_TAG_LAST             ATRACE_TAG_DATABASE
    ++#define ATRACE_TAG_NETWORK          (1<<21)
    ++#define ATRACE_TAG_LAST             ATRACE_TAG_NETWORK
    + 
    + // Reserved for initialization.
    + #define ATRACE_TAG_NOT_READY        (1ULL<<63)
     diff --git a/include/system/camera.h b/include/system/camera.h
     index 5d0873a..e4c0a47 100644
     --- a/include/system/camera.h
    @@ -112,6 +689,167 @@ index 67541b8..ff343e9 100644
      
      init_cflags += \
          $(init_options) \
    +diff --git a/init/builtins.cpp b/init/builtins.cpp
    +index 70f9194..44217f0 100644
    +--- a/init/builtins.cpp
    ++++ b/init/builtins.cpp
    +@@ -479,9 +479,9 @@ exit_success:
    +  *
    +  * start_index: index of the first path in the args list
    +  */
    +-static void import_late(const std::vector<std::string>& args, size_t start_index) {
    ++static void import_late(const std::vector<std::string>& args, size_t start_index, size_t end_index) {
    +     Parser& parser = Parser::GetInstance();
    +-    if (args.size() <= start_index) {
    ++    if (end_index <= start_index) {
    +         // Use the default set if no path is given
    +         static const std::vector<std::string> init_directories = {
    +             "/system/etc/init",
    +@@ -493,25 +493,23 @@ static void import_late(const std::vector<std::string>& args, size_t start_index
    +             parser.ParseConfig(dir);
    +         }
    +     } else {
    +-        for (size_t i = start_index; i < args.size(); ++i) {
    ++        for (size_t i = start_index; i < end_index; ++i) {
    +             parser.ParseConfig(args[i]);
    +         }
    +     }
    + }
    + 
    +-/* mount_all <fstab> [ <path> ]*
    ++/* mount_fstab
    +  *
    +- * This function might request a reboot, in which case it will
    +- * not return.
    ++ *  Call fs_mgr_mount_all() to mount the given fstab
    +  */
    +-static int do_mount_all(const std::vector<std::string>& args) {
    ++static int mount_fstab(const char* fstabfile, int mount_mode) {
    +     pid_t pid;
    +     int ret = -1;
    +     int child_ret = -1;
    +     int status;
    +     struct fstab *fstab;
    + 
    +-    const char* fstabfile = args[1].c_str();
    +     /*
    +      * Call fs_mgr_mount_all() to mount all filesystems.  We fork(2) and
    +      * do the call in the child to provide protection to the main init
    +@@ -536,7 +534,7 @@ static int do_mount_all(const std::vector<std::string>& args) {
    +         /* child, call fs_mgr_mount_all() */
    +         klog_set_level(6);  /* So we can see what fs_mgr_mount_all() does */
    +         fstab = fs_mgr_read_fstab(fstabfile);
    +-        child_ret = fs_mgr_mount_all(fstab);
    ++        child_ret = fs_mgr_mount_all(fstab, mount_mode);
    +         fs_mgr_free_fstab(fstab);
    +         if (child_ret == -1) {
    +             ERROR("fs_mgr_mount_all returned an error\n");
    +@@ -546,28 +544,38 @@ static int do_mount_all(const std::vector<std::string>& args) {
    +         /* fork failed, return an error */
    +         return -1;
    +     }
    ++    return ret;
    ++}
    + 
    +-    /* Paths of .rc files are specified at the 2nd argument and beyond */
    +-    import_late(args, 2);
    +-
    +-    if (ret == FS_MGR_MNTALL_DEV_NEEDS_ENCRYPTION) {
    ++/* Queue event based on fs_mgr return code.
    ++ *
    ++ * code: return code of fs_mgr_mount_all
    ++ *
    ++ * This function might request a reboot, in which case it will
    ++ * not return.
    ++ *
    ++ * return code is processed based on input code
    ++ */
    ++static int queue_fs_event(int code) {
    ++    int ret = code;
    ++    if (code == FS_MGR_MNTALL_DEV_NEEDS_ENCRYPTION) {
    +         ActionManager::GetInstance().QueueEventTrigger("encrypt");
    +-    } else if (ret == FS_MGR_MNTALL_DEV_MIGHT_BE_ENCRYPTED) {
    ++    } else if (code == FS_MGR_MNTALL_DEV_MIGHT_BE_ENCRYPTED) {
    +         property_set("ro.crypto.state", "encrypted");
    +         property_set("ro.crypto.type", "block");
    +         ActionManager::GetInstance().QueueEventTrigger("defaultcrypto");
    +-    } else if (ret == FS_MGR_MNTALL_DEV_NOT_ENCRYPTED) {
    ++    } else if (code == FS_MGR_MNTALL_DEV_NOT_ENCRYPTED) {
    +         property_set("ro.crypto.state", "unencrypted");
    +         ActionManager::GetInstance().QueueEventTrigger("nonencrypted");
    +-    } else if (ret == FS_MGR_MNTALL_DEV_NOT_ENCRYPTABLE) {
    ++    } else if (code == FS_MGR_MNTALL_DEV_NOT_ENCRYPTABLE) {
    +         property_set("ro.crypto.state", "unsupported");
    +         ActionManager::GetInstance().QueueEventTrigger("nonencrypted");
    +-    } else if (ret == FS_MGR_MNTALL_DEV_NEEDS_RECOVERY) {
    ++    } else if (code == FS_MGR_MNTALL_DEV_NEEDS_RECOVERY) {
    +         /* Setup a wipe via recovery, and reboot into recovery */
    +         ERROR("fs_mgr_mount_all suggested recovery, so wiping data via recovery.\n");
    +         ret = wipe_data_via_recovery("wipe_data_via_recovery");
    +         /* If reboot worked, there is no return. */
    +-    } else if (ret == FS_MGR_MNTALL_DEV_FILE_ENCRYPTED) {
    ++    } else if (code == FS_MGR_MNTALL_DEV_FILE_ENCRYPTED) {
    +         if (e4crypt_install_keyring()) {
    +             return -1;
    +         }
    +@@ -577,14 +585,55 @@ static int do_mount_all(const std::vector<std::string>& args) {
    +         // Although encrypted, we have device key, so we do not need to
    +         // do anything different from the nonencrypted case.
    +         ActionManager::GetInstance().QueueEventTrigger("nonencrypted");
    +-    } else if (ret > 0) {
    +-        ERROR("fs_mgr_mount_all returned unexpected error %d\n", ret);
    ++    } else if (code > 0) {
    ++        ERROR("fs_mgr_mount_all returned unexpected error %d\n", code);
    +     }
    +     /* else ... < 0: error */
    + 
    +     return ret;
    + }
    + 
    ++/* mount_all <fstab> [ <path> ]* [--<options>]*
    ++ *
    ++ * This function might request a reboot, in which case it will
    ++ * not return.
    ++ */
    ++static int do_mount_all(const std::vector<std::string>& args) {
    ++    std::size_t na = 0;
    ++    bool import_rc = true;
    ++    bool queue_event = true;
    ++    int mount_mode = MOUNT_MODE_DEFAULT;
    ++    const char* fstabfile = args[1].c_str();
    ++    std::size_t path_arg_end = args.size();
    ++
    ++    for (na = args.size() - 1; na > 1; --na) {
    ++        if (args[na] == "--early") {
    ++             path_arg_end = na;
    ++             queue_event = false;
    ++             mount_mode = MOUNT_MODE_EARLY;
    ++        } else if (args[na] == "--late") {
    ++            path_arg_end = na;
    ++            import_rc = false;
    ++            mount_mode = MOUNT_MODE_LATE;
    ++        }
    ++    }
    ++
    ++    int ret =  mount_fstab(fstabfile, mount_mode);
    ++
    ++    if (import_rc) {
    ++        /* Paths of .rc files are specified at the 2nd argument and beyond */
    ++        import_late(args, 2, path_arg_end);
    ++    }
    ++
    ++    if (queue_event) {
    ++        /* queue_fs_event will queue event based on mount_fstab return code
    ++         * and return processed return code*/
    ++        ret = queue_fs_event(ret);
    ++    }
    ++
    ++    return ret;
    ++}
    ++
    + static int do_swapon_all(const std::vector<std::string>& args) {
    +     struct fstab *fstab;
    +     int ret;
     diff --git a/init/init.cpp b/init/init.cpp
     index 84da2b9..dc3be38 100644
     --- a/init/init.cpp
    @@ -181,11 +919,433 @@ index 84da2b9..dc3be38 100644
          am.QueueBuiltinAction(keychord_init_action, "keychord_init");
          am.QueueBuiltinAction(console_init_action, "console_init");
      
    +diff --git a/init/init_parser.cpp b/init/init_parser.cpp
    +index b44ca59..f2e5d6d 100644
    +--- a/init/init_parser.cpp
    ++++ b/init/init_parser.cpp
    +@@ -122,14 +122,20 @@ bool Parser::ParseConfigDir(const std::string& path) {
    +         return false;
    +     }
    +     dirent* current_file;
    ++    std::vector<std::string> files;
    +     while ((current_file = readdir(config_dir.get()))) {
    +-        std::string current_path =
    +-            android::base::StringPrintf("%s/%s", path.c_str(), current_file->d_name);
    +         // Ignore directories and only process regular files.
    +         if (current_file->d_type == DT_REG) {
    +-            if (!ParseConfigFile(current_path)) {
    +-                ERROR("could not import file '%s'\n", current_path.c_str());
    +-            }
    ++            std::string current_path =
    ++                android::base::StringPrintf("%s/%s", path.c_str(), current_file->d_name);
    ++            files.emplace_back(current_path);
    ++        }
    ++    }
    ++    // Sort first so we load files in a consistent order (bug 31996208)
    ++    std::sort(files.begin(), files.end());
    ++    for (const auto& file : files) {
    ++        if (!ParseConfigFile(file)) {
    ++            ERROR("Could not import file '%s'\n", file.c_str());
    +         }
    +     }
    +     return true;
    +diff --git a/init/readme.txt b/init/readme.txt
    +index 4481e24..dad7e06 100644
    +--- a/init/readme.txt
    ++++ b/init/readme.txt
    +@@ -1,4 +1,3 @@
    +-
    + Android Init Language
    + ---------------------
    + 
    +@@ -78,6 +77,14 @@ monolithic init .rc files.  This additionally will aid in merge
    + conflict resolution when multiple services are added to the system, as
    + each one will go into a separate file.
    + 
    ++There are two options "early" and "late" in mount_all command
    ++which can be set after optional paths. With "--early" set, the
    ++init executable will skip mounting entries with "latemount" flag
    ++and triggering fs encryption state event. With "--late" set,
    ++init executable will only mount entries with "latemount" flag but skip
    ++importing rc files. By default, no option is set, and mount_all will
    ++mount_all will process all entries in the given fstab.
    ++
    + Actions
    + -------
    + Actions are named sequences of commands.  Actions have a trigger which
    +@@ -291,10 +298,11 @@ mkdir <path> [mode] [owner] [group]
    +    owned by the root user and root group. If provided, the mode, owner and group
    +    will be updated if the directory exists already.
    + 
    +-mount_all <fstab> [ <path> ]*
    ++mount_all <fstab> [ <path> ]* [--<option>]
    +    Calls fs_mgr_mount_all on the given fs_mgr-format fstab and imports .rc files
    +-   at the specified paths (e.g., on the partitions just mounted). Refer to the
    +-   section of "Init .rc Files" for detail.
    ++   at the specified paths (e.g., on the partitions just mounted) with optional
    ++   options "early" and "late".
    ++   Refer to the section of "Init .rc Files" for detail.
    + 
    + mount <type> <device> <dir> [ <flag> ]* [<options>]
    +    Attempt to mount the named device at the directory <dir>
    +diff --git a/libbacktrace/BacktraceMap.cpp b/libbacktrace/BacktraceMap.cpp
    +index ba86632..85f2436 100644
    +--- a/libbacktrace/BacktraceMap.cpp
    ++++ b/libbacktrace/BacktraceMap.cpp
    +@@ -35,8 +35,8 @@ BacktraceMap::~BacktraceMap() {
    + }
    + 
    + void BacktraceMap::FillIn(uintptr_t addr, backtrace_map_t* map) {
    +-  for (BacktraceMap::const_iterator it = begin();
    +-       it != end(); ++it) {
    ++  ScopedBacktraceMapIteratorLock lock(this);
    ++  for (BacktraceMap::const_iterator it = begin(); it != end(); ++it) {
    +     if (addr >= it->start && addr < it->end) {
    +       *map = *it;
    +       return;
    +diff --git a/libbacktrace/UnwindMap.cpp b/libbacktrace/UnwindMap.cpp
    +index 34d79f9..af79562 100644
    +--- a/libbacktrace/UnwindMap.cpp
    ++++ b/libbacktrace/UnwindMap.cpp
    +@@ -14,6 +14,7 @@
    +  * limitations under the License.
    +  */
    + 
    ++#include <pthread.h>
    + #include <stdint.h>
    + #include <stdlib.h>
    + #include <sys/types.h>
    +@@ -72,6 +73,7 @@ bool UnwindMapRemote::Build() {
    + }
    + 
    + UnwindMapLocal::UnwindMapLocal() : UnwindMap(getpid()), map_created_(false) {
    ++  pthread_rwlock_init(&map_lock_, nullptr);
    + }
    + 
    + UnwindMapLocal::~UnwindMapLocal() {
    +@@ -82,9 +84,14 @@ UnwindMapLocal::~UnwindMapLocal() {
    + }
    + 
    + bool UnwindMapLocal::GenerateMap() {
    ++  // Lock so that multiple threads cannot modify the maps data at the
    ++  // same time.
    ++  pthread_rwlock_wrlock(&map_lock_);
    ++
    +   // It's possible for the map to be regenerated while this loop is occurring.
    +   // If that happens, get the map again, but only try at most three times
    +   // before giving up.
    ++  bool generated = false;
    +   for (int i = 0; i < 3; i++) {
    +     maps_.clear();
    + 
    +@@ -110,12 +117,17 @@ bool UnwindMapLocal::GenerateMap() {
    +     }
    +     // Check to see if the map changed while getting the data.
    +     if (ret != -UNW_EINVAL) {
    +-      return true;
    ++      generated = true;
    ++      break;
    +     }
    +   }
    + 
    +-  BACK_LOGW("Unable to generate the map.");
    +-  return false;
    ++  pthread_rwlock_unlock(&map_lock_);
    ++
    ++  if (!generated) {
    ++    BACK_LOGW("Unable to generate the map.");
    ++  }
    ++  return generated;
    + }
    + 
    + bool UnwindMapLocal::Build() {
    +diff --git a/libbacktrace/UnwindMap.h b/libbacktrace/UnwindMap.h
    +index 111401f..f85b54a 100644
    +--- a/libbacktrace/UnwindMap.h
    ++++ b/libbacktrace/UnwindMap.h
    +@@ -17,6 +17,7 @@
    + #ifndef _LIBBACKTRACE_UNWIND_MAP_H
    + #define _LIBBACKTRACE_UNWIND_MAP_H
    + 
    ++#include <pthread.h>
    + #include <stdint.h>
    + #include <sys/types.h>
    + 
    +@@ -56,10 +57,15 @@ public:
    + 
    +   void FillIn(uintptr_t addr, backtrace_map_t* map) override;
    + 
    ++  void LockIterator() override { pthread_rwlock_rdlock(&map_lock_); }
    ++  void UnlockIterator() override { pthread_rwlock_unlock(&map_lock_); }
    ++
    + private:
    +   bool GenerateMap();
    + 
    +   bool map_created_;
    ++
    ++  pthread_rwlock_t map_lock_;
    + };
    + 
    + #endif // _LIBBACKTRACE_UNWIND_MAP_H
    +diff --git a/libbacktrace/backtrace_test.cpp b/libbacktrace/backtrace_test.cpp
    +index f6b2591..913e12d 100644
    +--- a/libbacktrace/backtrace_test.cpp
    ++++ b/libbacktrace/backtrace_test.cpp
    +@@ -896,6 +896,7 @@ void VerifyMap(pid_t pid) {
    +   std::unique_ptr<BacktraceMap> map(BacktraceMap::Create(pid));
    + 
    +   // Basic test that verifies that the map is in the expected order.
    ++  ScopedBacktraceMapIteratorLock lock(map.get());
    +   std::vector<map_test_t>::const_iterator test_it = test_maps.begin();
    +   for (BacktraceMap::const_iterator it = map->begin(); it != map->end(); ++it) {
    +     ASSERT_TRUE(test_it != test_maps.end());
    +diff --git a/liblog/event_tag_map.c b/liblog/event_tag_map.c
    +index 3cb04cf..345f0d3 100644
    +--- a/liblog/event_tag_map.c
    ++++ b/liblog/event_tag_map.c
    +@@ -99,6 +99,9 @@ LIBLOG_ABI_PUBLIC EventTagMap* android_openEventTagMap(const char* fileName)
    +     if (processFile(newTagMap) != 0)
    +         goto fail;
    + 
    ++    if (fd >= 0)
    ++      close(fd);
    ++
    +     return newTagMap;
    + 
    + fail:
    +diff --git a/liblog/pmsg_writer.c b/liblog/pmsg_writer.c
    +index b338dca..944feba 100644
    +--- a/liblog/pmsg_writer.c
    ++++ b/liblog/pmsg_writer.c
    +@@ -31,8 +31,6 @@
    + #include <private/android_filesystem_config.h>
    + #include <private/android_logger.h>
    + 
    +-#include <sys/system_properties.h>
    +-
    + #include "config_write.h"
    + #include "log_portability.h"
    + #include "logger.h"
    +@@ -53,25 +51,8 @@ LIBLOG_HIDDEN struct android_log_transport_write pmsgLoggerWrite = {
    +     .write = pmsgWrite,
    + };
    + 
    +-static bool pmsgShouldUse = false;
    +-
    +-// Only use pmsg on eng builds
    +-static bool pmsgIsEng() {
    +-    char buf[PROP_VALUE_MAX];
    +-
    +-    if (__system_property_get("ro.build.type", buf) == 0) {
    +-        return false;
    +-    }
    +-
    +-    if (!strncmp(buf, "eng", sizeof("eng"))) {
    +-        return true;
    +-    }
    +-    return false;
    +-}
    +-
    + static int pmsgOpen()
    + {
    +-    pmsgShouldUse = pmsgIsEng();
    +     if (pmsgLoggerWrite.context.fd < 0) {
    +         pmsgLoggerWrite.context.fd = TEMP_FAILURE_RETRY(open("/dev/pmsg0", O_WRONLY | O_CLOEXEC));
    +     }
    +@@ -94,7 +75,7 @@ static int pmsgAvailable(log_id_t logId)
    +     }
    +     if ((logId != LOG_ID_SECURITY) &&
    +             (logId != LOG_ID_EVENTS) &&
    +-            (!pmsgShouldUse || !__android_log_is_debuggable())) {
    ++            !__android_log_is_debuggable()) {
    +         return -EINVAL;
    +     }
    +     if (pmsgLoggerWrite.context.fd < 0) {
    +@@ -124,7 +105,7 @@ static int pmsgWrite(log_id_t logId, struct timespec *ts,
    +     size_t i, payloadSize;
    +     ssize_t ret;
    + 
    +-    if ((logId == LOG_ID_EVENTS) && (!pmsgShouldUse || !__android_log_is_debuggable())) {
    ++    if ((logId == LOG_ID_EVENTS) && !__android_log_is_debuggable()) {
    +         if (vec[0].iov_len < 4) {
    +             return -EINVAL;
    +         }
    +diff --git a/libutils/RefBase.cpp b/libutils/RefBase.cpp
    +index f90e28b..4ead19c 100644
    +--- a/libutils/RefBase.cpp
    ++++ b/libutils/RefBase.cpp
    +@@ -575,15 +575,14 @@ bool RefBase::weakref_type::attemptIncStrong(const void* id)
    +             // grab a strong-reference, which is always safe due to the
    +             // extended life-time.
    +             curCount = impl->mStrong.fetch_add(1, std::memory_order_relaxed);
    +-        }
    +-
    +-        // If the strong reference count has already been incremented by
    +-        // someone else, the implementor of onIncStrongAttempted() is holding
    +-        // an unneeded reference.  So call onLastStrongRef() here to remove it.
    +-        // (No, this is not pretty.)  Note that we MUST NOT do this if we
    +-        // are in fact acquiring the first reference.
    +-        if (curCount > 0 && curCount < INITIAL_STRONG_VALUE) {
    +-            impl->mBase->onLastStrongRef(id);
    ++            // If the strong reference count has already been incremented by
    ++            // someone else, the implementor of onIncStrongAttempted() is holding
    ++            // an unneeded reference.  So call onLastStrongRef() here to remove it.
    ++            // (No, this is not pretty.)  Note that we MUST NOT do this if we
    ++            // are in fact acquiring the first reference.
    ++            if (curCount != 0 && curCount != INITIAL_STRONG_VALUE) {
    ++                impl->mBase->onLastStrongRef(id);
    ++            }
    +         }
    +     }
    +     
    +@@ -593,7 +592,7 @@ bool RefBase::weakref_type::attemptIncStrong(const void* id)
    +     ALOGD("attemptIncStrong of %p from %p: cnt=%d\n", this, id, curCount);
    + #endif
    + 
    +-    // curCount is the value of mStrong before we increment ed it.
    ++    // curCount is the value of mStrong before we incremented it.
    +     // Now we need to fix-up the count if it was INITIAL_STRONG_VALUE.
    +     // This must be done safely, i.e.: handle the case where several threads
    +     // were here in attemptIncStrong().
    +diff --git a/libziparchive/zip_archive.cc b/libziparchive/zip_archive.cc
    +index 1f27500..986ee72 100644
    +--- a/libziparchive/zip_archive.cc
    ++++ b/libziparchive/zip_archive.cc
    +@@ -269,9 +269,14 @@ static int32_t MapCentralDirectory0(int fd, const char* debug_file_name,
    +    * Grab the CD offset and size, and the number of entries in the
    +    * archive and verify that they look reasonable.
    +    */
    +-  if (eocd->cd_start_offset + eocd->cd_size > eocd_offset) {
    ++  if (static_cast<off64_t>(eocd->cd_start_offset) + eocd->cd_size > eocd_offset) {
    +     ALOGW("Zip: bad offsets (dir %" PRIu32 ", size %" PRIu32 ", eocd %" PRId64 ")",
    +         eocd->cd_start_offset, eocd->cd_size, static_cast<int64_t>(eocd_offset));
    ++#if defined(__ANDROID__)
    ++    if (eocd->cd_start_offset + eocd->cd_size <= eocd_offset) {
    ++      android_errorWriteLog(0x534e4554, "31251826");
    ++    }
    ++#endif
    +     return kInvalidOffset;
    +   }
    +   if (eocd->num_records == 0) {
    +diff --git a/logd/LogBuffer.cpp b/logd/LogBuffer.cpp
    +index 8c30f79..0497a89 100644
    +--- a/logd/LogBuffer.cpp
    ++++ b/logd/LogBuffer.cpp
    +@@ -313,6 +313,9 @@ LogBufferElementCollection::iterator LogBuffer::erase(
    +     LogBufferElement *element = *it;
    +     log_id_t id = element->getLogId();
    + 
    ++    // Remove iterator references in the various lists that will become stale
    ++    // after the element is erased from the main logging list.
    ++
    +     {   // start of scope for uid found iterator
    +         LogBufferIteratorMap::iterator found =
    +             mLastWorstUid[id].find(element->getUid());
    +@@ -322,8 +325,8 @@ LogBufferElementCollection::iterator LogBuffer::erase(
    +         }
    +     }
    + 
    +-    if (element->getUid() == AID_SYSTEM) {
    +-        // start of scope for pid found iterator
    ++    {   // start of scope for pid found iterator
    ++        // element->getUid() may not be AID_SYSTEM for next-best-watermark.
    +         LogBufferPidIteratorMap::iterator found =
    +             mLastWorstPidOfSystem[id].find(element->getPid());
    +         if ((found != mLastWorstPidOfSystem[id].end())
    +@@ -639,6 +642,7 @@ bool LogBuffer::prune(log_id_t id, unsigned long pruneRows, uid_t caller_uid) {
    +                 ++it;
    +                 continue;
    +             }
    ++            // below this point element->getLogId() == id
    + 
    +             if (leading && (!mLastSet[id] || ((*mLast[id])->getLogId() != id))) {
    +                 mLast[id] = it;
    +@@ -691,7 +695,9 @@ bool LogBuffer::prune(log_id_t id, unsigned long pruneRows, uid_t caller_uid) {
    +                         && ((!gc && (element->getPid() == worstPid))
    +                             || (mLastWorstPidOfSystem[id].find(element->getPid())
    +                                 == mLastWorstPidOfSystem[id].end()))) {
    +-                    mLastWorstPidOfSystem[id][element->getUid()] = it;
    ++                    // element->getUid() may not be AID_SYSTEM, next best
    ++                    // watermark if current one empty.
    ++                    mLastWorstPidOfSystem[id][element->getPid()] = it;
    +                 }
    +                 if ((!gc && !worstPid && (element->getUid() == worst))
    +                         || (mLastWorstUid[id].find(element->getUid())
    +@@ -709,6 +715,8 @@ bool LogBuffer::prune(log_id_t id, unsigned long pruneRows, uid_t caller_uid) {
    +                 ++it;
    +                 continue;
    +             }
    ++            // key == worst below here
    ++            // If worstPid set, then element->getPid() == worstPid below here
    + 
    +             pruneRows--;
    +             if (pruneRows == 0) {
    +@@ -732,6 +740,8 @@ bool LogBuffer::prune(log_id_t id, unsigned long pruneRows, uid_t caller_uid) {
    +                     if (worstPid && (!gc
    +                                 || (mLastWorstPidOfSystem[id].find(worstPid)
    +                                     == mLastWorstPidOfSystem[id].end()))) {
    ++                        // element->getUid() may not be AID_SYSTEM, next best
    ++                        // watermark if current one empty.
    +                         mLastWorstPidOfSystem[id][worstPid] = it;
    +                     }
    +                     if ((!gc && !worstPid) || (mLastWorstUid[id].find(worst)
     diff --git a/rootdir/init.rc b/rootdir/init.rc
    -index 56379db..3b0fd4d 100644
    +index 56379db..7a5c9b3 100644
     --- a/rootdir/init.rc
     +++ b/rootdir/init.rc
    -@@ -654,6 +654,6 @@ on property:ro.debuggable=1
    +@@ -236,6 +236,9 @@ on init
    + 
    +     export DOWNLOAD_CACHE /data/cache
    + 
    ++    # set RLIMIT_NICE to allow priorities from 19 to -20
    ++    setrlimit 13 40 40
    ++
    + # Healthd can trigger a full boot from charger mode by signaling this
    + # property when the power button is held.
    + on property:sys.boot_from_charger_mode=1
    +@@ -258,6 +261,11 @@ on firmware_mounts_complete
    + # Mount filesystems and start core system services.
    + on late-init
    +     trigger early-fs
    ++
    ++    # Mount fstab in init.{$device}.rc by mount_all command. Optional parameter
    ++    # '--early' can be specified to skip entries with 'latemount'.
    ++    # /system and /vendor must be mounted by the end of the fs stage,
    ++    # while /data is optional.
    +     trigger fs
    +     trigger post-fs
    + 
    +@@ -266,9 +274,18 @@ on late-init
    +     # issued fs triggers have completed.
    +     trigger load_system_props_action
    + 
    ++    # Mount fstab in init.{$device}.rc by mount_all with '--late' parameter
    ++    # to only mount entries with 'latemount'. This is needed if '--early' is
    ++    # specified in the previous mount_all command on the fs stage.
    ++    # With /system mounted and properties form /system + /factory available,
    ++    # some services can be started.
    ++    trigger late-fs
    ++
    +     # Now we can mount /data. File encryption requires keymaster to decrypt
    +-    # /data, which in turn can only be loaded when system properties are present
    ++    # /data, which in turn can only be loaded when system properties are present.
    +     trigger post-fs-data
    ++
    ++    # Load persist properties and override properties (if enabled) from /data.
    +     trigger load_persist_props_action
    + 
    +     # Remove a file to wake up anything waiting for firmware.
    +@@ -484,9 +501,6 @@ on boot
    +     hostname localhost
    +     domainname localdomain
    + 
    +-    # set RLIMIT_NICE to allow priorities from 19 to -20
    +-    setrlimit 13 40 40
    +-
    +     # Memory management.  Basic kernel parameters, and allow the high
    +     # level system server to be able to adjust the kernel OOM driver
    +     # parameters to match how it is managing things.
    +@@ -654,6 +668,6 @@ on property:ro.debuggable=1
          chmod 0773 /data/misc/trace
          start console
      
    @@ -195,3 +1355,47 @@ index 56379db..3b0fd4d 100644
     +#service flash_recovery /system/bin/install-recovery.sh
     +#    class main
     +#    oneshot
    +diff --git a/sdcard/sdcard.c b/sdcard/sdcard.c
    +index 9480e4a..13ebaf1 100644
    +--- a/sdcard/sdcard.c
    ++++ b/sdcard/sdcard.c
    +@@ -1221,7 +1221,13 @@ static int handle_open(struct fuse* fuse, struct fuse_handler* handler,
    +     }
    +     out.fh = ptr_to_id(h);
    +     out.open_flags = 0;
    ++
    ++#ifdef FUSE_SHORTCIRCUIT
    ++    out.lower_fd = h->fd;
    ++#else
    +     out.padding = 0;
    ++#endif
    ++
    +     fuse_reply(fuse, hdr->unique, &out, sizeof(out));
    +     return NO_STATUS;
    + }
    +@@ -1385,7 +1391,13 @@ static int handle_opendir(struct fuse* fuse, struct fuse_handler* handler,
    +     }
    +     out.fh = ptr_to_id(h);
    +     out.open_flags = 0;
    ++
    ++#ifdef FUSE_SHORTCIRCUIT
    ++    out.lower_fd = -1;
    ++#else
    +     out.padding = 0;
    ++#endif
    ++
    +     fuse_reply(fuse, hdr->unique, &out, sizeof(out));
    +     return NO_STATUS;
    + }
    +@@ -1467,6 +1479,11 @@ static int handle_init(struct fuse* fuse, struct fuse_handler* handler,
    +     out.major = FUSE_KERNEL_VERSION;
    +     out.max_readahead = req->max_readahead;
    +     out.flags = FUSE_ATOMIC_O_TRUNC | FUSE_BIG_WRITES;
    ++
    ++#ifdef FUSE_SHORTCIRCUIT
    ++    out.flags |= FUSE_SHORTCIRCUIT;
    ++#endif
    ++
    +     out.max_background = 32;
    +     out.congestion_threshold = 32;
    +     out.max_write = MAX_WRITE;
    diff --git a/system_sepolicy.patch b/system_sepolicy.patch
    index 1c95f0f..f35473d 100644
    --- a/system_sepolicy.patch
    +++ b/system_sepolicy.patch
    @@ -11,6 +11,18 @@ index e9dd7b3..ef2bd9d 100644
      neverallow { appdomain -bluetooth } self:capability2 *;
      
      # Block device access.
    +diff --git a/bootanim.te b/bootanim.te
    +index e18654c..c3091ab 100644
    +--- a/bootanim.te
    ++++ b/bootanim.te
    +@@ -19,6 +19,7 @@ allow bootanim audio_device:chr_file rw_file_perms;
    + 
    + allow bootanim audioserver_service:service_manager find;
    + allow bootanim surfaceflinger_service:service_manager find;
    ++allow bootanim audioserver_service:service_manager find;
    + 
    + # Allow access to ion memory allocation device
    + allow bootanim ion_device:chr_file rw_file_perms;
     diff --git a/domain.te b/domain.te
     index 45569de..21c9df2 100644
     --- a/domain.te
    @@ -98,6 +110,28 @@ index 45569de..21c9df2 100644
      
      neverallow {
        domain
    +diff --git a/dumpstate.te b/dumpstate.te
    +index dda8a58..115bb09 100644
    +--- a/dumpstate.te
    ++++ b/dumpstate.te
    +@@ -5,6 +5,7 @@ type dumpstate_exec, exec_type, file_type;
    + init_daemon_domain(dumpstate)
    + net_domain(dumpstate)
    + binder_use(dumpstate)
    ++wakelock_use(dumpstate)
    + 
    + # Allow setting process priority, protect from OOM killer, and dropping
    + # privileges by switching UID / GID
    +@@ -136,6 +137,9 @@ control_logd(dumpstate)
    + allow dumpstate net_data_file:dir search;
    + allow dumpstate net_data_file:file r_file_perms;
    + 
    ++# List sockets via ss.
    ++allow dumpstate self:netlink_tcpdiag_socket { create_socket_perms nlmsg_read };
    ++
    + # Access /data/tombstones.
    + allow dumpstate tombstone_data_file:dir r_dir_perms;
    + allow dumpstate tombstone_data_file:file r_file_perms;
     diff --git a/file.te b/file.te
     index 84af4a7..55910d2 100644
     --- a/file.te
    @@ -111,6 +145,31 @@ index 84af4a7..55910d2 100644
      type fuse, sdcard_type, fs_type, mlstrustedobject;
      type sdcardfs, sdcard_type, fs_type, mlstrustedobject;
      type vfat, sdcard_type, fs_type, mlstrustedobject;
    +diff --git a/otapreopt_chroot.te b/otapreopt_chroot.te
    +index fcba7b1..1c5f2ee 100644
    +--- a/otapreopt_chroot.te
    ++++ b/otapreopt_chroot.te
    +@@ -10,6 +10,8 @@ allow otapreopt_chroot self:capability { sys_admin sys_chroot };
    + # This is required to mount /vendor.
    + allow otapreopt_chroot block_device:dir search;
    + allow otapreopt_chroot labeledfs:filesystem mount;
    ++# Mounting /vendor can have this side-effect. Ignore denial.
    ++dontaudit otapreopt_chroot kernel:process setsched;
    + 
    + # Allow to transition to postinstall_ota, to run otapreopt in its own sandbox.
    + domain_auto_trans(otapreopt_chroot, postinstall_file, postinstall_dexopt)
    +diff --git a/platform_app.te b/platform_app.te
    +index 0d3bdba..d4a27ad 100644
    +--- a/platform_app.te
    ++++ b/platform_app.te
    +@@ -45,6 +45,7 @@ allow platform_app drmserver_service:service_manager find;
    + allow platform_app mediaserver_service:service_manager find;
    + allow platform_app mediaextractor_service:service_manager find;
    + allow platform_app mediacodec_service:service_manager find;
    ++allow platform_app mediadrmserver_service:service_manager find;
    + allow platform_app persistent_data_block_service:service_manager find;
    + allow platform_app radio_service:service_manager find;
    + allow platform_app surfaceflinger_service:service_manager find;
     diff --git a/priv_app.te b/priv_app.te
     index 85516a6..e1f96d5 100644
     --- a/priv_app.te
    @@ -124,6 +183,35 @@ index 85516a6..e1f96d5 100644
      
      # Do not allow privileged apps to register services.
      # Only trusted components of Android should be registering
    +diff --git a/service.te b/service.te
    +index 6b5838c..e7a30f9 100644
    +--- a/service.te
    ++++ b/service.te
    +@@ -39,6 +39,7 @@ type contexthub_service, app_api_service, system_server_service, service_manager
    + type IProxyService_service, app_api_service, system_server_service, service_manager_type;
    + type commontime_management_service, system_server_service, service_manager_type;
    + type connectivity_service, app_api_service, system_server_service, service_manager_type;
    ++type connmetrics_service, app_api_service, system_server_service, service_manager_type;
    + type consumer_ir_service, app_api_service, system_server_service, service_manager_type;
    + type content_service, app_api_service, system_server_service, service_manager_type;
    + type country_detector_service, app_api_service, system_server_service, service_manager_type;
    +diff --git a/service_contexts b/service_contexts
    +index 0ddbdc1..dd7e49f 100644
    +--- a/service_contexts
    ++++ b/service_contexts
    +@@ -19,9 +19,10 @@ carrier_config                            u:object_r:radio_service:s0
    + clipboard                                 u:object_r:clipboard_service:s0
    + com.android.net.IProxyService             u:object_r:IProxyService_service:s0
    + commontime_management                     u:object_r:commontime_management_service:s0
    +-common_time.clock                        u:object_r:mediaserver_service:s0
    +-common_time.config                       u:object_r:mediaserver_service:s0
    ++common_time.clock                         u:object_r:mediaserver_service:s0
    ++common_time.config                        u:object_r:mediaserver_service:s0
    + connectivity                              u:object_r:connectivity_service:s0
    ++connmetrics                               u:object_r:connmetrics_service:s0
    + consumer_ir                               u:object_r:consumer_ir_service:s0
    + content                                   u:object_r:content_service:s0
    + contexthub_service                        u:object_r:contexthub_service:s0
     diff --git a/untrusted_app.te b/untrusted_app.te
     index 35c811c..19cfc64 100644
     --- a/untrusted_app.te
    
    From 9d9cf04ef80ba2030a6a9469ec84539ff16d1e2a Mon Sep 17 00:00:00 2001
    From: AndDiSa <anddisa@googlemail.com>
    Date: Sun, 11 Dec 2016 14:13:22 +0100
    Subject: [PATCH 054/159] move to proprietary_vendor_widevine
    
    Change-Id: Ib752297ab16f09299fc6c9538d217ff3ecb91edd
    ---
     default.xml | 4 +++-
     1 file changed, 3 insertions(+), 1 deletion(-)
    
    diff --git a/default.xml b/default.xml
    index f213df5..90c0b9f 100644
    --- a/default.xml
    +++ b/default.xml
    @@ -7,6 +7,8 @@
                fetch="https://github.com/AndDiSa/" />
       <remote  name="millosr"
                fetch="https://github.com/millosr/" />
    +  <remote  name="unlegacy"
    +           fetch="https://github.com/Unlegacy-Android/" />
       <default revision="refs/tags/android-7.1.1_r4"
                remote="aosp"
                sync-j="4" />
    @@ -510,5 +512,5 @@
       <project path="vendor/elan" name="proprietary_vendor_elan" remote="ads" revision="oct-mm" />
       <project path="vendor/invensense" name="proprietary_vendor_invensense" remote="ads" revision="ads-7.0.1" />
       <project path="vendor/nvidia" name="proprietary_vendor_nvidia" remote="ads" revision="ads-7.0.1" />
    -  <project path="vendor/widevine" name="proprietary_vendor_widevine" remote="ads" revision="ads-7.0.1" />
    +  <project path="vendor/widevine" name="proprietary_vendor_widevine" remote="unlegacy" revision="aosp-7.1" />
     </manifest>
    
    From 63efc411e1a97085c07bc6f3b58f4754f42884ea Mon Sep 17 00:00:00 2001
    From: AndDiSa <anddisa@googlemail.com>
    Date: Mon, 12 Dec 2016 18:42:41 +0100
    Subject: [PATCH 055/159] add projects
    
    Change-Id: I4d5c7c3aae093bc1a8e366273c665ea924ef9dfa
    ---
     default.xml | 2 ++
     1 file changed, 2 insertions(+)
    
    diff --git a/default.xml b/default.xml
    index 90c0b9f..e411ddc 100644
    --- a/default.xml
    +++ b/default.xml
    @@ -37,6 +37,7 @@
       <project path="device/generic/armv7-a-neon" name="device/generic/armv7-a-neon" groups="pdk" />
       <project path="device/generic/common" name="device/generic/common" groups="pdk" />
       <project path="device/generic/goldfish" name="device/generic/goldfish" groups="pdk" />
    +  <project path="device/generic/goldfish-opengl" name="device/generic/goldfish-opengl" groups="pdk" />
       <project path="device/generic/mini-emulator-arm64" name="device/generic/mini-emulator-arm64" groups="pdk" />
       <project path="device/generic/mini-emulator-armv7-a-neon" name="device/generic/mini-emulator-armv7-a-neon" groups="pdk" />
       <project path="device/generic/mini-emulator-x86" name="device/generic/mini-emulator-x86" groups="pdk" />
    @@ -424,6 +425,7 @@
       <project path="packages/apps/Test/connectivity" name="platform/packages/apps/Test/connectivity" />
       <project path="packages/apps/TvSettings" name="platform/packages/apps/TvSettings" groups="generic_fs" />
       <project path="packages/apps/UnifiedEmail" name="platform/packages/apps/UnifiedEmail" groups="pdk-fs" />
    +  <project path="packages/apps/WallpaperPicker" name="platform/packages/apps/WallpaperPicker" />
       <project path="packages/experimental" name="platform/packages/experimental" />
       <project path="packages/inputmethods/LatinIME" name="platform/packages/inputmethods/LatinIME" groups="pdk-fs" />
       <project path="packages/inputmethods/OpenWnn" name="platform/packages/inputmethods/OpenWnn" groups="pdk-fs" />
    
    From 2ae6094d406bc523df19aee0850f0c90a5905552 Mon Sep 17 00:00:00 2001
    From: AndDiSa <anddisa@googlemail.com>
    Date: Tue, 13 Dec 2016 17:37:51 +0100
    Subject: [PATCH 056/159] update patches
    
    Change-Id: I19a943bef82b1ef54efb48fea41a6a094f93b424
    ---
     build.patch             |  27427 -------
     frameworks_av.patch     |   3473 +-
     frameworks_base.patch   | 155247 +------------------------------------
     frameworks_native.patch |   1308 +-
     hardware_ril.patch      |     66 +-
     system_core.patch       |   1208 +-
     system_sepolicy.patch   |     88 -
     7 files changed, 1999 insertions(+), 186818 deletions(-)
    
    diff --git a/build.patch b/build.patch
    index bfec89e..b699411 100644
    --- a/build.patch
    +++ b/build.patch
    @@ -1,35 +1,3 @@
    -diff --git a/core/Makefile b/core/Makefile
    -index 2031132..5badde5 100644
    ---- a/core/Makefile
    -+++ b/core/Makefile
    -@@ -1383,6 +1383,8 @@ $(INSTALLED_USERDATATARBALL_TARGET): PRIVATE_USERDATA_TAR := $(userdata_tar)
    - $(INSTALLED_USERDATATARBALL_TARGET): $(FS_GET_STATS) $(INTERNAL_USERDATAIMAGE_FILES)
    - 	$(build-userdatatarball-target)
    - 
    -+$(call dist-for-goals,userdatatarball,$(INSTALLED_USERDATATARBALL_TARGET))
    -+
    - .PHONY: userdatatarball-nodeps
    - userdatatarball-nodeps: $(FS_GET_STATS)
    - 	$(build-userdatatarball-target)
    -@@ -2039,7 +2041,7 @@ PROGUARD_DICT_ZIP := $(PRODUCT_OUT)/$(TARGET_PRODUCT)-proguard-dict-$(FILE_NAME_
    - # the dependency will be set up later in build/core/main.mk.
    - $(PROGUARD_DICT_ZIP) :
    - 	@echo "Packaging Proguard obfuscation dictionary files."
    --	$(hide) dict_files=`find $(TARGET_OUT_COMMON_INTERMEDIATES)/APPS -name proguard_dictionary`; \
    -+	$(hide) dict_files=`find $(TARGET_OUT_COMMON_INTERMEDIATES)/APPS -name proguard_dictionary -o -name jack_dictionary`; \
    - 		if [ -n "$$dict_files" ]; then \
    - 		  unobfuscated_jars=$${dict_files//proguard_dictionary/classes.jar}; \
    - 		  zip -qX $@ $$dict_files $$unobfuscated_jars; \
    -diff --git a/core/build_id.mk b/core/build_id.mk
    -index c8d331d..c3d6c40 100644
    ---- a/core/build_id.mk
    -+++ b/core/build_id.mk
    -@@ -18,4 +18,4 @@
    - # (like "CRB01").  It must be a single word, and is
    - # capitalized by convention.
    - 
    --export BUILD_ID=NDE63U
    -+export BUILD_ID=NMF26O
     diff --git a/core/main.mk b/core/main.mk
     index a612f83..921eb32 100644
     --- a/core/main.mk
    @@ -43,18 +11,6 @@ index a612f83..921eb32 100644
      endif
      
      
    -diff --git a/core/pathmap.mk b/core/pathmap.mk
    -index edc584b..effc878 100644
    ---- a/core/pathmap.mk
    -+++ b/core/pathmap.mk
    -@@ -121,6 +121,7 @@ FRAMEWORKS_SUPPORT_SUBDIRS := \
    -         design \
    -         percent \
    -         recommendation \
    -+        transition \
    -         v7/preference \
    -         v14/preference \
    -         v17/preference-leanback \
     diff --git a/core/tasks/kernel.mk b/core/tasks/kernel.mk
     new file mode 100644
     index 0000000..9c12bc0
    @@ -257,28 +213,6 @@ index 0000000..9c12bc0
     +
     +ALL_PREBUILT += $(INSTALLED_KERNEL_TARGET)
     +endif
    -diff --git a/core/version_defaults.mk b/core/version_defaults.mk
    -index 47dc01c..2c8a21f 100644
    ---- a/core/version_defaults.mk
    -+++ b/core/version_defaults.mk
    -@@ -43,7 +43,7 @@ ifeq "" "$(PLATFORM_VERSION)"
    -   # which is the version that we reveal to the end user.
    -   # Update this value when the platform version changes (rather
    -   # than overriding it somewhere else).  Can be an arbitrary string.
    --  PLATFORM_VERSION := 7.1
    -+  PLATFORM_VERSION := 7.1.1
    - endif
    - 
    - ifeq "" "$(PLATFORM_SDK_VERSION)"
    -@@ -114,7 +114,7 @@ ifeq "" "$(PLATFORM_SECURITY_PATCH)"
    -     #  It must be of the form "YYYY-MM-DD" on production devices.
    -     #  It must match one of the Android Security Patch Level strings of the Public Security Bulletins.
    -     #  If there is no $PLATFORM_SECURITY_PATCH set, keep it empty.
    --      PLATFORM_SECURITY_PATCH := 2016-11-05
    -+      PLATFORM_SECURITY_PATCH := 2016-12-05
    - endif
    - 
    - ifeq "" "$(PLATFORM_BASE_OS)"
     diff --git a/core/version_defaults_BACKUP_20377.mk b/core/version_defaults_BACKUP_20377.mk
     new file mode 100644
     index 0000000..eb97b11
    @@ -955,27364 +889,3 @@ index 0000000..2c8a21f
     +  # anyone trying to parse it as an integer will probably get "0".
     +  BUILD_NUMBER := eng.$(shell echo $${USER:0:6}).$(shell $(DATE) +%Y%m%d.%H%M%S)
     +endif
    -diff --git a/target/board/generic/BoardConfig.mk b/target/board/generic/BoardConfig.mk
    -index 325b0ce..02c1c88 100644
    ---- a/target/board/generic/BoardConfig.mk
    -+++ b/target/board/generic/BoardConfig.mk
    -@@ -45,28 +45,6 @@ BUILD_EMULATOR_OPENGL := true
    - # the GLES renderer disables itself if host GL acceleration isn't available.
    - USE_OPENGL_RENDERER := true
    - 
    --# Set the phase offset of the system's vsync event relative to the hardware
    --# vsync. The system's vsync event drives Choreographer and SurfaceFlinger's
    --# rendering. This value is the number of nanoseconds after the hardware vsync
    --# that the system vsync event will occur.
    --#
    --# This phase offset allows adjustment of the minimum latency from application
    --# wake-up (by Choregographer) time to the time at which the resulting window
    --# image is displayed.  This value may be either positive (after the HW vsync)
    --# or negative (before the HW vsync).  Setting it to 0 will result in a
    --# minimum latency of two vsync periods because the app and SurfaceFlinger
    --# will run just after the HW vsync.  Setting it to a positive number will
    --# result in the minimum latency being:
    --#
    --#     (2 * VSYNC_PERIOD - (vsyncPhaseOffsetNs % VSYNC_PERIOD))
    --#
    --# Note that reducing this latency makes it more likely for the applications
    --# to not have their window content image ready in time.  When this happens
    --# the latency will end up being an additional vsync period, and animations
    --# will hiccup.  Therefore, this latency should be tuned somewhat
    --# conservatively (or at least with awareness of the trade-off being made).
    --VSYNC_EVENT_PHASE_OFFSET_NS := 0
    --
    - TARGET_USERIMAGES_USE_EXT4 := true
    - BOARD_SYSTEMIMAGE_PARTITION_SIZE := 1879048192  # 1.75 GB
    - BOARD_USERDATAIMAGE_PARTITION_SIZE := 576716800
    -diff --git a/target/board/generic/sepolicy/file_contexts b/target/board/generic/sepolicy/file_contexts
    -index e8d32f7..e9502d9 100644
    ---- a/target/board/generic/sepolicy/file_contexts
    -+++ b/target/board/generic/sepolicy/file_contexts
    -@@ -9,6 +9,7 @@
    - /dev/block/vdc               u:object_r:userdata_block_device:s0
    - 
    - /dev/goldfish_pipe           u:object_r:qemu_device:s0
    -+/dev/goldfish_sync           u:object_r:qemu_device:s0
    - /dev/qemu_.*                 u:object_r:qemu_device:s0
    - /dev/socket/qemud            u:object_r:qemud_socket:s0
    - /dev/ttyGF[0-9]*             u:object_r:serial_device:s0
    -diff --git a/target/board/generic_x86_64/BoardConfig.mk b/target/board/generic_x86_64/BoardConfig.mk
    -index 553bec9..283e9cc 100755
    ---- a/target/board/generic_x86_64/BoardConfig.mk
    -+++ b/target/board/generic_x86_64/BoardConfig.mk
    -@@ -38,7 +38,7 @@ BUILD_EMULATOR_OPENGL := true
    - USE_OPENGL_RENDERER := true
    - 
    - TARGET_USERIMAGES_USE_EXT4 := true
    --BOARD_SYSTEMIMAGE_PARTITION_SIZE := 1879048192  # 1.75 GB
    -+BOARD_SYSTEMIMAGE_PARTITION_SIZE := 2147483648 # 2 GB
    - BOARD_USERDATAIMAGE_PARTITION_SIZE := 576716800
    - BOARD_CACHEIMAGE_PARTITION_SIZE := 69206016
    - BOARD_CACHEIMAGE_FILE_SYSTEM_TYPE := ext4
    -diff --git a/tools/droiddoc/templates-ndk/assets/css/default.css b/tools/droiddoc/templates-ndk/assets/css/default.css
    -index f411d93..036c0eb 100644
    ---- a/tools/droiddoc/templates-ndk/assets/css/default.css
    -+++ b/tools/droiddoc/templates-ndk/assets/css/default.css
    -@@ -4217,7 +4217,7 @@ EndColorStr='#ececec');
    - }
    - 
    - /* offset the <a name=""> tags to account for sticky nav */
    --body.reference a[name] {
    -+body.reference a[name]:empty {
    -   visibility: hidden;
    -   display: block;
    -   position: relative;
    -diff --git a/tools/droiddoc/templates-sdk-dev/assets/GPL-LICENSE.txt b/tools/droiddoc/templates-sdk-dev/assets/GPL-LICENSE.txt
    -deleted file mode 100644
    -index 66a0f18..0000000
    ---- a/tools/droiddoc/templates-sdk-dev/assets/GPL-LICENSE.txt
    -+++ /dev/null
    -@@ -1,278 +0,0 @@
    --       GNU GENERAL PUBLIC LICENSE
    --           Version 2, June 1991
    --
    -- Copyright (C) 1989, 1991 Free Software Foundation, Inc.
    -- 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
    -- Everyone is permitted to copy and distribute verbatim copies
    -- of this license document, but changing it is not allowed.
    --
    --          Preamble
    --
    --  The licenses for most software are designed to take away your
    --freedom to share and change it.  By contrast, the GNU General Public
    --License is intended to guarantee your freedom to share and change free
    --software--to make sure the software is free for all its users.  This
    --General Public License applies to most of the Free Software
    --Foundation's software and to any other program whose authors commit to
    --using it.  (Some other Free Software Foundation software is covered by
    --the GNU Lesser General Public License instead.)  You can apply it to
    --your programs, too.
    --
    --  When we speak of free software, we are referring to freedom, not
    --price.  Our General Public Licenses are designed to make sure that you
    --have the freedom to distribute copies of free software (and charge for
    --this service if you wish), that you receive source code or can get it
    --if you want it, that you can change the software or use pieces of it
    --in new free programs; and that you know you can do these things.
    --
    --  To protect your rights, we need to make restrictions that forbid
    --anyone to deny you these rights or to ask you to surrender the rights.
    --These restrictions translate to certain responsibilities for you if you
    --distribute copies of the software, or if you modify it.
    --
    --  For example, if you distribute copies of such a program, whether
    --gratis or for a fee, you must give the recipients all the rights that
    --you have.  You must make sure that they, too, receive or can get the
    --source code.  And you must show them these terms so they know their
    --rights.
    --
    --  We protect your rights with two steps: (1) copyright the software, and
    --(2) offer you this license which gives you legal permission to copy,
    --distribute and/or modify the software.
    --
    --  Also, for each author's protection and ours, we want to make certain
    --that everyone understands that there is no warranty for this free
    --software.  If the software is modified by someone else and passed on, we
    --want its recipients to know that what they have is not the original, so
    --that any problems introduced by others will not reflect on the original
    --authors' reputations.
    --
    --  Finally, any free program is threatened constantly by software
    --patents.  We wish to avoid the danger that redistributors of a free
    --program will individually obtain patent licenses, in effect making the
    --program proprietary.  To prevent this, we have made it clear that any
    --patent must be licensed for everyone's free use or not licensed at all.
    --
    --  The precise terms and conditions for copying, distribution and
    --modification follow.
    --
    --        GNU GENERAL PUBLIC LICENSE
    --   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
    --
    --  0. This License applies to any program or other work which contains
    --a notice placed by the copyright holder saying it may be distributed
    --under the terms of this General Public License.  The "Program", below,
    --refers to any such program or work, and a "work based on the Program"
    --means either the Program or any derivative work under copyright law:
    --that is to say, a work containing the Program or a portion of it,
    --either verbatim or with modifications and/or translated into another
    --language.  (Hereinafter, translation is included without limitation in
    --the term "modification".)  Each licensee is addressed as "you".
    --
    --Activities other than copying, distribution and modification are not
    --covered by this License; they are outside its scope.  The act of
    --running the Program is not restricted, and the output from the Program
    --is covered only if its contents constitute a work based on the
    --Program (independent of having been made by running the Program).
    --Whether that is true depends on what the Program does.
    --
    --  1. You may copy and distribute verbatim copies of the Program's
    --source code as you receive it, in any medium, provided that you
    --conspicuously and appropriately publish on each copy an appropriate
    --copyright notice and disclaimer of warranty; keep intact all the
    --notices that refer to this License and to the absence of any warranty;
    --and give any other recipients of the Program a copy of this License
    --along with the Program.
    --
    --You may charge a fee for the physical act of transferring a copy, and
    --you may at your option offer warranty protection in exchange for a fee.
    --
    --  2. You may modify your copy or copies of the Program or any portion
    --of it, thus forming a work based on the Program, and copy and
    --distribute such modifications or work under the terms of Section 1
    --above, provided that you also meet all of these conditions:
    --
    --    a) You must cause the modified files to carry prominent notices
    --    stating that you changed the files and the date of any change.
    --
    --    b) You must cause any work that you distribute or publish, that in
    --    whole or in part contains or is derived from the Program or any
    --    part thereof, to be licensed as a whole at no charge to all third
    --    parties under the terms of this License.
    --
    --    c) If the modified program normally reads commands interactively
    --    when run, you must cause it, when started running for such
    --    interactive use in the most ordinary way, to print or display an
    --    announcement including an appropriate copyright notice and a
    --    notice that there is no warranty (or else, saying that you provide
    --    a warranty) and that users may redistribute the program under
    --    these conditions, and telling the user how to view a copy of this
    --    License.  (Exception: if the Program itself is interactive but
    --    does not normally print such an announcement, your work based on
    --    the Program is not required to print an announcement.)
    --
    --These requirements apply to the modified work as a whole.  If
    --identifiable sections of that work are not derived from the Program,
    --and can be reasonably considered independent and separate works in
    --themselves, then this License, and its terms, do not apply to those
    --sections when you distribute them as separate works.  But when you
    --distribute the same sections as part of a whole which is a work based
    --on the Program, the distribution of the whole must be on the terms of
    --this License, whose permissions for other licensees extend to the
    --entire whole, and thus to each and every part regardless of who wrote it.
    --
    --Thus, it is not the intent of this section to claim rights or contest
    --your rights to work written entirely by you; rather, the intent is to
    --exercise the right to control the distribution of derivative or
    --collective works based on the Program.
    --
    --In addition, mere aggregation of another work not based on the Program
    --with the Program (or with a work based on the Program) on a volume of
    --a storage or distribution medium does not bring the other work under
    --the scope of this License.
    --
    --  3. You may copy and distribute the Program (or a work based on it,
    --under Section 2) in object code or executable form under the terms of
    --Sections 1 and 2 above provided that you also do one of the following:
    --
    --    a) Accompany it with the complete corresponding machine-readable
    --    source code, which must be distributed under the terms of Sections
    --    1 and 2 above on a medium customarily used for software interchange; or,
    --
    --    b) Accompany it with a written offer, valid for at least three
    --    years, to give any third party, for a charge no more than your
    --    cost of physically performing source distribution, a complete
    --    machine-readable copy of the corresponding source code, to be
    --    distributed under the terms of Sections 1 and 2 above on a medium
    --    customarily used for software interchange; or,
    --
    --    c) Accompany it with the information you received as to the offer
    --    to distribute corresponding source code.  (This alternative is
    --    allowed only for noncommercial distribution and only if you
    --    received the program in object code or executable form with such
    --    an offer, in accord with Subsection b above.)
    --
    --The source code for a work means the preferred form of the work for
    --making modifications to it.  For an executable work, complete source
    --code means all the source code for all modules it contains, plus any
    --associated interface definition files, plus the scripts used to
    --control compilation and installation of the executable.  However, as a
    --special exception, the source code distributed need not include
    --anything that is normally distributed (in either source or binary
    --form) with the major components (compiler, kernel, and so on) of the
    --operating system on which the executable runs, unless that component
    --itself accompanies the executable.
    --
    --If distribution of executable or object code is made by offering
    --access to copy from a designated place, then offering equivalent
    --access to copy the source code from the same place counts as
    --distribution of the source code, even though third parties are not
    --compelled to copy the source along with the object code.
    --
    --  4. You may not copy, modify, sublicense, or distribute the Program
    --except as expressly provided under this License.  Any attempt
    --otherwise to copy, modify, sublicense or distribute the Program is
    --void, and will automatically terminate your rights under this License.
    --However, parties who have received copies, or rights, from you under
    --this License will not have their licenses terminated so long as such
    --parties remain in full compliance.
    --
    --  5. You are not required to accept this License, since you have not
    --signed it.  However, nothing else grants you permission to modify or
    --distribute the Program or its derivative works.  These actions are
    --prohibited by law if you do not accept this License.  Therefore, by
    --modifying or distributing the Program (or any work based on the
    --Program), you indicate your acceptance of this License to do so, and
    --all its terms and conditions for copying, distributing or modifying
    --the Program or works based on it.
    --
    --  6. Each time you redistribute the Program (or any work based on the
    --Program), the recipient automatically receives a license from the
    --original licensor to copy, distribute or modify the Program subject to
    --these terms and conditions.  You may not impose any further
    --restrictions on the recipients' exercise of the rights granted herein.
    --You are not responsible for enforcing compliance by third parties to
    --this License.
    --
    --  7. If, as a consequence of a court judgment or allegation of patent
    --infringement or for any other reason (not limited to patent issues),
    --conditions are imposed on you (whether by court order, agreement or
    --otherwise) that contradict the conditions of this License, they do not
    --excuse you from the conditions of this License.  If you cannot
    --distribute so as to satisfy simultaneously your obligations under this
    --License and any other pertinent obligations, then as a consequence you
    --may not distribute the Program at all.  For example, if a patent
    --license would not permit royalty-free redistribution of the Program by
    --all those who receive copies directly or indirectly through you, then
    --the only way you could satisfy both it and this License would be to
    --refrain entirely from distribution of the Program.
    --
    --If any portion of this section is held invalid or unenforceable under
    --any particular circumstance, the balance of the section is intended to
    --apply and the section as a whole is intended to apply in other
    --circumstances.
    --
    --It is not the purpose of this section to induce you to infringe any
    --patents or other property right claims or to contest validity of any
    --such claims; this section has the sole purpose of protecting the
    --integrity of the free software distribution system, which is
    --implemented by public license practices.  Many people have made
    --generous contributions to the wide range of software distributed
    --through that system in reliance on consistent application of that
    --system; it is up to the author/donor to decide if he or she is willing
    --to distribute software through any other system and a licensee cannot
    --impose that choice.
    --
    --This section is intended to make thoroughly clear what is believed to
    --be a consequence of the rest of this License.
    --
    --  8. If the distribution and/or use of the Program is restricted in
    --certain countries either by patents or by copyrighted interfaces, the
    --original copyright holder who places the Program under this License
    --may add an explicit geographical distribution limitation excluding
    --those countries, so that distribution is permitted only in or among
    --countries not thus excluded.  In such case, this License incorporates
    --the limitation as if written in the body of this License.
    --
    --  9. The Free Software Foundation may publish revised and/or new versions
    --of the General Public License from time to time.  Such new versions will
    --be similar in spirit to the present version, but may differ in detail to
    --address new problems or concerns.
    --
    --Each version is given a distinguishing version number.  If the Program
    --specifies a version number of this License which applies to it and "any
    --later version", you have the option of following the terms and conditions
    --either of that version or of any later version published by the Free
    --Software Foundation.  If the Program does not specify a version number of
    --this License, you may choose any version ever published by the Free Software
    --Foundation.
    --
    --  10. If you wish to incorporate parts of the Program into other free
    --programs whose distribution conditions are different, write to the author
    --to ask for permission.  For software which is copyrighted by the Free
    --Software Foundation, write to the Free Software Foundation; we sometimes
    --make exceptions for this.  Our decision will be guided by the two goals
    --of preserving the free status of all derivatives of our free software and
    --of promoting the sharing and reuse of software generally.
    --
    --          NO WARRANTY
    --
    --  11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
    --FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.  EXCEPT WHEN
    --OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
    --PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
    --OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
    --MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS
    --TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE
    --PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
    --REPAIR OR CORRECTION.
    --
    --  12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
    --WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
    --REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
    --INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
    --OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
    --TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
    --YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
    --PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
    --POSSIBILITY OF SUCH DAMAGES.
    -\ No newline at end of file
    -diff --git a/tools/droiddoc/templates-sdk-dev/assets/LICENSE.txt b/tools/droiddoc/templates-sdk-dev/assets/LICENSE.txt
    -deleted file mode 100644
    -index e84328b..0000000
    ---- a/tools/droiddoc/templates-sdk-dev/assets/LICENSE.txt
    -+++ /dev/null
    -@@ -1,20 +0,0 @@
    --Copyright (c) 2011 John Resig, http://jquery.com/
    --
    --Permission is hereby granted, free of charge, to any person obtaining
    --a copy of this software and associated documentation files (the
    --"Software"), to deal in the Software without restriction, including
    --without limitation the rights to use, copy, modify, merge, publish,
    --distribute, sublicense, and/or sell copies of the Software, and to
    --permit persons to whom the Software is furnished to do so, subject to
    --the following conditions:
    --
    --The above copyright notice and this permission notice shall be
    --included in all copies or substantial portions of the Software.
    --
    --THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
    --EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
    --MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
    --NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
    --LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
    --OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
    --WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
    -\ No newline at end of file
    -diff --git a/tools/droiddoc/templates-sdk-dev/assets/android-developer-docs.css b/tools/droiddoc/templates-sdk-dev/assets/android-developer-docs.css
    -deleted file mode 100644
    -index cd610f7..0000000
    ---- a/tools/droiddoc/templates-sdk-dev/assets/android-developer-docs.css
    -+++ /dev/null
    -@@ -1,2768 +0,0 @@
    --/* file: android-developer-core.css
    --   author: smain
    --   date: september 2008
    --   info: core developer styles (developer.android.com)
    --   Required by jdiff
    --*/
    --
    --
    --/* RESET STYLES */
    --
    --html,body,div,h1,h2,h3,h4,h5,h6,p,img,
    --dl,dt,dd,ol,ul,li,table,caption,tbody,
    --tfoot,thead,tr,th,td,form,fieldset,
    --embed,object,applet {
    --  margin: 0;
    --  padding: 0;
    --  border: 0;
    --}
    --
    --/* BASICS */
    --
    --html, body {
    --  overflow:hidden; /* keeps scrollbar off IE */
    --  background-color:#fff;
    --}
    --
    --body {
    --  font-family:arial,sans-serif;
    --  color:#000;
    --  font-size:13px;
    --  color:#333;
    --  background-image:url(images/bg_fade.jpg);
    --  background-repeat:repeat-x;
    --}
    --
    --a, a code {
    --  color:#006699;
    --}
    --
    --a:active,
    --a:active code {
    --  color:#f00;
    --} 
    --
    --a:visited,
    --a:visited code {
    --  color:#006699;
    --}
    --
    --input, select,
    --textarea, option, label {
    --  font-family:inherit;
    --  font-size:inherit;
    --  padding:0;
    --  margin:0;
    --  vertical-align:middle;
    --}
    --
    --option {
    --  padding:0 4px;
    --}
    --
    --p, form {
    --  padding:0;
    --  margin:0 0 1em;
    --}
    --
    --code, pre {
    --  color:#007000;
    --  font-family:monospace;
    --  line-height:1em;
    --}
    --
    --var {
    --  color:#007000;
    --  font-style:italic;
    --}
    --
    --pre {
    --  border:1px solid #ccc;
    --  background-color:#fafafa;
    --  padding:10px;
    --  margin:0 0 1em 1em;
    --  overflow:auto;
    --  line-height:inherit; /* fixes vertical scrolling in webkit */
    --}
    --
    --h1,h2,h3,h4,h5 {
    --  margin:1em 0;
    --  padding:0;
    --}
    --
    --p,ul,ol,dl,dd,dt,li {
    --  line-height:1.3em;
    --}
    --
    --ul,ol {
    --  margin:0 0 .8em;
    --  padding:0 0 0 2em;
    --}
    --
    --li {
    --  padding:0 0 .5em;
    --}
    --
    --dl {
    --  margin:0 0 1em 0;
    --  padding:0;
    --}
    --
    --dt {
    --  margin:0;
    --  padding:0;
    --}
    --
    --dd {
    --  margin:0 0 1em;
    --  padding:0 0 0 2em;
    --}
    --
    --li p {
    --  margin:.5em 0 0;
    --}
    --
    --dd p {
    --  margin:1em 0 0;
    --}
    --
    --li pre, li table, li img {
    --  margin:.5em 0 0 1em;
    --}
    --
    --dd pre,
    --#jd-content dd table,
    --#jd-content dd img {
    --  margin:1em 0 0 1em;
    --}
    --
    --li ul,
    --li ol,
    --dd ul,
    --dd ol {
    --  margin:0;
    --  padding: 0 0 0 2em;
    --}
    --
    --li li,
    --dd li {
    --  margin:0;
    --  padding:.5em 0 0;
    --}
    --
    --dl dl,
    --ol dl,
    --ul dl {
    --  margin:0 0 1em;
    --  padding:0;
    --}
    --
    --table {
    --  font-size:1em;
    --  margin:0 0 1em;
    --  padding:0;
    --  border-collapse:collapse;
    --  border-width:0;
    --  empty-cells:show;
    --}
    --
    --td,th {
    --  border:1px solid #ccc;
    --  padding:6px 12px;
    --  text-align:left;
    --  vertical-align:top;
    --  background-color:inherit;
    --}
    --
    --th {
    --  background-color:#dee8f1;
    --}
    --
    --td > p:last-child {
    --  margin:0;
    --}
    --
    --hr.blue {
    --  background-color:#DDF0F2;
    --  border:none;
    --  height:5px;
    --  margin:20px 0 10px;
    --}
    --
    --blockquote {
    --  margin: 0 0 1em 1em;
    --  padding: 0 4em 0 1em;
    --  border-left:2px solid #eee;
    --}
    --/* LAYOUT */
    --
    --#body-content {
    --  /* "Preliminary" watermark for preview releases and interim builds.
    --  background:transparent url(images/preliminary.png) repeat scroll 0 0; */
    --  margin:0;
    --  position:relative;
    --  width:100%;
    --}
    --
    --#header {
    --  height: 114px;
    --  position:relative;
    --  z-index:100;
    --  min-width:675px; /* min width for the tabs, before they wrap */
    --  padding:0 10px;
    --  border-bottom:3px solid #94b922;
    --}
    --
    --#headerLeft{
    --  padding: 25px 0 0;
    --}
    --
    --#headerLeft img{
    --  height:50px;
    --  width:180px;
    --}
    --
    --#headerRight {
    --  position:absolute;
    --  right:0;
    --  top:0;
    --  text-align:right;
    --}
    --
    --/* Tabs in the header */
    --
    --#header ul {
    --  list-style: none;
    --  margin: 7px 0 0;
    --  padding: 0;
    --  height: 29px;
    --}
    --
    --#header li {
    --  float: left;
    --  margin: 0px 2px 0px 0px;
    --  padding:0;
    --}
    --
    --#header li a {
    --  text-decoration: none;
    --  display: block;
    --  background-image: url(images/bg_images_sprite.png);
    --  background-position: 0 -58px;
    --  background-repeat: no-repeat;
    --  color: #666;
    --  font-size: 13px;
    --  font-weight: bold;
    --  width: 94px;
    --  height: 29px;
    --  text-align: center;
    --  margin: 0px;
    --}
    --
    --#header li a:hover {
    --  background-image: url(images/bg_images_sprite.png);
    --  background-position: 0 -29px;
    --  background-repeat: no-repeat;
    --}
    --
    --#header li a span {
    --  position:relative;
    --  top:7px;
    --}
    --
    --#header li a span+span {
    --  display:none;
    --}
    --
    --/* tab highlighting */
    --
    --.home #home-link a,
    --.guide #guide-link a,
    --.reference #reference-link a,
    --.sdk #sdk-link a,
    --.resources #resources-link a,
    --.videos #videos-link a {
    --  background-image: url(images/bg_images_sprite.png);
    --  background-position: 0 0;
    --  background-repeat: no-repeat;
    --  color: #fff;
    --  font-weight: bold;
    --  cursor:default;
    --}
    --
    --.home #home-link a:hover,
    --.guide #guide-link a:hover,
    --.reference #reference-link a:hover,
    --.sdk #sdk-link a:hover,
    --.resources #resources-link a:hover,
    --.videos #videos-link  a:hover {
    --  background-image: url(images/bg_images_sprite.png);
    --  background-position: 0 0;
    --}
    --
    --#headerLinks {
    --  margin:10px 10px 0 0;
    --  height:13px;
    --  font-size: 11px;
    --  vertical-align: top;
    --}
    --
    --#headerLinks a {
    --  color: #7FA9B5;
    --}
    --
    --#headerLinks img {
    --  vertical-align:middle;
    --}
    --
    --#language {
    --  margin:0 10px 0 4px;
    --}
    --
    --#search {
    --  height:45px;
    --  margin:15px 10px 0 0;
    --}
    --
    --/* MAIN BODY */
    --
    --#mainBodyFluid {
    --  margin: 20px 10px;
    --  color:#333;
    --}
    --
    --#mainBodyFixed {
    --  margin: 20px 10px;
    --  color: #333;
    --  width:930px;
    --  position:relative;
    --}
    --
    --#mainBodyFixed h3,
    --#mainBodyFluid h3 {
    --  color:#336666;
    --  font-size:1.25em;
    --  margin: 0em 0em 0em 0em;
    --  padding-bottom:.5em;
    --}
    --
    --#mainBodyFixed h2,
    --#mainBodyFluid h2 {
    --  color:#336666;
    --  font-size:1.25em;
    --  margin: 0;
    --  padding-bottom:.5em;
    --}
    --
    --#mainBodyFixed h1,
    --#mainBodyFluid h1 {
    --  color:#435A6E;
    --  font-size:1.7em;
    --  margin: 1em 0;
    --}
    --
    --#mainBodyFixed .green,
    --#mainBodyFluid .green,
    --#jd-content .green {
    --  color:#7BB026;
    --  background-color:none;
    --}
    --
    --#mainBodyLeft {
    --  float: left;
    --  width: 600px;
    --  margin-right: 20px;
    --  color: #333;
    --  position:relative;
    --}
    --
    --div.indent {
    --  margin-left: 40px;
    --  margin-right: 70px;
    --}
    --
    --#mainBodyLeft p {
    --  color: #333;
    --  font-size: 13px;
    --}
    --
    --#mainBodyLeft p.blue {
    --  color: #669999;
    --}
    --
    --#mainBodyLeft #communityDiv {
    --  float: left;
    --  background-image:url(images/bg_community_leftDiv.jpg);
    --  background-repeat: no-repeat;
    --  width: 581px;
    --  height: 347px;
    --  padding: 20px 0px 0px 20px;
    --}
    --
    --#mainBodyRight {
    --  float: left;
    --  width: 300px;
    --  color: #333;
    --}
    --
    --#mainBodyRight p {
    --  padding-right: 50px;
    --  color: #333;
    --}
    --
    --#mainBodyRight table {
    --  width: 100%;
    --}
    --
    --#mainBodyRight td {
    --  border:0px solid #666;
    --  padding:0px 5px;
    --  text-align:left;
    --}
    --
    --#mainBodyRight td p {
    --  margin:0 0 1em 0;
    --}
    --
    --#mainBodyRight .blueBorderBox {
    --  border:5px solid #ddf0f2;
    --  padding:18px 18px 18px 18px;
    --  text-align:left;
    --}
    --
    --#mainBodyFixed .seperator {
    --  background-image:url(images/hr_gray_side.jpg);
    --  background-repeat:no-repeat;
    --  width: 100%;
    --  float: left;
    --  clear: both;
    --}
    --
    --#mainBodyBottom {
    --  float: left;
    --  width: 100%;
    --  clear:both;
    --  color: #333;
    --}
    --
    --#mainBodyBottom .seperator {
    --  background-image:url(images/hr_gray_main.jpg);
    --  background-repeat:no-repeat;
    --  width: 100%;
    --  float: left;
    --  clear: both;
    --}
    --
    --/* FOOTER */
    --
    --#footer {
    --  float: left;
    --  width:90%;
    --  margin: 20px;
    --  color: #aaa;
    --  font-size: 11px;
    --}
    --
    --#footer a {
    --  color: #aaa;
    --  font-size: 11px;
    --}
    --
    --#footer a:hover {
    --  text-decoration: underline;
    --  color:#aaa;
    --}
    --
    --#footerlinks {
    --  margin-top:2px;
    --}
    --
    --#footerlinks a,
    --#footerlinks a:visited {
    --  color:#006699;
    --}
    --
    --/* SEARCH FILTER */
    --
    --#search_autocomplete {
    --  color:#aaa;
    --}
    --
    --#search-button {
    --  display:inline;
    --}
    --
    --#search_filtered_div {
    --  position:absolute;
    --  margin-top:-1px;
    --  z-index:101;
    --  border:1px solid #BCCDF0;
    --  background-color:#fff;
    --}
    --
    --#search_filtered {
    --  min-width:100%;
    --}
    --#search_filtered td{
    --  background-color:#fff;
    --  border-bottom: 1px solid #669999;
    --  line-height:1.5em;
    --}
    --
    --#search_filtered .jd-selected {
    --  background-color: #94b922;
    --  cursor:pointer;
    --}
    --#search_filtered .jd-selected,
    --#search_filtered .jd-selected a {
    --  color:#fff;
    --}
    --
    --.no-display {
    --  display: none;
    --}
    --
    --.jd-autocomplete {
    --  font-family: Arial, sans-serif;
    --  padding-left: 6px;
    --  padding-right: 6px;
    --  padding-top: 1px;
    --  padding-bottom: 1px;
    --  font-size: 0.81em;
    --  border: none;
    --  margin: 0;
    --  line-height: 1.05em;
    --}
    --
    --.show-row {
    --  display: table-row;
    --}
    --.hide-row {
    --  display: hidden;
    --}
    --
    --/* SEARCH */
    --
    --/* restrict global search form width */
    --#searchForm {
    --  width:350px;
    --}
    --
    --#searchTxt {
    --  width:200px;
    --}
    --
    --/* disable twiddle and size selectors for left column */
    --#leftSearchControl div {
    --  width: 100%;
    --}
    --
    --#leftSearchControl .gsc-twiddle {
    --  background-image : none;
    --}
    --
    --#leftSearchControl td, #searchForm td {
    --  border: 0px solid #000;
    --}
    --
    --#leftSearchControl .gsc-resultsHeader .gsc-title {
    --  padding-left : 0px;
    --  font-weight : bold;
    --  font-size : 13px;
    --  color:#006699;
    --  display : none;
    --}
    --
    --#leftSearchControl .gsc-resultsHeader div.gsc-results-selector {
    --  display : none;
    --}
    --
    --#leftSearchControl .gsc-resultsRoot {
    --  padding-top : 6px;
    --}
    --
    --#leftSearchControl div.gs-visibleUrl-long {
    --  display : block;
    --  color:#006699;
    --}
    --
    --.gsc-webResult div.gs-visibleUrl-short,
    --table.gsc-branding,
    --.gsc-clear-button {
    --  display : none;
    --}
    --
    --.gsc-cursor-box .gsc-cursor div.gsc-cursor-page,
    --.gsc-cursor-box .gsc-trailing-more-results a.gsc-trailing-more-results,
    --#leftSearchControl a,
    --#leftSearchControl a b {
    --  color:#006699;
    --}
    --
    --.gsc-resultsHeader {
    --  display: none;
    --}
    --
    --/* Disable built in search forms */
    --.gsc-control form.gsc-search-box {
    --  display : none;
    --}
    --table.gsc-search-box {
    --  margin:6px 0 0 0;
    --  border-collapse:collapse;
    --}
    --
    --td.gsc-input {
    --  padding:0 2px;
    --  width:100%;
    --  vertical-align:middle;
    --}
    --
    --input.gsc-input {
    --  border:1px solid #BCCDF0;
    --  width:99%;
    --  padding-left:2px;
    --  font-size:.95em;
    --}
    --
    --td.gsc-search-button {
    --  text-align: right;
    --  padding:0;
    --  vertical-align:top;
    --}
    --
    --#search-button {
    --  margin:0 0 0 2px;
    --  font-size:11px;
    --}
    --
    --/* search result tabs */
    --
    --#doc-content .gsc-control {
    --  position:relative;
    --}
    --
    --#doc-content .gsc-tabsArea {
    --  position:relative;
    --  white-space:nowrap;
    --}
    --
    --#doc-content .gsc-tabHeader {
    --  padding: 3px 6px;
    --  position:relative;
    --  width:auto;
    --}
    --
    --#doc-content .gsc-tabHeader.gsc-tabhActive {
    --  border-top: 2px solid #94B922;
    --}
    --
    --#doc-content h2#searchTitle {
    --  padding:0;
    --}
    --
    --#doc-content .gsc-resultsbox-visible {
    --  padding:1em 0 0 6px;
    --}
    --
    --/* CAROUSEL */
    --
    --#homeMiddle {
    --  padding: 0px 0px 0px 0px;
    --  float: left;
    --  width: 584px;
    --  height: 627px;
    --  position:relative;
    --}
    --
    --#topAnnouncement {
    --  background:url(images/home/bg_home_announcement.png) no-repeat 0 0;
    --}
    --  
    --#homeTitle {
    --  padding:15px 15px 0;
    --  height:30px;
    --}
    --
    --#homeTitle h2 {
    --  padding:0;
    --}
    --
    --#announcement-block {
    --  padding:0 15px 0;
    --  overflow:hidden;
    --  background: url(images/hr_gray_side.jpg) no-repeat 15px 0;
    --  zoom:1;
    --}
    --
    --#announcement-block>* {
    --  padding:15px 0 0;
    --}
    --
    --#announcement-block img {
    --  float:left;
    --  margin:0 30px 0 0;
    --}
    --
    --#announcement {
    --  float:left;
    --  margin:0;
    --}
    --
    --#carousel {
    --  background:url(images/home/bg_home_carousel.png) no-repeat 0 0;
    --  position:relative;
    --  height:400px;
    --}
    --
    --#carouselMain {
    --  background: url(images/home/bg_home_carousel_board.png) 0 0 no-repeat;
    --  height:auto;
    --  padding: 25px 21px 0;
    --  overflow:hidden;
    --  position:relative;
    --  zoom:1; /*IE6*/
    --}
    --
    --#carouselMain img {
    --  margin:0;
    --}
    --
    --#carouselMain .bulletinDesc h3 {
    --  margin:0;
    --  padding:0;
    --}
    --
    --#carouselMain .bulletinDesc p {
    --  margin:0;
    --  padding:0.7em 0 0;
    --}
    --
    --#carouselWheel {
    --  background: url(images/home/bg_home_carousel_wheel.png) 0 0 no-repeat;
    --  padding-top:40px;
    --  height:150px;
    --}
    --
    --.clearer { clear:both; }
    --
    --a#arrow-left, a#arrow-right {
    --  float:left;
    --  width:42px;
    --  height:42px;
    --  background-image:url(images/home/carousel_buttons_sprite.png);
    --  background-repeat:no-repeat;
    --}
    --a#arrow-left {
    --  margin:35px 3px 0 10px;
    --}
    --a#arrow-right {
    --  margin:35px 10px 0 0;
    --}
    --a.arrow-left-off,
    --a#arrow-left.arrow-left-off:hover {
    --  background-position:0 0;
    --}
    --a.arrow-right-off,
    --a#arrow-right.arrow-right-off:hover {
    --  background-position:-42px 0;
    --}
    --a#arrow-left:hover {
    --  background-position:0 -42px;
    --}
    --a#arrow-right:hover {
    --  background-position:-42px -42px;
    --}
    --a.arrow-left-on {
    --  background-position:0 0;
    --}
    --a.arrow-right-on {
    --  background-position:-42px 0;
    --}
    --a.arrow-right-off,
    --a.arrow-left-off {
    --  cursor:default;
    --}
    --
    --.app-list-container {
    --  margin:0 20px;
    --  position:relative;
    --  width:100%;
    --}
    --
    --div#list-clip {
    --  height:110px;
    --  width:438px;
    --  overflow:hidden;
    --  position:relative;
    --  float:left;
    --}
    --
    --div#app-list {
    --  left:0;
    --  z-index:1;
    --  position:absolute;
    --  margin:11px 0 0;
    --  _margin-top:13px;
    --  width:1000%;
    --}
    --
    --#app-list a {
    --  display:block;
    --  float:left;
    --  height:90px;
    --  width:90px;
    --  margin:0 24px 0;
    --  padding:3px;
    --  background:#99cccc;
    --  -webkit-border-radius:7px;
    --  -moz-border-radius:7px;
    --  border-radius:7px;
    --  text-decoration:none;
    --  text-align:center;
    --  font-size:11px;
    --  line-height:11px;
    --}
    --
    --#app-list a span {
    --  position:relative;
    --  top:-4px;
    --}
    --
    --#app-list img {
    --  width:90px;
    --  height:70px;
    --  margin:0;
    --}
    --
    --#app-list a.selected,
    --#app-list a:active.selected,
    --#app-list a:hover.selected {
    --  background:#A4C639;
    --  color:#fff;
    --  cursor:default;
    --  text-decoration:none;
    --}
    --
    --#app-list a:hover,
    --#app-list a:active {
    --  background:#ff9900;
    --}
    --
    --#app-list a:hover span,
    --#app-list a:active span {
    --  text-decoration:underline;
    --}
    --
    --#droid-name {
    --  padding-top:.5em;
    --  color:#666;
    --  padding-bottom:.25em;
    --}
    --
    --/*IE6*/
    --* html #app-list a { zoom: 1; margin:0 24px 0 15px;}
    --
    --* html #list-clip {
    --  width:430px !important;
    --}
    --
    --/*carousel bulletin layouts*/
    --/*460px width*/
    --/*185px height*/
    --.img-left {
    --  float:left;
    --  width:230px;
    --  overflow:hidden;
    --  padding:8px 0 8px 8px;
    --}
    --.desc-right {
    --  float:left;
    --  width:270px;
    --  padding:10px;
    --}
    --.img-right {
    --  float:right;
    --  width:220px;
    --  overflow:hidden;
    --  padding:8px 8px 8px 0;
    --}
    --.desc-left {
    --  float:right;
    --  width:280px;
    --  padding:10px;
    --  text-align:right;
    --}
    --.img-top {
    --  padding:20px 20px 0;
    --}
    --.desc-bottom {
    --  padding:10px;
    --}
    --
    --
    --/* VIDEO PAGE */
    --
    --#mainBodyLeft.videoPlayer {
    --  width:570px;
    --}
    --
    --#mainBodyRight.videoPlayer {
    --  width:330px;
    --}
    --
    --/* player */
    --
    --#videoPlayerBox {
    --  background-color: #DAF3FC;
    --  border-radius:7px;
    --  -moz-border-radius:7px;
    --  -webkit-border-radius:7px;
    --  width:530px;
    --  padding:20px;
    --  border:1px solid #d3ecf5;
    --  box-shadow:2px 3px 1px #eee;
    --  -moz-box-shadow:2px 3px 1px #eee;
    --  -webkit-box-shadow:2px 3px 1px #eee;
    --}
    --
    --#videoBorder {
    --  background-color: #FFF;
    --  min-height:399px;
    --  height:auto !important;
    --  border:1px solid #ccdada;
    --  border-radius:7px 7px 0 0;
    --  -moz-border-radius:7px 7px 0 0;
    --  -webkit-border-top-left-radius:7px;
    --  -webkit-border-top-right-radius:7px;
    --}
    --
    --#videoPlayerTitle {
    --  width:500px;
    --  padding:15px 15px 0;
    --}
    --
    --#videoPlayerTitle h2 {
    --  font-weight:bold;
    --  font-size:1.2em;
    --  color:#336666;
    --  margin:0;
    --  padding:0;
    --}
    --
    --#objectWrapper {
    --  padding:15px 15px;
    --  height:334px;
    --  width:500px;
    --}
    --
    --/* playlist tabs */
    --
    --ul#videoTabs {
    --  list-style-type:none;
    --  padding:0;
    --  clear:both;
    --  margin:0;
    --  padding: 20px 0 0 15px;
    --  zoom:1; /* IE7/8, otherwise top-padding is double */
    --}
    --
    --ul#videoTabs li {
    --  display:inline;
    --  padding:0;
    --  margin:0 3px 0 0;
    --  line-height:2em;
    --}
    --
    --ul#videoTabs li a {
    --  border-radius:7px 7px 0 0;
    --  -moz-border-radius:7px 7px 0 0;
    --  -webkit-border-top-left-radius:7px;
    --  -webkit-border-top-right-radius:7px;
    --  background:#95c0d0;
    --  color:#fff;
    --  text-decoration:none;
    --  padding:.45em 1.5em;
    --  font-weight:bold;
    --}
    --
    --ul#videoTabs li.selected a {
    --  font-weight:bold;
    --  text-decoration:none;
    --  color:#555;
    --  background:#daf3fc;
    --  border-bottom:1px solid #daf3fc;
    --}
    --
    --ul#videoTabs li:hover a {
    --  background:#85acba;
    --}
    --
    --ul#videoTabs li.selected:hover a {
    --  background:#daf3fc;
    --}
    --
    --/* playlists */
    --
    --#videos {
    --  background:#daf3fc;
    --  margin-bottom:1.5em;
    --  padding:15px;
    --  border-radius:5px;
    --  -moz-border-radius:5px;
    --  -webkit-border-radius:5px;
    --  box-shadow:2px 3px 1px #eee;
    --  -moz-box-shadow:2px 3px 1px #eee;
    --  -webkit-box-shadow:2px 3px 1px #eee;
    --}
    --
    --#videos div {
    --  display:none;
    --}
    --
    --#videos div.selected {
    --  display:block;
    --}
    --
    --ul.videoPreviews {
    --  list-style:none;
    --  padding:0;
    --  margin:0;
    --  zoom:1; /* IE, otherwise, layout doesn't update when showing 'more' */
    --}
    --
    --ul.videoPreviews li {
    --  margin:0 0 5px;
    --  padding:0;
    --  overflow:hidden;
    --  position:relative;
    --}
    --
    --#mainBodyFixed ul.videoPreviews h3 {
    --  font-size: 12px;
    --  margin:0 0 1em 130px;
    --  padding:0;
    --  font-weight:bold;
    --  color:inherit;
    --}
    --
    --ul.videoPreviews a {
    --  margin:1px;
    --  padding:10px;
    --  text-decoration:none;
    --  height:90px;
    --  display:block;
    --  border-radius:5px;
    --  -moz-border-radius:5px;
    --  -webkit-border-radius:5px;
    --  background-color:transparent;
    --}
    --
    --ul.videoPreviews a:hover {
    --  background-color:#FFF;
    --  border:none; /* IE8, otherwise, bg doesn't work */
    --}
    --
    --ul.videoPreviews a.selected {
    --  background-color: #FF9900;
    --}
    --
    --ul.videoPreviews img {
    --  float:left;
    --  clear:left;
    --  margin:0;
    --}
    --
    --ul.videoPreviews h3 {
    --  font-size:12px;
    --  font-weight:bold;
    --  text-decoration:none;
    --  margin:0 0 1em 130px;
    --  padding:0;
    --}
    --
    --ul.videoPreviews p {
    --  font-size: 12px;
    --  text-decoration:none;
    --  margin:0 0 1.2em 130px;
    --}
    --
    --ul.videoPreviews p.full {
    --  display:none;
    --}
    --
    --ul.videoPreviews span.more {
    --  padding:0 0 0 12px;
    --  background:url(images/arrow_bluelink_down.png) 0 2px no-repeat;
    --}
    --
    --ul.videoPreviews span.less {
    --  padding:0 0 0 12px;
    --  background:url(images/arrow_bluelink_up.png) 0 2px no-repeat;
    --  display:none;
    --}
    --
    --ul.videoPreviews p.toggle {
    --  position:absolute;
    --  margin:0;
    --  margin-top:-23px; /* instead of bottom:23px, because IE won't do it correctly */
    --  left:140px;
    --}
    --
    --ul.videoPreviews p.toggle a {
    --  height:auto;
    --  margin:0;
    --  padding:0;
    --  zoom:1; /* IE6, otherwise the margin considers the img on redraws */
    --}
    --
    --ul.videoPreviews p.toggle a:hover {
    --  text-decoration:underline;
    --  background:transparent; /* IE6, otherwise it inherits white */
    --}
    --
    --/* featured videos */
    --
    --#mainBodyRight h2 {
    --  padding:0 0 5px;
    --}
    --
    --#mainBodyRight ul.videoPreviews {
    --  margin:10px 0 0;
    --}
    --
    --#mainBodyRight ul.videoPreviews li {
    --  font-size:11px;
    --  line-height:13px;
    --  margin:0 0 5px;
    --  padding:0;
    --}
    --
    --#mainBodyRight ul.videoPreviews h3 {
    --  padding:0;
    --  margin:0;
    --  font-size:100%;
    --}
    --
    --#mainBodyRight ul.videoPreviews a {
    --  text-decoration:none;
    --  height:108px;
    --  border:1px solid #FFF;
    --}
    --
    --#mainBodyRight ul.videoPreviews a:hover {
    --  border:1px solid #CCDADA;
    --}
    --
    --#mainBodyRight ul.videoPreviews a.selected {
    --  border:1px solid #FFF;
    --}
    --
    --#mainBodyRight ul.videoPreviews p {
    --  line-height:1.2em;
    --  padding:0;
    --  margin:4px 0 0 130px;
    --}
    --
    --#mainBodyRight ul.videoPreviews img {
    --  margin-top:5px;
    --}
    --
    --/* Pretty printing styles. Used with prettify.js. */
    --
    --.str { color: #080; }
    --.kwd { color: #008; }
    --.com { color: #800; }
    --.typ { color: #606; }
    --.lit { color: #066; }
    --.pun { color: #660; }
    --.pln { color: #000; }
    --dl.tag-list dt code,
    --.tag { color: #008; }
    --dl.atn-list dt code,
    --.atn { color: #828; }
    --.atv { color: #080; }
    --.dec { color: #606; }
    --
    --@media print {
    --  .str { color: #060; }
    --  .kwd { color: #006; font-weight: bold; }
    --  .com { color: #600; font-style: italic; }
    --  .typ { color: #404; font-weight: bold; }
    --  .lit { color: #044; }
    --  .pun { color: #440; }
    --  .pln { color: #000; }
    --  .tag { color: #006; font-weight: bold; }
    --  .atn { color: #404; }
    --  .atv { color: #060; }
    --}
    --
    --
    --#title {
    --  border-bottom: 4px solid #ccc;
    --  display:none;
    --}
    --
    --#title h1 {
    --  color:#336666;
    --  margin:0;
    --  padding: 5px 10px;
    --  font-size: 1em;
    --  line-height: 15px;
    --}
    --
    --#title h1 .small{
    --  color:#000;
    --  margin:0;
    --  font-size: 13px;
    --  padding:0 0 0 15px;
    --}
    --
    --/* SIDE NAVIGATION */
    --
    --#side-nav {
    --  padding:0 6px 0 0;
    --  background-color: #fff;
    --  font-size:12px;
    --}
    --
    --#resize-packages-nav {
    --/* keeps the resize handle below the h-scroll handle */
    --  height:270px;
    --  overflow:hidden;
    --  max-height:100%;
    --}
    --
    --#packages-nav {
    --  height:270px;
    --  max-height:inherit;
    --  position:relative;
    --  overflow:auto;
    --}
    --
    --#classes-nav,
    --#devdoc-nav {
    --  overflow:auto;
    --  position:relative;
    --}
    --
    --#side-nav ul {
    --  list-style: none;
    --  margin: 0;
    --  padding:5px 0;
    --}
    --
    --#side-nav ul ul {
    --  margin: .5em 0 0 0;
    --  padding: 0;
    --}
    --
    --#side-nav li {
    --  padding:0;
    --  padding:1px 0 1px 0;
    --  zoom:1;
    --}
    --
    --#side-nav li span.heading,
    --#side-nav li h2 {
    --  display:block;
    --  font-size:12px;
    --  font-weight: bold;
    --  margin:.5em 0 0 0;
    --  padding: 3px 0 1px 9px;
    --}
    --
    --#side-nav li a {
    --  display: inline-block; /* needed to apply padding to line-wraps */
    --  text-decoration:none;
    --  padding: 0 0 0 18px;
    --  zoom:1;
    --}
    --
    --#side-nav li a span+span {
    --  display:none;
    --}
    --
    --#side-nav li a:hover {
    --  text-decoration:underline;
    --}
    --
    --#side-nav li a+a {
    --  padding: 0;
    --}
    --/*second level (nested) list*/
    --#side-nav li li li a {
    --  padding: 0 0 0 28px;
    --}
    --/*third level (nested) list*/
    --#side-nav li li li li a {
    --  padding: 0 0 0 38px;
    --}
    --
    --#side-nav .selected {
    --  background-color: #435a6e;
    --  color: #fff;
    --  font-weight:bold;
    --}
    --
    --#side-nav .selected a {
    --  color: #fff;
    --  text-decoration:none;
    --}
    --
    --#side-nav strong {
    --  display:block;
    --}
    --
    --#side-nav .toggle-list .toggle-img {
    --  margin:0;
    --  padding:0;
    --  position:absolute;
    --  top:0;
    --  left:0;
    --  height:16px;
    --  width:15px;
    --  outline-style:none;
    --}
    --/* second-level toggle */
    --#side-nav .toggle-list .toggle-list .toggle-img {
    --  left:10px;
    --}
    --
    --#side-nav .closed .toggle-img,
    --#side-nav .open .closed .toggle-img {
    --  background:url('images/triangle-closed-small.png') 7px 4px no-repeat;
    --}
    --#side-nav .open .toggle-img {
    --  background:url('images/triangle-opened-small.png') 7px 4px no-repeat;
    --}
    --
    --#side-nav .toggle-list {
    --  position:relative;
    --}
    --
    --#side-nav .toggle-list ul {
    --  margin:0;
    --  display:none;
    --}
    --
    --#side-nav .toggle-list div {
    --  display:block;
    --}
    --
    --#index-links .selected {
    --  background-color: #fff;
    --  color: #000;
    --  font-weight:normal;
    --  text-decoration:none;
    --}
    --
    --#index-links {
    --  padding:7px 0 4px 10px;
    --}
    --
    --/* nav tree */
    --
    --#nav-tree ul {
    --  padding:5px 0 1.5em;
    --}
    --
    --#side-nav #nav-tree ul li a,
    --#side-nav #nav-tree ul li span.no-children {
    --  padding: 0 0 0 0;
    --  margin: 0;
    --}
    --
    --#nav-tree .plus {
    --  margin: 0 3px 0 0;
    --}
    --
    --#nav-tree ul ul {
    --  list-style: none;
    --  margin: 0;
    --  padding: 0 0 0 0;
    --}
    --
    --#nav-tree ul li {
    --  margin: 0;
    --  padding: 0 0 0 0;
    --  white-space: nowrap;
    --}
    --
    --#nav-tree .children_ul {
    --  margin:0;
    --}
    --
    --#nav-tree a.nolink {
    --  color: black;
    --  text-decoration: none;
    --}
    --
    --#nav-tree span.label {
    --  width: 100%;
    --}
    --
    --#nav-tree {
    --  overflow-x: auto;
    --  overflow-y: scroll;
    --}
    --
    --#nav-swap {
    --  font-size:10px;
    --  line-height:10px;
    --  margin-left:1em;
    --  text-decoration:none;
    --  display:block;
    --}
    --
    --#tree-link {
    --
    --}
    --
    --/* DOCUMENT BODY */
    --
    --#doc-content {
    --  overflow:auto;
    --}
    --
    --#jd-header {
    --  background-color: #E2E2E2;
    --  padding: 7px 15px;
    --}
    --
    --#jd-header h1 {
    --  margin: 0 0 10px;
    --  font-size:1.7em;
    --}
    --
    --#jd-header .crumb {
    --  font-size:.9em;
    --  line-height:1em;
    --  color:#777;
    --}
    --
    --#jd-header .crumb a,
    --#jd-header .crumb a:visited {
    --  text-decoration:none;
    --  color:#777;
    --}
    --
    --#jd-header .crumb a:hover {
    --  text-decoration:underline;
    --}
    --
    --#jd-header table {
    --  margin:0;
    --  padding:0;
    --}
    --
    --#jd-header td {
    --  border:none;
    --  padding:0;
    --  vertical-align:top;
    --}
    --
    --#jd-header.guide-header {
    --  background-color:#fff;
    --  color:#435a6e;
    --  height:50px;
    --}
    --
    --#jd-descr {
    --  position:relative;
    --}
    --
    --/* summary tables for reference pages */
    --.jd-sumtable {
    --  margin: .5em 1em 1em 1em;
    --  width:95%; /* consistent table widths; within IE's quirks */
    --  font-size:.9em;
    --}
    --
    --.jd-sumtable a {
    --  text-decoration:none;
    --}
    --
    --.jd-sumtable a:hover {
    --  text-decoration:underline;
    --}
    --
    --/* the link inside a sumtable for "Show All/Hide All" */
    --.toggle-all {
    --  display:block;
    --  float:right;
    --  font-weight:normal;
    --  font-size:0.9em;
    --}
    --
    --/* adjustments for in/direct subclasses tables */
    --.jd-sumtable-subclasses {
    --  margin: 1em 0 0 0;
    --  max-width:968px;
    --}
    --
    --/* extra space between end of method name and open-paren */
    --.sympad {
    --  margin-right: 2px;
    --}
    --
    --/* right alignment for the return type in sumtable */
    --.jd-sumtable .jd-typecol {
    --  text-align:right;
    --}
    --
    --/* adjustments for the expando table-in-table */
    --.jd-sumtable-expando {
    --  margin:.5em 0;
    --  padding:0;
    --}
    --
    --/* a div that holds a short description */
    --.jd-descrdiv {
    --  padding:3px 1em 0 1em;
    --  margin:0;
    --  border:0;
    --}
    --
    --/* page-top-right container for reference pages (holds
    --links to summary tables) */
    --#api-info-block {
    --  font-size:.8em;
    --  padding:6px 10px;
    --  font-weight:normal;
    --  float:right;
    --  text-align:right;
    --  color:#999;
    --  max-width:70%;
    --}
    --
    --#api-level-toggle {
    --  padding:0 10px;
    --  font-size:11px;
    --  float:right;
    --}
    --
    --#api-level-toggle label.disabled {
    --  color:#999;
    --}
    --
    --div.api-level {
    --  font-size:.8em;
    --  font-weight:normal;
    --  color:#999;
    --  float:right;
    --  padding:0 7px 0;
    --  margin-top:-25px;
    --}
    --
    --#api-info-block div.api-level {
    --  font-size:1.3em;
    --  font-weight:bold;
    --  float:none;
    --  color:#444;
    --  padding:0;
    --  margin:0;
    --}
    --
    --/* Force link colors for IE6 */
    --div.api-level a {
    --  color:#999;
    --}
    --#api-info-block div.api-level a:link {
    --  color:#444;
    --}
    --#api-level-toggle a {
    --  color:#999;
    --}
    --
    --div#deprecatedSticker {
    --  display:none;
    --  z-index:99;
    --  position:fixed;
    --  right:15px;
    --  top:114px;
    --  margin:0;
    --  padding:1em;
    --  background:#FFF;
    --  border:1px solid #dddd00;
    --  box-shadow:-5px 5px 10px #ccc;
    --  -moz-box-shadow:-5px 5px 10px #ccc;
    --  -webkit-box-shadow:-5px 5px 10px #ccc;
    --}
    --
    --div#naMessage {
    --  display:none;
    --  width:555px;
    --  height:0;
    --  margin:0 auto;
    --}
    --
    --div#naMessage div {
    --  z-index:99;
    --  width:450px;
    --  position:fixed;
    --  margin:50px 0;
    --  padding:4em 4em 3em;
    --  background:#FFF;
    --  border:1px solid #dddd00;
    --  box-shadow:-10px 10px 40px #888;
    --  -moz-box-shadow:-10px 10px 40px #888;
    --  -webkit-box-shadow:-10px 10px 40px #888;
    --}
    --/* IE6 can't position fixed */
    --* html div#naMessage div { position:absolute; }
    --
    --div#naMessage strong {
    --  font-size:1.1em;
    --}
    --
    --.absent,
    --.absent a:link,
    --.absent a:visited,
    --.absent a:hover,
    --.absent * {
    --  color:#bbb !important;
    --  cursor:default !important;
    --  text-decoration:none !important;
    --}
    --
    --#api-level-toggle a,
    --.api-level a {
    --  color:inherit;
    --  text-decoration:none;
    --}
    --
    --#api-level-toggle a:hover,
    --.api-level a:hover {
    --  color:inherit;
    --  text-decoration:underline !important;
    --  cursor:pointer !important;
    --}
    --
    --#side-nav li.absent.selected,
    --#side-nav li.absent.selected *,
    --#side-nav div.label.absent.selected,
    --#side-nav div.label.absent.selected * {
    --  background-color:#eaeaea !important;
    --}
    --/* IE6 quirk (won't chain classes, so just keep background blue) */
    --* html #side-nav li.selected,
    --* html #side-nav li.selected *,
    --* html #side-nav div.label.selected,
    --* html #side-nav div.label.selected * {
    --  background-color: #435a6e !important;
    --}
    --
    --
    --.absent h4.jd-details-title,
    --.absent h4.jd-details-title * {
    --  background-color:#f6f6f6 !important;
    --}
    --
    --.absent img {
    --  opacity: .3;
    --  filter: alpha(opacity=30);
    --  -ms-filter:"progid:DXImageTransform.Microsoft.Alpha(Opacity=30)";
    --}
    --
    --
    --/* applies to a div containing links to summary tables */
    --.sum-details-links {
    --  padding:0;
    --  font-weight:normal;
    --}
    --
    --.sum-details-links a {
    --  text-decoration:none;
    --}
    --
    --.sum-details-links a:hover {
    --  text-decoration:underline;
    --}
    --
    --
    --/* inheritance table */
    --.jd-inheritance-table {
    --  border-spacing:0;
    --  margin:0;
    --  padding:0;
    --  font-size:.9em;
    --}
    --.jd-inheritance-table td {
    --  border: none;
    --  margin: 0;
    --  padding: 0;
    --}
    --.jd-inheritance-table .jd-inheritance-space {
    --  font-weight:bold;
    --  width:1em;
    --}
    --.jd-inheritance-table .jd-inheritance-interface-cell {
    --  padding-left: 17px;
    --}
    --
    --#jd-content {
    --  padding: 18px 15px;
    --}
    --
    --hr {
    --  background-color:#ccc;
    --  border-color:#fff;
    --  margin:2em 0 1em;
    --}
    --
    --/* DOC CLASSES */
    --
    --#jd-content h1 {
    --/*sdk page*/
    --  font-size:1.6em;
    --  color:#336666;
    --  margin:0 0 .5em;
    --}
    --
    --#jd-content h2 {
    --  font-size:1.45em;
    --  color:#111;
    --  border-top:2px solid #ccc;
    --  padding: .5em 0 0;
    --  margin: 2em 0 1em 0;
    --}
    --
    --#jd-content h3 {
    --  font-size:1.3em;
    --  color:#3a3a3a;
    --  padding: 0;
    --  margin: 1.5em 0 .65em 0;
    --}
    --
    --#jd-content h4 {
    --  font-size:1.1em;
    --  color:#3a3a3a;
    --  padding: 0;
    --  margin: 1.25em 0 .65em 0;
    --}
    --
    --#jd-content h5 {
    --  font-size:1.0em;
    --  color:#3a3a3a;
    --  padding: 0;
    --  margin: 1em 0 .65em 0;
    --}
    --
    --#jd-content .small-header {
    --  font-size:1em;
    --  color:#000;
    --  font-weight:bold;
    --  border:none;
    --  padding:0;
    --  margin:1em 0 .5em;
    --  position:inherit;
    --}
    --
    --#jd-content table {
    --  margin: 0 0 1em 1em;
    --}
    --
    --#jd-content img {
    --  margin: 0 0 1em 1em;
    --}
    --
    --#jd-content li img,
    --#jd-content dd img {
    --  margin:.5em 0 .5em 1em;
    --}
    --
    --.nolist {
    --  list-style:none;
    --  padding:0;
    --  margin:0 0 1em 1em;
    --}
    --
    --.nolist li {
    --  padding:0 0 2px;
    --  margin:0;
    --}
    --
    --h4 .normal {
    --  font-size:.9em;
    --  font-weight:normal;
    --}
    --
    --.caps {
    --  font-variant:small-caps;
    --  font-size:1.2em;
    --}
    --
    --dl.tag-list dl.atn-list {
    --  padding:0 0 0 2em;
    --}
    --
    --.jd-details {
    --/*  border:1px solid #669999;
    --  padding:4px; */
    --  margin:0 0 1em;
    --}
    --
    --/* API reference: a container for the
    --.tagdata blocks that make up the detailed
    --description */
    --.jd-details-descr {
    --  padding:0;
    --  margin:.5em .25em;
    --}
    --
    --/* API reference: a block containing
    --a detailed description, a params table,
    --seealso list, etc */
    --.jd-tagdata {
    --  margin:.5em 1em;
    --}
    --
    --.jd-tagdata p {
    --  margin:0 0 1em 1em;
    --}
    --
    --/* API reference: adjustments to
    --the detailed description block */
    --.jd-tagdescr {
    --  margin:.25em 0 .75em 0;
    --  line-height:1em;
    --}
    --
    --.jd-tagdescr p {
    --  margin:.5em 0;
    --  padding:0;
    --
    --}
    --
    --.jd-tagdescr ol,
    --.jd-tagdescr ul {
    --  margin:0 2.5em;
    --  padding:0;
    --}
    --
    --.jd-tagdescr table,
    --.jd-tagdescr img {
    --  margin:.25em 1em;
    --}
    --
    --.jd-tagdescr li {
    --margin:0 0 .25em 0;
    --padding:0;
    --}
    --
    --/* API reference: heading marking
    --the details section for constants,
    --attrs, methods, etc. */
    --h4.jd-details-title {
    --  font-size:1.15em;
    --  background-color: #E2E2E2;
    --  margin:1.5em 0 .6em;
    --  padding:3px 95px 3px 3px; /* room for api-level */
    --}
    --
    --h4.jd-tagtitle {
    --  margin:0;
    --}
    --
    --/* API reference: heading for "Parameters", "See Also", etc.,
    --in details sections */
    --h5.jd-tagtitle {
    --  margin:0 0 .25em 0;
    --  font-size:1em;
    --}
    --
    --.jd-tagtable {
    --  margin:0;
    --}
    --
    --.jd-tagtable td,
    --.jd-tagtable th {
    --  border:none;
    --  background-color:#fff;
    --  vertical-align:top;
    --  font-weight:normal;
    --  padding:2px 10px;
    --}
    --
    --.jd-tagtable th {
    --  font-style:italic;
    --}
    --
    --#jd-content table h2 {
    --  background-color: #d6d6d6;
    --  font-size: 1.1em;
    --  margin:0 0 10px;
    --  padding:5px;
    --  left:0;
    --  width:auto;
    --}
    --
    --div.design-announce {
    --  border-top:1px solid #33B5E5;
    --  border-bottom:1px solid #33B5E5;
    --  padding:5px 10px 10px 55px;
    --  margin:2em 0;
    --  background:url('images/icon_design.png') 5px 13px no-repeat;
    --}
    --
    --div.design-announce p {
    --  margin: .5em 0 0 0;
    --}
    --
    --div.special {
    --  padding: .5em 1em 1em 1em;
    --  margin: 0 0 1em;
    --  background-color: #DAF3FC;
    --  border:1px solid #d3ecf5;
    --  border-radius:5px;
    --  -moz-border-radius:5px;
    --  -webkit-border-radius:5px;
    --}
    --
    --div.special p {
    --  margin: .5em 0 0 0;
    --}
    --
    --div.special ol {
    --  margin: 0;
    --}
    --
    --div.special ol li {
    --  margin: 0;
    --  padding: 0;
    --}
    --
    --#jd-content div.special h2,
    --#jd-content div.special h3 {
    --  color:#669999;
    --  font-size:1.2em;
    --  border:none;
    --  margin:0 0 .5em;
    --  padding:0;
    --}
    --
    --#jd-content div.special.reference h2,
    --#jd-content div.special.reference h3,
    --#jd-content div.special.reference h4 {
    --  color:#000;
    --  font-size:1em;
    --  border:none;
    --  font-weight:bold;
    --  margin:.5em 0;
    --  padding:0;
    --}
    --
    --p.note, div.note,
    --p.caution, div.caution,
    --p.warning, div.warning {
    --  margin: 1em;
    --  padding: 0 0 0 .5em;
    --  border-left: 4px solid;
    --}
    --
    --p.special-note,
    --div.special-note {
    --  background-color:#EBF3DB;
    --  padding:10px 20px;
    --  margin:0 0 1em;
    --}
    --
    --p.note,
    --div.note {
    -- border-color: #99aacc;
    --}
    --
    --p.warning,
    --div.warning {
    --  border-color: #aa0033;
    --}
    --
    --p.caution,
    --div.caution {
    --  border-color: #ffcf00;
    --}
    --
    --li .note,
    --li .caution,
    --li .warning {
    --  margin: .5em 0 0 0;
    --  padding: .2em .5em .2em .9em;
    --}
    --
    --/* Makes sure the first paragraph does not add top-whitespace within the box*/
    --li .note>p:first-child,
    --li .caution>p:first-child,
    --li .warning>p:first-child {
    --  margin-top:0;
    --  padding-top:0;
    --}
    --
    --dl.xml dt {
    --  font-variant:small-caps;
    --  font-size:1.2em;
    --}
    --
    --dl.xml dl {
    --  padding:0;
    --}
    --
    --dl.xml dl dt {
    --  font-variant:normal;
    --  font-size:1em;
    --}
    --
    --.listhead li {
    --  font-weight: bold;
    --}
    --
    --.listhead li *, /*ie*/.listhead li li {
    --  font-weight: normal;
    --}
    --
    --ol.no-style,
    --ul.no-style {
    --  list-style:none;
    --  padding-left:1em;
    --}
    --
    --.new,
    --.new-child {
    --  font-size: .78em;
    --  font-weight: bold;
    --  color: #ff3d3d;
    --  text-decoration: none;
    --  vertical-align:top;
    --  line-height:.9em;
    --  white-space:nowrap;
    --}
    --
    --.toggle-list.open .new-child {
    --  display:none;
    --}
    --
    --pre.classic {
    --  background-color:transparent;
    --  border:none;
    --  padding:0;
    --}
    --
    --p.img-caption {
    --  margin: -0.5em 0 1em 1em; /* matches default img left-margin */
    --}
    --
    --div.figure {
    --  float:right;
    --  clear:right;
    --  margin:1em 0 0 0;
    --  padding:0 0 0 3em;
    --  background-color:#fff;
    --  /* width must be defined w/ an inline style matching the image width */
    --}
    --
    --#jd-content
    --div.figure img {
    --  margin: 0 0 1em;
    --}
    --
    --div.figure p.img-caption {
    --  margin: -0.5em 0 1em 0;
    --}
    --
    --p.table-caption {
    --  margin: 0 0 0.5em 1em; /* matches default table left-margin */
    --}
    --
    --
    --/* toggle for misc content (such as long sample code) 
    --   see toggleContent() script in android-developer-docs.js */
    --.toggle-content.closed .toggle-content-toggleme {
    --  display:none;
    --}
    --
    --.toggle-content a[href="#"] {
    --  text-decoration:none;
    --  color:inherit;
    --}
    --
    --.toggle-content-toggleme {
    --  padding-bottom:1px; /* fixes animation bounce due to margins */
    --}
    --
    --#jd-content .toggle-content img.toggle-content-img {
    --  margin:0;
    --}
    --
    --
    --/* BEGIN quickview sidebar element styles */
    --
    --#qv-wrapper {
    --  float: right;
    --  width:310px; /* +35px padding */
    --  background-color:#fff;
    --  margin:-48px 0 2px 0;
    --  padding:0 0 20px 35px;
    --}
    --
    --#qv {
    --  background-color:#fff;
    --  border:4px solid #dee8f1;
    --  margin:0;
    --  padding:0 5px 5px;
    --  width:292px; /* +10px padding; +8px border */
    --  font-size:.9em;
    --}
    --
    --#qv ol {
    --  list-style:none;
    --  padding: 0;
    --}
    --
    --#qv ol ol{
    --  list-style:none;
    --  padding: 0 0 0 12px;
    --  margin:0;
    --}
    --
    --#qv ul {
    --  padding: 0 10px 0 2em;
    --}
    --
    --#qv li {
    --  padding: 0 10px 3px;
    --  line-height: 1.2em;
    --}
    --
    --#qv li li {
    --  padding: 3px 10px 0;
    --}
    --
    --#qv ul li {
    --  padding: 0 10px 0 0;
    --}
    --
    --#qv li.selected a {
    --  color:#555;
    --  text-decoration:none;
    --}
    --
    --#qv a,
    --#qv a code {
    --  color:#cc6600;
    --}
    --
    --#qv p {
    --  margin:8px 0 0;
    --  padding:0 10px;
    --}
    --
    --#jd-content #qv h2 {
    --  font-size:1.05em;
    --  font-weight:bold;
    --  margin:12px 0 .25em 0;
    --  padding:0 10px;
    --  background-color:transparent;
    --  color:#7BB026;
    --  border:none;
    --  left:0;
    --  z-index:1;
    --}
    --
    --#qv-extra #rule {
    --  padding: 0 10px;
    --  margin: 0;
    --}
    --
    --#qv-sub-rule {
    --  padding: 5px 15px 10px;
    --  margin: 0;
    --}
    --
    --#jd-content
    --#qv-sub-rule h2 {
    --  margin: 0 0 .5em 0;
    --}
    --
    --/* END quickview sidebar element styles */
    --
    --/* Begin sidebox sidebar element styles */
    --
    --.sidebox-wrapper {
    --  float:right;
    --  clear:right;
    --  width:310px; /* +35px padding */
    --  background-color:#fff;
    --  margin:0;
    --  padding:0 0 20px 35px;
    --}
    --
    --.sidebox {
    --  border-left:1px solid #dee8f1;
    --  background-color:#ffffee;
    --  margin:0;
    --  padding:8px 12px;
    --  font-size:0.9em;
    --  width:285px; /* +24px padding; +1px border */
    --}
    --
    --.sidebox p {
    --  margin-bottom: .75em;
    --}
    --
    --.sidebox ul {
    --  padding: 0 0 0 1.5em;
    --}
    --
    --.sidebox li ul {
    --  margin-top:0;
    --  margin-bottom:.1em;
    --}
    --
    --.sidebox li {
    --padding:0 0 0 0em;
    --}
    --
    --#jd-content .sidebox h2,
    --#jd-content .sidebox h3,
    --#jd-content .sidebox h4,
    --#jd-content .sidebox h5 {
    --  border:none;
    --  font-size:1em;
    --  margin:0;
    --  padding:0 0 8px;
    --  left:0;
    --  z-index:0;
    --}
    --
    --.sidebox hr {
    --  background-color:#ccc;
    --  border:none;
    --}
    --
    --/* End sidebox sidebar element styles */
    --
    --/* BEGIN developer training bar styles */
    --
    --div#tb-wrapper {
    --  float: right;
    --  clear:right;
    --  width:380px; /* +25px padding = 405 */
    --  background-color:#fff;
    --  margin:0 0 2px 0;
    --  padding:0 0 20px 25px;
    --}
    --
    --div#tb {
    --  margin:0;
    --  padding:0 15px;
    --  width:350px; /* +15px padding = 380 */
    --  font-size:.9em;
    --  background:#e9e9e9;
    --  border:1px solid #aaa;
    --  border-radius:5px;
    --  -moz-border-radius:5px;
    --  -webkit-border-radius:5px;
    --  overflow:auto;
    --}
    --
    --div#tb h2 {
    --  font-size:1.3em;
    --  font-weight:bold;
    --  margin:1em 0;
    --  padding:0;
    --  background-color:transparent;
    --  border:none;
    --  clear:both;
    --}
    --
    --div.download-box a.button {
    --  color: #069;
    --  font-size:1.1em;
    --  font-weight:bold;
    --  text-decoration:none;
    --  height:27px;
    --  line-height:27px;
    --  text-align:center;
    --  padding:5px 8px;
    --  background-color: #fff;
    --  border: 1px solid #aaa;
    --  -webkit-border-radius: 2px;
    --  -moz-border-radius: 2px;
    --  border-radius: 2px;
    --}
    --
    --div.download-box a.button:hover {
    --  border-color: #09C;
    --  background-color: #4CADCB;
    --  background-image: -webkit-gradient(linear,left top,left bottom,from(#5dbcd9),to(#4cadcb));
    --  background-image: -webkit-linear-gradient(top,#5dbcd9,#4cadcb);
    --  background-image: -moz-linear-gradient(top,#5dbcd9,#4cadcb);
    --  background-image: -ms-linear-gradient(top,#5dbcd9,#4cadcb);
    --  background-image: -o-linear-gradient(top,#5dbcd9,#4cadcb);
    --  background-image: linear-gradient(top,#5dbcd9,#4cadcb);
    --  filter: progid:DXImageTransform.Microsoft.gradient(startColorStr='#5dbcd9',EndColorStr='#4cadcb');
    --  color: #fff;
    --}
    --
    --div.download-box a.button:active {
    --  background-color: #1E799A;
    --  background-image: none;
    --  border-color: #30B7E6;
    --}
    --
    --div.download-box p.filename {
    --  font-size:0.85em;
    --  color:#888;
    --  margin:4px 0 1em 10px;
    --}
    --
    --/* End developer training bar */
    --
    --/* Training nav bar (previous/next) */
    --
    --div.training-nav-top {
    --  float: right;
    --  width:380px; /* +25px padding = 405 */
    --  margin:-58px 0 0 0;
    --  padding:0 0 20px 25px;
    --}
    --
    --div.training-nav-bottom {
    --  padding:1px; /* for weird FF bug (scrollbar appears) */
    --  margin:3em 0;
    --  overflow:auto;
    --}
    --
    --div.training-nav-button-next a,
    --div.training-nav-button-previous a {
    --  display:block;
    --  width:160px;
    --  height:55px;
    --  padding:4px 7px;
    --  border:1px solid #aaa;
    --  border-radius:5px;
    --  -moz-border-radius:5px;
    --  -webkit-border-radius:5px;
    --  text-decoration:none;
    --  font-weight:bold;
    --}
    --
    --div.training-nav-button-next a:hover,
    --div.training-nav-button-previous a:hover {
    --  border:1px solid #069; /* match link color */
    --}
    --
    --div.training-nav-button-next a:active,
    --div.training-nav-button-previous a:active {
    --  border:1px solid #f00; /* match link color */
    --}
    --  
    --div.training-nav-button-previous {
    --  float:left;
    --  text-align:left;
    --}
    --
    --div.training-nav-button-next {
    --  float:right;
    --  text-align:right;
    --}
    --
    --span.training-nav-button-title {
    --  display:block;
    --  font-size:.85em;
    --  font-weight:normal;
    --  line-height:1.3em;
    --  margin:.5em 0 0;
    --}
    --
    --/* End training nav bar */
    --
    --/* BEGIN image and caption styles (originally for UI Guidelines docs) */
    --
    --table.image-caption {
    --  padding:0;
    --  margin:.5em 0;
    --  border:0;
    --}
    --
    --td.image-caption-i {
    --  font-size:92%;
    --  padding:0 5px;
    --  margin:0;
    --  border:0;
    --}
    --
    --td.image-caption-i img {
    --  padding:0 1em;
    --  margin:0;
    --}
    --
    --.image-list {
    --  width:24px;
    --  text-align:center;
    --}
    --
    --td.image-caption-c {
    --  font-size:92%;
    --  padding:1em 2px 2px 2px;
    --  margin:0;
    --  border:0;
    --  width:350px;
    --}
    --
    --.grad-rule-top {
    --background-image:url(images/grad-rule-qv.png);
    --background-repeat:no-repeat;
    --padding-top:1em;
    --margin-top:0;
    --}
    --
    --.image-caption-nested {
    --  margin-top:0;
    --  padding:0 0 0 1em;
    --}
    --
    --.image-caption-nested td {
    --  padding:0 4px 2px 0;
    --  margin:0;
    --  border:0;
    --}
    --
    --/* END image and caption styles */
    --
    --/* table of contents */
    --
    --ol.toc {
    --  margin: 0 0 1em 0;
    --  padding: 0;
    --  list-style: none;
    --  font-size:95%;
    --}
    --
    --ol.toc li {
    --  font-weight: bold;
    --  margin: 0 0 .5em 1em;
    --  padding: 0;
    --}
    --
    --ol.toc li p {
    --  font-weight: normal;
    --}
    --
    --ol.toc li ol {
    --  margin: 0;
    --  padding: 0;
    --}
    --
    --ol.toc li li {
    --  padding: 0;
    --  margin: 0 0 0 1em;
    --  font-weight: normal;
    --  list-style: none;
    --}
    --
    --table ol.toc {
    --  margin-left: 0;
    --}
    --
    --.columns td {
    --  padding:0 5px;
    --  border:none;
    --}
    --
    --/* link table */
    --.jd-linktable {
    --  margin: 0 0 1em;
    --  border-bottom: 1px solid #888;
    --}
    --.jd-linktable th,
    --.jd-linktable td {
    --  padding: 3px 5px;
    --  vertical-align: top;
    --  text-align: left;
    --  border:none;
    --}
    --.jd-linktable tr {
    --  background-color: #fff;
    --}
    --.jd-linktable td {
    --  border-top: 1px solid #888;
    --  background-color: inherit;
    --}
    --.jd-linktable td  p {
    --  padding: 0 0 5px;
    --}
    --.jd-linktable .jd-linkcol {
    --}
    --.jd-linktable .jd-descrcol {
    --}
    --.jd-linktable .jd-typecol {
    --  text-align:right;
    --}
    --.jd-linktable .jd-valcol {
    --}
    --.jd-linktable .jd-commentrow {
    --  border-top:none;
    --  padding-left:25px;
    --}
    --.jd-deprecated-warning {
    --  margin-top: 0;
    --  margin-bottom: 10px;
    --}
    --
    --tr.alt-color {
    --  background-color: #f6f6f6;
    --}
    --
    --/* expando trigger */
    --#jd-content .jd-expando-trigger-img {
    --  margin:0;
    --}
    --
    --/* jd-expando */
    --.jd-inheritedlinks {
    --  padding:0 0 0 13px
    --}
    --
    --/* SDK PAGE */
    --table.download tr {
    --  background-color:#d9d9d9;
    --}
    --
    --table.download tr.alt-color {
    --  background-color:#ededed;
    --}
    --
    --table.download td,
    --table.download th {
    --  border:2px solid #fff;
    --  padding:10px 5px;
    --}
    --
    --table.download th {
    --  background-color:#6d8293;
    --  color:#fff;
    --}
    --
    --/* INLAY 180 COPY and 240PX EXTENSION */
    --/* modified to 43px so that all browsers eliminate the package panel h-scroll */
    --.g-tpl-240 .g-unit,
    --.g-unit .g-tpl-240 .g-unit,
    --.g-unit .g-unit .g-tpl-240 .g-unit {
    --  display: block;
    --  margin: 0 0 0 243px;
    --  width: auto;
    --  float: none;
    --}
    --.g-unit .g-unit .g-tpl-240 .g-first,
    --.g-unit .g-tpl-240 .g-first,
    --.g-tpl-240 .g-first {
    --  display: block;
    --  margin: 0;
    --  width: 243px;
    --  float: left;
    --}
    --/* 240px alt */
    --.g-tpl-240-alt .g-unit,
    --.g-unit .g-tpl-240-alt .g-unit,
    --.g-unit .g-unit .g-tpl-240-alt .g-unit {
    --  display: block;
    --  margin: 0 243px 0 0;
    --  width: auto;
    --  float: none;
    --}
    --.g-unit .g-unit .g-tpl-240-alt .g-first,
    --.g-unit .g-tpl-240-alt .g-first,
    --.g-tpl-240-alt .g-first {
    --  display: block;
    --  margin: 0;
    --  width: 243px;
    --  float: right;
    --}
    --
    --/* 200px */
    --.g-tpl-200 .g-unit,
    --.g-unit .g-tpl-200 .g-unit,
    --.g-unit .g-unit .g-tpl-200 .g-unit {
    --  display: block;
    --  margin: 0 0 0 200px;
    --  width: auto;
    --  float: none;
    --}
    --.g-unit .g-unit .g-tpl-200 .g-first,
    --.g-unit .g-tpl-200 .g-first,
    --.g-tpl-200 .g-first {
    --  display: block;
    --  margin: 0;
    --  width: 200px;
    --  float: left;
    --}
    --/* 200px alt */
    --.g-tpl-200-alt .g-unit,
    --.g-unit .g-tpl-200-alt .g-unit,
    --.g-unit .g-unit .g-tpl-200-alt .g-unit {
    --  display: block;
    --  margin: 0 200px 0 0;
    --  width: auto;
    --  float: none;
    --}
    --.g-unit .g-unit .g-tpl-200-alt .g-first,
    --.g-unit .g-tpl-200-alt .g-first,
    --.g-tpl-200-alt .g-first {
    --  display: block;
    --  margin: 0;
    --  width: 200px;
    --  float: right;
    --}
    --
    --/* 190px */
    --.g-tpl-190 .g-unit,
    --.g-unit .g-tpl-190 .g-unit,
    --.g-unit .g-unit .g-tpl-190 .g-unit {
    --  display: block;
    --  margin: 0 0 0 190px;
    --  width: auto;
    --  float: none;
    --}
    --.g-unit .g-unit .g-tpl-190 .g-first,
    --.g-unit .g-tpl-190 .g-first,
    --.g-tpl-190 .g-first {
    --  display: block;
    --  margin: 0;
    --  width: 190px;
    --  float: left;
    --}
    --/* 190px alt */
    --.g-tpl-190-alt .g-unit,
    --.g-unit .g-tpl-190-alt .g-unit,
    --.g-unit .g-unit .g-tpl-190-alt .g-unit {
    --  display: block;
    --  margin: 0 190px 0 0;
    --  width: auto;
    --  float: none;
    --}
    --.g-unit .g-unit .g-tpl-190-alt .g-first,
    --.g-unit .g-tpl-190-alt .g-first,
    --.g-tpl-190-alt .g-first {
    --  display: block;
    --  margin: 0;
    --  width: 190px;
    --  float: right;
    --}
    --
    --/* 180px */
    --.g-tpl-180 .g-unit,
    --.g-unit .g-tpl-180 .g-unit,
    --.g-unit .g-unit .g-tpl-180 .g-unit {
    --  display: block;
    --  margin: 0 0 0 180px;
    --  width: auto;
    --  float: none;
    --}
    --.g-unit .g-unit .g-tpl-180 .g-first,
    --.g-unit .g-tpl-180 .g-first,
    --.g-tpl-180 .g-first {
    --  display: block;
    --  margin: 0;
    --  width: 180px;
    --  float: left;
    --}
    --/* 180px alt */
    --.g-tpl-180-alt .g-unit,
    --.g-unit .g-tpl-180-alt .g-unit,
    --.g-unit .g-unit .g-tpl-180-alt .g-unit {
    --  display: block;
    --  margin: 0 180px 0 0;
    --  width: auto;
    --  float: none;
    --}
    --.g-unit .g-unit .g-tpl-180-alt .g-first,
    --.g-unit .g-tpl-180-alt .g-first,
    --.g-tpl-180-alt .g-first {
    --  display: block;
    --  margin: 0;
    --  width: 180px;
    --  float: right;
    --}
    --
    --
    --/* JQUERY RESIZABLE STYLES */
    --.ui-resizable { position: relative; }
    --.ui-resizable-handle { position: absolute; display: none; font-size: 0.1px; z-index:1; }
    --.ui-resizable .ui-resizable-handle { display: block; }
    --body .ui-resizable-disabled .ui-resizable-handle { display: none; }
    --body .ui-resizable-autohide .ui-resizable-handle { display: none; }
    --.ui-resizable-s { cursor: s-resize; height: 6px; width: 100%; bottom: 0px; left: 0px;
    --  background: transparent url("images/resizable-s2.gif") repeat scroll center top; }
    --.ui-resizable-e { cursor: e-resize; width: 6px; right: 0px; top: 0px; height: 100%;
    --  background: transparent url("images/resizable-e2.gif") repeat scroll right center; }
    --
    --@media print {
    --
    --  body {
    --    overflow:visible;
    --  }
    --
    --  #header {
    --    height:60px;
    --  }
    --
    --  #headerLeft {
    --    padding:0;
    --  }
    --
    --  #header-tabs,
    --  #headerRight,
    --  #side-nav,
    --  #api-info-block {
    --    display:none;
    --  }
    --
    --  #body-content {
    --    position:inherit;
    --  }
    --
    --  #doc-content {
    --    margin-left:0 !important;
    --    height:auto !important;
    --    width:auto !important;
    --    overflow:inherit;
    --    display:inline;
    --  }
    --
    --  #jd-header {
    --    padding:10px 0;
    --  }
    --
    --  #jd-content {
    --    padding:15px 0 0;
    --  }
    --
    --  #footer {
    --    float:none;
    --    margin:2em 0 0;
    --  }
    --
    --  h4.jd-details-title {
    --    border-bottom:1px solid #666;
    --  }
    --
    --  pre {
    --    /* these allow lines to break (if there's a white space) */
    --    overflow: visible;
    --    text-wrap: unrestricted;
    --    white-space: -moz-pre-wrap; /* Moz */
    --    white-space: -pre-wrap; /* Opera 4-6 */
    --    white-space: -o-pre-wrap; /* Opera 7 */
    --    white-space: pre-wrap; /* CSS3  */
    --    word-wrap: break-word; /* IE 5.5+ */
    --  }
    --
    --  h1, h2, h3, h4, h5, h6 {
    --    page-break-after: avoid;
    --  }
    --
    --  table, img {
    --    page-break-inside: avoid;
    --  }
    --}
    -diff --git a/tools/droiddoc/templates-sdk-dev/assets/css/default.css b/tools/droiddoc/templates-sdk-dev/assets/css/default.css
    -deleted file mode 100644
    -index e422d75..0000000
    ---- a/tools/droiddoc/templates-sdk-dev/assets/css/default.css
    -+++ /dev/null
    -@@ -1,10452 +0,0 @@
    --/* color definitions */
    --/* 16 column layout */
    --/* clearfix idiom */
    --/* common mixins */
    --/* page layout + top-level styles */
    --::selection {
    --  background-color: #0099cc;
    --  color: #fff; }
    --::-webkit-selection {
    --  background-color: #0099cc;
    --  color: #fff; }
    --::-moz-selection {
    --  background-color: #0099cc;
    --  color: #fff; }
    --
    --html, body {
    --  height: 100%;
    --  margin: 0;
    --  padding: 0;
    --  background-color: #fff;
    --  -webkit-font-smoothing: antialiased;
    --  -moz-osx-font-smoothing: grayscale;
    --  /* prevent subpixel antialiasing, which thickens the text */
    --  /* text-rendering: optimizeLegibility; */
    --  /* turned off ligatures due to bug 5945455 */ }
    --
    --body {
    --  color: #515151;
    --  color: rgba(0, 0, 0, .68);
    --  font: 14px/24px Roboto, sans-serif;
    --  font-weight: 400;
    --  letter-spacing:.1;
    --  padding: 0 20px;
    --}
    --
    --@media (max-width: 719px) {
    --  html {
    --    /* Disable accidental horizontal overflow. */
    --    overflow-x: hidden;
    --  }
    --
    --  body {
    --    padding-left: 10px;
    --    padding-right: 10px;
    --  }
    --}
    --
    --#page-container {
    --  width: 940px;
    --  margin: 0 40px; }
    --
    --#page-header {
    --  height: 80px;
    --  margin-bottom: 20px;
    --  font-size: 48px;
    --  line-height: 48px;
    --  font-weight: 100;
    --  padding-left: 10px; }
    --  #page-header a {
    --    display: block;
    --    position: relative;
    --    top: 20px;
    --    text-decoration: none;
    --    color: #555555 !important; }
    --
    --#main-row {
    --  display: inline-block; }
    --  #main-row:after {
    --    content: ".";
    --    display: block;
    --    height: 0;
    --    clear: both;
    --    visibility: hidden; }
    --  * html #main-row {
    --    height: 1px; }
    --
    --#page-footer {
    --  margin-left: 190px;
    --  margin-top: 80px;
    --  color: #999999;
    --  padding-bottom: 40px;
    --  font-size: 12px;
    --  line-height: 15px; }
    --  #page-footer a {
    --    color: #777777; }
    --  #page-footer #copyright {
    --    margin-bottom: 10px; }
    --
    --.hide-text {
    --  position: absolute;
    --  text-indent: -9999px;
    --}
    --
    --#nav-container {
    --  width: 160px;
    --  min-height: 10px;
    --  margin-right: 20px;
    --  float: left; }
    --
    --#devdoc-nav h2 {
    --  border:0;
    --}
    --
    --#devdoc-nav.fixed {
    --  position: fixed;
    --  margin:0;
    --  top: 84px; /* sticky-header height + 20px gutter */
    --}
    --
    --.dac-devdoc-toggle {
    --  cursor: pointer;
    --  padding: 8px 0;
    --}
    --
    --.scroll-pane {
    --  /* Match height of fixed parent. */
    --  height: 100%;
    --}
    --
    --#content {
    --  width: 760px;
    --  float: left; }
    --
    --
    --/***** PREVIOUSLY style.css ******************/
    --/* This should be close to the top, so it is easier to override. */
    --[dir='rtl'] {
    --  direction: rtl;
    --}
    --html {
    --  line-height: 20px;
    --}
    --pre, table, input, textarea, code {
    --  font-size: 1em;
    --}
    --address, abbr, cite {
    --  font-style: normal;
    --}
    --[dir='rtl'] th {
    --  text-align: right;
    --}
    --html[lang^=ja] blockquote, html[lang^=ja] q, html[lang^=ko] blockquote, html[lang^=ko] q,
    --html[lang^=zh] blockquote, html[lang^=zh] q {
    --  font-style: normal;
    --}
    --q {
    --  font-style: italic;
    --}
    --fieldset, iframe, img {
    --  border: 0;
    --}
    --img {
    --  border: none;
    --  -ms-interpolation-mode: bicubic;
    --  max-width: 100%;
    --  vertical-align: middle;
    --}
    --
    --video {
    --  cursor: pointer;
    --  margin-bottom: 10px; /* same as img */
    --  max-width: 100%;
    --  object-fit: cover;
    --}
    --
    --.video-wrapper {
    --  line-height: 0;
    --  margin-bottom: 10px; /* same as img */
    --  position: relative;
    --}
    --
    --.video-wrapper video {
    --  margin:0;
    --}
    --
    --.video-wrapper:before {
    --  background: rgba(0, 0, 0, 0.5) url(//material-design.storage.googleapis.com/images/play.svg) no-repeat center center;
    --  background-size: 72px 72px;
    --  bottom: 0;
    --  content: "";
    --  left: 0;
    --  position: absolute;
    --  right: 0;
    --  top: 0;
    --  transition: opacity .2s;
    --}
    --
    --.video-wrapper:hover:before {
    --  opacity: .7;
    --}
    --
    --.video-wrapper.playing:before {
    --  opacity: 0;
    --}
    --
    --q {
    --  quotes: none;
    --}
    --sup, sub {
    --  font-size: 11px;
    --  line-height: 0;
    --}
    --
    --table, fieldset {
    --  margin: 0;
    --}
    --/* Biggest type */
    --.display-1 {
    --  font-size: 56px;
    --  line-height: 68px;
    --}
    --@media (max-width: 719px) {
    --  .display-1 {
    --    font-size: 44px;
    --    line-height: 56px;
    --  }
    --}
    --h1, h2, h3 {
    --  color: #212121;
    --  color: rgba(0, 0, 0, .87);
    --}
    --h1 {
    --  font-size: 44px;
    --  line-height: 56px;
    --  font-weight: 300;
    --  margin: 0;
    --  padding: 24px 0 12px;
    --}
    --h1.short {
    --  padding-right:320px;
    --}
    --@media (max-width: 719px) {
    --  h1 {
    --    font-size: 36px;
    --    line-height: 48px;
    --  }
    --}
    --h2 {
    --  clear: left;
    --  font-size: 28px;
    --  font-weight: 400;
    --  line-height: 32px;
    --  margin: 0;
    --  padding: 12px 0 16px;
    --}
    --h3 {
    --  font-size: 24px;
    --  line-height: 32px;
    --  font-weight: 400;
    --  margin: 0;
    --  padding: 8px 0 12px;
    --}
    --h4 {
    --  font-size: 18px;
    --  line-height: 24px;
    --  margin: 0;
    --  padding: 4px 0 8px;
    --  font-weight: 500;
    --}
    --h5, h6 {
    --  font-size: 16px;
    --  line-height: 24px;
    --  margin: 0;
    --  padding: 4px 0 8px;
    --}
    --th>h3 {
    --  font-size:inherit;
    --  line-height:inherit;
    --  font-weight:inherit;
    --  margin:0;
    --  padding:0;
    --  color:inherit;
    --}
    --hr { /* applied to the bottom of h2 elements */
    --  height: 1px;
    --  margin: 7px 0 12px;
    --  border: 0;
    --  background: rgba(0, 0, 0, 0.1);
    --}
    --h2[id], h3[id], h4[id], h5[id], h6[id] {
    --  margin-top: -64px;
    --  border-top: 64px solid transparent;
    --  -webkit-background-clip: padding-box;
    --  -moz-background-clip: padding;
    --  background-clip: padding-box;
    --}
    --p, pre, table, form {
    --  margin: 0 0 12px;
    --}
    --small {
    --  font-size: 11.5px;
    --  color: #000;
    --}
    --ul, ol {
    --  margin: 0 0 15px 20px;
    --  padding: 0;
    --}
    --[dir='rtl'] ul, [dir='rtl'] ol {
    --  margin: 10px 30px 10px 10px;
    --}
    --ul ul, ul ol, ol ul, ol ol {
    --  margin-bottom: 0;
    --  margin-top: 0;
    --}
    --li {
    --  margin: 0 0 12px;
    --}
    --dt {
    --  margin: 24px 0 12px;
    --}
    --dd {
    --  margin:0 0 10px 40px;
    --}
    --dd p,
    --dd pre,
    --dd ul,
    --dd ol,
    --dd dl {
    --  margin-top:10px;
    --}
    --li p,
    --li pre,
    --li ul,
    --li ol,
    --li dl,
    --#body-content li img {
    --  margin-top: 6px;
    --  margin-bottom: 6px;
    --}
    --dl dd dl:first-child {
    --  margin-top: 0;
    --}
    --pre strong, pre b, a strong, a b, a code {
    --  color: inherit;
    --}
    --pre, code {
    --  color: #060;
    --  font: 13px/18px Consolas, "Liberation Mono", Menlo, Monaco, Courier, monospace;
    --  -webkit-font-smoothing: subpixel-antialiased;
    --  -moz-osx-font-smoothing: auto;
    --}
    --legend {
    --  display: none;
    --}
    --a, .link-color {
    --  color: #039BE5;
    --  text-decoration: none;
    --}
    --a:focus, a:hover {
    --  color: rgba(3, 155, 229, .7);
    --  text-decoration: none;
    --}
    --a.white {
    --  color: #fff;
    --  text-decoration:underline;
    --}
    --a.white:hover, a.white:active {
    --  color: #ccc;
    --}
    --strong, b {
    --  font-weight: bold;
    --}
    --table {
    --  border-collapse: collapse;
    --  border-spacing: 0;
    --  border:0;
    --  margin: .5em 1em 1em 0;
    --  width:100%; /* consistent table widths; within IE's quirks */
    --  background-color:#f7f7f7;
    --}
    --th, td {
    --  padding: 4px 12px;
    --  vertical-align: top;
    --  text-align: left;
    --}
    --td {
    --  background-color:inherit;
    --  border:solid 1px #DDD;
    --}
    --td *:last-child {
    --  margin-bottom:0;
    --}
    --th {
    --  background-color: #999;
    --  color: #fff;
    --  border:solid 1px #DDD;
    --  font-weight: normal;
    --}
    --tr.alt th {
    --  color:inherit;
    --  background-color: #e0e0e0;
    --}
    --tr:first-of-type th:first-of-type:empty {
    --  visibility: hidden;
    --}
    --
    --a.external-link {
    --  background:url('../images/styles/open_new_page.png') no-repeat 100% 50%;
    --  padding-right:16px;
    --}
    --
    --#body-content img {
    --  margin-bottom:12px;
    --}
    --
    --#body-content p>img {
    --  margin-bottom:0;
    --}
    --
    --#body-content img.inline-icon {
    --  vertical-align:sub;
    --  margin:0;
    --  height:16px;
    --}
    --
    --em {
    --  font-style: italic; }
    --
    --acronym,
    --.tooltip-link {
    --  border-bottom: 1px dotted #555555;
    --  cursor: help; }
    --
    --acronym:hover,
    --.tooltip-link:hover {
    --  color: #7aa1b0;
    --  border-bottom-color: #7aa1b0; }
    --
    --img.with-shadow,
    --video.with-shadow {
    --  box-shadow: 0 2px 4px rgba(0, 0, 0, 0.25); }
    --
    --/* disclosures mixin */
    --/* content layout */
    --/* This grid is deprecated in favor of .cols and .col-X */
    --.layout-content-row {
    --  display: inline-block;
    --  margin-bottom: 10px; }
    --  * html .layout-content-row {
    --    height: 1px; }
    --
    --.layout-content-col {
    --  float: left;
    --  margin-left: 20px; }
    --  .layout-content-col:first-child {
    --    margin-left: 0; }
    --  .layout-content-col h3,
    --  .layout-content-col h4 {
    --    padding-top:0; }
    --
    --.layout-content-col.span-1 {
    --  width: 40px; }
    --
    --.layout-content-col.span-2 {
    --  width: 100px; }
    --
    --.layout-content-col.span-3 {
    --  width: 160px; }
    --
    --.layout-content-col.span-4 {
    --  width: 220px; }
    --
    --.layout-content-col.span-5 {
    --  width: 280px; }
    --
    --.layout-content-col.span-6 {
    --  width: 340px; }
    --
    --.layout-content-col.span-7 {
    --  width: 400px; }
    --
    --.layout-content-col.span-8 {
    --  width: 460px; }
    --
    --.layout-content-col.span-9 {
    --  width: 520px; }
    --
    --.layout-content-col.span-10 {
    --  width: 580px; }
    --
    --.layout-content-col.span-11 {
    --  width: 640px; }
    --
    --.layout-content-col.span-12 {
    --  width: 700px; }
    --
    --.layout-content-col.span-13 {
    --  width: 760px; }
    --
    --.vspace.size-1 {
    --  height: 10px; }
    --
    --.vspace.size-2 {
    --  height: 20px; }
    --
    --.vspace.size-3 {
    --  height: 30px; }
    --
    --.vspace.size-4 {
    --  height: 40px; }
    --
    --.vspace.size-5 {
    --  height: 50px; }
    --
    --.vspace.size-6 {
    --  height: 60px; }
    --
    --.vspace.size-7 {
    --  height: 70px; }
    --
    --.vspace.size-8 {
    --  height: 80px; }
    --
    --.vspace.size-9 {
    --  height: 90px; }
    --
    --.vspace.size-10 {
    --  height: 100px; }
    --
    --.vspace.size-11 {
    --  height: 110px; }
    --
    --.vspace.size-12 {
    --  height: 120px; }
    --
    --.vspace.size-13 {
    --  height: 130px; }
    --
    --.vspace.size-14 {
    --  height: 140px; }
    --
    --.vspace.size-15 {
    --  height: 150px; }
    --
    --.vspace.size-16 {
    --  height: 160px; }
    --
    --.new,
    --.new-child {
    --  font-size: .78em;
    --  font-weight: bold;
    --  color: #ff3d3d;
    --  vertical-align:top;
    --  white-space:nowrap;
    --}
    --
    --/* content header */
    --.content-header {
    --  position: relative;
    --}
    --.content-header:before,
    --.content-header:after {
    --  content: '';
    --  display: table;
    --  /* Clear heading margins, to make absolutely positioned nav a bit more predictable. */
    --}
    --.content-header.just-links {
    --  margin-bottom:0;
    --  padding-bottom:0;}
    --
    --.content-footer {
    --  margin-top: 10px;
    --  padding-top:10px;
    --  width:100%; }
    --
    --.content-footer .col-9 {
    --  margin-left:0;
    --}
    --.content-footer .col-4 {
    --  margin-right:0;
    --}
    --.content-footer.wrap {
    --  max-width:940px;
    --}
    --.content-footer .plus-container {
    --  margin:5px 0 0;
    --  text-align:right;
    --  float:right;
    --}
    --
    --a.back-link {
    --    text-decoration: none;
    --    text-transform: uppercase;
    --}
    --
    --.content-header .paging-links {
    --  position: absolute;
    --  right: 0;
    --  top: 8px;
    --  width: 220px;
    --}
    --.paging-links {
    --  position: relative;
    --  min-height:30px; }
    --  .paging-links a,
    --  .training-nav-top a {
    --    text-decoration: none; }
    --    .training-nav-top .prev-page-link:before,
    --    a.back-link:before {
    --      content: '';
    --      background: transparent url(../images/styles/disclosure_left.png) no-repeat scroll 50% 50%;
    --      width: 10px;
    --      height: 10px;
    --      display: inline-block;
    --      margin-right: 5px; }
    --    .training-nav-top .next-page-link:after,
    --    .training-nav-top .start-class-link:after,
    --    .training-nav-top .start-course-link:after,
    --    .go-link:after {
    --      content: '';
    --      background: transparent url(../images/styles/disclosure_right.png) no-repeat scroll 50% 50%;
    --      width: 10px;
    --      height: 10px;
    --      display: inline-block;
    --      margin-left: 5px; }
    --    .prev-page-link.inline:before {
    --      content: none; }
    --    .next-page-link.inline:after {
    --      content: none; }
    --
    --  .content-footer {
    --    left:0;
    --  }
    --
    --  .training-nav-top a {
    --    border-bottom:0;
    --    box-sizing: border-box;
    --    color: inherit;
    --    display:block;
    --    float:left;
    --    padding:10px 0;
    --    line-height:30px;
    --    text-align:center;
    --    width: 50%;
    --  }
    --
    --  .training-nav-top a.prev-page-link {
    --    padding-left: 15px;
    --    text-align: left;
    --  }
    --
    --  .training-nav-top a.next-page-link {
    --    padding-right: 15px;
    --    text-align: right;
    --  }
    --
    --  .paging-links a.disabled,
    --  .training-nav-top a.disabled,
    --  .content-footer a.disabled {
    --    color:#bbb;
    --  }
    --
    --  .paging-links a.disabled:hover,
    --  .training-nav-top a.disabled:hover,
    --  .content-footer a.disabled:hover {
    --    cursor:default;
    --    color:#bbb !important;
    --  }
    --
    --  .training-nav-top a.start-class-link,
    --  .training-nav-top a.start-course-link {
    --    width:100%;
    --  }
    --
    --  /* list of classes on course landing page */
    --  ol.class-list {
    --    counter-reset: class;
    --    list-style: none;
    --    margin: 60px 0 0;
    --  }
    --  ol.class-list>li {
    --    box-shadow: 0px 2px 5px 0 rgba(0, 0, 0, 0.26);
    --    margin: 0 0 20px;
    --    overflow: hidden;
    --  }
    --  ol.class-list .title {
    --    background: #00bcd4;
    --    color: #fff;
    --    display: block;
    --    font-size: 20px;
    --    font-weight: 500;
    --    height: 32px;
    --    padding: 52px 16px 12px;
    --    position: relative;
    --  }
    --  ol.class-list .title:before {
    --    border-bottom: 1px solid white;
    --    box-sizing: border-box;
    --    /* Disable the numbers for now, since vert few classes need to be taken in order. */
    --    /* content: counter(class); */
    --    counter-increment: class;
    --    height: 40px;
    --    left: 0;
    --    padding: 10px 1px 0 5px;
    --    position: absolute;
    --    top: 0;
    --    text-align: right;
    --    min-width: 30px;
    --  }
    --  ol.class-list .title h2 {
    --    color: currentColor;
    --    font-size: inherit;
    --    font-weight: inherit;
    --    padding:0 0 10px;
    --    display:block;
    --    float:left;
    --    width:675px;
    --  }
    --  ol.class-list .title span {
    --    display:none;
    --    float:left;
    --    font-size:18px;
    --    font-weight:bold;
    --    background: transparent url(../images/styles/disclosure_right.png) no-repeat scroll 50% 50%;
    --    width: 10px;
    --    height: 32px;
    --  }
    --
    --  ol.class-list .description {
    --    box-sizing: border-box;
    --    float:left;
    --    display:block;
    --    margin:0;
    --    padding: 16px 10px 16px 16px;
    --    width: 50%;
    --  }
    --  ol.class-list .description.article {
    --    width: 550px;
    --  }
    --  ol.class-list ol {
    --    box-sizing: border-box;
    --    float: left;
    --    list-style: none;
    --    margin: 0;
    --    padding: 16px 16px 16px 10px;
    --    width: 50%;
    --  }
    --  ol.class-list .lessons li {
    --    margin: 0 0 6px;
    --    line-height: 16px;
    --  }
    --
    --  /* Class colors */
    --  ol.class-list li:nth-child(10n+1) .title {
    --    background: #00bcd4;
    --  }
    --  ol.class-list li:nth-child(10n+2) .title {
    --    background: #4db6ac;
    --  }
    --  ol.class-list li:nth-child(10n+3) .title {
    --    background: #66bb6a;
    --  }
    --  ol.class-list li:nth-child(10n+4) .title {
    --    background: #7cb342;
    --  }
    --  ol.class-list li:nth-child(10n+5) .title {
    --    background: #afb42b;
    --  }
    --  ol.class-list li:nth-child(10n+6) .title {
    --    background: #ffb300;
    --  }
    --  ol.class-list li:nth-child(10n+7) .title {
    --    background: #ff7043;
    --  }
    --  ol.class-list li:nth-child(10n+8) .title {
    --    background: #ec407a;
    --  }
    --  ol.class-list li:nth-child(10n+9) .title {
    --    background: #ab47bc;
    --  }
    --  ol.class-list li:nth-child(10n+10) .title {
    --    background: #7e57c2;
    --  }
    --
    --  @media (max-width: 719px) {
    --    ol.class-list ol,
    --    ol.class-list .description {
    --      float: none;
    --      margin: 16px;
    --      padding: 0;
    --      width: auto;
    --    }
    --  }
    --
    --
    --  .hide {
    --    display:none !important;
    --  }
    --
    --
    --
    --  /* inner-doc tabs w/ title */
    --
    --div#title-tabs-wrapper {
    --  border-bottom:1px solid #ccc;
    --  margin:20px 0 30px;
    --}
    --h1.with-title-tabs {
    --  display:inline-block;
    --  margin-bottom: -1px;
    --  padding:0 60px 0 0;
    --  border-bottom:1px solid #F9F9F9;
    --}
    --ul#title-tabs {
    --  list-style:none;
    --  padding:0;
    --  height:29px;
    --  margin:0;
    --  font-size:16px;
    --  line-height:26px;
    --  display:inline-block;
    --  vertical-align:bottom;
    --}
    --ul#title-tabs li {
    --  display:block;
    --  float:left;
    --  margin-right:40px;
    --  border-bottom: 3px solid transparent;
    --}
    --ul#title-tabs li.selected {
    --  border-bottom: 3px solid #93C;
    --}
    --ul#title-tabs li a {
    --  color:#333;
    --}
    --ul#title-tabs li a:hover,
    --ul#title-tabs li a:active {
    --  color:#039BE5 !important;
    --}
    --
    --
    --
    --/* content body */
    --@-webkit-keyframes glowheader {
    --  from {
    --    background-color: #33b5e5;
    --    color: #000;
    --    border-bottom-color: #000; }
    --
    --  to {
    --    background-color: transparent;
    --    color: #33b5e5;
    --    border-bottom-color: #33b5e5; } }
    --
    --@-moz-keyframes glowheader {
    --  from {
    --    background-color: #33b5e5;
    --    color: #000;
    --    border-bottom-color: #000; }
    --
    --  to {
    --    background-color: transparent;
    --    color: #33b5e5;
    --    border-bottom-color: #33b5e5; } }
    --
    --@keyframes glowheader {
    --  from {
    --    background-color: #33b5e5;
    --    color: #000;
    --    border-bottom-color: #000; }
    --
    --  to {
    --    background-color: transparent;
    --    color: #33b5e5;
    --    border-bottom-color: #33b5e5; } }
    --
    --h1:target,
    --h2:target,
    --h3:target {
    --    -webkit-animation-name: glowheader;
    --    -moz-animation-name: glowheader;
    --    animation-name: glowheader;
    --    -webkit-animation-duration: 0.7s;
    --    -moz-animation-duration: 0.7s;
    --    animation-duration: 0.7s;
    --    -webkit-animation-timing-function: ease-out;
    --    -moz-animation-timing-function: ease-out;
    --    animation-timing-function: ease-out; }
    --
    --.design ol h4 {
    --  padding-bottom:0;
    --}
    --.design ol {
    --  counter-reset: item; }
    --  .design ol>li {
    --    font-size: 14px;
    --    line-height: 20px;
    --    list-style-type: none;
    --    position: relative; }
    --    .design ol>li:before {
    --      content: counter(item) ". ";
    --      counter-increment: item;
    --      position: absolute;
    --      left: -20px;
    --      top: 0; }
    --    .design ol li.value-1:before {
    --      content: "1. "; }
    --    .design ol li.value-2:before {
    --      content: "2. "; }
    --    .design ol li.value-3:before {
    --      content: "3. "; }
    --    .design ol li.value-4:before {
    --      content: "4. "; }
    --    .design ol li.value-5:before {
    --      content: "5. "; }
    --    .design ol li.value-6:before {
    --      content: "6. "; }
    --    .design ol li.value-7:before {
    --      content: "7. "; }
    --    .design ol li.value-8:before {
    --      content: "8. "; }
    --    .design ol li.value-9:before {
    --      content: "9. "; }
    --    .design ol li.value-10:before {
    --      content: "10. "; }
    --.design .with-callouts ol>li {
    --  list-style-position: inside;
    --  margin-left: 0; }
    --  .design .with-callouts ol>li:before {
    --    display: inline;
    --    left: -20px;
    --    float: left;
    --    width: 17px;
    --    color: #33b5e5;
    --    font-weight: 500; }
    --.design .with-callouts ul>li {
    --  list-style-position: outside; }
    --
    --/* special list items */
    --li.no-bullet {
    --  list-style-type: none !important; }
    --li.no-bullet *{
    --  margin:0; }
    --
    --.design li.with-icon {
    --  position: relative;
    --  margin-left: 20px;
    --  min-height: 30px; }
    --  .design li.with-icon p {
    --    margin-left: 0 !important; }
    --  .design li.with-icon:before {
    --    position: absolute;
    --    left: -40px;
    --    top: 0;
    --    content: '';
    --    width: 30px;
    --    height: 30px; }
    --  .design li.with-icon.tablet:before {
    --    background-image: url(../images/styles/ico_phone_tablet.png); }
    --  .design li.with-icon.web:before {
    --    background-image: url(../images/styles/ico_web.png); }
    --  .design li.with-icon.action:before {
    --    background-image: url(../images/styles/ico_action.png); }
    --  .design li.with-icon.use:before {
    --    background-image: url(../images/styles/ico_use.png); }
    --
    --/* video  containers */
    --.framed-galaxynexus-land-span-13 {
    --  background: transparent url(../images/styles/device_galaxynexus_blank_land_span13.png) no-repeat
    --scroll top left;
    --  padding: 42px 122px 62px 126px;
    --  overflow: hidden; }
    --  .framed-galaxynexus-land-span-13, .framed-galaxynexus-land-span-13 video,
    --.framed-galaxynexus-land-span-13 img {
    --    width: 512px;
    --    height: 286px; }
    --
    --
    --.framed-galaxynexus-land-span-8{
    --  background: transparent url(../images/styles/device_galaxynexus_blank_land_span8.png) no-repeat
    --scroll top left;
    --  padding: 26px 68px 38px 72px;
    --  overflow: hidden; }
    --  .framed-galaxynexus-land-span-8, .framed-galaxynexus-land-span-8 video,
    --.framed-galaxynexus-land-span-8 img {
    --    width: 320px;
    --    height: 180px; }
    --
    --.framed-galaxynexus-port-span-9 {
    --  background: transparent url(../images/styles/device_galaxynexus_blank_port_span9.png) no-repeat
    --scroll top left;
    --  padding: 95px 122px 107px 124px;
    --  overflow: hidden; }
    --  .framed-galaxynexus-port-span-9, .framed-galaxynexus-port-span-9 video,
    --.framed-galaxynexus-port-span-9 img {
    --    width: 274px;
    --    height: 488px; }
    --
    --.framed-galaxynexus-port-span-5 {
    --  background: transparent url(../images/styles/device_galaxynexus_blank_port_span5.png) no-repeat
    --scroll top left;
    --  padding: 75px 31px 76px 33px;
    --  overflow: hidden; }
    --  .framed-galaxynexus-port-span-5, .framed-galaxynexus-port-span-5 video,
    --.framed-galaxynexus-port-span-5 img {
    --    width: 216px;
    --    height: 384px; }
    --
    --.framed-nexus4-port-216 {
    --  background: transparent url(../images/styles/device_nexus4_blank_port_432.png) no-repeat
    --scroll top left;
    --  background-size:240px 465px;
    --  padding: 52px 12px 52px 12px;
    --  overflow: hidden; }
    --  .framed-nexus4-port-216, .framed-nexus4-port-216 video,
    --  .framed-nexus4-port-216 img {
    --    width: 216px;
    --    height: 360px; }
    --
    --.framed-nexus5-port-span-5 {
    --  background: transparent url(../images/styles/device_nexus5_blank_port_span5.png) no-repeat
    --  scroll top left;
    --  padding: 52px 33px 69px 31px;
    --  overflow: hidden;
    --}
    --
    --.framed-nexus5-port-span-5,
    --.framed-nexus5-port-span-5 video,
    --.framed-nexus5-port-span-5 img {
    --  width: 216px;
    --  height: 384px;
    --}
    --
    --.framed-nexus5-land-span-13 {
    --  background: transparent url(../images/styles/device_nexus5_blank_land_span13.png) no-repeat scroll top left;
    --  padding: 36px 119px 54px 108px;
    --  overflow: hidden;
    --}
    --
    --.framed-nexus5-land-span-13,
    --.framed-nexus5-land-span-13 video,
    --.framed-nexus5-land-span-13 img {
    --  width: 533px;
    --  height: 300px;
    --}
    --
    --.framed-nexus5-port-span-5,
    --.framed-nexus5-port-span-5 video,
    --.framed-nexus5-port-span-5 img {
    --  width: 216px;
    --  height: 384px;
    --}
    --
    --/* wear device frames */
    --
    --.framed-wear-square {
    --  background: transparent url(../images/styles/device_wear_square.png) no-repeat scroll top left;
    --  background-size: 302px 302px;
    --  height:222px;
    --  width:222px;
    --  padding:40px;
    --  overflow:hidden;
    --}
    --
    --.framed-wear-square-small {
    --  background: transparent url(../images/styles/device_wear_square_small.png) no-repeat scroll top left;
    --  background-size: 169px 200px;
    --  height:147px;
    --  width:147px;
    --  padding:27px 11px;
    --  overflow:hidden;
    --}
    --
    --#api-info-block {
    --  color: #999;
    --  float: right;
    --  font-size: 12px;
    --  font-weight: normal;
    --  line-height: 14px;
    --  margin: 20px 0 0;
    --  max-width: 80%;
    --  padding: 0 10px 6px;
    --  text-align: right;
    --}
    --
    --#api-info-block a,
    --#api-info-block a:active,
    --#api-info-block a:visited {
    --  color: #222;
    --}
    --
    --#jd-header {
    --  font-size: 12px;
    --  margin: 20px 0 12px;
    --  padding: 0 0 12px;
    --}
    --
    --#jd-header h1 {
    --  margin: 0;
    --  padding: 0 0 6px;
    --}
    --
    --#jd-content
    --.framed-wear-square img {
    --  height:222px;
    --  width: 222px;
    --  padding:0;
    --  margin:0;
    --}
    --
    --#jd-content
    --.framed-wear-square-small img {
    --  height:147px;
    --  width: 147px;
    --  padding:0;
    --  margin:0;
    --}
    --
    --
    --
    --
    --
    --
    --/* landing page disclosures */
    --.landing-page-link {
    --  text-decoration: none;
    --  font-weight: 500;
    --  color: #333333; }
    --  .landing-page-link:after {
    --    content: '';
    --    background: transparent url(../images/styles/disclosure_right.png) no-repeat scroll 50% 50%;
    --    width: 10px;
    --    height: 10px;
    --    display: inline-block;
    --    margin-left: 5px; }
    --
    --/* tooltips */
    --.tooltip-box {
    --  position: absolute;
    --  background-color: rgba(0, 0, 0, 0.9);
    --  border-radius: 2px;
    --  font-size: 14px;
    --  line-height: 20px;
    --  color: #fff;
    --  padding: 6px 10px;
    --  max-width: 250px;
    --  z-index: 10000; }
    --  .tooltip-box.below:after {
    --    position: absolute;
    --    content: '';
    --    line-height: 0;
    --    display: block;
    --    top: -10px;
    --    left: 5px;
    --    border: 5px solid transparent;
    --    border-bottom-color: rgba(0, 0, 0, 0.9); }
    --
    --/* video note */
    --.video-instructions {
    --  margin-top: 10px;
    --  margin-bottom: 10px; }
    --  .video-instructions:before {
    --    content: '';
    --    background: transparent url(../images/styles/ico_movie_inline.png) no-repeat scroll top left;
    --    display: inline-block;
    --    width: 12px;
    --    height: 12px;
    --    margin-right: 8px; }
    --  .video-instructions:after {
    --    content: 'Click device screen to replay movie.'; }
    --
    --/* download buttons */
    --.download-button {
    --  display: block;
    --  margin-bottom: 5px;
    --  text-decoration: none;
    --  background-color: #33b5e5;
    --  color: #fff !important;
    --  font-weight: 500;
    --  box-shadow: 0 1px 1px rgba(0, 0, 0, 0.12);
    --  padding: 6px 12px;
    --  border-radius: 2px; }
    --  .download-button:hover, .download-button:focus {
    --    background-color: #0099cc;
    --    color: #fff !important; }
    --  .download-button:active {
    --    background-color: #006699; }
    --
    --/* UI tables and other things found in Writing style and Settings pattern */
    --.ui-table {
    --  width: 100%;
    --  background-color: #282828;
    --  color: #fff;
    --  border-radius: 2px;
    --  box-shadow: 0 2px 4px rgba(0, 0, 0, 0.25);
    --  border-collapse: separate; }
    --  .ui-table th,
    --  .ui-table td {
    --    padding: 5px 10px;
    --    background-color: inherit;
    --    border:0;}
    --  .ui-table thead th {
    --    font-weight: bold; }
    --  .ui-table tfoot td {
    --    border-top: 1px solid #494949;
    --    border-right: 1px solid #494949;
    --    text-align: center; }
    --    .ui-table tfoot td:last-child {
    --      border-right: 0; }
    --
    --.layout-with-list-item-margins {
    --  margin-left: 30px !important; }
    --
    --.emulate-content-left-padding {
    --  margin-left: 10px; }
    --
    --.do-dont-label {
    --  margin-bottom: 10px;
    --  padding-left: 20px;
    --  background: transparent none no-repeat scroll 0px 3px; }
    --  .do-dont-label.bad {
    --    background-image: url(../images/styles/ico_wrong.png); }
    --  .do-dont-label.good {
    --    background-image: url(../images/styles/ico_good.png); }
    --
    --
    --
    --
    --/* --------------------------------------------------------------------------
    --Footer
    --*/
    --.line {
    --    clear: both;
    --    background: #acbc00;
    --    background: -moz-linear-gradient(top, #acbc00 0, #acbc00 50%, #bdde00 50%, #bdde00 100%);
    --    background: -webkit-gradient(linear, left top, left bottom, color-stop(0, #acbc00),
    --color-stop(50%, #acbc00), color-stop(50%, #bdde00), color-stop(100%, #bdde00));
    --    background: -webkit-linear-gradient(top, #acbc00 0, #acbc00 50%, #bdde00 50%, #bdde00 100%);
    --    background: -o-linear-gradient(top, #acbc00 0, #acbc00 50%, #bdde00 50%, #bdde00 100%);
    --    background: -ms-linear-gradient(top, #acbc00 0, #acbc00 50%, #bdde00 50%, #bdde00 100%);
    --    background: linear-gradient(top, #acbc00 0, #acbc00 50%, #bdde00 50%, #bdde00 100%);
    --    height: 2px;
    --    margin-top: 150px;
    --    position: relative;
    --    z-index: 11;
    --}
    --#footer {
    --    font-size:11px;
    --    clear: both;
    --    color: #999;
    --    padding: 15px 0;
    --    margin-top:10px;
    --    width:auto;
    --}
    --#footer-local ul {
    --  list-style: none;
    --  margin: 5px 0 30px 0;
    --}
    --#footer-local li {
    --    display: inline;
    --}
    --#footer-local li+li:before {
    --    content: '|';
    --    padding: 0 3px;
    --  color: #e5e5e5;
    --}
    --#footer-global {
    --    padding: 10px 15px;
    --  background: #f5f5f5;
    --}
    --#footer-global {
    --    border-top: 1px solid #ebebeb;
    --    font-size: 11.5px;
    --    line-height: 1.8;
    --    list-style: none;
    --}
    --#footer-global ul {
    --    margin: 0;
    --}
    --#footer-global li {
    --    display: inline;
    --    font-weight: bold;
    --}
    --#footer-global li+li:before {
    --    content: '¬?';
    --    padding: 0 3px;
    --}
    --* html #footer-global li {
    --    margin: 0 13px 0 0;
    --}
    --* [dir='rtl'] #footer-global li {
    --    margin: 0 0 0 13px;
    --}
    --*+html #footer-global li {
    --    margin: 0 13px 0 0;
    --}
    --*+[dir='rtl'] #footer-global li {
    --    margin: 0 0 0 13px;
    --}
    --#footer-global li a {
    --    font-weight: normal;
    --}
    --.locales {
    --  margin: 10px 0 0 0px;
    --}
    --[dir='rtl'] .locales {
    --    background-position: right center;
    --    float: left;
    --    padding: 0 24px 0 0;
    --}
    --.locales form {
    --    margin: 0;
    --}
    --
    --.locales select,
    --.locales option {
    --  text-transform: capitalize;
    --}
    --
    --.locales select, .sites select {
    --  line-height: 3.08;
    --  margin: 0px 0;
    --  border: solid 1px #EBEBEB;
    --  -webkit-appearance: none;
    --  background: white url('../images/arrows-up-down.png') right center no-repeat;
    --  height: 30px;
    --  color: #222;
    --  line-height: normal;
    --  padding: 5px;
    --  width: 230px;
    --}
    --}
    --
    --/* =============================================================================
    --   Print Only
    --   ========================================================================== */
    --@media print {
    --  /* configure printed page */
    --  @page {
    --      margin: 0.75in 1in;
    --      widows: 4;
    --      orphans: 4;
    --  }
    --
    --  /* reset spacing metrics */
    --  html, body, .wrap {
    --      margin: 0 !important;
    --      padding: 0 !important;
    --      width: auto !important;
    --  }
    --
    --  /* leave enough space on the left for bullets */
    --  body {
    --      padding-left: 20px !important;
    --  }
    --  #doc-col {
    --      margin-left: 0;
    --  }
    --
    --  /* hide a bunch of non-content elements */
    --  #header, #footer, #nav-x, #side-nav,
    --  .training-nav-top, .training-nav-bottom,
    --  #doc-col .content-footer,
    --  .nav-x, .nav-y,
    --  .paging-links {
    --      display: none !important;
    --  }
    --
    --  /* remove extra space above page titles */
    --  #doc-col .content-header {
    --      margin-top: 0;
    --  }
    --
    --  /* bump up spacing above subheadings */
    --  h2 {
    --      padding-top: 40px !important;
    --  }
    --
    --  /* print link URLs where possible and give links default text color */
    --  p a:after {
    --      content: " (" attr(href) ")";
    --      font-size: 80%;
    --  }
    --  p a {
    --      word-wrap: break-word;
    --  }
    --  a {
    --      color: inherit;
    --  }
    --
    --  /* syntax highlighting rules */
    --  .str { color: #060; }
    --  .kwd { color: #006; font-weight: bold; }
    --  .com { color: #600; font-style: italic; }
    --  .typ { color: #404; font-weight: bold; }
    --  .lit { color: #044; }
    --  .pun { color: #440; }
    --  .pln { color: #000; }
    --  .tag { color: #006; font-weight: bold; }
    --  .atn { color: #404; }
    --  .atv { color: #060; }
    --}
    --
    --/* =============================================================================
    --   Layout
    --   ========================================================================== */
    --@media screen, projection, print {
    --
    --.training-nav-top {
    --  border:1px solid #e5e5e5;
    --  border-width: 1px 1px 0;
    --  bottom: -56px;
    --  box-sizing: border-box;
    --  position: absolute;
    --  right: 0;
    --  width: 280px;
    --}
    --
    --.training-nav-bottom {
    --  float:right;
    --  margin:0 0 0 20px;
    --  padding:0 0 20px;
    --}
    --
    --#tb-wrapper,
    --#qv-wrapper {
    --  float:right;
    --  clear:right;
    --  margin:6px 0 0 30px; /* negative top-margin to counter the content-header bottom margin */
    --  padding:0 0 30px;
    --}
    --
    --#tb-wrapper {
    --  margin:56px 0 0 20px; /* negative top-margin to counter the content-header bottom margin */
    --}
    --
    --#tb,
    --#qv {
    --  border: 1px solid #e5e5e5;
    --  box-sizing: border-box;
    --  float: right;
    --  line-height: 16px;
    --  padding: 5px 0;
    --  width: 240px;
    --}
    --
    --#tb {
    --  width:280px;
    --}
    --
    --#tb h2,
    --#qv h2 {
    --  border-top: 1px solid #e5e5e5;
    --  color: inherit;
    --  font-size: 16px;
    --  line-height: 24px;
    --  margin: 15px 0 4px;
    --  padding: 10px 15px 0;
    --}
    --
    --#tb h2:first-child,
    --#qv h2:first-child {
    --  border-top: 0;
    --  padding-top: 0;
    --  margin-top: 10px;
    --}
    --
    --#tb .download-box,
    --#qv .download-box {
    --  padding:0 0 0 15px;
    --}
    --
    --#tb .download-box .filename,
    --#qv .download-box .filename {
    --  font-size:11px;
    --  margin:4px 4px 10px;
    --}
    --
    --@media (max-width: 719px) {
    --  .training-nav-top {
    --    left: 0;
    --    width: auto;
    --  }
    --
    --  #tb-wrapper {
    --    clear: none;
    --    float: none;
    --    margin-left: 0;
    --  }
    --
    --  #tb {
    --    float: none;
    --    width: auto;
    --  }
    --
    --  #qv-wrapper {
    --    display: none;
    --  }
    --}
    --
    --
    --/* Dev guide quicknav */
    --
    --.sidebox-wrapper {
    --  float:right;
    --  clear:right;
    --  margin:0 0 0 20px;
    --  padding:0 0 20px;
    --}
    --
    --.sidebox {
    --  width:226px;
    --  font-size:13px;
    --  line-height:18px;
    --  border-left:3px solid #96ca7c;
    --  border-left-color: rgba(106, 179, 68, .7); /* #6ab344 * 70% */
    --  float:right;
    --  padding:0 0 0 20px;
    --  margin:0 0 1em 20px;
    --}
    --
    --.sidebox h2,
    --.sidebox h3,
    --.sidebox h4,
    --.sidebox h5 {
    --  font-weight:bold;
    --  padding: 0 0 10px;
    --  line-height: 16px;
    --}
    --
    --.sidebox * {
    --  font-size:inherit;
    --}
    --
    --.sidebox > *:last-child {
    --  margin-bottom:0;
    --}
    --
    --#tb ol,
    --#tb ul,
    --#tb p,
    --#qv ul {
    --  list-style-type: none;
    --  margin:0 15px 10px 15px;
    --}
    --
    --#tb li,
    --#qv li {
    --  margin: 8px 0;
    --  padding: 0 0 0 16px;
    --  position: relative;
    --}
    --
    --#qv ol {
    --  list-style:none;
    --  margin:0 15px 15px;
    --  font-size:inherit;
    --  line-height:inherit;
    --}
    --
    --#tb ol ol,
    --#tb ul ul,
    --#qv ol ol,
    --#qv ul ul,
    --.sidebox ol ol,
    --.sidebox ul ul {
    --  margin: 8px 0;
    --}
    --
    --.sidebox p,
    --#qv p {
    --  margin: 0 0 10px;
    --}
    --
    --/* related resources blocks in checklists */
    --
    --/* related resources sections that have dynamic content */
    --
    --
    --
    --h3.rel-resources {
    --  padding:1.25em auto;
    --}
    --
    --/* --------------------------------------------------------------------------
    --Form
    --*/
    --.article form {
    --    margin: 0 0 20px;
    --}
    --.article form .form-required {
    --    color: #dd4b39;
    --}
    --.article form fieldset {
    --    margin: 0 0 20px;
    --    padding: 0;
    --}
    --.article form legend {
    --    display: block;
    --    line-height: 1.5;
    --    margin: 0;
    --    padding: 0;
    --}
    --/*
    --.article form ol, .article form ul {
    --    margin: 0 0 0 1em;
    --    padding: 0 0 0 1em;
    --}
    --[dir='rtl'] .article form ol, [dir='rtl'] .article form ul {
    --    margin: 0 1em 0 0;
    --    padding: 0 1em 0 0;
    --}
    --.article form ol ul, .article form ul ul, [dir='rtl'] .article form ol ul, [dir='rtl'] .article form
    --ul ul {
    --    list-style: none;
    --    margin: 0;
    --    padding: 0;
    --}
    --.article form li {
    --    margin: 0 0 20px;
    --}
    --.article form li li {
    --    margin: 0 0 5px;
    --}
    --*/
    --.article form label {
    --    display: block;
    --    margin: 0 0 5px;
    --    padding: 0;
    --}
    --.article form input[type='text'], .article form select, .article form textarea, .article form
    --.checkbox-group, .article form .radio-group {
    --    margin-bottom: 15px;
    --}
    --.checkbox-group input {
    --  width: 13px;
    --  height: 13px;
    --  background: #fff;
    --  border: solid 1px #c6c6c6;
    --  float: left;
    --}
    --.article form .checkbox-group, .article form .radio-group {
    --  display: block
    --}
    --.article form select {
    --    border: solid 1px #ebebeb;
    --    border-top-color: #ddd;
    --    -webkit-appearance: none;
    --    background: #f3f3f3 url(../images/arrows-up-down.png) right center no-repeat;
    --    height: 30px;
    --    color: #222;
    --    line-height: normal;
    --    padding: 5px;
    --    width: 130px;
    --}
    --
    --.article form .browse .browse-msg {
    --  font-size: 11.5px;
    --}
    --.article form .browse .button-secondary {
    --  height: auto;
    --  line-height: 25px;
    --  font-size: 11px;
    --  padding: 0 8px;
    --  margin: 0 10px 15px 0;
    --}
    --.article form input[type='text'], .article form textarea {
    --    border: 1px solid #ebebeb;
    --    border-top-color: #dcdcdc;
    --    color: #222;
    --    line-height: normal;
    --    padding: 6px 10px;
    --    width: 300px;
    --}
    --.article form textarea {
    --    height: 150px;
    --}
    --.article form input[type='text']:focus, .article form textarea:focus {
    --    border-color: #33B5E5;
    --    -moz-box-shadow: inset 0 1px 2px rgba(0, 0, 0, .2);
    --    -o-box-shadow: inset 0 1px 2px rgba(0, 0, 0, .2);
    --    -webkit-box-shadow: inset 0 1px 2px rgba(0, 0, 0, .2);
    --    box-shadow: inset 0 1px 2px rgba(0, 0, 0, .2);
    --    outline: 0;
    --}
    --.article form input[disabled], .article form textarea[disabled], .article form label.form-disabled {
    --    color: #999;
    --}
    --.article form input[type='text'][disabled], .article form textarea[disabled] {
    --    background-color: #ebebeb;
    --}
    --form .form-error input[type='text'], form .form-error textarea {
    --    border-color: #dd4b39;
    --  margin-right: 20px;
    --}
    --.aside {
    --    -moz-border-radius: 2px;
    --    -webkit-border-radius: 2px;
    --    border-radius: 2px;
    --    margin: 10px 0;
    --    padding: 20px;
    --    position: relative;
    --  background: #f9f9f9;
    --}
    --/*
    --.aside, .notification, .promo {
    --    -moz-border-radius: 2px;
    --    -webkit-border-radius: 2px;
    --    border-radius: 2px;
    --    margin: 10px 0;
    --    padding: 10px;
    --    position: relative;
    --}
    --.aside>:first-child, .notification>:first-child, .promo>:first-child {
    --    margin-top: 0;
    --}
    --.aside>:last-child, .notification>:last-child, .promo>:last-child {
    --    margin-bottom: 0;
    --}
    --.aside {
    --    background: #f9f9f9;
    --}
    --.notification {
    --    background: #fffbe4;
    --    border-color: #f8f6e6;
    --}
    --.promo {
    --    background: #f6f9ff;
    --    border-color: #eff2f9;
    --}
    --*/
    --
    --/* SDK TOS styles */
    --
    --div.sdk-terms {
    --  white-space: pre-wrap;
    --  word-wrap: break-word;
    --  font-family: inherit;
    --  font-size: inherit;
    --  padding: 10px;
    --  height: 370px;
    --  width: 738px;
    --  border: 1px solid #444;
    --  background: transparent;
    --  overflow:auto;
    --  margin:0 0 10px;
    --}
    --
    --div.sdk-terms.fullsize {
    --  padding: 0;
    --  height: auto;
    --  width: auto;
    --  border:none;
    --}
    --
    --div.sdk-terms h3,
    --div.sdk-terms h2 {
    --  padding: 0;
    --}
    --
    --div#sdk-terms-form {
    --  padding:0 0 0 10px;
    --}
    --
    --div#sdk-terms-form input {
    --  display:inline;
    --  margin:4px 4px 4px 0;
    --}
    --
    --
    --/* --------------------------------------------------------------------------
    --Code Style
    --*/
    --pre {
    --  margin:0 0 1em 0;
    --  padding: 1em;
    --  overflow: auto;
    --  border: solid 1px #ddd;
    --  background: #f7f7f7;
    --}
    --
    --p.package-name {
    --  margin:1em 0;
    --}
    --
    --h1.api-title {
    --  padding-bottom:0;
    --}
    --
    --h2.api-section {
    --  margin: 60px 0 0;
    --}
    --
    --h2.api-section+hr {
    --  margin-bottom: 30px;
    --}
    --
    --h3.api-name {
    --  margin: 80px 0 12px;
    --  padding: 0;
    --}
    --
    --/* remove top padding when this h3 (visibly) follows an h2.
    --   This accounts for the variation in structure,
    --   including the collapsed mobile headings */
    --h2+hr+div>div>a+div>h3.api-name,
    --h2+hr+a+div>h3.api-name,
    --h2+hr+a+h3.api-name {
    --  margin-top: 0;
    --}
    --
    --pre.api-signature,
    --code.api-signature {
    --  color:inherit;
    --  padding:0;
    --  margin:1em 0;
    --  border:0;
    --  background:transparent;
    --}
    --
    --.str { color: #800; } /* Code string */
    --.kwd { color: #008; }
    --.typ { color: #606; }
    --.lit { color: #066; }
    --.pun { color: #660; }
    --.pln { color: #000; }
    --.tag { color: #008; }
    --.atn { color: #828; }
    --.atv { color: #800; } /* XML string */
    --.dec { color: #606; }
    --
    --/* --------------------------------------------------------------------------
    --Three-Pane
    --*/
    --/* Package Nav & Classes Nav */
    --.three-pane {
    --  position: relative;
    --  border-top: solid 1px #ebebeb;
    --}
    --#packages-nav .js-pane,
    --#classes-nav .js-pane {
    --  overflow:visible;
    --}
    --#packages-nav {
    --        height:270px;
    --  max-height: inherit;
    --  overflow: hidden;
    --  position: relative;
    --}
    --#classes-nav {
    --  overflow: hidden;
    --  position: relative;
    --}
    --#packages-nav ul, #classes-nav ul {
    --  list-style-type: none;
    --  margin: 10px 0 20px 0;
    --  padding: 0;
    --}
    --#classes-nav li {
    --  font-weight: bold;
    --  margin: 5px 0;
    --}
    --#packages-nav li,
    --#classes-nav li li {
    --  margin: 0;
    --}
    --#packages-nav li a, #packages-nav li a:active, #packages-nav li a:visited,
    --#classes-nav li a, #classes-nav li a:active, #classes-nav li a:visited {
    --  padding: 0 0 0 4px;
    --}
    --#packages-nav li a, #packages-nav li a:active, #packages-nav li a:visited,
    --#classes-nav li li a, #classes-nav li li a:active, #classes-nav li li a:visited {
    --  color: #222;
    --  font-weight: normal;
    --}
    --#packages-nav li a, #packages-nav li a:active, #packages-nav li a:visited,
    --#classes-nav li li a, #classes-nav li li a:active, #classes-nav li li a:visited {
    --  display: block;
    --}
    --#packages-nav li.selected a, #packages-nav li.selected a:active, #packages-nav li.selected
    --a:visited,
    --#classes-nav li li.selected a, #classes-nav li li.selected a:active, #classes-nav li li.selected
    --a:visited {
    --    font-weight: 500;
    --    color: #0099cc;
    --    background-color:#fff; }
    --  #packages-nav li.selected ul li a,
    --  #classes-nav li.selected ul li a {
    --  /* don't highlight child items */
    --    color: #555555; }
    --
    --#nav-swap {
    --  height:30px;
    --  border-top:1px solid #ccc;
    --}
    --#nav-swap a {
    --  display:inline-block;
    --  height:100%;
    --  color: #222;
    --  font-size: 12px;
    --  padding: 5px 0 5px 5px;
    --}
    --
    --#nav-swap .fullscreen {
    --  float: right;
    --  width: 24px;
    --  height: 24px;
    --  text-indent: -1000em;
    --  padding:0;
    --  margin:3px 5px 0;
    --  background: url(../images/fullscreen.png) no-repeat -24px 0;
    --}
    --#nav-swap .fullscreen.disabled {
    --  background-position: 0 0;
    --}
    --#nav-swap .fullscreen:hover,
    --#nav-swap .fullscreen:focus {
    --  cursor:pointer;
    --}
    --
    --/* Content */
    --#doc-col {
    --  margin-right:0;
    --}
    --
    --/* Uncomment this for preview release watermark
    --#doc-col {
    --  background: url('../images/preview.png') repeat;
    --}
    --*/
    --
    --#doc-content-container {
    --  margin-left: 291px
    --}
    --
    --#doc-header, #doc-content {
    --  padding: 0;
    --}
    --
    --#doc-header {
    --  background: #f7f7f7;
    --}
    --
    --#doc-header h1 {
    --  line-height: 0;
    --  padding-bottom: 15px;
    --}
    --
    --
    --#api-info-block {
    --  float: right;
    --  font-weight: bold;
    --}
    --
    --#api-info-block a, #api-info-block a:active, #api-info-block a:visited {
    --  color: #222;
    --}
    --
    --#api-info-block a:hover, #api-info-block a:focus {
    --  color: #33B5E5;
    --}
    --
    --#api-nav-header {
    --  height:19px; /* plus 16px padding = 35; same as #nav li */
    --  font-size:14px;
    --  padding: 8px 0;
    --  margin: 0;
    --  border-bottom: 1px solid #CCC;
    --  background:#e9e9e9;
    --  background: rgba(0, 0, 0, 0.05); /* matches #nav li.expanded */
    --  line-height: 19px; /* Fix regression after page line-height is bumped to 24px */
    --}
    --
    --#api-nav-title {
    --  padding:0 5px;
    --  white-space:nowrap;
    --}
    --
    --#api-level-toggle {
    --  float:right;
    --  padding:0 5px;
    --}
    --
    --#api-level-toggle label {
    --  margin:0;
    --  vertical-align:top;
    --  line-height: 19px;
    --  font-size:13px;
    --  height: 19px;
    --}
    --
    --#api-level-toggle .select-wrapper {
    --  width: 35px;
    --  display: inline-block;
    --  overflow: hidden;
    --}
    --
    --#api-level-toggle select {
    --  border: 0;
    --  appearance:none;
    --  -moz-appearance:none;
    --  -webkit-appearance: none;
    --  background: transparent url(../images/arrows-up-down.png) 23px 5px no-repeat;
    --  color: #222;
    --  /* remove the lines below after xp testing
    --     height: 19px;
    --     line-height: 19px; */
    --  padding: 0;
    --  margin: .5px 0 0 0;
    --  width:150%;
    --  font-size:13px;
    --  vertical-align:top;
    --  outline:0;
    --}
    --
    --
    --/* Toggle for revision notes and stuff */
    --div.toggle-content.closed .toggle-content-toggleme {
    --  display:none;
    --}
    --
    --#jd-content img.toggle-content-img {
    --  margin:0 5px 5px 0;
    --}
    --
    --div.toggle-content-toggleme {
    --  padding:0 0 0 15px;
    --}
    --
    --
    --/* API LEVEL FILTERED MEMBERS */
    --
    --.absent,
    --.absent a:link,
    --.absent a:visited,
    --.absent a:hover,
    --.absent * {
    --  color:#bbb !important;
    --  cursor:default !important;
    --  text-decoration:none !important;
    --}
    --#devdoc-nav li.absent.selected,
    --#devdoc-nav li.absent.selected *,
    --#devdoc-nav div.label.absent.selected,
    --#devdoc-nav div.label.absent.selected * {
    --  background-color:#eaeaea !important;
    --}
    --.absent h4.jd-details-title,
    --.absent h4.jd-details-title * {
    --  background-color:#f6f6f6 !important;
    --}
    --.absent img {
    --  opacity: .3;
    --  filter: alpha(opacity=30);
    --  -ms-filter:"progid:DXImageTransform.Microsoft.Alpha(Opacity=30)";
    --}
    --
    --
    --
    --
    --
    --
    --
    --
    --
    --/* JQUERY RESIZABLE STYLES */
    --.ui-resizable { position: relative; }
    --.ui-resizable-handle { position: absolute; display: none; font-size: 0.1px; z-index:1; }
    --.ui-resizable .ui-resizable-handle { display: block; border-bottom: 1px solid #e4e4e4; }
    --/*body .ui-resizable-disabled .ui-resizable-handle { display: none; }
    --body .ui-resizable-autohide .ui-resizable-handle { display: none; }*/
    --.ui-resizable-s { cursor: s-resize; height: 10px; width: 100% !important; bottom: -11px; left: 0;
    --border-bottom: solid 1px #ededed;
    --  background: #f7f7f7 url("../images/resizable-s2.png") no-repeat scroll center center; }
    --/*
    --.ui-resizable-e {
    --cursor: e-resize; width: 10px; right: 0; top: 0; height: 100%; border-right: solid
    --1px #ededed;background: #f7f7f7 url("../images/resizable-e2.png") no-repeat scroll center center; }
    --*/
    --
    --/* --------------------------------------------------------------------------
    --Lightbox
    --*/
    --.lightbox {
    --  width: 769px;
    --  padding: 1.5em;
    --  margin: 0 auto;
    --  border: solid 1px #dcdcdc;
    --  background: #fff;
    --  -moz-box-shadow: 1px 1px 5px rgba(0,0,0,0.1);
    --  -webkit-box-shadow: 1px 1px 5px rgba(0,0,0,0.1);
    --  box-shadow: 1px 1px 5px rgba(0,0,0,0.1)
    --}
    --.lightbox .header {
    --  float: left;
    --  width: 720px;
    --  margin: -10px 20px 10px 0;
    --}
    --.lightbox .close {
    --  float: right;
    --  width: 10px;
    --  height: 10px;
    --  margin: -10px -10px 10px 0;
    --  text-indent: -1000em;
    --  background: url(../images/close.png) no-repeat 0 0;
    --}
    --.lightbox .close:hover, .lightbox .close:focus {
    --  background-position: -10px 0;
    --}
    --
    --/* --------------------------------------------------------------------------
    --Styles for samples browser
    --*/
    --
    --#codesample-wrapper {
    --  width:100000px; /* super wide to contain floats, but doesn't cause scroll */
    --  overflow:visible;
    --}
    --pre#codesample-block {
    --  float:left;
    --  overflow:visible;
    --  background:transparent;
    --  border:none;
    --}
    --pre#codesample-block a.number {
    --  display:none;
    --}
    --pre#codesample-block .code-line:hover {
    --  background:#e7e7e7;
    --}
    --pre#codesample-line-numbers {
    --  float:left;
    --  width:2em;
    --  background:transparent;
    --  border:none;
    --  border-right:1px solid #ccc;
    --  padding-left:0;
    --  font-family:monospace;
    --  text-align:right;
    --  -webkit-touch-callout: none;
    --  -webkit-user-select: none;
    --  -khtml-user-select: none;
    --  -moz-user-select: -moz-none;
    --  -ms-user-select: none;
    --  user-select: none;
    --}
    --pre#codesample-line-numbers a {
    --  color:#999;
    --}
    --pre#codesample-line-numbers.hidden {
    --  display:none;
    --}
    --pre#codesample-block span.code-line {
    --  width:100%;
    --  display:inline-block;
    --}
    --
    --/*
    --Styles for displaying image or video resources in samples browser.
    --Resources are marked as no-display if they exceed the size limit.
    --*/
    --div#codesample-resource img, div#codesample-resource video {
    --  border: 1px solid #ececec;
    --}
    --
    --div#codesample-resource.noDisplay div {
    --  border: 1px solid #ececec;
    --  width:120px;
    --  margin-bottom:4px;
    --  padding:20px;
    --}
    --
    --div#codesample-resource .noDisplay-message:after {
    --  font-style:italic;
    --  font-size:12px;
    --  content: 'This resource is not available for browsing. To view it, please download the project.';
    --}
    --
    --/*
    --Styles for project structure (treeview) page
    --*/
    --.structure-dir {
    --background-image:url(../images/folder.png);
    --background-repeat:no-repeat;
    --background-position:16px 2px;
    --  margin:.25em 0 0 0;
    --  padding:0 0 0 0;
    --}
    --
    --.structure-toggleme {
    --  margin:0 0 0 3em;
    --  padding:0 0 0 0;
    --  text-decoration:none;
    --}
    --
    --.structure-java{
    --background-image:url(../images/file-java.png);
    --background-repeat:no-repeat;
    --background-position:0px 2px;
    --  margin:.3em 0 0 0;
    --  padding:.3em 0 .3em 22px;
    --}
    --
    --.structure-file {
    --background-image:url(../images/file-generic.png);
    --background-repeat:no-repeat;
    --background-position:0px 2px;
    --  margin:.3em 0 0 0;
    --  padding:.3em 0 .3em 22px;
    --}
    --
    --.structure-xml {
    --background-image:url(../images/file-xml.png);
    --background-repeat:no-repeat;
    --background-position:0px 2px;
    --  margin:.3em 0 0 0;
    --  padding:.3em 0 .25em 22px;
    --}
    --
    --.structure-img {
    --background-image:url(../images/file-image.png);
    --background-repeat:no-repeat;
    --background-position:0px 2px;
    --  margin:.3em 0 0 0;
    --  padding:.3em 0 .25em 22px;
    --}
    --
    --.structure-manifest {
    --background-image:url(../images/file-manifest.png);
    --background-repeat:no-repeat;
    --  margin:.0 0 0 1.25em;
    --  padding:0 0 0 22px;
    --  text-decoration:none;
    --}
    --
    --#jd-content .structure-toggle-img {
    --  margin:.5em 0 0 0;
    --padding-right:2.1em;
    --}
    --
    --.dirInfo {
    --  margin-left:2em;
    --}
    --
    --.structure-dir a {
    --  text-decoration:none;
    --}
    --
    --.structure-manifest a {
    --  text-decoration: none;
    --}
    --.structure-file a {
    --  text-decoration: none;
    --}
    --
    --.sampleEmbed {
    --  background-color:rgb(249, 249, 249);
    --}
    --
    --.sampleEmbed ol.lineNumbers {
    --  list-style-type: decimal;
    --  padding-left:1em;
    --}
    --
    --.sampleEmbed ol.lineNumbers li {
    --border-left:1px solid #ddd;
    --border-right:1px solid #ddd;
    --color:gray;
    --background-color:#f7f7f7;
    --margin:0 0 0 24px;
    --padding: 2px 2px 2px 6px;
    --}
    --
    --.sampleEmbed ol.lineNumbers li:hover {
    --background: #efefef;
    --}
    --
    --.samples-nav li a {
    --  overflow: hidden;
    --  text-overflow: ellipsis;
    --  white-space: nowrap;
    --}
    --
    --/* --------------------------------------------------------------------------
    --Styles for raw formatted line numbers (not used with listformatted version)
    --div.sampleLine div.lineNumber {
    --  display: inline;
    --}
    --div.sampleLine div.lineCode {
    --  display: inline;
    --  padding-left:6px;
    --}
    --div.sampleLine {
    --  padding:0;
    --  margin:0;
    --}*/
    --
    --/* --------------------------------------------------------------------------
    --Misc and article typography
    --*/
    --
    --
    --.clearfix:before, .clearfix:after {
    --  content: "";
    --  display: table
    --}
    --.clearfix:after {
    --  clear: both
    --}
    --.clearfix {
    --  *zoom: 1
    --}
    --table.blank th, table.blank td {
    --    border: 0;
    --  background: none
    --}
    --.caption {
    --  margin: 0.5em 0 2em 0;
    --  color: #000;
    --  font-size: 11.5px;
    --}
    --
    --.nolist, .nolist ul, .nolist ol {
    --  list-style:none;
    --  margin-left:0;
    --}
    --
    --ol.callouts {
    --  counter-reset: item;
    --  list-style-type: none;
    --  margin-left:44px;
    --}
    --ol.callouts>li:before {
    --  counter-increment: item;
    --  content: counter(item);
    --  position: absolute;
    --  color:#fff;
    --  font-weight:bold;
    --  background-image:url(../images/styles/callout-bg_2x.png);
    --  background-size:24px;
    --  width:16px;
    --  padding-left:8px;
    --  margin-left:-34px;
    --}
    --
    --#tb .nolist {
    --  margin-left:15px;
    --}
    --
    --dl.xml>dt {
    --  text-transform:uppercase;
    --}
    --dl.xml dl.attr {
    --  margin-top:0;
    --}
    --
    --pre.classic {
    --  background-color:transparent;
    --  border:none;
    --  padding:0;
    --}
    --
    --p.img-caption {
    --  margin: -10px 0 20px;
    --  font-size: 13px;
    --}
    --
    --/* figures and callouts */
    --.figure {
    --  position: relative;
    --}
    --
    --.figure.pad-below {
    --  margin-bottom: 20px;
    --}
    --
    --.figure .figure-callout {
    --  position: absolute;
    --  color: #fff;
    --  font-weight: 500;
    --  font-size: 16px;
    --  line-height: 23px;
    --  text-align: center;
    --  background: transparent url(../images/styles/callout.png) no-repeat scroll 50% 50%;
    --  padding-right: 2px;
    --  width: 30px;
    --  height: 29px;
    --  z-index: 1000;
    --}
    --
    --.figure .figure-callout.top {
    --  top: -9px;
    --}
    --
    --.figure .figure-callout.right {
    --  right: -5px;
    --}
    --
    --.figure-caption {
    --  margin: 0 10px 20px 0;
    --  font-size: 14px;
    --  line-height: 20px;
    --  font-style: italic;
    --}
    --
    --/* rows of figures */
    --.figure-row {
    --  font-size: 0;
    --  line-height: 0;
    --  /* to prevent space between figures */
    --}
    --
    --.figure-row .figure {
    --  display: inline-block;
    --  vertical-align: top;
    --}
    --
    --.figure-row .figure + .figure {
    --  margin-left: 10px;
    --  /* reintroduce space between figures */
    --}
    --
    --.border-img {
    --  border: 1px solid #CCC;
    --}
    --
    --.center-img {
    --  margin: auto;
    --  text-align: center;
    --}
    --.center-img img {
    --  margin-bottom: 15px;
    --}
    --
    --.figure img,
    --.figure-right img,
    --.figure-left img,
    --.figure-center img,
    --.border-img {
    --  margin-bottom: 15px;
    --}
    --
    --.figure-center {
    --  margin: 32px auto 24px;
    --  max-width: 100%;
    --}
    --
    --.figure,
    --.figure-right {
    --  clear: right;
    --  float: right;
    --  margin: 10px 0 0 0;
    --  padding: 0 0 0 20px;
    --  max-width: 50%;
    --  /* width must be defined w/ an inline style matching the image width */
    --}
    --
    --.figure-left {
    --  clear: left;
    --  float: left;
    --  margin: 10px 0 0 0;
    --  padding: 0 20px 0 0;
    --  max-width: 50%;
    --  /* width must be defined w/ an inline style matching the image width */
    --}
    --
    --@media (max-width: 719px) {
    --  /* Collapse on mobile. */
    --  .figure,
    --  .figure-right,
    --  .figure-left {
    --    float: none;
    --    clear: none;
    --    padding: 0;
    --    margin: 32px auto 24px;
    --    max-width: 100%;
    --  }
    --}
    --
    --img.frame {
    --  border:1px solid #DDD;
    --  padding:4px;
    --}
    --
    --p.table-caption {
    --  margin: 0 0 4px 0;
    --  font-size:13px;
    --}
    --
    --p.code-caption {
    --  margin-bottom: 4px;
    --  font: 12px/1.5 monospace;
    --}
    --
    --p.note, div.note,
    --p.caution, div.caution,
    --p.warning, div.warning {
    --  padding: 0 0 0 20px;
    --  border-left: 3px solid;
    --  margin: 16px 0;
    --}
    --
    --p.note, div.note {
    --  border-color: #4eb9ed;
    --  border-color: rgba(3, 155, 229, .7); /* #039be5 * 70% */
    --}
    --
    --p.caution, div.caution {
    --  border-color: #ffbc4c;
    --  border-color: rgba(255, 160, 0, .7); /* #ffa000 * 70% */
    --}
    --
    --p.warning, div.warning {
    --  border-color: #f48684;
    --  border-color: rgba(239, 83, 80, .7); /* #ef5350 * 70% */
    --}
    --
    --div.note.design {
    --  border-left: 4px solid #00bcd4;
    --}
    --
    --div.note.develop {
    --  border-left: 4px solid #ff7043;
    --}
    --
    --div.note.distribute {
    --  border-left: 4px solid #afb42b;
    --}
    --
    --.note p, .caution p, .warning p {
    --  margin:0 0 5px;
    --}
    --
    --.note p:last-child, .caution p:last-child, .warning p:last-child {
    --  margin-bottom:0;
    --}
    --
    --.summary-table {
    --  background-color:#eceff1;
    --  padding:1em;
    --  margin-bottom:1.5em;
    --}
    --
    --.summary-table h5 {
    --  line-height:1em;
    --  font-size:.98em;
    --}
    --
    --body.about blockquote {
    --  display:block;
    --  float:right;
    --  width:280px;
    --  font-size:20px;
    --  font-style:italic;
    --  line-height:24px;
    --  color:#33B5E5;
    --  margin:0 0 20px 30px;
    --}
    --
    --div.design-announce p {
    --  margin:0 0 10px;
    --}
    --
    --.expandable {
    --  height:34px;
    --  padding-left:20px;
    --  position:relative;
    --}
    --.expandable:before {
    --  content: '';
    --  background-image: url(../images/styles/disclosure_down.png);
    --  background-repeat:no-repeat;
    --  background-position: -12px -9px;
    --  width: 20px;
    --  height: 20px;
    --  display: inline-block;
    --  position: absolute;
    --  top: 0;
    --  left: 0; }
    --}
    --.expandable.expanded:before {
    --  background-image: url(../images/styles/disclosure_up.png);
    --}
    --
    --/* notice box for cross links between Design/Develop docs */
    --a.notice-developers-video,
    --a.notice-developers,
    --a.notice-designers-video,
    --a.notice-designers {
    --  float:right;
    --  clear:right;
    --  width:238px;
    --  min-height:50px;
    --  margin:0 0 20px 20px;
    --  border:1px solid #ddd;
    --}
    --a.notice-developers-video.wide,
    --a.notice-developers.wide,
    --a.notice-designers-video.wide,
    --a.notice-designers.wide {
    --  width:278px;
    --}
    --a.notice-developers-video div,
    --a.notice-developers div,
    --a.notice-designers-video div,
    --a.notice-designers div {
    --  min-height:40px;
    --  background:url('../images/styles/notice-developers_2x.png') no-repeat 10px 10px;
    --  background-size:40px 40px;
    --  padding:10px 10px 10px 60px;
    --}
    --a.notice-designers div {
    --  background:url('../images/styles/notice-designers_2x.png') no-repeat 10px 10px;
    --  background-size:40px 40px;
    --}
    --a.notice-designers-video div {
    --  background:url('../images/styles/notice-designers-video_2x.png') no-repeat 10px 10px;
    --  background-size:40px 40px;
    --}
    --a.notice-developers-video div {
    --  background:url('../images/styles/notice-developers-video_2x.png') no-repeat 10px 10px;
    --  background-size:40px 40px;
    --}
    --a.notice-developers-video:hover,
    --a.notice-developers:hover,
    --a.notice-designers-video:hover,
    --a.notice-designers:hover {
    --  background:#eee;
    --}
    --a.notice-developers-video h3,
    --a.notice-developers h3,
    --a.notice-designers-video h3,
    --a.notice-designers h3 {
    --  font-size:13px;
    --  line-height:18px;
    --  font-weight:bold;
    --  text-transform:uppercase;
    --  color:#000 !important;
    --  padding:0 0 1px;
    --}
    --a.notice-developers-video p,
    --a.notice-developers p,
    --a.notice-designers-video p,
    --a.notice-designers p {
    --  margin:0;
    --  line-height:14px;
    --}
    --a.notice-developers-video.left,
    --a.notice-developers.left,
    --a.notice-designers-video.left,
    --a.notice-designers.left {
    --  margin-left:0;
    --  float:left;
    --}
    --
    --
    --/* hide nested list items; companion to hideNestedLists() */
    --.hide-nested li ol,
    --.hide-nested li ul {
    --  display:none;
    --}
    --
    --a.header-toggle {
    --  display:block;
    --  float:right;
    --  text-transform:uppercase;
    --  font-size:.8em !important;
    --  font-weight:normal;
    --  margin-top:2px;
    --}
    --
    --
    --/* for IDE instruction toggle (Studio/Eclipse/Other) */
    --select.ide {
    --  background: transparent;
    --  border: 1px solid #bbb;
    --  border-left: 0;
    --  border-right: 0;
    --  margin: 10px 0;
    --  padding: 10px 0;
    --  color:#666;
    --}
    --select.ide,
    --select.ide option {
    --  font-family: inherit;
    --  font-size:16px;
    --  font-weight:500;
    --}
    --/* hide all except studio by default */
    --.select-ide.eclipse,
    --.select-ide.other {
    --  display:none;
    --}
    --/* ... unless studio also includes one of the others */
    --.select-ide.studio.eclipse,
    --.select-ide.studio.other {
    --  display:none;
    --}
    --
    --
    --/* -----------------------------------------------
    --good/bad example containers
    --*/
    --
    --div.example-block {
    --  background-repeat: no-repeat;
    --  background-position:10px 8px;
    --  background-color:#ccc;
    --  padding:4px;
    --  margin:.8em auto 1.5em 2em;
    --  width:260px;
    --  float:right;
    --}
    --/* red container */
    --.example-block.bad {
    --  background-image: url(/images/example-bad.png);
    --  background-color:#f4cccc;
    --}
    --/* green container */
    --.example-block.good {
    --  background-image: url(/images/example-good.png);
    --  background-color:#d9ead3;
    --}
    --/* container heading div */
    --#jd-content .example-block .heading {
    --  font-weight:bold;
    --  margin:6px 0 9px 36px;
    --  padding:6px auto;
    --}
    --/* container image (if any) */
    --#jd-content .example-block img {
    --  margin:0;
    --  padding:0px;
    --}
    --
    --.example-block table {
    --  margin:0;
    --}
    --
    --/* -----------------------------------------------
    --Dialog box for popup messages
    --*/
    --
    --div.dialog {
    --  height:0;
    --  margin:0 auto;
    --}
    --
    --div.dialog>div {
    --  z-index:99;
    --  position:fixed;
    --  margin:70px 0;
    --  width: 391px;
    --  height: 200px;
    --  background: #F7F7F7;
    ---moz-box-shadow: 0 0 15px rgba(0,0,0,0.5);
    ---webkit-box-shadow: 0 0 15px rgba(0,0,0,0.5);
    --box-shadow: 0 0 15px rgba(0,0,0,0.5);
    --}
    --/* IE6 can't position fixed */
    --* html div.dialog div { position:absolute; }
    --
    --
    --div#deprecatedSticker {
    --  display:none;
    --  z-index:99;
    --  position:fixed;
    --  right:15px;
    --  top:114px;
    --  margin:0;
    --  padding:1em;
    --  background:#FFF;
    --  border:1px solid #dddd00;
    --  box-shadow:-5px 5px 10px #ccc;
    --  -moz-box-shadow:-5px 5px 10px #ccc;
    --  -webkit-box-shadow:-5px 5px 10px #ccc;
    --}
    --
    --div#langMessage,
    --div#naMessage {
    --  display:none;
    --  width:555px;
    --  height:0;
    --  margin:0 auto;
    --}
    --
    --
    --div#langMessage>div,
    --div#naMessage div {
    --  z-index:99;
    --  width:450px;
    --  position:fixed;
    --  margin:80px 0;
    --  padding:4em 4em 3em;
    --  background:#FFF;
    --  border:1px solid #999;
    --  box-shadow:-10px 10px 40px #888;
    --  -moz-box-shadow:-10px 10px 40px #888;
    --  -webkit-box-shadow:-10px 10px 40px #888;
    --}
    --/* IE6 can't position fixed */
    --* html div#langMessage>div,
    --* html div#naMessage div { position:absolute; }
    --
    --div#naMessage strong {
    --  font-size:1.1em;
    --}
    --
    --div#langMessage .lang {
    --  display:none;
    --}
    --
    --/* --------------------------------------------------------------------------
    --Slideshow Controls & Next/Prev
    --*/
    --.slideshow-next, .slideshow-prev {
    --  width: 20px;
    --  height: 36px;
    --  text-indent: -1000em;
    --}
    --.slideshow-container {
    --  margin: 2em 0;
    --}
    --.slideshow-container:before, .slideshow-container:after {
    --  content: "";
    --  display: table;
    --  clear: both;
    --}
    --a.slideshow-next, a.slideshow-next:visited {
    --
    --  float: right;
    --
    --  background: url(../images/arrow-right.png) no-repeat 0 0
    --
    --}
    --
    --a.slideshow-prev, a.slideshow-prev:visited {
    --
    --  float: left;
    --
    --  background: url(../images/arrow-left.png) no-repeat 0 0
    --
    --}
    --
    --.slideshow-next:hover, .slideshow-prev:hover, .slideshow-next:focus, .slideshow-prev:focus {
    --
    --  background-position: 0 -36px
    --
    --}
    --
    --.slideshow-next:active, .slideshow-prev:active {
    --
    --  background-position: 0 -72px
    --
    --}
    --.slideshow-nav {
    --  width: 74px;
    --  margin: 0 auto;
    --}
    --.slideshow-nav a, .slideshow-nav a:visited {
    --  display: inline-block;
    --  width: 12px;
    --  height: 12px;
    --  margin: 0 2px 20px 2px;
    --  background: #ccc;
    --  -webkit-border-radius: 50%;
    --  -moz-border-radius: 50%;
    --  border-radius: 50%;
    --}
    --.slideshow-nav a:hover, .slideshow-nav a:focus {
    --
    --  background: #33B5E5
    --}
    --
    --.slideshow-nav a:active {
    --
    --  background: #1e799a;
    --  background: #ebebeb;
    --  -webkit-box-shadow: inset 0px 0px 5px 2px rgba(0, 0, 0, .05);
    --  -moz-box-shadow: inset 0px 0px 5px 2px rgba(0, 0, 0, .05);
    --  box-shadow: inset 0px 0px 5px 2px rgba(0, 0, 0, .05);
    --}
    --.slideshow-nav a.active, .slideshow-nav a.active:active, .slideshow-nav a.active:visited {
    --  background: #33B5E5
    --}
    --/* --------------------------------------------------------------------------
    --Tabs
    --*/
    --ul.tabs {
    --  padding: 0;
    --  margin: 2em 0 0 0;
    --}
    --ul.tabs:before, ul.tabs:after {
    --  content: "";
    --  display: table;
    --  clear: both;
    --}
    --ul.tabs li {
    --  list-style-type: none;
    --  float: left;
    --}
    --ul.tabs li a, ul.tabs li a:active, ul.tabs li a:visited {
    --  display: block;
    --  height: 36px;
    --  line-height: 36px;
    --  padding: 0 15px;
    --  margin-right: 2px;
    --  color: #222;
    --  -moz-border-radius-topleft: 2px;
    --  -moz-border-radius-topright: 2px;
    --  -moz-border-radius-bottomright: px;
    --  -moz-border-radius-bottomleft: px;
    --  -webkit-border-radius: 2px 2px px px;
    --  border-radius: 2px 2px px px;
    --  border-top: solid 1px #ebebeb;
    --  border-left: solid 1px #ebebeb;
    --  border-right: solid 1px #ebebeb;
    --  background-color: #fff;
    --    background-image: -webkit-gradient(linear, left top, left bottom, from(#ffffff), to(#fafafa));
    --    background-image: -webkit-linear-gradient(top, #ffffff, #fafafa);
    --    background-image: -moz-linear-gradient(top, #ffffff, #fafafa);
    --    background-image: -ms-linear-gradient(top, #ffffff, #fafafa);
    --    background-image: -o-linear-gradient(top, #ffffff, #fafafa);
    --    background-image: linear-gradient(top, #ffffff, #fafafa);
    --    filter: progid:DXImageTransform.Microsoft.gradient(startColorStr='#ffffff',
    --EndColorStr='#fafafa');
    --}
    --ul.tabs li a:hover {
    --  color: #33B5E5;
    --}
    --ul.tabs li a.selected {
    --  height: 37px;
    --  color: #33B5E5;
    --  background-color: #f7f7f7;
    --  background-image: none;
    --  border-color: #ddd;
    --}
    --.tab-content {
    --  padding: 1.2em;
    --  margin: -1px 0 2em 0;
    --  -webkit-border-radius: 2px;
    --    -moz-border-radius: 2px;
    --    border-radius: 2px;
    --  border: solid 1px #ddd;
    --  background: #f7f7f7;
    --}
    --/* --------------------------------------------------------------------------
    --Feature Boxes
    --*/
    --.feature-box {
    --  width: 291px;
    --  height: 200px;
    --  position: relative;
    --  background: #F7F7F7;
    --}
    --.box-border .top, .box-border .bottom, .box-border .left, .box-border .right {
    --  z-index: 100;
    --  position: absolute;
    --  background-color: #aaa;
    --}
    --.box-border .top, .box-border .bottom {
    --  width: 291px;
    --  height: 1px;
    --}
    --.dialog .box-border .top,
    --.dialog .box-border .bottom { width:391px; }
    --
    --.box-border .left, .box-border .right {
    --  width: 1px;
    --  height: 8px;
    --}
    --.box-border .top { top: 0; left: 0 }
    --.box-border .top .left { top: 1px; left: 0 }
    --.box-border .top .right { top: 1px; right: 0 }
    --.box-border .bottom .left { top: -8px; left: 0 }
    --.box-border .bottom { top: 200px; left: 0 }
    --.box-border .bottom .right { top: -8px; right: 0 }
    --
    --.feature-box h4,
    --.dialog h4 {
    --    padding: 15px 18px 10px;
    --}
    --
    --.feature-box p,
    --.dialog p {
    --    margin: 10px 18px;
    --    padding:0;
    --}
    --.feature-box .link,
    --.dialog .link {
    --    border-top: 1px solid #dedede;
    --    bottom: 0;
    --    position: absolute;
    --    width: inherit;
    --}
    --.feature-box a, .feature-box h4,
    --.dialog a, .dialog h4 {
    --    -webkit-transition: color .4s ease;
    --    -moz-transition: color .4s ease;
    --    -o-transition: color .4s ease;
    --    transition: color .4s ease;
    --}
    --.feature-box:hover {
    --  cursor: pointer;
    --}
    --.feature-box:hover .box-border .top, .feature-box:hover .box-border .bottom, .feature-box:hover
    --.left, .feature-box:hover .right {
    --  background-color: #33B5E5;
    --}
    --.feature-box:hover h4, .feature-box:hover a {
    --  color: #33B5E5;
    --}
    --/* --------------------------------------------------------------------------
    --Page-Specific Styles
    --*/
    --.colors {
    --  position: relative;
    --  float: left;
    --  width: 92px;
    --  margin: 40px 0 20px;
    --}
    --.colors div {
    --  color: #fff;
    --  font-size: 11.5px;
    --  width: 82px;
    --  height: 82px;
    --  margin-top:-30px;
    --  line-height: 82px;
    --  text-align: center;
    --  border: solid 5px #fff;
    --  -webkit-border-radius: 50%;
    --  -moz-border-radius: 50%;
    --  border-radius: 50%;
    --}
    --
    --
    --
    --
    --
    --
    --
    --
    --
    --
    --
    --
    --
    --
    --/* ########### REFERENCE DOCS ################## */
    --
    --#packages-nav h2,
    --#classes-nav h2 {
    --  font-size:18px;
    --  margin:0;
    --  padding:0 0 0 4px;
    --}
    --
    --/* not sure if this is needed in the ref docs, disabling for now
    --.jd-descr h2 {
    --  margin:16px 0;
    --}
    --*/
    --
    --/* First paragraph of a content pages is a bit larger
    --   - note the very specific selector. */
    --.jd-descr > p:first-child,
    --.jd-descr > #tb-wrapper + p,
    --.jd-descr > #qv-wrapper + p {
    --  font-size: 16px;
    --  margin-bottom: 16px;
    --}
    --
    --/* page-top-right container for reference pages (holds
    --links to summary tables) */
    --#api-info-block {
    --  font-size:12px;
    --  margin:20px 0 0;
    --  font-weight:normal;
    --  float:right;
    --  text-align:right;
    --  color:#999;
    --  max-width:300px;
    --  font-size: 12px;
    --  line-height:14px;
    --}
    --
    --#api-info-block div.api-level {
    --  font-weight:bold;
    --  font-size:inherit;
    --  float:none;
    --  color:#222;
    --  padding:0;
    --  margin:0;
    --}
    --
    --/* inheritance table */
    --table.inhtable>tbody>tr>td {
    --  padding-left:0;
    --}
    --table.inhtable>tbody>tr>td div:first-of-type {
    --  padding-left:12px;
    --}
    --
    --.jd-inheritance-table {
    --  border-spacing:0;
    --  margin:1em 0;
    --  padding:0;
    --  background-color:transparent;
    --}
    --.jd-inheritance-table tr td {
    --  border: none;
    --  margin: 0;
    --  padding: 0;
    --  background-color:transparent;
    --}
    --.jd-inheritance-table .jd-inheritance-space {
    --  width:2em;
    --}
    --.jd-inheritance-table .jd-inheritance-interface-cell {
    --  padding-left: 17px;
    --}
    --
    --
    --/* the link inside a sumtable for "Show All/Hide All" */
    --.toggle-all {
    --  display:block;
    --  float:right;
    --  font-weight:normal;
    --  font-size:0.9em;
    --}
    --
    --/* adjustments for in/direct subclasses tables */
    --.jd-sumtable-subclasses {
    --  margin: 1em 0 0 0;
    --  max-width:968px;
    --  background-color:transparent;
    --}
    --
    --/* extra space between end of method name and open-paren */
    --.sympad {
    --  margin-right: 2px;
    --}
    --
    --/* adjustments for the expando table-in-table */
    --.jd-sumtable-expando {
    --  margin:.5em 0;
    --  padding:0;
    --}
    --
    --/* a div that holds a short description */
    --.jd-descrdiv {
    --  padding:3px 1em 0 1em;
    --  margin:0;
    --  border:0;
    --}
    --
    --#jd-content img.jd-expando-trigger-img {
    --  padding:0 4px 4px 0;
    --  margin:0;
    --}
    --
    --.jd-sumtable-subclasses div#subclasses-direct,
    --.jd-sumtable-subclasses div#subclasses-indirect {
    --  /* left margin matches width of the toggle image,
    --     so this section aligns with the text above */
    --  margin:0 0 0 34px;
    --}
    --
    --
    --
    --/********* MEMBER REF *************/
    --
    --
    --.jd-details {
    --/*  border:1px solid #669999;
    --  padding:4px; */
    --  margin:0 0 1em;
    --}
    --
    --/* API reference: a container for the
    --.tagdata blocks that make up the detailed
    --description */
    --.jd-details-descr {
    --  padding:0;
    --  margin:.5em .25em;
    --}
    --
    --/* API reference: a block containing
    --a detailed description, a params table,
    --seealso list, etc */
    --.jd-tagdata {
    --  margin:.5em 1em;
    --}
    --
    --.jd-tagdata p {
    --  margin:0 0 1em 1em;
    --}
    --
    --/* API reference: adjustments to
    --the detailed description block */
    --.jd-tagdescr {
    --  margin:.25em 0 .75em 0;
    --}
    --
    --.jd-tagdescr ol,
    --.jd-tagdescr ul {
    --  margin:0 2.5em;
    --  padding:0;
    --}
    --
    --.jd-tagdescr table,
    --.jd-tagdescr img {
    --  margin:.25em 1em;
    --}
    --
    --.jd-tagdescr li {
    --margin:0 0 .25em 0;
    --padding:0;
    --}
    --
    --/* API reference: heading marking
    --the details section for constants,
    --attrs, methods, etc. */
    --h4.jd-details-title {
    --  font-size:1.15em;
    --  background-color: #E2E2E2;
    --  margin:1.5em 0 .6em;
    --  padding:3px 95px 3px 3px; /* room for api-level */
    --}
    --body.google h4.jd-details-title {
    --  background-color: #FFF;
    --  padding-top:5px;
    --  border-top: 1px solid #ccc;
    --}
    --
    --h4.jd-tagtitle {
    --  padding:0;
    --}
    --
    --h4 .normal {
    --  font-weight:normal;
    --}
    --
    --/* API reference: heading for "Parameters", "See Also", etc.,
    --in details sections */
    --h5.jd-tagtitle {
    --  padding:0 0 .25em 0;
    --  font-size:1em;
    --}
    --
    --.jd-tagtable {
    --  margin:0;
    --  background-color:transparent;
    --  width:auto;
    --}
    --
    --.jd-tagtable td,
    --.jd-tagtable th {
    --  border:none;
    --  background-color:#fff;
    --  vertical-align:top;
    --  font-weight:normal;
    --  padding:2px 10px;
    --}
    --
    --.jd-tagtable th {
    --  font-style:italic;
    --}
    --
    --
    --/* Inline api level indicator for methods */
    --div.api-level {
    --  font-size:.8em;
    --  font-weight:normal;
    --  color:#999;
    --  float:right;
    --  padding:0 8px 0;
    --  margin-top:-35px;
    --}
    --
    --table.jd-tagtable td,
    --table.jd-tagtable th {
    --  background-color:transparent;
    --}
    --
    --table.jd-tagtable th {
    --  color:inherit;
    --}
    --
    --/************ STICKY NAV BAR ******************/
    --
    --#context {
    --  clear: both;
    --  padding-top: 14px;
    --}
    --#context .breadcrumb {
    --  float: left;
    --  margin-bottom: 10px;
    --}
    --#context .util {
    --  float: right;
    --  margin-right: 20px;
    --}
    --
    --.breadcrumb {
    --  list-style: none;
    --  margin: 0;
    --  padding: 0;
    --  position: relative;
    --}
    --.breadcrumb li {
    --  float: left;
    --  padding: 0 20px 0 0;
    --  color: #000;
    --  white-space: nowrap;
    --}
    --.breadcrumb li a {
    --  color: #000;
    --}
    --.breadcrumb li:after {
    --  content: url(../images/breadcrumb.png);
    --  position: relative;
    --  top: 1px;
    --  left: 10px;
    --  width: 5px;
    --  height: 10px;
    --}
    --.breadcrumb li.current {
    --  font-weight: 700;
    --}
    --.breadcrumb li.current:after {
    --  display: none;
    --}
    --
    --/* offset the <a name=""> tags to account for sticky nav */
    --body.reference a[name]:not(.nav-start-marker) {
    --  visibility: hidden;
    --  display: block;
    --  position: relative;
    --  top: -56px;
    --
    --}
    --
    --.nav-start-marker {
    --  position: absolute;
    --}
    --
    --
    --/* Quicknav */
    --.btn-quicknav {
    --  width:20px;
    --  height:28px;
    --  float:left;
    --  margin-left:6px;
    --  padding-right:10px;
    --  position:relative;
    --  cursor:pointer;
    --  border-right:1px solid #CCC;
    --}
    --
    --.btn-quicknav a {
    --  zoom:1;
    --  position:absolute;
    --  top:13px;
    --  left:5px;
    --  display:block;
    --  text-indent:-9999em;
    --  width:10px;
    --  height:5px;
    --  background:url(../images/quicknav_arrow.png) no-repeat;
    --}
    --
    --.btn-quicknav a.arrow-active {
    --  background-position: 0 -5px;
    --  display:none;
    --}
    --
    --#header-wrap.quicknav a.arrow-inactive {
    --  display:none;
    --}
    --
    --.btn-quicknav.active a.arrow-active {
    --  display:block;
    --}
    --
    --#header-wrap.quicknav .nav-x li {
    --  min-width:160px;
    --  margin-right:20px;
    --}
    --
    --#header-wrap.quicknav li.last {
    --  margin-right:0px;
    --}
    --
    --#quicknav {
    -- float:none;
    -- clear:both;
    -- margin-left:0;
    -- margin-top:-30px;
    -- display:none;
    -- overflow:hidden;
    --}
    --
    --#header-wrap.quicknav #quicknav {
    --
    --}
    --
    --#quicknav ul {
    --  margin:10px 0;
    --  padding:0;
    --}
    --
    --#quicknav ul li.about {
    --  border-top:1px solid #9933CC;
    --}
    --
    --#quicknav ul li.design {
    --  border-top:1px solid #33b5e5;
    --}
    --
    --#quicknav ul li.develop {
    --  border-top:1px solid #FF8800;
    --}
    --
    --#quicknav ul li.distribute {
    --  border-top:1px solid #99cc00;
    --}
    --
    --#quicknav ul li {
    --  display:block;
    --  float:left;
    --  margin:0 20px 0 0;
    --  min-width:140px;
    --}
    --
    --#quicknav ul li.last {
    --  margin-right:0px;
    --}
    --
    --#quicknav ul li ul li {
    --  float:none;
    --}
    --
    --#quicknav ul li ul li a {
    --  color:#222;
    --}
    --
    --#quicknav ul li li ul,
    --#quicknav ul li li ul li {
    --  margin:0;
    --}
    --
    --#quicknav ul li li ul li:before {
    --  content:"\21B3";
    --}
    --
    --#header-wrap {
    --   -webkit-transition: all 0.25s ease-out;
    --      -moz-transition: all 0.25s ease-out;
    --       -ms-transition: all 0.25s ease-out;
    --        -o-transition: all 0.25s ease-out;
    --           transition: all 0.25s ease-out;
    --
    --}
    --
    --#header-wrap.quicknav {
    --  height:216px;
    --
    --}
    --
    --.moremenu {
    --  float: right;
    --  position: relative;
    --  width: 50px;
    --  height:28px;
    --  display: block;
    --  margin-top:-3px;
    --  margin-bottom:7px;
    --  overflow:hidden;
    --  -webkit-transition: width 0.25s ease;
    --     -moz-transition: width 0.25s ease;
    --       -o-transition: width 0.25s ease;
    --          transition: width 0.25s ease;
    --}
    --
    --.moremenu #more-btn {
    --  width:40px;
    --  height:28px;
    --  background:url(../images/icon_more.png) no-repeat;
    --  border-left:1px solid #CCC;
    --  float:left;
    --  cursor:pointer;
    --}
    --
    --.moremenu:hover #more-btn {
    --  background-position:0 -28px;
    --}
    --
    --.morehover {
    --  position:absolute;
    --  right:6px;
    --  top:-9px;
    --  width:40px;
    --  height:35px;
    --  z-index:99;
    --  overflow:hidden;
    --
    --  -webkit-opacity:0;
    --     -moz-opacity:0;
    --       -o-opacity:0;
    --          opacity:0;
    --
    --  -webkit-transform-origin:100% 0%;
    --     -moz-transform-origin:100% 0%;
    --       -o-transform-origin:100% 0%;
    --          transform-origin:100% 0%;
    --
    --  -webkit-transition-property: -webkit-opacity;
    --  -webkit-transition-duration: .25s;
    --  -webkit-transition-timing-function:ease;
    --
    --  -moz-transition-property: -moz-opacity;
    --  -moz-transition-duration: .25s;
    --  -moz-transition-timing-function:ease;
    --
    --  -o-transition-property: -o-opacity;
    --  -o-transition-duration: .25s;
    --  -o-transition-timing-function:ease;
    --
    --  transition-property: opacity;
    --  transition-duration: .25s;
    --  transition-timing-function:ease;
    --}
    --
    --.morehover:hover,
    --.morehover.hover {
    --  opacity:1;
    --  height:385px;
    --  width:268px;
    --  -webkit-transition-property:height,  -webkit-opacity;
    --}
    --
    --.morehover .top {
    --  width:268px;
    --  height:39px;
    --  background:url(../images/more_top.png) no-repeat;
    --}
    --
    --.morehover .mid {
    --  width:228px;
    --  background:url(../images/more_mid.png) repeat-y;
    --  padding:10px 20px 0 20px;
    --}
    --
    --.morehover .mid .header {
    --  border-bottom:1px solid #ccc;
    --  font-weight:bold;
    --}
    --
    --.morehover .bottom {
    --  width:268px;
    --  height:6px;
    --  background:url(../images/more_bottom.png) no-repeat;
    --}
    --
    --.morehover ul {
    --  margin:10px 10px 20px 0;
    --}
    --
    --.morehover ul li {
    --  list-style:none;
    --}
    --
    --.morehover ul li.active a,
    --.morehover ul li.active a:hover {
    --  color:#222 !important;
    --}
    --
    --.morehover ul li.active img {
    --  margin-right:4px;
    --}
    --
    --
    --
    --
    --/* MARQUEE */
    --.slideshow-container {
    --  width:100%;
    --  overflow:hidden;
    --  position:relative;
    --}
    --.slideshow-container .slideshow-prev {
    --  position:absolute;
    --  top:50%;
    --  left:0px;
    --  margin-top:-36px;
    --  z-index:99;
    --}
    --.slideshow-container .slideshow-next {
    --  position:absolute;
    --  top:50%;
    --  margin-top:-36px;
    --  z-index:99;
    --  right:0px;
    --}
    --
    --.slideshow-container .pagination {
    --  position:absolute;
    --  bottom:20px;
    --  width:100%;
    --  text-align:center;
    --  z-index:99;
    --}
    --.slideshow-container .pagination ul {
    --  margin:0;
    --}
    --.slideshow-container .pagination ul li{
    --  display: inline-block;
    --  width:12px;
    --  height:12px;
    --  text-indent:-8000px;
    --  list-style:none;
    --  margin: 0 3px;
    --  border-radius:6px;
    --  background-color:#ddd;
    --  cursor:pointer;
    --        -webkit-transition:color .5s ease-in;
    --        -moz-transition:color .5s ease-in;
    --        -o-transition:color .5s ease-in;
    --        transition:color .5s ease-in;
    --}
    --.slideshow-container .pagination ul li:hover {
    --  background-color:#bbb;
    --}
    --.slideshow-container .pagination ul li.active {
    --  background-color:#6ab344;
    --}
    --.slideshow-container .pagination ul li.active:hover {
    --  background-color:#6ab344;
    --}
    --.slideshow-container ul li {
    --  display:inline;
    --  list-style:none;
    --}
    --
    --
    --#landing h1 {
    --  padding:17px 0 20px 0 !important;
    --}
    --
    --a.download-sdk {
    --    float:right;
    --    margin:-10px 0;
    --    height:30px;
    --    padding-top:4px;
    --    padding-bottom:0px;
    --}
    --
    --#searchResults.wrap {
    --    max-width:940px;
    --    border-bottom:1px solid #e5e5e5;
    --}
    --
    --#searchResults.wrap #leftSearchControl {
    --  min-height:700px
    --}
    --
    --
    --
    --
    --
    --
    --
    --
    --
    --
    --/*
    -- * CSS Styles that are needed by jScrollPane for it to operate correctly.
    -- */
    --
    --.jspContainer {
    --  overflow: hidden;
    --  position: relative;
    --}
    --
    --.jspPane {
    --  position: absolute;
    --  width:100% !important; /* to avoid cut-off api names in reference in horiz scroll */
    --}
    --
    --.jspVerticalBar {
    --  position: absolute;
    --  top: 0;
    --  right: 0;
    --  width: 4px;
    --  height: 100%;
    --  background: #f5f5f5;
    --}
    --
    --.jspHorizontalBar {
    --  position: absolute;
    --  bottom: 0;
    --  left: 0;
    --  width: 100%;
    --  height: 4px;
    --  background: #f5f5f5;
    --}
    --
    --.jspVerticalBar *,
    --.jspHorizontalBar * {
    --  margin: 0;
    --  padding: 0;
    --}
    --.jspCap {
    --  display: block;
    --}
    --
    --.jspVerticalBar .jspCap {
    --  height: 4px;
    --}
    --
    --.jspHorizontalBar .jspCap {
    --  width: 0;
    --  height: 100%;
    --}
    --
    --.jspHorizontalBar .jspCap {
    --  float: left;
    --}
    --
    --.jspTrack {
    --  position: relative;
    --}
    --
    --.jspDrag {
    --  background: #ccc;
    --  position: relative;
    --  top: 0;
    --  left: 0;
    --  cursor: pointer;
    --}
    --
    --.jspDrag:hover,
    --.jspDrag:active {
    --  border-color: #09c;
    --  background-color: #4cadcb;
    --  background-image: -webkit-gradient(linear, left top, right top, from(#5dbcd9), to(#4cadcb));
    --  background-image: -webkit-linear-gradient(left, #5dbcd9, #4cadcb);
    --  background-image: -moz-linear-gradient(left, #5dbcd9, #4cadcb);
    --  background-image: -ms-linear-gradient(left, #5dbcd9, #4cadcb);
    --  background-image: -o-linear-gradient(left, #5dbcd9, #4cadcb);
    --  background-image: linear-gradient(left, #5dbcd9, #4cadcb);
    --  filter: progid:DXImageTransform.Microsoft.gradient(startColorStr='#5dbcd9', EndColorStr='#4cadcb');
    --}
    --
    --.jspHorizontalBar .jspTrack,
    --.jspHorizontalBar .jspDrag {
    --  float: left;
    --  height: 100%;
    --}
    --
    --.jspArrow {
    --  background: #999;
    --  text-indent: -20000px;
    --  display: block;
    --  cursor: pointer;
    --}
    --
    --.jspArrow.jspDisabled {
    --  cursor: default;
    --  background: #ccc;
    --}
    --
    --.jspVerticalBar .jspArrow {
    --  height: 16px;
    --}
    --
    --.jspHorizontalBar .jspArrow {
    --  width: 16px;
    --  float: left;
    --  height: 100%;
    --}
    --
    --.jspVerticalBar .jspArrow:focus {
    --  outline: none;
    --}
    --
    --.jspCorner {
    --  float: left;
    --  height: 100%;
    --}
    --
    --/* Yuk! CSS Hack for IE6 3 pixel bug :( */
    --* html .jspCorner {
    --  margin: 0 -3px 0 0;
    --}
    --/******* end of jscrollpane *********/
    --
    --
    --
    --
    --
    --/************ DEVELOP HOMEPAGE ******************/
    --
    --/* Slideshow */
    --.slideshow-develop {
    --  height: 316px;
    --  width: 940px;
    --  position: relative;
    --  overflow:hidden;
    --}
    --.slideshow-develop .frame {
    --  width: 940px;
    --  height: 316px;
    --}
    --.slideshow-develop img.play {
    --  max-width:350px;
    --  max-height:240px;
    --  margin:20px 0 0 90px;
    --  -webkit-transform: perspective(800px ) rotateY( 35deg );
    --  box-shadow: -16px 20px 40px rgba(0, 0, 0, 0.3);
    --  -moz-box-shadow: -16px 20px 40px rgba(0, 0, 0, 0.3);
    --  -webkit-box-shadow: -16px 20px 40px rgba(0, 0, 0, 0.3);
    --}
    --.slideshow-develop img.play.no-shadow {
    --    box-shadow: none;
    --    -moz-box-shadow: none;
    --    -webkit-box-shadow: none;
    --}
    --.slideshow-develop img.play.no-transform {
    --  -webkit-transform: none;
    --}
    --.slideshow-develop a.slideshow-next {
    --  background: url(../images/arrow-right-develop.png);
    --}
    --.slideshow-develop a.slideshow-prev {
    --  background: url(../images/arrow-left-develop.png);
    --}
    --.slideshow-develop .content-right {
    --  float: left;
    --}
    --.slideshow-develop .content-right h2 {
    --  padding:0;
    --  padding-bottom:10px;
    --  border:none;
    --  font-size:24px;
    --}
    --.slideshow-develop .item {
    --  height: 300px;
    --  width: 940px;
    --}
    --.slideshow-develop .pagination ul li.active {
    --  background-color: #F80;
    --}
    --.slideshow-develop .pagination ul li.active:hover {
    --  background-color: #F80;
    --}
    --.slideshow-develop .item hr {
    --  margin:5px 0 10px;
    --}
    --.slideshow-develop .item p {
    --  margin:10px 0;
    --}
    --.slideshow-develop .item p.title-intro {
    --  position:absolute;
    --  margin:0;
    --}
    --
    --/* Feeds */
    --.feed ul {
    --  margin: 0;
    --}
    --.feed .feed-nav {
    --  height: 25px;
    --  border-bottom: 1px solid #CCC;
    --}
    --.feed .feed-nav li {
    --  list-style: none;
    --  float: left;
    --  height: 21px; /* +4px bottom border = 25px; same as .feed-nav */
    --  margin-right: 25px;
    --  cursor: pointer;
    --}
    --.feed .feed-nav li.active {
    --  color: #000;
    --  border-bottom: 4px solid #F80;
    --}
    --.feed .feed-container {
    --  overflow: hidden;
    --  width: 460px;
    --}
    --.feed .feed-container .feed-frame {
    --  width: 1000px;
    --}
    --.feed .feed-container .feed-frame ul {
    --  float: left;
    --  width:460px;
    --}
    --.feed .feed-container .feed-frame ul ul {
    --  float: none;
    --  margin:10px 0 0 30px;
    --}
    --.feed .feed-container .feed-frame li {
    --  list-style: none;
    --  margin: 20px 0 20px 0;
    --  width: 460px;
    --  height:93px;
    --}
    --.feed .feed-container .feed-frame li.playlist {
    --  height:auto;
    --}
    --.feed .feed-container .feed-frame li.playlist a {
    --  height:93px;
    --  display:block;
    --}
    --.feed .feed-container .feed-frame li.more {
    --  height:20px;
    --  margin:10px 0 5px 5px;
    --}
    --.feed .feed-container .feed-frame li.more a {
    --  height:inherit;
    --}
    --.feed .feed-container .feed-frame li.playlist-video {
    --  list-style: none;
    --  margin: 0;
    --  width: 460px;
    --  height:55px;
    --  font-size:12px;
    --}
    --.feed .feed-container .feed-frame li.playlist-video a {
    --  height:45px;
    --  padding:5px;
    --}
    --.feed .feed-container .feed-frame li.playlist-video h5 {
    --  font-size:12px;
    --  line-height:13px;
    --  padding:0;
    --}
    --.feed .feed-container .feed-frame li.playlist-video p {
    --  margin:5px 0 0;
    --  line-height:15px;
    --}
    --.feed-container .feed-frame div.feed-image {
    --  float: left;
    --  border: 1px solid #999;
    --  margin:0 20px 0 0;
    --  width:122px;
    --  height:92px;
    --  background:url('../images/blog-default.png') no-repeat 0 0;
    --  background-size:180px;
    --}
    --#jd-content .feed .feed-container .feed-frame li img {
    --  float: left;
    --  border: 1px solid #999;
    --  margin:0 20px 0 0;
    --  width:122px;
    --  height:92px;
    --}
    --#jd-content .feed .feed-container .feed-frame li.playlist-video img {
    --  width:inherit;
    --  height:inherit;
    --}
    --
    --.feed .feed-container .feed-frame li a,
    --.feed .feed-container .feed-frame li a:active {
    --  color:#555 !important;
    --}
    --
    --.feed .feed-container .feed-frame li a:hover,
    --.feed .feed-container .feed-frame li a:hover * {
    --  color:#7AA1B0 !important;
    --}
    --
    --/* Video player */
    --#player-wrapper {
    --  display:none;
    --  margin: -1px auto 0;
    --  position: relative;
    --  max-width: 940px;
    --  height: 0px;
    --}
    --#player-frame {
    --  background: #EFEFEF;
    --  border: 1px solid #CCC;
    --  padding: 0px 207px;
    --  z-index: 10; /* stay above marque, but below search suggestions */
    --  width: 525px;
    --  height: 330px;
    --  position: relative;
    --}
    --#player-frame .close {
    --  position: absolute;
    --  right: 8px;
    --  bottom: 4px;
    --  width: 16px;
    --  height: 16px;
    --  margin: 0;
    --  text-indent: -1000em;
    --  top: 6px;
    --  background: url(../images/close.png) no-repeat 0 0;
    --  z-index:9999;
    --}
    --#player-frame .close:hover, #player-frame .close:focus {
    --  background-position: -16px 0;
    --  cursor:pointer;
    --}
    --
    --
    --
    --/************ DEVELOP TOPIC CONTAINERS ************/
    --
    --.landing-banner,
    --.landing-docs {
    --  margin:20px 0;
    --}
    --.landing-banner > div:first-child,
    --.landing-docs > div:first-child,
    --.landing-docs > .col-12 {
    --  margin-left:0;
    --  min-height:280px;
    --}
    --.landing-banner.short > div {
    --  min-height:50px;
    --}
    --.landing-banner > div:last-child,
    --.landing-docs > div:last-child,
    --.landing-docs > .col-12 {
    --  margin-right:0;
    --}
    --
    --.landing-banner > div > *:last-child {
    --  margin-bottom:0;
    --}
    --.landing-banner h1 {
    --  padding-top:16px;
    --  padding-bottom:24px;
    --}
    --.landing-docs,
    --.landing-banner {
    --  clear:both;
    --  overflow:hidden;
    --}
    --.landing-docs h3 {
    --  font-size:14px;
    --  line-height:21px;
    --  color:#555;
    --  text-transform:uppercase;
    --  border-bottom:1px solid #CCC;
    --  padding:0 0 20px;
    --}
    --.landing-docs a {
    --  color:#333 !important;
    --}
    --
    --.landing-docs a:hover,
    --.landing-docs a:hover * {
    --  color:#7AA1B0 !important
    --}
    --
    --.landing-docs .normal-links a {
    --  color:#039BE5 !important;
    --}
    --
    --.plusone {
    --  float:right;
    --}
    --
    --
    --
    --.next-docs {
    --  border-top:1px solid #ccc;
    --  margin:40px 0 0;
    --  padding:5px 0 0;
    --  clear:left;
    --  overflow:hidden;
    --}
    --.next-docs div:first-child {
    --  margin-left:0;
    --}
    --.next-docs div:last-child {
    --  margin-right:0;
    --}
    --
    --.next-docs h2 {
    --  font-size:14px;
    --  line-height:21px;
    --  color:#555;
    --  text-transform:uppercase;
    --  border-bottom:none;
    --  padding:5px 0 1em;
    --}
    --
    --
    --
    --/************* HOME/LANDING PAGE *****************/
    --
    --.slideshow-home {
    --  height: 500px;
    --  width: 940px;
    --  border-bottom: 1px solid #CCC;
    --  position: relative;
    --  margin: 0;
    --}
    --.slideshow-home .frame {
    --  width: 940px;
    --  height: 500px;
    --}
    --.slideshow-home .content-left {
    --  float: left;
    --  text-align: center;
    --  vertical-align: center;
    --  margin: 0 0 0 35px;
    --}
    --.slideshow-home .content-right {
    --  margin: 80px 0 0 0;
    --}
    --.slideshow-home .content-right p {
    --  margin-bottom: 10px;
    --}
    --.slideshow-home .content-right p:last-child {
    --  margin-top: 15px;
    --}
    --.slideshow-home .content-right h1 {
    --  padding:0;
    --}
    --.slideshow-home .item {
    --  height: 500px;
    --  width: 940px;
    --}
    --.home-sections {
    --  padding: 30px 20px 20px;
    --  margin: 20px 0;
    --  background: -webkit-linear-gradient(top, #F6F6F6,#F9F9F9);
    --}
    --.home-sections ul {
    --  margin: 0;
    --}
    --.home-sections ul li {
    --  float: left;
    --  display: block;
    --  list-style: none;
    --  width: 170px;
    --  height: 35px;
    --  border: 1px solid #ccc;
    --  background: white;
    --  margin-right: 10px;
    --  border-radius: 1px;
    --  -webkit-border-radius: 1px;
    --  -moz-border-radius: 1px;
    --  box-shadow: 1px 1px 5px #EEE;
    --  -webkit-box-shadow: 1px 1px 5px #EEE;
    --  -moz-box-shadow: 1px 1px 5px #EEE;
    --  background: white;
    --}
    --.home-sections ul li:hover {
    --  background: #F9F9F9;
    --  border: 1px solid #CCC;
    --}
    --.home-sections ul li a,
    --.home-sections ul li a:hover {
    --  font-weight: bold;
    --  margin-top: 8px;
    --  line-height: 18px;
    --  float: left;
    --  width: 100%;
    --  text-align: center;
    --  color: #039BE5 !important;
    --}
    --.home-sections ul li a {
    --  font-weight: bold;
    --  margin-top: 8px;
    --  line-height: 18px;
    --  float: left;
    --  width:100%;
    --  text-align:center;
    --}
    --.home-sections ul li img {
    --  float: left;
    --  margin: -8px 0 0 10px;
    --}
    --.home-sections ul li.last {
    --  margin-right: 0px;
    --}
    --
    --/************ DISTRIBUTE PAGES ******************/
    --
    --.article-detail #body-content {
    --  padding-top: 10px;
    --}
    --
    --/* A container for grid sets with uppercase h3 and rule */
    --.dynamic-grid h3 {
    --  font-size:14px;
    --  line-height:21px;
    --  color:#555;
    --  text-transform:uppercase;
    --  border-bottom:1px solid #CCC;
    --  padding:8px 0 14px 1px;
    --  clear:both;
    --}
    --
    --.top-right-float {
    --  float: right;
    --}
    --
    --.clearfloat {
    --  float: none;
    --  clear: both;
    --}
    --
    --
    --/**
    -- * UTILITIES
    -- */
    --
    --
    --.border-box {
    --  box-sizing: border-box;
    --}
    --
    --.vertical-center-outer {
    --  display: table;
    --  height: 100%;
    --  width: 100%;
    --}
    --
    --.vertical-center-inner {
    --  display: table-cell;
    --  vertical-align: middle;
    --}
    --
    --/**
    -- * TYPE STYLES
    -- */
    --
    --.landing-h1 {
    --  color: #44555d;
    --  font-weight: 300;
    --  font-size: 56px;
    --  line-height: 80px;
    --  text-align: center;
    --  letter-spacing: -1px;
    --  padding-bottom: 6px;
    --}
    --
    --.landing-pre-h1 {
    --  font-weight: 400;
    --  font-size: 28px;
    --  color: #93B73F;
    --  line-height: 36px;
    --  text-align: center;
    --  letter-spacing: -1px;
    --  text-transform: uppercase;
    --}
    --
    --.landing-h1.hero {
    --  text-align: left;
    --  color: #fff;
    --}
    --
    --.landing-h2 {
    --  font-weight: 300;
    --  font-size: 42px;
    --  line-height: 64px;
    --  text-align: center;
    --}
    --
    --.landing-subhead {
    --  color: #78868d;
    --  font-size: 20px;
    --  font-weight: 300;
    --  line-height: 32px;
    --  text-align: center;
    --}
    --.landing-subhead.hero {
    --  text-align: left;
    --  color: white;
    --}
    --
    --.landing-hero-description {
    --  text-align: left;
    --  margin: 1em 0;
    --}
    --
    --.landing-hero-description p {
    --  font-weight: 300;
    --  margin: 0;
    --  font-size: 18px;
    --  line-height: 24px;
    --}
    --
    --.landing-body .landing-small {
    --  font-size: 14px;
    --  line-height: 19px;
    --}
    --
    --.landing-body.landing-align-center {
    --  text-align: center;
    --}
    --
    --.landing-align-left {
    --  text-align: left;
    --}
    --
    --/**
    -- * LAYOUT
    -- */
    --
    --.landing-section {
    --  background: #eceff1;
    --  clear: both;
    --  padding: 80px 20px 80px;
    --  margin: 0 -20px;
    --  text-rendering: optimizeLegibility;
    --}
    --
    --@media (max-width: 719px) {
    --  .landing-section {
    --    margin-left: -10px;
    --    margin-right: -10px;
    --    padding-left: 10px;
    --    padding-right: 10px;
    --  }
    --}
    --
    --.landing-short-section {
    --  padding: 40px 10px 28px;
    --}
    --
    --.landing-gray-background {
    --  background-color: #b0bec5;
    --}
    --
    --.landing-white-background {
    --  background-color: white;
    --}
    --
    --.landing-red-background {
    --  color: white;
    --  background-color: hsl(8, 70%, 54%);
    --}
    --
    --.landing-red-background .landing-h1 {
    --  color: white;
    --}
    --
    --.landing-red-background .landing-subhead {
    --  color: hsl(8, 71%, 84%);
    --  text-align: left;
    --}
    --
    --
    --.preview-hero {
    --  height: calc(100vh - 128px);
    --  min-height: 504px;
    --  padding-top: 0;
    --  padding-bottom: 0;
    --  background-image: url(../../preview/images/hero.jpg);
    --  background-size: cover;
    --  background-position: right center;
    --  color: white;
    --  position: relative;
    --  overflow: hidden;
    --}
    --
    --.wear-hero {
    --  height: calc(100vh - 128px);
    --  min-height: 504px;
    --  padding-top: 0;
    --  padding-bottom: 0;
    --  background-image: url(../../wear/images/hero.jpg);
    --  background-size: cover;
    --  background-position: top center;
    --  color: white;
    --  position: relative;
    --  overflow: hidden;
    --}
    --
    --.tv-hero {
    --  height: calc(100vh - 128px);
    --  min-height: 504px;
    --  padding-top: 0;
    --  padding-bottom: 0;
    --  background-image: url(../../tv/images/hero.jpg);
    --  background-size: cover;
    --  background-position: right center;
    --  color: white;
    --  position: relative;
    --  overflow: hidden;
    --}
    --
    --.auto-hero {
    --  height: calc(100vh - 128px);
    --  min-height: 504px;
    --  padding-top: 0;
    --  padding-bottom: 0;
    --  background-image: url(../../auto/images/hero.jpg);
    --  background-size: cover;
    --  background-position: right center;
    --  color: white;
    --  position: relative;
    --  overflow: hidden;
    --}
    --
    --.landing-hero-scrim {
    --  background: black;
    --  height: 100%;
    --  left: 0;
    --  position: absolute;
    --  opacity: .2;
    --  width: 100%;
    --}
    --
    --.landing-hero-wrap {
    --  margin: 0 auto;
    --  max-width: 940px;
    --  clear: both;
    --  height: 100%;
    --  position: relative;
    --}
    --
    --.landing-section-header {
    --  margin-bottom: 40px;
    --}
    --
    --.landing-hero-wrap .landing-section-header {
    --  margin-bottom: 16px;
    --}
    --
    --.landing-body {
    --  font-size: 18px;
    --  line-height: 24px;
    --}
    --
    --.landing-video-link {
    --  white-space: nowrap;
    --  display: inline-block;
    --  padding: 16px 32px 16px 82px;
    --  font-size: 18px;
    --  font-weight: 400;
    --  line-height: 24px;
    --  cursor: pointer;
    --  color: hsla(0, 0%, 100%, .8);
    --  -webkit-user-select: none;
    --     -moz-user-select: none;
    --       -o-user-select: none;
    --  user-select: none;
    --  -webkit-transition: .2s color ease-in-out;
    --     -moz-transition: .2s color ease-in-out;
    --       -o-transition: .2s color ease-in-out;
    --  transition: .2s color ease-in-out;
    --}
    --
    --.landing-video-link:before {
    --  height: 64px;
    --  width: 64px;
    --  display: inline-block;
    --  background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAGAAAABgCAYAAADimHc4AAAFuklEQVR42u2dXWgcVRSAV9LWtBBTTZVWUhNqEQtq1QeroDRKFRFsROqTYPuo+JCiIoJKFC0USqlUfCiowRcfrBgVUUElefAPkW5T8aeaGn9aRbFsjP0x2cx8PuRMvFxmdjeb2Z17Z8+B85DsZPbO+eaec3/OPSkABdXsVI2gABSAqgJQAKoKQAGoKgAFoKoAFICqAlAAqgpAAai6DqDRAiwDeoFtwB7gPaAInABKwKToCWAMeB/YDdwJrAWWNLh9+QMAXABsBQ4A3wFTwAxQBmaBAAhjNJDPy3L938BXwAvArUCHAkh+kCXAVcA+YBw4bRg7MngtkgTlDPA98CywHmhTAP8/xCbgVeAvMZZpwDQllN7xB/AysKGlAQAXAvuBkzW85UVgCBgENlfQQbmuWAXELPAnsAvoaikAQBtwh/j3coLhS2LIfqCzzu/plL8fkvvFgZiR4L2lHrfkHQBgpQTFUwmGnwC212v0KjC2y/3jQPwDPA+05xYAcBHwubx1YZzhC02QBBBRbxgBzssdAOBy4JgRZE0ZTPuNr7FHDCbEhqNAd24AAN0yUbID7QSwsZChABut3hANXY8Bq70HIMb/Ocb4w81+66v0hmGrN0QQ1ngLQJYRvpWHMWWo4KDIaMnuCcVKgdlZAGL8t2J8vpPGrwChDLyWBMFlAA8D0z4ZvwKEs8D93gCQEc9Jy/jFgkdizaRDGUSs8wXAu1bQLQE9ngHosWbPAXDQeQAypT9rBd3+gociyxi2K9riLABZUj5iuZ6RgsciM2OzFxw2A7JrAO6VwGtKTwpG+Anoy9AVmb3gDHCPcwCAFcChRox6jPu9CazMeFQUAKNRL3AJwE2yopjq228BQPZ/d2bcCyaBTa4BeNGa8Q6naIA4GQWubiKEYWvBbp8zAGQt5VfL/fQ3GEAkTzXDLVkjokA2k5a7AuA2GaLNj/tTfvhq0pQgbcwLQtlQusYVALtlzSR191MjADNI9zbJDZWBR10BMGr5/4GMADQ0SAMDlht62xUAxy0AmzMEEMnhtIO0ZF2YAH5wITd0hQw/5wE04M1bjDyXZpC2hqMlYGnWAHqBf40APOEYgChI35VSWyasWfGqrAH0WVkOIw4CSC1IG2tDoSy7XJE1gPs8ArDoIG0BmJGk30wBDHgGYFFBOgbAtqwB7GxxAHerC8rOBU0Dt2gQzjYIb8gawDor+6HVhqFdrkzEwhabiAVOTMSkUb+06FLEUVfWgj5q0cW4g64AeNo66ZLlcnTDNmesBN4y8KArAG6QU42ttCEzBVzpCoAO4EfLDeV5SzIEvgHaXdqUP2BlQud1Ux55zj2uZUX02cPRnKalRLmu17qYmPWF5YbymJgVAh8Ay5wCII3ZEZOYm6fURGT2u9X43Mnk3CDHybmfmRVYXExPv9nKEcpLejqSC3SjdY2TBzTesHqB7wc0onTEV2KucxLApXKkJy9HlAI5anuJFwCkYQ/EuCJfD+mdBnYkXOssgHY53un7MdVZ4CVgqVcADAhjMafkfTioHc14P04yvvMApIEXy5F/+7S8y6UKolPyR4BVVf7Wi2IdawwIPhTrmAW+rmZ8bwBIQ7vloXwoVzNWS6UUrwAYy9YfOlqwKZDkgneA5Qu4l3cly84F9sqGhislywLmaozuYoGFXr0DII1ukxP1hxJ6QzR7HqLxRfumZaRzXZ3f4XXZyi7gCeB3kqsnzs+kSb9s5XHgMeD8RTxDLgq3rmeuYuFvNYCoR8wqujNi+L3UWBcu9wAMt3QZ8LiMlk5RuU50teq6kcEDgTolveIRYHUQBOek1O5cFu/ukLz7/ZJgNSm+OirebWpgaPS7slxfAr4EngGuX8jopqUBxGzyrAVuB54EXgc+lV4yLhO8cfn5E+ZqUD8kBu9sQvv0Hzj4rmoEBaAAVBWAAlBVAApAVQEoAFUFoABUFYACUFUACkC1CfofXVRJocowZVYAAAAASUVORK5CYII=);
    --  background-size: contain;
    --  position: absolute;
    --  content: "";
    --  opacity: .7;
    --  margin-top: -19px;
    --  margin-left: -64px;
    --  -webkit-transition: .2s opacity ease-in-out;
    --     -moz-transition: .2s opacity ease-in-out;
    --       -o-transition: .2s opacity ease-in-out;
    --  transition: .2s opacity ease-in-out;
    --}
    --
    --.landing-video-link:hover {
    --  color: hsla(0, 0%, 100%, 1);
    --}
    --
    --.landing-video-link:hover:before {
    --  opacity: 1;
    --}
    --
    --.landing-social-image {
    --  float: left;
    --  margin-right: 14px;
    --  height: 64px;
    --  width: 64px;
    --}
    --
    --.landing-social-copy {
    --  padding-left: 78px;
    --}
    --
    --.landing-scroll-down-affordance {
    --  position: absolute;
    --  bottom: 0;
    --  width: 100%;
    --  text-align: center;
    --  z-index: 10;
    --}
    --
    --.landing-down-arrow {
    --  padding: 24px;
    --  display: inline-block;
    --  opacity: .5;
    --  -webkit-transition: .2s opacity ease-in-out;
    --     -moz-transition: .2s opacity ease-in-out;
    --       -o-transition: .2s opacity ease-in-out;
    --  transition: .2s opacity ease-in-out;
    --
    --  -webkit-animation-name: pulse-opacity;
    --  -webkit-animation-duration: 4s;
    --}
    --
    --.landing-down-arrow:hover {
    --  opacity: 1;
    --}
    --
    --.landing-down-arrow img {
    --  height: 28px;
    --  width: 28px;
    --  margin: 0 auto;
    --  display: block;
    --}
    --
    --.landing-divider {
    --  display: inline-block;
    --  height: 2px;
    --  background-color: white;
    --  position: relative;
    --  margin: 10px 0;
    --}
    --
    --/* 3 CLOLUMN LAYOUT */
    --
    --.landing-breakout {
    --  margin-top: 40px;
    --  margin-bottom: 40px;
    --}
    --
    --.landing-breakout img {
    --  margin-bottom: 20px;
    --}
    --
    --.landing-partners img {
    --  margin-bottom: 20px;
    --}
    --
    --.landing-breakout p {
    --  padding: 0 23px;
    --}
    --
    --.landing-breakout.landing-partners img {
    --  margin-bottom: 20px;
    --}
    --
    --/**
    -- * ANIMATION
    -- */
    --
    --@-webkit-keyframes pulse-opacity {
    --  0% {
    --    opacity: .5;
    --  }
    --  20% {
    --    opacity: .5;
    --  }
    --  40% {
    --    opacity: 1;
    --  }
    --  60% {
    --    opacity: .5;
    --  }
    --  80% {
    --    opacity: 1;
    --  }
    --  100% {
    --    opacity: .5;
    --  }
    --}
    --
    --
    --/******************
    --Styles for d.a.c/index:
    --*******************/
    --
    --
    --
    --/* Generic full screen carousel styling to be used across pages. */
    --.fullscreen-carousel {
    --  margin: 0 -20px;
    --  overflow: hidden;
    --  position: relative;
    --}
    --
    --.fullscreen-carousel-content {
    --  width: 100%;
    --  height: 100%;
    --  position: relative;
    --  display: table; /* For vertical centering */
    --}
    --
    --.fullscreen-carousel .vcenter {
    --  display: table-cell;
    --  vertical-align: middle;
    --  position: relative;
    --}
    --
    --.fullscreen-carousel .vcenter > div {
    --  margin: 10px auto;
    --}
    --
    --/* Styles for the full-bleed hero image type. */
    --.fullscreen-carousel .hero, .fullscreen-carousel .hero h1 {
    --  color: #fff;
    --}
    --
    --.fullscreen-carousel .hero h1 {
    --  font-weight: 300;
    --  font-size: 60px;
    --  line-height: 68px;
    --  letter-spacing: -1px;
    --  padding-top: 0;
    --}
    --
    --.fullscreen-carousel .hero p {
    --  font-weight: 300;
    --  font-size: 18px;
    --  line-height: 24px;
    --}
    --
    --.fullscreen-carousel .hero .hero-bg {
    --  background-size: cover;
    --  width: 100%;
    --  height: 100%;
    --  position: absolute;
    --  left: 0px;
    --  top: 0px;
    --}
    --
    --
    --/* Full screen carousel styling for the resource flow layout type of content */
    --.fullscreen-carousel .resource-flow-layout:after {
    --  height: 0; /* Dont know why this is set at 10 in default.css */
    --}
    --
    --.fullscreen-carousel .resource-flow-layout {
    --  margin-bottom: 20px;
    --}
    --
    --
    --
    --/* Generic Tab carousel styling to be used across multiple pages. */
    --
    --.tab-carousel .tab-nav {
    --  list-style: none;
    --  position: relative;
    --  text-align: center;
    --}
    --
    --.tab-carousel .tab-nav li {
    --  display: inline-block;
    --  font-size: 22px;
    --  font-weight: 400;
    --  line-height: 50px;
    --  list-style: none;
    --  margin: 0;
    --  padding: 0 25px;
    --  position: relative;
    --}
    --
    --.tab-carousel .tab-nav li a,
    --.tab-carousel .tab-nav li a:hover {
    --  color: #333 !important;
    --  padding: 10px 10px 13px 10px;
    --  position: relative;
    --  z-index: 1000;
    --}
    --
    --.tab-carousel .tab-nav li:after {
    --  background: #ddd;
    --  bottom: 0;
    --  content: '';
    --  height: 4px;
    --  left: 0;
    --  position: absolute;
    --  width: 100%;
    --  z-index: 0;
    --}
    --
    --.tab-carousel .tab-nav .highlight {
    --  position: absolute;
    --  height: 4px;
    --  width: 100px;
    --  bottom: 0;
    --  background: #33b5e5;
    --}
    --
    --.tab-carousel .tab-carousel-content {
    --  position: relative;
    --  overflow: hidden;
    --  white-space: nowrap;
    --}
    --
    --.tab-carousel .tab-carousel-content [data-tab] {
    --  display: inline-block;
    --  white-space: normal;
    --}
    --
    --
    --
    --/*
    --  Resource styling for the tab carousel. The tab carousel contains either
    --  a 3 column layout of resources or a single full-width resource. The
    --  latter has the 18x12 class applied to it and can be styled differently
    --  that way.
    --*/
    --
    --.tab-carousel .resource .image {
    --  width: 100%;
    --  height: 250px;
    --  background-repeat: no-repeat;
    --  background-size: contain;
    --  background-position: 50% 50%;
    --}
    --
    --.tab-carousel .resource .info .title {
    --  font-size: 18px;
    --  line-height: 24px;
    --}
    --
    --.tab-carousel .resource .info .summary,
    --.tab-carousel .resource .info .cta {
    --  line-height: 24px;
    --  font-size: 16px;
    --}
    --
    --.tab-carousel .resource-card-18x12 {
    --  position: relative;
    --  padding-left: 450px;
    --  box-sizing: border-box;
    --  display: table-cell;
    --  vertical-align: middle;
    --}
    --
    --.tab-carousel .resource-card-18x12 .image {
    --  position: absolute;
    --  width: 420px;
    --  height: 100%;
    --  left: 0;
    --  top: 0;
    --}
    --
    --.tab-carousel .resource-card-18x12 .info {
    --  display: inline-block;
    --}
    --
    --.tab-carousel .resource-card-18x12 .info .title {
    --  margin-bottom: 26px;
    --}
    --
    --/*
    --  Specific styles for new home page layout of the carousels.
    --*/
    --
    --/* Big blue button */
    --a.home-new-cta-btn,
    --.home-new-carousel-1 .resource-card-18x6 .cta {
    --  white-space: nowrap;
    --  display: inline-block;
    --  padding: 14px 32px;
    --  font-size: 18px;
    --  font-weight: 500;
    --  line-height: 24px;
    --  cursor: pointer;
    --  background: #33b5e6;
    --  border-radius: 4px;
    --  margin-top: 20px;
    --  color: #fff;
    --  transition: 0.2s background-color ease-in-out;
    --}
    --
    --.home-new-carousel-1 .resource-card-18x6 .cta:after {
    --  display: none; /* Hide the entity for this button */
    --}
    --
    --a.home-new-cta-btn:hover,
    --.home-new-carousel-1 .resource-card-18x6 .cta:hover {
    --  color: #fff !important;
    --  background: #2d9fca;
    --}
    --
    --.home-new-carousel-1 .resource-card-18x6 .cta {
    --  position: absolute;
    --  bottom: 20px;
    --  left: 16px;
    --}
    --
    --/* Fullscreen carousel. */
    --.home-new-carousel-1 {
    --  max-height: 700px; /* Set max height so doesn't get too long */
    --}
    --
    --.home-new-carousel-1 .fullscreen-carousel-content {
    --  min-height: 450px;  /* Set min height for all content */
    --}
    --
    --.home-new-carousel-1 .hero {
    --  background: #000;
    --}
    --
    --.home-new-carousel-1 .hero-bg {
    --  background-image: url(/home-new/images/hero.jpg);
    --  background-position: right center;
    --  opacity: 0.85;
    --}
    --
    --/*
    --  Styling for special top card of full screen layout resource layout.
    --  We need to specifically style the 18x6 card to adjust its size and layout,
    --  since it's not a standard card, not sure if this is unique to the home page
    --  layout or should be namespaced within the fullscreen-carousel container.
    --*/
    --.home-new-carousel-1 .resource-flow-layout.col-16 .resource-card-18x6 {
    --  height: 320px;
    --  background-color:#F9F9F9;
    --  border-radius: 0px;
    --  box-shadow: 0px 0px 0px rgba(0, 0, 0, 0);
    --
    --}
    --
    --.home-new-carousel-1 .resource-card-18x6 .card-bg {
    --  width: 636px;
    --  height: 100%;
    --}
    --
    --.home-new-carousel-1 .resource-card-18x6 .card-info {
    --  right: 0px;
    --  left: 636px;
    --  height: 100%;
    --  top: 0px;
    --  padding: 15px 22px;
    --}
    --
    --.home-new-carousel-1 .resource-card-18x6 .card-info .util {
    --  display: none;
    --}
    --
    --.home-new-carousel-1 .resource-card-18x6 .card-info .title {
    --  font-size: 20px;
    --  font-weight: 500;
    --  margin-top: 15px;
    --  margin-bottom: 15px;
    --}
    --
    --.home-new-carousel-1 .resource-card-18x6 .card-info .text {
    --  font-size: 15px;
    --  line-height: 21px;
    --}
    --
    --
    --/* Tabbed carousel. */
    --.home-new-carousel-2 {
    --  margin: 35px auto 100px auto;
    --}
    --
    --.home-new-carousel-2 h1 {
    --  font-size: 47px;
    --  font-weight: 100;
    --  line-height: 54px;
    --  text-align: center;
    --}
    --
    --.annotation-message {
    --    display: block;
    --    font-style: italic;
    --    color: #F80;
    --}
    --
    --
    --
    --/* Helpouts widget */
    --.resource-card-6x2.helpouts-card {
    --  width: 255px;
    --  height: 40px;
    --  position:absolute;
    --  z-index:999;
    --  top:-8px;
    --  right:1px;
    --}
    --
    --.resource-card-6x2.helpouts-card > .card-info {
    --  left:35px;
    --  height:35px;
    --  padding:4px 8px 4px 0;
    --}
    --
    --.resource-card-6x2.helpouts-card > .card-info .helpouts-description {
    --  display:block;
    --  overflow:visible;
    --  font-size:12px;
    --  line-height:12px;
    --  text-align:right;
    --  color:#666;
    --}
    --
    --.helpouts-description .link-color {
    --  text-transform: uppercase;
    --}
    --
    --.resource-card-6x2 > .card-bg.helpouts-card-bg {
    --  width:35px;
    --  height:35px;
    --  margin:2px 0 0 0;
    --  background-image: url(../images/styles/helpouts-logo-35_2x.png);
    --  background-image: -webkit-image-set(url(../images/styles/helpouts-logo-35.png) 1x, url(../images/styles/helpouts-logo-35_2x.png) 2x);
    --}
    --
    --.resource-card-6x2 > .card-bg.helpouts-card-bg:after {
    --  display:none;
    --}
    --
    --#tb li:before, #qv li:before {
    --  background-position: 0px -196px;
    --  height: 24px;
    --  width: 24px;
    --  content: '';
    --  left: -8px;
    --  opacity: .7;
    --  position: absolute;
    --  top: -4px;
    --}
    --
    --/* CHANGE EXISTING SELECTOR FOR ANDROID M HERO ONLY
    --   REMOVE THE BELOW STYLES WHEN THE ANDROID M CAROUSEL
    --   GRAPHIC ON THE MAIN LANDING IS TAKEN DOWN */
    --.dac-hero.mprev {
    --  background-color: #fff;
    --  background-position: 50% 53%;
    --  background-size: cover;
    --  background-image: url(../images/home/android_m_hero_1200.jpg);
    --  box-sizing: border-box;
    --  font-size: 16px;
    --  min-height: 550px;
    --  padding-top: 88px;
    --}
    --.dac-hero.dac-darken.mprev::before {
    --  background: rgba(0, 0, 0, 0.3);
    --  bottom: 0;
    --  content: '';
    --  display: block;
    --  left: 0;
    --  position: absolute;
    --  right: 0;
    --  top: 0;
    --}
    --
    --.dac-hero.dac-darken.mprev::before {
    --  background: -webkit-linear-gradient(top, rgba(0, 0, 0, .05), rgba(0, 0, 0, .05), #000 950px);
    --  background: linear-gradient(to bottom, rgba(0, 0, 0, .05), rgba(0, 0, 0, 0.05), #000 950px);
    --}
    --
    --@media (max-width: 719px) {
    --  .dac-hero.dac-darken.mprev {
    --    background-size: auto 600px;
    --    background-position: 55% 0;
    --    background-repeat: no-repeat;
    --  }
    --
    --  .dac-hero-figure.mprev {
    --    height: 10px;
    --    margin: 15px 0;
    --  }
    --}
    --
    --@media (max-width: 719px) {
    --  .dac-hero.dac-darken.mprev {
    --    background-size: auto 600px;
    --    background-position: 55% 0;
    --    background-repeat: no-repeat;
    --  }
    --
    --  .dac-hero-figure.mprev {
    --    height: 10px;
    --    margin: 15px 0;
    --  }
    --}
    --
    --@media (max-width: 1200px) {
    --  .dac-hero.dac-darken.mprev {
    --    background-size: auto 700px;
    --    background-position: 55% 0;
    --    background-repeat: no-repeat;
    --  }
    --
    --  .dac-hero-cta.mprev {
    --    white-space:nowrap;
    --  }
    --}
    --
    --@charset "UTF-8";
    --/**
    -- * Fades out an element.
    -- * Applies visibility hidden when the transition is finished.
    -- *
    -- * Use opacity: 1; to show the element.
    -- */
    --.dac-visible-mobile-block, .dac-mobile-only,
    --.dac-visible-mobile-inline,
    --.dac-visible-mobile-inline-block,
    --.dac-visible-tablet-block,
    --.dac-visible-tablet-inline,
    --.dac-visible-tablet-inline-block,
    --.dac-visible-desktop-block,
    --.dac-visible-desktop-inline,
    --.dac-visible-desktop-inline-block {
    --  display: none !important;
    --}
    --
    --@media (max-width: 719px) {
    --  .dac-hidden-mobile {
    --    display: none !important;
    --  }
    --
    --  .dac-visible-mobile-block, .dac-mobile-only {
    --    display: block !important;
    --  }
    --
    --  .dac-visible-mobile-inline {
    --    display: inline !important;
    --  }
    --
    --  .dac-visible-mobile-inline-block {
    --    display: inline-block !important;
    --  }
    --}
    --
    --@media (min-width: 720px) and (max-width: 979px) {
    --  .dac-hidden-tablet {
    --    display: none !important;
    --  }
    --
    --  .dac-visible-tablet-block {
    --    display: block !important;
    --  }
    --
    --  .dac-visible-tablet-inline {
    --    display: inline !important;
    --  }
    --
    --  .dac-visible-tablet-inline-block {
    --    display: inline-block !important;
    --  }
    --}
    --
    --@media (min-width: 980px) {
    --  .dac-hidden-desktop {
    --    display: none !important;
    --  }
    --
    --  .dac-visible-desktop-block {
    --    display: block !important;
    --  }
    --
    --  .dac-visible-desktop-inline {
    --    display: inline !important;
    --  }
    --
    --  .dac-visible-desktop-inline-block {
    --    display: inline-block !important;
    --  }
    --}
    --
    --.dac-offset-parent {
    --  position: relative !important;
    --}
    --
    --/**
    -- * Hide from browsers/screenreaders on all sizes.
    -- */
    --.dac-hidden {
    --  display: none !important;
    --}
    --
    --/**
    -- * Break strings when their length exceeds the width of their container.
    -- */
    --.dac-text-break {
    --  word-wrap: break-word !important;
    --}
    --
    --/**
    -- * Horizontal text alignment
    -- */
    --.dac-text-center {
    --  text-align: center !important;
    --}
    --
    --.dac-text-left {
    --  text-align: left !important;
    --}
    --
    --.dac-text-right {
    --  text-align: right !important;
    --}
    --
    --/**
    -- * Prevent whitespace wrapping
    -- */
    --.dac-text-no-wrap {
    --  white-space: nowrap !important;
    --}
    --
    --/**
    -- * Prevent text from wrapping onto multiple lines, instead truncate with an ellipsis.
    -- */
    --.dac-text-truncate {
    --  max-width: 100%;
    --  overflow: hidden !important;
    --  text-overflow: ellipsis !important;
    --  white-space: nowrap !important;
    --  word-wrap: normal !important;
    --}
    --
    --/**
    -- * Floats
    -- */
    --.dac-float-left {
    --  float: left !important;
    --}
    --
    --.dac-float-right {
    --  float: right !important;
    --}
    --
    --/**
    -- * New block formatting context
    -- *
    -- * This affords some useful properties to the element. It won't wrap under
    -- * floats. Will also contain any floated children.
    -- * N.B. This will clip overflow. Use the alternative method below if this is
    -- * problematic.
    -- */
    --.dac-nbfc {
    --  overflow: hidden !important; }
    --
    --/**
    -- * New block formatting context (alternative)
    -- *
    -- * Alternative method when overflow must not be clipped.
    -- *
    -- * N.B. This breaks down in some browsers when elements within this element
    -- * exceed its width.
    -- */
    --.dac-nbfc-alt {
    --  display: table-cell !important;
    --  width: 10000px !important; }
    --
    --/* New CSS */
    --/************ RESOURCE CARDS ******************/
    --/* Basic card-styling with shadow */
    --.resource-card {
    --  background: #fff;
    --  box-shadow: 0px 1px 3px 0px rgba(0, 0, 0, 0.21);
    --  display: block;
    --  position: relative; }
    --
    --/* Play button is only visible on 6by6 cards */
    --.play-button {
    --  background-color: #000;
    --  border-radius: 50%;
    --  box-sizing: border-box;
    --  display: none;
    --  height: 70px;
    --  line-height: 65px;
    --  padding-left: 4px;
    --  position: absolute;
    --  opacity: .6;
    --  text-align: center;
    --  -webkit-transition: opacity .5s;
    --          transition: opacity .5s;
    --  width: 70px;
    --  z-index: 1; }
    --  .resource-card-6x2 .play-button {
    --    display: block;
    --    left: 10px;
    --    top: 15px;
    --    -webkit-transform: scale(0.73);
    --        -ms-transform: scale(0.73);
    --            transform: scale(0.73); }
    --  .resource-card-6x6 .play-button {
    --    display: block;
    --    left: 50%;
    --    margin-left: -35px;
    --    top: 50px; }
    --
    --/* Styling for background image including tinting and section icons in stacks */
    --.card-bg {
    --  bottom: 131px;
    --  display: block;
    --  position: absolute;
    --  vertical-align: top;
    --  width: 100%;
    --  left: 0;
    --  top: 0;
    --  background-size: cover;
    --  background-repeat: no-repeat;
    --  background-position: center;
    --  background-image: url(../images/resource-card-default-android.jpg); }
    --  .card-bg:after {
    --    content: "";
    --    display: block;
    --    height: 100%;
    --    width: 100%;
    --    opacity: 1;
    --    background: rgba(0, 0, 0, 0.05);
    --    -webkit-transition: opacity 0.5s;
    --            transition: opacity 0.5s; }
    --  .static .card-bg:after {
    --    display: none; }
    --  .card-bg .card-section-icon {
    --    position: absolute;
    --    top: 50%;
    --    width: 100%;
    --    margin-top: -35px;
    --    text-align: center;
    --    padding-top: 65px;
    --    z-index: 100; }
    --    .card-bg .card-section-icon .icon {
    --      position: absolute;
    --      left: 50%;
    --      margin-left: -28px;
    --      top: 0px;
    --      width: 56px;
    --      height: 56px;
    --      background-repeat: no-repeat;
    --      background-position: 50% 50%;
    --      background-image: url(../images/stack-icon.png); }
    --    .card-bg .card-section-icon .section {
    --      text-transform: uppercase;
    --      color: white;
    --      font-size: 14px; }
    --
    --.card-info {
    --  position: absolute;
    --  box-sizing: border-box;
    --  height: 131px;
    --  right: 0;
    --  bottom: 0;
    --  left: 0;
    --  overflow: hidden;
    --  background: #fefefe;
    --  padding: 6px 12px;
    --}
    --
    --.card-info .section {
    --  color: #898989;
    --  font-size: 11px;
    --  font-weight: 700;
    --  letter-spacing: .3px;
    --  line-height: 20px;
    --  text-transform: uppercase;
    --}
    --
    --.card-info .title {
    --  color: #333;
    --  font-size: 18px;
    --  font-weight: 500;
    --  line-height: 23px;
    --  margin-bottom: 7px;
    --  max-height: 46px;
    --  overflow: hidden;
    --  text-overflow: ellipsis;
    --  white-space: normal;
    --}
    --
    --.card-info .description {
    --  overflow: hidden;
    --}
    --
    --.card-info .description .text {
    --  color: #666;
    --  font-size: 14px;
    --  height: 60px;
    --  line-height: 20px;
    --  overflow: hidden;
    --  width: 100%;
    --}
    --
    --.card-info .description .util {
    --  position: absolute;
    --  right: 5px;
    --  bottom: 70px;
    --  opacity: 0;
    --  -webkit-transition: opacity 0.5s;
    --  transition: opacity 0.5s;
    --}
    --
    --.card-info.empty-desc .title {
    --  white-space: normal;
    --  overflow: visible;
    --}
    --
    --.card-info.empty-desc .description {
    --  display: none;
    --}
    --
    --/* Resource card with icon instead of bg image */
    --.resource-widget-card-icon {
    --  text-align: center;
    --}
    --
    --.card-icon {
    --  margin: 20px 0 0;
    --}
    --
    --.resource-widget-card-icon .card-info {
    --  height: 210px;
    --}
    --
    --.resource-widget-card-icon .card-info .title {
    --  color: #333;
    --  line-height: 24px;
    --}
    --
    --.resource-widget-card-icon .card-bg {
    --  background: none;
    --  bottom: 220px;
    --  opacity: 1;
    --  top: 30px;
    --  -webkit-transition: opacity .3s;
    --  transition: opacity .3s;
    --}
    --
    --.resource-widget-card-icon .resource-card:hover .card-bg {
    --  opacity: .5;
    --}
    --
    --.resource-widget-card-icon .card-bg img {
    --  max-height: 100%;
    --}
    --
    --.resource-widget-card-icon .card-bg::after {
    --  background: transparent;
    --}
    --
    --@media (min-width: 1210px) {
    --  .resource-widget-card-icon .resource {
    --    height: 240px;
    --  }
    --  .resource-widget-card-icon .card-bg {
    --    bottom: 160px;
    --  }
    --  .resource-widget-card-icon .card-info {
    --    height: 160px;
    --  }
    --}
    --
    --@media (max-width: 979px) {
    --  .resource-widget-card-icon .resource {
    --    height: 240px;
    --  }
    --  .resource-widget-card-icon .card-bg {
    --    bottom: 160px;
    --  }
    --
    --  .resource-widget-card-icon .card-info {
    --    height: 160px;
    --  }
    --}
    --
    --/* Truncate card summaries at bounding box and
    -- * and apply ellipsis at lower right */
    --.ellipsis {
    --  overflow: hidden;
    --  float: right;
    --  line-height: 15px;
    --  width: 100%; }
    --  .ellipsis:before {
    --    content: "";
    --    float: left;
    --    width: 5px;
    --    height: 100%; }
    --  .ellipsis > *:first-child.text {
    --    float: right;
    --    width: 100% !important;
    --    margin-left: -5px; }
    --  .ellipsis:after {
    --    content: "\02026";
    --    height: 17px;
    --    padding-bottom: 4px;
    --    box-sizing: content-box;
    --    float: right;
    --    position: relative;
    --    top: -16px;
    --    left: 100%;
    --    width: 4em;
    --    margin-left: -4em;
    --    padding-right: 5px;
    --    background: -webkit-gradient(linear, left top, right top, from(rgba(255, 255, 255, 0)), to(white), color-stop(65%, white));
    --    background: -webkit-linear-gradient(left, rgba(255, 255, 255, 0), white 65%, white);
    --    background: linear-gradient(to right, rgba(255, 255, 255, 0), white 65%, white); }
    --  .ellipsis:after {
    --    font-style: normal;
    --    color: #aaa;
    --    font-size: 13px;
    --    text-align: right; }
    --
    --.resource-card:hover {
    --  cursor: pointer; }
    --  .static .resource-card:hover {
    --    cursor: auto; }
    --  .resource-card:hover .card-bg:after {
    --    opacity: 0; }
    --  .resource-card:hover .play-button {
    --    opacity: .3; }
    --  .resource-card:hover .card-info .description .util {
    --    opacity: 1; }
    --
    --/* Carousel Layout */
    --/* Carousel styles for landing page */
    --.resource-carousel-layout {
    --  height: 531px;
    --  margin: 20px 0 20px 0;
    --  padding: 0 !important;
    --  position: relative;
    --  overflow: hidden; }
    --  .resource-carousel-layout .slideshow-prev, .resource-carousel-layout .slideshow-next {
    --    display: none; }
    --  .resource-carousel-layout .pagination {
    --    bottom: 97px;
    --    left: auto;
    --    padding-right: 10px;
    --    right: 0;
    --    text-align: right;
    --    width: 16.66666667%; }
    --    .resource-carousel-layout .pagination ul li {
    --      text-indent: 8000px; }
    --  .resource-carousel-layout .frame li {
    --    position: relative; }
    --    .resource-carousel-layout .frame li .card-bg {
    --      bottom: 131px; }
    --    .resource-carousel-layout .frame li .card-info {
    --      height: 131px;
    --      padding: 6px 12px;
    --      top: auto; }
    --      .resource-carousel-layout .frame li .card-info .title {
    --        font-size: 28px;
    --        font-weight: 400;
    --        line-height: 32px; }
    --      .resource-carousel-layout .frame li .card-info .description .text {
    --        height: 40px; }
    --      .resource-carousel-layout .frame li .card-info .description .util {
    --        bottom: 97px;
    --        right: 4px; }
    --
    --/* Stack Layout */
    --.resource-stack-layout {
    --  display: inline-block;
    --  padding: 0; }
    --  .resource-stack-layout .section-card-menu > .card-info .section, .resource-stack-layout .section-card > .card-info .title {
    --    /*text-transform: uppercase;*/
    --    color: #898989;
    --    font-size: 17px;
    --    line-height: 23px;
    --    margin-bottom: 6px; }
    --  .resource-stack-layout .section-card {
    --    height: 284px; }
    --    .resource-stack-layout .section-card > .card-bg {
    --      height: 192px; }
    --    .resource-stack-layout .section-card > .card-info {
    --      padding: 4px 12px 6px 12px;
    --      top: 192px; }
    --      .resource-stack-layout .section-card > .card-info .section {
    --        display: none; }
    --      .resource-stack-layout .section-card > .card-info .title {
    --        font-size: 17px;
    --        border-bottom: 1px solid #959595;
    --        padding-bottom: 0px; }
    --      .resource-stack-layout .section-card > .card-info .description {
    --        font-size: 13px;
    --        line-height: 15px; }
    --        .resource-stack-layout .section-card > .card-info .description .text {
    --          height: 30px; }
    --  .resource-stack-layout .related-card {
    --    height: 90px; }
    --    .resource-stack-layout .related-card > .card-bg {
    --      left: 0;
    --      top: 0;
    --      width: 90px;
    --      height: 100%;
    --      position: absolute;
    --      display: block; }
    --    .resource-stack-layout .related-card > .card-info {
    --      left: 90px;
    --      padding: 4px 12px 4px 12px; }
    --      .resource-stack-layout .related-card > .card-info .section {
    --        font-size: 12px;
    --        margin-bottom: 1px;
    --        display: none; }
    --      .resource-stack-layout .related-card > .card-info .title {
    --        font-size: 16px;
    --        margin-bottom: -2px;
    --        white-space: normal;
    --        overflow: visible;
    --        text-overflow: ellipsis; }
    --        .resource-stack-layout .related-card > .card-info .title:after {
    --          content: url(../images/link-out.png);
    --          display: block; }
    --      .resource-stack-layout .related-card > .card-info .description {
    --        display: none; }
    --  .resource-stack-layout .section-card-menu {
    --    /* Flexible height */
    --    display: block;
    --    height: auto;
    --    width: auto; }
    --    .resource-stack-layout .section-card-menu .card-bg {
    --      height: 155px;
    --      /* Flexible height */
    --      position: relative;
    --      display: inline-block;
    --      vertical-align: top; }
    --    .resource-stack-layout .section-card-menu .card-info {
    --      padding: 4px 12px 0px 12px;
    --      /* Flexible height */
    --      position: relative;
    --      left: auto;
    --      top: auto;
    --      right: auto;
    --      bottom: auto; }
    --      .resource-stack-layout .section-card-menu .card-info ul {
    --        list-style: none;
    --        margin: 0; }
    --        .resource-stack-layout .section-card-menu .card-info ul li {
    --          list-style: none;
    --          margin: 0;
    --          padding: 15px 0;
    --          border-top-width: 1px;
    --          border-top-style: solid;
    --          border-top-color: #959595; }
    --          .resource-stack-layout .section-card-menu .card-info ul li a, .resource-stack-layout .section-card-menu .card-info ul li a:focus, .resource-stack-layout .section-card-menu .card-info ul li a:hover {
    --            color: #333 !important; }
    --          .resource-stack-layout .section-card-menu .card-info ul li:first-child {
    --            border-top: none; }
    --          .resource-stack-layout .section-card-menu .card-info ul li:hover .title:after {
    --            opacity: 1;
    --            -webkit-transition: opacity 0.5s;
    --                    transition: opacity 0.5s; }
    --          .resource-stack-layout .section-card-menu .card-info ul li:hover .description {
    --            max-height: 30px;
    --            opacity: 1;
    --            -webkit-transition: max-height 0.5s, opacity 1s;
    --                    transition: max-height 0.5s, opacity 1s; }
    --      .resource-stack-layout .section-card-menu .card-info .title {
    --        font-size: 16px;
    --        margin-bottom: -2px;
    --        position: relative; }
    --        .resource-stack-layout .section-card-menu .card-info .title:after {
    --          background: url(../images/stack-arrow-right.png);
    --          content: '';
    --          opacity: 0;
    --          -webkit-transition: opacity 0.25s;
    --                  transition: opacity 0.25s;
    --          position: absolute;
    --          right: 0px;
    --          top: 3px;
    --          width: 10px;
    --          height: 15px; }
    --      .resource-stack-layout .section-card-menu .card-info .title.more {
    --        text-transform: uppercase;
    --        color: #898989;
    --        display: inline-block; }
    --        .resource-stack-layout .section-card-menu .card-info .title.more:after {
    --          background: url(../images/stack-arrow-right.png);
    --          content: '';
    --          display: block;
    --          position: absolute;
    --          right: -20px;
    --          top: 3px;
    --          width: 10px;
    --          height: 15px; }
    --      .resource-stack-layout .section-card-menu .card-info .description {
    --        max-height: 0px;
    --        opacity: 0;
    --        overflow: hidden;
    --        font-size: 13px;
    --        line-height: 15px;
    --        /* Hover off */
    --        -webkit-transition: max-height 0.5s, opacity 0.5s;
    --                transition: max-height 0.5s, opacity 0.5s; }
    --        .resource-stack-layout .section-card-menu .card-info .description .text {
    --          height: 30px; }
    --  .resource-stack-layout:after {
    --    content: ".";
    --    display: block;
    --    height: 0;
    --    clear: both;
    --    visibility: hidden; }
    --
    --.resource-card, .resource-card-stack {
    --  margin-bottom: 20px; }
    --
    --.resource-card-row-stack-last {
    --  margin-bottom: 0px !important; }
    --
    --.resource-card-col-stack-last {
    --  margin-bottom: 0px !important; }
    --
    --.resource-card-3x6 {
    --  height: 300px; }
    --
    --.resource-card-3x12 {
    --  height: 620px; }
    --
    --.resource-card-3x18 {
    --  height: 940px; }
    --
    --.resource-card-6x6 {
    --  height: 300px; }
    --
    --.resource-card-6x12 {
    --  height: 620px; }
    --
    --.resource-card-6x18 {
    --  height: 940px; }
    --
    --.resource-card-9x6 {
    --  height: 300px; }
    --
    --.resource-card-9x12 {
    --  height: 620px; }
    --
    --.resource-card-9x18 {
    --  height: 940px; }
    --
    --.resource-card-12x6 {
    --  height: 300px; }
    --
    --.resource-card-12x12 {
    --  height: 620px; }
    --
    --.resource-card-12x18 {
    --  height: 940px; }
    --
    --.resource-card-15x6 {
    --  height: 300px; }
    --
    --.resource-card-15x12 {
    --  height: 620px; }
    --
    --.resource-card-15x18 {
    --  height: 940px; }
    --
    --.resource-card-18x6 {
    --  height: 300px; }
    --
    --.resource-card-18x12 {
    --  height: 620px; }
    --
    --.resource-card-18x18 {
    --  height: 940px; }
    --
    --.resource-card-3x2 {
    --  height: 100px; }
    --
    --.resource-card-3x2x3 {
    --  height: 90px;
    --  margin-bottom: 15px; }
    --
    --.resource-card-3x3 {
    --  height: 150px; }
    --
    --.resource-card-3x3x2 {
    --  height: 142px;
    --  margin-bottom: 16px; }
    --
    --.resource-card-6x2 {
    --  height: 100px; }
    --
    --.resource-card-6x2x3 {
    --  height: 90px;
    --  margin-bottom: 15px; }
    --
    --.resource-card-6x3 {
    --  height: 150px; }
    --
    --.resource-card-6x3x2 {
    --  height: 142px;
    --  margin-bottom: 16px; }
    --
    --.resource-card-9x2 {
    --  height: 100px; }
    --
    --.resource-card-9x2x3 {
    --  height: 90px;
    --  margin-bottom: 15px; }
    --
    --.resource-card-9x3 {
    --  height: 150px; }
    --
    --.resource-card-9x3x2 {
    --  height: 142px;
    --  margin-bottom: 16px; }
    --
    --.resource-card-12x2 {
    --  height: 100px; }
    --
    --.resource-card-12x2x3 {
    --  height: 90px;
    --  margin-bottom: 15px; }
    --
    --.resource-card-12x3 {
    --  height: 150px; }
    --
    --.resource-card-12x3x2 {
    --  height: 142px;
    --  margin-bottom: 16px; }
    --
    --.resource-card-15x2 {
    --  height: 100px; }
    --
    --.resource-card-15x2x3 {
    --  height: 90px;
    --  margin-bottom: 15px; }
    --
    --.resource-card-15x3 {
    --  height: 150px; }
    --
    --.resource-card-15x3x2 {
    --  height: 142px;
    --  margin-bottom: 16px; }
    --
    --.resource-card-18x2 {
    --  height: 100px; }
    --
    --.resource-card-18x2x3 {
    --  height: 90px;
    --  margin-bottom: 15px; }
    --
    --.resource-card-18x3 {
    --  height: 150px; }
    --
    --.resource-card-18x3x2 {
    --  height: 142px;
    --  margin-bottom: 16px; }
    --
    --/*
    --  The following are styles for cards in the flowlayout above, styled by the number of rows they span
    --*/
    --/* Single row, 2 column items. */
    --.resource-card-9x6 {
    --  height: 390px; }
    --
    --/* Double row, 1 column items. Eg full width video thumbnails. */
    --.resource-card-18x12 {
    --  height: 558px; }
    --
    --/* 1/3 row items */
    --.resource-card-3x2 > .card-bg,
    --.resource-card-6x2 > .card-bg,
    --.resource-card-9x2 > .card-bg,
    --.resource-card-12x2 > .card-bg,
    --.resource-card-15x2 > .card-bg,
    --.resource-card-18x2 > .card-bg {
    --  left: 0;
    --  top: 0;
    --  width: 90px;
    --  height: 100%;
    --  position: absolute;
    --  display: block;
    --}
    --
    --.resource-card-3x2 > .card-info, .resource-card-6x2 > .card-info, .resource-card-9x2 > .card-info, .resource-card-12x2 > .card-info, .resource-card-15x2 > .card-info, .resource-card-18x2 > .card-info {
    --  height: 100%;
    --  left: 90px;
    --  padding: 6px 12px;
    --  overflow: hidden;
    --}
    --
    --.resource-card-3x2 > .card-info .title,
    --.resource-card-6x2 > .card-info .title,
    --.resource-card-9x2 > .card-info .title,
    --.resource-card-12x2 > .card-info .title,
    --.resource-card-15x2 > .card-info .title,
    --.resource-card-18x2 > .card-info .title {
    --  max-height: 69px;
    --  white-space: normal;
    --}
    --
    --.resource-card-3x2 > .card-info .description,
    --.resource-card-6x2 > .card-info .description,
    --.resource-card-9x2 > .card-info .description,
    --.resource-card-12x2 > .card-info .description,
    --.resource-card-15x2 > .card-info .description,
    --.resource-card-18x2 > .card-info .description {
    --  display: none;
    --}
    --
    --.resource-card-3x2 > .card-info .text,
    --.resource-card-6x2 > .card-info .text,
    --.resource-card-9x2 > .card-info .text,
    --.resource-card-12x2 > .card-info .text,
    --.resource-card-15x2 > .card-info .text,
    --.resource-card-18x2 > .card-info .text {
    --  height: auto;
    --}
    --
    --/* Override to show the description instead of the content section */
    --.no-section .resource-card-3x2 > .card-info .section,
    --.no-section .resource-card-6x2 > .card-info .section {
    --  display: none; }
    --
    --.no-section .resource-card-3x2 > .card-info .description,
    --.no-section .resource-card-6x2 > .card-info .description {
    --  display: block; }
    --
    --/* 1/2 row items */
    --.resource-card-3x3, .resource-card-6x3, .resource-card-9x3, .resource-card-12x3, .resource-card-15x3, .resource-card-18x3 {
    --  height: 160px; }
    --  .resource-card-3x3 > .card-bg, .resource-card-6x3 > .card-bg, .resource-card-9x3 > .card-bg, .resource-card-12x3 > .card-bg, .resource-card-15x3 > .card-bg, .resource-card-18x3 > .card-bg {
    --    left: 0;
    --    top: 0;
    --    width: 90px;
    --    height: 100%;
    --    position: absolute;
    --    display: block; }
    --  .resource-card-3x3 > .card-info, .resource-card-6x3 > .card-info, .resource-card-9x3 > .card-info, .resource-card-12x3 > .card-info, .resource-card-15x3 > .card-info, .resource-card-18x3 > .card-info {
    --    height: 100%;
    --    left: 90px;
    --    padding: 6px 12px; }
    --    .resource-card-3x3 > .card-info .section, .resource-card-6x3 > .card-info .section, .resource-card-9x3 > .card-info .section, .resource-card-12x3 > .card-info .section, .resource-card-15x3 > .card-info .section, .resource-card-18x3 > .card-info .section {
    --      display: none; }
    --    .resource-card-3x3 > .card-info .title, .resource-card-6x3 > .card-info .title, .resource-card-9x3 > .card-info .title, .resource-card-12x3 > .card-info .title, .resource-card-15x3 > .card-info .title, .resource-card-18x3 > .card-info .title {
    --      max-height: 92px;
    --      white-space: normal; }
    --    .resource-card-3x3 > .card-info .text, .resource-card-6x3 > .card-info .text, .resource-card-9x3 > .card-info .text, .resource-card-12x3 > .card-info .text, .resource-card-15x3 > .card-info .text, .resource-card-18x3 > .card-info .text {
    --      height: auto; }
    --    .resource-card-3x3 > .card-info .util, .resource-card-6x3 > .card-info .util, .resource-card-9x3 > .card-info .util, .resource-card-12x3 > .card-info .util, .resource-card-15x3 > .card-info .util, .resource-card-18x3 > .card-info .util {
    --      display: none; }
    --
    --/* placement of plusone */
    --.resource-card-6x12 > .card-info .description .util, .resource-card-9x12 > .card-info .description .util, .resource-card-12x12 > .card-info .description .util, .resource-card-15x12 > .card-info .description .util {
    --  bottom: 2px; }
    --
    --.resource-card-18x12 > .card-info .description .util {
    --  bottom: 2px; }
    --
    --/* Overrides for col-16 6x6 cards linking to local content on landing pages.
    --   Suppresses "section". */
    --.landing .card-info .section {
    --  display: none; }
    --
    --/*
    --  Generate a resource stack layout for a 3 column widget spanning 16 grid cols
    --*/
    --.resource-stack-layout.col-16 {
    --  margin: 0 -14px 0 0;
    --  width: 954px; }
    --  .resource-stack-layout.col-16 .resource-card-stack {
    --    margin: 0 14px 0 0;
    --    width: 304px; }
    --
    --/* Example of card menu tinting */
    --.resource-widget[data-section=distribute\/tools] .section-card-menu .card-bg:after {
    --  background: rgba(126, 55, 148, 0.4) !important; }
    --
    --.resource-widget[data-section=distribute\/tools] .section-card-menu .card-section-icon .icon {
    --  background-color: #7e3794 !important; }
    --
    --.resource-widget[data-section=distribute\/tools] .section-card-menu .card-info ul li {
    --  border-top-color: #7e3794 !important; }
    --
    --/* tinting for stacks */
    --div.jd-descr > .resource-widget[data-section=distribute\/tools]
    --.section-card-menu .card-info ul li {
    --  border-top-color: #7e3794 !important; }
    --
    --/* Show more/less */
    --.dac-show-more,
    --.dac-show-less {
    --  display: none !important; }
    --
    --.dac-has-more .dac-show-more {
    --  display: inline-block !important; }
    --
    --.dac-has-less .dac-show-less {
    --  display: inline-block !important; }
    --
    --.dac-fab, .dac-button-social, .button, .landing-button,
    --.dac-button {
    --  background: transparent;
    --  border: 0;
    --  border-radius: 3px;
    --  box-sizing: border-box;
    --  color: currentColor;
    --  cursor: pointer;
    --  display: inline-block;
    --  font-weight: 500;
    --  font-size: 14px;
    --  font-style: inherit;
    --  font-variant: inherit;
    --  font-family: inherit;
    --  letter-spacing: .5px;
    --  line-height: 24px;
    --  margin: 6px 16px 6px 0;
    --  min-width: 88px;
    --  outline: 0;
    --  padding: 6px 12px;
    --  position: relative;
    --  text-align: center;
    --  text-decoration: none;
    --  text-transform: uppercase;
    --  -webkit-transition: box-shadow 0.4s cubic-bezier(0.25, 0.8, 0.25, 1), background-color 0.4s cubic-bezier(0.25, 0.8, 0.25, 1);
    --          transition: box-shadow 0.4s cubic-bezier(0.25, 0.8, 0.25, 1), background-color 0.4s cubic-bezier(0.25, 0.8, 0.25, 1);
    --  -webkit-user-select: none;
    --     -moz-user-select: none;
    --      -ms-user-select: none;
    --          user-select: none;
    --  white-space: nowrap; }
    --
    --.button, .landing-button,
    --.dac-button.dac-raised {
    --  background-color: #FAFAFA;
    --  box-shadow: 0 2px 5px rgba(0, 0, 0, 0.26); }
    --
    --.dac-button.dac-raised.dac-primary, .landing-secondary, .button {
    --  background-color: #039bef; }
    --  .dac-button.dac-raised.dac-primary:hover, .landing-secondary:hover, .button:hover {
    --    background-color: #0288d1; }
    --  .dac-button.dac-raised.dac-primary:active, .landing-secondary:active, .button:active {
    --    background-color: #0277bd; }
    --  .dac-button.dac-raised.dac-primary.disabled, .button.disabled {
    --    background-color: #bbb; }
    --
    --.dac-button.dac-raised.dac-red, .landing-primary {
    --  background-color: #bf3722; }
    --  .dac-button.dac-raised.dac-red:hover, .landing-primary:hover {
    --    background-color: #9c2d1c; }
    --  .dac-button.dac-raised.dac-red:active, .landing-primary:active {
    --    background-color: #822517; }
    --
    --.dac-button.dac-raised.dac-green, .landing-button.green {
    --  background-color: #90c653; }
    --  .dac-button.dac-raised.dac-green:hover, .landing-button.green:hover {
    --    background-color: #79b03b; }
    --  .dac-button.dac-raised.dac-green:active, .landing-button.green:active {
    --    background-color: #699933; }
    --
    --.dac-button.dac-raised.dac-primary, .landing-secondary, .button,
    --.dac-button.dac-raised.dac-red,
    --.landing-primary,
    --.dac-button.dac-raised.dac-green,
    --.landing-button.green {
    --  color: #fff; }
    --
    --.dac-button.dac-large, .landing-button {
    --  padding: 12px 24px; }
    --
    --.landing-button-wrap {
    --  float: left;
    --  margin-right: 40px;
    --  width: auto;
    --}
    --
    --.dac-fab, .dac-button-social {
    --  background: #fff;
    --  box-shadow: 0 2px 5px rgba(0, 0, 0, 0.26);
    --  border-radius: 50%;
    --  height: 36px;
    --  line-height: 36px;
    --  margin: 0;
    --  min-width: 0;
    --  overflow: hidden;
    --  padding: 0;
    --  vertical-align: middle;
    --  width: 36px; }
    --  .dac-fab:hover, .dac-button-social:hover,
    --  a:hover > .dac-fab,
    --  a:hover > .dac-button-social {
    --    box-shadow: 0 3px 8px rgba(0, 0, 0, 0.26); }
    --  .dac-fab > .dac-sprite, .dac-button-social > .dac-sprite, .dac-fab > .dac-modal-header-close:before, .dac-button-social > .dac-modal-header-close:before, .paging-links .dac-fab > .prev-page-link:before, .paging-links .dac-button-social > .prev-page-link:before, .paging-links .dac-fab > .next-page-link:before, .paging-links .dac-button-social > .next-page-link:before, .paging-links .dac-fab > .next-class-link:before, .paging-links .dac-button-social > .next-class-link:before, .paging-links .dac-fab > .start-class-link:after, .paging-links .dac-button-social > .start-class-link:after {
    --    margin-top: -2px; }
    --  .dac-fab.dac-primary, .dac-primary.dac-button-social {
    --    background: #00c7a0; }
    --  .dac-fab.dac-large, .dac-large.dac-button-social {
    --    height: 54px;
    --    line-height: 54px;
    --    width: 54px; }
    --
    --.dac-button-social {
    --  background: #ccc;
    --  box-shadow: none;
    --  position: relative;
    --  overflow: hidden; }
    --  .dac-button-social::after {
    --    background: rgba(0, 0, 0, 0.2);
    --    border-radius: 50%;
    --    bottom: 0;
    --    content: '';
    --    display: block;
    --    left: 0;
    --    opacity: 0;
    --    position: absolute;
    --    right: 0;
    --    top: 0;
    --    -webkit-transition: opacity .3s;
    --            transition: opacity .3s; }
    --  .dac-button-social:hover {
    --    box-shadow: none; }
    --  .dac-button-social:active::after {
    --    opacity: 1; }
    --  .dac-button-social:focus.dac-rss, .dac-button-social:hover.dac-rss {
    --    background: #ff9800; }
    --  .dac-button-social:focus.dac-youtube, .dac-button-social:hover.dac-youtube {
    --    background: #f44336; }
    --  .dac-button-social:focus.dac-gplus, .dac-button-social:hover.dac-gplus {
    --    background: #f44336; }
    --  .dac-button-social:focus.dac-twitter, .dac-button-social:hover.dac-twitter {
    --    background: #55acee; }
    --
    --.dac-action {
    --  display: inline-block;
    --  margin: 0 16px; }
    --  .dac-action-link {
    --    color: inherit;
    --    font-size: 24px;
    --    font-weight: 300;
    --    line-height: 50px;
    --    -webkit-transition: opacity .3s;
    --            transition: opacity .3s; }
    --    .dac-action-link:hover {
    --      color: inherit;
    --      opacity: .54; }
    --  .dac-action-sprite {
    --    margin-left: -12px;
    --    margin-right: -8px; }
    --  .dac-actions {
    --    list-style-type: none;
    --    margin: 0;
    --    padding-bottom: 24px;
    --    padding-top: 24px;
    --    text-align: center; }
    --    @media (max-width: 719px) {
    --      .dac-actions {
    --        text-align: left; } }
    --  @media (max-width: 719px) {
    --    .dac-action {
    --      display: block;
    --      margin: 0; } }
    --
    --.dac-scroll-button {
    --  height: 54px;
    --  line-height: 54px;
    --  margin: 0;
    --  position: absolute;
    --  right: 0;
    --  top: -27px;
    --  width: 54px;
    --  z-index: 1; }
    --  @media (max-width: 719px) {
    --    .dac-scroll-button {
    --      display: none; } }
    --
    --/* Footer component */
    --.dac-footer {
    --  background-color: #fff;
    --  border-top: 1px solid #f0f0f0;
    --  clear: both;
    --  color: #999;
    --  font-size: 12px;
    --  margin-top: 96px;
    --  padding-bottom: 20px;
    --  position: relative;
    --}
    --
    --.dac-footer a {
    --  color: #999;
    --}
    --
    --.dac-footer p {
    --  margin: 7px 0 0;
    --}
    --
    --.dac-footer-main {
    --  padding: 30px 0;
    --}
    --
    --.dac-footer-reachout {
    --  text-align: right;
    --}
    --
    --.dac-footer-contact,
    --.dac-footer-social {
    --  display: inline-block;
    --}
    --
    --.dac-footer .dac-footer-getnews,
    --.dac-footer .dac-footer-contact-link {
    --  color: #000;
    --  cursor: pointer;
    --  font-size: 20px;
    --  font-weight: 300;
    --  margin: 8px 0;
    --  vertical-align: middle;
    --}
    --
    --.dac-footer .dac-footer-contact-link,
    --.dac-footer .dac-footer-social-link {
    --  margin-left: 16px;
    --  margin-right: 0;
    --}
    --
    --.dac-footer-getnews > .dac-fab, .dac-footer-getnews > .dac-button-social {
    --  margin-left: 4px;
    --}
    --
    --.dac-footer-separator {
    --  background: #f0f0f0;
    --  margin: 0 0 12px;
    --}
    --
    --.dac-footer-links {
    --  float: left;
    --  margin: 10px 0 60px;
    --  width: 50%;
    --}
    --
    --.dac-footer-links a + a:before {
    --  content: '|';
    --  cursor: default;
    --  margin: 0 10px 0 8px;
    --}
    --
    --.devsite-utility-footer-language {
    --  float: right;
    --  margin: 10px 0 60px;
    --  width: 50%;
    --}
    --
    --.dac-footer .locales {
    --  float: right;
    --  margin: 0;
    --}
    --
    --.dac-footer .locales select {
    --  background-color: #f0f0f0;
    --  border-radius: 3px;
    --  font-size: 12px;
    --  height: auto;
    --  margin-top: -2px;
    --  padding: 8px 12px;
    --  width: 146px;
    --}
    --
    --.dac-footer.dac-landing {
    --  margin-top: 0;
    --  border-top: 0;
    --}
    --
    --@media (max-width: 719px) {
    --  .dac-footer-reachout {
    --    text-align: left;
    --  }
    --
    --  .dac-footer-social {
    --    display: block;
    --  }
    --
    --  .dac-footer-social-link,
    --  .dac-footer-contact-link {
    --    display: inline-block;
    --  }
    --
    --  .dac-footer .dac-footer-contact-link,
    --  .dac-footer .dac-footer-social-link {
    --    margin-left: 0;
    --    margin-right: 16px;
    --  }
    --
    --  .dac-footer-links {
    --    display: block;
    --    float: none;
    --    width: 100%;
    --  }
    --
    --  .devsite-utility-footer-language {
    --    float: none;
    --    margin: 0 0 20px;
    --    width: 100%;
    --  }
    --
    --  .dac-footer .locales {
    --    display: block;
    --    float: none;
    --    margin-top: 15px;
    --  }
    --}
    --
    --/* =============================================================================
    --   Columns
    --   ========================================================================== */
    --.wrap {
    --  margin: 0 auto;
    --  max-width: 940px;
    --  clear: both;
    --}
    --
    --.dac-fullscreen-mode .wrap {
    --  max-width: none;
    --}
    --
    --.dac-fullscreen-mode .dac-search-open .wrap {
    --  max-width: 940px;
    --}
    --
    --.cols {
    --  margin-left: -10px;
    --  margin-right: -10px;
    --  /**
    --   * For modern browsers
    --   * 1. The space content is one way to avoid an Opera bug when the
    --   *    contenteditable attribute is included anywhere else in the document.
    --   *    Otherwise it causes space to appear at the top and bottom of elements
    --   *    that are clearfixed.
    --   * 2. The use of `table` rather than `block` is only necessary if using
    --   *    `:before` to contain the top-margins of child elements.
    --   */ }
    --  .cols:before, .cols:after {
    --    content: ' ';
    --    /* 1 */
    --    display: table;
    --    /* 2 */ }
    --  .cols:after {
    --    clear: both; }
    --
    --[class*=col-] {
    --  box-sizing: border-box;
    --  float: left;
    --  min-height: 1px;
    --  padding-left: 10px;
    --  padding-right: 10px;
    --  position: relative; }
    --
    --.col-1 {
    --  width: 6.25%; }
    --
    --.col-2 {
    --  width: 12.5%; }
    --
    --.col-3 {
    --  width: 18.75%; }
    --
    --.col-4 {
    --  width: 25%; }
    --
    --.col-5 {
    --  width: 31.25%; }
    --
    --.col-6 {
    --  width: 37.5%; }
    --
    --.col-7 {
    --  width: 43.75%; }
    --
    --.col-8 {
    --  width: 50%; }
    --
    --.col-9 {
    --  width: 56.25%; }
    --
    --.col-10 {
    --  width: 62.5%; }
    --
    --.col-11 {
    --  width: 68.75%; }
    --
    --.col-12 {
    --  width: 75%; }
    --
    --.col-13 {
    --  width: 81.25%; }
    --
    --.col-14 {
    --  width: 87.5%; }
    --
    --.col-15 {
    --  width: 93.75%; }
    --
    --.col-16 {
    --  width: 100%; }
    --
    --.col-13 .col-1 {
    --  width: 7.69230769%; }
    --
    --.col-13 .col-2 {
    --  width: 15.38461538%; }
    --
    --.col-13 .col-3 {
    --  width: 23.07692308%; }
    --
    --.col-13 .col-4 {
    --  width: 30.76923077%; }
    --
    --.col-13 .col-5 {
    --  width: 38.46153846%; }
    --
    --.col-13 .col-6 {
    --  width: 46.15384615%; }
    --
    --.col-13 .col-7 {
    --  width: 53.84615385%; }
    --
    --.col-13 .col-8 {
    --  width: 61.53846154%; }
    --
    --.col-13 .col-9 {
    --  width: 69.23076923%; }
    --
    --.col-13 .col-10 {
    --  width: 76.92307692%; }
    --
    --.col-13 .col-11 {
    --  width: 84.61538462%; }
    --
    --.col-13 .col-12 {
    --  width: 92.30769231%; }
    --
    --.col-13 .col-13 {
    --  width: 100%; }
    --
    --.col-12 .col-1 {
    --  width: 8.33333333%; }
    --
    --.col-12 .col-2 {
    --  width: 16.66666667%; }
    --
    --.col-12 .col-3 {
    --  width: 25%; }
    --
    --.col-12 .col-4 {
    --  width: 33.33333333%; }
    --
    --.col-12 .col-5 {
    --  width: 41.66666667%; }
    --
    --.col-12 .col-6 {
    --  width: 50%; }
    --
    --.col-12 .col-7 {
    --  width: 58.33333333%; }
    --
    --.col-12 .col-8 {
    --  width: 66.66666667%; }
    --
    --.col-12 .col-9 {
    --  width: 75%; }
    --
    --.col-12 .col-10 {
    --  width: 83.33333333%; }
    --
    --.col-12 .col-11 {
    --  width: 91.66666667%; }
    --
    --.col-12 .col-12 {
    --  width: 100%; }
    --
    --.col-1of1, .col-2of2, .col-3of3, .col-4of4, .col-5of5, .col-6of6, .col-8of8, .col-10of10, .col-12of12, .col-16of16 {
    --  width: 100%; }
    --
    --.col-1of2, .col-2of4, .col-3of6, .col-4of8, .col-5of10, .col-6of12, .col-8of16 {
    --  width: 50%; }
    --
    --.col-1of3, .col-2of6, .col-4of12 {
    --  width: 33.33333333%; }
    --
    --.col-2of3, .col-4of6, .col-8of12 {
    --  width: 66.66666667%; }
    --
    --.col-1of4, .col-2of8, .col-3of12, .col-4of16 {
    --  width: 25%; }
    --
    --.col-3of4, .col-6of8, .col-9of12, .col-12of16 {
    --  width: 75%; }
    --
    --.col-1of5, .col-2of10 {
    --  width: 20%; }
    --
    --.col-2of5, .col-4of10 {
    --  width: 40%; }
    --
    --.col-3of5, .col-6of10 {
    --  width: 60%; }
    --
    --.col-4of5, .col-8of10 {
    --  width: 80%; }
    --
    --.col-1of6, .col-2of12 {
    --  width: 16.66666667%; }
    --
    --.col-5of6, .col-10of12 {
    --  width: 83.33333333%; }
    --
    --.col-1of8, .col-2of16 {
    --  width: 12.5%; }
    --
    --.col-3of8, .col-6of16 {
    --  width: 37.5%; }
    --
    --.col-5of8, .col-10of16 {
    --  width: 62.5%; }
    --
    --.col-7of8, .col-14of16 {
    --  width: 87.5%; }
    --
    --.col-1of10 {
    --  width: 10%; }
    --
    --.col-3of10 {
    --  width: 30%; }
    --
    --.col-7of10 {
    --  width: 70%; }
    --
    --.col-9of10 {
    --  width: 90%; }
    --
    --.col-1of12 {
    --  width: 8.33333333%; }
    --
    --.col-5of12 {
    --  width: 41.66666667%; }
    --
    --.col-7of12 {
    --  width: 58.33333333%; }
    --
    --.col-11of12 {
    --  width: 91.66666667%; }
    --
    --.col-1of16 {
    --  width: 6.25%; }
    --
    --.col-3of16 {
    --  width: 18.75%; }
    --
    --.col-5of16 {
    --  width: 31.25%; }
    --
    --.col-7of16 {
    --  width: 43.75%; }
    --
    --.col-9of16 {
    --  width: 56.25%; }
    --
    --.col-11of16 {
    --  width: 68.75%; }
    --
    --.col-13of16 {
    --  width: 81.25%; }
    --
    --.col-15of16 {
    --  width: 93.75%; }
    --
    --.col-pull-1of1, .col-pull-2of2, .col-pull-3of3, .col-pull-4of4, .col-pull-5of5, .col-pull-6of6, .col-pull-8of8, .col-pull-10of10, .col-pull-12of12, .col-pull-16of16 {
    --  left: -100%; }
    --
    --.col-pull-1of2, .col-pull-2of4, .col-pull-3of6, .col-pull-4of8, .col-pull-5of10, .col-pull-6of12, .col-pull-8of16 {
    --  left: -50%; }
    --
    --.col-pull-1of3, .col-pull-2of6, .col-pull-4of12 {
    --  left: -33.33333333%; }
    --
    --.col-pull-2of3, .col-pull-4of6, .col-pull-8of12 {
    --  left: -66.66666667%; }
    --
    --.col-pull-1of4, .col-pull-2of8, .col-pull-3of12, .col-pull-4of16 {
    --  left: -25%; }
    --
    --.col-pull-3of4, .col-pull-6of8, .col-pull-9of12, .col-pull-12of16 {
    --  left: -75%; }
    --
    --.col-pull-1of5, .col-pull-2of10 {
    --  left: -20%; }
    --
    --.col-pull-2of5, .col-pull-4of10 {
    --  left: -40%; }
    --
    --.col-pull-3of5, .col-pull-6of10 {
    --  left: -60%; }
    --
    --.col-pull-4of5, .col-pull-8of10 {
    --  left: -80%; }
    --
    --.col-pull-1of6, .col-pull-2of12 {
    --  left: -16.66666667%; }
    --
    --.col-pull-5of6, .col-pull-10of12 {
    --  left: -83.33333333%; }
    --
    --.col-pull-1of8, .col-pull-2of16 {
    --  left: -12.5%; }
    --
    --.col-pull-3of8, .col-pull-6of16 {
    --  left: -37.5%; }
    --
    --.col-pull-5of8, .col-pull-10of16 {
    --  left: -62.5%; }
    --
    --.col-pull-7of8, .col-pull-14of16 {
    --  left: -87.5%; }
    --
    --.col-pull-1of10 {
    --  left: -10%; }
    --
    --.col-pull-3of10 {
    --  left: -30%; }
    --
    --.col-pull-7of10 {
    --  left: -70%; }
    --
    --.col-pull-9of10 {
    --  left: -90%; }
    --
    --.col-pull-1of12 {
    --  left: -8.33333333%; }
    --
    --.col-pull-5of12 {
    --  left: -41.66666667%; }
    --
    --.col-pull-7of12 {
    --  left: -58.33333333%; }
    --
    --.col-pull-11of12 {
    --  left: -91.66666667%; }
    --
    --.col-pull-1of16 {
    --  left: -6.25%; }
    --
    --.col-pull-3of16 {
    --  left: -18.75%; }
    --
    --.col-pull-5of16 {
    --  left: -31.25%; }
    --
    --.col-pull-7of16 {
    --  left: -43.75%; }
    --
    --.col-pull-9of16 {
    --  left: -56.25%; }
    --
    --.col-pull-11of16 {
    --  left: -68.75%; }
    --
    --.col-pull-13of16 {
    --  left: -81.25%; }
    --
    --.col-pull-15of16 {
    --  left: -93.75%; }
    --
    --.col-push-1of1, .col-push-2of2, .col-push-3of3, .col-push-4of4, .col-push-5of5, .col-push-6of6, .col-push-8of8, .col-push-10of10, .col-push-12of12, .col-push-16of16 {
    --  left: 100%; }
    --
    --.col-push-1of2, .col-push-2of4, .col-push-3of6, .col-push-4of8, .col-push-5of10, .col-push-6of12, .col-push-8of16 {
    --  left: 50%; }
    --
    --.col-push-1of3, .col-push-2of6, .col-push-4of12 {
    --  left: 33.33333333%; }
    --
    --.col-push-2of3, .col-push-4of6, .col-push-8of12 {
    --  left: 66.66666667%; }
    --
    --.col-push-1of4, .col-push-2of8, .col-push-3of12, .col-push-4of16 {
    --  left: 25%; }
    --
    --.col-push-3of4, .col-push-6of8, .col-push-9of12, .col-push-12of16 {
    --  left: 75%; }
    --
    --.col-push-1of5, .col-push-2of10 {
    --  left: 20%; }
    --
    --.col-push-2of5, .col-push-4of10 {
    --  left: 40%; }
    --
    --.col-push-3of5, .col-push-6of10 {
    --  left: 60%; }
    --
    --.col-push-4of5, .col-push-8of10 {
    --  left: 80%; }
    --
    --.col-push-1of6, .col-push-2of12 {
    --  left: 16.66666667%; }
    --
    --.col-push-5of6, .col-push-10of12 {
    --  left: 83.33333333%; }
    --
    --.col-push-1of8, .col-push-2of16 {
    --  left: 12.5%; }
    --
    --.col-push-3of8, .col-push-6of16 {
    --  left: 37.5%; }
    --
    --.col-push-5of8, .col-push-10of16 {
    --  left: 62.5%; }
    --
    --.col-push-7of8, .col-push-14of16 {
    --  left: 87.5%; }
    --
    --.col-push-1of10 {
    --  left: 10%; }
    --
    --.col-push-3of10 {
    --  left: 30%; }
    --
    --.col-push-7of10 {
    --  left: 70%; }
    --
    --.col-push-9of10 {
    --  left: 90%; }
    --
    --.col-push-1of12 {
    --  left: 8.33333333%; }
    --
    --.col-push-5of12 {
    --  left: 41.66666667%; }
    --
    --.col-push-7of12 {
    --  left: 58.33333333%; }
    --
    --.col-push-11of12 {
    --  left: 91.66666667%; }
    --
    --.col-push-1of16 {
    --  left: 6.25%; }
    --
    --.col-push-3of16 {
    --  left: 18.75%; }
    --
    --.col-push-5of16 {
    --  left: 31.25%; }
    --
    --.col-push-7of16 {
    --  left: 43.75%; }
    --
    --.col-push-9of16 {
    --  left: 56.25%; }
    --
    --.col-push-11of16 {
    --  left: 68.75%; }
    --
    --.col-push-13of16 {
    --  left: 81.25%; }
    --
    --.col-push-15of16 {
    --  left: 93.75%; }
    --
    --@media (max-width: 959px) and (min-width: 720px) {
    --  .col-tablet-1of1, .col-tablet-2of2, .col-tablet-3of3, .col-tablet-4of4, .col-tablet-5of5, .col-tablet-6of6, .col-tablet-8of8, .col-tablet-10of10, .col-tablet-12of12, .col-tablet-16of16 {
    --    width: 100%; }
    --  .col-tablet-1of2, .col-tablet-2of4, .col-tablet-3of6, .col-tablet-4of8, .col-tablet-5of10, .col-tablet-6of12, .col-tablet-8of16 {
    --    width: 50%; }
    --  .col-tablet-1of3, .col-tablet-2of6, .col-tablet-4of12 {
    --    width: 33.33333333%; }
    --  .col-tablet-2of3, .col-tablet-4of6, .col-tablet-8of12 {
    --    width: 66.66666667%; }
    --  .col-tablet-1of4, .col-tablet-2of8, .col-tablet-3of12, .col-tablet-4of16 {
    --    width: 25%; }
    --  .col-tablet-3of4, .col-tablet-6of8, .col-tablet-9of12, .col-tablet-12of16 {
    --    width: 75%; }
    --  .col-tablet-1of5, .col-tablet-2of10 {
    --    width: 20%; }
    --  .col-tablet-2of5, .col-tablet-4of10 {
    --    width: 40%; }
    --  .col-tablet-3of5, .col-tablet-6of10 {
    --    width: 60%; }
    --  .col-tablet-4of5, .col-tablet-8of10 {
    --    width: 80%; }
    --  .col-tablet-1of6, .col-tablet-2of12 {
    --    width: 16.66666667%; }
    --  .col-tablet-5of6, .col-tablet-10of12 {
    --    width: 83.33333333%; }
    --  .col-tablet-1of8, .col-tablet-2of16 {
    --    width: 12.5%; }
    --  .col-tablet-3of8, .col-tablet-6of16 {
    --    width: 37.5%; }
    --  .col-tablet-5of8, .col-tablet-10of16 {
    --    width: 62.5%; }
    --  .col-tablet-7of8, .col-tablet-14of16 {
    --    width: 87.5%; }
    --  .col-tablet-1of10 {
    --    width: 10%; }
    --  .col-tablet-3of10 {
    --    width: 30%; }
    --  .col-tablet-7of10 {
    --    width: 70%; }
    --  .col-tablet-9of10 {
    --    width: 90%; }
    --  .col-tablet-1of12 {
    --    width: 8.33333333%; }
    --  .col-tablet-5of12 {
    --    width: 41.66666667%; }
    --  .col-tablet-7of12 {
    --    width: 58.33333333%; }
    --  .col-tablet-11of12 {
    --    width: 91.66666667%; }
    --  .col-tablet-1of16 {
    --    width: 6.25%; }
    --  .col-tablet-3of16 {
    --    width: 18.75%; }
    --  .col-tablet-5of16 {
    --    width: 31.25%; }
    --  .col-tablet-7of16 {
    --    width: 43.75%; }
    --  .col-tablet-9of16 {
    --    width: 56.25%; }
    --  .col-tablet-11of16 {
    --    width: 68.75%; }
    --  .col-tablet-13of16 {
    --    width: 81.25%; }
    --  .col-tablet-15of16 {
    --    width: 93.75%; }
    --  .col-tablet-pull-1of1, .col-tablet-pull-2of2, .col-tablet-pull-3of3, .col-tablet-pull-4of4, .col-tablet-pull-5of5, .col-tablet-pull-6of6, .col-tablet-pull-8of8, .col-tablet-pull-10of10, .col-tablet-pull-12of12, .col-tablet-pull-16of16 {
    --    left: -100%; }
    --  .col-tablet-pull-1of2, .col-tablet-pull-2of4, .col-tablet-pull-3of6, .col-tablet-pull-4of8, .col-tablet-pull-5of10, .col-tablet-pull-6of12, .col-tablet-pull-8of16 {
    --    left: -50%; }
    --  .col-tablet-pull-1of3, .col-tablet-pull-2of6, .col-tablet-pull-4of12 {
    --    left: -33.33333333%; }
    --  .col-tablet-pull-2of3, .col-tablet-pull-4of6, .col-tablet-pull-8of12 {
    --    left: -66.66666667%; }
    --  .col-tablet-pull-1of4, .col-tablet-pull-2of8, .col-tablet-pull-3of12, .col-tablet-pull-4of16 {
    --    left: -25%; }
    --  .col-tablet-pull-3of4, .col-tablet-pull-6of8, .col-tablet-pull-9of12, .col-tablet-pull-12of16 {
    --    left: -75%; }
    --  .col-tablet-pull-1of5, .col-tablet-pull-2of10 {
    --    left: -20%; }
    --  .col-tablet-pull-2of5, .col-tablet-pull-4of10 {
    --    left: -40%; }
    --  .col-tablet-pull-3of5, .col-tablet-pull-6of10 {
    --    left: -60%; }
    --  .col-tablet-pull-4of5, .col-tablet-pull-8of10 {
    --    left: -80%; }
    --  .col-tablet-pull-1of6, .col-tablet-pull-2of12 {
    --    left: -16.66666667%; }
    --  .col-tablet-pull-5of6, .col-tablet-pull-10of12 {
    --    left: -83.33333333%; }
    --  .col-tablet-pull-1of8, .col-tablet-pull-2of16 {
    --    left: -12.5%; }
    --  .col-tablet-pull-3of8, .col-tablet-pull-6of16 {
    --    left: -37.5%; }
    --  .col-tablet-pull-5of8, .col-tablet-pull-10of16 {
    --    left: -62.5%; }
    --  .col-tablet-pull-7of8, .col-tablet-pull-14of16 {
    --    left: -87.5%; }
    --  .col-tablet-pull-1of10 {
    --    left: -10%; }
    --  .col-tablet-pull-3of10 {
    --    left: -30%; }
    --  .col-tablet-pull-7of10 {
    --    left: -70%; }
    --  .col-tablet-pull-9of10 {
    --    left: -90%; }
    --  .col-tablet-pull-1of12 {
    --    left: -8.33333333%; }
    --  .col-tablet-pull-5of12 {
    --    left: -41.66666667%; }
    --  .col-tablet-pull-7of12 {
    --    left: -58.33333333%; }
    --  .col-tablet-pull-11of12 {
    --    left: -91.66666667%; }
    --  .col-tablet-pull-1of16 {
    --    left: -6.25%; }
    --  .col-tablet-pull-3of16 {
    --    left: -18.75%; }
    --  .col-tablet-pull-5of16 {
    --    left: -31.25%; }
    --  .col-tablet-pull-7of16 {
    --    left: -43.75%; }
    --  .col-tablet-pull-9of16 {
    --    left: -56.25%; }
    --  .col-tablet-pull-11of16 {
    --    left: -68.75%; }
    --  .col-tablet-pull-13of16 {
    --    left: -81.25%; }
    --  .col-tablet-pull-15of16 {
    --    left: -93.75%; }
    --  .col-tablet-push-1of1, .col-tablet-push-2of2, .col-tablet-push-3of3, .col-tablet-push-4of4, .col-tablet-push-5of5, .col-tablet-push-6of6, .col-tablet-push-8of8, .col-tablet-push-10of10, .col-tablet-push-12of12, .col-tablet-push-16of16 {
    --    left: 100%; }
    --  .col-tablet-push-1of2, .col-tablet-push-2of4, .col-tablet-push-3of6, .col-tablet-push-4of8, .col-tablet-push-5of10, .col-tablet-push-6of12, .col-tablet-push-8of16 {
    --    left: 50%; }
    --  .col-tablet-push-1of3, .col-tablet-push-2of6, .col-tablet-push-4of12 {
    --    left: 33.33333333%; }
    --  .col-tablet-push-2of3, .col-tablet-push-4of6, .col-tablet-push-8of12 {
    --    left: 66.66666667%; }
    --  .col-tablet-push-1of4, .col-tablet-push-2of8, .col-tablet-push-3of12, .col-tablet-push-4of16 {
    --    left: 25%; }
    --  .col-tablet-push-3of4, .col-tablet-push-6of8, .col-tablet-push-9of12, .col-tablet-push-12of16 {
    --    left: 75%; }
    --  .col-tablet-push-1of5, .col-tablet-push-2of10 {
    --    left: 20%; }
    --  .col-tablet-push-2of5, .col-tablet-push-4of10 {
    --    left: 40%; }
    --  .col-tablet-push-3of5, .col-tablet-push-6of10 {
    --    left: 60%; }
    --  .col-tablet-push-4of5, .col-tablet-push-8of10 {
    --    left: 80%; }
    --  .col-tablet-push-1of6, .col-tablet-push-2of12 {
    --    left: 16.66666667%; }
    --  .col-tablet-push-5of6, .col-tablet-push-10of12 {
    --    left: 83.33333333%; }
    --  .col-tablet-push-1of8, .col-tablet-push-2of16 {
    --    left: 12.5%; }
    --  .col-tablet-push-3of8, .col-tablet-push-6of16 {
    --    left: 37.5%; }
    --  .col-tablet-push-5of8, .col-tablet-push-10of16 {
    --    left: 62.5%; }
    --  .col-tablet-push-7of8, .col-tablet-push-14of16 {
    --    left: 87.5%; }
    --  .col-tablet-push-1of10 {
    --    left: 10%; }
    --  .col-tablet-push-3of10 {
    --    left: 30%; }
    --  .col-tablet-push-7of10 {
    --    left: 70%; }
    --  .col-tablet-push-9of10 {
    --    left: 90%; }
    --  .col-tablet-push-1of12 {
    --    left: 8.33333333%; }
    --  .col-tablet-push-5of12 {
    --    left: 41.66666667%; }
    --  .col-tablet-push-7of12 {
    --    left: 58.33333333%; }
    --  .col-tablet-push-11of12 {
    --    left: 91.66666667%; }
    --  .col-tablet-push-1of16 {
    --    left: 6.25%; }
    --  .col-tablet-push-3of16 {
    --    left: 18.75%; }
    --  .col-tablet-push-5of16 {
    --    left: 31.25%; }
    --  .col-tablet-push-7of16 {
    --    left: 43.75%; }
    --  .col-tablet-push-9of16 {
    --    left: 56.25%; }
    --  .col-tablet-push-11of16 {
    --    left: 68.75%; }
    --  .col-tablet-push-13of16 {
    --    left: 81.25%; }
    --  .col-tablet-push-15of16 {
    --    left: 93.75%; } }
    --
    --.col-3-wide {
    --  width: 33.3333333333%; }
    --
    --@media (max-width: 719px) {
    --  /* Remove .col-12 and .col-13 backward compatibility support as soon as it's been removed. */
    --[class*=col-],
    --  .col-12 [class*=col-],
    --  .col-13 [class*=col-] {
    --  float: none;
    --  left: 0;
    --  width: auto;
    --} }
    --
    --/**
    -- * Fades out an element.
    -- * Applies visibility hidden when the transition is finished.
    -- *
    -- * Use opacity: 1; to show the element.
    -- */
    --/* Header component */
    --.dac-header {
    --  box-shadow: 0 2px 2px 0 rgba(0, 0, 0, 0.07);
    --  box-sizing: border-box;
    --  background: #6ab344;
    --  height: 64px;
    --  margin: 0;
    --  left: 0;
    --  position: fixed;
    --  right: 0;
    --  top: 0;
    --  -webkit-transition: background 200ms;
    --  transition: background 200ms;
    --  z-index: 61;
    --}
    --
    --.dac-ndk .dac-header {
    --  background: #00bcd4;
    --}
    --
    --.dac-studio .dac-header {
    --  background: #424242;
    --}
    --
    --.dac-search-mode .dac-header {
    --  background: #b0bec5;
    --  -webkit-transition: background 200ms;
    --  transition: background 200ms;
    --}
    --
    --.dac-search-mode .dac-header-logo,
    --  .dac-search-mode .dac-header-console-btn {
    --  opacity: 0;
    --  visibility: hidden;
    --  -webkit-transition: visibility 0s linear 200ms, opacity 200ms linear;
    --  transition: visibility 0s linear 200ms, opacity 200ms linear;
    --}
    --
    --.dac-header-logo {
    --  display: block;
    --  font-size: 20px;
    --  font-weight: 400;
    --  float: left;
    --  letter-spacing: .3px;
    --  line-height: 36px;
    --  opacity: 1;
    --  padding: 13px 48px 15px 0;
    --}
    --
    --.dac-header-logo, .dac-header-logo:hover, .dac-header-logo:focus {
    --  color: #fff;
    --}
    --
    --@media (min-width: 980px) {
    --  .dac-header-logo {
    --    border-right: 1px solid rgba(0, 0, 0, 0.1);
    --  }
    --}
    --
    --@media (min-width: 720px) and (max-width: 979px) {
    --  .dac-header-logo {
    --    padding-right: 10px;
    --  }
    --}
    --
    --.dac-header-logo-image {
    --  margin-right: 5px;
    --  vertical-align: top;
    --}
    --
    --.dac-header-tabs {
    --  list-style: none;
    --  margin: 0 10px;
    --  display: none;
    --  opacity: 1;
    --  -webkit-transition: opacity 200ms linear 200ms;
    --  transition: opacity 200ms linear 200ms;
    --}
    --
    --@media (min-width: 720px) {
    --  .dac-header-tabs {
    --    display: inline-block;
    --  }
    --
    --  /* Do not show nav toggle and up-nav button for left nav,
    --     when header tabs are visible (when no sub navigation) */
    --  body.no-subnav .dac-nav-back-button {
    --    display:none;
    --  }
    --  body.no-subnav .dac-nav-sub {
    --    top: 0 !important;
    --  }
    --}
    --
    --.dac-header-tabs li {
    --  display: inline-block;
    --}
    --
    --.dac-header-tab {
    --  display: inline-block;
    --  line-height: 64px;
    --  height: 64px;
    --  padding: 0 9px;
    --  color: #fff;
    --  color: rgba(255, 255, 255, 0.7);
    --  font-size: 14px;
    --  text-transform: uppercase;
    --  font-weight: 500;
    --}
    --
    --.dac-header-tab:hover,
    --.dac-header-tab:focus {
    --  color: #fff;
    --}
    --
    --.dac-header-tab.selected {
    --  border-bottom: 4px solid #fff;
    --  height: 60px;
    --  color: #fff;
    --}
    --
    --.dac-search-mode .dac-header-tabs {
    --  opacity: 0;
    --  -webkit-transition: opacity 0ms linear 0ms;
    --  transition: opacity 0ms linear 0ms;
    --}
    --
    --.dac-header-console-btn {
    --  border-radius: 3px;
    --  box-shadow: 0 1px 4px 0 rgba(0, 0, 0, 0.2);
    --  float: right;
    --  font-size: 14px;
    --  font-weight: 500;
    --  line-height: 28px;
    --  margin: 13px 13px 12px 24px;
    --  opacity: 1;
    --  padding: 4px 10px;
    --  position: relative;
    --  text-transform: uppercase;
    --  -webkit-transition: box-shadow .2s;
    --  transition: box-shadow .2s;
    --  z-index: 60;
    --}
    --
    --@media (min-width: 720px) and (max-width: 979px) {
    --  .dac-header-console-btn {
    --    display: none;
    --  }
    --}
    --
    --.dac-header-console-btn > .dac-sprite, .dac-header-console-btn > .dac-modal-header-close:before, .paging-links .dac-header-console-btn > .prev-page-link:before, .paging-links .dac-header-console-btn > .next-page-link:before, .paging-links .dac-header-console-btn > .next-class-link:before, .paging-links .dac-header-console-btn > .start-class-link:after {
    --  margin-right: 5px;
    --}
    --
    --.dac-header-console-btn, .dac-header-console-btn:hover, .dac-header-console-btn:focus {
    --  color: #fff;
    --}
    --
    --.dac-header-console-btn:hover {
    --  box-shadow: 0 2px 8px 0 rgba(0, 0, 0, 0.3);
    --}
    --
    --.dac-header-console-btn:focus {
    --  background: rgba(63, 81, 181, 0.1);
    --  outline: 0;
    --}
    --
    --.dac-studio .dac-header-console-btn {
    --  color:#fff;
    --  background:rgba(255, 255, 255, 0.3);
    --}
    --.dac-studio .dac-header-console-btn:hover {
    --  background:rgba(255, 255, 255, 0.5);
    --}
    --.dac-studio .dac-header-console-btn:focus {
    --  background:rgba(255, 255, 255, 0.7);
    --  color:#000;
    --}
    --
    --@media (max-width: 719px) {
    --  .dac-header {
    --    text-align: center;
    --  }
    --
    --  .dac-header-logo {
    --    border-right: 0;
    --    display: inline-block;
    --    margin-right: 0;
    --    float: none;
    --    padding-left: 0;
    --    padding-right: 0;
    --  }
    --
    --  .dac-header-console-btn {
    --    display: none;
    --  }
    --}
    --
    --/* Header Breadcrumbs component */
    --.dac-header-crumbs {
    --  list-style-type: none;
    --  margin: 23px 0 -13px 0;
    --  display: inline-block;
    --}
    --
    --body.no-crumbs .dac-header-crumbs {
    --  display:none;
    --}
    --
    --.dac-header-crumbs.dac-has-content {
    --  opacity: 1;
    --}
    --
    --.dac-header-crumbs-item {
    --  float: left;
    --  position: relative;
    --  margin: 0;
    --  padding: 0;
    --}
    --
    --.dac-header-crumbs-item i, .dac-header-crumbs-item .dac-nav-link-forward {
    --  display: none;
    --}
    --
    --.dac-header-crumbs-item:before {
    --  content: '';
    --  background: transparent url(../images/styles/disclosure_right.png) no-repeat scroll 50% 50%;
    --  width: 10px;
    --  height: 10px;
    --  display: inline-block;
    --  position: absolute;
    --  top: 12px;
    --  left: -15px;
    --}
    --
    --.dac-header-crumbs-item:first-child:before {
    --  content: none;
    --}
    --
    --.dac-header-crumbs-link {
    --  display: block;
    --  font-size: 16px;
    --  line-height: 32px;
    --  padding: 0 20px 0 0;
    --}
    --
    --.dac-header-crumbs-link, .dac-header-crumbs-link:hover, .dac-header-crumbs-link:focus {
    --  color: #666;
    --}
    --
    --.dac-header-crumbs-link:focus {
    --  outline: 0;
    --  text-decoration: underline;
    --}
    --
    --.dac-header-crumbs-link.current {
    --  font-weight: 400;
    --}
    --
    --/* Header site search component */
    --.dac-header-search {
    --  bottom: 64px;
    --  position: absolute;
    --  right: 220px;
    --  top: 0;
    --  width: 238px;
    --  -webkit-transition: width 300ms, right 100ms, margin 100ms;
    --  transition: width 300ms, right 100ms, margin 100ms;
    --}
    --
    --.dac-studio .dac-header-search {
    --  right: 20px; /* move searchbar farther right, because there's no button */
    --}
    --
    --.dac-header-search-inner {
    --  margin: 0 auto;
    --  max-width: 940px;
    --  position: relative;
    --  width: 100%;
    --}
    --
    --@media (min-width: 980px) {
    --  .dac-header-search-inner::after {
    --    background: -webkit-linear-gradient(right, #6ab344, rgba(106, 179, 68, 0));
    --    background: linear-gradient(to left, #6ab344, rgba(106, 179, 68, 0));
    --    content: '';
    --    display: block;
    --    height: 64px;
    --    position: absolute;
    --    right: 100%;
    --    top: 0;
    --    -webkit-transition: opacity 200ms, -webkit-transform 300ms;
    --    transition: opacity 200ms, transform 300ms;
    --    -webkit-transform-origin: right center;
    --    -ms-transform-origin: right center;
    --    transform-origin: right center;
    --    width: 64px;
    --  }
    --  .dac-studio .dac-header-search-inner::after {
    --    background: -webkit-linear-gradient(right, #424242, rgba(66, 66, 66, 0));
    --    background: linear-gradient(to left, #424242, rgba(66, 66, 66, 0));
    --  }
    --
    --  .dac-search-mode .dac-header-search-inner::after {
    --    opacity: 0;
    --    -webkit-transform: scaleX(0);
    --    -ms-transform: scaleX(0);
    --    transform: scaleX(0);
    --  }
    --}
    --
    --.dac-header-search-icon {
    --  left: 8px;
    --  pointer-events: none;
    --  position: absolute;
    --  top: 18px;
    --}
    --
    --.dac-header-search-input {
    --  background: #77be53;
    --  border-radius: 3px;
    --  border: none;
    --  box-sizing: border-box;
    --  color: #fff;
    --  font-size: 14px;
    --  font-weight: 600;
    --  margin: 13px 0;
    --  padding: 9px 36px 10px;
    --  -webkit-transition: background 200ms, color 200ms;
    --  transition: background 200ms, color 200ms;
    --  width: 100%;
    --}
    --
    --.dac-studio .dac-header-search-input {
    --  background: rgba(255, 255, 255, 0.3);
    --}
    --
    --.dac-header-search-close, .dac-header-search-clear {
    --  background: none;
    --  border: none;
    --  cursor: pointer;
    --  font-size: 0;
    --  outline: none;
    --  position: absolute;
    --  margin: 0;
    --}
    --
    --.dac-header-search-clear {
    --  display: inline-block;
    --  opacity: .4;
    --  padding: 8px;
    --  top: 15px;
    --  right: 0;
    --}
    --
    --.dac-header-search-clear:hover, .dac-header-search-clear:focus {
    --  opacity: .8;
    --}
    --
    --.dac-header-search-close {
    --  left: -45px;
    --  top: 20px;
    --  -webkit-transform: translateX(45px);
    --  -ms-transform: translateX(45px);
    --  transform: translateX(45px);
    --  visibility: hidden;
    --}
    --
    --.dac-header-search ::-webkit-input-placeholder {
    --  color: #fff;
    --  font-weight: 300;
    --  -webkit-transition: color 200ms;
    --  transition: color 200ms;
    --}
    --
    --.dac-header-search :-moz-placeholder {
    --  color: #fff;
    --  font-weight: 300;
    --  transition: color 200ms;
    --}
    --
    --.dac-header-search ::-moz-placeholder {
    --  color: #fff;
    --  font-weight: 300;
    --  transition: color 200ms;
    --}
    --
    --.dac-header-search :-ms-input-placeholder {
    --  color: #fff;
    --  font-weight: 300;
    --  transition: color 200ms;
    --}
    --
    --.dac-header-search-input:focus {
    --  outline: 0;
    --}
    --
    --.dac-search-mode .dac-header-search {
    --  width: 940px;
    --  right: 50%;
    --  margin-right: -470px;
    --}
    --
    --.dac-search-mode .dac-header-search .dac-header-search-input::after {
    --  background: -webkit-linear-gradient(right, #b0bec5, rgba(176, 190, 197, 0));
    --  background: linear-gradient(to left, #b0bec5, rgba(176, 190, 197, 0));
    --}
    --
    --.dac-search-mode .dac-header-search .dac-header-search-close {
    --  -webkit-transition: -webkit-transform 200ms ease-out 300ms;
    --  transition: transform 200ms ease-out 300ms;
    --  -webkit-transform: translateX(0);
    --  -ms-transform: translateX(0);
    --  transform: translateX(0);
    --  visibility: visible;
    --}
    --
    --.dac-search-mode .dac-header-search .dac-header-search-icon {
    --  left: 23px;
    --}
    --
    --.dac-search-mode .dac-header-search .dac-header-search-input {
    --  background: #fff;
    --  border-radius: 0;
    --  font-size: 18px;
    --  color: #666;
    --  padding-left: 55px;
    --  margin-top: 11px;
    --}
    --
    --.dac-search-mode .dac-header-search ::-webkit-input-placeholder {
    --  color: #505050;
    --}
    --
    --.dac-search-mode .dac-header-search :-moz-placeholder {
    --  color: #505050;
    --}
    --
    --.dac-search-mode .dac-header-search ::-moz-placeholder {
    --  color: #505050;
    --}
    --
    --.dac-search-mode .dac-header-search :-ms-input-placeholder {
    --  color: #505050;
    --}
    --
    --@media (min-width: 720px) and (max-width: 979px) {
    --  .dac-studio .dac-header-search,
    --  .dac-header-search {
    --    right: 20px;
    --    width: 200px;
    --    -webkit-transition: left 200ms, right 200ms, width 200ms;
    --    transition: left 200ms, right 200ms, width 200ms;
    --  }
    --
    --  .dac-search-mode .dac-header-search {
    --    left: 60px;
    --    right: 0;
    --    width: 100%;
    --  }
    --
    --  .dac-search-mode .dac-header-search .dac-header-search-inner {
    --    margin: 0;
    --    width: calc(100% - 60px - 10px);
    --  }
    --
    --  .dac-header-search-close {
    --    left: -42px;
    --  }
    --}
    --
    --@media (max-width: 719px) {
    --  .dac-header-search {
    --    bottom: 0;
    --    border-radius: 0;
    --    border-left: 1px solid rgba(0, 0, 0, 0.1);
    --    cursor: pointer;
    --    left: calc(100% - 64px);
    --    margin: 0;
    --    overflow: hidden;
    --    padding-left: 10px;
    --    padding-right: 10px;
    --    position: absolute;
    --    right: 0;
    --    top: 0;
    --  }
    --
    --  .dac-header-search-input {
    --    background: none;
    --    cursor: pointer;
    --    opacity: 0;
    --  }
    --
    --  .dac-search-mode .dac-header-search {
    --    background: #b0bec5;
    --    cursor: default;
    --    overflow: visible;
    --    left: 60px;
    --    right: 0;
    --    width: 100%;
    --    -webkit-transition: left 200ms, right 200ms, width 200ms;
    --    transition: left 200ms, right 200ms, width 200ms;
    --    padding: 0;
    --    border: none;
    --  }
    --
    --  .dac-search-mode .dac-header-search .dac-header-search-inner {
    --    margin: 0;
    --    width: calc(100% - 60px - 10px);
    --  }
    --
    --  .dac-search-mode .dac-header-search .dac-header-search-input {
    --    opacity: 1;
    --  }
    --}
    --
    --.highlighted em {
    --  color: #333;
    --  font-style: normal;
    --  font-weight: 700;
    --}
    --
    --.card-info .title.highlighted {
    --  color: #666;
    --}
    --
    --/* Main navigation component */
    --.dac-nav-sidebar {
    --  background: #f5f8fa;
    --  border-right: 1px solid rgba(0, 0, 0, 0.1);
    --  bottom: 0;
    --  left: 0;
    --  overflow: hidden;
    --  padding: 0;
    --  position: fixed;
    --  top: 64px;
    --  -webkit-transform: translate(-100%, 0);
    --  -ms-transform: translate(-100%, 0);
    --  transform: translate(-100%, 0);
    --  width: 250px;
    --  z-index: 60;
    --}
    --
    --.dac-nav-animating .dac-nav-sidebar {
    --  -webkit-transition: -webkit-transform .3s;
    --  transition: transform .3s;
    --}
    --
    --.dac-nav-open .dac-nav-sidebar {
    --  -webkit-transform: translate(0, 0);
    --  -ms-transform: translate(0, 0);
    --  transform: translate(0, 0);
    --}
    --
    --.dac-search-mode .dac-nav-sidebar {
    --  -webkit-transition: -webkit-transform .3s;
    --  transition: transform .3s;
    --  -webkit-transform: translate(-100%, 0);
    --  -ms-transform: translate(-100%, 0);
    --  transform: translate(-100%, 0);
    --}
    --
    --.dac-nav .dac-swap-section {
    --  -webkit-transition-duration: .3s;
    --  transition-duration: .3s;
    --}
    --
    --.dac-nav-back {
    --  margin-top: -3px;
    --  margin-right: 10px;
    --}
    --
    --.dac-nav-fullscreen {
    --  background: transparent;
    --  border: none;
    --  bottom: 100%;
    --  cursor: pointer;
    --  display: none;
    --  opacity: .8;
    --  outline: none;
    --  padding: 20px 15px;
    --  position: absolute;
    --  right: 0;
    --}
    --
    --@media (min-width: 980px) {
    --  .dac-nav-fullscreen {
    --    display: inline-block;
    --  }
    --}
    --
    --.dac-nav-fullscreen:hover {
    --  opacity: 1;
    --}
    --
    --.dac-nav-sub-slider {
    --  cursor: pointer;
    --  opacity: .5;
    --  position: absolute;
    --  right: 7px;
    --  top: 5px;
    --}
    --
    --.dac-nav-back-button {
    --  background: #546e7a;
    --  border-bottom: 1px solid rgba(0, 0, 0, 0.1);
    --  display: block;
    --  font-weight: 500;
    --  font-size: 18px;
    --  left: 0;
    --  margin: 0;
    --  padding: 20px;
    --  position: absolute !important;
    --  right: 0;
    --  top: 0;
    --  z-index: 1;
    --}
    --
    --.dac-nav-back-button,
    --.dac-nav-back-button:hover,
    --.dac-nav-back-button:active,
    --.dac-nav-back-button:focus     {
    --  color: rgba(255, 255, 255, 0.7);
    --}
    --
    --/* The back button in Studio and NDK left nav */
    --.dac-nav-back-button.back-to-dev {
    --  background: none;
    --  color: #444;
    --  position: relative !important;
    --  top: -16px;
    --}
    --
    --.dac-nav-back-button.back-to-dev:hover,
    --.dac-nav-back-button.back-to-dev:active,
    --.dac-nav-back-button.back-to-dev:focus {
    --  color: rgba(68, 68, 68, .7);
    --}
    --
    --.dac-nav-back-button:focus .dac-nav-back {
    --  outline-color: rgb(77, 144, 254);
    --  outline-offset: 15px;
    --  outline-style: auto;
    --}
    --
    --.dac-nav-back-button > .dac-sprite, .dac-nav-back-button > .dac-modal-header-close:before, .paging-links .dac-nav-back-button > .prev-page-link:before, .paging-links .dac-nav-back-button > .next-page-link:before, .paging-links .dac-nav-back-button > .next-class-link:before, .paging-links .dac-nav-back-button > .start-class-link:after {
    --  opacity: .7;
    --}
    --
    --.dac-nav-logo {
    --  font-size: 20px;
    --  font-weight: 300;
    --  letter-spacing: .3px;
    --  line-height: 36px;
    --  margin: 0;
    --  padding: 14px 24px;
    --}
    --
    --.dac-nav-logo, .dac-nav-logo:hover, .dac-nav-logo:focus {
    --  color: #444;
    --}
    --
    --.dac-nav-list {
    --  bottom: 0;
    --  left: 0;
    --  list-style-type: none;
    --  margin: 0;
    --  -webkit-overflow-scrolling: touch;
    --  overflow-y: scroll;
    --  padding: 16px 0;
    --  position: absolute !important;
    --  right: 0;
    --  top: 0 !important;
    --  scrollbar-face-color: #b7baba;
    --  scrollbar-track-color: #e5e8e9;
    --}
    --
    --.dac-nav-list::-webkit-scrollbar {
    --  width: 4px;
    --  height: 4px;
    --}
    --
    --.dac-nav-list::-webkit-scrollbar-thumb {
    --  background: #b7baba;
    --}
    --
    --.dac-nav-list::-webkit-scrollbar-track {
    --  background: #e5e8e9;
    --}
    --
    --.dac-nav-secondary {
    --  margin: 0;
    --}
    --
    --.dac-nav-item {
    --  list-style-type: none;
    --  margin: 0 0 10px;
    --  position: relative;
    --}
    --
    --.dac-nav-secondary .dac-nav-item {
    --  margin-bottom: 0;
    --}
    --
    --.dac-nav-head {
    --  display: block;
    --  font-size: 16px;
    --  font-weight: 300;
    --  letter-spacing: .24px;
    --  line-height: 32px;
    --  margin-bottom: 20px;
    --  margin-top: 0;
    --}
    --
    --.dac-nav-dimmer {
    --  background: #000;
    --  display: block;
    --  height: 100%;
    --  left: 0;
    --  opacity: 0;
    --  position: fixed;
    --  top: 0;
    --  -webkit-transform: translateZ(0);
    --  transform: translateZ(0);
    --  visibility: hidden;
    --  width: 100%;
    --  z-index: 60;
    --}
    --
    --.dac-nav-animating .dac-nav-dimmer {
    --  -webkit-transition: visibility 0s linear .3s, opacity .3s linear;
    --  transition: visibility 0s linear .3s, opacity .3s linear;
    --}
    --
    --.dac-nav-open .dac-nav-dimmer {
    --  opacity: .8;
    --  -webkit-transition-delay: 0s;
    --  transition-delay: 0s;
    --  visibility: visible;
    --}
    --
    --@media (min-width: 980px) {
    --  .dac-nav-dimmer {
    --    display: none;
    --  }
    --}
    --
    --.dac-nav-hamburger {
    --  display: inline-block;
    --  float: left;
    --  height: 15px;
    --  padding: 22px 20px;
    --  width: 18px;
    --}
    --
    --@media (max-width: 719px) {
    --  .dac-nav-hamburger {
    --    border-right: 1px solid rgba(0, 0, 0, 0.1);
    --    left: 0;
    --    padding-bottom: 27px;
    --    position: absolute;
    --    top: 0;
    --  }
    --}
    --
    --.dac-nav-hamburger-top, .dac-nav-hamburger-mid, .dac-nav-hamburger-bot {
    --  background: rgba(0, 0, 0, 0.4);
    --  display: block;
    --  height: 2px;
    --  margin: 3px 0 0;
    --  opacity: .5;
    --  width: 100%;
    --}
    --
    --.dac-studio .dac-nav-hamburger-top,
    --.dac-studio .dac-nav-hamburger-mid,
    --.dac-studio .dac-nav-hamburger-bot {
    --  background: rgba(256, 256, 256, 0.4);
    --}
    --
    --.dac-nav-animating .dac-nav-hamburger-top, .dac-nav-animating .dac-nav-hamburger-mid, .dac-nav-animating .dac-nav-hamburger-bot {
    --  -webkit-transition: opacity .3s;
    --  transition: opacity .3s;
    --}
    --
    --@media (max-width: 719px) {
    --  .dac-nav-hamburger-top, .dac-nav-hamburger-mid, .dac-nav-hamburger-bot {
    --    background: #fff;
    --    opacity: 1;
    --  }
    --}
    --
    --.dac-nav-open .dac-nav-hamburger-top,
    --  .dac-nav-open .dac-nav-hamburger-mid,
    --  .dac-nav-open .dac-nav-hamburger-bot {
    --  opacity: 1;
    --}
    --
    --.dac-search-mode .dac-nav-hamburger {
    --  opacity: 0;
    --  visibility: hidden;
    --  -webkit-transition: visibility 0s linear 200ms, opacity 200ms linear;
    --  transition: visibility 0s linear 200ms, opacity 200ms linear;
    --}
    --
    --.dac-nav-link {
    --  color: #444;
    --  display: block;
    --  font-size: 14px;
    --  text-transform: uppercase;
    --  font-weight: 500;
    --  letter-spacing: .24px;
    --  padding: 5px 20px;
    --  -webkit-transition: background-color 0.35s cubic-bezier(0.35, 0, 0.25, 1);
    --  transition: background-color 0.35s cubic-bezier(0.35, 0, 0.25, 1);
    --}
    --
    --.dac-nav-link:hover, .dac-nav-link:focus {
    --  color: rgba(68, 68, 68, 0.7);
    --}
    --
    --.dac-nav-link:focus {
    --  background: rgba(63, 81, 181, 0.1);
    --  outline: 0;
    --}
    --
    --.dac-nav-secondary .dac-nav-link {
    --  font-size: 12px;
    --  font-weight: 400;
    --  padding-left: 40px;
    --  text-transform: none;
    --}
    --
    --.dac-nav-link.selected {
    --  background: rgba(63, 81, 181, 0.1);
    --  color: #039bef;
    --  position: relative;
    --}
    --
    --.dac-nav-link-forward {
    --  background: #546E7A;
    --  color: #fff;
    --  cursor: pointer;
    --  display: inline-block;
    --  line-height: 34px;
    --  padding: 0;
    --  position: absolute;
    --  right: 0;
    --  top: 0;
    --  text-align: center;
    --  width: 34px;
    --}
    --
    --.dac-nav-link-forward > .dac-nav-forward {
    --  opacity: .7;
    --  vertical-align: -3px;
    --}
    --
    --.dac-nav-sub {
    --  bottom: 0;
    --  left: 0;
    --  position: absolute !important;
    --  top: 65px !important;
    --  right: 0;
    --  z-index: 1;
    --}
    --
    --#body-content {
    --  padding-top: 64px;
    --}
    --
    --.dac-nav-animating #body-content {
    --  -webkit-transition: padding .3s;
    --  transition: padding .3s;
    --}
    --
    --@media (min-width: 980px) {
    --  .dac-nav-open #body-content {
    --    padding-left: 250px;
    --  }
    --
    --  /* Do not show nav toggle on large screens (when no subnav) */
    --  body.no-subnav .dac-nav-toggle {
    --    display:none;
    --  }
    --  body.no-subnav .dac-header-logo {
    --    padding-left:20px;
    --  }
    --  /* ...If the page is also full-width, then don't show left nav at all */
    --  body.no-subnav.full-width .dac-nav {
    --    display: none;
    --  }
    --  body.no-subnav.full-width #body-content {
    --    padding-left:0;
    --  }
    --}
    --
    --.dac-nav-open {
    --  overflow: hidden;
    --}
    --
    --@media (min-width: 980px) {
    --  .dac-nav-open {
    --    overflow: visible;
    --  }
    --}
    --
    --#devdoc-nav {
    --  height: 100%;
    --}
    --
    --.data-reference-resources-wrapper {
    --  display: none;
    --}
    --
    --.dac-reference-nav {
    --  height: calc(100% - 36px);
    --  overflow: hidden;
    --  position: relative;
    --}
    --
    --.dac-reference-nav ul,
    --  .dac-reference-nav li {
    --  margin: 0;
    --  list-style-type: none;
    --}
    --
    --.dac-reference-nav-list {
    --  bottom: 0;
    --  overflow: hidden;
    --  overflow-y: scroll;
    --  left: 0;
    --  padding: 10px;
    --  padding-left: 20px;
    --  position: absolute;
    --  right: 0;
    --  top: 0;
    --  scrollbar-face-color: #9da4a7;
    --  scrollbar-track-color: #c4cdd1;
    --}
    --
    --.dac-reference-nav-list::-webkit-scrollbar {
    --  width: 4px;
    --  height: 4px;
    --}
    --
    --.dac-reference-nav-list::-webkit-scrollbar-thumb {
    --  background: #9da4a7;
    --}
    --
    --.dac-reference-nav-list::-webkit-scrollbar-track {
    --  background: #c4cdd1;
    --}
    --
    --.dac-reference-nav-resources {
    --  display: none;
    --  padding: 0 0 0 13px;
    --}
    --
    --.dac-reference-nav-resource,
    --.dac-reference-nav-toggle {
    --  color: #505050;
    --  cursor: pointer;
    --  display: block;
    --  font-size: 12px;
    --  line-height: 1;
    --  overflow: hidden;
    --  margin: 0;
    --  padding: 3px 0;
    --  position: relative;
    --  text-overflow: ellipsis;
    --  white-space: nowrap;
    --}
    --
    --.dac-reference-nav-toggle {
    --  margin-left: -12px;
    --  padding-left: 12px;
    --}
    --
    --.selected > .dac-reference-nav-resource {
    --  color: #039bef;
    --  font-weight: 600;
    --}
    --
    --.dac-reference-nav-toggle::before {
    --  background: transparent url(../images/styles/disclosure_up.png) no-repeat center center;
    --  content: '';
    --  display: block;
    --  height: 19px;
    --  left: 0;
    --  position: absolute;
    --  top: 0;
    --  width: 8px;
    --}
    --
    --.dac-reference-nav-toggle.dac-closed::before {
    --  -webkit-transform: scaleY(-1);
    --  -ms-transform: scaleY(-1);
    --  transform: scaleY(-1);
    --}
    --
    --/* nav */
    --#nav {
    --  background: #cfd8dc;
    --  bottom: 0;
    --  left: 0;
    --  margin: 0;
    --  -webkit-overflow-scrolling: touch;
    --  overflow-y: scroll;
    --  position: absolute !important;
    --  right: 0;
    --  top: 0 !important;
    --  padding: 10px;
    --  scrollbar-face-color: #9da4a7;
    --  scrollbar-track-color: #c4cdd1;
    --  /* section header links */
    --  /* nested nav headers */
    --}
    --
    --#nav::-webkit-scrollbar {
    --  width: 4px;
    --  height: 4px;
    --}
    --
    --#nav::-webkit-scrollbar-thumb {
    --  background: #9da4a7;
    --}
    --
    --#nav::-webkit-scrollbar-track {
    --  background: #c4cdd1;
    --}
    --
    --#nav li {
    --  font-size: 12px;
    --  line-height: 18px;
    --  list-style-type: none;
    --  margin: 0;
    --  padding: 0;
    --}
    --
    --#nav a {
    --  color: #505050;
    --  text-decoration: none;
    --  word-wrap: break-word;
    --}
    --
    --#nav .nav-section-header {
    --  padding: 0 30px 0 0;
    --  position: relative;
    --  -webkit-transition: background-color .1s;
    --  transition: background-color .1s;
    --}
    --
    --#nav .nav-section-header.empty {
    --  padding: 0;
    --}
    --
    --#nav .nav-section-header.empty::after {
    --  display: none;
    --}
    --
    --#nav .nav-section-header .toggle-icon {
    --  background: transparent url(../images/styles/disclosure_down.png) no-repeat scroll 50% 50%;
    --  content: '';
    --  height: 34px;
    --  display: block;
    --  position: absolute;
    --  right: 0;
    --  top: 1px;
    --  width: 34px;
    --}
    --
    --#nav li.selected a {
    --  color: #0288D1;
    --}
    --
    --#nav li.selected ul li a {
    --  color: #505050;
    --}
    --
    --#nav li.expanded .nav-section-header {
    --  background: #bac2c6;
    --}
    --
    --#nav li.expanded .nav-section-header.empty {
    --  background: none;
    --}
    --
    --#nav li.expanded li .nav-section-header {
    --  background: none;
    --}
    --
    --#nav li.expanded li ul {
    --  padding: 0 10px;
    --}
    --
    --#nav li.expanded > .nav-section-header .toggle-icon {
    --  content: '';
    --  background: transparent url(../images/styles/disclosure_up.png) no-repeat scroll 50% 50%;
    --  width: 34px;
    --  height: 34px;
    --}
    --
    --#nav li.expanded li ul.tree-list-children {
    --  padding: 0;
    --}
    --
    --#nav li.expanded li ul.tree-list-children .tree-list-children {
    --  padding: 0 0 0 10px;
    --}
    --
    --#nav .nav-section .nav-section .nav-section-header {
    --    /* no white line between second level sections */
    --  margin-bottom: 0;
    --}
    --
    --#nav > li > div > a {
    --  display: block;
    --  font-weight: 700;
    --  padding: 10px;
    --}
    --
    --#nav .nav-section .nav-section {
    --  position: relative;
    --  padding: 0;
    --  margin: 0;
    --}
    --
    --#nav .nav-section li a {
    --    /* first gen child (2nd level li) */
    --  display: block;
    --  font-weight: 700;
    --  text-transform: none;
    --  padding: 10px;
    --}
    --
    --#nav .nav-section li li a {
    --    /* second gen child (3rd level li) */
    --  font-weight: 400;
    --  padding: 6px 6px 6px 10px;
    --}
    --
    --#nav li span.tree-list-subtitle {
    --  display: inline-block;
    --  color: #555;
    --  font-size: 12px;
    --  padding: 10px;
    --  text-transform: uppercase;
    --}
    --
    --#nav li span.tree-list-subtitle:before {
    --  content: '—';
    --}
    --
    --#nav li span.tree-list-subtitle:after {
    --  content: '—';
    --}
    --
    --#nav li span.tree-list-subtitle.package {
    --  padding-top: 15px;
    --  cursor: default;
    --}
    --
    --#nav li span.tree-list-subtitle.package:before {
    --  content: '';
    --}
    --
    --#nav li span.tree-list-subtitle.package:after {
    --  content: '';
    --}
    --
    --#nav li ul.tree-list-children.classes {
    --  padding-left: 10px;
    --}
    --
    --#nav li ul {
    --  display: none;
    --  overflow: hidden;
    --  margin: 0;
    --}
    --
    --#nav li ul.animate-height-in {
    --  -webkit-transition: height 0.25s ease-in;
    --  transition: height 0.25s ease-in;
    --}
    --
    --#nav li ul.animate-height-out {
    --  -webkit-transition: height 0.25s ease-out;
    --  transition: height 0.25s ease-out;
    --}
    --
    --#nav li ul li {
    --  padding: 0;
    --}
    --
    --#nav li li li {
    --  padding: 0;
    --}
    --
    --#nav li ul > li {
    --  padding: 0;
    --}
    --
    --#nav li ul > li:last-child {
    --  padding-bottom: 5px;
    --}
    --
    --#nav li ul.tree-list-children > li:last-child {
    --  padding-bottom: 0;
    --}
    --
    --#nav li.expanded ul > li {
    --  background: #c4cdd1;
    --}
    --
    --#nav li.expanded ul > li li {
    --  background: inherit;
    --}
    --
    --#nav li ul.tree-list-children ul {
    --  display: block;
    --}
    --
    --#nav.samples-nav li li li a {
    --  padding-top: 3px;
    --  padding-bottom: 3px;
    --}
    --
    --#nav.samples-nav li li ul > li:last-child {
    --  padding-bottom: 3px;
    --}
    --
    --/* Hero carousel */
    --.dac-hero {
    --  background-color: #fff;
    --  background-position: 50% 30%;
    --  background-size: cover;
    --  box-sizing: border-box;
    --  font-size: 16px;
    --  min-height: 550px;
    --  padding-top: 88px;
    --}
    --
    --.dac-hero.dac-darken::before {
    --  background: rgba(0, 0, 0, 0.3);
    --  bottom: 0;
    --  content: '';
    --  display: block;
    --  left: 0;
    --  position: absolute;
    --  right: 0;
    --  top: 0;
    --}
    --
    --.dac-hero {
    --  background-size: cover;
    --  position: relative;
    --}
    --
    --.dac-hero-headline {
    --  background-color: #fff;
    --  bottom: 25px;
    --  float: none !important;
    --  padding: 0 10px 10px;
    --  position: absolute;
    --  right: 0;
    --  z-index: 2;
    --}
    --
    --@media (max-width: 719px) {
    --  .dac-hero-headline {
    --    bottom: 0;
    --  }
    --
    --  .dac-hero.dac-darken::before {
    --    background: -webkit-linear-gradient(top, rgba(0, 0, 0, 0.3), rgba(0, 0, 0, 0.8), rgba(0, 0, 0, 0.9) 80%);
    --    background: linear-gradient(to bottom, rgba(0, 0, 0, 0.3), rgba(0, 0, 0, 0.8), rgba(0, 0, 0, 0.9) 80%);
    --  }
    --}
    --
    --.dac-hero.dac-darken .dac-hero-content {
    --  position: relative;
    --}
    --
    --@media (max-width: 719px) {
    --  .dac-hero {
    --    padding-bottom: 20px;
    --    padding-top: 20px;
    --  }
    --}
    --
    --.dac-hero-tag {
    --  font-size: 11px;
    --  font-weight: 700;
    --  letter-spacing: .07em;
    --  margin-bottom: 2px;
    --  text-transform: uppercase;
    --}
    --
    --.dac-hero-title {
    --  margin: 0 0 14px;
    --}
    --
    --.dac-studio .dac-hero-title {
    --  padding-top:0;
    --}
    --
    --@media (max-width: 719px) {
    --  .dac-hero-title {
    --    font-size: 28px;
    --    line-height: 35px;
    --  }
    --}
    --
    --.dac-hero-description {
    --  margin-bottom: 16px;
    --}
    --
    --@media (max-width: 719px) {
    --  .dac-hero-description {
    --    font-size: 14px;
    --  }
    --}
    --
    --.dac-hero-cta {
    --  display: inline-block;
    --  line-height: 40px;
    --  margin-right: 20px;
    --  -webkit-transition: opacity .3s;
    --  transition: opacity .3s;
    --}
    --
    --.dac-hero-cta:hover {
    --  color: currentColor;
    --  opacity: .54;
    --}
    --
    --.dac-hero-cta .dac-sprite, .dac-hero-cta .dac-modal-header-close:before, .dac-hero-cta .paging-links .prev-page-link:before, .paging-links .dac-hero-cta .prev-page-link:before, .dac-hero-cta .paging-links .next-page-link:before, .paging-links .dac-hero-cta .next-page-link:before, .dac-hero-cta .paging-links .next-class-link:before, .paging-links .dac-hero-cta .next-class-link:before, .dac-hero-cta .paging-links .start-class-link:after, .paging-links .dac-hero-cta .start-class-link:after {
    --  margin-left: -8px;
    --}
    --
    --.dac-hero-cta.col-16 {
    --  line-height: 1.4em;
    --  margin-top: 20px;
    --  padding-left: 0;
    --  position: relative;
    --}
    --
    --.dac-hero-cta.col-16 .dac-sprite {
    --  position: absolute;
    --  left: 0;
    --  top: -3px;
    --}
    --
    --.dac-hero-cta.col-16 .dac-sprite-text {
    --  position: relative;
    --  left: 12px;
    --}
    --
    --@media (max-width: 719px) {
    --  .dac-hero-cta {
    --    line-height: 28px;
    --  }
    --}
    --
    --.dac-hero-figure {
    --  text-align: center;
    --}
    --
    --/* Android Studio download page */
    --.dac-studio section#features {
    --  padding-top:0;
    --}
    --.dac-studio .wrap.feature {
    --  margin:80px auto;
    --}
    --.dac-studio .dac-section-links.feature-more {
    --  margin-top:-20px;
    --}
    --.dac-studio .dac-toggle-content .wrap.feature {
    --  margin-top:0;
    --}
    --
    --@media (max-width: 719px) {
    --  .dac-hero-figure {
    --    height: 150px;
    --    margin: 15px 0;
    --  }
    --
    --  .dac-hero-figure img {
    --    max-height: 150px;
    --  }
    --
    --  /* Android Studio download page */
    --  .dac-studio .feature .dac-hero-figure,
    --  .dac-studio .feature .dac-hero-figure img {
    --    height:auto;
    --    max-height:none;
    --  }
    --  .dac-studio .feature .dac-hero-figure img {
    --    width:90%;
    --    margin:0 auto;
    --  }
    --}
    --
    --.dac-hero-carousel {
    --  height: 550px;
    --  position: relative;
    --}
    --
    --.dac-hero-carousel > .dac-hero {
    --  bottom: 0;
    --  left: 0;
    --  position: absolute;
    --  right: 0;
    --  top: 0;
    --  will-change: opacity;
    --}
    --
    --.dac-hero-carousel > .dac-hero,
    --    .dac-hero-carousel > .dac-hero .wrap {
    --  opacity: 0;
    --}
    --
    --.dac-hero-carousel > .dac-hero.active {
    --  opacity: 1;
    --  -webkit-transition: opacity .5s;
    --  transition: opacity .5s;
    --  z-index: 1;
    --}
    --
    --.dac-hero-carousel > .dac-hero.active .wrap {
    --  opacity: 1;
    --  -webkit-transition: opacity .5s .5s;
    --  transition: opacity .5s .5s;
    --}
    --
    --.dac-hero-carousel > .dac-hero.out,
    --    .dac-hero-carousel > .dac-hero.out .wrap {
    --  -webkit-transition: opacity 0s .5s;
    --  transition: opacity 0s .5s;
    --  opacity: 0;
    --}
    --
    --.dac-hero-carousel-action {
    --  bottom: 0;
    --  display: block;
    --  left: 0;
    --  position: absolute;
    --  right: 0;
    --  top: 0;
    --  z-index: 1;
    --}
    --
    --.dac-hero-carousel .dac-hero-cta {
    --  position: relative;
    --  z-index: 1;
    --}
    --
    --.dac-hero-carousel-pagination {
    --  bottom: 33px;
    --  left: 0;
    --  position: absolute;
    --  right: 0;
    --}
    --
    --@media (max-width: 719px) {
    --  .dac-hero-carousel-pagination {
    --    text-align: center;
    --    bottom: 20px;
    --  }
    --}
    --
    --.dac-hero-carousel-pagination .dac-pagination-item {
    --  position: relative;
    --  z-index: 1;
    --}
    --
    --.dac-pagination {
    --  list-style: none;
    --  margin: 0 -6px;
    --}
    --
    --.dac-pagination-item {
    --  background-clip: content-box;
    --  background-color: rgba(153, 153, 153, 0.4);
    --  border-radius: 50%;
    --  cursor: pointer;
    --  display: inline-block;
    --  height: 14px;
    --  overflow: hidden;
    --  padding: 6px;
    --  pointer-events: all;
    --  text-indent: 100%;
    --  -webkit-transition: background-color .1s ease-in;
    --  transition: background-color .1s ease-in;
    --  white-space: nowrap;
    --  width: 14px;
    --  will-change: background-color;
    --}
    --
    --.dac-pagination-item:hover {
    --  background-color: rgba(153, 153, 153, 0.6);
    --}
    --
    --.dac-pagination-item.active, .dac-pagination-item.active:hover {
    --  background-color: #6ab344;
    --}
    --
    --.dac-invert .dac-pagination-item {
    --  background-color: rgba(204, 204, 204, 0.2);
    --}
    --
    --.dac-invert .dac-pagination-item:hover {
    --  background-color: rgba(153, 153, 153, 0.4);
    --}
    --
    --@media (max-width: 719px) {
    --  .dac-pagination-item {
    --    height: 12px;
    --    width: 12px;
    --  }
    --}
    --
    --/* Form component */
    --.dac-form {
    --  color: #505050;
    --  font-size: 16px;
    --  /* Modal Responsive */
    --}
    --
    --.dac-form a {
    --  color: #000;
    --}
    --
    --.dac-form-aside {
    --  display: inline-block;
    --  font-size: 12px;
    --  margin-top: 0;
    --}
    --
    --.dac-form-required {
    --  color: #ef4300;
    --}
    --
    --.dac-form-fieldset {
    --  padding: 0;
    --}
    --
    --.dac-form-legend {
    --  display: block;
    --  color: #333;
    --  font-weight: 500;
    --  margin: 20px 0 12px;
    --  padding: 0;
    --  width: 100%;
    --}
    --
    --.dac-form-legend > .dac-form-required {
    --  float: right;
    --  margin-top: 3px;
    --}
    --
    --.dac-form-input {
    --  border: 0 solid #e3e3e3;
    --  border-bottom-width: 1px;
    --  display: block;
    --  outline: 0;
    --  padding: 1px 0 8px;
    --  -webkit-transition: border-color .2s;
    --  transition: border-color .2s;
    --  width: 100%;
    --}
    --
    --.dac-form-input-group {
    --  position: relative;
    --}
    --
    --.dac-form-input-group > .dac-form-required {
    --  display: block;
    --  bottom: 3px;
    --  position: absolute;
    --  right: 0;
    --}
    --
    --.dac-form-input:focus {
    --  border-bottom-color: #09f;
    --}
    --
    --.dac-form-floatlabel {
    --  display: block;
    --  cursor: text;
    --  margin-top: 5px;
    --  pointer-events: none;
    --  -webkit-transform-origin: 0 100%;
    --  -ms-transform-origin: 0 100%;
    --  transform-origin: 0 100%;
    --  -webkit-transform: translate3d(0, 22px, 0) scale(1);
    --  transform: translate3d(0, 22px, 0) scale(1);
    --  -webkit-transition: -webkit-transform .2s;
    --  transition: transform .2s;
    --}
    --
    --.dac-focused > .dac-form-floatlabel,
    --    .dac-has-value > .dac-form-floatlabel {
    --  cursor: default;
    --  -webkit-transform: translate3d(0, 0, 0) scale(0.75);
    --  transform: translate3d(0, 0, 0) scale(0.75);
    --}
    --
    --.dac-form-radio, .dac-form-checkbox {
    --  opacity: 0;
    --  position: absolute;
    --  visibility: hidden;
    --}
    --
    --.dac-form-radio-group, .dac-form-checkbox-group {
    --  display: table;
    --}
    --
    --.dac-form-radio-group + .dac-form-radio-group, .dac-form-checkbox-group + .dac-form-radio-group, .dac-form-radio-group + .dac-form-checkbox-group, .dac-form-checkbox-group + .dac-form-checkbox-group {
    --  margin-top: 10px;
    --}
    --
    --.dac-form-radio-button, .dac-form-checkbox-button {
    --  box-sizing: border-box;
    --  cursor: pointer;
    --  display: table-cell;
    --  float: left;
    --  height: 18px;
    --  margin: 2px 10px 0 0;
    --  position: relative;
    --  width: 18px;
    --}
    --
    --.dac-form-radio-button::after, .dac-form-radio-button::before, .dac-form-checkbox-button::after, .dac-form-checkbox-button::before {
    --  box-sizing: border-box;
    --  content: '';
    --  display: block;
    --  position: absolute;
    --}
    --
    --.dac-form-radio-button::after, .dac-form-radio-button::before {
    --  border-radius: 50%;
    --  height: 100%;
    --  width: 100%;
    --}
    --
    --.dac-form-radio-button::before {
    --  background: rgba(0, 0, 0, 0.7);
    --  -webkit-transform: translateZ(0) scale(0);
    --  transform: translateZ(0) scale(0);
    --  -webkit-transition: -webkit-transform .3s;
    --  transition: transform .3s;
    --}
    --
    --.dac-form-radio-button::after {
    --  border: 2px solid rgba(0, 0, 0, 0.7);
    --}
    --
    --.dac-form-radio:checked + .dac-form-radio-button::before {
    --  -webkit-transform: translateZ(0) scale(0.5);
    --  transform: translateZ(0) scale(0.5);
    --}
    --
    --.dac-form-radio:focus + .dac-form-radio-button::after {
    --  border: 2px solid #09f;
    --}
    --
    --.dac-form-checkbox-button::before {
    --  border: 1px solid #6c6e6f;
    --  border-radius: 3px;
    --  height: 100%;
    --  -webkit-transition: background .1s ease-out, box-shadow .3s ease-out;
    --  transition: background .1s ease-out, box-shadow .3s ease-out;
    --  width: 100%;
    --}
    --
    --.dac-form-checkbox-button::after {
    --  border-bottom: 2px solid #fff;
    --  border-left: 2px solid #fff;
    --  bottom: 7px;
    --  height: 7px;
    --  left: 3px;
    --  -webkit-transform: rotate(-45deg);
    --  -ms-transform: rotate(-45deg);
    --  transform: rotate(-45deg);
    --  width: 12px;
    --}
    --
    --.dac-form-checkbox:checked + .dac-form-checkbox-button::before {
    --  background: #6c6e6f;
    --  -webkit-transition-timing-function: ease-in;
    --  transition-timing-function: ease-in;
    --}
    --
    --.dac-form-checkbox:focus + .dac-form-checkbox-button::before,
    --  .dac-form-checkbox:active + .dac-form-checkbox-button::before {
    --  box-shadow: 0 0 0 4px rgba(0, 0, 0, 0.05);
    --}
    --
    --.dac-form-label {
    --  cursor: pointer;
    --  -webkit-user-select: none;
    --  -moz-user-select: none;
    --  -ms-user-select: none;
    --  user-select: none;
    --}
    --
    --@media (max-width: 719px) {
    --  .dac-form-legend {
    --    margin-bottom: 0;
    --  }
    --}
    --
    --/* Filter Resources Component*/
    --.dac-filter {
    --  color: #505050;
    --  margin-bottom: 20px;
    --  position: relative;
    --}
    --
    --.dac-filter.dac-filter-section {
    --  margin-top: -45px;
    --  text-align: right;
    --}
    --
    --@media (max-width: 719px) {
    --  .dac-filter.dac-filter-section {
    --    margin-top: 0;
    --    text-align: left;
    --  }
    --}
    --
    --.dac-filter-title {
    --  color: #666;
    --  cursor: default;
    --  display: inline-block;
    --  font-size: 12px;
    --  font-weight: 500;
    --  line-height: 24px;
    --  margin: 0;
    --  text-transform: uppercase;
    --}
    --
    --@media (max-width: 719px) {
    --  .dac-filter-title {
    --    margin-bottom: 20px;
    --  }
    --}
    --
    --.dac-filter-message {
    --  color: #78868d;
    --  font-size: 18px;
    --  margin: 0 10px 10px;
    --}
    --
    --.dac-filter-count {
    --  background: #6ab344;
    --  border-radius: 50%;
    --  color: #fff;
    --  display: inline-block;
    --  font-size: 12px;
    --  font-weight: 600;
    --  height: 24px;
    --  text-align: center;
    --  width: 24px;
    --}
    --
    --.dac-filter-count.dac-disabled {
    --  visibility: hidden;
    --}
    --
    --.dac-filter-chip {
    --  background: #bfc7cb;
    --  border-radius: 15px;
    --  color: #333;
    --  cursor: default;
    --  display: inline-block;
    --  line-height: 21px;
    --  margin: 0 10px 10px 0;
    --  padding: 4px 26px 4px 10px;
    --  position: relative;
    --}
    --
    --.dac-filter-chip-close {
    --  background-color: transparent;
    --  border: none;
    --  cursor: pointer;
    --  outline: 0;
    --  padding: 3px;
    --  position: absolute;
    --  right: 5px;
    --  top: 5px;
    --}
    --
    --.dac-filter-chip-close-icon {
    --  opacity: .7;
    --  margin-top: -2px;
    --  -webkit-transform: scale(0.57142857);
    --  -ms-transform: scale(0.57142857);
    --  transform: scale(0.57142857);
    --}
    --
    --.dac-filter-chip-close:hover > .dac-filter-chip-close-icon {
    --  opacity: 1;
    --}
    --
    --.dac-filter-chips {
    --  border-top: 1px solid rgba(0, 0, 0, 0.1);
    --  margin: 0;
    --  list-style-type: none;
    --  padding: 10px 0 0;
    --  position: relative;
    --  text-align: left;
    --}
    --
    --.dac-filter-item {
    --  box-sizing: border-box;
    --  float: left;
    --  margin-bottom: 20px;
    --  padding: 0 10px;
    --  width: 33.33333333%;
    --}
    --
    --@media (min-width: 720px) and (max-width: 979px) {
    --  .dac-filter-item {
    --    width: 50%;
    --  }
    --}
    --
    --@media (max-width: 719px) {
    --  .dac-filter-item {
    --    width: 100%;
    --  }
    --}
    --
    --/* Media component */
    --.dac-media {
    --  display: table;
    --  width: 100%;
    --}
    --
    --.dac-media-body, .dac-media-figure {
    --  display: table-cell;
    --  vertical-align: top;
    --}
    --
    --.dac-media-figure {
    --  padding: 0;
    --}
    --
    --.dac-media-body {
    --  width: 100%;
    --}
    --
    --.dac-swap {
    --  overflow: hidden;
    --  position: relative;
    --}
    --
    --.dac-swap-section {
    --  left: 0;
    --  opacity: 0;
    --  position: absolute;
    --  top: 0;
    --  width: 100%;
    --  -webkit-transition: opacity 1s, -webkit-transform .5s;
    --  transition: opacity 1s, transform .5s;
    --}
    --
    --.dac-swap-section.dac-no-anim {
    --  -webkit-transition: none;
    --  transition: none;
    --}
    --
    --.dac-swap-section.dac-up {
    --  -webkit-transform: translateY(-100%);
    --  -ms-transform: translateY(-100%);
    --  transform: translateY(-100%);
    --}
    --
    --.dac-swap-section.dac-down {
    --  -webkit-transform: translateY(100%);
    --  -ms-transform: translateY(100%);
    --  transform: translateY(100%);
    --}
    --
    --.dac-swap-section.dac-left {
    --  -webkit-transform: translateX(-100%);
    --  -ms-transform: translateX(-100%);
    --  transform: translateX(-100%);
    --}
    --
    --.dac-swap-section.dac-right {
    --  -webkit-transform: translateX(100%);
    --  -ms-transform: translateX(100%);
    --  transform: translateX(100%);
    --}
    --
    --.dac-swap-section.dac-active {
    --  opacity: 1;
    --  position: relative;
    --  -webkit-transform: translate(0, 0);
    --  -ms-transform: translate(0, 0);
    --  transform: translate(0, 0);
    --  width: auto;
    --}
    --
    --/* Modal component */
    --.dac-modal {
    --  opacity: 0;
    --  visibility: hidden;
    --  -webkit-transition: visibility 0s linear 300ms, opacity 300ms linear;
    --  transition: visibility 0s linear 300ms, opacity 300ms linear;
    --  background: rgba(0, 0, 0, 0.8);
    --  bottom: 0;
    --  left: 0;
    --  overflow-x: hidden;
    --  overflow-y: auto;
    --  position: fixed;
    --  right: 0;
    --  top: 0;
    --  z-index: 70;
    --}
    --
    --.dac-modal.dac-active {
    --  opacity: 1;
    --  -webkit-transition-delay: 0s;
    --  transition-delay: 0s;
    --  visibility: visible;
    --}
    --
    --.dac-modal-open {
    --  overflow: hidden;
    --}
    --
    --.dac-modal-container {
    --  -webkit-box-align: center;
    --  -webkit-align-items: center;
    --  -ms-flex-align: center;
    --  align-items: center;
    --  display: -webkit-box;
    --  display: -webkit-flex;
    --  display: -ms-flexbox;
    --  display: flex;
    --  -webkit-filter: drop-shadow(0 5px 15px rgba(0, 0, 0, 0.4));
    --  filter: drop-shadow(0 5px 15px rgba(0, 0, 0, 0.4));
    --  -webkit-box-pack: center;
    --  -webkit-justify-content: center;
    --  -ms-flex-pack: center;
    --  justify-content: center;
    --  min-height: 100%;
    --  width: 100%;
    --}
    --
    --.dac-modal-window {
    --  background: #fff;
    --  box-sizing: border-box;
    --  margin: 20px auto;
    --  -webkit-transition: -webkit-transform .3s;
    --  transition: transform .3s;
    --  -webkit-transform: translate3d(0, -30px, 0);
    --  transform: translate3d(0, -30px, 0);
    --  width: 960px;
    --}
    --
    --.dac-modal.dac-active .dac-modal-window {
    --  -webkit-transform: translate3d(0, 0, 0);
    --  transform: translate3d(0, 0, 0);
    --}
    --
    --.dac-modal-header {
    --  background: #00695c;
    --  padding: 35px 35px 30px;
    --  position: relative;
    --}
    --
    --.dac-has-small-header .dac-modal-header {
    --  padding: 10px 20px;
    --}
    --
    --.dac-modal-header-actions {
    --  padding: 8px;
    --  position: absolute;
    --  right: 5px;
    --  top: 5px;
    --}
    --
    --.dac-modal-header-open, .dac-modal-header-close {
    --  background: none;
    --  border: none;
    --  cursor: pointer;
    --  line-height: 0;
    --  outline: 0;
    --  opacity: .7;
    --  -webkit-transition: background-color .3s;
    --  transition: background-color .3s;
    --}
    --
    --.dac-modal-header-open:active, .dac-modal-header-close:active {
    --  background: rgba(255, 255, 255, 0.2);
    --}
    --
    --.dac-modal-header-close:before {
    --  content: '';
    --  top: -1px;
    --  position: relative;
    --}
    --
    --.dac-modal-header-open {
    --  margin: 10px;
    --}
    --
    --.dac-modal-header-title {
    --  color: #fff;
    --  font-size: 24px;
    --  font-weight: 300;
    --  line-height: 32px;
    --  padding: 0 150px 0 0;
    --}
    --
    --.dac-has-small-header .dac-modal-header-title {
    --  font-size: 16px;
    --  font-weight: 500;
    --}
    --
    --.dac-modal-header-subtitle {
    --  bottom: 0;
    --  color: #fff;
    --  display: inline-block;
    --  font: inherit;
    --  font-size: 14px;
    --  margin: 0;
    --  opacity: .8;
    --  position: absolute;
    --  right: 0;
    --}
    --
    --.dac-modal-content {
    --  padding: 12px 35px;
    --}
    --
    --.dac-modal-action {
    --  margin: 0;
    --}
    --
    --.dac-modal-footer {
    --  padding: 24px 35px;
    --}
    --
    --@media (max-width: 1000px) {
    --  .dac-modal-window {
    --    margin: 20px;
    --    width: auto;
    --  }
    --
    --  .dac-modal-container {
    --    z-index: auto;
    --  }
    --}
    --
    --@media (max-width: 719px) {
    --  .dac-modal-window {
    --    margin: 10px;
    --  }
    --
    --  .dac-modal-header {
    --    padding: 35px 10px 10px;
    --  }
    --
    --  .dac-modal-header-title {
    --    font-size: 16px;
    --    line-height: 24px;
    --    padding: 0;
    --  }
    --
    --  .dac-modal-header-subtitle {
    --    display: block;
    --    margin: 0;
    --    position: static;
    --    text-align: right;
    --  }
    --
    --  .dac-modal-header-actions {
    --    top: 1px;
    --  }
    --
    --  .dac-modal-content {
    --    padding: 10px;
    --  }
    --
    --  .dac-modal-footer {
    --    border-top: 1px solid #e3e3e3;
    --    padding: 35px 10px;
    --  }
    --}
    --
    --.newsletter .dac-modal-footer {
    --  padding-top: 0;
    --  text-align: right;
    --}
    --
    --.newsletter-checkboxes {
    --  padding-top: 20px;
    --}
    --
    --.newsletter-success-message {
    --  font-size: 32px;
    --  line-height: 1.4;
    --  padding: 40px 30px;
    --  text-align: center;
    --}
    --
    --@media (max-width: 719px) {
    --  .newsletter-success-message {
    --    font-size: 16px;
    --    padding: 12px 0 0;
    --  }
    --}
    --
    --@media (min-width: 720px) {
    --  .newsletter-checkboxes {
    --    padding-top: 46px;
    --  }
    --
    --  .newsletter-leftCol {
    --    padding-right: 40px;
    --  }
    --
    --  .newsletter-rightCol {
    --    padding-left: 40px;
    --  }
    --}
    --
    --@media (max-width: 719px) {
    --  .newsletter .dac-modal-footer {
    --    margin-top: 30px;
    --    padding: 30px 10px;
    --    text-align: center;
    --  }
    --}
    --
    --.dac-blog-reader {
    --  padding: 50px 90px;
    --}
    --
    --.dac-blog-reader-title {
    --  color: #333;
    --  font-size: 45px;
    --  font-weight: 300;
    --  line-height: 1.2;
    --  padding: 10px 0;
    --}
    --
    --.dac-blog-reader-date {
    --  color: #b8b8b8;
    --  font-size: 12px;
    --  font-weight: 600;
    --  line-height: 1;
    --  text-transform: uppercase;
    --}
    --
    --.dac-blog-reader-text > p:first-child i {
    --  display: inline-block;
    --  margin-bottom: 40px;
    --}
    --
    --.dac-blog-reader-text li {
    --  margin-bottom: 0;
    --}
    --
    --.dac-blog-reader-text iframe {
    --  margin-left: auto !important;
    --  margin-right: auto !important;
    --  max-width: 100%;
    --}
    --
    --@media (max-width: 719px) {
    --  .dac-blog-reader {
    --    padding: 30px 20px;
    --  }
    --}
    --
    --.dac-custom-search {
    --  background: #fff;
    --  margin: 0 -10px;
    --  padding: 20px 10px;
    --  z-index: 1;
    --}
    --
    --.dac-custom-search .dac-fab, .dac-custom-search .dac-button-social {
    --  top: -48px;
    --}
    --
    --.dac-custom-search-section-title {
    --  color: #505050;
    --}
    --
    --.dac-custom-search-entry {
    --  margin-bottom: 36px;
    --  margin-top: 24px;
    --  margin-left:10px;
    --}
    --
    --.dac-custom-search-entry.cols:after {
    --    clear: none; }
    --
    --.dac-custom-search-image-wrapper {
    --  float: left;
    --  position: relative;
    --}
    --
    --.dac-custom-search-image {
    --  background-size: cover;
    --  height: 112px;
    --  width:150px;
    --  margin-right:15px;
    --}
    --
    --.dac-custom-search-text-wrapper {
    --  position: relative;
    --}
    --
    --.dac-custom-search-title {
    --  color: #333;
    --  font-size: 14px;
    --  font-weight: 700;
    --  line-height: 24px;
    --  padding: 0;
    --  clear:none;
    --}
    --
    --.dac-custom-search-title a {
    --  color: inherit;
    --}
    --
    --.dac-custom-search-section {
    --  color: #999;
    --  font-size: 16px;
    --  font-variant: small-caps;
    --  font-weight: 700;
    --  margin: -5px 0 0 0;
    --}
    --
    --.dac-custom-search-snippet {
    --  color: #666;
    --  margin: 0;
    --}
    --
    --.dac-custom-search-link {
    --  font-weight: 500;
    --  word-wrap: break-word;
    --  width: 100%;
    --}
    --
    --.dac-custom-search-load-more {
    --  background: none;
    --  border: none;
    --  color: #333;
    --  cursor: pointer;
    --  display: block;
    --  font-size: 14px;
    --  font-weight: 700;
    --  margin: 75px auto;
    --  outline: none;
    --  padding: 10px;
    --}
    --
    --.dac-custom-search-load-more:hover {
    --  opacity: 0.7;
    --}
    --
    --.dac-custom-search-no-results {
    --  color: #999;
    --}
    --
    --.dac-search-hero {
    --  font-size: 16px;
    --  padding: 50px 0 14px 0;
    --}
    --
    --.dac-search-results {
    --  opacity: 0;
    --  visibility: hidden;
    --  -webkit-transition: visibility 0s linear 300ms, opacity 300ms linear;
    --  transition: visibility 0s linear 300ms, opacity 300ms linear;
    --  background-color: #fff;
    --  bottom: 0;
    --  left: 0;
    --  overflow-y: auto;
    --  padding: 0 10px;
    --  position: fixed;
    --  right: 0;
    --  -webkit-transition: opacity 100ms;
    --  transition: opacity 100ms;
    --  top: 64px;
    --  z-index: 50;
    --}
    --
    --.dac-nav-animating .dac-search-results {
    --  -webkit-transition: opacity 100ms, padding .3s;
    --  transition: opacity 100ms, padding .3s;
    --}
    --
    --.dac-search-results * {
    --  box-sizing: border-box;
    --}
    --
    --.dac-search-open .dac-search-results {
    --  opacity: 1;
    --  visibility: visible;
    --}
    --
    --.dac-search-results-content {
    --  background: #eceff1;
    --  margin: 0 -10px;
    --  padding: 0 10px;
    --}
    --
    --.dac-search-results-for {
    --  margin-bottom: -5px;
    --  overflow: hidden;
    --  padding-top: 5px;
    --}
    --
    --.dac-search-results-for span {
    --  color: #039bef;
    --}
    --
    --.dac-search-mode .dac-search-results-for {
    --  display: none;
    --}
    --
    --.dac-search-results-history {
    --  background: #eceff1;
    --  min-height: 100%;
    --  margin: 0 -10px;
    --  padding: 0 10px;
    --}
    --
    --.dac-search-results-hero {
    --  padding-top: 20px;
    --}
    --
    --.dac-search-results-metadata {
    --  padding-bottom: 40px;
    --}
    --
    --#dac-search-results-reference {
    --  float:right;
    --  z-index:999;
    --}
    --
    --@media (max-width: 719px) {
    --  #dac-search-results-reference {
    --    float:none;
    --  }
    --}
    --
    --.dac-search-results-reference {
    --  background: white;
    --  box-shadow: 0px 1px 3px 0px rgba(0, 0, 0, 0.21);
    --  margin: 0 0 20px 0;
    --  overflow: hidden;
    --  padding: 6px 0 4px;
    --}
    --
    --.dac-search-results-reference .namespace {
    --  color: #666;
    --}
    --
    --.dac-search-results-reference.is-expanded {
    --  height: auto;
    --}
    --
    --.dac-search-results-reference-header {
    --  color: #999;
    --  font-size: 16px;
    --  font-variant: small-caps;
    --  font-weight: 700;
    --  margin: 0;
    --  padding: 18px 12px 0;
    --  text-transform: lowercase;
    --}
    --
    --.dac-search-results-reference-header:first-child {
    --  padding-top: 0;
    --}
    --
    --.dac-search-results-reference-entry {
    --  margin: 0;
    --}
    --
    --.dac-search-results-reference-entry a {
    --  color: #333;
    --  display: block;
    --  font-size: 0.81em;
    --  line-height: 1.5em;
    --  padding: 0 12px 5px 12px;
    --  width: 100%;
    --  white-space: nowrap;
    --}
    --
    --ul.dac-search-results-reference {
    --list-style: none;
    --}
    --
    --ul.dac-search-results-reference li[data-toggle="show-more"] {
    --  cursor:pointer;
    --}
    --
    --ul.dac-search-results-reference.is-expanded li[data-toggle="show-more"] {
    --  display:none;
    --}
    --
    --.dac-search-results-reference-entry a:hover {
    --  background-color: #eceff1;
    --}
    --
    --.dac-search-results-reference-entry em {
    --  font-style: normal;
    --  font-weight: 700;
    --}
    --
    --.dac-search-results-reference-entry-empty {
    --  color: #999;
    --  font-size: 0.81em;
    --  margin: 0;
    --  padding: 2px 12px 14px;
    --}
    --
    --.dac-search-results-resources {
    --  margin: 0;
    --}
    --
    --.dac-search-results-resources .resource-card {
    --  border-right: 2px solid #999;
    --}
    --
    --.dac-search-results-resources .resource-card-about {
    --  border-right: 2px solid #6ab344;
    --}
    --
    --.dac-search-results-resources .resource-card-about .section {
    --  color: #6ab344;
    --}
    --
    --.dac-search-results-resources .resource-card-develop {
    --  border-right: 2px solid #ff7043;
    --}
    --
    --.dac-search-results-resources .resource-card-develop .section {
    --  color: #ff7043;
    --}
    --
    --.dac-search-results-resources .resource-card-design {
    --  border-right: 2px solid #00bcd4;
    --}
    --
    --.dac-search-results-resources .resource-card-design .section {
    --  color: #00bcd4;
    --}
    --
    --.dac-search-results-resources .resource-card-distribute {
    --  border-right: 2px solid #afb42b;
    --}
    --
    --.dac-search-results-resources .resource-card-distribute .section {
    --  color: #afb42b;
    --}
    --
    --@media (max-width: 719px) {
    --  .dac-search-results-reference.no-results {
    --    display: none;
    --  }
    --}
    --
    --@media (min-width: 980px) {
    --  .dac-nav-open.dac-search-open .dac-search-results {
    --    padding-left: 260px;
    --  }
    --
    --  .dac-search-mode.dac-search-open .dac-search-results {
    --    padding-left: 10px;
    --  }
    --}
    --
    --.dac-selected {
    --  color: #039bef !important;
    --}
    --
    --.dac-selected em {
    --  color: #039bef;
    --}
    --
    --.resource-card.dac-selected {
    --  box-shadow: 0px 1px 10px 0px rgba(3, 155, 239, 0.7);
    --}
    --
    --.resource-card.dac-selected em {
    --  color: #333;
    --}
    --
    --.dac-expand, .dac-section {
    --  margin-left: -20px;
    --  margin-right: -20px;
    --  padding-left: 20px;
    --  padding-right: 20px;
    --}
    --
    --@media (max-width: 719px) {
    --  .dac-expand, .dac-section {
    --    margin-left: -10px;
    --    margin-right: -10px;
    --    padding-left: 10px;
    --    padding-right: 10px;
    --  }
    --}
    --
    --.dac-invert {
    --  color: #b3b3b3;
    --  color: rgba(255, 255, 255, 0.7);
    --}
    --
    --.dac-invert h1, .dac-invert h2, .dac-invert h3 {
    --  color: #fff;
    --}
    --
    --.dac-light.dac-hero, .dac-light.dac-section {
    --  background-color: #eceff1;
    --}
    --
    --.dac-gray.dac-hero, .dac-gray.dac-section {
    --  background-color: #d8dfe2;
    --}
    --
    --.dac-gray-dark.dac-hero, .dac-gray-dark.dac-section {
    --   background-color: #b0bec5;
    --}
    --
    --.dac-dark.dac-hero, .dac-dark.dac-section {
    --  background-color: #37474f;
    --}
    --
    --.dac-red.dac-hero, .dac-red.dac-section {
    --  background-color: #dc4d38;
    --}
    --
    --.dac-blue.dac-hero,
    --.dac-blue.dac-section {
    --  background-color: #0277bd;
    --}
    --
    --.dac-blue.dac-invert .dac-hero-description,
    --.dac-blue.dac-invert .dac-section-subtitle {
    --  color: #fff;
    --}
    --
    --.dac-dark-gray.dac-hero,
    --.dac-dark-gray.dac-section {
    --  background-color: #455a64;
    --}
    --
    --.dac-bg-opacity::after {
    --  background-color: rgba(0, 0, 0, .3);
    --  content : "";
    --  display: block;
    --  position: absolute;
    --  top: 0;
    --  left: 0;
    --  width: 100%;
    --  height: 100%;
    --  z-index: 1;
    --}
    --
    --.dac-hero-cta, .dac-section-title, .dac-section-links {
    --  color: #212121;
    --  color: rgba(0, 0, 0, 0.87);
    --}
    --
    --.dac-invert .dac-hero-cta, .dac-invert .dac-section-title, .dac-invert .dac-section-links {
    --  color: white;
    --}
    --
    --.dac-hero-cta .dac-sprite, .dac-section-title .dac-sprite, .dac-section-links .dac-sprite, .dac-hero-cta .dac-modal-header-close:before, .dac-section-title .dac-modal-header-close:before, .dac-section-links .dac-modal-header-close:before, .dac-hero-cta .paging-links .prev-page-link:before, .paging-links .dac-hero-cta .prev-page-link:before, .dac-section-title .paging-links .prev-page-link:before, .paging-links .dac-section-title .prev-page-link:before, .dac-section-links .paging-links .prev-page-link:before, .paging-links .dac-section-links .prev-page-link:before, .dac-hero-cta .paging-links .next-page-link:before, .paging-links .dac-hero-cta .next-page-link:before, .dac-section-title .paging-links .next-page-link:before, .paging-links .dac-section-title .next-page-link:before, .dac-section-links .paging-links .next-page-link:before, .paging-links .dac-section-links .next-page-link:before, .dac-hero-cta .paging-links .next-class-link:before, .paging-links .dac-hero-cta .next-class-link:before, .dac-section-title .paging-links .next-class-link:before, .paging-links .dac-section-title .next-class-link:before, .dac-section-links .paging-links .next-class-link:before, .paging-links .dac-section-links .next-class-link:before, .dac-hero-cta .paging-links .start-class-link:after, .paging-links .dac-hero-cta .start-class-link:after, .dac-section-title .paging-links .start-class-link:after, .paging-links .dac-section-title .start-class-link:after, .dac-section-links .paging-links .start-class-link:after, .paging-links .dac-section-links .start-class-link:after {
    --  opacity: .87;
    --}
    --
    --.dac-invert .dac-hero-cta .dac-sprite, .dac-invert .dac-section-title .dac-sprite, .dac-invert .dac-section-links .dac-sprite, .dac-invert .dac-hero-cta .dac-modal-header-close:before, .dac-invert .dac-section-title .dac-modal-header-close:before, .dac-invert .dac-section-links .dac-modal-header-close:before, .dac-invert .dac-hero-cta .paging-links .prev-page-link:before, .paging-links .dac-invert .dac-hero-cta .prev-page-link:before, .dac-invert .dac-section-title .paging-links .prev-page-link:before, .paging-links .dac-invert .dac-section-title .prev-page-link:before, .dac-invert .dac-section-links .paging-links .prev-page-link:before, .paging-links .dac-invert .dac-section-links .prev-page-link:before, .dac-invert .dac-hero-cta .paging-links .next-page-link:before, .paging-links .dac-invert .dac-hero-cta .next-page-link:before, .dac-invert .dac-section-title .paging-links .next-page-link:before, .paging-links .dac-invert .dac-section-title .next-page-link:before, .dac-invert .dac-section-links .paging-links .next-page-link:before, .paging-links .dac-invert .dac-section-links .next-page-link:before, .dac-invert .dac-hero-cta .paging-links .next-class-link:before, .paging-links .dac-invert .dac-hero-cta .next-class-link:before, .dac-invert .dac-section-title .paging-links .next-class-link:before, .paging-links .dac-invert .dac-section-title .next-class-link:before, .dac-invert .dac-section-links .paging-links .next-class-link:before, .paging-links .dac-invert .dac-section-links .next-class-link:before, .dac-invert .dac-hero-cta .paging-links .start-class-link:after, .paging-links .dac-invert .dac-hero-cta .start-class-link:after, .dac-invert .dac-section-title .paging-links .start-class-link:after, .paging-links .dac-invert .dac-section-title .start-class-link:after, .dac-invert .dac-section-links .paging-links .start-class-link:after, .paging-links .dac-invert .dac-section-links .start-class-link:after {
    --  opacity: 1;
    --}
    --
    --.dac-hero-tag, .dac-hero-description, .dac-section-subtitle {
    --  color: #757575;
    --  color: rgba(0, 0, 0, 0.54);
    --}
    --
    --.dac-invert .dac-hero-tag, .dac-invert .dac-hero-description, .dac-invert .dac-section-subtitle {
    --  color: #b3b3b3;
    --  color: rgba(255, 255, 255, 0.7);
    --}
    --
    --.dac-hero.dac-no-min-height {
    --  min-height: 0;
    --}
    --
    --.dac-hero-half-bg {
    --  background-size: cover;
    --  background-repeat: no-repeat;
    --  float: right;
    --  height: 440px;
    --}
    --
    --.dac-hero-half-bg-centered {
    --  background-position: center;
    --  background-repeat: no-repeat;
    --  background-size: cover;
    --  float: right;
    --  height: 440px;
    --}
    --
    --@media only screen and (-webkit-min-device-pixel-ratio: 2),
    --only screen and (-moz-min-device-pixel-ratio: 2),
    --only screen and (min-device-pixel-ratio: 2),
    --only screen and (min-resolution: 192dpi),
    --only screen and (min-resolution: 2dppx) {
    --  .dac-hero-half-bg,
    --  .dac-hero-half-bg-centered {
    --    background-size: "" "";
    --  }
    --}
    --
    --@media (max-width: 719px) {
    --  .dac-hero-half-bg,
    --  .dac-hero-half-bg-centered {
    --    background-position: center;
    --    background-size: auto 100%;
    --    float: none;
    --    height: 200px;
    --    margin-top: 32px;
    --  }
    --}
    --
    --.dac-section {
    --  background-position: 50% 50%;
    --  background-size: cover;
    --  padding-bottom: 84px;
    --  padding-top: 84px;
    --  position: relative;
    --}
    --
    --@media (max-width: 719px) {
    --  .dac-section {
    --    padding-bottom: 52px;
    --    padding-top: 52px;
    --  }
    --}
    --
    --.dac-section.dac-small,
    --.dac-hero.dac-small {
    --  padding-bottom: 32px;
    --  padding-top: 32px;
    --}
    --
    --.dac-section.dac-slim {
    --  padding-bottom: 0;
    --  padding-top: 0;
    --}
    --
    --.dac-section-title {
    --  text-align: center;
    --  padding-bottom: 40px;
    --  padding-top: 0;
    --}
    --
    --.dac-section-subtitle {
    --  font-size: 16px;
    --  padding-bottom: 40px;
    --  margin-top: -24px;
    --  text-align: center;
    --}
    --
    --.dac-section-links {
    --  font-size: 16px;
    --  list-style: none;
    --  line-height: 40px;
    --  margin: 16px 0 0;
    --  text-align: center;
    --}
    --
    --@media (max-width: 719px) {
    --  .dac-section-links {
    --    margin-left: -8px;
    --    text-align: left;
    --  }
    --}
    --
    --.dac-section-link {
    --  cursor: pointer;
    --  display: inline-block;
    --  margin: 0 32px;
    --  -webkit-transition: opacity .3s;
    --  transition: opacity .3s;
    --}
    --
    --.dac-section-link:hover {
    --  opacity: .54;
    --}
    --
    --@media (max-width: 719px) {
    --  .dac-section-link {
    --    display: block;
    --    margin: 0;
    --  }
    --}
    --
    --.dac-section-link a {
    --  color: inherit;
    --}
    --
    --/*
    --SCSS variables are information about icon's compiled state, stored under its original file name
    --
    --.icon-home {
    --  width: $icon-home-width;
    --}
    --
    --The large array-like variables contain all information about a single icon
    --$icon-home: x y offset_x offset_y width height total_width total_height image_path;
    --
    --At the bottom of this section, we provide information about the spritesheet itself
    --$spritesheet: width height image $spritesheet-sprites;
    --*/
    --.dac-sprite, .dac-modal-header-close:before, .paging-links .prev-page-link:before, .paging-links .next-page-link:before, .paging-links .next-class-link:before, .paging-links .start-class-link:after, .Video-button--picture-in-picture, .Video-button--close, a.video-shadowbox-button.white::after, #tb li:before,
    --#qv li:before {
    --  background-image: url(../images/sprite.png);
    --  display: inline-block;
    --  vertical-align: middle;
    --}
    --
    --@media (-webkit-min-device-pixel-ratio: 1.5), (min-resolution: 1.5dppx), (min-resolution: 144px) {
    --
    --  .dac-sprite,
    --  .dac-modal-header-close:before,
    --  .paging-links .prev-page-link:before,
    --  .paging-links .next-page-link:before,
    --  .paging-links .next-class-link:before,
    --  .paging-links .start-class-link:after,
    --  .Video-button--picture-in-picture,
    --  .Video-button--close,
    --  a.video-shadowbox-button.white::after,
    --  #tb li:before,
    --  #qv li:before {
    --    background-image: url(../images/sprite_2x.png);
    --    background-size: 36px 900px;
    --  }
    --}
    --
    --.dac-chevron {
    --  background-size: 9px 39px;
    --  display: inline-block;
    --  height: 13px;
    --  text-indent: -9999px;
    --  width: 9px;
    --}
    --
    --.dac-sprite.dac-auto-chevron,
    --.dac-auto-chevron.dac-modal-header-close:before,
    --.paging-links .dac-auto-chevron.prev-page-link:before,
    --.paging-links .dac-auto-chevron.next-page-link:before,
    --.paging-links .dac-auto-chevron.next-class-link:before,
    --.paging-links .dac-auto-chevron.start-class-link:after {
    --  background-position: 0px -669px;
    --  height: 24px;
    --  width: 24px;
    --  vertical-align: -6px;
    --}
    --
    --.dac-invert .dac-sprite.dac-auto-chevron, .dac-invert .dac-auto-chevron.dac-modal-header-close:before, .dac-invert .paging-links .dac-auto-chevron.prev-page-link:before, .paging-links .dac-invert .dac-auto-chevron.prev-page-link:before, .dac-invert .paging-links .dac-auto-chevron.next-page-link:before, .paging-links .dac-invert .dac-auto-chevron.next-page-link:before, .dac-invert .paging-links .dac-auto-chevron.next-class-link:before, .paging-links .dac-invert .dac-auto-chevron.next-class-link:before, .dac-invert .paging-links .dac-auto-chevron.start-class-link:after, .paging-links .dac-invert .dac-auto-chevron.start-class-link:after {
    --  background-position: 0px -513px;
    --  height: 24px;
    --  width: 24px;
    --}
    --
    --.dac-sprite.dac-auto-chevron-large, .dac-auto-chevron-large.dac-modal-header-close:before, .paging-links .dac-auto-chevron-large.prev-page-link:before, .paging-links .dac-auto-chevron-large.next-page-link:before, .paging-links .dac-auto-chevron-large.next-class-link:before, .paging-links .dac-auto-chevron-large.start-class-link:after {
    --  background-position: 0px -695px;
    --  height: 36px;
    --  width: 36px;
    --  vertical-align: -10px;
    --}
    --
    --.dac-invert .dac-sprite.dac-auto-chevron-large,
    --.dac-invert .dac-auto-chevron-large.dac-modal-header-close:before,
    --.dac-invert .paging-links .dac-auto-chevron-large.prev-page-link:before,
    --.paging-links .dac-invert .dac-auto-chevron-large.prev-page-link:before,
    --.dac-invert .paging-links .dac-auto-chevron-large.next-page-link:before,
    --.paging-links .dac-invert .dac-auto-chevron-large.next-page-link:before,
    --.dac-invert .paging-links .dac-auto-chevron-large.next-class-link:before,
    --.paging-links .dac-invert .dac-auto-chevron-large.next-class-link:before,
    --.dac-invert .paging-links .dac-auto-chevron-large.start-class-link:after,
    --.paging-links .dac-invert .dac-auto-chevron-large.start-class-link:after {
    --  background-position: 0px -771px;
    --  height: 36px;
    --  width: 36px;
    --}
    --
    --.dac-sprite.dac-auto-unfold-less, .dac-auto-unfold-less.dac-modal-header-close:before, .paging-links .dac-auto-unfold-less.prev-page-link:before, .paging-links .dac-auto-unfold-less.next-page-link:before, .paging-links .dac-auto-unfold-less.next-class-link:before, .paging-links .dac-auto-unfold-less.start-class-link:after {
    --  background-position: 0px -487px;
    --  height: 24px;
    --  width: 24px;
    --  vertical-align: -6px; }
    --  .dac-invert .dac-sprite.dac-auto-unfold-less, .dac-invert .dac-auto-unfold-less.dac-modal-header-close:before, .dac-invert .paging-links .dac-auto-unfold-less.prev-page-link:before, .paging-links .dac-invert .dac-auto-unfold-less.prev-page-link:before, .dac-invert .paging-links .dac-auto-unfold-less.next-page-link:before, .paging-links .dac-invert .dac-auto-unfold-less.next-page-link:before, .dac-invert .paging-links .dac-auto-unfold-less.next-class-link:before, .paging-links .dac-invert .dac-auto-unfold-less.next-class-link:before, .dac-invert .paging-links .dac-auto-unfold-less.start-class-link:after, .paging-links .dac-invert .dac-auto-unfold-less.start-class-link:after {
    --    background-position: 0px -565px;
    --    height: 24px;
    --    width: 24px; }
    --
    --.dac-sprite.dac-auto-unfold-more, .dac-auto-unfold-more.dac-modal-header-close:before, .paging-links .dac-auto-unfold-more.prev-page-link:before, .paging-links .dac-auto-unfold-more.next-page-link:before, .paging-links .dac-auto-unfold-more.next-class-link:before, .paging-links .dac-auto-unfold-more.start-class-link:after {
    --  background-position: 0px -539px;
    --  height: 24px;
    --  width: 24px;
    --  vertical-align: -6px; }
    --  .dac-invert .dac-sprite.dac-auto-unfold-more, .dac-invert .dac-auto-unfold-more.dac-modal-header-close:before, .dac-invert .paging-links .dac-auto-unfold-more.prev-page-link:before, .paging-links .dac-invert .dac-auto-unfold-more.prev-page-link:before, .dac-invert .paging-links .dac-auto-unfold-more.next-page-link:before, .paging-links .dac-invert .dac-auto-unfold-more.next-page-link:before, .dac-invert .paging-links .dac-auto-unfold-more.next-class-link:before, .paging-links .dac-invert .dac-auto-unfold-more.next-class-link:before, .dac-invert .paging-links .dac-auto-unfold-more.start-class-link:after, .paging-links .dac-invert .dac-auto-unfold-more.start-class-link:after {
    --    background-position: 0px -305px;
    --    height: 24px;
    --    width: 24px; }
    --
    --.dac-sprite.dac-arrow-down-gray, .dac-arrow-down-gray.dac-modal-header-close:before, .paging-links .dac-arrow-down-gray.prev-page-link:before, .paging-links .dac-arrow-down-gray.next-page-link:before, .paging-links .dac-arrow-down-gray.next-class-link:before, .paging-links .dac-arrow-down-gray.start-class-link:after {
    --  background-position: 0px 0px;
    --  height: 11px;
    --  width: 19px; }
    --
    --.dac-sprite.dac-arrow-right, .dac-arrow-right.dac-modal-header-close:before, .paging-links .dac-arrow-right.prev-page-link:before, .paging-links .dac-arrow-right.next-page-link:before, .paging-links .dac-arrow-right.next-class-link:before, .paging-links .dac-arrow-right.start-class-link:after {
    --  background-position: 0px -215px;
    --  height: 18px;
    --  width: 11px; }
    --
    --.dac-sprite.dac-back-arrow, .dac-back-arrow.dac-modal-header-close:before, .paging-links .dac-back-arrow.prev-page-link:before, .paging-links .dac-back-arrow.next-page-link:before, .paging-links .dac-back-arrow.next-class-link:before, .paging-links .dac-back-arrow.start-class-link:after {
    --  background-position: 0px -123px;
    --  height: 16px;
    --  width: 16px; }
    --
    --.dac-sprite.dac-chevron-large-right-black, .dac-chevron-large-right-black.dac-modal-header-close:before, .paging-links .dac-chevron-large-right-black.prev-page-link:before, .paging-links .dac-chevron-large-right-black.next-page-link:before, .paging-links .dac-chevron-large-right-black.next-class-link:before, .paging-links .dac-chevron-large-right-black.start-class-link:after {
    --  background-position: 0px -695px;
    --  height: 36px;
    --  width: 36px; }
    --
    --.dac-sprite.dac-chevron-large-right-white, .dac-chevron-large-right-white.dac-modal-header-close:before, .paging-links .dac-chevron-large-right-white.prev-page-link:before, .paging-links .dac-chevron-large-right-white.next-page-link:before, .paging-links .dac-chevron-large-right-white.next-class-link:before, .paging-links .dac-chevron-large-right-white.start-class-link:after {
    --  background-position: 0px -771px;
    --  height: 36px;
    --  width: 36px; }
    --
    --.dac-sprite.dac-chevron-right-black, .dac-chevron-right-black.dac-modal-header-close:before, .paging-links .dac-chevron-right-black.prev-page-link:before, .paging-links .dac-chevron-right-black.next-page-link:before, .paging-links .dac-chevron-right-black.next-class-link:before, .paging-links .dac-chevron-right-black.start-class-link:after {
    --  background-position: 0px -669px;
    --  height: 24px;
    --  width: 24px; }
    --
    --.dac-sprite.dac-chevron-right-white, .dac-chevron-right-white.dac-modal-header-close:before, .paging-links .dac-chevron-right-white.prev-page-link:before, .paging-links .dac-chevron-right-white.next-page-link:before, .paging-links .dac-chevron-right-white.next-class-link:before, .paging-links .dac-chevron-right-white.start-class-link:after {
    --  background-position: 0px -513px;
    --  height: 24px;
    --  width: 24px; }
    --
    --.dac-sprite.dac-close-black, .dac-close-black.dac-modal-header-close:before, .paging-links .dac-close-black.prev-page-link:before, .paging-links .dac-close-black.next-page-link:before, .paging-links .dac-close-black.next-class-link:before, .paging-links .dac-close-black.start-class-link:after {
    --  background-position: 0px -89px;
    --  height: 14px;
    --  width: 14px; }
    --
    --.dac-sprite.dac-close-video-white, .dac-modal-header-close:before, .paging-links .dac-close-video-white.prev-page-link:before, .paging-links .prev-page-link.dac-modal-header-close:before, .paging-links .dac-close-video-white.next-page-link:before, .paging-links .next-page-link.dac-modal-header-close:before, .paging-links .dac-close-video-white.next-class-link:before, .paging-links .next-class-link.dac-modal-header-close:before, .paging-links .dac-close-video-white.start-class-link:after {
    --  background-position: 0px -435px;
    --  height: 24px;
    --  width: 24px; }
    --
    --.dac-sprite.dac-close, .dac-close.dac-modal-header-close:before, .paging-links .dac-close.prev-page-link:before, .paging-links .dac-close.next-page-link:before, .paging-links .dac-close.next-class-link:before, .paging-links .dac-close.start-class-link:after {
    --  background-position: 0px -27px;
    --  height: 12px;
    --  width: 12px; }
    --
    --.dac-sprite.dac-enlarge-video-white, .dac-enlarge-video-white.dac-modal-header-close:before, .paging-links .dac-enlarge-video-white.prev-page-link:before, .paging-links .dac-enlarge-video-white.next-page-link:before, .paging-links .dac-enlarge-video-white.next-class-link:before, .paging-links .dac-enlarge-video-white.start-class-link:after {
    --  background-position: 0px -409px;
    --  height: 24px;
    --  width: 24px; }
    --
    --.dac-sprite.dac-expand-less-black, .dac-expand-less-black.dac-modal-header-close:before, .paging-links .dac-expand-less-black.prev-page-link:before, .paging-links .dac-expand-less-black.next-page-link:before, .paging-links .dac-expand-less-black.next-class-link:before, .paging-links .dac-expand-less-black.start-class-link:after {
    --  background-position: 0px -383px;
    --  height: 24px;
    --  width: 24px; }
    --
    --.dac-sprite.dac-expand-more-black, .dac-expand-more-black.dac-modal-header-close:before, .paging-links .dac-expand-more-black.prev-page-link:before, .paging-links .dac-expand-more-black.next-page-link:before, .paging-links .dac-expand-more-black.next-class-link:before, .paging-links .dac-expand-more-black.start-class-link:after {
    --  background-position: 0px -357px;
    --  height: 24px;
    --  width: 24px; }
    --
    --.dac-sprite.dac-fullscreen-exit, .dac-fullscreen-exit.dac-modal-header-close:before, .paging-links .dac-fullscreen-exit.prev-page-link:before, .paging-links .dac-fullscreen-exit.next-page-link:before, .paging-links .dac-fullscreen-exit.next-class-link:before, .paging-links .dac-fullscreen-exit.start-class-link:after {
    --  background-position: 0px -331px;
    --  height: 24px;
    --  width: 24px; }
    --
    --.dac-sprite.dac-fullscreen, .dac-fullscreen.dac-modal-header-close:before, .paging-links .dac-fullscreen.prev-page-link:before, .paging-links .dac-fullscreen.next-page-link:before, .paging-links .dac-fullscreen.next-class-link:before, .paging-links .dac-fullscreen.start-class-link:after {
    --  background-position: 0px -279px;
    --  height: 24px;
    --  width: 24px; }
    --
    --.dac-sprite.dac-google-play, .dac-google-play.dac-modal-header-close:before, .paging-links .dac-google-play.prev-page-link:before, .paging-links .dac-google-play.next-page-link:before, .paging-links .dac-google-play.next-class-link:before, .paging-links .dac-google-play.start-class-link:after {
    --  background-position: 0px -235px;
    --  height: 20px;
    --  width: 17px; }
    --
    --.dac-sprite.dac-gplus, .dac-gplus.dac-modal-header-close:before, .paging-links .dac-gplus.prev-page-link:before, .paging-links .dac-gplus.next-page-link:before, .paging-links .dac-gplus.next-class-link:before, .paging-links .dac-gplus.start-class-link:after {
    --  background-position: 0px -809px;
    --  height: 36px;
    --  width: 36px; }
    --
    --.dac-sprite.dac-mail, .dac-mail.dac-modal-header-close:before, .paging-links .dac-mail.prev-page-link:before, .paging-links .dac-mail.next-page-link:before, .paging-links .dac-mail.next-class-link:before, .paging-links .dac-mail.start-class-link:after {
    --  background-position: 0px -13px;
    --  height: 12px;
    --  width: 16px; }
    --
    --.dac-sprite.dac-nav-back-blue, .dac-nav-back-blue.dac-modal-header-close:before, .paging-links .prev-page-link:before, .paging-links .dac-nav-back-blue.next-page-link:before, .paging-links .dac-nav-back-blue.next-class-link:before, .paging-links .dac-nav-back-blue.start-class-link:after {
    --  background-position: 0px -105px;
    --  height: 16px;
    --  width: 16px; }
    --
    --.dac-sprite.dac-nav-back, .dac-nav-back.dac-modal-header-close:before, .paging-links .dac-nav-back.prev-page-link:before, .paging-links .dac-nav-back.next-page-link:before, .paging-links .dac-nav-back.next-class-link:before, .paging-links .dac-nav-back.start-class-link:after {
    --  background-position: 0px -177px;
    --  height: 16px;
    --  width: 16px; }
    --
    --/* The back button in Studio and NDK left nav */
    --.dac-nav-back-button.back-to-dev .dac-sprite.dac-nav-back {
    --  background-position: 0px -884px;
    --  height: 16px;
    --  width: 16px;
    --}
    --
    --.dac-sprite.dac-nav-forward-blue, .dac-nav-forward-blue.dac-modal-header-close:before, .paging-links .dac-nav-forward-blue.prev-page-link:before, .paging-links .next-page-link:before, .paging-links .next-class-link:before, .paging-links .start-class-link:after {
    --  background-position: 0px -159px;
    --  height: 16px;
    --  width: 16px; }
    --
    --.dac-sprite.dac-nav-forward, .dac-nav-forward.dac-modal-header-close:before, .paging-links .dac-nav-forward.prev-page-link:before, .paging-links .dac-nav-forward.next-page-link:before, .paging-links .dac-nav-forward.next-class-link:before, .paging-links .dac-nav-forward.start-class-link:after {
    --  background-position: 0px -141px;
    --  height: 16px;
    --  width: 16px; }
    --
    --.dac-sprite.dac-open-in-new, .dac-open-in-new.dac-modal-header-close:before, .paging-links .dac-open-in-new.prev-page-link:before, .paging-links .dac-open-in-new.next-page-link:before, .paging-links .dac-open-in-new.next-class-link:before, .paging-links .dac-open-in-new.start-class-link:after {
    --  background-position: 0px -195px;
    --  height: 18px;
    --  width: 18px; }
    --
    --.dac-sprite.dac-picture-in-picture-white, .dac-picture-in-picture-white.dac-modal-header-close:before, .paging-links .dac-picture-in-picture-white.prev-page-link:before, .paging-links .dac-picture-in-picture-white.next-page-link:before, .paging-links .dac-picture-in-picture-white.next-class-link:before, .paging-links .dac-picture-in-picture-white.start-class-link:after {
    --  background-position: 0px -461px;
    --  height: 24px;
    --  width: 24px; }
    --
    --.dac-sprite.dac-play-circle-grey, .dac-play-circle-grey.dac-modal-header-close:before, .paging-links .dac-play-circle-grey.prev-page-link:before, .paging-links .dac-play-circle-grey.next-page-link:before, .paging-links .dac-play-circle-grey.next-class-link:before, .paging-links .dac-play-circle-grey.start-class-link:after {
    --  background-position: 0px -733px;
    --  height: 36px;
    --  width: 36px; }
    --
    --.dac-sprite.dac-play-circle-white, .dac-play-circle-white.dac-modal-header-close:before, .paging-links .dac-play-circle-white.prev-page-link:before, .paging-links .dac-play-circle-white.next-page-link:before, .paging-links .dac-play-circle-white.next-class-link:before, .paging-links .dac-play-circle-white.start-class-link:after {
    --  background-position: 0px -847px;
    --  height: 36px;
    --  width: 36px; }
    --
    --.dac-sprite.dac-play-white, .dac-play-white.dac-modal-header-close:before, .paging-links .dac-play-white.prev-page-link:before, .paging-links .dac-play-white.next-page-link:before, .paging-links .dac-play-white.next-class-link:before, .paging-links .dac-play-white.start-class-link:after {
    --  background-position: 0px -257px;
    --  height: 20px;
    --  width: 16px; }
    --
    --.dac-sprite.dac-rss, .dac-rss.dac-modal-header-close:before, .paging-links .dac-rss.prev-page-link:before, .paging-links .dac-rss.next-page-link:before, .paging-links .dac-rss.next-class-link:before, .paging-links .dac-rss.start-class-link:after {
    --  background-position: 0px -41px;
    --  height: 14px;
    --  width: 14px; }
    --
    --.dac-sprite.dac-search-white, .dac-search-white.dac-modal-header-close:before, .paging-links .dac-search-white.prev-page-link:before, .paging-links .dac-search-white.next-page-link:before, .paging-links .dac-search-white.next-class-link:before, .paging-links .dac-search-white.start-class-link:after {
    --  background-position: 0px -591px;
    --  height: 24px;
    --  width: 24px; }
    --
    --.dac-sprite.dac-search, .dac-search.dac-modal-header-close:before, .paging-links .dac-search.prev-page-link:before, .paging-links .dac-search.next-page-link:before, .paging-links .dac-search.next-class-link:before, .paging-links .dac-search.start-class-link:after {
    --  background-position: 0px -617px;
    --  height: 24px;
    --  width: 24px; }
    --
    --.dac-sprite.dac-star-outline, .dac-star-outline.dac-modal-header-close:before, .paging-links .dac-star-outline.prev-page-link:before, .paging-links .dac-star-outline.next-page-link:before, .paging-links .dac-star-outline.next-class-link:before, .paging-links .dac-star-outline.start-class-link:after {
    --  background-position: 0px -643px;
    --  height: 24px;
    --  width: 24px; }
    --
    --.dac-sprite.dac-twitter, .dac-twitter.dac-modal-header-close:before, .paging-links .dac-twitter.prev-page-link:before, .paging-links .dac-twitter.next-page-link:before, .paging-links .dac-twitter.next-class-link:before, .paging-links .dac-twitter.start-class-link:after {
    --  background-position: 0px -73px;
    --  height: 14px;
    --  width: 16px; }
    --
    --.dac-sprite.dac-unfold-less-white, .dac-unfold-less-white.dac-modal-header-close:before, .paging-links .dac-unfold-less-white.prev-page-link:before, .paging-links .dac-unfold-less-white.next-page-link:before, .paging-links .dac-unfold-less-white.next-class-link:before, .paging-links .dac-unfold-less-white.start-class-link:after {
    --  background-position: 0px -565px;
    --  height: 24px;
    --  width: 24px; }
    --
    --.dac-sprite.dac-unfold-less, .dac-unfold-less.dac-modal-header-close:before, .paging-links .dac-unfold-less.prev-page-link:before, .paging-links .dac-unfold-less.next-page-link:before, .paging-links .dac-unfold-less.next-class-link:before, .paging-links .dac-unfold-less.start-class-link:after {
    --  background-position: 0px -487px;
    --  height: 24px;
    --  width: 24px; }
    --
    --.dac-sprite.dac-unfold-more-white, .dac-unfold-more-white.dac-modal-header-close:before, .paging-links .dac-unfold-more-white.prev-page-link:before, .paging-links .dac-unfold-more-white.next-page-link:before, .paging-links .dac-unfold-more-white.next-class-link:before, .paging-links .dac-unfold-more-white.start-class-link:after {
    --  background-position: 0px -305px;
    --  height: 24px;
    --  width: 24px; }
    --
    --.dac-sprite.dac-unfold-more, .dac-unfold-more.dac-modal-header-close:before, .paging-links .dac-unfold-more.prev-page-link:before, .paging-links .dac-unfold-more.next-page-link:before, .paging-links .dac-unfold-more.next-class-link:before, .paging-links .dac-unfold-more.start-class-link:after {
    --  background-position: 0px -539px;
    --  height: 24px;
    --  width: 24px; }
    --
    --.dac-sprite.dac-youtube, .dac-youtube.dac-modal-header-close:before, .paging-links .dac-youtube.prev-page-link:before, .paging-links .dac-youtube.next-page-link:before, .paging-links .dac-youtube.next-class-link:before, .paging-links .dac-youtube.start-class-link:after {
    --  background-position: 0px -57px;
    --  height: 14px;
    --  width: 18px; }
    --
    --/* Toast Component */
    --.dac-toast {
    --  background: #ffebc3;
    --  border-top: 1px solid #e5d4a1;
    --  display: none;
    --  color: rgba(0, 0, 0, .87);
    --  line-height: 1.4;
    --  padding: 10px;
    --}
    --
    --.dac-toast.dac-visible {
    --  display: block;
    --}
    --
    --.dac-toast-wrap {
    --  box-sizing: border-box;
    --  margin: 0 auto;
    --  max-width: 940px;
    --  padding-right: 20px;
    --  position: relative;
    --}
    --
    --.dac-toast-close-btn {
    --  background-color: transparent;
    --  border: none;
    --  border-radius: 0;
    --  cursor: pointer;
    --  opacity: .4;
    --  padding: 0;
    --  position: absolute;
    --  right: 0;
    --  top: -2px;
    --}
    --
    --.dac-toast-close-btn:hover,
    --.dac-toast-close-btn:focus,
    --.dac-toast-close-btn:active {
    --  opacity: 1;
    --  outline: none;
    --}
    --
    --.dac-toast-close-btn .dac-button.dac-raised.dac-primary{
    --  margin: 0;
    --  padding: 0;
    --}
    --
    --.dac-toast-group {
    --  bottom: 0;
    --  left: 0;
    --  position: fixed;
    --  right: 0;
    --  z-index: 60;
    --}
    --
    --.dac-toast.dac-danger {
    --  background-color: #ffccbc;
    --  border-top-color: #e5b7a9;
    --}
    --
    --.dac-toast.dac-success {
    --  background-color: #cdedc8;
    --  border-top-color: #c6d5b4;
    --}
    --
    --@media (max-width: 719px) {
    --  .dac-toast-close-btn {
    --    position: relative;
    --    top: 0;
    --    margin: 10px 0 0;
    --    display: block;
    --  }
    --}
    --
    --.dac-tab-item {
    --  box-sizing: border-box;
    --  cursor: pointer;
    --  display: table-cell;
    --  margin: 0;
    --  padding: 8px 12px;
    --  position: relative;
    --  text-align: left; }
    --  @media (max-width: 719px) {
    --    .dac-tab-item {
    --      padding-right: 12px;
    --      text-align: center;
    --      width: 33.33333333%; } }
    --
    --.dac-tab-title {
    --  color: #333;
    --  display: inline-block;
    --  font-size: 16px;
    --  font-weight: 500;
    --  margin: 0; }
    --
    --.dac-tab-arrow {
    --  margin-top: -2px; }
    --  @media (max-width: 719px) {
    --    .dac-tab-arrow {
    --      position: absolute;
    --      visibility: hidden; } }
    --
    --.dac-tab-bar {
    --  display: inline-block;
    --  list-style-type: none;
    --  margin: 0 0 0 12px;
    --  vertical-align: middle;
    --  overflow: hidden; }
    --  @media (max-width: 719px) {
    --    .dac-tab-bar {
    --      display: table;
    --      margin-left: 0;
    --      width: 100%; } }
    --
    --.dac-tab-views {
    --  list-style-type: none;
    --  margin: 0; }
    --
    --.dac-tab-view {
    --  background: #fff;
    --  display: none;
    --  overflow: hidden;
    --  margin: 0 0 10px;
    --  padding: 20px 10px 0;
    --  text-align: left; }
    --
    --.dac-tab-item.dac-active {
    --  background: #fff; }
    --
    --.dac-tab-item.dac-active .dac-tab-arrow {
    --  -webkit-transform: scaleY(-1);
    --      -ms-transform: scaleY(-1);
    --          transform: scaleY(-1); }
    --
    --.dac-tab-view.dac-active {
    --  display: block; }
    --
    --.dac-toggle-expand {
    --  cursor: pointer;
    --  display: inline-block; }
    --
    --.dac-toggle-collapse {
    --  cursor: pointer;
    --  display: none; }
    --
    --.dac-toggle.is-expanded .dac-toggle-expand {
    --  display: none; }
    --
    --.dac-toggle.is-expanded .dac-toggle-collapse {
    --  display: inline-block; }
    --
    --.dac-toggle-content {
    --  clear: left;
    --  overflow: hidden;
    --  max-height: 0;
    --  -webkit-transition: .3s max-height;
    --          transition: .3s max-height; }
    --
    --.dac-toggle.is-expanded .dac-toggle-content {
    --  max-height: none; }
    --
    --.dac-toggle.dac-mobile .dac-toggle-content {
    --  max-height: none; }
    --
    --@media (max-width: 719px) {
    --  .dac-toggle.dac-mobile .dac-toggle-content {
    --    max-height: 0; }
    --  .dac-toggle.is-expanded .dac-toggle-content {
    --    max-height: none; } }
    --
    --/**
    -- * Fades out an element.
    -- * Applies visibility hidden when the transition is finished.
    -- *
    -- * Use opacity: 1; to show the element.
    -- */
    --.dac-visible-mobile-block, .dac-mobile-only,
    --.dac-visible-mobile-inline,
    --.dac-visible-mobile-inline-block,
    --.dac-visible-tablet-block,
    --.dac-visible-tablet-inline,
    --.dac-visible-tablet-inline-block,
    --.dac-visible-desktop-block,
    --.dac-visible-desktop-inline,
    --.dac-visible-desktop-inline-block {
    --  display: none !important; }
    --
    --@media (max-width: 719px) {
    --  .dac-hidden-mobile {
    --    display: none !important; }
    --  .dac-visible-mobile-block, .dac-mobile-only {
    --    display: block !important; }
    --  .dac-visible-mobile-inline {
    --    display: inline !important; }
    --  .dac-visible-mobile-inline-block {
    --    display: inline-block !important; } }
    --
    --@media (min-width: 720px) and (max-width: 979px) {
    --  .dac-hidden-tablet {
    --    display: none !important; }
    --  .dac-visible-tablet-block {
    --    display: block !important; }
    --  .dac-visible-tablet-inline {
    --    display: inline !important; }
    --  .dac-visible-tablet-inline-block {
    --    display: inline-block !important; } }
    --
    --@media (min-width: 980px) {
    --  .dac-hidden-desktop {
    --    display: none !important; }
    --  .dac-visible-desktop-block {
    --    display: block !important; }
    --  .dac-visible-desktop-inline {
    --    display: inline !important; }
    --  .dac-visible-desktop-inline-block {
    --    display: inline-block !important; } }
    --
    --.dac-offset-parent {
    --  position: relative !important; }
    --
    --/**
    -- * Hide from browsers/screenreaders on all sizes.
    -- */
    --.dac-hidden {
    --  display: none !important; }
    --
    --/**
    -- * Break strings when their length exceeds the width of their container.
    -- */
    --.dac-text-break {
    --  word-wrap: break-word !important; }
    --
    --/**
    -- * Horizontal text alignment
    -- */
    --.dac-text-center {
    --  text-align: center !important; }
    --
    --.dac-text-left {
    --  text-align: left !important; }
    --
    --.dac-text-right {
    --  text-align: right !important; }
    --
    --/**
    -- * Prevent whitespace wrapping
    -- */
    --.dac-text-no-wrap {
    --  white-space: nowrap !important; }
    --
    --/**
    -- * Prevent text from wrapping onto multiple lines, instead truncate with an ellipsis.
    -- */
    --.dac-text-truncate {
    --  max-width: 100%;
    --  overflow: hidden !important;
    --  text-overflow: ellipsis !important;
    --  white-space: nowrap !important;
    --  word-wrap: normal !important; }
    --
    --/**
    -- * Floats
    -- */
    --.dac-float-left {
    --  float: left !important; }
    --
    --.dac-float-right {
    --  float: right !important; }
    --
    --/**
    -- * New block formatting context
    -- *
    -- * This affords some useful properties to the element. It won't wrap under
    -- * floats. Will also contain any floated children.
    -- * N.B. This will clip overflow. Use the alternative method below if this is
    -- * problematic.
    -- */
    --.dac-nbfc {
    --  overflow: hidden !important;
    --}
    --
    --/**
    -- * New block formatting context (alternative)
    -- *
    -- * Alternative method when overflow must not be clipped.
    -- *
    -- * N.B. This breaks down in some browsers when elements within this element
    -- * exceed its width.
    -- */
    --.dac-nbfc-alt {
    --  display: table-cell !important;
    --  width: 10000px !important;
    --}
    --
    --.Video {
    --  display: none;
    --}
    --
    --.Video-overlay {
    --  background-color: rgba(0, 0, 0, 0.8);
    --  width: 100%;
    --  height: 100%;
    --  position: fixed;
    --  top: 0;
    --  left: 0;
    --  z-index: 9999;
    --}
    --
    --.Video-container {
    --  width: 90vw;
    --  height: 50.625vw;
    --  max-height: calc(90vh - 29.25px);
    --  max-width: calc(160vh - 52px);
    --  margin: auto;
    --  position: fixed;
    --  top: -52px;
    --  right: 0;
    --  bottom: 0;
    --  left: 0;
    --  z-index: 9999;
    --}
    --
    --@media (min-width: 1422.22222222px) and (min-height: 800px) {
    --  .Video-container {
    --    width: 1280px;
    --    height: 720px;
    --  }
    --}
    --
    --.Video-controls {
    --  background: #28655F;
    --  height: 52px;
    --  margin: 0 auto;
    --  position: relative;
    --  box-shadow: 2px 3px 12px 0px rgba(0, 0, 0, 0.4);
    --}
    --
    --.Video-frame {
    --  position: relative;
    --  height: 100%;
    --  background: black;
    --  box-shadow: 2px 3px 12px 0px rgba(0, 0, 0, 0.4);
    --}
    --
    --.Video-loading {
    --  color: rgba(255, 255, 255, 0.35);
    --  font-size: 16px;
    --  position: absolute;
    --  top: 50%;
    --  left: 50%;
    --  -webkit-transform: translate(-50%, -50%);
    --  -ms-transform: translate(-50%, -50%);
    --  transform: translate(-50%, -50%);
    --}
    --
    --#youTubePlayer {
    --  max-height: 720px;
    --  position: absolute;
    --  top: 0;
    --  right: 0;
    --  bottom: 0;
    --  left: 0;
    --  width: 100%;
    --  height: 100%;
    --}
    --
    --.Video-button {
    --  background-color: transparent;
    --  border: none;
    --  display: inline-block;
    --  height: 100%;
    --  width: 52px;
    --  outline: none;
    --  cursor: pointer;
    --  -webkit-transition: opacity 200ms;
    --  transition: opacity 200ms;
    --}
    --
    --.Video-button:hover {
    --  opacity: 0.8;
    --}
    --
    --.Video-button--picture-in-picture {
    --  background-position: 0px -461px;
    --  height: 24px;
    --  width: 24px;
    --  display: none;
    --  position: absolute;
    --  right: 64px;
    --  top: 14px;
    --}
    --
    --.Video-button--close {
    --  background-position: 0px -435px;
    --  height: 24px;
    --  width: 24px;
    --  position: absolute;
    --  right: 14px;
    --  top: 14px;
    --}
    --
    --@media (min-width: 720px) {
    --  .Video--picture-in-picture .Video-overlay {
    --    display: none;
    --  }
    --
    --  .Video--picture-in-picture .Video-container {
    --    top: auto;
    --    left: auto;
    --    bottom: 20px;
    --    right: 20px;
    --    width: 40%;
    --    max-width: 420px;
    --    height: auto;
    --  }
    --
    --  .Video--picture-in-picture .Video-button--picture-in-picture {
    --    background-position: 0px -409px;
    --    height: 24px;
    --    width: 24px;
    --  }
    --
    --  .Video--picture-in-picture .Video-frame {
    --    padding-bottom: 56.25%;
    --  }
    --
    --  .Video-button--picture-in-picture {
    --    display: inline-block;
    --  }
    --}
    --
    --a.video-shadowbox-button.white {
    --  padding: 16px 42px 16px 8px;
    --  font-size: 18px;
    --  font-weight: 500;
    --  line-height: 24px;
    --  color: #fff;
    --  text-decoration: none;
    --}
    --
    --a.video-shadowbox-button.white::after {
    --  content: '';
    --  background-position: 0px -847px;
    --  height: 36px;
    --  width: 36px;
    --}
    --
    --a.video-shadowbox-button.white:hover {
    --  color: #bababa !important;
    --}
    --
    --a.video-shadowbox-button.white:hover::after {
    --  background-position: 0px -733px;
    --  height: 36px;
    --  width: 36px;
    --}
    --
    --#video-frame, #video-container {
    --  display: none;
    --}
    --
    --@media (max-width: 720px) {
    --  .wide-table {
    --    overflow-x: auto;
    --  }
    --
    --  .wide-table table {
    --    display: inline-table;
    --    margin-right: 0;
    --  }
    --}
    --
    --/* New CSS that isn't part of a component */
    --.paging-links {
    --  box-shadow: 0px 2px 6px 0px rgba(0, 0, 0, 0.2);
    --  margin: 30px 0;
    --  padding: 0 40px;
    --  /* Start class link doesn't have a caption */ }
    --
    --.paging-links .start-class-link, .paging-links .next-class-link, .paging-links .prev-page-link, .paging-links .next-page-link {
    --  font-size: 20px;
    --  font-weight: 500;
    --  display: inline-block;
    --  width: calc(50% - 2px);
    --  position: relative;
    --  padding: 46px 0 36px 0;
    --}
    --
    --@media (max-width: 719px) {
    --  .paging-links .start-class-link, .paging-links .next-class-link, .paging-links .prev-page-link, .paging-links .next-page-link {
    --    width: 100%;
    --  }
    --}
    --
    --.paging-links .start-class-link {
    --  padding: 36px 0;
    --}
    --
    --.paging-links .start-class-link, .paging-links .next-class-link {
    --  text-align: center;
    --  width: 100%;
    --}
    --
    --.paging-links .prev-page-link .page-link-caption {
    --  left: 0;
    --}
    --
    --.paging-links .prev-page-link:before {
    --  content: '';
    --  left: -24px;
    --  position: absolute;
    --  bottom: 41px;
    --}
    --
    --@media (max-width: 719px) {
    --  .paging-links .prev-page-link {
    --    display: none;
    --  }
    --}
    --
    --.paging-links .next-page-link, .paging-links .next-class-link {
    --  text-align: right;
    --}
    --
    --.paging-links .next-page-link .page-link-caption, .paging-links .next-class-link .page-link-caption {
    --  right: 0;
    --}
    --
    --.paging-links .next-page-link:before, .paging-links .next-class-link:before {
    --  content: '';
    --  right: -24px;
    --  position: absolute;
    --  bottom: 41px;
    --}
    --
    --.paging-links .start-class-link:after {
    --  content: '';
    --  right: -12px;
    --  position: relative;
    --  bottom: 3px;
    --}
    --
    --.paging-links .page-link-caption {
    --  position: absolute;
    --  top: 26px;
    --  font-size: 14px;
    --  font-weight: 700;
    --  opacity: 0.54;
    --}
    --
    --#tb li:before,
    --#qv li:before {
    --  background-position: 0px -669px;
    --  height: 24px;
    --  width: 24px;
    --  content: '';
    --  left: -8px;
    --  opacity: .7;
    --  position: absolute;
    --  top: -4px;
    --}
    --
    --#skip-to-main {
    --  border: 0;
    --  clip: rect(0 0 0 0);
    --  height: 1px;
    --  margin: -1px;
    --  overflow: hidden;
    --  padding: 0;
    --  position: absolute;
    --  width: 1px;
    --}
    --
    --#skip-to-main:focus {
    --  background: #fff;
    --  clip: auto;
    --  height: auto;
    --  padding: 10px;
    --  width: auto;
    --  z-index: 10000;
    --}
    -diff --git a/tools/droiddoc/templates-sdk-dev/assets/css/fullscreen.css b/tools/droiddoc/templates-sdk-dev/assets/css/fullscreen.css
    -deleted file mode 100644
    -index 0f108e0..0000000
    ---- a/tools/droiddoc/templates-sdk-dev/assets/css/fullscreen.css
    -+++ /dev/null
    -@@ -1,20 +0,0 @@
    --
    --/* =============================================================================
    --   Columns
    --   ========================================================================== */
    --/* Applied to body to debug layout alignments
    --.grid {
    --  width:100%;
    --  height:100%;
    --  background:url(../images/grid.png) center repeat-y;
    --  top:0px;
    --  margin:auto;
    --  position:absolute;
    --}   
    --*/
    --
    --@media screen, projection, print {
    --  .wrap {
    --    max-width: none;
    --  }
    --}
    -diff --git a/tools/droiddoc/templates-sdk-dev/assets/design/default.js b/tools/droiddoc/templates-sdk-dev/assets/design/default.js
    -deleted file mode 100644
    -index 3ba8486..0000000
    ---- a/tools/droiddoc/templates-sdk-dev/assets/design/default.js
    -+++ /dev/null
    -@@ -1,188 +0,0 @@
    --$(document).ready(function() {
    --  // prep nav expandos
    --  var pagePath = document.location.pathname;
    --  if (pagePath.indexOf(SITE_ROOT) == 0) {
    --    pagePath = pagePath.substr(SITE_ROOT.length);
    --    if (pagePath == '' || pagePath.charAt(pagePath.length - 1) == '/') {
    --      pagePath += 'index.html';
    --    }
    --  }
    --
    --  if (SITE_ROOT.match(/\.\.\//) || SITE_ROOT == '') {
    --    // If running locally, SITE_ROOT will be a relative path, so account for that by
    --    // finding the relative URL to this page. This will allow us to find links on the page
    --    // leading back to this page.
    --    var pathParts = pagePath.split('/');
    --    var relativePagePathParts = [];
    --    var upDirs = (SITE_ROOT.match(/(\.\.\/)+/) || [''])[0].length / 3;
    --    for (var i = 0; i < upDirs; i++) {
    --      relativePagePathParts.push('..');
    --    }
    --    for (var i = 0; i < upDirs; i++) {
    --      relativePagePathParts.push(pathParts[pathParts.length - (upDirs - i) - 1]);
    --    }
    --    relativePagePathParts.push(pathParts[pathParts.length - 1]);
    --    pagePath = relativePagePathParts.join('/');
    --  } else {
    --    // Otherwise the page path should be an absolute URL.
    --    pagePath = SITE_ROOT + pagePath;
    --  }
    --
    --  // select current page in sidenav and set up prev/next links if they exist
    --  var $selNavLink = $('.nav-y').find('a[href="' + pagePath + '"]');
    --  if ($selNavLink.length) {
    --    $selListItem = $selNavLink.closest('li');
    --
    --    $selListItem.addClass('selected');
    --    $selListItem.closest('li>ul').addClass('expanded');
    --
    --    // set up prev links
    --    var $prevLink = [];
    --    var $prevListItem = $selListItem.prev('li');
    --    if ($prevListItem.length) {
    --      if ($prevListItem.hasClass('nav-section')) {
    --        // jump to last topic of previous section
    --        $prevLink = $prevListItem.find('a:last');
    --      } else {
    --        // jump to previous topic in this section
    --        $prevLink = $prevListItem.find('a:eq(0)');
    --      }
    --    } else {
    --      // jump to this section's index page (if it exists)
    --      $prevLink = $selListItem.parents('li').find('a');
    --    }
    --
    --    if ($prevLink.length) {
    --      var prevHref = $prevLink.attr('href');
    --      if (prevHref == SITE_ROOT + 'index.html') {
    --        // Don't show Previous when it leads to the homepage
    --        $('.prev-page-link').hide();
    --      } else {
    --        $('.prev-page-link').attr('href', prevHref).show();
    --      }
    --    } else {
    --      $('.prev-page-link').hide();
    --    }
    --
    --    // set up next links
    --    var $nextLink = [];
    --    if ($selListItem.hasClass('nav-section')) {
    --      // we're on an index page, jump to the first topic
    --      $nextLink = $selListItem.find('ul').find('a:eq(0)')
    --    } else {
    --      // jump to the next topic in this section (if it exists)
    --      $nextLink = $selListItem.next('li').find('a:eq(0)');
    --      if (!$nextLink.length) {
    --        // no more topics in this section, jump to the first topic in the next section
    --        $nextLink = $selListItem.parents('li').next('li.nav-section').find('a:eq(0)');
    --      }
    --    }
    --    if ($nextLink.length) {
    --      $('.next-page-link').attr('href', $nextLink.attr('href')).show();
    --    } else {
    --      $('.next-page-link').hide();
    --    }
    --  }
    --
    --  // Set up expand/collapse behavior
    --  $('.nav-y li').has('ul').click(function() {
    --    if ($(this).hasClass('expanded')) {
    --      return;
    --    }
    --
    --    // hide other
    --    var $old = $('.nav-y li.expanded');
    --    if ($old.length) {
    --      var $oldUl = $old.children('ul');
    --      $oldUl.css('height', $oldUl.height() + 'px');
    --      window.setTimeout(function() {
    --        $oldUl
    --            .addClass('animate-height')
    --            .css('height', '');
    --      }, 0);
    --      $old.removeClass('expanded');
    --    }
    --
    --    // show me
    --    $(this).addClass('expanded');
    --    var $ul = $(this).children('ul');
    --    var expandedHeight = $ul.height();
    --    $ul
    --        .removeClass('animate-height')
    --        .css('height', 0);
    --    window.setTimeout(function() {
    --      $ul
    --          .addClass('animate-height')
    --          .css('height', expandedHeight + 'px');
    --    }, 0);
    --  });
    --
    --  // Stop expand/collapse behavior when clicking on nav section links (since we're navigating away
    --  // from the page)
    --  $('.nav-y li').has('ul').find('a:eq(0)').click(function(evt) {
    --    window.location.href = $(this).attr('href');
    --    return false;
    --  });
    --
    --  // Set up play-on-hover <video> tags.
    --  $('video.play-on-hover').bind('click', function(){
    --    $(this).get(0).load(); // in case the video isn't seekable
    --    $(this).get(0).play();
    --  });
    --
    --  // Set up tooltips
    --  var TOOLTIP_MARGIN = 10;
    --  $('acronym').each(function() {
    --    var $target = $(this);
    --    var $tooltip = $('<div>')
    --        .addClass('tooltip-box')
    --        .text($target.attr('title'))
    --        .hide()
    --        .appendTo('body');
    --    $target.removeAttr('title');
    --
    --    $target.hover(function() {
    --      // in
    --      var targetRect = $target.offset();
    --      targetRect.width = $target.width();
    --      targetRect.height = $target.height();
    --
    --      $tooltip.css({
    --        left: targetRect.left,
    --        top: targetRect.top + targetRect.height + TOOLTIP_MARGIN
    --      });
    --      $tooltip.addClass('below');
    --      $tooltip.show();
    --    }, function() {
    --      // out
    --      $tooltip.hide();
    --    });
    --  });
    --
    --  // Set up <h2> deeplinks
    --  $('h2').click(function() {
    --    var id = $(this).attr('id');
    --    if (id) {
    --      document.location.hash = id;
    --    }
    --  });
    --
    --  // Set up fixed navbar
    --  var navBarIsFixed = false;
    --  $(window).scroll(function() {
    --    var scrollTop = $(window).scrollTop();
    --    var navBarShouldBeFixed = (scrollTop > (100 - 40));
    --    if (navBarIsFixed != navBarShouldBeFixed) {
    --      if (navBarShouldBeFixed) {
    --        $('#nav')
    --            .addClass('fixed')
    --            .prependTo('#page-container');
    --      } else {
    --        $('#nav')
    --            .removeClass('fixed')
    --            .prependTo('#nav-container');
    --      }
    --      navBarIsFixed = navBarShouldBeFixed;
    --    }
    --  });
    --});
    -\ No newline at end of file
    -diff --git a/tools/droiddoc/templates-sdk-dev/assets/images/android-developers-logo.png b/tools/droiddoc/templates-sdk-dev/assets/images/android-developers-logo.png
    -deleted file mode 100644
    -index 30a8f62..0000000
    -Binary files a/tools/droiddoc/templates-sdk-dev/assets/images/android-developers-logo.png and /dev/null differ
    -diff --git a/tools/droiddoc/templates-sdk-dev/assets/images/android.png b/tools/droiddoc/templates-sdk-dev/assets/images/android.png
    -deleted file mode 100644
    -index 4040f3f..0000000
    -Binary files a/tools/droiddoc/templates-sdk-dev/assets/images/android.png and /dev/null differ
    -diff --git a/tools/droiddoc/templates-sdk-dev/assets/images/android_logo.png b/tools/droiddoc/templates-sdk-dev/assets/images/android_logo.png
    -deleted file mode 100644
    -index 53f59c6..0000000
    -Binary files a/tools/droiddoc/templates-sdk-dev/assets/images/android_logo.png and /dev/null differ
    -diff --git a/tools/droiddoc/templates-sdk-dev/assets/images/android_logo@2x.png b/tools/droiddoc/templates-sdk-dev/assets/images/android_logo@2x.png
    -deleted file mode 100644
    -index 85b9211..0000000
    -Binary files a/tools/droiddoc/templates-sdk-dev/assets/images/android_logo@2x.png and /dev/null differ
    -diff --git a/tools/droiddoc/templates-sdk-dev/assets/images/android_logo_ndk.png b/tools/droiddoc/templates-sdk-dev/assets/images/android_logo_ndk.png
    -deleted file mode 100644
    -index 3f39f4d..0000000
    -Binary files a/tools/droiddoc/templates-sdk-dev/assets/images/android_logo_ndk.png and /dev/null differ
    -diff --git a/tools/droiddoc/templates-sdk-dev/assets/images/android_logo_ndk@2x.png b/tools/droiddoc/templates-sdk-dev/assets/images/android_logo_ndk@2x.png
    -deleted file mode 100644
    -index 8081ac5..0000000
    -Binary files a/tools/droiddoc/templates-sdk-dev/assets/images/android_logo_ndk@2x.png and /dev/null differ
    -diff --git a/tools/droiddoc/templates-sdk-dev/assets/images/android_wrench.png b/tools/droiddoc/templates-sdk-dev/assets/images/android_wrench.png
    -deleted file mode 100644
    -index 6390a2d..0000000
    -Binary files a/tools/droiddoc/templates-sdk-dev/assets/images/android_wrench.png and /dev/null differ
    -diff --git a/tools/droiddoc/templates-sdk-dev/assets/images/arrow-left-develop.png b/tools/droiddoc/templates-sdk-dev/assets/images/arrow-left-develop.png
    -deleted file mode 100644
    -index 5fdfaa3..0000000
    -Binary files a/tools/droiddoc/templates-sdk-dev/assets/images/arrow-left-develop.png and /dev/null differ
    -diff --git a/tools/droiddoc/templates-sdk-dev/assets/images/arrow-left.png b/tools/droiddoc/templates-sdk-dev/assets/images/arrow-left.png
    -deleted file mode 100644
    -index 43afec8..0000000
    -Binary files a/tools/droiddoc/templates-sdk-dev/assets/images/arrow-left.png and /dev/null differ
    -diff --git a/tools/droiddoc/templates-sdk-dev/assets/images/arrow-right-develop.png b/tools/droiddoc/templates-sdk-dev/assets/images/arrow-right-develop.png
    -deleted file mode 100644
    -index c86f1f3..0000000
    -Binary files a/tools/droiddoc/templates-sdk-dev/assets/images/arrow-right-develop.png and /dev/null differ
    -diff --git a/tools/droiddoc/templates-sdk-dev/assets/images/arrow-right.png b/tools/droiddoc/templates-sdk-dev/assets/images/arrow-right.png
    -deleted file mode 100644
    -index 6f7d6db..0000000
    -Binary files a/tools/droiddoc/templates-sdk-dev/assets/images/arrow-right.png and /dev/null differ
    -diff --git a/tools/droiddoc/templates-sdk-dev/assets/images/arrow_bluelink_down.png b/tools/droiddoc/templates-sdk-dev/assets/images/arrow_bluelink_down.png
    -deleted file mode 100755
    -index 58c248a..0000000
    -Binary files a/tools/droiddoc/templates-sdk-dev/assets/images/arrow_bluelink_down.png and /dev/null differ
    -diff --git a/tools/droiddoc/templates-sdk-dev/assets/images/arrow_bluelink_up.png b/tools/droiddoc/templates-sdk-dev/assets/images/arrow_bluelink_up.png
    -deleted file mode 100755
    -index 7d0f38e..0000000
    -Binary files a/tools/droiddoc/templates-sdk-dev/assets/images/arrow_bluelink_up.png and /dev/null differ
    -diff --git a/tools/droiddoc/templates-sdk-dev/assets/images/arrow_left_off.jpg b/tools/droiddoc/templates-sdk-dev/assets/images/arrow_left_off.jpg
    -deleted file mode 100755
    -index fd32a64..0000000
    -Binary files a/tools/droiddoc/templates-sdk-dev/assets/images/arrow_left_off.jpg and /dev/null differ
    -diff --git a/tools/droiddoc/templates-sdk-dev/assets/images/arrow_left_on.jpg b/tools/droiddoc/templates-sdk-dev/assets/images/arrow_left_on.jpg
    -deleted file mode 100755
    -index 143184b..0000000
    -Binary files a/tools/droiddoc/templates-sdk-dev/assets/images/arrow_left_on.jpg and /dev/null differ
    -diff --git a/tools/droiddoc/templates-sdk-dev/assets/images/arrow_right_off.jpg b/tools/droiddoc/templates-sdk-dev/assets/images/arrow_right_off.jpg
    -deleted file mode 100755
    -index 17d2efe..0000000
    -Binary files a/tools/droiddoc/templates-sdk-dev/assets/images/arrow_right_off.jpg and /dev/null differ
    -diff --git a/tools/droiddoc/templates-sdk-dev/assets/images/arrow_right_on.jpg b/tools/droiddoc/templates-sdk-dev/assets/images/arrow_right_on.jpg
    -deleted file mode 100755
    -index baa2af1..0000000
    -Binary files a/tools/droiddoc/templates-sdk-dev/assets/images/arrow_right_on.jpg and /dev/null differ
    -diff --git a/tools/droiddoc/templates-sdk-dev/assets/images/arrows-up-down.png b/tools/droiddoc/templates-sdk-dev/assets/images/arrows-up-down.png
    -deleted file mode 100644
    -index a2a91ed..0000000
    -Binary files a/tools/droiddoc/templates-sdk-dev/assets/images/arrows-up-down.png and /dev/null differ
    -diff --git a/tools/droiddoc/templates-sdk-dev/assets/images/bg_community_leftDiv.jpg b/tools/droiddoc/templates-sdk-dev/assets/images/bg_community_leftDiv.jpg
    -deleted file mode 100755
    -index a6d6f0e..0000000
    -Binary files a/tools/droiddoc/templates-sdk-dev/assets/images/bg_community_leftDiv.jpg and /dev/null differ
    -diff --git a/tools/droiddoc/templates-sdk-dev/assets/images/bg_fade.jpg b/tools/droiddoc/templates-sdk-dev/assets/images/bg_fade.jpg
    -deleted file mode 100755
    -index c6c70b6..0000000
    -Binary files a/tools/droiddoc/templates-sdk-dev/assets/images/bg_fade.jpg and /dev/null differ
    -diff --git a/tools/droiddoc/templates-sdk-dev/assets/images/bg_gradient.jpg b/tools/droiddoc/templates-sdk-dev/assets/images/bg_gradient.jpg
    -deleted file mode 100644
    -index 884f8f5..0000000
    -Binary files a/tools/droiddoc/templates-sdk-dev/assets/images/bg_gradient.jpg and /dev/null differ
    -diff --git a/tools/droiddoc/templates-sdk-dev/assets/images/bg_images_sprite.png b/tools/droiddoc/templates-sdk-dev/assets/images/bg_images_sprite.png
    -deleted file mode 100755
    -index 84437e7..0000000
    -Binary files a/tools/droiddoc/templates-sdk-dev/assets/images/bg_images_sprite.png and /dev/null differ
    -diff --git a/tools/droiddoc/templates-sdk-dev/assets/images/bg_logo.png b/tools/droiddoc/templates-sdk-dev/assets/images/bg_logo.png
    -deleted file mode 100755
    -index 7cf0cb9..0000000
    -Binary files a/tools/droiddoc/templates-sdk-dev/assets/images/bg_logo.png and /dev/null differ
    -diff --git a/tools/droiddoc/templates-sdk-dev/assets/images/blog-default.png b/tools/droiddoc/templates-sdk-dev/assets/images/blog-default.png
    -deleted file mode 100644
    -index f8ab6c3..0000000
    -Binary files a/tools/droiddoc/templates-sdk-dev/assets/images/blog-default.png and /dev/null differ
    -diff --git a/tools/droiddoc/templates-sdk-dev/assets/images/body-gradient-tab.png b/tools/droiddoc/templates-sdk-dev/assets/images/body-gradient-tab.png
    -deleted file mode 100644
    -index 5223ac3..0000000
    -Binary files a/tools/droiddoc/templates-sdk-dev/assets/images/body-gradient-tab.png and /dev/null differ
    -diff --git a/tools/droiddoc/templates-sdk-dev/assets/images/body-gradient.png b/tools/droiddoc/templates-sdk-dev/assets/images/body-gradient.png
    -deleted file mode 100755
    -index 9d59855..0000000
    -Binary files a/tools/droiddoc/templates-sdk-dev/assets/images/body-gradient.png and /dev/null differ
    -diff --git a/tools/droiddoc/templates-sdk-dev/assets/images/breadcrumb.png b/tools/droiddoc/templates-sdk-dev/assets/images/breadcrumb.png
    -deleted file mode 100644
    -index 407a318..0000000
    -Binary files a/tools/droiddoc/templates-sdk-dev/assets/images/breadcrumb.png and /dev/null differ
    -diff --git a/tools/droiddoc/templates-sdk-dev/assets/images/close-grey.png b/tools/droiddoc/templates-sdk-dev/assets/images/close-grey.png
    -deleted file mode 100644
    -index 1b0d7f1..0000000
    -Binary files a/tools/droiddoc/templates-sdk-dev/assets/images/close-grey.png and /dev/null differ
    -diff --git a/tools/droiddoc/templates-sdk-dev/assets/images/close-grey_2x.png b/tools/droiddoc/templates-sdk-dev/assets/images/close-grey_2x.png
    -deleted file mode 100644
    -index 1355507..0000000
    -Binary files a/tools/droiddoc/templates-sdk-dev/assets/images/close-grey_2x.png and /dev/null differ
    -diff --git a/tools/droiddoc/templates-sdk-dev/assets/images/close-white.png b/tools/droiddoc/templates-sdk-dev/assets/images/close-white.png
    -deleted file mode 100644
    -index ef02018..0000000
    -Binary files a/tools/droiddoc/templates-sdk-dev/assets/images/close-white.png and /dev/null differ
    -diff --git a/tools/droiddoc/templates-sdk-dev/assets/images/close-white_2x.png b/tools/droiddoc/templates-sdk-dev/assets/images/close-white_2x.png
    -deleted file mode 100644
    -index 9b9c41d..0000000
    -Binary files a/tools/droiddoc/templates-sdk-dev/assets/images/close-white_2x.png and /dev/null differ
    -diff --git a/tools/droiddoc/templates-sdk-dev/assets/images/close.png b/tools/droiddoc/templates-sdk-dev/assets/images/close.png
    -deleted file mode 100644
    -index 6ae3391..0000000
    -Binary files a/tools/droiddoc/templates-sdk-dev/assets/images/close.png and /dev/null differ
    -diff --git a/tools/droiddoc/templates-sdk-dev/assets/images/dac_logo.png b/tools/droiddoc/templates-sdk-dev/assets/images/dac_logo.png
    -deleted file mode 100644
    -index 0f11044..0000000
    -Binary files a/tools/droiddoc/templates-sdk-dev/assets/images/dac_logo.png and /dev/null differ
    -diff --git a/tools/droiddoc/templates-sdk-dev/assets/images/dac_logo@2x.png b/tools/droiddoc/templates-sdk-dev/assets/images/dac_logo@2x.png
    -deleted file mode 100644
    -index 0f2784d..0000000
    -Binary files a/tools/droiddoc/templates-sdk-dev/assets/images/dac_logo@2x.png and /dev/null differ
    -diff --git a/tools/droiddoc/templates-sdk-dev/assets/images/developers-logo.png b/tools/droiddoc/templates-sdk-dev/assets/images/developers-logo.png
    -deleted file mode 100755
    -index 08122ee..0000000
    -Binary files a/tools/droiddoc/templates-sdk-dev/assets/images/developers-logo.png and /dev/null differ
    -diff --git a/tools/droiddoc/templates-sdk-dev/assets/images/file-generic.png b/tools/droiddoc/templates-sdk-dev/assets/images/file-generic.png
    -deleted file mode 100644
    -index 1802457..0000000
    -Binary files a/tools/droiddoc/templates-sdk-dev/assets/images/file-generic.png and /dev/null differ
    -diff --git a/tools/droiddoc/templates-sdk-dev/assets/images/file-image.png b/tools/droiddoc/templates-sdk-dev/assets/images/file-image.png
    -deleted file mode 100644
    -index d3aec46..0000000
    -Binary files a/tools/droiddoc/templates-sdk-dev/assets/images/file-image.png and /dev/null differ
    -diff --git a/tools/droiddoc/templates-sdk-dev/assets/images/file-java.png b/tools/droiddoc/templates-sdk-dev/assets/images/file-java.png
    -deleted file mode 100644
    -index ec85e4b..0000000
    -Binary files a/tools/droiddoc/templates-sdk-dev/assets/images/file-java.png and /dev/null differ
    -diff --git a/tools/droiddoc/templates-sdk-dev/assets/images/file-manifest.png b/tools/droiddoc/templates-sdk-dev/assets/images/file-manifest.png
    -deleted file mode 100644
    -index 332d066..0000000
    -Binary files a/tools/droiddoc/templates-sdk-dev/assets/images/file-manifest.png and /dev/null differ
    -diff --git a/tools/droiddoc/templates-sdk-dev/assets/images/file-xml.png b/tools/droiddoc/templates-sdk-dev/assets/images/file-xml.png
    -deleted file mode 100644
    -index 3dd21b6..0000000
    -Binary files a/tools/droiddoc/templates-sdk-dev/assets/images/file-xml.png and /dev/null differ
    -diff --git a/tools/droiddoc/templates-sdk-dev/assets/images/folder.png b/tools/droiddoc/templates-sdk-dev/assets/images/folder.png
    -deleted file mode 100644
    -index 44c6100..0000000
    -Binary files a/tools/droiddoc/templates-sdk-dev/assets/images/folder.png and /dev/null differ
    -diff --git a/tools/droiddoc/templates-sdk-dev/assets/images/fullscreen.png b/tools/droiddoc/templates-sdk-dev/assets/images/fullscreen.png
    -deleted file mode 100644
    -index 01f971c..0000000
    -Binary files a/tools/droiddoc/templates-sdk-dev/assets/images/fullscreen.png and /dev/null differ
    -diff --git a/tools/droiddoc/templates-sdk-dev/assets/images/grad-rule-qv.png b/tools/droiddoc/templates-sdk-dev/assets/images/grad-rule-qv.png
    -deleted file mode 100644
    -index bae2d18..0000000
    -Binary files a/tools/droiddoc/templates-sdk-dev/assets/images/grad-rule-qv.png and /dev/null differ
    -diff --git a/tools/droiddoc/templates-sdk-dev/assets/images/home/Android_Dev_Lab_l.png b/tools/droiddoc/templates-sdk-dev/assets/images/home/Android_Dev_Lab_l.png
    -deleted file mode 100644
    -index 3c04f24..0000000
    -Binary files a/tools/droiddoc/templates-sdk-dev/assets/images/home/Android_Dev_Lab_l.png and /dev/null differ
    -diff --git a/tools/droiddoc/templates-sdk-dev/assets/images/home/GDC2011.png b/tools/droiddoc/templates-sdk-dev/assets/images/home/GDC2011.png
    -deleted file mode 100644
    -index 82ce918..0000000
    -Binary files a/tools/droiddoc/templates-sdk-dev/assets/images/home/GDC2011.png and /dev/null differ
    -diff --git a/tools/droiddoc/templates-sdk-dev/assets/images/home/GTV_icon_large.png b/tools/droiddoc/templates-sdk-dev/assets/images/home/GTV_icon_large.png
    -deleted file mode 100644
    -index 72d54ad..0000000
    -Binary files a/tools/droiddoc/templates-sdk-dev/assets/images/home/GTV_icon_large.png and /dev/null differ
    -diff --git a/tools/droiddoc/templates-sdk-dev/assets/images/home/GTV_icon_small.png b/tools/droiddoc/templates-sdk-dev/assets/images/home/GTV_icon_small.png
    -deleted file mode 100644
    -index 3da1699..0000000
    -Binary files a/tools/droiddoc/templates-sdk-dev/assets/images/home/GTV_icon_small.png and /dev/null differ
    -diff --git a/tools/droiddoc/templates-sdk-dev/assets/images/home/IO-logo-2011.png b/tools/droiddoc/templates-sdk-dev/assets/images/home/IO-logo-2011.png
    -deleted file mode 100644
    -index 4a28447..0000000
    -Binary files a/tools/droiddoc/templates-sdk-dev/assets/images/home/IO-logo-2011.png and /dev/null differ
    -diff --git a/tools/droiddoc/templates-sdk-dev/assets/images/home/IO-logo.png b/tools/droiddoc/templates-sdk-dev/assets/images/home/IO-logo.png
    -deleted file mode 100644
    -index 65334c8..0000000
    -Binary files a/tools/droiddoc/templates-sdk-dev/assets/images/home/IO-logo.png and /dev/null differ
    -diff --git a/tools/droiddoc/templates-sdk-dev/assets/images/home/adc2_l.png b/tools/droiddoc/templates-sdk-dev/assets/images/home/adc2_l.png
    -deleted file mode 100644
    -index 0b101a4..0000000
    -Binary files a/tools/droiddoc/templates-sdk-dev/assets/images/home/adc2_l.png and /dev/null differ
    -diff --git a/tools/droiddoc/templates-sdk-dev/assets/images/home/adc2_s.png b/tools/droiddoc/templates-sdk-dev/assets/images/home/adc2_s.png
    -deleted file mode 100644
    -index 0d36bdb..0000000
    -Binary files a/tools/droiddoc/templates-sdk-dev/assets/images/home/adc2_s.png and /dev/null differ
    -diff --git a/tools/droiddoc/templates-sdk-dev/assets/images/home/android_adc.png b/tools/droiddoc/templates-sdk-dev/assets/images/home/android_adc.png
    -deleted file mode 100644
    -index 9fe7f8f..0000000
    -Binary files a/tools/droiddoc/templates-sdk-dev/assets/images/home/android_adc.png and /dev/null differ
    -diff --git a/tools/droiddoc/templates-sdk-dev/assets/images/home/android_m_hero_1200.jpg b/tools/droiddoc/templates-sdk-dev/assets/images/home/android_m_hero_1200.jpg
    -deleted file mode 100644
    -index 6b79295..0000000
    -Binary files a/tools/droiddoc/templates-sdk-dev/assets/images/home/android_m_hero_1200.jpg and /dev/null differ
    -diff --git a/tools/droiddoc/templates-sdk-dev/assets/images/home/bg_home_announcement.png b/tools/droiddoc/templates-sdk-dev/assets/images/home/bg_home_announcement.png
    -deleted file mode 100755
    -index 91485ff..0000000
    -Binary files a/tools/droiddoc/templates-sdk-dev/assets/images/home/bg_home_announcement.png and /dev/null differ
    -diff --git a/tools/droiddoc/templates-sdk-dev/assets/images/home/bg_home_bottom.jpg b/tools/droiddoc/templates-sdk-dev/assets/images/home/bg_home_bottom.jpg
    -deleted file mode 100755
    -index dacd401..0000000
    -Binary files a/tools/droiddoc/templates-sdk-dev/assets/images/home/bg_home_bottom.jpg and /dev/null differ
    -diff --git a/tools/droiddoc/templates-sdk-dev/assets/images/home/bg_home_carousel.png b/tools/droiddoc/templates-sdk-dev/assets/images/home/bg_home_carousel.png
    -deleted file mode 100755
    -index 5ce5e30..0000000
    -Binary files a/tools/droiddoc/templates-sdk-dev/assets/images/home/bg_home_carousel.png and /dev/null differ
    -diff --git a/tools/droiddoc/templates-sdk-dev/assets/images/home/bg_home_carousel_board.png b/tools/droiddoc/templates-sdk-dev/assets/images/home/bg_home_carousel_board.png
    -deleted file mode 100755
    -index c577e02..0000000
    -Binary files a/tools/droiddoc/templates-sdk-dev/assets/images/home/bg_home_carousel_board.png and /dev/null differ
    -diff --git a/tools/droiddoc/templates-sdk-dev/assets/images/home/bg_home_carousel_wheel.png b/tools/droiddoc/templates-sdk-dev/assets/images/home/bg_home_carousel_wheel.png
    -deleted file mode 100755
    -index aa224ad..0000000
    -Binary files a/tools/droiddoc/templates-sdk-dev/assets/images/home/bg_home_carousel_wheel.png and /dev/null differ
    -diff --git a/tools/droiddoc/templates-sdk-dev/assets/images/home/carousel_buttons_sprite.png b/tools/droiddoc/templates-sdk-dev/assets/images/home/carousel_buttons_sprite.png
    -deleted file mode 100755
    -index e98c942..0000000
    -Binary files a/tools/droiddoc/templates-sdk-dev/assets/images/home/carousel_buttons_sprite.png and /dev/null differ
    -diff --git a/tools/droiddoc/templates-sdk-dev/assets/images/home/devphone-large.png b/tools/droiddoc/templates-sdk-dev/assets/images/home/devphone-large.png
    -deleted file mode 100644
    -index 0db0f6c..0000000
    -Binary files a/tools/droiddoc/templates-sdk-dev/assets/images/home/devphone-large.png and /dev/null differ
    -diff --git a/tools/droiddoc/templates-sdk-dev/assets/images/home/devphone-small.png b/tools/droiddoc/templates-sdk-dev/assets/images/home/devphone-small.png
    -deleted file mode 100644
    -index e10bfa9..0000000
    -Binary files a/tools/droiddoc/templates-sdk-dev/assets/images/home/devphone-small.png and /dev/null differ
    -diff --git a/tools/droiddoc/templates-sdk-dev/assets/images/home/donut-android.png b/tools/droiddoc/templates-sdk-dev/assets/images/home/donut-android.png
    -deleted file mode 100755
    -index 6aba06b..0000000
    -Binary files a/tools/droiddoc/templates-sdk-dev/assets/images/home/donut-android.png and /dev/null differ
    -diff --git a/tools/droiddoc/templates-sdk-dev/assets/images/home/eclair-android.png b/tools/droiddoc/templates-sdk-dev/assets/images/home/eclair-android.png
    -deleted file mode 100644
    -index d476ce9..0000000
    -Binary files a/tools/droiddoc/templates-sdk-dev/assets/images/home/eclair-android.png and /dev/null differ
    -diff --git a/tools/droiddoc/templates-sdk-dev/assets/images/home/froyo-android.png b/tools/droiddoc/templates-sdk-dev/assets/images/home/froyo-android.png
    -deleted file mode 100644
    -index c63f7f0..0000000
    -Binary files a/tools/droiddoc/templates-sdk-dev/assets/images/home/froyo-android.png and /dev/null differ
    -diff --git a/tools/droiddoc/templates-sdk-dev/assets/images/home/gdc-logo.png b/tools/droiddoc/templates-sdk-dev/assets/images/home/gdc-logo.png
    -deleted file mode 100644
    -index 5fb53fb..0000000
    -Binary files a/tools/droiddoc/templates-sdk-dev/assets/images/home/gdc-logo.png and /dev/null differ
    -diff --git a/tools/droiddoc/templates-sdk-dev/assets/images/home/gingerdroid.png b/tools/droiddoc/templates-sdk-dev/assets/images/home/gingerdroid.png
    -deleted file mode 100644
    -index 8399d84..0000000
    -Binary files a/tools/droiddoc/templates-sdk-dev/assets/images/home/gingerdroid.png and /dev/null differ
    -diff --git a/tools/droiddoc/templates-sdk-dev/assets/images/home/google-plus-small.png b/tools/droiddoc/templates-sdk-dev/assets/images/home/google-plus-small.png
    -deleted file mode 100644
    -index 5bb7d7a..0000000
    -Binary files a/tools/droiddoc/templates-sdk-dev/assets/images/home/google-plus-small.png and /dev/null differ
    -diff --git a/tools/droiddoc/templates-sdk-dev/assets/images/home/google-plus.png b/tools/droiddoc/templates-sdk-dev/assets/images/home/google-plus.png
    -deleted file mode 100644
    -index 90871e1..0000000
    -Binary files a/tools/droiddoc/templates-sdk-dev/assets/images/home/google-plus.png and /dev/null differ
    -diff --git a/tools/droiddoc/templates-sdk-dev/assets/images/home/honeycomb-android.png b/tools/droiddoc/templates-sdk-dev/assets/images/home/honeycomb-android.png
    -deleted file mode 100644
    -index 6cc5031..0000000
    -Binary files a/tools/droiddoc/templates-sdk-dev/assets/images/home/honeycomb-android.png and /dev/null differ
    -diff --git a/tools/droiddoc/templates-sdk-dev/assets/images/home/icon-about.png b/tools/droiddoc/templates-sdk-dev/assets/images/home/icon-about.png
    -deleted file mode 100644
    -index 8339762..0000000
    -Binary files a/tools/droiddoc/templates-sdk-dev/assets/images/home/icon-about.png and /dev/null differ
    -diff --git a/tools/droiddoc/templates-sdk-dev/assets/images/home/icon-design.png b/tools/droiddoc/templates-sdk-dev/assets/images/home/icon-design.png
    -deleted file mode 100644
    -index 0d31cdf..0000000
    -Binary files a/tools/droiddoc/templates-sdk-dev/assets/images/home/icon-design.png and /dev/null differ
    -diff --git a/tools/droiddoc/templates-sdk-dev/assets/images/home/icon-develop.png b/tools/droiddoc/templates-sdk-dev/assets/images/home/icon-develop.png
    -deleted file mode 100644
    -index e02b20f..0000000
    -Binary files a/tools/droiddoc/templates-sdk-dev/assets/images/home/icon-develop.png and /dev/null differ
    -diff --git a/tools/droiddoc/templates-sdk-dev/assets/images/home/icon-distribute.png b/tools/droiddoc/templates-sdk-dev/assets/images/home/icon-distribute.png
    -deleted file mode 100644
    -index 4824072..0000000
    -Binary files a/tools/droiddoc/templates-sdk-dev/assets/images/home/icon-distribute.png and /dev/null differ
    -diff --git a/tools/droiddoc/templates-sdk-dev/assets/images/home/ics-android.png b/tools/droiddoc/templates-sdk-dev/assets/images/home/ics-android.png
    -deleted file mode 100644
    -index be62ca8..0000000
    -Binary files a/tools/droiddoc/templates-sdk-dev/assets/images/home/ics-android.png and /dev/null differ
    -diff --git a/tools/droiddoc/templates-sdk-dev/assets/images/home/io-large.png b/tools/droiddoc/templates-sdk-dev/assets/images/home/io-large.png
    -deleted file mode 100755
    -index 986053c..0000000
    -Binary files a/tools/droiddoc/templates-sdk-dev/assets/images/home/io-large.png and /dev/null differ
    -diff --git a/tools/droiddoc/templates-sdk-dev/assets/images/home/io-small.png b/tools/droiddoc/templates-sdk-dev/assets/images/home/io-small.png
    -deleted file mode 100755
    -index 3a22549..0000000
    -Binary files a/tools/droiddoc/templates-sdk-dev/assets/images/home/io-small.png and /dev/null differ
    -diff --git a/tools/droiddoc/templates-sdk-dev/assets/images/home/maps-large.png b/tools/droiddoc/templates-sdk-dev/assets/images/home/maps-large.png
    -deleted file mode 100644
    -index b26f65a..0000000
    -Binary files a/tools/droiddoc/templates-sdk-dev/assets/images/home/maps-large.png and /dev/null differ
    -diff --git a/tools/droiddoc/templates-sdk-dev/assets/images/home/maps-small.png b/tools/droiddoc/templates-sdk-dev/assets/images/home/maps-small.png
    -deleted file mode 100644
    -index cc5f1fa..0000000
    -Binary files a/tools/droiddoc/templates-sdk-dev/assets/images/home/maps-small.png and /dev/null differ
    -diff --git a/tools/droiddoc/templates-sdk-dev/assets/images/home/market-large.png b/tools/droiddoc/templates-sdk-dev/assets/images/home/market-large.png
    -deleted file mode 100644
    -index 069fee7..0000000
    -Binary files a/tools/droiddoc/templates-sdk-dev/assets/images/home/market-large.png and /dev/null differ
    -diff --git a/tools/droiddoc/templates-sdk-dev/assets/images/home/market-small.png b/tools/droiddoc/templates-sdk-dev/assets/images/home/market-small.png
    -deleted file mode 100644
    -index fa1201c..0000000
    -Binary files a/tools/droiddoc/templates-sdk-dev/assets/images/home/market-small.png and /dev/null differ
    -diff --git a/tools/droiddoc/templates-sdk-dev/assets/images/home/sdk-large.png b/tools/droiddoc/templates-sdk-dev/assets/images/home/sdk-large.png
    -deleted file mode 100644
    -index 315a1bf..0000000
    -Binary files a/tools/droiddoc/templates-sdk-dev/assets/images/home/sdk-large.png and /dev/null differ
    -diff --git a/tools/droiddoc/templates-sdk-dev/assets/images/home/sdk-small.png b/tools/droiddoc/templates-sdk-dev/assets/images/home/sdk-small.png
    -deleted file mode 100644
    -index 0f1670d..0000000
    -Binary files a/tools/droiddoc/templates-sdk-dev/assets/images/home/sdk-small.png and /dev/null differ
    -diff --git a/tools/droiddoc/templates-sdk-dev/assets/images/hr_gray_main.jpg b/tools/droiddoc/templates-sdk-dev/assets/images/hr_gray_main.jpg
    -deleted file mode 100755
    -index f7a0a2f..0000000
    -Binary files a/tools/droiddoc/templates-sdk-dev/assets/images/hr_gray_main.jpg and /dev/null differ
    -diff --git a/tools/droiddoc/templates-sdk-dev/assets/images/hr_gray_side.jpg b/tools/droiddoc/templates-sdk-dev/assets/images/hr_gray_side.jpg
    -deleted file mode 100755
    -index 6667476..0000000
    -Binary files a/tools/droiddoc/templates-sdk-dev/assets/images/hr_gray_side.jpg and /dev/null differ
    -diff --git a/tools/droiddoc/templates-sdk-dev/assets/images/icon_contribute.jpg b/tools/droiddoc/templates-sdk-dev/assets/images/icon_contribute.jpg
    -deleted file mode 100755
    -index 1aa12b6..0000000
    -Binary files a/tools/droiddoc/templates-sdk-dev/assets/images/icon_contribute.jpg and /dev/null differ
    -diff --git a/tools/droiddoc/templates-sdk-dev/assets/images/icon_design.png b/tools/droiddoc/templates-sdk-dev/assets/images/icon_design.png
    -deleted file mode 100644
    -index c12907c..0000000
    -Binary files a/tools/droiddoc/templates-sdk-dev/assets/images/icon_design.png and /dev/null differ
    -diff --git a/tools/droiddoc/templates-sdk-dev/assets/images/icon_download.jpg b/tools/droiddoc/templates-sdk-dev/assets/images/icon_download.jpg
    -deleted file mode 100755
    -index f8c1165..0000000
    -Binary files a/tools/droiddoc/templates-sdk-dev/assets/images/icon_download.jpg and /dev/null differ
    -diff --git a/tools/droiddoc/templates-sdk-dev/assets/images/icon_download2.jpg b/tools/droiddoc/templates-sdk-dev/assets/images/icon_download2.jpg
    -deleted file mode 100755
    -index c0af7a2..0000000
    -Binary files a/tools/droiddoc/templates-sdk-dev/assets/images/icon_download2.jpg and /dev/null differ
    -diff --git a/tools/droiddoc/templates-sdk-dev/assets/images/icon_guidelines_logo.png b/tools/droiddoc/templates-sdk-dev/assets/images/icon_guidelines_logo.png
    -deleted file mode 100644
    -index 9362c8f..0000000
    -Binary files a/tools/droiddoc/templates-sdk-dev/assets/images/icon_guidelines_logo.png and /dev/null differ
    -diff --git a/tools/droiddoc/templates-sdk-dev/assets/images/icon_market.jpg b/tools/droiddoc/templates-sdk-dev/assets/images/icon_market.jpg
    -deleted file mode 100644
    -index 0fbb197..0000000
    -Binary files a/tools/droiddoc/templates-sdk-dev/assets/images/icon_market.jpg and /dev/null differ
    -diff --git a/tools/droiddoc/templates-sdk-dev/assets/images/icon_more.png b/tools/droiddoc/templates-sdk-dev/assets/images/icon_more.png
    -deleted file mode 100644
    -index 6cd03a3..0000000
    -Binary files a/tools/droiddoc/templates-sdk-dev/assets/images/icon_more.png and /dev/null differ
    -diff --git a/tools/droiddoc/templates-sdk-dev/assets/images/icon_play.png b/tools/droiddoc/templates-sdk-dev/assets/images/icon_play.png
    -deleted file mode 100644
    -index 8bfdc7b..0000000
    -Binary files a/tools/droiddoc/templates-sdk-dev/assets/images/icon_play.png and /dev/null differ
    -diff --git a/tools/droiddoc/templates-sdk-dev/assets/images/icon_robot.jpg b/tools/droiddoc/templates-sdk-dev/assets/images/icon_robot.jpg
    -deleted file mode 100755
    -index ca0fd39..0000000
    -Binary files a/tools/droiddoc/templates-sdk-dev/assets/images/icon_robot.jpg and /dev/null differ
    -diff --git a/tools/droiddoc/templates-sdk-dev/assets/images/icon_search.png b/tools/droiddoc/templates-sdk-dev/assets/images/icon_search.png
    -deleted file mode 100644
    -index ee90a12..0000000
    -Binary files a/tools/droiddoc/templates-sdk-dev/assets/images/icon_search.png and /dev/null differ
    -diff --git a/tools/droiddoc/templates-sdk-dev/assets/images/icon_world.jpg b/tools/droiddoc/templates-sdk-dev/assets/images/icon_world.jpg
    -deleted file mode 100755
    -index 65b8fa6..0000000
    -Binary files a/tools/droiddoc/templates-sdk-dev/assets/images/icon_world.jpg and /dev/null differ
    -diff --git a/tools/droiddoc/templates-sdk-dev/assets/images/left_off.jpg b/tools/droiddoc/templates-sdk-dev/assets/images/left_off.jpg
    -deleted file mode 100755
    -index fd32a64..0000000
    -Binary files a/tools/droiddoc/templates-sdk-dev/assets/images/left_off.jpg and /dev/null differ
    -diff --git a/tools/droiddoc/templates-sdk-dev/assets/images/left_on.jpg b/tools/droiddoc/templates-sdk-dev/assets/images/left_on.jpg
    -deleted file mode 100755
    -index 143184b..0000000
    -Binary files a/tools/droiddoc/templates-sdk-dev/assets/images/left_on.jpg and /dev/null differ
    -diff --git a/tools/droiddoc/templates-sdk-dev/assets/images/link-out.png b/tools/droiddoc/templates-sdk-dev/assets/images/link-out.png
    -deleted file mode 100644
    -index aa55f9a..0000000
    -Binary files a/tools/droiddoc/templates-sdk-dev/assets/images/link-out.png and /dev/null differ
    -diff --git a/tools/droiddoc/templates-sdk-dev/assets/images/locale.png b/tools/droiddoc/templates-sdk-dev/assets/images/locale.png
    -deleted file mode 100644
    -index de3aae7..0000000
    -Binary files a/tools/droiddoc/templates-sdk-dev/assets/images/locale.png and /dev/null differ
    -diff --git a/tools/droiddoc/templates-sdk-dev/assets/images/logo_breadcrumbz.jpg b/tools/droiddoc/templates-sdk-dev/assets/images/logo_breadcrumbz.jpg
    -deleted file mode 100755
    -index e743f86..0000000
    -Binary files a/tools/droiddoc/templates-sdk-dev/assets/images/logo_breadcrumbz.jpg and /dev/null differ
    -diff --git a/tools/droiddoc/templates-sdk-dev/assets/images/more_bottom.png b/tools/droiddoc/templates-sdk-dev/assets/images/more_bottom.png
    -deleted file mode 100644
    -index 632546a..0000000
    -Binary files a/tools/droiddoc/templates-sdk-dev/assets/images/more_bottom.png and /dev/null differ
    -diff --git a/tools/droiddoc/templates-sdk-dev/assets/images/more_check.png b/tools/droiddoc/templates-sdk-dev/assets/images/more_check.png
    -deleted file mode 100644
    -index f2fcbfc..0000000
    -Binary files a/tools/droiddoc/templates-sdk-dev/assets/images/more_check.png and /dev/null differ
    -diff --git a/tools/droiddoc/templates-sdk-dev/assets/images/more_mid.png b/tools/droiddoc/templates-sdk-dev/assets/images/more_mid.png
    -deleted file mode 100644
    -index 99bc999..0000000
    -Binary files a/tools/droiddoc/templates-sdk-dev/assets/images/more_mid.png and /dev/null differ
    -diff --git a/tools/droiddoc/templates-sdk-dev/assets/images/more_top.png b/tools/droiddoc/templates-sdk-dev/assets/images/more_top.png
    -deleted file mode 100644
    -index 8ead1d3..0000000
    -Binary files a/tools/droiddoc/templates-sdk-dev/assets/images/more_top.png and /dev/null differ
    -diff --git a/tools/droiddoc/templates-sdk-dev/assets/images/open_source.png b/tools/droiddoc/templates-sdk-dev/assets/images/open_source.png
    -deleted file mode 100755
    -index 12bb1fb..0000000
    -Binary files a/tools/droiddoc/templates-sdk-dev/assets/images/open_source.png and /dev/null differ
    -diff --git a/tools/droiddoc/templates-sdk-dev/assets/images/preliminary.png b/tools/droiddoc/templates-sdk-dev/assets/images/preliminary.png
    -deleted file mode 100644
    -index fe0da3d..0000000
    -Binary files a/tools/droiddoc/templates-sdk-dev/assets/images/preliminary.png and /dev/null differ
    -diff --git a/tools/droiddoc/templates-sdk-dev/assets/images/preview.png b/tools/droiddoc/templates-sdk-dev/assets/images/preview.png
    -deleted file mode 100644
    -index e5856db..0000000
    -Binary files a/tools/droiddoc/templates-sdk-dev/assets/images/preview.png and /dev/null differ
    -diff --git a/tools/droiddoc/templates-sdk-dev/assets/images/quicknav_arrow.png b/tools/droiddoc/templates-sdk-dev/assets/images/quicknav_arrow.png
    -deleted file mode 100644
    -index 697ac82..0000000
    -Binary files a/tools/droiddoc/templates-sdk-dev/assets/images/quicknav_arrow.png and /dev/null differ
    -diff --git a/tools/droiddoc/templates-sdk-dev/assets/images/quicknav_btn_bg.png b/tools/droiddoc/templates-sdk-dev/assets/images/quicknav_btn_bg.png
    -deleted file mode 100644
    -index b80c9a8..0000000
    -Binary files a/tools/droiddoc/templates-sdk-dev/assets/images/quicknav_btn_bg.png and /dev/null differ
    -diff --git a/tools/droiddoc/templates-sdk-dev/assets/images/resizable-e.gif b/tools/droiddoc/templates-sdk-dev/assets/images/resizable-e.gif
    -deleted file mode 100755
    -index f748097..0000000
    -Binary files a/tools/droiddoc/templates-sdk-dev/assets/images/resizable-e.gif and /dev/null differ
    -diff --git a/tools/droiddoc/templates-sdk-dev/assets/images/resizable-e2.gif b/tools/droiddoc/templates-sdk-dev/assets/images/resizable-e2.gif
    -deleted file mode 100755
    -index e45d0c5..0000000
    -Binary files a/tools/droiddoc/templates-sdk-dev/assets/images/resizable-e2.gif and /dev/null differ
    -diff --git a/tools/droiddoc/templates-sdk-dev/assets/images/resizable-eg.gif b/tools/droiddoc/templates-sdk-dev/assets/images/resizable-eg.gif
    -deleted file mode 100755
    -index 6196616..0000000
    -Binary files a/tools/droiddoc/templates-sdk-dev/assets/images/resizable-eg.gif and /dev/null differ
    -diff --git a/tools/droiddoc/templates-sdk-dev/assets/images/resizable-s.gif b/tools/droiddoc/templates-sdk-dev/assets/images/resizable-s.gif
    -deleted file mode 100755
    -index 7f6a4eb..0000000
    -Binary files a/tools/droiddoc/templates-sdk-dev/assets/images/resizable-s.gif and /dev/null differ
    -diff --git a/tools/droiddoc/templates-sdk-dev/assets/images/resizable-s2.gif b/tools/droiddoc/templates-sdk-dev/assets/images/resizable-s2.gif
    -deleted file mode 100755
    -index 99e869c..0000000
    -Binary files a/tools/droiddoc/templates-sdk-dev/assets/images/resizable-s2.gif and /dev/null differ
    -diff --git a/tools/droiddoc/templates-sdk-dev/assets/images/resizable-s2.png b/tools/droiddoc/templates-sdk-dev/assets/images/resizable-s2.png
    -deleted file mode 100644
    -index f3a6d2d..0000000
    -Binary files a/tools/droiddoc/templates-sdk-dev/assets/images/resizable-s2.png and /dev/null differ
    -diff --git a/tools/droiddoc/templates-sdk-dev/assets/images/resizable-sg.gif b/tools/droiddoc/templates-sdk-dev/assets/images/resizable-sg.gif
    -deleted file mode 100755
    -index b4bea10..0000000
    -Binary files a/tools/droiddoc/templates-sdk-dev/assets/images/resizable-sg.gif and /dev/null differ
    -diff --git a/tools/droiddoc/templates-sdk-dev/assets/images/resource-article.png b/tools/droiddoc/templates-sdk-dev/assets/images/resource-article.png
    -deleted file mode 100644
    -index 416493f..0000000
    -Binary files a/tools/droiddoc/templates-sdk-dev/assets/images/resource-article.png and /dev/null differ
    -diff --git a/tools/droiddoc/templates-sdk-dev/assets/images/resource-big-article.png b/tools/droiddoc/templates-sdk-dev/assets/images/resource-big-article.png
    -deleted file mode 100644
    -index 7273275..0000000
    -Binary files a/tools/droiddoc/templates-sdk-dev/assets/images/resource-big-article.png and /dev/null differ
    -diff --git a/tools/droiddoc/templates-sdk-dev/assets/images/resource-big-sample.png b/tools/droiddoc/templates-sdk-dev/assets/images/resource-big-sample.png
    -deleted file mode 100644
    -index 59b6b68..0000000
    -Binary files a/tools/droiddoc/templates-sdk-dev/assets/images/resource-big-sample.png and /dev/null differ
    -diff --git a/tools/droiddoc/templates-sdk-dev/assets/images/resource-big-tutorial.png b/tools/droiddoc/templates-sdk-dev/assets/images/resource-big-tutorial.png
    -deleted file mode 100644
    -index c32e89a..0000000
    -Binary files a/tools/droiddoc/templates-sdk-dev/assets/images/resource-big-tutorial.png and /dev/null differ
    -diff --git a/tools/droiddoc/templates-sdk-dev/assets/images/resource-big-video.png b/tools/droiddoc/templates-sdk-dev/assets/images/resource-big-video.png
    -deleted file mode 100644
    -index 59d46a0..0000000
    -Binary files a/tools/droiddoc/templates-sdk-dev/assets/images/resource-big-video.png and /dev/null differ
    -diff --git a/tools/droiddoc/templates-sdk-dev/assets/images/resource-card-default-android.jpg b/tools/droiddoc/templates-sdk-dev/assets/images/resource-card-default-android.jpg
    -deleted file mode 100644
    -index 398030f..0000000
    -Binary files a/tools/droiddoc/templates-sdk-dev/assets/images/resource-card-default-android.jpg and /dev/null differ
    -diff --git a/tools/droiddoc/templates-sdk-dev/assets/images/resource-sample.png b/tools/droiddoc/templates-sdk-dev/assets/images/resource-sample.png
    -deleted file mode 100644
    -index f7a411c..0000000
    -Binary files a/tools/droiddoc/templates-sdk-dev/assets/images/resource-sample.png and /dev/null differ
    -diff --git a/tools/droiddoc/templates-sdk-dev/assets/images/resource-tutorial.png b/tools/droiddoc/templates-sdk-dev/assets/images/resource-tutorial.png
    -deleted file mode 100644
    -index 10a14fe..0000000
    -Binary files a/tools/droiddoc/templates-sdk-dev/assets/images/resource-tutorial.png and /dev/null differ
    -diff --git a/tools/droiddoc/templates-sdk-dev/assets/images/resource-video.png b/tools/droiddoc/templates-sdk-dev/assets/images/resource-video.png
    -deleted file mode 100644
    -index 8fd5cae..0000000
    -Binary files a/tools/droiddoc/templates-sdk-dev/assets/images/resource-video.png and /dev/null differ
    -diff --git a/tools/droiddoc/templates-sdk-dev/assets/images/right_off.jpg b/tools/droiddoc/templates-sdk-dev/assets/images/right_off.jpg
    -deleted file mode 100755
    -index 17d2efe..0000000
    -Binary files a/tools/droiddoc/templates-sdk-dev/assets/images/right_off.jpg and /dev/null differ
    -diff --git a/tools/droiddoc/templates-sdk-dev/assets/images/right_on.jpg b/tools/droiddoc/templates-sdk-dev/assets/images/right_on.jpg
    -deleted file mode 100755
    -index baa2af1..0000000
    -Binary files a/tools/droiddoc/templates-sdk-dev/assets/images/right_on.jpg and /dev/null differ
    -diff --git a/tools/droiddoc/templates-sdk-dev/assets/images/sidenav-rule.png b/tools/droiddoc/templates-sdk-dev/assets/images/sidenav-rule.png
    -deleted file mode 100644
    -index eab9920..0000000
    -Binary files a/tools/droiddoc/templates-sdk-dev/assets/images/sidenav-rule.png and /dev/null differ
    -diff --git a/tools/droiddoc/templates-sdk-dev/assets/images/slide_1.jpg b/tools/droiddoc/templates-sdk-dev/assets/images/slide_1.jpg
    -deleted file mode 100755
    -index 6d75be1..0000000
    -Binary files a/tools/droiddoc/templates-sdk-dev/assets/images/slide_1.jpg and /dev/null differ
    -diff --git a/tools/droiddoc/templates-sdk-dev/assets/images/slide_2.jpg b/tools/droiddoc/templates-sdk-dev/assets/images/slide_2.jpg
    -deleted file mode 100755
    -index aa994c2..0000000
    -Binary files a/tools/droiddoc/templates-sdk-dev/assets/images/slide_2.jpg and /dev/null differ
    -diff --git a/tools/droiddoc/templates-sdk-dev/assets/images/slide_3.jpg b/tools/droiddoc/templates-sdk-dev/assets/images/slide_3.jpg
    -deleted file mode 100755
    -index b04deb3..0000000
    -Binary files a/tools/droiddoc/templates-sdk-dev/assets/images/slide_3.jpg and /dev/null differ
    -diff --git a/tools/droiddoc/templates-sdk-dev/assets/images/slide_large_1.jpg b/tools/droiddoc/templates-sdk-dev/assets/images/slide_large_1.jpg
    -deleted file mode 100755
    -index a992e92..0000000
    -Binary files a/tools/droiddoc/templates-sdk-dev/assets/images/slide_large_1.jpg and /dev/null differ
    -diff --git a/tools/droiddoc/templates-sdk-dev/assets/images/slide_large_2.jpg b/tools/droiddoc/templates-sdk-dev/assets/images/slide_large_2.jpg
    -deleted file mode 100755
    -index 9af63f4..0000000
    -Binary files a/tools/droiddoc/templates-sdk-dev/assets/images/slide_large_2.jpg and /dev/null differ
    -diff --git a/tools/droiddoc/templates-sdk-dev/assets/images/slide_large_3.jpg b/tools/droiddoc/templates-sdk-dev/assets/images/slide_large_3.jpg
    -deleted file mode 100755
    -index fcf236c..0000000
    -Binary files a/tools/droiddoc/templates-sdk-dev/assets/images/slide_large_3.jpg and /dev/null differ
    -diff --git a/tools/droiddoc/templates-sdk-dev/assets/images/slide_off.jpg b/tools/droiddoc/templates-sdk-dev/assets/images/slide_off.jpg
    -deleted file mode 100755
    -index 5971227..0000000
    -Binary files a/tools/droiddoc/templates-sdk-dev/assets/images/slide_off.jpg and /dev/null differ
    -diff --git a/tools/droiddoc/templates-sdk-dev/assets/images/slide_on.jpg b/tools/droiddoc/templates-sdk-dev/assets/images/slide_on.jpg
    -deleted file mode 100755
    -index 7ca3577..0000000
    -Binary files a/tools/droiddoc/templates-sdk-dev/assets/images/slide_on.jpg and /dev/null differ
    -diff --git a/tools/droiddoc/templates-sdk-dev/assets/images/spacer.gif b/tools/droiddoc/templates-sdk-dev/assets/images/spacer.gif
    -deleted file mode 100755
    -index f96b355..0000000
    -Binary files a/tools/droiddoc/templates-sdk-dev/assets/images/spacer.gif and /dev/null differ
    -diff --git a/tools/droiddoc/templates-sdk-dev/assets/images/sprite-2x.png b/tools/droiddoc/templates-sdk-dev/assets/images/sprite-2x.png
    -deleted file mode 100644
    -index 185b7e8..0000000
    -Binary files a/tools/droiddoc/templates-sdk-dev/assets/images/sprite-2x.png and /dev/null differ
    -diff --git a/tools/droiddoc/templates-sdk-dev/assets/images/sprite.png b/tools/droiddoc/templates-sdk-dev/assets/images/sprite.png
    -deleted file mode 100644
    -index 562b23c..0000000
    -Binary files a/tools/droiddoc/templates-sdk-dev/assets/images/sprite.png and /dev/null differ
    -diff --git a/tools/droiddoc/templates-sdk-dev/assets/images/sprite@2x.png b/tools/droiddoc/templates-sdk-dev/assets/images/sprite@2x.png
    -deleted file mode 100644
    -index 2019e02..0000000
    -Binary files a/tools/droiddoc/templates-sdk-dev/assets/images/sprite@2x.png and /dev/null differ
    -diff --git a/tools/droiddoc/templates-sdk-dev/assets/images/stack-arrow-right.png b/tools/droiddoc/templates-sdk-dev/assets/images/stack-arrow-right.png
    -deleted file mode 100644
    -index 46d6a50..0000000
    -Binary files a/tools/droiddoc/templates-sdk-dev/assets/images/stack-arrow-right.png and /dev/null differ
    -diff --git a/tools/droiddoc/templates-sdk-dev/assets/images/styles/callout.png b/tools/droiddoc/templates-sdk-dev/assets/images/styles/callout.png
    -deleted file mode 100644
    -index 5d49f34..0000000
    -Binary files a/tools/droiddoc/templates-sdk-dev/assets/images/styles/callout.png and /dev/null differ
    -diff --git a/tools/droiddoc/templates-sdk-dev/assets/images/styles/device_galaxynexus_blank_land_span13.png b/tools/droiddoc/templates-sdk-dev/assets/images/styles/device_galaxynexus_blank_land_span13.png
    -deleted file mode 100644
    -index bab6aca..0000000
    -Binary files a/tools/droiddoc/templates-sdk-dev/assets/images/styles/device_galaxynexus_blank_land_span13.png and /dev/null differ
    -diff --git a/tools/droiddoc/templates-sdk-dev/assets/images/styles/device_galaxynexus_blank_land_span8.png b/tools/droiddoc/templates-sdk-dev/assets/images/styles/device_galaxynexus_blank_land_span8.png
    -deleted file mode 100644
    -index cb180bf..0000000
    -Binary files a/tools/droiddoc/templates-sdk-dev/assets/images/styles/device_galaxynexus_blank_land_span8.png and /dev/null differ
    -diff --git a/tools/droiddoc/templates-sdk-dev/assets/images/styles/device_galaxynexus_blank_port_span5.png b/tools/droiddoc/templates-sdk-dev/assets/images/styles/device_galaxynexus_blank_port_span5.png
    -deleted file mode 100644
    -index bdccc2f..0000000
    -Binary files a/tools/droiddoc/templates-sdk-dev/assets/images/styles/device_galaxynexus_blank_port_span5.png and /dev/null differ
    -diff --git a/tools/droiddoc/templates-sdk-dev/assets/images/styles/device_galaxynexus_blank_port_span9.png b/tools/droiddoc/templates-sdk-dev/assets/images/styles/device_galaxynexus_blank_port_span9.png
    -deleted file mode 100644
    -index 5e0135b..0000000
    -Binary files a/tools/droiddoc/templates-sdk-dev/assets/images/styles/device_galaxynexus_blank_port_span9.png and /dev/null differ
    -diff --git a/tools/droiddoc/templates-sdk-dev/assets/images/styles/device_nexus4_blank_port_432.png b/tools/droiddoc/templates-sdk-dev/assets/images/styles/device_nexus4_blank_port_432.png
    -deleted file mode 100644
    -index 9d41aa3..0000000
    -Binary files a/tools/droiddoc/templates-sdk-dev/assets/images/styles/device_nexus4_blank_port_432.png and /dev/null differ
    -diff --git a/tools/droiddoc/templates-sdk-dev/assets/images/styles/device_nexus5_blank_land_span13.png b/tools/droiddoc/templates-sdk-dev/assets/images/styles/device_nexus5_blank_land_span13.png
    -deleted file mode 100644
    -index 5d37121..0000000
    -Binary files a/tools/droiddoc/templates-sdk-dev/assets/images/styles/device_nexus5_blank_land_span13.png and /dev/null differ
    -diff --git a/tools/droiddoc/templates-sdk-dev/assets/images/styles/device_nexus5_blank_port_span5.png b/tools/droiddoc/templates-sdk-dev/assets/images/styles/device_nexus5_blank_port_span5.png
    -deleted file mode 100644
    -index df35117..0000000
    -Binary files a/tools/droiddoc/templates-sdk-dev/assets/images/styles/device_nexus5_blank_port_span5.png and /dev/null differ
    -diff --git a/tools/droiddoc/templates-sdk-dev/assets/images/styles/device_wear_square.png b/tools/droiddoc/templates-sdk-dev/assets/images/styles/device_wear_square.png
    -deleted file mode 100644
    -index 077a7e6..0000000
    -Binary files a/tools/droiddoc/templates-sdk-dev/assets/images/styles/device_wear_square.png and /dev/null differ
    -diff --git a/tools/droiddoc/templates-sdk-dev/assets/images/styles/device_wear_square_small.png b/tools/droiddoc/templates-sdk-dev/assets/images/styles/device_wear_square_small.png
    -deleted file mode 100644
    -index e7e1540..0000000
    -Binary files a/tools/droiddoc/templates-sdk-dev/assets/images/styles/device_wear_square_small.png and /dev/null differ
    -diff --git a/tools/droiddoc/templates-sdk-dev/assets/images/styles/disclosure_down.png b/tools/droiddoc/templates-sdk-dev/assets/images/styles/disclosure_down.png
    -deleted file mode 100644
    -index 6a0a8ee..0000000
    -Binary files a/tools/droiddoc/templates-sdk-dev/assets/images/styles/disclosure_down.png and /dev/null differ
    -diff --git a/tools/droiddoc/templates-sdk-dev/assets/images/styles/disclosure_left.png b/tools/droiddoc/templates-sdk-dev/assets/images/styles/disclosure_left.png
    -deleted file mode 100644
    -index e887b2a..0000000
    -Binary files a/tools/droiddoc/templates-sdk-dev/assets/images/styles/disclosure_left.png and /dev/null differ
    -diff --git a/tools/droiddoc/templates-sdk-dev/assets/images/styles/disclosure_right.png b/tools/droiddoc/templates-sdk-dev/assets/images/styles/disclosure_right.png
    -deleted file mode 100644
    -index ced7fa4..0000000
    -Binary files a/tools/droiddoc/templates-sdk-dev/assets/images/styles/disclosure_right.png and /dev/null differ
    -diff --git a/tools/droiddoc/templates-sdk-dev/assets/images/styles/disclosure_up.png b/tools/droiddoc/templates-sdk-dev/assets/images/styles/disclosure_up.png
    -deleted file mode 100644
    -index ddd4ec9..0000000
    -Binary files a/tools/droiddoc/templates-sdk-dev/assets/images/styles/disclosure_up.png and /dev/null differ
    -diff --git a/tools/droiddoc/templates-sdk-dev/assets/images/styles/gototop.png b/tools/droiddoc/templates-sdk-dev/assets/images/styles/gototop.png
    -deleted file mode 100644
    -index 5f09a29..0000000
    -Binary files a/tools/droiddoc/templates-sdk-dev/assets/images/styles/gototop.png and /dev/null differ
    -diff --git a/tools/droiddoc/templates-sdk-dev/assets/images/styles/helpouts-logo-35.png b/tools/droiddoc/templates-sdk-dev/assets/images/styles/helpouts-logo-35.png
    -deleted file mode 100644
    -index 3c2dc1a..0000000
    -Binary files a/tools/droiddoc/templates-sdk-dev/assets/images/styles/helpouts-logo-35.png and /dev/null differ
    -diff --git a/tools/droiddoc/templates-sdk-dev/assets/images/styles/helpouts-logo-35_2x.png b/tools/droiddoc/templates-sdk-dev/assets/images/styles/helpouts-logo-35_2x.png
    -deleted file mode 100644
    -index e34be2e..0000000
    -Binary files a/tools/droiddoc/templates-sdk-dev/assets/images/styles/helpouts-logo-35_2x.png and /dev/null differ
    -diff --git a/tools/droiddoc/templates-sdk-dev/assets/images/styles/ico_action.png b/tools/droiddoc/templates-sdk-dev/assets/images/styles/ico_action.png
    -deleted file mode 100644
    -index 30e4cc7..0000000
    -Binary files a/tools/droiddoc/templates-sdk-dev/assets/images/styles/ico_action.png and /dev/null differ
    -diff --git a/tools/droiddoc/templates-sdk-dev/assets/images/styles/ico_good.png b/tools/droiddoc/templates-sdk-dev/assets/images/styles/ico_good.png
    -deleted file mode 100644
    -index afebe1c..0000000
    -Binary files a/tools/droiddoc/templates-sdk-dev/assets/images/styles/ico_good.png and /dev/null differ
    -diff --git a/tools/droiddoc/templates-sdk-dev/assets/images/styles/ico_movie_inline.png b/tools/droiddoc/templates-sdk-dev/assets/images/styles/ico_movie_inline.png
    -deleted file mode 100644
    -index 7cfb5c5..0000000
    -Binary files a/tools/droiddoc/templates-sdk-dev/assets/images/styles/ico_movie_inline.png and /dev/null differ
    -diff --git a/tools/droiddoc/templates-sdk-dev/assets/images/styles/ico_phone_tablet.png b/tools/droiddoc/templates-sdk-dev/assets/images/styles/ico_phone_tablet.png
    -deleted file mode 100644
    -index 003b876..0000000
    -Binary files a/tools/droiddoc/templates-sdk-dev/assets/images/styles/ico_phone_tablet.png and /dev/null differ
    -diff --git a/tools/droiddoc/templates-sdk-dev/assets/images/styles/ico_use.png b/tools/droiddoc/templates-sdk-dev/assets/images/styles/ico_use.png
    -deleted file mode 100644
    -index 9d868b3..0000000
    -Binary files a/tools/droiddoc/templates-sdk-dev/assets/images/styles/ico_use.png and /dev/null differ
    -diff --git a/tools/droiddoc/templates-sdk-dev/assets/images/styles/ico_web.png b/tools/droiddoc/templates-sdk-dev/assets/images/styles/ico_web.png
    -deleted file mode 100644
    -index 0848e3c..0000000
    -Binary files a/tools/droiddoc/templates-sdk-dev/assets/images/styles/ico_web.png and /dev/null differ
    -diff --git a/tools/droiddoc/templates-sdk-dev/assets/images/styles/ico_wrong.png b/tools/droiddoc/templates-sdk-dev/assets/images/styles/ico_wrong.png
    -deleted file mode 100644
    -index b7d04ce..0000000
    -Binary files a/tools/droiddoc/templates-sdk-dev/assets/images/styles/ico_wrong.png and /dev/null differ
    -diff --git a/tools/droiddoc/templates-sdk-dev/assets/images/styles/notice-designers-video.png b/tools/droiddoc/templates-sdk-dev/assets/images/styles/notice-designers-video.png
    -deleted file mode 100644
    -index eea3485..0000000
    -Binary files a/tools/droiddoc/templates-sdk-dev/assets/images/styles/notice-designers-video.png and /dev/null differ
    -diff --git a/tools/droiddoc/templates-sdk-dev/assets/images/styles/notice-designers-video@2x.png b/tools/droiddoc/templates-sdk-dev/assets/images/styles/notice-designers-video@2x.png
    -deleted file mode 100644
    -index a5fdae3..0000000
    -Binary files a/tools/droiddoc/templates-sdk-dev/assets/images/styles/notice-designers-video@2x.png and /dev/null differ
    -diff --git a/tools/droiddoc/templates-sdk-dev/assets/images/styles/notice-designers.png b/tools/droiddoc/templates-sdk-dev/assets/images/styles/notice-designers.png
    -deleted file mode 100644
    -index 1fb22a2..0000000
    -Binary files a/tools/droiddoc/templates-sdk-dev/assets/images/styles/notice-designers.png and /dev/null differ
    -diff --git a/tools/droiddoc/templates-sdk-dev/assets/images/styles/notice-designers@2x.png b/tools/droiddoc/templates-sdk-dev/assets/images/styles/notice-designers@2x.png
    -deleted file mode 100644
    -index bc2f74b..0000000
    -Binary files a/tools/droiddoc/templates-sdk-dev/assets/images/styles/notice-designers@2x.png and /dev/null differ
    -diff --git a/tools/droiddoc/templates-sdk-dev/assets/images/styles/notice-developers-video.png b/tools/droiddoc/templates-sdk-dev/assets/images/styles/notice-developers-video.png
    -deleted file mode 100644
    -index e9f8ed2..0000000
    -Binary files a/tools/droiddoc/templates-sdk-dev/assets/images/styles/notice-developers-video.png and /dev/null differ
    -diff --git a/tools/droiddoc/templates-sdk-dev/assets/images/styles/notice-developers-video@2x.png b/tools/droiddoc/templates-sdk-dev/assets/images/styles/notice-developers-video@2x.png
    -deleted file mode 100644
    -index c067ac1..0000000
    -Binary files a/tools/droiddoc/templates-sdk-dev/assets/images/styles/notice-developers-video@2x.png and /dev/null differ
    -diff --git a/tools/droiddoc/templates-sdk-dev/assets/images/styles/notice-developers.png b/tools/droiddoc/templates-sdk-dev/assets/images/styles/notice-developers.png
    -deleted file mode 100644
    -index a29c31a..0000000
    -Binary files a/tools/droiddoc/templates-sdk-dev/assets/images/styles/notice-developers.png and /dev/null differ
    -diff --git a/tools/droiddoc/templates-sdk-dev/assets/images/styles/notice-developers@2x.png b/tools/droiddoc/templates-sdk-dev/assets/images/styles/notice-developers@2x.png
    -deleted file mode 100644
    -index d42f537..0000000
    -Binary files a/tools/droiddoc/templates-sdk-dev/assets/images/styles/notice-developers@2x.png and /dev/null differ
    -diff --git a/tools/droiddoc/templates-sdk-dev/assets/images/styles/open_new_page.png b/tools/droiddoc/templates-sdk-dev/assets/images/styles/open_new_page.png
    -deleted file mode 100644
    -index 6197e3a..0000000
    -Binary files a/tools/droiddoc/templates-sdk-dev/assets/images/styles/open_new_page.png and /dev/null differ
    -diff --git a/tools/droiddoc/templates-sdk-dev/assets/images/triangle-closed-small.png b/tools/droiddoc/templates-sdk-dev/assets/images/triangle-closed-small.png
    -deleted file mode 100644
    -index 002364a..0000000
    -Binary files a/tools/droiddoc/templates-sdk-dev/assets/images/triangle-closed-small.png and /dev/null differ
    -diff --git a/tools/droiddoc/templates-sdk-dev/assets/images/triangle-closed.png b/tools/droiddoc/templates-sdk-dev/assets/images/triangle-closed.png
    -deleted file mode 100644
    -index 40a68d9..0000000
    -Binary files a/tools/droiddoc/templates-sdk-dev/assets/images/triangle-closed.png and /dev/null differ
    -diff --git a/tools/droiddoc/templates-sdk-dev/assets/images/triangle-opened-small.png b/tools/droiddoc/templates-sdk-dev/assets/images/triangle-opened-small.png
    -deleted file mode 100644
    -index e1eb784..0000000
    -Binary files a/tools/droiddoc/templates-sdk-dev/assets/images/triangle-opened-small.png and /dev/null differ
    -diff --git a/tools/droiddoc/templates-sdk-dev/assets/images/triangle-opened.png b/tools/droiddoc/templates-sdk-dev/assets/images/triangle-opened.png
    -deleted file mode 100644
    -index 789f5fa..0000000
    -Binary files a/tools/droiddoc/templates-sdk-dev/assets/images/triangle-opened.png and /dev/null differ
    -diff --git a/tools/droiddoc/templates-sdk-dev/assets/images/uiguidelines1.png b/tools/droiddoc/templates-sdk-dev/assets/images/uiguidelines1.png
    -deleted file mode 100644
    -index 5ce1611..0000000
    -Binary files a/tools/droiddoc/templates-sdk-dev/assets/images/uiguidelines1.png and /dev/null differ
    -diff --git a/tools/droiddoc/templates-sdk-dev/assets/images/video-droid.png b/tools/droiddoc/templates-sdk-dev/assets/images/video-droid.png
    -deleted file mode 100644
    -index 25163b6..0000000
    -Binary files a/tools/droiddoc/templates-sdk-dev/assets/images/video-droid.png and /dev/null differ
    -diff --git a/tools/droiddoc/templates-sdk-dev/assets/js/android_3p-bundle.js b/tools/droiddoc/templates-sdk-dev/assets/js/android_3p-bundle.js
    -deleted file mode 100644
    -index 70d6c2f..0000000
    ---- a/tools/droiddoc/templates-sdk-dev/assets/js/android_3p-bundle.js
    -+++ /dev/null
    -@@ -1,2772 +0,0 @@
    --//third_party/javascript/google_code_prettify/src/prettify.js
    --/**
    -- * @license Copyright (C) 2006 Google Inc.
    -- *
    -- * 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.
    -- */
    --
    --/**
    -- * @fileoverview
    -- * some functions for browser-side pretty printing of code contained in html.
    -- * <p>
    -- *
    -- * For a fairly comprehensive set of languages see the
    -- * <a href="http://google-code-prettify.googlecode.com/svn/trunk/README.html#langs">README</a>
    -- * file that came with this source.  At a minimum, the lexer should work on a
    -- * number of languages including C and friends, Java, Python, Bash, SQL, HTML,
    -- * XML, CSS, Javascript, and Makefiles.  It works passably on Ruby, PHP and Awk
    -- * and a subset of Perl, but, because of commenting conventions, doesn't work on
    -- * Smalltalk, Lisp-like, or CAML-like languages without an explicit lang class.
    -- * <p>
    -- * Usage: <ol>
    -- * <li> include this source file in an html page via
    -- *   {@code <script type="text/javascript" src="/path/to/prettify.js"></script>}
    -- * <li> define style rules.  See the example page for examples.
    -- * <li> mark the {@code <pre>} and {@code <code>} tags in your source with
    -- *    {@code class=prettyprint.}
    -- *    You can also use the (html deprecated) {@code <xmp>} tag, but the pretty
    -- *    printer needs to do more substantial DOM manipulations to support that, so
    -- *    some css styles may not be preserved.
    -- * </ol>
    -- * That's it.  I wanted to keep the API as simple as possible, so there's no
    -- * need to specify which language the code is in, but if you wish, you can add
    -- * another class to the {@code <pre>} or {@code <code>} element to specify the
    -- * language, as in {@code <pre class="prettyprint lang-java">}.  Any class that
    -- * starts with "lang-" followed by a file extension, specifies the file type.
    -- * See the "lang-*.js" files in this directory for code that implements
    -- * per-language file handlers.
    -- * <p>
    -- * Change log:<br>
    -- * cbeust, 2006/08/22
    -- * <blockquote>
    -- *   Java annotations (start with "@") are now captured as literals ("lit")
    -- * </blockquote>
    -- * @requires console
    -- */
    --
    --// JSLint declarations
    --/*global console, document, navigator, setTimeout, window */
    --
    --/**
    -- * Split {@code prettyPrint} into multiple timeouts so as not to interfere with
    -- * UI events.
    -- * If set to {@code false}, {@code prettyPrint()} is synchronous.
    -- */
    --window['PR_SHOULD_USE_CONTINUATION'] = true;
    --
    --/** the number of characters between tab columns */
    --window['PR_TAB_WIDTH'] = 8;
    --
    --/** Walks the DOM returning a properly escaped version of innerHTML.
    --  * @param {Node} node
    --  * @param {Array.<string>} out output buffer that receives chunks of HTML.
    --  */
    --window['PR_normalizedHtml']
    --
    --/** Contains functions for creating and registering new language handlers.
    --  * @type {Object}
    --  */
    --  = window['PR']
    --
    --/** Pretty print a chunk of code.
    --  *
    --  * @param {string} sourceCodeHtml code as html
    --  * @return {string} code as html, but prettier
    --  */
    --  = window['prettyPrintOne']
    --/** Find all the {@code <pre>} and {@code <code>} tags in the DOM with
    --  * {@code class=prettyprint} and prettify them.
    --  * @param {Function?} opt_whenDone if specified, called when the last entry
    --  *     has been finished.
    --  */
    --  = window['prettyPrint'] = void 0;
    --
    --/** browser detection. @extern @returns false if not IE, otherwise the major version. */
    --window['_pr_isIE6'] = function () {
    --  var ieVersion = navigator && navigator.userAgent &&
    --      navigator.userAgent.match(/\bMSIE ([678])\./);
    --  ieVersion = ieVersion ? +ieVersion[1] : false;
    --  window['_pr_isIE6'] = function () { return ieVersion; };
    --  return ieVersion;
    --};
    --
    --
    --(function () {
    --  // Keyword lists for various languages.
    --  var FLOW_CONTROL_KEYWORDS =
    --      "break continue do else for if return while ";
    --  var C_KEYWORDS = FLOW_CONTROL_KEYWORDS + "auto case char const default " +
    --      "double enum extern float goto int long register short signed sizeof " +
    --      "static struct switch typedef union unsigned void volatile ";
    --  var COMMON_KEYWORDS = C_KEYWORDS + "catch class delete false import " +
    --      "new operator private protected public this throw true try typeof ";
    --  var CPP_KEYWORDS = COMMON_KEYWORDS + "alignof align_union asm axiom bool " +
    --      "concept concept_map const_cast constexpr decltype " +
    --      "dynamic_cast explicit export friend inline late_check " +
    --      "mutable namespace nullptr reinterpret_cast static_assert static_cast " +
    --      "template typeid typename using virtual wchar_t where ";
    --  var JAVA_KEYWORDS = COMMON_KEYWORDS +
    --      "abstract boolean byte extends final finally implements import " +
    --      "instanceof null native package strictfp super synchronized throws " +
    --      "transient ";
    --  var CSHARP_KEYWORDS = JAVA_KEYWORDS +
    --      "as base by checked decimal delegate descending dynamic event " +
    --      "fixed foreach from group implicit in interface internal into is lock " +
    --      "object out override orderby params partial readonly ref sbyte sealed " +
    --      "stackalloc string select uint ulong unchecked unsafe ushort var ";
    --  var COFFEE_KEYWORDS = "all and by catch class else extends false finally " +
    --      "for if in is isnt loop new no not null of off on or return super then " +
    --      "true try unless until when while yes ";
    --  var JSCRIPT_KEYWORDS = COMMON_KEYWORDS +
    --      "debugger eval export function get null set undefined var with " +
    --      "Infinity NaN ";
    --  var PERL_KEYWORDS = "caller delete die do dump elsif eval exit foreach for " +
    --      "goto if import last local my next no our print package redo require " +
    --      "sub undef unless until use wantarray while BEGIN END ";
    --  var PYTHON_KEYWORDS = FLOW_CONTROL_KEYWORDS + "and as assert class def del " +
    --      "elif except exec finally from global import in is lambda " +
    --      "nonlocal not or pass print raise try with yield " +
    --      "False True None ";
    --  var RUBY_KEYWORDS = FLOW_CONTROL_KEYWORDS + "alias and begin case class def" +
    --      " defined elsif end ensure false in module next nil not or redo rescue " +
    --      "retry self super then true undef unless until when yield BEGIN END ";
    --  var SH_KEYWORDS = FLOW_CONTROL_KEYWORDS + "case done elif esac eval fi " +
    --      "function in local set then until ";
    --  var ALL_KEYWORDS = (
    --      CPP_KEYWORDS + CSHARP_KEYWORDS + JSCRIPT_KEYWORDS + PERL_KEYWORDS +
    --      PYTHON_KEYWORDS + RUBY_KEYWORDS + SH_KEYWORDS);
    --
    --  // token style names.  correspond to css classes
    --  /** token style for a string literal */
    --  var PR_STRING = 'str';
    --  /** token style for a keyword */
    --  var PR_KEYWORD = 'kwd';
    --  /** token style for a comment */
    --  var PR_COMMENT = 'com';
    --  /** token style for a type */
    --  var PR_TYPE = 'typ';
    --  /** token style for a literal value.  e.g. 1, null, true. */
    --  var PR_LITERAL = 'lit';
    --  /** token style for a punctuation string. */
    --  var PR_PUNCTUATION = 'pun';
    --  /** token style for a punctuation string. */
    --  var PR_PLAIN = 'pln';
    --
    --  /** token style for an sgml tag. */
    --  var PR_TAG = 'tag';
    --  /** token style for a markup declaration such as a DOCTYPE. */
    --  var PR_DECLARATION = 'dec';
    --  /** token style for embedded source. */
    --  var PR_SOURCE = 'src';
    --  /** token style for an sgml attribute name. */
    --  var PR_ATTRIB_NAME = 'atn';
    --  /** token style for an sgml attribute value. */
    --  var PR_ATTRIB_VALUE = 'atv';
    --
    --  /**
    --   * A class that indicates a section of markup that is not code, e.g. to allow
    --   * embedding of line numbers within code listings.
    --   */
    --  var PR_NOCODE = 'nocode';
    --
    --  /** A set of tokens that can precede a regular expression literal in
    --    * javascript.
    --    * http://www.mozilla.org/js/language/js20/rationale/syntax.html has the full
    --    * list, but I've removed ones that might be problematic when seen in
    --    * languages that don't support regular expression literals.
    --    *
    --    * <p>Specifically, I've removed any keywords that can't precede a regexp
    --    * literal in a syntactically legal javascript program, and I've removed the
    --    * "in" keyword since it's not a keyword in many languages, and might be used
    --    * as a count of inches.
    --    *
    --    * <p>The link a above does not accurately describe EcmaScript rules since
    --    * it fails to distinguish between (a=++/b/i) and (a++/b/i) but it works
    --    * very well in practice.
    --    *
    --    * @private
    --    */
    --  var REGEXP_PRECEDER_PATTERN = function () {
    --      var preceders = [
    --          "!", "!=", "!==", "#", "%", "%=", "&", "&&", "&&=",
    --          "&=", "(", "*", "*=", /* "+", */ "+=", ",", /* "-", */ "-=",
    --          "->", /*".", "..", "...", handled below */ "/", "/=", ":", "::", ";",
    --          "<", "<<", "<<=", "<=", "=", "==", "===", ">",
    --          ">=", ">>", ">>=", ">>>", ">>>=", "?", "@", "[",
    --          "^", "^=", "^^", "^^=", "{", "|", "|=", "||",
    --          "||=", "~" /* handles =~ and !~ */,
    --          "break", "case", "continue", "delete",
    --          "do", "else", "finally", "instanceof",
    --          "return", "throw", "try", "typeof"
    --          ];
    --      var pattern = '(?:^^|[+-]';
    --      for (var i = 0; i < preceders.length; ++i) {
    --        pattern += '|' + preceders[i].replace(/([^=<>:&a-z])/g, '\\$1');
    --      }
    --      pattern += ')\\s*';  // matches at end, and matches empty string
    --      return pattern;
    --      // CAVEAT: this does not properly handle the case where a regular
    --      // expression immediately follows another since a regular expression may
    --      // have flags for case-sensitivity and the like.  Having regexp tokens
    --      // adjacent is not valid in any language I'm aware of, so I'm punting.
    --      // TODO: maybe style special characters inside a regexp as punctuation.
    --    }();
    --
    --  // Define regexps here so that the interpreter doesn't have to create an
    --  // object each time the function containing them is called.
    --  // The language spec requires a new object created even if you don't access
    --  // the $1 members.
    --  var pr_amp = /&/g;
    --  var pr_lt = /</g;
    --  var pr_gt = />/g;
    --  var pr_quot = /\"/g;
    --  /** like textToHtml but escapes double quotes to be attribute safe. */
    --  function attribToHtml(str) {
    --    return str.replace(pr_amp, '&amp;')
    --        .replace(pr_lt, '&lt;')
    --        .replace(pr_gt, '&gt;')
    --        .replace(pr_quot, '&quot;');
    --  }
    --
    --  /** escapest html special characters to html. */
    --  function textToHtml(str) {
    --    return str.replace(pr_amp, '&amp;')
    --        .replace(pr_lt, '&lt;')
    --        .replace(pr_gt, '&gt;');
    --  }
    --
    --
    --  var pr_ltEnt = /&lt;/g;
    --  var pr_gtEnt = /&gt;/g;
    --  var pr_aposEnt = /&apos;/g;
    --  var pr_quotEnt = /&quot;/g;
    --  var pr_ampEnt = /&amp;/g;
    --  var pr_nbspEnt = /&nbsp;/g;
    --  /** unescapes html to plain text. */
    --  function htmlToText(html) {
    --    var pos = html.indexOf('&');
    --    if (pos < 0) { return html; }
    --    // Handle numeric entities specially.  We can't use functional substitution
    --    // since that doesn't work in older versions of Safari.
    --    // These should be rare since most browsers convert them to normal chars.
    --    for (--pos; (pos = html.indexOf('&#', pos + 1)) >= 0;) {
    --      var end = html.indexOf(';', pos);
    --      if (end >= 0) {
    --        var num = html.substring(pos + 3, end);
    --        var radix = 10;
    --        if (num && num.charAt(0) === 'x') {
    --          num = num.substring(1);
    --          radix = 16;
    --        }
    --        var codePoint = parseInt(num, radix);
    --        if (!isNaN(codePoint)) {
    --          html = (html.substring(0, pos) + String.fromCharCode(codePoint) +
    --                  html.substring(end + 1));
    --        }
    --      }
    --    }
    --
    --    return html.replace(pr_ltEnt, '<')
    --        .replace(pr_gtEnt, '>')
    --        .replace(pr_aposEnt, "'")
    --        .replace(pr_quotEnt, '"')
    --        .replace(pr_nbspEnt, ' ')
    --        .replace(pr_ampEnt, '&');
    --  }
    --
    --  /** is the given node's innerHTML normally unescaped? */
    --  function isRawContent(node) {
    --    return 'XMP' === node.tagName;
    --  }
    --
    --  var newlineRe = /[\r\n]/g;
    --  /**
    --   * Are newlines and adjacent spaces significant in the given node's innerHTML?
    --   */
    --  function isPreformatted(node, content) {
    --    // PRE means preformatted, and is a very common case, so don't create
    --    // unnecessary computed style objects.
    --    if ('PRE' === node.tagName) { return true; }
    --    if (!newlineRe.test(content)) { return true; }  // Don't care
    --    var whitespace = '';
    --    // For disconnected nodes, IE has no currentStyle.
    --    if (node.currentStyle) {
    --      whitespace = node.currentStyle.whiteSpace;
    --    } else if (window.getComputedStyle) {
    --      // Firefox makes a best guess if node is disconnected whereas Safari
    --      // returns the empty string.
    --      whitespace = window.getComputedStyle(node, null).whiteSpace;
    --    }
    --    return !whitespace || whitespace === 'pre';
    --  }
    --
    --  function normalizedHtml(node, out, opt_sortAttrs) {
    --    switch (node.nodeType) {
    --      case 1:  // an element
    --        var name = node.tagName.toLowerCase();
    --
    --        out.push('<', name);
    --        var attrs = node.attributes;
    --        var n = attrs.length;
    --        if (n) {
    --          if (opt_sortAttrs) {
    --            var sortedAttrs = [];
    --            for (var i = n; --i >= 0;) { sortedAttrs[i] = attrs[i]; }
    --            sortedAttrs.sort(function (a, b) {
    --                return (a.name < b.name) ? -1 : a.name === b.name ? 0 : 1;
    --              });
    --            attrs = sortedAttrs;
    --          }
    --          for (var i = 0; i < n; ++i) {
    --            var attr = attrs[i];
    --            if (!attr.specified) { continue; }
    --            out.push(' ', attr.name.toLowerCase(),
    --                     '="', attribToHtml(attr.value), '"');
    --          }
    --        }
    --        out.push('>');
    --        for (var child = node.firstChild; child; child = child.nextSibling) {
    --          normalizedHtml(child, out, opt_sortAttrs);
    --        }
    --        if (node.firstChild || !/^(?:br|link|img)$/.test(name)) {
    --          out.push('<\/', name, '>');
    --        }
    --        break;
    --      case 3: case 4: // text
    --        out.push(textToHtml(node.nodeValue));
    --        break;
    --    }
    --  }
    --
    --  /**
    --   * Given a group of {@link RegExp}s, returns a {@code RegExp} that globally
    --   * matches the union o the sets o strings matched d by the input RegExp.
    --   * Since it matches globally, if the input strings have a start-of-input
    --   * anchor (/^.../), it is ignored for the purposes of unioning.
    --   * @param {Array.<RegExp>} regexs non multiline, non-global regexs.
    --   * @return {RegExp} a global regex.
    --   */
    --  function combinePrefixPatterns(regexs) {
    --    var capturedGroupIndex = 0;
    --
    --    var needToFoldCase = false;
    --    var ignoreCase = false;
    --    for (var i = 0, n = regexs.length; i < n; ++i) {
    --      var regex = regexs[i];
    --      if (regex.ignoreCase) {
    --        ignoreCase = true;
    --      } else if (/[a-z]/i.test(regex.source.replace(
    --                     /\\u[0-9a-f]{4}|\\x[0-9a-f]{2}|\\[^ux]/gi, ''))) {
    --        needToFoldCase = true;
    --        ignoreCase = false;
    --        break;
    --      }
    --    }
    --
    --    function decodeEscape(charsetPart) {
    --      if (charsetPart.charAt(0) !== '\\') { return charsetPart.charCodeAt(0); }
    --      switch (charsetPart.charAt(1)) {
    --        case 'b': return 8;
    --        case 't': return 9;
    --        case 'n': return 0xa;
    --        case 'v': return 0xb;
    --        case 'f': return 0xc;
    --        case 'r': return 0xd;
    --        case 'u': case 'x':
    --          return parseInt(charsetPart.substring(2), 16)
    --              || charsetPart.charCodeAt(1);
    --        case '0': case '1': case '2': case '3': case '4':
    --        case '5': case '6': case '7':
    --          return parseInt(charsetPart.substring(1), 8);
    --        default: return charsetPart.charCodeAt(1);
    --      }
    --    }
    --
    --    function encodeEscape(charCode) {
    --      if (charCode < 0x20) {
    --        return (charCode < 0x10 ? '\\x0' : '\\x') + charCode.toString(16);
    --      }
    --      var ch = String.fromCharCode(charCode);
    --      if (ch === '\\' || ch === '-' || ch === '[' || ch === ']') {
    --        ch = '\\' + ch;
    --      }
    --      return ch;
    --    }
    --
    --    function caseFoldCharset(charSet) {
    --      var charsetParts = charSet.substring(1, charSet.length - 1).match(
    --          new RegExp(
    --              '\\\\u[0-9A-Fa-f]{4}'
    --              + '|\\\\x[0-9A-Fa-f]{2}'
    --              + '|\\\\[0-3][0-7]{0,2}'
    --              + '|\\\\[0-7]{1,2}'
    --              + '|\\\\[\\s\\S]'
    --              + '|-'
    --              + '|[^-\\\\]',
    --              'g'));
    --      var groups = [];
    --      var ranges = [];
    --      var inverse = charsetParts[0] === '^';
    --      for (var i = inverse ? 1 : 0, n = charsetParts.length; i < n; ++i) {
    --        var p = charsetParts[i];
    --        switch (p) {
    --          case '\\B': case '\\b':
    --          case '\\D': case '\\d':
    --          case '\\S': case '\\s':
    --          case '\\W': case '\\w':
    --            groups.push(p);
    --            continue;
    --        }
    --        var start = decodeEscape(p);
    --        var end;
    --        if (i + 2 < n && '-' === charsetParts[i + 1]) {
    --          end = decodeEscape(charsetParts[i + 2]);
    --          i += 2;
    --        } else {
    --          end = start;
    --        }
    --        ranges.push([start, end]);
    --        // If the range might intersect letters, then expand it.
    --        if (!(end < 65 || start > 122)) {
    --          if (!(end < 65 || start > 90)) {
    --            ranges.push([Math.max(65, start) | 32, Math.min(end, 90) | 32]);
    --          }
    --          if (!(end < 97 || start > 122)) {
    --            ranges.push([Math.max(97, start) & ~32, Math.min(end, 122) & ~32]);
    --          }
    --        }
    --      }
    --
    --      // [[1, 10], [3, 4], [8, 12], [14, 14], [16, 16], [17, 17]]
    --      // -> [[1, 12], [14, 14], [16, 17]]
    --      ranges.sort(function (a, b) { return (a[0] - b[0]) || (b[1]  - a[1]); });
    --      var consolidatedRanges = [];
    --      var lastRange = [NaN, NaN];
    --      for (var i = 0; i < ranges.length; ++i) {
    --        var range = ranges[i];
    --        if (range[0] <= lastRange[1] + 1) {
    --          lastRange[1] = Math.max(lastRange[1], range[1]);
    --        } else {
    --          consolidatedRanges.push(lastRange = range);
    --        }
    --      }
    --
    --      var out = ['['];
    --      if (inverse) { out.push('^'); }
    --      out.push.apply(out, groups);
    --      for (var i = 0; i < consolidatedRanges.length; ++i) {
    --        var range = consolidatedRanges[i];
    --        out.push(encodeEscape(range[0]));
    --        if (range[1] > range[0]) {
    --          if (range[1] + 1 > range[0]) { out.push('-'); }
    --          out.push(encodeEscape(range[1]));
    --        }
    --      }
    --      out.push(']');
    --      return out.join('');
    --    }
    --
    --    function allowAnywhereFoldCaseAndRenumberGroups(regex) {
    --      // Split into character sets, escape sequences, punctuation strings
    --      // like ('(', '(?:', ')', '^'), and runs of characters that do not
    --      // include any of the above.
    --      var parts = regex.source.match(
    --          new RegExp(
    --              '(?:'
    --              + '\\[(?:[^\\x5C\\x5D]|\\\\[\\s\\S])*\\]'  // a character set
    --              + '|\\\\u[A-Fa-f0-9]{4}'  // a unicode escape
    --              + '|\\\\x[A-Fa-f0-9]{2}'  // a hex escape
    --              + '|\\\\[0-9]+'  // a back-reference or octal escape
    --              + '|\\\\[^ux0-9]'  // other escape sequence
    --              + '|\\(\\?[:!=]'  // start of a non-capturing group
    --              + '|[\\(\\)\\^]'  // start/emd of a group, or line start
    --              + '|[^\\x5B\\x5C\\(\\)\\^]+'  // run of other characters
    --              + ')',
    --              'g'));
    --      var n = parts.length;
    --
    --      // Maps captured group numbers to the number they will occupy in
    --      // the output or to -1 if that has not been determined, or to
    --      // undefined if they need not be capturing in the output.
    --      var capturedGroups = [];
    --
    --      // Walk over and identify back references to build the capturedGroups
    --      // mapping.
    --      for (var i = 0, groupIndex = 0; i < n; ++i) {
    --        var p = parts[i];
    --        if (p === '(') {
    --          // groups are 1-indexed, so max group index is count of '('
    --          ++groupIndex;
    --        } else if ('\\' === p.charAt(0)) {
    --          var decimalValue = +p.substring(1);
    --          if (decimalValue && decimalValue <= groupIndex) {
    --            capturedGroups[decimalValue] = -1;
    --          }
    --        }
    --      }
    --
    --      // Renumber groups and reduce capturing groups to non-capturing groups
    --      // where possible.
    --      for (var i = 1; i < capturedGroups.length; ++i) {
    --        if (-1 === capturedGroups[i]) {
    --          capturedGroups[i] = ++capturedGroupIndex;
    --        }
    --      }
    --      for (var i = 0, groupIndex = 0; i < n; ++i) {
    --        var p = parts[i];
    --        if (p === '(') {
    --          ++groupIndex;
    --          if (capturedGroups[groupIndex] === undefined) {
    --            parts[i] = '(?:';
    --          }
    --        } else if ('\\' === p.charAt(0)) {
    --          var decimalValue = +p.substring(1);
    --          if (decimalValue && decimalValue <= groupIndex) {
    --            parts[i] = '\\' + capturedGroups[groupIndex];
    --          }
    --        }
    --      }
    --
    --      // Remove any prefix anchors so that the output will match anywhere.
    --      // ^^ really does mean an anchored match though.
    --      for (var i = 0, groupIndex = 0; i < n; ++i) {
    --        if ('^' === parts[i] && '^' !== parts[i + 1]) { parts[i] = ''; }
    --      }
    --
    --      // Expand letters to groupts to handle mixing of case-sensitive and
    --      // case-insensitive patterns if necessary.
    --      if (regex.ignoreCase && needToFoldCase) {
    --        for (var i = 0; i < n; ++i) {
    --          var p = parts[i];
    --          var ch0 = p.charAt(0);
    --          if (p.length >= 2 && ch0 === '[') {
    --            parts[i] = caseFoldCharset(p);
    --          } else if (ch0 !== '\\') {
    --            // TODO: handle letters in numeric escapes.
    --            parts[i] = p.replace(
    --                /[a-zA-Z]/g,
    --                function (ch) {
    --                  var cc = ch.charCodeAt(0);
    --                  return '[' + String.fromCharCode(cc & ~32, cc | 32) + ']';
    --                });
    --          }
    --        }
    --      }
    --
    --      return parts.join('');
    --    }
    --
    --    var rewritten = [];
    --    for (var i = 0, n = regexs.length; i < n; ++i) {
    --      var regex = regexs[i];
    --      if (regex.global || regex.multiline) { throw new Error('' + regex); }
    --      rewritten.push(
    --          '(?:' + allowAnywhereFoldCaseAndRenumberGroups(regex) + ')');
    --    }
    --
    --    return new RegExp(rewritten.join('|'), ignoreCase ? 'gi' : 'g');
    --  }
    --
    --  var PR_innerHtmlWorks = null;
    --  function getInnerHtml(node) {
    --    // inner html is hopelessly broken in Safari 2.0.4 when the content is
    --    // an html description of well formed XML and the containing tag is a PRE
    --    // tag, so we detect that case and emulate innerHTML.
    --    if (null === PR_innerHtmlWorks) {
    --      var testNode = document.createElement('PRE');
    --      testNode.appendChild(
    --          document.createTextNode('<!DOCTYPE foo PUBLIC "foo bar">\n<foo />'));
    --      PR_innerHtmlWorks = !/</.test(testNode.innerHTML);
    --    }
    --
    --    if (PR_innerHtmlWorks) {
    --      var content = node.innerHTML;
    --      // XMP tags contain unescaped entities so require special handling.
    --      if (isRawContent(node)) {
    --        content = textToHtml(content);
    --      } else if (!isPreformatted(node, content)) {
    --        content = content.replace(/(<br\s*\/?>)[\r\n]+/g, '$1')
    --            .replace(/(?:[\r\n]+[ \t]*)+/g, ' ');
    --      }
    --      return content;
    --    }
    --
    --    var out = [];
    --    for (var child = node.firstChild; child; child = child.nextSibling) {
    --      normalizedHtml(child, out);
    --    }
    --    return out.join('');
    --  }
    --
    --  /** returns a function that expand tabs to spaces.  This function can be fed
    --    * successive chunks of text, and will maintain its own internal state to
    --    * keep track of how tabs are expanded.
    --    * @return {function (string) : string} a function that takes
    --    *   plain text and return the text with tabs expanded.
    --    * @private
    --    */
    --  function makeTabExpander(tabWidth) {
    --    var SPACES = '                ';
    --    var charInLine = 0;
    --
    --    return function (plainText) {
    --      // walk over each character looking for tabs and newlines.
    --      // On tabs, expand them.  On newlines, reset charInLine.
    --      // Otherwise increment charInLine
    --      var out = null;
    --      var pos = 0;
    --      for (var i = 0, n = plainText.length; i < n; ++i) {
    --        var ch = plainText.charAt(i);
    --
    --        switch (ch) {
    --          case '\t':
    --            if (!out) { out = []; }
    --            out.push(plainText.substring(pos, i));
    --            // calculate how much space we need in front of this part
    --            // nSpaces is the amount of padding -- the number of spaces needed
    --            // to move us to the next column, where columns occur at factors of
    --            // tabWidth.
    --            var nSpaces = tabWidth - (charInLine % tabWidth);
    --            charInLine += nSpaces;
    --            for (; nSpaces >= 0; nSpaces -= SPACES.length) {
    --              out.push(SPACES.substring(0, nSpaces));
    --            }
    --            pos = i + 1;
    --            break;
    --          case '\n':
    --            charInLine = 0;
    --            break;
    --          default:
    --            ++charInLine;
    --        }
    --      }
    --      if (!out) { return plainText; }
    --      out.push(plainText.substring(pos));
    --      return out.join('');
    --    };
    --  }
    --
    --  var pr_chunkPattern = new RegExp(
    --      '[^<]+'  // A run of characters other than '<'
    --      + '|<\!--[\\s\\S]*?--\>'  // an HTML comment
    --      + '|<!\\[CDATA\\[[\\s\\S]*?\\]\\]>'  // a CDATA section
    --      // a probable tag that should not be highlighted
    --      + '|<\/?[a-zA-Z](?:[^>\"\']|\'[^\']*\'|\"[^\"]*\")*>'
    --      + '|<',  // A '<' that does not begin a larger chunk
    --      'g');
    --  var pr_commentPrefix = /^<\!--/;
    --  var pr_cdataPrefix = /^<!\[CDATA\[/;
    --  var pr_brPrefix = /^<br\b/i;
    --  var pr_tagNameRe = /^<(\/?)([a-zA-Z][a-zA-Z0-9]*)/;
    --
    --  /** split markup into chunks of html tags (style null) and
    --    * plain text (style {@link #PR_PLAIN}), converting tags which are
    --    * significant for tokenization (<br>) into their textual equivalent.
    --    *
    --    * @param {string} s html where whitespace is considered significant.
    --    * @return {Object} source code and extracted tags.
    --    * @private
    --    */
    --  function extractTags(s) {
    --    // since the pattern has the 'g' modifier and defines no capturing groups,
    --    // this will return a list of all chunks which we then classify and wrap as
    --    // PR_Tokens
    --    var matches = s.match(pr_chunkPattern);
    --    var sourceBuf = [];
    --    var sourceBufLen = 0;
    --    var extractedTags = [];
    --    if (matches) {
    --      for (var i = 0, n = matches.length; i < n; ++i) {
    --        var match = matches[i];
    --        if (match.length > 1 && match.charAt(0) === '<') {
    --          if (pr_commentPrefix.test(match)) { continue; }
    --          if (pr_cdataPrefix.test(match)) {
    --            // strip CDATA prefix and suffix.  Don't unescape since it's CDATA
    --            sourceBuf.push(match.substring(9, match.length - 3));
    --            sourceBufLen += match.length - 12;
    --          } else if (pr_brPrefix.test(match)) {
    --            // <br> tags are lexically significant so convert them to text.
    --            // This is undone later.
    --            sourceBuf.push('\n');
    --            ++sourceBufLen;
    --          } else {
    --            if (match.indexOf(PR_NOCODE) >= 0 && isNoCodeTag(match)) {
    --              // A <span class="nocode"> will start a section that should be
    --              // ignored.  Continue walking the list until we see a matching end
    --              // tag.
    --              var name = match.match(pr_tagNameRe)[2];
    --              var depth = 1;
    --              var j;
    --              end_tag_loop:
    --              for (j = i + 1; j < n; ++j) {
    --                var name2 = matches[j].match(pr_tagNameRe);
    --                if (name2 && name2[2] === name) {
    --                  if (name2[1] === '/') {
    --                    if (--depth === 0) { break end_tag_loop; }
    --                  } else {
    --                    ++depth;
    --                  }
    --                }
    --              }
    --              if (j < n) {
    --                extractedTags.push(
    --                    sourceBufLen, matches.slice(i, j + 1).join(''));
    --                i = j;
    --              } else {  // Ignore unclosed sections.
    --                extractedTags.push(sourceBufLen, match);
    --              }
    --            } else {
    --              extractedTags.push(sourceBufLen, match);
    --            }
    --          }
    --        } else {
    --          var literalText = htmlToText(match);
    --          sourceBuf.push(literalText);
    --          sourceBufLen += literalText.length;
    --        }
    --      }
    --    }
    --    return { source: sourceBuf.join(''), tags: extractedTags };
    --  }
    --
    --  /** True if the given tag contains a class attribute with the nocode class. */
    --  function isNoCodeTag(tag) {
    --    return !!tag
    --        // First canonicalize the representation of attributes
    --        .replace(/\s(\w+)\s*=\s*(?:\"([^\"]*)\"|'([^\']*)'|(\S+))/g,
    --                 ' $1="$2$3$4"')
    --        // Then look for the attribute we want.
    --        .match(/[cC][lL][aA][sS][sS]=\"[^\"]*\bnocode\b/);
    --  }
    --
    --  /**
    --   * Apply the given language handler to sourceCode and add the resulting
    --   * decorations to out.
    --   * @param {number} basePos the index of sourceCode within the chunk of source
    --   *    whose decorations are already present on out.
    --   */
    --  function appendDecorations(basePos, sourceCode, langHandler, out) {
    --    if (!sourceCode) { return; }
    --    var job = {
    --      source: sourceCode,
    --      basePos: basePos
    --    };
    --    langHandler(job);
    --    out.push.apply(out, job.decorations);
    --  }
    --
    --  /** Given triples of [style, pattern, context] returns a lexing function,
    --    * The lexing function interprets the patterns to find token boundaries and
    --    * returns a decoration list of the form
    --    * [index_0, style_0, index_1, style_1, ..., index_n, style_n]
    --    * where index_n is an index into the sourceCode, and style_n is a style
    --    * constant like PR_PLAIN.  index_n-1 <= index_n, and style_n-1 applies to
    --    * all characters in sourceCode[index_n-1:index_n].
    --    *
    --    * The stylePatterns is a list whose elements have the form
    --    * [style : string, pattern : RegExp, DEPRECATED, shortcut : string].
    --    *
    --    * Style is a style constant like PR_PLAIN, or can be a string of the
    --    * form 'lang-FOO', where FOO is a language extension describing the
    --    * language of the portion of the token in $1 after pattern executes.
    --    * E.g., if style is 'lang-lisp', and group 1 contains the text
    --    * '(hello (world))', then that portion of the token will be passed to the
    --    * registered lisp handler for formatting.
    --    * The text before and after group 1 will be restyled using this decorator
    --    * so decorators should take care that this doesn't result in infinite
    --    * recursion.  For example, the HTML lexer rule for SCRIPT elements looks
    --    * something like ['lang-js', /<[s]cript>(.+?)<\/script>/].  This may match
    --    * '<script>foo()<\/script>', which would cause the current decorator to
    --    * be called with '<script>' which would not match the same rule since
    --    * group 1 must not be empty, so it would be instead styled as PR_TAG by
    --    * the generic tag rule.  The handler registered for the 'js' extension would
    --    * then be called with 'foo()', and finally, the current decorator would
    --    * be called with '<\/script>' which would not match the original rule and
    --    * so the generic tag rule would identify it as a tag.
    --    *
    --    * Pattern must only match prefixes, and if it matches a prefix, then that
    --    * match is considered a token with the same style.
    --    *
    --    * Context is applied to the last non-whitespace, non-comment token
    --    * recognized.
    --    *
    --    * Shortcut is an optional string of characters, any of which, if the first
    --    * character, gurantee that this pattern and only this pattern matches.
    --    *
    --    * @param {Array} shortcutStylePatterns patterns that always start with
    --    *   a known character.  Must have a shortcut string.
    --    * @param {Array} fallthroughStylePatterns patterns that will be tried in
    --    *   order if the shortcut ones fail.  May have shortcuts.
    --    *
    --    * @return {function (Object)} a
    --    *   function that takes source code and returns a list of decorations.
    --    */
    --  function createSimpleLexer(shortcutStylePatterns, fallthroughStylePatterns) {
    --    var shortcuts = {};
    --    var tokenizer;
    --    (function () {
    --      var allPatterns = shortcutStylePatterns.concat(fallthroughStylePatterns);
    --      var allRegexs = [];
    --      var regexKeys = {};
    --      for (var i = 0, n = allPatterns.length; i < n; ++i) {
    --        var patternParts = allPatterns[i];
    --        var shortcutChars = patternParts[3];
    --        if (shortcutChars) {
    --          for (var c = shortcutChars.length; --c >= 0;) {
    --            shortcuts[shortcutChars.charAt(c)] = patternParts;
    --          }
    --        }
    --        var regex = patternParts[1];
    --        var k = '' + regex;
    --        if (!regexKeys.hasOwnProperty(k)) {
    --          allRegexs.push(regex);
    --          regexKeys[k] = null;
    --        }
    --      }
    --      allRegexs.push(/[\0-\uffff]/);
    --      tokenizer = combinePrefixPatterns(allRegexs);
    --    })();
    --
    --    var nPatterns = fallthroughStylePatterns.length;
    --    var notWs = /\S/;
    --
    --    /**
    --     * Lexes job.source and produces an output array job.decorations of style
    --     * classes preceded by the position at which they start in job.source in
    --     * order.
    --     *
    --     * @param {Object} job an object like {@code
    --     *    source: {string} sourceText plain text,
    --     *    basePos: {int} position of job.source in the larger chunk of
    --     *        sourceCode.
    --     * }
    --     */
    --    var decorate = function (job) {
    --      var sourceCode = job.source, basePos = job.basePos;
    --      /** Even entries are positions in source in ascending order.  Odd enties
    --        * are style markers (e.g., PR_COMMENT) that run from that position until
    --        * the end.
    --        * @type {Array.<number|string>}
    --        */
    --      var decorations = [basePos, PR_PLAIN];
    --      var pos = 0;  // index into sourceCode
    --      var tokens = sourceCode.match(tokenizer) || [];
    --      var styleCache = {};
    --
    --      for (var ti = 0, nTokens = tokens.length; ti < nTokens; ++ti) {
    --        var token = tokens[ti];
    --        var style = styleCache[token];
    --        var match = void 0;
    --
    --        var isEmbedded;
    --        if (typeof style === 'string') {
    --          isEmbedded = false;
    --        } else {
    --          var patternParts = shortcuts[token.charAt(0)];
    --          if (patternParts) {
    --            match = token.match(patternParts[1]);
    --            style = patternParts[0];
    --          } else {
    --            for (var i = 0; i < nPatterns; ++i) {
    --              patternParts = fallthroughStylePatterns[i];
    --              match = token.match(patternParts[1]);
    --              if (match) {
    --                style = patternParts[0];
    --                break;
    --              }
    --            }
    --
    --            if (!match) {  // make sure that we make progress
    --              style = PR_PLAIN;
    --            }
    --          }
    --
    --          isEmbedded = style.length >= 5 && 'lang-' === style.substring(0, 5);
    --          if (isEmbedded && !(match && typeof match[1] === 'string')) {
    --            isEmbedded = false;
    --            style = PR_SOURCE;
    --          }
    --
    --          if (!isEmbedded) { styleCache[token] = style; }
    --        }
    --
    --        var tokenStart = pos;
    --        pos += token.length;
    --
    --        if (!isEmbedded) {
    --          decorations.push(basePos + tokenStart, style);
    --        } else {  // Treat group 1 as an embedded block of source code.
    --          var embeddedSource = match[1];
    --          var embeddedSourceStart = token.indexOf(embeddedSource);
    --          var embeddedSourceEnd = embeddedSourceStart + embeddedSource.length;
    --          if (match[2]) {
    --            // If embeddedSource can be blank, then it would match at the
    --            // beginning which would cause us to infinitely recurse on the
    --            // entire token, so we catch the right context in match[2].
    --            embeddedSourceEnd = token.length - match[2].length;
    --            embeddedSourceStart = embeddedSourceEnd - embeddedSource.length;
    --          }
    --          var lang = style.substring(5);
    --          // Decorate the left of the embedded source
    --          appendDecorations(
    --              basePos + tokenStart,
    --              token.substring(0, embeddedSourceStart),
    --              decorate, decorations);
    --          // Decorate the embedded source
    --          appendDecorations(
    --              basePos + tokenStart + embeddedSourceStart,
    --              embeddedSource,
    --              langHandlerForExtension(lang, embeddedSource),
    --              decorations);
    --          // Decorate the right of the embedded section
    --          appendDecorations(
    --              basePos + tokenStart + embeddedSourceEnd,
    --              token.substring(embeddedSourceEnd),
    --              decorate, decorations);
    --        }
    --      }
    --      job.decorations = decorations;
    --    };
    --    return decorate;
    --  }
    --
    --  /** returns a function that produces a list of decorations from source text.
    --    *
    --    * This code treats ", ', and ` as string delimiters, and \ as a string
    --    * escape.  It does not recognize perl's qq() style strings.
    --    * It has no special handling for double delimiter escapes as in basic, or
    --    * the tripled delimiters used in python, but should work on those regardless
    --    * although in those cases a single string literal may be broken up into
    --    * multiple adjacent string literals.
    --    *
    --    * It recognizes C, C++, and shell style comments.
    --    *
    --    * @param {Object} options a set of optional parameters.
    --    * @return {function (Object)} a function that examines the source code
    --    *     in the input job and builds the decoration list.
    --    */
    --  function sourceDecorator(options) {
    --    var shortcutStylePatterns = [], fallthroughStylePatterns = [];
    --    if (options['tripleQuotedStrings']) {
    --      // '''multi-line-string''', 'single-line-string', and double-quoted
    --      shortcutStylePatterns.push(
    --          [PR_STRING,  /^(?:\'\'\'(?:[^\'\\]|\\[\s\S]|\'{1,2}(?=[^\']))*(?:\'\'\'|$)|\"\"\"(?:[^\"\\]|\\[\s\S]|\"{1,2}(?=[^\"]))*(?:\"\"\"|$)|\'(?:[^\\\']|\\[\s\S])*(?:\'|$)|\"(?:[^\\\"]|\\[\s\S])*(?:\"|$))/,
    --           null, '\'"']);
    --    } else if (options['multiLineStrings']) {
    --      // 'multi-line-string', "multi-line-string"
    --      shortcutStylePatterns.push(
    --          [PR_STRING,  /^(?:\'(?:[^\\\']|\\[\s\S])*(?:\'|$)|\"(?:[^\\\"]|\\[\s\S])*(?:\"|$)|\`(?:[^\\\`]|\\[\s\S])*(?:\`|$))/,
    --           null, '\'"`']);
    --    } else {
    --      // 'single-line-string', "single-line-string"
    --      shortcutStylePatterns.push(
    --          [PR_STRING,
    --           /^(?:\'(?:[^\\\'\r\n]|\\.)*(?:\'|$)|\"(?:[^\\\"\r\n]|\\.)*(?:\"|$))/,
    --           null, '"\'']);
    --    }
    --    if (options['verbatimStrings']) {
    --      // verbatim-string-literal production from the C# grammar.  See issue 93.
    --      fallthroughStylePatterns.push(
    --          [PR_STRING, /^@\"(?:[^\"]|\"\")*(?:\"|$)/, null]);
    --    }
    --    var hc = options['hashComments'];
    --    if (hc) {
    --      if (options['cStyleComments']) {
    --        if (hc > 1) {  // multiline hash comments
    --          shortcutStylePatterns.push(
    --              [PR_COMMENT, /^#(?:##(?:[^#]|#(?!##))*(?:###|$)|.*)/, null, '#']);
    --        } else {
    --          // Stop C preprocessor declarations at an unclosed open comment
    --          shortcutStylePatterns.push(
    --              [PR_COMMENT, /^#(?:(?:define|elif|else|endif|error|ifdef|include|ifndef|line|pragma|undef|warning)\b|[^\r\n]*)/,
    --               null, '#']);
    --        }
    --        fallthroughStylePatterns.push(
    --            [PR_STRING,
    --             /^<(?:(?:(?:\.\.\/)*|\/?)(?:[\w-]+(?:\/[\w-]+)+)?[\w-]+\.h|[a-z]\w*)>/,
    --             null]);
    --      } else {
    --        shortcutStylePatterns.push([PR_COMMENT, /^#[^\r\n]*/, null, '#']);
    --      }
    --    }
    --    if (options['cStyleComments']) {
    --      fallthroughStylePatterns.push([PR_COMMENT, /^\/\/[^\r\n]*/, null]);
    --      fallthroughStylePatterns.push(
    --          [PR_COMMENT, /^\/\*[\s\S]*?(?:\*\/|$)/, null]);
    --    }
    --    if (options['regexLiterals']) {
    --      var REGEX_LITERAL = (
    --          // A regular expression literal starts with a slash that is
    --          // not followed by * or / so that it is not confused with
    --          // comments.
    --          '/(?=[^/*])'
    --          // and then contains any number of raw characters,
    --          + '(?:[^/\\x5B\\x5C]'
    --          // escape sequences (\x5C),
    --          +    '|\\x5C[\\s\\S]'
    --          // or non-nesting character sets (\x5B\x5D);
    --          +    '|\\x5B(?:[^\\x5C\\x5D]|\\x5C[\\s\\S])*(?:\\x5D|$))+'
    --          // finally closed by a /.
    --          + '/');
    --      fallthroughStylePatterns.push(
    --          ['lang-regex',
    --           new RegExp('^' + REGEXP_PRECEDER_PATTERN + '(' + REGEX_LITERAL + ')')
    --           ]);
    --    }
    --
    --    var keywords = options['keywords'].replace(/^\s+|\s+$/g, '');
    --    if (keywords.length) {
    --      fallthroughStylePatterns.push(
    --          [PR_KEYWORD,
    --           new RegExp('^(?:' + keywords.replace(/\s+/g, '|') + ')\\b'), null]);
    --    }
    --
    --    shortcutStylePatterns.push([PR_PLAIN,       /^\s+/, null, ' \r\n\t\xA0']);
    --    fallthroughStylePatterns.push(
    --        // TODO(mikesamuel): recognize non-latin letters and numerals in idents
    --        [PR_LITERAL,     /^@[a-z_$][a-z_$@0-9]*/i, null],
    --        [PR_TYPE,        /^@?[A-Z]+[a-z][A-Za-z_$@0-9]*/, null],
    --        [PR_PLAIN,       /^[a-z_$][a-z_$@0-9]*/i, null],
    --        [PR_LITERAL,
    --         new RegExp(
    --             '^(?:'
    --             // A hex number
    --             + '0x[a-f0-9]+'
    --             // or an octal or decimal number,
    --             + '|(?:\\d(?:_\\d+)*\\d*(?:\\.\\d*)?|\\.\\d\\+)'
    --             // possibly in scientific notation
    --             + '(?:e[+\\-]?\\d+)?'
    --             + ')'
    --             // with an optional modifier like UL for unsigned long
    --             + '[a-z]*', 'i'),
    --         null, '0123456789'],
    --        [PR_PUNCTUATION, /^.[^\s\w\.$@\'\"\`\/\#]*/, null]);
    --
    --    return createSimpleLexer(shortcutStylePatterns, fallthroughStylePatterns);
    --  }
    --
    --  var decorateSource = sourceDecorator({
    --        'keywords': ALL_KEYWORDS,
    --        'hashComments': true,
    --        'cStyleComments': true,
    --        'multiLineStrings': true,
    --        'regexLiterals': true
    --      });
    --
    --  /** Breaks {@code job.source} around style boundaries in
    --    * {@code job.decorations} while re-interleaving {@code job.extractedTags},
    --    * and leaves the result in {@code job.prettyPrintedHtml}.
    --    * @param {Object} job like {
    --    *    source: {string} source as plain text,
    --    *    extractedTags: {Array.<number|string>} extractedTags chunks of raw
    --    *                   html preceded by their position in {@code job.source}
    --    *                   in order
    --    *    decorations: {Array.<number|string} an array of style classes preceded
    --    *                 by the position at which they start in job.source in order
    --    * }
    --    * @private
    --    */
    --  function recombineTagsAndDecorations(job) {
    --    var sourceText = job.source;
    --    var extractedTags = job.extractedTags;
    --    var decorations = job.decorations;
    --    var numberLines = job.numberLines;
    --    var sourceNode = job.sourceNode;
    --
    --    var html = [];
    --    // index past the last char in sourceText written to html
    --    var outputIdx = 0;
    --
    --    var openDecoration = null;
    --    var currentDecoration = null;
    --    var tagPos = 0;  // index into extractedTags
    --    var decPos = 0;  // index into decorations
    --    var tabExpander = makeTabExpander(window['PR_TAB_WIDTH']);
    --
    --    var adjacentSpaceRe = /([\r\n ]) /g;
    --    var startOrSpaceRe = /(^| ) /gm;
    --    var newlineRe = /\r\n?|\n/g;
    --    var trailingSpaceRe = /[ \r\n]$/;
    --    var lastWasSpace = true;  // the last text chunk emitted ended with a space.
    --
    --    // See bug 71 and http://stackoverflow.com/questions/136443/why-doesnt-ie7-
    --    var isIE678 = window['_pr_isIE6']();
    --    var lineBreakHtml = (
    --        isIE678
    --        ? (sourceNode && sourceNode.tagName === 'PRE'
    --           // Use line feeds instead of <br>s so that copying and pasting works
    --           // on IE.
    --           // See Issue 104 for the derivation of this mess.
    --           ? (isIE678 === 6 ? '&#160;\r\n' :
    --              isIE678 === 7 ? '&#160;<br />\r' :
    --              isIE678 === 8 ? '&#160;<br />' : '&#160;\r')
    --           // IE collapses multiple adjacent <br>s into 1 line break.
    --           // Prefix every newline with '&#160;' to prevent such behavior.
    --           // &nbsp; is the same as &#160; but works in XML as well as HTML.
    --           : '&#160;<br />')
    --        : '<br />');
    --
    --    var lineBreaker;
    --    if (numberLines) {
    --      var lineBreaks = [];
    --      for (var i = 0; i < 10; ++i) {
    --        lineBreaks[i] = lineBreakHtml + '</li><li class="L' + i + '">';
    --      }
    --      var lineNum = typeof numberLines === 'number'
    --          ? numberLines - 1 /* number lines are 1 indexed */ : 0;
    --      html.push('<ol class="linenums"><li class="L', (lineNum) % 10, '"');
    --      if (lineNum) {
    --        html.push(' value="', lineNum + 1, '"');
    --      }
    --      html.push('>');
    --      lineBreaker = function () {
    --        var lb = lineBreaks[++lineNum % 10];
    --        // If a decoration is open, we need to close it before closing a list-item
    --        // and reopen it on the other side of the list item.
    --        return openDecoration
    --            ? ('</span>' + lb + '<span class="' + openDecoration + '">') : lb;
    --      };
    --    } else {
    --      lineBreaker = lineBreakHtml;
    --    }
    --
    --    // A helper function that is responsible for opening sections of decoration
    --    // and outputing properly escaped chunks of source
    --    function emitTextUpTo(sourceIdx) {
    --      if (sourceIdx > outputIdx) {
    --        if (openDecoration && openDecoration !== currentDecoration) {
    --          // Close the current decoration
    --          html.push('</span>');
    --          openDecoration = null;
    --        }
    --        if (!openDecoration && currentDecoration) {
    --          openDecoration = currentDecoration;
    --          html.push('<span class="', openDecoration, '">');
    --        }
    --        // This interacts badly with some wikis which introduces paragraph tags
    --        // into pre blocks for some strange reason.
    --        // It's necessary for IE though which seems to lose the preformattedness
    --        // of <pre> tags when their innerHTML is assigned.
    --        // http://stud3.tuwien.ac.at/~e0226430/innerHtmlQuirk.html
    --        // and it serves to undo the conversion of <br>s to newlines done in
    --        // chunkify.
    --        var htmlChunk = textToHtml(
    --            tabExpander(sourceText.substring(outputIdx, sourceIdx)))
    --            .replace(lastWasSpace
    --                     ? startOrSpaceRe
    --                     : adjacentSpaceRe, '$1&#160;');
    --        // Keep track of whether we need to escape space at the beginning of the
    --        // next chunk.
    --        lastWasSpace = trailingSpaceRe.test(htmlChunk);
    --        html.push(htmlChunk.replace(newlineRe, lineBreaker));
    --        outputIdx = sourceIdx;
    --      }
    --    }
    --
    --    while (true) {
    --      // Determine if we're going to consume a tag this time around.  Otherwise
    --      // we consume a decoration or exit.
    --      var outputTag;
    --      if (tagPos < extractedTags.length) {
    --        if (decPos < decorations.length) {
    --          // Pick one giving preference to extractedTags since we shouldn't open
    --          // a new style that we're going to have to immediately close in order
    --          // to output a tag.
    --          outputTag = extractedTags[tagPos] <= decorations[decPos];
    --        } else {
    --          outputTag = true;
    --        }
    --      } else {
    --        outputTag = false;
    --      }
    --      // Consume either a decoration or a tag or exit.
    --      if (outputTag) {
    --        emitTextUpTo(extractedTags[tagPos]);
    --        if (openDecoration) {
    --          // Close the current decoration
    --          html.push('</span>');
    --          openDecoration = null;
    --        }
    --        html.push(extractedTags[tagPos + 1]);
    --        tagPos += 2;
    --      } else if (decPos < decorations.length) {
    --        emitTextUpTo(decorations[decPos]);
    --        currentDecoration = decorations[decPos + 1];
    --        decPos += 2;
    --      } else {
    --        break;
    --      }
    --    }
    --    emitTextUpTo(sourceText.length);
    --    if (openDecoration) {
    --      html.push('</span>');
    --    }
    --    if (numberLines) { html.push('</li></ol>'); }
    --    job.prettyPrintedHtml = html.join('');
    --  }
    --
    --  /** Maps language-specific file extensions to handlers. */
    --  var langHandlerRegistry = {};
    --  /** Register a language handler for the given file extensions.
    --    * @param {function (Object)} handler a function from source code to a list
    --    *      of decorations.  Takes a single argument job which describes the
    --    *      state of the computation.   The single parameter has the form
    --    *      {@code {
    --    *        source: {string} as plain text.
    --    *        decorations: {Array.<number|string>} an array of style classes
    --    *                     preceded by the position at which they start in
    --    *                     job.source in order.
    --    *                     The language handler should assigned this field.
    --    *        basePos: {int} the position of source in the larger source chunk.
    --    *                 All positions in the output decorations array are relative
    --    *                 to the larger source chunk.
    --    *      } }
    --    * @param {Array.<string>} fileExtensions
    --    */
    --  function registerLangHandler(handler, fileExtensions) {
    --    for (var i = fileExtensions.length; --i >= 0;) {
    --      var ext = fileExtensions[i];
    --      if (!langHandlerRegistry.hasOwnProperty(ext)) {
    --        langHandlerRegistry[ext] = handler;
    --      } else if ('console' in window) {
    --        console['warn']('cannot override language handler %s', ext);
    --      }
    --    }
    --  }
    --  function langHandlerForExtension(extension, source) {
    --    if (!(extension && langHandlerRegistry.hasOwnProperty(extension))) {
    --      // Treat it as markup if the first non whitespace character is a < and
    --      // the last non-whitespace character is a >.
    --      extension = /^\s*</.test(source)
    --          ? 'default-markup'
    --          : 'default-code';
    --    }
    --    return langHandlerRegistry[extension];
    --  }
    --  registerLangHandler(decorateSource, ['default-code']);
    --  registerLangHandler(
    --      createSimpleLexer(
    --          [],
    --          [
    --           [PR_PLAIN,       /^[^<?]+/],
    --           [PR_DECLARATION, /^<!\w[^>]*(?:>|$)/],
    --           [PR_COMMENT,     /^<\!--[\s\S]*?(?:-\->|$)/],
    --           // Unescaped content in an unknown language
    --           ['lang-',        /^<\?([\s\S]+?)(?:\?>|$)/],
    --           ['lang-',        /^<%([\s\S]+?)(?:%>|$)/],
    --           [PR_PUNCTUATION, /^(?:<[%?]|[%?]>)/],
    --           ['lang-',        /^<xmp\b[^>]*>([\s\S]+?)<\/xmp\b[^>]*>/i],
    --           // Unescaped content in javascript.  (Or possibly vbscript).
    --           ['lang-js',      /^<script\b[^>]*>([\s\S]*?)(<\/script\b[^>]*>)/i],
    --           // Contains unescaped stylesheet content
    --           ['lang-css',     /^<style\b[^>]*>([\s\S]*?)(<\/style\b[^>]*>)/i],
    --           ['lang-in.tag',  /^(<\/?[a-z][^<>]*>)/i]
    --          ]),
    --      ['default-markup', 'htm', 'html', 'mxml', 'xhtml', 'xml', 'xsl']);
    --  registerLangHandler(
    --      createSimpleLexer(
    --          [
    --           [PR_PLAIN,        /^[\s]+/, null, ' \t\r\n'],
    --           [PR_ATTRIB_VALUE, /^(?:\"[^\"]*\"?|\'[^\']*\'?)/, null, '\"\'']
    --           ],
    --          [
    --           [PR_TAG,          /^^<\/?[a-z](?:[\w.:-]*\w)?|\/?>$/i],
    --           [PR_ATTRIB_NAME,  /^(?!style[\s=]|on)[a-z](?:[\w:-]*\w)?/i],
    --           ['lang-uq.val',   /^=\s*([^>\'\"\s]*(?:[^>\'\"\s\/]|\/(?=\s)))/],
    --           [PR_PUNCTUATION,  /^[=<>\/]+/],
    --           ['lang-js',       /^on\w+\s*=\s*\"([^\"]+)\"/i],
    --           ['lang-js',       /^on\w+\s*=\s*\'([^\']+)\'/i],
    --           ['lang-js',       /^on\w+\s*=\s*([^\"\'>\s]+)/i],
    --           ['lang-css',      /^style\s*=\s*\"([^\"]+)\"/i],
    --           ['lang-css',      /^style\s*=\s*\'([^\']+)\'/i],
    --           ['lang-css',      /^style\s*=\s*([^\"\'>\s]+)/i]
    --           ]),
    --      ['in.tag']);
    --  registerLangHandler(
    --      createSimpleLexer([], [[PR_ATTRIB_VALUE, /^[\s\S]+/]]), ['uq.val']);
    --  registerLangHandler(sourceDecorator({
    --          'keywords': CPP_KEYWORDS,
    --          'hashComments': true,
    --          'cStyleComments': true
    --        }), ['c', 'cc', 'cpp', 'cxx', 'cyc', 'm']);
    --  registerLangHandler(sourceDecorator({
    --          'keywords': 'null true false'
    --        }), ['json']);
    --  registerLangHandler(sourceDecorator({
    --          'keywords': CSHARP_KEYWORDS,
    --          'hashComments': true,
    --          'cStyleComments': true,
    --          'verbatimStrings': true
    --        }), ['cs']);
    --  registerLangHandler(sourceDecorator({
    --          'keywords': JAVA_KEYWORDS,
    --          'cStyleComments': true
    --        }), ['java']);
    --  registerLangHandler(sourceDecorator({
    --          'keywords': SH_KEYWORDS,
    --          'hashComments': true,
    --          'multiLineStrings': true
    --        }), ['bsh', 'csh', 'sh']);
    --  registerLangHandler(sourceDecorator({
    --          'keywords': PYTHON_KEYWORDS,
    --          'hashComments': true,
    --          'multiLineStrings': true,
    --          'tripleQuotedStrings': true
    --        }), ['cv', 'py']);
    --  registerLangHandler(sourceDecorator({
    --          'keywords': PERL_KEYWORDS,
    --          'hashComments': true,
    --          'multiLineStrings': true,
    --          'regexLiterals': true
    --        }), ['perl', 'pl', 'pm']);
    --  registerLangHandler(sourceDecorator({
    --          'keywords': RUBY_KEYWORDS,
    --          'hashComments': true,
    --          'multiLineStrings': true,
    --          'regexLiterals': true
    --        }), ['rb']);
    --  registerLangHandler(sourceDecorator({
    --          'keywords': JSCRIPT_KEYWORDS,
    --          'cStyleComments': true,
    --          'regexLiterals': true
    --        }), ['js']);
    --  registerLangHandler(sourceDecorator({
    --          'keywords': COFFEE_KEYWORDS,
    --          'hashComments': 3,  // ### style block comments
    --          'cStyleComments': true,
    --          'multilineStrings': true,
    --          'tripleQuotedStrings': true,
    --          'regexLiterals': true
    --        }), ['coffee']);
    --  registerLangHandler(createSimpleLexer([], [[PR_STRING, /^[\s\S]+/]]), ['regex']);
    --
    --  function applyDecorator(job) {
    --    var sourceCodeHtml = job.sourceCodeHtml;
    --    var opt_langExtension = job.langExtension;
    --
    --    // Prepopulate output in case processing fails with an exception.
    --    job.prettyPrintedHtml = sourceCodeHtml;
    --
    --    try {
    --      // Extract tags, and convert the source code to plain text.
    --      var sourceAndExtractedTags = extractTags(sourceCodeHtml);
    --      /** Plain text. @type {string} */
    --      var source = sourceAndExtractedTags.source;
    --      job.source = source;
    --      job.basePos = 0;
    --
    --      /** Even entries are positions in source in ascending order.  Odd entries
    --        * are tags that were extracted at that position.
    --        * @type {Array.<number|string>}
    --        */
    --      job.extractedTags = sourceAndExtractedTags.tags;
    --
    --      // Apply the appropriate language handler
    --      langHandlerForExtension(opt_langExtension, source)(job);
    --      // Integrate the decorations and tags back into the source code to produce
    --      // a decorated html string which is left in job.prettyPrintedHtml.
    --      recombineTagsAndDecorations(job);
    --    } catch (e) {
    --      if ('console' in window) {
    --        console['log'](e && e['stack'] ? e['stack'] : e);
    --      }
    --    }
    --  }
    --
    --  /**
    --   * @param sourceCodeHtml {string} The HTML to pretty print.
    --   * @param opt_langExtension {string} The language name to use.
    --   *     Typically, a filename extension like 'cpp' or 'java'.
    --   * @param opt_numberLines {number|boolean} True to number lines,
    --   *     or the 1-indexed number of the first line in sourceCodeHtml.
    --   */
    --  function prettyPrintOne(sourceCodeHtml, opt_langExtension, opt_numberLines) {
    --    var job = {
    --      sourceCodeHtml: sourceCodeHtml,
    --      langExtension: opt_langExtension,
    --      numberLines: opt_numberLines
    --    };
    --    applyDecorator(job);
    --    return job.prettyPrintedHtml;
    --  }
    --
    --  function prettyPrint(opt_whenDone) {
    --    function byTagName(tn) { return document.getElementsByTagName(tn); }
    --    // fetch a list of nodes to rewrite
    --    var codeSegments = [byTagName('pre'), byTagName('code'), byTagName('xmp')];
    --    var elements = [];
    --    for (var i = 0; i < codeSegments.length; ++i) {
    --      for (var j = 0, n = codeSegments[i].length; j < n; ++j) {
    --        elements.push(codeSegments[i][j]);
    --      }
    --    }
    --    codeSegments = null;
    --
    --    var clock = Date;
    --    if (!clock['now']) {
    --      clock = { 'now': function () { return (new Date).getTime(); } };
    --    }
    --
    --    // The loop is broken into a series of continuations to make sure that we
    --    // don't make the browser unresponsive when rewriting a large page.
    --    var k = 0;
    --    var prettyPrintingJob;
    --
    --    function doWork() {
    --      var endTime = (window['PR_SHOULD_USE_CONTINUATION'] ?
    --                     clock.now() + 250 /* ms */ :
    --                     Infinity);
    --      for (; k < elements.length && clock.now() < endTime; k++) {
    --        var cs = elements[k];
    --        if (cs.className && cs.className.indexOf('prettyprint') >= 0) {
    --          // If the classes includes a language extensions, use it.
    --          // Language extensions can be specified like
    --          //     <pre class="prettyprint lang-cpp">
    --          // the language extension "cpp" is used to find a language handler as
    --          // passed to PR.registerLangHandler.
    --          var langExtension = cs.className.match(/\blang-(\w+)\b/);
    --          if (langExtension) { langExtension = langExtension[1]; }
    --
    --          // make sure this is not nested in an already prettified element
    --          var nested = false;
    --          for (var p = cs.parentNode; p; p = p.parentNode) {
    --            if ((p.tagName === 'pre' || p.tagName === 'code' ||
    --                 p.tagName === 'xmp') &&
    --                p.className && p.className.indexOf('prettyprint') >= 0) {
    --              nested = true;
    --              break;
    --            }
    --          }
    --          if (!nested) {
    --            // fetch the content as a snippet of properly escaped HTML.
    --            // Firefox adds newlines at the end.
    --            var content = getInnerHtml(cs);
    --            content = content.replace(/(?:\r\n?|\n)$/, '');
    --
    --            // Look for a class like linenums or linenums:<n> where <n> is the
    --            // 1-indexed number of the first line.
    --            var numberLines = cs.className.match(/\blinenums\b(?::(\d+))?/);
    --
    --            // do the pretty printing
    --            prettyPrintingJob = {
    --              sourceCodeHtml: content,
    --              langExtension: langExtension,
    --              sourceNode: cs,
    --              numberLines: numberLines
    --                  ? numberLines[1] && numberLines[1].length ? +numberLines[1] : true
    --                  : false
    --            };
    --            applyDecorator(prettyPrintingJob);
    --            replaceWithPrettyPrintedHtml();
    --          }
    --        }
    --      }
    --      if (k < elements.length) {
    --        // finish up in a continuation
    --        setTimeout(doWork, 250);
    --      } else if (opt_whenDone) {
    --        opt_whenDone();
    --      }
    --    }
    --
    --    function replaceWithPrettyPrintedHtml() {
    --      var newContent = prettyPrintingJob.prettyPrintedHtml;
    --      if (!newContent) { return; }
    --      var cs = prettyPrintingJob.sourceNode;
    --
    --      // push the prettified html back into the tag.
    --      if (!isRawContent(cs)) {
    --        // just replace the old html with the new
    --        cs.innerHTML = newContent;
    --      } else {
    --        // we need to change the tag to a <pre> since <xmp>s do not allow
    --        // embedded tags such as the span tags used to attach styles to
    --        // sections of source code.
    --        var pre = document.createElement('PRE');
    --        for (var i = 0; i < cs.attributes.length; ++i) {
    --          var a = cs.attributes[i];
    --          if (a.specified) {
    --            var aname = a.name.toLowerCase();
    --            if (aname === 'class') {
    --              pre.className = a.value;  // For IE 6
    --            } else {
    --              pre.setAttribute(a.name, a.value);
    --            }
    --          }
    --        }
    --        pre.innerHTML = newContent;
    --
    --        // remove the old
    --        cs.parentNode.replaceChild(pre, cs);
    --        cs = pre;
    --      }
    --    }
    --
    --    doWork();
    --  }
    --
    --  window['PR_normalizedHtml'] = normalizedHtml;
    --  window['prettyPrintOne'] = prettyPrintOne;
    --  window['prettyPrint'] = prettyPrint;
    --  window['PR'] = {
    --        'combinePrefixPatterns': combinePrefixPatterns,
    --        'createSimpleLexer': createSimpleLexer,
    --        'registerLangHandler': registerLangHandler,
    --        'sourceDecorator': sourceDecorator,
    --        'PR_ATTRIB_NAME': PR_ATTRIB_NAME,
    --        'PR_ATTRIB_VALUE': PR_ATTRIB_VALUE,
    --        'PR_COMMENT': PR_COMMENT,
    --        'PR_DECLARATION': PR_DECLARATION,
    --        'PR_KEYWORD': PR_KEYWORD,
    --        'PR_LITERAL': PR_LITERAL,
    --        'PR_NOCODE': PR_NOCODE,
    --        'PR_PLAIN': PR_PLAIN,
    --        'PR_PUNCTUATION': PR_PUNCTUATION,
    --        'PR_SOURCE': PR_SOURCE,
    --        'PR_STRING': PR_STRING,
    --        'PR_TAG': PR_TAG,
    --        'PR_TYPE': PR_TYPE
    --      };
    --})();
    --
    --//third_party/javascript/google_code_prettify/src/lang-apollo.js
    --/**
    -- * @license Copyright (C) 2009 Onno Hommes.
    -- *
    -- * 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.
    -- */
    --
    --/**
    -- * @fileoverview
    -- * Registers a language handler for the AGC/AEA Assembly Language as described
    -- * at http://virtualagc.googlecode.com
    -- * <p>
    -- * This file could be used by goodle code to allow syntax highlight for
    -- * Virtual AGC SVN repository or if you don't want to commonize
    -- * the header for the agc/aea html assembly listing.
    -- *
    -- * @author ohommes@alumni.cmu.edu
    -- */
    --
    --PR['registerLangHandler'](
    --    PR['createSimpleLexer'](
    --        [
    --         // A line comment that starts with ;
    --         [PR['PR_COMMENT'],     /^#[^\r\n]*/, null, '#'],
    --         // Whitespace
    --         [PR['PR_PLAIN'],       /^[\t\n\r \xA0]+/, null, '\t\n\r \xA0'],
    --         // A double quoted, possibly multi-line, string.
    --         [PR['PR_STRING'],      /^\"(?:[^\"\\]|\\[\s\S])*(?:\"|$)/, null, '"']
    --        ],
    --        [
    --         [PR['PR_KEYWORD'], /^(?:ADS|AD|AUG|BZF|BZMF|CAE|CAF|CA|CCS|COM|CS|DAS|DCA|DCOM|DCS|DDOUBL|DIM|DOUBLE|DTCB|DTCF|DV|DXCH|EDRUPT|EXTEND|INCR|INDEX|NDX|INHINT|LXCH|MASK|MSK|MP|MSU|NOOP|OVSK|QXCH|RAND|READ|RELINT|RESUME|RETURN|ROR|RXOR|SQUARE|SU|TCR|TCAA|OVSK|TCF|TC|TS|WAND|WOR|WRITE|XCH|XLQ|XXALQ|ZL|ZQ|ADD|ADZ|SUB|SUZ|MPY|MPR|MPZ|DVP|COM|ABS|CLA|CLZ|LDQ|STO|STQ|ALS|LLS|LRS|TRA|TSQ|TMI|TOV|AXT|TIX|DLY|INP|OUT)\s/,null],
    --         [PR['PR_TYPE'], /^(?:-?GENADR|=MINUS|2BCADR|VN|BOF|MM|-?2CADR|-?[1-6]DNADR|ADRES|BBCON|[SE]?BANK\=?|BLOCK|BNKSUM|E?CADR|COUNT\*?|2?DEC\*?|-?DNCHAN|-?DNPTR|EQUALS|ERASE|MEMORY|2?OCT|REMADR|SETLOC|SUBRO|ORG|BSS|BES|SYN|EQU|DEFINE|END)\s/,null],
    --         // A single quote possibly followed by a word that optionally ends with
    --         // = ! or ?.
    --         [PR['PR_LITERAL'],
    --          /^\'(?:-*(?:\w|\\[\x21-\x7e])(?:[\w-]*|\\[\x21-\x7e])[=!?]?)?/],
    --         // Any word including labels that optionally ends with = ! or ?.
    --         [PR['PR_PLAIN'],
    --          /^-*(?:[!-z_]|\\[\x21-\x7e])(?:[\w-]*|\\[\x21-\x7e])[=!?]?/i],
    --         // A printable non-space non-special character
    --         [PR['PR_PUNCTUATION'], /^[^\w\t\n\r \xA0()\"\\\';]+/]
    --        ]),
    --    ['apollo', 'agc', 'aea']);
    --
    --//third_party/javascript/google_code_prettify/src/lang-clj.js
    --/**
    -- * @license Copyright (C) 2011 Google Inc.
    -- *
    -- * 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.
    -- */
    --
    --/**
    -- * @fileoverview
    -- * Registers a language handler for Clojure.
    -- *
    -- *
    -- * To use, include prettify.js and this file in your HTML page.
    -- * Then put your code in an HTML tag like
    -- *      <pre class="prettyprint lang-lisp">(my lisp code)</pre>
    -- * The lang-cl class identifies the language as common lisp.
    -- * This file supports the following language extensions:
    -- *     lang-clj - Clojure
    -- *
    -- *
    -- * I used lang-lisp.js as the basis for this adding the clojure specific
    -- * keywords and syntax.
    -- *
    -- * "Name"    = 'Clojure'
    -- * "Author"  = 'Rich Hickey'
    -- * "Version" = '1.2'
    -- * "About"   = 'Clojure is a lisp for the jvm with concurrency primitives and a richer set of types.'
    -- *
    -- *
    -- * I used <a href="http://clojure.org/Reference">Clojure.org Reference</a> as
    -- * the basis for the reserved word list.
    -- *
    -- *
    -- * @author jwall@google.com
    -- */
    --
    --PR['registerLangHandler'](
    --    PR['createSimpleLexer'](
    --        [
    --         // clojure has more paren types than minimal lisp.
    --         ['opn',             /^[\(\{\[]+/, null, '([{'],
    --         ['clo',             /^[\)\}\]]+/, null, ')]}'],
    --         // A line comment that starts with ;
    --         [PR['PR_COMMENT'],     /^;[^\r\n]*/, null, ';'],
    --         // Whitespace
    --         [PR['PR_PLAIN'],       /^[\t\n\r \xA0]+/, null, '\t\n\r \xA0'],
    --         // A double quoted, possibly multi-line, string.
    --         [PR['PR_STRING'],      /^\"(?:[^\"\\]|\\[\s\S])*(?:\"|$)/, null, '"']
    --        ],
    --        [
    --         // clojure has a much larger set of keywords
    --         [PR['PR_KEYWORD'],     /^(?:def|if|do|let|quote|var|fn|loop|recur|throw|try|monitor-enter|monitor-exit|defmacro|defn|defn-|macroexpand|macroexpand-1|for|doseq|dosync|dotimes|and|or|when|not|assert|doto|proxy|defstruct|first|rest|cons|defprotocol|deftype|defrecord|reify|defmulti|defmethod|meta|with-meta|ns|in-ns|create-ns|import|intern|refer|alias|namespace|resolve|ref|deref|refset|new|set!|memfn|to-array|into-array|aset|gen-class|reduce|map|filter|find|nil?|empty?|hash-map|hash-set|vec|vector|seq|flatten|reverse|assoc|dissoc|list|list?|disj|get|union|difference|intersection|extend|extend-type|extend-protocol|prn)\b/, null],
    --         [PR['PR_TYPE'], /^:[0-9a-zA-Z\-]+/]
    --        ]),
    --    ['clj']);
    --
    --//third_party/javascript/google_code_prettify/src/lang-css.js
    --/**
    -- * @license Copyright (C) 2009 Google Inc.
    -- *
    -- * 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.
    -- */
    --
    --/**
    -- * @fileoverview
    -- * Registers a language handler for CSS.
    -- *
    -- *
    -- * To use, include prettify.js and this file in your HTML page.
    -- * Then put your code in an HTML tag like
    -- *      <pre class="prettyprint lang-css"></pre>
    -- *
    -- *
    -- * http://www.w3.org/TR/CSS21/grammar.html Section G2 defines the lexical
    -- * grammar.  This scheme does not recognize keywords containing escapes.
    -- *
    -- * @author mikesamuel@gmail.com
    -- */
    --
    --PR['registerLangHandler'](
    --    PR['createSimpleLexer'](
    --        [
    --         // The space production <s>
    --         [PR['PR_PLAIN'],       /^[ \t\r\n\f]+/, null, ' \t\r\n\f']
    --        ],
    --        [
    --         // Quoted strings.  <string1> and <string2>
    --         [PR['PR_STRING'],
    --          /^\"(?:[^\n\r\f\\\"]|\\(?:\r\n?|\n|\f)|\\[\s\S])*\"/, null],
    --         [PR['PR_STRING'],
    --          /^\'(?:[^\n\r\f\\\']|\\(?:\r\n?|\n|\f)|\\[\s\S])*\'/, null],
    --         ['lang-css-str', /^url\(([^\)\"\']*)\)/i],
    --         [PR['PR_KEYWORD'],
    --          /^(?:url|rgb|\!important|@import|@page|@media|@charset|inherit)(?=[^\-\w]|$)/i,
    --          null],
    --         // A property name -- an identifier followed by a colon.
    --         ['lang-css-kw', /^(-?(?:[_a-z]|(?:\\[0-9a-f]+ ?))(?:[_a-z0-9\-]|\\(?:\\[0-9a-f]+ ?))*)\s*:/i],
    --         // A C style block comment.  The <comment> production.
    --         [PR['PR_COMMENT'], /^\/\*[^*]*\*+(?:[^\/*][^*]*\*+)*\//],
    --         // Escaping text spans
    --         [PR['PR_COMMENT'], /^(?:<!--|-->)/],
    --         // A number possibly containing a suffix.
    --         [PR['PR_LITERAL'], /^(?:\d+|\d*\.\d+)(?:%|[a-z]+)?/i],
    --         // A hex color
    --         [PR['PR_LITERAL'], /^#(?:[0-9a-f]{3}){1,2}/i],
    --         // An identifier
    --         [PR['PR_PLAIN'],
    --          /^-?(?:[_a-z]|(?:\\[\da-f]+ ?))(?:[_a-z\d\-]|\\(?:\\[\da-f]+ ?))*/i],
    --         // A run of punctuation
    --         [PR['PR_PUNCTUATION'], /^[^\s\w\'\"]+/]
    --        ]),
    --    ['css']);
    --PR['registerLangHandler'](
    --    PR['createSimpleLexer']([],
    --        [
    --         [PR['PR_KEYWORD'],
    --          /^-?(?:[_a-z]|(?:\\[\da-f]+ ?))(?:[_a-z\d\-]|\\(?:\\[\da-f]+ ?))*/i]
    --        ]),
    --    ['css-kw']);
    --PR['registerLangHandler'](
    --    PR['createSimpleLexer']([],
    --        [
    --         [PR['PR_STRING'], /^[^\)\"\']+/]
    --        ]),
    --    ['css-str']);
    --
    --//third_party/javascript/google_code_prettify/src/lang-go.js
    --/**
    -- * @license Copyright (C) 2010 Google Inc.
    -- *
    -- * 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.
    -- */
    --
    --/**
    -- * @fileoverview
    -- * Registers a language handler for the Go language..
    -- * <p>
    -- * Based on the lexical grammar at 
    -- * http://golang.org/doc/go_spec.html#Lexical_elements
    -- * <p>
    -- * Go uses a minimal style for highlighting so the below does not distinguish
    -- * strings, keywords, literals, etc. by design.
    -- * From a discussion with the Go designers:
    -- * <pre>
    -- * On Thursday, July 22, 2010, Mike Samuel <...> wrote:
    -- * > On Thu, Jul 22, 2010, Rob 'Commander' Pike <...> wrote:
    -- * >> Personally, I would vote for the subdued style godoc presents at http://golang.org
    -- * >>
    -- * >> Not as fancy as some like, but a case can be made it's the official style.
    -- * >> If people want more colors, I wouldn't fight too hard, in the interest of
    -- * >> encouragement through familiarity, but even then I would ask to shy away
    -- * >> from technicolor starbursts.
    -- * >
    -- * > Like http://golang.org/pkg/go/scanner/ where comments are blue and all
    -- * > other content is black?  I can do that.
    -- * </pre>
    -- *
    -- * @author mikesamuel@gmail.com
    -- */
    --
    --PR['registerLangHandler'](
    --    PR['createSimpleLexer'](
    --        [
    --         // Whitespace is made up of spaces, tabs and newline characters.
    --         [PR['PR_PLAIN'],       /^[\t\n\r \xA0]+/, null, '\t\n\r \xA0'],
    --         // Not escaped as a string.  See note on minimalism above.
    --         [PR['PR_PLAIN'],       /^(?:\"(?:[^\"\\]|\\[\s\S])*(?:\"|$)|\'(?:[^\'\\]|\\[\s\S])+(?:\'|$))/, null, '"\'']
    --        ],
    --        [
    --         // Block comments are delimited by /* and */.
    --         // Single-line comments begin with // and extend to the end of a line.
    --         [PR['PR_COMMENT'],     /^(?:\/\/[^\r\n]*|\/\*[\s\S]*?\*\/)/],
    --         [PR['PR_PLAIN'],       /^(?:[^\/\"\']|\/(?![\/\*]))+/i]
    --        ]),
    --    ['go']);
    --
    --//third_party/javascript/google_code_prettify/src/lang-hs.js
    --/**
    -- * @license Copyright (C) 2009 Google Inc.
    -- *
    -- * 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.
    -- */
    --
    --/**
    -- * @fileoverview
    -- * Registers a language handler for Haskell.
    -- *
    -- *
    -- * To use, include prettify.js and this file in your HTML page.
    -- * Then put your code in an HTML tag like
    -- *      <pre class="prettyprint lang-hs">(my lisp code)</pre>
    -- * The lang-cl class identifies the language as common lisp.
    -- * This file supports the following language extensions:
    -- *     lang-cl - Common Lisp
    -- *     lang-el - Emacs Lisp
    -- *     lang-lisp - Lisp
    -- *     lang-scm - Scheme
    -- *
    -- *
    -- * I used http://www.informatik.uni-freiburg.de/~thiemann/haskell/haskell98-report-html/syntax-iso.html
    -- * as the basis, but ignore the way the ncomment production nests since this
    -- * makes the lexical grammar irregular.  It might be possible to support
    -- * ncomments using the lookbehind filter.
    -- *
    -- *
    -- * @author mikesamuel@gmail.com
    -- */
    --
    --PR['registerLangHandler'](
    --    PR['createSimpleLexer'](
    --        [
    --         // Whitespace
    --         // whitechar    ->    newline | vertab | space | tab | uniWhite
    --         // newline      ->    return linefeed | return | linefeed | formfeed
    --         [PR['PR_PLAIN'],       /^[\t\n\x0B\x0C\r ]+/, null, '\t\n\x0B\x0C\r '],
    --         // Single line double and single-quoted strings.
    --         // char         ->    ' (graphic<' | \> | space | escape<\&>) '
    --         // string       ->    " {graphic<" | \> | space | escape | gap}"
    --         // escape       ->    \ ( charesc | ascii | decimal | o octal
    --         //                        | x hexadecimal )
    --         // charesc      ->    a | b | f | n | r | t | v | \ | " | ' | &
    --         [PR['PR_STRING'],      /^\"(?:[^\"\\\n\x0C\r]|\\[\s\S])*(?:\"|$)/,
    --          null, '"'],
    --         [PR['PR_STRING'],      /^\'(?:[^\'\\\n\x0C\r]|\\[^&])\'?/,
    --          null, "'"],
    --         // decimal      ->    digit{digit}
    --         // octal        ->    octit{octit}
    --         // hexadecimal  ->    hexit{hexit}
    --         // integer      ->    decimal
    --         //               |    0o octal | 0O octal
    --         //               |    0x hexadecimal | 0X hexadecimal
    --         // float        ->    decimal . decimal [exponent]
    --         //               |    decimal exponent
    --         // exponent     ->    (e | E) [+ | -] decimal
    --         [PR['PR_LITERAL'],
    --          /^(?:0o[0-7]+|0x[\da-f]+|\d+(?:\.\d+)?(?:e[+\-]?\d+)?)/i,
    --          null, '0123456789']
    --        ],
    --        [
    --         // Haskell does not have a regular lexical grammar due to the nested
    --         // ncomment.
    --         // comment      ->    dashes [ any<symbol> {any}] newline
    --         // ncomment     ->    opencom ANYseq {ncomment ANYseq}closecom
    --         // dashes       ->    '--' {'-'}
    --         // opencom      ->    '{-'
    --         // closecom     ->    '-}'
    --         [PR['PR_COMMENT'],     /^(?:(?:--+(?:[^\r\n\x0C]*)?)|(?:\{-(?:[^-]|-+[^-\}])*-\}))/],
    --         // reservedid   ->    case | class | data | default | deriving | do
    --         //               |    else | if | import | in | infix | infixl | infixr
    --         //               |    instance | let | module | newtype | of | then
    --         //               |    type | where | _
    --         [PR['PR_KEYWORD'],     /^(?:case|class|data|default|deriving|do|else|if|import|in|infix|infixl|infixr|instance|let|module|newtype|of|then|type|where|_)(?=[^a-zA-Z0-9\']|$)/, null],
    --         // qvarid       ->    [ modid . ] varid
    --         // qconid       ->    [ modid . ] conid
    --         // varid        ->    (small {small | large | digit | ' })<reservedid>
    --         // conid        ->    large {small | large | digit | ' }
    --         // modid        ->    conid
    --         // small        ->    ascSmall | uniSmall | _
    --         // ascSmall     ->    a | b | ... | z
    --         // uniSmall     ->    any Unicode lowercase letter
    --         // large        ->    ascLarge | uniLarge
    --         // ascLarge     ->    A | B | ... | Z
    --         // uniLarge     ->    any uppercase or titlecase Unicode letter
    --         [PR['PR_PLAIN'],  /^(?:[A-Z][\w\']*\.)*[a-zA-Z][\w\']*/],
    --         // matches the symbol production
    --         [PR['PR_PUNCTUATION'], /^[^\t\n\x0B\x0C\r a-zA-Z0-9\'\"]+/]
    --        ]),
    --    ['hs']);
    --
    --//third_party/javascript/google_code_prettify/src/lang-lisp.js
    --/**
    -- * @license Copyright (C) 2008 Google Inc.
    -- *
    -- * 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.
    -- */
    --
    --/**
    -- * @fileoverview
    -- * Registers a language handler for Common Lisp and related languages.
    -- *
    -- *
    -- * To use, include prettify.js and this file in your HTML page.
    -- * Then put your code in an HTML tag like
    -- *      <pre class="prettyprint lang-lisp">(my lisp code)</pre>
    -- * The lang-cl class identifies the language as common lisp.
    -- * This file supports the following language extensions:
    -- *     lang-cl - Common Lisp
    -- *     lang-el - Emacs Lisp
    -- *     lang-lisp - Lisp
    -- *     lang-scm - Scheme
    -- *
    -- *
    -- * I used http://www.devincook.com/goldparser/doc/meta-language/grammar-LISP.htm
    -- * as the basis, but added line comments that start with ; and changed the atom
    -- * production to disallow unquoted semicolons.
    -- *
    -- * "Name"    = 'LISP'
    -- * "Author"  = 'John McCarthy'
    -- * "Version" = 'Minimal'
    -- * "About"   = 'LISP is an abstract language that organizes ALL'
    -- *           | 'data around "lists".'
    -- *
    -- * "Start Symbol" = [s-Expression]
    -- *
    -- * {Atom Char}   = {Printable} - {Whitespace} - [()"\'']
    -- *
    -- * Atom = ( {Atom Char} | '\'{Printable} )+
    -- *
    -- * [s-Expression] ::= [Quote] Atom
    -- *                  | [Quote] '(' [Series] ')'
    -- *                  | [Quote] '(' [s-Expression] '.' [s-Expression] ')'
    -- *
    -- * [Series] ::= [s-Expression] [Series]
    -- *            |
    -- *
    -- * [Quote]  ::= ''      !Quote = do not evaluate
    -- *            |
    -- *
    -- *
    -- * I used <a href="http://gigamonkeys.com/book/">Practical Common Lisp</a> as
    -- * the basis for the reserved word list.
    -- *
    -- *
    -- * @author mikesamuel@gmail.com
    -- */
    --
    --PR['registerLangHandler'](
    --    PR['createSimpleLexer'](
    --        [
    --         ['opn',             /^\(+/, null, '('],
    --         ['clo',             /^\)+/, null, ')'],
    --         // A line comment that starts with ;
    --         [PR['PR_COMMENT'],     /^;[^\r\n]*/, null, ';'],
    --         // Whitespace
    --         [PR['PR_PLAIN'],       /^[\t\n\r \xA0]+/, null, '\t\n\r \xA0'],
    --         // A double quoted, possibly multi-line, string.
    --         [PR['PR_STRING'],      /^\"(?:[^\"\\]|\\[\s\S])*(?:\"|$)/, null, '"']
    --        ],
    --        [
    --         [PR['PR_KEYWORD'],     /^(?:block|c[ad]+r|catch|con[ds]|def(?:ine|un)|do|eq|eql|equal|equalp|eval-when|flet|format|go|if|labels|lambda|let|load-time-value|locally|macrolet|multiple-value-call|nil|progn|progv|quote|require|return-from|setq|symbol-macrolet|t|tagbody|the|throw|unwind)\b/, null],
    --         [PR['PR_LITERAL'],
    --          /^[+\-]?(?:[0#]x[0-9a-f]+|\d+\/\d+|(?:\.\d+|\d+(?:\.\d*)?)(?:[ed][+\-]?\d+)?)/i],
    --         // A single quote possibly followed by a word that optionally ends with
    --         // = ! or ?.
    --         [PR['PR_LITERAL'],
    --          /^\'(?:-*(?:\w|\\[\x21-\x7e])(?:[\w-]*|\\[\x21-\x7e])[=!?]?)?/],
    --         // A word that optionally ends with = ! or ?.
    --         [PR['PR_PLAIN'],
    --          /^-*(?:[a-z_]|\\[\x21-\x7e])(?:[\w-]*|\\[\x21-\x7e])[=!?]?/i],
    --         // A printable non-space non-special character
    --         [PR['PR_PUNCTUATION'], /^[^\w\t\n\r \xA0()\"\\\';]+/]
    --        ]),
    --    ['cl', 'el', 'lisp', 'scm']);
    --
    --//third_party/javascript/google_code_prettify/src/lang-lua.js
    --/**
    -- * @license Copyright (C) 2008 Google Inc.
    -- *
    -- * 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.
    -- */
    --
    --/**
    -- * @fileoverview
    -- * Registers a language handler for Lua.
    -- *
    -- *
    -- * To use, include prettify.js and this file in your HTML page.
    -- * Then put your code in an HTML tag like
    -- *      <pre class="prettyprint lang-lua">(my Lua code)</pre>
    -- *
    -- *
    -- * I used http://www.lua.org/manual/5.1/manual.html#2.1
    -- * Because of the long-bracket concept used in strings and comments, Lua does
    -- * not have a regular lexical grammar, but luckily it fits within the space
    -- * of irregular grammars supported by javascript regular expressions.
    -- *
    -- * @author mikesamuel@gmail.com
    -- */
    --
    --PR['registerLangHandler'](
    --    PR['createSimpleLexer'](
    --        [
    --         // Whitespace
    --         [PR['PR_PLAIN'],       /^[\t\n\r \xA0]+/, null, '\t\n\r \xA0'],
    --         // A double or single quoted, possibly multi-line, string.
    --         [PR['PR_STRING'],      /^(?:\"(?:[^\"\\]|\\[\s\S])*(?:\"|$)|\'(?:[^\'\\]|\\[\s\S])*(?:\'|$))/, null, '"\'']
    --        ],
    --        [
    --         // A comment is either a line comment that starts with two dashes, or
    --         // two dashes preceding a long bracketed block.
    --         [PR['PR_COMMENT'], /^--(?:\[(=*)\[[\s\S]*?(?:\]\1\]|$)|[^\r\n]*)/],
    --         // A long bracketed block not preceded by -- is a string.
    --         [PR['PR_STRING'],  /^\[(=*)\[[\s\S]*?(?:\]\1\]|$)/],
    --         [PR['PR_KEYWORD'], /^(?:and|break|do|else|elseif|end|false|for|function|if|in|local|nil|not|or|repeat|return|then|true|until|while)\b/, null],
    --         // A number is a hex integer literal, a decimal real literal, or in
    --         // scientific notation.
    --         [PR['PR_LITERAL'],
    --          /^[+-]?(?:0x[\da-f]+|(?:(?:\.\d+|\d+(?:\.\d*)?)(?:e[+\-]?\d+)?))/i],
    --         // An identifier
    --         [PR['PR_PLAIN'], /^[a-z_]\w*/i],
    --         // A run of punctuation
    --         [PR['PR_PUNCTUATION'], /^[^\w\t\n\r \xA0][^\w\t\n\r \xA0\"\'\-\+=]*/]
    --        ]),
    --    ['lua']);
    --
    --//third_party/javascript/google_code_prettify/src/lang-ml.js
    --/**
    -- * @license Copyright (C) 2008 Google Inc.
    -- *
    -- * 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.
    -- */
    --
    --/**
    -- * @fileoverview
    -- * Registers a language handler for OCaml, SML, F# and similar languages.
    -- *
    -- * Based on the lexical grammar at
    -- * http://research.microsoft.com/en-us/um/cambridge/projects/fsharp/manual/spec.html#_Toc270597388
    -- *
    -- * @author mikesamuel@gmail.com
    -- */
    --
    --PR['registerLangHandler'](
    --    PR['createSimpleLexer'](
    --        [
    --         // Whitespace is made up of spaces, tabs and newline characters.
    --         [PR['PR_PLAIN'],       /^[\t\n\r \xA0]+/, null, '\t\n\r \xA0'],
    --         // #if ident/#else/#endif directives delimit conditional compilation
    --         // sections
    --         [PR['PR_COMMENT'],
    --          /^#(?:if[\t\n\r \xA0]+(?:[a-z_$][\w\']*|``[^\r\n\t`]*(?:``|$))|else|endif|light)/i,
    --          null, '#'],
    --         // A double or single quoted, possibly multi-line, string.
    --         // F# allows escaped newlines in strings.
    --         [PR['PR_STRING'],      /^(?:\"(?:[^\"\\]|\\[\s\S])*(?:\"|$)|\'(?:[^\'\\]|\\[\s\S])(?:\'|$))/, null, '"\'']
    --        ],
    --        [
    --         // Block comments are delimited by (* and *) and may be
    --         // nested. Single-line comments begin with // and extend to
    --         // the end of a line.
    --         // TODO: (*...*) comments can be nested.  This does not handle that.
    --         [PR['PR_COMMENT'],     /^(?:\/\/[^\r\n]*|\(\*[\s\S]*?\*\))/],
    --         [PR['PR_KEYWORD'],     /^(?:abstract|and|as|assert|begin|class|default|delegate|do|done|downcast|downto|elif|else|end|exception|extern|false|finally|for|fun|function|if|in|inherit|inline|interface|internal|lazy|let|match|member|module|mutable|namespace|new|null|of|open|or|override|private|public|rec|return|static|struct|then|to|true|try|type|upcast|use|val|void|when|while|with|yield|asr|land|lor|lsl|lsr|lxor|mod|sig|atomic|break|checked|component|const|constraint|constructor|continue|eager|event|external|fixed|functor|global|include|method|mixin|object|parallel|process|protected|pure|sealed|trait|virtual|volatile)\b/],
    --         // A number is a hex integer literal, a decimal real literal, or in
    --         // scientific notation.
    --         [PR['PR_LITERAL'],
    --          /^[+\-]?(?:0x[\da-f]+|(?:(?:\.\d+|\d+(?:\.\d*)?)(?:e[+\-]?\d+)?))/i],
    --         [PR['PR_PLAIN'],       /^(?:[a-z_][\w']*[!?#]?|``[^\r\n\t`]*(?:``|$))/i],
    --         // A printable non-space non-special character
    --         [PR['PR_PUNCTUATION'], /^[^\t\n\r \xA0\"\'\w]+/]
    --        ]),
    --    ['fs', 'ml']);
    --
    --//third_party/javascript/google_code_prettify/src/lang-proto.js
    --/**
    -- * @license Copyright (C) 2006 Google Inc.
    -- *
    -- * 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.
    -- */
    --
    --/**
    -- * @fileoverview
    -- * Registers a language handler for Protocol Buffers as described at
    -- * http://code.google.com/p/protobuf/.
    -- *
    -- * Based on the lexical grammar at
    -- * http://research.microsoft.com/fsharp/manual/spec2.aspx#_Toc202383715
    -- *
    -- * @author mikesamuel@gmail.com
    -- */
    --
    --PR['registerLangHandler'](PR['sourceDecorator']({
    --        keywords: (
    --            'bool bytes default double enum extend extensions false fixed32 '
    --            + 'fixed64 float group import int32 int64 max message option '
    --            + 'optional package repeated required returns rpc service '
    --            + 'sfixed32 sfixed64 sint32 sint64 string syntax to true uint32 '
    --            + 'uint64'),
    --        cStyleComments: true
    --      }), ['proto']);
    --
    --//third_party/javascript/google_code_prettify/src/lang-scala.js
    --/**
    -- * @license Copyright (C) 2010 Google Inc.
    -- *
    -- * 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.
    -- */
    --
    --/**
    -- * @fileoverview
    -- * Registers a language handler for Scala.
    -- *
    -- * Derived from http://lampsvn.epfl.ch/svn-repos/scala/scala-documentation/trunk/src/reference/SyntaxSummary.tex
    -- *
    -- * @author mikesamuel@gmail.com
    -- */
    --
    --PR['registerLangHandler'](
    --    PR['createSimpleLexer'](
    --        [
    --         // Whitespace
    --         [PR['PR_PLAIN'],       /^[\t\n\r \xA0]+/, null, '\t\n\r \xA0'],
    --         // A double or single quoted string
    --          // or a triple double-quoted multi-line string.
    --         [PR['PR_STRING'],
    --          /^(?:"(?:(?:""(?:""?(?!")|[^\\"]|\\.)*"{0,3})|(?:[^"\r\n\\]|\\.)*"?))/,
    --          null, '"'],
    --         [PR['PR_LITERAL'],     /^`(?:[^\r\n\\`]|\\.)*`?/, null, '`'],
    --         [PR['PR_PUNCTUATION'], /^[!#%&()*+,\-:;<=>?@\[\\\]^{|}~]+/, null,
    --          '!#%&()*+,-:;<=>?@[\\]^{|}~']
    --        ],
    --        [
    --         // A symbol literal is a single quote followed by an identifier with no
    --         // single quote following
    --         // A character literal has single quotes on either side
    --         [PR['PR_STRING'],      /^'(?:[^\r\n\\']|\\(?:'|[^\r\n']+))'/],
    --         [PR['PR_LITERAL'],     /^'[a-zA-Z_$][\w$]*(?!['$\w])/],
    --         [PR['PR_KEYWORD'],     /^(?:abstract|case|catch|class|def|do|else|extends|final|finally|for|forSome|if|implicit|import|lazy|match|new|object|override|package|private|protected|requires|return|sealed|super|throw|trait|try|type|val|var|while|with|yield)\b/],
    --         [PR['PR_LITERAL'],     /^(?:true|false|null|this)\b/],
    --         [PR['PR_LITERAL'],     /^(?:(?:0(?:[0-7]+|X[0-9A-F]+))L?|(?:(?:0|[1-9][0-9]*)(?:(?:\.[0-9]+)?(?:E[+\-]?[0-9]+)?F?|L?))|\\.[0-9]+(?:E[+\-]?[0-9]+)?F?)/i],
    --         // Treat upper camel case identifiers as types.
    --         [PR['PR_TYPE'],        /^[$_]*[A-Z][_$A-Z0-9]*[a-z][\w$]*/],
    --         [PR['PR_PLAIN'],       /^[$a-zA-Z_][\w$]*/],
    --         [PR['PR_COMMENT'],     /^\/(?:\/.*|\*(?:\/|\**[^*/])*(?:\*+\/?)?)/],
    --         [PR['PR_PUNCTUATION'], /^(?:\.+|\/)/]
    --        ]),
    --    ['scala']);
    --
    --//third_party/javascript/google_code_prettify/src/lang-sql.js
    --/**
    -- * @license Copyright (C) 2008 Google Inc.
    -- *
    -- * 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.
    -- */
    --
    --
    --/**
    -- * @fileoverview
    -- * Registers a language handler for SQL.
    -- *
    -- *
    -- * To use, include prettify.js and this file in your HTML page.
    -- * Then put your code in an HTML tag like
    -- *      <pre class="prettyprint lang-sql">(my SQL code)</pre>
    -- *
    -- *
    -- * http://savage.net.au/SQL/sql-99.bnf.html is the basis for the grammar, and
    -- * http://msdn.microsoft.com/en-us/library/aa238507(SQL.80).aspx as the basis
    -- * for the keyword list.
    -- *
    -- * @author mikesamuel@gmail.com
    -- */
    --
    --PR['registerLangHandler'](
    --    PR['createSimpleLexer'](
    --        [
    --         // Whitespace
    --         [PR['PR_PLAIN'],       /^[\t\n\r \xA0]+/, null, '\t\n\r \xA0'],
    --         // A double or single quoted, possibly multi-line, string.
    --         [PR['PR_STRING'],      /^(?:"(?:[^\"\\]|\\.)*"|'(?:[^\'\\]|\\.)*')/, null,
    --          '"\'']
    --        ],
    --        [
    --         // A comment is either a line comment that starts with two dashes, or
    --         // two dashes preceding a long bracketed block.
    --         [PR['PR_COMMENT'], /^(?:--[^\r\n]*|\/\*[\s\S]*?(?:\*\/|$))/],
    --         [PR['PR_KEYWORD'], /^(?:ADD|ALL|ALTER|AND|ANY|AS|ASC|AUTHORIZATION|BACKUP|BEGIN|BETWEEN|BREAK|BROWSE|BULK|BY|CASCADE|CASE|CHECK|CHECKPOINT|CLOSE|CLUSTERED|COALESCE|COLLATE|COLUMN|COMMIT|COMPUTE|CONSTRAINT|CONTAINS|CONTAINSTABLE|CONTINUE|CONVERT|CREATE|CROSS|CURRENT|CURRENT_DATE|CURRENT_TIME|CURRENT_TIMESTAMP|CURRENT_USER|CURSOR|DATABASE|DBCC|DEALLOCATE|DECLARE|DEFAULT|DELETE|DENY|DESC|DISK|DISTINCT|DISTRIBUTED|DOUBLE|DROP|DUMMY|DUMP|ELSE|END|ERRLVL|ESCAPE|EXCEPT|EXEC|EXECUTE|EXISTS|EXIT|FETCH|FILE|FILLFACTOR|FOR|FOREIGN|FREETEXT|FREETEXTTABLE|FROM|FULL|FUNCTION|GOTO|GRANT|GROUP|HAVING|HOLDLOCK|IDENTITY|IDENTITYCOL|IDENTITY_INSERT|IF|IN|INDEX|INNER|INSERT|INTERSECT|INTO|IS|JOIN|KEY|KILL|LEFT|LIKE|LINENO|LOAD|NATIONAL|NOCHECK|NONCLUSTERED|NOT|NULL|NULLIF|OF|OFF|OFFSETS|ON|OPEN|OPENDATASOURCE|OPENQUERY|OPENROWSET|OPENXML|OPTION|OR|ORDER|OUTER|OVER|PERCENT|PLAN|PRECISION|PRIMARY|PRINT|PROC|PROCEDURE|PUBLIC|RAISERROR|READ|READTEXT|RECONFIGURE|REFERENCES|REPLICATION|RESTORE|RESTRICT|RETURN|REVOKE|RIGHT|ROLLBACK|ROWCOUNT|ROWGUIDCOL|RULE|SAVE|SCHEMA|SELECT|SESSION_USER|SET|SETUSER|SHUTDOWN|SOME|STATISTICS|SYSTEM_USER|TABLE|TEXTSIZE|THEN|TO|TOP|TRAN|TRANSACTION|TRIGGER|TRUNCATE|TSEQUAL|UNION|UNIQUE|UPDATE|UPDATETEXT|USE|USER|VALUES|VARYING|VIEW|WAITFOR|WHEN|WHERE|WHILE|WITH|WRITETEXT)(?=[^\w-]|$)/i, null],
    --         // A number is a hex integer literal, a decimal real literal, or in
    --         // scientific notation.
    --         [PR['PR_LITERAL'],
    --          /^[+-]?(?:0x[\da-f]+|(?:(?:\.\d+|\d+(?:\.\d*)?)(?:e[+\-]?\d+)?))/i],
    --         // An identifier
    --         [PR['PR_PLAIN'], /^[a-z_][\w-]*/i],
    --         // A run of punctuation
    --         [PR['PR_PUNCTUATION'], /^[^\w\t\n\r \xA0\"\'][^\w\t\n\r \xA0+\-\"\']*/]
    --        ]),
    --    ['sql']);
    --
    --//third_party/javascript/google_code_prettify/src/lang-vb.js
    --/**
    -- * @license Copyright (C) 2009 Google Inc.
    -- *
    -- * 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.
    -- */
    --
    --
    --
    --/**
    -- * @fileoverview
    -- * Registers a language handler for various flavors of basic.
    -- *
    -- *
    -- * To use, include prettify.js and this file in your HTML page.
    -- * Then put your code in an HTML tag like
    -- *      <pre class="prettyprint lang-vb"></pre>
    -- *
    -- *
    -- * http://msdn.microsoft.com/en-us/library/aa711638(VS.71).aspx defines the
    -- * visual basic grammar lexical grammar.
    -- *
    -- * @author mikesamuel@gmail.com
    -- */
    --
    --PR['registerLangHandler'](
    --    PR['createSimpleLexer'](
    --        [
    --         // Whitespace
    --         [PR['PR_PLAIN'],       /^[\t\n\r \xA0\u2028\u2029]+/, null, '\t\n\r \xA0\u2028\u2029'],
    --         // A double quoted string with quotes escaped by doubling them.
    --         // A single character can be suffixed with C.
    --         [PR['PR_STRING'],      /^(?:[\"\u201C\u201D](?:[^\"\u201C\u201D]|[\"\u201C\u201D]{2})(?:[\"\u201C\u201D]c|$)|[\"\u201C\u201D](?:[^\"\u201C\u201D]|[\"\u201C\u201D]{2})*(?:[\"\u201C\u201D]|$))/i, null,
    --          '"\u201C\u201D'],
    --         // A comment starts with a single quote and runs until the end of the
    --         // line.
    --         [PR['PR_COMMENT'],     /^[\'\u2018\u2019][^\r\n\u2028\u2029]*/, null, '\'\u2018\u2019']
    --        ],
    --        [
    --         [PR['PR_KEYWORD'], /^(?:AddHandler|AddressOf|Alias|And|AndAlso|Ansi|As|Assembly|Auto|Boolean|ByRef|Byte|ByVal|Call|Case|Catch|CBool|CByte|CChar|CDate|CDbl|CDec|Char|CInt|Class|CLng|CObj|Const|CShort|CSng|CStr|CType|Date|Decimal|Declare|Default|Delegate|Dim|DirectCast|Do|Double|Each|Else|ElseIf|End|EndIf|Enum|Erase|Error|Event|Exit|Finally|For|Friend|Function|Get|GetType|GoSub|GoTo|Handles|If|Implements|Imports|In|Inherits|Integer|Interface|Is|Let|Lib|Like|Long|Loop|Me|Mod|Module|MustInherit|MustOverride|MyBase|MyClass|Namespace|New|Next|Not|NotInheritable|NotOverridable|Object|On|Option|Optional|Or|OrElse|Overloads|Overridable|Overrides|ParamArray|Preserve|Private|Property|Protected|Public|RaiseEvent|ReadOnly|ReDim|RemoveHandler|Resume|Return|Select|Set|Shadows|Shared|Short|Single|Static|Step|Stop|String|Structure|Sub|SyncLock|Then|Throw|To|Try|TypeOf|Unicode|Until|Variant|Wend|When|While|With|WithEvents|WriteOnly|Xor|EndIf|GoSub|Let|Variant|Wend)\b/i, null],
    --         // A second comment form
    --         [PR['PR_COMMENT'], /^REM[^\r\n\u2028\u2029]*/i],
    --         // A boolean, numeric, or date literal.
    --         [PR['PR_LITERAL'],
    --          /^(?:True\b|False\b|Nothing\b|\d+(?:E[+\-]?\d+[FRD]?|[FRDSIL])?|(?:&H[0-9A-F]+|&O[0-7]+)[SIL]?|\d*\.\d+(?:E[+\-]?\d+)?[FRD]?|#\s+(?:\d+[\-\/]\d+[\-\/]\d+(?:\s+\d+:\d+(?::\d+)?(\s*(?:AM|PM))?)?|\d+:\d+(?::\d+)?(\s*(?:AM|PM))?)\s+#)/i],
    --         // An identifier?
    --         [PR['PR_PLAIN'], /^(?:(?:[a-z]|_\w)\w*|\[(?:[a-z]|_\w)\w*\])/i],
    --         // A run of punctuation
    --         [PR['PR_PUNCTUATION'],
    --          /^[^\w\t\n\r \"\'\[\]\xA0\u2018\u2019\u201C\u201D\u2028\u2029]+/],
    --         // Square brackets
    --         [PR['PR_PUNCTUATION'], /^(?:\[|\])/]
    --        ]),
    --    ['vb', 'vbs']);
    --
    --//third_party/javascript/google_code_prettify/src/lang-vhdl.js
    --/**
    -- * @fileoverview
    -- * Registers a language handler for VHDL '93.
    -- *
    -- * Based on the lexical grammar and keywords at
    -- * http://www.iis.ee.ethz.ch/~zimmi/download/vhdl93_syntax.html
    -- *
    -- * @author benoit@ryder.fr
    -- */
    --
    --PR['registerLangHandler'](
    --    PR['createSimpleLexer'](
    --        [
    --         // Whitespace
    --         [PR['PR_PLAIN'], /^[\t\n\r \xA0]+/, null, '\t\n\r \xA0']
    --        ],
    --        [
    --         // String, character or bit string
    --         [PR['PR_STRING'], /^(?:[BOX]?"(?:[^\"]|"")*"|'.')/i],
    --         // Comment, from two dashes until end of line.
    --         [PR['PR_COMMENT'], /^--[^\r\n]*/],
    --         [PR['PR_KEYWORD'], /^(?:abs|access|after|alias|all|and|architecture|array|assert|attribute|begin|block|body|buffer|bus|case|component|configuration|constant|disconnect|downto|else|elsif|end|entity|exit|file|for|function|generate|generic|group|guarded|if|impure|in|inertial|inout|is|label|library|linkage|literal|loop|map|mod|nand|new|next|nor|not|null|of|on|open|or|others|out|package|port|postponed|procedure|process|pure|range|record|register|reject|rem|report|return|rol|ror|select|severity|shared|signal|sla|sll|sra|srl|subtype|then|to|transport|type|unaffected|units|until|use|variable|wait|when|while|with|xnor|xor)(?=[^\w-]|$)/i, null],
    --         // Type, predefined or standard
    --         [PR['PR_TYPE'], /^(?:bit|bit_vector|character|boolean|integer|real|time|string|severity_level|positive|natural|signed|unsigned|line|text|std_u?logic(?:_vector)?)(?=[^\w-]|$)/i, null],
    --         // Predefined attributes
    --         [PR['PR_TYPE'], /^\'(?:ACTIVE|ASCENDING|BASE|DELAYED|DRIVING|DRIVING_VALUE|EVENT|HIGH|IMAGE|INSTANCE_NAME|LAST_ACTIVE|LAST_EVENT|LAST_VALUE|LEFT|LEFTOF|LENGTH|LOW|PATH_NAME|POS|PRED|QUIET|RANGE|REVERSE_RANGE|RIGHT|RIGHTOF|SIMPLE_NAME|STABLE|SUCC|TRANSACTION|VAL|VALUE)(?=[^\w-]|$)/i, null],
    --         // Number, decimal or based literal
    --         [PR['PR_LITERAL'], /^\d+(?:_\d+)*(?:#[\w\\.]+#(?:[+\-]?\d+(?:_\d+)*)?|(?:\.\d+(?:_\d+)*)?(?:E[+\-]?\d+(?:_\d+)*)?)/i],
    --         // Identifier, basic or extended
    --         [PR['PR_PLAIN'], /^(?:[a-z]\w*|\\[^\\]*\\)/i],
    --         // Punctuation
    --         [PR['PR_PUNCTUATION'], /^[^\w\t\n\r \xA0\"\'][^\w\t\n\r \xA0\-\"\']*/]
    --        ]),
    --    ['vhdl', 'vhd']);
    --
    --//third_party/javascript/google_code_prettify/src/lang-wiki.js
    --/**
    -- * @license Copyright (C) 2009 Google Inc.
    -- *
    -- * 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.
    -- */
    --
    --/**
    -- * @fileoverview
    -- * Registers a language handler for Wiki pages.
    -- *
    -- * Based on WikiSyntax at http://code.google.com/p/support/wiki/WikiSyntax
    -- *
    -- * @author mikesamuel@gmail.com
    -- */
    --
    --PR['registerLangHandler'](
    --    PR['createSimpleLexer'](
    --        [
    --         // Whitespace
    --         [PR['PR_PLAIN'],       /^[\t \xA0a-gi-z0-9]+/, null,
    --          '\t \xA0abcdefgijklmnopqrstuvwxyz0123456789'],
    --         // Wiki formatting
    --         [PR['PR_PUNCTUATION'], /^[=*~\^\[\]]+/, null, '=*~^[]']
    --        ],
    --        [
    --         // Meta-info like #summary, #labels, etc.
    --         ['lang-wiki.meta',  /(?:^^|\r\n?|\n)(#[a-z]+)\b/],
    --         // A WikiWord
    --         [PR['PR_LITERAL'],     /^(?:[A-Z][a-z][a-z0-9]+[A-Z][a-z][a-zA-Z0-9]+)\b/
    --          ],
    --         // A preformatted block in an unknown language
    --         ['lang-',           /^\{\{\{([\s\S]+?)\}\}\}/],
    --         // A block of source code in an unknown language
    --         ['lang-',           /^`([^\r\n`]+)`/],
    --         // An inline URL.
    --         [PR['PR_STRING'],
    --          /^https?:\/\/[^\/?#\s]*(?:\/[^?#\s]*)?(?:\?[^#\s]*)?(?:#\S*)?/i],
    --         [PR['PR_PLAIN'],       /^(?:\r\n|[\s\S])[^#=*~^A-Zh\{`\[\r\n]*/]
    --        ]),
    --    ['wiki']);
    --
    --PR['registerLangHandler'](
    --    PR['createSimpleLexer']([[PR['PR_KEYWORD'], /^#[a-z]+/i, null, '#']], []),
    --    ['wiki.meta']);
    --
    --//third_party/javascript/google_code_prettify/src/lang-yaml.js
    --/** Contributed by ribrdb @ code.google.com
    -- */
    --
    --/**
    -- * @fileoverview
    -- * Registers a language handler for YAML.
    -- *
    -- * @author ribrdb
    -- */
    --
    --PR['registerLangHandler'](
    --  PR['createSimpleLexer'](
    --    [
    --      [PR['PR_PUNCTUATION'], /^[:|>?]+/, null, ':|>?'],
    --      [PR['PR_DECLARATION'],  /^%(?:YAML|TAG)[^#\r\n]+/, null, '%'],
    --      [PR['PR_TYPE'], /^[&]\S+/, null, '&'],
    --      [PR['PR_TYPE'], /^!\S*/, null, '!'],
    --      [PR['PR_STRING'], /^"(?:[^\\"]|\\.)*(?:"|$)/, null, '"'],
    --      [PR['PR_STRING'], /^'(?:[^']|'')*(?:'|$)/, null, "'"],
    --      [PR['PR_COMMENT'], /^#[^\r\n]*/, null, '#'],
    --      [PR['PR_PLAIN'], /^\s+/, null, ' \t\r\n']
    --    ],
    --    [
    --      [PR['PR_DECLARATION'], /^(?:---|\.\.\.)(?:[\r\n]|$)/],
    --      [PR['PR_PUNCTUATION'], /^-/],
    --      [PR['PR_KEYWORD'], /^\w+:[ \r\n]/],
    --      [PR['PR_PLAIN'], /^\w+/]
    --    ]), ['yaml', 'yml']);
    --
    --//third_party/javascript/jquery/v1_7_2/jquery-1.7.2.min.js
    --/**
    -- * @license jQuery JavaScript Library v1.7.2
    -- * http://jquery.com/
    -- *
    -- * Copyright 2011, John Resig
    -- * Dual licensed under the MIT or GPL Version 2 licenses.
    -- * http://jquery.org/license
    -- *
    -- * Includes Sizzle.js
    -- * http://sizzlejs.com/
    -- * Copyright 2011, The Dojo Foundation
    -- * Released under the MIT, BSD, and GPL Licenses.
    -- *
    -- * Date: Wed Mar 21 12:46:34 2012 -0700
    -- */
    --(function(a,b){function cy(a){return f.isWindow(a)?a:a.nodeType===9?a.defaultView||a.parentWindow:!1}function cu(a){if(!cj[a]){var b=c.body,d=f("<"+a+">").appendTo(b),e=d.css("display");d.remove();if(e==="none"||e===""){ck||(ck=c.createElement("iframe"),ck.frameBorder=ck.width=ck.height=0),b.appendChild(ck);if(!cl||!ck.createElement)cl=(ck.contentWindow||ck.contentDocument).document,cl.write((f.support.boxModel?"<!doctype html>":"")+"<html><body>"),cl.close();d=cl.createElement(a),cl.body.appendChild(d),e=f.css(d,"display"),b.removeChild(ck)}cj[a]=e}return cj[a]}function ct(a,b){var c={};f.each(cp.concat.apply([],cp.slice(0,b)),function(){c[this]=a});return c}function cs(){cq=b}function cr(){setTimeout(cs,0);return cq=f.now()}function ci(){try{return new a.ActiveXObject("Microsoft.XMLHTTP")}catch(b){}}function ch(){try{return new a.XMLHttpRequest}catch(b){}}function cb(a,c){a.dataFilter&&(c=a.dataFilter(c,a.dataType));var d=a.dataTypes,e={},g,h,i=d.length,j,k=d[0],l,m,n,o,p;for(g=1;g<i;g++){if(g===1)for(h in a.converters)typeof h=="string"&&(e[h.toLowerCase()]=a.converters[h]);l=k,k=d[g];if(k==="*")k=l;else if(l!=="*"&&l!==k){m=l+" "+k,n=e[m]||e["* "+k];if(!n){p=b;for(o in e){j=o.split(" ");if(j[0]===l||j[0]==="*"){p=e[j[1]+" "+k];if(p){o=e[o],o===!0?n=p:p===!0&&(n=o);break}}}}!n&&!p&&f.error("No conversion from "+m.replace(" "," to ")),n!==!0&&(c=n?n(c):p(o(c)))}}return c}function ca(a,c,d){var e=a.contents,f=a.dataTypes,g=a.responseFields,h,i,j,k;for(i in g)i in d&&(c[g[i]]=d[i]);while(f[0]==="*")f.shift(),h===b&&(h=a.mimeType||c.getResponseHeader("content-type"));if(h)for(i in e)if(e[i]&&e[i].test(h)){f.unshift(i);break}if(f[0]in d)j=f[0];else{for(i in d){if(!f[0]||a.converters[i+" "+f[0]]){j=i;break}k||(k=i)}j=j||k}if(j){j!==f[0]&&f.unshift(j);return d[j]}}function b_(a,b,c,d){if(f.isArray(b))f.each(b,function(b,e){c||bD.test(a)?d(a,e):b_(a+"["+(typeof e=="object"?b:"")+"]",e,c,d)});else if(!c&&f.type(b)==="object")for(var e in b)b_(a+"["+e+"]",b[e],c,d);else d(a,b)}function b$(a,c){var d,e,g=f.ajaxSettings.flatOptions||{};for(d in c)c[d]!==b&&((g[d]?a:e||(e={}))[d]=c[d]);e&&f.extend(!0,a,e)}function bZ(a,c,d,e,f,g){f=f||c.dataTypes[0],g=g||{},g[f]=!0;var h=a[f],i=0,j=h?h.length:0,k=a===bS,l;for(;i<j&&(k||!l);i++)l=h[i](c,d,e),typeof l=="string"&&(!k||g[l]?l=b:(c.dataTypes.unshift(l),l=bZ(a,c,d,e,l,g)));(k||!l)&&!g["*"]&&(l=bZ(a,c,d,e,"*",g));return l}function bY(a){return function(b,c){typeof b!="string"&&(c=b,b="*");if(f.isFunction(c)){var d=b.toLowerCase().split(bO),e=0,g=d.length,h,i,j;for(;e<g;e++)h=d[e],j=/^\+/.test(h),j&&(h=h.substr(1)||"*"),i=a[h]=a[h]||[],i[j?"unshift":"push"](c)}}}function bB(a,b,c){var d=b==="width"?a.offsetWidth:a.offsetHeight,e=b==="width"?1:0,g=4;if(d>0){if(c!=="border")for(;e<g;e+=2)c||(d-=parseFloat(f.css(a,"padding"+bx[e]))||0),c==="margin"?d+=parseFloat(f.css(a,c+bx[e]))||0:d-=parseFloat(f.css(a,"border"+bx[e]+"Width"))||0;return d+"px"}d=by(a,b);if(d<0||d==null)d=a.style[b];if(bt.test(d))return d;d=parseFloat(d)||0;if(c)for(;e<g;e+=2)d+=parseFloat(f.css(a,"padding"+bx[e]))||0,c!=="padding"&&(d+=parseFloat(f.css(a,"border"+bx[e]+"Width"))||0),c==="margin"&&(d+=parseFloat(f.css(a,c+bx[e]))||0);return d+"px"}function bo(a){var b=c.createElement("div");bh.appendChild(b),b.innerHTML=a.outerHTML;return b.firstChild}function bn(a){var b=(a.nodeName||"").toLowerCase();b==="input"?bm(a):b!=="script"&&typeof a.getElementsByTagName!="undefined"&&f.grep(a.getElementsByTagName("input"),bm)}function bm(a){if(a.type==="checkbox"||a.type==="radio")a.defaultChecked=a.checked}function bl(a){return typeof a.getElementsByTagName!="undefined"?a.getElementsByTagName("*"):typeof a.querySelectorAll!="undefined"?a.querySelectorAll("*"):[]}function bk(a,b){var c;b.nodeType===1&&(b.clearAttributes&&b.clearAttributes(),b.mergeAttributes&&b.mergeAttributes(a),c=b.nodeName.toLowerCase(),c==="object"?b.outerHTML=a.outerHTML:c!=="input"||a.type!=="checkbox"&&a.type!=="radio"?c==="option"?b.selected=a.defaultSelected:c==="input"||c==="textarea"?b.defaultValue=a.defaultValue:c==="script"&&b.text!==a.text&&(b.text=a.text):(a.checked&&(b.defaultChecked=b.checked=a.checked),b.value!==a.value&&(b.value=a.value)),b.removeAttribute(f.expando),b.removeAttribute("_submit_attached"),b.removeAttribute("_change_attached"))}function bj(a,b){if(b.nodeType===1&&!!f.hasData(a)){var c,d,e,g=f._data(a),h=f._data(b,g),i=g.events;if(i){delete h.handle,h.events={};for(c in i)for(d=0,e=i[c].length;d<e;d++)f.event.add(b,c,i[c][d])}h.data&&(h.data=f.extend({},h.data))}}function bi(a,b){return f.nodeName(a,"table")?a.getElementsByTagName("tbody")[0]||a.appendChild(a.ownerDocument.createElement("tbody")):a}function U(a){var b=V.split("|"),c=a.createDocumentFragment();if(c.createElement)while(b.length)c.createElement(b.pop());return c}function T(a,b,c){b=b||0;if(f.isFunction(b))return f.grep(a,function(a,d){var e=!!b.call(a,d,a);return e===c});if(b.nodeType)return f.grep(a,function(a,d){return a===b===c});if(typeof b=="string"){var d=f.grep(a,function(a){return a.nodeType===1});if(O.test(b))return f.filter(b,d,!c);b=f.filter(b,d)}return f.grep(a,function(a,d){return f.inArray(a,b)>=0===c})}function S(a){return!a||!a.parentNode||a.parentNode.nodeType===11}function K(){return!0}function J(){return!1}function n(a,b,c){var d=b+"defer",e=b+"queue",g=b+"mark",h=f._data(a,d);h&&(c==="queue"||!f._data(a,e))&&(c==="mark"||!f._data(a,g))&&setTimeout(function(){!f._data(a,e)&&!f._data(a,g)&&(f.removeData(a,d,!0),h.fire())},0)}function m(a){for(var b in a){if(b==="data"&&f.isEmptyObject(a[b]))continue;if(b!=="toJSON")return!1}return!0}function l(a,c,d){if(d===b&&a.nodeType===1){var e="data-"+c.replace(k,"-$1").toLowerCase();d=a.getAttribute(e);if(typeof d=="string"){try{d=d==="true"?!0:d==="false"?!1:d==="null"?null:f.isNumeric(d)?+d:j.test(d)?f.parseJSON(d):d}catch(g){}f.data(a,c,d)}else d=b}return d}function h(a){var b=g[a]={},c,d;a=a.split(/\s+/);for(c=0,d=a.length;c<d;c++)b[a[c]]=!0;return b}var c=a.document,d=a.navigator,e=a.location,f=function(){function J(){if(!e.isReady){try{c.documentElement.doScroll("left")}catch(a){setTimeout(J,1);return}e.ready()}}var e=function(a,b){return new e.fn.init(a,b,h)},f=a.jQuery,g=a.$,h,i=/^(?:[^#<]*(<[\w\W]+>)[^>]*$|#([\w\-]*)$)/,j=/\S/,k=/^\s+/,l=/\s+$/,m=/^<(\w+)\s*\/?>(?:<\/\1>)?$/,n=/^[\],:{}\s]*$/,o=/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g,p=/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g,q=/(?:^|:|,)(?:\s*\[)+/g,r=/(webkit)[ \/]([\w.]+)/,s=/(opera)(?:.*version)?[ \/]([\w.]+)/,t=/(msie) ([\w.]+)/,u=/(mozilla)(?:.*? rv:([\w.]+))?/,v=/-([a-z]|[0-9])/ig,w=/^-ms-/,x=function(a,b){return(b+"").toUpperCase()},y=d.userAgent,z,A,B,C=Object.prototype.toString,D=Object.prototype.hasOwnProperty,E=Array.prototype.push,F=Array.prototype.slice,G=String.prototype.trim,H=Array.prototype.indexOf,I={};e.fn=e.prototype={constructor:e,init:function(a,d,f){var g,h,j,k;if(!a)return this;if(a.nodeType){this.context=this[0]=a,this.length=1;return this}if(a==="body"&&!d&&c.body){this.context=c,this[0]=c.body,this.selector=a,this.length=1;return this}if(typeof a=="string"){a.charAt(0)!=="<"||a.charAt(a.length-1)!==">"||a.length<3?g=i.exec(a):g=[null,a,null];if(g&&(g[1]||!d)){if(g[1]){d=d instanceof e?d[0]:d,k=d?d.ownerDocument||d:c,j=m.exec(a),j?e.isPlainObject(d)?(a=[c.createElement(j[1])],e.fn.attr.call(a,d,!0)):a=[k.createElement(j[1])]:(j=e.buildFragment([g[1]],[k]),a=(j.cacheable?e.clone(j.fragment):j.fragment).childNodes);return e.merge(this,a)}h=c.getElementById(g[2]);if(h&&h.parentNode){if(h.id!==g[2])return f.find(a);this.length=1,this[0]=h}this.context=c,this.selector=a;return this}return!d||d.jquery?(d||f).find(a):this.constructor(d).find(a)}if(e.isFunction(a))return f.ready(a);a.selector!==b&&(this.selector=a.selector,this.context=a.context);return e.makeArray(a,this)},selector:"",jquery:"1.7.2",length:0,size:function(){return this.length},toArray:function(){return F.call(this,0)},get:function(a){return a==null?this.toArray():a<0?this[this.length+a]:this[a]},pushStack:function(a,b,c){var d=this.constructor();e.isArray(a)?E.apply(d,a):e.merge(d,a),d.prevObject=this,d.context=this.context,b==="find"?d.selector=this.selector+(this.selector?" ":"")+c:b&&(d.selector=this.selector+"."+b+"("+c+")");return d},each:function(a,b){return e.each(this,a,b)},ready:function(a){e.bindReady(),A.add(a);return this},eq:function(a){a=+a;return a===-1?this.slice(a):this.slice(a,a+1)},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},slice:function(){return this.pushStack(F.apply(this,arguments),"slice",F.call(arguments).join(","))},map:function(a){return this.pushStack(e.map(this,function(b,c){return a.call(b,c,b)}))},end:function(){return this.prevObject||this.constructor(null)},push:E,sort:[].sort,splice:[].splice},e.fn.init.prototype=e.fn,e.extend=e.fn.extend=function(){var a,c,d,f,g,h,i=arguments[0]||{},j=1,k=arguments.length,l=!1;typeof i=="boolean"&&(l=i,i=arguments[1]||{},j=2),typeof i!="object"&&!e.isFunction(i)&&(i={}),k===j&&(i=this,--j);for(;j<k;j++)if((a=arguments[j])!=null)for(c in a){d=i[c],f=a[c];if(i===f)continue;l&&f&&(e.isPlainObject(f)||(g=e.isArray(f)))?(g?(g=!1,h=d&&e.isArray(d)?d:[]):h=d&&e.isPlainObject(d)?d:{},i[c]=e.extend(l,h,f)):f!==b&&(i[c]=f)}return i},e.extend({noConflict:function(b){a.$===e&&(a.$=g),b&&a.jQuery===e&&(a.jQuery=f);return e},isReady:!1,readyWait:1,holdReady:function(a){a?e.readyWait++:e.ready(!0)},ready:function(a){if(a===!0&&!--e.readyWait||a!==!0&&!e.isReady){if(!c.body)return setTimeout(e.ready,1);e.isReady=!0;if(a!==!0&&--e.readyWait>0)return;A.fireWith(c,[e]),e.fn.trigger&&e(c).trigger("ready").off("ready")}},bindReady:function(){if(!A){A=e.Callbacks("once memory");if(c.readyState==="complete")return setTimeout(e.ready,1);if(c.addEventListener)c.addEventListener("DOMContentLoaded",B,!1),a.addEventListener("load",e.ready,!1);else if(c.attachEvent){c.attachEvent("onreadystatechange",B),a.attachEvent("onload",e.ready);var b=!1;try{b=a.frameElement==null}catch(d){}c.documentElement.doScroll&&b&&J()}}},isFunction:function(a){return e.type(a)==="function"},isArray:Array.isArray||function(a){return e.type(a)==="array"},isWindow:function(a){return a!=null&&a==a.window},isNumeric:function(a){return!isNaN(parseFloat(a))&&isFinite(a)},type:function(a){return a==null?String(a):I[C.call(a)]||"object"},isPlainObject:function(a){if(!a||e.type(a)!=="object"||a.nodeType||e.isWindow(a))return!1;try{if(a.constructor&&!D.call(a,"constructor")&&!D.call(a.constructor.prototype,"isPrototypeOf"))return!1}catch(c){return!1}var d;for(d in a);return d===b||D.call(a,d)},isEmptyObject:function(a){for(var b in a)return!1;return!0},error:function(a){throw new Error(a)},parseJSON:function(b){if(typeof b!="string"||!b)return null;b=e.trim(b);if(a.JSON&&a.JSON.parse)return a.JSON.parse(b);if(n.test(b.replace(o,"@").replace(p,"]").replace(q,"")))return(new Function("return "+b))();e.error("Invalid JSON: "+b)},parseXML:function(c){if(typeof c!="string"||!c)return null;var d,f;try{a.DOMParser?(f=new DOMParser,d=f.parseFromString(c,"text/xml")):(d=new ActiveXObject("Microsoft.XMLDOM"),d.async="false",d.loadXML(c))}catch(g){d=b}(!d||!d.documentElement||d.getElementsByTagName("parsererror").length)&&e.error("Invalid XML: "+c);return d},noop:function(){},globalEval:function(b){b&&j.test(b)&&(a.execScript||function(b){a.eval.call(a,b)})(b)},camelCase:function(a){return a.replace(w,"ms-").replace(v,x)},nodeName:function(a,b){return a.nodeName&&a.nodeName.toUpperCase()===b.toUpperCase()},each:function(a,c,d){var f,g=0,h=a.length,i=h===b||e.isFunction(a);if(d){if(i){for(f in a)if(c.apply(a[f],d)===!1)break}else for(;g<h;)if(c.apply(a[g++],d)===!1)break}else if(i){for(f in a)if(c.call(a[f],f,a[f])===!1)break}else for(;g<h;)if(c.call(a[g],g,a[g++])===!1)break;return a},trim:G?function(a){return a==null?"":G.call(a)}:function(a){return a==null?"":(a+"").replace(k,"").replace(l,"")},makeArray:function(a,b){var c=b||[];if(a!=null){var d=e.type(a);a.length==null||d==="string"||d==="function"||d==="regexp"||e.isWindow(a)?E.call(c,a):e.merge(c,a)}return c},inArray:function(a,b,c){var d;if(b){if(H)return H.call(b,a,c);d=b.length,c=c?c<0?Math.max(0,d+c):c:0;for(;c<d;c++)if(c in b&&b[c]===a)return c}return-1},merge:function(a,c){var d=a.length,e=0;if(typeof c.length=="number")for(var f=c.length;e<f;e++)a[d++]=c[e];else while(c[e]!==b)a[d++]=c[e++];a.length=d;return a},grep:function(a,b,c){var d=[],e;c=!!c;for(var f=0,g=a.length;f<g;f++)e=!!b(a[f],f),c!==e&&d.push(a[f]);return d},map:function(a,c,d){var f,g,h=[],i=0,j=a.length,k=a instanceof e||j!==b&&typeof j=="number"&&(j>0&&a[0]&&a[j-1]||j===0||e.isArray(a));if(k)for(;i<j;i++)f=c(a[i],i,d),f!=null&&(h[h.length]=f);else for(g in a)f=c(a[g],g,d),f!=null&&(h[h.length]=f);return h.concat.apply([],h)},guid:1,proxy:function(a,c){if(typeof c=="string"){var d=a[c];c=a,a=d}if(!e.isFunction(a))return b;var f=F.call(arguments,2),g=function(){return a.apply(c,f.concat(F.call(arguments)))};g.guid=a.guid=a.guid||g.guid||e.guid++;return g},access:function(a,c,d,f,g,h,i){var j,k=d==null,l=0,m=a.length;if(d&&typeof d=="object"){for(l in d)e.access(a,c,l,d[l],1,h,f);g=1}else if(f!==b){j=i===b&&e.isFunction(f),k&&(j?(j=c,c=function(a,b,c){return j.call(e(a),c)}):(c.call(a,f),c=null));if(c)for(;l<m;l++)c(a[l],d,j?f.call(a[l],l,c(a[l],d)):f,i);g=1}return g?a:k?c.call(a):m?c(a[0],d):h},now:function(){return(new Date).getTime()},uaMatch:function(a){a=a.toLowerCase();var b=r.exec(a)||s.exec(a)||t.exec(a)||a.indexOf("compatible")<0&&u.exec(a)||[];return{browser:b[1]||"",version:b[2]||"0"}},sub:function(){function a(b,c){return new a.fn.init(b,c)}e.extend(!0,a,this),a.superclass=this,a.fn=a.prototype=this(),a.fn.constructor=a,a.sub=this.sub,a.fn.init=function(d,f){f&&f instanceof e&&!(f instanceof a)&&(f=a(f));return e.fn.init.call(this,d,f,b)},a.fn.init.prototype=a.fn;var b=a(c);return a},browser:{}}),e.each("Boolean Number String Function Array Date RegExp Object".split(" "),function(a,b){I["[object "+b+"]"]=b.toLowerCase()}),z=e.uaMatch(y),z.browser&&(e.browser[z.browser]=!0,e.browser.version=z.version),e.browser.webkit&&(e.browser.safari=!0),j.test("Â ")&&(k=/^[\s\xA0]+/,l=/[\s\xA0]+$/),h=e(c),c.addEventListener?B=function(){c.removeEventListener("DOMContentLoaded",B,!1),e.ready()}:c.attachEvent&&(B=function(){c.readyState==="complete"&&(c.detachEvent("onreadystatechange",B),e.ready())});return e}(),g={};f.Callbacks=function(a){a=a?g[a]||h(a):{};var c=[],d=[],e,i,j,k,l,m,n=function(b){var d,e,g,h,i;for(d=0,e=b.length;d<e;d++)g=b[d],h=f.type(g),h==="array"?n(g):h==="function"&&(!a.unique||!p.has(g))&&c.push(g)},o=function(b,f){f=f||[],e=!a.memory||[b,f],i=!0,j=!0,m=k||0,k=0,l=c.length;for(;c&&m<l;m++)if(c[m].apply(b,f)===!1&&a.stopOnFalse){e=!0;break}j=!1,c&&(a.once?e===!0?p.disable():c=[]:d&&d.length&&(e=d.shift(),p.fireWith(e[0],e[1])))},p={add:function(){if(c){var a=c.length;n(arguments),j?l=c.length:e&&e!==!0&&(k=a,o(e[0],e[1]))}return this},remove:function(){if(c){var b=arguments,d=0,e=b.length;for(;d<e;d++)for(var f=0;f<c.length;f++)if(b[d]===c[f]){j&&f<=l&&(l--,f<=m&&m--),c.splice(f--,1);if(a.unique)break}}return this},has:function(a){if(c){var b=0,d=c.length;for(;b<d;b++)if(a===c[b])return!0}return!1},empty:function(){c=[];return this},disable:function(){c=d=e=b;return this},disabled:function(){return!c},lock:function(){d=b,(!e||e===!0)&&p.disable();return this},locked:function(){return!d},fireWith:function(b,c){d&&(j?a.once||d.push([b,c]):(!a.once||!e)&&o(b,c));return this},fire:function(){p.fireWith(this,arguments);return this},fired:function(){return!!i}};return p};var i=[].slice;f.extend({Deferred:function(a){var b=f.Callbacks("once memory"),c=f.Callbacks("once memory"),d=f.Callbacks("memory"),e="pending",g={resolve:b,reject:c,notify:d},h={done:b.add,fail:c.add,progress:d.add,state:function(){return e},isResolved:b.fired,isRejected:c.fired,then:function(a,b,c){i.done(a).fail(b).progress(c);return this},always:function(){i.done.apply(i,arguments).fail.apply(i,arguments);return this},pipe:function(a,b,c){return f.Deferred(function(d){f.each({done:[a,"resolve"],fail:[b,"reject"],progress:[c,"notify"]},function(a,b){var c=b[0],e=b[1],g;f.isFunction(c)?i[a](function(){g=c.apply(this,arguments),g&&f.isFunction(g.promise)?g.promise().then(d.resolve,d.reject,d.notify):d[e+"With"](this===i?d:this,[g])}):i[a](d[e])})}).promise()},promise:function(a){if(a==null)a=h;else for(var b in h)a[b]=h[b];return a}},i=h.promise({}),j;for(j in g)i[j]=g[j].fire,i[j+"With"]=g[j].fireWith;i.done(function(){e="resolved"},c.disable,d.lock).fail(function(){e="rejected"},b.disable,d.lock),a&&a.call(i,i);return i},when:function(a){function m(a){return function(b){e[a]=arguments.length>1?i.call(arguments,0):b,j.notifyWith(k,e)}}function l(a){return function(c){b[a]=arguments.length>1?i.call(arguments,0):c,--g||j.resolveWith(j,b)}}var b=i.call(arguments,0),c=0,d=b.length,e=Array(d),g=d,h=d,j=d<=1&&a&&f.isFunction(a.promise)?a:f.Deferred(),k=j.promise();if(d>1){for(;c<d;c++)b[c]&&b[c].promise&&f.isFunction(b[c].promise)?b[c].promise().then(l(c),j.reject,m(c)):--g;g||j.resolveWith(j,b)}else j!==a&&j.resolveWith(j,d?[a]:[]);return k}}),f.support=function(){var b,d,e,g,h,i,j,k,l,m,n,o,p=c.createElement("div"),q=c.documentElement;p.setAttribute("className","t"),p.innerHTML="   <link/><table></table><a href='/a' style='top:1px;float:left;opacity:.55;'>a</a><input type='checkbox'/>",d=p.getElementsByTagName("*"),e=p.getElementsByTagName("a")[0];if(!d||!d.length||!e)return{};g=c.createElement("select"),h=g.appendChild(c.createElement("option")),i=p.getElementsByTagName("input")[0],b={leadingWhitespace:p.firstChild.nodeType===3,tbody:!p.getElementsByTagName("tbody").length,htmlSerialize:!!p.getElementsByTagName("link").length,style:/top/.test(e.getAttribute("style")),hrefNormalized:e.getAttribute("href")==="/a",opacity:/^0.55/.test(e.style.opacity),cssFloat:!!e.style.cssFloat,checkOn:i.value==="on",optSelected:h.selected,getSetAttribute:p.className!=="t",enctype:!!c.createElement("form").enctype,html5Clone:c.createElement("nav").cloneNode(!0).outerHTML!=="<:nav></:nav>",submitBubbles:!0,changeBubbles:!0,focusinBubbles:!1,deleteExpando:!0,noCloneEvent:!0,inlineBlockNeedsLayout:!1,shrinkWrapBlocks:!1,reliableMarginRight:!0,pixelMargin:!0},f.boxModel=b.boxModel=c.compatMode==="CSS1Compat",i.checked=!0,b.noCloneChecked=i.cloneNode(!0).checked,g.disabled=!0,b.optDisabled=!h.disabled;try{delete p.test}catch(r){b.deleteExpando=!1}!p.addEventListener&&p.attachEvent&&p.fireEvent&&(p.attachEvent("onclick",function(){b.noCloneEvent=!1}),p.cloneNode(!0).fireEvent("onclick")),i=c.createElement("input"),i.value="t",i.setAttribute("type","radio"),b.radioValue=i.value==="t",i.setAttribute("checked","checked"),i.setAttribute("name","t"),p.appendChild(i),j=c.createDocumentFragment(),j.appendChild(p.lastChild),b.checkClone=j.cloneNode(!0).cloneNode(!0).lastChild.checked,b.appendChecked=i.checked,j.removeChild(i),j.appendChild(p);if(p.attachEvent)for(n in{submit:1,change:1,focusin:1})m="on"+n,o=m in p,o||(p.setAttribute(m,"return;"),o=typeof p[m]=="function"),b[n+"Bubbles"]=o;j.removeChild(p),j=g=h=p=i=null,f(function(){var d,e,g,h,i,j,l,m,n,q,r,s,t,u=c.getElementsByTagName("body")[0];!u||(m=1,t="padding:0;margin:0;border:",r="position:absolute;top:0;left:0;width:1px;height:1px;",s=t+"0;visibility:hidden;",n="style='"+r+t+"5px solid #000;",q="<div "+n+"display:block;'><div style='"+t+"0;display:block;overflow:hidden;'></div></div>"+"<table "+n+"' cellpadding='0' cellspacing='0'>"+"<tr><td></td></tr></table>",d=c.createElement("div"),d.style.cssText=s+"width:0;height:0;position:static;top:0;margin-top:"+m+"px",u.insertBefore(d,u.firstChild),p=c.createElement("div"),d.appendChild(p),p.innerHTML="<table><tr><td style='"+t+"0;display:none'></td><td>t</td></tr></table>",k=p.getElementsByTagName("td"),o=k[0].offsetHeight===0,k[0].style.display="",k[1].style.display="none",b.reliableHiddenOffsets=o&&k[0].offsetHeight===0,a.getComputedStyle&&(p.innerHTML="",l=c.createElement("div"),l.style.width="0",l.style.marginRight="0",p.style.width="2px",p.appendChild(l),b.reliableMarginRight=(parseInt((a.getComputedStyle(l,null)||{marginRight:0}).marginRight,10)||0)===0),typeof p.style.zoom!="undefined"&&(p.innerHTML="",p.style.width=p.style.padding="1px",p.style.border=0,p.style.overflow="hidden",p.style.display="inline",p.style.zoom=1,b.inlineBlockNeedsLayout=p.offsetWidth===3,p.style.display="block",p.style.overflow="visible",p.innerHTML="<div style='width:5px;'></div>",b.shrinkWrapBlocks=p.offsetWidth!==3),p.style.cssText=r+s,p.innerHTML=q,e=p.firstChild,g=e.firstChild,i=e.nextSibling.firstChild.firstChild,j={doesNotAddBorder:g.offsetTop!==5,doesAddBorderForTableAndCells:i.offsetTop===5},g.style.position="fixed",g.style.top="20px",j.fixedPosition=g.offsetTop===20||g.offsetTop===15,g.style.position=g.style.top="",e.style.overflow="hidden",e.style.position="relative",j.subtractsBorderForOverflowNotVisible=g.offsetTop===-5,j.doesNotIncludeMarginInBodyOffset=u.offsetTop!==m,a.getComputedStyle&&(p.style.marginTop="1%",b.pixelMargin=(a.getComputedStyle(p,null)||{marginTop:0}).marginTop!=="1%"),typeof d.style.zoom!="undefined"&&(d.style.zoom=1),u.removeChild(d),l=p=d=null,f.extend(b,j))});return b}();var j=/^(?:\{.*\}|\[.*\])$/,k=/([A-Z])/g;f.extend({cache:{},uuid:0,expando:"jQuery"+(f.fn.jquery+Math.random()).replace(/\D/g,""),noData:{embed:!0,object:"clsid:D27CDB6E-AE6D-11cf-96B8-444553540000",applet:!0},hasData:function(a){a=a.nodeType?f.cache[a[f.expando]]:a[f.expando];return!!a&&!m(a)},data:function(a,c,d,e){if(!!f.acceptData(a)){var g,h,i,j=f.expando,k=typeof c=="string",l=a.nodeType,m=l?f.cache:a,n=l?a[j]:a[j]&&j,o=c==="events";if((!n||!m[n]||!o&&!e&&!m[n].data)&&k&&d===b)return;n||(l?a[j]=n=++f.uuid:n=j),m[n]||(m[n]={},l||(m[n].toJSON=f.noop));if(typeof c=="object"||typeof c=="function")e?m[n]=f.extend(m[n],c):m[n].data=f.extend(m[n].data,c);g=h=m[n],e||(h.data||(h.data={}),h=h.data),d!==b&&(h[f.camelCase(c)]=d);if(o&&!h[c])return g.events;k?(i=h[c],i==null&&(i=h[f.camelCase(c)])):i=h;return i}},removeData:function(a,b,c){if(!!f.acceptData(a)){var d,e,g,h=f.expando,i=a.nodeType,j=i?f.cache:a,k=i?a[h]:h;if(!j[k])return;if(b){d=c?j[k]:j[k].data;if(d){f.isArray(b)||(b in d?b=[b]:(b=f.camelCase(b),b in d?b=[b]:b=b.split(" ")));for(e=0,g=b.length;e<g;e++)delete d[b[e]];if(!(c?m:f.isEmptyObject)(d))return}}if(!c){delete j[k].data;if(!m(j[k]))return}f.support.deleteExpando||!j.setInterval?delete j[k]:j[k]=null,i&&(f.support.deleteExpando?delete a[h]:a.removeAttribute?a.removeAttribute(h):a[h]=null)}},_data:function(a,b,c){return f.data(a,b,c,!0)},acceptData:function(a){if(a.nodeName){var b=f.noData[a.nodeName.toLowerCase()];if(b)return b!==!0&&a.getAttribute("classid")===b}return!0}}),f.fn.extend({data:function(a,c){var d,e,g,h,i,j=this[0],k=0,m=null;if(a===b){if(this.length){m=f.data(j);if(j.nodeType===1&&!f._data(j,"parsedAttrs")){g=j.attributes;for(i=g.length;k<i;k++)h=g[k].name,h.indexOf("data-")===0&&(h=f.camelCase(h.substring(5)),l(j,h,m[h]));f._data(j,"parsedAttrs",!0)}}return m}if(typeof a=="object")return this.each(function(){f.data(this,a)});d=a.split(".",2),d[1]=d[1]?"."+d[1]:"",e=d[1]+"!";return f.access(this,function(c){if(c===b){m=this.triggerHandler("getData"+e,[d[0]]),m===b&&j&&(m=f.data(j,a),m=l(j,a,m));return m===b&&d[1]?this.data(d[0]):m}d[1]=c,this.each(function(){var b=f(this);b.triggerHandler("setData"+e,d),f.data(this,a,c),b.triggerHandler("changeData"+e,d)})},null,c,arguments.length>1,null,!1)},removeData:function(a){return this.each(function(){f.removeData(this,a)})}}),f.extend({_mark:function(a,b){a&&(b=(b||"fx")+"mark",f._data(a,b,(f._data(a,b)||0)+1))},_unmark:function(a,b,c){a!==!0&&(c=b,b=a,a=!1);if(b){c=c||"fx";var d=c+"mark",e=a?0:(f._data(b,d)||1)-1;e?f._data(b,d,e):(f.removeData(b,d,!0),n(b,c,"mark"))}},queue:function(a,b,c){var d;if(a){b=(b||"fx")+"queue",d=f._data(a,b),c&&(!d||f.isArray(c)?d=f._data(a,b,f.makeArray(c)):d.push(c));return d||[]}},dequeue:function(a,b){b=b||"fx";var c=f.queue(a,b),d=c.shift(),e={};d==="inprogress"&&(d=c.shift()),d&&(b==="fx"&&c.unshift("inprogress"),f._data(a,b+".run",e),d.call(a,function(){f.dequeue(a,b)},e)),c.length||(f.removeData(a,b+"queue "+b+".run",!0),n(a,b,"queue"))}}),f.fn.extend({queue:function(a,c){var d=2;typeof a!="string"&&(c=a,a="fx",d--);if(arguments.length<d)return f.queue(this[0],a);return c===b?this:this.each(function(){var b=f.queue(this,a,c);a==="fx"&&b[0]!=="inprogress"&&f.dequeue(this,a)})},dequeue:function(a){return this.each(function(){f.dequeue(this,a)})},delay:function(a,b){a=f.fx?f.fx.speeds[a]||a:a,b=b||"fx";return this.queue(b,function(b,c){var d=setTimeout(b,a);c.stop=function(){clearTimeout(d)}})},clearQueue:function(a){return this.queue(a||"fx",[])},promise:function(a,c){function m(){--h||d.resolveWith(e,[e])}typeof a!="string"&&(c=a,a=b),a=a||"fx";var d=f.Deferred(),e=this,g=e.length,h=1,i=a+"defer",j=a+"queue",k=a+"mark",l;while(g--)if(l=f.data(e[g],i,b,!0)||(f.data(e[g],j,b,!0)||f.data(e[g],k,b,!0))&&f.data(e[g],i,f.Callbacks("once memory"),!0))h++,l.add(m);m();return d.promise(c)}});var o=/[\n\t\r]/g,p=/\s+/,q=/\r/g,r=/^(?:button|input)$/i,s=/^(?:button|input|object|select|textarea)$/i,t=/^a(?:rea)?$/i,u=/^(?:autofocus|autoplay|async|checked|controls|defer|disabled|hidden|loop|multiple|open|readonly|required|scoped|selected)$/i,v=f.support.getSetAttribute,w,x,y;f.fn.extend({attr:function(a,b){return f.access(this,f.attr,a,b,arguments.length>1)},removeAttr:function(a){return this.each(function(){f.removeAttr(this,a)})},prop:function(a,b){return f.access(this,f.prop,a,b,arguments.length>1)},removeProp:function(a){a=f.propFix[a]||a;return this.each(function(){try{this[a]=b,delete this[a]}catch(c){}})},addClass:function(a){var b,c,d,e,g,h,i;if(f.isFunction(a))return this.each(function(b){f(this).addClass(a.call(this,b,this.className))});if(a&&typeof a=="string"){b=a.split(p);for(c=0,d=this.length;c<d;c++){e=this[c];if(e.nodeType===1)if(!e.className&&b.length===1)e.className=a;else{g=" "+e.className+" ";for(h=0,i=b.length;h<i;h++)~g.indexOf(" "+b[h]+" ")||(g+=b[h]+" ");e.className=f.trim(g)}}}return this},removeClass:function(a){var c,d,e,g,h,i,j;if(f.isFunction(a))return this.each(function(b){f(this).removeClass(a.call(this,b,this.className))});if(a&&typeof a=="string"||a===b){c=(a||"").split(p);for(d=0,e=this.length;d<e;d++){g=this[d];if(g.nodeType===1&&g.className)if(a){h=(" "+g.className+" ").replace(o," ");for(i=0,j=c.length;i<j;i++)h=h.replace(" "+c[i]+" "," ");g.className=f.trim(h)}else g.className=""}}return this},toggleClass:function(a,b){var c=typeof a,d=typeof b=="boolean";if(f.isFunction(a))return this.each(function(c){f(this).toggleClass(a.call(this,c,this.className,b),b)});return this.each(function(){if(c==="string"){var e,g=0,h=f(this),i=b,j=a.split(p);while(e=j[g++])i=d?i:!h.hasClass(e),h[i?"addClass":"removeClass"](e)}else if(c==="undefined"||c==="boolean")this.className&&f._data(this,"__className__",this.className),this.className=this.className||a===!1?"":f._data(this,"__className__")||""})},hasClass:function(a){var b=" "+a+" ",c=0,d=this.length;for(;c<d;c++)if(this[c].nodeType===1&&(" "+this[c].className+" ").replace(o," ").indexOf(b)>-1)return!0;return!1},val:function(a){var c,d,e,g=this[0];{if(!!arguments.length){e=f.isFunction(a);return this.each(function(d){var g=f(this),h;if(this.nodeType===1){e?h=a.call(this,d,g.val()):h=a,h==null?h="":typeof h=="number"?h+="":f.isArray(h)&&(h=f.map(h,function(a){return a==null?"":a+""})),c=f.valHooks[this.type]||f.valHooks[this.nodeName.toLowerCase()];if(!c||!("set"in c)||c.set(this,h,"value")===b)this.value=h}})}if(g){c=f.valHooks[g.type]||f.valHooks[g.nodeName.toLowerCase()];if(c&&"get"in c&&(d=c.get(g,"value"))!==b)return d;d=g.value;return typeof d=="string"?d.replace(q,""):d==null?"":d}}}}),f.extend({valHooks:{option:{get:function(a){var b=a.attributes.value;return!b||b.specified?a.value:a.text}},select:{get:function(a){var b,c,d,e,g=a.selectedIndex,h=[],i=a.options,j=a.type==="select-one";if(g<0)return null;c=j?g:0,d=j?g+1:i.length;for(;c<d;c++){e=i[c];if(e.selected&&(f.support.optDisabled?!e.disabled:e.getAttribute("disabled")===null)&&(!e.parentNode.disabled||!f.nodeName(e.parentNode,"optgroup"))){b=f(e).val();if(j)return b;h.push(b)}}if(j&&!h.length&&i.length)return f(i[g]).val();return h},set:function(a,b){var c=f.makeArray(b);f(a).find("option").each(function(){this.selected=f.inArray(f(this).val(),c)>=0}),c.length||(a.selectedIndex=-1);return c}}},attrFn:{val:!0,css:!0,html:!0,text:!0,data:!0,width:!0,height:!0,offset:!0},attr:function(a,c,d,e){var g,h,i,j=a.nodeType;if(!!a&&j!==3&&j!==8&&j!==2){if(e&&c in f.attrFn)return f(a)[c](d);if(typeof a.getAttribute=="undefined")return f.prop(a,c,d);i=j!==1||!f.isXMLDoc(a),i&&(c=c.toLowerCase(),h=f.attrHooks[c]||(u.test(c)?x:w));if(d!==b){if(d===null){f.removeAttr(a,c);return}if(h&&"set"in h&&i&&(g=h.set(a,d,c))!==b)return g;a.setAttribute(c,""+d);return d}if(h&&"get"in h&&i&&(g=h.get(a,c))!==null)return g;g=a.getAttribute(c);return g===null?b:g}},removeAttr:function(a,b){var c,d,e,g,h,i=0;if(b&&a.nodeType===1){d=b.toLowerCase().split(p),g=d.length;for(;i<g;i++)e=d[i],e&&(c=f.propFix[e]||e,h=u.test(e),h||f.attr(a,e,""),a.removeAttribute(v?e:c),h&&c in a&&(a[c]=!1))}},attrHooks:{type:{set:function(a,b){if(r.test(a.nodeName)&&a.parentNode)f.error("type property can't be changed");else if(!f.support.radioValue&&b==="radio"&&f.nodeName(a,"input")){var c=a.value;a.setAttribute("type",b),c&&(a.value=c);return b}}},value:{get:function(a,b){if(w&&f.nodeName(a,"button"))return w.get(a,b);return b in a?a.value:null},set:function(a,b,c){if(w&&f.nodeName(a,"button"))return w.set(a,b,c);a.value=b}}},propFix:{tabindex:"tabIndex",readonly:"readOnly","for":"htmlFor","class":"className",maxlength:"maxLength",cellspacing:"cellSpacing",cellpadding:"cellPadding",rowspan:"rowSpan",colspan:"colSpan",usemap:"useMap",frameborder:"frameBorder",contenteditable:"contentEditable"},prop:function(a,c,d){var e,g,h,i=a.nodeType;if(!!a&&i!==3&&i!==8&&i!==2){h=i!==1||!f.isXMLDoc(a),h&&(c=f.propFix[c]||c,g=f.propHooks[c]);return d!==b?g&&"set"in g&&(e=g.set(a,d,c))!==b?e:a[c]=d:g&&"get"in g&&(e=g.get(a,c))!==null?e:a[c]}},propHooks:{tabIndex:{get:function(a){var c=a.getAttributeNode("tabindex");return c&&c.specified?parseInt(c.value,10):s.test(a.nodeName)||t.test(a.nodeName)&&a.href?0:b}}}}),f.attrHooks.tabindex=f.propHooks.tabIndex,x={get:function(a,c){var d,e=f.prop(a,c);return e===!0||typeof e!="boolean"&&(d=a.getAttributeNode(c))&&d.nodeValue!==!1?c.toLowerCase():b},set:function(a,b,c){var d;b===!1?f.removeAttr(a,c):(d=f.propFix[c]||c,d in a&&(a[d]=!0),a.setAttribute(c,c.toLowerCase()));return c}},v||(y={name:!0,id:!0,coords:!0},w=f.valHooks.button={get:function(a,c){var d;d=a.getAttributeNode(c);return d&&(y[c]?d.nodeValue!=="":d.specified)?d.nodeValue:b},set:function(a,b,d){var e=a.getAttributeNode(d);e||(e=c.createAttribute(d),a.setAttributeNode(e));return e.nodeValue=b+""}},f.attrHooks.tabindex.set=w.set,f.each(["width","height"],function(a,b){f.attrHooks[b]=f.extend(f.attrHooks[b],{set:function(a,c){if(c===""){a.setAttribute(b,"auto");return c}}})}),f.attrHooks.contenteditable={get:w.get,set:function(a,b,c){b===""&&(b="false"),w.set(a,b,c)}}),f.support.hrefNormalized||f.each(["href","src","width","height"],function(a,c){f.attrHooks[c]=f.extend(f.attrHooks[c],{get:function(a){var d=a.getAttribute(c,2);return d===null?b:d}})}),f.support.style||(f.attrHooks.style={get:function(a){return a.style.cssText.toLowerCase()||b},set:function(a,b){return a.style.cssText=""+b}}),f.support.optSelected||(f.propHooks.selected=f.extend(f.propHooks.selected,{get:function(a){var b=a.parentNode;b&&(b.selectedIndex,b.parentNode&&b.parentNode.selectedIndex);return null}})),f.support.enctype||(f.propFix.enctype="encoding"),f.support.checkOn||f.each(["radio","checkbox"],function(){f.valHooks[this]={get:function(a){return a.getAttribute("value")===null?"on":a.value}}}),f.each(["radio","checkbox"],function(){f.valHooks[this]=f.extend(f.valHooks[this],{set:function(a,b){if(f.isArray(b))return a.checked=f.inArray(f(a).val(),b)>=0}})});var z=/^(?:textarea|input|select)$/i,A=/^([^\.]*)?(?:\.(.+))?$/,B=/(?:^|\s)hover(\.\S+)?\b/,C=/^key/,D=/^(?:mouse|contextmenu)|click/,E=/^(?:focusinfocus|focusoutblur)$/,F=/^(\w*)(?:#([\w\-]+))?(?:\.([\w\-]+))?$/,G=function(
    --a){var b=F.exec(a);b&&(b[1]=(b[1]||"").toLowerCase(),b[3]=b[3]&&new RegExp("(?:^|\\s)"+b[3]+"(?:\\s|$)"));return b},H=function(a,b){var c=a.attributes||{};return(!b[1]||a.nodeName.toLowerCase()===b[1])&&(!b[2]||(c.id||{}).value===b[2])&&(!b[3]||b[3].test((c["class"]||{}).value))},I=function(a){return f.event.special.hover?a:a.replace(B,"mouseenter$1 mouseleave$1")};f.event={add:function(a,c,d,e,g){var h,i,j,k,l,m,n,o,p,q,r,s;if(!(a.nodeType===3||a.nodeType===8||!c||!d||!(h=f._data(a)))){d.handler&&(p=d,d=p.handler,g=p.selector),d.guid||(d.guid=f.guid++),j=h.events,j||(h.events=j={}),i=h.handle,i||(h.handle=i=function(a){return typeof f!="undefined"&&(!a||f.event.triggered!==a.type)?f.event.dispatch.apply(i.elem,arguments):b},i.elem=a),c=f.trim(I(c)).split(" ");for(k=0;k<c.length;k++){l=A.exec(c[k])||[],m=l[1],n=(l[2]||"").split(".").sort(),s=f.event.special[m]||{},m=(g?s.delegateType:s.bindType)||m,s=f.event.special[m]||{},o=f.extend({type:m,origType:l[1],data:e,handler:d,guid:d.guid,selector:g,quick:g&&G(g),namespace:n.join(".")},p),r=j[m];if(!r){r=j[m]=[],r.delegateCount=0;if(!s.setup||s.setup.call(a,e,n,i)===!1)a.addEventListener?a.addEventListener(m,i,!1):a.attachEvent&&a.attachEvent("on"+m,i)}s.add&&(s.add.call(a,o),o.handler.guid||(o.handler.guid=d.guid)),g?r.splice(r.delegateCount++,0,o):r.push(o),f.event.global[m]=!0}a=null}},global:{},remove:function(a,b,c,d,e){var g=f.hasData(a)&&f._data(a),h,i,j,k,l,m,n,o,p,q,r,s;if(!!g&&!!(o=g.events)){b=f.trim(I(b||"")).split(" ");for(h=0;h<b.length;h++){i=A.exec(b[h])||[],j=k=i[1],l=i[2];if(!j){for(j in o)f.event.remove(a,j+b[h],c,d,!0);continue}p=f.event.special[j]||{},j=(d?p.delegateType:p.bindType)||j,r=o[j]||[],m=r.length,l=l?new RegExp("(^|\\.)"+l.split(".").sort().join("\\.(?:.*\\.)?")+"(\\.|$)"):null;for(n=0;n<r.length;n++)s=r[n],(e||k===s.origType)&&(!c||c.guid===s.guid)&&(!l||l.test(s.namespace))&&(!d||d===s.selector||d==="**"&&s.selector)&&(r.splice(n--,1),s.selector&&r.delegateCount--,p.remove&&p.remove.call(a,s));r.length===0&&m!==r.length&&((!p.teardown||p.teardown.call(a,l)===!1)&&f.removeEvent(a,j,g.handle),delete o[j])}f.isEmptyObject(o)&&(q=g.handle,q&&(q.elem=null),f.removeData(a,["events","handle"],!0))}},customEvent:{getData:!0,setData:!0,changeData:!0},trigger:function(c,d,e,g){if(!e||e.nodeType!==3&&e.nodeType!==8){var h=c.type||c,i=[],j,k,l,m,n,o,p,q,r,s;if(E.test(h+f.event.triggered))return;h.indexOf("!")>=0&&(h=h.slice(0,-1),k=!0),h.indexOf(".")>=0&&(i=h.split("."),h=i.shift(),i.sort());if((!e||f.event.customEvent[h])&&!f.event.global[h])return;c=typeof c=="object"?c[f.expando]?c:new f.Event(h,c):new f.Event(h),c.type=h,c.isTrigger=!0,c.exclusive=k,c.namespace=i.join("."),c.namespace_re=c.namespace?new RegExp("(^|\\.)"+i.join("\\.(?:.*\\.)?")+"(\\.|$)"):null,o=h.indexOf(":")<0?"on"+h:"";if(!e){j=f.cache;for(l in j)j[l].events&&j[l].events[h]&&f.event.trigger(c,d,j[l].handle.elem,!0);return}c.result=b,c.target||(c.target=e),d=d!=null?f.makeArray(d):[],d.unshift(c),p=f.event.special[h]||{};if(p.trigger&&p.trigger.apply(e,d)===!1)return;r=[[e,p.bindType||h]];if(!g&&!p.noBubble&&!f.isWindow(e)){s=p.delegateType||h,m=E.test(s+h)?e:e.parentNode,n=null;for(;m;m=m.parentNode)r.push([m,s]),n=m;n&&n===e.ownerDocument&&r.push([n.defaultView||n.parentWindow||a,s])}for(l=0;l<r.length&&!c.isPropagationStopped();l++)m=r[l][0],c.type=r[l][1],q=(f._data(m,"events")||{})[c.type]&&f._data(m,"handle"),q&&q.apply(m,d),q=o&&m[o],q&&f.acceptData(m)&&q.apply(m,d)===!1&&c.preventDefault();c.type=h,!g&&!c.isDefaultPrevented()&&(!p._default||p._default.apply(e.ownerDocument,d)===!1)&&(h!=="click"||!f.nodeName(e,"a"))&&f.acceptData(e)&&o&&e[h]&&(h!=="focus"&&h!=="blur"||c.target.offsetWidth!==0)&&!f.isWindow(e)&&(n=e[o],n&&(e[o]=null),f.event.triggered=h,e[h](),f.event.triggered=b,n&&(e[o]=n));return c.result}},dispatch:function(c){c=f.event.fix(c||a.event);var d=(f._data(this,"events")||{})[c.type]||[],e=d.delegateCount,g=[].slice.call(arguments,0),h=!c.exclusive&&!c.namespace,i=f.event.special[c.type]||{},j=[],k,l,m,n,o,p,q,r,s,t,u;g[0]=c,c.delegateTarget=this;if(!i.preDispatch||i.preDispatch.call(this,c)!==!1){if(e&&(!c.button||c.type!=="click")){n=f(this),n.context=this.ownerDocument||this;for(m=c.target;m!=this;m=m.parentNode||this)if(m.disabled!==!0){p={},r=[],n[0]=m;for(k=0;k<e;k++)s=d[k],t=s.selector,p[t]===b&&(p[t]=s.quick?H(m,s.quick):n.is(t)),p[t]&&r.push(s);r.length&&j.push({elem:m,matches:r})}}d.length>e&&j.push({elem:this,matches:d.slice(e)});for(k=0;k<j.length&&!c.isPropagationStopped();k++){q=j[k],c.currentTarget=q.elem;for(l=0;l<q.matches.length&&!c.isImmediatePropagationStopped();l++){s=q.matches[l];if(h||!c.namespace&&!s.namespace||c.namespace_re&&c.namespace_re.test(s.namespace))c.data=s.data,c.handleObj=s,o=((f.event.special[s.origType]||{}).handle||s.handler).apply(q.elem,g),o!==b&&(c.result=o,o===!1&&(c.preventDefault(),c.stopPropagation()))}}i.postDispatch&&i.postDispatch.call(this,c);return c.result}},props:"attrChange attrName relatedNode srcElement altKey bubbles cancelable ctrlKey currentTarget eventPhase metaKey relatedTarget shiftKey target timeStamp view which".split(" "),fixHooks:{},keyHooks:{props:"char charCode key keyCode".split(" "),filter:function(a,b){a.which==null&&(a.which=b.charCode!=null?b.charCode:b.keyCode);return a}},mouseHooks:{props:"button buttons clientX clientY fromElement offsetX offsetY pageX pageY screenX screenY toElement".split(" "),filter:function(a,d){var e,f,g,h=d.button,i=d.fromElement;a.pageX==null&&d.clientX!=null&&(e=a.target.ownerDocument||c,f=e.documentElement,g=e.body,a.pageX=d.clientX+(f&&f.scrollLeft||g&&g.scrollLeft||0)-(f&&f.clientLeft||g&&g.clientLeft||0),a.pageY=d.clientY+(f&&f.scrollTop||g&&g.scrollTop||0)-(f&&f.clientTop||g&&g.clientTop||0)),!a.relatedTarget&&i&&(a.relatedTarget=i===a.target?d.toElement:i),!a.which&&h!==b&&(a.which=h&1?1:h&2?3:h&4?2:0);return a}},fix:function(a){if(a[f.expando])return a;var d,e,g=a,h=f.event.fixHooks[a.type]||{},i=h.props?this.props.concat(h.props):this.props;a=f.Event(g);for(d=i.length;d;)e=i[--d],a[e]=g[e];a.target||(a.target=g.srcElement||c),a.target.nodeType===3&&(a.target=a.target.parentNode),a.metaKey===b&&(a.metaKey=a.ctrlKey);return h.filter?h.filter(a,g):a},special:{ready:{setup:f.bindReady},load:{noBubble:!0},focus:{delegateType:"focusin"},blur:{delegateType:"focusout"},beforeunload:{setup:function(a,b,c){f.isWindow(this)&&(this.onbeforeunload=c)},teardown:function(a,b){this.onbeforeunload===b&&(this.onbeforeunload=null)}}},simulate:function(a,b,c,d){var e=f.extend(new f.Event,c,{type:a,isSimulated:!0,originalEvent:{}});d?f.event.trigger(e,null,b):f.event.dispatch.call(b,e),e.isDefaultPrevented()&&c.preventDefault()}},f.event.handle=f.event.dispatch,f.removeEvent=c.removeEventListener?function(a,b,c){a.removeEventListener&&a.removeEventListener(b,c,!1)}:function(a,b,c){a.detachEvent&&a.detachEvent("on"+b,c)},f.Event=function(a,b){if(!(this instanceof f.Event))return new f.Event(a,b);a&&a.type?(this.originalEvent=a,this.type=a.type,this.isDefaultPrevented=a.defaultPrevented||a.returnValue===!1||a.getPreventDefault&&a.getPreventDefault()?K:J):this.type=a,b&&f.extend(this,b),this.timeStamp=a&&a.timeStamp||f.now(),this[f.expando]=!0},f.Event.prototype={preventDefault:function(){this.isDefaultPrevented=K;var a=this.originalEvent;!a||(a.preventDefault?a.preventDefault():a.returnValue=!1)},stopPropagation:function(){this.isPropagationStopped=K;var a=this.originalEvent;!a||(a.stopPropagation&&a.stopPropagation(),a.cancelBubble=!0)},stopImmediatePropagation:function(){this.isImmediatePropagationStopped=K,this.stopPropagation()},isDefaultPrevented:J,isPropagationStopped:J,isImmediatePropagationStopped:J},f.each({mouseenter:"mouseover",mouseleave:"mouseout"},function(a,b){f.event.special[a]={delegateType:b,bindType:b,handle:function(a){var c=this,d=a.relatedTarget,e=a.handleObj,g=e.selector,h;if(!d||d!==c&&!f.contains(c,d))a.type=e.origType,h=e.handler.apply(this,arguments),a.type=b;return h}}}),f.support.submitBubbles||(f.event.special.submit={setup:function(){if(f.nodeName(this,"form"))return!1;f.event.add(this,"click._submit keypress._submit",function(a){var c=a.target,d=f.nodeName(c,"input")||f.nodeName(c,"button")?c.form:b;d&&!d._submit_attached&&(f.event.add(d,"submit._submit",function(a){a._submit_bubble=!0}),d._submit_attached=!0)})},postDispatch:function(a){a._submit_bubble&&(delete a._submit_bubble,this.parentNode&&!a.isTrigger&&f.event.simulate("submit",this.parentNode,a,!0))},teardown:function(){if(f.nodeName(this,"form"))return!1;f.event.remove(this,"._submit")}}),f.support.changeBubbles||(f.event.special.change={setup:function(){if(z.test(this.nodeName)){if(this.type==="checkbox"||this.type==="radio")f.event.add(this,"propertychange._change",function(a){a.originalEvent.propertyName==="checked"&&(this._just_changed=!0)}),f.event.add(this,"click._change",function(a){this._just_changed&&!a.isTrigger&&(this._just_changed=!1,f.event.simulate("change",this,a,!0))});return!1}f.event.add(this,"beforeactivate._change",function(a){var b=a.target;z.test(b.nodeName)&&!b._change_attached&&(f.event.add(b,"change._change",function(a){this.parentNode&&!a.isSimulated&&!a.isTrigger&&f.event.simulate("change",this.parentNode,a,!0)}),b._change_attached=!0)})},handle:function(a){var b=a.target;if(this!==b||a.isSimulated||a.isTrigger||b.type!=="radio"&&b.type!=="checkbox")return a.handleObj.handler.apply(this,arguments)},teardown:function(){f.event.remove(this,"._change");return z.test(this.nodeName)}}),f.support.focusinBubbles||f.each({focus:"focusin",blur:"focusout"},function(a,b){var d=0,e=function(a){f.event.simulate(b,a.target,f.event.fix(a),!0)};f.event.special[b]={setup:function(){d++===0&&c.addEventListener(a,e,!0)},teardown:function(){--d===0&&c.removeEventListener(a,e,!0)}}}),f.fn.extend({on:function(a,c,d,e,g){var h,i;if(typeof a=="object"){typeof c!="string"&&(d=d||c,c=b);for(i in a)this.on(i,c,d,a[i],g);return this}d==null&&e==null?(e=c,d=c=b):e==null&&(typeof c=="string"?(e=d,d=b):(e=d,d=c,c=b));if(e===!1)e=J;else if(!e)return this;g===1&&(h=e,e=function(a){f().off(a);return h.apply(this,arguments)},e.guid=h.guid||(h.guid=f.guid++));return this.each(function(){f.event.add(this,a,e,d,c)})},one:function(a,b,c,d){return this.on(a,b,c,d,1)},off:function(a,c,d){if(a&&a.preventDefault&&a.handleObj){var e=a.handleObj;f(a.delegateTarget).off(e.namespace?e.origType+"."+e.namespace:e.origType,e.selector,e.handler);return this}if(typeof a=="object"){for(var g in a)this.off(g,c,a[g]);return this}if(c===!1||typeof c=="function")d=c,c=b;d===!1&&(d=J);return this.each(function(){f.event.remove(this,a,d,c)})},bind:function(a,b,c){return this.on(a,null,b,c)},unbind:function(a,b){return this.off(a,null,b)},live:function(a,b,c){f(this.context).on(a,this.selector,b,c);return this},die:function(a,b){f(this.context).off(a,this.selector||"**",b);return this},delegate:function(a,b,c,d){return this.on(b,a,c,d)},undelegate:function(a,b,c){return arguments.length==1?this.off(a,"**"):this.off(b,a,c)},trigger:function(a,b){return this.each(function(){f.event.trigger(a,b,this)})},triggerHandler:function(a,b){if(this[0])return f.event.trigger(a,b,this[0],!0)},toggle:function(a){var b=arguments,c=a.guid||f.guid++,d=0,e=function(c){var e=(f._data(this,"lastToggle"+a.guid)||0)%d;f._data(this,"lastToggle"+a.guid,e+1),c.preventDefault();return b[e].apply(this,arguments)||!1};e.guid=c;while(d<b.length)b[d++].guid=c;return this.click(e)},hover:function(a,b){return this.mouseenter(a).mouseleave(b||a)}}),f.each("blur focus focusin focusout load resize scroll unload click dblclick mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave change select submit keydown keypress keyup error contextmenu".split(" "),function(a,b){f.fn[b]=function(a,c){c==null&&(c=a,a=null);return arguments.length>0?this.on(b,null,a,c):this.trigger(b)},f.attrFn&&(f.attrFn[b]=!0),C.test(b)&&(f.event.fixHooks[b]=f.event.keyHooks),D.test(b)&&(f.event.fixHooks[b]=f.event.mouseHooks)}),function(){function x(a,b,c,e,f,g){for(var h=0,i=e.length;h<i;h++){var j=e[h];if(j){var k=!1;j=j[a];while(j){if(j[d]===c){k=e[j.sizset];break}if(j.nodeType===1){g||(j[d]=c,j.sizset=h);if(typeof b!="string"){if(j===b){k=!0;break}}else if(m.filter(b,[j]).length>0){k=j;break}}j=j[a]}e[h]=k}}}function w(a,b,c,e,f,g){for(var h=0,i=e.length;h<i;h++){var j=e[h];if(j){var k=!1;j=j[a];while(j){if(j[d]===c){k=e[j.sizset];break}j.nodeType===1&&!g&&(j[d]=c,j.sizset=h);if(j.nodeName.toLowerCase()===b){k=j;break}j=j[a]}e[h]=k}}}var a=/((?:\((?:\([^()]+\)|[^()]+)+\)|\[(?:\[[^\[\]]*\]|['"][^'"]*['"]|[^\[\]'"]+)+\]|\\.|[^ >+~,(\[\\]+)+|[>+~])(\s*,\s*)?((?:.|\r|\n)*)/g,d="sizcache"+(Math.random()+"").replace(".",""),e=0,g=Object.prototype.toString,h=!1,i=!0,j=/\\/g,k=/\r\n/g,l=/\W/;[0,0].sort(function(){i=!1;return 0});var m=function(b,d,e,f){e=e||[],d=d||c;var h=d;if(d.nodeType!==1&&d.nodeType!==9)return[];if(!b||typeof b!="string")return e;var i,j,k,l,n,q,r,t,u=!0,v=m.isXML(d),w=[],x=b;do{a.exec(""),i=a.exec(x);if(i){x=i[3],w.push(i[1]);if(i[2]){l=i[3];break}}}while(i);if(w.length>1&&p.exec(b))if(w.length===2&&o.relative[w[0]])j=y(w[0]+w[1],d,f);else{j=o.relative[w[0]]?[d]:m(w.shift(),d);while(w.length)b=w.shift(),o.relative[b]&&(b+=w.shift()),j=y(b,j,f)}else{!f&&w.length>1&&d.nodeType===9&&!v&&o.match.ID.test(w[0])&&!o.match.ID.test(w[w.length-1])&&(n=m.find(w.shift(),d,v),d=n.expr?m.filter(n.expr,n.set)[0]:n.set[0]);if(d){n=f?{expr:w.pop(),set:s(f)}:m.find(w.pop(),w.length===1&&(w[0]==="~"||w[0]==="+")&&d.parentNode?d.parentNode:d,v),j=n.expr?m.filter(n.expr,n.set):n.set,w.length>0?k=s(j):u=!1;while(w.length)q=w.pop(),r=q,o.relative[q]?r=w.pop():q="",r==null&&(r=d),o.relative[q](k,r,v)}else k=w=[]}k||(k=j),k||m.error(q||b);if(g.call(k)==="[object Array]")if(!u)e.push.apply(e,k);else if(d&&d.nodeType===1)for(t=0;k[t]!=null;t++)k[t]&&(k[t]===!0||k[t].nodeType===1&&m.contains(d,k[t]))&&e.push(j[t]);else for(t=0;k[t]!=null;t++)k[t]&&k[t].nodeType===1&&e.push(j[t]);else s(k,e);l&&(m(l,h,e,f),m.uniqueSort(e));return e};m.uniqueSort=function(a){if(u){h=i,a.sort(u);if(h)for(var b=1;b<a.length;b++)a[b]===a[b-1]&&a.splice(b--,1)}return a},m.matches=function(a,b){return m(a,null,null,b)},m.matchesSelector=function(a,b){return m(b,null,null,[a]).length>0},m.find=function(a,b,c){var d,e,f,g,h,i;if(!a)return[];for(e=0,f=o.order.length;e<f;e++){h=o.order[e];if(g=o.leftMatch[h].exec(a)){i=g[1],g.splice(1,1);if(i.substr(i.length-1)!=="\\"){g[1]=(g[1]||"").replace(j,""),d=o.find[h](g,b,c);if(d!=null){a=a.replace(o.match[h],"");break}}}}d||(d=typeof b.getElementsByTagName!="undefined"?b.getElementsByTagName("*"):[]);return{set:d,expr:a}},m.filter=function(a,c,d,e){var f,g,h,i,j,k,l,n,p,q=a,r=[],s=c,t=c&&c[0]&&m.isXML(c[0]);while(a&&c.length){for(h in o.filter)if((f=o.leftMatch[h].exec(a))!=null&&f[2]){k=o.filter[h],l=f[1],g=!1,f.splice(1,1);if(l.substr(l.length-1)==="\\")continue;s===r&&(r=[]);if(o.preFilter[h]){f=o.preFilter[h](f,s,d,r,e,t);if(!f)g=i=!0;else if(f===!0)continue}if(f)for(n=0;(j=s[n])!=null;n++)j&&(i=k(j,f,n,s),p=e^i,d&&i!=null?p?g=!0:s[n]=!1:p&&(r.push(j),g=!0));if(i!==b){d||(s=r),a=a.replace(o.match[h],"");if(!g)return[];break}}if(a===q)if(g==null)m.error(a);else break;q=a}return s},m.error=function(a){throw new Error("Syntax error, unrecognized expression: "+a)};var n=m.getText=function(a){var b,c,d=a.nodeType,e="";if(d){if(d===1||d===9||d===11){if(typeof a.textContent=="string")return a.textContent;if(typeof a.innerText=="string")return a.innerText.replace(k,"");for(a=a.firstChild;a;a=a.nextSibling)e+=n(a)}else if(d===3||d===4)return a.nodeValue}else for(b=0;c=a[b];b++)c.nodeType!==8&&(e+=n(c));return e},o=m.selectors={order:["ID","NAME","TAG"],match:{ID:/#((?:[\w\u00c0-\uFFFF\-]|\\.)+)/,CLASS:/\.((?:[\w\u00c0-\uFFFF\-]|\\.)+)/,NAME:/\[name=['"]*((?:[\w\u00c0-\uFFFF\-]|\\.)+)['"]*\]/,ATTR:/\[\s*((?:[\w\u00c0-\uFFFF\-]|\\.)+)\s*(?:(\S?=)\s*(?:(['"])(.*?)\3|(#?(?:[\w\u00c0-\uFFFF\-]|\\.)*)|)|)\s*\]/,TAG:/^((?:[\w\u00c0-\uFFFF\*\-]|\\.)+)/,CHILD:/:(only|nth|last|first)-child(?:\(\s*(even|odd|(?:[+\-]?\d+|(?:[+\-]?\d*)?n\s*(?:[+\-]\s*\d+)?))\s*\))?/,POS:/:(nth|eq|gt|lt|first|last|even|odd)(?:\((\d*)\))?(?=[^\-]|$)/,PSEUDO:/:((?:[\w\u00c0-\uFFFF\-]|\\.)+)(?:\((['"]?)((?:\([^\)]+\)|[^\(\)]*)+)\2\))?/},leftMatch:{},attrMap:{"class":"className","for":"htmlFor"},attrHandle:{href:function(a){return a.getAttribute("href")},type:function(a){return a.getAttribute("type")}},relative:{"+":function(a,b){var c=typeof b=="string",d=c&&!l.test(b),e=c&&!d;d&&(b=b.toLowerCase());for(var f=0,g=a.length,h;f<g;f++)if(h=a[f]){while((h=h.previousSibling)&&h.nodeType!==1);a[f]=e||h&&h.nodeName.toLowerCase()===b?h||!1:h===b}e&&m.filter(b,a,!0)},">":function(a,b){var c,d=typeof b=="string",e=0,f=a.length;if(d&&!l.test(b)){b=b.toLowerCase();for(;e<f;e++){c=a[e];if(c){var g=c.parentNode;a[e]=g.nodeName.toLowerCase()===b?g:!1}}}else{for(;e<f;e++)c=a[e],c&&(a[e]=d?c.parentNode:c.parentNode===b);d&&m.filter(b,a,!0)}},"":function(a,b,c){var d,f=e++,g=x;typeof b=="string"&&!l.test(b)&&(b=b.toLowerCase(),d=b,g=w),g("parentNode",b,f,a,d,c)},"~":function(a,b,c){var d,f=e++,g=x;typeof b=="string"&&!l.test(b)&&(b=b.toLowerCase(),d=b,g=w),g("previousSibling",b,f,a,d,c)}},find:{ID:function(a,b,c){if(typeof b.getElementById!="undefined"&&!c){var d=b.getElementById(a[1]);return d&&d.parentNode?[d]:[]}},NAME:function(a,b){if(typeof b.getElementsByName!="undefined"){var c=[],d=b.getElementsByName(a[1]);for(var e=0,f=d.length;e<f;e++)d[e].getAttribute("name")===a[1]&&c.push(d[e]);return c.length===0?null:c}},TAG:function(a,b){if(typeof b.getElementsByTagName!="undefined")return b.getElementsByTagName(a[1])}},preFilter:{CLASS:function(a,b,c,d,e,f){a=" "+a[1].replace(j,"")+" ";if(f)return a;for(var g=0,h;(h=b[g])!=null;g++)h&&(e^(h.className&&(" "+h.className+" ").replace(/[\t\n\r]/g," ").indexOf(a)>=0)?c||d.push(h):c&&(b[g]=!1));return!1},ID:function(a){return a[1].replace(j,"")},TAG:function(a,b){return a[1].replace(j,"").toLowerCase()},CHILD:function(a){if(a[1]==="nth"){a[2]||m.error(a[0]),a[2]=a[2].replace(/^\+|\s*/g,"");var b=/(-?)(\d*)(?:n([+\-]?\d*))?/.exec(a[2]==="even"&&"2n"||a[2]==="odd"&&"2n+1"||!/\D/.test(a[2])&&"0n+"+a[2]||a[2]);a[2]=b[1]+(b[2]||1)-0,a[3]=b[3]-0}else a[2]&&m.error(a[0]);a[0]=e++;return a},ATTR:function(a,b,c,d,e,f){var g=a[1]=a[1].replace(j,"");!f&&o.attrMap[g]&&(a[1]=o.attrMap[g]),a[4]=(a[4]||a[5]||"").replace(j,""),a[2]==="~="&&(a[4]=" "+a[4]+" ");return a},PSEUDO:function(b,c,d,e,f){if(b[1]==="not")if((a.exec(b[3])||"").length>1||/^\w/.test(b[3]))b[3]=m(b[3],null,null,c);else{var g=m.filter(b[3],c,d,!0^f);d||e.push.apply(e,g);return!1}else if(o.match.POS.test(b[0])||o.match.CHILD.test(b[0]))return!0;return b},POS:function(a){a.unshift(!0);return a}},filters:{enabled:function(a){return a.disabled===!1&&a.type!=="hidden"},disabled:function(a){return a.disabled===!0},checked:function(a){return a.checked===!0},selected:function(a){a.parentNode&&a.parentNode.selectedIndex;return a.selected===!0},parent:function(a){return!!a.firstChild},empty:function(a){return!a.firstChild},has:function(a,b,c){return!!m(c[3],a).length},header:function(a){return/h\d/i.test(a.nodeName)},text:function(a){var b=a.getAttribute("type"),c=a.type;return a.nodeName.toLowerCase()==="input"&&"text"===c&&(b===c||b===null)},radio:function(a){return a.nodeName.toLowerCase()==="input"&&"radio"===a.type},checkbox:function(a){return a.nodeName.toLowerCase()==="input"&&"checkbox"===a.type},file:function(a){return a.nodeName.toLowerCase()==="input"&&"file"===a.type},password:function(a){return a.nodeName.toLowerCase()==="input"&&"password"===a.type},submit:function(a){var b=a.nodeName.toLowerCase();return(b==="input"||b==="button")&&"submit"===a.type},image:function(a){return a.nodeName.toLowerCase()==="input"&&"image"===a.type},reset:function(a){var b=a.nodeName.toLowerCase();return(b==="input"||b==="button")&&"reset"===a.type},button:function(a){var b=a.nodeName.toLowerCase();return b==="input"&&"button"===a.type||b==="button"},input:function(a){return/input|select|textarea|button/i.test(a.nodeName)},focus:function(a){return a===a.ownerDocument.activeElement}},setFilters:{first:function(a,b){return b===0},last:function(a,b,c,d){return b===d.length-1},even:function(a,b){return b%2===0},odd:function(a,b){return b%2===1},lt:function(a,b,c){return b<c[3]-0},gt:function(a,b,c){return b>c[3]-0},nth:function(a,b,c){return c[3]-0===b},eq:function(a,b,c){return c[3]-0===b}},filter:{PSEUDO:function(a,b,c,d){var e=b[1],f=o.filters[e];if(f)return f(a,c,b,d);if(e==="contains")return(a.textContent||a.innerText||n([a])||"").indexOf(b[3])>=0;if(e==="not"){var g=b[3];for(var h=0,i=g.length;h<i;h++)if(g[h]===a)return!1;return!0}m.error(e)},CHILD:function(a,b){var c,e,f,g,h,i,j,k=b[1],l=a;switch(k){case"only":case"first":while(l=l.previousSibling)if(l.nodeType===1)return!1;if(k==="first")return!0;l=a;case"last":while(l=l.nextSibling)if(l.nodeType===1)return!1;return!0;case"nth":c=b[2],e=b[3];if(c===1&&e===0)return!0;f=b[0],g=a.parentNode;if(g&&(g[d]!==f||!a.nodeIndex)){i=0;for(l=g.firstChild;l;l=l.nextSibling)l.nodeType===1&&(l.nodeIndex=++i);g[d]=f}j=a.nodeIndex-e;return c===0?j===0:j%c===0&&j/c>=0}},ID:function(a,b){return a.nodeType===1&&a.getAttribute("id")===b},TAG:function(a,b){return b==="*"&&a.nodeType===1||!!a.nodeName&&a.nodeName.toLowerCase()===b},CLASS:function(a,b){return(" "+(a.className||a.getAttribute("class"))+" ").indexOf(b)>-1},ATTR:function(a,b){var c=b[1],d=m.attr?m.attr(a,c):o.attrHandle[c]?o.attrHandle[c](a):a[c]!=null?a[c]:a.getAttribute(c),e=d+"",f=b[2],g=b[4];return d==null?f==="!=":!f&&m.attr?d!=null:f==="="?e===g:f==="*="?e.indexOf(g)>=0:f==="~="?(" "+e+" ").indexOf(g)>=0:g?f==="!="?e!==g:f==="^="?e.indexOf(g)===0:f==="$="?e.substr(e.length-g.length)===g:f==="|="?e===g||e.substr(0,g.length+1)===g+"-":!1:e&&d!==!1},POS:function(a,b,c,d){var e=b[2],f=o.setFilters[e];if(f)return f(a,c,b,d)}}},p=o.match.POS,q=function(a,b){return"\\"+(b-0+1)};for(var r in o.match)o.match[r]=new RegExp(o.match[r].source+/(?![^\[]*\])(?![^\(]*\))/.source),o.leftMatch[r]=new RegExp(/(^(?:.|\r|\n)*?)/.source+o.match[r].source.replace(/\\(\d+)/g,q));o.match.globalPOS=p;var s=function(a,b){a=Array.prototype.slice.call(a,0);if(b){b.push.apply(b,a);return b}return a};try{Array.prototype.slice.call(c.documentElement.childNodes,0)[0].nodeType}catch(t){s=function(a,b){var c=0,d=b||[];if(g.call(a)==="[object Array]")Array.prototype.push.apply(d,a);else if(typeof a.length=="number")for(var e=a.length;c<e;c++)d.push(a[c]);else for(;a[c];c++)d.push(a[c]);return d}}var u,v;c.documentElement.compareDocumentPosition?u=function(a,b){if(a===b){h=!0;return 0}if(!a.compareDocumentPosition||!b.compareDocumentPosition)return a.compareDocumentPosition?-1:1;return a.compareDocumentPosition(b)&4?-1:1}:(u=function(a,b){if(a===b){h=!0;return 0}if(a.sourceIndex&&b.sourceIndex)return a.sourceIndex-b.sourceIndex;var c,d,e=[],f=[],g=a.parentNode,i=b.parentNode,j=g;if(g===i)return v(a,b);if(!g)return-1;if(!i)return 1;while(j)e.unshift(j),j=j.parentNode;j=i;while(j)f.unshift(j),j=j.parentNode;c=e.length,d=f.length;for(var k=0;k<c&&k<d;k++)if(e[k]!==f[k])return v(e[k],f[k]);return k===c?v(a,f[k],-1):v(e[k],b,1)},v=function(a,b,c){if(a===b)return c;var d=a.nextSibling;while(d){if(d===b)return-1;d=d.nextSibling}return 1}),function(){var a=c.createElement("div"),d="script"+(new Date).getTime(),e=c.documentElement;a.innerHTML="<a name='"+d+"'/>",e.insertBefore(a,e.firstChild),c.getElementById(d)&&(o.find.ID=function(a,c,d){if(typeof c.getElementById!="undefined"&&!d){var e=c.getElementById(a[1]);return e?e.id===a[1]||typeof e.getAttributeNode!="undefined"&&e.getAttributeNode("id").nodeValue===a[1]?[e]:b:[]}},o.filter.ID=function(a,b){var c=typeof a.getAttributeNode!="undefined"&&a.getAttributeNode("id");return a.nodeType===1&&c&&c.nodeValue===b}),e.removeChild(a),e=a=null}(),function(){var a=c.createElement("div");a.appendChild(c.createComment("")),a.getElementsByTagName("*").length>0&&(o.find.TAG=function(a,b){var c=b.getElementsByTagName(a[1]);if(a[1]==="*"){var d=[];for(var e=0;c[e];e++)c[e].nodeType===1&&d.push(c[e]);c=d}return c}),a.innerHTML="<a href='#'></a>",a.firstChild&&typeof a.firstChild.getAttribute!="undefined"&&a.firstChild.getAttribute("href")!=="#"&&(o.attrHandle.href=function(a){return a.getAttribute("href",2)}),a=null}(),c.querySelectorAll&&function(){var a=m,b=c.createElement("div"),d="__sizzle__";b.innerHTML="<p class='TEST'></p>";if(!b.querySelectorAll||b.querySelectorAll(".TEST").length!==0){m=function(b,e,f,g){e=e||c;if(!g&&!m.isXML(e)){var h=/^(\w+$)|^\.([\w\-]+$)|^#([\w\-]+$)/.exec(b);if(h&&(e.nodeType===1||e.nodeType===9)){if(h[1])return s(e.getElementsByTagName(b),f);if(h[2]&&o.find.CLASS&&e.getElementsByClassName)return s(e.getElementsByClassName(h[2]),f)}if(e.nodeType===9){if(b==="body"&&e.body)return s([e.body],f);if(h&&h[3]){var i=e.getElementById(h[3]);if(!i||!i.parentNode)return s([],f);if(i.id===h[3])return s([i],f)}try{return s(e.querySelectorAll(b),f)}catch(j){}}else if(e.nodeType===1&&e.nodeName.toLowerCase()!=="object"){var k=e,l=e.getAttribute("id"),n=l||d,p=e.parentNode,q=/^\s*[+~]/.test(b);l?n=n.replace(/'/g,"\\$&"):e.setAttribute("id",n),q&&p&&(e=e.parentNode);try{if(!q||p)return s(e.querySelectorAll("[id='"+n+"'] "+b),f)}catch(r){}finally{l||k.removeAttribute("id")}}}return a(b,e,f,g)};for(var e in a)m[e]=a[e];b=null}}(),function(){var a=c.documentElement,b=a.matchesSelector||a.mozMatchesSelector||a.webkitMatchesSelector||a.msMatchesSelector;if(b){var d=!b.call(c.createElement("div"),"div"),e=!1;try{b.call(c.documentElement,"[test!='']:sizzle")}catch(f){e=!0}m.matchesSelector=function(a,c){c=c.replace(/\=\s*([^'"\]]*)\s*\]/g,"='$1']");if(!m.isXML(a))try{if(e||!o.match.PSEUDO.test(c)&&!/!=/.test(c)){var f=b.call(a,c);if(f||!d||a.document&&a.document.nodeType!==11)return f}}catch(g){}return m(c,null,null,[a]).length>0}}}(),function(){var a=c.createElement("div");a.innerHTML="<div class='test e'></div><div class='test'></div>";if(!!a.getElementsByClassName&&a.getElementsByClassName("e").length!==0){a.lastChild.className="e";if(a.getElementsByClassName("e").length===1)return;o.order.splice(1,0,"CLASS"),o.find.CLASS=function(a,b,c){if(typeof b.getElementsByClassName!="undefined"&&!c)return b.getElementsByClassName(a[1])},a=null}}(),c.documentElement.contains?m.contains=function(a,b){return a!==b&&(a.contains?a.contains(b):!0)}:c.documentElement.compareDocumentPosition?m.contains=function(a,b){return!!(a.compareDocumentPosition(b)&16)}:m.contains=function(){return!1},m.isXML=function(a){var b=(a?a.ownerDocument||a:0).documentElement;return b?b.nodeName!=="HTML":!1};var y=function(a,b,c){var d,e=[],f="",g=b.nodeType?[b]:b;while(d=o.match.PSEUDO.exec(a))f+=d[0],a=a.replace(o.match.PSEUDO,"");a=o.relative[a]?a+"*":a;for(var h=0,i=g.length;h<i;h++)m(a,g[h],e,c);return m.filter(f,e)};m.attr=f.attr,m.selectors.attrMap={},f.find=m,f.expr=m.selectors,f.expr[":"]=f.expr.filters,f.unique=m.uniqueSort,f.text=m.getText,f.isXMLDoc=m.isXML,f.contains=m.contains}();var L=/Until$/,M=/^(?:parents|prevUntil|prevAll)/,N=/,/,O=/^.[^:#\[\.,]*$/,P=Array.prototype.slice,Q=f.expr.match.globalPOS,R={children:!0,contents:!0,next:!0,prev:!0};f.fn.extend({find:function(a){var b=this,c,d;if(typeof a!="string")return f(a).filter(function(){for(c=0,d=b.length;c<d;c++)if(f.contains(b[c],this))return!0});var e=this.pushStack("","find",a),g,h,i;for(c=0,d=this.length;c<d;c++){g=e.length,f.find(a,this[c],e);if(c>0)for(h=g;h<e.length;h++)for(i=0;i<g;i++)if(e[i]===e[h]){e.splice(h--,1);break}}return e},has:function(a){var b=f(a);return this.filter(function(){for(var a=0,c=b.length;a<c;a++)if(f.contains(this,b[a]))return!0})},not:function(a){return this.pushStack(T(this,a,!1),"not",a)},filter:function(a){return this.pushStack(T(this,a,!0),"filter",a)},is:function(a){return!!a&&(typeof a=="string"?Q.test(a)?f(a,this.context).index(this[0])>=0:f.filter(a,this).length>0:this.filter(a).length>0)},closest:function(a,b){var c=[],d,e,g=this[0];if(f.isArray(a)){var h=1;while(g&&g.ownerDocument&&g!==b){for(d=0;d<a.length;d++)f(g).is(a[d])&&c.push({selector:a[d],elem:g,level:h});g=g.parentNode,h++}return c}var i=Q.test(a)||typeof a!="string"?f(a,b||this.context):0;for(d=0,e=this.length;d<e;d++){g=this[d];while(g){if(i?i.index(g)>-1:f.find.matchesSelector(g,a)){c.push(g);break}g=g.parentNode;if(!g||!g.ownerDocument||g===b||g.nodeType===11)break}}c=c.length>1?f.unique(c):c;return this.pushStack(c,"closest",a)},index:function(a){if(!a)return this[0]&&this[0].parentNode?this.prevAll().length:-1;if(typeof a=="string")return f.inArray(this[0],f(a));return f.inArray(a.jquery?a[0]:a,this)},add:function(a,b){var c=typeof a=="string"?f(a,b):f.makeArray(a&&a.nodeType?[a]:a),d=f.merge(this.get(),c);return this.pushStack(S(c[0])||S(d[0])?d:f.unique(d))},andSelf:function(){return this.add(this.prevObject)}}),f.each({parent:function(a){var b=a.parentNode;return b&&b.nodeType!==11?b:null},parents:function(a){return f.dir(a,"parentNode")},parentsUntil:function(a,b,c){return f.dir(a,"parentNode",c)},next:function(a){return f.nth(a,2,"nextSibling")},prev:function(a){return f.nth(a,2,"previousSibling")},nextAll:function(a){return f.dir(a,"nextSibling")},prevAll:function(a){return f.dir(a,"previousSibling")},nextUntil:function(a,b,c){return f.dir(a,"nextSibling",c)},prevUntil:function(a,b,c){return f.dir(a,"previousSibling",c)},siblings:function(a){return f.sibling((a.parentNode||{}).firstChild,a)},children:function(a){return f.sibling(a.firstChild)},contents:function(a){return f.nodeName(a,"iframe")?a.contentDocument||a.contentWindow.document:f.makeArray(a.childNodes)}},function(a,b){f.fn[a]=function(c,d){var e=f.map(this,b,c);L.test(a)||(d=c),d&&typeof d=="string"&&(e=f.filter(d,e)),e=this.length>1&&!R[a]?f.unique(e):e,(this.length>1||N.test(d))&&M.test(a)&&(e=e.reverse());return this.pushStack(e,a,P.call(arguments).join(","))}}),f.extend({filter:function(a,b,c){c&&(a=":not("+a+")");return b.length===1?f.find.matchesSelector(b[0],a)?[b[0]]:[]:f.find.matches(a,b)},dir:function(a,c,d){var e=[],g=a[c];while(g&&g.nodeType!==9&&(d===b||g.nodeType!==1||!f(g).is(d)))g.nodeType===1&&e.push(g),g=g[c];return e},nth:function(a,b,c,d){b=b||1;var e=0;for(;a;a=a[c])if(a.nodeType===1&&++e===b)break;return a},sibling:function(a,b){var c=[];for(;a;a=a.nextSibling)a.nodeType===1&&a!==b&&c.push(a);return c}});var V="abbr|article|aside|audio|bdi|canvas|data|datalist|details|figcaption|figure|footer|header|hgroup|mark|meter|nav|output|progress|section|summary|time|video",W=/ jQuery\d+="(?:\d+|null)"/g,X=/^\s+/,Y=/<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/ig,Z=/<([\w:]+)/,$=/<tbody/i,_=/<|&#?\w+;/,ba=/<(?:script|style)/i,bb=/<(?:script|object|embed|option|style)/i,bc=new RegExp("<(?:"+V+")[\\s/>]","i"),bd=/checked\s*(?:[^=]|=\s*.checked.)/i,be=/\/(java|ecma)script/i,bf=/^\s*<!(?:\[CDATA\[|\-\-)/,bg={option:[1,"<select multiple='multiple'>","</select>"],legend:[1,"<fieldset>","</fieldset>"],thead:[1,"<table>","</table>"],tr:[2,"<table><tbody>","</tbody></table>"],td:[3,"<table><tbody><tr>","</tr></tbody></table>"],col:[2,"<table><tbody></tbody><colgroup>","</colgroup></table>"],area:[1,"<map>","</map>"],_default:[0,"",""]},bh=U(c);bg.optgroup=bg.option,bg.tbody=bg.tfoot=bg.colgroup=bg.caption=bg.thead,bg.th=bg.td,f.support.htmlSerialize||(bg._default=[1,"div<div>","</div>"]),f.fn.extend({text:function(a){return f.access(this,function(a){return a===b?f.text(this):this.empty().append((this[0]&&this[0].ownerDocument||c).createTextNode(a))},null,a,arguments.length)},wrapAll:function(a){if(f.isFunction(a))return this.each(function(b){f(this).wrapAll(a.call(this,b))});if(this[0]){var b=f(a,this[0].ownerDocument).eq(0).clone(!0);this[0].parentNode&&b.insertBefore(this[0]),b.map(function(){var a=this;while(a.firstChild&&a.firstChild.nodeType===1)a=a.firstChild;return a}).append(this)}return this},wrapInner:function(a){if(f.isFunction(a))return this.each(function(b){f(this).wrapInner(a.call(this,b))});return this.each(function(){var b=f(this),c=b.contents();c.length?c.wrapAll(a):b.append(a)})},wrap:function(a){var b=f.isFunction(a);return this.each(function(c){f(this).wrapAll(b?a.call(this,c):a)})},unwrap:function(){return this.parent().each(function(){f.nodeName(this,"body")||f(this).replaceWith(this.childNodes)}).end()},append:function(){return this.domManip(arguments,!0,function(a){this.nodeType===1&&this.appendChild(a)})},prepend:function(){return this.domManip(arguments,!0,function(a){this.nodeType===1&&this.insertBefore(a,this.firstChild)})},before:function(){if(this[0]&&this[0].parentNode)return this.domManip(arguments,!1,function(a){this.parentNode.insertBefore(a,this)});if(arguments.length){var a=f
    --.clean(arguments);a.push.apply(a,this.toArray());return this.pushStack(a,"before",arguments)}},after:function(){if(this[0]&&this[0].parentNode)return this.domManip(arguments,!1,function(a){this.parentNode.insertBefore(a,this.nextSibling)});if(arguments.length){var a=this.pushStack(this,"after",arguments);a.push.apply(a,f.clean(arguments));return a}},remove:function(a,b){for(var c=0,d;(d=this[c])!=null;c++)if(!a||f.filter(a,[d]).length)!b&&d.nodeType===1&&(f.cleanData(d.getElementsByTagName("*")),f.cleanData([d])),d.parentNode&&d.parentNode.removeChild(d);return this},empty:function(){for(var a=0,b;(b=this[a])!=null;a++){b.nodeType===1&&f.cleanData(b.getElementsByTagName("*"));while(b.firstChild)b.removeChild(b.firstChild)}return this},clone:function(a,b){a=a==null?!1:a,b=b==null?a:b;return this.map(function(){return f.clone(this,a,b)})},html:function(a){return f.access(this,function(a){var c=this[0]||{},d=0,e=this.length;if(a===b)return c.nodeType===1?c.innerHTML.replace(W,""):null;if(typeof a=="string"&&!ba.test(a)&&(f.support.leadingWhitespace||!X.test(a))&&!bg[(Z.exec(a)||["",""])[1].toLowerCase()]){a=a.replace(Y,"<$1></$2>");try{for(;d<e;d++)c=this[d]||{},c.nodeType===1&&(f.cleanData(c.getElementsByTagName("*")),c.innerHTML=a);c=0}catch(g){}}c&&this.empty().append(a)},null,a,arguments.length)},replaceWith:function(a){if(this[0]&&this[0].parentNode){if(f.isFunction(a))return this.each(function(b){var c=f(this),d=c.html();c.replaceWith(a.call(this,b,d))});typeof a!="string"&&(a=f(a).detach());return this.each(function(){var b=this.nextSibling,c=this.parentNode;f(this).remove(),b?f(b).before(a):f(c).append(a)})}return this.length?this.pushStack(f(f.isFunction(a)?a():a),"replaceWith",a):this},detach:function(a){return this.remove(a,!0)},domManip:function(a,c,d){var e,g,h,i,j=a[0],k=[];if(!f.support.checkClone&&arguments.length===3&&typeof j=="string"&&bd.test(j))return this.each(function(){f(this).domManip(a,c,d,!0)});if(f.isFunction(j))return this.each(function(e){var g=f(this);a[0]=j.call(this,e,c?g.html():b),g.domManip(a,c,d)});if(this[0]){i=j&&j.parentNode,f.support.parentNode&&i&&i.nodeType===11&&i.childNodes.length===this.length?e={fragment:i}:e=f.buildFragment(a,this,k),h=e.fragment,h.childNodes.length===1?g=h=h.firstChild:g=h.firstChild;if(g){c=c&&f.nodeName(g,"tr");for(var l=0,m=this.length,n=m-1;l<m;l++)d.call(c?bi(this[l],g):this[l],e.cacheable||m>1&&l<n?f.clone(h,!0,!0):h)}k.length&&f.each(k,function(a,b){b.src?f.ajax({type:"GET",global:!1,url:b.src,async:!1,dataType:"script"}):f.globalEval((b.text||b.textContent||b.innerHTML||"").replace(bf,"/*$0*/")),b.parentNode&&b.parentNode.removeChild(b)})}return this}}),f.buildFragment=function(a,b,d){var e,g,h,i,j=a[0];b&&b[0]&&(i=b[0].ownerDocument||b[0]),i.createDocumentFragment||(i=c),a.length===1&&typeof j=="string"&&j.length<512&&i===c&&j.charAt(0)==="<"&&!bb.test(j)&&(f.support.checkClone||!bd.test(j))&&(f.support.html5Clone||!bc.test(j))&&(g=!0,h=f.fragments[j],h&&h!==1&&(e=h)),e||(e=i.createDocumentFragment(),f.clean(a,i,e,d)),g&&(f.fragments[j]=h?e:1);return{fragment:e,cacheable:g}},f.fragments={},f.each({appendTo:"append",prependTo:"prepend",insertBefore:"before",insertAfter:"after",replaceAll:"replaceWith"},function(a,b){f.fn[a]=function(c){var d=[],e=f(c),g=this.length===1&&this[0].parentNode;if(g&&g.nodeType===11&&g.childNodes.length===1&&e.length===1){e[b](this[0]);return this}for(var h=0,i=e.length;h<i;h++){var j=(h>0?this.clone(!0):this).get();f(e[h])[b](j),d=d.concat(j)}return this.pushStack(d,a,e.selector)}}),f.extend({clone:function(a,b,c){var d,e,g,h=f.support.html5Clone||f.isXMLDoc(a)||!bc.test("<"+a.nodeName+">")?a.cloneNode(!0):bo(a);if((!f.support.noCloneEvent||!f.support.noCloneChecked)&&(a.nodeType===1||a.nodeType===11)&&!f.isXMLDoc(a)){bk(a,h),d=bl(a),e=bl(h);for(g=0;d[g];++g)e[g]&&bk(d[g],e[g])}if(b){bj(a,h);if(c){d=bl(a),e=bl(h);for(g=0;d[g];++g)bj(d[g],e[g])}}d=e=null;return h},clean:function(a,b,d,e){var g,h,i,j=[];b=b||c,typeof b.createElement=="undefined"&&(b=b.ownerDocument||b[0]&&b[0].ownerDocument||c);for(var k=0,l;(l=a[k])!=null;k++){typeof l=="number"&&(l+="");if(!l)continue;if(typeof l=="string")if(!_.test(l))l=b.createTextNode(l);else{l=l.replace(Y,"<$1></$2>");var m=(Z.exec(l)||["",""])[1].toLowerCase(),n=bg[m]||bg._default,o=n[0],p=b.createElement("div"),q=bh.childNodes,r;b===c?bh.appendChild(p):U(b).appendChild(p),p.innerHTML=n[1]+l+n[2];while(o--)p=p.lastChild;if(!f.support.tbody){var s=$.test(l),t=m==="table"&&!s?p.firstChild&&p.firstChild.childNodes:n[1]==="<table>"&&!s?p.childNodes:[];for(i=t.length-1;i>=0;--i)f.nodeName(t[i],"tbody")&&!t[i].childNodes.length&&t[i].parentNode.removeChild(t[i])}!f.support.leadingWhitespace&&X.test(l)&&p.insertBefore(b.createTextNode(X.exec(l)[0]),p.firstChild),l=p.childNodes,p&&(p.parentNode.removeChild(p),q.length>0&&(r=q[q.length-1],r&&r.parentNode&&r.parentNode.removeChild(r)))}var u;if(!f.support.appendChecked)if(l[0]&&typeof (u=l.length)=="number")for(i=0;i<u;i++)bn(l[i]);else bn(l);l.nodeType?j.push(l):j=f.merge(j,l)}if(d){g=function(a){return!a.type||be.test(a.type)};for(k=0;j[k];k++){h=j[k];if(e&&f.nodeName(h,"script")&&(!h.type||be.test(h.type)))e.push(h.parentNode?h.parentNode.removeChild(h):h);else{if(h.nodeType===1){var v=f.grep(h.getElementsByTagName("script"),g);j.splice.apply(j,[k+1,0].concat(v))}d.appendChild(h)}}}return j},cleanData:function(a){var b,c,d=f.cache,e=f.event.special,g=f.support.deleteExpando;for(var h=0,i;(i=a[h])!=null;h++){if(i.nodeName&&f.noData[i.nodeName.toLowerCase()])continue;c=i[f.expando];if(c){b=d[c];if(b&&b.events){for(var j in b.events)e[j]?f.event.remove(i,j):f.removeEvent(i,j,b.handle);b.handle&&(b.handle.elem=null)}g?delete i[f.expando]:i.removeAttribute&&i.removeAttribute(f.expando),delete d[c]}}}});var bp=/alpha\([^)]*\)/i,bq=/opacity=([^)]*)/,br=/([A-Z]|^ms)/g,bs=/^[\-+]?(?:\d*\.)?\d+$/i,bt=/^-?(?:\d*\.)?\d+(?!px)[^\d\s]+$/i,bu=/^([\-+])=([\-+.\de]+)/,bv=/^margin/,bw={position:"absolute",visibility:"hidden",display:"block"},bx=["Top","Right","Bottom","Left"],by,bz,bA;f.fn.css=function(a,c){return f.access(this,function(a,c,d){return d!==b?f.style(a,c,d):f.css(a,c)},a,c,arguments.length>1)},f.extend({cssHooks:{opacity:{get:function(a,b){if(b){var c=by(a,"opacity");return c===""?"1":c}return a.style.opacity}}},cssNumber:{fillOpacity:!0,fontWeight:!0,lineHeight:!0,opacity:!0,orphans:!0,widows:!0,zIndex:!0,zoom:!0},cssProps:{"float":f.support.cssFloat?"cssFloat":"styleFloat"},style:function(a,c,d,e){if(!!a&&a.nodeType!==3&&a.nodeType!==8&&!!a.style){var g,h,i=f.camelCase(c),j=a.style,k=f.cssHooks[i];c=f.cssProps[i]||i;if(d===b){if(k&&"get"in k&&(g=k.get(a,!1,e))!==b)return g;return j[c]}h=typeof d,h==="string"&&(g=bu.exec(d))&&(d=+(g[1]+1)*+g[2]+parseFloat(f.css(a,c)),h="number");if(d==null||h==="number"&&isNaN(d))return;h==="number"&&!f.cssNumber[i]&&(d+="px");if(!k||!("set"in k)||(d=k.set(a,d))!==b)try{j[c]=d}catch(l){}}},css:function(a,c,d){var e,g;c=f.camelCase(c),g=f.cssHooks[c],c=f.cssProps[c]||c,c==="cssFloat"&&(c="float");if(g&&"get"in g&&(e=g.get(a,!0,d))!==b)return e;if(by)return by(a,c)},swap:function(a,b,c){var d={},e,f;for(f in b)d[f]=a.style[f],a.style[f]=b[f];e=c.call(a);for(f in b)a.style[f]=d[f];return e}}),f.curCSS=f.css,c.defaultView&&c.defaultView.getComputedStyle&&(bz=function(a,b){var c,d,e,g,h=a.style;b=b.replace(br,"-$1").toLowerCase(),(d=a.ownerDocument.defaultView)&&(e=d.getComputedStyle(a,null))&&(c=e.getPropertyValue(b),c===""&&!f.contains(a.ownerDocument.documentElement,a)&&(c=f.style(a,b))),!f.support.pixelMargin&&e&&bv.test(b)&&bt.test(c)&&(g=h.width,h.width=c,c=e.width,h.width=g);return c}),c.documentElement.currentStyle&&(bA=function(a,b){var c,d,e,f=a.currentStyle&&a.currentStyle[b],g=a.style;f==null&&g&&(e=g[b])&&(f=e),bt.test(f)&&(c=g.left,d=a.runtimeStyle&&a.runtimeStyle.left,d&&(a.runtimeStyle.left=a.currentStyle.left),g.left=b==="fontSize"?"1em":f,f=g.pixelLeft+"px",g.left=c,d&&(a.runtimeStyle.left=d));return f===""?"auto":f}),by=bz||bA,f.each(["height","width"],function(a,b){f.cssHooks[b]={get:function(a,c,d){if(c)return a.offsetWidth!==0?bB(a,b,d):f.swap(a,bw,function(){return bB(a,b,d)})},set:function(a,b){return bs.test(b)?b+"px":b}}}),f.support.opacity||(f.cssHooks.opacity={get:function(a,b){return bq.test((b&&a.currentStyle?a.currentStyle.filter:a.style.filter)||"")?parseFloat(RegExp.$1)/100+"":b?"1":""},set:function(a,b){var c=a.style,d=a.currentStyle,e=f.isNumeric(b)?"alpha(opacity="+b*100+")":"",g=d&&d.filter||c.filter||"";c.zoom=1;if(b>=1&&f.trim(g.replace(bp,""))===""){c.removeAttribute("filter");if(d&&!d.filter)return}c.filter=bp.test(g)?g.replace(bp,e):g+" "+e}}),f(function(){f.support.reliableMarginRight||(f.cssHooks.marginRight={get:function(a,b){return f.swap(a,{display:"inline-block"},function(){return b?by(a,"margin-right"):a.style.marginRight})}})}),f.expr&&f.expr.filters&&(f.expr.filters.hidden=function(a){var b=a.offsetWidth,c=a.offsetHeight;return b===0&&c===0||!f.support.reliableHiddenOffsets&&(a.style&&a.style.display||f.css(a,"display"))==="none"},f.expr.filters.visible=function(a){return!f.expr.filters.hidden(a)}),f.each({margin:"",padding:"",border:"Width"},function(a,b){f.cssHooks[a+b]={expand:function(c){var d,e=typeof c=="string"?c.split(" "):[c],f={};for(d=0;d<4;d++)f[a+bx[d]+b]=e[d]||e[d-2]||e[0];return f}}});var bC=/%20/g,bD=/\[\]$/,bE=/\r?\n/g,bF=/#.*$/,bG=/^(.*?):[ \t]*([^\r\n]*)\r?$/mg,bH=/^(?:color|date|datetime|datetime-local|email|hidden|month|number|password|range|search|tel|text|time|url|week)$/i,bI=/^(?:about|app|app\-storage|.+\-extension|file|res|widget):$/,bJ=/^(?:GET|HEAD)$/,bK=/^\/\//,bL=/\?/,bM=/<script\b[^<]*(?:(?!<\/script>)<[^<]*)*<\/script>/gi,bN=/^(?:select|textarea)/i,bO=/\s+/,bP=/([?&])_=[^&]*/,bQ=/^([\w\+\.\-]+:)(?:\/\/([^\/?#:]*)(?::(\d+))?)?/,bR=f.fn.load,bS={},bT={},bU,bV,bW=["*/"]+["*"];try{bU=e.href}catch(bX){bU=c.createElement("a"),bU.href="",bU=bU.href}bV=bQ.exec(bU.toLowerCase())||[],f.fn.extend({load:function(a,c,d){if(typeof a!="string"&&bR)return bR.apply(this,arguments);if(!this.length)return this;var e=a.indexOf(" ");if(e>=0){var g=a.slice(e,a.length);a=a.slice(0,e)}var h="GET";c&&(f.isFunction(c)?(d=c,c=b):typeof c=="object"&&(c=f.param(c,f.ajaxSettings.traditional),h="POST"));var i=this;f.ajax({url:a,type:h,dataType:"html",data:c,complete:function(a,b,c){c=a.responseText,a.isResolved()&&(a.done(function(a){c=a}),i.html(g?f("<div>").append(c.replace(bM,"")).find(g):c)),d&&i.each(d,[c,b,a])}});return this},serialize:function(){return f.param(this.serializeArray())},serializeArray:function(){return this.map(function(){return this.elements?f.makeArray(this.elements):this}).filter(function(){return this.name&&!this.disabled&&(this.checked||bN.test(this.nodeName)||bH.test(this.type))}).map(function(a,b){var c=f(this).val();return c==null?null:f.isArray(c)?f.map(c,function(a,c){return{name:b.name,value:a.replace(bE,"\r\n")}}):{name:b.name,value:c.replace(bE,"\r\n")}}).get()}}),f.each("ajaxStart ajaxStop ajaxComplete ajaxError ajaxSuccess ajaxSend".split(" "),function(a,b){f.fn[b]=function(a){return this.on(b,a)}}),f.each(["get","post"],function(a,c){f[c]=function(a,d,e,g){f.isFunction(d)&&(g=g||e,e=d,d=b);return f.ajax({type:c,url:a,data:d,success:e,dataType:g})}}),f.extend({getScript:function(a,c){return f.get(a,b,c,"script")},getJSON:function(a,b,c){return f.get(a,b,c,"json")},ajaxSetup:function(a,b){b?b$(a,f.ajaxSettings):(b=a,a=f.ajaxSettings),b$(a,b);return a},ajaxSettings:{url:bU,isLocal:bI.test(bV[1]),global:!0,type:"GET",contentType:"application/x-www-form-urlencoded; charset=UTF-8",processData:!0,async:!0,accepts:{xml:"application/xml, text/xml",html:"text/html",text:"text/plain",json:"application/json, text/javascript","*":bW},contents:{xml:/xml/,html:/html/,json:/json/},responseFields:{xml:"responseXML",text:"responseText"},converters:{"* text":a.String,"text html":!0,"text json":f.parseJSON,"text xml":f.parseXML},flatOptions:{context:!0,url:!0}},ajaxPrefilter:bY(bS),ajaxTransport:bY(bT),ajax:function(a,c){function w(a,c,l,m){if(s!==2){s=2,q&&clearTimeout(q),p=b,n=m||"",v.readyState=a>0?4:0;var o,r,u,w=c,x=l?ca(d,v,l):b,y,z;if(a>=200&&a<300||a===304){if(d.ifModified){if(y=v.getResponseHeader("Last-Modified"))f.lastModified[k]=y;if(z=v.getResponseHeader("Etag"))f.etag[k]=z}if(a===304)w="notmodified",o=!0;else try{r=cb(d,x),w="success",o=!0}catch(A){w="parsererror",u=A}}else{u=w;if(!w||a)w="error",a<0&&(a=0)}v.status=a,v.statusText=""+(c||w),o?h.resolveWith(e,[r,w,v]):h.rejectWith(e,[v,w,u]),v.statusCode(j),j=b,t&&g.trigger("ajax"+(o?"Success":"Error"),[v,d,o?r:u]),i.fireWith(e,[v,w]),t&&(g.trigger("ajaxComplete",[v,d]),--f.active||f.event.trigger("ajaxStop"))}}typeof a=="object"&&(c=a,a=b),c=c||{};var d=f.ajaxSetup({},c),e=d.context||d,g=e!==d&&(e.nodeType||e instanceof f)?f(e):f.event,h=f.Deferred(),i=f.Callbacks("once memory"),j=d.statusCode||{},k,l={},m={},n,o,p,q,r,s=0,t,u,v={readyState:0,setRequestHeader:function(a,b){if(!s){var c=a.toLowerCase();a=m[c]=m[c]||a,l[a]=b}return this},getAllResponseHeaders:function(){return s===2?n:null},getResponseHeader:function(a){var c;if(s===2){if(!o){o={};while(c=bG.exec(n))o[c[1].toLowerCase()]=c[2]}c=o[a.toLowerCase()]}return c===b?null:c},overrideMimeType:function(a){s||(d.mimeType=a);return this},abort:function(a){a=a||"abort",p&&p.abort(a),w(0,a);return this}};h.promise(v),v.success=v.done,v.error=v.fail,v.complete=i.add,v.statusCode=function(a){if(a){var b;if(s<2)for(b in a)j[b]=[j[b],a[b]];else b=a[v.status],v.then(b,b)}return this},d.url=((a||d.url)+"").replace(bF,"").replace(bK,bV[1]+"//"),d.dataTypes=f.trim(d.dataType||"*").toLowerCase().split(bO),d.crossDomain==null&&(r=bQ.exec(d.url.toLowerCase()),d.crossDomain=!(!r||r[1]==bV[1]&&r[2]==bV[2]&&(r[3]||(r[1]==="http:"?80:443))==(bV[3]||(bV[1]==="http:"?80:443)))),d.data&&d.processData&&typeof d.data!="string"&&(d.data=f.param(d.data,d.traditional)),bZ(bS,d,c,v);if(s===2)return!1;t=d.global,d.type=d.type.toUpperCase(),d.hasContent=!bJ.test(d.type),t&&f.active++===0&&f.event.trigger("ajaxStart");if(!d.hasContent){d.data&&(d.url+=(bL.test(d.url)?"&":"?")+d.data,delete d.data),k=d.url;if(d.cache===!1){var x=f.now(),y=d.url.replace(bP,"$1_="+x);d.url=y+(y===d.url?(bL.test(d.url)?"&":"?")+"_="+x:"")}}(d.data&&d.hasContent&&d.contentType!==!1||c.contentType)&&v.setRequestHeader("Content-Type",d.contentType),d.ifModified&&(k=k||d.url,f.lastModified[k]&&v.setRequestHeader("If-Modified-Since",f.lastModified[k]),f.etag[k]&&v.setRequestHeader("If-None-Match",f.etag[k])),v.setRequestHeader("Accept",d.dataTypes[0]&&d.accepts[d.dataTypes[0]]?d.accepts[d.dataTypes[0]]+(d.dataTypes[0]!=="*"?", "+bW+"; q=0.01":""):d.accepts["*"]);for(u in d.headers)v.setRequestHeader(u,d.headers[u]);if(d.beforeSend&&(d.beforeSend.call(e,v,d)===!1||s===2)){v.abort();return!1}for(u in{success:1,error:1,complete:1})v[u](d[u]);p=bZ(bT,d,c,v);if(!p)w(-1,"No Transport");else{v.readyState=1,t&&g.trigger("ajaxSend",[v,d]),d.async&&d.timeout>0&&(q=setTimeout(function(){v.abort("timeout")},d.timeout));try{s=1,p.send(l,w)}catch(z){if(s<2)w(-1,z);else throw z}}return v},param:function(a,c){var d=[],e=function(a,b){b=f.isFunction(b)?b():b,d[d.length]=encodeURIComponent(a)+"="+encodeURIComponent(b)};c===b&&(c=f.ajaxSettings.traditional);if(f.isArray(a)||a.jquery&&!f.isPlainObject(a))f.each(a,function(){e(this.name,this.value)});else for(var g in a)b_(g,a[g],c,e);return d.join("&").replace(bC,"+")}}),f.extend({active:0,lastModified:{},etag:{}});var cc=f.now(),cd=/(\=)\?(&|$)|\?\?/i;f.ajaxSetup({jsonp:"callback",jsonpCallback:function(){return f.expando+"_"+cc++}}),f.ajaxPrefilter("json jsonp",function(b,c,d){var e=typeof b.data=="string"&&/^application\/x\-www\-form\-urlencoded/.test(b.contentType);if(b.dataTypes[0]==="jsonp"||b.jsonp!==!1&&(cd.test(b.url)||e&&cd.test(b.data))){var g,h=b.jsonpCallback=f.isFunction(b.jsonpCallback)?b.jsonpCallback():b.jsonpCallback,i=a[h],j=b.url,k=b.data,l="$1"+h+"$2";b.jsonp!==!1&&(j=j.replace(cd,l),b.url===j&&(e&&(k=k.replace(cd,l)),b.data===k&&(j+=(/\?/.test(j)?"&":"?")+b.jsonp+"="+h))),b.url=j,b.data=k,a[h]=function(a){g=[a]},d.always(function(){a[h]=i,g&&f.isFunction(i)&&a[h](g[0])}),b.converters["script json"]=function(){g||f.error(h+" was not called");return g[0]},b.dataTypes[0]="json";return"script"}}),f.ajaxSetup({accepts:{script:"text/javascript, application/javascript, application/ecmascript, application/x-ecmascript"},contents:{script:/javascript|ecmascript/},converters:{"text script":function(a){f.globalEval(a);return a}}}),f.ajaxPrefilter("script",function(a){a.cache===b&&(a.cache=!1),a.crossDomain&&(a.type="GET",a.global=!1)}),f.ajaxTransport("script",function(a){if(a.crossDomain){var d,e=c.head||c.getElementsByTagName("head")[0]||c.documentElement;return{send:function(f,g){d=c.createElement("script"),d.async="async",a.scriptCharset&&(d.charset=a.scriptCharset),d.src=a.url,d.onload=d.onreadystatechange=function(a,c){if(c||!d.readyState||/loaded|complete/.test(d.readyState))d.onload=d.onreadystatechange=null,e&&d.parentNode&&e.removeChild(d),d=b,c||g(200,"success")},e.insertBefore(d,e.firstChild)},abort:function(){d&&d.onload(0,1)}}}});var ce=a.ActiveXObject?function(){for(var a in cg)cg[a](0,1)}:!1,cf=0,cg;f.ajaxSettings.xhr=a.ActiveXObject?function(){return!this.isLocal&&ch()||ci()}:ch,function(a){f.extend(f.support,{ajax:!!a,cors:!!a&&"withCredentials"in a})}(f.ajaxSettings.xhr()),f.support.ajax&&f.ajaxTransport(function(c){if(!c.crossDomain||f.support.cors){var d;return{send:function(e,g){var h=c.xhr(),i,j;c.username?h.open(c.type,c.url,c.async,c.username,c.password):h.open(c.type,c.url,c.async);if(c.xhrFields)for(j in c.xhrFields)h[j]=c.xhrFields[j];c.mimeType&&h.overrideMimeType&&h.overrideMimeType(c.mimeType),!c.crossDomain&&!e["X-Requested-With"]&&(e["X-Requested-With"]="XMLHttpRequest");try{for(j in e)h.setRequestHeader(j,e[j])}catch(k){}h.send(c.hasContent&&c.data||null),d=function(a,e){var j,k,l,m,n;try{if(d&&(e||h.readyState===4)){d=b,i&&(h.onreadystatechange=f.noop,ce&&delete cg[i]);if(e)h.readyState!==4&&h.abort();else{j=h.status,l=h.getAllResponseHeaders(),m={},n=h.responseXML,n&&n.documentElement&&(m.xml=n);try{m.text=h.responseText}catch(a){}try{k=h.statusText}catch(o){k=""}!j&&c.isLocal&&!c.crossDomain?j=m.text?200:404:j===1223&&(j=204)}}}catch(p){e||g(-1,p)}m&&g(j,k,m,l)},!c.async||h.readyState===4?d():(i=++cf,ce&&(cg||(cg={},f(a).unload(ce)),cg[i]=d),h.onreadystatechange=d)},abort:function(){d&&d(0,1)}}}});var cj={},ck,cl,cm=/^(?:toggle|show|hide)$/,cn=/^([+\-]=)?([\d+.\-]+)([a-z%]*)$/i,co,cp=[["height","marginTop","marginBottom","paddingTop","paddingBottom"],["width","marginLeft","marginRight","paddingLeft","paddingRight"],["opacity"]],cq;f.fn.extend({show:function(a,b,c){var d,e;if(a||a===0)return this.animate(ct("show",3),a,b,c);for(var g=0,h=this.length;g<h;g++)d=this[g],d.style&&(e=d.style.display,!f._data(d,"olddisplay")&&e==="none"&&(e=d.style.display=""),(e===""&&f.css(d,"display")==="none"||!f.contains(d.ownerDocument.documentElement,d))&&f._data(d,"olddisplay",cu(d.nodeName)));for(g=0;g<h;g++){d=this[g];if(d.style){e=d.style.display;if(e===""||e==="none")d.style.display=f._data(d,"olddisplay")||""}}return this},hide:function(a,b,c){if(a||a===0)return this.animate(ct("hide",3),a,b,c);var d,e,g=0,h=this.length;for(;g<h;g++)d=this[g],d.style&&(e=f.css(d,"display"),e!=="none"&&!f._data(d,"olddisplay")&&f._data(d,"olddisplay",e));for(g=0;g<h;g++)this[g].style&&(this[g].style.display="none");return this},_toggle:f.fn.toggle,toggle:function(a,b,c){var d=typeof a=="boolean";f.isFunction(a)&&f.isFunction(b)?this._toggle.apply(this,arguments):a==null||d?this.each(function(){var b=d?a:f(this).is(":hidden");f(this)[b?"show":"hide"]()}):this.animate(ct("toggle",3),a,b,c);return this},fadeTo:function(a,b,c,d){return this.filter(":hidden").css("opacity",0).show().end().animate({opacity:b},a,c,d)},animate:function(a,b,c,d){function g(){e.queue===!1&&f._mark(this);var b=f.extend({},e),c=this.nodeType===1,d=c&&f(this).is(":hidden"),g,h,i,j,k,l,m,n,o,p,q;b.animatedProperties={};for(i in a){g=f.camelCase(i),i!==g&&(a[g]=a[i],delete a[i]);if((k=f.cssHooks[g])&&"expand"in k){l=k.expand(a[g]),delete a[g];for(i in l)i in a||(a[i]=l[i])}}for(g in a){h=a[g],f.isArray(h)?(b.animatedProperties[g]=h[1],h=a[g]=h[0]):b.animatedProperties[g]=b.specialEasing&&b.specialEasing[g]||b.easing||"swing";if(h==="hide"&&d||h==="show"&&!d)return b.complete.call(this);c&&(g==="height"||g==="width")&&(b.overflow=[this.style.overflow,this.style.overflowX,this.style.overflowY],f.css(this,"display")==="inline"&&f.css(this,"float")==="none"&&(!f.support.inlineBlockNeedsLayout||cu(this.nodeName)==="inline"?this.style.display="inline-block":this.style.zoom=1))}b.overflow!=null&&(this.style.overflow="hidden");for(i in a)j=new f.fx(this,b,i),h=a[i],cm.test(h)?(q=f._data(this,"toggle"+i)||(h==="toggle"?d?"show":"hide":0),q?(f._data(this,"toggle"+i,q==="show"?"hide":"show"),j[q]()):j[h]()):(m=cn.exec(h),n=j.cur(),m?(o=parseFloat(m[2]),p=m[3]||(f.cssNumber[i]?"":"px"),p!=="px"&&(f.style(this,i,(o||1)+p),n=(o||1)/j.cur()*n,f.style(this,i,n+p)),m[1]&&(o=(m[1]==="-="?-1:1)*o+n),j.custom(n,o,p)):j.custom(n,h,""));return!0}var e=f.speed(b,c,d);if(f.isEmptyObject(a))return this.each(e.complete,[!1]);a=f.extend({},a);return e.queue===!1?this.each(g):this.queue(e.queue,g)},stop:function(a,c,d){typeof a!="string"&&(d=c,c=a,a=b),c&&a!==!1&&this.queue(a||"fx",[]);return this.each(function(){function h(a,b,c){var e=b[c];f.removeData(a,c,!0),e.stop(d)}var b,c=!1,e=f.timers,g=f._data(this);d||f._unmark(!0,this);if(a==null)for(b in g)g[b]&&g[b].stop&&b.indexOf(".run")===b.length-4&&h(this,g,b);else g[b=a+".run"]&&g[b].stop&&h(this,g,b);for(b=e.length;b--;)e[b].elem===this&&(a==null||e[b].queue===a)&&(d?e[b](!0):e[b].saveState(),c=!0,e.splice(b,1));(!d||!c)&&f.dequeue(this,a)})}}),f.each({slideDown:ct("show",1),slideUp:ct("hide",1),slideToggle:ct("toggle",1),fadeIn:{opacity:"show"},fadeOut:{opacity:"hide"},fadeToggle:{opacity:"toggle"}},function(a,b){f.fn[a]=function(a,c,d){return this.animate(b,a,c,d)}}),f.extend({speed:function(a,b,c){var d=a&&typeof a=="object"?f.extend({},a):{complete:c||!c&&b||f.isFunction(a)&&a,duration:a,easing:c&&b||b&&!f.isFunction(b)&&b};d.duration=f.fx.off?0:typeof d.duration=="number"?d.duration:d.duration in f.fx.speeds?f.fx.speeds[d.duration]:f.fx.speeds._default;if(d.queue==null||d.queue===!0)d.queue="fx";d.old=d.complete,d.complete=function(a){f.isFunction(d.old)&&d.old.call(this),d.queue?f.dequeue(this,d.queue):a!==!1&&f._unmark(this)};return d},easing:{linear:function(a){return a},swing:function(a){return-Math.cos(a*Math.PI)/2+.5}},timers:[],fx:function(a,b,c){this.options=b,this.elem=a,this.prop=c,b.orig=b.orig||{}}}),f.fx.prototype={update:function(){this.options.step&&this.options.step.call(this.elem,this.now,this),(f.fx.step[this.prop]||f.fx.step._default)(this)},cur:function(){if(this.elem[this.prop]!=null&&(!this.elem.style||this.elem.style[this.prop]==null))return this.elem[this.prop];var a,b=f.css(this.elem,this.prop);return isNaN(a=parseFloat(b))?!b||b==="auto"?0:b:a},custom:function(a,c,d){function h(a){return e.step(a)}var e=this,g=f.fx;this.startTime=cq||cr(),this.end=c,this.now=this.start=a,this.pos=this.state=0,this.unit=d||this.unit||(f.cssNumber[this.prop]?"":"px"),h.queue=this.options.queue,h.elem=this.elem,h.saveState=function(){f._data(e.elem,"fxshow"+e.prop)===b&&(e.options.hide?f._data(e.elem,"fxshow"+e.prop,e.start):e.options.show&&f._data(e.elem,"fxshow"+e.prop,e.end))},h()&&f.timers.push(h)&&!co&&(co=setInterval(g.tick,g.interval))},show:function(){var a=f._data(this.elem,"fxshow"+this.prop);this.options.orig[this.prop]=a||f.style(this.elem,this.prop),this.options.show=!0,a!==b?this.custom(this.cur(),a):this.custom(this.prop==="width"||this.prop==="height"?1:0,this.cur()),f(this.elem).show()},hide:function(){this.options.orig[this.prop]=f._data(this.elem,"fxshow"+this.prop)||f.style(this.elem,this.prop),this.options.hide=!0,this.custom(this.cur(),0)},step:function(a){var b,c,d,e=cq||cr(),g=!0,h=this.elem,i=this.options;if(a||e>=i.duration+this.startTime){this.now=this.end,this.pos=this.state=1,this.update(),i.animatedProperties[this.prop]=!0;for(b in i.animatedProperties)i.animatedProperties[b]!==!0&&(g=!1);if(g){i.overflow!=null&&!f.support.shrinkWrapBlocks&&f.each(["","X","Y"],function(a,b){h.style["overflow"+b]=i.overflow[a]}),i.hide&&f(h).hide();if(i.hide||i.show)for(b in i.animatedProperties)f.style(h,b,i.orig[b]),f.removeData(h,"fxshow"+b,!0),f.removeData(h,"toggle"+b,!0);d=i.complete,d&&(i.complete=!1,d.call(h))}return!1}i.duration==Infinity?this.now=e:(c=e-this.startTime,this.state=c/i.duration,this.pos=f.easing[i.animatedProperties[this.prop]](this.state,c,0,1,i.duration),this.now=this.start+(this.end-this.start)*this.pos),this.update();return!0}},f.extend(f.fx,{tick:function(){var a,b=f.timers,c=0;for(;c<b.length;c++)a=b[c],!a()&&b[c]===a&&b.splice(c--,1);b.length||f.fx.stop()},interval:13,stop:function(){clearInterval(co),co=null},speeds:{slow:600,fast:200,_default:400},step:{opacity:function(a){f.style(a.elem,"opacity",a.now)},_default:function(a){a.elem.style&&a.elem.style[a.prop]!=null?a.elem.style[a.prop]=a.now+a.unit:a.elem[a.prop]=a.now}}}),f.each(cp.concat.apply([],cp),function(a,b){b.indexOf("margin")&&(f.fx.step[b]=function(a){f.style(a.elem,b,Math.max(0,a.now)+a.unit)})}),f.expr&&f.expr.filters&&(f.expr.filters.animated=function(a){return f.grep(f.timers,function(b){return a===b.elem}).length});var cv,cw=/^t(?:able|d|h)$/i,cx=/^(?:body|html)$/i;"getBoundingClientRect"in c.documentElement?cv=function(a,b,c,d){try{d=a.getBoundingClientRect()}catch(e){}if(!d||!f.contains(c,a))return d?{top:d.top,left:d.left}:{top:0,left:0};var g=b.body,h=cy(b),i=c.clientTop||g.clientTop||0,j=c.clientLeft||g.clientLeft||0,k=h.pageYOffset||f.support.boxModel&&c.scrollTop||g.scrollTop,l=h.pageXOffset||f.support.boxModel&&c.scrollLeft||g.scrollLeft,m=d.top+k-i,n=d.left+l-j;return{top:m,left:n}}:cv=function(a,b,c){var d,e=a.offsetParent,g=a,h=b.body,i=b.defaultView,j=i?i.getComputedStyle(a,null):a.currentStyle,k=a.offsetTop,l=a.offsetLeft;while((a=a.parentNode)&&a!==h&&a!==c){if(f.support.fixedPosition&&j.position==="fixed")break;d=i?i.getComputedStyle(a,null):a.currentStyle,k-=a.scrollTop,l-=a.scrollLeft,a===e&&(k+=a.offsetTop,l+=a.offsetLeft,f.support.doesNotAddBorder&&(!f.support.doesAddBorderForTableAndCells||!cw.test(a.nodeName))&&(k+=parseFloat(d.borderTopWidth)||0,l+=parseFloat(d.borderLeftWidth)||0),g=e,e=a.offsetParent),f.support.subtractsBorderForOverflowNotVisible&&d.overflow!=="visible"&&(k+=parseFloat(d.borderTopWidth)||0,l+=parseFloat(d.borderLeftWidth)||0),j=d}if(j.position==="relative"||j.position==="static")k+=h.offsetTop,l+=h.offsetLeft;f.support.fixedPosition&&j.position==="fixed"&&(k+=Math.max(c.scrollTop,h.scrollTop),l+=Math.max(c.scrollLeft,h.scrollLeft));return{top:k,left:l}},f.fn.offset=function(a){if(arguments.length)return a===b?this:this.each(function(b){f.offset.setOffset(this,a,b)});var c=this[0],d=c&&c.ownerDocument;if(!d)return null;if(c===d.body)return f.offset.bodyOffset(c);return cv(c,d,d.documentElement)},f.offset={bodyOffset:function(a){var b=a.offsetTop,c=a.offsetLeft;f.support.doesNotIncludeMarginInBodyOffset&&(b+=parseFloat(f.css(a,"marginTop"))||0,c+=parseFloat(f.css(a,"marginLeft"))||0);return{top:b,left:c}},setOffset:function(a,b,c){var d=f.css(a,"position");d==="static"&&(a.style.position="relative");var e=f(a),g=e.offset(),h=f.css(a,"top"),i=f.css(a,"left"),j=(d==="absolute"||d==="fixed")&&f.inArray("auto",[h,i])>-1,k={},l={},m,n;j?(l=e.position(),m=l.top,n=l.left):(m=parseFloat(h)||0,n=parseFloat(i)||0),f.isFunction(b)&&(b=b.call(a,c,g)),b.top!=null&&(k.top=b.top-g.top+m),b.left!=null&&(k.left=b.left-g.left+n),"using"in b?b.using.call(a,k):e.css(k)}},f.fn.extend({position:function(){if(!this[0])return null;var a=this[0],b=this.offsetParent(),c=this.offset(),d=cx.test(b[0].nodeName)?{top:0,left:0}:b.offset();c.top-=parseFloat(f.css(a,"marginTop"))||0,c.left-=parseFloat(f.css(a,"marginLeft"))||0,d.top+=parseFloat(f.css(b[0],"borderTopWidth"))||0,d.left+=parseFloat(f.css(b[0],"borderLeftWidth"))||0;return{top:c.top-d.top,left:c.left-d.left}},offsetParent:function(){return this.map(function(){var a=this.offsetParent||c.body;while(a&&!cx.test(a.nodeName)&&f.css(a,"position")==="static")a=a.offsetParent;return a})}}),f.each({scrollLeft:"pageXOffset",scrollTop:"pageYOffset"},function(a,c){var d=/Y/.test(c);f.fn[a]=function(e){return f.access(this,function(a,e,g){var h=cy(a);if(g===b)return h?c in h?h[c]:f.support.boxModel&&h.document.documentElement[e]||h.document.body[e]:a[e];h?h.scrollTo(d?f(h).scrollLeft():g,d?g:f(h).scrollTop()):a[e]=g},a,e,arguments.length,null)}}),f.each({Height:"height",Width:"width"},function(a,c){var d="client"+a,e="scroll"+a,g="offset"+a;f.fn["inner"+a]=function(){var a=this[0];return a?a.style?parseFloat(f.css(a,c,"padding")):this[c]():null},f.fn["outer"+a]=function(a){var b=this[0];return b?b.style?parseFloat(f.css(b,c,a?"margin":"border")):this[c]():null},f.fn[c]=function(a){return f.access(this,function(a,c,h){var i,j,k,l;if(f.isWindow(a)){i=a.document,j=i.documentElement[d];return f.support.boxModel&&j||i.body&&i.body[d]||j}if(a.nodeType===9){i=a.documentElement;if(i[d]>=i[e])return i[d];return Math.max(a.body[e],i[e],a.body[g],i[g])}if(h===b){k=f.css(a,c),l=parseFloat(k);return f.isNumeric(l)?l:k}f(a).css(c,h)},c,a,arguments.length,null)}}),a.jQuery=a.$=f,typeof define=="function"&&define.amd&&define.amd.jQuery&&define("jquery",[],function(){return f})})(window);
    --
    --//third_party/javascript/jquery_hashchange/jquery.hashchange.js
    --/**
    -- * @license
    -- * jQuery hashchange 1.0.0
    -- * 
    -- * (based on jquery.history)
    -- *
    -- * Copyright (c) 2008 Chris Leishman (chrisleishman.com)
    -- * Dual licensed under the MIT (MIT-LICENSE.txt)
    -- * and GPL (GPL-LICENSE.txt) licenses.
    -- */
    --(function($) {
    --
    --$.fn.extend({
    --    hashchange: function(callback) { this.bind('hashchange', callback) },
    --    openOnClick: function(href) {
    --		if (href === undefined || href.length == 0)
    --			href = '#';
    --		return this.click(function(ev) {
    --			if (href && href.charAt(0) == '#') {
    --				// execute load in separate call stack
    --				window.setTimeout(function() { $.locationHash(href) }, 0);
    --			} else {
    --				window.location(href);
    --			}
    --			ev.stopPropagation();
    --			return false;
    --		});
    --    }
    --});
    --
    --// IE 8 introduces the hashchange event natively - so nothing more to do
    --if ($.browser.msie && document.documentMode && document.documentMode >= 8) {
    --	$.extend({
    --		locationHash: function(hash) {
    --	        if (!hash) hash = '#';
    --	        else if (hash.charAt(0) != '#') hash = '#' + hash;
    --	        location.hash = hash;
    --	    }
    --	});
    --	return;
    --}
    --
    --var curHash;
    --// hidden iframe for IE (earlier than 8)
    --var iframe;
    --
    --$.extend({
    --	locationHash: function(hash) {
    --		if (curHash === undefined) return;
    --
    --		if (!hash) hash = '#';
    --		else if (hash.charAt(0) != '#') hash = '#' + hash;
    --		
    --		location.hash = hash;
    --		
    --		if (curHash == hash) return;
    --		curHash = hash;
    --		
    --		if ($.browser.msie) updateIEFrame(hash);
    --		$.event.trigger('hashchange');
    --	}
    --});
    --
    --$(document).ready(function() {
    --    curHash = location.hash;
    --    if ($.browser.msie) {
    --        // stop the callback firing twice during init if no hash present
    --        if (curHash == '') curHash = '#';
    --        // add hidden iframe for IE
    --        iframe = $('<iframe />').hide().get(0);
    --        $('body').prepend(iframe);
    --        updateIEFrame(location.hash);
    --        setInterval(checkHashIE, 100);
    --    } else {
    --        setInterval(checkHash, 100);
    --    }
    --});
    --$(window).unload(function() { iframe = null });
    --
    --function checkHash() {
    --    var hash = location.hash;
    --    if (hash != curHash) {
    --        curHash = hash;
    --        $.event.trigger('hashchange');
    --    }
    --}
    --
    --if ($.browser.msie) {
    --    // Attach a live handler for any anchor links
    --    $('a[href^=#]').live('click', function() {
    --        var hash = $(this).attr('href');
    --        // Don't intercept the click if there is an existing anchor on the page
    --        // that matches this hash
    --        if ($(hash).length == 0 && $('a[name='+hash.slice(1)+']').length == 0) {
    --            $.locationHash(hash);
    --            return false;
    --        }
    --    });
    --}
    --
    --function checkHashIE() {
    --    // On IE, check for location.hash of iframe
    --    var idoc = iframe.contentDocument || iframe.contentWindow.document;
    --    var hash = idoc.location.hash;
    --    if (hash == '') hash = '#';
    --
    --    if (hash != curHash) {
    --        if (location.hash != hash) location.hash = hash;
    --        curHash = hash;
    --        $.event.trigger('hashchange');
    --    }
    --}
    --
    --function updateIEFrame(hash) {
    --    if (hash == '#') hash = '';
    --    var idoc = iframe.contentWindow.document;
    --    idoc.open();
    --    idoc.close();
    --    if (idoc.location.hash != hash) idoc.location.hash = hash;
    --}
    --
    --})(jQuery);
    --
    --//third_party/javascript/jquery_jscrollpane/jquery.jscrollpane.min.js
    --/*
    -- * @license
    -- * jScrollPane - v2.0.0beta12 - 2012-09-27
    -- * http://jscrollpane.kelvinluck.com/
    -- *
    -- * Copyright (c) 2010 Kelvin Luck
    -- * Dual licensed under the MIT or GPL licenses.
    -- */
    --(function(b,a,c){b.fn.jScrollPane=function(e){function d(D,O){var ay,Q=this,Y,aj,v,al,T,Z,y,q,az,aE,au,i,I,h,j,aa,U,ap,X,t,A,aq,af,am,G,l,at,ax,x,av,aH,f,L,ai=true,P=true,aG=false,k=false,ao=D.clone(false,false).empty(),ac=b.fn.mwheelIntent?"mwheelIntent.jsp":"mousewheel.jsp";aH=D.css("paddingTop")+" "+D.css("paddingRight")+" "+D.css("paddingBottom")+" "+D.css("paddingLeft");f=(parseInt(D.css("paddingLeft"),10)||0)+(parseInt(D.css("paddingRight"),10)||0);function ar(aQ){var aL,aN,aM,aJ,aI,aP,aO=false,aK=false;ay=aQ;if(Y===c){aI=D.scrollTop();aP=D.scrollLeft();D.css({overflow:"hidden",padding:0});aj=D.innerWidth()+f;v=D.innerHeight();D.width(aj);Y=b('<div class="jspPane" />').css("padding",aH).append(D.children());al=b('<div class="jspContainer" />').css({width:aj+"px",height:v+"px"}).append(Y).appendTo(D)}else{D.css("width","");aO=ay.stickToBottom&&K();aK=ay.stickToRight&&B();aJ=D.innerWidth()+f!=aj||D.outerHeight()!=v;if(aJ){aj=D.innerWidth()+f;v=D.innerHeight();al.css({width:aj+"px",height:v+"px"})}if(!aJ&&L==T&&Y.outerHeight()==Z){D.width(aj);return}L=T;Y.css("width","");D.width(aj);al.find(">.jspVerticalBar,>.jspHorizontalBar").remove().end()}Y.css("overflow","auto");if(aQ.contentWidth){T=aQ.contentWidth}else{T=Y[0].scrollWidth}Z=Y[0].scrollHeight;Y.css("overflow","");y=T/aj;q=Z/v;az=q>1;aE=y>1;if(!(aE||az)){D.removeClass("jspScrollable");Y.css({top:0,width:al.width()-f});n();E();R();w()}else{D.addClass("jspScrollable");aL=ay.maintainPosition&&(I||aa);if(aL){aN=aC();aM=aA()}aF();z();F();if(aL){N(aK?(T-aj):aN,false);M(aO?(Z-v):aM,false)}J();ag();an();if(ay.enableKeyboardNavigation){S()}if(ay.clickOnTrack){p()}C();if(ay.hijackInternalLinks){m()}}if(ay.autoReinitialise&&!av){av=setInterval(function(){ar(ay)},ay.autoReinitialiseDelay)}else{if(!ay.autoReinitialise&&av){clearInterval(av)}}aI&&D.scrollTop(0)&&M(aI,false);aP&&D.scrollLeft(0)&&N(aP,false);D.trigger("jsp-initialised",[aE||az])}function aF(){if(az){al.append(b('<div class="jspVerticalBar" />').append(b('<div class="jspCap jspCapTop" />'),b('<div class="jspTrack" />').append(b('<div class="jspDrag" />').append(b('<div class="jspDragTop" />'),b('<div class="jspDragBottom" />'))),b('<div class="jspCap jspCapBottom" />')));U=al.find(">.jspVerticalBar");ap=U.find(">.jspTrack");au=ap.find(">.jspDrag");if(ay.showArrows){aq=b('<a class="jspArrow jspArrowUp" />').bind("mousedown.jsp",aD(0,-1)).bind("click.jsp",aB);af=b('<a class="jspArrow jspArrowDown" />').bind("mousedown.jsp",aD(0,1)).bind("click.jsp",aB);if(ay.arrowScrollOnHover){aq.bind("mouseover.jsp",aD(0,-1,aq));af.bind("mouseover.jsp",aD(0,1,af))}ak(ap,ay.verticalArrowPositions,aq,af)}t=v;al.find(">.jspVerticalBar>.jspCap:visible,>.jspVerticalBar>.jspArrow").each(function(){t-=b(this).outerHeight()});au.hover(function(){au.addClass("jspHover")},function(){au.removeClass("jspHover")}).bind("mousedown.jsp",function(aI){b("html").bind("dragstart.jsp selectstart.jsp",aB);au.addClass("jspActive");var s=aI.pageY-au.position().top;b("html").bind("mousemove.jsp",function(aJ){V(aJ.pageY-s,false)}).bind("mouseup.jsp mouseleave.jsp",aw);return false});o()}}function o(){ap.height(t+"px");I=0;X=ay.verticalGutter+ap.outerWidth();Y.width(aj-X-f);try{if(U.position().left===0){Y.css("margin-left",X+"px")}}catch(s){}}function z(){if(aE){al.append(b('<div class="jspHorizontalBar" />').append(b('<div class="jspCap jspCapLeft" />'),b('<div class="jspTrack" />').append(b('<div class="jspDrag" />').append(b('<div class="jspDragLeft" />'),b('<div class="jspDragRight" />'))),b('<div class="jspCap jspCapRight" />')));am=al.find(">.jspHorizontalBar");G=am.find(">.jspTrack");h=G.find(">.jspDrag");if(ay.showArrows){ax=b('<a class="jspArrow jspArrowLeft" />').bind("mousedown.jsp",aD(-1,0)).bind("click.jsp",aB);x=b('<a class="jspArrow jspArrowRight" />').bind("mousedown.jsp",aD(1,0)).bind("click.jsp",aB);
    --if(ay.arrowScrollOnHover){ax.bind("mouseover.jsp",aD(-1,0,ax));x.bind("mouseover.jsp",aD(1,0,x))}ak(G,ay.horizontalArrowPositions,ax,x)}h.hover(function(){h.addClass("jspHover")},function(){h.removeClass("jspHover")}).bind("mousedown.jsp",function(aI){b("html").bind("dragstart.jsp selectstart.jsp",aB);h.addClass("jspActive");var s=aI.pageX-h.position().left;b("html").bind("mousemove.jsp",function(aJ){W(aJ.pageX-s,false)}).bind("mouseup.jsp mouseleave.jsp",aw);return false});l=al.innerWidth();ah()}}function ah(){al.find(">.jspHorizontalBar>.jspCap:visible,>.jspHorizontalBar>.jspArrow").each(function(){l-=b(this).outerWidth()});G.width(l+"px");aa=0}function F(){if(aE&&az){var aI=G.outerHeight(),s=ap.outerWidth();t-=aI;b(am).find(">.jspCap:visible,>.jspArrow").each(function(){l+=b(this).outerWidth()});l-=s;v-=s;aj-=aI;G.parent().append(b('<div class="jspCorner" />').css("width",aI+"px"));o();ah()}if(aE){Y.width((al.outerWidth()-f)+"px")}Z=Y.outerHeight();q=Z/v;if(aE){at=Math.ceil(1/y*l);if(at>ay.horizontalDragMaxWidth){at=ay.horizontalDragMaxWidth}else{if(at<ay.horizontalDragMinWidth){at=ay.horizontalDragMinWidth}}h.width(at+"px");j=l-at;ae(aa)}if(az){A=Math.ceil(1/q*t);if(A>ay.verticalDragMaxHeight){A=ay.verticalDragMaxHeight}else{if(A<ay.verticalDragMinHeight){A=ay.verticalDragMinHeight}}au.height(A+"px");i=t-A;ad(I)}}function ak(aJ,aL,aI,s){var aN="before",aK="after",aM;if(aL=="os"){aL=/Mac/.test(navigator.platform)?"after":"split"}if(aL==aN){aK=aL}else{if(aL==aK){aN=aL;aM=aI;aI=s;s=aM}}aJ[aN](aI)[aK](s)}function aD(aI,s,aJ){return function(){H(aI,s,this,aJ);this.blur();return false}}function H(aL,aK,aO,aN){aO=b(aO).addClass("jspActive");var aM,aJ,aI=true,s=function(){if(aL!==0){Q.scrollByX(aL*ay.arrowButtonSpeed)}if(aK!==0){Q.scrollByY(aK*ay.arrowButtonSpeed)}aJ=setTimeout(s,aI?ay.initialDelay:ay.arrowRepeatFreq);aI=false};s();aM=aN?"mouseout.jsp":"mouseup.jsp";aN=aN||b("html");aN.bind(aM,function(){aO.removeClass("jspActive");aJ&&clearTimeout(aJ);aJ=null;aN.unbind(aM)})}function p(){w();if(az){ap.bind("mousedown.jsp",function(aN){if(aN.originalTarget===c||aN.originalTarget==aN.currentTarget){var aL=b(this),aO=aL.offset(),aM=aN.pageY-aO.top-I,aJ,aI=true,s=function(){var aR=aL.offset(),aS=aN.pageY-aR.top-A/2,aP=v*ay.scrollPagePercent,aQ=i*aP/(Z-v);if(aM<0){if(I-aQ>aS){Q.scrollByY(-aP)}else{V(aS)}}else{if(aM>0){if(I+aQ<aS){Q.scrollByY(aP)}else{V(aS)}}else{aK();return}}aJ=setTimeout(s,aI?ay.initialDelay:ay.trackClickRepeatFreq);aI=false},aK=function(){aJ&&clearTimeout(aJ);aJ=null;b(document).unbind("mouseup.jsp",aK)};s();b(document).bind("mouseup.jsp",aK);return false}})}if(aE){G.bind("mousedown.jsp",function(aN){if(aN.originalTarget===c||aN.originalTarget==aN.currentTarget){var aL=b(this),aO=aL.offset(),aM=aN.pageX-aO.left-aa,aJ,aI=true,s=function(){var aR=aL.offset(),aS=aN.pageX-aR.left-at/2,aP=aj*ay.scrollPagePercent,aQ=j*aP/(T-aj);if(aM<0){if(aa-aQ>aS){Q.scrollByX(-aP)}else{W(aS)}}else{if(aM>0){if(aa+aQ<aS){Q.scrollByX(aP)}else{W(aS)}}else{aK();return}}aJ=setTimeout(s,aI?ay.initialDelay:ay.trackClickRepeatFreq);aI=false},aK=function(){aJ&&clearTimeout(aJ);aJ=null;b(document).unbind("mouseup.jsp",aK)};s();b(document).bind("mouseup.jsp",aK);return false}})}}function w(){if(G){G.unbind("mousedown.jsp")}if(ap){ap.unbind("mousedown.jsp")}}function aw(){b("html").unbind("dragstart.jsp selectstart.jsp mousemove.jsp mouseup.jsp mouseleave.jsp");if(au){au.removeClass("jspActive")}if(h){h.removeClass("jspActive")}}function V(s,aI){if(!az){return}if(s<0){s=0}else{if(s>i){s=i}}if(aI===c){aI=ay.animateScroll}if(aI){Q.animate(au,"top",s,ad)}else{au.css("top",s);ad(s)}}function ad(aI){if(aI===c){aI=au.position().top}al.scrollTop(0);I=aI;var aL=I===0,aJ=I==i,aK=aI/i,s=-aK*(Z-v);if(ai!=aL||aG!=aJ){ai=aL;aG=aJ;D.trigger("jsp-arrow-change",[ai,aG,P,k])}u(aL,aJ);Y.css("top",s);D.trigger("jsp-scroll-y",[-s,aL,aJ]).trigger("scroll")}function W(aI,s){if(!aE){return}if(aI<0){aI=0}else{if(aI>j){aI=j}}if(s===c){s=ay.animateScroll}if(s){Q.animate(h,"left",aI,ae)
    --}else{h.css("left",aI);ae(aI)}}function ae(aI){if(aI===c){aI=h.position().left}al.scrollTop(0);aa=aI;var aL=aa===0,aK=aa==j,aJ=aI/j,s=-aJ*(T-aj);if(P!=aL||k!=aK){P=aL;k=aK;D.trigger("jsp-arrow-change",[ai,aG,P,k])}r(aL,aK);Y.css("left",s);D.trigger("jsp-scroll-x",[-s,aL,aK]).trigger("scroll")}function u(aI,s){if(ay.showArrows){aq[aI?"addClass":"removeClass"]("jspDisabled");af[s?"addClass":"removeClass"]("jspDisabled")}}function r(aI,s){if(ay.showArrows){ax[aI?"addClass":"removeClass"]("jspDisabled");x[s?"addClass":"removeClass"]("jspDisabled")}}function M(s,aI){var aJ=s/(Z-v);V(aJ*i,aI)}function N(aI,s){var aJ=aI/(T-aj);W(aJ*j,s)}function ab(aV,aQ,aJ){var aN,aK,aL,s=0,aU=0,aI,aP,aO,aS,aR,aT;try{aN=b(aV)}catch(aM){return}aK=aN.outerHeight();aL=aN.outerWidth();al.scrollTop(0);al.scrollLeft(0);while(!aN.is(".jspPane")){s+=aN.position().top;aU+=aN.position().left;aN=aN.offsetParent();if(/^body|html$/i.test(aN[0].nodeName)){return}}aI=aA();aO=aI+v;if(s<aI||aQ){aR=s-ay.verticalGutter}else{if(s+aK>aO){aR=s-v+aK+ay.verticalGutter}}if(aR){M(aR,aJ)}aP=aC();aS=aP+aj;if(aU<aP||aQ){aT=aU-ay.horizontalGutter}else{if(aU+aL>aS){aT=aU-aj+aL+ay.horizontalGutter}}if(aT){N(aT,aJ)}}function aC(){return -Y.position().left}function aA(){return -Y.position().top}function K(){var s=Z-v;return(s>20)&&(s-aA()<10)}function B(){var s=T-aj;return(s>20)&&(s-aC()<10)}function ag(){al.unbind(ac).bind(ac,function(aL,aM,aK,aI){var aJ=aa,s=I;Q.scrollBy(aK*ay.mouseWheelSpeed,-aI*ay.mouseWheelSpeed,false);return aJ==aa&&s==I})}function n(){al.unbind(ac)}function aB(){return false}function J(){Y.find(":input,a").unbind("focus.jsp").bind("focus.jsp",function(s){ab(s.target,false)})}function E(){Y.find(":input,a").unbind("focus.jsp")}function S(){var s,aI,aK=[];aE&&aK.push(am[0]);az&&aK.push(U[0]);Y.focus(function(){D.focus()});D.attr("tabindex",0).unbind("keydown.jsp keypress.jsp").bind("keydown.jsp",function(aN){if(aN.target!==this&&!(aK.length&&b(aN.target).closest(aK).length)){return}var aM=aa,aL=I;switch(aN.keyCode){case 40:case 38:case 34:case 32:case 33:case 39:case 37:s=aN.keyCode;aJ();break;case 35:M(Z-v);s=null;break;case 36:M(0);s=null;break}aI=aN.keyCode==s&&aM!=aa||aL!=I;return !aI}).bind("keypress.jsp",function(aL){if(aL.keyCode==s){aJ()}return !aI});if(ay.hideFocus){D.css("outline","none");if("hideFocus" in al[0]){D.attr("hideFocus",true)}}else{D.css("outline","");if("hideFocus" in al[0]){D.attr("hideFocus",false)}}function aJ(){var aM=aa,aL=I;switch(s){case 40:Q.scrollByY(ay.keyboardSpeed,false);break;case 38:Q.scrollByY(-ay.keyboardSpeed,false);break;case 34:case 32:Q.scrollByY(v*ay.scrollPagePercent,false);break;case 33:Q.scrollByY(-v*ay.scrollPagePercent,false);break;case 39:Q.scrollByX(ay.keyboardSpeed,false);break;case 37:Q.scrollByX(-ay.keyboardSpeed,false);break}aI=aM!=aa||aL!=I;return aI}}function R(){D.attr("tabindex","-1").removeAttr("tabindex").unbind("keydown.jsp keypress.jsp")}function C(){if(location.hash&&location.hash.length>1){var aK,aI,aJ=escape(location.hash.substr(1));try{aK=b("#"+aJ+', a[name="'+aJ+'"]')}catch(s){return}if(aK.length&&Y.find(aJ)){if(al.scrollTop()===0){aI=setInterval(function(){if(al.scrollTop()>0){ab(aK,true);b(document).scrollTop(al.position().top);clearInterval(aI)}},50)}else{ab(aK,true);b(document).scrollTop(al.position().top)}}}}function m(){if(b(document.body).data("jspHijack")){return}b(document.body).data("jspHijack",true);b(document.body).delegate("a[href*=#]","click",function(s){var aI=this.href.substr(0,this.href.indexOf("#")),aK=location.href,aO,aP,aJ,aM,aL,aN;if(location.href.indexOf("#")!==-1){aK=location.href.substr(0,location.href.indexOf("#"))}if(aI!==aK){return}aO=escape(this.href.substr(this.href.indexOf("#")+1));aP;try{aP=b("#"+aO+', a[name="'+aO+'"]')}catch(aQ){return}if(!aP.length){return}aJ=aP.closest(".jspScrollable");aM=aJ.data("jsp");aM.scrollToElement(aP,true);if(aJ[0].scrollIntoView){aL=b(a).scrollTop();aN=aP.offset().top;if(aN<aL||aN>aL+b(a).height()){aJ[0].scrollIntoView()}}s.preventDefault()
    --})}function an(){var aJ,aI,aL,aK,aM,s=false;al.unbind("touchstart.jsp touchmove.jsp touchend.jsp click.jsp-touchclick").bind("touchstart.jsp",function(aN){var aO=aN.originalEvent.touches[0];aJ=aC();aI=aA();aL=aO.pageX;aK=aO.pageY;aM=false;s=true}).bind("touchmove.jsp",function(aQ){if(!s){return}var aP=aQ.originalEvent.touches[0],aO=aa,aN=I;Q.scrollTo(aJ+aL-aP.pageX,aI+aK-aP.pageY);aM=aM||Math.abs(aL-aP.pageX)>5||Math.abs(aK-aP.pageY)>5;return aO==aa&&aN==I}).bind("touchend.jsp",function(aN){s=false}).bind("click.jsp-touchclick",function(aN){if(aM){aM=false;return false}})}function g(){var s=aA(),aI=aC();D.removeClass("jspScrollable").unbind(".jsp");D.replaceWith(ao.append(Y.children()));ao.scrollTop(s);ao.scrollLeft(aI);if(av){clearInterval(av)}}b.extend(Q,{reinitialise:function(aI){aI=b.extend({},ay,aI);ar(aI)},scrollToElement:function(aJ,aI,s){ab(aJ,aI,s)},scrollTo:function(aJ,s,aI){N(aJ,aI);M(s,aI)},scrollToX:function(aI,s){N(aI,s)},scrollToY:function(s,aI){M(s,aI)},scrollToPercentX:function(aI,s){N(aI*(T-aj),s)},scrollToPercentY:function(aI,s){M(aI*(Z-v),s)},scrollBy:function(aI,s,aJ){Q.scrollByX(aI,aJ);Q.scrollByY(s,aJ)},scrollByX:function(s,aJ){var aI=aC()+Math[s<0?"floor":"ceil"](s),aK=aI/(T-aj);W(aK*j,aJ)},scrollByY:function(s,aJ){var aI=aA()+Math[s<0?"floor":"ceil"](s),aK=aI/(Z-v);V(aK*i,aJ)},positionDragX:function(s,aI){W(s,aI)},positionDragY:function(aI,s){V(aI,s)},animate:function(aI,aL,s,aK){var aJ={};aJ[aL]=s;aI.animate(aJ,{duration:ay.animateDuration,easing:ay.animateEase,queue:false,step:aK})},getContentPositionX:function(){return aC()},getContentPositionY:function(){return aA()},getContentWidth:function(){return T},getContentHeight:function(){return Z},getPercentScrolledX:function(){return aC()/(T-aj)},getPercentScrolledY:function(){return aA()/(Z-v)},getIsScrollableH:function(){return aE},getIsScrollableV:function(){return az},getContentPane:function(){return Y},scrollToBottom:function(s){V(i,s)},hijackInternalLinks:b.noop,destroy:function(){g()}});ar(O)}e=b.extend({},b.fn.jScrollPane.defaults,e);b.each(["mouseWheelSpeed","arrowButtonSpeed","trackClickSpeed","keyboardSpeed"],function(){e[this]=e[this]||e.speed});return this.each(function(){var f=b(this),g=f.data("jsp");if(g){g.reinitialise(e)}else{b("script",f).filter('[type="text/javascript"],:not([type])').remove();g=new d(f,e);f.data("jsp",g)}})};b.fn.jScrollPane.defaults={showArrows:false,maintainPosition:true,stickToBottom:false,stickToRight:false,clickOnTrack:true,autoReinitialise:false,autoReinitialiseDelay:500,verticalDragMinHeight:0,verticalDragMaxHeight:99999,horizontalDragMinWidth:0,horizontalDragMaxWidth:99999,contentWidth:c,animateScroll:false,animateDuration:300,animateEase:"linear",hijackInternalLinks:false,verticalGutter:4,horizontalGutter:4,mouseWheelSpeed:0,arrowButtonSpeed:0,arrowRepeatFreq:50,arrowScrollOnHover:false,trackClickSpeed:0,trackClickRepeatFreq:70,verticalArrowPositions:"split",horizontalArrowPositions:"split",enableKeyboardNavigation:true,hideFocus:false,keyboardSpeed:0,initialDelay:300,speed:30,scrollPagePercent:0.8}})(jQuery,this);
    --
    --//third_party/javascript/jquery_mousewheel/jquery.mousewheel.min.js
    --/**
    -- * @license
    -- * Copyright (c) 2011 Brandon Aaron (http://brandonaaron.net)
    -- * Licensed under the MIT License (LICENSE.txt).
    -- *
    -- * Thanks to: http://adomas.org/javascript-mouse-wheel/ for some pointers.
    -- * Thanks to: Mathias Bank(http://www.mathias-bank.de) for a scope bug fix.
    -- * Thanks to: Seamus Leahy for adding deltaX and deltaY
    -- *
    -- * Version: 3.0.6
    -- * 
    -- * Requires: 1.2.2+
    -- */
    --(function(a){function d(b){var c=b||window.event,d=[].slice.call(arguments,1),e=0,f=!0,g=0,h=0;return b=a.event.fix(c),b.type="mousewheel",c.wheelDelta&&(e=c.wheelDelta/120),c.detail&&(e=-c.detail/3),h=e,c.axis!==undefined&&c.axis===c.HORIZONTAL_AXIS&&(h=0,g=-1*e),c.wheelDeltaY!==undefined&&(h=c.wheelDeltaY/120),c.wheelDeltaX!==undefined&&(g=-1*c.wheelDeltaX/120),d.unshift(b,e,g,h),(a.event.dispatch||a.event.handle).apply(this,d)}var b=["DOMMouseScroll","mousewheel"];if(a.event.fixHooks)for(var c=b.length;c;)a.event.fixHooks[b[--c]]=a.event.mouseHooks;a.event.special.mousewheel={setup:function(){if(this.addEventListener)for(var a=b.length;a;)this.addEventListener(b[--a],d,!1);else this.onmousewheel=d},teardown:function(){if(this.removeEventListener)for(var a=b.length;a;)this.removeEventListener(b[--a],d,!1);else this.onmousewheel=null}},a.fn.extend({mousewheel:function(a){return a?this.bind("mousewheel",a):this.trigger("mousewheel")},unmousewheel:function(a){return this.unbind("mousewheel",a)}})})(jQuery);
    --
    --//third_party/javascript/jquery_ui/v1_8_23/js/jquery-ui-1.8.23.custom.min.js
    --/**
    -- * jQuery UI
    -- * @version 1.8.23
    -- * @date 2012-08-15
    -- * @link https://github.com/jquery/jquery-ui
    -- * Includes: jquery.ui.core.js
    -- * Copyright 2012, AUTHORS.txt (http://jqueryui.com/about)
    -- * @license MIT (Dual licensed with GPL Version 2 license).
    -- * http://jquery.org/license
    -- */
    --(function(a,b){function c(b,c){var e=b.nodeName.toLowerCase();if("area"===e){var f=b.parentNode,g=f.name,h;return!b.href||!g||f.nodeName.toLowerCase()!=="map"?!1:(h=a("img[usemap=#"+g+"]")[0],!!h&&d(h))}return(/input|select|textarea|button|object/.test(e)?!b.disabled:"a"==e?b.href||c:c)&&d(b)}function d(b){return!a(b).parents().andSelf().filter(function(){return a.curCSS(this,"visibility")==="hidden"||a.expr.filters.hidden(this)}).length}a.ui=a.ui||{};if(a.ui.version)return;a.extend(a.ui,{version:"1.8.23",keyCode:{ALT:18,BACKSPACE:8,CAPS_LOCK:20,COMMA:188,COMMAND:91,COMMAND_LEFT:91,COMMAND_RIGHT:93,CONTROL:17,DELETE:46,DOWN:40,END:35,ENTER:13,ESCAPE:27,HOME:36,INSERT:45,LEFT:37,MENU:93,NUMPAD_ADD:107,NUMPAD_DECIMAL:110,NUMPAD_DIVIDE:111,NUMPAD_ENTER:108,NUMPAD_MULTIPLY:106,NUMPAD_SUBTRACT:109,PAGE_DOWN:34,PAGE_UP:33,PERIOD:190,RIGHT:39,SHIFT:16,SPACE:32,TAB:9,UP:38,WINDOWS:91}}),a.fn.extend({propAttr:a.fn.prop||a.fn.attr,_focus:a.fn.focus,focus:function(b,c){return typeof b=="number"?this.each(function(){var d=this;setTimeout(function(){a(d).focus(),c&&c.call(d)},b)}):this._focus.apply(this,arguments)},scrollParent:function(){var b;return a.browser.msie&&/(static|relative)/.test(this.css("position"))||/absolute/.test(this.css("position"))?b=this.parents().filter(function(){return/(relative|absolute|fixed)/.test(a.curCSS(this,"position",1))&&/(auto|scroll)/.test(a.curCSS(this,"overflow",1)+a.curCSS(this,"overflow-y",1)+a.curCSS(this,"overflow-x",1))}).eq(0):b=this.parents().filter(function(){return/(auto|scroll)/.test(a.curCSS(this,"overflow",1)+a.curCSS(this,"overflow-y",1)+a.curCSS(this,"overflow-x",1))}).eq(0),/fixed/.test(this.css("position"))||!b.length?a(document):b},zIndex:function(c){if(c!==b)return this.css("zIndex",c);if(this.length){var d=a(this[0]),e,f;while(d.length&&d[0]!==document){e=d.css("position");if(e==="absolute"||e==="relative"||e==="fixed"){f=parseInt(d.css("zIndex"),10);if(!isNaN(f)&&f!==0)return f}d=d.parent()}}return 0},disableSelection:function(){return this.bind((a.support.selectstart?"selectstart":"mousedown")+".ui-disableSelection",function(a){a.preventDefault()})},enableSelection:function(){return this.unbind(".ui-disableSelection")}}),a("<a>").outerWidth(1).jquery||a.each(["Width","Height"],function(c,d){function h(b,c,d,f){return a.each(e,function(){c-=parseFloat(a.curCSS(b,"padding"+this,!0))||0,d&&(c-=parseFloat(a.curCSS(b,"border"+this+"Width",!0))||0),f&&(c-=parseFloat(a.curCSS(b,"margin"+this,!0))||0)}),c}var e=d==="Width"?["Left","Right"]:["Top","Bottom"],f=d.toLowerCase(),g={innerWidth:a.fn.innerWidth,innerHeight:a.fn.innerHeight,outerWidth:a.fn.outerWidth,outerHeight:a.fn.outerHeight};a.fn["inner"+d]=function(c){return c===b?g["inner"+d].call(this):this.each(function(){a(this).css(f,h(this,c)+"px")})},a.fn["outer"+d]=function(b,c){return typeof b!="number"?g["outer"+d].call(this,b):this.each(function(){a(this).css(f,h(this,b,!0,c)+"px")})}}),a.extend(a.expr[":"],{data:a.expr.createPseudo?a.expr.createPseudo(function(b){return function(c){return!!a.data(c,b)}}):function(b,c,d){return!!a.data(b,d[3])},focusable:function(b){return c(b,!isNaN(a.attr(b,"tabindex")))},tabbable:function(b){var d=a.attr(b,"tabindex"),e=isNaN(d);return(e||d>=0)&&c(b,!e)}}),a(function(){var b=document.body,c=b.appendChild(c=document.createElement("div"));c.offsetHeight,a.extend(c.style,{minHeight:"100px",height:"auto",padding:0,borderWidth:0}),a.support.minHeight=c.offsetHeight===100,a.support.selectstart="onselectstart"in c,b.removeChild(c).style.display="none"}),a.curCSS||(a.curCSS=a.css),a.extend(a.ui,{plugin:{add:function(b,c,d){var e=a.ui[b].prototype;for(var f in d)e.plugins[f]=e.plugins[f]||[],e.plugins[f].push([c,d[f]])},call:function(a,b,c){var d=a.plugins[b];if(!d||!a.element[0].parentNode)return;for(var e=0;e<d.length;e++)a.options[d[e][0]]&&d[e][1].apply(a.element,c)}},contains:function(a,b){return document.compareDocumentPosition?a.compareDocumentPosition(b)&16:a!==b&&a.contains(b)},hasScroll:function(b,c){if(a(b).css("overflow")==="hidden")return!1;var d=c&&c==="left"?"scrollLeft":"scrollTop",e=!1;return b[d]>0?!0:(b[d]=1,e=b[d]>0,b[d]=0,e)},isOverAxis:function(a,b,c){return a>b&&a<b+c},isOver:function(b,c,d,e,f,g){return a.ui.isOverAxis(b,d,f)&&a.ui.isOverAxis(c,e,g)}})})(jQuery);;/*! jQuery UI - v1.8.23 - 2012-08-15
    --* https://github.com/jquery/jquery-ui
    --* Includes: jquery.ui.widget.js
    --* Copyright (c) 2012 AUTHORS.txt; Licensed MIT, GPL */
    --(function(a,b){if(a.cleanData){var c=a.cleanData;a.cleanData=function(b){for(var d=0,e;(e=b[d])!=null;d++)try{a(e).triggerHandler("remove")}catch(f){}c(b)}}else{var d=a.fn.remove;a.fn.remove=function(b,c){return this.each(function(){return c||(!b||a.filter(b,[this]).length)&&a("*",this).add([this]).each(function(){try{a(this).triggerHandler("remove")}catch(b){}}),d.call(a(this),b,c)})}}a.widget=function(b,c,d){var e=b.split(".")[0],f;b=b.split(".")[1],f=e+"-"+b,d||(d=c,c=a.Widget),a.expr[":"][f]=function(c){return!!a.data(c,b)},a[e]=a[e]||{},a[e][b]=function(a,b){arguments.length&&this._createWidget(a,b)};var g=new c;g.options=a.extend(!0,{},g.options),a[e][b].prototype=a.extend(!0,g,{namespace:e,widgetName:b,widgetEventPrefix:a[e][b].prototype.widgetEventPrefix||b,widgetBaseClass:f},d),a.widget.bridge(b,a[e][b])},a.widget.bridge=function(c,d){a.fn[c]=function(e){var f=typeof e=="string",g=Array.prototype.slice.call(arguments,1),h=this;return e=!f&&g.length?a.extend.apply(null,[!0,e].concat(g)):e,f&&e.charAt(0)==="_"?h:(f?this.each(function(){var d=a.data(this,c),f=d&&a.isFunction(d[e])?d[e].apply(d,g):d;if(f!==d&&f!==b)return h=f,!1}):this.each(function(){var b=a.data(this,c);b?b.option(e||{})._init():a.data(this,c,new d(e,this))}),h)}},a.Widget=function(a,b){arguments.length&&this._createWidget(a,b)},a.Widget.prototype={widgetName:"widget",widgetEventPrefix:"",options:{disabled:!1},_createWidget:function(b,c){a.data(c,this.widgetName,this),this.element=a(c),this.options=a.extend(!0,{},this.options,this._getCreateOptions(),b);var d=this;this.element.bind("remove."+this.widgetName,function(){d.destroy()}),this._create(),this._trigger("create"),this._init()},_getCreateOptions:function(){return a.metadata&&a.metadata.get(this.element[0])[this.widgetName]},_create:function(){},_init:function(){},destroy:function(){this.element.unbind("."+this.widgetName).removeData(this.widgetName),this.widget().unbind("."+this.widgetName).removeAttr("aria-disabled").removeClass(this.widgetBaseClass+"-disabled "+"ui-state-disabled")},widget:function(){return this.element},option:function(c,d){var e=c;if(arguments.length===0)return a.extend({},this.options);if(typeof c=="string"){if(d===b)return this.options[c];e={},e[c]=d}return this._setOptions(e),this},_setOptions:function(b){var c=this;return a.each(b,function(a,b){c._setOption(a,b)}),this},_setOption:function(a,b){return this.options[a]=b,a==="disabled"&&this.widget()[b?"addClass":"removeClass"](this.widgetBaseClass+"-disabled"+" "+"ui-state-disabled").attr("aria-disabled",b),this},enable:function(){return this._setOption("disabled",!1)},disable:function(){return this._setOption("disabled",!0)},_trigger:function(b,c,d){var e,f,g=this.options[b];d=d||{},c=a.Event(c),c.type=(b===this.widgetEventPrefix?b:this.widgetEventPrefix+b).toLowerCase(),c.target=this.element[0],f=c.originalEvent;if(f)for(e in f)e in c||(c[e]=f[e]);return this.element.trigger(c,d),!(a.isFunction(g)&&g.call(this.element[0],c,d)===!1||c.isDefaultPrevented())}}})(jQuery);;/*! jQuery UI - v1.8.23 - 2012-08-15
    --* https://github.com/jquery/jquery-ui
    --* Includes: jquery.ui.mouse.js
    --* Copyright (c) 2012 AUTHORS.txt; Licensed MIT, GPL */
    --(function(a,b){var c=!1;a(document).mouseup(function(a){c=!1}),a.widget("ui.mouse",{options:{cancel:":input,option",distance:1,delay:0},_mouseInit:function(){var b=this;this.element.bind("mousedown."+this.widgetName,function(a){return b._mouseDown(a)}).bind("click."+this.widgetName,function(c){if(!0===a.data(c.target,b.widgetName+".preventClickEvent"))return a.removeData(c.target,b.widgetName+".preventClickEvent"),c.stopImmediatePropagation(),!1}),this.started=!1},_mouseDestroy:function(){this.element.unbind("."+this.widgetName),this._mouseMoveDelegate&&a(document).unbind("mousemove."+this.widgetName,this._mouseMoveDelegate).unbind("mouseup."+this.widgetName,this._mouseUpDelegate)},_mouseDown:function(b){if(c)return;this._mouseStarted&&this._mouseUp(b),this._mouseDownEvent=b;var d=this,e=b.which==1,f=typeof this.options.cancel=="string"&&b.target.nodeName?a(b.target).closest(this.options.cancel).length:!1;if(!e||f||!this._mouseCapture(b))return!0;this.mouseDelayMet=!this.options.delay,this.mouseDelayMet||(this._mouseDelayTimer=setTimeout(function(){d.mouseDelayMet=!0},this.options.delay));if(this._mouseDistanceMet(b)&&this._mouseDelayMet(b)){this._mouseStarted=this._mouseStart(b)!==!1;if(!this._mouseStarted)return b.preventDefault(),!0}return!0===a.data(b.target,this.widgetName+".preventClickEvent")&&a.removeData(b.target,this.widgetName+".preventClickEvent"),this._mouseMoveDelegate=function(a){return d._mouseMove(a)},this._mouseUpDelegate=function(a){return d._mouseUp(a)},a(document).bind("mousemove."+this.widgetName,this._mouseMoveDelegate).bind("mouseup."+this.widgetName,this._mouseUpDelegate),b.preventDefault(),c=!0,!0},_mouseMove:function(b){return!a.browser.msie||document.documentMode>=9||!!b.button?this._mouseStarted?(this._mouseDrag(b),b.preventDefault()):(this._mouseDistanceMet(b)&&this._mouseDelayMet(b)&&(this._mouseStarted=this._mouseStart(this._mouseDownEvent,b)!==!1,this._mouseStarted?this._mouseDrag(b):this._mouseUp(b)),!this._mouseStarted):this._mouseUp(b)},_mouseUp:function(b){return a(document).unbind("mousemove."+this.widgetName,this._mouseMoveDelegate).unbind("mouseup."+this.widgetName,this._mouseUpDelegate),this._mouseStarted&&(this._mouseStarted=!1,b.target==this._mouseDownEvent.target&&a.data(b.target,this.widgetName+".preventClickEvent",!0),this._mouseStop(b)),!1},_mouseDistanceMet:function(a){return Math.max(Math.abs(this._mouseDownEvent.pageX-a.pageX),Math.abs(this._mouseDownEvent.pageY-a.pageY))>=this.options.distance},_mouseDelayMet:function(a){return this.mouseDelayMet},_mouseStart:function(a){},_mouseDrag:function(a){},_mouseStop:function(a){},_mouseCapture:function(a){return!0}})})(jQuery);;/*! jQuery UI - v1.8.23 - 2012-08-15
    --* https://github.com/jquery/jquery-ui
    --* Includes: jquery.ui.position.js
    --* Copyright (c) 2012 AUTHORS.txt; Licensed MIT, GPL */
    --(function(a,b){a.ui=a.ui||{};var c=/left|center|right/,d=/top|center|bottom/,e="center",f={},g=a.fn.position,h=a.fn.offset;a.fn.position=function(b){if(!b||!b.of)return g.apply(this,arguments);b=a.extend({},b);var h=a(b.of),i=h[0],j=(b.collision||"flip").split(" "),k=b.offset?b.offset.split(" "):[0,0],l,m,n;return i.nodeType===9?(l=h.width(),m=h.height(),n={top:0,left:0}):i.setTimeout?(l=h.width(),m=h.height(),n={top:h.scrollTop(),left:h.scrollLeft()}):i.preventDefault?(b.at="left top",l=m=0,n={top:b.of.pageY,left:b.of.pageX}):(l=h.outerWidth(),m=h.outerHeight(),n=h.offset()),a.each(["my","at"],function(){var a=(b[this]||"").split(" ");a.length===1&&(a=c.test(a[0])?a.concat([e]):d.test(a[0])?[e].concat(a):[e,e]),a[0]=c.test(a[0])?a[0]:e,a[1]=d.test(a[1])?a[1]:e,b[this]=a}),j.length===1&&(j[1]=j[0]),k[0]=parseInt(k[0],10)||0,k.length===1&&(k[1]=k[0]),k[1]=parseInt(k[1],10)||0,b.at[0]==="right"?n.left+=l:b.at[0]===e&&(n.left+=l/2),b.at[1]==="bottom"?n.top+=m:b.at[1]===e&&(n.top+=m/2),n.left+=k[0],n.top+=k[1],this.each(function(){var c=a(this),d=c.outerWidth(),g=c.outerHeight(),h=parseInt(a.curCSS(this,"marginLeft",!0))||0,i=parseInt(a.curCSS(this,"marginTop",!0))||0,o=d+h+(parseInt(a.curCSS(this,"marginRight",!0))||0),p=g+i+(parseInt(a.curCSS(this,"marginBottom",!0))||0),q=a.extend({},n),r;b.my[0]==="right"?q.left-=d:b.my[0]===e&&(q.left-=d/2),b.my[1]==="bottom"?q.top-=g:b.my[1]===e&&(q.top-=g/2),f.fractions||(q.left=Math.round(q.left),q.top=Math.round(q.top)),r={left:q.left-h,top:q.top-i},a.each(["left","top"],function(c,e){a.ui.position[j[c]]&&a.ui.position[j[c]][e](q,{targetWidth:l,targetHeight:m,elemWidth:d,elemHeight:g,collisionPosition:r,collisionWidth:o,collisionHeight:p,offset:k,my:b.my,at:b.at})}),a.fn.bgiframe&&c.bgiframe(),c.offset(a.extend(q,{using:b.using}))})},a.ui.position={fit:{left:function(b,c){var d=a(window),e=c.collisionPosition.left+c.collisionWidth-d.width()-d.scrollLeft();b.left=e>0?b.left-e:Math.max(b.left-c.collisionPosition.left,b.left)},top:function(b,c){var d=a(window),e=c.collisionPosition.top+c.collisionHeight-d.height()-d.scrollTop();b.top=e>0?b.top-e:Math.max(b.top-c.collisionPosition.top,b.top)}},flip:{left:function(b,c){if(c.at[0]===e)return;var d=a(window),f=c.collisionPosition.left+c.collisionWidth-d.width()-d.scrollLeft(),g=c.my[0]==="left"?-c.elemWidth:c.my[0]==="right"?c.elemWidth:0,h=c.at[0]==="left"?c.targetWidth:-c.targetWidth,i=-2*c.offset[0];b.left+=c.collisionPosition.left<0?g+h+i:f>0?g+h+i:0},top:function(b,c){if(c.at[1]===e)return;var d=a(window),f=c.collisionPosition.top+c.collisionHeight-d.height()-d.scrollTop(),g=c.my[1]==="top"?-c.elemHeight:c.my[1]==="bottom"?c.elemHeight:0,h=c.at[1]==="top"?c.targetHeight:-c.targetHeight,i=-2*c.offset[1];b.top+=c.collisionPosition.top<0?g+h+i:f>0?g+h+i:0}}},a.offset.setOffset||(a.offset.setOffset=function(b,c){/static/.test(a.curCSS(b,"position"))&&(b.style.position="relative");var d=a(b),e=d.offset(),f=parseInt(a.curCSS(b,"top",!0),10)||0,g=parseInt(a.curCSS(b,"left",!0),10)||0,h={top:c.top-e.top+f,left:c.left-e.left+g};"using"in c?c.using.call(b,h):d.css(h)},a.fn.offset=function(b){var c=this[0];return!c||!c.ownerDocument?null:b?a.isFunction(b)?this.each(function(c){a(this).offset(b.call(this,c,a(this).offset()))}):this.each(function(){a.offset.setOffset(this,b)}):h.call(this)}),a.curCSS||(a.curCSS=a.css),function(){var b=document.getElementsByTagName("body")[0],c=document.createElement("div"),d,e,g,h,i;d=document.createElement(b?"div":"body"),g={visibility:"hidden",width:0,height:0,border:0,margin:0,background:"none"},b&&a.extend(g,{position:"absolute",left:"-1000px",top:"-1000px"});for(var j in g)d.style[j]=g[j];d.appendChild(c),e=b||document.documentElement,e.insertBefore(d,e.firstChild),c.style.cssText="position: absolute; left: 10.7432222px; top: 10.432325px; height: 30px; width: 201px;",h=a(c).offset(function(a,b){return b}).offset(),d.innerHTML="",e.removeChild(d),i=h.top+h.left+(b?2e3:0),f.fractions=i>21&&i<22}()})(jQuery);;/*! jQuery UI - v1.8.23 - 2012-08-15
    --* https://github.com/jquery/jquery-ui
    --* Includes: jquery.ui.draggable.js
    --* Copyright (c) 2012 AUTHORS.txt; Licensed MIT, GPL */
    --(function(a,b){a.widget("ui.draggable",a.ui.mouse,{widgetEventPrefix:"drag",options:{addClasses:!0,appendTo:"parent",axis:!1,connectToSortable:!1,containment:!1,cursor:"auto",cursorAt:!1,grid:!1,handle:!1,helper:"original",iframeFix:!1,opacity:!1,refreshPositions:!1,revert:!1,revertDuration:500,scope:"default",scroll:!0,scrollSensitivity:20,scrollSpeed:20,snap:!1,snapMode:"both",snapTolerance:20,stack:!1,zIndex:!1},_create:function(){this.options.helper=="original"&&!/^(?:r|a|f)/.test(this.element.css("position"))&&(this.element[0].style.position="relative"),this.options.addClasses&&this.element.addClass("ui-draggable"),this.options.disabled&&this.element.addClass("ui-draggable-disabled"),this._mouseInit()},destroy:function(){if(!this.element.data("draggable"))return;return this.element.removeData("draggable").unbind(".draggable").removeClass("ui-draggable ui-draggable-dragging ui-draggable-disabled"),this._mouseDestroy(),this},_mouseCapture:function(b){var c=this.options;return this.helper||c.disabled||a(b.target).is(".ui-resizable-handle")?!1:(this.handle=this._getHandle(b),this.handle?(c.iframeFix&&a(c.iframeFix===!0?"iframe":c.iframeFix).each(function(){a('<div class="ui-draggable-iframeFix" style="background: #fff;"></div>').css({width:this.offsetWidth+"px",height:this.offsetHeight+"px",position:"absolute",opacity:"0.001",zIndex:1e3}).css(a(this).offset()).appendTo("body")}),!0):!1)},_mouseStart:function(b){var c=this.options;return this.helper=this._createHelper(b),this.helper.addClass("ui-draggable-dragging"),this._cacheHelperProportions(),a.ui.ddmanager&&(a.ui.ddmanager.current=this),this._cacheMargins(),this.cssPosition=this.helper.css("position"),this.scrollParent=this.helper.scrollParent(),this.offset=this.positionAbs=this.element.offset(),this.offset={top:this.offset.top-this.margins.top,left:this.offset.left-this.margins.left},a.extend(this.offset,{click:{left:b.pageX-this.offset.left,top:b.pageY-this.offset.top},parent:this._getParentOffset(),relative:this._getRelativeOffset()}),this.originalPosition=this.position=this._generatePosition(b),this.originalPageX=b.pageX,this.originalPageY=b.pageY,c.cursorAt&&this._adjustOffsetFromHelper(c.cursorAt),c.containment&&this._setContainment(),this._trigger("start",b)===!1?(this._clear(),!1):(this._cacheHelperProportions(),a.ui.ddmanager&&!c.dropBehaviour&&a.ui.ddmanager.prepareOffsets(this,b),this._mouseDrag(b,!0),a.ui.ddmanager&&a.ui.ddmanager.dragStart(this,b),!0)},_mouseDrag:function(b,c){this.position=this._generatePosition(b),this.positionAbs=this._convertPositionTo("absolute");if(!c){var d=this._uiHash();if(this._trigger("drag",b,d)===!1)return this._mouseUp({}),!1;this.position=d.position}if(!this.options.axis||this.options.axis!="y")this.helper[0].style.left=this.position.left+"px";if(!this.options.axis||this.options.axis!="x")this.helper[0].style.top=this.position.top+"px";return a.ui.ddmanager&&a.ui.ddmanager.drag(this,b),!1},_mouseStop:function(b){var c=!1;a.ui.ddmanager&&!this.options.dropBehaviour&&(c=a.ui.ddmanager.drop(this,b)),this.dropped&&(c=this.dropped,this.dropped=!1);var d=this.element[0],e=!1;while(d&&(d=d.parentNode))d==document&&(e=!0);if(!e&&this.options.helper==="original")return!1;if(this.options.revert=="invalid"&&!c||this.options.revert=="valid"&&c||this.options.revert===!0||a.isFunction(this.options.revert)&&this.options.revert.call(this.element,c)){var f=this;a(this.helper).animate(this.originalPosition,parseInt(this.options.revertDuration,10),function(){f._trigger("stop",b)!==!1&&f._clear()})}else this._trigger("stop",b)!==!1&&this._clear();return!1},_mouseUp:function(b){return this.options.iframeFix===!0&&a("div.ui-draggable-iframeFix").each(function(){this.parentNode.removeChild(this)}),a.ui.ddmanager&&a.ui.ddmanager.dragStop(this,b),a.ui.mouse.prototype._mouseUp.call(this,b)},cancel:function(){return this.helper.is(".ui-draggable-dragging")?this._mouseUp({}):this._clear(),this},_getHandle:function(b){var c=!this.options.handle||!a(this.options.handle,this.element).length?!0:!1;return a(this.options.handle,this.element).find("*").andSelf().each(function(){this==b.target&&(c=!0)}),c},_createHelper:function(b){var c=this.options,d=a.isFunction(c.helper)?a(c.helper.apply(this.element[0],[b])):c.helper=="clone"?this.element.clone().removeAttr("id"):this.element;return d.parents("body").length||d.appendTo(c.appendTo=="parent"?this.element[0].parentNode:c.appendTo),d[0]!=this.element[0]&&!/(fixed|absolute)/.test(d.css("position"))&&d.css("position","absolute"),d},_adjustOffsetFromHelper:function(b){typeof b=="string"&&(b=b.split(" ")),a.isArray(b)&&(b={left:+b[0],top:+b[1]||0}),"left"in b&&(this.offset.click.left=b.left+this.margins.left),"right"in b&&(this.offset.click.left=this.helperProportions.width-b.right+this.margins.left),"top"in b&&(this.offset.click.top=b.top+this.margins.top),"bottom"in b&&(this.offset.click.top=this.helperProportions.height-b.bottom+this.margins.top)},_getParentOffset:function(){this.offsetParent=this.helper.offsetParent();var b=this.offsetParent.offset();this.cssPosition=="absolute"&&this.scrollParent[0]!=document&&a.ui.contains(this.scrollParent[0],this.offsetParent[0])&&(b.left+=this.scrollParent.scrollLeft(),b.top+=this.scrollParent.scrollTop());if(this.offsetParent[0]==document.body||this.offsetParent[0].tagName&&this.offsetParent[0].tagName.toLowerCase()=="html"&&a.browser.msie)b={top:0,left:0};return{top:b.top+(parseInt(this.offsetParent.css("borderTopWidth"),10)||0),left:b.left+(parseInt(this.offsetParent.css("borderLeftWidth"),10)||0)}},_getRelativeOffset:function(){if(this.cssPosition=="relative"){var a=this.element.position();return{top:a.top-(parseInt(this.helper.css("top"),10)||0)+this.scrollParent.scrollTop(),left:a.left-(parseInt(this.helper.css("left"),10)||0)+this.scrollParent.scrollLeft()}}return{top:0,left:0}},_cacheMargins:function(){this.margins={left:parseInt(this.element.css("marginLeft"),10)||0,top:parseInt(this.element.css("marginTop"),10)||0,right:parseInt(this.element.css("marginRight"),10)||0,bottom:parseInt(this.element.css("marginBottom"),10)||0}},_cacheHelperProportions:function(){this.helperProportions={width:this.helper.outerWidth(),height:this.helper.outerHeight()}},_setContainment:function(){var b=this.options;b.containment=="parent"&&(b.containment=this.helper[0].parentNode);if(b.containment=="document"||b.containment=="window")this.containment=[b.containment=="document"?0:a(window).scrollLeft()-this.offset.relative.left-this.offset.parent.left,b.containment=="document"?0:a(window).scrollTop()-this.offset.relative.top-this.offset.parent.top,(b.containment=="document"?0:a(window).scrollLeft())+a(b.containment=="document"?document:window).width()-this.helperProportions.width-this.margins.left,(b.containment=="document"?0:a(window).scrollTop())+(a(b.containment=="document"?document:window).height()||document.body.parentNode.scrollHeight)-this.helperProportions.height-this.margins.top];if(!/^(document|window|parent)$/.test(b.containment)&&b.containment.constructor!=Array){var c=a(b.containment),d=c[0];if(!d)return;var e=c.offset(),f=a(d).css("overflow")!="hidden";this.containment=[(parseInt(a(d).css("borderLeftWidth"),10)||0)+(parseInt(a(d).css("paddingLeft"),10)||0),(parseInt(a(d).css("borderTopWidth"),10)||0)+(parseInt(a(d).css("paddingTop"),10)||0),(f?Math.max(d.scrollWidth,d.offsetWidth):d.offsetWidth)-(parseInt(a(d).css("borderLeftWidth"),10)||0)-(parseInt(a(d).css("paddingRight"),10)||0)-this.helperProportions.width-this.margins.left-this.margins.right,(f?Math.max(d.scrollHeight,d.offsetHeight):d.offsetHeight)-(parseInt(a(d).css("borderTopWidth"),10)||0)-(parseInt(a(d).css("paddingBottom"),10)||0)-this.helperProportions.height-this.margins.top-this.margins.bottom],this.relative_container=c}else b.containment.constructor==Array&&(this.containment=b.containment)},_convertPositionTo:function(b,c){c||(c=this.position);var d=b=="absolute"?1:-1,e=this.options,f=this.cssPosition=="absolute"&&(this.scrollParent[0]==document||!a.ui.contains(this.scrollParent[0],this.offsetParent[0]))?this.offsetParent:this.scrollParent,g=/(html|body)/i.test(f[0].tagName);return{top:c.top+this.offset.relative.top*d+this.offset.parent.top*d-(a.browser.safari&&a.browser.version<526&&this.cssPosition=="fixed"?0:(this.cssPosition=="fixed"?-this.scrollParent.scrollTop():g?0:f.scrollTop())*d),left:c.left+this.offset.relative.left*d+this.offset.parent.left*d-(a.browser.safari&&a.browser.version<526&&this.cssPosition=="fixed"?0:(this.cssPosition=="fixed"?-this.scrollParent.scrollLeft():g?0:f.scrollLeft())*d)}},_generatePosition:function(b){var c=this.options,d=this.cssPosition=="absolute"&&(this.scrollParent[0]==document||!a.ui.contains(this.scrollParent[0],this.offsetParent[0]))?this.offsetParent:this.scrollParent,e=/(html|body)/i.test(d[0].tagName),f=b.pageX,g=b.pageY;if(this.originalPosition){var h;if(this.containment){if(this.relative_container){var i=this.relative_container.offset();h=[this.containment[0]+i.left,this.containment[1]+i.top,this.containment[2]+i.left,this.containment[3]+i.top]}else h=this.containment;b.pageX-this.offset.click.left<h[0]&&(f=h[0]+this.offset.click.left),b.pageY-this.offset.click.top<h[1]&&(g=h[1]+this.offset.click.top),b.pageX-this.offset.click.left>h[2]&&(f=h[2]+this.offset.click.left),b.pageY-this.offset.click.top>h[3]&&(g=h[3]+this.offset.click.top)}if(c.grid){var j=c.grid[1]?this.originalPageY+Math.round((g-this.originalPageY)/c.grid[1])*c.grid[1]:this.originalPageY;g=h?j-this.offset.click.top<h[1]||j-this.offset.click.top>h[3]?j-this.offset.click.top<h[1]?j+c.grid[1]:j-c.grid[1]:j:j;var k=c.grid[0]?this.originalPageX+Math.round((f-this.originalPageX)/c.grid[0])*c.grid[0]:this.originalPageX;f=h?k-this.offset.click.left<h[0]||k-this.offset.click.left>h[2]?k-this.offset.click.left<h[0]?k+c.grid[0]:k-c.grid[0]:k:k}}return{top:g-this.offset.click.top-this.offset.relative.top-this.offset.parent.top+(a.browser.safari&&a.browser.version<526&&this.cssPosition=="fixed"?0:this.cssPosition=="fixed"?-this.scrollParent.scrollTop():e?0:d.scrollTop()),left:f-this.offset.click.left-this.offset.relative.left-this.offset.parent.left+(a.browser.safari&&a.browser.version<526&&this.cssPosition=="fixed"?0:this.cssPosition=="fixed"?-this.scrollParent.scrollLeft():e?0:d.scrollLeft())}},_clear:function(){this.helper.removeClass("ui-draggable-dragging"),this.helper[0]!=this.element[0]&&!this.cancelHelperRemoval&&this.helper.remove(),this.helper=null,this.cancelHelperRemoval=!1},_trigger:function(b,c,d){return d=d||this._uiHash(),a.ui.plugin.call(this,b,[c,d]),b=="drag"&&(this.positionAbs=this._convertPositionTo("absolute")),a.Widget.prototype._trigger.call(this,b,c,d)},plugins:{},_uiHash:function(a){return{helper:this.helper,position:this.position,originalPosition:this.originalPosition,offset:this.positionAbs}}}),a.extend(a.ui.draggable,{version:"1.8.23"}),a.ui.plugin.add("draggable","connectToSortable",{start:function(b,c){var d=a(this).data("draggable"),e=d.options,f=a.extend({},c,{item:d.element});d.sortables=[],a(e.connectToSortable).each(function(){var c=a.data(this,"sortable");c&&!c.options.disabled&&(d.sortables.push({instance:c,shouldRevert:c.options.revert}),c.refreshPositions(),c._trigger("activate",b,f))})},stop:function(b,c){var d=a(this).data("draggable"),e=a.extend({},c,{item:d.element});a.each(d.sortables,function(){this.instance.isOver?(this.instance.isOver=0,d.cancelHelperRemoval=!0,this.instance.cancelHelperRemoval=!1,this.shouldRevert&&(this.instance.options.revert=!0),this.instance._mouseStop(b),this.instance.options.helper=this.instance.options._helper,d.options.helper=="original"&&this.instance.currentItem.css({top:"auto",left:"auto"})):(this.instance.cancelHelperRemoval=!1,this.instance._trigger("deactivate",b,e))})},drag:function(b,c){var d=a(this).data("draggable"),e=this,f=function(b){var c=this.offset.click.top,d=this.offset.click.left,e=this.positionAbs.top,f=this.positionAbs.left,g=b.height,h=b.width,i=b.top,j=b.left;return a.ui.isOver(e+c,f+d,i,j,g,h)};a.each(d.sortables,function(f){this.instance.positionAbs=d.positionAbs,this.instance.helperProportions=d.helperProportions,this.instance.offset.click=d.offset.click,this.instance._intersectsWith(this.instance.containerCache)?(this.instance.isOver||(this.instance.isOver=1,this.instance.currentItem=a(e).clone().removeAttr("id").appendTo(this.instance.element).data("sortable-item",!0),this.instance.options._helper=this.instance.options.helper,this.instance.options.helper=function(){return c.helper[0]},b.target=this.instance.currentItem[0],this.instance._mouseCapture(b,!0),this.instance._mouseStart(b,!0,!0),this.instance.offset.click.top=d.offset.click.top,this.instance.offset.click.left=d.offset.click.left,this.instance.offset.parent.left-=d.offset.parent.left-this.instance.offset.parent.left,this.instance.offset.parent.top-=d.offset.parent.top-this.instance.offset.parent.top,d._trigger("toSortable",b),d.dropped=this.instance.element,d.currentItem=d.element,this.instance.fromOutside=d),this.instance.currentItem&&this.instance._mouseDrag(b)):this.instance.isOver&&(this.instance.isOver=0,this.instance.cancelHelperRemoval=!0,this.instance.options.revert=!1,this.instance._trigger("out",b,this.instance._uiHash(this.instance)),this.instance._mouseStop(b,!0),this.instance.options.helper=this.instance.options._helper,this.instance.currentItem.remove(),this.instance.placeholder&&this.instance.placeholder.remove(),d._trigger("fromSortable",b),d.dropped=!1)})}}),a.ui.plugin.add("draggable","cursor",{start:function(b,c){var d=a("body"),e=a(this).data("draggable").options;d.css("cursor")&&(e._cursor=d.css("cursor")),d.css("cursor",e.cursor)},stop:function(b,c){var d=a(this).data("draggable").options;d._cursor&&a("body").css("cursor",d._cursor)}}),a.ui.plugin.add("draggable","opacity",{start:function(b,c){var d=a(c.helper),e=a(this).data("draggable").options;d.css("opacity")&&(e._opacity=d.css("opacity")),d.css("opacity",e.opacity)},stop:function(b,c){var d=a(this).data("draggable").options;d._opacity&&a(c.helper).css("opacity",d._opacity)}}),a.ui.plugin.add("draggable","scroll",{start:function(b,c){var d=a(this).data("draggable");d.scrollParent[0]!=document&&d.scrollParent[0].tagName!="HTML"&&(d.overflowOffset=d.scrollParent.offset())},drag:function(b,c){var d=a(this).data("draggable"),e=d.options,f=!1;if(d.scrollParent[0]!=document&&d.scrollParent[0].tagName!="HTML"){if(!e.axis||e.axis!="x")d.overflowOffset.top+d.scrollParent[0].offsetHeight-b.pageY<e.scrollSensitivity?d.scrollParent[0].scrollTop=f=d.scrollParent[0].scrollTop+e.scrollSpeed:b.pageY-d.overflowOffset.top<e.scrollSensitivity&&(d.scrollParent[0].scrollTop=f=d.scrollParent[0].scrollTop-e.scrollSpeed);if(!e.axis||e.axis!="y")d.overflowOffset.left+d.scrollParent[0].offsetWidth-b.pageX<e.scrollSensitivity?d.scrollParent[0].scrollLeft=f=d.scrollParent[0].scrollLeft+e.scrollSpeed:b.pageX-d.overflowOffset.left<e.scrollSensitivity&&(d.scrollParent[0].scrollLeft=f=d.scrollParent[0].scrollLeft-e.scrollSpeed)}else{if(!e.axis||e.axis!="x")b.pageY-a(document).scrollTop()<e.scrollSensitivity?f=a(document).scrollTop(a(document).scrollTop()-e.scrollSpeed):a(window).height()-(b.pageY-a(document).scrollTop())<e.scrollSensitivity&&(f=a(document).scrollTop(a(document).scrollTop()+e.scrollSpeed));if(!e.axis||e.axis!="y")b.pageX-a(document).scrollLeft()<e.scrollSensitivity?f=a(document).scrollLeft(a(document).scrollLeft()-e.scrollSpeed):a(window).width()-(b.pageX-a(document).scrollLeft())<e.scrollSensitivity&&(f=a(document).scrollLeft(a(document).scrollLeft()+e.scrollSpeed))}f!==!1&&a.ui.ddmanager&&!e.dropBehaviour&&a.ui.ddmanager.prepareOffsets(d,b)}}),a.ui.plugin.add("draggable","snap",{start:function(b,c){var d=a(this).data("draggable"),e=d.options;d.snapElements=[],a(e.snap.constructor!=String?e.snap.items||":data(draggable)":e.snap).each(function(){var b=a(this),c=b.offset();this!=d.element[0]&&d.snapElements.push({item:this,width:b.outerWidth(),height:b.outerHeight(),top:c.top,left:c.left})})},drag:function(b,c){var d=a(this).data("draggable"),e=d.options,f=e.snapTolerance,g=c.offset.left,h=g+d.helperProportions.width,i=c.offset.top,j=i+d.helperProportions.height;for(var k=d.snapElements.length-1;k>=0;k--){var l=d.snapElements[k].left,m=l+d.snapElements[k].width,n=d.snapElements[k].top,o=n+d.snapElements[k].height;if(!(l-f<g&&g<m+f&&n-f<i&&i<o+f||l-f<g&&g<m+f&&n-f<j&&j<o+f||l-f<h&&h<m+f&&n-f<i&&i<o+f||l-f<h&&h<m+f&&n-f<j&&j<o+f)){d.snapElements[k].snapping&&d.options.snap.release&&d.options.snap.release.call(d.element,b,a.extend(d._uiHash(),{snapItem:d.snapElements[k].item})),d.snapElements[k].snapping=!1;continue}if(e.snapMode!="inner"){var p=Math.abs(n-j)<=f,q=Math.abs(o-i)<=f,r=Math.abs(l-h)<=f,s=Math.abs(m-g)<=f;p&&(c.position.top=d._convertPositionTo("relative",{top:n-d.helperProportions.height,left:0}).top-d.margins.top),q&&(c.position.top=d._convertPositionTo("relative",{top:o,left:0}).top-d.margins.top),r&&(c.position.left=d._convertPositionTo("relative",{top:0,left:l-d.helperProportions.width}).left-d.margins.left),s&&(c.position.left=d._convertPositionTo("relative",{top:0,left:m}).left-d.margins.left)}var t=p||q||r||s;if(e.snapMode!="outer"){var p=Math.abs(n-i)<=f,q=Math.abs(o-j)<=f,r=Math.abs(l-g)<=f,s=Math.abs(m-h)<=f;p&&(c.position.top=d._convertPositionTo("relative",{top:n,left:0}).top-d.margins.top),q&&(c.position.top=d._convertPositionTo("relative",{top:o-d.helperProportions.height,left:0}).top-d.margins.top),r&&(c.position.left=d._convertPositionTo("relative",{top:0,left:l}).left-d.margins.left),s&&(c.position.left=d._convertPositionTo("relative",{top:0,left:m-d.helperProportions.width}).left-d.margins.left)}!d.snapElements[k].snapping&&(p||q||r||s||t)&&d.options.snap.snap&&d.options.snap.snap.call(d.element,b,a.extend(d._uiHash(),{snapItem:d.snapElements[k].item})),d.snapElements[k].snapping=p||q||r||s||t}}}),a.ui.plugin.add("draggable","stack",{start:function(b,c){var d=a(this).data("draggable").options,e=a.makeArray(a(d.stack)).sort(function(b,c){return(parseInt(a(b).css("zIndex"),10)||0)-(parseInt(a(c).css("zIndex"),10)||0)});if(!e.length)return;var f=parseInt(e[0].style.zIndex)||0;a(e).each(function(a){this.style.zIndex=f+a}),this[0].style.zIndex=f+e.length}}),a.ui.plugin.add("draggable","zIndex",{start:function(b,c){var d=a(c.helper),e=a(this).data("draggable").options;d.css("zIndex")&&(e._zIndex=d.css("zIndex")),d.css("zIndex",e.zIndex)},stop:function(b,c){var d=a(this).data("draggable").options;d._zIndex&&a(c.helper).css("zIndex",d._zIndex)}})})(jQuery);;/*! jQuery UI - v1.8.23 - 2012-08-15
    --* https://github.com/jquery/jquery-ui
    --* Includes: jquery.ui.droppable.js
    --* Copyright (c) 2012 AUTHORS.txt; Licensed MIT, GPL */
    --(function(a,b){a.widget("ui.droppable",{widgetEventPrefix:"drop",options:{accept:"*",activeClass:!1,addClasses:!0,greedy:!1,hoverClass:!1,scope:"default",tolerance:"intersect"},_create:function(){var b=this.options,c=b.accept;this.isover=0,this.isout=1,this.accept=a.isFunction(c)?c:function(a){return a.is(c)},this.proportions={width:this.element[0].offsetWidth,height:this.element[0].offsetHeight},a.ui.ddmanager.droppables[b.scope]=a.ui.ddmanager.droppables[b.scope]||[],a.ui.ddmanager.droppables[b.scope].push(this),b.addClasses&&this.element.addClass("ui-droppable")},destroy:function(){var b=a.ui.ddmanager.droppables[this.options.scope];for(var c=0;c<b.length;c++)b[c]==this&&b.splice(c,1);return this.element.removeClass("ui-droppable ui-droppable-disabled").removeData("droppable").unbind(".droppable"),this},_setOption:function(b,c){b=="accept"&&(this.accept=a.isFunction(c)?c:function(a){return a.is(c)}),a.Widget.prototype._setOption.apply(this,arguments)},_activate:function(b){var c=a.ui.ddmanager.current;this.options.activeClass&&this.element.addClass(this.options.activeClass),c&&this._trigger("activate",b,this.ui(c))},_deactivate:function(b){var c=a.ui.ddmanager.current;this.options.activeClass&&this.element.removeClass(this.options.activeClass),c&&this._trigger("deactivate",b,this.ui(c))},_over:function(b){var c=a.ui.ddmanager.current;if(!c||(c.currentItem||c.element)[0]==this.element[0])return;this.accept.call(this.element[0],c.currentItem||c.element)&&(this.options.hoverClass&&this.element.addClass(this.options.hoverClass),this._trigger("over",b,this.ui(c)))},_out:function(b){var c=a.ui.ddmanager.current;if(!c||(c.currentItem||c.element)[0]==this.element[0])return;this.accept.call(this.element[0],c.currentItem||c.element)&&(this.options.hoverClass&&this.element.removeClass(this.options.hoverClass),this._trigger("out",b,this.ui(c)))},_drop:function(b,c){var d=c||a.ui.ddmanager.current;if(!d||(d.currentItem||d.element)[0]==this.element[0])return!1;var e=!1;return this.element.find(":data(droppable)").not(".ui-draggable-dragging").each(function(){var b=a.data(this,"droppable");if(b.options.greedy&&!b.options.disabled&&b.options.scope==d.options.scope&&b.accept.call(b.element[0],d.currentItem||d.element)&&a.ui.intersect(d,a.extend(b,{offset:b.element.offset()}),b.options.tolerance))return e=!0,!1}),e?!1:this.accept.call(this.element[0],d.currentItem||d.element)?(this.options.activeClass&&this.element.removeClass(this.options.activeClass),this.options.hoverClass&&this.element.removeClass(this.options.hoverClass),this._trigger("drop",b,this.ui(d)),this.element):!1},ui:function(a){return{draggable:a.currentItem||a.element,helper:a.helper,position:a.position,offset:a.positionAbs}}}),a.extend(a.ui.droppable,{version:"1.8.23"}),a.ui.intersect=function(b,c,d){if(!c.offset)return!1;var e=(b.positionAbs||b.position.absolute).left,f=e+b.helperProportions.width,g=(b.positionAbs||b.position.absolute).top,h=g+b.helperProportions.height,i=c.offset.left,j=i+c.proportions.width,k=c.offset.top,l=k+c.proportions.height;switch(d){case"fit":return i<=e&&f<=j&&k<=g&&h<=l;case"intersect":return i<e+b.helperProportions.width/2&&f-b.helperProportions.width/2<j&&k<g+b.helperProportions.height/2&&h-b.helperProportions.height/2<l;case"pointer":var m=(b.positionAbs||b.position.absolute).left+(b.clickOffset||b.offset.click).left,n=(b.positionAbs||b.position.absolute).top+(b.clickOffset||b.offset.click).top,o=a.ui.isOver(n,m,k,i,c.proportions.height,c.proportions.width);return o;case"touch":return(g>=k&&g<=l||h>=k&&h<=l||g<k&&h>l)&&(e>=i&&e<=j||f>=i&&f<=j||e<i&&f>j);default:return!1}},a.ui.ddmanager={current:null,droppables:{"default":[]},prepareOffsets:function(b,c){var d=a.ui.ddmanager.droppables[b.options.scope]||[],e=c?c.type:null,f=(b.currentItem||b.element).find(":data(droppable)").andSelf();g:for(var h=0;h<d.length;h++){if(d[h].options.disabled||b&&!d[h].accept.call(d[h].element[0],b.currentItem||b.element))continue;for(var i=0;i<f.length;i++)if(f[i]==d[h].element[0]){d[h].proportions.height=0;continue g}d[h].visible=d[h].element.css("display")!="none";if(!d[h].visible)continue;e=="mousedown"&&d[h]._activate.call(d[h],c),d[h].offset=d[h].element.offset(),d[h].proportions={width:d[h].element[0].offsetWidth,height:d[h].element[0].offsetHeight}}},drop:function(b,c){var d=!1;return a.each(a.ui.ddmanager.droppables[b.options.scope]||[],function(){if(!this.options)return;!this.options.disabled&&this.visible&&a.ui.intersect(b,this,this.options.tolerance)&&(d=this._drop.call(this,c)||d),!this.options.disabled&&this.visible&&this.accept.call(this.element[0],b.currentItem||b.element)&&(this.isout=1,this.isover=0,this._deactivate.call(this,c))}),d},dragStart:function(b,c){b.element.parents(":not(body,html)").bind("scroll.droppable",function(){b.options.refreshPositions||a.ui.ddmanager.prepareOffsets(b,c)})},drag:function(b,c){b.options.refreshPositions&&a.ui.ddmanager.prepareOffsets(b,c),a.each(a.ui.ddmanager.droppables[b.options.scope]||[],function(){if(this.options.disabled||this.greedyChild||!this.visible)return;var d=a.ui.intersect(b,this,this.options.tolerance),e=!d&&this.isover==1?"isout":d&&this.isover==0?"isover":null;if(!e)return;var f;if(this.options.greedy){var g=this.element.parents(":data(droppable):eq(0)");g.length&&(f=a.data(g[0],"droppable"),f.greedyChild=e=="isover"?1:0)}f&&e=="isover"&&(f.isover=0,f.isout=1,f._out.call(f,c)),this[e]=1,this[e=="isout"?"isover":"isout"]=0,this[e=="isover"?"_over":"_out"].call(this,c),f&&e=="isout"&&(f.isout=0,f.isover=1,f._over.call(f,c))})},dragStop:function(b,c){b.element.parents(":not(body,html)").unbind("scroll.droppable"),b.options.refreshPositions||a.ui.ddmanager.prepareOffsets(b,c)}}})(jQuery);;/*! jQuery UI - v1.8.23 - 2012-08-15
    --* https://github.com/jquery/jquery-ui
    --* Includes: jquery.ui.resizable.js
    --* Copyright (c) 2012 AUTHORS.txt; Licensed MIT, GPL */
    --(function(a,b){a.widget("ui.resizable",a.ui.mouse,{widgetEventPrefix:"resize",options:{alsoResize:!1,animate:!1,animateDuration:"slow",animateEasing:"swing",aspectRatio:!1,autoHide:!1,containment:!1,ghost:!1,grid:!1,handles:"e,s,se",helper:!1,maxHeight:null,maxWidth:null,minHeight:10,minWidth:10,zIndex:1e3},_create:function(){var b=this,c=this.options;this.element.addClass("ui-resizable"),a.extend(this,{_aspectRatio:!!c.aspectRatio,aspectRatio:c.aspectRatio,originalElement:this.element,_proportionallyResizeElements:[],_helper:c.helper||c.ghost||c.animate?c.helper||"ui-resizable-helper":null}),this.element[0].nodeName.match(/canvas|textarea|input|select|button|img/i)&&(this.element.wrap(a('<div class="ui-wrapper" style="overflow: hidden;"></div>').css({position:this.element.css("position"),width:this.element.outerWidth(),height:this.element.outerHeight(),top:this.element.css("top"),left:this.element.css("left")})),this.element=this.element.parent().data("resizable",this.element.data("resizable")),this.elementIsWrapper=!0,this.element.css({marginLeft:this.originalElement.css("marginLeft"),marginTop:this.originalElement.css("marginTop"),marginRight:this.originalElement.css("marginRight"),marginBottom:this.originalElement.css("marginBottom")}),this.originalElement.css({marginLeft:0,marginTop:0,marginRight:0,marginBottom:0}),this.originalResizeStyle=this.originalElement.css("resize"),this.originalElement.css("resize","none"),this._proportionallyResizeElements.push(this.originalElement.css({position:"static",zoom:1,display:"block"})),this.originalElement.css({margin:this.originalElement.css("margin")}),this._proportionallyResize()),this.handles=c.handles||(a(".ui-resizable-handle",this.element).length?{n:".ui-resizable-n",e:".ui-resizable-e",s:".ui-resizable-s",w:".ui-resizable-w",se:".ui-resizable-se",sw:".ui-resizable-sw",ne:".ui-resizable-ne",nw:".ui-resizable-nw"}:"e,s,se");if(this.handles.constructor==String){this.handles=="all"&&(this.handles="n,e,s,w,se,sw,ne,nw");var d=this.handles.split(",");this.handles={};for(var e=0;e<d.length;e++){var f=a.trim(d[e]),g="ui-resizable-"+f,h=a('<div class="ui-resizable-handle '+g+'"></div>');h.css({zIndex:c.zIndex}),"se"==f&&h.addClass("ui-icon ui-icon-gripsmall-diagonal-se"),this.handles[f]=".ui-resizable-"+f,this.element.append(h)}}this._renderAxis=function(b){b=b||this.element;for(var c in this.handles){this.handles[c].constructor==String&&(this.handles[c]=a(this.handles[c],this.element).show());if(this.elementIsWrapper&&this.originalElement[0].nodeName.match(/textarea|input|select|button/i)){var d=a(this.handles[c],this.element),e=0;e=/sw|ne|nw|se|n|s/.test(c)?d.outerHeight():d.outerWidth();var f=["padding",/ne|nw|n/.test(c)?"Top":/se|sw|s/.test(c)?"Bottom":/^e$/.test(c)?"Right":"Left"].join("");b.css(f,e),this._proportionallyResize()}if(!a(this.handles[c]).length)continue}},this._renderAxis(this.element),this._handles=a(".ui-resizable-handle",this.element).disableSelection(),this._handles.mouseover(function(){if(!b.resizing){if(this.className)var a=this.className.match(/ui-resizable-(se|sw|ne|nw|n|e|s|w)/i);b.axis=a&&a[1]?a[1]:"se"}}),c.autoHide&&(this._handles.hide(),a(this.element).addClass("ui-resizable-autohide").hover(function(){if(c.disabled)return;a(this).removeClass("ui-resizable-autohide"),b._handles.show()},function(){if(c.disabled)return;b.resizing||(a(this).addClass("ui-resizable-autohide"),b._handles.hide())})),this._mouseInit()},destroy:function(){this._mouseDestroy();var b=function(b){a(b).removeClass("ui-resizable ui-resizable-disabled ui-resizable-resizing").removeData("resizable").unbind(".resizable").find(".ui-resizable-handle").remove()};if(this.elementIsWrapper){b(this.element);var c=this.element;c.after(this.originalElement.css({position:c.css("position"),width:c.outerWidth(),height:c.outerHeight(),top:c.css("top"),left:c.css("left")})).remove()}return this.originalElement.css("resize",this.originalResizeStyle),b(this.originalElement),this},_mouseCapture:function(b){var c=!1;for(var d in this.handles)a(this.handles[d])[0]==b.target&&(c=!0);return!this.options.disabled&&c},_mouseStart:function(b){var d=this.options,e=this.element.position(),f=this.element;this.resizing=!0,this.documentScroll={top:a(document).scrollTop(),left:a(document).scrollLeft()},(f.is(".ui-draggable")||/absolute/.test(f.css("position")))&&f.css({position:"absolute",top:e.top,left:e.left}),this._renderProxy();var g=c(this.helper.css("left")),h=c(this.helper.css("top"));d.containment&&(g+=a(d.containment).scrollLeft()||0,h+=a(d.containment).scrollTop()||0),this.offset=this.helper.offset(),this.position={left:g,top:h},this.size=this._helper?{width:f.outerWidth(),height:f.outerHeight()}:{width:f.width(),height:f.height()},this.originalSize=this._helper?{width:f.outerWidth(),height:f.outerHeight()}:{width:f.width(),height:f.height()},this.originalPosition={left:g,top:h},this.sizeDiff={width:f.outerWidth()-f.width(),height:f.outerHeight()-f.height()},this.originalMousePosition={left:b.pageX,top:b.pageY},this.aspectRatio=typeof d.aspectRatio=="number"?d.aspectRatio:this.originalSize.width/this.originalSize.height||1;var i=a(".ui-resizable-"+this.axis).css("cursor");return a("body").css("cursor",i=="auto"?this.axis+"-resize":i),f.addClass("ui-resizable-resizing"),this._propagate("start",b),!0},_mouseDrag:function(b){var c=this.helper,d=this.options,e={},f=this,g=this.originalMousePosition,h=this.axis,i=b.pageX-g.left||0,j=b.pageY-g.top||0,k=this._change[h];if(!k)return!1;var l=k.apply(this,[b,i,j]),m=a.browser.msie&&a.browser.version<7,n=this.sizeDiff;this._updateVirtualBoundaries(b.shiftKey);if(this._aspectRatio||b.shiftKey)l=this._updateRatio(l,b);return l=this._respectSize(l,b),this._propagate("resize",b),c.css({top:this.position.top+"px",left:this.position.left+"px",width:this.size.width+"px",height:this.size.height+"px"}),!this._helper&&this._proportionallyResizeElements.length&&this._proportionallyResize(),this._updateCache(l),this._trigger("resize",b,this.ui()),!1},_mouseStop:function(b){this.resizing=!1;var c=this.options,d=this;if(this._helper){var e=this._proportionallyResizeElements,f=e.length&&/textarea/i.test(e[0].nodeName),g=f&&a.ui.hasScroll(e[0],"left")?0:d.sizeDiff.height,h=f?0:d.sizeDiff.width,i={width:d.helper.width()-h,height:d.helper.height()-g},j=parseInt(d.element.css("left"),10)+(d.position.left-d.originalPosition.left)||null,k=parseInt(d.element.css("top"),10)+(d.position.top-d.originalPosition.top)||null;c.animate||this.element.css(a.extend(i,{top:k,left:j})),d.helper.height(d.size.height),d.helper.width(d.size.width),this._helper&&!c.animate&&this._proportionallyResize()}return a("body").css("cursor","auto"),this.element.removeClass("ui-resizable-resizing"),this._propagate("stop",b),this._helper&&this.helper.remove(),!1},_updateVirtualBoundaries:function(a){var b=this.options,c,e,f,g,h;h={minWidth:d(b.minWidth)?b.minWidth:0,maxWidth:d(b.maxWidth)?b.maxWidth:Infinity,minHeight:d(b.minHeight)?b.minHeight:0,maxHeight:d(b.maxHeight)?b.maxHeight:Infinity};if(this._aspectRatio||a)c=h.minHeight*this.aspectRatio,f=h.minWidth/this.aspectRatio,e=h.maxHeight*this.aspectRatio,g=h.maxWidth/this.aspectRatio,c>h.minWidth&&(h.minWidth=c),f>h.minHeight&&(h.minHeight=f),e<h.maxWidth&&(h.maxWidth=e),g<h.maxHeight&&(h.maxHeight=g);this._vBoundaries=h},_updateCache:function(a){var b=this.options;this.offset=this.helper.offset(),d(a.left)&&(this.position.left=a.left),d(a.top)&&(this.position.top=a.top),d(a.height)&&(this.size.height=a.height),d(a.width)&&(this.size.width=a.width)},_updateRatio:function(a,b){var c=this.options,e=this.position,f=this.size,g=this.axis;return d(a.height)?a.width=a.height*this.aspectRatio:d(a.width)&&(a.height=a.width/this.aspectRatio),g=="sw"&&(a.left=e.left+(f.width-a.width),a.top=null),g=="nw"&&(a.top=e.top+(f.height-a.height),a.left=e.left+(f.width-a.width)),a},_respectSize:function(a,b){var c=this.helper,e=this._vBoundaries,f=this._aspectRatio||b.shiftKey,g=this.axis,h=d(a.width)&&e.maxWidth&&e.maxWidth<a.width,i=d(a.height)&&e.maxHeight&&e.maxHeight<a.height,j=d(a.width)&&e.minWidth&&e.minWidth>a.width,k=d(a.height)&&e.minHeight&&e.minHeight>a.height;j&&(a.width=e.minWidth),k&&(a.height=e.minHeight),h&&(a.width=e.maxWidth),i&&(a.height=e.maxHeight);var l=this.originalPosition.left+this.originalSize.width,m=this.position.top+this.size.height,n=/sw|nw|w/.test(g),o=/nw|ne|n/.test(g);j&&n&&(a.left=l-e.minWidth),h&&n&&(a.left=l-e.maxWidth),k&&o&&(a.top=m-e.minHeight),i&&o&&(a.top=m-e.maxHeight);var p=!a.width&&!a.height;return p&&!a.left&&a.top?a.top=null:p&&!a.top&&a.left&&(a.left=null),a},_proportionallyResize:function(){var b=this.options;if(!this._proportionallyResizeElements.length)return;var c=this.helper||this.element;for(var d=0;d<this._proportionallyResizeElements.length;d++){var e=this._proportionallyResizeElements[d];if(!this.borderDif){var f=[e.css("borderTopWidth"),e.css("borderRightWidth"),e.css("borderBottomWidth"),e.css("borderLeftWidth")],g=[e.css("paddingTop"),e.css("paddingRight"),e.css("paddingBottom"),e.css("paddingLeft")];this.borderDif=a.map(f,function(a,b){var c=parseInt(a,10)||0,d=parseInt(g[b],10)||0;return c+d})}if(!a.browser.msie||!a(c).is(":hidden")&&!a(c).parents(":hidden").length)e.css({height:c.height()-this.borderDif[0]-this.borderDif[2]||0,width:c.width()-this.borderDif[1]-this.borderDif[3]||0});else continue}},_renderProxy:function(){var b=this.element,c=this.options;this.elementOffset=b.offset();if(this._helper){this.helper=this.helper||a('<div style="overflow:hidden;"></div>');var d=a.browser.msie&&a.browser.version<7,e=d?1:0,f=d?2:-1;this.helper.addClass(this._helper).css({width:this.element.outerWidth()+f,height:this.element.outerHeight()+f,position:"absolute",left:this.elementOffset.left-e+"px",top:this.elementOffset.top-e+"px",zIndex:++c.zIndex}),this.helper.appendTo("body").disableSelection()}else this.helper=this.element},_change:{e:function(a,b,c){return{width:this.originalSize.width+b}},w:function(a,b,c){var d=this.options,e=this.originalSize,f=this.originalPosition;return{left:f.left+b,width:e.width-b}},n:function(a,b,c){var d=this.options,e=this.originalSize,f=this.originalPosition;return{top:f.top+c,height:e.height-c}},s:function(a,b,c){return{height:this.originalSize.height+c}},se:function(b,c,d){return a.extend(this._change.s.apply(this,arguments),this._change.e.apply(this,[b,c,d]))},sw:function(b,c,d){return a.extend(this._change.s.apply(this,arguments),this._change.w.apply(this,[b,c,d]))},ne:function(b,c,d){return a.extend(this._change.n.apply(this,arguments),this._change.e.apply(this,[b,c,d]))},nw:function(b,c,d){return a.extend(this._change.n.apply(this,arguments),this._change.w.apply(this,[b,c,d]))}},_propagate:function(b,c){a.ui.plugin.call(this,b,[c,this.ui()]),b!="resize"&&this._trigger(b,c,this.ui())},plugins:{},ui:function(){return{originalElement:this.originalElement,element:this.element,helper:this.helper,position:this.position,size:this.size,originalSize:this.originalSize,originalPosition:this.originalPosition}}}),a.extend(a.ui.resizable,{version:"1.8.23"}),a.ui.plugin.add("resizable","alsoResize",{start:function(b,c){var d=a(this).data("resizable"),e=d.options,f=function(b){a(b).each(function(){var b=a(this);b.data("resizable-alsoresize",{width:parseInt(b.width(),10),height:parseInt(b.height(),10),left:parseInt(b.css("left"),10),top:parseInt(b.css("top"),10)})})};typeof e.alsoResize=="object"&&!e.alsoResize.parentNode?e.alsoResize.length?(e.alsoResize=e.alsoResize[0],f(e.alsoResize)):a.each(e.alsoResize,function(a){f(a)}):f(e.alsoResize)},resize:function(b,c){var d=a(this).data("resizable"),e=d.options,f=d.originalSize,g=d.originalPosition,h={height:d.size.height-f.height||0,width:d.size.width-f.width||0,top:d.position.top-g.top||0,left:d.position.left-g.left||0},i=function(b,d){a(b).each(function(){var b=a(this),e=a(this).data("resizable-alsoresize"),f={},g=d&&d.length?d:b.parents(c.originalElement[0]).length?["width","height"]:["width","height","top","left"];a.each(g,function(a,b){var c=(e[b]||0)+(h[b]||0);c&&c>=0&&(f[b]=c||null)}),b.css(f)})};typeof e.alsoResize=="object"&&!e.alsoResize.nodeType?a.each(e.alsoResize,function(a,b){i(a,b)}):i(e.alsoResize)},stop:function(b,c){a(this).removeData("resizable-alsoresize")}}),a.ui.plugin.add("resizable","animate",{stop:function(b,c){var d=a(this).data("resizable"),e=d.options,f=d._proportionallyResizeElements,g=f.length&&/textarea/i.test(f[0].nodeName),h=g&&a.ui.hasScroll(f[0],"left")?0:d.sizeDiff.height,i=g?0:d.sizeDiff.width,j={width:d.size.width-i,height:d.size.height-h},k=parseInt(d.element.css("left"),10)+(d.position.left-d.originalPosition.left)||null,l=parseInt(d.element.css("top"),10)+(d.position.top-d.originalPosition.top)||null;d.element.animate(a.extend(j,l&&k?{top:l,left:k}:{}),{duration:e.animateDuration,easing:e.animateEasing,step:function(){var c={width:parseInt(d.element.css("width"),10),height:parseInt(d.element.css("height"),10),top:parseInt(d.element.css("top"),10),left:parseInt(d.element.css("left"),10)};f&&f.length&&a(f[0]).css({width:c.width,height:c.height}),d._updateCache(c),d._propagate("resize",b)}})}}),a.ui.plugin.add("resizable","containment",{start:function(b,d){var e=a(this).data("resizable"),f=e.options,g=e.element,h=f.containment,i=h instanceof a?h.get(0):/parent/.test(h)?g.parent().get(0):h;if(!i)return;e.containerElement=a(i);if(/document/.test(h)||h==document)e.containerOffset={left:0,top:0},e.containerPosition={left:0,top:0},e.parentData={element:a(document),left:0,top:0,width:a(document).width(),height:a(document).height()||document.body.parentNode.scrollHeight};else{var j=a(i),k=[];a(["Top","Right","Left","Bottom"]).each(function(a,b){k[a]=c(j.css("padding"+b))}),e.containerOffset=j.offset(),e.containerPosition=j.position(),e.containerSize={height:j.innerHeight()-k[3],width:j.innerWidth()-k[1]};var l=e.containerOffset,m=e.containerSize.height,n=e.containerSize.width,o=a.ui.hasScroll(i,"left")?i.scrollWidth:n,p=a.ui.hasScroll(i)?i.scrollHeight:m;e.parentData={element:i,left:l.left,top:l.top,width:o,height:p}}},resize:function(b,c){var d=a(this).data("resizable"),e=d.options,f=d.containerSize,g=d.containerOffset,h=d.size,i=d.position,j=d._aspectRatio||b.shiftKey,k={top:0,left:0},l=d.containerElement;l[0]!=document&&/static/.test(l.css("position"))&&(k=g),i.left<(d._helper?g.left:0)&&(d.size.width=d.size.width+(d._helper?d.position.left-g.left:d.position.left-k.left),j&&(d.size.height=d.size.width/d.aspectRatio),d.position.left=e.helper?g.left:0),i.top<(d._helper?g.top:0)&&(d.size.height=d.size.height+(d._helper?d.position.top-g.top:d.position.top),j&&(d.size.width=d.size.height*d.aspectRatio),d.position.top=d._helper?g.top:0),d.offset.left=d.parentData.left+d.position.left,d.offset.top=d.parentData.top+d.position.top;var m=Math.abs((d._helper?d.offset.left-k.left:d.offset.left-k.left)+d.sizeDiff.width),n=Math.abs((d._helper?d.offset.top-k.top:d.offset.top-g.top)+d.sizeDiff.height),o=d.containerElement.get(0)==d.element.parent().get(0),p=/relative|absolute/.test(d.containerElement.css("position"));o&&p&&(m-=d.parentData.left),m+d.size.width>=d.parentData.width&&(d.size.width=d.parentData.width-m,j&&(d.size.height=d.size.width/d.aspectRatio)),n+d.size.height>=d.parentData.height&&(d.size.height=d.parentData.height-n,j&&(d.size.width=d.size.height*d.aspectRatio))},stop:function(b,c){var d=a(this).data("resizable"),e=d.options,f=d.position,g=d.containerOffset,h=d.containerPosition,i=d.containerElement,j=a(d.helper),k=j.offset(),l=j.outerWidth()-d.sizeDiff.width,m=j.outerHeight()-d.sizeDiff.height;d._helper&&!e.animate&&/relative/.test(i.css("position"))&&a(this).css({left:k.left-h.left-g.left,width:l,height:m}),d._helper&&!e.animate&&/static/.test(i.css("position"))&&a(this).css({left:k.left-h.left-g.left,width:l,height:m})}}),a.ui.plugin.add("resizable","ghost",{start:function(b,c){var d=a(this).data("resizable"),e=d.options,f=d.size;d.ghost=d.originalElement.clone(),d.ghost.css({opacity:.25,display:"block",position:"relative",height:f.height,width:f.width,margin:0,left:0,top:0}).addClass("ui-resizable-ghost").addClass(typeof e.ghost=="string"?e.ghost:""),d.ghost.appendTo(d.helper)},resize:function(b,c){var d=a(this).data("resizable"),e=d.options;d.ghost&&d.ghost.css({position:"relative",height:d.size.height,width:d.size.width})},stop:function(b,c){var d=a(this).data("resizable"),e=d.options;d.ghost&&d.helper&&d.helper.get(0).removeChild(d.ghost.get(0))}}),a.ui.plugin.add("resizable","grid",{resize:function(b,c){var d=a(this).data("resizable"),e=d.options,f=d.size,g=d.originalSize,h=d.originalPosition,i=d.axis,j=e._aspectRatio||b.shiftKey;e.grid=typeof e.grid=="number"?[e.grid,e.grid]:e.grid;var k=Math.round((f.width-g.width)/(e.grid[0]||1))*(e.grid[0]||1),l=Math.round((f.height-g.height)/(e.grid[1]||1))*(e.grid[1]||1);/^(se|s|e)$/.test(i)?(d.size.width=g.width+k,d.size.height=g.height+l):/^(ne)$/.test(i)?(d.size.width=g.width+k,d.size.height=g.height+l,d.position.top=h.top-l):/^(sw)$/.test(i)?(d.size.width=g.width+k,d.size.height=g.height+l,d.position.left=h.left-k):(d.size.width=g.width+k,d.size.height=g.height+l,d.position.top=h.top-l,d.position.left=h.left-k)}});var c=function(a){return parseInt(a,10)||0},d=function(a){return!isNaN(parseInt(a,10))}})(jQuery);;/*! jQuery UI - v1.8.23 - 2012-08-15
    --* https://github.com/jquery/jquery-ui
    --* Includes: jquery.ui.selectable.js
    --* Copyright (c) 2012 AUTHORS.txt; Licensed MIT, GPL */
    --(function(a,b){a.widget("ui.selectable",a.ui.mouse,{options:{appendTo:"body",autoRefresh:!0,distance:0,filter:"*",tolerance:"touch"},_create:function(){var b=this;this.element.addClass("ui-selectable"),this.dragged=!1;var c;this.refresh=function(){c=a(b.options.filter,b.element[0]),c.addClass("ui-selectee"),c.each(function(){var b=a(this),c=b.offset();a.data(this,"selectable-item",{element:this,$element:b,left:c.left,top:c.top,right:c.left+b.outerWidth(),bottom:c.top+b.outerHeight(),startselected:!1,selected:b.hasClass("ui-selected"),selecting:b.hasClass("ui-selecting"),unselecting:b.hasClass("ui-unselecting")})})},this.refresh(),this.selectees=c.addClass("ui-selectee"),this._mouseInit(),this.helper=a("<div class='ui-selectable-helper'></div>")},destroy:function(){return this.selectees.removeClass("ui-selectee").removeData("selectable-item"),this.element.removeClass("ui-selectable ui-selectable-disabled").removeData("selectable").unbind(".selectable"),this._mouseDestroy(),this},_mouseStart:function(b){var c=this;this.opos=[b.pageX,b.pageY];if(this.options.disabled)return;var d=this.options;this.selectees=a(d.filter,this.element[0]),this._trigger("start",b),a(d.appendTo).append(this.helper),this.helper.css({left:b.clientX,top:b.clientY,width:0,height:0}),d.autoRefresh&&this.refresh(),this.selectees.filter(".ui-selected").each(function(){var d=a.data(this,"selectable-item");d.startselected=!0,!b.metaKey&&!b.ctrlKey&&(d.$element.removeClass("ui-selected"),d.selected=!1,d.$element.addClass("ui-unselecting"),d.unselecting=!0,c._trigger("unselecting",b,{unselecting:d.element}))}),a(b.target).parents().andSelf().each(function(){var d=a.data(this,"selectable-item");if(d){var e=!b.metaKey&&!b.ctrlKey||!d.$element.hasClass("ui-selected");return d.$element.removeClass(e?"ui-unselecting":"ui-selected").addClass(e?"ui-selecting":"ui-unselecting"),d.unselecting=!e,d.selecting=e,d.selected=e,e?c._trigger("selecting",b,{selecting:d.element}):c._trigger("unselecting",b,{unselecting:d.element}),!1}})},_mouseDrag:function(b){var c=this;this.dragged=!0;if(this.options.disabled)return;var d=this.options,e=this.opos[0],f=this.opos[1],g=b.pageX,h=b.pageY;if(e>g){var i=g;g=e,e=i}if(f>h){var i=h;h=f,f=i}return this.helper.css({left:e,top:f,width:g-e,height:h-f}),this.selectees.each(function(){var i=a.data(this,"selectable-item");if(!i||i.element==c.element[0])return;var j=!1;d.tolerance=="touch"?j=!(i.left>g||i.right<e||i.top>h||i.bottom<f):d.tolerance=="fit"&&(j=i.left>e&&i.right<g&&i.top>f&&i.bottom<h),j?(i.selected&&(i.$element.removeClass("ui-selected"),i.selected=!1),i.unselecting&&(i.$element.removeClass("ui-unselecting"),i.unselecting=!1),i.selecting||(i.$element.addClass("ui-selecting"),i.selecting=!0,c._trigger("selecting",b,{selecting:i.element}))):(i.selecting&&((b.metaKey||b.ctrlKey)&&i.startselected?(i.$element.removeClass("ui-selecting"),i.selecting=!1,i.$element.addClass("ui-selected"),i.selected=!0):(i.$element.removeClass("ui-selecting"),i.selecting=!1,i.startselected&&(i.$element.addClass("ui-unselecting"),i.unselecting=!0),c._trigger("unselecting",b,{unselecting:i.element}))),i.selected&&!b.metaKey&&!b.ctrlKey&&!i.startselected&&(i.$element.removeClass("ui-selected"),i.selected=!1,i.$element.addClass("ui-unselecting"),i.unselecting=!0,c._trigger("unselecting",b,{unselecting:i.element})))}),!1},_mouseStop:function(b){var c=this;this.dragged=!1;var d=this.options;return a(".ui-unselecting",this.element[0]).each(function(){var d=a.data(this,"selectable-item");d.$element.removeClass("ui-unselecting"),d.unselecting=!1,d.startselected=!1,c._trigger("unselected",b,{unselected:d.element})}),a(".ui-selecting",this.element[0]).each(function(){var d=a.data(this,"selectable-item");d.$element.removeClass("ui-selecting").addClass("ui-selected"),d.selecting=!1,d.selected=!0,d.startselected=!0,c._trigger("selected",b,{selected:d.element})}),this._trigger("stop",b),this.helper.remove(),!1}}),a.extend(a.ui.selectable,{version:"1.8.23"})})(jQuery);;/*! jQuery UI - v1.8.23 - 2012-08-15
    --* https://github.com/jquery/jquery-ui
    --* Includes: jquery.ui.sortable.js
    --* Copyright (c) 2012 AUTHORS.txt; Licensed MIT, GPL */
    --(function(a,b){a.widget("ui.sortable",a.ui.mouse,{widgetEventPrefix:"sort",ready:!1,options:{appendTo:"parent",axis:!1,connectWith:!1,containment:!1,cursor:"auto",cursorAt:!1,dropOnEmpty:!0,forcePlaceholderSize:!1,forceHelperSize:!1,grid:!1,handle:!1,helper:"original",items:"> *",opacity:!1,placeholder:!1,revert:!1,scroll:!0,scrollSensitivity:20,scrollSpeed:20,scope:"default",tolerance:"intersect",zIndex:1e3},_create:function(){var a=this.options;this.containerCache={},this.element.addClass("ui-sortable"),this.refresh(),this.floating=this.items.length?a.axis==="x"||/left|right/.test(this.items[0].item.css("float"))||/inline|table-cell/.test(this.items[0].item.css("display")):!1,this.offset=this.element.offset(),this._mouseInit(),this.ready=!0},destroy:function(){a.Widget.prototype.destroy.call(this),this.element.removeClass("ui-sortable ui-sortable-disabled"),this._mouseDestroy();for(var b=this.items.length-1;b>=0;b--)this.items[b].item.removeData(this.widgetName+"-item");return this},_setOption:function(b,c){b==="disabled"?(this.options[b]=c,this.widget()[c?"addClass":"removeClass"]("ui-sortable-disabled")):a.Widget.prototype._setOption.apply(this,arguments)},_mouseCapture:function(b,c){var d=this;if(this.reverting)return!1;if(this.options.disabled||this.options.type=="static")return!1;this._refreshItems(b);var e=null,f=this,g=a(b.target).parents().each(function(){if(a.data(this,d.widgetName+"-item")==f)return e=a(this),!1});a.data(b.target,d.widgetName+"-item")==f&&(e=a(b.target));if(!e)return!1;if(this.options.handle&&!c){var h=!1;a(this.options.handle,e).find("*").andSelf().each(function(){this==b.target&&(h=!0)});if(!h)return!1}return this.currentItem=e,this._removeCurrentsFromItems(),!0},_mouseStart:function(b,c,d){var e=this.options,f=this;this.currentContainer=this,this.refreshPositions(),this.helper=this._createHelper(b),this._cacheHelperProportions(),this._cacheMargins(),this.scrollParent=this.helper.scrollParent(),this.offset=this.currentItem.offset(),this.offset={top:this.offset.top-this.margins.top,left:this.offset.left-this.margins.left},a.extend(this.offset,{click:{left:b.pageX-this.offset.left,top:b.pageY-this.offset.top},parent:this._getParentOffset(),relative:this._getRelativeOffset()}),this.helper.css("position","absolute"),this.cssPosition=this.helper.css("position"),this.originalPosition=this._generatePosition(b),this.originalPageX=b.pageX,this.originalPageY=b.pageY,e.cursorAt&&this._adjustOffsetFromHelper(e.cursorAt),this.domPosition={prev:this.currentItem.prev()[0],parent:this.currentItem.parent()[0]},this.helper[0]!=this.currentItem[0]&&this.currentItem.hide(),this._createPlaceholder(),e.containment&&this._setContainment(),e.cursor&&(a("body").css("cursor")&&(this._storedCursor=a("body").css("cursor")),a("body").css("cursor",e.cursor)),e.opacity&&(this.helper.css("opacity")&&(this._storedOpacity=this.helper.css("opacity")),this.helper.css("opacity",e.opacity)),e.zIndex&&(this.helper.css("zIndex")&&(this._storedZIndex=this.helper.css("zIndex")),this.helper.css("zIndex",e.zIndex)),this.scrollParent[0]!=document&&this.scrollParent[0].tagName!="HTML"&&(this.overflowOffset=this.scrollParent.offset()),this._trigger("start",b,this._uiHash()),this._preserveHelperProportions||this._cacheHelperProportions();if(!d)for(var g=this.containers.length-1;g>=0;g--)this.containers[g]._trigger("activate",b,f._uiHash(this));return a.ui.ddmanager&&(a.ui.ddmanager.current=this),a.ui.ddmanager&&!e.dropBehaviour&&a.ui.ddmanager.prepareOffsets(this,b),this.dragging=!0,this.helper.addClass("ui-sortable-helper"),this._mouseDrag(b),!0},_mouseDrag:function(b){this.position=this._generatePosition(b),this.positionAbs=this._convertPositionTo("absolute"),this.lastPositionAbs||(this.lastPositionAbs=this.positionAbs);if(this.options.scroll){var c=this.options,d=!1;this.scrollParent[0]!=document&&this.scrollParent[0].tagName!="HTML"?(this.overflowOffset.top+this.scrollParent[0].offsetHeight-b.pageY<c.scrollSensitivity?this.scrollParent[0].scrollTop=d=this.scrollParent[0].scrollTop+c.scrollSpeed:b.pageY-this.overflowOffset.top<c.scrollSensitivity&&(this.scrollParent[0].scrollTop=d=this.scrollParent[0].scrollTop-c.scrollSpeed),this.overflowOffset.left+this.scrollParent[0].offsetWidth-b.pageX<c.scrollSensitivity?this.scrollParent[0].scrollLeft=d=this.scrollParent[0].scrollLeft+c.scrollSpeed:b.pageX-this.overflowOffset.left<c.scrollSensitivity&&(this.scrollParent[0].scrollLeft=d=this.scrollParent[0].scrollLeft-c.scrollSpeed)):(b.pageY-a(document).scrollTop()<c.scrollSensitivity?d=a(document).scrollTop(a(document).scrollTop()-c.scrollSpeed):a(window).height()-(b.pageY-a(document).scrollTop())<c.scrollSensitivity&&(d=a(document).scrollTop(a(document).scrollTop()+c.scrollSpeed)),b.pageX-a(document).scrollLeft()<c.scrollSensitivity?d=a(document).scrollLeft(a(document).scrollLeft()-c.scrollSpeed):a(window).width()-(b.pageX-a(document).scrollLeft())<c.scrollSensitivity&&(d=a(document).scrollLeft(a(document).scrollLeft()+c.scrollSpeed))),d!==!1&&a.ui.ddmanager&&!c.dropBehaviour&&a.ui.ddmanager.prepareOffsets(this,b)}this.positionAbs=this._convertPositionTo("absolute");if(!this.options.axis||this.options.axis!="y")this.helper[0].style.left=this.position.left+"px";if(!this.options.axis||this.options.axis!="x")this.helper[0].style.top=this.position.top+"px";for(var e=this.items.length-1;e>=0;e--){var f=this.items[e],g=f.item[0],h=this._intersectsWithPointer(f);if(!h)continue;if(g!=this.currentItem[0]&&this.placeholder[h==1?"next":"prev"]()[0]!=g&&!a.ui.contains(this.placeholder[0],g)&&(this.options.type=="semi-dynamic"?!a.ui.contains(this.element[0],g):!0)){this.direction=h==1?"down":"up";if(this.options.tolerance=="pointer"||this._intersectsWithSides(f))this._rearrange(b,f);else break;this._trigger("change",b,this._uiHash());break}}return this._contactContainers(b),a.ui.ddmanager&&a.ui.ddmanager.drag(this,b),this._trigger("sort",b,this._uiHash()),this.lastPositionAbs=this.positionAbs,!1},_mouseStop:function(b,c){if(!b)return;a.ui.ddmanager&&!this.options.dropBehaviour&&a.ui.ddmanager.drop(this,b);if(this.options.revert){var d=this,e=d.placeholder.offset();d.reverting=!0,a(this.helper).animate({left:e.left-this.offset.parent.left-d.margins.left+(this.offsetParent[0]==document.body?0:this.offsetParent[0].scrollLeft),top:e.top-this.offset.parent.top-d.margins.top+(this.offsetParent[0]==document.body?0:this.offsetParent[0].scrollTop)},parseInt(this.options.revert,10)||500,function(){d._clear(b)})}else this._clear(b,c);return!1},cancel:function(){var b=this;if(this.dragging){this._mouseUp({target:null}),this.options.helper=="original"?this.currentItem.css(this._storedCSS).removeClass("ui-sortable-helper"):this.currentItem.show();for(var c=this.containers.length-1;c>=0;c--)this.containers[c]._trigger("deactivate",null,b._uiHash(this)),this.containers[c].containerCache.over&&(this.containers[c]._trigger("out",null,b._uiHash(this)),this.containers[c].containerCache.over=0)}return this.placeholder&&(this.placeholder[0].parentNode&&this.placeholder[0].parentNode.removeChild(this.placeholder[0]),this.options.helper!="original"&&this.helper&&this.helper[0].parentNode&&this.helper.remove(),a.extend(this,{helper:null,dragging:!1,reverting:!1,_noFinalSort:null}),this.domPosition.prev?a(this.domPosition.prev).after(this.currentItem):a(this.domPosition.parent).prepend(this.currentItem)),this},serialize:function(b){var c=this._getItemsAsjQuery(b&&b.connected),d=[];return b=b||{},a(c).each(function(){var c=(a(b.item||this).attr(b.attribute||"id")||"").match(b.expression||/(.+)[-=_](.+)/);c&&d.push((b.key||c[1]+"[]")+"="+(b.key&&b.expression?c[1]:c[2]))}),!d.length&&b.key&&d.push(b.key+"="),d.join("&")},toArray:function(b){var c=this._getItemsAsjQuery(b&&b.connected),d=[];return b=b||{},c.each(function(){d.push(a(b.item||this).attr(b.attribute||"id")||"")}),d},_intersectsWith:function(a){var b=this.positionAbs.left,c=b+this.helperProportions.width,d=this.positionAbs.top,e=d+this.helperProportions.height,f=a.left,g=f+a.width,h=a.top,i=h+a.height,j=this.offset.click.top,k=this.offset.click.left,l=d+j>h&&d+j<i&&b+k>f&&b+k<g;return this.options.tolerance=="pointer"||this.options.forcePointerForContainers||this.options.tolerance!="pointer"&&this.helperProportions[this.floating?"width":"height"]>a[this.floating?"width":"height"]?l:f<b+this.helperProportions.width/2&&c-this.helperProportions.width/2<g&&h<d+this.helperProportions.height/2&&e-this.helperProportions.height/2<i},_intersectsWithPointer:function(b){var c=this.options.axis==="x"||a.ui.isOverAxis(this.positionAbs.top+this.offset.click.top,b.top,b.height),d=this.options.axis==="y"||a.ui.isOverAxis(this.positionAbs.left+this.offset.click.left,b.left,b.width),e=c&&d,f=this._getDragVerticalDirection(),g=this._getDragHorizontalDirection();return e?this.floating?g&&g=="right"||f=="down"?2:1:f&&(f=="down"?2:1):!1},_intersectsWithSides:function(b){var c=a.ui.isOverAxis(this.positionAbs.top+this.offset.click.top,b.top+b.height/2,b.height),d=a.ui.isOverAxis(this.positionAbs.left+this.offset.click.left,b.left+b.width/2,b.width),e=this._getDragVerticalDirection(),f=this._getDragHorizontalDirection();return this.floating&&f?f=="right"&&d||f=="left"&&!d:e&&(e=="down"&&c||e=="up"&&!c)},_getDragVerticalDirection:function(){var a=this.positionAbs.top-this.lastPositionAbs.top;return a!=0&&(a>0?"down":"up")},_getDragHorizontalDirection:function(){var a=this.positionAbs.left-this.lastPositionAbs.left;return a!=0&&(a>0?"right":"left")},refresh:function(a){return this._refreshItems(a),this.refreshPositions(),this},_connectWith:function(){var a=this.options;return a.connectWith.constructor==String?[a.connectWith]:a.connectWith},_getItemsAsjQuery:function(b){var c=this,d=[],e=[],f=this._connectWith();if(f&&b)for(var g=f.length-1;g>=0;g--){var h=a(f[g]);for(var i=h.length-1;i>=0;i--){var j=a.data(h[i],this.widgetName);j&&j!=this&&!j.options.disabled&&e.push([a.isFunction(j.options.items)?j.options.items.call(j.element):a(j.options.items,j.element).not(".ui-sortable-helper").not(".ui-sortable-placeholder"),j])}}e.push([a.isFunction(this.options.items)?this.options.items.call(this.element,null,{options:this.options,item:this.currentItem}):a(this.options.items,this.element).not(".ui-sortable-helper").not(".ui-sortable-placeholder"),this]);for(var g=e.length-1;g>=0;g--)e[g][0].each(function(){d.push(this)});return a(d)},_removeCurrentsFromItems:function(){var a=this.currentItem.find(":data("+this.widgetName+"-item)");for(var b=0;b<this.items.length;b++)for(var c=0;c<a.length;c++)a[c]==this.items[b].item[0]&&this.items.splice(b,1)},_refreshItems:function(b){this.items=[],this.containers=[this];var c=this.items,d=this,e=[[a.isFunction(this.options.items)?this.options.items.call(this.element[0],b,{item:this.currentItem}):a(this.options.items,this.element),this]],f=this._connectWith();if(f&&this.ready)for(var g=f.length-1;g>=0;g--){var h=a(f[g]);for(var i=h.length-1;i>=0;i--){var j=a.data(h[i],this.widgetName);j&&j!=this&&!j.options.disabled&&(e.push([a.isFunction(j.options.items)?j.options.items.call(j.element[0],b,{item:this.currentItem}):a(j.options.items,j.element),j]),this.containers.push(j))}}for(var g=e.length-1;g>=0;g--){var k=e[g][1],l=e[g][0];for(var i=0,m=l.length;i<m;i++){var n=a(l[i]);n.data(this.widgetName+"-item",k),c.push({item:n,instance:k,width:0,height:0,left:0,top:0})}}},refreshPositions:function(b){this.offsetParent&&this.helper&&(this.offset.parent=this._getParentOffset());for(var c=this.items.length-1;c>=0;c--){var d=this.items[c];if(d.instance!=this.currentContainer&&this.currentContainer&&d.item[0]!=this.currentItem[0])continue;var e=this.options.toleranceElement?a(this.options.toleranceElement,d.item):d.item;b||(d.width=e.outerWidth(),d.height=e.outerHeight());var f=e.offset();d.left=f.left,d.top=f.top}if(this.options.custom&&this.options.custom.refreshContainers)this.options.custom.refreshContainers.call(this);else for(var c=this.containers.length-1;c>=0;c--){var f=this.containers[c].element.offset();this.containers[c].containerCache.left=f.left,this.containers[c].containerCache.top=f.top,this.containers[c].containerCache.width=this.containers[c].element.outerWidth(),this.containers[c].containerCache.height=this.containers[c].element.outerHeight()}return this},_createPlaceholder:function(b){var c=b||this,d=c.options;if(!d.placeholder||d.placeholder.constructor==String){var e=d.placeholder;d.placeholder={element:function(){var b=a(document.createElement(c.currentItem[0].nodeName)).addClass(e||c.currentItem[0].className+" ui-sortable-placeholder").removeClass("ui-sortable-helper")[0];return e||(b.style.visibility="hidden"),b},update:function(a,b){if(e&&!d.forcePlaceholderSize)return;b.height()||b.height(c.currentItem.innerHeight()-parseInt(c.currentItem.css("paddingTop")||0,10)-parseInt(c.currentItem.css("paddingBottom")||0,10)),b.width()||b.width(c.currentItem.innerWidth()-parseInt(c.currentItem.css("paddingLeft")||0,10)-parseInt(c.currentItem.css("paddingRight")||0,10))}}}c.placeholder=a(d.placeholder.element.call(c.element,c.currentItem)),c.currentItem.after(c.placeholder),d.placeholder.update(c,c.placeholder)},_contactContainers:function(b){var c=null,d=null;for(var e=this.containers.length-1;e>=0;e--){if(a.ui.contains(this.currentItem[0],this.containers[e].element[0]))continue;if(this._intersectsWith(this.containers[e].containerCache)){if(c&&a.ui.contains(this.containers[e].element[0],c.element[0]))continue;c=this.containers[e],d=e}else this.containers[e].containerCache.over&&(this.containers[e]._trigger("out",b,this._uiHash(this)),this.containers[e].containerCache.over=0)}if(!c)return;if(this.containers.length===1)this.containers[d]._trigger("over",b,this._uiHash(this)),this.containers[d].containerCache.over=1;else if(this.currentContainer!=this.containers[d]){var f=1e4,g=null,h=this.positionAbs[this.containers[d].floating?"left":"top"];for(var i=this.items.length-1;i>=0;i--){if(!a.ui.contains(this.containers[d].element[0],this.items[i].item[0]))continue;var j=this.containers[d].floating?this.items[i].item.offset().left:this.items[i].item.offset().top;Math.abs(j-h)<f&&(f=Math.abs(j-h),g=this.items[i],this.direction=j-h>0?"down":"up")}if(!g&&!this.options.dropOnEmpty)return;this.currentContainer=this.containers[d],g?this._rearrange(b,g,null,!0):this._rearrange(b,null,this.containers[d].element,!0),this._trigger("change",b,this._uiHash()),this.containers[d]._trigger("change",b,this._uiHash(this)),this.options.placeholder.update(this.currentContainer,this.placeholder),this.containers[d]._trigger("over",b,this._uiHash(this)),this.containers[d].containerCache.over=1}},_createHelper:function(b){var c=this.options,d=a.isFunction(c.helper)?a(c.helper.apply(this.element[0],[b,this.currentItem])):c.helper=="clone"?this.currentItem.clone():this.currentItem;return d.parents("body").length||a(c.appendTo!="parent"?c.appendTo:this.currentItem[0].parentNode)[0].appendChild(d[0]),d[0]==this.currentItem[0]&&(this._storedCSS={width:this.currentItem[0].style.width,height:this.currentItem[0].style.height,position:this.currentItem.css("position"),top:this.currentItem.css("top"),left:this.currentItem.css("left")}),(d[0].style.width==""||c.forceHelperSize)&&d.width(this.currentItem.width()),(d[0].style.height==""||c.forceHelperSize)&&d.height(this.currentItem.height()),d},_adjustOffsetFromHelper:function(b){typeof b=="string"&&(b=b.split(" ")),a.isArray(b)&&(b={left:+b[0],top:+b[1]||0}),"left"in b&&(this.offset.click.left=b.left+this.margins.left),"right"in b&&(this.offset.click.left=this.helperProportions.width-b.right+this.margins.left),"top"in b&&(this.offset.click.top=b.top+this.margins.top),"bottom"in b&&(this.offset.click.top=this.helperProportions.height-b.bottom+this.margins.top)},_getParentOffset:function(){this.offsetParent=this.helper.offsetParent();var b=this.offsetParent.offset();this.cssPosition=="absolute"&&this.scrollParent[0]!=document&&a.ui.contains(this.scrollParent[0],this.offsetParent[0])&&(b.left+=this.scrollParent.scrollLeft(),b.top+=this.scrollParent.scrollTop());if(this.offsetParent[0]==document.body||this.offsetParent[0].tagName&&this.offsetParent[0].tagName.toLowerCase()=="html"&&a.browser.msie)b={top:0,left:0};return{top:b.top+(parseInt(this.offsetParent.css("borderTopWidth"),10)||0),left:b.left+(parseInt(this.offsetParent.css("borderLeftWidth"),10)||0)}},_getRelativeOffset:function(){if(this.cssPosition=="relative"){var a=this.currentItem.position();return{top:a.top-(parseInt(this.helper.css("top"),10)||0)+this.scrollParent.scrollTop(),left:a.left-(parseInt(this.helper.css("left"),10)||0)+this.scrollParent.scrollLeft()}}return{top:0,left:0}},_cacheMargins:function(){this.margins={left:parseInt(this.currentItem.css("marginLeft"),10)||0,top:parseInt(this.currentItem.css("marginTop"),10)||0}},_cacheHelperProportions:function(){this.helperProportions={width:this.helper.outerWidth(),height:this.helper.outerHeight()}},_setContainment:function(){var b=this.options;b.containment=="parent"&&(b.containment=this.helper[0].parentNode);if(b.containment=="document"||b.containment=="window")this.containment=[0-this.offset.relative.left-this.offset.parent.left,0-this.offset.relative.top-this.offset.parent.top,a(b.containment=="document"?document:window).width()-this.helperProportions.width-this.margins.left,(a(b.containment=="document"?document:window).height()||document.body.parentNode.scrollHeight)-this.helperProportions.height-this.margins.top];if(!/^(document|window|parent)$/.test(b.containment)){var c=a(b.containment)[0],d=a(b.containment).offset(),e=a(c).css("overflow")!="hidden";this.containment=[d.left+(parseInt(a(c).css("borderLeftWidth"),10)||0)+(parseInt(a(c).css("paddingLeft"),10)||0)-this.margins.left,d.top+(parseInt(a(c).css("borderTopWidth"),10)||0)+(parseInt(a(c).css("paddingTop"),10)||0)-this.margins.top,d.left+(e?Math.max(c.scrollWidth,c.offsetWidth):c.offsetWidth)-(parseInt(a(c).css("borderLeftWidth"),10)||0)-(parseInt(a(c).css("paddingRight"),10)||0)-this.helperProportions.width-this.margins.left,d.top+(e?Math.max(c.scrollHeight,c.offsetHeight):c.offsetHeight)-(parseInt(a(c).css("borderTopWidth"),10)||0)-(parseInt(a(c).css("paddingBottom"),10)||0)-this.helperProportions.height-this.margins.top]}},_convertPositionTo:function(b,c){c||(c=this.position);var d=b=="absolute"?1:-1,e=this.options,f=this.cssPosition=="absolute"&&(this.scrollParent[0]==document||!a.ui.contains(this.scrollParent[0],this.offsetParent[0]))?this.offsetParent:this.scrollParent,g=/(html|body)/i.test(f[0].tagName);return{top:c.top+this.offset.relative.top*d+this.offset.parent.top*d-(a.browser.safari&&this.cssPosition=="fixed"?0:(this.cssPosition=="fixed"?-this.scrollParent.scrollTop():g?0:f.scrollTop())*d),left:c.left+this.offset.relative.left*d+this.offset.parent.left*d-(a.browser.safari&&this.cssPosition=="fixed"?0:(this.cssPosition=="fixed"?-this.scrollParent.scrollLeft():g?0:f.scrollLeft())*d)}},_generatePosition:function(b){var c=this.options,d=this.cssPosition=="absolute"&&(this.scrollParent[0]==document||!a.ui.contains(this.scrollParent[0],this.offsetParent[0]))?this.offsetParent:this.scrollParent,e=/(html|body)/i.test(d[0].tagName);this.cssPosition=="relative"&&(this.scrollParent[0]==document||this.scrollParent[0]==this.offsetParent[0])&&(this.offset.relative=this._getRelativeOffset());var f=b.pageX,g=b.pageY;if(this.originalPosition){this.containment&&(b.pageX-this.offset.click.left<this.containment[0]&&(f=this.containment[0]+this.offset.click.left),b.pageY-this.offset.click.top<this.containment[1]&&(g=this.containment[1]+this.offset.click.top),b.pageX-this.offset.click.left>this.containment[2]&&(f=this.containment[2]+this.offset.click.left),b.pageY-this.offset.click.top>this.containment[3]&&(g=this.containment[3]+this.offset.click.top));if(c.grid){var h=this.originalPageY+Math.round((g-this.originalPageY)/c.grid[1])*c.grid[1];g=this.containment?h-this.offset.click.top<this.containment[1]||h-this.offset.click.top>this.containment[3]?h-this.offset.click.top<this.containment[1]?h+c.grid[1]:h-c.grid[1]:h:h;var i=this.originalPageX+Math.round((f-this.originalPageX)/c.grid[0])*c.grid[0];f=this.containment?i-this.offset.click.left<this.containment[0]||i-this.offset.click.left>this.containment[2]?i-this.offset.click.left<this.containment[0]?i+c.grid[0]:i-c.grid[0]:i:i}}return{top:g-this.offset.click.top-this.offset.relative.top-this.offset.parent.top+(a.browser.safari&&this.cssPosition=="fixed"?0:this.cssPosition=="fixed"?-this.scrollParent.scrollTop():e?0:d.scrollTop()),left:f-this.offset.click.left-this.offset.relative.left-this.offset.parent.left+(a.browser.safari&&this.cssPosition=="fixed"?0:this.cssPosition=="fixed"?-this.scrollParent.scrollLeft():e?0:d.scrollLeft())}},_rearrange:function(a,b,c,d){c?c[0].appendChild(this.placeholder[0]):b.item[0].parentNode.insertBefore(this.placeholder[0],this.direction=="down"?b.item[0]:b.item[0].nextSibling),this.counter=this.counter?++this.counter:1;var e=this,f=this.counter;window.setTimeout(function(){f==e.counter&&e.refreshPositions(!d)},0)},_clear:function(b,c){this.reverting=!1;var d=[],e=this;!this._noFinalSort&&this.currentItem.parent().length&&this.placeholder.before(this.currentItem),this._noFinalSort=null;if(this.helper[0]==this.currentItem[0]){for(var f in this._storedCSS)if(this._storedCSS[f]=="auto"||this._storedCSS[f]=="static")this._storedCSS[f]="";this.currentItem.css(this._storedCSS).removeClass("ui-sortable-helper")}else this.currentItem.show();this.fromOutside&&!c&&d.push(function(a){this._trigger("receive",a,this._uiHash(this.fromOutside))}),(this.fromOutside||this.domPosition.prev!=this.currentItem.prev().not(".ui-sortable-helper")[0]||this.domPosition.parent!=this.currentItem.parent()[0])&&!c&&d.push(function(a){this._trigger("update",a,this._uiHash())});if(!a.ui.contains(this.element[0],this.currentItem[0])){c||d.push(function(a){this._trigger("remove",a,this._uiHash())});for(var f=this.containers.length-1;f>=0;f--)a.ui.contains(this.containers[f].element[0],this.currentItem[0])&&!c&&(d.push(function(a){return function(b){a._trigger("receive",b,this._uiHash(this))}}.call(this,this.containers[f])),d.push(function(a){return function(b){a._trigger("update",b,this._uiHash(this))}}.call(this,this.containers[f])))}for(var f=this.containers.length-1;f>=0;f--)c||d.push(function(a){return function(b){a._trigger("deactivate",b,this._uiHash(this))}}.call(this,this.containers[f])),this.containers[f].containerCache.over&&(d.push(function(a){return function(b){a._trigger("out",b,this._uiHash(this))}}.call(this,this.containers[f])),this.containers[f].containerCache.over=0);this._storedCursor&&a("body").css("cursor",this._storedCursor),this._storedOpacity&&this.helper.css("opacity",this._storedOpacity),this._storedZIndex&&this.helper.css("zIndex",this._storedZIndex=="auto"?"":this._storedZIndex),this.dragging=!1;if(this.cancelHelperRemoval){if(!c){this._trigger("beforeStop",b,this._uiHash());for(var f=0;f<d.length;f++)d[f].call(this,b);this._trigger("stop",b,this._uiHash())}return this.fromOutside=!1,!1}c||this._trigger("beforeStop",b,this._uiHash()),this.placeholder[0].parentNode.removeChild(this.placeholder[0]),this.helper[0]!=this.currentItem[0]&&this.helper.remove(),this.helper=null;if(!c){for(var f=0;f<d.length;f++)d[f].call(this,b);this._trigger("stop",b,this._uiHash())}return this.fromOutside=!1,!0},_trigger:function(){a.Widget.prototype._trigger.apply(this,arguments)===!1&&this.cancel()},_uiHash:function(b){var c=b||this;return{helper:c.helper,placeholder:c.placeholder||a([]),position:c.position,originalPosition:c.originalPosition,offset:c.positionAbs,item:c.currentItem,sender:b?b.element:null}}}),a.extend(a.ui.sortable,{version:"1.8.23"})})(jQuery);;/*! jQuery UI - v1.8.23 - 2012-08-15
    --* https://github.com/jquery/jquery-ui
    --* Includes: jquery.ui.accordion.js
    --* Copyright (c) 2012 AUTHORS.txt; Licensed MIT, GPL */
    --(function(a,b){a.widget("ui.accordion",{options:{active:0,animated:"slide",autoHeight:!0,clearStyle:!1,collapsible:!1,event:"click",fillSpace:!1,header:"> li > :first-child,> :not(li):even",icons:{header:"ui-icon-triangle-1-e",headerSelected:"ui-icon-triangle-1-s"},navigation:!1,navigationFilter:function(){return this.href.toLowerCase()===location.href.toLowerCase()}},_create:function(){var b=this,c=b.options;b.running=0,b.element.addClass("ui-accordion ui-widget ui-helper-reset").children("li").addClass("ui-accordion-li-fix"),b.headers=b.element.find(c.header).addClass("ui-accordion-header ui-helper-reset ui-state-default ui-corner-all").bind("mouseenter.accordion",function(){if(c.disabled)return;a(this).addClass("ui-state-hover")}).bind("mouseleave.accordion",function(){if(c.disabled)return;a(this).removeClass("ui-state-hover")}).bind("focus.accordion",function(){if(c.disabled)return;a(this).addClass("ui-state-focus")}).bind("blur.accordion",function(){if(c.disabled)return;a(this).removeClass("ui-state-focus")}),b.headers.next().addClass("ui-accordion-content ui-helper-reset ui-widget-content ui-corner-bottom");if(c.navigation){var d=b.element.find("a").filter(c.navigationFilter).eq(0);if(d.length){var e=d.closest(".ui-accordion-header");e.length?b.active=e:b.active=d.closest(".ui-accordion-content").prev()}}b.active=b._findActive(b.active||c.active).addClass("ui-state-default ui-state-active").toggleClass("ui-corner-all").toggleClass("ui-corner-top"),b.active.next().addClass("ui-accordion-content-active"),b._createIcons(),b.resize(),b.element.attr("role","tablist"),b.headers.attr("role","tab").bind("keydown.accordion",function(a){return b._keydown(a)}).next().attr("role","tabpanel"),b.headers.not(b.active||"").attr({"aria-expanded":"false","aria-selected":"false",tabIndex:-1}).next().hide(),b.active.length?b.active.attr({"aria-expanded":"true","aria-selected":"true",tabIndex:0}):b.headers.eq(0).attr("tabIndex",0),a.browser.safari||b.headers.find("a").attr("tabIndex",-1),c.event&&b.headers.bind(c.event.split(" ").join(".accordion ")+".accordion",function(a){b._clickHandler.call(b,a,this),a.preventDefault()})},_createIcons:function(){var b=this.options;b.icons&&(a("<span></span>").addClass("ui-icon "+b.icons.header).prependTo(this.headers),this.active.children(".ui-icon").toggleClass(b.icons.header).toggleClass(b.icons.headerSelected),this.element.addClass("ui-accordion-icons"))},_destroyIcons:function(){this.headers.children(".ui-icon").remove(),this.element.removeClass("ui-accordion-icons")},destroy:function(){var b=this.options;this.element.removeClass("ui-accordion ui-widget ui-helper-reset").removeAttr("role"),this.headers.unbind(".accordion").removeClass("ui-accordion-header ui-accordion-disabled ui-helper-reset ui-state-default ui-corner-all ui-state-active ui-state-disabled ui-corner-top").removeAttr("role").removeAttr("aria-expanded").removeAttr("aria-selected").removeAttr("tabIndex"),this.headers.find("a").removeAttr("tabIndex"),this._destroyIcons();var c=this.headers.next().css("display","").removeAttr("role").removeClass("ui-helper-reset ui-widget-content ui-corner-bottom ui-accordion-content ui-accordion-content-active ui-accordion-disabled ui-state-disabled");return(b.autoHeight||b.fillHeight)&&c.css("height",""),a.Widget.prototype.destroy.call(this)},_setOption:function(b,c){a.Widget.prototype._setOption.apply(this,arguments),b=="active"&&this.activate(c),b=="icons"&&(this._destroyIcons(),c&&this._createIcons()),b=="disabled"&&this.headers.add(this.headers.next())[c?"addClass":"removeClass"]("ui-accordion-disabled ui-state-disabled")},_keydown:function(b){if(this.options.disabled||b.altKey||b.ctrlKey)return;var c=a.ui.keyCode,d=this.headers.length,e=this.headers.index(b.target),f=!1;switch(b.keyCode){case c.RIGHT:case c.DOWN:f=this.headers[(e+1)%d];break;case c.LEFT:case c.UP:f=this.headers[(e-1+d)%d];break;case c.SPACE:case c.ENTER:this._clickHandler({target:b.target},b.target),b.preventDefault()}return f?(a(b.target).attr("tabIndex",-1),a(f).attr("tabIndex",0),f.focus(),!1):!0},resize:function(){var b=this.options,c;if(b.fillSpace){if(a.browser.msie){var d=this.element.parent().css("overflow");this.element.parent().css("overflow","hidden")}c=this.element.parent().height(),a.browser.msie&&this.element.parent().css("overflow",d),this.headers.each(function(){c-=a(this).outerHeight(!0)}),this.headers.next().each(function(){a(this).height(Math.max(0,c-a(this).innerHeight()+a(this).height()))}).css("overflow","auto")}else b.autoHeight&&(c=0,this.headers.next().each(function(){c=Math.max(c,a(this).height("").height())}).height(c));return this},activate:function(a){this.options.active=a;var b=this._findActive(a)[0];return this._clickHandler({target:b},b),this},_findActive:function(b){return b?typeof b=="number"?this.headers.filter(":eq("+b+")"):this.headers.not(this.headers.not(b)):b===!1?a([]):this.headers.filter(":eq(0)")},_clickHandler:function(b,c){var d=this.options;if(d.disabled)return;if(!b.target){if(!d.collapsible)return;this.active.removeClass("ui-state-active ui-corner-top").addClass("ui-state-default ui-corner-all").children(".ui-icon").removeClass(d.icons.headerSelected).addClass(d.icons.header),this.active.next().addClass("ui-accordion-content-active");var e=this.active.next(),f={options:d,newHeader:a([]),oldHeader:d.active,newContent:a([]),oldContent:e},g=this.active=a([]);this._toggle(g,e,f);return}var h=a(b.currentTarget||c),i=h[0]===this.active[0];d.active=d.collapsible&&i?!1:this.headers.index(h);if(this.running||!d.collapsible&&i)return;var j=this.active,g=h.next(),e=this.active.next(),f={options:d,newHeader:i&&d.collapsible?a([]):h,oldHeader:this.active,newContent:i&&d.collapsible?a([]):g,oldContent:e},k=this.headers.index(this.active[0])>this.headers.index(h[0]);this.active=i?a([]):h,this._toggle(g,e,f,i,k),j.removeClass("ui-state-active ui-corner-top").addClass("ui-state-default ui-corner-all").children(".ui-icon").removeClass(d.icons.headerSelected).addClass(d.icons.header),i||(h.removeClass("ui-state-default ui-corner-all").addClass("ui-state-active ui-corner-top").children(".ui-icon").removeClass(d.icons.header).addClass(d.icons.headerSelected),h.next().addClass("ui-accordion-content-active"));return},_toggle:function(b,c,d,e,f){var g=this,h=g.options;g.toShow=b,g.toHide=c,g.data=d;var i=function(){if(!g)return;return g._completed.apply(g,arguments)};g._trigger("changestart",null,g.data),g.running=c.size()===0?b.size():c.size();if(h.animated){var j={};h.collapsible&&e?j={toShow:a([]),toHide:c,complete:i,down:f,autoHeight:h.autoHeight||h.fillSpace}:j={toShow:b,toHide:c,complete:i,down:f,autoHeight:h.autoHeight||h.fillSpace},h.proxied||(h.proxied=h.animated),h.proxiedDuration||(h.proxiedDuration=h.duration),h.animated=a.isFunction(h.proxied)?h.proxied(j):h.proxied,h.duration=a.isFunction(h.proxiedDuration)?h.proxiedDuration(j):h.proxiedDuration;var k=a.ui.accordion.animations,l=h.duration,m=h.animated;m&&!k[m]&&!a.easing[m]&&(m="slide"),k[m]||(k[m]=function(a){this.slide(a,{easing:m,duration:l||700})}),k[m](j)}else h.collapsible&&e?b.toggle():(c.hide(),b.show()),i(!0);c.prev().attr({"aria-expanded":"false","aria-selected":"false",tabIndex:-1}).blur(),b.prev().attr({"aria-expanded":"true","aria-selected":"true",tabIndex:0}).focus()},_completed:function(a){this.running=a?0:--this.running;if(this.running)return;this.options.clearStyle&&this.toShow.add(this.toHide).css({height:"",overflow:""}),this.toHide.removeClass("ui-accordion-content-active"),this.toHide.length&&(this.toHide.parent()[0].className=this.toHide.parent()[0].className),this._trigger("change",null,this.data)}}),a.extend(a.ui.accordion,{version:"1.8.23",animations:{slide:function(b,c){b=a.extend({easing:"swing",duration:300},b,c);if(!b.toHide.size()){b.toShow.animate({height:"show",paddingTop:"show",paddingBottom:"show"},b);return}if(!b.toShow.size()){b.toHide.animate({height:"hide",paddingTop:"hide",paddingBottom:"hide"},b);return}var d=b.toShow.css("overflow"),e=0,f={},g={},h=["height","paddingTop","paddingBottom"],i,j=b.toShow;i=j[0].style.width,j.width(j.parent().width()-parseFloat(j.css("paddingLeft"))-parseFloat(j.css("paddingRight"))-(parseFloat(j.css("borderLeftWidth"))||0)-(parseFloat(j.css("borderRightWidth"))||0)),a.each(h,function(c,d){g[d]="hide";var e=(""+a.css(b.toShow[0],d)).match(/^([\d+-.]+)(.*)$/);f[d]={value:e[1],unit:e[2]||"px"}}),b.toShow.css({height:0,overflow:"hidden"}).show(),b.toHide.filter(":hidden").each(b.complete).end().filter(":visible").animate(g,{step:function(a,c){c.prop=="height"&&(e=c.end-c.start===0?0:(c.now-c.start)/(c.end-c.start)),b.toShow[0].style[c.prop]=e*f[c.prop].value+f[c.prop].unit},duration:b.duration,easing:b.easing,complete:function(){b.autoHeight||b.toShow.css("height",""),b.toShow.css({width:i,overflow:d}),b.complete()}})},bounceslide:function(a){this.slide(a,{easing:a.down?"easeOutBounce":"swing",duration:a.down?1e3:200})}}})})(jQuery);;/*! jQuery UI - v1.8.23 - 2012-08-15
    --* https://github.com/jquery/jquery-ui
    --* Includes: jquery.ui.autocomplete.js
    --* Copyright (c) 2012 AUTHORS.txt; Licensed MIT, GPL */
    --(function(a,b){var c=0;a.widget("ui.autocomplete",{options:{appendTo:"body",autoFocus:!1,delay:300,minLength:1,position:{my:"left top",at:"left bottom",collision:"none"},source:null},pending:0,_create:function(){var b=this,c=this.element[0].ownerDocument,d;this.isMultiLine=this.element.is("textarea"),this.element.addClass("ui-autocomplete-input").attr("autocomplete","off").attr({role:"textbox","aria-autocomplete":"list","aria-haspopup":"true"}).bind("keydown.autocomplete",function(c){if(b.options.disabled||b.element.propAttr("readOnly"))return;d=!1;var e=a.ui.keyCode;switch(c.keyCode){case e.PAGE_UP:b._move("previousPage",c);break;case e.PAGE_DOWN:b._move("nextPage",c);break;case e.UP:b._keyEvent("previous",c);break;case e.DOWN:b._keyEvent("next",c);break;case e.ENTER:case e.NUMPAD_ENTER:b.menu.active&&(d=!0,c.preventDefault());case e.TAB:if(!b.menu.active)return;b.menu.select(c);break;case e.ESCAPE:b.element.val(b.term),b.close(c);break;default:clearTimeout(b.searching),b.searching=setTimeout(function(){b.term!=b.element.val()&&(b.selectedItem=null,b.search(null,c))},b.options.delay)}}).bind("keypress.autocomplete",function(a){d&&(d=!1,a.preventDefault())}).bind("focus.autocomplete",function(){if(b.options.disabled)return;b.selectedItem=null,b.previous=b.element.val()}).bind("blur.autocomplete",function(a){if(b.options.disabled)return;clearTimeout(b.searching),b.closing=setTimeout(function(){b.close(a),b._change(a)},150)}),this._initSource(),this.menu=a("<ul></ul>").addClass("ui-autocomplete").appendTo(a(this.options.appendTo||"body",c)[0]).mousedown(function(c){var d=b.menu.element[0];a(c.target).closest(".ui-menu-item").length||setTimeout(function(){a(document).one("mousedown",function(c){c.target!==b.element[0]&&c.target!==d&&!a.ui.contains(d,c.target)&&b.close()})},1),setTimeout(function(){clearTimeout(b.closing)},13)}).menu({focus:function(a,c){var d=c.item.data("item.autocomplete");!1!==b._trigger("focus",a,{item:d})&&/^key/.test(a.originalEvent.type)&&b.element.val(d.value)},selected:function(a,d){var e=d.item.data("item.autocomplete"),f=b.previous;b.element[0]!==c.activeElement&&(b.element.focus(),b.previous=f,setTimeout(function(){b.previous=f,b.selectedItem=e},1)),!1!==b._trigger("select",a,{item:e})&&b.element.val(e.value),b.term=b.element.val(),b.close(a),b.selectedItem=e},blur:function(a,c){b.menu.element.is(":visible")&&b.element.val()!==b.term&&b.element.val(b.term)}}).zIndex(this.element.zIndex()+1).css({top:0,left:0}).hide().data("menu"),a.fn.bgiframe&&this.menu.element.bgiframe(),b.beforeunloadHandler=function(){b.element.removeAttr("autocomplete")},a(window).bind("beforeunload",b.beforeunloadHandler)},destroy:function(){this.element.removeClass("ui-autocomplete-input").removeAttr("autocomplete").removeAttr("role").removeAttr("aria-autocomplete").removeAttr("aria-haspopup"),this.menu.element.remove(),a(window).unbind("beforeunload",this.beforeunloadHandler),a.Widget.prototype.destroy.call(this)},_setOption:function(b,c){a.Widget.prototype._setOption.apply(this,arguments),b==="source"&&this._initSource(),b==="appendTo"&&this.menu.element.appendTo(a(c||"body",this.element[0].ownerDocument)[0]),b==="disabled"&&c&&this.xhr&&this.xhr.abort()},_initSource:function(){var b=this,c,d;a.isArray(this.options.source)?(c=this.options.source,this.source=function(b,d){d(a.ui.autocomplete.filter(c,b.term))}):typeof this.options.source=="string"?(d=this.options.source,this.source=function(c,e){b.xhr&&b.xhr.abort(),b.xhr=a.ajax({url:d,data:c,dataType:"json",success:function(a,b){e(a)},error:function(){e([])}})}):this.source=this.options.source},search:function(a,b){a=a!=null?a:this.element.val(),this.term=this.element.val();if(a.length<this.options.minLength)return this.close(b);clearTimeout(this.closing);if(this._trigger("search",b)===!1)return;return this._search(a)},_search:function(a){this.pending++,this.element.addClass("ui-autocomplete-loading"),this.source({term:a},this._response())},_response:function(){var a=this,b=++c;return function(d){b===c&&a.__response(d),a.pending--,a.pending||a.element.removeClass("ui-autocomplete-loading")}},__response:function(a){!this.options.disabled&&a&&a.length?(a=this._normalize(a),this._suggest(a),this._trigger("open")):this.close()},close:function(a){clearTimeout(this.closing),this.menu.element.is(":visible")&&(this.menu.element.hide(),this.menu.deactivate(),this._trigger("close",a))},_change:function(a){this.previous!==this.element.val()&&this._trigger("change",a,{item:this.selectedItem})},_normalize:function(b){return b.length&&b[0].label&&b[0].value?b:a.map(b,function(b){return typeof b=="string"?{label:b,value:b}:a.extend({label:b.label||b.value,value:b.value||b.label},b)})},_suggest:function(b){var c=this.menu.element.empty().zIndex(this.element.zIndex()+1);this._renderMenu(c,b),this.menu.deactivate(),this.menu.refresh(),c.show(),this._resizeMenu(),c.position(a.extend({of:this.element},this.options.position)),this.options.autoFocus&&this.menu.next(new a.Event("mouseover"))},_resizeMenu:function(){var a=this.menu.element;a.outerWidth(Math.max(a.width("").outerWidth()+1,this.element.outerWidth()))},_renderMenu:function(b,c){var d=this;a.each(c,function(a,c){d._renderItem(b,c)})},_renderItem:function(b,c){return a("<li></li>").data("item.autocomplete",c).append(a("<a></a>").text(c.label)).appendTo(b)},_move:function(a,b){if(!this.menu.element.is(":visible")){this.search(null,b);return}if(this.menu.first()&&/^previous/.test(a)||this.menu.last()&&/^next/.test(a)){this.element.val(this.term),this.menu.deactivate();return}this.menu[a](b)},widget:function(){return this.menu.element},_keyEvent:function(a,b){if(!this.isMultiLine||this.menu.element.is(":visible"))this._move(a,b),b.preventDefault()}}),a.extend(a.ui.autocomplete,{escapeRegex:function(a){return a.replace(/[-[\]{}()*+?.,\\^$|#\s]/g,"\\$&")},filter:function(b,c){var d=new RegExp(a.ui.autocomplete.escapeRegex(c),"i");return a.grep(b,function(a){return d.test(a.label||a.value||a)})}})})(jQuery),function(a){a.widget("ui.menu",{_create:function(){var b=this;this.element.addClass("ui-menu ui-widget ui-widget-content ui-corner-all").attr({role:"listbox","aria-activedescendant":"ui-active-menuitem"}).click(function(c){if(!a(c.target).closest(".ui-menu-item a").length)return;c.preventDefault(),b.select(c)}),this.refresh()},refresh:function(){var b=this,c=this.element.children("li:not(.ui-menu-item):has(a)").addClass("ui-menu-item").attr("role","menuitem");c.children("a").addClass("ui-corner-all").attr("tabindex",-1).mouseenter(function(c){b.activate(c,a(this).parent())}).mouseleave(function(){b.deactivate()})},activate:function(a,b){this.deactivate();if(this.hasScroll()){var c=b.offset().top-this.element.offset().top,d=this.element.scrollTop(),e=this.element.height();c<0?this.element.scrollTop(d+c):c>=e&&this.element.scrollTop(d+c-e+b.height())}this.active=b.eq(0).children("a").addClass("ui-state-hover").attr("id","ui-active-menuitem").end(),this._trigger("focus",a,{item:b})},deactivate:function(){if(!this.active)return;this.active.children("a").removeClass("ui-state-hover").removeAttr("id"),this._trigger("blur"),this.active=null},next:function(a){this.move("next",".ui-menu-item:first",a)},previous:function(a){this.move("prev",".ui-menu-item:last",a)},first:function(){return this.active&&!this.active.prevAll(".ui-menu-item").length},last:function(){return this.active&&!this.active.nextAll(".ui-menu-item").length},move:function(a,b,c){if(!this.active){this.activate(c,this.element.children(b));return}var d=this.active[a+"All"](".ui-menu-item").eq(0);d.length?this.activate(c,d):this.activate(c,this.element.children(b))},nextPage:function(b){if(this.hasScroll()){if(!this.active||this.last()){this.activate(b,this.element.children(".ui-menu-item:first"));return}var c=this.active.offset().top,d=this.element.height(),e=this.element.children(".ui-menu-item").filter(function(){var b=a(this).offset().top-c-d+a(this).height();return b<10&&b>-10});e.length||(e=this.element.children(".ui-menu-item:last")),this.activate(b,e)}else this.activate(b,this.element.children(".ui-menu-item").filter(!this.active||this.last()?":first":":last"))},previousPage:function(b){if(this.hasScroll()){if(!this.active||this.first()){this.activate(b,this.element.children(".ui-menu-item:last"));return}var c=this.active.offset().top,d=this.element.height(),e=this.element.children(".ui-menu-item").filter(function(){var b=a(this).offset().top-c+d-a(this).height();return b<10&&b>-10});e.length||(e=this.element.children(".ui-menu-item:first")),this.activate(b,e)}else this.activate(b,this.element.children(".ui-menu-item").filter(!this.active||this.first()?":last":":first"))},hasScroll:function(){return this.element.height()<this.element[a.fn.prop?"prop":"attr"]("scrollHeight")},select:function(a){this._trigger("selected",a,{item:this.active})}})}(jQuery);;/*! jQuery UI - v1.8.23 - 2012-08-15
    --* https://github.com/jquery/jquery-ui
    --* Includes: jquery.ui.button.js
    --* Copyright (c) 2012 AUTHORS.txt; Licensed MIT, GPL */
    --(function(a,b){var c,d,e,f,g="ui-button ui-widget ui-state-default ui-corner-all",h="ui-state-hover ui-state-active ",i="ui-button-icons-only ui-button-icon-only ui-button-text-icons ui-button-text-icon-primary ui-button-text-icon-secondary ui-button-text-only",j=function(){var b=a(this).find(":ui-button");setTimeout(function(){b.button("refresh")},1)},k=function(b){var c=b.name,d=b.form,e=a([]);return c&&(d?e=a(d).find("[name='"+c+"']"):e=a("[name='"+c+"']",b.ownerDocument).filter(function(){return!this.form})),e};a.widget("ui.button",{options:{disabled:null,text:!0,label:null,icons:{primary:null,secondary:null}},_create:function(){this.element.closest("form").unbind("reset.button").bind("reset.button",j),typeof this.options.disabled!="boolean"?this.options.disabled=!!this.element.propAttr("disabled"):this.element.propAttr("disabled",this.options.disabled),this._determineButtonType(),this.hasTitle=!!this.buttonElement.attr("title");var b=this,h=this.options,i=this.type==="checkbox"||this.type==="radio",l="ui-state-hover"+(i?"":" ui-state-active"),m="ui-state-focus";h.label===null&&(h.label=this.buttonElement.html()),this.buttonElement.addClass(g).attr("role","button").bind("mouseenter.button",function(){if(h.disabled)return;a(this).addClass("ui-state-hover"),this===c&&a(this).addClass("ui-state-active")}).bind("mouseleave.button",function(){if(h.disabled)return;a(this).removeClass(l)}).bind("click.button",function(a){h.disabled&&(a.preventDefault(),a.stopImmediatePropagation())}),this.element.bind("focus.button",function(){b.buttonElement.addClass(m)}).bind("blur.button",function(){b.buttonElement.removeClass(m)}),i&&(this.element.bind("change.button",function(){if(f)return;b.refresh()}),this.buttonElement.bind("mousedown.button",function(a){if(h.disabled)return;f=!1,d=a.pageX,e=a.pageY}).bind("mouseup.button",function(a){if(h.disabled)return;if(d!==a.pageX||e!==a.pageY)f=!0})),this.type==="checkbox"?this.buttonElement.bind("click.button",function(){if(h.disabled||f)return!1;a(this).toggleClass("ui-state-active"),b.buttonElement.attr("aria-pressed",b.element[0].checked)}):this.type==="radio"?this.buttonElement.bind("click.button",function(){if(h.disabled||f)return!1;a(this).addClass("ui-state-active"),b.buttonElement.attr("aria-pressed","true");var c=b.element[0];k(c).not(c).map(function(){return a(this).button("widget")[0]}).removeClass("ui-state-active").attr("aria-pressed","false")}):(this.buttonElement.bind("mousedown.button",function(){if(h.disabled)return!1;a(this).addClass("ui-state-active"),c=this,a(document).one("mouseup",function(){c=null})}).bind("mouseup.button",function(){if(h.disabled)return!1;a(this).removeClass("ui-state-active")}).bind("keydown.button",function(b){if(h.disabled)return!1;(b.keyCode==a.ui.keyCode.SPACE||b.keyCode==a.ui.keyCode.ENTER)&&a(this).addClass("ui-state-active")}).bind("keyup.button",function(){a(this).removeClass("ui-state-active")}),this.buttonElement.is("a")&&this.buttonElement.keyup(function(b){b.keyCode===a.ui.keyCode.SPACE&&a(this).click()})),this._setOption("disabled",h.disabled),this._resetButton()},_determineButtonType:function(){this.element.is(":checkbox")?this.type="checkbox":this.element.is(":radio")?this.type="radio":this.element.is("input")?this.type="input":this.type="button";if(this.type==="checkbox"||this.type==="radio"){var a=this.element.parents().filter(":last"),b="label[for='"+this.element.attr("id")+"']";this.buttonElement=a.find(b),this.buttonElement.length||(a=a.length?a.siblings():this.element.siblings(),this.buttonElement=a.filter(b),this.buttonElement.length||(this.buttonElement=a.find(b))),this.element.addClass("ui-helper-hidden-accessible");var c=this.element.is(":checked");c&&this.buttonElement.addClass("ui-state-active"),this.buttonElement.attr("aria-pressed",c)}else this.buttonElement=this.element},widget:function(){return this.buttonElement},destroy:function(){this.element.removeClass("ui-helper-hidden-accessible"),this.buttonElement.removeClass(g+" "+h+" "+i).removeAttr("role").removeAttr("aria-pressed").html(this.buttonElement.find(".ui-button-text").html()),this.hasTitle||this.buttonElement.removeAttr("title"),a.Widget.prototype.destroy.call(this)},_setOption:function(b,c){a.Widget.prototype._setOption.apply(this,arguments);if(b==="disabled"){c?this.element.propAttr("disabled",!0):this.element.propAttr("disabled",!1);return}this._resetButton()},refresh:function(){var b=this.element.is(":disabled");b!==this.options.disabled&&this._setOption("disabled",b),this.type==="radio"?k(this.element[0]).each(function(){a(this).is(":checked")?a(this).button("widget").addClass("ui-state-active").attr("aria-pressed","true"):a(this).button("widget").removeClass("ui-state-active").attr("aria-pressed","false")}):this.type==="checkbox"&&(this.element.is(":checked")?this.buttonElement.addClass("ui-state-active").attr("aria-pressed","true"):this.buttonElement.removeClass("ui-state-active").attr("aria-pressed","false"))},_resetButton:function(){if(this.type==="input"){this.options.label&&this.element.val(this.options.label);return}var b=this.buttonElement.removeClass(i),c=a("<span></span>",this.element[0].ownerDocument).addClass("ui-button-text").html(this.options.label).appendTo(b.empty()).text(),d=this.options.icons,e=d.primary&&d.secondary,f=[];d.primary||d.secondary?(this.options.text&&f.push("ui-button-text-icon"+(e?"s":d.primary?"-primary":"-secondary")),d.primary&&b.prepend("<span class='ui-button-icon-primary ui-icon "+d.primary+"'></span>"),d.secondary&&b.append("<span class='ui-button-icon-secondary ui-icon "+d.secondary+"'></span>"),this.options.text||(f.push(e?"ui-button-icons-only":"ui-button-icon-only"),this.hasTitle||b.attr("title",c))):f.push("ui-button-text-only"),b.addClass(f.join(" "))}}),a.widget("ui.buttonset",{options:{items:":button, :submit, :reset, :checkbox, :radio, a, :data(button)"},_create:function(){this.element.addClass("ui-buttonset")},_init:function(){this.refresh()},_setOption:function(b,c){b==="disabled"&&this.buttons.button("option",b,c),a.Widget.prototype._setOption.apply(this,arguments)},refresh:function(){var b=this.element.css("direction")==="rtl";this.buttons=this.element.find(this.options.items).filter(":ui-button").button("refresh").end().not(":ui-button").button().end().map(function(){return a(this).button("widget")[0]}).removeClass("ui-corner-all ui-corner-left ui-corner-right").filter(":first").addClass(b?"ui-corner-right":"ui-corner-left").end().filter(":last").addClass(b?"ui-corner-left":"ui-corner-right").end().end()},destroy:function(){this.element.removeClass("ui-buttonset"),this.buttons.map(function(){return a(this).button("widget")[0]}).removeClass("ui-corner-left ui-corner-right").end().button("destroy"),a.Widget.prototype.destroy.call(this)}})})(jQuery);;/*! jQuery UI - v1.8.23 - 2012-08-15
    --* https://github.com/jquery/jquery-ui
    --* Includes: jquery.ui.dialog.js
    --* Copyright (c) 2012 AUTHORS.txt; Licensed MIT, GPL */
    --(function(a,b){var c="ui-dialog ui-widget ui-widget-content ui-corner-all ",d={buttons:!0,height:!0,maxHeight:!0,maxWidth:!0,minHeight:!0,minWidth:!0,width:!0},e={maxHeight:!0,maxWidth:!0,minHeight:!0,minWidth:!0};a.widget("ui.dialog",{options:{autoOpen:!0,buttons:{},closeOnEscape:!0,closeText:"close",dialogClass:"",draggable:!0,hide:null,height:"auto",maxHeight:!1,maxWidth:!1,minHeight:150,minWidth:150,modal:!1,position:{my:"center",at:"center",collision:"fit",using:function(b){var c=a(this).css(b).offset().top;c<0&&a(this).css("top",b.top-c)}},resizable:!0,show:null,stack:!0,title:"",width:300,zIndex:1e3},_create:function(){this.originalTitle=this.element.attr("title"),typeof this.originalTitle!="string"&&(this.originalTitle=""),this.options.title=this.options.title||this.originalTitle;var b=this,d=b.options,e=d.title||"&#160;",f=a.ui.dialog.getTitleId(b.element),g=(b.uiDialog=a("<div></div>")).appendTo(document.body).hide().addClass(c+d.dialogClass).css({zIndex:d.zIndex}).attr("tabIndex",-1).css("outline",0).keydown(function(c){d.closeOnEscape&&!c.isDefaultPrevented()&&c.keyCode&&c.keyCode===a.ui.keyCode.ESCAPE&&(b.close(c),c.preventDefault())}).attr({role:"dialog","aria-labelledby":f}).mousedown(function(a){b.moveToTop(!1,a)}),h=b.element.show().removeAttr("title").addClass("ui-dialog-content ui-widget-content").appendTo(g),i=(b.uiDialogTitlebar=a("<div></div>")).addClass("ui-dialog-titlebar ui-widget-header ui-corner-all ui-helper-clearfix").prependTo(g),j=a('<a href="#"></a>').addClass("ui-dialog-titlebar-close ui-corner-all").attr("role","button").hover(function(){j.addClass("ui-state-hover")},function(){j.removeClass("ui-state-hover")}).focus(function(){j.addClass("ui-state-focus")}).blur(function(){j.removeClass("ui-state-focus")}).click(function(a){return b.close(a),!1}).appendTo(i),k=(b.uiDialogTitlebarCloseText=a("<span></span>")).addClass("ui-icon ui-icon-closethick").text(d.closeText).appendTo(j),l=a("<span></span>").addClass("ui-dialog-title").attr("id",f).html(e).prependTo(i);a.isFunction(d.beforeclose)&&!a.isFunction(d.beforeClose)&&(d.beforeClose=d.beforeclose),i.find("*").add(i).disableSelection(),d.draggable&&a.fn.draggable&&b._makeDraggable(),d.resizable&&a.fn.resizable&&b._makeResizable(),b._createButtons(d.buttons),b._isOpen=!1,a.fn.bgiframe&&g.bgiframe()},_init:function(){this.options.autoOpen&&this.open()},destroy:function(){var a=this;return a.overlay&&a.overlay.destroy(),a.uiDialog.hide(),a.element.unbind(".dialog").removeData("dialog").removeClass("ui-dialog-content ui-widget-content").hide().appendTo("body"),a.uiDialog.remove(),a.originalTitle&&a.element.attr("title",a.originalTitle),a},widget:function(){return this.uiDialog},close:function(b){var c=this,d,e;if(!1===c._trigger("beforeClose",b))return;return c.overlay&&c.overlay.destroy(),c.uiDialog.unbind("keypress.ui-dialog"),c._isOpen=!1,c.options.hide?c.uiDialog.hide(c.options.hide,function(){c._trigger("close",b)}):(c.uiDialog.hide(),c._trigger("close",b)),a.ui.dialog.overlay.resize(),c.options.modal&&(d=0,a(".ui-dialog").each(function(){this!==c.uiDialog[0]&&(e=a(this).css("z-index"),isNaN(e)||(d=Math.max(d,e)))}),a.ui.dialog.maxZ=d),c},isOpen:function(){return this._isOpen},moveToTop:function(b,c){var d=this,e=d.options,f;return e.modal&&!b||!e.stack&&!e.modal?d._trigger("focus",c):(e.zIndex>a.ui.dialog.maxZ&&(a.ui.dialog.maxZ=e.zIndex),d.overlay&&(a.ui.dialog.maxZ+=1,d.overlay.$el.css("z-index",a.ui.dialog.overlay.maxZ=a.ui.dialog.maxZ)),f={scrollTop:d.element.scrollTop(),scrollLeft:d.element.scrollLeft()},a.ui.dialog.maxZ+=1,d.uiDialog.css("z-index",a.ui.dialog.maxZ),d.element.attr(f),d._trigger("focus",c),d)},open:function(){if(this._isOpen)return;var b=this,c=b.options,d=b.uiDialog;return b.overlay=c.modal?new a.ui.dialog.overlay(b):null,b._size(),b._position(c.position),d.show(c.show),b.moveToTop(!0),c.modal&&d.bind("keydown.ui-dialog",function(b){if(b.keyCode!==a.ui.keyCode.TAB)return;var c=a(":tabbable",this),d=c.filter(":first"),e=c.filter(":last");if(b.target===e[0]&&!b.shiftKey)return d.focus(1),!1;if(b.target===d[0]&&b.shiftKey)return e.focus(1),!1}),a(b.element.find(":tabbable").get().concat(d.find(".ui-dialog-buttonpane :tabbable").get().concat(d.get()))).eq(0).focus(),b._isOpen=!0,b._trigger("open"),b},_createButtons:function(b){var c=this,d=!1,e=a("<div></div>").addClass("ui-dialog-buttonpane ui-widget-content ui-helper-clearfix"),f=a("<div></div>").addClass("ui-dialog-buttonset").appendTo(e);c.uiDialog.find(".ui-dialog-buttonpane").remove(),typeof b=="object"&&b!==null&&a.each(b,function(){return!(d=!0)}),d&&(a.each(b,function(b,d){d=a.isFunction(d)?{click:d,text:b}:d;var e=a('<button type="button"></button>').click(function(){d.click.apply(c.element[0],arguments)}).appendTo(f);a.each(d,function(a,b){if(a==="click")return;a in e?e[a](b):e.attr(a,b)}),a.fn.button&&e.button()}),e.appendTo(c.uiDialog))},_makeDraggable:function(){function f(a){return{position:a.position,offset:a.offset}}var b=this,c=b.options,d=a(document),e;b.uiDialog.draggable({cancel:".ui-dialog-content, .ui-dialog-titlebar-close",handle:".ui-dialog-titlebar",containment:"document",start:function(d,g){e=c.height==="auto"?"auto":a(this).height(),a(this).height(a(this).height()).addClass("ui-dialog-dragging"),b._trigger("dragStart",d,f(g))},drag:function(a,c){b._trigger("drag",a,f(c))},stop:function(g,h){c.position=[h.position.left-d.scrollLeft(),h.position.top-d.scrollTop()],a(this).removeClass("ui-dialog-dragging").height(e),b._trigger("dragStop",g,f(h)),a.ui.dialog.overlay.resize()}})},_makeResizable:function(c){function h(a){return{originalPosition:a.originalPosition,originalSize:a.originalSize,position:a.position,size:a.size}}c=c===b?this.options.resizable:c;var d=this,e=d.options,f=d.uiDialog.css("position"),g=typeof c=="string"?c:"n,e,s,w,se,sw,ne,nw";d.uiDialog.resizable({cancel:".ui-dialog-content",containment:"document",alsoResize:d.element,maxWidth:e.maxWidth,maxHeight:e.maxHeight,minWidth:e.minWidth,minHeight:d._minHeight(),handles:g,start:function(b,c){a(this).addClass("ui-dialog-resizing"),d._trigger("resizeStart",b,h(c))},resize:function(a,b){d._trigger("resize",a,h(b))},stop:function(b,c){a(this).removeClass("ui-dialog-resizing"),e.height=a(this).height(),e.width=a(this).width(),d._trigger("resizeStop",b,h(c)),a.ui.dialog.overlay.resize()}}).css("position",f).find(".ui-resizable-se").addClass("ui-icon ui-icon-grip-diagonal-se")},_minHeight:function(){var a=this.options;return a.height==="auto"?a.minHeight:Math.min(a.minHeight,a.height)},_position:function(b){var c=[],d=[0,0],e;if(b){if(typeof b=="string"||typeof b=="object"&&"0"in b)c=b.split?b.split(" "):[b[0],b[1]],c.length===1&&(c[1]=c[0]),a.each(["left","top"],function(a,b){+c[a]===c[a]&&(d[a]=c[a],c[a]=b)}),b={my:c.join(" "),at:c.join(" "),offset:d.join(" ")};b=a.extend({},a.ui.dialog.prototype.options.position,b)}else b=a.ui.dialog.prototype.options.position;e=this.uiDialog.is(":visible"),e||this.uiDialog.show(),this.uiDialog.css({top:0,left:0}).position(a.extend({of:window},b)),e||this.uiDialog.hide()},_setOptions:function(b){var c=this,f={},g=!1;a.each(b,function(a,b){c._setOption(a,b),a in d&&(g=!0),a in e&&(f[a]=b)}),g&&this._size(),this.uiDialog.is(":data(resizable)")&&this.uiDialog.resizable("option",f)},_setOption:function(b,d){var e=this,f=e.uiDialog;switch(b){case"beforeclose":b="beforeClose";break;case"buttons":e._createButtons(d);break;case"closeText":e.uiDialogTitlebarCloseText.text(""+d);break;case"dialogClass":f.removeClass(e.options.dialogClass).addClass(c+d);break;case"disabled":d?f.addClass("ui-dialog-disabled"):f.removeClass("ui-dialog-disabled");break;case"draggable":var g=f.is(":data(draggable)");g&&!d&&f.draggable("destroy"),!g&&d&&e._makeDraggable();break;case"position":e._position(d);break;case"resizable":var h=f.is(":data(resizable)");h&&!d&&f.resizable("destroy"),h&&typeof d=="string"&&f.resizable("option","handles",d),!h&&d!==!1&&e._makeResizable(d);break;case"title":a(".ui-dialog-title",e.uiDialogTitlebar).html(""+(d||"&#160;"))}a.Widget.prototype._setOption.apply(e,arguments)},_size:function(){var b=this.options,c,d,e=this.uiDialog.is(":visible");this.element.show().css({width:"auto",minHeight:0,height:0}),b.minWidth>b.width&&(b.width=b.minWidth),c=this.uiDialog.css({height:"auto",width:b.width}).height(),d=Math.max(0,b.minHeight-c);if(b.height==="auto")if(a.support.minHeight)this.element.css({minHeight:d,height:"auto"});else{this.uiDialog.show();var f=this.element.css("height","auto").height();e||this.uiDialog.hide(),this.element.height(Math.max(f,d))}else this.element.height(Math.max(b.height-c,0));this.uiDialog.is(":data(resizable)")&&this.uiDialog.resizable("option","minHeight",this._minHeight())}}),a.extend(a.ui.dialog,{version:"1.8.23",uuid:0,maxZ:0,getTitleId:function(a){var b=a.attr("id");return b||(this.uuid+=1,b=this.uuid),"ui-dialog-title-"+b},overlay:function(b){this.$el=a.ui.dialog.overlay.create(b)}}),a.extend(a.ui.dialog.overlay,{instances:[],oldInstances:[],maxZ:0,events:a.map("focus,mousedown,mouseup,keydown,keypress,click".split(","),function(a){return a+".dialog-overlay"}).join(" "),create:function(b){this.instances.length===0&&(setTimeout(function(){a.ui.dialog.overlay.instances.length&&a(document).bind(a.ui.dialog.overlay.events,function(b){if(a(b.target).zIndex()<a.ui.dialog.overlay.maxZ)return!1})},1),a(document).bind("keydown.dialog-overlay",function(c){b.options.closeOnEscape&&!c.isDefaultPrevented()&&c.keyCode&&c.keyCode===a.ui.keyCode.ESCAPE&&(b.close(c),c.preventDefault())}),a(window).bind("resize.dialog-overlay",a.ui.dialog.overlay.resize));var c=(this.oldInstances.pop()||a("<div></div>").addClass("ui-widget-overlay")).appendTo(document.body).css({width:this.width(),height:this.height()});return a.fn.bgiframe&&c.bgiframe(),this.instances.push(c),c},destroy:function(b){var c=a.inArray(b,this.instances);c!=-1&&this.oldInstances.push(this.instances.splice(c,1)[0]),this.instances.length===0&&a([document,window]).unbind(".dialog-overlay"),b.remove();var d=0;a.each(this.instances,function(){d=Math.max(d,this.css("z-index"))}),this.maxZ=d},height:function(){var b,c;return a.browser.msie&&a.browser.version<7?(b=Math.max(document.documentElement.scrollHeight,document.body.scrollHeight),c=Math.max(document.documentElement.offsetHeight,document.body.offsetHeight),b<c?a(window).height()+"px":b+"px"):a(document).height()+"px"},width:function(){var b,c;return a.browser.msie?(b=Math.max(document.documentElement.scrollWidth,document.body.scrollWidth),c=Math.max(document.documentElement.offsetWidth,document.body.offsetWidth),b<c?a(window).width()+"px":b+"px"):a(document).width()+"px"},resize:function(){var b=a([]);a.each(a.ui.dialog.overlay.instances,function(){b=b.add(this)}),b.css({width:0,height:0}).css({width:a.ui.dialog.overlay.width(),height:a.ui.dialog.overlay.height()})}}),a.extend(a.ui.dialog.overlay.prototype,{destroy:function(){a.ui.dialog.overlay.destroy(this.$el)}})})(jQuery);;/*! jQuery UI - v1.8.23 - 2012-08-15
    --* https://github.com/jquery/jquery-ui
    --* Includes: jquery.ui.slider.js
    --* Copyright (c) 2012 AUTHORS.txt; Licensed MIT, GPL */
    --(function(a,b){var c=5;a.widget("ui.slider",a.ui.mouse,{widgetEventPrefix:"slide",options:{animate:!1,distance:0,max:100,min:0,orientation:"horizontal",range:!1,step:1,value:0,values:null},_create:function(){var b=this,d=this.options,e=this.element.find(".ui-slider-handle").addClass("ui-state-default ui-corner-all"),f="<a class='ui-slider-handle ui-state-default ui-corner-all' href='#'></a>",g=d.values&&d.values.length||1,h=[];this._keySliding=!1,this._mouseSliding=!1,this._animateOff=!0,this._handleIndex=null,this._detectOrientation(),this._mouseInit(),this.element.addClass("ui-slider ui-slider-"+this.orientation+" ui-widget"+" ui-widget-content"+" ui-corner-all"+(d.disabled?" ui-slider-disabled ui-disabled":"")),this.range=a([]),d.range&&(d.range===!0&&(d.values||(d.values=[this._valueMin(),this._valueMin()]),d.values.length&&d.values.length!==2&&(d.values=[d.values[0],d.values[0]])),this.range=a("<div></div>").appendTo(this.element).addClass("ui-slider-range ui-widget-header"+(d.range==="min"||d.range==="max"?" ui-slider-range-"+d.range:"")));for(var i=e.length;i<g;i+=1)h.push(f);this.handles=e.add(a(h.join("")).appendTo(b.element)),this.handle=this.handles.eq(0),this.handles.add(this.range).filter("a").click(function(a){a.preventDefault()}).hover(function(){d.disabled||a(this).addClass("ui-state-hover")},function(){a(this).removeClass("ui-state-hover")}).focus(function(){d.disabled?a(this).blur():(a(".ui-slider .ui-state-focus").removeClass("ui-state-focus"),a(this).addClass("ui-state-focus"))}).blur(function(){a(this).removeClass("ui-state-focus")}),this.handles.each(function(b){a(this).data("index.ui-slider-handle",b)}),this.handles.keydown(function(d){var e=a(this).data("index.ui-slider-handle"),f,g,h,i;if(b.options.disabled)return;switch(d.keyCode){case a.ui.keyCode.HOME:case a.ui.keyCode.END:case a.ui.keyCode.PAGE_UP:case a.ui.keyCode.PAGE_DOWN:case a.ui.keyCode.UP:case a.ui.keyCode.RIGHT:case a.ui.keyCode.DOWN:case a.ui.keyCode.LEFT:d.preventDefault();if(!b._keySliding){b._keySliding=!0,a(this).addClass("ui-state-active"),f=b._start(d,e);if(f===!1)return}}i=b.options.step,b.options.values&&b.options.values.length?g=h=b.values(e):g=h=b.value();switch(d.keyCode){case a.ui.keyCode.HOME:h=b._valueMin();break;case a.ui.keyCode.END:h=b._valueMax();break;case a.ui.keyCode.PAGE_UP:h=b._trimAlignValue(g+(b._valueMax()-b._valueMin())/c);break;case a.ui.keyCode.PAGE_DOWN:h=b._trimAlignValue(g-(b._valueMax()-b._valueMin())/c);break;case a.ui.keyCode.UP:case a.ui.keyCode.RIGHT:if(g===b._valueMax())return;h=b._trimAlignValue(g+i);break;case a.ui.keyCode.DOWN:case a.ui.keyCode.LEFT:if(g===b._valueMin())return;h=b._trimAlignValue(g-i)}b._slide(d,e,h)}).keyup(function(c){var d=a(this).data("index.ui-slider-handle");b._keySliding&&(b._keySliding=!1,b._stop(c,d),b._change(c,d),a(this).removeClass("ui-state-active"))}),this._refreshValue(),this._animateOff=!1},destroy:function(){return this.handles.remove(),this.range.remove(),this.element.removeClass("ui-slider ui-slider-horizontal ui-slider-vertical ui-slider-disabled ui-widget ui-widget-content ui-corner-all").removeData("slider").unbind(".slider"),this._mouseDestroy(),this},_mouseCapture:function(b){var c=this.options,d,e,f,g,h,i,j,k,l;return c.disabled?!1:(this.elementSize={width:this.element.outerWidth(),height:this.element.outerHeight()},this.elementOffset=this.element.offset(),d={x:b.pageX,y:b.pageY},e=this._normValueFromMouse(d),f=this._valueMax()-this._valueMin()+1,h=this,this.handles.each(function(b){var c=Math.abs(e-h.values(b));f>c&&(f=c,g=a(this),i=b)}),c.range===!0&&this.values(1)===c.min&&(i+=1,g=a(this.handles[i])),j=this._start(b,i),j===!1?!1:(this._mouseSliding=!0,h._handleIndex=i,g.addClass("ui-state-active").focus(),k=g.offset(),l=!a(b.target).parents().andSelf().is(".ui-slider-handle"),this._clickOffset=l?{left:0,top:0}:{left:b.pageX-k.left-g.width()/2,top:b.pageY-k.top-g.height()/2-(parseInt(g.css("borderTopWidth"),10)||0)-(parseInt(g.css("borderBottomWidth"),10)||0)+(parseInt(g.css("marginTop"),10)||0)},this.handles.hasClass("ui-state-hover")||this._slide(b,i,e),this._animateOff=!0,!0))},_mouseStart:function(a){return!0},_mouseDrag:function(a){var b={x:a.pageX,y:a.pageY},c=this._normValueFromMouse(b);return this._slide(a,this._handleIndex,c),!1},_mouseStop:function(a){return this.handles.removeClass("ui-state-active"),this._mouseSliding=!1,this._stop(a,this._handleIndex),this._change(a,this._handleIndex),this._handleIndex=null,this._clickOffset=null,this._animateOff=!1,!1},_detectOrientation:function(){this.orientation=this.options.orientation==="vertical"?"vertical":"horizontal"},_normValueFromMouse:function(a){var b,c,d,e,f;return this.orientation==="horizontal"?(b=this.elementSize.width,c=a.x-this.elementOffset.left-(this._clickOffset?this._clickOffset.left:0)):(b=this.elementSize.height,c=a.y-this.elementOffset.top-(this._clickOffset?this._clickOffset.top:0)),d=c/b,d>1&&(d=1),d<0&&(d=0),this.orientation==="vertical"&&(d=1-d),e=this._valueMax()-this._valueMin(),f=this._valueMin()+d*e,this._trimAlignValue(f)},_start:function(a,b){var c={handle:this.handles[b],value:this.value()};return this.options.values&&this.options.values.length&&(c.value=this.values(b),c.values=this.values()),this._trigger("start",a,c)},_slide:function(a,b,c){var d,e,f;this.options.values&&this.options.values.length?(d=this.values(b?0:1),this.options.values.length===2&&this.options.range===!0&&(b===0&&c>d||b===1&&c<d)&&(c=d),c!==this.values(b)&&(e=this.values(),e[b]=c,f=this._trigger("slide",a,{handle:this.handles[b],value:c,values:e}),d=this.values(b?0:1),f!==!1&&this.values(b,c,!0))):c!==this.value()&&(f=this._trigger("slide",a,{handle:this.handles[b],value:c}),f!==!1&&this.value(c))},_stop:function(a,b){var c={handle:this.handles[b],value:this.value()};this.options.values&&this.options.values.length&&(c.value=this.values(b),c.values=this.values()),this._trigger("stop",a,c)},_change:function(a,b){if(!this._keySliding&&!this._mouseSliding){var c={handle:this.handles[b],value:this.value()};this.options.values&&this.options.values.length&&(c.value=this.values(b),c.values=this.values()),this._trigger("change",a,c)}},value:function(a){if(arguments.length){this.options.value=this._trimAlignValue(a),this._refreshValue(),this._change(null,0);return}return this._value()},values:function(b,c){var d,e,f;if(arguments.length>1){this.options.values[b]=this._trimAlignValue(c),this._refreshValue(),this._change(null,b);return}if(!arguments.length)return this._values();if(!a.isArray(arguments[0]))return this.options.values&&this.options.values.length?this._values(b):this.value();d=this.options.values,e=arguments[0];for(f=0;f<d.length;f+=1)d[f]=this._trimAlignValue(e[f]),this._change(null,f);this._refreshValue()},_setOption:function(b,c){var d,e=0;a.isArray(this.options.values)&&(e=this.options.values.length),a.Widget.prototype._setOption.apply(this,arguments);switch(b){case"disabled":c?(this.handles.filter(".ui-state-focus").blur(),this.handles.removeClass("ui-state-hover"),this.handles.propAttr("disabled",!0),this.element.addClass("ui-disabled")):(this.handles.propAttr("disabled",!1),this.element.removeClass("ui-disabled"));break;case"orientation":this._detectOrientation(),this.element.removeClass("ui-slider-horizontal ui-slider-vertical").addClass("ui-slider-"+this.orientation),this._refreshValue();break;case"value":this._animateOff=!0,this._refreshValue(),this._change(null,0),this._animateOff=!1;break;case"values":this._animateOff=!0,this._refreshValue();for(d=0;d<e;d+=1)this._change(null,d);this._animateOff=!1}},_value:function(){var a=this.options.value;return a=this._trimAlignValue(a),a},_values:function(a){var b,c,d;if(arguments.length)return b=this.options.values[a],b=this._trimAlignValue(b),b;c=this.options.values.slice();for(d=0;d<c.length;d+=1)c[d]=this._trimAlignValue(c[d]);return c},_trimAlignValue:function(a){if(a<=this._valueMin())return this._valueMin();if(a>=this._valueMax())return this._valueMax();var b=this.options.step>0?this.options.step:1,c=(a-this._valueMin())%b,d=a-c;return Math.abs(c)*2>=b&&(d+=c>0?b:-b),parseFloat(d.toFixed(5))},_valueMin:function(){return this.options.min},_valueMax:function(){return this.options.max},_refreshValue:function(){var b=this.options.range,c=this.options,d=this,e=this._animateOff?!1:c.animate,f,g={},h,i,j,k;this.options.values&&this.options.values.length?this.handles.each(function(b,i){f=(d.values(b)-d._valueMin())/(d._valueMax()-d._valueMin())*100,g[d.orientation==="horizontal"?"left":"bottom"]=f+"%",a(this).stop(1,1)[e?"animate":"css"](g,c.animate),d.options.range===!0&&(d.orientation==="horizontal"?(b===0&&d.range.stop(1,1)[e?"animate":"css"]({left:f+"%"},c.animate),b===1&&d.range[e?"animate":"css"]({width:f-h+"%"},{queue:!1,duration:c.animate})):(b===0&&d.range.stop(1,1)[e?"animate":"css"]({bottom:f+"%"},c.animate),b===1&&d.range[e?"animate":"css"]({height:f-h+"%"},{queue:!1,duration:c.animate}))),h=f}):(i=this.value(),j=this._valueMin(),k=this._valueMax(),f=k!==j?(i-j)/(k-j)*100:0,g[d.orientation==="horizontal"?"left":"bottom"]=f+"%",this.handle.stop(1,1)[e?"animate":"css"](g,c.animate),b==="min"&&this.orientation==="horizontal"&&this.range.stop(1,1)[e?"animate":"css"]({width:f+"%"},c.animate),b==="max"&&this.orientation==="horizontal"&&this.range[e?"animate":"css"]({width:100-f+"%"},{queue:!1,duration:c.animate}),b==="min"&&this.orientation==="vertical"&&this.range.stop(1,1)[e?"animate":"css"]({height:f+"%"},c.animate),b==="max"&&this.orientation==="vertical"&&this.range[e?"animate":"css"]({height:100-f+"%"},{queue:!1,duration:c.animate}))}}),a.extend(a.ui.slider,{version:"1.8.23"})})(jQuery);;/*! jQuery UI - v1.8.23 - 2012-08-15
    --* https://github.com/jquery/jquery-ui
    --* Includes: jquery.ui.tabs.js
    --* Copyright (c) 2012 AUTHORS.txt; Licensed MIT, GPL */
    --(function(a,b){function e(){return++c}function f(){return++d}var c=0,d=0;a.widget("ui.tabs",{options:{add:null,ajaxOptions:null,cache:!1,cookie:null,collapsible:!1,disable:null,disabled:[],enable:null,event:"click",fx:null,idPrefix:"ui-tabs-",load:null,panelTemplate:"<div></div>",remove:null,select:null,show:null,spinner:"<em>Loading&#8230;</em>",tabTemplate:"<li><a href='#{href}'><span>#{label}</span></a></li>"},_create:function(){this._tabify(!0)},_setOption:function(a,b){if(a=="selected"){if(this.options.collapsible&&b==this.options.selected)return;this.select(b)}else this.options[a]=b,this._tabify()},_tabId:function(a){return a.title&&a.title.replace(/\s/g,"_").replace(/[^\w\u00c0-\uFFFF-]/g,"")||this.options.idPrefix+e()},_sanitizeSelector:function(a){return a.replace(/:/g,"\\:")},_cookie:function(){var b=this.cookie||(this.cookie=this.options.cookie.name||"ui-tabs-"+f());return a.cookie.apply(null,[b].concat(a.makeArray(arguments)))},_ui:function(a,b){return{tab:a,panel:b,index:this.anchors.index(a)}},_cleanup:function(){this.lis.filter(".ui-state-processing").removeClass("ui-state-processing").find("span:data(label.tabs)").each(function(){var b=a(this);b.html(b.data("label.tabs")).removeData("label.tabs")})},_tabify:function(c){function m(b,c){b.css("display",""),!a.support.opacity&&c.opacity&&b[0].style.removeAttribute("filter")}var d=this,e=this.options,f=/^#.+/;this.list=this.element.find("ol,ul").eq(0),this.lis=a(" > li:has(a[href])",this.list),this.anchors=this.lis.map(function(){return a("a",this)[0]}),this.panels=a([]),this.anchors.each(function(b,c){var g=a(c).attr("href"),h=g.split("#")[0],i;h&&(h===location.toString().split("#")[0]||(i=a("base")[0])&&h===i.href)&&(g=c.hash,c.href=g);if(f.test(g))d.panels=d.panels.add(d.element.find(d._sanitizeSelector(g)));else if(g&&g!=="#"){a.data(c,"href.tabs",g),a.data(c,"load.tabs",g.replace(/#.*$/,""));var j=d._tabId(c);c.href="#"+j;var k=d.element.find("#"+j);k.length||(k=a(e.panelTemplate).attr("id",j).addClass("ui-tabs-panel ui-widget-content ui-corner-bottom").insertAfter(d.panels[b-1]||d.list),k.data("destroy.tabs",!0)),d.panels=d.panels.add(k)}else e.disabled.push(b)}),c?(this.element.addClass("ui-tabs ui-widget ui-widget-content ui-corner-all"),this.list.addClass("ui-tabs-nav ui-helper-reset ui-helper-clearfix ui-widget-header ui-corner-all"),this.lis.addClass("ui-state-default ui-corner-top"),this.panels.addClass("ui-tabs-panel ui-widget-content ui-corner-bottom"),e.selected===b?(location.hash&&this.anchors.each(function(a,b){if(b.hash==location.hash)return e.selected=a,!1}),typeof e.selected!="number"&&e.cookie&&(e.selected=parseInt(d._cookie(),10)),typeof e.selected!="number"&&this.lis.filter(".ui-tabs-selected").length&&(e.selected=this.lis.index(this.lis.filter(".ui-tabs-selected"))),e.selected=e.selected||(this.lis.length?0:-1)):e.selected===null&&(e.selected=-1),e.selected=e.selected>=0&&this.anchors[e.selected]||e.selected<0?e.selected:0,e.disabled=a.unique(e.disabled.concat(a.map(this.lis.filter(".ui-state-disabled"),function(a,b){return d.lis.index(a)}))).sort(),a.inArray(e.selected,e.disabled)!=-1&&e.disabled.splice(a.inArray(e.selected,e.disabled),1),this.panels.addClass("ui-tabs-hide"),this.lis.removeClass("ui-tabs-selected ui-state-active"),e.selected>=0&&this.anchors.length&&(d.element.find(d._sanitizeSelector(d.anchors[e.selected].hash)).removeClass("ui-tabs-hide"),this.lis.eq(e.selected).addClass("ui-tabs-selected ui-state-active"),d.element.queue("tabs",function(){d._trigger("show",null,d._ui(d.anchors[e.selected],d.element.find(d._sanitizeSelector(d.anchors[e.selected].hash))[0]))}),this.load(e.selected)),a(window).bind("unload",function(){d.lis.add(d.anchors).unbind(".tabs"),d.lis=d.anchors=d.panels=null})):e.selected=this.lis.index(this.lis.filter(".ui-tabs-selected")),this.element[e.collapsible?"addClass":"removeClass"]("ui-tabs-collapsible"),e.cookie&&this._cookie(e.selected,e.cookie);for(var g=0,h;h=this.lis[g];g++)a(h)[a.inArray(g,e.disabled)!=-1&&!a(h).hasClass("ui-tabs-selected")?"addClass":"removeClass"]("ui-state-disabled");e.cache===!1&&this.anchors.removeData("cache.tabs"),this.lis.add(this.anchors).unbind(".tabs");if(e.event!=="mouseover"){var i=function(a,b){b.is(":not(.ui-state-disabled)")&&b.addClass("ui-state-"+a)},j=function(a,b){b.removeClass("ui-state-"+a)};this.lis.bind("mouseover.tabs",function(){i("hover",a(this))}),this.lis.bind("mouseout.tabs",function(){j("hover",a(this))}),this.anchors.bind("focus.tabs",function(){i("focus",a(this).closest("li"))}),this.anchors.bind("blur.tabs",function(){j("focus",a(this).closest("li"))})}var k,l;e.fx&&(a.isArray(e.fx)?(k=e.fx[0],l=e.fx[1]):k=l=e.fx);var n=l?function(b,c){a(b).closest("li").addClass("ui-tabs-selected ui-state-active"),c.hide().removeClass("ui-tabs-hide").animate(l,l.duration||"normal",function(){m(c,l),d._trigger("show",null,d._ui(b,c[0]))})}:function(b,c){a(b).closest("li").addClass("ui-tabs-selected ui-state-active"),c.removeClass("ui-tabs-hide"),d._trigger("show",null,d._ui(b,c[0]))},o=k?function(a,b){b.animate(k,k.duration||"normal",function(){d.lis.removeClass("ui-tabs-selected ui-state-active"),b.addClass("ui-tabs-hide"),m(b,k),d.element.dequeue("tabs")})}:function(a,b,c){d.lis.removeClass("ui-tabs-selected ui-state-active"),b.addClass("ui-tabs-hide"),d.element.dequeue("tabs")};this.anchors.bind(e.event+".tabs",function(){var b=this,c=a(b).closest("li"),f=d.panels.filter(":not(.ui-tabs-hide)"),g=d.element.find(d._sanitizeSelector(b.hash));if(c.hasClass("ui-tabs-selected")&&!e.collapsible||c.hasClass("ui-state-disabled")||c.hasClass("ui-state-processing")||d.panels.filter(":animated").length||d._trigger("select",null,d._ui(this,g[0]))===!1)return this.blur(),!1;e.selected=d.anchors.index(this),d.abort();if(e.collapsible){if(c.hasClass("ui-tabs-selected"))return e.selected=-1,e.cookie&&d._cookie(e.selected,e.cookie),d.element.queue("tabs",function(){o(b,f)}).dequeue("tabs"),this.blur(),!1;if(!f.length)return e.cookie&&d._cookie(e.selected,e.cookie),d.element.queue("tabs",function(){n(b,g)}),d.load(d.anchors.index(this)),this.blur(),!1}e.cookie&&d._cookie(e.selected,e.cookie);if(g.length)f.length&&d.element.queue("tabs",function(){o(b,f)}),d.element.queue("tabs",function(){n(b,g)}),d.load(d.anchors.index(this));else throw"jQuery UI Tabs: Mismatching fragment identifier.";a.browser.msie&&this.blur()}),this.anchors.bind("click.tabs",function(){return!1})},_getIndex:function(a){return typeof a=="string"&&(a=this.anchors.index(this.anchors.filter("[href$='"+a+"']"))),a},destroy:function(){var b=this.options;return this.abort(),this.element.unbind(".tabs").removeClass("ui-tabs ui-widget ui-widget-content ui-corner-all ui-tabs-collapsible").removeData("tabs"),this.list.removeClass("ui-tabs-nav ui-helper-reset ui-helper-clearfix ui-widget-header ui-corner-all"),this.anchors.each(function(){var b=a.data(this,"href.tabs");b&&(this.href=b);var c=a(this).unbind(".tabs");a.each(["href","load","cache"],function(a,b){c.removeData(b+".tabs")})}),this.lis.unbind(".tabs").add(this.panels).each(function(){a.data(this,"destroy.tabs")?a(this).remove():a(this).removeClass(["ui-state-default","ui-corner-top","ui-tabs-selected","ui-state-active","ui-state-hover","ui-state-focus","ui-state-disabled","ui-tabs-panel","ui-widget-content","ui-corner-bottom","ui-tabs-hide"].join(" "))}),b.cookie&&this._cookie(null,b.cookie),this},add:function(c,d,e){e===b&&(e=this.anchors.length);var f=this,g=this.options,h=a(g.tabTemplate.replace(/#\{href\}/g,c).replace(/#\{label\}/g,d)),i=c.indexOf("#")?this._tabId(a("a",h)[0]):c.replace("#","");h.addClass("ui-state-default ui-corner-top").data("destroy.tabs",!0);var j=f.element.find("#"+i);return j.length||(j=a(g.panelTemplate).attr("id",i).data("destroy.tabs",!0)),j.addClass("ui-tabs-panel ui-widget-content ui-corner-bottom ui-tabs-hide"),e>=this.lis.length?(h.appendTo(this.list),j.appendTo(this.list[0].parentNode)):(h.insertBefore(this.lis[e]),j.insertBefore(this.panels[e])),g.disabled=a.map(g.disabled,function(a,b){return a>=e?++a:a}),this._tabify(),this.anchors.length==1&&(g.selected=0,h.addClass("ui-tabs-selected ui-state-active"),j.removeClass("ui-tabs-hide"),this.element.queue("tabs",function(){f._trigger("show",null,f._ui(f.anchors[0],f.panels[0]))}),this.load(0)),this._trigger("add",null,this._ui(this.anchors[e],this.panels[e])),this},remove:function(b){b=this._getIndex(b);var c=this.options,d=this.lis.eq(b).remove(),e=this.panels.eq(b).remove();return d.hasClass("ui-tabs-selected")&&this.anchors.length>1&&this.select(b+(b+1<this.anchors.length?1:-1)),c.disabled=a.map(a.grep(c.disabled,function(a,c){return a!=b}),function(a,c){return a>=b?--a:a}),this._tabify(),this._trigger("remove",null,this._ui(d.find("a")[0],e[0])),this},enable:function(b){b=this._getIndex(b);var c=this.options;if(a.inArray(b,c.disabled)==-1)return;return this.lis.eq(b).removeClass("ui-state-disabled"),c.disabled=a.grep(c.disabled,function(a,c){return a!=b}),this._trigger("enable",null,this._ui(this.anchors[b],this.panels[b])),this},disable:function(a){a=this._getIndex(a);var b=this,c=this.options;return a!=c.selected&&(this.lis.eq(a).addClass("ui-state-disabled"),c.disabled.push(a),c.disabled.sort(),this._trigger("disable",null,this._ui(this.anchors[a],this.panels[a]))),this},select:function(a){a=this._getIndex(a);if(a==-1)if(this.options.collapsible&&this.options.selected!=-1)a=this.options.selected;else return this;return this.anchors.eq(a).trigger(this.options.event+".tabs"),this},load:function(b){b=this._getIndex(b);var c=this,d=this.options,e=this.anchors.eq(b)[0],f=a.data(e,"load.tabs");this.abort();if(!f||this.element.queue("tabs").length!==0&&a.data(e,"cache.tabs")){this.element.dequeue("tabs");return}this.lis.eq(b).addClass("ui-state-processing");if(d.spinner){var g=a("span",e);g.data("label.tabs",g.html()).html(d.spinner)}return this.xhr=a.ajax(a.extend({},d.ajaxOptions,{url:f,success:function(f,g){c.element.find(c._sanitizeSelector(e.hash)).html(f),c._cleanup(),d.cache&&a.data(e,"cache.tabs",!0),c._trigger("load",null,c._ui(c.anchors[b],c.panels[b]));try{d.ajaxOptions.success(f,g)}catch(h){}},error:function(a,f,g){c._cleanup(),c._trigger("load",null,c._ui(c.anchors[b],c.panels[b]));try{d.ajaxOptions.error(a,f,b,e)}catch(g){}}})),c.element.dequeue("tabs"),this},abort:function(){return this.element.queue([]),this.panels.stop(!1,!0),this.element.queue("tabs",this.element.queue("tabs").splice(-2,2)),this.xhr&&(this.xhr.abort(),delete this.xhr),this._cleanup(),this},url:function(a,b){return this.anchors.eq(a).removeData("cache.tabs").data("load.tabs",b),this},length:function(){return this.anchors.length}}),a.extend(a.ui.tabs,{version:"1.8.23"}),a.extend(a.ui.tabs.prototype,{rotation:null,rotate:function(a,b){var c=this,d=this.options,e=c._rotate||(c._rotate=function(b){clearTimeout(c.rotation),c.rotation=setTimeout(function(){var a=d.selected;c.select(++a<c.anchors.length?a:0)},a),b&&b.stopPropagation()}),f=c._unrotate||(c._unrotate=b?function(a){e()}:function(a){a.clientX&&c.rotate(null)});return a?(this.element.bind("tabsshow",e),this.anchors.bind(d.event+".tabs",f),e()):(clearTimeout(c.rotation),this.element.unbind("tabsshow",e),this.anchors.unbind(d.event+".tabs",f),delete this._rotate,delete this._unrotate),this}})})(jQuery);;/*! jQuery UI - v1.8.23 - 2012-08-15
    --* https://github.com/jquery/jquery-ui
    --* Includes: jquery.ui.datepicker.js
    --* Copyright (c) 2012 AUTHORS.txt; Licensed MIT, GPL */
    --(function($,undefined){function Datepicker(){this.debug=!1,this._curInst=null,this._keyEvent=!1,this._disabledInputs=[],this._datepickerShowing=!1,this._inDialog=!1,this._mainDivId="ui-datepicker-div",this._inlineClass="ui-datepicker-inline",this._appendClass="ui-datepicker-append",this._triggerClass="ui-datepicker-trigger",this._dialogClass="ui-datepicker-dialog",this._disableClass="ui-datepicker-disabled",this._unselectableClass="ui-datepicker-unselectable",this._currentClass="ui-datepicker-current-day",this._dayOverClass="ui-datepicker-days-cell-over",this.regional=[],this.regional[""]={closeText:"Done",prevText:"Prev",nextText:"Next",currentText:"Today",monthNames:["January","February","March","April","May","June","July","August","September","October","November","December"],monthNamesShort:["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"],dayNames:["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"],dayNamesShort:["Sun","Mon","Tue","Wed","Thu","Fri","Sat"],dayNamesMin:["Su","Mo","Tu","We","Th","Fr","Sa"],weekHeader:"Wk",dateFormat:"mm/dd/yy",firstDay:0,isRTL:!1,showMonthAfterYear:!1,yearSuffix:""},this._defaults={showOn:"focus",showAnim:"fadeIn",showOptions:{},defaultDate:null,appendText:"",buttonText:"...",buttonImage:"",buttonImageOnly:!1,hideIfNoPrevNext:!1,navigationAsDateFormat:!1,gotoCurrent:!1,changeMonth:!1,changeYear:!1,yearRange:"c-10:c+10",showOtherMonths:!1,selectOtherMonths:!1,showWeek:!1,calculateWeek:this.iso8601Week,shortYearCutoff:"+10",minDate:null,maxDate:null,duration:"fast",beforeShowDay:null,beforeShow:null,onSelect:null,onChangeMonthYear:null,onClose:null,numberOfMonths:1,showCurrentAtPos:0,stepMonths:1,stepBigMonths:12,altField:"",altFormat:"",constrainInput:!0,showButtonPanel:!1,autoSize:!1,disabled:!1},$.extend(this._defaults,this.regional[""]),this.dpDiv=bindHover($('<div id="'+this._mainDivId+'" class="ui-datepicker ui-widget ui-widget-content ui-helper-clearfix ui-corner-all"></div>'))}function bindHover(a){var b="button, .ui-datepicker-prev, .ui-datepicker-next, .ui-datepicker-calendar td a";return a.bind("mouseout",function(a){var c=$(a.target).closest(b);if(!c.length)return;c.removeClass("ui-state-hover ui-datepicker-prev-hover ui-datepicker-next-hover")}).bind("mouseover",function(c){var d=$(c.target).closest(b);if($.datepicker._isDisabledDatepicker(instActive.inline?a.parent()[0]:instActive.input[0])||!d.length)return;d.parents(".ui-datepicker-calendar").find("a").removeClass("ui-state-hover"),d.addClass("ui-state-hover"),d.hasClass("ui-datepicker-prev")&&d.addClass("ui-datepicker-prev-hover"),d.hasClass("ui-datepicker-next")&&d.addClass("ui-datepicker-next-hover")})}function extendRemove(a,b){$.extend(a,b);for(var c in b)if(b[c]==null||b[c]==undefined)a[c]=b[c];return a}function isArray(a){return a&&($.browser.safari&&typeof a=="object"&&a.length||a.constructor&&a.constructor.toString().match(/\Array\(\)/))}$.extend($.ui,{datepicker:{version:"1.8.23"}});var PROP_NAME="datepicker",dpuuid=(new Date).getTime(),instActive;$.extend(Datepicker.prototype,{markerClassName:"hasDatepicker",maxRows:4,log:function(){this.debug&&console.log.apply("",arguments)},_widgetDatepicker:function(){return this.dpDiv},setDefaults:function(a){return extendRemove(this._defaults,a||{}),this},_attachDatepicker:function(target,settings){var inlineSettings=null;for(var attrName in this._defaults){var attrValue=target.getAttribute("date:"+attrName);if(attrValue){inlineSettings=inlineSettings||{};try{inlineSettings[attrName]=eval(attrValue)}catch(err){inlineSettings[attrName]=attrValue}}}var nodeName=target.nodeName.toLowerCase(),inline=nodeName=="div"||nodeName=="span";target.id||(this.uuid+=1,target.id="dp"+this.uuid);var inst=this._newInst($(target),inline);inst.settings=$.extend({},settings||{},inlineSettings||{}),nodeName=="input"?this._connectDatepicker(target,inst):inline&&this._inlineDatepicker(target,inst)},_newInst:function(a,b){var c=a[0].id.replace(/([^A-Za-z0-9_-])/g,"\\\\$1");return{id:c,input:a,selectedDay:0,selectedMonth:0,selectedYear:0,drawMonth:0,drawYear:0,inline:b,dpDiv:b?bindHover($('<div class="'+this._inlineClass+' ui-datepicker ui-widget ui-widget-content ui-helper-clearfix ui-corner-all"></div>')):this.dpDiv}},_connectDatepicker:function(a,b){var c=$(a);b.append=$([]),b.trigger=$([]);if(c.hasClass(this.markerClassName))return;this._attachments(c,b),c.addClass(this.markerClassName).keydown(this._doKeyDown).keypress(this._doKeyPress).keyup(this._doKeyUp).bind("setData.datepicker",function(a,c,d){b.settings[c]=d}).bind("getData.datepicker",function(a,c){return this._get(b,c)}),this._autoSize(b),$.data(a,PROP_NAME,b),b.settings.disabled&&this._disableDatepicker(a)},_attachments:function(a,b){var c=this._get(b,"appendText"),d=this._get(b,"isRTL");b.append&&b.append.remove(),c&&(b.append=$('<span class="'+this._appendClass+'">'+c+"</span>"),a[d?"before":"after"](b.append)),a.unbind("focus",this._showDatepicker),b.trigger&&b.trigger.remove();var e=this._get(b,"showOn");(e=="focus"||e=="both")&&a.focus(this._showDatepicker);if(e=="button"||e=="both"){var f=this._get(b,"buttonText"),g=this._get(b,"buttonImage");b.trigger=$(this._get(b,"buttonImageOnly")?$("<img/>").addClass(this._triggerClass).attr({src:g,alt:f,title:f}):$('<button type="button"></button>').addClass(this._triggerClass).html(g==""?f:$("<img/>").attr({src:g,alt:f,title:f}))),a[d?"before":"after"](b.trigger),b.trigger.click(function(){return $.datepicker._datepickerShowing&&$.datepicker._lastInput==a[0]?$.datepicker._hideDatepicker():$.datepicker._datepickerShowing&&$.datepicker._lastInput!=a[0]?($.datepicker._hideDatepicker(),$.datepicker._showDatepicker(a[0])):$.datepicker._showDatepicker(a[0]),!1})}},_autoSize:function(a){if(this._get(a,"autoSize")&&!a.inline){var b=new Date(2009,11,20),c=this._get(a,"dateFormat");if(c.match(/[DM]/)){var d=function(a){var b=0,c=0;for(var d=0;d<a.length;d++)a[d].length>b&&(b=a[d].length,c=d);return c};b.setMonth(d(this._get(a,c.match(/MM/)?"monthNames":"monthNamesShort"))),b.setDate(d(this._get(a,c.match(/DD/)?"dayNames":"dayNamesShort"))+20-b.getDay())}a.input.attr("size",this._formatDate(a,b).length)}},_inlineDatepicker:function(a,b){var c=$(a);if(c.hasClass(this.markerClassName))return;c.addClass(this.markerClassName).append(b.dpDiv).bind("setData.datepicker",function(a,c,d){b.settings[c]=d}).bind("getData.datepicker",function(a,c){return this._get(b,c)}),$.data(a,PROP_NAME,b),this._setDate(b,this._getDefaultDate(b),!0),this._updateDatepicker(b),this._updateAlternate(b),b.settings.disabled&&this._disableDatepicker(a),b.dpDiv.css("display","block")},_dialogDatepicker:function(a,b,c,d,e){var f=this._dialogInst;if(!f){this.uuid+=1;var g="dp"+this.uuid;this._dialogInput=$('<input type="text" id="'+g+'" style="position: absolute; top: -100px; width: 0px;"/>'),this._dialogInput.keydown(this._doKeyDown),$("body").append(this._dialogInput),f=this._dialogInst=this._newInst(this._dialogInput,!1),f.settings={},$.data(this._dialogInput[0],PROP_NAME,f)}extendRemove(f.settings,d||{}),b=b&&b.constructor==Date?this._formatDate(f,b):b,this._dialogInput.val(b),this._pos=e?e.length?e:[e.pageX,e.pageY]:null;if(!this._pos){var h=document.documentElement.clientWidth,i=document.documentElement.clientHeight,j=document.documentElement.scrollLeft||document.body.scrollLeft,k=document.documentElement.scrollTop||document.body.scrollTop;this._pos=[h/2-100+j,i/2-150+k]}return this._dialogInput.css("left",this._pos[0]+20+"px").css("top",this._pos[1]+"px"),f.settings.onSelect=c,this._inDialog=!0,this.dpDiv.addClass(this._dialogClass),this._showDatepicker(this._dialogInput[0]),$.blockUI&&$.blockUI(this.dpDiv),$.data(this._dialogInput[0],PROP_NAME,f),this},_destroyDatepicker:function(a){var b=$(a),c=$.data(a,PROP_NAME);if(!b.hasClass(this.markerClassName))return;var d=a.nodeName.toLowerCase();$.removeData(a,PROP_NAME),d=="input"?(c.append.remove(),c.trigger.remove(),b.removeClass(this.markerClassName).unbind("focus",this._showDatepicker).unbind("keydown",this._doKeyDown).unbind("keypress",this._doKeyPress).unbind("keyup",this._doKeyUp)):(d=="div"||d=="span")&&b.removeClass(this.markerClassName).empty()},_enableDatepicker:function(a){var b=$(a),c=$.data(a,PROP_NAME);if(!b.hasClass(this.markerClassName))return;var d=a.nodeName.toLowerCase();if(d=="input")a.disabled=!1,c.trigger.filter("button").each(function(){this.disabled=!1}).end().filter("img").css({opacity:"1.0",cursor:""});else if(d=="div"||d=="span"){var e=b.children("."+this._inlineClass);e.children().removeClass("ui-state-disabled"),e.find("select.ui-datepicker-month, select.ui-datepicker-year").removeAttr("disabled")}this._disabledInputs=$.map(this._disabledInputs,function(b){return b==a?null:b})},_disableDatepicker:function(a){var b=$(a),c=$.data(a,PROP_NAME);if(!b.hasClass(this.markerClassName))return;var d=a.nodeName.toLowerCase();if(d=="input")a.disabled=!0,c.trigger.filter("button").each(function(){this.disabled=!0}).end().filter("img").css({opacity:"0.5",cursor:"default"});else if(d=="div"||d=="span"){var e=b.children("."+this._inlineClass);e.children().addClass("ui-state-disabled"),e.find("select.ui-datepicker-month, select.ui-datepicker-year").attr("disabled","disabled")}this._disabledInputs=$.map(this._disabledInputs,function(b){return b==a?null:b}),this._disabledInputs[this._disabledInputs.length]=a},_isDisabledDatepicker:function(a){if(!a)return!1;for(var b=0;b<this._disabledInputs.length;b++)if(this._disabledInputs[b]==a)return!0;return!1},_getInst:function(a){try{return $.data(a,PROP_NAME)}catch(b){throw"Missing instance data for this datepicker"}},_optionDatepicker:function(a,b,c){var d=this._getInst(a);if(arguments.length==2&&typeof b=="string")return b=="defaults"?$.extend({},$.datepicker._defaults):d?b=="all"?$.extend({},d.settings):this._get(d,b):null;var e=b||{};typeof b=="string"&&(e={},e[b]=c);if(d){this._curInst==d&&this._hideDatepicker();var f=this._getDateDatepicker(a,!0),g=this._getMinMaxDate(d,"min"),h=this._getMinMaxDate(d,"max");extendRemove(d.settings,e),g!==null&&e.dateFormat!==undefined&&e.minDate===undefined&&(d.settings.minDate=this._formatDate(d,g)),h!==null&&e.dateFormat!==undefined&&e.maxDate===undefined&&(d.settings.maxDate=this._formatDate(d,h)),this._attachments($(a),d),this._autoSize(d),this._setDate(d,f),this._updateAlternate(d),this._updateDatepicker(d)}},_changeDatepicker:function(a,b,c){this._optionDatepicker(a,b,c)},_refreshDatepicker:function(a){var b=this._getInst(a);b&&this._updateDatepicker(b)},_setDateDatepicker:function(a,b){var c=this._getInst(a);c&&(this._setDate(c,b),this._updateDatepicker(c),this._updateAlternate(c))},_getDateDatepicker:function(a,b){var c=this._getInst(a);return c&&!c.inline&&this._setDateFromField(c,b),c?this._getDate(c):null},_doKeyDown:function(a){var b=$.datepicker._getInst(a.target),c=!0,d=b.dpDiv.is(".ui-datepicker-rtl");b._keyEvent=!0;if($.datepicker._datepickerShowing)switch(a.keyCode){case 9:$.datepicker._hideDatepicker(),c=!1;break;case 13:var e=$("td."+$.datepicker._dayOverClass+":not(."+$.datepicker._currentClass+")",b.dpDiv);e[0]&&$.datepicker._selectDay(a.target,b.selectedMonth,b.selectedYear,e[0]);var f=$.datepicker._get(b,"onSelect");if(f){var g=$.datepicker._formatDate(b);f.apply(b.input?b.input[0]:null,[g,b])}else $.datepicker._hideDatepicker();return!1;case 27:$.datepicker._hideDatepicker();break;case 33:$.datepicker._adjustDate(a.target,a.ctrlKey?-$.datepicker._get(b,"stepBigMonths"):-$.datepicker._get(b,"stepMonths"),"M");break;case 34:$.datepicker._adjustDate(a.target,a.ctrlKey?+$.datepicker._get(b,"stepBigMonths"):+$.datepicker._get(b,"stepMonths"),"M");break;case 35:(a.ctrlKey||a.metaKey)&&$.datepicker._clearDate(a.target),c=a.ctrlKey||a.metaKey;break;case 36:(a.ctrlKey||a.metaKey)&&$.datepicker._gotoToday(a.target),c=a.ctrlKey||a.metaKey;break;case 37:(a.ctrlKey||a.metaKey)&&$.datepicker._adjustDate(a.target,d?1:-1,"D"),c=a.ctrlKey||a.metaKey,a.originalEvent.altKey&&$.datepicker._adjustDate(a.target,a.ctrlKey?-$.datepicker._get(b,"stepBigMonths"):-$.datepicker._get(b,"stepMonths"),"M");break;case 38:(a.ctrlKey||a.metaKey)&&$.datepicker._adjustDate(a.target,-7,"D"),c=a.ctrlKey||a.metaKey;break;case 39:(a.ctrlKey||a.metaKey)&&$.datepicker._adjustDate(a.target,d?-1:1,"D"),c=a.ctrlKey||a.metaKey,a.originalEvent.altKey&&$.datepicker._adjustDate(a.target,a.ctrlKey?+$.datepicker._get(b,"stepBigMonths"):+$.datepicker._get(b,"stepMonths"),"M");break;case 40:(a.ctrlKey||a.metaKey)&&$.datepicker._adjustDate(a.target,7,"D"),c=a.ctrlKey||a.metaKey;break;default:c=!1}else a.keyCode==36&&a.ctrlKey?$.datepicker._showDatepicker(this):c=!1;c&&(a.preventDefault(),a.stopPropagation())},_doKeyPress:function(a){var b=$.datepicker._getInst(a.target);if($.datepicker._get(b,"constrainInput")){var c=$.datepicker._possibleChars($.datepicker._get(b,"dateFormat")),d=String.fromCharCode(a.charCode==undefined?a.keyCode:a.charCode);return a.ctrlKey||a.metaKey||d<" "||!c||c.indexOf(d)>-1}},_doKeyUp:function(a){var b=$.datepicker._getInst(a.target);if(b.input.val()!=b.lastVal)try{var c=$.datepicker.parseDate($.datepicker._get(b,"dateFormat"),b.input?b.input.val():null,$.datepicker._getFormatConfig(b));c&&($.datepicker._setDateFromField(b),$.datepicker._updateAlternate(b),$.datepicker._updateDatepicker(b))}catch(d){$.datepicker.log(d)}return!0},_showDatepicker:function(a){a=a.target||a,a.nodeName.toLowerCase()!="input"&&(a=$("input",a.parentNode)[0]);if($.datepicker._isDisabledDatepicker(a)||$.datepicker._lastInput==a)return;var b=$.datepicker._getInst(a);$.datepicker._curInst&&$.datepicker._curInst!=b&&($.datepicker._curInst.dpDiv.stop(!0,!0),b&&$.datepicker._datepickerShowing&&$.datepicker._hideDatepicker($.datepicker._curInst.input[0]));var c=$.datepicker._get(b,"beforeShow"),d=c?c.apply(a,[a,b]):{};if(d===!1)return;extendRemove(b.settings,d),b.lastVal=null,$.datepicker._lastInput=a,$.datepicker._setDateFromField(b),$.datepicker._inDialog&&(a.value=""),$.datepicker._pos||($.datepicker._pos=$.datepicker._findPos(a),$.datepicker._pos[1]+=a.offsetHeight);var e=!1;$(a).parents().each(function(){return e|=$(this).css("position")=="fixed",!e}),e&&$.browser.opera&&($.datepicker._pos[0]-=document.documentElement.scrollLeft,$.datepicker._pos[1]-=document.documentElement.scrollTop);var f={left:$.datepicker._pos[0],top:$.datepicker._pos[1]};$.datepicker._pos=null,b.dpDiv.empty(),b.dpDiv.css({position:"absolute",display:"block",top:"-1000px"}),$.datepicker._updateDatepicker(b),f=$.datepicker._checkOffset(b,f,e),b.dpDiv.css({position:$.datepicker._inDialog&&$.blockUI?"static":e?"fixed":"absolute",display:"none",left:f.left+"px",top:f.top+"px"});if(!b.inline){var g=$.datepicker._get(b,"showAnim"),h=$.datepicker._get(b,"duration"),i=function(){var a=b.dpDiv.find("iframe.ui-datepicker-cover");if(!!a.length){var c=$.datepicker._getBorders(b.dpDiv);a.css({left:-c[0],top:-c[1],width:b.dpDiv.outerWidth(),height:b.dpDiv.outerHeight()})}};b.dpDiv.zIndex($(a).zIndex()+1),$.datepicker._datepickerShowing=!0,$.effects&&$.effects[g]?b.dpDiv.show(g,$.datepicker._get(b,"showOptions"),h,i):b.dpDiv[g||"show"](g?h:null,i),(!g||!h)&&i(),b.input.is(":visible")&&!b.input.is(":disabled")&&b.input.focus(),$.datepicker._curInst=b}},_updateDatepicker:function(a){var b=this;b.maxRows=4;var c=$.datepicker._getBorders(a.dpDiv);instActive=a,a.dpDiv.empty().append(this._generateHTML(a)),this._attachHandlers(a);var d=a.dpDiv.find("iframe.ui-datepicker-cover");!d.length||d.css({left:-c[0],top:-c[1],width:a.dpDiv.outerWidth(),height:a.dpDiv.outerHeight()}),a.dpDiv.find("."+this._dayOverClass+" a").mouseover();var e=this._getNumberOfMonths(a),f=e[1],g=17;a.dpDiv.removeClass("ui-datepicker-multi-2 ui-datepicker-multi-3 ui-datepicker-multi-4").width(""),f>1&&a.dpDiv.addClass("ui-datepicker-multi-"+f).css("width",g*f+"em"),a.dpDiv[(e[0]!=1||e[1]!=1?"add":"remove")+"Class"]("ui-datepicker-multi"),a.dpDiv[(this._get(a,"isRTL")?"add":"remove")+"Class"]("ui-datepicker-rtl"),a==$.datepicker._curInst&&$.datepicker._datepickerShowing&&a.input&&a.input.is(":visible")&&!a.input.is(":disabled")&&a.input[0]!=document.activeElement&&a.input.focus();if(a.yearshtml){var h=a.yearshtml;setTimeout(function(){h===a.yearshtml&&a.yearshtml&&a.dpDiv.find("select.ui-datepicker-year:first").replaceWith(a.yearshtml),h=a.yearshtml=null},0)}},_getBorders:function(a){var b=function(a){return{thin:1,medium:2,thick:3}[a]||a};return[parseFloat(b(a.css("border-left-width"))),parseFloat(b(a.css("border-top-width")))]},_checkOffset:function(a,b,c){var d=a.dpDiv.outerWidth(),e=a.dpDiv.outerHeight(),f=a.input?a.input.outerWidth():0,g=a.input?a.input.outerHeight():0,h=document.documentElement.clientWidth+(c?0:$(document).scrollLeft()),i=document.documentElement.clientHeight+(c?0:$(document).scrollTop());return b.left-=this._get(a,"isRTL")?d-f:0,b.left-=c&&b.left==a.input.offset().left?$(document).scrollLeft():0,b.top-=c&&b.top==a.input.offset().top+g?$(document).scrollTop():0,b.left-=Math.min(b.left,b.left+d>h&&h>d?Math.abs(b.left+d-h):0),b.top-=Math.min(b.top,b.top+e>i&&i>e?Math.abs(e+g):0),b},_findPos:function(a){var b=this._getInst(a),c=this._get(b,"isRTL");while(a&&(a.type=="hidden"||a.nodeType!=1||$.expr.filters.hidden(a)))a=a[c?"previousSibling":"nextSibling"];var d=$(a).offset();return[d.left,d.top]},_hideDatepicker:function(a){var b=this._curInst;if(!b||a&&b!=$.data(a,PROP_NAME))return;if(this._datepickerShowing){var c=this._get(b,"showAnim"),d=this._get(b,"duration"),e=function(){$.datepicker._tidyDialog(b)};$.effects&&$.effects[c]?b.dpDiv.hide(c,$.datepicker._get(b,"showOptions"),d,e):b.dpDiv[c=="slideDown"?"slideUp":c=="fadeIn"?"fadeOut":"hide"](c?d:null,e),c||e(),this._datepickerShowing=!1;var f=this._get(b,"onClose");f&&f.apply(b.input?b.input[0]:null,[b.input?b.input.val():"",b]),this._lastInput=null,this._inDialog&&(this._dialogInput.css({position:"absolute",left:"0",top:"-100px"}),$.blockUI&&($.unblockUI(),$("body").append(this.dpDiv))),this._inDialog=!1}},_tidyDialog:function(a){a.dpDiv.removeClass(this._dialogClass).unbind(".ui-datepicker-calendar")},_checkExternalClick:function(a){if(!$.datepicker._curInst)return;var b=$(a.target),c=$.datepicker._getInst(b[0]);(b[0].id!=$.datepicker._mainDivId&&b.parents("#"+$.datepicker._mainDivId).length==0&&!b.hasClass($.datepicker.markerClassName)&&!b.closest("."+$.datepicker._triggerClass).length&&$.datepicker._datepickerShowing&&(!$.datepicker._inDialog||!$.blockUI)||b.hasClass($.datepicker.markerClassName)&&$.datepicker._curInst!=c)&&$.datepicker._hideDatepicker()},_adjustDate:function(a,b,c){var d=$(a),e=this._getInst(d[0]);if(this._isDisabledDatepicker(d[0]))return;this._adjustInstDate(e,b+(c=="M"?this._get(e,"showCurrentAtPos"):0),c),this._updateDatepicker(e)},_gotoToday:function(a){var b=$(a),c=this._getInst(b[0]);if(this._get(c,"gotoCurrent")&&c.currentDay)c.selectedDay=c.currentDay,c.drawMonth=c.selectedMonth=c.currentMonth,c.drawYear=c.selectedYear=c.currentYear;else{var d=new Date;c.selectedDay=d.getDate(),c.drawMonth=c.selectedMonth=d.getMonth(),c.drawYear=c.selectedYear=d.getFullYear()}this._notifyChange(c),this._adjustDate(b)},_selectMonthYear:function(a,b,c){var d=$(a),e=this._getInst(d[0]);e["selected"+(c=="M"?"Month":"Year")]=e["draw"+(c=="M"?"Month":"Year")]=parseInt(b.options[b.selectedIndex].value,10),this._notifyChange(e),this._adjustDate(d)},_selectDay:function(a,b,c,d){var e=$(a);if($(d).hasClass(this._unselectableClass)||this._isDisabledDatepicker(e[0]))return;var f=this._getInst(e[0]);f.selectedDay=f.currentDay=$("a",d).html(),f.selectedMonth=f.currentMonth=b,f.selectedYear=f.currentYear=c,this._selectDate(a,this._formatDate(f,f.currentDay,f.currentMonth,f.currentYear))},_clearDate:function(a){var b=$(a),c=this._getInst(b[0]);this._selectDate(b,"")},_selectDate:function(a,b){var c=$(a),d=this._getInst(c[0]);b=b!=null?b:this._formatDate(d),d.input&&d.input.val(b),this._updateAlternate(d);var e=this._get(d,"onSelect");e?e.apply(d.input?d.input[0]:null,[b,d]):d.input&&d.input.trigger("change"),d.inline?this._updateDatepicker(d):(this._hideDatepicker(),this._lastInput=d.input[0],typeof d.input[0]!="object"&&d.input.focus(),this._lastInput=null)},_updateAlternate:function(a){var b=this._get(a,"altField");if(b){var c=this._get(a,"altFormat")||this._get(a,"dateFormat"),d=this._getDate(a),e=this.formatDate(c,d,this._getFormatConfig(a));$(b).each(function(){$(this).val(e)})}},noWeekends:function(a){var b=a.getDay();return[b>0&&b<6,""]},iso8601Week:function(a){var b=new Date(a.getTime());b.setDate(b.getDate()+4-(b.getDay()||7));var c=b.getTime();return b.setMonth(0),b.setDate(1),Math.floor(Math.round((c-b)/864e5)/7)+1},parseDate:function(a,b,c){if(a==null||b==null)throw"Invalid arguments";b=typeof b=="object"?b.toString():b+"";if(b=="")return null;var d=(c?c.shortYearCutoff:null)||this._defaults.shortYearCutoff;d=typeof d!="string"?d:(new Date).getFullYear()%100+parseInt(d,10);var e=(c?c.dayNamesShort:null)||this._defaults.dayNamesShort,f=(c?c.dayNames:null)||this._defaults.dayNames,g=(c?c.monthNamesShort:null)||this._defaults.monthNamesShort,h=(c?c.monthNames:null)||this._defaults.monthNames,i=-1,j=-1,k=-1,l=-1,m=!1,n=function(b){var c=s+1<a.length&&a.charAt(s+1)==b;return c&&s++,c},o=function(a){var c=n(a),d=a=="@"?14:a=="!"?20:a=="y"&&c?4:a=="o"?3:2,e=new RegExp("^\\d{1,"+d+"}"),f=b.substring(r).match(e);if(!f)throw"Missing number at position "+r;return r+=f[0].length,parseInt(f[0],10)},p=function(a,c,d){var e=$.map(n(a)?d:c,function(a,b){return[[b,a]]}).sort(function(a,b){return-(a[1].length-b[1].length)}),f=-1;$.each(e,function(a,c){var d=c[1];if(b.substr(r,d.length).toLowerCase()==d.toLowerCase())return f=c[0],r+=d.length,!1});if(f!=-1)return f+1;throw"Unknown name at position "+r},q=function(){if(b.charAt(r)!=a.charAt(s))throw"Unexpected literal at position "+r;r++},r=0;for(var s=0;s<a.length;s++)if(m)a.charAt(s)=="'"&&!n("'")?m=!1:q();else switch(a.charAt(s)){case"d":k=o("d");break;case"D":p("D",e,f);break;case"o":l=o("o");break;case"m":j=o("m");break;case"M":j=p("M",g,h);break;case"y":i=o("y");break;case"@":var t=new Date(o("@"));i=t.getFullYear(),j=t.getMonth()+1,k=t.getDate();break;case"!":var t=new Date((o("!")-this._ticksTo1970)/1e4);i=t.getFullYear(),j=t.getMonth()+1,k=t.getDate();break;case"'":n("'")?q():m=!0;break;default:q()}if(r<b.length)throw"Extra/unparsed characters found in date: "+b.substring(r);i==-1?i=(new Date).getFullYear():i<100&&(i+=(new Date).getFullYear()-(new Date).getFullYear()%100+(i<=d?0:-100));if(l>-1){j=1,k=l;do{var u=this._getDaysInMonth(i,j-1);if(k<=u)break;j++,k-=u}while(!0)}var t=this._daylightSavingAdjust(new Date(i,j-1,k));if(t.getFullYear()!=i||t.getMonth()+1!=j||t.getDate()!=k)throw"Invalid date";return t},ATOM:"yy-mm-dd",COOKIE:"D, dd M yy",ISO_8601:"yy-mm-dd",RFC_822:"D, d M y",RFC_850:"DD, dd-M-y",RFC_1036:"D, d M y",RFC_1123:"D, d M yy",RFC_2822:"D, d M yy",RSS:"D, d M y",TICKS:"!",TIMESTAMP:"@",W3C:"yy-mm-dd",_ticksTo1970:(718685+Math.floor(492.5)-Math.floor(19.7)+Math.floor(4.925))*24*60*60*1e7,formatDate:function(a,b,c){if(!b)return"";var d=(c?c.dayNamesShort:null)||this._defaults.dayNamesShort,e=(c?c.dayNames:null)||this._defaults.dayNames,f=(c?c.monthNamesShort:null)||this._defaults.monthNamesShort,g=(c?c.monthNames:null)||this._defaults.monthNames,h=function(b){var c=m+1<a.length&&a.charAt(m+1)==b;return c&&m++,c},i=function(a,b,c){var d=""+b;if(h(a))while(d.length<c)d="0"+d;return d},j=function(a,b,c,d){return h(a)?d[b]:c[b]},k="",l=!1;if(b)for(var m=0;m<a.length;m++)if(l)a.charAt(m)=="'"&&!h("'")?l=!1:k+=a.charAt(m);else switch(a.charAt(m)){case"d":k+=i("d",b.getDate(),2);break;case"D":k+=j("D",b.getDay(),d,e);break;case"o":k+=i("o",Math.round(((new Date(b.getFullYear(),b.getMonth(),b.getDate())).getTime()-(new Date(b.getFullYear(),0,0)).getTime())/864e5),3);break;case"m":k+=i("m",b.getMonth()+1,2);break;case"M":k+=j("M",b.getMonth(),f,g);break;case"y":k+=h("y")?b.getFullYear():(b.getYear()%100<10?"0":"")+b.getYear()%100;break;case"@":k+=b.getTime();break;case"!":k+=b.getTime()*1e4+this._ticksTo1970;break;case"'":h("'")?k+="'":l=!0;break;default:k+=a.charAt(m)}return k},_possibleChars:function(a){var b="",c=!1,d=function(b){var c=e+1<a.length&&a.charAt(e+1)==b;return c&&e++,c};for(var e=0;e<a.length;e++)if(c)a.charAt(e)=="'"&&!d("'")?c=!1:b+=a.charAt(e);else switch(a.charAt(e)){case"d":case"m":case"y":case"@":b+="0123456789";break;case"D":case"M":return null;case"'":d("'")?b+="'":c=!0;break;default:b+=a.charAt(e)}return b},_get:function(a,b){return a.settings[b]!==undefined?a.settings[b]:this._defaults[b]},_setDateFromField:function(a,b){if(a.input.val()==a.lastVal)return;var c=this._get(a,"dateFormat"),d=a.lastVal=a.input?a.input.val():null,e,f;e=f=this._getDefaultDate(a);var g=this._getFormatConfig(a);try{e=this.parseDate(c,d,g)||f}catch(h){this.log(h),d=b?"":d}a.selectedDay=e.getDate(),a.drawMonth=a.selectedMonth=e.getMonth(),a.drawYear=a.selectedYear=e.getFullYear(),a.currentDay=d?e.getDate():0,a.currentMonth=d?e.getMonth():0,a.currentYear=d?e.getFullYear():0,this._adjustInstDate(a)},_getDefaultDate:function(a){return this._restrictMinMax(a,this._determineDate(a,this._get(a,"defaultDate"),new Date))},_determineDate:function(a,b,c){var d=function(a){var b=new Date;return b.setDate(b.getDate()+a),b},e=function(b){try{return $.datepicker.parseDate($.datepicker._get(a,"dateFormat"),b,$.datepicker._getFormatConfig(a))}catch(c){}var d=(b.toLowerCase().match(/^c/)?$.datepicker._getDate(a):null)||new Date,e=d.getFullYear(),f=d.getMonth(),g=d.getDate(),h=/([+-]?[0-9]+)\s*(d|D|w|W|m|M|y|Y)?/g,i=h.exec(b);while(i){switch(i[2]||"d"){case"d":case"D":g+=parseInt(i[1],10);break;case"w":case"W":g+=parseInt(i[1],10)*7;break;case"m":case"M":f+=parseInt(i[1],10),g=Math.min(g,$.datepicker._getDaysInMonth(e,f));break;case"y":case"Y":e+=parseInt(i[1],10),g=Math.min(g,$.datepicker._getDaysInMonth(e,f))}i=h.exec(b)}return new Date(e,f,g)},f=b==null||b===""?c:typeof b=="string"?e(b):typeof b=="number"?isNaN(b)?c:d(b):new Date(b.getTime());return f=f&&f.toString()=="Invalid Date"?c:f,f&&(f.setHours(0),f.setMinutes(0),f.setSeconds(0),f.setMilliseconds(0)),this._daylightSavingAdjust(f)},_daylightSavingAdjust:function(a){return a?(a.setHours(a.getHours()>12?a.getHours()+2:0),a):null},_setDate:function(a,b,c){var d=!b,e=a.selectedMonth,f=a.selectedYear,g=this._restrictMinMax(a,this._determineDate(a,b,new Date));a.selectedDay=a.currentDay=g.getDate(),a.drawMonth=a.selectedMonth=a.currentMonth=g.getMonth(),a.drawYear=a.selectedYear=a.currentYear=g.getFullYear(),(e!=a.selectedMonth||f!=a.selectedYear)&&!c&&this._notifyChange(a),this._adjustInstDate(a),a.input&&a.input.val(d?"":this._formatDate(a))},_getDate:function(a){var b=!a.currentYear||a.input&&a.input.val()==""?null:this._daylightSavingAdjust(new Date(a.currentYear,a.currentMonth,a.currentDay));return b},_attachHandlers:function(a){var b=this._get(a,"stepMonths"),c="#"+a.id.replace(/\\\\/g,"\\");a.dpDiv.find("[data-handler]").map(function(){var a={prev:function(){window["DP_jQuery_"+dpuuid].datepicker._adjustDate(c,-b,"M")},next:function(){window["DP_jQuery_"+dpuuid].datepicker._adjustDate(c,+b,"M")},hide:function(){window["DP_jQuery_"+dpuuid].datepicker._hideDatepicker()},today:function(){window["DP_jQuery_"+dpuuid].datepicker._gotoToday(c)},selectDay:function(){return window["DP_jQuery_"+dpuuid].datepicker._selectDay(c,+this.getAttribute("data-month"),+this.getAttribute("data-year"),this),!1},selectMonth:function(){return window["DP_jQuery_"+dpuuid].datepicker._selectMonthYear(c,this,"M"),!1},selectYear:function(){return window["DP_jQuery_"+dpuuid].datepicker._selectMonthYear(c,this,"Y"),!1}};$(this).bind(this.getAttribute("data-event"),a[this.getAttribute("data-handler")])})},_generateHTML:function(a){var b=new Date;b=this._daylightSavingAdjust(new Date(b.getFullYear(),b.getMonth(),b.getDate()));var c=this._get(a,"isRTL"),d=this._get(a,"showButtonPanel"),e=this._get(a,"hideIfNoPrevNext"),f=this._get(a,"navigationAsDateFormat"),g=this._getNumberOfMonths(a),h=this._get(a,"showCurrentAtPos"),i=this._get(a,"stepMonths"),j=g[0]!=1||g[1]!=1,k=this._daylightSavingAdjust(a.currentDay?new Date(a.currentYear,a.currentMonth,a.currentDay):new Date(9999,9,9)),l=this._getMinMaxDate(a,"min"),m=this._getMinMaxDate(a,"max"),n=a.drawMonth-h,o=a.drawYear;n<0&&(n+=12,o--);if(m){var p=this._daylightSavingAdjust(new Date(m.getFullYear(),m.getMonth()-g[0]*g[1]+1,m.getDate()));p=l&&p<l?l:p;while(this._daylightSavingAdjust(new Date(o,n,1))>p)n--,n<0&&(n=11,o--)}a.drawMonth=n,a.drawYear=o;var q=this._get(a,"prevText");q=f?this.formatDate(q,this._daylightSavingAdjust(new Date(o,n-i,1)),this._getFormatConfig(a)):q;var r=this._canAdjustMonth(a,-1,o,n)?'<a class="ui-datepicker-prev ui-corner-all" data-handler="prev" data-event="click" title="'+q+'"><span class="ui-icon ui-icon-circle-triangle-'+(c?"e":"w")+'">'+q+"</span></a>":e?"":'<a class="ui-datepicker-prev ui-corner-all ui-state-disabled" title="'+q+'"><span class="ui-icon ui-icon-circle-triangle-'+(c?"e":"w")+'">'+q+"</span></a>",s=this._get(a,"nextText");s=f?this.formatDate(s,this._daylightSavingAdjust(new Date(o,n+i,1)),this._getFormatConfig(a)):s;var t=this._canAdjustMonth(a,1,o,n)?'<a class="ui-datepicker-next ui-corner-all" data-handler="next" data-event="click" title="'+s+'"><span class="ui-icon ui-icon-circle-triangle-'+(c?"w":"e")+'">'+s+"</span></a>":e?"":'<a class="ui-datepicker-next ui-corner-all ui-state-disabled" title="'+s+'"><span class="ui-icon ui-icon-circle-triangle-'+(c?"w":"e")+'">'+s+"</span></a>",u=this._get(a,"currentText"),v=this._get(a,"gotoCurrent")&&a.currentDay?k:b;u=f?this.formatDate(u,v,this._getFormatConfig(a)):u;var w=a.inline?"":'<button type="button" class="ui-datepicker-close ui-state-default ui-priority-primary ui-corner-all" data-handler="hide" data-event="click">'+this._get(a,"closeText")+"</button>",x=d?'<div class="ui-datepicker-buttonpane ui-widget-content">'+(c?w:"")+(this._isInRange(a,v)?'<button type="button" class="ui-datepicker-current ui-state-default ui-priority-secondary ui-corner-all" data-handler="today" data-event="click">'+u+"</button>":"")+(c?"":w)+"</div>":"",y=parseInt(this._get(a,"firstDay"),10);y=isNaN(y)?0:y;var z=this._get(a,"showWeek"),A=this._get(a,"dayNames"),B=this._get(a,"dayNamesShort"),C=this._get(a,"dayNamesMin"),D=this._get(a,"monthNames"),E=this._get(a,"monthNamesShort"),F=this._get(a,"beforeShowDay"),G=this._get(a,"showOtherMonths"),H=this._get(a,"selectOtherMonths"),I=this._get(a,"calculateWeek")||this.iso8601Week,J=this._getDefaultDate(a),K="";for(var L=0;L<g[0];L++){var M="";this.maxRows=4;for(var N=0;N<g[1];N++){var O=this._daylightSavingAdjust(new Date(o,n,a.selectedDay)),P=" ui-corner-all",Q="";if(j){Q+='<div class="ui-datepicker-group';if(g[1]>1)switch(N){case 0:Q+=" ui-datepicker-group-first",P=" ui-corner-"+(c?"right":"left");break;case g[1]-1:Q+=" ui-datepicker-group-last",P=" ui-corner-"+(c?"left":"right");break;default:Q+=" ui-datepicker-group-middle",P=""}Q+='">'}Q+='<div class="ui-datepicker-header ui-widget-header ui-helper-clearfix'+P+'">'+(/all|left/.test(P)&&L==0?c?t:r:"")+(/all|right/.test(P)&&L==0?c?r:t:"")+this._generateMonthYearHeader(a,n,o,l,m,L>0||N>0,D,E)+'</div><table class="ui-datepicker-calendar"><thead>'+"<tr>";var R=z?'<th class="ui-datepicker-week-col">'+this._get(a,"weekHeader")+"</th>":"";for(var S=0;S<7;S++){var T=(S+y)%7;R+="<th"+((S+y+6)%7>=5?' class="ui-datepicker-week-end"':"")+">"+'<span title="'+A[T]+'">'+C[T]+"</span></th>"}Q+=R+"</tr></thead><tbody>";var U=this._getDaysInMonth(o,n);o==a.selectedYear&&n==a.selectedMonth&&(a.selectedDay=Math.min(a.selectedDay,U));var V=(this._getFirstDayOfMonth(o,n)-y+7)%7,W=Math.ceil((V+U)/7),X=j?this.maxRows>W?this.maxRows:W:W;this.maxRows=X;var Y=this._daylightSavingAdjust(new Date(o,n,1-V));for(var Z=0;Z<X;Z++){Q+="<tr>";var _=z?'<td class="ui-datepicker-week-col">'+this._get(a,"calculateWeek")(Y)+"</td>":"";for(var S=0;S<7;S++){var ba=F?F.apply(a.input?a.input[0]:null,[Y]):[!0,""],bb=Y.getMonth()!=n,bc=bb&&!H||!ba[0]||l&&Y<l||m&&Y>m;_+='<td class="'+((S+y+6)%7>=5?" ui-datepicker-week-end":"")+(bb?" ui-datepicker-other-month":"")+(Y.getTime()==O.getTime()&&n==a.selectedMonth&&a._keyEvent||J.getTime()==Y.getTime()&&J.getTime()==O.getTime()?" "+this._dayOverClass:"")+(bc?" "+this._unselectableClass+" ui-state-disabled":"")+(bb&&!G?"":" "+ba[1]+(Y.getTime()==k.getTime()?" "+this._currentClass:"")+(Y.getTime()==b.getTime()?" ui-datepicker-today":""))+'"'+((!bb||G)&&ba[2]?' title="'+ba[2]+'"':"")+(bc?"":' data-handler="selectDay" data-event="click" data-month="'+Y.getMonth()+'" data-year="'+Y.getFullYear()+'"')+">"+(bb&&!G?"&#xa0;":bc?'<span class="ui-state-default">'+Y.getDate()+"</span>":'<a class="ui-state-default'+(Y.getTime()==b.getTime()?" ui-state-highlight":"")+(Y.getTime()==k.getTime()?" ui-state-active":"")+(bb?" ui-priority-secondary":"")+'" href="#">'+Y.getDate()+"</a>")+"</td>",Y.setDate(Y.getDate()+1),Y=this._daylightSavingAdjust(Y)}Q+=_+"</tr>"}n++,n>11&&(n=0,o++),Q+="</tbody></table>"+(j?"</div>"+(g[0]>0&&N==g[1]-1?'<div class="ui-datepicker-row-break"></div>':""):""),M+=Q}K+=M}return K+=x+($.browser.msie&&parseInt($.browser.version,10)<7&&!a.inline?'<iframe src="javascript:false;" class="ui-datepicker-cover" frameborder="0"></iframe>':""),a._keyEvent=!1,K},_generateMonthYearHeader:function(a,b,c,d,e,f,g,h){var i=this._get(a,"changeMonth"),j=this._get(a,"changeYear"),k=this._get(a,"showMonthAfterYear"),l='<div class="ui-datepicker-title">',m="";if(f||!i)m+='<span class="ui-datepicker-month">'+g[b]+"</span>";else{var n=d&&d.getFullYear()==c,o=e&&e.getFullYear()==c;m+='<select class="ui-datepicker-month" data-handler="selectMonth" data-event="change">';for(var p=0;p<12;p++)(!n||p>=d.getMonth())&&(!o||p<=e.getMonth())&&(m+='<option value="'+p+'"'+(p==b?' selected="selected"':"")+">"+h[p]+"</option>");m+="</select>"}k||(l+=m+(f||!i||!j?"&#xa0;":""));if(!a.yearshtml){a.yearshtml="";if(f||!j)l+='<span class="ui-datepicker-year">'+c+"</span>";else{var q=this._get(a,"yearRange").split(":"),r=(new Date).getFullYear(),s=function(a){var b=a.match(/c[+-].*/)?c+parseInt(a.substring(1),10):a.match(/[+-].*/)?r+parseInt(a,10):parseInt(a,10);return isNaN(b)?r:b},t=s(q[0]),u=Math.max(t,s(q[1]||""));t=d?Math.max(t,d.getFullYear()):t,u=e?Math.min(u,e.getFullYear()):u,a.yearshtml+='<select class="ui-datepicker-year" data-handler="selectYear" data-event="change">';for(;t<=u;t++)a.yearshtml+='<option value="'+t+'"'+(t==c?' selected="selected"':"")+">"+t+"</option>";a.yearshtml+="</select>",l+=a.yearshtml,a.yearshtml=null}}return l+=this._get(a,"yearSuffix"),k&&(l+=(f||!i||!j?"&#xa0;":"")+m),l+="</div>",l},_adjustInstDate:function(a,b,c){var d=a.drawYear+(c=="Y"?b:0),e=a.drawMonth+(c=="M"?b:0),f=Math.min(a.selectedDay,this._getDaysInMonth(d,e))+(c=="D"?b:0),g=this._restrictMinMax(a,this._daylightSavingAdjust(new Date(d,e,f)));a.selectedDay=g.getDate(),a.drawMonth=a.selectedMonth=g.getMonth(),a.drawYear=a.selectedYear=g.getFullYear(),(c=="M"||c=="Y")&&this._notifyChange(a)},_restrictMinMax:function(a,b){var c=this._getMinMaxDate(a,"min"),d=this._getMinMaxDate(a,"max"),e=c&&b<c?c:b;return e=d&&e>d?d:e,e},_notifyChange:function(a){var b=this._get(a,"onChangeMonthYear");b&&b.apply(a.input?a.input[0]:null,[a.selectedYear,a.selectedMonth+1,a])},_getNumberOfMonths:function(a){var b=this._get(a,"numberOfMonths");return b==null?[1,1]:typeof b=="number"?[1,b]:b},_getMinMaxDate:function(a,b){return this._determineDate(a,this._get(a,b+"Date"),null)},_getDaysInMonth:function(a,b){return 32-this._daylightSavingAdjust(new Date(a,b,32)).getDate()},_getFirstDayOfMonth:function(a,b){return(new Date(a,b,1)).getDay()},_canAdjustMonth:function(a,b,c,d){var e=this._getNumberOfMonths(a),f=this._daylightSavingAdjust(new Date(c,d+(b<0?b:e[0]*e[1]),1));return b<0&&f.setDate(this._getDaysInMonth(f.getFullYear(),f.getMonth())),this._isInRange(a,f)},_isInRange:function(a,b){var c=this._getMinMaxDate(a,"min"),d=this._getMinMaxDate(a,"max");return(!c||b.getTime()>=c.getTime())&&(!d||b.getTime()<=d.getTime())},_getFormatConfig:function(a){var b=this._get(a,"shortYearCutoff");return b=typeof b!="string"?b:(new Date).getFullYear()%100+parseInt(b,10),{shortYearCutoff:b,dayNamesShort:this._get(a,"dayNamesShort"),dayNames:this._get(a,"dayNames"),monthNamesShort:this._get(a,"monthNamesShort"),monthNames:this._get(a,"monthNames")}},_formatDate:function(a,b,c,d){b||(a.currentDay=a.selectedDay,a.currentMonth=a.selectedMonth,a.currentYear=a.selectedYear);var e=b?typeof b=="object"?b:this._daylightSavingAdjust(new Date(d,c,b)):this._daylightSavingAdjust(new Date(a.currentYear,a.currentMonth,a.currentDay));return this.formatDate(this._get(a,"dateFormat"),e,this._getFormatConfig(a))}}),$.fn.datepicker=function(a){if(!this.length)return this;$.datepicker.initialized||($(document).mousedown($.datepicker._checkExternalClick).find("body").append($.datepicker.dpDiv),$.datepicker.initialized=!0);var b=Array.prototype.slice.call(arguments,1);return typeof a!="string"||a!="isDisabled"&&a!="getDate"&&a!="widget"?a=="option"&&arguments.length==2&&typeof arguments[1]=="string"?$.datepicker["_"+a+"Datepicker"].apply($.datepicker,[this[0]].concat(b)):this.each(function(){typeof a=="string"?$.datepicker["_"+a+"Datepicker"].apply($.datepicker,[this].concat(b)):$.datepicker._attachDatepicker(this,a)}):$.datepicker["_"+a+"Datepicker"].apply($.datepicker,[this[0]].concat(b))},$.datepicker=new Datepicker,$.datepicker.initialized=!1,$.datepicker.uuid=(new Date).getTime(),$.datepicker.version="1.8.23",window["DP_jQuery_"+dpuuid]=$})(jQuery);;/*! jQuery UI - v1.8.23 - 2012-08-15
    --* https://github.com/jquery/jquery-ui
    --* Includes: jquery.ui.progressbar.js
    --* Copyright (c) 2012 AUTHORS.txt; Licensed MIT, GPL */
    --(function(a,b){a.widget("ui.progressbar",{options:{value:0,max:100},min:0,_create:function(){this.element.addClass("ui-progressbar ui-widget ui-widget-content ui-corner-all").attr({role:"progressbar","aria-valuemin":this.min,"aria-valuemax":this.options.max,"aria-valuenow":this._value()}),this.valueDiv=a("<div class='ui-progressbar-value ui-widget-header ui-corner-left'></div>").appendTo(this.element),this.oldValue=this._value(),this._refreshValue()},destroy:function(){this.element.removeClass("ui-progressbar ui-widget ui-widget-content ui-corner-all").removeAttr("role").removeAttr("aria-valuemin").removeAttr("aria-valuemax").removeAttr("aria-valuenow"),this.valueDiv.remove(),a.Widget.prototype.destroy.apply(this,arguments)},value:function(a){return a===b?this._value():(this._setOption("value",a),this)},_setOption:function(b,c){b==="value"&&(this.options.value=c,this._refreshValue(),this._value()===this.options.max&&this._trigger("complete")),a.Widget.prototype._setOption.apply(this,arguments)},_value:function(){var a=this.options.value;return typeof a!="number"&&(a=0),Math.min(this.options.max,Math.max(this.min,a))},_percentage:function(){return 100*this._value()/this.options.max},_refreshValue:function(){var a=this.value(),b=this._percentage();this.oldValue!==a&&(this.oldValue=a,this._trigger("change")),this.valueDiv.toggle(a>this.min).toggleClass("ui-corner-right",a===this.options.max).width(b.toFixed(0)+"%"),this.element.attr("aria-valuenow",a)}}),a.extend(a.ui.progressbar,{version:"1.8.23"})})(jQuery);;/*! jQuery UI - v1.8.23 - 2012-08-15
    --* https://github.com/jquery/jquery-ui
    --* Includes: jquery.effects.core.js
    --* Copyright (c) 2012 AUTHORS.txt; Licensed MIT, GPL */
    --jQuery.effects||function(a,b){function c(b){var c;return b&&b.constructor==Array&&b.length==3?b:(c=/rgb\(\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*\)/.exec(b))?[parseInt(c[1],10),parseInt(c[2],10),parseInt(c[3],10)]:(c=/rgb\(\s*([0-9]+(?:\.[0-9]+)?)\%\s*,\s*([0-9]+(?:\.[0-9]+)?)\%\s*,\s*([0-9]+(?:\.[0-9]+)?)\%\s*\)/.exec(b))?[parseFloat(c[1])*2.55,parseFloat(c[2])*2.55,parseFloat(c[3])*2.55]:(c=/#([a-fA-F0-9]{2})([a-fA-F0-9]{2})([a-fA-F0-9]{2})/.exec(b))?[parseInt(c[1],16),parseInt(c[2],16),parseInt(c[3],16)]:(c=/#([a-fA-F0-9])([a-fA-F0-9])([a-fA-F0-9])/.exec(b))?[parseInt(c[1]+c[1],16),parseInt(c[2]+c[2],16),parseInt(c[3]+c[3],16)]:(c=/rgba\(0, 0, 0, 0\)/.exec(b))?e.transparent:e[a.trim(b).toLowerCase()]}function d(b,d){var e;do{e=(a.curCSS||a.css)(b,d);if(e!=""&&e!="transparent"||a.nodeName(b,"body"))break;d="backgroundColor"}while(b=b.parentNode);return c(e)}function h(){var a=document.defaultView?document.defaultView.getComputedStyle(this,null):this.currentStyle,b={},c,d;if(a&&a.length&&a[0]&&a[a[0]]){var e=a.length;while(e--)c=a[e],typeof a[c]=="string"&&(d=c.replace(/\-(\w)/g,function(a,b){return b.toUpperCase()}),b[d]=a[c])}else for(c in a)typeof a[c]=="string"&&(b[c]=a[c]);return b}function i(b){var c,d;for(c in b)d=b[c],(d==null||a.isFunction(d)||c in g||/scrollbar/.test(c)||!/color/i.test(c)&&isNaN(parseFloat(d)))&&delete b[c];return b}function j(a,b){var c={_:0},d;for(d in b)a[d]!=b[d]&&(c[d]=b[d]);return c}function k(b,c,d,e){typeof b=="object"&&(e=c,d=null,c=b,b=c.effect),a.isFunction(c)&&(e=c,d=null,c={});if(typeof c=="number"||a.fx.speeds[c])e=d,d=c,c={};return a.isFunction(d)&&(e=d,d=null),c=c||{},d=d||c.duration,d=a.fx.off?0:typeof d=="number"?d:d in a.fx.speeds?a.fx.speeds[d]:a.fx.speeds._default,e=e||c.complete,[b,c,d,e]}function l(b){return!b||typeof b=="number"||a.fx.speeds[b]?!0:typeof b=="string"&&!a.effects[b]?!0:!1}a.effects={},a.each(["backgroundColor","borderBottomColor","borderLeftColor","borderRightColor","borderTopColor","borderColor","color","outlineColor"],function(b,e){a.fx.step[e]=function(a){a.colorInit||(a.start=d(a.elem,e),a.end=c(a.end),a.colorInit=!0),a.elem.style[e]="rgb("+Math.max(Math.min(parseInt(a.pos*(a.end[0]-a.start[0])+a.start[0],10),255),0)+","+Math.max(Math.min(parseInt(a.pos*(a.end[1]-a.start[1])+a.start[1],10),255),0)+","+Math.max(Math.min(parseInt(a.pos*(a.end[2]-a.start[2])+a.start[2],10),255),0)+")"}});var e={aqua:[0,255,255],azure:[240,255,255],beige:[245,245,220],black:[0,0,0],blue:[0,0,255],brown:[165,42,42],cyan:[0,255,255],darkblue:[0,0,139],darkcyan:[0,139,139],darkgrey:[169,169,169],darkgreen:[0,100,0],darkkhaki:[189,183,107],darkmagenta:[139,0,139],darkolivegreen:[85,107,47],darkorange:[255,140,0],darkorchid:[153,50,204],darkred:[139,0,0],darksalmon:[233,150,122],darkviolet:[148,0,211],fuchsia:[255,0,255],gold:[255,215,0],green:[0,128,0],indigo:[75,0,130],khaki:[240,230,140],lightblue:[173,216,230],lightcyan:[224,255,255],lightgreen:[144,238,144],lightgrey:[211,211,211],lightpink:[255,182,193],lightyellow:[255,255,224],lime:[0,255,0],magenta:[255,0,255],maroon:[128,0,0],navy:[0,0,128],olive:[128,128,0],orange:[255,165,0],pink:[255,192,203],purple:[128,0,128],violet:[128,0,128],red:[255,0,0],silver:[192,192,192],white:[255,255,255],yellow:[255,255,0],transparent:[255,255,255]},f=["add","remove","toggle"],g={border:1,borderBottom:1,borderColor:1,borderLeft:1,borderRight:1,borderTop:1,borderWidth:1,margin:1,padding:1};a.effects.animateClass=function(b,c,d,e){return a.isFunction(d)&&(e=d,d=null),this.queue(function(){var g=a(this),k=g.attr("style")||" ",l=i(h.call(this)),m,n=g.attr("class")||"";a.each(f,function(a,c){b[c]&&g[c+"Class"](b[c])}),m=i(h.call(this)),g.attr("class",n),g.animate(j(l,m),{queue:!1,duration:c,easing:d,complete:function(){a.each(f,function(a,c){b[c]&&g[c+"Class"](b[c])}),typeof g.attr("style")=="object"?(g.attr("style").cssText="",g.attr("style").cssText=k):g.attr("style",k),e&&e.apply(this,arguments),a.dequeue(this)}})})},a.fn.extend({_addClass:a.fn.addClass,addClass:function(b,c,d,e){return c?a.effects.animateClass.apply(this,[{add:b},c,d,e]):this._addClass(b)},_removeClass:a.fn.removeClass,removeClass:function(b,c,d,e){return c?a.effects.animateClass.apply(this,[{remove:b},c,d,e]):this._removeClass(b)},_toggleClass:a.fn.toggleClass,toggleClass:function(c,d,e,f,g){return typeof d=="boolean"||d===b?e?a.effects.animateClass.apply(this,[d?{add:c}:{remove:c},e,f,g]):this._toggleClass(c,d):a.effects.animateClass.apply(this,[{toggle:c},d,e,f])},switchClass:function(b,c,d,e,f){return a.effects.animateClass.apply(this,[{add:c,remove:b},d,e,f])}}),a.extend(a.effects,{version:"1.8.23",save:function(a,b){for(var c=0;c<b.length;c++)b[c]!==null&&a.data("ec.storage."+b[c],a[0].style[b[c]])},restore:function(a,b){for(var c=0;c<b.length;c++)b[c]!==null&&a.css(b[c],a.data("ec.storage."+b[c]))},setMode:function(a,b){return b=="toggle"&&(b=a.is(":hidden")?"show":"hide"),b},getBaseline:function(a,b){var c,d;switch(a[0]){case"top":c=0;break;case"middle":c=.5;break;case"bottom":c=1;break;default:c=a[0]/b.height}switch(a[1]){case"left":d=0;break;case"center":d=.5;break;case"right":d=1;break;default:d=a[1]/b.width}return{x:d,y:c}},createWrapper:function(b){if(b.parent().is(".ui-effects-wrapper"))return b.parent();var c={width:b.outerWidth(!0),height:b.outerHeight(!0),"float":b.css("float")},d=a("<div></div>").addClass("ui-effects-wrapper").css({fontSize:"100%",background:"transparent",border:"none",margin:0,padding:0}),e=document.activeElement;try{e.id}catch(f){e=document.body}return b.wrap(d),(b[0]===e||a.contains(b[0],e))&&a(e).focus(),d=b.parent(),b.css("position")=="static"?(d.css({position:"relative"}),b.css({position:"relative"})):(a.extend(c,{position:b.css("position"),zIndex:b.css("z-index")}),a.each(["top","left","bottom","right"],function(a,d){c[d]=b.css(d),isNaN(parseInt(c[d],10))&&(c[d]="auto")}),b.css({position:"relative",top:0,left:0,right:"auto",bottom:"auto"})),d.css(c).show()},removeWrapper:function(b){var c,d=document.activeElement;return b.parent().is(".ui-effects-wrapper")?(c=b.parent().replaceWith(b),(b[0]===d||a.contains(b[0],d))&&a(d).focus(),c):b},setTransition:function(b,c,d,e){return e=e||{},a.each(c,function(a,c){var f=b.cssUnit(c);f[0]>0&&(e[c]=f[0]*d+f[1])}),e}}),a.fn.extend({effect:function(b,c,d,e){var f=k.apply(this,arguments),g={options:f[1],duration:f[2],callback:f[3]},h=g.options.mode,i=a.effects[b];return a.fx.off||!i?h?this[h](g.duration,g.callback):this.each(function(){g.callback&&g.callback.call(this)}):i.call(this,g)},_show:a.fn.show,show:function(a){if(l(a))return this._show.apply(this,arguments);var b=k.apply(this,arguments);return b[1].mode="show",this.effect.apply(this,b)},_hide:a.fn.hide,hide:function(a){if(l(a))return this._hide.apply(this,arguments);var b=k.apply(this,arguments);return b[1].mode="hide",this.effect.apply(this,b)},__toggle:a.fn.toggle,toggle:function(b){if(l(b)||typeof b=="boolean"||a.isFunction(b))return this.__toggle.apply(this,arguments);var c=k.apply(this,arguments);return c[1].mode="toggle",this.effect.apply(this,c)},cssUnit:function(b){var c=this.css(b),d=[];return a.each(["em","px","%","pt"],function(a,b){c.indexOf(b)>0&&(d=[parseFloat(c),b])}),d}});var m={};a.each(["Quad","Cubic","Quart","Quint","Expo"],function(a,b){m[b]=function(b){return Math.pow(b,a+2)}}),a.extend(m,{Sine:function(a){return 1-Math.cos(a*Math.PI/2)},Circ:function(a){return 1-Math.sqrt(1-a*a)},Elastic:function(a){return a===0||a===1?a:-Math.pow(2,8*(a-1))*Math.sin(((a-1)*80-7.5)*Math.PI/15)},Back:function(a){return a*a*(3*a-2)},Bounce:function(a){var b,c=4;while(a<((b=Math.pow(2,--c))-1)/11);return 1/Math.pow(4,3-c)-7.5625*Math.pow((b*3-2)/22-a,2)}}),a.each(m,function(b,c){a.easing["easeIn"+b]=c,a.easing["easeOut"+b]=function(a){return 1-c(1-a)},a.easing["easeInOut"+b]=function(a){return a<.5?c(a*2)/2:c(a*-2+2)/-2+1}})}(jQuery);;/*! jQuery UI - v1.8.23 - 2012-08-15
    --* https://github.com/jquery/jquery-ui
    --* Includes: jquery.effects.blind.js
    --* Copyright (c) 2012 AUTHORS.txt; Licensed MIT, GPL */
    --(function(a,b){a.effects.blind=function(b){return this.queue(function(){var c=a(this),d=["position","top","bottom","left","right"],e=a.effects.setMode(c,b.options.mode||"hide"),f=b.options.direction||"vertical";a.effects.save(c,d),c.show();var g=a.effects.createWrapper(c).css({overflow:"hidden"}),h=f=="vertical"?"height":"width",i=f=="vertical"?g.height():g.width();e=="show"&&g.css(h,0);var j={};j[h]=e=="show"?i:0,g.animate(j,b.duration,b.options.easing,function(){e=="hide"&&c.hide(),a.effects.restore(c,d),a.effects.removeWrapper(c),b.callback&&b.callback.apply(c[0],arguments),c.dequeue()})})}})(jQuery);;/*! jQuery UI - v1.8.23 - 2012-08-15
    --* https://github.com/jquery/jquery-ui
    --* Includes: jquery.effects.bounce.js
    --* Copyright (c) 2012 AUTHORS.txt; Licensed MIT, GPL */
    --(function(a,b){a.effects.bounce=function(b){return this.queue(function(){var c=a(this),d=["position","top","bottom","left","right"],e=a.effects.setMode(c,b.options.mode||"effect"),f=b.options.direction||"up",g=b.options.distance||20,h=b.options.times||5,i=b.duration||250;/show|hide/.test(e)&&d.push("opacity"),a.effects.save(c,d),c.show(),a.effects.createWrapper(c);var j=f=="up"||f=="down"?"top":"left",k=f=="up"||f=="left"?"pos":"neg",g=b.options.distance||(j=="top"?c.outerHeight(!0)/3:c.outerWidth(!0)/3);e=="show"&&c.css("opacity",0).css(j,k=="pos"?-g:g),e=="hide"&&(g=g/(h*2)),e!="hide"&&h--;if(e=="show"){var l={opacity:1};l[j]=(k=="pos"?"+=":"-=")+g,c.animate(l,i/2,b.options.easing),g=g/2,h--}for(var m=0;m<h;m++){var n={},p={};n[j]=(k=="pos"?"-=":"+=")+g,p[j]=(k=="pos"?"+=":"-=")+g,c.animate(n,i/2,b.options.easing).animate(p,i/2,b.options.easing),g=e=="hide"?g*2:g/2}if(e=="hide"){var l={opacity:0};l[j]=(k=="pos"?"-=":"+=")+g,c.animate(l,i/2,b.options.easing,function(){c.hide(),a.effects.restore(c,d),a.effects.removeWrapper(c),b.callback&&b.callback.apply(this,arguments)})}else{var n={},p={};n[j]=(k=="pos"?"-=":"+=")+g,p[j]=(k=="pos"?"+=":"-=")+g,c.animate(n,i/2,b.options.easing).animate(p,i/2,b.options.easing,function(){a.effects.restore(c,d),a.effects.removeWrapper(c),b.callback&&b.callback.apply(this,arguments)})}c.queue("fx",function(){c.dequeue()}),c.dequeue()})}})(jQuery);;/*! jQuery UI - v1.8.23 - 2012-08-15
    --* https://github.com/jquery/jquery-ui
    --* Includes: jquery.effects.clip.js
    --* Copyright (c) 2012 AUTHORS.txt; Licensed MIT, GPL */
    --(function(a,b){a.effects.clip=function(b){return this.queue(function(){var c=a(this),d=["position","top","bottom","left","right","height","width"],e=a.effects.setMode(c,b.options.mode||"hide"),f=b.options.direction||"vertical";a.effects.save(c,d),c.show();var g=a.effects.createWrapper(c).css({overflow:"hidden"}),h=c[0].tagName=="IMG"?g:c,i={size:f=="vertical"?"height":"width",position:f=="vertical"?"top":"left"},j=f=="vertical"?h.height():h.width();e=="show"&&(h.css(i.size,0),h.css(i.position,j/2));var k={};k[i.size]=e=="show"?j:0,k[i.position]=e=="show"?0:j/2,h.animate(k,{queue:!1,duration:b.duration,easing:b.options.easing,complete:function(){e=="hide"&&c.hide(),a.effects.restore(c,d),a.effects.removeWrapper(c),b.callback&&b.callback.apply(c[0],arguments),c.dequeue()}})})}})(jQuery);;/*! jQuery UI - v1.8.23 - 2012-08-15
    --* https://github.com/jquery/jquery-ui
    --* Includes: jquery.effects.drop.js
    --* Copyright (c) 2012 AUTHORS.txt; Licensed MIT, GPL */
    --(function(a,b){a.effects.drop=function(b){return this.queue(function(){var c=a(this),d=["position","top","bottom","left","right","opacity"],e=a.effects.setMode(c,b.options.mode||"hide"),f=b.options.direction||"left";a.effects.save(c,d),c.show(),a.effects.createWrapper(c);var g=f=="up"||f=="down"?"top":"left",h=f=="up"||f=="left"?"pos":"neg",i=b.options.distance||(g=="top"?c.outerHeight(!0)/2:c.outerWidth(!0)/2);e=="show"&&c.css("opacity",0).css(g,h=="pos"?-i:i);var j={opacity:e=="show"?1:0};j[g]=(e=="show"?h=="pos"?"+=":"-=":h=="pos"?"-=":"+=")+i,c.animate(j,{queue:!1,duration:b.duration,easing:b.options.easing,complete:function(){e=="hide"&&c.hide(),a.effects.restore(c,d),a.effects.removeWrapper(c),b.callback&&b.callback.apply(this,arguments),c.dequeue()}})})}})(jQuery);;/*! jQuery UI - v1.8.23 - 2012-08-15
    --* https://github.com/jquery/jquery-ui
    --* Includes: jquery.effects.explode.js
    --* Copyright (c) 2012 AUTHORS.txt; Licensed MIT, GPL */
    --(function(a,b){a.effects.explode=function(b){return this.queue(function(){var c=b.options.pieces?Math.round(Math.sqrt(b.options.pieces)):3,d=b.options.pieces?Math.round(Math.sqrt(b.options.pieces)):3;b.options.mode=b.options.mode=="toggle"?a(this).is(":visible")?"hide":"show":b.options.mode;var e=a(this).show().css("visibility","hidden"),f=e.offset();f.top-=parseInt(e.css("marginTop"),10)||0,f.left-=parseInt(e.css("marginLeft"),10)||0;var g=e.outerWidth(!0),h=e.outerHeight(!0);for(var i=0;i<c;i++)for(var j=0;j<d;j++)e.clone().appendTo("body").wrap("<div></div>").css({position:"absolute",visibility:"visible",left:-j*(g/d),top:-i*(h/c)}).parent().addClass("ui-effects-explode").css({position:"absolute",overflow:"hidden",width:g/d,height:h/c,left:f.left+j*(g/d)+(b.options.mode=="show"?(j-Math.floor(d/2))*(g/d):0),top:f.top+i*(h/c)+(b.options.mode=="show"?(i-Math.floor(c/2))*(h/c):0),opacity:b.options.mode=="show"?0:1}).animate({left:f.left+j*(g/d)+(b.options.mode=="show"?0:(j-Math.floor(d/2))*(g/d)),top:f.top+i*(h/c)+(b.options.mode=="show"?0:(i-Math.floor(c/2))*(h/c)),opacity:b.options.mode=="show"?1:0},b.duration||500);setTimeout(function(){b.options.mode=="show"?e.css({visibility:"visible"}):e.css({visibility:"visible"}).hide(),b.callback&&b.callback.apply(e[0]),e.dequeue(),a("div.ui-effects-explode").remove()},b.duration||500)})}})(jQuery);;/*! jQuery UI - v1.8.23 - 2012-08-15
    --* https://github.com/jquery/jquery-ui
    --* Includes: jquery.effects.fade.js
    --* Copyright (c) 2012 AUTHORS.txt; Licensed MIT, GPL */
    --(function(a,b){a.effects.fade=function(b){return this.queue(function(){var c=a(this),d=a.effects.setMode(c,b.options.mode||"hide");c.animate({opacity:d},{queue:!1,duration:b.duration,easing:b.options.easing,complete:function(){b.callback&&b.callback.apply(this,arguments),c.dequeue()}})})}})(jQuery);;/*! jQuery UI - v1.8.23 - 2012-08-15
    --* https://github.com/jquery/jquery-ui
    --* Includes: jquery.effects.fold.js
    --* Copyright (c) 2012 AUTHORS.txt; Licensed MIT, GPL */
    --(function(a,b){a.effects.fold=function(b){return this.queue(function(){var c=a(this),d=["position","top","bottom","left","right"],e=a.effects.setMode(c,b.options.mode||"hide"),f=b.options.size||15,g=!!b.options.horizFirst,h=b.duration?b.duration/2:a.fx.speeds._default/2;a.effects.save(c,d),c.show();var i=a.effects.createWrapper(c).css({overflow:"hidden"}),j=e=="show"!=g,k=j?["width","height"]:["height","width"],l=j?[i.width(),i.height()]:[i.height(),i.width()],m=/([0-9]+)%/.exec(f);m&&(f=parseInt(m[1],10)/100*l[e=="hide"?0:1]),e=="show"&&i.css(g?{height:0,width:f}:{height:f,width:0});var n={},p={};n[k[0]]=e=="show"?l[0]:f,p[k[1]]=e=="show"?l[1]:0,i.animate(n,h,b.options.easing).animate(p,h,b.options.easing,function(){e=="hide"&&c.hide(),a.effects.restore(c,d),a.effects.removeWrapper(c),b.callback&&b.callback.apply(c[0],arguments),c.dequeue()})})}})(jQuery);;/*! jQuery UI - v1.8.23 - 2012-08-15
    --* https://github.com/jquery/jquery-ui
    --* Includes: jquery.effects.highlight.js
    --* Copyright (c) 2012 AUTHORS.txt; Licensed MIT, GPL */
    --(function(a,b){a.effects.highlight=function(b){return this.queue(function(){var c=a(this),d=["backgroundImage","backgroundColor","opacity"],e=a.effects.setMode(c,b.options.mode||"show"),f={backgroundColor:c.css("backgroundColor")};e=="hide"&&(f.opacity=0),a.effects.save(c,d),c.show().css({backgroundImage:"none",backgroundColor:b.options.color||"#ffff99"}).animate(f,{queue:!1,duration:b.duration,easing:b.options.easing,complete:function(){e=="hide"&&c.hide(),a.effects.restore(c,d),e=="show"&&!a.support.opacity&&this.style.removeAttribute("filter"),b.callback&&b.callback.apply(this,arguments),c.dequeue()}})})}})(jQuery);;/*! jQuery UI - v1.8.23 - 2012-08-15
    --* https://github.com/jquery/jquery-ui
    --* Includes: jquery.effects.pulsate.js
    --* Copyright (c) 2012 AUTHORS.txt; Licensed MIT, GPL */
    --(function(a,b){a.effects.pulsate=function(b){return this.queue(function(){var c=a(this),d=a.effects.setMode(c,b.options.mode||"show"),e=(b.options.times||5)*2-1,f=b.duration?b.duration/2:a.fx.speeds._default/2,g=c.is(":visible"),h=0;g||(c.css("opacity",0).show(),h=1),(d=="hide"&&g||d=="show"&&!g)&&e--;for(var i=0;i<e;i++)c.animate({opacity:h},f,b.options.easing),h=(h+1)%2;c.animate({opacity:h},f,b.options.easing,function(){h==0&&c.hide(),b.callback&&b.callback.apply(this,arguments)}),c.queue("fx",function(){c.dequeue()}).dequeue()})}})(jQuery);;/*! jQuery UI - v1.8.23 - 2012-08-15
    --* https://github.com/jquery/jquery-ui
    --* Includes: jquery.effects.scale.js
    --* Copyright (c) 2012 AUTHORS.txt; Licensed MIT, GPL */
    --(function(a,b){a.effects.puff=function(b){return this.queue(function(){var c=a(this),d=a.effects.setMode(c,b.options.mode||"hide"),e=parseInt(b.options.percent,10)||150,f=e/100,g={height:c.height(),width:c.width()};a.extend(b.options,{fade:!0,mode:d,percent:d=="hide"?e:100,from:d=="hide"?g:{height:g.height*f,width:g.width*f}}),c.effect("scale",b.options,b.duration,b.callback),c.dequeue()})},a.effects.scale=function(b){return this.queue(function(){var c=a(this),d=a.extend(!0,{},b.options),e=a.effects.setMode(c,b.options.mode||"effect"),f=parseInt(b.options.percent,10)||(parseInt(b.options.percent,10)==0?0:e=="hide"?0:100),g=b.options.direction||"both",h=b.options.origin;e!="effect"&&(d.origin=h||["middle","center"],d.restore=!0);var i={height:c.height(),width:c.width()};c.from=b.options.from||(e=="show"?{height:0,width:0}:i);var j={y:g!="horizontal"?f/100:1,x:g!="vertical"?f/100:1};c.to={height:i.height*j.y,width:i.width*j.x},b.options.fade&&(e=="show"&&(c.from.opacity=0,c.to.opacity=1),e=="hide"&&(c.from.opacity=1,c.to.opacity=0)),d.from=c.from,d.to=c.to,d.mode=e,c.effect("size",d,b.duration,b.callback),c.dequeue()})},a.effects.size=function(b){return this.queue(function(){var c=a(this),d=["position","top","bottom","left","right","width","height","overflow","opacity"],e=["position","top","bottom","left","right","overflow","opacity"],f=["width","height","overflow"],g=["fontSize"],h=["borderTopWidth","borderBottomWidth","paddingTop","paddingBottom"],i=["borderLeftWidth","borderRightWidth","paddingLeft","paddingRight"],j=a.effects.setMode(c,b.options.mode||"effect"),k=b.options.restore||!1,l=b.options.scale||"both",m=b.options.origin,n={height:c.height(),width:c.width()};c.from=b.options.from||n,c.to=b.options.to||n;if(m){var p=a.effects.getBaseline(m,n);c.from.top=(n.height-c.from.height)*p.y,c.from.left=(n.width-c.from.width)*p.x,c.to.top=(n.height-c.to.height)*p.y,c.to.left=(n.width-c.to.width)*p.x}var q={from:{y:c.from.height/n.height,x:c.from.width/n.width},to:{y:c.to.height/n.height,x:c.to.width/n.width}};if(l=="box"||l=="both")q.from.y!=q.to.y&&(d=d.concat(h),c.from=a.effects.setTransition(c,h,q.from.y,c.from),c.to=a.effects.setTransition(c,h,q.to.y,c.to)),q.from.x!=q.to.x&&(d=d.concat(i),c.from=a.effects.setTransition(c,i,q.from.x,c.from),c.to=a.effects.setTransition(c,i,q.to.x,c.to));(l=="content"||l=="both")&&q.from.y!=q.to.y&&(d=d.concat(g),c.from=a.effects.setTransition(c,g,q.from.y,c.from),c.to=a.effects.setTransition(c,g,q.to.y,c.to)),a.effects.save(c,k?d:e),c.show(),a.effects.createWrapper(c),c.css("overflow","hidden").css(c.from);if(l=="content"||l=="both")h=h.concat(["marginTop","marginBottom"]).concat(g),i=i.concat(["marginLeft","marginRight"]),f=d.concat(h).concat(i),c.find("*[width]").each(function(){var c=a(this);k&&a.effects.save(c,f);var d={height:c.height(),width:c.width()};c.from={height:d.height*q.from.y,width:d.width*q.from.x},c.to={height:d.height*q.to.y,width:d.width*q.to.x},q.from.y!=q.to.y&&(c.from=a.effects.setTransition(c,h,q.from.y,c.from),c.to=a.effects.setTransition(c,h,q.to.y,c.to)),q.from.x!=q.to.x&&(c.from=a.effects.setTransition(c,i,q.from.x,c.from),c.to=a.effects.setTransition(c,i,q.to.x,c.to)),c.css(c.from),c.animate(c.to,b.duration,b.options.easing,function(){k&&a.effects.restore(c,f)})});c.animate(c.to,{queue:!1,duration:b.duration,easing:b.options.easing,complete:function(){c.to.opacity===0&&c.css("opacity",c.from.opacity),j=="hide"&&c.hide(),a.effects.restore(c,k?d:e),a.effects.removeWrapper(c),b.callback&&b.callback.apply(this,arguments),c.dequeue()}})})}})(jQuery);;/*! jQuery UI - v1.8.23 - 2012-08-15
    --* https://github.com/jquery/jquery-ui
    --* Includes: jquery.effects.shake.js
    --* Copyright (c) 2012 AUTHORS.txt; Licensed MIT, GPL */
    --(function(a,b){a.effects.shake=function(b){return this.queue(function(){var c=a(this),d=["position","top","bottom","left","right"],e=a.effects.setMode(c,b.options.mode||"effect"),f=b.options.direction||"left",g=b.options.distance||20,h=b.options.times||3,i=b.duration||b.options.duration||140;a.effects.save(c,d),c.show(),a.effects.createWrapper(c);var j=f=="up"||f=="down"?"top":"left",k=f=="up"||f=="left"?"pos":"neg",l={},m={},n={};l[j]=(k=="pos"?"-=":"+=")+g,m[j]=(k=="pos"?"+=":"-=")+g*2,n[j]=(k=="pos"?"-=":"+=")+g*2,c.animate(l,i,b.options.easing);for(var p=1;p<h;p++)c.animate(m,i,b.options.easing).animate(n,i,b.options.easing);c.animate(m,i,b.options.easing).animate(l,i/2,b.options.easing,function(){a.effects.restore(c,d),a.effects.removeWrapper(c),b.callback&&b.callback.apply(this,arguments)}),c.queue("fx",function(){c.dequeue()}),c.dequeue()})}})(jQuery);;/*! jQuery UI - v1.8.23 - 2012-08-15
    --* https://github.com/jquery/jquery-ui
    --* Includes: jquery.effects.slide.js
    --* Copyright (c) 2012 AUTHORS.txt; Licensed MIT, GPL */
    --(function(a,b){a.effects.slide=function(b){return this.queue(function(){var c=a(this),d=["position","top","bottom","left","right"],e=a.effects.setMode(c,b.options.mode||"show"),f=b.options.direction||"left";a.effects.save(c,d),c.show(),a.effects.createWrapper(c).css({overflow:"hidden"});var g=f=="up"||f=="down"?"top":"left",h=f=="up"||f=="left"?"pos":"neg",i=b.options.distance||(g=="top"?c.outerHeight(!0):c.outerWidth(!0));e=="show"&&c.css(g,h=="pos"?isNaN(i)?"-"+i:-i:i);var j={};j[g]=(e=="show"?h=="pos"?"+=":"-=":h=="pos"?"-=":"+=")+i,c.animate(j,{queue:!1,duration:b.duration,easing:b.options.easing,complete:function(){e=="hide"&&c.hide(),a.effects.restore(c,d),a.effects.removeWrapper(c),b.callback&&b.callback.apply(this,arguments),c.dequeue()}})})}})(jQuery);;/*! jQuery UI - v1.8.23 - 2012-08-15
    --* https://github.com/jquery/jquery-ui
    --* Includes: jquery.effects.transfer.js
    --* Copyright (c) 2012 AUTHORS.txt; Licensed MIT, GPL */
    --(function(a,b){a.effects.transfer=function(b){return this.queue(function(){var c=a(this),d=a(b.options.to),e=d.offset(),f={top:e.top,left:e.left,height:d.innerHeight(),width:d.innerWidth()},g=c.offset(),h=a('<div class="ui-effects-transfer"></div>').appendTo(document.body).addClass(b.options.className).css({top:g.top,left:g.left,height:c.innerHeight(),width:c.innerWidth(),position:"absolute"}).animate(f,b.duration,b.options.easing,function(){h.remove(),b.callback&&b.callback.apply(c[0],arguments),c.dequeue()})})}})(jQuery);;
    --/*! (c) 2012 Airbnb, Inc.
    --*
    --* polyglot.js 0.4.3 may be freely distributed under the terms of the BSD
    --* license. For all licensing information, details, and documention:
    --* http://airbnb.github.com/polyglot.js */
    --(function(e,t){typeof define=="function"&&define.amd?define([],function(){return t(e)}):typeof exports=="object"?module.exports=t(e):e.Polyglot=t(e)})(this,function(e){"use strict";function t(e){e=e||{},this.phrases={},this.extend(e.phrases||{}),this.currentLocale=e.locale||"en",this.allowMissing=!!e.allowMissing,this.warn=e.warn||c}function s(e){var t,n,r,i={};for(t in e)if(e.hasOwnProperty(t)){n=e[t];for(r in n)i[n[r]]=t}return i}function o(e){var t=/^\s+|\s+$/g;return e.replace(t,"")}function u(e,t,r){var i,s,u;return r!=null&&e?(s=e.split(n),u=s[f(t,r)]||s[0],i=o(u)):i=e,i}function a(e){var t=s(i);return t[e]||t.en}function f(e,t){return r[a(e)](t)}function l(e,t){for(var n in t)n!=="_"&&t.hasOwnProperty(n)&&(e=e.replace(new RegExp("%\\{"+n+"\\}","g"),t[n]));return e}function c(t){e.console&&e.console.warn&&e.console.warn("WARNING: "+t)}function h(e){var t={};for(var n in e)t[n]=e[n];return t}t.VERSION="0.4.3",t.prototype.locale=function(e){return e&&(this.currentLocale=e),this.currentLocale},t.prototype.extend=function(e,t){var n;for(var r in e)e.hasOwnProperty(r)&&(n=e[r],t&&(r=t+"."+r),typeof n=="object"?this.extend(n,r):this.phrases[r]=n)},t.prototype.clear=function(){this.phrases={}},t.prototype.replace=function(e){this.clear(),this.extend(e)},t.prototype.t=function(e,t){var n,r;return t=t==null?{}:t,typeof t=="number"&&(t={smart_count:t}),typeof this.phrases[e]=="string"?n=this.phrases[e]:typeof t._=="string"?n=t._:this.allowMissing?n=e:(this.warn('Missing translation for key: "'+e+'"'),r=e),typeof n=="string"&&(t=h(t),r=u(n,this.currentLocale,t.smart_count),r=l(r,t)),r},t.prototype.has=function(e){return e in this.phrases};var n="||||",r={chinese:function(e){return 0},german:function(e){return e!==1?1:0},french:function(e){return e>1?1:0},russian:function(e){return e%10===1&&e%100!==11?0:e%10>=2&&e%10<=4&&(e%100<10||e%100>=20)?1:2},czech:function(e){return e===1?0:e>=2&&e<=4?1:2},polish:function(e){return e===1?0:e%10>=2&&e%10<=4&&(e%100<10||e%100>=20)?1:2},icelandic:function(e){return e%10!==1||e%100===11?1:0}},i={chinese:["fa","id","ja","ko","lo","ms","th","tr","zh"],german:["da","de","en","es","fi","el","he","hu","it","nl","no","pt","sv"],french:["fr","tl","pt-br"],russian:["hr","ru"],czech:["cs"],polish:["pl"],icelandic:["is"]};return t});
    -diff --git a/tools/droiddoc/templates-sdk-dev/assets/js/docs.js b/tools/droiddoc/templates-sdk-dev/assets/js/docs.js
    -deleted file mode 100644
    -index 5ed947c..0000000
    ---- a/tools/droiddoc/templates-sdk-dev/assets/js/docs.js
    -+++ /dev/null
    -@@ -1,6690 +0,0 @@
    --var cookie_namespace = 'android_developer';
    --var isMobile = false; // true if mobile, so we can adjust some layout
    --var mPagePath; // initialized in ready() function
    --
    --var basePath = getBaseUri(location.pathname);
    --var SITE_ROOT = toRoot + basePath.substring(1, basePath.indexOf("/", 1));
    --
    --// TODO(akassay) generate this var in the reference doc build.
    --var API_LEVELS = ['1', '2', '3', '4', '5', '6', '7', '8', '9',
    --      '10', '11', '12', '13', '14', '15', '16',
    --      '17', '18', '19', '20', '21', '22', '23', '24'];
    --var METADATA = METADATA || {};
    --var RESERVED_METADATA_CATEGORY_NAMES = ['extras', 'carousel', 'collections',
    --                                        'searchHeroCollections'];
    --
    --// Ensure that all ajax getScript() requests allow caching
    --$.ajaxSetup({
    --  cache: true
    --});
    --
    --/******  ON LOAD SET UP STUFF *********/
    --
    --$(document).ready(function() {
    --
    --  // prep nav expandos
    --  var pagePath = location.href.replace(location.hash, '');
    --  // account for intl docs by removing the intl/*/ path
    --  if (pagePath.indexOf("/intl/") == 0) {
    --    pagePath = pagePath.substr(pagePath.indexOf("/", 6)); // start after intl/ to get last /
    --  }
    --
    --  if (pagePath.indexOf(SITE_ROOT) == 0) {
    --    if (pagePath == '' || pagePath.charAt(pagePath.length - 1) == '/') {
    --      pagePath += 'index.html';
    --    }
    --  }
    --
    --  // Need a copy of the pagePath before it gets changed in the next block;
    --  // it's needed to perform proper tab highlighting in offline docs (see rootDir below)
    --  var pagePathOriginal = pagePath;
    --  if (SITE_ROOT.match(/\.\.\//) || SITE_ROOT == '') {
    --    // If running locally, SITE_ROOT will be a relative path, so account for that by
    --    // finding the relative URL to this page. This will allow us to find links on the page
    --    // leading back to this page.
    --    var pathParts = pagePath.split('/');
    --    var relativePagePathParts = [];
    --    var upDirs = (SITE_ROOT.match(/(\.\.\/)+/) || [''])[0].length / 3;
    --    for (var i = 0; i < upDirs; i++) {
    --      relativePagePathParts.push('..');
    --    }
    --    for (var i = 0; i < upDirs; i++) {
    --      relativePagePathParts.push(pathParts[pathParts.length - (upDirs - i) - 1]);
    --    }
    --    relativePagePathParts.push(pathParts[pathParts.length - 1]);
    --    pagePath = relativePagePathParts.join('/');
    --  } else {
    --    // Otherwise the page path is already an absolute URL
    --  }
    --
    --  // set global variable so we can highlight the sidenav a bit later (such as for google reference)
    --  // and highlight the sidenav
    --  mPagePath = pagePath;
    --
    --  // Check for params and remove them.
    --  mPagePath = mPagePath.split('?')[0];
    --  highlightSidenav();
    --
    --  // set up prev/next links if they exist
    --  var $selNavLink = $('#nav').find('a[href="' + pagePath + '"]');
    --  var $selListItem;
    --  if ($selNavLink.length) {
    --    $selListItem = $selNavLink.closest('li');
    --
    --    // set up prev links
    --    var $prevLink = [];
    --    var $prevListItem = $selListItem.prev('li');
    --
    --    var crossBoundaries = ($("body.design").length > 0) || ($("body.guide").length > 0) ? true :
    --false; // navigate across topic boundaries only in design docs
    --    if ($prevListItem.length) {
    --      if ($prevListItem.hasClass('nav-section') || crossBoundaries) {
    --        // jump to last topic of previous section
    --        $prevLink = $prevListItem.find('a:last');
    --      } else if (!$selListItem.hasClass('nav-section')) {
    --        // jump to previous topic in this section
    --        $prevLink = $prevListItem.find('a:eq(0)');
    --      }
    --    } else {
    --      // jump to this section's index page (if it exists)
    --      var $parentListItem = $selListItem.parents('li');
    --      $prevLink = $selListItem.parents('li').find('a');
    --
    --      // except if cross boundaries aren't allowed, and we're at the top of a section already
    --      // (and there's another parent)
    --      if (!crossBoundaries && $parentListItem.hasClass('nav-section') &&
    --                           $selListItem.hasClass('nav-section')) {
    --        $prevLink = [];
    --      }
    --    }
    --
    --    // set up next links
    --    var $nextLink = [];
    --    var startClass = false;
    --    var isCrossingBoundary = false;
    --
    --    if ($selListItem.hasClass('nav-section') && $selListItem.children('div.empty').length == 0) {
    --      // we're on an index page, jump to the first topic
    --      $nextLink = $selListItem.find('ul:eq(0)').find('a:eq(0)');
    --
    --      // if there aren't any children, go to the next section (required for About pages)
    --      if ($nextLink.length == 0) {
    --        $nextLink = $selListItem.next('li').find('a');
    --      } else if ($('.topic-start-link').length) {
    --        // as long as there's a child link and there is a "topic start link" (we're on a landing)
    --        // then set the landing page "start link" text to be the first doc title
    --        $('.topic-start-link').text($nextLink.text().toUpperCase());
    --      }
    --
    --      // If the selected page has a description, then it's a class or article homepage
    --      if ($selListItem.find('a[description]').length) {
    --        // this means we're on a class landing page
    --        startClass = true;
    --      }
    --    } else {
    --      // jump to the next topic in this section (if it exists)
    --      $nextLink = $selListItem.next('li').find('a:eq(0)');
    --      if ($nextLink.length == 0) {
    --        isCrossingBoundary = true;
    --        // no more topics in this section, jump to the first topic in the next section
    --        $nextLink = $selListItem.parents('li:eq(0)').next('li').find('a:eq(0)');
    --        if (!$nextLink.length) {  // Go up another layer to look for next page (lesson > class > course)
    --          $nextLink = $selListItem.parents('li:eq(1)').next('li.nav-section').find('a:eq(0)');
    --          if ($nextLink.length == 0) {
    --            // if that doesn't work, we're at the end of the list, so disable NEXT link
    --            $('.next-page-link').attr('href', '').addClass("disabled")
    --                                .click(function() { return false; });
    --            // and completely hide the one in the footer
    --            $('.content-footer .next-page-link').hide();
    --          }
    --        }
    --      }
    --    }
    --
    --    if (startClass) {
    --      $('.start-class-link').attr('href', $nextLink.attr('href')).removeClass("hide");
    --
    --      // if there's no training bar (below the start button),
    --      // then we need to add a bottom border to button
    --      if (!$("#tb").length) {
    --        $('.start-class-link').css({'border-bottom':'1px solid #DADADA'});
    --      }
    --    } else if (isCrossingBoundary && !$('body.design').length) {  // Design always crosses boundaries
    --      $('.content-footer.next-class').show();
    --      $('.next-page-link').attr('href', '')
    --                          .removeClass("hide").addClass("disabled")
    --                          .click(function() { return false; });
    --      // and completely hide the one in the footer
    --      $('.content-footer .next-page-link').hide();
    --      $('.content-footer .prev-page-link').hide();
    --
    --      if ($nextLink.length) {
    --        $('.next-class-link').attr('href', $nextLink.attr('href'))
    --                             .removeClass("hide");
    --
    --        $('.content-footer .next-class-link').append($nextLink.html());
    --
    --        $('.next-class-link').find('.new').empty();
    --      }
    --    } else {
    --      $('.next-page-link').attr('href', $nextLink.attr('href'))
    --                          .removeClass("hide");
    --      // for the footer link, also add the previous and next page titles
    --      if ($prevLink.length) {
    --        $('.content-footer .prev-page-link').append($prevLink.html());
    --      }
    --      if ($nextLink.length) {
    --        $('.content-footer .next-page-link').append($nextLink.html());
    --      }
    --    }
    --
    --    if (!startClass && $prevLink.length) {
    --      var prevHref = $prevLink.attr('href');
    --      if (prevHref == SITE_ROOT + 'index.html') {
    --        // Don't show Previous when it leads to the homepage
    --      } else {
    --        $('.prev-page-link').attr('href', $prevLink.attr('href')).removeClass("hide");
    --      }
    --    }
    --  }
    --
    --  // Set up the course landing pages for Training with class names and descriptions
    --  if ($('body.trainingcourse').length) {
    --    var $classLinks = $selListItem.find('ul li a').not('#nav .nav-section .nav-section ul a');
    --
    --    // create an array for all the class descriptions
    --    var $classDescriptions = new Array($classLinks.length);
    --    var lang = getLangPref();
    --    $classLinks.each(function(index) {
    --      var langDescr = $(this).attr(lang + "-description");
    --      if (typeof langDescr !== 'undefined' && langDescr !== false) {
    --        // if there's a class description in the selected language, use that
    --        $classDescriptions[index] = langDescr;
    --      } else {
    --        // otherwise, use the default english description
    --        $classDescriptions[index] = $(this).attr("description");
    --      }
    --    });
    --
    --    var $olClasses  = $('<ol class="class-list"></ol>');
    --    var $liClass;
    --    var $h2Title;
    --    var $pSummary;
    --    var $olLessons;
    --    var $liLesson;
    --    $classLinks.each(function(index) {
    --      $liClass  = $('<li class="clearfix"></li>');
    --      $h2Title  = $('<a class="title" href="' + $(this).attr('href') + '"><h2 class="norule">' + $(this).html() + '</h2><span></span></a>');
    --      $pSummary = $('<p class="description">' + $classDescriptions[index] + '</p>');
    --
    --      $olLessons  = $('<ol class="lesson-list"></ol>');
    --
    --      $lessons = $(this).closest('li').find('ul li a');
    --
    --      if ($lessons.length) {
    --        $lessons.each(function(index) {
    --          $olLessons.append('<li><a href="' + $(this).attr('href') + '">' + $(this).html() + '</a></li>');
    --        });
    --      } else {
    --        $pSummary.addClass('article');
    --      }
    --
    --      $liClass.append($h2Title).append($pSummary).append($olLessons);
    --      $olClasses.append($liClass);
    --    });
    --    $('#classes').append($olClasses);
    --  }
    --
    --  // Set up expand/collapse behavior
    --  initExpandableNavItems("#nav");
    --
    --  // Set up play-on-hover <video> tags.
    --  $('video.play-on-hover').bind('click', function() {
    --    $(this).get(0).load(); // in case the video isn't seekable
    --    $(this).get(0).play();
    --  });
    --
    --  // Set up play-on-click for <video> tags with a "video-wrapper".
    --  $('.video-wrapper > video').bind('click', function() {
    --    this.play();
    --    $(this.parentElement).addClass('playing');
    --  });
    --
    --  // Set up tooltips
    --  var TOOLTIP_MARGIN = 10;
    --  $('acronym,.tooltip-link').each(function() {
    --    var $target = $(this);
    --    var $tooltip = $('<div>')
    --        .addClass('tooltip-box')
    --        .append($target.attr('title'))
    --        .hide()
    --        .appendTo('body');
    --    $target.removeAttr('title');
    --
    --    $target.hover(function() {
    --      // in
    --      var targetRect = $target.offset();
    --      targetRect.width = $target.width();
    --      targetRect.height = $target.height();
    --
    --      $tooltip.css({
    --        left: targetRect.left,
    --        top: targetRect.top + targetRect.height + TOOLTIP_MARGIN
    --      });
    --      $tooltip.addClass('below');
    --      $tooltip.show();
    --    }, function() {
    --      // out
    --      $tooltip.hide();
    --    });
    --  });
    --
    --  // Set up <h2> deeplinks
    --  $('h2').click(function() {
    --    var id = $(this).attr('id');
    --    if (id) {
    --      if (history && history.replaceState) {
    --        // Change url without scrolling.
    --        history.replaceState({}, '', '#' + id);
    --      } else {
    --        document.location.hash = id;
    --      }
    --    }
    --  });
    --
    --  //Loads the +1 button
    --  //var po = document.createElement('script'); po.type = 'text/javascript'; po.async = true;
    --  //po.src = 'https://apis.google.com/js/plusone.js';
    --  //var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(po, s);
    --});
    --// END of the onload event
    --
    --function initExpandableNavItems(rootTag) {
    --  var toggleIcon = $(
    --      rootTag + ' li.nav-section .nav-section-header .toggle-icon, ' +
    --      rootTag + ' li.nav-section .nav-section-header a[href="#"]');
    --
    --  toggleIcon.on('click keypress', function(e) {
    --    if (e.type == 'keypress' && e.which == 13 || e.type == 'click') {
    --      doNavToggle(this);
    --    }
    --  });
    --
    --  // Stop expand/collapse behavior when clicking on nav section links
    --  // (since we're navigating away from the page)
    --  // This selector captures the first instance of <a>, but not those with "#" as the href.
    --  $('.nav-section-header').find('a:eq(0)').not('a[href="#"]').click(function(evt) {
    --    window.location.href = $(this).attr('href');
    --    return false;
    --  });
    --}
    --
    --function doNavToggle(el) {
    --  var section = $(el).closest('li.nav-section');
    --  if (section.hasClass('expanded')) {
    --    /* hide me and descendants */
    --    section.find('ul').slideUp(250, function() {
    --      // remove 'expanded' class from my section and any children
    --      section.closest('li').removeClass('expanded');
    --      $('li.nav-section', section).removeClass('expanded');
    --    });
    --  } else {
    --    /* show me */
    --    // first hide all other siblings
    --    var $others = $('li.nav-section.expanded', $(el).closest('ul')).not('.sticky');
    --    $others.removeClass('expanded').children('ul').slideUp(250);
    --
    --    // now expand me
    --    section.closest('li').addClass('expanded');
    --    section.children('ul').slideDown(250);
    --  }
    --}
    --
    --/** Highlight the current page in sidenav, expanding children as appropriate */
    --function highlightSidenav() {
    --  // if something is already highlighted, undo it. This is for dynamic navigation (Samples index)
    --  if ($("ul#nav li.selected").length) {
    --    unHighlightSidenav();
    --  }
    --  // look for URL in sidenav, including the hash
    --  var $selNavLink = $('#nav').find('a[href="' + mPagePath + location.hash + '"]');
    --
    --  // If the selNavLink is still empty, look for it without the hash
    --  if ($selNavLink.length == 0) {
    --    $selNavLink = $('#nav').find('a[href="' + mPagePath + '"]');
    --  }
    --
    --  var $selListItem;
    --  var breadcrumb = [];
    --
    --  if ($selNavLink.length) {
    --    // Find this page's <li> in sidenav and set selected
    --    $selListItem = $selNavLink.closest('li');
    --    $selListItem.addClass('selected');
    --
    --    // Traverse up the tree and expand all parent nav-sections
    --    $selNavLink.parents('li.nav-section').each(function() {
    --      $(this).addClass('expanded');
    --      $(this).children('ul').show();
    --
    --      var link = $(this).find('a').first();
    --
    --      if (!$(this).is($selListItem)) {
    --        breadcrumb.unshift(link)
    --      }
    --    });
    --
    --    $('#nav').scrollIntoView($selNavLink);
    --  }
    --
    --  breadcrumb.forEach(function(link) {
    --    link.dacCrumbs();
    --  });
    --}
    --
    --function unHighlightSidenav() {
    --  $("ul#nav li.selected").removeClass("selected");
    --  $('ul#nav li.nav-section.expanded').removeClass('expanded').children('ul').hide();
    --}
    --
    --var agent = navigator['userAgent'].toLowerCase();
    --// If a mobile phone, set flag and do mobile setup
    --if ((agent.indexOf("mobile") != -1) ||      // android, iphone, ipod
    --    (agent.indexOf("blackberry") != -1) ||
    --    (agent.indexOf("webos") != -1) ||
    --    (agent.indexOf("mini") != -1)) {        // opera mini browsers
    --  isMobile = true;
    --}
    --
    --$(document).ready(function() {
    --  $("pre:not(.no-pretty-print)").addClass("prettyprint");
    --  prettyPrint();
    --});
    --
    --/* Show popup dialogs */
    --function showDialog(id) {
    --  $dialog = $("#" + id);
    --  $dialog.prepend('<div class="box-border"><div class="top"> <div class="left"></div> <div class="right"></div></div><div class="bottom"> <div class="left"></div> <div class="right"></div> </div> </div>');
    --  $dialog.wrapInner('<div/>');
    --  $dialog.removeClass("hide");
    --}
    --
    --/* #########    COOKIES!     ########## */
    --
    --function readCookie(cookie) {
    --  var myCookie = cookie_namespace + "_" + cookie + "=";
    --  if (document.cookie) {
    --    var index = document.cookie.indexOf(myCookie);
    --    if (index != -1) {
    --      var valStart = index + myCookie.length;
    --      var valEnd = document.cookie.indexOf(";", valStart);
    --      if (valEnd == -1) {
    --        valEnd = document.cookie.length;
    --      }
    --      var val = document.cookie.substring(valStart, valEnd);
    --      return val;
    --    }
    --  }
    --  return 0;
    --}
    --
    --function writeCookie(cookie, val, section) {
    --  if (val == undefined) return;
    --  section = section == null ? "_" : "_" + section + "_";
    --  var age = 2 * 365 * 24 * 60 * 60; // set max-age to 2 years
    --  var cookieValue = cookie_namespace + section + cookie + "=" + val +
    --                    "; max-age=" + age + "; path=/";
    --  document.cookie = cookieValue;
    --}
    --
    --/* #########     END COOKIES!     ########## */
    --
    --/*
    -- * Manages secion card states and nav resize to conclude loading
    -- */
    --(function() {
    --  $(document).ready(function() {
    --
    --    // Stack hover states
    --    $('.section-card-menu').each(function(index, el) {
    --      var height = $(el).height();
    --      $(el).css({height:height + 'px', position:'relative'});
    --      var $cardInfo = $(el).find('.card-info');
    --
    --      $cardInfo.css({position: 'absolute', bottom:'0px', left:'0px', right:'0px', overflow:'visible'});
    --    });
    --
    --  });
    --
    --})();
    --
    --/*      MISC LIBRARY FUNCTIONS     */
    --
    --function toggle(obj, slide) {
    --  var ul = $("ul:first", obj);
    --  var li = ul.parent();
    --  if (li.hasClass("closed")) {
    --    if (slide) {
    --      ul.slideDown("fast");
    --    } else {
    --      ul.show();
    --    }
    --    li.removeClass("closed");
    --    li.addClass("open");
    --    $(".toggle-img", li).attr("title", "hide pages");
    --  } else {
    --    ul.slideUp("fast");
    --    li.removeClass("open");
    --    li.addClass("closed");
    --    $(".toggle-img", li).attr("title", "show pages");
    --  }
    --}
    --
    --function buildToggleLists() {
    --  $(".toggle-list").each(
    --    function(i) {
    --      $("div:first", this).append("<a class='toggle-img' href='#' title='show pages' onClick='toggle(this.parentNode.parentNode, true); return false;'></a>");
    --      $(this).addClass("closed");
    --    });
    --}
    --
    --function hideNestedItems(list, toggle) {
    --  $list = $(list);
    --  // hide nested lists
    --  if ($list.hasClass('showing')) {
    --    $("li ol", $list).hide('fast');
    --    $list.removeClass('showing');
    --  // show nested lists
    --  } else {
    --    $("li ol", $list).show('fast');
    --    $list.addClass('showing');
    --  }
    --  $(".more,.less", $(toggle)).toggle();
    --}
    --
    --/* Call this to add listeners to a <select> element for Studio/Eclipse/Other docs */
    --function setupIdeDocToggle() {
    --  $("select.ide").change(function() {
    --    var selected = $(this).find("option:selected").attr("value");
    --    $(".select-ide").hide();
    --    $(".select-ide." + selected).show();
    --
    --    $("select.ide").val(selected);
    --  });
    --}
    --
    --/* Used to hide and reveal supplemental content, such as long code samples.
    --   See the companion CSS in android-developer-docs.css */
    --function toggleContent(obj) {
    --  var div = $(obj).closest(".toggle-content");
    --  var toggleMe = $(".toggle-content-toggleme:eq(0)", div);
    --  if (div.hasClass("closed")) { // if it's closed, open it
    --    toggleMe.slideDown();
    --    $(".toggle-content-text:eq(0)", obj).toggle();
    --    div.removeClass("closed").addClass("open");
    --    $(".toggle-content-img:eq(0)", div).attr("title", "hide").attr("src", toRoot +
    --                  "assets/images/styles/disclosure_up.png");
    --  } else { // if it's open, close it
    --    toggleMe.slideUp('fast', function() {  // Wait until the animation is done before closing arrow
    --      $(".toggle-content-text:eq(0)", obj).toggle();
    --      div.removeClass("open").addClass("closed");
    --      div.find(".toggle-content").removeClass("open").addClass("closed")
    --              .find(".toggle-content-toggleme").hide();
    --      $(".toggle-content-img", div).attr("title", "show").attr("src", toRoot +
    --                  "assets/images/styles/disclosure_down.png");
    --    });
    --  }
    --  return false;
    --}
    --
    --/* New version of expandable content */
    --function toggleExpandable(link, id) {
    --  if ($(id).is(':visible')) {
    --    $(id).slideUp();
    --    $(link).removeClass('expanded');
    --  } else {
    --    $(id).slideDown();
    --    $(link).addClass('expanded');
    --  }
    --}
    --
    --function hideExpandable(ids) {
    --  $(ids).slideUp();
    --  $(ids).prev('h4').find('a.expandable').removeClass('expanded');
    --}
    --
    --/*
    -- *  Slideshow 1.0
    -- *  Used on /index.html and /develop/index.html for carousel
    -- *
    -- *  Sample usage:
    -- *  HTML -
    -- *  <div class="slideshow-container">
    -- *   <a href="" class="slideshow-prev">Prev</a>
    -- *   <a href="" class="slideshow-next">Next</a>
    -- *   <ul>
    -- *       <li class="item"><img src="images/marquee1.jpg"></li>
    -- *       <li class="item"><img src="images/marquee2.jpg"></li>
    -- *       <li class="item"><img src="images/marquee3.jpg"></li>
    -- *       <li class="item"><img src="images/marquee4.jpg"></li>
    -- *   </ul>
    -- *  </div>
    -- *
    -- *   <script type="text/javascript">
    -- *   $('.slideshow-container').dacSlideshow({
    -- *       auto: true,
    -- *       btnPrev: '.slideshow-prev',
    -- *       btnNext: '.slideshow-next'
    -- *   });
    -- *   </script>
    -- *
    -- *  Options:
    -- *  btnPrev:    optional identifier for previous button
    -- *  btnNext:    optional identifier for next button
    -- *  btnPause:   optional identifier for pause button
    -- *  auto:       whether or not to auto-proceed
    -- *  speed:      animation speed
    -- *  autoTime:   time between auto-rotation
    -- *  easing:     easing function for transition
    -- *  start:      item to select by default
    -- *  scroll:     direction to scroll in
    -- *  pagination: whether or not to include dotted pagination
    -- *
    -- */
    --
    --(function($) {
    --  $.fn.dacSlideshow = function(o) {
    --
    --    //Options - see above
    --    o = $.extend({
    --      btnPrev:   null,
    --      btnNext:   null,
    --      btnPause:  null,
    --      auto:      true,
    --      speed:     500,
    --      autoTime:  12000,
    --      easing:    null,
    --      start:     0,
    --      scroll:    1,
    --      pagination: true
    --
    --    }, o || {});
    --
    --    //Set up a carousel for each
    --    return this.each(function() {
    --
    --      var running = false;
    --      var animCss = o.vertical ? "top" : "left";
    --      var sizeCss = o.vertical ? "height" : "width";
    --      var div = $(this);
    --      var ul = $("ul", div);
    --      var tLi = $("li", ul);
    --      var tl = tLi.size();
    --      var timer = null;
    --
    --      var li = $("li", ul);
    --      var itemLength = li.size();
    --      var curr = o.start;
    --
    --      li.css({float: o.vertical ? "none" : "left"});
    --      ul.css({margin: "0", padding: "0", position: "relative", "list-style-type": "none", "z-index": "1"});
    --      div.css({position: "relative", "z-index": "2", left: "0px"});
    --
    --      var liSize = o.vertical ? height(li) : width(li);
    --      var ulSize = liSize * itemLength;
    --      var divSize = liSize;
    --
    --      li.css({width: li.width(), height: li.height()});
    --      ul.css(sizeCss, ulSize + "px").css(animCss, -(curr * liSize));
    --
    --      div.css(sizeCss, divSize + "px");
    --
    --      //Pagination
    --      if (o.pagination) {
    --        var pagination = $("<div class='pagination'></div>");
    --        var pag_ul = $("<ul></ul>");
    --        if (tl > 1) {
    --          for (var i = 0; i < tl; i++) {
    --            var li = $("<li>" + i + "</li>");
    --            pag_ul.append(li);
    --            if (i == o.start) li.addClass('active');
    --            li.click(function() {
    --              go(parseInt($(this).text()));
    --            })
    --          }
    --          pagination.append(pag_ul);
    --          div.append(pagination);
    --        }
    --      }
    --
    --      //Previous button
    --      if (o.btnPrev)
    --             $(o.btnPrev).click(function(e) {
    --               e.preventDefault();
    --               return go(curr - o.scroll);
    --             });
    --
    --      //Next button
    --      if (o.btnNext)
    --             $(o.btnNext).click(function(e) {
    --               e.preventDefault();
    --               return go(curr + o.scroll);
    --             });
    --
    --      //Pause button
    --      if (o.btnPause)
    --             $(o.btnPause).click(function(e) {
    --               e.preventDefault();
    --               if ($(this).hasClass('paused')) {
    --                 startRotateTimer();
    --               } else {
    --                 pauseRotateTimer();
    --               }
    --             });
    --
    --      //Auto rotation
    --      if (o.auto) startRotateTimer();
    --
    --      function startRotateTimer() {
    --        clearInterval(timer);
    --        timer = setInterval(function() {
    --          if (curr == tl - 1) {
    --            go(0);
    --          } else {
    --            go(curr + o.scroll);
    --          }
    --        }, o.autoTime);
    --        $(o.btnPause).removeClass('paused');
    --      }
    --
    --      function pauseRotateTimer() {
    --        clearInterval(timer);
    --        $(o.btnPause).addClass('paused');
    --      }
    --
    --      //Go to an item
    --      function go(to) {
    --        if (!running) {
    --
    --          if (to < 0) {
    --            to = itemLength - 1;
    --          } else if (to > itemLength - 1) {
    --            to = 0;
    --          }
    --          curr = to;
    --
    --          running = true;
    --
    --          ul.animate(
    --              animCss == "left" ? {left: -(curr * liSize)} : {top: -(curr * liSize)} , o.speed, o.easing,
    --                     function() {
    --                       running = false;
    --                     }
    --                 );
    --
    --          $(o.btnPrev + "," + o.btnNext).removeClass("disabled");
    --          $((curr - o.scroll < 0 && o.btnPrev)              ||
    --             (curr + o.scroll > itemLength && o.btnNext)              ||
    --             []
    --           ).addClass("disabled");
    --
    --          var nav_items = $('li', pagination);
    --          nav_items.removeClass('active');
    --          nav_items.eq(to).addClass('active');
    --
    --        }
    --        if (o.auto) startRotateTimer();
    --        return false;
    --      };
    --    });
    --  };
    --
    --  function css(el, prop) {
    --    return parseInt($.css(el[0], prop)) || 0;
    --  };
    --  function width(el) {
    --    return el[0].offsetWidth + css(el, 'marginLeft') + css(el, 'marginRight');
    --  };
    --  function height(el) {
    --    return el[0].offsetHeight + css(el, 'marginTop') + css(el, 'marginBottom');
    --  };
    --
    --})(jQuery);
    --
    --/*
    -- *  dacSlideshow 1.0
    -- *  Used on develop/index.html for side-sliding tabs
    -- *
    -- *  Sample usage:
    -- *  HTML -
    -- *  <div class="slideshow-container">
    -- *   <a href="" class="slideshow-prev">Prev</a>
    -- *   <a href="" class="slideshow-next">Next</a>
    -- *   <ul>
    -- *       <li class="item"><img src="images/marquee1.jpg"></li>
    -- *       <li class="item"><img src="images/marquee2.jpg"></li>
    -- *       <li class="item"><img src="images/marquee3.jpg"></li>
    -- *       <li class="item"><img src="images/marquee4.jpg"></li>
    -- *   </ul>
    -- *  </div>
    -- *
    -- *   <script type="text/javascript">
    -- *   $('.slideshow-container').dacSlideshow({
    -- *       auto: true,
    -- *       btnPrev: '.slideshow-prev',
    -- *       btnNext: '.slideshow-next'
    -- *   });
    -- *   </script>
    -- *
    -- *  Options:
    -- *  btnPrev:    optional identifier for previous button
    -- *  btnNext:    optional identifier for next button
    -- *  auto:       whether or not to auto-proceed
    -- *  speed:      animation speed
    -- *  autoTime:   time between auto-rotation
    -- *  easing:     easing function for transition
    -- *  start:      item to select by default
    -- *  scroll:     direction to scroll in
    -- *  pagination: whether or not to include dotted pagination
    -- *
    -- */
    --(function($) {
    --  $.fn.dacTabbedList = function(o) {
    --
    --    //Options - see above
    --    o = $.extend({
    --      speed : 250,
    --      easing: null,
    --      nav_id: null,
    --      frame_id: null
    --    }, o || {});
    --
    --    //Set up a carousel for each
    --    return this.each(function() {
    --
    --      var curr = 0;
    --      var running = false;
    --      var animCss = "margin-left";
    --      var sizeCss = "width";
    --      var div = $(this);
    --
    --      var nav = $(o.nav_id, div);
    --      var nav_li = $("li", nav);
    --      var nav_size = nav_li.size();
    --      var frame = div.find(o.frame_id);
    --      var content_width = $(frame).find('ul').width();
    --      //Buttons
    --      $(nav_li).click(function(e) {
    --           go($(nav_li).index($(this)));
    --         })
    --
    --      //Go to an item
    --      function go(to) {
    --        if (!running) {
    --          curr = to;
    --          running = true;
    --
    --          frame.animate({'margin-left' : -(curr * content_width)}, o.speed, o.easing,
    --                     function() {
    --                       running = false;
    --                     }
    --                 );
    --
    --          nav_li.removeClass('active');
    --          nav_li.eq(to).addClass('active');
    --
    --        }
    --        return false;
    --      };
    --    });
    --  };
    --
    --  function css(el, prop) {
    --    return parseInt($.css(el[0], prop)) || 0;
    --  };
    --  function width(el) {
    --    return el[0].offsetWidth + css(el, 'marginLeft') + css(el, 'marginRight');
    --  };
    --  function height(el) {
    --    return el[0].offsetHeight + css(el, 'marginTop') + css(el, 'marginBottom');
    --  };
    --
    --})(jQuery);
    --
    --/* ######################################################## */
    --/* #################  JAVADOC REFERENCE ################### */
    --/* ######################################################## */
    --
    --
    --
    --var API_LEVEL_COOKIE = "api_level";
    --var minLevel = 1;
    --var maxLevel = 1;
    --
    --function buildApiLevelSelector() {
    --  maxLevel = API_LEVELS.length;
    --  var userApiLevel = parseInt(readCookie(API_LEVEL_COOKIE));
    --  userApiLevel = userApiLevel == 0 ? maxLevel : userApiLevel; // If there's no cookie (zero), use the max by default
    --
    --  minLevel = parseInt($("#doc-api-level").attr("class"));
    --  // Handle provisional api levels; the provisional level will always be the highest possible level
    --  // Provisional api levels will also have a length; other stuff that's just missing a level won't,
    --  // so leave those kinds of entities at the default level of 1 (for example, the R.styleable class)
    --  if (isNaN(minLevel) && minLevel.length) {
    --    minLevel = maxLevel;
    --  }
    --  var select = $("#apiLevelSelector").html("").change(changeApiLevel);
    --  for (var i = maxLevel - 1; i >= 0; i--) {
    --    var option = $("<option />").attr("value", "" + API_LEVELS[i]).append("" + API_LEVELS[i]);
    --    //  if (API_LEVELS[i] < minLevel) option.addClass("absent"); // always false for strings (codenames)
    --    select.append(option);
    --  }
    --
    --  // get the DOM element and use setAttribute cuz IE6 fails when using jquery .attr('selected',true)
    --  var selectedLevelItem = $("#apiLevelSelector option[value='" + userApiLevel + "']").get(0);
    --  selectedLevelItem.setAttribute('selected', true);
    --}
    --
    --function changeApiLevel() {
    --  maxLevel = API_LEVELS.length;
    --  minLevel = parseInt($('#doc-api-level').attr('class'));
    --  var selectedLevel = maxLevel;
    --
    --  selectedLevel = parseInt($("#apiLevelSelector option:selected").val());
    --  toggleVisisbleApis(selectedLevel, "body");
    --
    --  writeCookie(API_LEVEL_COOKIE, selectedLevel, null);
    --
    --  if (selectedLevel < minLevel) {
    --      // Show the API notice dialog, set number values and button event
    --      $('#api-unavailable').trigger('modal-open');
    --      $('#api-unavailable .selected-level').text(selectedLevel);
    --      $('#api-unavailable .api-level').text(minLevel);
    --      $('#api-unavailable button.ok').attr('onclick','$("#apiLevelSelector").val("' + minLevel + '");changeApiLevel();');
    --  }
    --}
    --
    --function toggleVisisbleApis(selectedLevel, context) {
    --  var apis = $(".api", context);
    --  apis.each(function(i) {
    --    var obj = $(this);
    --    var className = obj.attr("class");
    --    var apiLevelIndex = className.lastIndexOf("-") + 1;
    --    var apiLevelEndIndex = className.indexOf(" ", apiLevelIndex);
    --    apiLevelEndIndex = apiLevelEndIndex != -1 ? apiLevelEndIndex : className.length;
    --    var apiLevel = className.substring(apiLevelIndex, apiLevelEndIndex);
    --    if (apiLevel.length == 0) { // for odd cases when the since data is actually missing, just bail
    --      return;
    --    }
    --    apiLevel = parseInt(apiLevel);
    --
    --    // Handle provisional api levels; if this item's level is the provisional one, set it to the max
    --    var selectedLevelNum = parseInt(selectedLevel)
    --    var apiLevelNum = parseInt(apiLevel);
    --    if (isNaN(apiLevelNum)) {
    --      apiLevelNum = maxLevel;
    --    }
    --
    --    // Grey things out that aren't available and give a tooltip title
    --    if (apiLevelNum > selectedLevelNum) {
    --      obj.addClass("absent").attr("title", "Requires API Level \"" +
    --            apiLevel + "\" or higher. To reveal, change the target API level " +
    --              "above the left navigation.");
    --    } else obj.removeClass("absent").removeAttr("title");
    --  });
    --}
    --
    --/* #################  SIDENAV TREE VIEW ################### */
    --/* TODO: eliminate redundancy with non-google functions */
    --function init_google_navtree(navtree_id, toroot, root_nodes) {
    --  var me = new Object();
    --  me.toroot = toroot;
    --  me.node = new Object();
    --
    --  me.node.li = document.getElementById(navtree_id);
    --  if (!me.node.li) {
    --    return;
    --  }
    --
    --  me.node.children_data = root_nodes;
    --  me.node.children = new Array();
    --  me.node.children_ul = document.createElement("ul");
    --  me.node.get_children_ul = function() { return me.node.children_ul; };
    --  //me.node.children_ul.className = "children_ul";
    --  me.node.li.appendChild(me.node.children_ul);
    --  me.node.depth = 0;
    --
    --  get_google_node(me, me.node);
    --}
    --
    --function new_google_node(me, mom, text, link, children_data, api_level) {
    --  var node = new Object();
    --  var child;
    --  node.children = Array();
    --  node.children_data = children_data;
    --  node.depth = mom.depth + 1;
    --  node.get_children_ul = function() {
    --      if (!node.children_ul) {
    --        node.children_ul = document.createElement("ul");
    --        node.children_ul.className = "tree-list-children";
    --        node.li.appendChild(node.children_ul);
    --      }
    --      return node.children_ul;
    --    };
    --  node.li = document.createElement("li");
    --
    --  mom.get_children_ul().appendChild(node.li);
    --
    --  if (link) {
    --    child = document.createElement("a");
    --
    --  } else {
    --    child = document.createElement("span");
    --    child.className = "tree-list-subtitle";
    --
    --  }
    --  if (children_data != null) {
    --    node.li.className = "nav-section";
    --    node.label_div = document.createElement("div");
    --    node.label_div.className = "nav-section-header-ref";
    --    node.li.appendChild(node.label_div);
    --    get_google_node(me, node);
    --    node.label_div.appendChild(child);
    --  } else {
    --    node.li.appendChild(child);
    --  }
    --  if (link) {
    --    child.href = me.toroot + link;
    --  }
    --  node.label = document.createTextNode(text);
    --  child.appendChild(node.label);
    --
    --  node.children_ul = null;
    --
    --  return node;
    --}
    --
    --function get_google_node(me, mom) {
    --  mom.children_visited = true;
    --  var linkText;
    --  for (var i in mom.children_data) {
    --    var node_data = mom.children_data[i];
    --    linkText = node_data[0];
    --
    --    if (linkText.match("^" + "com.google.android") == "com.google.android") {
    --      linkText = linkText.substr(19, linkText.length);
    --    }
    --    mom.children[i] = new_google_node(me, mom, linkText, node_data[1],
    --        node_data[2], node_data[3]);
    --  }
    --}
    --
    --/****** NEW version of script to build google and sample navs dynamically ******/
    --// TODO: update Google reference docs to tolerate this new implementation
    --
    --var NODE_NAME = 0;
    --var NODE_HREF = 1;
    --var NODE_GROUP = 2;
    --var NODE_TAGS = 3;
    --var NODE_CHILDREN = 4;
    --
    --function init_google_navtree2(navtree_id, data) {
    --  var $containerUl = $("#" + navtree_id);
    --  for (var i in data) {
    --    var node_data = data[i];
    --    $containerUl.append(new_google_node2(node_data));
    --  }
    --
    --  // Make all third-generation list items 'sticky' to prevent them from collapsing
    --  $containerUl.find('li li li.nav-section').addClass('sticky');
    --
    --  initExpandableNavItems("#" + navtree_id);
    --}
    --
    --function new_google_node2(node_data) {
    --  var linkText = node_data[NODE_NAME];
    --  if (linkText.match("^" + "com.google.android") == "com.google.android") {
    --    linkText = linkText.substr(19, linkText.length);
    --  }
    --  var $li = $('<li>');
    --  var $a;
    --  if (node_data[NODE_HREF] != null) {
    --    $a = $('<a href="' + toRoot + node_data[NODE_HREF] + '" title="' + linkText + '" >' +
    --        linkText + '</a>');
    --  } else {
    --    $a = $('<a href="#" onclick="return false;" title="' + linkText + '" >' +
    --        linkText + '/</a>');
    --  }
    --  var $childUl = $('<ul>');
    --  if (node_data[NODE_CHILDREN] != null) {
    --    $li.addClass("nav-section");
    --    $a = $('<div class="nav-section-header">').append($a);
    --    if (node_data[NODE_HREF] == null) $a.addClass('empty');
    --
    --    for (var i in node_data[NODE_CHILDREN]) {
    --      var child_node_data = node_data[NODE_CHILDREN][i];
    --      $childUl.append(new_google_node2(child_node_data));
    --    }
    --    $li.append($childUl);
    --  }
    --  $li.prepend($a);
    --
    --  return $li;
    --}
    --
    --function showGoogleRefTree() {
    --  init_default_google_navtree(toRoot);
    --  init_default_gcm_navtree(toRoot);
    --}
    --
    --function init_default_google_navtree(toroot) {
    --  // load json file for navtree data
    --  $.getScript(toRoot + 'gms_navtree_data.js', function(data, textStatus, jqxhr) {
    --    // when the file is loaded, initialize the tree
    --    if (jqxhr.status === 200) {
    --      init_google_navtree("gms-tree-list", toroot, GMS_NAVTREE_DATA);
    --      highlightSidenav();
    --    }
    --  });
    --}
    --
    --function init_default_gcm_navtree(toroot) {
    --  // load json file for navtree data
    --  $.getScript(toRoot + 'gcm_navtree_data.js', function(data, textStatus, jqxhr) {
    --    // when the file is loaded, initialize the tree
    --    if (jqxhr.status === 200) {
    --      init_google_navtree("gcm-tree-list", toroot, GCM_NAVTREE_DATA);
    --      highlightSidenav();
    --    }
    --  });
    --}
    --
    --/* TOGGLE INHERITED MEMBERS */
    --
    --/* Toggle an inherited class (arrow toggle)
    -- * @param linkObj  The link that was clicked.
    -- * @param expand  'true' to ensure it's expanded. 'false' to ensure it's closed.
    -- *                'null' to simply toggle.
    -- */
    --function toggleInherited(linkObj, expand) {
    --  var base = linkObj.getAttribute("id");
    --  var list = document.getElementById(base + "-list");
    --  var summary = document.getElementById(base + "-summary");
    --  var trigger = document.getElementById(base + "-trigger");
    --  var a = $(linkObj);
    --  if ((expand == null && a.hasClass("closed")) || expand) {
    --    list.style.display = "none";
    --    summary.style.display = "block";
    --    trigger.src = toRoot + "assets/images/styles/disclosure_up.png";
    --    a.removeClass("closed");
    --    a.addClass("opened");
    --  } else if ((expand == null && a.hasClass("opened")) || (expand == false)) {
    --    list.style.display = "block";
    --    summary.style.display = "none";
    --    trigger.src = toRoot + "assets/images/styles/disclosure_down.png";
    --    a.removeClass("opened");
    --    a.addClass("closed");
    --  }
    --  return false;
    --}
    --
    --/* Toggle all inherited classes in a single table (e.g. all inherited methods)
    -- * @param linkObj  The link that was clicked.
    -- * @param expand  'true' to ensure it's expanded. 'false' to ensure it's closed.
    -- *                'null' to simply toggle.
    -- */
    --function toggleAllInherited(linkObj, expand) {
    --  var a = $(linkObj);
    --  var table = $(a.parent().parent().parent()); // ugly way to get table/tbody
    --  var expandos = $(".jd-expando-trigger", table);
    --  if ((expand == null && a.text() == "[Expand]") || expand) {
    --    expandos.each(function(i) {
    --      toggleInherited(this, true);
    --    });
    --    a.text("[Collapse]");
    --  } else if ((expand == null && a.text() == "[Collapse]") || (expand == false)) {
    --    expandos.each(function(i) {
    --      toggleInherited(this, false);
    --    });
    --    a.text("[Expand]");
    --  }
    --  return false;
    --}
    --
    --/* Toggle all inherited members in the class (link in the class title)
    -- */
    --function toggleAllClassInherited() {
    --  var a = $("#toggleAllClassInherited"); // get toggle link from class title
    --  var toggles = $(".toggle-all", $("#body-content"));
    --  if (a.text() == "[Expand All]") {
    --    toggles.each(function(i) {
    --      toggleAllInherited(this, true);
    --    });
    --    a.text("[Collapse All]");
    --  } else {
    --    toggles.each(function(i) {
    --      toggleAllInherited(this, false);
    --    });
    --    a.text("[Expand All]");
    --  }
    --  return false;
    --}
    --
    --/* Expand all inherited members in the class. Used when initiating page search */
    --function ensureAllInheritedExpanded() {
    --  var toggles = $(".toggle-all", $("#body-content"));
    --  toggles.each(function(i) {
    --    toggleAllInherited(this, true);
    --  });
    --  $("#toggleAllClassInherited").text("[Collapse All]");
    --}
    --
    --/* HANDLE KEY EVENTS
    -- * - Listen for Ctrl+F (Cmd on Mac) and expand all inherited members (to aid page search)
    -- */
    --var agent = navigator['userAgent'].toLowerCase();
    --var mac = agent.indexOf("macintosh") != -1;
    --
    --$(document).keydown(function(e) {
    --  var control = mac ? e.metaKey && !e.ctrlKey : e.ctrlKey; // get ctrl key
    --  if (control && e.which == 70) {  // 70 is "F"
    --    ensureAllInheritedExpanded();
    --  }
    --});
    --
    --/* On-demand functions */
    --
    --/** Move sample code line numbers out of PRE block and into non-copyable column */
    --function initCodeLineNumbers() {
    --  var numbers = $("#codesample-block a.number");
    --  if (numbers.length) {
    --    $("#codesample-line-numbers").removeClass("hidden").append(numbers);
    --  }
    --
    --  $(document).ready(function() {
    --    // select entire line when clicked
    --    $("span.code-line").click(function() {
    --      if (!shifted) {
    --        selectText(this);
    --      }
    --    });
    --    // invoke line link on double click
    --    $(".code-line").dblclick(function() {
    --      document.location.hash = $(this).attr('id');
    --    });
    --    // highlight the line when hovering on the number
    --    $("#codesample-line-numbers a.number").mouseover(function() {
    --      var id = $(this).attr('href');
    --      $(id).css('background', '#e7e7e7');
    --    });
    --    $("#codesample-line-numbers a.number").mouseout(function() {
    --      var id = $(this).attr('href');
    --      $(id).css('background', 'none');
    --    });
    --  });
    --}
    --
    --// create SHIFT key binder to avoid the selectText method when selecting multiple lines
    --var shifted = false;
    --$(document).bind('keyup keydown', function(e) {
    --  shifted = e.shiftKey; return true;
    --});
    --
    --// courtesy of jasonedelman.com
    --function selectText(element) {
    --  var doc = document      ,
    --        range, selection
    --  ;
    --  if (doc.body.createTextRange) { //ms
    --    range = doc.body.createTextRange();
    --    range.moveToElementText(element);
    --    range.select();
    --  } else if (window.getSelection) { //all others
    --    selection = window.getSelection();
    --    range = doc.createRange();
    --    range.selectNodeContents(element);
    --    selection.removeAllRanges();
    --    selection.addRange(range);
    --  }
    --}
    --
    --/** Display links and other information about samples that match the
    --    group specified by the URL */
    --function showSamples() {
    --  var group = $("#samples").attr('class');
    --  $("#samples").html("<p>Here are some samples for <b>" + group + "</b> apps:</p>");
    --
    --  var $ul = $("<ul>");
    --  $selectedLi = $("#nav li.selected");
    --
    --  $selectedLi.children("ul").children("li").each(function() {
    --    var $li = $("<li>").append($(this).find("a").first().clone());
    --    var $samplesLink = $li.find("a");
    --    if ($samplesLink.text().endsWith('/')) {
    --      $samplesLink.text($samplesLink.text().slice(0,-1));
    --    }
    --    $ul.append($li);
    --  });
    --
    --  $("#samples").append($ul);
    --
    --}
    --
    --/* ########################################################## */
    --/* ###################  RESOURCE CARDS  ##################### */
    --/* ########################################################## */
    --
    --/** Handle resource queries, collections, and grids (sections). Requires
    --    jd_tag_helpers.js and the *_unified_data.js to be loaded. */
    --
    --(function() {
    --  $(document).ready(function() {
    --    // Need to initialize hero carousel before other sections for dedupe
    --    // to work correctly.
    --    $('[data-carousel-query]').dacCarouselQuery();
    --
    --    // Iterate over all instances and initialize a resource widget.
    --    $('.resource-widget').resourceWidget();
    --  });
    --
    --  $.fn.widgetOptions = function() {
    --    return {
    --      cardSizes: (this.data('cardsizes') || '').split(','),
    --      maxResults: parseInt(this.data('maxresults'), 10) || Infinity,
    --      initialResults: this.data('initialResults'),
    --      itemsPerPage: this.data('itemsPerPage'),
    --      sortOrder: this.data('sortorder'),
    --      query: this.data('query'),
    --      section: this.data('section'),
    --      /* Added by LFL 6/6/14 */
    --      resourceStyle: this.data('resourcestyle') || 'card',
    --      stackSort: this.data('stacksort') || 'true',
    --      // For filter based resources
    --      allowDuplicates: this.data('allow-duplicates') || 'false'
    --    };
    --  };
    --
    --  $.fn.deprecateOldGridStyles = function() {
    --    var m = this.get(0).className.match(/\bcol-(\d+)\b/);
    --    if (m && !this.is('.cols > *')) {
    --      this.removeClass('col-' + m[1]);
    --    }
    --    return this;
    --  }
    --
    --  /*
    --   * Three types of resource layouts:
    --   * Flow - Uses a fixed row-height flow using float left style.
    --   * Carousel - Single card slideshow all same dimension absolute.
    --   * Stack - Uses fixed columns and flexible element height.
    --   */
    --  function initResourceWidget(widget, resources, opts) {
    --    var $widget = $(widget).deprecateOldGridStyles();
    --    var isFlow = $widget.hasClass('resource-flow-layout');
    --    var isCarousel = $widget.hasClass('resource-carousel-layout');
    --    var isStack = $widget.hasClass('resource-stack-layout');
    --
    --    opts = opts || $widget.widgetOptions();
    --    resources = resources || metadata.query(opts);
    --
    --    if (opts.maxResults !== undefined) {
    --      resources = resources.slice(0, opts.maxResults);
    --    }
    --
    --    if (isFlow) {
    --      drawResourcesFlowWidget($widget, opts, resources);
    --    } else if (isCarousel) {
    --      drawResourcesCarouselWidget($widget, opts, resources);
    --    } else if (isStack) {
    --      opts.numStacks = $widget.data('numstacks');
    --      drawResourcesStackWidget($widget, opts, resources);
    --    }
    --  }
    --
    --  $.fn.resourceWidget = function(resources, options) {
    --    return this.each(function() {
    --      initResourceWidget(this, resources, options);
    --    });
    --  };
    --
    --  /* Initializes a Resource Carousel Widget */
    --  function drawResourcesCarouselWidget($widget, opts, resources) {
    --    $widget.empty();
    --    var plusone = false; // stop showing plusone buttons on cards
    --
    --    $widget.addClass('resource-card slideshow-container')
    --      .append($('<a>').addClass('slideshow-prev').text('Prev'))
    --      .append($('<a>').addClass('slideshow-next').text('Next'));
    --
    --    var css = {'width': $widget.width() + 'px',
    --                'height': $widget.height() + 'px'};
    --
    --    var $ul = $('<ul>');
    --
    --    for (var i = 0; i < resources.length; ++i) {
    --      var $card = $('<a>')
    --        .attr('href', cleanUrl(resources[i].url))
    --        .decorateResourceCard(resources[i], plusone);
    --
    --      $('<li>').css(css)
    --          .append($card)
    --          .appendTo($ul);
    --    }
    --
    --    $('<div>').addClass('frame')
    --      .append($ul)
    --      .appendTo($widget);
    --
    --    $widget.dacSlideshow({
    --      auto: true,
    --      btnPrev: '.slideshow-prev',
    --      btnNext: '.slideshow-next'
    --    });
    --  }
    --
    --  /* Initializes a Resource Card Stack Widget (column-based layout)
    --     Modified by LFL 6/6/14
    --   */
    --  function drawResourcesStackWidget($widget, opts, resources, sections) {
    --    // Don't empty widget, grab all items inside since they will be the first
    --    // items stacked, followed by the resource query
    --    var plusone = false; // stop showing plusone buttons on cards
    --    var cards = $widget.find('.resource-card').detach().toArray();
    --    var numStacks = opts.numStacks || 1;
    --    var $stacks = [];
    --
    --    for (var i = 0; i < numStacks; ++i) {
    --      $stacks[i] = $('<div>').addClass('resource-card-stack')
    --          .appendTo($widget);
    --    }
    --
    --    var sectionResources = [];
    --
    --    // Extract any subsections that are actually resource cards
    --    if (sections) {
    --      for (i = 0; i < sections.length; ++i) {
    --        if (!sections[i].sections || !sections[i].sections.length) {
    --          // Render it as a resource card
    --          sectionResources.push(
    --            $('<a>')
    --              .addClass('resource-card section-card')
    --              .attr('href', cleanUrl(sections[i].resource.url))
    --              .decorateResourceCard(sections[i].resource, plusone)[0]
    --          );
    --
    --        } else {
    --          cards.push(
    --            $('<div>')
    --              .addClass('resource-card section-card-menu')
    --              .decorateResourceSection(sections[i], plusone)[0]
    --          );
    --        }
    --      }
    --    }
    --
    --    cards = cards.concat(sectionResources);
    --
    --    for (i = 0; i < resources.length; ++i) {
    --      var $card = createResourceElement(resources[i], opts);
    --
    --      if (opts.resourceStyle.indexOf('related') > -1) {
    --        $card.addClass('related-card');
    --      }
    --
    --      cards.push($card[0]);
    --    }
    --
    --    if (opts.stackSort !== 'false') {
    --      for (i = 0; i < cards.length; ++i) {
    --        // Find the stack with the shortest height, but give preference to
    --        // left to right order.
    --        var minHeight = $stacks[0].height();
    --        var minIndex = 0;
    --
    --        for (var j = 1; j < numStacks; ++j) {
    --          var height = $stacks[j].height();
    --          if (height < minHeight - 45) {
    --            minHeight = height;
    --            minIndex = j;
    --          }
    --        }
    --
    --        $stacks[minIndex].append($(cards[i]));
    --      }
    --    }
    --  }
    --
    --  /*
    --    Create a resource card using the given resource object and a list of html
    --     configured options. Returns a jquery object containing the element.
    --  */
    --  function createResourceElement(resource, opts, plusone) {
    --    var $el;
    --
    --    // The difference here is that generic cards are not entirely clickable
    --    // so its a div instead of an a tag, also the generic one is not given
    --    // the resource-card class so it appears with a transparent background
    --    // and can be styled in whatever way the css setup.
    --    if (opts.resourceStyle === 'generic') {
    --      $el = $('<div>')
    --        .addClass('resource')
    --        .attr('href', cleanUrl(resource.url))
    --        .decorateResource(resource, opts);
    --    } else {
    --      var cls = 'resource resource-card';
    --
    --      $el = $('<a>')
    --        .addClass(cls)
    --        .attr('href', cleanUrl(resource.url))
    --        .decorateResourceCard(resource, plusone);
    --    }
    --
    --    return $el;
    --  }
    --
    --  function createResponsiveFlowColumn(cardSize) {
    --    var cardWidth = parseInt(cardSize.match(/(\d+)/)[1], 10);
    --    var column = $('<div>').addClass('col-' + (cardWidth / 3) + 'of6');
    --    if (cardWidth < 9) {
    --      column.addClass('col-tablet-1of2');
    --    } else if (cardWidth > 9 && cardWidth < 18) {
    --      column.addClass('col-tablet-1of1');
    --    }
    --    if (cardWidth < 18) {
    --      column.addClass('col-mobile-1of1');
    --    }
    --    return column;
    --  }
    --
    --  /* Initializes a flow widget, see distribute.scss for generating accompanying css */
    --  function drawResourcesFlowWidget($widget, opts, resources) {
    --    // We'll be doing our own modifications to opts.
    --    opts = $.extend({}, opts);
    --
    --    $widget.empty().addClass('cols');
    --    if (opts.itemsPerPage) {
    --      $('<div class="col-1of1 dac-section-links dac-text-center">')
    --        .append(
    --          $('<div class="dac-section-link dac-show-less" data-toggle="show-less">Less<i class="dac-sprite dac-auto-unfold-less"></i></div>'),
    --          $('<div class="dac-section-link dac-show-more" data-toggle="show-more">More<i class="dac-sprite dac-auto-unfold-more"></i></div>')
    --        )
    --        .appendTo($widget);
    --    }
    --
    --    $widget.data('options.resourceflow', opts);
    --    $widget.data('resources.resourceflow', resources);
    --
    --    drawResourceFlowPage($widget, opts, resources);
    --  }
    --
    --  function drawResourceFlowPage($widget, opts, resources) {
    --    var cardSizes = opts.cardSizes || ['6x6']; // 2015-08-09: dynamic card sizes are deprecated
    --    var i = opts.currentIndex || 0;
    --    var j = 0;
    --    var plusone = false; // stop showing plusone buttons on cards
    --    var firstPage = i === 0;
    --    var initialResults = opts.initialResults || opts.itemsPerPage || resources.length;
    --    var max = firstPage ? initialResults : i + opts.itemsPerPage;
    --    max = Math.min(resources.length, max);
    --
    --    var page = $('<div class="resource-flow-page">');
    --    if (opts.itemsPerPage) {
    --      $widget.find('.dac-section-links').before(page);
    --    } else {
    --      $widget.append(page);
    --    }
    --
    --    while (i < max) {
    --      var cardSize = cardSizes[j++ % cardSizes.length];
    --      cardSize = cardSize.replace(/^\s+|\s+$/, '');
    --
    --      var column = createResponsiveFlowColumn(cardSize).appendTo(page);
    --
    --      // A stack has a third dimension which is the number of stacked items
    --      var isStack = cardSize.match(/(\d+)x(\d+)x(\d+)/);
    --      var stackCount = 0;
    --      var $stackDiv = null;
    --
    --      if (isStack) {
    --        // Create a stack container which should have the dimensions defined
    --        // by the product of the items inside.
    --        $stackDiv = $('<div>').addClass('resource-card-stack resource-card-' + isStack[1] +
    --          'x' + isStack[2] * isStack[3]) .appendTo(column);
    --      }
    --
    --      // Build each stack item or just a single item
    --      do {
    --        var resource = resources[i];
    --
    --        var $card = createResourceElement(resources[i], opts, plusone);
    --
    --        $card.addClass('resource-card-' + cardSize +
    --          ' resource-card-' + resource.type.toLowerCase());
    --
    --        if (isStack) {
    --          $card.addClass('resource-card-' + isStack[1] + 'x' + isStack[2]);
    --          if (++stackCount === parseInt(isStack[3])) {
    --            $card.addClass('resource-card-row-stack-last');
    --            stackCount = 0;
    --          }
    --        } else {
    --          stackCount = 0;
    --        }
    --
    --        $card.appendTo($stackDiv || column);
    --
    --      } while (++i < max && stackCount > 0);
    --
    --      // Record number of pages viewed in analytics.
    --      if (!firstPage) {
    --        var clicks = Math.ceil((i - initialResults) / opts.itemsPerPage);
    --        devsite.analytics.trackAnalyticsEvent('event',
    --            'Cards', 'Click More', clicks);
    --      }
    --    }
    --
    --    opts.currentIndex = i;
    --    $widget.toggleClass('dac-has-more', i < resources.length);
    --    $widget.toggleClass('dac-has-less', !firstPage);
    --
    --    $widget.trigger('dac:domchange');
    --    if (opts.onRenderPage) {
    --      opts.onRenderPage(page);
    --    }
    --  }
    --
    --  function drawResourceFlowReset($widget, opts, resources) {
    --    $widget.find('.resource-flow-page')
    --        .slice(1)
    --        .remove();
    --    $widget.toggleClass('dac-has-more', true);
    --    $widget.toggleClass('dac-has-less', false);
    --
    --    opts.currentIndex = Math.min(opts.initialResults, resources.length);
    --    devsite.analytics.trackAnalyticsEvent('event', 'Cards', 'Click Less');
    --  }
    --
    --  /* A decorator for event functions which finds the surrounding widget and it's options */
    --  function wrapWithWidget(func) {
    --    return function(e) {
    --      if (e) e.preventDefault();
    --
    --      var $widget = $(this).closest('.resource-flow-layout');
    --      var opts = $widget.data('options.resourceflow');
    --      var resources = $widget.data('resources.resourceflow');
    --      func($widget, opts, resources);
    --    };
    --  }
    --
    --  /* Build a site map of resources using a section as a root. */
    --  function buildSectionList(opts) {
    --    if (opts.section && SECTION_BY_ID[opts.section]) {
    --      return SECTION_BY_ID[opts.section].sections || [];
    --    }
    --    return [];
    --  }
    --
    --  function cleanUrl(url) {
    --    if (url && url.indexOf('//') === -1) {
    --      url = toRoot + url;
    --    }
    --
    --    return url;
    --  }
    --
    --  // Delegated events for resources.
    --  $(document).on('click', '.resource-flow-layout [data-toggle="show-more"]', wrapWithWidget(drawResourceFlowPage));
    --  $(document).on('click', '.resource-flow-layout [data-toggle="show-less"]', wrapWithWidget(drawResourceFlowReset));
    --})();
    --
    --(function($) {
    --  // A mapping from category and type values to new values or human presentable strings.
    --  var SECTION_MAP = {
    --    googleplay: 'google play'
    --  };
    --
    --  /*
    --    Utility method for creating dom for the description area of a card.
    --    Used in decorateResourceCard and decorateResource.
    --  */
    --  function buildResourceCardDescription(resource, plusone) {
    --    var $description = $('<div>').addClass('description ellipsis');
    --
    --    $description.append($('<div>').addClass('text').html(resource.summary));
    --
    --    if (resource.cta) {
    --      $description.append($('<a>').addClass('cta').html(resource.cta));
    --    }
    --
    --    if (plusone) {
    --      var plusurl = resource.url.indexOf("//") > -1 ? resource.url :
    --        "//developer.android.com/" + resource.url;
    --
    --      $description.append($('<div>').addClass('util')
    --        .append($('<div>').addClass('g-plusone')
    --          .attr('data-size', 'small')
    --          .attr('data-align', 'right')
    --          .attr('data-href', plusurl)));
    --    }
    --
    --    return $description;
    --  }
    --
    --  /* Simple jquery function to create dom for a standard resource card */
    --  $.fn.decorateResourceCard = function(resource, plusone) {
    --    var section = resource.category || resource.type;
    --    section = (SECTION_MAP[section] || section).toLowerCase();
    --    var imgUrl = resource.image ||
    --      'assets/images/resource-card-default-android.jpg';
    --
    --    if (imgUrl.indexOf('//') === -1) {
    --      imgUrl = toRoot + imgUrl;
    --    }
    --
    --    if (resource.type === 'youtube' || resource.type === 'video') {
    --      $('<div>').addClass('play-button')
    --        .append($('<i class="dac-sprite dac-play-white">'))
    --        .appendTo(this);
    --    }
    --
    --    $('<div>').addClass('card-bg')
    --      .css('background-image', 'url(' + (imgUrl || toRoot +
    --        'assets/images/resource-card-default-android.jpg') + ')')
    --      .appendTo(this);
    --
    --    $('<div>').addClass('card-info' + (!resource.summary ? ' empty-desc' : ''))
    --      .append($('<div>').addClass('section').text(section))
    --      .append($('<div>').addClass('title' + (resource.title_highlighted ? ' highlighted' : ''))
    --        .html(resource.title_highlighted || resource.title))
    --      .append(buildResourceCardDescription(resource, plusone))
    --      .appendTo(this);
    --
    --    return this;
    --  };
    --
    --  /* Simple jquery function to create dom for a resource section card (menu) */
    --  $.fn.decorateResourceSection = function(section, plusone) {
    --    var resource = section.resource;
    --    //keep url clean for matching and offline mode handling
    --    var urlPrefix = resource.image.indexOf("//") > -1 ? "" : toRoot;
    --    var $base = $('<a>')
    --        .addClass('card-bg')
    --        .attr('href', resource.url)
    --        .append($('<div>').addClass('card-section-icon')
    --          .append($('<div>').addClass('icon'))
    --          .append($('<div>').addClass('section').html(resource.title)))
    --      .appendTo(this);
    --
    --    var $cardInfo = $('<div>').addClass('card-info').appendTo(this);
    --
    --    if (section.sections && section.sections.length) {
    --      // Recurse the section sub-tree to find a resource image.
    --      var stack = [section];
    --
    --      while (stack.length) {
    --        if (stack[0].resource.image) {
    --          $base.css('background-image', 'url(' + urlPrefix + stack[0].resource.image + ')');
    --          break;
    --        }
    --
    --        if (stack[0].sections) {
    --          stack = stack.concat(stack[0].sections);
    --        }
    --
    --        stack.shift();
    --      }
    --
    --      var $ul = $('<ul>')
    --        .appendTo($cardInfo);
    --
    --      var max = section.sections.length > 3 ? 3 : section.sections.length;
    --
    --      for (var i = 0; i < max; ++i) {
    --
    --        var subResource = section.sections[i];
    --        if (!plusone) {
    --          $('<li>')
    --            .append($('<a>').attr('href', subResource.url)
    --              .append($('<div>').addClass('title').html(subResource.title))
    --              .append($('<div>').addClass('description ellipsis')
    --                .append($('<div>').addClass('text').html(subResource.summary))
    --                .append($('<div>').addClass('util'))))
    --          .appendTo($ul);
    --        } else {
    --          $('<li>')
    --            .append($('<a>').attr('href', subResource.url)
    --              .append($('<div>').addClass('title').html(subResource.title))
    --              .append($('<div>').addClass('description ellipsis')
    --                .append($('<div>').addClass('text').html(subResource.summary))
    --                .append($('<div>').addClass('util')
    --                  .append($('<div>').addClass('g-plusone')
    --                    .attr('data-size', 'small')
    --                    .attr('data-align', 'right')
    --                    .attr('data-href', resource.url)))))
    --          .appendTo($ul);
    --        }
    --      }
    --
    --      // Add a more row
    --      if (max < section.sections.length) {
    --        $('<li>')
    --          .append($('<a>').attr('href', resource.url)
    --            .append($('<div>')
    --              .addClass('title')
    --              .text('More')))
    --        .appendTo($ul);
    --      }
    --    } else {
    --      // No sub-resources, just render description?
    --    }
    --
    --    return this;
    --  };
    --
    --  /* Render other types of resource styles that are not cards. */
    --  $.fn.decorateResource = function(resource, opts) {
    --    var imgUrl = resource.image ||
    --      'assets/images/resource-card-default-android.jpg';
    --    var linkUrl = resource.url;
    --
    --    if (imgUrl.indexOf('//') === -1) {
    --      imgUrl = toRoot + imgUrl;
    --    }
    --
    --    if (linkUrl && linkUrl.indexOf('//') === -1) {
    --      linkUrl = toRoot + linkUrl;
    --    }
    --
    --    $(this).append(
    --      $('<div>').addClass('image')
    --        .css('background-image', 'url(' + imgUrl + ')'),
    --      $('<div>').addClass('info').append(
    --        $('<h4>').addClass('title').html(resource.title_highlighted || resource.title),
    --        $('<p>').addClass('summary').html(resource.summary),
    --        $('<a>').attr('href', linkUrl).addClass('cta').html('Learn More')
    --      )
    --    );
    --
    --    return this;
    --  };
    --})(jQuery);
    --
    --/*
    --  Fullscreen Carousel
    --
    --  The following allows for an area at the top of the page that takes over the
    --  entire browser height except for its top offset and an optional bottom
    --  padding specified as a data attribute.
    --
    --  HTML:
    --
    --  <div class="fullscreen-carousel">
    --    <div class="fullscreen-carousel-content">
    --      <!-- content here -->
    --    </div>
    --    <div class="fullscreen-carousel-content">
    --      <!-- content here -->
    --    </div>
    --
    --    etc ...
    --
    --  </div>
    --
    --  Control over how the carousel takes over the screen can mostly be defined in
    --  a css file. Setting min-height on the .fullscreen-carousel-content elements
    --  will prevent them from shrinking to far vertically when the browser is very
    --  short, and setting max-height on the .fullscreen-carousel itself will prevent
    --  the area from becoming to long in the case that the browser is stretched very
    --  tall.
    --
    --  There is limited functionality for having multiple sections since that request
    --  was removed, but it is possible to add .next-arrow and .prev-arrow elements to
    --  scroll between multiple content areas.
    --*/
    --
    --(function() {
    --  $(document).ready(function() {
    --    $('.fullscreen-carousel').each(function() {
    --      initWidget(this);
    --    });
    --  });
    --
    --  function initWidget(widget) {
    --    var $widget = $(widget);
    --
    --    var topOffset = $widget.offset().top;
    --    var padBottom = parseInt($widget.data('paddingbottom')) || 0;
    --    var maxHeight = 0;
    --    var minHeight = 0;
    --    var $content = $widget.find('.fullscreen-carousel-content');
    --    var $nextArrow = $widget.find('.next-arrow');
    --    var $prevArrow = $widget.find('.prev-arrow');
    --    var $curSection = $($content[0]);
    --
    --    if ($content.length <= 1) {
    --      $nextArrow.hide();
    --      $prevArrow.hide();
    --    } else {
    --      $nextArrow.click(function() {
    --        var index = ($content.index($curSection) + 1);
    --        $curSection.hide();
    --        $curSection = $($content[index >= $content.length ? 0 : index]);
    --        $curSection.show();
    --      });
    --
    --      $prevArrow.click(function() {
    --        var index = ($content.index($curSection) - 1);
    --        $curSection.hide();
    --        $curSection = $($content[index < 0 ? $content.length - 1 : 0]);
    --        $curSection.show();
    --      });
    --    }
    --
    --    // Just hide all content sections except first.
    --    $content.each(function(index) {
    --      if ($(this).height() > minHeight) minHeight = $(this).height();
    --      $(this).css({position: 'absolute',  display: index > 0 ? 'none' : ''});
    --    });
    --
    --    // Register for changes to window size, and trigger.
    --    $(window).resize(resizeWidget);
    --    resizeWidget();
    --
    --    function resizeWidget() {
    --      var height = $(window).height() - topOffset - padBottom;
    --      $widget.width($(window).width());
    --      $widget.height(height < minHeight ? minHeight :
    --        (maxHeight && height > maxHeight ? maxHeight : height));
    --    }
    --  }
    --})();
    --
    --/*
    --  Tab Carousel
    --
    --  The following allows tab widgets to be installed via the html below. Each
    --  tab content section should have a data-tab attribute matching one of the
    --  nav items'. Also each tab content section should have a width matching the
    --  tab carousel.
    --
    --  HTML:
    --
    --  <div class="tab-carousel">
    --    <ul class="tab-nav">
    --      <li><a href="#" data-tab="handsets">Handsets</a>
    --      <li><a href="#" data-tab="wearable">Wearable</a>
    --      <li><a href="#" data-tab="tv">TV</a>
    --    </ul>
    --
    --    <div class="tab-carousel-content">
    --      <div data-tab="handsets">
    --        <!--Full width content here-->
    --      </div>
    --
    --      <div data-tab="wearable">
    --        <!--Full width content here-->
    --      </div>
    --
    --      <div data-tab="tv">
    --        <!--Full width content here-->
    --      </div>
    --    </div>
    --  </div>
    --
    --*/
    --(function() {
    --  $(document).ready(function() {
    --    $('.tab-carousel').each(function() {
    --      initWidget(this);
    --    });
    --  });
    --
    --  function initWidget(widget) {
    --    var $widget = $(widget);
    --    var $nav = $widget.find('.tab-nav');
    --    var $anchors = $nav.find('[data-tab]');
    --    var $li = $nav.find('li');
    --    var $contentContainer = $widget.find('.tab-carousel-content');
    --    var $tabs = $contentContainer.find('[data-tab]');
    --    var $curTab = $($tabs[0]); // Current tab is first tab.
    --    var width = $widget.width();
    --
    --    // Setup nav interactivity.
    --    $anchors.click(function(evt) {
    --      evt.preventDefault();
    --      var query = '[data-tab=' + $(this).data('tab') + ']';
    --      transitionWidget($tabs.filter(query));
    --    });
    --
    --    // Add highlight for navigation on first item.
    --    var $highlight = $('<div>').addClass('highlight')
    --      .css({left:$li.position().left + 'px', width:$li.outerWidth() + 'px'})
    --      .appendTo($nav);
    --
    --    // Store height since we will change contents to absolute.
    --    $contentContainer.height($contentContainer.height());
    --
    --    // Absolutely position tabs so they're ready for transition.
    --    $tabs.each(function(index) {
    --      $(this).css({position: 'absolute', left: index > 0 ? width + 'px' : '0'});
    --    });
    --
    --    function transitionWidget($toTab) {
    --      if (!$curTab.is($toTab)) {
    --        var curIndex = $tabs.index($curTab[0]);
    --        var toIndex = $tabs.index($toTab[0]);
    --        var dir = toIndex > curIndex ? 1 : -1;
    --
    --        // Animate content sections.
    --        $toTab.css({left:(width * dir) + 'px'});
    --        $curTab.animate({left:(width * -dir) + 'px'});
    --        $toTab.animate({left:'0'});
    --
    --        // Animate navigation highlight.
    --        $highlight.animate({left:$($li[toIndex]).position().left + 'px',
    --          width:$($li[toIndex]).outerWidth() + 'px'})
    --
    --        // Store new current section.
    --        $curTab = $toTab;
    --      }
    --    }
    --  }
    --})();
    --
    --/**
    -- * Auto TOC
    -- *
    -- * Upgrades h2s on the page to have a rule and be toggle-able on mobile.
    -- */
    --(function($) {
    --  var upgraded = false;
    --  var h2Titles;
    --
    --  function initWidget() {
    --    // add HRs below all H2s (except for a few other h2 variants)
    --    // Consider doing this with css instead.
    --    h2Titles = $('h2').not('#qv h2, #tb h2, .sidebox h2, #devdoc-nav h2, h2.norule');
    --    h2Titles.css({paddingBottom:0}).after('<hr/>');
    --
    --    // Exit early if on older browser.
    --    if (!window.matchMedia) {
    --      return;
    --    }
    --
    --    // Only run logic in mobile layout.
    --    var query = window.matchMedia('(max-width: 719px)');
    --    if (query.matches) {
    --      makeTogglable();
    --    } else {
    --      query.addListener(makeTogglable);
    --    }
    --  }
    --
    --  function makeTogglable() {
    --    // Only run this logic once.
    --    if (upgraded) { return; }
    --    upgraded = true;
    --
    --    // Only make content h2s togglable.
    --    var contentTitles = h2Titles.filter('#jd-content *');
    --
    --    // If there are more than 1
    --    if (contentTitles.size() < 2) {
    --      return;
    --    }
    --
    --    contentTitles.each(function() {
    --      // Find all the relevant nodes.
    --      var $title = $(this);
    --      var $hr = $title.next();
    --      var $contents = allNextUntil($hr[0], 'h2, .next-docs');
    --      var $section = $($title)
    --        .add($hr)
    --        .add($title.prev('a[name]'))
    --        .add($contents);
    --      var $anchor = $section.first().prev();
    --      var anchorMethod = 'after';
    --      if ($anchor.length === 0) {
    --        $anchor = $title.parent();
    --        anchorMethod = 'prepend';
    --      }
    --
    --      // Some h2s are in their own container making it pretty hard to find the end, so skip.
    --      if ($contents.length === 0) {
    --        return;
    --      }
    --
    --      // Remove from DOM before messing with it. DOM is slow!
    --      $section.detach();
    --
    --      // Add mobile-only expand arrows.
    --      $title.prepend('<span class="dac-visible-mobile-inline-block">' +
    --          '<i class="dac-toggle-expand dac-sprite dac-expand-more-black"></i>' +
    --          '<i class="dac-toggle-collapse dac-sprite dac-expand-less-black"></i>' +
    --          '</span>')
    --        .attr('data-toggle', 'section');
    --
    --      // Wrap in magic markup.
    --      $section = $section.wrapAll('<div class="dac-toggle dac-mobile">').parent();
    --
    --      // extra div used for max-height calculation.
    --      $contents.wrapAll('<div class="dac-toggle-content dac-expand"><div>');
    --
    --      // Pre-expand section if requested.
    --      if ($title.hasClass('is-expanded')) {
    --        $section.addClass('is-expanded');
    --      }
    --
    --      // Pre-expand section if targetted by hash.
    --      if (location.hash && $section.find(location.hash).length) {
    --        $section.addClass('is-expanded');
    --      }
    --
    --      // Add it back to the dom.
    --      $anchor[anchorMethod].call($anchor, $section);
    --    });
    --  }
    --
    --  // Similar to $.fn.nextUntil() except we need all nodes, jQuery skips text nodes.
    --  function allNextUntil(elem, until) {
    --    var matched = [];
    --
    --    while ((elem = elem.nextSibling) && elem.nodeType !== 9) {
    --      if (elem.nodeType === 1 && jQuery(elem).is(until)) {
    --        break;
    --      }
    --      matched.push(elem);
    --    }
    --    return $(matched);
    --  }
    --
    --  $(function() {
    --    initWidget();
    --  });
    --})(jQuery);
    --
    --(function($, window) {
    --  'use strict';
    --
    --  // Blogger API info
    --  var apiUrl = 'https://www.googleapis.com/blogger/v3';
    --  var apiKey = 'AIzaSyCFhbGnjW06dYwvRCU8h_zjdpS4PYYbEe8';
    --
    --  // Blog IDs can be found in the markup of the blog posts
    --  var blogs = {
    --    'android-developers': {
    --      id: '6755709643044947179',
    --      title: 'Android Developers Blog'
    --    }
    --  };
    --  var monthNames = ['January', 'February', 'March', 'April', 'May', 'June',
    --      'July', 'August', 'September', 'October', 'November', 'December'];
    --
    --  var BlogReader = (function() {
    --    var reader;
    --
    --    function BlogReader() {
    --      this.doneSetup = false;
    --    }
    --
    --    /**
    --     * Initialize the blog reader and modal.
    --     */
    --    BlogReader.prototype.setup = function() {
    --      $('#jd-content').append(
    --          '<div id="blog-reader" data-modal="blog-reader" class="dac-modal dac-has-small-header">' +
    --            '<div class="dac-modal-container">' +
    --              '<div class="dac-modal-window">' +
    --                '<header class="dac-modal-header">' +
    --                  '<div class="dac-modal-header-actions">' +
    --                    '<a href="" class="dac-modal-header-open" target="_blank">' +
    --                      '<i class="dac-sprite dac-open-in-new"></i>' +
    --                    '</a>' +
    --                    '<button class="dac-modal-header-close" data-modal-toggle>' +
    --                    '</button>' +
    --                  '</div>' +
    --                  '<h2 class="norule dac-modal-header-title"></h2>' +
    --                '</header>' +
    --                '<div class="dac-modal-content dac-blog-reader">' +
    --                  '<time class="dac-blog-reader-date" pubDate></time>' +
    --                  '<h3 class="dac-blog-reader-title"></h3>' +
    --                  '<div class="dac-blog-reader-text clearfix"></div>' +
    --                '</div>' +
    --              '</div>' +
    --            '</div>' +
    --          '</div>');
    --
    --      this.blogReader = $('#blog-reader').dacModal();
    --
    --      this.doneSetup = true;
    --    };
    --
    --    BlogReader.prototype.openModal_ = function(blog, post) {
    --      var published = new Date(post.published);
    --      var formattedDate = monthNames[published.getMonth()] + ' ' + published.getDate() + ' ' + published.getFullYear();
    --      this.blogReader.find('.dac-modal-header-open').attr('href', post.url);
    --      this.blogReader.find('.dac-modal-header-title').text(blog.title);
    --      this.blogReader.find('.dac-blog-reader-title').html(post.title);
    --      this.blogReader.find('.dac-blog-reader-date').html(formattedDate);
    --      this.blogReader.find('.dac-blog-reader-text').html(post.content);
    --      this.blogReader.trigger('modal-open');
    --    };
    --
    --    /**
    --     * Show a blog post in a modal
    --     * @param  {string} blogName - The name of the Blogspot blog.
    --     * @param  {string} postPath - The path to the blog post.
    --     * @param  {bool} secondTry - Has it failed once?
    --     */
    --    BlogReader.prototype.showPost = function(blogName, postPath, secondTry) {
    --      var blog = blogs[blogName];
    --      var postUrl = 'https://' + blogName + '.blogspot.com' + postPath;
    --
    --      var url = apiUrl + '/blogs/' + blog.id + '/posts/bypath?path=' + encodeURIComponent(postPath) + '&key=' + apiKey;
    --      $.ajax(url, {timeout: 650}).done(this.openModal_.bind(this, blog)).fail(function(error) {
    --        // Retry once if we get an error
    --        if (error.status === 500 && !secondTry) {
    --          this.showPost(blogName, postPath, true);
    --        } else {
    --          window.location.href = postUrl;
    --        }
    --      }.bind(this));
    --    };
    --
    --    return {
    --      getReader: function() {
    --        if (!reader) {
    --          reader = new BlogReader();
    --        }
    --        return reader;
    --      }
    --    };
    --  })();
    --
    --  var blogReader = BlogReader.getReader();
    --
    --  function wrapLinkWithReader(e) {
    --    var el = $(e.currentTarget);
    --    if (el.hasClass('dac-modal-header-open')) {
    --      return;
    --    }
    --
    --    // Only catch links on blogspot.com
    --    var matches = el.attr('href').match(/https?:\/\/([^\.]*).blogspot.com([^$]*)/);
    --    if (matches && matches.length === 3) {
    --      var blogName = matches[1];
    --      var postPath = matches[2];
    --
    --      // Check if we have information about the blog
    --      if (!blogs[blogName]) {
    --        return;
    --      }
    --
    --      // Setup the first time it's used
    --      if (!blogReader.doneSetup) {
    --        blogReader.setup();
    --      }
    --
    --      e.preventDefault();
    --      blogReader.showPost(blogName, postPath);
    --    }
    --  }
    --
    --  $(document).on('click.blog-reader', 'a.resource-card[href*="blogspot.com/"]',
    --      wrapLinkWithReader);
    --})(jQuery, window);
    --
    --(function($) {
    --  $.fn.debounce = function(func, wait, immediate) {
    --    var timeout;
    --
    --    return function() {
    --      var context = this;
    --      var args = arguments;
    --
    --      var later = function() {
    --        timeout = null;
    --        if (!immediate) {
    --          func.apply(context, args);
    --        }
    --      };
    --
    --      var callNow = immediate && !timeout;
    --      clearTimeout(timeout);
    --      timeout = setTimeout(later, wait);
    --
    --      if (callNow) {
    --        func.apply(context, args);
    --      }
    --    };
    --  };
    --})(jQuery);
    --
    --/* Calculate the vertical area remaining */
    --(function($) {
    --  $.fn.ellipsisfade = function() {
    --    // Only fetch line-height of first element to avoid recalculate style.
    --    // Will be NaN if no elements match, which is ok.
    --    var lineHeight = parseInt(this.css('line-height'), 10);
    --
    --    this.each(function() {
    --      // get element text
    --      var $this = $(this);
    --      var remainingHeight = $this.parent().parent().height();
    --      $this.parent().siblings().each(function() {
    --        var elHeight;
    --        if ($(this).is(':visible')) {
    --          elHeight = $(this).outerHeight(true);
    --          remainingHeight = remainingHeight - elHeight;
    --        }
    --      });
    --
    --      var adjustedRemainingHeight = ((remainingHeight) / lineHeight >> 0) * lineHeight;
    --      $this.parent().css({height: adjustedRemainingHeight});
    --      $this.css({height: 'auto'});
    --    });
    --
    --    return this;
    --  };
    --
    --  /* Pass the line height to ellipsisfade() to adjust the height of the
    --   text container to show the max number of lines possible, without
    --   showing lines that are cut off. This works with the css ellipsis
    --   classes to fade last text line and apply an ellipsis char. */
    --  function updateEllipsis(context) {
    --    if (!(context instanceof jQuery)) {
    --      context = $('html');
    --    }
    --
    --    context.find('.card-info .text').ellipsisfade();
    --  }
    --
    --  $(window).on('resize', $.fn.debounce(updateEllipsis, 500));
    --  $(updateEllipsis);
    --  $('html').on('dac:domchange', function(e) { updateEllipsis($(e.target)); });
    --})(jQuery);
    --
    --/* Filter */
    --(function($) {
    --  'use strict';
    --
    --  /**
    --   * A single filter item content.
    --   * @type {string} - Element template.
    --   * @private
    --   */
    --  var ITEM_STR_ = '<input type="checkbox" value="{{value}}" class="dac-form-checkbox" id="{{id}}">' +
    --      '<label for="{{id}}" class="dac-form-checkbox-button"></label>' +
    --      '<label for="{{id}}" class="dac-form-label">{{name}}</label>';
    --
    --  /**
    --   * Template for a chip element.
    --   * @type {*|HTMLElement}
    --   * @private
    --   */
    --  var CHIP_BASE_ = $('<li class="dac-filter-chip">' +
    --    '<button class="dac-filter-chip-close">' +
    --      '<i class="dac-sprite dac-close-black dac-filter-chip-close-icon"></i>' +
    --    '</button>' +
    --  '</li>');
    --
    --  /**
    --   * Component to handle narrowing down resources.
    --   * @param {HTMLElement} el - The DOM element.
    --   * @param {Object} options
    --   * @constructor
    --   */
    --  function Filter(el, options) {
    --    this.el = $(el);
    --    this.options = $.extend({}, Filter.DEFAULTS_, options);
    --    this.init();
    --  }
    --
    --  Filter.DEFAULTS_ = {
    --    activeClass: 'dac-active',
    --    chipsDataAttr: 'filter-chips',
    --    nameDataAttr: 'filter-name',
    --    countDataAttr: 'filter-count',
    --    tabViewDataAttr: 'tab-view',
    --    valueDataAttr: 'filter-value'
    --  };
    --
    --  /**
    --   * Draw resource cards.
    --   * @param {Array} resources
    --   * @private
    --   */
    --  Filter.prototype.draw_ = function(resources) {
    --    var that = this;
    --
    --    if (resources.length === 0) {
    --      this.containerEl_.html('<p class="dac-filter-message">Nothing matches selected filters.</p>');
    --      return;
    --    }
    --
    --    // Draw resources.
    --    that.containerEl_.resourceWidget(resources, that.data_.options);
    --  };
    --
    --  /**
    --   * Initialize a Filter component.
    --   */
    --  Filter.prototype.init = function() {
    --    this.containerEl_ = $(this.options.filter);
    --
    --    // Setup data settings
    --    this.data_ = {};
    --    this.data_.chips = {};
    --    this.data_.options = this.containerEl_.widgetOptions();
    --    this.data_.all = window.metadata.query(this.data_.options);
    --
    --    // Initialize filter UI
    --    this.initUi();
    --  };
    --
    --  /**
    --   * Generate a chip for a given filter item.
    --   * @param {Object} item - A single filter option (checkbox container).
    --   * @returns {HTMLElement} A new Chip element.
    --   */
    --  Filter.prototype.chipForItem = function(item) {
    --    var chip = CHIP_BASE_.clone();
    --    chip.prepend(this.data_.chips[item.data('filter-value')]);
    --    chip.data('item.dac-filter', item);
    --    item.data('chip.dac-filter', chip);
    --    this.addToItemValue(item, 1);
    --    return chip[0];
    --  };
    --
    --  /**
    --   * Update count of checked filter items.
    --   * @param {Object} item - A single filter option (checkbox container).
    --   * @param {Number} value - Either -1 or 1.
    --   */
    --  Filter.prototype.addToItemValue = function(item, value) {
    --    var tab = item.parent().data(this.options.tabViewDataAttr);
    --    var countEl = this.countEl_.filter('[data-' + this.options.countDataAttr + '="' + tab + '"]');
    --    var count = value + parseInt(countEl.text(), 10);
    --    countEl.text(count);
    --    countEl.toggleClass('dac-disabled', count === 0);
    --  };
    --
    --  /**
    --   * Set event listeners.
    --   * @private
    --   */
    --  Filter.prototype.setEventListeners_ = function() {
    --    this.chipsEl_.on('click.dac-filter', '.dac-filter-chip-close', this.closeChipHandler_.bind(this));
    --    this.tabViewEl_.on('change.dac-filter', ':checkbox', this.toggleCheckboxHandler_.bind(this));
    --  };
    --
    --  /**
    --   * Check filter items that are active by default.
    --   */
    --  Filter.prototype.activateInitialFilters_ = function() {
    --    var id = (new Date()).getTime();
    --    var initiallyCheckedValues = this.data_.options.query.replace(/,\s*/g, '+').split('+');
    --    var chips = document.createDocumentFragment();
    --    var that = this;
    --
    --    this.items_.each(function(i) {
    --      var item = $(this);
    --      var opts = item.data();
    --      that.data_.chips[opts.filterValue] = opts.filterName;
    --
    --      var checkbox = $(ITEM_STR_.replace(/\{\{name\}\}/g, opts.filterName)
    --        .replace(/\{\{value\}\}/g, opts.filterValue)
    --        .replace(/\{\{id\}\}/g, 'filter-' + id + '-' + (i + 1)));
    --
    --      if (initiallyCheckedValues.indexOf(opts.filterValue) > -1) {
    --        checkbox[0].checked = true;
    --        chips.appendChild(that.chipForItem(item));
    --      }
    --
    --      item.append(checkbox);
    --    });
    --
    --    this.chipsEl_.append(chips);
    --  };
    --
    --  /**
    --   * Initialize the Filter view
    --   */
    --  Filter.prototype.initUi = function() {
    --    // Cache DOM elements
    --    this.chipsEl_ = this.el.find('[data-' + this.options.chipsDataAttr + ']');
    --    this.countEl_ = this.el.find('[data-' + this.options.countDataAttr + ']');
    --    this.tabViewEl_ = this.el.find('[data-' + this.options.tabViewDataAttr + ']');
    --    this.items_ = this.el.find('[data-' + this.options.nameDataAttr + ']');
    --
    --    // Setup UI
    --    this.draw_(this.data_.all);
    --    this.activateInitialFilters_();
    --    this.setEventListeners_();
    --  };
    --
    --  /**
    --   * @returns {[types|Array, tags|Array, category|Array]}
    --   */
    --  Filter.prototype.getActiveClauses = function() {
    --    var tags = [];
    --    var types = [];
    --    var categories = [];
    --
    --    this.items_.find(':checked').each(function(i, checkbox) {
    --      // Currently, there is implicit business logic here that `tag` is AND'ed together
    --      // while `type` is OR'ed. So , and + do the same thing here. It would be great to
    --      // reuse the same query engine for filters, but it would need more powerful syntax.
    --      // Probably parenthesis, to support "tag:dog + tag:cat + (type:video, type:blog)"
    --      var expression = $(checkbox).val();
    --      var regex = /(\w+):(\w+)/g;
    --      var match;
    --
    --      while (match = regex.exec(expression)) {
    --        switch (match[1]) {
    --          case 'category':
    --            categories.push(match[2]);
    --            break;
    --          case 'tag':
    --            tags.push(match[2]);
    --            break;
    --          case 'type':
    --            types.push(match[2]);
    --            break;
    --        }
    --      }
    --    });
    --
    --    return [types, tags, categories];
    --  };
    --
    --  /**
    --   * Actual filtering logic.
    --   * @returns {Array}
    --   */
    --  Filter.prototype.filteredResources = function() {
    --    var data = this.getActiveClauses();
    --    var types = data[0];
    --    var tags = data[1];
    --    var categories = data[2];
    --    var resources = [];
    --    var resource = {};
    --    var tag = '';
    --    var shouldAddResource = true;
    --
    --    for (var resourceIndex = 0; resourceIndex < this.data_.all.length; resourceIndex++) {
    --      resource = this.data_.all[resourceIndex];
    --      shouldAddResource = types.indexOf(resource.type) > -1;
    --
    --      if (categories && categories.length > 0) {
    --        shouldAddResource = shouldAddResource && categories.indexOf(resource.category) > -1;
    --      }
    --
    --      for (var tagIndex = 0; shouldAddResource && tagIndex < tags.length; tagIndex++) {
    --        tag = tags[tagIndex];
    --        shouldAddResource = resource.tags.indexOf(tag) > -1;
    --      }
    --
    --      if (shouldAddResource) {
    --        resources.push(resource);
    --      }
    --    }
    --
    --    return resources;
    --  };
    --
    --  /**
    --   * Close Chip Handler
    --   * @param {Event} event - Click event
    --   * @private
    --   */
    --  Filter.prototype.closeChipHandler_ = function(event) {
    --    var chip = $(event.currentTarget).parent();
    --    var checkbox = chip.data('item.dac-filter').find(':first-child')[0];
    --    checkbox.checked = false;
    --    this.changeStateForCheckbox(checkbox);
    --  };
    --
    --  /**
    --   * Handle filter item state change.
    --   * @param {Event} event - Change event
    --   * @private
    --   */
    --  Filter.prototype.toggleCheckboxHandler_ = function(event) {
    --    this.changeStateForCheckbox(event.currentTarget);
    --  };
    --
    --  /**
    --   * Redraw resource view based on new state.
    --   * @param checkbox
    --   */
    --  Filter.prototype.changeStateForCheckbox = function(checkbox) {
    --    var item = $(checkbox).parent();
    --
    --    if (checkbox.checked) {
    --      this.chipsEl_.append(this.chipForItem(item));
    --      devsite.analytics.trackAnalyticsEvent('event',
    --          'Filters', 'Check', $(checkbox).val());
    --    } else {
    --      item.data('chip.dac-filter').remove();
    --      this.addToItemValue(item, -1);
    --      devsite.analytics.trackAnalyticsEvent('event',
    --          'Filters', 'Uncheck', $(checkbox).val());
    --    }
    --
    --    this.draw_(this.filteredResources());
    --  };
    --
    --  /**
    --   * jQuery plugin
    --   */
    --  $.fn.dacFilter = function() {
    --    return this.each(function() {
    --      var el = $(this);
    --      new Filter(el, el.data());
    --    });
    --  };
    --
    --  /**
    --   * Data Attribute API
    --   */
    --  $(function() {
    --    $('[data-filter]').dacFilter();
    --  });
    --})(jQuery);
    --
    --(function($) {
    --  'use strict';
    --
    --  /**
    --   * Toggle Floating Label state.
    --   * @param {HTMLElement} el - The DOM element.
    --   * @param options
    --   * @constructor
    --   */
    --  function FloatingLabel(el, options) {
    --    this.el = $(el);
    --    this.options = $.extend({}, FloatingLabel.DEFAULTS_, options);
    --    this.group = this.el.closest('.dac-form-input-group');
    --    this.input = this.group.find('.dac-form-input');
    --
    --    this.checkValue_ = this.checkValue_.bind(this);
    --    this.checkValue_();
    --
    --    this.input.on('focus', function() {
    --      this.group.addClass('dac-focused');
    --    }.bind(this));
    --    this.input.on('blur', function() {
    --      this.group.removeClass('dac-focused');
    --      this.checkValue_();
    --    }.bind(this));
    --    this.input.on('keyup', this.checkValue_);
    --  }
    --
    --  /**
    --   * The label is moved out of the textbox when it has a value.
    --   */
    --  FloatingLabel.prototype.checkValue_ = function() {
    --    if (this.input.val().length) {
    --      this.group.addClass('dac-has-value');
    --    } else {
    --      this.group.removeClass('dac-has-value');
    --    }
    --  };
    --
    --  /**
    --   * jQuery plugin
    --   * @param  {object} options - Override default options.
    --   */
    --  $.fn.dacFloatingLabel = function(options) {
    --    return this.each(function() {
    --      new FloatingLabel(this, options);
    --    });
    --  };
    --
    --  $(document).on('ready.aranja', function() {
    --    $('.dac-form-floatlabel').each(function() {
    --      $(this).dacFloatingLabel($(this).data());
    --    });
    --  });
    --})(jQuery);
    --
    --(function($) {
    --  'use strict';
    --
    --  /**
    --   * @param {HTMLElement} el - The DOM element.
    --   * @param {Object} options
    --   * @constructor
    --   */
    --  function Crumbs(selected, options) {
    --    this.options = $.extend({}, Crumbs.DEFAULTS_, options);
    --    this.el = $(this.options.container);
    --
    --    // Do not build breadcrumbs for landing site.
    --    if (!selected || location.pathname === '/index.html' || location.pathname === '/') {
    --      return;
    --    }
    --
    --    // Cache navigation resources
    --    this.selected = $(selected);
    --    this.selectedParent = this.selected.closest('.dac-nav-secondary').siblings('a');
    --
    --    // Build the breadcrumb list.
    --    this.init();
    --  }
    --
    --  Crumbs.DEFAULTS_ = {
    --    container: '.dac-header-crumbs',
    --    crumbItem: $('<li class="dac-header-crumbs-item">'),
    --    linkClass: 'dac-header-crumbs-link'
    --  };
    --
    --  Crumbs.prototype.init = function() {
    --    Crumbs.buildCrumbForLink(this.selected.clone()).appendTo(this.el);
    --
    --    if (this.selectedParent.length) {
    --      Crumbs.buildCrumbForLink(this.selectedParent.clone()).prependTo(this.el);
    --    }
    --
    --    // Reveal the breadcrumbs
    --    this.el.addClass('dac-has-content');
    --  };
    --
    --  /**
    --   * Build a HTML structure for a breadcrumb.
    --   * @param {string} link
    --   * @return {jQuery}
    --   */
    --  Crumbs.buildCrumbForLink = function(link) {
    --    link.find('br').replaceWith(' ');
    --
    --    var crumbLink = $('<a>')
    --      .attr('class', Crumbs.DEFAULTS_.linkClass)
    --      .attr('href', link.attr('href'))
    --      .text(link.text());
    --
    --    return Crumbs.DEFAULTS_.crumbItem.clone().append(crumbLink);
    --  };
    --
    --  /**
    --   * jQuery plugin
    --   */
    --  $.fn.dacCrumbs = function(options) {
    --    return this.each(function() {
    --      new Crumbs(this, options);
    --    });
    --  };
    --})(jQuery);
    --
    --(function($) {
    --  'use strict';
    --
    --  /**
    --   * @param {HTMLElement} el - The DOM element.
    --   * @param {Object} options
    --   * @constructor
    --   */
    --  function SearchInput(el, options) {
    --    this.el = $(el);
    --    this.options = $.extend({}, SearchInput.DEFAULTS_, options);
    --    this.body = $('body');
    --    this.input = this.el.find('input');
    --    this.close = this.el.find(this.options.closeButton);
    --    this.clear = this.el.find(this.options.clearButton);
    --    this.icon = this.el.find('.' + this.options.iconClass);
    --    this.init();
    --  }
    --
    --  SearchInput.DEFAULTS_ = {
    --    activeClass: 'dac-active',
    --    activeIconClass: 'dac-search',
    --    closeButton: '[data-search-close]',
    --    clearButton: '[data-search-clear]',
    --    hiddenClass: 'dac-hidden',
    --    iconClass: 'dac-header-search-icon',
    --    searchModeClass: 'dac-search-mode',
    --    transitionDuration: 250
    --  };
    --
    --  SearchInput.prototype.init = function() {
    --    this.input.on('focus.dac-search', this.setActiveState.bind(this))
    --              .on('input.dac-search', this.checkInputValue.bind(this));
    --    this.close.on('click.dac-search', this.unsetActiveStateHandler_.bind(this));
    --    this.clear.on('click.dac-search', this.clearInput.bind(this));
    --  };
    --
    --  SearchInput.prototype.setActiveState = function() {
    --    var that = this;
    --
    --    this.clear.addClass(this.options.hiddenClass);
    --    this.body.addClass(this.options.searchModeClass);
    --    this.checkInputValue();
    --
    --    // Set icon to black after background has faded to white.
    --    setTimeout(function() {
    --      that.icon.addClass(that.options.activeIconClass);
    --    }, this.options.transitionDuration);
    --  };
    --
    --  SearchInput.prototype.unsetActiveStateHandler_ = function(event) {
    --    event.preventDefault();
    --    this.unsetActiveState();
    --  };
    --
    --  SearchInput.prototype.unsetActiveState = function() {
    --    this.icon.removeClass(this.options.activeIconClass);
    --    this.clear.addClass(this.options.hiddenClass);
    --    this.body.removeClass(this.options.searchModeClass);
    --  };
    --
    --  SearchInput.prototype.clearInput = function(event) {
    --    event.preventDefault();
    --    this.input.val('');
    --    this.clear.addClass(this.options.hiddenClass);
    --  };
    --
    --  SearchInput.prototype.checkInputValue = function() {
    --    if (this.input.val().length) {
    --      this.clear.removeClass(this.options.hiddenClass);
    --    } else {
    --      this.clear.addClass(this.options.hiddenClass);
    --    }
    --  };
    --
    --  /**
    --   * jQuery plugin
    --   * @param {object} options - Override default options.
    --   */
    --  $.fn.dacSearchInput = function() {
    --    return this.each(function() {
    --      var el = $(this);
    --      el.data('search-input.dac', new SearchInput(el, el.data()));
    --    });
    --  };
    --
    --  /**
    --   * Data Attribute API
    --   */
    --  $(function() {
    --    $('[data-search]').dacSearchInput();
    --  });
    --})(jQuery);
    --
    --/* global METADATA */
    --(function($) {
    --  function DacCarouselQuery(el) {
    --    el = $(el);
    --
    --    var opts = el.data();
    --    opts.maxResults = parseInt(opts.maxResults || '100', 10);
    --    opts.query = opts.carouselQuery;
    --    var resources = window.metadata.query(opts);
    --
    --    el.empty();
    --    $(resources).each(function() {
    --      var resource = $.extend({}, this, METADATA.carousel[this.url]);
    --      el.dacHero(resource);
    --    });
    --
    --    // Pagination element.
    --    el.append('<div class="dac-hero-carousel-pagination"><div class="wrap" data-carousel-pagination>');
    --
    --    el.dacCarousel();
    --  }
    --
    --  // jQuery plugin
    --  $.fn.dacCarouselQuery = function() {
    --    return this.each(function() {
    --      var el = $(this);
    --      var data = el.data('dac.carouselQuery');
    --
    --      if (!data) { el.data('dac.carouselQuery', (data = new DacCarouselQuery(el))); }
    --    });
    --  };
    --
    --  // Data API
    --  $(function() {
    --    $('[data-carousel-query]').dacCarouselQuery();
    --  });
    --})(jQuery);
    --
    --(function($) {
    --  /**
    --   * A CSS based carousel, inspired by SequenceJS.
    --   * @param {jQuery} el
    --   * @param {object} options
    --   * @constructor
    --   */
    --  function DacCarousel(el, options) {
    --    this.el = $(el);
    --    this.options = options = $.extend({}, DacCarousel.OPTIONS, this.el.data(), options || {});
    --    this.frames = this.el.find(options.frameSelector);
    --    this.count = this.frames.size();
    --    this.current = options.start;
    --
    --    this.initPagination();
    --    this.initEvents();
    --    this.initFrame();
    --  }
    --
    --  DacCarousel.OPTIONS = {
    --    auto:      true,
    --    autoTime:  10000,
    --    autoMinTime: 5000,
    --    btnPrev:   '[data-carousel-prev]',
    --    btnNext:   '[data-carousel-next]',
    --    frameSelector: 'article',
    --    loop:      true,
    --    start:     0,
    --    swipeThreshold: 160,
    --    pagination: '[data-carousel-pagination]'
    --  };
    --
    --  DacCarousel.prototype.initPagination = function() {
    --    this.pagination = $([]);
    --    if (!this.options.pagination) { return; }
    --
    --    var pagination = $('<ul class="dac-pagination">');
    --    var parent = this.el;
    --    if (typeof this.options.pagination === 'string') { parent = this.el.find(this.options.pagination); }
    --
    --    if (this.count > 1) {
    --      for (var i = 0; i < this.count; i++) {
    --        var li = $('<li class="dac-pagination-item">').text(i);
    --        if (i === this.options.start) { li.addClass('active'); }
    --        li.click(this.go.bind(this, i));
    --
    --        pagination.append(li);
    --      }
    --      this.pagination = pagination.children();
    --      parent.append(pagination);
    --    }
    --  };
    --
    --  DacCarousel.prototype.initEvents = function() {
    --    var that = this;
    --
    --    this.touch = {
    --      start: {x: 0, y: 0},
    --      end:   {x: 0, y: 0}
    --    };
    --
    --    this.el.on('touchstart', this.touchstart_.bind(this));
    --    this.el.on('touchend', this.touchend_.bind(this));
    --    this.el.on('touchmove', this.touchmove_.bind(this));
    --
    --    this.el.hover(function() {
    --      that.pauseRotateTimer();
    --    }, function() {
    --      that.startRotateTimer();
    --    });
    --
    --    $(this.options.btnPrev).click(function(e) {
    --      e.preventDefault();
    --      that.prev();
    --    });
    --
    --    $(this.options.btnNext).click(function(e) {
    --      e.preventDefault();
    --      that.next();
    --    });
    --  };
    --
    --  DacCarousel.prototype.touchstart_ = function(event) {
    --    var t = event.originalEvent.touches[0];
    --    this.touch.start = {x: t.screenX, y: t.screenY};
    --  };
    --
    --  DacCarousel.prototype.touchend_ = function() {
    --    var deltaX = this.touch.end.x - this.touch.start.x;
    --    var deltaY = Math.abs(this.touch.end.y - this.touch.start.y);
    --    var shouldSwipe = (deltaY < Math.abs(deltaX)) && (Math.abs(deltaX) >= this.options.swipeThreshold);
    --
    --    if (shouldSwipe) {
    --      if (deltaX > 0) {
    --        this.prev();
    --      } else {
    --        this.next();
    --      }
    --    }
    --  };
    --
    --  DacCarousel.prototype.touchmove_ = function(event) {
    --    var t = event.originalEvent.touches[0];
    --    this.touch.end = {x: t.screenX, y: t.screenY};
    --  };
    --
    --  DacCarousel.prototype.initFrame = function() {
    --    this.frames.removeClass('active').eq(this.options.start).addClass('active');
    --  };
    --
    --  DacCarousel.prototype.startRotateTimer = function() {
    --    if (!this.options.auto || this.rotateTimer) { return; }
    --    this.rotateTimer = setTimeout(this.next.bind(this), this.options.autoTime);
    --  };
    --
    --  DacCarousel.prototype.pauseRotateTimer = function() {
    --    clearTimeout(this.rotateTimer);
    --    this.rotateTimer = null;
    --  };
    --
    --  DacCarousel.prototype.prev = function() {
    --    this.go(this.current - 1);
    --  };
    --
    --  DacCarousel.prototype.next = function() {
    --    this.go(this.current + 1);
    --  };
    --
    --  DacCarousel.prototype.go = function(next) {
    --    // Figure out what the next slide is.
    --    while (this.count > 0 && next >= this.count) { next -= this.count; }
    --    while (next < 0) { next += this.count; }
    --
    --    // Cancel if we're already on that slide.
    --    if (next === this.current) { return; }
    --
    --    // Prepare next slide.
    --    this.frames.eq(next).removeClass('out');
    --
    --    // Recalculate styles before starting slide transition.
    --    this.el.resolveStyles();
    --    // Update pagination
    --    this.pagination.removeClass('active').eq(next).addClass('active');
    --
    --    // Transition out current frame
    --    this.frames.eq(this.current).toggleClass('active out');
    --
    --    // Transition in a new frame
    --    this.frames.eq(next).toggleClass('active');
    --
    --    this.current = next;
    --  };
    --
    --  // Helper which resolves new styles for an element, so it can start transitioning
    --  // from the new values.
    --  $.fn.resolveStyles = function() {
    --    /*jshint expr:true*/
    --    this[0] && this[0].offsetTop;
    --    return this;
    --  };
    --
    --  // jQuery plugin
    --  $.fn.dacCarousel = function() {
    --    this.each(function() {
    --      var $el = $(this);
    --      $el.data('dac-carousel', new DacCarousel(this));
    --    });
    --    return this;
    --  };
    --
    --  // Data API
    --  $(function() {
    --    $('[data-carousel]').dacCarousel();
    --  });
    --})(jQuery);
    --
    --/* global toRoot */
    --
    --(function($) {
    --  // Ordering matters
    --  var TAG_MAP = [
    --    {from: 'developerstory', to: 'Android Developer Story'},
    --    {from: 'googleplay', to: 'Google Play'}
    --  ];
    --
    --  function DacHero(el, resource, isSearch) {
    --    var slide = $('<article>');
    --    slide.addClass(isSearch ? 'dac-search-hero' : 'dac-expand dac-hero');
    --    var image = cleanUrl(resource.heroImage || resource.image);
    --    var fullBleed = image && !resource.heroColor;
    --
    --    if (!isSearch) {
    --      // Configure background
    --      slide.css({
    --        backgroundImage: fullBleed ? 'url(' + image + ')' : '',
    --        backgroundColor: resource.heroColor || ''
    --      });
    --
    --      // Should copy be inverted
    --      slide.toggleClass('dac-invert', resource.heroInvert || fullBleed);
    --      slide.toggleClass('dac-darken', fullBleed);
    --
    --      // Should be clickable
    --      slide.append($('<a class="dac-hero-carousel-action">').attr('href', cleanUrl(resource.url)));
    --    }
    --
    --    var cols = $('<div class="cols dac-hero-content">');
    --
    --    // inline image column
    --    var rightCol = $('<div class="col-1of2 col-push-1of2 dac-hero-figure">')
    --      .appendTo(cols);
    --
    --    if ((!fullBleed || isSearch) && image) {
    --      rightCol.append($('<img>').attr('src', image));
    --    }
    --
    --    // info column
    --    $('<div class="col-1of2 col-pull-1of2">')
    --      .append($('<div class="dac-hero-tag">').text(formatTag(resource)))
    --      .append($('<h1 class="dac-hero-title">').text(formatTitle(resource)))
    --      .append($('<p class="dac-hero-description">').text(resource.summary))
    --      .append($('<a class="dac-hero-cta">')
    --        .text(formatCTA(resource))
    --        .attr('href', cleanUrl(resource.url))
    --        .prepend($('<span class="dac-sprite dac-auto-chevron">'))
    --      )
    --      .appendTo(cols);
    --
    --    slide.append(cols.wrap('<div class="wrap">').parent());
    --    el.append(slide);
    --  }
    --
    --  function cleanUrl(url) {
    --    if (url && url.indexOf('//') === -1) {
    --      url = toRoot + url;
    --    }
    --    return url;
    --  }
    --
    --  function formatTag(resource) {
    --    // Hmm, need a better more scalable solution for this.
    --    for (var i = 0, mapping; mapping = TAG_MAP[i]; i++) {
    --      if (resource.tags.indexOf(mapping.from) > -1) {
    --        return mapping.to;
    --      }
    --    }
    --    return resource.type;
    --  }
    --
    --  function formatTitle(resource) {
    --    return resource.title.replace(/android developer story: /i, '');
    --  }
    --
    --  function formatCTA(resource) {
    --    return resource.type === 'youtube' ? 'Watch the video' : 'Learn more';
    --  }
    --
    --  // jQuery plugin
    --  $.fn.dacHero = function(resource, isSearch) {
    --    return this.each(function() {
    --      var el = $(this);
    --      return new DacHero(el, resource, isSearch);
    --    });
    --  };
    --})(jQuery);
    --
    --(function($) {
    --  'use strict';
    --
    --  function highlightString(label, query) {
    --    query = query || '';
    --    //query = query.replace('<wbr>', '').replace('.', '\\.');
    --    var queryRE = new RegExp('(' + query + ')', 'ig');
    --    return label.replace(queryRE, '<em>$1</em>');
    --  }
    --
    --  $.fn.highlightMatches = function(query) {
    --    return this.each(function() {
    --      var el = $(this);
    --      var label = el.html();
    --      var highlighted = highlightString(label, query);
    --      el.html(highlighted);
    --      el.addClass('highlighted');
    --    });
    --  };
    --})(jQuery);
    --
    --/**
    -- * History tracking.
    -- * Track visited urls in localStorage.
    -- */
    --(function($) {
    --  var PAGES_TO_STORE_ = 100;
    --  var MIN_NUMBER_OF_PAGES_TO_DISPLAY_ = 6;
    --  var CONTAINER_SELECTOR_ = '.dac-search-results-history-wrap';
    --
    --  /**
    --   * Generate resource cards for visited pages.
    --   * @param {HTMLElement} el
    --   * @constructor
    --   */
    --  function HistoryQuery(el) {
    --    this.el = $(el);
    --
    --    // Only show history component if enough pages have been visited.
    --    if (getVisitedPages().length < MIN_NUMBER_OF_PAGES_TO_DISPLAY_) {
    --      this.el.closest(CONTAINER_SELECTOR_).addClass('dac-hidden');
    --      return;
    --    }
    --
    --    // Rename query
    --    this.el.data('query', this.el.data('history-query'));
    --
    --    // jQuery method to populate cards.
    --    this.el.resourceWidget();
    --  }
    --
    --  /**
    --   * Fetch from localStorage an array of visted pages
    --   * @returns {Array}
    --   */
    --  function getVisitedPages() {
    --    var visited = localStorage.getItem('visited-pages');
    --    return visited ? JSON.parse(visited) : [];
    --  }
    --
    --  /**
    --   * Return a page corresponding to cuurent pathname. If none exists, create one.
    --   * @param {Array} pages
    --   * @param {String} path
    --   * @returns {Object} Page
    --   */
    --  function getPageForPath(pages, path) {
    --    var page;
    --
    --    // Backwards lookup for current page, last pages most likely to be visited again.
    --    for (var i = pages.length - 1; i >= 0; i--) {
    --      if (pages[i].path === path) {
    --        page = pages[i];
    --
    --        // Remove page object from pages list to ensure correct ordering.
    --        pages.splice(i, 1);
    --
    --        return page;
    --      }
    --    }
    --
    --    // If storage limit is exceeded, remove last visited path.
    --    if (pages.length >= PAGES_TO_STORE_) {
    --      pages.shift();
    --    }
    --
    --    return {path: path};
    --  }
    --
    --  /**
    --   * Add current page to back of visited array, increase hit count by 1.
    --   */
    --  function addCurrectPage() {
    --    var path = location.pathname;
    --
    --    // Do not track frontpage visits.
    --    if (path === '/' || path === '/index.html') {return;}
    --
    --    var pages = getVisitedPages();
    --    var page = getPageForPath(pages, path);
    --
    --    // New page visits have no hit count.
    --    page.hit = ~~page.hit + 1;
    --
    --    // Most recently visted pages are located at the end of the visited array.
    --    pages.push(page);
    --
    --    localStorage.setItem('visited-pages', JSON.stringify(pages));
    --  }
    --
    --  /**
    --   * Hit count compare function.
    --   * @param {Object} a - page
    --   * @param {Object} b - page
    --   * @returns {number}
    --   */
    --  function byHit(a, b) {
    --    if (a.hit > b.hit) {
    --      return -1;
    --    } else if (a.hit < b.hit) {
    --      return 1;
    --    }
    --
    --    return 0;
    --  }
    --
    --  /**
    --   * Return a list of visited urls in a given order.
    --   * @param {String} order - (recent|most-visited)
    --   * @returns {Array}
    --   */
    --  $.dacGetVisitedUrls = function(order) {
    --    var pages = getVisitedPages();
    --
    --    if (order === 'recent') {
    --      pages.reverse();
    --    } else {
    --      pages.sort(byHit);
    --    }
    --
    --    return pages.map(function(page) {
    --      return page.path.replace(/^\//, '');
    --    });
    --  };
    --
    --  // jQuery plugin
    --  $.fn.dacHistoryQuery = function() {
    --    return this.each(function() {
    --      var el = $(this);
    --      var data = el.data('dac.recentlyVisited');
    --
    --      if (!data) {
    --        el.data('dac.recentlyVisited', (data = new HistoryQuery(el)));
    --      }
    --    });
    --  };
    --
    --  $(function() {
    --    $('[data-history-query]').dacHistoryQuery();
    --    // Do not block page rendering.
    --    setTimeout(addCurrectPage, 0);
    --  });
    --})(jQuery);
    --
    --/* ############################################ */
    --/* ##########     LOCALIZATION     ############ */
    --/* ############################################ */
    --/**
    -- * Global helpers.
    -- */
    --function getBaseUri(uri) {
    --  var intlUrl = (uri.substring(0, 6) === '/intl/');
    --  if (intlUrl) {
    --    var base = uri.substring(uri.indexOf('intl/') + 5, uri.length);
    --    base = base.substring(base.indexOf('/') + 1, base.length);
    --    return '/' + base;
    --  } else {
    --    return uri;
    --  }
    --}
    --
    --function changeLangPref(targetLang, submit) {
    --  window.writeCookie('pref_lang', targetLang, null);
    --  $('#language').find('option[value="' + targetLang + '"]').attr('selected', true);
    --  if (submit) {
    --    $('#setlang').submit();
    --  }
    --}
    --// Redundant usage to appease jshint.
    --window.changeLangPref = changeLangPref;
    --
    --(function() {
    --  /**
    --   * Whitelisted locales. Should match choices in language dropdown. Repeated here
    --   * as a lot of i18n logic happens before page load and dropdown is ready.
    --   */
    --  var LANGUAGES = [
    --    'en',
    --    'es',
    --    'in',
    --    'ja',
    --    'ko',
    --    'pt-br',
    --    'ru',
    --    'vi',
    --    'zh-cn',
    --    'zh-tw'
    --  ];
    --
    --  /**
    --   * Master list of translated strings for template files.
    --   */
    --  var PHRASES = {
    --    'newsletter': {
    --      'title': 'Get the latest Android developer news and tips that will help you find success on Google Play.',
    --      'requiredHint': '* Required Fields',
    --      'name': 'Full name',
    --      'email': 'Email address',
    --      'company': 'Company / developer name',
    --      'appUrl': 'One of your Play Store app URLs',
    --      'business': {
    --        'label': 'Which best describes your business:',
    --        'apps': 'Apps',
    --        'games': 'Games',
    --        'both': 'Apps & Games'
    --      },
    --      'confirmMailingList': 'Add me to the mailing list for the monthly newsletter and occasional emails about ' +
    --                            'development and Google Play opportunities.',
    --      'privacyPolicy': 'I acknowledge that the information provided in this form will be subject to Google\'s ' +
    --                       '<a href="https://www.google.com/policies/privacy/" target="_blank">privacy policy</a>.',
    --      'languageVal': 'English',
    --      'successTitle': 'Hooray!',
    --      'successDetails': 'You have successfully signed up for the latest Android developer news and tips.',
    --      'languageValTarget': {
    --        'en': 'English',
    --        'ar': 'Arabic (العربيّة)',
    --        'in': 'Indonesian (Bahasa)',
    --        'fr': 'French (français)',
    --        'de': 'German (Deutsch)',
    --        'ja': 'Japanese (日本語)',
    --        'ko': 'Korean (한국어)',
    --        'ru': 'Russian (Русский)',
    --        'es': 'Spanish (español)',
    --        'th': 'Thai (ภาษาไทย)',
    --        'tr': 'Turkish (Türkçe)',
    --        'vi': 'Vietnamese (tiếng Việt)',
    --        'pt-br': 'Brazilian Portuguese (Português Brasileiro)',
    --        'zh-cn': 'Simplified Chinese (简体中文)',
    --        'zh-tw': 'Traditional Chinese (繁體中文)',
    --      },
    --      'resetLangTitle': "Browse this site in %{targetLang}?",
    --      'resetLangTextIntro': 'You requested a page in %{targetLang}, but your language preference for this site is %{lang}.',
    --      'resetLangTextCta': 'Would you like to change your language preference and browse this site in %{targetLang}? ' +
    --                          'If you want to change your language preference later, use the language menu at the bottom of each page.',
    --      'resetLangButtonYes': 'Change Language',
    --      'resetLangButtonNo': 'Not Now'
    --    }
    --  };
    --
    --  /**
    --   * Current locale.
    --   */
    --  var locale = (function() {
    --    var lang = window.readCookie('pref_lang');
    --    if (lang === 0 || LANGUAGES.indexOf(lang) === -1) {
    --      lang = 'en';
    --    }
    --    return lang;
    --  })();
    --  var localeTarget = (function() {
    --    var lang = getQueryVariable('hl');
    --    if (lang === false || LANGUAGES.indexOf(lang) === -1) {
    --      lang = locale;
    --    }
    --    return lang;
    --  })();
    --
    --  /**
    --   * Global function shims for backwards compatibility
    --   */
    --  window.changeNavLang = function() {
    --    // Already done.
    --  };
    --
    --  window.loadLangPref = function() {
    --    // Languages pref already loaded.
    --  };
    --
    --  window.getLangPref = function() {
    --    return locale;
    --  };
    --
    --  window.getLangTarget = function() {
    --    return localeTarget;
    --  };
    --
    --  // Expose polyglot instance for advanced localization.
    --  var polyglot = window.polyglot = new window.Polyglot({
    --    locale: locale,
    --    phrases: PHRASES
    --  });
    --
    --  // When DOM is ready.
    --  $(function() {
    --    // Mark current locale in language picker.
    --    $('#language').find('option[value="' + locale + '"]').attr('selected', true);
    --
    --    $('html').dacTranslate().on('dac:domchange', function(e) {
    --      $(e.target).dacTranslate();
    --    });
    --  });
    --
    --  $.fn.dacTranslate = function() {
    --    // Translate strings in template markup:
    --
    --    // OLD
    --    // Having all translations in HTML does not scale well and bloats every page.
    --    // Need to migrate this to data-l JS translations below.
    --    if (locale !== 'en') {
    --      var $links = this.find('a[' + locale + '-lang]');
    --      $links.each(function() { // for each link with a translation
    --        var $link = $(this);
    --        // put the desired language from the attribute as the text
    --        $link.text($link.attr(locale + '-lang'));
    --      });
    --    }
    --
    --    // NEW
    --    // A simple declarative api for JS translations. Feel free to extend as appropriate.
    --
    --    // Miscellaneous string compilations
    --    // Build full strings from localized substrings:
    --    var myLocaleTarget = window.getLangTarget();
    --    var myTargetLang = window.polyglot.t("newsletter.languageValTarget." + myLocaleTarget);
    --    var myLang = window.polyglot.t("newsletter.languageVal");
    --    var myTargetLangTitleString = window.polyglot.t("newsletter.resetLangTitle", {targetLang: myTargetLang});
    --    var myResetLangTextIntro = window.polyglot.t("newsletter.resetLangTextIntro", {targetLang: myTargetLang, lang: myLang});
    --    var myResetLangTextCta = window.polyglot.t("newsletter.resetLangTextCta", {targetLang: myTargetLang});
    --    //var myResetLangButtonYes = window.polyglot.t("newsletter.resetLangButtonYes", {targetLang: myTargetLang});
    --
    --    // Inject strings as text values in dialog components:
    --    $("#langform .dac-modal-header-title").text(myTargetLangTitleString);
    --    $("#langform #resetLangText").text(myResetLangTextIntro);
    --    $("#langform #resetLangCta").text(myResetLangTextCta);
    --    //$("#resetLangButtonYes").attr("data-t", window.polyglot.t(myResetLangButtonYes));
    --
    --    // Text: <div data-t="nav.home"></div>
    --    // HTML: <div data-t="privacy" data-t-html></html>
    --    this.find('[data-t]').each(function() {
    --      var el = $(this);
    --      var data = el.data();
    --      if (data.t) {
    --        el[data.tHtml === '' ? 'html' : 'text'](polyglot.t(data.t));
    --      }
    --    });
    --
    --    return this;
    --  };
    --})();
    --/* ##########     END LOCALIZATION     ############ */
    --
    --// Translations. These should eventually be moved into language-specific files and loaded on demand.
    --// jshint nonbsp:false
    --switch (window.getLangPref()) {
    --  case 'ar':
    --    window.polyglot.extend({
    --      'newsletter': {
    --        'title': 'Google Play. يمكنك الحصول على آخر الأخبار والنصائح من مطوّري تطبيقات Android، مما يساعدك ' +
    --          'على تحقيق النجاح على',
    --        'requiredHint': '* حقول مطلوبة',
    --        'name': '. الاسم بالكامل ',
    --        'email': '. عنوان البريد الإلكتروني ',
    --        'company': '. اسم الشركة / اسم مطوّر البرامج',
    --        'appUrl': '. أحد عناوين URL لتطبيقاتك في متجر Play',
    --        'business': {
    --          'label': '. ما العنصر الذي يوضح طبيعة نشاطك التجاري بدقة؟ ',
    --          'apps': 'التطبيقات',
    --          'games': 'الألعاب',
    --          'both': 'التطبيقات والألعاب'
    --        },
    --        'confirmMailingList': 'إضافتي إلى القائمة البريدية للنشرة الإخبارية الشهرية والرسائل الإلكترونية التي يتم' +
    --          ' إرسالها من حين لآخر بشأن التطوير وفرص Google Play.',
    --        'privacyPolicy': 'أقر بأن المعلومات المقدَّمة في هذا النموذج تخضع لسياسة خصوصية ' +
    --          '<a href="https://www.google.com/intl/ar/policies/privacy/" target="_blank">Google</a>.',
    --        'languageVal': 'Arabic (العربيّة)',
    --        'successTitle': 'رائع!',
    --        'successDetails': 'لقد اشتركت بنجاح للحصول على آخر الأخبار والنصائح من مطوّري برامج Android.'
    --      }
    --    });
    --    break;
    --  case 'zh-cn':
    --    window.polyglot.extend({
    --      'newsletter': {
    --        'title': '获取最新的 Android 开发者资讯和提示,助您在 Google Play 上取得成功。',
    --        'requiredHint': '* 必填字段',
    --        'name': '全名',
    --        'email': '电子邮件地址',
    --        'company': '公司/开发者名称',
    --        'appUrl': '您的某个 Play 商店应用网址',
    --        'business': {
    --          'label': '哪一项能够最准确地描述您的业务?',
    --          'apps': '应用',
    --          'games': '游戏',
    --          'both': '应用和游戏'
    --        },
    --        'confirmMailingList': '将我添加到邮寄名单,以便接收每月简报以及不定期发送的关于开发和 Google Play 商机的电子邮件。',
    --        'privacyPolicy': '我确认自己了解在此表单中提供的信息受 <a href="https://www.google.com/intl/zh-CN/' +
    --        'policies/privacy/" target="_blank">Google</a> 隐私权政策的约束。',
    --        'languageVal': 'Simplified Chinese (简体中文)',
    --        'successTitle': '太棒了!',
    --        'successDetails': '您已成功订阅最新的 Android 开发者资讯和提示。'
    --      }
    --    });
    --    break;
    --  case 'zh-tw':
    --    window.polyglot.extend({
    --      'newsletter': {
    --        'title': '獲得 Android 開發人員的最新消息和各項秘訣,讓您在 Google Play 上輕鬆邁向成功之路。',
    --        'requiredHint': '* 必要欄位',
    --        'name': '全名',
    --        'email': '電子郵件地址',
    --        'company': '公司/開發人員名稱',
    --        'appUrl': '您其中一個 Play 商店應用程式的網址',
    --        'business': {
    --          'label': '為您的商家選取最合適的產品類別。',
    --          'apps': '應用程式',
    --          'games': '遊戲',
    --          'both': '應用程式和遊戲'
    --        },
    --        'confirmMailingList': '我想加入 Google Play 的郵寄清單,以便接收每月電子報和 Google Play 不定期寄送的電子郵件,' +
    --          '瞭解關於開發和 Google Play 商機的資訊。',
    --        'privacyPolicy': '我瞭解,我在這張表單中提供的資訊將受到 <a href="' +
    --        'https://www.google.com/intl/zh-TW/policies/privacy/" target="_blank">Google</a> 隱私權政策.',
    --        'languageVal': 'Traditional Chinese (繁體中文)',
    --        'successTitle': '太棒了!',
    --        'successDetails': '您已經成功訂閱 Android 開發人員的最新消息和各項秘訣。'
    --      }
    --    });
    --    break;
    --  case 'fr':
    --    window.polyglot.extend({
    --      'newsletter': {
    --        'title': 'Recevez les dernières actualités destinées aux développeurs Android, ainsi que des conseils qui ' +
    --          'vous mèneront vers le succès sur Google Play.',
    --        'requiredHint': '* Champs obligatoires',
    --        'name': 'Nom complet',
    --        'email': 'Adresse e-mail',
    --        'company': 'Nom de la société ou du développeur',
    --        'appUrl': 'Une de vos URL Play Store',
    --        'business': {
    --          'label': 'Quelle option décrit le mieux votre activité ?',
    --          'apps': 'Applications',
    --          'games': 'Jeux',
    --          'both': 'Applications et jeux'
    --        },
    --        'confirmMailingList': 'Ajoutez-moi à la liste de diffusion de la newsletter mensuelle et tenez-moi informé ' +
    --          'par des e-mails occasionnels de l\'évolution et des opportunités de Google Play.',
    --        'privacyPolicy': 'Je comprends que les renseignements fournis dans ce formulaire seront soumis aux <a href="' +
    --        'https://www.google.com/intl/fr/policies/privacy/" target="_blank">règles de confidentialité</a> de Google.',
    --        'languageVal': 'French (français)',
    --        'successTitle': 'Super !',
    --        'successDetails': 'Vous êtes bien inscrit pour recevoir les actualités et les conseils destinés aux ' +
    --          'développeurs Android.'
    --      }
    --    });
    --    break;
    --  case 'de':
    --    window.polyglot.extend({
    --      'newsletter': {
    --        'title': 'Abonniere aktuelle Informationen und Tipps für Android-Entwickler und werde noch erfolgreicher ' +
    --          'bei Google Play.',
    --        'requiredHint': '* Pflichtfelder',
    --        'name': 'Vollständiger Name',
    --        'email': 'E-Mail-Adresse',
    --        'company': 'Unternehmens-/Entwicklername',
    --        'appUrl': 'Eine der URLs deiner Play Store App',
    --        'business': {
    --          'label': 'Welche der folgenden Kategorien beschreibt dein Unternehmen am besten?',
    --          'apps': 'Apps',
    --          'games': 'Spiele',
    --          'both': 'Apps und Spiele'
    --        },
    --        'confirmMailingList': 'Meine E-Mail-Adresse soll zur Mailingliste hinzugefügt werden, damit ich den ' +
    --          'monatlichen Newsletter sowie gelegentlich E-Mails zu Entwicklungen und Optionen bei Google Play erhalte.',
    --        'privacyPolicy': 'Ich bestätige, dass die in diesem Formular bereitgestellten Informationen gemäß der ' +
    --          '<a href="https://www.google.com/intl/de/policies/privacy/" target="_blank">Datenschutzerklärung</a> von ' +
    --          'Google verwendet werden dürfen.',
    --        'languageVal': 'German (Deutsch)',
    --        'successTitle': 'Super!',
    --        'successDetails': 'Du hast dich erfolgreich angemeldet und erhältst jetzt aktuelle Informationen und Tipps ' +
    --          'für Android-Entwickler.'
    --      }
    --    });
    --    break;
    --  case 'in':
    --    window.polyglot.extend({
    --      'newsletter': {
    --        'title': 'Receba as dicas e as notícias mais recentes para os desenvolvedores Android e seja bem-sucedido ' +
    --        'no Google Play.',
    --        'requiredHint': '* Bidang Wajib Diisi',
    --        'name': 'Nama lengkap',
    --        'email': 'Alamat email',
    --        'company': 'Nama pengembang / perusahaan',
    --        'appUrl': 'Salah satu URL aplikasi Play Store Anda',
    --        'business': {
    --          'label': 'Dari berikut ini, mana yang paling cocok dengan bisnis Anda?',
    --          'apps': 'Aplikasi',
    --          'games': 'Game',
    --          'both': 'Aplikasi dan Game'
    --        },
    --        'confirmMailingList': 'Tambahkan saya ke milis untuk mendapatkan buletin bulanan dan email sesekali mengenai ' +
    --          'perkembangan dan kesempatan yang ada di Google Play.',
    --        'privacyPolicy': 'Saya memahami bahwa informasi yang diberikan dalam formulir ini tunduk pada <a href="' +
    --        'https://www.google.com/intl/in/policies/privacy/" target="_blank">kebijakan privasi</a> Google.',
    --        'languageVal': 'Indonesian (Bahasa)',
    --        'successTitle': 'Hore!',
    --        'successDetails': 'Anda berhasil mendaftar untuk kiat dan berita pengembang Android terbaru.'
    --      }
    --    });
    --    break;
    --  case 'it':
    --    //window.polyglot.extend({
    --    //  'newsletter': {
    --    //    'title': 'Receba as dicas e as notícias mais recentes para os desenvolvedores Android e seja bem-sucedido ' +
    --    //    'no Google Play.',
    --    //    'requiredHint': '* Campos obrigatórios',
    --    //    'name': 'Nome completo',
    --    //    'email': 'Endereço de Email',
    --    //    'company': 'Nome da empresa / do desenvolvedor',
    --    //    'appUrl': 'URL de um dos seus apps da Play Store',
    --    //    'business': {
    --    //      'label': 'Qual das seguintes opções melhor descreve sua empresa?',
    --    //      'apps': 'Apps',
    --    //      'games': 'Jogos',
    --    //      'both': 'Apps e Jogos'
    --    //    },
    --    //    'confirmMailingList': 'Inscreva-me na lista de e-mails para que eu receba o boletim informativo mensal, ' +
    --    //    'bem como e-mails ocasionais sobre o desenvolvimento e as oportunidades do Google Play.',
    --    //    'privacyPolicy': 'Reconheço que as informações fornecidas neste formulário estão sujeitas à <a href="' +
    --    //    'https://www.google.com.br/policies/privacy/" target="_blank">Política de Privacidade</a> do Google.',
    --    //    'languageVal': 'Italian (italiano)',
    --    //    'successTitle': 'Uhu!',
    --    //    'successDetails': 'Você se inscreveu para receber as notícias e as dicas mais recentes para os ' +
    --    //    'desenvolvedores Android.',
    --    //  }
    --    //});
    --    break;
    --  case 'ja':
    --    window.polyglot.extend({
    --      'newsletter': {
    --        'title': 'Google Play での成功に役立つ Android デベロッパー向けの最新ニュースやおすすめの情報をお届けします。',
    --        'requiredHint': '* 必須',
    --        'name': '氏名',
    --        'email': 'メールアドレス',
    --        'company': '会社名 / デベロッパー名',
    --        'appUrl': 'Play ストア アプリの URL(いずれか 1 つ)',
    --        'business': {
    --          'label': 'お客様のビジネスに最もよく当てはまるものをお選びください。',
    --          'apps': 'アプリ',
    --          'games': 'ゲーム',
    --          'both': 'アプリとゲーム'
    --        },
    --        'confirmMailingList': '開発や Google Play の最新情報に関する毎月発行のニュースレターや不定期発行のメールを受け取る',
    --        'privacyPolicy': 'このフォームに入力した情報に <a href="https://www.google.com/intl/ja/policies/privacy/" ' +
    --          'target="_blank">Google</a> のプライバシー ポリシーが適用',
    --        'languageVal': 'Japanese (日本語)',
    --        'successTitle': '完了です!',
    --        'successDetails': 'Android デベロッパー向けの最新ニュースやおすすめの情報の配信登録が完了しました。'
    --      }
    --    });
    --    break;
    --  case 'ko':
    --    window.polyglot.extend({
    --      'newsletter': {
    --        'title': 'Google Play에서 성공을 거두는 데 도움이 되는 최신 Android 개발자 소식 및 도움말을 받아 보세요.',
    --        'requiredHint': '* 필수 입력란',
    --        'name': '이름',
    --        'email': '이메일 주소',
    --        'company': '회사/개발자 이름',
    --        'appUrl': 'Play 스토어 앱 URL 중 1개',
    --        'business': {
    --          'label': '다음 중 내 비즈니스를 가장 잘 설명하는 단어는 무엇인가요?',
    --          'apps': '앱',
    --          'games': '게임',
    --          'both': '앱 및 게임'
    --        },
    --        'confirmMailingList': '개발 및 Google Play 관련 소식에 관한 월별 뉴스레터 및 비정기 이메일을 받아보겠습니다.',
    --        'privacyPolicy': '이 양식에 제공한 정보는 <a href="https://www.google.com/intl/ko/policies/privacy/" ' +
    --          'target="_blank">Google의</a> 개인정보취급방침에 따라 사용됨을',
    --        'languageVal':'Korean (한국어)',
    --        'successTitle': '축하합니다!',
    --        'successDetails': '최신 Android 개발자 뉴스 및 도움말을 받아볼 수 있도록 가입을 완료했습니다.'
    --      }
    --    });
    --    break;
    --  case 'pt-br':
    --    window.polyglot.extend({
    --      'newsletter': {
    --        'title': 'Receba as dicas e as notícias mais recentes para os desenvolvedores Android e seja bem-sucedido ' +
    --        'no Google Play.',
    --        'requiredHint': '* Campos obrigatórios',
    --        'name': 'Nome completo',
    --        'email': 'Endereço de Email',
    --        'company': 'Nome da empresa / do desenvolvedor',
    --        'appUrl': 'URL de um dos seus apps da Play Store',
    --        'business': {
    --          'label': 'Qual das seguintes opções melhor descreve sua empresa?',
    --          'apps': 'Apps',
    --          'games': 'Jogos',
    --          'both': 'Apps e Jogos'
    --        },
    --        'confirmMailingList': 'Inscreva-me na lista de e-mails para que eu receba o boletim informativo mensal, ' +
    --        'bem como e-mails ocasionais sobre o desenvolvimento e as oportunidades do Google Play.',
    --        'privacyPolicy': 'Reconheço que as informações fornecidas neste formulário estão sujeitas à <a href="' +
    --        'https://www.google.com.br/policies/privacy/" target="_blank">Política de Privacidade</a> do Google.',
    --        'languageVal': 'Brazilian Portuguese (Português Brasileiro)',
    --        'successTitle': 'Uhu!',
    --        'successDetails': 'Você se inscreveu para receber as notícias e as dicas mais recentes para os ' +
    --        'desenvolvedores Android.'
    --      }
    --    });
    --    break;
    --  case 'ru':
    --    window.polyglot.extend({
    --      'newsletter': {
    --        'title': 'Хотите получать последние новости и советы для разработчиков Google Play? Заполните эту форму.',
    --        'requiredHint': '* Обязательные поля',
    --        'name': 'Полное имя',
    --        'email': 'Адрес электронной почты',
    --        'company': 'Название компании или имя разработчика',
    --        'appUrl': 'Ссылка на любое ваше приложение в Google Play',
    --        'business': {
    --          'label': 'Что вы создаете?',
    --          'apps': 'Приложения',
    --          'games': 'Игры',
    --          'both': 'Игры и приложения'
    --        },
    --        'confirmMailingList': 'Я хочу получать ежемесячную рассылку для разработчиков и другие полезные новости ' +
    --          'Google Play.',
    --        'privacyPolicy': 'Я предоставляю эти данные в соответствии с <a href="' +
    --          'https://www.google.com/intl/ru/policies/privacy/" target="_blank">Политикой конфиденциальности</a> Google.',
    --        'languageVal': 'Russian (Русский)',
    --        'successTitle': 'Поздравляем!',
    --        'successDetails': 'Теперь вы подписаны на последние новости и советы для разработчиков Android.'
    --      }
    --    });
    --    break;
    --  case 'es':
    --    window.polyglot.extend({
    --      'newsletter': {
    --        'title': 'Recibe las últimas noticias y sugerencias para programadores de Android y logra tener éxito en ' +
    --          'Google Play.',
    --        'requiredHint': '* Campos obligatorios',
    --        'name': 'Dirección de correo electrónico',
    --        'email': 'Endereço de Email',
    --        'company': 'Nombre de la empresa o del programador',
    --        'appUrl': 'URL de una de tus aplicaciones de Play Store',
    --        'business': {
    --          'label': '¿Qué describe mejor a tu empresa?',
    --          'apps': 'Aplicaciones',
    --          'games': 'Juegos',
    --          'both': 'Juegos y aplicaciones'
    --        },
    --        'confirmMailingList': 'Deseo unirme a la lista de distribución para recibir el boletín informativo mensual ' +
    --          'y correos electrónicos ocasionales sobre desarrollo y oportunidades de Google Play.',
    --        'privacyPolicy': 'Acepto que la información que proporcioné en este formulario cumple con la <a href="' +
    --        'https://www.google.com/intl/es/policies/privacy/" target="_blank">política de privacidad</a> de Google.',
    --        'languageVal': 'Spanish (español)',
    --        'successTitle': '¡Felicitaciones!',
    --        'successDetails': 'El registro para recibir las últimas noticias y sugerencias para programadores de Android ' +
    --          'se realizó correctamente.'
    --      }
    --    });
    --    break;
    --  case 'th':
    --    window.polyglot.extend({
    --      'newsletter': {
    --        'title': 'รับข่าวสารล่าสุดสำหรับนักพัฒนาซอฟต์แวร์ Android ตลอดจนเคล็ดลับที่จะช่วยให้คุณประสบความสำเร็จบน ' +
    --          'Google Play',
    --        'requiredHint': '* ช่องที่ต้องกรอก',
    --        'name': 'ชื่อและนามสกุล',
    --        'email': 'ที่อยู่อีเมล',
    --        'company': 'ชื่อบริษัท/นักพัฒนาซอฟต์แวร์',
    --        'appUrl': 'URL แอปใดแอปหนึ่งของคุณใน Play สโตร์',
    --        'business': {
    --          'label': 'ข้อใดตรงกับธุรกิจของคุณมากที่สุด',
    --          'apps': 'แอป',
    --          'games': 'เกม',
    --          'both': 'แอปและเกม'
    --        },
    --        'confirmMailingList': 'เพิ่มฉันลงในรายชื่ออีเมลเพื่อรับจดหมายข่าวรายเดือนและอีเมลเป็นครั้งคราวเกี่ยวกับก' +
    --          'ารพัฒนาซอฟต์แวร์และโอกาสใน Google Play',
    --        'privacyPolicy': 'ฉันรับทราบว่าข้อมูลที่ให้ไว้ในแบบฟอร์มนี้จะเป็นไปตามนโยบายส่วนบุคคลของ ' +
    --          '<a href="https://www.google.com/intl/th/policies/privacy/" target="_blank">Google</a>',
    --        'languageVal': 'Thai (ภาษาไทย)',
    --        'successTitle': 'ไชโย!',
    --        'successDetails': 'คุณลงชื่อสมัครรับข่าวสารและเคล็ดลับล่าสุดสำหรับนักพัฒนาซอฟต์แวร์ Android เสร็จเรียบร้อยแล้ว'
    --      }
    --    });
    --    break;
    --  case 'tr':
    --    window.polyglot.extend({
    --      'newsletter': {
    --        'title': 'Google Play\'de başarılı olmanıza yardımcı olacak en son Android geliştirici haberleri ve ipuçları.',
    --        'requiredHint': '* Zorunlu Alanlar',
    --        'name': 'Tam ad',
    --        'email': 'E-posta adresi',
    --        'company': 'Şirket / geliştirici adı',
    --        'appUrl': 'Play Store uygulama URL\'lerinizden biri',
    --        'business': {
    --          'label': 'İşletmenizi en iyi hangisi tanımlar?',
    --          'apps': 'Uygulamalar',
    --          'games': 'Oyunlar',
    --          'both': 'Uygulamalar ve Oyunlar'
    --        },
    --        'confirmMailingList': 'Beni, geliştirme ve Google Play fırsatlarıyla ilgili ara sıra gönderilen e-posta ' +
    --          'iletilerine ilişkin posta listesine ve aylık haber bültenine ekle.',
    --        'privacyPolicy': 'Bu formda sağlanan bilgilerin Google\'ın ' +
    --          '<a href="https://www.google.com/intl/tr/policies/privacy/" target="_blank">Gizlilik Politikası\'na</a> ' +
    --          'tabi olacağını kabul ediyorum.',
    --        'languageVal': 'Turkish (Türkçe)',
    --        'successTitle': 'Yaşasın!',
    --        'successDetails': 'En son Android geliştirici haberleri ve ipuçlarına başarıyla kaydoldunuz.'
    --      }
    --    });
    --    break;
    --  case 'vi':
    --    window.polyglot.extend({
    --      'newsletter': {
    --        'title': 'Nhận tin tức và mẹo mới nhất dành cho nhà phát triển Android sẽ giúp bạn tìm thấy thành công trên ' +
    --          'Google Play.',
    --        'requiredHint': '* Các trường bắt buộc',
    --        'name': 'Tên đầy đủ',
    --        'email': 'Địa chỉ email',
    --        'company': 'Tên công ty/nhà phát triển',
    --        'appUrl': 'Một trong số các URL ứng dụng trên cửa hàng Play của bạn',
    --        'business': {
    --          'label': 'Lựa chọn nào sau đây mô tả chính xác nhất doanh nghiệp của bạn?',
    --          'apps': 'Ứng dụng',
    --          'games': 'Trò chơi',
    --          'both': 'Ứng dụng và trò chơi'
    --        },
    --        'confirmMailingList': 'Thêm tôi vào danh sách gửi thư cho bản tin hàng tháng và email định kỳ về việc phát ' +
    --          'triển và cơ hội của Google Play.',
    --        'privacyPolicy': 'Tôi xác nhận rằng thông tin được cung cấp trong biểu mẫu này tuân thủ chính sách bảo mật ' +
    --          'của <a href="https://www.google.com/intl/vi/policies/privacy/" target="_blank">Google</a>.',
    --        'languageVal': 'Vietnamese (tiếng Việt)',
    --        'successTitle': 'Thật tuyệt!',
    --        'successDetails': 'Bạn đã đăng ký thành công nhận tin tức và mẹo mới nhất dành cho nhà phát triển của Android.'
    --      }
    --    });
    --    break;
    --}
    --
    --(function($) {
    --  'use strict';
    --
    --  function Modal(el, options) {
    --    this.el = $(el);
    --    this.options = $.extend({}, options);
    --    this.isOpen = false;
    --
    --    this.el.on('click', function(event) {
    --      if (!$.contains(this.el.find('.dac-modal-window')[0], event.target)) {
    --        return this.el.trigger('modal-close');
    --      }
    --    }.bind(this));
    --
    --    this.el.on('modal-open', this.open_.bind(this));
    --    this.el.on('modal-close', this.close_.bind(this));
    --    this.el.on('modal-toggle', this.toggle_.bind(this));
    --  }
    --
    --  Modal.prototype.toggle_ = function() {
    --    this.el.trigger('modal-' + (this.isOpen ? 'close' : 'open'));
    --  };
    --
    --  Modal.prototype.close_ = function() {
    --    // When closing the modal for Android Studio downloads, reload the page
    --    // because otherwise we might get stuck with post-download dialog state
    --    if ($("[data-modal='studio_tos'].dac-active").length) {
    --      location.reload();
    --    }
    --    this.el.removeClass('dac-active');
    --    $('body').removeClass('dac-modal-open');
    --    this.isOpen = false;
    --  };
    --
    --  Modal.prototype.open_ = function() {
    --    this.el.addClass('dac-active');
    --    $('body').addClass('dac-modal-open');
    --    this.isOpen = true;
    --  };
    --
    --  function onClickToggleModal(event) {
    --    event.preventDefault();
    --    var toggle = $(event.currentTarget);
    --    var options = toggle.data();
    --    var modal = options.modalToggle ? $('[data-modal="' + options.modalToggle + '"]') :
    --      toggle.closest('[data-modal]');
    --    modal.trigger('modal-toggle');
    --  }
    --
    --  /**
    --   * jQuery plugin
    --   * @param  {object} options - Override default options.
    --   */
    --  $.fn.dacModal = function(options) {
    --    return this.each(function() {
    --      new Modal(this, options);
    --    });
    --  };
    --
    --  $.fn.dacToggleModal = function(options) {
    --    return this.each(function() {
    --      new ToggleModal(this, options);
    --    });
    --  };
    --
    --  /**
    --   * Data Attribute API
    --   */
    --  $(document).on('ready.aranja', function() {
    --    $('[data-modal]').each(function() {
    --      $(this).dacModal($(this).data());
    --    });
    --
    --    $('html').on('click.modal', '[data-modal-toggle]', onClickToggleModal);
    --
    --    // Check if url anchor is targetting a toggle to open the modal.
    --    if (location.hash) {
    --      var $elem = $(document.getElementById(location.hash.substr(1)));
    --      if ($elem.attr('data-modal-toggle')) {
    --        $elem.trigger('click');
    --      }
    --    }
    --
    --    var isTargetLangValid = false;
    --    $(ANDROID_LANGUAGES).each(function(index, langCode) {
    --      if (langCode == window.getLangTarget()) {
    --        isTargetLangValid = true;
    --        return;
    --      }
    --    });
    --    if (window.getLangTarget() !== window.getLangPref() && isTargetLangValid) {
    --        $('#langform').trigger('modal-open');
    --        $("#langform button.yes").attr("onclick","window.changeLangPref('" + window.getLangTarget() + "', true);  return false;");
    --        $("#langform button.no").attr("onclick","window.changeLangPref('" + window.getLangPref() + "', true); return false;");
    --    }
    --
    --    /* Check the current API level, but only if we're in the reference */
    --    if (location.pathname.indexOf('/reference') == 0) {
    --      // init available apis based on user pref
    --      changeApiLevel();
    --    }
    --  });
    --})(jQuery);
    --
    --/* Fullscreen - Toggle fullscreen mode for reference pages */
    --(function($) {
    --  'use strict';
    --
    --  /**
    --   * @param {HTMLElement} el - The DOM element.
    --   * @constructor
    --   */
    --  function Fullscreen(el) {
    --    this.el = $(el);
    --    this.html = $('html');
    --    this.icon = this.el.find('.dac-sprite');
    --    this.isFullscreen = window.readCookie(Fullscreen.COOKIE_) === 'true';
    --    this.activate_();
    --    this.el.on('click.dac-fullscreen', this.toggleHandler_.bind(this));
    --  }
    --
    --  /**
    --   * Cookie name for storing the state
    --   * @type {string}
    --   * @private
    --   */
    --  Fullscreen.COOKIE_ = 'fullscreen';
    --
    --  /**
    --   * Classes to modify the DOM
    --   * @type {{mode: string, fullscreen: string, fullscreenExit: string}}
    --   * @private
    --   */
    --  Fullscreen.CLASSES_ = {
    --    mode: 'dac-fullscreen-mode',
    --    fullscreen: 'dac-fullscreen',
    --    fullscreenExit: 'dac-fullscreen-exit'
    --  };
    --
    --  /**
    --   * Event listener for toggling fullscreen mode
    --   * @param {MouseEvent} event
    --   * @private
    --   */
    --  Fullscreen.prototype.toggleHandler_ = function(event) {
    --    event.stopPropagation();
    --    this.toggle(!this.isFullscreen, true);
    --  };
    --
    --  /**
    --   * Change the DOM based on current state.
    --   * @private
    --   */
    --  Fullscreen.prototype.activate_ = function() {
    --    this.icon.toggleClass(Fullscreen.CLASSES_.fullscreen, !this.isFullscreen);
    --    this.icon.toggleClass(Fullscreen.CLASSES_.fullscreenExit, this.isFullscreen);
    --    this.html.toggleClass(Fullscreen.CLASSES_.mode, this.isFullscreen);
    --  };
    --
    --  /**
    --   * Toggle fullscreen mode and store the state in a cookie.
    --   */
    --  Fullscreen.prototype.toggle = function() {
    --    this.isFullscreen = !this.isFullscreen;
    --    window.writeCookie(Fullscreen.COOKIE_, this.isFullscreen, null);
    --    this.activate_();
    --  };
    --
    --  /**
    --   * jQuery plugin
    --   */
    --  $.fn.dacFullscreen = function() {
    --    return this.each(function() {
    --      new Fullscreen($(this));
    --    });
    --  };
    --})(jQuery);
    --
    --(function($) {
    --  'use strict';
    --
    --  /**
    --   * @param {HTMLElement} selected - The link that is selected in the nav.
    --   * @constructor
    --   */
    --  function HeaderTabs(selected) {
    --
    --    // Don't highlight any tabs on the index page
    --    if (location.pathname === '/index.html' || location.pathname === '/') {
    --      //return;
    --    }
    --
    --    this.selected = $(selected);
    --    this.selectedParent = this.selected.closest('.dac-nav-secondary').siblings('a');
    --    this.links = $('.dac-header-tabs a');
    --
    --    this.selectActiveTab();
    --  }
    --
    --  HeaderTabs.prototype.selectActiveTab = function() {
    --    var section = null;
    --
    --    if (this.selectedParent.length) {
    --      section = this.selectedParent.text();
    --    } else {
    --      section = this.selected.text();
    --    }
    --
    --    if (section) {
    --      this.links.removeClass('selected');
    --
    --      this.links.filter(function() {
    --        return $(this).text() === $.trim(section);
    --      }).addClass('selected');
    --    }
    --  };
    --
    --  /**
    --   * jQuery plugin
    --   */
    --  $.fn.dacHeaderTabs = function() {
    --    return this.each(function() {
    --      new HeaderTabs(this);
    --    });
    --  };
    --})(jQuery);
    --
    --(function($) {
    --  'use strict';
    --  var icon = $('<i/>').addClass('dac-sprite dac-nav-forward');
    --  var config = JSON.parse(window.localStorage.getItem('global-navigation') || '{}');
    --  var forwardLink = $('<span/>')
    --    .addClass('dac-nav-link-forward')
    --    .html(icon)
    --    .attr('tabindex', 0)
    --    .on('click keypress', function(e) {
    --      if (e.type == 'keypress' && e.which == 13 || e.type == 'click') {
    --        swap_(e);
    --      }
    --    });
    --
    --  /**
    --   * @constructor
    --   */
    --  function Nav(navigation) {
    --    $('.dac-nav-list').dacCurrentPage().dacHeaderTabs().dacSidebarToggle($('body'));
    --
    --    navigation.find('[data-reference-tree]').dacReferenceNav();
    --
    --    setupViews_(navigation.children().eq(0).children());
    --
    --    initCollapsedNavs(navigation.find('.dac-nav-sub-slider'));
    --
    --    $('#dac-main-navigation').scrollIntoView('.selected')
    --  }
    --
    --  function updateStore(icon) {
    --    var navClass = getCurrentLandingPage_(icon);
    --    var isExpanded = icon.hasClass('dac-expand-less-black');
    --    var expandedNavs = config.expanded || [];
    --    if (isExpanded) {
    --      expandedNavs.push(navClass);
    --    } else {
    --      expandedNavs = expandedNavs.filter(function(item) {
    --        return item !== navClass;
    --      });
    --    }
    --    config.expanded = expandedNavs;
    --    window.localStorage.setItem('global-navigation', JSON.stringify(config));
    --  }
    --
    --  function toggleSubNav_(icon) {
    --    var isExpanded = icon.hasClass('dac-expand-less-black');
    --    icon.toggleClass('dac-expand-less-black', !isExpanded);
    --    icon.toggleClass('dac-expand-more-black', isExpanded);
    --    icon.data('sub-navigation.dac').slideToggle(200);
    --
    --    updateStore(icon);
    --  }
    --
    --  function handleSubNavToggle_(event) {
    --    event.preventDefault();
    --    var icon = $(event.target);
    --    toggleSubNav_(icon);
    --  }
    --
    --  function getCurrentLandingPage_(icon) {
    --    return icon.closest('li')[0].className.replace('dac-nav-item ', '');
    --  }
    --
    --  // Setup sub navigation collapse/expand
    --  function initCollapsedNavs(toggleIcons) {
    --    toggleIcons.each(setInitiallyActive_($('body')));
    --    toggleIcons.on('click keypress', function(e) {
    --      if (e.type == 'keypress' && e.which == 13 || e.type == 'click') {
    --        handleSubNavToggle_(e);
    --      }
    --    });
    --  }
    --
    --  function setInitiallyActive_(body) {
    --    var expandedNavs = config.expanded || [];
    --    return function(i, icon) {
    --      icon = $(icon);
    --      var subNav = icon.next();
    --
    --      if (!subNav.length) {
    --        return;
    --      }
    --
    --      var landingPageClass = getCurrentLandingPage_(icon);
    --      var expanded = expandedNavs.indexOf(landingPageClass) >= 0;
    --      landingPageClass = landingPageClass === 'home' ? 'about' : landingPageClass;
    --
    --      if (landingPageClass == 'about' && location.pathname == '/index.html') {
    --        expanded = true;
    --      }
    --
    --      // TODO: Should read from localStorage
    --      var visible = body.hasClass(landingPageClass) || expanded;
    --
    --      icon.data('sub-navigation.dac', subNav);
    --      icon.toggleClass('dac-expand-less-black', visible);
    --      icon.toggleClass('dac-expand-more-black', !visible);
    --      subNav.toggle(visible);
    --    };
    --  }
    --
    --  function setupViews_(views) {
    --    if (views.length === 1) {
    --      // Active tier 1 nav.
    --      views.addClass('dac-active');
    --    } else {
    --      // Activate back button and tier 2 nav.
    --      views.slice(0, 2).addClass('dac-active');
    --      var selectedNav = views.eq(2).find('.selected').after(forwardLink);
    --      var langAttr = selectedNav.attr(window.getLangPref() + '-lang');
    --      //form the label from locale attr if possible, else set to selectedNav text value
    --      if ((typeof langAttr !== typeof undefined &&  langAttr !== false) && (langAttr !== '')) {
    --        $('.dac-nav-back-title').text(langAttr);
    --      } else {
    --        $('.dac-nav-back-title').text(selectedNav.text());
    --      }
    --    }
    --
    --    // Navigation should animate.
    --    setTimeout(function() {
    --      views.removeClass('dac-no-anim');
    --    }, 10);
    --  }
    --
    --  function swap_(event) {
    --    event.preventDefault();
    --    $(event.currentTarget).trigger('swap-content');
    --  }
    --
    --  /**
    --   * jQuery plugin
    --   */
    --  $.fn.dacNav = function() {
    --    return this.each(function() {
    --      new Nav($(this));
    --    });
    --  };
    --})(jQuery);
    --
    --/* global NAVTREE_DATA */
    --(function($) {
    --  /**
    --   * Build the reference navigation with namespace dropdowns.
    --   * @param {jQuery} el - The DOM element.
    --   */
    --  function buildReferenceNav(el) {
    --    var supportLibraryPath = '/reference/android/support/';
    --    var currPath = location.pathname;
    --
    --    if (currPath.indexOf(supportLibraryPath) > -1) {
    --      updateSupportLibrariesNav(supportLibraryPath, currPath);
    --    }
    --    var namespaceList = el.find('[data-reference-namespaces]');
    --    var resources = $('[data-reference-resources]').detach();
    --    var selected = namespaceList.find('.selected');
    --    resources.appendTo(el);
    --
    --    // Links should be toggleable.
    --    namespaceList.find('a').addClass('dac-reference-nav-toggle dac-closed');
    --
    --    // Set the path for the navtree data to use.
    --    var navtree_filepath = getNavtreeFilePath(supportLibraryPath, currPath);
    --
    --    // Load in all resources
    --    $.getScript(navtree_filepath, function(data, textStatus, xhr) {
    --      if (xhr.status === 200) {
    --        namespaceList.on(
    --            'click', 'a.dac-reference-nav-toggle', toggleResourcesHandler);
    --      }
    --    });
    --
    --    // No setup required if no resources are present
    --    if (!resources.length) {
    --      return;
    --    }
    --
    --    // The resources should be a part of selected namespace.
    --    var overview = addResourcesToView(resources, selected);
    --
    --    // Currently viewing Overview
    --    if (location.href === overview.attr('href')) {
    --      overview.parent().addClass('selected');
    --    }
    --
    --    // Open currently selected resource
    --    var listsToOpen = selected.children().eq(1);
    --    listsToOpen = listsToOpen.add(
    --        listsToOpen.find('.selected').parent()).show();
    --
    --    // Mark dropdowns as open
    --    listsToOpen.prev().removeClass('dac-closed');
    --
    --    // Scroll into view
    --    namespaceList.scrollIntoView(selected);
    --  }
    --
    --  function getNavtreeFilePath(supportLibraryPath, currPath) {
    --    var navtree_filepath = '';
    --    var navtree_filename = 'navtree_data.js';
    --    if (currPath.indexOf(supportLibraryPath + 'test') > -1) {
    --      navtree_filepath = supportLibraryPath + 'test/' + navtree_filename;
    --    } else if (currPath.indexOf(supportLibraryPath + 'wearable') > -1) {
    --      navtree_filepath = supportLibraryPath + 'wearable/' + navtree_filename;
    --    } else {
    --      navtree_filepath = '/' + navtree_filename;
    --    }
    --    return navtree_filepath;
    --  }
    --
    --  function updateSupportLibrariesNav(supportLibraryPath, currPath) {
    --    var navTitle = '';
    --    if (currPath.indexOf(supportLibraryPath + 'test') > -1) {
    --      navTitle = 'Test Support APIs';
    --    } else if (currPath.indexOf(supportLibraryPath + 'wearable') > -1) {
    --      navTitle = 'Wearable Support APIs';
    --    }
    --    $('#api-nav-title').text(navTitle);
    --    $('#api-level-toggle').hide();
    --  }
    --
    --  /**
    --   * Handles the toggling of resources.
    --   * @param {Event} event
    --   */
    --  function toggleResourcesHandler(event) {
    --    event.preventDefault();
    --    if (event.type == 'click' || event.type == 'keypress' && event.which == 13) {
    --      var el = $(this);
    --      // If resources for given namespace is not present, fetch correct data.
    --      if (this.tagName === 'A' && !this.hasResources) {
    --        addResourcesToView(buildResourcesViewForData(getDataForNamespace(el.text())), el.parent());
    --      }
    --
    --      el.toggleClass('dac-closed').next().slideToggle(200);
    --    }
    --  }
    --
    --  /**
    --   * @param {String} namespace
    --   * @returns {Array} namespace data
    --   */
    --  function getDataForNamespace(namespace) {
    --    var namespaceData = NAVTREE_DATA.filter(function(data) {
    --      return data[0] === namespace;
    --    });
    --
    --    return namespaceData.length ? namespaceData[0][2] : [];
    --  }
    --
    --  /**
    --   * Build a list item for a resource
    --   * @param {Array} resource
    --   * @returns {String}
    --   */
    --  function buildResourceItem(resource) {
    --    return '<li class="api apilevel-' + resource[3] + '"><a href="/' + resource[1] + '">' + resource[0] + '</a></li>';
    --  }
    --
    --  /**
    --   * Build resources list items.
    --   * @param {Array} resources
    --   * @returns {String}
    --   */
    --  function buildResourceList(resources) {
    --    return '<li><h2>' + resources[0] + '</h2><ul>' + resources[2].map(buildResourceItem).join('') + '</ul>';
    --  }
    --
    --  /**
    --   * Build a resources view
    --   * @param {Array} data
    --   * @returns {jQuery} resources in an unordered list.
    --   */
    --  function buildResourcesViewForData(data) {
    --    return $('<ul>' + data.map(buildResourceList).join('') + '</ul>');
    --  }
    --
    --  /**
    --   * Add resources to a containing view.
    --   * @param {jQuery} resources
    --   * @param {jQuery} view
    --   * @returns {jQuery} the overview link.
    --   */
    --  function addResourcesToView(resources, view) {
    --    var namespace = view.children().eq(0);
    --    var overview = $('<a href="' + namespace.attr('href') + '">Overview</a>');
    --
    --    // Mark namespace with content;
    --    namespace[0].hasResources = true;
    --
    --    // Add correct classes / event listeners to resources.
    --    resources.prepend($('<li>').html(overview))
    --      .find('a')
    --        .addClass('dac-reference-nav-resource')
    --      .end()
    --        .find('h2').attr('tabindex', 0)
    --        .addClass('dac-reference-nav-toggle dac-closed')
    --        .on('click keypress', toggleResourcesHandler)
    --      .end()
    --        .add(resources.find('ul'))
    --        .addClass('dac-reference-nav-resources')
    --      .end()
    --        .appendTo(view);
    --
    --    return overview;
    --  }
    --
    --  function setActiveReferencePackage(el) {
    --    var packageLinkEls = el.find('[data-reference-namespaces] a');
    --    var selected = null;
    --    var highestMatchCount = 0;
    --    packageLinkEls.each(function(index, linkEl) {
    --      var matchCount = 0;
    --      $(location.pathname.split('/')).each(function(index, subpath) {
    --        if (linkEl.href.indexOf('/' + subpath + '/') > -1) {
    --          matchCount++;
    --        }
    --      });
    --      if (matchCount > highestMatchCount) {
    --        selected = linkEl;
    --        highestMatchCount = matchCount;
    --      }
    --    });
    --    $(selected).parent().addClass('selected');
    --  }
    --
    --  /**
    --   * jQuery plugin
    --   */
    --  $.fn.dacReferenceNav = function() {
    --    return this.each(function() {
    --      setActiveReferencePackage($(this));
    --      buildReferenceNav($(this));
    --    });
    --  };
    --})(jQuery);
    --
    --/** Scroll a container to make a target element visible
    -- This is called when the page finished loading. */
    --$.fn.scrollIntoView = function(target) {
    --  if ('string' === typeof target) {
    --    target = this.find(target);
    --  }
    --  if (this.is(':visible')) {
    --    if (target.length == 0) {
    --      // If no selected item found, exit
    --      return;
    --    }
    --
    --    // get the target element's offset from its container nav by measuring the element's offset
    --    // relative to the document then subtract the container nav's offset relative to the document
    --    var targetOffset = target.offset().top - this.offset().top;
    --    var containerHeight = this.height();
    --    if (targetOffset > containerHeight * .8) { // multiply nav height by .8 so we move up the item
    --      // if it's more than 80% down the nav
    --      // scroll the item up by an amount equal to 80% the container height
    --      this.scrollTop(targetOffset - (containerHeight * .8));
    --    }
    --  }
    --};
    --
    --(function($) {
    --  $.fn.dacCurrentPage = function() {
    --    // Highlight the header tabs...
    --    // highlight Design tab
    --    var baseurl = getBaseUri(window.location.pathname);
    --    var urlSegments = baseurl.split('/');
    --    var navEl = this;
    --    var body = $('body');
    --    var subNavEl = navEl.find('.dac-nav-secondary');
    --    var parentNavEl;
    --    var selected;
    --    // In NDK docs, highlight appropriate sub-nav
    --    if (body.hasClass('dac-ndk')) {
    --      if (body.hasClass('guide')) {
    --        selected = navEl.find('> li.guides > a').addClass('selected');
    --      } else if (body.hasClass('reference')) {
    --        selected = navEl.find('> li.reference > a').addClass('selected');
    --      } else if (body.hasClass('samples')) {
    --        selected = navEl.find('> li.samples > a').addClass('selected');
    --      } else if (body.hasClass('downloads')) {
    --        selected = navEl.find('> li.downloads > a').addClass('selected');
    --      }
    --    } else if (body.hasClass('dac-studio')) {
    --      if (body.hasClass('download')) {
    --        selected = navEl.find('> li.download > a').addClass('selected');
    --      } else if (body.hasClass('features')) {
    --        selected = navEl.find('> li.features > a').addClass('selected');
    --      } else if (body.hasClass('guide')) {
    --        selected = navEl.find('> li.guide > a').addClass('selected');
    --      } else if (body.hasClass('preview')) {
    --        selected = navEl.find('> li.preview > a').addClass('selected');
    --      }
    --    } else if (body.hasClass('design')) {
    --      selected = navEl.find('> li.design > a').addClass('selected');
    --      // highlight Home nav
    --    } else if (body.hasClass('about') || location.pathname == '/index.html') {
    --      parentNavEl = navEl.find('> li.home > a');
    --      parentNavEl.addClass('has-subnav');
    --      // In Home docs, also highlight appropriate sub-nav
    --      if (urlSegments[1] === 'wear' || urlSegments[1] === 'tv' ||
    --        urlSegments[1] === 'auto') {
    --        selected = subNavEl.find('li.' + urlSegments[1] + ' > a').addClass('selected');
    --      } else if (urlSegments[1] === 'about') {
    --        selected = subNavEl.find('li.versions > a').addClass('selected');
    --      } else {
    --        selected = parentNavEl.removeClass('has-subnav').addClass('selected');
    --      }
    --      // highlight Develop nav
    --    } else if (body.hasClass('develop') || body.hasClass('google')) {
    --      parentNavEl = navEl.find('> li.develop > a');
    --      parentNavEl.addClass('has-subnav');
    --      // In Develop docs, also highlight appropriate sub-nav
    --      if (urlSegments[1] === 'training') {
    --        selected = subNavEl.find('li.training > a').addClass('selected');
    --      } else if (urlSegments[1] === 'guide') {
    --        selected = subNavEl.find('li.guide > a').addClass('selected');
    --      } else if (urlSegments[1] === 'reference') {
    --        // If the root is reference, but page is also part of Google Services, select Google
    --        if (body.hasClass('google')) {
    --          selected = subNavEl.find('li.google > a').addClass('selected');
    --        } else {
    --          selected = subNavEl.find('li.reference > a').addClass('selected');
    --        }
    --      } else if (body.hasClass('google')) {
    --        selected = subNavEl.find('li.google > a').addClass('selected');
    --      } else if (body.hasClass('samples')) {
    --        selected = subNavEl.find('li.samples > a').addClass('selected');
    --      } else {
    --        selected = parentNavEl.removeClass('has-subnav').addClass('selected');
    --      }
    --      // highlight Distribute nav
    --    } else if (body.hasClass('distribute')) {
    --      parentNavEl = navEl.find('> li.distribute > a');
    --      parentNavEl.addClass('has-subnav');
    --      // In Distribute docs, also highlight appropriate sub-nav
    --      if (urlSegments[2] === 'users') {
    --        selected = subNavEl.find('li.users > a').addClass('selected');
    --      } else if (urlSegments[2] === 'engage') {
    --        selected = subNavEl.find('li.engage > a').addClass('selected');
    --      } else if (urlSegments[2] === 'monetize') {
    --        selected = subNavEl.find('li.monetize > a').addClass('selected');
    --      } else if (urlSegments[2] === 'analyze') {
    --        selected = subNavEl.find('li.analyze > a').addClass('selected');
    --      } else if (urlSegments[2] === 'tools') {
    --        selected = subNavEl.find('li.disttools > a').addClass('selected');
    --      } else if (urlSegments[2] === 'stories') {
    --        selected = subNavEl.find('li.stories > a').addClass('selected');
    --      } else if (urlSegments[2] === 'essentials') {
    --        selected = subNavEl.find('li.essentials > a').addClass('selected');
    --      } else if (urlSegments[2] === 'googleplay') {
    --        selected = subNavEl.find('li.googleplay > a').addClass('selected');
    --      } else {
    --        selected = parentNavEl.removeClass('has-subnav').addClass('selected');
    --      }
    --    } else if (body.hasClass('preview')) {
    --      selected = navEl.find('> li.preview > a').addClass('selected');
    --    }
    --    return $(selected);
    --  };
    --})(jQuery);
    --
    --(function($) {
    --  'use strict';
    --
    --  /**
    --   * Toggle the visabilty of the mobile navigation.
    --   * @param {HTMLElement} el - The DOM element.
    --   * @param {Object} options
    --   * @constructor
    --   */
    --  function ToggleNav(el, options) {
    --    this.el = $(el);
    --    this.options = $.extend({}, ToggleNav.DEFAULTS_, options);
    --    this.body = $(document.body);
    --    this.navigation_ = this.body.find(this.options.navigation);
    --    this.el.on('click', this.clickHandler_.bind(this));
    --  }
    --
    --  ToggleNav.BREAKPOINT_ = 980;
    --
    --  /**
    --   * Open on correct sizes
    --   */
    --  function toggleSidebarVisibility(body) {
    --    var wasClosed = ('' + localStorage.getItem('navigation-open')) === 'false';
    --    // Override the local storage setting for navigation-open for child sites
    --    // with no-subnav class.
    --    if (document.body.classList.contains('no-subnav')) {
    --      wasClosed = false;
    --    }
    --
    --    if (wasClosed) {
    --      body.removeClass(ToggleNav.DEFAULTS_.activeClass);
    --    } else if (window.innerWidth >= ToggleNav.BREAKPOINT_) {
    --      body.addClass(ToggleNav.DEFAULTS_.activeClass);
    --    } else {
    --      body.removeClass(ToggleNav.DEFAULTS_.activeClass);
    --    }
    --  }
    --
    --  /**
    --   * ToggleNav Default Settings
    --   * @type {{body: boolean, dimmer: string, navigation: string, activeClass: string}}
    --   * @private
    --   */
    --  ToggleNav.DEFAULTS_ = {
    --    body: true,
    --    dimmer: '.dac-nav-dimmer',
    --    animatingClass: 'dac-nav-animating',
    --    navigation: '[data-dac-nav]',
    --    activeClass: 'dac-nav-open'
    --  };
    --
    --  /**
    --   * The actual toggle logic.
    --   * @param {Event} event
    --   * @private
    --   */
    --  ToggleNav.prototype.clickHandler_ = function(event) {
    --    event.preventDefault();
    --    var animatingClass = this.options.animatingClass;
    --    var body = this.body;
    --
    --    body.addClass(animatingClass);
    --    body.toggleClass(this.options.activeClass);
    --
    --    setTimeout(function() {
    --      body.removeClass(animatingClass);
    --    }, this.navigation_.transitionDuration());
    --
    --    if (window.innerWidth >= ToggleNav.BREAKPOINT_) {
    --      localStorage.setItem('navigation-open', body.hasClass(this.options.activeClass));
    --    }
    --  };
    --
    --  /**
    --   * jQuery plugin
    --   * @param  {object} options - Override default options.
    --   */
    --  $.fn.dacToggleMobileNav = function() {
    --    return this.each(function() {
    --      var el = $(this);
    --      new ToggleNav(el, el.data());
    --    });
    --  };
    --
    --  $.fn.dacSidebarToggle = function(body) {
    --    toggleSidebarVisibility(body);
    --    $(window).on('resize', toggleSidebarVisibility.bind(null, body));
    --  };
    --
    --  /**
    --   * Data Attribute API
    --   */
    --  $(function() {
    --    $('[data-dac-toggle-nav]').dacToggleMobileNav();
    --  });
    --})(jQuery);
    --
    --(function($) {
    --  'use strict';
    --
    --  /**
    --   * Submit the newsletter form to a Google Form.
    --   * @param {HTMLElement} el - The Form DOM element.
    --   * @constructor
    --   */
    --  function NewsletterForm(el) {
    --    this.el = $(el);
    --    this.form = this.el.find('form');
    --    $('<iframe/>').hide()
    --      .attr('name', 'dac-newsletter-iframe')
    --      .attr('src', '')
    --      .insertBefore(this.form);
    --    this.el.find('[data-newsletter-language]').val(window.polyglot.t('newsletter.languageVal'));
    --    this.form.on('submit', this.submitHandler_.bind(this));
    --  }
    --
    --  /**
    --   * Milliseconds until modal has vanished after modal-close is triggered.
    --   * @type {number}
    --   * @private
    --   */
    --  NewsletterForm.CLOSE_DELAY_ = 300;
    --
    --  /**
    --   * Switch view to display form after close.
    --   * @private
    --   */
    --  NewsletterForm.prototype.closeHandler_ = function() {
    --    setTimeout(function() {
    --      this.el.trigger('swap-reset');
    --    }.bind(this), NewsletterForm.CLOSE_DELAY_);
    --  };
    --
    --  /**
    --   * Reset the modal to initial state.
    --   * @private
    --   */
    --  NewsletterForm.prototype.reset_ = function() {
    --    this.form.trigger('reset');
    --    this.el.one('modal-close', this.closeHandler_.bind(this));
    --  };
    --
    --  /**
    --   * Display a success view on submit.
    --   * @private
    --   */
    --  NewsletterForm.prototype.submitHandler_ = function() {
    --    this.el.one('swap-complete', this.reset_.bind(this));
    --    this.el.trigger('swap-content');
    --  };
    --
    --  /**
    --   * jQuery plugin
    --   * @param  {object} options - Override default options.
    --   */
    --  $.fn.dacNewsletterForm = function(options) {
    --    return this.each(function() {
    --      new NewsletterForm(this, options);
    --    });
    --  };
    --
    --  /**
    --   * Data Attribute API
    --   */
    --  $(document).on('ready.aranja', function() {
    --    $('[data-newsletter]').each(function() {
    --      $(this).dacNewsletterForm();
    --    });
    --  });
    --})(jQuery);
    --
    --/* globals METADATA, YOUTUBE_RESOURCES, BLOGGER_RESOURCES */
    --window.metadata = {};
    --
    --/**
    -- * Prepare metadata and indices for querying.
    -- */
    --window.metadata.prepare = (function() {
    --  // Helper functions.
    --  function mergeArrays() {
    --    return Array.prototype.concat.apply([], arguments);
    --  }
    --
    --  /**
    --   * Creates lookup maps for a resource index.
    --   * I.e. where MAP['some tag'][resource.id] === true when that resource has 'some tag'.
    --   * @param resourceDict
    --   * @returns {{}}
    --   */
    --  function buildResourceLookupMap(resourceDict) {
    --    var map = {};
    --    for (var key in resourceDict) {
    --      var dictForKey = {};
    --      var srcArr = resourceDict[key];
    --      for (var i = 0; i < srcArr.length; i++) {
    --        dictForKey[srcArr[i].index] = true;
    --      }
    --      map[key] = dictForKey;
    --    }
    --    return map;
    --  }
    --
    --  /**
    --   * Merges metadata maps for english and the current language into the global store.
    --   */
    --  function mergeMetadataMap(name, locale) {
    --    if (locale && locale !== 'en' && METADATA[locale]) {
    --      METADATA[name] = $.extend(METADATA.en[name], METADATA[locale][name]);
    --    } else {
    --      METADATA[name] = METADATA.en[name];
    --    }
    --  }
    --
    --  /**
    --   * Index all resources by type, url, tag and category.
    --   * @param resources
    --   */
    --  function createIndices(resources) {
    --    // URL, type, tag and category lookups
    --    var byType = METADATA.byType = {};
    --    var byUrl = METADATA.byUrl = {};
    --    var byTag = METADATA.byTag = {};
    --    var byCategory = METADATA.byCategory = {};
    --
    --    for (var i = 0; i < resources.length; i++) {
    --      var res = resources[i];
    --
    --      // Store index.
    --      res.index = i;
    --
    --      // Index by type.
    --      var type = res.type;
    --      if (type) {
    --        byType[type] = byType[type] || [];
    --        byType[type].push(res);
    --      }
    --
    --      // Index by tag.
    --      var tags = res.tags || [];
    --      for (var j = 0; j < tags.length; j++) {
    --        var tag = tags[j];
    --        if (tag) {
    --          byTag[tag] = byTag[tag] || [];
    --          byTag[tag].push(res);
    --        }
    --      }
    --
    --      // Index by category.
    --      var category = res.category;
    --      if (category) {
    --        byCategory[category] = byCategory[category] || [];
    --        byCategory[category].push(res);
    --      }
    --
    --      // Index by url.
    --      var url = res.url;
    --      if (url) {
    --        res.baseUrl = url.replace(/^intl\/\w+[\/]/, '');
    --        byUrl[res.baseUrl] = res;
    --      }
    --    }
    --    METADATA.hasType = buildResourceLookupMap(byType);
    --    METADATA.hasTag = buildResourceLookupMap(byTag);
    --    METADATA.hasCategory = buildResourceLookupMap(byCategory);
    --  }
    --
    --  return function() {
    --    // Only once.
    --    if (METADATA.all) { return; }
    --
    --    // Get current language.
    --    var locale = getLangPref();
    --    // Merge english resources.
    --    if (useDevsiteMetadata) {
    --      var all_keys = Object.keys(METADATA['en']);
    --      METADATA.all = []
    --
    --      $(all_keys).each(function(index, category) {
    --        if (RESERVED_METADATA_CATEGORY_NAMES.indexOf(category) == -1) {
    --          METADATA.all = mergeArrays(
    --            METADATA.all,
    --            METADATA.en[category]
    --          );
    --        }
    --      });
    --
    --      METADATA.all = mergeArrays(
    --        METADATA.all,
    --        YOUTUBE_RESOURCES,
    --        BLOGGER_RESOURCES,
    --        METADATA.en.extras
    --      );
    --    } else {
    --      METADATA.all = mergeArrays(
    --        METADATA.en.about,
    --        METADATA.en.design,
    --        METADATA.en.distribute,
    --        METADATA.en.develop,
    --        YOUTUBE_RESOURCES,
    --        BLOGGER_RESOURCES,
    --        METADATA.en.extras
    --      );
    --    }
    --
    --    // Merge local language resources.
    --    if (locale !== 'en' && METADATA[locale]) {
    --      if (useDevsiteMetadata) {
    --        all_keys = Object.keys(METADATA[locale]);
    --        $(all_keys).each(function(index, category) {
    --          if (RESERVED_METADATA_CATEGORY_NAMES.indexOf(category) == -1) {
    --            METADATA.all = mergeArrays(
    --              METADATA.all,
    --              METADATA.en[category]
    --            );
    --          }
    --        });
    --
    --        METADATA.all = mergeArrays(
    --          METADATA.all,
    --          METADATA[locale].extras
    --        );
    --      } else {
    --        METADATA.all = mergeArrays(
    --          METADATA.all,
    --          METADATA[locale].about,
    --          METADATA[locale].design,
    --          METADATA[locale].distribute,
    --          METADATA[locale].develop,
    --          METADATA[locale].extras
    --        );
    --
    --      }
    --    }
    --
    --    mergeMetadataMap('collections', locale);
    --    mergeMetadataMap('searchHeroCollections', locale);
    --    mergeMetadataMap('carousel', locale);
    --
    --    // Create query indicies for resources.
    --    createIndices(METADATA.all, locale);
    --
    --    // Reference metadata.
    --    METADATA.androidReference = mergeArrays(
    --        window.DATA, window.SUPPORT_WEARABLE_DATA, window.SUPPORT_TEST_DATA);
    --    METADATA.googleReference = mergeArrays(window.GMS_DATA, window.GCM_DATA);
    --  };
    --})();
    --
    --/* global METADATA, util */
    --window.metadata.query = (function($) {
    --  var pageMap = {};
    --
    --  function buildResourceList(opts) {
    --    window.metadata.prepare();
    --    var expressions = parseResourceQuery(opts.query || '');
    --    var instanceMap = {};
    --    var results = [];
    --
    --    for (var i = 0; i < expressions.length; i++) {
    --      var clauses = expressions[i];
    --
    --      // Get all resources for first clause
    --      var resources = getResourcesForClause(clauses.shift());
    --
    --      // Concat to final results list
    --      results = results.concat(resources.map(filterResources(clauses, i > 0, instanceMap)).filter(filterEmpty));
    --    }
    --
    --    // Set correct order
    --    if (opts.sortOrder && results.length) {
    --      results = opts.sortOrder === 'random' ? util.shuffle(results) : results.sort(sortResultsByKey(opts.sortOrder));
    --    }
    --
    --    // Slice max results.
    --    if (opts.maxResults !== Infinity) {
    --      results = results.slice(0, opts.maxResults);
    --    }
    --
    --    // Remove page level duplicates
    --    if (opts.allowDuplicates === undefined || opts.allowDuplicates === 'false') {
    --      results = results.filter(removePageLevelDuplicates);
    --
    --      for (var index = 0; index < results.length; ++index) {
    --        pageMap[results[index].index] = 1;
    --      }
    --    }
    --
    --    return results;
    --  }
    --
    --  function filterResources(clauses, removeDuplicates, map) {
    --    return function(resource) {
    --      var resourceIsAllowed = true;
    --
    --      // References must be defined.
    --      if (resource === undefined) {
    --        return;
    --      }
    --
    --      // Get canonical (localized) version of resource if possible.
    --      resource = METADATA.byUrl[resource.baseUrl] || METADATA.byUrl[resource.url] || resource;
    --
    --      // Filter out resources already used
    --      if (removeDuplicates) {
    --        resourceIsAllowed = !map[resource.index];
    --      }
    --
    --      // Must fulfill all criteria
    --      if (clauses.length > 0) {
    --        resourceIsAllowed = resourceIsAllowed && doesResourceMatchClauses(resource, clauses);
    --      }
    --
    --      // Mark resource as used.
    --      if (resourceIsAllowed) {
    --        map[resource.index] = 1;
    --      }
    --
    --      return resourceIsAllowed && resource;
    --    };
    --  }
    --
    --  function filterEmpty(resource) {
    --    return resource;
    --  }
    --
    --  function sortResultsByKey(key) {
    --    var desc = key.charAt(0) === '-';
    --
    --    if (desc) {
    --      key = key.substring(1);
    --    }
    --
    --    return function(x, y) {
    --      return (desc ? -1 : 1) * (parseInt(x[key], 10) - parseInt(y[key], 10));
    --    };
    --  }
    --
    --  function getResourcesForClause(clause) {
    --    switch (clause.attr) {
    --      case 'type':
    --        return METADATA.byType[clause.value];
    --      case 'tag':
    --        return METADATA.byTag[clause.value];
    --      case 'collection':
    --        var resources = METADATA.collections[clause.value] || {};
    --        return getResourcesByUrlCollection(resources.resources);
    --      case 'history':
    --        return getResourcesByUrlCollection($.dacGetVisitedUrls(clause.value));
    --      case 'section':
    --        return getResourcesByUrlCollection([clause.value].sections);
    --      default:
    --        return [];
    --    }
    --  }
    --
    --  function getResourcesByUrlCollection(resources) {
    --    return (resources || []).map(function(url) {
    --      return METADATA.byUrl[url];
    --    });
    --  }
    --
    --  function removePageLevelDuplicates(resource) {
    --    return resource && !pageMap[resource.index];
    --  }
    --
    --  function doesResourceMatchClauses(resource, clauses) {
    --    for (var i = 0; i < clauses.length; i++) {
    --      var map;
    --      switch (clauses[i].attr) {
    --        case 'type':
    --          map = METADATA.hasType[clauses[i].value];
    --          break;
    --        case 'tag':
    --          map = METADATA.hasTag[clauses[i].value];
    --          break;
    --      }
    --
    --      if (!map || (!!clauses[i].negative ? map[resource.index] : !map[resource.index])) {
    --        return clauses[i].negative;
    --      }
    --    }
    --
    --    return true;
    --  }
    --
    --  function parseResourceQuery(query) {
    --    // Parse query into array of expressions (expression e.g. 'tag:foo + type:video')
    --    var expressions = [];
    --    var expressionStrs = query.split(',') || [];
    --    for (var i = 0; i < expressionStrs.length; i++) {
    --      var expr = expressionStrs[i] || '';
    --
    --      // Break expression into clauses (clause e.g. 'tag:foo')
    --      var clauses = [];
    --      var clauseStrs = expr.split(/(?=[\+\-])/);
    --      for (var j = 0; j < clauseStrs.length; j++) {
    --        var clauseStr = clauseStrs[j] || '';
    --
    --        // Get attribute and value from clause (e.g. attribute='tag', value='foo')
    --        var parts = clauseStr.split(':');
    --        var clause = {};
    --
    --        clause.attr = parts[0].replace(/^\s+|\s+$/g, '');
    --        if (clause.attr) {
    --          if (clause.attr.charAt(0) === '+') {
    --            clause.attr = clause.attr.substring(1);
    --          } else if (clause.attr.charAt(0) === '-') {
    --            clause.negative = true;
    --            clause.attr = clause.attr.substring(1);
    --          }
    --        }
    --
    --        if (parts.length > 1) {
    --          clause.value = parts[1].replace(/^\s+|\s+$/g, '');
    --        }
    --
    --        clauses.push(clause);
    --      }
    --
    --      if (!clauses.length) {
    --        continue;
    --      }
    --
    --      expressions.push(clauses);
    --    }
    --
    --    return expressions;
    --  }
    --
    --  return buildResourceList;
    --})(jQuery);
    --
    --/* global METADATA, getLangPref */
    --
    --window.metadata.search = (function() {
    --  'use strict';
    --
    --  var currentLang = getLangPref();
    --
    --  function search(query) {
    --    window.metadata.prepare();
    --    return {
    --      android: findDocsMatches(query, METADATA.androidReference),
    --      docs: findDocsMatches(query, METADATA.googleReference),
    --      resources: findResourceMatches(query)
    --    };
    --  }
    --
    --  function findDocsMatches(query, data) {
    --    var results = [];
    --
    --    for (var i = 0; i < data.length; i++) {
    --      var s = data[i];
    --      if (query.length !== 0 && s.label.toLowerCase().indexOf(query.toLowerCase()) !== -1) {
    --        results.push(s);
    --      }
    --    }
    --
    --    rankAutocompleteApiResults(query, results);
    --
    --    return results;
    --  }
    --
    --  function findResourceMatches(query) {
    --    var results = [];
    --
    --    // Search for matching JD docs
    --    if (query.length >= 2) {
    --      /* In some langs, spaces may be optional between certain non-Ascii word-glyphs. For
    --       * those langs, only match query at word boundaries if query includes Ascii chars only.
    --       */
    --      var NO_BOUNDARY_LANGUAGES = ['ja','ko','vi','zh-cn','zh-tw'];
    --      var isAsciiOnly = /^[\u0000-\u007f]*$/.test(query);
    --      var noBoundaries = (NO_BOUNDARY_LANGUAGES.indexOf(window.getLangPref()) !== -1);
    --      var exprBoundary = (!isAsciiOnly && noBoundaries) ? '' : '(?:^|\\s)';
    --      var queryRegex = new RegExp(exprBoundary + query.toLowerCase(), 'g');
    --
    --      var all = METADATA.all;
    --      for (var i = 0; i < all.length; i++) {
    --        // current search comparison, with counters for tag and title,
    --        // used later to improve ranking
    --        var s = all[i];
    --        s.matched_tag = 0;
    --        s.matched_title = 0;
    --        var matched = false;
    --
    --        // Check if query matches any tags; work backwards toward 1 to assist ranking
    --        if (s.keywords) {
    --          for (var j = s.keywords.length - 1; j >= 0; j--) {
    --            // it matches a tag
    --            if (s.keywords[j].toLowerCase().match(queryRegex)) {
    --              matched = true;
    --              s.matched_tag = j + 1; // add 1 to index position
    --            }
    --          }
    --        }
    --
    --        // Check if query matches doc title
    --        if (s.title.toLowerCase().match(queryRegex)) {
    --          matched = true;
    --          s.matched_title = 1;
    --        }
    --
    --        // Remember the doc if it matches either
    --        if (matched) {
    --          results.push(s);
    --        }
    --      }
    --
    --      // Improve the current results
    --      results = lookupBetterResult(results);
    --
    --      // Rank/sort all the matched pages
    --      rankAutocompleteDocResults(results);
    --
    --      return results;
    --    }
    --  }
    --
    --  // Replaces a match with another resource by url, if it exists.
    --  function lookupReplacementByUrl(match, url) {
    --    var replacement = METADATA.byUrl[url];
    --
    --    // Replacement resource does not exists.
    --    if (!replacement) { return; }
    --
    --    replacement.matched_title = Math.max(replacement.matched_title, match.matched_title);
    --    replacement.matched_tag = Math.max(replacement.matched_tag, match.matched_tag);
    --
    --    return replacement;
    --  }
    --
    --  // Find the localized version of a page if it exists.
    --  function lookupLocalizedVersion(match) {
    --    return METADATA.byUrl[match.baseUrl] || METADATA.byUrl[match.url];
    --  }
    --
    --  // Find the main page for a tutorial when matching a subpage.
    --  function lookupTutorialIndex(match) {
    --    // Guard for non index tutorial pages.
    --    if (match.type !== 'training' || match.url.indexOf('index.html') >= 0) { return; }
    --
    --    var indexUrl = match.url.replace(/[^\/]+$/, 'index.html');
    --    return lookupReplacementByUrl(match, indexUrl);
    --  }
    --
    --  // Find related results which are a better match for the user.
    --  function lookupBetterResult(matches) {
    --    var newMatches = [];
    --
    --    matches = matches.filter(function(match) {
    --      var newMatch = match;
    --      newMatch = lookupTutorialIndex(newMatch) || newMatch;
    --      newMatch = lookupLocalizedVersion(newMatch) || newMatch;
    --
    --      if (newMatch !== match) {
    --        newMatches.push(newMatch);
    --      }
    --
    --      return newMatch === match;
    --    });
    --
    --    return toUnique(newMatches.concat(matches));
    --  }
    --
    --  /* Order the jd doc result list based on match quality */
    --  function rankAutocompleteDocResults(matches) {
    --    if (!matches || !matches.length) {
    --      return;
    --    }
    --
    --    var _resultScoreFn = function(match) {
    --      var score = 1.0;
    --
    --      // if the query matched a tag
    --      if (match.matched_tag > 0) {
    --        // multiply score by factor relative to position in tags list (max of 3)
    --        score *= 3 / match.matched_tag;
    --
    --        // if it also matched the title
    --        if (match.matched_title > 0) {
    --          score *= 2;
    --        }
    --      } else if (match.matched_title > 0) {
    --        score *= 3;
    --      }
    --
    --      if (match.lang === currentLang) {
    --        score *= 5;
    --      }
    --
    --      return score;
    --    };
    --
    --    for (var i = 0; i < matches.length; i++) {
    --      matches[i].__resultScore = _resultScoreFn(matches[i]);
    --    }
    --
    --    matches.sort(function(a, b) {
    --      var n = b.__resultScore - a.__resultScore;
    --
    --      if (n === 0) {
    --        // lexicographical sort if scores are the same
    --        n = (a.title < b.title) ? -1 : 1;
    --      }
    --
    --      return n;
    --    });
    --  }
    --
    --  /* Order the result list based on match quality */
    --  function rankAutocompleteApiResults(query, matches) {
    --    query = query || '';
    --    if (!matches || !matches.length) {
    --      return;
    --    }
    --
    --    // helper function that gets the last occurence index of the given regex
    --    // in the given string, or -1 if not found
    --    var _lastSearch = function(s, re) {
    --      if (s === '') {
    --        return -1;
    --      }
    --      var l = -1;
    --      var tmp;
    --      while ((tmp = s.search(re)) >= 0) {
    --        if (l < 0) {
    --          l = 0;
    --        }
    --        l += tmp;
    --        s = s.substr(tmp + 1);
    --      }
    --      return l;
    --    };
    --
    --    // helper function that counts the occurrences of a given character in
    --    // a given string
    --    var _countChar = function(s, c) {
    --      var n = 0;
    --      for (var i = 0; i < s.length; i++) {
    --        if (s.charAt(i) === c) {
    --          ++n;
    --        }
    --      }
    --      return n;
    --    };
    --
    --    var queryLower = query.toLowerCase();
    --    var queryAlnum = (queryLower.match(/\w+/) || [''])[0];
    --    var partPrefixAlnumRE = new RegExp('\\b' + queryAlnum);
    --    var partExactAlnumRE = new RegExp('\\b' + queryAlnum + '\\b');
    --
    --    var _resultScoreFn = function(result) {
    --      // scores are calculated based on exact and prefix matches,
    --      // and then number of path separators (dots) from the last
    --      // match (i.e. favoring classes and deep package names)
    --      var score = 1.0;
    --      var labelLower = result.label.toLowerCase();
    --      var t;
    --      var partsAfter;
    --      t = _lastSearch(labelLower, partExactAlnumRE);
    --      if (t >= 0) {
    --        // exact part match
    --        partsAfter = _countChar(labelLower.substr(t + 1), '.');
    --        score *= 200 / (partsAfter + 1);
    --      } else {
    --        t = _lastSearch(labelLower, partPrefixAlnumRE);
    --        if (t >= 0) {
    --          // part prefix match
    --          partsAfter = _countChar(labelLower.substr(t + 1), '.');
    --          score *= 20 / (partsAfter + 1);
    --        }
    --      }
    --
    --      return score;
    --    };
    --
    --    for (var i = 0; i < matches.length; i++) {
    --      // if the API is deprecated, default score is 0; otherwise, perform scoring
    --      if (matches[i].deprecated === 'true') {
    --        matches[i].__resultScore = 0;
    --      } else {
    --        matches[i].__resultScore = _resultScoreFn(matches[i]);
    --      }
    --    }
    --
    --    matches.sort(function(a, b) {
    --      var n = b.__resultScore - a.__resultScore;
    --
    --      if (n === 0) {
    --        // lexicographical sort if scores are the same
    --        n = (a.label < b.label) ? -1 : 1;
    --      }
    --
    --      return n;
    --    });
    --  }
    --
    --  // Destructive but fast toUnique.
    --  // http://stackoverflow.com/a/25082874
    --  function toUnique(array) {
    --    var c;
    --    var b = array.length || 1;
    --
    --    while (c = --b) {
    --      while (c--) {
    --        if (array[b] === array[c]) {
    --          array.splice(c, 1);
    --        }
    --      }
    --    }
    --    return array;
    --  }
    --
    --  return search;
    --})();
    --
    --(function($) {
    --  'use strict';
    --
    --  /**
    --   * Smoothly scroll to location on current page.
    --   * @param el
    --   * @param options
    --   * @constructor
    --   */
    --  function ScrollButton(el, options) {
    --    this.el = $(el);
    --    this.target = $(this.el.attr('href'));
    --    this.options = $.extend({}, ScrollButton.DEFAULTS_, options);
    --
    --    if (typeof this.options.offset === 'string') {
    --      this.options.offset = $(this.options.offset).height();
    --    }
    --
    --    this.el.on('click', this.clickHandler_.bind(this));
    --  }
    --
    --  /**
    --   * Default options
    --   * @type {{duration: number, easing: string, offset: number, scrollContainer: string}}
    --   * @private
    --   */
    --  ScrollButton.DEFAULTS_ = {
    --    duration: 300,
    --    easing: 'swing',
    --    offset: '.dac-header',
    --    scrollContainer: 'html, body'
    --  };
    --
    --  /**
    --   * Scroll logic
    --   * @param event
    --   * @private
    --   */
    --  ScrollButton.prototype.clickHandler_ = function(event) {
    --    if (event.altKey || event.ctrlKey || event.metaKey || event.shiftKey) {
    --      return;
    --    }
    --
    --    event.preventDefault();
    --
    --    var position = this.getTargetPosition();
    --    $(this.options.scrollContainer).animate({
    --      scrollTop: position - this.options.offset
    --    }, this.options);
    --  };
    --
    --  ScrollButton.prototype.getTargetPosition = function() {
    --    if (this.options.scrollContainer === ScrollButton.DEFAULTS_.scrollContainer) {
    --      return this.target.offset().top;
    --    }
    --    var scrollContainer = $(this.options.scrollContainer)[0];
    --    var currentEl = this.target[0];
    --    var pos = 0;
    --    while (currentEl !== scrollContainer && currentEl !== null) {
    --      pos += currentEl.offsetTop;
    --      currentEl = currentEl.offsetParent;
    --    }
    --    return pos;
    --  };
    --
    --  /**
    --   * jQuery plugin
    --   * @param  {object} options - Override default options.
    --   */
    --  $.fn.dacScrollButton = function(options) {
    --    return this.each(function() {
    --      new ScrollButton(this, options);
    --    });
    --  };
    --
    --  /**
    --   * Data Attribute API
    --   */
    --  $(document).on('ready.aranja', function() {
    --    $('[data-scroll-button]').each(function() {
    --      $(this).dacScrollButton($(this).data());
    --    });
    --  });
    --})(jQuery);
    --
    --/* global getLangPref */
    --(function($) {
    --  var LANG;
    --
    --  function getSearchLang() {
    --    if (!LANG) {
    --      LANG = getLangPref();
    --
    --      // Fix zh-cn to be zh-CN.
    --      LANG = LANG.replace(/-\w+/, function(m) { return m.toUpperCase(); });
    --    }
    --    return LANG;
    --  }
    --
    --  function customSearch(query, start) {
    --    var searchParams = {
    --      // current cse instance:
    --      //cx: '001482626316274216503:zu90b7s047u',
    --      // new cse instance:
    --      cx: '000521750095050289010:zpcpi1ea4s8',
    --      key: 'AIzaSyCFhbGnjW06dYwvRCU8h_zjdpS4PYYbEe8',
    --      q: query,
    --      start: start || 1,
    --      num: 9,
    --      hl: getSearchLang(),
    --      fields: 'queries,items(pagemap,link,title,htmlSnippet,formattedUrl)'
    --    };
    --
    --    return $.get('https://content.googleapis.com/customsearch/v1?' +  $.param(searchParams));
    --  }
    --
    --  function renderResults(el, results, searchAppliance) {
    --    var referenceResults = searchAppliance.getReferenceResults();
    --    if (!results.items) {
    --      el.append($('<div>').text('No results'));
    --      return;
    --    }
    --
    --    for (var i = 0; i < results.items.length; i++) {
    --      var item = results.items[i];
    --      var isDuplicate = false;
    --      $(referenceResults.android).each(function(index, result) {
    --        if (item.link.indexOf(result.link) > -1) {
    --          isDuplicate = true;
    --          return false;
    --        }
    --      });
    --
    --      if (!isDuplicate) {
    --        var hasImage = item.pagemap && item.pagemap.cse_thumbnail;
    --        var sectionMatch = item.link.match(/developer\.android\.com\/(\w*)/);
    --        var section = (sectionMatch && sectionMatch[1]) || 'blog';
    --
    --        var entry = $('<div>').addClass('dac-custom-search-entry cols');
    --
    --        if (hasImage) {
    --          var image = item.pagemap.cse_thumbnail[0];
    --          entry.append($('<div>').addClass('dac-custom-search-image-wrapper')
    --            .append($('<div>').addClass('dac-custom-search-image').css('background-image', 'url(' + image.src + ')')));
    --        }
    --
    --        entry.append($('<div>').addClass('dac-custom-search-text-wrapper')
    --          .append($('<p>').addClass('dac-custom-search-section').text(section))
    --          .append(
    --            $('<a>').text(item.title).attr('href', item.link).wrap('<h2>').parent().addClass('dac-custom-search-title')
    --          )
    --          .append($('<p>').addClass('dac-custom-search-snippet').html(item.htmlSnippet.replace(/<br>/g, '')))
    --          .append($('<a>').addClass('dac-custom-search-link').text(item.formattedUrl).attr('href', item.link)));
    --
    --        el.append(entry);
    --      }
    --    }
    --
    --    if (results.queries.nextPage) {
    --      var loadMoreButton = $('<button id="dac-custom-search-load-more">')
    --        .addClass('dac-custom-search-load-more')
    --        .text('Load more')
    --        .click(function() {
    --          loadMoreResults(el, results, searchAppliance);
    --        });
    --
    --      el.append(loadMoreButton);
    --    }
    --  };
    --
    --  function loadMoreResults(el, results, searchAppliance) {
    --    var query = results.queries.request[0].searchTerms;
    --    var start = results.queries.nextPage[0].startIndex;
    --    var loadMoreButton = el.find('#dac-custom-search-load-more');
    --
    --    loadMoreButton.text('Loading more...');
    --
    --    customSearch(query, start).then(function(results) {
    --      loadMoreButton.remove();
    --      renderResults(el, results, searchAppliance);
    --    });
    --  }
    --
    --  $.fn.customSearch = function(query, searchAppliance) {
    --    var el = $(this);
    --
    --    customSearch(query).then(function(results) {
    --      el.empty();
    --      renderResults(el, results, searchAppliance);
    --    });
    --  };
    --})(jQuery);
    --
    --/* global METADATA */
    --
    --(function($) {
    --  $.fn.dacSearchRenderHero = function(resources, query) {
    --    var el = $(this);
    --    el.empty();
    --
    --    var resource = METADATA.searchHeroCollections[query];
    --
    --    if (resource) {
    --      el.dacHero(resource, true);
    --      el.show();
    --
    --      return true;
    --    } else {
    --      el.hide();
    --    }
    --  };
    --})(jQuery);
    --
    --(function($) {
    --  $.fn.dacSearchRenderReferences = function(results, query) {
    --    var referenceCard = $('.suggest-card.reference');
    --    referenceCard.data('searchreferences.dac', {results: results, query: query});
    --    renderResults(referenceCard, results, query, false);
    --  };
    --
    --  var ROW_COUNT_COLLAPSED = 20;
    --  var ROW_COUNT_EXPANDED = 40;
    --  var ROW_COUNT_GOOGLE_COLLAPSED = 1;
    --  var ROW_COUNT_GOOGLE_EXPANDED = 8;
    --
    --  function onSuggestionClick(e) {
    --    devsite.analytics.trackAnalyticsEvent('event',
    --        'Suggestion Click', 'clicked: ' + $(e.currentTarget).attr('href'),
    --        'query: ' + $('#search_autocomplete').val().toLowerCase());
    --  }
    --
    --  function buildLink(match) {
    --    var link = $('<a>').attr('href', window.toRoot + match.link);
    --
    --    var label = match.label;
    --    var classNameStart = label.match(/[A-Z]/) ? label.search(/[A-Z]/) : label.lastIndexOf('.') + 1;
    --    var newLink = '<span class="namespace">' +
    --      label.substr(0, classNameStart) +
    --      '</span>' +
    --      label.substr(classNameStart, label.length);
    --
    --    link.html(newLink);
    --    return link;
    --  }
    --
    --  function buildSuggestion(match, query) {
    --    var li = $('<li>').addClass('dac-search-results-reference-entry');
    --
    --    var link = buildLink(match);
    --    link.highlightMatches(query);
    --    li.append(link);
    --    return li[0];
    --  }
    --
    --  function buildResults(results, query) {
    --    return results.map(function(match) {
    --      return buildSuggestion(match, query);
    --    });
    --  }
    --
    --  function renderAndroidResults(list, gMatches, query) {
    --    list.empty();
    --
    --    var header = $('<li class="dac-search-results-reference-header">android APIs</li>');
    --    list.append(header);
    --
    --    if (gMatches.length > 0) {
    --      list.removeClass('no-results');
    --
    --      var resources = buildResults(gMatches, query);
    --      list.append(resources);
    --      return true;
    --    } else {
    --      list.append('<li class="dac-search-results-reference-entry-empty">No results</li>');
    --    }
    --  }
    --
    --  function renderGoogleDocsResults(list, gGoogleMatches, query) {
    --    list = $('.suggest-card.reference ul');
    --
    --    if (gGoogleMatches.length > 0) {
    --      list.append('<li class="dac-search-results-reference-header">in Google Services</li>');
    --
    --      var resources = buildResults(gGoogleMatches, query);
    --      list.append(resources);
    --
    --      return true;
    --    }
    --  }
    --
    --  function renderResults(referenceCard, results, query, expanded) {
    --    var list = referenceCard.find('ul');
    --    list.toggleClass('is-expanded', !!expanded);
    --
    --    // Figure out how many results we can show in our fixed size box.
    --    var total = expanded ? ROW_COUNT_EXPANDED : ROW_COUNT_COLLAPSED;
    --    var googleCount = expanded ? ROW_COUNT_GOOGLE_EXPANDED : ROW_COUNT_GOOGLE_COLLAPSED;
    --    googleCount = Math.max(googleCount, total - results.android.length);
    --    googleCount = Math.min(googleCount, results.docs.length);
    --
    --    if (googleCount > 0) {
    --      // If there are google results, reserve space for its header.
    --      googleCount++;
    --    }
    --
    --    var androidCount = Math.max(0, total - googleCount);
    --    if (androidCount === 0) {
    --      // Reserve space for "No reference results"
    --      googleCount--;
    --    }
    --
    --    renderAndroidResults(list, results.android.slice(0, androidCount), query);
    --    renderGoogleDocsResults(list, results.docs.slice(0, googleCount - 1), query);
    --
    --    var totalResults = results.android.length + results.docs.length;
    --    if (totalResults === 0) {
    --      list.addClass('no-results');
    --    }
    --
    --    // Tweak see more logic to account for references.
    --    var hasMore = totalResults > ROW_COUNT_COLLAPSED && !util.matchesMedia('mobile');
    --    if (hasMore) {
    --      // We can't actually show all matches, only as many as the expanded list
    --      // will fit, so we actually lie if the total results count is more
    --      var moreCount = Math.min(totalResults, ROW_COUNT_EXPANDED + ROW_COUNT_GOOGLE_EXPANDED);
    --      var $moreLink = $('<li class="dac-search-results-reference-entry-empty " data-toggle="show-more">see more matches</li>');
    --      list.append($moreLink.on('click', onToggleMore));
    --    }
    --    var searchEl = $('#search-resources');
    --    searchEl.toggleClass('dac-has-more', searchEl.hasClass('dac-has-more') || (hasMore && !expanded));
    --    searchEl.toggleClass('dac-has-less', searchEl.hasClass('dac-has-less') || (hasMore && expanded));
    --  }
    --
    --  function onToggleMore(e) {
    --    var link = $(e.currentTarget);
    --    var referenceCard = $('.suggest-card.reference');
    --    var data = referenceCard.data('searchreferences.dac');
    --
    --    if (util.matchesMedia('mobile')) { return; }
    --
    --    renderResults(referenceCard, data.results, data.query, link.data('toggle') === 'show-more');
    --  }
    --
    --  $(document).on('click', '.dac-search-results-resources [data-toggle="show-more"]', onToggleMore);
    --  $(document).on('click', '.dac-search-results-resources [data-toggle="show-less"]', onToggleMore);
    --  $(document).on('click', '.suggest-card.reference a', onSuggestionClick);
    --})(jQuery);
    --
    --(function($) {
    --  function highlightPage(query, page) {
    --    page.find('.title').highlightMatches(query);
    --  }
    --
    --  $.fn.dacSearchRenderResources = function(gDocsMatches, query) {
    --    this.resourceWidget(gDocsMatches, {
    --      itemsPerPage: 18,
    --      initialResults: 6,
    --      cardSizes: ['6x2'],
    --      onRenderPage: highlightPage.bind(null, query)
    --    });
    --
    --    return this;
    --  };
    --})(jQuery);
    --
    --/*global metadata */
    --
    --(function($, metadata) {
    --  'use strict';
    --
    --  function Search() {
    --    this.body = $('body');
    --    this.lastQuery = null;
    --    this.searchResults = $('#search-results');
    --    this.searchClose = $('[data-search-close]');
    --    this.searchClear = $('[data-search-clear]');
    --    this.searchInput = $('#search_autocomplete');
    --    this.searchResultsContent = $('#dac-search-results-content');
    --    this.searchResultsFor = $('#search-results-for');
    --    this.searchResultsHistory = $('#dac-search-results-history');
    --    this.searchResultsResources = $('#search-resources');
    --    this.searchResultsHero = $('#dac-search-results-hero');
    --    this.searchResultsReference = $('#dac-search-results-reference');
    --    this.searchHeader = $('[data-search]').data('search-input.dac');
    --    this.pageNav = $('a[name=navigation]');
    --    this.currQueryReferenceResults = {};
    --    this.isOpen = false;
    --  }
    --
    --  Search.prototype.init = function() {
    --    this.searchHistory = window.dacStore('search-history');
    --
    --    this.searchInput.focus(this.onSearchChanged.bind(this));
    --    this.searchInput.keypress(this.handleKeyboardShortcut.bind(this));
    --    this.pageNav.keyup(this.handleTabbedToNav.bind(this));
    --    this.searchResults.keyup(this.handleKeyboardShortcut.bind(this));
    --    this.searchInput.on('input', this.onSearchChanged.bind(this));
    --    this.searchClear.click(this.clear.bind(this));
    --    this.searchClose.click(this.close.bind(this));
    --
    --    this.customSearch = $.fn.debounce(function(query) {
    --      $('#dac-custom-search-results').customSearch(query, this);
    --    }.bind(this), 1000);
    --    // Start search shortcut (/)
    --    $('body').keyup(function(event) {
    --      if (event.which === 191 && $(event.target).is(':not(:input)')) {
    --        this.searchInput.focus();
    --      }
    --    }.bind(this));
    --
    --    $(window).on('popstate', this.onPopState.bind(this));
    --    $(window).hashchange(this.onHashChange.bind(this));
    --    this.onHashChange();
    --  };
    --
    --  Search.prototype.checkRedirectToIndex = function() {
    --    var query = this.getUrlQuery();
    --    var target = window.getLangTarget();
    --    var prefix = (target !== 'en') ? '/intl/' + target : '';
    --    var pathname = location.pathname.slice(prefix.length);
    --    if (query != null && pathname !== '/index.html') {
    --      location.href = prefix + '/index.html' + location.hash;
    --      return true;
    --    }
    --  };
    --
    --  Search.prototype.handleKeyboardShortcut = function(event) {
    --    // Close (esc)
    --    if (event.which === 27) {
    --      this.searchClose.trigger('click');
    --      event.preventDefault();
    --    }
    --
    --    // Previous result (up arrow)
    --    if (event.which === 38) {
    --      this.previousResult();
    --      event.preventDefault();
    --    }
    --
    --    // Next result (down arrow)
    --    if (event.which === 40) {
    --      this.nextResult();
    --      event.preventDefault();
    --    }
    --
    --    // Navigate to result (enter)
    --    if (event.which === 13) {
    --      this.navigateToResult();
    --      event.preventDefault();
    --    }
    --  };
    --
    --  Search.prototype.handleTabbedToNav = function(event) {
    --    if (this.isOpen) {
    --      this.searchClose.trigger('click');
    --    }
    --  }
    --
    --  Search.prototype.goToResult = function(relativeIndex) {
    --    var links = this.searchResults.find('a').filter(':visible');
    --    var selectedLink = this.searchResults.find('.dac-selected');
    --
    --    if (selectedLink.length) {
    --      var found = $.inArray(selectedLink[0], links);
    --
    --      selectedLink.removeClass('dac-selected');
    --      links.eq(found + relativeIndex).addClass('dac-selected');
    --      return true;
    --    } else {
    --      if (relativeIndex > 0) {
    --        links.first().addClass('dac-selected');
    --      }
    --    }
    --  };
    --
    --  Search.prototype.previousResult = function() {
    --    this.goToResult(-1);
    --  };
    --
    --  Search.prototype.nextResult = function() {
    --    this.goToResult(1);
    --  };
    --
    --  Search.prototype.navigateToResult = function() {
    --    var query = this.getQuery();
    --    var selectedLink = this.searchResults.find('.dac-selected');
    --
    --    if (selectedLink.length) {
    --      selectedLink[0].click();
    --    } else {
    --      this.searchHistory.push(query);
    --      this.addQueryToUrl(query);
    --
    --      var isMobileOrTablet = typeof window.orientation !== 'undefined';
    --
    --      if (isMobileOrTablet) {
    --        this.searchInput.blur();
    --      }
    --    }
    --  };
    --
    --  Search.prototype.onHashChange = function() {
    --    var query = this.getUrlQuery();
    --    if (query != null && query !== this.getQuery()) {
    --      this.searchInput.val(query);
    --      this.onSearchChanged();
    --    }
    --  };
    --
    --  Search.prototype.clear = function() {
    --    this.searchInput.val('');
    --    window.location.hash = '';
    --    this.onSearchChanged();
    --    this.searchInput.focus();
    --  };
    --
    --  Search.prototype.close = function() {
    --    this.removeQueryFromUrl();
    --    this.searchInput.blur();
    --    this.hideOverlay();
    --    this.pageNav.focus();
    --    this.isOpen = false;
    --  };
    --
    --  Search.prototype.getUrlQuery = function() {
    --    var queryMatch = location.hash.match(/q=(.*)&?/);
    --    return queryMatch && queryMatch[1] && decodeURI(queryMatch[1]);
    --  };
    --
    --  Search.prototype.getQuery = function() {
    --    return this.searchInput.val().replace(/(^ +)|( +$)/g, '');
    --  };
    --
    --  Search.prototype.getReferenceResults = function() {
    --    return this.currQueryReferenceResults;
    --  };
    --
    --  Search.prototype.onSearchChanged = function() {
    --    var query = this.getQuery();
    --
    --    this.showOverlay();
    --    this.render(query);
    --  };
    --
    --  Search.prototype.render = function(query) {
    --    if (this.lastQuery === query) { return; }
    --
    --    if (query.length < 2) {
    --      query = '';
    --    }
    --
    --    this.lastQuery = query;
    --    this.searchResultsFor.text(query);
    --
    --    // CSE results lag behind the metadata/reference results. We need to empty
    --    // the CSE results and add 'Loading' text so user's aren't looking at two
    --    // different sets of search results at one time.
    --    var $loadingEl =
    --        $('<div class="loadingCustomSearchResults">Loading Results...</div>');
    --    $('#dac-custom-search-results').empty().prepend($loadingEl);
    --
    --    this.customSearch(query);
    --    var metadataResults = metadata.search(query);
    --    this.searchResultsResources.dacSearchRenderResources(metadataResults.resources, query);
    --    this.searchResultsReference.dacSearchRenderReferences(metadataResults, query);
    --    this.currQueryReferenceResults = metadataResults;
    --    var hasHero = this.searchResultsHero.dacSearchRenderHero(metadataResults.resources, query);
    --    var hasQuery = !!query;
    --
    --    this.searchResultsReference.toggle(!hasHero);
    --    this.searchResultsContent.toggle(hasQuery);
    --    this.searchResultsHistory.toggle(!hasQuery);
    --    this.addQueryToUrl(query);
    --    this.pushState();
    --  };
    --
    --  Search.prototype.addQueryToUrl = function(query) {
    --    var hash = 'q=' + encodeURI(query);
    --
    --    if (query) {
    --      if (window.history.replaceState) {
    --        window.history.replaceState(null, '', '#' + hash);
    --      } else {
    --        window.location.hash = hash;
    --      }
    --    }
    --  };
    --
    --  Search.prototype.onPopState = function() {
    --    if (!this.getUrlQuery()) {
    --      this.hideOverlay();
    --      this.searchHeader.unsetActiveState();
    --    }
    --  };
    --
    --  Search.prototype.removeQueryFromUrl = function() {
    --    window.location.hash = '';
    --  };
    --
    --  Search.prototype.pushState = function() {
    --    if (window.history.pushState && !this.lastQuery.length) {
    --      window.history.pushState(null, '');
    --    }
    --  };
    --
    --  Search.prototype.showOverlay = function() {
    --    this.isOpen = true;
    --    this.body.addClass('dac-modal-open dac-search-open');
    --  };
    --
    --  Search.prototype.hideOverlay = function() {
    --    this.body.removeClass('dac-modal-open dac-search-open');
    --  };
    --
    --  $(document).on('ready.aranja', function() {
    --    var search = new Search();
    --    search.init();
    --  });
    --})(jQuery, metadata);
    --
    --window.dacStore = (function(window) {
    --  /**
    --   * Creates a new persistent store.
    --   * If localStorage is unavailable, the items are stored in memory.
    --   *
    --   * @constructor
    --   * @param {string} name    The name of the store
    --   * @param {number} maxSize The maximum number of items the store can hold.
    --   */
    --  var Store = function(name, maxSize) {
    --    var content = [];
    --
    --    var hasLocalStorage = !!window.localStorage;
    --
    --    if (hasLocalStorage) {
    --      try {
    --        content = JSON.parse(window.localStorage.getItem(name) || []);
    --      } catch (e) {
    --        // Store contains invalid data
    --        window.localStorage.removeItem(name);
    --      }
    --    }
    --
    --    function push(item) {
    --      if (content[0] === item) {
    --        return;
    --      }
    --
    --      content.unshift(item);
    --
    --      if (maxSize) {
    --        content.splice(maxSize, content.length);
    --      }
    --
    --      if (hasLocalStorage) {
    --        window.localStorage.setItem(name, JSON.stringify(content));
    --      }
    --    }
    --
    --    function all() {
    --      // Return a copy
    --      return content.slice();
    --    }
    --
    --    return {
    --      push: push,
    --      all: all
    --    };
    --  };
    --
    --  var stores = {
    --    'search-history': new Store('search-history', 3)
    --  };
    --
    --  /**
    --   * Get a named persistent store.
    --   * @param  {string} name
    --   * @return {Store}
    --   */
    --  return function getStore(name) {
    --    return stores[name];
    --  };
    --})(window);
    --
    --(function($) {
    --  'use strict';
    --
    --  /**
    --   * A component that swaps two dynamic height views with an animation.
    --   * Listens for the following events:
    --   * * swap-content: triggers SwapContent.swap_()
    --   * * swap-reset: triggers SwapContent.reset()
    --   * @param el
    --   * @param options
    --   * @constructor
    --   */
    --  function SwapContent(el, options) {
    --    this.el = $(el);
    --    this.options = $.extend({}, SwapContent.DEFAULTS_, options);
    --    this.options.dynamic = this.options.dynamic === 'true';
    --    this.containers = this.el.find(this.options.container);
    --    this.initiallyActive = this.containers.children('.' + this.options.activeClass).eq(0);
    --    this.el.on('swap-content', this.swap.bind(this));
    --    this.el.on('swap-reset', this.reset.bind(this));
    --    this.el.find(this.options.swapButton).on('click keypress', function(e) {
    --      if (e.type == 'keypress' && e.which == 13 || e.type == 'click') {
    --        this.swap();
    --      }
    --    }.bind(this));
    --  }
    --
    --  /**
    --   * SwapContent's default settings.
    --   * @type {{activeClass: string, container: string, transitionSpeed: number}}
    --   * @private
    --   */
    --  SwapContent.DEFAULTS_ = {
    --    activeClass: 'dac-active',
    --    container: '[data-swap-container]',
    --    dynamic: 'true',
    --    swapButton: '[data-swap-button]',
    --    transitionSpeed: 500
    --  };
    --
    --  /**
    --   * Returns container's visible height.
    --   * @param container
    --   * @returns {number}
    --   */
    --  SwapContent.prototype.currentHeight = function(container) {
    --    return container.children('.' + this.options.activeClass).outerHeight();
    --  };
    --
    --  /**
    --   * Reset to show initial content
    --   */
    --  SwapContent.prototype.reset = function() {
    --    if (!this.initiallyActive.hasClass(this.initiallyActive)) {
    --      this.containers.children().toggleClass(this.options.activeClass);
    --    }
    --  };
    --
    --  /**
    --   * Complete the swap.
    --   */
    --  SwapContent.prototype.complete = function() {
    --    this.containers.height('auto');
    --    this.containers.trigger('swap-complete');
    --  };
    --
    --  /**
    --   * Perform the swap of content.
    --   */
    --  SwapContent.prototype.swap = function() {
    --    this.containers.each(function(index, container) {
    --      container = $(container);
    --
    --      if (!this.options.dynamic) {
    --        container.children().toggleClass(this.options.activeClass);
    --        this.complete.bind(this);
    --        $('.' + this.options.activeClass).focus();
    --        return;
    --      }
    --
    --      container.height(this.currentHeight(container)).children().toggleClass(this.options.activeClass);
    --      container.animate({height: this.currentHeight(container)}, this.options.transitionSpeed,
    --        this.complete.bind(this));
    --    }.bind(this));
    --  };
    --
    --  /**
    --   * jQuery plugin
    --   * @param  {object} options - Override default options.
    --   */
    --  $.fn.dacSwapContent = function(options) {
    --    return this.each(function() {
    --      new SwapContent(this, options);
    --    });
    --  };
    --
    --  /**
    --   * Data Attribute API
    --   */
    --  $(document).on('ready.aranja', function() {
    --    $('[data-swap]').each(function() {
    --      $(this).dacSwapContent($(this).data());
    --    });
    --  });
    --})(jQuery);
    --
    --/* Tabs */
    --(function($) {
    --  'use strict';
    --
    --  /**
    --   * @param {HTMLElement} el - The DOM element.
    --   * @param {Object} options
    --   * @constructor
    --   */
    --  function Tabs(el, options) {
    --    this.el = $(el);
    --    this.options = $.extend({}, Tabs.DEFAULTS_, options);
    --    this.init();
    --  }
    --
    --  Tabs.DEFAULTS_ = {
    --    activeClass: 'dac-active',
    --    viewDataAttr: 'tab-view',
    --    itemDataAttr: 'tab-item'
    --  };
    --
    --  Tabs.prototype.init = function() {
    --    var itemDataAttribute = '[data-' + this.options.itemDataAttr + ']';
    --    this.tabEl_ = this.el.find(itemDataAttribute);
    --    this.tabViewEl_ = this.el.find('[data-' + this.options.viewDataAttr + ']');
    --    this.el.on('click.dac-tabs', itemDataAttribute, this.changeTabs.bind(this));
    --  };
    --
    --  Tabs.prototype.changeTabs = function(event) {
    --    var current = $(event.currentTarget);
    --    var index = current.index();
    --
    --    if (current.hasClass(this.options.activeClass)) {
    --      current.add(this.tabViewEl_.eq(index)).removeClass(this.options.activeClass);
    --    } else {
    --      this.tabEl_.add(this.tabViewEl_).removeClass(this.options.activeClass);
    --      current.add(this.tabViewEl_.eq(index)).addClass(this.options.activeClass);
    --    }
    --  };
    --
    --  /**
    --   * jQuery plugin
    --   */
    --  $.fn.dacTabs = function() {
    --    return this.each(function() {
    --      var el = $(this);
    --      new Tabs(el, el.data());
    --    });
    --  };
    --
    --  /**
    --   * Data Attribute API
    --   */
    --  $(function() {
    --    $('[data-tabs]').dacTabs();
    --  });
    --})(jQuery);
    --
    --/* Toast Component */
    --(function($) {
    --  'use strict';
    --  /**
    --   * @constant
    --   * @type {String}
    --   */
    --  var LOCAL_STORAGE_KEY = 'toast-closed-index';
    --
    --  /**
    --   * Dictionary from local storage.
    --   */
    --  var toastDictionary = localStorage.getItem(LOCAL_STORAGE_KEY);
    --  toastDictionary = toastDictionary ? JSON.parse(toastDictionary) : {};
    --
    --  /**
    --   * Variable used for caching the body.
    --   */
    --  var bodyCached;
    --
    --  /**
    --   * @param {HTMLElement} el - The DOM element.
    --   * @param {Object} options
    --   * @constructor
    --   */
    --  function Toast(el, options) {
    --    this.el = $(el);
    --    this.options = $.extend({}, Toast.DEFAULTS_, options);
    --    this.init();
    --  }
    --
    --  Toast.DEFAULTS_ = {
    --    closeBtnClass: 'dac-toast-close-btn',
    --    closeDuration: 200,
    --    visibleClass: 'dac-visible',
    --    wrapClass: 'dac-toast-wrap'
    --  };
    --
    --  /**
    --   * Generate a close button.
    --   * @returns {*|HTMLElement}
    --   */
    --  Toast.prototype.closeBtn = function() {
    --    this.closeBtnEl = this.closeBtnEl || $('<button class="' + this.options.closeBtnClass + '">' +
    --      '<span class="dac-button dac-raised dac-primary">OK</span>' +
    --    '</button>');
    --    return this.closeBtnEl;
    --  };
    --
    --  /**
    --   * Initialize a new toast element
    --   */
    --  Toast.prototype.init = function() {
    --    this.hash = this.el.text().replace(/[\s\n\t]/g, '').split('').slice(0, 128).join('');
    --
    --    if (toastDictionary[this.hash]) {
    --      return;
    --    }
    --
    --    this.closeBtn().on('click', this.onClickHandler.bind(this));
    --    this.el.find('.' + this.options.wrapClass).append(this.closeBtn());
    --    this.el.addClass(this.options.visibleClass);
    --    this.dynamicPadding(this.el.outerHeight());
    --  };
    --
    --  /**
    --   * Add padding to make sure all page is visible.
    --   */
    --  Toast.prototype.dynamicPadding = function(val) {
    --    var currentPadding = parseInt(bodyCached.css('padding-bottom') || 0);
    --    bodyCached.css('padding-bottom', val + currentPadding);
    --  };
    --
    --  /**
    --   * Remove a toast from the DOM
    --   */
    --  Toast.prototype.remove = function() {
    --    this.dynamicPadding(-this.el.outerHeight());
    --    this.el.remove();
    --  };
    --
    --  /**
    --   * Handle removal of the toast.
    --   */
    --  Toast.prototype.onClickHandler = function() {
    --    // Only fadeout toasts from top of stack. Others are removed immediately.
    --    var duration = this.el.index() === 0 ? this.options.closeDuration : 0;
    --    this.el.fadeOut(duration, this.remove.bind(this));
    --
    --    // Save closed state.
    --    toastDictionary[this.hash] = 1;
    --    localStorage.setItem(LOCAL_STORAGE_KEY, JSON.stringify(toastDictionary));
    --  };
    --
    --  /**
    --   * jQuery plugin
    --   * @param  {object} options - Override default options.
    --   */
    --  $.fn.dacToast = function() {
    --    return this.each(function() {
    --      var el = $(this);
    --      new Toast(el, el.data());
    --    });
    --  };
    --
    --  /**
    --   * Data Attribute API
    --   */
    --  $(function() {
    --    bodyCached = $('#body-content');
    --    $('[data-toast]').dacToast();
    --  });
    --})(jQuery);
    --
    --(function($) {
    --  function Toggle(el) {
    --    $(el).on('click.dac.togglesection', this.toggle);
    --  }
    --
    --  Toggle.prototype.toggle = function() {
    --    var $this = $(this);
    --
    --    var $parent = getParent($this);
    --    var isExpanded = $parent.hasClass('is-expanded');
    --
    --    transitionMaxHeight($parent.find('.dac-toggle-content'), !isExpanded);
    --    $parent.toggleClass('is-expanded');
    --
    --    return false;
    --  };
    --
    --  function getParent($this) {
    --    var selector = $this.attr('data-target');
    --
    --    if (!selector) {
    --      selector = $this.attr('href');
    --      selector = selector && /#[A-Za-z]/.test(selector) && selector.replace(/.*(?=#[^\s]*$)/, '');
    --    }
    --
    --    var $parent = selector && $(selector);
    --
    --    $parent = $parent && $parent.length ? $parent : $this.closest('.dac-toggle');
    --
    --    return $parent.length ? $parent : $this.parent();
    --  }
    --
    --  /**
    --   * Runs a transition of max-height along with responsive styles which hide or expand the element.
    --   * @param $el
    --   * @param visible
    --   */
    --  function transitionMaxHeight($el, visible) {
    --    var contentHeight = $el.prop('scrollHeight');
    --    var targetHeight = visible ? contentHeight : 0;
    --    var duration = $el.transitionDuration();
    --
    --    // If we're hiding, first set the maxHeight we're transitioning from.
    --    if (!visible) {
    --      $el.css({
    --          transitionDuration: '0s',
    --          maxHeight: contentHeight + 'px'
    --        })
    --        .resolveStyles()
    --        .css('transitionDuration', '');
    --    }
    --
    --    // Transition to new state
    --    $el.css('maxHeight', targetHeight);
    --
    --    // Reset maxHeight to css value after transition.
    --    setTimeout(function() {
    --      $el.css({
    --          transitionDuration: '0s',
    --          maxHeight: ''
    --        })
    --        .resolveStyles()
    --        .css('transitionDuration', '');
    --    }, duration);
    --  }
    --
    --  // Utility to get the transition duration for the element.
    --  $.fn.transitionDuration = function() {
    --    var d = $(this).css('transitionDuration') || '0s';
    --
    --    return +(parseFloat(d) * (/ms/.test(d) ? 1 : 1000)).toFixed(0);
    --  };
    --
    --  // jQuery plugin
    --  $.fn.toggleSection = function(option) {
    --    return this.each(function() {
    --      var $this = $(this);
    --      var data = $this.data('dac.togglesection');
    --      if (!data) {$this.data('dac.togglesection', (data = new Toggle(this)));}
    --      if (typeof option === 'string') {data[option].call($this);}
    --    });
    --  };
    --
    --  // Data api
    --  $(document)
    --    .on('click.toggle', '[data-toggle="section"]', Toggle.prototype.toggle);
    --})(jQuery);
    --
    --(function(window) {
    --  /**
    --   * Media query breakpoints. Should match CSS.
    --   */
    --  var BREAKPOINTS = {
    --    mobile: [0, 719],
    --    tablet: [720, 959],
    --    desktop: [960, 9999]
    --  };
    --
    --  /**
    --   * Fisher-Yates Shuffle (Knuth shuffle).
    --   * @param {Array} input
    --   * @returns {Array} shuffled array.
    --   */
    --  function shuffle(input) {
    --    for (var i = input.length; i >= 0; i--) {
    --      var randomIndex = Math.floor(Math.random() * (i + 1));
    --      var randomItem = input[randomIndex];
    --      input[randomIndex] = input[i];
    --      input[i] = randomItem;
    --    }
    --
    --    return input;
    --  }
    --
    --  /**
    --   * Matches media breakpoints like in CSS.
    --   * @param {string} form of either mobile, tablet or desktop.
    --   */
    --  function matchesMedia(form) {
    --    var breakpoint = BREAKPOINTS[form];
    --    return window.innerWidth >= breakpoint[0] && window.innerWidth <= breakpoint[1];
    --  }
    --
    --  window.util = {
    --    shuffle: shuffle,
    --    matchesMedia: matchesMedia
    --  };
    --})(window);
    --
    --(function($, window) {
    --  'use strict';
    --
    --  var YouTubePlayer = (function() {
    --    var player;
    --
    --    function VideoPlayer() {
    --      this.mPlayerPaused = false;
    --      this.doneSetup = false;
    --    }
    --
    --    VideoPlayer.prototype.setup = function() {
    --      // loads the IFrame Player API code asynchronously.
    --      $.getScript('https://www.youtube.com/iframe_api');
    --
    --      // Add the shadowbox HTML to the body
    --      $('body').prepend(
    --'<div id="video-player" class="Video">' +
    --  '<div id="video-overlay" class="Video-overlay" />' +
    --  '<div class="Video-container">' +
    --    '<div class="Video-frame">' +
    --      '<span class="Video-loading">Loading&hellip;</span>' +
    --      '<div id="youTubePlayer"></div>' +
    --    '</div>' +
    --    '<div class="Video-controls">' +
    --      '<button id="picture-in-picture" class="Video-button Video-button--picture-in-picture">' +
    --      '<button id="close-video" class="Video-button Video-button--close" />' +
    --    '</div>' +
    --  '</div>' +
    --'</div>');
    --
    --      this.videoPlayer = $('#video-player');
    --
    --      var pictureInPictureButton = this.videoPlayer.find('#picture-in-picture');
    --      pictureInPictureButton.on('click.aranja', this.toggleMinimizeVideo.bind(this));
    --
    --      var videoOverlay = this.videoPlayer.find('#video-overlay');
    --      var closeButton = this.videoPlayer.find('#close-video');
    --      var closeVideo = this.closeVideo.bind(this);
    --      videoOverlay.on('click.aranja', closeVideo);
    --      closeButton.on('click.aranja', closeVideo);
    --
    --      this.doneSetup = true;
    --    };
    --
    --    VideoPlayer.prototype.startYouTubePlayer = function(videoId) {
    --      this.videoPlayer.show();
    --
    --      if (!this.isLoaded) {
    --        this.queueVideo = videoId;
    --        return;
    --      }
    --
    --      this.mPlayerPaused = false;
    --      // check if we've already created this player
    --      if (!this.youTubePlayer) {
    --        // check if there's a start time specified
    --        var idAndHash = videoId.split('#');
    --        var startTime = 0;
    --        if (idAndHash.length > 1) {
    --          startTime = idAndHash[1].split('t=')[1] !== undefined ? idAndHash[1].split('t=')[1] : 0;
    --        }
    --        // enable localized player
    --        var lang = getLangPref();
    --        var captionsOn = lang === 'en' ? 0 : 1;
    --
    --        this.youTubePlayer = new YT.Player('youTubePlayer', {
    --          height: 720,
    --          width: 1280,
    --          videoId: idAndHash[0],
    --          // jscs:disable requireCamelCaseOrUpperCaseIdentifiers
    --          playerVars: {start: startTime, hl: lang, cc_load_policy: captionsOn},
    --          // jscs:enable
    --          events: {
    --            'onReady': this.onPlayerReady.bind(this),
    --            'onStateChange': this.onPlayerStateChange.bind(this)
    --          }
    --        });
    --      } else {
    --        // if a video different from the one already playing was requested, cue it up
    --        if (videoId !== this.getVideoId()) {
    --          this.youTubePlayer.cueVideoById(videoId);
    --        }
    --        this.youTubePlayer.playVideo();
    --      }
    --    };
    --
    --    VideoPlayer.prototype.onPlayerReady = function(event) {
    --      if (!isMobile) {
    --        event.target.playVideo();
    --        this.mPlayerPaused = false;
    --      }
    --    };
    --
    --    VideoPlayer.prototype.toggleMinimizeVideo = function(event) {
    --      event.stopPropagation();
    --      this.videoPlayer.toggleClass('Video--picture-in-picture');
    --    };
    --
    --    VideoPlayer.prototype.closeVideo = function() {
    --      try {
    --        this.youTubePlayer.pauseVideo();
    --      } catch (e) {
    --      }
    --      this.videoPlayer.fadeOut(200, function() {
    --        this.videoPlayer.removeClass('Video--picture-in-picture');
    --      }.bind(this));
    --    };
    --
    --    VideoPlayer.prototype.getVideoId = function() {
    --      // jscs:disable requireCamelCaseOrUpperCaseIdentifiers
    --      return this.youTubePlayer && this.youTubePlayer.getVideoData().video_id;
    --      // jscs:enable
    --    };
    --
    --    /* Track youtube playback for analytics */
    --    VideoPlayer.prototype.onPlayerStateChange = function(event) {
    --      var videoId = this.getVideoId();
    --      var currentTime = this.youTubePlayer && this.youTubePlayer.getCurrentTime();
    --
    --      // Video starts, send the video ID
    --      if (event.data === YT.PlayerState.PLAYING) {
    --        if (this.mPlayerPaused) {
    --          devsite.analytics.trackAnalyticsEvent('event',
    --              'Videos', 'Resume', videoId);
    --        } else {
    --          // track the start playing event so we know from which page the video was selected
    --          devsite.analytics.trackAnalyticsEvent('event',
    --              'Videos', 'Start: ' + videoId, 'on: ' + document.location.href);
    --        }
    --        this.mPlayerPaused = false;
    --      }
    --
    --      // Video paused, send video ID and video elapsed time
    --      if (event.data === YT.PlayerState.PAUSED) {
    --        devsite.analytics.trackAnalyticsEvent('event',
    --            'Videos', 'Paused: ' + videoId, 'on: ' + currentTime);
    --        this.mPlayerPaused = true;
    --      }
    --
    --      // Video finished, send video ID and video elapsed time
    --      if (event.data === YT.PlayerState.ENDED) {
    --        devsite.analytics.trackAnalyticsEvent('event',
    --            'Videos', 'Finished: ' + videoId, 'on: ' + currentTime);
    --        this.mPlayerPaused = true;
    --      }
    --    };
    --
    --    return {
    --      getPlayer: function() {
    --        if (!player) {
    --          player = new VideoPlayer();
    --        }
    --
    --        return player;
    --      }
    --    };
    --  })();
    --
    --  var videoPlayer = YouTubePlayer.getPlayer();
    --
    --  window.onYouTubeIframeAPIReady = function() {
    --    videoPlayer.isLoaded = true;
    --
    --    if (videoPlayer.queueVideo) {
    --      videoPlayer.startYouTubePlayer(videoPlayer.queueVideo);
    --    }
    --  };
    --
    --  function wrapLinkInPlayer(e) {
    --    e.preventDefault();
    --
    --    if (!videoPlayer.doneSetup) {
    --      videoPlayer.setup();
    --    }
    --
    --    var videoIdMatches = $(e.currentTarget).attr('href').match(/(?:youtu.be\/|v=)([^&]*)/);
    --    var videoId = videoIdMatches && videoIdMatches[1];
    --
    --    if (videoId) {
    --      videoPlayer.startYouTubePlayer(videoId);
    --    }
    --  }
    --
    --  $(document).on('click.video', 'a[href*="youtube.com/watch"], a[href*="youtu.be"]', wrapLinkInPlayer);
    --})(jQuery, window);
    --
    --/**
    -- * Wide table
    -- *
    -- * Wraps tables in a scrollable area so you can read them on mobile.
    -- */
    --(function($) {
    --  function initWideTable() {
    --    $('table.jd-sumtable').each(function(i, table) {
    --      $(table).wrap('<div class="dac-expand wide-table">');
    --    });
    --  }
    --
    --  $(function() {
    --    initWideTable();
    --  });
    --})(jQuery);
    --
    --/** Utilities */
    --
    --/* returns the given string with all HTML brackets converted to entities
    --    TODO: move this to the site's JS library */
    --function escapeHTML(string) {
    --  return string.replace(/</g,"&lt;")
    --                .replace(/>/g,"&gt;");
    --};
    --
    --function getQueryVariable(variable) {
    --  var query = window.location.search.substring(1);
    --  var vars = query.split("&");
    --  for (var i=0;i<vars.length;i++) {
    --    var pair = vars[i].split("=");
    --    if(pair[0] == variable){return pair[1];}
    --  }
    --  return(false);
    --};
    -diff --git a/tools/droiddoc/templates-sdk-dev/assets/js/prettify.js b/tools/droiddoc/templates-sdk-dev/assets/js/prettify.js
    -deleted file mode 100644
    -index eef5ad7..0000000
    ---- a/tools/droiddoc/templates-sdk-dev/assets/js/prettify.js
    -+++ /dev/null
    -@@ -1,28 +0,0 @@
    --var q=null;window.PR_SHOULD_USE_CONTINUATION=!0;
    --(function(){function L(a){function m(a){var f=a.charCodeAt(0);if(f!==92)return f;var b=a.charAt(1);return(f=r[b])?f:"0"<=b&&b<="7"?parseInt(a.substring(1),8):b==="u"||b==="x"?parseInt(a.substring(2),16):a.charCodeAt(1)}function e(a){if(a<32)return(a<16?"\\x0":"\\x")+a.toString(16);a=String.fromCharCode(a);if(a==="\\"||a==="-"||a==="["||a==="]")a="\\"+a;return a}function h(a){for(var f=a.substring(1,a.length-1).match(/\\u[\dA-Fa-f]{4}|\\x[\dA-Fa-f]{2}|\\[0-3][0-7]{0,2}|\\[0-7]{1,2}|\\[\S\s]|[^\\]/g),a=
    --[],b=[],o=f[0]==="^",c=o?1:0,i=f.length;c<i;++c){var j=f[c];if(/\\[bdsw]/i.test(j))a.push(j);else{var j=m(j),d;c+2<i&&"-"===f[c+1]?(d=m(f[c+2]),c+=2):d=j;b.push([j,d]);d<65||j>122||(d<65||j>90||b.push([Math.max(65,j)|32,Math.min(d,90)|32]),d<97||j>122||b.push([Math.max(97,j)&-33,Math.min(d,122)&-33]))}}b.sort(function(a,f){return a[0]-f[0]||f[1]-a[1]});f=[];j=[NaN,NaN];for(c=0;c<b.length;++c)i=b[c],i[0]<=j[1]+1?j[1]=Math.max(j[1],i[1]):f.push(j=i);b=["["];o&&b.push("^");b.push.apply(b,a);for(c=0;c<
    --f.length;++c)i=f[c],b.push(e(i[0])),i[1]>i[0]&&(i[1]+1>i[0]&&b.push("-"),b.push(e(i[1])));b.push("]");return b.join("")}function y(a){for(var f=a.source.match(/\[(?:[^\\\]]|\\[\S\s])*]|\\u[\dA-Fa-f]{4}|\\x[\dA-Fa-f]{2}|\\\d+|\\[^\dux]|\(\?[!:=]|[()^]|[^()[\\^]+/g),b=f.length,d=[],c=0,i=0;c<b;++c){var j=f[c];j==="("?++i:"\\"===j.charAt(0)&&(j=+j.substring(1))&&j<=i&&(d[j]=-1)}for(c=1;c<d.length;++c)-1===d[c]&&(d[c]=++t);for(i=c=0;c<b;++c)j=f[c],j==="("?(++i,d[i]===void 0&&(f[c]="(?:")):"\\"===j.charAt(0)&&
    --(j=+j.substring(1))&&j<=i&&(f[c]="\\"+d[i]);for(i=c=0;c<b;++c)"^"===f[c]&&"^"!==f[c+1]&&(f[c]="");if(a.ignoreCase&&s)for(c=0;c<b;++c)j=f[c],a=j.charAt(0),j.length>=2&&a==="["?f[c]=h(j):a!=="\\"&&(f[c]=j.replace(/[A-Za-z]/g,function(a){a=a.charCodeAt(0);return"["+String.fromCharCode(a&-33,a|32)+"]"}));return f.join("")}for(var t=0,s=!1,l=!1,p=0,d=a.length;p<d;++p){var g=a[p];if(g.ignoreCase)l=!0;else if(/[a-z]/i.test(g.source.replace(/\\u[\da-f]{4}|\\x[\da-f]{2}|\\[^UXux]/gi,""))){s=!0;l=!1;break}}for(var r=
    --{b:8,t:9,n:10,v:11,f:12,r:13},n=[],p=0,d=a.length;p<d;++p){g=a[p];if(g.global||g.multiline)throw Error(""+g);n.push("(?:"+y(g)+")")}return RegExp(n.join("|"),l?"gi":"g")}function M(a){function m(a){switch(a.nodeType){case 1:if(e.test(a.className))break;for(var g=a.firstChild;g;g=g.nextSibling)m(g);g=a.nodeName;if("BR"===g||"LI"===g)h[s]="\n",t[s<<1]=y++,t[s++<<1|1]=a;break;case 3:case 4:g=a.nodeValue,g.length&&(g=p?g.replace(/\r\n?/g,"\n"):g.replace(/[\t\n\r ]+/g," "),h[s]=g,t[s<<1]=y,y+=g.length,
    --t[s++<<1|1]=a)}}var e=/(?:^|\s)nocode(?:\s|$)/,h=[],y=0,t=[],s=0,l;a.currentStyle?l=a.currentStyle.whiteSpace:window.getComputedStyle&&(l=document.defaultView.getComputedStyle(a,q).getPropertyValue("white-space"));var p=l&&"pre"===l.substring(0,3);m(a);return{a:h.join("").replace(/\n$/,""),c:t}}function B(a,m,e,h){m&&(a={a:m,d:a},e(a),h.push.apply(h,a.e))}function x(a,m){function e(a){for(var l=a.d,p=[l,"pln"],d=0,g=a.a.match(y)||[],r={},n=0,z=g.length;n<z;++n){var f=g[n],b=r[f],o=void 0,c;if(typeof b===
    --"string")c=!1;else{var i=h[f.charAt(0)];if(i)o=f.match(i[1]),b=i[0];else{for(c=0;c<t;++c)if(i=m[c],o=f.match(i[1])){b=i[0];break}o||(b="pln")}if((c=b.length>=5&&"lang-"===b.substring(0,5))&&!(o&&typeof o[1]==="string"))c=!1,b="src";c||(r[f]=b)}i=d;d+=f.length;if(c){c=o[1];var j=f.indexOf(c),k=j+c.length;o[2]&&(k=f.length-o[2].length,j=k-c.length);b=b.substring(5);B(l+i,f.substring(0,j),e,p);B(l+i+j,c,C(b,c),p);B(l+i+k,f.substring(k),e,p)}else p.push(l+i,b)}a.e=p}var h={},y;(function(){for(var e=a.concat(m),
    --l=[],p={},d=0,g=e.length;d<g;++d){var r=e[d],n=r[3];if(n)for(var k=n.length;--k>=0;)h[n.charAt(k)]=r;r=r[1];n=""+r;p.hasOwnProperty(n)||(l.push(r),p[n]=q)}l.push(/[\S\s]/);y=L(l)})();var t=m.length;return e}function u(a){var m=[],e=[];a.tripleQuotedStrings?m.push(["str",/^(?:'''(?:[^'\\]|\\[\S\s]|''?(?=[^']))*(?:'''|$)|"""(?:[^"\\]|\\[\S\s]|""?(?=[^"]))*(?:"""|$)|'(?:[^'\\]|\\[\S\s])*(?:'|$)|"(?:[^"\\]|\\[\S\s])*(?:"|$))/,q,"'\""]):a.multiLineStrings?m.push(["str",/^(?:'(?:[^'\\]|\\[\S\s])*(?:'|$)|"(?:[^"\\]|\\[\S\s])*(?:"|$)|`(?:[^\\`]|\\[\S\s])*(?:`|$))/,
    --q,"'\"`"]):m.push(["str",/^(?:'(?:[^\n\r'\\]|\\.)*(?:'|$)|"(?:[^\n\r"\\]|\\.)*(?:"|$))/,q,"\"'"]);a.verbatimStrings&&e.push(["str",/^@"(?:[^"]|"")*(?:"|$)/,q]);var h=a.hashComments;h&&(a.cStyleComments?(h>1?m.push(["com",/^#(?:##(?:[^#]|#(?!##))*(?:###|$)|.*)/,q,"#"]):m.push(["com",/^#(?:(?:define|elif|else|endif|error|ifdef|include|ifndef|line|pragma|undef|warning)\b|[^\n\r]*)/,q,"#"]),e.push(["str",/^<(?:(?:(?:\.\.\/)*|\/?)(?:[\w-]+(?:\/[\w-]+)+)?[\w-]+\.h|[a-z]\w*)>/,q])):m.push(["com",/^#[^\n\r]*/,
    --q,"#"]));a.cStyleComments&&(e.push(["com",/^\/\/[^\n\r]*/,q]),e.push(["com",/^\/\*[\S\s]*?(?:\*\/|$)/,q]));a.regexLiterals&&e.push(["lang-regex",/^(?:^^\.?|[!+-]|!=|!==|#|%|%=|&|&&|&&=|&=|\(|\*|\*=|\+=|,|-=|->|\/|\/=|:|::|;|<|<<|<<=|<=|=|==|===|>|>=|>>|>>=|>>>|>>>=|[?@[^]|\^=|\^\^|\^\^=|{|\||\|=|\|\||\|\|=|~|break|case|continue|delete|do|else|finally|instanceof|return|throw|try|typeof)\s*(\/(?=[^*/])(?:[^/[\\]|\\[\S\s]|\[(?:[^\\\]]|\\[\S\s])*(?:]|$))+\/)/]);(h=a.types)&&e.push(["typ",h]);a=(""+a.keywords).replace(/^ | $/g,
    --"");a.length&&e.push(["kwd",RegExp("^(?:"+a.replace(/[\s,]+/g,"|")+")\\b"),q]);m.push(["pln",/^\s+/,q," \r\n\t\xa0"]);e.push(["lit",/^@[$_a-z][\w$@]*/i,q],["typ",/^(?:[@_]?[A-Z]+[a-z][\w$@]*|\w+_t\b)/,q],["pln",/^[$_a-z][\w$@]*/i,q],["lit",/^(?:0x[\da-f]+|(?:\d(?:_\d+)*\d*(?:\.\d*)?|\.\d\+)(?:e[+-]?\d+)?)[a-z]*/i,q,"0123456789"],["pln",/^\\[\S\s]?/,q],["pun",/^.[^\s\w"-$'./@\\`]*/,q]);return x(m,e)}function D(a,m){function e(a){switch(a.nodeType){case 1:if(k.test(a.className))break;if("BR"===a.nodeName)h(a),
    --a.parentNode&&a.parentNode.removeChild(a);else for(a=a.firstChild;a;a=a.nextSibling)e(a);break;case 3:case 4:if(p){var b=a.nodeValue,d=b.match(t);if(d){var c=b.substring(0,d.index);a.nodeValue=c;(b=b.substring(d.index+d[0].length))&&a.parentNode.insertBefore(s.createTextNode(b),a.nextSibling);h(a);c||a.parentNode.removeChild(a)}}}}function h(a){function b(a,d){var e=d?a.cloneNode(!1):a,f=a.parentNode;if(f){var f=b(f,1),g=a.nextSibling;f.appendChild(e);for(var h=g;h;h=g)g=h.nextSibling,f.appendChild(h)}return e}
    --for(;!a.nextSibling;)if(a=a.parentNode,!a)return;for(var a=b(a.nextSibling,0),e;(e=a.parentNode)&&e.nodeType===1;)a=e;d.push(a)}var k=/(?:^|\s)nocode(?:\s|$)/,t=/\r\n?|\n/,s=a.ownerDocument,l;a.currentStyle?l=a.currentStyle.whiteSpace:window.getComputedStyle&&(l=s.defaultView.getComputedStyle(a,q).getPropertyValue("white-space"));var p=l&&"pre"===l.substring(0,3);for(l=s.createElement("LI");a.firstChild;)l.appendChild(a.firstChild);for(var d=[l],g=0;g<d.length;++g)e(d[g]);m===(m|0)&&d[0].setAttribute("value",
    --m);var r=s.createElement("OL");r.className="linenums";for(var n=Math.max(0,m-1|0)||0,g=0,z=d.length;g<z;++g)l=d[g],l.className="L"+(g+n)%10,l.firstChild||l.appendChild(s.createTextNode("\xa0")),r.appendChild(l);a.appendChild(r)}function k(a,m){for(var e=m.length;--e>=0;){var h=m[e];A.hasOwnProperty(h)?window.console&&console.warn("cannot override language handler %s",h):A[h]=a}}function C(a,m){if(!a||!A.hasOwnProperty(a))a=/^\s*</.test(m)?"default-markup":"default-code";return A[a]}function E(a){var m=
    --a.g;try{var e=M(a.h),h=e.a;a.a=h;a.c=e.c;a.d=0;C(m,h)(a);var k=/\bMSIE\b/.test(navigator.userAgent),m=/\n/g,t=a.a,s=t.length,e=0,l=a.c,p=l.length,h=0,d=a.e,g=d.length,a=0;d[g]=s;var r,n;for(n=r=0;n<g;)d[n]!==d[n+2]?(d[r++]=d[n++],d[r++]=d[n++]):n+=2;g=r;for(n=r=0;n<g;){for(var z=d[n],f=d[n+1],b=n+2;b+2<=g&&d[b+1]===f;)b+=2;d[r++]=z;d[r++]=f;n=b}for(d.length=r;h<p;){var o=l[h+2]||s,c=d[a+2]||s,b=Math.min(o,c),i=l[h+1],j;if(i.nodeType!==1&&(j=t.substring(e,b))){k&&(j=j.replace(m,"\r"));i.nodeValue=
    --j;var u=i.ownerDocument,v=u.createElement("SPAN");v.className=d[a+1];var x=i.parentNode;x.replaceChild(v,i);v.appendChild(i);e<o&&(l[h+1]=i=u.createTextNode(t.substring(b,o)),x.insertBefore(i,v.nextSibling))}e=b;e>=o&&(h+=2);e>=c&&(a+=2)}}catch(w){"console"in window&&console.log(w&&w.stack?w.stack:w)}}var v=["break,continue,do,else,for,if,return,while"],w=[[v,"auto,case,char,const,default,double,enum,extern,float,goto,int,long,register,short,signed,sizeof,static,struct,switch,typedef,union,unsigned,void,volatile"],
    --"catch,class,delete,false,import,new,operator,private,protected,public,this,throw,true,try,typeof"],F=[w,"alignof,align_union,asm,axiom,bool,concept,concept_map,const_cast,constexpr,decltype,dynamic_cast,explicit,export,friend,inline,late_check,mutable,namespace,nullptr,reinterpret_cast,static_assert,static_cast,template,typeid,typename,using,virtual,where"],G=[w,"abstract,boolean,byte,extends,final,finally,implements,import,instanceof,null,native,package,strictfp,super,synchronized,throws,transient"],
    --H=[G,"as,base,by,checked,decimal,delegate,descending,dynamic,event,fixed,foreach,from,group,implicit,in,interface,internal,into,is,lock,object,out,override,orderby,params,partial,readonly,ref,sbyte,sealed,stackalloc,string,select,uint,ulong,unchecked,unsafe,ushort,var"],w=[w,"debugger,eval,export,function,get,null,set,undefined,var,with,Infinity,NaN"],I=[v,"and,as,assert,class,def,del,elif,except,exec,finally,from,global,import,in,is,lambda,nonlocal,not,or,pass,print,raise,try,with,yield,False,True,None"],
    --J=[v,"alias,and,begin,case,class,def,defined,elsif,end,ensure,false,in,module,next,nil,not,or,redo,rescue,retry,self,super,then,true,undef,unless,until,when,yield,BEGIN,END"],v=[v,"case,done,elif,esac,eval,fi,function,in,local,set,then,until"],K=/^(DIR|FILE|vector|(de|priority_)?queue|list|stack|(const_)?iterator|(multi)?(set|map)|bitset|u?(int|float)\d*)/,N=/\S/,O=u({keywords:[F,H,w,"caller,delete,die,do,dump,elsif,eval,exit,foreach,for,goto,if,import,last,local,my,next,no,our,print,package,redo,require,sub,undef,unless,until,use,wantarray,while,BEGIN,END"+
    --I,J,v],hashComments:!0,cStyleComments:!0,multiLineStrings:!0,regexLiterals:!0}),A={};k(O,["default-code"]);k(x([],[["pln",/^[^<?]+/],["dec",/^<!\w[^>]*(?:>|$)/],["com",/^<\!--[\S\s]*?(?:--\>|$)/],["lang-",/^<\?([\S\s]+?)(?:\?>|$)/],["lang-",/^<%([\S\s]+?)(?:%>|$)/],["pun",/^(?:<[%?]|[%?]>)/],["lang-",/^<xmp\b[^>]*>([\S\s]+?)<\/xmp\b[^>]*>/i],["lang-js",/^<script\b[^>]*>([\S\s]*?)(<\/script\b[^>]*>)/i],["lang-css",/^<style\b[^>]*>([\S\s]*?)(<\/style\b[^>]*>)/i],["lang-in.tag",/^(<\/?[a-z][^<>]*>)/i]]),
    --["default-markup","htm","html","mxml","xhtml","xml","xsl"]);k(x([["pln",/^\s+/,q," \t\r\n"],["atv",/^(?:"[^"]*"?|'[^']*'?)/,q,"\"'"]],[["tag",/^^<\/?[a-z](?:[\w-.:]*\w)?|\/?>$/i],["atn",/^(?!style[\s=]|on)[a-z](?:[\w:-]*\w)?/i],["lang-uq.val",/^=\s*([^\s"'>]*(?:[^\s"'/>]|\/(?=\s)))/],["pun",/^[/<->]+/],["lang-js",/^on\w+\s*=\s*"([^"]+)"/i],["lang-js",/^on\w+\s*=\s*'([^']+)'/i],["lang-js",/^on\w+\s*=\s*([^\s"'>]+)/i],["lang-css",/^style\s*=\s*"([^"]+)"/i],["lang-css",/^style\s*=\s*'([^']+)'/i],["lang-css",
    --/^style\s*=\s*([^\s"'>]+)/i]]),["in.tag"]);k(x([],[["atv",/^[\S\s]+/]]),["uq.val"]);k(u({keywords:F,hashComments:!0,cStyleComments:!0,types:K}),["c","cc","cpp","cxx","cyc","m"]);k(u({keywords:"null,true,false"}),["json"]);k(u({keywords:H,hashComments:!0,cStyleComments:!0,verbatimStrings:!0,types:K}),["cs"]);k(u({keywords:G,cStyleComments:!0}),["java"]);k(u({keywords:v,hashComments:!0,multiLineStrings:!0}),["bsh","csh","sh"]);k(u({keywords:I,hashComments:!0,multiLineStrings:!0,tripleQuotedStrings:!0}),
    --["cv","py"]);k(u({keywords:"caller,delete,die,do,dump,elsif,eval,exit,foreach,for,goto,if,import,last,local,my,next,no,our,print,package,redo,require,sub,undef,unless,until,use,wantarray,while,BEGIN,END",hashComments:!0,multiLineStrings:!0,regexLiterals:!0}),["perl","pl","pm"]);k(u({keywords:J,hashComments:!0,multiLineStrings:!0,regexLiterals:!0}),["rb"]);k(u({keywords:w,cStyleComments:!0,regexLiterals:!0}),["js"]);k(u({keywords:"all,and,by,catch,class,else,extends,false,finally,for,if,in,is,isnt,loop,new,no,not,null,of,off,on,or,return,super,then,true,try,unless,until,when,while,yes",
    --hashComments:3,cStyleComments:!0,multilineStrings:!0,tripleQuotedStrings:!0,regexLiterals:!0}),["coffee"]);k(x([],[["str",/^[\S\s]+/]]),["regex"]);window.prettyPrintOne=function(a,m,e){var h=document.createElement("PRE");h.innerHTML=a;e&&D(h,e);E({g:m,i:e,h:h});return h.innerHTML};window.prettyPrint=function(a){function m(){for(var e=window.PR_SHOULD_USE_CONTINUATION?l.now()+250:Infinity;p<h.length&&l.now()<e;p++){var n=h[p],k=n.className;if(k.indexOf("prettyprint")>=0){var k=k.match(g),f,b;if(b=
    --!k){b=n;for(var o=void 0,c=b.firstChild;c;c=c.nextSibling)var i=c.nodeType,o=i===1?o?b:c:i===3?N.test(c.nodeValue)?b:o:o;b=(f=o===b?void 0:o)&&"CODE"===f.tagName}b&&(k=f.className.match(g));k&&(k=k[1]);b=!1;for(o=n.parentNode;o;o=o.parentNode)if((o.tagName==="pre"||o.tagName==="code"||o.tagName==="xmp")&&o.className&&o.className.indexOf("prettyprint")>=0){b=!0;break}b||((b=(b=n.className.match(/\blinenums\b(?::(\d+))?/))?b[1]&&b[1].length?+b[1]:!0:!1)&&D(n,b),d={g:k,h:n,i:b},E(d))}}p<h.length?setTimeout(m,
    --250):a&&a()}for(var e=[document.getElementsByTagName("pre"),document.getElementsByTagName("code"),document.getElementsByTagName("xmp")],h=[],k=0;k<e.length;++k)for(var t=0,s=e[k].length;t<s;++t)h.push(e[k][t]);var e=q,l=Date;l.now||(l={now:function(){return+new Date}});var p=0,d,g=/\blang(?:uage)?-([\w.]+)(?!\S)/;m()};window.PR={createSimpleLexer:x,registerLangHandler:k,sourceDecorator:u,PR_ATTRIB_NAME:"atn",PR_ATTRIB_VALUE:"atv",PR_COMMENT:"com",PR_DECLARATION:"dec",PR_KEYWORD:"kwd",PR_LITERAL:"lit",
    --PR_NOCODE:"nocode",PR_PLAIN:"pln",PR_PUNCTUATION:"pun",PR_SOURCE:"src",PR_STRING:"str",PR_TAG:"tag",PR_TYPE:"typ"}})();
    -diff --git a/tools/droiddoc/templates-sdk-dev/body_tag.cs b/tools/droiddoc/templates-sdk-dev/body_tag.cs
    -deleted file mode 100644
    -index 5761b71..0000000
    ---- a/tools/droiddoc/templates-sdk-dev/body_tag.cs
    -+++ /dev/null
    -@@ -1,15 +0,0 @@
    --<body class="gc-documentation <?cs
    --  if:(reference.gms || reference.gcm)
    --    ?>google<?cs
    --  /if ?><?cs
    --  if:(guide||develop||training||reference||tools||sdk)
    --    ?>develop<?cs
    --    if:reference
    --      ?> reference api apilevel-<?cs var:class.since ?><?cs var:package.since ?><?cs
    --    /if ?><?cs
    --  elif:design
    --    ?>design<?cs
    --  elif:distribute
    --    ?>distribute<?cs
    --  /if ?>">
    --<div id="doc-api-level" class="<?cs var:class.since ?><?cs var:package.since ?>" style="display:none"></div>
    -diff --git a/tools/droiddoc/templates-sdk-dev/class.cs b/tools/droiddoc/templates-sdk-dev/class.cs
    -deleted file mode 100644
    -index dee7a4c..0000000
    ---- a/tools/droiddoc/templates-sdk-dev/class.cs
    -+++ /dev/null
    -@@ -1,646 +0,0 @@
    --<?cs # THIS CREATES A CLASS OR INTERFACE PAGE FROM .java FILES ?>
    --<?cs include:"macros.cs" ?>
    --<?cs include:"macros_override.cs" ?>
    --<?cs
    --####################
    --# MACRO FUNCTION USED ONLY IN THIS TEMPLATE TO GENERATE API REFERENCE
    --# FIRST, THE FUNCTIONS FOR THE SUMMARY AT THE TOP OF THE PAGE
    --####################
    --?>
    --
    --<?cs
    --# Prints the table cells for the summary of methods.
    --?><?cs def:write_method_summary(methods, included) ?>
    --<?cs set:count = #1 ?>
    --<?cs each:method = methods ?>
    --  <?cs # The apilevel-N class MUST BE LAST in the sequence of class names ?>
    --  <tr class="api apilevel-<?cs var:method.since ?>" >
    --  <?cs # leave out this cell if there is no return type = if constructors ?>
    --  <?cs if:subcount(method.returnType) ?>
    --    <td><code>
    --        <?cs var:method.abstract ?>
    --        <?cs var:method.default ?>
    --        <?cs var:method.static ?>
    --        <?cs var:method.final ?>
    --        <?cs call:type_link(method.generic) ?>
    --        <?cs call:type_link(method.returnType) ?></code>
    --    </td>
    --  <?cs /if ?>
    --    <td width="100%">
    --      <code>
    --      <?cs call:cond_link(method.name, toroot, method.href, included) ?>(<?cs call:parameter_list(method.params, 0) ?>)
    --      </code>
    --      <?cs if:subcount(method.shortDescr) || subcount(method.deprecated) ?>
    --        <p><?cs call:short_descr(method) ?>
    --        <?cs call:show_annotations_list(method) ?></p>
    --      <?cs /if ?>
    --    </td>
    --  </tr>
    --  <?cs set:count = count + #1 ?>
    --<?cs /each ?>
    --<?cs /def ?>
    --
    --<?cs
    --# Print the table cells for the summary of fields.
    --?><?cs def:write_field_summary(fields, included) ?>
    --<?cs set:count = #1 ?>
    --<?cs each:field=fields ?>
    --  <tr class="api apilevel-<?cs var:field.since ?>" >
    --    <td><code>
    --    <?cs var:field.scope ?>
    --    <?cs var:field.static ?>
    --    <?cs var:field.final ?>
    --    <?cs call:type_link(field.type) ?></code></td>
    --    <td width="100%">
    --      <code><?cs call:cond_link(field.name, toroot, field.href, included) ?></code>
    --      <p><?cs call:short_descr(field) ?>
    --      <?cs call:show_annotations_list(field) ?></p>
    --    </td>
    --  </tr>
    --  <?cs set:count = count + #1 ?>
    --<?cs /each ?>
    --<?cs /def ?>
    --
    --<?cs
    --# Print the table cells for the summary of constants
    --?><?cs def:write_constant_summary(fields, included) ?>
    --<?cs set:count = #1 ?>
    --    <?cs each:field=fields ?>
    --    <tr class="api apilevel-<?cs var:field.since ?>" >
    --        <td><code><?cs call:type_link(field.type) ?></code></td>
    --        <td width="100%">
    --          <code><?cs call:cond_link(field.name, toroot, field.href, included) ?></code>
    --          <p><?cs call:short_descr(field) ?>
    --          <?cs call:show_annotations_list(field) ?></p>
    --        </td>
    --    </tr>
    --    <?cs set:count = count + #1 ?>
    --    <?cs /each ?>
    --<?cs /def ?>
    --
    --<?cs
    --# Print the table cells for the summary of attributes
    --?><?cs def:write_attr_summary(attrs, included) ?>
    --<?cs set:count = #1 ?>
    --    <?cs each:attr=attrs ?>
    --    <tr class="api apilevel-<?cs var:attr.since ?>" >
    --        <td><?cs if:included ?><a href="<?cs var:toroot ?><?cs var:attr.href ?>"><?cs /if
    --          ?><code><?cs var:attr.name ?></code><?cs if:included ?></a><?cs /if ?></td>
    --        <td width="100%">
    --          <?cs call:short_descr(attr) ?>&nbsp;
    --          <?cs call:show_annotations_list(attr) ?>
    --        </td>
    --    </tr>
    --    <?cs set:count = count + #1 ?>
    --    <?cs /each ?>
    --<?cs /def ?>
    --
    --<?cs
    --# Print the table cells for the inner classes
    --?><?cs def:write_inners_summary(classes) ?>
    --<?cs set:count = #1 ?>
    --  <?cs each:cl=class.inners ?>
    --    <tr class="api apilevel-<?cs var:cl.since ?>" >
    --      <td class="jd-typecol"><code>
    --        <?cs var:cl.scope ?>
    --        <?cs var:cl.static ?>
    --        <?cs var:cl.final ?>
    --        <?cs var:cl.abstract ?>
    --        <?cs var:cl.kind ?></code></td>
    --      <td class="jd-descrcol" width="100%">
    --        <code><?cs call:type_link(cl.type) ?></code>
    --        <p><?cs call:short_descr(cl) ?>&nbsp;
    --        <?cs call:show_annotations_list(cl) ?></p>
    --      </td>
    --    </tr>
    --    <?cs set:count = count + #1 ?>
    --    <?cs /each ?>
    --<?cs /def ?>
    --<?cs
    --###################
    --# END OF FUNCTIONS FOR API SUMMARY
    --# START OF FUNCTIONS FOR THE API DETAILS
    --###################
    --?>
    --<?cs
    --# Print the table cells for the summary of constants
    --?>
    --<?cs def:write_field_details(fields) ?>
    --<?cs each:field=fields ?>
    --<?cs # this next line must be exactly like this to be parsed by eclipse ?>
    --<?cs # the A tag in the next line must remain where it is, so that Eclipse can parse the docs ?>
    --<A NAME="<?cs var:field.anchor ?>"></A>
    --<?cs # The apilevel-N class MUST BE LAST in the sequence of class names ?>
    --<div class="api apilevel-<?cs var:field.since ?>">
    --    <h3 class="api-name"><?cs var:field.name ?></h3>
    --    <div class="api-level">
    --      <?cs call:since_tags(field) ?>
    --      <?cs call:federated_refs(field) ?>
    --    </div>
    --<pre class="api-signature no-pretty-print">
    --<?cs if:subcount(field.scope) ?><?cs var:field.scope
    --?> <?cs /if ?><?cs if:subcount(field.static) ?><?cs var:field.static
    --?> <?cs /if ?><?cs if:subcount(field.final) ?><?cs var:field.final
    --?> <?cs /if ?><?cs if:subcount(field.type) ?><?cs call:type_link(field.type)
    --?> <?cs /if ?><?cs var:field.name ?></pre>
    --    <?cs call:show_annotations_list(field) ?>
    --    <?cs call:description(field) ?>
    --    <?cs if:subcount(field.constantValue) ?>
    --      <p>Constant Value:
    --      <?cs if:field.constantValue.isString ?>
    --          <?cs var:field.constantValue.str ?>
    --      <?cs else ?>
    --          <?cs var:field.constantValue.dec ?>
    --          (<?cs var:field.constantValue.hex ?>)
    --      <?cs /if ?>
    --    <?cs /if ?>
    --</div>
    --<?cs /each ?>
    --<?cs /def ?>
    --
    --<?cs def:write_method_details(methods) ?>
    --<?cs each:method=methods ?>
    --<?cs # the A tag in the next line must remain where it is, so that Eclipse can parse the docs ?>
    --<A NAME="<?cs var:method.anchor ?>"></A>
    --<?cs # The apilevel-N class MUST BE LAST in the sequence of class names ?>
    --<div class="api apilevel-<?cs var:method.since ?>">
    --    <h3 class="api-name"><?cs var:method.name ?></h3>
    --    <div class="api-level">
    --      <div><?cs call:since_tags(method) ?></div>
    --      <?cs call:federated_refs(method) ?>
    --    </div>
    --<pre class="api-signature no-pretty-print">
    --<?cs if:subcount(method.scope) ?><?cs var:method.scope
    --?> <?cs /if ?><?cs if:subcount(method.static) ?><?cs var:method.static
    --?> <?cs /if ?><?cs if:subcount(method.final) ?><?cs var:method.final
    --?> <?cs /if ?><?cs if:subcount(method.abstract) ?><?cs var:method.abstract
    --?> <?cs /if ?><?cs if:subcount(method.returnType) ?><?cs call:type_link(method.returnType)
    --?> <?cs /if ?><?cs var:method.name ?> (<?cs call:parameter_list(method.params, 1) ?>)</pre>
    --    <?cs call:show_annotations_list(method) ?>
    --    <?cs call:description(method) ?>
    --</div>
    --<?cs /each ?>
    --<?cs /def ?>
    --
    --<?cs def:write_attr_details(attrs) ?>
    --<?cs each:attr=attrs ?>
    --<?cs # the A tag in the next line must remain where it is, so that Eclipse can parse the docs ?>
    --<A NAME="<?cs var:attr.anchor ?>"></A>
    --<h3 class="api-name"><?cs var:attr.name ?></h3>
    --<?cs call:show_annotations_list(attr) ?>
    --<?cs call:description(attr) ?>
    --<?cs if:subcount(attr.methods) ?>
    --  <p><b>Related methods:</b></p>
    --  <ul class="nolist">
    --  <?cs each:m=attr.methods ?>
    --    <li><a href="<?cs var:toroot ?><?cs var:m.href ?>"><?cs var:m.name ?></a></li>
    --  <?cs /each ?>
    --  </ul>
    --<?cs /if ?>
    --<?cs /each ?>
    --<?cs /def ?>
    --<?cs
    --#########################
    --# END OF MACROS
    --# START OF PAGE PRINTING
    --#########################
    --?>
    --<?cs include:"doctype.cs" ?>
    --<html<?cs if:devsite ?> devsite<?cs /if ?>>
    --<?cs include:"head_tag.cs" ?>
    --<?cs include:"body_tag.cs" ?>
    --<?cs include:"header.cs" ?>
    --<?cs include:"page_info.cs" ?>
    --<?cs # This DIV spans the entire document to provide scope for some scripts ?>
    --<div class="api apilevel-<?cs var:class.since ?>" id="jd-content">
    --<?cs # this next line must be exactly like this to be parsed by eclipse ?>
    --<!-- ======== START OF CLASS DATA ======== -->
    --<?cs
    --#
    --# Page header with class name and signature
    --#
    --?>
    --<h1 class="api-title"><?cs var:class.name ?></h1>
    --<p>
    --<code class="api-signature">
    --  <?cs var:class.scope ?>
    --  <?cs var:class.static ?>
    --  <?cs var:class.final ?>
    --  <?cs var:class.abstract ?>
    --  <?cs var:class.kind ?>
    --  <?cs var:class.name ?>
    --</code>
    --<br>
    --<?cs set:colspan = subcount(class.inheritance) ?>
    --<?cs each:supr = class.inheritance ?>
    --<code class="api-signature">
    --  <?cs if:colspan == 2 ?>
    --    extends <?cs call:type_link(supr.short_class) ?>
    --  <?cs /if ?>
    --  <?cs if:last(supr) && subcount(supr.interfaces) ?>
    --      implements
    --      <?cs each:t=supr.interfaces ?>
    --        <?cs call:type_link(t) ?><?cs
    --          if: name(t)!=subcount(supr.interfaces)-1
    --            ?>, <?cs /if ?>
    --      <?cs /each ?>
    --  <?cs /if ?>
    --  <?cs set:colspan = colspan-1 ?>
    --</code>
    --<?cs /each ?>
    --</p><?cs
    --#
    --# Class inheritance tree
    --#
    --?><table class="jd-inheritance-table">
    --<?cs set:colspan = subcount(class.inheritance) ?>
    --<?cs each:supr = class.inheritance ?>
    --  <tr>
    --    <?cs loop:i = 1, (subcount(class.inheritance)-colspan), 1 ?>
    --      <td class="jd-inheritance-space">&nbsp;<?cs
    --        if:(subcount(class.inheritance)-colspan) == i
    --          ?>&nbsp;&nbsp;&#x21b3;<?cs
    --        /if ?></td>
    --    <?cs /loop ?>
    --    <td colspan="<?cs var:colspan ?>" class="jd-inheritance-class-cell"><?cs
    --      if:colspan == 1
    --          ?><?cs call:class_name(class.qualifiedType) ?><?cs
    --      else
    --          ?><?cs call:type_link(supr.class) ?><?cs
    --      /if ?>
    --    </td>
    --  </tr>
    --  <?cs set:colspan = colspan-1 ?>
    --<?cs /each ?>
    --</table><?cs
    --#
    --# Collapsible list of subclasses
    --#
    --?><?cs
    --if:subcount(class.subclasses.direct) && !class.subclasses.hidden ?>
    --  <table class="jd-sumtable jd-sumtable-subclasses">
    --  <tr><td style="border:none;margin:0;padding:0;">
    --    <?cs call:expando_trigger("subclasses-direct", "closed") ?>Known Direct Subclasses
    --    <?cs call:expandable_class_list("subclasses-direct", class.subclasses.direct, "list") ?>
    --  </td></tr>
    --  </table>
    --  <?cs /if ?>
    --  <?cs if:subcount(class.subclasses.indirect) && !class.subclasses.hidden ?>
    --  <table class="jd-sumtable jd-sumtable-subclasses"><tr><td colspan="2" style="border:none;margin:0;padding:0;">
    --  <?cs call:expando_trigger("subclasses-indirect", "closed") ?>Known Indirect Subclasses
    --  <?cs call:expandable_class_list("subclasses-indirect", class.subclasses.indirect, "list") ?>
    --  </td></tr></table><?cs
    --/if ?>
    --<?cs call:show_annotations_list(class) ?>
    --<br><hr><?cs
    --#
    --# The long-form class description.
    --#
    --?><?cs call:deprecated_warning(class) ?>
    --
    --<?cs if:subcount(class.descr) ?>
    --  <p><?cs call:tag_list(class.descr) ?></p>
    --<?cs /if ?>
    --
    --<?cs call:see_also_tags(class.seeAlso) ?>
    --<?cs
    --#################
    --# CLASS SUMMARY
    --#################
    --?>
    --<?cs # make sure there is a summary view to display ?>
    --<?cs if:subcount(class.inners)
    --     || subcount(class.attrs)
    --     || inhattrs
    --     || subcount(class.enumConstants)
    --     || subcount(class.constants)
    --     || inhconstants
    --     || subcount(class.fields)
    --     || inhfields
    --     || subcount(class.ctors.public)
    --     || subcount(class.ctors.protected)
    --     || subcount(class.methods.public)
    --     || subcount(class.methods.protected)
    --     || inhmethods ?>
    --<h2 class="api-section">Summary</h2>
    --
    --<?cs if:subcount(class.inners) ?>
    --<?cs # this next line must be exactly like this to be parsed by eclipse ?>
    --<!-- ======== NESTED CLASS SUMMARY ======== -->
    --<table id="nestedclasses" class="responsive">
    --<tr><th colspan="2"><h3>Nested classes</h3></th></tr>
    --<?cs call:write_inners_summary(class.inners) ?>
    --<?cs /if ?>
    --
    --<?cs # this next line must be exactly like this to be parsed by eclipse ?>
    --<?cs if:subcount(class.attrs) ?>
    --<!-- =========== FIELD SUMMARY =========== -->
    --<table id="lattrs" class="responsive">
    --<tr><th colspan="2"><h3>XML attributes</h3></th></tr>
    --<?cs call:write_attr_summary(class.attrs, 1) ?>
    --<?cs /if ?>
    --
    --<?cs # if there are inherited attrs, write the table ?>
    --<?cs if:inhattrs ?>
    --<?cs # this next line must be exactly like this to be parsed by eclipse ?>
    --<!-- =========== FIELD SUMMARY =========== -->
    --<table id="inhattrs" class="responsive inhtable">
    --<tr><th><h3>Inherited XML attributes</h3></th></tr>
    --<?cs each:cl=class.inherited ?>
    --<?cs if:subcount(cl.attrs) ?>
    --<tr class="api apilevel-<?cs var:cl.since ?>" >
    --<td colspan="2">
    --<?cs call:expando_trigger("inherited-attrs-"+cl.qualified, "closed") ?>From
    --<?cs var:cl.kind ?>
    --<code>
    --  <?cs call:cond_link(cl.qualified, toroot, cl.link, cl.included) ?>
    --</code>
    --<div id="inherited-attrs-<?cs var:cl.qualified ?>">
    --  <div id="inherited-attrs-<?cs var:cl.qualified ?>-list"
    --        class="jd-inheritedlinks">
    --  </div>
    --  <div id="inherited-attrs-<?cs var:cl.qualified ?>-summary" style="display: none;">
    --    <table class="jd-sumtable-expando">
    --    <?cs call:write_attr_summary(cl.attrs, cl.included) ?></table>
    --  </div>
    --</div>
    --</td></tr>
    --<?cs /if ?>
    --<?cs /each ?>
    --</table>
    --<?cs /if ?>
    --
    --<?cs if:subcount(class.enumConstants) ?>
    --<?cs # this next line must be exactly like this to be parsed by eclipse ?>
    --<!-- =========== ENUM CONSTANT SUMMARY =========== -->
    --<table id="enumconstants" class="responsive constants">
    --  <tr><th colspan="2"><h3>Enum values</h3></th></tr>
    --<?cs set:count = #1 ?>
    --  <?cs each:field=class.enumConstants ?>
    --  <tr class="api apilevel-<?cs var:field.since ?>" >
    --    <td><code><?cs call:type_link(field.type) ?></code>&nbsp;</td>
    --    <td width="100%">
    --      <code><?cs call:cond_link(field.name, toroot, field.href, cl.included) ?></code>
    --      <p><?cs call:short_descr(field) ?>&nbsp;
    --      <?cs call:show_annotations_list(field) ?></p>
    --    </td>
    --  </tr>
    --  <?cs set:count = count + #1 ?>
    --  <?cs /each ?>
    --<?cs /if ?>
    --
    --<?cs if:subcount(class.constants) ?>
    --<?cs # this next line must be exactly like this to be parsed by eclipse ?>
    --<!-- =========== ENUM CONSTANT SUMMARY =========== -->
    --<table id="constants" class="responsive constants">
    --<tr><th colspan="2"><h3>Constants</h3></th></tr>
    --<?cs call:write_constant_summary(class.constants, 1) ?>
    --</table>
    --<?cs /if ?>
    --
    --<?cs # if there are inherited constants, write the table ?>
    --<?cs if:inhconstants ?>
    --<?cs # this next line must be exactly like this to be parsed by eclipse ?>
    --<!-- =========== ENUM CONSTANT SUMMARY =========== -->
    --<table id="inhconstants" class="responsive constants inhtable">
    --<tr><th><h3>Inherited constants</h3></th></tr>
    --<?cs each:cl=class.inherited ?>
    --<?cs if:subcount(cl.constants) ?>
    --  <tr class="api apilevel-<?cs var:cl.since ?>" >
    --  <td>
    --  <?cs call:expando_trigger("inherited-constants-"+cl.qualified, "closed") ?>From
    --  <?cs var:cl.kind ?>
    --  <code>
    --    <?cs call:cond_link(cl.qualified, toroot, cl.link, cl.included) ?>
    --  </code>
    --  <div id="inherited-constants-<?cs var:cl.qualified ?>">
    --    <div id="inherited-constants-<?cs var:cl.qualified ?>-list"
    --          class="jd-inheritedlinks">
    --    </div>
    --    <div id="inherited-constants-<?cs var:cl.qualified ?>-summary" style="display: none;">
    --      <table class="jd-sumtable-expando responsive">
    --      <?cs call:write_constant_summary(cl.constants, cl.included) ?></table>
    --    </div>
    --  </div>
    --  </td></tr>
    --<?cs /if ?>
    --<?cs /each ?>
    --</table>
    --<?cs /if ?>
    --
    --<?cs if:subcount(class.fields) ?>
    --<?cs # this next line must be exactly like this to be parsed by eclipse ?>
    --<!-- =========== FIELD SUMMARY =========== -->
    --<table id="lfields" class="responsive properties">
    --<tr><th colspan="2"><h3>Fields</h3></th></tr>
    --<?cs call:write_field_summary(class.fields, 1) ?>
    --</table>
    --<?cs /if ?>
    --
    --<?cs # if there are inherited fields, write the table ?>
    --<?cs if:inhfields ?>
    --<?cs # this next line must be exactly like this to be parsed by eclipse ?>
    --<!-- =========== FIELD SUMMARY =========== -->
    --<table id="inhfields" class="properties inhtable">
    --<tr><th><h3>Inherited fields</h3></th></tr>
    --<?cs each:cl=class.inherited ?>
    --<?cs if:subcount(cl.fields) ?>
    --  <tr class="api apilevel-<?cs var:cl.since ?>" >
    --  <td>
    --  <?cs call:expando_trigger("inherited-fields-"+cl.qualified, "closed") ?>From
    --  <?cs var:cl.kind ?>
    --  <code>
    --    <?cs call:cond_link(cl.qualified, toroot, cl.link, cl.included) ?>
    --  </code>
    --  <div id="inherited-fields-<?cs var:cl.qualified ?>">
    --    <div id="inherited-fields-<?cs var:cl.qualified ?>-list"
    --          class="jd-inheritedlinks">
    --    </div>
    --    <div id="inherited-fields-<?cs var:cl.qualified ?>-summary" style="display: none;">
    --      <table class="jd-sumtable-expando responsive">
    --      <?cs call:write_field_summary(cl.fields, cl.included) ?></table>
    --    </div>
    --  </div>
    --  </td></tr>
    --<?cs /if ?>
    --<?cs /each ?>
    --</table>
    --<?cs /if ?>
    --
    --<?cs if:subcount(class.ctors.public) ?>
    --<?cs # this next line must be exactly like this to be parsed by eclipse ?>
    --<!-- ======== CONSTRUCTOR SUMMARY ======== -->
    --<table id="pubctors" class="responsive constructors">
    --<tr><th colspan="2"><h3>Public constructors</h3></th></tr>
    --<?cs call:write_method_summary(class.ctors.public, 1) ?>
    --</table>
    --<?cs /if ?>
    --
    --<?cs if:subcount(class.ctors.protected) ?>
    --<?cs # this next line must be exactly like this to be parsed by eclipse ?>
    --<!-- ======== CONSTRUCTOR SUMMARY ======== -->
    --<table id="proctors" class="responsive constructors">
    --<tr><th colspan="2"><h3>Protected constructors</h3></th></tr>
    --<?cs call:write_method_summary(class.ctors.protected, 1) ?>
    --</table>
    --<?cs /if ?>
    --
    --<?cs if:subcount(class.methods.public) ?>
    --<?cs # this next line must be exactly like this to be parsed by eclipse ?>
    --<!-- ========== METHOD SUMMARY =========== -->
    --<table id="pubmethods" class="responsive methods">
    --<tr><th colspan="2"><h3>Public methods</h3></th></tr>
    --<?cs call:write_method_summary(class.methods.public, 1) ?>
    --</table>
    --<?cs /if ?>
    --
    --<?cs if:subcount(class.methods.protected) ?>
    --<?cs # this next line must be exactly like this to be parsed by eclipse ?>
    --<!-- ========== METHOD SUMMARY =========== -->
    --<table id="promethods" class="reponsive methods">
    --<tr><th colspan="2"><h3>Protected methods</h3></th></tr>
    --<?cs call:write_method_summary(class.methods.protected, 1) ?>
    --</table>
    --<?cs /if ?>
    --
    --<?cs # if there are inherited methods, write the table ?>
    --<?cs if:inhmethods ?>
    --<?cs # this next line must be exactly like this to be parsed by eclipse ?>
    --<!-- ========== METHOD SUMMARY =========== -->
    --<table id="inhmethods" class="methods inhtable">
    --<tr><th><h3>Inherited methods</h3></th></tr>
    --<?cs each:cl=class.inherited ?>
    --<?cs if:subcount(cl.methods) ?>
    --<tr class="api apilevel-<?cs var:cl.since ?>" >
    --<td colspan="2">
    --<?cs call:expando_trigger("inherited-methods-"+cl.qualified, "closed") ?>From
    --<?cs var:cl.kind ?>
    --<code>
    --  <?cs if:cl.included ?>
    --    <a href="<?cs var:toroot ?><?cs var:cl.link ?>"><?cs var:cl.qualified ?></a>
    --  <?cs elif:cl.federated ?>
    --    <a href="<?cs var:cl.link ?>"><?cs var:cl.qualified ?></a>
    --  <?cs else ?>
    --    <?cs var:cl.qualified ?>
    --  <?cs /if ?>
    --</code>
    --<div id="inherited-methods-<?cs var:cl.qualified ?>">
    --  <div id="inherited-methods-<?cs var:cl.qualified ?>-list"
    --        class="jd-inheritedlinks">
    --  </div>
    --  <div id="inherited-methods-<?cs var:cl.qualified ?>-summary" style="display: none;">
    --    <table class="jd-sumtable-expando responsive">
    --      <?cs call:write_method_summary(cl.methods, cl.included) ?>
    --    </table>
    --  </div>
    --</div>
    --</td></tr>
    --<?cs /if ?>
    --<?cs /each ?>
    --</table>
    --<?cs /if ?>
    --<?cs /if ?>
    --<?cs
    --################
    --# CLASS DETAILS
    --################
    --?>
    --<!-- XML Attributes -->
    --<?cs if:subcount(class.attrs) ?>
    --<?cs # this next line must be exactly like this to be parsed by eclipse ?>
    --<!-- ========= FIELD DETAIL ======== -->
    --<h2 class="api-section">XML attributes</h2>
    --<?cs call:write_attr_details(class.attrs) ?>
    --<?cs /if ?>
    --
    --<!-- Enum Values -->
    --<?cs if:subcount(class.enumConstants) ?>
    --<?cs # this next line must be exactly like this to be parsed by eclipse ?>
    --<!-- ========= ENUM CONSTANTS DETAIL ======== -->
    --<h2 class="api-section">Enum values</h2>
    --<?cs call:write_field_details(class.enumConstants) ?>
    --<?cs /if ?>
    --
    --<!-- Constants -->
    --<?cs if:subcount(class.constants) ?>
    --<?cs # this next line must be exactly like this to be parsed by eclipse ?>
    --<!-- ========= ENUM CONSTANTS DETAIL ======== -->
    --<h2 class="api-section">Constants</h2>
    --<?cs call:write_field_details(class.constants) ?>
    --<?cs /if ?>
    --
    --<!-- Fields -->
    --<?cs if:subcount(class.fields) ?>
    --<?cs # this next line must be exactly like this to be parsed by eclipse ?>
    --<!-- ========= FIELD DETAIL ======== -->
    --<h2 class="api-section">Fields</h2>
    --<?cs call:write_field_details(class.fields) ?>
    --<?cs /if ?>
    --
    --<!-- Public ctors -->
    --<?cs if:subcount(class.ctors.public) ?>
    --<?cs # this next line must be exactly like this to be parsed by eclipse ?>
    --<!-- ========= CONSTRUCTOR DETAIL ======== -->
    --<h2 class="api-section">Public constructors</h2>
    --<?cs call:write_method_details(class.ctors.public) ?>
    --<?cs /if ?>
    --
    --<?cs # this next line must be exactly like this to be parsed by eclipse ?>
    --<!-- ========= CONSTRUCTOR DETAIL ======== -->
    --<!-- Protected ctors -->
    --<?cs if:subcount(class.ctors.protected) ?>
    --<h2 class="api-section">Protected constructors</h2>
    --<?cs call:write_method_details(class.ctors.protected) ?>
    --<?cs /if ?>
    --
    --<?cs # this next line must be exactly like this to be parsed by eclipse ?>
    --<!-- ========= METHOD DETAIL ======== -->
    --<!-- Public methdos -->
    --<?cs if:subcount(class.methods.public) ?>
    --<h2 class="api-section">Public methods</h2>
    --<?cs call:write_method_details(class.methods.public) ?>
    --<?cs /if ?>
    --
    --<?cs # this next line must be exactly like this to be parsed by eclipse ?>
    --<!-- ========= METHOD DETAIL ======== -->
    --<?cs if:subcount(class.methods.protected) ?>
    --<h2 class="api-section">Protected methods</h2>
    --<?cs call:write_method_details(class.methods.protected) ?>
    --<?cs /if ?>
    --
    --<?cs # the next two lines must be exactly like this to be parsed by eclipse ?>
    --<!-- ========= END OF CLASS DATA ========= -->
    --
    --</div><!-- end jd-content -->
    --
    --<?cs if:devsite ?>
    --
    --<div class="data-reference-resources-wrapper">
    --  <?cs if:subcount(class.package) ?>
    --  <ul data-reference-resources>
    --    <?cs call:list("Annotations", class.package.annotations) ?>
    --    <?cs call:list("Interfaces", class.package.interfaces) ?>
    --    <?cs call:list("Classes", class.package.classes) ?>
    --    <?cs call:list("Enums", class.package.enums) ?>
    --    <?cs call:list("Exceptions", class.package.exceptions) ?>
    --    <?cs call:list("Errors", class.package.errors) ?>
    --  </ul>
    --  <?cs elif:subcount(package) ?>
    --  <ul data-reference-resources>
    --    <?cs call:class_link_list("Annotations", package.annotations) ?>
    --    <?cs call:class_link_list("Interfaces", package.interfaces) ?>
    --    <?cs call:class_link_list("Classes", package.classes) ?>
    --    <?cs call:class_link_list("Enums", package.enums) ?>
    --    <?cs call:class_link_list("Exceptions", package.exceptions) ?>
    --    <?cs call:class_link_list("Errors", package.errors) ?>
    --  </ul>
    --  <?cs /if ?>
    --</div>
    --<?cs /if ?>
    --
    --<?cs if:!devsite ?>
    --<?cs include:"footer.cs" ?>
    --<?cs include:"trailer.cs" ?>
    --<?cs /if ?>
    --</body>
    --</html>
    -diff --git a/tools/droiddoc/templates-sdk-dev/classes.cs b/tools/droiddoc/templates-sdk-dev/classes.cs
    -deleted file mode 100644
    -index 007b57e..0000000
    ---- a/tools/droiddoc/templates-sdk-dev/classes.cs
    -+++ /dev/null
    -@@ -1,69 +0,0 @@
    --<?cs # THIS CREATES A LIST OF ALL PACKAGES AND NAMES IT packages.html ?>
    --<?cs include:"macros.cs" ?>
    --<?cs include:"macros_override.cs" ?>
    --<?cs include:"doctype.cs" ?>
    --<html<?cs if:devsite ?> devsite<?cs /if ?>>
    --<?cs include:"head_tag.cs" ?>
    --<?cs include:"body_tag.cs" ?>
    --<?cs include:"header.cs" ?>
    --
    --<h1><?cs var:page.title ?></h1>
    --<p>These are the API classes. See all
    --<a href="packages.html">API packages</a>.</p>
    --
    --<div class="jd-letterlist"><?cs
    --  each:letter=docs.classes ?>
    --    <a href="#letter_<?cs name:letter ?>"><?cs
    --      name:letter ?></a>&nbsp;&nbsp;<?cs
    --  /each?>
    --</div>
    --
    --<?cs each:letter=docs.classes ?>
    --<?cs set:count = #1 ?>
    --<h2 id="letter_<?cs name:letter ?>"><?cs name:letter ?></h2>
    --<table>
    --    <?cs set:cur_row = #0 ?>
    --    <?cs each:cl = letter ?>
    --        <tr class="<?cs if:count % #2 ?>alt-color<?cs /if ?> api apilevel-<?cs var:cl.since ?>" >
    --            <td class="jd-linkcol"><?cs call:type_link(cl.type) ?></td>
    --            <td class="jd-descrcol" width="100%">
    --              <?cs call:short_descr(cl) ?>&nbsp;
    --              <?cs call:show_annotations_list(cl) ?>
    --            </td>
    --        </tr>
    --    <?cs set:count = count + #1 ?>
    --    <?cs /each ?>
    --</table>
    --<?cs /each ?>
    --
    --<?cs if:devsite ?>
    --<div class="data-reference-resources-wrapper">
    --  <?cs if:subcount(class.package) ?>
    --  <ul data-reference-resources>
    --    <?cs call:list("Annotations", class.package.annotations) ?>
    --    <?cs call:list("Interfaces", class.package.interfaces) ?>
    --    <?cs call:list("Classes", class.package.classes) ?>
    --    <?cs call:list("Enums", class.package.enums) ?>
    --    <?cs call:list("Exceptions", class.package.exceptions) ?>
    --    <?cs call:list("Errors", class.package.errors) ?>
    --  </ul>
    --  <?cs elif:subcount(package) ?>
    --  <ul data-reference-resources>
    --    <?cs call:class_link_list("Annotations", package.annotations) ?>
    --    <?cs call:class_link_list("Interfaces", package.interfaces) ?>
    --    <?cs call:class_link_list("Classes", package.classes) ?>
    --    <?cs call:class_link_list("Enums", package.enums) ?>
    --    <?cs call:class_link_list("Exceptions", package.exceptions) ?>
    --    <?cs call:class_link_list("Errors", package.errors) ?>
    --  </ul>
    --  <?cs /if ?>
    --</div>
    --<?cs /if ?>
    --
    --
    --<?cs if:!devsite ?>
    --<?cs include:"footer.cs" ?>
    --<?cs include:"trailer.cs" ?>
    --<?cs /if ?>
    --</body>
    --</html>
    -diff --git a/tools/droiddoc/templates-sdk-dev/components/masthead.cs b/tools/droiddoc/templates-sdk-dev/components/masthead.cs
    -deleted file mode 100644
    -index 1fef965..0000000
    ---- a/tools/droiddoc/templates-sdk-dev/components/masthead.cs
    -+++ /dev/null
    -@@ -1,322 +0,0 @@
    --<?cs def:custom_masthead() ?>
    --  <a name="top"></a>
    --  <!-- Header -->
    --  <div id="header-wrapper">
    --    <div class="dac-header <?cs if:ndk ?>dac-ndk<?cs /if ?>" id="header">
    --      <div class="dac-header-inner">
    --        <a class="dac-nav-toggle" data-dac-toggle-nav href="javascript:;" title="Open navigation">
    --          <span class="dac-nav-hamburger">
    --            <span class="dac-nav-hamburger-top"></span>
    --            <span class="dac-nav-hamburger-mid"></span>
    --            <span class="dac-nav-hamburger-bot"></span>
    --          </span>
    --        </a>
    --        <?cs if:ndk ?><a class="dac-header-logo" style="width:144px;" href="<?cs var:toroot
    --        ?>ndk/index.html">
    --          <img class="dac-header-logo-image" src="<?cs var:toroot ?>assets/images/android_logo.png"
    --              srcset="<?cs var:toroot ?>assets/images/android_logo@2x.png 2x"
    --              width="32" height="36" alt="Android" /> NDK
    --          </a><?cs else ?><a class="dac-header-logo" href="<?cs var:toroot ?>index.html">
    --          <img class="dac-header-logo-image" src="<?cs var:toroot ?>assets/images/android_logo.png"
    --              srcset="<?cs var:toroot ?>assets/images/android_logo@2x.png 2x"
    --              width="32" height="36" alt="Android" /> Developers
    --          </a><?cs /if ?>
    --
    --        <?cs if:ndk
    --        ?><ul class="dac-header-tabs">
    --          <li>
    --            <a href="<?cs var:toroot ?>ndk/guides/index.html" class="dac-header-tab"
    --            zh-tw-lang="API 指南"
    --            zh-cn-lang="API 指南"
    --            ru-lang="Руководства по API"
    --            ko-lang="API 가이드"
    --            ja-lang="API ガイド"
    --            es-lang="Guías de la API">Guides</a>
    --          </li>
    --          <li>
    --            <a href="<?cs var:toroot ?>ndk/reference/index.html" class="dac-header-tab"
    --            zh-tw-lang="參考資源"
    --            zh-cn-lang="参考"
    --            ru-lang="Справочник"
    --            ko-lang="참조문서"
    --            ja-lang="リファレンス"
    --            es-lang="Referencia">Reference</a>
    --          </li>
    --          <li>
    --            <a href="<?cs var:toroot ?>ndk/samples/index.html" class="dac-header-tab"
    --           >Samples</a>
    --          </li>
    --          <li>
    --            <a href="<?cs var:toroot ?>ndk/downloads/index.html" class="dac-header-tab"
    --            >Downloads</a>
    --          </li>
    --        </ul><?cs else
    --        ?><?cs
    --        #
    --        # For the reference only docs, include just one tab
    --        #
    --        ?><?cs if:referenceonly
    --          ?><ul class="dac-header-tabs">
    --            <li><a href="<?cs var:toroot ?>reference/packages.html" class="dac-header-tab"><?cs
    --              if:sdk.preview
    --                ?>Android <?cs var:sdk.codename ?>
    --                  Preview <?cs var:sdk.preview.version ?><?cs
    --              else
    --                ?>Android <?cs var:sdk.version ?>
    --                  r<?cs var:sdk.rel.id ?><?cs
    --              /if ?></a>
    --            </li>
    --          </ul>
    --        <?cs else ?><?cs
    --        #
    --        # End reference only docs, now the online DAC tabs...
    --        #
    --        ?><ul class="dac-header-tabs">
    --          <li>
    --          <a class="dac-header-tab" href="<?cs var:toroot ?>design/index.html"
    --             zh-tw-lang="設計"
    --             zh-cn-lang="设计"
    --             ru-lang="Проектирование"
    --             ko-lang="디자인"
    --             ja-lang="設計"
    --             es-lang="Diseñar">Design</a>
    --          </li>
    --          <li>
    --          <a class="dac-header-tab" href="<?cs var:toroot ?>develop/index.html"
    --             zh-tw-lang="開發"
    --             zh-cn-lang="开发"
    --             ru-lang="Разработка"
    --             ko-lang="개발"
    --             ja-lang="開発"
    --             es-lang="Desarrollar">Develop</a>
    --          </li>
    --          <li>
    --          <a class="dac-header-tab" href="<?cs var:toroot ?>distribute/index.html"
    --             zh-tw-lang="發佈"
    --             zh-cn-lang="分发"
    --             ru-lang="Распространение"
    --             ko-lang="배포"
    --             ja-lang="配布"
    --             es-lang="Distribuir">Distribute</a>
    --          </li>
    --        </ul><?cs
    --        /if ?><?cs
    --        #
    --        # End if/else reference only docs
    --        #
    --        ?><?cs
    --        /if ?><?cs # end if/else ndk ?>
    --
    --        <?cs if:ndk ?><a class="dac-header-console-btn" href="http://developer.android.com">
    --          Back to Android Developers
    --        </a><?cs else ?><a class="dac-header-console-btn" href="https://play.google.com/apps/publish/">
    --          <span class="dac-sprite dac-google-play"></span>
    --          <span class="dac-visible-desktop-inline">Developer</span>
    --          Console
    --        </a><?cs /if ?><?cs
    --
    --        # ADD SEARCH AND MENU ?><?cs
    --        if:!ndk ?><?cs
    --          if:!referenceonly ?><?cs
    --            call:header_search_widget() ?><?cs
    --          /if ?><?cs
    --        /if ?>
    --      </div><!-- end header-wrap.wrap -->
    --    </div><!-- end header -->
    --  </div> <!--end header-wrapper -->
    --
    --  <?cs if:ndk ?>
    --  <!-- NDK Navigation-->
    --  <nav class="dac-nav">
    --    <div class="dac-nav-dimmer" data-dac-toggle-nav></div>
    --
    --    <div class="dac-nav-sidebar" data-swap data-dynamic="false" data-transition-speed="300" data-dac-nav>
    --                   <div data-swap-container>
    --        <?cs call:custom_left_nav() ?>
    --      <ul id="dac-main-navigation" class="dac-nav-list dac-swap-section dac-left dac-no-anim">
    --      <li class="dac-nav-item guides">
    --        <a class="dac-nav-link" href="<?cs var:toroot ?>ndk/guides/index.html"
    --           zh-tw-lang="API 指南"
    --           zh-cn-lang="API 指南"
    --           ru-lang="Руководства по API"
    --           ko-lang="API 가이드"
    --           ja-lang="API ガイド"
    --           es-lang="Guías de la API">Guides</a>
    --      </li>
    --      <li class="dac-nav-item reference">
    --        <a class="dac-nav-link" href="<?cs var:toroot ?>ndk/reference/index.html"
    --           zh-tw-lang="參考資源"
    --           zh-cn-lang="参考"
    --           ru-lang="Справочник"
    --           ko-lang="참조문서"
    --           ja-lang="リファレンス"
    --           es-lang="Referencia">Reference</a>
    --      </li>
    --      <li class="dac-nav-item samples">
    --        <a class="dac-nav-link" href="<?cs var:toroot ?>ndk/samples/index.html"
    --           >Samples</a>
    --      </li>
    --      <li class="dac-nav-item downloads">
    --        <a class="dac-nav-link" href="<?cs var:toroot ?>ndk/downloads/index.html"
    --           >Downloads</a>
    --      </li>
    --      </ul>
    --    </div>
    --                       </div>
    --  </nav>
    --  <!-- end NDK navigation-->
    --
    --
    --
    --  <?cs else ?>
    --  <!-- Navigation-->
    --  <nav class="dac-nav">
    --    <div class="dac-nav-dimmer" data-dac-toggle-nav></div>
    --
    --    <div class="dac-nav-sidebar" data-swap data-dynamic="false" data-transition-speed="300" data-dac-nav>
    --      <div <?cs if:!referenceonly ?>data-swap-container<?cs /if ?>>
    --        <?cs call:custom_left_nav() ?>
    --        <?cs if:!referenceonly ?>
    --        <ul id="dac-main-navigation" class="dac-nav-list dac-swap-section dac-left dac-no-anim">
    --        <li class="dac-nav-item home">
    --          <a class="dac-nav-link" href="<?cs var:toroot ?>index.html">Home</a>
    --          <i class="dac-sprite dac-expand-more-black dac-nav-sub-slider"></i>
    --          <ul class="dac-nav-secondary about">
    --            <li class="dac-nav-item versions">
    --              <a class="dac-nav-link" href="<?cs var:toroot ?>about/versions/nougat/index.html">Android</a>
    --            </li>
    --            <li class="dac-nav-item wear">
    --              <a class="dac-nav-link" href="<?cs var:toroot ?>wear/index.html">Wear</a>
    --            </li>
    --            <li class="dac-nav-item tv">
    --              <a class="dac-nav-link" href="<?cs var:toroot ?>tv/index.html">TV</a>
    --            </li>
    --            <li class="dac-nav-item auto">
    --              <a class="dac-nav-link" href="<?cs var:toroot ?>auto/index.html">Auto</a>
    --            </li>
    --          </ul>
    --        </li>
    --        <li class="dac-nav-item design">
    --          <a class="dac-nav-link" href="<?cs var:toroot ?>design/index.html"
    --             zh-tw-lang="設計"
    --             zh-cn-lang="设计"
    --             ru-lang="Проектирование"
    --             ko-lang="디자인"
    --             ja-lang="設計"
    --             es-lang="Diseñar">Design</a>
    --        </li>
    --        <li class="dac-nav-item develop">
    --          <a class="dac-nav-link" href="<?cs var:toroot ?>develop/index.html"
    --             zh-tw-lang="開發"
    --             zh-cn-lang="开发"
    --             ru-lang="Разработка"
    --             ko-lang="개발"
    --             ja-lang="開発"
    --             es-lang="Desarrollar">Develop</a>
    --          <i class="dac-sprite dac-expand-more-black dac-nav-sub-slider"></i>
    --          <ul class="dac-nav-secondary develop">
    --            <li class="dac-nav-item training">
    --              <a class="dac-nav-link" href="<?cs var:toroot ?>training/index.html"
    --                 zh-tw-lang="訓練課程"
    --                 zh-cn-lang="培训"
    --                 ru-lang="Курсы"
    --                 ko-lang="교육"
    --                 ja-lang="トレーニング"
    --                 es-lang="Capacitación">Training</a>
    --            </li>
    --            <li class="dac-nav-item guide">
    --              <a class="dac-nav-link" href="<?cs var:toroot ?>guide/index.html"
    --                 zh-tw-lang="API 指南"
    --                 zh-cn-lang="API 指南"
    --                 ru-lang="Руководства по API"
    --                 ko-lang="API 가이드"
    --                 ja-lang="API ガイド"
    --                 es-lang="Guías de la API">API Guides</a>
    --            </li>
    --            <li class="dac-nav-item reference">
    --              <a class="dac-nav-link" href="<?cs var:toroot ?>reference/packages.html"
    --                 zh-tw-lang="參考資源"
    --                 zh-cn-lang="参考"
    --                 ru-lang="Справочник"
    --                 ko-lang="참조문서"
    --                 ja-lang="リファレンス"
    --                 es-lang="Referencia">Reference</a>
    --            </li>
    --            <li class="dac-nav-item tools">
    --              <a class="dac-nav-link" href="<?cs var:toroot ?>sdk/index.html"
    --                 zh-tw-lang="相關工具"
    --                 zh-cn-lang="工具"
    --                 ru-lang="Инструменты"
    --                 ko-lang="도구"
    --                 ja-lang="ツール"
    --                 es-lang="Herramientas">Tools</a></li>
    --            <li class="dac-nav-item google">
    --              <a class="dac-nav-link" href="<?cs var:toroot ?>google/index.html">Google Services</a>
    --            </li>
    --            <?cs if:android.hasSamples ?>
    --            <li class="dac-nav-item samples">
    --              <a class="dac-nav-link" href="<?cs var:toroot ?>samples/index.html">Samples</a>
    --            </li>
    --            <?cs /if ?>
    --          </ul>
    --        </li>
    --        <li class="dac-nav-item distribute">
    --          <a class="dac-nav-link" href="<?cs var:toroot ?>distribute/<?cs if:android.whichdoc == 'offline' ?>googleplay/<?cs /if ?>index.html"
    --             zh-tw-lang="發佈"
    --             zh-cn-lang="分发"
    --             ru-lang="Распространение"
    --             ko-lang="배포"
    --             ja-lang="配布"
    --             es-lang="Distribuir">Distribute</a>
    --          <i class="dac-sprite dac-expand-more-black dac-nav-sub-slider"></i>
    --          <ul class="dac-nav-secondary distribute">
    --            <li class="dac-nav-item googleplay">
    --              <a class="dac-nav-link" href="<?cs var:toroot ?>distribute/googleplay/index.html">Google Play</a></li>
    --            <li class="dac-nav-item essentials">
    --              <a class="dac-nav-link" href="<?cs var:toroot ?>distribute/essentials/index.html">Essentials</a></li>
    --            <li class="dac-nav-item users">
    --              <a class="dac-nav-link" href="<?cs var:toroot ?>distribute/users/index.html">Get Users</a></li>
    --            <li class="dac-nav-item engage">
    --              <a class="dac-nav-link" href="<?cs var:toroot ?>distribute/engage/index.html">Engage &amp; Retain</a></li>
    --            <li class="dac-nav-item monetize">
    --              <a class="dac-nav-link" href="<?cs var:toroot ?>distribute/monetize/index.html">Earn</a>
    --            </li>
    --            <li class="dac-nav-item analyze">
    --              <a class="dac-nav-link" href="<?cs var:toroot ?>distribute/analyze/index.html">Analyze</a>
    --            </li>
    --            <li class="dac-nav-item stories">
    --              <a class="dac-nav-link" href="<?cs var:toroot ?>distribute/stories/index.html">Stories</a>
    --            </li>
    --          </ul>
    --        </li>
    --        <!--<li class="dac-nav-item preview">
    --          <a class="dac-nav-link" href="<?cs var:toroot ?>preview/index.html">Preview</a>
    --        </li>-->
    --        </ul>
    --        <?cs /if ?><?cs # end if referenceonly ?>
    --      </div>
    --    </div>
    --  </nav>
    --  <!-- end navigation-->
    --  <?cs /if ?>
    --
    --<!-- Nav Setup -->
    --<script>$('[data-dac-nav]').dacNav();</script>
    --
    --<?cs
    --/def ?><?cs # end custom_masthead() ?><?cs
    --
    --def:toast() ?><?cs
    --
    --# (UN)COMMENT TO TOGGLE VISIBILITY
    --
    --  <div class="dac-toast-group">
    --    <div class="dac-toast" data-toast>
    --      <div class="dac-toast-wrap">
    --        This is a demo notification <a href="#">Learn more</a>.
    --      </div>
    --    </div>
    --  </div>
    --
    --?><?cs
    --/def ?>
    -\ No newline at end of file
    -diff --git a/tools/droiddoc/templates-sdk-dev/customizations.cs b/tools/droiddoc/templates-sdk-dev/customizations.cs
    -deleted file mode 100644
    -index 0b938ac..0000000
    ---- a/tools/droiddoc/templates-sdk-dev/customizations.cs
    -+++ /dev/null
    -@@ -1,248 +0,0 @@
    --<?cs def:body_content_wrap_start() ?>
    --  <div class="wrap clearfix" id="body-content">
    --<?cs /def ?><?cs
    --
    --def:fullpage() ?>
    --  <div id="body-content">
    --    <div>
    --<?cs /def ?><?cs
    --
    --# The default side navigation for the reference docs ?><?cs
    --def:reference_default_nav() ?>
    --  <!-- Fullscreen toggler -->
    --  <button data-fullscreen class="dac-nav-fullscreen">
    --    <i class="dac-sprite dac-fullscreen"></i>
    --  </button>
    --
    --  <script>$('[data-fullscreen]').dacFullscreen();</script>
    --  <!-- End: Fullscreen toggler -->
    --
    --  <?cs if:reference.gcm || reference.gms ?>
    --    <?cs include:"../../../../frameworks/base/docs/html/google/google_toc.cs" ?>
    --    <script type="text/javascript">
    --      showGoogleRefTree();
    --    </script>
    --  <?cs else ?>
    --    <div id="devdoc-nav">
    --      <div id="api-nav-header">
    --        <div id="api-level-toggle">
    --          <label for="apiLevelCheckbox" class="disabled"
    --                 title="Select your target API level to dim unavailable APIs">API level: </label>
    --          <div class="select-wrapper">
    --            <select id="apiLevelSelector">
    --              <!-- option elements added by buildApiLevelSelector() -->
    --            </select>
    --          </div>
    --        </div><!-- end toggle -->
    --        <div id="api-nav-title">Android APIs</div>
    --      </div><!-- end nav header -->
    --      <script>
    --        var SINCE_DATA = [ <?cs
    --          each:since = since ?>'<?cs
    --            var:since.name ?>'<?cs
    --            if:!last(since) ?>, <?cs /if ?><?cs
    --            /each
    --          ?> ];
    --        buildApiLevelSelector();
    --      </script>
    --
    --      <div class="dac-reference-nav" data-reference-tree>
    --        <ul class="dac-reference-nav-list" data-reference-namespaces>
    --          <?cs call:package_link_list(docs.packages) ?>
    --        </ul>
    --
    --        <?cs if:subcount(class.package) ?>
    --        <ul data-reference-resources>
    --          <?cs call:list("Annotations", class.package.annotations) ?>
    --          <?cs call:list("Interfaces", class.package.interfaces) ?>
    --          <?cs call:list("Classes", class.package.classes) ?>
    --          <?cs call:list("Enums", class.package.enums) ?>
    --          <?cs call:list("Exceptions", class.package.exceptions) ?>
    --          <?cs call:list("Errors", class.package.errors) ?>
    --        </ul>
    --        <?cs elif:subcount(package) ?>
    --        <ul data-reference-resources>
    --          <?cs call:class_link_list("Annotations", package.annotations) ?>
    --          <?cs call:class_link_list("Interfaces", package.interfaces) ?>
    --          <?cs call:class_link_list("Classes", package.classes) ?>
    --          <?cs call:class_link_list("Enums", package.enums) ?>
    --          <?cs call:class_link_list("Exceptions", package.exceptions) ?>
    --          <?cs call:class_link_list("Errors", package.errors) ?>
    --        </ul>
    --        <?cs /if ?>
    --      </div>
    --    </div>
    --  <?cs /if ?>
    --<?cs /def ?><?cs
    --
    --def:ndk_nav() ?>
    --  <div class="wrap clearfix" id="body-content"><div class="cols">
    --    <div class="col-3 dac-toggle dac-mobile" id="side-nav" itemscope itemtype="http://schema.org/SiteNavigationElement">
    --      <?cs call:mobile_nav_toggle() ?>
    --      <div class="dac-toggle-content" id="devdoc-nav">
    --        <div class="scroll-pane">
    --<?cs
    --if:guide ?><?cs include:"../../../../frameworks/base/docs/html/ndk/guides/guides_toc.cs" ?><?cs
    --elif:reference ?><?cs include:"../../../../frameworks/base/docs/html/ndk/reference/reference_toc.cs" ?><?cs
    --elif:downloads ?><?cs include:"../../../../frameworks/base/docs/html/ndk/downloads/downloads_toc.cs" ?><?cs
    --elif:samples ?><?cs include:"../../../../frameworks/base/docs/html/ndk/samples/samples_toc.cs" ?><?cs
    --/if ?>
    --        </div>
    --      </div>
    --    </div> <!-- end side-nav -->
    --<?cs /def ?><?cs
    --
    --def:header_search_widget() ?>
    --  <form data-search class="dac-header-search">
    --    <button class="dac-header-search-close" data-search-close>
    --      <i class="dac-sprite dac-back-arrow"></i>
    --    </button>
    --
    --    <div class="dac-header-search-inner">
    --      <i class="dac-sprite dac-search-white dac-header-search-icon"></i>
    --      <input id="search_autocomplete" type="text" value="" autocomplete="off" name="q" class="dac-header-search-input" placeholder="Search" />
    --      <button class="dac-header-search-clear dac-hidden" data-search-clear>
    --        <i class="dac-sprite dac-close-black"></i>
    --      </button>
    --    </div>
    --  </form>
    --<?cs /def ?><?cs
    --
    --def:search_results() ?>
    --  <div id="search-results" class="dac-search-results">
    --    <div id="dac-search-results-history" class="dac-search-results-history">
    --      <div class="wrap dac-search-results-history-wrap">
    --        <div class="cols">
    --          <div class="col-1of2 col-tablet-1of2 col-mobile-1of1">
    --            <h2>Most visited</h2>
    --            <div class="resource-flow-layout" data-history-query="history:most/visited" data-maxresults="3" data-cardsizes="18x2"></div>
    --          </div>
    --
    --          <div class="col-1of2 col-tablet-1of2 col-mobile-1of1">
    --            <h2>Recently visited</h2>
    --            <div class="resource-flow-layout cols" data-history-query="history:recent" data-allow-duplicates="true" data-maxresults="3" data-cardsizes="18x2"></div>
    --          </div>
    --        </div>
    --      </div>
    --    </div>
    --
    --    <div id="dac-search-results-content" class="dac-search-results-content">
    --      <div class="dac-search-results-metadata wrap">
    --        <div class="dac-search-results-for">
    --          <h2>Results for <span id="search-results-for"></span></h2>
    --        </div>
    --
    --        <div id="dac-search-results-hero"></div>
    --
    --        <div class="dac-search-results-hero cols">
    --          <div id="dac-search-results-reference" class="col-3of6 col-tablet-1of2 col-mobile-1of1">
    --            <div class="suggest-card reference no-display">
    --              <ul class="dac-search-results-reference">
    --              </ul>
    --            </div>
    --          </div>
    --          <div id="dac-custom-search-results"></div>
    --        </div>
    --      </div>
    --
    --    </div>
    --  </div>
    --<?cs /def ?><?cs
    --
    --def:custom_left_nav() ?>
    --  <?cs if:(!fullpage && !nonavpage) || forcelocalnav ?>
    --    <?cs if:!referenceonly ?>
    --    <a class="dac-nav-back-button dac-swap-section dac-up dac-no-anim" data-swap-button href="javascript:;">
    --      <i class="dac-sprite dac-nav-back"></i> <span class="dac-nav-back-title">Back</span>
    --    </a>
    --    <?cs /if ?>
    --    <div class="dac-nav-sub dac-swap-section dac-right dac-active" itemscope
    --      itemtype="http://schema.org/SiteNavigationElement" <?cs
    --        if:referenceonly ?>style="top:0 !important;"<?cs /if ?>>
    --      <?cs if:ndk ?>
    --        <?cs if:guide ?>
    --          <?cs include:"../../../../frameworks/base/docs/html/ndk/guides/guides_toc.cs" ?>
    --        <?cs elif:reference ?>
    --          <?cs include:"../../../../frameworks/base/docs/html/ndk/reference/reference_toc.cs" ?>
    --        <?cs elif:downloads ?>
    --          <?cs include:"../../../../frameworks/base/docs/html/ndk/downloads/downloads_toc.cs" ?>
    --        <?cs elif:samples ?>
    --          <?cs include:"../../../../frameworks/base/docs/html/ndk/samples/samples_toc.cs" ?>
    --        <?cs else ?>
    --          <?cs call:reference_default_nav() ?>
    --        <?cs /if ?>
    --      <?cs elif:guide ?>
    --        <?cs include:"../../../../frameworks/base/docs/html/guide/guide_toc.cs" ?>
    --      <?cs elif:design ?>
    --        <?cs include:"../../../../frameworks/base/docs/html/design/design_toc.cs" ?>
    --      <?cs elif:training ?>
    --        <?cs include:"../../../../frameworks/base/docs/html/training/training_toc.cs" ?>
    --      <?cs elif:tools ?>
    --        <?cs include:"../../../../frameworks/base/docs/html/tools/tools_toc.cs" ?>
    --      <?cs elif:google ?>
    --        <?cs include:"../../../../frameworks/base/docs/html/google/google_toc.cs" ?>
    --      <?cs elif:samples ?>
    --        <?cs include:"../../../../frameworks/base/docs/html/samples/samples_toc.cs" ?>
    --      <?cs elif:preview ?>
    --        <?cs include:"../../../../frameworks/base/docs/html/preview/preview_toc.cs" ?>
    --      <?cs elif:preview ?>
    --        <?cs include:"../../../../frameworks/base/docs/html/wear/preview/preview_toc.cs" ?>
    --      <?cs elif:distribute ?>
    --        <?cs if:googleplay ?>
    --          <?cs include:"../../../../frameworks/base/docs/html/distribute/googleplay/googleplay_toc.cs" ?>
    --        <?cs elif:essentials ?>
    --          <?cs include:"../../../../frameworks/base/docs/html/distribute/essentials/essentials_toc.cs" ?>
    --        <?cs elif:users ?>
    --          <?cs include:"../../../../frameworks/base/docs/html/distribute/users/users_toc.cs" ?>
    --        <?cs elif:engage ?>
    --          <?cs include:"../../../../frameworks/base/docs/html/distribute/engage/engage_toc.cs" ?>
    --        <?cs elif:monetize ?>
    --          <?cs include:"../../../../frameworks/base/docs/html/distribute/monetize/monetize_toc.cs" ?>
    --        <?cs elif:analyze ?>
    --          <?cs include:"../../../../frameworks/base/docs/html/distribute/analyze/analyze_toc.cs" ?>
    --        <?cs elif:disttools ?>
    --          <?cs include:"../../../../frameworks/base/docs/html/distribute/tools/disttools_toc.cs" ?>
    --        <?cs elif:stories ?>
    --          <?cs include:"../../../../frameworks/base/docs/html/distribute/stories/stories_toc.cs" ?>
    --        <?cs /if ?>
    --      <?cs elif:about ?>
    --        <?cs include:"../../../../frameworks/base/docs/html/about/about_toc.cs" ?>
    --      <?cs else ?>
    --        <?cs call:reference_default_nav() ?>
    --      <?cs /if ?>
    --    </div>
    --  <?cs /if ?>
    --<?cs /def ?><?cs
    --
    --# appears at the bottom of every page ?><?cs
    --def:custom_cc_copyright() ?>
    --  Except as noted, this content is
    --  licensed under <a href="http://creativecommons.org/licenses/by/2.5/">
    --  Creative Commons Attribution 2.5</a>. For details and
    --  restrictions, see the <a href="<?cs var:toroot ?>license.html">Content
    --  License</a>.
    --<?cs /def ?><?cs
    --
    --def:custom_copyright() ?>
    --  Except as noted, this content is licensed under <a
    --  href="http://www.apache.org/licenses/LICENSE-2.0">Apache 2.0</a>.
    --  For details and restrictions, see the <a href="<?cs var:toroot ?>license.html">
    --  Content License</a>.
    --<?cs /def ?><?cs
    --
    --def:custom_footerlinks() ?>
    --  <a href="<?cs var:toroot ?>about/android.html">About Android</a>
    --  <a href="<?cs var:toroot ?>auto/index.html">Auto</a>
    --  <a href="<?cs var:toroot ?>tv/index.html">TV</a>
    --  <a href="<?cs var:toroot ?>wear/index.html">Wear</a>
    --  <a href="<?cs var:toroot ?>legal.html">Legal</a>
    --<?cs /def ?><?cs
    --
    --# appears on the right side of the blue bar at the bottom off every page ?><?cs
    --def:custom_buildinfo() ?>
    --  <?cs if:!google && !reference.gcm && !reference.gms ?>
    --    Android <?cs var:sdk.version ?>&nbsp;r<?cs var:sdk.rel.id ?> &mdash;
    --  <?cs /if ?>
    --  <script src="<?cs var:toroot ?>timestamp.js" type="text/javascript"></script>
    --  <script>document.write(BUILD_TIMESTAMP)</script>
    --<?cs /def ?>
    -\ No newline at end of file
    -diff --git a/tools/droiddoc/templates-sdk-dev/data.hdf b/tools/droiddoc/templates-sdk-dev/data.hdf
    -deleted file mode 100644
    -index 9411b78..0000000
    ---- a/tools/droiddoc/templates-sdk-dev/data.hdf
    -+++ /dev/null
    -@@ -1,4 +0,0 @@
    --template {
    --    which = normal
    --}
    --
    -diff --git a/tools/droiddoc/templates-sdk-dev/designpage.cs b/tools/droiddoc/templates-sdk-dev/designpage.cs
    -deleted file mode 100644
    -index d75ce0a..0000000
    ---- a/tools/droiddoc/templates-sdk-dev/designpage.cs
    -+++ /dev/null
    -@@ -1,104 +0,0 @@
    --<!DOCTYPE html>
    --<?cs include:"macros.cs" ?>
    --<html lang="en">
    --  <head>
    --    <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
    --    <title>
    --      Android Design<?cs if:page.title ?> - <?cs var:page.title ?><?cs /if ?>
    --    </title>
    --    <link rel="shortcut icon" type="image/x-icon" href="/favicon.ico">
    --    <link rel="stylesheet" href="http://fonts.googleapis.com/css?family=Roboto:regular,medium,thin,italic,mediumitalic">
    --    <link rel="stylesheet" href="<?cs var:toroot ?>assets/yui-3.3.0-reset-min.css">
    --    <link rel="stylesheet" href="<?cs var:toroot ?>assets/design/default.css">
    --    <script src="<?cs var:toroot ?>assets/jquery-1.6.2.min.js"></script>
    --    <script>var SITE_ROOT = '<?cs var:toroot ?>design';</script>
    --    <script src="<?cs var:toroot ?>assets/design/default.js"></script>
    --  </head>
    --  <body class="gc-documentation 
    --    <?cs if:(guide||develop||training||reference||tools||sdk) ?>develop<?cs
    --    elif:design ?>design<?cs
    --    elif:distribute ?>distribute<?cs
    --    /if ?>" itemscope itemtype="http://schema.org/Article">
    --    <a name="top"></a>
    --
    --    <div id="page-container">
    --
    --      <div id="page-header" itemscope itemtype="http://schema.org/WPHeader"><a href="<?cs var:toroot ?>design/index.html">Android Design</a></div>
    --
    --      <div id="main-row">
    --
    --        <div id="nav-container" itemscope itemtype="http://schema.org/SiteNavigationElement">
    --
    --        <?cs call:design_nav() ?>
    --
    --        </div>
    --
    --        <div id="content">
    --
    --<?cs if:header.hide ?>
    --<?cs else ?>
    --<div class="content-header <?cs if:header.justLinks ?>just-links<?cs /if ?>">
    --    <?cs if:header.justLinks ?>&nbsp;
    --      <?cs elif:header.title ?><h2><?cs var:header.title ?></h2>
    --                   <?cs else ?><h2><?cs var:page.title ?></h2>
    --    <?cs /if ?>
    --</div>
    --<?cs /if ?>
    --
    --<?cs call:tag_list(root.descr) ?>
    --
    --<?cs if:footer.hide ?>
    --<?cs else ?>
    --<div class="cols content-footer" itemscope itemtype="http://schema.org/SiteNavigationElement">
    --  <div class="paging-links col-9">&nbsp;</div>
    --  <div class="paging-links col-4">
    --    <a href="#" class="prev-page-link">Previous</a>
    --    <a href="#" class="next-page-link">Next</a>
    --  </div>
    --</div>
    --<?cs /if ?>
    --
    --        </div>
    --
    --      </div>
    --
    --      <div id="page-footer" itemscope itemtype="http://schema.org/WPFooter">
    --
    --        <p id="copyright">
    --          Except as noted, this content is licensed under
    --          <a href="http://creativecommons.org/licenses/by/2.5/">
    --          Creative Commons Attribution 2.5</a>.<br>
    --          For details and restrictions, see the
    --          <a href="http://developer.android.com/license.html">Content License</a>.
    --        </p>
    --
    --        <p>
    --          <a href="http://www.android.com/terms.html">Site Terms of Service</a> &ndash;
    --          <a href="http://www.android.com/privacy.html">Privacy Policy</a> &ndash;
    --          <a href="http://www.android.com/branding.html">Brand Guidelines</a>
    --        </p>
    --
    --      </div>
    --    </div>
    --
    --    <script type="text/javascript">
    --    var gaJsHost = (("https:" == document.location.protocol) ? "https://ssl." : "http://www.");
    --    document.write(unescape("%3Cscript src='" + gaJsHost + "google-analytics.com/ga.js' type='text/javascript'%3E%3C/script%3E"));
    --    </script>
    --    <script type="text/javascript">
    --    var pageTracker = _gat._getTracker("UA-5831155-1");
    --    pageTracker._trackPageview();
    --    </script>
    --
    --<!-- Start of Tag -->
    --<script type="text/javascript">
    --var axel = Math.random() + "";
    --var a = axel * 10000000000000;
    --document.write('<iframe src="https://2507573.fls.doubleclick.net/activityi;src=2507573;type=other026;cat=googl348;ord=' + a + '?" width="1" height="1" frameborder="0" style="display:none"></iframe>');
    --</script>
    --<noscript>
    --<iframe src="https://2507573.fls.doubleclick.net/activityi;src=2507573;type=other026;cat=googl348;ord=1?" width="1" height="1" frameborder="0" style="display:none"></iframe>
    --</noscript>
    --<!-- End of Tag -->
    --  </body>
    --</html>
    -diff --git a/tools/droiddoc/templates-sdk-dev/docpage.cs b/tools/droiddoc/templates-sdk-dev/docpage.cs
    -deleted file mode 100644
    -index e8a5ba3..0000000
    ---- a/tools/droiddoc/templates-sdk-dev/docpage.cs
    -+++ /dev/null
    -@@ -1,261 +0,0 @@
    --<?cs if:!devsite ?><?cs
    --  include:"doctype.cs" ?><?cs /if ?><?cs
    --  include:"macros.cs" ?><html<?cs if:devsite ?> devsite<?cs /if ?>>
    --<?cs include:"head_tag.cs" ?>
    --<body<?cs
    --if:!devsite ?> class="gc-documentation<?cs
    --# add document classes for navigation header selection (and other stuff) ?>
    --<?cs
    --  if:(google || reference.gms || reference.gcm) ?>google <?cs /if ?><?cs
    --  if:ndk ?>ndk<?cs
    --    if:guide ?> guide<?cs /if ?><?cs
    --    if:samples ?> samples<?cs /if ?><?cs
    --    if:reference ?> reference<?cs /if ?><?cs
    --    if:downloads ?> downloads<?cs /if ?><?cs
    --  else ?><?cs
    --    if:(guide||develop||training||reference||tools||sdk||google||samples) ?>develop<?cs
    --      if:guide ?> guide<?cs /if ?><?cs
    --      if:samples ?> samples<?cs /if ?><?cs
    --    elif:(distribute||googleplay||essentials||users||engage||monetize||disttools||stories||analyze) ?>distribute<?cs
    --      if:googleplay ?> googleplay<?cs /if ?><?cs
    --      if:essentials ?> essentials<?cs /if ?><?cs
    --      if:users ?> users<?cs /if ?><?cs
    --      if:engage ?> engage<?cs /if ?><?cs
    --      if:monetize ?> monetize<?cs /if ?><?cs
    --      if:disttools ?> disttools<?cs /if ?><?cs
    --      if:stories ?> stories<?cs /if ?><?cs
    --      if:analyze ?> analyze<?cs /if ?><?cs
    --    elif:(design||vision||material||patterns||devices||designdownloads) ?> design<?cs
    --      if:vision ?> vision<?cs /if ?><?cs
    --      if:material ?> material<?cs /if ?><?cs
    --      if:patterns ?> patterns<?cs /if ?><?cs
    --      if:devices ?> devices<?cs /if ?><?cs
    --      if:designdownloads ?> designdownloads<?cs /if ?><?cs
    --    elif:(about||versions||wear||tv||auto) ?> about<?cs
    --      if:versions ?> versions<?cs /if ?><?cs
    --      if:wear ?> wear<?cs /if ?><?cs
    --      if:tv ?> tv<?cs /if ?><?cs
    --      if:auto ?> auto<?cs /if ?><?cs
    --    elif:(preview) ?> preview<?cs
    --    /if ?><?cs
    --    if:page.trainingcourse ?> trainingcourse<?cs /if ?><?cs
    --  /if ?>" itemscope itemtype="http://schema.org/Article"><?cs
    --/if ?>><?cs
    --include:"header.cs" ?><?cs
    --
    --if:(design||training||walkthru) && !page.trainingcourse && !page.article ?><?cs
    --# header logic for docs that provide previous/next buttons ?><?cs
    --  if:(header.hide||devsite) ?><?cs
    --  else ?>
    --    <div class="content-header <?cs if:header.justLinks ?>just-links<?cs /if ?>">
    --      <?cs if:header.justLinks ?>&nbsp;
    --      <?cs else ?>
    --        <ul class="dac-header-crumbs">
    --          <?cs # More <li> elements added here with javascript ?>
    --        </ul>
    --
    --        <!-- Breadcrumb Setup -->
    --        <script>$('.dac-nav-list').dacCurrentPage().dacCrumbs();</script>
    --
    --        <h1 itemprop="name"><?cs var:page.title ?>
    --      </h1><?cs
    --      /if ?><?cs
    --      if:training ?>
    --      <div class="training-nav-top" itemscope itemtype="http://schema.org/SiteNavigationElement">
    --        <a href="#" class="prev-page-link hide"
    --            zh-tw-lang="上一堂課"
    --            zh-cn-lang="上一课"
    --            ru-lang="Предыдущий"
    --            ko-lang="이전"
    --            ja-lang="前へ"
    --            es-lang="Anterior"
    --            >Previous</a>
    --        <a href="#" class="next-page-link hide"
    --            zh-tw-lang="下一堂課"
    --            zh-cn-lang="下一课"
    --            ru-lang="Следующий"
    --            ko-lang="다음"
    --            ja-lang="次へ"
    --            es-lang="Siguiente"
    --            >Next</a>
    --        <a href="#" class="start-class-link hide"
    --            zh-tw-lang="開始上課"
    --            zh-cn-lang="开始"
    --            ru-lang="Начало работы"
    --            ko-lang="시작하기"
    --            ja-lang="開始する"
    --            es-lang="Empezar"
    --            >Get started</a>
    --      </div><?cs
    --      elif:!page.trainingcourse ?>
    --      <?cs # <div class="paging-linkss" itemscope itemtype="http://schema.org/SiteNavigationElement">
    --        <a href="#" class="prev-page-link hide"
    --            zh-tw-lang="上一堂課"
    --            zh-cn-lang="上一课"
    --            ru-lang="Предыдущий"
    --            ko-lang="이전"
    --            ja-lang="前へ"
    --            es-lang="Anterior"
    --            >Previous</a>
    --        <a href="#" class="next-page-link hide"
    --            zh-tw-lang="下一堂課"
    --            zh-cn-lang="下一课"
    --            ru-lang="Следующий"
    --            ko-lang="다음"
    --            ja-lang="次へ"
    --            es-lang="Siguiente"
    --            >Next</a>
    --      </div> ?><?cs
    --      /if ?><?cs # end if training ?>
    --  </div>
    --  <?cs /if ?><?cs # end if header.hide ?><?cs
    --
    --elif:samplesProjectIndex ?>
    --  <div id="api-info-block">
    --  <div class="sum-details-links">
    --  Overview
    --  &#124; <a href="<?cs var:toroot ?>samples/<?cs var:projectDir ?>/project.html">Project</a>
    --  &#124; <a href="<?cs var:toroot ?>downloads/samples/<?cs var:projectDir ?>.zip">Download</a>
    --  </div><!-- end sum-details-links -->
    --  </div><!-- end breadcurmb block -->
    --  <h1 itemprop="name"><?cs var:projectDir ?></h1>
    --
    --<?cs else ?><?cs
    --  if:(!fullpage && !header.hide && !devsite) ?><?cs
    --    if:page.landing ?><?cs # header logic for docs that are landing pages ?>
    --      <div class="landing-banner">
    --        <?cs if:page.landing.image ?><?cs # use two-column layout only if there is an image ?>
    --        <div class="cols">
    --          <div class="col-6">
    --            <img src="<?cs var:toroot ?><?cs var:page.landing.image ?>" alt="" />
    --          </div>
    --          <div class="col-6">
    --        <?cs /if ?>
    --          <h1 itemprop="name" style="margin-bottom:0;"><?cs var:page.title ?></h1>
    --          <p itemprop="description"><?cs var:page.landing.intro ?></p>
    --
    --          <p><a class="next-page-link topic-start-link"></a></p>
    --        <?cs if:page.landing.image ?>
    --          </div>
    --        </div>
    --        <?cs /if ?>
    --      </div>
    --    <?cs else ?><?cs
    --      if:tab1 ?><div id="title-tabs-wrapper"><?cs /if ?>
    --        <ul class="dac-header-crumbs">
    --          <?cs # More <li> elements added here with javascript ?>
    --        </ul>
    --
    --        <!-- Breadcrumb Setup -->
    --        <p><script>$('.dac-nav-list').dacCurrentPage().dacCrumbs();</script></p>
    --
    --        <h1 itemprop="name" <?cs if:tab1 ?>class="with-title-tabs"<?cs /if ?>><?cs var:page.title ?></h1><?cs
    --          if:tab1 ?><ul id="title-tabs">
    --              <li class="selected"><a href="<?cs var:tab1.link ?>"><?cs var:tab1 ?></a></li>
    --              <?cs if:tab2 ?>
    --              <li><a href="<?cs var:tab2.link ?>"><?cs var:tab2 ?></a></li><?cs /if ?>
    --              <?cs if:tab3 ?>
    --              <li><a href="<?cs var:tab3.link ?>"><?cs var:tab3 ?></a></li><?cs /if ?>
    --            </ul>
    --          <?cs /if ?>
    --      <?cs if:tab1 ?></div><!-- end tab-wrapper --><?cs /if ?><?cs
    --    /if ?><?cs
    --  /if ?><?cs
    --/if ?><?cs # end if design ?><?cs
    --
    --if devsite ?><?cs
    --  if:tab1 ?>
    --  <div id="title-tabs-wrapper">
    --    <ul id="title-tabs">
    --      <li class="selected"><a href="<?cs var:tab1.link ?>"><?cs var:tab1 ?></a></li>
    --      <?cs if:tab2 ?>
    --      <li><a href="<?cs var:tab2.link ?>"><?cs var:tab2 ?></a></li><?cs /if ?>
    --      <?cs if:tab3 ?>
    --      <li><a href="<?cs var:tab3.link ?>"><?cs var:tab3 ?></a></li><?cs /if ?>
    --    </ul>
    --  </div><!-- end tab-wrapper --><?cs
    --  /if ?><?cs
    --/if ?><?cs
    --
    --# THIS IS THE MAIN DOC CONTENT ?><?cs
    --  if:!devsite ?>
    --  <div id="jd-content">
    --    <div class="jd-descr" itemprop="articleBody"><?cs
    --  /if ?><?cs
    --  if:(!fullpage && !header.hide && devsite) ?><?cs
    --    if:page.landing ?><?cs # header logic for docs that are landing pages ?>
    --        <div class="landing-banner">
    --          <?cs if:page.landing.image ?><?cs # use two-column layout only if there is an image ?>
    --          <div class="cols">
    --            <div class="col-6">
    --              <img src="<?cs var:toroot ?><?cs var:page.landing.image ?>" alt="" />
    --            </div>
    --            <div class="col-6">
    --          <?cs /if ?>
    --            <h1 itemprop="name" style="margin-bottom:0;"><?cs var:page.title ?></h1>
    --            <p itemprop="description"><?cs var:page.landing.intro ?></p>
    --
    --            <p><a class="next-page-link topic-start-link"></a></p><?cs
    --            if:page.landing.image ?>
    --            </div>
    --          </div><?cs
    --          /if ?>
    --        </div><?cs
    --    /if ?><?cs
    --  /if ?>
    --
    --<?cs call:tag_list(root.descr) ?><?cs
    --
    --if:!devsite ?>
    --    </div><!-- end jd-descr --><?cs
    --/if ?><?cs
    --
    --if:!fullscreen && (design||training||walkthru) && !page.landing && !page.trainingcourse
    --      && !footer.hide && !devsite?>
    --      <div class="content-footer <?cs
    --                    if:fullpage ?>wrap<?cs /if ?>"
    --                    itemscope itemtype="http://schema.org/SiteNavigationElement">
    --          <div class="paging-links">
    --            <a href="#" class="prev-page-link hide"
    --              zh-tw-lang="上一堂課"
    --              zh-cn-lang="上一课"
    --              ru-lang="Предыдущий"
    --              ko-lang="이전"
    --              ja-lang="前へ"
    --              es-lang="Anterior"
    --              ><span class="page-link-caption">Previous</span>
    --            </a>
    --            <a href="#" class="next-page-link hide"
    --                zh-tw-lang="下一堂課"
    --                zh-cn-lang="下一课"
    --                ru-lang="Следующий"
    --                ko-lang="다음"
    --                ja-lang="次へ"
    --                es-lang="Siguiente"
    --                ><span class="page-link-caption">Next</span>
    --            </a>
    --            <a href="#" class="start-class-link hide"
    --                zh-tw-lang="開始上課"
    --                zh-cn-lang="开始"
    --                ru-lang="Начало работы"
    --                ko-lang="시작하기"
    --                ja-lang="開始する"
    --                es-lang="Empezar"
    --                >Get started</a>
    --            <a href="#" class="next-class-link hide">
    --              <span class="page-link-caption">Next class</span>
    --            </a>
    --          </div>
    --      </div><?cs
    --    /if ?><?cs
    --if:!devsite ?>
    --  </div> <!-- end jd-content --><?cs
    --/if ?><?cs
    --
    --if:!devsite ?>
    --<?cs include:"footer.cs" ?>
    --<?cs include:"trailer.cs" ?>
    --<?cs /if ?>
    --
    --</body>
    --</html>
    -diff --git a/tools/droiddoc/templates-sdk-dev/footer.cs b/tools/droiddoc/templates-sdk-dev/footer.cs
    -deleted file mode 100644
    -index af34a1a..0000000
    ---- a/tools/droiddoc/templates-sdk-dev/footer.cs
    -+++ /dev/null
    -@@ -1,219 +0,0 @@
    --<?cs # page footer content ?>
    --<div class="wrap">
    --  <div class="dac-footer<?cs if:fullpage ?> dac-landing<?cs /if ?>">
    --    <div class="cols dac-footer-main">
    --      <div class="col-1of2">
    --        <a class="dac-footer-getnews" id="newsletter" data-modal-toggle="newsletter" href="javascript:;">Get news &amp; tips <span
    --          class="dac-fab dac-primary"><i class="dac-sprite dac-mail"></i></span></a>
    --      </div>
    --      <div class="col-1of2 dac-footer-reachout">
    --        <div class="dac-footer-contact">
    --          <a class="dac-footer-contact-link" href="http://android-developers.blogspot.com/">Blog</a>
    --          <a class="dac-footer-contact-link" href="/support.html">Support</a>
    --        </div>
    --        <div class="dac-footer-social">
    --          <a class="dac-button-social dac-youtube dac-footer-social-link" href="https://www.youtube.com/user/androiddevelopers"><i class="dac-sprite dac-youtube"></i></a>
    --          <a class="dac-button-social dac-gplus dac-footer-social-link" href="https://plus.google.com/+AndroidDevelopers"><i class="dac-sprite dac-gplus"></i></a>
    --          <a class="dac-button-social dac-twitter dac-footer-social-link" href="https://twitter.com/AndroidDev"><i class="dac-sprite dac-twitter"></i></a>
    --        </div>
    --      </div>
    --    </div>
    --
    --    <hr class="dac-footer-separator"/>
    --
    --    <?cs if:reference ?>
    --      <p class="dac-footer-copyright">
    --        <?cs call:custom_copyright() ?>
    --      </p>
    --      <p class="dac-footer-build">
    --        <?cs call:custom_buildinfo() ?>
    --      </p>
    --    <?cs elif:!hide_license_footer ?>
    --      <p class="dac-footer-copyright">
    --        <?cs call:custom_cc_copyright() ?>
    --      </p>
    --    <?cs /if ?>
    --
    --    <p class="dac-footer-links">
    --      <a href="/about/android.html">About Android</a>
    --      <a href="/auto/index.html">Auto</a>
    --      <a href="/tv/index.html">TV</a>
    --      <a href="/wear/index.html">Wear</a>
    --      <a href="/legal.html">Legal</a>
    --
    --      <span id="language" class="locales">
    --        <select name="language" onchange="changeLangPref(this.value, true)">
    --          <option value="en" selected="selected">English</option>
    --          <option value="es">Español</option>
    --          <option value="in">Bahasa Indonesia</option>
    --          <option value="ja">日本語</option>
    --          <option value="ko">한국어</option>
    --          <option value="pt-br">Português Brasileiro</option>
    --          <option value="ru">Русский</option>
    --          <option value="vi">tiếng Việt</option>
    --          <option value="zh-cn">中文(简体)</option>
    --          <option value="zh-tw">中文(繁體)</option>
    --        </select>
    --      </span>
    --    </p>
    --  </div>
    --</div>
    --<!-- end footer -->
    --
    --<?cs call:toast() ?>
    --
    --<div data-modal="newsletter" data-newsletter data-swap class="dac-modal newsletter">
    --  <div class="dac-modal-container">
    --    <div class="dac-modal-window">
    --      <header class="dac-modal-header">
    --        <div class="dac-modal-header-actions">
    --          <button class="dac-modal-header-close" data-modal-toggle></button>
    --        </div>
    --        <div class="dac-swap" data-swap-container>
    --          <section class="dac-swap-section dac-active dac-down">
    --            <h2 class="norule dac-modal-header-title" data-t="newsletter.title"></h2>
    --            <p class="dac-modal-header-subtitle" data-t="newsletter.requiredHint"></p>
    --          </section>
    --          <section class="dac-swap-section dac-up">
    --            <h2 class="norule dac-modal-header-title" data-t="newsletter.successTitle">Hooray!</h2>
    --          </section>
    --        </div>
    --      </header>
    --      <div class="dac-swap" data-swap-container>
    --        <section class="dac-swap-section dac-active dac-left">
    --          <form action="https://docs.google.com/forms/d/1QgnkzbEJIDu9lMEea0mxqWrXUJu0oBCLD7ar23V0Yys/formResponse" class="dac-form" method="post" target="dac-newsletter-iframe">
    --            <input type="hidden" name="entry.935454734" data-newsletter-language>
    --            <section class="dac-modal-content">
    --              <fieldset class="dac-form-fieldset">
    --                <div class="cols">
    --                  <div class="col-1of2 newsletter-leftCol">
    --                    <div class="dac-form-input-group">
    --                      <label for="newsletter-full-name" class="dac-form-floatlabel" data-t="newsletter.name">Full name</label>
    --                      <input type="text" class="dac-form-input" name="entry.1357890476" id="newsletter-full-name" required>
    --                      <span class="dac-form-required">*</span>
    --                    </div>
    --                    <div class="dac-form-input-group">
    --                      <label for="newsletter-email" class="dac-form-floatlabel" data-t="newsletter.email">Email address</label>
    --                      <input type="email" class="dac-form-input" name="entry.472100832" id="newsletter-email" required>
    --                      <span class="dac-form-required">*</span>
    --                    </div>
    --                  </div>
    --                  <div class="col-1of2 newsletter-rightCol">
    --                    <div class="dac-form-input-group">
    --                      <label for="newsletter-company" class="dac-form-floatlabel" data-t="newsletter.company">Company / developer name</label>
    --                      <input type="text" class="dac-form-input" name="entry.1664780309" id="newsletter-company">
    --                    </div>
    --                    <div class="dac-form-input-group">
    --                      <label for="newsletter-play-store" class="dac-form-floatlabel" data-t="newsletter.appUrl">One of your Play Store app URLs</label>
    --                      <input type="url" class="dac-form-input" name="entry.47013838" id="newsletter-play-store" required>
    --                      <span class="dac-form-required">*</span>
    --                    </div>
    --                  </div>
    --                </div>
    --              </fieldset>
    --              <fieldset class="dac-form-fieldset">
    --                <div class="cols">
    --                  <div class="col-1of2 newsletter-leftCol">
    --                    <legend class="dac-form-legend"><span data-t="newsletter.business.label">Which best describes your business:</span><span class="dac-form-required">*</span>
    --                    </legend>
    --                    <div class="dac-form-radio-group">
    --                      <input type="radio" value="Apps" class="dac-form-radio" name="entry.1796324055" id="newsletter-business-type-app" required>
    --                      <label for="newsletter-business-type-app" class="dac-form-radio-button"></label>
    --                      <label for="newsletter-business-type-app" class="dac-form-label" data-t="newsletter.business.apps">Apps</label>
    --                    </div>
    --                    <div class="dac-form-radio-group">
    --                      <input type="radio" value="Games" class="dac-form-radio" name="entry.1796324055" id="newsletter-business-type-games" required>
    --                      <label for="newsletter-business-type-games" class="dac-form-radio-button"></label>
    --                      <label for="newsletter-business-type-games" class="dac-form-label" data-t="newsletter.business.games">Games</label>
    --                    </div>
    --                    <div class="dac-form-radio-group">
    --                      <input type="radio" value="Apps and Games" class="dac-form-radio" name="entry.1796324055" id="newsletter-business-type-appsgames" required>
    --                      <label for="newsletter-business-type-appsgames" class="dac-form-radio-button"></label>
    --                      <label for="newsletter-business-type-appsgames" class="dac-form-label" data-t="newsletter.business.both">Apps &amp; Games</label>
    --                    </div>
    --                  </div>
    --                  <div class="col-1of2 newsletter-rightCol newsletter-checkboxes">
    --                    <div class="dac-form-radio-group">
    --                      <div class="dac-media">
    --                        <div class="dac-media-figure">
    --                          <input type="checkbox" class="dac-form-checkbox" name="entry.732309842" id="newsletter-add" required value="Add me to the mailing list for the monthly newsletter and occasional emails about development and Google Play opportunities.">
    --                          <label for="newsletter-add" class="dac-form-checkbox-button"></label>
    --                        </div>
    --                        <div class="dac-media-body">
    --                          <label for="newsletter-add" class="dac-form-label dac-form-aside"><span data-t="newsletter.confirmMailingList"></span><span class="dac-form-required">*</span></label>
    --                        </div>
    --                      </div>
    --                    </div>
    --                    <div class="dac-form-radio-group">
    --                      <div class="dac-media">
    --                        <div class="dac-media-figure">
    --                          <input type="checkbox" class="dac-form-checkbox" name="entry.2045036090" id="newsletter-terms" required value="I acknowledge that the information provided in this form will be subject to Google's privacy policy (https://www.google.com/policies/privacy/).">
    --                          <label for="newsletter-terms" class="dac-form-checkbox-button"></label>
    --                        </div>
    --                        <div class="dac-media-body">
    --                          <label for="newsletter-terms" class="dac-form-label dac-form-aside"><span data-t="newsletter.privacyPolicy" data-t-html></span><span class="dac-form-required">*</span></label>
    --                        </div>
    --                      </div>
    --                    </div>
    --                  </div>
    --                </div>
    --              </fieldset>
    --            </section>
    --            <footer class="dac-modal-footer">
    --              <div class="cols">
    --                <div class="col-2of5">
    --                </div>
    --              </div>
    --              <button type="submit" value="Submit" class="dac-fab dac-primary dac-large dac-modal-action"><i class="dac-sprite dac-arrow-right"></i></button>
    --            </footer>
    --          </form>
    --        </section>
    --        <section class="dac-swap-section dac-right">
    --          <div class="dac-modal-content">
    --            <p class="newsletter-success-message" data-t="newsletter.successDetails"></p>
    --          </div>
    --        </section>
    --      </div>
    --    </div>
    --  </div>
    --</div>
    --<!-- end newsletter modal -->
    --
    --<!-- start reset language header modal -->
    --<div data-modal="langform" class="dac-modal" id="langform">
    --  <div class="dac-modal-container">
    --    <div class="dac-modal-window">
    --      <header class="dac-modal-header">
    --        <div class="dac-modal-header-actions">
    --          <button class="dac-modal-header-close" data-modal-toggle></button>
    --        </div>
    --        <section class="dac-swap-section dac-active dac-down">
    --          <h2 class="norule dac-modal-header-title"></h2>
    --        </section>
    --      </header>
    --      <section class="dac-swap-section dac-active dac-left">
    --          <section class="dac-modal-content">
    --            <fieldset class="dac-form-fieldset">
    --              <div class="cols">
    --                <div class="col-2of2 langform-leftCol">
    --                  <p id="resetLangText"></p>
    --                  <p id="resetLangCta"></p>
    --                </div>
    --              </div>
    --            </fieldset>
    --          </section>
    --          <footer class="dac-modal-footer" id="langfooter">
    --            <div class="cols">
    --              <div class="col-2of5">
    --              </div>
    --            </div>
    --              <button class="button dac-primary dac-modal-action lang yes" data-t="newsletter.resetLangButtonYes" data-modal-toggle></button>
    --              <button class="button dac-primary dac-modal-action lang no" data-t="newsletter.resetLangButtonNo" data-modal-toggle></button>
    --            </a>
    --          </footer>
    --        </form>
    --      </section>
    --    </div>
    --  </div>
    --</div>
    --<!-- end langreset modal -->
    -diff --git a/tools/droiddoc/templates-sdk-dev/gcm_navtree_data.cs b/tools/droiddoc/templates-sdk-dev/gcm_navtree_data.cs
    -deleted file mode 100644
    -index 6f33d88..0000000
    ---- a/tools/droiddoc/templates-sdk-dev/gcm_navtree_data.cs
    -+++ /dev/null
    -@@ -1,3 +0,0 @@
    --var GCM_NAVTREE_DATA =
    --<?cs var:reference_tree ?>
    --;
    -diff --git a/tools/droiddoc/templates-sdk-dev/gms_navtree_data.cs b/tools/droiddoc/templates-sdk-dev/gms_navtree_data.cs
    -deleted file mode 100644
    -index 66b7d55..0000000
    ---- a/tools/droiddoc/templates-sdk-dev/gms_navtree_data.cs
    -+++ /dev/null
    -@@ -1,3 +0,0 @@
    --var GMS_NAVTREE_DATA =
    --<?cs var:reference_tree ?>
    --;
    -diff --git a/tools/droiddoc/templates-sdk-dev/head_tag.cs b/tools/droiddoc/templates-sdk-dev/head_tag.cs
    -deleted file mode 100644
    -index 0c5bb78..0000000
    ---- a/tools/droiddoc/templates-sdk-dev/head_tag.cs
    -+++ /dev/null
    -@@ -1,219 +0,0 @@
    --<head>
    --  <title><?cs
    --if:devsite ?><?cs
    --  if:page.title ?><?cs
    --    var:html_strip(page.title) ?><?cs
    --  else ?>Android Developers<?cs
    --  /if ?><?cs
    --else ?><?cs
    --  if:page.title ?><?cs
    --    var:page.title ?> | <?cs
    --  /if ?>Android Developers
    --<?cs /if ?><?cs
    --# END if/else devsite ?></title><?cs
    --  ####### If building devsite, add some meta data needed for when generating the top nav ######### ?><?cs
    --if:devsite ?>
    --  <meta name="top_category" value="<?cs
    --      if:ndk ?>ndk<?cs
    --      elif:(guide||develop||training||reference||tools||sdk||google||reference.gms||reference.gcm||samples) ?>develop<?cs
    --      elif:(topic||libraries||instantapps||perf||arc) ?>develop<?cs
    --      elif:(distribute||googleplay||essentials||users||engage||monetize||disttools||stories||analyze) ?>distribute<?cs
    --      elif:(design||vision||material||patterns||devices||designdownloads) ?>design<?cs
    --      elif:(about||versions||wear||tv||auto) ?>about<?cs
    --      elif:wearpreview ?>about<?cs
    --      elif:work ?>about<?cs
    --      elif:preview ?>preview<?cs
    --      else ?>none<?cs
    --      /if ?>" /><?cs set:dac_subcategory_set = #1 ?>
    --  <meta name="subcategory" value="<?cs
    --      if:ndk ?><?cs
    --        if:guide ?>guide<?cs
    --        elif:samples ?>samples<?cs
    --          if:(samplesDocPage&&!samplesProjectIndex) ?> samples-docpage<?cs /if ?><?cs
    --        elif:reference ?>reference<?cs
    --        elif:downloads ?>downloads<?cs
    --        else ?>none<?cs set:dac_subcategory_set = #0 ?><?cs /if ?><?cs
    --      else ?><?cs
    --        if:(guide||develop||training||reference||tools||sdk||samples) ?><?cs
    --          if:guide ?>guide<?cs
    --          elif:training ?><?cs
    --            if:page.trainingcourse ?>trainingcourse<?cs
    --            else ?>training<?cs /if ?><?cs
    --          elif:reference ?>reference<?cs
    --          elif:samples ?>samples<?cs
    --            if:(samplesDocPage&&!samplesProjectIndex) ?> samples-docpage<?cs /if ?><?cs
    --          else ?>none<?cs set:dac_subcategory_set = #0 ?><?cs /if ?><?cs
    --        elif:(google||reference.gms||reference.gcm) ?>google<?cs
    --        elif:(topic||libraries||perf||arc) ?><?cs
    --          if:libraries ?>libraries<?cs
    --          elif:instantapps ?>instantapps<?cs
    --          elif:perf ?>perf<?cs
    --          elif:arc ?>arc<?cs
    --          else ?>none<?cs set:dac_subcategory_set = #0 ?><?cs /if ?><?cs
    --        elif:(distribute||googleplay||essentials||users||engage||monetize||disttools||stories||analyze) ?><?cs
    --          if:googleplay ?>googleplay<?cs
    --          elif:essentials ?>essentials<?cs
    --          elif:users ?>users<?cs
    --          elif:engage ?>engage<?cs
    --          elif:monetize ?>monetize<?cs
    --          elif:disttools ?>disttools<?cs
    --          elif:stories ?>stories<?cs
    --          elif:analyze ?>analyze<?cs
    --          else ?>none<?cs set:dac_subcategory_set = #0 ?><?cs /if ?><?cs
    --        elif:(about||versions||wear||tv||auto) ?>about<?cs
    --        elif:preview ?>preview<?cs
    --        elif:wearpreview ?>wear<?cs
    --        elif:work ?>work<?cs
    --        elif:design ?>design<?cs
    --        elif:walkthru ?>walkthru<?cs
    --        else ?>none<?cs set:dac_subcategory_set = #0 ?><?cs /if ?><?cs
    --      /if ?>" /><?cs
    --      if:nonavpage ?>
    --  <meta name="hide_toc" value='True' /><?cs
    --      elif: !nonavpage && dac_subcategory_set && !tools && !sdk ?>
    --  <meta name="book_path" value="<?cs
    --        if:ndk ?>/ndk<?cs
    --          if:guide ?>/guides<?cs
    --          elif:samples ?>/samples<?cs
    --          elif:reference ?>/reference<?cs
    --          elif:downloads ?>/downloads<?cs /if ?><?cs
    --        else ?><?cs
    --          if:(guide||develop||training||reference||tools||sdk||samples) ?><?cs
    --            if:guide ?>/guide<?cs
    --            elif:training ?>/training<?cs
    --            elif:reference ?>/reference<?cs
    --            elif:samples ?>/samples<?cs /if ?><?cs
    --          elif:(google||reference.gms||reference.gcm) ?>/google<?cs
    --          elif:(topic||libraries||perf) ?>/topic<?cs
    --            if:libraries ?>/libraries<?cs
    --            elif:instantapps ?>/instant-apps<?cs
    --            elif:perf ?>/performance<?cs
    --            elif:arc ?>/arc<?cs /if ?><?cs
    --          elif:(distribute||googleplay||essentials||users||engage||monetize||disttools||stories||analyze) ?>/distribute<?cs
    --            if:googleplay ?>/googleplay<?cs
    --            elif:essentials ?>/essentials<?cs
    --            elif:users ?>/users<?cs
    --            elif:engage ?>/engage<?cs
    --            elif:monetize ?>/monetize<?cs
    --            elif:disttools ?>/tools<?cs
    --            elif:stories ?>/stories<?cs
    --            elif:analyze ?>/analyze<?cs /if ?><?cs
    --          elif:(about||versions||wear||tv||auto) ?>/about<?cs
    --          elif:preview ?>/preview<?cs
    --          elif:wearpreview ?>/wear/preview<?cs
    --          elif:work ?>/work<?cs
    --          elif:design ?>/design<?cs
    --          elif:reference.testSupport ?>/reference/android/support/test<?cs
    --          elif:reference.wearableSupport ?>/reference/android/support/wearable<?cs
    --          elif:walkthru ?>/walkthru<?cs /if ?><?cs
    --        /if ?>/_book.yaml" /><?cs
    --        /if ?>
    --  <meta name="project_path" value="<?cs
    --      if:(guide||develop||training||reference||tools||sdk||samples) ?><?cs
    --        if:guide ?>/guide<?cs
    --        elif:training ?>/training<?cs
    --        elif:reference ?>/reference<?cs
    --        elif:samples ?>/samples<?cs /if ?><?cs
    --      elif:(google||reference.gms||reference.gcm) ?>/google<?cs
    --      elif:(topic||libraries) ?>/develop<?cs
    --      elif:(distribute||googleplay||essentials||users||engage||monetize||disttools||stories||analyze) ?>/distribute<?cs
    --        if:googleplay ?>/googleplay<?cs
    --        elif:essentials ?>/essentials<?cs
    --        elif:users ?>/users<?cs
    --        elif:engage ?>/engage<?cs
    --        elif:monetize ?>/monetize<?cs
    --        elif:disttools ?>/tools<?cs
    --        elif:stories ?>/stories<?cs
    --        elif:analyze ?>/analyze<?cs
    --        else ?><?cs /if ?><?cs
    --      elif:(about||versions||wear||tv||auto) ?>/about<?cs
    --      elif:wearpreview ?>/wear<?cs
    --      elif:work ?>/work<?cs
    --      elif:preview ?>/preview<?cs
    --      elif:design ?>/design<?cs /if ?>/_project.yaml" /><?cs
    --
    --      if:page.tags && page.tags != "" ?>
    --  <meta name="keywords" value='<?cs var:page.tags ?>' /><?cs
    --      /if ?><?cs
    --      if:meta.tags && meta.tags != "" ?>
    --  <meta name="meta_tags" value='<?cs var:meta.tags ?>' /><?cs
    --      /if ?><?cs
    --      if:fullpage ?>
    --  <meta name="full_width" value="True" /><?cs
    --      /if ?><?cs
    --      if:page.landing ?>
    --  <meta name="page_type" value="landing" /><?cs
    --      /if ?><?cs
    --      if:page.article ?>
    --  <meta name="page_type" value="article" /><?cs
    --      /if ?><?cs
    --      if:page.image ?>
    --  <meta name="image_path" value='<?cs var:page.image ?>' /><?cs
    --      /if ?><?cs
    --/if ?><?cs # END if/else devsite ?><?cs
    --
    --  if:!devsite ?>
    --<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
    --<meta name="viewport" content="width=device-width,initial-scale=1.0,minimum-scale=1.0,maximum-scale=1.0,user-scalable=no" />
    --<meta content="IE=edge" http-equiv="X-UA-Compatible">
    --<link rel="shortcut icon" type="image/x-icon" href="<?cs var:toroot ?>favicon.ico" />
    --<link rel="alternate" href="http://developer.android.com/<?cs var:path.canonical ?>" hreflang="en" />
    --<link rel="alternate" href="http://developer.android.com/intl/es/<?cs var:path.canonical ?>" hreflang="es" />
    --<link rel="alternate" href="http://developer.android.com/intl/id/<?cs var:path.canonical ?>" hreflang="id" />
    --<link rel="alternate" href="http://developer.android.com/intl/ja/<?cs var:path.canonical ?>" hreflang="ja" />
    --<link rel="alternate" href="http://developer.android.com/intl/ko/<?cs var:path.canonical ?>" hreflang="ko" />
    --<link rel="alternate" href="http://developer.android.com/intl/pt-br/<?cs var:path.canonical ?>" hreflang="pt-br" />
    --<link rel="alternate" href="http://developer.android.com/intl/ru/<?cs var:path.canonical ?>" hreflang="ru" />
    --<link rel="alternate" href="http://developer.android.com/intl/vi/<?cs var:path.canonical ?>" hreflang="vi" />
    --<link rel="alternate" href="http://developer.android.com/intl/zh-cn/<?cs var:path.canonical ?>" hreflang="zh-cn" />
    --<link rel="alternate" href="http://developer.android.com/intl/zh-tw/<?cs var:path.canonical ?>" hreflang="zh-tw" />
    --<?cs /if ?><?cs
    --# END if/else !devsite ?><?cs
    --
    --      if:page.metaDescription ?>
    --  <meta name="description" content="<?cs var:page.metaDescription ?>"><?cs
    --      /if ?><?cs
    --  if:!devsite ?>
    --<!-- STYLESHEETS -->
    --<link rel="stylesheet"
    --href="<?cs
    --if:android.whichdoc != 'online' ?>http:<?cs
    --/if ?>//fonts.googleapis.com/css?family=Roboto+Condensed">
    --<link rel="stylesheet" href="<?cs
    --if:android.whichdoc != 'online' ?>http:<?cs
    --/if ?>//fonts.googleapis.com/css?family=Roboto:light,regular,medium,thin,italic,mediumitalic,bold"
    --  title="roboto">
    --<?cs
    --  if:ndk ?><link rel="stylesheet" href="<?cs
    --  if:android.whichdoc != 'online' ?>http:<?cs
    --  /if ?>//fonts.googleapis.com/css?family=Roboto+Mono:400,500,700" title="roboto-mono" type="text/css"><?cs
    --/if ?>
    --<link href="<?cs var:toroot ?>assets/css/default.css?v=16" rel="stylesheet" type="text/css">
    --
    --<!-- JAVASCRIPT -->
    --<script src="<?cs if:android.whichdoc != 'online' ?>http:<?cs /if ?>//www.google.com/jsapi" type="text/javascript"></script>
    --<script src="<?cs var:toroot ?>assets/js/android_3p-bundle.js" type="text/javascript"></script><?cs
    --  if:page.customHeadTag ?>
    --<?cs var:page.customHeadTag ?><?cs
    --  /if ?>
    --<script type="text/javascript">
    --  var toRoot = "<?cs var:toroot ?>";
    --  var metaTags = [<?cs var:meta.tags ?>];
    --  var devsite = <?cs if:devsite ?>true<?cs else ?>false<?cs /if ?>;
    --  var useUpdatedTemplates = <?cs if:useUpdatedTemplates ?>true<?cs else ?>false<?cs /if ?>;
    --</script>
    --<script src="<?cs var:toroot ?>assets/js/docs.js?v=17" type="text/javascript"></script>
    --
    --<script>
    --  (function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
    --  (i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
    --  m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
    --  })(window,document,'script','//www.google-analytics.com/analytics.js','ga');
    --
    --  ga('create', 'UA-5831155-1', 'android.com');
    --  ga('create', 'UA-49880327-2', 'android.com', {'name': 'universal'});  // New tracker);
    --  ga('send', 'pageview');
    --  ga('universal.send', 'pageview'); // Send page view for new tracker.
    --</script><?cs /if ?><?cs
    --# END if/else !devsite ?>
    --</head>
    -diff --git a/tools/droiddoc/templates-sdk-dev/header.cs b/tools/droiddoc/templates-sdk-dev/header.cs
    -deleted file mode 100644
    -index a927393..0000000
    ---- a/tools/droiddoc/templates-sdk-dev/header.cs
    -+++ /dev/null
    -@@ -1,11 +0,0 @@
    --<?cs if:!devsite ?><?cs # leave out the global header for devsite; it is in devsite template ?>
    --  <?cs call:custom_masthead() ?>
    --
    --  <?cs if:(fullpage) ?>
    --    <?cs call:fullpage() ?>
    --  <?cs else ?>
    --    <?cs call:body_content_wrap_start() ?>
    --  <?cs /if ?>
    --
    --  <?cs call:search_results() ?>
    --<?cs /if ?><?cs # end if/else !devsite ?>
    -\ No newline at end of file
    -diff --git a/tools/droiddoc/templates-sdk-dev/header_tabs.cs b/tools/droiddoc/templates-sdk-dev/header_tabs.cs
    -deleted file mode 100644
    -index 38c9da8..0000000
    ---- a/tools/droiddoc/templates-sdk-dev/header_tabs.cs
    -+++ /dev/null
    -@@ -1,2 +0,0 @@
    --
    --<!-- CURRENTLY NOT USED... ALL TABS ARE IN masthead.cs -->
    -diff --git a/tools/droiddoc/templates-sdk-dev/jd_lists_unified.cs b/tools/droiddoc/templates-sdk-dev/jd_lists_unified.cs
    -deleted file mode 100644
    -index 4a6f4f7..0000000
    ---- a/tools/droiddoc/templates-sdk-dev/jd_lists_unified.cs
    -+++ /dev/null
    -@@ -1,10 +0,0 @@
    --window.METADATA = window.METADATA || {};
    --METADATA['<?cs var:metadata.lang ?>'] = {};
    --
    --METADATA['<?cs var:metadata.lang ?>'].about = [];
    --METADATA['<?cs var:metadata.lang ?>'].design = [];
    --METADATA['<?cs var:metadata.lang ?>'].develop = [];
    --METADATA['<?cs var:metadata.lang ?>'].distribute = [];
    --METADATA['<?cs var:metadata.lang ?>'].extras = [];
    --
    --<?cs var:reference_tree ?>
    -diff --git a/tools/droiddoc/templates-sdk-dev/lists.cs b/tools/droiddoc/templates-sdk-dev/lists.cs
    -deleted file mode 100644
    -index ede8c43..0000000
    ---- a/tools/droiddoc/templates-sdk-dev/lists.cs
    -+++ /dev/null
    -@@ -1,8 +0,0 @@
    --var <?cs
    --  if:reference.testSupport ?>SUPPORT_TEST_<?cs
    --  elif: reference.wearableSupport ?>SUPPORT_WEARABLE_<?cs 
    --  /if ?>DATA = [
    --<?cs each:page = docs.pages
    --?>      { id:<?cs var: page.id ?>, label:"<?cs var:page.label ?>", link:"<?cs var:page.link ?>", type:"<?cs var:page.type ?>", deprecated:"<?cs var:page.deprecated ?>" }<?cs if:!last(page) ?>,<?cs /if ?>
    --<?cs /each ?>
    --    ];
    -diff --git a/tools/droiddoc/templates-sdk-dev/macros_override.cs b/tools/droiddoc/templates-sdk-dev/macros_override.cs
    -deleted file mode 100644
    -index 5b92fe3..0000000
    ---- a/tools/droiddoc/templates-sdk-dev/macros_override.cs
    -+++ /dev/null
    -@@ -1,51 +0,0 @@
    --<?cs # Create a comma separated list of annotations on obj that were in showAnnotations in Doclava ?>
    --<?cs # pre is an HTML string to start the list, post is an HTML string to close the list ?>
    --<?cs # for example call:show_annotations_list(cl, "<td>Annotations: ", "</td>") ?>
    --<?cs # if obj has nothing on obj.showAnnotations, nothing will be output ?>
    --<?cs def:show_annotations_list(obj) ?>
    --    <?cs each:anno = obj.showAnnotations ?>
    --      <?cs if:first(anno) ?>
    --        <span class='annotation-message'>
    --          Included in documentation by the annotations:
    --      <?cs /if ?>
    --      @<?cs var:anno.type.label ?>
    --      <?cs if:last(anno) == 0 ?>
    --        , &nbsp;
    --      <?cs /if ?>
    --      <?cs if:last(anno)?>
    --        </span>
    --      <?cs /if ?>
    --    <?cs /each ?>
    --<?cs /def ?>
    --
    --<?cs # Override default class_link_table to display annotations ?>
    --<?cs def:class_link_table(classes) ?>
    --  <?cs set:count = #1 ?>
    --  <table class="jd-sumtable-expando">
    --    <?cs each:cl=classes ?>
    --      <tr class="<?cs if:count % #2 ?>alt-color<?cs /if ?> api apilevel-<?cs var:cl.type.since ?>" >
    --        <td class="jd-linkcol"><?cs call:type_link(cl.type) ?></td>
    --        <td class="jd-descrcol" width="100%">
    --          <?cs call:short_descr(cl) ?>&nbsp;
    --          <?cs call:show_annotations_list(cl) ?>
    --        </td>
    --      </tr>
    --      <?cs set:count = count + #1 ?>
    --    <?cs /each ?>
    --  </table>
    --<?cs /def ?>
    --
    --<?cs
    --# Prints a comma separated list of parameters with optional line breaks
    --?><?cs
    --def:parameter_list(params, linebreaks) ?><?cs
    --  each:param = params ?><?cs
    --      call:simple_type_link(param.type)?> <?cs
    --      var:param.name ?><?cs
    --      if: name(param)!=subcount(params)-1
    --        ?>, <?cs if:linebreaks
    --?>
    --                <?cs /if ?><?cs
    --      /if ?><?cs
    --  /each ?><?cs
    --/def ?>
    -\ No newline at end of file
    -diff --git a/tools/droiddoc/templates-sdk-dev/navtree_data.cs b/tools/droiddoc/templates-sdk-dev/navtree_data.cs
    -deleted file mode 100644
    -index 73aa199..0000000
    ---- a/tools/droiddoc/templates-sdk-dev/navtree_data.cs
    -+++ /dev/null
    -@@ -1,3 +0,0 @@
    --var NAVTREE_DATA =
    --<?cs var:reference_tree ?>
    --;
    -diff --git a/tools/droiddoc/templates-sdk-dev/nosidenavpage.cs b/tools/droiddoc/templates-sdk-dev/nosidenavpage.cs
    -deleted file mode 100644
    -index 61754f0..0000000
    ---- a/tools/droiddoc/templates-sdk-dev/nosidenavpage.cs
    -+++ /dev/null
    -@@ -1,28 +0,0 @@
    --<?cs include:"doctype.cs" ?>
    --<?cs include:"macros.cs" ?>
    --<html<?cs if:devsite ?> devsite<?cs /if ?>>
    --<?cs include:"head_tag.cs" ?>
    --<body class="gc-documentation 
    --  <?cs if:(guide||develop||training||reference||tools||sdk) ?>develop<?cs
    --  elif:design ?>design<?cs
    --  elif:distribute ?>distribute<?cs
    --  /if ?>" itemscope itemtype="http://schema.org/Article">
    --<a name="top"></a>
    --<?cs call:custom_masthead() ?>
    --
    --<div id="body-content">
    --<div>
    --<div id="doc-content" style="position:relative;">
    --
    --<?cs call:tag_list(root.descr) ?>
    --
    --<?cs include:"footer.cs" ?>
    --</div><!-- end doc-content -->
    --
    --<?cs include:"trailer.cs" ?>
    --
    --</body>
    --</html>
    --
    --
    --
    -diff --git a/tools/droiddoc/templates-sdk-dev/package.cs b/tools/droiddoc/templates-sdk-dev/package.cs
    -deleted file mode 100644
    -index d3efdda..0000000
    ---- a/tools/droiddoc/templates-sdk-dev/package.cs
    -+++ /dev/null
    -@@ -1,64 +0,0 @@
    --<?cs # THIS CREATES A PACKAGE SUMMARY PAGE FROM EACH package.html FILES
    --     # AND NAMES IT package-summary.html ?>
    --<?cs include:"macros.cs" ?>
    --<?cs include:"macros_override.cs" ?>
    --<?cs include:"doctype.cs" ?>
    --<html<?cs if:devsite ?> devsite<?cs /if ?>>
    --<?cs include:"head_tag.cs" ?>
    --<?cs include:"body_tag.cs" ?>
    --<?cs include:"header.cs" ?>
    --<?cs include:"page_info.cs" ?>
    --<div class="api apilevel-<?cs var:package.since ?>" id="jd-content">
    --
    --<h1><?cs var:package.name ?></h1>
    --
    --<?cs if:subcount(package.descr) ?>
    --  <?cs call:tag_list(package.descr) ?>
    --<?cs /if ?>
    --
    --<?cs def:class_table(label, classes) ?>
    --  <?cs if:subcount(classes) ?>
    --    <h2><?cs var:label ?></h2>
    --    <?cs call:class_link_table(classes) ?>
    --  <?cs /if ?>
    --<?cs /def ?>
    --
    --<?cs call:class_table("Annotations", package.annotations) ?>
    --<?cs call:class_table("Interfaces", package.interfaces) ?>
    --<?cs call:class_table("Classes", package.classes) ?>
    --<?cs call:class_table("Enums", package.enums) ?>
    --<?cs call:class_table("Exceptions", package.exceptions) ?>
    --<?cs call:class_table("Errors", package.errors) ?>
    --
    --</div><!-- end apilevel -->
    --
    --<?cs if:devsite ?>
    --<div class="data-reference-resources-wrapper">
    --  <?cs if:subcount(class.package) ?>
    --  <ul data-reference-resources>
    --    <?cs call:list("Annotations", class.package.annotations) ?>
    --    <?cs call:list("Interfaces", class.package.interfaces) ?>
    --    <?cs call:list("Classes", class.package.classes) ?>
    --    <?cs call:list("Enums", class.package.enums) ?>
    --    <?cs call:list("Exceptions", class.package.exceptions) ?>
    --    <?cs call:list("Errors", class.package.errors) ?>
    --  </ul>
    --  <?cs elif:subcount(package) ?>
    --  <ul data-reference-resources>
    --    <?cs call:class_link_list("Annotations", package.annotations) ?>
    --    <?cs call:class_link_list("Interfaces", package.interfaces) ?>
    --    <?cs call:class_link_list("Classes", package.classes) ?>
    --    <?cs call:class_link_list("Enums", package.enums) ?>
    --    <?cs call:class_link_list("Exceptions", package.exceptions) ?>
    --    <?cs call:class_link_list("Errors", package.errors) ?>
    --  </ul>
    --  <?cs /if ?>
    --</div>
    --<?cs /if ?>
    --
    --<?cs if:!devsite ?>
    --<?cs include:"footer.cs" ?>
    --<?cs include:"trailer.cs" ?>
    --<?cs /if ?>
    --</body>
    --</html>
    -diff --git a/tools/droiddoc/templates-sdk-dev/packages.cs b/tools/droiddoc/templates-sdk-dev/packages.cs
    -deleted file mode 100644
    -index 3fcfb81..0000000
    ---- a/tools/droiddoc/templates-sdk-dev/packages.cs
    -+++ /dev/null
    -@@ -1,53 +0,0 @@
    --<?cs # THIS CREATES A LIST OF ALL PACKAGES AND NAMES IT packages.html ?>
    --<?cs include:"macros.cs" ?>
    --<?cs include:"doctype.cs" ?>
    --<html<?cs if:devsite ?> devsite<?cs /if ?>>
    --<?cs include:"head_tag.cs" ?>
    --<?cs include:"body_tag.cs" ?>
    --<?cs include:"header.cs" ?>
    --
    --<h1><?cs var:page.title ?></h1>
    --<p>These are the API packages.
    --See all <a href="classes.html">API classes</a>.</p>
    --
    --<?cs set:count = #1 ?>
    --<table>
    --<?cs each:pkg = docs.packages ?>
    --    <tr class="api apilevel-<?cs var:pkg.since ?>" >
    --        <td class="jd-linkcol"><?cs call:package_link(pkg) ?></td>
    --        <td class="jd-descrcol" width="100%"><?cs call:tag_list(pkg.shortDescr) ?></td>
    --    </tr>
    --<?cs set:count = count + #1 ?>
    --<?cs /each ?>
    --</table>
    --
    --<?cs if:devsite ?>
    --<div class="data-reference-resources-wrapper">
    --  <?cs if:subcount(class.package) ?>
    --  <ul data-reference-resources>
    --    <?cs call:list("Annotations", class.package.annotations) ?>
    --    <?cs call:list("Interfaces", class.package.interfaces) ?>
    --    <?cs call:list("Classes", class.package.classes) ?>
    --    <?cs call:list("Enums", class.package.enums) ?>
    --    <?cs call:list("Exceptions", class.package.exceptions) ?>
    --    <?cs call:list("Errors", class.package.errors) ?>
    --  </ul>
    --  <?cs elif:subcount(package) ?>
    --  <ul data-reference-resources>
    --    <?cs call:class_link_list("Annotations", package.annotations) ?>
    --    <?cs call:class_link_list("Interfaces", package.interfaces) ?>
    --    <?cs call:class_link_list("Classes", package.classes) ?>
    --    <?cs call:class_link_list("Enums", package.enums) ?>
    --    <?cs call:class_link_list("Exceptions", package.exceptions) ?>
    --    <?cs call:class_link_list("Errors", package.errors) ?>
    --  </ul>
    --  <?cs /if ?>
    --</div>
    --<?cs /if ?>
    --
    --<?cs if:!devsite ?>
    --<?cs include:"footer.cs" ?>
    --<?cs include:"trailer.cs" ?>
    --<?cs /if ?>
    --</body>
    --</html>
    -diff --git a/tools/droiddoc/templates-sdk-dev/page_info.cs b/tools/droiddoc/templates-sdk-dev/page_info.cs
    -deleted file mode 100644
    -index fad1274..0000000
    ---- a/tools/droiddoc/templates-sdk-dev/page_info.cs
    -+++ /dev/null
    -@@ -1,109 +0,0 @@
    --<?cs # optional, more info about the page, such as API level and links ?>
    --<?cs
    --# A modal dialog when API level is set too low for this page
    --?><div id="naMessage"></div>
    --<?cs
    --#
    --# If this is a package summary page...
    --#
    --?><?cs
    --if:subcount(package)
    --?>
    --<div id="api-info-block">
    --<div class="api-level">
    --  <?cs call:since_tags(package) ?>
    --  <?cs call:federated_refs(package) ?>
    --</div>
    --</div><?cs
    --#
    --# Or if this is a class page...
    --#
    --?><?cs
    --elif:subcount(class)
    --?>
    --<div id="api-info-block">
    --<div class="api-level">
    --  <?cs call:since_tags(class) ?><?cs
    --  if:class.deprecatedsince
    --    ?><br>Deprecated since <a href="<?cs var:toroot ?>guide/topics/manifest/uses-sdk-element.html#ApiLevels"
    --        >API level <?cs var:class.deprecatedsince ?></a><?cs
    --  /if ?>
    --  <?cs call:federated_refs(class) ?>
    --</div>
    --
    --<?cs # Set variables about whether there are inherited members; no output ?>
    --<?cs each:cl=class.inherited ?>
    --  <?cs if:subcount(cl.methods) ?>
    --   <?cs set:inhmethods = #1 ?>
    --  <?cs /if ?>
    --  <?cs if:subcount(cl.constants) ?>
    --   <?cs set:inhconstants = #1 ?>
    --  <?cs /if ?>
    --  <?cs if:subcount(cl.fields) ?>
    --   <?cs set:inhfields = #1 ?>
    --  <?cs /if ?>
    --  <?cs if:subcount(cl.attrs) ?>
    --   <?cs set:inhattrs = #1 ?>
    --  <?cs /if ?>
    --<?cs /each ?>
    --
    --<div class="sum-details-links">
    --<?cs if:inhattrs || inhconstants || inhfields || inhmethods || (!class.subclasses.hidden &&
    --     (subcount(class.subclasses.direct) || subcount(class.subclasses.indirect))) ?>
    --Summary:
    --<?cs if:subcount(class.inners) ?>
    --  <a href="#nestedclasses">Nested Classes</a>
    --  <?cs set:linkcount = #1 ?>
    --<?cs /if ?>
    --<?cs if:subcount(class.attrs) ?>
    --  <?cs if:linkcount ?>&#124; <?cs /if ?><a href="#lattrs">XML Attrs</a>
    --  <?cs set:linkcount = #1 ?>
    --<?cs /if ?>
    --<?cs if:inhattrs ?>
    --  <?cs if:linkcount ?>&#124; <?cs /if ?><a href="#inhattrs">Inherited XML Attrs</a>
    --  <?cs set:linkcount = #1 ?>
    --<?cs /if ?>
    --<?cs if:subcount(class.enumConstants) ?>
    --  <?cs if:linkcount ?>&#124; <?cs /if ?><a href="#enumconstants">Enums</a>
    --  <?cs set:linkcount = #1 ?>
    --<?cs /if ?>
    --<?cs if:subcount(class.constants) ?>
    --  <?cs if:linkcount ?>&#124; <?cs /if ?><a href="#constants">Constants</a>
    --  <?cs set:linkcount = #1 ?>
    --<?cs /if ?>
    --<?cs if:inhconstants ?>
    --  <?cs if:linkcount ?>&#124; <?cs /if ?><a href="#inhconstants">Inherited Constants</a>
    --  <?cs set:linkcount = #1 ?>
    --<?cs /if ?>
    --<?cs if:subcount(class.fields) ?>
    --  <?cs if:linkcount ?>&#124; <?cs /if ?><a href="#lfields">Fields</a>
    --  <?cs set:linkcount = #1 ?>
    --<?cs /if ?>
    --<?cs if:inhfields ?>
    --  <?cs if:linkcount ?>&#124; <?cs /if ?><a href="#inhfields">Inherited Fields</a>
    --  <?cs set:linkcount = #1 ?>
    --<?cs /if ?>
    --<?cs if:subcount(class.ctors.public) ?>
    --  <?cs if:linkcount ?>&#124; <?cs /if ?><a href="#pubctors">Ctors</a>
    --  <?cs set:linkcount = #1 ?>
    --<?cs /if ?>
    --<?cs if:subcount(class.ctors.protected) ?>
    --  <?cs if:linkcount ?>&#124; <?cs /if ?><a href="#proctors">Protected Ctors</a>
    --  <?cs set:linkcount = #1 ?>
    --<?cs /if ?>
    --<?cs if:subcount(class.methods.public) ?>
    --  <?cs if:linkcount ?>&#124; <?cs /if ?><a href="#pubmethods">Methods</a>
    --  <?cs set:linkcount = #1 ?>
    --<?cs /if ?>
    --<?cs if:subcount(class.methods.protected) ?>
    --  <?cs if:linkcount ?>&#124; <?cs /if ?><a href="#promethods">Protected Methods</a>
    --  <?cs set:linkcount = #1 ?>
    --<?cs /if ?>
    --<?cs if:inhmethods ?>
    --  <?cs if:linkcount ?>&#124; <?cs /if ?><a href="#inhmethods">Inherited Methods</a>
    --<?cs /if ?>
    --&#124; <a href="#" onclick="return toggleAllClassInherited()" id="toggleAllClassInherited">[Expand All]</a>
    --<?cs /if ?>
    --</div><!-- end sum-details-links -->
    --</div><!-- end api-info-block --><?cs
    --/if ?><?cs # end of if package or class ?>
    -\ No newline at end of file
    -diff --git a/tools/droiddoc/templates-sdk-dev/sample.cs b/tools/droiddoc/templates-sdk-dev/sample.cs
    -deleted file mode 100644
    -index 2c5b9d2..0000000
    ---- a/tools/droiddoc/templates-sdk-dev/sample.cs
    -+++ /dev/null
    -@@ -1,139 +0,0 @@
    --<?cs include:"doctype.cs" ?>
    --<?cs include:"macros.cs" ?>
    --<html<?cs if:devsite ?> devsite<?cs /if ?>>
    --<?cs include:"head_tag.cs" ?>
    --<body class="gc-documentation develop samples" itemscope itemtype="http://schema.org/Article">
    --<?cs include:"header.cs" ?>
    --
    --<!-- start breadcrumb block -->
    --<div id="api-info-block">
    --  <div class="sum-details-links">
    --
    --  <!-- related links -->
    --  <a href="<?cs var:toroot ?>samples/<?cs var:projectDir ?>/index.html">Overview</a>
    --  &#124; <a href="<?cs var:toroot ?>samples/<?cs var:projectDir ?>/project.html">Project</a>
    --  &#124; <a href="<?cs var:toroot ?>downloads/samples/<?cs var:projectDir ?>.zip"
    --    onclick="ga('send', 'event', 'Samples', 'Download', <?cs var:projectDir ?>);"
    --    >Download</a>
    --
    --</div><!-- end sum-details-links -->
    --
    --</div><!-- end breadcurmb block -->
    --
    --<div id="jd-header" style="border:0;">
    --
    --<div id="pathCrumb">
    --<?cs each:item = parentdirs ?>
    --  <?cs if:LinkifyPathCrumb
    --    ?><a href="<?cs var:toroot ?><?cs var:item.Link ?>"><?cs var:item.Name ?></a> /
    --  <?cs else
    --    ?><?cs var:item.Name ?> / <?cs /if ?>
    --<?cs /each ?>
    --</div>
    --
    --  <h1 itemprop="name"><?cs var:page.title ?></h1>
    --</div>
    --<!-- end breadcrumb block -->
    --
    --
    --<?cs # THIS IS THE MAIN DOC CONTENT ?>
    --<div id="jd-content">
    --
    --<?cs if:android.whichdoc == "online" ?>
    --
    --<?cs # If this is the online docs, build the src code navigation links ?>
    --
    --
    --<?cs var:summary ?>
    --
    --<!-- begin file contents -->
    --
    --<?cs # embed image/videos if below maxsize (show message otherwise), else display source code ?>
    --<?cs if:resType == "img" ?>
    --  <div id="codesample-resource"
    --    <?cs if:noDisplay ?>
    --      class="noDisplay"><div class="noDisplay-message"></div>
    --    <?cs else ?>
    --      ><img src="<?cs var:realFile ?>" title="<?cs var:page.title ?>">
    --    <?cs /if ?>
    --  </div>
    --<?cs elif:resType == "video" ?>
    --  <div id="codesample-resource"
    --    <?cs if:noDisplay ?>
    --      class="noDisplay"><div class="noDisplay-message"></div>
    --    <?cs else ?>
    --      ><video class="play-on-hover" controls style="border:1px solid #ececec;background-color:#f9f9f9;" poster="">
    --        <source src="<?cs var:page.title ?>">
    --      </video>
    --    <?cs /if ?>
    --  </div>
    --<?cs else ?>
    --  <div id="codesample-wrapper">
    --    <pre id="codesample-line-numbers" class="no-pretty-print hidden"></pre>
    --    <pre id="codesample-block"><?cs var:fileContents ?></pre>
    --  </div>
    --  <script type="text/javascript">
    --  initCodeLineNumbers();
    --  </script>
    --<?cs /if ?>
    --
    --<!-- end file contents -->
    --
    --<?cs else ?><?cs
    --  # else, this means it's offline docs,
    --          so don't show src links (we dont have the pages!) ?>
    --
    --<?cs /if ?><?cs # end if/else online docs ?>
    --
    --      <div class="content-footer <?cs
    --                    if:fullpage ?>wrap<?cs
    --                    else ?>cols<?cs /if ?>"
    --                    itemscope itemtype="http://schema.org/SiteNavigationElement">
    --        <div class="<?cs
    --                    if:fullpage ?>col-16<?cs
    --                    elif:training||guide ?>col-8<?cs
    --                    else ?>col-9<?cs /if ?>" style="padding-top:4px">
    --          <?cs if:!page.noplus ?><?cs if:fullpage ?><style>#___plusone_0 {float:right !important;}</style><?cs /if ?>
    --            <div class="g-plusone" data-size="medium"></div>
    --          <?cs /if ?>
    --        </div>
    --        <?cs if:!fullscreen ?>
    --        <div class="paging-links col-4">
    --          <?cs if:(design||training||walkthru) && !page.landing && !page.trainingcourse && !footer.hide ?>
    --            <a href="#" class="prev-page-link hide"
    --                zh-tw-lang="上一堂課"
    --                zh-cn-lang="上一课"
    --                ru-lang="Предыдущий"
    --                ko-lang="이전"
    --                ja-lang="前へ"
    --                es-lang="Anterior"
    --                >Previous</a>
    --            <a href="#" class="next-page-link hide"
    --                zh-tw-lang="下一堂課"
    --                zh-cn-lang="下一课"
    --                ru-lang="Следующий"
    --                ko-lang="다음"
    --                ja-lang="次へ"
    --                es-lang="Siguiente"
    --                >Next</a>
    --          <?cs /if ?>
    --        </div>
    --        <?cs /if ?>
    --      </div>
    --
    --      <?cs # for training classes, provide a different kind of link when the next page is a different class ?>
    --      <?cs if:training && !page.article ?>
    --      <div class="content-footer next-class" style="display:none" itemscope itemtype="http://schema.org/SiteNavigationElement">
    --          <a href="#" class="next-class-link hide">Next class: </a>
    --      </div>
    --      <?cs /if ?>
    --
    --  </div> <!-- end jd-content -->
    --
    --  <?cs if:!devsite ?>
    --  <?cs include:"footer.cs" ?>
    --  <?cs include:"trailer.cs" ?>
    --  <?cs /if ?>
    --
    --</body>
    --</html>
    -diff --git a/tools/droiddoc/templates-sdk-dev/sampleindex.cs b/tools/droiddoc/templates-sdk-dev/sampleindex.cs
    -deleted file mode 100644
    -index db648ff..0000000
    ---- a/tools/droiddoc/templates-sdk-dev/sampleindex.cs
    -+++ /dev/null
    -@@ -1,130 +0,0 @@
    --<?cs include:"doctype.cs" ?>
    --<?cs include:"macros.cs" ?>
    --<html<?cs if:devsite ?> devsite<?cs /if ?>>
    --<?cs include:"head_tag.cs" ?>
    --<body class="gc-documentation develop samples" itemscope itemtype="http://schema.org/Article">
    --<?cs include:"header.cs" ?>
    --
    --<!-- start breadcrumb block -->
    --<div id="api-info-block">
    --<div class="sum-details-links">
    --
    --<!-- related links -->
    --<?cs if:projectStructure ?>
    --<a href="<?cs var:toroot ?>samples/<?cs var:projectDir ?>/index.html">Overview</a>
    --&#124; Project<?cs else ?>Overview
    --&#124; <a href="<?cs var:toroot ?>samples/<?cs var:projectDir ?>/project.html">Project</a>
    --<?cs /if ?>
    --&#124; <a href="<?cs var:toroot ?>downloads/samples/<?cs var:projectDir ?>.zip"
    --    onclick="ga('send', 'event', 'Samples', 'Download', <?cs var:projectDir ?>);"
    --    >Download</a>
    --
    --</div><!-- end sum-details-links -->
    --
    --</div><!-- end breadcurmb block -->
    --
    --<h1 itemprop="name"><?cs var:projectDir ?></h1>
    --  
    --<div id="jd-content">
    --<?cs def:display_files(files) ?>
    --
    --    <?cs each:file = files ?>
    --        <?cs if:file.Type != "dir" ?>
    --            <div class="structure-<?cs var:file.Type ?>">
    --            <a href="<?cs var:toroot ?><?cs var:file.Href ?>"><?cs var:file.Name ?></a>
    --            </div>
    --        <?cs else ?>
    --            <div class="toggle-content opened structure-dir">
    --               <a href="#" onclick="return toggleContent(this)">
    --               <img src="<?cs var:toroot ?>assets/images/triangle-opened.png"
    --                  class="toggle-content-img structure-toggle-img" height="9px" width="9px" />
    --               <?cs var:file.Name ?></a><?cs 
    --                  if:file.SummaryFlag == "true" ?><span class="dirInfo"
    --                    >[&nbsp;<a href="file.SummaryHref">Info</a>&nbsp;]</a></span><?cs 
    --                  /if ?>
    --               <div class="toggle-content-toggleme structure-toggleme"> 
    --            <?cs if:file.Sub.0.Name ?>
    --                 <?cs call:display_files(file.Sub) ?>
    --            <?cs /if ?>
    --               </div> <?cs # /toggleme ?>
    --            </div> <?cs # /toggle-content ?>
    --         <?cs /if ?>
    --    <?cs /each ?>
    --<?cs /def ?>
    --
    --<?cs if:android.whichdoc == "online" ?>
    --  <?cs # If this is the online docs, build the src code navigation links ?>
    --
    --  <?cs if:projectStructure ?>
    --
    --    <?cs call:display_files(Files) ?>
    --
    --  <?cs else ?> <?cs # else not project structure doc ?>
    --
    --    <?cs var:summary ?>
    --
    --    <?cs # Remove project structure from landing pages for now
    --         # <h2>Project Structure</h2>
    --         # <p>Decide what to do with this ...</p>
    --         # <?cs call:display_files(Files) ?>
    --
    --  <?cs /if ?> <?cs # end if projectStructure ?>
    --
    --<?cs else ?><?cs
    --  # else, this means it's offline docs,
    --          so don't show src links (we dont have the pages!) ?>
    --
    --<?cs /if ?><?cs # end if/else online docs ?>
    --      <div class="content-footer <?cs
    --                    if:fullpage ?>wrap<?cs
    --                    else ?>cols<?cs /if ?>"
    --                    itemscope itemtype="http://schema.org/SiteNavigationElement">
    --        <div class="<?cs
    --                    if:fullpage ?>col-16<?cs
    --                    elif:training||guide ?>col-8<?cs
    --                    else ?>col-9<?cs /if ?>" style="padding-top:4px">
    --          <?cs if:!page.noplus ?><?cs if:fullpage ?><style>#___plusone_0 {float:right !important;}</style><?cs /if ?>
    --            <div class="g-plusone" data-size="medium"></div>
    --          <?cs /if ?>
    --        </div>
    --        <?cs if:!fullscreen ?>
    --        <div class="paging-links col-4">
    --          <?cs if:(design||training||walkthru) && !page.landing && !page.trainingcourse && !footer.hide ?>
    --            <a href="#" class="prev-page-link hide"
    --                zh-tw-lang="上一堂課"
    --                zh-cn-lang="上一课"
    --                ru-lang="Предыдущий"
    --                ko-lang="이전"
    --                ja-lang="前へ"
    --                es-lang="Anterior"
    --                >Previous</a>
    --            <a href="#" class="next-page-link hide"
    --                zh-tw-lang="下一堂課"
    --                zh-cn-lang="下一课"
    --                ru-lang="Следующий"
    --                ko-lang="다음"
    --                ja-lang="次へ"
    --                es-lang="Siguiente"
    --                >Next</a>
    --          <?cs /if ?>
    --        </div>
    --        <?cs /if ?>
    --      </div>
    --
    --      <?cs # for training classes, provide a different kind of link when the next page is a different class ?>
    --      <?cs if:training && !page.article ?>
    --      <div class="content-footer next-class" style="display:none" itemscope itemtype="http://schema.org/SiteNavigationElement">
    --          <a href="#" class="next-class-link hide">Next class: </a>
    --      </div>
    --      <?cs /if ?>
    --
    --  </div> <!-- end jd-content -->
    --
    --<?cs include:"footer.cs" ?>
    --
    --<?cs include:"trailer.cs" ?>
    --
    --</body>
    --</html>
    --
    --
    -diff --git a/tools/droiddoc/templates-sdk-dev/samples_navtree_data.cs b/tools/droiddoc/templates-sdk-dev/samples_navtree_data.cs
    -deleted file mode 100644
    -index b9b4214..0000000
    ---- a/tools/droiddoc/templates-sdk-dev/samples_navtree_data.cs
    -+++ /dev/null
    -@@ -1,8 +0,0 @@
    --toc:
    --- title: About the Samples
    --  path: /samples/index.html
    --
    --- title: What's New
    --  path: /samples/new/index.html
    --
    --<?cs var:samples_toc_tree ?>
    -\ No newline at end of file
    -diff --git a/tools/droiddoc/templates-sdk-dev/timestamp.cs b/tools/droiddoc/templates-sdk-dev/timestamp.cs
    -deleted file mode 100644
    -index 4bf502a..0000000
    ---- a/tools/droiddoc/templates-sdk-dev/timestamp.cs
    -+++ /dev/null
    -@@ -1 +0,0 @@
    --var BUILD_TIMESTAMP = "<?cs var:page.now ?>";
    -diff --git a/tools/droiddoc/templates-sdk-dev/trailer.cs b/tools/droiddoc/templates-sdk-dev/trailer.cs
    -deleted file mode 100644
    -index 2050475..0000000
    ---- a/tools/droiddoc/templates-sdk-dev/trailer.cs
    -+++ /dev/null
    -@@ -1,38 +0,0 @@
    --<?cs
    --# Other, non-visible things needed at the end of the page,
    --# because not every page needs footer content, but does need other stuff
    --?>
    --</div> <!-- end body-content --> <?cs # normally opened by header.cs ?>
    --
    --<?cs if:carousel ?>
    --<script type="text/javascript">
    --$('.slideshow-container').dacSlideshow({
    --    btnPrev: '.slideshow-prev',
    --    btnNext: '.slideshow-next',
    --    btnPause: '#pauseButton'
    --});
    --</script>
    --<?cs /if ?>
    --<?cs if:tabbedList ?>
    --<script type="text/javascript">
    --$(".feed").dacTabbedList({
    --    nav_id: '.feed-nav',
    --    frame_id: '.feed-frame'
    --});
    --</script>
    --<?cs /if ?>
    --
    --<script src="https://developer.android.com/ytblogger_lists_unified.js" defer></script>
    --<script src="/jd_lists_unified_en.js?v=17" defer></script>
    --<script src="/reference/lists.js?v=17" defer></script>
    --<script src="/reference/gcm_lists.js?v=17" defer></script>
    --<script src="/reference/gms_lists.js?v=17" defer></script>
    --<script>
    --  // Load localized metadata.
    --  (function(lang) {
    --    if (lang === 'en') { return; }
    --
    --    // Write it to the document so it gets evaluated before DOMContentReady.
    --    document.write('<script src="/jd_lists_unified_' + lang + '.js?v=14" defer></' + 'script>');
    --  })(getLangPref())
    --</script>
    -diff --git a/tools/droiddoc/templates-sdk-dev/yaml_navtree.cs b/tools/droiddoc/templates-sdk-dev/yaml_navtree.cs
    -deleted file mode 100644
    -index e5a6404..0000000
    ---- a/tools/droiddoc/templates-sdk-dev/yaml_navtree.cs
    -+++ /dev/null
    -@@ -1,14 +0,0 @@
    --<?cs
    --
    --# print out the yaml nav for the reference docs, only printing the title,
    --path, and status_text (API level) for each package.
    --
    --?>
    --reference:<?cs
    --each:page = docs.pages?><?cs
    --  if:page.type == "package"?>
    --- title: <?cs var:page.label ?>
    --  path: /<?cs var:page.link ?>
    --  status_text: apilevel-<?cs var:page.apilevel ?><?cs
    --  /if?><?cs
    --/each ?>
    -diff --git a/tools/droiddoc/templates-sdk/assets/css/default.css b/tools/droiddoc/templates-sdk/assets/css/default.css
    -index e422d75..9e5df48 100644
    ---- a/tools/droiddoc/templates-sdk/assets/css/default.css
    -+++ b/tools/droiddoc/templates-sdk/assets/css/default.css
    -@@ -3322,20 +3322,18 @@ table.jd-tagtable th {
    -   display: none;
    - }
    - 
    --/* offset the <a name=""> tags to account for sticky nav */
    --body.reference a[name]:not(.nav-start-marker) {
    -+/* offset the empty <a name=""> tags to account for sticky nav */
    -+body.reference a[name]:not(.nav-start-marker):empty {
    -   visibility: hidden;
    -   display: block;
    -   position: relative;
    -   top: -56px;
    --
    - }
    - 
    - .nav-start-marker {
    -   position: absolute;
    - }
    - 
    --
    - /* Quicknav */
    - .btn-quicknav {
    -   width:20px;
    -diff --git a/tools/droiddoc/templates-sdk/assets/js/docs.js b/tools/droiddoc/templates-sdk/assets/js/docs.js
    -index 5ed947c..9709f50 100644
    ---- a/tools/droiddoc/templates-sdk/assets/js/docs.js
    -+++ b/tools/droiddoc/templates-sdk/assets/js/docs.js
    -@@ -3314,7 +3314,7 @@ window.changeLangPref = changeLangPref;
    -   var LANGUAGES = [
    -     'en',
    -     'es',
    --    'in',
    -+    'id',
    -     'ja',
    -     'ko',
    -     'pt-br',
    -@@ -3351,7 +3351,7 @@ window.changeLangPref = changeLangPref;
    -       'languageValTarget': {
    -         'en': 'English',
    -         'ar': 'Arabic (العربيّة)',
    --        'in': 'Indonesian (Bahasa)',
    -+        'id': 'Indonesian (Bahasa)',
    -         'fr': 'French (français)',
    -         'de': 'German (Deutsch)',
    -         'ja': 'Japanese (日本語)',
    -@@ -3609,7 +3609,7 @@ switch (window.getLangPref()) {
    -       }
    -     });
    -     break;
    --  case 'in':
    -+  case 'id':
    -     window.polyglot.extend({
    -       'newsletter': {
    -         'title': 'Receba as dicas e as notícias mais recentes para os desenvolvedores Android e seja bem-sucedido ' +
    -diff --git a/tools/droiddoc/templates-sdk/footer.cs b/tools/droiddoc/templates-sdk/footer.cs
    -index af34a1a..452a811 100644
    ---- a/tools/droiddoc/templates-sdk/footer.cs
    -+++ b/tools/droiddoc/templates-sdk/footer.cs
    -@@ -45,7 +45,7 @@
    -         <select name="language" onchange="changeLangPref(this.value, true)">
    -           <option value="en" selected="selected">English</option>
    -           <option value="es">Español</option>
    --          <option value="in">Bahasa Indonesia</option>
    -+          <option value="id">Bahasa Indonesia</option>
    -           <option value="ja">日本語</option>
    -           <option value="ko">한국어</option>
    -           <option value="pt-br">Português Brasileiro</option>
    -diff --git a/tools/droiddoc/templates-sdk/head_tag.cs b/tools/droiddoc/templates-sdk/head_tag.cs
    -index 0c5bb78..dd67aa5 100644
    ---- a/tools/droiddoc/templates-sdk/head_tag.cs
    -+++ b/tools/droiddoc/templates-sdk/head_tag.cs
    -@@ -126,8 +126,13 @@ if:devsite ?>
    -         elif:stories ?>/stories<?cs
    -         elif:analyze ?>/analyze<?cs
    -         else ?><?cs /if ?><?cs
    --      elif:(about||versions||wear||tv||auto) ?>/about<?cs
    --      elif:wearpreview ?>/wear<?cs
    -+      elif:(about||versions||wear||tv||auto) ?><?cs
    -+        if:versions ?>/about/versions<?cs
    -+        elif:wear ?>/wear<?cs
    -+        elif:tv ?>/tv<?cs
    -+        elif:auto ?>/auto<?cs
    -+        else ?>/about<?cs /if ?><?cs
    -+      elif:wearpreview ?>/wear/preview<?cs
    -       elif:work ?>/work<?cs
    -       elif:preview ?>/preview<?cs
    -       elif:design ?>/design<?cs /if ?>/_project.yaml" /><?cs
    -@@ -150,6 +155,9 @@ if:devsite ?>
    -       if:page.image ?>
    -   <meta name="image_path" value='<?cs var:page.image ?>' /><?cs
    -       /if ?><?cs
    -+      if:excludeFromSuggestions ?>
    -+  <meta name="hide_from_search_suggest" value="true" /><?cs
    -+      /if ?><?cs
    - /if ?><?cs # END if/else devsite ?><?cs
    - 
    -   if:!devsite ?>
    -diff --git a/tools/droiddoc/templates-sdk/jd_lists_unified.cs b/tools/droiddoc/templates-sdk/jd_lists_unified.cs
    -index 4a6f4f7..03141b0 100644
    ---- a/tools/droiddoc/templates-sdk/jd_lists_unified.cs
    -+++ b/tools/droiddoc/templates-sdk/jd_lists_unified.cs
    -@@ -1,4 +1,9 @@
    --window.METADATA = window.METADATA || {};
    -+<?cs # generate metadata file for samples only ?><?cs
    -+if:samples_only ?>METADATA['<?cs var:metadata.lang ?>'].develop = METADATA['<?cs var:metadata.lang ?>'].develop.concat([
    -+<?cs var:reference_tree ?>
    -+]);
    -+<?cs # generate standard unified metadata file ?><?cs
    -+else ?>window.METADATA = window.METADATA || {};
    - METADATA['<?cs var:metadata.lang ?>'] = {};
    - 
    - METADATA['<?cs var:metadata.lang ?>'].about = [];
    -@@ -8,3 +13,4 @@ METADATA['<?cs var:metadata.lang ?>'].distribute = [];
    - METADATA['<?cs var:metadata.lang ?>'].extras = [];
    - 
    - <?cs var:reference_tree ?>
    -+<?cs /if ?>
    -\ No newline at end of file
    -diff --git a/tools/droiddoc/templates-sdk/lists.cs b/tools/droiddoc/templates-sdk/lists.cs
    -index ede8c43..f08abba 100644
    ---- a/tools/droiddoc/templates-sdk/lists.cs
    -+++ b/tools/droiddoc/templates-sdk/lists.cs
    -@@ -1,6 +1,7 @@
    - var <?cs
    -   if:reference.testSupport ?>SUPPORT_TEST_<?cs
    --  elif: reference.wearableSupport ?>SUPPORT_WEARABLE_<?cs 
    -+  elif: reference.wearableSupport ?>SUPPORT_WEARABLE_<?cs
    -+  elif: reference.constraintSupport ?>CONSTRAINT_<?cs
    -   /if ?>DATA = [
    - <?cs each:page = docs.pages
    - ?>      { id:<?cs var: page.id ?>, label:"<?cs var:page.label ?>", link:"<?cs var:page.link ?>", type:"<?cs var:page.type ?>", deprecated:"<?cs var:page.deprecated ?>" }<?cs if:!last(page) ?>,<?cs /if ?>
    -diff --git a/tools/releasetools/blockimgdiff.py b/tools/releasetools/blockimgdiff.py
    -index 0d9aabd..31dabc7 100644
    ---- a/tools/releasetools/blockimgdiff.py
    -+++ b/tools/releasetools/blockimgdiff.py
    -@@ -696,10 +696,19 @@ class BlockImageDiff(object):
    -     with open(prefix + ".new.dat", "wb") as new_f:
    -       for xf in self.transfers:
    -         if xf.style == "zero":
    --          pass
    -+          tgt_size = xf.tgt_ranges.size() * self.tgt.blocksize
    -+          print("%10d %10d (%6.2f%%) %7s %s %s" % (
    -+              tgt_size, tgt_size, 100.0, xf.style, xf.tgt_name,
    -+              str(xf.tgt_ranges)))
    -+
    -         elif xf.style == "new":
    -           for piece in self.tgt.ReadRangeSet(xf.tgt_ranges):
    -             new_f.write(piece)
    -+          tgt_size = xf.tgt_ranges.size() * self.tgt.blocksize
    -+          print("%10d %10d (%6.2f%%) %7s %s %s" % (
    -+              tgt_size, tgt_size, 100.0, xf.style,
    -+              xf.tgt_name, str(xf.tgt_ranges)))
    -+
    -         elif xf.style == "diff":
    -           src = self.src.ReadRangeSet(xf.src_ranges)
    -           tgt = self.tgt.ReadRangeSet(xf.tgt_ranges)
    -@@ -726,6 +735,12 @@ class BlockImageDiff(object):
    -             # These are identical; we don't need to generate a patch,
    -             # just issue copy commands on the device.
    -             xf.style = "move"
    -+            if xf.src_ranges != xf.tgt_ranges:
    -+              print("%10d %10d (%6.2f%%) %7s %s %s (from %s)" % (
    -+                  tgt_size, tgt_size, 100.0, xf.style,
    -+                  xf.tgt_name if xf.tgt_name == xf.src_name else (
    -+                      xf.tgt_name + " (from " + xf.src_name + ")"),
    -+                  str(xf.tgt_ranges), str(xf.src_ranges)))
    -           else:
    -             # For files in zip format (eg, APKs, JARs, etc.) we would
    -             # like to use imgdiff -z if possible (because it usually
    -@@ -773,10 +788,11 @@ class BlockImageDiff(object):
    -           size = len(patch)
    -           with lock:
    -             patches[patchnum] = (patch, xf)
    --            print("%10d %10d (%6.2f%%) %7s %s" % (
    -+            print("%10d %10d (%6.2f%%) %7s %s %s %s" % (
    -                 size, tgt_size, size * 100.0 / tgt_size, xf.style,
    -                 xf.tgt_name if xf.tgt_name == xf.src_name else (
    --                    xf.tgt_name + " (from " + xf.src_name + ")")))
    -+                    xf.tgt_name + " (from " + xf.src_name + ")"),
    -+                str(xf.tgt_ranges), str(xf.src_ranges)))
    - 
    -       threads = [threading.Thread(target=diff_worker)
    -                  for _ in range(self.threads)]
    -@@ -1102,27 +1118,23 @@ class BlockImageDiff(object):
    -   def FindTransfers(self):
    -     """Parse the file_map to generate all the transfers."""
    - 
    --    def AddTransfer(tgt_name, src_name, tgt_ranges, src_ranges, style, by_id,
    --                    split=False):
    --      """Wrapper function for adding a Transfer().
    -+    def AddSplitTransfers(tgt_name, src_name, tgt_ranges, src_ranges,
    -+                          style, by_id):
    -+      """Add one or multiple Transfer()s by splitting large files.
    - 
    -       For BBOTA v3, we need to stash source blocks for resumable feature.
    -       However, with the growth of file size and the shrink of the cache
    -       partition source blocks are too large to be stashed. If a file occupies
    --      too many blocks (greater than MAX_BLOCKS_PER_DIFF_TRANSFER), we split it
    --      into smaller pieces by getting multiple Transfer()s.
    -+      too many blocks, we split it into smaller pieces by getting multiple
    -+      Transfer()s.
    - 
    -       The downside is that after splitting, we may increase the package size
    -       since the split pieces don't align well. According to our experiments,
    -       1/8 of the cache size as the per-piece limit appears to be optimal.
    -       Compared to the fixed 1024-block limit, it reduces the overall package
    --      size by 30% volantis, and 20% for angler and bullhead."""
    --
    --      # We care about diff transfers only.
    --      if style != "diff" or not split:
    --        Transfer(tgt_name, src_name, tgt_ranges, src_ranges, style, by_id)
    --        return
    -+      size by 30% for volantis, and 20% for angler and bullhead."""
    - 
    -+      # Possibly split large files into smaller chunks.
    -       pieces = 0
    -       cache_size = common.OPTIONS.cache_size
    -       split_threshold = 0.125
    -@@ -1158,6 +1170,74 @@ class BlockImageDiff(object):
    -         Transfer(tgt_split_name, src_split_name, tgt_ranges, src_ranges, style,
    -                  by_id)
    - 
    -+    def AddTransfer(tgt_name, src_name, tgt_ranges, src_ranges, style, by_id,
    -+                    split=False):
    -+      """Wrapper function for adding a Transfer()."""
    -+
    -+      # We specialize diff transfers only (which covers bsdiff/imgdiff/move);
    -+      # otherwise add the Transfer() as is.
    -+      if style != "diff" or not split:
    -+        Transfer(tgt_name, src_name, tgt_ranges, src_ranges, style, by_id)
    -+        return
    -+
    -+      # Handle .odex files specially to analyze the block-wise difference. If
    -+      # most of the blocks are identical with only few changes (e.g. header),
    -+      # we will patch the changed blocks only. This avoids stashing unchanged
    -+      # blocks while patching. We limit the analysis to files without size
    -+      # changes only. This is to avoid sacrificing the OTA generation cost too
    -+      # much.
    -+      if (tgt_name.split(".")[-1].lower() == 'odex' and
    -+          tgt_ranges.size() == src_ranges.size()):
    -+
    -+        # 0.5 threshold can be further tuned. The tradeoff is: if only very
    -+        # few blocks remain identical, we lose the opportunity to use imgdiff
    -+        # that may have better compression ratio than bsdiff.
    -+        crop_threshold = 0.5
    -+
    -+        tgt_skipped = RangeSet()
    -+        src_skipped = RangeSet()
    -+        tgt_size = tgt_ranges.size()
    -+        tgt_changed = 0
    -+        for src_block, tgt_block in zip(src_ranges.next_item(),
    -+                                        tgt_ranges.next_item()):
    -+          src_rs = RangeSet(str(src_block))
    -+          tgt_rs = RangeSet(str(tgt_block))
    -+          if self.src.ReadRangeSet(src_rs) == self.tgt.ReadRangeSet(tgt_rs):
    -+            tgt_skipped = tgt_skipped.union(tgt_rs)
    -+            src_skipped = src_skipped.union(src_rs)
    -+          else:
    -+            tgt_changed += tgt_rs.size()
    -+
    -+          # Terminate early if no clear sign of benefits.
    -+          if tgt_changed > tgt_size * crop_threshold:
    -+            break
    -+
    -+        if tgt_changed < tgt_size * crop_threshold:
    -+          assert tgt_changed + tgt_skipped.size() == tgt_size
    -+          print('%10d %10d (%6.2f%%) %s' % (tgt_skipped.size(), tgt_size,
    -+                tgt_skipped.size() * 100.0 / tgt_size, tgt_name))
    -+          AddSplitTransfers(
    -+              "%s-skipped" % (tgt_name,),
    -+              "%s-skipped" % (src_name,),
    -+              tgt_skipped, src_skipped, style, by_id)
    -+
    -+          # Intentionally change the file extension to avoid being imgdiff'd as
    -+          # the files are no longer in their original format.
    -+          tgt_name = "%s-cropped" % (tgt_name,)
    -+          src_name = "%s-cropped" % (src_name,)
    -+          tgt_ranges = tgt_ranges.subtract(tgt_skipped)
    -+          src_ranges = src_ranges.subtract(src_skipped)
    -+
    -+          # Possibly having no changed blocks.
    -+          if not tgt_ranges:
    -+            return
    -+
    -+      # Add the transfer(s).
    -+      AddSplitTransfers(
    -+          tgt_name, src_name, tgt_ranges, src_ranges, style, by_id)
    -+
    -+    print("Finding transfers...")
    -+
    -     empty = RangeSet()
    -     for tgt_fn, tgt_ranges in self.tgt.file_map.items():
    -       if tgt_fn == "__ZERO":
    -diff --git a/tools/releasetools/rangelib.py b/tools/releasetools/rangelib.py
    -index aa572cc..c9bd375 100644
    ---- a/tools/releasetools/rangelib.py
    -+++ b/tools/releasetools/rangelib.py
    -@@ -300,6 +300,20 @@ class RangeSet(object):
    -         n -= e - s
    -     return RangeSet(data=out)
    - 
    -+  def next_item(self):
    -+    """Return the next integer represented by the RangeSet.
    -+
    -+    >>> list(RangeSet("0-9").next_item())
    -+    [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
    -+    >>> list(RangeSet("10-19 3-5").next_item())
    -+    [3, 4, 5, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19]
    -+    >>> list(rangelib.RangeSet("10-19 3 5 7").next_item())
    -+    [3, 5, 7, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19]
    -+    """
    -+    for s, e in self:
    -+      for element in range(s, e):
    -+        yield element
    -+
    - 
    - if __name__ == "__main__":
    -   import doctest
    -diff --git a/tools/releasetools/test_rangelib.py b/tools/releasetools/test_rangelib.py
    -index a61a64e..edf1c4b 100644
    ---- a/tools/releasetools/test_rangelib.py
    -+++ b/tools/releasetools/test_rangelib.py
    -@@ -124,3 +124,14 @@ class RangeSetTest(unittest.TestCase):
    -     self.assertTrue(RangeSet(data=[2, 9, 30, 31, 31, 32, 35, 36]).monotonic)
    -     self.assertTrue(RangeSet(data=[0, 5, 5, 10]).monotonic)
    -     self.assertFalse(RangeSet(data=[5, 10, 0, 5]).monotonic)
    -+
    -+  def test_next_item(self):
    -+    self.assertEqual(
    -+        list(RangeSet("0-9").next_item()),
    -+        [0, 1, 2, 3, 4, 5, 6, 7, 8, 9])
    -+    self.assertEqual(
    -+        list(RangeSet("10-19 3-5").next_item()),
    -+        [3, 4, 5, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19])
    -+    self.assertEqual(
    -+        list(RangeSet("10-19 3 5 7").next_item()),
    -+        [3, 5, 7, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19])
    diff --git a/frameworks_av.patch b/frameworks_av.patch
    index df12cda..9af12f4 100644
    --- a/frameworks_av.patch
    +++ b/frameworks_av.patch
    @@ -1,82 +1,3 @@
    -diff --git a/camera/camera2/CaptureRequest.cpp b/camera/camera2/CaptureRequest.cpp
    -index fb43708..0d689a6 100644
    ---- a/camera/camera2/CaptureRequest.cpp
    -+++ b/camera/camera2/CaptureRequest.cpp
    -@@ -37,7 +37,7 @@ status_t CaptureRequest::readFromParcel(const Parcel* parcel) {
    -     mMetadata.clear();
    -     mSurfaceList.clear();
    - 
    --    status_t err;
    -+    status_t err = OK;
    - 
    -     if ((err = mMetadata.readFromParcel(parcel)) != OK) {
    -         ALOGE("%s: Failed to read metadata from parcel", __FUNCTION__);
    -@@ -65,19 +65,16 @@ status_t CaptureRequest::readFromParcel(const Parcel* parcel) {
    -         }
    - 
    -         // Surface.writeToParcel
    --        const char16_t* name = parcel->readString16Inplace(&len);
    --        ALOGV("%s: Read surface name = %s", __FUNCTION__,
    --            name != NULL ? String8(name).string() : "<null>");
    --        sp<IBinder> binder(parcel->readStrongBinder());
    --        ALOGV("%s: Read surface binder = %p",
    --              __FUNCTION__, binder.get());
    -+        view::Surface surfaceShim;
    -+        if ((err = surfaceShim.readFromParcel(parcel)) != OK) {
    -+            ALOGE("%s: Failed to read output target Surface %d from parcel: %s (%d)",
    -+                    __FUNCTION__, i, strerror(-err), err);
    -+            return err;
    -+        }
    - 
    -         sp<Surface> surface;
    --
    --        if (binder != NULL) {
    --            sp<IGraphicBufferProducer> gbp =
    --                    interface_cast<IGraphicBufferProducer>(binder);
    --            surface = new Surface(gbp);
    -+        if (surfaceShim.graphicBufferProducer != NULL) {
    -+            surface = new Surface(surfaceShim.graphicBufferProducer);
    -         }
    - 
    -         mSurfaceList.push_back(surface);
    -@@ -99,7 +96,7 @@ status_t CaptureRequest::writeToParcel(Parcel* parcel) const {
    -         return BAD_VALUE;
    -     }
    - 
    --    status_t err;
    -+    status_t err = OK;
    - 
    -     if ((err = mMetadata.writeToParcel(parcel)) != OK) {
    -         return err;
    -@@ -111,20 +108,18 @@ status_t CaptureRequest::writeToParcel(Parcel* parcel) const {
    -     parcel->writeInt32(size);
    - 
    -     for (int32_t i = 0; i < size; ++i) {
    --        sp<Surface> surface = mSurfaceList[i];
    --
    --        sp<IBinder> binder;
    --        if (surface != 0) {
    --            binder = IInterface::asBinder(surface->getIGraphicBufferProducer());
    --        }
    --
    -         // not sure if readParcelableArray does this, hard to tell from source
    -         parcel->writeString16(String16("android.view.Surface"));
    - 
    -         // Surface.writeToParcel
    --        parcel->writeString16(String16("unknown_name"));
    --        // Surface.nativeWriteToParcel
    --        parcel->writeStrongBinder(binder);
    -+        view::Surface surfaceShim;
    -+        surfaceShim.name = String16("unknown_name");
    -+        surfaceShim.graphicBufferProducer = mSurfaceList[i]->getIGraphicBufferProducer();
    -+        if ((err = surfaceShim.writeToParcel(parcel)) != OK) {
    -+            ALOGE("%s: Failed to write output target Surface %d to parcel: %s (%d)",
    -+                    __FUNCTION__, i, strerror(-err), err);
    -+            return err;
    -+        }
    -     }
    - 
    -     parcel->writeInt32(mIsReprocess ? 1 : 0);
     diff --git a/camera/cameraserver/Android.mk b/camera/cameraserver/Android.mk
     index 7e36c5e..aca7a19 100644
     --- a/camera/cameraserver/Android.mk
    @@ -96,1345 +17,21 @@ index 7e36c5e..aca7a19 100644
      
      include $(BUILD_EXECUTABLE)
     +endif
    -diff --git a/drm/mediadrm/plugins/clearkey/DrmFactory.cpp b/drm/mediadrm/plugins/clearkey/DrmFactory.cpp
    -index 40275cf..d27956c 100644
    ---- a/drm/mediadrm/plugins/clearkey/DrmFactory.cpp
    -+++ b/drm/mediadrm/plugins/clearkey/DrmFactory.cpp
    -@@ -24,6 +24,7 @@
    - 
    - #include "DrmPlugin.h"
    - #include "ClearKeyUUID.h"
    -+#include "MimeType.h"
    - #include "SessionLibrary.h"
    - 
    - namespace clearkeydrm {
    -@@ -32,10 +33,14 @@ bool DrmFactory::isCryptoSchemeSupported(const uint8_t uuid[16]) {
    -     return isClearKeyUUID(uuid);
    - }
    - 
    --bool DrmFactory::isContentTypeSupported(const android::String8 &initDataType) {
    -+bool DrmFactory::isContentTypeSupported(const android::String8 &type) {
    -     // This should match the types handed by InitDataParser.
    --    return initDataType == "cenc" ||
    --           initDataType == "webm";
    -+    return type == kIsoBmffVideoMimeType ||
    -+        type == kIsoBmffAudioMimeType ||
    -+        type == kCencInitDataFormat ||
    -+        type == kWebmVideoMimeType ||
    -+        type == kWebmAudioMimeType ||
    -+        type == kWebmInitDataFormat;
    - }
    - 
    - android::status_t DrmFactory::createDrmPlugin(
    -diff --git a/drm/mediadrm/plugins/clearkey/DrmFactory.h b/drm/mediadrm/plugins/clearkey/DrmFactory.h
    -index 164d3d0..87db982 100644
    ---- a/drm/mediadrm/plugins/clearkey/DrmFactory.h
    -+++ b/drm/mediadrm/plugins/clearkey/DrmFactory.h
    -@@ -32,7 +32,7 @@ public:
    - 
    -     virtual bool isCryptoSchemeSupported(const uint8_t uuid[16]);
    - 
    --    virtual bool isContentTypeSupported(const android::String8 &initDataType);
    -+    virtual bool isContentTypeSupported(const android::String8 &mimeType);
    - 
    -     virtual android::status_t createDrmPlugin(
    -             const uint8_t uuid[16], android::DrmPlugin** plugin);
    -diff --git a/drm/mediadrm/plugins/clearkey/DrmPlugin.cpp b/drm/mediadrm/plugins/clearkey/DrmPlugin.cpp
    -index e5ee403..86bf047 100644
    ---- a/drm/mediadrm/plugins/clearkey/DrmPlugin.cpp
    -+++ b/drm/mediadrm/plugins/clearkey/DrmPlugin.cpp
    -@@ -46,7 +46,7 @@ status_t DrmPlugin::closeSession(const Vector<uint8_t>& sessionId) {
    - status_t DrmPlugin::getKeyRequest(
    -         const Vector<uint8_t>& scope,
    -         const Vector<uint8_t>& initData,
    --        const String8& initDataType,
    -+        const String8& mimeType,
    -         KeyType keyType,
    -         const KeyedVector<String8, String8>& optionalParameters,
    -         Vector<uint8_t>& request,
    -@@ -62,7 +62,7 @@ status_t DrmPlugin::getKeyRequest(
    -     if (!session.get()) {
    -         return android::ERROR_DRM_SESSION_NOT_OPENED;
    -     }
    --    return session->getKeyRequest(initData, initDataType, &request);
    -+    return session->getKeyRequest(initData, mimeType, &request);
    - }
    - 
    - status_t DrmPlugin::provideKeyResponse(
    -diff --git a/drm/mediadrm/plugins/clearkey/DrmPlugin.h b/drm/mediadrm/plugins/clearkey/DrmPlugin.h
    -index 9095045..efb9f8b 100644
    ---- a/drm/mediadrm/plugins/clearkey/DrmPlugin.h
    -+++ b/drm/mediadrm/plugins/clearkey/DrmPlugin.h
    -@@ -49,7 +49,7 @@ public:
    - 
    -     virtual status_t getKeyRequest(
    -             const Vector<uint8_t>& scope,
    --            const Vector<uint8_t>& initData,
    -+            const Vector<uint8_t>& mimeType,
    -             const String8& initDataType,
    -             KeyType keyType,
    -             const KeyedVector<String8, String8>& optionalParameters,
    -diff --git a/drm/mediadrm/plugins/clearkey/InitDataParser.cpp b/drm/mediadrm/plugins/clearkey/InitDataParser.cpp
    -index c22d73a..0216b8d 100644
    ---- a/drm/mediadrm/plugins/clearkey/InitDataParser.cpp
    -+++ b/drm/mediadrm/plugins/clearkey/InitDataParser.cpp
    -@@ -27,6 +27,7 @@
    - #include "InitDataParser.h"
    - 
    - #include "ClearKeyUUID.h"
    -+#include "MimeType.h"
    - #include "Utils.h"
    - 
    - namespace clearkeydrm {
    -@@ -41,16 +42,20 @@ namespace {
    - }
    - 
    - android::status_t InitDataParser::parse(const Vector<uint8_t>& initData,
    --        const String8& initDataType,
    -+        const String8& type,
    -         Vector<uint8_t>* licenseRequest) {
    -     // Build a list of the key IDs
    -     Vector<const uint8_t*> keyIds;
    --    if (initDataType == "cenc") {
    -+    if (type == kIsoBmffVideoMimeType ||
    -+        type == kIsoBmffAudioMimeType ||
    -+        type == kCencInitDataFormat) {
    -         android::status_t res = parsePssh(initData, &keyIds);
    -         if (res != android::OK) {
    -             return res;
    -         }
    --    } else if (initDataType == "webm") {
    -+    } else if (type == kWebmVideoMimeType ||
    -+        type == kWebmAudioMimeType ||
    -+        type == kWebmInitDataFormat) {
    -         // WebM "init data" is just a single key ID
    -         if (initData.size() != kKeyIdSize) {
    -             return android::ERROR_DRM_CANNOT_HANDLE;
    -diff --git a/drm/mediadrm/plugins/clearkey/InitDataParser.h b/drm/mediadrm/plugins/clearkey/InitDataParser.h
    -index 9505d2a..a9707bf 100644
    ---- a/drm/mediadrm/plugins/clearkey/InitDataParser.h
    -+++ b/drm/mediadrm/plugins/clearkey/InitDataParser.h
    -@@ -29,7 +29,7 @@ public:
    -     InitDataParser() {}
    - 
    -     android::status_t parse(const android::Vector<uint8_t>& initData,
    --            const android::String8& initDataType,
    -+            const android::String8& type,
    -             android::Vector<uint8_t>* licenseRequest);
    - 
    - private:
    -diff --git a/drm/mediadrm/plugins/clearkey/MimeType.h b/drm/mediadrm/plugins/clearkey/MimeType.h
    -new file mode 100644
    -index 0000000..085f17a
    ---- /dev/null
    -+++ b/drm/mediadrm/plugins/clearkey/MimeType.h
    -@@ -0,0 +1,15 @@
    -+#ifndef CLEARKEY_MIMETYPE_H_
    -+#define CLEARKEY_MIMETYPE_H_
    -+
    -+#include <utils/String8.h>
    -+
    -+namespace {
    -+    const android::String8 kCencInitDataFormat("cenc");
    -+    const android::String8 kIsoBmffAudioMimeType("audio/mp4");
    -+    const android::String8 kIsoBmffVideoMimeType("video/mp4");
    -+    const android::String8 kWebmInitDataFormat("webm");
    -+    const android::String8 kWebmAudioMimeType("audio/webm");
    -+    const android::String8 kWebmVideoMimeType("video/webm");
    -+}
    -+
    -+#endif // CLEARKEY_MIMETYPE_H_
    -diff --git a/drm/mediadrm/plugins/clearkey/Session.cpp b/drm/mediadrm/plugins/clearkey/Session.cpp
    -index 95016f5..d210f5e 100644
    ---- a/drm/mediadrm/plugins/clearkey/Session.cpp
    -+++ b/drm/mediadrm/plugins/clearkey/Session.cpp
    -@@ -36,10 +36,10 @@ using android::status_t;
    - 
    - status_t Session::getKeyRequest(
    -         const Vector<uint8_t>& initData,
    --        const String8& initDataType,
    -+        const String8& mimeType,
    -         Vector<uint8_t>* keyRequest) const {
    -     InitDataParser parser;
    --    return parser.parse(initData, initDataType, keyRequest);
    -+    return parser.parse(initData, mimeType, keyRequest);
    - }
    - 
    - status_t Session::provideKeyResponse(const Vector<uint8_t>& response) {
    -diff --git a/drm/mediadrm/plugins/clearkey/Session.h b/drm/mediadrm/plugins/clearkey/Session.h
    -index cab0dc3..0933506 100644
    ---- a/drm/mediadrm/plugins/clearkey/Session.h
    -+++ b/drm/mediadrm/plugins/clearkey/Session.h
    -@@ -38,7 +38,7 @@ public:
    -     const android::Vector<uint8_t>& sessionId() const { return mSessionId; }
    - 
    -     android::status_t getKeyRequest(
    --            const android::Vector<uint8_t>& initData,
    -+            const android::Vector<uint8_t>& mimeType,
    -             const android::String8& initDataType,
    -             android::Vector<uint8_t>* keyRequest) const;
    - 
    -diff --git a/drm/mediadrm/plugins/clearkey/tests/InitDataParserUnittest.cpp b/drm/mediadrm/plugins/clearkey/tests/InitDataParserUnittest.cpp
    -index 4ba65ed..e275108 100644
    ---- a/drm/mediadrm/plugins/clearkey/tests/InitDataParserUnittest.cpp
    -+++ b/drm/mediadrm/plugins/clearkey/tests/InitDataParserUnittest.cpp
    -@@ -30,27 +30,27 @@ using namespace android;
    - 
    - namespace {
    -     const size_t kKeyIdSize = 16;
    --    const String8 kCencType("cenc");
    --    const String8 kWebMType("webm");
    -+    const String8 kCencMimeType("video/mp4");
    -+    const String8 kWebmMimeType("video/webm");
    -     const String8 kBase64Padding("=");
    - }
    - 
    - class InitDataParserTest : public ::testing::Test {
    -   protected:
    -     status_t attemptParse(const Vector<uint8_t>& initData,
    --                          const String8& initDataType,
    -+                          const String8& mimeType,
    -                           Vector<uint8_t>* licenseRequest) {
    -         InitDataParser parser;
    --        return parser.parse(initData, initDataType, licenseRequest);
    -+        return parser.parse(initData, mimeType, licenseRequest);
    -     }
    - 
    -     void attemptParseExpectingSuccess(const Vector<uint8_t>& initData,
    --                                      const String8& initDataType,
    -+                                      const String8& mimeType,
    -                                       const Vector<String8>& expectedKeys) {
    -         const String8 kRequestPrefix("{\"kids\":[");
    -         const String8 kRequestSuffix("],\"type\":\"temporary\"}");
    -         Vector<uint8_t> request;
    --        ASSERT_EQ(android::OK, attemptParse(initData, initDataType, &request));
    -+        ASSERT_EQ(android::OK, attemptParse(initData, mimeType, &request));
    - 
    -         String8 requestString(reinterpret_cast<const char*>(request.array()),
    -                               request.size());
    -@@ -68,9 +68,9 @@ class InitDataParserTest : public ::testing::Test {
    -     }
    - 
    -     void attemptParseExpectingFailure(const Vector<uint8_t>& initData,
    --                                      const String8& initDataType) {
    -+                                      const String8& mimeType) {
    -         Vector<uint8_t> request;
    --        ASSERT_NE(android::OK, attemptParse(initData, initDataType, &request));
    -+        ASSERT_NE(android::OK, attemptParse(initData, mimeType, &request));
    -         EXPECT_EQ(0, request.size());
    -     }
    - };
    -@@ -93,7 +93,7 @@ TEST_F(InitDataParserTest, ParsesSingleKeyPssh) {
    -     Vector<String8> expectedKeys;
    -     expectedKeys.push(String8("01234567890ABCDE"));
    - 
    --    attemptParseExpectingSuccess(initData, kCencType, expectedKeys);
    -+    attemptParseExpectingSuccess(initData, kCencMimeType, expectedKeys);
    - }
    - 
    - TEST_F(InitDataParserTest, ParsesMultipleKeyPssh) {
    -@@ -120,7 +120,7 @@ TEST_F(InitDataParserTest, ParsesMultipleKeyPssh) {
    -     expectedKeys.push(String8("ClearKeyClearKey"));
    -     expectedKeys.push(String8(" GOOGLE  GOOGLE "));
    - 
    --    attemptParseExpectingSuccess(initData, kCencType, expectedKeys);
    -+    attemptParseExpectingSuccess(initData, kCencMimeType, expectedKeys);
    - }
    - 
    - TEST_F(InitDataParserTest, ParsesWebM) {
    -@@ -134,7 +134,7 @@ TEST_F(InitDataParserTest, ParsesWebM) {
    -     Vector<String8> expectedKeys;
    -     expectedKeys.push(String8("01234567890ABCDE"));
    - 
    --    attemptParseExpectingSuccess(initData, kWebMType, expectedKeys);
    -+    attemptParseExpectingSuccess(initData, kWebmMimeType, expectedKeys);
    - }
    - 
    - TEST_F(InitDataParserTest, FailsForPsshTooSmall) {
    -@@ -147,7 +147,7 @@ TEST_F(InitDataParserTest, FailsForPsshTooSmall) {
    -     Vector<uint8_t> initData;
    -     initData.appendArray(pssh, 16);
    - 
    --    attemptParseExpectingFailure(initData, kCencType);
    -+    attemptParseExpectingFailure(initData, kCencMimeType);
    - }
    - 
    - TEST_F(InitDataParserTest, FailsForWebMTooSmall) {
    -@@ -157,7 +157,7 @@ TEST_F(InitDataParserTest, FailsForWebMTooSmall) {
    -     Vector<uint8_t> initData;
    -     initData.appendArray(initDataRaw, 8);
    - 
    --    attemptParseExpectingFailure(initData, kWebMType);
    -+    attemptParseExpectingFailure(initData, kWebmMimeType);
    - }
    - 
    - TEST_F(InitDataParserTest, FailsForPsshBadSystemId) {
    -@@ -175,7 +175,7 @@ TEST_F(InitDataParserTest, FailsForPsshBadSystemId) {
    -     Vector<uint8_t> initData;
    -     initData.appendArray(pssh, 52);
    - 
    --    attemptParseExpectingFailure(initData, kCencType);
    -+    attemptParseExpectingFailure(initData, kCencMimeType);
    - }
    - 
    - TEST_F(InitDataParserTest, FailsForPsshBadSize) {
    -@@ -193,7 +193,7 @@ TEST_F(InitDataParserTest, FailsForPsshBadSize) {
    -     Vector<uint8_t> initData;
    -     initData.appendArray(pssh, 52);
    - 
    --    attemptParseExpectingFailure(initData, kCencType);
    -+    attemptParseExpectingFailure(initData, kCencMimeType);
    - }
    - 
    - TEST_F(InitDataParserTest, FailsForPsshWrongVersion) {
    -@@ -211,7 +211,7 @@ TEST_F(InitDataParserTest, FailsForPsshWrongVersion) {
    -     Vector<uint8_t> initData;
    -     initData.appendArray(pssh, 52);
    - 
    --    attemptParseExpectingFailure(initData, kCencType);
    -+    attemptParseExpectingFailure(initData, kCencMimeType);
    - }
    - 
    - TEST_F(InitDataParserTest, FailsForPsshBadKeyCount) {
    -@@ -229,7 +229,7 @@ TEST_F(InitDataParserTest, FailsForPsshBadKeyCount) {
    -     Vector<uint8_t> initData;
    -     initData.appendArray(pssh, 52);
    - 
    --    attemptParseExpectingFailure(initData, kCencType);
    -+    attemptParseExpectingFailure(initData, kCencMimeType);
    - }
    - 
    - }  // namespace clearkeydrm
    -diff --git a/include/media/ToneGenerator.h b/include/media/ToneGenerator.h
    -index 75515ac..9fd5f61 100644
    ---- a/include/media/ToneGenerator.h
    -+++ b/include/media/ToneGenerator.h
    -@@ -193,8 +193,8 @@ private:
    -         TONE_JAPAN_DIAL,            // Dial tone: 400Hz, continuous
    -         TONE_JAPAN_BUSY,            // Busy tone: 400Hz, 500ms ON, 500ms OFF...
    -         TONE_JAPAN_RADIO_ACK,       // Radio path acknowlegment: 400Hz, 1s ON, 2s OFF...
    --        // UK Supervisory tones
    --        TONE_UK_RINGTONE,           // Ring Tone: A 400Hz + 450Hz tone repeated in a 0.4s on, 0.2s off, 0.4s on, 2.0s off pattern.
    -+        // GB Supervisory tones
    -+        TONE_GB_RINGTONE,           // Ring Tone: A 400Hz + 450Hz tone repeated in a 0.4s on, 0.2s off, 0.4s on, 2.0s off pattern.
    -         // AUSTRALIA Supervisory tones
    -         TONE_AUSTRALIA_RINGTONE,    // Ring tone: A 400Hz + 450Hz tone repeated in a 0.4s on, 0.2s off, 0.4s on, 2.0s off pattern.
    -         TONE_AUSTRALIA_BUSY,        // Busy tone: 425 Hz repeated in a 0.375s on, 0.375s off pattern.
    -@@ -206,7 +206,7 @@ private:
    -     enum region {
    -         ANSI,
    -         JAPAN,
    --        UK,
    -+        GB,
    -         AUSTRALIA,
    -         CEPT,
    -         NUM_REGIONS
    -@@ -313,7 +313,7 @@ private:
    - 
    -         short mA1_Q14;  // Q14 coefficient
    -         // delay line of full amplitude generator
    --        short mS1, mS2;  // delay line S2 oldest
    -+        long mS1, mS2;  // delay line S2 oldest
    -         short mS2_0;  // saved value for reinitialisation
    -         short mAmplitude_Q15;  // Q15 amplitude
    -     };
    -diff --git a/include/media/Visualizer.h b/include/media/Visualizer.h
    -index ec0dad5..7bb9e8b 100644
    ---- a/include/media/Visualizer.h
    -+++ b/include/media/Visualizer.h
    -@@ -95,8 +95,7 @@ public:
    - 
    -     // install a callback to receive periodic captures. The capture rate is specified in milliHertz
    -     // and the capture format is according to flags  (see callback_flags).
    --    status_t setCaptureCallBack(capture_cbk_t cbk, void* user, uint32_t flags, uint32_t rate,
    --                                bool force = false);
    -+    status_t setCaptureCallBack(capture_cbk_t cbk, void* user, uint32_t flags, uint32_t rate);
    - 
    -     // set the capture size capture size must be a power of two in the range
    -     // [VISUALIZER_CAPTURE_SIZE_MAX. VISUALIZER_CAPTURE_SIZE_MIN]
    -diff --git a/include/media/stagefright/MediaBuffer.h b/include/media/stagefright/MediaBuffer.h
    -index abfe068..a61ddaa 100644
    ---- a/include/media/stagefright/MediaBuffer.h
    -+++ b/include/media/stagefright/MediaBuffer.h
    -@@ -68,11 +68,16 @@ public:
    -         mMemory = mem;
    -     }
    - 
    --    // Decrements the reference count and returns the buffer to its
    --    // associated MediaBufferGroup if the reference count drops to 0.
    -+    // If MediaBufferGroup is set, decrement the local reference count;
    -+    // if the local reference count drops to 0, return the buffer to the
    -+    // associated MediaBufferGroup.
    -+    //
    -+    // If no MediaBufferGroup is set, the local reference count must be zero
    -+    // when called, whereupon the MediaBuffer is deleted.
    -     virtual void release();
    - 
    --    // Increments the reference count.
    -+    // Increments the local reference count.
    -+    // Use only when MediaBufferGroup is set.
    -     virtual void add_ref();
    - 
    -     void *data() const;
    -@@ -97,7 +102,28 @@ public:
    -     // MetaData.
    -     MediaBuffer *clone();
    - 
    --    int refcount() const;
    -+    // sum of localRefcount() and remoteRefcount()
    -+    int refcount() const {
    -+        return localRefcount() + remoteRefcount();
    -+    }
    -+
    -+    int localRefcount() const {
    -+        return mRefCount;
    -+    }
    -+
    -+    int remoteRefcount() const {
    -+        if (mMemory.get() == nullptr || mMemory->pointer() == nullptr) return 0;
    -+        int32_t remoteRefcount =
    -+                reinterpret_cast<SharedControl *>(mMemory->pointer())->getRemoteRefcount();
    -+        // Sanity check so that remoteRefCount() is non-negative.
    -+        return remoteRefcount >= 0 ? remoteRefcount : 0; // do not allow corrupted data.
    -+    }
    -+
    -+    // returns old value
    -+    int addRemoteRefcount(int32_t value) {
    -+        if (mMemory.get() == nullptr || mMemory->pointer() == nullptr) return 0;
    -+        return reinterpret_cast<SharedControl *>(mMemory->pointer())->addRemoteRefcount(value);
    -+    }
    - 
    -     bool isDeadObject() const {
    -         return isDeadObject(mMemory);
    -@@ -117,25 +143,6 @@ public:
    -     }
    - 
    - protected:
    --    // MediaBuffer remote releases are handled through a
    --    // pending release count variable stored in a SharedControl block
    --    // at the start of the IMemory.
    --
    --    // Returns old value of pending release count.
    --    inline int32_t addPendingRelease(int32_t value) {
    --        return getSharedControl()->addPendingRelease(value);
    --    }
    --
    --    // Issues all pending releases (works in parallel).
    --    // Assumes there is a MediaBufferObserver.
    --    inline void resolvePendingRelease() {
    --        if (mMemory.get() == nullptr) return;
    --        while (addPendingRelease(-1) > 0) {
    --            release();
    --        }
    --        addPendingRelease(1);
    --    }
    --
    -     // true if MediaBuffer is observed (part of a MediaBufferGroup).
    -     inline bool isObserved() const {
    -         return mObserver != nullptr;
    -@@ -181,18 +188,18 @@ private:
    -         };
    - 
    -         // returns old value
    --        inline int32_t addPendingRelease(int32_t value) {
    -+        inline int32_t addRemoteRefcount(int32_t value) {
    -             return std::atomic_fetch_add_explicit(
    --                    &mPendingRelease, (int_least32_t)value, std::memory_order_seq_cst);
    -+                    &mRemoteRefcount, (int_least32_t)value, std::memory_order_seq_cst);
    -         }
    - 
    --        inline int32_t getPendingRelease() const {
    --            return std::atomic_load_explicit(&mPendingRelease, std::memory_order_seq_cst);
    -+        inline int32_t getRemoteRefcount() const {
    -+            return std::atomic_load_explicit(&mRemoteRefcount, std::memory_order_seq_cst);
    -         }
    - 
    --        inline void setPendingRelease(int32_t value) {
    -+        inline void setRemoteRefcount(int32_t value) {
    -             std::atomic_store_explicit(
    --                    &mPendingRelease, (int_least32_t)value, std::memory_order_seq_cst);
    -+                    &mRemoteRefcount, (int_least32_t)value, std::memory_order_seq_cst);
    -         }
    - 
    -         inline bool isDeadObject() const {
    -@@ -209,13 +216,13 @@ private:
    -             std::atomic_store_explicit(
    -                     &mFlags, (int_least32_t)0, std::memory_order_seq_cst);
    -             std::atomic_store_explicit(
    --                    &mPendingRelease, (int_least32_t)0, std::memory_order_seq_cst);
    -+                    &mRemoteRefcount, (int_least32_t)0, std::memory_order_seq_cst);
    -         }
    - 
    -     private:
    -         // Caution: atomic_int_fast32_t is 64 bits on LP64.
    -         std::atomic_int_least32_t mFlags;
    --        std::atomic_int_least32_t mPendingRelease;
    -+        std::atomic_int_least32_t mRemoteRefcount;
    -         int32_t unused[6]; // additional buffer space
    -     };
    - 
     diff --git a/include/media/stagefright/MediaBufferGroup.h b/include/media/stagefright/MediaBufferGroup.h
    -index dfa31b2..e0e5856 100644
    +index 3051406..e0e5856 100644
     --- a/include/media/stagefright/MediaBufferGroup.h
     +++ b/include/media/stagefright/MediaBufferGroup.h
    -@@ -49,14 +49,14 @@ public:
    +@@ -49,7 +49,10 @@ public:
          // If requestedSize is > 0, the returned MediaBuffer should have buffer
          // size of at least requstedSize.
          status_t acquire_buffer(
     -            MediaBuffer **buffer, bool nonBlocking = false, size_t requestedSize = 0);
     +            MediaBuffer **buffer, bool nonBlocking, size_t requestedSize);
    - 
    --    size_t buffers() const { return mBuffers.size(); }
    ++
     +    status_t acquire_buffer(MediaBuffer **buffer);
     +    status_t acquire_buffer(MediaBuffer **buffer, bool nonBlocking);
      
    --    // freeBuffers is the number of free buffers allowed to remain.
    --    void gc(size_t freeBuffers = 0);
    -+    size_t buffers() const { return mBuffers.size(); }
    - 
    --protected:
    -+    // If buffer is nullptr, have acquire_buffer() check for remote release.
    -     virtual void signalBufferReturned(MediaBuffer *buffer);
    - 
    - private:
    -diff --git a/include/private/media/AudioTrackShared.h b/include/private/media/AudioTrackShared.h
    -index ffdb9b5..7becf57 100644
    ---- a/include/private/media/AudioTrackShared.h
    -+++ b/include/private/media/AudioTrackShared.h
    -@@ -522,6 +522,12 @@ public:
    -         mTimestampMutator.push(timestamp);
    -     }
    - 
    -+    // Flushes the shared ring buffer if the client had requested it using mStreaming.mFlush.
    -+    // If flush occurs then:
    -+    //   cblk->u.mStreaming.mFront, ServerProxy::mFlush and ServerProxy::mFlushed will be modified
    -+    //   client will be notified via Futex
    -+    virtual void    flushBufferIfNeeded();
    -+
    -     // Total count of the number of flushed frames since creation (never reset).
    -     virtual int64_t     framesFlushed() const { return mFlushed; }
    - 
    -diff --git a/media/libeffects/visualizer/EffectVisualizer.cpp b/media/libeffects/visualizer/EffectVisualizer.cpp
    -index 91f9fc7..21fddb1 100644
    ---- a/media/libeffects/visualizer/EffectVisualizer.cpp
    -+++ b/media/libeffects/visualizer/EffectVisualizer.cpp
    -@@ -602,9 +602,14 @@ int Visualizer_command(effect_handle_t self, uint32_t cmdCode, uint32_t cmdSize,
    -     case VISUALIZER_CMD_MEASURE: {
    -         if (pReplyData == NULL || replySize == NULL ||
    -                 *replySize < (sizeof(int32_t) * MEASUREMENT_COUNT)) {
    --            ALOGV("VISUALIZER_CMD_MEASURE() error *replySize %" PRIu32
    --                    " < (sizeof(int32_t) * MEASUREMENT_COUNT) %" PRIu32, *replySize,
    --                    sizeof(int32_t) * MEASUREMENT_COUNT);
    -+            if (replySize == NULL) {
    -+                ALOGV("VISUALIZER_CMD_MEASURE() error replySize NULL");
    -+            } else {
    -+                ALOGV("VISUALIZER_CMD_MEASURE() error *replySize %" PRIu32
    -+                        " < (sizeof(int32_t) * MEASUREMENT_COUNT) %" PRIu32,
    -+                        *replySize,
    -+                        uint32_t(sizeof(int32_t)) * MEASUREMENT_COUNT);
    -+            }
    -             android_errorWriteLog(0x534e4554, "30229821");
    -             return -EINVAL;
    -         }
    -diff --git a/media/libmedia/AudioTrackShared.cpp b/media/libmedia/AudioTrackShared.cpp
    -index 7119517..846f8b8 100644
    ---- a/media/libmedia/AudioTrackShared.cpp
    -+++ b/media/libmedia/AudioTrackShared.cpp
    -@@ -622,6 +622,56 @@ ServerProxy::ServerProxy(audio_track_cblk_t* cblk, void *buffers, size_t frameCo
    - }
    - 
    - __attribute__((no_sanitize("integer")))
    -+void ServerProxy::flushBufferIfNeeded()
    -+{
    -+    audio_track_cblk_t* cblk = mCblk;
    -+    // The acquire_load is not really required. But since the write is a release_store in the
    -+    // client, using acquire_load here makes it easier for people to maintain the code,
    -+    // and the logic for communicating ipc variables seems somewhat standard,
    -+    // and there really isn't much penalty for 4 or 8 byte atomics.
    -+    int32_t flush = android_atomic_acquire_load(&cblk->u.mStreaming.mFlush);
    -+    if (flush != mFlush) {
    -+        ALOGV("ServerProxy::flushBufferIfNeeded() mStreaming.mFlush = 0x%x, mFlush = 0x%0x",
    -+                flush, mFlush);
    -+        int32_t rear = android_atomic_acquire_load(&cblk->u.mStreaming.mRear);
    -+        int32_t front = cblk->u.mStreaming.mFront;
    -+
    -+        // effectively obtain then release whatever is in the buffer
    -+        const size_t overflowBit = mFrameCountP2 << 1;
    -+        const size_t mask = overflowBit - 1;
    -+        int32_t newFront = (front & ~mask) | (flush & mask);
    -+        ssize_t filled = rear - newFront;
    -+        if (filled >= (ssize_t)overflowBit) {
    -+            // front and rear offsets span the overflow bit of the p2 mask
    -+            // so rebasing newFront on the front offset is off by the overflow bit.
    -+            // adjust newFront to match rear offset.
    -+            ALOGV("flush wrap: filled %zx >= overflowBit %zx", filled, overflowBit);
    -+            newFront += overflowBit;
    -+            filled -= overflowBit;
    -+        }
    -+        // Rather than shutting down on a corrupt flush, just treat it as a full flush
    -+        if (!(0 <= filled && (size_t) filled <= mFrameCount)) {
    -+            ALOGE("mFlush %#x -> %#x, front %#x, rear %#x, mask %#x, newFront %#x, "
    -+                    "filled %zd=%#x",
    -+                    mFlush, flush, front, rear,
    -+                    (unsigned)mask, newFront, filled, (unsigned)filled);
    -+            newFront = rear;
    -+        }
    -+        mFlush = flush;
    -+        android_atomic_release_store(newFront, &cblk->u.mStreaming.mFront);
    -+        // There is no danger from a false positive, so err on the side of caution
    -+        if (true /*front != newFront*/) {
    -+            int32_t old = android_atomic_or(CBLK_FUTEX_WAKE, &cblk->mFutex);
    -+            if (!(old & CBLK_FUTEX_WAKE)) {
    -+                (void) syscall(__NR_futex, &cblk->mFutex,
    -+                        mClientInServer ? FUTEX_WAKE_PRIVATE : FUTEX_WAKE, 1);
    -+            }
    -+        }
    -+        mFlushed += (newFront - front) & mask;
    -+    }
    -+}
    -+
    -+__attribute__((no_sanitize("integer")))
    - status_t ServerProxy::obtainBuffer(Buffer* buffer, bool ackFlush)
    - {
    -     LOG_ALWAYS_FATAL_IF(buffer == NULL || buffer->mFrameCount == 0);
    -@@ -636,44 +686,9 @@ status_t ServerProxy::obtainBuffer(Buffer* buffer, bool ackFlush)
    -     int32_t rear;
    -     // See notes on barriers at ClientProxy::obtainBuffer()
    -     if (mIsOut) {
    --        int32_t flush = cblk->u.mStreaming.mFlush;
    -+        flushBufferIfNeeded(); // might modify mFront
    -         rear = android_atomic_acquire_load(&cblk->u.mStreaming.mRear);
    -         front = cblk->u.mStreaming.mFront;
    --        if (flush != mFlush) {
    --            // effectively obtain then release whatever is in the buffer
    --            const size_t overflowBit = mFrameCountP2 << 1;
    --            const size_t mask = overflowBit - 1;
    --            int32_t newFront = (front & ~mask) | (flush & mask);
    --            ssize_t filled = rear - newFront;
    --            if (filled >= (ssize_t)overflowBit) {
    --                // front and rear offsets span the overflow bit of the p2 mask
    --                // so rebasing newFront on the front offset is off by the overflow bit.
    --                // adjust newFront to match rear offset.
    --                ALOGV("flush wrap: filled %zx >= overflowBit %zx", filled, overflowBit);
    --                newFront += overflowBit;
    --                filled -= overflowBit;
    --            }
    --            // Rather than shutting down on a corrupt flush, just treat it as a full flush
    --            if (!(0 <= filled && (size_t) filled <= mFrameCount)) {
    --                ALOGE("mFlush %#x -> %#x, front %#x, rear %#x, mask %#x, newFront %#x, "
    --                        "filled %zd=%#x",
    --                        mFlush, flush, front, rear,
    --                        (unsigned)mask, newFront, filled, (unsigned)filled);
    --                newFront = rear;
    --            }
    --            mFlush = flush;
    --            android_atomic_release_store(newFront, &cblk->u.mStreaming.mFront);
    --            // There is no danger from a false positive, so err on the side of caution
    --            if (true /*front != newFront*/) {
    --                int32_t old = android_atomic_or(CBLK_FUTEX_WAKE, &cblk->mFutex);
    --                if (!(old & CBLK_FUTEX_WAKE)) {
    --                    (void) syscall(__NR_futex, &cblk->mFutex,
    --                            mClientInServer ? FUTEX_WAKE_PRIVATE : FUTEX_WAKE, 1);
    --                }
    --            }
    --            mFlushed += (newFront - front) & mask;
    --            front = newFront;
    --        }
    -     } else {
    -         front = android_atomic_acquire_load(&cblk->u.mStreaming.mFront);
    -         rear = cblk->u.mStreaming.mRear;
    -diff --git a/media/libmedia/ICrypto.cpp b/media/libmedia/ICrypto.cpp
    -index 26dd2c9..302e6ee 100644
    ---- a/media/libmedia/ICrypto.cpp
    -+++ b/media/libmedia/ICrypto.cpp
    -@@ -150,10 +150,10 @@ struct BpCrypto : public BpInterface<ICrypto> {
    - 
    -         if (isCryptoError(result)) {
    -             errorDetailMsg->setTo(reply.readCString());
    --        }
    --
    --        if (dstType == kDestinationTypeVmPointer && result >= 0) {
    --            reply.read(dstPtr, result);
    -+        } else if (dstType == kDestinationTypeVmPointer) {
    -+            // For the non-secure case, copy the decrypted
    -+            // data from shared memory to its final destination
    -+            memcpy(dstPtr, sharedBuffer->pointer(), result);
    -         }
    - 
    -         return result;
    -@@ -369,7 +369,11 @@ status_t BnCrypto::onTransact(
    -             if (dstType == kDestinationTypeVmPointer) {
    -                 if (result >= 0) {
    -                     CHECK_LE(result, static_cast<ssize_t>(totalSize));
    --                    reply->write(dstPtr, result);
    -+                    // For the non-secure case, pass the decrypted
    -+                    // data back via the shared buffer rather than
    -+                    // copying it separately over binder to avoid
    -+                    // binder's 1MB limit.
    -+                    memcpy(sharedBuffer->pointer(), dstPtr, result);
    -                 }
    -                 free(dstPtr);
    -                 dstPtr = NULL;
    -diff --git a/media/libmedia/IMediaExtractor.cpp b/media/libmedia/IMediaExtractor.cpp
    -index e8ad75b..72d1d7c 100644
    ---- a/media/libmedia/IMediaExtractor.cpp
    -+++ b/media/libmedia/IMediaExtractor.cpp
    -@@ -160,6 +160,9 @@ status_t BnMediaExtractor::onTransact(
    -             if (data.readUint32(&idx) == NO_ERROR &&
    -                     data.readUint32(&flags) == NO_ERROR) {
    -                 sp<MetaData> meta = getTrackMetaData(idx, flags);
    -+                if (meta == NULL) {
    -+                    return UNKNOWN_ERROR;
    -+                }
    -                 meta->writeToParcel(*reply);
    -                 return NO_ERROR;
    -             }
    -diff --git a/media/libmedia/IMediaSource.cpp b/media/libmedia/IMediaSource.cpp
    -index dd94ccf..595bad9 100644
    ---- a/media/libmedia/IMediaSource.cpp
    -+++ b/media/libmedia/IMediaSource.cpp
    -@@ -58,9 +58,9 @@ public:
    - 
    - protected:
    -     virtual ~RemoteMediaBufferWrapper() {
    --        // Indicate to MediaBufferGroup to release.
    --        int32_t old = addPendingRelease(1);
    --        ALOGV("RemoteMediaBufferWrapper: releasing %p, old %d", this, old);
    -+        // Release our interest in the MediaBuffer's shared memory.
    -+        int32_t old = addRemoteRefcount(-1);
    -+        ALOGV("RemoteMediaBufferWrapper: releasing %p, refcount %d", this, old - 1);
    -         mMemory.clear(); // don't set the dead object flag.
    -     }
    - };
    -@@ -296,8 +296,8 @@ status_t BnMediaSource::onTransact(
    -         case STOP: {
    -             ALOGV("stop");
    -             CHECK_INTERFACE(IMediaSource, data, reply);
    -+            mGroup->signalBufferReturned(nullptr);
    -             status_t status = stop();
    --            mGroup->gc();
    -             mIndexCache.reset();
    -             mBuffersSinceStop = 0;
    -             return status;
    -@@ -305,6 +305,7 @@ status_t BnMediaSource::onTransact(
    -         case PAUSE: {
    -             ALOGV("pause");
    -             CHECK_INTERFACE(IMediaSource, data, reply);
    -+            mGroup->signalBufferReturned(nullptr);
    -             return pause();
    -         }
    -         case GETFORMAT: {
    -@@ -336,7 +337,7 @@ status_t BnMediaSource::onTransact(
    -                     && len == sizeof(opts)
    -                     && data.read((void *)&opts, len) == NO_ERROR;
    - 
    --            mGroup->gc(kBinderMediaBuffers /* freeBuffers */);
    -+            mGroup->signalBufferReturned(nullptr);
    -             mIndexCache.gc();
    -             size_t inlineTransferSize = 0;
    -             status_t ret = NO_ERROR;
    -@@ -411,8 +412,9 @@ status_t BnMediaSource::onTransact(
    -                     reply->writeInt32(offset);
    -                     reply->writeInt32(length);
    -                     buf->meta_data()->writeToParcel(*reply);
    -+                    transferBuf->addRemoteRefcount(1);
    -                     if (transferBuf != buf) {
    --                        buf->release();
    -+                        transferBuf->release(); // release local ref
    -                     } else if (!supportNonblockingRead()) {
    -                         maxNumBuffers = 0; // stop readMultiple with one shared buffer.
    -                     }
    -@@ -423,12 +425,12 @@ status_t BnMediaSource::onTransact(
    -                     reply->writeInt32(INLINE_BUFFER);
    -                     reply->writeByteArray(length, (uint8_t*)buf->data() + offset);
    -                     buf->meta_data()->writeToParcel(*reply);
    --                    buf->release();
    -                     inlineTransferSize += length;
    -                     if (inlineTransferSize > kInlineMaxTransfer) {
    -                         maxNumBuffers = 0; // stop readMultiple if inline transfer is too large.
    -                     }
    -                 }
    -+                buf->release();
    -             }
    -             reply->writeInt32(NULL_BUFFER); // Indicate no more MediaBuffers.
    -             reply->writeInt32(ret);
    -diff --git a/media/libmedia/ToneGenerator.cpp b/media/libmedia/ToneGenerator.cpp
    -index 2f53637..7a72237 100644
    ---- a/media/libmedia/ToneGenerator.cpp
    -+++ b/media/libmedia/ToneGenerator.cpp
    -@@ -746,7 +746,7 @@ const ToneGenerator::ToneDescriptor ToneGenerator::sToneDescriptors[] = {
    -                         { .duration = 2000, .waveFreq = { 0 }, 0, 0},
    -                         { .duration = 0, .waveFreq = { 0 }, 0, 0}},
    -           .repeatCnt = ToneGenerator::TONEGEN_INF,
    --          .repeatSegment = 0 },                              // TONE_UK_RINGTONE
    -+          .repeatSegment = 0 },                              // TONE_GB_RINGTONE
    -         { .segments = { { .duration = 400, .waveFreq = { 400, 450, 0 }, 0, 0 },
    -                         { .duration = 200, .waveFreq = { 0 }, 0, 0 },
    -                         { .duration = 400, .waveFreq = { 400, 450, 0 }, 0, 0 },
    -@@ -796,7 +796,7 @@ const unsigned char /*tone_type*/ ToneGenerator::sToneMappingTable[NUM_REGIONS-1
    -             TONE_SUP_CALL_WAITING,       // TONE_SUP_CALL_WAITING
    -             TONE_SUP_RINGTONE            // TONE_SUP_RINGTONE
    -         },
    --        {   // UK
    -+        {   // GB
    -             TONE_SUP_DIAL,               // TONE_SUP_DIAL
    -             TONE_SUP_BUSY,               // TONE_SUP_BUSY
    -             TONE_SUP_CONGESTION,         // TONE_SUP_CONGESTION
    -@@ -804,7 +804,7 @@ const unsigned char /*tone_type*/ ToneGenerator::sToneMappingTable[NUM_REGIONS-1
    -             TONE_SUP_RADIO_NOTAVAIL,     // TONE_SUP_RADIO_NOTAVAIL
    -             TONE_SUP_ERROR,              // TONE_SUP_ERROR
    -             TONE_SUP_CALL_WAITING,       // TONE_SUP_CALL_WAITING
    --            TONE_UK_RINGTONE             // TONE_SUP_RINGTONE
    -+            TONE_GB_RINGTONE             // TONE_SUP_RINGTONE
    -         },
    -         {   // AUSTRALIA
    -             TONE_ANSI_DIAL,             // TONE_SUP_DIAL
    -@@ -869,8 +869,8 @@ ToneGenerator::ToneGenerator(audio_stream_type_t streamType, float volume, bool
    -         mRegion = ANSI;
    -     } else if (strstr(value, "jp") != NULL) {
    -         mRegion = JAPAN;
    --    } else if (strstr(value, "uk") != NULL) {
    --        mRegion = UK;
    -+    } else if (strstr(value, "gb") != NULL) {
    -+        mRegion = GB;
    -     } else if (strstr(value, "au") != NULL) {
    -         mRegion = AUSTRALIA;
    -     } else {
    -@@ -1612,8 +1612,8 @@ void ToneGenerator::WaveGenerator::getSamples(short *outBuffer,
    -         lS1 = (long)0;
    -         lS2 = (long)mS2_0;
    -     } else {
    --        lS1 = (long)mS1;
    --        lS2 = (long)mS2;
    -+        lS1 = mS1;
    -+        lS2 = mS2;
    -     }
    -     lA1 = (long)mA1_Q14;
    -     lAmplitude = (long)mAmplitude_Q15;
    -@@ -1649,8 +1649,8 @@ void ToneGenerator::WaveGenerator::getSamples(short *outBuffer,
    -     }
    - 
    -     // save status
    --    mS1 = (short)lS1;
    --    mS2 = (short)lS2;
    -+    mS1 = lS1;
    -+    mS2 = lS2;
    - }
    - 
    - }  // end namespace android
    -diff --git a/media/libmedia/Visualizer.cpp b/media/libmedia/Visualizer.cpp
    -index 31e310b..37bf0bd 100644
    ---- a/media/libmedia/Visualizer.cpp
    -+++ b/media/libmedia/Visualizer.cpp
    -@@ -55,7 +55,7 @@ Visualizer::~Visualizer()
    - {
    -     ALOGV("Visualizer::~Visualizer()");
    -     setEnabled(false);
    --    setCaptureCallBack(NULL, NULL, 0, 0, true);
    -+    setCaptureCallBack(NULL, NULL, 0, 0);
    - }
    - 
    - status_t Visualizer::setEnabled(bool enabled)
    -@@ -77,13 +77,11 @@ status_t Visualizer::setEnabled(bool enabled)
    - 
    -     status_t status = AudioEffect::setEnabled(enabled);
    - 
    --    if (status == NO_ERROR) {
    --        if (t != 0) {
    --            if (enabled) {
    --                t->run("Visualizer");
    --            } else {
    --                t->requestExit();
    --            }
    -+    if (t != 0) {
    -+        if (enabled && status == NO_ERROR) {
    -+            t->run("Visualizer");
    -+        } else {
    -+            t->requestExit();
    -         }
    -     }
    - 
    -@@ -95,14 +93,14 @@ status_t Visualizer::setEnabled(bool enabled)
    - }
    - 
    - status_t Visualizer::setCaptureCallBack(capture_cbk_t cbk, void* user, uint32_t flags,
    --        uint32_t rate, bool force)
    -+        uint32_t rate)
    - {
    -     if (rate > CAPTURE_RATE_MAX) {
    -         return BAD_VALUE;
    -     }
    -     Mutex::Autolock _l(mCaptureLock);
    - 
    --    if (force || mEnabled) {
    -+    if (mEnabled) {
    -         return INVALID_OPERATION;
    -     }
    - 
    -diff --git a/media/libmediaplayerservice/nuplayer/HTTPLiveSource.cpp b/media/libmediaplayerservice/nuplayer/HTTPLiveSource.cpp
    -index 3fffdc1..5027e01 100644
    ---- a/media/libmediaplayerservice/nuplayer/HTTPLiveSource.cpp
    -+++ b/media/libmediaplayerservice/nuplayer/HTTPLiveSource.cpp
    -@@ -30,6 +30,7 @@
    - #include <media/stagefright/MediaErrors.h>
    - #include <media/stagefright/MetaData.h>
    - #include <media/stagefright/MediaDefs.h>
    -+#include <media/stagefright/Utils.h>
    - 
    - namespace android {
    - 
    -@@ -100,26 +101,38 @@ void NuPlayer::HTTPLiveSource::prepareAsync() {
    - void NuPlayer::HTTPLiveSource::start() {
    - }
    - 
    -+sp<MetaData> NuPlayer::HTTPLiveSource::getFormatMeta(bool audio) {
    -+    sp<MetaData> meta;
    -+    if (mLiveSession != NULL) {
    -+        mLiveSession->getStreamFormatMeta(
    -+                audio ? LiveSession::STREAMTYPE_AUDIO
    -+                      : LiveSession::STREAMTYPE_VIDEO,
    -+                &meta);
    -+    }
    -+
    -+    return meta;
    -+}
    -+
    - sp<AMessage> NuPlayer::HTTPLiveSource::getFormat(bool audio) {
    --    sp<AMessage> format;
    -+    sp<MetaData> meta;
    -     status_t err = -EWOULDBLOCK;
    -     if (mLiveSession != NULL) {
    --        err = mLiveSession->getStreamFormat(
    -+        err = mLiveSession->getStreamFormatMeta(
    -                 audio ? LiveSession::STREAMTYPE_AUDIO
    -                       : LiveSession::STREAMTYPE_VIDEO,
    --                &format);
    -+                &meta);
    -     }
    - 
    -+    sp<AMessage> format;
    -     if (err == -EWOULDBLOCK) {
    -         format = new AMessage();
    -         format->setInt32("err", err);
    -         return format;
    -     }
    - 
    --    if (err != OK) {
    -+    if (err != OK || convertMetaDataToMessage(meta, &format) != OK) {
    -         return NULL;
    -     }
    --
    -     return format;
    - }
    - 
    -diff --git a/media/libmediaplayerservice/nuplayer/HTTPLiveSource.h b/media/libmediaplayerservice/nuplayer/HTTPLiveSource.h
    -index 9e0ec2f..574937d 100644
    ---- a/media/libmediaplayerservice/nuplayer/HTTPLiveSource.h
    -+++ b/media/libmediaplayerservice/nuplayer/HTTPLiveSource.h
    -@@ -38,6 +38,7 @@ struct NuPlayer::HTTPLiveSource : public NuPlayer::Source {
    -     virtual void start();
    - 
    -     virtual status_t dequeueAccessUnit(bool audio, sp<ABuffer> *accessUnit);
    -+    virtual sp<MetaData> getFormatMeta(bool audio);
    -     virtual sp<AMessage> getFormat(bool audio);
    - 
    -     virtual status_t feedMoreTSData();
    -diff --git a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp
    -index 134da14..dc4e5d4 100644
    ---- a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp
    -+++ b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp
    -@@ -1339,7 +1339,16 @@ void NuPlayer::onStart(int64_t startPositionUs) {
    -     }
    - 
    -     sp<MetaData> audioMeta = mSource->getFormatMeta(true /* audio */);
    -+    sp<MetaData> videoMeta = mSource->getFormatMeta(false /* audio */);
    -+    if (audioMeta == NULL && videoMeta == NULL) {
    -+        ALOGE("no metadata for either audio or video source");
    -+        mSource->stop();
    -+        mSourceStarted = false;
    -+        notifyListener(MEDIA_ERROR, MEDIA_ERROR_UNKNOWN, ERROR_MALFORMED);
    -+        return;
    -+    }
    -     ALOGV_IF(audioMeta == NULL, "no metadata for audio source");  // video only stream
    -+
    -     audio_stream_type_t streamType = AUDIO_STREAM_MUSIC;
    -     if (mAudioSink != NULL) {
    -         streamType = mAudioSink->getAudioStreamType();
    -diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp b/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp
    -index cf38efc..594128c 100644
    ---- a/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp
    -+++ b/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp
    -@@ -754,7 +754,7 @@ bool NuPlayer::Decoder::isStaleReply(const sp<AMessage> &msg) {
    - 
    - status_t NuPlayer::Decoder::fetchInputData(sp<AMessage> &reply) {
    -     sp<ABuffer> accessUnit;
    --    bool dropAccessUnit;
    -+    bool dropAccessUnit = true;
    -     do {
    -         status_t err = mSource->dequeueAccessUnit(mIsAudio, &accessUnit);
    - 
    -diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp b/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp
    -index b47a4f1..b742762 100644
    ---- a/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp
    -+++ b/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp
    -@@ -141,6 +141,17 @@ NuPlayer::Renderer::~Renderer() {
    -         mAudioSink->flush();
    -         mAudioSink->close();
    -     }
    -+
    -+    // Try to avoid racing condition in case callback is still on.
    -+    Mutex::Autolock autoLock(mLock);
    -+    mUseAudioCallback = false;
    -+    flushQueue(&mAudioQueue);
    -+    flushQueue(&mVideoQueue);
    -+    mWakeLock.clear();
    -+    mMediaClock.clear();
    -+    mVideoScheduler.clear();
    -+    mNotify.clear();
    -+    mAudioSink.clear();
    - }
    - 
    - void NuPlayer::Renderer::queueBuffer(
    -@@ -744,7 +755,7 @@ size_t NuPlayer::Renderer::AudioSinkCallback(
    -         case MediaPlayerBase::AudioSink::CB_EVENT_STREAM_END:
    -         {
    -             ALOGV("AudioSink::CB_EVENT_STREAM_END");
    --            me->notifyEOS(true /* audio */, ERROR_END_OF_STREAM);
    -+            me->notifyEOSCallback();
    -             break;
    -         }
    - 
    -@@ -759,6 +770,16 @@ size_t NuPlayer::Renderer::AudioSinkCallback(
    -     return 0;
    - }
    - 
    -+void NuPlayer::Renderer::notifyEOSCallback() {
    -+    Mutex::Autolock autoLock(mLock);
    -+
    -+    if (!mUseAudioCallback) {
    -+        return;
    -+    }
    -+
    -+    notifyEOS(true /* audio */, ERROR_END_OF_STREAM);
    -+}
    -+
    - size_t NuPlayer::Renderer::fillAudioBuffer(void *buffer, size_t size) {
    -     Mutex::Autolock autoLock(mLock);
    - 
    -@@ -1190,8 +1211,10 @@ void NuPlayer::Renderer::postDrainVideoQueue() {
    -             msg->setWhat(kWhatPostDrainVideoQueue);
    -             msg->post(postDelayUs);
    -             mVideoScheduler->restart();
    --            ALOGI("possible video time jump of %dms or uninitialized media clock, retrying in %dms",
    --                    (int)(delayUs / 1000), (int)(postDelayUs / 1000));
    -+            ALOGI("possible video time jump of %dms (%lld : %lld) or uninitialized media clock,"
    -+                    " retrying in %dms",
    -+                    (int)(delayUs / 1000), (long long)mediaTimeUs,
    -+                    (long long)mAudioFirstAnchorTimeMediaUs, (int)(postDelayUs / 1000));
    -             mDrainVideoQueuePending = true;
    -             return;
    -         }
    -diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.h b/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.h
    -index 004e21c..fe7f8fa 100644
    ---- a/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.h
    -+++ b/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.h
    -@@ -212,6 +212,7 @@ private:
    -     status_t getCurrentPositionFromAnchor(
    -             int64_t *mediaUs, int64_t nowUs, bool allowPastQueuedVideo = false);
    - 
    -+    void notifyEOSCallback();
    -     size_t fillAudioBuffer(void *buffer, size_t size);
    - 
    -     bool onDrainAudioQueue();
    -diff --git a/media/libmediaplayerservice/nuplayer/RTSPSource.cpp b/media/libmediaplayerservice/nuplayer/RTSPSource.cpp
    -index 8a305de..c4e5df7 100644
    ---- a/media/libmediaplayerservice/nuplayer/RTSPSource.cpp
    -+++ b/media/libmediaplayerservice/nuplayer/RTSPSource.cpp
    -@@ -58,6 +58,7 @@ NuPlayer::RTSPSource::RTSPSource(
    -       mDisconnectReplyID(0),
    -       mBuffering(false),
    -       mInPreparationPhase(true),
    -+      mEOSPending(false),
    -       mSeekGeneration(0),
    -       mEOSTimeoutAudio(0),
    -       mEOSTimeoutVideo(0) {
    -@@ -200,34 +201,28 @@ status_t NuPlayer::RTSPSource::dequeueAccessUnit(
    -     status_t finalResult;
    -     if (!source->hasBufferAvailable(&finalResult)) {
    -         if (finalResult == OK) {
    --            int64_t mediaDurationUs = 0;
    --            getDuration(&mediaDurationUs);
    --            sp<AnotherPacketSource> otherSource = getSource(!audio);
    --            status_t otherFinalResult;
    --
    --            // If other source already signaled EOS, this source should also signal EOS
    --            if (otherSource != NULL &&
    --                    !otherSource->hasBufferAvailable(&otherFinalResult) &&
    --                    otherFinalResult == ERROR_END_OF_STREAM) {
    --                source->signalEOS(ERROR_END_OF_STREAM);
    -+
    -+            // If other source already signaled EOS, this source should also return EOS
    -+            if (sourceReachedEOS(!audio)) {
    -                 return ERROR_END_OF_STREAM;
    -             }
    - 
    -             // If this source has detected near end, give it some time to retrieve more
    --            // data before signaling EOS
    -+            // data before returning EOS
    -+            int64_t mediaDurationUs = 0;
    -+            getDuration(&mediaDurationUs);
    -             if (source->isFinished(mediaDurationUs)) {
    -                 int64_t eosTimeout = audio ? mEOSTimeoutAudio : mEOSTimeoutVideo;
    -                 if (eosTimeout == 0) {
    -                     setEOSTimeout(audio, ALooper::GetNowUs());
    -                 } else if ((ALooper::GetNowUs() - eosTimeout) > kNearEOSTimeoutUs) {
    -                     setEOSTimeout(audio, 0);
    --                    source->signalEOS(ERROR_END_OF_STREAM);
    -                     return ERROR_END_OF_STREAM;
    -                 }
    -                 return -EWOULDBLOCK;
    -             }
    - 
    --            if (!(otherSource != NULL && otherSource->isFinished(mediaDurationUs))) {
    -+            if (!sourceNearEOS(!audio)) {
    -                 // We should not enter buffering mode
    -                 // if any of the sources already have detected EOS.
    -                 startBufferingIfNecessary();
    -@@ -306,6 +301,7 @@ void NuPlayer::RTSPSource::performSeek(int64_t seekTimeUs) {
    - 
    -     mState = SEEKING;
    -     mHandler->seek(seekTimeUs);
    -+    mEOSPending = false;
    - }
    - 
    - void NuPlayer::RTSPSource::schedulePollBuffering() {
    -@@ -314,10 +310,10 @@ void NuPlayer::RTSPSource::schedulePollBuffering() {
    - }
    - 
    - void NuPlayer::RTSPSource::checkBuffering(
    --        bool *prepared, bool *underflow, bool *overflow, bool *startServer) {
    -+        bool *prepared, bool *underflow, bool *overflow, bool *startServer, bool *finished) {
    -     size_t numTracks = mTracks.size();
    --    size_t preparedCount, underflowCount, overflowCount, startCount;
    --    preparedCount = underflowCount = overflowCount = startCount = 0;
    -+    size_t preparedCount, underflowCount, overflowCount, startCount, finishedCount;
    -+    preparedCount = underflowCount = overflowCount = startCount = finishedCount = 0;
    - 
    -     size_t count = numTracks;
    -     for (size_t i = 0; i < count; ++i) {
    -@@ -337,6 +333,7 @@ void NuPlayer::RTSPSource::checkBuffering(
    - 
    -         if (src->isFinished(/* duration */ 0)) {
    -             ++overflowCount;
    -+            ++finishedCount;
    -         } else {
    -             if (bufferedDurationUs < kUnderflowMarkUs) {
    -                 ++underflowCount;
    -@@ -354,11 +351,12 @@ void NuPlayer::RTSPSource::checkBuffering(
    -     *underflow   = (underflowCount > 0);
    -     *overflow    = (overflowCount == numTracks);
    -     *startServer = (startCount > 0);
    -+    *finished    = (finishedCount > 0);
    - }
    - 
    - void NuPlayer::RTSPSource::onPollBuffering() {
    --    bool prepared, underflow, overflow, startServer;
    --    checkBuffering(&prepared, &underflow, &overflow, &startServer);
    -+    bool prepared, underflow, overflow, startServer, finished;
    -+    checkBuffering(&prepared, &underflow, &overflow, &startServer, &finished);
    - 
    -     if (prepared && mInPreparationPhase) {
    -         mInPreparationPhase = false;
    -@@ -369,8 +367,11 @@ void NuPlayer::RTSPSource::onPollBuffering() {
    -         startBufferingIfNecessary();
    -     }
    - 
    --    if (overflow && mHandler != NULL) {
    -+    if (haveSufficientDataOnAllTracks()) {
    -         stopBufferingIfNecessary();
    -+    }
    -+
    -+    if (overflow && mHandler != NULL) {
    -         mHandler->pause();
    -     }
    - 
    -@@ -378,9 +379,72 @@ void NuPlayer::RTSPSource::onPollBuffering() {
    -         mHandler->resume();
    -     }
    - 
    -+    if (finished && mHandler != NULL) {
    -+        mHandler->cancelAccessUnitTimeoutCheck();
    -+    }
    -+
    -     schedulePollBuffering();
    - }
    - 
    -+void NuPlayer::RTSPSource::signalSourceEOS(status_t result) {
    -+    const bool audio = true;
    -+    const bool video = false;
    -+
    -+    sp<AnotherPacketSource> source = getSource(audio);
    -+    if (source != NULL) {
    -+        source->signalEOS(result);
    -+    }
    -+
    -+    source = getSource(video);
    -+    if (source != NULL) {
    -+        source->signalEOS(result);
    -+    }
    -+}
    -+
    -+bool NuPlayer::RTSPSource::sourceReachedEOS(bool audio) {
    -+    sp<AnotherPacketSource> source = getSource(audio);
    -+    status_t finalResult;
    -+    return (source != NULL &&
    -+            !source->hasBufferAvailable(&finalResult) &&
    -+            finalResult == ERROR_END_OF_STREAM);
    -+}
    -+
    -+bool NuPlayer::RTSPSource::sourceNearEOS(bool audio) {
    -+    sp<AnotherPacketSource> source = getSource(audio);
    -+    int64_t mediaDurationUs = 0;
    -+    getDuration(&mediaDurationUs);
    -+    return (source != NULL && source->isFinished(mediaDurationUs));
    -+}
    -+
    -+void NuPlayer::RTSPSource::onSignalEOS(const sp<AMessage> &msg) {
    -+    int32_t generation;
    -+    CHECK(msg->findInt32("generation", &generation));
    -+
    -+    if (generation != mSeekGeneration) {
    -+        return;
    -+    }
    -+
    -+    if (mEOSPending) {
    -+        signalSourceEOS(ERROR_END_OF_STREAM);
    -+        mEOSPending = false;
    -+    }
    -+}
    -+
    -+void NuPlayer::RTSPSource::postSourceEOSIfNecessary() {
    -+    const bool audio = true;
    -+    const bool video = false;
    -+    // If a source has detected near end, give it some time to retrieve more
    -+    // data before signaling EOS
    -+    if (sourceNearEOS(audio) || sourceNearEOS(video)) {
    -+        if (!mEOSPending) {
    -+            sp<AMessage> msg = new AMessage(kWhatSignalEOS, this);
    -+            msg->setInt32("generation", mSeekGeneration);
    -+            msg->post(kNearEOSTimeoutUs);
    -+            mEOSPending = true;
    -+        }
    -+    }
    -+}
    -+
    - void NuPlayer::RTSPSource::onMessageReceived(const sp<AMessage> &msg) {
    -     if (msg->what() == kWhatDisconnect) {
    -         sp<AReplyToken> replyID;
    -@@ -408,6 +472,9 @@ void NuPlayer::RTSPSource::onMessageReceived(const sp<AMessage> &msg) {
    -     } else if (msg->what() == kWhatPollBuffering) {
    -         onPollBuffering();
    -         return;
    -+    } else if (msg->what() == kWhatSignalEOS) {
    -+        onSignalEOS(msg);
    -+        return;
    -     }
    - 
    -     CHECK_EQ(msg->what(), (int)kWhatNotify);
    -@@ -517,16 +584,10 @@ void NuPlayer::RTSPSource::onMessageReceived(const sp<AMessage> &msg) {
    -                 }
    - 
    -                 if (err != OK) {
    --                    sp<AnotherPacketSource> source = getSource(false /* audio */);
    --                    if (source != NULL) {
    --                        source->signalEOS(err);
    --                    }
    --
    --                    source = getSource(true /* audio */);
    --                    if (source != NULL) {
    --                        source->signalEOS(err);
    --                    }
    -+                    signalSourceEOS(err);
    -                 }
    -+
    -+                postSourceEOSIfNecessary();
    -                 break;
    -             }
    - 
    -@@ -554,6 +615,7 @@ void NuPlayer::RTSPSource::onMessageReceived(const sp<AMessage> &msg) {
    - 
    -                 source->queueAccessUnit(accessUnit);
    -             }
    -+            postSourceEOSIfNecessary();
    -             break;
    -         }
    - 
    -@@ -564,17 +626,7 @@ void NuPlayer::RTSPSource::onMessageReceived(const sp<AMessage> &msg) {
    -             CHECK_NE(finalResult, (status_t)OK);
    - 
    -             if (mTSParser != NULL) {
    --                sp<AnotherPacketSource> source = getSource(false /* audio */);
    --                if (source != NULL) {
    --                    source->signalEOS(finalResult);
    --                }
    --
    --                source = getSource(true /* audio */);
    --                if (source != NULL) {
    --                    source->signalEOS(finalResult);
    --                }
    --
    --                return;
    -+                signalSourceEOS(finalResult);
    -             }
    - 
    -             size_t trackIndex;
    -diff --git a/media/libmediaplayerservice/nuplayer/RTSPSource.h b/media/libmediaplayerservice/nuplayer/RTSPSource.h
    -index a6a7644..c7834ef 100644
    ---- a/media/libmediaplayerservice/nuplayer/RTSPSource.h
    -+++ b/media/libmediaplayerservice/nuplayer/RTSPSource.h
    -@@ -64,6 +64,7 @@ private:
    -         kWhatDisconnect      = 'disc',
    -         kWhatPerformSeek     = 'seek',
    -         kWhatPollBuffering   = 'poll',
    -+        kWhatSignalEOS       = 'eos ',
    -     };
    - 
    -     enum State {
    -@@ -106,6 +107,7 @@ private:
    -     Mutex mBufferingLock;
    -     bool mBuffering;
    -     bool mInPreparationPhase;
    -+    bool mEOSPending;
    - 
    -     sp<ALooper> mLooper;
    -     sp<MyHandler> mHandler;
    -@@ -133,7 +135,12 @@ private:
    - 
    -     void performSeek(int64_t seekTimeUs);
    -     void schedulePollBuffering();
    --    void checkBuffering(bool *prepared, bool *underflow, bool *overflow, bool *startServer);
    -+    void checkBuffering(
    -+            bool *prepared,
    -+            bool *underflow,
    -+            bool *overflow,
    -+            bool *startServer,
    -+            bool *finished);
    -     void onPollBuffering();
    - 
    -     bool haveSufficientDataOnAllTracks();
    -@@ -144,6 +151,13 @@ private:
    -     bool stopBufferingIfNecessary();
    -     void finishSeek(status_t err);
    - 
    -+    void postSourceEOSIfNecessary();
    -+    void signalSourceEOS(status_t result);
    -+    void onSignalEOS(const sp<AMessage> &msg);
    -+
    -+    bool sourceNearEOS(bool audio);
    -+    bool sourceReachedEOS(bool audio);
    -+
    -     DISALLOW_EVIL_CONSTRUCTORS(RTSPSource);
    - };
    +     size_t buffers() const { return mBuffers.size(); }
      
     diff --git a/media/libstagefright/ACodec.cpp b/media/libstagefright/ACodec.cpp
     index 37fd5a5..706ba4e 100644
    @@ -1554,20 +151,10 @@ index 3848502..c06f6a4 100644
      
      # enable experiments only in userdebug and eng builds
     diff --git a/media/libstagefright/CameraSource.cpp b/media/libstagefright/CameraSource.cpp
    -index e087249..c9f60ec 100644
    +index 893da89..c9f60ec 100644
     --- a/media/libstagefright/CameraSource.cpp
     +++ b/media/libstagefright/CameraSource.cpp
    -@@ -1117,6 +1117,9 @@ void CameraSource::releaseRecordingFrameHandle(native_handle_t* handle) {
    -         int64_t token = IPCThreadState::self()->clearCallingIdentity();
    -         mCamera->releaseRecordingFrameHandle(handle);
    -         IPCThreadState::self()->restoreCallingIdentity(token);
    -+    } else {
    -+        native_handle_close(handle);
    -+        native_handle_delete(handle);
    -     }
    - }
    - 
    -@@ -1247,6 +1250,10 @@ void CameraSource::processBufferQueueFrame(BufferItem& buffer) {
    +@@ -1250,6 +1250,10 @@ void CameraSource::processBufferQueueFrame(BufferItem& buffer) {
      MetadataBufferType CameraSource::metaDataStoredInVideoBuffers() const {
          ALOGV("metaDataStoredInVideoBuffers");
      
    @@ -1578,418 +165,6 @@ index e087249..c9f60ec 100644
          // Output buffers will contain metadata if camera sends us buffer in metadata mode or via
          // buffer queue.
          switch (mVideoBufferMode) {
    -diff --git a/media/libstagefright/MPEG4Extractor.cpp b/media/libstagefright/MPEG4Extractor.cpp
    -index 70a294c..f42fbcf 100644
    ---- a/media/libstagefright/MPEG4Extractor.cpp
    -+++ b/media/libstagefright/MPEG4Extractor.cpp
    -@@ -374,7 +374,6 @@ MPEG4Extractor::MPEG4Extractor(const sp<DataSource> &source)
    -       mMdatFound(false),
    -       mDataSource(source),
    -       mInitCheck(NO_INIT),
    --      mHasVideo(false),
    -       mHeaderTimescale(0),
    -       mIsQT(false),
    -       mFirstTrack(NULL),
    -@@ -479,7 +478,8 @@ sp<MetaData> MPEG4Extractor::getTrackMetaData(
    -             } else {
    -                 uint32_t sampleIndex;
    -                 uint32_t sampleTime;
    --                if (track->sampleTable->findThumbnailSample(&sampleIndex) == OK
    -+                if (track->timescale != 0 &&
    -+                        track->sampleTable->findThumbnailSample(&sampleIndex) == OK
    -                         && track->sampleTable->getMetaDataForSample(
    -                             sampleIndex, NULL /* offset */, NULL /* size */,
    -                             &sampleTime) == OK) {
    -@@ -545,11 +545,13 @@ status_t MPEG4Extractor::readMetaData() {
    -     }
    - 
    -     if (mInitCheck == OK) {
    --        if (mHasVideo) {
    -+        if (findTrackByMimePrefix("video/") != NULL) {
    -             mFileMetaData->setCString(
    -                     kKeyMIMEType, MEDIA_MIMETYPE_CONTAINER_MPEG4);
    --        } else {
    -+        } else if (findTrackByMimePrefix("audio/") != NULL) {
    -             mFileMetaData->setCString(kKeyMIMEType, "audio/mp4");
    -+        } else {
    -+            mFileMetaData->setCString(kKeyMIMEType, "application/octet-stream");
    -         }
    -     } else {
    -         mInitCheck = err;
    -@@ -929,6 +931,10 @@ status_t MPEG4Extractor::parseChunk(off64_t *offset, int depth) {
    -         case FOURCC('e', 'd', 't', 's'):
    -         case FOURCC('w', 'a', 'v', 'e'):
    -         {
    -+            if (chunk_type == FOURCC('m', 'o', 'o', 'v') && depth != 0) {
    -+                ALOGE("moov: depth %d", depth);
    -+                return ERROR_MALFORMED;
    -+            }
    -             if (chunk_type == FOURCC('m', 'o', 'o', 'f') && !mMoofFound) {
    -                 // store the offset of the first segment
    -                 mMoofFound = true;
    -@@ -957,6 +963,10 @@ status_t MPEG4Extractor::parseChunk(off64_t *offset, int depth) {
    - 
    -             bool isTrack = false;
    -             if (chunk_type == FOURCC('t', 'r', 'a', 'k')) {
    -+                if (depth != 1) {
    -+                    ALOGE("trak: depth %d", depth);
    -+                    return ERROR_MALFORMED;
    -+                }
    -                 isTrack = true;
    - 
    -                 Track *track = new Track;
    -@@ -980,6 +990,10 @@ status_t MPEG4Extractor::parseChunk(off64_t *offset, int depth) {
    -             while (*offset < stop_offset) {
    -                 status_t err = parseChunk(offset, depth + 1);
    -                 if (err != OK) {
    -+                    if (isTrack) {
    -+                        mLastTrack->skipTrack = true;
    -+                        break;
    -+                    }
    -                     return err;
    -                 }
    -             }
    -@@ -1325,10 +1339,6 @@ status_t MPEG4Extractor::parseChunk(off64_t *offset, int depth) {
    - 
    -         case FOURCC('s', 't', 's', 'd'):
    -         {
    --            if (chunk_data_size < 8) {
    --                return ERROR_MALFORMED;
    --            }
    --
    -             uint8_t buffer[8];
    -             if (chunk_data_size < (off64_t)sizeof(buffer)) {
    -                 return ERROR_MALFORMED;
    -@@ -1481,8 +1491,6 @@ status_t MPEG4Extractor::parseChunk(off64_t *offset, int depth) {
    -         case FOURCC('h', 'v', 'c', '1'):
    -         case FOURCC('h', 'e', 'v', '1'):
    -         {
    --            mHasVideo = true;
    --
    -             uint8_t buffer[78];
    -             if (chunk_data_size < (ssize_t)sizeof(buffer)) {
    -                 // Basic VideoSampleEntry size.
    -@@ -1825,6 +1833,9 @@ status_t MPEG4Extractor::parseChunk(off64_t *offset, int depth) {
    -         case FOURCC('b', 't', 'r', 't'):
    -         {
    -             *offset += chunk_size;
    -+            if (mLastTrack == NULL) {
    -+                return ERROR_MALFORMED;
    -+            }
    - 
    -             uint8_t buffer[12];
    -             if (chunk_data_size != sizeof(buffer)) {
    -@@ -1994,6 +2005,10 @@ status_t MPEG4Extractor::parseChunk(off64_t *offset, int depth) {
    -         {
    -             *offset += chunk_size;
    - 
    -+            if (depth != 1) {
    -+                ALOGE("mvhd: depth %d", depth);
    -+                return ERROR_MALFORMED;
    -+            }
    -             if (chunk_data_size < 32) {
    -                 return ERROR_MALFORMED;
    -             }
    -@@ -4121,11 +4136,13 @@ status_t MPEG4Source::parseTrackFragmentRun(off64_t offset, off64_t size) {
    -     if (!mDataSource->getUInt32(offset, &flags)) {
    -         return ERROR_MALFORMED;
    -     }
    --    ALOGV("fragment run flags: %08x", flags);
    --
    --    if (flags & 0xff000000) {
    --        return -EINVAL;
    --    }
    -+    // |version| only affects SampleCompositionTimeOffset field.
    -+    // If version == 0, SampleCompositionTimeOffset is uint32_t;
    -+    // Otherwise, SampleCompositionTimeOffset is int32_t.
    -+    // Sample.compositionOffset is defined as int32_t.
    -+    uint8_t version = flags >> 24;
    -+    flags &= 0xffffff;
    -+    ALOGV("fragment run version: 0x%02x, flags: 0x%06x", version, flags);
    - 
    -     if ((flags & kFirstSampleFlagsPresent) && (flags & kSampleFlagsPresent)) {
    -         // These two shall not be used together.
    -diff --git a/media/libstagefright/MPEG4Writer.cpp b/media/libstagefright/MPEG4Writer.cpp
    -index 4681abd..5e96c2b 100644
    ---- a/media/libstagefright/MPEG4Writer.cpp
    -+++ b/media/libstagefright/MPEG4Writer.cpp
    -@@ -272,6 +272,7 @@ private:
    -     bool mIsHevc;
    -     bool mIsAudio;
    -     bool mIsMPEG4;
    -+    bool mIsMalformed;
    -     int32_t mTrackId;
    -     int64_t mTrackDurationUs;
    -     int64_t mMaxChunkDurationUs;
    -@@ -1536,6 +1537,7 @@ MPEG4Writer::Track::Track(
    -       mPaused(false),
    -       mResumed(false),
    -       mStarted(false),
    -+      mIsMalformed(false),
    -       mTrackId(trackId),
    -       mTrackDurationUs(0),
    -       mEstimatedTrackSizeBytes(0),
    -@@ -2479,12 +2481,16 @@ status_t MPEG4Writer::Track::threadEntry() {
    -             ALOGW("Recorded file size exceeds limit %" PRId64 "bytes",
    -                     mOwner->mMaxFileSizeLimitBytes);
    -             mOwner->notify(MEDIA_RECORDER_EVENT_INFO, MEDIA_RECORDER_INFO_MAX_FILESIZE_REACHED, 0);
    -+            copy->release();
    -+            mSource->stop();
    -             break;
    -         }
    -         if (mOwner->exceedsFileDurationLimit()) {
    -             ALOGW("Recorded file duration exceeds limit %" PRId64 "microseconds",
    -                     mOwner->mMaxFileDurationLimitUs);
    -             mOwner->notify(MEDIA_RECORDER_EVENT_INFO, MEDIA_RECORDER_INFO_MAX_DURATION_REACHED, 0);
    -+            copy->release();
    -+            mSource->stop();
    -             break;
    -         }
    - 
    -@@ -2505,13 +2511,17 @@ status_t MPEG4Writer::Track::threadEntry() {
    -             int64_t durExcludingEarlierPausesUs = timestampUs - previousPausedDurationUs;
    -             if (WARN_UNLESS(durExcludingEarlierPausesUs >= 0ll, "for %s track", trackName)) {
    -                 copy->release();
    --                return ERROR_MALFORMED;
    -+                mSource->stop();
    -+                mIsMalformed = true;
    -+                break;
    -             }
    - 
    -             int64_t pausedDurationUs = durExcludingEarlierPausesUs - mTrackDurationUs;
    -             if (WARN_UNLESS(pausedDurationUs >= lastDurationUs, "for %s track", trackName)) {
    -                 copy->release();
    --                return ERROR_MALFORMED;
    -+                mSource->stop();
    -+                mIsMalformed = true;
    -+                break;
    -             }
    - 
    -             previousPausedDurationUs += pausedDurationUs - lastDurationUs;
    -@@ -2521,7 +2531,9 @@ status_t MPEG4Writer::Track::threadEntry() {
    -         timestampUs -= previousPausedDurationUs;
    -         if (WARN_UNLESS(timestampUs >= 0ll, "for %s track", trackName)) {
    -             copy->release();
    --            return ERROR_MALFORMED;
    -+            mSource->stop();
    -+            mIsMalformed = true;
    -+            break;
    -         }
    - 
    -         if (!mIsAudio) {
    -@@ -2548,7 +2560,9 @@ status_t MPEG4Writer::Track::threadEntry() {
    -                     timestampUs + kMaxCttsOffsetTimeUs - decodingTimeUs;
    -             if (WARN_UNLESS(cttsOffsetTimeUs >= 0ll, "for %s track", trackName)) {
    -                 copy->release();
    --                return ERROR_MALFORMED;
    -+                mSource->stop();
    -+                mIsMalformed = true;
    -+                break;
    -             }
    - 
    -             timestampUs = decodingTimeUs;
    -@@ -2560,7 +2574,9 @@ status_t MPEG4Writer::Track::threadEntry() {
    -                     (cttsOffsetTimeUs * mTimeScale + 500000LL) / 1000000LL;
    -             if (WARN_UNLESS(currCttsOffsetTimeTicks <= 0x0FFFFFFFFLL, "for %s track", trackName)) {
    -                 copy->release();
    --                return ERROR_MALFORMED;
    -+                mSource->stop();
    -+                mIsMalformed = true;
    -+                break;
    -             }
    - 
    -             if (mStszTableEntries->count() == 0) {
    -@@ -2602,7 +2618,9 @@ status_t MPEG4Writer::Track::threadEntry() {
    - 
    -         if (WARN_UNLESS(timestampUs >= 0ll, "for %s track", trackName)) {
    -             copy->release();
    --            return ERROR_MALFORMED;
    -+            mSource->stop();
    -+            mIsMalformed = true;
    -+            break;
    -         }
    - 
    -         ALOGV("%s media time stamp: %" PRId64 " and previous paused duration %" PRId64,
    -@@ -2624,7 +2642,8 @@ status_t MPEG4Writer::Track::threadEntry() {
    -                     (long long)timestampUs, (long long)lastTimestampUs, trackName);
    -             copy->release();
    -             mSource->stop();
    --            return UNKNOWN_ERROR;
    -+            mIsMalformed = true;
    -+            break;
    -         }
    - 
    -         // if the duration is different for this sample, see if it is close enough to the previous
    -@@ -2780,6 +2799,10 @@ status_t MPEG4Writer::Track::threadEntry() {
    - }
    - 
    - bool MPEG4Writer::Track::isTrackMalFormed() const {
    -+    if (mIsMalformed) {
    -+        return true;
    -+    }
    -+
    -     if (mStszTableEntries->count() == 0) {                      // no samples written
    -         ALOGE("The number of recorded samples is 0");
    -         return true;
    -diff --git a/media/libstagefright/MediaCodec.cpp b/media/libstagefright/MediaCodec.cpp
    -index ff5c4d4..e476424 100644
    ---- a/media/libstagefright/MediaCodec.cpp
    -+++ b/media/libstagefright/MediaCodec.cpp
    -@@ -2160,14 +2160,19 @@ void MediaCodec::onMessageReceived(const sp<AMessage> &msg) {
    -             CHECK(msg->findPointer("buffers", (void **)&dstBuffers));
    - 
    -             dstBuffers->clear();
    --            const Vector<BufferInfo> &srcBuffers = mPortBuffers[portIndex];
    --
    --            for (size_t i = 0; i < srcBuffers.size(); ++i) {
    --                const BufferInfo &info = srcBuffers.itemAt(i);
    --
    --                dstBuffers->push_back(
    --                        (portIndex == kPortIndexInput && mCrypto != NULL)
    --                                ? info.mEncryptedData : info.mData);
    -+            // If we're using input surface (either non-persistent created by
    -+            // createInputSurface(), or persistent set by setInputSurface()),
    -+            // give the client an empty input buffers array.
    -+            if (portIndex != kPortIndexInput || !mHaveInputSurface) {
    -+                const Vector<BufferInfo> &srcBuffers = mPortBuffers[portIndex];
    -+
    -+                for (size_t i = 0; i < srcBuffers.size(); ++i) {
    -+                    const BufferInfo &info = srcBuffers.itemAt(i);
    -+
    -+                    dstBuffers->push_back(
    -+                            (portIndex == kPortIndexInput && mCrypto != NULL)
    -+                                    ? info.mEncryptedData : info.mData);
    -+                }
    -             }
    - 
    -             (new AMessage)->postReply(replyID);
    -diff --git a/media/libstagefright/MediaCodecSource.cpp b/media/libstagefright/MediaCodecSource.cpp
    -index 33d624e..ea5ef06 100644
    ---- a/media/libstagefright/MediaCodecSource.cpp
    -+++ b/media/libstagefright/MediaCodecSource.cpp
    -@@ -859,6 +859,7 @@ void MediaCodecSource::onMessageReceived(const sp<AMessage> &msg) {
    -             }
    - 
    -             MediaBuffer *mbuf = new MediaBuffer(outbuf->size());
    -+            mbuf->setObserver(this);
    -             mbuf->add_ref();
    - 
    -             if (!(flags & MediaCodec::BUFFER_FLAG_CODECCONFIG)) {
    -@@ -911,7 +912,6 @@ void MediaCodecSource::onMessageReceived(const sp<AMessage> &msg) {
    -                 mbuf->meta_data()->setInt32(kKeyIsSyncFrame, true);
    -             }
    -             memcpy(mbuf->data(), outbuf->data(), outbuf->size());
    --            mbuf->setObserver(this);
    - 
    -             {
    -                 Mutexed<Output>::Locked output(mOutput);
    -diff --git a/media/libstagefright/NuMediaExtractor.cpp b/media/libstagefright/NuMediaExtractor.cpp
    -index a669dca..276d731 100644
    ---- a/media/libstagefright/NuMediaExtractor.cpp
    -+++ b/media/libstagefright/NuMediaExtractor.cpp
    -@@ -305,7 +305,10 @@ status_t NuMediaExtractor::selectTrack(size_t index) {
    - 
    -     sp<IMediaSource> source = mImpl->getTrack(index);
    - 
    --    CHECK_EQ((status_t)OK, source->start());
    -+    status_t ret = source->start();
    -+    if (ret != OK) {
    -+        return ret;
    -+    }
    - 
    -     mSelectedTracks.push();
    -     TrackInfo *info = &mSelectedTracks.editItemAt(mSelectedTracks.size() - 1);
    -diff --git a/media/libstagefright/OMXClient.cpp b/media/libstagefright/OMXClient.cpp
    -index e994069..e40dbcf 100644
    ---- a/media/libstagefright/OMXClient.cpp
    -+++ b/media/libstagefright/OMXClient.cpp
    -@@ -303,6 +303,12 @@ status_t MuxOMX::allocateNode(
    - status_t MuxOMX::freeNode(node_id node) {
    -     Mutex::Autolock autoLock(mLock);
    - 
    -+    // exit if we have already freed the node
    -+    if (mNodeLocation.indexOfKey(node) < 0) {
    -+        ALOGD("MuxOMX::freeNode: node %d seems to be released already --- ignoring.", node);
    -+        return OK;
    -+    }
    -+
    -     status_t err = getOMX_l(node)->freeNode(node);
    - 
    -     if (err != OK) {
    -diff --git a/media/libstagefright/StagefrightMetadataRetriever.cpp b/media/libstagefright/StagefrightMetadataRetriever.cpp
    -index d2ba02e..be5067d 100644
    ---- a/media/libstagefright/StagefrightMetadataRetriever.cpp
    -+++ b/media/libstagefright/StagefrightMetadataRetriever.cpp
    -@@ -158,11 +158,14 @@ static VideoFrame *extractVideoFrame(
    -     // TODO: Use Flexible color instead
    -     videoFormat->setInt32("color-format", OMX_COLOR_FormatYUV420Planar);
    - 
    --    // For the thumbnail extraction case, try to allocate single buffer
    --    // in both input and output ports. NOTE: This request may fail if
    --    // component requires more than that for decoding.
    --    videoFormat->setInt32("android._num-input-buffers", 1);
    --    videoFormat->setInt32("android._num-output-buffers", 1);
    -+    // For the thumbnail extraction case, try to allocate single buffer in both
    -+    // input and output ports, if seeking to a sync frame. NOTE: This request may
    -+    // fail if component requires more than that for decoding.
    -+    bool isSeekingClosest = (seekMode == MediaSource::ReadOptions::SEEK_CLOSEST);
    -+    if (!isSeekingClosest) {
    -+        videoFormat->setInt32("android._num-input-buffers", 1);
    -+        videoFormat->setInt32("android._num-output-buffers", 1);
    -+    }
    - 
    -     status_t err;
    -     sp<ALooper> looper = new ALooper;
    -@@ -254,6 +257,9 @@ static VideoFrame *extractVideoFrame(
    -     bool isAvcOrHevc = !strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_AVC)
    -             || !strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_HEVC);
    - 
    -+    bool firstSample = true;
    -+    int64_t targetTimeUs = -1ll;
    -+
    -     do {
    -         size_t inputIndex = -1;
    -         int64_t ptsUs = 0ll;
    -@@ -280,6 +286,11 @@ static VideoFrame *extractVideoFrame(
    -                 haveMoreInputs = false;
    -                 break;
    -             }
    -+            if (firstSample && isSeekingClosest) {
    -+                mediaBuffer->meta_data()->findInt64(kKeyTargetTime, &targetTimeUs);
    -+                ALOGV("Seeking closest: targetTimeUs=%lld", (long long)targetTimeUs);
    -+            }
    -+            firstSample = false;
    - 
    -             if (mediaBuffer->range_length() > codecBuffer->capacity()) {
    -                 ALOGE("buffer size (%zu) too large for codec input size (%zu)",
    -@@ -292,8 +303,9 @@ static VideoFrame *extractVideoFrame(
    -                 memcpy(codecBuffer->data(),
    -                         (const uint8_t*)mediaBuffer->data() + mediaBuffer->range_offset(),
    -                         mediaBuffer->range_length());
    --                if (isAvcOrHevc && IsIDR(codecBuffer)) {
    --                    // Only need to decode one IDR frame.
    -+                if (isAvcOrHevc && IsIDR(codecBuffer) && !isSeekingClosest) {
    -+                    // Only need to decode one IDR frame, unless we're seeking with CLOSEST
    -+                    // option, in which case we need to actually decode to targetTimeUs.
    -                     haveMoreInputs = false;
    -                     flags |= MediaCodec::BUFFER_FLAG_EOS;
    -                 }
    -@@ -340,8 +352,13 @@ static VideoFrame *extractVideoFrame(
    -                     ALOGV("Timed-out waiting for output.. retries left = %zu", retriesLeft);
    -                     err = OK;
    -                 } else if (err == OK) {
    --                    ALOGV("Received an output buffer");
    --                    done = true;
    -+                    // If we're seeking with CLOSEST option and obtained a valid targetTimeUs
    -+                    // from the extractor, decode to the specified frame. Otherwise we're done.
    -+                    done = (targetTimeUs < 0ll) || (timeUs >= targetTimeUs);
    -+                    ALOGV("Received an output buffer, timeUs=%lld", (long long)timeUs);
    -+                    if (!done) {
    -+                        err = decoder->releaseOutputBuffer(index);
    -+                    }
    -                 } else {
    -                     ALOGW("Received error %d (%s) instead of output", err, asString(err));
    -                     done = true;
     diff --git a/media/libstagefright/SurfaceMediaSource.cpp b/media/libstagefright/SurfaceMediaSource.cpp
     index 15ff569..0e9b4e6 100644
     --- a/media/libstagefright/SurfaceMediaSource.cpp
    @@ -2054,346 +229,27 @@ index 15ff569..0e9b4e6 100644
      
          (*buffer)->setObserver(this);
          (*buffer)->add_ref();
    -diff --git a/media/libstagefright/SurfaceUtils.cpp b/media/libstagefright/SurfaceUtils.cpp
    -index 60ef662..568837a 100644
    ---- a/media/libstagefright/SurfaceUtils.cpp
    -+++ b/media/libstagefright/SurfaceUtils.cpp
    -@@ -186,10 +186,6 @@ status_t pushBlankBuffersToNativeWindow(ANativeWindow *nativeWindow /* nonnull *
    -             break;
    -         }
    - 
    --        if (img == NULL) {
    --            ALOGE("error pushing blank frames: lock returned NULL buffer");
    --            break;
    --        }
    -         *img = 0;
    - 
    -         err = buf->unlock();
    -diff --git a/media/libstagefright/foundation/ColorUtils.cpp b/media/libstagefright/foundation/ColorUtils.cpp
    -index e329766..d7439b2 100644
    ---- a/media/libstagefright/foundation/ColorUtils.cpp
    -+++ b/media/libstagefright/foundation/ColorUtils.cpp
    -@@ -286,6 +286,7 @@ ALookup<int32_t, ColorAspects::Transfer> sIsoTransfers {
    -         { 15, ColorAspects::TransferSMPTE170M },
    -         { 16, ColorAspects::TransferST2084 },
    -         { 17, ColorAspects::TransferST428 },
    -+        { 18, ColorAspects::TransferHLG },
    -     }
    - };
    - 
    -diff --git a/media/libstagefright/foundation/MediaBuffer.cpp b/media/libstagefright/foundation/MediaBuffer.cpp
    -index 718b7e5..16000ef 100644
    ---- a/media/libstagefright/foundation/MediaBuffer.cpp
    -+++ b/media/libstagefright/foundation/MediaBuffer.cpp
    -@@ -105,14 +105,7 @@ MediaBuffer::MediaBuffer(const sp<ABuffer> &buffer)
    - 
    - void MediaBuffer::release() {
    -     if (mObserver == NULL) {
    --        if (mMemory.get() != nullptr) {
    --            // See if there is a pending release and there are no observers.
    --            // Ideally this never happens.
    --            while (addPendingRelease(-1) > 0) {
    --                __sync_fetch_and_sub(&mRefCount, 1);
    --            }
    --            addPendingRelease(1);
    --        }
    -+        // Legacy contract for MediaBuffer without a MediaBufferGroup.
    -         CHECK_EQ(mRefCount, 0);
    -         delete this;
    -         return;
    -@@ -205,10 +198,6 @@ void MediaBuffer::setObserver(MediaBufferObserver *observer) {
    -     mObserver = observer;
    - }
    - 
    --int MediaBuffer::refcount() const {
    --    return mRefCount;
    --}
    --
    - MediaBuffer *MediaBuffer::clone() {
    -     CHECK(mGraphicBuffer == NULL);
    - 
     diff --git a/media/libstagefright/foundation/MediaBufferGroup.cpp b/media/libstagefright/foundation/MediaBufferGroup.cpp
    -index cb78879..1334f93 100644
    +index 54f768a..1334f93 100644
     --- a/media/libstagefright/foundation/MediaBufferGroup.cpp
     +++ b/media/libstagefright/foundation/MediaBufferGroup.cpp
    -@@ -51,7 +51,7 @@ MediaBufferGroup::MediaBufferGroup(size_t buffers, size_t buffer_size, size_t gr
    - 
    -         for (size_t i = 0; i < buffers; ++i) {
    -             sp<IMemory> mem = memoryDealer->allocate(augmented_size);
    --            if (mem.get() == nullptr) {
    -+            if (mem.get() == nullptr || mem->pointer() == nullptr) {
    -                 ALOGW("Only allocated %zu shared buffers of size %zu", i, buffer_size);
    -                 break;
    -             }
    -@@ -76,11 +76,24 @@ MediaBufferGroup::MediaBufferGroup(size_t buffers, size_t buffer_size, size_t gr
    - 
    - MediaBufferGroup::~MediaBufferGroup() {
    -     for (MediaBuffer *buffer : mBuffers) {
    --        buffer->resolvePendingRelease();
    --        // If we don't release it, perhaps noone will release it.
    --        LOG_ALWAYS_FATAL_IF(buffer->refcount() != 0,
    --                "buffer refcount %p = %d != 0", buffer, buffer->refcount());
    --        // actually delete it.
    -+        if (buffer->refcount() != 0) {
    -+            const int localRefcount = buffer->localRefcount();
    -+            const int remoteRefcount = buffer->remoteRefcount();
    -+
    -+            // Fatal if we have a local refcount.
    -+            LOG_ALWAYS_FATAL_IF(localRefcount != 0,
    -+                    "buffer(%p) localRefcount %d != 0, remoteRefcount %d",
    -+                    buffer, localRefcount, remoteRefcount);
    -+
    -+            // Log an error if we have a remaining remote refcount,
    -+            // as the remote process may have died or may have inappropriate behavior.
    -+            // The shared memory associated with the MediaBuffer will
    -+            // automatically be reclaimed when there are no remaining fds
    -+            // associated with it.
    -+            ALOGE("buffer(%p) has residual remoteRefcount %d",
    -+                    buffer, remoteRefcount);
    -+        }
    -+        // gracefully delete.
    -         buffer->setObserver(nullptr);
    -         buffer->release();
    -     }
    -@@ -94,32 +107,11 @@ void MediaBufferGroup::add_buffer(MediaBuffer *buffer) {
    -     // optionally: mGrowthLimit = max(mGrowthLimit, mBuffers.size());
    - }
    - 
    --void MediaBufferGroup::gc(size_t freeBuffers) {
    --    Mutex::Autolock autoLock(mLock);
    --
    --    size_t freeCount = 0;
    --    for (auto it = mBuffers.begin(); it != mBuffers.end(); ) {
    --        (*it)->resolvePendingRelease();
    --        if ((*it)->isDeadObject()) {
    --            // The MediaBuffer has been deleted, why is it in the MediaBufferGroup?
    --            LOG_ALWAYS_FATAL("buffer(%p) has dead object with refcount %d",
    --                    (*it), (*it)->refcount());
    --        } else if ((*it)->refcount() == 0 && ++freeCount > freeBuffers) {
    --            (*it)->setObserver(nullptr);
    --            (*it)->release();
    --            it = mBuffers.erase(it);
    --        } else {
    --            ++it;
    --        }
    --    }
    --}
    --
    - bool MediaBufferGroup::has_buffers() {
    -     if (mBuffers.size() < mGrowthLimit) {
    -         return true; // We can add more buffers internally.
    -     }
    -     for (MediaBuffer *buffer : mBuffers) {
    --        buffer->resolvePendingRelease();
    -         if (buffer->refcount() == 0) {
    -             return true;
    -         }
    -@@ -135,7 +127,6 @@ status_t MediaBufferGroup::acquire_buffer(
    -         MediaBuffer *buffer = nullptr;
    -         auto free = mBuffers.end();
    -         for (auto it = mBuffers.begin(); it != mBuffers.end(); ++it) {
    --            (*it)->resolvePendingRelease();
    -             if ((*it)->refcount() == 0) {
    -                 const size_t size = (*it)->size();
    -                 if (size >= requestedSize) {
    -@@ -188,6 +179,16 @@ status_t MediaBufferGroup::acquire_buffer(
    +@@ -179,6 +179,16 @@ status_t MediaBufferGroup::acquire_buffer(
          // Never gets here.
      }
      
     +status_t MediaBufferGroup::acquire_buffer(
     +       MediaBuffer **out) {
    -+   return acquire_buffer(out, false, 0);
    -+}
    -+
    -+status_t MediaBufferGroup::acquire_buffer(
    -+        MediaBuffer **out, bool nonBlocking) {
    -+    return acquire_buffer(out, nonBlocking, 0);
    -+}
    -+
    - void MediaBufferGroup::signalBufferReturned(MediaBuffer *) {
    -     mCondition.signal();
    - }
    -diff --git a/media/libstagefright/foundation/MetaData.cpp b/media/libstagefright/foundation/MetaData.cpp
    -index b4abc60..a8965f0 100644
    ---- a/media/libstagefright/foundation/MetaData.cpp
    -+++ b/media/libstagefright/foundation/MetaData.cpp
    -@@ -392,8 +392,12 @@ void MetaData::dumpToLog() const {
    - }
    - 
    - status_t MetaData::writeToParcel(Parcel &parcel) {
    -+    status_t ret;
    -     size_t numItems = mItems.size();
    --    parcel.writeUint32(uint32_t(numItems));
    -+    ret = parcel.writeUint32(uint32_t(numItems));
    -+    if (ret) {
    -+        return ret;
    -+    }
    -     for (size_t i = 0; i < numItems; i++) {
    -         int32_t key = mItems.keyAt(i);
    -         const typed_data &item = mItems.valueAt(i);
    -@@ -401,9 +405,32 @@ status_t MetaData::writeToParcel(Parcel &parcel) {
    -         const void *data;
    -         size_t size;
    -         item.getData(&type, &data, &size);
    --        parcel.writeInt32(key);
    --        parcel.writeUint32(type);
    --        parcel.writeByteArray(size, (uint8_t*)data);
    -+        ret = parcel.writeInt32(key);
    -+        if (ret) {
    -+            return ret;
    -+        }
    -+        ret = parcel.writeUint32(type);
    -+        if (ret) {
    -+            return ret;
    -+        }
    -+        if (type == TYPE_NONE) {
    -+            android::Parcel::WritableBlob blob;
    -+            ret = parcel.writeUint32(static_cast<uint32_t>(size));
    -+            if (ret) {
    -+                return ret;
    -+            }
    -+            ret = parcel.writeBlob(size, false, &blob);
    -+            if (ret) {
    -+                return ret;
    -+            }
    -+            memcpy(blob.data(), data, size);
    -+            blob.release();
    -+        } else {
    -+            ret = parcel.writeByteArray(size, (uint8_t*)data);
    -+            if (ret) {
    -+                return ret;
    -+            }
    -+        }
    -     }
    -     return OK;
    - }
    -@@ -422,8 +449,20 @@ status_t MetaData::updateFromParcel(const Parcel &parcel) {
    -             if (ret != OK) {
    -                 break;
    -             }
    --            // copy data directly from Parcel storage, then advance position
    --            setData(key, type, parcel.readInplace(size), size);
    -+            // copy data from Blob, which may be inline in Parcel storage,
    -+            // then advance position
    -+            if (type == TYPE_NONE) {
    -+                android::Parcel::ReadableBlob blob;
    -+                ret = parcel.readBlob(size, &blob);
    -+                if (ret != OK) {
    -+                    break;
    -+                }
    -+                setData(key, type, blob.data(), size);
    -+                blob.release();
    -+            } else {
    -+                // copy data directly from Parcel storage, then advance position
    -+                setData(key, type, parcel.readInplace(size), size);
    -+            }
    -          }
    - 
    -         return OK;
    -diff --git a/media/libstagefright/httplive/LiveSession.cpp b/media/libstagefright/httplive/LiveSession.cpp
    -index cebf95c..7abc019 100644
    ---- a/media/libstagefright/httplive/LiveSession.cpp
    -+++ b/media/libstagefright/httplive/LiveSession.cpp
    -@@ -467,28 +467,28 @@ status_t LiveSession::dequeueAccessUnit(
    -     return err;
    - }
    - 
    --status_t LiveSession::getStreamFormat(StreamType stream, sp<AMessage> *format) {
    -+status_t LiveSession::getStreamFormatMeta(StreamType stream, sp<MetaData> *meta) {
    -     if (!(mStreamMask & stream)) {
    -         return UNKNOWN_ERROR;
    -     }
    - 
    -     sp<AnotherPacketSource> packetSource = mPacketSources.valueFor(stream);
    - 
    --    sp<MetaData> meta = packetSource->getFormat();
    -+    *meta = packetSource->getFormat();
    - 
    --    if (meta == NULL) {
    -+    if (*meta == NULL) {
    -         return -EWOULDBLOCK;
    -     }
    - 
    -     if (stream == STREAMTYPE_AUDIO) {
    -         // set AAC input buffer size to 32K bytes (256kbps x 1sec)
    --        meta->setInt32(kKeyMaxInputSize, 32 * 1024);
    -+        (*meta)->setInt32(kKeyMaxInputSize, 32 * 1024);
    -     } else if (stream == STREAMTYPE_VIDEO) {
    --        meta->setInt32(kKeyMaxWidth, mMaxWidth);
    --        meta->setInt32(kKeyMaxHeight, mMaxHeight);
    -+        (*meta)->setInt32(kKeyMaxWidth, mMaxWidth);
    -+        (*meta)->setInt32(kKeyMaxHeight, mMaxHeight);
    -     }
    - 
    --    return convertMetaDataToMessage(meta, format);
    -+    return OK;
    - }
    - 
    - sp<HTTPDownloader> LiveSession::getHTTPDownloader() {
    -diff --git a/media/libstagefright/httplive/LiveSession.h b/media/libstagefright/httplive/LiveSession.h
    -index 90d56d0..b600eba 100644
    ---- a/media/libstagefright/httplive/LiveSession.h
    -+++ b/media/libstagefright/httplive/LiveSession.h
    -@@ -75,7 +75,7 @@ struct LiveSession : public AHandler {
    -     int64_t calculateMediaTimeUs(int64_t firstTimeUs, int64_t timeUs, int32_t discontinuitySeq);
    -     status_t dequeueAccessUnit(StreamType stream, sp<ABuffer> *accessUnit);
    - 
    --    status_t getStreamFormat(StreamType stream, sp<AMessage> *format);
    -+    status_t getStreamFormatMeta(StreamType stream, sp<MetaData> *meta);
    - 
    -     sp<HTTPDownloader> getHTTPDownloader();
    - 
    -diff --git a/media/libstagefright/include/MPEG4Extractor.h b/media/libstagefright/include/MPEG4Extractor.h
    -index 37c35e3..836cb08 100644
    ---- a/media/libstagefright/include/MPEG4Extractor.h
    -+++ b/media/libstagefright/include/MPEG4Extractor.h
    -@@ -93,7 +93,6 @@ private:
    - 
    -     sp<DataSource> mDataSource;
    -     status_t mInitCheck;
    --    bool mHasVideo;
    -     uint32_t mHeaderTimescale;
    -     bool mIsQT;
    - 
    -diff --git a/media/libstagefright/mpeg2ts/ATSParser.cpp b/media/libstagefright/mpeg2ts/ATSParser.cpp
    -index b863d67..844479e 100644
    ---- a/media/libstagefright/mpeg2ts/ATSParser.cpp
    -+++ b/media/libstagefright/mpeg2ts/ATSParser.cpp
    -@@ -701,6 +701,10 @@ status_t ATSParser::Stream::parse(
    -         }
    - 
    -         mPayloadStarted = true;
    -+        // There should be at most 2 elements in |mPesStartOffsets|.
    -+        while (mPesStartOffsets.size() >= 2) {
    -+            mPesStartOffsets.erase(mPesStartOffsets.begin());
    -+        }
    -         mPesStartOffsets.push_back(offset);
    -     }
    - 
    -@@ -1104,15 +1108,20 @@ void ATSParser::Stream::onPayloadData(
    -             mSource->queueAccessUnit(accessUnit);
    -         }
    - 
    --        if ((event != NULL) && !found && mQueue->getFormat() != NULL) {
    -+        // Every access unit has a pesStartOffset queued in |mPesStartOffsets|.
    -+        off64_t pesStartOffset = -1;
    -+        if (!mPesStartOffsets.empty()) {
    -+            pesStartOffset = *mPesStartOffsets.begin();
    -+            mPesStartOffsets.erase(mPesStartOffsets.begin());
    -+        }
    ++   return acquire_buffer(out, false, 0);
    ++}
     +
    -+        if (pesStartOffset >= 0 && (event != NULL) && !found && mQueue->getFormat() != NULL) {
    -             int32_t sync = 0;
    -             if (accessUnit->meta()->findInt32("isSync", &sync) && sync) {
    -                 int64_t timeUs;
    -                 if (accessUnit->meta()->findInt64("timeUs", &timeUs)) {
    -                     found = true;
    --                    off64_t pesStartOffset = *mPesStartOffsets.begin();
    -                     event->init(pesStartOffset, mSource, timeUs);
    --                    mPesStartOffsets.erase(mPesStartOffsets.begin());
    -                 }
    -             }
    -         }
    ++status_t MediaBufferGroup::acquire_buffer(
    ++        MediaBuffer **out, bool nonBlocking) {
    ++    return acquire_buffer(out, nonBlocking, 0);
    ++}
    ++
    + void MediaBufferGroup::signalBufferReturned(MediaBuffer *) {
    +     mCondition.signal();
    + }
     diff --git a/media/libstagefright/omx/Android.mk b/media/libstagefright/omx/Android.mk
     index e4fbd81..c262782 100644
     --- a/media/libstagefright/omx/Android.mk
    @@ -2418,149 +274,18 @@ index e4fbd81..c262782 100644
      LOCAL_CFLAGS += -Werror -Wall
      LOCAL_CLANG := true
     diff --git a/media/libstagefright/omx/GraphicBufferSource.cpp b/media/libstagefright/omx/GraphicBufferSource.cpp
    -index e025653..50cc940 100644
    +index 93d6584..50cc940 100644
     --- a/media/libstagefright/omx/GraphicBufferSource.cpp
     +++ b/media/libstagefright/omx/GraphicBufferSource.cpp
    -@@ -139,7 +139,6 @@ GraphicBufferSource::GraphicBufferSource(
    -     mRepeatLastFrameTimestamp(-1ll),
    -     mLatestBufferId(-1),
    -     mLatestBufferFrameNum(0),
    --    mLatestBufferUseCount(0),
    -     mLatestBufferFence(Fence::NO_FENCE),
    -     mRepeatBufferDeferred(false),
    -     mTimePerCaptureUs(-1ll),
    -@@ -398,12 +397,16 @@ void GraphicBufferSource::codecBufferEmptied(OMX_BUFFERHEADERTYPE* header, int f
    -     sp<Fence> fence = new Fence(fenceFd);
    -     if (mBufferSlot[id] != NULL &&
    -         mBufferSlot[id]->handle == codecBuffer.mGraphicBuffer->handle) {
    --        ALOGV("cbi %d matches bq slot %d, handle=%p",
    --                cbi, id, mBufferSlot[id]->handle);
    -+        mBufferUseCount[id]--;
    +@@ -724,6 +724,8 @@ bool GraphicBufferSource::repeatLatestBuffer_l() {
      
    --        if (id == mLatestBufferId) {
    --            CHECK_GT(mLatestBufferUseCount--, 0);
    --        } else {
    -+        ALOGV("codecBufferEmptied: slot=%d, cbi=%d, useCount=%d, handle=%p",
    -+                id, cbi, mBufferUseCount[id], mBufferSlot[id]->handle);
    + void GraphicBufferSource::setLatestBuffer_l(
    +         const BufferItem &item, bool dropped) {
    ++    ALOGV("setLatestBuffer_l");
     +
    -+        if (mBufferUseCount[id] < 0) {
    -+            ALOGW("mBufferUseCount for bq slot %d < 0 (=%d)", id, mBufferUseCount[id]);
    -+            mBufferUseCount[id] = 0;
    -+        }
    -+        if (id != mLatestBufferId && mBufferUseCount[id] == 0) {
    -             releaseBuffer(id, codecBuffer.mFrameNumber, mBufferSlot[id], fence);
    -         }
    -     } else {
    -@@ -614,6 +617,7 @@ bool GraphicBufferSource::fillCodecBuffer_l() {
    -     if (item.mGraphicBuffer != NULL) {
    -         ALOGV("fillCodecBuffer_l: setting mBufferSlot %d", item.mSlot);
    -         mBufferSlot[item.mSlot] = item.mGraphicBuffer;
    -+        mBufferUseCount[item.mSlot] = 0;
    -     }
    - 
    -     if (item.mDataSpace != mLastDataSpace) {
    -@@ -699,7 +703,7 @@ bool GraphicBufferSource::repeatLatestBuffer_l() {
    -         return false;
    -     }
    - 
    --    ++mLatestBufferUseCount;
    -+    ++mBufferUseCount[item.mSlot];
    - 
    -     /* repeat last frame up to kRepeatLastFrameCount times.
    -      * in case of static scene, a single repeat might not get rid of encoder
    -@@ -723,7 +727,7 @@ void GraphicBufferSource::setLatestBuffer_l(
    -     ALOGV("setLatestBuffer_l");
    - 
          if (mLatestBufferId >= 0) {
    --        if (mLatestBufferUseCount == 0) {
    -+        if (mBufferUseCount[mLatestBufferId] == 0) {
    +         if (mBufferUseCount[mLatestBufferId] == 0) {
                  releaseBuffer(mLatestBufferId, mLatestBufferFrameNum,
    -                     mBufferSlot[mLatestBufferId], mLatestBufferFence);
    -             // mLatestBufferFence will be set to new fence just below
    -@@ -734,7 +738,13 @@ void GraphicBufferSource::setLatestBuffer_l(
    -     mLatestBufferFrameNum = item.mFrameNumber;
    -     mRepeatLastFrameTimestamp = item.mTimestamp + mRepeatAfterUs * 1000;
    - 
    --    mLatestBufferUseCount = dropped ? 0 : 1;
    -+    if (!dropped) {
    -+        ++mBufferUseCount[item.mSlot];
    -+    }
    -+
    -+    ALOGV("setLatestBuffer_l: slot=%d, useCount=%d",
    -+            item.mSlot, mBufferUseCount[item.mSlot]);
    -+
    -     mRepeatBufferDeferred = false;
    -     mRepeatLastFrameCount = kRepeatLastFrameCount;
    -     mLatestBufferFence = item.mFence;
    -@@ -827,11 +837,11 @@ int64_t GraphicBufferSource::getTimestamp(const BufferItem &item) {
    -                 int64_t timestampGapUs = originalTimeUs - mPrevOriginalTimeUs;
    -                 timeUs = (timestampGapUs < mMaxTimestampGapUs ?
    -                     timestampGapUs : mMaxTimestampGapUs) + mPrevModifiedTimeUs;
    --                mOriginalTimeUs.add(timeUs, originalTimeUs);
    --                ALOGV("IN  timestamp: %lld -> %lld",
    --                    static_cast<long long>(originalTimeUs),
    --                    static_cast<long long>(timeUs));
    -             }
    -+            mOriginalTimeUs.add(timeUs, originalTimeUs);
    -+            ALOGV("IN  timestamp: %lld -> %lld",
    -+                static_cast<long long>(originalTimeUs),
    -+                static_cast<long long>(timeUs));
    -         }
    - 
    -         mPrevOriginalTimeUs = originalTimeUs;
    -@@ -842,7 +852,7 @@ int64_t GraphicBufferSource::getTimestamp(const BufferItem &item) {
    - }
    - 
    - status_t GraphicBufferSource::submitBuffer_l(const BufferItem &item, int cbi) {
    --    ALOGV("submitBuffer_l cbi=%d", cbi);
    -+    ALOGV("submitBuffer_l: slot=%d, cbi=%d", item.mSlot, cbi);
    - 
    -     int64_t timeUs = getTimestamp(item);
    -     if (timeUs < 0ll) {
    -@@ -935,6 +945,7 @@ int GraphicBufferSource::findMatchingCodecBuffer_l(
    - void GraphicBufferSource::releaseBuffer(
    -         int &id, uint64_t frameNum,
    -         const sp<GraphicBuffer> buffer, const sp<Fence> &fence) {
    -+    ALOGV("releaseBuffer: slot=%d", id);
    -     if (mIsPersistent) {
    -         mConsumer->detachBuffer(id);
    -         mBufferSlot[id] = NULL;
    -@@ -978,6 +989,7 @@ void GraphicBufferSource::onFrameAvailable(const BufferItem& /*item*/) {
    -             if (item.mGraphicBuffer != NULL) {
    -                 ALOGV("onFrameAvailable: setting mBufferSlot %d", item.mSlot);
    -                 mBufferSlot[item.mSlot] = item.mGraphicBuffer;
    -+                mBufferUseCount[item.mSlot] = 0;
    -             }
    - 
    -             releaseBuffer(item.mSlot, item.mFrameNumber,
    -@@ -1011,6 +1023,7 @@ void GraphicBufferSource::onBuffersReleased() {
    -     for (int i = 0; i < BufferQueue::NUM_BUFFER_SLOTS; i++) {
    -         if ((slotMask & 0x01) != 0) {
    -             mBufferSlot[i] = NULL;
    -+            mBufferUseCount[i] = 0;
    -         }
    -         slotMask >>= 1;
    -     }
    -diff --git a/media/libstagefright/omx/GraphicBufferSource.h b/media/libstagefright/omx/GraphicBufferSource.h
    -index 30bfddb..aa4ceb3 100644
    ---- a/media/libstagefright/omx/GraphicBufferSource.h
    -+++ b/media/libstagefright/omx/GraphicBufferSource.h
    -@@ -295,6 +295,7 @@ private:
    -     // is done processing a GraphicBuffer, we can use this to map back
    -     // to a slot number.
    -     sp<GraphicBuffer> mBufferSlot[BufferQueue::NUM_BUFFER_SLOTS];
    -+    int32_t mBufferUseCount[BufferQueue::NUM_BUFFER_SLOTS];
    - 
    -     // Tracks codec buffers.
    -     Vector<CodecBuffer> mCodecBuffers;
    -@@ -327,7 +328,6 @@ private:
    - 
    -     int mLatestBufferId;
    -     uint64_t mLatestBufferFrameNum;
    --    int32_t mLatestBufferUseCount;
    -     sp<Fence> mLatestBufferFence;
    - 
    -     // The previous buffer should've been repeated but
     diff --git a/media/libstagefright/omx/OMXMaster.cpp b/media/libstagefright/omx/OMXMaster.cpp
     index 6132a2c..7f0d270 100644
     --- a/media/libstagefright/omx/OMXMaster.cpp
    @@ -2574,18 +299,9 @@ index 6132a2c..7f0d270 100644
      
      void OMXMaster::addPlugin(const char *libname) {
     diff --git a/media/libstagefright/omx/OMXNodeInstance.cpp b/media/libstagefright/omx/OMXNodeInstance.cpp
    -index 395dad8..3cf9c3b 100644
    +index 5f903a9..3cf9c3b 100644
     --- a/media/libstagefright/omx/OMXNodeInstance.cpp
     +++ b/media/libstagefright/omx/OMXNodeInstance.cpp
    -@@ -431,7 +431,7 @@ bool OMXNodeInstance::isProhibitedIndex_l(OMX_INDEXTYPE index) {
    -             || (index > (OMX_INDEXTYPE)OMX_IndexExtAudioStartUnused
    -                     && index <= (OMX_INDEXTYPE)OMX_IndexParamAudioProfileQuerySupported)
    -             || (index > (OMX_INDEXTYPE)OMX_IndexExtVideoStartUnused
    --                    && index <= (OMX_INDEXTYPE)OMX_IndexConfigAndroidIntraRefresh)
    -+                    && index <= (OMX_INDEXTYPE)OMX_IndexConfigAndroidVideoTemporalLayering)
    -             || (index > (OMX_INDEXTYPE)OMX_IndexExtOtherStartUnused
    -                     && index <= (OMX_INDEXTYPE)OMX_IndexParamConsumerUsageBits)) {
    -         return false;
     @@ -795,7 +795,11 @@ status_t OMXNodeInstance::useBuffer(
          // metadata buffers are not connected cross process
          // use a backup buffer instead of the actual buffer
    @@ -2641,197 +357,6 @@ index 395dad8..3cf9c3b 100644
              header->nOffset = 0;
          } else {
              // rangeLength and rangeOffset must be a subset of the allocated data in the buffer.
    -diff --git a/media/libstagefright/omx/SimpleSoftOMXComponent.cpp b/media/libstagefright/omx/SimpleSoftOMXComponent.cpp
    -index 13afd45..7c975f7 100644
    ---- a/media/libstagefright/omx/SimpleSoftOMXComponent.cpp
    -+++ b/media/libstagefright/omx/SimpleSoftOMXComponent.cpp
    -@@ -426,7 +426,19 @@ void SimpleSoftOMXComponent::onSendCommand(
    - }
    - 
    - void SimpleSoftOMXComponent::onChangeState(OMX_STATETYPE state) {
    -+    ALOGV("%p requesting change from %d to %d", this, mState, state);
    -     // We shouldn't be in a state transition already.
    -+
    -+    if (mState == OMX_StateLoaded
    -+            && mTargetState == OMX_StateIdle
    -+            && state == OMX_StateLoaded) {
    -+        // OMX specifically allows "canceling" a state transition from loaded
    -+        // to idle. Pretend we made it to idle, and go back to loaded
    -+        ALOGV("load->idle canceled");
    -+        mState = mTargetState = OMX_StateIdle;
    -+        state = OMX_StateLoaded;
    -+    }
    -+
    -     CHECK_EQ((int)mState, (int)mTargetState);
    - 
    -     switch (mState) {
    -@@ -606,6 +618,7 @@ void SimpleSoftOMXComponent::checkTransitions() {
    -         }
    - 
    -         if (transitionComplete) {
    -+            ALOGV("state transition from %d to %d complete", mState, mTargetState);
    -             mState = mTargetState;
    - 
    -             if (mState == OMX_StateLoaded) {
    -@@ -613,6 +626,8 @@ void SimpleSoftOMXComponent::checkTransitions() {
    -             }
    - 
    -             notify(OMX_EventCmdComplete, OMX_CommandStateSet, mState, NULL);
    -+        } else {
    -+            ALOGV("state transition from %d to %d not yet complete", mState, mTargetState);
    -         }
    -     }
    - 
    -diff --git a/media/libstagefright/rtsp/MyHandler.h b/media/libstagefright/rtsp/MyHandler.h
    -index 42a1182..76e2e6e 100644
    ---- a/media/libstagefright/rtsp/MyHandler.h
    -+++ b/media/libstagefright/rtsp/MyHandler.h
    -@@ -1408,6 +1408,11 @@ struct MyHandler : public AHandler {
    -         msg->post((mKeepAliveTimeoutUs * 9) / 10);
    -     }
    - 
    -+    void cancelAccessUnitTimeoutCheck() {
    -+        ALOGV("cancelAccessUnitTimeoutCheck");
    -+        ++mCheckGeneration;
    -+    }
    -+
    -     void postAccessUnitTimeoutCheck() {
    -         if (mCheckPending) {
    -             return;
    -@@ -1792,14 +1797,8 @@ private:
    - 
    -             // Time is now established, lets start timestamping immediately
    -             for (size_t i = 0; i < mTracks.size(); ++i) {
    --                TrackInfo *trackInfo = &mTracks.editItemAt(i);
    --                while (!trackInfo->mPackets.empty()) {
    --                    sp<ABuffer> accessUnit = *trackInfo->mPackets.begin();
    --                    trackInfo->mPackets.erase(trackInfo->mPackets.begin());
    --
    --                    if (addMediaTimestamp(i, trackInfo, accessUnit)) {
    --                        postQueueAccessUnit(i, accessUnit);
    --                    }
    -+                if (OK != processAccessUnitQueue(i)) {
    -+                    return;
    -                 }
    -             }
    -             for (size_t i = 0; i < mTracks.size(); ++i) {
    -@@ -1812,26 +1811,8 @@ private:
    -         }
    -     }
    - 
    --    void onAccessUnitComplete(
    --            int32_t trackIndex, const sp<ABuffer> &accessUnit) {
    --        ALOGV("onAccessUnitComplete track %d", trackIndex);
    --
    -+    status_t processAccessUnitQueue(int32_t trackIndex) {
    -         TrackInfo *track = &mTracks.editItemAt(trackIndex);
    --        if(!mPlayResponseParsed){
    --            uint32_t seqNum = (uint32_t)accessUnit->int32Data();
    --            ALOGI("play response is not parsed, storing accessunit %u", seqNum);
    --            track->mPackets.push_back(accessUnit);
    --            return;
    --        }
    --
    --        handleFirstAccessUnit();
    --
    --        if (!mAllTracksHaveTime) {
    --            ALOGV("storing accessUnit, no time established yet");
    --            track->mPackets.push_back(accessUnit);
    --            return;
    --        }
    --
    -         while (!track->mPackets.empty()) {
    -             sp<ABuffer> accessUnit = *track->mPackets.begin();
    -             track->mPackets.erase(track->mPackets.begin());
    -@@ -1842,27 +1823,29 @@ private:
    -                 // by ARTPSource. Only the low 16 bits of seq in RTP-Info of reply of
    -                 // RTSP "PLAY" command should be used to detect the first RTP packet
    -                 // after seeking.
    --                if (track->mAllowedStaleAccessUnits > 0) {
    --                    uint32_t seqNum16 = seqNum & 0xffff;
    --                    uint32_t firstSeqNumInSegment16 = track->mFirstSeqNumInSegment & 0xffff;
    --                    if (seqNum16 > firstSeqNumInSegment16 + kMaxAllowedStaleAccessUnits
    --                            || seqNum16 < firstSeqNumInSegment16) {
    --                        // Not the first rtp packet of the stream after seeking, discarding.
    --                        track->mAllowedStaleAccessUnits--;
    --                        ALOGV("discarding stale access unit (0x%x : 0x%x)",
    --                             seqNum, track->mFirstSeqNumInSegment);
    --                        continue;
    -+                if (mSeekable) {
    -+                    if (track->mAllowedStaleAccessUnits > 0) {
    -+                        uint32_t seqNum16 = seqNum & 0xffff;
    -+                        uint32_t firstSeqNumInSegment16 = track->mFirstSeqNumInSegment & 0xffff;
    -+                        if (seqNum16 > firstSeqNumInSegment16 + kMaxAllowedStaleAccessUnits
    -+                                || seqNum16 < firstSeqNumInSegment16) {
    -+                            // Not the first rtp packet of the stream after seeking, discarding.
    -+                            track->mAllowedStaleAccessUnits--;
    -+                            ALOGV("discarding stale access unit (0x%x : 0x%x)",
    -+                                 seqNum, track->mFirstSeqNumInSegment);
    -+                            continue;
    -+                        }
    -+                        ALOGW_IF(seqNum16 != firstSeqNumInSegment16,
    -+                                "Missing the first packet(%u), now take packet(%u) as first one",
    -+                                track->mFirstSeqNumInSegment, seqNum);
    -+                    } else { // track->mAllowedStaleAccessUnits <= 0
    -+                        mNumAccessUnitsReceived = 0;
    -+                        ALOGW_IF(track->mAllowedStaleAccessUnits == 0,
    -+                             "Still no first rtp packet after %d stale ones",
    -+                             kMaxAllowedStaleAccessUnits);
    -+                        track->mAllowedStaleAccessUnits = -1;
    -+                        return UNKNOWN_ERROR;
    -                     }
    --                    ALOGW_IF(seqNum16 != firstSeqNumInSegment16,
    --                            "Missing the first packet(%u), now take packet(%u) as first one",
    --                            track->mFirstSeqNumInSegment, seqNum);
    --                } else { // track->mAllowedStaleAccessUnits <= 0
    --                    mNumAccessUnitsReceived = 0;
    --                    ALOGW_IF(track->mAllowedStaleAccessUnits == 0,
    --                         "Still no first rtp packet after %d stale ones",
    --                         kMaxAllowedStaleAccessUnits);
    --                    track->mAllowedStaleAccessUnits = -1;
    --                    return;
    -                 }
    - 
    -                 // Now found the first rtp packet of the stream after seeking.
    -@@ -1876,14 +1859,35 @@ private:
    -                 continue;
    -             }
    - 
    --
    -             if (addMediaTimestamp(trackIndex, track, accessUnit)) {
    -                 postQueueAccessUnit(trackIndex, accessUnit);
    -             }
    -         }
    -+        return OK;
    -+    }
    - 
    --        if (addMediaTimestamp(trackIndex, track, accessUnit)) {
    --            postQueueAccessUnit(trackIndex, accessUnit);
    -+    void onAccessUnitComplete(
    -+            int32_t trackIndex, const sp<ABuffer> &accessUnit) {
    -+        TrackInfo *track = &mTracks.editItemAt(trackIndex);
    -+        track->mPackets.push_back(accessUnit);
    -+
    -+        uint32_t seqNum = (uint32_t)accessUnit->int32Data();
    -+        ALOGV("onAccessUnitComplete track %d storing accessunit %u", trackIndex, seqNum);
    -+
    -+        if(!mPlayResponseParsed){
    -+            ALOGV("play response is not parsed");
    -+            return;
    -+        }
    -+
    -+        handleFirstAccessUnit();
    -+
    -+        if (!mAllTracksHaveTime) {
    -+            ALOGV("storing accessUnit, no time established yet");
    -+            return;
    -+        }
    -+
    -+        if (OK != processAccessUnitQueue(trackIndex)) {
    -+            return;
    -         }
    - 
    -         if (track->mEOSReceived) {
     diff --git a/media/mediaserver/Android.mk b/media/mediaserver/Android.mk
     index 1738df8..c2b9c1f 100644
     --- a/media/mediaserver/Android.mk
    @@ -2869,716 +394,6 @@ index ecddc48..0abe6ac 100644
          registerExtensions();
          ProcessState::self()->startThreadPool();
          IPCThreadState::self()->joinThreadPool();
    -diff --git a/media/mtp/MtpServer.cpp b/media/mtp/MtpServer.cpp
    -index 90f1a77..e39dcdd 100644
    ---- a/media/mtp/MtpServer.cpp
    -+++ b/media/mtp/MtpServer.cpp
    -@@ -927,6 +927,10 @@ MtpResponseCode MtpServer::doSendObjectInfo() {
    -     if (!mData.getUInt32(temp32)) return MTP_RESPONSE_INVALID_PARAMETER;  // sequence number
    -     MtpStringBuffer name, created, modified;
    -     if (!mData.getString(name)) return MTP_RESPONSE_INVALID_PARAMETER;    // file name
    -+    if (name.getCharCount() == 0) {
    -+        ALOGE("empty name");
    -+        return MTP_RESPONSE_INVALID_PARAMETER;
    -+    }
    -     if (!mData.getString(created)) return MTP_RESPONSE_INVALID_PARAMETER;      // date created
    -     if (!mData.getString(modified)) return MTP_RESPONSE_INVALID_PARAMETER;     // date modified
    -     // keywords follow
    -diff --git a/media/ndk/NdkMediaExtractor.cpp b/media/ndk/NdkMediaExtractor.cpp
    -index 1118959..89f2d9c 100644
    ---- a/media/ndk/NdkMediaExtractor.cpp
    -+++ b/media/ndk/NdkMediaExtractor.cpp
    -@@ -148,7 +148,14 @@ media_status_t AMediaExtractor_unselectTrack(AMediaExtractor *mData, size_t idx)
    - EXPORT
    - bool AMediaExtractor_advance(AMediaExtractor *mData) {
    -     //ALOGV("advance");
    --    return mData->mImpl->advance();
    -+    status_t err = mData->mImpl->advance();
    -+    if (err == ERROR_END_OF_STREAM) {
    -+        return false;
    -+    } else if (err != OK) {
    -+        ALOGE("sf error code: %d", err);
    -+        return false;
    -+    }
    -+    return true;
    - }
    - 
    - EXPORT
    -@@ -343,9 +350,9 @@ AMediaCodecCryptoInfo *AMediaExtractor_getSampleCryptoInfo(AMediaExtractor *ex)
    - 
    -     const void *key;
    -     size_t keysize;
    --    if (meta->findData(kKeyCryptoIV, &type, &key, &keysize)) {
    -+    if (meta->findData(kKeyCryptoKey, &type, &key, &keysize)) {
    -         if (keysize != 16) {
    --            // IVs must be 16 bytes in length.
    -+            // Keys must be 16 bytes in length.
    -             return NULL;
    -         }
    -     }
    -diff --git a/services/audioflinger/AudioFlinger.cpp b/services/audioflinger/AudioFlinger.cpp
    -index 79f4a66..1785a03 100644
    ---- a/services/audioflinger/AudioFlinger.cpp
    -+++ b/services/audioflinger/AudioFlinger.cpp
    -@@ -1104,14 +1104,20 @@ status_t AudioFlinger::setParameters(audio_io_handle_t ioHandle, const String8&
    -     // AUDIO_IO_HANDLE_NONE means the parameters are global to the audio hardware interface
    -     if (ioHandle == AUDIO_IO_HANDLE_NONE) {
    -         Mutex::Autolock _l(mLock);
    --        status_t final_result = NO_ERROR;
    -+        // result will remain NO_INIT if no audio device is present
    -+        status_t final_result = NO_INIT;
    -         {
    -             AutoMutex lock(mHardwareLock);
    -             mHardwareStatus = AUDIO_HW_SET_PARAMETER;
    -             for (size_t i = 0; i < mAudioHwDevs.size(); i++) {
    -                 audio_hw_device_t *dev = mAudioHwDevs.valueAt(i)->hwDevice();
    -                 status_t result = dev->set_parameters(dev, keyValuePairs.string());
    --                final_result = result ?: final_result;
    -+                // return success if at least one audio device accepts the parameters as not all
    -+                // HALs are requested to support all parameters. If no audio device supports the
    -+                // requested parameters, the last error is reported.
    -+                if (final_result != NO_ERROR) {
    -+                    final_result = result;
    -+                }
    -             }
    -             mHardwareStatus = AUDIO_HW_IDLE;
    -         }
    -diff --git a/services/audioflinger/BufferProviders.cpp b/services/audioflinger/BufferProviders.cpp
    -index 2ca2cac..7b6dfcb 100644
    ---- a/services/audioflinger/BufferProviders.cpp
    -+++ b/services/audioflinger/BufferProviders.cpp
    -@@ -474,18 +474,18 @@ void TimestretchBufferProvider::processFrames(void *dstBuffer, size_t *dstFrames
    -     ALOGV("processFrames(%zu %zu)  remaining(%zu)", *dstFrames, *srcFrames, mRemaining);
    -     // Note dstFrames is the required number of frames.
    - 
    --    // Ensure consumption from src is as expected.
    --    //TODO: add logic to track "very accurate" consumption related to speed, original sampling
    --    //rate, actual frames processed.
    --    const size_t targetSrc = *dstFrames * mPlaybackRate.mSpeed;
    --    if (*srcFrames < targetSrc) { // limit dst frames to that possible
    --        *dstFrames = *srcFrames / mPlaybackRate.mSpeed;
    --    } else if (*srcFrames > targetSrc + 1) {
    --        *srcFrames = targetSrc + 1;
    --    }
    --
    -     if (!mAudioPlaybackRateValid) {
    -         //fallback mode
    -+        // Ensure consumption from src is as expected.
    -+        // TODO: add logic to track "very accurate" consumption related to speed, original sampling
    -+        // rate, actual frames processed.
    -+
    -+        const size_t targetSrc = *dstFrames * mPlaybackRate.mSpeed;
    -+        if (*srcFrames < targetSrc) { // limit dst frames to that possible
    -+            *dstFrames = *srcFrames / mPlaybackRate.mSpeed;
    -+        } else if (*srcFrames > targetSrc + 1) {
    -+            *srcFrames = targetSrc + 1;
    -+        }
    -         if (*dstFrames > 0) {
    -             switch(mPlaybackRate.mFallbackMode) {
    -             case AUDIO_TIMESTRETCH_FALLBACK_CUT_REPEAT:
    -diff --git a/services/audioflinger/Effects.cpp b/services/audioflinger/Effects.cpp
    -index bbea971..9711f2d 100644
    ---- a/services/audioflinger/Effects.cpp
    -+++ b/services/audioflinger/Effects.cpp
    -@@ -279,12 +279,29 @@ void AudioFlinger::EffectModule::process()
    -                                         mConfig.inputCfg.buffer.s32,
    -                                         mConfig.inputCfg.buffer.frameCount/2);
    -         }
    --
    --        // do the actual processing in the effect engine
    --        int ret = (*mEffectInterface)->process(mEffectInterface,
    --                                               &mConfig.inputCfg.buffer,
    --                                               &mConfig.outputCfg.buffer);
    --
    -+        int ret;
    -+        if (isProcessImplemented()) {
    -+            // do the actual processing in the effect engine
    -+            ret = (*mEffectInterface)->process(mEffectInterface,
    -+                                                   &mConfig.inputCfg.buffer,
    -+                                                   &mConfig.outputCfg.buffer);
    -+        } else {
    -+            if (mConfig.inputCfg.buffer.raw != mConfig.outputCfg.buffer.raw) {
    -+                size_t frameCnt = mConfig.inputCfg.buffer.frameCount * FCC_2;  //always stereo here
    -+                int16_t *in = mConfig.inputCfg.buffer.s16;
    -+                int16_t *out = mConfig.outputCfg.buffer.s16;
    -+
    -+                if (mConfig.outputCfg.accessMode == EFFECT_BUFFER_ACCESS_ACCUMULATE) {
    -+                    for (size_t i = 0; i < frameCnt; i++) {
    -+                        out[i] = clamp16((int32_t)out[i] + (int32_t)in[i]);
    -+                    }
    -+                } else {
    -+                    memcpy(mConfig.outputCfg.buffer.raw, mConfig.inputCfg.buffer.raw,
    -+                           frameCnt * sizeof(int16_t));
    -+                }
    -+            }
    -+            ret = -ENODATA;
    -+        }
    -         // force transition to IDLE state when engine is ready
    -         if (mState == STOPPED && ret == -ENODATA) {
    -             mDisableWaitCnt = 1;
    -@@ -301,7 +318,7 @@ void AudioFlinger::EffectModule::process()
    -         // accumulate input onto output
    -         sp<EffectChain> chain = mChain.promote();
    -         if (chain != 0 && chain->activeTrackCnt() != 0) {
    --            size_t frameCnt = mConfig.inputCfg.buffer.frameCount * 2;  //always stereo here
    -+            size_t frameCnt = mConfig.inputCfg.buffer.frameCount * FCC_2;  //always stereo here
    -             int16_t *in = mConfig.inputCfg.buffer.s16;
    -             int16_t *out = mConfig.outputCfg.buffer.s16;
    -             for (size_t i = 0; i < frameCnt; i++) {
    -@@ -2015,15 +2032,49 @@ void AudioFlinger::EffectChain::setThread(const sp<ThreadBase>& thread)
    -     }
    - }
    - 
    --bool AudioFlinger::EffectChain::hasSoftwareEffect() const
    -+void AudioFlinger::EffectChain::checkOutputFlagCompatibility(audio_output_flags_t *flags) const
    -+{
    -+    if ((*flags & AUDIO_OUTPUT_FLAG_RAW) != 0 && !isRawCompatible()) {
    -+        *flags = (audio_output_flags_t)(*flags & ~AUDIO_OUTPUT_FLAG_RAW);
    -+    }
    -+    if ((*flags & AUDIO_OUTPUT_FLAG_FAST) != 0 && !isFastCompatible()) {
    -+        *flags = (audio_output_flags_t)(*flags & ~AUDIO_OUTPUT_FLAG_FAST);
    -+    }
    -+}
    -+
    -+void AudioFlinger::EffectChain::checkInputFlagCompatibility(audio_input_flags_t *flags) const
    -+{
    -+    if ((*flags & AUDIO_INPUT_FLAG_RAW) != 0 && !isRawCompatible()) {
    -+        *flags = (audio_input_flags_t)(*flags & ~AUDIO_INPUT_FLAG_RAW);
    -+    }
    -+    if ((*flags & AUDIO_INPUT_FLAG_FAST) != 0 && !isFastCompatible()) {
    -+        *flags = (audio_input_flags_t)(*flags & ~AUDIO_INPUT_FLAG_FAST);
    -+    }
    -+}
    -+
    -+bool AudioFlinger::EffectChain::isRawCompatible() const
    - {
    -     Mutex::Autolock _l(mLock);
    --    for (size_t i = 0; i < mEffects.size(); i++) {
    --        if (mEffects[i]->isImplementationSoftware()) {
    --            return true;
    -+    for (const auto &effect : mEffects) {
    -+        if (effect->isProcessImplemented()) {
    -+            return false;
    -         }
    -     }
    --    return false;
    -+    // Allow effects without processing.
    -+    return true;
    -+}
    -+
    -+bool AudioFlinger::EffectChain::isFastCompatible() const
    -+{
    -+    Mutex::Autolock _l(mLock);
    -+    for (const auto &effect : mEffects) {
    -+        if (effect->isProcessImplemented()
    -+                && effect->isImplementationSoftware()) {
    -+            return false;
    -+        }
    -+    }
    -+    // Allow effects without processing or hw accelerated effects.
    -+    return true;
    - }
    - 
    - // isCompatibleWithThread_l() must be called with thread->mLock held
    -diff --git a/services/audioflinger/Effects.h b/services/audioflinger/Effects.h
    -index 322c06a..818bf94 100644
    ---- a/services/audioflinger/Effects.h
    -+++ b/services/audioflinger/Effects.h
    -@@ -119,6 +119,8 @@ public:
    -                         { return (mDescriptor.flags & EFFECT_FLAG_OFFLOAD_SUPPORTED) != 0; }
    -     bool             isImplementationSoftware() const
    -                         { return (mDescriptor.flags & EFFECT_FLAG_HW_ACC_MASK) == 0; }
    -+    bool             isProcessImplemented() const
    -+                        { return (mDescriptor.flags & EFFECT_FLAG_NO_PROCESS) == 0; }
    -     status_t         setOffloaded(bool offloaded, audio_io_handle_t io);
    -     bool             isOffloaded() const;
    -     void             addEffectToHal_l();
    -@@ -326,7 +328,17 @@ public:
    - 
    -     void syncHalEffectsState();
    - 
    --    bool hasSoftwareEffect() const;
    -+    // flags is an ORed set of audio_output_flags_t which is updated on return.
    -+    void checkOutputFlagCompatibility(audio_output_flags_t *flags) const;
    -+
    -+    // flags is an ORed set of audio_input_flags_t which is updated on return.
    -+    void checkInputFlagCompatibility(audio_input_flags_t *flags) const;
    -+
    -+    // Is this EffectChain compatible with the RAW audio flag.
    -+    bool isRawCompatible() const;
    -+
    -+    // Is this EffectChain compatible with the FAST audio flag.
    -+    bool isFastCompatible() const;
    - 
    -     // isCompatibleWithThread_l() must be called with thread->mLock held
    -     bool isCompatibleWithThread_l(const sp<ThreadBase>& thread) const;
    -diff --git a/services/audioflinger/FastMixer.cpp b/services/audioflinger/FastMixer.cpp
    -index b0780a4..93f7ce5 100644
    ---- a/services/audioflinger/FastMixer.cpp
    -+++ b/services/audioflinger/FastMixer.cpp
    -@@ -412,6 +412,7 @@ void FastMixer::onWork()
    -             }
    -             ftDump->mUnderruns = underruns;
    -             ftDump->mFramesReady = framesReady;
    -+            ftDump->mFramesWritten = trackFramesWritten;
    -         }
    - 
    -         if (anyEnabledTracks) {
    -diff --git a/services/audioflinger/FastMixerDumpState.cpp b/services/audioflinger/FastMixerDumpState.cpp
    -index 2326e2a..6475f22 100644
    ---- a/services/audioflinger/FastMixerDumpState.cpp
    -+++ b/services/audioflinger/FastMixerDumpState.cpp
    -@@ -168,7 +168,7 @@ void FastMixerDumpState::dump(int fd) const
    -     uint32_t trackMask = mTrackMask;
    -     dprintf(fd, "  Fast tracks: sMaxFastTracks=%u activeMask=%#x\n",
    -             FastMixerState::sMaxFastTracks, trackMask);
    --    dprintf(fd, "  Index Active Full Partial Empty  Recent Ready\n");
    -+    dprintf(fd, "  Index Active Full Partial Empty  Recent Ready    Written\n");
    -     for (uint32_t i = 0; i < FastMixerState::sMaxFastTracks; ++i, trackMask >>= 1) {
    -         bool isActive = trackMask & 1;
    -         const FastTrackDump *ftDump = &mTracks[i];
    -@@ -188,11 +188,13 @@ void FastMixerDumpState::dump(int fd) const
    -             mostRecent = "?";
    -             break;
    -         }
    --        dprintf(fd, "  %5u %6s %4u %7u %5u %7s %5zu\n", i, isActive ? "yes" : "no",
    -+        dprintf(fd, "  %5u %6s %4u %7u %5u %7s %5zu %10lld\n",
    -+                i, isActive ? "yes" : "no",
    -                 (underruns.mBitFields.mFull) & UNDERRUN_MASK,
    -                 (underruns.mBitFields.mPartial) & UNDERRUN_MASK,
    -                 (underruns.mBitFields.mEmpty) & UNDERRUN_MASK,
    --                mostRecent, ftDump->mFramesReady);
    -+                mostRecent, ftDump->mFramesReady,
    -+                (long long)ftDump->mFramesWritten);
    -     }
    - }
    - 
    -diff --git a/services/audioflinger/FastMixerDumpState.h b/services/audioflinger/FastMixerDumpState.h
    -index ac15e7c..301c5b1 100644
    ---- a/services/audioflinger/FastMixerDumpState.h
    -+++ b/services/audioflinger/FastMixerDumpState.h
    -@@ -57,6 +57,7 @@ struct FastTrackDump {
    -     /*virtual*/ ~FastTrackDump() { }
    -     FastTrackUnderruns  mUnderruns;
    -     size_t              mFramesReady;        // most recent value only; no long-term statistics kept
    -+    int64_t             mFramesWritten;      // last value from track
    - };
    - 
    - struct FastMixerDumpState : FastThreadDumpState {
    -diff --git a/services/audioflinger/Threads.cpp b/services/audioflinger/Threads.cpp
    -index a671128..0f403ae 100644
    ---- a/services/audioflinger/Threads.cpp
    -+++ b/services/audioflinger/Threads.cpp
    -@@ -1272,6 +1272,12 @@ status_t AudioFlinger::RecordThread::checkEffectCompatibility_l(
    -                 desc->name, mThreadName);
    -         return BAD_VALUE;
    -     }
    -+
    -+    // always allow effects without processing load or latency
    -+    if ((desc->flags & EFFECT_FLAG_NO_PROCESS_MASK) == EFFECT_FLAG_NO_PROCESS) {
    -+        return NO_ERROR;
    -+    }
    -+
    -     audio_input_flags_t flags = mInput->flags;
    -     if (hasFastCapture() || (flags & AUDIO_INPUT_FLAG_FAST)) {
    -         if (flags & AUDIO_INPUT_FLAG_RAW) {
    -@@ -1328,6 +1334,11 @@ status_t AudioFlinger::PlaybackThread::checkEffectCompatibility_l(
    -                     break;
    -                 }
    -             }
    -+
    -+            // always allow effects without processing load or latency
    -+            if ((desc->flags & EFFECT_FLAG_NO_PROCESS_MASK) == EFFECT_FLAG_NO_PROCESS) {
    -+                break;
    -+            }
    -             if (flags & AUDIO_OUTPUT_FLAG_RAW) {
    -                 ALOGW("checkEffectCompatibility_l(): effect %s on playback thread in raw mode",
    -                       desc->name);
    -@@ -1815,6 +1826,15 @@ void AudioFlinger::PlaybackThread::dumpInternals(int fd, const Vector<String16>&
    -     audio_output_flags_t flags = output != NULL ? output->flags : AUDIO_OUTPUT_FLAG_NONE;
    -     String8 flagsAsString = outputFlagsToString(flags);
    -     dprintf(fd, "  AudioStreamOut: %p flags %#x (%s)\n", output, flags, flagsAsString.string());
    -+    dprintf(fd, "  Frames written: %lld\n", (long long)mFramesWritten);
    -+    dprintf(fd, "  Suspended frames: %lld\n", (long long)mSuspendedFrames);
    -+    if (mPipeSink.get() != nullptr) {
    -+        dprintf(fd, "  PipeSink frames written: %lld\n", (long long)mPipeSink->framesWritten());
    -+    }
    -+    if (output != nullptr) {
    -+        dprintf(fd, "  Hal stream dump:\n");
    -+        (void)output->stream->common.dump(&output->stream->common, fd);
    -+    }
    - }
    - 
    - // Thread virtuals
    -@@ -1898,34 +1918,19 @@ sp<AudioFlinger::PlaybackThread::Track> AudioFlinger::PlaybackThread::createTrac
    -         // check compatibility with audio effects.
    -         { // scope for mLock
    -             Mutex::Autolock _l(mLock);
    --            // do not accept RAW flag if post processing are present. Note that post processing on
    --            // a fast mixer are necessarily hardware
    --            sp<EffectChain> chain = getEffectChain_l(AUDIO_SESSION_OUTPUT_STAGE);
    --            if (chain != 0) {
    --                ALOGV_IF((*flags & AUDIO_OUTPUT_FLAG_RAW) != 0,
    --                        "AUDIO_OUTPUT_FLAG_RAW denied: post processing effect present");
    --                *flags = (audio_output_flags_t)(*flags & ~AUDIO_OUTPUT_FLAG_RAW);
    --            }
    --            // Do not accept FAST flag if software global effects are present
    --            chain = getEffectChain_l(AUDIO_SESSION_OUTPUT_MIX);
    --            if (chain != 0) {
    --                ALOGV_IF((*flags & AUDIO_OUTPUT_FLAG_RAW) != 0,
    --                        "AUDIO_OUTPUT_FLAG_RAW denied: global effect present");
    --                *flags = (audio_output_flags_t)(*flags & ~AUDIO_OUTPUT_FLAG_RAW);
    --                if (chain->hasSoftwareEffect()) {
    --                    ALOGV("AUDIO_OUTPUT_FLAG_FAST denied: software global effect present");
    --                    *flags = (audio_output_flags_t)(*flags & ~AUDIO_OUTPUT_FLAG_FAST);
    --                }
    --            }
    --            // Do not accept FAST flag if the session has software effects
    --            chain = getEffectChain_l(sessionId);
    --            if (chain != 0) {
    --                ALOGV_IF((*flags & AUDIO_OUTPUT_FLAG_RAW) != 0,
    --                        "AUDIO_OUTPUT_FLAG_RAW denied: effect present on session");
    --                *flags = (audio_output_flags_t)(*flags & ~AUDIO_OUTPUT_FLAG_RAW);
    --                if (chain->hasSoftwareEffect()) {
    --                    ALOGV("AUDIO_OUTPUT_FLAG_FAST denied: software effect present on session");
    --                    *flags = (audio_output_flags_t)(*flags & ~AUDIO_OUTPUT_FLAG_FAST);
    -+            for (audio_session_t session : {
    -+                    AUDIO_SESSION_OUTPUT_STAGE,
    -+                    AUDIO_SESSION_OUTPUT_MIX,
    -+                    sessionId,
    -+                }) {
    -+                sp<EffectChain> chain = getEffectChain_l(session);
    -+                if (chain.get() != nullptr) {
    -+                    audio_output_flags_t old = *flags;
    -+                    chain->checkOutputFlagCompatibility(flags);
    -+                    if (old != *flags) {
    -+                        ALOGV("AUDIO_OUTPUT_FLAGS denied by effect, session=%d old=%#x new=%#x",
    -+                                (int)session, (int)old, (int)*flags);
    -+                    }
    -                 }
    -             }
    -         }
    -@@ -3106,9 +3111,9 @@ bool AudioFlinger::PlaybackThread::threadLoop()
    -                 if (!keepWakeLock()) {
    -                     releaseWakeLock_l();
    -                     released = true;
    -+                    mWakeLockUids.clear();
    -+                    mActiveTracksGeneration++;
    -                 }
    --                mWakeLockUids.clear();
    --                mActiveTracksGeneration++;
    -                 ALOGV("wait async completion");
    -                 mWaitWorkCV.wait(mLock);
    -                 ALOGV("async completion/wake");
    -@@ -4577,10 +4582,25 @@ AudioFlinger::PlaybackThread::mixer_state AudioFlinger::MixerThread::prepareTrac
    -     return mixerStatus;
    - }
    - 
    -+// trackCountForUid_l() must be called with ThreadBase::mLock held
    -+uint32_t AudioFlinger::PlaybackThread::trackCountForUid_l(uid_t uid)
    -+{
    -+    uint32_t trackCount = 0;
    -+    for (size_t i = 0; i < mTracks.size() ; i++) {
    -+        if (mTracks[i]->uid() == (int)uid) {
    -+            trackCount++;
    -+        }
    -+    }
    -+    return trackCount;
    -+}
    -+
    - // getTrackName_l() must be called with ThreadBase::mLock held
    - int AudioFlinger::MixerThread::getTrackName_l(audio_channel_mask_t channelMask,
    --        audio_format_t format, audio_session_t sessionId)
    -+        audio_format_t format, audio_session_t sessionId, uid_t uid)
    - {
    -+    if (trackCountForUid_l(uid) > (PlaybackThread::kMaxTracksPerUid - 1)) {
    -+        return -1;
    -+    }
    -     return mAudioMixer->getTrackName(channelMask, format, sessionId);
    - }
    - 
    -@@ -4685,7 +4705,7 @@ bool AudioFlinger::MixerThread::checkForNewParameter_l(const String8& keyValuePa
    -             mAudioMixer = new AudioMixer(mNormalFrameCount, mSampleRate);
    -             for (size_t i = 0; i < mTracks.size() ; i++) {
    -                 int name = getTrackName_l(mTracks[i]->mChannelMask,
    --                        mTracks[i]->mFormat, mTracks[i]->mSessionId);
    -+                        mTracks[i]->mFormat, mTracks[i]->mSessionId, mTracks[i]->uid());
    -                 if (name < 0) {
    -                     break;
    -                 }
    -@@ -5130,8 +5150,11 @@ bool AudioFlinger::DirectOutputThread::shouldStandby_l()
    - 
    - // getTrackName_l() must be called with ThreadBase::mLock held
    - int AudioFlinger::DirectOutputThread::getTrackName_l(audio_channel_mask_t channelMask __unused,
    --        audio_format_t format __unused, audio_session_t sessionId __unused)
    -+        audio_format_t format __unused, audio_session_t sessionId __unused, uid_t uid)
    - {
    -+    if (trackCountForUid_l(uid) > (PlaybackThread::kMaxTracksPerUid - 1)) {
    -+        return -1;
    -+    }
    -     return 0;
    - }
    - 
    -@@ -6556,12 +6579,11 @@ sp<AudioFlinger::RecordThread::RecordTrack> AudioFlinger::RecordThread::createRe
    -           // Do not accept FAST flag if the session has software effects
    -           sp<EffectChain> chain = getEffectChain_l(sessionId);
    -           if (chain != 0) {
    --              ALOGV_IF((*flags & AUDIO_INPUT_FLAG_RAW) != 0,
    --                      "AUDIO_INPUT_FLAG_RAW denied: effect present on session");
    --              *flags = (audio_input_flags_t)(*flags & ~AUDIO_INPUT_FLAG_RAW);
    --              if (chain->hasSoftwareEffect()) {
    --                  ALOGV("AUDIO_INPUT_FLAG_FAST denied: software effect present on session");
    --                  *flags = (audio_input_flags_t)(*flags & ~AUDIO_INPUT_FLAG_FAST);
    -+              audio_input_flags_t old = *flags;
    -+              chain->checkInputFlagCompatibility(flags);
    -+              if (old != *flags) {
    -+                  ALOGV("AUDIO_INPUT_FLAGS denied by effect old=%#x new=%#x",
    -+                          (int)old, (int)*flags);
    -               }
    -           }
    -           ALOGV_IF((*flags & AUDIO_INPUT_FLAG_FAST) != 0,
    -diff --git a/services/audioflinger/Threads.h b/services/audioflinger/Threads.h
    -index 1d5d3c8..f353f3b 100644
    ---- a/services/audioflinger/Threads.h
    -+++ b/services/audioflinger/Threads.h
    -@@ -506,6 +506,8 @@ public:
    -     static const int8_t kMaxTrackRetriesOffload = 20;
    -     static const int8_t kMaxTrackStartupRetriesOffload = 100;
    -     static const int8_t kMaxTrackStopRetriesOffload = 2;
    -+    // 14 tracks max per client allows for 2 misbehaving application leaving 4 available tracks.
    -+    static const uint32_t kMaxTracksPerUid = 14;
    - 
    -     PlaybackThread(const sp<AudioFlinger>& audioFlinger, AudioStreamOut* output,
    -                    audio_io_handle_t id, audio_devices_t device, type_t type, bool systemReady);
    -@@ -736,8 +738,8 @@ protected:
    - 
    -     // Allocate a track name for a given channel mask.
    -     //   Returns name >= 0 if successful, -1 on failure.
    --    virtual int             getTrackName_l(audio_channel_mask_t channelMask,
    --                                           audio_format_t format, audio_session_t sessionId) = 0;
    -+    virtual int             getTrackName_l(audio_channel_mask_t channelMask, audio_format_t format,
    -+                                           audio_session_t sessionId, uid_t uid) = 0;
    -     virtual void            deleteTrackName_l(int name) = 0;
    - 
    -     // Time to sleep between cycles when:
    -@@ -767,6 +769,8 @@ protected:
    -                                     && mHwSupportsPause
    -                                     && (mOutput->flags & AUDIO_OUTPUT_FLAG_HW_AV_SYNC); }
    - 
    -+                uint32_t    trackCountForUid_l(uid_t uid);
    -+
    - private:
    - 
    -     friend class AudioFlinger;      // for numerous
    -@@ -889,8 +893,8 @@ public:
    - 
    - protected:
    -     virtual     mixer_state prepareTracks_l(Vector< sp<Track> > *tracksToRemove);
    --    virtual     int         getTrackName_l(audio_channel_mask_t channelMask,
    --                                           audio_format_t format, audio_session_t sessionId);
    -+    virtual     int         getTrackName_l(audio_channel_mask_t channelMask, audio_format_t format,
    -+                                           audio_session_t sessionId, uid_t uid);
    -     virtual     void        deleteTrackName_l(int name);
    -     virtual     uint32_t    idleSleepTimeUs() const;
    -     virtual     uint32_t    suspendSleepTimeUs() const;
    -@@ -969,8 +973,8 @@ public:
    -     virtual     void        flushHw_l();
    - 
    - protected:
    --    virtual     int         getTrackName_l(audio_channel_mask_t channelMask,
    --                                           audio_format_t format, audio_session_t sessionId);
    -+    virtual     int         getTrackName_l(audio_channel_mask_t channelMask, audio_format_t format,
    -+                                           audio_session_t sessionId, uid_t uid);
    -     virtual     void        deleteTrackName_l(int name);
    -     virtual     uint32_t    activeSleepTimeUs() const;
    -     virtual     uint32_t    idleSleepTimeUs() const;
    -diff --git a/services/audioflinger/Tracks.cpp b/services/audioflinger/Tracks.cpp
    -index b387af3..ba6e6e5 100644
    ---- a/services/audioflinger/Tracks.cpp
    -+++ b/services/audioflinger/Tracks.cpp
    -@@ -388,7 +388,7 @@ AudioFlinger::PlaybackThread::Track::Track(
    -     }
    -     mServerProxy = mAudioTrackServerProxy;
    - 
    --    mName = thread->getTrackName_l(channelMask, format, sessionId);
    -+    mName = thread->getTrackName_l(channelMask, format, sessionId, uid);
    -     if (mName < 0) {
    -         ALOGE("no more track names available");
    -         return;
    -@@ -777,6 +777,13 @@ void AudioFlinger::PlaybackThread::Track::flush()
    -         Mutex::Autolock _l(thread->mLock);
    -         PlaybackThread *playbackThread = (PlaybackThread *)thread.get();
    - 
    -+        // Flush the ring buffer now if the track is not active in the PlaybackThread.
    -+        // Otherwise the flush would not be done until the track is resumed.
    -+        // Requires FastTrack removal be BLOCK_UNTIL_ACKED
    -+        if (playbackThread->mActiveTracks.indexOf(this) < 0) {
    -+            (void)mServerProxy->flushBufferIfNeeded();
    -+        }
    -+
    -         if (isOffloaded()) {
    -             // If offloaded we allow flush during any state except terminated
    -             // and keep the track active to avoid problems if user is seeking
    -@@ -828,6 +835,10 @@ void AudioFlinger::PlaybackThread::Track::flushAck()
    -     if (!isOffloaded() && !isDirect())
    -         return;
    - 
    -+    // Clear the client ring buffer so that the app can prime the buffer while paused.
    -+    // Otherwise it might not get cleared until playback is resumed and obtainBuffer() is called.
    -+    mServerProxy->flushBufferIfNeeded();
    -+
    -     mFlushHwPending = false;
    - }
    - 
    -diff --git a/services/audiopolicy/common/managerdefinitions/include/AudioInputDescriptor.h b/services/audiopolicy/common/managerdefinitions/include/AudioInputDescriptor.h
    -index 46309ed..f2b39f2 100644
    ---- a/services/audiopolicy/common/managerdefinitions/include/AudioInputDescriptor.h
    -+++ b/services/audiopolicy/common/managerdefinitions/include/AudioInputDescriptor.h
    -@@ -93,7 +93,9 @@ public:
    - 
    -     sp<AudioInputDescriptor> getInputFromId(audio_port_handle_t id) const;
    - 
    --    uint32_t activeInputsCount() const;
    -+    // count active capture sessions using one of the specified devices.
    -+    // ignore devices if AUDIO_DEVICE_IN_DEFAULT is passed
    -+    uint32_t activeInputsCountOnDevices(audio_devices_t devices = AUDIO_DEVICE_IN_DEFAULT) const;
    - 
    -     /**
    -      * return io handle of active input or 0 if no input is active
    -diff --git a/services/audiopolicy/common/managerdefinitions/src/AudioInputDescriptor.cpp b/services/audiopolicy/common/managerdefinitions/src/AudioInputDescriptor.cpp
    -index 6dacaa4..c7d2ee4 100644
    ---- a/services/audiopolicy/common/managerdefinitions/src/AudioInputDescriptor.cpp
    -+++ b/services/audiopolicy/common/managerdefinitions/src/AudioInputDescriptor.cpp
    -@@ -222,12 +222,14 @@ sp<AudioInputDescriptor> AudioInputCollection::getInputFromId(audio_port_handle_
    -     return inputDesc;
    - }
    - 
    --uint32_t AudioInputCollection::activeInputsCount() const
    -+uint32_t AudioInputCollection::activeInputsCountOnDevices(audio_devices_t devices) const
    - {
    -     uint32_t count = 0;
    -     for (size_t i = 0; i < size(); i++) {
    -         const sp<AudioInputDescriptor>  inputDescriptor = valueAt(i);
    --        if (inputDescriptor->isActive()) {
    -+        if (inputDescriptor->isActive() &&
    -+                ((devices == AUDIO_DEVICE_IN_DEFAULT) ||
    -+                 ((inputDescriptor->mDevice & devices & ~AUDIO_DEVICE_BIT_IN) != 0))) {
    -             count++;
    -         }
    -     }
    -diff --git a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
    -index b752541..968b80f 100644
    ---- a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
    -+++ b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
    -@@ -1315,16 +1315,23 @@ status_t AudioPolicyManager::stopSource(sp<AudioOutputDescriptor> outputDesc,
    - 
    -             // force restoring the device selection on other active outputs if it differs from the
    -             // one being selected for this output
    -+            uint32_t delayMs = outputDesc->latency()*2;
    -             for (size_t i = 0; i < mOutputs.size(); i++) {
    -                 sp<AudioOutputDescriptor> desc = mOutputs.valueAt(i);
    -                 if (desc != outputDesc &&
    -                         desc->isActive() &&
    -                         outputDesc->sharesHwModuleWith(desc) &&
    -                         (newDevice != desc->device())) {
    -+                    audio_devices_t newDevice2 = getNewOutputDevice(desc, false /*fromCache*/);
    -+                    bool force = desc->device() != newDevice2;
    -                     setOutputDevice(desc,
    --                                    getNewOutputDevice(desc, false /*fromCache*/),
    --                                    true,
    --                                    outputDesc->latency()*2);
    -+                                    newDevice2,
    -+                                    force,
    -+                                    delayMs);
    -+                    // re-apply device specific volume if not done by setOutputDevice()
    -+                    if (!force) {
    -+                        applyStreamVolumes(desc, newDevice2, delayMs);
    -+                    }
    -                 }
    -             }
    -             // update the outputs if stopping one with a stream that can affect notification routing
    -@@ -1681,10 +1688,15 @@ status_t AudioPolicyManager::startInput(audio_io_handle_t input,
    -                     MIX_STATE_MIXING);
    -         }
    - 
    --        if (mInputs.activeInputsCount() == 0) {
    -+        // indicate active capture to sound trigger service if starting capture from a mic on
    -+        // primary HW module
    -+        audio_devices_t device = getNewInputDevice(input);
    -+        audio_devices_t primaryInputDevices = availablePrimaryInputDevices();
    -+        if (((device & primaryInputDevices & ~AUDIO_DEVICE_BIT_IN) != 0) &&
    -+                mInputs.activeInputsCountOnDevices(primaryInputDevices) == 0) {
    -             SoundTrigger::setCaptureState(true);
    -         }
    --        setInputDevice(input, getNewInputDevice(input), true /* force */);
    -+        setInputDevice(input, device, true /* force */);
    - 
    -         // automatically enable the remote submix output when input is started if not
    -         // used by a policy mix of type MIX_TYPE_RECORDERS
    -@@ -1761,9 +1773,14 @@ status_t AudioPolicyManager::stopInput(audio_io_handle_t input,
    -             }
    -         }
    - 
    -+        audio_devices_t device = inputDesc->mDevice;
    -         resetInputDevice(input);
    - 
    --        if (mInputs.activeInputsCount() == 0) {
    -+        // indicate inactive capture to sound trigger service if stopping capture from a mic on
    -+        // primary HW module
    -+        audio_devices_t primaryInputDevices = availablePrimaryInputDevices();
    -+        if (((device & primaryInputDevices & ~AUDIO_DEVICE_BIT_IN) != 0) &&
    -+                mInputs.activeInputsCountOnDevices(primaryInputDevices) == 0) {
    -             SoundTrigger::setCaptureState(false);
    -         }
    -         inputDesc->clearPreemptedSessions();
    -@@ -1901,19 +1918,21 @@ status_t AudioPolicyManager::setStreamVolumeIndex(audio_stream_type_t stream,
    -                 continue;
    -             }
    -             routing_strategy curStrategy = getStrategy((audio_stream_type_t)curStream);
    --            audio_devices_t curStreamDevice = getDeviceForStrategy(curStrategy, true /*fromCache*/);
    --            if ((curStreamDevice & device) == 0) {
    -+            audio_devices_t curStreamDevice = getDeviceForStrategy(curStrategy, false /*fromCache*/);
    -+            if ((device != AUDIO_DEVICE_OUT_DEFAULT_FOR_VOLUME) &&
    -+                    ((curStreamDevice & device) == 0)) {
    -                 continue;
    -             }
    --            bool applyDefault = false;
    -+            bool applyVolume;
    -             if (device != AUDIO_DEVICE_OUT_DEFAULT_FOR_VOLUME) {
    -                 curStreamDevice |= device;
    --            } else if (!mVolumeCurves->hasVolumeIndexForDevice(
    --                    stream, Volume::getDeviceForVolume(curStreamDevice))) {
    --                applyDefault = true;
    -+                applyVolume = (curDevice & curStreamDevice) != 0;
    -+            } else {
    -+                applyVolume = !mVolumeCurves->hasVolumeIndexForDevice(
    -+                        stream, Volume::getDeviceForVolume(curStreamDevice));
    -             }
    - 
    --            if (applyDefault || ((curDevice & curStreamDevice) != 0)) {
    -+            if (applyVolume) {
    -                 //FIXME: workaround for truncated touch sounds
    -                 // delayed volume change for system stream to be removed when the problem is
    -                 // handled by system UI
    -@@ -4937,6 +4956,18 @@ float AudioPolicyManager::computeVolume(audio_stream_type_t stream,
    -                                         audio_devices_t device)
    - {
    -     float volumeDB = mVolumeCurves->volIndexToDb(stream, Volume::getDeviceCategory(device), index);
    -+
    -+    // handle the case of accessibility active while a ringtone is playing: if the ringtone is much
    -+    // louder than the accessibility prompt, the prompt cannot be heard, thus masking the touch
    -+    // exploration of the dialer UI. In this situation, bring the accessibility volume closer to
    -+    // the ringtone volume
    -+    if ((stream == AUDIO_STREAM_ACCESSIBILITY)
    -+            && (AUDIO_MODE_RINGTONE == mEngine->getPhoneState())
    -+            && isStreamActive(AUDIO_STREAM_RING, 0)) {
    -+        const float ringVolumeDB = computeVolume(AUDIO_STREAM_RING, index, device);
    -+        return ringVolumeDB - 4 > volumeDB ? ringVolumeDB - 4 : volumeDB;
    -+    }
    -+
    -     // if a headset is connected, apply the following rules to ring tones and notifications
    -     // to avoid sound level bursts in user's ears:
    -     // - always attenuate notifications volume by 6dB
     diff --git a/services/camera/libcameraservice/Android.mk b/services/camera/libcameraservice/Android.mk
     index 8d7f71c..d98ad47 100644
     --- a/services/camera/libcameraservice/Android.mk
    @@ -3635,241 +450,3 @@ index 266fb03..3c2b98a 100644
      }
      
      status_t CameraClient::setVideoBufferMode(int32_t videoBufferMode) {
    -diff --git a/services/camera/libcameraservice/api1/client2/Parameters.cpp b/services/camera/libcameraservice/api1/client2/Parameters.cpp
    -index 9d5f33c..9a7839b 100644
    ---- a/services/camera/libcameraservice/api1/client2/Parameters.cpp
    -+++ b/services/camera/libcameraservice/api1/client2/Parameters.cpp
    -@@ -238,6 +238,10 @@ status_t Parameters::initialize(const CameraMetadata *info, int deviceVersion) {
    -     {
    -         String8 supportedPreviewFpsRange;
    -         for (size_t i=0; i < availableFpsRanges.count; i += 2) {
    -+            if (!isFpsSupported(availablePreviewSizes,
    -+                HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED, availableFpsRanges.data.i32[i+1])) {
    -+                continue;
    -+            }
    -             if (i != 0) supportedPreviewFpsRange += ",";
    -             supportedPreviewFpsRange += String8::format("(%d,%d)",
    -                     availableFpsRanges.data.i32[i] * kFpsToApiScale,
    -@@ -255,7 +259,10 @@ status_t Parameters::initialize(const CameraMetadata *info, int deviceVersion) {
    -             // from the [min, max] fps range use the max value
    -             int fps = fpsFromRange(availableFpsRanges.data.i32[i],
    -                                    availableFpsRanges.data.i32[i+1]);
    --
    -+            if (!isFpsSupported(availablePreviewSizes,
    -+                    HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED, fps)) {
    -+                continue;
    -+            }
    -             // de-dupe frame rates
    -             if (sortedPreviewFrameRates.indexOf(fps) == NAME_NOT_FOUND) {
    -                 sortedPreviewFrameRates.add(fps);
    -@@ -951,21 +958,40 @@ status_t Parameters::buildFastInfo() {
    -         return NO_INIT;
    -     }
    - 
    -+    // Get supported preview fps ranges.
    -+    Vector<Size> supportedPreviewSizes;
    -+    Vector<FpsRange> supportedPreviewFpsRanges;
    -+    const Size PREVIEW_SIZE_BOUND = { MAX_PREVIEW_WIDTH, MAX_PREVIEW_HEIGHT };
    -+    status_t res = getFilteredSizes(PREVIEW_SIZE_BOUND, &supportedPreviewSizes);
    -+    if (res != OK) return res;
    -+    for (size_t i=0; i < availableFpsRanges.count; i += 2) {
    -+        if (!isFpsSupported(supportedPreviewSizes,
    -+                HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED, availableFpsRanges.data.i32[i+1])) {
    -+            continue;
    -+        }
    -+        FpsRange fpsRange = {availableFpsRanges.data.i32[i], availableFpsRanges.data.i32[i+1]};
    -+        supportedPreviewFpsRanges.add(fpsRange);
    -+    }
    -+    if (supportedPreviewFpsRanges.size() == 0) {
    -+        ALOGE("Supported preview fps range is empty");
    -+        return NO_INIT;
    -+    }
    -+
    -     int32_t bestStillCaptureFpsRange[2] = {
    --        availableFpsRanges.data.i32[0], availableFpsRanges.data.i32[1]
    -+        supportedPreviewFpsRanges[0].low, supportedPreviewFpsRanges[0].high
    -     };
    -     int32_t curRange =
    -             bestStillCaptureFpsRange[1] - bestStillCaptureFpsRange[0];
    --    for (size_t i = 2; i < availableFpsRanges.count; i += 2) {
    -+    for (size_t i = 1; i < supportedPreviewFpsRanges.size(); i ++) {
    -         int32_t nextRange =
    --                availableFpsRanges.data.i32[i + 1] -
    --                availableFpsRanges.data.i32[i];
    -+                supportedPreviewFpsRanges[i].high -
    -+                supportedPreviewFpsRanges[i].low;
    -         if ( (nextRange > curRange) ||       // Maximize size of FPS range first
    -                 (nextRange == curRange &&    // Then minimize low-end FPS
    --                 bestStillCaptureFpsRange[0] > availableFpsRanges.data.i32[i])) {
    -+                 bestStillCaptureFpsRange[0] > supportedPreviewFpsRanges[i].low)) {
    - 
    --            bestStillCaptureFpsRange[0] = availableFpsRanges.data.i32[i];
    --            bestStillCaptureFpsRange[1] = availableFpsRanges.data.i32[i + 1];
    -+            bestStillCaptureFpsRange[0] = supportedPreviewFpsRanges[i].low;
    -+            bestStillCaptureFpsRange[1] = supportedPreviewFpsRanges[i].high;
    -             curRange = nextRange;
    -         }
    -     }
    -@@ -2836,22 +2862,7 @@ Vector<Parameters::StreamConfiguration> Parameters::getStreamConfigurations() {
    - 
    - int64_t Parameters::getJpegStreamMinFrameDurationNs(Parameters::Size size) {
    -     if (mDeviceVersion >= CAMERA_DEVICE_API_VERSION_3_2) {
    --        const int STREAM_DURATION_SIZE = 4;
    --        const int STREAM_FORMAT_OFFSET = 0;
    --        const int STREAM_WIDTH_OFFSET = 1;
    --        const int STREAM_HEIGHT_OFFSET = 2;
    --        const int STREAM_DURATION_OFFSET = 3;
    --        camera_metadata_ro_entry_t availableStreamMinDurations =
    --                    staticInfo(ANDROID_SCALER_AVAILABLE_MIN_FRAME_DURATIONS);
    --        for (size_t i = 0; i < availableStreamMinDurations.count; i+= STREAM_DURATION_SIZE) {
    --            int64_t format = availableStreamMinDurations.data.i64[i + STREAM_FORMAT_OFFSET];
    --            int64_t width = availableStreamMinDurations.data.i64[i + STREAM_WIDTH_OFFSET];
    --            int64_t height = availableStreamMinDurations.data.i64[i + STREAM_HEIGHT_OFFSET];
    --            int64_t duration = availableStreamMinDurations.data.i64[i + STREAM_DURATION_OFFSET];
    --            if (format == HAL_PIXEL_FORMAT_BLOB && width == size.width && height == size.height) {
    --                return duration;
    --            }
    --        }
    -+        return getMinFrameDurationNs(size, HAL_PIXEL_FORMAT_BLOB);
    -     } else {
    -         Vector<Size> availableJpegSizes = getAvailableJpegSizes();
    -         size_t streamIdx = availableJpegSizes.size();
    -@@ -2875,6 +2886,57 @@ int64_t Parameters::getJpegStreamMinFrameDurationNs(Parameters::Size size) {
    -     return -1;
    - }
    - 
    -+int64_t Parameters::getMinFrameDurationNs(Parameters::Size size, int fmt) {
    -+    if (mDeviceVersion < CAMERA_DEVICE_API_VERSION_3_2) {
    -+        ALOGE("Min frame duration for HAL 3.1 or lower is not supported");
    -+        return -1;
    -+    }
    -+
    -+    const int STREAM_DURATION_SIZE = 4;
    -+    const int STREAM_FORMAT_OFFSET = 0;
    -+    const int STREAM_WIDTH_OFFSET = 1;
    -+    const int STREAM_HEIGHT_OFFSET = 2;
    -+    const int STREAM_DURATION_OFFSET = 3;
    -+    camera_metadata_ro_entry_t availableStreamMinDurations =
    -+                staticInfo(ANDROID_SCALER_AVAILABLE_MIN_FRAME_DURATIONS);
    -+    for (size_t i = 0; i < availableStreamMinDurations.count; i+= STREAM_DURATION_SIZE) {
    -+        int64_t format = availableStreamMinDurations.data.i64[i + STREAM_FORMAT_OFFSET];
    -+        int64_t width = availableStreamMinDurations.data.i64[i + STREAM_WIDTH_OFFSET];
    -+        int64_t height = availableStreamMinDurations.data.i64[i + STREAM_HEIGHT_OFFSET];
    -+        int64_t duration = availableStreamMinDurations.data.i64[i + STREAM_DURATION_OFFSET];
    -+        if (format == fmt && width == size.width && height == size.height) {
    -+            return duration;
    -+        }
    -+    }
    -+
    -+    return -1;
    -+}
    -+
    -+bool Parameters::isFpsSupported(const Vector<Size> &sizes, int format, int32_t fps) {
    -+    // Skip the check for older HAL version, as the min duration is not supported.
    -+    if (mDeviceVersion < CAMERA_DEVICE_API_VERSION_3_2) {
    -+        return true;
    -+    }
    -+
    -+    // Get min frame duration for each size and check if the given fps range can be supported.
    -+    const int32_t FPS_MARGIN = 1;
    -+    for (size_t i = 0 ; i < sizes.size(); i++) {
    -+        int64_t minFrameDuration = getMinFrameDurationNs(sizes[i], format);
    -+        if (minFrameDuration <= 0) {
    -+            ALOGE("Min frame duration (%" PRId64") for size (%dx%d) and format 0x%x is wrong!",
    -+                minFrameDuration, sizes[i].width, sizes[i].height, format);
    -+            return false;
    -+        }
    -+        int32_t maxSupportedFps = 1e9 / minFrameDuration;
    -+        // Add some margin here for the case where the hal supports 29.xxxfps.
    -+        maxSupportedFps += FPS_MARGIN;
    -+        if (fps > maxSupportedFps) {
    -+            return false;
    -+        }
    -+    }
    -+    return true;
    -+}
    -+
    - SortedVector<int32_t> Parameters::getAvailableOutputFormats() {
    -     SortedVector<int32_t> outputFormats; // Non-duplicated output formats
    -     if (mDeviceVersion >= CAMERA_DEVICE_API_VERSION_3_2) {
    -diff --git a/services/camera/libcameraservice/api1/client2/Parameters.h b/services/camera/libcameraservice/api1/client2/Parameters.h
    -index f4bb34c..687ac3e 100644
    ---- a/services/camera/libcameraservice/api1/client2/Parameters.h
    -+++ b/services/camera/libcameraservice/api1/client2/Parameters.h
    -@@ -115,6 +115,11 @@ struct Parameters {
    -         int32_t height;
    -     };
    - 
    -+    struct FpsRange {
    -+        int32_t low;
    -+        int32_t high;
    -+    };
    -+
    -     int32_t exposureCompensation;
    -     bool autoExposureLock;
    -     bool autoWhiteBalanceLock;
    -@@ -390,6 +395,15 @@ private:
    -     // return -1 if input jpeg size cannot be found in supported size list
    -     int64_t getJpegStreamMinFrameDurationNs(Parameters::Size size);
    - 
    -+    // Helper function to get minimum frame duration for a size/format combination
    -+    // return -1 if input size/format combination cannot be found.
    -+    int64_t getMinFrameDurationNs(Parameters::Size size, int format);
    -+
    -+    // Helper function to check if a given fps is supported by all the sizes with
    -+    // the same format.
    -+    // return true if the device doesn't support min frame duration metadata tag.
    -+    bool isFpsSupported(const Vector<Size> &size, int format, int32_t fps);
    -+
    -     // Helper function to get non-duplicated available output formats
    -     SortedVector<int32_t> getAvailableOutputFormats();
    -     // Helper function to get available output jpeg sizes
    -diff --git a/services/camera/libcameraservice/device3/Camera3Device.cpp b/services/camera/libcameraservice/device3/Camera3Device.cpp
    -index aeab451..48a2a99 100644
    ---- a/services/camera/libcameraservice/device3/Camera3Device.cpp
    -+++ b/services/camera/libcameraservice/device3/Camera3Device.cpp
    -@@ -170,6 +170,9 @@ status_t Camera3Device::initialize(CameraModule *module)
    -         return res;
    -     }
    - 
    -+    /** Register in-flight map to the status tracker */
    -+    mInFlightStatusId = mStatusTracker->addComponent();
    -+
    -     /** Create buffer manager */
    -     mBufferManager = new Camera3BufferManager();
    - 
    -@@ -2196,6 +2199,10 @@ status_t Camera3Device::registerInFlight(uint32_t frameNumber,
    -             aeTriggerCancelOverride));
    -     if (res < 0) return res;
    - 
    -+    if (mInFlightMap.size() == 1) {
    -+        mStatusTracker->markComponentActive(mInFlightStatusId);
    -+    }
    -+
    -     return OK;
    - }
    - 
    -@@ -2252,6 +2259,11 @@ void Camera3Device::removeInFlightRequestIfReadyLocked(int idx) {
    - 
    -         mInFlightMap.removeItemsAt(idx, 1);
    - 
    -+        // Indicate idle inFlightMap to the status tracker
    -+        if (mInFlightMap.size() == 0) {
    -+            mStatusTracker->markComponentIdle(mInFlightStatusId, Fence::NO_FENCE);
    -+        }
    -+
    -         ALOGVV("%s: removed frame %d from InFlightMap", __FUNCTION__, frameNumber);
    -      }
    - 
    -diff --git a/services/camera/libcameraservice/device3/Camera3Device.h b/services/camera/libcameraservice/device3/Camera3Device.h
    -index 3244258..17893a9 100644
    ---- a/services/camera/libcameraservice/device3/Camera3Device.h
    -+++ b/services/camera/libcameraservice/device3/Camera3Device.h
    -@@ -725,6 +725,7 @@ class Camera3Device :
    - 
    -     Mutex                  mInFlightLock; // Protects mInFlightMap
    -     InFlightMap            mInFlightMap;
    -+    int                    mInFlightStatusId;
    - 
    -     status_t registerInFlight(uint32_t frameNumber,
    -             int32_t numBuffers, CaptureResultExtras resultExtras, bool hasInput,
    diff --git a/frameworks_base.patch b/frameworks_base.patch
    index ee99cdf..c91c6a1 100644
    --- a/frameworks_base.patch
    +++ b/frameworks_base.patch
    @@ -1,150929 +1,381 @@
    -diff --git a/Android.mk b/Android.mk
    -index 2c99df7..d813c91 100644
    ---- a/Android.mk
    -+++ b/Android.mk
    -@@ -199,6 +199,7 @@ LOCAL_SRC_FILES += \
    - 	core/java/android/net/ICaptivePortal.aidl \
    - 	core/java/android/net/IConnectivityManager.aidl \
    - 	core/java/android/net/IConnectivityMetricsLogger.aidl \
    -+	core/java/android/net/IIpConnectivityMetrics.aidl \
    - 	core/java/android/net/IEthernetManager.aidl \
    - 	core/java/android/net/IEthernetServiceListener.aidl \
    - 	core/java/android/net/INetworkManagementEventObserver.aidl \
    -@@ -859,6 +860,7 @@ framework_docs_LOCAL_DROIDDOC_OPTIONS := \
    -     -since $(SRC_API_DIR)/22.txt 22 \
    -     -since $(SRC_API_DIR)/23.txt 23 \
    -     -since $(SRC_API_DIR)/24.txt 24 \
    -+    -since $(SRC_API_DIR)/25.txt 25 \
    - 		-werror -hide 111 -hide 113 \
    - 		-overview $(LOCAL_PATH)/core/java/overview.html
    - 
    -@@ -926,6 +928,7 @@ LOCAL_DROIDDOC_STUB_OUT_DIR := $(TARGET_OUT_COMMON_INTERMEDIATES)/JAVA_LIBRARIES
    - 
    - LOCAL_DROIDDOC_OPTIONS:=\
    - 		$(framework_docs_LOCAL_DROIDDOC_OPTIONS) \
    -+		-referenceonly \
    - 		-api $(INTERNAL_PLATFORM_API_FILE) \
    - 		-removedApi $(INTERNAL_PLATFORM_REMOVED_API_FILE) \
    - 		-nodocs
    -@@ -959,6 +962,7 @@ LOCAL_DROIDDOC_STUB_OUT_DIR := $(TARGET_OUT_COMMON_INTERMEDIATES)/JAVA_LIBRARIES
    - 
    - LOCAL_DROIDDOC_OPTIONS:=\
    - 		$(framework_docs_LOCAL_DROIDDOC_OPTIONS) \
    -+		-referenceonly \
    - 		-showAnnotation android.annotation.SystemApi \
    - 		-api $(INTERNAL_PLATFORM_SYSTEM_API_FILE) \
    - 		-removedApi $(INTERNAL_PLATFORM_SYSTEM_REMOVED_API_FILE) \
    -@@ -993,6 +997,7 @@ LOCAL_DROIDDOC_STUB_OUT_DIR := $(TARGET_OUT_COMMON_INTERMEDIATES)/JAVA_LIBRARIES
    - 
    - LOCAL_DROIDDOC_OPTIONS:=\
    -                $(framework_docs_LOCAL_DROIDDOC_OPTIONS) \
    -+               -referenceonly \
    -                -stubs $(TARGET_OUT_COMMON_INTERMEDIATES)/JAVA_LIBRARIES/android_test_stubs_current_intermediates/src \
    -                -showAnnotation android.annotation.TestApi \
    -                -api $(INTERNAL_PLATFORM_TEST_API_FILE) \
    -@@ -1026,6 +1031,7 @@ LOCAL_MODULE := doc-comment-check
    - 
    - LOCAL_DROIDDOC_OPTIONS:=\
    - 		$(framework_docs_LOCAL_DROIDDOC_OPTIONS) \
    -+		-referenceonly \
    - 		-parsecomments
    - 
    - LOCAL_DROIDDOC_CUSTOM_TEMPLATE_DIR:=build/tools/droiddoc/templates-sdk
    -@@ -1064,7 +1070,7 @@ LOCAL_DROIDDOC_OPTIONS:=\
    - 		-sdkvalues $(OUT_DOCS) \
    - 		-hdf android.whichdoc offline
    - 
    --LOCAL_DROIDDOC_CUSTOM_TEMPLATE_DIR:=build/tools/droiddoc/templates-sdk-dev
    -+LOCAL_DROIDDOC_CUSTOM_TEMPLATE_DIR:=build/tools/droiddoc/templates-sdk
    - 
    - include $(BUILD_DROIDDOC)
    - 
    -@@ -1101,7 +1107,7 @@ LOCAL_DROIDDOC_OPTIONS:=\
    - 		-hdf android.whichdoc offline \
    - 		-referenceonly
    - 
    --LOCAL_DROIDDOC_CUSTOM_TEMPLATE_DIR:=build/tools/droiddoc/templates-sdk-dev
    -+LOCAL_DROIDDOC_CUSTOM_TEMPLATE_DIR:=build/tools/droiddoc/templates-sdk
    - 
    - include $(BUILD_DROIDDOC)
    - 
    -@@ -1111,7 +1117,14 @@ $(static_doc_index_redirect): \
    - 	$(hide) mkdir -p $(dir $@)
    - 	$(hide) $(ACP) $< $@
    - 
    -+static_doc_properties := $(out_dir)/source.properties
    -+$(static_doc_properties): \
    -+	$(LOCAL_PATH)/docs/source.properties | $(ACP)
    -+	$(hide) mkdir -p $(dir $@)
    -+	$(hide) $(ACP) $< $@
    -+
    - $(full_target): $(static_doc_index_redirect)
    -+$(full_target): $(static_doc_properties)
    - $(full_target): $(framework_built)
    - 
    - 
    -@@ -1139,7 +1152,7 @@ LOCAL_DROIDDOC_OPTIONS:= \
    - 		-hdf android.hasSamples true \
    - 		-samplesdir $(samples_dir)
    - 
    --LOCAL_DROIDDOC_CUSTOM_TEMPLATE_DIR:=build/tools/droiddoc/templates-sdk-dev
    -+LOCAL_DROIDDOC_CUSTOM_TEMPLATE_DIR:=build/tools/droiddoc/templates-sdk
    - 
    - include $(BUILD_DROIDDOC)
    - 
    -@@ -1163,6 +1176,7 @@ LOCAL_MODULE := online-system-api-sdk
    - 
    - LOCAL_DROIDDOC_OPTIONS:= \
    - 		$(framework_docs_LOCAL_DROIDDOC_OPTIONS) \
    -+		-referenceonly \
    - 		-showAnnotation android.annotation.SystemApi \
    - 		-title "Android SDK - Including system APIs." \
    - 		-toroot / \
    -@@ -1206,7 +1220,7 @@ LOCAL_DROIDDOC_OPTIONS:= \
    - 		-hdf android.hasSamples true \
    - 		-samplesdir $(samples_dir)
    - 
    --LOCAL_DROIDDOC_CUSTOM_TEMPLATE_DIR:=build/tools/droiddoc/templates-sdk-dev
    -+LOCAL_DROIDDOC_CUSTOM_TEMPLATE_DIR:=build/tools/droiddoc/templates-sdk
    - 
    - include $(BUILD_DROIDDOC)
    - 
    -@@ -1234,7 +1248,32 @@ LOCAL_DROIDDOC_OPTIONS:= \
    - 		-devsite \
    - 		-ignoreJdLinks
    - 
    --LOCAL_DROIDDOC_CUSTOM_TEMPLATE_DIR:=build/tools/droiddoc/templates-sdk-dev
    -+LOCAL_DROIDDOC_CUSTOM_TEMPLATE_DIR:=build/tools/droiddoc/templates-sdk
    -+
    -+include $(BUILD_DROIDDOC)
    -+
    -+# ==== generates full navtree for resolving @links in ds postprocessing ====
    -+include $(CLEAR_VARS)
    -+
    -+LOCAL_SRC_FILES:=$(framework_docs_LOCAL_SRC_FILES)
    -+LOCAL_INTERMEDIATE_SOURCES:=$(framework_docs_LOCAL_INTERMEDIATE_SOURCES)
    -+LOCAL_STATIC_JAVA_LIBRARIES:=$(framework_docs_LOCAL_STATIC_JAVA_LIBRARIES)
    -+LOCAL_JAVA_LIBRARIES:=$(framework_docs_LOCAL_JAVA_LIBRARIES)
    -+LOCAL_MODULE_CLASS:=$(framework_docs_LOCAL_MODULE_CLASS)
    -+LOCAL_DROIDDOC_SOURCE_PATH:=$(framework_docs_LOCAL_DROIDDOC_SOURCE_PATH)
    -+LOCAL_ADDITIONAL_JAVA_DIR:=$(framework_docs_LOCAL_ADDITIONAL_JAVA_DIR)
    -+LOCAL_ADDITIONAL_DEPENDENCIES:=$(framework_docs_LOCAL_ADDITIONAL_DEPENDENCIES)
    -+
    -+LOCAL_MODULE := ds-ref-navtree
    -+
    -+LOCAL_DROIDDOC_OPTIONS:= \
    -+		$(framework_docs_LOCAL_DROIDDOC_OPTIONS) \
    -+		-hdf android.whichdoc online \
    -+		-toroot / \
    -+		-atLinksNavtree \
    -+		-navtreeonly
    -+
    -+LOCAL_DROIDDOC_CUSTOM_TEMPLATE_DIR:=build/tools/droiddoc/templates-sdk
    - 
    - include $(BUILD_DROIDDOC)
    - 
    -@@ -1259,11 +1298,10 @@ LOCAL_DROIDDOC_OPTIONS:= \
    - 		-toroot / \
    - 		-hdf android.whichdoc online \
    - 		$(sample_groups) \
    --		-useUpdatedTemplates \
    - 		-hdf android.hasSamples true \
    - 		-samplesdir $(samples_dir)
    - 
    --LOCAL_DROIDDOC_CUSTOM_TEMPLATE_DIR:=build/tools/droiddoc/templates-sdk-dev
    -+LOCAL_DROIDDOC_CUSTOM_TEMPLATE_DIR:=build/tools/droiddoc/templates-sdk
    - 
    - include $(BUILD_DROIDDOC)
    - 
    -@@ -1282,6 +1320,7 @@ LOCAL_ADDITIONAL_DEPENDENCIES:=$(framework_docs_LOCAL_ADDITIONAL_DEPENDENCIES)
    - LOCAL_MODULE := hidden
    - LOCAL_DROIDDOC_OPTIONS:=\
    - 		$(framework_docs_LOCAL_DROIDDOC_OPTIONS) \
    -+		-referenceonly \
    - 		-title "Android SDK - Including hidden APIs."
    - #		-hidden
    - 
    -diff --git a/api/current.txt b/api/current.txt
    -index 533b577..8655d89 100644
    ---- a/api/current.txt
    -+++ b/api/current.txt
    -@@ -2906,11 +2906,11 @@ package android.accounts {
    -     field public static final java.lang.String LOGIN_ACCOUNTS_CHANGED_ACTION = "android.accounts.LOGIN_ACCOUNTS_CHANGED";
    -   }
    - 
    --  public abstract interface AccountManagerCallback {
    -+  public abstract interface AccountManagerCallback<V> {
    -     method public abstract void run(android.accounts.AccountManagerFuture<V>);
    -   }
    - 
    --  public abstract interface AccountManagerFuture {
    -+  public abstract interface AccountManagerFuture<V> {
    -     method public abstract boolean cancel(boolean);
    -     method public abstract V getResult() throws android.accounts.AuthenticatorException, java.io.IOException, android.accounts.OperationCanceledException;
    -     method public abstract V getResult(long, java.util.concurrent.TimeUnit) throws android.accounts.AuthenticatorException, java.io.IOException, android.accounts.OperationCanceledException;
    -@@ -3056,7 +3056,7 @@ package android.animation {
    -     method public java.lang.Object evaluate(float, java.lang.Object, java.lang.Object);
    -   }
    - 
    --  public abstract class BidirectionalTypeConverter extends android.animation.TypeConverter {
    -+  public abstract class BidirectionalTypeConverter<T, V> extends android.animation.TypeConverter {
    -     ctor public BidirectionalTypeConverter(java.lang.Class<T>, java.lang.Class<V>);
    -     method public abstract T convertBack(V);
    -     method public android.animation.BidirectionalTypeConverter<V, T> invert();
    -@@ -3148,26 +3148,26 @@ package android.animation {
    -     method public java.lang.String getPropertyName();
    -     method public java.lang.Object getTarget();
    -     method public static android.animation.ObjectAnimator ofArgb(java.lang.Object, java.lang.String, int...);
    --    method public static android.animation.ObjectAnimator ofArgb(T, android.util.Property<T, java.lang.Integer>, int...);
    -+    method public static <T> android.animation.ObjectAnimator ofArgb(T, android.util.Property<T, java.lang.Integer>, int...);
    -     method public static android.animation.ObjectAnimator ofFloat(java.lang.Object, java.lang.String, float...);
    -     method public static android.animation.ObjectAnimator ofFloat(java.lang.Object, java.lang.String, java.lang.String, android.graphics.Path);
    --    method public static android.animation.ObjectAnimator ofFloat(T, android.util.Property<T, java.lang.Float>, float...);
    --    method public static android.animation.ObjectAnimator ofFloat(T, android.util.Property<T, java.lang.Float>, android.util.Property<T, java.lang.Float>, android.graphics.Path);
    -+    method public static <T> android.animation.ObjectAnimator ofFloat(T, android.util.Property<T, java.lang.Float>, float...);
    -+    method public static <T> android.animation.ObjectAnimator ofFloat(T, android.util.Property<T, java.lang.Float>, android.util.Property<T, java.lang.Float>, android.graphics.Path);
    -     method public static android.animation.ObjectAnimator ofInt(java.lang.Object, java.lang.String, int...);
    -     method public static android.animation.ObjectAnimator ofInt(java.lang.Object, java.lang.String, java.lang.String, android.graphics.Path);
    --    method public static android.animation.ObjectAnimator ofInt(T, android.util.Property<T, java.lang.Integer>, int...);
    --    method public static android.animation.ObjectAnimator ofInt(T, android.util.Property<T, java.lang.Integer>, android.util.Property<T, java.lang.Integer>, android.graphics.Path);
    -+    method public static <T> android.animation.ObjectAnimator ofInt(T, android.util.Property<T, java.lang.Integer>, int...);
    -+    method public static <T> android.animation.ObjectAnimator ofInt(T, android.util.Property<T, java.lang.Integer>, android.util.Property<T, java.lang.Integer>, android.graphics.Path);
    -     method public static android.animation.ObjectAnimator ofMultiFloat(java.lang.Object, java.lang.String, float[][]);
    -     method public static android.animation.ObjectAnimator ofMultiFloat(java.lang.Object, java.lang.String, android.graphics.Path);
    --    method public static android.animation.ObjectAnimator ofMultiFloat(java.lang.Object, java.lang.String, android.animation.TypeConverter<T, float[]>, android.animation.TypeEvaluator<T>, T...);
    -+    method public static <T> android.animation.ObjectAnimator ofMultiFloat(java.lang.Object, java.lang.String, android.animation.TypeConverter<T, float[]>, android.animation.TypeEvaluator<T>, T...);
    -     method public static android.animation.ObjectAnimator ofMultiInt(java.lang.Object, java.lang.String, int[][]);
    -     method public static android.animation.ObjectAnimator ofMultiInt(java.lang.Object, java.lang.String, android.graphics.Path);
    --    method public static android.animation.ObjectAnimator ofMultiInt(java.lang.Object, java.lang.String, android.animation.TypeConverter<T, int[]>, android.animation.TypeEvaluator<T>, T...);
    -+    method public static <T> android.animation.ObjectAnimator ofMultiInt(java.lang.Object, java.lang.String, android.animation.TypeConverter<T, int[]>, android.animation.TypeEvaluator<T>, T...);
    -     method public static android.animation.ObjectAnimator ofObject(java.lang.Object, java.lang.String, android.animation.TypeEvaluator, java.lang.Object...);
    -     method public static android.animation.ObjectAnimator ofObject(java.lang.Object, java.lang.String, android.animation.TypeConverter<android.graphics.PointF, ?>, android.graphics.Path);
    --    method public static android.animation.ObjectAnimator ofObject(T, android.util.Property<T, V>, android.animation.TypeEvaluator<V>, V...);
    --    method public static android.animation.ObjectAnimator ofObject(T, android.util.Property<T, P>, android.animation.TypeConverter<V, P>, android.animation.TypeEvaluator<V>, V...);
    --    method public static android.animation.ObjectAnimator ofObject(T, android.util.Property<T, V>, android.animation.TypeConverter<android.graphics.PointF, V>, android.graphics.Path);
    -+    method public static <T, V> android.animation.ObjectAnimator ofObject(T, android.util.Property<T, V>, android.animation.TypeEvaluator<V>, V...);
    -+    method public static <T, V, P> android.animation.ObjectAnimator ofObject(T, android.util.Property<T, P>, android.animation.TypeConverter<V, P>, android.animation.TypeEvaluator<V>, V...);
    -+    method public static <T, V> android.animation.ObjectAnimator ofObject(T, android.util.Property<T, V>, android.animation.TypeConverter<android.graphics.PointF, V>, android.graphics.Path);
    -     method public static android.animation.ObjectAnimator ofPropertyValuesHolder(java.lang.Object, android.animation.PropertyValuesHolder...);
    -     method public void setAutoCancel(boolean);
    -     method public void setProperty(android.util.Property);
    -@@ -3191,17 +3191,17 @@ package android.animation {
    -     method public static android.animation.PropertyValuesHolder ofKeyframe(android.util.Property, android.animation.Keyframe...);
    -     method public static android.animation.PropertyValuesHolder ofMultiFloat(java.lang.String, float[][]);
    -     method public static android.animation.PropertyValuesHolder ofMultiFloat(java.lang.String, android.graphics.Path);
    --    method public static android.animation.PropertyValuesHolder ofMultiFloat(java.lang.String, android.animation.TypeConverter<V, float[]>, android.animation.TypeEvaluator<V>, V...);
    --    method public static android.animation.PropertyValuesHolder ofMultiFloat(java.lang.String, android.animation.TypeConverter<T, float[]>, android.animation.TypeEvaluator<T>, android.animation.Keyframe...);
    -+    method public static <V> android.animation.PropertyValuesHolder ofMultiFloat(java.lang.String, android.animation.TypeConverter<V, float[]>, android.animation.TypeEvaluator<V>, V...);
    -+    method public static <T> android.animation.PropertyValuesHolder ofMultiFloat(java.lang.String, android.animation.TypeConverter<T, float[]>, android.animation.TypeEvaluator<T>, android.animation.Keyframe...);
    -     method public static android.animation.PropertyValuesHolder ofMultiInt(java.lang.String, int[][]);
    -     method public static android.animation.PropertyValuesHolder ofMultiInt(java.lang.String, android.graphics.Path);
    --    method public static android.animation.PropertyValuesHolder ofMultiInt(java.lang.String, android.animation.TypeConverter<V, int[]>, android.animation.TypeEvaluator<V>, V...);
    --    method public static android.animation.PropertyValuesHolder ofMultiInt(java.lang.String, android.animation.TypeConverter<T, int[]>, android.animation.TypeEvaluator<T>, android.animation.Keyframe...);
    -+    method public static <V> android.animation.PropertyValuesHolder ofMultiInt(java.lang.String, android.animation.TypeConverter<V, int[]>, android.animation.TypeEvaluator<V>, V...);
    -+    method public static <T> android.animation.PropertyValuesHolder ofMultiInt(java.lang.String, android.animation.TypeConverter<T, int[]>, android.animation.TypeEvaluator<T>, android.animation.Keyframe...);
    -     method public static android.animation.PropertyValuesHolder ofObject(java.lang.String, android.animation.TypeEvaluator, java.lang.Object...);
    -     method public static android.animation.PropertyValuesHolder ofObject(java.lang.String, android.animation.TypeConverter<android.graphics.PointF, ?>, android.graphics.Path);
    --    method public static android.animation.PropertyValuesHolder ofObject(android.util.Property, android.animation.TypeEvaluator<V>, V...);
    --    method public static android.animation.PropertyValuesHolder ofObject(android.util.Property<?, V>, android.animation.TypeConverter<T, V>, android.animation.TypeEvaluator<T>, T...);
    --    method public static android.animation.PropertyValuesHolder ofObject(android.util.Property<?, V>, android.animation.TypeConverter<android.graphics.PointF, V>, android.graphics.Path);
    -+    method public static <V> android.animation.PropertyValuesHolder ofObject(android.util.Property, android.animation.TypeEvaluator<V>, V...);
    -+    method public static <T, V> android.animation.PropertyValuesHolder ofObject(android.util.Property<?, V>, android.animation.TypeConverter<T, V>, android.animation.TypeEvaluator<T>, T...);
    -+    method public static <V> android.animation.PropertyValuesHolder ofObject(android.util.Property<?, V>, android.animation.TypeConverter<android.graphics.PointF, V>, android.graphics.Path);
    -     method public void setConverter(android.animation.TypeConverter);
    -     method public void setEvaluator(android.animation.TypeEvaluator);
    -     method public void setFloatValues(float...);
    -@@ -3238,12 +3238,12 @@ package android.animation {
    -     method public abstract float getInterpolation(float);
    -   }
    - 
    --  public abstract class TypeConverter {
    -+  public abstract class TypeConverter<T, V> {
    -     ctor public TypeConverter(java.lang.Class<T>, java.lang.Class<V>);
    -     method public abstract V convert(T);
    -   }
    - 
    --  public abstract interface TypeEvaluator {
    -+  public abstract interface TypeEvaluator<T> {
    -     method public abstract T evaluate(float, T, T);
    -   }
    - 
    -@@ -4571,7 +4571,7 @@ package android.app {
    -     method public android.os.Parcelable saveAllState();
    -   }
    - 
    --  public abstract class FragmentHostCallback extends android.app.FragmentContainer {
    -+  public abstract class FragmentHostCallback<E> extends android.app.FragmentContainer {
    -     ctor public FragmentHostCallback(android.content.Context, android.os.Handler, int);
    -     method public void onAttachFragment(android.app.Fragment);
    -     method public void onDump(java.lang.String, java.io.FileDescriptor, java.io.PrintWriter, java.lang.String[]);
    -@@ -4838,12 +4838,12 @@ package android.app {
    -     method public abstract void destroyLoader(int);
    -     method public abstract void dump(java.lang.String, java.io.FileDescriptor, java.io.PrintWriter, java.lang.String[]);
    -     method public static void enableDebugLogging(boolean);
    --    method public abstract android.content.Loader<D> getLoader(int);
    --    method public abstract android.content.Loader<D> initLoader(int, android.os.Bundle, android.app.LoaderManager.LoaderCallbacks<D>);
    --    method public abstract android.content.Loader<D> restartLoader(int, android.os.Bundle, android.app.LoaderManager.LoaderCallbacks<D>);
    -+    method public abstract <D> android.content.Loader<D> getLoader(int);
    -+    method public abstract <D> android.content.Loader<D> initLoader(int, android.os.Bundle, android.app.LoaderManager.LoaderCallbacks<D>);
    -+    method public abstract <D> android.content.Loader<D> restartLoader(int, android.os.Bundle, android.app.LoaderManager.LoaderCallbacks<D>);
    -   }
    - 
    --  public static abstract interface LoaderManager.LoaderCallbacks {
    -+  public static abstract interface LoaderManager.LoaderCallbacks<D> {
    -     method public abstract android.content.Loader<D> onCreateLoader(int, android.os.Bundle);
    -     method public abstract void onLoadFinished(android.content.Loader<D>, D);
    -     method public abstract void onLoaderReset(android.content.Loader<D>);
    -@@ -7629,7 +7629,7 @@ package android.content {
    -     ctor public AsyncQueryHandler.WorkerHandler(android.os.Looper);
    -   }
    - 
    --  public abstract class AsyncTaskLoader extends android.content.Loader {
    -+  public abstract class AsyncTaskLoader<D> extends android.content.Loader {
    -     ctor public AsyncTaskLoader(android.content.Context);
    -     method public void cancelLoadInBackground();
    -     method public boolean isLoadInBackgroundCanceled();
    -@@ -7811,7 +7811,7 @@ package android.content {
    -     method public android.os.ParcelFileDescriptor openFile(android.net.Uri, java.lang.String) throws java.io.FileNotFoundException;
    -     method public android.os.ParcelFileDescriptor openFile(android.net.Uri, java.lang.String, android.os.CancellationSignal) throws java.io.FileNotFoundException;
    -     method protected final android.os.ParcelFileDescriptor openFileHelper(android.net.Uri, java.lang.String) throws java.io.FileNotFoundException;
    --    method public android.os.ParcelFileDescriptor openPipeHelper(android.net.Uri, java.lang.String, android.os.Bundle, T, android.content.ContentProvider.PipeDataWriter<T>) throws java.io.FileNotFoundException;
    -+    method public <T> android.os.ParcelFileDescriptor openPipeHelper(android.net.Uri, java.lang.String, android.os.Bundle, T, android.content.ContentProvider.PipeDataWriter<T>) throws java.io.FileNotFoundException;
    -     method public android.content.res.AssetFileDescriptor openTypedAssetFile(android.net.Uri, java.lang.String, android.os.Bundle) throws java.io.FileNotFoundException;
    -     method public android.content.res.AssetFileDescriptor openTypedAssetFile(android.net.Uri, java.lang.String, android.os.Bundle, android.os.CancellationSignal) throws java.io.FileNotFoundException;
    -     method public abstract android.database.Cursor query(android.net.Uri, java.lang.String[], java.lang.String, java.lang.String[], java.lang.String);
    -@@ -7824,7 +7824,7 @@ package android.content {
    -     method public abstract int update(android.net.Uri, android.content.ContentValues, java.lang.String, java.lang.String[]);
    -   }
    - 
    --  public static abstract interface ContentProvider.PipeDataWriter {
    -+  public static abstract interface ContentProvider.PipeDataWriter<T> {
    -     method public abstract void writeDataToPipe(android.os.ParcelFileDescriptor, android.net.Uri, java.lang.String, android.os.Bundle, T);
    -   }
    - 
    -@@ -8095,7 +8095,7 @@ package android.content {
    -     method public final java.lang.String getString(int);
    -     method public final java.lang.String getString(int, java.lang.Object...);
    -     method public abstract java.lang.Object getSystemService(java.lang.String);
    --    method public final T getSystemService(java.lang.Class<T>);
    -+    method public final <T> T getSystemService(java.lang.Class<T>);
    -     method public abstract java.lang.String getSystemServiceName(java.lang.Class<?>);
    -     method public final java.lang.CharSequence getText(int);
    -     method public abstract android.content.res.Resources.Theme getTheme();
    -@@ -8450,8 +8450,8 @@ package android.content {
    -     method public long getLongExtra(java.lang.String, long);
    -     method public java.lang.String getPackage();
    -     method public android.os.Parcelable[] getParcelableArrayExtra(java.lang.String);
    --    method public java.util.ArrayList<T> getParcelableArrayListExtra(java.lang.String);
    --    method public T getParcelableExtra(java.lang.String);
    -+    method public <T extends android.os.Parcelable> java.util.ArrayList<T> getParcelableArrayListExtra(java.lang.String);
    -+    method public <T extends android.os.Parcelable> T getParcelableExtra(java.lang.String);
    -     method public java.lang.String getScheme();
    -     method public android.content.Intent getSelector();
    -     method public java.io.Serializable getSerializableExtra(java.lang.String);
    -@@ -8926,7 +8926,7 @@ package android.content {
    -     ctor public IntentSender.SendIntentException(java.lang.Exception);
    -   }
    - 
    --  public class Loader {
    -+  public class Loader<D> {
    -     ctor public Loader(android.content.Context);
    -     method public void abandon();
    -     method public boolean cancelLoad();
    -@@ -8963,11 +8963,11 @@ package android.content {
    -     ctor public Loader.ForceLoadContentObserver();
    -   }
    - 
    --  public static abstract interface Loader.OnLoadCanceledListener {
    -+  public static abstract interface Loader.OnLoadCanceledListener<D> {
    -     method public abstract void onLoadCanceled(android.content.Loader<D>);
    -   }
    - 
    --  public static abstract interface Loader.OnLoadCompleteListener {
    -+  public static abstract interface Loader.OnLoadCompleteListener<D> {
    -     method public abstract void onLoadComplete(android.content.Loader<D>, D);
    -   }
    - 
    -@@ -10839,7 +10839,7 @@ package android.database {
    -     method public boolean isNull(int);
    -   }
    - 
    --  public abstract class Observable {
    -+  public abstract class Observable<T> {
    -     ctor public Observable();
    -     method public void registerObserver(T);
    -     method public void unregisterAll();
    -@@ -12729,7 +12729,7 @@ package android.graphics.drawable {
    -   public class AnimatedStateListDrawable extends android.graphics.drawable.StateListDrawable {
    -     ctor public AnimatedStateListDrawable();
    -     method public void addState(int[], android.graphics.drawable.Drawable, int);
    --    method public void addTransition(int, int, T, boolean);
    -+    method public <T extends android.graphics.drawable.Drawable & android.graphics.drawable.Animatable> void addTransition(int, int, T, boolean);
    -   }
    - 
    -   public class AnimatedVectorDrawable extends android.graphics.drawable.Drawable implements android.graphics.drawable.Animatable2 {
    -@@ -13853,7 +13853,7 @@ package android.hardware.camera2 {
    -   }
    - 
    -   public final class CameraCharacteristics extends android.hardware.camera2.CameraMetadata {
    --    method public T get(android.hardware.camera2.CameraCharacteristics.Key<T>);
    -+    method public <T> T get(android.hardware.camera2.CameraCharacteristics.Key<T>);
    -     method public java.util.List<android.hardware.camera2.CaptureRequest.Key<?>> getAvailableCaptureRequestKeys();
    -     method public java.util.List<android.hardware.camera2.CaptureResult.Key<?>> getAvailableCaptureResultKeys();
    -     field public static final android.hardware.camera2.CameraCharacteristics.Key<int[]> COLOR_CORRECTION_AVAILABLE_ABERRATION_MODES;
    -@@ -13938,7 +13938,7 @@ package android.hardware.camera2 {
    -     field public static final android.hardware.camera2.CameraCharacteristics.Key<java.lang.Integer> TONEMAP_MAX_CURVE_POINTS;
    -   }
    - 
    --  public static final class CameraCharacteristics.Key {
    -+  public static final class CameraCharacteristics.Key<T> {
    -     method public final boolean equals(java.lang.Object);
    -     method public java.lang.String getName();
    -     method public final int hashCode();
    -@@ -14003,7 +14003,7 @@ package android.hardware.camera2 {
    -     method public void onTorchModeUnavailable(java.lang.String);
    -   }
    - 
    --  public abstract class CameraMetadata {
    -+  public abstract class CameraMetadata<TKey> {
    -     method public java.util.List<TKey> getKeys();
    -     field public static final int COLOR_CORRECTION_ABERRATION_MODE_FAST = 1; // 0x1
    -     field public static final int COLOR_CORRECTION_ABERRATION_MODE_HIGH_QUALITY = 2; // 0x2
    -@@ -14211,7 +14211,7 @@ package android.hardware.camera2 {
    - 
    -   public final class CaptureRequest extends android.hardware.camera2.CameraMetadata implements android.os.Parcelable {
    -     method public int describeContents();
    --    method public T get(android.hardware.camera2.CaptureRequest.Key<T>);
    -+    method public <T> T get(android.hardware.camera2.CaptureRequest.Key<T>);
    -     method public java.lang.Object getTag();
    -     method public boolean isReprocess();
    -     method public void writeToParcel(android.os.Parcel, int);
    -@@ -14274,20 +14274,20 @@ package android.hardware.camera2 {
    -   public static final class CaptureRequest.Builder {
    -     method public void addTarget(android.view.Surface);
    -     method public android.hardware.camera2.CaptureRequest build();
    --    method public T get(android.hardware.camera2.CaptureRequest.Key<T>);
    -+    method public <T> T get(android.hardware.camera2.CaptureRequest.Key<T>);
    -     method public void removeTarget(android.view.Surface);
    --    method public void set(android.hardware.camera2.CaptureRequest.Key<T>, T);
    -+    method public <T> void set(android.hardware.camera2.CaptureRequest.Key<T>, T);
    -     method public void setTag(java.lang.Object);
    -   }
    - 
    --  public static final class CaptureRequest.Key {
    -+  public static final class CaptureRequest.Key<T> {
    -     method public final boolean equals(java.lang.Object);
    -     method public java.lang.String getName();
    -     method public final int hashCode();
    -   }
    - 
    -   public class CaptureResult extends android.hardware.camera2.CameraMetadata {
    --    method public T get(android.hardware.camera2.CaptureResult.Key<T>);
    -+    method public <T> T get(android.hardware.camera2.CaptureResult.Key<T>);
    -     method public long getFrameNumber();
    -     method public android.hardware.camera2.CaptureRequest getRequest();
    -     method public int getSequenceId();
    -@@ -14368,7 +14368,7 @@ package android.hardware.camera2 {
    -     field public static final android.hardware.camera2.CaptureResult.Key<java.lang.Integer> TONEMAP_PRESET_CURVE;
    -   }
    - 
    --  public static final class CaptureResult.Key {
    -+  public static final class CaptureResult.Key<T> {
    -     method public final boolean equals(java.lang.Object);
    -     method public java.lang.String getName();
    -     method public final int hashCode();
    -@@ -14493,14 +14493,14 @@ package android.hardware.camera2.params {
    -     method public android.util.Size[] getInputSizes(int);
    -     method public final int[] getOutputFormats();
    -     method public long getOutputMinFrameDuration(int, android.util.Size);
    --    method public long getOutputMinFrameDuration(java.lang.Class<T>, android.util.Size);
    --    method public android.util.Size[] getOutputSizes(java.lang.Class<T>);
    -+    method public <T> long getOutputMinFrameDuration(java.lang.Class<T>, android.util.Size);
    -+    method public <T> android.util.Size[] getOutputSizes(java.lang.Class<T>);
    -     method public android.util.Size[] getOutputSizes(int);
    -     method public long getOutputStallDuration(int, android.util.Size);
    --    method public long getOutputStallDuration(java.lang.Class<T>, android.util.Size);
    -+    method public <T> long getOutputStallDuration(java.lang.Class<T>, android.util.Size);
    -     method public final int[] getValidOutputFormatsForInput(int);
    -     method public boolean isOutputSupportedFor(int);
    --    method public static boolean isOutputSupportedFor(java.lang.Class<T>);
    -+    method public static <T> boolean isOutputSupportedFor(java.lang.Class<T>);
    -     method public boolean isOutputSupportedFor(android.view.Surface);
    -   }
    - 
    -@@ -16201,7 +16201,7 @@ package android.icu.math {
    - 
    - package android.icu.text {
    - 
    --  public final class AlphabeticIndex implements java.lang.Iterable {
    -+  public final class AlphabeticIndex<V> implements java.lang.Iterable {
    -     ctor public AlphabeticIndex(android.icu.util.ULocale);
    -     ctor public AlphabeticIndex(java.util.Locale);
    -     ctor public AlphabeticIndex(android.icu.text.RuleBasedCollator);
    -@@ -16227,7 +16227,7 @@ package android.icu.text {
    -     method public android.icu.text.AlphabeticIndex<V> setUnderflowLabel(java.lang.String);
    -   }
    - 
    --  public static class AlphabeticIndex.Bucket implements java.lang.Iterable {
    -+  public static class AlphabeticIndex.Bucket<V> implements java.lang.Iterable {
    -     method public java.lang.String getLabel();
    -     method public android.icu.text.AlphabeticIndex.Bucket.LabelType getLabelType();
    -     method public java.util.Iterator<android.icu.text.AlphabeticIndex.Record<V>> iterator();
    -@@ -16243,14 +16243,14 @@ package android.icu.text {
    -     enum_constant public static final android.icu.text.AlphabeticIndex.Bucket.LabelType UNDERFLOW;
    -   }
    - 
    --  public static final class AlphabeticIndex.ImmutableIndex implements java.lang.Iterable {
    -+  public static final class AlphabeticIndex.ImmutableIndex<V> implements java.lang.Iterable {
    -     method public android.icu.text.AlphabeticIndex.Bucket<V> getBucket(int);
    -     method public int getBucketCount();
    -     method public int getBucketIndex(java.lang.CharSequence);
    -     method public java.util.Iterator<android.icu.text.AlphabeticIndex.Bucket<V>> iterator();
    -   }
    - 
    --  public static class AlphabeticIndex.Record {
    -+  public static class AlphabeticIndex.Record<V> {
    -     method public V getData();
    -     method public java.lang.CharSequence getName();
    -   }
    -@@ -17763,8 +17763,8 @@ package android.icu.text {
    -     method public final android.icu.text.UnicodeSet addAll(java.lang.CharSequence);
    -     method public android.icu.text.UnicodeSet addAll(android.icu.text.UnicodeSet);
    -     method public android.icu.text.UnicodeSet addAll(java.lang.Iterable<?>);
    --    method public android.icu.text.UnicodeSet addAll(T...);
    --    method public T addAllTo(T);
    -+    method public <T extends java.lang.CharSequence> android.icu.text.UnicodeSet addAll(T...);
    -+    method public <T extends java.util.Collection<java.lang.String>> T addAllTo(T);
    -     method public void addMatchSetTo(android.icu.text.UnicodeSet);
    -     method public android.icu.text.UnicodeSet applyIntPropertyValue(int, int);
    -     method public final android.icu.text.UnicodeSet applyPattern(java.lang.String);
    -@@ -17792,15 +17792,15 @@ package android.icu.text {
    -     method public final boolean contains(java.lang.CharSequence);
    -     method public boolean containsAll(android.icu.text.UnicodeSet);
    -     method public boolean containsAll(java.lang.String);
    --    method public boolean containsAll(java.lang.Iterable<T>);
    -+    method public <T extends java.lang.CharSequence> boolean containsAll(java.lang.Iterable<T>);
    -     method public boolean containsNone(int, int);
    -     method public boolean containsNone(android.icu.text.UnicodeSet);
    -     method public boolean containsNone(java.lang.CharSequence);
    --    method public boolean containsNone(java.lang.Iterable<T>);
    -+    method public <T extends java.lang.CharSequence> boolean containsNone(java.lang.Iterable<T>);
    -     method public final boolean containsSome(int, int);
    -     method public final boolean containsSome(android.icu.text.UnicodeSet);
    -     method public final boolean containsSome(java.lang.CharSequence);
    --    method public final boolean containsSome(java.lang.Iterable<T>);
    -+    method public final <T extends java.lang.CharSequence> boolean containsSome(java.lang.Iterable<T>);
    -     method public android.icu.text.UnicodeSet freeze();
    -     method public static android.icu.text.UnicodeSet from(java.lang.CharSequence);
    -     method public static android.icu.text.UnicodeSet fromAll(java.lang.CharSequence);
    -@@ -17818,14 +17818,14 @@ package android.icu.text {
    -     method public final android.icu.text.UnicodeSet remove(java.lang.CharSequence);
    -     method public final android.icu.text.UnicodeSet removeAll(java.lang.CharSequence);
    -     method public android.icu.text.UnicodeSet removeAll(android.icu.text.UnicodeSet);
    --    method public android.icu.text.UnicodeSet removeAll(java.lang.Iterable<T>);
    -+    method public <T extends java.lang.CharSequence> android.icu.text.UnicodeSet removeAll(java.lang.Iterable<T>);
    -     method public final android.icu.text.UnicodeSet removeAllStrings();
    -     method public android.icu.text.UnicodeSet retain(int, int);
    -     method public final android.icu.text.UnicodeSet retain(int);
    -     method public final android.icu.text.UnicodeSet retain(java.lang.CharSequence);
    -     method public final android.icu.text.UnicodeSet retainAll(java.lang.CharSequence);
    -     method public android.icu.text.UnicodeSet retainAll(android.icu.text.UnicodeSet);
    --    method public android.icu.text.UnicodeSet retainAll(java.lang.Iterable<T>);
    -+    method public <T extends java.lang.CharSequence> android.icu.text.UnicodeSet retainAll(java.lang.Iterable<T>);
    -     method public android.icu.text.UnicodeSet set(int, int);
    -     method public android.icu.text.UnicodeSet set(android.icu.text.UnicodeSet);
    -     method public int size();
    -@@ -18235,7 +18235,7 @@ package android.icu.util {
    -     method public long getToDate();
    -   }
    - 
    --  public abstract interface Freezable implements java.lang.Cloneable {
    -+  public abstract interface Freezable<T> implements java.lang.Cloneable {
    -     method public abstract T cloneAsThawed();
    -     method public abstract T freeze();
    -     method public abstract boolean isFrozen();
    -@@ -18517,7 +18517,7 @@ package android.icu.util {
    -     field public static final android.icu.util.TimeUnit YEAR;
    -   }
    - 
    --  public class Output {
    -+  public class Output<T> {
    -     ctor public Output();
    -     ctor public Output(T);
    -     field public T value;
    -@@ -28169,7 +28169,7 @@ package android.opengl {
    - 
    - package android.os {
    - 
    --  public abstract class AsyncTask {
    -+  public abstract class AsyncTask<Params, Progress, Result> {
    -     ctor public AsyncTask();
    -     method public final boolean cancel(boolean);
    -     method protected abstract Result doInBackground(Params...);
    -@@ -28396,16 +28396,16 @@ package android.os {
    -     method public float getFloat(java.lang.String, float);
    -     method public float[] getFloatArray(java.lang.String);
    -     method public java.util.ArrayList<java.lang.Integer> getIntegerArrayList(java.lang.String);
    --    method public T getParcelable(java.lang.String);
    -+    method public <T extends android.os.Parcelable> T getParcelable(java.lang.String);
    -     method public android.os.Parcelable[] getParcelableArray(java.lang.String);
    --    method public java.util.ArrayList<T> getParcelableArrayList(java.lang.String);
    -+    method public <T extends android.os.Parcelable> java.util.ArrayList<T> getParcelableArrayList(java.lang.String);
    -     method public java.io.Serializable getSerializable(java.lang.String);
    -     method public short getShort(java.lang.String);
    -     method public short getShort(java.lang.String, short);
    -     method public short[] getShortArray(java.lang.String);
    -     method public android.util.Size getSize(java.lang.String);
    -     method public android.util.SizeF getSizeF(java.lang.String);
    --    method public android.util.SparseArray<T> getSparseParcelableArray(java.lang.String);
    -+    method public <T extends android.os.Parcelable> android.util.SparseArray<T> getSparseParcelableArray(java.lang.String);
    -     method public java.util.ArrayList<java.lang.String> getStringArrayList(java.lang.String);
    -     method public boolean hasFileDescriptors();
    -     method public void putAll(android.os.Bundle);
    -@@ -28910,8 +28910,8 @@ package android.os {
    -     method public final long[] createLongArray();
    -     method public final java.lang.String[] createStringArray();
    -     method public final java.util.ArrayList<java.lang.String> createStringArrayList();
    --    method public final T[] createTypedArray(android.os.Parcelable.Creator<T>);
    --    method public final java.util.ArrayList<T> createTypedArrayList(android.os.Parcelable.Creator<T>);
    -+    method public final <T> T[] createTypedArray(android.os.Parcelable.Creator<T>);
    -+    method public final <T> java.util.ArrayList<T> createTypedArrayList(android.os.Parcelable.Creator<T>);
    -     method public final int dataAvail();
    -     method public final int dataCapacity();
    -     method public final int dataPosition();
    -@@ -28944,7 +28944,7 @@ package android.os {
    -     method public final long readLong();
    -     method public final void readLongArray(long[]);
    -     method public final void readMap(java.util.Map, java.lang.ClassLoader);
    --    method public final T readParcelable(java.lang.ClassLoader);
    -+    method public final <T extends android.os.Parcelable> T readParcelable(java.lang.ClassLoader);
    -     method public final android.os.Parcelable[] readParcelableArray(java.lang.ClassLoader);
    -     method public final android.os.PersistableBundle readPersistableBundle();
    -     method public final android.os.PersistableBundle readPersistableBundle(java.lang.ClassLoader);
    -@@ -28957,9 +28957,9 @@ package android.os {
    -     method public final void readStringArray(java.lang.String[]);
    -     method public final void readStringList(java.util.List<java.lang.String>);
    -     method public final android.os.IBinder readStrongBinder();
    --    method public final void readTypedArray(T[], android.os.Parcelable.Creator<T>);
    --    method public final void readTypedList(java.util.List<T>, android.os.Parcelable.Creator<T>);
    --    method public final T readTypedObject(android.os.Parcelable.Creator<T>);
    -+    method public final <T> void readTypedArray(T[], android.os.Parcelable.Creator<T>);
    -+    method public final <T> void readTypedList(java.util.List<T>, android.os.Parcelable.Creator<T>);
    -+    method public final <T> T readTypedObject(android.os.Parcelable.Creator<T>);
    -     method public final java.lang.Object readValue(java.lang.ClassLoader);
    -     method public final void recycle();
    -     method public final void setDataCapacity(int);
    -@@ -28990,7 +28990,7 @@ package android.os {
    -     method public final void writeMap(java.util.Map);
    -     method public final void writeNoException();
    -     method public final void writeParcelable(android.os.Parcelable, int);
    --    method public final void writeParcelableArray(T[], int);
    -+    method public final <T extends android.os.Parcelable> void writeParcelableArray(T[], int);
    -     method public final void writePersistableBundle(android.os.PersistableBundle);
    -     method public final void writeSerializable(java.io.Serializable);
    -     method public final void writeSize(android.util.Size);
    -@@ -29002,9 +29002,9 @@ package android.os {
    -     method public final void writeStringList(java.util.List<java.lang.String>);
    -     method public final void writeStrongBinder(android.os.IBinder);
    -     method public final void writeStrongInterface(android.os.IInterface);
    --    method public final void writeTypedArray(T[], int);
    --    method public final void writeTypedList(java.util.List<T>);
    --    method public final void writeTypedObject(T, int);
    -+    method public final <T extends android.os.Parcelable> void writeTypedArray(T[], int);
    -+    method public final <T extends android.os.Parcelable> void writeTypedList(java.util.List<T>);
    -+    method public final <T extends android.os.Parcelable> void writeTypedObject(T, int);
    -     method public final void writeValue(java.lang.Object);
    -     field public static final android.os.Parcelable.Creator<java.lang.String> STRING_CREATOR;
    -   }
    -@@ -29082,11 +29082,11 @@ package android.os {
    -     field public static final int PARCELABLE_WRITE_RETURN_VALUE = 1; // 0x1
    -   }
    - 
    --  public static abstract interface Parcelable.ClassLoaderCreator implements android.os.Parcelable.Creator {
    -+  public static abstract interface Parcelable.ClassLoaderCreator<T> implements android.os.Parcelable.Creator {
    -     method public abstract T createFromParcel(android.os.Parcel, java.lang.ClassLoader);
    -   }
    - 
    --  public static abstract interface Parcelable.Creator {
    -+  public static abstract interface Parcelable.Creator<T> {
    -     method public abstract T createFromParcel(android.os.Parcel);
    -     method public abstract T[] newArray(int);
    -   }
    -@@ -29200,7 +29200,7 @@ package android.os {
    -     method public abstract void onProgress(int);
    -   }
    - 
    --  public class RemoteCallbackList {
    -+  public class RemoteCallbackList<E extends android.os.IInterface> {
    -     ctor public RemoteCallbackList();
    -     method public int beginBroadcast();
    -     method public void finishBroadcast();
    -@@ -32482,7 +32482,7 @@ package android.provider {
    -     field public static final java.lang.String RADIO_CELL = "cell";
    -     field public static final java.lang.String RADIO_NFC = "nfc";
    -     field public static final java.lang.String RADIO_WIFI = "wifi";
    --    field public static final java.lang.String SHOW_PROCESSES = "show_processes";
    -+    field public static final deprecated java.lang.String SHOW_PROCESSES = "show_processes";
    -     field public static final java.lang.String STAY_ON_WHILE_PLUGGED_IN = "stay_on_while_plugged_in";
    -     field public static final java.lang.String TRANSITION_ANIMATION_SCALE = "transition_animation_scale";
    -     field public static final java.lang.String USB_MASS_STORAGE_ENABLED = "usb_mass_storage_enabled";
    -@@ -34520,7 +34520,7 @@ package android.service.carrier {
    -     field public static final java.lang.String SERVICE_INTERFACE = "android.service.carrier.CarrierMessagingService";
    -   }
    - 
    --  public static abstract interface CarrierMessagingService.ResultCallback {
    -+  public static abstract interface CarrierMessagingService.ResultCallback<T> {
    -     method public abstract void onReceiveResult(T) throws android.os.RemoteException;
    -   }
    - 
    -@@ -34671,7 +34671,7 @@ package android.service.media {
    -     field public static final java.lang.String EXTRA_SUGGESTED = "android.service.media.extra.SUGGESTED";
    -   }
    - 
    --  public class MediaBrowserService.Result {
    -+  public class MediaBrowserService.Result<T> {
    -     method public void detach();
    -     method public void sendResult(T);
    -   }
    -@@ -37584,14 +37584,14 @@ package android.telephony.gsm {
    - 
    - package android.test {
    - 
    --  public abstract deprecated class ActivityInstrumentationTestCase extends android.test.ActivityTestCase {
    -+  public abstract deprecated class ActivityInstrumentationTestCase<T extends android.app.Activity> extends android.test.ActivityTestCase {
    -     ctor public ActivityInstrumentationTestCase(java.lang.String, java.lang.Class<T>);
    -     ctor public ActivityInstrumentationTestCase(java.lang.String, java.lang.Class<T>, boolean);
    -     method public T getActivity();
    -     method public void testActivityTestCaseSetUpProperly() throws java.lang.Exception;
    -   }
    - 
    --  public abstract deprecated class ActivityInstrumentationTestCase2 extends android.test.ActivityTestCase {
    -+  public abstract deprecated class ActivityInstrumentationTestCase2<T extends android.app.Activity> extends android.test.ActivityTestCase {
    -     ctor public deprecated ActivityInstrumentationTestCase2(java.lang.String, java.lang.Class<T>);
    -     ctor public ActivityInstrumentationTestCase2(java.lang.Class<T>);
    -     method public T getActivity();
    -@@ -37606,7 +37606,7 @@ package android.test {
    -     method protected void setActivity(android.app.Activity);
    -   }
    - 
    --  public abstract deprecated class ActivityUnitTestCase extends android.test.ActivityTestCase {
    -+  public abstract deprecated class ActivityUnitTestCase<T extends android.app.Activity> extends android.test.ActivityTestCase {
    -     ctor public ActivityUnitTestCase(java.lang.Class<T>);
    -     method public T getActivity();
    -     method public int getFinishedActivityRequest();
    -@@ -37652,7 +37652,7 @@ package android.test {
    -     method public void testStarted(java.lang.String);
    -   }
    - 
    --  public abstract deprecated class ApplicationTestCase extends android.test.AndroidTestCase {
    -+  public abstract deprecated class ApplicationTestCase<T extends android.app.Application> extends android.test.AndroidTestCase {
    -     ctor public ApplicationTestCase(java.lang.Class<T>);
    -     method protected final void createApplication();
    -     method public T getApplication();
    -@@ -37678,8 +37678,8 @@ package android.test {
    -     method public android.app.Instrumentation getInstrumentation();
    -     method public deprecated void injectInsrumentation(android.app.Instrumentation);
    -     method public void injectInstrumentation(android.app.Instrumentation);
    --    method public final T launchActivity(java.lang.String, java.lang.Class<T>, android.os.Bundle);
    --    method public final T launchActivityWithIntent(java.lang.String, java.lang.Class<T>, android.content.Intent);
    -+    method public final <T extends android.app.Activity> T launchActivity(java.lang.String, java.lang.Class<T>, android.os.Bundle);
    -+    method public final <T extends android.app.Activity> T launchActivityWithIntent(java.lang.String, java.lang.Class<T>, android.content.Intent);
    -     method public void runTestOnUiThread(java.lang.Runnable) throws java.lang.Throwable;
    -     method public void sendKeys(java.lang.String);
    -     method public void sendKeys(int...);
    -@@ -37719,7 +37719,7 @@ package android.test {
    - 
    -   public class LoaderTestCase extends android.test.AndroidTestCase {
    -     ctor public LoaderTestCase();
    --    method public T getLoaderResultSynchronously(android.content.Loader<T>);
    -+    method public <T> T getLoaderResultSynchronously(android.content.Loader<T>);
    -   }
    - 
    -   public final deprecated class MoreAsserts {
    -@@ -37774,20 +37774,20 @@ package android.test {
    -     method public abstract void startTiming(boolean);
    -   }
    - 
    --  public abstract deprecated class ProviderTestCase extends android.test.InstrumentationTestCase {
    -+  public abstract deprecated class ProviderTestCase<T extends android.content.ContentProvider> extends android.test.InstrumentationTestCase {
    -     ctor public ProviderTestCase(java.lang.Class<T>, java.lang.String);
    -     method public android.test.mock.MockContentResolver getMockContentResolver();
    -     method public android.test.IsolatedContext getMockContext();
    -     method public T getProvider();
    --    method public static android.content.ContentResolver newResolverWithContentProviderFromSql(android.content.Context, java.lang.Class<T>, java.lang.String, java.lang.String, int, java.lang.String) throws java.lang.IllegalAccessException, java.lang.InstantiationException;
    -+    method public static <T extends android.content.ContentProvider> android.content.ContentResolver newResolverWithContentProviderFromSql(android.content.Context, java.lang.Class<T>, java.lang.String, java.lang.String, int, java.lang.String) throws java.lang.IllegalAccessException, java.lang.InstantiationException;
    -   }
    - 
    --  public abstract class ProviderTestCase2 extends android.test.AndroidTestCase {
    -+  public abstract class ProviderTestCase2<T extends android.content.ContentProvider> extends android.test.AndroidTestCase {
    -     ctor public ProviderTestCase2(java.lang.Class<T>, java.lang.String);
    -     method public android.test.mock.MockContentResolver getMockContentResolver();
    -     method public android.test.IsolatedContext getMockContext();
    -     method public T getProvider();
    --    method public static android.content.ContentResolver newResolverWithContentProviderFromSql(android.content.Context, java.lang.String, java.lang.Class<T>, java.lang.String, java.lang.String, int, java.lang.String) throws java.lang.IllegalAccessException, java.lang.InstantiationException;
    -+    method public static <T extends android.content.ContentProvider> android.content.ContentResolver newResolverWithContentProviderFromSql(android.content.Context, java.lang.String, java.lang.Class<T>, java.lang.String, java.lang.String, int, java.lang.String) throws java.lang.IllegalAccessException, java.lang.InstantiationException;
    -   }
    - 
    -   public deprecated class RenamingDelegatingContext extends android.content.ContextWrapper {
    -@@ -37795,11 +37795,11 @@ package android.test {
    -     ctor public RenamingDelegatingContext(android.content.Context, android.content.Context, java.lang.String);
    -     method public java.lang.String getDatabasePrefix();
    -     method public void makeExistingFilesAndDbsAccessible();
    --    method public static T providerWithRenamedContext(java.lang.Class<T>, android.content.Context, java.lang.String) throws java.lang.IllegalAccessException, java.lang.InstantiationException;
    --    method public static T providerWithRenamedContext(java.lang.Class<T>, android.content.Context, java.lang.String, boolean) throws java.lang.IllegalAccessException, java.lang.InstantiationException;
    -+    method public static <T extends android.content.ContentProvider> T providerWithRenamedContext(java.lang.Class<T>, android.content.Context, java.lang.String) throws java.lang.IllegalAccessException, java.lang.InstantiationException;
    -+    method public static <T extends android.content.ContentProvider> T providerWithRenamedContext(java.lang.Class<T>, android.content.Context, java.lang.String, boolean) throws java.lang.IllegalAccessException, java.lang.InstantiationException;
    -   }
    - 
    --  public abstract deprecated class ServiceTestCase extends android.test.AndroidTestCase {
    -+  public abstract deprecated class ServiceTestCase<T extends android.app.Service> extends android.test.AndroidTestCase {
    -     ctor public ServiceTestCase(java.lang.Class<T>);
    -     method protected android.os.IBinder bindService(android.content.Intent);
    -     method public android.app.Application getApplication();
    -@@ -37812,7 +37812,7 @@ package android.test {
    -     method public void testServiceTestCaseSetUpProperly() throws java.lang.Exception;
    -   }
    - 
    --  public abstract deprecated class SingleLaunchActivityTestCase extends android.test.InstrumentationTestCase {
    -+  public abstract deprecated class SingleLaunchActivityTestCase<T extends android.app.Activity> extends android.test.InstrumentationTestCase {
    -     ctor public SingleLaunchActivityTestCase(java.lang.String, java.lang.Class<T>);
    -     method public T getActivity();
    -     method public void testActivityTestCaseSetUpProperly() throws java.lang.Exception;
    -@@ -38167,7 +38167,7 @@ package android.test.suitebuilder {
    -     ctor public TestMethod(java.lang.String, java.lang.Class<? extends junit.framework.TestCase>);
    -     ctor public TestMethod(junit.framework.TestCase);
    -     method public junit.framework.TestCase createTest() throws java.lang.IllegalAccessException, java.lang.InstantiationException, java.lang.reflect.InvocationTargetException;
    --    method public T getAnnotation(java.lang.Class<T>);
    -+    method public <T extends java.lang.annotation.Annotation> T getAnnotation(java.lang.Class<T>);
    -     method public java.lang.Class<? extends junit.framework.TestCase> getEnclosingClass();
    -     method public java.lang.String getEnclosingClassname();
    -     method public java.lang.String getName();
    -@@ -38610,7 +38610,7 @@ package android.text {
    -     method public int getSpanEnd(java.lang.Object);
    -     method public int getSpanFlags(java.lang.Object);
    -     method public int getSpanStart(java.lang.Object);
    --    method public T[] getSpans(int, int, java.lang.Class<T>);
    -+    method public <T> T[] getSpans(int, int, java.lang.Class<T>);
    -     method public deprecated int getTextRunCursor(int, int, int, int, int, android.graphics.Paint);
    -     method public int getTextWatcherDepth();
    -     method public android.text.SpannableStringBuilder insert(int, java.lang.CharSequence, int, int);
    -@@ -38632,7 +38632,7 @@ package android.text {
    -     method public int getSpanEnd(java.lang.Object);
    -     method public int getSpanFlags(java.lang.Object);
    -     method public int getSpanStart(java.lang.Object);
    --    method public T[] getSpans(int, int, java.lang.Class<T>);
    -+    method public <T> T[] getSpans(int, int, java.lang.Class<T>);
    -     method public final int length();
    -     method public int nextSpanTransition(int, int, java.lang.Class);
    -     method public final java.lang.String toString();
    -@@ -38642,7 +38642,7 @@ package android.text {
    -     method public abstract int getSpanEnd(java.lang.Object);
    -     method public abstract int getSpanFlags(java.lang.Object);
    -     method public abstract int getSpanStart(java.lang.Object);
    --    method public abstract T[] getSpans(int, int, java.lang.Class<T>);
    -+    method public abstract <T> T[] getSpans(int, int, java.lang.Class<T>);
    -     method public abstract int nextSpanTransition(int, int, java.lang.Class);
    -     field public static final int SPAN_COMPOSING = 256; // 0x100
    -     field public static final int SPAN_EXCLUSIVE_EXCLUSIVE = 33; // 0x21
    -@@ -39619,7 +39619,7 @@ package android.text.style {
    -     field public static final int WEEKDAY_WEDNESDAY = 4; // 0x4
    -   }
    - 
    --  public static class TtsSpan.Builder {
    -+  public static class TtsSpan.Builder<C extends android.text.style.TtsSpan.Builder<?>> {
    -     ctor public TtsSpan.Builder(java.lang.String);
    -     method public android.text.style.TtsSpan build();
    -     method public C setIntArgument(java.lang.String, int);
    -@@ -39715,7 +39715,7 @@ package android.text.style {
    -     method public android.text.style.TtsSpan.OrdinalBuilder setNumber(java.lang.String);
    -   }
    - 
    --  public static class TtsSpan.SemioticClassBuilder extends android.text.style.TtsSpan.Builder {
    -+  public static class TtsSpan.SemioticClassBuilder<C extends android.text.style.TtsSpan.SemioticClassBuilder<?>> extends android.text.style.TtsSpan.Builder {
    -     ctor public TtsSpan.SemioticClassBuilder(java.lang.String);
    -     method public C setAnimacy(java.lang.String);
    -     method public C setCase(java.lang.String);
    -@@ -40122,7 +40122,7 @@ package android.util {
    -     ctor public AndroidRuntimeException(java.lang.Exception);
    -   }
    - 
    --  public final class ArrayMap implements java.util.Map {
    -+  public final class ArrayMap<K, V> implements java.util.Map {
    -     ctor public ArrayMap();
    -     ctor public ArrayMap(int);
    -     ctor public ArrayMap(android.util.ArrayMap<K, V>);
    -@@ -40150,7 +40150,7 @@ package android.util {
    -     method public java.util.Collection<V> values();
    -   }
    - 
    --  public final class ArraySet implements java.util.Collection java.util.Set {
    -+  public final class ArraySet<E> implements java.util.Collection java.util.Set {
    -     ctor public ArraySet();
    -     ctor public ArraySet(int);
    -     ctor public ArraySet(android.util.ArraySet<E>);
    -@@ -40171,7 +40171,7 @@ package android.util {
    -     method public boolean retainAll(java.util.Collection<?>);
    -     method public int size();
    -     method public java.lang.Object[] toArray();
    --    method public T[] toArray(T[]);
    -+    method public <T> T[] toArray(T[]);
    -     method public E valueAt(int);
    -   }
    - 
    -@@ -40316,13 +40316,13 @@ package android.util {
    -   public deprecated class FloatMath {
    -   }
    - 
    --  public abstract class FloatProperty extends android.util.Property {
    -+  public abstract class FloatProperty<T> extends android.util.Property {
    -     ctor public FloatProperty(java.lang.String);
    -     method public final void set(T, java.lang.Float);
    -     method public abstract void setValue(T, float);
    -   }
    - 
    --  public abstract class IntProperty extends android.util.Property {
    -+  public abstract class IntProperty<T> extends android.util.Property {
    -     ctor public IntProperty(java.lang.String);
    -     method public final void set(T, java.lang.Integer);
    -     method public abstract void setValue(T, int);
    -@@ -40422,7 +40422,7 @@ package android.util {
    -     method public void println(java.lang.String);
    -   }
    - 
    --  public class LongSparseArray implements java.lang.Cloneable {
    -+  public class LongSparseArray<E> implements java.lang.Cloneable {
    -     ctor public LongSparseArray();
    -     ctor public LongSparseArray(int);
    -     method public void append(long, E);
    -@@ -40442,7 +40442,7 @@ package android.util {
    -     method public E valueAt(int);
    -   }
    - 
    --  public class LruCache {
    -+  public class LruCache<K, V> {
    -     ctor public LruCache(int);
    -     method protected V create(K);
    -     method public final synchronized int createCount();
    -@@ -40530,9 +40530,9 @@ package android.util {
    -     ctor public NoSuchPropertyException(java.lang.String);
    -   }
    - 
    --  public class Pair {
    -+  public class Pair<F, S> {
    -     ctor public Pair(F, S);
    --    method public static android.util.Pair<A, B> create(A, B);
    -+    method public static <A, B> android.util.Pair<A, B> create(A, B);
    -     field public final F first;
    -     field public final S second;
    -   }
    -@@ -40565,22 +40565,22 @@ package android.util {
    -     method public abstract void println(java.lang.String);
    -   }
    - 
    --  public abstract class Property {
    -+  public abstract class Property<T, V> {
    -     ctor public Property(java.lang.Class<V>, java.lang.String);
    -     method public abstract V get(T);
    -     method public java.lang.String getName();
    -     method public java.lang.Class<V> getType();
    -     method public boolean isReadOnly();
    --    method public static android.util.Property<T, V> of(java.lang.Class<T>, java.lang.Class<V>, java.lang.String);
    -+    method public static <T, V> android.util.Property<T, V> of(java.lang.Class<T>, java.lang.Class<V>, java.lang.String);
    -     method public void set(T, V);
    -   }
    - 
    --  public final class Range {
    -+  public final class Range<T extends java.lang.Comparable<? super T>> {
    -     ctor public Range(T, T);
    -     method public T clamp(T);
    -     method public boolean contains(T);
    -     method public boolean contains(android.util.Range<T>);
    --    method public static android.util.Range<T> create(T, T);
    -+    method public static <T extends java.lang.Comparable<? super T>> android.util.Range<T> create(T, T);
    -     method public android.util.Range<T> extend(android.util.Range<T>);
    -     method public android.util.Range<T> extend(T, T);
    -     method public android.util.Range<T> extend(T);
    -@@ -40624,7 +40624,7 @@ package android.util {
    -     method public static android.util.SizeF parseSizeF(java.lang.String) throws java.lang.NumberFormatException;
    -   }
    - 
    --  public class SparseArray implements java.lang.Cloneable {
    -+  public class SparseArray<E> implements java.lang.Cloneable {
    -     ctor public SparseArray();
    -     ctor public SparseArray(int);
    -     method public void append(int, E);
    -@@ -45353,7 +45353,7 @@ package android.webkit {
    -     method public static java.lang.String stripAnchor(java.lang.String);
    -   }
    - 
    --  public abstract interface ValueCallback {
    -+  public abstract interface ValueCallback<T> {
    -     method public abstract void onReceiveValue(T);
    -   }
    - 
    -@@ -46087,7 +46087,7 @@ package android.widget {
    -     field public static final int NO_SELECTION = -2147483648; // 0x80000000
    -   }
    - 
    --  public abstract class AdapterView extends android.view.ViewGroup {
    -+  public abstract class AdapterView<T extends android.widget.Adapter> extends android.view.ViewGroup {
    -     ctor public AdapterView(android.content.Context);
    -     ctor public AdapterView(android.content.Context, android.util.AttributeSet);
    -     ctor public AdapterView(android.content.Context, android.util.AttributeSet, int);
    -@@ -46210,7 +46210,7 @@ package android.widget {
    -     ctor public AnalogClock(android.content.Context, android.util.AttributeSet, int, int);
    -   }
    - 
    --  public class ArrayAdapter extends android.widget.BaseAdapter implements android.widget.Filterable android.widget.ThemedSpinnerAdapter {
    -+  public class ArrayAdapter<T> extends android.widget.BaseAdapter implements android.widget.Filterable android.widget.ThemedSpinnerAdapter {
    -     ctor public ArrayAdapter(android.content.Context, int);
    -     ctor public ArrayAdapter(android.content.Context, int, int);
    -     ctor public ArrayAdapter(android.content.Context, int, T[]);
    -@@ -46271,7 +46271,7 @@ package android.widget {
    -     method protected void performFiltering(java.lang.CharSequence, int);
    -     method public void performValidation();
    -     method protected void replaceText(java.lang.CharSequence);
    --    method public void setAdapter(T);
    -+    method public <T extends android.widget.ListAdapter & android.widget.Filterable> void setAdapter(T);
    -     method public void setCompletionHint(java.lang.CharSequence);
    -     method public void setDropDownAnchor(int);
    -     method public void setDropDownBackgroundDrawable(android.graphics.drawable.Drawable);
    -@@ -48556,7 +48556,7 @@ package android.widget {
    - 
    - package com.android.internal.util {
    - 
    --  public abstract interface Predicate {
    -+  public abstract interface Predicate<T> {
    -     method public abstract boolean apply(T);
    -   }
    - 
    -@@ -50603,13 +50603,13 @@ package java.lang {
    -     enum_constant public static final java.lang.Character.UnicodeScript YI;
    -   }
    - 
    --  public final class Class implements java.lang.reflect.AnnotatedElement java.lang.reflect.GenericDeclaration java.io.Serializable java.lang.reflect.Type {
    --    method public java.lang.Class<? extends U> asSubclass(java.lang.Class<U>);
    -+  public final class Class<T> implements java.lang.reflect.AnnotatedElement java.lang.reflect.GenericDeclaration java.io.Serializable java.lang.reflect.Type {
    -+    method public <U> java.lang.Class<? extends U> asSubclass(java.lang.Class<U>);
    -     method public T cast(java.lang.Object);
    -     method public boolean desiredAssertionStatus();
    -     method public static java.lang.Class<?> forName(java.lang.String) throws java.lang.ClassNotFoundException;
    -     method public static java.lang.Class<?> forName(java.lang.String, boolean, java.lang.ClassLoader) throws java.lang.ClassNotFoundException;
    --    method public A getAnnotation(java.lang.Class<A>);
    -+    method public <A extends java.lang.annotation.Annotation> A getAnnotation(java.lang.Class<A>);
    -     method public java.lang.annotation.Annotation[] getAnnotations();
    -     method public java.lang.String getCanonicalName();
    -     method public java.lang.ClassLoader getClassLoader();
    -@@ -50726,7 +50726,7 @@ package java.lang {
    -   public abstract interface Cloneable {
    -   }
    - 
    --  public abstract interface Comparable {
    -+  public abstract interface Comparable<T> {
    -     method public abstract int compareTo(T);
    -   }
    - 
    -@@ -50780,7 +50780,7 @@ package java.lang {
    -     field public static final java.lang.Class<java.lang.Double> TYPE;
    -   }
    - 
    --  public abstract class Enum implements java.lang.Comparable java.io.Serializable {
    -+  public abstract class Enum<E extends java.lang.Enum<E>> implements java.lang.Comparable java.io.Serializable {
    -     ctor protected Enum(java.lang.String, int);
    -     method protected final java.lang.Object clone() throws java.lang.CloneNotSupportedException;
    -     method public final int compareTo(E);
    -@@ -50790,7 +50790,7 @@ package java.lang {
    -     method public final int hashCode();
    -     method public final java.lang.String name();
    -     method public final int ordinal();
    --    method public static T valueOf(java.lang.Class<T>, java.lang.String);
    -+    method public static <T extends java.lang.Enum<T>> T valueOf(java.lang.Class<T>, java.lang.String);
    -   }
    - 
    -   public class EnumConstantNotPresentException extends java.lang.RuntimeException {
    -@@ -50909,7 +50909,7 @@ package java.lang {
    -     ctor public IndexOutOfBoundsException(java.lang.String);
    -   }
    - 
    --  public class InheritableThreadLocal extends java.lang.ThreadLocal {
    -+  public class InheritableThreadLocal<T> extends java.lang.ThreadLocal {
    -     ctor public InheritableThreadLocal();
    -     method protected T childValue(T);
    -   }
    -@@ -50980,7 +50980,7 @@ package java.lang {
    -     ctor public InterruptedException(java.lang.String);
    -   }
    - 
    --  public abstract interface Iterable {
    -+  public abstract interface Iterable<T> {
    -     method public default void forEach(java.util.function.Consumer<? super T>);
    -     method public abstract java.util.Iterator<T> iterator();
    -     method public default java.util.Spliterator<T> spliterator();
    -@@ -51188,12 +51188,12 @@ package java.lang {
    -   }
    - 
    -   public class Package implements java.lang.reflect.AnnotatedElement {
    --    method public A getAnnotation(java.lang.Class<A>);
    -+    method public <A extends java.lang.annotation.Annotation> A getAnnotation(java.lang.Class<A>);
    -     method public java.lang.annotation.Annotation[] getAnnotations();
    --    method public A[] getAnnotationsByType(java.lang.Class<A>);
    --    method public A getDeclaredAnnotation(java.lang.Class<A>);
    -+    method public <A extends java.lang.annotation.Annotation> A[] getAnnotationsByType(java.lang.Class<A>);
    -+    method public <A extends java.lang.annotation.Annotation> A getDeclaredAnnotation(java.lang.Class<A>);
    -     method public java.lang.annotation.Annotation[] getDeclaredAnnotations();
    --    method public A[] getDeclaredAnnotationsByType(java.lang.Class<A>);
    -+    method public <A extends java.lang.annotation.Annotation> A[] getDeclaredAnnotationsByType(java.lang.Class<A>);
    -     method public java.lang.String getImplementationTitle();
    -     method public java.lang.String getImplementationVendor();
    -     method public java.lang.String getImplementationVersion();
    -@@ -51753,7 +51753,7 @@ package java.lang {
    -     method public void uncaughtException(java.lang.Thread, java.lang.Throwable);
    -   }
    - 
    --  public class ThreadLocal {
    -+  public class ThreadLocal<T> {
    -     ctor public ThreadLocal();
    -     method public T get();
    -     method protected T initialValue();
    -@@ -51893,30 +51893,30 @@ package java.lang.annotation {
    - 
    - package java.lang.ref {
    - 
    --  public class PhantomReference extends java.lang.ref.Reference {
    -+  public class PhantomReference<T> extends java.lang.ref.Reference {
    -     ctor public PhantomReference(T, java.lang.ref.ReferenceQueue<? super T>);
    -   }
    - 
    --  public abstract class Reference {
    -+  public abstract class Reference<T> {
    -     method public void clear();
    -     method public boolean enqueue();
    -     method public T get();
    -     method public boolean isEnqueued();
    -   }
    - 
    --  public class ReferenceQueue {
    -+  public class ReferenceQueue<T> {
    -     ctor public ReferenceQueue();
    -     method public java.lang.ref.Reference<? extends T> poll();
    -     method public java.lang.ref.Reference<? extends T> remove(long) throws java.lang.IllegalArgumentException, java.lang.InterruptedException;
    -     method public java.lang.ref.Reference<? extends T> remove() throws java.lang.InterruptedException;
    -   }
    - 
    --  public class SoftReference extends java.lang.ref.Reference {
    -+  public class SoftReference<T> extends java.lang.ref.Reference {
    -     ctor public SoftReference(T);
    -     ctor public SoftReference(T, java.lang.ref.ReferenceQueue<? super T>);
    -   }
    - 
    --  public class WeakReference extends java.lang.ref.Reference {
    -+  public class WeakReference<T> extends java.lang.ref.Reference {
    -     ctor public WeakReference(T);
    -     ctor public WeakReference(T, java.lang.ref.ReferenceQueue<? super T>);
    -   }
    -@@ -51927,7 +51927,7 @@ package java.lang.reflect {
    - 
    -   public class AccessibleObject implements java.lang.reflect.AnnotatedElement {
    -     ctor protected AccessibleObject();
    --    method public T getAnnotation(java.lang.Class<T>);
    -+    method public <T extends java.lang.annotation.Annotation> T getAnnotation(java.lang.Class<T>);
    -     method public java.lang.annotation.Annotation[] getAnnotations();
    -     method public java.lang.annotation.Annotation[] getDeclaredAnnotations();
    -     method public boolean isAccessible();
    -@@ -51936,12 +51936,12 @@ package java.lang.reflect {
    -   }
    - 
    -   public abstract interface AnnotatedElement {
    --    method public abstract T getAnnotation(java.lang.Class<T>);
    -+    method public abstract <T extends java.lang.annotation.Annotation> T getAnnotation(java.lang.Class<T>);
    -     method public abstract java.lang.annotation.Annotation[] getAnnotations();
    --    method public default T[] getAnnotationsByType(java.lang.Class<T>);
    --    method public default java.lang.annotation.Annotation getDeclaredAnnotation(java.lang.Class<T>);
    -+    method public default <T extends java.lang.annotation.Annotation> T[] getAnnotationsByType(java.lang.Class<T>);
    -+    method public default <T extends java.lang.annotation.Annotation> java.lang.annotation.Annotation getDeclaredAnnotation(java.lang.Class<T>);
    -     method public abstract java.lang.annotation.Annotation[] getDeclaredAnnotations();
    --    method public default T[] getDeclaredAnnotationsByType(java.lang.Class<T>);
    -+    method public default <T extends java.lang.annotation.Annotation> T[] getDeclaredAnnotationsByType(java.lang.Class<T>);
    -     method public default boolean isAnnotationPresent(java.lang.Class<? extends java.lang.annotation.Annotation>);
    -   }
    - 
    -@@ -51969,8 +51969,8 @@ package java.lang.reflect {
    -     method public static void setShort(java.lang.Object, int, short) throws java.lang.ArrayIndexOutOfBoundsException, java.lang.IllegalArgumentException;
    -   }
    - 
    --  public final class Constructor extends java.lang.reflect.AccessibleObject implements java.lang.reflect.GenericDeclaration java.lang.reflect.Member {
    --    method public A getAnnotation(java.lang.Class<A>);
    -+  public final class Constructor<T> extends java.lang.reflect.AccessibleObject implements java.lang.reflect.GenericDeclaration java.lang.reflect.Member {
    -+    method public <A extends java.lang.annotation.Annotation> A getAnnotation(java.lang.Class<A>);
    -     method public java.lang.Class<T> getDeclaringClass();
    -     method public java.lang.Class<?>[] getExceptionTypes();
    -     method public java.lang.reflect.Type[] getGenericExceptionTypes();
    -@@ -51989,7 +51989,7 @@ package java.lang.reflect {
    - 
    -   public final class Field extends java.lang.reflect.AccessibleObject implements java.lang.reflect.Member {
    -     method public java.lang.Object get(java.lang.Object) throws java.lang.IllegalAccessException, java.lang.IllegalArgumentException;
    --    method public A getAnnotation(java.lang.Class<A>);
    -+    method public <A extends java.lang.annotation.Annotation> A getAnnotation(java.lang.Class<A>);
    -     method public boolean getBoolean(java.lang.Object) throws java.lang.IllegalAccessException, java.lang.IllegalArgumentException;
    -     method public byte getByte(java.lang.Object) throws java.lang.IllegalAccessException, java.lang.IllegalArgumentException;
    -     method public char getChar(java.lang.Object) throws java.lang.IllegalAccessException, java.lang.IllegalArgumentException;
    -@@ -52055,7 +52055,7 @@ package java.lang.reflect {
    -   }
    - 
    -   public final class Method extends java.lang.reflect.AccessibleObject implements java.lang.reflect.GenericDeclaration java.lang.reflect.Member {
    --    method public A getAnnotation(java.lang.Class<A>);
    -+    method public <A extends java.lang.annotation.Annotation> A getAnnotation(java.lang.Class<A>);
    -     method public java.lang.Class<?> getDeclaringClass();
    -     method public java.lang.Object getDefaultValue();
    -     method public java.lang.Class<?>[] getExceptionTypes();
    -@@ -52133,7 +52133,7 @@ package java.lang.reflect {
    -   public abstract interface Type {
    -   }
    - 
    --  public abstract interface TypeVariable implements java.lang.reflect.Type {
    -+  public abstract interface TypeVariable<D extends java.lang.reflect.GenericDeclaration> implements java.lang.reflect.Type {
    -     method public abstract java.lang.reflect.Type[] getBounds();
    -     method public abstract D getGenericDeclaration();
    -     method public abstract java.lang.String getName();
    -@@ -52922,7 +52922,7 @@ package java.net {
    -     method public abstract java.net.SocketImpl createSocketImpl();
    -   }
    - 
    --  public abstract interface SocketOption {
    -+  public abstract interface SocketOption<T> {
    -     method public abstract java.lang.String name();
    -     method public abstract java.lang.Class<T> type();
    -   }
    -@@ -53506,7 +53506,7 @@ package java.nio.channels {
    -     method public final long read(java.nio.ByteBuffer[]) throws java.io.IOException;
    -     method public abstract java.net.SocketAddress receive(java.nio.ByteBuffer) throws java.io.IOException;
    -     method public abstract int send(java.nio.ByteBuffer, java.net.SocketAddress) throws java.io.IOException;
    --    method public abstract java.nio.channels.DatagramChannel setOption(java.net.SocketOption<T>, T) throws java.io.IOException;
    -+    method public abstract <T> java.nio.channels.DatagramChannel setOption(java.net.SocketOption<T>, T) throws java.io.IOException;
    -     method public abstract java.net.DatagramSocket socket();
    -     method public final int validOps();
    -     method public abstract int write(java.nio.ByteBuffer) throws java.io.IOException;
    -@@ -53582,8 +53582,8 @@ package java.nio.channels {
    -   public abstract interface NetworkChannel implements java.nio.channels.Channel {
    -     method public abstract java.nio.channels.NetworkChannel bind(java.net.SocketAddress) throws java.io.IOException;
    -     method public abstract java.net.SocketAddress getLocalAddress() throws java.io.IOException;
    --    method public abstract T getOption(java.net.SocketOption<T>) throws java.io.IOException;
    --    method public abstract java.nio.channels.NetworkChannel setOption(java.net.SocketOption<T>, T) throws java.io.IOException;
    -+    method public abstract <T> T getOption(java.net.SocketOption<T>) throws java.io.IOException;
    -+    method public abstract <T> java.nio.channels.NetworkChannel setOption(java.net.SocketOption<T>, T) throws java.io.IOException;
    -     method public abstract java.util.Set<java.net.SocketOption<?>> supportedOptions();
    -   }
    - 
    -@@ -53700,7 +53700,7 @@ package java.nio.channels {
    -     method public final java.nio.channels.ServerSocketChannel bind(java.net.SocketAddress) throws java.io.IOException;
    -     method public abstract java.nio.channels.ServerSocketChannel bind(java.net.SocketAddress, int) throws java.io.IOException;
    -     method public static java.nio.channels.ServerSocketChannel open() throws java.io.IOException;
    --    method public abstract java.nio.channels.ServerSocketChannel setOption(java.net.SocketOption<T>, T) throws java.io.IOException;
    -+    method public abstract <T> java.nio.channels.ServerSocketChannel setOption(java.net.SocketOption<T>, T) throws java.io.IOException;
    -     method public abstract java.net.ServerSocket socket();
    -     method public final int validOps();
    -   }
    -@@ -53718,7 +53718,7 @@ package java.nio.channels {
    -     method public abstract int read(java.nio.ByteBuffer) throws java.io.IOException;
    -     method public abstract long read(java.nio.ByteBuffer[], int, int) throws java.io.IOException;
    -     method public final long read(java.nio.ByteBuffer[]) throws java.io.IOException;
    --    method public abstract java.nio.channels.SocketChannel setOption(java.net.SocketOption<T>, T) throws java.io.IOException;
    -+    method public abstract <T> java.nio.channels.SocketChannel setOption(java.net.SocketOption<T>, T) throws java.io.IOException;
    -     method public abstract java.nio.channels.SocketChannel shutdownInput() throws java.io.IOException;
    -     method public abstract java.nio.channels.SocketChannel shutdownOutput() throws java.io.IOException;
    -     method public abstract java.net.Socket socket();
    -@@ -53965,12 +53965,12 @@ package java.security {
    - 
    -   public final class AccessController {
    -     method public static void checkPermission(java.security.Permission) throws java.security.AccessControlException;
    --    method public static T doPrivileged(java.security.PrivilegedAction<T>);
    --    method public static T doPrivileged(java.security.PrivilegedAction<T>, java.security.AccessControlContext);
    --    method public static T doPrivileged(java.security.PrivilegedExceptionAction<T>) throws java.security.PrivilegedActionException;
    --    method public static T doPrivileged(java.security.PrivilegedExceptionAction<T>, java.security.AccessControlContext) throws java.security.PrivilegedActionException;
    --    method public static T doPrivilegedWithCombiner(java.security.PrivilegedAction<T>);
    --    method public static T doPrivilegedWithCombiner(java.security.PrivilegedExceptionAction<T>) throws java.security.PrivilegedActionException;
    -+    method public static <T> T doPrivileged(java.security.PrivilegedAction<T>);
    -+    method public static <T> T doPrivileged(java.security.PrivilegedAction<T>, java.security.AccessControlContext);
    -+    method public static <T> T doPrivileged(java.security.PrivilegedExceptionAction<T>) throws java.security.PrivilegedActionException;
    -+    method public static <T> T doPrivileged(java.security.PrivilegedExceptionAction<T>, java.security.AccessControlContext) throws java.security.PrivilegedActionException;
    -+    method public static <T> T doPrivilegedWithCombiner(java.security.PrivilegedAction<T>);
    -+    method public static <T> T doPrivilegedWithCombiner(java.security.PrivilegedExceptionAction<T>) throws java.security.PrivilegedActionException;
    -     method public static java.security.AccessControlContext getContext();
    -   }
    - 
    -@@ -54009,7 +54009,7 @@ package java.security {
    -     method public static java.security.AlgorithmParameters getInstance(java.lang.String) throws java.security.NoSuchAlgorithmException;
    -     method public static java.security.AlgorithmParameters getInstance(java.lang.String, java.lang.String) throws java.security.NoSuchAlgorithmException, java.security.NoSuchProviderException;
    -     method public static java.security.AlgorithmParameters getInstance(java.lang.String, java.security.Provider) throws java.security.NoSuchAlgorithmException;
    --    method public final T getParameterSpec(java.lang.Class<T>) throws java.security.spec.InvalidParameterSpecException;
    -+    method public final <T extends java.security.spec.AlgorithmParameterSpec> T getParameterSpec(java.lang.Class<T>) throws java.security.spec.InvalidParameterSpecException;
    -     method public final java.security.Provider getProvider();
    -     method public final void init(java.security.spec.AlgorithmParameterSpec) throws java.security.spec.InvalidParameterSpecException;
    -     method public final void init(byte[]) throws java.io.IOException;
    -@@ -54021,7 +54021,7 @@ package java.security {
    -     ctor public AlgorithmParametersSpi();
    -     method protected abstract byte[] engineGetEncoded() throws java.io.IOException;
    -     method protected abstract byte[] engineGetEncoded(java.lang.String) throws java.io.IOException;
    --    method protected abstract T engineGetParameterSpec(java.lang.Class<T>) throws java.security.spec.InvalidParameterSpecException;
    -+    method protected abstract <T extends java.security.spec.AlgorithmParameterSpec> T engineGetParameterSpec(java.lang.Class<T>) throws java.security.spec.InvalidParameterSpecException;
    -     method protected abstract void engineInit(java.security.spec.AlgorithmParameterSpec) throws java.security.spec.InvalidParameterSpecException;
    -     method protected abstract void engineInit(byte[]) throws java.io.IOException;
    -     method protected abstract void engineInit(byte[], java.lang.String) throws java.io.IOException;
    -@@ -54206,7 +54206,7 @@ package java.security {
    -     method public static java.security.KeyFactory getInstance(java.lang.String) throws java.security.NoSuchAlgorithmException;
    -     method public static java.security.KeyFactory getInstance(java.lang.String, java.lang.String) throws java.security.NoSuchAlgorithmException, java.security.NoSuchProviderException;
    -     method public static java.security.KeyFactory getInstance(java.lang.String, java.security.Provider) throws java.security.NoSuchAlgorithmException;
    --    method public final T getKeySpec(java.security.Key, java.lang.Class<T>) throws java.security.spec.InvalidKeySpecException;
    -+    method public final <T extends java.security.spec.KeySpec> T getKeySpec(java.security.Key, java.lang.Class<T>) throws java.security.spec.InvalidKeySpecException;
    -     method public final java.security.Provider getProvider();
    -     method public final java.security.Key translateKey(java.security.Key) throws java.security.InvalidKeyException;
    -   }
    -@@ -54215,7 +54215,7 @@ package java.security {
    -     ctor public KeyFactorySpi();
    -     method protected abstract java.security.PrivateKey engineGeneratePrivate(java.security.spec.KeySpec) throws java.security.spec.InvalidKeySpecException;
    -     method protected abstract java.security.PublicKey engineGeneratePublic(java.security.spec.KeySpec) throws java.security.spec.InvalidKeySpecException;
    --    method protected abstract T engineGetKeySpec(java.security.Key, java.lang.Class<T>) throws java.security.spec.InvalidKeySpecException;
    -+    method protected abstract <T extends java.security.spec.KeySpec> T engineGetKeySpec(java.security.Key, java.lang.Class<T>) throws java.security.spec.InvalidKeySpecException;
    -     method protected abstract java.security.Key engineTranslateKey(java.security.Key) throws java.security.InvalidKeyException;
    -   }
    - 
    -@@ -54484,7 +54484,7 @@ package java.security {
    -     field public static final long serialVersionUID = 6034044314589513430L; // 0x53bd3b559a12c6d6L
    -   }
    - 
    --  public abstract interface PrivilegedAction {
    -+  public abstract interface PrivilegedAction<T> {
    -     method public abstract T run();
    -   }
    - 
    -@@ -54493,7 +54493,7 @@ package java.security {
    -     method public java.lang.Exception getException();
    -   }
    - 
    --  public abstract interface PrivilegedExceptionAction {
    -+  public abstract interface PrivilegedExceptionAction<T> {
    -     method public abstract T run() throws java.lang.Exception;
    -   }
    - 
    -@@ -56675,11 +56675,11 @@ package java.sql {
    -     method public abstract void free() throws java.sql.SQLException;
    -     method public abstract java.io.InputStream getBinaryStream() throws java.sql.SQLException;
    -     method public abstract java.io.Reader getCharacterStream() throws java.sql.SQLException;
    --    method public abstract T getSource(java.lang.Class<T>) throws java.sql.SQLException;
    -+    method public abstract <T extends javax.xml.transform.Source> T getSource(java.lang.Class<T>) throws java.sql.SQLException;
    -     method public abstract java.lang.String getString() throws java.sql.SQLException;
    -     method public abstract java.io.OutputStream setBinaryStream() throws java.sql.SQLException;
    -     method public abstract java.io.Writer setCharacterStream() throws java.sql.SQLException;
    --    method public abstract T setResult(java.lang.Class<T>) throws java.sql.SQLException;
    -+    method public abstract <T extends javax.xml.transform.Result> T setResult(java.lang.Class<T>) throws java.sql.SQLException;
    -     method public abstract void setString(java.lang.String) throws java.sql.SQLException;
    -   }
    - 
    -@@ -56803,7 +56803,7 @@ package java.sql {
    - 
    -   public abstract interface Wrapper {
    -     method public abstract boolean isWrapperFor(java.lang.Class<?>) throws java.sql.SQLException;
    --    method public abstract T unwrap(java.lang.Class<T>) throws java.sql.SQLException;
    -+    method public abstract <T> T unwrap(java.lang.Class<T>) throws java.sql.SQLException;
    -   }
    - 
    - }
    -@@ -57336,7 +57336,7 @@ package java.text {
    - 
    - package java.util {
    - 
    --  public abstract class AbstractCollection implements java.util.Collection {
    -+  public abstract class AbstractCollection<E> implements java.util.Collection {
    -     ctor protected AbstractCollection();
    -     method public boolean add(E);
    -     method public boolean addAll(java.util.Collection<? extends E>);
    -@@ -57350,10 +57350,10 @@ package java.util {
    -     method public boolean retainAll(java.util.Collection<?>);
    -     method public abstract int size();
    -     method public java.lang.Object[] toArray();
    --    method public T[] toArray(T[]);
    -+    method public <T> T[] toArray(T[]);
    -   }
    - 
    --  public abstract class AbstractList extends java.util.AbstractCollection implements java.util.List {
    -+  public abstract class AbstractList<E> extends java.util.AbstractCollection implements java.util.List {
    -     ctor protected AbstractList();
    -     method public void add(int, E);
    -     method public boolean addAll(int, java.util.Collection<? extends E>);
    -@@ -57370,7 +57370,7 @@ package java.util {
    -     field protected transient int modCount;
    -   }
    - 
    --  public abstract class AbstractMap implements java.util.Map {
    -+  public abstract class AbstractMap<K, V> implements java.util.Map {
    -     ctor protected AbstractMap();
    -     method public void clear();
    -     method public boolean containsKey(java.lang.Object);
    -@@ -57386,7 +57386,7 @@ package java.util {
    -     method public java.util.Collection<V> values();
    -   }
    - 
    --  public static class AbstractMap.SimpleEntry implements java.util.Map.Entry java.io.Serializable {
    -+  public static class AbstractMap.SimpleEntry<K, V> implements java.util.Map.Entry java.io.Serializable {
    -     ctor public AbstractMap.SimpleEntry(K, V);
    -     ctor public AbstractMap.SimpleEntry(java.util.Map.Entry<? extends K, ? extends V>);
    -     method public K getKey();
    -@@ -57394,7 +57394,7 @@ package java.util {
    -     method public V setValue(V);
    -   }
    - 
    --  public static class AbstractMap.SimpleImmutableEntry implements java.util.Map.Entry java.io.Serializable {
    -+  public static class AbstractMap.SimpleImmutableEntry<K, V> implements java.util.Map.Entry java.io.Serializable {
    -     ctor public AbstractMap.SimpleImmutableEntry(K, V);
    -     ctor public AbstractMap.SimpleImmutableEntry(java.util.Map.Entry<? extends K, ? extends V>);
    -     method public K getKey();
    -@@ -57402,23 +57402,23 @@ package java.util {
    -     method public V setValue(V);
    -   }
    - 
    --  public abstract class AbstractQueue extends java.util.AbstractCollection implements java.util.Queue {
    -+  public abstract class AbstractQueue<E> extends java.util.AbstractCollection implements java.util.Queue {
    -     ctor protected AbstractQueue();
    -     method public E element();
    -     method public E remove();
    -   }
    - 
    --  public abstract class AbstractSequentialList extends java.util.AbstractList {
    -+  public abstract class AbstractSequentialList<E> extends java.util.AbstractList {
    -     ctor protected AbstractSequentialList();
    -     method public E get(int);
    -     method public abstract java.util.ListIterator<E> listIterator(int);
    -   }
    - 
    --  public abstract class AbstractSet extends java.util.AbstractCollection implements java.util.Set {
    -+  public abstract class AbstractSet<E> extends java.util.AbstractCollection implements java.util.Set {
    -     ctor protected AbstractSet();
    -   }
    - 
    --  public class ArrayDeque extends java.util.AbstractCollection implements java.lang.Cloneable java.util.Deque java.io.Serializable {
    -+  public class ArrayDeque<E> extends java.util.AbstractCollection implements java.lang.Cloneable java.util.Deque java.io.Serializable {
    -     ctor public ArrayDeque();
    -     ctor public ArrayDeque(int);
    -     ctor public ArrayDeque(java.util.Collection<? extends E>);
    -@@ -57450,7 +57450,7 @@ package java.util {
    -     method public java.util.Spliterator<E> spliterator();
    -   }
    - 
    --  public class ArrayList extends java.util.AbstractList implements java.lang.Cloneable java.util.List java.util.RandomAccess java.io.Serializable {
    -+  public class ArrayList<E> extends java.util.AbstractList implements java.lang.Cloneable java.util.List java.util.RandomAccess java.io.Serializable {
    -     ctor public ArrayList(int);
    -     ctor public ArrayList();
    -     ctor public ArrayList(java.util.Collection<? extends E>);
    -@@ -57467,7 +57467,7 @@ package java.util {
    -   }
    - 
    -   public class Arrays {
    --    method public static java.util.List<T> asList(T...);
    -+    method public static <T> java.util.List<T> asList(T...);
    -     method public static int binarySearch(long[], long);
    -     method public static int binarySearch(long[], int, int, long);
    -     method public static int binarySearch(int[], int);
    -@@ -57484,10 +57484,10 @@ package java.util {
    -     method public static int binarySearch(float[], int, int, float);
    -     method public static int binarySearch(java.lang.Object[], java.lang.Object);
    -     method public static int binarySearch(java.lang.Object[], int, int, java.lang.Object);
    --    method public static int binarySearch(T[], T, java.util.Comparator<? super T>);
    --    method public static int binarySearch(T[], int, int, T, java.util.Comparator<? super T>);
    --    method public static T[] copyOf(T[], int);
    --    method public static T[] copyOf(U[], int, java.lang.Class<? extends T[]>);
    -+    method public static <T> int binarySearch(T[], T, java.util.Comparator<? super T>);
    -+    method public static <T> int binarySearch(T[], int, int, T, java.util.Comparator<? super T>);
    -+    method public static <T> T[] copyOf(T[], int);
    -+    method public static <T, U> T[] copyOf(U[], int, java.lang.Class<? extends T[]>);
    -     method public static byte[] copyOf(byte[], int);
    -     method public static short[] copyOf(short[], int);
    -     method public static int[] copyOf(int[], int);
    -@@ -57496,8 +57496,8 @@ package java.util {
    -     method public static float[] copyOf(float[], int);
    -     method public static double[] copyOf(double[], int);
    -     method public static boolean[] copyOf(boolean[], int);
    --    method public static T[] copyOfRange(T[], int, int);
    --    method public static T[] copyOfRange(U[], int, int, java.lang.Class<? extends T[]>);
    -+    method public static <T> T[] copyOfRange(T[], int, int);
    -+    method public static <T, U> T[] copyOfRange(U[], int, int, java.lang.Class<? extends T[]>);
    -     method public static byte[] copyOfRange(byte[], int, int);
    -     method public static short[] copyOfRange(short[], int, int);
    -     method public static int[] copyOfRange(int[], int, int);
    -@@ -57545,15 +57545,15 @@ package java.util {
    -     method public static int hashCode(float[]);
    -     method public static int hashCode(double[]);
    -     method public static int hashCode(java.lang.Object[]);
    --    method public static void parallelPrefix(T[], java.util.function.BinaryOperator<T>);
    --    method public static void parallelPrefix(T[], int, int, java.util.function.BinaryOperator<T>);
    -+    method public static <T> void parallelPrefix(T[], java.util.function.BinaryOperator<T>);
    -+    method public static <T> void parallelPrefix(T[], int, int, java.util.function.BinaryOperator<T>);
    -     method public static void parallelPrefix(long[], java.util.function.LongBinaryOperator);
    -     method public static void parallelPrefix(long[], int, int, java.util.function.LongBinaryOperator);
    -     method public static void parallelPrefix(double[], java.util.function.DoubleBinaryOperator);
    -     method public static void parallelPrefix(double[], int, int, java.util.function.DoubleBinaryOperator);
    -     method public static void parallelPrefix(int[], java.util.function.IntBinaryOperator);
    -     method public static void parallelPrefix(int[], int, int, java.util.function.IntBinaryOperator);
    --    method public static void parallelSetAll(T[], java.util.function.IntFunction<? extends T>);
    -+    method public static <T> void parallelSetAll(T[], java.util.function.IntFunction<? extends T>);
    -     method public static void parallelSetAll(int[], java.util.function.IntUnaryOperator);
    -     method public static void parallelSetAll(long[], java.util.function.IntToLongFunction);
    -     method public static void parallelSetAll(double[], java.util.function.IntToDoubleFunction);
    -@@ -57571,11 +57571,11 @@ package java.util {
    -     method public static void parallelSort(float[], int, int);
    -     method public static void parallelSort(double[]);
    -     method public static void parallelSort(double[], int, int);
    --    method public static void parallelSort(T[]);
    --    method public static void parallelSort(T[], int, int);
    --    method public static void parallelSort(T[], java.util.Comparator<? super T>);
    --    method public static void parallelSort(T[], int, int, java.util.Comparator<? super T>);
    --    method public static void setAll(T[], java.util.function.IntFunction<? extends T>);
    -+    method public static <T extends java.lang.Comparable<? super T>> void parallelSort(T[]);
    -+    method public static <T extends java.lang.Comparable<? super T>> void parallelSort(T[], int, int);
    -+    method public static <T> void parallelSort(T[], java.util.Comparator<? super T>);
    -+    method public static <T> void parallelSort(T[], int, int, java.util.Comparator<? super T>);
    -+    method public static <T> void setAll(T[], java.util.function.IntFunction<? extends T>);
    -     method public static void setAll(int[], java.util.function.IntUnaryOperator);
    -     method public static void setAll(long[], java.util.function.IntToLongFunction);
    -     method public static void setAll(double[], java.util.function.IntToDoubleFunction);
    -@@ -57595,18 +57595,18 @@ package java.util {
    -     method public static void sort(double[], int, int);
    -     method public static void sort(java.lang.Object[]);
    -     method public static void sort(java.lang.Object[], int, int);
    --    method public static void sort(T[], java.util.Comparator<? super T>);
    --    method public static void sort(T[], int, int, java.util.Comparator<? super T>);
    --    method public static java.util.Spliterator<T> spliterator(T[]);
    --    method public static java.util.Spliterator<T> spliterator(T[], int, int);
    -+    method public static <T> void sort(T[], java.util.Comparator<? super T>);
    -+    method public static <T> void sort(T[], int, int, java.util.Comparator<? super T>);
    -+    method public static <T> java.util.Spliterator<T> spliterator(T[]);
    -+    method public static <T> java.util.Spliterator<T> spliterator(T[], int, int);
    -     method public static java.util.Spliterator.OfInt spliterator(int[]);
    -     method public static java.util.Spliterator.OfInt spliterator(int[], int, int);
    -     method public static java.util.Spliterator.OfLong spliterator(long[]);
    -     method public static java.util.Spliterator.OfLong spliterator(long[], int, int);
    -     method public static java.util.Spliterator.OfDouble spliterator(double[]);
    -     method public static java.util.Spliterator.OfDouble spliterator(double[], int, int);
    --    method public static java.util.stream.Stream<T> stream(T[]);
    --    method public static java.util.stream.Stream<T> stream(T[], int, int);
    -+    method public static <T> java.util.stream.Stream<T> stream(T[]);
    -+    method public static <T> java.util.stream.Stream<T> stream(T[], int, int);
    -     method public static java.util.stream.IntStream stream(int[]);
    -     method public static java.util.stream.IntStream stream(int[], int, int);
    -     method public static java.util.stream.LongStream stream(long[]);
    -@@ -57763,7 +57763,7 @@ package java.util {
    -     field protected long time;
    -   }
    - 
    --  public abstract interface Collection implements java.lang.Iterable {
    -+  public abstract interface Collection<E> implements java.lang.Iterable {
    -     method public abstract boolean add(E);
    -     method public abstract boolean addAll(java.util.Collection<? extends E>);
    -     method public abstract void clear();
    -@@ -57781,86 +57781,86 @@ package java.util {
    -     method public abstract int size();
    -     method public default java.util.stream.Stream<E> stream();
    -     method public abstract java.lang.Object[] toArray();
    --    method public abstract T[] toArray(T[]);
    -+    method public abstract <T> T[] toArray(T[]);
    -   }
    - 
    -   public class Collections {
    --    method public static boolean addAll(java.util.Collection<? super T>, T...);
    --    method public static java.util.Queue<T> asLifoQueue(java.util.Deque<T>);
    --    method public static int binarySearch(java.util.List<? extends java.lang.Comparable<? super T>>, T);
    --    method public static int binarySearch(java.util.List<? extends T>, T, java.util.Comparator<? super T>);
    --    method public static java.util.Collection<E> checkedCollection(java.util.Collection<E>, java.lang.Class<E>);
    --    method public static java.util.List<E> checkedList(java.util.List<E>, java.lang.Class<E>);
    --    method public static java.util.Map<K, V> checkedMap(java.util.Map<K, V>, java.lang.Class<K>, java.lang.Class<V>);
    --    method public static java.util.Set<E> checkedSet(java.util.Set<E>, java.lang.Class<E>);
    --    method public static java.util.SortedMap<K, V> checkedSortedMap(java.util.SortedMap<K, V>, java.lang.Class<K>, java.lang.Class<V>);
    --    method public static java.util.SortedSet<E> checkedSortedSet(java.util.SortedSet<E>, java.lang.Class<E>);
    --    method public static void copy(java.util.List<? super T>, java.util.List<? extends T>);
    -+    method public static <T> boolean addAll(java.util.Collection<? super T>, T...);
    -+    method public static <T> java.util.Queue<T> asLifoQueue(java.util.Deque<T>);
    -+    method public static <T> int binarySearch(java.util.List<? extends java.lang.Comparable<? super T>>, T);
    -+    method public static <T> int binarySearch(java.util.List<? extends T>, T, java.util.Comparator<? super T>);
    -+    method public static <E> java.util.Collection<E> checkedCollection(java.util.Collection<E>, java.lang.Class<E>);
    -+    method public static <E> java.util.List<E> checkedList(java.util.List<E>, java.lang.Class<E>);
    -+    method public static <K, V> java.util.Map<K, V> checkedMap(java.util.Map<K, V>, java.lang.Class<K>, java.lang.Class<V>);
    -+    method public static <E> java.util.Set<E> checkedSet(java.util.Set<E>, java.lang.Class<E>);
    -+    method public static <K, V> java.util.SortedMap<K, V> checkedSortedMap(java.util.SortedMap<K, V>, java.lang.Class<K>, java.lang.Class<V>);
    -+    method public static <E> java.util.SortedSet<E> checkedSortedSet(java.util.SortedSet<E>, java.lang.Class<E>);
    -+    method public static <T> void copy(java.util.List<? super T>, java.util.List<? extends T>);
    -     method public static boolean disjoint(java.util.Collection<?>, java.util.Collection<?>);
    --    method public static java.util.Enumeration<T> emptyEnumeration();
    --    method public static java.util.Iterator<T> emptyIterator();
    --    method public static final java.util.List<T> emptyList();
    --    method public static java.util.ListIterator<T> emptyListIterator();
    --    method public static final java.util.Map<K, V> emptyMap();
    --    method public static final java.util.Set<T> emptySet();
    --    method public static java.util.Enumeration<T> enumeration(java.util.Collection<T>);
    --    method public static void fill(java.util.List<? super T>, T);
    -+    method public static <T> java.util.Enumeration<T> emptyEnumeration();
    -+    method public static <T> java.util.Iterator<T> emptyIterator();
    -+    method public static final <T> java.util.List<T> emptyList();
    -+    method public static <T> java.util.ListIterator<T> emptyListIterator();
    -+    method public static final <K, V> java.util.Map<K, V> emptyMap();
    -+    method public static final <T> java.util.Set<T> emptySet();
    -+    method public static <T> java.util.Enumeration<T> enumeration(java.util.Collection<T>);
    -+    method public static <T> void fill(java.util.List<? super T>, T);
    -     method public static int frequency(java.util.Collection<?>, java.lang.Object);
    -     method public static int indexOfSubList(java.util.List<?>, java.util.List<?>);
    -     method public static int lastIndexOfSubList(java.util.List<?>, java.util.List<?>);
    --    method public static java.util.ArrayList<T> list(java.util.Enumeration<T>);
    --    method public static T max(java.util.Collection<? extends T>);
    --    method public static T max(java.util.Collection<? extends T>, java.util.Comparator<? super T>);
    --    method public static T min(java.util.Collection<? extends T>);
    --    method public static T min(java.util.Collection<? extends T>, java.util.Comparator<? super T>);
    --    method public static java.util.List<T> nCopies(int, T);
    --    method public static java.util.Set<E> newSetFromMap(java.util.Map<E, java.lang.Boolean>);
    --    method public static boolean replaceAll(java.util.List<T>, T, T);
    -+    method public static <T> java.util.ArrayList<T> list(java.util.Enumeration<T>);
    -+    method public static <T extends java.lang.Object & java.lang.Comparable<? super T>> T max(java.util.Collection<? extends T>);
    -+    method public static <T> T max(java.util.Collection<? extends T>, java.util.Comparator<? super T>);
    -+    method public static <T extends java.lang.Object & java.lang.Comparable<? super T>> T min(java.util.Collection<? extends T>);
    -+    method public static <T> T min(java.util.Collection<? extends T>, java.util.Comparator<? super T>);
    -+    method public static <T> java.util.List<T> nCopies(int, T);
    -+    method public static <E> java.util.Set<E> newSetFromMap(java.util.Map<E, java.lang.Boolean>);
    -+    method public static <T> boolean replaceAll(java.util.List<T>, T, T);
    -     method public static void reverse(java.util.List<?>);
    --    method public static java.util.Comparator<T> reverseOrder();
    --    method public static java.util.Comparator<T> reverseOrder(java.util.Comparator<T>);
    -+    method public static <T> java.util.Comparator<T> reverseOrder();
    -+    method public static <T> java.util.Comparator<T> reverseOrder(java.util.Comparator<T>);
    -     method public static void rotate(java.util.List<?>, int);
    -     method public static void shuffle(java.util.List<?>);
    -     method public static void shuffle(java.util.List<?>, java.util.Random);
    --    method public static java.util.Set<E> singleton(E);
    --    method public static java.util.List<E> singletonList(E);
    --    method public static java.util.Map<K, V> singletonMap(K, V);
    --    method public static void sort(java.util.List<T>);
    --    method public static void sort(java.util.List<T>, java.util.Comparator<? super T>);
    -+    method public static <E> java.util.Set<E> singleton(E);
    -+    method public static <E> java.util.List<E> singletonList(E);
    -+    method public static <K, V> java.util.Map<K, V> singletonMap(K, V);
    -+    method public static <T extends java.lang.Comparable<? super T>> void sort(java.util.List<T>);
    -+    method public static <T> void sort(java.util.List<T>, java.util.Comparator<? super T>);
    -     method public static void swap(java.util.List<?>, int, int);
    --    method public static java.util.Collection<T> synchronizedCollection(java.util.Collection<T>);
    --    method public static java.util.List<T> synchronizedList(java.util.List<T>);
    --    method public static java.util.Map<K, V> synchronizedMap(java.util.Map<K, V>);
    --    method public static java.util.Set<T> synchronizedSet(java.util.Set<T>);
    --    method public static java.util.SortedMap<K, V> synchronizedSortedMap(java.util.SortedMap<K, V>);
    --    method public static java.util.SortedSet<T> synchronizedSortedSet(java.util.SortedSet<T>);
    --    method public static java.util.Collection<T> unmodifiableCollection(java.util.Collection<? extends T>);
    --    method public static java.util.List<T> unmodifiableList(java.util.List<? extends T>);
    --    method public static java.util.Map<K, V> unmodifiableMap(java.util.Map<? extends K, ? extends V>);
    --    method public static java.util.Set<T> unmodifiableSet(java.util.Set<? extends T>);
    --    method public static java.util.SortedMap<K, V> unmodifiableSortedMap(java.util.SortedMap<K, ? extends V>);
    --    method public static java.util.SortedSet<T> unmodifiableSortedSet(java.util.SortedSet<T>);
    -+    method public static <T> java.util.Collection<T> synchronizedCollection(java.util.Collection<T>);
    -+    method public static <T> java.util.List<T> synchronizedList(java.util.List<T>);
    -+    method public static <K, V> java.util.Map<K, V> synchronizedMap(java.util.Map<K, V>);
    -+    method public static <T> java.util.Set<T> synchronizedSet(java.util.Set<T>);
    -+    method public static <K, V> java.util.SortedMap<K, V> synchronizedSortedMap(java.util.SortedMap<K, V>);
    -+    method public static <T> java.util.SortedSet<T> synchronizedSortedSet(java.util.SortedSet<T>);
    -+    method public static <T> java.util.Collection<T> unmodifiableCollection(java.util.Collection<? extends T>);
    -+    method public static <T> java.util.List<T> unmodifiableList(java.util.List<? extends T>);
    -+    method public static <K, V> java.util.Map<K, V> unmodifiableMap(java.util.Map<? extends K, ? extends V>);
    -+    method public static <T> java.util.Set<T> unmodifiableSet(java.util.Set<? extends T>);
    -+    method public static <K, V> java.util.SortedMap<K, V> unmodifiableSortedMap(java.util.SortedMap<K, ? extends V>);
    -+    method public static <T> java.util.SortedSet<T> unmodifiableSortedSet(java.util.SortedSet<T>);
    -     field public static final java.util.List EMPTY_LIST;
    -     field public static final java.util.Map EMPTY_MAP;
    -     field public static final java.util.Set EMPTY_SET;
    -   }
    - 
    --  public abstract interface Comparator {
    -+  public abstract interface Comparator<T> {
    -     method public abstract int compare(T, T);
    --    method public static java.util.Comparator<T> comparing(java.util.function.Function<? super T, ? extends U>, java.util.Comparator<? super U>);
    --    method public static java.util.Comparator<T> comparing(java.util.function.Function<? super T, ? extends U>);
    --    method public static java.util.Comparator<T> comparingDouble(java.util.function.ToDoubleFunction<? super T>);
    --    method public static java.util.Comparator<T> comparingInt(java.util.function.ToIntFunction<? super T>);
    --    method public static java.util.Comparator<T> comparingLong(java.util.function.ToLongFunction<? super T>);
    -+    method public static <T, U> java.util.Comparator<T> comparing(java.util.function.Function<? super T, ? extends U>, java.util.Comparator<? super U>);
    -+    method public static <T, U extends java.lang.Comparable<? super U>> java.util.Comparator<T> comparing(java.util.function.Function<? super T, ? extends U>);
    -+    method public static <T> java.util.Comparator<T> comparingDouble(java.util.function.ToDoubleFunction<? super T>);
    -+    method public static <T> java.util.Comparator<T> comparingInt(java.util.function.ToIntFunction<? super T>);
    -+    method public static <T> java.util.Comparator<T> comparingLong(java.util.function.ToLongFunction<? super T>);
    -     method public abstract boolean equals(java.lang.Object);
    --    method public static java.util.Comparator<T> naturalOrder();
    --    method public static java.util.Comparator<T> nullsFirst(java.util.Comparator<? super T>);
    --    method public static java.util.Comparator<T> nullsLast(java.util.Comparator<? super T>);
    --    method public static java.util.Comparator<T> reverseOrder();
    -+    method public static <T extends java.lang.Comparable<? super T>> java.util.Comparator<T> naturalOrder();
    -+    method public static <T> java.util.Comparator<T> nullsFirst(java.util.Comparator<? super T>);
    -+    method public static <T> java.util.Comparator<T> nullsLast(java.util.Comparator<? super T>);
    -+    method public static <T extends java.lang.Comparable<? super T>> java.util.Comparator<T> reverseOrder();
    -     method public default java.util.Comparator<T> reversed();
    -     method public default java.util.Comparator<T> thenComparing(java.util.Comparator<? super T>);
    --    method public default java.util.Comparator<T> thenComparing(java.util.function.Function<? super T, ? extends U>, java.util.Comparator<? super U>);
    --    method public default java.util.Comparator<T> thenComparing(java.util.function.Function<? super T, ? extends U>);
    -+    method public default <U> java.util.Comparator<T> thenComparing(java.util.function.Function<? super T, ? extends U>, java.util.Comparator<? super U>);
    -+    method public default <U extends java.lang.Comparable<? super U>> java.util.Comparator<T> thenComparing(java.util.function.Function<? super T, ? extends U>);
    -     method public default java.util.Comparator<T> thenComparingDouble(java.util.function.ToDoubleFunction<? super T>);
    -     method public default java.util.Comparator<T> thenComparingInt(java.util.function.ToIntFunction<? super T>);
    -     method public default java.util.Comparator<T> thenComparingLong(java.util.function.ToLongFunction<? super T>);
    -@@ -57919,7 +57919,7 @@ package java.util {
    -     method public deprecated java.lang.String toLocaleString();
    -   }
    - 
    --  public abstract interface Deque implements java.util.Queue {
    -+  public abstract interface Deque<E> implements java.util.Queue {
    -     method public abstract boolean add(E);
    -     method public abstract void addFirst(E);
    -     method public abstract void addLast(E);
    -@@ -57949,7 +57949,7 @@ package java.util {
    -     method public abstract int size();
    -   }
    - 
    --  public abstract class Dictionary {
    -+  public abstract class Dictionary<K, V> {
    -     ctor public Dictionary();
    -     method public abstract java.util.Enumeration<V> elements();
    -     method public abstract V get(java.lang.Object);
    -@@ -57980,7 +57980,7 @@ package java.util {
    -     ctor public EmptyStackException();
    -   }
    - 
    --  public class EnumMap extends java.util.AbstractMap implements java.lang.Cloneable java.io.Serializable {
    -+  public class EnumMap<K extends java.lang.Enum<K>, V> extends java.util.AbstractMap implements java.lang.Cloneable java.io.Serializable {
    -     ctor public EnumMap(java.lang.Class<K>);
    -     ctor public EnumMap(java.util.EnumMap<K, ? extends V>);
    -     ctor public EnumMap(java.util.Map<K, ? extends V>);
    -@@ -57988,23 +57988,23 @@ package java.util {
    -     method public java.util.Set<java.util.Map.Entry<K, V>> entrySet();
    -   }
    - 
    --  public abstract class EnumSet extends java.util.AbstractSet implements java.lang.Cloneable java.io.Serializable {
    --    method public static java.util.EnumSet<E> allOf(java.lang.Class<E>);
    -+  public abstract class EnumSet<E extends java.lang.Enum<E>> extends java.util.AbstractSet implements java.lang.Cloneable java.io.Serializable {
    -+    method public static <E extends java.lang.Enum<E>> java.util.EnumSet<E> allOf(java.lang.Class<E>);
    -     method public java.util.EnumSet<E> clone();
    --    method public static java.util.EnumSet<E> complementOf(java.util.EnumSet<E>);
    --    method public static java.util.EnumSet<E> copyOf(java.util.EnumSet<E>);
    --    method public static java.util.EnumSet<E> copyOf(java.util.Collection<E>);
    --    method public static java.util.EnumSet<E> noneOf(java.lang.Class<E>);
    --    method public static java.util.EnumSet<E> of(E);
    --    method public static java.util.EnumSet<E> of(E, E);
    --    method public static java.util.EnumSet<E> of(E, E, E);
    --    method public static java.util.EnumSet<E> of(E, E, E, E);
    --    method public static java.util.EnumSet<E> of(E, E, E, E, E);
    --    method public static java.util.EnumSet<E> of(E, E...);
    --    method public static java.util.EnumSet<E> range(E, E);
    --  }
    --
    --  public abstract interface Enumeration {
    -+    method public static <E extends java.lang.Enum<E>> java.util.EnumSet<E> complementOf(java.util.EnumSet<E>);
    -+    method public static <E extends java.lang.Enum<E>> java.util.EnumSet<E> copyOf(java.util.EnumSet<E>);
    -+    method public static <E extends java.lang.Enum<E>> java.util.EnumSet<E> copyOf(java.util.Collection<E>);
    -+    method public static <E extends java.lang.Enum<E>> java.util.EnumSet<E> noneOf(java.lang.Class<E>);
    -+    method public static <E extends java.lang.Enum<E>> java.util.EnumSet<E> of(E);
    -+    method public static <E extends java.lang.Enum<E>> java.util.EnumSet<E> of(E, E);
    -+    method public static <E extends java.lang.Enum<E>> java.util.EnumSet<E> of(E, E, E);
    -+    method public static <E extends java.lang.Enum<E>> java.util.EnumSet<E> of(E, E, E, E);
    -+    method public static <E extends java.lang.Enum<E>> java.util.EnumSet<E> of(E, E, E, E, E);
    -+    method public static <E extends java.lang.Enum<E>> java.util.EnumSet<E> of(E, E...);
    -+    method public static <E extends java.lang.Enum<E>> java.util.EnumSet<E> range(E, E);
    -+  }
    -+
    -+  public abstract interface Enumeration<E> {
    -     method public abstract boolean hasMoreElements();
    -     method public abstract E nextElement();
    -   }
    -@@ -58012,7 +58012,7 @@ package java.util {
    -   public abstract interface EventListener {
    -   }
    - 
    --  public abstract class EventListenerProxy implements java.util.EventListener {
    -+  public abstract class EventListenerProxy<T extends java.util.EventListener> implements java.util.EventListener {
    -     ctor public EventListenerProxy(T);
    -     method public T getListener();
    -   }
    -@@ -58098,7 +58098,7 @@ package java.util {
    -     field public static final int BC = 0; // 0x0
    -   }
    - 
    --  public class HashMap extends java.util.AbstractMap implements java.lang.Cloneable java.util.Map java.io.Serializable {
    -+  public class HashMap<K, V> extends java.util.AbstractMap implements java.lang.Cloneable java.util.Map java.io.Serializable {
    -     ctor public HashMap(int, float);
    -     ctor public HashMap(int);
    -     ctor public HashMap();
    -@@ -58110,7 +58110,7 @@ package java.util {
    -     method public void replaceAll(java.util.function.BiFunction<? super K, ? super V, ? extends V>);
    -   }
    - 
    --  public class HashSet extends java.util.AbstractSet implements java.lang.Cloneable java.io.Serializable java.util.Set {
    -+  public class HashSet<E> extends java.util.AbstractSet implements java.lang.Cloneable java.io.Serializable java.util.Set {
    -     ctor public HashSet();
    -     ctor public HashSet(java.util.Collection<? extends E>);
    -     ctor public HashSet(int, float);
    -@@ -58121,7 +58121,7 @@ package java.util {
    -     method public java.util.Spliterator<E> spliterator();
    -   }
    - 
    --  public class Hashtable extends java.util.Dictionary implements java.lang.Cloneable java.util.Map java.io.Serializable {
    -+  public class Hashtable<K, V> extends java.util.Dictionary implements java.lang.Cloneable java.util.Map java.io.Serializable {
    -     ctor public Hashtable(int, float);
    -     ctor public Hashtable(int);
    -     ctor public Hashtable();
    -@@ -58156,7 +58156,7 @@ package java.util {
    -     method public java.util.Collection<V> values();
    -   }
    - 
    --  public class IdentityHashMap extends java.util.AbstractMap implements java.lang.Cloneable java.util.Map java.io.Serializable {
    -+  public class IdentityHashMap<K, V> extends java.util.AbstractMap implements java.lang.Cloneable java.util.Map java.io.Serializable {
    -     ctor public IdentityHashMap();
    -     ctor public IdentityHashMap(int);
    -     ctor public IdentityHashMap(java.util.Map<? extends K, ? extends V>);
    -@@ -58223,14 +58223,14 @@ package java.util {
    -     ctor public InvalidPropertiesFormatException(java.lang.String);
    -   }
    - 
    --  public abstract interface Iterator {
    -+  public abstract interface Iterator<E> {
    -     method public default void forEachRemaining(java.util.function.Consumer<? super E>);
    -     method public abstract boolean hasNext();
    -     method public abstract E next();
    -     method public default void remove();
    -   }
    - 
    --  public class LinkedHashMap extends java.util.HashMap implements java.util.Map {
    -+  public class LinkedHashMap<K, V> extends java.util.HashMap implements java.util.Map {
    -     ctor public LinkedHashMap(int, float);
    -     ctor public LinkedHashMap(int);
    -     ctor public LinkedHashMap();
    -@@ -58239,14 +58239,14 @@ package java.util {
    -     method protected boolean removeEldestEntry(java.util.Map.Entry<K, V>);
    -   }
    - 
    --  public class LinkedHashSet extends java.util.HashSet implements java.lang.Cloneable java.io.Serializable java.util.Set {
    -+  public class LinkedHashSet<E> extends java.util.HashSet implements java.lang.Cloneable java.io.Serializable java.util.Set {
    -     ctor public LinkedHashSet(int, float);
    -     ctor public LinkedHashSet(int);
    -     ctor public LinkedHashSet();
    -     ctor public LinkedHashSet(java.util.Collection<? extends E>);
    -   }
    - 
    --  public class LinkedList extends java.util.AbstractSequentialList implements java.lang.Cloneable java.util.Deque java.util.List java.io.Serializable {
    -+  public class LinkedList<E> extends java.util.AbstractSequentialList implements java.lang.Cloneable java.util.Deque java.util.List java.io.Serializable {
    -     ctor public LinkedList();
    -     ctor public LinkedList(java.util.Collection<? extends E>);
    -     method public void addFirst(E);
    -@@ -58277,7 +58277,7 @@ package java.util {
    -     method public java.util.Spliterator<E> spliterator();
    -   }
    - 
    --  public abstract interface List implements java.util.Collection {
    -+  public abstract interface List<E> implements java.util.Collection {
    -     method public abstract boolean add(E);
    -     method public abstract void add(int, E);
    -     method public abstract boolean addAll(java.util.Collection<? extends E>);
    -@@ -58304,10 +58304,10 @@ package java.util {
    -     method public default void sort(java.util.Comparator<? super E>);
    -     method public abstract java.util.List<E> subList(int, int);
    -     method public abstract java.lang.Object[] toArray();
    --    method public abstract T[] toArray(T[]);
    -+    method public abstract <T> T[] toArray(T[]);
    -   }
    - 
    --  public abstract interface ListIterator implements java.util.Iterator {
    -+  public abstract interface ListIterator<E> implements java.util.Iterator {
    -     method public abstract void add(E);
    -     method public abstract boolean hasNext();
    -     method public abstract boolean hasPrevious();
    -@@ -58424,7 +58424,7 @@ package java.util {
    -     method public final long getSum();
    -   }
    - 
    --  public abstract interface Map {
    -+  public abstract interface Map<K, V> {
    -     method public abstract void clear();
    -     method public default V compute(K, java.util.function.BiFunction<? super K, ? super V, ? extends V>);
    -     method public default V computeIfAbsent(K, java.util.function.Function<? super K, ? extends V>);
    -@@ -58452,11 +58452,11 @@ package java.util {
    -     method public abstract java.util.Collection<V> values();
    -   }
    - 
    --  public static abstract interface Map.Entry {
    --    method public static java.util.Comparator<java.util.Map.Entry<K, V>> comparingByKey();
    --    method public static java.util.Comparator<java.util.Map.Entry<K, V>> comparingByKey(java.util.Comparator<? super K>);
    --    method public static java.util.Comparator<java.util.Map.Entry<K, V>> comparingByValue();
    --    method public static java.util.Comparator<java.util.Map.Entry<K, V>> comparingByValue(java.util.Comparator<? super V>);
    -+  public static abstract interface Map.Entry<K, V> {
    -+    method public static <K extends java.lang.Comparable<? super K>, V> java.util.Comparator<java.util.Map.Entry<K, V>> comparingByKey();
    -+    method public static <K, V> java.util.Comparator<java.util.Map.Entry<K, V>> comparingByKey(java.util.Comparator<? super K>);
    -+    method public static <K, V extends java.lang.Comparable<? super V>> java.util.Comparator<java.util.Map.Entry<K, V>> comparingByValue();
    -+    method public static <K, V> java.util.Comparator<java.util.Map.Entry<K, V>> comparingByValue(java.util.Comparator<? super V>);
    -     method public abstract boolean equals(java.lang.Object);
    -     method public abstract K getKey();
    -     method public abstract V getValue();
    -@@ -58480,7 +58480,7 @@ package java.util {
    -     method public java.lang.String getKey();
    -   }
    - 
    --  public abstract interface NavigableMap implements java.util.SortedMap {
    -+  public abstract interface NavigableMap<K, V> implements java.util.SortedMap {
    -     method public abstract java.util.Map.Entry<K, V> ceilingEntry(K);
    -     method public abstract K ceilingKey(K);
    -     method public abstract java.util.NavigableSet<K> descendingKeySet();
    -@@ -58504,7 +58504,7 @@ package java.util {
    -     method public abstract java.util.SortedMap<K, V> tailMap(K);
    -   }
    - 
    --  public abstract interface NavigableSet implements java.util.SortedSet {
    -+  public abstract interface NavigableSet<E> implements java.util.SortedSet {
    -     method public abstract E ceiling(E);
    -     method public abstract java.util.Iterator<E> descendingIterator();
    -     method public abstract java.util.NavigableSet<E> descendingSet();
    -@@ -58528,16 +58528,16 @@ package java.util {
    -   }
    - 
    -   public final class Objects {
    --    method public static int compare(T, T, java.util.Comparator<? super T>);
    -+    method public static <T> int compare(T, T, java.util.Comparator<? super T>);
    -     method public static boolean deepEquals(java.lang.Object, java.lang.Object);
    -     method public static boolean equals(java.lang.Object, java.lang.Object);
    -     method public static int hash(java.lang.Object...);
    -     method public static int hashCode(java.lang.Object);
    -     method public static boolean isNull(java.lang.Object);
    -     method public static boolean nonNull(java.lang.Object);
    --    method public static T requireNonNull(T);
    --    method public static T requireNonNull(T, java.lang.String);
    --    method public static T requireNonNull(T, java.util.function.Supplier<java.lang.String>);
    -+    method public static <T> T requireNonNull(T);
    -+    method public static <T> T requireNonNull(T, java.lang.String);
    -+    method public static <T> T requireNonNull(T, java.util.function.Supplier<java.lang.String>);
    -     method public static java.lang.String toString(java.lang.Object);
    -     method public static java.lang.String toString(java.lang.Object, java.lang.String);
    -   }
    -@@ -58559,19 +58559,19 @@ package java.util {
    -     method public abstract void update(java.util.Observable, java.lang.Object);
    -   }
    - 
    --  public final class Optional {
    --    method public static java.util.Optional<T> empty();
    -+  public final class Optional<T> {
    -+    method public static <T> java.util.Optional<T> empty();
    -     method public java.util.Optional<T> filter(java.util.function.Predicate<? super T>);
    --    method public java.util.Optional<U> flatMap(java.util.function.Function<? super T, java.util.Optional<U>>);
    -+    method public <U> java.util.Optional<U> flatMap(java.util.function.Function<? super T, java.util.Optional<U>>);
    -     method public T get();
    -     method public void ifPresent(java.util.function.Consumer<? super T>);
    -     method public boolean isPresent();
    --    method public java.util.Optional<U> map(java.util.function.Function<? super T, ? extends U>);
    --    method public static java.util.Optional<T> of(T);
    --    method public static java.util.Optional<T> ofNullable(T);
    -+    method public <U> java.util.Optional<U> map(java.util.function.Function<? super T, ? extends U>);
    -+    method public static <T> java.util.Optional<T> of(T);
    -+    method public static <T> java.util.Optional<T> ofNullable(T);
    -     method public T orElse(T);
    -     method public T orElseGet(java.util.function.Supplier<? extends T>);
    --    method public T orElseThrow(java.util.function.Supplier<? extends X>) throws java.lang.Throwable;
    -+    method public <X extends java.lang.Throwable> T orElseThrow(java.util.function.Supplier<? extends X>) throws java.lang.Throwable;
    -   }
    - 
    -   public final class OptionalDouble {
    -@@ -58582,7 +58582,7 @@ package java.util {
    -     method public static java.util.OptionalDouble of(double);
    -     method public double orElse(double);
    -     method public double orElseGet(java.util.function.DoubleSupplier);
    --    method public double orElseThrow(java.util.function.Supplier<X>) throws java.lang.Throwable;
    -+    method public <X extends java.lang.Throwable> double orElseThrow(java.util.function.Supplier<X>) throws java.lang.Throwable;
    -   }
    - 
    -   public final class OptionalInt {
    -@@ -58593,7 +58593,7 @@ package java.util {
    -     method public static java.util.OptionalInt of(int);
    -     method public int orElse(int);
    -     method public int orElseGet(java.util.function.IntSupplier);
    --    method public int orElseThrow(java.util.function.Supplier<X>) throws java.lang.Throwable;
    -+    method public <X extends java.lang.Throwable> int orElseThrow(java.util.function.Supplier<X>) throws java.lang.Throwable;
    -   }
    - 
    -   public final class OptionalLong {
    -@@ -58604,10 +58604,10 @@ package java.util {
    -     method public static java.util.OptionalLong of(long);
    -     method public long orElse(long);
    -     method public long orElseGet(java.util.function.LongSupplier);
    --    method public long orElseThrow(java.util.function.Supplier<X>) throws java.lang.Throwable;
    -+    method public <X extends java.lang.Throwable> long orElseThrow(java.util.function.Supplier<X>) throws java.lang.Throwable;
    -   }
    - 
    --  public abstract interface PrimitiveIterator implements java.util.Iterator {
    -+  public abstract interface PrimitiveIterator<T, T_CONS> implements java.util.Iterator {
    -     method public abstract void forEachRemaining(T_CONS);
    -   }
    - 
    -@@ -58632,7 +58632,7 @@ package java.util {
    -     method public abstract long nextLong();
    -   }
    - 
    --  public class PriorityQueue extends java.util.AbstractQueue implements java.io.Serializable {
    -+  public class PriorityQueue<E> extends java.util.AbstractQueue implements java.io.Serializable {
    -     ctor public PriorityQueue();
    -     ctor public PriorityQueue(int);
    -     ctor public PriorityQueue(java.util.Comparator<? super E>);
    -@@ -58681,7 +58681,7 @@ package java.util {
    -     method public java.lang.Object handleGetObject(java.lang.String);
    -   }
    - 
    --  public abstract interface Queue implements java.util.Collection {
    -+  public abstract interface Queue<E> implements java.util.Collection {
    -     method public abstract boolean add(E);
    -     method public abstract E element();
    -     method public abstract boolean offer(E);
    -@@ -58831,15 +58831,15 @@ package java.util {
    -     ctor public ServiceConfigurationError(java.lang.String, java.lang.Throwable);
    -   }
    - 
    --  public final class ServiceLoader implements java.lang.Iterable {
    -+  public final class ServiceLoader<S> implements java.lang.Iterable {
    -     method public java.util.Iterator<S> iterator();
    --    method public static java.util.ServiceLoader<S> load(java.lang.Class<S>, java.lang.ClassLoader);
    --    method public static java.util.ServiceLoader<S> load(java.lang.Class<S>);
    --    method public static java.util.ServiceLoader<S> loadInstalled(java.lang.Class<S>);
    -+    method public static <S> java.util.ServiceLoader<S> load(java.lang.Class<S>, java.lang.ClassLoader);
    -+    method public static <S> java.util.ServiceLoader<S> load(java.lang.Class<S>);
    -+    method public static <S> java.util.ServiceLoader<S> loadInstalled(java.lang.Class<S>);
    -     method public void reload();
    -   }
    - 
    --  public abstract interface Set implements java.util.Collection {
    -+  public abstract interface Set<E> implements java.util.Collection {
    -     method public abstract boolean add(E);
    -     method public abstract boolean addAll(java.util.Collection<? extends E>);
    -     method public abstract void clear();
    -@@ -58854,7 +58854,7 @@ package java.util {
    -     method public abstract boolean retainAll(java.util.Collection<?>);
    -     method public abstract int size();
    -     method public abstract java.lang.Object[] toArray();
    --    method public abstract T[] toArray(T[]);
    -+    method public abstract <T> T[] toArray(T[]);
    -   }
    - 
    -   public class SimpleTimeZone extends java.util.TimeZone {
    -@@ -58880,7 +58880,7 @@ package java.util {
    -     field public static final int WALL_TIME = 0; // 0x0
    -   }
    - 
    --  public abstract interface SortedMap implements java.util.Map {
    -+  public abstract interface SortedMap<K, V> implements java.util.Map {
    -     method public abstract java.util.Comparator<? super K> comparator();
    -     method public abstract java.util.Set<java.util.Map.Entry<K, V>> entrySet();
    -     method public abstract K firstKey();
    -@@ -58892,7 +58892,7 @@ package java.util {
    -     method public abstract java.util.Collection<V> values();
    -   }
    - 
    --  public abstract interface SortedSet implements java.util.Set {
    -+  public abstract interface SortedSet<E> implements java.util.Set {
    -     method public abstract java.util.Comparator<? super E> comparator();
    -     method public abstract E first();
    -     method public abstract java.util.SortedSet<E> headSet(E);
    -@@ -58901,7 +58901,7 @@ package java.util {
    -     method public abstract java.util.SortedSet<E> tailSet(E);
    -   }
    - 
    --  public abstract interface Spliterator {
    -+  public abstract interface Spliterator<T> {
    -     method public abstract int characteristics();
    -     method public abstract long estimateSize();
    -     method public default void forEachRemaining(java.util.function.Consumer<? super T>);
    -@@ -58944,7 +58944,7 @@ package java.util {
    -     method public abstract java.util.Spliterator.OfLong trySplit();
    -   }
    - 
    --  public static abstract interface Spliterator.OfPrimitive implements java.util.Spliterator {
    -+  public static abstract interface Spliterator.OfPrimitive<T, T_CONS, T_SPLITR extends java.util.Spliterator.OfPrimitive<T, T_CONS, T_SPLITR>> implements java.util.Spliterator {
    -     method public default void forEachRemaining(T_CONS);
    -     method public abstract boolean tryAdvance(T_CONS);
    -     method public abstract T_SPLITR trySplit();
    -@@ -58954,25 +58954,25 @@ package java.util {
    -     method public static java.util.Spliterator.OfDouble emptyDoubleSpliterator();
    -     method public static java.util.Spliterator.OfInt emptyIntSpliterator();
    -     method public static java.util.Spliterator.OfLong emptyLongSpliterator();
    --    method public static java.util.Spliterator<T> emptySpliterator();
    --    method public static java.util.Iterator<T> iterator(java.util.Spliterator<? extends T>);
    -+    method public static <T> java.util.Spliterator<T> emptySpliterator();
    -+    method public static <T> java.util.Iterator<T> iterator(java.util.Spliterator<? extends T>);
    -     method public static java.util.PrimitiveIterator.OfInt iterator(java.util.Spliterator.OfInt);
    -     method public static java.util.PrimitiveIterator.OfLong iterator(java.util.Spliterator.OfLong);
    -     method public static java.util.PrimitiveIterator.OfDouble iterator(java.util.Spliterator.OfDouble);
    --    method public static java.util.Spliterator<T> spliterator(java.lang.Object[], int);
    --    method public static java.util.Spliterator<T> spliterator(java.lang.Object[], int, int, int);
    -+    method public static <T> java.util.Spliterator<T> spliterator(java.lang.Object[], int);
    -+    method public static <T> java.util.Spliterator<T> spliterator(java.lang.Object[], int, int, int);
    -     method public static java.util.Spliterator.OfInt spliterator(int[], int);
    -     method public static java.util.Spliterator.OfInt spliterator(int[], int, int, int);
    -     method public static java.util.Spliterator.OfLong spliterator(long[], int);
    -     method public static java.util.Spliterator.OfLong spliterator(long[], int, int, int);
    -     method public static java.util.Spliterator.OfDouble spliterator(double[], int);
    -     method public static java.util.Spliterator.OfDouble spliterator(double[], int, int, int);
    --    method public static java.util.Spliterator<T> spliterator(java.util.Collection<? extends T>, int);
    --    method public static java.util.Spliterator<T> spliterator(java.util.Iterator<? extends T>, long, int);
    -+    method public static <T> java.util.Spliterator<T> spliterator(java.util.Collection<? extends T>, int);
    -+    method public static <T> java.util.Spliterator<T> spliterator(java.util.Iterator<? extends T>, long, int);
    -     method public static java.util.Spliterator.OfInt spliterator(java.util.PrimitiveIterator.OfInt, long, int);
    -     method public static java.util.Spliterator.OfLong spliterator(java.util.PrimitiveIterator.OfLong, long, int);
    -     method public static java.util.Spliterator.OfDouble spliterator(java.util.PrimitiveIterator.OfDouble, long, int);
    --    method public static java.util.Spliterator<T> spliteratorUnknownSize(java.util.Iterator<? extends T>, int);
    -+    method public static <T> java.util.Spliterator<T> spliteratorUnknownSize(java.util.Iterator<? extends T>, int);
    -     method public static java.util.Spliterator.OfInt spliteratorUnknownSize(java.util.PrimitiveIterator.OfInt, int);
    -     method public static java.util.Spliterator.OfLong spliteratorUnknownSize(java.util.PrimitiveIterator.OfLong, int);
    -     method public static java.util.Spliterator.OfDouble spliteratorUnknownSize(java.util.PrimitiveIterator.OfDouble, int);
    -@@ -58999,7 +58999,7 @@ package java.util {
    -     method public java.util.Spliterator.OfLong trySplit();
    -   }
    - 
    --  public static abstract class Spliterators.AbstractSpliterator implements java.util.Spliterator {
    -+  public static abstract class Spliterators.AbstractSpliterator<T> implements java.util.Spliterator {
    -     ctor protected Spliterators.AbstractSpliterator(long, int);
    -     method public int characteristics();
    -     method public long estimateSize();
    -@@ -59034,7 +59034,7 @@ package java.util {
    -     method public java.util.SplittableRandom split();
    -   }
    - 
    --  public class Stack extends java.util.Vector {
    -+  public class Stack<E> extends java.util.Vector {
    -     ctor public Stack();
    -     method public boolean empty();
    -     method public synchronized E peek();
    -@@ -59118,7 +59118,7 @@ package java.util {
    -     ctor public TooManyListenersException(java.lang.String);
    -   }
    - 
    --  public class TreeMap extends java.util.AbstractMap implements java.lang.Cloneable java.util.NavigableMap java.io.Serializable {
    -+  public class TreeMap<K, V> extends java.util.AbstractMap implements java.lang.Cloneable java.util.NavigableMap java.io.Serializable {
    -     ctor public TreeMap();
    -     ctor public TreeMap(java.util.Comparator<? super K>);
    -     ctor public TreeMap(java.util.Map<? extends K, ? extends V>);
    -@@ -59155,7 +59155,7 @@ package java.util {
    -     method public java.util.SortedMap<K, V> tailMap(K);
    -   }
    - 
    --  public class TreeSet extends java.util.AbstractSet implements java.lang.Cloneable java.util.NavigableSet java.io.Serializable {
    -+  public class TreeSet<E> extends java.util.AbstractSet implements java.lang.Cloneable java.util.NavigableSet java.io.Serializable {
    -     ctor public TreeSet();
    -     ctor public TreeSet(java.util.Comparator<? super E>);
    -     ctor public TreeSet(java.util.Collection<? extends E>);
    -@@ -59208,7 +59208,7 @@ package java.util {
    -     method public java.lang.String getFlags();
    -   }
    - 
    --  public class Vector extends java.util.AbstractList implements java.lang.Cloneable java.util.List java.util.RandomAccess java.io.Serializable {
    -+  public class Vector<E> extends java.util.AbstractList implements java.lang.Cloneable java.util.List java.util.RandomAccess java.io.Serializable {
    -     ctor public Vector(int, int);
    -     ctor public Vector(int);
    -     ctor public Vector();
    -@@ -59243,7 +59243,7 @@ package java.util {
    -     field protected java.lang.Object[] elementData;
    -   }
    - 
    --  public class WeakHashMap extends java.util.AbstractMap implements java.util.Map {
    -+  public class WeakHashMap<K, V> extends java.util.AbstractMap implements java.util.Map {
    -     ctor public WeakHashMap(int, float);
    -     ctor public WeakHashMap(int);
    -     ctor public WeakHashMap();
    -@@ -59259,18 +59259,18 @@ package java.util.concurrent {
    - 
    -   public abstract class AbstractExecutorService implements java.util.concurrent.ExecutorService {
    -     ctor public AbstractExecutorService();
    --    method public java.util.List<java.util.concurrent.Future<T>> invokeAll(java.util.Collection<? extends java.util.concurrent.Callable<T>>) throws java.lang.InterruptedException;
    --    method public java.util.List<java.util.concurrent.Future<T>> invokeAll(java.util.Collection<? extends java.util.concurrent.Callable<T>>, long, java.util.concurrent.TimeUnit) throws java.lang.InterruptedException;
    --    method public T invokeAny(java.util.Collection<? extends java.util.concurrent.Callable<T>>) throws java.util.concurrent.ExecutionException, java.lang.InterruptedException;
    --    method public T invokeAny(java.util.Collection<? extends java.util.concurrent.Callable<T>>, long, java.util.concurrent.TimeUnit) throws java.util.concurrent.ExecutionException, java.lang.InterruptedException, java.util.concurrent.TimeoutException;
    --    method protected java.util.concurrent.RunnableFuture<T> newTaskFor(java.lang.Runnable, T);
    --    method protected java.util.concurrent.RunnableFuture<T> newTaskFor(java.util.concurrent.Callable<T>);
    -+    method public <T> java.util.List<java.util.concurrent.Future<T>> invokeAll(java.util.Collection<? extends java.util.concurrent.Callable<T>>) throws java.lang.InterruptedException;
    -+    method public <T> java.util.List<java.util.concurrent.Future<T>> invokeAll(java.util.Collection<? extends java.util.concurrent.Callable<T>>, long, java.util.concurrent.TimeUnit) throws java.lang.InterruptedException;
    -+    method public <T> T invokeAny(java.util.Collection<? extends java.util.concurrent.Callable<T>>) throws java.util.concurrent.ExecutionException, java.lang.InterruptedException;
    -+    method public <T> T invokeAny(java.util.Collection<? extends java.util.concurrent.Callable<T>>, long, java.util.concurrent.TimeUnit) throws java.util.concurrent.ExecutionException, java.lang.InterruptedException, java.util.concurrent.TimeoutException;
    -+    method protected <T> java.util.concurrent.RunnableFuture<T> newTaskFor(java.lang.Runnable, T);
    -+    method protected <T> java.util.concurrent.RunnableFuture<T> newTaskFor(java.util.concurrent.Callable<T>);
    -     method public java.util.concurrent.Future<?> submit(java.lang.Runnable);
    --    method public java.util.concurrent.Future<T> submit(java.lang.Runnable, T);
    --    method public java.util.concurrent.Future<T> submit(java.util.concurrent.Callable<T>);
    -+    method public <T> java.util.concurrent.Future<T> submit(java.lang.Runnable, T);
    -+    method public <T> java.util.concurrent.Future<T> submit(java.util.concurrent.Callable<T>);
    -   }
    - 
    --  public class ArrayBlockingQueue extends java.util.AbstractQueue implements java.util.concurrent.BlockingQueue java.io.Serializable {
    -+  public class ArrayBlockingQueue<E> extends java.util.AbstractQueue implements java.util.concurrent.BlockingQueue java.io.Serializable {
    -     ctor public ArrayBlockingQueue(int);
    -     ctor public ArrayBlockingQueue(int, boolean);
    -     ctor public ArrayBlockingQueue(int, boolean, java.util.Collection<? extends E>);
    -@@ -59289,7 +59289,7 @@ package java.util.concurrent {
    -     method public E take() throws java.lang.InterruptedException;
    -   }
    - 
    --  public abstract interface BlockingDeque implements java.util.concurrent.BlockingQueue java.util.Deque {
    -+  public abstract interface BlockingDeque<E> implements java.util.concurrent.BlockingQueue java.util.Deque {
    -     method public abstract boolean add(E);
    -     method public abstract void addFirst(E);
    -     method public abstract void addLast(E);
    -@@ -59321,7 +59321,7 @@ package java.util.concurrent {
    -     method public abstract E takeLast() throws java.lang.InterruptedException;
    -   }
    - 
    --  public abstract interface BlockingQueue implements java.util.Queue {
    -+  public abstract interface BlockingQueue<E> implements java.util.Queue {
    -     method public abstract boolean add(E);
    -     method public abstract boolean contains(java.lang.Object);
    -     method public abstract int drainTo(java.util.Collection<? super E>);
    -@@ -59340,7 +59340,7 @@ package java.util.concurrent {
    -     ctor public BrokenBarrierException(java.lang.String);
    -   }
    - 
    --  public abstract interface Callable {
    -+  public abstract interface Callable<V> {
    -     method public abstract V call() throws java.lang.Exception;
    -   }
    - 
    -@@ -59349,28 +59349,28 @@ package java.util.concurrent {
    -     ctor public CancellationException(java.lang.String);
    -   }
    - 
    --  public class CompletableFuture implements java.util.concurrent.CompletionStage java.util.concurrent.Future {
    -+  public class CompletableFuture<T> implements java.util.concurrent.CompletionStage java.util.concurrent.Future {
    -     ctor public CompletableFuture();
    -     method public java.util.concurrent.CompletableFuture<java.lang.Void> acceptEither(java.util.concurrent.CompletionStage<? extends T>, java.util.function.Consumer<? super T>);
    -     method public java.util.concurrent.CompletableFuture<java.lang.Void> acceptEitherAsync(java.util.concurrent.CompletionStage<? extends T>, java.util.function.Consumer<? super T>);
    -     method public java.util.concurrent.CompletableFuture<java.lang.Void> acceptEitherAsync(java.util.concurrent.CompletionStage<? extends T>, java.util.function.Consumer<? super T>, java.util.concurrent.Executor);
    -     method public static java.util.concurrent.CompletableFuture<java.lang.Void> allOf(java.util.concurrent.CompletableFuture<?>...);
    -     method public static java.util.concurrent.CompletableFuture<java.lang.Object> anyOf(java.util.concurrent.CompletableFuture<?>...);
    --    method public java.util.concurrent.CompletableFuture<U> applyToEither(java.util.concurrent.CompletionStage<? extends T>, java.util.function.Function<? super T, U>);
    --    method public java.util.concurrent.CompletableFuture<U> applyToEitherAsync(java.util.concurrent.CompletionStage<? extends T>, java.util.function.Function<? super T, U>);
    --    method public java.util.concurrent.CompletableFuture<U> applyToEitherAsync(java.util.concurrent.CompletionStage<? extends T>, java.util.function.Function<? super T, U>, java.util.concurrent.Executor);
    -+    method public <U> java.util.concurrent.CompletableFuture<U> applyToEither(java.util.concurrent.CompletionStage<? extends T>, java.util.function.Function<? super T, U>);
    -+    method public <U> java.util.concurrent.CompletableFuture<U> applyToEitherAsync(java.util.concurrent.CompletionStage<? extends T>, java.util.function.Function<? super T, U>);
    -+    method public <U> java.util.concurrent.CompletableFuture<U> applyToEitherAsync(java.util.concurrent.CompletionStage<? extends T>, java.util.function.Function<? super T, U>, java.util.concurrent.Executor);
    -     method public boolean cancel(boolean);
    -     method public boolean complete(T);
    -     method public boolean completeExceptionally(java.lang.Throwable);
    --    method public static java.util.concurrent.CompletableFuture<U> completedFuture(U);
    -+    method public static <U> java.util.concurrent.CompletableFuture<U> completedFuture(U);
    -     method public java.util.concurrent.CompletableFuture<T> exceptionally(java.util.function.Function<java.lang.Throwable, ? extends T>);
    -     method public T get() throws java.util.concurrent.ExecutionException, java.lang.InterruptedException;
    -     method public T get(long, java.util.concurrent.TimeUnit) throws java.util.concurrent.ExecutionException, java.lang.InterruptedException, java.util.concurrent.TimeoutException;
    -     method public T getNow(T);
    -     method public int getNumberOfDependents();
    --    method public java.util.concurrent.CompletableFuture<U> handle(java.util.function.BiFunction<? super T, java.lang.Throwable, ? extends U>);
    --    method public java.util.concurrent.CompletableFuture<U> handleAsync(java.util.function.BiFunction<? super T, java.lang.Throwable, ? extends U>);
    --    method public java.util.concurrent.CompletableFuture<U> handleAsync(java.util.function.BiFunction<? super T, java.lang.Throwable, ? extends U>, java.util.concurrent.Executor);
    -+    method public <U> java.util.concurrent.CompletableFuture<U> handle(java.util.function.BiFunction<? super T, java.lang.Throwable, ? extends U>);
    -+    method public <U> java.util.concurrent.CompletableFuture<U> handleAsync(java.util.function.BiFunction<? super T, java.lang.Throwable, ? extends U>);
    -+    method public <U> java.util.concurrent.CompletableFuture<U> handleAsync(java.util.function.BiFunction<? super T, java.lang.Throwable, ? extends U>, java.util.concurrent.Executor);
    -     method public boolean isCancelled();
    -     method public boolean isCompletedExceptionally();
    -     method public boolean isDone();
    -@@ -59385,23 +59385,23 @@ package java.util.concurrent {
    -     method public java.util.concurrent.CompletableFuture<java.lang.Void> runAfterEitherAsync(java.util.concurrent.CompletionStage<?>, java.lang.Runnable, java.util.concurrent.Executor);
    -     method public static java.util.concurrent.CompletableFuture<java.lang.Void> runAsync(java.lang.Runnable);
    -     method public static java.util.concurrent.CompletableFuture<java.lang.Void> runAsync(java.lang.Runnable, java.util.concurrent.Executor);
    --    method public static java.util.concurrent.CompletableFuture<U> supplyAsync(java.util.function.Supplier<U>);
    --    method public static java.util.concurrent.CompletableFuture<U> supplyAsync(java.util.function.Supplier<U>, java.util.concurrent.Executor);
    -+    method public static <U> java.util.concurrent.CompletableFuture<U> supplyAsync(java.util.function.Supplier<U>);
    -+    method public static <U> java.util.concurrent.CompletableFuture<U> supplyAsync(java.util.function.Supplier<U>, java.util.concurrent.Executor);
    -     method public java.util.concurrent.CompletableFuture<java.lang.Void> thenAccept(java.util.function.Consumer<? super T>);
    -     method public java.util.concurrent.CompletableFuture<java.lang.Void> thenAcceptAsync(java.util.function.Consumer<? super T>);
    -     method public java.util.concurrent.CompletableFuture<java.lang.Void> thenAcceptAsync(java.util.function.Consumer<? super T>, java.util.concurrent.Executor);
    --    method public java.util.concurrent.CompletableFuture<java.lang.Void> thenAcceptBoth(java.util.concurrent.CompletionStage<? extends U>, java.util.function.BiConsumer<? super T, ? super U>);
    --    method public java.util.concurrent.CompletableFuture<java.lang.Void> thenAcceptBothAsync(java.util.concurrent.CompletionStage<? extends U>, java.util.function.BiConsumer<? super T, ? super U>);
    --    method public java.util.concurrent.CompletableFuture<java.lang.Void> thenAcceptBothAsync(java.util.concurrent.CompletionStage<? extends U>, java.util.function.BiConsumer<? super T, ? super U>, java.util.concurrent.Executor);
    --    method public java.util.concurrent.CompletableFuture<U> thenApply(java.util.function.Function<? super T, ? extends U>);
    --    method public java.util.concurrent.CompletableFuture<U> thenApplyAsync(java.util.function.Function<? super T, ? extends U>);
    --    method public java.util.concurrent.CompletableFuture<U> thenApplyAsync(java.util.function.Function<? super T, ? extends U>, java.util.concurrent.Executor);
    --    method public java.util.concurrent.CompletableFuture<V> thenCombine(java.util.concurrent.CompletionStage<? extends U>, java.util.function.BiFunction<? super T, ? super U, ? extends V>);
    --    method public java.util.concurrent.CompletableFuture<V> thenCombineAsync(java.util.concurrent.CompletionStage<? extends U>, java.util.function.BiFunction<? super T, ? super U, ? extends V>);
    --    method public java.util.concurrent.CompletableFuture<V> thenCombineAsync(java.util.concurrent.CompletionStage<? extends U>, java.util.function.BiFunction<? super T, ? super U, ? extends V>, java.util.concurrent.Executor);
    --    method public java.util.concurrent.CompletableFuture<U> thenCompose(java.util.function.Function<? super T, ? extends java.util.concurrent.CompletionStage<U>>);
    --    method public java.util.concurrent.CompletableFuture<U> thenComposeAsync(java.util.function.Function<? super T, ? extends java.util.concurrent.CompletionStage<U>>);
    --    method public java.util.concurrent.CompletableFuture<U> thenComposeAsync(java.util.function.Function<? super T, ? extends java.util.concurrent.CompletionStage<U>>, java.util.concurrent.Executor);
    -+    method public <U> java.util.concurrent.CompletableFuture<java.lang.Void> thenAcceptBoth(java.util.concurrent.CompletionStage<? extends U>, java.util.function.BiConsumer<? super T, ? super U>);
    -+    method public <U> java.util.concurrent.CompletableFuture<java.lang.Void> thenAcceptBothAsync(java.util.concurrent.CompletionStage<? extends U>, java.util.function.BiConsumer<? super T, ? super U>);
    -+    method public <U> java.util.concurrent.CompletableFuture<java.lang.Void> thenAcceptBothAsync(java.util.concurrent.CompletionStage<? extends U>, java.util.function.BiConsumer<? super T, ? super U>, java.util.concurrent.Executor);
    -+    method public <U> java.util.concurrent.CompletableFuture<U> thenApply(java.util.function.Function<? super T, ? extends U>);
    -+    method public <U> java.util.concurrent.CompletableFuture<U> thenApplyAsync(java.util.function.Function<? super T, ? extends U>);
    -+    method public <U> java.util.concurrent.CompletableFuture<U> thenApplyAsync(java.util.function.Function<? super T, ? extends U>, java.util.concurrent.Executor);
    -+    method public <U, V> java.util.concurrent.CompletableFuture<V> thenCombine(java.util.concurrent.CompletionStage<? extends U>, java.util.function.BiFunction<? super T, ? super U, ? extends V>);
    -+    method public <U, V> java.util.concurrent.CompletableFuture<V> thenCombineAsync(java.util.concurrent.CompletionStage<? extends U>, java.util.function.BiFunction<? super T, ? super U, ? extends V>);
    -+    method public <U, V> java.util.concurrent.CompletableFuture<V> thenCombineAsync(java.util.concurrent.CompletionStage<? extends U>, java.util.function.BiFunction<? super T, ? super U, ? extends V>, java.util.concurrent.Executor);
    -+    method public <U> java.util.concurrent.CompletableFuture<U> thenCompose(java.util.function.Function<? super T, ? extends java.util.concurrent.CompletionStage<U>>);
    -+    method public <U> java.util.concurrent.CompletableFuture<U> thenComposeAsync(java.util.function.Function<? super T, ? extends java.util.concurrent.CompletionStage<U>>);
    -+    method public <U> java.util.concurrent.CompletableFuture<U> thenComposeAsync(java.util.function.Function<? super T, ? extends java.util.concurrent.CompletionStage<U>>, java.util.concurrent.Executor);
    -     method public java.util.concurrent.CompletableFuture<java.lang.Void> thenRun(java.lang.Runnable);
    -     method public java.util.concurrent.CompletableFuture<java.lang.Void> thenRunAsync(java.lang.Runnable);
    -     method public java.util.concurrent.CompletableFuture<java.lang.Void> thenRunAsync(java.lang.Runnable, java.util.concurrent.Executor);
    -@@ -59421,7 +59421,7 @@ package java.util.concurrent {
    -     ctor public CompletionException(java.lang.Throwable);
    -   }
    - 
    --  public abstract interface CompletionService {
    -+  public abstract interface CompletionService<V> {
    -     method public abstract java.util.concurrent.Future<V> poll();
    -     method public abstract java.util.concurrent.Future<V> poll(long, java.util.concurrent.TimeUnit) throws java.lang.InterruptedException;
    -     method public abstract java.util.concurrent.Future<V> submit(java.util.concurrent.Callable<V>);
    -@@ -59429,17 +59429,17 @@ package java.util.concurrent {
    -     method public abstract java.util.concurrent.Future<V> take() throws java.lang.InterruptedException;
    -   }
    - 
    --  public abstract interface CompletionStage {
    -+  public abstract interface CompletionStage<T> {
    -     method public abstract java.util.concurrent.CompletionStage<java.lang.Void> acceptEither(java.util.concurrent.CompletionStage<? extends T>, java.util.function.Consumer<? super T>);
    -     method public abstract java.util.concurrent.CompletionStage<java.lang.Void> acceptEitherAsync(java.util.concurrent.CompletionStage<? extends T>, java.util.function.Consumer<? super T>);
    -     method public abstract java.util.concurrent.CompletionStage<java.lang.Void> acceptEitherAsync(java.util.concurrent.CompletionStage<? extends T>, java.util.function.Consumer<? super T>, java.util.concurrent.Executor);
    --    method public abstract java.util.concurrent.CompletionStage<U> applyToEither(java.util.concurrent.CompletionStage<? extends T>, java.util.function.Function<? super T, U>);
    --    method public abstract java.util.concurrent.CompletionStage<U> applyToEitherAsync(java.util.concurrent.CompletionStage<? extends T>, java.util.function.Function<? super T, U>);
    --    method public abstract java.util.concurrent.CompletionStage<U> applyToEitherAsync(java.util.concurrent.CompletionStage<? extends T>, java.util.function.Function<? super T, U>, java.util.concurrent.Executor);
    -+    method public abstract <U> java.util.concurrent.CompletionStage<U> applyToEither(java.util.concurrent.CompletionStage<? extends T>, java.util.function.Function<? super T, U>);
    -+    method public abstract <U> java.util.concurrent.CompletionStage<U> applyToEitherAsync(java.util.concurrent.CompletionStage<? extends T>, java.util.function.Function<? super T, U>);
    -+    method public abstract <U> java.util.concurrent.CompletionStage<U> applyToEitherAsync(java.util.concurrent.CompletionStage<? extends T>, java.util.function.Function<? super T, U>, java.util.concurrent.Executor);
    -     method public abstract java.util.concurrent.CompletionStage<T> exceptionally(java.util.function.Function<java.lang.Throwable, ? extends T>);
    --    method public abstract java.util.concurrent.CompletionStage<U> handle(java.util.function.BiFunction<? super T, java.lang.Throwable, ? extends U>);
    --    method public abstract java.util.concurrent.CompletionStage<U> handleAsync(java.util.function.BiFunction<? super T, java.lang.Throwable, ? extends U>);
    --    method public abstract java.util.concurrent.CompletionStage<U> handleAsync(java.util.function.BiFunction<? super T, java.lang.Throwable, ? extends U>, java.util.concurrent.Executor);
    -+    method public abstract <U> java.util.concurrent.CompletionStage<U> handle(java.util.function.BiFunction<? super T, java.lang.Throwable, ? extends U>);
    -+    method public abstract <U> java.util.concurrent.CompletionStage<U> handleAsync(java.util.function.BiFunction<? super T, java.lang.Throwable, ? extends U>);
    -+    method public abstract <U> java.util.concurrent.CompletionStage<U> handleAsync(java.util.function.BiFunction<? super T, java.lang.Throwable, ? extends U>, java.util.concurrent.Executor);
    -     method public abstract java.util.concurrent.CompletionStage<java.lang.Void> runAfterBoth(java.util.concurrent.CompletionStage<?>, java.lang.Runnable);
    -     method public abstract java.util.concurrent.CompletionStage<java.lang.Void> runAfterBothAsync(java.util.concurrent.CompletionStage<?>, java.lang.Runnable);
    -     method public abstract java.util.concurrent.CompletionStage<java.lang.Void> runAfterBothAsync(java.util.concurrent.CompletionStage<?>, java.lang.Runnable, java.util.concurrent.Executor);
    -@@ -59449,18 +59449,18 @@ package java.util.concurrent {
    -     method public abstract java.util.concurrent.CompletionStage<java.lang.Void> thenAccept(java.util.function.Consumer<? super T>);
    -     method public abstract java.util.concurrent.CompletionStage<java.lang.Void> thenAcceptAsync(java.util.function.Consumer<? super T>);
    -     method public abstract java.util.concurrent.CompletionStage<java.lang.Void> thenAcceptAsync(java.util.function.Consumer<? super T>, java.util.concurrent.Executor);
    --    method public abstract java.util.concurrent.CompletionStage<java.lang.Void> thenAcceptBoth(java.util.concurrent.CompletionStage<? extends U>, java.util.function.BiConsumer<? super T, ? super U>);
    --    method public abstract java.util.concurrent.CompletionStage<java.lang.Void> thenAcceptBothAsync(java.util.concurrent.CompletionStage<? extends U>, java.util.function.BiConsumer<? super T, ? super U>);
    --    method public abstract java.util.concurrent.CompletionStage<java.lang.Void> thenAcceptBothAsync(java.util.concurrent.CompletionStage<? extends U>, java.util.function.BiConsumer<? super T, ? super U>, java.util.concurrent.Executor);
    --    method public abstract java.util.concurrent.CompletionStage<U> thenApply(java.util.function.Function<? super T, ? extends U>);
    --    method public abstract java.util.concurrent.CompletionStage<U> thenApplyAsync(java.util.function.Function<? super T, ? extends U>);
    --    method public abstract java.util.concurrent.CompletionStage<U> thenApplyAsync(java.util.function.Function<? super T, ? extends U>, java.util.concurrent.Executor);
    --    method public abstract java.util.concurrent.CompletionStage<V> thenCombine(java.util.concurrent.CompletionStage<? extends U>, java.util.function.BiFunction<? super T, ? super U, ? extends V>);
    --    method public abstract java.util.concurrent.CompletionStage<V> thenCombineAsync(java.util.concurrent.CompletionStage<? extends U>, java.util.function.BiFunction<? super T, ? super U, ? extends V>);
    --    method public abstract java.util.concurrent.CompletionStage<V> thenCombineAsync(java.util.concurrent.CompletionStage<? extends U>, java.util.function.BiFunction<? super T, ? super U, ? extends V>, java.util.concurrent.Executor);
    --    method public abstract java.util.concurrent.CompletionStage<U> thenCompose(java.util.function.Function<? super T, ? extends java.util.concurrent.CompletionStage<U>>);
    --    method public abstract java.util.concurrent.CompletionStage<U> thenComposeAsync(java.util.function.Function<? super T, ? extends java.util.concurrent.CompletionStage<U>>);
    --    method public abstract java.util.concurrent.CompletionStage<U> thenComposeAsync(java.util.function.Function<? super T, ? extends java.util.concurrent.CompletionStage<U>>, java.util.concurrent.Executor);
    -+    method public abstract <U> java.util.concurrent.CompletionStage<java.lang.Void> thenAcceptBoth(java.util.concurrent.CompletionStage<? extends U>, java.util.function.BiConsumer<? super T, ? super U>);
    -+    method public abstract <U> java.util.concurrent.CompletionStage<java.lang.Void> thenAcceptBothAsync(java.util.concurrent.CompletionStage<? extends U>, java.util.function.BiConsumer<? super T, ? super U>);
    -+    method public abstract <U> java.util.concurrent.CompletionStage<java.lang.Void> thenAcceptBothAsync(java.util.concurrent.CompletionStage<? extends U>, java.util.function.BiConsumer<? super T, ? super U>, java.util.concurrent.Executor);
    -+    method public abstract <U> java.util.concurrent.CompletionStage<U> thenApply(java.util.function.Function<? super T, ? extends U>);
    -+    method public abstract <U> java.util.concurrent.CompletionStage<U> thenApplyAsync(java.util.function.Function<? super T, ? extends U>);
    -+    method public abstract <U> java.util.concurrent.CompletionStage<U> thenApplyAsync(java.util.function.Function<? super T, ? extends U>, java.util.concurrent.Executor);
    -+    method public abstract <U, V> java.util.concurrent.CompletionStage<V> thenCombine(java.util.concurrent.CompletionStage<? extends U>, java.util.function.BiFunction<? super T, ? super U, ? extends V>);
    -+    method public abstract <U, V> java.util.concurrent.CompletionStage<V> thenCombineAsync(java.util.concurrent.CompletionStage<? extends U>, java.util.function.BiFunction<? super T, ? super U, ? extends V>);
    -+    method public abstract <U, V> java.util.concurrent.CompletionStage<V> thenCombineAsync(java.util.concurrent.CompletionStage<? extends U>, java.util.function.BiFunction<? super T, ? super U, ? extends V>, java.util.concurrent.Executor);
    -+    method public abstract <U> java.util.concurrent.CompletionStage<U> thenCompose(java.util.function.Function<? super T, ? extends java.util.concurrent.CompletionStage<U>>);
    -+    method public abstract <U> java.util.concurrent.CompletionStage<U> thenComposeAsync(java.util.function.Function<? super T, ? extends java.util.concurrent.CompletionStage<U>>);
    -+    method public abstract <U> java.util.concurrent.CompletionStage<U> thenComposeAsync(java.util.function.Function<? super T, ? extends java.util.concurrent.CompletionStage<U>>, java.util.concurrent.Executor);
    -     method public abstract java.util.concurrent.CompletionStage<java.lang.Void> thenRun(java.lang.Runnable);
    -     method public abstract java.util.concurrent.CompletionStage<java.lang.Void> thenRunAsync(java.lang.Runnable);
    -     method public abstract java.util.concurrent.CompletionStage<java.lang.Void> thenRunAsync(java.lang.Runnable, java.util.concurrent.Executor);
    -@@ -59470,7 +59470,7 @@ package java.util.concurrent {
    -     method public abstract java.util.concurrent.CompletionStage<T> whenCompleteAsync(java.util.function.BiConsumer<? super T, ? super java.lang.Throwable>, java.util.concurrent.Executor);
    -   }
    - 
    --  public class ConcurrentHashMap extends java.util.AbstractMap implements java.util.concurrent.ConcurrentMap java.io.Serializable {
    -+  public class ConcurrentHashMap<K, V> extends java.util.AbstractMap implements java.util.concurrent.ConcurrentMap java.io.Serializable {
    -     ctor public ConcurrentHashMap();
    -     ctor public ConcurrentHashMap(int);
    -     ctor public ConcurrentHashMap(java.util.Map<? extends K, ? extends V>);
    -@@ -59484,29 +59484,29 @@ package java.util.concurrent {
    -     method public java.util.Set<java.util.Map.Entry<K, V>> entrySet();
    -     method public void forEach(java.util.function.BiConsumer<? super K, ? super V>);
    -     method public void forEach(long, java.util.function.BiConsumer<? super K, ? super V>);
    --    method public void forEach(long, java.util.function.BiFunction<? super K, ? super V, ? extends U>, java.util.function.Consumer<? super U>);
    -+    method public <U> void forEach(long, java.util.function.BiFunction<? super K, ? super V, ? extends U>, java.util.function.Consumer<? super U>);
    -     method public void forEachEntry(long, java.util.function.Consumer<? super java.util.Map.Entry<K, V>>);
    --    method public void forEachEntry(long, java.util.function.Function<java.util.Map.Entry<K, V>, ? extends U>, java.util.function.Consumer<? super U>);
    -+    method public <U> void forEachEntry(long, java.util.function.Function<java.util.Map.Entry<K, V>, ? extends U>, java.util.function.Consumer<? super U>);
    -     method public void forEachKey(long, java.util.function.Consumer<? super K>);
    --    method public void forEachKey(long, java.util.function.Function<? super K, ? extends U>, java.util.function.Consumer<? super U>);
    -+    method public <U> void forEachKey(long, java.util.function.Function<? super K, ? extends U>, java.util.function.Consumer<? super U>);
    -     method public void forEachValue(long, java.util.function.Consumer<? super V>);
    --    method public void forEachValue(long, java.util.function.Function<? super V, ? extends U>, java.util.function.Consumer<? super U>);
    -+    method public <U> void forEachValue(long, java.util.function.Function<? super V, ? extends U>, java.util.function.Consumer<? super U>);
    -     method public V getOrDefault(java.lang.Object, V);
    -     method public java.util.concurrent.ConcurrentHashMap.KeySetView<K, V> keySet(V);
    -     method public java.util.Enumeration<K> keys();
    -     method public long mappingCount();
    -     method public V merge(K, V, java.util.function.BiFunction<? super V, ? super V, ? extends V>);
    --    method public static java.util.concurrent.ConcurrentHashMap.KeySetView<K, java.lang.Boolean> newKeySet();
    --    method public static java.util.concurrent.ConcurrentHashMap.KeySetView<K, java.lang.Boolean> newKeySet(int);
    -+    method public static <K> java.util.concurrent.ConcurrentHashMap.KeySetView<K, java.lang.Boolean> newKeySet();
    -+    method public static <K> java.util.concurrent.ConcurrentHashMap.KeySetView<K, java.lang.Boolean> newKeySet(int);
    -     method public V putIfAbsent(K, V);
    --    method public U reduce(long, java.util.function.BiFunction<? super K, ? super V, ? extends U>, java.util.function.BiFunction<? super U, ? super U, ? extends U>);
    -+    method public <U> U reduce(long, java.util.function.BiFunction<? super K, ? super V, ? extends U>, java.util.function.BiFunction<? super U, ? super U, ? extends U>);
    -     method public java.util.Map.Entry<K, V> reduceEntries(long, java.util.function.BiFunction<java.util.Map.Entry<K, V>, java.util.Map.Entry<K, V>, ? extends java.util.Map.Entry<K, V>>);
    --    method public U reduceEntries(long, java.util.function.Function<java.util.Map.Entry<K, V>, ? extends U>, java.util.function.BiFunction<? super U, ? super U, ? extends U>);
    -+    method public <U> U reduceEntries(long, java.util.function.Function<java.util.Map.Entry<K, V>, ? extends U>, java.util.function.BiFunction<? super U, ? super U, ? extends U>);
    -     method public double reduceEntriesToDouble(long, java.util.function.ToDoubleFunction<java.util.Map.Entry<K, V>>, double, java.util.function.DoubleBinaryOperator);
    -     method public int reduceEntriesToInt(long, java.util.function.ToIntFunction<java.util.Map.Entry<K, V>>, int, java.util.function.IntBinaryOperator);
    -     method public long reduceEntriesToLong(long, java.util.function.ToLongFunction<java.util.Map.Entry<K, V>>, long, java.util.function.LongBinaryOperator);
    -     method public K reduceKeys(long, java.util.function.BiFunction<? super K, ? super K, ? extends K>);
    --    method public U reduceKeys(long, java.util.function.Function<? super K, ? extends U>, java.util.function.BiFunction<? super U, ? super U, ? extends U>);
    -+    method public <U> U reduceKeys(long, java.util.function.Function<? super K, ? extends U>, java.util.function.BiFunction<? super U, ? super U, ? extends U>);
    -     method public double reduceKeysToDouble(long, java.util.function.ToDoubleFunction<? super K>, double, java.util.function.DoubleBinaryOperator);
    -     method public int reduceKeysToInt(long, java.util.function.ToIntFunction<? super K>, int, java.util.function.IntBinaryOperator);
    -     method public long reduceKeysToLong(long, java.util.function.ToLongFunction<? super K>, long, java.util.function.LongBinaryOperator);
    -@@ -59514,7 +59514,7 @@ package java.util.concurrent {
    -     method public int reduceToInt(long, java.util.function.ToIntBiFunction<? super K, ? super V>, int, java.util.function.IntBinaryOperator);
    -     method public long reduceToLong(long, java.util.function.ToLongBiFunction<? super K, ? super V>, long, java.util.function.LongBinaryOperator);
    -     method public V reduceValues(long, java.util.function.BiFunction<? super V, ? super V, ? extends V>);
    --    method public U reduceValues(long, java.util.function.Function<? super V, ? extends U>, java.util.function.BiFunction<? super U, ? super U, ? extends U>);
    -+    method public <U> U reduceValues(long, java.util.function.Function<? super V, ? extends U>, java.util.function.BiFunction<? super U, ? super U, ? extends U>);
    -     method public double reduceValuesToDouble(long, java.util.function.ToDoubleFunction<? super V>, double, java.util.function.DoubleBinaryOperator);
    -     method public int reduceValuesToInt(long, java.util.function.ToIntFunction<? super V>, int, java.util.function.IntBinaryOperator);
    -     method public long reduceValuesToLong(long, java.util.function.ToLongFunction<? super V>, long, java.util.function.LongBinaryOperator);
    -@@ -59522,13 +59522,13 @@ package java.util.concurrent {
    -     method public boolean replace(K, V, V);
    -     method public V replace(K, V);
    -     method public void replaceAll(java.util.function.BiFunction<? super K, ? super V, ? extends V>);
    --    method public U search(long, java.util.function.BiFunction<? super K, ? super V, ? extends U>);
    --    method public U searchEntries(long, java.util.function.Function<java.util.Map.Entry<K, V>, ? extends U>);
    --    method public U searchKeys(long, java.util.function.Function<? super K, ? extends U>);
    --    method public U searchValues(long, java.util.function.Function<? super V, ? extends U>);
    -+    method public <U> U search(long, java.util.function.BiFunction<? super K, ? super V, ? extends U>);
    -+    method public <U> U searchEntries(long, java.util.function.Function<java.util.Map.Entry<K, V>, ? extends U>);
    -+    method public <U> U searchKeys(long, java.util.function.Function<? super K, ? extends U>);
    -+    method public <U> U searchValues(long, java.util.function.Function<? super V, ? extends U>);
    -   }
    - 
    --   static abstract class ConcurrentHashMap.CollectionView implements java.util.Collection java.io.Serializable {
    -+   static abstract class ConcurrentHashMap.CollectionView<K, V, E> implements java.util.Collection java.io.Serializable {
    -     method public final void clear();
    -     method public abstract boolean contains(java.lang.Object);
    -     method public final boolean containsAll(java.util.Collection<?>);
    -@@ -59540,11 +59540,11 @@ package java.util.concurrent {
    -     method public final boolean retainAll(java.util.Collection<?>);
    -     method public final int size();
    -     method public final java.lang.Object[] toArray();
    --    method public final T[] toArray(T[]);
    -+    method public final <T> T[] toArray(T[]);
    -     method public final java.lang.String toString();
    -   }
    - 
    --  public static class ConcurrentHashMap.KeySetView extends java.util.concurrent.ConcurrentHashMap.CollectionView implements java.io.Serializable java.util.Set {
    -+  public static class ConcurrentHashMap.KeySetView<K, V> extends java.util.concurrent.ConcurrentHashMap.CollectionView implements java.io.Serializable java.util.Set {
    -     method public boolean add(K);
    -     method public boolean addAll(java.util.Collection<? extends K>);
    -     method public boolean contains(java.lang.Object);
    -@@ -59555,7 +59555,7 @@ package java.util.concurrent {
    -     method public java.util.Spliterator<K> spliterator();
    -   }
    - 
    --  public class ConcurrentLinkedDeque extends java.util.AbstractCollection implements java.util.Deque java.io.Serializable {
    -+  public class ConcurrentLinkedDeque<E> extends java.util.AbstractCollection implements java.util.Deque java.io.Serializable {
    -     ctor public ConcurrentLinkedDeque();
    -     ctor public ConcurrentLinkedDeque(java.util.Collection<? extends E>);
    -     method public void addFirst(E);
    -@@ -59585,7 +59585,7 @@ package java.util.concurrent {
    -     method public java.util.Spliterator<E> spliterator();
    -   }
    - 
    --  public class ConcurrentLinkedQueue extends java.util.AbstractQueue implements java.util.Queue java.io.Serializable {
    -+  public class ConcurrentLinkedQueue<E> extends java.util.AbstractQueue implements java.util.Queue java.io.Serializable {
    -     ctor public ConcurrentLinkedQueue();
    -     ctor public ConcurrentLinkedQueue(java.util.Collection<? extends E>);
    -     method public java.util.Iterator<E> iterator();
    -@@ -59596,14 +59596,14 @@ package java.util.concurrent {
    -     method public java.util.Spliterator<E> spliterator();
    -   }
    - 
    --  public abstract interface ConcurrentMap implements java.util.Map {
    -+  public abstract interface ConcurrentMap<K, V> implements java.util.Map {
    -     method public abstract V putIfAbsent(K, V);
    -     method public abstract boolean remove(java.lang.Object, java.lang.Object);
    -     method public abstract boolean replace(K, V, V);
    -     method public abstract V replace(K, V);
    -   }
    - 
    --  public abstract interface ConcurrentNavigableMap implements java.util.concurrent.ConcurrentMap java.util.NavigableMap {
    -+  public abstract interface ConcurrentNavigableMap<K, V> implements java.util.concurrent.ConcurrentMap java.util.NavigableMap {
    -     method public abstract java.util.NavigableSet<K> descendingKeySet();
    -     method public abstract java.util.concurrent.ConcurrentNavigableMap<K, V> descendingMap();
    -     method public abstract java.util.concurrent.ConcurrentNavigableMap<K, V> headMap(K, boolean);
    -@@ -59616,7 +59616,7 @@ package java.util.concurrent {
    -     method public abstract java.util.concurrent.ConcurrentNavigableMap<K, V> tailMap(K);
    -   }
    - 
    --  public class ConcurrentSkipListMap extends java.util.AbstractMap implements java.lang.Cloneable java.util.concurrent.ConcurrentNavigableMap java.io.Serializable {
    -+  public class ConcurrentSkipListMap<K, V> extends java.util.AbstractMap implements java.lang.Cloneable java.util.concurrent.ConcurrentNavigableMap java.io.Serializable {
    -     ctor public ConcurrentSkipListMap();
    -     ctor public ConcurrentSkipListMap(java.util.Comparator<? super K>);
    -     ctor public ConcurrentSkipListMap(java.util.Map<? extends K, ? extends V>);
    -@@ -59660,7 +59660,7 @@ package java.util.concurrent {
    -     method public java.util.concurrent.ConcurrentNavigableMap<K, V> tailMap(K);
    -   }
    - 
    --  public class ConcurrentSkipListSet extends java.util.AbstractSet implements java.lang.Cloneable java.util.NavigableSet java.io.Serializable {
    -+  public class ConcurrentSkipListSet<E> extends java.util.AbstractSet implements java.lang.Cloneable java.util.NavigableSet java.io.Serializable {
    -     ctor public ConcurrentSkipListSet();
    -     ctor public ConcurrentSkipListSet(java.util.Comparator<? super E>);
    -     ctor public ConcurrentSkipListSet(java.util.Collection<? extends E>);
    -@@ -59688,7 +59688,7 @@ package java.util.concurrent {
    -     method public java.util.NavigableSet<E> tailSet(E);
    -   }
    - 
    --  public class CopyOnWriteArrayList implements java.lang.Cloneable java.util.List java.util.RandomAccess java.io.Serializable {
    -+  public class CopyOnWriteArrayList<E> implements java.lang.Cloneable java.util.List java.util.RandomAccess java.io.Serializable {
    -     ctor public CopyOnWriteArrayList();
    -     ctor public CopyOnWriteArrayList(java.util.Collection<? extends E>);
    -     ctor public CopyOnWriteArrayList(E[]);
    -@@ -59720,10 +59720,10 @@ package java.util.concurrent {
    -     method public int size();
    -     method public java.util.List<E> subList(int, int);
    -     method public java.lang.Object[] toArray();
    --    method public T[] toArray(T[]);
    -+    method public <T> T[] toArray(T[]);
    -   }
    - 
    --  public class CopyOnWriteArraySet extends java.util.AbstractSet implements java.io.Serializable {
    -+  public class CopyOnWriteArraySet<E> extends java.util.AbstractSet implements java.io.Serializable {
    -     ctor public CopyOnWriteArraySet();
    -     ctor public CopyOnWriteArraySet(java.util.Collection<? extends E>);
    -     method public void forEach(java.util.function.Consumer<? super E>);
    -@@ -59741,7 +59741,7 @@ package java.util.concurrent {
    -     method public long getCount();
    -   }
    - 
    --  public abstract class CountedCompleter extends java.util.concurrent.ForkJoinTask {
    -+  public abstract class CountedCompleter<T> extends java.util.concurrent.ForkJoinTask {
    -     ctor protected CountedCompleter(java.util.concurrent.CountedCompleter<?>, int);
    -     ctor protected CountedCompleter(java.util.concurrent.CountedCompleter<?>);
    -     ctor protected CountedCompleter();
    -@@ -59778,7 +59778,7 @@ package java.util.concurrent {
    -     method public void reset();
    -   }
    - 
    --  public class DelayQueue extends java.util.AbstractQueue implements java.util.concurrent.BlockingQueue {
    -+  public class DelayQueue<E extends java.util.concurrent.Delayed> extends java.util.AbstractQueue implements java.util.concurrent.BlockingQueue {
    -     ctor public DelayQueue();
    -     ctor public DelayQueue(java.util.Collection<? extends E>);
    -     method public int drainTo(java.util.Collection<? super E>);
    -@@ -59799,7 +59799,7 @@ package java.util.concurrent {
    -     method public abstract long getDelay(java.util.concurrent.TimeUnit);
    -   }
    - 
    --  public class Exchanger {
    -+  public class Exchanger<V> {
    -     ctor public Exchanger();
    -     method public V exchange(V) throws java.lang.InterruptedException;
    -     method public V exchange(V, long, java.util.concurrent.TimeUnit) throws java.lang.InterruptedException, java.util.concurrent.TimeoutException;
    -@@ -59816,7 +59816,7 @@ package java.util.concurrent {
    -     method public abstract void execute(java.lang.Runnable);
    -   }
    - 
    --  public class ExecutorCompletionService implements java.util.concurrent.CompletionService {
    -+  public class ExecutorCompletionService<V> implements java.util.concurrent.CompletionService {
    -     ctor public ExecutorCompletionService(java.util.concurrent.Executor);
    -     ctor public ExecutorCompletionService(java.util.concurrent.Executor, java.util.concurrent.BlockingQueue<java.util.concurrent.Future<V>>);
    -     method public java.util.concurrent.Future<V> poll();
    -@@ -59828,21 +59828,21 @@ package java.util.concurrent {
    - 
    -   public abstract interface ExecutorService implements java.util.concurrent.Executor {
    -     method public abstract boolean awaitTermination(long, java.util.concurrent.TimeUnit) throws java.lang.InterruptedException;
    --    method public abstract java.util.List<java.util.concurrent.Future<T>> invokeAll(java.util.Collection<? extends java.util.concurrent.Callable<T>>) throws java.lang.InterruptedException;
    --    method public abstract java.util.List<java.util.concurrent.Future<T>> invokeAll(java.util.Collection<? extends java.util.concurrent.Callable<T>>, long, java.util.concurrent.TimeUnit) throws java.lang.InterruptedException;
    --    method public abstract T invokeAny(java.util.Collection<? extends java.util.concurrent.Callable<T>>) throws java.util.concurrent.ExecutionException, java.lang.InterruptedException;
    --    method public abstract T invokeAny(java.util.Collection<? extends java.util.concurrent.Callable<T>>, long, java.util.concurrent.TimeUnit) throws java.util.concurrent.ExecutionException, java.lang.InterruptedException, java.util.concurrent.TimeoutException;
    -+    method public abstract <T> java.util.List<java.util.concurrent.Future<T>> invokeAll(java.util.Collection<? extends java.util.concurrent.Callable<T>>) throws java.lang.InterruptedException;
    -+    method public abstract <T> java.util.List<java.util.concurrent.Future<T>> invokeAll(java.util.Collection<? extends java.util.concurrent.Callable<T>>, long, java.util.concurrent.TimeUnit) throws java.lang.InterruptedException;
    -+    method public abstract <T> T invokeAny(java.util.Collection<? extends java.util.concurrent.Callable<T>>) throws java.util.concurrent.ExecutionException, java.lang.InterruptedException;
    -+    method public abstract <T> T invokeAny(java.util.Collection<? extends java.util.concurrent.Callable<T>>, long, java.util.concurrent.TimeUnit) throws java.util.concurrent.ExecutionException, java.lang.InterruptedException, java.util.concurrent.TimeoutException;
    -     method public abstract boolean isShutdown();
    -     method public abstract boolean isTerminated();
    -     method public abstract void shutdown();
    -     method public abstract java.util.List<java.lang.Runnable> shutdownNow();
    --    method public abstract java.util.concurrent.Future<T> submit(java.util.concurrent.Callable<T>);
    --    method public abstract java.util.concurrent.Future<T> submit(java.lang.Runnable, T);
    -+    method public abstract <T> java.util.concurrent.Future<T> submit(java.util.concurrent.Callable<T>);
    -+    method public abstract <T> java.util.concurrent.Future<T> submit(java.lang.Runnable, T);
    -     method public abstract java.util.concurrent.Future<?> submit(java.lang.Runnable);
    -   }
    - 
    -   public class Executors {
    --    method public static java.util.concurrent.Callable<T> callable(java.lang.Runnable, T);
    -+    method public static <T> java.util.concurrent.Callable<T> callable(java.lang.Runnable, T);
    -     method public static java.util.concurrent.Callable<java.lang.Object> callable(java.lang.Runnable);
    -     method public static java.util.concurrent.Callable<java.lang.Object> callable(java.security.PrivilegedAction<?>);
    -     method public static java.util.concurrent.Callable<java.lang.Object> callable(java.security.PrivilegedExceptionAction<?>);
    -@@ -59859,8 +59859,8 @@ package java.util.concurrent {
    -     method public static java.util.concurrent.ScheduledExecutorService newSingleThreadScheduledExecutor(java.util.concurrent.ThreadFactory);
    -     method public static java.util.concurrent.ExecutorService newWorkStealingPool(int);
    -     method public static java.util.concurrent.ExecutorService newWorkStealingPool();
    --    method public static java.util.concurrent.Callable<T> privilegedCallable(java.util.concurrent.Callable<T>);
    --    method public static java.util.concurrent.Callable<T> privilegedCallableUsingCurrentClassLoader(java.util.concurrent.Callable<T>);
    -+    method public static <T> java.util.concurrent.Callable<T> privilegedCallable(java.util.concurrent.Callable<T>);
    -+    method public static <T> java.util.concurrent.Callable<T> privilegedCallableUsingCurrentClassLoader(java.util.concurrent.Callable<T>);
    -     method public static java.util.concurrent.ThreadFactory privilegedThreadFactory();
    -     method public static java.util.concurrent.ExecutorService unconfigurableExecutorService(java.util.concurrent.ExecutorService);
    -     method public static java.util.concurrent.ScheduledExecutorService unconfigurableScheduledExecutorService(java.util.concurrent.ScheduledExecutorService);
    -@@ -59888,7 +59888,7 @@ package java.util.concurrent {
    -     method public long getStealCount();
    -     method public java.lang.Thread.UncaughtExceptionHandler getUncaughtExceptionHandler();
    -     method public boolean hasQueuedSubmissions();
    --    method public T invoke(java.util.concurrent.ForkJoinTask<T>);
    -+    method public <T> T invoke(java.util.concurrent.ForkJoinTask<T>);
    -     method public boolean isQuiescent();
    -     method public boolean isShutdown();
    -     method public boolean isTerminated();
    -@@ -59897,7 +59897,7 @@ package java.util.concurrent {
    -     method protected java.util.concurrent.ForkJoinTask<?> pollSubmission();
    -     method public void shutdown();
    -     method public java.util.List<java.lang.Runnable> shutdownNow();
    --    method public java.util.concurrent.ForkJoinTask<T> submit(java.util.concurrent.ForkJoinTask<T>);
    -+    method public <T> java.util.concurrent.ForkJoinTask<T> submit(java.util.concurrent.ForkJoinTask<T>);
    -     field public static final java.util.concurrent.ForkJoinPool.ForkJoinWorkerThreadFactory defaultForkJoinWorkerThreadFactory;
    -   }
    - 
    -@@ -59910,11 +59910,11 @@ package java.util.concurrent {
    -     method public abstract boolean isReleasable();
    -   }
    - 
    --  public abstract class ForkJoinTask implements java.util.concurrent.Future java.io.Serializable {
    -+  public abstract class ForkJoinTask<V> implements java.util.concurrent.Future java.io.Serializable {
    -     ctor public ForkJoinTask();
    -     method public static java.util.concurrent.ForkJoinTask<?> adapt(java.lang.Runnable);
    --    method public static java.util.concurrent.ForkJoinTask<T> adapt(java.lang.Runnable, T);
    --    method public static java.util.concurrent.ForkJoinTask<T> adapt(java.util.concurrent.Callable<? extends T>);
    -+    method public static <T> java.util.concurrent.ForkJoinTask<T> adapt(java.lang.Runnable, T);
    -+    method public static <T> java.util.concurrent.ForkJoinTask<T> adapt(java.util.concurrent.Callable<? extends T>);
    -     method public boolean cancel(boolean);
    -     method public final boolean compareAndSetForkJoinTaskTag(short, short);
    -     method public void complete(V);
    -@@ -59934,7 +59934,7 @@ package java.util.concurrent {
    -     method public final V invoke();
    -     method public static void invokeAll(java.util.concurrent.ForkJoinTask<?>, java.util.concurrent.ForkJoinTask<?>);
    -     method public static void invokeAll(java.util.concurrent.ForkJoinTask<?>...);
    --    method public static java.util.Collection<T> invokeAll(java.util.Collection<T>);
    -+    method public static <T extends java.util.concurrent.ForkJoinTask<?>> java.util.Collection<T> invokeAll(java.util.Collection<T>);
    -     method public final boolean isCancelled();
    -     method public final boolean isCompletedAbnormally();
    -     method public final boolean isCompletedNormally();
    -@@ -59960,7 +59960,7 @@ package java.util.concurrent {
    -     method protected void onTermination(java.lang.Throwable);
    -   }
    - 
    --  public abstract interface Future {
    -+  public abstract interface Future<V> {
    -     method public abstract boolean cancel(boolean);
    -     method public abstract V get() throws java.util.concurrent.ExecutionException, java.lang.InterruptedException;
    -     method public abstract V get(long, java.util.concurrent.TimeUnit) throws java.util.concurrent.ExecutionException, java.lang.InterruptedException, java.util.concurrent.TimeoutException;
    -@@ -59968,7 +59968,7 @@ package java.util.concurrent {
    -     method public abstract boolean isDone();
    -   }
    - 
    --  public class FutureTask implements java.util.concurrent.RunnableFuture {
    -+  public class FutureTask<V> implements java.util.concurrent.RunnableFuture {
    -     ctor public FutureTask(java.util.concurrent.Callable<V>);
    -     ctor public FutureTask(java.lang.Runnable, V);
    -     method public boolean cancel(boolean);
    -@@ -59983,7 +59983,7 @@ package java.util.concurrent {
    -     method protected void setException(java.lang.Throwable);
    -   }
    - 
    --  public class LinkedBlockingDeque extends java.util.AbstractQueue implements java.util.concurrent.BlockingDeque java.io.Serializable {
    -+  public class LinkedBlockingDeque<E> extends java.util.AbstractQueue implements java.util.concurrent.BlockingDeque java.io.Serializable {
    -     ctor public LinkedBlockingDeque();
    -     ctor public LinkedBlockingDeque(int);
    -     ctor public LinkedBlockingDeque(java.util.Collection<? extends E>);
    -@@ -60027,7 +60027,7 @@ package java.util.concurrent {
    -     method public E takeLast() throws java.lang.InterruptedException;
    -   }
    - 
    --  public class LinkedBlockingQueue extends java.util.AbstractQueue implements java.util.concurrent.BlockingQueue java.io.Serializable {
    -+  public class LinkedBlockingQueue<E> extends java.util.AbstractQueue implements java.util.concurrent.BlockingQueue java.io.Serializable {
    -     ctor public LinkedBlockingQueue();
    -     ctor public LinkedBlockingQueue(int);
    -     ctor public LinkedBlockingQueue(java.util.Collection<? extends E>);
    -@@ -60046,7 +60046,7 @@ package java.util.concurrent {
    -     method public E take() throws java.lang.InterruptedException;
    -   }
    - 
    --  public class LinkedTransferQueue extends java.util.AbstractQueue implements java.io.Serializable java.util.concurrent.TransferQueue {
    -+  public class LinkedTransferQueue<E> extends java.util.AbstractQueue implements java.io.Serializable java.util.concurrent.TransferQueue {
    -     ctor public LinkedTransferQueue();
    -     ctor public LinkedTransferQueue(java.util.Collection<? extends E>);
    -     method public int drainTo(java.util.Collection<? super E>);
    -@@ -60093,7 +60093,7 @@ package java.util.concurrent {
    -     method public int register();
    -   }
    - 
    --  public class PriorityBlockingQueue extends java.util.AbstractQueue implements java.util.concurrent.BlockingQueue java.io.Serializable {
    -+  public class PriorityBlockingQueue<E> extends java.util.AbstractQueue implements java.util.concurrent.BlockingQueue java.io.Serializable {
    -     ctor public PriorityBlockingQueue();
    -     ctor public PriorityBlockingQueue(int);
    -     ctor public PriorityBlockingQueue(int, java.util.Comparator<? super E>);
    -@@ -60122,7 +60122,7 @@ package java.util.concurrent {
    -     method protected final void setRawResult(java.lang.Void);
    -   }
    - 
    --  public abstract class RecursiveTask extends java.util.concurrent.ForkJoinTask {
    -+  public abstract class RecursiveTask<V> extends java.util.concurrent.ForkJoinTask {
    -     ctor public RecursiveTask();
    -     method protected abstract V compute();
    -     method protected final boolean exec();
    -@@ -60141,22 +60141,22 @@ package java.util.concurrent {
    -     method public abstract void rejectedExecution(java.lang.Runnable, java.util.concurrent.ThreadPoolExecutor);
    -   }
    - 
    --  public abstract interface RunnableFuture implements java.util.concurrent.Future java.lang.Runnable {
    -+  public abstract interface RunnableFuture<V> implements java.util.concurrent.Future java.lang.Runnable {
    -     method public abstract void run();
    -   }
    - 
    --  public abstract interface RunnableScheduledFuture implements java.util.concurrent.RunnableFuture java.util.concurrent.ScheduledFuture {
    -+  public abstract interface RunnableScheduledFuture<V> implements java.util.concurrent.RunnableFuture java.util.concurrent.ScheduledFuture {
    -     method public abstract boolean isPeriodic();
    -   }
    - 
    -   public abstract interface ScheduledExecutorService implements java.util.concurrent.ExecutorService {
    -     method public abstract java.util.concurrent.ScheduledFuture<?> schedule(java.lang.Runnable, long, java.util.concurrent.TimeUnit);
    --    method public abstract java.util.concurrent.ScheduledFuture<V> schedule(java.util.concurrent.Callable<V>, long, java.util.concurrent.TimeUnit);
    -+    method public abstract <V> java.util.concurrent.ScheduledFuture<V> schedule(java.util.concurrent.Callable<V>, long, java.util.concurrent.TimeUnit);
    -     method public abstract java.util.concurrent.ScheduledFuture<?> scheduleAtFixedRate(java.lang.Runnable, long, long, java.util.concurrent.TimeUnit);
    -     method public abstract java.util.concurrent.ScheduledFuture<?> scheduleWithFixedDelay(java.lang.Runnable, long, long, java.util.concurrent.TimeUnit);
    -   }
    - 
    --  public abstract interface ScheduledFuture implements java.util.concurrent.Delayed java.util.concurrent.Future {
    -+  public abstract interface ScheduledFuture<V> implements java.util.concurrent.Delayed java.util.concurrent.Future {
    -   }
    - 
    -   public class ScheduledThreadPoolExecutor extends java.util.concurrent.ThreadPoolExecutor implements java.util.concurrent.ScheduledExecutorService {
    -@@ -60164,13 +60164,13 @@ package java.util.concurrent {
    -     ctor public ScheduledThreadPoolExecutor(int, java.util.concurrent.ThreadFactory);
    -     ctor public ScheduledThreadPoolExecutor(int, java.util.concurrent.RejectedExecutionHandler);
    -     ctor public ScheduledThreadPoolExecutor(int, java.util.concurrent.ThreadFactory, java.util.concurrent.RejectedExecutionHandler);
    --    method protected java.util.concurrent.RunnableScheduledFuture<V> decorateTask(java.lang.Runnable, java.util.concurrent.RunnableScheduledFuture<V>);
    --    method protected java.util.concurrent.RunnableScheduledFuture<V> decorateTask(java.util.concurrent.Callable<V>, java.util.concurrent.RunnableScheduledFuture<V>);
    -+    method protected <V> java.util.concurrent.RunnableScheduledFuture<V> decorateTask(java.lang.Runnable, java.util.concurrent.RunnableScheduledFuture<V>);
    -+    method protected <V> java.util.concurrent.RunnableScheduledFuture<V> decorateTask(java.util.concurrent.Callable<V>, java.util.concurrent.RunnableScheduledFuture<V>);
    -     method public boolean getContinueExistingPeriodicTasksAfterShutdownPolicy();
    -     method public boolean getExecuteExistingDelayedTasksAfterShutdownPolicy();
    -     method public boolean getRemoveOnCancelPolicy();
    -     method public java.util.concurrent.ScheduledFuture<?> schedule(java.lang.Runnable, long, java.util.concurrent.TimeUnit);
    --    method public java.util.concurrent.ScheduledFuture<V> schedule(java.util.concurrent.Callable<V>, long, java.util.concurrent.TimeUnit);
    -+    method public <V> java.util.concurrent.ScheduledFuture<V> schedule(java.util.concurrent.Callable<V>, long, java.util.concurrent.TimeUnit);
    -     method public java.util.concurrent.ScheduledFuture<?> scheduleAtFixedRate(java.lang.Runnable, long, long, java.util.concurrent.TimeUnit);
    -     method public java.util.concurrent.ScheduledFuture<?> scheduleWithFixedDelay(java.lang.Runnable, long, long, java.util.concurrent.TimeUnit);
    -     method public void setContinueExistingPeriodicTasksAfterShutdownPolicy(boolean);
    -@@ -60200,7 +60200,7 @@ package java.util.concurrent {
    -     method public boolean tryAcquire(int, long, java.util.concurrent.TimeUnit) throws java.lang.InterruptedException;
    -   }
    - 
    --  public class SynchronousQueue extends java.util.AbstractQueue implements java.util.concurrent.BlockingQueue java.io.Serializable {
    -+  public class SynchronousQueue<E> extends java.util.AbstractQueue implements java.util.concurrent.BlockingQueue java.io.Serializable {
    -     ctor public SynchronousQueue();
    -     ctor public SynchronousQueue(boolean);
    -     method public int drainTo(java.util.Collection<? super E>);
    -@@ -60318,7 +60318,7 @@ package java.util.concurrent {
    -     ctor public TimeoutException(java.lang.String);
    -   }
    - 
    --  public abstract interface TransferQueue implements java.util.concurrent.BlockingQueue {
    -+  public abstract interface TransferQueue<E> implements java.util.concurrent.BlockingQueue {
    -     method public abstract int getWaitingConsumerCount();
    -     method public abstract boolean hasWaitingConsumer();
    -     method public abstract void transfer(E) throws java.lang.InterruptedException;
    -@@ -60388,7 +60388,7 @@ package java.util.concurrent.atomic {
    -     method public final boolean weakCompareAndSet(int, int, int);
    -   }
    - 
    --  public abstract class AtomicIntegerFieldUpdater {
    -+  public abstract class AtomicIntegerFieldUpdater<T> {
    -     ctor protected AtomicIntegerFieldUpdater();
    -     method public final int accumulateAndGet(T, int, java.util.function.IntBinaryOperator);
    -     method public int addAndGet(T, int);
    -@@ -60403,7 +60403,7 @@ package java.util.concurrent.atomic {
    -     method public final int getAndUpdate(T, java.util.function.IntUnaryOperator);
    -     method public int incrementAndGet(T);
    -     method public abstract void lazySet(T, int);
    --    method public static java.util.concurrent.atomic.AtomicIntegerFieldUpdater<U> newUpdater(java.lang.Class<U>, java.lang.String);
    -+    method public static <U> java.util.concurrent.atomic.AtomicIntegerFieldUpdater<U> newUpdater(java.lang.Class<U>, java.lang.String);
    -     method public abstract void set(T, int);
    -     method public final int updateAndGet(T, java.util.function.IntUnaryOperator);
    -     method public abstract boolean weakCompareAndSet(T, int, int);
    -@@ -60456,7 +60456,7 @@ package java.util.concurrent.atomic {
    -     method public final boolean weakCompareAndSet(int, long, long);
    -   }
    - 
    --  public abstract class AtomicLongFieldUpdater {
    -+  public abstract class AtomicLongFieldUpdater<T> {
    -     ctor protected AtomicLongFieldUpdater();
    -     method public final long accumulateAndGet(T, long, java.util.function.LongBinaryOperator);
    -     method public long addAndGet(T, long);
    -@@ -60471,13 +60471,13 @@ package java.util.concurrent.atomic {
    -     method public final long getAndUpdate(T, java.util.function.LongUnaryOperator);
    -     method public long incrementAndGet(T);
    -     method public abstract void lazySet(T, long);
    --    method public static java.util.concurrent.atomic.AtomicLongFieldUpdater<U> newUpdater(java.lang.Class<U>, java.lang.String);
    -+    method public static <U> java.util.concurrent.atomic.AtomicLongFieldUpdater<U> newUpdater(java.lang.Class<U>, java.lang.String);
    -     method public abstract void set(T, long);
    -     method public final long updateAndGet(T, java.util.function.LongUnaryOperator);
    -     method public abstract boolean weakCompareAndSet(T, long, long);
    -   }
    - 
    --  public class AtomicMarkableReference {
    -+  public class AtomicMarkableReference<V> {
    -     ctor public AtomicMarkableReference(V, boolean);
    -     method public boolean attemptMark(V, boolean);
    -     method public boolean compareAndSet(V, V, boolean, boolean);
    -@@ -60488,7 +60488,7 @@ package java.util.concurrent.atomic {
    -     method public boolean weakCompareAndSet(V, V, boolean, boolean);
    -   }
    - 
    --  public class AtomicReference implements java.io.Serializable {
    -+  public class AtomicReference<V> implements java.io.Serializable {
    -     ctor public AtomicReference(V);
    -     ctor public AtomicReference();
    -     method public final V accumulateAndGet(V, java.util.function.BinaryOperator<V>);
    -@@ -60503,7 +60503,7 @@ package java.util.concurrent.atomic {
    -     method public final boolean weakCompareAndSet(V, V);
    -   }
    - 
    --  public class AtomicReferenceArray implements java.io.Serializable {
    -+  public class AtomicReferenceArray<E> implements java.io.Serializable {
    -     ctor public AtomicReferenceArray(int);
    -     ctor public AtomicReferenceArray(E[]);
    -     method public final E accumulateAndGet(int, E, java.util.function.BinaryOperator<E>);
    -@@ -60519,7 +60519,7 @@ package java.util.concurrent.atomic {
    -     method public final boolean weakCompareAndSet(int, E, E);
    -   }
    - 
    --  public abstract class AtomicReferenceFieldUpdater {
    -+  public abstract class AtomicReferenceFieldUpdater<T, V> {
    -     ctor protected AtomicReferenceFieldUpdater();
    -     method public final V accumulateAndGet(T, V, java.util.function.BinaryOperator<V>);
    -     method public abstract boolean compareAndSet(T, V, V);
    -@@ -60528,13 +60528,13 @@ package java.util.concurrent.atomic {
    -     method public V getAndSet(T, V);
    -     method public final V getAndUpdate(T, java.util.function.UnaryOperator<V>);
    -     method public abstract void lazySet(T, V);
    --    method public static java.util.concurrent.atomic.AtomicReferenceFieldUpdater<U, W> newUpdater(java.lang.Class<U>, java.lang.Class<W>, java.lang.String);
    -+    method public static <U, W> java.util.concurrent.atomic.AtomicReferenceFieldUpdater<U, W> newUpdater(java.lang.Class<U>, java.lang.Class<W>, java.lang.String);
    -     method public abstract void set(T, V);
    -     method public final V updateAndGet(T, java.util.function.UnaryOperator<V>);
    -     method public abstract boolean weakCompareAndSet(T, V, V);
    -   }
    - 
    --  public class AtomicStampedReference {
    -+  public class AtomicStampedReference<V> {
    -     ctor public AtomicStampedReference(V, int);
    -     method public boolean attemptStamp(V, int);
    -     method public boolean compareAndSet(V, V, int, int);
    -@@ -60837,33 +60837,33 @@ package java.util.concurrent.locks {
    - 
    - package java.util.function {
    - 
    --  public abstract interface BiConsumer {
    -+  public abstract interface BiConsumer<T, U> {
    -     method public abstract void accept(T, U);
    -     method public default java.util.function.BiConsumer<T, U> andThen(java.util.function.BiConsumer<? super T, ? super U>);
    -   }
    - 
    --  public abstract interface BiFunction {
    --    method public default java.util.function.BiFunction<T, U, V> andThen(java.util.function.Function<? super R, ? extends V>);
    -+  public abstract interface BiFunction<T, U, R> {
    -+    method public default <V> java.util.function.BiFunction<T, U, V> andThen(java.util.function.Function<? super R, ? extends V>);
    -     method public abstract R apply(T, U);
    -   }
    - 
    --  public abstract interface BiPredicate {
    -+  public abstract interface BiPredicate<T, U> {
    -     method public default java.util.function.BiPredicate<T, U> and(java.util.function.BiPredicate<? super T, ? super U>);
    -     method public default java.util.function.BiPredicate<T, U> negate();
    -     method public default java.util.function.BiPredicate<T, U> or(java.util.function.BiPredicate<? super T, ? super U>);
    -     method public abstract boolean test(T, U);
    -   }
    - 
    --  public abstract interface BinaryOperator implements java.util.function.BiFunction {
    --    method public static java.util.function.BinaryOperator<T> maxBy(java.util.Comparator<? super T>);
    --    method public static java.util.function.BinaryOperator<T> minBy(java.util.Comparator<? super T>);
    -+  public abstract interface BinaryOperator<T> implements java.util.function.BiFunction {
    -+    method public static <T> java.util.function.BinaryOperator<T> maxBy(java.util.Comparator<? super T>);
    -+    method public static <T> java.util.function.BinaryOperator<T> minBy(java.util.Comparator<? super T>);
    -   }
    - 
    -   public abstract interface BooleanSupplier {
    -     method public abstract boolean getAsBoolean();
    -   }
    - 
    --  public abstract interface Consumer {
    -+  public abstract interface Consumer<T> {
    -     method public abstract void accept(T);
    -     method public default java.util.function.Consumer<T> andThen(java.util.function.Consumer<? super T>);
    -   }
    -@@ -60877,7 +60877,7 @@ package java.util.function {
    -     method public default java.util.function.DoubleConsumer andThen(java.util.function.DoubleConsumer);
    -   }
    - 
    --  public abstract interface DoubleFunction {
    -+  public abstract interface DoubleFunction<R> {
    -     method public abstract R apply(double);
    -   }
    - 
    -@@ -60907,11 +60907,11 @@ package java.util.function {
    -     method public static java.util.function.DoubleUnaryOperator identity();
    -   }
    - 
    --  public abstract interface Function {
    --    method public default java.util.function.Function<T, V> andThen(java.util.function.Function<? super R, ? extends V>);
    -+  public abstract interface Function<T, R> {
    -+    method public default <V> java.util.function.Function<T, V> andThen(java.util.function.Function<? super R, ? extends V>);
    -     method public abstract R apply(T);
    --    method public default java.util.function.Function<V, R> compose(java.util.function.Function<? super V, ? extends T>);
    --    method public static java.util.function.Function<T, T> identity();
    -+    method public default <V> java.util.function.Function<V, R> compose(java.util.function.Function<? super V, ? extends T>);
    -+    method public static <T> java.util.function.Function<T, T> identity();
    -   }
    - 
    -   public abstract interface IntBinaryOperator {
    -@@ -60923,7 +60923,7 @@ package java.util.function {
    -     method public default java.util.function.IntConsumer andThen(java.util.function.IntConsumer);
    -   }
    - 
    --  public abstract interface IntFunction {
    -+  public abstract interface IntFunction<R> {
    -     method public abstract R apply(int);
    -   }
    - 
    -@@ -60962,7 +60962,7 @@ package java.util.function {
    -     method public default java.util.function.LongConsumer andThen(java.util.function.LongConsumer);
    -   }
    - 
    --  public abstract interface LongFunction {
    -+  public abstract interface LongFunction<R> {
    -     method public abstract R apply(long);
    -   }
    - 
    -@@ -60992,56 +60992,56 @@ package java.util.function {
    -     method public static java.util.function.LongUnaryOperator identity();
    -   }
    - 
    --  public abstract interface ObjDoubleConsumer {
    -+  public abstract interface ObjDoubleConsumer<T> {
    -     method public abstract void accept(T, double);
    -   }
    - 
    --  public abstract interface ObjIntConsumer {
    -+  public abstract interface ObjIntConsumer<T> {
    -     method public abstract void accept(T, int);
    -   }
    - 
    --  public abstract interface ObjLongConsumer {
    -+  public abstract interface ObjLongConsumer<T> {
    -     method public abstract void accept(T, long);
    -   }
    - 
    --  public abstract interface Predicate {
    -+  public abstract interface Predicate<T> {
    -     method public default java.util.function.Predicate<T> and(java.util.function.Predicate<? super T>);
    --    method public static java.util.function.Predicate<T> isEqual(java.lang.Object);
    -+    method public static <T> java.util.function.Predicate<T> isEqual(java.lang.Object);
    -     method public default java.util.function.Predicate<T> negate();
    -     method public default java.util.function.Predicate<T> or(java.util.function.Predicate<? super T>);
    -     method public abstract boolean test(T);
    -   }
    - 
    --  public abstract interface Supplier {
    -+  public abstract interface Supplier<T> {
    -     method public abstract T get();
    -   }
    - 
    --  public abstract interface ToDoubleBiFunction {
    -+  public abstract interface ToDoubleBiFunction<T, U> {
    -     method public abstract double applyAsDouble(T, U);
    -   }
    - 
    --  public abstract interface ToDoubleFunction {
    -+  public abstract interface ToDoubleFunction<T> {
    -     method public abstract double applyAsDouble(T);
    -   }
    - 
    --  public abstract interface ToIntBiFunction {
    -+  public abstract interface ToIntBiFunction<T, U> {
    -     method public abstract int applyAsInt(T, U);
    -   }
    - 
    --  public abstract interface ToIntFunction {
    -+  public abstract interface ToIntFunction<T> {
    -     method public abstract int applyAsInt(T);
    -   }
    - 
    --  public abstract interface ToLongBiFunction {
    -+  public abstract interface ToLongBiFunction<T, U> {
    -     method public abstract long applyAsLong(T, U);
    -   }
    - 
    --  public abstract interface ToLongFunction {
    -+  public abstract interface ToLongFunction<T> {
    -     method public abstract long applyAsLong(T);
    -   }
    - 
    --  public abstract interface UnaryOperator implements java.util.function.Function {
    --    method public static java.util.function.UnaryOperator<T> identity();
    -+  public abstract interface UnaryOperator<T> implements java.util.function.Function {
    -+    method public static <T> java.util.function.UnaryOperator<T> identity();
    -   }
    - 
    - }
    -@@ -61629,7 +61629,7 @@ package java.util.regex {
    - 
    - package java.util.stream {
    - 
    --  public abstract interface BaseStream implements java.lang.AutoCloseable {
    -+  public abstract interface BaseStream<T, S extends java.util.stream.BaseStream<T, S>> implements java.lang.AutoCloseable {
    -     method public abstract void close();
    -     method public abstract boolean isParallel();
    -     method public abstract java.util.Iterator<T> iterator();
    -@@ -61640,13 +61640,13 @@ package java.util.stream {
    -     method public abstract S unordered();
    -   }
    - 
    --  public abstract interface Collector {
    -+  public abstract interface Collector<T, A, R> {
    -     method public abstract java.util.function.BiConsumer<A, T> accumulator();
    -     method public abstract java.util.Set<java.util.stream.Collector.Characteristics> characteristics();
    -     method public abstract java.util.function.BinaryOperator<A> combiner();
    -     method public abstract java.util.function.Function<A, R> finisher();
    --    method public static java.util.stream.Collector<T, R, R> of(java.util.function.Supplier<R>, java.util.function.BiConsumer<R, T>, java.util.function.BinaryOperator<R>, java.util.stream.Collector.Characteristics...);
    --    method public static java.util.stream.Collector<T, A, R> of(java.util.function.Supplier<A>, java.util.function.BiConsumer<A, T>, java.util.function.BinaryOperator<A>, java.util.function.Function<A, R>, java.util.stream.Collector.Characteristics...);
    -+    method public static <T, R> java.util.stream.Collector<T, R, R> of(java.util.function.Supplier<R>, java.util.function.BiConsumer<R, T>, java.util.function.BinaryOperator<R>, java.util.stream.Collector.Characteristics...);
    -+    method public static <T, A, R> java.util.stream.Collector<T, A, R> of(java.util.function.Supplier<A>, java.util.function.BiConsumer<A, T>, java.util.function.BinaryOperator<A>, java.util.function.Function<A, R>, java.util.stream.Collector.Characteristics...);
    -     method public abstract java.util.function.Supplier<A> supplier();
    -   }
    - 
    -@@ -61659,43 +61659,43 @@ package java.util.stream {
    -   }
    - 
    -   public final class Collectors {
    --    method public static java.util.stream.Collector<T, ?, java.lang.Double> averagingDouble(java.util.function.ToDoubleFunction<? super T>);
    --    method public static java.util.stream.Collector<T, ?, java.lang.Double> averagingInt(java.util.function.ToIntFunction<? super T>);
    --    method public static java.util.stream.Collector<T, ?, java.lang.Double> averagingLong(java.util.function.ToLongFunction<? super T>);
    --    method public static java.util.stream.Collector<T, A, RR> collectingAndThen(java.util.stream.Collector<T, A, R>, java.util.function.Function<R, RR>);
    --    method public static java.util.stream.Collector<T, ?, java.lang.Long> counting();
    --    method public static java.util.stream.Collector<T, ?, java.util.Map<K, java.util.List<T>>> groupingBy(java.util.function.Function<? super T, ? extends K>);
    --    method public static java.util.stream.Collector<T, ?, java.util.Map<K, D>> groupingBy(java.util.function.Function<? super T, ? extends K>, java.util.stream.Collector<? super T, A, D>);
    --    method public static java.util.stream.Collector<T, ?, M> groupingBy(java.util.function.Function<? super T, ? extends K>, java.util.function.Supplier<M>, java.util.stream.Collector<? super T, A, D>);
    --    method public static java.util.stream.Collector<T, ?, java.util.concurrent.ConcurrentMap<K, java.util.List<T>>> groupingByConcurrent(java.util.function.Function<? super T, ? extends K>);
    --    method public static java.util.stream.Collector<T, ?, java.util.concurrent.ConcurrentMap<K, D>> groupingByConcurrent(java.util.function.Function<? super T, ? extends K>, java.util.stream.Collector<? super T, A, D>);
    --    method public static java.util.stream.Collector<T, ?, M> groupingByConcurrent(java.util.function.Function<? super T, ? extends K>, java.util.function.Supplier<M>, java.util.stream.Collector<? super T, A, D>);
    -+    method public static <T> java.util.stream.Collector<T, ?, java.lang.Double> averagingDouble(java.util.function.ToDoubleFunction<? super T>);
    -+    method public static <T> java.util.stream.Collector<T, ?, java.lang.Double> averagingInt(java.util.function.ToIntFunction<? super T>);
    -+    method public static <T> java.util.stream.Collector<T, ?, java.lang.Double> averagingLong(java.util.function.ToLongFunction<? super T>);
    -+    method public static <T, A, R, RR> java.util.stream.Collector<T, A, RR> collectingAndThen(java.util.stream.Collector<T, A, R>, java.util.function.Function<R, RR>);
    -+    method public static <T> java.util.stream.Collector<T, ?, java.lang.Long> counting();
    -+    method public static <T, K> java.util.stream.Collector<T, ?, java.util.Map<K, java.util.List<T>>> groupingBy(java.util.function.Function<? super T, ? extends K>);
    -+    method public static <T, K, A, D> java.util.stream.Collector<T, ?, java.util.Map<K, D>> groupingBy(java.util.function.Function<? super T, ? extends K>, java.util.stream.Collector<? super T, A, D>);
    -+    method public static <T, K, D, A, M extends java.util.Map<K, D>> java.util.stream.Collector<T, ?, M> groupingBy(java.util.function.Function<? super T, ? extends K>, java.util.function.Supplier<M>, java.util.stream.Collector<? super T, A, D>);
    -+    method public static <T, K> java.util.stream.Collector<T, ?, java.util.concurrent.ConcurrentMap<K, java.util.List<T>>> groupingByConcurrent(java.util.function.Function<? super T, ? extends K>);
    -+    method public static <T, K, A, D> java.util.stream.Collector<T, ?, java.util.concurrent.ConcurrentMap<K, D>> groupingByConcurrent(java.util.function.Function<? super T, ? extends K>, java.util.stream.Collector<? super T, A, D>);
    -+    method public static <T, K, A, D, M extends java.util.concurrent.ConcurrentMap<K, D>> java.util.stream.Collector<T, ?, M> groupingByConcurrent(java.util.function.Function<? super T, ? extends K>, java.util.function.Supplier<M>, java.util.stream.Collector<? super T, A, D>);
    -     method public static java.util.stream.Collector<java.lang.CharSequence, ?, java.lang.String> joining();
    -     method public static java.util.stream.Collector<java.lang.CharSequence, ?, java.lang.String> joining(java.lang.CharSequence);
    -     method public static java.util.stream.Collector<java.lang.CharSequence, ?, java.lang.String> joining(java.lang.CharSequence, java.lang.CharSequence, java.lang.CharSequence);
    --    method public static java.util.stream.Collector<T, ?, R> mapping(java.util.function.Function<? super T, ? extends U>, java.util.stream.Collector<? super U, A, R>);
    --    method public static java.util.stream.Collector<T, ?, java.util.Optional<T>> maxBy(java.util.Comparator<? super T>);
    --    method public static java.util.stream.Collector<T, ?, java.util.Optional<T>> minBy(java.util.Comparator<? super T>);
    --    method public static java.util.stream.Collector<T, ?, java.util.Map<java.lang.Boolean, java.util.List<T>>> partitioningBy(java.util.function.Predicate<? super T>);
    --    method public static java.util.stream.Collector<T, ?, java.util.Map<java.lang.Boolean, D>> partitioningBy(java.util.function.Predicate<? super T>, java.util.stream.Collector<? super T, A, D>);
    --    method public static java.util.stream.Collector<T, ?, T> reducing(T, java.util.function.BinaryOperator<T>);
    --    method public static java.util.stream.Collector<T, ?, java.util.Optional<T>> reducing(java.util.function.BinaryOperator<T>);
    --    method public static java.util.stream.Collector<T, ?, U> reducing(U, java.util.function.Function<? super T, ? extends U>, java.util.function.BinaryOperator<U>);
    --    method public static java.util.stream.Collector<T, ?, java.util.DoubleSummaryStatistics> summarizingDouble(java.util.function.ToDoubleFunction<? super T>);
    --    method public static java.util.stream.Collector<T, ?, java.util.IntSummaryStatistics> summarizingInt(java.util.function.ToIntFunction<? super T>);
    --    method public static java.util.stream.Collector<T, ?, java.util.LongSummaryStatistics> summarizingLong(java.util.function.ToLongFunction<? super T>);
    --    method public static java.util.stream.Collector<T, ?, java.lang.Double> summingDouble(java.util.function.ToDoubleFunction<? super T>);
    --    method public static java.util.stream.Collector<T, ?, java.lang.Integer> summingInt(java.util.function.ToIntFunction<? super T>);
    --    method public static java.util.stream.Collector<T, ?, java.lang.Long> summingLong(java.util.function.ToLongFunction<? super T>);
    --    method public static java.util.stream.Collector<T, ?, C> toCollection(java.util.function.Supplier<C>);
    --    method public static java.util.stream.Collector<T, ?, java.util.concurrent.ConcurrentMap<K, U>> toConcurrentMap(java.util.function.Function<? super T, ? extends K>, java.util.function.Function<? super T, ? extends U>);
    --    method public static java.util.stream.Collector<T, ?, java.util.concurrent.ConcurrentMap<K, U>> toConcurrentMap(java.util.function.Function<? super T, ? extends K>, java.util.function.Function<? super T, ? extends U>, java.util.function.BinaryOperator<U>);
    --    method public static java.util.stream.Collector<T, ?, M> toConcurrentMap(java.util.function.Function<? super T, ? extends K>, java.util.function.Function<? super T, ? extends U>, java.util.function.BinaryOperator<U>, java.util.function.Supplier<M>);
    --    method public static java.util.stream.Collector<T, ?, java.util.List<T>> toList();
    --    method public static java.util.stream.Collector<T, ?, java.util.Map<K, U>> toMap(java.util.function.Function<? super T, ? extends K>, java.util.function.Function<? super T, ? extends U>);
    --    method public static java.util.stream.Collector<T, ?, java.util.Map<K, U>> toMap(java.util.function.Function<? super T, ? extends K>, java.util.function.Function<? super T, ? extends U>, java.util.function.BinaryOperator<U>);
    --    method public static java.util.stream.Collector<T, ?, M> toMap(java.util.function.Function<? super T, ? extends K>, java.util.function.Function<? super T, ? extends U>, java.util.function.BinaryOperator<U>, java.util.function.Supplier<M>);
    --    method public static java.util.stream.Collector<T, ?, java.util.Set<T>> toSet();
    -+    method public static <T, U, A, R> java.util.stream.Collector<T, ?, R> mapping(java.util.function.Function<? super T, ? extends U>, java.util.stream.Collector<? super U, A, R>);
    -+    method public static <T> java.util.stream.Collector<T, ?, java.util.Optional<T>> maxBy(java.util.Comparator<? super T>);
    -+    method public static <T> java.util.stream.Collector<T, ?, java.util.Optional<T>> minBy(java.util.Comparator<? super T>);
    -+    method public static <T> java.util.stream.Collector<T, ?, java.util.Map<java.lang.Boolean, java.util.List<T>>> partitioningBy(java.util.function.Predicate<? super T>);
    -+    method public static <T, D, A> java.util.stream.Collector<T, ?, java.util.Map<java.lang.Boolean, D>> partitioningBy(java.util.function.Predicate<? super T>, java.util.stream.Collector<? super T, A, D>);
    -+    method public static <T> java.util.stream.Collector<T, ?, T> reducing(T, java.util.function.BinaryOperator<T>);
    -+    method public static <T> java.util.stream.Collector<T, ?, java.util.Optional<T>> reducing(java.util.function.BinaryOperator<T>);
    -+    method public static <T, U> java.util.stream.Collector<T, ?, U> reducing(U, java.util.function.Function<? super T, ? extends U>, java.util.function.BinaryOperator<U>);
    -+    method public static <T> java.util.stream.Collector<T, ?, java.util.DoubleSummaryStatistics> summarizingDouble(java.util.function.ToDoubleFunction<? super T>);
    -+    method public static <T> java.util.stream.Collector<T, ?, java.util.IntSummaryStatistics> summarizingInt(java.util.function.ToIntFunction<? super T>);
    -+    method public static <T> java.util.stream.Collector<T, ?, java.util.LongSummaryStatistics> summarizingLong(java.util.function.ToLongFunction<? super T>);
    -+    method public static <T> java.util.stream.Collector<T, ?, java.lang.Double> summingDouble(java.util.function.ToDoubleFunction<? super T>);
    -+    method public static <T> java.util.stream.Collector<T, ?, java.lang.Integer> summingInt(java.util.function.ToIntFunction<? super T>);
    -+    method public static <T> java.util.stream.Collector<T, ?, java.lang.Long> summingLong(java.util.function.ToLongFunction<? super T>);
    -+    method public static <T, C extends java.util.Collection<T>> java.util.stream.Collector<T, ?, C> toCollection(java.util.function.Supplier<C>);
    -+    method public static <T, K, U> java.util.stream.Collector<T, ?, java.util.concurrent.ConcurrentMap<K, U>> toConcurrentMap(java.util.function.Function<? super T, ? extends K>, java.util.function.Function<? super T, ? extends U>);
    -+    method public static <T, K, U> java.util.stream.Collector<T, ?, java.util.concurrent.ConcurrentMap<K, U>> toConcurrentMap(java.util.function.Function<? super T, ? extends K>, java.util.function.Function<? super T, ? extends U>, java.util.function.BinaryOperator<U>);
    -+    method public static <T, K, U, M extends java.util.concurrent.ConcurrentMap<K, U>> java.util.stream.Collector<T, ?, M> toConcurrentMap(java.util.function.Function<? super T, ? extends K>, java.util.function.Function<? super T, ? extends U>, java.util.function.BinaryOperator<U>, java.util.function.Supplier<M>);
    -+    method public static <T> java.util.stream.Collector<T, ?, java.util.List<T>> toList();
    -+    method public static <T, K, U> java.util.stream.Collector<T, ?, java.util.Map<K, U>> toMap(java.util.function.Function<? super T, ? extends K>, java.util.function.Function<? super T, ? extends U>);
    -+    method public static <T, K, U> java.util.stream.Collector<T, ?, java.util.Map<K, U>> toMap(java.util.function.Function<? super T, ? extends K>, java.util.function.Function<? super T, ? extends U>, java.util.function.BinaryOperator<U>);
    -+    method public static <T, K, U, M extends java.util.Map<K, U>> java.util.stream.Collector<T, ?, M> toMap(java.util.function.Function<? super T, ? extends K>, java.util.function.Function<? super T, ? extends U>, java.util.function.BinaryOperator<U>, java.util.function.Supplier<M>);
    -+    method public static <T> java.util.stream.Collector<T, ?, java.util.Set<T>> toSet();
    -   }
    - 
    -   public abstract interface DoubleStream implements java.util.stream.BaseStream {
    -@@ -61704,7 +61704,7 @@ package java.util.stream {
    -     method public abstract java.util.OptionalDouble average();
    -     method public abstract java.util.stream.Stream<java.lang.Double> boxed();
    -     method public static java.util.stream.DoubleStream.Builder builder();
    --    method public abstract R collect(java.util.function.Supplier<R>, java.util.function.ObjDoubleConsumer<R>, java.util.function.BiConsumer<R, R>);
    -+    method public abstract <R> R collect(java.util.function.Supplier<R>, java.util.function.ObjDoubleConsumer<R>, java.util.function.BiConsumer<R, R>);
    -     method public static java.util.stream.DoubleStream concat(java.util.stream.DoubleStream, java.util.stream.DoubleStream);
    -     method public abstract long count();
    -     method public abstract java.util.stream.DoubleStream distinct();
    -@@ -61722,7 +61722,7 @@ package java.util.stream {
    -     method public abstract java.util.stream.DoubleStream map(java.util.function.DoubleUnaryOperator);
    -     method public abstract java.util.stream.IntStream mapToInt(java.util.function.DoubleToIntFunction);
    -     method public abstract java.util.stream.LongStream mapToLong(java.util.function.DoubleToLongFunction);
    --    method public abstract java.util.stream.Stream<U> mapToObj(java.util.function.DoubleFunction<? extends U>);
    -+    method public abstract <U> java.util.stream.Stream<U> mapToObj(java.util.function.DoubleFunction<? extends U>);
    -     method public abstract java.util.OptionalDouble max();
    -     method public abstract java.util.OptionalDouble min();
    -     method public abstract boolean noneMatch(java.util.function.DoublePredicate);
    -@@ -61755,7 +61755,7 @@ package java.util.stream {
    -     method public abstract java.util.OptionalDouble average();
    -     method public abstract java.util.stream.Stream<java.lang.Integer> boxed();
    -     method public static java.util.stream.IntStream.Builder builder();
    --    method public abstract R collect(java.util.function.Supplier<R>, java.util.function.ObjIntConsumer<R>, java.util.function.BiConsumer<R, R>);
    -+    method public abstract <R> R collect(java.util.function.Supplier<R>, java.util.function.ObjIntConsumer<R>, java.util.function.BiConsumer<R, R>);
    -     method public static java.util.stream.IntStream concat(java.util.stream.IntStream, java.util.stream.IntStream);
    -     method public abstract long count();
    -     method public abstract java.util.stream.IntStream distinct();
    -@@ -61773,7 +61773,7 @@ package java.util.stream {
    -     method public abstract java.util.stream.IntStream map(java.util.function.IntUnaryOperator);
    -     method public abstract java.util.stream.DoubleStream mapToDouble(java.util.function.IntToDoubleFunction);
    -     method public abstract java.util.stream.LongStream mapToLong(java.util.function.IntToLongFunction);
    --    method public abstract java.util.stream.Stream<U> mapToObj(java.util.function.IntFunction<? extends U>);
    -+    method public abstract <U> java.util.stream.Stream<U> mapToObj(java.util.function.IntFunction<? extends U>);
    -     method public abstract java.util.OptionalInt max();
    -     method public abstract java.util.OptionalInt min();
    -     method public abstract boolean noneMatch(java.util.function.IntPredicate);
    -@@ -61807,7 +61807,7 @@ package java.util.stream {
    -     method public abstract java.util.OptionalDouble average();
    -     method public abstract java.util.stream.Stream<java.lang.Long> boxed();
    -     method public static java.util.stream.LongStream.Builder builder();
    --    method public abstract R collect(java.util.function.Supplier<R>, java.util.function.ObjLongConsumer<R>, java.util.function.BiConsumer<R, R>);
    -+    method public abstract <R> R collect(java.util.function.Supplier<R>, java.util.function.ObjLongConsumer<R>, java.util.function.BiConsumer<R, R>);
    -     method public static java.util.stream.LongStream concat(java.util.stream.LongStream, java.util.stream.LongStream);
    -     method public abstract long count();
    -     method public abstract java.util.stream.LongStream distinct();
    -@@ -61825,7 +61825,7 @@ package java.util.stream {
    -     method public abstract java.util.stream.LongStream map(java.util.function.LongUnaryOperator);
    -     method public abstract java.util.stream.DoubleStream mapToDouble(java.util.function.LongToDoubleFunction);
    -     method public abstract java.util.stream.IntStream mapToInt(java.util.function.LongToIntFunction);
    --    method public abstract java.util.stream.Stream<U> mapToObj(java.util.function.LongFunction<? extends U>);
    -+    method public abstract <U> java.util.stream.Stream<U> mapToObj(java.util.function.LongFunction<? extends U>);
    -     method public abstract java.util.OptionalLong max();
    -     method public abstract java.util.OptionalLong min();
    -     method public abstract boolean noneMatch(java.util.function.LongPredicate);
    -@@ -61852,49 +61852,49 @@ package java.util.stream {
    -     method public abstract java.util.stream.LongStream build();
    -   }
    - 
    --  public abstract interface Stream implements java.util.stream.BaseStream {
    -+  public abstract interface Stream<T> implements java.util.stream.BaseStream {
    -     method public abstract boolean allMatch(java.util.function.Predicate<? super T>);
    -     method public abstract boolean anyMatch(java.util.function.Predicate<? super T>);
    --    method public static java.util.stream.Stream.Builder<T> builder();
    --    method public abstract R collect(java.util.function.Supplier<R>, java.util.function.BiConsumer<R, ? super T>, java.util.function.BiConsumer<R, R>);
    --    method public abstract R collect(java.util.stream.Collector<? super T, A, R>);
    --    method public static java.util.stream.Stream<T> concat(java.util.stream.Stream<? extends T>, java.util.stream.Stream<? extends T>);
    -+    method public static <T> java.util.stream.Stream.Builder<T> builder();
    -+    method public abstract <R> R collect(java.util.function.Supplier<R>, java.util.function.BiConsumer<R, ? super T>, java.util.function.BiConsumer<R, R>);
    -+    method public abstract <R, A> R collect(java.util.stream.Collector<? super T, A, R>);
    -+    method public static <T> java.util.stream.Stream<T> concat(java.util.stream.Stream<? extends T>, java.util.stream.Stream<? extends T>);
    -     method public abstract long count();
    -     method public abstract java.util.stream.Stream<T> distinct();
    --    method public static java.util.stream.Stream<T> empty();
    -+    method public static <T> java.util.stream.Stream<T> empty();
    -     method public abstract java.util.stream.Stream<T> filter(java.util.function.Predicate<? super T>);
    -     method public abstract java.util.Optional<T> findAny();
    -     method public abstract java.util.Optional<T> findFirst();
    --    method public abstract java.util.stream.Stream<R> flatMap(java.util.function.Function<? super T, ? extends java.util.stream.Stream<? extends R>>);
    -+    method public abstract <R> java.util.stream.Stream<R> flatMap(java.util.function.Function<? super T, ? extends java.util.stream.Stream<? extends R>>);
    -     method public abstract java.util.stream.DoubleStream flatMapToDouble(java.util.function.Function<? super T, ? extends java.util.stream.DoubleStream>);
    -     method public abstract java.util.stream.IntStream flatMapToInt(java.util.function.Function<? super T, ? extends java.util.stream.IntStream>);
    -     method public abstract java.util.stream.LongStream flatMapToLong(java.util.function.Function<? super T, ? extends java.util.stream.LongStream>);
    -     method public abstract void forEach(java.util.function.Consumer<? super T>);
    -     method public abstract void forEachOrdered(java.util.function.Consumer<? super T>);
    --    method public static java.util.stream.Stream<T> generate(java.util.function.Supplier<T>);
    --    method public static java.util.stream.Stream<T> iterate(T, java.util.function.UnaryOperator<T>);
    -+    method public static <T> java.util.stream.Stream<T> generate(java.util.function.Supplier<T>);
    -+    method public static <T> java.util.stream.Stream<T> iterate(T, java.util.function.UnaryOperator<T>);
    -     method public abstract java.util.stream.Stream<T> limit(long);
    --    method public abstract java.util.stream.Stream<R> map(java.util.function.Function<? super T, ? extends R>);
    -+    method public abstract <R> java.util.stream.Stream<R> map(java.util.function.Function<? super T, ? extends R>);
    -     method public abstract java.util.stream.DoubleStream mapToDouble(java.util.function.ToDoubleFunction<? super T>);
    -     method public abstract java.util.stream.IntStream mapToInt(java.util.function.ToIntFunction<? super T>);
    -     method public abstract java.util.stream.LongStream mapToLong(java.util.function.ToLongFunction<? super T>);
    -     method public abstract java.util.Optional<T> max(java.util.Comparator<? super T>);
    -     method public abstract java.util.Optional<T> min(java.util.Comparator<? super T>);
    -     method public abstract boolean noneMatch(java.util.function.Predicate<? super T>);
    --    method public static java.util.stream.Stream<T> of(T);
    --    method public static java.util.stream.Stream<T> of(T...);
    -+    method public static <T> java.util.stream.Stream<T> of(T);
    -+    method public static <T> java.util.stream.Stream<T> of(T...);
    -     method public abstract java.util.stream.Stream<T> peek(java.util.function.Consumer<? super T>);
    -     method public abstract T reduce(T, java.util.function.BinaryOperator<T>);
    -     method public abstract java.util.Optional<T> reduce(java.util.function.BinaryOperator<T>);
    --    method public abstract U reduce(U, java.util.function.BiFunction<U, ? super T, U>, java.util.function.BinaryOperator<U>);
    -+    method public abstract <U> U reduce(U, java.util.function.BiFunction<U, ? super T, U>, java.util.function.BinaryOperator<U>);
    -     method public abstract java.util.stream.Stream<T> skip(long);
    -     method public abstract java.util.stream.Stream<T> sorted();
    -     method public abstract java.util.stream.Stream<T> sorted(java.util.Comparator<? super T>);
    -     method public abstract java.lang.Object[] toArray();
    --    method public abstract A[] toArray(java.util.function.IntFunction<A[]>);
    -+    method public abstract <A> A[] toArray(java.util.function.IntFunction<A[]>);
    -   }
    - 
    --  public static abstract interface Stream.Builder implements java.util.function.Consumer {
    -+  public static abstract interface Stream.Builder<T> implements java.util.function.Consumer {
    -     method public abstract void accept(T);
    -     method public default java.util.stream.Stream.Builder<T> add(T);
    -     method public abstract java.util.stream.Stream<T> build();
    -@@ -61907,8 +61907,8 @@ package java.util.stream {
    -     method public static java.util.stream.IntStream intStream(java.util.function.Supplier<? extends java.util.Spliterator.OfInt>, int, boolean);
    -     method public static java.util.stream.LongStream longStream(java.util.Spliterator.OfLong, boolean);
    -     method public static java.util.stream.LongStream longStream(java.util.function.Supplier<? extends java.util.Spliterator.OfLong>, int, boolean);
    --    method public static java.util.stream.Stream<T> stream(java.util.Spliterator<T>, boolean);
    --    method public static java.util.stream.Stream<T> stream(java.util.function.Supplier<? extends java.util.Spliterator<T>>, int, boolean);
    -+    method public static <T> java.util.stream.Stream<T> stream(java.util.Spliterator<T>, boolean);
    -+    method public static <T> java.util.stream.Stream<T> stream(java.util.function.Supplier<? extends java.util.Spliterator<T>>, int, boolean);
    -   }
    - 
    - }
    -@@ -64079,16 +64079,16 @@ package javax.security.auth {
    -   public final class Subject implements java.io.Serializable {
    -     ctor public Subject();
    -     ctor public Subject(boolean, java.util.Set<? extends java.security.Principal>, java.util.Set<?>, java.util.Set<?>);
    --    method public static T doAs(javax.security.auth.Subject, java.security.PrivilegedAction<T>);
    --    method public static T doAs(javax.security.auth.Subject, java.security.PrivilegedExceptionAction<T>) throws java.security.PrivilegedActionException;
    --    method public static T doAsPrivileged(javax.security.auth.Subject, java.security.PrivilegedAction<T>, java.security.AccessControlContext);
    --    method public static T doAsPrivileged(javax.security.auth.Subject, java.security.PrivilegedExceptionAction<T>, java.security.AccessControlContext) throws java.security.PrivilegedActionException;
    -+    method public static <T> T doAs(javax.security.auth.Subject, java.security.PrivilegedAction<T>);
    -+    method public static <T> T doAs(javax.security.auth.Subject, java.security.PrivilegedExceptionAction<T>) throws java.security.PrivilegedActionException;
    -+    method public static <T> T doAsPrivileged(javax.security.auth.Subject, java.security.PrivilegedAction<T>, java.security.AccessControlContext);
    -+    method public static <T> T doAsPrivileged(javax.security.auth.Subject, java.security.PrivilegedExceptionAction<T>, java.security.AccessControlContext) throws java.security.PrivilegedActionException;
    -     method public java.util.Set<java.security.Principal> getPrincipals();
    --    method public java.util.Set<T> getPrincipals(java.lang.Class<T>);
    -+    method public <T extends java.security.Principal> java.util.Set<T> getPrincipals(java.lang.Class<T>);
    -     method public java.util.Set<java.lang.Object> getPrivateCredentials();
    --    method public java.util.Set<T> getPrivateCredentials(java.lang.Class<T>);
    -+    method public <T> java.util.Set<T> getPrivateCredentials(java.lang.Class<T>);
    -     method public java.util.Set<java.lang.Object> getPublicCredentials();
    --    method public java.util.Set<T> getPublicCredentials(java.lang.Class<T>);
    -+    method public <T> java.util.Set<T> getPublicCredentials(java.lang.Class<T>);
    -     method public static javax.security.auth.Subject getSubject(java.security.AccessControlContext);
    -     method public boolean isReadOnly();
    -     method public void setReadOnly();
    -diff --git a/api/system-current.txt b/api/system-current.txt
    -index c33fe6e..0fe164a 100644
    ---- a/api/system-current.txt
    -+++ b/api/system-current.txt
    -@@ -3031,11 +3031,11 @@ package android.accounts {
    -     field public static final java.lang.String LOGIN_ACCOUNTS_CHANGED_ACTION = "android.accounts.LOGIN_ACCOUNTS_CHANGED";
    -   }
    - 
    --  public abstract interface AccountManagerCallback {
    -+  public abstract interface AccountManagerCallback<V> {
    -     method public abstract void run(android.accounts.AccountManagerFuture<V>);
    -   }
    - 
    --  public abstract interface AccountManagerFuture {
    -+  public abstract interface AccountManagerFuture<V> {
    -     method public abstract boolean cancel(boolean);
    -     method public abstract V getResult() throws android.accounts.AuthenticatorException, java.io.IOException, android.accounts.OperationCanceledException;
    -     method public abstract V getResult(long, java.util.concurrent.TimeUnit) throws android.accounts.AuthenticatorException, java.io.IOException, android.accounts.OperationCanceledException;
    -@@ -3181,7 +3181,7 @@ package android.animation {
    -     method public java.lang.Object evaluate(float, java.lang.Object, java.lang.Object);
    -   }
    - 
    --  public abstract class BidirectionalTypeConverter extends android.animation.TypeConverter {
    -+  public abstract class BidirectionalTypeConverter<T, V> extends android.animation.TypeConverter {
    -     ctor public BidirectionalTypeConverter(java.lang.Class<T>, java.lang.Class<V>);
    -     method public abstract T convertBack(V);
    -     method public android.animation.BidirectionalTypeConverter<V, T> invert();
    -@@ -3273,26 +3273,26 @@ package android.animation {
    -     method public java.lang.String getPropertyName();
    -     method public java.lang.Object getTarget();
    -     method public static android.animation.ObjectAnimator ofArgb(java.lang.Object, java.lang.String, int...);
    --    method public static android.animation.ObjectAnimator ofArgb(T, android.util.Property<T, java.lang.Integer>, int...);
    -+    method public static <T> android.animation.ObjectAnimator ofArgb(T, android.util.Property<T, java.lang.Integer>, int...);
    -     method public static android.animation.ObjectAnimator ofFloat(java.lang.Object, java.lang.String, float...);
    -     method public static android.animation.ObjectAnimator ofFloat(java.lang.Object, java.lang.String, java.lang.String, android.graphics.Path);
    --    method public static android.animation.ObjectAnimator ofFloat(T, android.util.Property<T, java.lang.Float>, float...);
    --    method public static android.animation.ObjectAnimator ofFloat(T, android.util.Property<T, java.lang.Float>, android.util.Property<T, java.lang.Float>, android.graphics.Path);
    -+    method public static <T> android.animation.ObjectAnimator ofFloat(T, android.util.Property<T, java.lang.Float>, float...);
    -+    method public static <T> android.animation.ObjectAnimator ofFloat(T, android.util.Property<T, java.lang.Float>, android.util.Property<T, java.lang.Float>, android.graphics.Path);
    -     method public static android.animation.ObjectAnimator ofInt(java.lang.Object, java.lang.String, int...);
    -     method public static android.animation.ObjectAnimator ofInt(java.lang.Object, java.lang.String, java.lang.String, android.graphics.Path);
    --    method public static android.animation.ObjectAnimator ofInt(T, android.util.Property<T, java.lang.Integer>, int...);
    --    method public static android.animation.ObjectAnimator ofInt(T, android.util.Property<T, java.lang.Integer>, android.util.Property<T, java.lang.Integer>, android.graphics.Path);
    -+    method public static <T> android.animation.ObjectAnimator ofInt(T, android.util.Property<T, java.lang.Integer>, int...);
    -+    method public static <T> android.animation.ObjectAnimator ofInt(T, android.util.Property<T, java.lang.Integer>, android.util.Property<T, java.lang.Integer>, android.graphics.Path);
    -     method public static android.animation.ObjectAnimator ofMultiFloat(java.lang.Object, java.lang.String, float[][]);
    -     method public static android.animation.ObjectAnimator ofMultiFloat(java.lang.Object, java.lang.String, android.graphics.Path);
    --    method public static android.animation.ObjectAnimator ofMultiFloat(java.lang.Object, java.lang.String, android.animation.TypeConverter<T, float[]>, android.animation.TypeEvaluator<T>, T...);
    -+    method public static <T> android.animation.ObjectAnimator ofMultiFloat(java.lang.Object, java.lang.String, android.animation.TypeConverter<T, float[]>, android.animation.TypeEvaluator<T>, T...);
    -     method public static android.animation.ObjectAnimator ofMultiInt(java.lang.Object, java.lang.String, int[][]);
    -     method public static android.animation.ObjectAnimator ofMultiInt(java.lang.Object, java.lang.String, android.graphics.Path);
    --    method public static android.animation.ObjectAnimator ofMultiInt(java.lang.Object, java.lang.String, android.animation.TypeConverter<T, int[]>, android.animation.TypeEvaluator<T>, T...);
    -+    method public static <T> android.animation.ObjectAnimator ofMultiInt(java.lang.Object, java.lang.String, android.animation.TypeConverter<T, int[]>, android.animation.TypeEvaluator<T>, T...);
    -     method public static android.animation.ObjectAnimator ofObject(java.lang.Object, java.lang.String, android.animation.TypeEvaluator, java.lang.Object...);
    -     method public static android.animation.ObjectAnimator ofObject(java.lang.Object, java.lang.String, android.animation.TypeConverter<android.graphics.PointF, ?>, android.graphics.Path);
    --    method public static android.animation.ObjectAnimator ofObject(T, android.util.Property<T, V>, android.animation.TypeEvaluator<V>, V...);
    --    method public static android.animation.ObjectAnimator ofObject(T, android.util.Property<T, P>, android.animation.TypeConverter<V, P>, android.animation.TypeEvaluator<V>, V...);
    --    method public static android.animation.ObjectAnimator ofObject(T, android.util.Property<T, V>, android.animation.TypeConverter<android.graphics.PointF, V>, android.graphics.Path);
    -+    method public static <T, V> android.animation.ObjectAnimator ofObject(T, android.util.Property<T, V>, android.animation.TypeEvaluator<V>, V...);
    -+    method public static <T, V, P> android.animation.ObjectAnimator ofObject(T, android.util.Property<T, P>, android.animation.TypeConverter<V, P>, android.animation.TypeEvaluator<V>, V...);
    -+    method public static <T, V> android.animation.ObjectAnimator ofObject(T, android.util.Property<T, V>, android.animation.TypeConverter<android.graphics.PointF, V>, android.graphics.Path);
    -     method public static android.animation.ObjectAnimator ofPropertyValuesHolder(java.lang.Object, android.animation.PropertyValuesHolder...);
    -     method public void setAutoCancel(boolean);
    -     method public void setProperty(android.util.Property);
    -@@ -3316,17 +3316,17 @@ package android.animation {
    -     method public static android.animation.PropertyValuesHolder ofKeyframe(android.util.Property, android.animation.Keyframe...);
    -     method public static android.animation.PropertyValuesHolder ofMultiFloat(java.lang.String, float[][]);
    -     method public static android.animation.PropertyValuesHolder ofMultiFloat(java.lang.String, android.graphics.Path);
    --    method public static android.animation.PropertyValuesHolder ofMultiFloat(java.lang.String, android.animation.TypeConverter<V, float[]>, android.animation.TypeEvaluator<V>, V...);
    --    method public static android.animation.PropertyValuesHolder ofMultiFloat(java.lang.String, android.animation.TypeConverter<T, float[]>, android.animation.TypeEvaluator<T>, android.animation.Keyframe...);
    -+    method public static <V> android.animation.PropertyValuesHolder ofMultiFloat(java.lang.String, android.animation.TypeConverter<V, float[]>, android.animation.TypeEvaluator<V>, V...);
    -+    method public static <T> android.animation.PropertyValuesHolder ofMultiFloat(java.lang.String, android.animation.TypeConverter<T, float[]>, android.animation.TypeEvaluator<T>, android.animation.Keyframe...);
    -     method public static android.animation.PropertyValuesHolder ofMultiInt(java.lang.String, int[][]);
    -     method public static android.animation.PropertyValuesHolder ofMultiInt(java.lang.String, android.graphics.Path);
    --    method public static android.animation.PropertyValuesHolder ofMultiInt(java.lang.String, android.animation.TypeConverter<V, int[]>, android.animation.TypeEvaluator<V>, V...);
    --    method public static android.animation.PropertyValuesHolder ofMultiInt(java.lang.String, android.animation.TypeConverter<T, int[]>, android.animation.TypeEvaluator<T>, android.animation.Keyframe...);
    -+    method public static <V> android.animation.PropertyValuesHolder ofMultiInt(java.lang.String, android.animation.TypeConverter<V, int[]>, android.animation.TypeEvaluator<V>, V...);
    -+    method public static <T> android.animation.PropertyValuesHolder ofMultiInt(java.lang.String, android.animation.TypeConverter<T, int[]>, android.animation.TypeEvaluator<T>, android.animation.Keyframe...);
    -     method public static android.animation.PropertyValuesHolder ofObject(java.lang.String, android.animation.TypeEvaluator, java.lang.Object...);
    -     method public static android.animation.PropertyValuesHolder ofObject(java.lang.String, android.animation.TypeConverter<android.graphics.PointF, ?>, android.graphics.Path);
    --    method public static android.animation.PropertyValuesHolder ofObject(android.util.Property, android.animation.TypeEvaluator<V>, V...);
    --    method public static android.animation.PropertyValuesHolder ofObject(android.util.Property<?, V>, android.animation.TypeConverter<T, V>, android.animation.TypeEvaluator<T>, T...);
    --    method public static android.animation.PropertyValuesHolder ofObject(android.util.Property<?, V>, android.animation.TypeConverter<android.graphics.PointF, V>, android.graphics.Path);
    -+    method public static <V> android.animation.PropertyValuesHolder ofObject(android.util.Property, android.animation.TypeEvaluator<V>, V...);
    -+    method public static <T, V> android.animation.PropertyValuesHolder ofObject(android.util.Property<?, V>, android.animation.TypeConverter<T, V>, android.animation.TypeEvaluator<T>, T...);
    -+    method public static <V> android.animation.PropertyValuesHolder ofObject(android.util.Property<?, V>, android.animation.TypeConverter<android.graphics.PointF, V>, android.graphics.Path);
    -     method public void setConverter(android.animation.TypeConverter);
    -     method public void setEvaluator(android.animation.TypeEvaluator);
    -     method public void setFloatValues(float...);
    -@@ -3363,12 +3363,12 @@ package android.animation {
    -     method public abstract float getInterpolation(float);
    -   }
    - 
    --  public abstract class TypeConverter {
    -+  public abstract class TypeConverter<T, V> {
    -     ctor public TypeConverter(java.lang.Class<T>, java.lang.Class<V>);
    -     method public abstract V convert(T);
    -   }
    - 
    --  public abstract interface TypeEvaluator {
    -+  public abstract interface TypeEvaluator<T> {
    -     method public abstract T evaluate(float, T, T);
    -   }
    - 
    -@@ -4726,7 +4726,7 @@ package android.app {
    -     method public android.os.Parcelable saveAllState();
    -   }
    - 
    --  public abstract class FragmentHostCallback extends android.app.FragmentContainer {
    -+  public abstract class FragmentHostCallback<E> extends android.app.FragmentContainer {
    -     ctor public FragmentHostCallback(android.content.Context, android.os.Handler, int);
    -     method public void onAttachFragment(android.app.Fragment);
    -     method public void onDump(java.lang.String, java.io.FileDescriptor, java.io.PrintWriter, java.lang.String[]);
    -@@ -4993,12 +4993,12 @@ package android.app {
    -     method public abstract void destroyLoader(int);
    -     method public abstract void dump(java.lang.String, java.io.FileDescriptor, java.io.PrintWriter, java.lang.String[]);
    -     method public static void enableDebugLogging(boolean);
    --    method public abstract android.content.Loader<D> getLoader(int);
    --    method public abstract android.content.Loader<D> initLoader(int, android.os.Bundle, android.app.LoaderManager.LoaderCallbacks<D>);
    --    method public abstract android.content.Loader<D> restartLoader(int, android.os.Bundle, android.app.LoaderManager.LoaderCallbacks<D>);
    -+    method public abstract <D> android.content.Loader<D> getLoader(int);
    -+    method public abstract <D> android.content.Loader<D> initLoader(int, android.os.Bundle, android.app.LoaderManager.LoaderCallbacks<D>);
    -+    method public abstract <D> android.content.Loader<D> restartLoader(int, android.os.Bundle, android.app.LoaderManager.LoaderCallbacks<D>);
    -   }
    - 
    --  public static abstract interface LoaderManager.LoaderCallbacks {
    -+  public static abstract interface LoaderManager.LoaderCallbacks<D> {
    -     method public abstract android.content.Loader<D> onCreateLoader(int, android.os.Bundle);
    -     method public abstract void onLoadFinished(android.content.Loader<D>, D);
    -     method public abstract void onLoaderReset(android.content.Loader<D>);
    -@@ -7952,7 +7952,7 @@ package android.content {
    -     ctor public AsyncQueryHandler.WorkerHandler(android.os.Looper);
    -   }
    - 
    --  public abstract class AsyncTaskLoader extends android.content.Loader {
    -+  public abstract class AsyncTaskLoader<D> extends android.content.Loader {
    -     ctor public AsyncTaskLoader(android.content.Context);
    -     method public void cancelLoadInBackground();
    -     method public boolean isLoadInBackgroundCanceled();
    -@@ -8134,7 +8134,7 @@ package android.content {
    -     method public android.os.ParcelFileDescriptor openFile(android.net.Uri, java.lang.String) throws java.io.FileNotFoundException;
    -     method public android.os.ParcelFileDescriptor openFile(android.net.Uri, java.lang.String, android.os.CancellationSignal) throws java.io.FileNotFoundException;
    -     method protected final android.os.ParcelFileDescriptor openFileHelper(android.net.Uri, java.lang.String) throws java.io.FileNotFoundException;
    --    method public android.os.ParcelFileDescriptor openPipeHelper(android.net.Uri, java.lang.String, android.os.Bundle, T, android.content.ContentProvider.PipeDataWriter<T>) throws java.io.FileNotFoundException;
    -+    method public <T> android.os.ParcelFileDescriptor openPipeHelper(android.net.Uri, java.lang.String, android.os.Bundle, T, android.content.ContentProvider.PipeDataWriter<T>) throws java.io.FileNotFoundException;
    -     method public android.content.res.AssetFileDescriptor openTypedAssetFile(android.net.Uri, java.lang.String, android.os.Bundle) throws java.io.FileNotFoundException;
    -     method public android.content.res.AssetFileDescriptor openTypedAssetFile(android.net.Uri, java.lang.String, android.os.Bundle, android.os.CancellationSignal) throws java.io.FileNotFoundException;
    -     method public abstract android.database.Cursor query(android.net.Uri, java.lang.String[], java.lang.String, java.lang.String[], java.lang.String);
    -@@ -8147,7 +8147,7 @@ package android.content {
    -     method public abstract int update(android.net.Uri, android.content.ContentValues, java.lang.String, java.lang.String[]);
    -   }
    - 
    --  public static abstract interface ContentProvider.PipeDataWriter {
    -+  public static abstract interface ContentProvider.PipeDataWriter<T> {
    -     method public abstract void writeDataToPipe(android.os.ParcelFileDescriptor, android.net.Uri, java.lang.String, android.os.Bundle, T);
    -   }
    - 
    -@@ -8420,7 +8420,7 @@ package android.content {
    -     method public final java.lang.String getString(int);
    -     method public final java.lang.String getString(int, java.lang.Object...);
    -     method public abstract java.lang.Object getSystemService(java.lang.String);
    --    method public final T getSystemService(java.lang.Class<T>);
    -+    method public final <T> T getSystemService(java.lang.Class<T>);
    -     method public abstract java.lang.String getSystemServiceName(java.lang.Class<?>);
    -     method public final java.lang.CharSequence getText(int);
    -     method public abstract android.content.res.Resources.Theme getTheme();
    -@@ -8789,8 +8789,8 @@ package android.content {
    -     method public long getLongExtra(java.lang.String, long);
    -     method public java.lang.String getPackage();
    -     method public android.os.Parcelable[] getParcelableArrayExtra(java.lang.String);
    --    method public java.util.ArrayList<T> getParcelableArrayListExtra(java.lang.String);
    --    method public T getParcelableExtra(java.lang.String);
    -+    method public <T extends android.os.Parcelable> java.util.ArrayList<T> getParcelableArrayListExtra(java.lang.String);
    -+    method public <T extends android.os.Parcelable> T getParcelableExtra(java.lang.String);
    -     method public java.lang.String getScheme();
    -     method public android.content.Intent getSelector();
    -     method public java.io.Serializable getSerializableExtra(java.lang.String);
    -@@ -9277,7 +9277,7 @@ package android.content {
    -     ctor public IntentSender.SendIntentException(java.lang.Exception);
    -   }
    - 
    --  public class Loader {
    -+  public class Loader<D> {
    -     ctor public Loader(android.content.Context);
    -     method public void abandon();
    -     method public boolean cancelLoad();
    -@@ -9314,11 +9314,11 @@ package android.content {
    -     ctor public Loader.ForceLoadContentObserver();
    -   }
    - 
    --  public static abstract interface Loader.OnLoadCanceledListener {
    -+  public static abstract interface Loader.OnLoadCanceledListener<D> {
    -     method public abstract void onLoadCanceled(android.content.Loader<D>);
    -   }
    - 
    --  public static abstract interface Loader.OnLoadCompleteListener {
    -+  public static abstract interface Loader.OnLoadCompleteListener<D> {
    -     method public abstract void onLoadComplete(android.content.Loader<D>, D);
    -   }
    - 
    -@@ -11287,7 +11287,7 @@ package android.database {
    -     method public boolean isNull(int);
    -   }
    - 
    --  public abstract class Observable {
    -+  public abstract class Observable<T> {
    -     ctor public Observable();
    -     method public void registerObserver(T);
    -     method public void unregisterAll();
    -@@ -13177,7 +13177,7 @@ package android.graphics.drawable {
    -   public class AnimatedStateListDrawable extends android.graphics.drawable.StateListDrawable {
    -     ctor public AnimatedStateListDrawable();
    -     method public void addState(int[], android.graphics.drawable.Drawable, int);
    --    method public void addTransition(int, int, T, boolean);
    -+    method public <T extends android.graphics.drawable.Drawable & android.graphics.drawable.Animatable> void addTransition(int, int, T, boolean);
    -   }
    - 
    -   public class AnimatedVectorDrawable extends android.graphics.drawable.Drawable implements android.graphics.drawable.Animatable2 {
    -@@ -14309,7 +14309,7 @@ package android.hardware.camera2 {
    -   }
    - 
    -   public final class CameraCharacteristics extends android.hardware.camera2.CameraMetadata {
    --    method public T get(android.hardware.camera2.CameraCharacteristics.Key<T>);
    -+    method public <T> T get(android.hardware.camera2.CameraCharacteristics.Key<T>);
    -     method public java.util.List<android.hardware.camera2.CaptureRequest.Key<?>> getAvailableCaptureRequestKeys();
    -     method public java.util.List<android.hardware.camera2.CaptureResult.Key<?>> getAvailableCaptureResultKeys();
    -     field public static final android.hardware.camera2.CameraCharacteristics.Key<int[]> COLOR_CORRECTION_AVAILABLE_ABERRATION_MODES;
    -@@ -14394,7 +14394,7 @@ package android.hardware.camera2 {
    -     field public static final android.hardware.camera2.CameraCharacteristics.Key<java.lang.Integer> TONEMAP_MAX_CURVE_POINTS;
    -   }
    - 
    --  public static final class CameraCharacteristics.Key {
    -+  public static final class CameraCharacteristics.Key<T> {
    -     method public final boolean equals(java.lang.Object);
    -     method public java.lang.String getName();
    -     method public final int hashCode();
    -@@ -14459,7 +14459,7 @@ package android.hardware.camera2 {
    -     method public void onTorchModeUnavailable(java.lang.String);
    -   }
    - 
    --  public abstract class CameraMetadata {
    -+  public abstract class CameraMetadata<TKey> {
    -     method public java.util.List<TKey> getKeys();
    -     field public static final int COLOR_CORRECTION_ABERRATION_MODE_FAST = 1; // 0x1
    -     field public static final int COLOR_CORRECTION_ABERRATION_MODE_HIGH_QUALITY = 2; // 0x2
    -@@ -14667,7 +14667,7 @@ package android.hardware.camera2 {
    - 
    -   public final class CaptureRequest extends android.hardware.camera2.CameraMetadata implements android.os.Parcelable {
    -     method public int describeContents();
    --    method public T get(android.hardware.camera2.CaptureRequest.Key<T>);
    -+    method public <T> T get(android.hardware.camera2.CaptureRequest.Key<T>);
    -     method public java.lang.Object getTag();
    -     method public boolean isReprocess();
    -     method public void writeToParcel(android.os.Parcel, int);
    -@@ -14730,20 +14730,20 @@ package android.hardware.camera2 {
    -   public static final class CaptureRequest.Builder {
    -     method public void addTarget(android.view.Surface);
    -     method public android.hardware.camera2.CaptureRequest build();
    --    method public T get(android.hardware.camera2.CaptureRequest.Key<T>);
    -+    method public <T> T get(android.hardware.camera2.CaptureRequest.Key<T>);
    -     method public void removeTarget(android.view.Surface);
    --    method public void set(android.hardware.camera2.CaptureRequest.Key<T>, T);
    -+    method public <T> void set(android.hardware.camera2.CaptureRequest.Key<T>, T);
    -     method public void setTag(java.lang.Object);
    -   }
    - 
    --  public static final class CaptureRequest.Key {
    -+  public static final class CaptureRequest.Key<T> {
    -     method public final boolean equals(java.lang.Object);
    -     method public java.lang.String getName();
    -     method public final int hashCode();
    -   }
    - 
    -   public class CaptureResult extends android.hardware.camera2.CameraMetadata {
    --    method public T get(android.hardware.camera2.CaptureResult.Key<T>);
    -+    method public <T> T get(android.hardware.camera2.CaptureResult.Key<T>);
    -     method public long getFrameNumber();
    -     method public android.hardware.camera2.CaptureRequest getRequest();
    -     method public int getSequenceId();
    -@@ -14824,7 +14824,7 @@ package android.hardware.camera2 {
    -     field public static final android.hardware.camera2.CaptureResult.Key<java.lang.Integer> TONEMAP_PRESET_CURVE;
    -   }
    - 
    --  public static final class CaptureResult.Key {
    -+  public static final class CaptureResult.Key<T> {
    -     method public final boolean equals(java.lang.Object);
    -     method public java.lang.String getName();
    -     method public final int hashCode();
    -@@ -14956,14 +14956,14 @@ package android.hardware.camera2.params {
    -     method public android.util.Size[] getInputSizes(int);
    -     method public final int[] getOutputFormats();
    -     method public long getOutputMinFrameDuration(int, android.util.Size);
    --    method public long getOutputMinFrameDuration(java.lang.Class<T>, android.util.Size);
    --    method public android.util.Size[] getOutputSizes(java.lang.Class<T>);
    -+    method public <T> long getOutputMinFrameDuration(java.lang.Class<T>, android.util.Size);
    -+    method public <T> android.util.Size[] getOutputSizes(java.lang.Class<T>);
    -     method public android.util.Size[] getOutputSizes(int);
    -     method public long getOutputStallDuration(int, android.util.Size);
    --    method public long getOutputStallDuration(java.lang.Class<T>, android.util.Size);
    -+    method public <T> long getOutputStallDuration(java.lang.Class<T>, android.util.Size);
    -     method public final int[] getValidOutputFormatsForInput(int);
    -     method public boolean isOutputSupportedFor(int);
    --    method public static boolean isOutputSupportedFor(java.lang.Class<T>);
    -+    method public static <T> boolean isOutputSupportedFor(java.lang.Class<T>);
    -     method public boolean isOutputSupportedFor(android.view.Surface);
    -   }
    - 
    -@@ -17411,7 +17411,7 @@ package android.icu.math {
    - 
    - package android.icu.text {
    - 
    --  public final class AlphabeticIndex implements java.lang.Iterable {
    -+  public final class AlphabeticIndex<V> implements java.lang.Iterable {
    -     ctor public AlphabeticIndex(android.icu.util.ULocale);
    -     ctor public AlphabeticIndex(java.util.Locale);
    -     ctor public AlphabeticIndex(android.icu.text.RuleBasedCollator);
    -@@ -17437,7 +17437,7 @@ package android.icu.text {
    -     method public android.icu.text.AlphabeticIndex<V> setUnderflowLabel(java.lang.String);
    -   }
    - 
    --  public static class AlphabeticIndex.Bucket implements java.lang.Iterable {
    -+  public static class AlphabeticIndex.Bucket<V> implements java.lang.Iterable {
    -     method public java.lang.String getLabel();
    -     method public android.icu.text.AlphabeticIndex.Bucket.LabelType getLabelType();
    -     method public java.util.Iterator<android.icu.text.AlphabeticIndex.Record<V>> iterator();
    -@@ -17453,14 +17453,14 @@ package android.icu.text {
    -     enum_constant public static final android.icu.text.AlphabeticIndex.Bucket.LabelType UNDERFLOW;
    -   }
    - 
    --  public static final class AlphabeticIndex.ImmutableIndex implements java.lang.Iterable {
    -+  public static final class AlphabeticIndex.ImmutableIndex<V> implements java.lang.Iterable {
    -     method public android.icu.text.AlphabeticIndex.Bucket<V> getBucket(int);
    -     method public int getBucketCount();
    -     method public int getBucketIndex(java.lang.CharSequence);
    -     method public java.util.Iterator<android.icu.text.AlphabeticIndex.Bucket<V>> iterator();
    -   }
    - 
    --  public static class AlphabeticIndex.Record {
    -+  public static class AlphabeticIndex.Record<V> {
    -     method public V getData();
    -     method public java.lang.CharSequence getName();
    -   }
    -@@ -18973,8 +18973,8 @@ package android.icu.text {
    -     method public final android.icu.text.UnicodeSet addAll(java.lang.CharSequence);
    -     method public android.icu.text.UnicodeSet addAll(android.icu.text.UnicodeSet);
    -     method public android.icu.text.UnicodeSet addAll(java.lang.Iterable<?>);
    --    method public android.icu.text.UnicodeSet addAll(T...);
    --    method public T addAllTo(T);
    -+    method public <T extends java.lang.CharSequence> android.icu.text.UnicodeSet addAll(T...);
    -+    method public <T extends java.util.Collection<java.lang.String>> T addAllTo(T);
    -     method public void addMatchSetTo(android.icu.text.UnicodeSet);
    -     method public android.icu.text.UnicodeSet applyIntPropertyValue(int, int);
    -     method public final android.icu.text.UnicodeSet applyPattern(java.lang.String);
    -@@ -19002,15 +19002,15 @@ package android.icu.text {
    -     method public final boolean contains(java.lang.CharSequence);
    -     method public boolean containsAll(android.icu.text.UnicodeSet);
    -     method public boolean containsAll(java.lang.String);
    --    method public boolean containsAll(java.lang.Iterable<T>);
    -+    method public <T extends java.lang.CharSequence> boolean containsAll(java.lang.Iterable<T>);
    -     method public boolean containsNone(int, int);
    -     method public boolean containsNone(android.icu.text.UnicodeSet);
    -     method public boolean containsNone(java.lang.CharSequence);
    --    method public boolean containsNone(java.lang.Iterable<T>);
    -+    method public <T extends java.lang.CharSequence> boolean containsNone(java.lang.Iterable<T>);
    -     method public final boolean containsSome(int, int);
    -     method public final boolean containsSome(android.icu.text.UnicodeSet);
    -     method public final boolean containsSome(java.lang.CharSequence);
    --    method public final boolean containsSome(java.lang.Iterable<T>);
    -+    method public final <T extends java.lang.CharSequence> boolean containsSome(java.lang.Iterable<T>);
    -     method public android.icu.text.UnicodeSet freeze();
    -     method public static android.icu.text.UnicodeSet from(java.lang.CharSequence);
    -     method public static android.icu.text.UnicodeSet fromAll(java.lang.CharSequence);
    -@@ -19028,14 +19028,14 @@ package android.icu.text {
    -     method public final android.icu.text.UnicodeSet remove(java.lang.CharSequence);
    -     method public final android.icu.text.UnicodeSet removeAll(java.lang.CharSequence);
    -     method public android.icu.text.UnicodeSet removeAll(android.icu.text.UnicodeSet);
    --    method public android.icu.text.UnicodeSet removeAll(java.lang.Iterable<T>);
    -+    method public <T extends java.lang.CharSequence> android.icu.text.UnicodeSet removeAll(java.lang.Iterable<T>);
    -     method public final android.icu.text.UnicodeSet removeAllStrings();
    -     method public android.icu.text.UnicodeSet retain(int, int);
    -     method public final android.icu.text.UnicodeSet retain(int);
    -     method public final android.icu.text.UnicodeSet retain(java.lang.CharSequence);
    -     method public final android.icu.text.UnicodeSet retainAll(java.lang.CharSequence);
    -     method public android.icu.text.UnicodeSet retainAll(android.icu.text.UnicodeSet);
    --    method public android.icu.text.UnicodeSet retainAll(java.lang.Iterable<T>);
    -+    method public <T extends java.lang.CharSequence> android.icu.text.UnicodeSet retainAll(java.lang.Iterable<T>);
    -     method public android.icu.text.UnicodeSet set(int, int);
    -     method public android.icu.text.UnicodeSet set(android.icu.text.UnicodeSet);
    -     method public int size();
    -@@ -19445,7 +19445,7 @@ package android.icu.util {
    -     method public long getToDate();
    -   }
    - 
    --  public abstract interface Freezable implements java.lang.Cloneable {
    -+  public abstract interface Freezable<T> implements java.lang.Cloneable {
    -     method public abstract T cloneAsThawed();
    -     method public abstract T freeze();
    -     method public abstract boolean isFrozen();
    -@@ -19727,7 +19727,7 @@ package android.icu.util {
    -     field public static final android.icu.util.TimeUnit YEAR;
    -   }
    - 
    --  public class Output {
    -+  public class Output<T> {
    -     ctor public Output();
    -     ctor public Output(T);
    -     field public T value;
    -@@ -30658,7 +30658,7 @@ package android.opengl {
    - 
    - package android.os {
    - 
    --  public abstract class AsyncTask {
    -+  public abstract class AsyncTask<Params, Progress, Result> {
    -     ctor public AsyncTask();
    -     method public final boolean cancel(boolean);
    -     method protected abstract Result doInBackground(Params...);
    -@@ -30886,16 +30886,16 @@ package android.os {
    -     method public float getFloat(java.lang.String, float);
    -     method public float[] getFloatArray(java.lang.String);
    -     method public java.util.ArrayList<java.lang.Integer> getIntegerArrayList(java.lang.String);
    --    method public T getParcelable(java.lang.String);
    -+    method public <T extends android.os.Parcelable> T getParcelable(java.lang.String);
    -     method public android.os.Parcelable[] getParcelableArray(java.lang.String);
    --    method public java.util.ArrayList<T> getParcelableArrayList(java.lang.String);
    -+    method public <T extends android.os.Parcelable> java.util.ArrayList<T> getParcelableArrayList(java.lang.String);
    -     method public java.io.Serializable getSerializable(java.lang.String);
    -     method public short getShort(java.lang.String);
    -     method public short getShort(java.lang.String, short);
    -     method public short[] getShortArray(java.lang.String);
    -     method public android.util.Size getSize(java.lang.String);
    -     method public android.util.SizeF getSizeF(java.lang.String);
    --    method public android.util.SparseArray<T> getSparseParcelableArray(java.lang.String);
    -+    method public <T extends android.os.Parcelable> android.util.SparseArray<T> getSparseParcelableArray(java.lang.String);
    -     method public java.util.ArrayList<java.lang.String> getStringArrayList(java.lang.String);
    -     method public boolean hasFileDescriptors();
    -     method public void putAll(android.os.Bundle);
    -@@ -31400,8 +31400,8 @@ package android.os {
    -     method public final long[] createLongArray();
    -     method public final java.lang.String[] createStringArray();
    -     method public final java.util.ArrayList<java.lang.String> createStringArrayList();
    --    method public final T[] createTypedArray(android.os.Parcelable.Creator<T>);
    --    method public final java.util.ArrayList<T> createTypedArrayList(android.os.Parcelable.Creator<T>);
    -+    method public final <T> T[] createTypedArray(android.os.Parcelable.Creator<T>);
    -+    method public final <T> java.util.ArrayList<T> createTypedArrayList(android.os.Parcelable.Creator<T>);
    -     method public final int dataAvail();
    -     method public final int dataCapacity();
    -     method public final int dataPosition();
    -@@ -31434,7 +31434,7 @@ package android.os {
    -     method public final long readLong();
    -     method public final void readLongArray(long[]);
    -     method public final void readMap(java.util.Map, java.lang.ClassLoader);
    --    method public final T readParcelable(java.lang.ClassLoader);
    -+    method public final <T extends android.os.Parcelable> T readParcelable(java.lang.ClassLoader);
    -     method public final android.os.Parcelable[] readParcelableArray(java.lang.ClassLoader);
    -     method public final android.os.PersistableBundle readPersistableBundle();
    -     method public final android.os.PersistableBundle readPersistableBundle(java.lang.ClassLoader);
    -@@ -31447,9 +31447,9 @@ package android.os {
    -     method public final void readStringArray(java.lang.String[]);
    -     method public final void readStringList(java.util.List<java.lang.String>);
    -     method public final android.os.IBinder readStrongBinder();
    --    method public final void readTypedArray(T[], android.os.Parcelable.Creator<T>);
    --    method public final void readTypedList(java.util.List<T>, android.os.Parcelable.Creator<T>);
    --    method public final T readTypedObject(android.os.Parcelable.Creator<T>);
    -+    method public final <T> void readTypedArray(T[], android.os.Parcelable.Creator<T>);
    -+    method public final <T> void readTypedList(java.util.List<T>, android.os.Parcelable.Creator<T>);
    -+    method public final <T> T readTypedObject(android.os.Parcelable.Creator<T>);
    -     method public final java.lang.Object readValue(java.lang.ClassLoader);
    -     method public final void recycle();
    -     method public final void setDataCapacity(int);
    -@@ -31480,7 +31480,7 @@ package android.os {
    -     method public final void writeMap(java.util.Map);
    -     method public final void writeNoException();
    -     method public final void writeParcelable(android.os.Parcelable, int);
    --    method public final void writeParcelableArray(T[], int);
    -+    method public final <T extends android.os.Parcelable> void writeParcelableArray(T[], int);
    -     method public final void writePersistableBundle(android.os.PersistableBundle);
    -     method public final void writeSerializable(java.io.Serializable);
    -     method public final void writeSize(android.util.Size);
    -@@ -31492,9 +31492,9 @@ package android.os {
    -     method public final void writeStringList(java.util.List<java.lang.String>);
    -     method public final void writeStrongBinder(android.os.IBinder);
    -     method public final void writeStrongInterface(android.os.IInterface);
    --    method public final void writeTypedArray(T[], int);
    --    method public final void writeTypedList(java.util.List<T>);
    --    method public final void writeTypedObject(T, int);
    -+    method public final <T extends android.os.Parcelable> void writeTypedArray(T[], int);
    -+    method public final <T extends android.os.Parcelable> void writeTypedList(java.util.List<T>);
    -+    method public final <T extends android.os.Parcelable> void writeTypedObject(T, int);
    -     method public final void writeValue(java.lang.Object);
    -     field public static final android.os.Parcelable.Creator<java.lang.String> STRING_CREATOR;
    -   }
    -@@ -31572,11 +31572,11 @@ package android.os {
    -     field public static final int PARCELABLE_WRITE_RETURN_VALUE = 1; // 0x1
    -   }
    - 
    --  public static abstract interface Parcelable.ClassLoaderCreator implements android.os.Parcelable.Creator {
    -+  public static abstract interface Parcelable.ClassLoaderCreator<T> implements android.os.Parcelable.Creator {
    -     method public abstract T createFromParcel(android.os.Parcel, java.lang.ClassLoader);
    -   }
    - 
    --  public static abstract interface Parcelable.Creator {
    -+  public static abstract interface Parcelable.Creator<T> {
    -     method public abstract T createFromParcel(android.os.Parcel);
    -     method public abstract T[] newArray(int);
    -   }
    -@@ -31718,7 +31718,7 @@ package android.os {
    -     method public abstract void onResult(android.os.Bundle);
    -   }
    - 
    --  public class RemoteCallbackList {
    -+  public class RemoteCallbackList<E extends android.os.IInterface> {
    -     ctor public RemoteCallbackList();
    -     method public int beginBroadcast();
    -     method public void finishBroadcast();
    -@@ -35238,7 +35238,7 @@ package android.provider {
    -     field public static final java.lang.String RADIO_CELL = "cell";
    -     field public static final java.lang.String RADIO_NFC = "nfc";
    -     field public static final java.lang.String RADIO_WIFI = "wifi";
    --    field public static final java.lang.String SHOW_PROCESSES = "show_processes";
    -+    field public static final deprecated java.lang.String SHOW_PROCESSES = "show_processes";
    -     field public static final java.lang.String STAY_ON_WHILE_PLUGGED_IN = "stay_on_while_plugged_in";
    -     field public static final java.lang.String THEATER_MODE_ON = "theater_mode_on";
    -     field public static final java.lang.String TRANSITION_ANIMATION_SCALE = "transition_animation_scale";
    -@@ -37278,7 +37278,7 @@ package android.service.carrier {
    -     field public static final java.lang.String SERVICE_INTERFACE = "android.service.carrier.CarrierMessagingService";
    -   }
    - 
    --  public static abstract interface CarrierMessagingService.ResultCallback {
    -+  public static abstract interface CarrierMessagingService.ResultCallback<T> {
    -     method public abstract void onReceiveResult(T) throws android.os.RemoteException;
    -   }
    - 
    -@@ -37429,7 +37429,7 @@ package android.service.media {
    -     field public static final java.lang.String EXTRA_SUGGESTED = "android.service.media.extra.SUGGESTED";
    -   }
    - 
    --  public class MediaBrowserService.Result {
    -+  public class MediaBrowserService.Result<T> {
    -     method public void detach();
    -     method public void sendResult(T);
    -   }
    -@@ -40749,14 +40749,14 @@ package android.telephony.gsm {
    - 
    - package android.test {
    - 
    --  public abstract deprecated class ActivityInstrumentationTestCase extends android.test.ActivityTestCase {
    -+  public abstract deprecated class ActivityInstrumentationTestCase<T extends android.app.Activity> extends android.test.ActivityTestCase {
    -     ctor public ActivityInstrumentationTestCase(java.lang.String, java.lang.Class<T>);
    -     ctor public ActivityInstrumentationTestCase(java.lang.String, java.lang.Class<T>, boolean);
    -     method public T getActivity();
    -     method public void testActivityTestCaseSetUpProperly() throws java.lang.Exception;
    -   }
    - 
    --  public abstract deprecated class ActivityInstrumentationTestCase2 extends android.test.ActivityTestCase {
    -+  public abstract deprecated class ActivityInstrumentationTestCase2<T extends android.app.Activity> extends android.test.ActivityTestCase {
    -     ctor public deprecated ActivityInstrumentationTestCase2(java.lang.String, java.lang.Class<T>);
    -     ctor public ActivityInstrumentationTestCase2(java.lang.Class<T>);
    -     method public T getActivity();
    -@@ -40771,7 +40771,7 @@ package android.test {
    -     method protected void setActivity(android.app.Activity);
    -   }
    - 
    --  public abstract deprecated class ActivityUnitTestCase extends android.test.ActivityTestCase {
    -+  public abstract deprecated class ActivityUnitTestCase<T extends android.app.Activity> extends android.test.ActivityTestCase {
    -     ctor public ActivityUnitTestCase(java.lang.Class<T>);
    -     method public T getActivity();
    -     method public int getFinishedActivityRequest();
    -@@ -40817,7 +40817,7 @@ package android.test {
    -     method public void testStarted(java.lang.String);
    -   }
    - 
    --  public abstract deprecated class ApplicationTestCase extends android.test.AndroidTestCase {
    -+  public abstract deprecated class ApplicationTestCase<T extends android.app.Application> extends android.test.AndroidTestCase {
    -     ctor public ApplicationTestCase(java.lang.Class<T>);
    -     method protected final void createApplication();
    -     method public T getApplication();
    -@@ -40843,8 +40843,8 @@ package android.test {
    -     method public android.app.Instrumentation getInstrumentation();
    -     method public deprecated void injectInsrumentation(android.app.Instrumentation);
    -     method public void injectInstrumentation(android.app.Instrumentation);
    --    method public final T launchActivity(java.lang.String, java.lang.Class<T>, android.os.Bundle);
    --    method public final T launchActivityWithIntent(java.lang.String, java.lang.Class<T>, android.content.Intent);
    -+    method public final <T extends android.app.Activity> T launchActivity(java.lang.String, java.lang.Class<T>, android.os.Bundle);
    -+    method public final <T extends android.app.Activity> T launchActivityWithIntent(java.lang.String, java.lang.Class<T>, android.content.Intent);
    -     method public void runTestOnUiThread(java.lang.Runnable) throws java.lang.Throwable;
    -     method public void sendKeys(java.lang.String);
    -     method public void sendKeys(int...);
    -@@ -40884,7 +40884,7 @@ package android.test {
    - 
    -   public class LoaderTestCase extends android.test.AndroidTestCase {
    -     ctor public LoaderTestCase();
    --    method public T getLoaderResultSynchronously(android.content.Loader<T>);
    -+    method public <T> T getLoaderResultSynchronously(android.content.Loader<T>);
    -   }
    - 
    -   public final deprecated class MoreAsserts {
    -@@ -40939,20 +40939,20 @@ package android.test {
    -     method public abstract void startTiming(boolean);
    -   }
    - 
    --  public abstract deprecated class ProviderTestCase extends android.test.InstrumentationTestCase {
    -+  public abstract deprecated class ProviderTestCase<T extends android.content.ContentProvider> extends android.test.InstrumentationTestCase {
    -     ctor public ProviderTestCase(java.lang.Class<T>, java.lang.String);
    -     method public android.test.mock.MockContentResolver getMockContentResolver();
    -     method public android.test.IsolatedContext getMockContext();
    -     method public T getProvider();
    --    method public static android.content.ContentResolver newResolverWithContentProviderFromSql(android.content.Context, java.lang.Class<T>, java.lang.String, java.lang.String, int, java.lang.String) throws java.lang.IllegalAccessException, java.lang.InstantiationException;
    -+    method public static <T extends android.content.ContentProvider> android.content.ContentResolver newResolverWithContentProviderFromSql(android.content.Context, java.lang.Class<T>, java.lang.String, java.lang.String, int, java.lang.String) throws java.lang.IllegalAccessException, java.lang.InstantiationException;
    -   }
    - 
    --  public abstract class ProviderTestCase2 extends android.test.AndroidTestCase {
    -+  public abstract class ProviderTestCase2<T extends android.content.ContentProvider> extends android.test.AndroidTestCase {
    -     ctor public ProviderTestCase2(java.lang.Class<T>, java.lang.String);
    -     method public android.test.mock.MockContentResolver getMockContentResolver();
    -     method public android.test.IsolatedContext getMockContext();
    -     method public T getProvider();
    --    method public static android.content.ContentResolver newResolverWithContentProviderFromSql(android.content.Context, java.lang.String, java.lang.Class<T>, java.lang.String, java.lang.String, int, java.lang.String) throws java.lang.IllegalAccessException, java.lang.InstantiationException;
    -+    method public static <T extends android.content.ContentProvider> android.content.ContentResolver newResolverWithContentProviderFromSql(android.content.Context, java.lang.String, java.lang.Class<T>, java.lang.String, java.lang.String, int, java.lang.String) throws java.lang.IllegalAccessException, java.lang.InstantiationException;
    -   }
    - 
    -   public deprecated class RenamingDelegatingContext extends android.content.ContextWrapper {
    -@@ -40960,11 +40960,11 @@ package android.test {
    -     ctor public RenamingDelegatingContext(android.content.Context, android.content.Context, java.lang.String);
    -     method public java.lang.String getDatabasePrefix();
    -     method public void makeExistingFilesAndDbsAccessible();
    --    method public static T providerWithRenamedContext(java.lang.Class<T>, android.content.Context, java.lang.String) throws java.lang.IllegalAccessException, java.lang.InstantiationException;
    --    method public static T providerWithRenamedContext(java.lang.Class<T>, android.content.Context, java.lang.String, boolean) throws java.lang.IllegalAccessException, java.lang.InstantiationException;
    -+    method public static <T extends android.content.ContentProvider> T providerWithRenamedContext(java.lang.Class<T>, android.content.Context, java.lang.String) throws java.lang.IllegalAccessException, java.lang.InstantiationException;
    -+    method public static <T extends android.content.ContentProvider> T providerWithRenamedContext(java.lang.Class<T>, android.content.Context, java.lang.String, boolean) throws java.lang.IllegalAccessException, java.lang.InstantiationException;
    -   }
    - 
    --  public abstract deprecated class ServiceTestCase extends android.test.AndroidTestCase {
    -+  public abstract deprecated class ServiceTestCase<T extends android.app.Service> extends android.test.AndroidTestCase {
    -     ctor public ServiceTestCase(java.lang.Class<T>);
    -     method protected android.os.IBinder bindService(android.content.Intent);
    -     method public android.app.Application getApplication();
    -@@ -40977,7 +40977,7 @@ package android.test {
    -     method public void testServiceTestCaseSetUpProperly() throws java.lang.Exception;
    -   }
    - 
    --  public abstract deprecated class SingleLaunchActivityTestCase extends android.test.InstrumentationTestCase {
    -+  public abstract deprecated class SingleLaunchActivityTestCase<T extends android.app.Activity> extends android.test.InstrumentationTestCase {
    -     ctor public SingleLaunchActivityTestCase(java.lang.String, java.lang.Class<T>);
    -     method public T getActivity();
    -     method public void testActivityTestCaseSetUpProperly() throws java.lang.Exception;
    -@@ -41344,7 +41344,7 @@ package android.test.suitebuilder {
    -     ctor public TestMethod(java.lang.String, java.lang.Class<? extends junit.framework.TestCase>);
    -     ctor public TestMethod(junit.framework.TestCase);
    -     method public junit.framework.TestCase createTest() throws java.lang.IllegalAccessException, java.lang.InstantiationException, java.lang.reflect.InvocationTargetException;
    --    method public T getAnnotation(java.lang.Class<T>);
    -+    method public <T extends java.lang.annotation.Annotation> T getAnnotation(java.lang.Class<T>);
    -     method public java.lang.Class<? extends junit.framework.TestCase> getEnclosingClass();
    -     method public java.lang.String getEnclosingClassname();
    -     method public java.lang.String getName();
    -@@ -41787,7 +41787,7 @@ package android.text {
    -     method public int getSpanEnd(java.lang.Object);
    -     method public int getSpanFlags(java.lang.Object);
    -     method public int getSpanStart(java.lang.Object);
    --    method public T[] getSpans(int, int, java.lang.Class<T>);
    -+    method public <T> T[] getSpans(int, int, java.lang.Class<T>);
    -     method public deprecated int getTextRunCursor(int, int, int, int, int, android.graphics.Paint);
    -     method public int getTextWatcherDepth();
    -     method public android.text.SpannableStringBuilder insert(int, java.lang.CharSequence, int, int);
    -@@ -41809,7 +41809,7 @@ package android.text {
    -     method public int getSpanEnd(java.lang.Object);
    -     method public int getSpanFlags(java.lang.Object);
    -     method public int getSpanStart(java.lang.Object);
    --    method public T[] getSpans(int, int, java.lang.Class<T>);
    -+    method public <T> T[] getSpans(int, int, java.lang.Class<T>);
    -     method public final int length();
    -     method public int nextSpanTransition(int, int, java.lang.Class);
    -     method public final java.lang.String toString();
    -@@ -41819,7 +41819,7 @@ package android.text {
    -     method public abstract int getSpanEnd(java.lang.Object);
    -     method public abstract int getSpanFlags(java.lang.Object);
    -     method public abstract int getSpanStart(java.lang.Object);
    --    method public abstract T[] getSpans(int, int, java.lang.Class<T>);
    -+    method public abstract <T> T[] getSpans(int, int, java.lang.Class<T>);
    -     method public abstract int nextSpanTransition(int, int, java.lang.Class);
    -     field public static final int SPAN_COMPOSING = 256; // 0x100
    -     field public static final int SPAN_EXCLUSIVE_EXCLUSIVE = 33; // 0x21
    -@@ -42796,7 +42796,7 @@ package android.text.style {
    -     field public static final int WEEKDAY_WEDNESDAY = 4; // 0x4
    -   }
    - 
    --  public static class TtsSpan.Builder {
    -+  public static class TtsSpan.Builder<C extends android.text.style.TtsSpan.Builder<?>> {
    -     ctor public TtsSpan.Builder(java.lang.String);
    -     method public android.text.style.TtsSpan build();
    -     method public C setIntArgument(java.lang.String, int);
    -@@ -42892,7 +42892,7 @@ package android.text.style {
    -     method public android.text.style.TtsSpan.OrdinalBuilder setNumber(java.lang.String);
    -   }
    - 
    --  public static class TtsSpan.SemioticClassBuilder extends android.text.style.TtsSpan.Builder {
    -+  public static class TtsSpan.SemioticClassBuilder<C extends android.text.style.TtsSpan.SemioticClassBuilder<?>> extends android.text.style.TtsSpan.Builder {
    -     ctor public TtsSpan.SemioticClassBuilder(java.lang.String);
    -     method public C setAnimacy(java.lang.String);
    -     method public C setCase(java.lang.String);
    -@@ -43299,7 +43299,7 @@ package android.util {
    -     ctor public AndroidRuntimeException(java.lang.Exception);
    -   }
    - 
    --  public final class ArrayMap implements java.util.Map {
    -+  public final class ArrayMap<K, V> implements java.util.Map {
    -     ctor public ArrayMap();
    -     ctor public ArrayMap(int);
    -     ctor public ArrayMap(android.util.ArrayMap<K, V>);
    -@@ -43327,7 +43327,7 @@ package android.util {
    -     method public java.util.Collection<V> values();
    -   }
    - 
    --  public final class ArraySet implements java.util.Collection java.util.Set {
    -+  public final class ArraySet<E> implements java.util.Collection java.util.Set {
    -     ctor public ArraySet();
    -     ctor public ArraySet(int);
    -     ctor public ArraySet(android.util.ArraySet<E>);
    -@@ -43348,7 +43348,7 @@ package android.util {
    -     method public boolean retainAll(java.util.Collection<?>);
    -     method public int size();
    -     method public java.lang.Object[] toArray();
    --    method public T[] toArray(T[]);
    -+    method public <T> T[] toArray(T[]);
    -     method public E valueAt(int);
    -   }
    - 
    -@@ -43493,13 +43493,13 @@ package android.util {
    -   public deprecated class FloatMath {
    -   }
    - 
    --  public abstract class FloatProperty extends android.util.Property {
    -+  public abstract class FloatProperty<T> extends android.util.Property {
    -     ctor public FloatProperty(java.lang.String);
    -     method public final void set(T, java.lang.Float);
    -     method public abstract void setValue(T, float);
    -   }
    - 
    --  public abstract class IntProperty extends android.util.Property {
    -+  public abstract class IntProperty<T> extends android.util.Property {
    -     ctor public IntProperty(java.lang.String);
    -     method public final void set(T, java.lang.Integer);
    -     method public abstract void setValue(T, int);
    -@@ -43599,7 +43599,7 @@ package android.util {
    -     method public void println(java.lang.String);
    -   }
    - 
    --  public class LongSparseArray implements java.lang.Cloneable {
    -+  public class LongSparseArray<E> implements java.lang.Cloneable {
    -     ctor public LongSparseArray();
    -     ctor public LongSparseArray(int);
    -     method public void append(long, E);
    -@@ -43619,7 +43619,7 @@ package android.util {
    -     method public E valueAt(int);
    -   }
    - 
    --  public class LruCache {
    -+  public class LruCache<K, V> {
    -     ctor public LruCache(int);
    -     method protected V create(K);
    -     method public final synchronized int createCount();
    -@@ -43707,9 +43707,9 @@ package android.util {
    -     ctor public NoSuchPropertyException(java.lang.String);
    -   }
    - 
    --  public class Pair {
    -+  public class Pair<F, S> {
    -     ctor public Pair(F, S);
    --    method public static android.util.Pair<A, B> create(A, B);
    -+    method public static <A, B> android.util.Pair<A, B> create(A, B);
    -     field public final F first;
    -     field public final S second;
    -   }
    -@@ -43742,22 +43742,22 @@ package android.util {
    -     method public abstract void println(java.lang.String);
    -   }
    - 
    --  public abstract class Property {
    -+  public abstract class Property<T, V> {
    -     ctor public Property(java.lang.Class<V>, java.lang.String);
    -     method public abstract V get(T);
    -     method public java.lang.String getName();
    -     method public java.lang.Class<V> getType();
    -     method public boolean isReadOnly();
    --    method public static android.util.Property<T, V> of(java.lang.Class<T>, java.lang.Class<V>, java.lang.String);
    -+    method public static <T, V> android.util.Property<T, V> of(java.lang.Class<T>, java.lang.Class<V>, java.lang.String);
    -     method public void set(T, V);
    -   }
    - 
    --  public final class Range {
    -+  public final class Range<T extends java.lang.Comparable<? super T>> {
    -     ctor public Range(T, T);
    -     method public T clamp(T);
    -     method public boolean contains(T);
    -     method public boolean contains(android.util.Range<T>);
    --    method public static android.util.Range<T> create(T, T);
    -+    method public static <T extends java.lang.Comparable<? super T>> android.util.Range<T> create(T, T);
    -     method public android.util.Range<T> extend(android.util.Range<T>);
    -     method public android.util.Range<T> extend(T, T);
    -     method public android.util.Range<T> extend(T);
    -@@ -43801,7 +43801,7 @@ package android.util {
    -     method public static android.util.SizeF parseSizeF(java.lang.String) throws java.lang.NumberFormatException;
    -   }
    - 
    --  public class SparseArray implements java.lang.Cloneable {
    -+  public class SparseArray<E> implements java.lang.Cloneable {
    -     ctor public SparseArray();
    -     ctor public SparseArray(int);
    -     method public void append(int, E);
    -@@ -48606,7 +48606,7 @@ package android.webkit {
    -     method public static java.lang.String stripAnchor(java.lang.String);
    -   }
    - 
    --  public abstract interface ValueCallback {
    -+  public abstract interface ValueCallback<T> {
    -     method public abstract void onReceiveValue(T);
    -   }
    - 
    -@@ -49621,7 +49621,7 @@ package android.widget {
    -     field public static final int NO_SELECTION = -2147483648; // 0x80000000
    -   }
    - 
    --  public abstract class AdapterView extends android.view.ViewGroup {
    -+  public abstract class AdapterView<T extends android.widget.Adapter> extends android.view.ViewGroup {
    -     ctor public AdapterView(android.content.Context);
    -     ctor public AdapterView(android.content.Context, android.util.AttributeSet);
    -     ctor public AdapterView(android.content.Context, android.util.AttributeSet, int);
    -@@ -49744,7 +49744,7 @@ package android.widget {
    -     ctor public AnalogClock(android.content.Context, android.util.AttributeSet, int, int);
    -   }
    - 
    --  public class ArrayAdapter extends android.widget.BaseAdapter implements android.widget.Filterable android.widget.ThemedSpinnerAdapter {
    -+  public class ArrayAdapter<T> extends android.widget.BaseAdapter implements android.widget.Filterable android.widget.ThemedSpinnerAdapter {
    -     ctor public ArrayAdapter(android.content.Context, int);
    -     ctor public ArrayAdapter(android.content.Context, int, int);
    -     ctor public ArrayAdapter(android.content.Context, int, T[]);
    -@@ -49805,7 +49805,7 @@ package android.widget {
    -     method protected void performFiltering(java.lang.CharSequence, int);
    -     method public void performValidation();
    -     method protected void replaceText(java.lang.CharSequence);
    --    method public void setAdapter(T);
    -+    method public <T extends android.widget.ListAdapter & android.widget.Filterable> void setAdapter(T);
    -     method public void setCompletionHint(java.lang.CharSequence);
    -     method public void setDropDownAnchor(int);
    -     method public void setDropDownBackgroundDrawable(android.graphics.drawable.Drawable);
    -@@ -52090,7 +52090,7 @@ package android.widget {
    - 
    - package com.android.internal.util {
    - 
    --  public abstract interface Predicate {
    -+  public abstract interface Predicate<T> {
    -     method public abstract boolean apply(T);
    -   }
    - 
    -@@ -54137,13 +54137,13 @@ package java.lang {
    -     enum_constant public static final java.lang.Character.UnicodeScript YI;
    -   }
    - 
    --  public final class Class implements java.lang.reflect.AnnotatedElement java.lang.reflect.GenericDeclaration java.io.Serializable java.lang.reflect.Type {
    --    method public java.lang.Class<? extends U> asSubclass(java.lang.Class<U>);
    -+  public final class Class<T> implements java.lang.reflect.AnnotatedElement java.lang.reflect.GenericDeclaration java.io.Serializable java.lang.reflect.Type {
    -+    method public <U> java.lang.Class<? extends U> asSubclass(java.lang.Class<U>);
    -     method public T cast(java.lang.Object);
    -     method public boolean desiredAssertionStatus();
    -     method public static java.lang.Class<?> forName(java.lang.String) throws java.lang.ClassNotFoundException;
    -     method public static java.lang.Class<?> forName(java.lang.String, boolean, java.lang.ClassLoader) throws java.lang.ClassNotFoundException;
    --    method public A getAnnotation(java.lang.Class<A>);
    -+    method public <A extends java.lang.annotation.Annotation> A getAnnotation(java.lang.Class<A>);
    -     method public java.lang.annotation.Annotation[] getAnnotations();
    -     method public java.lang.String getCanonicalName();
    -     method public java.lang.ClassLoader getClassLoader();
    -@@ -54260,7 +54260,7 @@ package java.lang {
    -   public abstract interface Cloneable {
    -   }
    - 
    --  public abstract interface Comparable {
    -+  public abstract interface Comparable<T> {
    -     method public abstract int compareTo(T);
    -   }
    - 
    -@@ -54314,7 +54314,7 @@ package java.lang {
    -     field public static final java.lang.Class<java.lang.Double> TYPE;
    -   }
    - 
    --  public abstract class Enum implements java.lang.Comparable java.io.Serializable {
    -+  public abstract class Enum<E extends java.lang.Enum<E>> implements java.lang.Comparable java.io.Serializable {
    -     ctor protected Enum(java.lang.String, int);
    -     method protected final java.lang.Object clone() throws java.lang.CloneNotSupportedException;
    -     method public final int compareTo(E);
    -@@ -54324,7 +54324,7 @@ package java.lang {
    -     method public final int hashCode();
    -     method public final java.lang.String name();
    -     method public final int ordinal();
    --    method public static T valueOf(java.lang.Class<T>, java.lang.String);
    -+    method public static <T extends java.lang.Enum<T>> T valueOf(java.lang.Class<T>, java.lang.String);
    -   }
    - 
    -   public class EnumConstantNotPresentException extends java.lang.RuntimeException {
    -@@ -54443,7 +54443,7 @@ package java.lang {
    -     ctor public IndexOutOfBoundsException(java.lang.String);
    -   }
    - 
    --  public class InheritableThreadLocal extends java.lang.ThreadLocal {
    -+  public class InheritableThreadLocal<T> extends java.lang.ThreadLocal {
    -     ctor public InheritableThreadLocal();
    -     method protected T childValue(T);
    -   }
    -@@ -54514,7 +54514,7 @@ package java.lang {
    -     ctor public InterruptedException(java.lang.String);
    -   }
    - 
    --  public abstract interface Iterable {
    -+  public abstract interface Iterable<T> {
    -     method public default void forEach(java.util.function.Consumer<? super T>);
    -     method public abstract java.util.Iterator<T> iterator();
    -     method public default java.util.Spliterator<T> spliterator();
    -@@ -54722,12 +54722,12 @@ package java.lang {
    -   }
    - 
    -   public class Package implements java.lang.reflect.AnnotatedElement {
    --    method public A getAnnotation(java.lang.Class<A>);
    -+    method public <A extends java.lang.annotation.Annotation> A getAnnotation(java.lang.Class<A>);
    -     method public java.lang.annotation.Annotation[] getAnnotations();
    --    method public A[] getAnnotationsByType(java.lang.Class<A>);
    --    method public A getDeclaredAnnotation(java.lang.Class<A>);
    -+    method public <A extends java.lang.annotation.Annotation> A[] getAnnotationsByType(java.lang.Class<A>);
    -+    method public <A extends java.lang.annotation.Annotation> A getDeclaredAnnotation(java.lang.Class<A>);
    -     method public java.lang.annotation.Annotation[] getDeclaredAnnotations();
    --    method public A[] getDeclaredAnnotationsByType(java.lang.Class<A>);
    -+    method public <A extends java.lang.annotation.Annotation> A[] getDeclaredAnnotationsByType(java.lang.Class<A>);
    -     method public java.lang.String getImplementationTitle();
    -     method public java.lang.String getImplementationVendor();
    -     method public java.lang.String getImplementationVersion();
    -@@ -55287,7 +55287,7 @@ package java.lang {
    -     method public void uncaughtException(java.lang.Thread, java.lang.Throwable);
    -   }
    - 
    --  public class ThreadLocal {
    -+  public class ThreadLocal<T> {
    -     ctor public ThreadLocal();
    -     method public T get();
    -     method protected T initialValue();
    -@@ -55427,30 +55427,30 @@ package java.lang.annotation {
    - 
    - package java.lang.ref {
    - 
    --  public class PhantomReference extends java.lang.ref.Reference {
    -+  public class PhantomReference<T> extends java.lang.ref.Reference {
    -     ctor public PhantomReference(T, java.lang.ref.ReferenceQueue<? super T>);
    -   }
    - 
    --  public abstract class Reference {
    -+  public abstract class Reference<T> {
    -     method public void clear();
    -     method public boolean enqueue();
    -     method public T get();
    -     method public boolean isEnqueued();
    -   }
    - 
    --  public class ReferenceQueue {
    -+  public class ReferenceQueue<T> {
    -     ctor public ReferenceQueue();
    -     method public java.lang.ref.Reference<? extends T> poll();
    -     method public java.lang.ref.Reference<? extends T> remove(long) throws java.lang.IllegalArgumentException, java.lang.InterruptedException;
    -     method public java.lang.ref.Reference<? extends T> remove() throws java.lang.InterruptedException;
    -   }
    - 
    --  public class SoftReference extends java.lang.ref.Reference {
    -+  public class SoftReference<T> extends java.lang.ref.Reference {
    -     ctor public SoftReference(T);
    -     ctor public SoftReference(T, java.lang.ref.ReferenceQueue<? super T>);
    -   }
    - 
    --  public class WeakReference extends java.lang.ref.Reference {
    -+  public class WeakReference<T> extends java.lang.ref.Reference {
    -     ctor public WeakReference(T);
    -     ctor public WeakReference(T, java.lang.ref.ReferenceQueue<? super T>);
    -   }
    -@@ -55461,7 +55461,7 @@ package java.lang.reflect {
    - 
    -   public class AccessibleObject implements java.lang.reflect.AnnotatedElement {
    -     ctor protected AccessibleObject();
    --    method public T getAnnotation(java.lang.Class<T>);
    -+    method public <T extends java.lang.annotation.Annotation> T getAnnotation(java.lang.Class<T>);
    -     method public java.lang.annotation.Annotation[] getAnnotations();
    -     method public java.lang.annotation.Annotation[] getDeclaredAnnotations();
    -     method public boolean isAccessible();
    -@@ -55470,12 +55470,12 @@ package java.lang.reflect {
    -   }
    - 
    -   public abstract interface AnnotatedElement {
    --    method public abstract T getAnnotation(java.lang.Class<T>);
    -+    method public abstract <T extends java.lang.annotation.Annotation> T getAnnotation(java.lang.Class<T>);
    -     method public abstract java.lang.annotation.Annotation[] getAnnotations();
    --    method public default T[] getAnnotationsByType(java.lang.Class<T>);
    --    method public default java.lang.annotation.Annotation getDeclaredAnnotation(java.lang.Class<T>);
    -+    method public default <T extends java.lang.annotation.Annotation> T[] getAnnotationsByType(java.lang.Class<T>);
    -+    method public default <T extends java.lang.annotation.Annotation> java.lang.annotation.Annotation getDeclaredAnnotation(java.lang.Class<T>);
    -     method public abstract java.lang.annotation.Annotation[] getDeclaredAnnotations();
    --    method public default T[] getDeclaredAnnotationsByType(java.lang.Class<T>);
    -+    method public default <T extends java.lang.annotation.Annotation> T[] getDeclaredAnnotationsByType(java.lang.Class<T>);
    -     method public default boolean isAnnotationPresent(java.lang.Class<? extends java.lang.annotation.Annotation>);
    -   }
    - 
    -@@ -55503,8 +55503,8 @@ package java.lang.reflect {
    -     method public static void setShort(java.lang.Object, int, short) throws java.lang.ArrayIndexOutOfBoundsException, java.lang.IllegalArgumentException;
    -   }
    - 
    --  public final class Constructor extends java.lang.reflect.AccessibleObject implements java.lang.reflect.GenericDeclaration java.lang.reflect.Member {
    --    method public A getAnnotation(java.lang.Class<A>);
    -+  public final class Constructor<T> extends java.lang.reflect.AccessibleObject implements java.lang.reflect.GenericDeclaration java.lang.reflect.Member {
    -+    method public <A extends java.lang.annotation.Annotation> A getAnnotation(java.lang.Class<A>);
    -     method public java.lang.Class<T> getDeclaringClass();
    -     method public java.lang.Class<?>[] getExceptionTypes();
    -     method public java.lang.reflect.Type[] getGenericExceptionTypes();
    -@@ -55523,7 +55523,7 @@ package java.lang.reflect {
    - 
    -   public final class Field extends java.lang.reflect.AccessibleObject implements java.lang.reflect.Member {
    -     method public java.lang.Object get(java.lang.Object) throws java.lang.IllegalAccessException, java.lang.IllegalArgumentException;
    --    method public A getAnnotation(java.lang.Class<A>);
    -+    method public <A extends java.lang.annotation.Annotation> A getAnnotation(java.lang.Class<A>);
    -     method public boolean getBoolean(java.lang.Object) throws java.lang.IllegalAccessException, java.lang.IllegalArgumentException;
    -     method public byte getByte(java.lang.Object) throws java.lang.IllegalAccessException, java.lang.IllegalArgumentException;
    -     method public char getChar(java.lang.Object) throws java.lang.IllegalAccessException, java.lang.IllegalArgumentException;
    -@@ -55589,7 +55589,7 @@ package java.lang.reflect {
    -   }
    - 
    -   public final class Method extends java.lang.reflect.AccessibleObject implements java.lang.reflect.GenericDeclaration java.lang.reflect.Member {
    --    method public A getAnnotation(java.lang.Class<A>);
    -+    method public <A extends java.lang.annotation.Annotation> A getAnnotation(java.lang.Class<A>);
    -     method public java.lang.Class<?> getDeclaringClass();
    -     method public java.lang.Object getDefaultValue();
    -     method public java.lang.Class<?>[] getExceptionTypes();
    -@@ -55667,7 +55667,7 @@ package java.lang.reflect {
    -   public abstract interface Type {
    -   }
    - 
    --  public abstract interface TypeVariable implements java.lang.reflect.Type {
    -+  public abstract interface TypeVariable<D extends java.lang.reflect.GenericDeclaration> implements java.lang.reflect.Type {
    -     method public abstract java.lang.reflect.Type[] getBounds();
    -     method public abstract D getGenericDeclaration();
    -     method public abstract java.lang.String getName();
    -@@ -56456,7 +56456,7 @@ package java.net {
    -     method public abstract java.net.SocketImpl createSocketImpl();
    -   }
    - 
    --  public abstract interface SocketOption {
    -+  public abstract interface SocketOption<T> {
    -     method public abstract java.lang.String name();
    -     method public abstract java.lang.Class<T> type();
    -   }
    -@@ -57040,7 +57040,7 @@ package java.nio.channels {
    -     method public final long read(java.nio.ByteBuffer[]) throws java.io.IOException;
    -     method public abstract java.net.SocketAddress receive(java.nio.ByteBuffer) throws java.io.IOException;
    -     method public abstract int send(java.nio.ByteBuffer, java.net.SocketAddress) throws java.io.IOException;
    --    method public abstract java.nio.channels.DatagramChannel setOption(java.net.SocketOption<T>, T) throws java.io.IOException;
    -+    method public abstract <T> java.nio.channels.DatagramChannel setOption(java.net.SocketOption<T>, T) throws java.io.IOException;
    -     method public abstract java.net.DatagramSocket socket();
    -     method public final int validOps();
    -     method public abstract int write(java.nio.ByteBuffer) throws java.io.IOException;
    -@@ -57116,8 +57116,8 @@ package java.nio.channels {
    -   public abstract interface NetworkChannel implements java.nio.channels.Channel {
    -     method public abstract java.nio.channels.NetworkChannel bind(java.net.SocketAddress) throws java.io.IOException;
    -     method public abstract java.net.SocketAddress getLocalAddress() throws java.io.IOException;
    --    method public abstract T getOption(java.net.SocketOption<T>) throws java.io.IOException;
    --    method public abstract java.nio.channels.NetworkChannel setOption(java.net.SocketOption<T>, T) throws java.io.IOException;
    -+    method public abstract <T> T getOption(java.net.SocketOption<T>) throws java.io.IOException;
    -+    method public abstract <T> java.nio.channels.NetworkChannel setOption(java.net.SocketOption<T>, T) throws java.io.IOException;
    -     method public abstract java.util.Set<java.net.SocketOption<?>> supportedOptions();
    -   }
    - 
    -@@ -57234,7 +57234,7 @@ package java.nio.channels {
    -     method public final java.nio.channels.ServerSocketChannel bind(java.net.SocketAddress) throws java.io.IOException;
    -     method public abstract java.nio.channels.ServerSocketChannel bind(java.net.SocketAddress, int) throws java.io.IOException;
    -     method public static java.nio.channels.ServerSocketChannel open() throws java.io.IOException;
    --    method public abstract java.nio.channels.ServerSocketChannel setOption(java.net.SocketOption<T>, T) throws java.io.IOException;
    -+    method public abstract <T> java.nio.channels.ServerSocketChannel setOption(java.net.SocketOption<T>, T) throws java.io.IOException;
    -     method public abstract java.net.ServerSocket socket();
    -     method public final int validOps();
    -   }
    -@@ -57252,7 +57252,7 @@ package java.nio.channels {
    -     method public abstract int read(java.nio.ByteBuffer) throws java.io.IOException;
    -     method public abstract long read(java.nio.ByteBuffer[], int, int) throws java.io.IOException;
    -     method public final long read(java.nio.ByteBuffer[]) throws java.io.IOException;
    --    method public abstract java.nio.channels.SocketChannel setOption(java.net.SocketOption<T>, T) throws java.io.IOException;
    -+    method public abstract <T> java.nio.channels.SocketChannel setOption(java.net.SocketOption<T>, T) throws java.io.IOException;
    -     method public abstract java.nio.channels.SocketChannel shutdownInput() throws java.io.IOException;
    -     method public abstract java.nio.channels.SocketChannel shutdownOutput() throws java.io.IOException;
    -     method public abstract java.net.Socket socket();
    -@@ -57499,12 +57499,12 @@ package java.security {
    - 
    -   public final class AccessController {
    -     method public static void checkPermission(java.security.Permission) throws java.security.AccessControlException;
    --    method public static T doPrivileged(java.security.PrivilegedAction<T>);
    --    method public static T doPrivileged(java.security.PrivilegedAction<T>, java.security.AccessControlContext);
    --    method public static T doPrivileged(java.security.PrivilegedExceptionAction<T>) throws java.security.PrivilegedActionException;
    --    method public static T doPrivileged(java.security.PrivilegedExceptionAction<T>, java.security.AccessControlContext) throws java.security.PrivilegedActionException;
    --    method public static T doPrivilegedWithCombiner(java.security.PrivilegedAction<T>);
    --    method public static T doPrivilegedWithCombiner(java.security.PrivilegedExceptionAction<T>) throws java.security.PrivilegedActionException;
    -+    method public static <T> T doPrivileged(java.security.PrivilegedAction<T>);
    -+    method public static <T> T doPrivileged(java.security.PrivilegedAction<T>, java.security.AccessControlContext);
    -+    method public static <T> T doPrivileged(java.security.PrivilegedExceptionAction<T>) throws java.security.PrivilegedActionException;
    -+    method public static <T> T doPrivileged(java.security.PrivilegedExceptionAction<T>, java.security.AccessControlContext) throws java.security.PrivilegedActionException;
    -+    method public static <T> T doPrivilegedWithCombiner(java.security.PrivilegedAction<T>);
    -+    method public static <T> T doPrivilegedWithCombiner(java.security.PrivilegedExceptionAction<T>) throws java.security.PrivilegedActionException;
    -     method public static java.security.AccessControlContext getContext();
    -   }
    - 
    -@@ -57543,7 +57543,7 @@ package java.security {
    -     method public static java.security.AlgorithmParameters getInstance(java.lang.String) throws java.security.NoSuchAlgorithmException;
    -     method public static java.security.AlgorithmParameters getInstance(java.lang.String, java.lang.String) throws java.security.NoSuchAlgorithmException, java.security.NoSuchProviderException;
    -     method public static java.security.AlgorithmParameters getInstance(java.lang.String, java.security.Provider) throws java.security.NoSuchAlgorithmException;
    --    method public final T getParameterSpec(java.lang.Class<T>) throws java.security.spec.InvalidParameterSpecException;
    -+    method public final <T extends java.security.spec.AlgorithmParameterSpec> T getParameterSpec(java.lang.Class<T>) throws java.security.spec.InvalidParameterSpecException;
    -     method public final java.security.Provider getProvider();
    -     method public final void init(java.security.spec.AlgorithmParameterSpec) throws java.security.spec.InvalidParameterSpecException;
    -     method public final void init(byte[]) throws java.io.IOException;
    -@@ -57555,7 +57555,7 @@ package java.security {
    -     ctor public AlgorithmParametersSpi();
    -     method protected abstract byte[] engineGetEncoded() throws java.io.IOException;
    -     method protected abstract byte[] engineGetEncoded(java.lang.String) throws java.io.IOException;
    --    method protected abstract T engineGetParameterSpec(java.lang.Class<T>) throws java.security.spec.InvalidParameterSpecException;
    -+    method protected abstract <T extends java.security.spec.AlgorithmParameterSpec> T engineGetParameterSpec(java.lang.Class<T>) throws java.security.spec.InvalidParameterSpecException;
    -     method protected abstract void engineInit(java.security.spec.AlgorithmParameterSpec) throws java.security.spec.InvalidParameterSpecException;
    -     method protected abstract void engineInit(byte[]) throws java.io.IOException;
    -     method protected abstract void engineInit(byte[], java.lang.String) throws java.io.IOException;
    -@@ -57740,7 +57740,7 @@ package java.security {
    -     method public static java.security.KeyFactory getInstance(java.lang.String) throws java.security.NoSuchAlgorithmException;
    -     method public static java.security.KeyFactory getInstance(java.lang.String, java.lang.String) throws java.security.NoSuchAlgorithmException, java.security.NoSuchProviderException;
    -     method public static java.security.KeyFactory getInstance(java.lang.String, java.security.Provider) throws java.security.NoSuchAlgorithmException;
    --    method public final T getKeySpec(java.security.Key, java.lang.Class<T>) throws java.security.spec.InvalidKeySpecException;
    -+    method public final <T extends java.security.spec.KeySpec> T getKeySpec(java.security.Key, java.lang.Class<T>) throws java.security.spec.InvalidKeySpecException;
    -     method public final java.security.Provider getProvider();
    -     method public final java.security.Key translateKey(java.security.Key) throws java.security.InvalidKeyException;
    -   }
    -@@ -57749,7 +57749,7 @@ package java.security {
    -     ctor public KeyFactorySpi();
    -     method protected abstract java.security.PrivateKey engineGeneratePrivate(java.security.spec.KeySpec) throws java.security.spec.InvalidKeySpecException;
    -     method protected abstract java.security.PublicKey engineGeneratePublic(java.security.spec.KeySpec) throws java.security.spec.InvalidKeySpecException;
    --    method protected abstract T engineGetKeySpec(java.security.Key, java.lang.Class<T>) throws java.security.spec.InvalidKeySpecException;
    -+    method protected abstract <T extends java.security.spec.KeySpec> T engineGetKeySpec(java.security.Key, java.lang.Class<T>) throws java.security.spec.InvalidKeySpecException;
    -     method protected abstract java.security.Key engineTranslateKey(java.security.Key) throws java.security.InvalidKeyException;
    -   }
    - 
    -@@ -58018,7 +58018,7 @@ package java.security {
    -     field public static final long serialVersionUID = 6034044314589513430L; // 0x53bd3b559a12c6d6L
    -   }
    - 
    --  public abstract interface PrivilegedAction {
    -+  public abstract interface PrivilegedAction<T> {
    -     method public abstract T run();
    -   }
    - 
    -@@ -58027,7 +58027,7 @@ package java.security {
    -     method public java.lang.Exception getException();
    -   }
    - 
    --  public abstract interface PrivilegedExceptionAction {
    -+  public abstract interface PrivilegedExceptionAction<T> {
    -     method public abstract T run() throws java.lang.Exception;
    -   }
    - 
    -@@ -60209,11 +60209,11 @@ package java.sql {
    -     method public abstract void free() throws java.sql.SQLException;
    -     method public abstract java.io.InputStream getBinaryStream() throws java.sql.SQLException;
    -     method public abstract java.io.Reader getCharacterStream() throws java.sql.SQLException;
    --    method public abstract T getSource(java.lang.Class<T>) throws java.sql.SQLException;
    -+    method public abstract <T extends javax.xml.transform.Source> T getSource(java.lang.Class<T>) throws java.sql.SQLException;
    -     method public abstract java.lang.String getString() throws java.sql.SQLException;
    -     method public abstract java.io.OutputStream setBinaryStream() throws java.sql.SQLException;
    -     method public abstract java.io.Writer setCharacterStream() throws java.sql.SQLException;
    --    method public abstract T setResult(java.lang.Class<T>) throws java.sql.SQLException;
    -+    method public abstract <T extends javax.xml.transform.Result> T setResult(java.lang.Class<T>) throws java.sql.SQLException;
    -     method public abstract void setString(java.lang.String) throws java.sql.SQLException;
    -   }
    - 
    -@@ -60337,7 +60337,7 @@ package java.sql {
    - 
    -   public abstract interface Wrapper {
    -     method public abstract boolean isWrapperFor(java.lang.Class<?>) throws java.sql.SQLException;
    --    method public abstract T unwrap(java.lang.Class<T>) throws java.sql.SQLException;
    -+    method public abstract <T> T unwrap(java.lang.Class<T>) throws java.sql.SQLException;
    -   }
    - 
    - }
    -@@ -60870,7 +60870,7 @@ package java.text {
    - 
    - package java.util {
    - 
    --  public abstract class AbstractCollection implements java.util.Collection {
    -+  public abstract class AbstractCollection<E> implements java.util.Collection {
    -     ctor protected AbstractCollection();
    -     method public boolean add(E);
    -     method public boolean addAll(java.util.Collection<? extends E>);
    -@@ -60884,10 +60884,10 @@ package java.util {
    -     method public boolean retainAll(java.util.Collection<?>);
    -     method public abstract int size();
    -     method public java.lang.Object[] toArray();
    --    method public T[] toArray(T[]);
    -+    method public <T> T[] toArray(T[]);
    -   }
    - 
    --  public abstract class AbstractList extends java.util.AbstractCollection implements java.util.List {
    -+  public abstract class AbstractList<E> extends java.util.AbstractCollection implements java.util.List {
    -     ctor protected AbstractList();
    -     method public void add(int, E);
    -     method public boolean addAll(int, java.util.Collection<? extends E>);
    -@@ -60904,7 +60904,7 @@ package java.util {
    -     field protected transient int modCount;
    -   }
    - 
    --  public abstract class AbstractMap implements java.util.Map {
    -+  public abstract class AbstractMap<K, V> implements java.util.Map {
    -     ctor protected AbstractMap();
    -     method public void clear();
    -     method public boolean containsKey(java.lang.Object);
    -@@ -60920,7 +60920,7 @@ package java.util {
    -     method public java.util.Collection<V> values();
    -   }
    - 
    --  public static class AbstractMap.SimpleEntry implements java.util.Map.Entry java.io.Serializable {
    -+  public static class AbstractMap.SimpleEntry<K, V> implements java.util.Map.Entry java.io.Serializable {
    -     ctor public AbstractMap.SimpleEntry(K, V);
    -     ctor public AbstractMap.SimpleEntry(java.util.Map.Entry<? extends K, ? extends V>);
    -     method public K getKey();
    -@@ -60928,7 +60928,7 @@ package java.util {
    -     method public V setValue(V);
    -   }
    - 
    --  public static class AbstractMap.SimpleImmutableEntry implements java.util.Map.Entry java.io.Serializable {
    -+  public static class AbstractMap.SimpleImmutableEntry<K, V> implements java.util.Map.Entry java.io.Serializable {
    -     ctor public AbstractMap.SimpleImmutableEntry(K, V);
    -     ctor public AbstractMap.SimpleImmutableEntry(java.util.Map.Entry<? extends K, ? extends V>);
    -     method public K getKey();
    -@@ -60936,23 +60936,23 @@ package java.util {
    -     method public V setValue(V);
    -   }
    - 
    --  public abstract class AbstractQueue extends java.util.AbstractCollection implements java.util.Queue {
    -+  public abstract class AbstractQueue<E> extends java.util.AbstractCollection implements java.util.Queue {
    -     ctor protected AbstractQueue();
    -     method public E element();
    -     method public E remove();
    -   }
    - 
    --  public abstract class AbstractSequentialList extends java.util.AbstractList {
    -+  public abstract class AbstractSequentialList<E> extends java.util.AbstractList {
    -     ctor protected AbstractSequentialList();
    -     method public E get(int);
    -     method public abstract java.util.ListIterator<E> listIterator(int);
    -   }
    - 
    --  public abstract class AbstractSet extends java.util.AbstractCollection implements java.util.Set {
    -+  public abstract class AbstractSet<E> extends java.util.AbstractCollection implements java.util.Set {
    -     ctor protected AbstractSet();
    -   }
    - 
    --  public class ArrayDeque extends java.util.AbstractCollection implements java.lang.Cloneable java.util.Deque java.io.Serializable {
    -+  public class ArrayDeque<E> extends java.util.AbstractCollection implements java.lang.Cloneable java.util.Deque java.io.Serializable {
    -     ctor public ArrayDeque();
    -     ctor public ArrayDeque(int);
    -     ctor public ArrayDeque(java.util.Collection<? extends E>);
    -@@ -60984,7 +60984,7 @@ package java.util {
    -     method public java.util.Spliterator<E> spliterator();
    -   }
    - 
    --  public class ArrayList extends java.util.AbstractList implements java.lang.Cloneable java.util.List java.util.RandomAccess java.io.Serializable {
    -+  public class ArrayList<E> extends java.util.AbstractList implements java.lang.Cloneable java.util.List java.util.RandomAccess java.io.Serializable {
    -     ctor public ArrayList(int);
    -     ctor public ArrayList();
    -     ctor public ArrayList(java.util.Collection<? extends E>);
    -@@ -61001,7 +61001,7 @@ package java.util {
    -   }
    - 
    -   public class Arrays {
    --    method public static java.util.List<T> asList(T...);
    -+    method public static <T> java.util.List<T> asList(T...);
    -     method public static int binarySearch(long[], long);
    -     method public static int binarySearch(long[], int, int, long);
    -     method public static int binarySearch(int[], int);
    -@@ -61018,10 +61018,10 @@ package java.util {
    -     method public static int binarySearch(float[], int, int, float);
    -     method public static int binarySearch(java.lang.Object[], java.lang.Object);
    -     method public static int binarySearch(java.lang.Object[], int, int, java.lang.Object);
    --    method public static int binarySearch(T[], T, java.util.Comparator<? super T>);
    --    method public static int binarySearch(T[], int, int, T, java.util.Comparator<? super T>);
    --    method public static T[] copyOf(T[], int);
    --    method public static T[] copyOf(U[], int, java.lang.Class<? extends T[]>);
    -+    method public static <T> int binarySearch(T[], T, java.util.Comparator<? super T>);
    -+    method public static <T> int binarySearch(T[], int, int, T, java.util.Comparator<? super T>);
    -+    method public static <T> T[] copyOf(T[], int);
    -+    method public static <T, U> T[] copyOf(U[], int, java.lang.Class<? extends T[]>);
    -     method public static byte[] copyOf(byte[], int);
    -     method public static short[] copyOf(short[], int);
    -     method public static int[] copyOf(int[], int);
    -@@ -61030,8 +61030,8 @@ package java.util {
    -     method public static float[] copyOf(float[], int);
    -     method public static double[] copyOf(double[], int);
    -     method public static boolean[] copyOf(boolean[], int);
    --    method public static T[] copyOfRange(T[], int, int);
    --    method public static T[] copyOfRange(U[], int, int, java.lang.Class<? extends T[]>);
    -+    method public static <T> T[] copyOfRange(T[], int, int);
    -+    method public static <T, U> T[] copyOfRange(U[], int, int, java.lang.Class<? extends T[]>);
    -     method public static byte[] copyOfRange(byte[], int, int);
    -     method public static short[] copyOfRange(short[], int, int);
    -     method public static int[] copyOfRange(int[], int, int);
    -@@ -61079,15 +61079,15 @@ package java.util {
    -     method public static int hashCode(float[]);
    -     method public static int hashCode(double[]);
    -     method public static int hashCode(java.lang.Object[]);
    --    method public static void parallelPrefix(T[], java.util.function.BinaryOperator<T>);
    --    method public static void parallelPrefix(T[], int, int, java.util.function.BinaryOperator<T>);
    -+    method public static <T> void parallelPrefix(T[], java.util.function.BinaryOperator<T>);
    -+    method public static <T> void parallelPrefix(T[], int, int, java.util.function.BinaryOperator<T>);
    -     method public static void parallelPrefix(long[], java.util.function.LongBinaryOperator);
    -     method public static void parallelPrefix(long[], int, int, java.util.function.LongBinaryOperator);
    -     method public static void parallelPrefix(double[], java.util.function.DoubleBinaryOperator);
    -     method public static void parallelPrefix(double[], int, int, java.util.function.DoubleBinaryOperator);
    -     method public static void parallelPrefix(int[], java.util.function.IntBinaryOperator);
    -     method public static void parallelPrefix(int[], int, int, java.util.function.IntBinaryOperator);
    --    method public static void parallelSetAll(T[], java.util.function.IntFunction<? extends T>);
    -+    method public static <T> void parallelSetAll(T[], java.util.function.IntFunction<? extends T>);
    -     method public static void parallelSetAll(int[], java.util.function.IntUnaryOperator);
    -     method public static void parallelSetAll(long[], java.util.function.IntToLongFunction);
    -     method public static void parallelSetAll(double[], java.util.function.IntToDoubleFunction);
    -@@ -61105,11 +61105,11 @@ package java.util {
    -     method public static void parallelSort(float[], int, int);
    -     method public static void parallelSort(double[]);
    -     method public static void parallelSort(double[], int, int);
    --    method public static void parallelSort(T[]);
    --    method public static void parallelSort(T[], int, int);
    --    method public static void parallelSort(T[], java.util.Comparator<? super T>);
    --    method public static void parallelSort(T[], int, int, java.util.Comparator<? super T>);
    --    method public static void setAll(T[], java.util.function.IntFunction<? extends T>);
    -+    method public static <T extends java.lang.Comparable<? super T>> void parallelSort(T[]);
    -+    method public static <T extends java.lang.Comparable<? super T>> void parallelSort(T[], int, int);
    -+    method public static <T> void parallelSort(T[], java.util.Comparator<? super T>);
    -+    method public static <T> void parallelSort(T[], int, int, java.util.Comparator<? super T>);
    -+    method public static <T> void setAll(T[], java.util.function.IntFunction<? extends T>);
    -     method public static void setAll(int[], java.util.function.IntUnaryOperator);
    -     method public static void setAll(long[], java.util.function.IntToLongFunction);
    -     method public static void setAll(double[], java.util.function.IntToDoubleFunction);
    -@@ -61129,18 +61129,18 @@ package java.util {
    -     method public static void sort(double[], int, int);
    -     method public static void sort(java.lang.Object[]);
    -     method public static void sort(java.lang.Object[], int, int);
    --    method public static void sort(T[], java.util.Comparator<? super T>);
    --    method public static void sort(T[], int, int, java.util.Comparator<? super T>);
    --    method public static java.util.Spliterator<T> spliterator(T[]);
    --    method public static java.util.Spliterator<T> spliterator(T[], int, int);
    -+    method public static <T> void sort(T[], java.util.Comparator<? super T>);
    -+    method public static <T> void sort(T[], int, int, java.util.Comparator<? super T>);
    -+    method public static <T> java.util.Spliterator<T> spliterator(T[]);
    -+    method public static <T> java.util.Spliterator<T> spliterator(T[], int, int);
    -     method public static java.util.Spliterator.OfInt spliterator(int[]);
    -     method public static java.util.Spliterator.OfInt spliterator(int[], int, int);
    -     method public static java.util.Spliterator.OfLong spliterator(long[]);
    -     method public static java.util.Spliterator.OfLong spliterator(long[], int, int);
    -     method public static java.util.Spliterator.OfDouble spliterator(double[]);
    -     method public static java.util.Spliterator.OfDouble spliterator(double[], int, int);
    --    method public static java.util.stream.Stream<T> stream(T[]);
    --    method public static java.util.stream.Stream<T> stream(T[], int, int);
    -+    method public static <T> java.util.stream.Stream<T> stream(T[]);
    -+    method public static <T> java.util.stream.Stream<T> stream(T[], int, int);
    -     method public static java.util.stream.IntStream stream(int[]);
    -     method public static java.util.stream.IntStream stream(int[], int, int);
    -     method public static java.util.stream.LongStream stream(long[]);
    -@@ -61297,7 +61297,7 @@ package java.util {
    -     field protected long time;
    -   }
    - 
    --  public abstract interface Collection implements java.lang.Iterable {
    -+  public abstract interface Collection<E> implements java.lang.Iterable {
    -     method public abstract boolean add(E);
    -     method public abstract boolean addAll(java.util.Collection<? extends E>);
    -     method public abstract void clear();
    -@@ -61315,86 +61315,86 @@ package java.util {
    -     method public abstract int size();
    -     method public default java.util.stream.Stream<E> stream();
    -     method public abstract java.lang.Object[] toArray();
    --    method public abstract T[] toArray(T[]);
    -+    method public abstract <T> T[] toArray(T[]);
    -   }
    - 
    -   public class Collections {
    --    method public static boolean addAll(java.util.Collection<? super T>, T...);
    --    method public static java.util.Queue<T> asLifoQueue(java.util.Deque<T>);
    --    method public static int binarySearch(java.util.List<? extends java.lang.Comparable<? super T>>, T);
    --    method public static int binarySearch(java.util.List<? extends T>, T, java.util.Comparator<? super T>);
    --    method public static java.util.Collection<E> checkedCollection(java.util.Collection<E>, java.lang.Class<E>);
    --    method public static java.util.List<E> checkedList(java.util.List<E>, java.lang.Class<E>);
    --    method public static java.util.Map<K, V> checkedMap(java.util.Map<K, V>, java.lang.Class<K>, java.lang.Class<V>);
    --    method public static java.util.Set<E> checkedSet(java.util.Set<E>, java.lang.Class<E>);
    --    method public static java.util.SortedMap<K, V> checkedSortedMap(java.util.SortedMap<K, V>, java.lang.Class<K>, java.lang.Class<V>);
    --    method public static java.util.SortedSet<E> checkedSortedSet(java.util.SortedSet<E>, java.lang.Class<E>);
    --    method public static void copy(java.util.List<? super T>, java.util.List<? extends T>);
    -+    method public static <T> boolean addAll(java.util.Collection<? super T>, T...);
    -+    method public static <T> java.util.Queue<T> asLifoQueue(java.util.Deque<T>);
    -+    method public static <T> int binarySearch(java.util.List<? extends java.lang.Comparable<? super T>>, T);
    -+    method public static <T> int binarySearch(java.util.List<? extends T>, T, java.util.Comparator<? super T>);
    -+    method public static <E> java.util.Collection<E> checkedCollection(java.util.Collection<E>, java.lang.Class<E>);
    -+    method public static <E> java.util.List<E> checkedList(java.util.List<E>, java.lang.Class<E>);
    -+    method public static <K, V> java.util.Map<K, V> checkedMap(java.util.Map<K, V>, java.lang.Class<K>, java.lang.Class<V>);
    -+    method public static <E> java.util.Set<E> checkedSet(java.util.Set<E>, java.lang.Class<E>);
    -+    method public static <K, V> java.util.SortedMap<K, V> checkedSortedMap(java.util.SortedMap<K, V>, java.lang.Class<K>, java.lang.Class<V>);
    -+    method public static <E> java.util.SortedSet<E> checkedSortedSet(java.util.SortedSet<E>, java.lang.Class<E>);
    -+    method public static <T> void copy(java.util.List<? super T>, java.util.List<? extends T>);
    -     method public static boolean disjoint(java.util.Collection<?>, java.util.Collection<?>);
    --    method public static java.util.Enumeration<T> emptyEnumeration();
    --    method public static java.util.Iterator<T> emptyIterator();
    --    method public static final java.util.List<T> emptyList();
    --    method public static java.util.ListIterator<T> emptyListIterator();
    --    method public static final java.util.Map<K, V> emptyMap();
    --    method public static final java.util.Set<T> emptySet();
    --    method public static java.util.Enumeration<T> enumeration(java.util.Collection<T>);
    --    method public static void fill(java.util.List<? super T>, T);
    -+    method public static <T> java.util.Enumeration<T> emptyEnumeration();
    -+    method public static <T> java.util.Iterator<T> emptyIterator();
    -+    method public static final <T> java.util.List<T> emptyList();
    -+    method public static <T> java.util.ListIterator<T> emptyListIterator();
    -+    method public static final <K, V> java.util.Map<K, V> emptyMap();
    -+    method public static final <T> java.util.Set<T> emptySet();
    -+    method public static <T> java.util.Enumeration<T> enumeration(java.util.Collection<T>);
    -+    method public static <T> void fill(java.util.List<? super T>, T);
    -     method public static int frequency(java.util.Collection<?>, java.lang.Object);
    -     method public static int indexOfSubList(java.util.List<?>, java.util.List<?>);
    -     method public static int lastIndexOfSubList(java.util.List<?>, java.util.List<?>);
    --    method public static java.util.ArrayList<T> list(java.util.Enumeration<T>);
    --    method public static T max(java.util.Collection<? extends T>);
    --    method public static T max(java.util.Collection<? extends T>, java.util.Comparator<? super T>);
    --    method public static T min(java.util.Collection<? extends T>);
    --    method public static T min(java.util.Collection<? extends T>, java.util.Comparator<? super T>);
    --    method public static java.util.List<T> nCopies(int, T);
    --    method public static java.util.Set<E> newSetFromMap(java.util.Map<E, java.lang.Boolean>);
    --    method public static boolean replaceAll(java.util.List<T>, T, T);
    -+    method public static <T> java.util.ArrayList<T> list(java.util.Enumeration<T>);
    -+    method public static <T extends java.lang.Object & java.lang.Comparable<? super T>> T max(java.util.Collection<? extends T>);
    -+    method public static <T> T max(java.util.Collection<? extends T>, java.util.Comparator<? super T>);
    -+    method public static <T extends java.lang.Object & java.lang.Comparable<? super T>> T min(java.util.Collection<? extends T>);
    -+    method public static <T> T min(java.util.Collection<? extends T>, java.util.Comparator<? super T>);
    -+    method public static <T> java.util.List<T> nCopies(int, T);
    -+    method public static <E> java.util.Set<E> newSetFromMap(java.util.Map<E, java.lang.Boolean>);
    -+    method public static <T> boolean replaceAll(java.util.List<T>, T, T);
    -     method public static void reverse(java.util.List<?>);
    --    method public static java.util.Comparator<T> reverseOrder();
    --    method public static java.util.Comparator<T> reverseOrder(java.util.Comparator<T>);
    -+    method public static <T> java.util.Comparator<T> reverseOrder();
    -+    method public static <T> java.util.Comparator<T> reverseOrder(java.util.Comparator<T>);
    -     method public static void rotate(java.util.List<?>, int);
    -     method public static void shuffle(java.util.List<?>);
    -     method public static void shuffle(java.util.List<?>, java.util.Random);
    --    method public static java.util.Set<E> singleton(E);
    --    method public static java.util.List<E> singletonList(E);
    --    method public static java.util.Map<K, V> singletonMap(K, V);
    --    method public static void sort(java.util.List<T>);
    --    method public static void sort(java.util.List<T>, java.util.Comparator<? super T>);
    -+    method public static <E> java.util.Set<E> singleton(E);
    -+    method public static <E> java.util.List<E> singletonList(E);
    -+    method public static <K, V> java.util.Map<K, V> singletonMap(K, V);
    -+    method public static <T extends java.lang.Comparable<? super T>> void sort(java.util.List<T>);
    -+    method public static <T> void sort(java.util.List<T>, java.util.Comparator<? super T>);
    -     method public static void swap(java.util.List<?>, int, int);
    --    method public static java.util.Collection<T> synchronizedCollection(java.util.Collection<T>);
    --    method public static java.util.List<T> synchronizedList(java.util.List<T>);
    --    method public static java.util.Map<K, V> synchronizedMap(java.util.Map<K, V>);
    --    method public static java.util.Set<T> synchronizedSet(java.util.Set<T>);
    --    method public static java.util.SortedMap<K, V> synchronizedSortedMap(java.util.SortedMap<K, V>);
    --    method public static java.util.SortedSet<T> synchronizedSortedSet(java.util.SortedSet<T>);
    --    method public static java.util.Collection<T> unmodifiableCollection(java.util.Collection<? extends T>);
    --    method public static java.util.List<T> unmodifiableList(java.util.List<? extends T>);
    --    method public static java.util.Map<K, V> unmodifiableMap(java.util.Map<? extends K, ? extends V>);
    --    method public static java.util.Set<T> unmodifiableSet(java.util.Set<? extends T>);
    --    method public static java.util.SortedMap<K, V> unmodifiableSortedMap(java.util.SortedMap<K, ? extends V>);
    --    method public static java.util.SortedSet<T> unmodifiableSortedSet(java.util.SortedSet<T>);
    -+    method public static <T> java.util.Collection<T> synchronizedCollection(java.util.Collection<T>);
    -+    method public static <T> java.util.List<T> synchronizedList(java.util.List<T>);
    -+    method public static <K, V> java.util.Map<K, V> synchronizedMap(java.util.Map<K, V>);
    -+    method public static <T> java.util.Set<T> synchronizedSet(java.util.Set<T>);
    -+    method public static <K, V> java.util.SortedMap<K, V> synchronizedSortedMap(java.util.SortedMap<K, V>);
    -+    method public static <T> java.util.SortedSet<T> synchronizedSortedSet(java.util.SortedSet<T>);
    -+    method public static <T> java.util.Collection<T> unmodifiableCollection(java.util.Collection<? extends T>);
    -+    method public static <T> java.util.List<T> unmodifiableList(java.util.List<? extends T>);
    -+    method public static <K, V> java.util.Map<K, V> unmodifiableMap(java.util.Map<? extends K, ? extends V>);
    -+    method public static <T> java.util.Set<T> unmodifiableSet(java.util.Set<? extends T>);
    -+    method public static <K, V> java.util.SortedMap<K, V> unmodifiableSortedMap(java.util.SortedMap<K, ? extends V>);
    -+    method public static <T> java.util.SortedSet<T> unmodifiableSortedSet(java.util.SortedSet<T>);
    -     field public static final java.util.List EMPTY_LIST;
    -     field public static final java.util.Map EMPTY_MAP;
    -     field public static final java.util.Set EMPTY_SET;
    -   }
    - 
    --  public abstract interface Comparator {
    -+  public abstract interface Comparator<T> {
    -     method public abstract int compare(T, T);
    --    method public static java.util.Comparator<T> comparing(java.util.function.Function<? super T, ? extends U>, java.util.Comparator<? super U>);
    --    method public static java.util.Comparator<T> comparing(java.util.function.Function<? super T, ? extends U>);
    --    method public static java.util.Comparator<T> comparingDouble(java.util.function.ToDoubleFunction<? super T>);
    --    method public static java.util.Comparator<T> comparingInt(java.util.function.ToIntFunction<? super T>);
    --    method public static java.util.Comparator<T> comparingLong(java.util.function.ToLongFunction<? super T>);
    -+    method public static <T, U> java.util.Comparator<T> comparing(java.util.function.Function<? super T, ? extends U>, java.util.Comparator<? super U>);
    -+    method public static <T, U extends java.lang.Comparable<? super U>> java.util.Comparator<T> comparing(java.util.function.Function<? super T, ? extends U>);
    -+    method public static <T> java.util.Comparator<T> comparingDouble(java.util.function.ToDoubleFunction<? super T>);
    -+    method public static <T> java.util.Comparator<T> comparingInt(java.util.function.ToIntFunction<? super T>);
    -+    method public static <T> java.util.Comparator<T> comparingLong(java.util.function.ToLongFunction<? super T>);
    -     method public abstract boolean equals(java.lang.Object);
    --    method public static java.util.Comparator<T> naturalOrder();
    --    method public static java.util.Comparator<T> nullsFirst(java.util.Comparator<? super T>);
    --    method public static java.util.Comparator<T> nullsLast(java.util.Comparator<? super T>);
    --    method public static java.util.Comparator<T> reverseOrder();
    -+    method public static <T extends java.lang.Comparable<? super T>> java.util.Comparator<T> naturalOrder();
    -+    method public static <T> java.util.Comparator<T> nullsFirst(java.util.Comparator<? super T>);
    -+    method public static <T> java.util.Comparator<T> nullsLast(java.util.Comparator<? super T>);
    -+    method public static <T extends java.lang.Comparable<? super T>> java.util.Comparator<T> reverseOrder();
    -     method public default java.util.Comparator<T> reversed();
    -     method public default java.util.Comparator<T> thenComparing(java.util.Comparator<? super T>);
    --    method public default java.util.Comparator<T> thenComparing(java.util.function.Function<? super T, ? extends U>, java.util.Comparator<? super U>);
    --    method public default java.util.Comparator<T> thenComparing(java.util.function.Function<? super T, ? extends U>);
    -+    method public default <U> java.util.Comparator<T> thenComparing(java.util.function.Function<? super T, ? extends U>, java.util.Comparator<? super U>);
    -+    method public default <U extends java.lang.Comparable<? super U>> java.util.Comparator<T> thenComparing(java.util.function.Function<? super T, ? extends U>);
    -     method public default java.util.Comparator<T> thenComparingDouble(java.util.function.ToDoubleFunction<? super T>);
    -     method public default java.util.Comparator<T> thenComparingInt(java.util.function.ToIntFunction<? super T>);
    -     method public default java.util.Comparator<T> thenComparingLong(java.util.function.ToLongFunction<? super T>);
    -@@ -61453,7 +61453,7 @@ package java.util {
    -     method public deprecated java.lang.String toLocaleString();
    -   }
    - 
    --  public abstract interface Deque implements java.util.Queue {
    -+  public abstract interface Deque<E> implements java.util.Queue {
    -     method public abstract boolean add(E);
    -     method public abstract void addFirst(E);
    -     method public abstract void addLast(E);
    -@@ -61483,7 +61483,7 @@ package java.util {
    -     method public abstract int size();
    -   }
    - 
    --  public abstract class Dictionary {
    -+  public abstract class Dictionary<K, V> {
    -     ctor public Dictionary();
    -     method public abstract java.util.Enumeration<V> elements();
    -     method public abstract V get(java.lang.Object);
    -@@ -61514,7 +61514,7 @@ package java.util {
    -     ctor public EmptyStackException();
    -   }
    - 
    --  public class EnumMap extends java.util.AbstractMap implements java.lang.Cloneable java.io.Serializable {
    -+  public class EnumMap<K extends java.lang.Enum<K>, V> extends java.util.AbstractMap implements java.lang.Cloneable java.io.Serializable {
    -     ctor public EnumMap(java.lang.Class<K>);
    -     ctor public EnumMap(java.util.EnumMap<K, ? extends V>);
    -     ctor public EnumMap(java.util.Map<K, ? extends V>);
    -@@ -61522,23 +61522,23 @@ package java.util {
    -     method public java.util.Set<java.util.Map.Entry<K, V>> entrySet();
    -   }
    - 
    --  public abstract class EnumSet extends java.util.AbstractSet implements java.lang.Cloneable java.io.Serializable {
    --    method public static java.util.EnumSet<E> allOf(java.lang.Class<E>);
    -+  public abstract class EnumSet<E extends java.lang.Enum<E>> extends java.util.AbstractSet implements java.lang.Cloneable java.io.Serializable {
    -+    method public static <E extends java.lang.Enum<E>> java.util.EnumSet<E> allOf(java.lang.Class<E>);
    -     method public java.util.EnumSet<E> clone();
    --    method public static java.util.EnumSet<E> complementOf(java.util.EnumSet<E>);
    --    method public static java.util.EnumSet<E> copyOf(java.util.EnumSet<E>);
    --    method public static java.util.EnumSet<E> copyOf(java.util.Collection<E>);
    --    method public static java.util.EnumSet<E> noneOf(java.lang.Class<E>);
    --    method public static java.util.EnumSet<E> of(E);
    --    method public static java.util.EnumSet<E> of(E, E);
    --    method public static java.util.EnumSet<E> of(E, E, E);
    --    method public static java.util.EnumSet<E> of(E, E, E, E);
    --    method public static java.util.EnumSet<E> of(E, E, E, E, E);
    --    method public static java.util.EnumSet<E> of(E, E...);
    --    method public static java.util.EnumSet<E> range(E, E);
    --  }
    --
    --  public abstract interface Enumeration {
    -+    method public static <E extends java.lang.Enum<E>> java.util.EnumSet<E> complementOf(java.util.EnumSet<E>);
    -+    method public static <E extends java.lang.Enum<E>> java.util.EnumSet<E> copyOf(java.util.EnumSet<E>);
    -+    method public static <E extends java.lang.Enum<E>> java.util.EnumSet<E> copyOf(java.util.Collection<E>);
    -+    method public static <E extends java.lang.Enum<E>> java.util.EnumSet<E> noneOf(java.lang.Class<E>);
    -+    method public static <E extends java.lang.Enum<E>> java.util.EnumSet<E> of(E);
    -+    method public static <E extends java.lang.Enum<E>> java.util.EnumSet<E> of(E, E);
    -+    method public static <E extends java.lang.Enum<E>> java.util.EnumSet<E> of(E, E, E);
    -+    method public static <E extends java.lang.Enum<E>> java.util.EnumSet<E> of(E, E, E, E);
    -+    method public static <E extends java.lang.Enum<E>> java.util.EnumSet<E> of(E, E, E, E, E);
    -+    method public static <E extends java.lang.Enum<E>> java.util.EnumSet<E> of(E, E...);
    -+    method public static <E extends java.lang.Enum<E>> java.util.EnumSet<E> range(E, E);
    -+  }
    -+
    -+  public abstract interface Enumeration<E> {
    -     method public abstract boolean hasMoreElements();
    -     method public abstract E nextElement();
    -   }
    -@@ -61546,7 +61546,7 @@ package java.util {
    -   public abstract interface EventListener {
    -   }
    - 
    --  public abstract class EventListenerProxy implements java.util.EventListener {
    -+  public abstract class EventListenerProxy<T extends java.util.EventListener> implements java.util.EventListener {
    -     ctor public EventListenerProxy(T);
    -     method public T getListener();
    -   }
    -@@ -61632,7 +61632,7 @@ package java.util {
    -     field public static final int BC = 0; // 0x0
    -   }
    - 
    --  public class HashMap extends java.util.AbstractMap implements java.lang.Cloneable java.util.Map java.io.Serializable {
    -+  public class HashMap<K, V> extends java.util.AbstractMap implements java.lang.Cloneable java.util.Map java.io.Serializable {
    -     ctor public HashMap(int, float);
    -     ctor public HashMap(int);
    -     ctor public HashMap();
    -@@ -61644,7 +61644,7 @@ package java.util {
    -     method public void replaceAll(java.util.function.BiFunction<? super K, ? super V, ? extends V>);
    -   }
    - 
    --  public class HashSet extends java.util.AbstractSet implements java.lang.Cloneable java.io.Serializable java.util.Set {
    -+  public class HashSet<E> extends java.util.AbstractSet implements java.lang.Cloneable java.io.Serializable java.util.Set {
    -     ctor public HashSet();
    -     ctor public HashSet(java.util.Collection<? extends E>);
    -     ctor public HashSet(int, float);
    -@@ -61655,7 +61655,7 @@ package java.util {
    -     method public java.util.Spliterator<E> spliterator();
    -   }
    - 
    --  public class Hashtable extends java.util.Dictionary implements java.lang.Cloneable java.util.Map java.io.Serializable {
    -+  public class Hashtable<K, V> extends java.util.Dictionary implements java.lang.Cloneable java.util.Map java.io.Serializable {
    -     ctor public Hashtable(int, float);
    -     ctor public Hashtable(int);
    -     ctor public Hashtable();
    -@@ -61690,7 +61690,7 @@ package java.util {
    -     method public java.util.Collection<V> values();
    -   }
    - 
    --  public class IdentityHashMap extends java.util.AbstractMap implements java.lang.Cloneable java.util.Map java.io.Serializable {
    -+  public class IdentityHashMap<K, V> extends java.util.AbstractMap implements java.lang.Cloneable java.util.Map java.io.Serializable {
    -     ctor public IdentityHashMap();
    -     ctor public IdentityHashMap(int);
    -     ctor public IdentityHashMap(java.util.Map<? extends K, ? extends V>);
    -@@ -61757,14 +61757,14 @@ package java.util {
    -     ctor public InvalidPropertiesFormatException(java.lang.String);
    -   }
    - 
    --  public abstract interface Iterator {
    -+  public abstract interface Iterator<E> {
    -     method public default void forEachRemaining(java.util.function.Consumer<? super E>);
    -     method public abstract boolean hasNext();
    -     method public abstract E next();
    -     method public default void remove();
    -   }
    - 
    --  public class LinkedHashMap extends java.util.HashMap implements java.util.Map {
    -+  public class LinkedHashMap<K, V> extends java.util.HashMap implements java.util.Map {
    -     ctor public LinkedHashMap(int, float);
    -     ctor public LinkedHashMap(int);
    -     ctor public LinkedHashMap();
    -@@ -61773,14 +61773,14 @@ package java.util {
    -     method protected boolean removeEldestEntry(java.util.Map.Entry<K, V>);
    -   }
    - 
    --  public class LinkedHashSet extends java.util.HashSet implements java.lang.Cloneable java.io.Serializable java.util.Set {
    -+  public class LinkedHashSet<E> extends java.util.HashSet implements java.lang.Cloneable java.io.Serializable java.util.Set {
    -     ctor public LinkedHashSet(int, float);
    -     ctor public LinkedHashSet(int);
    -     ctor public LinkedHashSet();
    -     ctor public LinkedHashSet(java.util.Collection<? extends E>);
    -   }
    - 
    --  public class LinkedList extends java.util.AbstractSequentialList implements java.lang.Cloneable java.util.Deque java.util.List java.io.Serializable {
    -+  public class LinkedList<E> extends java.util.AbstractSequentialList implements java.lang.Cloneable java.util.Deque java.util.List java.io.Serializable {
    -     ctor public LinkedList();
    -     ctor public LinkedList(java.util.Collection<? extends E>);
    -     method public void addFirst(E);
    -@@ -61811,7 +61811,7 @@ package java.util {
    -     method public java.util.Spliterator<E> spliterator();
    -   }
    - 
    --  public abstract interface List implements java.util.Collection {
    -+  public abstract interface List<E> implements java.util.Collection {
    -     method public abstract boolean add(E);
    -     method public abstract void add(int, E);
    -     method public abstract boolean addAll(java.util.Collection<? extends E>);
    -@@ -61838,10 +61838,10 @@ package java.util {
    -     method public default void sort(java.util.Comparator<? super E>);
    -     method public abstract java.util.List<E> subList(int, int);
    -     method public abstract java.lang.Object[] toArray();
    --    method public abstract T[] toArray(T[]);
    -+    method public abstract <T> T[] toArray(T[]);
    -   }
    - 
    --  public abstract interface ListIterator implements java.util.Iterator {
    -+  public abstract interface ListIterator<E> implements java.util.Iterator {
    -     method public abstract void add(E);
    -     method public abstract boolean hasNext();
    -     method public abstract boolean hasPrevious();
    -@@ -61958,7 +61958,7 @@ package java.util {
    -     method public final long getSum();
    -   }
    - 
    --  public abstract interface Map {
    -+  public abstract interface Map<K, V> {
    -     method public abstract void clear();
    -     method public default V compute(K, java.util.function.BiFunction<? super K, ? super V, ? extends V>);
    -     method public default V computeIfAbsent(K, java.util.function.Function<? super K, ? extends V>);
    -@@ -61986,11 +61986,11 @@ package java.util {
    -     method public abstract java.util.Collection<V> values();
    -   }
    - 
    --  public static abstract interface Map.Entry {
    --    method public static java.util.Comparator<java.util.Map.Entry<K, V>> comparingByKey();
    --    method public static java.util.Comparator<java.util.Map.Entry<K, V>> comparingByKey(java.util.Comparator<? super K>);
    --    method public static java.util.Comparator<java.util.Map.Entry<K, V>> comparingByValue();
    --    method public static java.util.Comparator<java.util.Map.Entry<K, V>> comparingByValue(java.util.Comparator<? super V>);
    -+  public static abstract interface Map.Entry<K, V> {
    -+    method public static <K extends java.lang.Comparable<? super K>, V> java.util.Comparator<java.util.Map.Entry<K, V>> comparingByKey();
    -+    method public static <K, V> java.util.Comparator<java.util.Map.Entry<K, V>> comparingByKey(java.util.Comparator<? super K>);
    -+    method public static <K, V extends java.lang.Comparable<? super V>> java.util.Comparator<java.util.Map.Entry<K, V>> comparingByValue();
    -+    method public static <K, V> java.util.Comparator<java.util.Map.Entry<K, V>> comparingByValue(java.util.Comparator<? super V>);
    -     method public abstract boolean equals(java.lang.Object);
    -     method public abstract K getKey();
    -     method public abstract V getValue();
    -@@ -62014,7 +62014,7 @@ package java.util {
    -     method public java.lang.String getKey();
    -   }
    - 
    --  public abstract interface NavigableMap implements java.util.SortedMap {
    -+  public abstract interface NavigableMap<K, V> implements java.util.SortedMap {
    -     method public abstract java.util.Map.Entry<K, V> ceilingEntry(K);
    -     method public abstract K ceilingKey(K);
    -     method public abstract java.util.NavigableSet<K> descendingKeySet();
    -@@ -62038,7 +62038,7 @@ package java.util {
    -     method public abstract java.util.SortedMap<K, V> tailMap(K);
    -   }
    - 
    --  public abstract interface NavigableSet implements java.util.SortedSet {
    -+  public abstract interface NavigableSet<E> implements java.util.SortedSet {
    -     method public abstract E ceiling(E);
    -     method public abstract java.util.Iterator<E> descendingIterator();
    -     method public abstract java.util.NavigableSet<E> descendingSet();
    -@@ -62062,16 +62062,16 @@ package java.util {
    -   }
    - 
    -   public final class Objects {
    --    method public static int compare(T, T, java.util.Comparator<? super T>);
    -+    method public static <T> int compare(T, T, java.util.Comparator<? super T>);
    -     method public static boolean deepEquals(java.lang.Object, java.lang.Object);
    -     method public static boolean equals(java.lang.Object, java.lang.Object);
    -     method public static int hash(java.lang.Object...);
    -     method public static int hashCode(java.lang.Object);
    -     method public static boolean isNull(java.lang.Object);
    -     method public static boolean nonNull(java.lang.Object);
    --    method public static T requireNonNull(T);
    --    method public static T requireNonNull(T, java.lang.String);
    --    method public static T requireNonNull(T, java.util.function.Supplier<java.lang.String>);
    -+    method public static <T> T requireNonNull(T);
    -+    method public static <T> T requireNonNull(T, java.lang.String);
    -+    method public static <T> T requireNonNull(T, java.util.function.Supplier<java.lang.String>);
    -     method public static java.lang.String toString(java.lang.Object);
    -     method public static java.lang.String toString(java.lang.Object, java.lang.String);
    -   }
    -@@ -62093,19 +62093,19 @@ package java.util {
    -     method public abstract void update(java.util.Observable, java.lang.Object);
    -   }
    - 
    --  public final class Optional {
    --    method public static java.util.Optional<T> empty();
    -+  public final class Optional<T> {
    -+    method public static <T> java.util.Optional<T> empty();
    -     method public java.util.Optional<T> filter(java.util.function.Predicate<? super T>);
    --    method public java.util.Optional<U> flatMap(java.util.function.Function<? super T, java.util.Optional<U>>);
    -+    method public <U> java.util.Optional<U> flatMap(java.util.function.Function<? super T, java.util.Optional<U>>);
    -     method public T get();
    -     method public void ifPresent(java.util.function.Consumer<? super T>);
    -     method public boolean isPresent();
    --    method public java.util.Optional<U> map(java.util.function.Function<? super T, ? extends U>);
    --    method public static java.util.Optional<T> of(T);
    --    method public static java.util.Optional<T> ofNullable(T);
    -+    method public <U> java.util.Optional<U> map(java.util.function.Function<? super T, ? extends U>);
    -+    method public static <T> java.util.Optional<T> of(T);
    -+    method public static <T> java.util.Optional<T> ofNullable(T);
    -     method public T orElse(T);
    -     method public T orElseGet(java.util.function.Supplier<? extends T>);
    --    method public T orElseThrow(java.util.function.Supplier<? extends X>) throws java.lang.Throwable;
    -+    method public <X extends java.lang.Throwable> T orElseThrow(java.util.function.Supplier<? extends X>) throws java.lang.Throwable;
    -   }
    - 
    -   public final class OptionalDouble {
    -@@ -62116,7 +62116,7 @@ package java.util {
    -     method public static java.util.OptionalDouble of(double);
    -     method public double orElse(double);
    -     method public double orElseGet(java.util.function.DoubleSupplier);
    --    method public double orElseThrow(java.util.function.Supplier<X>) throws java.lang.Throwable;
    -+    method public <X extends java.lang.Throwable> double orElseThrow(java.util.function.Supplier<X>) throws java.lang.Throwable;
    -   }
    - 
    -   public final class OptionalInt {
    -@@ -62127,7 +62127,7 @@ package java.util {
    -     method public static java.util.OptionalInt of(int);
    -     method public int orElse(int);
    -     method public int orElseGet(java.util.function.IntSupplier);
    --    method public int orElseThrow(java.util.function.Supplier<X>) throws java.lang.Throwable;
    -+    method public <X extends java.lang.Throwable> int orElseThrow(java.util.function.Supplier<X>) throws java.lang.Throwable;
    -   }
    - 
    -   public final class OptionalLong {
    -@@ -62138,10 +62138,10 @@ package java.util {
    -     method public static java.util.OptionalLong of(long);
    -     method public long orElse(long);
    -     method public long orElseGet(java.util.function.LongSupplier);
    --    method public long orElseThrow(java.util.function.Supplier<X>) throws java.lang.Throwable;
    -+    method public <X extends java.lang.Throwable> long orElseThrow(java.util.function.Supplier<X>) throws java.lang.Throwable;
    -   }
    - 
    --  public abstract interface PrimitiveIterator implements java.util.Iterator {
    -+  public abstract interface PrimitiveIterator<T, T_CONS> implements java.util.Iterator {
    -     method public abstract void forEachRemaining(T_CONS);
    -   }
    - 
    -@@ -62166,7 +62166,7 @@ package java.util {
    -     method public abstract long nextLong();
    -   }
    - 
    --  public class PriorityQueue extends java.util.AbstractQueue implements java.io.Serializable {
    -+  public class PriorityQueue<E> extends java.util.AbstractQueue implements java.io.Serializable {
    -     ctor public PriorityQueue();
    -     ctor public PriorityQueue(int);
    -     ctor public PriorityQueue(java.util.Comparator<? super E>);
    -@@ -62215,7 +62215,7 @@ package java.util {
    -     method public java.lang.Object handleGetObject(java.lang.String);
    -   }
    - 
    --  public abstract interface Queue implements java.util.Collection {
    -+  public abstract interface Queue<E> implements java.util.Collection {
    -     method public abstract boolean add(E);
    -     method public abstract E element();
    -     method public abstract boolean offer(E);
    -@@ -62365,15 +62365,15 @@ package java.util {
    -     ctor public ServiceConfigurationError(java.lang.String, java.lang.Throwable);
    -   }
    - 
    --  public final class ServiceLoader implements java.lang.Iterable {
    -+  public final class ServiceLoader<S> implements java.lang.Iterable {
    -     method public java.util.Iterator<S> iterator();
    --    method public static java.util.ServiceLoader<S> load(java.lang.Class<S>, java.lang.ClassLoader);
    --    method public static java.util.ServiceLoader<S> load(java.lang.Class<S>);
    --    method public static java.util.ServiceLoader<S> loadInstalled(java.lang.Class<S>);
    -+    method public static <S> java.util.ServiceLoader<S> load(java.lang.Class<S>, java.lang.ClassLoader);
    -+    method public static <S> java.util.ServiceLoader<S> load(java.lang.Class<S>);
    -+    method public static <S> java.util.ServiceLoader<S> loadInstalled(java.lang.Class<S>);
    -     method public void reload();
    -   }
    - 
    --  public abstract interface Set implements java.util.Collection {
    -+  public abstract interface Set<E> implements java.util.Collection {
    -     method public abstract boolean add(E);
    -     method public abstract boolean addAll(java.util.Collection<? extends E>);
    -     method public abstract void clear();
    -@@ -62388,7 +62388,7 @@ package java.util {
    -     method public abstract boolean retainAll(java.util.Collection<?>);
    -     method public abstract int size();
    -     method public abstract java.lang.Object[] toArray();
    --    method public abstract T[] toArray(T[]);
    -+    method public abstract <T> T[] toArray(T[]);
    -   }
    - 
    -   public class SimpleTimeZone extends java.util.TimeZone {
    -@@ -62414,7 +62414,7 @@ package java.util {
    -     field public static final int WALL_TIME = 0; // 0x0
    -   }
    - 
    --  public abstract interface SortedMap implements java.util.Map {
    -+  public abstract interface SortedMap<K, V> implements java.util.Map {
    -     method public abstract java.util.Comparator<? super K> comparator();
    -     method public abstract java.util.Set<java.util.Map.Entry<K, V>> entrySet();
    -     method public abstract K firstKey();
    -@@ -62426,7 +62426,7 @@ package java.util {
    -     method public abstract java.util.Collection<V> values();
    -   }
    - 
    --  public abstract interface SortedSet implements java.util.Set {
    -+  public abstract interface SortedSet<E> implements java.util.Set {
    -     method public abstract java.util.Comparator<? super E> comparator();
    -     method public abstract E first();
    -     method public abstract java.util.SortedSet<E> headSet(E);
    -@@ -62435,7 +62435,7 @@ package java.util {
    -     method public abstract java.util.SortedSet<E> tailSet(E);
    -   }
    - 
    --  public abstract interface Spliterator {
    -+  public abstract interface Spliterator<T> {
    -     method public abstract int characteristics();
    -     method public abstract long estimateSize();
    -     method public default void forEachRemaining(java.util.function.Consumer<? super T>);
    -@@ -62478,7 +62478,7 @@ package java.util {
    -     method public abstract java.util.Spliterator.OfLong trySplit();
    -   }
    - 
    --  public static abstract interface Spliterator.OfPrimitive implements java.util.Spliterator {
    -+  public static abstract interface Spliterator.OfPrimitive<T, T_CONS, T_SPLITR extends java.util.Spliterator.OfPrimitive<T, T_CONS, T_SPLITR>> implements java.util.Spliterator {
    -     method public default void forEachRemaining(T_CONS);
    -     method public abstract boolean tryAdvance(T_CONS);
    -     method public abstract T_SPLITR trySplit();
    -@@ -62488,25 +62488,25 @@ package java.util {
    -     method public static java.util.Spliterator.OfDouble emptyDoubleSpliterator();
    -     method public static java.util.Spliterator.OfInt emptyIntSpliterator();
    -     method public static java.util.Spliterator.OfLong emptyLongSpliterator();
    --    method public static java.util.Spliterator<T> emptySpliterator();
    --    method public static java.util.Iterator<T> iterator(java.util.Spliterator<? extends T>);
    -+    method public static <T> java.util.Spliterator<T> emptySpliterator();
    -+    method public static <T> java.util.Iterator<T> iterator(java.util.Spliterator<? extends T>);
    -     method public static java.util.PrimitiveIterator.OfInt iterator(java.util.Spliterator.OfInt);
    -     method public static java.util.PrimitiveIterator.OfLong iterator(java.util.Spliterator.OfLong);
    -     method public static java.util.PrimitiveIterator.OfDouble iterator(java.util.Spliterator.OfDouble);
    --    method public static java.util.Spliterator<T> spliterator(java.lang.Object[], int);
    --    method public static java.util.Spliterator<T> spliterator(java.lang.Object[], int, int, int);
    -+    method public static <T> java.util.Spliterator<T> spliterator(java.lang.Object[], int);
    -+    method public static <T> java.util.Spliterator<T> spliterator(java.lang.Object[], int, int, int);
    -     method public static java.util.Spliterator.OfInt spliterator(int[], int);
    -     method public static java.util.Spliterator.OfInt spliterator(int[], int, int, int);
    -     method public static java.util.Spliterator.OfLong spliterator(long[], int);
    -     method public static java.util.Spliterator.OfLong spliterator(long[], int, int, int);
    -     method public static java.util.Spliterator.OfDouble spliterator(double[], int);
    -     method public static java.util.Spliterator.OfDouble spliterator(double[], int, int, int);
    --    method public static java.util.Spliterator<T> spliterator(java.util.Collection<? extends T>, int);
    --    method public static java.util.Spliterator<T> spliterator(java.util.Iterator<? extends T>, long, int);
    -+    method public static <T> java.util.Spliterator<T> spliterator(java.util.Collection<? extends T>, int);
    -+    method public static <T> java.util.Spliterator<T> spliterator(java.util.Iterator<? extends T>, long, int);
    -     method public static java.util.Spliterator.OfInt spliterator(java.util.PrimitiveIterator.OfInt, long, int);
    -     method public static java.util.Spliterator.OfLong spliterator(java.util.PrimitiveIterator.OfLong, long, int);
    -     method public static java.util.Spliterator.OfDouble spliterator(java.util.PrimitiveIterator.OfDouble, long, int);
    --    method public static java.util.Spliterator<T> spliteratorUnknownSize(java.util.Iterator<? extends T>, int);
    -+    method public static <T> java.util.Spliterator<T> spliteratorUnknownSize(java.util.Iterator<? extends T>, int);
    -     method public static java.util.Spliterator.OfInt spliteratorUnknownSize(java.util.PrimitiveIterator.OfInt, int);
    -     method public static java.util.Spliterator.OfLong spliteratorUnknownSize(java.util.PrimitiveIterator.OfLong, int);
    -     method public static java.util.Spliterator.OfDouble spliteratorUnknownSize(java.util.PrimitiveIterator.OfDouble, int);
    -@@ -62533,7 +62533,7 @@ package java.util {
    -     method public java.util.Spliterator.OfLong trySplit();
    -   }
    - 
    --  public static abstract class Spliterators.AbstractSpliterator implements java.util.Spliterator {
    -+  public static abstract class Spliterators.AbstractSpliterator<T> implements java.util.Spliterator {
    -     ctor protected Spliterators.AbstractSpliterator(long, int);
    -     method public int characteristics();
    -     method public long estimateSize();
    -@@ -62568,7 +62568,7 @@ package java.util {
    -     method public java.util.SplittableRandom split();
    -   }
    - 
    --  public class Stack extends java.util.Vector {
    -+  public class Stack<E> extends java.util.Vector {
    -     ctor public Stack();
    -     method public boolean empty();
    -     method public synchronized E peek();
    -@@ -62652,7 +62652,7 @@ package java.util {
    -     ctor public TooManyListenersException(java.lang.String);
    -   }
    - 
    --  public class TreeMap extends java.util.AbstractMap implements java.lang.Cloneable java.util.NavigableMap java.io.Serializable {
    -+  public class TreeMap<K, V> extends java.util.AbstractMap implements java.lang.Cloneable java.util.NavigableMap java.io.Serializable {
    -     ctor public TreeMap();
    -     ctor public TreeMap(java.util.Comparator<? super K>);
    -     ctor public TreeMap(java.util.Map<? extends K, ? extends V>);
    -@@ -62689,7 +62689,7 @@ package java.util {
    -     method public java.util.SortedMap<K, V> tailMap(K);
    -   }
    - 
    --  public class TreeSet extends java.util.AbstractSet implements java.lang.Cloneable java.util.NavigableSet java.io.Serializable {
    -+  public class TreeSet<E> extends java.util.AbstractSet implements java.lang.Cloneable java.util.NavigableSet java.io.Serializable {
    -     ctor public TreeSet();
    -     ctor public TreeSet(java.util.Comparator<? super E>);
    -     ctor public TreeSet(java.util.Collection<? extends E>);
    -@@ -62742,7 +62742,7 @@ package java.util {
    -     method public java.lang.String getFlags();
    -   }
    - 
    --  public class Vector extends java.util.AbstractList implements java.lang.Cloneable java.util.List java.util.RandomAccess java.io.Serializable {
    -+  public class Vector<E> extends java.util.AbstractList implements java.lang.Cloneable java.util.List java.util.RandomAccess java.io.Serializable {
    -     ctor public Vector(int, int);
    -     ctor public Vector(int);
    -     ctor public Vector();
    -@@ -62777,7 +62777,7 @@ package java.util {
    -     field protected java.lang.Object[] elementData;
    -   }
    - 
    --  public class WeakHashMap extends java.util.AbstractMap implements java.util.Map {
    -+  public class WeakHashMap<K, V> extends java.util.AbstractMap implements java.util.Map {
    -     ctor public WeakHashMap(int, float);
    -     ctor public WeakHashMap(int);
    -     ctor public WeakHashMap();
    -@@ -62793,18 +62793,18 @@ package java.util.concurrent {
    - 
    -   public abstract class AbstractExecutorService implements java.util.concurrent.ExecutorService {
    -     ctor public AbstractExecutorService();
    --    method public java.util.List<java.util.concurrent.Future<T>> invokeAll(java.util.Collection<? extends java.util.concurrent.Callable<T>>) throws java.lang.InterruptedException;
    --    method public java.util.List<java.util.concurrent.Future<T>> invokeAll(java.util.Collection<? extends java.util.concurrent.Callable<T>>, long, java.util.concurrent.TimeUnit) throws java.lang.InterruptedException;
    --    method public T invokeAny(java.util.Collection<? extends java.util.concurrent.Callable<T>>) throws java.util.concurrent.ExecutionException, java.lang.InterruptedException;
    --    method public T invokeAny(java.util.Collection<? extends java.util.concurrent.Callable<T>>, long, java.util.concurrent.TimeUnit) throws java.util.concurrent.ExecutionException, java.lang.InterruptedException, java.util.concurrent.TimeoutException;
    --    method protected java.util.concurrent.RunnableFuture<T> newTaskFor(java.lang.Runnable, T);
    --    method protected java.util.concurrent.RunnableFuture<T> newTaskFor(java.util.concurrent.Callable<T>);
    -+    method public <T> java.util.List<java.util.concurrent.Future<T>> invokeAll(java.util.Collection<? extends java.util.concurrent.Callable<T>>) throws java.lang.InterruptedException;
    -+    method public <T> java.util.List<java.util.concurrent.Future<T>> invokeAll(java.util.Collection<? extends java.util.concurrent.Callable<T>>, long, java.util.concurrent.TimeUnit) throws java.lang.InterruptedException;
    -+    method public <T> T invokeAny(java.util.Collection<? extends java.util.concurrent.Callable<T>>) throws java.util.concurrent.ExecutionException, java.lang.InterruptedException;
    -+    method public <T> T invokeAny(java.util.Collection<? extends java.util.concurrent.Callable<T>>, long, java.util.concurrent.TimeUnit) throws java.util.concurrent.ExecutionException, java.lang.InterruptedException, java.util.concurrent.TimeoutException;
    -+    method protected <T> java.util.concurrent.RunnableFuture<T> newTaskFor(java.lang.Runnable, T);
    -+    method protected <T> java.util.concurrent.RunnableFuture<T> newTaskFor(java.util.concurrent.Callable<T>);
    -     method public java.util.concurrent.Future<?> submit(java.lang.Runnable);
    --    method public java.util.concurrent.Future<T> submit(java.lang.Runnable, T);
    --    method public java.util.concurrent.Future<T> submit(java.util.concurrent.Callable<T>);
    -+    method public <T> java.util.concurrent.Future<T> submit(java.lang.Runnable, T);
    -+    method public <T> java.util.concurrent.Future<T> submit(java.util.concurrent.Callable<T>);
    -   }
    - 
    --  public class ArrayBlockingQueue extends java.util.AbstractQueue implements java.util.concurrent.BlockingQueue java.io.Serializable {
    -+  public class ArrayBlockingQueue<E> extends java.util.AbstractQueue implements java.util.concurrent.BlockingQueue java.io.Serializable {
    -     ctor public ArrayBlockingQueue(int);
    -     ctor public ArrayBlockingQueue(int, boolean);
    -     ctor public ArrayBlockingQueue(int, boolean, java.util.Collection<? extends E>);
    -@@ -62823,7 +62823,7 @@ package java.util.concurrent {
    -     method public E take() throws java.lang.InterruptedException;
    -   }
    - 
    --  public abstract interface BlockingDeque implements java.util.concurrent.BlockingQueue java.util.Deque {
    -+  public abstract interface BlockingDeque<E> implements java.util.concurrent.BlockingQueue java.util.Deque {
    -     method public abstract boolean add(E);
    -     method public abstract void addFirst(E);
    -     method public abstract void addLast(E);
    -@@ -62855,7 +62855,7 @@ package java.util.concurrent {
    -     method public abstract E takeLast() throws java.lang.InterruptedException;
    -   }
    - 
    --  public abstract interface BlockingQueue implements java.util.Queue {
    -+  public abstract interface BlockingQueue<E> implements java.util.Queue {
    -     method public abstract boolean add(E);
    -     method public abstract boolean contains(java.lang.Object);
    -     method public abstract int drainTo(java.util.Collection<? super E>);
    -@@ -62874,7 +62874,7 @@ package java.util.concurrent {
    -     ctor public BrokenBarrierException(java.lang.String);
    -   }
    - 
    --  public abstract interface Callable {
    -+  public abstract interface Callable<V> {
    -     method public abstract V call() throws java.lang.Exception;
    -   }
    - 
    -@@ -62883,28 +62883,28 @@ package java.util.concurrent {
    -     ctor public CancellationException(java.lang.String);
    -   }
    - 
    --  public class CompletableFuture implements java.util.concurrent.CompletionStage java.util.concurrent.Future {
    -+  public class CompletableFuture<T> implements java.util.concurrent.CompletionStage java.util.concurrent.Future {
    -     ctor public CompletableFuture();
    -     method public java.util.concurrent.CompletableFuture<java.lang.Void> acceptEither(java.util.concurrent.CompletionStage<? extends T>, java.util.function.Consumer<? super T>);
    -     method public java.util.concurrent.CompletableFuture<java.lang.Void> acceptEitherAsync(java.util.concurrent.CompletionStage<? extends T>, java.util.function.Consumer<? super T>);
    -     method public java.util.concurrent.CompletableFuture<java.lang.Void> acceptEitherAsync(java.util.concurrent.CompletionStage<? extends T>, java.util.function.Consumer<? super T>, java.util.concurrent.Executor);
    -     method public static java.util.concurrent.CompletableFuture<java.lang.Void> allOf(java.util.concurrent.CompletableFuture<?>...);
    -     method public static java.util.concurrent.CompletableFuture<java.lang.Object> anyOf(java.util.concurrent.CompletableFuture<?>...);
    --    method public java.util.concurrent.CompletableFuture<U> applyToEither(java.util.concurrent.CompletionStage<? extends T>, java.util.function.Function<? super T, U>);
    --    method public java.util.concurrent.CompletableFuture<U> applyToEitherAsync(java.util.concurrent.CompletionStage<? extends T>, java.util.function.Function<? super T, U>);
    --    method public java.util.concurrent.CompletableFuture<U> applyToEitherAsync(java.util.concurrent.CompletionStage<? extends T>, java.util.function.Function<? super T, U>, java.util.concurrent.Executor);
    -+    method public <U> java.util.concurrent.CompletableFuture<U> applyToEither(java.util.concurrent.CompletionStage<? extends T>, java.util.function.Function<? super T, U>);
    -+    method public <U> java.util.concurrent.CompletableFuture<U> applyToEitherAsync(java.util.concurrent.CompletionStage<? extends T>, java.util.function.Function<? super T, U>);
    -+    method public <U> java.util.concurrent.CompletableFuture<U> applyToEitherAsync(java.util.concurrent.CompletionStage<? extends T>, java.util.function.Function<? super T, U>, java.util.concurrent.Executor);
    -     method public boolean cancel(boolean);
    -     method public boolean complete(T);
    -     method public boolean completeExceptionally(java.lang.Throwable);
    --    method public static java.util.concurrent.CompletableFuture<U> completedFuture(U);
    -+    method public static <U> java.util.concurrent.CompletableFuture<U> completedFuture(U);
    -     method public java.util.concurrent.CompletableFuture<T> exceptionally(java.util.function.Function<java.lang.Throwable, ? extends T>);
    -     method public T get() throws java.util.concurrent.ExecutionException, java.lang.InterruptedException;
    -     method public T get(long, java.util.concurrent.TimeUnit) throws java.util.concurrent.ExecutionException, java.lang.InterruptedException, java.util.concurrent.TimeoutException;
    -     method public T getNow(T);
    -     method public int getNumberOfDependents();
    --    method public java.util.concurrent.CompletableFuture<U> handle(java.util.function.BiFunction<? super T, java.lang.Throwable, ? extends U>);
    --    method public java.util.concurrent.CompletableFuture<U> handleAsync(java.util.function.BiFunction<? super T, java.lang.Throwable, ? extends U>);
    --    method public java.util.concurrent.CompletableFuture<U> handleAsync(java.util.function.BiFunction<? super T, java.lang.Throwable, ? extends U>, java.util.concurrent.Executor);
    -+    method public <U> java.util.concurrent.CompletableFuture<U> handle(java.util.function.BiFunction<? super T, java.lang.Throwable, ? extends U>);
    -+    method public <U> java.util.concurrent.CompletableFuture<U> handleAsync(java.util.function.BiFunction<? super T, java.lang.Throwable, ? extends U>);
    -+    method public <U> java.util.concurrent.CompletableFuture<U> handleAsync(java.util.function.BiFunction<? super T, java.lang.Throwable, ? extends U>, java.util.concurrent.Executor);
    -     method public boolean isCancelled();
    -     method public boolean isCompletedExceptionally();
    -     method public boolean isDone();
    -@@ -62919,23 +62919,23 @@ package java.util.concurrent {
    -     method public java.util.concurrent.CompletableFuture<java.lang.Void> runAfterEitherAsync(java.util.concurrent.CompletionStage<?>, java.lang.Runnable, java.util.concurrent.Executor);
    -     method public static java.util.concurrent.CompletableFuture<java.lang.Void> runAsync(java.lang.Runnable);
    -     method public static java.util.concurrent.CompletableFuture<java.lang.Void> runAsync(java.lang.Runnable, java.util.concurrent.Executor);
    --    method public static java.util.concurrent.CompletableFuture<U> supplyAsync(java.util.function.Supplier<U>);
    --    method public static java.util.concurrent.CompletableFuture<U> supplyAsync(java.util.function.Supplier<U>, java.util.concurrent.Executor);
    -+    method public static <U> java.util.concurrent.CompletableFuture<U> supplyAsync(java.util.function.Supplier<U>);
    -+    method public static <U> java.util.concurrent.CompletableFuture<U> supplyAsync(java.util.function.Supplier<U>, java.util.concurrent.Executor);
    -     method public java.util.concurrent.CompletableFuture<java.lang.Void> thenAccept(java.util.function.Consumer<? super T>);
    -     method public java.util.concurrent.CompletableFuture<java.lang.Void> thenAcceptAsync(java.util.function.Consumer<? super T>);
    -     method public java.util.concurrent.CompletableFuture<java.lang.Void> thenAcceptAsync(java.util.function.Consumer<? super T>, java.util.concurrent.Executor);
    --    method public java.util.concurrent.CompletableFuture<java.lang.Void> thenAcceptBoth(java.util.concurrent.CompletionStage<? extends U>, java.util.function.BiConsumer<? super T, ? super U>);
    --    method public java.util.concurrent.CompletableFuture<java.lang.Void> thenAcceptBothAsync(java.util.concurrent.CompletionStage<? extends U>, java.util.function.BiConsumer<? super T, ? super U>);
    --    method public java.util.concurrent.CompletableFuture<java.lang.Void> thenAcceptBothAsync(java.util.concurrent.CompletionStage<? extends U>, java.util.function.BiConsumer<? super T, ? super U>, java.util.concurrent.Executor);
    --    method public java.util.concurrent.CompletableFuture<U> thenApply(java.util.function.Function<? super T, ? extends U>);
    --    method public java.util.concurrent.CompletableFuture<U> thenApplyAsync(java.util.function.Function<? super T, ? extends U>);
    --    method public java.util.concurrent.CompletableFuture<U> thenApplyAsync(java.util.function.Function<? super T, ? extends U>, java.util.concurrent.Executor);
    --    method public java.util.concurrent.CompletableFuture<V> thenCombine(java.util.concurrent.CompletionStage<? extends U>, java.util.function.BiFunction<? super T, ? super U, ? extends V>);
    --    method public java.util.concurrent.CompletableFuture<V> thenCombineAsync(java.util.concurrent.CompletionStage<? extends U>, java.util.function.BiFunction<? super T, ? super U, ? extends V>);
    --    method public java.util.concurrent.CompletableFuture<V> thenCombineAsync(java.util.concurrent.CompletionStage<? extends U>, java.util.function.BiFunction<? super T, ? super U, ? extends V>, java.util.concurrent.Executor);
    --    method public java.util.concurrent.CompletableFuture<U> thenCompose(java.util.function.Function<? super T, ? extends java.util.concurrent.CompletionStage<U>>);
    --    method public java.util.concurrent.CompletableFuture<U> thenComposeAsync(java.util.function.Function<? super T, ? extends java.util.concurrent.CompletionStage<U>>);
    --    method public java.util.concurrent.CompletableFuture<U> thenComposeAsync(java.util.function.Function<? super T, ? extends java.util.concurrent.CompletionStage<U>>, java.util.concurrent.Executor);
    -+    method public <U> java.util.concurrent.CompletableFuture<java.lang.Void> thenAcceptBoth(java.util.concurrent.CompletionStage<? extends U>, java.util.function.BiConsumer<? super T, ? super U>);
    -+    method public <U> java.util.concurrent.CompletableFuture<java.lang.Void> thenAcceptBothAsync(java.util.concurrent.CompletionStage<? extends U>, java.util.function.BiConsumer<? super T, ? super U>);
    -+    method public <U> java.util.concurrent.CompletableFuture<java.lang.Void> thenAcceptBothAsync(java.util.concurrent.CompletionStage<? extends U>, java.util.function.BiConsumer<? super T, ? super U>, java.util.concurrent.Executor);
    -+    method public <U> java.util.concurrent.CompletableFuture<U> thenApply(java.util.function.Function<? super T, ? extends U>);
    -+    method public <U> java.util.concurrent.CompletableFuture<U> thenApplyAsync(java.util.function.Function<? super T, ? extends U>);
    -+    method public <U> java.util.concurrent.CompletableFuture<U> thenApplyAsync(java.util.function.Function<? super T, ? extends U>, java.util.concurrent.Executor);
    -+    method public <U, V> java.util.concurrent.CompletableFuture<V> thenCombine(java.util.concurrent.CompletionStage<? extends U>, java.util.function.BiFunction<? super T, ? super U, ? extends V>);
    -+    method public <U, V> java.util.concurrent.CompletableFuture<V> thenCombineAsync(java.util.concurrent.CompletionStage<? extends U>, java.util.function.BiFunction<? super T, ? super U, ? extends V>);
    -+    method public <U, V> java.util.concurrent.CompletableFuture<V> thenCombineAsync(java.util.concurrent.CompletionStage<? extends U>, java.util.function.BiFunction<? super T, ? super U, ? extends V>, java.util.concurrent.Executor);
    -+    method public <U> java.util.concurrent.CompletableFuture<U> thenCompose(java.util.function.Function<? super T, ? extends java.util.concurrent.CompletionStage<U>>);
    -+    method public <U> java.util.concurrent.CompletableFuture<U> thenComposeAsync(java.util.function.Function<? super T, ? extends java.util.concurrent.CompletionStage<U>>);
    -+    method public <U> java.util.concurrent.CompletableFuture<U> thenComposeAsync(java.util.function.Function<? super T, ? extends java.util.concurrent.CompletionStage<U>>, java.util.concurrent.Executor);
    -     method public java.util.concurrent.CompletableFuture<java.lang.Void> thenRun(java.lang.Runnable);
    -     method public java.util.concurrent.CompletableFuture<java.lang.Void> thenRunAsync(java.lang.Runnable);
    -     method public java.util.concurrent.CompletableFuture<java.lang.Void> thenRunAsync(java.lang.Runnable, java.util.concurrent.Executor);
    -@@ -62955,7 +62955,7 @@ package java.util.concurrent {
    -     ctor public CompletionException(java.lang.Throwable);
    -   }
    - 
    --  public abstract interface CompletionService {
    -+  public abstract interface CompletionService<V> {
    -     method public abstract java.util.concurrent.Future<V> poll();
    -     method public abstract java.util.concurrent.Future<V> poll(long, java.util.concurrent.TimeUnit) throws java.lang.InterruptedException;
    -     method public abstract java.util.concurrent.Future<V> submit(java.util.concurrent.Callable<V>);
    -@@ -62963,17 +62963,17 @@ package java.util.concurrent {
    -     method public abstract java.util.concurrent.Future<V> take() throws java.lang.InterruptedException;
    -   }
    - 
    --  public abstract interface CompletionStage {
    -+  public abstract interface CompletionStage<T> {
    -     method public abstract java.util.concurrent.CompletionStage<java.lang.Void> acceptEither(java.util.concurrent.CompletionStage<? extends T>, java.util.function.Consumer<? super T>);
    -     method public abstract java.util.concurrent.CompletionStage<java.lang.Void> acceptEitherAsync(java.util.concurrent.CompletionStage<? extends T>, java.util.function.Consumer<? super T>);
    -     method public abstract java.util.concurrent.CompletionStage<java.lang.Void> acceptEitherAsync(java.util.concurrent.CompletionStage<? extends T>, java.util.function.Consumer<? super T>, java.util.concurrent.Executor);
    --    method public abstract java.util.concurrent.CompletionStage<U> applyToEither(java.util.concurrent.CompletionStage<? extends T>, java.util.function.Function<? super T, U>);
    --    method public abstract java.util.concurrent.CompletionStage<U> applyToEitherAsync(java.util.concurrent.CompletionStage<? extends T>, java.util.function.Function<? super T, U>);
    --    method public abstract java.util.concurrent.CompletionStage<U> applyToEitherAsync(java.util.concurrent.CompletionStage<? extends T>, java.util.function.Function<? super T, U>, java.util.concurrent.Executor);
    -+    method public abstract <U> java.util.concurrent.CompletionStage<U> applyToEither(java.util.concurrent.CompletionStage<? extends T>, java.util.function.Function<? super T, U>);
    -+    method public abstract <U> java.util.concurrent.CompletionStage<U> applyToEitherAsync(java.util.concurrent.CompletionStage<? extends T>, java.util.function.Function<? super T, U>);
    -+    method public abstract <U> java.util.concurrent.CompletionStage<U> applyToEitherAsync(java.util.concurrent.CompletionStage<? extends T>, java.util.function.Function<? super T, U>, java.util.concurrent.Executor);
    -     method public abstract java.util.concurrent.CompletionStage<T> exceptionally(java.util.function.Function<java.lang.Throwable, ? extends T>);
    --    method public abstract java.util.concurrent.CompletionStage<U> handle(java.util.function.BiFunction<? super T, java.lang.Throwable, ? extends U>);
    --    method public abstract java.util.concurrent.CompletionStage<U> handleAsync(java.util.function.BiFunction<? super T, java.lang.Throwable, ? extends U>);
    --    method public abstract java.util.concurrent.CompletionStage<U> handleAsync(java.util.function.BiFunction<? super T, java.lang.Throwable, ? extends U>, java.util.concurrent.Executor);
    -+    method public abstract <U> java.util.concurrent.CompletionStage<U> handle(java.util.function.BiFunction<? super T, java.lang.Throwable, ? extends U>);
    -+    method public abstract <U> java.util.concurrent.CompletionStage<U> handleAsync(java.util.function.BiFunction<? super T, java.lang.Throwable, ? extends U>);
    -+    method public abstract <U> java.util.concurrent.CompletionStage<U> handleAsync(java.util.function.BiFunction<? super T, java.lang.Throwable, ? extends U>, java.util.concurrent.Executor);
    -     method public abstract java.util.concurrent.CompletionStage<java.lang.Void> runAfterBoth(java.util.concurrent.CompletionStage<?>, java.lang.Runnable);
    -     method public abstract java.util.concurrent.CompletionStage<java.lang.Void> runAfterBothAsync(java.util.concurrent.CompletionStage<?>, java.lang.Runnable);
    -     method public abstract java.util.concurrent.CompletionStage<java.lang.Void> runAfterBothAsync(java.util.concurrent.CompletionStage<?>, java.lang.Runnable, java.util.concurrent.Executor);
    -@@ -62983,18 +62983,18 @@ package java.util.concurrent {
    -     method public abstract java.util.concurrent.CompletionStage<java.lang.Void> thenAccept(java.util.function.Consumer<? super T>);
    -     method public abstract java.util.concurrent.CompletionStage<java.lang.Void> thenAcceptAsync(java.util.function.Consumer<? super T>);
    -     method public abstract java.util.concurrent.CompletionStage<java.lang.Void> thenAcceptAsync(java.util.function.Consumer<? super T>, java.util.concurrent.Executor);
    --    method public abstract java.util.concurrent.CompletionStage<java.lang.Void> thenAcceptBoth(java.util.concurrent.CompletionStage<? extends U>, java.util.function.BiConsumer<? super T, ? super U>);
    --    method public abstract java.util.concurrent.CompletionStage<java.lang.Void> thenAcceptBothAsync(java.util.concurrent.CompletionStage<? extends U>, java.util.function.BiConsumer<? super T, ? super U>);
    --    method public abstract java.util.concurrent.CompletionStage<java.lang.Void> thenAcceptBothAsync(java.util.concurrent.CompletionStage<? extends U>, java.util.function.BiConsumer<? super T, ? super U>, java.util.concurrent.Executor);
    --    method public abstract java.util.concurrent.CompletionStage<U> thenApply(java.util.function.Function<? super T, ? extends U>);
    --    method public abstract java.util.concurrent.CompletionStage<U> thenApplyAsync(java.util.function.Function<? super T, ? extends U>);
    --    method public abstract java.util.concurrent.CompletionStage<U> thenApplyAsync(java.util.function.Function<? super T, ? extends U>, java.util.concurrent.Executor);
    --    method public abstract java.util.concurrent.CompletionStage<V> thenCombine(java.util.concurrent.CompletionStage<? extends U>, java.util.function.BiFunction<? super T, ? super U, ? extends V>);
    --    method public abstract java.util.concurrent.CompletionStage<V> thenCombineAsync(java.util.concurrent.CompletionStage<? extends U>, java.util.function.BiFunction<? super T, ? super U, ? extends V>);
    --    method public abstract java.util.concurrent.CompletionStage<V> thenCombineAsync(java.util.concurrent.CompletionStage<? extends U>, java.util.function.BiFunction<? super T, ? super U, ? extends V>, java.util.concurrent.Executor);
    --    method public abstract java.util.concurrent.CompletionStage<U> thenCompose(java.util.function.Function<? super T, ? extends java.util.concurrent.CompletionStage<U>>);
    --    method public abstract java.util.concurrent.CompletionStage<U> thenComposeAsync(java.util.function.Function<? super T, ? extends java.util.concurrent.CompletionStage<U>>);
    --    method public abstract java.util.concurrent.CompletionStage<U> thenComposeAsync(java.util.function.Function<? super T, ? extends java.util.concurrent.CompletionStage<U>>, java.util.concurrent.Executor);
    -+    method public abstract <U> java.util.concurrent.CompletionStage<java.lang.Void> thenAcceptBoth(java.util.concurrent.CompletionStage<? extends U>, java.util.function.BiConsumer<? super T, ? super U>);
    -+    method public abstract <U> java.util.concurrent.CompletionStage<java.lang.Void> thenAcceptBothAsync(java.util.concurrent.CompletionStage<? extends U>, java.util.function.BiConsumer<? super T, ? super U>);
    -+    method public abstract <U> java.util.concurrent.CompletionStage<java.lang.Void> thenAcceptBothAsync(java.util.concurrent.CompletionStage<? extends U>, java.util.function.BiConsumer<? super T, ? super U>, java.util.concurrent.Executor);
    -+    method public abstract <U> java.util.concurrent.CompletionStage<U> thenApply(java.util.function.Function<? super T, ? extends U>);
    -+    method public abstract <U> java.util.concurrent.CompletionStage<U> thenApplyAsync(java.util.function.Function<? super T, ? extends U>);
    -+    method public abstract <U> java.util.concurrent.CompletionStage<U> thenApplyAsync(java.util.function.Function<? super T, ? extends U>, java.util.concurrent.Executor);
    -+    method public abstract <U, V> java.util.concurrent.CompletionStage<V> thenCombine(java.util.concurrent.CompletionStage<? extends U>, java.util.function.BiFunction<? super T, ? super U, ? extends V>);
    -+    method public abstract <U, V> java.util.concurrent.CompletionStage<V> thenCombineAsync(java.util.concurrent.CompletionStage<? extends U>, java.util.function.BiFunction<? super T, ? super U, ? extends V>);
    -+    method public abstract <U, V> java.util.concurrent.CompletionStage<V> thenCombineAsync(java.util.concurrent.CompletionStage<? extends U>, java.util.function.BiFunction<? super T, ? super U, ? extends V>, java.util.concurrent.Executor);
    -+    method public abstract <U> java.util.concurrent.CompletionStage<U> thenCompose(java.util.function.Function<? super T, ? extends java.util.concurrent.CompletionStage<U>>);
    -+    method public abstract <U> java.util.concurrent.CompletionStage<U> thenComposeAsync(java.util.function.Function<? super T, ? extends java.util.concurrent.CompletionStage<U>>);
    -+    method public abstract <U> java.util.concurrent.CompletionStage<U> thenComposeAsync(java.util.function.Function<? super T, ? extends java.util.concurrent.CompletionStage<U>>, java.util.concurrent.Executor);
    -     method public abstract java.util.concurrent.CompletionStage<java.lang.Void> thenRun(java.lang.Runnable);
    -     method public abstract java.util.concurrent.CompletionStage<java.lang.Void> thenRunAsync(java.lang.Runnable);
    -     method public abstract java.util.concurrent.CompletionStage<java.lang.Void> thenRunAsync(java.lang.Runnable, java.util.concurrent.Executor);
    -@@ -63004,7 +63004,7 @@ package java.util.concurrent {
    -     method public abstract java.util.concurrent.CompletionStage<T> whenCompleteAsync(java.util.function.BiConsumer<? super T, ? super java.lang.Throwable>, java.util.concurrent.Executor);
    -   }
    - 
    --  public class ConcurrentHashMap extends java.util.AbstractMap implements java.util.concurrent.ConcurrentMap java.io.Serializable {
    -+  public class ConcurrentHashMap<K, V> extends java.util.AbstractMap implements java.util.concurrent.ConcurrentMap java.io.Serializable {
    -     ctor public ConcurrentHashMap();
    -     ctor public ConcurrentHashMap(int);
    -     ctor public ConcurrentHashMap(java.util.Map<? extends K, ? extends V>);
    -@@ -63018,29 +63018,29 @@ package java.util.concurrent {
    -     method public java.util.Set<java.util.Map.Entry<K, V>> entrySet();
    -     method public void forEach(java.util.function.BiConsumer<? super K, ? super V>);
    -     method public void forEach(long, java.util.function.BiConsumer<? super K, ? super V>);
    --    method public void forEach(long, java.util.function.BiFunction<? super K, ? super V, ? extends U>, java.util.function.Consumer<? super U>);
    -+    method public <U> void forEach(long, java.util.function.BiFunction<? super K, ? super V, ? extends U>, java.util.function.Consumer<? super U>);
    -     method public void forEachEntry(long, java.util.function.Consumer<? super java.util.Map.Entry<K, V>>);
    --    method public void forEachEntry(long, java.util.function.Function<java.util.Map.Entry<K, V>, ? extends U>, java.util.function.Consumer<? super U>);
    -+    method public <U> void forEachEntry(long, java.util.function.Function<java.util.Map.Entry<K, V>, ? extends U>, java.util.function.Consumer<? super U>);
    -     method public void forEachKey(long, java.util.function.Consumer<? super K>);
    --    method public void forEachKey(long, java.util.function.Function<? super K, ? extends U>, java.util.function.Consumer<? super U>);
    -+    method public <U> void forEachKey(long, java.util.function.Function<? super K, ? extends U>, java.util.function.Consumer<? super U>);
    -     method public void forEachValue(long, java.util.function.Consumer<? super V>);
    --    method public void forEachValue(long, java.util.function.Function<? super V, ? extends U>, java.util.function.Consumer<? super U>);
    -+    method public <U> void forEachValue(long, java.util.function.Function<? super V, ? extends U>, java.util.function.Consumer<? super U>);
    -     method public V getOrDefault(java.lang.Object, V);
    -     method public java.util.concurrent.ConcurrentHashMap.KeySetView<K, V> keySet(V);
    -     method public java.util.Enumeration<K> keys();
    -     method public long mappingCount();
    -     method public V merge(K, V, java.util.function.BiFunction<? super V, ? super V, ? extends V>);
    --    method public static java.util.concurrent.ConcurrentHashMap.KeySetView<K, java.lang.Boolean> newKeySet();
    --    method public static java.util.concurrent.ConcurrentHashMap.KeySetView<K, java.lang.Boolean> newKeySet(int);
    -+    method public static <K> java.util.concurrent.ConcurrentHashMap.KeySetView<K, java.lang.Boolean> newKeySet();
    -+    method public static <K> java.util.concurrent.ConcurrentHashMap.KeySetView<K, java.lang.Boolean> newKeySet(int);
    -     method public V putIfAbsent(K, V);
    --    method public U reduce(long, java.util.function.BiFunction<? super K, ? super V, ? extends U>, java.util.function.BiFunction<? super U, ? super U, ? extends U>);
    -+    method public <U> U reduce(long, java.util.function.BiFunction<? super K, ? super V, ? extends U>, java.util.function.BiFunction<? super U, ? super U, ? extends U>);
    -     method public java.util.Map.Entry<K, V> reduceEntries(long, java.util.function.BiFunction<java.util.Map.Entry<K, V>, java.util.Map.Entry<K, V>, ? extends java.util.Map.Entry<K, V>>);
    --    method public U reduceEntries(long, java.util.function.Function<java.util.Map.Entry<K, V>, ? extends U>, java.util.function.BiFunction<? super U, ? super U, ? extends U>);
    -+    method public <U> U reduceEntries(long, java.util.function.Function<java.util.Map.Entry<K, V>, ? extends U>, java.util.function.BiFunction<? super U, ? super U, ? extends U>);
    -     method public double reduceEntriesToDouble(long, java.util.function.ToDoubleFunction<java.util.Map.Entry<K, V>>, double, java.util.function.DoubleBinaryOperator);
    -     method public int reduceEntriesToInt(long, java.util.function.ToIntFunction<java.util.Map.Entry<K, V>>, int, java.util.function.IntBinaryOperator);
    -     method public long reduceEntriesToLong(long, java.util.function.ToLongFunction<java.util.Map.Entry<K, V>>, long, java.util.function.LongBinaryOperator);
    -     method public K reduceKeys(long, java.util.function.BiFunction<? super K, ? super K, ? extends K>);
    --    method public U reduceKeys(long, java.util.function.Function<? super K, ? extends U>, java.util.function.BiFunction<? super U, ? super U, ? extends U>);
    -+    method public <U> U reduceKeys(long, java.util.function.Function<? super K, ? extends U>, java.util.function.BiFunction<? super U, ? super U, ? extends U>);
    -     method public double reduceKeysToDouble(long, java.util.function.ToDoubleFunction<? super K>, double, java.util.function.DoubleBinaryOperator);
    -     method public int reduceKeysToInt(long, java.util.function.ToIntFunction<? super K>, int, java.util.function.IntBinaryOperator);
    -     method public long reduceKeysToLong(long, java.util.function.ToLongFunction<? super K>, long, java.util.function.LongBinaryOperator);
    -@@ -63048,7 +63048,7 @@ package java.util.concurrent {
    -     method public int reduceToInt(long, java.util.function.ToIntBiFunction<? super K, ? super V>, int, java.util.function.IntBinaryOperator);
    -     method public long reduceToLong(long, java.util.function.ToLongBiFunction<? super K, ? super V>, long, java.util.function.LongBinaryOperator);
    -     method public V reduceValues(long, java.util.function.BiFunction<? super V, ? super V, ? extends V>);
    --    method public U reduceValues(long, java.util.function.Function<? super V, ? extends U>, java.util.function.BiFunction<? super U, ? super U, ? extends U>);
    -+    method public <U> U reduceValues(long, java.util.function.Function<? super V, ? extends U>, java.util.function.BiFunction<? super U, ? super U, ? extends U>);
    -     method public double reduceValuesToDouble(long, java.util.function.ToDoubleFunction<? super V>, double, java.util.function.DoubleBinaryOperator);
    -     method public int reduceValuesToInt(long, java.util.function.ToIntFunction<? super V>, int, java.util.function.IntBinaryOperator);
    -     method public long reduceValuesToLong(long, java.util.function.ToLongFunction<? super V>, long, java.util.function.LongBinaryOperator);
    -@@ -63056,13 +63056,13 @@ package java.util.concurrent {
    -     method public boolean replace(K, V, V);
    -     method public V replace(K, V);
    -     method public void replaceAll(java.util.function.BiFunction<? super K, ? super V, ? extends V>);
    --    method public U search(long, java.util.function.BiFunction<? super K, ? super V, ? extends U>);
    --    method public U searchEntries(long, java.util.function.Function<java.util.Map.Entry<K, V>, ? extends U>);
    --    method public U searchKeys(long, java.util.function.Function<? super K, ? extends U>);
    --    method public U searchValues(long, java.util.function.Function<? super V, ? extends U>);
    -+    method public <U> U search(long, java.util.function.BiFunction<? super K, ? super V, ? extends U>);
    -+    method public <U> U searchEntries(long, java.util.function.Function<java.util.Map.Entry<K, V>, ? extends U>);
    -+    method public <U> U searchKeys(long, java.util.function.Function<? super K, ? extends U>);
    -+    method public <U> U searchValues(long, java.util.function.Function<? super V, ? extends U>);
    -   }
    - 
    --   static abstract class ConcurrentHashMap.CollectionView implements java.util.Collection java.io.Serializable {
    -+   static abstract class ConcurrentHashMap.CollectionView<K, V, E> implements java.util.Collection java.io.Serializable {
    -     method public final void clear();
    -     method public abstract boolean contains(java.lang.Object);
    -     method public final boolean containsAll(java.util.Collection<?>);
    -@@ -63074,11 +63074,11 @@ package java.util.concurrent {
    -     method public final boolean retainAll(java.util.Collection<?>);
    -     method public final int size();
    -     method public final java.lang.Object[] toArray();
    --    method public final T[] toArray(T[]);
    -+    method public final <T> T[] toArray(T[]);
    -     method public final java.lang.String toString();
    -   }
    - 
    --  public static class ConcurrentHashMap.KeySetView extends java.util.concurrent.ConcurrentHashMap.CollectionView implements java.io.Serializable java.util.Set {
    -+  public static class ConcurrentHashMap.KeySetView<K, V> extends java.util.concurrent.ConcurrentHashMap.CollectionView implements java.io.Serializable java.util.Set {
    -     method public boolean add(K);
    -     method public boolean addAll(java.util.Collection<? extends K>);
    -     method public boolean contains(java.lang.Object);
    -@@ -63089,7 +63089,7 @@ package java.util.concurrent {
    -     method public java.util.Spliterator<K> spliterator();
    -   }
    - 
    --  public class ConcurrentLinkedDeque extends java.util.AbstractCollection implements java.util.Deque java.io.Serializable {
    -+  public class ConcurrentLinkedDeque<E> extends java.util.AbstractCollection implements java.util.Deque java.io.Serializable {
    -     ctor public ConcurrentLinkedDeque();
    -     ctor public ConcurrentLinkedDeque(java.util.Collection<? extends E>);
    -     method public void addFirst(E);
    -@@ -63119,7 +63119,7 @@ package java.util.concurrent {
    -     method public java.util.Spliterator<E> spliterator();
    -   }
    - 
    --  public class ConcurrentLinkedQueue extends java.util.AbstractQueue implements java.util.Queue java.io.Serializable {
    -+  public class ConcurrentLinkedQueue<E> extends java.util.AbstractQueue implements java.util.Queue java.io.Serializable {
    -     ctor public ConcurrentLinkedQueue();
    -     ctor public ConcurrentLinkedQueue(java.util.Collection<? extends E>);
    -     method public java.util.Iterator<E> iterator();
    -@@ -63130,14 +63130,14 @@ package java.util.concurrent {
    -     method public java.util.Spliterator<E> spliterator();
    -   }
    - 
    --  public abstract interface ConcurrentMap implements java.util.Map {
    -+  public abstract interface ConcurrentMap<K, V> implements java.util.Map {
    -     method public abstract V putIfAbsent(K, V);
    -     method public abstract boolean remove(java.lang.Object, java.lang.Object);
    -     method public abstract boolean replace(K, V, V);
    -     method public abstract V replace(K, V);
    -   }
    - 
    --  public abstract interface ConcurrentNavigableMap implements java.util.concurrent.ConcurrentMap java.util.NavigableMap {
    -+  public abstract interface ConcurrentNavigableMap<K, V> implements java.util.concurrent.ConcurrentMap java.util.NavigableMap {
    -     method public abstract java.util.NavigableSet<K> descendingKeySet();
    -     method public abstract java.util.concurrent.ConcurrentNavigableMap<K, V> descendingMap();
    -     method public abstract java.util.concurrent.ConcurrentNavigableMap<K, V> headMap(K, boolean);
    -@@ -63150,7 +63150,7 @@ package java.util.concurrent {
    -     method public abstract java.util.concurrent.ConcurrentNavigableMap<K, V> tailMap(K);
    -   }
    - 
    --  public class ConcurrentSkipListMap extends java.util.AbstractMap implements java.lang.Cloneable java.util.concurrent.ConcurrentNavigableMap java.io.Serializable {
    -+  public class ConcurrentSkipListMap<K, V> extends java.util.AbstractMap implements java.lang.Cloneable java.util.concurrent.ConcurrentNavigableMap java.io.Serializable {
    -     ctor public ConcurrentSkipListMap();
    -     ctor public ConcurrentSkipListMap(java.util.Comparator<? super K>);
    -     ctor public ConcurrentSkipListMap(java.util.Map<? extends K, ? extends V>);
    -@@ -63194,7 +63194,7 @@ package java.util.concurrent {
    -     method public java.util.concurrent.ConcurrentNavigableMap<K, V> tailMap(K);
    -   }
    - 
    --  public class ConcurrentSkipListSet extends java.util.AbstractSet implements java.lang.Cloneable java.util.NavigableSet java.io.Serializable {
    -+  public class ConcurrentSkipListSet<E> extends java.util.AbstractSet implements java.lang.Cloneable java.util.NavigableSet java.io.Serializable {
    -     ctor public ConcurrentSkipListSet();
    -     ctor public ConcurrentSkipListSet(java.util.Comparator<? super E>);
    -     ctor public ConcurrentSkipListSet(java.util.Collection<? extends E>);
    -@@ -63222,7 +63222,7 @@ package java.util.concurrent {
    -     method public java.util.NavigableSet<E> tailSet(E);
    -   }
    - 
    --  public class CopyOnWriteArrayList implements java.lang.Cloneable java.util.List java.util.RandomAccess java.io.Serializable {
    -+  public class CopyOnWriteArrayList<E> implements java.lang.Cloneable java.util.List java.util.RandomAccess java.io.Serializable {
    -     ctor public CopyOnWriteArrayList();
    -     ctor public CopyOnWriteArrayList(java.util.Collection<? extends E>);
    -     ctor public CopyOnWriteArrayList(E[]);
    -@@ -63254,10 +63254,10 @@ package java.util.concurrent {
    -     method public int size();
    -     method public java.util.List<E> subList(int, int);
    -     method public java.lang.Object[] toArray();
    --    method public T[] toArray(T[]);
    -+    method public <T> T[] toArray(T[]);
    -   }
    - 
    --  public class CopyOnWriteArraySet extends java.util.AbstractSet implements java.io.Serializable {
    -+  public class CopyOnWriteArraySet<E> extends java.util.AbstractSet implements java.io.Serializable {
    -     ctor public CopyOnWriteArraySet();
    -     ctor public CopyOnWriteArraySet(java.util.Collection<? extends E>);
    -     method public void forEach(java.util.function.Consumer<? super E>);
    -@@ -63275,7 +63275,7 @@ package java.util.concurrent {
    -     method public long getCount();
    -   }
    - 
    --  public abstract class CountedCompleter extends java.util.concurrent.ForkJoinTask {
    -+  public abstract class CountedCompleter<T> extends java.util.concurrent.ForkJoinTask {
    -     ctor protected CountedCompleter(java.util.concurrent.CountedCompleter<?>, int);
    -     ctor protected CountedCompleter(java.util.concurrent.CountedCompleter<?>);
    -     ctor protected CountedCompleter();
    -@@ -63312,7 +63312,7 @@ package java.util.concurrent {
    -     method public void reset();
    -   }
    - 
    --  public class DelayQueue extends java.util.AbstractQueue implements java.util.concurrent.BlockingQueue {
    -+  public class DelayQueue<E extends java.util.concurrent.Delayed> extends java.util.AbstractQueue implements java.util.concurrent.BlockingQueue {
    -     ctor public DelayQueue();
    -     ctor public DelayQueue(java.util.Collection<? extends E>);
    -     method public int drainTo(java.util.Collection<? super E>);
    -@@ -63333,7 +63333,7 @@ package java.util.concurrent {
    -     method public abstract long getDelay(java.util.concurrent.TimeUnit);
    -   }
    - 
    --  public class Exchanger {
    -+  public class Exchanger<V> {
    -     ctor public Exchanger();
    -     method public V exchange(V) throws java.lang.InterruptedException;
    -     method public V exchange(V, long, java.util.concurrent.TimeUnit) throws java.lang.InterruptedException, java.util.concurrent.TimeoutException;
    -@@ -63350,7 +63350,7 @@ package java.util.concurrent {
    -     method public abstract void execute(java.lang.Runnable);
    -   }
    - 
    --  public class ExecutorCompletionService implements java.util.concurrent.CompletionService {
    -+  public class ExecutorCompletionService<V> implements java.util.concurrent.CompletionService {
    -     ctor public ExecutorCompletionService(java.util.concurrent.Executor);
    -     ctor public ExecutorCompletionService(java.util.concurrent.Executor, java.util.concurrent.BlockingQueue<java.util.concurrent.Future<V>>);
    -     method public java.util.concurrent.Future<V> poll();
    -@@ -63362,21 +63362,21 @@ package java.util.concurrent {
    - 
    -   public abstract interface ExecutorService implements java.util.concurrent.Executor {
    -     method public abstract boolean awaitTermination(long, java.util.concurrent.TimeUnit) throws java.lang.InterruptedException;
    --    method public abstract java.util.List<java.util.concurrent.Future<T>> invokeAll(java.util.Collection<? extends java.util.concurrent.Callable<T>>) throws java.lang.InterruptedException;
    --    method public abstract java.util.List<java.util.concurrent.Future<T>> invokeAll(java.util.Collection<? extends java.util.concurrent.Callable<T>>, long, java.util.concurrent.TimeUnit) throws java.lang.InterruptedException;
    --    method public abstract T invokeAny(java.util.Collection<? extends java.util.concurrent.Callable<T>>) throws java.util.concurrent.ExecutionException, java.lang.InterruptedException;
    --    method public abstract T invokeAny(java.util.Collection<? extends java.util.concurrent.Callable<T>>, long, java.util.concurrent.TimeUnit) throws java.util.concurrent.ExecutionException, java.lang.InterruptedException, java.util.concurrent.TimeoutException;
    -+    method public abstract <T> java.util.List<java.util.concurrent.Future<T>> invokeAll(java.util.Collection<? extends java.util.concurrent.Callable<T>>) throws java.lang.InterruptedException;
    -+    method public abstract <T> java.util.List<java.util.concurrent.Future<T>> invokeAll(java.util.Collection<? extends java.util.concurrent.Callable<T>>, long, java.util.concurrent.TimeUnit) throws java.lang.InterruptedException;
    -+    method public abstract <T> T invokeAny(java.util.Collection<? extends java.util.concurrent.Callable<T>>) throws java.util.concurrent.ExecutionException, java.lang.InterruptedException;
    -+    method public abstract <T> T invokeAny(java.util.Collection<? extends java.util.concurrent.Callable<T>>, long, java.util.concurrent.TimeUnit) throws java.util.concurrent.ExecutionException, java.lang.InterruptedException, java.util.concurrent.TimeoutException;
    -     method public abstract boolean isShutdown();
    -     method public abstract boolean isTerminated();
    -     method public abstract void shutdown();
    -     method public abstract java.util.List<java.lang.Runnable> shutdownNow();
    --    method public abstract java.util.concurrent.Future<T> submit(java.util.concurrent.Callable<T>);
    --    method public abstract java.util.concurrent.Future<T> submit(java.lang.Runnable, T);
    -+    method public abstract <T> java.util.concurrent.Future<T> submit(java.util.concurrent.Callable<T>);
    -+    method public abstract <T> java.util.concurrent.Future<T> submit(java.lang.Runnable, T);
    -     method public abstract java.util.concurrent.Future<?> submit(java.lang.Runnable);
    -   }
    - 
    -   public class Executors {
    --    method public static java.util.concurrent.Callable<T> callable(java.lang.Runnable, T);
    -+    method public static <T> java.util.concurrent.Callable<T> callable(java.lang.Runnable, T);
    -     method public static java.util.concurrent.Callable<java.lang.Object> callable(java.lang.Runnable);
    -     method public static java.util.concurrent.Callable<java.lang.Object> callable(java.security.PrivilegedAction<?>);
    -     method public static java.util.concurrent.Callable<java.lang.Object> callable(java.security.PrivilegedExceptionAction<?>);
    -@@ -63393,8 +63393,8 @@ package java.util.concurrent {
    -     method public static java.util.concurrent.ScheduledExecutorService newSingleThreadScheduledExecutor(java.util.concurrent.ThreadFactory);
    -     method public static java.util.concurrent.ExecutorService newWorkStealingPool(int);
    -     method public static java.util.concurrent.ExecutorService newWorkStealingPool();
    --    method public static java.util.concurrent.Callable<T> privilegedCallable(java.util.concurrent.Callable<T>);
    --    method public static java.util.concurrent.Callable<T> privilegedCallableUsingCurrentClassLoader(java.util.concurrent.Callable<T>);
    -+    method public static <T> java.util.concurrent.Callable<T> privilegedCallable(java.util.concurrent.Callable<T>);
    -+    method public static <T> java.util.concurrent.Callable<T> privilegedCallableUsingCurrentClassLoader(java.util.concurrent.Callable<T>);
    -     method public static java.util.concurrent.ThreadFactory privilegedThreadFactory();
    -     method public static java.util.concurrent.ExecutorService unconfigurableExecutorService(java.util.concurrent.ExecutorService);
    -     method public static java.util.concurrent.ScheduledExecutorService unconfigurableScheduledExecutorService(java.util.concurrent.ScheduledExecutorService);
    -@@ -63422,7 +63422,7 @@ package java.util.concurrent {
    -     method public long getStealCount();
    -     method public java.lang.Thread.UncaughtExceptionHandler getUncaughtExceptionHandler();
    -     method public boolean hasQueuedSubmissions();
    --    method public T invoke(java.util.concurrent.ForkJoinTask<T>);
    -+    method public <T> T invoke(java.util.concurrent.ForkJoinTask<T>);
    -     method public boolean isQuiescent();
    -     method public boolean isShutdown();
    -     method public boolean isTerminated();
    -@@ -63431,7 +63431,7 @@ package java.util.concurrent {
    -     method protected java.util.concurrent.ForkJoinTask<?> pollSubmission();
    -     method public void shutdown();
    -     method public java.util.List<java.lang.Runnable> shutdownNow();
    --    method public java.util.concurrent.ForkJoinTask<T> submit(java.util.concurrent.ForkJoinTask<T>);
    -+    method public <T> java.util.concurrent.ForkJoinTask<T> submit(java.util.concurrent.ForkJoinTask<T>);
    -     field public static final java.util.concurrent.ForkJoinPool.ForkJoinWorkerThreadFactory defaultForkJoinWorkerThreadFactory;
    -   }
    - 
    -@@ -63444,11 +63444,11 @@ package java.util.concurrent {
    -     method public abstract boolean isReleasable();
    -   }
    - 
    --  public abstract class ForkJoinTask implements java.util.concurrent.Future java.io.Serializable {
    -+  public abstract class ForkJoinTask<V> implements java.util.concurrent.Future java.io.Serializable {
    -     ctor public ForkJoinTask();
    -     method public static java.util.concurrent.ForkJoinTask<?> adapt(java.lang.Runnable);
    --    method public static java.util.concurrent.ForkJoinTask<T> adapt(java.lang.Runnable, T);
    --    method public static java.util.concurrent.ForkJoinTask<T> adapt(java.util.concurrent.Callable<? extends T>);
    -+    method public static <T> java.util.concurrent.ForkJoinTask<T> adapt(java.lang.Runnable, T);
    -+    method public static <T> java.util.concurrent.ForkJoinTask<T> adapt(java.util.concurrent.Callable<? extends T>);
    -     method public boolean cancel(boolean);
    -     method public final boolean compareAndSetForkJoinTaskTag(short, short);
    -     method public void complete(V);
    -@@ -63468,7 +63468,7 @@ package java.util.concurrent {
    -     method public final V invoke();
    -     method public static void invokeAll(java.util.concurrent.ForkJoinTask<?>, java.util.concurrent.ForkJoinTask<?>);
    -     method public static void invokeAll(java.util.concurrent.ForkJoinTask<?>...);
    --    method public static java.util.Collection<T> invokeAll(java.util.Collection<T>);
    -+    method public static <T extends java.util.concurrent.ForkJoinTask<?>> java.util.Collection<T> invokeAll(java.util.Collection<T>);
    -     method public final boolean isCancelled();
    -     method public final boolean isCompletedAbnormally();
    -     method public final boolean isCompletedNormally();
    -@@ -63494,7 +63494,7 @@ package java.util.concurrent {
    -     method protected void onTermination(java.lang.Throwable);
    -   }
    - 
    --  public abstract interface Future {
    -+  public abstract interface Future<V> {
    -     method public abstract boolean cancel(boolean);
    -     method public abstract V get() throws java.util.concurrent.ExecutionException, java.lang.InterruptedException;
    -     method public abstract V get(long, java.util.concurrent.TimeUnit) throws java.util.concurrent.ExecutionException, java.lang.InterruptedException, java.util.concurrent.TimeoutException;
    -@@ -63502,7 +63502,7 @@ package java.util.concurrent {
    -     method public abstract boolean isDone();
    -   }
    - 
    --  public class FutureTask implements java.util.concurrent.RunnableFuture {
    -+  public class FutureTask<V> implements java.util.concurrent.RunnableFuture {
    -     ctor public FutureTask(java.util.concurrent.Callable<V>);
    -     ctor public FutureTask(java.lang.Runnable, V);
    -     method public boolean cancel(boolean);
    -@@ -63517,7 +63517,7 @@ package java.util.concurrent {
    -     method protected void setException(java.lang.Throwable);
    -   }
    - 
    --  public class LinkedBlockingDeque extends java.util.AbstractQueue implements java.util.concurrent.BlockingDeque java.io.Serializable {
    -+  public class LinkedBlockingDeque<E> extends java.util.AbstractQueue implements java.util.concurrent.BlockingDeque java.io.Serializable {
    -     ctor public LinkedBlockingDeque();
    -     ctor public LinkedBlockingDeque(int);
    -     ctor public LinkedBlockingDeque(java.util.Collection<? extends E>);
    -@@ -63561,7 +63561,7 @@ package java.util.concurrent {
    -     method public E takeLast() throws java.lang.InterruptedException;
    -   }
    - 
    --  public class LinkedBlockingQueue extends java.util.AbstractQueue implements java.util.concurrent.BlockingQueue java.io.Serializable {
    -+  public class LinkedBlockingQueue<E> extends java.util.AbstractQueue implements java.util.concurrent.BlockingQueue java.io.Serializable {
    -     ctor public LinkedBlockingQueue();
    -     ctor public LinkedBlockingQueue(int);
    -     ctor public LinkedBlockingQueue(java.util.Collection<? extends E>);
    -@@ -63580,7 +63580,7 @@ package java.util.concurrent {
    -     method public E take() throws java.lang.InterruptedException;
    -   }
    - 
    --  public class LinkedTransferQueue extends java.util.AbstractQueue implements java.io.Serializable java.util.concurrent.TransferQueue {
    -+  public class LinkedTransferQueue<E> extends java.util.AbstractQueue implements java.io.Serializable java.util.concurrent.TransferQueue {
    -     ctor public LinkedTransferQueue();
    -     ctor public LinkedTransferQueue(java.util.Collection<? extends E>);
    -     method public int drainTo(java.util.Collection<? super E>);
    -@@ -63627,7 +63627,7 @@ package java.util.concurrent {
    -     method public int register();
    -   }
    - 
    --  public class PriorityBlockingQueue extends java.util.AbstractQueue implements java.util.concurrent.BlockingQueue java.io.Serializable {
    -+  public class PriorityBlockingQueue<E> extends java.util.AbstractQueue implements java.util.concurrent.BlockingQueue java.io.Serializable {
    -     ctor public PriorityBlockingQueue();
    -     ctor public PriorityBlockingQueue(int);
    -     ctor public PriorityBlockingQueue(int, java.util.Comparator<? super E>);
    -@@ -63656,7 +63656,7 @@ package java.util.concurrent {
    -     method protected final void setRawResult(java.lang.Void);
    -   }
    - 
    --  public abstract class RecursiveTask extends java.util.concurrent.ForkJoinTask {
    -+  public abstract class RecursiveTask<V> extends java.util.concurrent.ForkJoinTask {
    -     ctor public RecursiveTask();
    -     method protected abstract V compute();
    -     method protected final boolean exec();
    -@@ -63675,22 +63675,22 @@ package java.util.concurrent {
    -     method public abstract void rejectedExecution(java.lang.Runnable, java.util.concurrent.ThreadPoolExecutor);
    -   }
    - 
    --  public abstract interface RunnableFuture implements java.util.concurrent.Future java.lang.Runnable {
    -+  public abstract interface RunnableFuture<V> implements java.util.concurrent.Future java.lang.Runnable {
    -     method public abstract void run();
    -   }
    - 
    --  public abstract interface RunnableScheduledFuture implements java.util.concurrent.RunnableFuture java.util.concurrent.ScheduledFuture {
    -+  public abstract interface RunnableScheduledFuture<V> implements java.util.concurrent.RunnableFuture java.util.concurrent.ScheduledFuture {
    -     method public abstract boolean isPeriodic();
    -   }
    - 
    -   public abstract interface ScheduledExecutorService implements java.util.concurrent.ExecutorService {
    -     method public abstract java.util.concurrent.ScheduledFuture<?> schedule(java.lang.Runnable, long, java.util.concurrent.TimeUnit);
    --    method public abstract java.util.concurrent.ScheduledFuture<V> schedule(java.util.concurrent.Callable<V>, long, java.util.concurrent.TimeUnit);
    -+    method public abstract <V> java.util.concurrent.ScheduledFuture<V> schedule(java.util.concurrent.Callable<V>, long, java.util.concurrent.TimeUnit);
    -     method public abstract java.util.concurrent.ScheduledFuture<?> scheduleAtFixedRate(java.lang.Runnable, long, long, java.util.concurrent.TimeUnit);
    -     method public abstract java.util.concurrent.ScheduledFuture<?> scheduleWithFixedDelay(java.lang.Runnable, long, long, java.util.concurrent.TimeUnit);
    -   }
    - 
    --  public abstract interface ScheduledFuture implements java.util.concurrent.Delayed java.util.concurrent.Future {
    -+  public abstract interface ScheduledFuture<V> implements java.util.concurrent.Delayed java.util.concurrent.Future {
    -   }
    - 
    -   public class ScheduledThreadPoolExecutor extends java.util.concurrent.ThreadPoolExecutor implements java.util.concurrent.ScheduledExecutorService {
    -@@ -63698,13 +63698,13 @@ package java.util.concurrent {
    -     ctor public ScheduledThreadPoolExecutor(int, java.util.concurrent.ThreadFactory);
    -     ctor public ScheduledThreadPoolExecutor(int, java.util.concurrent.RejectedExecutionHandler);
    -     ctor public ScheduledThreadPoolExecutor(int, java.util.concurrent.ThreadFactory, java.util.concurrent.RejectedExecutionHandler);
    --    method protected java.util.concurrent.RunnableScheduledFuture<V> decorateTask(java.lang.Runnable, java.util.concurrent.RunnableScheduledFuture<V>);
    --    method protected java.util.concurrent.RunnableScheduledFuture<V> decorateTask(java.util.concurrent.Callable<V>, java.util.concurrent.RunnableScheduledFuture<V>);
    -+    method protected <V> java.util.concurrent.RunnableScheduledFuture<V> decorateTask(java.lang.Runnable, java.util.concurrent.RunnableScheduledFuture<V>);
    -+    method protected <V> java.util.concurrent.RunnableScheduledFuture<V> decorateTask(java.util.concurrent.Callable<V>, java.util.concurrent.RunnableScheduledFuture<V>);
    -     method public boolean getContinueExistingPeriodicTasksAfterShutdownPolicy();
    -     method public boolean getExecuteExistingDelayedTasksAfterShutdownPolicy();
    -     method public boolean getRemoveOnCancelPolicy();
    -     method public java.util.concurrent.ScheduledFuture<?> schedule(java.lang.Runnable, long, java.util.concurrent.TimeUnit);
    --    method public java.util.concurrent.ScheduledFuture<V> schedule(java.util.concurrent.Callable<V>, long, java.util.concurrent.TimeUnit);
    -+    method public <V> java.util.concurrent.ScheduledFuture<V> schedule(java.util.concurrent.Callable<V>, long, java.util.concurrent.TimeUnit);
    -     method public java.util.concurrent.ScheduledFuture<?> scheduleAtFixedRate(java.lang.Runnable, long, long, java.util.concurrent.TimeUnit);
    -     method public java.util.concurrent.ScheduledFuture<?> scheduleWithFixedDelay(java.lang.Runnable, long, long, java.util.concurrent.TimeUnit);
    -     method public void setContinueExistingPeriodicTasksAfterShutdownPolicy(boolean);
    -@@ -63734,7 +63734,7 @@ package java.util.concurrent {
    -     method public boolean tryAcquire(int, long, java.util.concurrent.TimeUnit) throws java.lang.InterruptedException;
    -   }
    - 
    --  public class SynchronousQueue extends java.util.AbstractQueue implements java.util.concurrent.BlockingQueue java.io.Serializable {
    -+  public class SynchronousQueue<E> extends java.util.AbstractQueue implements java.util.concurrent.BlockingQueue java.io.Serializable {
    -     ctor public SynchronousQueue();
    -     ctor public SynchronousQueue(boolean);
    -     method public int drainTo(java.util.Collection<? super E>);
    -@@ -63852,7 +63852,7 @@ package java.util.concurrent {
    -     ctor public TimeoutException(java.lang.String);
    -   }
    - 
    --  public abstract interface TransferQueue implements java.util.concurrent.BlockingQueue {
    -+  public abstract interface TransferQueue<E> implements java.util.concurrent.BlockingQueue {
    -     method public abstract int getWaitingConsumerCount();
    -     method public abstract boolean hasWaitingConsumer();
    -     method public abstract void transfer(E) throws java.lang.InterruptedException;
    -@@ -63922,7 +63922,7 @@ package java.util.concurrent.atomic {
    -     method public final boolean weakCompareAndSet(int, int, int);
    -   }
    - 
    --  public abstract class AtomicIntegerFieldUpdater {
    -+  public abstract class AtomicIntegerFieldUpdater<T> {
    -     ctor protected AtomicIntegerFieldUpdater();
    -     method public final int accumulateAndGet(T, int, java.util.function.IntBinaryOperator);
    -     method public int addAndGet(T, int);
    -@@ -63937,7 +63937,7 @@ package java.util.concurrent.atomic {
    -     method public final int getAndUpdate(T, java.util.function.IntUnaryOperator);
    -     method public int incrementAndGet(T);
    -     method public abstract void lazySet(T, int);
    --    method public static java.util.concurrent.atomic.AtomicIntegerFieldUpdater<U> newUpdater(java.lang.Class<U>, java.lang.String);
    -+    method public static <U> java.util.concurrent.atomic.AtomicIntegerFieldUpdater<U> newUpdater(java.lang.Class<U>, java.lang.String);
    -     method public abstract void set(T, int);
    -     method public final int updateAndGet(T, java.util.function.IntUnaryOperator);
    -     method public abstract boolean weakCompareAndSet(T, int, int);
    -@@ -63990,7 +63990,7 @@ package java.util.concurrent.atomic {
    -     method public final boolean weakCompareAndSet(int, long, long);
    -   }
    - 
    --  public abstract class AtomicLongFieldUpdater {
    -+  public abstract class AtomicLongFieldUpdater<T> {
    -     ctor protected AtomicLongFieldUpdater();
    -     method public final long accumulateAndGet(T, long, java.util.function.LongBinaryOperator);
    -     method public long addAndGet(T, long);
    -@@ -64005,13 +64005,13 @@ package java.util.concurrent.atomic {
    -     method public final long getAndUpdate(T, java.util.function.LongUnaryOperator);
    -     method public long incrementAndGet(T);
    -     method public abstract void lazySet(T, long);
    --    method public static java.util.concurrent.atomic.AtomicLongFieldUpdater<U> newUpdater(java.lang.Class<U>, java.lang.String);
    -+    method public static <U> java.util.concurrent.atomic.AtomicLongFieldUpdater<U> newUpdater(java.lang.Class<U>, java.lang.String);
    -     method public abstract void set(T, long);
    -     method public final long updateAndGet(T, java.util.function.LongUnaryOperator);
    -     method public abstract boolean weakCompareAndSet(T, long, long);
    -   }
    - 
    --  public class AtomicMarkableReference {
    -+  public class AtomicMarkableReference<V> {
    -     ctor public AtomicMarkableReference(V, boolean);
    -     method public boolean attemptMark(V, boolean);
    -     method public boolean compareAndSet(V, V, boolean, boolean);
    -@@ -64022,7 +64022,7 @@ package java.util.concurrent.atomic {
    -     method public boolean weakCompareAndSet(V, V, boolean, boolean);
    -   }
    - 
    --  public class AtomicReference implements java.io.Serializable {
    -+  public class AtomicReference<V> implements java.io.Serializable {
    -     ctor public AtomicReference(V);
    -     ctor public AtomicReference();
    -     method public final V accumulateAndGet(V, java.util.function.BinaryOperator<V>);
    -@@ -64037,7 +64037,7 @@ package java.util.concurrent.atomic {
    -     method public final boolean weakCompareAndSet(V, V);
    -   }
    - 
    --  public class AtomicReferenceArray implements java.io.Serializable {
    -+  public class AtomicReferenceArray<E> implements java.io.Serializable {
    -     ctor public AtomicReferenceArray(int);
    -     ctor public AtomicReferenceArray(E[]);
    -     method public final E accumulateAndGet(int, E, java.util.function.BinaryOperator<E>);
    -@@ -64053,7 +64053,7 @@ package java.util.concurrent.atomic {
    -     method public final boolean weakCompareAndSet(int, E, E);
    -   }
    - 
    --  public abstract class AtomicReferenceFieldUpdater {
    -+  public abstract class AtomicReferenceFieldUpdater<T, V> {
    -     ctor protected AtomicReferenceFieldUpdater();
    -     method public final V accumulateAndGet(T, V, java.util.function.BinaryOperator<V>);
    -     method public abstract boolean compareAndSet(T, V, V);
    -@@ -64062,13 +64062,13 @@ package java.util.concurrent.atomic {
    -     method public V getAndSet(T, V);
    -     method public final V getAndUpdate(T, java.util.function.UnaryOperator<V>);
    -     method public abstract void lazySet(T, V);
    --    method public static java.util.concurrent.atomic.AtomicReferenceFieldUpdater<U, W> newUpdater(java.lang.Class<U>, java.lang.Class<W>, java.lang.String);
    -+    method public static <U, W> java.util.concurrent.atomic.AtomicReferenceFieldUpdater<U, W> newUpdater(java.lang.Class<U>, java.lang.Class<W>, java.lang.String);
    -     method public abstract void set(T, V);
    -     method public final V updateAndGet(T, java.util.function.UnaryOperator<V>);
    -     method public abstract boolean weakCompareAndSet(T, V, V);
    -   }
    - 
    --  public class AtomicStampedReference {
    -+  public class AtomicStampedReference<V> {
    -     ctor public AtomicStampedReference(V, int);
    -     method public boolean attemptStamp(V, int);
    -     method public boolean compareAndSet(V, V, int, int);
    -@@ -64371,33 +64371,33 @@ package java.util.concurrent.locks {
    - 
    - package java.util.function {
    - 
    --  public abstract interface BiConsumer {
    -+  public abstract interface BiConsumer<T, U> {
    -     method public abstract void accept(T, U);
    -     method public default java.util.function.BiConsumer<T, U> andThen(java.util.function.BiConsumer<? super T, ? super U>);
    -   }
    - 
    --  public abstract interface BiFunction {
    --    method public default java.util.function.BiFunction<T, U, V> andThen(java.util.function.Function<? super R, ? extends V>);
    -+  public abstract interface BiFunction<T, U, R> {
    -+    method public default <V> java.util.function.BiFunction<T, U, V> andThen(java.util.function.Function<? super R, ? extends V>);
    -     method public abstract R apply(T, U);
    -   }
    - 
    --  public abstract interface BiPredicate {
    -+  public abstract interface BiPredicate<T, U> {
    -     method public default java.util.function.BiPredicate<T, U> and(java.util.function.BiPredicate<? super T, ? super U>);
    -     method public default java.util.function.BiPredicate<T, U> negate();
    -     method public default java.util.function.BiPredicate<T, U> or(java.util.function.BiPredicate<? super T, ? super U>);
    -     method public abstract boolean test(T, U);
    -   }
    - 
    --  public abstract interface BinaryOperator implements java.util.function.BiFunction {
    --    method public static java.util.function.BinaryOperator<T> maxBy(java.util.Comparator<? super T>);
    --    method public static java.util.function.BinaryOperator<T> minBy(java.util.Comparator<? super T>);
    -+  public abstract interface BinaryOperator<T> implements java.util.function.BiFunction {
    -+    method public static <T> java.util.function.BinaryOperator<T> maxBy(java.util.Comparator<? super T>);
    -+    method public static <T> java.util.function.BinaryOperator<T> minBy(java.util.Comparator<? super T>);
    -   }
    - 
    -   public abstract interface BooleanSupplier {
    -     method public abstract boolean getAsBoolean();
    -   }
    - 
    --  public abstract interface Consumer {
    -+  public abstract interface Consumer<T> {
    -     method public abstract void accept(T);
    -     method public default java.util.function.Consumer<T> andThen(java.util.function.Consumer<? super T>);
    -   }
    -@@ -64411,7 +64411,7 @@ package java.util.function {
    -     method public default java.util.function.DoubleConsumer andThen(java.util.function.DoubleConsumer);
    -   }
    - 
    --  public abstract interface DoubleFunction {
    -+  public abstract interface DoubleFunction<R> {
    -     method public abstract R apply(double);
    -   }
    - 
    -@@ -64441,11 +64441,11 @@ package java.util.function {
    -     method public static java.util.function.DoubleUnaryOperator identity();
    -   }
    - 
    --  public abstract interface Function {
    --    method public default java.util.function.Function<T, V> andThen(java.util.function.Function<? super R, ? extends V>);
    -+  public abstract interface Function<T, R> {
    -+    method public default <V> java.util.function.Function<T, V> andThen(java.util.function.Function<? super R, ? extends V>);
    -     method public abstract R apply(T);
    --    method public default java.util.function.Function<V, R> compose(java.util.function.Function<? super V, ? extends T>);
    --    method public static java.util.function.Function<T, T> identity();
    -+    method public default <V> java.util.function.Function<V, R> compose(java.util.function.Function<? super V, ? extends T>);
    -+    method public static <T> java.util.function.Function<T, T> identity();
    -   }
    - 
    -   public abstract interface IntBinaryOperator {
    -@@ -64457,7 +64457,7 @@ package java.util.function {
    -     method public default java.util.function.IntConsumer andThen(java.util.function.IntConsumer);
    -   }
    - 
    --  public abstract interface IntFunction {
    -+  public abstract interface IntFunction<R> {
    -     method public abstract R apply(int);
    -   }
    - 
    -@@ -64496,7 +64496,7 @@ package java.util.function {
    -     method public default java.util.function.LongConsumer andThen(java.util.function.LongConsumer);
    -   }
    - 
    --  public abstract interface LongFunction {
    -+  public abstract interface LongFunction<R> {
    -     method public abstract R apply(long);
    -   }
    - 
    -@@ -64526,56 +64526,56 @@ package java.util.function {
    -     method public static java.util.function.LongUnaryOperator identity();
    -   }
    - 
    --  public abstract interface ObjDoubleConsumer {
    -+  public abstract interface ObjDoubleConsumer<T> {
    -     method public abstract void accept(T, double);
    -   }
    - 
    --  public abstract interface ObjIntConsumer {
    -+  public abstract interface ObjIntConsumer<T> {
    -     method public abstract void accept(T, int);
    -   }
    - 
    --  public abstract interface ObjLongConsumer {
    -+  public abstract interface ObjLongConsumer<T> {
    -     method public abstract void accept(T, long);
    -   }
    - 
    --  public abstract interface Predicate {
    -+  public abstract interface Predicate<T> {
    -     method public default java.util.function.Predicate<T> and(java.util.function.Predicate<? super T>);
    --    method public static java.util.function.Predicate<T> isEqual(java.lang.Object);
    -+    method public static <T> java.util.function.Predicate<T> isEqual(java.lang.Object);
    -     method public default java.util.function.Predicate<T> negate();
    -     method public default java.util.function.Predicate<T> or(java.util.function.Predicate<? super T>);
    -     method public abstract boolean test(T);
    -   }
    - 
    --  public abstract interface Supplier {
    -+  public abstract interface Supplier<T> {
    -     method public abstract T get();
    -   }
    - 
    --  public abstract interface ToDoubleBiFunction {
    -+  public abstract interface ToDoubleBiFunction<T, U> {
    -     method public abstract double applyAsDouble(T, U);
    -   }
    - 
    --  public abstract interface ToDoubleFunction {
    -+  public abstract interface ToDoubleFunction<T> {
    -     method public abstract double applyAsDouble(T);
    -   }
    - 
    --  public abstract interface ToIntBiFunction {
    -+  public abstract interface ToIntBiFunction<T, U> {
    -     method public abstract int applyAsInt(T, U);
    -   }
    - 
    --  public abstract interface ToIntFunction {
    -+  public abstract interface ToIntFunction<T> {
    -     method public abstract int applyAsInt(T);
    -   }
    - 
    --  public abstract interface ToLongBiFunction {
    -+  public abstract interface ToLongBiFunction<T, U> {
    -     method public abstract long applyAsLong(T, U);
    -   }
    - 
    --  public abstract interface ToLongFunction {
    -+  public abstract interface ToLongFunction<T> {
    -     method public abstract long applyAsLong(T);
    -   }
    - 
    --  public abstract interface UnaryOperator implements java.util.function.Function {
    --    method public static java.util.function.UnaryOperator<T> identity();
    -+  public abstract interface UnaryOperator<T> implements java.util.function.Function {
    -+    method public static <T> java.util.function.UnaryOperator<T> identity();
    -   }
    - 
    - }
    -@@ -65163,7 +65163,7 @@ package java.util.regex {
    - 
    - package java.util.stream {
    - 
    --  public abstract interface BaseStream implements java.lang.AutoCloseable {
    -+  public abstract interface BaseStream<T, S extends java.util.stream.BaseStream<T, S>> implements java.lang.AutoCloseable {
    -     method public abstract void close();
    -     method public abstract boolean isParallel();
    -     method public abstract java.util.Iterator<T> iterator();
    -@@ -65174,13 +65174,13 @@ package java.util.stream {
    -     method public abstract S unordered();
    -   }
    - 
    --  public abstract interface Collector {
    -+  public abstract interface Collector<T, A, R> {
    -     method public abstract java.util.function.BiConsumer<A, T> accumulator();
    -     method public abstract java.util.Set<java.util.stream.Collector.Characteristics> characteristics();
    -     method public abstract java.util.function.BinaryOperator<A> combiner();
    -     method public abstract java.util.function.Function<A, R> finisher();
    --    method public static java.util.stream.Collector<T, R, R> of(java.util.function.Supplier<R>, java.util.function.BiConsumer<R, T>, java.util.function.BinaryOperator<R>, java.util.stream.Collector.Characteristics...);
    --    method public static java.util.stream.Collector<T, A, R> of(java.util.function.Supplier<A>, java.util.function.BiConsumer<A, T>, java.util.function.BinaryOperator<A>, java.util.function.Function<A, R>, java.util.stream.Collector.Characteristics...);
    -+    method public static <T, R> java.util.stream.Collector<T, R, R> of(java.util.function.Supplier<R>, java.util.function.BiConsumer<R, T>, java.util.function.BinaryOperator<R>, java.util.stream.Collector.Characteristics...);
    -+    method public static <T, A, R> java.util.stream.Collector<T, A, R> of(java.util.function.Supplier<A>, java.util.function.BiConsumer<A, T>, java.util.function.BinaryOperator<A>, java.util.function.Function<A, R>, java.util.stream.Collector.Characteristics...);
    -     method public abstract java.util.function.Supplier<A> supplier();
    -   }
    - 
    -@@ -65193,43 +65193,43 @@ package java.util.stream {
    -   }
    - 
    -   public final class Collectors {
    --    method public static java.util.stream.Collector<T, ?, java.lang.Double> averagingDouble(java.util.function.ToDoubleFunction<? super T>);
    --    method public static java.util.stream.Collector<T, ?, java.lang.Double> averagingInt(java.util.function.ToIntFunction<? super T>);
    --    method public static java.util.stream.Collector<T, ?, java.lang.Double> averagingLong(java.util.function.ToLongFunction<? super T>);
    --    method public static java.util.stream.Collector<T, A, RR> collectingAndThen(java.util.stream.Collector<T, A, R>, java.util.function.Function<R, RR>);
    --    method public static java.util.stream.Collector<T, ?, java.lang.Long> counting();
    --    method public static java.util.stream.Collector<T, ?, java.util.Map<K, java.util.List<T>>> groupingBy(java.util.function.Function<? super T, ? extends K>);
    --    method public static java.util.stream.Collector<T, ?, java.util.Map<K, D>> groupingBy(java.util.function.Function<? super T, ? extends K>, java.util.stream.Collector<? super T, A, D>);
    --    method public static java.util.stream.Collector<T, ?, M> groupingBy(java.util.function.Function<? super T, ? extends K>, java.util.function.Supplier<M>, java.util.stream.Collector<? super T, A, D>);
    --    method public static java.util.stream.Collector<T, ?, java.util.concurrent.ConcurrentMap<K, java.util.List<T>>> groupingByConcurrent(java.util.function.Function<? super T, ? extends K>);
    --    method public static java.util.stream.Collector<T, ?, java.util.concurrent.ConcurrentMap<K, D>> groupingByConcurrent(java.util.function.Function<? super T, ? extends K>, java.util.stream.Collector<? super T, A, D>);
    --    method public static java.util.stream.Collector<T, ?, M> groupingByConcurrent(java.util.function.Function<? super T, ? extends K>, java.util.function.Supplier<M>, java.util.stream.Collector<? super T, A, D>);
    -+    method public static <T> java.util.stream.Collector<T, ?, java.lang.Double> averagingDouble(java.util.function.ToDoubleFunction<? super T>);
    -+    method public static <T> java.util.stream.Collector<T, ?, java.lang.Double> averagingInt(java.util.function.ToIntFunction<? super T>);
    -+    method public static <T> java.util.stream.Collector<T, ?, java.lang.Double> averagingLong(java.util.function.ToLongFunction<? super T>);
    -+    method public static <T, A, R, RR> java.util.stream.Collector<T, A, RR> collectingAndThen(java.util.stream.Collector<T, A, R>, java.util.function.Function<R, RR>);
    -+    method public static <T> java.util.stream.Collector<T, ?, java.lang.Long> counting();
    -+    method public static <T, K> java.util.stream.Collector<T, ?, java.util.Map<K, java.util.List<T>>> groupingBy(java.util.function.Function<? super T, ? extends K>);
    -+    method public static <T, K, A, D> java.util.stream.Collector<T, ?, java.util.Map<K, D>> groupingBy(java.util.function.Function<? super T, ? extends K>, java.util.stream.Collector<? super T, A, D>);
    -+    method public static <T, K, D, A, M extends java.util.Map<K, D>> java.util.stream.Collector<T, ?, M> groupingBy(java.util.function.Function<? super T, ? extends K>, java.util.function.Supplier<M>, java.util.stream.Collector<? super T, A, D>);
    -+    method public static <T, K> java.util.stream.Collector<T, ?, java.util.concurrent.ConcurrentMap<K, java.util.List<T>>> groupingByConcurrent(java.util.function.Function<? super T, ? extends K>);
    -+    method public static <T, K, A, D> java.util.stream.Collector<T, ?, java.util.concurrent.ConcurrentMap<K, D>> groupingByConcurrent(java.util.function.Function<? super T, ? extends K>, java.util.stream.Collector<? super T, A, D>);
    -+    method public static <T, K, A, D, M extends java.util.concurrent.ConcurrentMap<K, D>> java.util.stream.Collector<T, ?, M> groupingByConcurrent(java.util.function.Function<? super T, ? extends K>, java.util.function.Supplier<M>, java.util.stream.Collector<? super T, A, D>);
    -     method public static java.util.stream.Collector<java.lang.CharSequence, ?, java.lang.String> joining();
    -     method public static java.util.stream.Collector<java.lang.CharSequence, ?, java.lang.String> joining(java.lang.CharSequence);
    -     method public static java.util.stream.Collector<java.lang.CharSequence, ?, java.lang.String> joining(java.lang.CharSequence, java.lang.CharSequence, java.lang.CharSequence);
    --    method public static java.util.stream.Collector<T, ?, R> mapping(java.util.function.Function<? super T, ? extends U>, java.util.stream.Collector<? super U, A, R>);
    --    method public static java.util.stream.Collector<T, ?, java.util.Optional<T>> maxBy(java.util.Comparator<? super T>);
    --    method public static java.util.stream.Collector<T, ?, java.util.Optional<T>> minBy(java.util.Comparator<? super T>);
    --    method public static java.util.stream.Collector<T, ?, java.util.Map<java.lang.Boolean, java.util.List<T>>> partitioningBy(java.util.function.Predicate<? super T>);
    --    method public static java.util.stream.Collector<T, ?, java.util.Map<java.lang.Boolean, D>> partitioningBy(java.util.function.Predicate<? super T>, java.util.stream.Collector<? super T, A, D>);
    --    method public static java.util.stream.Collector<T, ?, T> reducing(T, java.util.function.BinaryOperator<T>);
    --    method public static java.util.stream.Collector<T, ?, java.util.Optional<T>> reducing(java.util.function.BinaryOperator<T>);
    --    method public static java.util.stream.Collector<T, ?, U> reducing(U, java.util.function.Function<? super T, ? extends U>, java.util.function.BinaryOperator<U>);
    --    method public static java.util.stream.Collector<T, ?, java.util.DoubleSummaryStatistics> summarizingDouble(java.util.function.ToDoubleFunction<? super T>);
    --    method public static java.util.stream.Collector<T, ?, java.util.IntSummaryStatistics> summarizingInt(java.util.function.ToIntFunction<? super T>);
    --    method public static java.util.stream.Collector<T, ?, java.util.LongSummaryStatistics> summarizingLong(java.util.function.ToLongFunction<? super T>);
    --    method public static java.util.stream.Collector<T, ?, java.lang.Double> summingDouble(java.util.function.ToDoubleFunction<? super T>);
    --    method public static java.util.stream.Collector<T, ?, java.lang.Integer> summingInt(java.util.function.ToIntFunction<? super T>);
    --    method public static java.util.stream.Collector<T, ?, java.lang.Long> summingLong(java.util.function.ToLongFunction<? super T>);
    --    method public static java.util.stream.Collector<T, ?, C> toCollection(java.util.function.Supplier<C>);
    --    method public static java.util.stream.Collector<T, ?, java.util.concurrent.ConcurrentMap<K, U>> toConcurrentMap(java.util.function.Function<? super T, ? extends K>, java.util.function.Function<? super T, ? extends U>);
    --    method public static java.util.stream.Collector<T, ?, java.util.concurrent.ConcurrentMap<K, U>> toConcurrentMap(java.util.function.Function<? super T, ? extends K>, java.util.function.Function<? super T, ? extends U>, java.util.function.BinaryOperator<U>);
    --    method public static java.util.stream.Collector<T, ?, M> toConcurrentMap(java.util.function.Function<? super T, ? extends K>, java.util.function.Function<? super T, ? extends U>, java.util.function.BinaryOperator<U>, java.util.function.Supplier<M>);
    --    method public static java.util.stream.Collector<T, ?, java.util.List<T>> toList();
    --    method public static java.util.stream.Collector<T, ?, java.util.Map<K, U>> toMap(java.util.function.Function<? super T, ? extends K>, java.util.function.Function<? super T, ? extends U>);
    --    method public static java.util.stream.Collector<T, ?, java.util.Map<K, U>> toMap(java.util.function.Function<? super T, ? extends K>, java.util.function.Function<? super T, ? extends U>, java.util.function.BinaryOperator<U>);
    --    method public static java.util.stream.Collector<T, ?, M> toMap(java.util.function.Function<? super T, ? extends K>, java.util.function.Function<? super T, ? extends U>, java.util.function.BinaryOperator<U>, java.util.function.Supplier<M>);
    --    method public static java.util.stream.Collector<T, ?, java.util.Set<T>> toSet();
    -+    method public static <T, U, A, R> java.util.stream.Collector<T, ?, R> mapping(java.util.function.Function<? super T, ? extends U>, java.util.stream.Collector<? super U, A, R>);
    -+    method public static <T> java.util.stream.Collector<T, ?, java.util.Optional<T>> maxBy(java.util.Comparator<? super T>);
    -+    method public static <T> java.util.stream.Collector<T, ?, java.util.Optional<T>> minBy(java.util.Comparator<? super T>);
    -+    method public static <T> java.util.stream.Collector<T, ?, java.util.Map<java.lang.Boolean, java.util.List<T>>> partitioningBy(java.util.function.Predicate<? super T>);
    -+    method public static <T, D, A> java.util.stream.Collector<T, ?, java.util.Map<java.lang.Boolean, D>> partitioningBy(java.util.function.Predicate<? super T>, java.util.stream.Collector<? super T, A, D>);
    -+    method public static <T> java.util.stream.Collector<T, ?, T> reducing(T, java.util.function.BinaryOperator<T>);
    -+    method public static <T> java.util.stream.Collector<T, ?, java.util.Optional<T>> reducing(java.util.function.BinaryOperator<T>);
    -+    method public static <T, U> java.util.stream.Collector<T, ?, U> reducing(U, java.util.function.Function<? super T, ? extends U>, java.util.function.BinaryOperator<U>);
    -+    method public static <T> java.util.stream.Collector<T, ?, java.util.DoubleSummaryStatistics> summarizingDouble(java.util.function.ToDoubleFunction<? super T>);
    -+    method public static <T> java.util.stream.Collector<T, ?, java.util.IntSummaryStatistics> summarizingInt(java.util.function.ToIntFunction<? super T>);
    -+    method public static <T> java.util.stream.Collector<T, ?, java.util.LongSummaryStatistics> summarizingLong(java.util.function.ToLongFunction<? super T>);
    -+    method public static <T> java.util.stream.Collector<T, ?, java.lang.Double> summingDouble(java.util.function.ToDoubleFunction<? super T>);
    -+    method public static <T> java.util.stream.Collector<T, ?, java.lang.Integer> summingInt(java.util.function.ToIntFunction<? super T>);
    -+    method public static <T> java.util.stream.Collector<T, ?, java.lang.Long> summingLong(java.util.function.ToLongFunction<? super T>);
    -+    method public static <T, C extends java.util.Collection<T>> java.util.stream.Collector<T, ?, C> toCollection(java.util.function.Supplier<C>);
    -+    method public static <T, K, U> java.util.stream.Collector<T, ?, java.util.concurrent.ConcurrentMap<K, U>> toConcurrentMap(java.util.function.Function<? super T, ? extends K>, java.util.function.Function<? super T, ? extends U>);
    -+    method public static <T, K, U> java.util.stream.Collector<T, ?, java.util.concurrent.ConcurrentMap<K, U>> toConcurrentMap(java.util.function.Function<? super T, ? extends K>, java.util.function.Function<? super T, ? extends U>, java.util.function.BinaryOperator<U>);
    -+    method public static <T, K, U, M extends java.util.concurrent.ConcurrentMap<K, U>> java.util.stream.Collector<T, ?, M> toConcurrentMap(java.util.function.Function<? super T, ? extends K>, java.util.function.Function<? super T, ? extends U>, java.util.function.BinaryOperator<U>, java.util.function.Supplier<M>);
    -+    method public static <T> java.util.stream.Collector<T, ?, java.util.List<T>> toList();
    -+    method public static <T, K, U> java.util.stream.Collector<T, ?, java.util.Map<K, U>> toMap(java.util.function.Function<? super T, ? extends K>, java.util.function.Function<? super T, ? extends U>);
    -+    method public static <T, K, U> java.util.stream.Collector<T, ?, java.util.Map<K, U>> toMap(java.util.function.Function<? super T, ? extends K>, java.util.function.Function<? super T, ? extends U>, java.util.function.BinaryOperator<U>);
    -+    method public static <T, K, U, M extends java.util.Map<K, U>> java.util.stream.Collector<T, ?, M> toMap(java.util.function.Function<? super T, ? extends K>, java.util.function.Function<? super T, ? extends U>, java.util.function.BinaryOperator<U>, java.util.function.Supplier<M>);
    -+    method public static <T> java.util.stream.Collector<T, ?, java.util.Set<T>> toSet();
    -   }
    - 
    -   public abstract interface DoubleStream implements java.util.stream.BaseStream {
    -@@ -65238,7 +65238,7 @@ package java.util.stream {
    -     method public abstract java.util.OptionalDouble average();
    -     method public abstract java.util.stream.Stream<java.lang.Double> boxed();
    -     method public static java.util.stream.DoubleStream.Builder builder();
    --    method public abstract R collect(java.util.function.Supplier<R>, java.util.function.ObjDoubleConsumer<R>, java.util.function.BiConsumer<R, R>);
    -+    method public abstract <R> R collect(java.util.function.Supplier<R>, java.util.function.ObjDoubleConsumer<R>, java.util.function.BiConsumer<R, R>);
    -     method public static java.util.stream.DoubleStream concat(java.util.stream.DoubleStream, java.util.stream.DoubleStream);
    -     method public abstract long count();
    -     method public abstract java.util.stream.DoubleStream distinct();
    -@@ -65256,7 +65256,7 @@ package java.util.stream {
    -     method public abstract java.util.stream.DoubleStream map(java.util.function.DoubleUnaryOperator);
    -     method public abstract java.util.stream.IntStream mapToInt(java.util.function.DoubleToIntFunction);
    -     method public abstract java.util.stream.LongStream mapToLong(java.util.function.DoubleToLongFunction);
    --    method public abstract java.util.stream.Stream<U> mapToObj(java.util.function.DoubleFunction<? extends U>);
    -+    method public abstract <U> java.util.stream.Stream<U> mapToObj(java.util.function.DoubleFunction<? extends U>);
    -     method public abstract java.util.OptionalDouble max();
    -     method public abstract java.util.OptionalDouble min();
    -     method public abstract boolean noneMatch(java.util.function.DoublePredicate);
    -@@ -65289,7 +65289,7 @@ package java.util.stream {
    -     method public abstract java.util.OptionalDouble average();
    -     method public abstract java.util.stream.Stream<java.lang.Integer> boxed();
    -     method public static java.util.stream.IntStream.Builder builder();
    --    method public abstract R collect(java.util.function.Supplier<R>, java.util.function.ObjIntConsumer<R>, java.util.function.BiConsumer<R, R>);
    -+    method public abstract <R> R collect(java.util.function.Supplier<R>, java.util.function.ObjIntConsumer<R>, java.util.function.BiConsumer<R, R>);
    -     method public static java.util.stream.IntStream concat(java.util.stream.IntStream, java.util.stream.IntStream);
    -     method public abstract long count();
    -     method public abstract java.util.stream.IntStream distinct();
    -@@ -65307,7 +65307,7 @@ package java.util.stream {
    -     method public abstract java.util.stream.IntStream map(java.util.function.IntUnaryOperator);
    -     method public abstract java.util.stream.DoubleStream mapToDouble(java.util.function.IntToDoubleFunction);
    -     method public abstract java.util.stream.LongStream mapToLong(java.util.function.IntToLongFunction);
    --    method public abstract java.util.stream.Stream<U> mapToObj(java.util.function.IntFunction<? extends U>);
    -+    method public abstract <U> java.util.stream.Stream<U> mapToObj(java.util.function.IntFunction<? extends U>);
    -     method public abstract java.util.OptionalInt max();
    -     method public abstract java.util.OptionalInt min();
    -     method public abstract boolean noneMatch(java.util.function.IntPredicate);
    -@@ -65341,7 +65341,7 @@ package java.util.stream {
    -     method public abstract java.util.OptionalDouble average();
    -     method public abstract java.util.stream.Stream<java.lang.Long> boxed();
    -     method public static java.util.stream.LongStream.Builder builder();
    --    method public abstract R collect(java.util.function.Supplier<R>, java.util.function.ObjLongConsumer<R>, java.util.function.BiConsumer<R, R>);
    -+    method public abstract <R> R collect(java.util.function.Supplier<R>, java.util.function.ObjLongConsumer<R>, java.util.function.BiConsumer<R, R>);
    -     method public static java.util.stream.LongStream concat(java.util.stream.LongStream, java.util.stream.LongStream);
    -     method public abstract long count();
    -     method public abstract java.util.stream.LongStream distinct();
    -@@ -65359,7 +65359,7 @@ package java.util.stream {
    -     method public abstract java.util.stream.LongStream map(java.util.function.LongUnaryOperator);
    -     method public abstract java.util.stream.DoubleStream mapToDouble(java.util.function.LongToDoubleFunction);
    -     method public abstract java.util.stream.IntStream mapToInt(java.util.function.LongToIntFunction);
    --    method public abstract java.util.stream.Stream<U> mapToObj(java.util.function.LongFunction<? extends U>);
    -+    method public abstract <U> java.util.stream.Stream<U> mapToObj(java.util.function.LongFunction<? extends U>);
    -     method public abstract java.util.OptionalLong max();
    -     method public abstract java.util.OptionalLong min();
    -     method public abstract boolean noneMatch(java.util.function.LongPredicate);
    -@@ -65386,49 +65386,49 @@ package java.util.stream {
    -     method public abstract java.util.stream.LongStream build();
    -   }
    - 
    --  public abstract interface Stream implements java.util.stream.BaseStream {
    -+  public abstract interface Stream<T> implements java.util.stream.BaseStream {
    -     method public abstract boolean allMatch(java.util.function.Predicate<? super T>);
    -     method public abstract boolean anyMatch(java.util.function.Predicate<? super T>);
    --    method public static java.util.stream.Stream.Builder<T> builder();
    --    method public abstract R collect(java.util.function.Supplier<R>, java.util.function.BiConsumer<R, ? super T>, java.util.function.BiConsumer<R, R>);
    --    method public abstract R collect(java.util.stream.Collector<? super T, A, R>);
    --    method public static java.util.stream.Stream<T> concat(java.util.stream.Stream<? extends T>, java.util.stream.Stream<? extends T>);
    -+    method public static <T> java.util.stream.Stream.Builder<T> builder();
    -+    method public abstract <R> R collect(java.util.function.Supplier<R>, java.util.function.BiConsumer<R, ? super T>, java.util.function.BiConsumer<R, R>);
    -+    method public abstract <R, A> R collect(java.util.stream.Collector<? super T, A, R>);
    -+    method public static <T> java.util.stream.Stream<T> concat(java.util.stream.Stream<? extends T>, java.util.stream.Stream<? extends T>);
    -     method public abstract long count();
    -     method public abstract java.util.stream.Stream<T> distinct();
    --    method public static java.util.stream.Stream<T> empty();
    -+    method public static <T> java.util.stream.Stream<T> empty();
    -     method public abstract java.util.stream.Stream<T> filter(java.util.function.Predicate<? super T>);
    -     method public abstract java.util.Optional<T> findAny();
    -     method public abstract java.util.Optional<T> findFirst();
    --    method public abstract java.util.stream.Stream<R> flatMap(java.util.function.Function<? super T, ? extends java.util.stream.Stream<? extends R>>);
    -+    method public abstract <R> java.util.stream.Stream<R> flatMap(java.util.function.Function<? super T, ? extends java.util.stream.Stream<? extends R>>);
    -     method public abstract java.util.stream.DoubleStream flatMapToDouble(java.util.function.Function<? super T, ? extends java.util.stream.DoubleStream>);
    -     method public abstract java.util.stream.IntStream flatMapToInt(java.util.function.Function<? super T, ? extends java.util.stream.IntStream>);
    -     method public abstract java.util.stream.LongStream flatMapToLong(java.util.function.Function<? super T, ? extends java.util.stream.LongStream>);
    -     method public abstract void forEach(java.util.function.Consumer<? super T>);
    -     method public abstract void forEachOrdered(java.util.function.Consumer<? super T>);
    --    method public static java.util.stream.Stream<T> generate(java.util.function.Supplier<T>);
    --    method public static java.util.stream.Stream<T> iterate(T, java.util.function.UnaryOperator<T>);
    -+    method public static <T> java.util.stream.Stream<T> generate(java.util.function.Supplier<T>);
    -+    method public static <T> java.util.stream.Stream<T> iterate(T, java.util.function.UnaryOperator<T>);
    -     method public abstract java.util.stream.Stream<T> limit(long);
    --    method public abstract java.util.stream.Stream<R> map(java.util.function.Function<? super T, ? extends R>);
    -+    method public abstract <R> java.util.stream.Stream<R> map(java.util.function.Function<? super T, ? extends R>);
    -     method public abstract java.util.stream.DoubleStream mapToDouble(java.util.function.ToDoubleFunction<? super T>);
    -     method public abstract java.util.stream.IntStream mapToInt(java.util.function.ToIntFunction<? super T>);
    -     method public abstract java.util.stream.LongStream mapToLong(java.util.function.ToLongFunction<? super T>);
    -     method public abstract java.util.Optional<T> max(java.util.Comparator<? super T>);
    -     method public abstract java.util.Optional<T> min(java.util.Comparator<? super T>);
    -     method public abstract boolean noneMatch(java.util.function.Predicate<? super T>);
    --    method public static java.util.stream.Stream<T> of(T);
    --    method public static java.util.stream.Stream<T> of(T...);
    -+    method public static <T> java.util.stream.Stream<T> of(T);
    -+    method public static <T> java.util.stream.Stream<T> of(T...);
    -     method public abstract java.util.stream.Stream<T> peek(java.util.function.Consumer<? super T>);
    -     method public abstract T reduce(T, java.util.function.BinaryOperator<T>);
    -     method public abstract java.util.Optional<T> reduce(java.util.function.BinaryOperator<T>);
    --    method public abstract U reduce(U, java.util.function.BiFunction<U, ? super T, U>, java.util.function.BinaryOperator<U>);
    -+    method public abstract <U> U reduce(U, java.util.function.BiFunction<U, ? super T, U>, java.util.function.BinaryOperator<U>);
    -     method public abstract java.util.stream.Stream<T> skip(long);
    -     method public abstract java.util.stream.Stream<T> sorted();
    -     method public abstract java.util.stream.Stream<T> sorted(java.util.Comparator<? super T>);
    -     method public abstract java.lang.Object[] toArray();
    --    method public abstract A[] toArray(java.util.function.IntFunction<A[]>);
    -+    method public abstract <A> A[] toArray(java.util.function.IntFunction<A[]>);
    -   }
    - 
    --  public static abstract interface Stream.Builder implements java.util.function.Consumer {
    -+  public static abstract interface Stream.Builder<T> implements java.util.function.Consumer {
    -     method public abstract void accept(T);
    -     method public default java.util.stream.Stream.Builder<T> add(T);
    -     method public abstract java.util.stream.Stream<T> build();
    -@@ -65441,8 +65441,8 @@ package java.util.stream {
    -     method public static java.util.stream.IntStream intStream(java.util.function.Supplier<? extends java.util.Spliterator.OfInt>, int, boolean);
    -     method public static java.util.stream.LongStream longStream(java.util.Spliterator.OfLong, boolean);
    -     method public static java.util.stream.LongStream longStream(java.util.function.Supplier<? extends java.util.Spliterator.OfLong>, int, boolean);
    --    method public static java.util.stream.Stream<T> stream(java.util.Spliterator<T>, boolean);
    --    method public static java.util.stream.Stream<T> stream(java.util.function.Supplier<? extends java.util.Spliterator<T>>, int, boolean);
    -+    method public static <T> java.util.stream.Stream<T> stream(java.util.Spliterator<T>, boolean);
    -+    method public static <T> java.util.stream.Stream<T> stream(java.util.function.Supplier<? extends java.util.Spliterator<T>>, int, boolean);
    -   }
    - 
    - }
    -@@ -67613,16 +67613,16 @@ package javax.security.auth {
    -   public final class Subject implements java.io.Serializable {
    -     ctor public Subject();
    -     ctor public Subject(boolean, java.util.Set<? extends java.security.Principal>, java.util.Set<?>, java.util.Set<?>);
    --    method public static T doAs(javax.security.auth.Subject, java.security.PrivilegedAction<T>);
    --    method public static T doAs(javax.security.auth.Subject, java.security.PrivilegedExceptionAction<T>) throws java.security.PrivilegedActionException;
    --    method public static T doAsPrivileged(javax.security.auth.Subject, java.security.PrivilegedAction<T>, java.security.AccessControlContext);
    --    method public static T doAsPrivileged(javax.security.auth.Subject, java.security.PrivilegedExceptionAction<T>, java.security.AccessControlContext) throws java.security.PrivilegedActionException;
    -+    method public static <T> T doAs(javax.security.auth.Subject, java.security.PrivilegedAction<T>);
    -+    method public static <T> T doAs(javax.security.auth.Subject, java.security.PrivilegedExceptionAction<T>) throws java.security.PrivilegedActionException;
    -+    method public static <T> T doAsPrivileged(javax.security.auth.Subject, java.security.PrivilegedAction<T>, java.security.AccessControlContext);
    -+    method public static <T> T doAsPrivileged(javax.security.auth.Subject, java.security.PrivilegedExceptionAction<T>, java.security.AccessControlContext) throws java.security.PrivilegedActionException;
    -     method public java.util.Set<java.security.Principal> getPrincipals();
    --    method public java.util.Set<T> getPrincipals(java.lang.Class<T>);
    -+    method public <T extends java.security.Principal> java.util.Set<T> getPrincipals(java.lang.Class<T>);
    -     method public java.util.Set<java.lang.Object> getPrivateCredentials();
    --    method public java.util.Set<T> getPrivateCredentials(java.lang.Class<T>);
    -+    method public <T> java.util.Set<T> getPrivateCredentials(java.lang.Class<T>);
    -     method public java.util.Set<java.lang.Object> getPublicCredentials();
    --    method public java.util.Set<T> getPublicCredentials(java.lang.Class<T>);
    -+    method public <T> java.util.Set<T> getPublicCredentials(java.lang.Class<T>);
    -     method public static javax.security.auth.Subject getSubject(java.security.AccessControlContext);
    -     method public boolean isReadOnly();
    -     method public void setReadOnly();
    -diff --git a/api/test-current.txt b/api/test-current.txt
    -index 3b5c223..d74526b 100644
    ---- a/api/test-current.txt
    -+++ b/api/test-current.txt
    -@@ -2906,11 +2906,11 @@ package android.accounts {
    -     field public static final java.lang.String LOGIN_ACCOUNTS_CHANGED_ACTION = "android.accounts.LOGIN_ACCOUNTS_CHANGED";
    -   }
    - 
    --  public abstract interface AccountManagerCallback {
    -+  public abstract interface AccountManagerCallback<V> {
    -     method public abstract void run(android.accounts.AccountManagerFuture<V>);
    -   }
    - 
    --  public abstract interface AccountManagerFuture {
    -+  public abstract interface AccountManagerFuture<V> {
    -     method public abstract boolean cancel(boolean);
    -     method public abstract V getResult() throws android.accounts.AuthenticatorException, java.io.IOException, android.accounts.OperationCanceledException;
    -     method public abstract V getResult(long, java.util.concurrent.TimeUnit) throws android.accounts.AuthenticatorException, java.io.IOException, android.accounts.OperationCanceledException;
    -@@ -3056,7 +3056,7 @@ package android.animation {
    -     method public java.lang.Object evaluate(float, java.lang.Object, java.lang.Object);
    -   }
    - 
    --  public abstract class BidirectionalTypeConverter extends android.animation.TypeConverter {
    -+  public abstract class BidirectionalTypeConverter<T, V> extends android.animation.TypeConverter {
    -     ctor public BidirectionalTypeConverter(java.lang.Class<T>, java.lang.Class<V>);
    -     method public abstract T convertBack(V);
    -     method public android.animation.BidirectionalTypeConverter<V, T> invert();
    -@@ -3148,26 +3148,26 @@ package android.animation {
    -     method public java.lang.String getPropertyName();
    -     method public java.lang.Object getTarget();
    -     method public static android.animation.ObjectAnimator ofArgb(java.lang.Object, java.lang.String, int...);
    --    method public static android.animation.ObjectAnimator ofArgb(T, android.util.Property<T, java.lang.Integer>, int...);
    -+    method public static <T> android.animation.ObjectAnimator ofArgb(T, android.util.Property<T, java.lang.Integer>, int...);
    -     method public static android.animation.ObjectAnimator ofFloat(java.lang.Object, java.lang.String, float...);
    -     method public static android.animation.ObjectAnimator ofFloat(java.lang.Object, java.lang.String, java.lang.String, android.graphics.Path);
    --    method public static android.animation.ObjectAnimator ofFloat(T, android.util.Property<T, java.lang.Float>, float...);
    --    method public static android.animation.ObjectAnimator ofFloat(T, android.util.Property<T, java.lang.Float>, android.util.Property<T, java.lang.Float>, android.graphics.Path);
    -+    method public static <T> android.animation.ObjectAnimator ofFloat(T, android.util.Property<T, java.lang.Float>, float...);
    -+    method public static <T> android.animation.ObjectAnimator ofFloat(T, android.util.Property<T, java.lang.Float>, android.util.Property<T, java.lang.Float>, android.graphics.Path);
    -     method public static android.animation.ObjectAnimator ofInt(java.lang.Object, java.lang.String, int...);
    -     method public static android.animation.ObjectAnimator ofInt(java.lang.Object, java.lang.String, java.lang.String, android.graphics.Path);
    --    method public static android.animation.ObjectAnimator ofInt(T, android.util.Property<T, java.lang.Integer>, int...);
    --    method public static android.animation.ObjectAnimator ofInt(T, android.util.Property<T, java.lang.Integer>, android.util.Property<T, java.lang.Integer>, android.graphics.Path);
    -+    method public static <T> android.animation.ObjectAnimator ofInt(T, android.util.Property<T, java.lang.Integer>, int...);
    -+    method public static <T> android.animation.ObjectAnimator ofInt(T, android.util.Property<T, java.lang.Integer>, android.util.Property<T, java.lang.Integer>, android.graphics.Path);
    -     method public static android.animation.ObjectAnimator ofMultiFloat(java.lang.Object, java.lang.String, float[][]);
    -     method public static android.animation.ObjectAnimator ofMultiFloat(java.lang.Object, java.lang.String, android.graphics.Path);
    --    method public static android.animation.ObjectAnimator ofMultiFloat(java.lang.Object, java.lang.String, android.animation.TypeConverter<T, float[]>, android.animation.TypeEvaluator<T>, T...);
    -+    method public static <T> android.animation.ObjectAnimator ofMultiFloat(java.lang.Object, java.lang.String, android.animation.TypeConverter<T, float[]>, android.animation.TypeEvaluator<T>, T...);
    -     method public static android.animation.ObjectAnimator ofMultiInt(java.lang.Object, java.lang.String, int[][]);
    -     method public static android.animation.ObjectAnimator ofMultiInt(java.lang.Object, java.lang.String, android.graphics.Path);
    --    method public static android.animation.ObjectAnimator ofMultiInt(java.lang.Object, java.lang.String, android.animation.TypeConverter<T, int[]>, android.animation.TypeEvaluator<T>, T...);
    -+    method public static <T> android.animation.ObjectAnimator ofMultiInt(java.lang.Object, java.lang.String, android.animation.TypeConverter<T, int[]>, android.animation.TypeEvaluator<T>, T...);
    -     method public static android.animation.ObjectAnimator ofObject(java.lang.Object, java.lang.String, android.animation.TypeEvaluator, java.lang.Object...);
    -     method public static android.animation.ObjectAnimator ofObject(java.lang.Object, java.lang.String, android.animation.TypeConverter<android.graphics.PointF, ?>, android.graphics.Path);
    --    method public static android.animation.ObjectAnimator ofObject(T, android.util.Property<T, V>, android.animation.TypeEvaluator<V>, V...);
    --    method public static android.animation.ObjectAnimator ofObject(T, android.util.Property<T, P>, android.animation.TypeConverter<V, P>, android.animation.TypeEvaluator<V>, V...);
    --    method public static android.animation.ObjectAnimator ofObject(T, android.util.Property<T, V>, android.animation.TypeConverter<android.graphics.PointF, V>, android.graphics.Path);
    -+    method public static <T, V> android.animation.ObjectAnimator ofObject(T, android.util.Property<T, V>, android.animation.TypeEvaluator<V>, V...);
    -+    method public static <T, V, P> android.animation.ObjectAnimator ofObject(T, android.util.Property<T, P>, android.animation.TypeConverter<V, P>, android.animation.TypeEvaluator<V>, V...);
    -+    method public static <T, V> android.animation.ObjectAnimator ofObject(T, android.util.Property<T, V>, android.animation.TypeConverter<android.graphics.PointF, V>, android.graphics.Path);
    -     method public static android.animation.ObjectAnimator ofPropertyValuesHolder(java.lang.Object, android.animation.PropertyValuesHolder...);
    -     method public void setAutoCancel(boolean);
    -     method public void setProperty(android.util.Property);
    -@@ -3191,17 +3191,17 @@ package android.animation {
    -     method public static android.animation.PropertyValuesHolder ofKeyframe(android.util.Property, android.animation.Keyframe...);
    -     method public static android.animation.PropertyValuesHolder ofMultiFloat(java.lang.String, float[][]);
    -     method public static android.animation.PropertyValuesHolder ofMultiFloat(java.lang.String, android.graphics.Path);
    --    method public static android.animation.PropertyValuesHolder ofMultiFloat(java.lang.String, android.animation.TypeConverter<V, float[]>, android.animation.TypeEvaluator<V>, V...);
    --    method public static android.animation.PropertyValuesHolder ofMultiFloat(java.lang.String, android.animation.TypeConverter<T, float[]>, android.animation.TypeEvaluator<T>, android.animation.Keyframe...);
    -+    method public static <V> android.animation.PropertyValuesHolder ofMultiFloat(java.lang.String, android.animation.TypeConverter<V, float[]>, android.animation.TypeEvaluator<V>, V...);
    -+    method public static <T> android.animation.PropertyValuesHolder ofMultiFloat(java.lang.String, android.animation.TypeConverter<T, float[]>, android.animation.TypeEvaluator<T>, android.animation.Keyframe...);
    -     method public static android.animation.PropertyValuesHolder ofMultiInt(java.lang.String, int[][]);
    -     method public static android.animation.PropertyValuesHolder ofMultiInt(java.lang.String, android.graphics.Path);
    --    method public static android.animation.PropertyValuesHolder ofMultiInt(java.lang.String, android.animation.TypeConverter<V, int[]>, android.animation.TypeEvaluator<V>, V...);
    --    method public static android.animation.PropertyValuesHolder ofMultiInt(java.lang.String, android.animation.TypeConverter<T, int[]>, android.animation.TypeEvaluator<T>, android.animation.Keyframe...);
    -+    method public static <V> android.animation.PropertyValuesHolder ofMultiInt(java.lang.String, android.animation.TypeConverter<V, int[]>, android.animation.TypeEvaluator<V>, V...);
    -+    method public static <T> android.animation.PropertyValuesHolder ofMultiInt(java.lang.String, android.animation.TypeConverter<T, int[]>, android.animation.TypeEvaluator<T>, android.animation.Keyframe...);
    -     method public static android.animation.PropertyValuesHolder ofObject(java.lang.String, android.animation.TypeEvaluator, java.lang.Object...);
    -     method public static android.animation.PropertyValuesHolder ofObject(java.lang.String, android.animation.TypeConverter<android.graphics.PointF, ?>, android.graphics.Path);
    --    method public static android.animation.PropertyValuesHolder ofObject(android.util.Property, android.animation.TypeEvaluator<V>, V...);
    --    method public static android.animation.PropertyValuesHolder ofObject(android.util.Property<?, V>, android.animation.TypeConverter<T, V>, android.animation.TypeEvaluator<T>, T...);
    --    method public static android.animation.PropertyValuesHolder ofObject(android.util.Property<?, V>, android.animation.TypeConverter<android.graphics.PointF, V>, android.graphics.Path);
    -+    method public static <V> android.animation.PropertyValuesHolder ofObject(android.util.Property, android.animation.TypeEvaluator<V>, V...);
    -+    method public static <T, V> android.animation.PropertyValuesHolder ofObject(android.util.Property<?, V>, android.animation.TypeConverter<T, V>, android.animation.TypeEvaluator<T>, T...);
    -+    method public static <V> android.animation.PropertyValuesHolder ofObject(android.util.Property<?, V>, android.animation.TypeConverter<android.graphics.PointF, V>, android.graphics.Path);
    -     method public void setConverter(android.animation.TypeConverter);
    -     method public void setEvaluator(android.animation.TypeEvaluator);
    -     method public void setFloatValues(float...);
    -@@ -3238,12 +3238,12 @@ package android.animation {
    -     method public abstract float getInterpolation(float);
    -   }
    - 
    --  public abstract class TypeConverter {
    -+  public abstract class TypeConverter<T, V> {
    -     ctor public TypeConverter(java.lang.Class<T>, java.lang.Class<V>);
    -     method public abstract V convert(T);
    -   }
    - 
    --  public abstract interface TypeEvaluator {
    -+  public abstract interface TypeEvaluator<T> {
    -     method public abstract T evaluate(float, T, T);
    -   }
    - 
    -@@ -3255,6 +3255,7 @@ package android.animation {
    -     method public java.lang.Object getAnimatedValue(java.lang.String);
    -     method public long getCurrentPlayTime();
    -     method public long getDuration();
    -+    method public static float getDurationScale();
    -     method public static long getFrameDelay();
    -     method public int getRepeatCount();
    -     method public int getRepeatMode();
    -@@ -3272,6 +3273,7 @@ package android.animation {
    -     method public void setCurrentFraction(float);
    -     method public void setCurrentPlayTime(long);
    -     method public android.animation.ValueAnimator setDuration(long);
    -+    method public static void setDurationScale(float);
    -     method public void setEvaluator(android.animation.TypeEvaluator);
    -     method public void setFloatValues(float...);
    -     method public static void setFrameDelay(long);
    -@@ -4572,7 +4574,7 @@ package android.app {
    -     method public android.os.Parcelable saveAllState();
    -   }
    - 
    --  public abstract class FragmentHostCallback extends android.app.FragmentContainer {
    -+  public abstract class FragmentHostCallback<E> extends android.app.FragmentContainer {
    -     ctor public FragmentHostCallback(android.content.Context, android.os.Handler, int);
    -     method public void onAttachFragment(android.app.Fragment);
    -     method public void onDump(java.lang.String, java.io.FileDescriptor, java.io.PrintWriter, java.lang.String[]);
    -@@ -4839,12 +4841,12 @@ package android.app {
    -     method public abstract void destroyLoader(int);
    -     method public abstract void dump(java.lang.String, java.io.FileDescriptor, java.io.PrintWriter, java.lang.String[]);
    -     method public static void enableDebugLogging(boolean);
    --    method public abstract android.content.Loader<D> getLoader(int);
    --    method public abstract android.content.Loader<D> initLoader(int, android.os.Bundle, android.app.LoaderManager.LoaderCallbacks<D>);
    --    method public abstract android.content.Loader<D> restartLoader(int, android.os.Bundle, android.app.LoaderManager.LoaderCallbacks<D>);
    -+    method public abstract <D> android.content.Loader<D> getLoader(int);
    -+    method public abstract <D> android.content.Loader<D> initLoader(int, android.os.Bundle, android.app.LoaderManager.LoaderCallbacks<D>);
    -+    method public abstract <D> android.content.Loader<D> restartLoader(int, android.os.Bundle, android.app.LoaderManager.LoaderCallbacks<D>);
    -   }
    - 
    --  public static abstract interface LoaderManager.LoaderCallbacks {
    -+  public static abstract interface LoaderManager.LoaderCallbacks<D> {
    -     method public abstract android.content.Loader<D> onCreateLoader(int, android.os.Bundle);
    -     method public abstract void onLoadFinished(android.content.Loader<D>, D);
    -     method public abstract void onLoaderReset(android.content.Loader<D>);
    -@@ -5629,6 +5631,7 @@ package android.app {
    -   public class TimePickerDialog extends android.app.AlertDialog implements android.content.DialogInterface.OnClickListener android.widget.TimePicker.OnTimeChangedListener {
    -     ctor public TimePickerDialog(android.content.Context, android.app.TimePickerDialog.OnTimeSetListener, int, int, boolean);
    -     ctor public TimePickerDialog(android.content.Context, int, android.app.TimePickerDialog.OnTimeSetListener, int, int, boolean);
    -+    method public android.widget.TimePicker getTimePicker();
    -     method public void onClick(android.content.DialogInterface, int);
    -     method public void onTimeChanged(android.widget.TimePicker, int, int);
    -     method public void updateTime(int, int);
    -@@ -7635,7 +7638,7 @@ package android.content {
    -     ctor public AsyncQueryHandler.WorkerHandler(android.os.Looper);
    -   }
    - 
    --  public abstract class AsyncTaskLoader extends android.content.Loader {
    -+  public abstract class AsyncTaskLoader<D> extends android.content.Loader {
    -     ctor public AsyncTaskLoader(android.content.Context);
    -     method public void cancelLoadInBackground();
    -     method public boolean isLoadInBackgroundCanceled();
    -@@ -7817,7 +7820,7 @@ package android.content {
    -     method public android.os.ParcelFileDescriptor openFile(android.net.Uri, java.lang.String) throws java.io.FileNotFoundException;
    -     method public android.os.ParcelFileDescriptor openFile(android.net.Uri, java.lang.String, android.os.CancellationSignal) throws java.io.FileNotFoundException;
    -     method protected final android.os.ParcelFileDescriptor openFileHelper(android.net.Uri, java.lang.String) throws java.io.FileNotFoundException;
    --    method public android.os.ParcelFileDescriptor openPipeHelper(android.net.Uri, java.lang.String, android.os.Bundle, T, android.content.ContentProvider.PipeDataWriter<T>) throws java.io.FileNotFoundException;
    -+    method public <T> android.os.ParcelFileDescriptor openPipeHelper(android.net.Uri, java.lang.String, android.os.Bundle, T, android.content.ContentProvider.PipeDataWriter<T>) throws java.io.FileNotFoundException;
    -     method public android.content.res.AssetFileDescriptor openTypedAssetFile(android.net.Uri, java.lang.String, android.os.Bundle) throws java.io.FileNotFoundException;
    -     method public android.content.res.AssetFileDescriptor openTypedAssetFile(android.net.Uri, java.lang.String, android.os.Bundle, android.os.CancellationSignal) throws java.io.FileNotFoundException;
    -     method public abstract android.database.Cursor query(android.net.Uri, java.lang.String[], java.lang.String, java.lang.String[], java.lang.String);
    -@@ -7830,7 +7833,7 @@ package android.content {
    -     method public abstract int update(android.net.Uri, android.content.ContentValues, java.lang.String, java.lang.String[]);
    -   }
    - 
    --  public static abstract interface ContentProvider.PipeDataWriter {
    -+  public static abstract interface ContentProvider.PipeDataWriter<T> {
    -     method public abstract void writeDataToPipe(android.os.ParcelFileDescriptor, android.net.Uri, java.lang.String, android.os.Bundle, T);
    -   }
    - 
    -@@ -8102,7 +8105,7 @@ package android.content {
    -     method public final java.lang.String getString(int);
    -     method public final java.lang.String getString(int, java.lang.Object...);
    -     method public abstract java.lang.Object getSystemService(java.lang.String);
    --    method public final T getSystemService(java.lang.Class<T>);
    -+    method public final <T> T getSystemService(java.lang.Class<T>);
    -     method public abstract java.lang.String getSystemServiceName(java.lang.Class<?>);
    -     method public final java.lang.CharSequence getText(int);
    -     method public abstract android.content.res.Resources.Theme getTheme();
    -@@ -8459,8 +8462,8 @@ package android.content {
    -     method public long getLongExtra(java.lang.String, long);
    -     method public java.lang.String getPackage();
    -     method public android.os.Parcelable[] getParcelableArrayExtra(java.lang.String);
    --    method public java.util.ArrayList<T> getParcelableArrayListExtra(java.lang.String);
    --    method public T getParcelableExtra(java.lang.String);
    -+    method public <T extends android.os.Parcelable> java.util.ArrayList<T> getParcelableArrayListExtra(java.lang.String);
    -+    method public <T extends android.os.Parcelable> T getParcelableExtra(java.lang.String);
    -     method public java.lang.String getScheme();
    -     method public android.content.Intent getSelector();
    -     method public java.io.Serializable getSerializableExtra(java.lang.String);
    -@@ -8935,7 +8938,7 @@ package android.content {
    -     ctor public IntentSender.SendIntentException(java.lang.Exception);
    -   }
    - 
    --  public class Loader {
    -+  public class Loader<D> {
    -     ctor public Loader(android.content.Context);
    -     method public void abandon();
    -     method public boolean cancelLoad();
    -@@ -8972,11 +8975,11 @@ package android.content {
    -     ctor public Loader.ForceLoadContentObserver();
    -   }
    - 
    --  public static abstract interface Loader.OnLoadCanceledListener {
    -+  public static abstract interface Loader.OnLoadCanceledListener<D> {
    -     method public abstract void onLoadCanceled(android.content.Loader<D>);
    -   }
    - 
    --  public static abstract interface Loader.OnLoadCompleteListener {
    -+  public static abstract interface Loader.OnLoadCompleteListener<D> {
    -     method public abstract void onLoadComplete(android.content.Loader<D>, D);
    -   }
    - 
    -@@ -10853,7 +10856,7 @@ package android.database {
    -     method public boolean isNull(int);
    -   }
    - 
    --  public abstract class Observable {
    -+  public abstract class Observable<T> {
    -     ctor public Observable();
    -     method public void registerObserver(T);
    -     method public void unregisterAll();
    -@@ -12743,7 +12746,7 @@ package android.graphics.drawable {
    -   public class AnimatedStateListDrawable extends android.graphics.drawable.StateListDrawable {
    -     ctor public AnimatedStateListDrawable();
    -     method public void addState(int[], android.graphics.drawable.Drawable, int);
    --    method public void addTransition(int, int, T, boolean);
    -+    method public <T extends android.graphics.drawable.Drawable & android.graphics.drawable.Animatable> void addTransition(int, int, T, boolean);
    -   }
    - 
    -   public class AnimatedVectorDrawable extends android.graphics.drawable.Drawable implements android.graphics.drawable.Animatable2 {
    -@@ -13867,7 +13870,7 @@ package android.hardware.camera2 {
    -   }
    - 
    -   public final class CameraCharacteristics extends android.hardware.camera2.CameraMetadata {
    --    method public T get(android.hardware.camera2.CameraCharacteristics.Key<T>);
    -+    method public <T> T get(android.hardware.camera2.CameraCharacteristics.Key<T>);
    -     method public java.util.List<android.hardware.camera2.CaptureRequest.Key<?>> getAvailableCaptureRequestKeys();
    -     method public java.util.List<android.hardware.camera2.CaptureResult.Key<?>> getAvailableCaptureResultKeys();
    -     field public static final android.hardware.camera2.CameraCharacteristics.Key<int[]> COLOR_CORRECTION_AVAILABLE_ABERRATION_MODES;
    -@@ -13952,7 +13955,7 @@ package android.hardware.camera2 {
    -     field public static final android.hardware.camera2.CameraCharacteristics.Key<java.lang.Integer> TONEMAP_MAX_CURVE_POINTS;
    -   }
    - 
    --  public static final class CameraCharacteristics.Key {
    -+  public static final class CameraCharacteristics.Key<T> {
    -     method public final boolean equals(java.lang.Object);
    -     method public java.lang.String getName();
    -     method public final int hashCode();
    -@@ -14017,7 +14020,7 @@ package android.hardware.camera2 {
    -     method public void onTorchModeUnavailable(java.lang.String);
    -   }
    - 
    --  public abstract class CameraMetadata {
    -+  public abstract class CameraMetadata<TKey> {
    -     method public java.util.List<TKey> getKeys();
    -     field public static final int COLOR_CORRECTION_ABERRATION_MODE_FAST = 1; // 0x1
    -     field public static final int COLOR_CORRECTION_ABERRATION_MODE_HIGH_QUALITY = 2; // 0x2
    -@@ -14225,7 +14228,7 @@ package android.hardware.camera2 {
    - 
    -   public final class CaptureRequest extends android.hardware.camera2.CameraMetadata implements android.os.Parcelable {
    -     method public int describeContents();
    --    method public T get(android.hardware.camera2.CaptureRequest.Key<T>);
    -+    method public <T> T get(android.hardware.camera2.CaptureRequest.Key<T>);
    -     method public java.lang.Object getTag();
    -     method public boolean isReprocess();
    -     method public void writeToParcel(android.os.Parcel, int);
    -@@ -14288,20 +14291,20 @@ package android.hardware.camera2 {
    -   public static final class CaptureRequest.Builder {
    -     method public void addTarget(android.view.Surface);
    -     method public android.hardware.camera2.CaptureRequest build();
    --    method public T get(android.hardware.camera2.CaptureRequest.Key<T>);
    -+    method public <T> T get(android.hardware.camera2.CaptureRequest.Key<T>);
    -     method public void removeTarget(android.view.Surface);
    --    method public void set(android.hardware.camera2.CaptureRequest.Key<T>, T);
    -+    method public <T> void set(android.hardware.camera2.CaptureRequest.Key<T>, T);
    -     method public void setTag(java.lang.Object);
    -   }
    - 
    --  public static final class CaptureRequest.Key {
    -+  public static final class CaptureRequest.Key<T> {
    -     method public final boolean equals(java.lang.Object);
    -     method public java.lang.String getName();
    -     method public final int hashCode();
    -   }
    - 
    -   public class CaptureResult extends android.hardware.camera2.CameraMetadata {
    --    method public T get(android.hardware.camera2.CaptureResult.Key<T>);
    -+    method public <T> T get(android.hardware.camera2.CaptureResult.Key<T>);
    -     method public long getFrameNumber();
    -     method public android.hardware.camera2.CaptureRequest getRequest();
    -     method public int getSequenceId();
    -@@ -14382,7 +14385,7 @@ package android.hardware.camera2 {
    -     field public static final android.hardware.camera2.CaptureResult.Key<java.lang.Integer> TONEMAP_PRESET_CURVE;
    -   }
    - 
    --  public static final class CaptureResult.Key {
    -+  public static final class CaptureResult.Key<T> {
    -     method public final boolean equals(java.lang.Object);
    -     method public java.lang.String getName();
    -     method public final int hashCode();
    -@@ -14507,14 +14510,14 @@ package android.hardware.camera2.params {
    -     method public android.util.Size[] getInputSizes(int);
    -     method public final int[] getOutputFormats();
    -     method public long getOutputMinFrameDuration(int, android.util.Size);
    --    method public long getOutputMinFrameDuration(java.lang.Class<T>, android.util.Size);
    --    method public android.util.Size[] getOutputSizes(java.lang.Class<T>);
    -+    method public <T> long getOutputMinFrameDuration(java.lang.Class<T>, android.util.Size);
    -+    method public <T> android.util.Size[] getOutputSizes(java.lang.Class<T>);
    -     method public android.util.Size[] getOutputSizes(int);
    -     method public long getOutputStallDuration(int, android.util.Size);
    --    method public long getOutputStallDuration(java.lang.Class<T>, android.util.Size);
    -+    method public <T> long getOutputStallDuration(java.lang.Class<T>, android.util.Size);
    -     method public final int[] getValidOutputFormatsForInput(int);
    -     method public boolean isOutputSupportedFor(int);
    --    method public static boolean isOutputSupportedFor(java.lang.Class<T>);
    -+    method public static <T> boolean isOutputSupportedFor(java.lang.Class<T>);
    -     method public boolean isOutputSupportedFor(android.view.Surface);
    -   }
    - 
    -@@ -16215,7 +16218,7 @@ package android.icu.math {
    - 
    - package android.icu.text {
    - 
    --  public final class AlphabeticIndex implements java.lang.Iterable {
    -+  public final class AlphabeticIndex<V> implements java.lang.Iterable {
    -     ctor public AlphabeticIndex(android.icu.util.ULocale);
    -     ctor public AlphabeticIndex(java.util.Locale);
    -     ctor public AlphabeticIndex(android.icu.text.RuleBasedCollator);
    -@@ -16241,7 +16244,7 @@ package android.icu.text {
    -     method public android.icu.text.AlphabeticIndex<V> setUnderflowLabel(java.lang.String);
    -   }
    - 
    --  public static class AlphabeticIndex.Bucket implements java.lang.Iterable {
    -+  public static class AlphabeticIndex.Bucket<V> implements java.lang.Iterable {
    -     method public java.lang.String getLabel();
    -     method public android.icu.text.AlphabeticIndex.Bucket.LabelType getLabelType();
    -     method public java.util.Iterator<android.icu.text.AlphabeticIndex.Record<V>> iterator();
    -@@ -16257,14 +16260,14 @@ package android.icu.text {
    -     enum_constant public static final android.icu.text.AlphabeticIndex.Bucket.LabelType UNDERFLOW;
    -   }
    - 
    --  public static final class AlphabeticIndex.ImmutableIndex implements java.lang.Iterable {
    -+  public static final class AlphabeticIndex.ImmutableIndex<V> implements java.lang.Iterable {
    -     method public android.icu.text.AlphabeticIndex.Bucket<V> getBucket(int);
    -     method public int getBucketCount();
    -     method public int getBucketIndex(java.lang.CharSequence);
    -     method public java.util.Iterator<android.icu.text.AlphabeticIndex.Bucket<V>> iterator();
    -   }
    - 
    --  public static class AlphabeticIndex.Record {
    -+  public static class AlphabeticIndex.Record<V> {
    -     method public V getData();
    -     method public java.lang.CharSequence getName();
    -   }
    -@@ -17777,8 +17780,8 @@ package android.icu.text {
    -     method public final android.icu.text.UnicodeSet addAll(java.lang.CharSequence);
    -     method public android.icu.text.UnicodeSet addAll(android.icu.text.UnicodeSet);
    -     method public android.icu.text.UnicodeSet addAll(java.lang.Iterable<?>);
    --    method public android.icu.text.UnicodeSet addAll(T...);
    --    method public T addAllTo(T);
    -+    method public <T extends java.lang.CharSequence> android.icu.text.UnicodeSet addAll(T...);
    -+    method public <T extends java.util.Collection<java.lang.String>> T addAllTo(T);
    -     method public void addMatchSetTo(android.icu.text.UnicodeSet);
    -     method public android.icu.text.UnicodeSet applyIntPropertyValue(int, int);
    -     method public final android.icu.text.UnicodeSet applyPattern(java.lang.String);
    -@@ -17806,15 +17809,15 @@ package android.icu.text {
    -     method public final boolean contains(java.lang.CharSequence);
    -     method public boolean containsAll(android.icu.text.UnicodeSet);
    -     method public boolean containsAll(java.lang.String);
    --    method public boolean containsAll(java.lang.Iterable<T>);
    -+    method public <T extends java.lang.CharSequence> boolean containsAll(java.lang.Iterable<T>);
    -     method public boolean containsNone(int, int);
    -     method public boolean containsNone(android.icu.text.UnicodeSet);
    -     method public boolean containsNone(java.lang.CharSequence);
    --    method public boolean containsNone(java.lang.Iterable<T>);
    -+    method public <T extends java.lang.CharSequence> boolean containsNone(java.lang.Iterable<T>);
    -     method public final boolean containsSome(int, int);
    -     method public final boolean containsSome(android.icu.text.UnicodeSet);
    -     method public final boolean containsSome(java.lang.CharSequence);
    --    method public final boolean containsSome(java.lang.Iterable<T>);
    -+    method public final <T extends java.lang.CharSequence> boolean containsSome(java.lang.Iterable<T>);
    -     method public android.icu.text.UnicodeSet freeze();
    -     method public static android.icu.text.UnicodeSet from(java.lang.CharSequence);
    -     method public static android.icu.text.UnicodeSet fromAll(java.lang.CharSequence);
    -@@ -17832,14 +17835,14 @@ package android.icu.text {
    -     method public final android.icu.text.UnicodeSet remove(java.lang.CharSequence);
    -     method public final android.icu.text.UnicodeSet removeAll(java.lang.CharSequence);
    -     method public android.icu.text.UnicodeSet removeAll(android.icu.text.UnicodeSet);
    --    method public android.icu.text.UnicodeSet removeAll(java.lang.Iterable<T>);
    -+    method public <T extends java.lang.CharSequence> android.icu.text.UnicodeSet removeAll(java.lang.Iterable<T>);
    -     method public final android.icu.text.UnicodeSet removeAllStrings();
    -     method public android.icu.text.UnicodeSet retain(int, int);
    -     method public final android.icu.text.UnicodeSet retain(int);
    -     method public final android.icu.text.UnicodeSet retain(java.lang.CharSequence);
    -     method public final android.icu.text.UnicodeSet retainAll(java.lang.CharSequence);
    -     method public android.icu.text.UnicodeSet retainAll(android.icu.text.UnicodeSet);
    --    method public android.icu.text.UnicodeSet retainAll(java.lang.Iterable<T>);
    -+    method public <T extends java.lang.CharSequence> android.icu.text.UnicodeSet retainAll(java.lang.Iterable<T>);
    -     method public android.icu.text.UnicodeSet set(int, int);
    -     method public android.icu.text.UnicodeSet set(android.icu.text.UnicodeSet);
    -     method public int size();
    -@@ -18249,7 +18252,7 @@ package android.icu.util {
    -     method public long getToDate();
    -   }
    - 
    --  public abstract interface Freezable implements java.lang.Cloneable {
    -+  public abstract interface Freezable<T> implements java.lang.Cloneable {
    -     method public abstract T cloneAsThawed();
    -     method public abstract T freeze();
    -     method public abstract boolean isFrozen();
    -@@ -18531,7 +18534,7 @@ package android.icu.util {
    -     field public static final android.icu.util.TimeUnit YEAR;
    -   }
    - 
    --  public class Output {
    -+  public class Output<T> {
    -     ctor public Output();
    -     ctor public Output(T);
    -     field public T value;
    -@@ -28239,7 +28242,7 @@ package android.opengl {
    - 
    - package android.os {
    - 
    --  public abstract class AsyncTask {
    -+  public abstract class AsyncTask<Params, Progress, Result> {
    -     ctor public AsyncTask();
    -     method public final boolean cancel(boolean);
    -     method protected abstract Result doInBackground(Params...);
    -@@ -28466,16 +28469,16 @@ package android.os {
    -     method public float getFloat(java.lang.String, float);
    -     method public float[] getFloatArray(java.lang.String);
    -     method public java.util.ArrayList<java.lang.Integer> getIntegerArrayList(java.lang.String);
    --    method public T getParcelable(java.lang.String);
    -+    method public <T extends android.os.Parcelable> T getParcelable(java.lang.String);
    -     method public android.os.Parcelable[] getParcelableArray(java.lang.String);
    --    method public java.util.ArrayList<T> getParcelableArrayList(java.lang.String);
    -+    method public <T extends android.os.Parcelable> java.util.ArrayList<T> getParcelableArrayList(java.lang.String);
    -     method public java.io.Serializable getSerializable(java.lang.String);
    -     method public short getShort(java.lang.String);
    -     method public short getShort(java.lang.String, short);
    -     method public short[] getShortArray(java.lang.String);
    -     method public android.util.Size getSize(java.lang.String);
    -     method public android.util.SizeF getSizeF(java.lang.String);
    --    method public android.util.SparseArray<T> getSparseParcelableArray(java.lang.String);
    -+    method public <T extends android.os.Parcelable> android.util.SparseArray<T> getSparseParcelableArray(java.lang.String);
    -     method public java.util.ArrayList<java.lang.String> getStringArrayList(java.lang.String);
    -     method public boolean hasFileDescriptors();
    -     method public void putAll(android.os.Bundle);
    -@@ -28980,8 +28983,8 @@ package android.os {
    -     method public final long[] createLongArray();
    -     method public final java.lang.String[] createStringArray();
    -     method public final java.util.ArrayList<java.lang.String> createStringArrayList();
    --    method public final T[] createTypedArray(android.os.Parcelable.Creator<T>);
    --    method public final java.util.ArrayList<T> createTypedArrayList(android.os.Parcelable.Creator<T>);
    -+    method public final <T> T[] createTypedArray(android.os.Parcelable.Creator<T>);
    -+    method public final <T> java.util.ArrayList<T> createTypedArrayList(android.os.Parcelable.Creator<T>);
    -     method public final int dataAvail();
    -     method public final int dataCapacity();
    -     method public final int dataPosition();
    -@@ -29014,7 +29017,7 @@ package android.os {
    -     method public final long readLong();
    -     method public final void readLongArray(long[]);
    -     method public final void readMap(java.util.Map, java.lang.ClassLoader);
    --    method public final T readParcelable(java.lang.ClassLoader);
    -+    method public final <T extends android.os.Parcelable> T readParcelable(java.lang.ClassLoader);
    -     method public final android.os.Parcelable[] readParcelableArray(java.lang.ClassLoader);
    -     method public final android.os.PersistableBundle readPersistableBundle();
    -     method public final android.os.PersistableBundle readPersistableBundle(java.lang.ClassLoader);
    -@@ -29027,9 +29030,9 @@ package android.os {
    -     method public final void readStringArray(java.lang.String[]);
    -     method public final void readStringList(java.util.List<java.lang.String>);
    -     method public final android.os.IBinder readStrongBinder();
    --    method public final void readTypedArray(T[], android.os.Parcelable.Creator<T>);
    --    method public final void readTypedList(java.util.List<T>, android.os.Parcelable.Creator<T>);
    --    method public final T readTypedObject(android.os.Parcelable.Creator<T>);
    -+    method public final <T> void readTypedArray(T[], android.os.Parcelable.Creator<T>);
    -+    method public final <T> void readTypedList(java.util.List<T>, android.os.Parcelable.Creator<T>);
    -+    method public final <T> T readTypedObject(android.os.Parcelable.Creator<T>);
    -     method public final java.lang.Object readValue(java.lang.ClassLoader);
    -     method public final void recycle();
    -     method public final void setDataCapacity(int);
    -@@ -29060,7 +29063,7 @@ package android.os {
    -     method public final void writeMap(java.util.Map);
    -     method public final void writeNoException();
    -     method public final void writeParcelable(android.os.Parcelable, int);
    --    method public final void writeParcelableArray(T[], int);
    -+    method public final <T extends android.os.Parcelable> void writeParcelableArray(T[], int);
    -     method public final void writePersistableBundle(android.os.PersistableBundle);
    -     method public final void writeSerializable(java.io.Serializable);
    -     method public final void writeSize(android.util.Size);
    -@@ -29072,9 +29075,9 @@ package android.os {
    -     method public final void writeStringList(java.util.List<java.lang.String>);
    -     method public final void writeStrongBinder(android.os.IBinder);
    -     method public final void writeStrongInterface(android.os.IInterface);
    --    method public final void writeTypedArray(T[], int);
    --    method public final void writeTypedList(java.util.List<T>);
    --    method public final void writeTypedObject(T, int);
    -+    method public final <T extends android.os.Parcelable> void writeTypedArray(T[], int);
    -+    method public final <T extends android.os.Parcelable> void writeTypedList(java.util.List<T>);
    -+    method public final <T extends android.os.Parcelable> void writeTypedObject(T, int);
    -     method public final void writeValue(java.lang.Object);
    -     field public static final android.os.Parcelable.Creator<java.lang.String> STRING_CREATOR;
    -   }
    -@@ -29152,11 +29155,11 @@ package android.os {
    -     field public static final int PARCELABLE_WRITE_RETURN_VALUE = 1; // 0x1
    -   }
    - 
    --  public static abstract interface Parcelable.ClassLoaderCreator implements android.os.Parcelable.Creator {
    -+  public static abstract interface Parcelable.ClassLoaderCreator<T> implements android.os.Parcelable.Creator {
    -     method public abstract T createFromParcel(android.os.Parcel, java.lang.ClassLoader);
    -   }
    - 
    --  public static abstract interface Parcelable.Creator {
    -+  public static abstract interface Parcelable.Creator<T> {
    -     method public abstract T createFromParcel(android.os.Parcel);
    -     method public abstract T[] newArray(int);
    -   }
    -@@ -29271,7 +29274,7 @@ package android.os {
    -     method public abstract void onProgress(int);
    -   }
    - 
    --  public class RemoteCallbackList {
    -+  public class RemoteCallbackList<E extends android.os.IInterface> {
    -     ctor public RemoteCallbackList();
    -     method public int beginBroadcast();
    -     method public void finishBroadcast();
    -@@ -32557,7 +32560,7 @@ package android.provider {
    -     field public static final java.lang.String RADIO_CELL = "cell";
    -     field public static final java.lang.String RADIO_NFC = "nfc";
    -     field public static final java.lang.String RADIO_WIFI = "wifi";
    --    field public static final java.lang.String SHOW_PROCESSES = "show_processes";
    -+    field public static final deprecated java.lang.String SHOW_PROCESSES = "show_processes";
    -     field public static final java.lang.String STAY_ON_WHILE_PLUGGED_IN = "stay_on_while_plugged_in";
    -     field public static final java.lang.String TRANSITION_ANIMATION_SCALE = "transition_animation_scale";
    -     field public static final java.lang.String USB_MASS_STORAGE_ENABLED = "usb_mass_storage_enabled";
    -@@ -34599,7 +34602,7 @@ package android.service.carrier {
    -     field public static final java.lang.String SERVICE_INTERFACE = "android.service.carrier.CarrierMessagingService";
    -   }
    - 
    --  public static abstract interface CarrierMessagingService.ResultCallback {
    -+  public static abstract interface CarrierMessagingService.ResultCallback<T> {
    -     method public abstract void onReceiveResult(T) throws android.os.RemoteException;
    -   }
    - 
    -@@ -34750,7 +34753,7 @@ package android.service.media {
    -     field public static final java.lang.String EXTRA_SUGGESTED = "android.service.media.extra.SUGGESTED";
    -   }
    - 
    --  public class MediaBrowserService.Result {
    -+  public class MediaBrowserService.Result<T> {
    -     method public void detach();
    -     method public void sendResult(T);
    -   }
    -@@ -37663,14 +37666,14 @@ package android.telephony.gsm {
    - 
    - package android.test {
    - 
    --  public abstract deprecated class ActivityInstrumentationTestCase extends android.test.ActivityTestCase {
    -+  public abstract deprecated class ActivityInstrumentationTestCase<T extends android.app.Activity> extends android.test.ActivityTestCase {
    -     ctor public ActivityInstrumentationTestCase(java.lang.String, java.lang.Class<T>);
    -     ctor public ActivityInstrumentationTestCase(java.lang.String, java.lang.Class<T>, boolean);
    -     method public T getActivity();
    -     method public void testActivityTestCaseSetUpProperly() throws java.lang.Exception;
    -   }
    - 
    --  public abstract deprecated class ActivityInstrumentationTestCase2 extends android.test.ActivityTestCase {
    -+  public abstract deprecated class ActivityInstrumentationTestCase2<T extends android.app.Activity> extends android.test.ActivityTestCase {
    -     ctor public deprecated ActivityInstrumentationTestCase2(java.lang.String, java.lang.Class<T>);
    -     ctor public ActivityInstrumentationTestCase2(java.lang.Class<T>);
    -     method public T getActivity();
    -@@ -37685,7 +37688,7 @@ package android.test {
    -     method protected void setActivity(android.app.Activity);
    -   }
    - 
    --  public abstract deprecated class ActivityUnitTestCase extends android.test.ActivityTestCase {
    -+  public abstract deprecated class ActivityUnitTestCase<T extends android.app.Activity> extends android.test.ActivityTestCase {
    -     ctor public ActivityUnitTestCase(java.lang.Class<T>);
    -     method public T getActivity();
    -     method public int getFinishedActivityRequest();
    -@@ -37731,7 +37734,7 @@ package android.test {
    -     method public void testStarted(java.lang.String);
    -   }
    - 
    --  public abstract deprecated class ApplicationTestCase extends android.test.AndroidTestCase {
    -+  public abstract deprecated class ApplicationTestCase<T extends android.app.Application> extends android.test.AndroidTestCase {
    -     ctor public ApplicationTestCase(java.lang.Class<T>);
    -     method protected final void createApplication();
    -     method public T getApplication();
    -@@ -37757,8 +37760,8 @@ package android.test {
    -     method public android.app.Instrumentation getInstrumentation();
    -     method public deprecated void injectInsrumentation(android.app.Instrumentation);
    -     method public void injectInstrumentation(android.app.Instrumentation);
    --    method public final T launchActivity(java.lang.String, java.lang.Class<T>, android.os.Bundle);
    --    method public final T launchActivityWithIntent(java.lang.String, java.lang.Class<T>, android.content.Intent);
    -+    method public final <T extends android.app.Activity> T launchActivity(java.lang.String, java.lang.Class<T>, android.os.Bundle);
    -+    method public final <T extends android.app.Activity> T launchActivityWithIntent(java.lang.String, java.lang.Class<T>, android.content.Intent);
    -     method public void runTestOnUiThread(java.lang.Runnable) throws java.lang.Throwable;
    -     method public void sendKeys(java.lang.String);
    -     method public void sendKeys(int...);
    -@@ -37798,7 +37801,7 @@ package android.test {
    - 
    -   public class LoaderTestCase extends android.test.AndroidTestCase {
    -     ctor public LoaderTestCase();
    --    method public T getLoaderResultSynchronously(android.content.Loader<T>);
    -+    method public <T> T getLoaderResultSynchronously(android.content.Loader<T>);
    -   }
    - 
    -   public final deprecated class MoreAsserts {
    -@@ -37853,20 +37856,20 @@ package android.test {
    -     method public abstract void startTiming(boolean);
    -   }
    - 
    --  public abstract deprecated class ProviderTestCase extends android.test.InstrumentationTestCase {
    -+  public abstract deprecated class ProviderTestCase<T extends android.content.ContentProvider> extends android.test.InstrumentationTestCase {
    -     ctor public ProviderTestCase(java.lang.Class<T>, java.lang.String);
    -     method public android.test.mock.MockContentResolver getMockContentResolver();
    -     method public android.test.IsolatedContext getMockContext();
    -     method public T getProvider();
    --    method public static android.content.ContentResolver newResolverWithContentProviderFromSql(android.content.Context, java.lang.Class<T>, java.lang.String, java.lang.String, int, java.lang.String) throws java.lang.IllegalAccessException, java.lang.InstantiationException;
    -+    method public static <T extends android.content.ContentProvider> android.content.ContentResolver newResolverWithContentProviderFromSql(android.content.Context, java.lang.Class<T>, java.lang.String, java.lang.String, int, java.lang.String) throws java.lang.IllegalAccessException, java.lang.InstantiationException;
    -   }
    - 
    --  public abstract class ProviderTestCase2 extends android.test.AndroidTestCase {
    -+  public abstract class ProviderTestCase2<T extends android.content.ContentProvider> extends android.test.AndroidTestCase {
    -     ctor public ProviderTestCase2(java.lang.Class<T>, java.lang.String);
    -     method public android.test.mock.MockContentResolver getMockContentResolver();
    -     method public android.test.IsolatedContext getMockContext();
    -     method public T getProvider();
    --    method public static android.content.ContentResolver newResolverWithContentProviderFromSql(android.content.Context, java.lang.String, java.lang.Class<T>, java.lang.String, java.lang.String, int, java.lang.String) throws java.lang.IllegalAccessException, java.lang.InstantiationException;
    -+    method public static <T extends android.content.ContentProvider> android.content.ContentResolver newResolverWithContentProviderFromSql(android.content.Context, java.lang.String, java.lang.Class<T>, java.lang.String, java.lang.String, int, java.lang.String) throws java.lang.IllegalAccessException, java.lang.InstantiationException;
    -   }
    - 
    -   public deprecated class RenamingDelegatingContext extends android.content.ContextWrapper {
    -@@ -37874,11 +37877,11 @@ package android.test {
    -     ctor public RenamingDelegatingContext(android.content.Context, android.content.Context, java.lang.String);
    -     method public java.lang.String getDatabasePrefix();
    -     method public void makeExistingFilesAndDbsAccessible();
    --    method public static T providerWithRenamedContext(java.lang.Class<T>, android.content.Context, java.lang.String) throws java.lang.IllegalAccessException, java.lang.InstantiationException;
    --    method public static T providerWithRenamedContext(java.lang.Class<T>, android.content.Context, java.lang.String, boolean) throws java.lang.IllegalAccessException, java.lang.InstantiationException;
    -+    method public static <T extends android.content.ContentProvider> T providerWithRenamedContext(java.lang.Class<T>, android.content.Context, java.lang.String) throws java.lang.IllegalAccessException, java.lang.InstantiationException;
    -+    method public static <T extends android.content.ContentProvider> T providerWithRenamedContext(java.lang.Class<T>, android.content.Context, java.lang.String, boolean) throws java.lang.IllegalAccessException, java.lang.InstantiationException;
    -   }
    - 
    --  public abstract deprecated class ServiceTestCase extends android.test.AndroidTestCase {
    -+  public abstract deprecated class ServiceTestCase<T extends android.app.Service> extends android.test.AndroidTestCase {
    -     ctor public ServiceTestCase(java.lang.Class<T>);
    -     method protected android.os.IBinder bindService(android.content.Intent);
    -     method public android.app.Application getApplication();
    -@@ -37891,7 +37894,7 @@ package android.test {
    -     method public void testServiceTestCaseSetUpProperly() throws java.lang.Exception;
    -   }
    - 
    --  public abstract deprecated class SingleLaunchActivityTestCase extends android.test.InstrumentationTestCase {
    -+  public abstract deprecated class SingleLaunchActivityTestCase<T extends android.app.Activity> extends android.test.InstrumentationTestCase {
    -     ctor public SingleLaunchActivityTestCase(java.lang.String, java.lang.Class<T>);
    -     method public T getActivity();
    -     method public void testActivityTestCaseSetUpProperly() throws java.lang.Exception;
    -@@ -38248,7 +38251,7 @@ package android.test.suitebuilder {
    -     ctor public TestMethod(java.lang.String, java.lang.Class<? extends junit.framework.TestCase>);
    -     ctor public TestMethod(junit.framework.TestCase);
    -     method public junit.framework.TestCase createTest() throws java.lang.IllegalAccessException, java.lang.InstantiationException, java.lang.reflect.InvocationTargetException;
    --    method public T getAnnotation(java.lang.Class<T>);
    -+    method public <T extends java.lang.annotation.Annotation> T getAnnotation(java.lang.Class<T>);
    -     method public java.lang.Class<? extends junit.framework.TestCase> getEnclosingClass();
    -     method public java.lang.String getEnclosingClassname();
    -     method public java.lang.String getName();
    -@@ -38691,7 +38694,7 @@ package android.text {
    -     method public int getSpanEnd(java.lang.Object);
    -     method public int getSpanFlags(java.lang.Object);
    -     method public int getSpanStart(java.lang.Object);
    --    method public T[] getSpans(int, int, java.lang.Class<T>);
    -+    method public <T> T[] getSpans(int, int, java.lang.Class<T>);
    -     method public deprecated int getTextRunCursor(int, int, int, int, int, android.graphics.Paint);
    -     method public int getTextWatcherDepth();
    -     method public android.text.SpannableStringBuilder insert(int, java.lang.CharSequence, int, int);
    -@@ -38713,7 +38716,7 @@ package android.text {
    -     method public int getSpanEnd(java.lang.Object);
    -     method public int getSpanFlags(java.lang.Object);
    -     method public int getSpanStart(java.lang.Object);
    --    method public T[] getSpans(int, int, java.lang.Class<T>);
    -+    method public <T> T[] getSpans(int, int, java.lang.Class<T>);
    -     method public final int length();
    -     method public int nextSpanTransition(int, int, java.lang.Class);
    -     method public final java.lang.String toString();
    -@@ -38723,7 +38726,7 @@ package android.text {
    -     method public abstract int getSpanEnd(java.lang.Object);
    -     method public abstract int getSpanFlags(java.lang.Object);
    -     method public abstract int getSpanStart(java.lang.Object);
    --    method public abstract T[] getSpans(int, int, java.lang.Class<T>);
    -+    method public abstract <T> T[] getSpans(int, int, java.lang.Class<T>);
    -     method public abstract int nextSpanTransition(int, int, java.lang.Class);
    -     field public static final int SPAN_COMPOSING = 256; // 0x100
    -     field public static final int SPAN_EXCLUSIVE_EXCLUSIVE = 33; // 0x21
    -@@ -39700,7 +39703,7 @@ package android.text.style {
    -     field public static final int WEEKDAY_WEDNESDAY = 4; // 0x4
    -   }
    - 
    --  public static class TtsSpan.Builder {
    -+  public static class TtsSpan.Builder<C extends android.text.style.TtsSpan.Builder<?>> {
    -     ctor public TtsSpan.Builder(java.lang.String);
    -     method public android.text.style.TtsSpan build();
    -     method public C setIntArgument(java.lang.String, int);
    -@@ -39796,7 +39799,7 @@ package android.text.style {
    -     method public android.text.style.TtsSpan.OrdinalBuilder setNumber(java.lang.String);
    -   }
    - 
    --  public static class TtsSpan.SemioticClassBuilder extends android.text.style.TtsSpan.Builder {
    -+  public static class TtsSpan.SemioticClassBuilder<C extends android.text.style.TtsSpan.SemioticClassBuilder<?>> extends android.text.style.TtsSpan.Builder {
    -     ctor public TtsSpan.SemioticClassBuilder(java.lang.String);
    -     method public C setAnimacy(java.lang.String);
    -     method public C setCase(java.lang.String);
    -@@ -40203,7 +40206,7 @@ package android.util {
    -     ctor public AndroidRuntimeException(java.lang.Exception);
    -   }
    - 
    --  public final class ArrayMap implements java.util.Map {
    -+  public final class ArrayMap<K, V> implements java.util.Map {
    -     ctor public ArrayMap();
    -     ctor public ArrayMap(int);
    -     ctor public ArrayMap(android.util.ArrayMap<K, V>);
    -@@ -40231,7 +40234,7 @@ package android.util {
    -     method public java.util.Collection<V> values();
    -   }
    - 
    --  public final class ArraySet implements java.util.Collection java.util.Set {
    -+  public final class ArraySet<E> implements java.util.Collection java.util.Set {
    -     ctor public ArraySet();
    -     ctor public ArraySet(int);
    -     ctor public ArraySet(android.util.ArraySet<E>);
    -@@ -40252,7 +40255,7 @@ package android.util {
    -     method public boolean retainAll(java.util.Collection<?>);
    -     method public int size();
    -     method public java.lang.Object[] toArray();
    --    method public T[] toArray(T[]);
    -+    method public <T> T[] toArray(T[]);
    -     method public E valueAt(int);
    -   }
    - 
    -@@ -40397,13 +40400,13 @@ package android.util {
    -   public deprecated class FloatMath {
    -   }
    - 
    --  public abstract class FloatProperty extends android.util.Property {
    -+  public abstract class FloatProperty<T> extends android.util.Property {
    -     ctor public FloatProperty(java.lang.String);
    -     method public final void set(T, java.lang.Float);
    -     method public abstract void setValue(T, float);
    -   }
    - 
    --  public abstract class IntProperty extends android.util.Property {
    -+  public abstract class IntProperty<T> extends android.util.Property {
    -     ctor public IntProperty(java.lang.String);
    -     method public final void set(T, java.lang.Integer);
    -     method public abstract void setValue(T, int);
    -@@ -40503,7 +40506,7 @@ package android.util {
    -     method public void println(java.lang.String);
    -   }
    - 
    --  public class LongSparseArray implements java.lang.Cloneable {
    -+  public class LongSparseArray<E> implements java.lang.Cloneable {
    -     ctor public LongSparseArray();
    -     ctor public LongSparseArray(int);
    -     method public void append(long, E);
    -@@ -40523,7 +40526,7 @@ package android.util {
    -     method public E valueAt(int);
    -   }
    - 
    --  public class LruCache {
    -+  public class LruCache<K, V> {
    -     ctor public LruCache(int);
    -     method protected V create(K);
    -     method public final synchronized int createCount();
    -@@ -40611,9 +40614,9 @@ package android.util {
    -     ctor public NoSuchPropertyException(java.lang.String);
    -   }
    - 
    --  public class Pair {
    -+  public class Pair<F, S> {
    -     ctor public Pair(F, S);
    --    method public static android.util.Pair<A, B> create(A, B);
    -+    method public static <A, B> android.util.Pair<A, B> create(A, B);
    -     field public final F first;
    -     field public final S second;
    -   }
    -@@ -40646,22 +40649,22 @@ package android.util {
    -     method public abstract void println(java.lang.String);
    -   }
    - 
    --  public abstract class Property {
    -+  public abstract class Property<T, V> {
    -     ctor public Property(java.lang.Class<V>, java.lang.String);
    -     method public abstract V get(T);
    -     method public java.lang.String getName();
    -     method public java.lang.Class<V> getType();
    -     method public boolean isReadOnly();
    --    method public static android.util.Property<T, V> of(java.lang.Class<T>, java.lang.Class<V>, java.lang.String);
    -+    method public static <T, V> android.util.Property<T, V> of(java.lang.Class<T>, java.lang.Class<V>, java.lang.String);
    -     method public void set(T, V);
    -   }
    - 
    --  public final class Range {
    -+  public final class Range<T extends java.lang.Comparable<? super T>> {
    -     ctor public Range(T, T);
    -     method public T clamp(T);
    -     method public boolean contains(T);
    -     method public boolean contains(android.util.Range<T>);
    --    method public static android.util.Range<T> create(T, T);
    -+    method public static <T extends java.lang.Comparable<? super T>> android.util.Range<T> create(T, T);
    -     method public android.util.Range<T> extend(android.util.Range<T>);
    -     method public android.util.Range<T> extend(T, T);
    -     method public android.util.Range<T> extend(T);
    -@@ -40705,7 +40708,7 @@ package android.util {
    -     method public static android.util.SizeF parseSizeF(java.lang.String) throws java.lang.NumberFormatException;
    -   }
    - 
    --  public class SparseArray implements java.lang.Cloneable {
    -+  public class SparseArray<E> implements java.lang.Cloneable {
    -     ctor public SparseArray();
    -     ctor public SparseArray(int);
    -     method public void append(int, E);
    -@@ -45434,7 +45437,7 @@ package android.webkit {
    -     method public static java.lang.String stripAnchor(java.lang.String);
    -   }
    - 
    --  public abstract interface ValueCallback {
    -+  public abstract interface ValueCallback<T> {
    -     method public abstract void onReceiveValue(T);
    -   }
    - 
    -@@ -46168,7 +46171,7 @@ package android.widget {
    -     field public static final int NO_SELECTION = -2147483648; // 0x80000000
    -   }
    - 
    --  public abstract class AdapterView extends android.view.ViewGroup {
    -+  public abstract class AdapterView<T extends android.widget.Adapter> extends android.view.ViewGroup {
    -     ctor public AdapterView(android.content.Context);
    -     ctor public AdapterView(android.content.Context, android.util.AttributeSet);
    -     ctor public AdapterView(android.content.Context, android.util.AttributeSet, int);
    -@@ -46291,7 +46294,7 @@ package android.widget {
    -     ctor public AnalogClock(android.content.Context, android.util.AttributeSet, int, int);
    -   }
    - 
    --  public class ArrayAdapter extends android.widget.BaseAdapter implements android.widget.Filterable android.widget.ThemedSpinnerAdapter {
    -+  public class ArrayAdapter<T> extends android.widget.BaseAdapter implements android.widget.Filterable android.widget.ThemedSpinnerAdapter {
    -     ctor public ArrayAdapter(android.content.Context, int);
    -     ctor public ArrayAdapter(android.content.Context, int, int);
    -     ctor public ArrayAdapter(android.content.Context, int, T[]);
    -@@ -46352,7 +46355,7 @@ package android.widget {
    -     method protected void performFiltering(java.lang.CharSequence, int);
    -     method public void performValidation();
    -     method protected void replaceText(java.lang.CharSequence);
    --    method public void setAdapter(T);
    -+    method public <T extends android.widget.ListAdapter & android.widget.Filterable> void setAdapter(T);
    -     method public void setCompletionHint(java.lang.CharSequence);
    -     method public void setDropDownAnchor(int);
    -     method public void setDropDownBackgroundDrawable(android.graphics.drawable.Drawable);
    -@@ -46603,6 +46606,7 @@ package android.widget {
    -     method public int getFirstDayOfWeek();
    -     method public long getMaxDate();
    -     method public long getMinDate();
    -+    method public int getMode();
    -     method public int getMonth();
    -     method public deprecated boolean getSpinnersShown();
    -     method public int getYear();
    -@@ -46613,6 +46617,8 @@ package android.widget {
    -     method public void setMinDate(long);
    -     method public deprecated void setSpinnersShown(boolean);
    -     method public void updateDate(int, int, int);
    -+    field public static final int MODE_CALENDAR = 2; // 0x2
    -+    field public static final int MODE_SPINNER = 1; // 0x1
    -   }
    - 
    -   public static abstract interface DatePicker.OnDateChangedListener {
    -@@ -48377,6 +48383,7 @@ package android.widget {
    -     method public deprecated java.lang.Integer getCurrentMinute();
    -     method public int getHour();
    -     method public int getMinute();
    -+    method public int getMode();
    -     method public boolean is24HourView();
    -     method public deprecated void setCurrentHour(java.lang.Integer);
    -     method public deprecated void setCurrentMinute(java.lang.Integer);
    -@@ -48384,6 +48391,8 @@ package android.widget {
    -     method public void setIs24HourView(java.lang.Boolean);
    -     method public void setMinute(int);
    -     method public void setOnTimeChangedListener(android.widget.TimePicker.OnTimeChangedListener);
    -+    field public static final int MODE_CLOCK = 2; // 0x2
    -+    field public static final int MODE_SPINNER = 1; // 0x1
    -   }
    - 
    -   public static abstract interface TimePicker.OnTimeChangedListener {
    -@@ -48638,7 +48647,7 @@ package android.widget {
    - 
    - package com.android.internal.util {
    - 
    --  public abstract interface Predicate {
    -+  public abstract interface Predicate<T> {
    -     method public abstract boolean apply(T);
    -   }
    - 
    -@@ -50685,13 +50694,13 @@ package java.lang {
    -     enum_constant public static final java.lang.Character.UnicodeScript YI;
    -   }
    - 
    --  public final class Class implements java.lang.reflect.AnnotatedElement java.lang.reflect.GenericDeclaration java.io.Serializable java.lang.reflect.Type {
    --    method public java.lang.Class<? extends U> asSubclass(java.lang.Class<U>);
    -+  public final class Class<T> implements java.lang.reflect.AnnotatedElement java.lang.reflect.GenericDeclaration java.io.Serializable java.lang.reflect.Type {
    -+    method public <U> java.lang.Class<? extends U> asSubclass(java.lang.Class<U>);
    -     method public T cast(java.lang.Object);
    -     method public boolean desiredAssertionStatus();
    -     method public static java.lang.Class<?> forName(java.lang.String) throws java.lang.ClassNotFoundException;
    -     method public static java.lang.Class<?> forName(java.lang.String, boolean, java.lang.ClassLoader) throws java.lang.ClassNotFoundException;
    --    method public A getAnnotation(java.lang.Class<A>);
    -+    method public <A extends java.lang.annotation.Annotation> A getAnnotation(java.lang.Class<A>);
    -     method public java.lang.annotation.Annotation[] getAnnotations();
    -     method public java.lang.String getCanonicalName();
    -     method public java.lang.ClassLoader getClassLoader();
    -@@ -50808,7 +50817,7 @@ package java.lang {
    -   public abstract interface Cloneable {
    -   }
    - 
    --  public abstract interface Comparable {
    -+  public abstract interface Comparable<T> {
    -     method public abstract int compareTo(T);
    -   }
    - 
    -@@ -50862,7 +50871,7 @@ package java.lang {
    -     field public static final java.lang.Class<java.lang.Double> TYPE;
    -   }
    - 
    --  public abstract class Enum implements java.lang.Comparable java.io.Serializable {
    -+  public abstract class Enum<E extends java.lang.Enum<E>> implements java.lang.Comparable java.io.Serializable {
    -     ctor protected Enum(java.lang.String, int);
    -     method protected final java.lang.Object clone() throws java.lang.CloneNotSupportedException;
    -     method public final int compareTo(E);
    -@@ -50872,7 +50881,7 @@ package java.lang {
    -     method public final int hashCode();
    -     method public final java.lang.String name();
    -     method public final int ordinal();
    --    method public static T valueOf(java.lang.Class<T>, java.lang.String);
    -+    method public static <T extends java.lang.Enum<T>> T valueOf(java.lang.Class<T>, java.lang.String);
    -   }
    - 
    -   public class EnumConstantNotPresentException extends java.lang.RuntimeException {
    -@@ -50991,7 +51000,7 @@ package java.lang {
    -     ctor public IndexOutOfBoundsException(java.lang.String);
    -   }
    - 
    --  public class InheritableThreadLocal extends java.lang.ThreadLocal {
    -+  public class InheritableThreadLocal<T> extends java.lang.ThreadLocal {
    -     ctor public InheritableThreadLocal();
    -     method protected T childValue(T);
    -   }
    -@@ -51062,7 +51071,7 @@ package java.lang {
    -     ctor public InterruptedException(java.lang.String);
    -   }
    - 
    --  public abstract interface Iterable {
    -+  public abstract interface Iterable<T> {
    -     method public default void forEach(java.util.function.Consumer<? super T>);
    -     method public abstract java.util.Iterator<T> iterator();
    -     method public default java.util.Spliterator<T> spliterator();
    -@@ -51270,12 +51279,12 @@ package java.lang {
    -   }
    - 
    -   public class Package implements java.lang.reflect.AnnotatedElement {
    --    method public A getAnnotation(java.lang.Class<A>);
    -+    method public <A extends java.lang.annotation.Annotation> A getAnnotation(java.lang.Class<A>);
    -     method public java.lang.annotation.Annotation[] getAnnotations();
    --    method public A[] getAnnotationsByType(java.lang.Class<A>);
    --    method public A getDeclaredAnnotation(java.lang.Class<A>);
    -+    method public <A extends java.lang.annotation.Annotation> A[] getAnnotationsByType(java.lang.Class<A>);
    -+    method public <A extends java.lang.annotation.Annotation> A getDeclaredAnnotation(java.lang.Class<A>);
    -     method public java.lang.annotation.Annotation[] getDeclaredAnnotations();
    --    method public A[] getDeclaredAnnotationsByType(java.lang.Class<A>);
    -+    method public <A extends java.lang.annotation.Annotation> A[] getDeclaredAnnotationsByType(java.lang.Class<A>);
    -     method public java.lang.String getImplementationTitle();
    -     method public java.lang.String getImplementationVendor();
    -     method public java.lang.String getImplementationVersion();
    -@@ -51835,7 +51844,7 @@ package java.lang {
    -     method public void uncaughtException(java.lang.Thread, java.lang.Throwable);
    -   }
    - 
    --  public class ThreadLocal {
    -+  public class ThreadLocal<T> {
    -     ctor public ThreadLocal();
    -     method public T get();
    -     method protected T initialValue();
    -@@ -51975,30 +51984,30 @@ package java.lang.annotation {
    - 
    - package java.lang.ref {
    - 
    --  public class PhantomReference extends java.lang.ref.Reference {
    -+  public class PhantomReference<T> extends java.lang.ref.Reference {
    -     ctor public PhantomReference(T, java.lang.ref.ReferenceQueue<? super T>);
    -   }
    - 
    --  public abstract class Reference {
    -+  public abstract class Reference<T> {
    -     method public void clear();
    -     method public boolean enqueue();
    -     method public T get();
    -     method public boolean isEnqueued();
    -   }
    - 
    --  public class ReferenceQueue {
    -+  public class ReferenceQueue<T> {
    -     ctor public ReferenceQueue();
    -     method public java.lang.ref.Reference<? extends T> poll();
    -     method public java.lang.ref.Reference<? extends T> remove(long) throws java.lang.IllegalArgumentException, java.lang.InterruptedException;
    -     method public java.lang.ref.Reference<? extends T> remove() throws java.lang.InterruptedException;
    -   }
    - 
    --  public class SoftReference extends java.lang.ref.Reference {
    -+  public class SoftReference<T> extends java.lang.ref.Reference {
    -     ctor public SoftReference(T);
    -     ctor public SoftReference(T, java.lang.ref.ReferenceQueue<? super T>);
    -   }
    - 
    --  public class WeakReference extends java.lang.ref.Reference {
    -+  public class WeakReference<T> extends java.lang.ref.Reference {
    -     ctor public WeakReference(T);
    -     ctor public WeakReference(T, java.lang.ref.ReferenceQueue<? super T>);
    -   }
    -@@ -52009,7 +52018,7 @@ package java.lang.reflect {
    - 
    -   public class AccessibleObject implements java.lang.reflect.AnnotatedElement {
    -     ctor protected AccessibleObject();
    --    method public T getAnnotation(java.lang.Class<T>);
    -+    method public <T extends java.lang.annotation.Annotation> T getAnnotation(java.lang.Class<T>);
    -     method public java.lang.annotation.Annotation[] getAnnotations();
    -     method public java.lang.annotation.Annotation[] getDeclaredAnnotations();
    -     method public boolean isAccessible();
    -@@ -52018,12 +52027,12 @@ package java.lang.reflect {
    -   }
    - 
    -   public abstract interface AnnotatedElement {
    --    method public abstract T getAnnotation(java.lang.Class<T>);
    -+    method public abstract <T extends java.lang.annotation.Annotation> T getAnnotation(java.lang.Class<T>);
    -     method public abstract java.lang.annotation.Annotation[] getAnnotations();
    --    method public default T[] getAnnotationsByType(java.lang.Class<T>);
    --    method public default java.lang.annotation.Annotation getDeclaredAnnotation(java.lang.Class<T>);
    -+    method public default <T extends java.lang.annotation.Annotation> T[] getAnnotationsByType(java.lang.Class<T>);
    -+    method public default <T extends java.lang.annotation.Annotation> java.lang.annotation.Annotation getDeclaredAnnotation(java.lang.Class<T>);
    -     method public abstract java.lang.annotation.Annotation[] getDeclaredAnnotations();
    --    method public default T[] getDeclaredAnnotationsByType(java.lang.Class<T>);
    -+    method public default <T extends java.lang.annotation.Annotation> T[] getDeclaredAnnotationsByType(java.lang.Class<T>);
    -     method public default boolean isAnnotationPresent(java.lang.Class<? extends java.lang.annotation.Annotation>);
    -   }
    - 
    -@@ -52051,8 +52060,8 @@ package java.lang.reflect {
    -     method public static void setShort(java.lang.Object, int, short) throws java.lang.ArrayIndexOutOfBoundsException, java.lang.IllegalArgumentException;
    -   }
    - 
    --  public final class Constructor extends java.lang.reflect.AccessibleObject implements java.lang.reflect.GenericDeclaration java.lang.reflect.Member {
    --    method public A getAnnotation(java.lang.Class<A>);
    -+  public final class Constructor<T> extends java.lang.reflect.AccessibleObject implements java.lang.reflect.GenericDeclaration java.lang.reflect.Member {
    -+    method public <A extends java.lang.annotation.Annotation> A getAnnotation(java.lang.Class<A>);
    -     method public java.lang.Class<T> getDeclaringClass();
    -     method public java.lang.Class<?>[] getExceptionTypes();
    -     method public java.lang.reflect.Type[] getGenericExceptionTypes();
    -@@ -52071,7 +52080,7 @@ package java.lang.reflect {
    - 
    -   public final class Field extends java.lang.reflect.AccessibleObject implements java.lang.reflect.Member {
    -     method public java.lang.Object get(java.lang.Object) throws java.lang.IllegalAccessException, java.lang.IllegalArgumentException;
    --    method public A getAnnotation(java.lang.Class<A>);
    -+    method public <A extends java.lang.annotation.Annotation> A getAnnotation(java.lang.Class<A>);
    -     method public boolean getBoolean(java.lang.Object) throws java.lang.IllegalAccessException, java.lang.IllegalArgumentException;
    -     method public byte getByte(java.lang.Object) throws java.lang.IllegalAccessException, java.lang.IllegalArgumentException;
    -     method public char getChar(java.lang.Object) throws java.lang.IllegalAccessException, java.lang.IllegalArgumentException;
    -@@ -52137,7 +52146,7 @@ package java.lang.reflect {
    -   }
    - 
    -   public final class Method extends java.lang.reflect.AccessibleObject implements java.lang.reflect.GenericDeclaration java.lang.reflect.Member {
    --    method public A getAnnotation(java.lang.Class<A>);
    -+    method public <A extends java.lang.annotation.Annotation> A getAnnotation(java.lang.Class<A>);
    -     method public java.lang.Class<?> getDeclaringClass();
    -     method public java.lang.Object getDefaultValue();
    -     method public java.lang.Class<?>[] getExceptionTypes();
    -@@ -52215,7 +52224,7 @@ package java.lang.reflect {
    -   public abstract interface Type {
    -   }
    - 
    --  public abstract interface TypeVariable implements java.lang.reflect.Type {
    -+  public abstract interface TypeVariable<D extends java.lang.reflect.GenericDeclaration> implements java.lang.reflect.Type {
    -     method public abstract java.lang.reflect.Type[] getBounds();
    -     method public abstract D getGenericDeclaration();
    -     method public abstract java.lang.String getName();
    -@@ -53004,7 +53013,7 @@ package java.net {
    -     method public abstract java.net.SocketImpl createSocketImpl();
    -   }
    - 
    --  public abstract interface SocketOption {
    -+  public abstract interface SocketOption<T> {
    -     method public abstract java.lang.String name();
    -     method public abstract java.lang.Class<T> type();
    -   }
    -@@ -53588,7 +53597,7 @@ package java.nio.channels {
    -     method public final long read(java.nio.ByteBuffer[]) throws java.io.IOException;
    -     method public abstract java.net.SocketAddress receive(java.nio.ByteBuffer) throws java.io.IOException;
    -     method public abstract int send(java.nio.ByteBuffer, java.net.SocketAddress) throws java.io.IOException;
    --    method public abstract java.nio.channels.DatagramChannel setOption(java.net.SocketOption<T>, T) throws java.io.IOException;
    -+    method public abstract <T> java.nio.channels.DatagramChannel setOption(java.net.SocketOption<T>, T) throws java.io.IOException;
    -     method public abstract java.net.DatagramSocket socket();
    -     method public final int validOps();
    -     method public abstract int write(java.nio.ByteBuffer) throws java.io.IOException;
    -@@ -53664,8 +53673,8 @@ package java.nio.channels {
    -   public abstract interface NetworkChannel implements java.nio.channels.Channel {
    -     method public abstract java.nio.channels.NetworkChannel bind(java.net.SocketAddress) throws java.io.IOException;
    -     method public abstract java.net.SocketAddress getLocalAddress() throws java.io.IOException;
    --    method public abstract T getOption(java.net.SocketOption<T>) throws java.io.IOException;
    --    method public abstract java.nio.channels.NetworkChannel setOption(java.net.SocketOption<T>, T) throws java.io.IOException;
    -+    method public abstract <T> T getOption(java.net.SocketOption<T>) throws java.io.IOException;
    -+    method public abstract <T> java.nio.channels.NetworkChannel setOption(java.net.SocketOption<T>, T) throws java.io.IOException;
    -     method public abstract java.util.Set<java.net.SocketOption<?>> supportedOptions();
    -   }
    - 
    -@@ -53782,7 +53791,7 @@ package java.nio.channels {
    -     method public final java.nio.channels.ServerSocketChannel bind(java.net.SocketAddress) throws java.io.IOException;
    -     method public abstract java.nio.channels.ServerSocketChannel bind(java.net.SocketAddress, int) throws java.io.IOException;
    -     method public static java.nio.channels.ServerSocketChannel open() throws java.io.IOException;
    --    method public abstract java.nio.channels.ServerSocketChannel setOption(java.net.SocketOption<T>, T) throws java.io.IOException;
    -+    method public abstract <T> java.nio.channels.ServerSocketChannel setOption(java.net.SocketOption<T>, T) throws java.io.IOException;
    -     method public abstract java.net.ServerSocket socket();
    -     method public final int validOps();
    -   }
    -@@ -53800,7 +53809,7 @@ package java.nio.channels {
    -     method public abstract int read(java.nio.ByteBuffer) throws java.io.IOException;
    -     method public abstract long read(java.nio.ByteBuffer[], int, int) throws java.io.IOException;
    -     method public final long read(java.nio.ByteBuffer[]) throws java.io.IOException;
    --    method public abstract java.nio.channels.SocketChannel setOption(java.net.SocketOption<T>, T) throws java.io.IOException;
    -+    method public abstract <T> java.nio.channels.SocketChannel setOption(java.net.SocketOption<T>, T) throws java.io.IOException;
    -     method public abstract java.nio.channels.SocketChannel shutdownInput() throws java.io.IOException;
    -     method public abstract java.nio.channels.SocketChannel shutdownOutput() throws java.io.IOException;
    -     method public abstract java.net.Socket socket();
    -@@ -54047,12 +54056,12 @@ package java.security {
    - 
    -   public final class AccessController {
    -     method public static void checkPermission(java.security.Permission) throws java.security.AccessControlException;
    --    method public static T doPrivileged(java.security.PrivilegedAction<T>);
    --    method public static T doPrivileged(java.security.PrivilegedAction<T>, java.security.AccessControlContext);
    --    method public static T doPrivileged(java.security.PrivilegedExceptionAction<T>) throws java.security.PrivilegedActionException;
    --    method public static T doPrivileged(java.security.PrivilegedExceptionAction<T>, java.security.AccessControlContext) throws java.security.PrivilegedActionException;
    --    method public static T doPrivilegedWithCombiner(java.security.PrivilegedAction<T>);
    --    method public static T doPrivilegedWithCombiner(java.security.PrivilegedExceptionAction<T>) throws java.security.PrivilegedActionException;
    -+    method public static <T> T doPrivileged(java.security.PrivilegedAction<T>);
    -+    method public static <T> T doPrivileged(java.security.PrivilegedAction<T>, java.security.AccessControlContext);
    -+    method public static <T> T doPrivileged(java.security.PrivilegedExceptionAction<T>) throws java.security.PrivilegedActionException;
    -+    method public static <T> T doPrivileged(java.security.PrivilegedExceptionAction<T>, java.security.AccessControlContext) throws java.security.PrivilegedActionException;
    -+    method public static <T> T doPrivilegedWithCombiner(java.security.PrivilegedAction<T>);
    -+    method public static <T> T doPrivilegedWithCombiner(java.security.PrivilegedExceptionAction<T>) throws java.security.PrivilegedActionException;
    -     method public static java.security.AccessControlContext getContext();
    -   }
    - 
    -@@ -54091,7 +54100,7 @@ package java.security {
    -     method public static java.security.AlgorithmParameters getInstance(java.lang.String) throws java.security.NoSuchAlgorithmException;
    -     method public static java.security.AlgorithmParameters getInstance(java.lang.String, java.lang.String) throws java.security.NoSuchAlgorithmException, java.security.NoSuchProviderException;
    -     method public static java.security.AlgorithmParameters getInstance(java.lang.String, java.security.Provider) throws java.security.NoSuchAlgorithmException;
    --    method public final T getParameterSpec(java.lang.Class<T>) throws java.security.spec.InvalidParameterSpecException;
    -+    method public final <T extends java.security.spec.AlgorithmParameterSpec> T getParameterSpec(java.lang.Class<T>) throws java.security.spec.InvalidParameterSpecException;
    -     method public final java.security.Provider getProvider();
    -     method public final void init(java.security.spec.AlgorithmParameterSpec) throws java.security.spec.InvalidParameterSpecException;
    -     method public final void init(byte[]) throws java.io.IOException;
    -@@ -54103,7 +54112,7 @@ package java.security {
    -     ctor public AlgorithmParametersSpi();
    -     method protected abstract byte[] engineGetEncoded() throws java.io.IOException;
    -     method protected abstract byte[] engineGetEncoded(java.lang.String) throws java.io.IOException;
    --    method protected abstract T engineGetParameterSpec(java.lang.Class<T>) throws java.security.spec.InvalidParameterSpecException;
    -+    method protected abstract <T extends java.security.spec.AlgorithmParameterSpec> T engineGetParameterSpec(java.lang.Class<T>) throws java.security.spec.InvalidParameterSpecException;
    -     method protected abstract void engineInit(java.security.spec.AlgorithmParameterSpec) throws java.security.spec.InvalidParameterSpecException;
    -     method protected abstract void engineInit(byte[]) throws java.io.IOException;
    -     method protected abstract void engineInit(byte[], java.lang.String) throws java.io.IOException;
    -@@ -54288,7 +54297,7 @@ package java.security {
    -     method public static java.security.KeyFactory getInstance(java.lang.String) throws java.security.NoSuchAlgorithmException;
    -     method public static java.security.KeyFactory getInstance(java.lang.String, java.lang.String) throws java.security.NoSuchAlgorithmException, java.security.NoSuchProviderException;
    -     method public static java.security.KeyFactory getInstance(java.lang.String, java.security.Provider) throws java.security.NoSuchAlgorithmException;
    --    method public final T getKeySpec(java.security.Key, java.lang.Class<T>) throws java.security.spec.InvalidKeySpecException;
    -+    method public final <T extends java.security.spec.KeySpec> T getKeySpec(java.security.Key, java.lang.Class<T>) throws java.security.spec.InvalidKeySpecException;
    -     method public final java.security.Provider getProvider();
    -     method public final java.security.Key translateKey(java.security.Key) throws java.security.InvalidKeyException;
    -   }
    -@@ -54297,7 +54306,7 @@ package java.security {
    -     ctor public KeyFactorySpi();
    -     method protected abstract java.security.PrivateKey engineGeneratePrivate(java.security.spec.KeySpec) throws java.security.spec.InvalidKeySpecException;
    -     method protected abstract java.security.PublicKey engineGeneratePublic(java.security.spec.KeySpec) throws java.security.spec.InvalidKeySpecException;
    --    method protected abstract T engineGetKeySpec(java.security.Key, java.lang.Class<T>) throws java.security.spec.InvalidKeySpecException;
    -+    method protected abstract <T extends java.security.spec.KeySpec> T engineGetKeySpec(java.security.Key, java.lang.Class<T>) throws java.security.spec.InvalidKeySpecException;
    -     method protected abstract java.security.Key engineTranslateKey(java.security.Key) throws java.security.InvalidKeyException;
    -   }
    - 
    -@@ -54566,7 +54575,7 @@ package java.security {
    -     field public static final long serialVersionUID = 6034044314589513430L; // 0x53bd3b559a12c6d6L
    -   }
    - 
    --  public abstract interface PrivilegedAction {
    -+  public abstract interface PrivilegedAction<T> {
    -     method public abstract T run();
    -   }
    - 
    -@@ -54575,7 +54584,7 @@ package java.security {
    -     method public java.lang.Exception getException();
    -   }
    - 
    --  public abstract interface PrivilegedExceptionAction {
    -+  public abstract interface PrivilegedExceptionAction<T> {
    -     method public abstract T run() throws java.lang.Exception;
    -   }
    - 
    -@@ -56757,11 +56766,11 @@ package java.sql {
    -     method public abstract void free() throws java.sql.SQLException;
    -     method public abstract java.io.InputStream getBinaryStream() throws java.sql.SQLException;
    -     method public abstract java.io.Reader getCharacterStream() throws java.sql.SQLException;
    --    method public abstract T getSource(java.lang.Class<T>) throws java.sql.SQLException;
    -+    method public abstract <T extends javax.xml.transform.Source> T getSource(java.lang.Class<T>) throws java.sql.SQLException;
    -     method public abstract java.lang.String getString() throws java.sql.SQLException;
    -     method public abstract java.io.OutputStream setBinaryStream() throws java.sql.SQLException;
    -     method public abstract java.io.Writer setCharacterStream() throws java.sql.SQLException;
    --    method public abstract T setResult(java.lang.Class<T>) throws java.sql.SQLException;
    -+    method public abstract <T extends javax.xml.transform.Result> T setResult(java.lang.Class<T>) throws java.sql.SQLException;
    -     method public abstract void setString(java.lang.String) throws java.sql.SQLException;
    -   }
    - 
    -@@ -56885,7 +56894,7 @@ package java.sql {
    - 
    -   public abstract interface Wrapper {
    -     method public abstract boolean isWrapperFor(java.lang.Class<?>) throws java.sql.SQLException;
    --    method public abstract T unwrap(java.lang.Class<T>) throws java.sql.SQLException;
    -+    method public abstract <T> T unwrap(java.lang.Class<T>) throws java.sql.SQLException;
    -   }
    - 
    - }
    -@@ -57418,7 +57427,7 @@ package java.text {
    - 
    - package java.util {
    - 
    --  public abstract class AbstractCollection implements java.util.Collection {
    -+  public abstract class AbstractCollection<E> implements java.util.Collection {
    -     ctor protected AbstractCollection();
    -     method public boolean add(E);
    -     method public boolean addAll(java.util.Collection<? extends E>);
    -@@ -57432,10 +57441,10 @@ package java.util {
    -     method public boolean retainAll(java.util.Collection<?>);
    -     method public abstract int size();
    -     method public java.lang.Object[] toArray();
    --    method public T[] toArray(T[]);
    -+    method public <T> T[] toArray(T[]);
    -   }
    - 
    --  public abstract class AbstractList extends java.util.AbstractCollection implements java.util.List {
    -+  public abstract class AbstractList<E> extends java.util.AbstractCollection implements java.util.List {
    -     ctor protected AbstractList();
    -     method public void add(int, E);
    -     method public boolean addAll(int, java.util.Collection<? extends E>);
    -@@ -57452,7 +57461,7 @@ package java.util {
    -     field protected transient int modCount;
    -   }
    - 
    --  public abstract class AbstractMap implements java.util.Map {
    -+  public abstract class AbstractMap<K, V> implements java.util.Map {
    -     ctor protected AbstractMap();
    -     method public void clear();
    -     method public boolean containsKey(java.lang.Object);
    -@@ -57468,7 +57477,7 @@ package java.util {
    -     method public java.util.Collection<V> values();
    -   }
    - 
    --  public static class AbstractMap.SimpleEntry implements java.util.Map.Entry java.io.Serializable {
    -+  public static class AbstractMap.SimpleEntry<K, V> implements java.util.Map.Entry java.io.Serializable {
    -     ctor public AbstractMap.SimpleEntry(K, V);
    -     ctor public AbstractMap.SimpleEntry(java.util.Map.Entry<? extends K, ? extends V>);
    -     method public K getKey();
    -@@ -57476,7 +57485,7 @@ package java.util {
    -     method public V setValue(V);
    -   }
    - 
    --  public static class AbstractMap.SimpleImmutableEntry implements java.util.Map.Entry java.io.Serializable {
    -+  public static class AbstractMap.SimpleImmutableEntry<K, V> implements java.util.Map.Entry java.io.Serializable {
    -     ctor public AbstractMap.SimpleImmutableEntry(K, V);
    -     ctor public AbstractMap.SimpleImmutableEntry(java.util.Map.Entry<? extends K, ? extends V>);
    -     method public K getKey();
    -@@ -57484,23 +57493,23 @@ package java.util {
    -     method public V setValue(V);
    -   }
    - 
    --  public abstract class AbstractQueue extends java.util.AbstractCollection implements java.util.Queue {
    -+  public abstract class AbstractQueue<E> extends java.util.AbstractCollection implements java.util.Queue {
    -     ctor protected AbstractQueue();
    -     method public E element();
    -     method public E remove();
    -   }
    - 
    --  public abstract class AbstractSequentialList extends java.util.AbstractList {
    -+  public abstract class AbstractSequentialList<E> extends java.util.AbstractList {
    -     ctor protected AbstractSequentialList();
    -     method public E get(int);
    -     method public abstract java.util.ListIterator<E> listIterator(int);
    -   }
    - 
    --  public abstract class AbstractSet extends java.util.AbstractCollection implements java.util.Set {
    -+  public abstract class AbstractSet<E> extends java.util.AbstractCollection implements java.util.Set {
    -     ctor protected AbstractSet();
    -   }
    - 
    --  public class ArrayDeque extends java.util.AbstractCollection implements java.lang.Cloneable java.util.Deque java.io.Serializable {
    -+  public class ArrayDeque<E> extends java.util.AbstractCollection implements java.lang.Cloneable java.util.Deque java.io.Serializable {
    -     ctor public ArrayDeque();
    -     ctor public ArrayDeque(int);
    -     ctor public ArrayDeque(java.util.Collection<? extends E>);
    -@@ -57532,7 +57541,7 @@ package java.util {
    -     method public java.util.Spliterator<E> spliterator();
    -   }
    - 
    --  public class ArrayList extends java.util.AbstractList implements java.lang.Cloneable java.util.List java.util.RandomAccess java.io.Serializable {
    -+  public class ArrayList<E> extends java.util.AbstractList implements java.lang.Cloneable java.util.List java.util.RandomAccess java.io.Serializable {
    -     ctor public ArrayList(int);
    -     ctor public ArrayList();
    -     ctor public ArrayList(java.util.Collection<? extends E>);
    -@@ -57549,7 +57558,7 @@ package java.util {
    -   }
    - 
    -   public class Arrays {
    --    method public static java.util.List<T> asList(T...);
    -+    method public static <T> java.util.List<T> asList(T...);
    -     method public static int binarySearch(long[], long);
    -     method public static int binarySearch(long[], int, int, long);
    -     method public static int binarySearch(int[], int);
    -@@ -57566,10 +57575,10 @@ package java.util {
    -     method public static int binarySearch(float[], int, int, float);
    -     method public static int binarySearch(java.lang.Object[], java.lang.Object);
    -     method public static int binarySearch(java.lang.Object[], int, int, java.lang.Object);
    --    method public static int binarySearch(T[], T, java.util.Comparator<? super T>);
    --    method public static int binarySearch(T[], int, int, T, java.util.Comparator<? super T>);
    --    method public static T[] copyOf(T[], int);
    --    method public static T[] copyOf(U[], int, java.lang.Class<? extends T[]>);
    -+    method public static <T> int binarySearch(T[], T, java.util.Comparator<? super T>);
    -+    method public static <T> int binarySearch(T[], int, int, T, java.util.Comparator<? super T>);
    -+    method public static <T> T[] copyOf(T[], int);
    -+    method public static <T, U> T[] copyOf(U[], int, java.lang.Class<? extends T[]>);
    -     method public static byte[] copyOf(byte[], int);
    -     method public static short[] copyOf(short[], int);
    -     method public static int[] copyOf(int[], int);
    -@@ -57578,8 +57587,8 @@ package java.util {
    -     method public static float[] copyOf(float[], int);
    -     method public static double[] copyOf(double[], int);
    -     method public static boolean[] copyOf(boolean[], int);
    --    method public static T[] copyOfRange(T[], int, int);
    --    method public static T[] copyOfRange(U[], int, int, java.lang.Class<? extends T[]>);
    -+    method public static <T> T[] copyOfRange(T[], int, int);
    -+    method public static <T, U> T[] copyOfRange(U[], int, int, java.lang.Class<? extends T[]>);
    -     method public static byte[] copyOfRange(byte[], int, int);
    -     method public static short[] copyOfRange(short[], int, int);
    -     method public static int[] copyOfRange(int[], int, int);
    -@@ -57627,15 +57636,15 @@ package java.util {
    -     method public static int hashCode(float[]);
    -     method public static int hashCode(double[]);
    -     method public static int hashCode(java.lang.Object[]);
    --    method public static void parallelPrefix(T[], java.util.function.BinaryOperator<T>);
    --    method public static void parallelPrefix(T[], int, int, java.util.function.BinaryOperator<T>);
    -+    method public static <T> void parallelPrefix(T[], java.util.function.BinaryOperator<T>);
    -+    method public static <T> void parallelPrefix(T[], int, int, java.util.function.BinaryOperator<T>);
    -     method public static void parallelPrefix(long[], java.util.function.LongBinaryOperator);
    -     method public static void parallelPrefix(long[], int, int, java.util.function.LongBinaryOperator);
    -     method public static void parallelPrefix(double[], java.util.function.DoubleBinaryOperator);
    -     method public static void parallelPrefix(double[], int, int, java.util.function.DoubleBinaryOperator);
    -     method public static void parallelPrefix(int[], java.util.function.IntBinaryOperator);
    -     method public static void parallelPrefix(int[], int, int, java.util.function.IntBinaryOperator);
    --    method public static void parallelSetAll(T[], java.util.function.IntFunction<? extends T>);
    -+    method public static <T> void parallelSetAll(T[], java.util.function.IntFunction<? extends T>);
    -     method public static void parallelSetAll(int[], java.util.function.IntUnaryOperator);
    -     method public static void parallelSetAll(long[], java.util.function.IntToLongFunction);
    -     method public static void parallelSetAll(double[], java.util.function.IntToDoubleFunction);
    -@@ -57653,11 +57662,11 @@ package java.util {
    -     method public static void parallelSort(float[], int, int);
    -     method public static void parallelSort(double[]);
    -     method public static void parallelSort(double[], int, int);
    --    method public static void parallelSort(T[]);
    --    method public static void parallelSort(T[], int, int);
    --    method public static void parallelSort(T[], java.util.Comparator<? super T>);
    --    method public static void parallelSort(T[], int, int, java.util.Comparator<? super T>);
    --    method public static void setAll(T[], java.util.function.IntFunction<? extends T>);
    -+    method public static <T extends java.lang.Comparable<? super T>> void parallelSort(T[]);
    -+    method public static <T extends java.lang.Comparable<? super T>> void parallelSort(T[], int, int);
    -+    method public static <T> void parallelSort(T[], java.util.Comparator<? super T>);
    -+    method public static <T> void parallelSort(T[], int, int, java.util.Comparator<? super T>);
    -+    method public static <T> void setAll(T[], java.util.function.IntFunction<? extends T>);
    -     method public static void setAll(int[], java.util.function.IntUnaryOperator);
    -     method public static void setAll(long[], java.util.function.IntToLongFunction);
    -     method public static void setAll(double[], java.util.function.IntToDoubleFunction);
    -@@ -57677,18 +57686,18 @@ package java.util {
    -     method public static void sort(double[], int, int);
    -     method public static void sort(java.lang.Object[]);
    -     method public static void sort(java.lang.Object[], int, int);
    --    method public static void sort(T[], java.util.Comparator<? super T>);
    --    method public static void sort(T[], int, int, java.util.Comparator<? super T>);
    --    method public static java.util.Spliterator<T> spliterator(T[]);
    --    method public static java.util.Spliterator<T> spliterator(T[], int, int);
    -+    method public static <T> void sort(T[], java.util.Comparator<? super T>);
    -+    method public static <T> void sort(T[], int, int, java.util.Comparator<? super T>);
    -+    method public static <T> java.util.Spliterator<T> spliterator(T[]);
    -+    method public static <T> java.util.Spliterator<T> spliterator(T[], int, int);
    -     method public static java.util.Spliterator.OfInt spliterator(int[]);
    -     method public static java.util.Spliterator.OfInt spliterator(int[], int, int);
    -     method public static java.util.Spliterator.OfLong spliterator(long[]);
    -     method public static java.util.Spliterator.OfLong spliterator(long[], int, int);
    -     method public static java.util.Spliterator.OfDouble spliterator(double[]);
    -     method public static java.util.Spliterator.OfDouble spliterator(double[], int, int);
    --    method public static java.util.stream.Stream<T> stream(T[]);
    --    method public static java.util.stream.Stream<T> stream(T[], int, int);
    -+    method public static <T> java.util.stream.Stream<T> stream(T[]);
    -+    method public static <T> java.util.stream.Stream<T> stream(T[], int, int);
    -     method public static java.util.stream.IntStream stream(int[]);
    -     method public static java.util.stream.IntStream stream(int[], int, int);
    -     method public static java.util.stream.LongStream stream(long[]);
    -@@ -57845,7 +57854,7 @@ package java.util {
    -     field protected long time;
    -   }
    - 
    --  public abstract interface Collection implements java.lang.Iterable {
    -+  public abstract interface Collection<E> implements java.lang.Iterable {
    -     method public abstract boolean add(E);
    -     method public abstract boolean addAll(java.util.Collection<? extends E>);
    -     method public abstract void clear();
    -@@ -57863,86 +57872,86 @@ package java.util {
    -     method public abstract int size();
    -     method public default java.util.stream.Stream<E> stream();
    -     method public abstract java.lang.Object[] toArray();
    --    method public abstract T[] toArray(T[]);
    -+    method public abstract <T> T[] toArray(T[]);
    -   }
    - 
    -   public class Collections {
    --    method public static boolean addAll(java.util.Collection<? super T>, T...);
    --    method public static java.util.Queue<T> asLifoQueue(java.util.Deque<T>);
    --    method public static int binarySearch(java.util.List<? extends java.lang.Comparable<? super T>>, T);
    --    method public static int binarySearch(java.util.List<? extends T>, T, java.util.Comparator<? super T>);
    --    method public static java.util.Collection<E> checkedCollection(java.util.Collection<E>, java.lang.Class<E>);
    --    method public static java.util.List<E> checkedList(java.util.List<E>, java.lang.Class<E>);
    --    method public static java.util.Map<K, V> checkedMap(java.util.Map<K, V>, java.lang.Class<K>, java.lang.Class<V>);
    --    method public static java.util.Set<E> checkedSet(java.util.Set<E>, java.lang.Class<E>);
    --    method public static java.util.SortedMap<K, V> checkedSortedMap(java.util.SortedMap<K, V>, java.lang.Class<K>, java.lang.Class<V>);
    --    method public static java.util.SortedSet<E> checkedSortedSet(java.util.SortedSet<E>, java.lang.Class<E>);
    --    method public static void copy(java.util.List<? super T>, java.util.List<? extends T>);
    -+    method public static <T> boolean addAll(java.util.Collection<? super T>, T...);
    -+    method public static <T> java.util.Queue<T> asLifoQueue(java.util.Deque<T>);
    -+    method public static <T> int binarySearch(java.util.List<? extends java.lang.Comparable<? super T>>, T);
    -+    method public static <T> int binarySearch(java.util.List<? extends T>, T, java.util.Comparator<? super T>);
    -+    method public static <E> java.util.Collection<E> checkedCollection(java.util.Collection<E>, java.lang.Class<E>);
    -+    method public static <E> java.util.List<E> checkedList(java.util.List<E>, java.lang.Class<E>);
    -+    method public static <K, V> java.util.Map<K, V> checkedMap(java.util.Map<K, V>, java.lang.Class<K>, java.lang.Class<V>);
    -+    method public static <E> java.util.Set<E> checkedSet(java.util.Set<E>, java.lang.Class<E>);
    -+    method public static <K, V> java.util.SortedMap<K, V> checkedSortedMap(java.util.SortedMap<K, V>, java.lang.Class<K>, java.lang.Class<V>);
    -+    method public static <E> java.util.SortedSet<E> checkedSortedSet(java.util.SortedSet<E>, java.lang.Class<E>);
    -+    method public static <T> void copy(java.util.List<? super T>, java.util.List<? extends T>);
    -     method public static boolean disjoint(java.util.Collection<?>, java.util.Collection<?>);
    --    method public static java.util.Enumeration<T> emptyEnumeration();
    --    method public static java.util.Iterator<T> emptyIterator();
    --    method public static final java.util.List<T> emptyList();
    --    method public static java.util.ListIterator<T> emptyListIterator();
    --    method public static final java.util.Map<K, V> emptyMap();
    --    method public static final java.util.Set<T> emptySet();
    --    method public static java.util.Enumeration<T> enumeration(java.util.Collection<T>);
    --    method public static void fill(java.util.List<? super T>, T);
    -+    method public static <T> java.util.Enumeration<T> emptyEnumeration();
    -+    method public static <T> java.util.Iterator<T> emptyIterator();
    -+    method public static final <T> java.util.List<T> emptyList();
    -+    method public static <T> java.util.ListIterator<T> emptyListIterator();
    -+    method public static final <K, V> java.util.Map<K, V> emptyMap();
    -+    method public static final <T> java.util.Set<T> emptySet();
    -+    method public static <T> java.util.Enumeration<T> enumeration(java.util.Collection<T>);
    -+    method public static <T> void fill(java.util.List<? super T>, T);
    -     method public static int frequency(java.util.Collection<?>, java.lang.Object);
    -     method public static int indexOfSubList(java.util.List<?>, java.util.List<?>);
    -     method public static int lastIndexOfSubList(java.util.List<?>, java.util.List<?>);
    --    method public static java.util.ArrayList<T> list(java.util.Enumeration<T>);
    --    method public static T max(java.util.Collection<? extends T>);
    --    method public static T max(java.util.Collection<? extends T>, java.util.Comparator<? super T>);
    --    method public static T min(java.util.Collection<? extends T>);
    --    method public static T min(java.util.Collection<? extends T>, java.util.Comparator<? super T>);
    --    method public static java.util.List<T> nCopies(int, T);
    --    method public static java.util.Set<E> newSetFromMap(java.util.Map<E, java.lang.Boolean>);
    --    method public static boolean replaceAll(java.util.List<T>, T, T);
    -+    method public static <T> java.util.ArrayList<T> list(java.util.Enumeration<T>);
    -+    method public static <T extends java.lang.Object & java.lang.Comparable<? super T>> T max(java.util.Collection<? extends T>);
    -+    method public static <T> T max(java.util.Collection<? extends T>, java.util.Comparator<? super T>);
    -+    method public static <T extends java.lang.Object & java.lang.Comparable<? super T>> T min(java.util.Collection<? extends T>);
    -+    method public static <T> T min(java.util.Collection<? extends T>, java.util.Comparator<? super T>);
    -+    method public static <T> java.util.List<T> nCopies(int, T);
    -+    method public static <E> java.util.Set<E> newSetFromMap(java.util.Map<E, java.lang.Boolean>);
    -+    method public static <T> boolean replaceAll(java.util.List<T>, T, T);
    -     method public static void reverse(java.util.List<?>);
    --    method public static java.util.Comparator<T> reverseOrder();
    --    method public static java.util.Comparator<T> reverseOrder(java.util.Comparator<T>);
    -+    method public static <T> java.util.Comparator<T> reverseOrder();
    -+    method public static <T> java.util.Comparator<T> reverseOrder(java.util.Comparator<T>);
    -     method public static void rotate(java.util.List<?>, int);
    -     method public static void shuffle(java.util.List<?>);
    -     method public static void shuffle(java.util.List<?>, java.util.Random);
    --    method public static java.util.Set<E> singleton(E);
    --    method public static java.util.List<E> singletonList(E);
    --    method public static java.util.Map<K, V> singletonMap(K, V);
    --    method public static void sort(java.util.List<T>);
    --    method public static void sort(java.util.List<T>, java.util.Comparator<? super T>);
    -+    method public static <E> java.util.Set<E> singleton(E);
    -+    method public static <E> java.util.List<E> singletonList(E);
    -+    method public static <K, V> java.util.Map<K, V> singletonMap(K, V);
    -+    method public static <T extends java.lang.Comparable<? super T>> void sort(java.util.List<T>);
    -+    method public static <T> void sort(java.util.List<T>, java.util.Comparator<? super T>);
    -     method public static void swap(java.util.List<?>, int, int);
    --    method public static java.util.Collection<T> synchronizedCollection(java.util.Collection<T>);
    --    method public static java.util.List<T> synchronizedList(java.util.List<T>);
    --    method public static java.util.Map<K, V> synchronizedMap(java.util.Map<K, V>);
    --    method public static java.util.Set<T> synchronizedSet(java.util.Set<T>);
    --    method public static java.util.SortedMap<K, V> synchronizedSortedMap(java.util.SortedMap<K, V>);
    --    method public static java.util.SortedSet<T> synchronizedSortedSet(java.util.SortedSet<T>);
    --    method public static java.util.Collection<T> unmodifiableCollection(java.util.Collection<? extends T>);
    --    method public static java.util.List<T> unmodifiableList(java.util.List<? extends T>);
    --    method public static java.util.Map<K, V> unmodifiableMap(java.util.Map<? extends K, ? extends V>);
    --    method public static java.util.Set<T> unmodifiableSet(java.util.Set<? extends T>);
    --    method public static java.util.SortedMap<K, V> unmodifiableSortedMap(java.util.SortedMap<K, ? extends V>);
    --    method public static java.util.SortedSet<T> unmodifiableSortedSet(java.util.SortedSet<T>);
    -+    method public static <T> java.util.Collection<T> synchronizedCollection(java.util.Collection<T>);
    -+    method public static <T> java.util.List<T> synchronizedList(java.util.List<T>);
    -+    method public static <K, V> java.util.Map<K, V> synchronizedMap(java.util.Map<K, V>);
    -+    method public static <T> java.util.Set<T> synchronizedSet(java.util.Set<T>);
    -+    method public static <K, V> java.util.SortedMap<K, V> synchronizedSortedMap(java.util.SortedMap<K, V>);
    -+    method public static <T> java.util.SortedSet<T> synchronizedSortedSet(java.util.SortedSet<T>);
    -+    method public static <T> java.util.Collection<T> unmodifiableCollection(java.util.Collection<? extends T>);
    -+    method public static <T> java.util.List<T> unmodifiableList(java.util.List<? extends T>);
    -+    method public static <K, V> java.util.Map<K, V> unmodifiableMap(java.util.Map<? extends K, ? extends V>);
    -+    method public static <T> java.util.Set<T> unmodifiableSet(java.util.Set<? extends T>);
    -+    method public static <K, V> java.util.SortedMap<K, V> unmodifiableSortedMap(java.util.SortedMap<K, ? extends V>);
    -+    method public static <T> java.util.SortedSet<T> unmodifiableSortedSet(java.util.SortedSet<T>);
    -     field public static final java.util.List EMPTY_LIST;
    -     field public static final java.util.Map EMPTY_MAP;
    -     field public static final java.util.Set EMPTY_SET;
    -   }
    - 
    --  public abstract interface Comparator {
    -+  public abstract interface Comparator<T> {
    -     method public abstract int compare(T, T);
    --    method public static java.util.Comparator<T> comparing(java.util.function.Function<? super T, ? extends U>, java.util.Comparator<? super U>);
    --    method public static java.util.Comparator<T> comparing(java.util.function.Function<? super T, ? extends U>);
    --    method public static java.util.Comparator<T> comparingDouble(java.util.function.ToDoubleFunction<? super T>);
    --    method public static java.util.Comparator<T> comparingInt(java.util.function.ToIntFunction<? super T>);
    --    method public static java.util.Comparator<T> comparingLong(java.util.function.ToLongFunction<? super T>);
    -+    method public static <T, U> java.util.Comparator<T> comparing(java.util.function.Function<? super T, ? extends U>, java.util.Comparator<? super U>);
    -+    method public static <T, U extends java.lang.Comparable<? super U>> java.util.Comparator<T> comparing(java.util.function.Function<? super T, ? extends U>);
    -+    method public static <T> java.util.Comparator<T> comparingDouble(java.util.function.ToDoubleFunction<? super T>);
    -+    method public static <T> java.util.Comparator<T> comparingInt(java.util.function.ToIntFunction<? super T>);
    -+    method public static <T> java.util.Comparator<T> comparingLong(java.util.function.ToLongFunction<? super T>);
    -     method public abstract boolean equals(java.lang.Object);
    --    method public static java.util.Comparator<T> naturalOrder();
    --    method public static java.util.Comparator<T> nullsFirst(java.util.Comparator<? super T>);
    --    method public static java.util.Comparator<T> nullsLast(java.util.Comparator<? super T>);
    --    method public static java.util.Comparator<T> reverseOrder();
    -+    method public static <T extends java.lang.Comparable<? super T>> java.util.Comparator<T> naturalOrder();
    -+    method public static <T> java.util.Comparator<T> nullsFirst(java.util.Comparator<? super T>);
    -+    method public static <T> java.util.Comparator<T> nullsLast(java.util.Comparator<? super T>);
    -+    method public static <T extends java.lang.Comparable<? super T>> java.util.Comparator<T> reverseOrder();
    -     method public default java.util.Comparator<T> reversed();
    -     method public default java.util.Comparator<T> thenComparing(java.util.Comparator<? super T>);
    --    method public default java.util.Comparator<T> thenComparing(java.util.function.Function<? super T, ? extends U>, java.util.Comparator<? super U>);
    --    method public default java.util.Comparator<T> thenComparing(java.util.function.Function<? super T, ? extends U>);
    -+    method public default <U> java.util.Comparator<T> thenComparing(java.util.function.Function<? super T, ? extends U>, java.util.Comparator<? super U>);
    -+    method public default <U extends java.lang.Comparable<? super U>> java.util.Comparator<T> thenComparing(java.util.function.Function<? super T, ? extends U>);
    -     method public default java.util.Comparator<T> thenComparingDouble(java.util.function.ToDoubleFunction<? super T>);
    -     method public default java.util.Comparator<T> thenComparingInt(java.util.function.ToIntFunction<? super T>);
    -     method public default java.util.Comparator<T> thenComparingLong(java.util.function.ToLongFunction<? super T>);
    -@@ -58001,7 +58010,7 @@ package java.util {
    -     method public deprecated java.lang.String toLocaleString();
    -   }
    - 
    --  public abstract interface Deque implements java.util.Queue {
    -+  public abstract interface Deque<E> implements java.util.Queue {
    -     method public abstract boolean add(E);
    -     method public abstract void addFirst(E);
    -     method public abstract void addLast(E);
    -@@ -58031,7 +58040,7 @@ package java.util {
    -     method public abstract int size();
    -   }
    - 
    --  public abstract class Dictionary {
    -+  public abstract class Dictionary<K, V> {
    -     ctor public Dictionary();
    -     method public abstract java.util.Enumeration<V> elements();
    -     method public abstract V get(java.lang.Object);
    -@@ -58062,7 +58071,7 @@ package java.util {
    -     ctor public EmptyStackException();
    -   }
    - 
    --  public class EnumMap extends java.util.AbstractMap implements java.lang.Cloneable java.io.Serializable {
    -+  public class EnumMap<K extends java.lang.Enum<K>, V> extends java.util.AbstractMap implements java.lang.Cloneable java.io.Serializable {
    -     ctor public EnumMap(java.lang.Class<K>);
    -     ctor public EnumMap(java.util.EnumMap<K, ? extends V>);
    -     ctor public EnumMap(java.util.Map<K, ? extends V>);
    -@@ -58070,23 +58079,23 @@ package java.util {
    -     method public java.util.Set<java.util.Map.Entry<K, V>> entrySet();
    -   }
    - 
    --  public abstract class EnumSet extends java.util.AbstractSet implements java.lang.Cloneable java.io.Serializable {
    --    method public static java.util.EnumSet<E> allOf(java.lang.Class<E>);
    -+  public abstract class EnumSet<E extends java.lang.Enum<E>> extends java.util.AbstractSet implements java.lang.Cloneable java.io.Serializable {
    -+    method public static <E extends java.lang.Enum<E>> java.util.EnumSet<E> allOf(java.lang.Class<E>);
    -     method public java.util.EnumSet<E> clone();
    --    method public static java.util.EnumSet<E> complementOf(java.util.EnumSet<E>);
    --    method public static java.util.EnumSet<E> copyOf(java.util.EnumSet<E>);
    --    method public static java.util.EnumSet<E> copyOf(java.util.Collection<E>);
    --    method public static java.util.EnumSet<E> noneOf(java.lang.Class<E>);
    --    method public static java.util.EnumSet<E> of(E);
    --    method public static java.util.EnumSet<E> of(E, E);
    --    method public static java.util.EnumSet<E> of(E, E, E);
    --    method public static java.util.EnumSet<E> of(E, E, E, E);
    --    method public static java.util.EnumSet<E> of(E, E, E, E, E);
    --    method public static java.util.EnumSet<E> of(E, E...);
    --    method public static java.util.EnumSet<E> range(E, E);
    --  }
    --
    --  public abstract interface Enumeration {
    -+    method public static <E extends java.lang.Enum<E>> java.util.EnumSet<E> complementOf(java.util.EnumSet<E>);
    -+    method public static <E extends java.lang.Enum<E>> java.util.EnumSet<E> copyOf(java.util.EnumSet<E>);
    -+    method public static <E extends java.lang.Enum<E>> java.util.EnumSet<E> copyOf(java.util.Collection<E>);
    -+    method public static <E extends java.lang.Enum<E>> java.util.EnumSet<E> noneOf(java.lang.Class<E>);
    -+    method public static <E extends java.lang.Enum<E>> java.util.EnumSet<E> of(E);
    -+    method public static <E extends java.lang.Enum<E>> java.util.EnumSet<E> of(E, E);
    -+    method public static <E extends java.lang.Enum<E>> java.util.EnumSet<E> of(E, E, E);
    -+    method public static <E extends java.lang.Enum<E>> java.util.EnumSet<E> of(E, E, E, E);
    -+    method public static <E extends java.lang.Enum<E>> java.util.EnumSet<E> of(E, E, E, E, E);
    -+    method public static <E extends java.lang.Enum<E>> java.util.EnumSet<E> of(E, E...);
    -+    method public static <E extends java.lang.Enum<E>> java.util.EnumSet<E> range(E, E);
    -+  }
    -+
    -+  public abstract interface Enumeration<E> {
    -     method public abstract boolean hasMoreElements();
    -     method public abstract E nextElement();
    -   }
    -@@ -58094,7 +58103,7 @@ package java.util {
    -   public abstract interface EventListener {
    -   }
    - 
    --  public abstract class EventListenerProxy implements java.util.EventListener {
    -+  public abstract class EventListenerProxy<T extends java.util.EventListener> implements java.util.EventListener {
    -     ctor public EventListenerProxy(T);
    -     method public T getListener();
    -   }
    -@@ -58180,7 +58189,7 @@ package java.util {
    -     field public static final int BC = 0; // 0x0
    -   }
    - 
    --  public class HashMap extends java.util.AbstractMap implements java.lang.Cloneable java.util.Map java.io.Serializable {
    -+  public class HashMap<K, V> extends java.util.AbstractMap implements java.lang.Cloneable java.util.Map java.io.Serializable {
    -     ctor public HashMap(int, float);
    -     ctor public HashMap(int);
    -     ctor public HashMap();
    -@@ -58192,7 +58201,7 @@ package java.util {
    -     method public void replaceAll(java.util.function.BiFunction<? super K, ? super V, ? extends V>);
    -   }
    - 
    --  public class HashSet extends java.util.AbstractSet implements java.lang.Cloneable java.io.Serializable java.util.Set {
    -+  public class HashSet<E> extends java.util.AbstractSet implements java.lang.Cloneable java.io.Serializable java.util.Set {
    -     ctor public HashSet();
    -     ctor public HashSet(java.util.Collection<? extends E>);
    -     ctor public HashSet(int, float);
    -@@ -58203,7 +58212,7 @@ package java.util {
    -     method public java.util.Spliterator<E> spliterator();
    -   }
    - 
    --  public class Hashtable extends java.util.Dictionary implements java.lang.Cloneable java.util.Map java.io.Serializable {
    -+  public class Hashtable<K, V> extends java.util.Dictionary implements java.lang.Cloneable java.util.Map java.io.Serializable {
    -     ctor public Hashtable(int, float);
    -     ctor public Hashtable(int);
    -     ctor public Hashtable();
    -@@ -58238,7 +58247,7 @@ package java.util {
    -     method public java.util.Collection<V> values();
    -   }
    - 
    --  public class IdentityHashMap extends java.util.AbstractMap implements java.lang.Cloneable java.util.Map java.io.Serializable {
    -+  public class IdentityHashMap<K, V> extends java.util.AbstractMap implements java.lang.Cloneable java.util.Map java.io.Serializable {
    -     ctor public IdentityHashMap();
    -     ctor public IdentityHashMap(int);
    -     ctor public IdentityHashMap(java.util.Map<? extends K, ? extends V>);
    -@@ -58305,14 +58314,14 @@ package java.util {
    -     ctor public InvalidPropertiesFormatException(java.lang.String);
    -   }
    - 
    --  public abstract interface Iterator {
    -+  public abstract interface Iterator<E> {
    -     method public default void forEachRemaining(java.util.function.Consumer<? super E>);
    -     method public abstract boolean hasNext();
    -     method public abstract E next();
    -     method public default void remove();
    -   }
    - 
    --  public class LinkedHashMap extends java.util.HashMap implements java.util.Map {
    -+  public class LinkedHashMap<K, V> extends java.util.HashMap implements java.util.Map {
    -     ctor public LinkedHashMap(int, float);
    -     ctor public LinkedHashMap(int);
    -     ctor public LinkedHashMap();
    -@@ -58321,14 +58330,14 @@ package java.util {
    -     method protected boolean removeEldestEntry(java.util.Map.Entry<K, V>);
    -   }
    - 
    --  public class LinkedHashSet extends java.util.HashSet implements java.lang.Cloneable java.io.Serializable java.util.Set {
    -+  public class LinkedHashSet<E> extends java.util.HashSet implements java.lang.Cloneable java.io.Serializable java.util.Set {
    -     ctor public LinkedHashSet(int, float);
    -     ctor public LinkedHashSet(int);
    -     ctor public LinkedHashSet();
    -     ctor public LinkedHashSet(java.util.Collection<? extends E>);
    -   }
    - 
    --  public class LinkedList extends java.util.AbstractSequentialList implements java.lang.Cloneable java.util.Deque java.util.List java.io.Serializable {
    -+  public class LinkedList<E> extends java.util.AbstractSequentialList implements java.lang.Cloneable java.util.Deque java.util.List java.io.Serializable {
    -     ctor public LinkedList();
    -     ctor public LinkedList(java.util.Collection<? extends E>);
    -     method public void addFirst(E);
    -@@ -58359,7 +58368,7 @@ package java.util {
    -     method public java.util.Spliterator<E> spliterator();
    -   }
    - 
    --  public abstract interface List implements java.util.Collection {
    -+  public abstract interface List<E> implements java.util.Collection {
    -     method public abstract boolean add(E);
    -     method public abstract void add(int, E);
    -     method public abstract boolean addAll(java.util.Collection<? extends E>);
    -@@ -58386,10 +58395,10 @@ package java.util {
    -     method public default void sort(java.util.Comparator<? super E>);
    -     method public abstract java.util.List<E> subList(int, int);
    -     method public abstract java.lang.Object[] toArray();
    --    method public abstract T[] toArray(T[]);
    -+    method public abstract <T> T[] toArray(T[]);
    -   }
    - 
    --  public abstract interface ListIterator implements java.util.Iterator {
    -+  public abstract interface ListIterator<E> implements java.util.Iterator {
    -     method public abstract void add(E);
    -     method public abstract boolean hasNext();
    -     method public abstract boolean hasPrevious();
    -@@ -58506,7 +58515,7 @@ package java.util {
    -     method public final long getSum();
    -   }
    - 
    --  public abstract interface Map {
    -+  public abstract interface Map<K, V> {
    -     method public abstract void clear();
    -     method public default V compute(K, java.util.function.BiFunction<? super K, ? super V, ? extends V>);
    -     method public default V computeIfAbsent(K, java.util.function.Function<? super K, ? extends V>);
    -@@ -58534,11 +58543,11 @@ package java.util {
    -     method public abstract java.util.Collection<V> values();
    -   }
    - 
    --  public static abstract interface Map.Entry {
    --    method public static java.util.Comparator<java.util.Map.Entry<K, V>> comparingByKey();
    --    method public static java.util.Comparator<java.util.Map.Entry<K, V>> comparingByKey(java.util.Comparator<? super K>);
    --    method public static java.util.Comparator<java.util.Map.Entry<K, V>> comparingByValue();
    --    method public static java.util.Comparator<java.util.Map.Entry<K, V>> comparingByValue(java.util.Comparator<? super V>);
    -+  public static abstract interface Map.Entry<K, V> {
    -+    method public static <K extends java.lang.Comparable<? super K>, V> java.util.Comparator<java.util.Map.Entry<K, V>> comparingByKey();
    -+    method public static <K, V> java.util.Comparator<java.util.Map.Entry<K, V>> comparingByKey(java.util.Comparator<? super K>);
    -+    method public static <K, V extends java.lang.Comparable<? super V>> java.util.Comparator<java.util.Map.Entry<K, V>> comparingByValue();
    -+    method public static <K, V> java.util.Comparator<java.util.Map.Entry<K, V>> comparingByValue(java.util.Comparator<? super V>);
    -     method public abstract boolean equals(java.lang.Object);
    -     method public abstract K getKey();
    -     method public abstract V getValue();
    -@@ -58562,7 +58571,7 @@ package java.util {
    -     method public java.lang.String getKey();
    -   }
    - 
    --  public abstract interface NavigableMap implements java.util.SortedMap {
    -+  public abstract interface NavigableMap<K, V> implements java.util.SortedMap {
    -     method public abstract java.util.Map.Entry<K, V> ceilingEntry(K);
    -     method public abstract K ceilingKey(K);
    -     method public abstract java.util.NavigableSet<K> descendingKeySet();
    -@@ -58586,7 +58595,7 @@ package java.util {
    -     method public abstract java.util.SortedMap<K, V> tailMap(K);
    -   }
    - 
    --  public abstract interface NavigableSet implements java.util.SortedSet {
    -+  public abstract interface NavigableSet<E> implements java.util.SortedSet {
    -     method public abstract E ceiling(E);
    -     method public abstract java.util.Iterator<E> descendingIterator();
    -     method public abstract java.util.NavigableSet<E> descendingSet();
    -@@ -58610,16 +58619,16 @@ package java.util {
    -   }
    - 
    -   public final class Objects {
    --    method public static int compare(T, T, java.util.Comparator<? super T>);
    -+    method public static <T> int compare(T, T, java.util.Comparator<? super T>);
    -     method public static boolean deepEquals(java.lang.Object, java.lang.Object);
    -     method public static boolean equals(java.lang.Object, java.lang.Object);
    -     method public static int hash(java.lang.Object...);
    -     method public static int hashCode(java.lang.Object);
    -     method public static boolean isNull(java.lang.Object);
    -     method public static boolean nonNull(java.lang.Object);
    --    method public static T requireNonNull(T);
    --    method public static T requireNonNull(T, java.lang.String);
    --    method public static T requireNonNull(T, java.util.function.Supplier<java.lang.String>);
    -+    method public static <T> T requireNonNull(T);
    -+    method public static <T> T requireNonNull(T, java.lang.String);
    -+    method public static <T> T requireNonNull(T, java.util.function.Supplier<java.lang.String>);
    -     method public static java.lang.String toString(java.lang.Object);
    -     method public static java.lang.String toString(java.lang.Object, java.lang.String);
    -   }
    -@@ -58641,19 +58650,19 @@ package java.util {
    -     method public abstract void update(java.util.Observable, java.lang.Object);
    -   }
    - 
    --  public final class Optional {
    --    method public static java.util.Optional<T> empty();
    -+  public final class Optional<T> {
    -+    method public static <T> java.util.Optional<T> empty();
    -     method public java.util.Optional<T> filter(java.util.function.Predicate<? super T>);
    --    method public java.util.Optional<U> flatMap(java.util.function.Function<? super T, java.util.Optional<U>>);
    -+    method public <U> java.util.Optional<U> flatMap(java.util.function.Function<? super T, java.util.Optional<U>>);
    -     method public T get();
    -     method public void ifPresent(java.util.function.Consumer<? super T>);
    -     method public boolean isPresent();
    --    method public java.util.Optional<U> map(java.util.function.Function<? super T, ? extends U>);
    --    method public static java.util.Optional<T> of(T);
    --    method public static java.util.Optional<T> ofNullable(T);
    -+    method public <U> java.util.Optional<U> map(java.util.function.Function<? super T, ? extends U>);
    -+    method public static <T> java.util.Optional<T> of(T);
    -+    method public static <T> java.util.Optional<T> ofNullable(T);
    -     method public T orElse(T);
    -     method public T orElseGet(java.util.function.Supplier<? extends T>);
    --    method public T orElseThrow(java.util.function.Supplier<? extends X>) throws java.lang.Throwable;
    -+    method public <X extends java.lang.Throwable> T orElseThrow(java.util.function.Supplier<? extends X>) throws java.lang.Throwable;
    -   }
    - 
    -   public final class OptionalDouble {
    -@@ -58664,7 +58673,7 @@ package java.util {
    -     method public static java.util.OptionalDouble of(double);
    -     method public double orElse(double);
    -     method public double orElseGet(java.util.function.DoubleSupplier);
    --    method public double orElseThrow(java.util.function.Supplier<X>) throws java.lang.Throwable;
    -+    method public <X extends java.lang.Throwable> double orElseThrow(java.util.function.Supplier<X>) throws java.lang.Throwable;
    -   }
    - 
    -   public final class OptionalInt {
    -@@ -58675,7 +58684,7 @@ package java.util {
    -     method public static java.util.OptionalInt of(int);
    -     method public int orElse(int);
    -     method public int orElseGet(java.util.function.IntSupplier);
    --    method public int orElseThrow(java.util.function.Supplier<X>) throws java.lang.Throwable;
    -+    method public <X extends java.lang.Throwable> int orElseThrow(java.util.function.Supplier<X>) throws java.lang.Throwable;
    -   }
    - 
    -   public final class OptionalLong {
    -@@ -58686,10 +58695,10 @@ package java.util {
    -     method public static java.util.OptionalLong of(long);
    -     method public long orElse(long);
    -     method public long orElseGet(java.util.function.LongSupplier);
    --    method public long orElseThrow(java.util.function.Supplier<X>) throws java.lang.Throwable;
    -+    method public <X extends java.lang.Throwable> long orElseThrow(java.util.function.Supplier<X>) throws java.lang.Throwable;
    -   }
    - 
    --  public abstract interface PrimitiveIterator implements java.util.Iterator {
    -+  public abstract interface PrimitiveIterator<T, T_CONS> implements java.util.Iterator {
    -     method public abstract void forEachRemaining(T_CONS);
    -   }
    - 
    -@@ -58714,7 +58723,7 @@ package java.util {
    -     method public abstract long nextLong();
    -   }
    - 
    --  public class PriorityQueue extends java.util.AbstractQueue implements java.io.Serializable {
    -+  public class PriorityQueue<E> extends java.util.AbstractQueue implements java.io.Serializable {
    -     ctor public PriorityQueue();
    -     ctor public PriorityQueue(int);
    -     ctor public PriorityQueue(java.util.Comparator<? super E>);
    -@@ -58763,7 +58772,7 @@ package java.util {
    -     method public java.lang.Object handleGetObject(java.lang.String);
    -   }
    - 
    --  public abstract interface Queue implements java.util.Collection {
    -+  public abstract interface Queue<E> implements java.util.Collection {
    -     method public abstract boolean add(E);
    -     method public abstract E element();
    -     method public abstract boolean offer(E);
    -@@ -58913,15 +58922,15 @@ package java.util {
    -     ctor public ServiceConfigurationError(java.lang.String, java.lang.Throwable);
    -   }
    - 
    --  public final class ServiceLoader implements java.lang.Iterable {
    -+  public final class ServiceLoader<S> implements java.lang.Iterable {
    -     method public java.util.Iterator<S> iterator();
    --    method public static java.util.ServiceLoader<S> load(java.lang.Class<S>, java.lang.ClassLoader);
    --    method public static java.util.ServiceLoader<S> load(java.lang.Class<S>);
    --    method public static java.util.ServiceLoader<S> loadInstalled(java.lang.Class<S>);
    -+    method public static <S> java.util.ServiceLoader<S> load(java.lang.Class<S>, java.lang.ClassLoader);
    -+    method public static <S> java.util.ServiceLoader<S> load(java.lang.Class<S>);
    -+    method public static <S> java.util.ServiceLoader<S> loadInstalled(java.lang.Class<S>);
    -     method public void reload();
    -   }
    - 
    --  public abstract interface Set implements java.util.Collection {
    -+  public abstract interface Set<E> implements java.util.Collection {
    -     method public abstract boolean add(E);
    -     method public abstract boolean addAll(java.util.Collection<? extends E>);
    -     method public abstract void clear();
    -@@ -58936,7 +58945,7 @@ package java.util {
    -     method public abstract boolean retainAll(java.util.Collection<?>);
    -     method public abstract int size();
    -     method public abstract java.lang.Object[] toArray();
    --    method public abstract T[] toArray(T[]);
    -+    method public abstract <T> T[] toArray(T[]);
    -   }
    - 
    -   public class SimpleTimeZone extends java.util.TimeZone {
    -@@ -58962,7 +58971,7 @@ package java.util {
    -     field public static final int WALL_TIME = 0; // 0x0
    -   }
    - 
    --  public abstract interface SortedMap implements java.util.Map {
    -+  public abstract interface SortedMap<K, V> implements java.util.Map {
    -     method public abstract java.util.Comparator<? super K> comparator();
    -     method public abstract java.util.Set<java.util.Map.Entry<K, V>> entrySet();
    -     method public abstract K firstKey();
    -@@ -58974,7 +58983,7 @@ package java.util {
    -     method public abstract java.util.Collection<V> values();
    -   }
    - 
    --  public abstract interface SortedSet implements java.util.Set {
    -+  public abstract interface SortedSet<E> implements java.util.Set {
    -     method public abstract java.util.Comparator<? super E> comparator();
    -     method public abstract E first();
    -     method public abstract java.util.SortedSet<E> headSet(E);
    -@@ -58983,7 +58992,7 @@ package java.util {
    -     method public abstract java.util.SortedSet<E> tailSet(E);
    -   }
    - 
    --  public abstract interface Spliterator {
    -+  public abstract interface Spliterator<T> {
    -     method public abstract int characteristics();
    -     method public abstract long estimateSize();
    -     method public default void forEachRemaining(java.util.function.Consumer<? super T>);
    -@@ -59026,7 +59035,7 @@ package java.util {
    -     method public abstract java.util.Spliterator.OfLong trySplit();
    -   }
    - 
    --  public static abstract interface Spliterator.OfPrimitive implements java.util.Spliterator {
    -+  public static abstract interface Spliterator.OfPrimitive<T, T_CONS, T_SPLITR extends java.util.Spliterator.OfPrimitive<T, T_CONS, T_SPLITR>> implements java.util.Spliterator {
    -     method public default void forEachRemaining(T_CONS);
    -     method public abstract boolean tryAdvance(T_CONS);
    -     method public abstract T_SPLITR trySplit();
    -@@ -59036,25 +59045,25 @@ package java.util {
    -     method public static java.util.Spliterator.OfDouble emptyDoubleSpliterator();
    -     method public static java.util.Spliterator.OfInt emptyIntSpliterator();
    -     method public static java.util.Spliterator.OfLong emptyLongSpliterator();
    --    method public static java.util.Spliterator<T> emptySpliterator();
    --    method public static java.util.Iterator<T> iterator(java.util.Spliterator<? extends T>);
    -+    method public static <T> java.util.Spliterator<T> emptySpliterator();
    -+    method public static <T> java.util.Iterator<T> iterator(java.util.Spliterator<? extends T>);
    -     method public static java.util.PrimitiveIterator.OfInt iterator(java.util.Spliterator.OfInt);
    -     method public static java.util.PrimitiveIterator.OfLong iterator(java.util.Spliterator.OfLong);
    -     method public static java.util.PrimitiveIterator.OfDouble iterator(java.util.Spliterator.OfDouble);
    --    method public static java.util.Spliterator<T> spliterator(java.lang.Object[], int);
    --    method public static java.util.Spliterator<T> spliterator(java.lang.Object[], int, int, int);
    -+    method public static <T> java.util.Spliterator<T> spliterator(java.lang.Object[], int);
    -+    method public static <T> java.util.Spliterator<T> spliterator(java.lang.Object[], int, int, int);
    -     method public static java.util.Spliterator.OfInt spliterator(int[], int);
    -     method public static java.util.Spliterator.OfInt spliterator(int[], int, int, int);
    -     method public static java.util.Spliterator.OfLong spliterator(long[], int);
    -     method public static java.util.Spliterator.OfLong spliterator(long[], int, int, int);
    -     method public static java.util.Spliterator.OfDouble spliterator(double[], int);
    -     method public static java.util.Spliterator.OfDouble spliterator(double[], int, int, int);
    --    method public static java.util.Spliterator<T> spliterator(java.util.Collection<? extends T>, int);
    --    method public static java.util.Spliterator<T> spliterator(java.util.Iterator<? extends T>, long, int);
    -+    method public static <T> java.util.Spliterator<T> spliterator(java.util.Collection<? extends T>, int);
    -+    method public static <T> java.util.Spliterator<T> spliterator(java.util.Iterator<? extends T>, long, int);
    -     method public static java.util.Spliterator.OfInt spliterator(java.util.PrimitiveIterator.OfInt, long, int);
    -     method public static java.util.Spliterator.OfLong spliterator(java.util.PrimitiveIterator.OfLong, long, int);
    -     method public static java.util.Spliterator.OfDouble spliterator(java.util.PrimitiveIterator.OfDouble, long, int);
    --    method public static java.util.Spliterator<T> spliteratorUnknownSize(java.util.Iterator<? extends T>, int);
    -+    method public static <T> java.util.Spliterator<T> spliteratorUnknownSize(java.util.Iterator<? extends T>, int);
    -     method public static java.util.Spliterator.OfInt spliteratorUnknownSize(java.util.PrimitiveIterator.OfInt, int);
    -     method public static java.util.Spliterator.OfLong spliteratorUnknownSize(java.util.PrimitiveIterator.OfLong, int);
    -     method public static java.util.Spliterator.OfDouble spliteratorUnknownSize(java.util.PrimitiveIterator.OfDouble, int);
    -@@ -59081,7 +59090,7 @@ package java.util {
    -     method public java.util.Spliterator.OfLong trySplit();
    -   }
    - 
    --  public static abstract class Spliterators.AbstractSpliterator implements java.util.Spliterator {
    -+  public static abstract class Spliterators.AbstractSpliterator<T> implements java.util.Spliterator {
    -     ctor protected Spliterators.AbstractSpliterator(long, int);
    -     method public int characteristics();
    -     method public long estimateSize();
    -@@ -59116,7 +59125,7 @@ package java.util {
    -     method public java.util.SplittableRandom split();
    -   }
    - 
    --  public class Stack extends java.util.Vector {
    -+  public class Stack<E> extends java.util.Vector {
    -     ctor public Stack();
    -     method public boolean empty();
    -     method public synchronized E peek();
    -@@ -59200,7 +59209,7 @@ package java.util {
    -     ctor public TooManyListenersException(java.lang.String);
    -   }
    - 
    --  public class TreeMap extends java.util.AbstractMap implements java.lang.Cloneable java.util.NavigableMap java.io.Serializable {
    -+  public class TreeMap<K, V> extends java.util.AbstractMap implements java.lang.Cloneable java.util.NavigableMap java.io.Serializable {
    -     ctor public TreeMap();
    -     ctor public TreeMap(java.util.Comparator<? super K>);
    -     ctor public TreeMap(java.util.Map<? extends K, ? extends V>);
    -@@ -59237,7 +59246,7 @@ package java.util {
    -     method public java.util.SortedMap<K, V> tailMap(K);
    -   }
    - 
    --  public class TreeSet extends java.util.AbstractSet implements java.lang.Cloneable java.util.NavigableSet java.io.Serializable {
    -+  public class TreeSet<E> extends java.util.AbstractSet implements java.lang.Cloneable java.util.NavigableSet java.io.Serializable {
    -     ctor public TreeSet();
    -     ctor public TreeSet(java.util.Comparator<? super E>);
    -     ctor public TreeSet(java.util.Collection<? extends E>);
    -@@ -59290,7 +59299,7 @@ package java.util {
    -     method public java.lang.String getFlags();
    -   }
    - 
    --  public class Vector extends java.util.AbstractList implements java.lang.Cloneable java.util.List java.util.RandomAccess java.io.Serializable {
    -+  public class Vector<E> extends java.util.AbstractList implements java.lang.Cloneable java.util.List java.util.RandomAccess java.io.Serializable {
    -     ctor public Vector(int, int);
    -     ctor public Vector(int);
    -     ctor public Vector();
    -@@ -59325,7 +59334,7 @@ package java.util {
    -     field protected java.lang.Object[] elementData;
    -   }
    - 
    --  public class WeakHashMap extends java.util.AbstractMap implements java.util.Map {
    -+  public class WeakHashMap<K, V> extends java.util.AbstractMap implements java.util.Map {
    -     ctor public WeakHashMap(int, float);
    -     ctor public WeakHashMap(int);
    -     ctor public WeakHashMap();
    -@@ -59341,18 +59350,18 @@ package java.util.concurrent {
    - 
    -   public abstract class AbstractExecutorService implements java.util.concurrent.ExecutorService {
    -     ctor public AbstractExecutorService();
    --    method public java.util.List<java.util.concurrent.Future<T>> invokeAll(java.util.Collection<? extends java.util.concurrent.Callable<T>>) throws java.lang.InterruptedException;
    --    method public java.util.List<java.util.concurrent.Future<T>> invokeAll(java.util.Collection<? extends java.util.concurrent.Callable<T>>, long, java.util.concurrent.TimeUnit) throws java.lang.InterruptedException;
    --    method public T invokeAny(java.util.Collection<? extends java.util.concurrent.Callable<T>>) throws java.util.concurrent.ExecutionException, java.lang.InterruptedException;
    --    method public T invokeAny(java.util.Collection<? extends java.util.concurrent.Callable<T>>, long, java.util.concurrent.TimeUnit) throws java.util.concurrent.ExecutionException, java.lang.InterruptedException, java.util.concurrent.TimeoutException;
    --    method protected java.util.concurrent.RunnableFuture<T> newTaskFor(java.lang.Runnable, T);
    --    method protected java.util.concurrent.RunnableFuture<T> newTaskFor(java.util.concurrent.Callable<T>);
    -+    method public <T> java.util.List<java.util.concurrent.Future<T>> invokeAll(java.util.Collection<? extends java.util.concurrent.Callable<T>>) throws java.lang.InterruptedException;
    -+    method public <T> java.util.List<java.util.concurrent.Future<T>> invokeAll(java.util.Collection<? extends java.util.concurrent.Callable<T>>, long, java.util.concurrent.TimeUnit) throws java.lang.InterruptedException;
    -+    method public <T> T invokeAny(java.util.Collection<? extends java.util.concurrent.Callable<T>>) throws java.util.concurrent.ExecutionException, java.lang.InterruptedException;
    -+    method public <T> T invokeAny(java.util.Collection<? extends java.util.concurrent.Callable<T>>, long, java.util.concurrent.TimeUnit) throws java.util.concurrent.ExecutionException, java.lang.InterruptedException, java.util.concurrent.TimeoutException;
    -+    method protected <T> java.util.concurrent.RunnableFuture<T> newTaskFor(java.lang.Runnable, T);
    -+    method protected <T> java.util.concurrent.RunnableFuture<T> newTaskFor(java.util.concurrent.Callable<T>);
    -     method public java.util.concurrent.Future<?> submit(java.lang.Runnable);
    --    method public java.util.concurrent.Future<T> submit(java.lang.Runnable, T);
    --    method public java.util.concurrent.Future<T> submit(java.util.concurrent.Callable<T>);
    -+    method public <T> java.util.concurrent.Future<T> submit(java.lang.Runnable, T);
    -+    method public <T> java.util.concurrent.Future<T> submit(java.util.concurrent.Callable<T>);
    -   }
    - 
    --  public class ArrayBlockingQueue extends java.util.AbstractQueue implements java.util.concurrent.BlockingQueue java.io.Serializable {
    -+  public class ArrayBlockingQueue<E> extends java.util.AbstractQueue implements java.util.concurrent.BlockingQueue java.io.Serializable {
    -     ctor public ArrayBlockingQueue(int);
    -     ctor public ArrayBlockingQueue(int, boolean);
    -     ctor public ArrayBlockingQueue(int, boolean, java.util.Collection<? extends E>);
    -@@ -59371,7 +59380,7 @@ package java.util.concurrent {
    -     method public E take() throws java.lang.InterruptedException;
    -   }
    - 
    --  public abstract interface BlockingDeque implements java.util.concurrent.BlockingQueue java.util.Deque {
    -+  public abstract interface BlockingDeque<E> implements java.util.concurrent.BlockingQueue java.util.Deque {
    -     method public abstract boolean add(E);
    -     method public abstract void addFirst(E);
    -     method public abstract void addLast(E);
    -@@ -59403,7 +59412,7 @@ package java.util.concurrent {
    -     method public abstract E takeLast() throws java.lang.InterruptedException;
    -   }
    - 
    --  public abstract interface BlockingQueue implements java.util.Queue {
    -+  public abstract interface BlockingQueue<E> implements java.util.Queue {
    -     method public abstract boolean add(E);
    -     method public abstract boolean contains(java.lang.Object);
    -     method public abstract int drainTo(java.util.Collection<? super E>);
    -@@ -59422,7 +59431,7 @@ package java.util.concurrent {
    -     ctor public BrokenBarrierException(java.lang.String);
    -   }
    - 
    --  public abstract interface Callable {
    -+  public abstract interface Callable<V> {
    -     method public abstract V call() throws java.lang.Exception;
    -   }
    - 
    -@@ -59431,28 +59440,28 @@ package java.util.concurrent {
    -     ctor public CancellationException(java.lang.String);
    -   }
    - 
    --  public class CompletableFuture implements java.util.concurrent.CompletionStage java.util.concurrent.Future {
    -+  public class CompletableFuture<T> implements java.util.concurrent.CompletionStage java.util.concurrent.Future {
    -     ctor public CompletableFuture();
    -     method public java.util.concurrent.CompletableFuture<java.lang.Void> acceptEither(java.util.concurrent.CompletionStage<? extends T>, java.util.function.Consumer<? super T>);
    -     method public java.util.concurrent.CompletableFuture<java.lang.Void> acceptEitherAsync(java.util.concurrent.CompletionStage<? extends T>, java.util.function.Consumer<? super T>);
    -     method public java.util.concurrent.CompletableFuture<java.lang.Void> acceptEitherAsync(java.util.concurrent.CompletionStage<? extends T>, java.util.function.Consumer<? super T>, java.util.concurrent.Executor);
    -     method public static java.util.concurrent.CompletableFuture<java.lang.Void> allOf(java.util.concurrent.CompletableFuture<?>...);
    -     method public static java.util.concurrent.CompletableFuture<java.lang.Object> anyOf(java.util.concurrent.CompletableFuture<?>...);
    --    method public java.util.concurrent.CompletableFuture<U> applyToEither(java.util.concurrent.CompletionStage<? extends T>, java.util.function.Function<? super T, U>);
    --    method public java.util.concurrent.CompletableFuture<U> applyToEitherAsync(java.util.concurrent.CompletionStage<? extends T>, java.util.function.Function<? super T, U>);
    --    method public java.util.concurrent.CompletableFuture<U> applyToEitherAsync(java.util.concurrent.CompletionStage<? extends T>, java.util.function.Function<? super T, U>, java.util.concurrent.Executor);
    -+    method public <U> java.util.concurrent.CompletableFuture<U> applyToEither(java.util.concurrent.CompletionStage<? extends T>, java.util.function.Function<? super T, U>);
    -+    method public <U> java.util.concurrent.CompletableFuture<U> applyToEitherAsync(java.util.concurrent.CompletionStage<? extends T>, java.util.function.Function<? super T, U>);
    -+    method public <U> java.util.concurrent.CompletableFuture<U> applyToEitherAsync(java.util.concurrent.CompletionStage<? extends T>, java.util.function.Function<? super T, U>, java.util.concurrent.Executor);
    -     method public boolean cancel(boolean);
    -     method public boolean complete(T);
    -     method public boolean completeExceptionally(java.lang.Throwable);
    --    method public static java.util.concurrent.CompletableFuture<U> completedFuture(U);
    -+    method public static <U> java.util.concurrent.CompletableFuture<U> completedFuture(U);
    -     method public java.util.concurrent.CompletableFuture<T> exceptionally(java.util.function.Function<java.lang.Throwable, ? extends T>);
    -     method public T get() throws java.util.concurrent.ExecutionException, java.lang.InterruptedException;
    -     method public T get(long, java.util.concurrent.TimeUnit) throws java.util.concurrent.ExecutionException, java.lang.InterruptedException, java.util.concurrent.TimeoutException;
    -     method public T getNow(T);
    -     method public int getNumberOfDependents();
    --    method public java.util.concurrent.CompletableFuture<U> handle(java.util.function.BiFunction<? super T, java.lang.Throwable, ? extends U>);
    --    method public java.util.concurrent.CompletableFuture<U> handleAsync(java.util.function.BiFunction<? super T, java.lang.Throwable, ? extends U>);
    --    method public java.util.concurrent.CompletableFuture<U> handleAsync(java.util.function.BiFunction<? super T, java.lang.Throwable, ? extends U>, java.util.concurrent.Executor);
    -+    method public <U> java.util.concurrent.CompletableFuture<U> handle(java.util.function.BiFunction<? super T, java.lang.Throwable, ? extends U>);
    -+    method public <U> java.util.concurrent.CompletableFuture<U> handleAsync(java.util.function.BiFunction<? super T, java.lang.Throwable, ? extends U>);
    -+    method public <U> java.util.concurrent.CompletableFuture<U> handleAsync(java.util.function.BiFunction<? super T, java.lang.Throwable, ? extends U>, java.util.concurrent.Executor);
    -     method public boolean isCancelled();
    -     method public boolean isCompletedExceptionally();
    -     method public boolean isDone();
    -@@ -59467,23 +59476,23 @@ package java.util.concurrent {
    -     method public java.util.concurrent.CompletableFuture<java.lang.Void> runAfterEitherAsync(java.util.concurrent.CompletionStage<?>, java.lang.Runnable, java.util.concurrent.Executor);
    -     method public static java.util.concurrent.CompletableFuture<java.lang.Void> runAsync(java.lang.Runnable);
    -     method public static java.util.concurrent.CompletableFuture<java.lang.Void> runAsync(java.lang.Runnable, java.util.concurrent.Executor);
    --    method public static java.util.concurrent.CompletableFuture<U> supplyAsync(java.util.function.Supplier<U>);
    --    method public static java.util.concurrent.CompletableFuture<U> supplyAsync(java.util.function.Supplier<U>, java.util.concurrent.Executor);
    -+    method public static <U> java.util.concurrent.CompletableFuture<U> supplyAsync(java.util.function.Supplier<U>);
    -+    method public static <U> java.util.concurrent.CompletableFuture<U> supplyAsync(java.util.function.Supplier<U>, java.util.concurrent.Executor);
    -     method public java.util.concurrent.CompletableFuture<java.lang.Void> thenAccept(java.util.function.Consumer<? super T>);
    -     method public java.util.concurrent.CompletableFuture<java.lang.Void> thenAcceptAsync(java.util.function.Consumer<? super T>);
    -     method public java.util.concurrent.CompletableFuture<java.lang.Void> thenAcceptAsync(java.util.function.Consumer<? super T>, java.util.concurrent.Executor);
    --    method public java.util.concurrent.CompletableFuture<java.lang.Void> thenAcceptBoth(java.util.concurrent.CompletionStage<? extends U>, java.util.function.BiConsumer<? super T, ? super U>);
    --    method public java.util.concurrent.CompletableFuture<java.lang.Void> thenAcceptBothAsync(java.util.concurrent.CompletionStage<? extends U>, java.util.function.BiConsumer<? super T, ? super U>);
    --    method public java.util.concurrent.CompletableFuture<java.lang.Void> thenAcceptBothAsync(java.util.concurrent.CompletionStage<? extends U>, java.util.function.BiConsumer<? super T, ? super U>, java.util.concurrent.Executor);
    --    method public java.util.concurrent.CompletableFuture<U> thenApply(java.util.function.Function<? super T, ? extends U>);
    --    method public java.util.concurrent.CompletableFuture<U> thenApplyAsync(java.util.function.Function<? super T, ? extends U>);
    --    method public java.util.concurrent.CompletableFuture<U> thenApplyAsync(java.util.function.Function<? super T, ? extends U>, java.util.concurrent.Executor);
    --    method public java.util.concurrent.CompletableFuture<V> thenCombine(java.util.concurrent.CompletionStage<? extends U>, java.util.function.BiFunction<? super T, ? super U, ? extends V>);
    --    method public java.util.concurrent.CompletableFuture<V> thenCombineAsync(java.util.concurrent.CompletionStage<? extends U>, java.util.function.BiFunction<? super T, ? super U, ? extends V>);
    --    method public java.util.concurrent.CompletableFuture<V> thenCombineAsync(java.util.concurrent.CompletionStage<? extends U>, java.util.function.BiFunction<? super T, ? super U, ? extends V>, java.util.concurrent.Executor);
    --    method public java.util.concurrent.CompletableFuture<U> thenCompose(java.util.function.Function<? super T, ? extends java.util.concurrent.CompletionStage<U>>);
    --    method public java.util.concurrent.CompletableFuture<U> thenComposeAsync(java.util.function.Function<? super T, ? extends java.util.concurrent.CompletionStage<U>>);
    --    method public java.util.concurrent.CompletableFuture<U> thenComposeAsync(java.util.function.Function<? super T, ? extends java.util.concurrent.CompletionStage<U>>, java.util.concurrent.Executor);
    -+    method public <U> java.util.concurrent.CompletableFuture<java.lang.Void> thenAcceptBoth(java.util.concurrent.CompletionStage<? extends U>, java.util.function.BiConsumer<? super T, ? super U>);
    -+    method public <U> java.util.concurrent.CompletableFuture<java.lang.Void> thenAcceptBothAsync(java.util.concurrent.CompletionStage<? extends U>, java.util.function.BiConsumer<? super T, ? super U>);
    -+    method public <U> java.util.concurrent.CompletableFuture<java.lang.Void> thenAcceptBothAsync(java.util.concurrent.CompletionStage<? extends U>, java.util.function.BiConsumer<? super T, ? super U>, java.util.concurrent.Executor);
    -+    method public <U> java.util.concurrent.CompletableFuture<U> thenApply(java.util.function.Function<? super T, ? extends U>);
    -+    method public <U> java.util.concurrent.CompletableFuture<U> thenApplyAsync(java.util.function.Function<? super T, ? extends U>);
    -+    method public <U> java.util.concurrent.CompletableFuture<U> thenApplyAsync(java.util.function.Function<? super T, ? extends U>, java.util.concurrent.Executor);
    -+    method public <U, V> java.util.concurrent.CompletableFuture<V> thenCombine(java.util.concurrent.CompletionStage<? extends U>, java.util.function.BiFunction<? super T, ? super U, ? extends V>);
    -+    method public <U, V> java.util.concurrent.CompletableFuture<V> thenCombineAsync(java.util.concurrent.CompletionStage<? extends U>, java.util.function.BiFunction<? super T, ? super U, ? extends V>);
    -+    method public <U, V> java.util.concurrent.CompletableFuture<V> thenCombineAsync(java.util.concurrent.CompletionStage<? extends U>, java.util.function.BiFunction<? super T, ? super U, ? extends V>, java.util.concurrent.Executor);
    -+    method public <U> java.util.concurrent.CompletableFuture<U> thenCompose(java.util.function.Function<? super T, ? extends java.util.concurrent.CompletionStage<U>>);
    -+    method public <U> java.util.concurrent.CompletableFuture<U> thenComposeAsync(java.util.function.Function<? super T, ? extends java.util.concurrent.CompletionStage<U>>);
    -+    method public <U> java.util.concurrent.CompletableFuture<U> thenComposeAsync(java.util.function.Function<? super T, ? extends java.util.concurrent.CompletionStage<U>>, java.util.concurrent.Executor);
    -     method public java.util.concurrent.CompletableFuture<java.lang.Void> thenRun(java.lang.Runnable);
    -     method public java.util.concurrent.CompletableFuture<java.lang.Void> thenRunAsync(java.lang.Runnable);
    -     method public java.util.concurrent.CompletableFuture<java.lang.Void> thenRunAsync(java.lang.Runnable, java.util.concurrent.Executor);
    -@@ -59503,7 +59512,7 @@ package java.util.concurrent {
    -     ctor public CompletionException(java.lang.Throwable);
    -   }
    - 
    --  public abstract interface CompletionService {
    -+  public abstract interface CompletionService<V> {
    -     method public abstract java.util.concurrent.Future<V> poll();
    -     method public abstract java.util.concurrent.Future<V> poll(long, java.util.concurrent.TimeUnit) throws java.lang.InterruptedException;
    -     method public abstract java.util.concurrent.Future<V> submit(java.util.concurrent.Callable<V>);
    -@@ -59511,17 +59520,17 @@ package java.util.concurrent {
    -     method public abstract java.util.concurrent.Future<V> take() throws java.lang.InterruptedException;
    -   }
    - 
    --  public abstract interface CompletionStage {
    -+  public abstract interface CompletionStage<T> {
    -     method public abstract java.util.concurrent.CompletionStage<java.lang.Void> acceptEither(java.util.concurrent.CompletionStage<? extends T>, java.util.function.Consumer<? super T>);
    -     method public abstract java.util.concurrent.CompletionStage<java.lang.Void> acceptEitherAsync(java.util.concurrent.CompletionStage<? extends T>, java.util.function.Consumer<? super T>);
    -     method public abstract java.util.concurrent.CompletionStage<java.lang.Void> acceptEitherAsync(java.util.concurrent.CompletionStage<? extends T>, java.util.function.Consumer<? super T>, java.util.concurrent.Executor);
    --    method public abstract java.util.concurrent.CompletionStage<U> applyToEither(java.util.concurrent.CompletionStage<? extends T>, java.util.function.Function<? super T, U>);
    --    method public abstract java.util.concurrent.CompletionStage<U> applyToEitherAsync(java.util.concurrent.CompletionStage<? extends T>, java.util.function.Function<? super T, U>);
    --    method public abstract java.util.concurrent.CompletionStage<U> applyToEitherAsync(java.util.concurrent.CompletionStage<? extends T>, java.util.function.Function<? super T, U>, java.util.concurrent.Executor);
    -+    method public abstract <U> java.util.concurrent.CompletionStage<U> applyToEither(java.util.concurrent.CompletionStage<? extends T>, java.util.function.Function<? super T, U>);
    -+    method public abstract <U> java.util.concurrent.CompletionStage<U> applyToEitherAsync(java.util.concurrent.CompletionStage<? extends T>, java.util.function.Function<? super T, U>);
    -+    method public abstract <U> java.util.concurrent.CompletionStage<U> applyToEitherAsync(java.util.concurrent.CompletionStage<? extends T>, java.util.function.Function<? super T, U>, java.util.concurrent.Executor);
    -     method public abstract java.util.concurrent.CompletionStage<T> exceptionally(java.util.function.Function<java.lang.Throwable, ? extends T>);
    --    method public abstract java.util.concurrent.CompletionStage<U> handle(java.util.function.BiFunction<? super T, java.lang.Throwable, ? extends U>);
    --    method public abstract java.util.concurrent.CompletionStage<U> handleAsync(java.util.function.BiFunction<? super T, java.lang.Throwable, ? extends U>);
    --    method public abstract java.util.concurrent.CompletionStage<U> handleAsync(java.util.function.BiFunction<? super T, java.lang.Throwable, ? extends U>, java.util.concurrent.Executor);
    -+    method public abstract <U> java.util.concurrent.CompletionStage<U> handle(java.util.function.BiFunction<? super T, java.lang.Throwable, ? extends U>);
    -+    method public abstract <U> java.util.concurrent.CompletionStage<U> handleAsync(java.util.function.BiFunction<? super T, java.lang.Throwable, ? extends U>);
    -+    method public abstract <U> java.util.concurrent.CompletionStage<U> handleAsync(java.util.function.BiFunction<? super T, java.lang.Throwable, ? extends U>, java.util.concurrent.Executor);
    -     method public abstract java.util.concurrent.CompletionStage<java.lang.Void> runAfterBoth(java.util.concurrent.CompletionStage<?>, java.lang.Runnable);
    -     method public abstract java.util.concurrent.CompletionStage<java.lang.Void> runAfterBothAsync(java.util.concurrent.CompletionStage<?>, java.lang.Runnable);
    -     method public abstract java.util.concurrent.CompletionStage<java.lang.Void> runAfterBothAsync(java.util.concurrent.CompletionStage<?>, java.lang.Runnable, java.util.concurrent.Executor);
    -@@ -59531,18 +59540,18 @@ package java.util.concurrent {
    -     method public abstract java.util.concurrent.CompletionStage<java.lang.Void> thenAccept(java.util.function.Consumer<? super T>);
    -     method public abstract java.util.concurrent.CompletionStage<java.lang.Void> thenAcceptAsync(java.util.function.Consumer<? super T>);
    -     method public abstract java.util.concurrent.CompletionStage<java.lang.Void> thenAcceptAsync(java.util.function.Consumer<? super T>, java.util.concurrent.Executor);
    --    method public abstract java.util.concurrent.CompletionStage<java.lang.Void> thenAcceptBoth(java.util.concurrent.CompletionStage<? extends U>, java.util.function.BiConsumer<? super T, ? super U>);
    --    method public abstract java.util.concurrent.CompletionStage<java.lang.Void> thenAcceptBothAsync(java.util.concurrent.CompletionStage<? extends U>, java.util.function.BiConsumer<? super T, ? super U>);
    --    method public abstract java.util.concurrent.CompletionStage<java.lang.Void> thenAcceptBothAsync(java.util.concurrent.CompletionStage<? extends U>, java.util.function.BiConsumer<? super T, ? super U>, java.util.concurrent.Executor);
    --    method public abstract java.util.concurrent.CompletionStage<U> thenApply(java.util.function.Function<? super T, ? extends U>);
    --    method public abstract java.util.concurrent.CompletionStage<U> thenApplyAsync(java.util.function.Function<? super T, ? extends U>);
    --    method public abstract java.util.concurrent.CompletionStage<U> thenApplyAsync(java.util.function.Function<? super T, ? extends U>, java.util.concurrent.Executor);
    --    method public abstract java.util.concurrent.CompletionStage<V> thenCombine(java.util.concurrent.CompletionStage<? extends U>, java.util.function.BiFunction<? super T, ? super U, ? extends V>);
    --    method public abstract java.util.concurrent.CompletionStage<V> thenCombineAsync(java.util.concurrent.CompletionStage<? extends U>, java.util.function.BiFunction<? super T, ? super U, ? extends V>);
    --    method public abstract java.util.concurrent.CompletionStage<V> thenCombineAsync(java.util.concurrent.CompletionStage<? extends U>, java.util.function.BiFunction<? super T, ? super U, ? extends V>, java.util.concurrent.Executor);
    --    method public abstract java.util.concurrent.CompletionStage<U> thenCompose(java.util.function.Function<? super T, ? extends java.util.concurrent.CompletionStage<U>>);
    --    method public abstract java.util.concurrent.CompletionStage<U> thenComposeAsync(java.util.function.Function<? super T, ? extends java.util.concurrent.CompletionStage<U>>);
    --    method public abstract java.util.concurrent.CompletionStage<U> thenComposeAsync(java.util.function.Function<? super T, ? extends java.util.concurrent.CompletionStage<U>>, java.util.concurrent.Executor);
    -+    method public abstract <U> java.util.concurrent.CompletionStage<java.lang.Void> thenAcceptBoth(java.util.concurrent.CompletionStage<? extends U>, java.util.function.BiConsumer<? super T, ? super U>);
    -+    method public abstract <U> java.util.concurrent.CompletionStage<java.lang.Void> thenAcceptBothAsync(java.util.concurrent.CompletionStage<? extends U>, java.util.function.BiConsumer<? super T, ? super U>);
    -+    method public abstract <U> java.util.concurrent.CompletionStage<java.lang.Void> thenAcceptBothAsync(java.util.concurrent.CompletionStage<? extends U>, java.util.function.BiConsumer<? super T, ? super U>, java.util.concurrent.Executor);
    -+    method public abstract <U> java.util.concurrent.CompletionStage<U> thenApply(java.util.function.Function<? super T, ? extends U>);
    -+    method public abstract <U> java.util.concurrent.CompletionStage<U> thenApplyAsync(java.util.function.Function<? super T, ? extends U>);
    -+    method public abstract <U> java.util.concurrent.CompletionStage<U> thenApplyAsync(java.util.function.Function<? super T, ? extends U>, java.util.concurrent.Executor);
    -+    method public abstract <U, V> java.util.concurrent.CompletionStage<V> thenCombine(java.util.concurrent.CompletionStage<? extends U>, java.util.function.BiFunction<? super T, ? super U, ? extends V>);
    -+    method public abstract <U, V> java.util.concurrent.CompletionStage<V> thenCombineAsync(java.util.concurrent.CompletionStage<? extends U>, java.util.function.BiFunction<? super T, ? super U, ? extends V>);
    -+    method public abstract <U, V> java.util.concurrent.CompletionStage<V> thenCombineAsync(java.util.concurrent.CompletionStage<? extends U>, java.util.function.BiFunction<? super T, ? super U, ? extends V>, java.util.concurrent.Executor);
    -+    method public abstract <U> java.util.concurrent.CompletionStage<U> thenCompose(java.util.function.Function<? super T, ? extends java.util.concurrent.CompletionStage<U>>);
    -+    method public abstract <U> java.util.concurrent.CompletionStage<U> thenComposeAsync(java.util.function.Function<? super T, ? extends java.util.concurrent.CompletionStage<U>>);
    -+    method public abstract <U> java.util.concurrent.CompletionStage<U> thenComposeAsync(java.util.function.Function<? super T, ? extends java.util.concurrent.CompletionStage<U>>, java.util.concurrent.Executor);
    -     method public abstract java.util.concurrent.CompletionStage<java.lang.Void> thenRun(java.lang.Runnable);
    -     method public abstract java.util.concurrent.CompletionStage<java.lang.Void> thenRunAsync(java.lang.Runnable);
    -     method public abstract java.util.concurrent.CompletionStage<java.lang.Void> thenRunAsync(java.lang.Runnable, java.util.concurrent.Executor);
    -@@ -59552,7 +59561,7 @@ package java.util.concurrent {
    -     method public abstract java.util.concurrent.CompletionStage<T> whenCompleteAsync(java.util.function.BiConsumer<? super T, ? super java.lang.Throwable>, java.util.concurrent.Executor);
    -   }
    - 
    --  public class ConcurrentHashMap extends java.util.AbstractMap implements java.util.concurrent.ConcurrentMap java.io.Serializable {
    -+  public class ConcurrentHashMap<K, V> extends java.util.AbstractMap implements java.util.concurrent.ConcurrentMap java.io.Serializable {
    -     ctor public ConcurrentHashMap();
    -     ctor public ConcurrentHashMap(int);
    -     ctor public ConcurrentHashMap(java.util.Map<? extends K, ? extends V>);
    -@@ -59566,29 +59575,29 @@ package java.util.concurrent {
    -     method public java.util.Set<java.util.Map.Entry<K, V>> entrySet();
    -     method public void forEach(java.util.function.BiConsumer<? super K, ? super V>);
    -     method public void forEach(long, java.util.function.BiConsumer<? super K, ? super V>);
    --    method public void forEach(long, java.util.function.BiFunction<? super K, ? super V, ? extends U>, java.util.function.Consumer<? super U>);
    -+    method public <U> void forEach(long, java.util.function.BiFunction<? super K, ? super V, ? extends U>, java.util.function.Consumer<? super U>);
    -     method public void forEachEntry(long, java.util.function.Consumer<? super java.util.Map.Entry<K, V>>);
    --    method public void forEachEntry(long, java.util.function.Function<java.util.Map.Entry<K, V>, ? extends U>, java.util.function.Consumer<? super U>);
    -+    method public <U> void forEachEntry(long, java.util.function.Function<java.util.Map.Entry<K, V>, ? extends U>, java.util.function.Consumer<? super U>);
    -     method public void forEachKey(long, java.util.function.Consumer<? super K>);
    --    method public void forEachKey(long, java.util.function.Function<? super K, ? extends U>, java.util.function.Consumer<? super U>);
    -+    method public <U> void forEachKey(long, java.util.function.Function<? super K, ? extends U>, java.util.function.Consumer<? super U>);
    -     method public void forEachValue(long, java.util.function.Consumer<? super V>);
    --    method public void forEachValue(long, java.util.function.Function<? super V, ? extends U>, java.util.function.Consumer<? super U>);
    -+    method public <U> void forEachValue(long, java.util.function.Function<? super V, ? extends U>, java.util.function.Consumer<? super U>);
    -     method public V getOrDefault(java.lang.Object, V);
    -     method public java.util.concurrent.ConcurrentHashMap.KeySetView<K, V> keySet(V);
    -     method public java.util.Enumeration<K> keys();
    -     method public long mappingCount();
    -     method public V merge(K, V, java.util.function.BiFunction<? super V, ? super V, ? extends V>);
    --    method public static java.util.concurrent.ConcurrentHashMap.KeySetView<K, java.lang.Boolean> newKeySet();
    --    method public static java.util.concurrent.ConcurrentHashMap.KeySetView<K, java.lang.Boolean> newKeySet(int);
    -+    method public static <K> java.util.concurrent.ConcurrentHashMap.KeySetView<K, java.lang.Boolean> newKeySet();
    -+    method public static <K> java.util.concurrent.ConcurrentHashMap.KeySetView<K, java.lang.Boolean> newKeySet(int);
    -     method public V putIfAbsent(K, V);
    --    method public U reduce(long, java.util.function.BiFunction<? super K, ? super V, ? extends U>, java.util.function.BiFunction<? super U, ? super U, ? extends U>);
    -+    method public <U> U reduce(long, java.util.function.BiFunction<? super K, ? super V, ? extends U>, java.util.function.BiFunction<? super U, ? super U, ? extends U>);
    -     method public java.util.Map.Entry<K, V> reduceEntries(long, java.util.function.BiFunction<java.util.Map.Entry<K, V>, java.util.Map.Entry<K, V>, ? extends java.util.Map.Entry<K, V>>);
    --    method public U reduceEntries(long, java.util.function.Function<java.util.Map.Entry<K, V>, ? extends U>, java.util.function.BiFunction<? super U, ? super U, ? extends U>);
    -+    method public <U> U reduceEntries(long, java.util.function.Function<java.util.Map.Entry<K, V>, ? extends U>, java.util.function.BiFunction<? super U, ? super U, ? extends U>);
    -     method public double reduceEntriesToDouble(long, java.util.function.ToDoubleFunction<java.util.Map.Entry<K, V>>, double, java.util.function.DoubleBinaryOperator);
    -     method public int reduceEntriesToInt(long, java.util.function.ToIntFunction<java.util.Map.Entry<K, V>>, int, java.util.function.IntBinaryOperator);
    -     method public long reduceEntriesToLong(long, java.util.function.ToLongFunction<java.util.Map.Entry<K, V>>, long, java.util.function.LongBinaryOperator);
    -     method public K reduceKeys(long, java.util.function.BiFunction<? super K, ? super K, ? extends K>);
    --    method public U reduceKeys(long, java.util.function.Function<? super K, ? extends U>, java.util.function.BiFunction<? super U, ? super U, ? extends U>);
    -+    method public <U> U reduceKeys(long, java.util.function.Function<? super K, ? extends U>, java.util.function.BiFunction<? super U, ? super U, ? extends U>);
    -     method public double reduceKeysToDouble(long, java.util.function.ToDoubleFunction<? super K>, double, java.util.function.DoubleBinaryOperator);
    -     method public int reduceKeysToInt(long, java.util.function.ToIntFunction<? super K>, int, java.util.function.IntBinaryOperator);
    -     method public long reduceKeysToLong(long, java.util.function.ToLongFunction<? super K>, long, java.util.function.LongBinaryOperator);
    -@@ -59596,7 +59605,7 @@ package java.util.concurrent {
    -     method public int reduceToInt(long, java.util.function.ToIntBiFunction<? super K, ? super V>, int, java.util.function.IntBinaryOperator);
    -     method public long reduceToLong(long, java.util.function.ToLongBiFunction<? super K, ? super V>, long, java.util.function.LongBinaryOperator);
    -     method public V reduceValues(long, java.util.function.BiFunction<? super V, ? super V, ? extends V>);
    --    method public U reduceValues(long, java.util.function.Function<? super V, ? extends U>, java.util.function.BiFunction<? super U, ? super U, ? extends U>);
    -+    method public <U> U reduceValues(long, java.util.function.Function<? super V, ? extends U>, java.util.function.BiFunction<? super U, ? super U, ? extends U>);
    -     method public double reduceValuesToDouble(long, java.util.function.ToDoubleFunction<? super V>, double, java.util.function.DoubleBinaryOperator);
    -     method public int reduceValuesToInt(long, java.util.function.ToIntFunction<? super V>, int, java.util.function.IntBinaryOperator);
    -     method public long reduceValuesToLong(long, java.util.function.ToLongFunction<? super V>, long, java.util.function.LongBinaryOperator);
    -@@ -59604,13 +59613,13 @@ package java.util.concurrent {
    -     method public boolean replace(K, V, V);
    -     method public V replace(K, V);
    -     method public void replaceAll(java.util.function.BiFunction<? super K, ? super V, ? extends V>);
    --    method public U search(long, java.util.function.BiFunction<? super K, ? super V, ? extends U>);
    --    method public U searchEntries(long, java.util.function.Function<java.util.Map.Entry<K, V>, ? extends U>);
    --    method public U searchKeys(long, java.util.function.Function<? super K, ? extends U>);
    --    method public U searchValues(long, java.util.function.Function<? super V, ? extends U>);
    -+    method public <U> U search(long, java.util.function.BiFunction<? super K, ? super V, ? extends U>);
    -+    method public <U> U searchEntries(long, java.util.function.Function<java.util.Map.Entry<K, V>, ? extends U>);
    -+    method public <U> U searchKeys(long, java.util.function.Function<? super K, ? extends U>);
    -+    method public <U> U searchValues(long, java.util.function.Function<? super V, ? extends U>);
    -   }
    - 
    --   static abstract class ConcurrentHashMap.CollectionView implements java.util.Collection java.io.Serializable {
    -+   static abstract class ConcurrentHashMap.CollectionView<K, V, E> implements java.util.Collection java.io.Serializable {
    -     method public final void clear();
    -     method public abstract boolean contains(java.lang.Object);
    -     method public final boolean containsAll(java.util.Collection<?>);
    -@@ -59622,11 +59631,11 @@ package java.util.concurrent {
    -     method public final boolean retainAll(java.util.Collection<?>);
    -     method public final int size();
    -     method public final java.lang.Object[] toArray();
    --    method public final T[] toArray(T[]);
    -+    method public final <T> T[] toArray(T[]);
    -     method public final java.lang.String toString();
    -   }
    - 
    --  public static class ConcurrentHashMap.KeySetView extends java.util.concurrent.ConcurrentHashMap.CollectionView implements java.io.Serializable java.util.Set {
    -+  public static class ConcurrentHashMap.KeySetView<K, V> extends java.util.concurrent.ConcurrentHashMap.CollectionView implements java.io.Serializable java.util.Set {
    -     method public boolean add(K);
    -     method public boolean addAll(java.util.Collection<? extends K>);
    -     method public boolean contains(java.lang.Object);
    -@@ -59637,7 +59646,7 @@ package java.util.concurrent {
    -     method public java.util.Spliterator<K> spliterator();
    -   }
    - 
    --  public class ConcurrentLinkedDeque extends java.util.AbstractCollection implements java.util.Deque java.io.Serializable {
    -+  public class ConcurrentLinkedDeque<E> extends java.util.AbstractCollection implements java.util.Deque java.io.Serializable {
    -     ctor public ConcurrentLinkedDeque();
    -     ctor public ConcurrentLinkedDeque(java.util.Collection<? extends E>);
    -     method public void addFirst(E);
    -@@ -59667,7 +59676,7 @@ package java.util.concurrent {
    -     method public java.util.Spliterator<E> spliterator();
    -   }
    - 
    --  public class ConcurrentLinkedQueue extends java.util.AbstractQueue implements java.util.Queue java.io.Serializable {
    -+  public class ConcurrentLinkedQueue<E> extends java.util.AbstractQueue implements java.util.Queue java.io.Serializable {
    -     ctor public ConcurrentLinkedQueue();
    -     ctor public ConcurrentLinkedQueue(java.util.Collection<? extends E>);
    -     method public java.util.Iterator<E> iterator();
    -@@ -59678,14 +59687,14 @@ package java.util.concurrent {
    -     method public java.util.Spliterator<E> spliterator();
    -   }
    - 
    --  public abstract interface ConcurrentMap implements java.util.Map {
    -+  public abstract interface ConcurrentMap<K, V> implements java.util.Map {
    -     method public abstract V putIfAbsent(K, V);
    -     method public abstract boolean remove(java.lang.Object, java.lang.Object);
    -     method public abstract boolean replace(K, V, V);
    -     method public abstract V replace(K, V);
    -   }
    - 
    --  public abstract interface ConcurrentNavigableMap implements java.util.concurrent.ConcurrentMap java.util.NavigableMap {
    -+  public abstract interface ConcurrentNavigableMap<K, V> implements java.util.concurrent.ConcurrentMap java.util.NavigableMap {
    -     method public abstract java.util.NavigableSet<K> descendingKeySet();
    -     method public abstract java.util.concurrent.ConcurrentNavigableMap<K, V> descendingMap();
    -     method public abstract java.util.concurrent.ConcurrentNavigableMap<K, V> headMap(K, boolean);
    -@@ -59698,7 +59707,7 @@ package java.util.concurrent {
    -     method public abstract java.util.concurrent.ConcurrentNavigableMap<K, V> tailMap(K);
    -   }
    - 
    --  public class ConcurrentSkipListMap extends java.util.AbstractMap implements java.lang.Cloneable java.util.concurrent.ConcurrentNavigableMap java.io.Serializable {
    -+  public class ConcurrentSkipListMap<K, V> extends java.util.AbstractMap implements java.lang.Cloneable java.util.concurrent.ConcurrentNavigableMap java.io.Serializable {
    -     ctor public ConcurrentSkipListMap();
    -     ctor public ConcurrentSkipListMap(java.util.Comparator<? super K>);
    -     ctor public ConcurrentSkipListMap(java.util.Map<? extends K, ? extends V>);
    -@@ -59742,7 +59751,7 @@ package java.util.concurrent {
    -     method public java.util.concurrent.ConcurrentNavigableMap<K, V> tailMap(K);
    -   }
    - 
    --  public class ConcurrentSkipListSet extends java.util.AbstractSet implements java.lang.Cloneable java.util.NavigableSet java.io.Serializable {
    -+  public class ConcurrentSkipListSet<E> extends java.util.AbstractSet implements java.lang.Cloneable java.util.NavigableSet java.io.Serializable {
    -     ctor public ConcurrentSkipListSet();
    -     ctor public ConcurrentSkipListSet(java.util.Comparator<? super E>);
    -     ctor public ConcurrentSkipListSet(java.util.Collection<? extends E>);
    -@@ -59770,7 +59779,7 @@ package java.util.concurrent {
    -     method public java.util.NavigableSet<E> tailSet(E);
    -   }
    - 
    --  public class CopyOnWriteArrayList implements java.lang.Cloneable java.util.List java.util.RandomAccess java.io.Serializable {
    -+  public class CopyOnWriteArrayList<E> implements java.lang.Cloneable java.util.List java.util.RandomAccess java.io.Serializable {
    -     ctor public CopyOnWriteArrayList();
    -     ctor public CopyOnWriteArrayList(java.util.Collection<? extends E>);
    -     ctor public CopyOnWriteArrayList(E[]);
    -@@ -59802,10 +59811,10 @@ package java.util.concurrent {
    -     method public int size();
    -     method public java.util.List<E> subList(int, int);
    -     method public java.lang.Object[] toArray();
    --    method public T[] toArray(T[]);
    -+    method public <T> T[] toArray(T[]);
    -   }
    - 
    --  public class CopyOnWriteArraySet extends java.util.AbstractSet implements java.io.Serializable {
    -+  public class CopyOnWriteArraySet<E> extends java.util.AbstractSet implements java.io.Serializable {
    -     ctor public CopyOnWriteArraySet();
    -     ctor public CopyOnWriteArraySet(java.util.Collection<? extends E>);
    -     method public void forEach(java.util.function.Consumer<? super E>);
    -@@ -59823,7 +59832,7 @@ package java.util.concurrent {
    -     method public long getCount();
    -   }
    - 
    --  public abstract class CountedCompleter extends java.util.concurrent.ForkJoinTask {
    -+  public abstract class CountedCompleter<T> extends java.util.concurrent.ForkJoinTask {
    -     ctor protected CountedCompleter(java.util.concurrent.CountedCompleter<?>, int);
    -     ctor protected CountedCompleter(java.util.concurrent.CountedCompleter<?>);
    -     ctor protected CountedCompleter();
    -@@ -59860,7 +59869,7 @@ package java.util.concurrent {
    -     method public void reset();
    -   }
    - 
    --  public class DelayQueue extends java.util.AbstractQueue implements java.util.concurrent.BlockingQueue {
    -+  public class DelayQueue<E extends java.util.concurrent.Delayed> extends java.util.AbstractQueue implements java.util.concurrent.BlockingQueue {
    -     ctor public DelayQueue();
    -     ctor public DelayQueue(java.util.Collection<? extends E>);
    -     method public int drainTo(java.util.Collection<? super E>);
    -@@ -59881,7 +59890,7 @@ package java.util.concurrent {
    -     method public abstract long getDelay(java.util.concurrent.TimeUnit);
    -   }
    - 
    --  public class Exchanger {
    -+  public class Exchanger<V> {
    -     ctor public Exchanger();
    -     method public V exchange(V) throws java.lang.InterruptedException;
    -     method public V exchange(V, long, java.util.concurrent.TimeUnit) throws java.lang.InterruptedException, java.util.concurrent.TimeoutException;
    -@@ -59898,7 +59907,7 @@ package java.util.concurrent {
    -     method public abstract void execute(java.lang.Runnable);
    -   }
    - 
    --  public class ExecutorCompletionService implements java.util.concurrent.CompletionService {
    -+  public class ExecutorCompletionService<V> implements java.util.concurrent.CompletionService {
    -     ctor public ExecutorCompletionService(java.util.concurrent.Executor);
    -     ctor public ExecutorCompletionService(java.util.concurrent.Executor, java.util.concurrent.BlockingQueue<java.util.concurrent.Future<V>>);
    -     method public java.util.concurrent.Future<V> poll();
    -@@ -59910,21 +59919,21 @@ package java.util.concurrent {
    - 
    -   public abstract interface ExecutorService implements java.util.concurrent.Executor {
    -     method public abstract boolean awaitTermination(long, java.util.concurrent.TimeUnit) throws java.lang.InterruptedException;
    --    method public abstract java.util.List<java.util.concurrent.Future<T>> invokeAll(java.util.Collection<? extends java.util.concurrent.Callable<T>>) throws java.lang.InterruptedException;
    --    method public abstract java.util.List<java.util.concurrent.Future<T>> invokeAll(java.util.Collection<? extends java.util.concurrent.Callable<T>>, long, java.util.concurrent.TimeUnit) throws java.lang.InterruptedException;
    --    method public abstract T invokeAny(java.util.Collection<? extends java.util.concurrent.Callable<T>>) throws java.util.concurrent.ExecutionException, java.lang.InterruptedException;
    --    method public abstract T invokeAny(java.util.Collection<? extends java.util.concurrent.Callable<T>>, long, java.util.concurrent.TimeUnit) throws java.util.concurrent.ExecutionException, java.lang.InterruptedException, java.util.concurrent.TimeoutException;
    -+    method public abstract <T> java.util.List<java.util.concurrent.Future<T>> invokeAll(java.util.Collection<? extends java.util.concurrent.Callable<T>>) throws java.lang.InterruptedException;
    -+    method public abstract <T> java.util.List<java.util.concurrent.Future<T>> invokeAll(java.util.Collection<? extends java.util.concurrent.Callable<T>>, long, java.util.concurrent.TimeUnit) throws java.lang.InterruptedException;
    -+    method public abstract <T> T invokeAny(java.util.Collection<? extends java.util.concurrent.Callable<T>>) throws java.util.concurrent.ExecutionException, java.lang.InterruptedException;
    -+    method public abstract <T> T invokeAny(java.util.Collection<? extends java.util.concurrent.Callable<T>>, long, java.util.concurrent.TimeUnit) throws java.util.concurrent.ExecutionException, java.lang.InterruptedException, java.util.concurrent.TimeoutException;
    -     method public abstract boolean isShutdown();
    -     method public abstract boolean isTerminated();
    -     method public abstract void shutdown();
    -     method public abstract java.util.List<java.lang.Runnable> shutdownNow();
    --    method public abstract java.util.concurrent.Future<T> submit(java.util.concurrent.Callable<T>);
    --    method public abstract java.util.concurrent.Future<T> submit(java.lang.Runnable, T);
    -+    method public abstract <T> java.util.concurrent.Future<T> submit(java.util.concurrent.Callable<T>);
    -+    method public abstract <T> java.util.concurrent.Future<T> submit(java.lang.Runnable, T);
    -     method public abstract java.util.concurrent.Future<?> submit(java.lang.Runnable);
    -   }
    - 
    -   public class Executors {
    --    method public static java.util.concurrent.Callable<T> callable(java.lang.Runnable, T);
    -+    method public static <T> java.util.concurrent.Callable<T> callable(java.lang.Runnable, T);
    -     method public static java.util.concurrent.Callable<java.lang.Object> callable(java.lang.Runnable);
    -     method public static java.util.concurrent.Callable<java.lang.Object> callable(java.security.PrivilegedAction<?>);
    -     method public static java.util.concurrent.Callable<java.lang.Object> callable(java.security.PrivilegedExceptionAction<?>);
    -@@ -59941,8 +59950,8 @@ package java.util.concurrent {
    -     method public static java.util.concurrent.ScheduledExecutorService newSingleThreadScheduledExecutor(java.util.concurrent.ThreadFactory);
    -     method public static java.util.concurrent.ExecutorService newWorkStealingPool(int);
    -     method public static java.util.concurrent.ExecutorService newWorkStealingPool();
    --    method public static java.util.concurrent.Callable<T> privilegedCallable(java.util.concurrent.Callable<T>);
    --    method public static java.util.concurrent.Callable<T> privilegedCallableUsingCurrentClassLoader(java.util.concurrent.Callable<T>);
    -+    method public static <T> java.util.concurrent.Callable<T> privilegedCallable(java.util.concurrent.Callable<T>);
    -+    method public static <T> java.util.concurrent.Callable<T> privilegedCallableUsingCurrentClassLoader(java.util.concurrent.Callable<T>);
    -     method public static java.util.concurrent.ThreadFactory privilegedThreadFactory();
    -     method public static java.util.concurrent.ExecutorService unconfigurableExecutorService(java.util.concurrent.ExecutorService);
    -     method public static java.util.concurrent.ScheduledExecutorService unconfigurableScheduledExecutorService(java.util.concurrent.ScheduledExecutorService);
    -@@ -59970,7 +59979,7 @@ package java.util.concurrent {
    -     method public long getStealCount();
    -     method public java.lang.Thread.UncaughtExceptionHandler getUncaughtExceptionHandler();
    -     method public boolean hasQueuedSubmissions();
    --    method public T invoke(java.util.concurrent.ForkJoinTask<T>);
    -+    method public <T> T invoke(java.util.concurrent.ForkJoinTask<T>);
    -     method public boolean isQuiescent();
    -     method public boolean isShutdown();
    -     method public boolean isTerminated();
    -@@ -59979,7 +59988,7 @@ package java.util.concurrent {
    -     method protected java.util.concurrent.ForkJoinTask<?> pollSubmission();
    -     method public void shutdown();
    -     method public java.util.List<java.lang.Runnable> shutdownNow();
    --    method public java.util.concurrent.ForkJoinTask<T> submit(java.util.concurrent.ForkJoinTask<T>);
    -+    method public <T> java.util.concurrent.ForkJoinTask<T> submit(java.util.concurrent.ForkJoinTask<T>);
    -     field public static final java.util.concurrent.ForkJoinPool.ForkJoinWorkerThreadFactory defaultForkJoinWorkerThreadFactory;
    -   }
    - 
    -@@ -59992,11 +60001,11 @@ package java.util.concurrent {
    -     method public abstract boolean isReleasable();
    -   }
    - 
    --  public abstract class ForkJoinTask implements java.util.concurrent.Future java.io.Serializable {
    -+  public abstract class ForkJoinTask<V> implements java.util.concurrent.Future java.io.Serializable {
    -     ctor public ForkJoinTask();
    -     method public static java.util.concurrent.ForkJoinTask<?> adapt(java.lang.Runnable);
    --    method public static java.util.concurrent.ForkJoinTask<T> adapt(java.lang.Runnable, T);
    --    method public static java.util.concurrent.ForkJoinTask<T> adapt(java.util.concurrent.Callable<? extends T>);
    -+    method public static <T> java.util.concurrent.ForkJoinTask<T> adapt(java.lang.Runnable, T);
    -+    method public static <T> java.util.concurrent.ForkJoinTask<T> adapt(java.util.concurrent.Callable<? extends T>);
    -     method public boolean cancel(boolean);
    -     method public final boolean compareAndSetForkJoinTaskTag(short, short);
    -     method public void complete(V);
    -@@ -60016,7 +60025,7 @@ package java.util.concurrent {
    -     method public final V invoke();
    -     method public static void invokeAll(java.util.concurrent.ForkJoinTask<?>, java.util.concurrent.ForkJoinTask<?>);
    -     method public static void invokeAll(java.util.concurrent.ForkJoinTask<?>...);
    --    method public static java.util.Collection<T> invokeAll(java.util.Collection<T>);
    -+    method public static <T extends java.util.concurrent.ForkJoinTask<?>> java.util.Collection<T> invokeAll(java.util.Collection<T>);
    -     method public final boolean isCancelled();
    -     method public final boolean isCompletedAbnormally();
    -     method public final boolean isCompletedNormally();
    -@@ -60042,7 +60051,7 @@ package java.util.concurrent {
    -     method protected void onTermination(java.lang.Throwable);
    -   }
    - 
    --  public abstract interface Future {
    -+  public abstract interface Future<V> {
    -     method public abstract boolean cancel(boolean);
    -     method public abstract V get() throws java.util.concurrent.ExecutionException, java.lang.InterruptedException;
    -     method public abstract V get(long, java.util.concurrent.TimeUnit) throws java.util.concurrent.ExecutionException, java.lang.InterruptedException, java.util.concurrent.TimeoutException;
    -@@ -60050,7 +60059,7 @@ package java.util.concurrent {
    -     method public abstract boolean isDone();
    -   }
    - 
    --  public class FutureTask implements java.util.concurrent.RunnableFuture {
    -+  public class FutureTask<V> implements java.util.concurrent.RunnableFuture {
    -     ctor public FutureTask(java.util.concurrent.Callable<V>);
    -     ctor public FutureTask(java.lang.Runnable, V);
    -     method public boolean cancel(boolean);
    -@@ -60065,7 +60074,7 @@ package java.util.concurrent {
    -     method protected void setException(java.lang.Throwable);
    -   }
    - 
    --  public class LinkedBlockingDeque extends java.util.AbstractQueue implements java.util.concurrent.BlockingDeque java.io.Serializable {
    -+  public class LinkedBlockingDeque<E> extends java.util.AbstractQueue implements java.util.concurrent.BlockingDeque java.io.Serializable {
    -     ctor public LinkedBlockingDeque();
    -     ctor public LinkedBlockingDeque(int);
    -     ctor public LinkedBlockingDeque(java.util.Collection<? extends E>);
    -@@ -60109,7 +60118,7 @@ package java.util.concurrent {
    -     method public E takeLast() throws java.lang.InterruptedException;
    -   }
    - 
    --  public class LinkedBlockingQueue extends java.util.AbstractQueue implements java.util.concurrent.BlockingQueue java.io.Serializable {
    -+  public class LinkedBlockingQueue<E> extends java.util.AbstractQueue implements java.util.concurrent.BlockingQueue java.io.Serializable {
    -     ctor public LinkedBlockingQueue();
    -     ctor public LinkedBlockingQueue(int);
    -     ctor public LinkedBlockingQueue(java.util.Collection<? extends E>);
    -@@ -60128,7 +60137,7 @@ package java.util.concurrent {
    -     method public E take() throws java.lang.InterruptedException;
    -   }
    - 
    --  public class LinkedTransferQueue extends java.util.AbstractQueue implements java.io.Serializable java.util.concurrent.TransferQueue {
    -+  public class LinkedTransferQueue<E> extends java.util.AbstractQueue implements java.io.Serializable java.util.concurrent.TransferQueue {
    -     ctor public LinkedTransferQueue();
    -     ctor public LinkedTransferQueue(java.util.Collection<? extends E>);
    -     method public int drainTo(java.util.Collection<? super E>);
    -@@ -60175,7 +60184,7 @@ package java.util.concurrent {
    -     method public int register();
    -   }
    - 
    --  public class PriorityBlockingQueue extends java.util.AbstractQueue implements java.util.concurrent.BlockingQueue java.io.Serializable {
    -+  public class PriorityBlockingQueue<E> extends java.util.AbstractQueue implements java.util.concurrent.BlockingQueue java.io.Serializable {
    -     ctor public PriorityBlockingQueue();
    -     ctor public PriorityBlockingQueue(int);
    -     ctor public PriorityBlockingQueue(int, java.util.Comparator<? super E>);
    -@@ -60204,7 +60213,7 @@ package java.util.concurrent {
    -     method protected final void setRawResult(java.lang.Void);
    -   }
    - 
    --  public abstract class RecursiveTask extends java.util.concurrent.ForkJoinTask {
    -+  public abstract class RecursiveTask<V> extends java.util.concurrent.ForkJoinTask {
    -     ctor public RecursiveTask();
    -     method protected abstract V compute();
    -     method protected final boolean exec();
    -@@ -60223,22 +60232,22 @@ package java.util.concurrent {
    -     method public abstract void rejectedExecution(java.lang.Runnable, java.util.concurrent.ThreadPoolExecutor);
    -   }
    - 
    --  public abstract interface RunnableFuture implements java.util.concurrent.Future java.lang.Runnable {
    -+  public abstract interface RunnableFuture<V> implements java.util.concurrent.Future java.lang.Runnable {
    -     method public abstract void run();
    -   }
    - 
    --  public abstract interface RunnableScheduledFuture implements java.util.concurrent.RunnableFuture java.util.concurrent.ScheduledFuture {
    -+  public abstract interface RunnableScheduledFuture<V> implements java.util.concurrent.RunnableFuture java.util.concurrent.ScheduledFuture {
    -     method public abstract boolean isPeriodic();
    -   }
    - 
    -   public abstract interface ScheduledExecutorService implements java.util.concurrent.ExecutorService {
    -     method public abstract java.util.concurrent.ScheduledFuture<?> schedule(java.lang.Runnable, long, java.util.concurrent.TimeUnit);
    --    method public abstract java.util.concurrent.ScheduledFuture<V> schedule(java.util.concurrent.Callable<V>, long, java.util.concurrent.TimeUnit);
    -+    method public abstract <V> java.util.concurrent.ScheduledFuture<V> schedule(java.util.concurrent.Callable<V>, long, java.util.concurrent.TimeUnit);
    -     method public abstract java.util.concurrent.ScheduledFuture<?> scheduleAtFixedRate(java.lang.Runnable, long, long, java.util.concurrent.TimeUnit);
    -     method public abstract java.util.concurrent.ScheduledFuture<?> scheduleWithFixedDelay(java.lang.Runnable, long, long, java.util.concurrent.TimeUnit);
    -   }
    - 
    --  public abstract interface ScheduledFuture implements java.util.concurrent.Delayed java.util.concurrent.Future {
    -+  public abstract interface ScheduledFuture<V> implements java.util.concurrent.Delayed java.util.concurrent.Future {
    -   }
    - 
    -   public class ScheduledThreadPoolExecutor extends java.util.concurrent.ThreadPoolExecutor implements java.util.concurrent.ScheduledExecutorService {
    -@@ -60246,13 +60255,13 @@ package java.util.concurrent {
    -     ctor public ScheduledThreadPoolExecutor(int, java.util.concurrent.ThreadFactory);
    -     ctor public ScheduledThreadPoolExecutor(int, java.util.concurrent.RejectedExecutionHandler);
    -     ctor public ScheduledThreadPoolExecutor(int, java.util.concurrent.ThreadFactory, java.util.concurrent.RejectedExecutionHandler);
    --    method protected java.util.concurrent.RunnableScheduledFuture<V> decorateTask(java.lang.Runnable, java.util.concurrent.RunnableScheduledFuture<V>);
    --    method protected java.util.concurrent.RunnableScheduledFuture<V> decorateTask(java.util.concurrent.Callable<V>, java.util.concurrent.RunnableScheduledFuture<V>);
    -+    method protected <V> java.util.concurrent.RunnableScheduledFuture<V> decorateTask(java.lang.Runnable, java.util.concurrent.RunnableScheduledFuture<V>);
    -+    method protected <V> java.util.concurrent.RunnableScheduledFuture<V> decorateTask(java.util.concurrent.Callable<V>, java.util.concurrent.RunnableScheduledFuture<V>);
    -     method public boolean getContinueExistingPeriodicTasksAfterShutdownPolicy();
    -     method public boolean getExecuteExistingDelayedTasksAfterShutdownPolicy();
    -     method public boolean getRemoveOnCancelPolicy();
    -     method public java.util.concurrent.ScheduledFuture<?> schedule(java.lang.Runnable, long, java.util.concurrent.TimeUnit);
    --    method public java.util.concurrent.ScheduledFuture<V> schedule(java.util.concurrent.Callable<V>, long, java.util.concurrent.TimeUnit);
    -+    method public <V> java.util.concurrent.ScheduledFuture<V> schedule(java.util.concurrent.Callable<V>, long, java.util.concurrent.TimeUnit);
    -     method public java.util.concurrent.ScheduledFuture<?> scheduleAtFixedRate(java.lang.Runnable, long, long, java.util.concurrent.TimeUnit);
    -     method public java.util.concurrent.ScheduledFuture<?> scheduleWithFixedDelay(java.lang.Runnable, long, long, java.util.concurrent.TimeUnit);
    -     method public void setContinueExistingPeriodicTasksAfterShutdownPolicy(boolean);
    -@@ -60282,7 +60291,7 @@ package java.util.concurrent {
    -     method public boolean tryAcquire(int, long, java.util.concurrent.TimeUnit) throws java.lang.InterruptedException;
    -   }
    - 
    --  public class SynchronousQueue extends java.util.AbstractQueue implements java.util.concurrent.BlockingQueue java.io.Serializable {
    -+  public class SynchronousQueue<E> extends java.util.AbstractQueue implements java.util.concurrent.BlockingQueue java.io.Serializable {
    -     ctor public SynchronousQueue();
    -     ctor public SynchronousQueue(boolean);
    -     method public int drainTo(java.util.Collection<? super E>);
    -@@ -60400,7 +60409,7 @@ package java.util.concurrent {
    -     ctor public TimeoutException(java.lang.String);
    -   }
    - 
    --  public abstract interface TransferQueue implements java.util.concurrent.BlockingQueue {
    -+  public abstract interface TransferQueue<E> implements java.util.concurrent.BlockingQueue {
    -     method public abstract int getWaitingConsumerCount();
    -     method public abstract boolean hasWaitingConsumer();
    -     method public abstract void transfer(E) throws java.lang.InterruptedException;
    -@@ -60470,7 +60479,7 @@ package java.util.concurrent.atomic {
    -     method public final boolean weakCompareAndSet(int, int, int);
    -   }
    - 
    --  public abstract class AtomicIntegerFieldUpdater {
    -+  public abstract class AtomicIntegerFieldUpdater<T> {
    -     ctor protected AtomicIntegerFieldUpdater();
    -     method public final int accumulateAndGet(T, int, java.util.function.IntBinaryOperator);
    -     method public int addAndGet(T, int);
    -@@ -60485,7 +60494,7 @@ package java.util.concurrent.atomic {
    -     method public final int getAndUpdate(T, java.util.function.IntUnaryOperator);
    -     method public int incrementAndGet(T);
    -     method public abstract void lazySet(T, int);
    --    method public static java.util.concurrent.atomic.AtomicIntegerFieldUpdater<U> newUpdater(java.lang.Class<U>, java.lang.String);
    -+    method public static <U> java.util.concurrent.atomic.AtomicIntegerFieldUpdater<U> newUpdater(java.lang.Class<U>, java.lang.String);
    -     method public abstract void set(T, int);
    -     method public final int updateAndGet(T, java.util.function.IntUnaryOperator);
    -     method public abstract boolean weakCompareAndSet(T, int, int);
    -@@ -60538,7 +60547,7 @@ package java.util.concurrent.atomic {
    -     method public final boolean weakCompareAndSet(int, long, long);
    -   }
    - 
    --  public abstract class AtomicLongFieldUpdater {
    -+  public abstract class AtomicLongFieldUpdater<T> {
    -     ctor protected AtomicLongFieldUpdater();
    -     method public final long accumulateAndGet(T, long, java.util.function.LongBinaryOperator);
    -     method public long addAndGet(T, long);
    -@@ -60553,13 +60562,13 @@ package java.util.concurrent.atomic {
    -     method public final long getAndUpdate(T, java.util.function.LongUnaryOperator);
    -     method public long incrementAndGet(T);
    -     method public abstract void lazySet(T, long);
    --    method public static java.util.concurrent.atomic.AtomicLongFieldUpdater<U> newUpdater(java.lang.Class<U>, java.lang.String);
    -+    method public static <U> java.util.concurrent.atomic.AtomicLongFieldUpdater<U> newUpdater(java.lang.Class<U>, java.lang.String);
    -     method public abstract void set(T, long);
    -     method public final long updateAndGet(T, java.util.function.LongUnaryOperator);
    -     method public abstract boolean weakCompareAndSet(T, long, long);
    -   }
    - 
    --  public class AtomicMarkableReference {
    -+  public class AtomicMarkableReference<V> {
    -     ctor public AtomicMarkableReference(V, boolean);
    -     method public boolean attemptMark(V, boolean);
    -     method public boolean compareAndSet(V, V, boolean, boolean);
    -@@ -60570,7 +60579,7 @@ package java.util.concurrent.atomic {
    -     method public boolean weakCompareAndSet(V, V, boolean, boolean);
    -   }
    - 
    --  public class AtomicReference implements java.io.Serializable {
    -+  public class AtomicReference<V> implements java.io.Serializable {
    -     ctor public AtomicReference(V);
    -     ctor public AtomicReference();
    -     method public final V accumulateAndGet(V, java.util.function.BinaryOperator<V>);
    -@@ -60585,7 +60594,7 @@ package java.util.concurrent.atomic {
    -     method public final boolean weakCompareAndSet(V, V);
    -   }
    - 
    --  public class AtomicReferenceArray implements java.io.Serializable {
    -+  public class AtomicReferenceArray<E> implements java.io.Serializable {
    -     ctor public AtomicReferenceArray(int);
    -     ctor public AtomicReferenceArray(E[]);
    -     method public final E accumulateAndGet(int, E, java.util.function.BinaryOperator<E>);
    -@@ -60601,7 +60610,7 @@ package java.util.concurrent.atomic {
    -     method public final boolean weakCompareAndSet(int, E, E);
    -   }
    - 
    --  public abstract class AtomicReferenceFieldUpdater {
    -+  public abstract class AtomicReferenceFieldUpdater<T, V> {
    -     ctor protected AtomicReferenceFieldUpdater();
    -     method public final V accumulateAndGet(T, V, java.util.function.BinaryOperator<V>);
    -     method public abstract boolean compareAndSet(T, V, V);
    -@@ -60610,13 +60619,13 @@ package java.util.concurrent.atomic {
    -     method public V getAndSet(T, V);
    -     method public final V getAndUpdate(T, java.util.function.UnaryOperator<V>);
    -     method public abstract void lazySet(T, V);
    --    method public static java.util.concurrent.atomic.AtomicReferenceFieldUpdater<U, W> newUpdater(java.lang.Class<U>, java.lang.Class<W>, java.lang.String);
    -+    method public static <U, W> java.util.concurrent.atomic.AtomicReferenceFieldUpdater<U, W> newUpdater(java.lang.Class<U>, java.lang.Class<W>, java.lang.String);
    -     method public abstract void set(T, V);
    -     method public final V updateAndGet(T, java.util.function.UnaryOperator<V>);
    -     method public abstract boolean weakCompareAndSet(T, V, V);
    -   }
    - 
    --  public class AtomicStampedReference {
    -+  public class AtomicStampedReference<V> {
    -     ctor public AtomicStampedReference(V, int);
    -     method public boolean attemptStamp(V, int);
    -     method public boolean compareAndSet(V, V, int, int);
    -@@ -60919,33 +60928,33 @@ package java.util.concurrent.locks {
    - 
    - package java.util.function {
    - 
    --  public abstract interface BiConsumer {
    -+  public abstract interface BiConsumer<T, U> {
    -     method public abstract void accept(T, U);
    -     method public default java.util.function.BiConsumer<T, U> andThen(java.util.function.BiConsumer<? super T, ? super U>);
    -   }
    - 
    --  public abstract interface BiFunction {
    --    method public default java.util.function.BiFunction<T, U, V> andThen(java.util.function.Function<? super R, ? extends V>);
    -+  public abstract interface BiFunction<T, U, R> {
    -+    method public default <V> java.util.function.BiFunction<T, U, V> andThen(java.util.function.Function<? super R, ? extends V>);
    -     method public abstract R apply(T, U);
    -   }
    - 
    --  public abstract interface BiPredicate {
    -+  public abstract interface BiPredicate<T, U> {
    -     method public default java.util.function.BiPredicate<T, U> and(java.util.function.BiPredicate<? super T, ? super U>);
    -     method public default java.util.function.BiPredicate<T, U> negate();
    -     method public default java.util.function.BiPredicate<T, U> or(java.util.function.BiPredicate<? super T, ? super U>);
    -     method public abstract boolean test(T, U);
    -   }
    - 
    --  public abstract interface BinaryOperator implements java.util.function.BiFunction {
    --    method public static java.util.function.BinaryOperator<T> maxBy(java.util.Comparator<? super T>);
    --    method public static java.util.function.BinaryOperator<T> minBy(java.util.Comparator<? super T>);
    -+  public abstract interface BinaryOperator<T> implements java.util.function.BiFunction {
    -+    method public static <T> java.util.function.BinaryOperator<T> maxBy(java.util.Comparator<? super T>);
    -+    method public static <T> java.util.function.BinaryOperator<T> minBy(java.util.Comparator<? super T>);
    -   }
    - 
    -   public abstract interface BooleanSupplier {
    -     method public abstract boolean getAsBoolean();
    -   }
    - 
    --  public abstract interface Consumer {
    -+  public abstract interface Consumer<T> {
    -     method public abstract void accept(T);
    -     method public default java.util.function.Consumer<T> andThen(java.util.function.Consumer<? super T>);
    -   }
    -@@ -60959,7 +60968,7 @@ package java.util.function {
    -     method public default java.util.function.DoubleConsumer andThen(java.util.function.DoubleConsumer);
    -   }
    - 
    --  public abstract interface DoubleFunction {
    -+  public abstract interface DoubleFunction<R> {
    -     method public abstract R apply(double);
    -   }
    - 
    -@@ -60989,11 +60998,11 @@ package java.util.function {
    -     method public static java.util.function.DoubleUnaryOperator identity();
    -   }
    - 
    --  public abstract interface Function {
    --    method public default java.util.function.Function<T, V> andThen(java.util.function.Function<? super R, ? extends V>);
    -+  public abstract interface Function<T, R> {
    -+    method public default <V> java.util.function.Function<T, V> andThen(java.util.function.Function<? super R, ? extends V>);
    -     method public abstract R apply(T);
    --    method public default java.util.function.Function<V, R> compose(java.util.function.Function<? super V, ? extends T>);
    --    method public static java.util.function.Function<T, T> identity();
    -+    method public default <V> java.util.function.Function<V, R> compose(java.util.function.Function<? super V, ? extends T>);
    -+    method public static <T> java.util.function.Function<T, T> identity();
    -   }
    - 
    -   public abstract interface IntBinaryOperator {
    -@@ -61005,7 +61014,7 @@ package java.util.function {
    -     method public default java.util.function.IntConsumer andThen(java.util.function.IntConsumer);
    -   }
    - 
    --  public abstract interface IntFunction {
    -+  public abstract interface IntFunction<R> {
    -     method public abstract R apply(int);
    -   }
    - 
    -@@ -61044,7 +61053,7 @@ package java.util.function {
    -     method public default java.util.function.LongConsumer andThen(java.util.function.LongConsumer);
    -   }
    - 
    --  public abstract interface LongFunction {
    -+  public abstract interface LongFunction<R> {
    -     method public abstract R apply(long);
    -   }
    - 
    -@@ -61074,56 +61083,56 @@ package java.util.function {
    -     method public static java.util.function.LongUnaryOperator identity();
    -   }
    - 
    --  public abstract interface ObjDoubleConsumer {
    -+  public abstract interface ObjDoubleConsumer<T> {
    -     method public abstract void accept(T, double);
    -   }
    - 
    --  public abstract interface ObjIntConsumer {
    -+  public abstract interface ObjIntConsumer<T> {
    -     method public abstract void accept(T, int);
    -   }
    - 
    --  public abstract interface ObjLongConsumer {
    -+  public abstract interface ObjLongConsumer<T> {
    -     method public abstract void accept(T, long);
    -   }
    - 
    --  public abstract interface Predicate {
    -+  public abstract interface Predicate<T> {
    -     method public default java.util.function.Predicate<T> and(java.util.function.Predicate<? super T>);
    --    method public static java.util.function.Predicate<T> isEqual(java.lang.Object);
    -+    method public static <T> java.util.function.Predicate<T> isEqual(java.lang.Object);
    -     method public default java.util.function.Predicate<T> negate();
    -     method public default java.util.function.Predicate<T> or(java.util.function.Predicate<? super T>);
    -     method public abstract boolean test(T);
    -   }
    - 
    --  public abstract interface Supplier {
    -+  public abstract interface Supplier<T> {
    -     method public abstract T get();
    -   }
    - 
    --  public abstract interface ToDoubleBiFunction {
    -+  public abstract interface ToDoubleBiFunction<T, U> {
    -     method public abstract double applyAsDouble(T, U);
    -   }
    - 
    --  public abstract interface ToDoubleFunction {
    -+  public abstract interface ToDoubleFunction<T> {
    -     method public abstract double applyAsDouble(T);
    -   }
    - 
    --  public abstract interface ToIntBiFunction {
    -+  public abstract interface ToIntBiFunction<T, U> {
    -     method public abstract int applyAsInt(T, U);
    -   }
    - 
    --  public abstract interface ToIntFunction {
    -+  public abstract interface ToIntFunction<T> {
    -     method public abstract int applyAsInt(T);
    -   }
    - 
    --  public abstract interface ToLongBiFunction {
    -+  public abstract interface ToLongBiFunction<T, U> {
    -     method public abstract long applyAsLong(T, U);
    -   }
    - 
    --  public abstract interface ToLongFunction {
    -+  public abstract interface ToLongFunction<T> {
    -     method public abstract long applyAsLong(T);
    -   }
    - 
    --  public abstract interface UnaryOperator implements java.util.function.Function {
    --    method public static java.util.function.UnaryOperator<T> identity();
    -+  public abstract interface UnaryOperator<T> implements java.util.function.Function {
    -+    method public static <T> java.util.function.UnaryOperator<T> identity();
    -   }
    - 
    - }
    -@@ -61711,7 +61720,7 @@ package java.util.regex {
    - 
    - package java.util.stream {
    - 
    --  public abstract interface BaseStream implements java.lang.AutoCloseable {
    -+  public abstract interface BaseStream<T, S extends java.util.stream.BaseStream<T, S>> implements java.lang.AutoCloseable {
    -     method public abstract void close();
    -     method public abstract boolean isParallel();
    -     method public abstract java.util.Iterator<T> iterator();
    -@@ -61722,13 +61731,13 @@ package java.util.stream {
    -     method public abstract S unordered();
    -   }
    - 
    --  public abstract interface Collector {
    -+  public abstract interface Collector<T, A, R> {
    -     method public abstract java.util.function.BiConsumer<A, T> accumulator();
    -     method public abstract java.util.Set<java.util.stream.Collector.Characteristics> characteristics();
    -     method public abstract java.util.function.BinaryOperator<A> combiner();
    -     method public abstract java.util.function.Function<A, R> finisher();
    --    method public static java.util.stream.Collector<T, R, R> of(java.util.function.Supplier<R>, java.util.function.BiConsumer<R, T>, java.util.function.BinaryOperator<R>, java.util.stream.Collector.Characteristics...);
    --    method public static java.util.stream.Collector<T, A, R> of(java.util.function.Supplier<A>, java.util.function.BiConsumer<A, T>, java.util.function.BinaryOperator<A>, java.util.function.Function<A, R>, java.util.stream.Collector.Characteristics...);
    -+    method public static <T, R> java.util.stream.Collector<T, R, R> of(java.util.function.Supplier<R>, java.util.function.BiConsumer<R, T>, java.util.function.BinaryOperator<R>, java.util.stream.Collector.Characteristics...);
    -+    method public static <T, A, R> java.util.stream.Collector<T, A, R> of(java.util.function.Supplier<A>, java.util.function.BiConsumer<A, T>, java.util.function.BinaryOperator<A>, java.util.function.Function<A, R>, java.util.stream.Collector.Characteristics...);
    -     method public abstract java.util.function.Supplier<A> supplier();
    -   }
    - 
    -@@ -61741,43 +61750,43 @@ package java.util.stream {
    -   }
    - 
    -   public final class Collectors {
    --    method public static java.util.stream.Collector<T, ?, java.lang.Double> averagingDouble(java.util.function.ToDoubleFunction<? super T>);
    --    method public static java.util.stream.Collector<T, ?, java.lang.Double> averagingInt(java.util.function.ToIntFunction<? super T>);
    --    method public static java.util.stream.Collector<T, ?, java.lang.Double> averagingLong(java.util.function.ToLongFunction<? super T>);
    --    method public static java.util.stream.Collector<T, A, RR> collectingAndThen(java.util.stream.Collector<T, A, R>, java.util.function.Function<R, RR>);
    --    method public static java.util.stream.Collector<T, ?, java.lang.Long> counting();
    --    method public static java.util.stream.Collector<T, ?, java.util.Map<K, java.util.List<T>>> groupingBy(java.util.function.Function<? super T, ? extends K>);
    --    method public static java.util.stream.Collector<T, ?, java.util.Map<K, D>> groupingBy(java.util.function.Function<? super T, ? extends K>, java.util.stream.Collector<? super T, A, D>);
    --    method public static java.util.stream.Collector<T, ?, M> groupingBy(java.util.function.Function<? super T, ? extends K>, java.util.function.Supplier<M>, java.util.stream.Collector<? super T, A, D>);
    --    method public static java.util.stream.Collector<T, ?, java.util.concurrent.ConcurrentMap<K, java.util.List<T>>> groupingByConcurrent(java.util.function.Function<? super T, ? extends K>);
    --    method public static java.util.stream.Collector<T, ?, java.util.concurrent.ConcurrentMap<K, D>> groupingByConcurrent(java.util.function.Function<? super T, ? extends K>, java.util.stream.Collector<? super T, A, D>);
    --    method public static java.util.stream.Collector<T, ?, M> groupingByConcurrent(java.util.function.Function<? super T, ? extends K>, java.util.function.Supplier<M>, java.util.stream.Collector<? super T, A, D>);
    -+    method public static <T> java.util.stream.Collector<T, ?, java.lang.Double> averagingDouble(java.util.function.ToDoubleFunction<? super T>);
    -+    method public static <T> java.util.stream.Collector<T, ?, java.lang.Double> averagingInt(java.util.function.ToIntFunction<? super T>);
    -+    method public static <T> java.util.stream.Collector<T, ?, java.lang.Double> averagingLong(java.util.function.ToLongFunction<? super T>);
    -+    method public static <T, A, R, RR> java.util.stream.Collector<T, A, RR> collectingAndThen(java.util.stream.Collector<T, A, R>, java.util.function.Function<R, RR>);
    -+    method public static <T> java.util.stream.Collector<T, ?, java.lang.Long> counting();
    -+    method public static <T, K> java.util.stream.Collector<T, ?, java.util.Map<K, java.util.List<T>>> groupingBy(java.util.function.Function<? super T, ? extends K>);
    -+    method public static <T, K, A, D> java.util.stream.Collector<T, ?, java.util.Map<K, D>> groupingBy(java.util.function.Function<? super T, ? extends K>, java.util.stream.Collector<? super T, A, D>);
    -+    method public static <T, K, D, A, M extends java.util.Map<K, D>> java.util.stream.Collector<T, ?, M> groupingBy(java.util.function.Function<? super T, ? extends K>, java.util.function.Supplier<M>, java.util.stream.Collector<? super T, A, D>);
    -+    method public static <T, K> java.util.stream.Collector<T, ?, java.util.concurrent.ConcurrentMap<K, java.util.List<T>>> groupingByConcurrent(java.util.function.Function<? super T, ? extends K>);
    -+    method public static <T, K, A, D> java.util.stream.Collector<T, ?, java.util.concurrent.ConcurrentMap<K, D>> groupingByConcurrent(java.util.function.Function<? super T, ? extends K>, java.util.stream.Collector<? super T, A, D>);
    -+    method public static <T, K, A, D, M extends java.util.concurrent.ConcurrentMap<K, D>> java.util.stream.Collector<T, ?, M> groupingByConcurrent(java.util.function.Function<? super T, ? extends K>, java.util.function.Supplier<M>, java.util.stream.Collector<? super T, A, D>);
    -     method public static java.util.stream.Collector<java.lang.CharSequence, ?, java.lang.String> joining();
    -     method public static java.util.stream.Collector<java.lang.CharSequence, ?, java.lang.String> joining(java.lang.CharSequence);
    -     method public static java.util.stream.Collector<java.lang.CharSequence, ?, java.lang.String> joining(java.lang.CharSequence, java.lang.CharSequence, java.lang.CharSequence);
    --    method public static java.util.stream.Collector<T, ?, R> mapping(java.util.function.Function<? super T, ? extends U>, java.util.stream.Collector<? super U, A, R>);
    --    method public static java.util.stream.Collector<T, ?, java.util.Optional<T>> maxBy(java.util.Comparator<? super T>);
    --    method public static java.util.stream.Collector<T, ?, java.util.Optional<T>> minBy(java.util.Comparator<? super T>);
    --    method public static java.util.stream.Collector<T, ?, java.util.Map<java.lang.Boolean, java.util.List<T>>> partitioningBy(java.util.function.Predicate<? super T>);
    --    method public static java.util.stream.Collector<T, ?, java.util.Map<java.lang.Boolean, D>> partitioningBy(java.util.function.Predicate<? super T>, java.util.stream.Collector<? super T, A, D>);
    --    method public static java.util.stream.Collector<T, ?, T> reducing(T, java.util.function.BinaryOperator<T>);
    --    method public static java.util.stream.Collector<T, ?, java.util.Optional<T>> reducing(java.util.function.BinaryOperator<T>);
    --    method public static java.util.stream.Collector<T, ?, U> reducing(U, java.util.function.Function<? super T, ? extends U>, java.util.function.BinaryOperator<U>);
    --    method public static java.util.stream.Collector<T, ?, java.util.DoubleSummaryStatistics> summarizingDouble(java.util.function.ToDoubleFunction<? super T>);
    --    method public static java.util.stream.Collector<T, ?, java.util.IntSummaryStatistics> summarizingInt(java.util.function.ToIntFunction<? super T>);
    --    method public static java.util.stream.Collector<T, ?, java.util.LongSummaryStatistics> summarizingLong(java.util.function.ToLongFunction<? super T>);
    --    method public static java.util.stream.Collector<T, ?, java.lang.Double> summingDouble(java.util.function.ToDoubleFunction<? super T>);
    --    method public static java.util.stream.Collector<T, ?, java.lang.Integer> summingInt(java.util.function.ToIntFunction<? super T>);
    --    method public static java.util.stream.Collector<T, ?, java.lang.Long> summingLong(java.util.function.ToLongFunction<? super T>);
    --    method public static java.util.stream.Collector<T, ?, C> toCollection(java.util.function.Supplier<C>);
    --    method public static java.util.stream.Collector<T, ?, java.util.concurrent.ConcurrentMap<K, U>> toConcurrentMap(java.util.function.Function<? super T, ? extends K>, java.util.function.Function<? super T, ? extends U>);
    --    method public static java.util.stream.Collector<T, ?, java.util.concurrent.ConcurrentMap<K, U>> toConcurrentMap(java.util.function.Function<? super T, ? extends K>, java.util.function.Function<? super T, ? extends U>, java.util.function.BinaryOperator<U>);
    --    method public static java.util.stream.Collector<T, ?, M> toConcurrentMap(java.util.function.Function<? super T, ? extends K>, java.util.function.Function<? super T, ? extends U>, java.util.function.BinaryOperator<U>, java.util.function.Supplier<M>);
    --    method public static java.util.stream.Collector<T, ?, java.util.List<T>> toList();
    --    method public static java.util.stream.Collector<T, ?, java.util.Map<K, U>> toMap(java.util.function.Function<? super T, ? extends K>, java.util.function.Function<? super T, ? extends U>);
    --    method public static java.util.stream.Collector<T, ?, java.util.Map<K, U>> toMap(java.util.function.Function<? super T, ? extends K>, java.util.function.Function<? super T, ? extends U>, java.util.function.BinaryOperator<U>);
    --    method public static java.util.stream.Collector<T, ?, M> toMap(java.util.function.Function<? super T, ? extends K>, java.util.function.Function<? super T, ? extends U>, java.util.function.BinaryOperator<U>, java.util.function.Supplier<M>);
    --    method public static java.util.stream.Collector<T, ?, java.util.Set<T>> toSet();
    -+    method public static <T, U, A, R> java.util.stream.Collector<T, ?, R> mapping(java.util.function.Function<? super T, ? extends U>, java.util.stream.Collector<? super U, A, R>);
    -+    method public static <T> java.util.stream.Collector<T, ?, java.util.Optional<T>> maxBy(java.util.Comparator<? super T>);
    -+    method public static <T> java.util.stream.Collector<T, ?, java.util.Optional<T>> minBy(java.util.Comparator<? super T>);
    -+    method public static <T> java.util.stream.Collector<T, ?, java.util.Map<java.lang.Boolean, java.util.List<T>>> partitioningBy(java.util.function.Predicate<? super T>);
    -+    method public static <T, D, A> java.util.stream.Collector<T, ?, java.util.Map<java.lang.Boolean, D>> partitioningBy(java.util.function.Predicate<? super T>, java.util.stream.Collector<? super T, A, D>);
    -+    method public static <T> java.util.stream.Collector<T, ?, T> reducing(T, java.util.function.BinaryOperator<T>);
    -+    method public static <T> java.util.stream.Collector<T, ?, java.util.Optional<T>> reducing(java.util.function.BinaryOperator<T>);
    -+    method public static <T, U> java.util.stream.Collector<T, ?, U> reducing(U, java.util.function.Function<? super T, ? extends U>, java.util.function.BinaryOperator<U>);
    -+    method public static <T> java.util.stream.Collector<T, ?, java.util.DoubleSummaryStatistics> summarizingDouble(java.util.function.ToDoubleFunction<? super T>);
    -+    method public static <T> java.util.stream.Collector<T, ?, java.util.IntSummaryStatistics> summarizingInt(java.util.function.ToIntFunction<? super T>);
    -+    method public static <T> java.util.stream.Collector<T, ?, java.util.LongSummaryStatistics> summarizingLong(java.util.function.ToLongFunction<? super T>);
    -+    method public static <T> java.util.stream.Collector<T, ?, java.lang.Double> summingDouble(java.util.function.ToDoubleFunction<? super T>);
    -+    method public static <T> java.util.stream.Collector<T, ?, java.lang.Integer> summingInt(java.util.function.ToIntFunction<? super T>);
    -+    method public static <T> java.util.stream.Collector<T, ?, java.lang.Long> summingLong(java.util.function.ToLongFunction<? super T>);
    -+    method public static <T, C extends java.util.Collection<T>> java.util.stream.Collector<T, ?, C> toCollection(java.util.function.Supplier<C>);
    -+    method public static <T, K, U> java.util.stream.Collector<T, ?, java.util.concurrent.ConcurrentMap<K, U>> toConcurrentMap(java.util.function.Function<? super T, ? extends K>, java.util.function.Function<? super T, ? extends U>);
    -+    method public static <T, K, U> java.util.stream.Collector<T, ?, java.util.concurrent.ConcurrentMap<K, U>> toConcurrentMap(java.util.function.Function<? super T, ? extends K>, java.util.function.Function<? super T, ? extends U>, java.util.function.BinaryOperator<U>);
    -+    method public static <T, K, U, M extends java.util.concurrent.ConcurrentMap<K, U>> java.util.stream.Collector<T, ?, M> toConcurrentMap(java.util.function.Function<? super T, ? extends K>, java.util.function.Function<? super T, ? extends U>, java.util.function.BinaryOperator<U>, java.util.function.Supplier<M>);
    -+    method public static <T> java.util.stream.Collector<T, ?, java.util.List<T>> toList();
    -+    method public static <T, K, U> java.util.stream.Collector<T, ?, java.util.Map<K, U>> toMap(java.util.function.Function<? super T, ? extends K>, java.util.function.Function<? super T, ? extends U>);
    -+    method public static <T, K, U> java.util.stream.Collector<T, ?, java.util.Map<K, U>> toMap(java.util.function.Function<? super T, ? extends K>, java.util.function.Function<? super T, ? extends U>, java.util.function.BinaryOperator<U>);
    -+    method public static <T, K, U, M extends java.util.Map<K, U>> java.util.stream.Collector<T, ?, M> toMap(java.util.function.Function<? super T, ? extends K>, java.util.function.Function<? super T, ? extends U>, java.util.function.BinaryOperator<U>, java.util.function.Supplier<M>);
    -+    method public static <T> java.util.stream.Collector<T, ?, java.util.Set<T>> toSet();
    -   }
    - 
    -   public abstract interface DoubleStream implements java.util.stream.BaseStream {
    -@@ -61786,7 +61795,7 @@ package java.util.stream {
    -     method public abstract java.util.OptionalDouble average();
    -     method public abstract java.util.stream.Stream<java.lang.Double> boxed();
    -     method public static java.util.stream.DoubleStream.Builder builder();
    --    method public abstract R collect(java.util.function.Supplier<R>, java.util.function.ObjDoubleConsumer<R>, java.util.function.BiConsumer<R, R>);
    -+    method public abstract <R> R collect(java.util.function.Supplier<R>, java.util.function.ObjDoubleConsumer<R>, java.util.function.BiConsumer<R, R>);
    -     method public static java.util.stream.DoubleStream concat(java.util.stream.DoubleStream, java.util.stream.DoubleStream);
    -     method public abstract long count();
    -     method public abstract java.util.stream.DoubleStream distinct();
    -@@ -61804,7 +61813,7 @@ package java.util.stream {
    -     method public abstract java.util.stream.DoubleStream map(java.util.function.DoubleUnaryOperator);
    -     method public abstract java.util.stream.IntStream mapToInt(java.util.function.DoubleToIntFunction);
    -     method public abstract java.util.stream.LongStream mapToLong(java.util.function.DoubleToLongFunction);
    --    method public abstract java.util.stream.Stream<U> mapToObj(java.util.function.DoubleFunction<? extends U>);
    -+    method public abstract <U> java.util.stream.Stream<U> mapToObj(java.util.function.DoubleFunction<? extends U>);
    -     method public abstract java.util.OptionalDouble max();
    -     method public abstract java.util.OptionalDouble min();
    -     method public abstract boolean noneMatch(java.util.function.DoublePredicate);
    -@@ -61837,7 +61846,7 @@ package java.util.stream {
    -     method public abstract java.util.OptionalDouble average();
    -     method public abstract java.util.stream.Stream<java.lang.Integer> boxed();
    -     method public static java.util.stream.IntStream.Builder builder();
    --    method public abstract R collect(java.util.function.Supplier<R>, java.util.function.ObjIntConsumer<R>, java.util.function.BiConsumer<R, R>);
    -+    method public abstract <R> R collect(java.util.function.Supplier<R>, java.util.function.ObjIntConsumer<R>, java.util.function.BiConsumer<R, R>);
    -     method public static java.util.stream.IntStream concat(java.util.stream.IntStream, java.util.stream.IntStream);
    -     method public abstract long count();
    -     method public abstract java.util.stream.IntStream distinct();
    -@@ -61855,7 +61864,7 @@ package java.util.stream {
    -     method public abstract java.util.stream.IntStream map(java.util.function.IntUnaryOperator);
    -     method public abstract java.util.stream.DoubleStream mapToDouble(java.util.function.IntToDoubleFunction);
    -     method public abstract java.util.stream.LongStream mapToLong(java.util.function.IntToLongFunction);
    --    method public abstract java.util.stream.Stream<U> mapToObj(java.util.function.IntFunction<? extends U>);
    -+    method public abstract <U> java.util.stream.Stream<U> mapToObj(java.util.function.IntFunction<? extends U>);
    -     method public abstract java.util.OptionalInt max();
    -     method public abstract java.util.OptionalInt min();
    -     method public abstract boolean noneMatch(java.util.function.IntPredicate);
    -@@ -61889,7 +61898,7 @@ package java.util.stream {
    -     method public abstract java.util.OptionalDouble average();
    -     method public abstract java.util.stream.Stream<java.lang.Long> boxed();
    -     method public static java.util.stream.LongStream.Builder builder();
    --    method public abstract R collect(java.util.function.Supplier<R>, java.util.function.ObjLongConsumer<R>, java.util.function.BiConsumer<R, R>);
    -+    method public abstract <R> R collect(java.util.function.Supplier<R>, java.util.function.ObjLongConsumer<R>, java.util.function.BiConsumer<R, R>);
    -     method public static java.util.stream.LongStream concat(java.util.stream.LongStream, java.util.stream.LongStream);
    -     method public abstract long count();
    -     method public abstract java.util.stream.LongStream distinct();
    -@@ -61907,7 +61916,7 @@ package java.util.stream {
    -     method public abstract java.util.stream.LongStream map(java.util.function.LongUnaryOperator);
    -     method public abstract java.util.stream.DoubleStream mapToDouble(java.util.function.LongToDoubleFunction);
    -     method public abstract java.util.stream.IntStream mapToInt(java.util.function.LongToIntFunction);
    --    method public abstract java.util.stream.Stream<U> mapToObj(java.util.function.LongFunction<? extends U>);
    -+    method public abstract <U> java.util.stream.Stream<U> mapToObj(java.util.function.LongFunction<? extends U>);
    -     method public abstract java.util.OptionalLong max();
    -     method public abstract java.util.OptionalLong min();
    -     method public abstract boolean noneMatch(java.util.function.LongPredicate);
    -@@ -61934,49 +61943,49 @@ package java.util.stream {
    -     method public abstract java.util.stream.LongStream build();
    -   }
    - 
    --  public abstract interface Stream implements java.util.stream.BaseStream {
    -+  public abstract interface Stream<T> implements java.util.stream.BaseStream {
    -     method public abstract boolean allMatch(java.util.function.Predicate<? super T>);
    -     method public abstract boolean anyMatch(java.util.function.Predicate<? super T>);
    --    method public static java.util.stream.Stream.Builder<T> builder();
    --    method public abstract R collect(java.util.function.Supplier<R>, java.util.function.BiConsumer<R, ? super T>, java.util.function.BiConsumer<R, R>);
    --    method public abstract R collect(java.util.stream.Collector<? super T, A, R>);
    --    method public static java.util.stream.Stream<T> concat(java.util.stream.Stream<? extends T>, java.util.stream.Stream<? extends T>);
    -+    method public static <T> java.util.stream.Stream.Builder<T> builder();
    -+    method public abstract <R> R collect(java.util.function.Supplier<R>, java.util.function.BiConsumer<R, ? super T>, java.util.function.BiConsumer<R, R>);
    -+    method public abstract <R, A> R collect(java.util.stream.Collector<? super T, A, R>);
    -+    method public static <T> java.util.stream.Stream<T> concat(java.util.stream.Stream<? extends T>, java.util.stream.Stream<? extends T>);
    -     method public abstract long count();
    -     method public abstract java.util.stream.Stream<T> distinct();
    --    method public static java.util.stream.Stream<T> empty();
    -+    method public static <T> java.util.stream.Stream<T> empty();
    -     method public abstract java.util.stream.Stream<T> filter(java.util.function.Predicate<? super T>);
    -     method public abstract java.util.Optional<T> findAny();
    -     method public abstract java.util.Optional<T> findFirst();
    --    method public abstract java.util.stream.Stream<R> flatMap(java.util.function.Function<? super T, ? extends java.util.stream.Stream<? extends R>>);
    -+    method public abstract <R> java.util.stream.Stream<R> flatMap(java.util.function.Function<? super T, ? extends java.util.stream.Stream<? extends R>>);
    -     method public abstract java.util.stream.DoubleStream flatMapToDouble(java.util.function.Function<? super T, ? extends java.util.stream.DoubleStream>);
    -     method public abstract java.util.stream.IntStream flatMapToInt(java.util.function.Function<? super T, ? extends java.util.stream.IntStream>);
    -     method public abstract java.util.stream.LongStream flatMapToLong(java.util.function.Function<? super T, ? extends java.util.stream.LongStream>);
    -     method public abstract void forEach(java.util.function.Consumer<? super T>);
    -     method public abstract void forEachOrdered(java.util.function.Consumer<? super T>);
    --    method public static java.util.stream.Stream<T> generate(java.util.function.Supplier<T>);
    --    method public static java.util.stream.Stream<T> iterate(T, java.util.function.UnaryOperator<T>);
    -+    method public static <T> java.util.stream.Stream<T> generate(java.util.function.Supplier<T>);
    -+    method public static <T> java.util.stream.Stream<T> iterate(T, java.util.function.UnaryOperator<T>);
    -     method public abstract java.util.stream.Stream<T> limit(long);
    --    method public abstract java.util.stream.Stream<R> map(java.util.function.Function<? super T, ? extends R>);
    -+    method public abstract <R> java.util.stream.Stream<R> map(java.util.function.Function<? super T, ? extends R>);
    -     method public abstract java.util.stream.DoubleStream mapToDouble(java.util.function.ToDoubleFunction<? super T>);
    -     method public abstract java.util.stream.IntStream mapToInt(java.util.function.ToIntFunction<? super T>);
    -     method public abstract java.util.stream.LongStream mapToLong(java.util.function.ToLongFunction<? super T>);
    -     method public abstract java.util.Optional<T> max(java.util.Comparator<? super T>);
    -     method public abstract java.util.Optional<T> min(java.util.Comparator<? super T>);
    -     method public abstract boolean noneMatch(java.util.function.Predicate<? super T>);
    --    method public static java.util.stream.Stream<T> of(T);
    --    method public static java.util.stream.Stream<T> of(T...);
    -+    method public static <T> java.util.stream.Stream<T> of(T);
    -+    method public static <T> java.util.stream.Stream<T> of(T...);
    -     method public abstract java.util.stream.Stream<T> peek(java.util.function.Consumer<? super T>);
    -     method public abstract T reduce(T, java.util.function.BinaryOperator<T>);
    -     method public abstract java.util.Optional<T> reduce(java.util.function.BinaryOperator<T>);
    --    method public abstract U reduce(U, java.util.function.BiFunction<U, ? super T, U>, java.util.function.BinaryOperator<U>);
    -+    method public abstract <U> U reduce(U, java.util.function.BiFunction<U, ? super T, U>, java.util.function.BinaryOperator<U>);
    -     method public abstract java.util.stream.Stream<T> skip(long);
    -     method public abstract java.util.stream.Stream<T> sorted();
    -     method public abstract java.util.stream.Stream<T> sorted(java.util.Comparator<? super T>);
    -     method public abstract java.lang.Object[] toArray();
    --    method public abstract A[] toArray(java.util.function.IntFunction<A[]>);
    -+    method public abstract <A> A[] toArray(java.util.function.IntFunction<A[]>);
    -   }
    - 
    --  public static abstract interface Stream.Builder implements java.util.function.Consumer {
    -+  public static abstract interface Stream.Builder<T> implements java.util.function.Consumer {
    -     method public abstract void accept(T);
    -     method public default java.util.stream.Stream.Builder<T> add(T);
    -     method public abstract java.util.stream.Stream<T> build();
    -@@ -61989,8 +61998,8 @@ package java.util.stream {
    -     method public static java.util.stream.IntStream intStream(java.util.function.Supplier<? extends java.util.Spliterator.OfInt>, int, boolean);
    -     method public static java.util.stream.LongStream longStream(java.util.Spliterator.OfLong, boolean);
    -     method public static java.util.stream.LongStream longStream(java.util.function.Supplier<? extends java.util.Spliterator.OfLong>, int, boolean);
    --    method public static java.util.stream.Stream<T> stream(java.util.Spliterator<T>, boolean);
    --    method public static java.util.stream.Stream<T> stream(java.util.function.Supplier<? extends java.util.Spliterator<T>>, int, boolean);
    -+    method public static <T> java.util.stream.Stream<T> stream(java.util.Spliterator<T>, boolean);
    -+    method public static <T> java.util.stream.Stream<T> stream(java.util.function.Supplier<? extends java.util.Spliterator<T>>, int, boolean);
    -   }
    - 
    - }
    -@@ -64161,16 +64170,16 @@ package javax.security.auth {
    -   public final class Subject implements java.io.Serializable {
    -     ctor public Subject();
    -     ctor public Subject(boolean, java.util.Set<? extends java.security.Principal>, java.util.Set<?>, java.util.Set<?>);
    --    method public static T doAs(javax.security.auth.Subject, java.security.PrivilegedAction<T>);
    --    method public static T doAs(javax.security.auth.Subject, java.security.PrivilegedExceptionAction<T>) throws java.security.PrivilegedActionException;
    --    method public static T doAsPrivileged(javax.security.auth.Subject, java.security.PrivilegedAction<T>, java.security.AccessControlContext);
    --    method public static T doAsPrivileged(javax.security.auth.Subject, java.security.PrivilegedExceptionAction<T>, java.security.AccessControlContext) throws java.security.PrivilegedActionException;
    -+    method public static <T> T doAs(javax.security.auth.Subject, java.security.PrivilegedAction<T>);
    -+    method public static <T> T doAs(javax.security.auth.Subject, java.security.PrivilegedExceptionAction<T>) throws java.security.PrivilegedActionException;
    -+    method public static <T> T doAsPrivileged(javax.security.auth.Subject, java.security.PrivilegedAction<T>, java.security.AccessControlContext);
    -+    method public static <T> T doAsPrivileged(javax.security.auth.Subject, java.security.PrivilegedExceptionAction<T>, java.security.AccessControlContext) throws java.security.PrivilegedActionException;
    -     method public java.util.Set<java.security.Principal> getPrincipals();
    --    method public java.util.Set<T> getPrincipals(java.lang.Class<T>);
    -+    method public <T extends java.security.Principal> java.util.Set<T> getPrincipals(java.lang.Class<T>);
    -     method public java.util.Set<java.lang.Object> getPrivateCredentials();
    --    method public java.util.Set<T> getPrivateCredentials(java.lang.Class<T>);
    -+    method public <T> java.util.Set<T> getPrivateCredentials(java.lang.Class<T>);
    -     method public java.util.Set<java.lang.Object> getPublicCredentials();
    --    method public java.util.Set<T> getPublicCredentials(java.lang.Class<T>);
    -+    method public <T> java.util.Set<T> getPublicCredentials(java.lang.Class<T>);
    -     method public static javax.security.auth.Subject getSubject(java.security.AccessControlContext);
    -     method public boolean isReadOnly();
    -     method public void setReadOnly();
    -diff --git a/cmds/bootanimation/audioplay.cpp b/cmds/bootanimation/audioplay.cpp
    -index 4983b9a..c546072 100644
    ---- a/cmds/bootanimation/audioplay.cpp
    -+++ b/cmds/bootanimation/audioplay.cpp
    -@@ -141,13 +141,27 @@ bool createBufferQueueAudioPlayer(const ChunkFormat* chunkFormat) {
    -     // configure audio source
    -     SLDataLocator_AndroidSimpleBufferQueue loc_bufq = {SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE, 1};
    - 
    -+    // Determine channelMask from num_channels
    -+    SLuint32 channelMask;
    -+    switch (chunkFormat->num_channels) {
    -+        case 1:
    -+            channelMask = SL_SPEAKER_FRONT_CENTER;
    -+            break;
    -+        case 2:
    -+            channelMask = SL_SPEAKER_FRONT_LEFT | SL_SPEAKER_FRONT_RIGHT;
    -+            break;
    -+        default:
    -+            // Default of 0 will derive mask from num_channels and log a warning.
    -+            channelMask = 0;
    -+    }
    -+
    -     SLDataFormat_PCM format_pcm = {
    -         SL_DATAFORMAT_PCM,
    -         chunkFormat->num_channels,
    -         chunkFormat->sample_rate * 1000,  // convert to milliHz
    -         chunkFormat->bits_per_sample,
    -         16,
    --        SL_SPEAKER_FRONT_CENTER,
    -+        channelMask,
    -         SL_BYTEORDER_LITTLEENDIAN
    -     };
    -     SLDataSource audioSrc = {&loc_bufq, &format_pcm};
    -diff --git a/cmds/idmap/scan.cpp b/cmds/idmap/scan.cpp
    -index 6d30f0d..ab6adfb 100644
    ---- a/cmds/idmap/scan.cpp
    -+++ b/cmds/idmap/scan.cpp
    -@@ -1,5 +1,6 @@
    - #include <dirent.h>
    - #include <inttypes.h>
    -+#include <sys/file.h>
    - #include <sys/stat.h>
    - 
    - #include "idmap.h"
    -@@ -35,16 +36,31 @@ namespace {
    - 
    -     bool writePackagesList(const char *filename, const SortedVector<Overlay>& overlayVector)
    -     {
    --        FILE* fout = fopen(filename, "w");
    -+        // the file is opened for appending so that it doesn't get truncated
    -+        // before we can guarantee mutual exclusion via the flock
    -+        FILE* fout = fopen(filename, "a");
    -         if (fout == NULL) {
    -             return false;
    -         }
    - 
    -+        if (TEMP_FAILURE_RETRY(flock(fileno(fout), LOCK_EX)) != 0) {
    -+            fclose(fout);
    -+            return false;
    -+        }
    -+
    -+        if (TEMP_FAILURE_RETRY(ftruncate(fileno(fout), 0)) != 0) {
    -+            TEMP_FAILURE_RETRY(flock(fileno(fout), LOCK_UN));
    -+            fclose(fout);
    -+            return false;
    -+        }
    -+
    -         for (size_t i = 0; i < overlayVector.size(); ++i) {
    -             const Overlay& overlay = overlayVector[i];
    -             fprintf(fout, "%s %s\n", overlay.apk_path.string(), overlay.idmap_path.string());
    -         }
    - 
    -+        TEMP_FAILURE_RETRY(fflush(fout));
    -+        TEMP_FAILURE_RETRY(flock(fileno(fout), LOCK_UN));
    -         fclose(fout);
    - 
    -         // Make file world readable since Zygote (running as root) will read
    -@@ -171,9 +187,6 @@ int idmap_scan(const char *target_package_name, const char *target_apk_path,
    - {
    -     String8 filename = String8(idmap_dir);
    -     filename.appendPath("overlays.list");
    --    if (unlink(filename.string()) != 0 && errno != ENOENT) {
    --        return EXIT_FAILURE;
    --    }
    - 
    -     SortedVector<Overlay> overlayVector;
    -     const size_t N = overlay_dirs->size();
    -diff --git a/cmds/pm/src/com/android/commands/pm/Pm.java b/cmds/pm/src/com/android/commands/pm/Pm.java
    -index 32a8088..1b4eda8 100644
    ---- a/cmds/pm/src/com/android/commands/pm/Pm.java
    -+++ b/cmds/pm/src/com/android/commands/pm/Pm.java
    -@@ -41,6 +41,10 @@ import android.content.pm.PackageInstaller;
    - import android.content.pm.PackageInstaller.SessionInfo;
    - import android.content.pm.PackageInstaller.SessionParams;
    - import android.content.pm.PackageManager;
    -+import android.content.pm.PackageParser;
    -+import android.content.pm.PackageParser.ApkLite;
    -+import android.content.pm.PackageParser.PackageLite;
    -+import android.content.pm.PackageParser.PackageParserException;
    - import android.content.pm.UserInfo;
    - import android.net.Uri;
    - import android.os.Binder;
    -@@ -362,11 +366,33 @@ public final class Pm {
    -      */
    -     private int runInstall() throws RemoteException {
    -         final InstallParams params = makeInstallParams();
    -+        final String inPath = nextArg();
    -+        boolean installExternal =
    -+                (params.sessionParams.installFlags & PackageManager.INSTALL_EXTERNAL) != 0;
    -+        if (params.sessionParams.sizeBytes < 0 && inPath != null) {
    -+            File file = new File(inPath);
    -+            if (file.isFile()) {
    -+                if (installExternal) {
    -+                    try {
    -+                        ApkLite baseApk = PackageParser.parseApkLite(file, 0);
    -+                        PackageLite pkgLite = new PackageLite(null, baseApk, null, null, null);
    -+                        params.sessionParams.setSize(
    -+                                PackageHelper.calculateInstalledSize(pkgLite, false,
    -+                                        params.sessionParams.abiOverride));
    -+                    } catch (PackageParserException | IOException e) {
    -+                        System.err.println("Error: Failed to parse APK file : " + e);
    -+                        return 1;
    -+                    }
    -+                } else {
    -+                    params.sessionParams.setSize(file.length());
    -+                }
    -+            }
    -+        }
    -+
    -         final int sessionId = doCreateSession(params.sessionParams,
    -                 params.installerPackageName, params.userId);
    - 
    -         try {
    --            final String inPath = nextArg();
    -             if (inPath == null && params.sessionParams.sizeBytes == 0) {
    -                 System.err.println("Error: must either specify a package size or an APK file");
    -                 return 1;
    -diff --git a/cmds/wm/src/com/android/commands/wm/Wm.java b/cmds/wm/src/com/android/commands/wm/Wm.java
    -index f7f7c88..383cd01 100644
    ---- a/cmds/wm/src/com/android/commands/wm/Wm.java
    -+++ b/cmds/wm/src/com/android/commands/wm/Wm.java
    -@@ -23,6 +23,7 @@ import android.graphics.Point;
    - import android.graphics.Rect;
    - import android.os.RemoteException;
    - import android.os.ServiceManager;
    -+import android.os.UserHandle;
    - import android.util.AndroidException;
    - import android.util.DisplayMetrics;
    - import android.view.Display;
    -@@ -201,9 +202,11 @@ public class Wm extends BaseCommand {
    -         try {
    -             if (density > 0) {
    -                 // TODO(multidisplay): For now Configuration only applies to main screen.
    --                mWm.setForcedDisplayDensity(Display.DEFAULT_DISPLAY, density);
    -+                mWm.setForcedDisplayDensityForUser(Display.DEFAULT_DISPLAY, density,
    -+                        UserHandle.USER_CURRENT);
    -             } else {
    --                mWm.clearForcedDisplayDensity(Display.DEFAULT_DISPLAY);
    -+                mWm.clearForcedDisplayDensityForUser(Display.DEFAULT_DISPLAY,
    -+                        UserHandle.USER_CURRENT);
    -             }
    -         } catch (RemoteException e) {
    -         }
    -diff --git a/core/java/android/accessibilityservice/AccessibilityService.java b/core/java/android/accessibilityservice/AccessibilityService.java
    -index c4eaccc..163e7d2 100644
    ---- a/core/java/android/accessibilityservice/AccessibilityService.java
    -+++ b/core/java/android/accessibilityservice/AccessibilityService.java
    -@@ -53,7 +53,7 @@ import java.lang.annotation.RetentionPolicy;
    - import java.util.List;
    - 
    - /**
    -- * Accessibility services are intended to assist users with disabilities in using
    -+ * Accessibility services should only be used to assist users with disabilities in using
    -  * Android devices and apps. They run in the background and receive callbacks by the system
    -  * when {@link AccessibilityEvent}s are fired. Such events denote some state transition
    -  * in the user interface, for example, the focus has changed, a button has been clicked,
    -diff --git a/core/java/android/accounts/Account.java b/core/java/android/accounts/Account.java
    -index 7b83a30..b6e85f1 100644
    ---- a/core/java/android/accounts/Account.java
    -+++ b/core/java/android/accounts/Account.java
    -@@ -16,9 +16,19 @@
    - 
    - package android.accounts;
    - 
    -+import android.annotation.NonNull;
    -+import android.annotation.Nullable;
    -+import android.content.Context;
    - import android.os.Parcelable;
    - import android.os.Parcel;
    -+import android.os.RemoteException;
    -+import android.os.ServiceManager;
    - import android.text.TextUtils;
    -+import android.util.ArraySet;
    -+import android.util.Log;
    -+import com.android.internal.annotations.GuardedBy;
    -+
    -+import java.util.Set;
    - 
    - /**
    -  * Value type that represents an Account in the {@link AccountManager}. This object is
    -@@ -26,8 +36,14 @@ import android.text.TextUtils;
    -  * suitable for use as the key of a {@link java.util.Map}
    -  */
    - public class Account implements Parcelable {
    -+    private static final String TAG = "Account";
    -+
    -+    @GuardedBy("sAccessedAccounts")
    -+    private static final Set<Account> sAccessedAccounts = new ArraySet<>();
    -+
    -     public final String name;
    -     public final String type;
    -+    private final @Nullable String accessId;
    - 
    -     public boolean equals(Object o) {
    -         if (o == this) return true;
    -@@ -44,6 +60,20 @@ public class Account implements Parcelable {
    -     }
    - 
    -     public Account(String name, String type) {
    -+        this(name, type, null);
    -+    }
    -+
    -+    /**
    -+     * @hide
    -+     */
    -+    public Account(@NonNull Account other, @NonNull String accessId) {
    -+        this(other.name, other.type, accessId);
    -+    }
    -+
    -+    /**
    -+     * @hide
    -+     */
    -+    public Account(String name, String type, String accessId) {
    -         if (TextUtils.isEmpty(name)) {
    -             throw new IllegalArgumentException("the name must not be empty: " + name);
    -         }
    -@@ -52,11 +82,31 @@ public class Account implements Parcelable {
    -         }
    -         this.name = name;
    -         this.type = type;
    -+        this.accessId = accessId;
    -     }
    - 
    -     public Account(Parcel in) {
    -         this.name = in.readString();
    -         this.type = in.readString();
    -+        this.accessId = in.readString();
    -+        if (accessId != null) {
    -+            synchronized (sAccessedAccounts) {
    -+                if (sAccessedAccounts.add(this)) {
    -+                    try {
    -+                        IAccountManager accountManager = IAccountManager.Stub.asInterface(
    -+                                ServiceManager.getService(Context.ACCOUNT_SERVICE));
    -+                        accountManager.onAccountAccessed(accessId);
    -+                    } catch (RemoteException e) {
    -+                        Log.e(TAG, "Error noting account access", e);
    -+                    }
    -+                }
    -+            }
    -+        }
    -+    }
    -+
    -+    /** @hide */
    -+    public String getAccessId() {
    -+        return accessId;
    -     }
    - 
    -     public int describeContents() {
    -@@ -66,6 +116,7 @@ public class Account implements Parcelable {
    -     public void writeToParcel(Parcel dest, int flags) {
    -         dest.writeString(name);
    -         dest.writeString(type);
    -+        dest.writeString(accessId);
    -     }
    - 
    -     public static final Creator<Account> CREATOR = new Creator<Account>() {
    -diff --git a/core/java/android/accounts/AccountManager.java b/core/java/android/accounts/AccountManager.java
    -index d3551b7..72707b7 100644
    ---- a/core/java/android/accounts/AccountManager.java
    -+++ b/core/java/android/accounts/AccountManager.java
    -@@ -28,6 +28,7 @@ import android.content.ComponentName;
    - import android.content.Context;
    - import android.content.Intent;
    - import android.content.IntentFilter;
    -+import android.content.IntentSender;
    - import android.content.res.Resources;
    - import android.database.SQLException;
    - import android.os.Build;
    -@@ -178,6 +179,14 @@ public class AccountManager {
    -     public static final String KEY_ACCOUNT_TYPE = "accountType";
    - 
    -     /**
    -+     * Bundle key used for the account access id used for noting the
    -+     * account was accessed when unmarshalled from a parcel.
    -+     *
    -+     * @hide
    -+     */
    -+    public static final String KEY_ACCOUNT_ACCESS_ID = "accountAccessId";
    -+
    -+    /**
    -      * Bundle key used for the auth token value in results
    -      * from {@link #getAuthToken} and friends.
    -      */
    -@@ -265,6 +274,15 @@ public class AccountManager {
    -             "android.accounts.AccountAuthenticator";
    -     public static final String AUTHENTICATOR_ATTRIBUTES_NAME = "account-authenticator";
    - 
    -+    /**
    -+     * Token type for the special case where a UID has access only to an account
    -+     * but no authenticator specific auth token types.
    -+     *
    -+     * @hide
    -+     */
    -+    public static final String ACCOUNT_ACCESS_TOKEN_TYPE =
    -+            "com.android.AccountManager.ACCOUNT_ACCESS_TOKEN_TYPE";
    -+
    -     private final Context mContext;
    -     private final IAccountManager mService;
    -     private final Handler mMainHandler;
    -@@ -803,7 +821,8 @@ public class AccountManager {
    -             public Account bundleToResult(Bundle bundle) throws AuthenticatorException {
    -                 String name = bundle.getString(KEY_ACCOUNT_NAME);
    -                 String type = bundle.getString(KEY_ACCOUNT_TYPE);
    --                return new Account(name, type);
    -+                String accessId = bundle.getString(KEY_ACCOUNT_ACCESS_ID);
    -+                return new Account(name, type, accessId);
    -             }
    -         }.start();
    -     }
    -@@ -2259,6 +2278,7 @@ public class AccountManager {
    -                                     result.putString(KEY_ACCOUNT_NAME, null);
    -                                     result.putString(KEY_ACCOUNT_TYPE, null);
    -                                     result.putString(KEY_AUTHTOKEN, null);
    -+                                    result.putBinder(KEY_ACCOUNT_ACCESS_ID, null);
    -                                     try {
    -                                         mResponse.onResult(result);
    -                                     } catch (RemoteException e) {
    -@@ -2284,9 +2304,11 @@ public class AccountManager {
    -                                         public void onResult(Bundle value) throws RemoteException {
    -                                             Account account = new Account(
    -                                                     value.getString(KEY_ACCOUNT_NAME),
    --                                                    value.getString(KEY_ACCOUNT_TYPE));
    --                                            mFuture = getAuthToken(account, mAuthTokenType, mLoginOptions,
    --                                                    mActivity, mMyCallback, mHandler);
    -+                                                    value.getString(KEY_ACCOUNT_TYPE),
    -+                                                    value.getString(KEY_ACCOUNT_ACCESS_ID));
    -+                                            mFuture = getAuthToken(account, mAuthTokenType,
    -+                                                    mLoginOptions,  mActivity, mMyCallback,
    -+                                                    mHandler);
    -                                         }
    - 
    -                                         @Override
    -@@ -2333,7 +2355,8 @@ public class AccountManager {
    -                         setException(new AuthenticatorException("account not in result"));
    -                         return;
    -                     }
    --                    final Account account = new Account(accountName, accountType);
    -+                    final String accessId = result.getString(KEY_ACCOUNT_ACCESS_ID);
    -+                    final Account account = new Account(accountName, accountType, accessId);
    -                     mNumAccounts = 1;
    -                     getAuthToken(account, mAuthTokenType, null /* options */, mActivity,
    -                             mMyCallback, mHandler);
    -@@ -2956,4 +2979,49 @@ public class AccountManager {
    -             }
    -         }.start();
    -     }
    -+
    -+    /**
    -+     * Gets whether a given package under a user has access to an account.
    -+     * Can be called only from the system UID.
    -+     *
    -+     * @param account The account for which to check.
    -+     * @param packageName The package for which to check.
    -+     * @param userHandle The user for which to check.
    -+     * @return True if the package can access the account.
    -+     *
    -+     * @hide
    -+     */
    -+    public boolean hasAccountAccess(@NonNull Account account, @NonNull String packageName,
    -+            @NonNull UserHandle userHandle) {
    -+        try {
    -+            return mService.hasAccountAccess(account, packageName, userHandle);
    -+        } catch (RemoteException e) {
    -+            throw e.rethrowFromSystemServer();
    -+        }
    -+    }
    -+
    -+    /**
    -+     * Creates an intent to request access to a given account for a UID.
    -+     * The returned intent should be stated for a result where {@link
    -+     * Activity#RESULT_OK} result means access was granted whereas {@link
    -+     * Activity#RESULT_CANCELED} result means access wasn't granted. Can
    -+     * be called only from the system UID.
    -+     *
    -+     * @param account The account for which to request.
    -+     * @param packageName The package name which to request.
    -+     * @param userHandle The user for which to request.
    -+     * @return The intent to request account access or null if the package
    -+     *     doesn't exist.
    -+     *
    -+     * @hide
    -+     */
    -+    public IntentSender createRequestAccountAccessIntentSenderAsUser(@NonNull Account account,
    -+            @NonNull String packageName, @NonNull UserHandle userHandle) {
    -+        try {
    -+            return mService.createRequestAccountAccessIntentSenderAsUser(account, packageName,
    -+                    userHandle);
    -+        } catch (RemoteException e) {
    -+            throw e.rethrowFromSystemServer();
    -+        }
    -+    }
    - }
    -diff --git a/core/java/android/accounts/AccountManagerInternal.java b/core/java/android/accounts/AccountManagerInternal.java
    -new file mode 100644
    -index 0000000..68c17c3
    ---- /dev/null
    -+++ b/core/java/android/accounts/AccountManagerInternal.java
    -@@ -0,0 +1,90 @@
    -+/*
    -+ * Copyright (C) 2016 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 android.accounts;
    -+
    -+import android.annotation.IntRange;
    -+import android.annotation.NonNull;
    -+import android.os.RemoteCallback;
    -+
    -+/**
    -+ * Account manager local system service interface.
    -+ *
    -+ * @hide Only for use within the system server.
    -+ */
    -+public abstract class AccountManagerInternal {
    -+
    -+    /**
    -+     * Listener for explicit UID account access grant changes.
    -+     */
    -+    public interface OnAppPermissionChangeListener {
    -+
    -+        /**
    -+         * Called when the explicit grant state for a given UID to
    -+         * access an account changes.
    -+         *
    -+         * @param account The account
    -+         * @param uid The UID for which the grant changed
    -+         */
    -+        public void onAppPermissionChanged(Account account, int uid);
    -+    }
    -+
    -+    /**
    -+     * Requests that a given package is given access to an account.
    -+     * The provided callback will be invoked with a {@link android.os.Bundle}
    -+     * containing the result which will be a boolean value mapped to the
    -+     * {@link AccountManager#KEY_BOOLEAN_RESULT} key.
    -+     *
    -+     * @param account The account for which to request.
    -+     * @param packageName The package name for which to request.
    -+     * @param userId Concrete user id for which to request.
    -+     * @param callback A callback for receiving the result.
    -+     */
    -+    public abstract void requestAccountAccess(@NonNull Account account,
    -+            @NonNull String packageName, @IntRange(from = 0) int userId,
    -+            @NonNull RemoteCallback callback);
    -+
    -+    /**
    -+     * Check whether the given UID has access to the account.
    -+     *
    -+     * @param account The account
    -+     * @param uid The UID
    -+     * @return Whether the UID can access the account
    -+     */
    -+    public abstract boolean hasAccountAccess(@NonNull Account account, @IntRange(from = 0) int uid);
    -+
    -+    /**
    -+     * Adds a listener for explicit UID account access grant changes.
    -+     *
    -+     * @param listener The listener
    -+     */
    -+    public abstract void addOnAppPermissionChangeListener(
    -+            @NonNull OnAppPermissionChangeListener listener);
    -+
    -+    /**
    -+     * Backups the account access permissions.
    -+     * @param userId The user for which to backup.
    -+     * @return The backup data.
    -+     */
    -+    public abstract byte[] backupAccountAccessPermissions(int userId);
    -+
    -+    /**
    -+     * Restores the account access permissions.
    -+     * @param data The restore data.
    -+     * @param userId The user for which to restore.
    -+     */
    -+    public abstract void restoreAccountAccessPermissions(byte[] data, int userId);
    -+}
    -diff --git a/core/java/android/accounts/ChooseTypeAndAccountActivity.java b/core/java/android/accounts/ChooseTypeAndAccountActivity.java
    -index 133df2b..bf96926 100644
    ---- a/core/java/android/accounts/ChooseTypeAndAccountActivity.java
    -+++ b/core/java/android/accounts/ChooseTypeAndAccountActivity.java
    -@@ -250,6 +250,10 @@ public class ChooseTypeAndAccountActivity extends Activity
    -             outState.putParcelableArray(KEY_INSTANCE_STATE_EXISTING_ACCOUNTS, mExistingAccounts);
    -         }
    -         if (mSelectedItemIndex != SELECTED_ITEM_NONE) {
    -+            if (mAccounts == null) {
    -+                final AccountManager accountManager = AccountManager.get(this);
    -+                mAccounts = getAcceptableAccountChoices(accountManager);
    -+            }
    -             if (mSelectedItemIndex == mAccounts.size()) {
    -                 outState.putBoolean(KEY_INSTANCE_STATE_SELECTED_ADD_ACCOUNT, true);
    -             } else {
    -@@ -291,6 +295,10 @@ public class ChooseTypeAndAccountActivity extends Activity
    -         mPendingRequest = REQUEST_NULL;
    - 
    -         if (resultCode == RESULT_CANCELED) {
    -+            if (mAccounts == null) {
    -+                final AccountManager accountManager = AccountManager.get(this);
    -+                mAccounts = getAcceptableAccountChoices(accountManager);
    -+            }
    -             // if canceling out of addAccount and the original state caused us to skip this,
    -             // finish this activity
    -             if (mAccounts.isEmpty()) {
    -@@ -399,7 +407,7 @@ public class ChooseTypeAndAccountActivity extends Activity
    -      * useless.
    -      */
    -     private void setNonLabelThemeAndCallSuperCreate(Bundle savedInstanceState) {
    --        setTheme(R.style.Theme_Material_Light_Dialog_NoActionBar);
    -+        setTheme(R.style.Theme_DeviceDefault_Light_Dialog_NoActionBar);
    -         super.onCreate(savedInstanceState);
    -     }
    - 
    -diff --git a/core/java/android/accounts/GrantCredentialsPermissionActivity.java b/core/java/android/accounts/GrantCredentialsPermissionActivity.java
    -index 12b2b9c..38eab29 100644
    ---- a/core/java/android/accounts/GrantCredentialsPermissionActivity.java
    -+++ b/core/java/android/accounts/GrantCredentialsPermissionActivity.java
    -@@ -35,12 +35,10 @@ import java.io.IOException;
    -  */
    - public class GrantCredentialsPermissionActivity extends Activity implements View.OnClickListener {
    -     public static final String EXTRAS_ACCOUNT = "account";
    --    public static final String EXTRAS_AUTH_TOKEN_LABEL = "authTokenLabel";
    -     public static final String EXTRAS_AUTH_TOKEN_TYPE = "authTokenType";
    -     public static final String EXTRAS_RESPONSE = "response";
    --    public static final String EXTRAS_ACCOUNT_TYPE_LABEL = "accountTypeLabel";
    --    public static final String EXTRAS_PACKAGES = "application";
    -     public static final String EXTRAS_REQUESTING_UID = "uid";
    -+
    -     private Account mAccount;
    -     private String mAuthTokenType;
    -     private int mUid;
    -@@ -109,7 +107,11 @@ public class GrantCredentialsPermissionActivity extends Activity implements View
    -                 }
    -             }
    -         };
    --        AccountManager.get(this).getAuthTokenLabel(mAccount.type, mAuthTokenType, callback, null);
    -+
    -+        if (!AccountManager.ACCOUNT_ACCESS_TOKEN_TYPE.equals(mAuthTokenType)) {
    -+            AccountManager.get(this).getAuthTokenLabel(mAccount.type,
    -+                    mAuthTokenType, callback, null);
    -+        }
    - 
    -         findViewById(R.id.allow_button).setOnClickListener(this);
    -         findViewById(R.id.deny_button).setOnClickListener(this);
    -diff --git a/core/java/android/accounts/IAccountManager.aidl b/core/java/android/accounts/IAccountManager.aidl
    -index 7199288..c271e7e 100644
    ---- a/core/java/android/accounts/IAccountManager.aidl
    -+++ b/core/java/android/accounts/IAccountManager.aidl
    -@@ -19,8 +19,10 @@ package android.accounts;
    - import android.accounts.IAccountManagerResponse;
    - import android.accounts.Account;
    - import android.accounts.AuthenticatorDescription;
    -+import android.content.IntentSender;
    - import android.os.Bundle;
    --
    -+import android.os.RemoteCallback;
    -+import android.os.UserHandle;
    - 
    - /**
    -  * Central application service that provides account management.
    -@@ -102,4 +104,12 @@ interface IAccountManager {
    -     /* Check if credentials update is suggested */
    -     void isCredentialsUpdateSuggested(in IAccountManagerResponse response, in Account account,
    -         String statusToken);
    -+
    -+    /* Check if the package in a user can access an account */
    -+    boolean hasAccountAccess(in Account account, String packageName, in UserHandle userHandle);
    -+    /* Crate an intent to request account access for package and a given user id */
    -+    IntentSender createRequestAccountAccessIntentSenderAsUser(in Account account,
    -+        String packageName, in UserHandle userHandle);
    -+
    -+    void onAccountAccessed(String token);
    - }
    -diff --git a/core/java/android/animation/LayoutTransition.java b/core/java/android/animation/LayoutTransition.java
    -index cdd72be..5a23fdd 100644
    ---- a/core/java/android/animation/LayoutTransition.java
    -+++ b/core/java/android/animation/LayoutTransition.java
    -@@ -62,7 +62,11 @@ import java.util.Map;
    -  * layout will run (closing the gap created in the layout when the item was removed). If this
    -  * default choreography behavior is not desired, the {@link #setDuration(int, long)} and
    -  * {@link #setStartDelay(int, long)} of any or all of the animations can be changed as
    -- * appropriate.</p>
    -+ * appropriate. Keep in mind, however, that if you start an APPEARING animation before a
    -+ * DISAPPEARING animation is completed, the DISAPPEARING animation stops, and any effects from
    -+ * the DISAPPEARING animation are reverted. If you instead start a DISAPPEARING animation
    -+ * before an APPEARING animation is completed, a similar set of effects occurs for the
    -+ * APPEARING animation.</p>
    -  *
    -  * <p>The animations specified for the transition, both the defaults and any custom animations
    -  * set on the transition object, are templates only. That is, these animations exist to hold the
    -diff --git a/core/java/android/animation/ObjectAnimator.java b/core/java/android/animation/ObjectAnimator.java
    -index 9a2aa30..0c21c4f 100644
    ---- a/core/java/android/animation/ObjectAnimator.java
    -+++ b/core/java/android/animation/ObjectAnimator.java
    -@@ -977,8 +977,9 @@ public final class ObjectAnimator extends ValueAnimator {
    -     @Override
    -     void animateValue(float fraction) {
    -         final Object target = getTarget();
    --        if (target == null) {
    --            // We lost the target reference, cancel and clean up.
    -+        if (mTarget != null && target == null) {
    -+            // We lost the target reference, cancel and clean up. Note: we allow null target if the
    -+            /// target has never been set.
    -             cancel();
    -             return;
    -         }
    -diff --git a/core/java/android/animation/ValueAnimator.java b/core/java/android/animation/ValueAnimator.java
    -index e3f8fa4..7e16e3e 100644
    ---- a/core/java/android/animation/ValueAnimator.java
    -+++ b/core/java/android/animation/ValueAnimator.java
    -@@ -18,6 +18,7 @@ package android.animation;
    - 
    - import android.annotation.CallSuper;
    - import android.annotation.IntDef;
    -+import android.annotation.TestApi;
    - import android.os.Looper;
    - import android.os.Trace;
    - import android.util.AndroidRuntimeException;
    -@@ -261,6 +262,7 @@ public class ValueAnimator extends Animator implements AnimationHandler.Animatio
    -     /**
    -      * @hide
    -      */
    -+    @TestApi
    -     public static void setDurationScale(float durationScale) {
    -         sDurationScale = durationScale;
    -     }
    -@@ -268,6 +270,7 @@ public class ValueAnimator extends Animator implements AnimationHandler.Animatio
    -     /**
    -      * @hide
    -      */
    -+    @TestApi
    -     public static float getDurationScale() {
    -         return sDurationScale;
    -     }
    -diff --git a/core/java/android/app/ActivityManagerNative.java b/core/java/android/app/ActivityManagerNative.java
    -index aacd5da..50479c8 100644
    ---- a/core/java/android/app/ActivityManagerNative.java
    -+++ b/core/java/android/app/ActivityManagerNative.java
    -@@ -3017,6 +3017,14 @@ public abstract class ActivityManagerNative extends Binder implements IActivityM
    -             reply.writeNoException();
    -             return true;
    -         }
    -+        case CAN_BYPASS_WORK_CHALLENGE: {
    -+            data.enforceInterface(IActivityManager.descriptor);
    -+            final PendingIntent intent = PendingIntent.CREATOR.createFromParcel(data);
    -+            final boolean result = canBypassWorkChallenge(intent);
    -+            reply.writeNoException();
    -+            reply.writeInt(result ? 1 : 0);
    -+            return true;
    -+        }
    -         }
    - 
    -         return super.onTransact(code, data, reply, flags);
    -@@ -7091,6 +7099,20 @@ class ActivityManagerProxy implements IActivityManager
    -         reply.recycle();
    -         return;
    -     }
    -+    @Override
    -+    public boolean canBypassWorkChallenge(PendingIntent intent)
    -+            throws RemoteException {
    -+        Parcel data = Parcel.obtain();
    -+        Parcel reply = Parcel.obtain();
    -+        data.writeInterfaceToken(IActivityManager.descriptor);
    -+        intent.writeToParcel(data, 0);
    -+        mRemote.transact(CAN_BYPASS_WORK_CHALLENGE, data, reply, 0);
    -+        reply.readException();
    -+        final int result = reply.readInt();
    -+        data.recycle();
    -+        reply.recycle();
    -+        return result != 0;
    -+    }
    - 
    -     private IBinder mRemote;
    - }
    -diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
    -index 2c5f881..6a2b9aa 100644
    ---- a/core/java/android/app/ActivityThread.java
    -+++ b/core/java/android/app/ActivityThread.java
    -@@ -108,6 +108,7 @@ import android.renderscript.RenderScriptCacheDir;
    - import android.system.Os;
    - import android.system.OsConstants;
    - import android.system.ErrnoException;
    -+import android.webkit.WebView;
    - 
    - import com.android.internal.annotations.GuardedBy;
    - import com.android.internal.app.IVoiceInteractor;
    -@@ -433,8 +434,10 @@ public final class ActivityThread {
    -     static final class NewIntentData {
    -         List<ReferrerIntent> intents;
    -         IBinder token;
    -+        boolean andPause;
    -         public String toString() {
    --            return "NewIntentData{intents=" + intents + " token=" + token + "}";
    -+            return "NewIntentData{intents=" + intents + " token=" + token
    -+                    + " andPause=" + andPause +"}";
    -         }
    -     }
    - 
    -@@ -751,10 +754,12 @@ public final class ActivityThread {
    -                     configChanges, notResumed, config, overrideConfig, true, preserveWindow);
    -         }
    - 
    --        public final void scheduleNewIntent(List<ReferrerIntent> intents, IBinder token) {
    -+        public final void scheduleNewIntent(
    -+                List<ReferrerIntent> intents, IBinder token, boolean andPause) {
    -             NewIntentData data = new NewIntentData();
    -             data.intents = intents;
    -             data.token = token;
    -+            data.andPause = andPause;
    - 
    -             sendMessage(H.NEW_INTENT, data);
    -         }
    -@@ -1037,10 +1042,21 @@ public final class ActivityThread {
    -             long dalvikMax = runtime.totalMemory() / 1024;
    -             long dalvikFree = runtime.freeMemory() / 1024;
    -             long dalvikAllocated = dalvikMax - dalvikFree;
    -+
    -+            Class[] classesToCount = new Class[] {
    -+                    ContextImpl.class,
    -+                    Activity.class,
    -+                    WebView.class,
    -+                    OpenSSLSocketImpl.class
    -+            };
    -+            long[] instanceCounts = VMDebug.countInstancesOfClasses(classesToCount, true);
    -+            long appContextInstanceCount = instanceCounts[0];
    -+            long activityInstanceCount = instanceCounts[1];
    -+            long webviewInstanceCount = instanceCounts[2];
    -+            long openSslSocketCount = instanceCounts[3];
    -+
    -             long viewInstanceCount = ViewDebug.getViewInstanceCount();
    -             long viewRootInstanceCount = ViewDebug.getViewRootImplCount();
    --            long appContextInstanceCount = Debug.countInstancesOfClass(ContextImpl.class);
    --            long activityInstanceCount = Debug.countInstancesOfClass(Activity.class);
    -             int globalAssetCount = AssetManager.getGlobalAssetCount();
    -             int globalAssetManagerCount = AssetManager.getGlobalAssetManagerCount();
    -             int binderLocalObjectCount = Debug.getBinderLocalObjectCount();
    -@@ -1048,7 +1064,6 @@ public final class ActivityThread {
    -             int binderDeathObjectCount = Debug.getBinderDeathObjectCount();
    -             long parcelSize = Parcel.getGlobalAllocSize();
    -             long parcelCount = Parcel.getGlobalAllocCount();
    --            long openSslSocketCount = Debug.countInstancesOfClass(OpenSSLSocketImpl.class);
    -             SQLiteDebug.PagerStats stats = SQLiteDebug.getDatabaseInfo();
    - 
    -             dumpMemInfoTable(pw, memInfo, checkin, dumpFullInfo, dumpDalvik, dumpSummaryOnly,
    -@@ -1111,6 +1126,7 @@ public final class ActivityThread {
    -                     "Parcel count:", parcelCount);
    -             printRow(pw, TWO_COUNT_COLUMNS, "Death Recipients:", binderDeathObjectCount,
    -                     "OpenSSL Sockets:", openSslSocketCount);
    -+            printRow(pw, ONE_COUNT_COLUMN, "WebViews:", webviewInstanceCount);
    - 
    -             // SQLite mem info
    -             pw.println(" ");
    -@@ -2787,24 +2803,34 @@ public final class ActivityThread {
    -         }
    -     }
    - 
    --    public final void performNewIntents(IBinder token, List<ReferrerIntent> intents) {
    --        ActivityClientRecord r = mActivities.get(token);
    --        if (r != null) {
    --            final boolean resumed = !r.paused;
    --            if (resumed) {
    --                r.activity.mTemporaryPause = true;
    --                mInstrumentation.callActivityOnPause(r.activity);
    --            }
    --            deliverNewIntents(r, intents);
    --            if (resumed) {
    --                r.activity.performResume();
    --                r.activity.mTemporaryPause = false;
    --            }
    -+    void performNewIntents(IBinder token, List<ReferrerIntent> intents, boolean andPause) {
    -+        final ActivityClientRecord r = mActivities.get(token);
    -+        if (r == null) {
    -+            return;
    -+        }
    -+
    -+        final boolean resumed = !r.paused;
    -+        if (resumed) {
    -+            r.activity.mTemporaryPause = true;
    -+            mInstrumentation.callActivityOnPause(r.activity);
    -+        }
    -+        deliverNewIntents(r, intents);
    -+        if (resumed) {
    -+            r.activity.performResume();
    -+            r.activity.mTemporaryPause = false;
    -+        }
    -+
    -+        if (r.paused && andPause) {
    -+            // In this case the activity was in the paused state when we delivered the intent,
    -+            // to guarantee onResume gets called after onNewIntent we temporarily resume the
    -+            // activity and pause again as the caller wanted.
    -+            performResumeActivity(token, false, "performNewIntents");
    -+            performPauseActivityIfNeeded(r, "performNewIntents");
    -         }
    -     }
    - 
    -     private void handleNewIntent(NewIntentData data) {
    --        performNewIntents(data.token, data.intents);
    -+        performNewIntents(data.token, data.intents, data.andPause);
    -     }
    - 
    -     public void handleRequestAssistContextExtras(RequestAssistContextExtras cmd) {
    -@@ -3785,7 +3811,7 @@ public final class ActivityThread {
    -      * than our client -- for the server, stop means to save state and give
    -      * it the result when it is done, but the window may still be visible.
    -      * For the client, we want to call onStop()/onStart() to indicate when
    --     * the activity's UI visibillity changes.
    -+     * the activity's UI visibility changes.
    -      */
    -     private void performStopActivityInner(ActivityClientRecord r,
    -             StopInfo info, boolean keepShown, boolean saveState, String reason) {
    -@@ -3959,6 +3985,9 @@ public final class ActivityThread {
    -         mSomeActivitiesChanged = true;
    -     }
    - 
    -+    // TODO: This method should be changed to use {@link #performStopActivityInner} to perform to
    -+    // stop operation on the activity to reduce code duplication and the chance of fixing a bug in
    -+    // one place and missing the other.
    -     private void handleSleeping(IBinder token, boolean sleeping) {
    -         ActivityClientRecord r = mActivities.get(token);
    - 
    -@@ -3969,6 +3998,10 @@ public final class ActivityThread {
    - 
    -         if (sleeping) {
    -             if (!r.stopped && !r.isPreHoneycomb()) {
    -+                if (!r.activity.mFinished && r.state == null) {
    -+                    callCallActivityOnSaveInstanceState(r);
    -+                }
    -+
    -                 try {
    -                     // Now we are idle.
    -                     r.activity.performStop(false /*preserveWindow*/);
    -@@ -4989,9 +5022,7 @@ public final class ActivityThread {
    -             int uid = Process.myUid();
    -             String[] packages = getPackageManager().getPackagesForUid(uid);
    - 
    --            // If there are several packages in this application we won't
    --            // initialize the graphics disk caches
    --            if (packages != null && packages.length == 1) {
    -+            if (packages != null) {
    -                 ThreadedRenderer.setupDiskCache(cacheDir);
    -                 RenderScriptCacheDir.setupDiskCache(cacheDir);
    -             }
    -diff --git a/core/java/android/app/ApplicationThreadNative.java b/core/java/android/app/ApplicationThreadNative.java
    -index d6da3f4..05d9d7e 100644
    ---- a/core/java/android/app/ApplicationThreadNative.java
    -+++ b/core/java/android/app/ApplicationThreadNative.java
    -@@ -190,7 +190,8 @@ public abstract class ApplicationThreadNative extends Binder
    -             data.enforceInterface(IApplicationThread.descriptor);
    -             List<ReferrerIntent> pi = data.createTypedArrayList(ReferrerIntent.CREATOR);
    -             IBinder b = data.readStrongBinder();
    --            scheduleNewIntent(pi, b);
    -+            final boolean andPause = data.readInt() == 1;
    -+            scheduleNewIntent(pi, b, andPause);
    -             return true;
    -         }
    - 
    -@@ -909,12 +910,13 @@ class ApplicationThreadProxy implements IApplicationThread {
    -         data.recycle();
    -     }
    - 
    --    public void scheduleNewIntent(List<ReferrerIntent> intents, IBinder token)
    -+    public void scheduleNewIntent(List<ReferrerIntent> intents, IBinder token, boolean andPause)
    -             throws RemoteException {
    -         Parcel data = Parcel.obtain();
    -         data.writeInterfaceToken(IApplicationThread.descriptor);
    -         data.writeTypedList(intents);
    -         data.writeStrongBinder(token);
    -+        data.writeInt(andPause ? 1 : 0);
    -         mRemote.transact(SCHEDULE_NEW_INTENT_TRANSACTION, data, null,
    -                 IBinder.FLAG_ONEWAY);
    -         data.recycle();
    -diff --git a/core/java/android/app/Dialog.java b/core/java/android/app/Dialog.java
    -index 85a0403..6e2c464 100644
    ---- a/core/java/android/app/Dialog.java
    -+++ b/core/java/android/app/Dialog.java
    -@@ -32,6 +32,7 @@ import android.content.ComponentName;
    - import android.content.Context;
    - import android.content.ContextWrapper;
    - import android.content.DialogInterface;
    -+import android.content.res.Configuration;
    - import android.content.pm.ApplicationInfo;
    - import android.graphics.drawable.Drawable;
    - import android.net.Uri;
    -@@ -288,9 +289,14 @@ public class Dialog implements DialogInterface, Window.Callback,
    -         }
    - 
    -         mCanceled = false;
    --        
    -+
    -         if (!mCreated) {
    -             dispatchOnCreate(null);
    -+        } else {
    -+            // Fill the DecorView in on any configuration changes that
    -+            // may have occured while it was removed from the WindowManager.
    -+            final Configuration config = mContext.getResources().getConfiguration();
    -+            mWindow.getDecorView().dispatchConfigurationChanged(config);
    -         }
    - 
    -         onStart();
    -diff --git a/core/java/android/app/DownloadManager.java b/core/java/android/app/DownloadManager.java
    -index 66234da..6e38347 100644
    ---- a/core/java/android/app/DownloadManager.java
    -+++ b/core/java/android/app/DownloadManager.java
    -@@ -1089,7 +1089,7 @@ public class DownloadManager {
    -             if (cursor.moveToFirst()) {
    -                 int status = cursor.getInt(cursor.getColumnIndexOrThrow(COLUMN_STATUS));
    -                 if (DownloadManager.STATUS_SUCCESSFUL == status) {
    --                   return ContentUris.withAppendedId(Downloads.Impl.ALL_DOWNLOADS_CONTENT_URI, id);
    -+                    return ContentUris.withAppendedId(Downloads.Impl.ALL_DOWNLOADS_CONTENT_URI, id);
    -                 }
    -             }
    -         } finally {
    -diff --git a/core/java/android/app/Fragment.java b/core/java/android/app/Fragment.java
    -index 8afca78..5dead28 100644
    ---- a/core/java/android/app/Fragment.java
    -+++ b/core/java/android/app/Fragment.java
    -@@ -194,7 +194,7 @@ final class FragmentState implements Parcelable {
    -  * <div class="special reference">
    -  * <h3>Developer Guides</h3>
    -  * <p>For more information about using fragments, read the
    -- * <a href="{@docRoot}guide/topics/fundamentals/fragments.html">Fragments</a> developer guide.</p>
    -+ * <a href="{@docRoot}guide/components/fragments.html">Fragments</a> developer guide.</p>
    -  * </div>
    -  *
    -  * <a name="OlderPlatforms"></a>
    -diff --git a/core/java/android/app/FragmentHostCallback.java b/core/java/android/app/FragmentHostCallback.java
    -index e1d7136..d869168 100644
    ---- a/core/java/android/app/FragmentHostCallback.java
    -+++ b/core/java/android/app/FragmentHostCallback.java
    -@@ -340,6 +340,11 @@ public abstract class FragmentHostCallback<E> extends FragmentContainer {
    -     }
    - 
    -     void restoreLoaderNonConfig(ArrayMap<String, LoaderManager> loaderManagers) {
    -+        if (loaderManagers != null) {
    -+            for (int i = 0, N = loaderManagers.size(); i < N; i++) {
    -+                ((LoaderManagerImpl) loaderManagers.valueAt(i)).updateHostController(this);
    -+            }
    -+        }
    -         mAllLoaderManagers = loaderManagers;
    -     }
    - 
    -diff --git a/core/java/android/app/FragmentManager.java b/core/java/android/app/FragmentManager.java
    -index cd7665c..bfaf332 100644
    ---- a/core/java/android/app/FragmentManager.java
    -+++ b/core/java/android/app/FragmentManager.java
    -@@ -59,7 +59,7 @@ import java.util.List;
    -  * <div class="special reference">
    -  * <h3>Developer Guides</h3>
    -  * <p>For more information about using fragments, read the
    -- * <a href="{@docRoot}guide/topics/fundamentals/fragments.html">Fragments</a> developer guide.</p>
    -+ * <a href="{@docRoot}guide/components/fragments.html">Fragments</a> developer guide.</p>
    -  * </div>
    -  *
    -  * While the FragmentManager API was introduced in
    -diff --git a/core/java/android/app/IActivityManager.java b/core/java/android/app/IActivityManager.java
    -index e411e03..5a4470b 100644
    ---- a/core/java/android/app/IActivityManager.java
    -+++ b/core/java/android/app/IActivityManager.java
    -@@ -671,6 +671,18 @@ public interface IActivityManager extends IInterface {
    -      */
    -     public void setHasTopUi(boolean hasTopUi) throws RemoteException;
    - 
    -+    /**
    -+     * Returns if the target of the PendingIntent can be fired directly, without triggering
    -+     * a work profile challenge. This can happen if the PendingIntent is to start direct-boot
    -+     * aware activities, and the target user is in RUNNING_LOCKED state, i.e. we should allow
    -+     * direct-boot aware activity to bypass work challenge when the user hasn't unlocked yet.
    -+     * @param intent the {@link  PendingIntent} to be tested.
    -+     * @return {@code true} if the intent should not trigger a work challenge, {@code false}
    -+     *     otherwise.
    -+     * @throws RemoteException
    -+     */
    -+    public boolean canBypassWorkChallenge(PendingIntent intent) throws RemoteException;
    -+
    -     /*
    -      * Private non-Binder interfaces
    -      */
    -@@ -1062,4 +1074,5 @@ public interface IActivityManager extends IInterface {
    -     int SET_VR_THREAD_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION + 377;
    -     int SET_RENDER_THREAD_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION + 378;
    -     int SET_HAS_TOP_UI = IBinder.FIRST_CALL_TRANSACTION + 379;
    -+    int CAN_BYPASS_WORK_CHALLENGE = IBinder.FIRST_CALL_TRANSACTION + 380;
    - }
    -diff --git a/core/java/android/app/IApplicationThread.java b/core/java/android/app/IApplicationThread.java
    -index 559f69f..3fa88ae 100644
    ---- a/core/java/android/app/IApplicationThread.java
    -+++ b/core/java/android/app/IApplicationThread.java
    -@@ -67,7 +67,8 @@ public interface IApplicationThread extends IInterface {
    -             List<ReferrerIntent> pendingNewIntents, int configChanges, boolean notResumed,
    -             Configuration config, Configuration overrideConfig, boolean preserveWindow)
    -             throws RemoteException;
    --    void scheduleNewIntent(List<ReferrerIntent> intent, IBinder token) throws RemoteException;
    -+    void scheduleNewIntent(
    -+            List<ReferrerIntent> intent, IBinder token, boolean andPause) throws RemoteException;
    -     void scheduleDestroyActivity(IBinder token, boolean finished,
    -             int configChanges) throws RemoteException;
    -     void scheduleReceiver(Intent intent, ActivityInfo info, CompatibilityInfo compatInfo,
    -diff --git a/core/java/android/app/ITransientNotification.aidl b/core/java/android/app/ITransientNotification.aidl
    -index 35b53a4..d5b3ed0 100644
    ---- a/core/java/android/app/ITransientNotification.aidl
    -+++ b/core/java/android/app/ITransientNotification.aidl
    -@@ -19,7 +19,7 @@ package android.app;
    - 
    - /** @hide */
    - oneway interface ITransientNotification {
    --    void show();
    -+    void show(IBinder windowToken);
    -     void hide();
    - }
    - 
    -diff --git a/core/java/android/app/IntentService.java b/core/java/android/app/IntentService.java
    -index f33af39..e4a22c4 100644
    ---- a/core/java/android/app/IntentService.java
    -+++ b/core/java/android/app/IntentService.java
    -@@ -46,7 +46,8 @@ import android.os.Message;
    -  * <div class="special reference">
    -  * <h3>Developer Guides</h3>
    -  * <p>For a detailed discussion about how to create services, read the
    -- * <a href="{@docRoot}guide/topics/fundamentals/services.html">Services</a> developer guide.</p>
    -+ * <a href="{@docRoot}guide/components/services.html">Services</a> developer
    -+ * guide.</p>
    -  * </div>
    -  *
    -  * @see android.os.AsyncTask
    -diff --git a/core/java/android/app/LoaderManager.java b/core/java/android/app/LoaderManager.java
    -index c14dec9..bedf31a 100644
    ---- a/core/java/android/app/LoaderManager.java
    -+++ b/core/java/android/app/LoaderManager.java
    -@@ -195,6 +195,9 @@ public abstract class LoaderManager {
    -     public static void enableDebugLogging(boolean enabled) {
    -         LoaderManagerImpl.DEBUG = enabled;
    -     }
    -+
    -+    /** @hide for internal testing only */
    -+    public FragmentHostCallback getFragmentHostCallback() { return null; }
    - }
    - 
    - class LoaderManagerImpl extends LoaderManager {
    -@@ -542,6 +545,10 @@ class LoaderManagerImpl extends LoaderManager {
    -     void updateHostController(FragmentHostCallback host) {
    -         mHost = host;
    -     }
    -+
    -+    public FragmentHostCallback getFragmentHostCallback() {
    -+        return mHost;
    -+    }
    -     
    -     private LoaderInfo createLoader(int id, Bundle args,
    -             LoaderManager.LoaderCallbacks<Object> callback) {
    -diff --git a/core/java/android/app/LocalActivityManager.java b/core/java/android/app/LocalActivityManager.java
    -index 2a1e3c2..3b273bc 100644
    ---- a/core/java/android/app/LocalActivityManager.java
    -+++ b/core/java/android/app/LocalActivityManager.java
    -@@ -314,7 +314,7 @@ public class LocalActivityManager {
    -                     ArrayList<ReferrerIntent> intents = new ArrayList<>(1);
    -                     intents.add(new ReferrerIntent(intent, mParent.getPackageName()));
    -                     if (localLOGV) Log.v(TAG, r.id + ": new intent");
    --                    mActivityThread.performNewIntents(r, intents);
    -+                    mActivityThread.performNewIntents(r, intents, false /* andPause */);
    -                     r.intent = intent;
    -                     moveToState(r, mCurState);
    -                     if (mSingleMode) {
    -diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java
    -index 29ed97e..0dd9c63 100644
    ---- a/core/java/android/app/Notification.java
    -+++ b/core/java/android/app/Notification.java
    -@@ -19,6 +19,7 @@ package android.app;
    - import android.annotation.ColorInt;
    - import android.annotation.DrawableRes;
    - import android.annotation.IntDef;
    -+import android.annotation.NonNull;
    - import android.annotation.SdkConstant;
    - import android.annotation.SdkConstant.SdkConstantType;
    - import android.annotation.SystemApi;
    -@@ -1048,6 +1049,7 @@ public class Notification implements Parcelable
    -             this(Icon.createWithResource("", icon), title, intent, new Bundle(), null, false);
    -         }
    - 
    -+        /** Keep in sync with {@link Notification.Action.Builder#Builder(Action)}! */
    -         private Action(Icon icon, CharSequence title, PendingIntent intent, Bundle extras,
    -                 RemoteInput[] remoteInputs, boolean allowGeneratedReplies) {
    -             this.mIcon = icon;
    -@@ -1114,7 +1116,7 @@ public class Notification implements Parcelable
    -              */
    -             @Deprecated
    -             public Builder(int icon, CharSequence title, PendingIntent intent) {
    --                this(Icon.createWithResource("", icon), title, intent, new Bundle(), null);
    -+                this(Icon.createWithResource("", icon), title, intent);
    -             }
    - 
    -             /**
    -@@ -1124,7 +1126,7 @@ public class Notification implements Parcelable
    -              * @param intent the {@link PendingIntent} to fire when users trigger this action
    -              */
    -             public Builder(Icon icon, CharSequence title, PendingIntent intent) {
    --                this(icon, title, intent, new Bundle(), null);
    -+                this(icon, title, intent, new Bundle(), null, false);
    -             }
    - 
    -             /**
    -@@ -1133,12 +1135,13 @@ public class Notification implements Parcelable
    -              * @param action the action to read fields from.
    -              */
    -             public Builder(Action action) {
    --                this(action.getIcon(), action.title, action.actionIntent, new Bundle(action.mExtras),
    --                        action.getRemoteInputs());
    -+                this(action.getIcon(), action.title, action.actionIntent,
    -+                        new Bundle(action.mExtras), action.getRemoteInputs(),
    -+                        action.getAllowGeneratedReplies());
    -             }
    - 
    -             private Builder(Icon icon, CharSequence title, PendingIntent intent, Bundle extras,
    --                    RemoteInput[] remoteInputs) {
    -+                    RemoteInput[] remoteInputs, boolean allowGeneratedReplies) {
    -                 mIcon = icon;
    -                 mTitle = title;
    -                 mIntent = intent;
    -@@ -1147,6 +1150,7 @@ public class Notification implements Parcelable
    -                     mRemoteInputs = new ArrayList<RemoteInput>(remoteInputs.length);
    -                     Collections.addAll(mRemoteInputs, remoteInputs);
    -                 }
    -+                mAllowGeneratedReplies = allowGeneratedReplies;
    -             }
    - 
    -             /**
    -@@ -1229,7 +1233,7 @@ public class Notification implements Parcelable
    -                     getIcon(),
    -                     title,
    -                     actionIntent, // safe to alias
    --                    new Bundle(mExtras),
    -+                    mExtras == null ? new Bundle() : new Bundle(mExtras),
    -                     getRemoteInputs(),
    -                     getAllowGeneratedReplies());
    -         }
    -@@ -4649,12 +4653,12 @@ public class Notification implements Parcelable
    -         }
    - 
    -         /**
    --         * @param userDisplayName the name to be displayed for any replies sent by the user before the
    --         * posting app reposts the notification with those messages after they've been actually
    --         * sent and in previous messages sent by the user added in
    -+         * @param userDisplayName Required - the name to be displayed for any replies sent by the
    -+         * user before the posting app reposts the notification with those messages after they've
    -+         * been actually sent and in previous messages sent by the user added in
    -          * {@link #addMessage(Notification.MessagingStyle.Message)}
    -          */
    --        public MessagingStyle(CharSequence userDisplayName) {
    -+        public MessagingStyle(@NonNull CharSequence userDisplayName) {
    -             mUserDisplayName = userDisplayName;
    -         }
    - 
    -diff --git a/core/java/android/app/ResourcesManager.java b/core/java/android/app/ResourcesManager.java
    -index d2e0327..5cc064e 100644
    ---- a/core/java/android/app/ResourcesManager.java
    -+++ b/core/java/android/app/ResourcesManager.java
    -@@ -839,19 +839,22 @@ public class ResourcesManager {
    -                             tmpConfig = new Configuration();
    -                         }
    -                         tmpConfig.setTo(config);
    -+
    -+                        // Get new DisplayMetrics based on the DisplayAdjustments given
    -+                        // to the ResourcesImpl. Update a copy if the CompatibilityInfo
    -+                        // changed, because the ResourcesImpl object will handle the
    -+                        // update internally.
    -+                        DisplayAdjustments daj = r.getDisplayAdjustments();
    -+                        if (compat != null) {
    -+                            daj = new DisplayAdjustments(daj);
    -+                            daj.setCompatibilityInfo(compat);
    -+                        }
    -+                        dm = getDisplayMetrics(displayId, daj);
    -+
    -                         if (!isDefaultDisplay) {
    --                            // Get new DisplayMetrics based on the DisplayAdjustments given
    --                            // to the ResourcesImpl. Udate a copy if the CompatibilityInfo
    --                            // changed, because the ResourcesImpl object will handle the
    --                            // update internally.
    --                            DisplayAdjustments daj = r.getDisplayAdjustments();
    --                            if (compat != null) {
    --                                daj = new DisplayAdjustments(daj);
    --                                daj.setCompatibilityInfo(compat);
    --                            }
    --                            dm = getDisplayMetrics(displayId, daj);
    -                             applyNonDefaultDisplayMetricsToConfiguration(dm, tmpConfig);
    -                         }
    -+
    -                         if (hasOverrideConfiguration) {
    -                             tmpConfig.updateFrom(key.mOverrideConfiguration);
    -                         }
    -diff --git a/core/java/android/app/TimePickerDialog.java b/core/java/android/app/TimePickerDialog.java
    -index aca0763..3f467a0 100644
    ---- a/core/java/android/app/TimePickerDialog.java
    -+++ b/core/java/android/app/TimePickerDialog.java
    -@@ -16,6 +16,7 @@
    - 
    - package android.app;
    - 
    -+import android.annotation.TestApi;
    - import android.content.Context;
    - import android.content.DialogInterface;
    - import android.content.DialogInterface.OnClickListener;
    -@@ -91,6 +92,12 @@ public class TimePickerDialog extends AlertDialog implements OnClickListener,
    - 
    -     /**
    -      * Creates a new time picker dialog with the specified theme.
    -+     * <p>
    -+     * The theme is overlaid on top of the theme of the parent {@code context}.
    -+     * If {@code themeResId} is 0, the dialog will be inflated using the theme
    -+     * specified by the
    -+     * {@link android.R.attr#timePickerDialogTheme android:timePickerDialogTheme}
    -+     * attribute on the parent {@code context}'s theme.
    -      *
    -      * @param context the parent context
    -      * @param themeResId the resource ID of the theme to apply to this dialog
    -@@ -109,11 +116,6 @@ public class TimePickerDialog extends AlertDialog implements OnClickListener,
    -         mIs24HourView = is24HourView;
    - 
    -         final Context themeContext = getContext();
    --
    --
    --        final TypedValue outValue = new TypedValue();
    --        context.getTheme().resolveAttribute(R.attr.timePickerDialogTheme, outValue, true);
    --
    -         final LayoutInflater inflater = LayoutInflater.from(themeContext);
    -         final View view = inflater.inflate(R.layout.time_picker_dialog, null);
    -         setView(view);
    -@@ -128,6 +130,15 @@ public class TimePickerDialog extends AlertDialog implements OnClickListener,
    -         mTimePicker.setOnTimeChangedListener(this);
    -     }
    - 
    -+    /**
    -+     * @return the time picker displayed in the dialog
    -+     * @hide For testing only.
    -+     */
    -+    @TestApi
    -+    public TimePicker getTimePicker() {
    -+        return mTimePicker;
    -+    }
    -+
    -     @Override
    -     public void onTimeChanged(TimePicker view, int hourOfDay, int minute) {
    -         /* do nothing */
    -diff --git a/core/java/android/app/WallpaperManager.java b/core/java/android/app/WallpaperManager.java
    -index 219afea..aa0eaae 100644
    ---- a/core/java/android/app/WallpaperManager.java
    -+++ b/core/java/android/app/WallpaperManager.java
    -@@ -910,7 +910,7 @@ public class WallpaperManager {
    -      * wallpaper.
    -      */
    -     public void setResource(@RawRes int resid) throws IOException {
    --        setResource(resid, FLAG_SYSTEM);
    -+        setResource(resid, FLAG_SYSTEM | FLAG_LOCK);
    -     }
    - 
    -     /**
    -@@ -1016,7 +1016,7 @@ public class WallpaperManager {
    -      */
    -     public int setBitmap(Bitmap fullImage, Rect visibleCropHint, boolean allowBackup)
    -             throws IOException {
    --        return setBitmap(fullImage, visibleCropHint, allowBackup, FLAG_SYSTEM);
    -+        return setBitmap(fullImage, visibleCropHint, allowBackup, FLAG_SYSTEM | FLAG_LOCK);
    -     }
    - 
    -     /**
    -@@ -1154,7 +1154,7 @@ public class WallpaperManager {
    -      */
    -     public int setStream(InputStream bitmapData, Rect visibleCropHint, boolean allowBackup)
    -             throws IOException {
    --        return setStream(bitmapData, visibleCropHint, allowBackup, FLAG_SYSTEM);
    -+        return setStream(bitmapData, visibleCropHint, allowBackup, FLAG_SYSTEM | FLAG_LOCK);
    -     }
    - 
    -     /**
    -@@ -1393,6 +1393,7 @@ public class WallpaperManager {
    -      */
    -     @SystemApi
    -     public void clearWallpaper() {
    -+        clearWallpaper(FLAG_LOCK, mContext.getUserId());
    -         clearWallpaper(FLAG_SYSTEM, mContext.getUserId());
    -     }
    - 
    -diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
    -index 2a12ac8..a2f9bdd 100644
    ---- a/core/java/android/app/admin/DevicePolicyManager.java
    -+++ b/core/java/android/app/admin/DevicePolicyManager.java
    -@@ -417,6 +417,14 @@ public class DevicePolicyManager {
    -     public static final int NOTIFICATION_BUGREPORT_FINISHED_NOT_ACCEPTED = 3;
    - 
    -     /**
    -+     * Default and maximum timeout in milliseconds after which unlocking with weak auth times out,
    -+     * i.e. the user has to use a strong authentication method like password, PIN or pattern.
    -+     *
    -+     * @hide
    -+     */
    -+    public static final long DEFAULT_STRONG_AUTH_TIMEOUT_MS = 72 * 60 * 60 * 1000; // 72h
    -+
    -+    /**
    -      * A {@link android.os.Parcelable} extra of type {@link android.os.PersistableBundle} that
    -      * allows a mobile device management application or NFC programmer application which starts
    -      * managed provisioning to pass data to the management application instance after provisioning.
    -@@ -1276,6 +1284,33 @@ public class DevicePolicyManager {
    -     public static final int PASSWORD_QUALITY_MANAGED = 0x80000;
    - 
    -     /**
    -+     * @hide
    -+     *
    -+     * adb shell dpm set-{device,profile}-owner will normally not allow installing an owner to
    -+     * a user with accounts.  {@link #ACCOUNT_FEATURE_DEVICE_OR_PROFILE_OWNER_ALLOWED}
    -+     * and {@link #ACCOUNT_FEATURE_DEVICE_OR_PROFILE_OWNER_DISALLOWED} are the account features
    -+     * used by authenticator to exempt their accounts from this:
    -+     *
    -+     * <ul>
    -+     *     <li>Non-test-only DO/PO still can't be installed when there are accounts.
    -+     *     <p>In order to make an apk test-only, add android:testOnly="true" to the
    -+     *     &lt;application&gt; tag in the manifest.
    -+     *
    -+     *     <li>Test-only DO/PO can be installed even when there are accounts, as long as all the
    -+     *     accounts have the {@link #ACCOUNT_FEATURE_DEVICE_OR_PROFILE_OWNER_ALLOWED} feature.
    -+     *     Some authenticators claim to have any features, so to detect it, we also check
    -+     *     {@link #ACCOUNT_FEATURE_DEVICE_OR_PROFILE_OWNER_DISALLOWED} and disallow installing
    -+     *     if any of the accounts have it.
    -+     * </ul>
    -+     */
    -+    public static final String ACCOUNT_FEATURE_DEVICE_OR_PROFILE_OWNER_ALLOWED =
    -+            "android.account.DEVICE_OR_PROFILE_OWNER_ALLOWED";
    -+
    -+    /** @hide See {@link #ACCOUNT_FEATURE_DEVICE_OR_PROFILE_OWNER_ALLOWED} */
    -+    public static final String ACCOUNT_FEATURE_DEVICE_OR_PROFILE_OWNER_DISALLOWED =
    -+            "android.account.DEVICE_OR_PROFILE_OWNER_DISALLOWED";
    -+
    -+    /**
    -      * Called by an application that is administering the device to set the password restrictions it
    -      * is imposing. After setting this, the user will not be able to enter a new password that is
    -      * not at least as restrictive as what has been set. Note that the current password will remain
    -@@ -2219,6 +2254,7 @@ public class DevicePolicyManager {
    -      * @throws SecurityException if the calling application does not own an active administrator
    -      *             that uses {@link DeviceAdminInfo#USES_POLICY_RESET_PASSWORD}
    -      * @throws IllegalStateException if the calling user is locked or has a managed profile.
    -+     * @throws IllegalArgumentException if the password does not meet system requirements.
    -      */
    -     public boolean resetPassword(String password, int flags) {
    -         throwIfParentInstance("resetPassword");
    -@@ -2308,6 +2344,83 @@ public class DevicePolicyManager {
    -     }
    - 
    -     /**
    -+     * Called by a device/profile owner to set the timeout after which unlocking with secondary, non
    -+     * strong auth (e.g. fingerprint, trust agents) times out, i.e. the user has to use a strong
    -+     * authentication method like password, pin or pattern.
    -+     *
    -+     * <p>This timeout is used internally to reset the timer to require strong auth again after
    -+     * specified timeout each time it has been successfully used.
    -+     *
    -+     * <p>Fingerprint can also be disabled altogether using {@link #KEYGUARD_DISABLE_FINGERPRINT}.
    -+     *
    -+     * <p>Trust agents can also be disabled altogether using {@link #KEYGUARD_DISABLE_TRUST_AGENTS}.
    -+     *
    -+     * <p>The calling device admin must be a device or profile owner. If it is not,
    -+     * a {@link SecurityException} will be thrown.
    -+     *
    -+     * <p>The calling device admin can verify the value it has set by calling
    -+     * {@link #getRequiredStrongAuthTimeout(ComponentName)} and passing in its instance.
    -+     *
    -+     * <p>This method can be called on the {@link DevicePolicyManager} instance returned by
    -+     * {@link #getParentProfileInstance(ComponentName)} in order to set restrictions on the parent
    -+     * profile.
    -+     *
    -+     * @param admin Which {@link DeviceAdminReceiver} this request is associated with.
    -+     * @param timeoutMs The new timeout, after which the user will have to unlock with strong
    -+     *         authentication method. A value of 0 means the admin is not participating in
    -+     *         controlling the timeout.
    -+     *         The minimum and maximum timeouts are platform-defined and are typically 1 hour and
    -+     *         72 hours, respectively. Though discouraged, the admin may choose to require strong
    -+     *         auth at all times using {@link #KEYGUARD_DISABLE_FINGERPRINT} and/or
    -+     *         {@link #KEYGUARD_DISABLE_TRUST_AGENTS}.
    -+     *
    -+     * @throws SecurityException if {@code admin} is not a device or profile owner.
    -+     *
    -+     * @hide
    -+     */
    -+    public void setRequiredStrongAuthTimeout(@NonNull ComponentName admin,
    -+            long timeoutMs) {
    -+        if (mService != null) {
    -+            try {
    -+                mService.setRequiredStrongAuthTimeout(admin, timeoutMs, mParentInstance);
    -+            } catch (RemoteException e) {
    -+                throw e.rethrowFromSystemServer();
    -+            }
    -+        }
    -+    }
    -+
    -+    /**
    -+     * Determine for how long the user will be able to use secondary, non strong auth for
    -+     * authentication, since last strong method authentication (password, pin or pattern) was used.
    -+     * After the returned timeout the user is required to use strong authentication method.
    -+     *
    -+     * <p>This method can be called on the {@link DevicePolicyManager} instance
    -+     * returned by {@link #getParentProfileInstance(ComponentName)} in order to retrieve
    -+     * restrictions on the parent profile.
    -+     *
    -+     * @param admin The name of the admin component to check, or {@code null} to aggregate
    -+     *         accross all participating admins.
    -+     * @return The timeout or 0 if not configured for the provided admin.
    -+     *
    -+     * @hide
    -+     */
    -+    public long getRequiredStrongAuthTimeout(@Nullable ComponentName admin) {
    -+        return getRequiredStrongAuthTimeout(admin, myUserId());
    -+    }
    -+
    -+    /** @hide per-user version */
    -+    public long getRequiredStrongAuthTimeout(@Nullable ComponentName admin, @UserIdInt int userId) {
    -+        if (mService != null) {
    -+            try {
    -+                return mService.getRequiredStrongAuthTimeout(admin, userId, mParentInstance);
    -+            } catch (RemoteException e) {
    -+                throw e.rethrowFromSystemServer();
    -+            }
    -+        }
    -+        return DEFAULT_STRONG_AUTH_TIMEOUT_MS;
    -+    }
    -+
    -+    /**
    -      * Make the device lock immediately, as if the lock screen timeout has expired at the point of
    -      * this call.
    -      * <p>
    -@@ -6465,4 +6578,35 @@ public class DevicePolicyManager {
    -             throw new SecurityException(functionName + " cannot be called on the parent instance");
    -         }
    -     }
    -+
    -+    /**
    -+     * @hide
    -+     * Enable backup service.
    -+     * <p>This includes all backup and restore mechanisms.
    -+     * Setting this to {@code false} will make backup service no-op or return empty results.
    -+     *
    -+     * <p>There must be only one user on the device, managed by the device owner.
    -+     * Otherwise a {@link SecurityException} will be thrown.
    -+     *
    -+     * <p>Backup service is off by default when device owner is present.
    -+     */
    -+    public void setBackupServiceEnabled(@NonNull ComponentName admin, boolean enabled) {
    -+        try {
    -+            mService.setBackupServiceEnabled(admin, enabled);
    -+        } catch (RemoteException re) {
    -+            throw re.rethrowFromSystemServer();
    -+        }
    -+    }
    -+
    -+    /**
    -+     * @hide
    -+     * @return {@code true} if backup service is enabled, {@code false} otherwise.
    -+     */
    -+    public boolean isBackupServiceEnabled(@NonNull ComponentName admin) {
    -+        try {
    -+            return mService.isBackupServiceEnabled(admin);
    -+        } catch (RemoteException re) {
    -+            throw re.rethrowFromSystemServer();
    -+        }
    -+    }
    - }
    -diff --git a/core/java/android/app/admin/IDevicePolicyManager.aidl b/core/java/android/app/admin/IDevicePolicyManager.aidl
    -index 1036f04..f39cb5a 100644
    ---- a/core/java/android/app/admin/IDevicePolicyManager.aidl
    -+++ b/core/java/android/app/admin/IDevicePolicyManager.aidl
    -@@ -82,6 +82,9 @@ interface IDevicePolicyManager {
    -     long getMaximumTimeToLock(in ComponentName who, int userHandle, boolean parent);
    -     long getMaximumTimeToLockForUserAndProfiles(int userHandle);
    - 
    -+    void setRequiredStrongAuthTimeout(in ComponentName who, long timeMs, boolean parent);
    -+    long getRequiredStrongAuthTimeout(in ComponentName who, int userId, boolean parent);
    -+
    -     void lockNow(boolean parent);
    - 
    -     void wipeData(int flags);
    -@@ -305,4 +308,7 @@ interface IDevicePolicyManager {
    -     boolean isDeviceProvisioned();
    -     boolean isDeviceProvisioningConfigApplied();
    -     void setDeviceProvisioningConfigApplied();
    -+
    -+    void setBackupServiceEnabled(in ComponentName admin, boolean enabled);
    -+    boolean isBackupServiceEnabled(in ComponentName admin);
    - }
    -diff --git a/core/java/android/app/backup/BackupAgent.java b/core/java/android/app/backup/BackupAgent.java
    -index bc82806..bad6325 100644
    ---- a/core/java/android/app/backup/BackupAgent.java
    -+++ b/core/java/android/app/backup/BackupAgent.java
    -@@ -35,6 +35,8 @@ import android.system.StructStat;
    - import android.util.ArraySet;
    - import android.util.Log;
    - 
    -+import libcore.io.IoUtils;
    -+
    - import org.xmlpull.v1.XmlPullParserException;
    - 
    - import java.io.File;
    -@@ -647,10 +649,11 @@ public abstract class BackupAgent extends ContextWrapper {
    -                 File file = scanQueue.remove(0);
    -                 String filePath;
    -                 try {
    --                    // Ignore symlinks outright
    -+                    // Ignore things that aren't "real" files or dirs
    -                     StructStat stat = Os.lstat(file.getPath());
    --                    if (OsConstants.S_ISLNK(stat.st_mode)) {
    --                        if (DEBUG) Log.i(TAG, "Symlink (skipping)!: " + file);
    -+                    if (!OsConstants.S_ISREG(stat.st_mode)
    -+                            && !OsConstants.S_ISDIR(stat.st_mode)) {
    -+                        if (DEBUG) Log.i(TAG, "Not a file/dir (skipping)!: " + file);
    -                         continue;
    -                     }
    - 
    -@@ -921,6 +924,13 @@ public abstract class BackupAgent extends ContextWrapper {
    -                 } catch (RemoteException e) {
    -                     // we'll time out anyway, so we're safe
    -                 }
    -+
    -+                // Don't close the fd out from under the system service if this was local
    -+                if (Binder.getCallingPid() != Process.myPid()) {
    -+                    IoUtils.closeQuietly(oldState);
    -+                    IoUtils.closeQuietly(data);
    -+                    IoUtils.closeQuietly(newState);
    -+                }
    -             }
    -         }
    - 
    -@@ -951,6 +961,11 @@ public abstract class BackupAgent extends ContextWrapper {
    -                 } catch (RemoteException e) {
    -                     // we'll time out anyway, so we're safe
    -                 }
    -+
    -+                if (Binder.getCallingPid() != Process.myPid()) {
    -+                    IoUtils.closeQuietly(data);
    -+                    IoUtils.closeQuietly(newState);
    -+                }
    -             }
    -         }
    - 
    -@@ -994,6 +1009,10 @@ public abstract class BackupAgent extends ContextWrapper {
    -                 } catch (RemoteException e) {
    -                     // we'll time out anyway, so we're safe
    -                 }
    -+
    -+                if (Binder.getCallingPid() != Process.myPid()) {
    -+                    IoUtils.closeQuietly(data);
    -+                }
    -             }
    -         }
    - 
    -@@ -1041,6 +1060,10 @@ public abstract class BackupAgent extends ContextWrapper {
    -                 } catch (RemoteException e) {
    -                     // we'll time out anyway, so we're safe
    -                 }
    -+
    -+                if (Binder.getCallingPid() != Process.myPid()) {
    -+                    IoUtils.closeQuietly(data);
    -+                }
    -             }
    -         }
    - 
    -diff --git a/core/java/android/app/backup/BackupManager.java b/core/java/android/app/backup/BackupManager.java
    -index 7fcca09..80bc136 100644
    ---- a/core/java/android/app/backup/BackupManager.java
    -+++ b/core/java/android/app/backup/BackupManager.java
    -@@ -128,6 +128,14 @@ public class BackupManager {
    -     @SystemApi
    -     public static final int ERROR_AGENT_FAILURE = BackupTransport.AGENT_ERROR;
    - 
    -+    /**
    -+     * Intent extra when any subsidiary backup-related UI is launched from Settings:  does
    -+     * device policy or configuration permit backup operations to run at all?
    -+     *
    -+     * @hide
    -+     */
    -+    public static final String EXTRA_BACKUP_SERVICES_AVAILABLE = "backup_services_available";
    -+
    -     private Context mContext;
    -     private static IBackupManager sService;
    - 
    -diff --git a/core/java/android/app/package.html b/core/java/android/app/package.html
    -index f37f1dc..b259cad 100644
    ---- a/core/java/android/app/package.html
    -+++ b/core/java/android/app/package.html
    -@@ -34,7 +34,7 @@ action bar.</p>
    - <p>For information about using some the classes in this package, see the following
    - documents: <a href="{@docRoot}guide/topics/fundamentals/activities.html">Activities</a>, <a
    - href="{@docRoot}guide/topics/fundamentals/services.html">Services</a>, <a
    --href="{@docRoot}guide/topics/fundamentals/fragments.html">Fragments</a>, <a
    -+href="{@docRoot}guide/components/fragments.html">Fragments</a>, <a
    - href="{@docRoot}guide/topics/ui/actionbar.html">Using the Action Bar</a>, <a
    - href="{@docRoot}guide/topics/ui/dialogs.html">Creating Dialogs</a>, and <a
    - href="{@docRoot}guide/topics/ui/notifiers/index.html">Notifying the User</a>.</p>
    -diff --git a/core/java/android/bluetooth/BluetoothAdapter.java b/core/java/android/bluetooth/BluetoothAdapter.java
    -index 246a752..50c8e27 100644
    ---- a/core/java/android/bluetooth/BluetoothAdapter.java
    -+++ b/core/java/android/bluetooth/BluetoothAdapter.java
    -@@ -765,19 +765,13 @@ public final class BluetoothAdapter {
    -     public boolean enableBLE() {
    -         if (!isBleScanAlwaysAvailable()) return false;
    - 
    --        if (isLeEnabled() == true) {
    --            if (DBG) Log.d(TAG, "enableBLE(): BT is already enabled..!");
    --            try {
    --                mManagerService.updateBleAppCount(mToken, true);
    --            } catch (RemoteException e) {
    --                Log.e(TAG, "", e);
    --            }
    --            return true;
    --        }
    --
    -         try {
    --            if (DBG) Log.d(TAG, "Calling enableBLE");
    -             mManagerService.updateBleAppCount(mToken, true);
    -+            if (isLeEnabled()) {
    -+                if (DBG) Log.d(TAG, "enableBLE(): Bluetooth already enabled");
    -+                return true;
    -+            }
    -+            if (DBG) Log.d(TAG, "enableBLE(): Calling enable");
    -             return mManagerService.enable();
    -         } catch (RemoteException e) {
    -             Log.e(TAG, "", e);
    -@@ -2006,7 +2000,7 @@ public final class BluetoothAdapter {
    -     final private IBluetoothManagerCallback mManagerCallback =
    -         new IBluetoothManagerCallback.Stub() {
    -             public void onBluetoothServiceUp(IBluetooth bluetoothService) {
    --                if (VDBG) Log.d(TAG, "onBluetoothServiceUp: " + bluetoothService);
    -+                if (DBG) Log.d(TAG, "onBluetoothServiceUp: " + bluetoothService);
    - 
    -                 mServiceLock.writeLock().lock();
    -                 mService = bluetoothService;
    -@@ -2028,7 +2022,7 @@ public final class BluetoothAdapter {
    -             }
    - 
    -             public void onBluetoothServiceDown() {
    --                if (VDBG) Log.d(TAG, "onBluetoothServiceDown: " + mService);
    -+                if (DBG) Log.d(TAG, "onBluetoothServiceDown: " + mService);
    - 
    -                 try {
    -                     mServiceLock.writeLock().lock();
    -@@ -2056,7 +2050,7 @@ public final class BluetoothAdapter {
    -             }
    - 
    -             public void onBrEdrDown() {
    --                if (VDBG) Log.i(TAG, "on QBrEdrDown: ");
    -+                if (DBG) Log.i(TAG, "onBrEdrDown:");
    -             }
    -     };
    - 
    -diff --git a/core/java/android/bluetooth/BluetoothDevice.java b/core/java/android/bluetooth/BluetoothDevice.java
    -index 6d6dfeb..cd5eff2 100644
    ---- a/core/java/android/bluetooth/BluetoothDevice.java
    -+++ b/core/java/android/bluetooth/BluetoothDevice.java
    -@@ -1596,7 +1596,7 @@ public final class BluetoothDevice implements Parcelable {
    -                 // BLE is not supported
    -                 return null;
    -             }
    --            BluetoothGatt gatt = new BluetoothGatt(context, iGatt, this, transport);
    -+            BluetoothGatt gatt = new BluetoothGatt(iGatt, this, transport);
    -             gatt.connect(autoConnect, callback);
    -             return gatt;
    -         } catch (RemoteException e) {Log.e(TAG, "", e);}
    -diff --git a/core/java/android/bluetooth/BluetoothGatt.java b/core/java/android/bluetooth/BluetoothGatt.java
    -index 800dd43..552c8d3 100644
    ---- a/core/java/android/bluetooth/BluetoothGatt.java
    -+++ b/core/java/android/bluetooth/BluetoothGatt.java
    -@@ -41,7 +41,6 @@ public final class BluetoothGatt implements BluetoothProfile {
    -     private static final boolean DBG = true;
    -     private static final boolean VDBG = false;
    - 
    --    private final Context mContext;
    -     private IBluetoothGatt mService;
    -     private BluetoothGattCallback mCallback;
    -     private int mClientIf;
    -@@ -496,9 +495,8 @@ public final class BluetoothGatt implements BluetoothProfile {
    -             }
    -         };
    - 
    --    /*package*/ BluetoothGatt(Context context, IBluetoothGatt iGatt, BluetoothDevice device,
    -+    /*package*/ BluetoothGatt(IBluetoothGatt iGatt, BluetoothDevice device,
    -                                 int transport) {
    --        mContext = context;
    -         mService = iGatt;
    -         mDevice = device;
    -         mTransport = transport;
    -diff --git a/core/java/android/bluetooth/BluetoothGattServer.java b/core/java/android/bluetooth/BluetoothGattServer.java
    -index f451340..9f8d1a7 100644
    ---- a/core/java/android/bluetooth/BluetoothGattServer.java
    -+++ b/core/java/android/bluetooth/BluetoothGattServer.java
    -@@ -44,7 +44,6 @@ public final class BluetoothGattServer implements BluetoothProfile {
    -     private static final boolean DBG = true;
    -     private static final boolean VDBG = false;
    - 
    --    private final Context mContext;
    -     private BluetoothAdapter mAdapter;
    -     private IBluetoothGatt mService;
    -     private BluetoothGattServerCallback mCallback;
    -@@ -307,8 +306,7 @@ public final class BluetoothGattServer implements BluetoothProfile {
    -     /**
    -      * Create a BluetoothGattServer proxy object.
    -      */
    --    /*package*/ BluetoothGattServer(Context context, IBluetoothGatt iGatt, int transport) {
    --        mContext = context;
    -+    /*package*/ BluetoothGattServer(IBluetoothGatt iGatt, int transport) {
    -         mService = iGatt;
    -         mAdapter = BluetoothAdapter.getDefaultAdapter();
    -         mCallback = null;
    -diff --git a/core/java/android/bluetooth/BluetoothHealthAppConfiguration.java b/core/java/android/bluetooth/BluetoothHealthAppConfiguration.java
    -index 15a9101..1717a1e 100644
    ---- a/core/java/android/bluetooth/BluetoothHealthAppConfiguration.java
    -+++ b/core/java/android/bluetooth/BluetoothHealthAppConfiguration.java
    -@@ -68,7 +68,9 @@ public final class BluetoothHealthAppConfiguration implements Parcelable {
    -     public boolean equals(Object o) {
    -         if (o instanceof BluetoothHealthAppConfiguration) {
    -             BluetoothHealthAppConfiguration config = (BluetoothHealthAppConfiguration) o;
    --            // config.getName() can never be NULL
    -+
    -+            if (mName == null) return false;
    -+
    -             return mName.equals(config.getName()) &&
    -                     mDataType == config.getDataType() &&
    -                     mRole == config.getRole() &&
    -diff --git a/core/java/android/bluetooth/BluetoothManager.java b/core/java/android/bluetooth/BluetoothManager.java
    -index 00058a9..29283e7 100644
    ---- a/core/java/android/bluetooth/BluetoothManager.java
    -+++ b/core/java/android/bluetooth/BluetoothManager.java
    -@@ -236,7 +236,7 @@ public final class BluetoothManager {
    -                 Log.e(TAG, "Fail to get GATT Server connection");
    -                 return null;
    -             }
    --            BluetoothGattServer mGattServer = new BluetoothGattServer(context, iGatt,transport);
    -+            BluetoothGattServer mGattServer = new BluetoothGattServer(iGatt,transport);
    -             Boolean regStatus = mGattServer.registerCallback(callback);
    -             return regStatus? mGattServer : null;
    -         } catch (RemoteException e) {
    -diff --git a/core/java/android/content/ContentResolver.java b/core/java/android/content/ContentResolver.java
    -index b3320d6..daa1b93 100644
    ---- a/core/java/android/content/ContentResolver.java
    -+++ b/core/java/android/content/ContentResolver.java
    -@@ -1877,6 +1877,7 @@ public abstract class ContentResolver {
    -         if (extras != null) {
    -             String accountName = extras.getString(SYNC_EXTRAS_ACCOUNT);
    -             if (!TextUtils.isEmpty(accountName)) {
    -+                // TODO: No references to Google in AOSP
    -                 account = new Account(accountName, "com.google");
    -             }
    -             extras.remove(SYNC_EXTRAS_ACCOUNT);
    -diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
    -index 3f18ea9..3a2f471 100644
    ---- a/core/java/android/content/Context.java
    -+++ b/core/java/android/content/Context.java
    -@@ -1130,7 +1130,9 @@ public abstract class Context {
    -      * <strong>Note: you should not <em>rely</em> on the system deleting these
    -      * files for you; you should always have a reasonable maximum, such as 1 MB,
    -      * for the amount of space you consume with cache files, and prune those
    --     * files when exceeding that space.</strong>
    -+     * files when exceeding that space.</strong> If your app requires a larger
    -+     * cache (larger than 1 MB), you should use {@link #getExternalCacheDir()}
    -+     * instead.
    -      * <p>
    -      * The returned path may change over time if the calling app is moved to an
    -      * adopted storage device, so only relative paths should be persisted.
    -@@ -1142,6 +1144,7 @@ public abstract class Context {
    -      * @see #openFileOutput
    -      * @see #getFileStreamPath
    -      * @see #getDir
    -+     * @see #getExternalCacheDir
    -      */
    -     public abstract File getCacheDir();
    - 
    -@@ -1190,7 +1193,7 @@ public abstract class Context {
    -      * </ul>
    -      * <p>
    -      * If a shared storage device is emulated (as determined by
    --     * {@link Environment#isExternalStorageEmulated(File)}), it's contents are
    -+     * {@link Environment#isExternalStorageEmulated(File)}), its contents are
    -      * backed by a private user data partition, which means there is little
    -      * benefit to storing data here instead of the private directory returned by
    -      * {@link #getCacheDir()}.
    -@@ -2761,8 +2764,10 @@ public abstract class Context {
    -      *  <dd> A {@link android.net.ConnectivityManager ConnectivityManager} for
    -      *  handling management of network connections.
    -      *  <dt> {@link #WIFI_SERVICE} ("wifi")
    --     *  <dd> A {@link android.net.wifi.WifiManager WifiManager} for management of
    --     * Wi-Fi connectivity.
    -+     *  <dd> A {@link android.net.wifi.WifiManager WifiManager} for management of Wi-Fi
    -+     *  connectivity.  On releases before NYC, it should only be obtained from an application
    -+     *  context, and not from any other derived context to avoid memory leaks within the calling
    -+     *  process.
    -      *  <dt> {@link #WIFI_P2P_SERVICE} ("wifip2p")
    -      *  <dd> A {@link android.net.wifi.p2p.WifiP2pManager WifiP2pManager} for management of
    -      * Wi-Fi Direct connectivity.
    -diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java
    -index 4d9db98..c6aaa48 100644
    ---- a/core/java/android/content/Intent.java
    -+++ b/core/java/android/content/Intent.java
    -@@ -128,7 +128,7 @@ import static android.content.ContentProvider.maybeAddUserId;
    -  *     a list of people, which the user can browse through.  This example is a
    -  *     typical top-level entry into the Contacts application, showing you the
    -  *     list of people. Selecting a particular person to view would result in a
    -- *     new intent { <b>{@link #ACTION_VIEW} <i>content://contacts/N</i></b> }
    -+ *     new intent { <b>{@link #ACTION_VIEW} <i>content://contacts/people/N</i></b> }
    -  *     being used to start an activity to display that person.</p>
    -  *   </li>
    -  * </ul>
    -@@ -4314,6 +4314,14 @@ public class Intent implements Parcelable, Cloneable {
    -     public static final int FLAG_DEBUG_TRIAGED_MISSING = 0x00000100;
    - 
    -     /**
    -+     * Internal flag used to indicate ephemeral applications should not be
    -+     * considered when resolving the intent.
    -+     *
    -+     * @hide
    -+     */
    -+    public static final int FLAG_IGNORE_EPHEMERAL = 0x00000200;
    -+
    -+    /**
    -      * If set, the new activity is not kept in the history stack.  As soon as
    -      * the user navigates away from it, the activity is finished.  This may also
    -      * be set with the {@link android.R.styleable#AndroidManifestActivity_noHistory
    -@@ -6565,7 +6573,7 @@ public class Intent implements Parcelable, Cloneable {
    -      */
    -     public void removeUnsafeExtras() {
    -         if (mExtras != null) {
    --            mExtras.filterValues();
    -+            mExtras = mExtras.filterValues();
    -         }
    -     }
    - 
    -diff --git a/core/java/android/content/IntentFilter.java b/core/java/android/content/IntentFilter.java
    -index 22ab43b..f5a79c8 100644
    ---- a/core/java/android/content/IntentFilter.java
    -+++ b/core/java/android/content/IntentFilter.java
    -@@ -124,7 +124,7 @@ import java.util.Set;
    -  * <em>Note that authority matching here is <b>case sensitive</b>, unlike
    -  * formal RFC host names!</em>  You should thus always use lower case letters
    -  * for your authority.
    -- * 
    -+ *
    -  * <p><strong>Data Path</strong> matches if any of the given values match the
    -  * Intent's data path <em>and</em> both a scheme and authority in the filter
    -  * has matched against the Intent, <em>or</em> no paths were supplied in the
    -@@ -265,6 +265,7 @@ public class IntentFilter implements Parcelable {
    -     public static final String SCHEME_HTTPS = "https";
    - 
    -     private int mPriority;
    -+    private int mOrder;
    -     private final ArrayList<String> mActions;
    -     private ArrayList<String> mCategories = null;
    -     private ArrayList<String> mDataSchemes = null;
    -@@ -358,8 +359,8 @@ public class IntentFilter implements Parcelable {
    -      * the {@link MalformedMimeTypeException} exception that the constructor
    -      * can call and turns it into a runtime exception.
    -      *
    --     * @param action The action to match, i.e. Intent.ACTION_VIEW.
    --     * @param dataType The type to match, i.e. "vnd.android.cursor.dir/person".
    -+     * @param action The action to match, such as Intent.ACTION_VIEW.
    -+     * @param dataType The type to match, such as "vnd.android.cursor.dir/person".
    -      *
    -      * @return A new IntentFilter for the given action and type.
    -      *
    -@@ -386,7 +387,7 @@ public class IntentFilter implements Parcelable {
    -      * no data characteristics are subsequently specified, then the
    -      * filter will only match intents that contain no data.
    -      *
    --     * @param action The action to match, i.e. Intent.ACTION_MAIN.
    -+     * @param action The action to match, such as Intent.ACTION_MAIN.
    -      */
    -     public IntentFilter(String action) {
    -         mPriority = 0;
    -@@ -406,8 +407,8 @@ public class IntentFilter implements Parcelable {
    -      * <p>Throws {@link MalformedMimeTypeException} if the given MIME type is
    -      * not syntactically correct.
    -      *
    --     * @param action The action to match, i.e. Intent.ACTION_VIEW.
    --     * @param dataType The type to match, i.e. "vnd.android.cursor.dir/person".
    -+     * @param action The action to match, such as Intent.ACTION_VIEW.
    -+     * @param dataType The type to match, such as "vnd.android.cursor.dir/person".
    -      *
    -      */
    -     public IntentFilter(String action, String dataType)
    -@@ -425,6 +426,7 @@ public class IntentFilter implements Parcelable {
    -      */
    -     public IntentFilter(IntentFilter o) {
    -         mPriority = o.mPriority;
    -+        mOrder = o.mOrder;
    -         mActions = new ArrayList<String>(o.mActions);
    -         if (o.mCategories != null) {
    -             mCategories = new ArrayList<String>(o.mCategories);
    -@@ -477,6 +479,16 @@ public class IntentFilter implements Parcelable {
    -         return mPriority;
    -     }
    - 
    -+    /** @hide */
    -+    public final void setOrder(int order) {
    -+        mOrder = order;
    -+    }
    -+
    -+    /** @hide */
    -+    public final int getOrder() {
    -+        return mOrder;
    -+    }
    -+
    -     /**
    -      * Set whether this filter will needs to be automatically verified against its data URIs or not.
    -      * The default is false.
    -@@ -640,7 +652,7 @@ public class IntentFilter implements Parcelable {
    -      * in the filter, then an Intent's action must be one of those values for
    -      * it to match.  If no actions are included, the Intent action is ignored.
    -      *
    --     * @param action Name of the action to match, i.e. Intent.ACTION_VIEW.
    -+     * @param action Name of the action to match, such as Intent.ACTION_VIEW.
    -      */
    -     public final void addAction(String action) {
    -         if (!mActions.contains(action)) {
    -@@ -709,7 +721,7 @@ public class IntentFilter implements Parcelable {
    -      * <p>Throws {@link MalformedMimeTypeException} if the given MIME type is
    -      * not syntactically correct.
    -      *
    --     * @param type Name of the data type to match, i.e. "vnd.android.cursor.dir/person".
    -+     * @param type Name of the data type to match, such as "vnd.android.cursor.dir/person".
    -      *
    -      * @see #matchData
    -      */
    -@@ -786,7 +798,7 @@ public class IntentFilter implements Parcelable {
    -      * and any schemes you receive from outside of Android should be
    -      * converted to lower case before supplying them here.</em></p>
    -      *
    --     * @param scheme Name of the scheme to match, i.e. "http".
    -+     * @param scheme Name of the scheme to match, such as "http".
    -      *
    -      * @see #matchData
    -      */
    -@@ -897,7 +909,7 @@ public class IntentFilter implements Parcelable {
    -          * Determine whether this AuthorityEntry matches the given data Uri.
    -          * <em>Note that this comparison is case-sensitive, unlike formal
    -          * RFC host names.  You thus should always normalize to lower-case.</em>
    --         * 
    -+         *
    -          * @param data The Uri to match.
    -          * @return Returns either {@link IntentFilter#NO_MATCH_DATA},
    -          * {@link IntentFilter#MATCH_CATEGORY_PORT}, or
    -@@ -1352,7 +1364,7 @@ public class IntentFilter implements Parcelable {
    -      * filter has no impact on matching unless that category is specified in
    -      * the intent.
    -      *
    --     * @param category Name of category to match, i.e. Intent.CATEGORY_EMBED.
    -+     * @param category Name of category to match, such as Intent.CATEGORY_EMBED.
    -      */
    -     public final void addCategory(String category) {
    -         if (mCategories == null) mCategories = new ArrayList<String>();
    -diff --git a/core/java/android/content/SyncAdapterType.java b/core/java/android/content/SyncAdapterType.java
    -index 8a16ac9..6ef7fd2 100644
    ---- a/core/java/android/content/SyncAdapterType.java
    -+++ b/core/java/android/content/SyncAdapterType.java
    -@@ -16,6 +16,7 @@
    - 
    - package android.content;
    - 
    -+import android.annotation.Nullable;
    - import android.text.TextUtils;
    - import android.os.Parcelable;
    - import android.os.Parcel;
    -@@ -33,6 +34,7 @@ public class SyncAdapterType implements Parcelable {
    -     private final boolean isAlwaysSyncable;
    -     private final boolean allowParallelSyncs;
    -     private final String settingsActivity;
    -+    private final String packageName;
    - 
    -     public SyncAdapterType(String authority, String accountType, boolean userVisible,
    -             boolean supportsUploading) {
    -@@ -50,6 +52,7 @@ public class SyncAdapterType implements Parcelable {
    -         this.allowParallelSyncs = false;
    -         this.settingsActivity = null;
    -         this.isKey = false;
    -+        this.packageName = null;
    -     }
    - 
    -     /** @hide */
    -@@ -57,7 +60,8 @@ public class SyncAdapterType implements Parcelable {
    -             boolean supportsUploading,
    -             boolean isAlwaysSyncable,
    -             boolean allowParallelSyncs,
    --            String settingsActivity) {
    -+            String settingsActivity,
    -+            String packageName) {
    -         if (TextUtils.isEmpty(authority)) {
    -             throw new IllegalArgumentException("the authority must not be empty: " + authority);
    -         }
    -@@ -72,6 +76,7 @@ public class SyncAdapterType implements Parcelable {
    -         this.allowParallelSyncs = allowParallelSyncs;
    -         this.settingsActivity = settingsActivity;
    -         this.isKey = false;
    -+        this.packageName = packageName;
    -     }
    - 
    -     private SyncAdapterType(String authority, String accountType) {
    -@@ -89,6 +94,7 @@ public class SyncAdapterType implements Parcelable {
    -         this.allowParallelSyncs = false;
    -         this.settingsActivity = null;
    -         this.isKey = true;
    -+        this.packageName = null;
    -     }
    - 
    -     public boolean supportsUploading() {
    -@@ -148,6 +154,16 @@ public class SyncAdapterType implements Parcelable {
    -         return settingsActivity;
    -     }
    - 
    -+    /**
    -+     * The package hosting the sync adapter.
    -+     * @return The package name.
    -+     *
    -+     * @hide
    -+     */
    -+    public @Nullable String getPackageName() {
    -+        return packageName;
    -+    }
    -+
    -     public static SyncAdapterType newKey(String authority, String accountType) {
    -         return new SyncAdapterType(authority, accountType);
    -     }
    -@@ -181,6 +197,7 @@ public class SyncAdapterType implements Parcelable {
    -                     + ", isAlwaysSyncable=" + isAlwaysSyncable
    -                     + ", allowParallelSyncs=" + allowParallelSyncs
    -                     + ", settingsActivity=" + settingsActivity
    -+                    + ", packageName=" + packageName
    -                     + "}";
    -         }
    -     }
    -@@ -201,6 +218,7 @@ public class SyncAdapterType implements Parcelable {
    -         dest.writeInt(isAlwaysSyncable ? 1 : 0);
    -         dest.writeInt(allowParallelSyncs ? 1 : 0);
    -         dest.writeString(settingsActivity);
    -+        dest.writeString(packageName);
    -     }
    - 
    -     public SyncAdapterType(Parcel source) {
    -@@ -211,6 +229,7 @@ public class SyncAdapterType implements Parcelable {
    -                 source.readInt() != 0,
    -                 source.readInt() != 0,
    -                 source.readInt() != 0,
    -+                source.readString(),
    -                 source.readString());
    -     }
    - 
    -diff --git a/core/java/android/content/SyncAdaptersCache.java b/core/java/android/content/SyncAdaptersCache.java
    -index 6704b75..ddbdb8a 100644
    ---- a/core/java/android/content/SyncAdaptersCache.java
    -+++ b/core/java/android/content/SyncAdaptersCache.java
    -@@ -81,7 +81,7 @@ public class SyncAdaptersCache extends RegisteredServicesCache<SyncAdapterType>
    -                     sa.getString(com.android.internal.R.styleable
    -                             .SyncAdapter_settingsActivity);
    -             return new SyncAdapterType(authority, accountType, userVisible, supportsUploading,
    --                    isAlwaysSyncable, allowParallelSyncs, settingsActivity);
    -+                    isAlwaysSyncable, allowParallelSyncs, settingsActivity, packageName);
    -         } finally {
    -             sa.recycle();
    -         }
    -diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
    -index 281d6f6..a75f111 100644
    ---- a/core/java/android/content/pm/PackageManager.java
    -+++ b/core/java/android/content/pm/PackageManager.java
    -@@ -5431,7 +5431,7 @@ public abstract class PackageManager {
    -      * {@link #COMPONENT_ENABLED_STATE_DISABLED}, or
    -      * {@link #COMPONENT_ENABLED_STATE_DEFAULT}.  The last one means the
    -      * application's enabled state is based on the original information in
    --     * the manifest as found in {@link ComponentInfo}.
    -+     * the manifest as found in {@link ApplicationInfo}.
    -      * @throws IllegalArgumentException if the named package does not exist.
    -      */
    -     public abstract int getApplicationEnabledSetting(String packageName);
    -diff --git a/core/java/android/content/pm/PackageManagerInternal.java b/core/java/android/content/pm/PackageManagerInternal.java
    -index d208fe7..f5bcf64 100644
    ---- a/core/java/android/content/pm/PackageManagerInternal.java
    -+++ b/core/java/android/content/pm/PackageManagerInternal.java
    -@@ -160,4 +160,12 @@ public abstract class PackageManagerInternal {
    -      * Returns {@code true} if a given package can't be wiped. Otherwise, returns {@code false}.
    -      */
    -     public abstract boolean isPackageDataProtected(int userId, String packageName);
    -+
    -+    /**
    -+     * Gets whether the package was ever launched.
    -+     * @param packageName The package name.
    -+     * @param userId The user for which to check.
    -+     * @return Whether was launched.
    -+     */
    -+    public abstract boolean wasPackageEverLaunched(String packageName, int userId);
    - }
    -diff --git a/core/java/android/content/pm/ResolveInfo.java b/core/java/android/content/pm/ResolveInfo.java
    -index c9be6ed..b5df4d7 100644
    ---- a/core/java/android/content/pm/ResolveInfo.java
    -+++ b/core/java/android/content/pm/ResolveInfo.java
    -@@ -68,12 +68,6 @@ public class ResolveInfo implements Parcelable {
    -     public EphemeralResolveInfo ephemeralResolveInfo;
    - 
    -     /**
    --     * A ResolveInfo that points at the ephemeral installer.
    --     * @hide
    --     */
    --    public ResolveInfo ephemeralInstaller;
    --
    --    /**
    -      * The IntentFilter that was matched for this ResolveInfo.
    -      */
    -     public IntentFilter filter;
    -diff --git a/core/java/android/content/pm/ShortcutInfo.java b/core/java/android/content/pm/ShortcutInfo.java
    -index ed0ac53..a854b89 100644
    ---- a/core/java/android/content/pm/ShortcutInfo.java
    -+++ b/core/java/android/content/pm/ShortcutInfo.java
    -@@ -46,7 +46,7 @@ import java.util.List;
    - import java.util.Set;
    - 
    - /**
    -- * Represents a "launcher shortcut" that can be published via {@link ShortcutManager}.
    -+ * Represents a shortcut that can be published via {@link ShortcutManager}.
    -  *
    -  * @see ShortcutManager
    -  */
    -@@ -776,17 +776,17 @@ public final class ShortcutInfo implements Parcelable {
    -          * activity is published using
    -          * {@link ShortcutManager#addDynamicShortcuts(List)} or
    -          * {@link ShortcutManager#setDynamicShortcuts(List)},
    --         * the first main activity defined in the application's <code>AndroidManifest.xml</code>
    -+         * the first main activity defined in the app's <code>AndroidManifest.xml</code>
    -          * file is used.
    -          *
    -          * <li>Only "main" activities&mdash;ones that define the {@link Intent#ACTION_MAIN}
    -          * and {@link Intent#CATEGORY_LAUNCHER} intent filters&mdash;can be target
    -          * activities.
    -          *
    --         * <li>By default, the first main activity defined in the application manifest is
    -+         * <li>By default, the first main activity defined in the app's manifest is
    -          * the target activity.
    -          *
    --         * <li>A target activity must belong to the publisher application.
    -+         * <li>A target activity must belong to the publisher app.
    -          * </ul>
    -          *
    -          * @see ShortcutInfo#getActivity()
    -@@ -802,7 +802,7 @@ public final class ShortcutInfo implements Parcelable {
    -          *
    -          * <p>Icons are not available on {@link ShortcutInfo} instances
    -          * returned by {@link ShortcutManager} or {@link LauncherApps}.  The default launcher
    --         * application can use {@link LauncherApps#getShortcutIconDrawable(ShortcutInfo, int)}
    -+         * app can use {@link LauncherApps#getShortcutIconDrawable(ShortcutInfo, int)}
    -          * or {@link LauncherApps#getShortcutBadgedIconDrawable(ShortcutInfo, int)} to fetch
    -          * shortcut icons.
    -          *
    -@@ -933,8 +933,8 @@ public final class ShortcutInfo implements Parcelable {
    -         }
    - 
    -         /**
    --         * Sets categories for a shortcut.  Launcher applications may use this information to
    --         * categorise shortcuts.
    -+         * Sets categories for a shortcut.  Launcher apps may use this information to
    -+         * categorize shortcuts.
    -          *
    -          * @see #SHORTCUT_CATEGORY_CONVERSATION
    -          * @see ShortcutInfo#getCategories()
    -@@ -953,9 +953,9 @@ public final class ShortcutInfo implements Parcelable {
    -          * {@link ShortcutManager#addDynamicShortcuts(List)} or
    -          * {@link ShortcutManager#setDynamicShortcuts(List)}.
    -          *
    --         * <p>A shortcut can launch any intent that the publisher application has permission to
    -+         * <p>A shortcut can launch any intent that the publisher app has permission to
    -          * launch.  For example, a shortcut can launch an unexported activity within the publisher
    --         * application.  A shortcut intent doesn't have to point at the target activity.
    -+         * app.  A shortcut intent doesn't have to point at the target activity.
    -          *
    -          * <p>The given {@code intent} can contain extras, but these extras must contain values
    -          * of primitive types in order for the system to persist these values.
    -@@ -970,7 +970,9 @@ public final class ShortcutInfo implements Parcelable {
    - 
    -         /**
    -          * Sets multiple intents instead of a single intent, in order to launch an activity with
    --         * other activities in back stack.  Use {@link TaskStackBuilder} to build intents.
    -+         * other activities in back stack.  Use {@link TaskStackBuilder} to build intents. The
    -+         * last element in the list represents the only intent that doesn't place an activity on
    -+         * the back stack.
    -          * See the {@link ShortcutManager} javadoc for details.
    -          *
    -          * @see Builder#setIntent(Intent)
    -@@ -1006,9 +1008,9 @@ public final class ShortcutInfo implements Parcelable {
    -         }
    - 
    -         /**
    --         * Extras that application can set for any purpose.
    -+         * Extras that the app can set for any purpose.
    -          *
    --         * <p>Applications can store arbitrary shortcut metadata in extras and retrieve the
    -+         * <p>Apps can store arbitrary shortcut metadata in extras and retrieve the
    -          * metadata later using {@link ShortcutInfo#getExtras()}.
    -          */
    -         @NonNull
    -@@ -1029,7 +1031,7 @@ public final class ShortcutInfo implements Parcelable {
    -     /**
    -      * Returns the ID of a shortcut.
    -      *
    --     * <p>Shortcut IDs are unique within each publisher application and must be stable across
    -+     * <p>Shortcut IDs are unique within each publisher app and must be stable across
    -      * devices so that shortcuts will still be valid when restored on a different device.
    -      * See {@link ShortcutManager} for details.
    -      */
    -@@ -1039,7 +1041,7 @@ public final class ShortcutInfo implements Parcelable {
    -     }
    - 
    -     /**
    --     * Return the package name of the publisher application.
    -+     * Return the package name of the publisher app.
    -      */
    -     @NonNull
    -     public String getPackage() {
    -@@ -1050,7 +1052,7 @@ public final class ShortcutInfo implements Parcelable {
    -      * Return the target activity.
    -      *
    -      * <p>This has nothing to do with the activity that this shortcut will launch.
    --     * Launcher applications should show the launcher icon for the returned activity alongside
    -+     * Launcher apps should show the launcher icon for the returned activity alongside
    -      * this shortcut.
    -      *
    -      * @see Builder#setActivity
    -@@ -1102,7 +1104,7 @@ public final class ShortcutInfo implements Parcelable {
    -     }
    - 
    -     /**
    --     * Return the shorter description of a shortcut.
    -+     * Return the short description of a shortcut.
    -      *
    -      * @see Builder#setShortLabel(CharSequence)
    -      */
    -@@ -1117,7 +1119,7 @@ public final class ShortcutInfo implements Parcelable {
    -     }
    - 
    -     /**
    --     * Return the longer description of a shortcut.
    -+     * Return the long description of a shortcut.
    -      *
    -      * @see Builder#setLongLabel(CharSequence)
    -      */
    -@@ -1161,7 +1163,7 @@ public final class ShortcutInfo implements Parcelable {
    -      * Returns the intent that is executed when the user selects this shortcut.
    -      * If setIntents() was used, then return the last intent in the array.
    -      *
    --     * <p>Launcher applications <b>cannot</b> see the intent.  If a {@link ShortcutInfo} is
    -+     * <p>Launcher apps <b>cannot</b> see the intent.  If a {@link ShortcutInfo} is
    -      * obtained via {@link LauncherApps}, then this method will always return null.
    -      * Launchers can only start a shortcut intent with {@link LauncherApps#startShortcut}.
    -      *
    -@@ -1180,7 +1182,7 @@ public final class ShortcutInfo implements Parcelable {
    -     /**
    -      * Return the intent set with {@link Builder#setIntents(Intent[])}.
    -      *
    --     * <p>Launcher applications <b>cannot</b> see the intents.  If a {@link ShortcutInfo} is
    -+     * <p>Launcher apps <b>cannot</b> see the intents.  If a {@link ShortcutInfo} is
    -      * obtained via {@link LauncherApps}, then this method will always return null.
    -      * Launchers can only start a shortcut intent with {@link LauncherApps#startShortcut}.
    -      *
    -@@ -1219,15 +1221,15 @@ public final class ShortcutInfo implements Parcelable {
    - 
    -     /**
    -      * "Rank" of a shortcut, which is a non-negative, sequential value that's unique for each
    --     * {@link #getActivity} for each of the two kinds, dynamic shortcuts and manifest shortcuts.
    -+     * {@link #getActivity} for each of the two types of shortcuts (static and dynamic).
    -      *
    --     * <p>Because manifest shortcuts and dynamic shortcuts have overlapping ranks,
    --     * when a launcher application shows shortcuts for an activity, it should first show
    --     * the manifest shortcuts followed by the dynamic shortcuts.  Within each of those categories,
    -+     * <p>Because static shortcuts and dynamic shortcuts have overlapping ranks,
    -+     * when a launcher app shows shortcuts for an activity, it should first show
    -+     * the static shortcuts, followed by the dynamic shortcuts.  Within each of those categories,
    -      * shortcuts should be sorted by rank in ascending order.
    -      *
    --     * <p>"Floating" shortcuts (i.e. shortcuts that are neither dynamic nor manifest) will all
    --     * have rank 0, because there's no sorting for them.
    -+     * <p><em>Floating shortcuts</em>, or shortcuts that are neither static nor dynamic, will all
    -+     * have rank 0, because they aren't sorted.
    -      *
    -      * See the {@link ShortcutManager}'s class javadoc for details.
    -      *
    -@@ -1274,7 +1276,7 @@ public final class ShortcutInfo implements Parcelable {
    -     }
    - 
    -     /**
    --     * Extras that application can set to any purposes.
    -+     * Extras that the app can set for any purpose.
    -      *
    -      * @see Builder#setExtras(PersistableBundle)
    -      */
    -@@ -1339,12 +1341,13 @@ public final class ShortcutInfo implements Parcelable {
    -     }
    - 
    -     /**
    --     * Return whether a shortcut is published from AndroidManifest.xml or not.  If {@code true},
    --     * it's also {@link #isImmutable()}.
    -+     * Return whether a shortcut is static; that is, whether a shortcut is
    -+     * published from AndroidManifest.xml.  If {@code true}, the shortcut is
    -+     * also {@link #isImmutable()}.
    -      *
    -      * <p>When an app is upgraded and a shortcut is no longer published from AndroidManifest.xml,
    --     * this will be set to {@code false}.  If the shortcut is not pinned, then it'll just disappear.
    --     * However, if it's pinned, it will still be alive, and {@link #isEnabled()} will be
    -+     * this will be set to {@code false}.  If the shortcut is not pinned, then it'll disappear.
    -+     * However, if it's pinned, it will still be visible, {@link #isEnabled()} will be
    -      * {@code false} and {@link #isImmutable()} will be {@code true}.
    -      */
    -     public boolean isDeclaredInManifest() {
    -@@ -1358,7 +1361,7 @@ public final class ShortcutInfo implements Parcelable {
    -     }
    - 
    -     /**
    --     * @return true if pinned but neither dynamic nor manifest.
    -+     * @return true if pinned but neither static nor dynamic.
    -      * @hide
    -      */
    -     public boolean isFloating() {
    -@@ -1374,9 +1377,10 @@ public final class ShortcutInfo implements Parcelable {
    -      * Return if a shortcut is immutable, in which case it cannot be modified with any of
    -      * {@link ShortcutManager} APIs.
    -      *
    --     * <p>All manifest shortcuts are immutable.  When a manifest shortcut is pinned and then
    --     * disabled because the app is upgraded and its AndroidManifest.xml no longer publishes it,
    --     * {@link #isDeclaredInManifest()} returns {@code false}, but it is still immutable.
    -+     * <p>All static shortcuts are immutable.  When a static shortcut is pinned and is then
    -+     * disabled because it doesn't appear in AndroidManifest.xml for a newer version of the
    -+     * app, {@link #isDeclaredInManifest()} returns {@code false}, but the shortcut
    -+     * is still immutable.
    -      *
    -      * <p>All shortcuts originally published via the {@link ShortcutManager} APIs
    -      * are all mutable.
    -@@ -1561,7 +1565,7 @@ public final class ShortcutInfo implements Parcelable {
    -     }
    - 
    -     /**
    --     * Replaces the intent
    -+     * Replaces the intent.
    -      *
    -      * @throws IllegalArgumentException when extra is not compatible with {@link PersistableBundle}.
    -      *
    -diff --git a/core/java/android/content/pm/ShortcutManager.java b/core/java/android/content/pm/ShortcutManager.java
    -index cd248ea..a93870e 100644
    ---- a/core/java/android/content/pm/ShortcutManager.java
    -+++ b/core/java/android/content/pm/ShortcutManager.java
    -@@ -31,87 +31,90 @@ import com.android.internal.annotations.VisibleForTesting;
    - import java.util.List;
    - 
    - /**
    -- * The ShortcutManager manages "launcher shortcuts" (or simply "shortcuts").  Shortcuts provide
    -- * users
    -- * with quick access to activities other than an application's main activity in the currently-active
    -+ * The ShortcutManager manages an app's <em>shortcuts</em>. Shortcuts provide users
    -+ * with quick access to activities other than an app's main activity in the currently-active
    -  * launcher.  For example,
    -- * an email application may publish the "compose new email" action, which will directly open the
    -+ * an email app may publish the "compose new email" action, which will directly open the
    -  * compose activity.  The {@link ShortcutInfo} class contains information about each of the
    -  * shortcuts themselves.
    -  *
    -- * <h3>Dynamic Shortcuts and Manifest Shortcuts</h3>
    -+ * <h3>Static Shortcuts and Dynamic Shortcuts</h3>
    -  *
    -- * There are two ways to publish shortcuts: manifest shortcuts and dynamic shortcuts.
    -+ * <p>
    -+ * There are two ways to publish shortcuts: static shortcuts and dynamic shortcuts.
    -  *
    -  * <ul>
    -- * <li>Manifest shortcuts are declared in a resource
    -- * XML, which is referenced in the publisher application's <code>AndroidManifest.xml</code> file.
    -- * Manifest shortcuts are published when an application is installed,
    -- * and the details of these shortcuts change when an application is upgraded with an updated XML
    -+ * <li>Static shortcuts are declared in a resource
    -+ * XML file, which is referenced in the publisher app's <code>AndroidManifest.xml</code> file.
    -+ * Static shortcuts are published when an app is installed,
    -+ * and the details of these shortcuts change when an app is upgraded with an updated XML
    -  * file.
    -- * Manifest shortcuts are immutable, and their
    -+ * Static shortcuts are immutable, and their
    -  * definitions, such as icons and labels, cannot be changed dynamically without upgrading the
    -- * publisher application.
    -+ * publisher app.
    -  *
    -- * <li>Dynamic shortcuts are published at runtime using the {@link ShortcutManager} APIs.
    -- * Applications can publish, update, and remove dynamic shortcuts at runtime.
    -+ * <li>Dynamic shortcuts are published at runtime using this class's APIs.
    -+ * Apps can publish, update, and remove dynamic shortcuts at runtime.
    -  * </ul>
    -  *
    -- * <p>Only "main" activities&mdash;activities that handle the {@code MAIN} action and the
    -+ * <p>Only main activities&mdash;activities that handle the {@code MAIN} action and the
    -  * {@code LAUNCHER} category&mdash;can have shortcuts.
    -- * If an application has multiple main activities, these activities will have different sets
    -+ * If an app has multiple main activities, these activities have different sets
    -  * of shortcuts.
    -  *
    -- * <p>Dynamic shortcuts and manifest shortcuts are shown in the currently active launcher when
    -- * the user long-presses on an application launcher icon.  The actual gesture may be different
    -- * depending on the launcher application.
    -+ * <p>Static shortcuts and dynamic shortcuts are shown in the currently active launcher when
    -+ * the user long-presses on an app's launcher icon.
    -+ *
    -+ * <p class="note"><strong>Note: </strong>The actual gesture may be different
    -+ * depending on the launcher app.
    -  *
    -  * <p>Each launcher icon can have at most {@link #getMaxShortcutCountPerActivity()} number of
    -- * dynamic and manifest shortcuts combined.
    -+ * static and dynamic shortcuts combined.
    -  *
    -  *
    -  * <h3>Pinning Shortcuts</h3>
    -  *
    -- * Launcher applications allow users to "pin" shortcuts so they're easier to access.  Both manifest
    -+ * <p>
    -+ * Launcher apps allow users to <em>pin</em> shortcuts so they're easier to access.  Both static
    -  * and dynamic shortcuts can be pinned.
    -  * Pinned shortcuts <b>cannot</b> be removed by publisher
    -- * applications; they're removed only when the user removes them,
    -- * when the publisher application is uninstalled, or when the
    -- * user performs the "clear data" action on the publisher application from the device's Settings
    -- * application.
    -+ * apps; they're removed only when the user removes them,
    -+ * when the publisher app is uninstalled, or when the
    -+ * user performs the <strong>clear data</strong> action on the publisher app from the device's Settings
    -+ * app.
    -  *
    -- * <p>However, the publisher application can <em>disable</em> pinned shortcuts so they cannot be
    -+ * <p>However, the publisher app can <em>disable</em> pinned shortcuts so they cannot be
    -  * started.  See the following sections for details.
    -  *
    -  *
    -  * <h3>Updating and Disabling Shortcuts</h3>
    -  *
    -  * <p>When a dynamic shortcut is pinned, even when the publisher removes it as a dynamic shortcut,
    -- * the pinned shortcut will still be visible and launchable.  This allows an application to have
    -+ * the pinned shortcut will still be visible and launchable.  This allows an app to have
    -  * more than {@link #getMaxShortcutCountPerActivity()} number of shortcuts.
    -  *
    -  * <p>For example, suppose {@link #getMaxShortcutCountPerActivity()} is 5:
    -- * <ul>
    -- *     <li>A chat application publishes 5 dynamic shortcuts for the 5 most recent
    -- *     conversations, "c1" - "c5".
    -+ * <ol>
    -+ *     <li>A chat app publishes 5 dynamic shortcuts for the 5 most recent
    -+ *     conversations (c1, c2, ..., c5).
    -  *
    -  *     <li>The user pins all 5 of the shortcuts.
    -  *
    -- *     <li>Later, the user has started 3 additional conversations ("c6", "c7", and "c8"),
    -- *     so the publisher application
    -+ *     <li>Later, the user has started 3 additional conversations (c6, c7, and c8),
    -+ *     so the publisher app
    -  *     re-publishes its dynamic shortcuts.  The new dynamic shortcut list is:
    -- *     "c4", "c5", "c6", "c7", and "c8".
    -- *     The publisher application has to remove "c1", "c2", and "c3" because it can't have more than
    -+ *     c4, c5, ..., c8.
    -+ *     The publisher app has to remove c1, c2, and c3 because it can't have more than
    -  *     5 dynamic shortcuts.
    -  *
    -- *     <li>However, even though "c1", "c2" and "c3" are no longer dynamic shortcuts, the pinned
    -+ *     <li>However, even though c1, c2, and c3 are no longer dynamic shortcuts, the pinned
    -  *     shortcuts for these conversations are still available and launchable.
    -  *
    -  *     <li>At this point, the user can access a total of 8 shortcuts that link to activities in
    -- *     the publisher application, including the 3 pinned
    -- *     shortcuts, even though it's allowed to have at most 5 dynamic shortcuts.
    -+ *     the publisher app, including the 3 pinned
    -+ *     shortcuts, even though an app can have at most 5 dynamic shortcuts.
    -  *
    -- *     <li>The application can use {@link #updateShortcuts(List)} to update any of the existing
    -+ *     <li>The app can use {@link #updateShortcuts(List)} to update <em>any</em> of the existing
    -  *     8 shortcuts, when, for example, the chat peers' icons have changed.
    -  * </ul>
    -  * The {@link #addDynamicShortcuts(List)} and {@link #setDynamicShortcuts(List)} methods
    -@@ -121,104 +124,108 @@ import java.util.List;
    -  * lists of shortcuts to dynamic shortcuts.
    -  *
    -  *
    -- * <h4>Disabling Manifest Shortcuts</h4>
    -- * When an application is upgraded and the new version
    -- * no longer uses a manifest shortcut that appeared in the previous version, this deprecated
    -- * shortcut will no longer be published as a manifest shortcut.
    -+ * <h4>Disabling Static Shortcuts</h4>
    -+ * When an app is upgraded and the new version
    -+ * no longer uses a static shortcut that appeared in the previous version, this deprecated
    -+ * shortcut will no longer be published as a static shortcut.
    -  *
    -  * <p>If the deprecated shortcut is pinned, then the pinned shortcut will remain on the launcher,
    -  * but it will be disabled automatically.
    -- * Note that, in this case, the pinned shortcut is no longer a manifest shortcut, but it's
    -- * still <b>immutable</b> and cannot be updated using the {@link ShortcutManager} APIs.
    -+ * Note that, in this case, the pinned shortcut is no longer a static shortcut, but it's
    -+ * still <b>immutable</b>. Therefore, it cannot be updated using this class's APIs.
    -  *
    -  *
    -  * <h4>Disabling Dynamic Shortcuts</h4>
    -  * Sometimes pinned shortcuts become obsolete and may not be usable.  For example, a pinned shortcut
    -- * to a group chat will be unusable when the associated group chat is deleted.  In cases like this,
    -- * applications should use {@link #disableShortcuts(List)}, which will remove the specified dynamic
    -- * shortcuts and also make any specified pinned shortcuts un-launchable.
    -+ * to a group chat becomes unusable when the associated group chat is deleted.  In cases like this,
    -+ * apps should use {@link #disableShortcuts(List)}, which removes the specified dynamic
    -+ * shortcuts and also makes any specified pinned shortcuts un-launchable.
    -  * The {@link #disableShortcuts(List, CharSequence)} method can also be used to disabled shortcuts
    -  * and show users a custom error message when they attempt to launch the disabled shortcuts.
    -  *
    -  *
    -- * <h3>Publishing Manifest Shortcuts</h3>
    -+ * <h3>Publishing Static Shortcuts</h3>
    -  *
    -- * In order to add manifest shortcuts to your application, first add
    -+ * <p>
    -+ * In order to add static shortcuts to your app, first add
    -  * {@code <meta-data android:name="android.app.shortcuts" />} to your main activity in
    -  * AndroidManifest.xml:
    -  * <pre>
    -- * &lt;manifest xmlns:android=&quot;http://schemas.android.com/apk/res/android&quot;
    -- *   package=&quot;com.example.myapplication&quot;&gt;
    -- *   &lt;application . . .&gt;
    -- *     &lt;activity android:name=&quot;Main&quot;&gt;
    -- *       &lt;intent-filter&gt;
    -- *         &lt;action android:name=&quot;android.intent.action.MAIN&quot; /&gt;
    -- *         &lt;category android:name=&quot;android.intent.category.LAUNCHER&quot; /&gt;
    -- *       &lt;/intent-filter&gt;
    -- *       <b>&lt;meta-data android:name=&quot;android.app.shortcuts&quot; android:resource=&quot;@xml/shortcuts&quot;/&gt;</b>
    -- *     &lt;/activity&gt;
    -- *   &lt;/application&gt;
    -- * &lt;/manifest&gt;
    -+ *&lt;manifest xmlns:android="http://schemas.android.com/apk/res/android"
    -+ *             package="com.example.myapplication"&gt;
    -+ *  &lt;application ... &gt;
    -+ *    &lt;activity android:name="Main"&gt;
    -+ *      &lt;intent-filter&gt;
    -+ *        &lt;action android:name="android.intent.action.MAIN" /&gt;
    -+ *        &lt;category android:name="android.intent.category.LAUNCHER" /&gt;
    -+ *      &lt;/intent-filter&gt;
    -+ *      <strong>&lt;meta-data android:name="android.app.shortcuts"
    -+ *                 android:resource="@xml/shortcuts" /&gt;</strong>
    -+ *    &lt;/activity&gt;
    -+ *  &lt;/application&gt;
    -+ *&lt;/manifest&gt;
    -  * </pre>
    -  *
    -- * Then, define your application's manifest shortcuts in the <code>res/xml/shortcuts.xml</code>
    -+ * Then, define your app's static shortcuts in the <code>res/xml/shortcuts.xml</code>
    -  * file:
    -  * <pre>
    -- * &lt;shortcuts xmlns:android=&quot;http://schemas.android.com/apk/res/android&quot; &gt;
    -- *   &lt;shortcut
    -- *     android:shortcutId=&quot;compose&quot;
    -- *     android:enabled=&quot;true&quot;
    -- *     android:icon=&quot;@drawable/compose_icon&quot;
    -- *     android:shortcutShortLabel=&quot;@string/compose_shortcut_short_label1&quot;
    -- *     android:shortcutLongLabel=&quot;@string/compose_shortcut_long_label1&quot;
    -- *     android:shortcutDisabledMessage=&quot;@string/compose_disabled_message1&quot;
    -- *     &gt;
    -- *     &lt;intent
    -- *       android:action=&quot;android.intent.action.VIEW&quot;
    -- *       android:targetPackage=&quot;com.example.myapplication&quot;
    -- *       android:targetClass=&quot;com.example.myapplication.ComposeActivity&quot; /&gt;
    -- *     &lt;!-- more intents can go here; see below --&gt;
    -- *     &lt;categories android:name=&quot;android.shortcut.conversation&quot; /&gt;
    -- *   &lt;/shortcut&gt;
    -- *   &lt;!-- more shortcuts can go here --&gt;
    -- * &lt;/shortcuts&gt;
    -+ *&lt;shortcuts xmlns:android="http://schemas.android.com/apk/res/android"&gt;
    -+ *  &lt;shortcut
    -+ *    android:shortcutId="compose"
    -+ *    android:enabled="true"
    -+ *    android:icon="@drawable/compose_icon"
    -+ *    android:shortcutShortLabel="@string/compose_shortcut_short_label1"
    -+ *    android:shortcutLongLabel="@string/compose_shortcut_long_label1"
    -+ *    android:shortcutDisabledMessage="@string/compose_disabled_message1"&gt;
    -+ *    &lt;intent
    -+ *      android:action="android.intent.action.VIEW"
    -+ *      android:targetPackage="com.example.myapplication"
    -+ *      android:targetClass="com.example.myapplication.ComposeActivity" /&gt;
    -+ *    &lt;!-- If your shortcut is associated with multiple intents, include them
    -+ *         here. The last intent in the list is what the user sees when they
    -+ *         launch this shortcut. --&gt;
    -+ *    &lt;categories android:name="android.shortcut.conversation" /&gt;
    -+ *  &lt;/shortcut&gt;
    -+ *  &lt;!-- Specify more shortcuts here. --&gt;
    -+ *&lt;/shortcuts&gt;
    -  * </pre>
    -  *
    -- * The following list includes descriptions for the different attributes within a manifest shortcut:
    -+ * The following list includes descriptions for the different attributes within a static shortcut:
    -  * <dl>
    -- *   <dt>android:shortcutId</dt>
    -+ *   <dt>{@code android:shortcutId}</dt>
    -  *   <dd>Mandatory shortcut ID</dd>
    -  *
    -- *   <dt>android:enabled</dt>
    -+ *   <dt>{@code android:enabled}</dt>
    -  *   <dd>Default is {@code true}.  Can be set to {@code false} in order
    -- *   to disable a manifest shortcut that was published in a previous version and and set a custom
    -- *   disabled message.  If a custom disabled message is not needed, then a manifest shortcut can
    -+ *   to disable a static shortcut that was published in a previous version and set a custom
    -+ *   disabled message.  If a custom disabled message is not needed, then a static shortcut can
    -  *   be simply removed from the XML file rather than keeping it with {@code enabled="false"}.</dd>
    -  *
    -- *   <dt>android:icon</dt>
    -+ *   <dt>{@code android:icon}</dt>
    -  *   <dd>Shortcut icon.</dd>
    -  *
    -- *   <dt>android:shortcutShortLabel</dt>
    -+ *   <dt>{@code android:shortcutShortLabel}</dt>
    -  *   <dd>Mandatory shortcut short label.
    -  *   See {@link ShortcutInfo.Builder#setShortLabel(CharSequence)}.</dd>
    -  *
    -- *   <dt>android:shortcutLongLabel</dt>
    -+ *   <dt>{@code android:shortcutLongLabel}</dt>
    -  *   <dd>Shortcut long label.
    -  *   See {@link ShortcutInfo.Builder#setLongLabel(CharSequence)}.</dd>
    -  *
    -- *   <dt>android:shortcutDisabledMessage</dt>
    -+ *   <dt>{@code android:shortcutDisabledMessage}</dt>
    -  *   <dd>When {@code android:enabled} is set to
    -  *   {@code false}, this attribute is used to display a custom disabled message.</dd>
    -  *
    -- *   <dt>intent</dt>
    -+ *   <dt>{@code intent}</dt>
    -  *   <dd>Intent to launch when the user selects the shortcut.
    -  *   {@code android:action} is mandatory.
    -  *   See <a href="{@docRoot}guide/topics/ui/settings.html#Intents">Using intents</a> for the
    -  *   other supported tags.
    -- *   You can provide multiple intents for a single shortcut so that an activity is launched
    -- *   with other activities in the back stack. See {@link android.app.TaskStackBuilder} for details.
    -+ *   You can provide multiple intents for a single shortcut so that the last defined activity is launched
    -+ *   with the other activities in the <a href="/guide/components/tasks-and-back-stack.html">back stack</a>.
    -+ *   See {@link android.app.TaskStackBuilder} for details.
    -  *   </dd>
    -- *   <dt>categories</dt>
    -+ *   <dt>{@code categories}</dt>
    -  *   <dd>Specify shortcut categories.  Currently only
    -  *   {@link ShortcutInfo#SHORTCUT_CATEGORY_CONVERSATION} is defined in the framework.
    -  *   </dd>
    -@@ -226,64 +233,68 @@ import java.util.List;
    -  *
    -  * <h3>Publishing Dynamic Shortcuts</h3>
    -  *
    -- * Applications can publish dynamic shortcuts with {@link #setDynamicShortcuts(List)}
    -+ * <p>
    -+ * Apps can publish dynamic shortcuts with {@link #setDynamicShortcuts(List)}
    -  * or {@link #addDynamicShortcuts(List)}.  The {@link #updateShortcuts(List)} method can also be
    -  * used to update existing, mutable shortcuts.
    -  * Use {@link #removeDynamicShortcuts(List)} or {@link #removeAllDynamicShortcuts()} to remove
    -  * dynamic shortcuts.
    -  *
    -- * <p>Example:
    -+ * <p>The following code snippet shows how to create a single dynamic shortcut:
    -  * <pre>
    -- * ShortcutManager shortcutManager = getSystemService(ShortcutManager.class);
    -+ *ShortcutManager shortcutManager = getSystemService(ShortcutManager.class);
    -  *
    -- * ShortcutInfo shortcut = new ShortcutInfo.Builder(this, "id1")
    -- *     .setIntent(new Intent(Intent.ACTION_VIEW, Uri.parse("http://www.mysite.com/")))
    -- *     .setShortLabel("Web site")
    -- *     .setLongLabel("Open the web site")
    -- *     .setIcon(Icon.createWithResource(context, R.drawable.icon_website))
    -- *     .build();
    -+ *ShortcutInfo shortcut = new ShortcutInfo.Builder(this, "id1")
    -+ *    .setShortLabel("Web site")
    -+ *    .setLongLabel("Open the web site")
    -+ *    .setIcon(Icon.createWithResource(context, R.drawable.icon_website))
    -+ *    .setIntent(new Intent(Intent.ACTION_VIEW,
    -+ *                   Uri.parse("https://www.mysite.example.com/")))
    -+ *    .build();
    -  *
    -- * shortcutManager.setDynamicShortcuts(Arrays.asList(shortcut));
    -+ *shortcutManager.setDynamicShortcuts(Arrays.asList(shortcut));
    -  * </pre>
    -  *
    -  *
    -  * <h3>Shortcut Intents</h3>
    -+ * <p>
    -  * Dynamic shortcuts can be published with any set of {@link Intent#addFlags Intent} flags.
    -  * Typically, {@link Intent#FLAG_ACTIVITY_CLEAR_TASK} is specified, possibly along with other
    -- * flags; otherwise, if the application is already running, the application is simply brought to
    -+ * flags; otherwise, if the app is already running, the app is simply brought to
    -  * the foreground, and the target activity may not appear.
    -  *
    -  * <p>The {@link ShortcutInfo.Builder#setIntents(Intent[])} method can be used instead of
    -  * {@link ShortcutInfo.Builder#setIntent(Intent)} with {@link android.app.TaskStackBuilder}
    -  * in order to launch an activity with other activities in the back stack.
    -  * When the user selects a shortcut to load an activity with a back stack,
    -- * then presses the back key, a "parent" activity will be shown instead of the user being
    -- * navigated back to the launcher.
    -+ * then presses the back key, a parent activity from the same app will be shown
    -+ * instead of the user being navigated back to the launcher.
    -  *
    -- * <p>Manifest shortcuts can also have multiple intents to achieve the same effect.
    -+ * <p>Static shortcuts can also have multiple intents to achieve the same effect.
    -  * In order to associate multiple {@link Intent} objects with a shortcut, simply list multiple
    -  * <code>&lt;intent&gt;</code> elements within a single <code>&lt;shortcut&gt;</code> element.
    -- * The last intent specifies what the user will see when they launch a shortcut.
    -+ * The last intent specifies what the user sees when they launch a shortcut.
    -  *
    -- * <p>Manifest shortcuts <b>cannot</b> have custom intent flags.
    -- * The first intent of a manifest shortcut will always have {@link Intent#FLAG_ACTIVITY_NEW_TASK}
    -+ * <p>Static shortcuts <b>cannot</b> have custom intent flags.
    -+ * The first intent of a static shortcut will always have {@link Intent#FLAG_ACTIVITY_NEW_TASK}
    -  * and {@link Intent#FLAG_ACTIVITY_CLEAR_TASK} set.
    -- * This means, when the application is already running, all the existing activities will be
    -- * destroyed when a manifest shortcut is launched.
    -+ * This means, when the app is already running, all the existing activities will be
    -+ * destroyed when a static shortcut is launched.
    -  * If this behavior is not desirable, you can use a <em>trampoline activity</em>,
    -  * or an invisible activity that starts another activity in {@link Activity#onCreate},
    -  * then calls {@link Activity#finish()}.
    -  * The first activity should include an attribute setting
    -- * of {@code android:taskAffinity=""} in the application's <code>AndroidManifest.xml</code>
    -- * file, and the intent within the manifest shortcut should point at this first activity.
    -+ * of {@code android:taskAffinity=""} in the app's <code>AndroidManifest.xml</code>
    -+ * file, and the intent within the static shortcut should point at this first activity.
    -  *
    -  *
    -  * <h3>Showing New Information in a Shortcut</h3>
    -+ * <p>
    -  * In order to avoid confusion, you should not use {@link #updateShortcuts(List)} to update
    -  * a shortcut so that it contains conceptually different information.
    -  *
    -- * <p>For example, a phone application may publish the most frequently called contact as a dynamic
    -- * shortcut.  Over time, this contact may change; when it does, the application should
    -+ * <p>For example, a phone app may publish the most frequently called contact as a dynamic
    -+ * shortcut.  Over time, this contact may change. When it does, the app should
    -  * represent the changed contact with a new shortcut that contains a different ID, using either
    -  * {@link #setDynamicShortcuts(List)} or {@link #addDynamicShortcuts(List)}, rather than updating
    -  * the existing shortcut with {@link #updateShortcuts(List)}.
    -@@ -291,7 +302,7 @@ import java.util.List;
    -  * it to reference a different contact will likely confuse the user.
    -  *
    -  * <p>On the other hand, when the
    -- * contact's information has changed, such as the name or picture, the application should
    -+ * contact's information has changed, such as the name or picture, the app should
    -  * use {@link #updateShortcuts(List)} so that the pinned shortcut is updated too.
    -  *
    -  *
    -@@ -299,21 +310,21 @@ import java.util.List;
    -  * When the launcher displays the shortcuts that are associated with a particular launcher icon,
    -  * the shortcuts should appear in the following order:
    -  * <ul>
    -- *   <li>First show manifest shortcuts
    -+ *   <li>First show static shortcuts
    -  *   (if {@link ShortcutInfo#isDeclaredInManifest()} is {@code true}),
    -  *   and then show dynamic shortcuts (if {@link ShortcutInfo#isDynamic()} is {@code true}).
    -- *   <li>Within each category of shortcuts (manifest and dynamic), sort the shortcuts in order
    -+ *   <li>Within each category of shortcuts (static and dynamic), sort the shortcuts in order
    -  *   of increasing rank according to {@link ShortcutInfo#getRank()}.
    -  * </ul>
    -- * <p>Shortcut ranks are non-negative sequential integers
    -+ * <p>Shortcut ranks are non-negative, sequential integers
    -  * that determine the order in which shortcuts appear, assuming that the shortcuts are all in
    -  * the same category.
    -  * Ranks of existing shortcuts can be updated with
    -- * {@link #updateShortcuts(List)}; you can use {@link #addDynamicShortcuts(List)} and
    -- * {@link #setDynamicShortcuts(List)}, too.
    -+ * {@link #updateShortcuts(List)}. You can also use {@link #addDynamicShortcuts(List)} and
    -+ * {@link #setDynamicShortcuts(List)}.
    -  *
    -  * <p>Ranks are auto-adjusted so that they're unique for each target activity in each category
    -- * (dynamic or manifest).  For example, if there are 3 dynamic shortcuts with ranks 0, 1 and 2,
    -+ * (static or dynamic).  For example, if there are 3 dynamic shortcuts with ranks 0, 1 and 2,
    -  * adding another dynamic shortcut with a rank of 1 represents a request to place this shortcut at
    -  * the second position.
    -  * In response, the third and fourth shortcuts move closer to the bottom of the shortcut list,
    -@@ -321,119 +332,120 @@ import java.util.List;
    -  *
    -  * <h3>Rate Limiting</h3>
    -  *
    -+ * <p>
    -  * Calls to {@link #setDynamicShortcuts(List)}, {@link #addDynamicShortcuts(List)}, and
    -- * {@link #updateShortcuts(List)} may be rate-limited when called by background applications, or
    -- * applications with no foreground activity or service.  When you attempt to call these methods
    -- * from a background application after exceeding the rate limit, these APIs return {@code false}.
    -+ * {@link #updateShortcuts(List)} may be rate-limited when called by <em>background apps</em>, or
    -+ * apps with no foreground activity or service.  When you attempt to call these methods
    -+ * from a background app after exceeding the rate limit, these APIs return {@code false}.
    -  *
    -- * <p>Applications with a foreground activity or service are not rate-limited.
    -+ * <p>Apps with a foreground activity or service are not rate-limited.
    -  *
    -- * <p>Rate-limiting will be reset upon certain events, so that even background applications
    -- * can call these APIs again until they are rate limit is reached again.
    -+ * <p>Rate-limiting is reset upon certain events, so that even background apps
    -+ * can call these APIs until the rate limit is reached again.
    -  * These events include the following:
    -  * <ul>
    -- *   <li>When an application comes to the foreground.
    -- *   <li>When the system locale changes.
    -- *   <li>When the user performs an "inline reply" action on a notification.
    -+ *   <li>An app comes to the foreground.
    -+ *   <li>The system locale changes.
    -+ *   <li>The user performs the <strong>inline reply</strong> action on a notification.
    -  * </ul>
    -  *
    -  * <p>When rate-limiting is active, {@link #isRateLimitingActive()} returns {@code true}.
    -  *
    -  * <h4>Resetting rate-limiting for testing</h4>
    -  *
    -- * If your application is rate-limited during development or testing, you can use the
    -- * "Reset ShortcutManager rate-limiting" development option or the following adb command to reset
    -- * it:
    -- * <pre>
    -- * adb shell cmd shortcut reset-throttling [ --user USER-ID ]
    -+ * <p>
    -+ * If your app is rate-limited during development or testing, you can use the
    -+ * <strong>Reset ShortcutManager rate-limiting</strong> development option or
    -+ * the following {@code adb} command to reset it:
    -+ * <pre class="no-pretty-print">
    -+ *$ adb shell cmd shortcut reset-throttling [ --user USER-ID ]
    -  * </pre>
    -  *
    -  * <h3>Handling System Locale Changes</h3>
    -  *
    -- * Applications should update dynamic and pinned shortcuts when the system locale changes
    -+ * <p>
    -+ * Apps should update dynamic and pinned shortcuts when the system locale changes
    -  * using the {@link Intent#ACTION_LOCALE_CHANGED} broadcast.
    -  *
    -- * <p>When the system locale changes, rate-limiting is reset, so even background applications
    -- * can set dynamic shortcuts, add dynamic shortcuts, and update shortcuts until the rate limit
    -- * is reached again.
    -+ * <p>When the system locale changes, rate-limiting is reset, so even background apps
    -+ * can add and update dynamic shortcuts until the rate limit is reached again.
    -  *
    -  *
    -  * <h3>Backup and Restore</h3>
    -  *
    -- * When an application has the {@code android:allowBackup="true"} attribute assignment included
    -+ * <p>
    -+ * When an app has the {@code android:allowBackup="true"} attribute assignment included
    -  * in its <code>AndroidManifest.xml</code> file, pinned shortcuts are
    -  * backed up automatically and are restored when the user sets up a new device.
    -  *
    -- * <h4>Categories of Shortcuts that are Backed Up</h4>
    -+ * <h4>Categories of shortcuts that are backed up</h4>
    -  *
    -  * <ul>
    -  *  <li>Pinned shortcuts are backed up.  Bitmap icons are not backed up by the system,
    -- *  but launcher applications should back them up and restore them so that the user still sees icons
    -- *  for pinned shortcuts on the launcher.  Applications can always use
    -+ *  so launcher apps should back them up and restore them so that the user still sees icons
    -+ *  for pinned shortcuts on the launcher.  Apps can always use
    -  *  {@link #updateShortcuts(List)} to re-publish icons.
    -  *
    -- *  <li>Manifest shortcuts are not backed up, but when an application is re-installed on a new
    -- *  device, they are re-published from the <code>AndroidManifest.xml</code> file, anyway.
    -+ *  <li>Static shortcuts aren't backed up, but when an app is re-installed on a new
    -+ *  device, they are re-published from the <code>AndroidManifest.xml</code> file.
    -  *
    -- *  <li>Dynamic shortcuts are <b>not</b> backed up.
    -+ *  <li>Dynamic shortcuts <b>aren't</b> backed up.
    -  * </ul>
    -  *
    -- * <p>Because dynamic shortcuts are not restored, it is recommended that applications check
    -+ * <p>Because dynamic shortcuts are not restored, it is recommended that apps check
    -  * currently-published dynamic shortcuts using {@link #getDynamicShortcuts()}
    -  * each time they are launched, and they should re-publish
    -  * dynamic shortcuts when necessary.
    -  *
    -  * <pre>
    -- * public class MainActivity extends Activity {
    -- *     public void onCreate(Bundle savedInstanceState) {
    -- *         super.onCreate(savedInstanceState);
    -- *
    -- *         ShortcutManager shortcutManager = getSystemService(ShortcutManager.class);
    -- *
    -- *         if (shortcutManager.getDynamicShortcuts().size() == 0) {
    -- *             // Application restored; re-publish dynamic shortcuts.
    -- *
    -- *             if (shortcutManager.getPinnedShortcuts().size() > 0) {
    -- *                 // Pinned shortcuts have been restored.  Use updateShortcuts() to make sure
    -- *                 // they have up-to-date information.
    -- *             }
    -- *         }
    -- *     }
    -- *     :
    -- *
    -- * }
    -+ *public class MainActivity extends Activity {
    -+ *    public void onCreate(Bundle savedInstanceState) {
    -+ *        super.onCreate(savedInstanceState);
    -+ *        ShortcutManager shortcutManager =
    -+ *                getSystemService(ShortcutManager.class);
    -+ *
    -+ *        if (shortcutManager.getDynamicShortcuts().size() == 0) {
    -+ *            // Application restored. Need to re-publish dynamic shortcuts.
    -+ *            if (shortcutManager.getPinnedShortcuts().size() > 0) {
    -+ *                // Pinned shortcuts have been restored. Use
    -+ *                // updateShortcuts() to make sure they contain
    -+ *                // up-to-date information.
    -+ *            }
    -+ *        }
    -+ *    }
    -+ *    // ...
    -+ *}
    -  * </pre>
    -  *
    -  *
    -  * <h4>Backup/restore and shortcut IDs</h4>
    -- *
    -- * Because pinned shortcuts are backed up and restored on new devices, shortcut IDs should be
    -- * meaningful across devices; that is, IDs should contain either stable, constant strings
    -- * or server-side identifiers,
    -+ * <p>
    -+ * Because pinned shortcuts are backed up and restored on new devices, shortcut IDs
    -+ * should contain either stable, constant strings or server-side identifiers,
    -  * rather than identifiers generated locally that might not make sense on other devices.
    -  *
    -  *
    -  * <h3>Report Shortcut Usage and Prediction</h3>
    -- *
    -- * Launcher applications may be capable of predicting which shortcuts will most likely be
    -+ * <p>
    -+ * Launcher apps may be capable of predicting which shortcuts will most likely be
    -  * used at a given time by examining the shortcut usage history data.
    -  *
    -- * <p>In order to provide launchers with such data, publisher applications should
    -+ * <p>In order to provide launchers with such data, publisher apps should
    -  * report the shortcuts that are used with {@link #reportShortcutUsed(String)}
    -  * when a shortcut is selected,
    -  * <b>or when an action equivalent to a shortcut is taken by the user even if it wasn't started
    -  * with the shortcut</b>.
    -  *
    -- * <p>For example, suppose a GPS navigation application supports "navigate to work" as a shortcut.
    -+ * <p>For example, suppose a navigation app supports "navigate to work" as a shortcut.
    -  * It should then report when the user selects this shortcut <b>and</b> when the user chooses
    -- * to navigate to work within the application itself.
    -- * This helps the launcher application
    -+ * to navigate to work within the app itself.
    -+ * This helps the launcher app
    -  * learn that the user wants to navigate to work at a certain time every
    -  * weekday, and it can then show this shortcut in a suggestion list at the right time.
    -  *
    -  * <h3>Launcher API</h3>
    -  *
    -- * The {@link LauncherApps} class provides APIs for launcher applications to access shortcuts.
    -+ * The {@link LauncherApps} class provides APIs for launcher apps to access shortcuts.
    -  *
    -  *
    -  * <h3>Direct Boot and Shortcuts</h3>
    -@@ -465,7 +477,7 @@ public class ShortcutManager {
    -     }
    - 
    -     /**
    --     * Publish the list of shortcuts.  All existing dynamic shortcuts from the caller application
    -+     * Publish the list of shortcuts.  All existing dynamic shortcuts from the caller app
    -      * will be replaced.  If there are already pinned shortcuts with the same IDs,
    -      * the mutable pinned shortcuts are updated.
    -      *
    -@@ -488,7 +500,7 @@ public class ShortcutManager {
    -     }
    - 
    -     /**
    --     * Return all dynamic shortcuts from the caller application.
    -+     * Return all dynamic shortcuts from the caller app.
    -      *
    -      * @throws IllegalStateException when the user is locked.
    -      */
    -@@ -503,7 +515,7 @@ public class ShortcutManager {
    -     }
    - 
    -     /**
    --     * Return all manifest shortcuts from the caller application.
    -+     * Return all static (manifest) shortcuts from the caller app.
    -      *
    -      * @throws IllegalStateException when the user is locked.
    -      */
    -@@ -554,7 +566,7 @@ public class ShortcutManager {
    -     }
    - 
    -     /**
    --     * Delete all dynamic shortcuts from the caller application.
    -+     * Delete all dynamic shortcuts from the caller app.
    -      *
    -      * @throws IllegalStateException when the user is locked.
    -      */
    -@@ -567,7 +579,7 @@ public class ShortcutManager {
    -     }
    - 
    -     /**
    --     * Return all pinned shortcuts from the caller application.
    -+     * Return all pinned shortcuts from the caller app.
    -      *
    -      * @throws IllegalStateException when the user is locked.
    -      */
    -@@ -661,7 +673,7 @@ public class ShortcutManager {
    - 
    -     /**
    -      * Re-enable pinned shortcuts that were previously disabled.  If the target shortcuts
    --     * already enabled, this method does nothing.
    -+     * are already enabled, this method does nothing.
    -      *
    -      * @throws IllegalArgumentException If trying to enable immutable shortcuts.
    -      *
    -@@ -684,7 +696,7 @@ public class ShortcutManager {
    -     }
    - 
    -     /**
    --     * Return the maximum number of dynamic and manifest shortcuts that each launcher icon
    -+     * Return the maximum number of static and dynamic shortcuts that each launcher icon
    -      * can have at a time.
    -      */
    -     public int getMaxShortcutCountPerActivity() {
    -@@ -697,7 +709,7 @@ public class ShortcutManager {
    -     }
    - 
    -     /**
    --     * Return the number of times the caller application can call the rate-limited APIs
    -+     * Return the number of times the caller app can call the rate-limited APIs
    -      * before the rate limit counter is reset.
    -      *
    -      * @see #getRateLimitResetTime()
    -@@ -729,7 +741,7 @@ public class ShortcutManager {
    -     }
    - 
    -     /**
    --     * Return {@code true} when rate-limiting is active for the caller application.
    -+     * Return {@code true} when rate-limiting is active for the caller app.
    -      *
    -      * <p>See the class level javadoc for details.
    -      *
    -@@ -769,13 +781,13 @@ public class ShortcutManager {
    -     }
    - 
    -     /**
    --     * Applications that publish shortcuts should call this method
    --     * whenever the user selects the shortcut containing the given ID or when the user completes
    --     * an action in the application that is equivalent to selecting the shortcut.
    -+     * Apps that publish shortcuts should call this method whenever the user
    -+     * selects the shortcut containing the given ID or when the user completes
    -+     * an action in the app that is equivalent to selecting the shortcut.
    -      * For more details, see the Javadoc for the {@link ShortcutManager} class
    -      *
    -      * <p>The information is accessible via {@link UsageStatsManager#queryEvents}
    --     * Typically, launcher applications use this information to build a prediction model
    -+     * Typically, launcher apps use this information to build a prediction model
    -      * so that they can promote the shortcuts that are likely to be used at the moment.
    -      *
    -      * @throws IllegalStateException when the user is locked.
    -@@ -790,9 +802,9 @@ public class ShortcutManager {
    -     }
    - 
    -     /**
    --     * Called internally when an application is considered to have come to foreground
    -+     * Called internally when an app is considered to have come to the foreground
    -      * even when technically it's not.  This method resets the throttling for this package.
    --     * For example, when the user sends an "inline reply" on an notification, the system UI will
    -+     * For example, when the user sends an "inline reply" on a notification, the system UI will
    -      * call it.
    -      *
    -      * @hide
    -diff --git a/core/java/android/database/CursorJoiner.java b/core/java/android/database/CursorJoiner.java
    -index e3c2988..a95263b 100644
    ---- a/core/java/android/database/CursorJoiner.java
    -+++ b/core/java/android/database/CursorJoiner.java
    -@@ -27,7 +27,7 @@ import java.util.Iterator;
    -  *
    -  * <pre>
    -  * CursorJoiner joiner = new CursorJoiner(cursorA, keyColumnsofA, cursorB, keyColumnsofB);
    -- * for (CursorJointer.Result joinerResult : joiner) {
    -+ * for (CursorJoiner.Result joinerResult : joiner) {
    -  *     switch (joinerResult) {
    -  *         case LEFT:
    -  *             // handle case where a row in cursorA is unique
    -diff --git a/core/java/android/database/sqlite/SQLiteDatabase.java b/core/java/android/database/sqlite/SQLiteDatabase.java
    -index 0f64b92..8e17832 100644
    ---- a/core/java/android/database/sqlite/SQLiteDatabase.java
    -+++ b/core/java/android/database/sqlite/SQLiteDatabase.java
    -@@ -1371,6 +1371,7 @@ public final class SQLiteDatabase extends SQLiteClosable {
    - 
    -     /**
    -      * Convenience method for replacing a row in the database.
    -+     * Inserts a new row if a row does not already exist.
    -      *
    -      * @param table the table in which to replace the row
    -      * @param nullColumnHack optional; may be <code>null</code>.
    -@@ -1381,7 +1382,7 @@ public final class SQLiteDatabase extends SQLiteClosable {
    -      *            provides the name of nullable column name to explicitly insert a NULL into
    -      *            in the case where your <code>initialValues</code> is empty.
    -      * @param initialValues this map contains the initial column values for
    --     *   the row.
    -+     *   the row. The keys should be the column names and the values the column values.
    -      * @return the row ID of the newly inserted row, or -1 if an error occurred
    -      */
    -     public long replace(String table, String nullColumnHack, ContentValues initialValues) {
    -@@ -1396,6 +1397,7 @@ public final class SQLiteDatabase extends SQLiteClosable {
    - 
    -     /**
    -      * Convenience method for replacing a row in the database.
    -+     * Inserts a new row if a row does not already exist.
    -      *
    -      * @param table the table in which to replace the row
    -      * @param nullColumnHack optional; may be <code>null</code>.
    -@@ -1406,7 +1408,7 @@ public final class SQLiteDatabase extends SQLiteClosable {
    -      *            provides the name of nullable column name to explicitly insert a NULL into
    -      *            in the case where your <code>initialValues</code> is empty.
    -      * @param initialValues this map contains the initial column values for
    --     *   the row. The key
    -+     *   the row. The keys should be the column names and the values the column values.
    -      * @throws SQLException
    -      * @return the row ID of the newly inserted row, or -1 if an error occurred
    -      */
    -@@ -1740,7 +1742,7 @@ public final class SQLiteDatabase extends SQLiteClosable {
    -      * Returns true if the new version code is greater than the current database version.
    -      *
    -      * @param newVersion The new version code.
    --     * @return True if the new version code is greater than the current database version. 
    -+     * @return True if the new version code is greater than the current database version.
    -      */
    -     public boolean needUpgrade(int newVersion) {
    -         return newVersion > getVersion();
    -diff --git a/core/java/android/database/sqlite/package.html b/core/java/android/database/sqlite/package.html
    -index ceed171..864a9bb 100644
    ---- a/core/java/android/database/sqlite/package.html
    -+++ b/core/java/android/database/sqlite/package.html
    -@@ -6,15 +6,44 @@ classes that an application would use to manage its own private database.
    - Applications use these classes to manage private databases. If creating a
    - content provider, you will probably have to use these classes to create and
    - manage your own database to store content. See <a
    --href="{@docRoot}guide/topics/providers/content-providers.html">Content Providers</a> to learn
    --the conventions for implementing a content provider. See the
    --NotePadProvider class in the NotePad sample application in the SDK for an
    --example of a content provider. Android ships with SQLite version 3.4.0
    --<p>If you are working with data sent to you by a provider, you will not use
    --these SQLite classes, but instead use the generic {@link android.database}
    --classes.
    --<p>Android ships with the sqlite3 database tool in the <code>tools/</code>
    --folder. You can use this tool to browse or run SQL commands on the device. Run by
    --typing <code>sqlite3</code> in a shell window.
    -+href="{@docRoot}guide/topics/providers/content-providers.html">Content Providers</a>
    -+to learn the conventions for implementing a content provider. If you are working
    -+with data sent to you by a provider, you do not use these SQLite classes, but
    -+instead use the generic {@link android.database} classes.
    -+
    -+<p>The Android SDK and Android emulators both include the
    -+<a href="{@docRoot}studio/command-line/sqlite3.html">sqlite3</a> command-line
    -+database tool. On your development machine, run the tool from the
    -+<code>platform-tools/</code> folder of your SDK. On the emulator, run the tool
    -+with adb shell, for example, <code>adb -e shell sqlite3</code>.
    -+
    -+<p>The version of SQLite depends on the version of Android. See the following table:
    -+<table style="width:auto;">
    -+  <tr><th>Android API</th><th>SQLite Version</th></tr>
    -+  <tr><td>API 24</td><td>3.9</td></tr>
    -+  <tr><td>API 21</td><td>3.8</td></tr>
    -+  <tr><td>API 11</td><td>3.7</td></tr>
    -+  <tr><td>API 8</td><td>3.6</td></tr>
    -+  <tr><td>API 3</td><td>3.5</td></tr>
    -+  <tr><td>API 1</td><td>3.4</td></tr>
    -+</table>
    -+
    -+<p>Some device manufacturers include different versions of SQLite on their devices.
    -+  There are two ways to programmatically determine the version number.
    -+
    -+<ul>
    -+  <li>If available, use the sqlite3 tool, for example:
    -+    <code>adb -e shell sqlite3 --version</code>.</li>
    -+  <li>Create and query an in-memory database as shown in the following code sample:
    -+    <pre>
    -+    String query = "select sqlite_version() AS sqlite_version";
    -+    SQLiteDatabase db = SQLiteDatabase.openOrCreateDatabase(":memory:", null);
    -+    Cursor cursor = db.rawQuery(query, null);
    -+    String sqliteVersion = "";
    -+    if (cursor.moveToNext()) {
    -+        sqliteVersion = cursor.getString(0);
    -+    }</pre>
    -+  </li>
    -+</ul>
    - </BODY>
    - </HTML>
    -diff --git a/core/java/android/hardware/camera2/DngCreator.java b/core/java/android/hardware/camera2/DngCreator.java
    -index 9478dc0..1a51acd 100644
    ---- a/core/java/android/hardware/camera2/DngCreator.java
    -+++ b/core/java/android/hardware/camera2/DngCreator.java
    -@@ -27,6 +27,7 @@ import android.location.Location;
    - import android.media.ExifInterface;
    - import android.media.Image;
    - import android.os.SystemClock;
    -+import android.util.Log;
    - import android.util.Size;
    - 
    - import java.io.IOException;
    -@@ -89,21 +90,43 @@ public final class DngCreator implements AutoCloseable {
    -             throw new IllegalArgumentException("Null argument to DngCreator constructor");
    -         }
    - 
    --        // Find current time
    -+        // Find current time in milliseconds since 1970
    -         long currentTime = System.currentTimeMillis();
    --
    --        // Find boot time
    --        long bootTimeMillis = currentTime - SystemClock.elapsedRealtime();
    -+        // Assume that sensor timestamp has that timebase to start
    -+        long timeOffset = 0;
    -+
    -+        int timestampSource = characteristics.get(
    -+                CameraCharacteristics.SENSOR_INFO_TIMESTAMP_SOURCE);
    -+
    -+        if (timestampSource == CameraCharacteristics.SENSOR_INFO_TIMESTAMP_SOURCE_REALTIME) {
    -+            // This means the same timebase as SystemClock.elapsedRealtime(),
    -+            // which is CLOCK_BOOTTIME
    -+            timeOffset = currentTime - SystemClock.elapsedRealtime();
    -+        } else if (timestampSource == CameraCharacteristics.SENSOR_INFO_TIMESTAMP_SOURCE_UNKNOWN) {
    -+            // This means the same timebase as System.currentTimeMillis(),
    -+            // which is CLOCK_MONOTONIC
    -+            timeOffset = currentTime - SystemClock.uptimeMillis();
    -+        } else {
    -+            // Unexpected time source - treat as CLOCK_MONOTONIC
    -+            Log.w(TAG, "Sensor timestamp source is unexpected: " + timestampSource);
    -+            timeOffset = currentTime - SystemClock.uptimeMillis();
    -+        }
    - 
    -         // Find capture time (nanos since boot)
    -         Long timestamp = metadata.get(CaptureResult.SENSOR_TIMESTAMP);
    -         long captureTime = currentTime;
    -         if (timestamp != null) {
    --            captureTime = timestamp / 1000000 + bootTimeMillis;
    -+            captureTime = timestamp / 1000000 + timeOffset;
    -         }
    - 
    -+        // Create this fresh each time since the time zone may change while a long-running application
    -+        // is active.
    -+        final DateFormat dateTimeStampFormat =
    -+            new SimpleDateFormat(TIFF_DATETIME_FORMAT);
    -+        dateTimeStampFormat.setTimeZone(TimeZone.getDefault());
    -+
    -         // Format for metadata
    --        String formattedCaptureTime = sDateTimeStampFormat.format(captureTime);
    -+        String formattedCaptureTime = dateTimeStampFormat.format(captureTime);
    - 
    -         nativeInit(characteristics.getNativeCopy(), metadata.getNativeCopy(),
    -                 formattedCaptureTime);
    -@@ -450,13 +473,10 @@ public final class DngCreator implements AutoCloseable {
    -     private static final String GPS_DATE_FORMAT_STR = "yyyy:MM:dd";
    -     private static final String TIFF_DATETIME_FORMAT = "yyyy:MM:dd HH:mm:ss";
    -     private static final DateFormat sExifGPSDateStamp = new SimpleDateFormat(GPS_DATE_FORMAT_STR);
    --    private static final DateFormat sDateTimeStampFormat =
    --            new SimpleDateFormat(TIFF_DATETIME_FORMAT);
    -     private final Calendar mGPSTimeStampCalendar = Calendar
    -             .getInstance(TimeZone.getTimeZone("UTC"));
    - 
    -     static {
    --        sDateTimeStampFormat.setTimeZone(TimeZone.getDefault());
    -         sExifGPSDateStamp.setTimeZone(TimeZone.getTimeZone("UTC"));
    -     }
    - 
    -diff --git a/core/java/android/hardware/camera2/utils/TaskDrainer.java b/core/java/android/hardware/camera2/utils/TaskDrainer.java
    -index 7c46e50..ed30ff3 100644
    ---- a/core/java/android/hardware/camera2/utils/TaskDrainer.java
    -+++ b/core/java/android/hardware/camera2/utils/TaskDrainer.java
    -@@ -29,8 +29,9 @@ import static com.android.internal.util.Preconditions.*;
    -  * (and new ones won't begin).
    -  *
    -  * <p>The initial state is to allow all tasks to be started and finished. A task may only be started
    -- * once, after which it must be finished before starting again. Likewise, finishing a task
    -- * that hasn't been started is also not allowed.</p>
    -+ * once, after which it must be finished before starting again. Likewise, a task may only be
    -+ * finished once, after which it must be started before finishing again. It is okay to finish a
    -+ * task before starting it due to different threads handling starting and finishing.</p>
    -  *
    -  * <p>When draining begins, no more new tasks can be started. This guarantees that at some
    -  * point when all the tasks are finished there will be no more collective new tasks,
    -@@ -60,6 +61,11 @@ public class TaskDrainer<T> {
    - 
    -     /** Set of tasks which have been started but not yet finished with #taskFinished */
    -     private final Set<T> mTaskSet = new HashSet<T>();
    -+    /**
    -+     * Set of tasks which have been finished but not yet started with #taskStarted. This may happen
    -+     * if taskStarted and taskFinished are called from two different threads.
    -+     */
    -+    private final Set<T> mEarlyFinishedTaskSet = new HashSet<T>();
    -     private final Object mLock = new Object();
    - 
    -     private boolean mDraining = false;
    -@@ -118,8 +124,12 @@ public class TaskDrainer<T> {
    -                 throw new IllegalStateException("Can't start more tasks after draining has begun");
    -             }
    - 
    --            if (!mTaskSet.add(task)) {
    --                throw new IllegalStateException("Task " + task + " was already started");
    -+            // Try to remove the task from the early finished set.
    -+            if (!mEarlyFinishedTaskSet.remove(task)) {
    -+                // The task is not finished early. Add it to the started set.
    -+                if (!mTaskSet.add(task)) {
    -+                    throw new IllegalStateException("Task " + task + " was already started");
    -+                }
    -             }
    -         }
    -     }
    -@@ -128,8 +138,7 @@ public class TaskDrainer<T> {
    -     /**
    -      * Mark an asynchronous task as having finished.
    -      *
    --     * <p>A task cannot be finished if it hasn't started. Once finished, a task
    --     * cannot be finished again (unless it's started again).</p>
    -+     * <p>A task cannot be finished more than once without first having started.</p>
    -      *
    -      * @param task a key to identify a task
    -      *
    -@@ -137,7 +146,7 @@ public class TaskDrainer<T> {
    -      * @see #beginDrain
    -      *
    -      * @throws IllegalStateException
    --     *          If attempting to start a task which is already finished (and not re-started),
    -+     *          If attempting to finish a task which is already finished (and not started),
    -      */
    -     public void taskFinished(T task) {
    -         synchronized (mLock) {
    -@@ -145,8 +154,12 @@ public class TaskDrainer<T> {
    -                 Log.v(TAG + "[" + mName + "]", "taskFinished " + task);
    -             }
    - 
    -+            // Try to remove the task from started set.
    -             if (!mTaskSet.remove(task)) {
    --                throw new IllegalStateException("Task " + task + " was already finished");
    -+                // Task is not started yet. Add it to the early finished set.
    -+                if (!mEarlyFinishedTaskSet.add(task)) {
    -+                    throw new IllegalStateException("Task " + task + " was already finished");
    -+                }
    -             }
    - 
    -             // If this is the last finished task and draining has already begun, fire #onDrained
    -diff --git a/core/java/android/hardware/location/ContextHubManager.java b/core/java/android/hardware/location/ContextHubManager.java
    -index 0c3d4b3..d4dcacc 100644
    ---- a/core/java/android/hardware/location/ContextHubManager.java
    -+++ b/core/java/android/hardware/location/ContextHubManager.java
    -@@ -123,10 +123,18 @@ public final class ContextHubManager {
    -     /**
    -      * Load a nano app on a specified context hub.
    -      *
    -+     * Note that loading is asynchronous.  When we return from this method,
    -+     * the nano app (probably) hasn't loaded yet.  Assuming a return of 0
    -+     * from this method, then the final success/failure for the load, along
    -+     * with the "handle" for the nanoapp, is all delivered in a byte
    -+     * string via a call to Callback.onMessageReceipt.
    -+     *
    -+     * TODO(b/30784270): Provide a better success/failure and "handle" delivery.
    -+     *
    -      * @param hubHandle handle of context hub to load the app on.
    -      * @param app the nanoApp to load on the hub
    -      *
    --     * @return int nanoAppInstance of the loaded nanoApp on success,
    -+     * @return 0 if the command for loading was sent to the context hub;
    -      *         -1 otherwise
    -      *
    -      * @see NanoApp
    -@@ -150,9 +158,17 @@ public final class ContextHubManager {
    -     /**
    -      * Unload a specified nanoApp
    -      *
    --     * @param nanoAppHandle handle of the nanoApp to load
    -+     * Note that unloading is asynchronous.  When we return from this method,
    -+     * the nano app (probably) hasn't unloaded yet.  Assuming a return of 0
    -+     * from this method, then the final success/failure for the unload is
    -+     * delivered in a byte string via a call to Callback.onMessageReceipt.
    -+     *
    -+     * TODO(b/30784270): Provide a better success/failure delivery.
    -      *
    --     * @return int  0 on success, -1 otherwise
    -+     * @param nanoAppHandle handle of the nanoApp to unload
    -+     *
    -+     * @return 0 if the command for unloading was sent to the context hub;
    -+     *         -1 otherwise
    -      */
    -     public int unloadNanoApp(int nanoAppHandle) {
    -         int retVal = -1;
    -@@ -169,6 +185,24 @@ public final class ContextHubManager {
    -     /**
    -      * get information about the nano app instance
    -      *
    -+     * NOTE: The returned NanoAppInstanceInfo does _not_ contain correct
    -+     * information for several fields, specifically:
    -+     * - getName()
    -+     * - getPublisher()
    -+     * - getNeededExecMemBytes()
    -+     * - getNeededReadMemBytes()
    -+     * - getNeededWriteMemBytes()
    -+     *
    -+     * For example, say you call loadNanoApp() with a NanoApp that has
    -+     * getName() returning "My Name".  Later, if you call getNanoAppInstanceInfo
    -+     * for that nanoapp, the returned NanoAppInstanceInfo's getName()
    -+     * method will claim "Preloaded app, unknown", even though you would
    -+     * have expected "My Name".  For now, as the user, you'll need to
    -+     * separately track the above fields if they are of interest to you.
    -+     *
    -+     * TODO(b/30943489): Have the returned NanoAppInstanceInfo contain the
    -+     *     correct information.
    -+     *
    -      * @param nanoAppHandle handle of the nanoAppInstance
    -      * @return NanoAppInstanceInfo Information about the nano app instance.
    -      *
    -@@ -209,6 +243,14 @@ public final class ContextHubManager {
    -     /**
    -      * Send a message to a specific nano app instance on a context hub.
    -      *
    -+     * Note that the return value of this method only speaks of success
    -+     * up to the point of sending this to the Context Hub.  It is not
    -+     * an assurance that the Context Hub successfully sent this message
    -+     * on to the nanoapp.  If assurance is desired, a protocol should be
    -+     * established between your code and the nanoapp, with the nanoapp
    -+     * sending a confirmation message (which will be reported via
    -+     * Callback.onMessageReceipt).
    -+     *
    -      * @param hubHandle handle of the hub to send the message to
    -      * @param nanoAppHandle  handle of the nano app to send to
    -      * @param message Message to be sent
    -diff --git a/core/java/android/hardware/location/ContextHubService.java b/core/java/android/hardware/location/ContextHubService.java
    -index 062c958..06af461 100644
    ---- a/core/java/android/hardware/location/ContextHubService.java
    -+++ b/core/java/android/hardware/location/ContextHubService.java
    -@@ -18,6 +18,8 @@ package android.hardware.location;
    - 
    - import java.io.FileDescriptor;
    - import java.io.PrintWriter;
    -+import java.nio.ByteBuffer;
    -+import java.nio.ByteOrder;
    - import java.util.ArrayList;
    - import java.util.HashMap;
    - 
    -@@ -146,6 +148,36 @@ public class ContextHubService extends IContextHubService.Stub {
    -         return mContextHubInfo[contextHubHandle];
    -     }
    - 
    -+    // TODO(b/30808791): Remove this when NanoApp's API is correctly treating
    -+    // app IDs as 64-bits.
    -+    private static long parseAppId(NanoApp app) {
    -+        // NOTE: If this shifting seems odd (since it's actually "ONAN"), note
    -+        //     that it matches how this is defined in context_hub.h.
    -+        final int HEADER_MAGIC =
    -+            (((int)'N' <<  0) |
    -+             ((int)'A' <<  8) |
    -+             ((int)'N' << 16) |
    -+             ((int)'O' << 24));
    -+        final int HEADER_MAGIC_OFFSET = 4;
    -+        final int HEADER_APP_ID_OFFSET = 8;
    -+
    -+        ByteBuffer header = ByteBuffer.wrap(app.getAppBinary())
    -+            .order(ByteOrder.LITTLE_ENDIAN);
    -+
    -+        try {
    -+            if (header.getInt(HEADER_MAGIC_OFFSET) == HEADER_MAGIC) {
    -+                // This is a legitimate nanoapp header.  Let's grab the app ID.
    -+                return header.getLong(HEADER_APP_ID_OFFSET);
    -+            }
    -+        } catch (IndexOutOfBoundsException e) {
    -+            // The header is undersized.  We'll fall through to our code
    -+            // path below, which handles being unable to parse the header.
    -+        }
    -+        // We failed to parse the header.  Even through it's probably wrong,
    -+        // let's give NanoApp's idea of our ID.  This is at least consistent.
    -+        return app.getAppId();
    -+    }
    -+
    -     @Override
    -     public int loadNanoApp(int contextHubHandle, NanoApp app) throws RemoteException {
    -         checkPermissions();
    -@@ -162,6 +194,15 @@ public class ContextHubService extends IContextHubService.Stub {
    -         msgHeader[HEADER_FIELD_MSG_TYPE] = MSG_LOAD_NANO_APP;
    - 
    -         long appId = app.getAppId();
    -+        // TODO(b/30808791): Remove this hack when the NanoApp API is fixed,
    -+        //     and getAppId() returns a 'long' instead of an 'int'.
    -+        if ((appId >> 32) != 0) {
    -+            // We're unlikely to notice this warning, but at least
    -+            // we can avoid running our hack logic.
    -+            Log.w(TAG, "Code has not been updated since API fix.");
    -+        } else {
    -+            appId = parseAppId(app);
    -+        }
    - 
    -         msgHeader[HEADER_FIELD_LOAD_APP_ID_LO] = (int)(appId & 0xFFFFFFFF);
    -         msgHeader[HEADER_FIELD_LOAD_APP_ID_HI] = (int)((appId >> 32) & 0xFFFFFFFF);
    -@@ -322,9 +363,16 @@ public class ContextHubService extends IContextHubService.Stub {
    -         appInfo.setNeededReadMemBytes(PRE_LOADED_APP_MEM_REQ);
    -         appInfo.setNeededWriteMemBytes(PRE_LOADED_APP_MEM_REQ);
    - 
    -+        String action;
    -+        if (mNanoAppHash.containsKey(appInstanceHandle)) {
    -+            action = "Updated";
    -+        } else {
    -+            action = "Added";
    -+        }
    -+
    -         mNanoAppHash.put(appInstanceHandle, appInfo);
    --        Log.d(TAG, "Added app instance " + appInstanceHandle + " with id " + appId
    --              + " version " + appVersion);
    -+        Log.d(TAG, action + " app instance " + appInstanceHandle + " with id "
    -+              + appId + " version " + appVersion);
    - 
    -         return 0;
    -     }
    -diff --git a/core/java/android/hardware/location/NanoAppFilter.java b/core/java/android/hardware/location/NanoAppFilter.java
    -index 8db70e9..bf35a3d 100644
    ---- a/core/java/android/hardware/location/NanoAppFilter.java
    -+++ b/core/java/android/hardware/location/NanoAppFilter.java
    -@@ -43,7 +43,8 @@ public class NanoAppFilter {
    -     private long mAppIdVendorMask;
    - 
    -     // Id of the context hub this instance is expected on
    --    private int mContextHubId;
    -+    // TODO: Provide an API which will let us change this HubId.
    -+    private int mContextHubId = HUB_ANY;
    - 
    -     /**
    -      * Flag indicating any version. With this flag set, all versions shall match provided version.
    -diff --git a/core/java/android/hardware/location/NanoAppInstanceInfo.java b/core/java/android/hardware/location/NanoAppInstanceInfo.java
    -index 71a5a88..ac6d83f 100644
    ---- a/core/java/android/hardware/location/NanoAppInstanceInfo.java
    -+++ b/core/java/android/hardware/location/NanoAppInstanceInfo.java
    -@@ -113,7 +113,12 @@ public class NanoAppInstanceInfo {
    -     }
    - 
    -     /**
    --     * Set the application version
    -+     * Get the application version
    -+     *
    -+     * NOTE: There is a race condition where shortly after loading, this
    -+     * may return -1 instead of the correct version.
    -+     *
    -+     * TODO(b/30970527): Fix this race condition.
    -      *
    -      * @return int - version of the app
    -      */
    -diff --git a/core/java/android/hardware/usb/UsbDeviceConnection.java b/core/java/android/hardware/usb/UsbDeviceConnection.java
    -index c062b3a..893b954 100644
    ---- a/core/java/android/hardware/usb/UsbDeviceConnection.java
    -+++ b/core/java/android/hardware/usb/UsbDeviceConnection.java
    -@@ -16,8 +16,10 @@
    - 
    - package android.hardware.usb;
    - 
    -+import android.annotation.NonNull;
    -+import android.annotation.Nullable;
    -+import android.content.Context;
    - import android.os.ParcelFileDescriptor;
    --
    - import java.io.FileDescriptor;
    - 
    - 
    -@@ -31,6 +33,8 @@ public class UsbDeviceConnection {
    - 
    -     private final UsbDevice mDevice;
    - 
    -+    private Context mContext;
    -+
    -     // used by the JNI code
    -     private long mNativeContext;
    - 
    -@@ -42,11 +46,22 @@ public class UsbDeviceConnection {
    -         mDevice = device;
    -     }
    - 
    --    /* package */ boolean open(String name, ParcelFileDescriptor pfd) {
    -+    /* package */ boolean open(String name, ParcelFileDescriptor pfd,  @NonNull Context context) {
    -+        mContext = context.getApplicationContext();
    -+
    -         return native_open(name, pfd.getFileDescriptor());
    -     }
    - 
    -     /**
    -+     * @return The application context the connection was created for.
    -+     *
    -+     * @hide
    -+     */
    -+    public @Nullable Context getContext() {
    -+        return mContext;
    -+    }
    -+
    -+    /**
    -      * Releases all system resources related to the device.
    -      * Once the object is closed it cannot be used again.
    -      * The client must call {@link UsbManager#openDevice} again
    -diff --git a/core/java/android/hardware/usb/UsbManager.java b/core/java/android/hardware/usb/UsbManager.java
    -index 629db06..cb2720a 100644
    ---- a/core/java/android/hardware/usb/UsbManager.java
    -+++ b/core/java/android/hardware/usb/UsbManager.java
    -@@ -330,7 +330,7 @@ public class UsbManager {
    -             ParcelFileDescriptor pfd = mService.openDevice(deviceName);
    -             if (pfd != null) {
    -                 UsbDeviceConnection connection = new UsbDeviceConnection(device);
    --                boolean result = connection.open(deviceName, pfd);
    -+                boolean result = connection.open(deviceName, pfd, mContext);
    -                 pfd.close();
    -                 if (result) {
    -                     return connection;
    -diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java
    -index b9e9b28..0afb546 100644
    ---- a/core/java/android/net/ConnectivityManager.java
    -+++ b/core/java/android/net/ConnectivityManager.java
    -@@ -1825,6 +1825,16 @@ public class ConnectivityManager {
    -         return (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
    -     }
    - 
    -+    /* TODO: These permissions checks don't belong in client-side code. Move them to
    -+     * services.jar, possibly in com.android.server.net. */
    -+
    -+    /** {@hide} */
    -+    public static final boolean checkChangePermission(Context context) {
    -+        int uid = Binder.getCallingUid();
    -+        return Settings.checkAndNoteChangeNetworkStateOperation(context, uid, Settings
    -+                .getPackageNameForUid(context, uid), false /* throwException */);
    -+    }
    -+
    -     /** {@hide} */
    -     public static final void enforceChangePermission(Context context) {
    -         int uid = Binder.getCallingUid();
    -diff --git a/core/java/android/net/IIpConnectivityMetrics.aidl b/core/java/android/net/IIpConnectivityMetrics.aidl
    -new file mode 100644
    -index 0000000..8f634bb
    ---- /dev/null
    -+++ b/core/java/android/net/IIpConnectivityMetrics.aidl
    -@@ -0,0 +1,29 @@
    -+/*
    -+ * Copyright (C) 2016 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 android.net;
    -+
    -+import android.os.Parcelable;
    -+import android.net.ConnectivityMetricsEvent;
    -+
    -+/** {@hide} */
    -+interface IIpConnectivityMetrics {
    -+
    -+    /**
    -+     * @return number of remaining available slots in buffer.
    -+     */
    -+    int logEvent(in ConnectivityMetricsEvent event);
    -+}
    -diff --git a/core/java/android/net/LocalSocketImpl.java b/core/java/android/net/LocalSocketImpl.java
    -index b83fb26..0f0e9c4 100644
    ---- a/core/java/android/net/LocalSocketImpl.java
    -+++ b/core/java/android/net/LocalSocketImpl.java
    -@@ -516,13 +516,11 @@ class LocalSocketImpl
    -                     Os.setsockoptLinger(fd, OsConstants.SOL_SOCKET, OsConstants.SO_LINGER, linger);
    -                     break;
    -                 case SocketOptions.SO_TIMEOUT:
    --                    /*
    --                     * SO_TIMEOUT from the core library gets converted to
    --                     * SO_SNDTIMEO, but the option is supposed to set both
    --                     * send and receive timeouts. Note: The incoming timeout
    --                     * value is in milliseconds.
    --                     */
    -+                    // The option must set both send and receive timeouts.
    -+                    // Note: The incoming timeout value is in milliseconds.
    -                     StructTimeval timeval = StructTimeval.fromMillis(intValue);
    -+                    Os.setsockoptTimeval(fd, OsConstants.SOL_SOCKET, OsConstants.SO_RCVTIMEO,
    -+                            timeval);
    -                     Os.setsockoptTimeval(fd, OsConstants.SOL_SOCKET, OsConstants.SO_SNDTIMEO,
    -                             timeval);
    -                     break;
    -diff --git a/core/java/android/net/NetworkCapabilities.java b/core/java/android/net/NetworkCapabilities.java
    -index 6243f46..56eba4f 100644
    ---- a/core/java/android/net/NetworkCapabilities.java
    -+++ b/core/java/android/net/NetworkCapabilities.java
    -@@ -182,8 +182,15 @@ public final class NetworkCapabilities implements Parcelable {
    -      */
    -     public static final int NET_CAPABILITY_CAPTIVE_PORTAL = 17;
    - 
    -+    /**
    -+     * Indicates that this network is available for use by apps, and not a network that is being
    -+     * kept up in the background to facilitate fast network switching.
    -+     * @hide
    -+     */
    -+    public static final int NET_CAPABILITY_FOREGROUND = 18;
    -+
    -     private static final int MIN_NET_CAPABILITY = NET_CAPABILITY_MMS;
    --    private static final int MAX_NET_CAPABILITY = NET_CAPABILITY_CAPTIVE_PORTAL;
    -+    private static final int MAX_NET_CAPABILITY = NET_CAPABILITY_FOREGROUND;
    - 
    -     /**
    -      * Network capabilities that are expected to be mutable, i.e., can change while a particular
    -@@ -194,7 +201,8 @@ public final class NetworkCapabilities implements Parcelable {
    -             // http://b/18206275
    -             (1 << NET_CAPABILITY_TRUSTED) |
    -             (1 << NET_CAPABILITY_VALIDATED) |
    --            (1 << NET_CAPABILITY_CAPTIVE_PORTAL);
    -+            (1 << NET_CAPABILITY_CAPTIVE_PORTAL) |
    -+            (1 << NET_CAPABILITY_FOREGROUND);
    - 
    -     /**
    -      * Network specifier for factories which want to match any network specifier
    -@@ -217,8 +225,7 @@ public final class NetworkCapabilities implements Parcelable {
    -      * get immediately torn down because they do not have the requested capability.
    -      */
    -     private static final long NON_REQUESTABLE_CAPABILITIES =
    --            (1 << NET_CAPABILITY_VALIDATED) |
    --            (1 << NET_CAPABILITY_CAPTIVE_PORTAL);
    -+            MUTABLE_CAPABILITIES & ~(1 << NET_CAPABILITY_TRUSTED);
    - 
    -     /**
    -      * Capabilities that are set by default when the object is constructed.
    -@@ -325,6 +332,7 @@ public final class NetworkCapabilities implements Parcelable {
    -     public String describeFirstNonRequestableCapability() {
    -         if (hasCapability(NET_CAPABILITY_VALIDATED)) return "NET_CAPABILITY_VALIDATED";
    -         if (hasCapability(NET_CAPABILITY_CAPTIVE_PORTAL)) return "NET_CAPABILITY_CAPTIVE_PORTAL";
    -+        if (hasCapability(NET_CAPABILITY_FOREGROUND)) return "NET_CAPABILITY_FOREGROUND";
    -         // This cannot happen unless the preceding checks are incomplete.
    -         if ((mNetworkCapabilities & NON_REQUESTABLE_CAPABILITIES) != 0) {
    -             return "unknown non-requestable capabilities " + Long.toHexString(mNetworkCapabilities);
    -@@ -352,6 +360,11 @@ public final class NetworkCapabilities implements Parcelable {
    -                 (that.mNetworkCapabilities & ~MUTABLE_CAPABILITIES));
    -     }
    - 
    -+    private boolean equalsNetCapabilitiesRequestable(NetworkCapabilities that) {
    -+        return ((this.mNetworkCapabilities & ~NON_REQUESTABLE_CAPABILITIES) ==
    -+                (that.mNetworkCapabilities & ~NON_REQUESTABLE_CAPABILITIES));
    -+    }
    -+
    -     /**
    -      * Removes the NET_CAPABILITY_NOT_RESTRICTED capability if all the capabilities it provides are
    -      * typically provided by restricted networks.
    -@@ -749,6 +762,19 @@ public final class NetworkCapabilities implements Parcelable {
    -                 equalsSpecifier(nc));
    -     }
    - 
    -+    /**
    -+     * Checks that our requestable capabilities are the same as those of the given
    -+     * {@code NetworkCapabilities}.
    -+     *
    -+     * @hide
    -+     */
    -+    public boolean equalRequestableCapabilities(NetworkCapabilities nc) {
    -+        if (nc == null) return false;
    -+        return (equalsNetCapabilitiesRequestable(nc) &&
    -+                equalsTransportTypes(nc) &&
    -+                equalsSpecifier(nc));
    -+    }
    -+
    -     @Override
    -     public boolean equals(Object obj) {
    -         if (obj == null || (obj instanceof NetworkCapabilities == false)) return false;
    -@@ -833,6 +859,7 @@ public final class NetworkCapabilities implements Parcelable {
    -                 case NET_CAPABILITY_NOT_VPN:        capabilities += "NOT_VPN"; break;
    -                 case NET_CAPABILITY_VALIDATED:      capabilities += "VALIDATED"; break;
    -                 case NET_CAPABILITY_CAPTIVE_PORTAL: capabilities += "CAPTIVE_PORTAL"; break;
    -+                case NET_CAPABILITY_FOREGROUND:     capabilities += "FOREGROUND"; break;
    -             }
    -             if (++i < types.length) capabilities += "&";
    -         }
    -diff --git a/core/java/android/net/NetworkIdentity.java b/core/java/android/net/NetworkIdentity.java
    -index 9cd563e..d570e66 100644
    ---- a/core/java/android/net/NetworkIdentity.java
    -+++ b/core/java/android/net/NetworkIdentity.java
    -@@ -175,7 +175,11 @@ public class NetworkIdentity implements Comparable<NetworkIdentity> {
    - 
    -         if (isNetworkTypeMobile(type)) {
    -             if (state.subscriberId == null) {
    --                Slog.w(TAG, "Active mobile network without subscriber!");
    -+                if (state.networkInfo.getState() != NetworkInfo.State.DISCONNECTED &&
    -+                        state.networkInfo.getState() != NetworkInfo.State.UNKNOWN) {
    -+                    Slog.w(TAG, "Active mobile network without subscriber! ni = "
    -+                            + state.networkInfo);
    -+                }
    -             }
    - 
    -             subscriberId = state.subscriberId;
    -diff --git a/core/java/android/net/NetworkRequest.java b/core/java/android/net/NetworkRequest.java
    -index 4501f7b..ae72470 100644
    ---- a/core/java/android/net/NetworkRequest.java
    -+++ b/core/java/android/net/NetworkRequest.java
    -@@ -49,7 +49,7 @@ public class NetworkRequest implements Parcelable {
    -     public final int legacyType;
    - 
    -     /**
    --     * A NetworkRequest as used by the system can be one of three types:
    -+     * A NetworkRequest as used by the system can be one of the following types:
    -      *
    -      *     - LISTEN, for which the framework will issue callbacks about any
    -      *       and all networks that match the specified NetworkCapabilities,
    -@@ -64,7 +64,20 @@ public class NetworkRequest implements Parcelable {
    -      *       current network (if any) that matches the capabilities of the
    -      *       default Internet request (mDefaultRequest), but which cannot cause
    -      *       the framework to either create or retain the existence of any
    --     *       specific network.
    -+     *       specific network. Note that from the point of view of the request
    -+     *       matching code, TRACK_DEFAULT is identical to REQUEST: its special
    -+     *       behaviour is not due to different semantics, but to the fact that
    -+     *       the system will only ever create a TRACK_DEFAULT with capabilities
    -+     *       that are identical to the default request's capabilities, thus
    -+     *       causing it to share fate in every way with the default request.
    -+     *
    -+     *     - BACKGROUND_REQUEST, like REQUEST but does not cause any networks
    -+     *       to retain the NET_CAPABILITY_FOREGROUND capability. A network with
    -+     *       no foreground requests is in the background. A network that has
    -+     *       one or more background requests and loses its last foreground
    -+     *       request to a higher-scoring network will not go into the
    -+     *       background immediately, but will linger and go into the background
    -+     *       after the linger timeout.
    -      *
    -      *     - The value NONE is used only by applications. When an application
    -      *       creates a NetworkRequest, it does not have a type; the type is set
    -@@ -77,7 +90,8 @@ public class NetworkRequest implements Parcelable {
    -         NONE,
    -         LISTEN,
    -         TRACK_DEFAULT,
    --        REQUEST
    -+        REQUEST,
    -+        BACKGROUND_REQUEST,
    -     };
    - 
    -     /**
    -@@ -140,7 +154,7 @@ public class NetworkRequest implements Parcelable {
    -          * Add the given capability requirement to this builder.  These represent
    -          * the requested network's required capabilities.  Note that when searching
    -          * for a network to satisfy a request, all capabilities requested must be
    --         * satisfied.  See {@link NetworkCapabilities} for {@code NET_CAPABILITIY_*}
    -+         * satisfied.  See {@link NetworkCapabilities} for {@code NET_CAPABILITY_*}
    -          * definitions.
    -          *
    -          * @param capability The {@code NetworkCapabilities.NET_CAPABILITY_*} to add.
    -@@ -284,7 +298,7 @@ public class NetworkRequest implements Parcelable {
    -         };
    - 
    -     /**
    --     * Returns true iff. the contained NetworkRequest is of type LISTEN.
    -+     * Returns true iff. this NetworkRequest is of type LISTEN.
    -      *
    -      * @hide
    -      */
    -@@ -298,8 +312,9 @@ public class NetworkRequest implements Parcelable {
    -      *     - should be associated with at most one satisfying network
    -      *       at a time;
    -      *
    --     *     - should cause a network to be kept up if it is the best network
    --     *       which can satisfy the NetworkRequest.
    -+     *     - should cause a network to be kept up, but not necessarily in
    -+     *       the foreground, if it is the best network which can satisfy the
    -+     *       NetworkRequest.
    -      *
    -      * For full detail of how isRequest() is used for pairing Networks with
    -      * NetworkRequests read rematchNetworkAndRequests().
    -@@ -307,9 +322,36 @@ public class NetworkRequest implements Parcelable {
    -      * @hide
    -      */
    -     public boolean isRequest() {
    -+        return isForegroundRequest() || isBackgroundRequest();
    -+    }
    -+
    -+    /**
    -+     * Returns true iff. the contained NetworkRequest is one that:
    -+     *
    -+     *     - should be associated with at most one satisfying network
    -+     *       at a time;
    -+     *
    -+     *     - should cause a network to be kept up and in the foreground if
    -+     *       it is the best network which can satisfy the NetworkRequest.
    -+     *
    -+     * For full detail of how isRequest() is used for pairing Networks with
    -+     * NetworkRequests read rematchNetworkAndRequests().
    -+     *
    -+     * @hide
    -+     */
    -+    public boolean isForegroundRequest() {
    -         return type == Type.TRACK_DEFAULT || type == Type.REQUEST;
    -     }
    - 
    -+    /**
    -+     * Returns true iff. this NetworkRequest is of type BACKGROUND_REQUEST.
    -+     *
    -+     * @hide
    -+     */
    -+    public boolean isBackgroundRequest() {
    -+        return type == Type.BACKGROUND_REQUEST;
    -+    }
    -+
    -     public String toString() {
    -         return "NetworkRequest [ " + type + " id=" + requestId +
    -                 (legacyType != ConnectivityManager.TYPE_NONE ? ", legacyType=" + legacyType : "") +
    -diff --git a/core/java/android/net/NetworkStats.java b/core/java/android/net/NetworkStats.java
    -index 25806fa..f65a50f 100644
    ---- a/core/java/android/net/NetworkStats.java
    -+++ b/core/java/android/net/NetworkStats.java
    -@@ -904,7 +904,8 @@ public class NetworkStats implements Parcelable {
    -         if (pool.isEmpty()) {
    -             return true;
    -         }
    --        Entry moved = addTrafficToApplications(tunIface,  underlyingIface, tunIfaceTotal, pool);
    -+        Entry moved =
    -+                addTrafficToApplications(tunUid, tunIface, underlyingIface, tunIfaceTotal, pool);
    -         deductTrafficFromVpnApp(tunUid, underlyingIface, moved);
    - 
    -         if (!moved.isEmpty()) {
    -@@ -919,9 +920,9 @@ public class NetworkStats implements Parcelable {
    -      * Initializes the data used by the migrateTun() method.
    -      *
    -      * This is the first pass iteration which does the following work:
    --     * (1) Adds up all the traffic through tun0.
    --     * (2) Adds up all the traffic through the tunUid's underlyingIface
    -+     * (1) Adds up all the traffic through the tunUid's underlyingIface
    -      *     (both foreground and background).
    -+     * (2) Adds up all the traffic through tun0 excluding traffic from the vpn app itself.
    -      */
    -     private void tunAdjustmentInit(int tunUid, String tunIface, String underlyingIface,
    -             Entry tunIfaceTotal, Entry underlyingIfaceTotal) {
    -@@ -941,8 +942,9 @@ public class NetworkStats implements Parcelable {
    -                 underlyingIfaceTotal.add(recycle);
    -             }
    - 
    --            if (recycle.tag == TAG_NONE && Objects.equals(tunIface, recycle.iface)) {
    --                // Add up all tunIface traffic.
    -+            if (recycle.uid != tunUid && recycle.tag == TAG_NONE
    -+                    && Objects.equals(tunIface, recycle.iface)) {
    -+                // Add up all tunIface traffic excluding traffic from the vpn app itself.
    -                 tunIfaceTotal.add(recycle);
    -             }
    -         }
    -@@ -958,13 +960,15 @@ public class NetworkStats implements Parcelable {
    -         return pool;
    -     }
    - 
    --    private Entry addTrafficToApplications(String tunIface, String underlyingIface,
    -+    private Entry addTrafficToApplications(int tunUid, String tunIface, String underlyingIface,
    -             Entry tunIfaceTotal, Entry pool) {
    -         Entry moved = new Entry();
    -         Entry tmpEntry = new Entry();
    -         tmpEntry.iface = underlyingIface;
    -         for (int i = 0; i < size; i++) {
    --            if (Objects.equals(iface[i], tunIface)) {
    -+            // the vpn app is excluded from the redistribution but all moved traffic will be
    -+            // deducted from the vpn app (see deductTrafficFromVpnApp below).
    -+            if (Objects.equals(iface[i], tunIface) && uid[i] != tunUid) {
    -                 if (tunIfaceTotal.rxBytes > 0) {
    -                     tmpEntry.rxBytes = pool.rxBytes * rxBytes[i] / tunIfaceTotal.rxBytes;
    -                 } else {
    -diff --git a/core/java/android/net/metrics/DhcpErrorEvent.java b/core/java/android/net/metrics/DhcpErrorEvent.java
    -index 59c5fb6..c3abcf7 100644
    ---- a/core/java/android/net/metrics/DhcpErrorEvent.java
    -+++ b/core/java/android/net/metrics/DhcpErrorEvent.java
    -@@ -50,9 +50,13 @@ public final class DhcpErrorEvent implements Parcelable {
    -     public static final int DHCP_INVALID_OPTION_LENGTH = makeErrorCode(DHCP_ERROR, 3);
    -     public static final int DHCP_NO_MSG_TYPE           = makeErrorCode(DHCP_ERROR, 4);
    -     public static final int DHCP_UNKNOWN_MSG_TYPE      = makeErrorCode(DHCP_ERROR, 5);
    -+    /** {@hide} */
    -+    public static final int DHCP_NO_COOKIE             = makeErrorCode(DHCP_ERROR, 6);
    - 
    -     public static final int BUFFER_UNDERFLOW           = makeErrorCode(MISC_ERROR, 1);
    -     public static final int RECEIVE_ERROR              = makeErrorCode(MISC_ERROR, 2);
    -+    /** {@hide} */
    -+    public static final int PARSING_ERROR              = makeErrorCode(MISC_ERROR, 3);
    - 
    -     public final String ifName;
    -     // error code byte format (MSB to LSB):
    -@@ -115,8 +119,9 @@ public final class DhcpErrorEvent implements Parcelable {
    -     }
    - 
    -     final static class Decoder {
    --        static final SparseArray<String> constants =
    --                MessageUtils.findMessageNames(new Class[]{DhcpErrorEvent.class},
    --                new String[]{"L2_", "L3_", "L4_", "BOOTP_", "DHCP_", "BUFFER_", "RECEIVE_"});
    -+        static final SparseArray<String> constants = MessageUtils.findMessageNames(
    -+                new Class[]{DhcpErrorEvent.class},
    -+                new String[]{"L2_", "L3_", "L4_", "BOOTP_", "DHCP_", "BUFFER_", "RECEIVE_",
    -+                "PARSING_"});
    -     }
    - }
    -diff --git a/core/java/android/net/metrics/IpConnectivityLog.java b/core/java/android/net/metrics/IpConnectivityLog.java
    -index dd7bd1b..173e5fd 100644
    ---- a/core/java/android/net/metrics/IpConnectivityLog.java
    -+++ b/core/java/android/net/metrics/IpConnectivityLog.java
    -@@ -17,63 +17,65 @@
    - package android.net.metrics;
    - 
    - import android.net.ConnectivityMetricsEvent;
    --import android.net.ConnectivityMetricsLogger;
    --import android.net.IConnectivityMetricsLogger;
    -+import android.net.IIpConnectivityMetrics;
    - import android.os.Parcelable;
    - import android.os.RemoteException;
    -+import android.os.ServiceManager;
    - import android.util.Log;
    --
    - import com.android.internal.annotations.VisibleForTesting;
    - 
    - /**
    -- * Specialization of the ConnectivityMetricsLogger class for recording IP connectivity events.
    -+ * Class for logging IpConnectvity events with IpConnectivityMetrics
    -  * {@hide}
    -  */
    --public class IpConnectivityLog extends ConnectivityMetricsLogger {
    --    private static String TAG = "IpConnectivityMetricsLogger";
    --    private static final boolean DBG = true;
    -+public class IpConnectivityLog {
    -+    private static final String TAG = IpConnectivityLog.class.getSimpleName();
    -+    private static final boolean DBG = false;
    -+
    -+    public static final String SERVICE_NAME = "connmetrics";
    -+
    -+    private IIpConnectivityMetrics mService;
    - 
    -     public IpConnectivityLog() {
    --        // mService initialized in super constructor.
    -     }
    - 
    -     @VisibleForTesting
    --    public IpConnectivityLog(IConnectivityMetricsLogger service) {
    --        super(service);
    -+    public IpConnectivityLog(IIpConnectivityMetrics service) {
    -+        mService = service;
    -+    }
    -+
    -+    private boolean checkLoggerService() {
    -+        if (mService != null) {
    -+            return true;
    -+        }
    -+        final IIpConnectivityMetrics service =
    -+                IIpConnectivityMetrics.Stub.asInterface(ServiceManager.getService(SERVICE_NAME));
    -+        if (service == null) {
    -+            return false;
    -+        }
    -+        // Two threads racing here will write the same pointer because getService
    -+        // is idempotent once MetricsLoggerService is initialized.
    -+        mService = service;
    -+        return true;
    -     }
    - 
    -     /**
    --     * Log an IpConnectivity event. Contrary to logEvent(), this method does not
    --     * keep track of skipped events and is thread-safe for callers.
    --     *
    -+     * Log an IpConnectivity event.
    -      * @param timestamp is the epoch timestamp of the event in ms.
    -      * @param data is a Parcelable instance representing the event.
    --     *
    -      * @return true if the event was successfully logged.
    -      */
    -     public boolean log(long timestamp, Parcelable data) {
    -         if (!checkLoggerService()) {
    -             if (DBG) {
    --                Log.d(TAG, CONNECTIVITY_METRICS_LOGGER_SERVICE + " service was not ready");
    --            }
    --            return false;
    --        }
    --
    --        if (System.currentTimeMillis() < mServiceUnblockedTimestampMillis) {
    --            if (DBG) {
    --                Log.d(TAG, "skipping logging due to throttling for IpConnectivity component");
    -+                Log.d(TAG, SERVICE_NAME + " service was not ready");
    -             }
    -             return false;
    -         }
    - 
    -         try {
    --            final ConnectivityMetricsEvent event =
    --                new ConnectivityMetricsEvent(timestamp, COMPONENT_TAG_CONNECTIVITY, 0, data);
    --            final long result = mService.logEvent(event);
    --            if (result >= 0) {
    --                mServiceUnblockedTimestampMillis = result;
    --            }
    --            return (result == 0);
    -+            int left = mService.logEvent(new ConnectivityMetricsEvent(timestamp, 0, 0, data));
    -+            return left >= 0;
    -         } catch (RemoteException e) {
    -             Log.e(TAG, "Error logging event", e);
    -             return false;
    -diff --git a/core/java/android/net/metrics/ValidationProbeEvent.java b/core/java/android/net/metrics/ValidationProbeEvent.java
    -index 331cf0c..1a31b56 100644
    ---- a/core/java/android/net/metrics/ValidationProbeEvent.java
    -+++ b/core/java/android/net/metrics/ValidationProbeEvent.java
    -@@ -34,10 +34,12 @@ import java.lang.annotation.RetentionPolicy;
    - @SystemApi
    - public final class ValidationProbeEvent implements Parcelable {
    - 
    --    public static final int PROBE_DNS   = 0;
    --    public static final int PROBE_HTTP  = 1;
    --    public static final int PROBE_HTTPS = 2;
    --    public static final int PROBE_PAC   = 3;
    -+    public static final int PROBE_DNS       = 0;
    -+    public static final int PROBE_HTTP      = 1;
    -+    public static final int PROBE_HTTPS     = 2;
    -+    public static final int PROBE_PAC       = 3;
    -+    /** {@hide} */
    -+    public static final int PROBE_FALLBACK  = 4;
    - 
    -     public static final int DNS_FAILURE = 0;
    -     public static final int DNS_SUCCESS = 1;
    -@@ -57,7 +59,7 @@ public final class ValidationProbeEvent implements Parcelable {
    -     public final @ProbeType int probeType;
    -     public final @ReturnCode int returnCode;
    - 
    --    /** @hide */
    -+    /** {@hide} */
    -     public ValidationProbeEvent(
    -             int netId, long durationMs, @ProbeType int probeType, @ReturnCode int returnCode) {
    -         this.netId = netId;
    -diff --git a/core/java/android/os/AsyncTask.java b/core/java/android/os/AsyncTask.java
    -index 4f4e722..fea64ec 100644
    ---- a/core/java/android/os/AsyncTask.java
    -+++ b/core/java/android/os/AsyncTask.java
    -@@ -298,12 +298,19 @@ public abstract class AsyncTask<Params, Progress, Result> {
    -         mWorker = new WorkerRunnable<Params, Result>() {
    -             public Result call() throws Exception {
    -                 mTaskInvoked.set(true);
    --
    --                Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
    --                //noinspection unchecked
    --                Result result = doInBackground(mParams);
    --                Binder.flushPendingCommands();
    --                return postResult(result);
    -+                Result result = null;
    -+                try {
    -+                    Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
    -+                    //noinspection unchecked
    -+                    result = doInBackground(mParams);
    -+                    Binder.flushPendingCommands();
    -+                } catch (Throwable tr) {
    -+                    mCancelled.set(true);
    -+                    throw tr;
    -+                } finally {
    -+                    postResult(result);
    -+                }
    -+                return result;
    -             }
    -         };
    - 
    -diff --git a/core/java/android/os/Build.java b/core/java/android/os/Build.java
    -index 3d3dc9c..151239b 100644
    ---- a/core/java/android/os/Build.java
    -+++ b/core/java/android/os/Build.java
    -@@ -709,6 +709,14 @@ public class Build {
    -          * {@link android.widget.LinearLayout.LayoutParams LinearLayout.LayoutParams} to
    -          * {@link android.widget.RelativeLayout.LayoutParams RelativeLayout.LayoutParams}).</li>
    -          * <li>Your application processes will not be killed when the device density changes.</li>
    -+         * <li>Drag and drop. After a view receives the
    -+         * {@link android.view.DragEvent#ACTION_DRAG_ENTERED} event, when the drag shadow moves into
    -+         * a descendant view that can accept the data, the view receives the
    -+         * {@link android.view.DragEvent#ACTION_DRAG_EXITED} event and won’t receive
    -+         * {@link android.view.DragEvent#ACTION_DRAG_LOCATION} and
    -+         * {@link android.view.DragEvent#ACTION_DROP} events while the drag shadow is within that
    -+         * descendant view, even if the descendant view returns <code>false</code> from its handler
    -+         * for these events.</li>
    -          * </ul>
    -          */
    -         public static final int N = 24;
    -diff --git a/core/java/android/os/Bundle.java b/core/java/android/os/Bundle.java
    -index ca64a96..62fa772 100644
    ---- a/core/java/android/os/Bundle.java
    -+++ b/core/java/android/os/Bundle.java
    -@@ -309,25 +309,49 @@ public final class Bundle extends BaseBundle implements Cloneable, Parcelable {
    -      * Filter values in Bundle to only basic types.
    -      * @hide
    -      */
    --    public void filterValues() {
    -+    public Bundle filterValues() {
    -         unparcel();
    -+        Bundle bundle = this;
    -         if (mMap != null) {
    --            for (int i = mMap.size() - 1; i >= 0; i--) {
    --                Object value = mMap.valueAt(i);
    -+            ArrayMap<String, Object> map = mMap;
    -+            for (int i = map.size() - 1; i >= 0; i--) {
    -+                Object value = map.valueAt(i);
    -                 if (PersistableBundle.isValidType(value)) {
    -                     continue;
    -                 }
    -                 if (value instanceof Bundle) {
    --                    ((Bundle)value).filterValues();
    -+                    Bundle newBundle = ((Bundle)value).filterValues();
    -+                    if (newBundle != value) {
    -+                        if (map == mMap) {
    -+                            // The filter had to generate a new bundle, but we have not yet
    -+                            // created a new one here.  Do that now.
    -+                            bundle = new Bundle(this);
    -+                            // Note the ArrayMap<> constructor is guaranteed to generate
    -+                            // a new object with items in the same order as the original.
    -+                            map = bundle.mMap;
    -+                        }
    -+                        // Replace this current entry with the new child bundle.
    -+                        map.setValueAt(i, newBundle);
    -+                    }
    -+                    continue;
    -                 }
    -                 if (value.getClass().getName().startsWith("android.")) {
    -                     continue;
    -                 }
    --                mMap.removeAt(i);
    -+                if (map == mMap) {
    -+                    // This is the first time we have had to remove something, that means we
    -+                    // need to switch to a new Bundle.
    -+                    bundle = new Bundle(this);
    -+                    // Note the ArrayMap<> constructor is guaranteed to generate
    -+                    // a new object with items in the same order as the original.
    -+                    map = bundle.mMap;
    -+                }
    -+                map.removeAt(i);
    -             }
    -         }
    -         mFlags |= FLAG_HAS_FDS_KNOWN;
    -         mFlags &= ~FLAG_HAS_FDS;
    -+        return bundle;
    -     }
    - 
    -     /**
    -diff --git a/core/java/android/os/FileObserver.java b/core/java/android/os/FileObserver.java
    -index 4e705e0..dd85e15 100644
    ---- a/core/java/android/os/FileObserver.java
    -+++ b/core/java/android/os/FileObserver.java
    -@@ -16,6 +16,7 @@
    - 
    - package android.os;
    - 
    -+import android.annotation.Nullable;
    - import android.util.Log;
    - 
    - import java.lang.ref.WeakReference;
    -@@ -204,7 +205,8 @@ public abstract class FileObserver {
    -      *
    -      * @param event The type of event which happened
    -      * @param path The path, relative to the main monitored file or directory,
    --     *     of the file or directory which triggered the event
    -+     *     of the file or directory which triggered the event.  This value can
    -+     *     be {@code null} for certain events, such as {@link #MOVE_SELF}.
    -      */
    --    public abstract void onEvent(int event, String path);
    -+    public abstract void onEvent(int event, @Nullable String path);
    - }
    -diff --git a/core/java/android/os/FileUtils.java b/core/java/android/os/FileUtils.java
    -index fa32848..8e24caf 100644
    ---- a/core/java/android/os/FileUtils.java
    -+++ b/core/java/android/os/FileUtils.java
    -@@ -605,6 +605,22 @@ public class FileUtils {
    -         return null;
    -     }
    - 
    -+    private static File buildUniqueFileWithExtension(File parent, String name, String ext)
    -+            throws FileNotFoundException {
    -+        File file = buildFile(parent, name, ext);
    -+
    -+        // If conflicting file, try adding counter suffix
    -+        int n = 0;
    -+        while (file.exists()) {
    -+            if (n++ >= 32) {
    -+                throw new FileNotFoundException("Failed to create unique file");
    -+            }
    -+            file = buildFile(parent, name + " (" + n + ")", ext);
    -+        }
    -+
    -+        return file;
    -+    }
    -+
    -     /**
    -      * Generates a unique file name under the given parent directory. If the display name doesn't
    -      * have an extension that matches the requested MIME type, the default extension for that MIME
    -@@ -619,20 +635,29 @@ public class FileUtils {
    -     public static File buildUniqueFile(File parent, String mimeType, String displayName)
    -             throws FileNotFoundException {
    -         final String[] parts = splitFileName(mimeType, displayName);
    --        final String name = parts[0];
    --        final String ext = parts[1];
    --        File file = buildFile(parent, name, ext);
    -+        return buildUniqueFileWithExtension(parent, parts[0], parts[1]);
    -+    }
    - 
    --        // If conflicting file, try adding counter suffix
    --        int n = 0;
    --        while (file.exists()) {
    --            if (n++ >= 32) {
    --                throw new FileNotFoundException("Failed to create unique file");
    --            }
    --            file = buildFile(parent, name + " (" + n + ")", ext);
    -+    /**
    -+     * Generates a unique file name under the given parent directory, keeping
    -+     * any extension intact.
    -+     */
    -+    public static File buildUniqueFile(File parent, String displayName)
    -+            throws FileNotFoundException {
    -+        final String name;
    -+        final String ext;
    -+
    -+        // Extract requested extension from display name
    -+        final int lastDot = displayName.lastIndexOf('.');
    -+        if (lastDot >= 0) {
    -+            name = displayName.substring(0, lastDot);
    -+            ext = displayName.substring(lastDot + 1);
    -+        } else {
    -+            name = displayName;
    -+            ext = null;
    -         }
    - 
    --        return file;
    -+        return buildUniqueFileWithExtension(parent, name, ext);
    -     }
    - 
    -     /**
    -diff --git a/core/java/android/os/IRecoverySystem.aidl b/core/java/android/os/IRecoverySystem.aidl
    -index 12830a4..c5ceecd 100644
    ---- a/core/java/android/os/IRecoverySystem.aidl
    -+++ b/core/java/android/os/IRecoverySystem.aidl
    -@@ -25,4 +25,5 @@ interface IRecoverySystem {
    -     boolean uncrypt(in String packageFile, IRecoverySystemProgressListener listener);
    -     boolean setupBcb(in String command);
    -     boolean clearBcb();
    -+    void rebootRecoveryWithCommand(in String command);
    - }
    -diff --git a/core/java/android/os/PatternMatcher.java b/core/java/android/os/PatternMatcher.java
    -index 56dc837..3890fbf 100644
    ---- a/core/java/android/os/PatternMatcher.java
    -+++ b/core/java/android/os/PatternMatcher.java
    -@@ -16,6 +16,10 @@
    - 
    - package android.os;
    - 
    -+import android.util.Log;
    -+
    -+import java.util.Arrays;
    -+
    - /**
    -  * A simple pattern matcher, which is safe to use on untrusted data: it does
    -  * not provide full reg-exp support, only simple globbing that can not be
    -@@ -44,13 +48,59 @@ public class PatternMatcher implements Parcelable {
    -      * wildcard part of a normal regexp. 
    -      */
    -     public static final int PATTERN_SIMPLE_GLOB = 2;
    --    
    -+
    -+    /**
    -+     * Pattern type: the given pattern is interpreted with a regular
    -+     * expression-like syntax for matching against the string it is tested
    -+     * against. Supported tokens include dot ({@code .}) and sets ({@code [...]})
    -+     * with full support for character ranges and the not ({@code ^}) modifier.
    -+     * Supported modifiers include star ({@code *}) for zero-or-more, plus ({@code +})
    -+     * for one-or-more and full range ({@code {...}}) support. This is a simple
    -+     * evaulation implementation in which matching is done against the pattern in
    -+     * realtime with no backtracking support.
    -+     *
    -+     * {@hide} Pending approval for public API
    -+     */
    -+    public static final int PATTERN_ADVANCED_GLOB = 3;
    -+
    -+    // token types for advanced matching
    -+    private static final int TOKEN_TYPE_LITERAL = 0;
    -+    private static final int TOKEN_TYPE_ANY = 1;
    -+    private static final int TOKEN_TYPE_SET = 2;
    -+    private static final int TOKEN_TYPE_INVERSE_SET = 3;
    -+
    -+    // Return for no match
    -+    private static final int NO_MATCH = -1;
    -+
    -+    private static final String TAG = "PatternMatcher";
    -+
    -+    // Parsed placeholders for advanced patterns
    -+    private static final int PARSED_TOKEN_CHAR_SET_START = -1;
    -+    private static final int PARSED_TOKEN_CHAR_SET_INVERSE_START = -2;
    -+    private static final int PARSED_TOKEN_CHAR_SET_STOP = -3;
    -+    private static final int PARSED_TOKEN_CHAR_ANY = -4;
    -+    private static final int PARSED_MODIFIER_RANGE_START = -5;
    -+    private static final int PARSED_MODIFIER_RANGE_STOP = -6;
    -+    private static final int PARSED_MODIFIER_ZERO_OR_MORE = -7;
    -+    private static final int PARSED_MODIFIER_ONE_OR_MORE = -8;
    -+
    -     private final String mPattern;
    -     private final int mType;
    --    
    -+    private final int[] mParsedPattern;
    -+
    -+
    -+    private static final int MAX_PATTERN_STORAGE = 2048;
    -+    // workspace to use for building a parsed advanced pattern;
    -+    private static final int[] sParsedPatternScratch = new int[MAX_PATTERN_STORAGE];
    -+
    -     public PatternMatcher(String pattern, int type) {
    -         mPattern = pattern;
    -         mType = type;
    -+        if (mType == PATTERN_ADVANCED_GLOB) {
    -+            mParsedPattern = parseAndVerifyAdvancedPattern(pattern);
    -+        } else {
    -+            mParsedPattern = null;
    -+        }
    -     }
    - 
    -     public final String getPath() {
    -@@ -62,7 +112,7 @@ public class PatternMatcher implements Parcelable {
    -     }
    -     
    -     public boolean match(String str) {
    --        return matchPattern(mPattern, str, mType);
    -+        return matchPattern(str, mPattern, mParsedPattern, mType);
    -     }
    - 
    -     public String toString() {
    -@@ -77,6 +127,9 @@ public class PatternMatcher implements Parcelable {
    -             case PATTERN_SIMPLE_GLOB:
    -                 type = "GLOB: ";
    -                 break;
    -+            case PATTERN_ADVANCED_GLOB:
    -+                type = "ADVANCED: ";
    -+                break;
    -         }
    -         return "PatternMatcher{" + type + mPattern + "}";
    -     }
    -@@ -88,11 +141,13 @@ public class PatternMatcher implements Parcelable {
    -     public void writeToParcel(Parcel dest, int flags) {
    -         dest.writeString(mPattern);
    -         dest.writeInt(mType);
    -+        dest.writeIntArray(mParsedPattern);
    -     }
    -     
    -     public PatternMatcher(Parcel src) {
    -         mPattern = src.readString();
    -         mType = src.readInt();
    -+        mParsedPattern = src.createIntArray();
    -     }
    -     
    -     public static final Parcelable.Creator<PatternMatcher> CREATOR
    -@@ -106,16 +161,21 @@ public class PatternMatcher implements Parcelable {
    -         }
    -     };
    -     
    --    static boolean matchPattern(String pattern, String match, int type) {
    -+    static boolean matchPattern(String match, String pattern, int[] parsedPattern, int type) {
    -         if (match == null) return false;
    -         if (type == PATTERN_LITERAL) {
    -             return pattern.equals(match);
    -         } if (type == PATTERN_PREFIX) {
    -             return match.startsWith(pattern);
    --        } else if (type != PATTERN_SIMPLE_GLOB) {
    --            return false;
    -+        } else if (type == PATTERN_SIMPLE_GLOB) {
    -+            return matchGlobPattern(pattern, match);
    -+        } else if (type == PATTERN_ADVANCED_GLOB) {
    -+            return matchAdvancedPattern(parsedPattern, match);
    -         }
    --        
    -+        return false;
    -+    }
    -+
    -+    static boolean matchGlobPattern(String pattern, String match) {
    -         final int NP = pattern.length();
    -         if (NP <= 0) {
    -             return match.length() <= 0;
    -@@ -194,4 +254,310 @@ public class PatternMatcher implements Parcelable {
    -         
    -         return false;
    -     }
    --}
    -+
    -+    /**
    -+     * Parses the advanced pattern and returns an integer array representation of it. The integer
    -+     * array treats each field as a character if positive and a unique token placeholder if
    -+     * negative. This method will throw on any pattern structure violations.
    -+     */
    -+    synchronized static int[] parseAndVerifyAdvancedPattern(String pattern) {
    -+        int ip = 0;
    -+        final int LP = pattern.length();
    -+
    -+        int it = 0;
    -+
    -+        boolean inSet = false;
    -+        boolean inRange = false;
    -+        boolean inCharClass = false;
    -+
    -+        boolean addToParsedPattern;
    -+
    -+        while (ip < LP) {
    -+            if (it > MAX_PATTERN_STORAGE - 3) {
    -+                throw new IllegalArgumentException("Pattern is too large!");
    -+            }
    -+
    -+            char c = pattern.charAt(ip);
    -+            addToParsedPattern = false;
    -+
    -+            switch (c) {
    -+                case '[':
    -+                    if (inSet) {
    -+                        addToParsedPattern = true; // treat as literal or char class in set
    -+                    } else {
    -+                        if (pattern.charAt(ip + 1) == '^') {
    -+                            sParsedPatternScratch[it++] = PARSED_TOKEN_CHAR_SET_INVERSE_START;
    -+                            ip++; // skip over the '^'
    -+                        } else {
    -+                            sParsedPatternScratch[it++] = PARSED_TOKEN_CHAR_SET_START;
    -+                        }
    -+                        ip++; // move to the next pattern char
    -+                        inSet = true;
    -+                        continue;
    -+                    }
    -+                    break;
    -+                case ']':
    -+                    if (!inSet) {
    -+                        addToParsedPattern = true; // treat as literal outside of set
    -+                    } else {
    -+                        int parsedToken = sParsedPatternScratch[it - 1];
    -+                        if (parsedToken == PARSED_TOKEN_CHAR_SET_START ||
    -+                            parsedToken == PARSED_TOKEN_CHAR_SET_INVERSE_START) {
    -+                            throw new IllegalArgumentException(
    -+                                    "You must define characters in a set.");
    -+                        }
    -+                        sParsedPatternScratch[it++] = PARSED_TOKEN_CHAR_SET_STOP;
    -+                        inSet = false;
    -+                        inCharClass = false;
    -+                    }
    -+                    break;
    -+                case '{':
    -+                    if (!inSet) {
    -+                        if (it == 0 || isParsedModifier(sParsedPatternScratch[it - 1])) {
    -+                            throw new IllegalArgumentException("Modifier must follow a token.");
    -+                        }
    -+                        sParsedPatternScratch[it++] = PARSED_MODIFIER_RANGE_START;
    -+                        ip++;
    -+                        inRange = true;
    -+                    }
    -+                    break;
    -+                case '}':
    -+                    if (inRange) { // only terminate the range if we're currently in one
    -+                        sParsedPatternScratch[it++] = PARSED_MODIFIER_RANGE_STOP;
    -+                        inRange = false;
    -+                    }
    -+                    break;
    -+                case '*':
    -+                    if (!inSet) {
    -+                        if (it == 0 || isParsedModifier(sParsedPatternScratch[it - 1])) {
    -+                            throw new IllegalArgumentException("Modifier must follow a token.");
    -+                        }
    -+                        sParsedPatternScratch[it++] = PARSED_MODIFIER_ZERO_OR_MORE;
    -+                    }
    -+                    break;
    -+                case '+':
    -+                    if (!inSet) {
    -+                        if (it == 0 || isParsedModifier(sParsedPatternScratch[it - 1])) {
    -+                            throw new IllegalArgumentException("Modifier must follow a token.");
    -+                        }
    -+                        sParsedPatternScratch[it++] = PARSED_MODIFIER_ONE_OR_MORE;
    -+                    }
    -+                    break;
    -+                case '.':
    -+                    if (!inSet) {
    -+                        sParsedPatternScratch[it++] = PARSED_TOKEN_CHAR_ANY;
    -+                    }
    -+                    break;
    -+                case '\\': // escape
    -+                    if (ip + 1 >= LP) {
    -+                        throw new IllegalArgumentException("Escape found at end of pattern!");
    -+                    }
    -+                    c = pattern.charAt(++ip);
    -+                    addToParsedPattern = true;
    -+                    break;
    -+                default:
    -+                    addToParsedPattern = true;
    -+                    break;
    -+            }
    -+            if (inSet) {
    -+                if (inCharClass) {
    -+                    sParsedPatternScratch[it++] = c;
    -+                    inCharClass = false;
    -+                } else {
    -+                    // look forward for character class
    -+                    if (ip + 2 < LP
    -+                            && pattern.charAt(ip + 1) == '-'
    -+                            && pattern.charAt(ip + 2) != ']') {
    -+                        inCharClass = true;
    -+                        sParsedPatternScratch[it++] = c; // set first token as lower end of range
    -+                        ip++; // advance past dash
    -+                    } else { // literal
    -+                        sParsedPatternScratch[it++] = c; // set first token as literal
    -+                        sParsedPatternScratch[it++] = c; // set second set as literal
    -+                    }
    -+                }
    -+            } else if (inRange) {
    -+                int endOfSet = pattern.indexOf('}', ip);
    -+                if (endOfSet < 0) {
    -+                    throw new IllegalArgumentException("Range not ended with '}'");
    -+                }
    -+                String rangeString = pattern.substring(ip, endOfSet);
    -+                int commaIndex = rangeString.indexOf(',');
    -+                try {
    -+                    final int rangeMin;
    -+                    final int rangeMax;
    -+                    if (commaIndex < 0) {
    -+                        int parsedRange = Integer.parseInt(rangeString);
    -+                        rangeMin = rangeMax = parsedRange;
    -+                    } else {
    -+                        rangeMin = Integer.parseInt(rangeString.substring(0, commaIndex));
    -+                        if (commaIndex == rangeString.length() - 1) { // e.g. {n,} (n or more)
    -+                            rangeMax = Integer.MAX_VALUE;
    -+                        } else {
    -+                            rangeMax = Integer.parseInt(rangeString.substring(commaIndex + 1));
    -+                        }
    -+                    }
    -+                    if (rangeMin > rangeMax) {
    -+                        throw new IllegalArgumentException(
    -+                            "Range quantifier minimum is greater than maximum");
    -+                    }
    -+                    sParsedPatternScratch[it++] = rangeMin;
    -+                    sParsedPatternScratch[it++] = rangeMax;
    -+                } catch (NumberFormatException e) {
    -+                    throw new IllegalArgumentException("Range number format incorrect", e);
    -+                }
    -+                ip = endOfSet;
    -+                continue; // don't increment ip
    -+            } else if (addToParsedPattern) {
    -+                sParsedPatternScratch[it++] = c;
    -+            }
    -+            ip++;
    -+        }
    -+        if (inSet) {
    -+            throw new IllegalArgumentException("Set was not terminated!");
    -+        }
    -+        return Arrays.copyOf(sParsedPatternScratch, it);
    -+    }
    -+
    -+    private static boolean isParsedModifier(int parsedChar) {
    -+        return parsedChar == PARSED_MODIFIER_ONE_OR_MORE ||
    -+                parsedChar == PARSED_MODIFIER_ZERO_OR_MORE ||
    -+                parsedChar == PARSED_MODIFIER_RANGE_STOP ||
    -+                parsedChar == PARSED_MODIFIER_RANGE_START;
    -+    }
    -+
    -+    static boolean matchAdvancedPattern(int[] parsedPattern, String match) {
    -+
    -+        // create indexes
    -+        int ip = 0, im = 0;
    -+
    -+        // one-time length check
    -+        final int LP = parsedPattern.length, LM = match.length();
    -+
    -+        // The current character being analyzed in the pattern
    -+        int patternChar;
    -+
    -+        int tokenType;
    -+
    -+        int charSetStart = 0, charSetEnd = 0;
    -+
    -+        while (ip < LP) { // we still have content in the pattern
    -+
    -+            patternChar = parsedPattern[ip];
    -+            // get the match type of the next verb
    -+
    -+            switch (patternChar) {
    -+                case PARSED_TOKEN_CHAR_ANY:
    -+                    tokenType = TOKEN_TYPE_ANY;
    -+                    ip++;
    -+                    break;
    -+                case PARSED_TOKEN_CHAR_SET_START:
    -+                case PARSED_TOKEN_CHAR_SET_INVERSE_START:
    -+                    tokenType = patternChar == PARSED_TOKEN_CHAR_SET_START
    -+                            ? TOKEN_TYPE_SET
    -+                            : TOKEN_TYPE_INVERSE_SET;
    -+                    charSetStart = ip + 1; // start from the char after the set start
    -+                    while (++ip < LP && parsedPattern[ip] != PARSED_TOKEN_CHAR_SET_STOP);
    -+                    charSetEnd = ip - 1; // we're on the set stop, end is the previous
    -+                    ip++; // move the pointer to the next pattern entry
    -+                    break;
    -+                default:
    -+                    charSetStart = ip;
    -+                    tokenType = TOKEN_TYPE_LITERAL;
    -+                    ip++;
    -+                    break;
    -+            }
    -+
    -+            final int minRepetition;
    -+            final int maxRepetition;
    -+
    -+            // look for a match length modifier
    -+            if (ip >= LP) {
    -+                minRepetition = maxRepetition = 1;
    -+            } else {
    -+                patternChar = parsedPattern[ip];
    -+                switch (patternChar) {
    -+                    case PARSED_MODIFIER_ZERO_OR_MORE:
    -+                        minRepetition = 0;
    -+                        maxRepetition = Integer.MAX_VALUE;
    -+                        ip++;
    -+                        break;
    -+                    case PARSED_MODIFIER_ONE_OR_MORE:
    -+                        minRepetition = 1;
    -+                        maxRepetition = Integer.MAX_VALUE;
    -+                        ip++;
    -+                        break;
    -+                    case PARSED_MODIFIER_RANGE_START:
    -+                        minRepetition = parsedPattern[++ip];
    -+                        maxRepetition = parsedPattern[++ip];
    -+                        ip += 2; // step over PARSED_MODIFIER_RANGE_STOP and on to the next token
    -+                        break;
    -+                    default:
    -+                        minRepetition = maxRepetition = 1; // implied literal
    -+                        break;
    -+                }
    -+            }
    -+            if (minRepetition > maxRepetition) {
    -+                return false;
    -+            }
    -+
    -+            // attempt to match as many characters as possible
    -+            int matched = matchChars(match, im, LM, tokenType, minRepetition, maxRepetition,
    -+                    parsedPattern, charSetStart, charSetEnd);
    -+
    -+            // if we found a conflict, return false immediately
    -+            if (matched == NO_MATCH) {
    -+                return false;
    -+            }
    -+
    -+            // move the match pointer the number of characters matched
    -+            im += matched;
    -+        }
    -+        return ip >= LP && im >= LM; // have parsed entire string and regex
    -+    }
    -+
    -+    private static int matchChars(String match, int im, final int lm, int tokenType,
    -+            int minRepetition, int maxRepetition, int[] parsedPattern,
    -+            int tokenStart, int tokenEnd) {
    -+        int matched = 0;
    -+
    -+        while(matched < maxRepetition
    -+                && matchChar(match, im + matched, lm, tokenType, parsedPattern, tokenStart,
    -+                    tokenEnd)) {
    -+            matched++;
    -+        }
    -+
    -+        return matched < minRepetition ? NO_MATCH : matched;
    -+    }
    -+
    -+    private static boolean matchChar(String match, int im, final int lm, int tokenType,
    -+            int[] parsedPattern, int tokenStart, int tokenEnd) {
    -+        if (im >= lm) { // we've overrun the string, no match
    -+            return false;
    -+        }
    -+        switch (tokenType) {
    -+            case TOKEN_TYPE_ANY:
    -+                return true;
    -+            case TOKEN_TYPE_SET:
    -+                for (int i = tokenStart; i < tokenEnd; i += 2) {
    -+                    char matchChar = match.charAt(im);
    -+                    if (matchChar >= parsedPattern[i] && matchChar <= parsedPattern[i + 1]) {
    -+                        return true;
    -+                    }
    -+                }
    -+                return false;
    -+            case TOKEN_TYPE_INVERSE_SET:
    -+                for (int i = tokenStart; i < tokenEnd; i += 2) {
    -+                    char matchChar = match.charAt(im);
    -+                    if (matchChar >= parsedPattern[i] && matchChar <= parsedPattern[i + 1]) {
    -+                        return false;
    -+                    }
    -+                }
    -+                return true;
    -+            case TOKEN_TYPE_LITERAL:
    -+                return match.charAt(im) == parsedPattern[tokenStart];
    -+            default:
    -+                return false;
    -+        }
    -+    }
    -+}
    -\ No newline at end of file
    -diff --git a/core/java/android/os/PowerManager.java b/core/java/android/os/PowerManager.java
    -index ce7a124..8d4d0a5 100644
    ---- a/core/java/android/os/PowerManager.java
    -+++ b/core/java/android/os/PowerManager.java
    -@@ -1340,6 +1340,11 @@ public final class PowerManager {
    -         }
    - 
    -         /** @hide */
    -+        public String getTag() {
    -+            return mTag;
    -+        }
    -+
    -+        /** @hide */
    -         public void setHistoryTag(String tag) {
    -             mHistoryTag = tag;
    -         }
    -@@ -1358,5 +1363,34 @@ public final class PowerManager {
    -                     + " held=" + mHeld + ", refCount=" + mCount + "}";
    -             }
    -         }
    -+
    -+        /**
    -+         * Wraps a Runnable such that this method immediately acquires the wake lock and then
    -+         * once the Runnable is done the wake lock is released.
    -+         *
    -+         * <p>Example:
    -+         *
    -+         * <pre>
    -+         * mHandler.post(mWakeLock.wrap(() -> {
    -+         *     // do things on handler, lock is held while we're waiting for this
    -+         *     // to get scheduled and until the runnable is done executing.
    -+         * });
    -+         * </pre>
    -+         *
    -+         * <p>Note: you must make sure that the Runnable eventually gets executed, otherwise you'll
    -+         *    leak the wakelock!
    -+         *
    -+         * @hide
    -+         */
    -+        public Runnable wrap(Runnable r) {
    -+            acquire();
    -+            return () -> {
    -+                try {
    -+                    r.run();
    -+                } finally {
    -+                    release();
    -+                }
    -+            };
    -+        }
    -     }
    - }
    -diff --git a/core/java/android/os/RecoverySystem.java b/core/java/android/os/RecoverySystem.java
    -index 507379b..d48431a 100644
    ---- a/core/java/android/os/RecoverySystem.java
    -+++ b/core/java/android/os/RecoverySystem.java
    -@@ -93,6 +93,14 @@ public class RecoverySystem {
    -      */
    -     public static final File UNCRYPT_PACKAGE_FILE = new File(RECOVERY_DIR, "uncrypt_file");
    - 
    -+    /**
    -+     * UNCRYPT_STATUS_FILE stores the time cost (and error code in the case of a failure)
    -+     * of uncrypt.
    -+     *
    -+     * @hide
    -+     */
    -+    public static final File UNCRYPT_STATUS_FILE = new File(RECOVERY_DIR, "uncrypt_status");
    -+
    -     // Length limits for reading files.
    -     private static final int LOG_FILE_MAX_LENGTH = 64 * 1024;
    - 
    -@@ -692,28 +700,22 @@ public class RecoverySystem {
    -      * @throws IOException if something goes wrong.
    -      */
    -     private static void bootCommand(Context context, String... args) throws IOException {
    --        synchronized (sRequestLock) {
    --            LOG_FILE.delete();
    -+        LOG_FILE.delete();
    - 
    --            StringBuilder command = new StringBuilder();
    --            for (String arg : args) {
    --                if (!TextUtils.isEmpty(arg)) {
    --                    command.append(arg);
    --                    command.append("\n");
    --                }
    -+        StringBuilder command = new StringBuilder();
    -+        for (String arg : args) {
    -+            if (!TextUtils.isEmpty(arg)) {
    -+                command.append(arg);
    -+                command.append("\n");
    -             }
    -+        }
    - 
    --            // Write the command into BCB (bootloader control block).
    --            RecoverySystem rs = (RecoverySystem) context.getSystemService(
    --                    Context.RECOVERY_SERVICE);
    --            rs.setupBcb(command.toString());
    --
    --            // Having set up the BCB, go ahead and reboot.
    --            PowerManager pm = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
    --            pm.reboot(PowerManager.REBOOT_RECOVERY);
    -+        // Write the command into BCB (bootloader control block) and boot from
    -+        // there. Will not return unless failed.
    -+        RecoverySystem rs = (RecoverySystem) context.getSystemService(Context.RECOVERY_SERVICE);
    -+        rs.rebootRecoveryWithCommand(command.toString());
    - 
    --            throw new IOException("Reboot failed (no permissions?)");
    --        }
    -+        throw new IOException("Reboot failed (no permissions?)");
    -     }
    - 
    -     // Read last_install; then report time (in seconds) and I/O (in MiB) for
    -@@ -724,6 +726,7 @@ public class RecoverySystem {
    -             String line = null;
    -             int bytesWrittenInMiB = -1, bytesStashedInMiB = -1;
    -             int timeTotal = -1;
    -+            int uncryptTime = -1;
    -             int sourceVersion = -1;
    -             while ((line = in.readLine()) != null) {
    -                 // Here is an example of lines in last_install:
    -@@ -759,6 +762,8 @@ public class RecoverySystem {
    - 
    -                 if (line.startsWith("time")) {
    -                     timeTotal = scaled;
    -+                } else if (line.startsWith("uncrypt_time")) {
    -+                    uncryptTime = scaled;
    -                 } else if (line.startsWith("source_build")) {
    -                     sourceVersion = scaled;
    -                 } else if (line.startsWith("bytes_written")) {
    -@@ -774,6 +779,9 @@ public class RecoverySystem {
    -             if (timeTotal != -1) {
    -                 MetricsLogger.histogram(context, "ota_time_total", timeTotal);
    -             }
    -+            if (uncryptTime != -1) {
    -+                MetricsLogger.histogram(context, "ota_uncrypt_time", uncryptTime);
    -+            }
    -             if (sourceVersion != -1) {
    -                 MetricsLogger.histogram(context, "ota_source_version", sourceVersion);
    -             }
    -@@ -902,6 +910,17 @@ public class RecoverySystem {
    -     }
    - 
    -     /**
    -+     * Talks to RecoverySystemService via Binder to set up the BCB command and
    -+     * reboot into recovery accordingly.
    -+     */
    -+    private void rebootRecoveryWithCommand(String command) {
    -+        try {
    -+            mService.rebootRecoveryWithCommand(command);
    -+        } catch (RemoteException ignored) {
    -+        }
    -+    }
    -+
    -+    /**
    -      * Internally, recovery treats each line of the command file as a separate
    -      * argv, so we only need to protect against newlines and nulls.
    -      */
    -diff --git a/core/java/android/os/RemoteCallbackList.java b/core/java/android/os/RemoteCallbackList.java
    -index 5849350..3546e17 100644
    ---- a/core/java/android/os/RemoteCallbackList.java
    -+++ b/core/java/android/os/RemoteCallbackList.java
    -@@ -288,20 +288,22 @@ public class RemoteCallbackList<E extends IInterface> {
    -      * @see #beginBroadcast
    -      */
    -     public void finishBroadcast() {
    --        if (mBroadcastCount < 0) {
    --            throw new IllegalStateException(
    --                    "finishBroadcast() called outside of a broadcast");
    --        }
    --        
    --        Object[] active = mActiveBroadcast;
    --        if (active != null) {
    --            final int N = mBroadcastCount;
    --            for (int i=0; i<N; i++) {
    --                active[i] = null;
    -+        synchronized (mCallbacks) {
    -+            if (mBroadcastCount < 0) {
    -+                throw new IllegalStateException(
    -+                        "finishBroadcast() called outside of a broadcast");
    -             }
    -+
    -+            Object[] active = mActiveBroadcast;
    -+            if (active != null) {
    -+                final int N = mBroadcastCount;
    -+                for (int i=0; i<N; i++) {
    -+                    active[i] = null;
    -+                }
    -+            }
    -+
    -+            mBroadcastCount = -1;
    -         }
    --        
    --        mBroadcastCount = -1;
    -     }
    - 
    -     /**
    -diff --git a/core/java/android/os/Trace.java b/core/java/android/os/Trace.java
    -index 9e8103a..3ae28fd 100644
    ---- a/core/java/android/os/Trace.java
    -+++ b/core/java/android/os/Trace.java
    -@@ -81,6 +81,8 @@ public final class Trace {
    -     public static final long TRACE_TAG_SYSTEM_SERVER = 1L << 19;
    -     /** @hide */
    -     public static final long TRACE_TAG_DATABASE = 1L << 20;
    -+    /** @hide */
    -+    public static final long TRACE_TAG_NETWORK = 1L << 21;
    - 
    -     private static final long TRACE_TAG_NOT_READY = 1L << 63;
    -     private static final int MAX_SECTION_NAME_LEN = 127;
    -diff --git a/core/java/android/os/storage/VolumeInfo.java b/core/java/android/os/storage/VolumeInfo.java
    -index 5a98482..19210b5 100644
    ---- a/core/java/android/os/storage/VolumeInfo.java
    -+++ b/core/java/android/os/storage/VolumeInfo.java
    -@@ -437,7 +437,7 @@ public class VolumeInfo implements Parcelable {
    - 
    -         final Intent intent = new Intent(DocumentsContract.ACTION_BROWSE);
    -         intent.addCategory(Intent.CATEGORY_DEFAULT);
    --        intent.setData(uri);
    -+        intent.setDataAndType(uri, DocumentsContract.Root.MIME_TYPE_ITEM);
    - 
    -         // note that docsui treats this as *force* show advanced. So sending
    -         // false permits advanced to be shown based on user preferences.
    -diff --git a/core/java/android/provider/CallLog.java b/core/java/android/provider/CallLog.java
    -index fbd61cf..c7c6ceb 100644
    ---- a/core/java/android/provider/CallLog.java
    -+++ b/core/java/android/provider/CallLog.java
    -@@ -284,8 +284,10 @@ public class CallLog {
    - 
    -         /**
    -          * The cached name associated with the phone number, if it exists.
    --         * This value is not guaranteed to be current, if the contact information
    --         * associated with this number has changed.
    -+         *
    -+         * <p>This value is typically filled in by the dialer app for the caching purpose,
    -+         * so it's not guaranteed to be present, and may not be current if the contact
    -+         * information associated with this number has changed.
    -          * <P>Type: TEXT</P>
    -          */
    -         public static final String CACHED_NAME = "name";
    -@@ -293,8 +295,10 @@ public class CallLog {
    -         /**
    -          * The cached number type (Home, Work, etc) associated with the
    -          * phone number, if it exists.
    --         * This value is not guaranteed to be current, if the contact information
    --         * associated with this number has changed.
    -+         *
    -+         * <p>This value is typically filled in by the dialer app for the caching purpose,
    -+         * so it's not guaranteed to be present, and may not be current if the contact
    -+         * information associated with this number has changed.
    -          * <P>Type: INTEGER</P>
    -          */
    -         public static final String CACHED_NUMBER_TYPE = "numbertype";
    -@@ -302,8 +306,10 @@ public class CallLog {
    -         /**
    -          * The cached number label, for a custom number type, associated with the
    -          * phone number, if it exists.
    --         * This value is not guaranteed to be current, if the contact information
    --         * associated with this number has changed.
    -+         *
    -+         * <p>This value is typically filled in by the dialer app for the caching purpose,
    -+         * so it's not guaranteed to be present, and may not be current if the contact
    -+         * information associated with this number has changed.
    -          * <P>Type: TEXT</P>
    -          */
    -         public static final String CACHED_NUMBER_LABEL = "numberlabel";
    -@@ -339,40 +345,50 @@ public class CallLog {
    - 
    -         /**
    -          * The cached URI to look up the contact associated with the phone number, if it exists.
    --         * This value may not be current if the contact information associated with this number
    --         * has changed.
    -+         *
    -+         * <p>This value is typically filled in by the dialer app for the caching purpose,
    -+         * so it's not guaranteed to be present, and may not be current if the contact
    -+         * information associated with this number has changed.
    -          * <P>Type: TEXT</P>
    -          */
    -         public static final String CACHED_LOOKUP_URI = "lookup_uri";
    - 
    -         /**
    -          * The cached phone number of the contact which matches this entry, if it exists.
    --         * This value may not be current if the contact information associated with this number
    --         * has changed.
    -+         *
    -+         * <p>This value is typically filled in by the dialer app for the caching purpose,
    -+         * so it's not guaranteed to be present, and may not be current if the contact
    -+         * information associated with this number has changed.
    -          * <P>Type: TEXT</P>
    -          */
    -         public static final String CACHED_MATCHED_NUMBER = "matched_number";
    - 
    -         /**
    -          * The cached normalized(E164) version of the phone number, if it exists.
    --         * This value may not be current if the contact information associated with this number
    --         * has changed.
    -+         *
    -+         * <p>This value is typically filled in by the dialer app for the caching purpose,
    -+         * so it's not guaranteed to be present, and may not be current if the contact
    -+         * information associated with this number has changed.
    -          * <P>Type: TEXT</P>
    -          */
    -         public static final String CACHED_NORMALIZED_NUMBER = "normalized_number";
    - 
    -         /**
    -          * The cached photo id of the picture associated with the phone number, if it exists.
    --         * This value may not be current if the contact information associated with this number
    --         * has changed.
    -+         *
    -+         * <p>This value is typically filled in by the dialer app for the caching purpose,
    -+         * so it's not guaranteed to be present, and may not be current if the contact
    -+         * information associated with this number has changed.
    -          * <P>Type: INTEGER (long)</P>
    -          */
    -         public static final String CACHED_PHOTO_ID = "photo_id";
    - 
    -         /**
    -          * The cached photo URI of the picture associated with the phone number, if it exists.
    --         * This value may not be current if the contact information associated with this number
    --         * has changed.
    -+         *
    -+         * <p>This value is typically filled in by the dialer app for the caching purpose,
    -+         * so it's not guaranteed to be present, and may not be current if the contact
    -+         * information associated with this number has changed.
    -          * <P>Type: TEXT (URI)</P>
    -          */
    -         public static final String CACHED_PHOTO_URI = "photo_uri";
    -@@ -380,9 +396,10 @@ public class CallLog {
    -         /**
    -          * The cached phone number, formatted with formatting rules based on the country the
    -          * user was in when the call was made or received.
    --         * This value is not guaranteed to be present, and may not be current if the contact
    --         * information associated with this number
    --         * has changed.
    -+         *
    -+         * <p>This value is typically filled in by the dialer app for the caching purpose,
    -+         * so it's not guaranteed to be present, and may not be current if the contact
    -+         * information associated with this number has changed.
    -          * <P>Type: TEXT</P>
    -          */
    -         public static final String CACHED_FORMATTED_NUMBER = "formatted_number";
    -diff --git a/core/java/android/provider/ContactsContract.java b/core/java/android/provider/ContactsContract.java
    -index c70304e..c495e6c 100644
    ---- a/core/java/android/provider/ContactsContract.java
    -+++ b/core/java/android/provider/ContactsContract.java
    -@@ -35,6 +35,7 @@ import android.content.Intent;
    - import android.content.res.AssetFileDescriptor;
    - import android.content.res.Resources;
    - import android.database.Cursor;
    -+import android.database.CursorWrapper;
    - import android.database.DatabaseUtils;
    - import android.graphics.Rect;
    - import android.net.Uri;
    -@@ -138,8 +139,20 @@ public final class ContactsContract {
    -     public static final String DIRECTORY_PARAM_KEY = "directory";
    - 
    -     /**
    --     * A query parameter that limits the number of results returned. The
    -+     * A query parameter that limits the number of results returned for supported URIs. The
    -      * parameter value should be an integer.
    -+     *
    -+     * <p>This parameter is not supported by all URIs.  Supported URIs include, but not limited to,
    -+     * {@link Contacts#CONTENT_URI},
    -+     * {@link RawContacts#CONTENT_URI},
    -+     * {@link Data#CONTENT_URI},
    -+     * {@link CommonDataKinds.Phone#CONTENT_URI},
    -+     * {@link CommonDataKinds.Callable#CONTENT_URI},
    -+     * {@link CommonDataKinds.Email#CONTENT_URI},
    -+     * {@link CommonDataKinds.Contactables#CONTENT_URI},
    -+     *
    -+     * <p>In order to limit the number of rows returned by a non-supported URI, you can implement a
    -+     * {@link CursorWrapper} and override the {@link CursorWrapper#getCount()} methods.
    -      */
    -     public static final String LIMIT_PARAM_KEY = "limit";
    - 
    -@@ -437,6 +450,9 @@ public final class ContactsContract {
    - 
    -         /**
    -          * _ID of the default directory, which represents locally stored contacts.
    -+         * <b>This is only supported by {@link ContactsContract.Contacts#CONTENT_URI} and
    -+         * {@link ContactsContract.Contacts#CONTENT_FILTER_URI}.
    -+         * Other URLs do not support the concept of "visible" or "invisible" contacts.
    -          */
    -         public static final long DEFAULT = 0;
    - 
    -diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
    -index ce6fcdd..8bb6942 100755
    ---- a/core/java/android/provider/Settings.java
    -+++ b/core/java/android/provider/Settings.java
    -@@ -44,7 +44,6 @@ import android.net.ConnectivityManager;
    - import android.net.Uri;
    - import android.net.wifi.WifiManager;
    - import android.os.BatteryManager;
    --import android.os.Binder;
    - import android.os.Bundle;
    - import android.os.DropBoxManager;
    - import android.os.IBinder;
    -@@ -1284,6 +1283,19 @@ public final class Settings {
    -             = "android.settings.VR_LISTENER_SETTINGS";
    - 
    -     /**
    -+     * Activity Action: Show Storage Manager settings.
    -+     * <p>
    -+     * Input: Nothing.
    -+     * <p>
    -+     * Output: Nothing.
    -+     *
    -+     * @hide
    -+     */
    -+    @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
    -+    public static final String ACTION_STORAGE_MANAGER_SETTINGS
    -+            = "android.settings.STORAGE_MANAGER_SETTINGS";
    -+
    -+    /**
    -      * Activity Action: Allows user to select current webview implementation.
    -      * <p>
    -      * Input: Nothing.
    -@@ -1838,7 +1850,6 @@ public final class Settings {
    -             MOVED_TO_GLOBAL.add(Settings.Global.CALL_AUTO_RETRY);
    -             MOVED_TO_GLOBAL.add(Settings.Global.DEBUG_APP);
    -             MOVED_TO_GLOBAL.add(Settings.Global.WAIT_FOR_DEBUGGER);
    --            MOVED_TO_GLOBAL.add(Settings.Global.SHOW_PROCESSES);
    -             MOVED_TO_GLOBAL.add(Settings.Global.ALWAYS_FINISH_ACTIVITIES);
    -             MOVED_TO_GLOBAL.add(Settings.Global.TZINFO_UPDATE_CONTENT_URL);
    -             MOVED_TO_GLOBAL.add(Settings.Global.TZINFO_UPDATE_METADATA_URL);
    -@@ -2775,7 +2786,8 @@ public final class Settings {
    -         /**
    -          * Control whether the process CPU usage meter should be shown.
    -          *
    --         * @deprecated Use {@link Global#SHOW_PROCESSES} instead
    -+         * @deprecated This functionality is no longer available as of
    -+         * {@link android.os.Build.VERSION_CODES#N_MR1}.
    -          */
    -         @Deprecated
    -         public static final String SHOW_PROCESSES = Global.SHOW_PROCESSES;
    -@@ -5839,6 +5851,8 @@ public final class Settings {
    -         /**
    -          * If nonzero, ANRs in invisible background processes bring up a dialog.
    -          * Otherwise, the process will be silently killed.
    -+         *
    -+         * Also prevents ANRs and crash dialogs from being suppressed.
    -          * @hide
    -          */
    -         public static final String ANR_SHOW_BACKGROUND = "anr_show_background";
    -@@ -5927,6 +5941,18 @@ public final class Settings {
    -         public static final String DOZE_ENABLED = "doze_enabled";
    - 
    -         /**
    -+         * Whether the device should pulse on pick up gesture.
    -+         * @hide
    -+         */
    -+        public static final String DOZE_PULSE_ON_PICK_UP = "doze_pulse_on_pick_up";
    -+
    -+        /**
    -+         * Whether the device should pulse on double tap gesture.
    -+         * @hide
    -+         */
    -+        public static final String DOZE_PULSE_ON_DOUBLE_TAP = "doze_pulse_on_double_tap";
    -+
    -+        /**
    -          * The current night mode that has been selected by the user.  Owned
    -          * and controlled by UiModeManagerService.  Constants are as per
    -          * UiModeManager.
    -@@ -6324,6 +6350,13 @@ public final class Settings {
    -                 = "demo_user_setup_complete";
    - 
    -         /**
    -+         * Specifies whether the web action API is enabled.
    -+         *
    -+         * @hide
    -+         */
    -+        public static final String WEB_ACTION_ENABLED = "web_action_enabled";
    -+
    -+        /**
    -          * This are the settings to be backed up.
    -          *
    -          * NOTE: Settings are backed up and restored in the order they appear
    -@@ -6404,6 +6437,9 @@ public final class Settings {
    -             CAMERA_DOUBLE_TAP_POWER_GESTURE_DISABLED,
    -             SYSTEM_NAVIGATION_KEYS_ENABLED,
    -             QS_TILES,
    -+            DOZE_ENABLED,
    -+            DOZE_PULSE_ON_PICK_UP,
    -+            DOZE_PULSE_ON_DOUBLE_TAP
    -         };
    - 
    -         /**
    -@@ -7924,12 +7960,37 @@ public final class Settings {
    -         /**
    -          * The server used for captive portal detection upon a new conection. A
    -          * 204 response code from the server is used for validation.
    -+         * TODO: remove this deprecated symbol.
    -          *
    -          * @hide
    -          */
    -         public static final String CAPTIVE_PORTAL_SERVER = "captive_portal_server";
    - 
    -         /**
    -+         * The URL used for HTTPS captive portal detection upon a new connection.
    -+         * A 204 response code from the server is used for validation.
    -+         *
    -+         * @hide
    -+         */
    -+        public static final String CAPTIVE_PORTAL_HTTPS_URL = "captive_portal_https_url";
    -+
    -+        /**
    -+         * The URL used for HTTP captive portal detection upon a new connection.
    -+         * A 204 response code from the server is used for validation.
    -+         *
    -+         * @hide
    -+         */
    -+        public static final String CAPTIVE_PORTAL_HTTP_URL = "captive_portal_http_url";
    -+
    -+        /**
    -+         * The URL used for fallback HTTP captive portal detection when previous HTTP
    -+         * and HTTPS captive portal detection attemps did not return a conclusive answer.
    -+         *
    -+         * @hide
    -+         */
    -+        public static final String CAPTIVE_PORTAL_FALLBACK_URL = "captive_portal_fallback_url";
    -+
    -+        /**
    -          * Whether to use HTTPS for network validation. This is enabled by default and the setting
    -          * needs to be set to 0 to disable it. This setting is a misnomer because captive portals
    -          * don't actually use HTTPS, but it's consistent with the other settings.
    -@@ -7939,6 +8000,14 @@ public final class Settings {
    -         public static final String CAPTIVE_PORTAL_USE_HTTPS = "captive_portal_use_https";
    - 
    -         /**
    -+         * Which User-Agent string to use in the header of the captive portal detection probes.
    -+         * The User-Agent field is unset when this setting has no value (HttpUrlConnection default).
    -+         *
    -+         * @hide
    -+         */
    -+        public static final String CAPTIVE_PORTAL_USER_AGENT = "captive_portal_user_agent";
    -+
    -+        /**
    -          * Whether network service discovery is enabled.
    -          *
    -          * @hide
    -@@ -8311,6 +8380,13 @@ public final class Settings {
    -         public static final String CALL_AUTO_RETRY = "call_auto_retry";
    - 
    -         /**
    -+         * A setting that can be read whether the emergency affordance is currently needed.
    -+         * The value is a boolean (1 or 0).
    -+         * @hide
    -+         */
    -+        public static final String EMERGENCY_AFFORDANCE_NEEDED = "emergency_affordance_needed";
    -+
    -+        /**
    -          * See RIL_PreferredNetworkType in ril.h
    -          * @hide
    -          */
    -@@ -8330,7 +8406,11 @@ public final class Settings {
    - 
    -         /**
    -          * Control whether the process CPU usage meter should be shown.
    -+         *
    -+         * @deprecated This functionality is no longer available as of
    -+         * {@link android.os.Build.VERSION_CODES#N_MR1}.
    -          */
    -+        @Deprecated
    -         public static final String SHOW_PROCESSES = "show_processes";
    - 
    -         /**
    -@@ -8642,7 +8722,7 @@ public final class Settings {
    -         public static final String WFC_IMS_ENABLED = "wfc_ims_enabled";
    - 
    -         /**
    --         * WFC Mode.
    -+         * WFC mode on home/non-roaming network.
    -          * <p>
    -          * Type: int - 2=Wi-Fi preferred, 1=Cellular preferred, 0=Wi-Fi only
    -          *
    -@@ -8651,6 +8731,15 @@ public final class Settings {
    -         public static final String WFC_IMS_MODE = "wfc_ims_mode";
    - 
    -         /**
    -+         * WFC mode on roaming network.
    -+         * <p>
    -+         * Type: int - see {@link WFC_IMS_MODE} for values
    -+         *
    -+         * @hide
    -+         */
    -+        public static final String WFC_IMS_ROAMING_MODE = "wfc_ims_roaming_mode";
    -+
    -+        /**
    -          * Whether WFC roaming is enabled
    -          * <p>
    -          * Type: int (0 for false, 1 for true)
    -@@ -8678,6 +8767,16 @@ public final class Settings {
    -                 "ephemeral_cookie_max_size_bytes";
    - 
    -         /**
    -+         * Toggle to enable/disable the entire ephemeral feature. By default, ephemeral is
    -+         * enabled. Set to zero to disable.
    -+         * <p>
    -+         * Type: int (0 for false, 1 for true)
    -+         *
    -+         * @hide
    -+         */
    -+        public static final String ENABLE_EPHEMERAL_FEATURE = "enable_ephemeral_feature";
    -+
    -+        /**
    -          * A mask applied to the ephemeral hash to generate the hash prefix.
    -          * <p>
    -          * Type: int
    -@@ -8756,6 +8855,16 @@ public final class Settings {
    -         public static final String RETAIL_DEMO_MODE_CONSTANTS = "retail_demo_mode_constants";
    - 
    -         /**
    -+         * The reason for the settings database being downgraded. This is only for
    -+         * troubleshooting purposes and its value should not be interpreted in any way.
    -+         *
    -+         * Type: string
    -+         *
    -+         * @hide
    -+         */
    -+        public static final String DATABASE_DOWNGRADE_REASON = "database_downgrade_reason";
    -+
    -+        /**
    -          * Settings to backup. This is here so that it's in the same place as the settings
    -          * keys and easy to update.
    -          *
    -diff --git a/core/java/android/security/net/config/DirectoryCertificateSource.java b/core/java/android/security/net/config/DirectoryCertificateSource.java
    -index e3c9d65..119f5d0 100644
    ---- a/core/java/android/security/net/config/DirectoryCertificateSource.java
    -+++ b/core/java/android/security/net/config/DirectoryCertificateSource.java
    -@@ -19,6 +19,7 @@ package android.security.net.config;
    - import android.os.Environment;
    - import android.os.UserHandle;
    - import android.util.ArraySet;
    -+import android.util.Log;
    - import android.util.Pair;
    - import java.io.BufferedInputStream;
    - import java.io.File;
    -@@ -44,6 +45,7 @@ import javax.security.auth.x500.X500Principal;
    -  * @hide
    -  */
    - abstract class DirectoryCertificateSource implements CertificateSource {
    -+    private static final String LOG_TAG = "DirectoryCertificateSrc";
    -     private final File mDir;
    -     private final Object mLock = new Object();
    -     private final CertificateFactory mCertFactory;
    -@@ -149,6 +151,9 @@ abstract class DirectoryCertificateSource implements CertificateSource {
    -                 continue;
    -             }
    -             X509Certificate cert = readCertificate(fileName);
    -+            if (cert == null) {
    -+                continue;
    -+            }
    -             if (!subj.equals(cert.getSubjectX500Principal())) {
    -                 continue;
    -             }
    -@@ -173,6 +178,9 @@ abstract class DirectoryCertificateSource implements CertificateSource {
    -                 continue;
    -             }
    -             X509Certificate cert = readCertificate(fileName);
    -+            if (cert == null) {
    -+                continue;
    -+            }
    -             if (!subj.equals(cert.getSubjectX500Principal())) {
    -                 continue;
    -             }
    -@@ -194,6 +202,7 @@ abstract class DirectoryCertificateSource implements CertificateSource {
    -             is = new BufferedInputStream(new FileInputStream(new File(mDir, file)));
    -             return (X509Certificate) mCertFactory.generateCertificate(is);
    -         } catch (CertificateException | IOException e) {
    -+            Log.e(LOG_TAG, "Failed to read certificate from " + file, e);
    -             return null;
    -         } finally {
    -             IoUtils.closeQuietly(is);
    -diff --git a/core/java/android/service/dreams/DreamService.java b/core/java/android/service/dreams/DreamService.java
    -index 0557d13..94505d3 100644
    ---- a/core/java/android/service/dreams/DreamService.java
    -+++ b/core/java/android/service/dreams/DreamService.java
    -@@ -27,6 +27,7 @@ import android.graphics.PixelFormat;
    - import android.graphics.drawable.ColorDrawable;
    - import android.os.Handler;
    - import android.os.IBinder;
    -+import android.os.IRemoteCallback;
    - import android.os.PowerManager;
    - import android.os.RemoteException;
    - import android.os.ServiceManager;
    -@@ -942,8 +943,9 @@ public class DreamService extends Service implements Window.Callback {
    -      * Must run on mHandler.
    -      *
    -      * @param windowToken A window token that will allow a window to be created in the correct layer.
    -+     * @param started A callback that will be invoked once onDreamingStarted has completed.
    -      */
    --    private final void attach(IBinder windowToken, boolean canDoze) {
    -+    private final void attach(IBinder windowToken, boolean canDoze, IRemoteCallback started) {
    -         if (mWindowToken != null) {
    -             Slog.e(TAG, "attach() called when already attached with token=" + mWindowToken);
    -             return;
    -@@ -1017,7 +1019,15 @@ public class DreamService extends Service implements Window.Callback {
    -                 if (mWindow != null || mWindowless) {
    -                     if (mDebug) Slog.v(TAG, "Calling onDreamingStarted()");
    -                     mStarted = true;
    --                    onDreamingStarted();
    -+                    try {
    -+                        onDreamingStarted();
    -+                    } finally {
    -+                        try {
    -+                            started.sendResult(null);
    -+                        } catch (RemoteException e) {
    -+                            throw e.rethrowFromSystemServer();
    -+                        }
    -+                    }
    -                 }
    -             }
    -         });
    -@@ -1092,11 +1102,12 @@ public class DreamService extends Service implements Window.Callback {
    - 
    -     private final class DreamServiceWrapper extends IDreamService.Stub {
    -         @Override
    --        public void attach(final IBinder windowToken, final boolean canDoze) {
    -+        public void attach(final IBinder windowToken, final boolean canDoze,
    -+                IRemoteCallback started) {
    -             mHandler.post(new Runnable() {
    -                 @Override
    -                 public void run() {
    --                    DreamService.this.attach(windowToken, canDoze);
    -+                    DreamService.this.attach(windowToken, canDoze, started);
    -                 }
    -             });
    -         }
    -diff --git a/core/java/android/service/dreams/IDreamService.aidl b/core/java/android/service/dreams/IDreamService.aidl
    -index 9bb1804..ce04354 100644
    ---- a/core/java/android/service/dreams/IDreamService.aidl
    -+++ b/core/java/android/service/dreams/IDreamService.aidl
    -@@ -16,11 +16,13 @@
    - 
    - package android.service.dreams;
    - 
    -+import android.os.IRemoteCallback;
    -+
    - /**
    -  * @hide
    -  */
    - oneway interface IDreamService {
    --    void attach(IBinder windowToken, boolean canDoze);
    -+    void attach(IBinder windowToken, boolean canDoze, IRemoteCallback started);
    -     void detach();
    -     void wakeUp();
    - }
    -diff --git a/core/java/android/util/DisplayMetrics.java b/core/java/android/util/DisplayMetrics.java
    -index f4db4d6..b7099b6 100644
    ---- a/core/java/android/util/DisplayMetrics.java
    -+++ b/core/java/android/util/DisplayMetrics.java
    -@@ -268,6 +268,10 @@ public class DisplayMetrics {
    -     }
    -     
    -     public void setTo(DisplayMetrics o) {
    -+        if (this == o) {
    -+            return;
    -+        }
    -+
    -         widthPixels = o.widthPixels;
    -         heightPixels = o.heightPixels;
    -         density = o.density;
    -diff --git a/core/java/android/util/PackageUtils.java b/core/java/android/util/PackageUtils.java
    -new file mode 100644
    -index 0000000..6531aef
    ---- /dev/null
    -+++ b/core/java/android/util/PackageUtils.java
    -@@ -0,0 +1,96 @@
    -+/*
    -+ * Copyright (C) 2016 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 android.util;
    -+
    -+import android.annotation.NonNull;
    -+import android.annotation.Nullable;
    -+import android.content.pm.PackageInfo;
    -+import android.content.pm.PackageManager;
    -+import android.content.pm.Signature;
    -+
    -+import java.security.MessageDigest;
    -+import java.security.NoSuchAlgorithmException;
    -+
    -+/**
    -+ * Helper functions applicable to packages.
    -+ * @hide
    -+ */
    -+public final class PackageUtils {
    -+    private final static char[] HEX_ARRAY = "0123456789ABCDEF".toCharArray();
    -+
    -+    private PackageUtils() {
    -+        /* hide constructor */
    -+    }
    -+
    -+    /**
    -+     * Computes the SHA256 digest of the signing cert for a package.
    -+     * @param packageManager The package manager.
    -+     * @param packageName The package for which to generate the digest.
    -+     * @param userId The user for which to generate the digest.
    -+     * @return The digest or null if the package does not exist for this user.
    -+     */
    -+    public static @Nullable String computePackageCertSha256Digest(
    -+            @NonNull PackageManager packageManager,
    -+            @NonNull String packageName, int userId) {
    -+        final PackageInfo packageInfo;
    -+        try {
    -+            packageInfo = packageManager.getPackageInfoAsUser(packageName,
    -+                    PackageManager.GET_SIGNATURES, userId);
    -+        } catch (PackageManager.NameNotFoundException e) {
    -+            return null;
    -+        }
    -+        return computeCertSha256Digest(packageInfo.signatures[0]);
    -+    }
    -+
    -+    /**
    -+     * Computes the SHA256 digest of a cert.
    -+     * @param signature The signature.
    -+     * @return The digest or null if an error occurs.
    -+     */
    -+    public static @Nullable String computeCertSha256Digest(@NonNull Signature signature) {
    -+        return computeSha256Digest(signature.toByteArray());
    -+    }
    -+
    -+    /**
    -+     * Computes the SHA256 digest of some data.
    -+     * @param data The data.
    -+     * @return The digest or null if an error occurs.
    -+     */
    -+    public static @Nullable String computeSha256Digest(@NonNull byte[] data) {
    -+        MessageDigest messageDigest;
    -+        try {
    -+            messageDigest = MessageDigest.getInstance("SHA256");
    -+        } catch (NoSuchAlgorithmException e) {
    -+            /* can't happen */
    -+            return null;
    -+        }
    -+
    -+        messageDigest.update(data);
    -+
    -+        final byte[] digest = messageDigest.digest();
    -+        final int digestLength = digest.length;
    -+        final int charCount = 2 * digestLength;
    -+
    -+        final char[] chars = new char[charCount];
    -+        for (int i = 0; i < digestLength; i++) {
    -+            final int byteHex = digest[i] & 0xFF;
    -+            chars[i * 2] = HEX_ARRAY[byteHex >>> 4];
    -+            chars[i * 2 + 1] = HEX_ARRAY[byteHex & 0x0F];
    -+        }
    -+        return new String(chars);
    -+    }
    -+}
    -diff --git a/core/java/android/view/DragEvent.java b/core/java/android/view/DragEvent.java
    -index b0f15b5..2baa0b4 100644
    ---- a/core/java/android/view/DragEvent.java
    -+++ b/core/java/android/view/DragEvent.java
    -@@ -134,6 +134,7 @@ public class DragEvent implements Parcelable {
    - 
    -     Object mLocalState;
    -     boolean mDragResult;
    -+    boolean mEventHandlerWasCalled;
    - 
    -     private DragEvent mNext;
    -     private RuntimeException mRecycledLocation;
    -@@ -152,12 +153,16 @@ public class DragEvent implements Parcelable {
    -      * if it can accept a drop. The onDragEvent() or onDrag() methods usually inspect the metadata
    -      * from {@link #getClipDescription()} to determine if they can accept the data contained in
    -      * this drag. For an operation that doesn't represent data transfer, these methods may
    --     * perform other actions to determine whether or not the View should accept the drag.
    -+     * perform other actions to determine whether or not the View should accept the data.
    -      * If the View wants to indicate that it is a valid drop target, it can also react by
    -      * changing its appearance.
    -      * <p>
    --     * A View only receives further drag events if it returns {@code true} in response to
    --     * ACTION_DRAG_STARTED.
    -+     *  Views added or becoming visible for the first time during a drag operation receive this
    -+     *  event when they are added or becoming visible.
    -+     * </p>
    -+     * <p>
    -+     *  A View only receives further drag events if it returns {@code true} in response to
    -+     *  ACTION_DRAG_STARTED.
    -      * </p>
    -      * @see #ACTION_DRAG_ENDED
    -      * @see #getX()
    -@@ -176,9 +181,10 @@ public class DragEvent implements Parcelable {
    -      * </p>
    -      * <p>
    -      * The system stops sending ACTION_DRAG_LOCATION events to a View once the user moves the
    --     * drag shadow out of the View object's bounding box. If the user moves the drag shadow back
    --     * into the View object's bounding box, the View receives an ACTION_DRAG_ENTERED again before
    --     * receiving any more ACTION_DRAG_LOCATION events.
    -+     * drag shadow out of the View object's bounding box or into a descendant view that can accept
    -+     * the data. If the user moves the drag shadow back into the View object's bounding box or out
    -+     * of a descendant view that can accept the data, the View receives an ACTION_DRAG_ENTERED again
    -+     * before receiving any more ACTION_DRAG_LOCATION events.
    -      * </p>
    -      * @see #ACTION_DRAG_ENTERED
    -      * @see #getX()
    -@@ -188,7 +194,8 @@ public class DragEvent implements Parcelable {
    - 
    -     /**
    -      * Action constant returned by {@link #getAction()}: Signals to a View that the user
    --     * has released the drag shadow, and the drag point is within the bounding box of the View.
    -+     * has released the drag shadow, and the drag point is within the bounding box of the View and
    -+     * not within a descendant view that can accept the data.
    -      * The View should retrieve the data from the DragEvent by calling {@link #getClipData()}.
    -      * The methods {@link #getX()} and {@link #getY()} return the X and Y position of the drop point
    -      * within the View object's bounding box.
    -@@ -211,8 +218,10 @@ public class DragEvent implements Parcelable {
    -      * operation has concluded.  A View that changed its appearance during the operation should
    -      * return to its usual drawing state in response to this event.
    -      * <p>
    --     * All views that received an ACTION_DRAG_STARTED event will receive the
    --     * ACTION_DRAG_ENDED event even if they are not currently visible when the drag ends.
    -+     *  All views with listeners that returned boolean <code>true</code> for the ACTION_DRAG_STARTED
    -+     *  event will receive the ACTION_DRAG_ENDED event even if they are not currently visible when
    -+     *  the drag ends. Views removed during the drag operation won't receive the ACTION_DRAG_ENDED
    -+     *  event.
    -      * </p>
    -      * <p>
    -      *  The View object can call {@link #getResult()} to see the result of the operation.
    -@@ -233,9 +242,10 @@ public class DragEvent implements Parcelable {
    -      *  drop target.
    -      * </p>
    -      * The system stops sending ACTION_DRAG_LOCATION events to a View once the user moves the
    --     * drag shadow out of the View object's bounding box. If the user moves the drag shadow back
    --     * into the View object's bounding box, the View receives an ACTION_DRAG_ENTERED again before
    --     * receiving any more ACTION_DRAG_LOCATION events.
    -+     * drag shadow out of the View object's bounding box or into a descendant view that can accept
    -+     * the data. If the user moves the drag shadow back into the View object's bounding box or out
    -+     * of a descendant view that can accept the data, the View receives an ACTION_DRAG_ENTERED again
    -+     * before receiving any more ACTION_DRAG_LOCATION events.
    -      * </p>
    -      * @see #ACTION_DRAG_ENTERED
    -      * @see #ACTION_DRAG_LOCATION
    -@@ -244,7 +254,8 @@ public class DragEvent implements Parcelable {
    - 
    -     /**
    -      * Action constant returned by {@link #getAction()}: Signals that the user has moved the
    --     * drag shadow outside the bounding box of the View.
    -+     * drag shadow out of the bounding box of the View or into a descendant view that can accept
    -+     * the data.
    -      * The View can react by changing its appearance in a way that tells the user that
    -      * View is no longer the immediate drop target.
    -      * <p>
    -@@ -377,6 +388,10 @@ public class DragEvent implements Parcelable {
    -      * The object is intended to provide local information about the drag and drop operation. For
    -      * example, it can indicate whether the drag and drop operation is a copy or a move.
    -      * <p>
    -+     * The local state is available only to views in the activity which has started the drag
    -+     * operation. In all other activities this method will return null
    -+     * </p>
    -+     * <p>
    -      *  This method returns valid data for all event actions except for {@link #ACTION_DRAG_ENDED}.
    -      * </p>
    -      * @return The local state object sent to the system by startDrag().
    -@@ -435,6 +450,7 @@ public class DragEvent implements Parcelable {
    -         mClipData = null;
    -         mClipDescription = null;
    -         mLocalState = null;
    -+        mEventHandlerWasCalled = false;
    - 
    -         synchronized (gRecyclerLock) {
    -             if (gRecyclerUsed < MAX_RECYCLED) {
    -diff --git a/core/java/android/view/IWindowManager.aidl b/core/java/android/view/IWindowManager.aidl
    -index 81469c8..855b1bc 100644
    ---- a/core/java/android/view/IWindowManager.aidl
    -+++ b/core/java/android/view/IWindowManager.aidl
    -@@ -73,8 +73,8 @@ interface IWindowManager
    -     void clearForcedDisplaySize(int displayId);
    -     int getInitialDisplayDensity(int displayId);
    -     int getBaseDisplayDensity(int displayId);
    --    void setForcedDisplayDensity(int displayId, int density);
    --    void clearForcedDisplayDensity(int displayId);
    -+    void setForcedDisplayDensityForUser(int displayId, int density, int userId);
    -+    void clearForcedDisplayDensityForUser(int displayId, int userId);
    -     void setForcedDisplayScalingMode(int displayId, int mode); // 0 = auto, 1 = disable
    - 
    -     void setOverscan(int displayId, int left, int top, int right, int bottom);
    -@@ -331,6 +331,16 @@ interface IWindowManager
    -     oneway void statusBarVisibilityChanged(int visibility);
    - 
    -     /**
    -+     * Called by System UI to notify of changes to the visibility of Recents.
    -+     */
    -+    oneway void setRecentsVisibility(boolean visible);
    -+
    -+    /**
    -+     * Called by System UI to notify of changes to the visibility of PIP.
    -+     */
    -+    oneway void setTvPipVisibility(boolean visible);
    -+
    -+    /**
    -      * Device has a software navigation bar (separate from the status bar).
    -      */
    -     boolean hasNavigationBar();
    -diff --git a/core/java/android/view/KeyEvent.java b/core/java/android/view/KeyEvent.java
    -index 990d553..b73acda 100644
    ---- a/core/java/android/view/KeyEvent.java
    -+++ b/core/java/android/view/KeyEvent.java
    -@@ -1289,8 +1289,9 @@ public class KeyEvent extends InputEvent implements Parcelable {
    -         boolean onKeyUp(int keyCode, KeyEvent event);
    - 
    -         /**
    --         * Called when multiple down/up pairs of the same key have occurred
    --         * in a row.
    -+         * Called when a user's interaction with an analog control, such as
    -+         * flinging a trackball, generates simulated down/up events for the same
    -+         * key multiple times in quick succession.
    -          *
    -          * @param keyCode The value in event.getKeyCode().
    -          * @param count Number of pairs as returned by event.getRepeatCount().
    -diff --git a/core/java/android/view/Surface.java b/core/java/android/view/Surface.java
    -index 286e097..22e68a3 100644
    ---- a/core/java/android/view/Surface.java
    -+++ b/core/java/android/view/Surface.java
    -@@ -33,6 +33,18 @@ import dalvik.system.CloseGuard;
    - 
    - /**
    -  * Handle onto a raw buffer that is being managed by the screen compositor.
    -+ *
    -+ * <p>A Surface is generally created by or from a consumer of image buffers (such as a
    -+ * {@link android.graphics.SurfaceTexture}, {@link android.media.MediaRecorder}, or
    -+ * {@link android.renderscript.Allocation}), and is handed to some kind of producer (such as
    -+ * {@link android.opengl.EGL14#eglCreateWindowSurface(android.opengl.EGLDisplay,android.opengl.EGLConfig,java.lang.Object,int[],int) OpenGL},
    -+ * {@link android.media.MediaPlayer#setSurface MediaPlayer}, or
    -+ * {@link android.hardware.camera2.CameraDevice#createCaptureSession CameraDevice}) to draw
    -+ * into.</p>
    -+ *
    -+ * <p><strong>Note:</strong> A Surface acts like a
    -+ * {@link java.lang.ref.WeakReference weak reference} to the consumer it is associated with. By
    -+ * itself it will not keep its parent consumer from being reclaimed.</p>
    -  */
    - public class Surface implements Parcelable {
    -     private static final String TAG = "Surface";
    -@@ -59,6 +71,7 @@ public class Surface implements Parcelable {
    -     private static native long nativeGetNextFrameNumber(long nativeObject);
    -     private static native int nativeSetScalingMode(long nativeObject, int scalingMode);
    -     private static native void nativeSetBuffersTransform(long nativeObject, long transform);
    -+    private static native int nativeForceScopedDisconnect(long nativeObject);
    - 
    -     public static final Parcelable.Creator<Surface> CREATOR =
    -             new Parcelable.Creator<Surface>() {
    -@@ -96,6 +109,8 @@ public class Surface implements Parcelable {
    - 
    -     private HwuiContext mHwuiContext;
    - 
    -+    private boolean mIsSingleBuffered;
    -+
    -     /** @hide */
    -     @Retention(RetentionPolicy.SOURCE)
    -     @IntDef({SCALING_MODE_FREEZE, SCALING_MODE_SCALE_TO_WINDOW,
    -@@ -158,7 +173,7 @@ public class Surface implements Parcelable {
    -         if (surfaceTexture == null) {
    -             throw new IllegalArgumentException("surfaceTexture must not be null");
    -         }
    --
    -+        mIsSingleBuffered = surfaceTexture.isSingleBuffered();
    -         synchronized (mLock) {
    -             mName = surfaceTexture.toString();
    -             setNativeObjectLocked(nativeCreateFromSurfaceTexture(surfaceTexture));
    -@@ -457,7 +472,10 @@ public class Surface implements Parcelable {
    -             // create a new native Surface and return it after reducing
    -             // the reference count on mNativeObject.  Either way, it is
    -             // not necessary to call nativeRelease() here.
    -+            // NOTE: This must be kept synchronized with the native parceling code
    -+            // in frameworks/native/libs/Surface.cpp
    -             mName = source.readString();
    -+            mIsSingleBuffered = source.readInt() != 0;
    -             setNativeObjectLocked(nativeReadFromParcel(mNativeObject, source));
    -         }
    -     }
    -@@ -468,7 +486,10 @@ public class Surface implements Parcelable {
    -             throw new IllegalArgumentException("dest must not be null");
    -         }
    -         synchronized (mLock) {
    -+            // NOTE: This must be kept synchronized with the native parceling code
    -+            // in frameworks/native/libs/Surface.cpp
    -             dest.writeString(mName);
    -+            dest.writeInt(mIsSingleBuffered ? 1 : 0);
    -             nativeWriteToParcel(mNativeObject, dest);
    -         }
    -         if ((flags & Parcelable.PARCELABLE_WRITE_RETURN_VALUE) != 0) {
    -@@ -530,6 +551,24 @@ public class Surface implements Parcelable {
    -         }
    -     }
    - 
    -+    void forceScopedDisconnect() {
    -+        synchronized (mLock) {
    -+            checkNotReleasedLocked();
    -+            int err = nativeForceScopedDisconnect(mNativeObject);
    -+            if (err != 0) {
    -+                throw new RuntimeException("Failed to disconnect Surface instance (bad object?)");
    -+            }
    -+        }
    -+    }
    -+
    -+    /**
    -+     * Returns whether or not this Surface is backed by a single-buffered SurfaceTexture
    -+     * @hide
    -+     */
    -+    public boolean isSingleBuffered() {
    -+        return mIsSingleBuffered;
    -+    }
    -+
    -     /**
    -      * Exception thrown when a Canvas couldn't be locked with {@link Surface#lockCanvas}, or
    -      * when a SurfaceTexture could not successfully be allocated.
    -diff --git a/core/java/android/view/SurfaceView.java b/core/java/android/view/SurfaceView.java
    -index 4818910..4b9a570 100644
    ---- a/core/java/android/view/SurfaceView.java
    -+++ b/core/java/android/view/SurfaceView.java
    -@@ -115,6 +115,7 @@ public class SurfaceView extends View {
    -     final Rect mStableInsets = new Rect();
    -     final Rect mOutsets = new Rect();
    -     final Rect mBackdropFrame = new Rect();
    -+    final Rect mTmpRect = new Rect();
    -     final Configuration mConfiguration = new Configuration();
    - 
    -     static final int KEEP_SCREEN_ON_MSG = 1;
    -@@ -193,26 +194,20 @@ public class SurfaceView extends View {
    -     private boolean mGlobalListenersAdded;
    - 
    -     public SurfaceView(Context context) {
    --        super(context);
    --        init();
    -+        this(context, null);
    -     }
    - 
    -     public SurfaceView(Context context, AttributeSet attrs) {
    --        super(context, attrs);
    --        init();
    -+        this(context, attrs, 0);
    -     }
    - 
    -     public SurfaceView(Context context, AttributeSet attrs, int defStyleAttr) {
    --        super(context, attrs, defStyleAttr);
    --        init();
    -+        this(context, attrs, defStyleAttr, 0);
    -     }
    - 
    -     public SurfaceView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
    -         super(context, attrs, defStyleAttr, defStyleRes);
    --        init();
    --    }
    - 
    --    private void init() {
    -         setWillNotDraw(true);
    -     }
    - 
    -@@ -233,6 +228,7 @@ public class SurfaceView extends View {
    -         mSession = getWindowSession();
    -         mLayout.token = getWindowToken();
    -         mLayout.setTitle("SurfaceView - " + getViewRootImpl().getTitle());
    -+        mLayout.packageName = mContext.getOpPackageName();
    -         mViewVisibility = getVisibility() == VISIBLE;
    - 
    -         if (!mGlobalListenersAdded) {
    -@@ -591,6 +587,20 @@ public class SurfaceView extends View {
    -                             for (SurfaceHolder.Callback c : callbacks) {
    -                                 c.surfaceDestroyed(mSurfaceHolder);
    -                             }
    -+                            // Since Android N the same surface may be reused and given to us
    -+                            // again by the system server at a later point. However
    -+                            // as we didn't do this in previous releases, clients weren't
    -+                            // necessarily required to clean up properly in
    -+                            // surfaceDestroyed. This leads to problems for example when
    -+                            // clients don't destroy their EGL context, and try
    -+                            // and create a new one on the same surface following reuse.
    -+                            // Since there is no valid use of the surface in-between
    -+                            // surfaceDestroyed and surfaceCreated, we force a disconnect,
    -+                            // so the next connect will always work if we end up reusing
    -+                            // the surface.
    -+                            if (mSurface.isValid()) {
    -+                                mSurface.forceScopedDisconnect();
    -+                            }
    -                         }
    -                     }
    - 
    -@@ -666,21 +676,21 @@ public class SurfaceView extends View {
    - 
    -                 transformFromViewToWindowSpace(mLocation);
    - 
    --                mWinFrame.set(mWindowSpaceLeft, mWindowSpaceTop,
    -+                mTmpRect.set(mWindowSpaceLeft, mWindowSpaceTop,
    -                         mLocation[0], mLocation[1]);
    - 
    -                 if (mTranslator != null) {
    --                    mTranslator.translateRectInAppWindowToScreen(mWinFrame);
    -+                    mTranslator.translateRectInAppWindowToScreen(mTmpRect);
    -                 }
    - 
    -                 if (!isHardwareAccelerated() || !mRtHandlingPositionUpdates) {
    -                     try {
    -                         if (DEBUG) Log.d(TAG, String.format("%d updateWindowPosition UI, " +
    -                                 "postion = [%d, %d, %d, %d]", System.identityHashCode(this),
    --                                mWinFrame.left, mWinFrame.top,
    --                                mWinFrame.right, mWinFrame.bottom));
    --                        mSession.repositionChild(mWindow, mWinFrame.left, mWinFrame.top,
    --                                mWinFrame.right, mWinFrame.bottom, -1, mWinFrame);
    -+                                mTmpRect.left, mTmpRect.top,
    -+                                mTmpRect.right, mTmpRect.bottom));
    -+                        mSession.repositionChild(mWindow, mTmpRect.left, mTmpRect.top,
    -+                                mTmpRect.right, mTmpRect.bottom, -1, mTmpRect);
    -                     } catch (RemoteException ex) {
    -                         Log.e(TAG, "Exception from relayout", ex);
    -                     }
    -@@ -692,10 +702,10 @@ public class SurfaceView extends View {
    -     private Rect mRTLastReportedPosition = new Rect();
    - 
    -     /**
    --     * Called by native on RenderThread to update the window position
    -+     * Called by native by a Rendering Worker thread to update the window position
    -      * @hide
    -      */
    --    public final void updateWindowPositionRT(long frameNumber,
    -+    public final void updateWindowPosition_renderWorker(long frameNumber,
    -             int left, int top, int right, int bottom) {
    -         IWindowSession session = mSession;
    -         MyWindow window = mWindow;
    -@@ -720,7 +730,7 @@ public class SurfaceView extends View {
    -         }
    -         try {
    -             if (DEBUG) {
    --                Log.d(TAG, String.format("%d updateWindowPosition RT, frameNr = %d, " +
    -+                Log.d(TAG, String.format("%d updateWindowPosition RenderWorker, frameNr = %d, " +
    -                         "postion = [%d, %d, %d, %d]", System.identityHashCode(this),
    -                         frameNumber, left, top, right, bottom));
    -             }
    -@@ -737,12 +747,12 @@ public class SurfaceView extends View {
    - 
    -     /**
    -      * Called by native on RenderThread to notify that the window is no longer in the
    --     * draw tree
    -+     * draw tree. UI thread is blocked at this point.
    -      * @hide
    -      */
    --    public final void windowPositionLostRT(long frameNumber) {
    -+    public final void windowPositionLost_uiRtSync(long frameNumber) {
    -         if (DEBUG) {
    --            Log.d(TAG, String.format("%d windowPositionLostRT RT, frameNr = %d",
    -+            Log.d(TAG, String.format("%d windowPositionLost, frameNr = %d",
    -                     System.identityHashCode(this), frameNumber));
    -         }
    -         IWindowSession session = mSession;
    -@@ -757,14 +767,18 @@ public class SurfaceView extends View {
    -             // safely access other member variables at this time.
    -             // So do what the UI thread would have done if RT wasn't handling position
    -             // updates.
    --            if (!mWinFrame.isEmpty() && !mWinFrame.equals(mRTLastReportedPosition)) {
    -+            mTmpRect.set(mLayout.x, mLayout.y,
    -+                    mLayout.x + mLayout.width,
    -+                    mLayout.y + mLayout.height);
    -+
    -+            if (!mTmpRect.isEmpty() && !mTmpRect.equals(mRTLastReportedPosition)) {
    -                 try {
    -                     if (DEBUG) Log.d(TAG, String.format("%d updateWindowPosition, " +
    -                             "postion = [%d, %d, %d, %d]", System.identityHashCode(this),
    --                            mWinFrame.left, mWinFrame.top,
    --                            mWinFrame.right, mWinFrame.bottom));
    --                    session.repositionChild(window, mWinFrame.left, mWinFrame.top,
    --                            mWinFrame.right, mWinFrame.bottom, frameNumber, mWinFrame);
    -+                            mTmpRect.left, mTmpRect.top,
    -+                            mTmpRect.right, mTmpRect.bottom));
    -+                    session.repositionChild(window, mTmpRect.left, mTmpRect.top,
    -+                            mTmpRect.right, mTmpRect.bottom, frameNumber, mWinFrame);
    -                 } catch (RemoteException ex) {
    -                     Log.e(TAG, "Exception from relayout", ex);
    -                 }
    -diff --git a/core/java/android/view/TextureView.java b/core/java/android/view/TextureView.java
    -index c7eca44..645ab5c 100644
    ---- a/core/java/android/view/TextureView.java
    -+++ b/core/java/android/view/TextureView.java
    -@@ -228,6 +228,7 @@ public class TextureView extends View {
    -      */
    -     @Override
    -     protected void destroyHardwareResources() {
    -+        super.destroyHardwareResources();
    -         destroyHardwareLayer();
    -     }
    - 
    -@@ -719,7 +720,7 @@ public class TextureView extends View {
    -     /**
    -      * Set the {@link SurfaceTexture} for this view to use. If a {@link
    -      * SurfaceTexture} is already being used by this view, it is immediately
    --     * released and not be usable any more.  The {@link
    -+     * released and not usable any more.  The {@link
    -      * SurfaceTextureListener#onSurfaceTextureDestroyed} callback is <b>not</b>
    -      * called for the previous {@link SurfaceTexture}.  Similarly, the {@link
    -      * SurfaceTextureListener#onSurfaceTextureAvailable} callback is <b>not</b>
    -diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
    -index c42ad2e..9722083 100644
    ---- a/core/java/android/view/View.java
    -+++ b/core/java/android/view/View.java
    -@@ -40,7 +40,6 @@ import android.content.res.Resources;
    - import android.content.res.TypedArray;
    - import android.graphics.Bitmap;
    - import android.graphics.Canvas;
    --import android.graphics.Color;
    - import android.graphics.Insets;
    - import android.graphics.Interpolator;
    - import android.graphics.LinearGradient;
    -@@ -831,6 +830,17 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
    -     protected static boolean sPreserveMarginParamsInLayoutParamConversion;
    - 
    -     /**
    -+     * Prior to N, when drag enters into child of a view that has already received an
    -+     * ACTION_DRAG_ENTERED event, the parent doesn't get a ACTION_DRAG_EXITED event.
    -+     * ACTION_DRAG_LOCATION and ACTION_DROP were delivered to the parent of a view that returned
    -+     * false from its event handler for these events.
    -+     * Starting from N, the parent will get ACTION_DRAG_EXITED event before the child gets its
    -+     * ACTION_DRAG_ENTERED. ACTION_DRAG_LOCATION and ACTION_DROP are never propagated to the parent.
    -+     * sCascadedDragDrop is true for pre-N apps for backwards compatibility implementation.
    -+     */
    -+    static boolean sCascadedDragDrop;
    -+
    -+    /**
    -      * This view does not want keystrokes. Use with TAKES_FOCUS_MASK when
    -      * calling setFlags.
    -      */
    -@@ -3086,20 +3096,6 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
    -     /**
    -      * @hide
    -      *
    --     * Whether Recents is visible or not.
    --     */
    --    public static final int RECENT_APPS_VISIBLE = 0x00004000;
    --
    --    /**
    --     * @hide
    --     *
    --     * Whether the TV's picture-in-picture is visible or not.
    --     */
    --    public static final int TV_PICTURE_IN_PICTURE_VISIBLE = 0x00010000;
    --
    --    /**
    --     * @hide
    --     *
    -      * Makes navigation bar transparent (but not the status bar).
    -      */
    -     public static final int NAVIGATION_BAR_TRANSPARENT = 0x00008000;
    -@@ -4066,6 +4062,8 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
    -             // in apps so we target check it to avoid breaking existing apps.
    -             sPreserveMarginParamsInLayoutParamConversion = targetSdkVersion >= N;
    - 
    -+            sCascadedDragDrop = targetSdkVersion < N;
    -+
    -             sCompatibilityDone = true;
    -         }
    -     }
    -@@ -8061,7 +8059,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
    -     }
    - 
    -     /**
    --     * Set the enabled state of this view.
    -+     * Set the visibility state of this view.
    -      *
    -      * @param visibility One of {@link #VISIBLE}, {@link #INVISIBLE}, or {@link #GONE}.
    -      * @attr ref android.R.styleable#View_visibility
    -@@ -20280,8 +20278,14 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
    -                 // remove it from the transparent region.
    -                 final int[] location = attachInfo.mTransparentLocation;
    -                 getLocationInWindow(location);
    --                region.op(location[0], location[1], location[0] + mRight - mLeft,
    --                        location[1] + mBottom - mTop, Region.Op.DIFFERENCE);
    -+                // When a view has Z value, then it will be better to leave some area below the view
    -+                // for drawing shadow. The shadow outset is proportional to the Z value. Note that
    -+                // the bottom part needs more offset than the left, top and right parts due to the
    -+                // spot light effects.
    -+                int shadowOffset = getZ() > 0 ? (int) getZ() : 0;
    -+                region.op(location[0] - shadowOffset, location[1] - shadowOffset,
    -+                        location[0] + mRight - mLeft + shadowOffset,
    -+                        location[1] + mBottom - mTop + (shadowOffset * 3), Region.Op.DIFFERENCE);
    -             } else {
    -                 if (mBackground != null && mBackground.getOpacity() != PixelFormat.TRANSPARENT) {
    -                     // The SKIP_DRAW flag IS set and the background drawable exists, we remove
    -@@ -20649,8 +20653,10 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
    -      * @param shadowBuilder A {@link android.view.View.DragShadowBuilder} object for building the
    -      * drag shadow.
    -      * @param myLocalState An {@link java.lang.Object} containing local data about the drag and
    --     * drop operation. This Object is put into every DragEvent object sent by the system during the
    --     * current drag.
    -+     * drop operation. When dispatching drag events to views in the same activity this object
    -+     * will be available through {@link android.view.DragEvent#getLocalState()}. Views in other
    -+     * activities will not have access to this data ({@link android.view.DragEvent#getLocalState()}
    -+     * will return null).
    -      * <p>
    -      * myLocalState is a lightweight mechanism for the sending information from the dragged View
    -      * to the target Views. For example, it can contain flags that differentiate between a
    -@@ -20851,6 +20857,11 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
    -         return false;
    -     }
    - 
    -+    // Dispatches ACTION_DRAG_ENTERED and ACTION_DRAG_EXITED events for pre-Nougat apps.
    -+    boolean dispatchDragEnterExitInPreN(DragEvent event) {
    -+        return callDragEventHandler(event);
    -+    }
    -+
    -     /**
    -      * Detects if this View is enabled and has a drag event listener.
    -      * If both are true, then it calls the drag event listener with the
    -@@ -20868,13 +20879,44 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
    -      * </p>
    -      */
    -     public boolean dispatchDragEvent(DragEvent event) {
    -+        event.mEventHandlerWasCalled = true;
    -+        if (event.mAction == DragEvent.ACTION_DRAG_LOCATION ||
    -+            event.mAction == DragEvent.ACTION_DROP) {
    -+            // About to deliver an event with coordinates to this view. Notify that now this view
    -+            // has drag focus. This will send exit/enter events as needed.
    -+            getViewRootImpl().setDragFocus(this, event);
    -+        }
    -+        return callDragEventHandler(event);
    -+    }
    -+
    -+    final boolean callDragEventHandler(DragEvent event) {
    -+        final boolean result;
    -+
    -         ListenerInfo li = mListenerInfo;
    -         //noinspection SimplifiableIfStatement
    -         if (li != null && li.mOnDragListener != null && (mViewFlags & ENABLED_MASK) == ENABLED
    -                 && li.mOnDragListener.onDrag(this, event)) {
    --            return true;
    -+            result = true;
    -+        } else {
    -+            result = onDragEvent(event);
    -         }
    --        return onDragEvent(event);
    -+
    -+        switch (event.mAction) {
    -+            case DragEvent.ACTION_DRAG_ENTERED: {
    -+                mPrivateFlags2 |= View.PFLAG2_DRAG_HOVERED;
    -+                refreshDrawableState();
    -+            } break;
    -+            case DragEvent.ACTION_DRAG_EXITED: {
    -+                mPrivateFlags2 &= ~View.PFLAG2_DRAG_HOVERED;
    -+                refreshDrawableState();
    -+            } break;
    -+            case DragEvent.ACTION_DRAG_ENDED: {
    -+                mPrivateFlags2 &= ~View.DRAG_MASK;
    -+                refreshDrawableState();
    -+            } break;
    -+        }
    -+
    -+        return result;
    -     }
    - 
    -     boolean canAcceptDrag() {
    -diff --git a/core/java/android/view/ViewGroup.java b/core/java/android/view/ViewGroup.java
    -index 3ff8d4f..d4b7d3b 100644
    ---- a/core/java/android/view/ViewGroup.java
    -+++ b/core/java/android/view/ViewGroup.java
    -@@ -153,8 +153,9 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager
    -      */
    -     Transformation mInvalidationTransformation;
    - 
    --    // View currently under an ongoing drag. Can be null, a child or this window.
    --    private View mCurrentDragView;
    -+    // Current frontmost child that can accept drag and lies under the drag location.
    -+    // Used only to generate ENTER/EXIT events for pre-Nougat aps.
    -+    private View mCurrentDragChild;
    - 
    -     // Metadata about the ongoing drag
    -     private DragEvent mCurrentDragStartEvent;
    -@@ -1355,6 +1356,20 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager
    -         return mLocalPoint;
    -     }
    - 
    -+    @Override
    -+    boolean dispatchDragEnterExitInPreN(DragEvent event) {
    -+        if (event.mAction == DragEvent.ACTION_DRAG_EXITED && mCurrentDragChild != null) {
    -+            // The drag exited a sub-tree of views; notify of the exit all descendants that are in
    -+            // entered state.
    -+            // We don't need this recursive delivery for ENTERED events because they get generated
    -+            // from the recursive delivery of LOCATION/DROP events, and hence, don't need their own
    -+            // recursion.
    -+            mCurrentDragChild.dispatchDragEnterExitInPreN(event);
    -+            mCurrentDragChild = null;
    -+        }
    -+        return mIsInterestedInDrag && super.dispatchDragEnterExitInPreN(event);
    -+    }
    -+
    -     // TODO: Write real docs
    -     @Override
    -     public boolean dispatchDragEvent(DragEvent event) {
    -@@ -1362,15 +1377,13 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager
    -         final float tx = event.mX;
    -         final float ty = event.mY;
    - 
    --        ViewRootImpl root = getViewRootImpl();
    --
    -         // Dispatch down the view hierarchy
    -         final PointF localPoint = getLocalPoint();
    - 
    -         switch (event.mAction) {
    -         case DragEvent.ACTION_DRAG_STARTED: {
    --            // clear state to recalculate which views we drag over
    --            mCurrentDragView = null;
    -+            // Clear the state to recalculate which views we drag over.
    -+            mCurrentDragChild = null;
    - 
    -             // Set up our tracking of drag-started notifications
    -             mCurrentDragStartEvent = DragEvent.obtain(event);
    -@@ -1416,8 +1429,6 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager
    -                     if (child.dispatchDragEvent(event)) {
    -                         retval = true;
    -                     }
    --                    child.mPrivateFlags2 &= ~View.DRAG_MASK;
    --                    child.refreshDrawableState();
    -                 }
    -                 childrenInterestedInDrag.clear();
    -             }
    -@@ -1434,60 +1445,45 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager
    -             }
    -         } break;
    - 
    --        case DragEvent.ACTION_DRAG_LOCATION: {
    -+        case DragEvent.ACTION_DRAG_LOCATION:
    -+        case DragEvent.ACTION_DROP: {
    -             // Find the [possibly new] drag target
    -             View target = findFrontmostDroppableChildAt(event.mX, event.mY, localPoint);
    --            if (target == null && mIsInterestedInDrag) {
    --                target = this;
    --            }
    - 
    --            // If we've changed apparent drag target, tell the view root which view
    --            // we're over now [for purposes of the eventual drag-recipient-changed
    --            // notifications to the framework] and tell the new target that the drag
    --            // has entered its bounds.  The root will see setDragFocus() calls all
    --            // the way down to the final leaf view that is handling the LOCATION event
    --            // before reporting the new potential recipient to the framework.
    --            if (mCurrentDragView != target) {
    --                root.setDragFocus(target);
    --
    --                final int action = event.mAction;
    --                // Position should not be available for ACTION_DRAG_ENTERED and ACTION_DRAG_EXITED.
    --                event.mX = 0;
    --                event.mY = 0;
    --
    --                // If we've dragged off of a child view or this window, send it the EXITED message
    --                if (mCurrentDragView != null) {
    --                    final View view = mCurrentDragView;
    --                    event.mAction = DragEvent.ACTION_DRAG_EXITED;
    --                    if (view != this) {
    --                        view.dispatchDragEvent(event);
    --                        view.mPrivateFlags2 &= ~View.PFLAG2_DRAG_HOVERED;
    --                        view.refreshDrawableState();
    --                    } else {
    --                        super.dispatchDragEvent(event);
    -+            if (target != mCurrentDragChild) {
    -+                if (sCascadedDragDrop) {
    -+                    // For pre-Nougat apps, make sure that the whole hierarchy of views that contain
    -+                    // the drag location is kept in the state between ENTERED and EXITED events.
    -+                    // (Starting with N, only the innermost view will be in that state).
    -+
    -+                    final int action = event.mAction;
    -+                    // Position should not be available for ACTION_DRAG_ENTERED and
    -+                    // ACTION_DRAG_EXITED.
    -+                    event.mX = 0;
    -+                    event.mY = 0;
    -+
    -+                    if (mCurrentDragChild != null) {
    -+                        event.mAction = DragEvent.ACTION_DRAG_EXITED;
    -+                        mCurrentDragChild.dispatchDragEnterExitInPreN(event);
    -                     }
    --                }
    - 
    --                mCurrentDragView = target;
    --
    --                // If we've dragged over a new child view, send it the ENTERED message, otherwise
    --                // send it to this window.
    --                if (target != null) {
    --                    event.mAction = DragEvent.ACTION_DRAG_ENTERED;
    --                    if (target != this) {
    --                        target.dispatchDragEvent(event);
    --                        target.mPrivateFlags2 |= View.PFLAG2_DRAG_HOVERED;
    --                        target.refreshDrawableState();
    --                    } else {
    --                        super.dispatchDragEvent(event);
    -+                    if (target != null) {
    -+                        event.mAction = DragEvent.ACTION_DRAG_ENTERED;
    -+                        target.dispatchDragEnterExitInPreN(event);
    -                     }
    -+
    -+                    event.mAction = action;
    -+                    event.mX = tx;
    -+                    event.mY = ty;
    -                 }
    --                event.mAction = action;  // restore the event's original state
    --                event.mX = tx;
    --                event.mY = ty;
    -+                mCurrentDragChild = target;
    -             }
    - 
    --            // Dispatch the actual drag location notice, localized into its coordinates
    -+            if (target == null && mIsInterestedInDrag) {
    -+                target = this;
    -+            }
    -+
    -+            // Dispatch the actual drag notice, localized into the target coordinates.
    -             if (target != null) {
    -                 if (target != this) {
    -                     event.mX = localPoint.x;
    -@@ -1497,55 +1493,21 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager
    - 
    -                     event.mX = tx;
    -                     event.mY = ty;
    --                } else {
    --                    retval = super.dispatchDragEvent(event);
    --                }
    --            }
    --        } break;
    - 
    --        /* Entered / exited dispatch
    --         *
    --         * DRAG_ENTERED is not dispatched downwards from ViewGroup.  The reason for this is
    --         * that we're about to get the corresponding LOCATION event, which we will use to
    --         * determine which of our children is the new target; at that point we will
    --         * push a DRAG_ENTERED down to the new target child [which may itself be a ViewGroup].
    --         * If no suitable child is detected, dispatch to this window.
    --         *
    --         * DRAG_EXITED *is* dispatched all the way down immediately: once we know the
    --         * drag has left this ViewGroup, we know by definition that every contained subview
    --         * is also no longer under the drag point.
    --         */
    -+                    if (mIsInterestedInDrag) {
    -+                        final boolean eventWasConsumed;
    -+                        if (sCascadedDragDrop) {
    -+                            eventWasConsumed = retval;
    -+                        } else {
    -+                            eventWasConsumed = event.mEventHandlerWasCalled;
    -+                        }
    - 
    --        case DragEvent.ACTION_DRAG_EXITED: {
    --            if (mCurrentDragView != null) {
    --                final View view = mCurrentDragView;
    --                if (view != this) {
    --                    view.dispatchDragEvent(event);
    --                    view.mPrivateFlags2 &= ~View.PFLAG2_DRAG_HOVERED;
    --                    view.refreshDrawableState();
    -+                        if (!eventWasConsumed) {
    -+                            retval = super.dispatchDragEvent(event);
    -+                        }
    -+                    }
    -                 } else {
    --                    super.dispatchDragEvent(event);
    --                }
    --
    --                mCurrentDragView = null;
    --            }
    --        } break;
    --
    --        case DragEvent.ACTION_DROP: {
    --            if (ViewDebug.DEBUG_DRAG) Log.d(View.VIEW_LOG_TAG, "Drop event: " + event);
    --            View target = findFrontmostDroppableChildAt(event.mX, event.mY, localPoint);
    --            if (target != null) {
    --                if (ViewDebug.DEBUG_DRAG) Log.d(View.VIEW_LOG_TAG, "   dispatch drop to " + target);
    --                event.mX = localPoint.x;
    --                event.mY = localPoint.y;
    --                retval = target.dispatchDragEvent(event);
    --                event.mX = tx;
    --                event.mY = ty;
    --            } else if (mIsInterestedInDrag) {
    --                retval = super.dispatchDragEvent(event);
    --            } else {
    --                if (ViewDebug.DEBUG_DRAG) {
    --                    Log.d(View.VIEW_LOG_TAG, "   not dropped on an accepting view");
    -+                    retval = super.dispatchDragEvent(event);
    -                 }
    -             }
    -         } break;
    -@@ -1592,6 +1554,7 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager
    -         final boolean canAccept = child.dispatchDragEvent(mCurrentDragStartEvent);
    -         mCurrentDragStartEvent.mX = tx;
    -         mCurrentDragStartEvent.mY = ty;
    -+        mCurrentDragStartEvent.mEventHandlerWasCalled = false;
    -         if (canAccept) {
    -             mChildrenInterestedInDrag.add(child);
    -             if (!child.canAcceptDrag()) {
    -@@ -6406,16 +6369,28 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager
    -             return true;
    -         }
    -         super.gatherTransparentRegion(region);
    --        final View[] children = mChildren;
    --        final int count = mChildrenCount;
    -+        // Instead of naively traversing the view tree, we have to traverse according to the Z
    -+        // order here. We need to go with the same order as dispatchDraw().
    -+        // One example is that after surfaceView punch a hole, we will still allow other views drawn
    -+        // on top of that hole. In this case, those other views should be able to cut the
    -+        // transparent region into smaller area.
    -+        final int childrenCount = mChildrenCount;
    -         boolean noneOfTheChildrenAreTransparent = true;
    --        for (int i = 0; i < count; i++) {
    --            final View child = children[i];
    --            if ((child.mViewFlags & VISIBILITY_MASK) == VISIBLE || child.getAnimation() != null) {
    --                if (!child.gatherTransparentRegion(region)) {
    --                    noneOfTheChildrenAreTransparent = false;
    -+        if (childrenCount > 0) {
    -+            final ArrayList<View> preorderedList = buildOrderedChildList();
    -+            final boolean customOrder = preorderedList == null
    -+                    && isChildrenDrawingOrderEnabled();
    -+            final View[] children = mChildren;
    -+            for (int i = 0; i < childrenCount; i++) {
    -+                final int childIndex = getAndVerifyPreorderedIndex(childrenCount, i, customOrder);
    -+                final View child = getAndVerifyPreorderedView(preorderedList, children, childIndex);
    -+                if ((child.mViewFlags & VISIBILITY_MASK) == VISIBLE || child.getAnimation() != null) {
    -+                    if (!child.gatherTransparentRegion(region)) {
    -+                        noneOfTheChildrenAreTransparent = false;
    -+                    }
    -                 }
    -             }
    -+            if (preorderedList != null) preorderedList.clear();
    -         }
    -         return meOpaque || noneOfTheChildrenAreTransparent;
    -     }
    -diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
    -index 1bb4c08..e95fa5e 100644
    ---- a/core/java/android/view/ViewRootImpl.java
    -+++ b/core/java/android/view/ViewRootImpl.java
    -@@ -2167,7 +2167,12 @@ public final class ViewRootImpl implements ViewParent,
    -         }
    - 
    -         if (changedVisibility || regainedFocus) {
    --            host.sendAccessibilityEvent(AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED);
    -+            // Toasts are presented as notifications - don't present them as windows as well
    -+            boolean isToast = (mWindowAttributes == null) ? false
    -+                    : (mWindowAttributes.type == WindowManager.LayoutParams.TYPE_TOAST);
    -+            if (!isToast) {
    -+                host.sendAccessibilityEvent(AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED);
    -+            }
    -         }
    - 
    -         mFirst = false;
    -@@ -5518,9 +5523,11 @@ public final class ViewRootImpl implements ViewParent,
    -             if (what == DragEvent.ACTION_DRAG_EXITED) {
    -                 // A direct EXITED event means that the window manager knows we've just crossed
    -                 // a window boundary, so the current drag target within this one must have
    --                // just been exited.  Send it the usual notifications and then we're done
    --                // for now.
    --                mView.dispatchDragEvent(event);
    -+                // just been exited. Send the EXITED notification to the current drag view, if any.
    -+                if (View.sCascadedDragDrop) {
    -+                    mView.dispatchDragEnterExitInPreN(event);
    -+                }
    -+                setDragFocus(null, event);
    -             } else {
    -                 // For events with a [screen] location, translate into window coordinates
    -                 if ((what == DragEvent.ACTION_DRAG_LOCATION) || (what == DragEvent.ACTION_DROP)) {
    -@@ -5543,6 +5550,12 @@ public final class ViewRootImpl implements ViewParent,
    -                 // Now dispatch the drag/drop event
    -                 boolean result = mView.dispatchDragEvent(event);
    - 
    -+                if (what == DragEvent.ACTION_DRAG_LOCATION && !event.mEventHandlerWasCalled) {
    -+                    // If the LOCATION event wasn't delivered to any handler, no view now has a drag
    -+                    // focus.
    -+                    setDragFocus(null, event);
    -+                }
    -+
    -                 // If we changed apparent drag target, tell the OS about it
    -                 if (prevDragView != mCurrentDragView) {
    -                     try {
    -@@ -5570,6 +5583,7 @@ public final class ViewRootImpl implements ViewParent,
    - 
    -                 // When the drag operation ends, reset drag-related state
    -                 if (what == DragEvent.ACTION_DRAG_ENDED) {
    -+                    mCurrentDragView = null;
    -                     setLocalDragState(null);
    -                     mAttachInfo.mDragToken = null;
    -                     if (mAttachInfo.mDragSurface != null) {
    -@@ -5629,10 +5643,33 @@ public final class ViewRootImpl implements ViewParent,
    -         return mLastTouchSource;
    -     }
    - 
    --    public void setDragFocus(View newDragTarget) {
    --        if (mCurrentDragView != newDragTarget) {
    --            mCurrentDragView = newDragTarget;
    -+    public void setDragFocus(View newDragTarget, DragEvent event) {
    -+        if (mCurrentDragView != newDragTarget && !View.sCascadedDragDrop) {
    -+            // Send EXITED and ENTERED notifications to the old and new drag focus views.
    -+
    -+            final float tx = event.mX;
    -+            final float ty = event.mY;
    -+            final int action = event.mAction;
    -+            // Position should not be available for ACTION_DRAG_ENTERED and ACTION_DRAG_EXITED.
    -+            event.mX = 0;
    -+            event.mY = 0;
    -+
    -+            if (mCurrentDragView != null) {
    -+                event.mAction = DragEvent.ACTION_DRAG_EXITED;
    -+                mCurrentDragView.callDragEventHandler(event);
    -+            }
    -+
    -+            if (newDragTarget != null) {
    -+                event.mAction = DragEvent.ACTION_DRAG_ENTERED;
    -+                newDragTarget.callDragEventHandler(event);
    -+            }
    -+
    -+            event.mAction = action;
    -+            event.mX = tx;
    -+            event.mY = ty;
    -         }
    -+
    -+        mCurrentDragView = newDragTarget;
    -     }
    - 
    -     private AudioManager getAudioManager() {
    -diff --git a/core/java/android/view/WindowManager.java b/core/java/android/view/WindowManager.java
    -index 0dbf00d..395f738 100644
    ---- a/core/java/android/view/WindowManager.java
    -+++ b/core/java/android/view/WindowManager.java
    -@@ -1752,14 +1752,18 @@ public interface WindowManager extends ViewManager {
    -         public CharSequence accessibilityTitle;
    - 
    -         /**
    --         * Sets a timeout in milliseconds before which the window will be removed
    -+         * Sets a timeout in milliseconds before which the window will be hidden
    -          * by the window manager. Useful for transient notifications like toasts
    -          * so we don't have to rely on client cooperation to ensure the window
    --         * is removed. Must be specified at window creation time.
    -+         * is hidden. Must be specified at window creation time. Note that apps
    -+         * are not prepared to handle their windows being removed without their
    -+         * explicit request and may try to interact with the removed window
    -+         * resulting in undefined behavior and crashes. Therefore, we do hide
    -+         * such windows to prevent them from overlaying other apps.
    -          *
    -          * @hide
    -          */
    --        public long removeTimeoutMilliseconds = -1;
    -+        public long hideTimeoutMilliseconds = -1;
    - 
    -         public LayoutParams() {
    -             super(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);
    -@@ -1895,7 +1899,7 @@ public interface WindowManager extends ViewManager {
    -             out.writeInt(needsMenuKey);
    -             out.writeInt(accessibilityIdOfAnchor);
    -             TextUtils.writeToParcel(accessibilityTitle, out, parcelableFlags);
    --            out.writeLong(removeTimeoutMilliseconds);
    -+            out.writeLong(hideTimeoutMilliseconds);
    -         }
    - 
    -         public static final Parcelable.Creator<LayoutParams> CREATOR
    -@@ -1949,7 +1953,7 @@ public interface WindowManager extends ViewManager {
    -             needsMenuKey = in.readInt();
    -             accessibilityIdOfAnchor = in.readInt();
    -             accessibilityTitle = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(in);
    --            removeTimeoutMilliseconds = in.readLong();
    -+            hideTimeoutMilliseconds = in.readLong();
    -         }
    - 
    -         @SuppressWarnings({"PointlessBitwiseExpression"})
    -@@ -2171,7 +2175,7 @@ public interface WindowManager extends ViewManager {
    -             }
    - 
    -             // This can't change, it's only set at window creation time.
    --            removeTimeoutMilliseconds = o.removeTimeoutMilliseconds;
    -+            hideTimeoutMilliseconds = o.hideTimeoutMilliseconds;
    - 
    -             return changes;
    -         }
    -diff --git a/core/java/android/view/WindowManagerPolicy.java b/core/java/android/view/WindowManagerPolicy.java
    -index b52e4b0..46a0194 100644
    ---- a/core/java/android/view/WindowManagerPolicy.java
    -+++ b/core/java/android/view/WindowManagerPolicy.java
    -@@ -507,6 +507,11 @@ public interface WindowManagerPolicy {
    -          * Retrieves the {@param outBounds} from the stack with id {@param stackId}.
    -          */
    -         void getStackBounds(int stackId, Rect outBounds);
    -+
    -+        /**
    -+         * Overrides all currently playing app animations with {@param a}.
    -+         */
    -+        void overridePlayingAppAnimationsLw(Animation a);
    -     }
    - 
    -     public interface PointerEventListener {
    -@@ -1301,6 +1306,16 @@ public interface WindowManagerPolicy {
    -     public int adjustSystemUiVisibilityLw(int visibility);
    - 
    -     /**
    -+     * Called by System UI to notify of changes to the visibility of Recents.
    -+     */
    -+    public void setRecentsVisibilityLw(boolean visible);
    -+
    -+    /**
    -+     * Called by System UI to notify of changes to the visibility of PIP.
    -+     */
    -+    public void setTvPipVisibilityLw(boolean visible);
    -+
    -+    /**
    -      * Specifies whether there is an on-screen navigation bar separate from the status bar.
    -      */
    -     public boolean hasNavigationBar();
    -diff --git a/core/java/android/view/inputmethod/InputConnection.java b/core/java/android/view/inputmethod/InputConnection.java
    -index 07910b6..71c1d62 100644
    ---- a/core/java/android/view/inputmethod/InputConnection.java
    -+++ b/core/java/android/view/inputmethod/InputConnection.java
    -@@ -43,12 +43,14 @@ import android.view.KeyEvent;
    -  *     in {@link android.os.Build.VERSION_CODES#HONEYCOMB}.</li>
    -  *     <li>{@link #requestCursorUpdates(int)}, which was introduced in
    -  *     {@link android.os.Build.VERSION_CODES#LOLLIPOP}.</li>
    -- *     <li>{@link #deleteSurroundingTextInCodePoints(int, int)}}, which
    -+ *     <li>{@link #deleteSurroundingTextInCodePoints(int, int)}, which
    -  *     was introduced in {@link android.os.Build.VERSION_CODES#N}.</li>
    -- *     <li>{@link #getHandler()}}, which was introduced in
    -+ *     <li>{@link #getHandler()}, which was introduced in
    -  *     {@link android.os.Build.VERSION_CODES#N}.</li>
    -- *     <li>{@link #closeConnection()}}, which was introduced in
    -+ *     <li>{@link #closeConnection()}, which was introduced in
    -  *     {@link android.os.Build.VERSION_CODES#N}.</li>
    -+ *     <li>{@link #commitContent(InputContentInfo, int, Bundle)}, which was
    -+ *     introduced in {@link android.os.Build.VERSION_CODES#N_MR1}.</li>
    -  * </ul>
    -  *
    -  * <h3>Implementing an IME or an editor</h3>
    -@@ -858,32 +860,35 @@ public interface InputConnection {
    -             android.content.Intent.FLAG_GRANT_READ_URI_PERMISSION;  // 0x00000001
    - 
    -     /**
    --     * Called by the input method to commit a content such as PNG image to the editor.
    -+     * Called by the input method to commit content such as a PNG image to the editor.
    -      *
    --     * <p>In order to avoid variety of compatibility issues, this focuses on a simple use case,
    --     * where we expect editors and IMEs work cooperatively as follows:</p>
    -+     * <p>In order to avoid a variety of compatibility issues, this focuses on a simple use case,
    -+     * where editors and IMEs are expected to work cooperatively as follows:</p>
    -      * <ul>
    --     *     <li>Editor must keep {@link EditorInfo#contentMimeTypes} to be {@code null} if it does
    -+     *     <li>Editor must keep {@link EditorInfo#contentMimeTypes} equal to {@code null} if it does
    -      *     not support this method at all.</li>
    -      *     <li>Editor can ignore this request when the MIME type specified in
    --     *     {@code inputContentInfo} does not match to any of {@link EditorInfo#contentMimeTypes}.
    -+     *     {@code inputContentInfo} does not match any of {@link EditorInfo#contentMimeTypes}.
    -      *     </li>
    --     *     <li>Editor can ignore the cursor position when inserting the provided context.</li>
    -+     *     <li>Editor can ignore the cursor position when inserting the provided content.</li>
    -      *     <li>Editor can return {@code true} asynchronously, even before it starts loading the
    -      *     content.</li>
    --     *     <li>Editor should provide a way to delete the content inserted by this method, or revert
    --     *     the effect caused by this method.</li>
    -+     *     <li>Editor should provide a way to delete the content inserted by this method or to
    -+     *     revert the effect caused by this method.</li>
    -      *     <li>IME should not call this method when there is any composing text, in case calling
    --     *     this method causes focus change.</li>
    -+     *     this method causes a focus change.</li>
    -      *     <li>IME should grant a permission for the editor to read the content. See
    -      *     {@link EditorInfo#packageName} about how to obtain the package name of the editor.</li>
    -      * </ul>
    -      *
    -      * @param inputContentInfo Content to be inserted.
    --     * @param flags {@code 0} or {@link #INPUT_CONTENT_GRANT_READ_URI_PERMISSION}.
    -+     * @param flags {@link #INPUT_CONTENT_GRANT_READ_URI_PERMISSION} if the content provider
    -+     * allows {@link android.R.styleable#AndroidManifestProvider_grantUriPermissions
    -+     * grantUriPermissions} or {@code 0} if the application does not need to call
    -+     * {@link InputContentInfo#requestPermission()}.
    -      * @param opts optional bundle data. This can be {@code null}.
    --     * @return {@code true} if this request is accepted by the application, no matter if the request
    --     * is already handled or still being handled in background.
    -+     * @return {@code true} if this request is accepted by the application, whether the request
    -+     * is already handled or still being handled in background, {@code false} otherwise.
    -      */
    -     public boolean commitContent(@NonNull InputContentInfo inputContentInfo, int flags,
    -             @Nullable Bundle opts);
    -diff --git a/core/java/android/view/inputmethod/InputMethodManager.java b/core/java/android/view/inputmethod/InputMethodManager.java
    -index c0c8e64..2e9cbf2 100644
    ---- a/core/java/android/view/inputmethod/InputMethodManager.java
    -+++ b/core/java/android/view/inputmethod/InputMethodManager.java
    -@@ -2056,12 +2056,10 @@ public final class InputMethodManager {
    -      * have any input method subtype.
    -      */
    -     public InputMethodSubtype getCurrentInputMethodSubtype() {
    --        synchronized (mH) {
    --            try {
    --                return mService.getCurrentInputMethodSubtype();
    --            } catch (RemoteException e) {
    --                throw e.rethrowFromSystemServer();
    --            }
    -+        try {
    -+            return mService.getCurrentInputMethodSubtype();
    -+        } catch (RemoteException e) {
    -+            throw e.rethrowFromSystemServer();
    -         }
    -     }
    - 
    -diff --git a/core/java/android/widget/DatePicker.java b/core/java/android/widget/DatePicker.java
    -index 8613f99..54818a1 100644
    ---- a/core/java/android/widget/DatePicker.java
    -+++ b/core/java/android/widget/DatePicker.java
    -@@ -18,7 +18,9 @@ package android.widget;
    - 
    - import com.android.internal.R;
    - 
    -+import android.annotation.IntDef;
    - import android.annotation.Nullable;
    -+import android.annotation.TestApi;
    - import android.annotation.Widget;
    - import android.content.Context;
    - import android.content.res.Configuration;
    -@@ -32,6 +34,8 @@ import android.util.SparseArray;
    - import android.view.View;
    - import android.view.accessibility.AccessibilityEvent;
    - 
    -+import java.lang.annotation.Retention;
    -+import java.lang.annotation.RetentionPolicy;
    - import java.util.Locale;
    - 
    - /**
    -@@ -75,11 +79,36 @@ import java.util.Locale;
    -  */
    - @Widget
    - public class DatePicker extends FrameLayout {
    --    private static final int MODE_SPINNER = 1;
    --    private static final int MODE_CALENDAR = 2;
    -+    /**
    -+     * Presentation mode for the Holo-style date picker that uses a set of
    -+     * {@link android.widget.NumberPicker}s.
    -+     *
    -+     * @see #getMode()
    -+     * @hide Visible for testing only.
    -+     */
    -+    @TestApi
    -+    public static final int MODE_SPINNER = 1;
    -+
    -+    /**
    -+     * Presentation mode for the Material-style date picker that uses a
    -+     * calendar.
    -+     *
    -+     * @see #getMode()
    -+     * @hide Visible for testing only.
    -+     */
    -+    @TestApi
    -+    public static final int MODE_CALENDAR = 2;
    -+
    -+    /** @hide */
    -+    @IntDef({MODE_SPINNER, MODE_CALENDAR})
    -+    @Retention(RetentionPolicy.SOURCE)
    -+    public @interface DatePickerMode {}
    - 
    -     private final DatePickerDelegate mDelegate;
    - 
    -+    @DatePickerMode
    -+    private final int mMode;
    -+
    -     /**
    -      * The callback used to indicate the user changed the date.
    -      */
    -@@ -114,11 +143,20 @@ public class DatePicker extends FrameLayout {
    - 
    -         final TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.DatePicker,
    -                 defStyleAttr, defStyleRes);
    --        final int mode = a.getInt(R.styleable.DatePicker_datePickerMode, MODE_SPINNER);
    -+        final boolean isDialogMode = a.getBoolean(R.styleable.DatePicker_dialogMode, false);
    -+        final int requestedMode = a.getInt(R.styleable.DatePicker_datePickerMode, MODE_SPINNER);
    -         final int firstDayOfWeek = a.getInt(R.styleable.DatePicker_firstDayOfWeek, 0);
    -         a.recycle();
    - 
    --        switch (mode) {
    -+        if (requestedMode == MODE_CALENDAR && isDialogMode) {
    -+            // You want MODE_CALENDAR? YOU CAN'T HANDLE MODE_CALENDAR! Well,
    -+            // maybe you can depending on your screen size. Let's check...
    -+            mMode = context.getResources().getInteger(R.integer.date_picker_mode);
    -+        } else {
    -+            mMode = requestedMode;
    -+        }
    -+
    -+        switch (mMode) {
    -             case MODE_CALENDAR:
    -                 mDelegate = createCalendarUIDelegate(context, attrs, defStyleAttr, defStyleRes);
    -                 break;
    -@@ -145,6 +183,18 @@ public class DatePicker extends FrameLayout {
    -     }
    - 
    -     /**
    -+     * @return the picker's presentation mode, one of {@link #MODE_CALENDAR} or
    -+     *         {@link #MODE_SPINNER}
    -+     * @attr ref android.R.styleable#DatePicker_datePickerMode
    -+     * @hide Visible for testing only.
    -+     */
    -+    @DatePickerMode
    -+    @TestApi
    -+    public int getMode() {
    -+        return mMode;
    -+    }
    -+
    -+    /**
    -      * Initialize the state. If the provided values designate an inconsistent
    -      * date the values are normalized before updating the spinners.
    -      *
    -diff --git a/core/java/android/widget/ImageView.java b/core/java/android/widget/ImageView.java
    -index aa67c82..4d405c5 100644
    ---- a/core/java/android/widget/ImageView.java
    -+++ b/core/java/android/widget/ImageView.java
    -@@ -467,6 +467,14 @@ public class ImageView extends View {
    -      * {@link #setImageBitmap(android.graphics.Bitmap)} and
    -      * {@link android.graphics.BitmapFactory} instead.</p>
    -      *
    -+     * <p class="note">On devices running SDK < 24, this method will fail to
    -+     * apply correct density scaling to images loaded from
    -+     * {@link ContentResolver#SCHEME_CONTENT content} and
    -+     * {@link ContentResolver#SCHEME_FILE file} schemes. Applications running
    -+     * on devices with SDK >= 24 <strong>MUST</strong> specify the
    -+     * {@code targetSdkVersion} in their manifest as 24 or above for density
    -+     * scaling to be applied to images loaded from these schemes.</p>
    -+     *
    -      * @param uri the Uri of an image, or {@code null} to clear the content
    -      */
    -     @android.view.RemotableViewMethod(asyncImpl="setImageURIAsync")
    -@@ -1441,7 +1449,9 @@ public class ImageView extends View {
    -     /**
    -      * Returns the alpha that will be applied to the drawable of this ImageView.
    -      *
    --     * @return the alpha that will be applied to the drawable of this ImageView
    -+     * @return the alpha value that will be applied to the drawable of this
    -+     * ImageView (between 0 and 255 inclusive, with 0 being transparent and
    -+     * 255 being opaque)
    -      *
    -      * @see #setImageAlpha(int)
    -      */
    -@@ -1452,7 +1462,8 @@ public class ImageView extends View {
    -     /**
    -      * Sets the alpha value that should be applied to the image.
    -      *
    --     * @param alpha the alpha value that should be applied to the image
    -+     * @param alpha the alpha value that should be applied to the image (between
    -+     * 0 and 255 inclusive, with 0 being transparent and 255 being opaque)
    -      *
    -      * @see #getImageAlpha()
    -      */
    -diff --git a/core/java/android/widget/NumberPicker.java b/core/java/android/widget/NumberPicker.java
    -index c3ddec7..25580fd 100644
    ---- a/core/java/android/widget/NumberPicker.java
    -+++ b/core/java/android/widget/NumberPicker.java
    -@@ -16,6 +16,8 @@
    - 
    - package android.widget;
    - 
    -+import com.android.internal.R;
    -+
    - import android.annotation.CallSuper;
    - import android.annotation.IntDef;
    - import android.annotation.Widget;
    -@@ -29,10 +31,12 @@ import android.graphics.Paint.Align;
    - import android.graphics.Rect;
    - import android.graphics.drawable.Drawable;
    - import android.os.Bundle;
    -+import android.text.Editable;
    - import android.text.InputFilter;
    - import android.text.InputType;
    - import android.text.Spanned;
    - import android.text.TextUtils;
    -+import android.text.TextWatcher;
    - import android.text.method.NumberKeyListener;
    - import android.util.AttributeSet;
    - import android.util.SparseArray;
    -@@ -52,9 +56,6 @@ import android.view.animation.DecelerateInterpolator;
    - import android.view.inputmethod.EditorInfo;
    - import android.view.inputmethod.InputMethodManager;
    - 
    --import com.android.internal.R;
    --import libcore.icu.LocaleData;
    --
    - import java.lang.annotation.Retention;
    - import java.lang.annotation.RetentionPolicy;
    - import java.util.ArrayList;
    -@@ -62,6 +63,8 @@ import java.util.Collections;
    - import java.util.List;
    - import java.util.Locale;
    - 
    -+import libcore.icu.LocaleData;
    -+
    - /**
    -  * A widget that enables the user to select a number from a predefined range.
    -  * There are two flavors of this widget and which one is presented to the user
    -@@ -1991,7 +1994,7 @@ public class NumberPicker extends LinearLayout {
    -             removeCallbacks(mChangeCurrentByOneFromLongPressCommand);
    -         }
    -         if (mSetSelectionCommand != null) {
    --            removeCallbacks(mSetSelectionCommand);
    -+            mSetSelectionCommand.cancel();
    -         }
    -         if (mBeginSoftInputOnLongPressCommand != null) {
    -             removeCallbacks(mBeginSoftInputOnLongPressCommand);
    -@@ -2033,18 +2036,14 @@ public class NumberPicker extends LinearLayout {
    -     }
    - 
    -     /**
    --     * Posts an {@link SetSelectionCommand} from the given <code>selectionStart
    --     * </code> to <code>selectionEnd</code>.
    -+     * Posts a {@link SetSelectionCommand} from the given
    -+     * {@code selectionStart} to {@code selectionEnd}.
    -      */
    -     private void postSetSelectionCommand(int selectionStart, int selectionEnd) {
    -         if (mSetSelectionCommand == null) {
    --            mSetSelectionCommand = new SetSelectionCommand();
    --        } else {
    --            removeCallbacks(mSetSelectionCommand);
    -+            mSetSelectionCommand = new SetSelectionCommand(mInputText);
    -         }
    --        mSetSelectionCommand.mSelectionStart = selectionStart;
    --        mSetSelectionCommand.mSelectionEnd = selectionEnd;
    --        post(mSetSelectionCommand);
    -+        mSetSelectionCommand.post(selectionStart, selectionEnd);
    -     }
    - 
    -     /**
    -@@ -2090,6 +2089,12 @@ public class NumberPicker extends LinearLayout {
    -         @Override
    -         public CharSequence filter(
    -                 CharSequence source, int start, int end, Spanned dest, int dstart, int dend) {
    -+            // We don't know what the output will be, so always cancel any
    -+            // pending set selection command.
    -+            if (mSetSelectionCommand != null) {
    -+                mSetSelectionCommand.cancel();
    -+            }
    -+
    -             if (mDisplayedValues == null) {
    -                 CharSequence filtered = super.filter(source, start, end, dest, dstart, dend);
    -                 if (filtered == null) {
    -@@ -2237,12 +2242,39 @@ public class NumberPicker extends LinearLayout {
    -     /**
    -      * Command for setting the input text selection.
    -      */
    --    class SetSelectionCommand implements Runnable {
    --        private int mSelectionStart;
    -+    private static class SetSelectionCommand implements Runnable {
    -+        private final EditText mInputText;
    - 
    -+        private int mSelectionStart;
    -         private int mSelectionEnd;
    - 
    -+        /** Whether this runnable is currently posted. */
    -+        private boolean mPosted;
    -+
    -+        public SetSelectionCommand(EditText inputText) {
    -+            mInputText = inputText;
    -+        }
    -+
    -+        public void post(int selectionStart, int selectionEnd) {
    -+            mSelectionStart = selectionStart;
    -+            mSelectionEnd = selectionEnd;
    -+
    -+            if (!mPosted) {
    -+                mInputText.post(this);
    -+                mPosted = true;
    -+            }
    -+        }
    -+
    -+        public void cancel() {
    -+            if (mPosted) {
    -+                mInputText.removeCallbacks(this);
    -+                mPosted = false;
    -+            }
    -+        }
    -+
    -+        @Override
    -         public void run() {
    -+            mPosted = false;
    -             mInputText.setSelection(mSelectionStart, mSelectionEnd);
    -         }
    -     }
    -diff --git a/core/java/android/widget/PopupWindow.java b/core/java/android/widget/PopupWindow.java
    -index 6432f70..9b89491 100644
    ---- a/core/java/android/widget/PopupWindow.java
    -+++ b/core/java/android/widget/PopupWindow.java
    -@@ -193,6 +193,8 @@ public class PopupWindow {
    - 
    -     private int mAnimationStyle = ANIMATION_STYLE_DEFAULT;
    - 
    -+    private int mGravity = Gravity.NO_GRAVITY;
    -+
    -     private static final int[] ABOVE_ANCHOR_STATE_SET = new int[] {
    -         com.android.internal.R.attr.state_above_anchor
    -     };
    -@@ -1141,15 +1143,11 @@ public class PopupWindow {
    - 
    -         mIsShowing = true;
    -         mIsDropdown = false;
    -+        mGravity = gravity;
    - 
    -         final WindowManager.LayoutParams p = createPopupLayoutParams(token);
    -         preparePopup(p);
    - 
    --        // Only override the default if some gravity was specified.
    --        if (gravity != Gravity.NO_GRAVITY) {
    --            p.gravity = gravity;
    --        }
    --
    -         p.x = x;
    -         p.y = y;
    - 
    -@@ -1394,8 +1392,8 @@ public class PopupWindow {
    -     }
    - 
    -     private int computeGravity() {
    --        int gravity = Gravity.START | Gravity.TOP;
    --        if (mClipToScreen || mClippingEnabled) {
    -+        int gravity = mGravity == Gravity.NO_GRAVITY ?  Gravity.START | Gravity.TOP : mGravity;
    -+        if (mIsDropdown && (mClipToScreen || mClippingEnabled)) {
    -             gravity |= Gravity.DISPLAY_CLIP_VERTICAL;
    -         }
    -         return gravity;
    -@@ -1547,7 +1545,7 @@ public class PopupWindow {
    -         }
    - 
    -         // Let the window manager know to align the top to y.
    --        outParams.gravity = Gravity.LEFT | Gravity.TOP;
    -+        outParams.gravity = computeGravity();
    -         outParams.width = width;
    -         outParams.height = height;
    - 
    -@@ -1760,11 +1758,22 @@ public class PopupWindow {
    -      */
    -     public int getMaxAvailableHeight(
    -             @NonNull View anchor, int yOffset, boolean ignoreBottomDecorations) {
    --        final Rect displayFrame = new Rect();
    -+        Rect displayFrame = null;
    -+        final Rect visibleDisplayFrame = new Rect();
    -+
    -+        anchor.getWindowVisibleDisplayFrame(visibleDisplayFrame);
    -         if (ignoreBottomDecorations) {
    -+            // In the ignore bottom decorations case we want to
    -+            // still respect all other decorations so we use the inset visible
    -+            // frame on the top right and left and take the bottom
    -+            // value from the full frame.
    -+            displayFrame = new Rect();
    -             anchor.getWindowDisplayFrame(displayFrame);
    -+            displayFrame.top = visibleDisplayFrame.top;
    -+            displayFrame.right = visibleDisplayFrame.right;
    -+            displayFrame.left = visibleDisplayFrame.left;
    -         } else {
    --            anchor.getWindowVisibleDisplayFrame(displayFrame);
    -+            displayFrame = visibleDisplayFrame;
    -         }
    - 
    -         final int[] anchorPos = mTmpDrawingLocation;
    -diff --git a/core/java/android/widget/ProgressBar.java b/core/java/android/widget/ProgressBar.java
    -index 3c967ac..1f379c9 100644
    ---- a/core/java/android/widget/ProgressBar.java
    -+++ b/core/java/android/widget/ProgressBar.java
    -@@ -22,6 +22,7 @@ import android.annotation.NonNull;
    - import android.annotation.Nullable;
    - import android.content.Context;
    - import android.content.res.ColorStateList;
    -+import android.content.res.Resources;
    - import android.content.res.TypedArray;
    - import android.graphics.Bitmap;
    - import android.graphics.Canvas;
    -@@ -230,7 +231,7 @@ public class ProgressBar extends View {
    -     private Drawable mCurrentDrawable;
    -     private ProgressTintInfo mProgressTintInfo;
    - 
    --    Bitmap mSampleTile;
    -+    int mSampleWidth = 0;
    -     private boolean mNoInvalidate;
    -     private Interpolator mInterpolator;
    -     private RefreshProgressRunnable mRefreshProgressRunnable;
    -@@ -505,15 +506,14 @@ public class ProgressBar extends View {
    -         }
    - 
    -         if (drawable instanceof BitmapDrawable) {
    --            final BitmapDrawable bitmap = (BitmapDrawable) drawable;
    --            final Bitmap tileBitmap = bitmap.getBitmap();
    --            if (mSampleTile == null) {
    --                mSampleTile = tileBitmap;
    --            }
    --
    --            final BitmapDrawable clone = (BitmapDrawable) bitmap.getConstantState().newDrawable();
    -+            final Drawable.ConstantState cs = drawable.getConstantState();
    -+            final BitmapDrawable clone = (BitmapDrawable) cs.newDrawable(getResources());
    -             clone.setTileModeXY(Shader.TileMode.REPEAT, Shader.TileMode.CLAMP);
    - 
    -+            if (mSampleWidth <= 0) {
    -+                mSampleWidth = clone.getIntrinsicWidth();
    -+            }
    -+
    -             if (clip) {
    -                 return new ClipDrawable(clone, Gravity.LEFT, ClipDrawable.HORIZONTAL);
    -             } else {
    -diff --git a/core/java/android/widget/RatingBar.java b/core/java/android/widget/RatingBar.java
    -index 3ad05b5..62dd90f 100644
    ---- a/core/java/android/widget/RatingBar.java
    -+++ b/core/java/android/widget/RatingBar.java
    -@@ -281,10 +281,8 @@ public class RatingBar extends AbsSeekBar {
    -     protected synchronized void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
    -         super.onMeasure(widthMeasureSpec, heightMeasureSpec);
    - 
    --        if (mSampleTile != null) {
    --            // TODO: Once ProgressBar's TODOs are gone, this can be done more
    --            // cleanly than mSampleTile
    --            final int width = mSampleTile.getWidth() * mNumStars;
    -+        if (mSampleWidth > 0) {
    -+            final int width = mSampleWidth * mNumStars;
    -             setMeasuredDimension(resolveSizeAndState(width, widthMeasureSpec, 0),
    -                     getMeasuredHeight());
    -         }
    -diff --git a/core/java/android/widget/SearchView.java b/core/java/android/widget/SearchView.java
    -index 5878cad..9139361 100644
    ---- a/core/java/android/widget/SearchView.java
    -+++ b/core/java/android/widget/SearchView.java
    -@@ -816,9 +816,11 @@ public class SearchView extends LinearLayout implements CollapsibleActionView {
    - 
    -         switch (heightMode) {
    -             case MeasureSpec.AT_MOST:
    --            case MeasureSpec.UNSPECIFIED:
    -                 height = Math.min(getPreferredHeight(), height);
    -                 break;
    -+            case MeasureSpec.UNSPECIFIED:
    -+                height = getPreferredHeight();
    -+                break;
    -         }
    -         heightMode = MeasureSpec.EXACTLY;
    - 
    -diff --git a/core/java/android/widget/Switch.java b/core/java/android/widget/Switch.java
    -index c4a1771..a01d65a 100644
    ---- a/core/java/android/widget/Switch.java
    -+++ b/core/java/android/widget/Switch.java
    -@@ -65,6 +65,9 @@ import com.android.internal.R;
    -  * {@link #setSwitchTextAppearance(android.content.Context, int) switchTextAppearance} and
    -  * the related setSwitchTypeface() methods control that of the thumb.
    -  *
    -+ * <p>{@link android.support.v7.widget.SwitchCompat} is a version of
    -+ * the Switch widget which runs on devices back to API 7.</p>
    -+ *
    -  * <p>See the <a href="{@docRoot}guide/topics/ui/controls/togglebutton.html">Toggle Buttons</a>
    -  * guide.</p>
    -  *
    -diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
    -index d3cb742..f8daa88 100644
    ---- a/core/java/android/widget/TextView.java
    -+++ b/core/java/android/widget/TextView.java
    -@@ -3234,6 +3234,10 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
    -      * Sets the text color for all the states (normal, selected,
    -      * focused) to be this color.
    -      *
    -+     * @param color A color value in the form 0xAARRGGBB.
    -+     * Do not pass a resource ID. To get a color value from a resource ID, call
    -+     * {@link android.support.v4.content.ContextCompat#getColor(Context, int) getColor}.
    -+     *
    -      * @see #setTextColor(ColorStateList)
    -      * @see #getTextColors()
    -      *
    -diff --git a/core/java/android/widget/TimePicker.java b/core/java/android/widget/TimePicker.java
    -index f2fc617..a1c854b 100644
    ---- a/core/java/android/widget/TimePicker.java
    -+++ b/core/java/android/widget/TimePicker.java
    -@@ -16,20 +16,24 @@
    - 
    - package android.widget;
    - 
    -+import com.android.internal.R;
    -+
    -+import android.annotation.IntDef;
    -+import android.annotation.IntRange;
    - import android.annotation.NonNull;
    --import android.annotation.Nullable;
    -+import android.annotation.TestApi;
    - import android.annotation.Widget;
    - import android.content.Context;
    --import android.content.res.Configuration;
    - import android.content.res.TypedArray;
    - import android.os.Parcel;
    - import android.os.Parcelable;
    --import android.os.Parcelable.Creator;
    - import android.util.AttributeSet;
    -+import android.util.MathUtils;
    - import android.view.View;
    - import android.view.accessibility.AccessibilityEvent;
    --import com.android.internal.R;
    - 
    -+import java.lang.annotation.Retention;
    -+import java.lang.annotation.RetentionPolicy;
    - import java.util.Locale;
    - 
    - import libcore.icu.LocaleData;
    -@@ -45,11 +49,36 @@ import libcore.icu.LocaleData;
    -  */
    - @Widget
    - public class TimePicker extends FrameLayout {
    --    private static final int MODE_SPINNER = 1;
    --    private static final int MODE_CLOCK = 2;
    -+    /**
    -+     * Presentation mode for the Holo-style time picker that uses a set of
    -+     * {@link android.widget.NumberPicker}s.
    -+     *
    -+     * @see #getMode()
    -+     * @hide Visible for testing only.
    -+     */
    -+    @TestApi
    -+    public static final int MODE_SPINNER = 1;
    -+
    -+    /**
    -+     * Presentation mode for the Material-style time picker that uses a clock
    -+     * face.
    -+     *
    -+     * @see #getMode()
    -+     * @hide Visible for testing only.
    -+     */
    -+    @TestApi
    -+    public static final int MODE_CLOCK = 2;
    -+
    -+    /** @hide */
    -+    @IntDef({MODE_SPINNER, MODE_CLOCK})
    -+    @Retention(RetentionPolicy.SOURCE)
    -+    public @interface TimePickerMode {}
    - 
    -     private final TimePickerDelegate mDelegate;
    - 
    -+    @TimePickerMode
    -+    private final int mMode;
    -+
    -     /**
    -      * The callback interface used to indicate the time has been adjusted.
    -      */
    -@@ -80,10 +109,19 @@ public class TimePicker extends FrameLayout {
    - 
    -         final TypedArray a = context.obtainStyledAttributes(
    -                 attrs, R.styleable.TimePicker, defStyleAttr, defStyleRes);
    --        final int mode = a.getInt(R.styleable.TimePicker_timePickerMode, MODE_SPINNER);
    -+        final boolean isDialogMode = a.getBoolean(R.styleable.TimePicker_dialogMode, false);
    -+        final int requestedMode = a.getInt(R.styleable.TimePicker_timePickerMode, MODE_SPINNER);
    -         a.recycle();
    - 
    --        switch (mode) {
    -+        if (requestedMode == MODE_CLOCK && isDialogMode) {
    -+            // You want MODE_CLOCK? YOU CAN'T HANDLE MODE_CLOCK! Well, maybe
    -+            // you can depending on your screen size. Let's check...
    -+            mMode = context.getResources().getInteger(R.integer.time_picker_mode);
    -+        } else {
    -+            mMode = requestedMode;
    -+        }
    -+
    -+        switch (mMode) {
    -             case MODE_CLOCK:
    -                 mDelegate = new TimePickerClockDelegate(
    -                         this, context, attrs, defStyleAttr, defStyleRes);
    -@@ -97,13 +135,25 @@ public class TimePicker extends FrameLayout {
    -     }
    - 
    -     /**
    -+     * @return the picker's presentation mode, one of {@link #MODE_CLOCK} or
    -+     *         {@link #MODE_SPINNER}
    -+     * @attr ref android.R.styleable#TimePicker_timePickerMode
    -+     * @hide Visible for testing only.
    -+     */
    -+    @TimePickerMode
    -+    @TestApi
    -+    public int getMode() {
    -+        return mMode;
    -+    }
    -+
    -+    /**
    -      * Sets the currently selected hour using 24-hour time.
    -      *
    -      * @param hour the hour to set, in the range (0-23)
    -      * @see #getHour()
    -      */
    --    public void setHour(int hour) {
    --        mDelegate.setHour(hour);
    -+    public void setHour(@IntRange(from = 0, to = 23) int hour) {
    -+        mDelegate.setHour(MathUtils.constrain(hour, 0, 23));
    -     }
    - 
    -     /**
    -@@ -117,13 +167,13 @@ public class TimePicker extends FrameLayout {
    -     }
    - 
    -     /**
    --     * Sets the currently selected minute..
    -+     * Sets the currently selected minute.
    -      *
    -      * @param minute the minute to set, in the range (0-59)
    -      * @see #getMinute()
    -      */
    --    public void setMinute(int minute) {
    --        mDelegate.setMinute(minute);
    -+    public void setMinute(@IntRange(from = 0, to = 59) int minute) {
    -+        mDelegate.setMinute(MathUtils.constrain(minute, 0, 59));
    -     }
    - 
    -     /**
    -@@ -137,8 +187,9 @@ public class TimePicker extends FrameLayout {
    -     }
    - 
    -     /**
    --     * Sets the current hour.
    -+     * Sets the currently selected hour using 24-hour time.
    -      *
    -+     * @param currentHour the hour to set, in the range (0-23)
    -      * @deprecated Use {@link #setHour(int)}
    -      */
    -     @Deprecated
    -@@ -147,33 +198,34 @@ public class TimePicker extends FrameLayout {
    -     }
    - 
    -     /**
    --     * @return the current hour in the range (0-23)
    -+     * @return the currently selected hour, in the range (0-23)
    -      * @deprecated Use {@link #getHour()}
    -      */
    -     @NonNull
    -     @Deprecated
    -     public Integer getCurrentHour() {
    --        return mDelegate.getHour();
    -+        return getHour();
    -     }
    - 
    -     /**
    --     * Set the current minute (0-59).
    -+     * Sets the currently selected minute.
    -      *
    -+     * @param currentMinute the minute to set, in the range (0-59)
    -      * @deprecated Use {@link #setMinute(int)}
    -      */
    -     @Deprecated
    -     public void setCurrentMinute(@NonNull Integer currentMinute) {
    --        mDelegate.setMinute(currentMinute);
    -+        setMinute(currentMinute);
    -     }
    - 
    -     /**
    --     * @return the current minute
    -+     * @return the currently selected minute, in the range (0-59)
    -      * @deprecated Use {@link #getMinute()}
    -      */
    -     @NonNull
    -     @Deprecated
    -     public Integer getCurrentMinute() {
    --        return mDelegate.getMinute();
    -+        return getMinute();
    -     }
    - 
    -     /**
    -@@ -256,10 +308,10 @@ public class TimePicker extends FrameLayout {
    -      * for the real behavior.
    -      */
    -     interface TimePickerDelegate {
    --        void setHour(int hour);
    -+        void setHour(@IntRange(from = 0, to = 23) int hour);
    -         int getHour();
    - 
    --        void setMinute(int minute);
    -+        void setMinute(@IntRange(from = 0, to = 59) int minute);
    -         int getMinute();
    - 
    -         void setIs24Hour(boolean is24Hour);
    -diff --git a/core/java/android/widget/Toast.java b/core/java/android/widget/Toast.java
    -index 7762675..a400d90 100644
    ---- a/core/java/android/widget/Toast.java
    -+++ b/core/java/android/widget/Toast.java
    -@@ -25,6 +25,8 @@ import android.content.res.Configuration;
    - import android.content.res.Resources;
    - import android.graphics.PixelFormat;
    - import android.os.Handler;
    -+import android.os.IBinder;
    -+import android.os.Message;
    - import android.os.RemoteException;
    - import android.os.ServiceManager;
    - import android.util.Log;
    -@@ -326,13 +328,6 @@ public class Toast {
    -     }
    - 
    -     private static class TN extends ITransientNotification.Stub {
    --        final Runnable mShow = new Runnable() {
    --            @Override
    --            public void run() {
    --                handleShow();
    --            }
    --        };
    --
    -         final Runnable mHide = new Runnable() {
    -             @Override
    -             public void run() {
    -@@ -343,7 +338,13 @@ public class Toast {
    -         };
    - 
    -         private final WindowManager.LayoutParams mParams = new WindowManager.LayoutParams();
    --        final Handler mHandler = new Handler();
    -+        final Handler mHandler = new Handler() {
    -+            @Override
    -+            public void handleMessage(Message msg) {
    -+                IBinder token = (IBinder) msg.obj;
    -+                handleShow(token);
    -+            }
    -+        };
    - 
    -         int mGravity;
    -         int mX, mY;
    -@@ -379,9 +380,9 @@ public class Toast {
    -          * schedule handleShow into the right thread
    -          */
    -         @Override
    --        public void show() {
    -+        public void show(IBinder windowToken) {
    -             if (localLOGV) Log.v(TAG, "SHOW: " + this);
    --            mHandler.post(mShow);
    -+            mHandler.obtainMessage(0, windowToken).sendToTarget();
    -         }
    - 
    -         /**
    -@@ -393,7 +394,7 @@ public class Toast {
    -             mHandler.post(mHide);
    -         }
    - 
    --        public void handleShow() {
    -+        public void handleShow(IBinder windowToken) {
    -             if (localLOGV) Log.v(TAG, "HANDLE SHOW: " + this + " mView=" + mView
    -                     + " mNextView=" + mNextView);
    -             if (mView != mNextView) {
    -@@ -422,8 +423,9 @@ public class Toast {
    -                 mParams.verticalMargin = mVerticalMargin;
    -                 mParams.horizontalMargin = mHorizontalMargin;
    -                 mParams.packageName = packageName;
    --                mParams.removeTimeoutMilliseconds = mDuration ==
    -+                mParams.hideTimeoutMilliseconds = mDuration ==
    -                     Toast.LENGTH_LONG ? LONG_DURATION_TIMEOUT : SHORT_DURATION_TIMEOUT;
    -+                mParams.token = windowToken;
    -                 if (mView.getParent() != null) {
    -                     if (localLOGV) Log.v(TAG, "REMOVE! " + mView + " in " + this);
    -                     mWM.removeView(mView);
    -@@ -458,7 +460,7 @@ public class Toast {
    -                 // the view isn't yet added, so let's try not to crash.
    -                 if (mView.getParent() != null) {
    -                     if (localLOGV) Log.v(TAG, "REMOVE! " + mView + " in " + this);
    --                    mWM.removeView(mView);
    -+                    mWM.removeViewImmediate(mView);
    -                 }
    - 
    -                 mView = null;
    -diff --git a/core/java/android/widget/VideoView.java b/core/java/android/widget/VideoView.java
    -index f084db2..b973324 100644
    ---- a/core/java/android/widget/VideoView.java
    -+++ b/core/java/android/widget/VideoView.java
    -@@ -70,46 +70,49 @@ import java.util.Vector;
    -  */
    - public class VideoView extends SurfaceView
    -         implements MediaPlayerControl, SubtitleController.Anchor {
    --    private String TAG = "VideoView";
    --    // settable by the client
    --    private Uri         mUri;
    --    private Map<String, String> mHeaders;
    -+    private static final String TAG = "VideoView";
    - 
    -     // all possible internal states
    --    private static final int STATE_ERROR              = -1;
    --    private static final int STATE_IDLE               = 0;
    --    private static final int STATE_PREPARING          = 1;
    --    private static final int STATE_PREPARED           = 2;
    --    private static final int STATE_PLAYING            = 3;
    --    private static final int STATE_PAUSED             = 4;
    -+    private static final int STATE_ERROR = -1;
    -+    private static final int STATE_IDLE = 0;
    -+    private static final int STATE_PREPARING = 1;
    -+    private static final int STATE_PREPARED = 2;
    -+    private static final int STATE_PLAYING = 3;
    -+    private static final int STATE_PAUSED = 4;
    -     private static final int STATE_PLAYBACK_COMPLETED = 5;
    - 
    -+    private final Vector<Pair<InputStream, MediaFormat>> mPendingSubtitleTracks = new Vector<>();
    -+
    -+    // settable by the client
    -+    private Uri mUri;
    -+    private Map<String, String> mHeaders;
    -+
    -     // mCurrentState is a VideoView object's current state.
    -     // mTargetState is the state that a method caller intends to reach.
    -     // For instance, regardless the VideoView object's current state,
    -     // calling pause() intends to bring the object to a target state
    -     // of STATE_PAUSED.
    -     private int mCurrentState = STATE_IDLE;
    --    private int mTargetState  = STATE_IDLE;
    -+    private int mTargetState = STATE_IDLE;
    - 
    -     // All the stuff we need for playing and showing a video
    -     private SurfaceHolder mSurfaceHolder = null;
    -     private MediaPlayer mMediaPlayer = null;
    --    private int         mAudioSession;
    --    private int         mVideoWidth;
    --    private int         mVideoHeight;
    --    private int         mSurfaceWidth;
    --    private int         mSurfaceHeight;
    -+    private int mAudioSession;
    -+    private int mVideoWidth;
    -+    private int mVideoHeight;
    -+    private int mSurfaceWidth;
    -+    private int mSurfaceHeight;
    -     private MediaController mMediaController;
    -     private OnCompletionListener mOnCompletionListener;
    -     private MediaPlayer.OnPreparedListener mOnPreparedListener;
    --    private int         mCurrentBufferPercentage;
    -+    private int mCurrentBufferPercentage;
    -     private OnErrorListener mOnErrorListener;
    --    private OnInfoListener  mOnInfoListener;
    --    private int         mSeekWhenPrepared;  // recording the seek position while preparing
    --    private boolean     mCanPause;
    --    private boolean     mCanSeekBack;
    --    private boolean     mCanSeekForward;
    -+    private OnInfoListener mOnInfoListener;
    -+    private int mSeekWhenPrepared;  // recording the seek position while preparing
    -+    private boolean mCanPause;
    -+    private boolean mCanSeekBack;
    -+    private boolean mCanSeekForward;
    - 
    -     /** Subtitle rendering widget overlaid on top of the video. */
    -     private RenderingWidget mSubtitleWidget;
    -@@ -118,13 +121,11 @@ public class VideoView extends SurfaceView
    -     private RenderingWidget.OnChangedListener mSubtitlesChangedListener;
    - 
    -     public VideoView(Context context) {
    --        super(context);
    --        initVideoView();
    -+        this(context, null);
    -     }
    - 
    -     public VideoView(Context context, AttributeSet attrs) {
    -         this(context, attrs, 0);
    --        initVideoView();
    -     }
    - 
    -     public VideoView(Context context, AttributeSet attrs, int defStyleAttr) {
    -@@ -133,7 +134,19 @@ public class VideoView extends SurfaceView
    - 
    -     public VideoView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
    -         super(context, attrs, defStyleAttr, defStyleRes);
    --        initVideoView();
    -+
    -+        mVideoWidth = 0;
    -+        mVideoHeight = 0;
    -+
    -+        getHolder().addCallback(mSHCallback);
    -+        getHolder().setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
    -+
    -+        setFocusable(true);
    -+        setFocusableInTouchMode(true);
    -+        requestFocus();
    -+
    -+        mCurrentState = STATE_IDLE;
    -+        mTargetState = STATE_IDLE;
    -     }
    - 
    -     @Override
    -@@ -209,19 +222,6 @@ public class VideoView extends SurfaceView
    -         return getDefaultSize(desiredSize, measureSpec);
    -     }
    - 
    --    private void initVideoView() {
    --        mVideoWidth = 0;
    --        mVideoHeight = 0;
    --        getHolder().addCallback(mSHCallback);
    --        getHolder().setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
    --        setFocusable(true);
    --        setFocusableInTouchMode(true);
    --        requestFocus();
    --        mPendingSubtitleTracks = new Vector<Pair<InputStream, MediaFormat>>();
    --        mCurrentState = STATE_IDLE;
    --        mTargetState  = STATE_IDLE;
    --    }
    --
    -     /**
    -      * Sets video path.
    -      *
    -@@ -294,8 +294,6 @@ public class VideoView extends SurfaceView
    -         }
    -     }
    - 
    --    private Vector<Pair<InputStream, MediaFormat>> mPendingSubtitleTracks;
    --
    -     public void stopPlayback() {
    -         if (mMediaPlayer != null) {
    -             mMediaPlayer.stop();
    -diff --git a/core/java/com/android/internal/app/ResolverActivity.java b/core/java/com/android/internal/app/ResolverActivity.java
    -index 0a4ac0d..1e26c92 100644
    ---- a/core/java/com/android/internal/app/ResolverActivity.java
    -+++ b/core/java/com/android/internal/app/ResolverActivity.java
    -@@ -1469,7 +1469,7 @@ public class ResolverActivity extends Activity {
    -                 boolean found = false;
    -                 // Only loop to the end of into as it was before we started; no dupes in from.
    -                 for (int j = 0; j < intoCount; j++) {
    --                    final ResolvedComponentInfo rci = into.get(i);
    -+                    final ResolvedComponentInfo rci = into.get(j);
    -                     if (isSameResolvedComponent(newInfo, rci)) {
    -                         found = true;
    -                         rci.add(intent, newInfo);
    -diff --git a/core/java/com/android/internal/app/ResolverComparator.java b/core/java/com/android/internal/app/ResolverComparator.java
    -index 03a3a38..4d4c7ce 100644
    ---- a/core/java/com/android/internal/app/ResolverComparator.java
    -+++ b/core/java/com/android/internal/app/ResolverComparator.java
    -@@ -157,7 +157,10 @@ class ResolverComparator implements Comparator<ResolvedComponentInfo> {
    - 
    -         // We want to put the one targeted to another user at the end of the dialog.
    -         if (lhs.targetUserId != UserHandle.USER_CURRENT) {
    --            return 1;
    -+            return rhs.targetUserId != UserHandle.USER_CURRENT ? 0 : 1;
    -+        }
    -+        if (rhs.targetUserId != UserHandle.USER_CURRENT) {
    -+            return -1;
    -         }
    - 
    -         if (mHttp) {
    -diff --git a/core/java/com/android/internal/app/SuggestedLocaleAdapter.java b/core/java/com/android/internal/app/SuggestedLocaleAdapter.java
    -index a4b5a8e..cb2b019 100644
    ---- a/core/java/com/android/internal/app/SuggestedLocaleAdapter.java
    -+++ b/core/java/com/android/internal/app/SuggestedLocaleAdapter.java
    -@@ -145,7 +145,11 @@ public class SuggestedLocaleAdapter extends BaseAdapter implements Filterable {
    -                 if (itemType == TYPE_HEADER_SUGGESTED) {
    -                     textView.setText(R.string.language_picker_section_suggested);
    -                 } else {
    --                    textView.setText(R.string.language_picker_section_all);
    -+                    if (mCountryMode) {
    -+                        textView.setText(R.string.region_picker_section_all);
    -+                    } else {
    -+                        textView.setText(R.string.language_picker_section_all);
    -+                    }
    -                 }
    -                 textView.setTextLocale(Locale.getDefault());
    -                 break;
    -diff --git a/core/java/com/android/internal/graphics/drawable/AnimationScaleListDrawable.java b/core/java/com/android/internal/graphics/drawable/AnimationScaleListDrawable.java
    -new file mode 100644
    -index 0000000..62f18ea
    ---- /dev/null
    -+++ b/core/java/com/android/internal/graphics/drawable/AnimationScaleListDrawable.java
    -@@ -0,0 +1,254 @@
    -+/*
    -+ * Copyright (C) 2016 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 com.android.internal.graphics.drawable;
    -+
    -+import android.animation.ValueAnimator;
    -+import android.annotation.NonNull;
    -+import android.annotation.Nullable;
    -+import android.content.res.Resources;
    -+import android.content.res.Resources.Theme;
    -+import android.content.res.TypedArray;
    -+import android.graphics.drawable.Animatable;
    -+import android.graphics.drawable.Drawable;
    -+import android.graphics.drawable.DrawableContainer;
    -+import android.util.AttributeSet;
    -+
    -+import com.android.internal.R;
    -+
    -+import org.xmlpull.v1.XmlPullParser;
    -+import org.xmlpull.v1.XmlPullParserException;
    -+
    -+import java.io.IOException;
    -+
    -+/**
    -+ * An internal DrawableContainer class, used to draw different things depending on animation scale.
    -+ * i.e: animation scale can be 0 in battery saver mode.
    -+ * This class contains 2 drawable, one is animatable, the other is static. When animation scale is
    -+ * not 0, the animatable drawable will the drawn. Otherwise, the static drawable will be drawn.
    -+ * <p>This class implements Animatable since ProgressBar can pick this up similarly as an
    -+ * AnimatedVectorDrawable.
    -+ * <p>It can be defined in an XML file with the {@code <AnimationScaleListDrawable>}
    -+ * element.
    -+ */
    -+public class AnimationScaleListDrawable extends DrawableContainer implements Animatable {
    -+    private static final String TAG = "AnimationScaleListDrawable";
    -+    private AnimationScaleListState mAnimationScaleListState;
    -+    private boolean mMutated;
    -+
    -+    public AnimationScaleListDrawable() {
    -+        this(null, null);
    -+    }
    -+
    -+    private AnimationScaleListDrawable(@Nullable AnimationScaleListState state,
    -+            @Nullable Resources res) {
    -+        // Every scale list drawable has its own constant state.
    -+        final AnimationScaleListState newState = new AnimationScaleListState(state, this, res);
    -+        setConstantState(newState);
    -+        onStateChange(getState());
    -+    }
    -+
    -+    /**
    -+     * Set the current drawable according to the animation scale. If scale is 0, then pick the
    -+     * static drawable, otherwise, pick the animatable drawable.
    -+     */
    -+    @Override
    -+    protected boolean onStateChange(int[] stateSet) {
    -+        final boolean changed = super.onStateChange(stateSet);
    -+        int idx = mAnimationScaleListState.getCurrentDrawableIndexBasedOnScale();
    -+        return selectDrawable(idx) || changed;
    -+    }
    -+
    -+
    -+    @Override
    -+    public void inflate(@NonNull Resources r, @NonNull XmlPullParser parser,
    -+            @NonNull AttributeSet attrs, @Nullable Theme theme)
    -+            throws XmlPullParserException, IOException {
    -+        final TypedArray a = obtainAttributes(r, theme, attrs,
    -+                R.styleable.AnimationScaleListDrawable);
    -+        updateDensity(r);
    -+        a.recycle();
    -+
    -+        inflateChildElements(r, parser, attrs, theme);
    -+
    -+        onStateChange(getState());
    -+    }
    -+
    -+    /**
    -+     * Inflates child elements from XML.
    -+     */
    -+    private void inflateChildElements(@NonNull Resources r, @NonNull XmlPullParser parser,
    -+            @NonNull AttributeSet attrs, @Nullable Theme theme)
    -+            throws XmlPullParserException, IOException {
    -+        final AnimationScaleListState state = mAnimationScaleListState;
    -+        final int innerDepth = parser.getDepth() + 1;
    -+        int type;
    -+        int depth;
    -+        while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
    -+                && ((depth = parser.getDepth()) >= innerDepth
    -+                || type != XmlPullParser.END_TAG)) {
    -+            if (type != XmlPullParser.START_TAG) {
    -+                continue;
    -+            }
    -+
    -+            if (depth > innerDepth || !parser.getName().equals("item")) {
    -+                continue;
    -+            }
    -+
    -+            // Either pick up the android:drawable attribute.
    -+            final TypedArray a = obtainAttributes(r, theme, attrs,
    -+                    R.styleable.AnimationScaleListDrawableItem);
    -+            Drawable dr = a.getDrawable(R.styleable.AnimationScaleListDrawableItem_drawable);
    -+            a.recycle();
    -+
    -+            // Or parse the child element under <item>.
    -+            if (dr == null) {
    -+                while ((type = parser.next()) == XmlPullParser.TEXT) {
    -+                }
    -+                if (type != XmlPullParser.START_TAG) {
    -+                    throw new XmlPullParserException(
    -+                            parser.getPositionDescription()
    -+                                    + ": <item> tag requires a 'drawable' attribute or "
    -+                                    + "child tag defining a drawable");
    -+                }
    -+                dr = Drawable.createFromXmlInner(r, parser, attrs, theme);
    -+            }
    -+
    -+            state.addDrawable(dr);
    -+        }
    -+    }
    -+
    -+    @Override
    -+    public Drawable mutate() {
    -+        if (!mMutated && super.mutate() == this) {
    -+            mAnimationScaleListState.mutate();
    -+            mMutated = true;
    -+        }
    -+        return this;
    -+    }
    -+
    -+    @Override
    -+    public void clearMutated() {
    -+        super.clearMutated();
    -+        mMutated = false;
    -+    }
    -+
    -+    @Override
    -+    public void start() {
    -+        Drawable dr = getCurrent();
    -+        if (dr != null && dr instanceof Animatable) {
    -+            ((Animatable) dr).start();
    -+        }
    -+    }
    -+
    -+    @Override
    -+    public void stop() {
    -+        Drawable dr = getCurrent();
    -+        if (dr != null && dr instanceof Animatable) {
    -+            ((Animatable) dr).stop();
    -+        }
    -+    }
    -+
    -+    @Override
    -+    public boolean isRunning() {
    -+        boolean result = false;
    -+        Drawable dr = getCurrent();
    -+        if (dr != null && dr instanceof Animatable) {
    -+            result = ((Animatable) dr).isRunning();
    -+        }
    -+        return result;
    -+    }
    -+
    -+    static class AnimationScaleListState extends DrawableContainerState {
    -+        int[] mThemeAttrs = null;
    -+        // The index of the last static drawable.
    -+        int mStaticDrawableIndex = -1;
    -+        // The index of the last animatable drawable.
    -+        int mAnimatableDrawableIndex = -1;
    -+
    -+        AnimationScaleListState(AnimationScaleListState orig, AnimationScaleListDrawable owner,
    -+                Resources res) {
    -+            super(orig, owner, res);
    -+
    -+            if (orig != null) {
    -+                // Perform a shallow copy and rely on mutate() to deep-copy.
    -+                mThemeAttrs = orig.mThemeAttrs;
    -+
    -+                mStaticDrawableIndex = orig.mStaticDrawableIndex;
    -+                mAnimatableDrawableIndex = orig.mAnimatableDrawableIndex;
    -+            }
    -+
    -+        }
    -+
    -+        void mutate() {
    -+            mThemeAttrs = mThemeAttrs != null ? mThemeAttrs.clone() : null;
    -+        }
    -+
    -+        /**
    -+         * Add the drawable into the container.
    -+         * This class only keep track one animatable drawable, and one static. If there are multiple
    -+         * defined in the XML, then pick the last one.
    -+         */
    -+        int addDrawable(Drawable drawable) {
    -+            final int pos = addChild(drawable);
    -+            if (drawable instanceof Animatable) {
    -+                mAnimatableDrawableIndex = pos;
    -+            } else {
    -+                mStaticDrawableIndex = pos;
    -+            }
    -+            return pos;
    -+        }
    -+
    -+        @Override
    -+        public Drawable newDrawable() {
    -+            return new AnimationScaleListDrawable(this, null);
    -+        }
    -+
    -+        @Override
    -+        public Drawable newDrawable(Resources res) {
    -+            return new AnimationScaleListDrawable(this, res);
    -+        }
    -+
    -+        @Override
    -+        public boolean canApplyTheme() {
    -+            return mThemeAttrs != null || super.canApplyTheme();
    -+        }
    -+
    -+        public int getCurrentDrawableIndexBasedOnScale() {
    -+            if (ValueAnimator.getDurationScale() == 0) {
    -+                return mStaticDrawableIndex;
    -+            }
    -+            return mAnimatableDrawableIndex;
    -+        }
    -+    }
    -+
    -+    @Override
    -+    public void applyTheme(@NonNull Theme theme) {
    -+        super.applyTheme(theme);
    -+
    -+        onStateChange(getState());
    -+    }
    -+
    -+    @Override
    -+    protected void setConstantState(@NonNull DrawableContainerState state) {
    -+        super.setConstantState(state);
    -+
    -+        if (state instanceof AnimationScaleListState) {
    -+            mAnimationScaleListState = (AnimationScaleListState) state;
    -+        }
    -+    }
    -+}
    -+
    -diff --git a/core/java/com/android/internal/hardware/AmbientDisplayConfiguration.java b/core/java/com/android/internal/hardware/AmbientDisplayConfiguration.java
    -new file mode 100644
    -index 0000000..cf1bf62
    ---- /dev/null
    -+++ b/core/java/com/android/internal/hardware/AmbientDisplayConfiguration.java
    -@@ -0,0 +1,87 @@
    -+/*
    -+ * Copyright (C) 2016 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 com.android.internal.hardware;
    -+
    -+import com.android.internal.R;
    -+
    -+import android.content.Context;
    -+import android.provider.Settings;
    -+import android.text.TextUtils;
    -+
    -+public class AmbientDisplayConfiguration {
    -+
    -+    private final Context mContext;
    -+
    -+    public AmbientDisplayConfiguration(Context context) {
    -+        mContext = context;
    -+    }
    -+    
    -+    public boolean enabled(int user) {
    -+        return pulseOnNotificationEnabled(user)
    -+                || pulseOnPickupEnabled(user)
    -+                || pulseOnDoubleTapEnabled(user);
    -+    }
    -+    
    -+    public boolean available() {
    -+        return pulseOnNotificationAvailable() || pulseOnPickupAvailable()
    -+                || pulseOnDoubleTapAvailable();
    -+    }
    -+    
    -+    public boolean pulseOnNotificationEnabled(int user) {
    -+        return boolSetting(Settings.Secure.DOZE_ENABLED, user) && pulseOnNotificationAvailable();
    -+    }
    -+
    -+    public boolean pulseOnNotificationAvailable() {
    -+        return ambientDisplayAvailable();
    -+    }
    -+
    -+    public boolean pulseOnPickupEnabled(int user) {
    -+        return boolSetting(Settings.Secure.DOZE_PULSE_ON_PICK_UP, user)
    -+                && pulseOnPickupAvailable();
    -+    }
    -+    
    -+    public boolean pulseOnPickupAvailable() {
    -+        return mContext.getResources().getBoolean(R.bool.config_dozePulsePickup)
    -+                && ambientDisplayAvailable();
    -+    }
    -+    
    -+    public boolean pulseOnDoubleTapEnabled(int user) {
    -+        return boolSetting(Settings.Secure.DOZE_PULSE_ON_DOUBLE_TAP, user)
    -+                && pulseOnDoubleTapAvailable();
    -+    }
    -+
    -+    public boolean pulseOnDoubleTapAvailable() {
    -+        return !TextUtils.isEmpty(doubleTapSensorType()) && ambientDisplayAvailable();
    -+    }
    -+
    -+    public String doubleTapSensorType() {
    -+        return mContext.getResources().getString(R.string.config_dozeDoubleTapSensorType);
    -+    }
    -+
    -+    public String ambientDisplayComponent() {
    -+        return mContext.getResources().getString(R.string.config_dozeComponent);
    -+    }
    -+
    -+    private boolean ambientDisplayAvailable() {
    -+        return !TextUtils.isEmpty(ambientDisplayComponent());
    -+    }
    -+
    -+    private boolean boolSetting(String name, int user) {
    -+        return Settings.Secure.getIntForUser(mContext.getContentResolver(), name, 1, user) != 0;
    -+    }
    -+
    -+}
    -diff --git a/core/java/com/android/internal/os/BatteryStatsImpl.java b/core/java/com/android/internal/os/BatteryStatsImpl.java
    -index 2538d60..3b3344e 100644
    ---- a/core/java/com/android/internal/os/BatteryStatsImpl.java
    -+++ b/core/java/com/android/internal/os/BatteryStatsImpl.java
    -@@ -10727,7 +10727,7 @@ public class BatteryStatsImpl extends BatteryStats {
    -             }
    - 
    -             int NW = in.readInt();
    --            if (NW > 100) {
    -+            if (NW > (MAX_WAKELOCKS_PER_UID+1)) {
    -                 throw new ParcelFormatException("File corrupt: too many wake locks " + NW);
    -             }
    -             for (int iw = 0; iw < NW; iw++) {
    -@@ -10736,7 +10736,7 @@ public class BatteryStatsImpl extends BatteryStats {
    -             }
    - 
    -             int NS = in.readInt();
    --            if (NS > 100) {
    -+            if (NS > (MAX_WAKELOCKS_PER_UID+1)) {
    -                 throw new ParcelFormatException("File corrupt: too many syncs " + NS);
    -             }
    -             for (int is = 0; is < NS; is++) {
    -@@ -10745,7 +10745,7 @@ public class BatteryStatsImpl extends BatteryStats {
    -             }
    - 
    -             int NJ = in.readInt();
    --            if (NJ > 100) {
    -+            if (NJ > (MAX_WAKELOCKS_PER_UID+1)) {
    -                 throw new ParcelFormatException("File corrupt: too many job timers " + NJ);
    -             }
    -             for (int ij = 0; ij < NJ; ij++) {
    -diff --git a/core/java/com/android/internal/os/ProcessCpuTracker.java b/core/java/com/android/internal/os/ProcessCpuTracker.java
    -index b7e5718..e46dfc4 100644
    ---- a/core/java/com/android/internal/os/ProcessCpuTracker.java
    -+++ b/core/java/com/android/internal/os/ProcessCpuTracker.java
    -@@ -39,6 +39,7 @@ import java.util.ArrayList;
    - import java.util.Collections;
    - import java.util.Comparator;
    - import java.util.Date;
    -+import java.util.List;
    - import java.util.StringTokenizer;
    - 
    - public class ProcessCpuTracker {
    -@@ -177,6 +178,11 @@ public class ProcessCpuTracker {
    - 
    -     private byte[] mBuffer = new byte[4096];
    - 
    -+    public interface FilterStats {
    -+        /** Which stats to pick when filtering */
    -+        boolean needed(Stats stats);
    -+    }
    -+
    -     public static class Stats {
    -         public final int pid;
    -         public final int uid;
    -@@ -695,6 +701,18 @@ public class ProcessCpuTracker {
    -         return mProcStats.get(index);
    -     }
    - 
    -+    final public List<Stats> getStats(FilterStats filter) {
    -+        final ArrayList<Stats> statses = new ArrayList<>(mProcStats.size());
    -+        final int N = mProcStats.size();
    -+        for (int p = 0; p < N; p++) {
    -+            Stats stats = mProcStats.get(p);
    -+            if (filter.needed(stats)) {
    -+                statses.add(stats);
    -+            }
    -+        }
    -+        return statses;
    -+    }
    -+
    -     final public int countWorkingStats() {
    -         buildWorkingProcs();
    -         return mWorkingProcs.size();
    -diff --git a/core/java/com/android/internal/policy/BackdropFrameRenderer.java b/core/java/com/android/internal/policy/BackdropFrameRenderer.java
    -index 619303f..1abb59b 100644
    ---- a/core/java/com/android/internal/policy/BackdropFrameRenderer.java
    -+++ b/core/java/com/android/internal/policy/BackdropFrameRenderer.java
    -@@ -110,12 +110,15 @@ public class BackdropFrameRenderer extends Thread implements Choreographer.Frame
    -             int statusBarColor, int navigationBarColor) {
    -         mDecorView = decorView;
    -         mResizingBackgroundDrawable = resizingBackgroundDrawable != null
    -+                        && resizingBackgroundDrawable.getConstantState() != null
    -                 ? resizingBackgroundDrawable.getConstantState().newDrawable()
    -                 : null;
    -         mCaptionBackgroundDrawable = captionBackgroundDrawableDrawable != null
    -+                        && captionBackgroundDrawableDrawable.getConstantState() != null
    -                 ? captionBackgroundDrawableDrawable.getConstantState().newDrawable()
    -                 : null;
    -         mUserCaptionBackgroundDrawable = userCaptionBackgroundDrawable != null
    -+                        && userCaptionBackgroundDrawable.getConstantState() != null
    -                 ? userCaptionBackgroundDrawable.getConstantState().newDrawable()
    -                 : null;
    -         if (mCaptionBackgroundDrawable == null) {
    -diff --git a/core/java/com/android/internal/policy/EmergencyAffordanceManager.java b/core/java/com/android/internal/policy/EmergencyAffordanceManager.java
    -new file mode 100644
    -index 0000000..eb75bd4
    ---- /dev/null
    -+++ b/core/java/com/android/internal/policy/EmergencyAffordanceManager.java
    -@@ -0,0 +1,102 @@
    -+/*
    -+ * Copyright (C) 2016 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 com.android.internal.policy;
    -+
    -+import android.content.Context;
    -+import android.content.Intent;
    -+import android.net.Uri;
    -+import android.os.Build;
    -+import android.os.UserHandle;
    -+import android.provider.Settings;
    -+
    -+/**
    -+ * A class that manages emergency affordances and enables immediate calling to emergency services
    -+ */
    -+public class EmergencyAffordanceManager {
    -+
    -+    public static final boolean ENABLED = true;
    -+
    -+    /**
    -+     * Global setting override with the number to call with the emergency affordance.
    -+     * @hide
    -+     */
    -+    private static final String EMERGENCY_CALL_NUMBER_SETTING = "emergency_affordance_number";
    -+
    -+    /**
    -+     * Global setting, whether the emergency affordance should be shown regardless of device state.
    -+     * The value is a boolean (1 or 0).
    -+     * @hide
    -+     */
    -+    private static final String FORCE_EMERGENCY_AFFORDANCE_SETTING = "force_emergency_affordance";
    -+
    -+    private final Context mContext;
    -+
    -+    public EmergencyAffordanceManager(Context context) {
    -+        mContext = context;
    -+    }
    -+
    -+    /**
    -+     * perform an emergency call.
    -+     */
    -+    public final void performEmergencyCall() {
    -+        performEmergencyCall(mContext);
    -+    }
    -+
    -+    private static Uri getPhoneUri(Context context) {
    -+        String number = context.getResources().getString(
    -+                com.android.internal.R.string.config_emergency_call_number);
    -+        if (Build.IS_DEBUGGABLE) {
    -+            String override = Settings.Global.getString(
    -+                    context.getContentResolver(), EMERGENCY_CALL_NUMBER_SETTING);
    -+            if (override != null) {
    -+                number = override;
    -+            }
    -+        }
    -+        return Uri.fromParts("tel", number, null);
    -+    }
    -+
    -+    private static void performEmergencyCall(Context context) {
    -+        Intent intent = new Intent(Intent.ACTION_CALL_EMERGENCY);
    -+        intent.setData(getPhoneUri(context));
    -+        intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
    -+        context.startActivityAsUser(intent, UserHandle.CURRENT);
    -+    }
    -+
    -+    /**
    -+     * @return whether emergency affordance should be active.
    -+     */
    -+    public boolean needsEmergencyAffordance() {
    -+        if (!ENABLED) {
    -+            return false;
    -+        }
    -+        if (forceShowing()) {
    -+            return true;
    -+        }
    -+        return isEmergencyAffordanceNeeded();
    -+    }
    -+
    -+    private boolean isEmergencyAffordanceNeeded() {
    -+        return Settings.Global.getInt(mContext.getContentResolver(),
    -+                Settings.Global.EMERGENCY_AFFORDANCE_NEEDED, 0) != 0;
    -+    }
    -+
    -+
    -+    private boolean forceShowing() {
    -+        return Settings.Global.getInt(mContext.getContentResolver(),
    -+                FORCE_EMERGENCY_AFFORDANCE_SETTING, 0) != 0;
    -+    }
    -+}
    -diff --git a/core/java/com/android/internal/policy/IKeyguardService.aidl b/core/java/com/android/internal/policy/IKeyguardService.aidl
    -index 83d75fb..e51ad3f 100644
    ---- a/core/java/com/android/internal/policy/IKeyguardService.aidl
    -+++ b/core/java/com/android/internal/policy/IKeyguardService.aidl
    -@@ -28,8 +28,9 @@ oneway interface IKeyguardService {
    -      * FLAG_SHOW_ON_LOCK_SCREEN.
    -      *
    -      * @param isOccluded Whether the Keyguard is occluded by another window.
    -+     * @param animate Whether to play an animation for the state change.
    -      */
    --    void setOccluded(boolean isOccluded);
    -+    void setOccluded(boolean isOccluded, boolean animate);
    - 
    -     void addStateMonitorCallback(IKeyguardStateCallback callback);
    -     void verifyUnlock(IKeyguardExitCallback callback);
    -diff --git a/core/java/com/android/internal/policy/PhoneFallbackEventHandler.java b/core/java/com/android/internal/policy/PhoneFallbackEventHandler.java
    -index 2cb9c25..fb0edea 100644
    ---- a/core/java/com/android/internal/policy/PhoneFallbackEventHandler.java
    -+++ b/core/java/com/android/internal/policy/PhoneFallbackEventHandler.java
    -@@ -150,6 +150,7 @@ public class PhoneFallbackEventHandler implements FallbackEventHandler {
    -                         sendCloseSystemWindows();
    -                         // Broadcast an intent that the Camera button was longpressed
    -                         Intent intent = new Intent(Intent.ACTION_CAMERA_BUTTON, null);
    -+                        intent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
    -                         intent.putExtra(Intent.EXTRA_KEY_EVENT, event);
    -                         mContext.sendOrderedBroadcastAsUser(intent, UserHandle.CURRENT_OR_SELF,
    -                                 null, null, null, 0, null, null);
    -diff --git a/core/java/com/android/internal/util/WakeupMessage.java b/core/java/com/android/internal/util/WakeupMessage.java
    -index 7d222c7..46098c5 100644
    ---- a/core/java/com/android/internal/util/WakeupMessage.java
    -+++ b/core/java/com/android/internal/util/WakeupMessage.java
    -@@ -108,7 +108,7 @@ public class WakeupMessage implements AlarmManager.OnAlarmListener {
    -         }
    -         if (stillScheduled) {
    -             Message msg = mHandler.obtainMessage(mCmd, mArg1, mArg2, mObj);
    --            mHandler.handleMessage(msg);
    -+            mHandler.dispatchMessage(msg);
    -             msg.recycle();
    -         }
    -     }
    -diff --git a/core/java/com/android/internal/view/IInputConnectionWrapper.java b/core/java/com/android/internal/view/IInputConnectionWrapper.java
    -index 644c7e9..4f7b106 100644
    ---- a/core/java/com/android/internal/view/IInputConnectionWrapper.java
    -+++ b/core/java/com/android/internal/view/IInputConnectionWrapper.java
    -@@ -580,7 +580,13 @@ public abstract class IInputConnectionWrapper extends IInputContext.Stub {
    -                         return;
    -                     }
    -                     if (grantUriPermission) {
    --                        inputContentInfo.requestPermission();
    -+                        try {
    -+                            inputContentInfo.requestPermission();
    -+                        } catch (Exception e) {
    -+                            Log.e(TAG, "InputConnectionInfo.requestPermission() failed", e);
    -+                            args.callback.setCommitContentResult(false, args.seq);
    -+                            return;
    -+                        }
    -                     }
    -                     final boolean result =
    -                             ic.commitContent(inputContentInfo, flags, (Bundle) args.arg2);
    -diff --git a/core/java/com/android/internal/widget/AlertDialogLayout.java b/core/java/com/android/internal/widget/AlertDialogLayout.java
    -index 891c920..9bf0948 100644
    ---- a/core/java/com/android/internal/widget/AlertDialogLayout.java
    -+++ b/core/java/com/android/internal/widget/AlertDialogLayout.java
    -@@ -20,7 +20,9 @@ import android.annotation.AttrRes;
    - import android.annotation.Nullable;
    - import android.annotation.StyleRes;
    - import android.content.Context;
    -+import android.graphics.drawable.Drawable;
    - import android.util.AttributeSet;
    -+import android.view.Gravity;
    - import android.view.View;
    - import android.view.ViewGroup;
    - import android.widget.LinearLayout;
    -@@ -265,4 +267,92 @@ public class AlertDialogLayout extends LinearLayout {
    - 
    -         return 0;
    -     }
    -+
    -+    @Override
    -+    protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
    -+        final int paddingLeft = mPaddingLeft;
    -+
    -+        // Where right end of child should go
    -+        final int width = right - left;
    -+        final int childRight = width - mPaddingRight;
    -+
    -+        // Space available for child
    -+        final int childSpace = width - paddingLeft - mPaddingRight;
    -+
    -+        final int totalLength = getMeasuredHeight();
    -+        final int count = getChildCount();
    -+        final int gravity = getGravity();
    -+        final int majorGravity = gravity & Gravity.VERTICAL_GRAVITY_MASK;
    -+        final int minorGravity = gravity & Gravity.RELATIVE_HORIZONTAL_GRAVITY_MASK;
    -+
    -+        int childTop;
    -+        switch (majorGravity) {
    -+            case Gravity.BOTTOM:
    -+                // totalLength contains the padding already
    -+                childTop = mPaddingTop + bottom - top - totalLength;
    -+                break;
    -+
    -+            // totalLength contains the padding already
    -+            case Gravity.CENTER_VERTICAL:
    -+                childTop = mPaddingTop + (bottom - top - totalLength) / 2;
    -+                break;
    -+
    -+            case Gravity.TOP:
    -+            default:
    -+                childTop = mPaddingTop;
    -+                break;
    -+        }
    -+
    -+        final Drawable dividerDrawable = getDividerDrawable();
    -+        final int dividerHeight = dividerDrawable == null ?
    -+                0 : dividerDrawable.getIntrinsicHeight();
    -+
    -+        for (int i = 0; i < count; i++) {
    -+            final View child = getChildAt(i);
    -+            if (child != null && child.getVisibility() != GONE) {
    -+                final int childWidth = child.getMeasuredWidth();
    -+                final int childHeight = child.getMeasuredHeight();
    -+
    -+                final LinearLayout.LayoutParams lp =
    -+                        (LinearLayout.LayoutParams) child.getLayoutParams();
    -+
    -+                int layoutGravity = lp.gravity;
    -+                if (layoutGravity < 0) {
    -+                    layoutGravity = minorGravity;
    -+                }
    -+                final int layoutDirection = getLayoutDirection();
    -+                final int absoluteGravity = Gravity.getAbsoluteGravity(
    -+                        layoutGravity, layoutDirection);
    -+
    -+                final int childLeft;
    -+                switch (absoluteGravity & Gravity.HORIZONTAL_GRAVITY_MASK) {
    -+                    case Gravity.CENTER_HORIZONTAL:
    -+                        childLeft = paddingLeft + ((childSpace - childWidth) / 2)
    -+                                + lp.leftMargin - lp.rightMargin;
    -+                        break;
    -+
    -+                    case Gravity.RIGHT:
    -+                        childLeft = childRight - childWidth - lp.rightMargin;
    -+                        break;
    -+
    -+                    case Gravity.LEFT:
    -+                    default:
    -+                        childLeft = paddingLeft + lp.leftMargin;
    -+                        break;
    -+                }
    -+
    -+                if (hasDividerBeforeChildAt(i)) {
    -+                    childTop += dividerHeight;
    -+                }
    -+
    -+                childTop += lp.topMargin;
    -+                setChildFrame(child, childLeft, childTop, childWidth, childHeight);
    -+                childTop += childHeight + lp.bottomMargin;
    -+            }
    -+        }
    -+    }
    -+
    -+    private void setChildFrame(View child, int left, int top, int width, int height) {
    -+        child.layout(left, top, left + width, top + height);
    -+    }
    - }
    -diff --git a/core/java/com/android/internal/widget/ImageFloatingTextView.java b/core/java/com/android/internal/widget/ImageFloatingTextView.java
    -index 926ebd1..358be60 100644
    ---- a/core/java/com/android/internal/widget/ImageFloatingTextView.java
    -+++ b/core/java/com/android/internal/widget/ImageFloatingTextView.java
    -@@ -40,6 +40,9 @@ public class ImageFloatingTextView extends TextView {
    -     /** Number of lines from the top to indent */
    -     private int mIndentLines;
    - 
    -+    /** Resolved layout direction */
    -+    private int mResolvedDirection = LAYOUT_DIRECTION_UNDEFINED;
    -+
    -     public ImageFloatingTextView(Context context) {
    -         this(context, null);
    -     }
    -@@ -82,7 +85,7 @@ public class ImageFloatingTextView extends TextView {
    -                 margins[i] = endMargin;
    -             }
    -         }
    --        if (getLayoutDirection() == LAYOUT_DIRECTION_RTL) {
    -+        if (mResolvedDirection == LAYOUT_DIRECTION_RTL) {
    -             builder.setIndents(margins, null);
    -         } else {
    -             builder.setIndents(null, margins);
    -@@ -91,6 +94,19 @@ public class ImageFloatingTextView extends TextView {
    -         return builder.build();
    -     }
    - 
    -+    @Override
    -+    public void onRtlPropertiesChanged(int layoutDirection) {
    -+        super.onRtlPropertiesChanged(layoutDirection);
    -+
    -+        if (layoutDirection != mResolvedDirection && isLayoutDirectionResolved()) {
    -+            mResolvedDirection = layoutDirection;
    -+            if (mIndentLines > 0) {
    -+                // Invalidate layout.
    -+                setHint(getHint());
    -+            }
    -+        }
    -+    }
    -+
    -     @RemotableViewMethod
    -     public void setHasImage(boolean hasImage) {
    -         setNumIndentLines(hasImage ? 2 : 0);
    -diff --git a/core/java/com/android/server/BootReceiver.java b/core/java/com/android/server/BootReceiver.java
    -index fbc51cd..5a50fbf 100644
    ---- a/core/java/com/android/server/BootReceiver.java
    -+++ b/core/java/com/android/server/BootReceiver.java
    -@@ -79,6 +79,9 @@ public class BootReceiver extends BroadcastReceiver {
    -     private static final String LOG_FILES_FILE = "log-files.xml";
    -     private static final AtomicFile sFile = new AtomicFile(new File(
    -             Environment.getDataSystemDirectory(), LOG_FILES_FILE));
    -+    private static final String LAST_HEADER_FILE = "last-header.txt";
    -+    private static final File lastHeaderFile = new File(
    -+            Environment.getDataSystemDirectory(), LAST_HEADER_FILE);
    - 
    -     @Override
    -     public void onReceive(final Context context, Intent intent) {
    -@@ -113,9 +116,17 @@ public class BootReceiver extends BroadcastReceiver {
    -         Downloads.removeAllDownloadsByPackage(context, OLD_UPDATER_PACKAGE, OLD_UPDATER_CLASS);
    -     }
    - 
    --    private void logBootEvents(Context ctx) throws IOException {
    --        final DropBoxManager db = (DropBoxManager) ctx.getSystemService(Context.DROPBOX_SERVICE);
    --        final String headers = new StringBuilder(512)
    -+    private String getPreviousBootHeaders() {
    -+        try {
    -+            return FileUtils.readTextFile(lastHeaderFile, 0, null);
    -+        } catch (IOException e) {
    -+            Slog.e(TAG, "Error reading " + lastHeaderFile, e);
    -+            return null;
    -+        }
    -+    }
    -+
    -+    private String getCurrentBootHeaders() throws IOException {
    -+        return new StringBuilder(512)
    -             .append("Build: ").append(Build.FINGERPRINT).append("\n")
    -             .append("Hardware: ").append(Build.BOARD).append("\n")
    -             .append("Revision: ")
    -@@ -125,6 +136,31 @@ public class BootReceiver extends BroadcastReceiver {
    -             .append("Kernel: ")
    -             .append(FileUtils.readTextFile(new File("/proc/version"), 1024, "...\n"))
    -             .append("\n").toString();
    -+    }
    -+
    -+
    -+    private String getBootHeadersToLogAndUpdate() throws IOException {
    -+        final String oldHeaders = getPreviousBootHeaders();
    -+        final String newHeaders = getCurrentBootHeaders();
    -+
    -+        try {
    -+            FileUtils.stringToFile(lastHeaderFile, newHeaders);
    -+        } catch (IOException e) {
    -+            Slog.e(TAG, "Error writing " + lastHeaderFile, e);
    -+        }
    -+
    -+        if (oldHeaders == null) {
    -+            // If we failed to read the old headers, use the current headers
    -+            // but note this in the headers so we know
    -+            return "isPrevious: false\n" + newHeaders;
    -+        }
    -+
    -+        return "isPrevious: true\n" + oldHeaders;
    -+    }
    -+
    -+    private void logBootEvents(Context ctx) throws IOException {
    -+        final DropBoxManager db = (DropBoxManager) ctx.getSystemService(Context.DROPBOX_SERVICE);
    -+        final String headers = getBootHeadersToLogAndUpdate();
    -         final String bootReason = SystemProperties.get("ro.boot.bootreason", null);
    - 
    -         String recovery = RecoverySystem.handleAftermath(ctx);
    -diff --git a/core/java/com/android/server/backup/AccountManagerBackupHelper.java b/core/java/com/android/server/backup/AccountManagerBackupHelper.java
    -new file mode 100644
    -index 0000000..39b18c0
    ---- /dev/null
    -+++ b/core/java/com/android/server/backup/AccountManagerBackupHelper.java
    -@@ -0,0 +1,85 @@
    -+/*
    -+ * Copyright (C) 2016 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 com.android.server.backup;
    -+
    -+import android.accounts.AccountManagerInternal;
    -+import android.app.backup.BlobBackupHelper;
    -+import android.os.UserHandle;
    -+import android.util.Slog;
    -+import com.android.server.LocalServices;
    -+
    -+/**
    -+ * Helper for handling backup of account manager specific state.
    -+ */
    -+public class AccountManagerBackupHelper extends BlobBackupHelper {
    -+    private static final String TAG = "AccountsBackup";
    -+    private static final boolean DEBUG = false;
    -+
    -+    // current schema of the backup state blob
    -+    private static final int STATE_VERSION = 1;
    -+
    -+    // key under which the account access grant state blob is committed to backup
    -+    private static final String KEY_ACCOUNT_ACCESS_GRANTS = "account_access_grants";
    -+
    -+    public AccountManagerBackupHelper() {
    -+        super(STATE_VERSION, KEY_ACCOUNT_ACCESS_GRANTS);
    -+    }
    -+
    -+    @Override
    -+    protected byte[] getBackupPayload(String key) {
    -+        AccountManagerInternal am = LocalServices.getService(AccountManagerInternal.class);
    -+        if (DEBUG) {
    -+            Slog.d(TAG, "Handling backup of " + key);
    -+        }
    -+        try {
    -+            switch (key) {
    -+                case KEY_ACCOUNT_ACCESS_GRANTS: {
    -+                    return am.backupAccountAccessPermissions(UserHandle.USER_SYSTEM);
    -+                }
    -+
    -+                default: {
    -+                    Slog.w(TAG, "Unexpected backup key " + key);
    -+                }
    -+            }
    -+        } catch (Exception e) {
    -+            Slog.e(TAG, "Unable to store payload " + key);
    -+        }
    -+
    -+        return new byte[0];
    -+    }
    -+
    -+    @Override
    -+    protected void applyRestoredPayload(String key, byte[] payload) {
    -+        AccountManagerInternal am = LocalServices.getService(AccountManagerInternal.class);
    -+        if (DEBUG) {
    -+            Slog.d(TAG, "Handling restore of " + key);
    -+        }
    -+        try {
    -+            switch (key) {
    -+                case KEY_ACCOUNT_ACCESS_GRANTS: {
    -+                    am.restoreAccountAccessPermissions(payload, UserHandle.USER_SYSTEM);
    -+                } break;
    -+
    -+                default: {
    -+                    Slog.w(TAG, "Unexpected restore key " + key);
    -+                }
    -+            }
    -+        } catch (Exception e) {
    -+            Slog.w(TAG, "Unable to restore key " + key);
    -+        }
    -+    }
    -+}
    -diff --git a/core/java/com/android/server/backup/SystemBackupAgent.java b/core/java/com/android/server/backup/SystemBackupAgent.java
    -index 9d296fa..5375651 100644
    ---- a/core/java/com/android/server/backup/SystemBackupAgent.java
    -+++ b/core/java/com/android/server/backup/SystemBackupAgent.java
    -@@ -49,6 +49,7 @@ public class SystemBackupAgent extends BackupAgentHelper {
    -     private static final String PERMISSION_HELPER = "permissions";
    -     private static final String USAGE_STATS_HELPER = "usage_stats";
    -     private static final String SHORTCUT_MANAGER_HELPER = "shortcut_manager";
    -+    private static final String ACCOUNT_MANAGER_HELPER = "account_manager";
    - 
    -     // These paths must match what the WallpaperManagerService uses.  The leaf *_FILENAME
    -     // are also used in the full-backup file format, so must not change unless steps are
    -@@ -82,6 +83,7 @@ public class SystemBackupAgent extends BackupAgentHelper {
    -         addHelper(PERMISSION_HELPER, new PermissionBackupHelper());
    -         addHelper(USAGE_STATS_HELPER, new UsageStatsBackupHelper(this));
    -         addHelper(SHORTCUT_MANAGER_HELPER, new ShortcutBackupHelper());
    -+        addHelper(ACCOUNT_MANAGER_HELPER, new AccountManagerBackupHelper());
    -         super.onBackup(oldState, data, newState);
    -     }
    - 
    -@@ -111,6 +113,7 @@ public class SystemBackupAgent extends BackupAgentHelper {
    -         addHelper(PERMISSION_HELPER, new PermissionBackupHelper());
    -         addHelper(USAGE_STATS_HELPER, new UsageStatsBackupHelper(this));
    -         addHelper(SHORTCUT_MANAGER_HELPER, new ShortcutBackupHelper());
    -+        addHelper(ACCOUNT_MANAGER_HELPER, new AccountManagerBackupHelper());
    - 
    -         try {
    -             super.onRestore(data, appVersionCode, newState);
    -diff --git a/core/jni/android/graphics/pdf/PdfEditor.cpp b/core/jni/android/graphics/pdf/PdfEditor.cpp
    -index d2d39cd..0468b64 100644
    ---- a/core/jni/android/graphics/pdf/PdfEditor.cpp
    -+++ b/core/jni/android/graphics/pdf/PdfEditor.cpp
    -@@ -52,11 +52,9 @@ static struct {
    - } gRectClassInfo;
    - 
    - // Also used in PdfRenderer.cpp
    --Mutex sPdfiumLock;
    - int sUnmatchedPdfiumInitRequestCount = 0;
    - 
    - static void initializeLibraryIfNeeded() {
    --    Mutex::Autolock _l(sPdfiumLock);
    -     if (sUnmatchedPdfiumInitRequestCount == 0) {
    -         FPDF_InitLibrary();
    -     }
    -@@ -64,7 +62,6 @@ static void initializeLibraryIfNeeded() {
    - }
    - 
    - static void destroyLibraryIfNeeded() {
    --    Mutex::Autolock _l(sPdfiumLock);
    -     sUnmatchedPdfiumInitRequestCount--;
    -     if (sUnmatchedPdfiumInitRequestCount == 0) {
    -        FPDF_DestroyLibrary();
    -diff --git a/core/jni/android/graphics/pdf/PdfRenderer.cpp b/core/jni/android/graphics/pdf/PdfRenderer.cpp
    -index 71bec78..43550ac 100644
    ---- a/core/jni/android/graphics/pdf/PdfRenderer.cpp
    -+++ b/core/jni/android/graphics/pdf/PdfRenderer.cpp
    -@@ -44,11 +44,9 @@ static struct {
    - } gPointClassInfo;
    - 
    - // See PdfEditor.cpp
    --extern Mutex sPdfiumLock;
    - extern int sUnmatchedPdfiumInitRequestCount;
    - 
    - static void initializeLibraryIfNeeded() {
    --    Mutex::Autolock _l(sPdfiumLock);
    -     if (sUnmatchedPdfiumInitRequestCount == 0) {
    -         FPDF_InitLibrary();
    -     }
    -@@ -56,7 +54,6 @@ static void initializeLibraryIfNeeded() {
    - }
    - 
    - static void destroyLibraryIfNeeded() {
    --    Mutex::Autolock _l(sPdfiumLock);
    -     sUnmatchedPdfiumInitRequestCount--;
    -     if (sUnmatchedPdfiumInitRequestCount == 0) {
    -        FPDF_DestroyLibrary();
    -diff --git a/core/jni/android_database_CursorWindow.cpp b/core/jni/android_database_CursorWindow.cpp
    -index bb09d00..e96613b 100644
    ---- a/core/jni/android_database_CursorWindow.cpp
    -+++ b/core/jni/android_database_CursorWindow.cpp
    -@@ -16,6 +16,7 @@
    - 
    - #undef LOG_TAG
    - #define LOG_TAG "CursorWindow"
    -+#define LOG_NDEBUG 0
    - 
    - #include <inttypes.h>
    - #include <jni.h>
    -@@ -30,6 +31,11 @@
    - #include <stdio.h>
    - #include <string.h>
    - #include <unistd.h>
    -+#include <sys/types.h>
    -+#include <dirent.h>
    -+
    -+#undef LOG_NDEBUG
    -+#define LOG_NDEBUG 1
    - 
    - #include <androidfw/CursorWindow.h>
    - #include "android_os_Parcel.h"
    -@@ -61,6 +67,22 @@ static void throwUnknownTypeException(JNIEnv * env, jint type) {
    -     jniThrowException(env, "java/lang/IllegalStateException", msg.string());
    - }
    - 
    -+static int getFdCount() {
    -+    char fdpath[PATH_MAX];
    -+    int count = 0;
    -+    snprintf(fdpath, PATH_MAX, "/proc/%d/fd", getpid());
    -+    DIR *dir = opendir(fdpath);
    -+    if (dir != NULL) {
    -+        struct dirent *dirent;
    -+        while ((dirent = readdir(dir))) {
    -+            count++;
    -+        }
    -+        count -= 2; // discount "." and ".."
    -+        closedir(dir);
    -+    }
    -+    return count;
    -+}
    -+
    - static jlong nativeCreate(JNIEnv* env, jclass clazz, jstring nameObj, jint cursorWindowSize) {
    -     String8 name;
    -     const char* nameStr = env->GetStringUTFChars(nameObj, NULL);
    -@@ -85,7 +107,8 @@ static jlong nativeCreateFromParcel(JNIEnv* env, jclass clazz, jobject parcelObj
    -     CursorWindow* window;
    -     status_t status = CursorWindow::createFromParcel(parcel, &window);
    -     if (status || !window) {
    --        ALOGE("Could not create CursorWindow from Parcel due to error %d.", status);
    -+        ALOGE("Could not create CursorWindow from Parcel due to error %d, process fd count=%d",
    -+                status, getFdCount());
    -         return 0;
    -     }
    - 
    -diff --git a/core/jni/android_hardware_Camera.cpp b/core/jni/android_hardware_Camera.cpp
    -index 9459257..b926270 100644
    ---- a/core/jni/android_hardware_Camera.cpp
    -+++ b/core/jni/android_hardware_Camera.cpp
    -@@ -350,9 +350,16 @@ void JNICameraContext::postDataTimestamp(nsecs_t timestamp, int32_t msgType, con
    -     postData(msgType, dataPtr, NULL);
    - }
    - 
    --void JNICameraContext::postRecordingFrameHandleTimestamp(nsecs_t, native_handle_t*) {
    --    // This is not needed at app layer. This should not be called because JNICameraContext cannot
    --    // start video recording.
    -+void JNICameraContext::postRecordingFrameHandleTimestamp(nsecs_t, native_handle_t* handle) {
    -+    // Video buffers are not needed at app layer so just return the video buffers here.
    -+    // This may be called when stagefright just releases camera but there are still outstanding
    -+    // video buffers.
    -+    if (mCamera != nullptr) {
    -+        mCamera->releaseRecordingFrameHandle(handle);
    -+    } else {
    -+        native_handle_close(handle);
    -+        native_handle_delete(handle);
    -+    }
    - }
    - 
    - void JNICameraContext::postMetadata(JNIEnv *env, int32_t msgType, camera_frame_metadata_t *metadata)
    -diff --git a/core/jni/android_hardware_location_ContextHubService.cpp b/core/jni/android_hardware_location_ContextHubService.cpp
    -index 9515a0e..8eb39e1 100644
    ---- a/core/jni/android_hardware_location_ContextHubService.cpp
    -+++ b/core/jni/android_hardware_location_ContextHubService.cpp
    -@@ -26,6 +26,10 @@
    - #include <stdint.h>
    - #include <stdio.h>
    - #include <stdlib.h>
    -+
    -+// TOOD: On master, alphabetize these and move <mutex> into this
    -+//     grouping.
    -+#include <chrono>
    - #include <unordered_map>
    - #include <queue>
    - 
    -@@ -34,11 +38,12 @@
    - #include "JNIHelp.h"
    - #include "core_jni_helpers.h"
    - 
    --static constexpr int OS_APP_ID = -1;
    -+static constexpr jint OS_APP_ID = -1;
    -+static constexpr jint INVALID_APP_ID = -2;
    - static constexpr uint64_t ALL_APPS = UINT64_C(0xFFFFFFFFFFFFFFFF);
    - 
    --static constexpr int MIN_APP_ID = 1;
    --static constexpr int MAX_APP_ID = 128;
    -+static constexpr jint MIN_APP_ID = 1;
    -+static constexpr jint MAX_APP_ID = 128;
    - 
    - static constexpr size_t MSG_HEADER_SIZE = 4;
    - static constexpr size_t HEADER_FIELD_MSG_TYPE = 0;
    -@@ -50,6 +55,10 @@ static constexpr size_t HEADER_FIELD_LOAD_APP_ID_LO = MSG_HEADER_SIZE;
    - static constexpr size_t HEADER_FIELD_LOAD_APP_ID_HI = MSG_HEADER_SIZE + 1;
    - static constexpr size_t MSG_HEADER_SIZE_LOAD_APP = MSG_HEADER_SIZE + 2;
    - 
    -+// Monotonically increasing clock we use to determine if we can cancel
    -+// a transaction.
    -+using std::chrono::steady_clock;
    -+
    - namespace android {
    - 
    - namespace {
    -@@ -102,10 +111,21 @@ struct context_hub_info_s {
    - struct app_instance_info_s {
    -     uint64_t truncName;          // Possibly truncated name for logging
    -     uint32_t hubHandle;          // Id of the hub this app is on
    --    int instanceId;              // system wide unique instance id - assigned
    -+    jint instanceId;             // system wide unique instance id - assigned
    -     struct hub_app_info appInfo; // returned from the HAL
    - };
    - 
    -+
    -+// If a transaction takes longer than this, we'll allow it to be
    -+// canceled by a new transaction.  Note we do _not_ automatically
    -+// cancel a transaction after this much time.  We can have a
    -+// legal transaction which takes longer than this amount of time,
    -+// as long as no other new transactions are attempted after this
    -+// time has expired.
    -+// TODO(b/31105001): Establish a clean timing approach for all
    -+// of our HAL interactions.
    -+constexpr auto kMinTransactionCancelTime = std::chrono::seconds(29);
    -+
    - /*
    -  * TODO(ashutoshj): From original code review:
    -  *
    -@@ -147,14 +167,15 @@ struct txnManager_s {
    -     std::mutex m;                 // mutex for manager
    -     hub_messages_e txnIdentifier; // What are we doing
    -     void *txnData;                // Details
    -+    steady_clock::time_point firstTimeTxnCanBeCanceled;
    - };
    - 
    - struct contextHubServiceDb_s {
    -     int initialized;
    -     context_hub_info_s hubInfo;
    -     jniInfo_s jniInfo;
    --    std::queue<int> freeIds;
    --    std::unordered_map<int, app_instance_info_s> appInstances;
    -+    std::queue<jint> freeIds;
    -+    std::unordered_map<jint, app_instance_info_s> appInstances;
    -     txnManager_s txnManager;
    - };
    - 
    -@@ -176,25 +197,40 @@ static int addTxn(hub_messages_e txnIdentifier, void *txnData) {
    -     std::lock_guard<std::mutex>lock(mgr->m);
    - 
    -     mgr->txnPending = true;
    -+    mgr->firstTimeTxnCanBeCanceled = steady_clock::now() +
    -+        kMinTransactionCancelTime;
    -     mgr->txnData = txnData;
    -     mgr->txnIdentifier = txnIdentifier;
    - 
    -     return 0;
    - }
    - 
    --static int closeTxn() {
    -+// Only call this if you hold the db.txnManager.m lock.
    -+static void closeTxnUnlocked() {
    -     txnManager_s *mgr = &db.txnManager;
    --    std::lock_guard<std::mutex>lock(mgr->m);
    -     mgr->txnPending = false;
    -     free(mgr->txnData);
    -     mgr->txnData = nullptr;
    -+}
    - 
    -+static int closeTxn() {
    -+    std::lock_guard<std::mutex>lock(db.txnManager.m);
    -+    closeTxnUnlocked();
    -     return 0;
    - }
    - 
    -+// If a transaction has been pending for longer than
    -+// kMinTransactionCancelTime, this call will "cancel" that
    -+// transaction and return that there are none pending.
    - static bool isTxnPending() {
    -     txnManager_s *mgr = &db.txnManager;
    -     std::lock_guard<std::mutex>lock(mgr->m);
    -+    if (mgr->txnPending) {
    -+        if (steady_clock::now() >= mgr->firstTimeTxnCanBeCanceled) {
    -+            ALOGW("Transaction canceled");
    -+            closeTxnUnlocked();
    -+        }
    -+    }
    -     return mgr->txnPending;
    - }
    - 
    -@@ -259,16 +295,17 @@ static int get_hub_id_for_hub_handle(int hubHandle) {
    -     }
    - }
    - 
    --static int get_hub_handle_for_app_instance(int id) {
    -+static int get_hub_handle_for_app_instance(jint id) {
    -     if (!db.appInstances.count(id)) {
    --        ALOGD("%s: Cannot find app for app instance %d", __FUNCTION__, id);
    -+        ALOGD("%s: Cannot find app for app instance %" PRId32,
    -+              __FUNCTION__, id);
    -         return -1;
    -     }
    - 
    -     return db.appInstances[id].hubHandle;
    - }
    - 
    --static int get_hub_id_for_app_instance(int id) {
    -+static int get_hub_id_for_app_instance(jint id) {
    -     int hubHandle = get_hub_handle_for_app_instance(id);
    - 
    -     if (hubHandle < 0) {
    -@@ -278,7 +315,7 @@ static int get_hub_id_for_app_instance(int id) {
    -     return db.hubInfo.hubs[hubHandle].hub_id;
    - }
    - 
    --static int get_app_instance_for_app_id(uint64_t app_id) {
    -+static jint get_app_instance_for_app_id(uint64_t app_id) {
    -     auto end = db.appInstances.end();
    -     for (auto current = db.appInstances.begin(); current != end; ++current) {
    -         if (current->second.appInfo.app_name.id == app_id) {
    -@@ -289,9 +326,10 @@ static int get_app_instance_for_app_id(uint64_t app_id) {
    -     return -1;
    - }
    - 
    --static int set_dest_app(hub_message_t *msg, int id) {
    -+static int set_dest_app(hub_message_t *msg, jint id) {
    -     if (!db.appInstances.count(id)) {
    --        ALOGD("%s: Cannot find app for app instance %d", __FUNCTION__, id);
    -+        ALOGD("%s: Cannot find app for app instance %" PRId32,
    -+              __FUNCTION__, id);
    -         return -1;
    -     }
    - 
    -@@ -299,11 +337,15 @@ static int set_dest_app(hub_message_t *msg, int id) {
    -     return 0;
    - }
    - 
    --static void query_hub_for_apps(uint64_t appId, uint32_t hubHandle) {
    -+static void query_hub_for_apps(uint32_t hubHandle) {
    -     hub_message_t msg;
    -     query_apps_request_t queryMsg;
    - 
    --    queryMsg.app_name.id = NANOAPP_VENDOR_ALL_APPS;
    -+    // TODO(b/30835598): When we're able to tell which request our
    -+    //     response matches, then we should allow this to be more
    -+    //     targetted, instead of always being every app in the
    -+    //     system.
    -+    queryMsg.app_name.id = ALL_APPS;
    - 
    -     msg.message_type = CONTEXT_HUB_QUERY_APPS;
    -     msg.message_len  = sizeof(queryMsg);
    -@@ -316,13 +358,13 @@ static void query_hub_for_apps(uint64_t appId, uint32_t hubHandle) {
    -     }
    - }
    - 
    --static void sendQueryForApps(uint64_t appId) {
    -+static void sendQueryForApps() {
    -     for (int i = 0; i < db.hubInfo.numHubs; i++ ) {
    --        query_hub_for_apps(appId, i);
    -+        query_hub_for_apps(i);
    -     }
    - }
    - 
    --static int return_id(int id) {
    -+static int return_id(jint id) {
    -     // Note : This method is not thread safe.
    -     // id returned is guaranteed to be in use
    -     if (id >= 0) {
    -@@ -333,9 +375,9 @@ static int return_id(int id) {
    -     return -1;
    - }
    - 
    --static int generate_id() {
    -+static jint generate_id() {
    -     // Note : This method is not thread safe.
    --    int retVal = -1;
    -+    jint retVal = -1;
    - 
    -     if (!db.freeIds.empty()) {
    -         retVal = db.freeIds.front();
    -@@ -346,23 +388,14 @@ static int generate_id() {
    - }
    - 
    - 
    --static int add_app_instance(const hub_app_info *appInfo, uint32_t hubHandle,
    --        int appInstanceHandle, JNIEnv *env) {
    --
    --    ALOGI("Loading App");
    --
    -+static jint add_app_instance(const hub_app_info *appInfo, uint32_t hubHandle,
    -+        jint appInstanceHandle, JNIEnv *env) {
    -     // Not checking if the apps are indeed distinct
    -     app_instance_info_s entry;
    -     assert(appInfo);
    - 
    --    if (db.appInstances.count(appInstanceHandle) == 0) {
    --        appInstanceHandle = generate_id();
    --        if (appInstanceHandle < 0) {
    --            ALOGE("Cannot find resources to add app instance %d",
    --                  appInstanceHandle);
    --            return -1;
    --        }
    --    }
    -+    const char *action =
    -+        (db.appInstances.count(appInstanceHandle) == 0) ? "Added" : "Updated";
    - 
    -     entry.appInfo = *appInfo;
    - 
    -@@ -372,42 +405,49 @@ static int add_app_instance(const hub_app_info *appInfo, uint32_t hubHandle,
    - 
    -     db.appInstances[appInstanceHandle] = entry;
    - 
    --    // Finally - let the service know of this app instance
    -+    // Finally - let the service know of this app instance, to populate
    -+    // the Java cache.
    -     env->CallIntMethod(db.jniInfo.jContextHubService,
    -                        db.jniInfo.contextHubServiceAddAppInstance,
    -                        hubHandle, entry.instanceId, entry.truncName,
    -                        entry.appInfo.version);
    - 
    --    ALOGW("Added App 0x%" PRIx64 " on hub Handle %" PRId32
    --          " as appInstance %d", entry.truncName,
    -+    ALOGI("%s App 0x%" PRIx64 " on hub Handle %" PRId32
    -+          " as appInstance %" PRId32, action, entry.truncName,
    -           entry.hubHandle, appInstanceHandle);
    - 
    -     return appInstanceHandle;
    - }
    - 
    --int delete_app_instance(int id, JNIEnv *env) {
    --    if (!db.appInstances.count(id)) {
    --        ALOGW("Cannot find App id : %d", id);
    --        return -1;
    --    }
    -+int delete_app_instance(jint id, JNIEnv *env) {
    -+    bool fullyDeleted = true;
    - 
    -+    if (db.appInstances.count(id)) {
    -+        db.appInstances.erase(id);
    -+    } else {
    -+        ALOGW("Cannot delete App id (%" PRId32 ") from the JNI C++ cache", id);
    -+        fullyDeleted = false;
    -+    }
    -     return_id(id);
    --    db.appInstances.erase(id);
    --    if (env->CallIntMethod(db.jniInfo.jContextHubService,
    -+
    -+    if ((env == nullptr) ||
    -+        (env->CallIntMethod(db.jniInfo.jContextHubService,
    -                        db.jniInfo.contextHubServiceDeleteAppInstance,
    --                       id) != 0) {
    --        ALOGW("Could not delete App id : %d", id);
    --        return -1;
    -+                       id) != 0)) {
    -+        ALOGW("Cannot delete App id (%" PRId32 ") from Java cache", id);
    -+        fullyDeleted = false;
    -     }
    - 
    --    ALOGI("Deleted App id : %d", id);
    --
    --    return 0;
    -+    if (fullyDeleted) {
    -+        ALOGI("Deleted App id : %" PRId32, id);
    -+        return 0;
    -+    }
    -+    return -1;
    - }
    - 
    - static int startLoadAppTxn(uint64_t appId, int hubHandle) {
    -     app_instance_info_s *txnInfo = (app_instance_info_s *)malloc(sizeof(app_instance_info_s));
    --    int instanceId = generate_id();
    -+    jint instanceId = generate_id();
    - 
    -     if (!txnInfo || instanceId < 0) {
    -         return_id(instanceId);
    -@@ -432,8 +472,8 @@ static int startLoadAppTxn(uint64_t appId, int hubHandle) {
    -     return 0;
    - }
    - 
    --static int startUnloadAppTxn(uint32_t appInstanceHandle) {
    --    uint32_t *txnData = (uint32_t *) malloc(sizeof(uint32_t));
    -+static int startUnloadAppTxn(jint appInstanceHandle) {
    -+    jint *txnData = (jint *) malloc(sizeof(jint));
    -     if (!txnData) {
    -         ALOGW("Cannot allocate memory to start unload transaction");
    -         return -1;
    -@@ -454,7 +494,6 @@ static void initContextHubService() {
    -     int err = 0;
    -     db.hubInfo.hubs = nullptr;
    -     db.hubInfo.numHubs = 0;
    --    int i;
    - 
    -     err = hw_get_module(CONTEXT_HUB_MODULE_ID,
    -                         (hw_module_t const**)(&db.hubInfo.contextHubModule));
    -@@ -465,7 +504,7 @@ static void initContextHubService() {
    -     }
    - 
    -     // Prep for storing app info
    --    for(i = MIN_APP_ID; i <= MAX_APP_ID; i++) {
    -+    for (jint i = MIN_APP_ID; i <= MAX_APP_ID; i++) {
    -         db.freeIds.push(i);
    -     }
    - 
    -@@ -485,7 +524,7 @@ static void initContextHubService() {
    -                 return;
    -             }
    - 
    --            for (i = 0; i < db.hubInfo.numHubs; i++) {
    -+            for (int i = 0; i < db.hubInfo.numHubs; i++) {
    -                 db.hubInfo.cookies[i] = db.hubInfo.hubs[i].hub_id;
    -                 ALOGI("Subscribing to hubHandle %d with OS App name %" PRIu64, i, db.hubInfo.hubs[i].os_app_name.id);
    -                 if (db.hubInfo.contextHubModule->subscribe_messages(db.hubInfo.hubs[i].hub_id,
    -@@ -495,7 +534,7 @@ static void initContextHubService() {
    -             }
    -         }
    - 
    --        sendQueryForApps(ALL_APPS);
    -+        sendQueryForApps();
    -     } else {
    -         ALOGW("No Context Hub Module present");
    -     }
    -@@ -539,21 +578,70 @@ int handle_query_apps_response(const uint8_t *msg, int msgLen,
    -             return -1;
    -     }
    - 
    --    int numApps = msgLen/sizeof(hub_app_info);
    --    hub_app_info info;
    -+    int numApps = msgLen / sizeof(hub_app_info);
    -     const hub_app_info *unalignedInfoAddr = (const hub_app_info*)msg;
    - 
    --    for (int i = 0; i < numApps; i++, unalignedInfoAddr++) {
    --        memcpy(&info, unalignedInfoAddr, sizeof(info));
    -+    // We use this information to sync our JNI and Java caches of nanoapp info.
    -+    // We want to accomplish two things here:
    -+    // 1) Remove entries from our caches which are stale, and pertained to
    -+    //    apps no longer running on Context Hub.
    -+    // 2) Populate our caches with the latest information of all these apps.
    -+
    -+    // We make a couple of assumptions here:
    -+    // A) The JNI and Java caches are in sync with each other (this isn't
    -+    //    necessarily true; any failure of a single call into Java land to
    -+    //    update its cache will leave that cache in a bad state.  For NYC,
    -+    //    we're willing to tolerate this for now).
    -+    // B) The total number of apps is relatively small, so horribly inefficent
    -+    //    algorithms aren't too painful.
    -+    // C) We're going to call this relatively infrequently, so its inefficency
    -+    //    isn't a big impact.
    -+
    -+
    -+    // (1).  Looking for stale cache entries.  Yes, this is O(N^2).  See
    -+    // assumption (B).  Per assumption (A), it is sufficient to iterate
    -+    // over just the JNI cache.
    -+    auto end = db.appInstances.end();
    -+    for (auto current = db.appInstances.begin(); current != end; ) {
    -+        app_instance_info_s cache_entry = current->second;
    -+        // We perform our iteration here because if we call
    -+        // delete_app_instance() below, it will erase() this entry.
    -+        current++;
    -+        bool entryIsStale = true;
    -+        for (int i = 0; i < numApps; i++) {
    -+            // We use memcmp since this could be unaligned.
    -+            if (memcmp(&unalignedInfoAddr[i].app_name.id,
    -+                       &cache_entry.appInfo.app_name.id,
    -+                       sizeof(cache_entry.appInfo.app_name.id)) == 0) {
    -+                // We found a match; this entry is current.
    -+                entryIsStale = false;
    -+                break;
    -+            }
    -+        }
    -+        if (entryIsStale) {
    -+            delete_app_instance(cache_entry.instanceId, env);
    -+        }
    -+    }
    -+
    -+    // (2).  Update our caches with the latest.
    -+    for (int i = 0; i < numApps; i++) {
    -+        hub_app_info query_info;
    -+        memcpy(&query_info, &unalignedInfoAddr[i], sizeof(query_info));
    -         // We will only have one instance of the app
    -         // TODO : Change this logic once we support multiple instances of the same app
    --        int appInstance = get_app_instance_for_app_id(info.app_name.id);
    --        add_app_instance(&info, hubHandle, appInstance, env);
    -+        jint appInstance = get_app_instance_for_app_id(query_info.app_name.id);
    -+        if (appInstance == -1) {
    -+            // This is a previously unknown app, let's allocate an "id" for it.
    -+            appInstance = generate_id();
    -+        }
    -+        add_app_instance(&query_info, hubHandle, appInstance, env);
    -     }
    - 
    -     return 0;
    - }
    - 
    -+// TODO(b/30807327): Do not use raw bytes for additional data.  Use the
    -+//     JNI interfaces for the appropriate types.
    - static void passOnOsResponse(uint32_t hubHandle, uint32_t msgType,
    -                              status_response_t *rsp, int8_t *additionalData,
    -                              size_t additionalDataLen) {
    -@@ -584,7 +672,32 @@ static void passOnOsResponse(uint32_t hubHandle, uint32_t msgType,
    -     header[HEADER_FIELD_HUB_HANDLE] = hubHandle;
    -     header[HEADER_FIELD_APP_INSTANCE] = OS_APP_ID;
    - 
    --    msg[0] = rsp->result;
    -+    // Due to API constraints, at the moment we can't change the fact that
    -+    // we're changing our 4-byte response to a 1-byte value.  But we can prevent
    -+    // the possible change in sign (and thus meaning) that would happen from
    -+    // a naive cast.  Further, we can log when we're losing part of the value.
    -+    // TODO(b/30918279): Don't truncate this result.
    -+    int8_t truncatedResult;
    -+    bool neededToTruncate;
    -+    if (rsp->result < INT8_MIN) {
    -+        neededToTruncate = true;
    -+        truncatedResult = INT8_MIN;
    -+    } else if (rsp->result > INT8_MAX) {
    -+        neededToTruncate = true;
    -+        truncatedResult = INT8_MAX;
    -+    } else {
    -+        neededToTruncate = false;
    -+        // Since this value fits within an int8_t, this is a safe cast which
    -+        // won't change the value or sign.
    -+        truncatedResult = static_cast<int8_t>(rsp->result);
    -+    }
    -+    if (neededToTruncate) {
    -+        ALOGW("Response from Context Hub truncated.  Value was %" PRId32
    -+              ", but giving Java layer %" PRId8,
    -+              rsp->result, (int)truncatedResult);
    -+    }
    -+
    -+    msg[0] = truncatedResult;
    - 
    -     if (additionalData) {
    -         memcpy(&msg[1], additionalData, additionalDataLen);
    -@@ -603,6 +716,8 @@ static void passOnOsResponse(uint32_t hubHandle, uint32_t msgType,
    -     env->CallIntMethod(db.jniInfo.jContextHubService,
    -                        db.jniInfo.contextHubServiceMsgReceiptCallback,
    -                        jheader, jmsg);
    -+    env->DeleteLocalRef(jmsg);
    -+    env->DeleteLocalRef(jheader);
    - 
    -     delete[] msg;
    - }
    -@@ -613,7 +728,13 @@ void closeUnloadTxn(bool success) {
    - 
    -     if (success && fetchTxnData(&txnId, &txnData) == 0 &&
    -         txnId == CONTEXT_HUB_UNLOAD_APP) {
    --        db.appInstances.erase(*(uint32_t *)txnData);
    -+        JNIEnv *env;
    -+        if ((db.jniInfo.vm)->AttachCurrentThread(&env, nullptr) != JNI_OK) {
    -+            ALOGW("Could not attach to JVM !");
    -+            env = nullptr;
    -+        }
    -+        jint handle = *reinterpret_cast<jint *>(txnData);
    -+        delete_app_instance(handle, env);
    -     } else {
    -         ALOGW("Could not unload the app successfully ! success %d, txnData %p", success, txnData);
    -     }
    -@@ -621,7 +742,7 @@ void closeUnloadTxn(bool success) {
    -     closeTxn();
    - }
    - 
    --void closeLoadTxn(bool success, int *appInstanceHandle) {
    -+static bool closeLoadTxn(bool success, jint *appInstanceHandle) {
    -     void *txnData;
    -     hub_messages_e txnId;
    - 
    -@@ -635,13 +756,22 @@ void closeLoadTxn(bool success, int *appInstanceHandle) {
    -             add_app_instance(&info->appInfo, info->hubHandle, info->instanceId, env);
    -         } else {
    -             ALOGW("Could not attach to JVM !");
    -+            success = false;
    -         }
    --        sendQueryForApps(info->appInfo.app_name.id);
    -+        // While we just called add_app_instance above, our info->appInfo was
    -+        // incomplete (for example, the 'version' is hardcoded to -1).  So we
    -+        // trigger an additional query to the CHRE, so we'll be able to get
    -+        // all the app "info", and have our JNI and Java caches with the
    -+        // full information.
    -+        sendQueryForApps();
    -     } else {
    -         ALOGW("Could not load the app successfully ! Unexpected failure");
    -+        *appInstanceHandle = INVALID_APP_ID;
    -+        success = false;
    -     }
    - 
    -     closeTxn();
    -+    return success;
    - }
    - 
    - static bool isValidOsStatus(const uint8_t *msg, size_t msgLen,
    -@@ -663,23 +793,6 @@ static bool isValidOsStatus(const uint8_t *msg, size_t msgLen,
    -     return true;
    - }
    - 
    --static void invalidateNanoApps(uint32_t hubHandle) {
    --    JNIEnv *env;
    --
    --    if ((db.jniInfo.vm)->AttachCurrentThread(&env, nullptr) != JNI_OK) {
    --        ALOGW("Could not attach to JVM !");
    --    }
    --
    --    auto end = db.appInstances.end();
    --    for (auto current = db.appInstances.begin(); current != end; ) {
    --        app_instance_info_s info = current->second;
    --        current++;
    --        if (info.hubHandle == hubHandle) {
    --             delete_app_instance(info.instanceId, env);
    --        }
    --    }
    --}
    --
    - static int handle_os_message(uint32_t msgType, uint32_t hubHandle,
    -                              const uint8_t *msg, int msgLen) {
    -     int retVal = -1;
    -@@ -697,8 +810,27 @@ static int handle_os_message(uint32_t msgType, uint32_t hubHandle,
    -       case CONTEXT_HUB_UNLOAD_APP:
    -           if (isValidOsStatus(msg, msgLen, &rsp)) {
    -               if (msgType == CONTEXT_HUB_LOAD_APP) {
    --                  int appInstanceHandle;
    --                  closeLoadTxn(rsp.result == 0, &appInstanceHandle);
    -+                  jint appInstanceHandle = INVALID_APP_ID;
    -+                  bool appRunningOnHub = (rsp.result == 0);
    -+                  if (!(closeLoadTxn(appRunningOnHub, &appInstanceHandle))) {
    -+                      if (appRunningOnHub) {
    -+                          // Now we're in an odd situation.  Our nanoapp
    -+                          // is up and running on the Context Hub.  However,
    -+                          // something went wrong in our Service code so that
    -+                          // we're not able to properly track this nanoapp
    -+                          // in our Service code.  If we tell the Java layer
    -+                          // things are good, it's a lie because the handle
    -+                          // we give them will fail when used with the Service.
    -+                          // If we tell the Java layer this failed, it's kind
    -+                          // of a lie as well, since this nanoapp is running.
    -+                          //
    -+                          // We leave a more robust fix for later, and for
    -+                          // now just tell the user things have failed.
    -+                          //
    -+                          // TODO(b/30835981): Make this situation better.
    -+                          rsp.result = -1;
    -+                      }
    -+                  }
    -                   passOnOsResponse(hubHandle, msgType, &rsp, (int8_t *)(&appInstanceHandle),
    -                                    sizeof(appInstanceHandle));
    -               } else if (msgType == CONTEXT_HUB_UNLOAD_APP) {
    -@@ -728,8 +860,7 @@ static int handle_os_message(uint32_t msgType, uint32_t hubHandle,
    -               ALOGW("Context Hub handle %d restarted", hubHandle);
    -               closeTxn();
    -               passOnOsResponse(hubHandle, msgType, &rsp, nullptr, 0);
    --              invalidateNanoApps(hubHandle);
    --              query_hub_for_apps(ALL_APPS, hubHandle);
    -+              query_hub_for_apps(hubHandle);
    -               retVal = 0;
    -           }
    -           break;
    -@@ -778,7 +909,7 @@ int context_hub_callback(uint32_t hubId,
    -     if (messageType < CONTEXT_HUB_TYPE_PRIVATE_MSG_BASE) {
    -         handle_os_message(messageType, hubHandle, (uint8_t*) msg->message, msg->message_len);
    -     } else {
    --        int appHandle = get_app_instance_for_app_id(msg->app_name.id);
    -+        jint appHandle = get_app_instance_for_app_id(msg->app_name.id);
    -         if (appHandle < 0) {
    -             ALOGE("Filtering out message due to invalid App Instance.");
    -         } else {
    -@@ -1051,7 +1182,8 @@ static jint nativeSendMessage(JNIEnv *env, jobject instance, jintArray header_,
    -         ALOGD("Asking HAL to remove app");
    -         retVal = db.hubInfo.contextHubModule->send_message(hubId, &msg);
    -     } else {
    --      ALOGD("Could not find app instance %d on hubHandle %d, setAddress %d",
    -+      ALOGD("Could not find app instance %" PRId32 " on hubHandle %" PRId32
    -+            ", setAddress %d",
    -             header[HEADER_FIELD_APP_INSTANCE],
    -             header[HEADER_FIELD_HUB_HANDLE],
    -             (int)setAddressSuccess);
    -@@ -1060,7 +1192,8 @@ static jint nativeSendMessage(JNIEnv *env, jobject instance, jintArray header_,
    -     if (retVal != 0) {
    -         ALOGD("Send Message failure - %d", retVal);
    -         if (msgType == CONTEXT_HUB_LOAD_APP) {
    --            closeLoadTxn(false, nullptr);
    -+            jint ignored;
    -+            closeLoadTxn(false, &ignored);
    -         } else if (msgType == CONTEXT_HUB_UNLOAD_APP) {
    -             closeUnloadTxn(false);
    -         }
    -diff --git a/core/jni/android_view_RenderNode.cpp b/core/jni/android_view_RenderNode.cpp
    -index b0028e1..1bad5f8 100644
    ---- a/core/jni/android_view_RenderNode.cpp
    -+++ b/core/jni/android_view_RenderNode.cpp
    -@@ -721,9 +721,9 @@ static const JNINativeMethod gMethods[] = {
    - int register_android_view_RenderNode(JNIEnv* env) {
    -     jclass clazz = FindClassOrDie(env, "android/view/SurfaceView");
    -     gSurfaceViewPositionUpdateMethod = GetMethodIDOrDie(env, clazz,
    --            "updateWindowPositionRT", "(JIIII)V");
    -+            "updateWindowPosition_renderWorker", "(JIIII)V");
    -     gSurfaceViewPositionLostMethod = GetMethodIDOrDie(env, clazz,
    --            "windowPositionLostRT", "(J)V");
    -+            "windowPositionLost_uiRtSync", "(J)V");
    -     clazz = FindClassOrDie(env, "android/view/RenderNode");
    -     gOnRenderNodeDetached = GetMethodIDOrDie(env, clazz,
    -             "onRenderNodeDetached", "()V");
    -diff --git a/core/jni/android_view_Surface.cpp b/core/jni/android_view_Surface.cpp
    -index 21e4d2f..a0c62c3 100644
    ---- a/core/jni/android_view_Surface.cpp
    -+++ b/core/jni/android_view_Surface.cpp
    -@@ -487,6 +487,11 @@ static jint nativeSetScalingMode(JNIEnv *env, jclass clazz, jlong nativeObject,
    -     return surface->setScalingMode(scalingMode);
    - }
    - 
    -+static jint nativeForceScopedDisconnect(JNIEnv *env, jclass clazz, jlong nativeObject) {
    -+    Surface* surface = reinterpret_cast<Surface*>(nativeObject);
    -+    return surface->disconnect(-1, IGraphicBufferProducer::DisconnectMode::AllLocal);
    -+}
    -+
    - namespace uirenderer {
    - 
    - using namespace android::uirenderer::renderthread;
    -@@ -564,6 +569,7 @@ static const JNINativeMethod gSurfaceMethods[] = {
    -     {"nativeGetHeight", "(J)I", (void*)nativeGetHeight },
    -     {"nativeGetNextFrameNumber", "(J)J", (void*)nativeGetNextFrameNumber },
    -     {"nativeSetScalingMode", "(JI)I", (void*)nativeSetScalingMode },
    -+    {"nativeForceScopedDisconnect", "(J)I", (void*)nativeForceScopedDisconnect},
    - 
    -     // HWUI context
    -     {"nHwuiCreate", "(JJ)J", (void*) hwui::create },
    -diff --git a/core/jni/android_view_SurfaceControl.cpp b/core/jni/android_view_SurfaceControl.cpp
    -index 0d8a95c..73b3f52 100644
    ---- a/core/jni/android_view_SurfaceControl.cpp
    -+++ b/core/jni/android_view_SurfaceControl.cpp
    -@@ -371,7 +371,12 @@ static void nativeSetDisplaySurface(JNIEnv* env, jclass clazz,
    -     if (sur != NULL) {
    -         bufferProducer = sur->getIGraphicBufferProducer();
    -     }
    --    SurfaceComposerClient::setDisplaySurface(token, bufferProducer);
    -+    status_t err = SurfaceComposerClient::setDisplaySurface(token,
    -+            bufferProducer);
    -+    if (err != NO_ERROR) {
    -+        doThrowIAE(env, "Illegal Surface, could not enable async mode. Was this"
    -+                " Surface created with singleBufferMode?");
    -+    }
    - }
    - 
    - static void nativeSetDisplayLayerStack(JNIEnv* env, jclass clazz,
    -diff --git a/core/jni/fd_utils-inl.h b/core/jni/fd_utils-inl.h
    -index db56c32..c67662b 100644
    ---- a/core/jni/fd_utils-inl.h
    -+++ b/core/jni/fd_utils-inl.h
    -@@ -50,7 +50,6 @@ static const char* kPathWhitelist[] = {
    -   "/dev/null",
    -   "/dev/socket/zygote",
    -   "/dev/socket/zygote_secondary",
    --  "/system/etc/event-log-tags",
    -   "/sys/kernel/debug/tracing/trace_marker",
    -   "/system/framework/framework-res.apk",
    -   "/dev/urandom",
    -diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
    -index ed71fc2..430c6b6 100644
    ---- a/core/res/AndroidManifest.xml
    -+++ b/core/res/AndroidManifest.xml
    -@@ -149,6 +149,8 @@
    -     <protected-broadcast
    -         android:name="android.bluetooth.headset.action.VENDOR_SPECIFIC_HEADSET_EVENT" />
    -     <protected-broadcast
    -+        android:name="android.bluetooth.headset.action.HF_INDICATORS_VALUE_CHANGED" />
    -+    <protected-broadcast
    -         android:name="android.bluetooth.headsetclient.profile.action.CONNECTION_STATE_CHANGED" />
    -     <protected-broadcast
    -         android:name="android.bluetooth.headsetclient.profile.action.AUDIO_STATE_CHANGED" />
    -@@ -183,6 +185,7 @@
    -     <protected-broadcast
    -         android:name="android.bluetooth.pan.profile.action.CONNECTION_STATE_CHANGED" />
    -     <protected-broadcast android:name="android.bluetooth.pbap.intent.action.PBAP_STATE_CHANGED" />
    -+    <protected-broadcast android:name="android.bluetooth.sap.profile.action.CONNECTION_STATE_CHANGED" />
    -     <protected-broadcast android:name="android.btopp.intent.action.INCOMING_FILE_NOTIFICATION" />
    -     <protected-broadcast android:name="android.btopp.intent.action.USER_CONFIRMATION_TIMEOUT" />
    -     <protected-broadcast android:name="android.btopp.intent.action.LIST" />
    -@@ -199,6 +202,8 @@
    -     <protected-broadcast android:name="com.android.bluetooth.pbap.userconfirmtimeout" />
    -     <protected-broadcast android:name="com.android.bluetooth.pbap.authresponse" />
    -     <protected-broadcast android:name="com.android.bluetooth.pbap.authcancelled" />
    -+    <protected-broadcast android:name="com.android.bluetooth.sap.USER_CONFIRM_TIMEOUT" />
    -+    <protected-broadcast android:name="com.android.bluetooth.sap.action.DISCONNECT_ACTION" />
    - 
    -     <protected-broadcast android:name="android.hardware.display.action.WIFI_DISPLAY_STATUS_CHANGED" />
    - 
    -@@ -394,6 +399,8 @@
    - 
    -     <protected-broadcast android:name="android.bluetooth.adapter.action.BLE_STATE_CHANGED" />
    -     <protected-broadcast android:name="com.android.bluetooth.map.USER_CONFIRM_TIMEOUT" />
    -+    <protected-broadcast android:name="com.android.bluetooth.BluetoothMapContentObserver.action.MESSAGE_SENT" />
    -+    <protected-broadcast android:name="com.android.bluetooth.BluetoothMapContentObserver.action.MESSAGE_DELIVERY" />
    -     <protected-broadcast android:name="android.content.jobscheduler.JOB_DELAY_EXPIRED" />
    -     <protected-broadcast android:name="android.content.syncmanager.SYNC_ALARM" />
    -     <protected-broadcast android:name="android.media.INTERNAL_RINGER_MODE_CHANGED_ACTION" />
    -@@ -1308,6 +1315,7 @@
    -         android:protectionLevel="dangerous"
    -         android:description="@string/permdesc_getAccounts"
    -         android:label="@string/permlab_getAccounts" />
    -+    <uses-permission android:name="android.permission.GET_ACCOUNTS"/>
    - 
    -     <!-- @SystemApi Allows applications to call into AccountAuthenticators.
    -     <p>Not for use by third-party applications. -->
    -@@ -1628,7 +1636,7 @@
    - 
    -     <!-- @hide Allows an application to create, remove users and get the list of
    -          users on the device. Applications holding this permission can only create restricted,
    --         guest, managed, and ephemeral users. For creating other kind of users,
    -+         guest, managed, demo, and ephemeral users. For creating other kind of users,
    -          {@link android.Manifest.permission#MANAGE_USERS} is needed.
    -          This permission is not available to third party applications. -->
    -     <permission android:name="android.permission.CREATE_USERS"
    -@@ -3024,7 +3032,7 @@
    -     <!-- @SystemApi Allows access to MAC addresses of WiFi and Bluetooth peer devices.
    -         @hide -->
    -     <permission android:name="android.permission.PEERS_MAC_ADDRESS"
    --                android:protectionLevel="signature" />
    -+                android:protectionLevel="signature|setup" />
    - 
    -     <!-- Allows the Nfc stack to dispatch Nfc messages to applications. Applications
    -         can use this permission to ensure incoming Nfc messages are from the Nfc stack
    -@@ -3111,7 +3119,7 @@
    -                  android:killAfterRestore="false"
    -                  android:icon="@drawable/ic_launcher_android"
    -                  android:supportsRtl="true"
    --                 android:theme="@style/Theme.Material.Light.DarkActionBar"
    -+                 android:theme="@style/Theme.DeviceDefault.Light.DarkActionBar"
    -                  android:defaultToDeviceProtectedStorage="true"
    -                  android:directBootAware="true">
    -         <activity android:name="com.android.internal.app.ChooserActivity"
    -@@ -3148,7 +3156,7 @@
    -                 android:label="@string/managed_profile_label">
    -         </activity-alias>
    -         <activity android:name="com.android.internal.app.HeavyWeightSwitcherActivity"
    --                android:theme="@style/Theme.Material.Light.Dialog"
    -+                android:theme="@style/Theme.DeviceDefault.Light.Dialog"
    -                 android:label="@string/heavy_weight_switcher_title"
    -                 android:finishOnCloseSystemDialogs="true"
    -                 android:excludeFromRecents="true"
    -@@ -3181,7 +3189,7 @@
    -         <activity android:name="android.accounts.ChooseAccountActivity"
    -                 android:excludeFromRecents="true"
    -                 android:exported="true"
    --                android:theme="@style/Theme.Material.Light.Dialog"
    -+                android:theme="@style/Theme.DeviceDefault.Light.Dialog"
    -                 android:label="@string/choose_account_label"
    -                 android:process=":ui">
    -         </activity>
    -@@ -3189,14 +3197,14 @@
    -         <activity android:name="android.accounts.ChooseTypeAndAccountActivity"
    -                 android:excludeFromRecents="true"
    -                 android:exported="true"
    --                android:theme="@style/Theme.Material.Light.Dialog"
    -+                android:theme="@style/Theme.DeviceDefault.Light.Dialog"
    -                 android:label="@string/choose_account_label"
    -                 android:process=":ui">
    -         </activity>
    - 
    -         <activity android:name="android.accounts.ChooseAccountTypeActivity"
    -                 android:excludeFromRecents="true"
    --                android:theme="@style/Theme.Material.Light.Dialog"
    -+                android:theme="@style/Theme.DeviceDefault.Light.Dialog"
    -                 android:label="@string/choose_account_label"
    -                 android:process=":ui">
    -         </activity>
    -@@ -3204,19 +3212,19 @@
    -         <activity android:name="android.accounts.CantAddAccountActivity"
    -                 android:excludeFromRecents="true"
    -                 android:exported="true"
    --                android:theme="@style/Theme.Material.Light.Dialog.NoActionBar"
    -+                android:theme="@style/Theme.DeviceDefault.Light.Dialog.NoActionBar"
    -                 android:process=":ui">
    -         </activity>
    - 
    -         <activity android:name="android.accounts.GrantCredentialsPermissionActivity"
    -                 android:excludeFromRecents="true"
    -                 android:exported="true"
    --                android:theme="@style/Theme.Material.Light.DialogWhenLarge"
    -+                android:theme="@style/Theme.DeviceDefault.Light.DialogWhenLarge"
    -                 android:process=":ui">
    -         </activity>
    - 
    -         <activity android:name="android.content.SyncActivityTooManyDeletes"
    --               android:theme="@style/Theme.Material.Light.Dialog"
    -+               android:theme="@style/Theme.DeviceDefault.Light.Dialog"
    -                android:label="@string/sync_too_many_deletes"
    -                android:process=":ui">
    -         </activity>
    -@@ -3236,7 +3244,7 @@
    -         </activity>
    - 
    -         <activity android:name="com.android.internal.app.NetInitiatedActivity"
    --                android:theme="@style/Theme.Material.Light.Dialog.Alert"
    -+                android:theme="@style/Theme.DeviceDefault.Light.Dialog.Alert"
    -                 android:excludeFromRecents="true"
    -                 android:process=":ui">
    -         </activity>
    -@@ -3257,7 +3265,7 @@
    -         <activity android:name="com.android.internal.app.ConfirmUserCreationActivity"
    -                 android:excludeFromRecents="true"
    -                 android:process=":ui"
    --                android:theme="@style/Theme.Material.Light.Dialog.Alert">
    -+                android:theme="@style/Theme.DeviceDefault.Light.Dialog.Alert">
    -             <intent-filter android:priority="1000">
    -                 <action android:name="android.os.action.CREATE_USER" />
    -                 <category android:name="android.intent.category.DEFAULT" />
    -@@ -3265,7 +3273,7 @@
    -         </activity>
    - 
    -         <activity android:name="com.android.internal.app.UnlaunchableAppActivity"
    --                android:theme="@style/Theme.Material.Light.Dialog.Alert"
    -+                android:theme="@style/Theme.DeviceDefault.Light.Dialog.Alert"
    -                 android:excludeFromRecents="true"
    -                 android:process=":ui">
    -         </activity>
    -diff --git a/core/res/res/anim/dock_bottom_exit_keyguard.xml b/core/res/res/anim/dock_bottom_exit_keyguard.xml
    -new file mode 100644
    -index 0000000..4de3ce5
    ---- /dev/null
    -+++ b/core/res/res/anim/dock_bottom_exit_keyguard.xml
    -@@ -0,0 +1,22 @@
    -+<!--
    -+  ~ Copyright (C) 2016 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
    -+  -->
    -+
    -+<!-- Animation for when a dock window at the bottom of the screen is exiting while on Keyguard -->
    -+<set xmlns:android="http://schemas.android.com/apk/res/android"
    -+    android:interpolator="@android:interpolator/fast_out_linear_in">
    -+    <translate android:fromYDelta="0" android:toYDelta="100%"
    -+        android:duration="200"/>
    -+</set>
    -\ No newline at end of file
    -diff --git a/core/res/res/color/hint_foreground_material_dark.xml b/core/res/res/color/hint_foreground_material_dark.xml
    -index 77883d9..5cc9559 100644
    ---- a/core/res/res/color/hint_foreground_material_dark.xml
    -+++ b/core/res/res/color/hint_foreground_material_dark.xml
    -@@ -15,6 +15,10 @@
    - -->
    - 
    - <selector xmlns:android="http://schemas.android.com/apk/res/android">
    -+    <item android:state_enabled="true"
    -+          android:state_pressed="true"
    -+          android:alpha="@dimen/hint_pressed_alpha_material_dark"
    -+          android:color="@color/foreground_material_dark" />
    -     <item android:alpha="@dimen/hint_alpha_material_dark"
    -           android:color="@color/foreground_material_dark" />
    - </selector>
    -diff --git a/core/res/res/color/hint_foreground_material_light.xml b/core/res/res/color/hint_foreground_material_light.xml
    -index 99168fd..f7465e0 100644
    ---- a/core/res/res/color/hint_foreground_material_light.xml
    -+++ b/core/res/res/color/hint_foreground_material_light.xml
    -@@ -15,6 +15,10 @@
    - -->
    - 
    - <selector xmlns:android="http://schemas.android.com/apk/res/android">
    -+    <item android:state_enabled="true"
    -+          android:state_pressed="true"
    -+          android:alpha="@dimen/hint_pressed_alpha_material_light"
    -+          android:color="@color/foreground_material_light" />
    -     <item android:alpha="@dimen/hint_alpha_material_light"
    -           android:color="@color/foreground_material_light" />
    - </selector>
    -diff --git a/core/res/res/drawable-hdpi/vpn_connected.png b/core/res/res/drawable-hdpi/vpn_connected.png
    -index c3547e8..e05e76f 100644
    -Binary files a/core/res/res/drawable-hdpi/vpn_connected.png and b/core/res/res/drawable-hdpi/vpn_connected.png differ
    -diff --git a/core/res/res/drawable-hdpi/vpn_disconnected.png b/core/res/res/drawable-hdpi/vpn_disconnected.png
    -index 10a9065..3508984 100644
    -Binary files a/core/res/res/drawable-hdpi/vpn_disconnected.png and b/core/res/res/drawable-hdpi/vpn_disconnected.png differ
    -diff --git a/core/res/res/drawable-mdpi/vpn_connected.png b/core/res/res/drawable-mdpi/vpn_connected.png
    -index 7e167f8..f7ac2a1 100644
    -Binary files a/core/res/res/drawable-mdpi/vpn_connected.png and b/core/res/res/drawable-mdpi/vpn_connected.png differ
    -diff --git a/core/res/res/drawable-mdpi/vpn_disconnected.png b/core/res/res/drawable-mdpi/vpn_disconnected.png
    -index a08c42a..9db4199 100644
    -Binary files a/core/res/res/drawable-mdpi/vpn_disconnected.png and b/core/res/res/drawable-mdpi/vpn_disconnected.png differ
    -diff --git a/core/res/res/drawable-nodpi/vpn_connected.xml b/core/res/res/drawable-nodpi/vpn_connected.xml
    -new file mode 100644
    -index 0000000..22a4a6c
    ---- /dev/null
    -+++ b/core/res/res/drawable-nodpi/vpn_connected.xml
    -@@ -0,0 +1,24 @@
    -+<!--
    -+Copyright (C) 2016 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.
    -+-->
    -+<vector xmlns:android="http://schemas.android.com/apk/res/android"
    -+        android:width="48dp"
    -+        android:height="48dp"
    -+        android:viewportWidth="48.0"
    -+        android:viewportHeight="48.0">
    -+    <path
    -+        android:fillColor="#FF000000"
    -+        android:pathData="M25.3,20c-1.65,-4.66 -6.08,-8 -11.3,-8 -6.63,0 -12,5.37 -12,12s5.37,12 12,12c5.22,0 9.65,-3.34 11.3,-8H34v8h8v-8h4v-8H25.3zM14,28c-2.21,0 -4,-1.79 -4,-4s1.79,-4 4,-4 4,1.79 4,4 -1.79,4 -4,4z"/>
    -+</vector>
    -diff --git a/core/res/res/drawable-nodpi/vpn_disconnected.xml b/core/res/res/drawable-nodpi/vpn_disconnected.xml
    -new file mode 100644
    -index 0000000..22a4a6c
    ---- /dev/null
    -+++ b/core/res/res/drawable-nodpi/vpn_disconnected.xml
    -@@ -0,0 +1,24 @@
    -+<!--
    -+Copyright (C) 2016 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.
    -+-->
    -+<vector xmlns:android="http://schemas.android.com/apk/res/android"
    -+        android:width="48dp"
    -+        android:height="48dp"
    -+        android:viewportWidth="48.0"
    -+        android:viewportHeight="48.0">
    -+    <path
    -+        android:fillColor="#FF000000"
    -+        android:pathData="M25.3,20c-1.65,-4.66 -6.08,-8 -11.3,-8 -6.63,0 -12,5.37 -12,12s5.37,12 12,12c5.22,0 9.65,-3.34 11.3,-8H34v8h8v-8h4v-8H25.3zM14,28c-2.21,0 -4,-1.79 -4,-4s1.79,-4 4,-4 4,1.79 4,4 -1.79,4 -4,4z"/>
    -+</vector>
    -diff --git a/core/res/res/drawable-xhdpi/vpn_connected.png b/core/res/res/drawable-xhdpi/vpn_connected.png
    -index 1f46be2..a8761c9 100644
    -Binary files a/core/res/res/drawable-xhdpi/vpn_connected.png and b/core/res/res/drawable-xhdpi/vpn_connected.png differ
    -diff --git a/core/res/res/drawable-xhdpi/vpn_disconnected.png b/core/res/res/drawable-xhdpi/vpn_disconnected.png
    -index 847d3f5..7118918 100644
    -Binary files a/core/res/res/drawable-xhdpi/vpn_disconnected.png and b/core/res/res/drawable-xhdpi/vpn_disconnected.png differ
    -diff --git a/core/res/res/drawable-xxhdpi/vpn_connected.png b/core/res/res/drawable-xxhdpi/vpn_connected.png
    -index ea4930c..16b1e4e 100644
    -Binary files a/core/res/res/drawable-xxhdpi/vpn_connected.png and b/core/res/res/drawable-xxhdpi/vpn_connected.png differ
    -diff --git a/core/res/res/drawable-xxhdpi/vpn_disconnected.png b/core/res/res/drawable-xxhdpi/vpn_disconnected.png
    -index 4cd0dd4..a025818 100644
    -Binary files a/core/res/res/drawable-xxhdpi/vpn_disconnected.png and b/core/res/res/drawable-xxhdpi/vpn_disconnected.png differ
    -diff --git a/core/res/res/drawable/emergency_icon.xml b/core/res/res/drawable/emergency_icon.xml
    -new file mode 100644
    -index 0000000..b2ffa2b
    ---- /dev/null
    -+++ b/core/res/res/drawable/emergency_icon.xml
    -@@ -0,0 +1,40 @@
    -+<!--
    -+Copyright (C) 2014 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.
    -+-->
    -+<vector xmlns:android="http://schemas.android.com/apk/res/android"
    -+        android:width="24.0dp"
    -+        android:height="24.0dp"
    -+        android:viewportWidth="24.0"
    -+        android:viewportHeight="24.0"
    -+        android:tint="?attr/colorControlNormal">
    -+    <path
    -+        android:fillColor="#FF000000"
    -+        android:pathData="M6.8,17.3C5.3,15.9 4.5,14.0 4.5,12.0c0.0,-2.0 0.8,-3.8 2.1,-5.2l1.4,1.4c-1.0,1.0 -1.6,2.4 -1.6,3.8c0.0,1.5 0.6,2.9 1.6,3.9L6.8,17.3z"/>
    -+    <path
    -+        android:fillColor="#FF000000"
    -+        android:pathData="M3.3,20.2C1.2,18.0 0.0,15.1 0.0,12.0c0.0,-3.1 1.2,-6.0 3.3,-8.2l1.4,1.4C3.0,7.0 2.0,9.4 2.0,12.0s1.0,5.0 2.7,6.9L3.3,20.2z"/>
    -+    <path
    -+        android:fillColor="#FF000000"
    -+        android:pathData="M17.2,17.3l-1.4,-1.4c1.1,-1.0 1.6,-2.4 1.6,-3.9c0.0,-1.4 -0.6,-2.8 -1.6,-3.8l1.4,-1.4c1.4,1.4 2.1,3.3 2.1,5.2C19.5,14.0 18.7,15.9 17.2,17.3z"/>
    -+    <path
    -+        android:fillColor="#FF000000"
    -+        android:pathData="M20.7,20.2l-1.4,-1.4C21.0,17.0 22.0,14.6 22.0,12.0c0.0,-2.6 -1.0,-5.0 -2.7,-6.9l1.4,-1.4C22.8,6.0 24.0,8.9 24.0,12.0C24.0,15.1 22.8,18.0 20.7,20.2z"/>
    -+    <path
    -+        android:fillColor="#FF000000"
    -+        android:pathData="M11.0,15.0l2.0,0.0l0.0,2.0l-2.0,0.0z"/>
    -+    <path
    -+        android:fillColor="#FF000000"
    -+        android:pathData="M11.0,7.0l2.0,0.0l0.0,6.0l-2.0,0.0z"/>
    -+</vector>
    -diff --git a/core/res/res/drawable/ic_check_circle_24px.xml b/core/res/res/drawable/ic_check_circle_24px.xml
    -index 066a8a7..e9af9e4 100644
    ---- a/core/res/res/drawable/ic_check_circle_24px.xml
    -+++ b/core/res/res/drawable/ic_check_circle_24px.xml
    -@@ -19,9 +19,6 @@ Copyright (C) 2015 The Android Open Source Project
    -         android:viewportWidth="24.0"
    -         android:viewportHeight="24.0">
    -     <path
    --        android:pathData="M0 0h24v24H0z"
    --        android:fillColor="#00000000"/>
    --    <path
    -         android:fillColor="#FF000000"
    -         android:pathData="M12.0,2.0C6.48,2.0 2.0,6.48 2.0,12.0s4.48,10.0 10.0,10.0 10.0,-4.48 10.0,-10.0S17.52,2.0 12.0,2.0zm-2.0,15.0l-5.0,-5.0 1.41,-1.41L10.0,14.17l7.59,-7.59L19.0,8.0l-9.0,9.0z"/>
    - </vector>
    -diff --git a/core/res/res/drawable/ic_collapse_notification.xml b/core/res/res/drawable/ic_collapse_notification.xml
    -index 603c159..124e99e 100644
    ---- a/core/res/res/drawable/ic_collapse_notification.xml
    -+++ b/core/res/res/drawable/ic_collapse_notification.xml
    -@@ -22,7 +22,4 @@ Copyright (C) 2015 The Android Open Source Project
    -     <path
    -         android:fillColor="#FF000000"
    -         android:pathData="M12.0,8.0l-6.0,6.0l1.4,1.4l4.6,-4.6l4.6,4.6L18.0,14.0L12.0,8.0z"/>
    --    <path
    --        android:pathData="M0,0h24v24H0V0z"
    --        android:fillColor="#00000000"/>
    - </vector>
    -diff --git a/core/res/res/drawable/ic_expand_more_48dp.xml b/core/res/res/drawable/ic_expand_more_48dp.xml
    -index 11323e3..5a71669 100644
    ---- a/core/res/res/drawable/ic_expand_more_48dp.xml
    -+++ b/core/res/res/drawable/ic_expand_more_48dp.xml
    -@@ -21,7 +21,4 @@ Copyright (C) 2015 The Android Open Source Project
    -     <path
    -         android:fillColor="#FF000000"
    -         android:pathData="M33.17,17.17L24.0,26.34l-9.17,-9.17L12.0,20.0l12.0,12.0 12.0,-12.0z"/>
    --    <path
    --        android:pathData="M0 0h48v48H0z"
    --        android:fillColor="#00000000"/>
    - </vector>
    -diff --git a/core/res/res/drawable/ic_expand_notification.xml b/core/res/res/drawable/ic_expand_notification.xml
    -index db7d3eb..847e326 100644
    ---- a/core/res/res/drawable/ic_expand_notification.xml
    -+++ b/core/res/res/drawable/ic_expand_notification.xml
    -@@ -22,7 +22,4 @@ Copyright (C) 2015 The Android Open Source Project
    -     <path
    -         android:fillColor="#FF000000"
    -         android:pathData="M16.6,8.6L12.0,13.2L7.4,8.6L6.0,10.0l6.0,6.0l6.0,-6.0L16.6,8.6z"/>
    --    <path
    --        android:pathData="M0,0h24v24H0V0z"
    --        android:fillColor="#00000000"/>
    - </vector>
    -diff --git a/core/res/res/drawable/ic_feedback.xml b/core/res/res/drawable/ic_feedback.xml
    -index b2d1cb8..365863d 100644
    ---- a/core/res/res/drawable/ic_feedback.xml
    -+++ b/core/res/res/drawable/ic_feedback.xml
    -@@ -19,9 +19,6 @@ Copyright (C) 2016 The Android Open Source Project
    -         android:viewportWidth="24.0"
    -         android:viewportHeight="24.0">
    -     <path
    --        android:pathData="M0 0h24v24H0z"
    --        android:fillColor="#00000000"/>
    --    <path
    -         android:fillColor="#FF000000"
    -         android:pathData="M20.0,2.0L4.0,2.0c-1.1,0.0 -1.9,0.9 -1.99,2.0L2.0,22.0l4.0,-4.0l14.0,0.0c1.1,0.0 2.0,-0.9 2.0,-2.0L22.0,4.0c0.0,-1.1 -0.9,-2.0 -2.0,-2.0zm-7.0,12.0l-2.0,0.0l0.0,-2.0l2.0,0.0l0.0,2.0zm0.0,-4.0l-2.0,0.0L11.0,6.0l2.0,0.0l0.0,4.0z"/>
    - </vector>
    -diff --git a/core/res/res/drawable/ic_more_items.xml b/core/res/res/drawable/ic_more_items.xml
    -index 5fdcdce..0ec754c 100644
    ---- a/core/res/res/drawable/ic_more_items.xml
    -+++ b/core/res/res/drawable/ic_more_items.xml
    -@@ -24,6 +24,5 @@
    -         android:fillColor="#000000"
    -         android:pathData="M3 13h2v-2H3v2zm0 4h2v-2H3v2zm0-8h2V7H3v2zm4 4h14v-2H7v2zm0 4h14v-2H7v2zM7
    - 7v2h14V7H7z" />
    --    <path
    --        android:pathData="M0 0h24v24H0z" />
    -+
    - </vector>
    -\ No newline at end of file
    -diff --git a/core/res/res/drawable/ic_refresh.xml b/core/res/res/drawable/ic_refresh.xml
    -index 1f67168..1297407 100644
    ---- a/core/res/res/drawable/ic_refresh.xml
    -+++ b/core/res/res/drawable/ic_refresh.xml
    -@@ -21,7 +21,4 @@ Copyright (C) 2016 The Android Open Source Project
    -     <path
    -         android:fillColor="#FF000000"
    -         android:pathData="M17.65,6.35C16.2,4.9 14.21,4.0 12.0,4.0c-4.42,0.0 -7.99,3.58 -7.99,8.0s3.57,8.0 7.99,8.0c3.73,0.0 6.84,-2.55 7.73,-6.0l-2.08,0.0c-0.82,2.33 -3.04,4.0 -5.65,4.0 -3.31,0.0 -6.0,-2.69 -6.0,-6.0s2.69,-6.0 6.0,-6.0c1.66,0.0 3.1,0.69 4.22,1.78L13.0,11.0l7.0,0.0L20.0,4.0l-2.35,2.35z"/>
    --    <path
    --        android:pathData="M0 0h24v24H0z"
    --        android:fillColor="#00000000"/>
    - </vector>
    -diff --git a/core/res/res/drawable/ic_schedule.xml b/core/res/res/drawable/ic_schedule.xml
    -index 899dc82..55d54b1 100644
    ---- a/core/res/res/drawable/ic_schedule.xml
    -+++ b/core/res/res/drawable/ic_schedule.xml
    -@@ -22,9 +22,6 @@ Copyright (C) 2016 The Android Open Source Project
    -         android:fillColor="#FF000000"
    -         android:pathData="M11.99,2.0C6.47,2.0 2.0,6.48 2.0,12.0s4.47,10.0 9.99,10.0C17.52,22.0 22.0,17.52 22.0,12.0S17.52,2.0 11.99,2.0zM12.0,20.0c-4.42,0.0 -8.0,-3.58 -8.0,-8.0s3.58,-8.0 8.0,-8.0 8.0,3.58 8.0,8.0 -3.58,8.0 -8.0,8.0z"/>
    -     <path
    --        android:pathData="M0 0h24v24H0z"
    --        android:fillColor="#00000000"/>
    --    <path
    -         android:fillColor="#FF000000"
    -         android:pathData="M12.5,7.0L11.0,7.0l0.0,6.0l5.25,3.1 0.75,-1.23 -4.5,-2.67z"/>
    - </vector>
    -diff --git a/core/res/res/drawable/perm_group_calendar.xml b/core/res/res/drawable/perm_group_calendar.xml
    -index 4dc7b37..85a783e 100644
    ---- a/core/res/res/drawable/perm_group_calendar.xml
    -+++ b/core/res/res/drawable/perm_group_calendar.xml
    -@@ -24,6 +24,5 @@
    -         android:fillColor="#000000"
    -         android:pathData="M17 12h-5v5h5v-5zM16 1v2H8V1H6v2H5c-1.11 0-1.99 .9 -1.99 2L3 19c0 1.1 .89 2 2
    - 2h14c1.1 0 2-.9 2-2V5c0-1.1-.9-2-2-2h-1V1h-2zm3 18H5V8h14v11z" />
    --    <path
    --        android:pathData="M0 0h24v24H0z" />
    -+
    - </vector>
    -\ No newline at end of file
    -diff --git a/core/res/res/drawable/perm_group_camera.xml b/core/res/res/drawable/perm_group_camera.xml
    -index 741a40e..61903a5 100644
    ---- a/core/res/res/drawable/perm_group_camera.xml
    -+++ b/core/res/res/drawable/perm_group_camera.xml
    -@@ -28,6 +28,4 @@
    -         android:pathData="M9 2L7.17 4H4c-1.1 0-2 .9-2 2v12c0 1.1 .9 2 2 2h16c1.1 0 2-.9
    - 2-2V6c0-1.1-.9-2-2-2h-3.17L15 2H9zm3 15c-2.76 0-5-2.24-5-5s2.24-5 5-5 5 2.24 5
    - 5-2.24 5-5 5z" />
    --    <path
    --        android:pathData="M0 0h24v24H0z" />
    - </vector>
    -\ No newline at end of file
    -diff --git a/core/res/res/drawable/perm_group_contacts.xml b/core/res/res/drawable/perm_group_contacts.xml
    -index d698fd1..8f9dc3e 100644
    ---- a/core/res/res/drawable/perm_group_contacts.xml
    -+++ b/core/res/res/drawable/perm_group_contacts.xml
    -@@ -21,8 +21,6 @@
    -     android:viewportHeight="24">
    - 
    -     <path
    --        android:pathData="M0 0h24v24H0zm0 0h24v24H0zm0 0h24v24H0z" />
    --    <path
    -         android:fillColor="#000000"
    -         android:pathData="M20 0H4v2h16V0zM4 24h16v-2H4v2zM20 4H4c-1.1 0-2 .9-2 2v12c0 1.1 .9 2 2 2h16c1.1
    - 0 2-.9 2-2V6c0-1.1-.9-2-2-2zm-8 2.75c1.24 0 2.25 1.01 2.25 2.25s-1.01 2.25-2.25
    -diff --git a/core/res/res/drawable/perm_group_location.xml b/core/res/res/drawable/perm_group_location.xml
    -index fbc6066..cc1ec90 100644
    ---- a/core/res/res/drawable/perm_group_location.xml
    -+++ b/core/res/res/drawable/perm_group_location.xml
    -@@ -24,6 +24,4 @@
    -         android:fillColor="#000000"
    -         android:pathData="M12 2C8.13 2 5 5.13 5 9c0 5.25 7 13 7 13s7-7.75 7-13c0-3.87-3.13-7-7-7zm0
    - 9.5c-1.38 0-2.5-1.12-2.5-2.5s1.12-2.5 2.5-2.5 2.5 1.12 2.5 2.5-1.12 2.5-2.5 2.5z" />
    --    <path
    --        android:pathData="M0 0h24v24H0z" />
    - </vector>
    -\ No newline at end of file
    -diff --git a/core/res/res/drawable/perm_group_microphone.xml b/core/res/res/drawable/perm_group_microphone.xml
    -index c565d20..d494e67 100644
    ---- a/core/res/res/drawable/perm_group_microphone.xml
    -+++ b/core/res/res/drawable/perm_group_microphone.xml
    -@@ -25,6 +25,4 @@
    -         android:pathData="M12 14c1.66 0 2.99-1.34 2.99-3L15 5c0-1.66-1.34-3-3-3S9 3.34 9 5v6c0 1.66 1.34 3
    - 3 3zm5.3-3c0 3-2.54 5.1-5.3 5.1S6.7 14 6.7 11H5c0 3.41 2.72 6.23 6
    - 6.72V21h2v-3.28c3.28-.48 6-3.3 6-6.72h-1.7z" />
    --    <path
    --        android:pathData="M0 0h24v24H0z" />
    - </vector>
    -\ No newline at end of file
    -diff --git a/core/res/res/drawable/perm_group_phone_calls.xml b/core/res/res/drawable/perm_group_phone_calls.xml
    -index a647894..324d864 100644
    ---- a/core/res/res/drawable/perm_group_phone_calls.xml
    -+++ b/core/res/res/drawable/perm_group_phone_calls.xml
    -@@ -19,9 +19,6 @@
    -     android:height="24dp"
    -     android:viewportWidth="24"
    -     android:viewportHeight="24">
    --
    --    <path
    --        android:pathData="M0 0h24v24H0z" />
    -     <path
    -         android:fillColor="#000000"
    -         android:pathData="M6.62 10.79c1.44 2.83 3.76 5.14 6.59 6.59l2.2-2.2c.27-.27 .67 -.36 1.02-.24 1.12
    -diff --git a/core/res/res/drawable/perm_group_sms.xml b/core/res/res/drawable/perm_group_sms.xml
    -index 9b32c601..47bca19 100644
    ---- a/core/res/res/drawable/perm_group_sms.xml
    -+++ b/core/res/res/drawable/perm_group_sms.xml
    -@@ -24,6 +24,4 @@
    -         android:fillColor="#000000"
    -         android:pathData="M20 2H4c-1.1 0-1.99 .9 -1.99 2L2 22l4-4h14c1.1 0 2-.9 2-2V4c0-1.1-.9-2-2-2zM9
    - 11H7V9h2v2zm4 0h-2V9h2v2zm4 0h-2V9h2v2z" />
    --    <path
    --        android:pathData="M0 0h24v24H0z" />
    - </vector>
    -\ No newline at end of file
    -diff --git a/core/res/res/drawable/perm_group_storage.xml b/core/res/res/drawable/perm_group_storage.xml
    -index 477270d..1ff1693 100644
    ---- a/core/res/res/drawable/perm_group_storage.xml
    -+++ b/core/res/res/drawable/perm_group_storage.xml
    -@@ -24,6 +24,4 @@
    -         android:fillColor="#000000"
    -         android:pathData="M10 4H4c-1.1 0-1.99 .9 -1.99 2L2 18c0 1.1 .9 2 2 2h16c1.1 0 2-.9
    - 2-2V8c0-1.1-.9-2-2-2h-8l-2-2z" />
    --    <path
    --        android:pathData="M0 0h24v24H0z" />
    - </vector>
    -\ No newline at end of file
    -diff --git a/core/res/res/drawable/progress_indeterminate_anim_large_material.xml b/core/res/res/drawable/progress_indeterminate_anim_large_material.xml
    -new file mode 100644
    -index 0000000..560ec5a
    ---- /dev/null
    -+++ b/core/res/res/drawable/progress_indeterminate_anim_large_material.xml
    -@@ -0,0 +1,26 @@
    -+<?xml version="1.0" encoding="utf-8"?>
    -+<!-- Copyright (C) 2016 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.
    -+-->
    -+<animated-vector xmlns:android="http://schemas.android.com/apk/res/android"
    -+                 android:drawable="@drawable/vector_drawable_progress_bar_large" >
    -+    <target
    -+            android:name="progressBar"
    -+            android:animation="@anim/progress_indeterminate_material" />
    -+
    -+    <target
    -+            android:name="root"
    -+            android:animation="@anim/progress_indeterminate_rotation_material" />
    -+</animated-vector>
    -+
    -diff --git a/core/res/res/drawable/progress_indeterminate_anim_medium_material.xml b/core/res/res/drawable/progress_indeterminate_anim_medium_material.xml
    -new file mode 100644
    -index 0000000..fbea22f
    ---- /dev/null
    -+++ b/core/res/res/drawable/progress_indeterminate_anim_medium_material.xml
    -@@ -0,0 +1,27 @@
    -+<?xml version="1.0" encoding="utf-8"?>
    -+<!-- Copyright (C) 2016 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.
    -+-->
    -+<animated-vector xmlns:android="http://schemas.android.com/apk/res/android"
    -+    android:drawable="@drawable/vector_drawable_progress_bar_medium" >
    -+
    -+    <target
    -+        android:name="progressBar"
    -+        android:animation="@anim/progress_indeterminate_material" />
    -+
    -+    <target
    -+        android:name="root"
    -+        android:animation="@anim/progress_indeterminate_rotation_material" />
    -+
    -+</animated-vector>
    -\ No newline at end of file
    -diff --git a/core/res/res/drawable/progress_large_material.xml b/core/res/res/drawable/progress_large_material.xml
    -index 526f914..ee82e35 100644
    ---- a/core/res/res/drawable/progress_large_material.xml
    -+++ b/core/res/res/drawable/progress_large_material.xml
    -@@ -13,16 +13,8 @@
    -      See the License for the specific language governing permissions and
    -      limitations under the License.
    - -->
    --
    --<animated-vector xmlns:android="http://schemas.android.com/apk/res/android"
    --    android:drawable="@drawable/vector_drawable_progress_bar_large" >
    --
    --    <target
    --        android:name="progressBar"
    --        android:animation="@anim/progress_indeterminate_material" />
    --
    --    <target
    --        android:name="root"
    --        android:animation="@anim/progress_indeterminate_rotation_material" />
    --
    --</animated-vector>
    -+<com.android.internal.graphics.drawable.AnimationScaleListDrawable
    -+        xmlns:android="http://schemas.android.com/apk/res/android">
    -+    <item android:drawable="@drawable/progress_static_material" />
    -+    <item android:drawable="@drawable/progress_indeterminate_anim_large_material" />
    -+</com.android.internal.graphics.drawable.AnimationScaleListDrawable>
    -diff --git a/core/res/res/drawable/progress_medium_material.xml b/core/res/res/drawable/progress_medium_material.xml
    -index cc35816..5c92600 100644
    ---- a/core/res/res/drawable/progress_medium_material.xml
    -+++ b/core/res/res/drawable/progress_medium_material.xml
    -@@ -13,15 +13,8 @@
    -      See the License for the specific language governing permissions and
    -      limitations under the License.
    - -->
    --<animated-vector xmlns:android="http://schemas.android.com/apk/res/android"
    --    android:drawable="@drawable/vector_drawable_progress_bar_medium" >
    --
    --    <target
    --        android:name="progressBar"
    --        android:animation="@anim/progress_indeterminate_material" />
    --
    --    <target
    --        android:name="root"
    --        android:animation="@anim/progress_indeterminate_rotation_material" />
    --
    --</animated-vector>
    -\ No newline at end of file
    -+<com.android.internal.graphics.drawable.AnimationScaleListDrawable
    -+        xmlns:android="http://schemas.android.com/apk/res/android">
    -+    <item android:drawable="@drawable/progress_static_material" />
    -+    <item android:drawable="@drawable/progress_indeterminate_anim_medium_material" />
    -+</com.android.internal.graphics.drawable.AnimationScaleListDrawable>
    -diff --git a/core/res/res/drawable/progress_small_material.xml b/core/res/res/drawable/progress_small_material.xml
    -index c6e4380..cec9d95 100644
    ---- a/core/res/res/drawable/progress_small_material.xml
    -+++ b/core/res/res/drawable/progress_small_material.xml
    -@@ -13,16 +13,17 @@
    -      See the License for the specific language governing permissions and
    -      limitations under the License.
    - -->
    --
    --<animated-vector xmlns:android="http://schemas.android.com/apk/res/android"
    --    android:drawable="@drawable/vector_drawable_progress_bar_small" >
    --
    --    <target
    --        android:name="progressBar"
    --        android:animation="@anim/progress_indeterminate_material" />
    --
    --    <target
    --        android:name="root"
    --        android:animation="@anim/progress_indeterminate_rotation_material" />
    --
    --</animated-vector>
    -+<com.android.internal.graphics.drawable.AnimationScaleListDrawable
    -+        xmlns:android="http://schemas.android.com/apk/res/android">
    -+    <item android:drawable="@drawable/progress_static_material" />
    -+    <item>
    -+        <animated-vector android:drawable="@drawable/vector_drawable_progress_bar_small" >
    -+            <target
    -+                    android:name="progressBar"
    -+                    android:animation="@anim/progress_indeterminate_material" />
    -+            <target
    -+                    android:name="root"
    -+                    android:animation="@anim/progress_indeterminate_rotation_material" />
    -+        </animated-vector>
    -+    </item>
    -+</com.android.internal.graphics.drawable.AnimationScaleListDrawable>
    -diff --git a/core/res/res/drawable/progress_static_material.xml b/core/res/res/drawable/progress_static_material.xml
    -new file mode 100644
    -index 0000000..b078fa9
    ---- /dev/null
    -+++ b/core/res/res/drawable/progress_static_material.xml
    -@@ -0,0 +1,25 @@
    -+<!--
    -+Copyright (C) 2016 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.
    -+-->
    -+<vector xmlns:android="http://schemas.android.com/apk/res/android"
    -+        android:width="24.0dp"
    -+        android:height="24.0dp"
    -+        android:viewportWidth="24.0"
    -+        android:viewportHeight="24.0"
    -+        >
    -+    <path
    -+        android:fillColor="?attr/colorControlActivated"
    -+        android:pathData="M17.65,6.35C16.2,4.9 14.21,4.0 12.0,4.0c-4.42,0.0 -7.99,3.58 -7.99,8.0s3.57,8.0 7.99,8.0c3.73,0.0 6.84,-2.55 7.73,-6.0l-2.08,0.0c-0.82,2.33 -3.04,4.0 -5.65,4.0 -3.31,0.0 -6.0,-2.69 -6.0,-6.0s2.69,-6.0 6.0,-6.0c1.66,0.0 3.1,0.69 4.22,1.78L13.0,11.0l7.0,0.0L20.0,4.0l-2.35,2.35z"/>
    -+</vector>
    -diff --git a/core/res/res/layout-sw600dp/date_picker_dialog.xml b/core/res/res/layout-sw600dp/date_picker_dialog.xml
    -index 5e3ca14..cd6af46 100644
    ---- a/core/res/res/layout-sw600dp/date_picker_dialog.xml
    -+++ b/core/res/res/layout-sw600dp/date_picker_dialog.xml
    -@@ -22,4 +22,4 @@
    -     android:layout_height="wrap_content"
    -     android:spinnersShown="true"
    -     android:calendarViewShown="true"
    --    android:datePickerMode="@integer/date_picker_mode" />
    -+    android:dialogMode="true" />
    -diff --git a/core/res/res/layout/date_picker_dialog.xml b/core/res/res/layout/date_picker_dialog.xml
    -index 8f36e95..32a7360 100644
    ---- a/core/res/res/layout/date_picker_dialog.xml
    -+++ b/core/res/res/layout/date_picker_dialog.xml
    -@@ -22,4 +22,4 @@
    -     android:layout_height="wrap_content"
    -     android:spinnersShown="true"
    -     android:calendarViewShown="false"
    --    android:datePickerMode="@integer/date_picker_mode" />
    -+    android:dialogMode="true" />
    -diff --git a/core/res/res/layout/time_picker_dialog.xml b/core/res/res/layout/time_picker_dialog.xml
    -index d1f3902..ada18d1 100644
    ---- a/core/res/res/layout/time_picker_dialog.xml
    -+++ b/core/res/res/layout/time_picker_dialog.xml
    -@@ -22,4 +22,4 @@
    -     android:layout_gravity="center_horizontal"
    -     android:layout_width="wrap_content"
    -     android:layout_height="wrap_content"
    --    android:timePickerMode="@integer/time_picker_mode" />
    -+    android:dialogMode="true" />
    -diff --git a/core/res/res/values-af/strings.xml b/core/res/res/values-af/strings.xml
    -index bd92ab6..4b59f21 100644
    ---- a/core/res/res/values-af/strings.xml
    -+++ b/core/res/res/values-af/strings.xml
    -@@ -214,6 +214,7 @@
    -     <string name="global_actions" product="default" msgid="2406416831541615258">"Foonopsies"</string>
    -     <string name="global_action_lock" msgid="2844945191792119712">"Skermslot"</string>
    -     <string name="global_action_power_off" msgid="4471879440839879722">"Sit af"</string>
    -+    <string name="global_action_emergency" msgid="7112311161137421166">"Noodgeval"</string>
    -     <string name="global_action_bug_report" msgid="7934010578922304799">"Foutverslag"</string>
    -     <string name="bugreport_title" msgid="2667494803742548533">"Neem foutverslag"</string>
    -     <string name="bugreport_message" msgid="398447048750350456">"Dit sal inligting oor die huidige toestand van jou toestel insamel om as \'n e-posboodskap te stuur. Dit sal \'n tydjie neem vandat die foutverslag begin is totdat dit reg is om gestuur te word; wees asseblief geduldig."</string>
    -@@ -1076,6 +1077,17 @@
    -     <skip />
    -     <string name="wifi_no_internet" msgid="8451173622563841546">"Wi-Fi het geen internettoegang nie"</string>
    -     <string name="wifi_no_internet_detailed" msgid="8083079241212301741">"Tik vir opsies"</string>
    -+    <string name="network_switch_metered" msgid="4671730921726992671">"Het oorgeskakel na <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
    -+    <string name="network_switch_metered_detail" msgid="5325661434777870353">"Toestel gebruik <xliff:g id="NEW_NETWORK">%1$s</xliff:g> wanneer <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> geen internetverbinding het nie. Heffings kan geld."</string>
    -+    <string name="network_switch_metered_toast" msgid="5779283181685974304">"Het oorgeskakel van <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> na <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
    -+  <string-array name="network_switch_type_name">
    -+    <item msgid="2952042958050315394">"sellulêre data"</item>
    -+    <item msgid="75483255295529161">"Wi-Fi"</item>
    -+    <item msgid="6862614801537202646">"Bluetooth"</item>
    -+    <item msgid="5447331121797802871">"Ethernet"</item>
    -+    <item msgid="8257233890381651999">"VPN"</item>
    -+  </string-array>
    -+    <string name="network_switch_type_name_unknown" msgid="4552612897806660656">"\'n onbekende netwerktipe"</string>
    -     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Kon nie aan Wi-Fikoppel nie"</string>
    -     <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" het \'n swak internetverbinding."</string>
    -     <string name="wifi_connect_alert_title" msgid="8455846016001810172">"Laat verbinding toe?"</string>
    -@@ -1153,7 +1165,6 @@
    -     <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"Tik om taal en uitleg te kies"</string>
    -     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
    -     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
    --    <string name="candidates_style" msgid="4333913089637062257"><u>"kandidate"</u></string>
    -     <string name="ext_media_checking_notification_title" msgid="5734005953288045806">"Berei tans <xliff:g id="NAME">%s</xliff:g> voor"</string>
    -     <string name="ext_media_checking_notification_message" msgid="4747432538578886744">"Kyk tans vir foute"</string>
    -     <string name="ext_media_new_notification_message" msgid="7589986898808506239">"Nuwe <xliff:g id="NAME">%s</xliff:g> bespeur"</string>
    -@@ -1232,8 +1243,9 @@
    -     <string name="vpn_text_long" msgid="4907843483284977618">"Gekoppel aan <xliff:g id="SESSION">%s</xliff:g>. Tik om die netwerk te bestuur."</string>
    -     <string name="vpn_lockdown_connecting" msgid="6443438964440960745">"Altydaan-VPN koppel tans..."</string>
    -     <string name="vpn_lockdown_connected" msgid="8202679674819213931">"Altydaan-VPN gekoppel"</string>
    -+    <string name="vpn_lockdown_disconnected" msgid="4532298952570796327">"Altydaan-VPN is ontkoppel"</string>
    -     <string name="vpn_lockdown_error" msgid="6009249814034708175">"Altydaan-VPN-fout"</string>
    --    <string name="vpn_lockdown_config" msgid="4655589351146766608">"Tik om op te stel"</string>
    -+    <string name="vpn_lockdown_config" msgid="5099330695245008680">"Tik om op te stel"</string>
    -     <string name="upload_file" msgid="2897957172366730416">"Kies lêer"</string>
    -     <string name="no_file_chosen" msgid="6363648562170759465">"Geen lêer gekies nie"</string>
    -     <string name="reset" msgid="2448168080964209908">"Stel terug"</string>
    -@@ -1317,7 +1329,7 @@
    -     <string name="storage_usb_drive_label" msgid="4501418548927759953">"<xliff:g id="MANUFACTURER">%s</xliff:g>-USB-datastokkie"</string>
    -     <string name="storage_usb" msgid="3017954059538517278">"USB-berging"</string>
    -     <string name="extract_edit_menu_button" msgid="8940478730496610137">"Redigeer"</string>
    --    <string name="data_usage_warning_title" msgid="1955638862122232342">"Dataverbruik-waarskuwing"</string>
    -+    <string name="data_usage_warning_title" msgid="3620440638180218181">"Datagebruik-opletberig"</string>
    -     <string name="data_usage_warning_body" msgid="6660692274311972007">"Tik om gebruik en instellings te bekyk."</string>
    -     <string name="data_usage_3g_limit_title" msgid="4361523876818447683">"2G-3G-datalimiet bereik"</string>
    -     <string name="data_usage_4g_limit_title" msgid="4609566827219442376">"4G-datalimiet bereik"</string>
    -@@ -1636,6 +1648,7 @@
    -     <string name="search_language_hint" msgid="7042102592055108574">"Voer taalnaam in"</string>
    -     <string name="language_picker_section_suggested" msgid="8414489646861640885">"Voorgestel"</string>
    -     <string name="language_picker_section_all" msgid="3097279199511617537">"Alle tale"</string>
    -+    <string name="region_picker_section_all" msgid="8966316787153001779">"Allle streke"</string>
    -     <string name="locale_search_menu" msgid="2560710726687249178">"Soek"</string>
    -     <string name="work_mode_off_title" msgid="8954725060677558855">"Werkmodus is AF"</string>
    -     <string name="work_mode_off_message" msgid="3286169091278094476">"Stel werkprofiel in staat om te werk, insluitend programme, agtergrondsinkronisering en verwante kenmerke."</string>
    -diff --git a/core/res/res/values-am/strings.xml b/core/res/res/values-am/strings.xml
    -index 98fcebb..54bddc7 100644
    ---- a/core/res/res/values-am/strings.xml
    -+++ b/core/res/res/values-am/strings.xml
    -@@ -214,6 +214,7 @@
    -     <string name="global_actions" product="default" msgid="2406416831541615258">"የስልክ አማራጮች"</string>
    -     <string name="global_action_lock" msgid="2844945191792119712">"ማያ ቆልፍ"</string>
    -     <string name="global_action_power_off" msgid="4471879440839879722">"ኃይል አጥፋ"</string>
    -+    <string name="global_action_emergency" msgid="7112311161137421166">"ድንገተኛ አደጋ"</string>
    -     <string name="global_action_bug_report" msgid="7934010578922304799">"የሳንካ ሪፖርት"</string>
    -     <string name="bugreport_title" msgid="2667494803742548533">"የሳንካ ሪፖርት ውሰድ"</string>
    -     <string name="bugreport_message" msgid="398447048750350456">"ይሄ እንደ የኢሜይል መልዕክት አድርጎ የሚልከውን ስለመሣሪያዎ የአሁኑ ሁኔታ መረጃ ይሰበስባል። የሳንካ ሪፖርቱን ከመጀመር ጀምሮ እስኪላክ ድረስ ትንሽ ጊዜ ይወስዳል፤ እባክዎ ይታገሱ።"</string>
    -@@ -1076,6 +1077,17 @@
    -     <skip />
    -     <string name="wifi_no_internet" msgid="8451173622563841546">"Wi-Fi በይነመረብ መዳረሻ የለውም"</string>
    -     <string name="wifi_no_internet_detailed" msgid="8083079241212301741">"ለአማራጮች መታ ያድርጉ"</string>
    -+    <string name="network_switch_metered" msgid="4671730921726992671">"ወደ <xliff:g id="NETWORK_TYPE">%1$s</xliff:g> ተቀይሯል"</string>
    -+    <string name="network_switch_metered_detail" msgid="5325661434777870353">"<xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> ምንም ዓይነት የበይነመረብ ግንኙነት በማይኖረው ጊዜ መሣሪያዎች <xliff:g id="NEW_NETWORK">%1$s</xliff:g>ን ይጠቀማሉ። ክፍያዎች ተፈጻሚ ሊሆኑ ይችላሉ።"</string>
    -+    <string name="network_switch_metered_toast" msgid="5779283181685974304">"ከ<xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> ወደ <xliff:g id="NEW_NETWORK">%2$s</xliff:g> ተቀይሯል"</string>
    -+  <string-array name="network_switch_type_name">
    -+    <item msgid="2952042958050315394">"የተንቀሳቃሽ ስልክ ውሂብ"</item>
    -+    <item msgid="75483255295529161">"Wi-Fi"</item>
    -+    <item msgid="6862614801537202646">"ብሉቱዝ"</item>
    -+    <item msgid="5447331121797802871">"ኤተርኔት"</item>
    -+    <item msgid="8257233890381651999">"VPN"</item>
    -+  </string-array>
    -+    <string name="network_switch_type_name_unknown" msgid="4552612897806660656">"አንድ ያልታወቀ አውታረ መረብ ዓይነት"</string>
    -     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"ወደ Wi-Fi ለማያያዝ አልተቻለም"</string>
    -     <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" ደካማ የበይነመረብ ግንኙነት ኣለው።"</string>
    -     <string name="wifi_connect_alert_title" msgid="8455846016001810172">"ግንኙነት ይፈቀድ?"</string>
    -@@ -1153,7 +1165,6 @@
    -     <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"ቋንቋ እና አቀማመጥን ለመምረጥ መታ ያድርጉ"</string>
    -     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
    -     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
    --    <string name="candidates_style" msgid="4333913089637062257"><u>"ዕጩዎች"</u></string>
    -     <string name="ext_media_checking_notification_title" msgid="5734005953288045806">"<xliff:g id="NAME">%s</xliff:g>ን በማዘጋጀት ላይ"</string>
    -     <string name="ext_media_checking_notification_message" msgid="4747432538578886744">"ስህተቶች ካሉ በመፈተሽ ላይ"</string>
    -     <string name="ext_media_new_notification_message" msgid="7589986898808506239">"አዲስ <xliff:g id="NAME">%s</xliff:g> ተገኝቷል"</string>
    -@@ -1232,8 +1243,9 @@
    -     <string name="vpn_text_long" msgid="4907843483284977618">"ለ<xliff:g id="SESSION">%s</xliff:g> የተገናኘ። አውታረመረቡን ለማደራጀት ሁለቴ ንካ።"</string>
    -     <string name="vpn_lockdown_connecting" msgid="6443438964440960745">"ሁልጊዜ የበራ VPN በመገናኘት ላይ…"</string>
    -     <string name="vpn_lockdown_connected" msgid="8202679674819213931">"ሁልጊዜ የበራ VPN ተገናኝቷል"</string>
    -+    <string name="vpn_lockdown_disconnected" msgid="4532298952570796327">"ሁልጊዜ የበራ የVPN ግንኙነት ተቋርጧል"</string>
    -     <string name="vpn_lockdown_error" msgid="6009249814034708175">"ሁልጊዜ የበራ VPN ስህተት"</string>
    --    <string name="vpn_lockdown_config" msgid="4655589351146766608">"ለማዋቀር መታ ያድርጉ"</string>
    -+    <string name="vpn_lockdown_config" msgid="5099330695245008680">"ለማዋቀር መታ ያድርጉ"</string>
    -     <string name="upload_file" msgid="2897957172366730416">"ፋይል ምረጥ"</string>
    -     <string name="no_file_chosen" msgid="6363648562170759465">"ምንም ፋይል አልተመረጠም"</string>
    -     <string name="reset" msgid="2448168080964209908">"ዳግም አስጀምር"</string>
    -@@ -1317,7 +1329,7 @@
    -     <string name="storage_usb_drive_label" msgid="4501418548927759953">"የ<xliff:g id="MANUFACTURER">%s</xliff:g> ዩኤስቢ አንጻፊ"</string>
    -     <string name="storage_usb" msgid="3017954059538517278">"የUSB  ማከማቻ"</string>
    -     <string name="extract_edit_menu_button" msgid="8940478730496610137">"አርትዕ"</string>
    --    <string name="data_usage_warning_title" msgid="1955638862122232342">"የውሂብ አጠቃቀም ማስጠንቀቂየ"</string>
    -+    <string name="data_usage_warning_title" msgid="3620440638180218181">"የውሂብ አጠቃቀም ማንቂያ"</string>
    -     <string name="data_usage_warning_body" msgid="6660692274311972007">"አጠቃቀምን እና ቅንብሮችን ለማየት መታ ያድርጉ።"</string>
    -     <string name="data_usage_3g_limit_title" msgid="4361523876818447683">"የ2ጂ-3ጂ ውሂብ ገደብ ላይ ተደርሷል"</string>
    -     <string name="data_usage_4g_limit_title" msgid="4609566827219442376">"የ4ጂ ውሂብ ገደብ ላይ ተደርሷል"</string>
    -@@ -1636,6 +1648,7 @@
    -     <string name="search_language_hint" msgid="7042102592055108574">"የቋንቋ ስም ይተይቡ"</string>
    -     <string name="language_picker_section_suggested" msgid="8414489646861640885">"የተጠቆሙ"</string>
    -     <string name="language_picker_section_all" msgid="3097279199511617537">"ሁሉም ቋንቋዎች"</string>
    -+    <string name="region_picker_section_all" msgid="8966316787153001779">"ሁሉም ክልሎች"</string>
    -     <string name="locale_search_menu" msgid="2560710726687249178">"ፈልግ"</string>
    -     <string name="work_mode_off_title" msgid="8954725060677558855">"የሥራ ሁነታ ጠፍቷል"</string>
    -     <string name="work_mode_off_message" msgid="3286169091278094476">"መተግበሪያዎችን፣ የበስተጀርባ ሥምረት እና ተዛማጅ ባሕሪዎችን ጨምሮ የሥራ መገለጫ እንዲሰራ ይፍቀዱ።"</string>
    -diff --git a/core/res/res/values-ar/strings.xml b/core/res/res/values-ar/strings.xml
    -index 32df247..493170b 100644
    ---- a/core/res/res/values-ar/strings.xml
    -+++ b/core/res/res/values-ar/strings.xml
    -@@ -222,6 +222,7 @@
    -     <string name="global_actions" product="default" msgid="2406416831541615258">"خيارات الهاتف"</string>
    -     <string name="global_action_lock" msgid="2844945191792119712">"تأمين الشاشة"</string>
    -     <string name="global_action_power_off" msgid="4471879440839879722">"إيقاف التشغيل"</string>
    -+    <string name="global_action_emergency" msgid="7112311161137421166">"الطوارئ"</string>
    -     <string name="global_action_bug_report" msgid="7934010578922304799">"تقرير الأخطاء"</string>
    -     <string name="bugreport_title" msgid="2667494803742548533">"إعداد تقرير بالأخطاء"</string>
    -     <string name="bugreport_message" msgid="398447048750350456">"سيجمع هذا معلومات حول حالة جهازك الحالي لإرسالها كرسالة إلكترونية، ولكنه سيستغرق وقتًا قليلاً من بدء عرض تقرير بالأخطاء. وحتى يكون جاهزًا للإرسال، الرجاء الانتظار."</string>
    -@@ -1045,7 +1046,7 @@
    -     <string name="editTextMenuTitle" msgid="4909135564941815494">"إجراءات النص"</string>
    -     <string name="low_internal_storage_view_title" msgid="5576272496365684834">"مساحة التخزين منخفضة"</string>
    -     <string name="low_internal_storage_view_text" msgid="6640505817617414371">"قد لا تعمل بعض وظائف النظام"</string>
    --    <string name="low_internal_storage_view_text_no_boot" msgid="6935190099204693424">"ليست هناك سعة تخزينية كافية للنظام. تأكد من أنه لديك مساحة خالية تبلغ ۲۵۰ ميغابايت وأعد التشغيل."</string>
    -+    <string name="low_internal_storage_view_text_no_boot" msgid="6935190099204693424">"ليست هناك سعة تخزينية كافية للنظام. تأكد من أنه لديك مساحة خالية تبلغ ٢٥٠ ميغابايت وأعد التشغيل."</string>
    -     <string name="app_running_notification_title" msgid="8718335121060787914">"<xliff:g id="APP_NAME">%1$s</xliff:g> قيد التشغيل"</string>
    -     <string name="app_running_notification_text" msgid="1197581823314971177">"انقر للحصول على مزيد من المعلومات أو لإيقاف التطبيق."</string>
    -     <string name="ok" msgid="5970060430562524910">"موافق"</string>
    -@@ -1176,6 +1177,17 @@
    -     <skip />
    -     <string name="wifi_no_internet" msgid="8451173622563841546">"‏شبكة Wi-Fi غير متصلة بالإنترنت"</string>
    -     <string name="wifi_no_internet_detailed" msgid="8083079241212301741">"انقر للحصول على الخيارات."</string>
    -+    <string name="network_switch_metered" msgid="4671730921726992671">"تم التبديل إلى <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
    -+    <string name="network_switch_metered_detail" msgid="5325661434777870353">"يستخدم الجهاز <xliff:g id="NEW_NETWORK">%1$s</xliff:g> عندما لا يتوفر اتصال بالإنترنت في شبكة <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g>، ويمكن أن يتم فرض رسوم مقابل ذلك."</string>
    -+    <string name="network_switch_metered_toast" msgid="5779283181685974304">"تم التبديل من <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> إلى <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
    -+  <string-array name="network_switch_type_name">
    -+    <item msgid="2952042958050315394">"بيانات شبكة الجوّال"</item>
    -+    <item msgid="75483255295529161">"Wi-Fi"</item>
    -+    <item msgid="6862614801537202646">"بلوتوث"</item>
    -+    <item msgid="5447331121797802871">"إيثرنت"</item>
    -+    <item msgid="8257233890381651999">"‏شبكة ظاهرية خاصة (VPN)"</item>
    -+  </string-array>
    -+    <string name="network_switch_type_name_unknown" msgid="4552612897806660656">"نوع شبكة غير معروف"</string>
    -     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"‏تعذر الاتصال بـ Wi-Fi"</string>
    -     <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" لديها اتصال إنترنت رديء."</string>
    -     <string name="wifi_connect_alert_title" msgid="8455846016001810172">"هل تريد السماح بالاتصال؟"</string>
    -@@ -1253,7 +1265,6 @@
    -     <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"انقر لاختيار لغة وتنسيق"</string>
    -     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" أ ب ت ث ج ح خ د ذ ر ز س ش ص ض ط ظ ع غ ف ق ك ل م ن ه و ي"</string>
    -     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789 أ ب ت ث ج ح خ د ذ ر ز س ش ص ض ط ظ ع غ ف ق ك ل م ن ه و ي"</string>
    --    <string name="candidates_style" msgid="4333913089637062257"><u>"العناصر المرشحة"</u></string>
    -     <string name="ext_media_checking_notification_title" msgid="5734005953288045806">"جارٍ تحضير <xliff:g id="NAME">%s</xliff:g>"</string>
    -     <string name="ext_media_checking_notification_message" msgid="4747432538578886744">"جارٍ التحقق من الأخطاء"</string>
    -     <string name="ext_media_new_notification_message" msgid="7589986898808506239">"تم اكتشاف <xliff:g id="NAME">%s</xliff:g> جديدة"</string>
    -@@ -1332,8 +1343,9 @@
    -     <string name="vpn_text_long" msgid="4907843483284977618">"تم الاتصال بـ <xliff:g id="SESSION">%s</xliff:g>. انقر لإدارة الشبكة."</string>
    -     <string name="vpn_lockdown_connecting" msgid="6443438964440960745">"‏جارٍ الاتصال بشبكة ظاهرية خاصة (VPN) دائمة التشغيل..."</string>
    -     <string name="vpn_lockdown_connected" msgid="8202679674819213931">"‏تم الاتصال بشبكة ظاهرية خاصة (VPN) دائمة التشغيل"</string>
    -+    <string name="vpn_lockdown_disconnected" msgid="4532298952570796327">"‏تم فصل الشبكة الظاهرية الخاصة (VPN) دائمة التشغيل"</string>
    -     <string name="vpn_lockdown_error" msgid="6009249814034708175">"‏خطأ بشبكة ظاهرية خاصة (VPN) دائمة التشغيل"</string>
    --    <string name="vpn_lockdown_config" msgid="4655589351146766608">"انقر للتهيئة."</string>
    -+    <string name="vpn_lockdown_config" msgid="5099330695245008680">"انقر للإعداد."</string>
    -     <string name="upload_file" msgid="2897957172366730416">"اختيار ملف"</string>
    -     <string name="no_file_chosen" msgid="6363648562170759465">"لم يتم اختيار أي ملف"</string>
    -     <string name="reset" msgid="2448168080964209908">"إعادة تعيين"</string>
    -@@ -1421,7 +1433,7 @@
    -     <string name="storage_usb_drive_label" msgid="4501418548927759953">"‏محرك أقراص USB من <xliff:g id="MANUFACTURER">%s</xliff:g>"</string>
    -     <string name="storage_usb" msgid="3017954059538517278">"‏وحدة تخزين USB"</string>
    -     <string name="extract_edit_menu_button" msgid="8940478730496610137">"تعديل"</string>
    --    <string name="data_usage_warning_title" msgid="1955638862122232342">"تحذير استخدام البيانات"</string>
    -+    <string name="data_usage_warning_title" msgid="3620440638180218181">"تنبيه استخدام البيانات"</string>
    -     <string name="data_usage_warning_body" msgid="6660692274311972007">"انقر لعرض الاستخدام والإعدادات."</string>
    -     <string name="data_usage_3g_limit_title" msgid="4361523876818447683">"‏تم بلوغ حد بيانات اتصال 2G-3G"</string>
    -     <string name="data_usage_4g_limit_title" msgid="4609566827219442376">"‏تم بلوغ حد بيانات اتصال 4G"</string>
    -@@ -1780,6 +1792,7 @@
    -     <string name="search_language_hint" msgid="7042102592055108574">"اكتب اسم اللغة"</string>
    -     <string name="language_picker_section_suggested" msgid="8414489646861640885">"المقترحة"</string>
    -     <string name="language_picker_section_all" msgid="3097279199511617537">"جميع اللغات"</string>
    -+    <string name="region_picker_section_all" msgid="8966316787153001779">"كل المناطق"</string>
    -     <string name="locale_search_menu" msgid="2560710726687249178">"البحث"</string>
    -     <string name="work_mode_off_title" msgid="8954725060677558855">"وضع العمل معطَّل"</string>
    -     <string name="work_mode_off_message" msgid="3286169091278094476">"السماح باستخدام الملف الشخصي للعمل، بما في ذلك التطبيقات ومزامنة الخلفية والميزات ذات الصلة."</string>
    -diff --git a/core/res/res/values-az-rAZ/strings.xml b/core/res/res/values-az-rAZ/strings.xml
    -index b1ed7dd..7c3f2a4 100644
    ---- a/core/res/res/values-az-rAZ/strings.xml
    -+++ b/core/res/res/values-az-rAZ/strings.xml
    -@@ -214,6 +214,7 @@
    -     <string name="global_actions" product="default" msgid="2406416831541615258">"Telefon seçimləri"</string>
    -     <string name="global_action_lock" msgid="2844945191792119712">"Ekran kilidi"</string>
    -     <string name="global_action_power_off" msgid="4471879440839879722">"Söndür"</string>
    -+    <string name="global_action_emergency" msgid="7112311161137421166">"Təcili"</string>
    -     <string name="global_action_bug_report" msgid="7934010578922304799">"Baq hesabatı"</string>
    -     <string name="bugreport_title" msgid="2667494803742548533">"Baqı xəbər verin"</string>
    -     <string name="bugreport_message" msgid="398447048750350456">"Bu, sizin hazırkı cihaz durumu haqqında məlumat toplayacaq ki, elektron məktub şəklində göndərsin. Baq raportuna başlamaq üçün bir az vaxt lazım ola bilər, bir az səbr edin."</string>
    -@@ -1076,6 +1077,17 @@
    -     <skip />
    -     <string name="wifi_no_internet" msgid="8451173622563841546">"Wi-Fi-ın İnternetə girişi yoxdur"</string>
    -     <string name="wifi_no_internet_detailed" msgid="8083079241212301741">"Seçimlər üçün tıklayın"</string>
    -+    <string name="network_switch_metered" msgid="4671730921726992671">"<xliff:g id="NETWORK_TYPE">%1$s</xliff:g> şəbəkə növünə keçirildi"</string>
    -+    <string name="network_switch_metered_detail" msgid="5325661434777870353">"<xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> şəbəkəsinin İnternetə çıxışı olmadıqda, cihaz <xliff:g id="NEW_NETWORK">%1$s</xliff:g> şəbəkəsini istifadə edir. Ödəniş tətbiq oluna bilər."</string>
    -+    <string name="network_switch_metered_toast" msgid="5779283181685974304">"<xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> şəbəkəsindən <xliff:g id="NEW_NETWORK">%2$s</xliff:g> şəbəkəsinə keçirildi"</string>
    -+  <string-array name="network_switch_type_name">
    -+    <item msgid="2952042958050315394">"mobil data"</item>
    -+    <item msgid="75483255295529161">"Wi-Fi"</item>
    -+    <item msgid="6862614801537202646">"Bluetooth"</item>
    -+    <item msgid="5447331121797802871">"Ethernet"</item>
    -+    <item msgid="8257233890381651999">"VPN"</item>
    -+  </string-array>
    -+    <string name="network_switch_type_name_unknown" msgid="4552612897806660656">"naməlum şəbəkə növü"</string>
    -     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Wi-Fi\'a qoşulmaq alınmadı"</string>
    -     <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" internet bağlantısı keyfiyyətsizdir."</string>
    -     <string name="wifi_connect_alert_title" msgid="8455846016001810172">"Bağlantıya icazə verilsin?"</string>
    -@@ -1153,7 +1165,6 @@
    -     <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"Dil və tərtibatı seçmək üçün tıklayın"</string>
    -     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCÇDEƏFGĞHXIİJKQLMNOÖPRSŞTUÜVYZ"</string>
    -     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCÇDEƏFGĞHİIJKLMNOÖPQRSŞTUÜVWXYZ"</string>
    --    <string name="candidates_style" msgid="4333913089637062257"><u>"namizədlər"</u></string>
    -     <string name="ext_media_checking_notification_title" msgid="5734005953288045806">"<xliff:g id="NAME">%s</xliff:g> hazırlanır"</string>
    -     <string name="ext_media_checking_notification_message" msgid="4747432538578886744">"Səhvlər yoxlanılır"</string>
    -     <string name="ext_media_new_notification_message" msgid="7589986898808506239">"Yeni <xliff:g id="NAME">%s</xliff:g> aşkarlandı"</string>
    -@@ -1232,8 +1243,9 @@
    -     <string name="vpn_text_long" msgid="4907843483284977618">"<xliff:g id="SESSION">%s</xliff:g> sessiyaya qoşulun. Şəbəkəni idarə etmək üçün tıklayın."</string>
    -     <string name="vpn_lockdown_connecting" msgid="6443438964440960745">"Həmişə aktiv VPN bağlanır..."</string>
    -     <string name="vpn_lockdown_connected" msgid="8202679674819213931">"VPN bağlantısı həmişə aktiv"</string>
    -+    <string name="vpn_lockdown_disconnected" msgid="4532298952570796327">"Həmişə aktiv VPN bağlantısı kəsildi"</string>
    -     <string name="vpn_lockdown_error" msgid="6009249814034708175">"Həmişə aktiv VPN xətası"</string>
    --    <string name="vpn_lockdown_config" msgid="4655589351146766608">"Konfiqurasiya üçün tıklayın"</string>
    -+    <string name="vpn_lockdown_config" msgid="5099330695245008680">"Quraşdırmaq üçün tıklayın"</string>
    -     <string name="upload_file" msgid="2897957172366730416">"Fayl seçin"</string>
    -     <string name="no_file_chosen" msgid="6363648562170759465">"Heç bir fayl seçilməyib"</string>
    -     <string name="reset" msgid="2448168080964209908">"Sıfırlayın"</string>
    -@@ -1317,7 +1329,7 @@
    -     <string name="storage_usb_drive_label" msgid="4501418548927759953">"<xliff:g id="MANUFACTURER">%s</xliff:g> USB drayv"</string>
    -     <string name="storage_usb" msgid="3017954059538517278">"USB yaddaş"</string>
    -     <string name="extract_edit_menu_button" msgid="8940478730496610137">"Düzəliş edin"</string>
    --    <string name="data_usage_warning_title" msgid="1955638862122232342">"Data istifadə xəbərdarlığı"</string>
    -+    <string name="data_usage_warning_title" msgid="3620440638180218181">"Data istifadə siqnalı"</string>
    -     <string name="data_usage_warning_body" msgid="6660692274311972007">"İstifadə və ayarları görmək üçün tıklayın."</string>
    -     <string name="data_usage_3g_limit_title" msgid="4361523876818447683">"2G-3G data limitinə çatdı"</string>
    -     <string name="data_usage_4g_limit_title" msgid="4609566827219442376">"4G data limitinə çatdı"</string>
    -@@ -1636,6 +1648,7 @@
    -     <string name="search_language_hint" msgid="7042102592055108574">"Dil adını daxil edin"</string>
    -     <string name="language_picker_section_suggested" msgid="8414489646861640885">"Təklif edilmiş"</string>
    -     <string name="language_picker_section_all" msgid="3097279199511617537">"Bütün dillər"</string>
    -+    <string name="region_picker_section_all" msgid="8966316787153001779">"Bütün bölgələr"</string>
    -     <string name="locale_search_menu" msgid="2560710726687249178">"Axtarın"</string>
    -     <string name="work_mode_off_title" msgid="8954725060677558855">"İş rejimi DEAKTİVDİR"</string>
    -     <string name="work_mode_off_message" msgid="3286169091278094476">"Tətbiq, arxa fon sinxronizasiyası və digər əlaqədar xüsusiyyətlər daxil olmaqla iş profilinin fəaliyyətinə icazə verin."</string>
    -diff --git a/core/res/res/values-b+sr+Latn/strings.xml b/core/res/res/values-b+sr+Latn/strings.xml
    -index ad74e2e..50e1327 100644
    ---- a/core/res/res/values-b+sr+Latn/strings.xml
    -+++ b/core/res/res/values-b+sr+Latn/strings.xml
    -@@ -152,7 +152,7 @@
    -     <string name="httpErrorAuth" msgid="1435065629438044534">"Nije moguće potvrditi autentičnost."</string>
    -     <string name="httpErrorProxyAuth" msgid="1788207010559081331">"Potvrda identiteta preko proksi servera nije uspela."</string>
    -     <string name="httpErrorConnect" msgid="8714273236364640549">"Nije moguće povezati se sa serverom."</string>
    --    <string name="httpErrorIO" msgid="2340558197489302188">"Nije moguće komunicirati sa serverom. Pokušajte ponovo kasnije."</string>
    -+    <string name="httpErrorIO" msgid="2340558197489302188">"Nije moguće komunicirati sa serverom. Probajte ponovo kasnije."</string>
    -     <string name="httpErrorTimeout" msgid="4743403703762883954">"Veza sa serverom je istekla."</string>
    -     <string name="httpErrorRedirectLoop" msgid="8679596090392779516">"Stranica sadrži previše veza za preusmeravanje sa servera."</string>
    -     <string name="httpErrorUnsupportedScheme" msgid="5015730812906192208">"Protokol nije podržan."</string>
    -@@ -160,7 +160,7 @@
    -     <string name="httpErrorBadUrl" msgid="3636929722728881972">"Stranicu nije moguće otvoriti zato što je URL adresa nevažeća."</string>
    -     <string name="httpErrorFile" msgid="2170788515052558676">"Nije moguće pristupiti datoteci."</string>
    -     <string name="httpErrorFileNotFound" msgid="6203856612042655084">"Nije moguće pronaći traženu datoteku."</string>
    --    <string name="httpErrorTooManyRequests" msgid="1235396927087188253">"Previše zahteva se obrađuje. Pokušajte ponovo kasnije."</string>
    -+    <string name="httpErrorTooManyRequests" msgid="1235396927087188253">"Previše zahteva se obrađuje. Probajte ponovo kasnije."</string>
    -     <string name="notification_title" msgid="8967710025036163822">"Greška pri prijavljivanju za <xliff:g id="ACCOUNT">%1$s</xliff:g>"</string>
    -     <string name="contentServiceSync" msgid="8353523060269335667">"Sinhronizacija"</string>
    -     <string name="contentServiceSyncNotificationTitle" msgid="397743349191901458">"Sinhronizacija"</string>
    -@@ -216,6 +216,7 @@
    -     <string name="global_actions" product="default" msgid="2406416831541615258">"Opcije telefona"</string>
    -     <string name="global_action_lock" msgid="2844945191792119712">"Zaključaj ekran"</string>
    -     <string name="global_action_power_off" msgid="4471879440839879722">"Isključi"</string>
    -+    <string name="global_action_emergency" msgid="7112311161137421166">"Hitni poziv"</string>
    -     <string name="global_action_bug_report" msgid="7934010578922304799">"Izveštaj o grešci"</string>
    -     <string name="bugreport_title" msgid="2667494803742548533">"Napravi izveštaj o grešci"</string>
    -     <string name="bugreport_message" msgid="398447048750350456">"Ovim će se prikupiti informacije o trenutnom stanju uređaja kako bi bile poslate u poruci e-pošte. Od započinjanja izveštaja o grešci do trenutka za njegovo slanje proći će neko vreme; budite strpljivi."</string>
    -@@ -256,9 +257,9 @@
    -     <string name="permgrouplab_storage" msgid="1971118770546336966">"Skladište"</string>
    -     <string name="permgroupdesc_storage" msgid="637758554581589203">"pristupa slikama, medijima i datotekama na uređaju"</string>
    -     <string name="permgrouplab_microphone" msgid="171539900250043464">"Mikrofon"</string>
    --    <string name="permgroupdesc_microphone" msgid="4988812113943554584">"snima audio snimke"</string>
    -+    <string name="permgroupdesc_microphone" msgid="4988812113943554584">"snima audio"</string>
    -     <string name="permgrouplab_camera" msgid="4820372495894586615">"Kamera"</string>
    --    <string name="permgroupdesc_camera" msgid="3250611594678347720">"snima slike i video snimke"</string>
    -+    <string name="permgroupdesc_camera" msgid="3250611594678347720">"snima slike i video"</string>
    -     <string name="permgrouplab_phone" msgid="5229115638567440675">"Telefon"</string>
    -     <string name="permgroupdesc_phone" msgid="6234224354060641055">"upućuje telefonske pozive i upravlja njima"</string>
    -     <string name="permgrouplab_sensors" msgid="416037179223226722">"Senzori za telo"</string>
    -@@ -439,19 +440,19 @@
    -     <string name="permdesc_manageFingerprint" msgid="178208705828055464">"Dozvoljava aplikaciji da aktivira metode za dodavanje i brisanje šablona otisaka prstiju koji će se koristiti."</string>
    -     <string name="permlab_useFingerprint" msgid="3150478619915124905">"koristi hardver za otiske prstiju"</string>
    -     <string name="permdesc_useFingerprint" msgid="9165097460730684114">"Dozvoljava aplikaciji da koristi hardver za otiske prstiju radi potvrde autentičnosti"</string>
    --    <string name="fingerprint_acquired_partial" msgid="735082772341716043">"Otkriven je delimični otisak prsta. Pokušajte ponovo."</string>
    --    <string name="fingerprint_acquired_insufficient" msgid="4596546021310923214">"Nije uspela obrada otiska prsta. Pokušajte ponovo."</string>
    -+    <string name="fingerprint_acquired_partial" msgid="735082772341716043">"Otkriven je delimični otisak prsta. Probajte ponovo."</string>
    -+    <string name="fingerprint_acquired_insufficient" msgid="4596546021310923214">"Nije uspela obrada otiska prsta. Probajte ponovo."</string>
    -     <string name="fingerprint_acquired_imager_dirty" msgid="1087209702421076105">"Senzor za otiske prstiju je prljav. Očistite ga i pokušajte ponovo."</string>
    --    <string name="fingerprint_acquired_too_fast" msgid="6470642383109155969">"Prebrzo ste pomerili prst. Pokušajte ponovo."</string>
    --    <string name="fingerprint_acquired_too_slow" msgid="59250885689661653">"Previše sporo ste pomerili prst. Pokušajte ponovo."</string>
    -+    <string name="fingerprint_acquired_too_fast" msgid="6470642383109155969">"Prebrzo ste pomerili prst. Probajte ponovo."</string>
    -+    <string name="fingerprint_acquired_too_slow" msgid="59250885689661653">"Previše sporo ste pomerili prst. Probajte ponovo."</string>
    -   <string-array name="fingerprint_acquired_vendor">
    -   </string-array>
    -     <string name="fingerprint_error_hw_not_available" msgid="7955921658939936596">"Hardver za otiske prstiju nije dostupan."</string>
    -     <string name="fingerprint_error_no_space" msgid="1055819001126053318">"Nije moguće sačuvati otisak prsta. Uklonite neki od postojećih otisaka prstiju."</string>
    --    <string name="fingerprint_error_timeout" msgid="3927186043737732875">"Vremensko ograničenje za otisak prsta je isteklo. Pokušajte ponovo."</string>
    -+    <string name="fingerprint_error_timeout" msgid="3927186043737732875">"Vremensko ograničenje za otisak prsta je isteklo. Probajte ponovo."</string>
    -     <string name="fingerprint_error_canceled" msgid="4402024612660774395">"Radnja sa otiskom prsta je otkazana."</string>
    --    <string name="fingerprint_error_lockout" msgid="5536934748136933450">"Previše pokušaja. Pokušajte ponovo kasnije."</string>
    --    <string name="fingerprint_error_unable_to_process" msgid="6107816084103552441">"Pokušajte ponovo."</string>
    -+    <string name="fingerprint_error_lockout" msgid="5536934748136933450">"Previše pokušaja. Probajte ponovo kasnije."</string>
    -+    <string name="fingerprint_error_unable_to_process" msgid="6107816084103552441">"Probajte ponovo."</string>
    -     <string name="fingerprint_name_template" msgid="5870957565512716938">"Prst <xliff:g id="FINGERID">%d</xliff:g>"</string>
    -   <string-array name="fingerprint_error_vendor">
    -   </string-array>
    -@@ -679,8 +680,8 @@
    -     <string name="lockscreen_emergency_call" msgid="5298642613417801888">"Hitne službe"</string>
    -     <string name="lockscreen_return_to_call" msgid="5244259785500040021">"Nazad na poziv"</string>
    -     <string name="lockscreen_pattern_correct" msgid="9039008650362261237">"Tačno!"</string>
    --    <string name="lockscreen_pattern_wrong" msgid="4317955014948108794">"Pokušajte ponovo"</string>
    --    <string name="lockscreen_password_wrong" msgid="5737815393253165301">"Pokušajte ponovo"</string>
    -+    <string name="lockscreen_pattern_wrong" msgid="4317955014948108794">"Probajte ponovo"</string>
    -+    <string name="lockscreen_password_wrong" msgid="5737815393253165301">"Probajte ponovo"</string>
    -     <string name="lockscreen_storage_locked" msgid="9167551160010625200">"Otključaj za sve funkcije i podatke"</string>
    -     <string name="faceunlock_multiple_failures" msgid="754137583022792429">"Premašen je najveći dozvoljeni broj pokušaja Otključavanja licem"</string>
    -     <string name="lockscreen_missing_sim_message_short" msgid="5099439277819215399">"Nema SIM kartice"</string>
    -@@ -704,19 +705,19 @@
    -     <string name="lockscreen_sim_puk_locked_instructions" msgid="8127916255245181063">"Pogledajte Korisnički vodič ili kontaktirajte Korisničku podršku."</string>
    -     <string name="lockscreen_sim_locked_message" msgid="8066660129206001039">"SIM kartica je zaključana."</string>
    -     <string name="lockscreen_sim_unlock_progress_dialog_message" msgid="595323214052881264">"Otključavanje SIM kartice…"</string>
    --    <string name="lockscreen_too_many_failed_attempts_dialog_message" msgid="6481623830344107222">"<xliff:g id="NUMBER_0">%1$d</xliff:g> puta ste nepravilno nacrtali šablon za otključavanje. \n\nPokušajte ponovo za <xliff:g id="NUMBER_1">%2$d</xliff:g> sekunde(i)."</string>
    --    <string name="lockscreen_too_many_failed_password_attempts_dialog_message" msgid="2725973286239344555">"<xliff:g id="NUMBER_0">%1$d</xliff:g> puta ste pogrešno uneli lozinku. \n\nPokušajte ponovo za <xliff:g id="NUMBER_1">%2$d</xliff:g> sekunde(i)."</string>
    --    <string name="lockscreen_too_many_failed_pin_attempts_dialog_message" msgid="6216672706545696955">"<xliff:g id="NUMBER_0">%1$d</xliff:g> puta ste pogrešno uneli PIN. \n\nPokušajte ponovo za <xliff:g id="NUMBER_1">%2$d</xliff:g> sekunde(i)."</string>
    --    <string name="lockscreen_failed_attempts_almost_glogin" product="tablet" msgid="9191611984625460820">"<xliff:g id="NUMBER_0">%1$d</xliff:g> puta ste netačno uneli šablon za otključavanje. Nakon još <xliff:g id="NUMBER_1">%2$d</xliff:g> nesupešna(ih) pokušaja, od vas će biti zatraženo da otključate tablet pomoću podataka za prijavljivanje na Google.\n\n Pokušajte ponovo za <xliff:g id="NUMBER_2">%3$d</xliff:g> sekunde(i)."</string>
    --    <string name="lockscreen_failed_attempts_almost_glogin" product="tv" msgid="5316664559603394684">"Neispravno ste nacrtali šablon za otključavanje <xliff:g id="NUMBER_0">%1$d</xliff:g> puta. Posle još <xliff:g id="NUMBER_1">%2$d</xliff:g> neuspešna(ih) pokušaja od vas će biti zatraženo da otključate TV pomoću podataka za prijavljivanje na Google.\n\n Pokušajte ponovo za <xliff:g id="NUMBER_2">%3$d</xliff:g> sek."</string>
    --    <string name="lockscreen_failed_attempts_almost_glogin" product="default" msgid="2590227559763762751">"<xliff:g id="NUMBER_0">%1$d</xliff:g> puta ste netačno uneli šablon za otključavanje. Nakon još <xliff:g id="NUMBER_1">%2$d</xliff:g> nesupešna(ih) pokušaja, od vas će biti zatraženo da otključate telefon pomoću podataka za prijavljivanje na Google.\n\n Pokušajte ponovo za <xliff:g id="NUMBER_2">%3$d</xliff:g> sekunde(i)."</string>
    -+    <string name="lockscreen_too_many_failed_attempts_dialog_message" msgid="6481623830344107222">"<xliff:g id="NUMBER_0">%1$d</xliff:g> puta ste nepravilno nacrtali šablon za otključavanje. \n\nProbajte ponovo za <xliff:g id="NUMBER_1">%2$d</xliff:g> sekunde(i)."</string>
    -+    <string name="lockscreen_too_many_failed_password_attempts_dialog_message" msgid="2725973286239344555">"<xliff:g id="NUMBER_0">%1$d</xliff:g> puta ste pogrešno uneli lozinku. \n\nProbajte ponovo za <xliff:g id="NUMBER_1">%2$d</xliff:g> sekunde(i)."</string>
    -+    <string name="lockscreen_too_many_failed_pin_attempts_dialog_message" msgid="6216672706545696955">"<xliff:g id="NUMBER_0">%1$d</xliff:g> puta ste pogrešno uneli PIN. \n\nProbajte ponovo za <xliff:g id="NUMBER_1">%2$d</xliff:g> sekunde(i)."</string>
    -+    <string name="lockscreen_failed_attempts_almost_glogin" product="tablet" msgid="9191611984625460820">"<xliff:g id="NUMBER_0">%1$d</xliff:g> puta ste netačno uneli šablon za otključavanje. Nakon još <xliff:g id="NUMBER_1">%2$d</xliff:g> nesupešna(ih) pokušaja, od vas će biti zatraženo da otključate tablet pomoću podataka za prijavljivanje na Google.\n\n Probajte ponovo za <xliff:g id="NUMBER_2">%3$d</xliff:g> sekunde(i)."</string>
    -+    <string name="lockscreen_failed_attempts_almost_glogin" product="tv" msgid="5316664559603394684">"Neispravno ste nacrtali šablon za otključavanje <xliff:g id="NUMBER_0">%1$d</xliff:g> puta. Posle još <xliff:g id="NUMBER_1">%2$d</xliff:g> neuspešna(ih) pokušaja od vas će biti zatraženo da otključate TV pomoću podataka za prijavljivanje na Google.\n\n Probajte ponovo za <xliff:g id="NUMBER_2">%3$d</xliff:g> sek."</string>
    -+    <string name="lockscreen_failed_attempts_almost_glogin" product="default" msgid="2590227559763762751">"<xliff:g id="NUMBER_0">%1$d</xliff:g> puta ste netačno uneli šablon za otključavanje. Nakon još <xliff:g id="NUMBER_1">%2$d</xliff:g> nesupešna(ih) pokušaja, od vas će biti zatraženo da otključate telefon pomoću podataka za prijavljivanje na Google.\n\n Probajte ponovo za <xliff:g id="NUMBER_2">%3$d</xliff:g> sekunde(i)."</string>
    -     <string name="lockscreen_failed_attempts_almost_at_wipe" product="tablet" msgid="6128106399745755604">"Nepravilno ste pokušali da otključate tablet <xliff:g id="NUMBER_0">%1$d</xliff:g> puta. Nakon još neuspešnih pokušaja (<xliff:g id="NUMBER_1">%2$d</xliff:g>) tablet će biti resetovan na fabrička podešavanja i svi korisnički podaci će biti izgubljeni."</string>
    -     <string name="lockscreen_failed_attempts_almost_at_wipe" product="tv" msgid="950408382418270260">"Pokušali ste da otključate TV netačno <xliff:g id="NUMBER_0">%1$d</xliff:g> puta. Posle još <xliff:g id="NUMBER_1">%2$d</xliff:g> neuspešna(ih) pokušaja TV će biti resetovan na podrazumevana fabrička podešavanja i svi korisnički podaci će biti izgubljeni."</string>
    -     <string name="lockscreen_failed_attempts_almost_at_wipe" product="default" msgid="8603565142156826565">"Neispravno ste pokušali da otključate telefon <xliff:g id="NUMBER_0">%1$d</xliff:g> puta. Nakon još neuspešnih pokušaja (<xliff:g id="NUMBER_1">%2$d</xliff:g>) telefon će biti resetovan na fabrička podešavanja i svi korisnički podaci će biti izgubljeni."</string>
    -     <string name="lockscreen_failed_attempts_now_wiping" product="tablet" msgid="280873516493934365">"Neispravno ste pokušali da otključate tablet <xliff:g id="NUMBER">%d</xliff:g> puta. Tablet će sada biti vraćen na podrazumevana fabrička podešavanja."</string>
    -     <string name="lockscreen_failed_attempts_now_wiping" product="tv" msgid="3195755534096192191">"Pokušali ste da otključate TV netačno <xliff:g id="NUMBER">%d</xliff:g> puta. TV će sada biti resetovan na podrazumevana fabrička podešavanja."</string>
    -     <string name="lockscreen_failed_attempts_now_wiping" product="default" msgid="3025504721764922246">"Neispravno ste pokušali da otključate telefon <xliff:g id="NUMBER">%d</xliff:g> puta. Telefon će sada biti vraćen na podrazumevana fabrička podešavanja."</string>
    --    <string name="lockscreen_too_many_failed_attempts_countdown" msgid="6251480343394389665">"Pokušajte ponovo za <xliff:g id="NUMBER">%d</xliff:g> sekunde(i)."</string>
    -+    <string name="lockscreen_too_many_failed_attempts_countdown" msgid="6251480343394389665">"Probajte ponovo za <xliff:g id="NUMBER">%d</xliff:g> sekunde(i)."</string>
    -     <string name="lockscreen_forgot_pattern_button_text" msgid="2626999449610695930">"Zaboravili ste šablon?"</string>
    -     <string name="lockscreen_glogin_forgot_pattern" msgid="2588521501166032747">"Otključavanje naloga"</string>
    -     <string name="lockscreen_glogin_too_many_attempts" msgid="2751368605287288808">"Previše pokušaja unosa šablona"</string>
    -@@ -1101,6 +1102,17 @@
    -     <skip />
    -     <string name="wifi_no_internet" msgid="8451173622563841546">"Wi-Fi nema pristup internetu"</string>
    -     <string name="wifi_no_internet_detailed" msgid="8083079241212301741">"Dodirnite za opcije"</string>
    -+    <string name="network_switch_metered" msgid="4671730921726992671">"Prešli ste na tip mreže <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
    -+    <string name="network_switch_metered_detail" msgid="5325661434777870353">"Uređaj koristi tip mreže <xliff:g id="NEW_NETWORK">%1$s</xliff:g> kada tip mreže <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> nema pristup internetu. Možda će se naplaćivati troškovi."</string>
    -+    <string name="network_switch_metered_toast" msgid="5779283181685974304">"Prešli ste sa tipa mreže <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> na tip mreže <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
    -+  <string-array name="network_switch_type_name">
    -+    <item msgid="2952042958050315394">"mobilni podaci"</item>
    -+    <item msgid="75483255295529161">"Wi-Fi"</item>
    -+    <item msgid="6862614801537202646">"Bluetooth"</item>
    -+    <item msgid="5447331121797802871">"Eternet"</item>
    -+    <item msgid="8257233890381651999">"VPN"</item>
    -+  </string-array>
    -+    <string name="network_switch_type_name_unknown" msgid="4552612897806660656">"nepoznat tip mreže"</string>
    -     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Nije moguće povezati sa Wi-Fi mrežom"</string>
    -     <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" ima lošu internet vezu."</string>
    -     <string name="wifi_connect_alert_title" msgid="8455846016001810172">"Želite li da dozvolite povezivanje?"</string>
    -@@ -1172,13 +1184,12 @@
    -     <string name="share_remote_bugreport_action" msgid="6249476773913384948">"DELI"</string>
    -     <string name="decline_remote_bugreport_action" msgid="6230987241608770062">"ODBIJ"</string>
    -     <string name="select_input_method" msgid="8547250819326693584">"Promenite tastaturu"</string>
    --    <string name="show_ime" msgid="2506087537466597099">"Zadrži ga na ekranu dok je fizička tastatura aktivna"</string>
    -+    <string name="show_ime" msgid="2506087537466597099">"Zadrži je na ekranu dok je fizička tastatura aktivna"</string>
    -     <string name="hardware" msgid="194658061510127999">"Prikaži virtuelnu tastaturu"</string>
    -     <string name="select_keyboard_layout_notification_title" msgid="597189518763083494">"Konfigurišite fizičku tastaturu"</string>
    -     <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"Dodirnite da biste izabrali jezik i raspored"</string>
    -     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
    -     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
    --    <string name="candidates_style" msgid="4333913089637062257"><u>"kandidati"</u></string>
    -     <string name="ext_media_checking_notification_title" msgid="5734005953288045806">"<xliff:g id="NAME">%s</xliff:g> se priprema"</string>
    -     <string name="ext_media_checking_notification_message" msgid="4747432538578886744">"Proverava se da li postoje greške"</string>
    -     <string name="ext_media_new_notification_message" msgid="7589986898808506239">"Novi uređaj <xliff:g id="NAME">%s</xliff:g> je otkriven"</string>
    -@@ -1257,8 +1268,9 @@
    -     <string name="vpn_text_long" msgid="4907843483284977618">"Povezano sa sesijom <xliff:g id="SESSION">%s</xliff:g>. Dodirnite da biste upravljali mrežom."</string>
    -     <string name="vpn_lockdown_connecting" msgid="6443438964440960745">"Povezivanje stalno uključenog VPN-a..."</string>
    -     <string name="vpn_lockdown_connected" msgid="8202679674819213931">"Stalno uključeni VPN je povezan"</string>
    -+    <string name="vpn_lockdown_disconnected" msgid="4532298952570796327">"Veza sa stalno uključenim VPN-om je prekinuta"</string>
    -     <string name="vpn_lockdown_error" msgid="6009249814034708175">"Greška stalno uključenog VPN-a"</string>
    --    <string name="vpn_lockdown_config" msgid="4655589351146766608">"Dodirnite da biste konfigurisali"</string>
    -+    <string name="vpn_lockdown_config" msgid="5099330695245008680">"Dodirnite da biste podesili"</string>
    -     <string name="upload_file" msgid="2897957172366730416">"Odaberi datoteku"</string>
    -     <string name="no_file_chosen" msgid="6363648562170759465">"Nije izabrana nijedna datoteka"</string>
    -     <string name="reset" msgid="2448168080964209908">"Ponovo postavi"</string>
    -@@ -1343,7 +1355,7 @@
    -     <string name="storage_usb_drive_label" msgid="4501418548927759953">"<xliff:g id="MANUFACTURER">%s</xliff:g> USB disk"</string>
    -     <string name="storage_usb" msgid="3017954059538517278">"USB memorija"</string>
    -     <string name="extract_edit_menu_button" msgid="8940478730496610137">"Izmeni"</string>
    --    <string name="data_usage_warning_title" msgid="1955638862122232342">"Upozorenje o potrošnji podataka"</string>
    -+    <string name="data_usage_warning_title" msgid="3620440638180218181">"Obaveštenje o potrošnji podataka"</string>
    -     <string name="data_usage_warning_body" msgid="6660692274311972007">"Dodirnite za potrošnju i podešavanja."</string>
    -     <string name="data_usage_3g_limit_title" msgid="4361523876818447683">"Nema više 2G-3G podataka"</string>
    -     <string name="data_usage_4g_limit_title" msgid="4609566827219442376">"Nema više 4G podataka"</string>
    -@@ -1409,7 +1421,7 @@
    -     <string name="kg_wrong_pattern" msgid="1850806070801358830">"Pogrešan šablon"</string>
    -     <string name="kg_wrong_password" msgid="2333281762128113157">"Pogrešna lozinka"</string>
    -     <string name="kg_wrong_pin" msgid="1131306510833563801">"Pogrešan PIN"</string>
    --    <string name="kg_too_many_failed_attempts_countdown" msgid="6358110221603297548">"Pokušajte ponovo za <xliff:g id="NUMBER">%1$d</xliff:g> sekunde(i)."</string>
    -+    <string name="kg_too_many_failed_attempts_countdown" msgid="6358110221603297548">"Probajte ponovo za <xliff:g id="NUMBER">%1$d</xliff:g> sekunde(i)."</string>
    -     <string name="kg_pattern_instructions" msgid="398978611683075868">"Nacrtajte šablon"</string>
    -     <string name="kg_sim_pin_instructions" msgid="2319508550934557331">"Unesite PIN SIM kartice"</string>
    -     <string name="kg_pin_instructions" msgid="2377242233495111557">"Unesite PIN"</string>
    -@@ -1431,18 +1443,18 @@
    -     <string name="kg_login_invalid_input" msgid="5754664119319872197">"Nevažeće korisničko ime ili lozinka."</string>
    -     <string name="kg_login_account_recovery_hint" msgid="5690709132841752974">"Zaboravili ste korisničko ime ili lozinku?\nPosetite adresu "<b>"google.com/accounts/recovery"</b>"."</string>
    -     <string name="kg_login_checking_password" msgid="1052685197710252395">"Provera naloga…"</string>
    --    <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"Uneli ste netačni PIN <xliff:g id="NUMBER_0">%1$d</xliff:g> puta. \n\nPokušajte ponovo za <xliff:g id="NUMBER_1">%2$d</xliff:g> sekunde(i)."</string>
    --    <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"Uneli ste netačnu lozinku <xliff:g id="NUMBER_0">%1$d</xliff:g> puta. \n\nPokušajte ponovo za <xliff:g id="NUMBER_1">%2$d</xliff:g> sekunde(i)."</string>
    --    <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"Nacrtali ste šablon za otključavanje netačno <xliff:g id="NUMBER_0">%1$d</xliff:g> puta. \n\nPokušajte ponovo za <xliff:g id="NUMBER_1">%2$d</xliff:g> sekunde(i)."</string>
    -+    <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"Uneli ste netačni PIN <xliff:g id="NUMBER_0">%1$d</xliff:g> puta. \n\nProbajte ponovo za <xliff:g id="NUMBER_1">%2$d</xliff:g> sekunde(i)."</string>
    -+    <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"Uneli ste netačnu lozinku <xliff:g id="NUMBER_0">%1$d</xliff:g> puta. \n\nProbajte ponovo za <xliff:g id="NUMBER_1">%2$d</xliff:g> sekunde(i)."</string>
    -+    <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"Nacrtali ste šablon za otključavanje netačno <xliff:g id="NUMBER_0">%1$d</xliff:g> puta. \n\nProbajte ponovo za <xliff:g id="NUMBER_1">%2$d</xliff:g> sekunde(i)."</string>
    -     <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="1575557200627128949">"Pokušali ste da otključate tablet netačno <xliff:g id="NUMBER_0">%1$d</xliff:g> puta. Nakon još <xliff:g id="NUMBER_1">%2$d</xliff:g> neuspešna(ih) pokušaja tablet će biti resetovan na fabrička podešavanja i svi korisnički podaci će biti izgubljeni."</string>
    -     <string name="kg_failed_attempts_almost_at_wipe" product="tv" msgid="5621231220154419413">"Pokušali ste da otključate TV netačno <xliff:g id="NUMBER_0">%1$d</xliff:g> puta. Posle još <xliff:g id="NUMBER_1">%2$d</xliff:g> neuspešna(ih) pokušaja TV će biti resetovan na podrazumevana fabrička podešavanja i svi korisnički podaci će biti izgubljeni."</string>
    -     <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4051015943038199910">"Pokušali ste da otključate telefon netačno <xliff:g id="NUMBER_0">%1$d</xliff:g> puta. Posle još <xliff:g id="NUMBER_1">%2$d</xliff:g> neuspešna(ih) pokušaja telefon će biti resetovan na fabrička podešavanja i svi korisnički podaci će biti izgubljeni."</string>
    -     <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="2072996269148483637">"Pokušali ste da otključate tablet netačno <xliff:g id="NUMBER">%d</xliff:g> puta. Tablet će sada biti vraćen na podrazumevana fabrička podešavanja."</string>
    -     <string name="kg_failed_attempts_now_wiping" product="tv" msgid="4987878286750741463">"Pokušali ste da otključate TV netačno <xliff:g id="NUMBER">%d</xliff:g> puta. TV će sada biti resetovan na podrazumevana fabrička podešavanja."</string>
    -     <string name="kg_failed_attempts_now_wiping" product="default" msgid="4817627474419471518">"Pokušali ste da otključate telefon netačno <xliff:g id="NUMBER">%d</xliff:g> puta. Telefon će sada biti vraćen na podrazumevana fabrička podešavanja."</string>
    --    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"Nacrtali ste šablon za otključavanje netačno <xliff:g id="NUMBER_0">%1$d</xliff:g> puta. Posle još <xliff:g id="NUMBER_1">%2$d</xliff:g> neuspešna(ih) pokušaja, od vas će biti zatraženo da otključate tablet pomoću naloga e-pošte.\n\nPokušajte ponovo za <xliff:g id="NUMBER_2">%3$d</xliff:g> sekunde(i)."</string>
    --    <string name="kg_failed_attempts_almost_at_login" product="tv" msgid="4224651132862313471">"Neispravno ste nacrtali šablon za otključavanje <xliff:g id="NUMBER_0">%1$d</xliff:g> puta. Posle još <xliff:g id="NUMBER_1">%2$d</xliff:g> neuspešna(ih) pokušaja, od vas će biti zatraženo da otključate TV pomoću naloga e-pošte.\n\n Pokušajte ponovo za <xliff:g id="NUMBER_2">%3$d</xliff:g> sek."</string>
    --    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Nacrtali ste šablon za otključavanje netačno <xliff:g id="NUMBER_0">%1$d</xliff:g> puta. Posle još <xliff:g id="NUMBER_1">%2$d</xliff:g> neuspešna(ih) pokušaja, od vas će biti zatraženo da otključate telefon pomoću naloga e-pošte.\n\nPokušajte ponovo za <xliff:g id="NUMBER_2">%3$d</xliff:g> sekunde(i)."</string>
    -+    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"Nacrtali ste šablon za otključavanje netačno <xliff:g id="NUMBER_0">%1$d</xliff:g> puta. Posle još <xliff:g id="NUMBER_1">%2$d</xliff:g> neuspešna(ih) pokušaja, od vas će biti zatraženo da otključate tablet pomoću naloga e-pošte.\n\nProbajte ponovo za <xliff:g id="NUMBER_2">%3$d</xliff:g> sekunde(i)."</string>
    -+    <string name="kg_failed_attempts_almost_at_login" product="tv" msgid="4224651132862313471">"Neispravno ste nacrtali šablon za otključavanje <xliff:g id="NUMBER_0">%1$d</xliff:g> puta. Posle još <xliff:g id="NUMBER_1">%2$d</xliff:g> neuspešna(ih) pokušaja, od vas će biti zatraženo da otključate TV pomoću naloga e-pošte.\n\n Probajte ponovo za <xliff:g id="NUMBER_2">%3$d</xliff:g> sek."</string>
    -+    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Nacrtali ste šablon za otključavanje netačno <xliff:g id="NUMBER_0">%1$d</xliff:g> puta. Posle još <xliff:g id="NUMBER_1">%2$d</xliff:g> neuspešna(ih) pokušaja, od vas će biti zatraženo da otključate telefon pomoću naloga e-pošte.\n\nProbajte ponovo za <xliff:g id="NUMBER_2">%3$d</xliff:g> sekunde(i)."</string>
    -     <string name="kg_text_message_separator" product="default" msgid="4160700433287233771">" – "</string>
    -     <string name="kg_reordering_delete_drop_target_text" msgid="7899202978204438708">"Ukloni"</string>
    -     <string name="safe_media_volume_warning" product="default" msgid="2276318909314492312">"Želite da pojačate zvuk iznad preporučenog nivoa?\n\nSlušanje glasne muzike duže vreme može da vam ošteti sluh."</string>
    -@@ -1553,14 +1565,14 @@
    -     <string name="restr_pin_enter_new_pin" msgid="5959606691619959184">"Novi PIN"</string>
    -     <string name="restr_pin_confirm_pin" msgid="8501523829633146239">"Potvrdite novi PIN"</string>
    -     <string name="restr_pin_create_pin" msgid="8017600000263450337">"Napravite PIN za izmenu ograničenja"</string>
    --    <string name="restr_pin_error_doesnt_match" msgid="2224214190906994548">"PIN-ovi se ne podudaraju. Pokušajte ponovo."</string>
    -+    <string name="restr_pin_error_doesnt_match" msgid="2224214190906994548">"PIN-ovi se ne podudaraju. Probajte ponovo."</string>
    -     <string name="restr_pin_error_too_short" msgid="8173982756265777792">"PIN je prekratak. Mora da sadrži najmanje 4 cifre."</string>
    -     <plurals name="restr_pin_countdown" formatted="false" msgid="9061246974881224688">
    --      <item quantity="one">Pokušajte ponovo za <xliff:g id="COUNT">%d</xliff:g> sekundu</item>
    --      <item quantity="few">Pokušajte ponovo za <xliff:g id="COUNT">%d</xliff:g> sekunde</item>
    --      <item quantity="other">Pokušajte ponovo za <xliff:g id="COUNT">%d</xliff:g> sekundi</item>
    -+      <item quantity="one">Probajte ponovo za <xliff:g id="COUNT">%d</xliff:g> sekundu</item>
    -+      <item quantity="few">Probajte ponovo za <xliff:g id="COUNT">%d</xliff:g> sekunde</item>
    -+      <item quantity="other">Probajte ponovo za <xliff:g id="COUNT">%d</xliff:g> sekundi</item>
    -     </plurals>
    --    <string name="restr_pin_try_later" msgid="973144472490532377">"Pokušajte ponovo kasnije"</string>
    -+    <string name="restr_pin_try_later" msgid="973144472490532377">"Probajte ponovo kasnije"</string>
    -     <string name="immersive_cling_title" msgid="8394201622932303336">"Prikazuje se ceo ekran"</string>
    -     <string name="immersive_cling_description" msgid="3482371193207536040">"Da biste izašli, prevucite nadole odozgo."</string>
    -     <string name="immersive_cling_positive" msgid="5016839404568297683">"Važi"</string>
    -@@ -1672,6 +1684,7 @@
    -     <string name="search_language_hint" msgid="7042102592055108574">"Unesite naziv jezika"</string>
    -     <string name="language_picker_section_suggested" msgid="8414489646861640885">"Predloženi"</string>
    -     <string name="language_picker_section_all" msgid="3097279199511617537">"Svi jezici"</string>
    -+    <string name="region_picker_section_all" msgid="8966316787153001779">"Svi regioni"</string>
    -     <string name="locale_search_menu" msgid="2560710726687249178">"Pretraži"</string>
    -     <string name="work_mode_off_title" msgid="8954725060677558855">"Režim za Work je ISKLJUČEN"</string>
    -     <string name="work_mode_off_message" msgid="3286169091278094476">"Dozvoljava profilu za Work da funkcioniše, uključujući aplikacije, sinhronizaciju u pozadini i srodne funkcije."</string>
    -diff --git a/core/res/res/values-be-rBY/strings.xml b/core/res/res/values-be-rBY/strings.xml
    -index 237820c..cadc0bc 100644
    ---- a/core/res/res/values-be-rBY/strings.xml
    -+++ b/core/res/res/values-be-rBY/strings.xml
    -@@ -218,6 +218,7 @@
    -     <string name="global_actions" product="default" msgid="2406416831541615258">"Параметры тэлефона"</string>
    -     <string name="global_action_lock" msgid="2844945191792119712">"Блакіроўка экрана"</string>
    -     <string name="global_action_power_off" msgid="4471879440839879722">"Выключыць"</string>
    -+    <string name="global_action_emergency" msgid="7112311161137421166">"SOS-выклік"</string>
    -     <string name="global_action_bug_report" msgid="7934010578922304799">"Справаздача пра памылкі"</string>
    -     <string name="bugreport_title" msgid="2667494803742548533">"Справаздача пра памылку"</string>
    -     <string name="bugreport_message" msgid="398447048750350456">"Будзе збiрацца iнфармацыя пра бягучы стан прылады, якая будзе адпраўляцца на электронную пошту. Стварэнне справаздачы пра памылкi зойме некаторы час."</string>
    -@@ -1126,6 +1127,17 @@
    -     <skip />
    -     <string name="wifi_no_internet" msgid="8451173622563841546">"У Wi-Fi няма доступу да Інтэрнэту"</string>
    -     <string name="wifi_no_internet_detailed" msgid="8083079241212301741">"Дакраніцеся, каб убачыць параметры"</string>
    -+    <string name="network_switch_metered" msgid="4671730921726992671">"Выкананы пераход да <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
    -+    <string name="network_switch_metered_detail" msgid="5325661434777870353">"Прылада выкарыстоўвае <xliff:g id="NEW_NETWORK">%1$s</xliff:g>, калі ў <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> няма доступу да інтэрнэту. Можа спаганяцца дадатковая плата."</string>
    -+    <string name="network_switch_metered_toast" msgid="5779283181685974304">"Выкананы пераход з <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> да <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
    -+  <string-array name="network_switch_type_name">
    -+    <item msgid="2952042958050315394">"сотавая перадача даных"</item>
    -+    <item msgid="75483255295529161">"Wi-Fi"</item>
    -+    <item msgid="6862614801537202646">"Bluetooth"</item>
    -+    <item msgid="5447331121797802871">"Ethernet"</item>
    -+    <item msgid="8257233890381651999">"VPN"</item>
    -+  </string-array>
    -+    <string name="network_switch_type_name_unknown" msgid="4552612897806660656">"невядомы тып сеткі"</string>
    -     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Немагчыма падключыцца да Wi-Fi"</string>
    -     <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" дрэннае падключэнне да Інтэрнэту."</string>
    -     <string name="wifi_connect_alert_title" msgid="8455846016001810172">"Дазволіць падключэнне?"</string>
    -@@ -1203,7 +1215,6 @@
    -     <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"Дакраніцеся, каб выбраць мову і раскладку"</string>
    -     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" АБВГДЕЁЖЗІЙКЛМНОПРСТУЎФХЦЧШ\'ЫЬЭЮЯ"</string>
    -     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
    --    <string name="candidates_style" msgid="4333913089637062257"><u>"кандыдат."</u></string>
    -     <string name="ext_media_checking_notification_title" msgid="5734005953288045806">"Падрыхтоўка <xliff:g id="NAME">%s</xliff:g>"</string>
    -     <string name="ext_media_checking_notification_message" msgid="4747432538578886744">"Праверка на наяўнасць памылак"</string>
    -     <string name="ext_media_new_notification_message" msgid="7589986898808506239">"Выяўлены новы носьбіт <xliff:g id="NAME">%s</xliff:g>"</string>
    -@@ -1282,8 +1293,9 @@
    -     <string name="vpn_text_long" msgid="4907843483284977618">"Падлучаны да <xliff:g id="SESSION">%s</xliff:g>. Націсніце, каб кiраваць сеткай."</string>
    -     <string name="vpn_lockdown_connecting" msgid="6443438964440960745">"Падключэнне заўсёды ўключанага VPN..."</string>
    -     <string name="vpn_lockdown_connected" msgid="8202679674819213931">"Заўсёды ўключаны i падключаны VPN"</string>
    -+    <string name="vpn_lockdown_disconnected" msgid="4532298952570796327">"Заўсёды ўключаны VPN адключаны"</string>
    -     <string name="vpn_lockdown_error" msgid="6009249814034708175">"Памылка заўсёды ўключанага VPN"</string>
    --    <string name="vpn_lockdown_config" msgid="4655589351146766608">"Дакраніцеся, каб сканфігураваць"</string>
    -+    <string name="vpn_lockdown_config" msgid="5099330695245008680">"Дакраніцеся, каб наладзіць"</string>
    -     <string name="upload_file" msgid="2897957172366730416">"Выберыце файл"</string>
    -     <string name="no_file_chosen" msgid="6363648562170759465">"Файл не выбраны"</string>
    -     <string name="reset" msgid="2448168080964209908">"Скінуць"</string>
    -@@ -1369,7 +1381,7 @@
    -     <string name="storage_usb_drive_label" msgid="4501418548927759953">"USB-дыск <xliff:g id="MANUFACTURER">%s</xliff:g>"</string>
    -     <string name="storage_usb" msgid="3017954059538517278">"USB-назапашвальнік"</string>
    -     <string name="extract_edit_menu_button" msgid="8940478730496610137">"Рэдагаваць"</string>
    --    <string name="data_usage_warning_title" msgid="1955638862122232342">"Папярэджанне выкарыстання дадзеных"</string>
    -+    <string name="data_usage_warning_title" msgid="3620440638180218181">"Абвестка аб выкарыстанні трафіка"</string>
    -     <string name="data_usage_warning_body" msgid="6660692274311972007">"Прагляд выкарыстання і налад."</string>
    -     <string name="data_usage_3g_limit_title" msgid="4361523876818447683">"Дасягнуты ліміт трафіку 2G-3G"</string>
    -     <string name="data_usage_4g_limit_title" msgid="4609566827219442376">"Дасягнуты ліміт трафіку 4G"</string>
    -@@ -1708,6 +1720,7 @@
    -     <string name="search_language_hint" msgid="7042102592055108574">"Увядзіце назву мовы"</string>
    -     <string name="language_picker_section_suggested" msgid="8414489646861640885">"Прапанаваныя"</string>
    -     <string name="language_picker_section_all" msgid="3097279199511617537">"Усе мовы"</string>
    -+    <string name="region_picker_section_all" msgid="8966316787153001779">"Усе рэгіёны"</string>
    -     <string name="locale_search_menu" msgid="2560710726687249178">"Шукаць"</string>
    -     <string name="work_mode_off_title" msgid="8954725060677558855">"Рэжым працы АДКЛЮЧАНЫ"</string>
    -     <string name="work_mode_off_message" msgid="3286169091278094476">"Дазволіць функцыянаванне працоўнага профілю, у тым ліку праграм, фонавай сінхранізацыі і звязаных з імі функцый."</string>
    -diff --git a/core/res/res/values-bg/strings.xml b/core/res/res/values-bg/strings.xml
    -index 098a1a5..4d8915b 100644
    ---- a/core/res/res/values-bg/strings.xml
    -+++ b/core/res/res/values-bg/strings.xml
    -@@ -214,6 +214,7 @@
    -     <string name="global_actions" product="default" msgid="2406416831541615258">"Опции на телефона"</string>
    -     <string name="global_action_lock" msgid="2844945191792119712">"Заключване на екрана"</string>
    -     <string name="global_action_power_off" msgid="4471879440839879722">"Изключване"</string>
    -+    <string name="global_action_emergency" msgid="7112311161137421166">"Спешно обаждане"</string>
    -     <string name="global_action_bug_report" msgid="7934010578922304799">"Сигнал за програмна грешка"</string>
    -     <string name="bugreport_title" msgid="2667494803742548533">"Сигнал за програмна грешка"</string>
    -     <string name="bugreport_message" msgid="398447048750350456">"По този начин ще се събере информация за текущото състояние на устройството ви, която да се изпрати като имейл съобщение. След стартирането на процеса ще мине известно време, докато сигналът за програмна грешка бъде готов за подаване. Моля, имайте търпение."</string>
    -@@ -1076,6 +1077,17 @@
    -     <skip />
    -     <string name="wifi_no_internet" msgid="8451173622563841546">"Wi-Fi мрежата няма достъп до интернет"</string>
    -     <string name="wifi_no_internet_detailed" msgid="8083079241212301741">"Докоснете за опции"</string>
    -+    <string name="network_switch_metered" msgid="4671730921726992671">"Превключи се към <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
    -+    <string name="network_switch_metered_detail" msgid="5325661434777870353">"Устройството използва <xliff:g id="NEW_NETWORK">%1$s</xliff:g>, когато <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> няма достъп до интернет. Възможно е да бъдете таксувани."</string>
    -+    <string name="network_switch_metered_toast" msgid="5779283181685974304">"Превключи се от <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> към <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
    -+  <string-array name="network_switch_type_name">
    -+    <item msgid="2952042958050315394">"мобилни данни"</item>
    -+    <item msgid="75483255295529161">"Wi-Fi"</item>
    -+    <item msgid="6862614801537202646">"Bluetooth"</item>
    -+    <item msgid="5447331121797802871">"Ethernet"</item>
    -+    <item msgid="8257233890381651999">"виртуална частна мрежа (VPN)"</item>
    -+  </string-array>
    -+    <string name="network_switch_type_name_unknown" msgid="4552612897806660656">"неизвестен тип мрежа"</string>
    -     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Не можа да се свърже с Wi-Fi"</string>
    -     <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" има лоша връзка с интернет."</string>
    -     <string name="wifi_connect_alert_title" msgid="8455846016001810172">"Да се разреши ли връзката?"</string>
    -@@ -1153,7 +1165,6 @@
    -     <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"Докоснете, за да изберете език и подредба"</string>
    -     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
    -     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
    --    <string name="candidates_style" msgid="4333913089637062257"><u>"кандидати"</u></string>
    -     <string name="ext_media_checking_notification_title" msgid="5734005953288045806">"<xliff:g id="NAME">%s</xliff:g>: Подготвя се"</string>
    -     <string name="ext_media_checking_notification_message" msgid="4747432538578886744">"Проверява се за грешки"</string>
    -     <string name="ext_media_new_notification_message" msgid="7589986898808506239">"Открито е ново хранилище (<xliff:g id="NAME">%s</xliff:g>)"</string>
    -@@ -1232,8 +1243,9 @@
    -     <string name="vpn_text_long" msgid="4907843483284977618">"Свързана с/ъс <xliff:g id="SESSION">%s</xliff:g>. Докоснете, за да управлявате мрежата."</string>
    -     <string name="vpn_lockdown_connecting" msgid="6443438964440960745">"Установява се връзка с винаги включената виртуална частна мрежа (VPN)…"</string>
    -     <string name="vpn_lockdown_connected" msgid="8202679674819213931">"Установена е връзка с винаги включената виртуална частна мрежа (VPN)"</string>
    -+    <string name="vpn_lockdown_disconnected" msgid="4532298952570796327">"Няма връзка с винаги включената виртуална частна мрежа (VPN)"</string>
    -     <string name="vpn_lockdown_error" msgid="6009249814034708175">"Грешка във винаги включената виртуална частна мрежа (VPN)"</string>
    --    <string name="vpn_lockdown_config" msgid="4655589351146766608">"Докоснете, за да конфигурирате"</string>
    -+    <string name="vpn_lockdown_config" msgid="5099330695245008680">"Докоснете, за да настроите"</string>
    -     <string name="upload_file" msgid="2897957172366730416">"Избор на файл"</string>
    -     <string name="no_file_chosen" msgid="6363648562170759465">"Няма избран файл"</string>
    -     <string name="reset" msgid="2448168080964209908">"Повторно задаване"</string>
    -@@ -1317,7 +1329,7 @@
    -     <string name="storage_usb_drive_label" msgid="4501418548927759953">"USB устройство от <xliff:g id="MANUFACTURER">%s</xliff:g>"</string>
    -     <string name="storage_usb" msgid="3017954059538517278">"USB хранилище"</string>
    -     <string name="extract_edit_menu_button" msgid="8940478730496610137">"Редактиране"</string>
    --    <string name="data_usage_warning_title" msgid="1955638862122232342">"Предупрежд. за ползване на данни"</string>
    -+    <string name="data_usage_warning_title" msgid="3620440638180218181">"Сигнал за преноса на данни"</string>
    -     <string name="data_usage_warning_body" msgid="6660692274311972007">"Пренос и настройки: Докоснете за преглед."</string>
    -     <string name="data_usage_3g_limit_title" msgid="4361523876818447683">"Достигнат лимит за 2G/3G данните"</string>
    -     <string name="data_usage_4g_limit_title" msgid="4609566827219442376">"Достигнат лимит за 4G данните"</string>
    -@@ -1636,6 +1648,7 @@
    -     <string name="search_language_hint" msgid="7042102592055108574">"Въведете име на език"</string>
    -     <string name="language_picker_section_suggested" msgid="8414489646861640885">"Предложени"</string>
    -     <string name="language_picker_section_all" msgid="3097279199511617537">"Всички езици"</string>
    -+    <string name="region_picker_section_all" msgid="8966316787153001779">"Всички региони"</string>
    -     <string name="locale_search_menu" msgid="2560710726687249178">"Търсене"</string>
    -     <string name="work_mode_off_title" msgid="8954725060677558855">"Работният режим е ИЗКЛЮЧЕН"</string>
    -     <string name="work_mode_off_message" msgid="3286169091278094476">"Разрешаване на функционирането на служебния потребителски профил, включително приложенията, синхронизирането на заден план и свързаните функции."</string>
    -diff --git a/core/res/res/values-bn-rBD/strings.xml b/core/res/res/values-bn-rBD/strings.xml
    -index c9e921a..8d893e5 100644
    ---- a/core/res/res/values-bn-rBD/strings.xml
    -+++ b/core/res/res/values-bn-rBD/strings.xml
    -@@ -214,8 +214,9 @@
    -     <string name="global_actions" product="default" msgid="2406416831541615258">"ফোন বিকল্পগুলি"</string>
    -     <string name="global_action_lock" msgid="2844945191792119712">"স্ক্রীণ লক"</string>
    -     <string name="global_action_power_off" msgid="4471879440839879722">"পাওয়ার বন্ধ করুন"</string>
    -+    <string name="global_action_emergency" msgid="7112311161137421166">"জরুরী"</string>
    -     <string name="global_action_bug_report" msgid="7934010578922304799">"ত্রুটির প্রতিবেদন"</string>
    --    <string name="bugreport_title" msgid="2667494803742548533">"ত্রুটির প্রতিবেদন করুন"</string>
    -+    <string name="bugreport_title" msgid="2667494803742548533">"ত্রুটির অভিযোগ করুন"</string>
    -     <string name="bugreport_message" msgid="398447048750350456">"এটি একটি ই-মেল বার্তা পাঠানোর জন্য আপনার ডিভাইসের বর্তমান অবস্থা সম্পর্কে তথ্য সংগ্রহ করবে৷ ত্রুটির প্রতিবেদন শুরুর সময় থেকে এটি পাঠানোর জন্য প্রস্তুত হতে কিছুটা সময় নেবে; দয়া করে ধৈর্য রাখুন৷"</string>
    -     <string name="bugreport_option_interactive_title" msgid="8635056131768862479">"ইন্টারেক্টিভ প্রতিবেদন"</string>
    -     <string name="bugreport_option_interactive_summary" msgid="229299488536107968">"বেশিরভাগ পরিস্থিতিতে এটিকে ব্যবহার করুন৷ এটি আপনাকে প্রতিবেদনের কাজ কতটা হয়েছে তার উপর নজর রাখতে দেয়, সমস্যাটির সম্পর্কে আরো অনেক কিছু লিখতে দেয় এবং স্ক্রীনশটগুলি নিতে দেয়৷ এটি হয়ত প্রতিবেদন করতে খুব বেশি সময় নেয় এমনকি কম-ব্যবহৃত বিভাগগুলি সরিয়ে দিতে পারে৷"</string>
    -@@ -1007,7 +1008,7 @@
    -     <string name="anr_application_process" msgid="6417199034861140083">"<xliff:g id="APPLICATION">%1$s</xliff:g> সাড়া দিচ্ছে না"</string>
    -     <string name="anr_process" msgid="6156880875555921105">"<xliff:g id="PROCESS">%1$s</xliff:g> প্রক্রিয়া সাড়া দিচ্ছে না"</string>
    -     <string name="force_close" msgid="8346072094521265605">"ঠিক আছে"</string>
    --    <string name="report" msgid="4060218260984795706">"প্রতিবেদন করুন"</string>
    -+    <string name="report" msgid="4060218260984795706">"অভিযোগ করুন"</string>
    -     <string name="wait" msgid="7147118217226317732">"অপেক্ষা করুন"</string>
    -     <string name="webpage_unresponsive" msgid="3272758351138122503">"পৃষ্ঠাটি কোনো পতিক্রিয়া করছে না৷\n\nআপনি কি এটিকে বন্ধ করতে চান?"</string>
    -     <string name="launch_warning_title" msgid="1547997780506713581">"অ্যাপ্লিকেশানকে পুনঃনির্দেশিত করা হয়েছে"</string>
    -@@ -1076,6 +1077,17 @@
    -     <skip />
    -     <string name="wifi_no_internet" msgid="8451173622563841546">"ওয়াই-ফাই -তে কোনো ইন্টারনেট অ্যাক্সেস নেই"</string>
    -     <string name="wifi_no_internet_detailed" msgid="8083079241212301741">"বিকল্পগুলির জন্য আলতো চাপুন"</string>
    -+    <string name="network_switch_metered" msgid="4671730921726992671">"<xliff:g id="NETWORK_TYPE">%1$s</xliff:g> এ পাল্টানো হয়েছে"</string>
    -+    <string name="network_switch_metered_detail" msgid="5325661434777870353">"যখন <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> এর কোনো ইন্টারনেট অ্যাক্সেস থাকে না তখন ডিভাইস <xliff:g id="NEW_NETWORK">%1$s</xliff:g> ব্যবহার করে৷ চার্জ লাগতে পারে৷"</string>
    -+    <string name="network_switch_metered_toast" msgid="5779283181685974304">"<xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> থেকে <xliff:g id="NEW_NETWORK">%2$s</xliff:g> এ পাল্টানো হয়েছে"</string>
    -+  <string-array name="network_switch_type_name">
    -+    <item msgid="2952042958050315394">"সেলুলার ডেটা"</item>
    -+    <item msgid="75483255295529161">"Wi-Fi"</item>
    -+    <item msgid="6862614801537202646">"Bluetooth"</item>
    -+    <item msgid="5447331121797802871">"ইথারনেট"</item>
    -+    <item msgid="8257233890381651999">"VPN"</item>
    -+  </string-array>
    -+    <string name="network_switch_type_name_unknown" msgid="4552612897806660656">"এই নেটওয়ার্কের প্রকার অজানা"</string>
    -     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"ওয়াই-ফাই এর সাথে সংযোগ করা যায়নি"</string>
    -     <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" একটি দুর্বল ইন্টারনেট সংযোগ রয়েছে৷"</string>
    -     <string name="wifi_connect_alert_title" msgid="8455846016001810172">"সংযোগের অনুমতি দেবেন?"</string>
    -@@ -1153,7 +1165,6 @@
    -     <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"ভাষা এবং লেআউট নির্বাচন করুন আলতো চাপ দিন"</string>
    -     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
    -     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
    --    <string name="candidates_style" msgid="4333913089637062257"><u>"প্রার্থীরা"</u></string>
    -     <string name="ext_media_checking_notification_title" msgid="5734005953288045806">"<xliff:g id="NAME">%s</xliff:g> প্রস্তুত করা হচ্ছে"</string>
    -     <string name="ext_media_checking_notification_message" msgid="4747432538578886744">"ত্রুটি রয়েছে কিনা পরীক্ষা করা হচ্ছে"</string>
    -     <string name="ext_media_new_notification_message" msgid="7589986898808506239">"নতুন <xliff:g id="NAME">%s</xliff:g> সনাক্ত করা হয়েছে"</string>
    -@@ -1232,8 +1243,9 @@
    -     <string name="vpn_text_long" msgid="4907843483284977618">"<xliff:g id="SESSION">%s</xliff:g> তে সংযুক্ত হয়েছে৷ নেটওয়ার্ক পরিচালনা করতে আলতো চাপুন৷"</string>
    -     <string name="vpn_lockdown_connecting" msgid="6443438964440960745">"সর্বদা-চালু VPN সংযুক্ত হচ্ছে..."</string>
    -     <string name="vpn_lockdown_connected" msgid="8202679674819213931">"সর্বদা-চালু VPN সংযুক্ত হয়েছে"</string>
    -+    <string name="vpn_lockdown_disconnected" msgid="4532298952570796327">"সর্বদা-চালু VPN এর সংযোগ বিচ্ছিন্ন হয়েছে"</string>
    -     <string name="vpn_lockdown_error" msgid="6009249814034708175">"সর্বদা-চালু VPN ত্রুটি"</string>
    --    <string name="vpn_lockdown_config" msgid="4655589351146766608">"কনফিগার করতে আলতো চাপুন"</string>
    -+    <string name="vpn_lockdown_config" msgid="5099330695245008680">"সেট আপ করতে আলতো চাপুন"</string>
    -     <string name="upload_file" msgid="2897957172366730416">"ফাইল বেছে নিন"</string>
    -     <string name="no_file_chosen" msgid="6363648562170759465">"কোনো ফাইল নির্বাচন করা হয়নি"</string>
    -     <string name="reset" msgid="2448168080964209908">"পুনরায় সেট করুন"</string>
    -@@ -1317,7 +1329,7 @@
    -     <string name="storage_usb_drive_label" msgid="4501418548927759953">"<xliff:g id="MANUFACTURER">%s</xliff:g> USB ড্রাইভ"</string>
    -     <string name="storage_usb" msgid="3017954059538517278">"USB সঞ্চয়স্থান"</string>
    -     <string name="extract_edit_menu_button" msgid="8940478730496610137">"সম্পাদনা করুন"</string>
    --    <string name="data_usage_warning_title" msgid="1955638862122232342">"ডেটা ব্যবহারের সতর্কতা"</string>
    -+    <string name="data_usage_warning_title" msgid="3620440638180218181">"ডেটা ব্যবহারের সতর্কতা"</string>
    -     <string name="data_usage_warning_body" msgid="6660692274311972007">"ব্যবহার এবং সেটিংস দেখতে আলতো চাপুন৷"</string>
    -     <string name="data_usage_3g_limit_title" msgid="4361523876818447683">"2G-3G ডেটা সীমা ছাড়িয়েছে"</string>
    -     <string name="data_usage_4g_limit_title" msgid="4609566827219442376">"4G ডেটা সীমা ছাড়িয়েছে"</string>
    -@@ -1636,6 +1648,7 @@
    -     <string name="search_language_hint" msgid="7042102592055108574">"ভাষার নাম লিখুন"</string>
    -     <string name="language_picker_section_suggested" msgid="8414489646861640885">"প্রস্তাবিত"</string>
    -     <string name="language_picker_section_all" msgid="3097279199511617537">"সকল ভাষা"</string>
    -+    <string name="region_picker_section_all" msgid="8966316787153001779">"সমস্ত অঞ্চল"</string>
    -     <string name="locale_search_menu" msgid="2560710726687249178">"অনুসন্ধান করুন"</string>
    -     <string name="work_mode_off_title" msgid="8954725060677558855">"কাজের মোড বন্ধ আছে"</string>
    -     <string name="work_mode_off_message" msgid="3286169091278094476">"অ্যাপ্লিকেশান, পটভূমি সিঙ্ক এবং সম্পর্কিত বৈশিষ্ট্যগুলি সহ কর্মস্থলের প্রোফাইলটিকে কাজ করার অনুমতি দিন।"</string>
    -diff --git a/core/res/res/values-bs-rBA/strings.xml b/core/res/res/values-bs-rBA/strings.xml
    -index 20104a6..e8a3c02 100644
    ---- a/core/res/res/values-bs-rBA/strings.xml
    -+++ b/core/res/res/values-bs-rBA/strings.xml
    -@@ -216,6 +216,7 @@
    -     <string name="global_actions" product="default" msgid="2406416831541615258">"Opcije telefona"</string>
    -     <string name="global_action_lock" msgid="2844945191792119712">"Zaključavanje ekrana"</string>
    -     <string name="global_action_power_off" msgid="4471879440839879722">"Isključi telefon"</string>
    -+    <string name="global_action_emergency" msgid="7112311161137421166">"Hitni slučaj"</string>
    -     <string name="global_action_bug_report" msgid="7934010578922304799">"Izvještaj o greškama"</string>
    -     <string name="bugreport_title" msgid="2667494803742548533">"Kreirajte izvještaj o greškama"</string>
    -     <string name="bugreport_message" msgid="398447048750350456">"Ovim će se prikupljati informacije o trenutnom stanju uređaja, koji će biti poslani kao poruka e-pošte. Može malo potrajati dok se izvještaj o greškama ne kreira i bude spreman za slanje. Budite strpljivi."</string>
    -@@ -1103,6 +1104,17 @@
    -     <skip />
    -     <string name="wifi_no_internet" msgid="8451173622563841546">"Wi-Fi nema pristup Internetu"</string>
    -     <string name="wifi_no_internet_detailed" msgid="8083079241212301741">"Dodirnite za opcije"</string>
    -+    <string name="network_switch_metered" msgid="4671730921726992671">"Prebačeno na: <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
    -+    <string name="network_switch_metered_detail" msgid="5325661434777870353">"Kada na uređaju <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> nema pristup internetu, koristi se <xliff:g id="NEW_NETWORK">%1$s</xliff:g>. Moguća je naplata usluge."</string>
    -+    <string name="network_switch_metered_toast" msgid="5779283181685974304">"Prebačeno iz mreže <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> u <xliff:g id="NEW_NETWORK">%2$s</xliff:g> mrežu"</string>
    -+  <string-array name="network_switch_type_name">
    -+    <item msgid="2952042958050315394">"mobilni podaci"</item>
    -+    <item msgid="75483255295529161">"Wi-Fi"</item>
    -+    <item msgid="6862614801537202646">"Bluetooth"</item>
    -+    <item msgid="5447331121797802871">"Ethernet"</item>
    -+    <item msgid="8257233890381651999">"VPN"</item>
    -+  </string-array>
    -+    <string name="network_switch_type_name_unknown" msgid="4552612897806660656">"nepoznata vrsta mreže"</string>
    -     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Problem prilikom spajanja na Wi-Fi mrežu"</string>
    -     <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" ima lošu internet vezu."</string>
    -     <string name="wifi_connect_alert_title" msgid="8455846016001810172">"Želite li dozvoliti povezivanje?"</string>
    -@@ -1180,7 +1192,6 @@
    -     <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"Dodirnite za odabir jezika i rasporeda"</string>
    -     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
    -     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
    --    <string name="candidates_style" msgid="4333913089637062257"><u>"kandidati"</u></string>
    -     <string name="ext_media_checking_notification_title" msgid="5734005953288045806">"Priprema se <xliff:g id="NAME">%s</xliff:g>"</string>
    -     <string name="ext_media_checking_notification_message" msgid="4747432538578886744">"Provjera grešaka"</string>
    -     <string name="ext_media_new_notification_message" msgid="7589986898808506239">"Novi uređaj <xliff:g id="NAME">%s</xliff:g> je otkriven"</string>
    -@@ -1259,8 +1270,9 @@
    -     <string name="vpn_text_long" msgid="4907843483284977618">"Povezano sa sesijom <xliff:g id="SESSION">%s</xliff:g>. Dodirnite da upravljate mrežom."</string>
    -     <string name="vpn_lockdown_connecting" msgid="6443438964440960745">"Povezivanje na uvijek aktivni VPN…"</string>
    -     <string name="vpn_lockdown_connected" msgid="8202679674819213931">"Povezan na uvijek aktivni VPN"</string>
    -+    <string name="vpn_lockdown_disconnected" msgid="4532298952570796327">"Uvijek aktivni VPN nije povezan"</string>
    -     <string name="vpn_lockdown_error" msgid="6009249814034708175">"Greška u povezivanju na uvijek aktivni VPN"</string>
    --    <string name="vpn_lockdown_config" msgid="4655589351146766608">"Dodirnite za konfiguriranje"</string>
    -+    <string name="vpn_lockdown_config" msgid="5099330695245008680">"Dodirnite za postavke"</string>
    -     <string name="upload_file" msgid="2897957172366730416">"Odabir fajla"</string>
    -     <string name="no_file_chosen" msgid="6363648562170759465">"Nije izabran nijedan fajl"</string>
    -     <string name="reset" msgid="2448168080964209908">"Ponovno pokretanje"</string>
    -@@ -1345,7 +1357,7 @@
    -     <string name="storage_usb_drive_label" msgid="4501418548927759953">"<xliff:g id="MANUFACTURER">%s</xliff:g> USB disk"</string>
    -     <string name="storage_usb" msgid="3017954059538517278">"USB pohrana"</string>
    -     <string name="extract_edit_menu_button" msgid="8940478730496610137">"Uredi"</string>
    --    <string name="data_usage_warning_title" msgid="1955638862122232342">"Upozorenje za prijenos podataka"</string>
    -+    <string name="data_usage_warning_title" msgid="3620440638180218181">"Upozorenje o prijenosu podataka"</string>
    -     <string name="data_usage_warning_body" msgid="6660692274311972007">"Dodirnite za prikaz upotrebe i postavki."</string>
    -     <string name="data_usage_3g_limit_title" msgid="4361523876818447683">"Dostignut limit za 2G-3G podatke"</string>
    -     <string name="data_usage_4g_limit_title" msgid="4609566827219442376">"Dostignut limit za 4G podatke"</string>
    -@@ -1586,7 +1598,7 @@
    -     <string name="package_updated_device_owner" msgid="8856631322440187071">"Ažurirao administrator"</string>
    -     <string name="package_deleted_device_owner" msgid="7650577387493101353">"Izbrisao administrator"</string>
    -     <string name="battery_saver_description" msgid="1960431123816253034">"Da bi se trajanje baterije produžilo, opcija za štednju baterije minimizira rad uređaja i ograničava vibriranje, usluge lokacije i većinu prijenosa podataka u pozadini. E-pošta, poruke i druge aplikacije koje se oslanjaju na sinhronizaciju ne mogu biti ažurirane dok ih ne otvorite.\n\nŠtednja baterije se automatski isključi prilikom punjenja uređaja."</string>
    --    <string name="data_saver_description" msgid="6015391409098303235">"Da bi se smanjilo korištenje podataka, usluga Ušteda podataka sprečava da neke aplikacije šalju ili primaju podatke u pozadini. Aplikacija koju trenutno koristite može pristupiti podacima, ali se to može desiti rjeđe. To može značiti, naprimjer, da se slike ne prikazuju sve dok ih ne dodirnete."</string>
    -+    <string name="data_saver_description" msgid="6015391409098303235">"Da bi se smanjio prijenos podataka, usluga Ušteda podataka sprečava da neke aplikacije šalju ili primaju podatke u pozadini. Aplikacija koju trenutno koristite može pristupiti podacima, ali se to može desiti rjeđe. To može značiti, naprimjer, da se slike ne prikazuju sve dok ih ne dodirnete."</string>
    -     <string name="data_saver_enable_title" msgid="4674073932722787417">"Uključiti Uštedu podataka?"</string>
    -     <string name="data_saver_enable_button" msgid="7147735965247211818">"Uključi"</string>
    -     <plurals name="zen_mode_duration_minutes_summary" formatted="false" msgid="4367877408072000848">
    -@@ -1674,6 +1686,7 @@
    -     <string name="search_language_hint" msgid="7042102592055108574">"Ukucajte naziv jezika"</string>
    -     <string name="language_picker_section_suggested" msgid="8414489646861640885">"Predloženo"</string>
    -     <string name="language_picker_section_all" msgid="3097279199511617537">"Svi jezici"</string>
    -+    <string name="region_picker_section_all" msgid="8966316787153001779">"Sve regije"</string>
    -     <string name="locale_search_menu" msgid="2560710726687249178">"Pretraga"</string>
    -     <string name="work_mode_off_title" msgid="8954725060677558855">"Radni način rada je ISKLJUČEN"</string>
    -     <string name="work_mode_off_message" msgid="3286169091278094476">"Omogući radnom profilu da funkcionira, uključujući aplikacije, sinhronizaciju u pozadini i povezane funkcije."</string>
    -diff --git a/core/res/res/values-ca/strings.xml b/core/res/res/values-ca/strings.xml
    -index eeed892..137d924 100644
    ---- a/core/res/res/values-ca/strings.xml
    -+++ b/core/res/res/values-ca/strings.xml
    -@@ -214,6 +214,7 @@
    -     <string name="global_actions" product="default" msgid="2406416831541615258">"Opcions del telèfon"</string>
    -     <string name="global_action_lock" msgid="2844945191792119712">"Bloqueig de pantalla"</string>
    -     <string name="global_action_power_off" msgid="4471879440839879722">"Apaga"</string>
    -+    <string name="global_action_emergency" msgid="7112311161137421166">"Emergències"</string>
    -     <string name="global_action_bug_report" msgid="7934010578922304799">"Informe d\'error"</string>
    -     <string name="bugreport_title" msgid="2667494803742548533">"Crea informe d\'errors"</string>
    -     <string name="bugreport_message" msgid="398447048750350456">"Es recopilarà informació sobre l\'estat actual del dispositiu i se t\'enviarà per correu electrònic. Passaran uns quants minuts des de l\'inici de l\'informe d\'errors fins al seu enviament, per la qual cosa et recomanem que tinguis paciència."</string>
    -@@ -1076,6 +1077,17 @@
    -     <skip />
    -     <string name="wifi_no_internet" msgid="8451173622563841546">"La Wi-Fi no té accés a Internet"</string>
    -     <string name="wifi_no_internet_detailed" msgid="8083079241212301741">"Toca per veure les opcions"</string>
    -+    <string name="network_switch_metered" msgid="4671730921726992671">"Actualment en ús: <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
    -+    <string name="network_switch_metered_detail" msgid="5325661434777870353">"El dispositiu utilitza <xliff:g id="NEW_NETWORK">%1$s</xliff:g> en cas que <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> no tingui accés a Internet. És possible que s\'apliquin càrrecs."</string>
    -+    <string name="network_switch_metered_toast" msgid="5779283181685974304">"Abans es feia servir la xarxa <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g>; ara s\'utilitza <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
    -+  <string-array name="network_switch_type_name">
    -+    <item msgid="2952042958050315394">"dades mòbils"</item>
    -+    <item msgid="75483255295529161">"Wi-Fi"</item>
    -+    <item msgid="6862614801537202646">"Bluetooth"</item>
    -+    <item msgid="5447331121797802871">"Ethernet"</item>
    -+    <item msgid="8257233890381651999">"VPN"</item>
    -+  </string-array>
    -+    <string name="network_switch_type_name_unknown" msgid="4552612897806660656">"una tipus de xarxa desconegut"</string>
    -     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"No s\'ha pogut connectar a la Wi-Fi"</string>
    -     <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" té una mala connexió a Internet."</string>
    -     <string name="wifi_connect_alert_title" msgid="8455846016001810172">"Vols permetre la connexió?"</string>
    -@@ -1153,7 +1165,6 @@
    -     <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"Toca per seleccionar l\'idioma i el disseny"</string>
    -     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
    -     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
    --    <string name="candidates_style" msgid="4333913089637062257"><u>"candidats"</u></string>
    -     <string name="ext_media_checking_notification_title" msgid="5734005953288045806">"S\'està preparant <xliff:g id="NAME">%s</xliff:g>"</string>
    -     <string name="ext_media_checking_notification_message" msgid="4747432538578886744">"S\'està comprovant si hi ha errors"</string>
    -     <string name="ext_media_new_notification_message" msgid="7589986898808506239">"S\'ha detectat <xliff:g id="NAME">%s</xliff:g>"</string>
    -@@ -1232,8 +1243,9 @@
    -     <string name="vpn_text_long" msgid="4907843483284977618">"Connectat a <xliff:g id="SESSION">%s</xliff:g>. Pica per gestionar la xarxa."</string>
    -     <string name="vpn_lockdown_connecting" msgid="6443438964440960745">"T\'estàs connectant a la VPN sempre activada…"</string>
    -     <string name="vpn_lockdown_connected" msgid="8202679674819213931">"Estàs connectat a la VPN sempre activada"</string>
    -+    <string name="vpn_lockdown_disconnected" msgid="4532298952570796327">"La VPN sempre activada està desconnectada"</string>
    -     <string name="vpn_lockdown_error" msgid="6009249814034708175">"Error de la VPN sempre activada"</string>
    --    <string name="vpn_lockdown_config" msgid="4655589351146766608">"Toca per configurar"</string>
    -+    <string name="vpn_lockdown_config" msgid="5099330695245008680">"Toca per configurar"</string>
    -     <string name="upload_file" msgid="2897957172366730416">"Trieu un fitxer"</string>
    -     <string name="no_file_chosen" msgid="6363648562170759465">"No s\'ha escollit cap fitxer"</string>
    -     <string name="reset" msgid="2448168080964209908">"Restableix"</string>
    -@@ -1317,7 +1329,7 @@
    -     <string name="storage_usb_drive_label" msgid="4501418548927759953">"Unitat USB de: <xliff:g id="MANUFACTURER">%s</xliff:g>"</string>
    -     <string name="storage_usb" msgid="3017954059538517278">"Emmagatzematge USB"</string>
    -     <string name="extract_edit_menu_button" msgid="8940478730496610137">"Edita"</string>
    --    <string name="data_usage_warning_title" msgid="1955638862122232342">"Advertiment d\'ús de dades"</string>
    -+    <string name="data_usage_warning_title" msgid="3620440638180218181">"Alerta d\'ús de dades"</string>
    -     <string name="data_usage_warning_body" msgid="6660692274311972007">"Toca per veure l\'ús i la configuració."</string>
    -     <string name="data_usage_3g_limit_title" msgid="4361523876818447683">"Límit de dades 2G-3G assolit"</string>
    -     <string name="data_usage_4g_limit_title" msgid="4609566827219442376">"Límit de dades 4G assolit"</string>
    -@@ -1636,6 +1648,7 @@
    -     <string name="search_language_hint" msgid="7042102592055108574">"Nom de l\'idioma"</string>
    -     <string name="language_picker_section_suggested" msgid="8414489646861640885">"Suggerits"</string>
    -     <string name="language_picker_section_all" msgid="3097279199511617537">"Tots els idiomes"</string>
    -+    <string name="region_picker_section_all" msgid="8966316787153001779">"Totes les regions"</string>
    -     <string name="locale_search_menu" msgid="2560710726687249178">"Cerca"</string>
    -     <string name="work_mode_off_title" msgid="8954725060677558855">"Mode de feina desactivat"</string>
    -     <string name="work_mode_off_message" msgid="3286169091278094476">"Permet que el perfil professional funcioni, incloses les aplicacions, la sincronització en segon pla i les funcions relacionades."</string>
    -diff --git a/core/res/res/values-cs/strings.xml b/core/res/res/values-cs/strings.xml
    -index df8bffd..8037681 100644
    ---- a/core/res/res/values-cs/strings.xml
    -+++ b/core/res/res/values-cs/strings.xml
    -@@ -218,6 +218,7 @@
    -     <string name="global_actions" product="default" msgid="2406416831541615258">"Možnosti telefonu"</string>
    -     <string name="global_action_lock" msgid="2844945191792119712">"Zámek obrazovky"</string>
    -     <string name="global_action_power_off" msgid="4471879440839879722">"Vypnout"</string>
    -+    <string name="global_action_emergency" msgid="7112311161137421166">"Stav nouze"</string>
    -     <string name="global_action_bug_report" msgid="7934010578922304799">"Hlášení chyb"</string>
    -     <string name="bugreport_title" msgid="2667494803742548533">"Vytvořit chybové hlášení"</string>
    -     <string name="bugreport_message" msgid="398447048750350456">"Shromažďuje informace o aktuálním stavu zařízení. Tyto informace je následně možné poslat v e-mailové zprávě, chvíli však potrvá, než bude hlášení o chybě připraveno k odeslání. Buďte prosím trpěliví."</string>
    -@@ -692,7 +693,7 @@
    -     <string name="lockscreen_missing_sim_message" product="default" msgid="2186920585695169078">"V telefonu není žádná SIM karta."</string>
    -     <string name="lockscreen_missing_sim_instructions" msgid="5372787138023272615">"Vložte SIM kartu."</string>
    -     <string name="lockscreen_missing_sim_instructions_long" msgid="3526573099019319472">"SIM karta chybí nebo je nečitelná. Vložte SIM kartu."</string>
    --    <string name="lockscreen_permanent_disabled_sim_message_short" msgid="5096149665138916184">"Nepoužitelná karta SIM."</string>
    -+    <string name="lockscreen_permanent_disabled_sim_message_short" msgid="5096149665138916184">"Nepoužitelná SIM karta."</string>
    -     <string name="lockscreen_permanent_disabled_sim_instructions" msgid="910904643433151371">"Vaše SIM karta byla natrvalo zablokována.\n Požádejte svého poskytovatele bezdrátových služeb o další SIM kartu."</string>
    -     <string name="lockscreen_transport_prev_description" msgid="6300840251218161534">"Předchozí skladba"</string>
    -     <string name="lockscreen_transport_next_description" msgid="573285210424377338">"Další skladba"</string>
    -@@ -1126,6 +1127,17 @@
    -     <skip />
    -     <string name="wifi_no_internet" msgid="8451173622563841546">"Wi-Fi nemá přístup k internetu"</string>
    -     <string name="wifi_no_internet_detailed" msgid="8083079241212301741">"Klepnutím zobrazíte možnosti"</string>
    -+    <string name="network_switch_metered" msgid="4671730921726992671">"Přechod na síť <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
    -+    <string name="network_switch_metered_detail" msgid="5325661434777870353">"Když síť <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> nebude mít přístup k internetu, zařízení použije síť <xliff:g id="NEW_NETWORK">%1$s</xliff:g>. Mohou být účtovány poplatky."</string>
    -+    <string name="network_switch_metered_toast" msgid="5779283181685974304">"Přechod ze sítě <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> na síť <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
    -+  <string-array name="network_switch_type_name">
    -+    <item msgid="2952042958050315394">"mobilní data"</item>
    -+    <item msgid="75483255295529161">"Wi-Fi"</item>
    -+    <item msgid="6862614801537202646">"Bluetooth"</item>
    -+    <item msgid="5447331121797802871">"Ethernet"</item>
    -+    <item msgid="8257233890381651999">"VPN"</item>
    -+  </string-array>
    -+    <string name="network_switch_type_name_unknown" msgid="4552612897806660656">"neznámý typ sítě"</string>
    -     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Připojení k síti Wi-Fi se nezdařilo"</string>
    -     <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" má pomalé připojení k internetu."</string>
    -     <string name="wifi_connect_alert_title" msgid="8455846016001810172">"Povolit připojení?"</string>
    -@@ -1203,7 +1215,6 @@
    -     <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"Klepnutím vyberte jazyk a rozvržení"</string>
    -     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" AÁBCČDĎEÉĚFGHCHIÍJKLMNŇOÓPQRŘSŠTŤUÚVWXYÝZŽ"</string>
    -     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789AÁBCČDĎEÉĚFGHCHIÍJKLMNŇOÓPQRŘSŠTŤUÚVWXYÝZŽ"</string>
    --    <string name="candidates_style" msgid="4333913089637062257"><u>"kandidáti"</u></string>
    -     <string name="ext_media_checking_notification_title" msgid="5734005953288045806">"Probíhá příprava úložiště <xliff:g id="NAME">%s</xliff:g>"</string>
    -     <string name="ext_media_checking_notification_message" msgid="4747432538578886744">"Kontrola chyb"</string>
    -     <string name="ext_media_new_notification_message" msgid="7589986898808506239">"Zjištěno nové úložiště <xliff:g id="NAME">%s</xliff:g>"</string>
    -@@ -1282,8 +1293,9 @@
    -     <string name="vpn_text_long" msgid="4907843483284977618">"Připojeno k relaci <xliff:g id="SESSION">%s</xliff:g>. Klepnutím můžete síť spravovat."</string>
    -     <string name="vpn_lockdown_connecting" msgid="6443438964440960745">"Připojování k trvalé síti VPN…"</string>
    -     <string name="vpn_lockdown_connected" msgid="8202679674819213931">"Je připojena trvalá síť VPN"</string>
    -+    <string name="vpn_lockdown_disconnected" msgid="4532298952570796327">"Trvalá síť VPN je odpojena"</string>
    -     <string name="vpn_lockdown_error" msgid="6009249814034708175">"Chyba trvalé sítě VPN"</string>
    --    <string name="vpn_lockdown_config" msgid="4655589351146766608">"Klepnutím zahájíte konfiguraci"</string>
    -+    <string name="vpn_lockdown_config" msgid="5099330695245008680">"Klepnutím přejděte do Nastavení"</string>
    -     <string name="upload_file" msgid="2897957172366730416">"Zvolit soubor"</string>
    -     <string name="no_file_chosen" msgid="6363648562170759465">"Není vybrán žádný soubor"</string>
    -     <string name="reset" msgid="2448168080964209908">"Resetovat"</string>
    -@@ -1369,7 +1381,7 @@
    -     <string name="storage_usb_drive_label" msgid="4501418548927759953">"Jednotka USB <xliff:g id="MANUFACTURER">%s</xliff:g>"</string>
    -     <string name="storage_usb" msgid="3017954059538517278">"Úložiště USB"</string>
    -     <string name="extract_edit_menu_button" msgid="8940478730496610137">"Upravit"</string>
    --    <string name="data_usage_warning_title" msgid="1955638862122232342">"Upozornění na využití dat"</string>
    -+    <string name="data_usage_warning_title" msgid="3620440638180218181">"Upozornění na používání dat"</string>
    -     <string name="data_usage_warning_body" msgid="6660692274311972007">"Klepnutím zobrazíte nastavení."</string>
    -     <string name="data_usage_3g_limit_title" msgid="4361523876818447683">"Dosáhli jste limitu dat 2G–3G"</string>
    -     <string name="data_usage_4g_limit_title" msgid="4609566827219442376">"Dosáhli jste limitu dat 4G"</string>
    -@@ -1708,6 +1720,7 @@
    -     <string name="search_language_hint" msgid="7042102592055108574">"Zadejte název jazyka"</string>
    -     <string name="language_picker_section_suggested" msgid="8414489646861640885">"Navrhované"</string>
    -     <string name="language_picker_section_all" msgid="3097279199511617537">"Všechny jazyky"</string>
    -+    <string name="region_picker_section_all" msgid="8966316787153001779">"Všechny oblasti"</string>
    -     <string name="locale_search_menu" msgid="2560710726687249178">"Vyhledávání"</string>
    -     <string name="work_mode_off_title" msgid="8954725060677558855">"Pracovní režim je VYPNUTÝ"</string>
    -     <string name="work_mode_off_message" msgid="3286169091278094476">"Povolí fungování pracovního profilu, včetně aplikací, synchronizace na pozadí a souvisejících funkcí."</string>
    -diff --git a/core/res/res/values-da/strings.xml b/core/res/res/values-da/strings.xml
    -index 731c847..eb4d255 100644
    ---- a/core/res/res/values-da/strings.xml
    -+++ b/core/res/res/values-da/strings.xml
    -@@ -214,6 +214,7 @@
    -     <string name="global_actions" product="default" msgid="2406416831541615258">"Indstillinger for telefon"</string>
    -     <string name="global_action_lock" msgid="2844945191792119712">"Skærmlås"</string>
    -     <string name="global_action_power_off" msgid="4471879440839879722">"Sluk"</string>
    -+    <string name="global_action_emergency" msgid="7112311161137421166">"Nødopkald"</string>
    -     <string name="global_action_bug_report" msgid="7934010578922304799">"Fejlrapport"</string>
    -     <string name="bugreport_title" msgid="2667494803742548533">"Lav fejlrapport"</string>
    -     <string name="bugreport_message" msgid="398447048750350456">"Der indsamles oplysninger om din enheds aktuelle status, der efterfølgende sendes i en e-mail. Der går lidt tid, fra fejlrapporten påbegyndes, til den er klar til at blive sendt. Tak for tålmodigheden."</string>
    -@@ -1076,6 +1077,17 @@
    -     <skip />
    -     <string name="wifi_no_internet" msgid="8451173622563841546">"Wi-Fi har ingen internetadgang"</string>
    -     <string name="wifi_no_internet_detailed" msgid="8083079241212301741">"Tryk for at se valgmuligheder"</string>
    -+    <string name="network_switch_metered" msgid="4671730921726992671">"Der blev skiftet til <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
    -+    <string name="network_switch_metered_detail" msgid="5325661434777870353">"Enheden benytter <xliff:g id="NEW_NETWORK">%1$s</xliff:g>, når <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> ikke har adgang til internettet. Der opkræves muligvis gebyr."</string>
    -+    <string name="network_switch_metered_toast" msgid="5779283181685974304">"Der blev skiftet fra <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> til <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
    -+  <string-array name="network_switch_type_name">
    -+    <item msgid="2952042958050315394">"mobildata"</item>
    -+    <item msgid="75483255295529161">"Wi-Fi"</item>
    -+    <item msgid="6862614801537202646">"Bluetooth"</item>
    -+    <item msgid="5447331121797802871">"Ethernet"</item>
    -+    <item msgid="8257233890381651999">"VPN"</item>
    -+  </string-array>
    -+    <string name="network_switch_type_name_unknown" msgid="4552612897806660656">"en ukendt netværkstype"</string>
    -     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Kunne ikke oprette forbindelse til Wi-Fi"</string>
    -     <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" har en dårlig internetforbindelse."</string>
    -     <string name="wifi_connect_alert_title" msgid="8455846016001810172">"Vil du tillade denne forbindelse?"</string>
    -@@ -1153,7 +1165,6 @@
    -     <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"Tryk for at vælge sprog og layout"</string>
    -     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
    -     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
    --    <string name="candidates_style" msgid="4333913089637062257"><u>"kandidater"</u></string>
    -     <string name="ext_media_checking_notification_title" msgid="5734005953288045806">"Forbereder <xliff:g id="NAME">%s</xliff:g>"</string>
    -     <string name="ext_media_checking_notification_message" msgid="4747432538578886744">"Kontrollerer for fejl"</string>
    -     <string name="ext_media_new_notification_message" msgid="7589986898808506239">"Der blev registreret et nyt <xliff:g id="NAME">%s</xliff:g>"</string>
    -@@ -1232,8 +1243,9 @@
    -     <string name="vpn_text_long" msgid="4907843483284977618">"Forbundet til <xliff:g id="SESSION">%s</xliff:g>. Tryk for at administrere netværket."</string>
    -     <string name="vpn_lockdown_connecting" msgid="6443438964440960745">"Opretter forbindelse til altid aktiveret VPN…"</string>
    -     <string name="vpn_lockdown_connected" msgid="8202679674819213931">"Always-on VPN er forbundet"</string>
    -+    <string name="vpn_lockdown_disconnected" msgid="4532298952570796327">"Forbindelsen til altid aktiveret VPN er afbrudt"</string>
    -     <string name="vpn_lockdown_error" msgid="6009249814034708175">"Fejl i altid aktiveret VPN"</string>
    --    <string name="vpn_lockdown_config" msgid="4655589351146766608">"Tryk for at konfigurere"</string>
    -+    <string name="vpn_lockdown_config" msgid="5099330695245008680">"Tryk for at konfigurere"</string>
    -     <string name="upload_file" msgid="2897957172366730416">"Vælg fil"</string>
    -     <string name="no_file_chosen" msgid="6363648562170759465">"Ingen fil er valgt"</string>
    -     <string name="reset" msgid="2448168080964209908">"Nulstil"</string>
    -@@ -1317,7 +1329,7 @@
    -     <string name="storage_usb_drive_label" msgid="4501418548927759953">"USB-drev fra <xliff:g id="MANUFACTURER">%s</xliff:g>"</string>
    -     <string name="storage_usb" msgid="3017954059538517278">"USB-lager"</string>
    -     <string name="extract_edit_menu_button" msgid="8940478730496610137">"Rediger"</string>
    --    <string name="data_usage_warning_title" msgid="1955638862122232342">"Advarsel om dataforbrug"</string>
    -+    <string name="data_usage_warning_title" msgid="3620440638180218181">"Underretning om dataforbrug"</string>
    -     <string name="data_usage_warning_body" msgid="6660692274311972007">"Tryk for at se forbrug og indstillinger."</string>
    -     <string name="data_usage_3g_limit_title" msgid="4361523876818447683">"Grænsen for 2G-3G-data er nået"</string>
    -     <string name="data_usage_4g_limit_title" msgid="4609566827219442376">"Grænsen for 4G-data er nået"</string>
    -@@ -1636,6 +1648,7 @@
    -     <string name="search_language_hint" msgid="7042102592055108574">"Angiv sprogets navn"</string>
    -     <string name="language_picker_section_suggested" msgid="8414489646861640885">"Foreslået"</string>
    -     <string name="language_picker_section_all" msgid="3097279199511617537">"Alle sprog"</string>
    -+    <string name="region_picker_section_all" msgid="8966316787153001779">"Alle områder"</string>
    -     <string name="locale_search_menu" msgid="2560710726687249178">"Søg"</string>
    -     <string name="work_mode_off_title" msgid="8954725060677558855">"Arbejdstilstand er slået FRA"</string>
    -     <string name="work_mode_off_message" msgid="3286169091278094476">"Tillad, at arbejdsprofilen aktiveres, bl.a. i forbindelse med apps, baggrundssynkronisering og relaterede funktioner."</string>
    -diff --git a/core/res/res/values-de/strings.xml b/core/res/res/values-de/strings.xml
    -index c478607..a6fad85 100644
    ---- a/core/res/res/values-de/strings.xml
    -+++ b/core/res/res/values-de/strings.xml
    -@@ -214,6 +214,7 @@
    -     <string name="global_actions" product="default" msgid="2406416831541615258">"Telefonoptionen"</string>
    -     <string name="global_action_lock" msgid="2844945191792119712">"Displaysperre"</string>
    -     <string name="global_action_power_off" msgid="4471879440839879722">"Ausschalten"</string>
    -+    <string name="global_action_emergency" msgid="7112311161137421166">"Notfall"</string>
    -     <string name="global_action_bug_report" msgid="7934010578922304799">"Fehlerbericht"</string>
    -     <string name="bugreport_title" msgid="2667494803742548533">"Fehlerbericht abrufen"</string>
    -     <string name="bugreport_message" msgid="398447048750350456">"Bei diesem Fehlerbericht werden Daten zum aktuellen Status deines Geräts erfasst und als E-Mail versandt. Vom Start des Berichts bis zu seinem Versand kann es eine Weile dauern. Bitte habe etwas Geduld."</string>
    -@@ -416,7 +417,7 @@
    -     <string name="permdesc_changeWifiMulticastState" product="default" msgid="6851949706025349926">"Ermöglicht der App, Pakete zu empfangen, die mithilfe von Multicast-Adressen an sämtliche Geräte in einem WLAN versendet wurden, nicht nur an dein Telefon. Dies nimmt mehr Leistung in Anspruch als der Nicht-Multicast-Modus."</string>
    -     <string name="permlab_bluetoothAdmin" msgid="6006967373935926659">"Auf Bluetooth-Einstellungen zugreifen"</string>
    -     <string name="permdesc_bluetoothAdmin" product="tablet" msgid="6921177471748882137">"Ermöglicht der App, das lokale Bluetooth-Tablet zu konfigurieren, Remote-Geräte zu erkennen und eine Verbindung zu diesen herzustellen"</string>
    --    <string name="permdesc_bluetoothAdmin" product="tv" msgid="3373125682645601429">"Ermöglicht der App, den lokalen Bluetooth-Fernseher zu konfigurieren, Remote-Geräte zu erkennen und ein Pairing mit diesen durchzuführen"</string>
    -+    <string name="permdesc_bluetoothAdmin" product="tv" msgid="3373125682645601429">"Ermöglicht der App, den lokalen Bluetooth-Fernseher zu konfigurieren, Remote-Geräte zu erkennen und eine Kopplung mit ihnen durchzuführen"</string>
    -     <string name="permdesc_bluetoothAdmin" product="default" msgid="8931682159331542137">"Ermöglicht der App, das lokale Bluetooth-Telefon zu konfigurieren, Remote-Geräte zu erkennen und eine Verbindung zu diesen herzustellen"</string>
    -     <string name="permlab_accessWimaxState" msgid="4195907010610205703">"WiMAX-Verbindungen herstellen und trennen"</string>
    -     <string name="permdesc_accessWimaxState" msgid="6360102877261978887">"Ermöglicht der App festzustellen, ob WiMAX aktiviert ist. Zudem kann sie Informationen zu verbundenen WiMAX-Netzwerken abrufen."</string>
    -@@ -424,9 +425,9 @@
    -     <string name="permdesc_changeWimaxState" product="tablet" msgid="3156456504084201805">"Ermöglicht der App, eine Verbindung zwischen dem Tablet und WiMAX-Netzwerken herzustellen und solche zu trennen."</string>
    -     <string name="permdesc_changeWimaxState" product="tv" msgid="6022307083934827718">"Ermöglicht der App, eine Verbindung zwischen dem Fernseher und WiMAX-Netzwerken herzustellen und diese zu trennen"</string>
    -     <string name="permdesc_changeWimaxState" product="default" msgid="697025043004923798">"Ermöglicht der App, eine Verbindung zwischen dem Telefon und WiMAX-Netzwerken herzustellen und solche zu trennen."</string>
    --    <string name="permlab_bluetooth" msgid="6127769336339276828">"Pairing mit Bluetooth-Geräten durchführen"</string>
    -+    <string name="permlab_bluetooth" msgid="6127769336339276828">"Kopplung mit Bluetooth-Geräten durchführen"</string>
    -     <string name="permdesc_bluetooth" product="tablet" msgid="3480722181852438628">"Ermöglicht der App, die Bluetooth-Konfiguration eines Tablets einzusehen und Verbindungen zu gekoppelten Geräten herzustellen und zu akzeptieren."</string>
    --    <string name="permdesc_bluetooth" product="tv" msgid="3974124940101104206">"Ermöglicht der App, die Bluetooth-Konfiguration des Fernsehers einzusehen und Verbindungen zu Pairing-Geräten herzustellen und zu akzeptieren"</string>
    -+    <string name="permdesc_bluetooth" product="tv" msgid="3974124940101104206">"Ermöglicht der App, die Bluetooth-Konfiguration des Fernsehers abzurufen und Verbindungen zu gekoppelten Geräten herzustellen und zu akzeptieren"</string>
    -     <string name="permdesc_bluetooth" product="default" msgid="3207106324452312739">"Ermöglicht der App, die Bluetooth-Konfiguration des Telefons einzusehen und Verbindungen mit gekoppelten Geräten herzustellen und zu akzeptieren."</string>
    -     <string name="permlab_nfc" msgid="4423351274757876953">"Nahfeldkommunikation steuern"</string>
    -     <string name="permdesc_nfc" msgid="7120611819401789907">"Ermöglicht der App die Kommunikation mit Tags für die Nahfeldkommunikation, Karten und Readern"</string>
    -@@ -1076,6 +1077,17 @@
    -     <skip />
    -     <string name="wifi_no_internet" msgid="8451173622563841546">"WLAN hat keinen Internetzugriff"</string>
    -     <string name="wifi_no_internet_detailed" msgid="8083079241212301741">"Für Optionen tippen"</string>
    -+    <string name="network_switch_metered" msgid="4671730921726992671">"Zu <xliff:g id="NETWORK_TYPE">%1$s</xliff:g> gewechselt"</string>
    -+    <string name="network_switch_metered_detail" msgid="5325661434777870353">"Auf dem Gerät wird \"<xliff:g id="NEW_NETWORK">%1$s</xliff:g>\" verwendet, wenn über \"<xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g>\" kein Internet verfügbar ist. Eventuell fallen Gebühren an."</string>
    -+    <string name="network_switch_metered_toast" msgid="5779283181685974304">"Von \"<xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g>\" zu \"<xliff:g id="NEW_NETWORK">%2$s</xliff:g>\" gewechselt"</string>
    -+  <string-array name="network_switch_type_name">
    -+    <item msgid="2952042958050315394">"mobile Datennutzung"</item>
    -+    <item msgid="75483255295529161">"WLAN"</item>
    -+    <item msgid="6862614801537202646">"Bluetooth"</item>
    -+    <item msgid="5447331121797802871">"Ethernet"</item>
    -+    <item msgid="8257233890381651999">"VPN"</item>
    -+  </string-array>
    -+    <string name="network_switch_type_name_unknown" msgid="4552612897806660656">"ein unbekannter Netzwerktyp"</string>
    -     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Es konnte keine WLAN-Verbindung hergestellt werden."</string>
    -     <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" hat eine schlechte Internetverbindung."</string>
    -     <string name="wifi_connect_alert_title" msgid="8455846016001810172">"Verbindung zulassen?"</string>
    -@@ -1153,7 +1165,6 @@
    -     <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"Zum Auswählen von Sprache und Layout tippen"</string>
    -     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
    -     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
    --    <string name="candidates_style" msgid="4333913089637062257"><u>"Kandidaten"</u></string>
    -     <string name="ext_media_checking_notification_title" msgid="5734005953288045806">"<xliff:g id="NAME">%s</xliff:g> wird vorbereitet"</string>
    -     <string name="ext_media_checking_notification_message" msgid="4747432538578886744">"Nach Fehlern wird gesucht"</string>
    -     <string name="ext_media_new_notification_message" msgid="7589986898808506239">"Neue <xliff:g id="NAME">%s</xliff:g> entdeckt"</string>
    -@@ -1232,8 +1243,9 @@
    -     <string name="vpn_text_long" msgid="4907843483284977618">"Verbunden mit <xliff:g id="SESSION">%s</xliff:g>. Zum Verwalten des Netzwerks tippen"</string>
    -     <string name="vpn_lockdown_connecting" msgid="6443438964440960745">"Verbindung zu durchgehend aktivem VPN wird hergestellt…"</string>
    -     <string name="vpn_lockdown_connected" msgid="8202679674819213931">"Mit durchgehend aktivem VPN verbunden"</string>
    -+    <string name="vpn_lockdown_disconnected" msgid="4532298952570796327">"Verbindung zu durchgehend aktivem VPN getrennt"</string>
    -     <string name="vpn_lockdown_error" msgid="6009249814034708175">"Durchgehend aktives VPN – Verbindungsfehler"</string>
    --    <string name="vpn_lockdown_config" msgid="4655589351146766608">"Zum Konfigurieren tippen"</string>
    -+    <string name="vpn_lockdown_config" msgid="5099330695245008680">"Zum Einrichten tippen"</string>
    -     <string name="upload_file" msgid="2897957172366730416">"Datei auswählen"</string>
    -     <string name="no_file_chosen" msgid="6363648562170759465">"Keine ausgewählt"</string>
    -     <string name="reset" msgid="2448168080964209908">"Zurücksetzen"</string>
    -@@ -1317,7 +1329,7 @@
    -     <string name="storage_usb_drive_label" msgid="4501418548927759953">"USB-Speichergerät von <xliff:g id="MANUFACTURER">%s</xliff:g>"</string>
    -     <string name="storage_usb" msgid="3017954059538517278">"USB-Speicher"</string>
    -     <string name="extract_edit_menu_button" msgid="8940478730496610137">"Bearbeiten"</string>
    --    <string name="data_usage_warning_title" msgid="1955638862122232342">"Warnung zum Datenverbrauch"</string>
    -+    <string name="data_usage_warning_title" msgid="3620440638180218181">"Warnung zur Datennutzung"</string>
    -     <string name="data_usage_warning_body" msgid="6660692274311972007">"Für Nutzung und Einstellungen tippen."</string>
    -     <string name="data_usage_3g_limit_title" msgid="4361523876818447683">"2G-/3G-Datenlimit erreicht"</string>
    -     <string name="data_usage_4g_limit_title" msgid="4609566827219442376">"4G-Datenlimit erreicht"</string>
    -@@ -1636,6 +1648,7 @@
    -     <string name="search_language_hint" msgid="7042102592055108574">"Sprache eingeben"</string>
    -     <string name="language_picker_section_suggested" msgid="8414489646861640885">"Vorschläge"</string>
    -     <string name="language_picker_section_all" msgid="3097279199511617537">"Alle Sprachen"</string>
    -+    <string name="region_picker_section_all" msgid="8966316787153001779">"Alle Regionen"</string>
    -     <string name="locale_search_menu" msgid="2560710726687249178">"Suche"</string>
    -     <string name="work_mode_off_title" msgid="8954725060677558855">"Arbeitsmodus ist AUS"</string>
    -     <string name="work_mode_off_message" msgid="3286169091278094476">"Arbeitsprofil aktivieren, einschließlich Apps, Synchronisierung im Hintergrund und verknüpfter Funktionen."</string>
    -diff --git a/core/res/res/values-el/strings.xml b/core/res/res/values-el/strings.xml
    -index 3c6e832..9e41023 100644
    ---- a/core/res/res/values-el/strings.xml
    -+++ b/core/res/res/values-el/strings.xml
    -@@ -214,6 +214,7 @@
    -     <string name="global_actions" product="default" msgid="2406416831541615258">"Επιλογές τηλεφώνου"</string>
    -     <string name="global_action_lock" msgid="2844945191792119712">"Κλείδωμα οθόνης"</string>
    -     <string name="global_action_power_off" msgid="4471879440839879722">"Απενεργοποίηση"</string>
    -+    <string name="global_action_emergency" msgid="7112311161137421166">"Κλήση έκτακτης ανάγκης"</string>
    -     <string name="global_action_bug_report" msgid="7934010578922304799">"Αναφορά σφαλμάτων"</string>
    -     <string name="bugreport_title" msgid="2667494803742548533">"Λήψη αναφοράς σφάλματος"</string>
    -     <string name="bugreport_message" msgid="398447048750350456">"Θα συλλέξει πληροφορίες σχετικά με την τρέχουσα κατάσταση της συσκευής σας και θα τις στείλει μέσω μηνύματος ηλεκτρονικού ταχυδρομείου. Απαιτείται λίγος χρόνος για τη σύνταξη της αναφοράς σφάλματος και την αποστολή της. Κάντε λίγη υπομονή."</string>
    -@@ -249,7 +250,7 @@
    -     <string name="permgrouplab_calendar" msgid="5863508437783683902">"Ημερολόγιο"</string>
    -     <string name="permgroupdesc_calendar" msgid="3889615280211184106">"έχει πρόσβαση στο ημερολόγιό σας"</string>
    -     <string name="permgrouplab_sms" msgid="228308803364967808">"SMS"</string>
    --    <string name="permgroupdesc_sms" msgid="4656988620100940350">"αποστολή και προβολή μηνυμάτων SMS"</string>
    -+    <string name="permgroupdesc_sms" msgid="4656988620100940350">"στέλνει και να διαβάζει μηνύματα SMS"</string>
    -     <string name="permgrouplab_storage" msgid="1971118770546336966">"Αποθηκευτικός χώρος"</string>
    -     <string name="permgroupdesc_storage" msgid="637758554581589203">"έχει πρόσβαση στις φωτογραφίες/πολυμέσα/αρχεία στη συσκευή σας"</string>
    -     <string name="permgrouplab_microphone" msgid="171539900250043464">"Μικρόφωνο"</string>
    -@@ -272,149 +273,149 @@
    -     <string name="capability_desc_canControlMagnification" msgid="4791858203568383773">"Ελέγξτε το επίπεδο ζουμ και τη θέση της οθόνης."</string>
    -     <string name="capability_title_canPerformGestures" msgid="7418984730362576862">"Εκτέλεση κινήσεων"</string>
    -     <string name="capability_desc_canPerformGestures" msgid="8296373021636981249">"Επιτρέπει το πάτημα, την ολίσθηση, το πλησίασμα και άλλες κινήσεις."</string>
    --    <string name="permlab_statusBar" msgid="7417192629601890791">"απενεργοποίηση ή τροποποίηση γραμμής κατάστασης"</string>
    -+    <string name="permlab_statusBar" msgid="7417192629601890791">"απενεργοποιεί ή να τροποποιεί την γραμμή κατάστασης"</string>
    -     <string name="permdesc_statusBar" msgid="8434669549504290975">"Επιτρέπει στην εφαρμογή να απενεργοποιεί τη γραμμή κατάστασης ή να προσθέτει και να αφαιρεί εικονίδια συστήματος."</string>
    --    <string name="permlab_statusBarService" msgid="4826835508226139688">"ορισμός ως γραμμής κατάστασης"</string>
    -+    <string name="permlab_statusBarService" msgid="4826835508226139688">"ορίζεται ως γραμμή κατάστασης"</string>
    -     <string name="permdesc_statusBarService" msgid="716113660795976060">"Επιτρέπει στην εφαρμογή να αποτελεί τη γραμμή κατάστασης."</string>
    --    <string name="permlab_expandStatusBar" msgid="1148198785937489264">"ανάπτυξη/σύμπτυξη γραμμής κατάστασης"</string>
    -+    <string name="permlab_expandStatusBar" msgid="1148198785937489264">"αναπτύσσει/συμπτύσσει τη γραμμή κατάστασης"</string>
    -     <string name="permdesc_expandStatusBar" msgid="6917549437129401132">"Επιτρέπει στην εφαρμογή να αναπτύξει ή να συμπτύξει τη γραμμή κατάστασης."</string>
    --    <string name="permlab_install_shortcut" msgid="4279070216371564234">"εγκατάσταση συντομεύσεων"</string>
    -+    <string name="permlab_install_shortcut" msgid="4279070216371564234">"εγκαθιστά συντομεύσεις"</string>
    -     <string name="permdesc_install_shortcut" msgid="8341295916286736996">"Επιτρέπει σε μια εφαρμογή την προσθήκη συντομεύσεων στην Αρχική οθόνη χωρίς την παρέμβαση του χρήστη."</string>
    --    <string name="permlab_uninstall_shortcut" msgid="4729634524044003699">"κατάργηση εγκατάστασης συντομεύσεων"</string>
    -+    <string name="permlab_uninstall_shortcut" msgid="4729634524044003699">"καταργεί την εγκατάσταση συντομεύσεων"</string>
    -     <string name="permdesc_uninstall_shortcut" msgid="6745743474265057975">"Επιτρέπει στην εφαρμογή την κατάργηση συντομεύσεων από την Αρχική οθόνη χωρίς την παρέμβαση του χρήστη."</string>
    --    <string name="permlab_processOutgoingCalls" msgid="3906007831192990946">"αναδρομολόγηση εξερχόμενων κλήσεων"</string>
    -+    <string name="permlab_processOutgoingCalls" msgid="3906007831192990946">"αναδρομολογεί τις εξερχόμενες κλήσεις"</string>
    -     <string name="permdesc_processOutgoingCalls" msgid="5156385005547315876">"Επιτρέπει στην εφαρμογή να βλέπει τον αριθμό που καλέσατε κατά τη διάρκεια μιας εξερχόμενης κλήσης με επιλογή ανακατεύθυνσης της κλήσης σε έναν διαφορετικό αριθμό ή διακοπής της κλήσης."</string>
    --    <string name="permlab_receiveSms" msgid="8673471768947895082">"λήψη μηνυμάτων κειμένου (SMS)"</string>
    -+    <string name="permlab_receiveSms" msgid="8673471768947895082">"λαμβάνει μηνύματα κειμένου (SMS)"</string>
    -     <string name="permdesc_receiveSms" msgid="6424387754228766939">"Επιτρέπει στην εφαρμογή τη λήψη και την επεξεργασία μηνυμάτων SMS. Αυτό σημαίνει ότι η εφαρμογή θα μπορούσε να παρακολουθήσει ή να διαγράψει τα μηνύματα που αποστέλλονται στη συσκευή σας χωρίς αυτά να εμφανιστούν σε εσάς."</string>
    --    <string name="permlab_receiveMms" msgid="1821317344668257098">"λήψη μηνυμάτων κειμένου (MMS)"</string>
    -+    <string name="permlab_receiveMms" msgid="1821317344668257098">"λαμβάνει μηνύματα κειμένου (MMS)"</string>
    -     <string name="permdesc_receiveMms" msgid="533019437263212260">"Επιτρέπει στην εφαρμογή τη λήψη και την επεξεργασία μηνυμάτων MMS. Αυτό σημαίνει ότι η εφαρμογή θα μπορούσε να παρακολουθήσει ή να διαγράψει τα μηνύματα που αποστέλλονται στη συσκευή σας χωρίς αυτά να εμφανιστούν σε εσάς."</string>
    --    <string name="permlab_readCellBroadcasts" msgid="1598328843619646166">"ανάγνωση μηνυμάτων που έχουν μεταδοθεί μέσω κινητού τηλεφώνου"</string>
    -+    <string name="permlab_readCellBroadcasts" msgid="1598328843619646166">"διαβάζει μηνύματα που έχουν μεταδοθεί μέσω κινητού τηλεφώνου"</string>
    -     <string name="permdesc_readCellBroadcasts" msgid="6361972776080458979">"Επιτρέπει στην εφαρμογή την ανάγνωση μηνυμάτων που έχουν μεταδοθεί μέσω κινητού τηλεφώνου και έχουν ληφθεί από τη συσκευή σας. Ειδοποιήσεις που μεταδίδονται μέσω κινητού παραδίδονται σε ορισμένες τοποθεσίες για να σας προειδοποιήσουν για καταστάσεις έκτακτης ανάγκης. Κακόβουλες εφαρμογές ενδέχεται να παρεμποδίσουν την απόδοση ή τη λειτουργία της συσκευής σας κατά τη λήψη μετάδοσης μέσω κινητού σχετικά με μια επείγουσα κατάσταση."</string>
    --    <string name="permlab_subscribedFeedsRead" msgid="4756609637053353318">"ανάγνωση ροών δεδομένων στις οποίες έχετε εγγραφεί"</string>
    -+    <string name="permlab_subscribedFeedsRead" msgid="4756609637053353318">"διαβάζει ροές δεδομένων στις οποίες έχετε εγγραφεί"</string>
    -     <string name="permdesc_subscribedFeedsRead" msgid="5557058907906144505">"Επιτρέπει στην εφαρμογή τη λήψη λεπτομερειών σχετικά με τις τρέχουσες συγχρονισμένες ροές δεδομένων."</string>
    --    <string name="permlab_sendSms" msgid="7544599214260982981">"πραγματοποιεί αποστολή και προβολή μηνυμάτων SMS"</string>
    -+    <string name="permlab_sendSms" msgid="7544599214260982981">"στέλνει και να διαβάζει μηνύματα SMS"</string>
    -     <string name="permdesc_sendSms" msgid="7094729298204937667">"Επιτρέπει στην εφαρμογή των αποστολή μηνυμάτων SMS. Αυτό μπορεί να προκαλέσει μη αναμενόμενες χρεώσεις. Οι κακόβουλες εφαρμογές ενδέχεται να σας κοστίσουν χρήματα, αποστέλλοντας μηνύματα χωρίς την έγκρισή σας."</string>
    --    <string name="permlab_readSms" msgid="8745086572213270480">"ανάγνωση των μηνυμάτων κειμένου σας (SMS ή MMS)"</string>
    -+    <string name="permlab_readSms" msgid="8745086572213270480">"διαβάζει τα μηνύματα κειμένου (SMS ή MMS)"</string>
    -     <string name="permdesc_readSms" product="tablet" msgid="2467981548684735522">"Επιτρέπει στην εφαρμογή την ανάγνωση μηνυμάτων SMS που είναι αποθηκευμένα στο tablet σας ή στην κάρτα σας SIM. Αυτό δίνει τη δυνατότητα στην εφαρμογή να διαβάζει όλα τα μηνύματα SMS, ανεξάρτητα από το περιεχόμενο ή το επίπεδο εμπιστευτικότητάς τους."</string>
    -     <string name="permdesc_readSms" product="tv" msgid="5102425513647038535">"Επιτρέπει στην εφαρμογή να διαβάζει μηνύματα SMS που έχουν αποθηκευτεί στην τηλεόραση ή στην κάρτα SIM. Έτσι, η εφαρμογή μπορεί να διαβάζει όλα τα μηνύματα SMS, ανεξαρτήτως περιεχομένου ή εμπιστευτικότητας."</string>
    -     <string name="permdesc_readSms" product="default" msgid="3695967533457240550">"Επιτρέπει στην εφαρμογή την ανάγνωση μηνυμάτων SMS που είναι αποθηκευμένα στο τηλέφωνό σας ή στην κάρτα σας SIM. Αυτό δίνει τη δυνατότητα στην εφαρμογή να διαβάζει όλα τα μηνύματα SMS, ανεξάρτητα από το περιεχόμενο ή το επίπεδο εμπιστευτικότητάς τους."</string>
    --    <string name="permlab_receiveWapPush" msgid="5991398711936590410">"λήψη μηνυμάτων κειμένου (WAP)"</string>
    -+    <string name="permlab_receiveWapPush" msgid="5991398711936590410">"λαμβάνει μηνύματα κειμένου (WAP)"</string>
    -     <string name="permdesc_receiveWapPush" msgid="748232190220583385">"Επιτρέπει στην εφαρμογή τη λήψη και την επεξεργασία μηνυμάτων WAP. Αυτό σημαίνει ότι η εφαρμογή θα μπορούσε να παρακολουθήσει ή να διαγράψει τα μηνύματα που αποστέλλονται στη συσκευή σας χωρίς αυτά να εμφανιστούν σε εσάς."</string>
    --    <string name="permlab_getTasks" msgid="6466095396623933906">"ανάκτηση εκτελούμενων εφαρμογών"</string>
    -+    <string name="permlab_getTasks" msgid="6466095396623933906">"ανακτά εκτελούμενες εφαρμογές"</string>
    -     <string name="permdesc_getTasks" msgid="7454215995847658102">"Επιτρέπει στην εφαρμογή την ανάκτηση πληροφοριών σχετικά με τρέχουσες και πρόσφατα εκτελούμενες εργασίες. Αυτό μπορεί να δίνει τη δυνατότητα στην εφαρμογή να ανακαλύπτει πληροφορίες σχετικά με το ποιες εφαρμογές χρησιμοποιούνται στη συσκευή."</string>
    --    <string name="permlab_manageProfileAndDeviceOwners" msgid="7918181259098220004">"διαχείριση προφίλ και κατόχων συσκευής"</string>
    -+    <string name="permlab_manageProfileAndDeviceOwners" msgid="7918181259098220004">"διαχειρίζεται το προφίλ και τους κατόχους συσκευής"</string>
    -     <string name="permdesc_manageProfileAndDeviceOwners" msgid="106894851498657169">"Επιτρέπει σε εφαρμογές να ορίζουν τους κατόχους προφίλ και τον κάτοχο της συσκευής."</string>
    --    <string name="permlab_reorderTasks" msgid="2018575526934422779">"αναδιάταξη εκτελούμενων εφαρμογών"</string>
    -+    <string name="permlab_reorderTasks" msgid="2018575526934422779">"αναδιατάσσει τις εκτελούμενες εφαρμογές"</string>
    -     <string name="permdesc_reorderTasks" msgid="7734217754877439351">"Επιτρέπει στην εφαρμογή τη μετακίνηση εργασιών στο προσκήνιο και το παρασκήνιο. Η εφαρμογή μπορεί να το κάνει αυτό χωρίς να καταχωρίσετε δεδομένα εισόδου."</string>
    --    <string name="permlab_enableCarMode" msgid="5684504058192921098">"ενεργοποίηση λειτουργίας αυτοκινήτου"</string>
    -+    <string name="permlab_enableCarMode" msgid="5684504058192921098">"ενεργοποιεί την λειτουργία αυτοκινήτου"</string>
    -     <string name="permdesc_enableCarMode" msgid="4853187425751419467">"Επιτρέπει στην εφαρμογή την ενεργοποίηση της λειτουργίας αυτοκινήτου."</string>
    --    <string name="permlab_killBackgroundProcesses" msgid="3914026687420177202">"κλείσιμο των άλλων εφαρμογών"</string>
    -+    <string name="permlab_killBackgroundProcesses" msgid="3914026687420177202">"κλείνει άλλες εφαρμογές"</string>
    -     <string name="permdesc_killBackgroundProcesses" msgid="4593353235959733119">"Επιτρέπει στην εφαρμογή τον τερματισμό των διεργασιών παρασκηνίου άλλων εφαρμογών. Αυτό μπορεί να προκαλεί τη διακοπή λειτουργίας άλλων εφαρμογών."</string>
    --    <string name="permlab_systemAlertWindow" msgid="3543347980839518613">"σχεδίαση πάνω σε άλλες εφαρμογές"</string>
    -+    <string name="permlab_systemAlertWindow" msgid="3543347980839518613">"σχεδιάζει πάνω από άλλες εφαρμογές"</string>
    -     <string name="permdesc_systemAlertWindow" msgid="8584678381972820118">"Επιτρέπει στην εφαρμογή το σχεδιασμό πάνω σε άλλες εφαρμογές ή τμήματα του περιβάλλοντος χρήστη. Ενδέχεται να παρεμβαίνουν στη χρήση του περιβάλλοντος σε άλλες εφαρμογές ή να αλλάζουν τα στοιχεία που βλέπετε σε άλλες εφαρμογές."</string>
    --    <string name="permlab_persistentActivity" msgid="8841113627955563938">"να εκτελείται συνεχώς η εφαρμογή"</string>
    -+    <string name="permlab_persistentActivity" msgid="8841113627955563938">"επιτρέπει στην εφαρμογή να εκτελείται συνεχώς"</string>
    -     <string name="permdesc_persistentActivity" product="tablet" msgid="8525189272329086137">"Επιτρέπει στην εφαρμογή να δημιουργεί μόνιμα τμήματα του εαυτού της στη μνήμη. Αυτό μπορεί να περιορίζει τη μνήμη που διατίθεται σε άλλες εφαρμογές, καθυστερώντας τη λειτουργία του tablet."</string>
    -     <string name="permdesc_persistentActivity" product="tv" msgid="5086862529499103587">"Επιτρέπει στην εφαρμογή να καθιστά τμήματά της μόνιμα στη μνήμη. Αυτό μπορεί να περιορίσει τη μνήμη που διατίθεται σε άλλες εφαρμογές, επιβραδύνοντας τη λειτουργία της τηλεόρασης."</string>
    -     <string name="permdesc_persistentActivity" product="default" msgid="4384760047508278272">"Επιτρέπει στην εφαρμογή να δημιουργεί μόνιμα τμήματα του εαυτού της στη μνήμη. Αυτό μπορεί να περιορίζει τη μνήμη που διατίθεται σε άλλες εφαρμογές, καθυστερώντας τη λειτουργία του τηλεφώνου."</string>
    --    <string name="permlab_getPackageSize" msgid="7472921768357981986">"μέτρηση αποθηκευτικού χώρου εφαρμογής"</string>
    -+    <string name="permlab_getPackageSize" msgid="7472921768357981986">"υπολογίζει τον αποθηκευτικό χώρο εφαρμογής"</string>
    -     <string name="permdesc_getPackageSize" msgid="3921068154420738296">"Επιτρέπει στην εφαρμογή να ανακτήσει τα μεγέθη κώδικα, δεδομένων και προσωρινής μνήμης"</string>
    -     <string name="permlab_writeSettings" msgid="2226195290955224730">"τροποποίηση ρυθμίσεων συστήματος"</string>
    -     <string name="permdesc_writeSettings" msgid="7775723441558907181">"Επιτρέπει στην εφαρμογή την τροποποίηση των δεδομένων των ρυθμίσεων του συστήματος. Τυχόν κακόβουλες εφαρμογές ενδέχεται να καταστρέψουν τη διαμόρφωση του συστήματός σας."</string>
    --    <string name="permlab_receiveBootCompleted" msgid="5312965565987800025">"εκτέλεση κατά την έναρξη"</string>
    -+    <string name="permlab_receiveBootCompleted" msgid="5312965565987800025">"εκτελείται κατά την έναρξη"</string>
    -     <string name="permdesc_receiveBootCompleted" product="tablet" msgid="7390304664116880704">"Επιτρέπει στην εφαρμογή να εκκινηθεί αμέσως μόλις ολοκληρωθεί η εκκίνηση του συστήματος. Αυτό ενδέχεται να καθυστερήσει την εκκίνηση του tablet και να προκαλέσει γενική μείωση της ταχύτητας λειτουργίας του tablet, καθώς η εφαρμογή θα εκτελείται συνεχώς."</string>
    -     <string name="permdesc_receiveBootCompleted" product="tv" msgid="4525890122209673621">"Επιτρέπει στην εφαρμογή να ξεκινάει μόλις ολοκληρώνεται η εκκίνηση του συστήματος. Αυτό μπορεί να καθυστερεί την εκκίνηση της τηλεόρασης και επιτρέπει στην εφαρμογή να επιβραδύνει τη συνολική λειτουργία του tablet, λόγω της συνεχούς προβολής."</string>
    -     <string name="permdesc_receiveBootCompleted" product="default" msgid="513950589102617504">"Επιτρέπει στην εφαρμογή να εκκινηθεί αμέσως μόλις ολοκληρωθεί η εκκίνηση του συστήματος. Αυτό ενδέχεται να καθυστερήσει την εκκίνηση του τηλεφώνου και να προκαλέσει γενική μείωση της ταχύτητας λειτουργίας του τηλεφώνου, καθώς η εφαρμογή θα εκτελείται συνεχώς."</string>
    --    <string name="permlab_broadcastSticky" msgid="7919126372606881614">"αποστολή εκπομπής sticky"</string>
    -+    <string name="permlab_broadcastSticky" msgid="7919126372606881614">"στέλνει εκπομπή sticky"</string>
    -     <string name="permdesc_broadcastSticky" product="tablet" msgid="7749760494399915651">"Επιτρέπει στην εφαρμογή την αποστολή εκπομπών sticky, οι οποίες παραμένουν μετά το τέλος της εκπομπής. Η υπερβολική χρήση ενδέχεται να καταστήσει τη λειτουργία του tablet αργή ή ασταθή, προκαλώντας τη χρήση μεγάλου τμήματος της μνήμης."</string>
    -     <string name="permdesc_broadcastSticky" product="tv" msgid="6839285697565389467">"Επιτρέπει στην εφαρμογή να στέλνει εκπομπές που παραμένουν μετά το τέλος της μετάδοσης. Η υπερβολική χρήση μπορεί να καταστήσει αργή ή ασταθή τη λειτουργία της τηλεόρασης, προκαλώντας τη χρήση υπερβολικά μεγάλου μέρους της μνήμης."</string>
    -     <string name="permdesc_broadcastSticky" product="default" msgid="2825803764232445091">"Επιτρέπει στην εφαρμογή την αποστολή εκπομπών sticky, οι οποίες παραμένουν μετά το τέλος της εκπομπής. Η υπερβολική χρήση ενδέχεται να καταστήσει τη λειτουργία του τηλεφώνου αργή ή ασταθή, προκαλώντας τη χρήση μεγάλου τμήματος της μνήμης."</string>
    --    <string name="permlab_readContacts" msgid="8348481131899886131">"ανάγνωση των επαφών σας"</string>
    -+    <string name="permlab_readContacts" msgid="8348481131899886131">"διαβάζει τις επαφές σας"</string>
    -     <string name="permdesc_readContacts" product="tablet" msgid="5294866856941149639">"Επιτρέπει στην εφαρμογή την ανάγνωση δεδομένων σχετικά με τις επαφές σας που είναι αποθηκευμένες στο tablet σας, συμπεριλαμβανομένης της συχνότητας με την οποία έχετε καλέσει συγκεκριμένα άτομα ή έχετε επικοινωνήσει μαζί τους μέσω ηλεκτρονικού ταχυδρομείου ή άλλου τρόπου. Αυτή η άδεια δίνει τη δυνατότητα σε εφαρμογές να αποθηκεύουν τα δεδομένα των επαφών σας και οι κακόβουλες εφαρμογές ενδέχεται να μοιράζονται δεδομένα επαφών χωρίς να το γνωρίζετε."</string>
    -     <string name="permdesc_readContacts" product="tv" msgid="1839238344654834087">"Επιτρέπει στην εφαρμογή να διαβάζει δεδομένα σχετικά με τις επαφές σας που είναι αποθηκευμένες στην τηλεόρασή σας, συμπεριλαμβανομένης της συχνότητας με την οποία έχετε καλέσει συγκεκριμένα άτομα ή έχετε επικοινωνήσει μαζί τους μέσω ηλεκτρονικού ταχυδρομείου ή άλλου τρόπου. Αυτό το δικαίωμα επιτρέπει στις εφαρμογές να αποθηκεύουν τα δεδομένα των επαφών σας. Επίσης, κακόβουλες εφαρμογές μπορεί να μοιραστούν δεδομένα επαφών χωρίς να το γνωρίζετε."</string>
    -     <string name="permdesc_readContacts" product="default" msgid="8440654152457300662">"Επιτρέπει στην εφαρμογή την ανάγνωση δεδομένων σχετικά με τις επαφές σας που είναι αποθηκευμένες στο τηλέφωνό σας, συμπεριλαμβανομένης της συχνότητας με την οποία έχετε καλέσει συγκεκριμένα άτομα ή έχετε επικοινωνήσει μαζί τους μέσω ηλεκτρονικού ταχυδρομείου ή άλλου τρόπου. Αυτή η άδεια δίνει τη δυνατότητα σε εφαρμογές να αποθηκεύουν τα δεδομένα των επαφών σας και οι κακόβουλες εφαρμογές ενδέχεται να μοιράζονται δεδομένα επαφών χωρίς να το γνωρίζετε."</string>
    --    <string name="permlab_writeContacts" msgid="5107492086416793544">"τροποποίηση των επαφών σας"</string>
    -+    <string name="permlab_writeContacts" msgid="5107492086416793544">"τροποποιεί τις επαφές σας"</string>
    -     <string name="permdesc_writeContacts" product="tablet" msgid="897243932521953602">"Επιτρέπει στην εφαρμογή την τροποποίηση των δεδομένων σχετικά με τις επαφές σας που είναι αποθηκευμένες στο tablet σας, συμπεριλαμβανομένης της συχνότητας με την οποία έχετε καλέσει συγκεκριμένες επαφές ή έχετε επικοινωνήσει μαζί τους μέσω ηλεκτρονικού ταχυδρομείου ή άλλου τρόπου. Αυτή η άδεια δίνει τη δυνατότητα σε εφαρμογές να διαγράφουν δεδομένα επαφών."</string>
    -     <string name="permdesc_writeContacts" product="tv" msgid="5438230957000018959">"Επιτρέπει στην εφαρμογή να τροποποιεί τα δεδομένα σχετικά με τις επαφές που είναι αποθηκευμένες στην τηλεόρασή σας, συμπεριλαμβανομένης της συχνότητας με την οποία έχετε καλέσει συγκεκριμένες επαφές ή έχετε επικοινωνήσει μαζί τους μέσω ηλεκτρονικού ταχυδρομείου ή άλλου τρόπου. Αυτό το δικαίωμα δίνει τη δυνατότητα σε εφαρμογές να διαγράφουν δεδομένα επαφών."</string>
    -     <string name="permdesc_writeContacts" product="default" msgid="589869224625163558">"Επιτρέπει στην εφαρμογή την τροποποίηση των δεδομένων σχετικά με τις επαφές σας που είναι αποθηκευμένες στο τηλέφωνό σας, συμπεριλαμβανομένης της συχνότητας με την οποία έχετε καλέσει συγκεκριμένες επαφές ή έχετε επικοινωνήσει μαζί τους μέσω ηλεκτρονικού ταχυδρομείου ή άλλου τρόπου. Αυτή η άδεια δίνει τη δυνατότητα σε εφαρμογές να διαγράφουν δεδομένα επαφών."</string>
    --    <string name="permlab_readCallLog" msgid="3478133184624102739">"ανάγνωση αρχείου καταγραφής κλήσεων"</string>
    -+    <string name="permlab_readCallLog" msgid="3478133184624102739">"διαβάζει το αρχείο καταγραφής κλήσεων"</string>
    -     <string name="permdesc_readCallLog" product="tablet" msgid="3700645184870760285">"Επιτρέπει στην εφαρμογή την ανάγνωση του αρχείου καταγραφής κλήσεων του tablet σας, συμπεριλαμβανομένων των δεδομένων σχετικά με τις εισερχόμενες και τις εξερχόμενες κλήσεις. Αυτή η άδεια δίνει τη δυνατότητα στις εφαρμογές να αποθηκεύει τα δεδομένα του αρχείου καταγραφής κλήσεων και οι κακόβουλες εφαρμογές ενδέχεται να μοιράζονται δεδομένα του αρχείου καταγραφής κλήσεων χωρίς να το γνωρίζετε."</string>
    -     <string name="permdesc_readCallLog" product="tv" msgid="5611770887047387926">"Επιτρέπει στην εφαρμογή να διαβάζει το αρχείο καταγραφής κλήσεων της τηλεόρασής σας, συμπεριλαμβανομένων δεδομένων σχετικά με τις εισερχόμενες και τις εξερχόμενες κλήσεις. Αυτό το δικαίωμα επιτρέπει στις εφαρμογές να αποθηκεύουν τα δεδομένα του αρχείου καταγραφής κλήσεων. Επίσης, κακόβουλες εφαρμογές μπορεί να μοιραστούν δεδομένα αρχείου καταγραφής κλήσεων χωρίς να το γνωρίζετε."</string>
    -     <string name="permdesc_readCallLog" product="default" msgid="5777725796813217244">"Επιτρέπει στην εφαρμογή την ανάγνωση του αρχείου καταγραφής κλήσεων του τηλεφώνου σας, συμπεριλαμβανομένων των δεδομένων σχετικά με τις εισερχόμενες και τις εξερχόμενες κλήσεις. Αυτή η άδεια δίνει τη δυνατότητα στις εφαρμογές να αποθηκεύει τα δεδομένα του αρχείου καταγραφής κλήσεων και οι κακόβουλες εφαρμογές ενδέχεται να μοιράζονται δεδομένα του αρχείου καταγραφής κλήσεων χωρίς να το γνωρίζετε."</string>
    --    <string name="permlab_writeCallLog" msgid="8552045664743499354">"εγγραφή αρχείου καταγραφής κλήσεων"</string>
    -+    <string name="permlab_writeCallLog" msgid="8552045664743499354">"εγγράφει αρχείο καταγραφής κλήσεων"</string>
    -     <string name="permdesc_writeCallLog" product="tablet" msgid="6661806062274119245">"Επιτρέπει στην εφαρμογή να τροποποιεί το αρχείο καταγραφής κλήσεων του tablet σας, συμπεριλαμβανομένων των δεδομένων σχετικά με τις εισερχόμενες και τις εξερχόμενες κλήσεις. Οι κακόβουλες εφαρμογές μπορεί να το χρησιμοποιήσουν για να διαγράψουν ή να τροποποιήσουν το αρχείο καταγραφής κλήσεων."</string>
    -     <string name="permdesc_writeCallLog" product="tv" msgid="4225034892248398019">"Επιτρέπει στην εφαρμογή να τροποποιεί το αρχείο καταγραφής κλήσεων της τηλεόρασής σας, συμπεριλαμβανομένων των δεδομένων σχετικά με τις εισερχόμενες και τις εξερχόμενες κλήσεις. Κακόβουλες εφαρμογές μπορεί να χρησιμοποιήσουν αυτήν τη δυνατότητα, για να διαγράψουν ή να τροποποιήσουν το αρχείο καταγραφής κλήσεων."</string>
    -     <string name="permdesc_writeCallLog" product="default" msgid="683941736352787842">"Επιτρέπει στην εφαρμογή να τροποποιεί το αρχείο καταγραφής κλήσεων του τηλεφώνου σας, συμπεριλαμβανομένων των δεδομένων σχετικά με τις εισερχόμενες και τις εξερχόμενες κλήσεις. Οι κακόβουλες εφαρμογές μπορεί να το χρησιμοποιήσουν για να διαγράψουν ή να τροποποιήσουν το αρχείο καταγραφής κλήσεων."</string>
    -     <string name="permlab_bodySensors" msgid="4683341291818520277">"πρόσβαση στους αισθητήρες λειτουργιών (π.χ. παρακολούθηση καρδιακού παλμού)"</string>
    -     <string name="permdesc_bodySensors" product="default" msgid="4380015021754180431">"Επιτρέπει στην εφαρμογή να αποκτήσει πρόσβαση στα δεδομένα των αισθητήρων που παρακολουθούν τη φυσική σας κατάσταση, όπως τον καρδιακό ρυθμό σας."</string>
    --    <string name="permlab_readCalendar" msgid="5972727560257612398">"ανάγνωση συμβάντων ημερολογίου και εμπιστευτικών πληροφοριών"</string>
    -+    <string name="permlab_readCalendar" msgid="5972727560257612398">"διαβάζει συμβάντα ημερολογίου και εμπιστευτικές πληροφορίες"</string>
    -     <string name="permdesc_readCalendar" product="tablet" msgid="4216462049057658723">"Επιτρέπει στην εφαρμογή την ανάγνωση όλων των συμβάντων ημερολογίου που είναι αποθηκευμένα στο tablet σας, συμπεριλαμβανομένων εκείνων των φίλων ή των συναδέλφων σας. Αυτό μπορεί να δίνει τη δυνατότητα στην εφαρμογή να μοιράζεται ή να αποθηκεύει τα δεδομένα του ημερολογίου σας, ανεξάρτητα από το βαθμό εμπιστευτικότητας ή ευαισθησίας τους."</string>
    -     <string name="permdesc_readCalendar" product="tv" msgid="3191352452242394196">"Επιτρέπει στην εφαρμογή να διαβάζει όλα τα συμβάντα ημερολογίου που είναι αποθηκευμένα στην τηλεόρασή σας, συμπεριλαμβανομένων εκείνων από τους φίλους ή τους συναδέλφους σας. Αυτό μπορεί να επιτρέψει στην εφαρμογή να μοιράζεται ή να αποθηκεύει τα δεδομένα ημερολογίου, ανεξαρτήτως εμπιστευτικότητας ή ευαισθησίας."</string>
    -     <string name="permdesc_readCalendar" product="default" msgid="7434548682470851583">"Επιτρέπει στην εφαρμογή την ανάγνωση όλων των συμβάντων ημερολογίου που είναι αποθηκευμένα στο τηλέφωνό σας, συμπεριλαμβανομένων εκείνων των φίλων ή των συναδέλφων σας. Αυτό μπορεί να δίνει τη δυνατότητα στην εφαρμογή να μοιράζεται ή να αποθηκεύει τα δεδομένα του ημερολογίου σας, ανεξάρτητα από το βαθμό εμπιστευτικότητας ή ευαισθησίας τους."</string>
    --    <string name="permlab_writeCalendar" msgid="8438874755193825647">"προσθήκη ή τροποποίηση συμβάντων ημερολογίου και αποστολή μηνυμάτων ηλεκτρονικού ταχυδρομείου σε προσκεκλημένους χωρίς να το γνωρίζουν οι κάτοχοι"</string>
    -+    <string name="permlab_writeCalendar" msgid="8438874755193825647">"προσθέτει ή τροποποιεί συμβάντα ημερολογίου και να στέλνει μηνύματα ηλ. ταχυδρομείου σε προσκεκλημένους χωρίς να το γνωρίζουν οι κάτοχοι"</string>
    -     <string name="permdesc_writeCalendar" product="tablet" msgid="6679035520113668528">"Επιτρέπει στην εφαρμογή την προσθήκη, την κατάργηση και την αλλαγή συμβάντων που μπορείτε να τροποποιήσετε στο tablet σας, συμπεριλαμβανομένων εκείνων των φίλων ή των συναδέλφων σας. Αυτό μπορεί να επιτρέπει στην εφαρμογή να αποστέλλει μηνύματα που φαίνεται ότι προέρχονται από κατόχους ημερολογίων ή να τροποποιεί συμβάντα χωρίς να το γνωρίζουν οι κάτοχοι."</string>
    -     <string name="permdesc_writeCalendar" product="tv" msgid="1273290605500902507">"Επιτρέπει στην εφαρμογή να προσθέτει, να καταργεί και να αλλάζει συμβάντα που μπορείτε να τροποποιείτε στην τηλεόρασή σας, συμπεριλαμβανομένων όσων ανήκουν σε φίλους ή συναδέλφους. Αυτό ενδέχεται να επιτρέπει στην εφαρμογή να αποστέλλει μηνύματα τα οποία φαίνεται ότι προέρχονται από κατόχους ημερολογίου ή να τροποποιεί συμβάντα χωρίς να το γνωρίζουν οι κάτοχοί τους."</string>
    -     <string name="permdesc_writeCalendar" product="default" msgid="2324469496327249376">"Επιτρέπει στην εφαρμογή την προσθήκη, την κατάργηση και την αλλαγή συμβάντων που μπορείτε να τροποποιήσετε στο τηλέφωνό σας, συμπεριλαμβανομένων εκείνων των φίλων ή των συναδέλφων σας. Αυτό μπορεί να επιτρέπει στην εφαρμογή να αποστέλλει μηνύματα που φαίνεται ότι προέρχονται από κατόχους ημερολογίων ή να τροποποιεί συμβάντα χωρίς να το γνωρίζουν οι κάτοχοι."</string>
    --    <string name="permlab_accessLocationExtraCommands" msgid="2836308076720553837">"πρόσβαση σε επιπλέον εντολές παρόχου τοποθεσίας"</string>
    -+    <string name="permlab_accessLocationExtraCommands" msgid="2836308076720553837">"έχει πρόσβαση σε επιπλέον εντολές παρόχου τοποθεσίας"</string>
    -     <string name="permdesc_accessLocationExtraCommands" msgid="6078307221056649927">"Επιτρέπει στην εφαρμογή την πρόσβαση σε επιπλέον εντολές παρόχου τοποθεσίας. Αυτό μπορεί να δώσει τη δυνατότητα στην εφαρμογή να παρέμβει στη λειτουργία του GPS ή άλλων πηγών τοποθεσίας."</string>
    --    <string name="permlab_accessFineLocation" msgid="251034415460950944">"πρόσβαση στην ακριβή τοποθεσία (με βάση το GPS και το δίκτυο)"</string>
    -+    <string name="permlab_accessFineLocation" msgid="251034415460950944">"έχει πρόσβαση στην ακριβή τοποθεσία (με βάση το GPS και το δίκτυο)"</string>
    -     <string name="permdesc_accessFineLocation" msgid="5295047563564981250">"Επιτρέπει στην εφαρμογή να λαμβάνει την ακριβή θέση σας με τη χρήση του Παγκόσμιου Συστήματος Εντοπισμού (GPS) ή πηγών τοποθεσίας δικτύου, όπως κεραίες κινητής τηλεφωνίας και Wi-Fi. Αυτές οι υπηρεσίες τοποθεσίας πρέπει να είναι ενεργοποιημένες και διαθέσιμες στην συσκευή σας, ώστε να μπορούν να χρησιμοποιηθούν από την εφαρμογή. Οι εφαρμογές ενδέχεται να τις χρησιμοποιήσουν για να προσδιορίσουν τη θέση σας και ενδέχεται να καταναλώσουν επιπλέον ισχύ μπαταρίας."</string>
    --    <string name="permlab_accessCoarseLocation" msgid="7715277613928539434">"πρόσβαση στην τοποθεσία κατά προσέγγιση (με βάση το δίκτυο)"</string>
    -+    <string name="permlab_accessCoarseLocation" msgid="7715277613928539434">"έχει πρόσβαση στην τοποθεσία κατά προσέγγιση (με βάση το δίκτυο)"</string>
    -     <string name="permdesc_accessCoarseLocation" msgid="2538200184373302295">"Επιτρέπει στην εφαρμογή τη λήψη της κατά προσέγγιση τοποθεσίας σας. Αυτή η τοποθεσία προκύπτει από τις υπηρεσίες τοποθεσίας με τη χρήση πηγών τοποθεσίας δικτύου, όπως κεραίες κινητής τηλεφωνίας και Wi-Fi. Αυτές οι υπηρεσίες τοποθεσίας πρέπει να είναι ενεργοποιημένες και διαθέσιμες στην συσκευή σας, ώστε να μπορούν να χρησιμοποιηθούν από την εφαρμογή. Οι εφαρμογές ενδέχεται να τις χρησιμοποιήσουν για να προσδιορίσουν κατά προσέγγιση τη θέση σας."</string>
    --    <string name="permlab_modifyAudioSettings" msgid="6095859937069146086">"αλλαγή των ρυθμίσεων ήχου"</string>
    -+    <string name="permlab_modifyAudioSettings" msgid="6095859937069146086">"αλλάζει τις ρυθμίσεις ήχου"</string>
    -     <string name="permdesc_modifyAudioSettings" msgid="3522565366806248517">"Επιτρέπει στην εφαρμογή την τροποποίηση καθολικών ρυθμίσεων ήχου, όπως η ένταση και ποιο ηχείο χρησιμοποιείται για έξοδο."</string>
    --    <string name="permlab_recordAudio" msgid="3876049771427466323">"εγγραφή ήχου"</string>
    -+    <string name="permlab_recordAudio" msgid="3876049771427466323">"εγγράφει ήχο"</string>
    -     <string name="permdesc_recordAudio" msgid="4906839301087980680">"Επιτρέπει στην εφαρμογή την εγγραφή ήχου με το μικρόφωνο. Αυτή η άδεια δίνει τη δυνατότητα στην εφαρμογή να εγγράφει ήχο ανά πάσα στιγμή χωρίς την έγκρισή σας."</string>
    -     <string name="permlab_sim_communication" msgid="2935852302216852065">"στέλνει εντολές στην κάρτα SIM"</string>
    -     <string name="permdesc_sim_communication" msgid="5725159654279639498">"Επιτρέπει στην εφαρμογή την αποστολή εντολών στην κάρτα SIM. Αυτό είναι εξαιρετικά επικίνδυνο."</string>
    --    <string name="permlab_camera" msgid="3616391919559751192">"λήψη φωτογραφιών και βίντεο"</string>
    -+    <string name="permlab_camera" msgid="3616391919559751192">"κάνει λήψη φωτογραφιών και βίντεο"</string>
    -     <string name="permdesc_camera" msgid="8497216524735535009">"Επιτρέπει στην εφαρμογή τη λήψη φωτογραφιών και βίντεο με τη φωτογραφική μηχανή. Αυτή η άδεια δίνει τη δυνατότητα στην εφαρμογή να χρησιμοποιεί τη φωτογραφική μηχανή ανά πάσα στιγμή χωρίς την έγκρισή σας."</string>
    --    <string name="permlab_vibrate" msgid="7696427026057705834">"έλεγχος δόνησης"</string>
    -+    <string name="permlab_vibrate" msgid="7696427026057705834">"ελέγχει τη δόνηση"</string>
    -     <string name="permdesc_vibrate" msgid="6284989245902300945">"Επιτρέπει στην εφαρμογή τον έλεγχο της δόνησης."</string>
    --    <string name="permlab_callPhone" msgid="3925836347681847954">"απευθείας κλήση τηλεφωνικών αριθμών"</string>
    -+    <string name="permlab_callPhone" msgid="3925836347681847954">"πραγματοποιεί απευθείας κλήση τηλεφωνικών αριθμών"</string>
    -     <string name="permdesc_callPhone" msgid="3740797576113760827">"Επιτρέπει στην εφαρμογή την κλήση αριθμών τηλεφώνου χωρίς δική σας παρέμβαση. Αυτό μπορεί να προκαλέσει μη αναμενόμενες χρεώσεις ή κλήσεις. Έχετε υπόψη ότι δεν επιτρέπεται στην εφαρμογή η κλήση αριθμών έκτακτης ανάγκης. Οι κακόβουλες εφαρμογές ενδέχεται να σας κοστίσουν χρήματα, πραγματοποιώντας κλήσεις χωρίς την έγκρισή σας."</string>
    --    <string name="permlab_accessImsCallService" msgid="3574943847181793918">"πρόσβαση στην υπηρεσία κλήσεων της IMS"</string>
    -+    <string name="permlab_accessImsCallService" msgid="3574943847181793918">"έχει πρόσβαση στην υπηρεσία κλήσεων της IMS"</string>
    -     <string name="permdesc_accessImsCallService" msgid="8992884015198298775">"Επιτρέπει στην εφαρμογή τη χρήση της υπηρεσίας IMS για την πραγματοποίηση κλήσεων χωρίς τη δική σας παρέμβαση."</string>
    --    <string name="permlab_readPhoneState" msgid="9178228524507610486">"ανάγνωση κατάστασης και ταυτότητας τηλεφώνου"</string>
    -+    <string name="permlab_readPhoneState" msgid="9178228524507610486">"διαβάζει την κατάσταση και ταυτότητα τηλεφώνου"</string>
    -     <string name="permdesc_readPhoneState" msgid="1639212771826125528">"Επιτρέπει στην εφαρμογή την πρόσβαση στις λειτουργίες τηλεφώνου της συσκευής. Αυτή η άδεια δίνει τη δυνατότητα στην εφαρμογή να καθορίζει τον αριθμό τηλεφώνου και τα αναγνωριστικά συσκευών, εάν μια κλήση είναι ενεργή, καθώς και τον απομακρυσμένο αριθμό που συνδέεται από μια κλήση."</string>
    --    <string name="permlab_wakeLock" product="tablet" msgid="1531731435011495015">"παρεμπόδιση μετάβασης του tablet σε κατάσταση αδράνειας"</string>
    --    <string name="permlab_wakeLock" product="tv" msgid="2601193288949154131">"αποτροπή μετάβασης της τηλεόρασης στην κατάσταση αδράνειας"</string>
    --    <string name="permlab_wakeLock" product="default" msgid="573480187941496130">"παρεμπόδιση μετάβασης του τηλεφώνου σε κατάσταση αδράνειας"</string>
    -+    <string name="permlab_wakeLock" product="tablet" msgid="1531731435011495015">"αποτρέπει την μετάβαση του tablet σε κατάσταση αδράνειας"</string>
    -+    <string name="permlab_wakeLock" product="tv" msgid="2601193288949154131">"αποτρέπει την μετάβαση της τηλεόρασης σε κατάσταση αδράνειας"</string>
    -+    <string name="permlab_wakeLock" product="default" msgid="573480187941496130">"αποτρέπει το τηλεφώνο να μεταβεί σε κατάσταση αδράνειας"</string>
    -     <string name="permdesc_wakeLock" product="tablet" msgid="7311319824400447868">"Επιτρέπει στην εφαρμογή την παρεμπόδιση της μετάβασης του tablet σε κατάσταση αδράνειας."</string>
    -     <string name="permdesc_wakeLock" product="tv" msgid="3208534859208996974">"Επιτρέπει στην εφαρμογή να εμποδίζει τη μετάβαση της τηλεόρασης στην κατάσταση αδράνειας."</string>
    -     <string name="permdesc_wakeLock" product="default" msgid="8559100677372928754">"Επιτρέπει στην εφαρμογή την παρεμπόδιση της μετάβασης του τηλεφώνου σε κατάσταση αδράνειας."</string>
    --    <string name="permlab_transmitIr" msgid="7545858504238530105">"μετάδοση υπερύθρων"</string>
    -+    <string name="permlab_transmitIr" msgid="7545858504238530105">"μεταδίδει με υπερύθρες"</string>
    -     <string name="permdesc_transmitIr" product="tablet" msgid="5358308854306529170">"Επιτρέπει στην εφαρμογή να χρησιμοποιεί τον πομπό υπερύθρων του tablet."</string>
    -     <string name="permdesc_transmitIr" product="tv" msgid="3926790828514867101">"Επιτρέπει στην εφαρμογή να χρησιμοποιεί τον πομπό υπερύθρων της τηλεόρασης."</string>
    -     <string name="permdesc_transmitIr" product="default" msgid="7957763745020300725">"Επιτρέπει στην εφαρμογή να χρησιμοποιεί τον πομπό υπερύθρων του τηλεφώνου."</string>
    --    <string name="permlab_setWallpaper" msgid="6627192333373465143">"ορισμός ταπετσαρίας"</string>
    -+    <string name="permlab_setWallpaper" msgid="6627192333373465143">"ορίζει ταπετσαρία"</string>
    -     <string name="permdesc_setWallpaper" msgid="7373447920977624745">"Επιτρέπει στην εφαρμογή τον ορισμό της ταπετσαρίας συστήματος."</string>
    --    <string name="permlab_setWallpaperHints" msgid="3278608165977736538">"ρύθμιση του μεγέθους της ταπετσαρίας σας"</string>
    -+    <string name="permlab_setWallpaperHints" msgid="3278608165977736538">"ρυθμίζει το μέγεθος της ταπετσαρίας"</string>
    -     <string name="permdesc_setWallpaperHints" msgid="8235784384223730091">"Επιτρέπει στην εφαρμογή τον ορισμό συμβουλών μεγέθους ταπετσαρίας συστήματος."</string>
    --    <string name="permlab_setTimeZone" msgid="2945079801013077340">"ορισμός ζώνης ώρας"</string>
    -+    <string name="permlab_setTimeZone" msgid="2945079801013077340">"ορίζει τη ζώνης ώρας"</string>
    -     <string name="permdesc_setTimeZone" product="tablet" msgid="1676983712315827645">"Επιτρέπει στην εφαρμογή την αλλαγή της ζώνης ώρας του tablet."</string>
    -     <string name="permdesc_setTimeZone" product="tv" msgid="888864653946175955">"Επιτρέπει στην εφαρμογή να αλλάζει τη ζώνη ώρας της τηλεόρασης."</string>
    -     <string name="permdesc_setTimeZone" product="default" msgid="4499943488436633398">"Επιτρέπει στην εφαρμογή την αλλαγή της ζώνης ώρας του τηλεφώνου."</string>
    --    <string name="permlab_getAccounts" msgid="1086795467760122114">"εύρεση λογαριασμών στη συσκευή"</string>
    -+    <string name="permlab_getAccounts" msgid="1086795467760122114">"βρίσκει λογαριασμούς στη συσκευή"</string>
    -     <string name="permdesc_getAccounts" product="tablet" msgid="2741496534769660027">"Επιτρέπει στην εφαρμογή τη λήψη της λίστας λογαριασμών που υπάρχουν στο tablet. Μπορεί να περιλαμβάνονται τυχόν λογαριασμοί που δημιουργήθηκαν από εφαρμογές που έχετε εγκαταστήσει."</string>
    -     <string name="permdesc_getAccounts" product="tv" msgid="4190633395633907543">"Επιτρέπει στην εφαρμογή να λαμβάνει τη λίστα λογαριασμών που γνωρίζει η τηλεόραση. Αυτό μπορεί να περιλαμβάνει λογαριασμούς που δημιουργούνται από λογαριασμούς που έχετε εγκαταστήσει."</string>
    -     <string name="permdesc_getAccounts" product="default" msgid="3448316822451807382">"Επιτρέπει στην εφαρμογή τη λήψη της λίστας λογαριασμών που υπάρχουν στο τηλέφωνο. Μπορεί να περιλαμβάνονται τυχόν λογαριασμοί που δημιουργήθηκαν από εφαρμογές που έχετε εγκαταστήσει."</string>
    --    <string name="permlab_accessNetworkState" msgid="4951027964348974773">"προβολή συνδέσεων δικτύου"</string>
    -+    <string name="permlab_accessNetworkState" msgid="4951027964348974773">"βλέπει τις συνδέσεις δικτύου"</string>
    -     <string name="permdesc_accessNetworkState" msgid="8318964424675960975">"Επιτρέπει στην εφαρμογή την προβολή πληροφοριών σχετικά με συνδέσεις δικτύου, όπως ποια δίκτυα υπάρχουν και είναι συνδεδεμένα."</string>
    --    <string name="permlab_createNetworkSockets" msgid="7934516631384168107">"πλήρης πρόσβαση στο δίκτυο"</string>
    -+    <string name="permlab_createNetworkSockets" msgid="7934516631384168107">"έχει πλήρη πρόσβαση στο δίκτυο"</string>
    -     <string name="permdesc_createNetworkSockets" msgid="3403062187779724185">"Επιτρέπει στην εφαρμογή τη δημιουργία θέσεων δικτύου και τη χρήση προσαρμοσμένων πρωτοκόλλων δικτύου. Το πρόγραμμα περιήγησης και άλλες εφαρμογές παρέχουν μέσα για την αποστολή δεδομένων στο διαδίκτυο, επομένως η συγκεκριμένη άδεια δεν είναι απαραίτητη για την αποστολή δεδομένων στο διαδίκτυο."</string>
    --    <string name="permlab_changeNetworkState" msgid="958884291454327309">"αλλαγή συνδεσιμότητας δικτύου"</string>
    -+    <string name="permlab_changeNetworkState" msgid="958884291454327309">"αλλάζει την συνδεσιμότητα δικτύου"</string>
    -     <string name="permdesc_changeNetworkState" msgid="6789123912476416214">"Επιτρέπει στην εφαρμογή την αλλαγή της κατάστασης συνδεσιμότητας δικτύου."</string>
    --    <string name="permlab_changeTetherState" msgid="5952584964373017960">"αλλαγή συνδεσιμότητας μέσω σύνδεσης με κινητή συσκευή"</string>
    -+    <string name="permlab_changeTetherState" msgid="5952584964373017960">"αλλάζει συνδεσιμότητα μέσω σύνδεσης με κινητή συσκευή"</string>
    -     <string name="permdesc_changeTetherState" msgid="1524441344412319780">"Επιτρέπει στην εφαρμογή την αλλαγή της κατάστασης συνδεσιμότητας δικτύου."</string>
    --    <string name="permlab_accessWifiState" msgid="5202012949247040011">"προβολή συνδέσεων Wi-Fi"</string>
    -+    <string name="permlab_accessWifiState" msgid="5202012949247040011">"βλέπει τις συνδέσεις Wi-Fi"</string>
    -     <string name="permdesc_accessWifiState" msgid="5002798077387803726">"Επιτρέπει στην εφαρμογή την προβολή πληροφοριών σχετικά με τη δικτύωση Wi-Fi, όπως εάν το Wi-Fi είναι ενεργοποιημένο και τα ονόματα των συνδεδεμένων συσκευών Wi-Fi."</string>
    --    <string name="permlab_changeWifiState" msgid="6550641188749128035">"σύνδεση και αποσύνδεση από το Wi-Fi"</string>
    -+    <string name="permlab_changeWifiState" msgid="6550641188749128035">"συνδέεται/αποσυνδέεται από το Wi-Fi"</string>
    -     <string name="permdesc_changeWifiState" msgid="7137950297386127533">"Επιτρέπει στην εφαρμογή τη σύνδεση σε σημεία πρόσβασης Wi-Fi και την αποσύνδεση από αυτά, καθώς και την πραγματοποίηση αλλαγών σε διαμόρφωση συσκευών για δίκτυα Wi-Fi."</string>
    --    <string name="permlab_changeWifiMulticastState" msgid="1368253871483254784">"να επιτρέπεται η λήψη πολλαπλής διανομής Wi-Fi"</string>
    -+    <string name="permlab_changeWifiMulticastState" msgid="1368253871483254784">"επιτρέπει την λήψη πολλαπλής διανομής Wi-Fi"</string>
    -     <string name="permdesc_changeWifiMulticastState" product="tablet" msgid="7969774021256336548">"Επιτρέπει στην εφαρμογή τη λήψη πακέτων που αποστέλλονται σε όλες τις συσκευές σε ένα δίκτυο Wi-Fi, με χρήση διευθύνσεων πολλαπλής διανομής και όχι απλώς στο tablet σας. Χρησιμοποιεί περισσότερη ενέργεια σε σχέση με τη λειτουργία χωρίς πολλαπλή διανομή."</string>
    -     <string name="permdesc_changeWifiMulticastState" product="tv" msgid="9031975661145014160">"Επιτρέπει στην εφαρμογή να λαμβάνει πακέτα που αποστέλλονται σε όλες τις συσκευές σε ένα δίκτυο Wi-Fi, χρησιμοποιώντας διευθύνσεις multicast και όχι μόνο την τηλεόρασή σας. Χρησιμοποιεί περισσότερη ενέργεια από τη λειτουργία χωρίς multicast."</string>
    -     <string name="permdesc_changeWifiMulticastState" product="default" msgid="6851949706025349926">"Επιτρέπει στην εφαρμογή τη λήψη πακέτων που αποστέλλονται σε όλες τις συσκευές σε ένα δίκτυο Wi-Fi, με χρήση διευθύνσεων πολλαπλής διανομής και όχι απλώς στο τηλέφωνό σας. Χρησιμοποιεί περισσότερη ενέργεια σε σχέση με τη λειτουργία χωρίς πολλαπλή διανομή."</string>
    --    <string name="permlab_bluetoothAdmin" msgid="6006967373935926659">"πρόσβαση στις ρυθμίσεις Bluetooth"</string>
    -+    <string name="permlab_bluetoothAdmin" msgid="6006967373935926659">"διαβάζει τις ρυθμίσεις Bluetooth"</string>
    -     <string name="permdesc_bluetoothAdmin" product="tablet" msgid="6921177471748882137">"Επιτρέπει στην εφαρμογή τη διαμόρφωση του τοπικού tablet Bluetooth, τον εντοπισμό και τη σύζευξη με απομακρυσμένες συσκευές."</string>
    -     <string name="permdesc_bluetoothAdmin" product="tv" msgid="3373125682645601429">"Επιτρέπει στην εφαρμογή να διαμορφώνει το τοπικό Bluetooth στην τηλεόραση, καθώς και να ανακαλύπτει απομακρυσμένες συσκευές και να συνδέεται μαζί τους."</string>
    -     <string name="permdesc_bluetoothAdmin" product="default" msgid="8931682159331542137">"Επιτρέπει στην εφαρμογή τη διαμόρφωση του τοπικού tablet Bluetooth, τον εντοπισμό και τη σύζευξη με απομακρυσμένες συσκευές."</string>
    -@@ -424,17 +425,17 @@
    -     <string name="permdesc_changeWimaxState" product="tablet" msgid="3156456504084201805">"Επιτρέπει στην εφαρμογή τη σύνδεση στο tablet και την αποσύνδεση από αυτό, από δίκτυα WiMAX."</string>
    -     <string name="permdesc_changeWimaxState" product="tv" msgid="6022307083934827718">"Επιτρέπει στην εφαρμογή να συνδέει και να αποσυνδέει την τηλεόραση από δίκτυα WiMAX."</string>
    -     <string name="permdesc_changeWimaxState" product="default" msgid="697025043004923798">"Επιτρέπει στην εφαρμογή τη σύνδεση στο τηλέφωνο και την αποσύνδεση από αυτό, από δίκτυα WiMAX."</string>
    --    <string name="permlab_bluetooth" msgid="6127769336339276828">"σύζευξη με συσκευές Bluetooth"</string>
    -+    <string name="permlab_bluetooth" msgid="6127769336339276828">"πραγματοποιεί σύζευξη με συσκευές Bluetooth"</string>
    -     <string name="permdesc_bluetooth" product="tablet" msgid="3480722181852438628">"Επιτρέπει στην εφαρμογή να προβάλλει τη διαμόρφωση του Bluetooth στο tablet, καθώς και να πραγματοποιεί και να αποδέχεται συνδέσεις με συνδεδεμένες συσκευές."</string>
    -     <string name="permdesc_bluetooth" product="tv" msgid="3974124940101104206">"Επιτρέπει στην εφαρμογή να προβάλλει τη διαμόρφωση του Bluetooth στην τηλεόραση, καθώς και να δημιουργεί και να αποδέχεται συνδέσεις με συσκευές σε σύζευξη."</string>
    -     <string name="permdesc_bluetooth" product="default" msgid="3207106324452312739">"Επιτρέπει στην εφαρμογή να προβάλλει τη διαμόρφωση του Bluetooth στο τηλέφωνο, καθώς και να πραγματοποιεί και να αποδέχεται συνδέσεις με συνδεδεμένες συσκευές."</string>
    --    <string name="permlab_nfc" msgid="4423351274757876953">"έλεγχος Επικοινωνίας κοντινού πεδίου (Near Field Communication)"</string>
    -+    <string name="permlab_nfc" msgid="4423351274757876953">"ελέγχει την Επικοινωνία κοντινού πεδίου (FNC)"</string>
    -     <string name="permdesc_nfc" msgid="7120611819401789907">"Επιτρέπει στην εφαρμογή την επικοινωνία με ετικέτες, κάρτες και αναγνώστες της Επικοινωνίας κοντινού πεδίου (NFC)."</string>
    --    <string name="permlab_disableKeyguard" msgid="3598496301486439258">"απενεργοποίηση κλειδώματος οθόνης"</string>
    -+    <string name="permlab_disableKeyguard" msgid="3598496301486439258">"απενεργοποιεί το κλείδωμα οθόνης"</string>
    -     <string name="permdesc_disableKeyguard" msgid="6034203065077122992">"Επιτρέπει στην εφαρμογή την απενεργοποίηση του κλειδώματος πληκτρολογίου και άλλης σχετικής ασφάλειας με κωδικό πρόσβασης. Για παράδειγμα, το κλείδωμα πληκτρολογίου στο τηλέφωνο απενεργοποιείται όταν λαμβάνεται εισερχόμενη τηλεφωνική κλήση και ενεργοποιείται ξανά όταν η κλήση τερματιστεί."</string>
    --    <string name="permlab_manageFingerprint" msgid="5640858826254575638">"διαχείριση εξοπλισμού μοναδικού χαρακτηριστικού"</string>
    -+    <string name="permlab_manageFingerprint" msgid="5640858826254575638">"διαχειρίζεται τον εξοπλισμό δακτυλικού αποτυπώματος"</string>
    -     <string name="permdesc_manageFingerprint" msgid="178208705828055464">"Επιτρέπει στην εφαρμογή να επικαλείται μεθόδους για την προσθήκη και τη διαγραφή προτύπων μοναδικού χαρακτηριστικού για χρήση."</string>
    --    <string name="permlab_useFingerprint" msgid="3150478619915124905">"χρήση εξοπλισμού μοναδικού χαρακτηριστικού"</string>
    -+    <string name="permlab_useFingerprint" msgid="3150478619915124905">"χρησιμοποιεί τον εξοπλισμό δακτυλικού αποτυπώματος"</string>
    -     <string name="permdesc_useFingerprint" msgid="9165097460730684114">"Επιτρέπει στην εφαρμογή να χρησιμοποιεί εξοπλισμό μοναδικού χαρακτηριστικού για έλεγχο ταυτότητας"</string>
    -     <string name="fingerprint_acquired_partial" msgid="735082772341716043">"Εντοπίστηκε μερικό μοναδικό χαρακτηριστικό. Δοκιμάστε ξανά."</string>
    -     <string name="fingerprint_acquired_insufficient" msgid="4596546021310923214">"Δεν ήταν δυνατή η επεξεργασία του μοναδικού χαρακτηριστικού. Δοκιμάστε ξανά."</string>
    -@@ -453,65 +454,65 @@
    -   <string-array name="fingerprint_error_vendor">
    -   </string-array>
    -     <string name="fingerprint_icon_content_description" msgid="2340202869968465936">"Εικονίδιο δακτυλικών αποτυπωμάτων"</string>
    --    <string name="permlab_readSyncSettings" msgid="6201810008230503052">"ανάγνωση ρυθμίσεων συγχρονισμού"</string>
    -+    <string name="permlab_readSyncSettings" msgid="6201810008230503052">"διαβάζει τις ρυθμίσεις συγχρονισμού"</string>
    -     <string name="permdesc_readSyncSettings" msgid="2706745674569678644">"Επιτρέπει στην εφαρμογή την ανάγνωση των ρυθμίσεων συγχρονισμού για έναν λογαριασμό. Για παράδειγμα, αυτό μπορεί να καθορίσει εάν η εφαρμογή \"Άτομα\" είναι συγχρονισμένη με έναν λογαριασμό."</string>
    --    <string name="permlab_writeSyncSettings" msgid="5408694875793945314">"εναλλαγή ενεργοποίησης και απενεργοποίησης συγχρονισμού"</string>
    -+    <string name="permlab_writeSyncSettings" msgid="5408694875793945314">"ενεργοποιεί/απενεργοποιεί τον συγχρονισμό"</string>
    -     <string name="permdesc_writeSyncSettings" msgid="8956262591306369868">"Επιτρέπει σε μια εφαρμογή την τροποποίηση των ρυθμίσεων συγχρονισμού για έναν λογαριασμό. Για παράδειγμα, αυτό μπορεί να χρησιμοποιηθεί για να ενεργοποιηθεί ο συγχρονισμός της εφαρμογής \"Άτομα\" με έναν λογαριασμό."</string>
    --    <string name="permlab_readSyncStats" msgid="7396577451360202448">"ανάγνωση στατιστικών συγχρονισμού"</string>
    -+    <string name="permlab_readSyncStats" msgid="7396577451360202448">"διαβάζει στατιστικά στοιχεία συγχρονισμού"</string>
    -     <string name="permdesc_readSyncStats" msgid="1510143761757606156">"Επιτρέπει σε μια εφαρμογή την ανάγνωση των στατιστικών στοιχείων συγχρονισμού για έναν λογαριασμό, συμπεριλαμβανομένων του ιστορικού των συμβάντων συγχρονισμού και του όγκου των δεδομένων που συγχρονίζονται."</string>
    -     <string name="permlab_sdcardRead" product="nosdcard" msgid="367275095159405468">"ανάγν. περιεχ. αποθηκ. χώρ.USB"</string>
    --    <string name="permlab_sdcardRead" product="default" msgid="2188156462934977940">"ανάγνωση του περιεχομένου της κάρτας SD"</string>
    -+    <string name="permlab_sdcardRead" product="default" msgid="2188156462934977940">"διαβάζει το περιεχομένο της κάρτας SD"</string>
    -     <string name="permdesc_sdcardRead" product="nosdcard" msgid="3446988712598386079">"Επιτρέπει στην εφαρμογή την ανάγνωση του περιεχομένου του αποθηκευτικού σας χώρου USB."</string>
    -     <string name="permdesc_sdcardRead" product="default" msgid="2607362473654975411">"Επιτρέπει στην εφαρμογή την ανάγνωση του περιεχομένου της κάρτας SD."</string>
    --    <string name="permlab_sdcardWrite" product="nosdcard" msgid="8485979062254666748">"τροποποίηση ή διαγραφή του USB"</string>
    --    <string name="permlab_sdcardWrite" product="default" msgid="8805693630050458763">"τροποποίηση ή διαγραφή των περιεχομένων της κάρτας SD"</string>
    -+    <string name="permlab_sdcardWrite" product="nosdcard" msgid="8485979062254666748">"τροποποιεί/διαγράφει το USB"</string>
    -+    <string name="permlab_sdcardWrite" product="default" msgid="8805693630050458763">"τροποποιεί ή διαγράφει τα περιεχόμενα της κάρτας SD"</string>
    -     <string name="permdesc_sdcardWrite" product="nosdcard" msgid="6175406299445710888">"Επιτρέπει στην εφαρμογή την εγγραφή στον αποθηκευτικό χώρο USB."</string>
    -     <string name="permdesc_sdcardWrite" product="default" msgid="4337417790936632090">"Επιτρέπει στην εφαρμογή την εγγραφή στην κάρτα SD."</string>
    --    <string name="permlab_use_sip" msgid="2052499390128979920">"πραγματοποίηση/λήψη κλήσεων SIP"</string>
    -+    <string name="permlab_use_sip" msgid="2052499390128979920">"πραγματοποιεί/λαμβάνει κλήσεις SIP"</string>
    -     <string name="permdesc_use_sip" msgid="2297804849860225257">"Επιτρέπει στην εφαρμογή να πραγματοποιεί και να λαμβάνει κλήσεις SIP."</string>
    --    <string name="permlab_register_sim_subscription" msgid="3166535485877549177">"εγγραφή νέων συνδέσεων SIM τηλεπικοινωνιών"</string>
    -+    <string name="permlab_register_sim_subscription" msgid="3166535485877549177">"πραγματοποιεί εγγραφή νέων συνδέσεων SIM τηλεπικοινωνιών"</string>
    -     <string name="permdesc_register_sim_subscription" msgid="2138909035926222911">"Επιτρέπει στην εφαρμογή την εγγραφή νέων συνδέσεων SIM τηλεπικοινωνιών."</string>
    --    <string name="permlab_register_call_provider" msgid="108102120289029841">"εγγραφή νέων συνδέσεων τηλεπικοινωνιών"</string>
    -+    <string name="permlab_register_call_provider" msgid="108102120289029841">"πραγματοποιεί εγγραφή των νέων συνδέσεων τηλεπικοινωνιών"</string>
    -     <string name="permdesc_register_call_provider" msgid="7034310263521081388">"Επιτρέπει στην εφαρμογή την εγγραφή νέων συνδέσεων τηλεπικοινωνιών."</string>
    --    <string name="permlab_connection_manager" msgid="1116193254522105375">"διαχείριση των συνδέσεων τηλεπικοινωνιών"</string>
    -+    <string name="permlab_connection_manager" msgid="1116193254522105375">"διαχειρίζεται τις συνδέσεις τηλεπικοινωνιών"</string>
    -     <string name="permdesc_connection_manager" msgid="5925480810356483565">"Επιτρέπει στην εφαρμογή να διαχειρίζεται τις συνδέσεις τηλεπικοινωνιών."</string>
    --    <string name="permlab_bind_incall_service" msgid="6773648341975287125">"αλληλεπίδραση με την οθόνη κατά τη διάρκεια κλήσης"</string>
    -+    <string name="permlab_bind_incall_service" msgid="6773648341975287125">"αλληλεπιδρά με την οθόνη κατά τη διάρκεια κλήσης"</string>
    -     <string name="permdesc_bind_incall_service" msgid="8343471381323215005">"Επιτρέπει στην εφαρμογή να ελέγχει πότε και πώς βλέπει ο χρήστης την οθόνη κατά τη διάρκεια κλήσης."</string>
    --    <string name="permlab_bind_connection_service" msgid="3557341439297014940">"αλληλεπίδραση με υπηρεσίες τηλεφωνίας"</string>
    -+    <string name="permlab_bind_connection_service" msgid="3557341439297014940">"αλληλεπιδρά με υπηρεσίες τηλεφωνίας"</string>
    -     <string name="permdesc_bind_connection_service" msgid="4008754499822478114">"Επιτρέπει στην εφαρμογή να αλληλεπιδρά με υπηρεσίες τηλεφωνίας για την πραγματοποίηση/λήψη κλήσεων."</string>
    --    <string name="permlab_control_incall_experience" msgid="9061024437607777619">"παροχή εμπειρίας χρήστη κατά τη διάρκεια κλήσης"</string>
    -+    <string name="permlab_control_incall_experience" msgid="9061024437607777619">"παρέχει εμπειρία χρήστη κατά τη διάρκεια κλήσης"</string>
    -     <string name="permdesc_control_incall_experience" msgid="915159066039828124">"Επιτρέπει στην εφαρμογή να παρέχει μια εμπειρία στο χρήστη κατά τη διάρκεια κλήσης."</string>
    --    <string name="permlab_readNetworkUsageHistory" msgid="7862593283611493232">"ανάγνωση ιστορικών δεδομένων χρήσης δικτύου"</string>
    -+    <string name="permlab_readNetworkUsageHistory" msgid="7862593283611493232">"διαβάζει ιστορικά στοιχεία δεδομένων χρήσης δικτύου"</string>
    -     <string name="permdesc_readNetworkUsageHistory" msgid="7689060749819126472">"Επιτρέπει στην εφαρμογή την ανάγνωση ιστορικών στοιχείων χρήσης δικτύου για συγκεκριμένα δίκτυα και εφαρμογές."</string>
    --    <string name="permlab_manageNetworkPolicy" msgid="2562053592339859990">"διαχείριση πολιτικής δικτύου"</string>
    -+    <string name="permlab_manageNetworkPolicy" msgid="2562053592339859990">"διαχειρίζεται την πολιτική δικτύου"</string>
    -     <string name="permdesc_manageNetworkPolicy" msgid="7537586771559370668">"Επιτρέπει στην εφαρμογή τη διαχείριση των πολιτικών δικτύου και τον ορισμό κανόνων για ορισμένες εφαρμογές."</string>
    --    <string name="permlab_modifyNetworkAccounting" msgid="5088217309088729650">"τροποποίηση υπολογισμού χρήσης δικτύου"</string>
    -+    <string name="permlab_modifyNetworkAccounting" msgid="5088217309088729650">"τροποποιεί τον υπολογισμό χρήσης δικτύου"</string>
    -     <string name="permdesc_modifyNetworkAccounting" msgid="5443412866746198123">"Επιτρέπει στην εφαρμογή την τροποποίηση του τρόπου υπολογισμού της χρήσης δικτύου έναντι των εφαρμογών. Δεν προορίζεται για χρήση από συνήθεις εφαρμογές."</string>
    --    <string name="permlab_accessNotifications" msgid="7673416487873432268">"πρόσβαση στις ειδοποιήσεις"</string>
    -+    <string name="permlab_accessNotifications" msgid="7673416487873432268">"έχει πρόσβαση στις ειδοποιήσεις"</string>
    -     <string name="permdesc_accessNotifications" msgid="458457742683431387">"Επιτρέπει στην εφαρμογή να ανακτά, να εξετάζει και να απαλείφει ειδοποιήσεις, συμπεριλαμβανομένων εκείνων που δημοσιεύονται από άλλες εφαρμογές."</string>
    --    <string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"δέσμευση σε υπηρεσία ακρόασης ειδοποίησης"</string>
    -+    <string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"συνδέεται σε υπηρεσία ακρόασης ειδοποίησης"</string>
    -     <string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"Επιτρέπει στον κάτοχο τη δέσμευση στη διεπαφή ανωτάτου επιπέδου μιας υπηρεσίας ακρόασης ειδοποιήσεων. Δεν απαιτείται σε κανονικές εφαρμογές."</string>
    --    <string name="permlab_bindConditionProviderService" msgid="1180107672332704641">"σύνδεση σε μια υπηρεσία παρόχου συνθηκών"</string>
    -+    <string name="permlab_bindConditionProviderService" msgid="1180107672332704641">"δεσμεύεται σε μια υπηρεσία παρόχου συνθηκών"</string>
    -     <string name="permdesc_bindConditionProviderService" msgid="1680513931165058425">"Επιτρέπει στον κάτοχο τη σύνδεση στη διεπαφή ανωτάτου επιπέδου ενός παρόχου συνθηκών. Δεν απαιτείται για κανονικές εφαρμογές."</string>
    --    <string name="permlab_bindDreamService" msgid="4153646965978563462">"δέσμευση σε υπηρεσία dream"</string>
    -+    <string name="permlab_bindDreamService" msgid="4153646965978563462">"δεσμεύεται σε υπηρεσία dream"</string>
    -     <string name="permdesc_bindDreamService" msgid="7325825272223347863">"Επιτρέπει στον κάτοχο τη δέσμευση στη διεπαφή ανωτάτου επιπέδου μιας υπηρεσίας dream. Δεν απαιτείται σε κανονικές εφαρμογές."</string>
    --    <string name="permlab_invokeCarrierSetup" msgid="3699600833975117478">"κλήση της εφαρμογής διαμόρφωσης που παρέχεται από την εταιρεία κινητής τηλεφωνίας"</string>
    -+    <string name="permlab_invokeCarrierSetup" msgid="3699600833975117478">"καλέι την εφαρμογή διαμόρφωσης του παρόχου κινητής τηλεφωνίας"</string>
    -     <string name="permdesc_invokeCarrierSetup" msgid="4159549152529111920">"Επιτρέπει στον κάτοχο την κλήση της εφαρμογής διαμόρφωσης που παρέχεται από την εταιρεία κινητής τηλεφωνίας. Δεν απαιτείται για κανονικές εφαρμογές."</string>
    --    <string name="permlab_accessNetworkConditions" msgid="8206077447838909516">"λήψη παρατηρήσεων σχετικά με την κατάσταση δικτύου"</string>
    -+    <string name="permlab_accessNetworkConditions" msgid="8206077447838909516">"ανιχνεύει παρατηρήσεις σχετικά με την κατάσταση δικτύου"</string>
    -     <string name="permdesc_accessNetworkConditions" msgid="6899102075825272211">"Επιτρέπει σε μια εφαρμογή να λαμβάνει παρατηρήσεις σχετικά με την κατάσταση δικτύου. Δεν θα πρέπει να απαιτείται ποτέ για κανονικές εφαρμογές."</string>
    -     <string name="permlab_setInputCalibration" msgid="4902620118878467615">"αλλαγή βαθμονόμησης της συσκευής εισόδου"</string>
    -     <string name="permdesc_setInputCalibration" msgid="4527511047549456929">"Επιτρέπει στην εφαρμογή να τροποποιεί τις παραμέτρους βαθμονόμησης της οθόνης αφής. Δεν απαιτείται για τις κανονικές εφαρμογές."</string>
    --    <string name="permlab_accessDrmCertificates" msgid="7436886640723203615">"πρόσβαση σε πιστοποιητικά DRM"</string>
    -+    <string name="permlab_accessDrmCertificates" msgid="7436886640723203615">"έχει πρόσβαση σε πιστοποιητικά DRM"</string>
    -     <string name="permdesc_accessDrmCertificates" msgid="8073288354426159089">"Επιτρέπει σε μια εφαρμογή να παρέχει και να χρησιμοποιεί πιστοποιητικά DRM. Δεν θα χρειαστεί ποτέ για κανονικές εφαρμογές."</string>
    -     <string name="permlab_handoverStatus" msgid="7820353257219300883">"λήψη κατάστασης μεταφοράς Android Beam"</string>
    -     <string name="permdesc_handoverStatus" msgid="4788144087245714948">"Επιτρέπει σε αυτήν την εφαρμογή να λαμβάνει πληροφορίες σχετικά με τις τρέχουσες μεταφορές Android Beam"</string>
    --    <string name="permlab_removeDrmCertificates" msgid="7044888287209892751">"κατάργηση πιστοποιητικών DRM"</string>
    -+    <string name="permlab_removeDrmCertificates" msgid="7044888287209892751">"καταργεί πιστοποιητικά DRM"</string>
    -     <string name="permdesc_removeDrmCertificates" msgid="7272999075113400993">"Επιτρέπει σε μια εφαρμογή την κατάργηση πιστοποιητικών DRM. Δεν χρειάζεται ποτέ για κανονικές εφαρμογές."</string>
    --    <string name="permlab_bindCarrierMessagingService" msgid="1490229371796969158">"δέσμευση σε υπηρεσία ανταλλαγής μηνυμάτων εταιρείας κινητής τηλεφωνίας"</string>
    -+    <string name="permlab_bindCarrierMessagingService" msgid="1490229371796969158">"δεσμεύεται σε υπηρεσία ανταλλαγής μηνυμάτων παρόχου κινητής τηλεφωνίας"</string>
    -     <string name="permdesc_bindCarrierMessagingService" msgid="2762882888502113944">"Επιτρέπει στον κάτοχο τη δέσμευση στη διεπαφή ανωτάτου επιπέδου μιας υπηρεσίας ανταλλαγής μηνυμάτων εταιρείας κινητής τηλεφωνίας. Δεν απαιτείται για συνήθεις εφαρμογές."</string>
    --    <string name="permlab_bindCarrierServices" msgid="3233108656245526783">"δέσμευση σε υπηρεσίες εταιρείας κινητής τηλεφωνίας"</string>
    -+    <string name="permlab_bindCarrierServices" msgid="3233108656245526783">"δεσμεύεται σε υπηρεσίες του παρόχου κινητής τηλεφωνίας"</string>
    -     <string name="permdesc_bindCarrierServices" msgid="1391552602551084192">"Δίνει στον κάτοχο τη δυνατότητα δέσμευσης σε υπηρεσίες εταιρείας κινητής τηλεφωνίας. Δεν απαιτείται ποτέ για κανονικές εφαρμογές."</string>
    --    <string name="permlab_access_notification_policy" msgid="4247510821662059671">"πρόσβαση στη λειτουργία \"Μην ενοχλείτε\""</string>
    -+    <string name="permlab_access_notification_policy" msgid="4247510821662059671">"έχει πρόσβαση στη λειτουργία \"Μην ενοχλείτε\""</string>
    -     <string name="permdesc_access_notification_policy" msgid="3296832375218749580">"Επιτρέπει στην εφαρμογή την εγγραφή και τη σύνταξη διαμόρφωσης για τη λειτουργία \"Μην ενοχλείτε\"."</string>
    -     <string name="policylab_limitPassword" msgid="4497420728857585791">"Ορισμός κανόνων κωδικού πρόσβασης"</string>
    -     <string name="policydesc_limitPassword" msgid="2502021457917874968">"Ελέγξτε την έκταση και τους επιτρεπόμενους χαρακτήρες σε κωδικούς πρόσβασης κλειδώματος οθόνης και PIN."</string>
    -@@ -791,17 +792,17 @@
    -     <string name="autofill_parish" msgid="8202206105468820057">"Ενορία"</string>
    -     <string name="autofill_area" msgid="3547409050889952423">"Περιοχή"</string>
    -     <string name="autofill_emirate" msgid="2893880978835698818">"Εμιράτο"</string>
    --    <string name="permlab_readHistoryBookmarks" msgid="3775265775405106983">"ανάγνωση των σελιδοδεικτών και του ιστορικού ιστού σας"</string>
    -+    <string name="permlab_readHistoryBookmarks" msgid="3775265775405106983">"διαβάζει τους σελιδοδείκτες και το ιστορικού ιστού"</string>
    -     <string name="permdesc_readHistoryBookmarks" msgid="8462378226600439658">"Επιτρέπει στην εφαρμογή την ανάγνωση του ιστορικού όλων των διευθύνσεων URL που έχει επισκεφτεί το πρόγραμμα περιήγησης, καθώς και όλων των σελιδοδεικτών του προγράμματος περιήγησης. Σημείωση: αυτή η άδεια ίσως να μην μπορεί να εφαρμοστεί από τρίτα προγράμματα περιήγησης ή άλλες εφαρμογές με δυνατότητες περιήγησης ιστού."</string>
    --    <string name="permlab_writeHistoryBookmarks" msgid="3714785165273314490">"εγγραφή σελιδοδεικτών και ιστορικού ιστού"</string>
    -+    <string name="permlab_writeHistoryBookmarks" msgid="3714785165273314490">"εγγράφει σελιδοδείκτες και ιστορικό ιστού"</string>
    -     <string name="permdesc_writeHistoryBookmarks" product="tablet" msgid="6825527469145760922">"Επιτρέπει στην εφαρμογή την τροποποίηση του ιστορικού του προγράμματος περιήγησης ή των σελιδοδεικτών που έχουν αποθηκευτεί στο tablet σας. Αυτό μπορεί να δίνει τη δυνατότητα στην εφαρμογή να διαγράφει ή να τροποποιεί δεδομένα του προγράμματος περιήγησης. Σημείωση: αυτή η άδεια ίσως να μην μπορεί να εφαρμοστεί από τρίτα προγράμματα περιήγησης ή άλλες εφαρμογές με δυνατότητες περιήγησης ιστού."</string>
    -     <string name="permdesc_writeHistoryBookmarks" product="tv" msgid="7007393823197766548">"Επιτρέπει στην εφαρμογή να τροποποιεί το ιστορικό του προγράμματος περιήγησης ή τους σελιδοδείκτες που είναι αποθηκευμένοι στην τηλεόρασή σας. Σημείωση: Αυτό το δικαίωμα δεν πρέπει να εφαρμόζεται από τρίτα προγράμματα περιήγησης ή άλλες εφαρμογές με δυνατότητες περιήγησης στον ιστό."</string>
    -     <string name="permdesc_writeHistoryBookmarks" product="default" msgid="8497389531014185509">"Επιτρέπει στην εφαρμογή την τροποποίηση του ιστορικού του προγράμματος περιήγησης ή των σελιδοδεικτών που έχουν αποθηκευτεί στο τηλέφωνό σας. Αυτό μπορεί να δίνει τη δυνατότητα στην εφαρμογή να διαγράφει ή να τροποποιεί δεδομένα του προγράμματος περιήγησης. Σημείωση: αυτή η άδεια ίσως να μην μπορεί να εφαρμοστεί από τρίτα προγράμματα περιήγησης ή άλλες εφαρμογές με δυνατότητες περιήγησης ιστού."</string>
    --    <string name="permlab_setAlarm" msgid="1379294556362091814">"ρύθμιση ξυπνητηριού"</string>
    -+    <string name="permlab_setAlarm" msgid="1379294556362091814">"ρυθμίζει το ξυπνητήρι"</string>
    -     <string name="permdesc_setAlarm" msgid="316392039157473848">"Επιτρέπει στην εφαρμογή τη ρύθμιση μιας ειδοποίησης σε μια εγκατεστημένη εφαρμογή ξυπνητηριού. Ορισμένες εφαρμογές ξυπνητηριού ενδέχεται να μην μπορούν να ενσωματώσουν αυτήν τη λειτουργία."</string>
    --    <string name="permlab_addVoicemail" msgid="5525660026090959044">"προσθήκη τηλεφωνητή"</string>
    -+    <string name="permlab_addVoicemail" msgid="5525660026090959044">"προσθέτει τηλεφωνητή"</string>
    -     <string name="permdesc_addVoicemail" msgid="6604508651428252437">"Επιτρέπει στην εφαρμογή να προσθέτει μηνύματα στα εισερχόμενα του αυτόματου τηλεφωνητή σας."</string>
    --    <string name="permlab_writeGeolocationPermissions" msgid="5962224158955273932">"τροποποίηση δικαιωμάτων γεωγραφικής θέσης του Προγράμματος περιήγησης"</string>
    -+    <string name="permlab_writeGeolocationPermissions" msgid="5962224158955273932">"τροποποιεί δικαιώματα γεωγραφικής θέσης του Προγράμματος περιήγησης"</string>
    -     <string name="permdesc_writeGeolocationPermissions" msgid="1083743234522638747">"Επιτρέπει στην εφαρμογή την τροποποίηση των αδειών γεωτοποθεσίας του Προγράμματος περιήγησης. Τυχόν κακόβουλες εφαρμογές ενδέχεται να το χρησιμοποιήσουν για να επιτρέψουν την αποστολή πληροφοριών τοποθεσίας σε αυθαίρετους ιστότοπους."</string>
    -     <string name="save_password_message" msgid="767344687139195790">"Θέλετε το πρόγραμμα περιήγησης να διατηρήσει αυτόν τον κωδικό πρόσβασης;"</string>
    -     <string name="save_password_notnow" msgid="6389675316706699758">"Να μην γίνει τώρα"</string>
    -@@ -1076,6 +1077,17 @@
    -     <skip />
    -     <string name="wifi_no_internet" msgid="8451173622563841546">"Το δίκτυο Wi-Fi δεν έχει πρόσβαση στο διαδίκτυο"</string>
    -     <string name="wifi_no_internet_detailed" msgid="8083079241212301741">"Πατήστε για να δείτε τις επιλογές"</string>
    -+    <string name="network_switch_metered" msgid="4671730921726992671">"Μετάβαση σε δίκτυο <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
    -+    <string name="network_switch_metered_detail" msgid="5325661434777870353">"Η συσκευή χρησιμοποιεί το δίκτυο <xliff:g id="NEW_NETWORK">%1$s</xliff:g> όταν το δίκτυο <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> δεν έχει πρόσβαση στο διαδίκτυο. Ενδέχεται να ισχύουν χρεώσεις."</string>
    -+    <string name="network_switch_metered_toast" msgid="5779283181685974304">"Μετάβαση από το δίκτυο <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> στο δίκτυο <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
    -+  <string-array name="network_switch_type_name">
    -+    <item msgid="2952042958050315394">"δεδομένα κινητής τηλεφωνίας"</item>
    -+    <item msgid="75483255295529161">"Wi-Fi"</item>
    -+    <item msgid="6862614801537202646">"Bluetooth"</item>
    -+    <item msgid="5447331121797802871">"Ethernet"</item>
    -+    <item msgid="8257233890381651999">"VPN"</item>
    -+  </string-array>
    -+    <string name="network_switch_type_name_unknown" msgid="4552612897806660656">"άγνωστος τύπος δικτύου"</string>
    -     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Δεν είναι δυνατή η σύνδεση στο Wi-Fi"</string>
    -     <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" έχει κακή σύνδεση στο Διαδίκτυο."</string>
    -     <string name="wifi_connect_alert_title" msgid="8455846016001810172">"Να επιτρέπεται η σύνδεση;"</string>
    -@@ -1153,7 +1165,6 @@
    -     <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"Πατήστε για να επιλέξετε γλώσσα και διάταξη"</string>
    -     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
    -     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
    --    <string name="candidates_style" msgid="4333913089637062257"><u>"υποψήφιοι"</u></string>
    -     <string name="ext_media_checking_notification_title" msgid="5734005953288045806">"Προετοιμασία <xliff:g id="NAME">%s</xliff:g>"</string>
    -     <string name="ext_media_checking_notification_message" msgid="4747432538578886744">"Έλεγχος για σφάλματα"</string>
    -     <string name="ext_media_new_notification_message" msgid="7589986898808506239">"Εντοπίστηκε νέο μέσο αποθήκευσης <xliff:g id="NAME">%s</xliff:g>"</string>
    -@@ -1191,11 +1202,11 @@
    -     <string name="ext_media_status_formatting" msgid="1085079556538644861">"Διαμόρφωση…"</string>
    -     <string name="ext_media_status_missing" msgid="5638633895221670766">"Δεν έχει εισαχθεί"</string>
    -     <string name="activity_list_empty" msgid="1675388330786841066">"Δεν βρέθηκαν δραστηριότητες που να συμφωνούν με τα κριτήρια."</string>
    --    <string name="permlab_route_media_output" msgid="6243022988998972085">"δρομολόγηση εξόδου μέσων"</string>
    -+    <string name="permlab_route_media_output" msgid="6243022988998972085">"δρομολογεί την έξοδο μέσων"</string>
    -     <string name="permdesc_route_media_output" msgid="4932818749547244346">"Επιτρέπει σε μια εφαρμογή τη διαγραφή διαδρομής δεδομένων εξόδου μέσων σε άλλες εξωτερικές συσκευές."</string>
    --    <string name="permlab_readInstallSessions" msgid="3713753067455750349">"ανάγνωση περιόδων σύνδεσης εγκατάστασης"</string>
    -+    <string name="permlab_readInstallSessions" msgid="3713753067455750349">"διαβάζει τις περιόδους σύνδεσης εγκατάστασης"</string>
    -     <string name="permdesc_readInstallSessions" msgid="2049771699626019849">"Επιτρέπει σε μια εφαρμογή την ανάγνωση των περιόδων σύνδεσης εγκατάστασης. Αυτό της επιτρέπει να βλέπει λεπτομέρειες σχετικά με τις εγκαταστάσεις του ενεργού πακέτου."</string>
    --    <string name="permlab_requestInstallPackages" msgid="5782013576218172577">"αίτημα εγκατάστασης πακέτων"</string>
    -+    <string name="permlab_requestInstallPackages" msgid="5782013576218172577">"ζητά πακέτα εγκατάστασης"</string>
    -     <string name="permdesc_requestInstallPackages" msgid="5740101072486783082">"Επιτρέπει σε μια εφαρμογή να ζητά εγκατάσταση πακέτων."</string>
    -     <string name="tutorial_double_tap_to_zoom_message_short" msgid="1311810005957319690">"Πατήστε δύο φορές για έλεγχο εστίασης"</string>
    -     <string name="gadget_host_error_inflating" msgid="4882004314906466162">"Δεν ήταν δυνατή η προσθήκη του γραφικού στοιχείου."</string>
    -@@ -1232,8 +1243,9 @@
    -     <string name="vpn_text_long" msgid="4907843483284977618">"Συνδέθηκε με <xliff:g id="SESSION">%s</xliff:g>. Πατήστε για να διαχειριστείτε το δίκτυο."</string>
    -     <string name="vpn_lockdown_connecting" msgid="6443438964440960745">"Σύνδεση πάντα ενεργοποιημένου VPN…"</string>
    -     <string name="vpn_lockdown_connected" msgid="8202679674819213931">"Έχει συνδεθεί πάντα ενεργοποιημένο VPN"</string>
    -+    <string name="vpn_lockdown_disconnected" msgid="4532298952570796327">"Το πάντα ενεργοποιημένο VPN αποσυνδέθηκε"</string>
    -     <string name="vpn_lockdown_error" msgid="6009249814034708175">"Σφάλμα πάντα ενεργοποιημένου VPN"</string>
    --    <string name="vpn_lockdown_config" msgid="4655589351146766608">"Πατήστε για διαμόρφωση"</string>
    -+    <string name="vpn_lockdown_config" msgid="5099330695245008680">"Πατήστε για ρύθμιση"</string>
    -     <string name="upload_file" msgid="2897957172366730416">"Επιλογή αρχείου"</string>
    -     <string name="no_file_chosen" msgid="6363648562170759465">"Δεν επιλέχθηκε κανένα αρχείο."</string>
    -     <string name="reset" msgid="2448168080964209908">"Επαναφορά"</string>
    -@@ -1317,7 +1329,7 @@
    -     <string name="storage_usb_drive_label" msgid="4501418548927759953">"Μονάδα USB <xliff:g id="MANUFACTURER">%s</xliff:g>"</string>
    -     <string name="storage_usb" msgid="3017954059538517278">"Αποθηκευτικός χώρος USB"</string>
    -     <string name="extract_edit_menu_button" msgid="8940478730496610137">"Επεξεργασία"</string>
    --    <string name="data_usage_warning_title" msgid="1955638862122232342">"Προειδοποίηση χρήσης δεδομένων"</string>
    -+    <string name="data_usage_warning_title" msgid="3620440638180218181">"Ειδοποίηση χρήσης δεδομένων"</string>
    -     <string name="data_usage_warning_body" msgid="6660692274311972007">"Πατήστε για προβολή χρήσης/ρυθμ."</string>
    -     <string name="data_usage_3g_limit_title" msgid="4361523876818447683">"Συμπλ. το όριο δεδομένων 2G-3G"</string>
    -     <string name="data_usage_4g_limit_title" msgid="4609566827219442376">"Συμπλ. το όριο δεδομένων 4G"</string>
    -@@ -1636,6 +1648,7 @@
    -     <string name="search_language_hint" msgid="7042102592055108574">"Εισαγ. όνομα γλώσσας"</string>
    -     <string name="language_picker_section_suggested" msgid="8414489646861640885">"Προτεινόμενες"</string>
    -     <string name="language_picker_section_all" msgid="3097279199511617537">"Όλες οι γλώσσες"</string>
    -+    <string name="region_picker_section_all" msgid="8966316787153001779">"Όλες οι περιοχές"</string>
    -     <string name="locale_search_menu" msgid="2560710726687249178">"Αναζήτηση"</string>
    -     <string name="work_mode_off_title" msgid="8954725060677558855">"Λειτουργία εργασίας ΑΠΕΝΕΡΓ/ΝΗ"</string>
    -     <string name="work_mode_off_message" msgid="3286169091278094476">"Να επιτρέπεται η λειτουργία του προφίλ εργασίας σας, συμπεριλαμβανομένων των εφαρμογών, του συγχρονισμού στο παρασκήνιο και των σχετικών λειτουργιών."</string>
    -diff --git a/core/res/res/values-en-rAU/strings.xml b/core/res/res/values-en-rAU/strings.xml
    -index 12b7aa5..c6e04d7 100644
    ---- a/core/res/res/values-en-rAU/strings.xml
    -+++ b/core/res/res/values-en-rAU/strings.xml
    -@@ -214,6 +214,7 @@
    -     <string name="global_actions" product="default" msgid="2406416831541615258">"Phone options"</string>
    -     <string name="global_action_lock" msgid="2844945191792119712">"Screen lock"</string>
    -     <string name="global_action_power_off" msgid="4471879440839879722">"Power off"</string>
    -+    <string name="global_action_emergency" msgid="7112311161137421166">"Emergency"</string>
    -     <string name="global_action_bug_report" msgid="7934010578922304799">"Bug report"</string>
    -     <string name="bugreport_title" msgid="2667494803742548533">"Take bug report"</string>
    -     <string name="bugreport_message" msgid="398447048750350456">"This will collect information about your current device state, to send as an email message. It will take a little time from starting the bug report until it is ready to be sent. Please be patient."</string>
    -@@ -1076,6 +1077,17 @@
    -     <skip />
    -     <string name="wifi_no_internet" msgid="8451173622563841546">"Wi-Fi has no Internet access"</string>
    -     <string name="wifi_no_internet_detailed" msgid="8083079241212301741">"Tap for options"</string>
    -+    <string name="network_switch_metered" msgid="4671730921726992671">"Switched to <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
    -+    <string name="network_switch_metered_detail" msgid="5325661434777870353">"Device uses <xliff:g id="NEW_NETWORK">%1$s</xliff:g> when <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> has no Internet access. Charges may apply."</string>
    -+    <string name="network_switch_metered_toast" msgid="5779283181685974304">"Switched from <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> to <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
    -+  <string-array name="network_switch_type_name">
    -+    <item msgid="2952042958050315394">"mobile data"</item>
    -+    <item msgid="75483255295529161">"Wi-Fi"</item>
    -+    <item msgid="6862614801537202646">"Bluetooth"</item>
    -+    <item msgid="5447331121797802871">"Ethernet"</item>
    -+    <item msgid="8257233890381651999">"VPN"</item>
    -+  </string-array>
    -+    <string name="network_switch_type_name_unknown" msgid="4552612897806660656">"an unknown network type"</string>
    -     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Couldn\'t connect to Wi-Fi"</string>
    -     <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" has a poor Internet connection."</string>
    -     <string name="wifi_connect_alert_title" msgid="8455846016001810172">"Allow connection?"</string>
    -@@ -1153,7 +1165,6 @@
    -     <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"Tap to select language and layout"</string>
    -     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
    -     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
    --    <string name="candidates_style" msgid="4333913089637062257"><u>"candidates"</u></string>
    -     <string name="ext_media_checking_notification_title" msgid="5734005953288045806">"Preparing <xliff:g id="NAME">%s</xliff:g>"</string>
    -     <string name="ext_media_checking_notification_message" msgid="4747432538578886744">"Checking for errors"</string>
    -     <string name="ext_media_new_notification_message" msgid="7589986898808506239">"New <xliff:g id="NAME">%s</xliff:g> detected"</string>
    -@@ -1232,8 +1243,9 @@
    -     <string name="vpn_text_long" msgid="4907843483284977618">"Connected to <xliff:g id="SESSION">%s</xliff:g>. Tap to manage the network."</string>
    -     <string name="vpn_lockdown_connecting" msgid="6443438964440960745">"Always-on VPN connecting…"</string>
    -     <string name="vpn_lockdown_connected" msgid="8202679674819213931">"Always-on VPN connected"</string>
    -+    <string name="vpn_lockdown_disconnected" msgid="4532298952570796327">"Always-on VPN disconnected"</string>
    -     <string name="vpn_lockdown_error" msgid="6009249814034708175">"Always-on VPN error"</string>
    --    <string name="vpn_lockdown_config" msgid="4655589351146766608">"Tap to configure"</string>
    -+    <string name="vpn_lockdown_config" msgid="5099330695245008680">"Tap to set up"</string>
    -     <string name="upload_file" msgid="2897957172366730416">"Choose file"</string>
    -     <string name="no_file_chosen" msgid="6363648562170759465">"No file chosen"</string>
    -     <string name="reset" msgid="2448168080964209908">"Reset"</string>
    -@@ -1317,7 +1329,7 @@
    -     <string name="storage_usb_drive_label" msgid="4501418548927759953">"<xliff:g id="MANUFACTURER">%s</xliff:g> USB drive"</string>
    -     <string name="storage_usb" msgid="3017954059538517278">"USB storage"</string>
    -     <string name="extract_edit_menu_button" msgid="8940478730496610137">"Edit"</string>
    --    <string name="data_usage_warning_title" msgid="1955638862122232342">"Data usage warning"</string>
    -+    <string name="data_usage_warning_title" msgid="3620440638180218181">"Data usage alert"</string>
    -     <string name="data_usage_warning_body" msgid="6660692274311972007">"Tap to view usage and settings."</string>
    -     <string name="data_usage_3g_limit_title" msgid="4361523876818447683">"2G-3G data limit reached"</string>
    -     <string name="data_usage_4g_limit_title" msgid="4609566827219442376">"4G data limit reached"</string>
    -@@ -1636,6 +1648,7 @@
    -     <string name="search_language_hint" msgid="7042102592055108574">"Type language name"</string>
    -     <string name="language_picker_section_suggested" msgid="8414489646861640885">"Suggested"</string>
    -     <string name="language_picker_section_all" msgid="3097279199511617537">"All languages"</string>
    -+    <string name="region_picker_section_all" msgid="8966316787153001779">"All regions"</string>
    -     <string name="locale_search_menu" msgid="2560710726687249178">"Search"</string>
    -     <string name="work_mode_off_title" msgid="8954725060677558855">"Work mode is OFF"</string>
    -     <string name="work_mode_off_message" msgid="3286169091278094476">"Allow work profile to function, including apps, background sync and related features."</string>
    -diff --git a/core/res/res/values-en-rGB/strings.xml b/core/res/res/values-en-rGB/strings.xml
    -index 12b7aa5..c6e04d7 100644
    ---- a/core/res/res/values-en-rGB/strings.xml
    -+++ b/core/res/res/values-en-rGB/strings.xml
    -@@ -214,6 +214,7 @@
    -     <string name="global_actions" product="default" msgid="2406416831541615258">"Phone options"</string>
    -     <string name="global_action_lock" msgid="2844945191792119712">"Screen lock"</string>
    -     <string name="global_action_power_off" msgid="4471879440839879722">"Power off"</string>
    -+    <string name="global_action_emergency" msgid="7112311161137421166">"Emergency"</string>
    -     <string name="global_action_bug_report" msgid="7934010578922304799">"Bug report"</string>
    -     <string name="bugreport_title" msgid="2667494803742548533">"Take bug report"</string>
    -     <string name="bugreport_message" msgid="398447048750350456">"This will collect information about your current device state, to send as an email message. It will take a little time from starting the bug report until it is ready to be sent. Please be patient."</string>
    -@@ -1076,6 +1077,17 @@
    -     <skip />
    -     <string name="wifi_no_internet" msgid="8451173622563841546">"Wi-Fi has no Internet access"</string>
    -     <string name="wifi_no_internet_detailed" msgid="8083079241212301741">"Tap for options"</string>
    -+    <string name="network_switch_metered" msgid="4671730921726992671">"Switched to <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
    -+    <string name="network_switch_metered_detail" msgid="5325661434777870353">"Device uses <xliff:g id="NEW_NETWORK">%1$s</xliff:g> when <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> has no Internet access. Charges may apply."</string>
    -+    <string name="network_switch_metered_toast" msgid="5779283181685974304">"Switched from <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> to <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
    -+  <string-array name="network_switch_type_name">
    -+    <item msgid="2952042958050315394">"mobile data"</item>
    -+    <item msgid="75483255295529161">"Wi-Fi"</item>
    -+    <item msgid="6862614801537202646">"Bluetooth"</item>
    -+    <item msgid="5447331121797802871">"Ethernet"</item>
    -+    <item msgid="8257233890381651999">"VPN"</item>
    -+  </string-array>
    -+    <string name="network_switch_type_name_unknown" msgid="4552612897806660656">"an unknown network type"</string>
    -     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Couldn\'t connect to Wi-Fi"</string>
    -     <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" has a poor Internet connection."</string>
    -     <string name="wifi_connect_alert_title" msgid="8455846016001810172">"Allow connection?"</string>
    -@@ -1153,7 +1165,6 @@
    -     <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"Tap to select language and layout"</string>
    -     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
    -     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
    --    <string name="candidates_style" msgid="4333913089637062257"><u>"candidates"</u></string>
    -     <string name="ext_media_checking_notification_title" msgid="5734005953288045806">"Preparing <xliff:g id="NAME">%s</xliff:g>"</string>
    -     <string name="ext_media_checking_notification_message" msgid="4747432538578886744">"Checking for errors"</string>
    -     <string name="ext_media_new_notification_message" msgid="7589986898808506239">"New <xliff:g id="NAME">%s</xliff:g> detected"</string>
    -@@ -1232,8 +1243,9 @@
    -     <string name="vpn_text_long" msgid="4907843483284977618">"Connected to <xliff:g id="SESSION">%s</xliff:g>. Tap to manage the network."</string>
    -     <string name="vpn_lockdown_connecting" msgid="6443438964440960745">"Always-on VPN connecting…"</string>
    -     <string name="vpn_lockdown_connected" msgid="8202679674819213931">"Always-on VPN connected"</string>
    -+    <string name="vpn_lockdown_disconnected" msgid="4532298952570796327">"Always-on VPN disconnected"</string>
    -     <string name="vpn_lockdown_error" msgid="6009249814034708175">"Always-on VPN error"</string>
    --    <string name="vpn_lockdown_config" msgid="4655589351146766608">"Tap to configure"</string>
    -+    <string name="vpn_lockdown_config" msgid="5099330695245008680">"Tap to set up"</string>
    -     <string name="upload_file" msgid="2897957172366730416">"Choose file"</string>
    -     <string name="no_file_chosen" msgid="6363648562170759465">"No file chosen"</string>
    -     <string name="reset" msgid="2448168080964209908">"Reset"</string>
    -@@ -1317,7 +1329,7 @@
    -     <string name="storage_usb_drive_label" msgid="4501418548927759953">"<xliff:g id="MANUFACTURER">%s</xliff:g> USB drive"</string>
    -     <string name="storage_usb" msgid="3017954059538517278">"USB storage"</string>
    -     <string name="extract_edit_menu_button" msgid="8940478730496610137">"Edit"</string>
    --    <string name="data_usage_warning_title" msgid="1955638862122232342">"Data usage warning"</string>
    -+    <string name="data_usage_warning_title" msgid="3620440638180218181">"Data usage alert"</string>
    -     <string name="data_usage_warning_body" msgid="6660692274311972007">"Tap to view usage and settings."</string>
    -     <string name="data_usage_3g_limit_title" msgid="4361523876818447683">"2G-3G data limit reached"</string>
    -     <string name="data_usage_4g_limit_title" msgid="4609566827219442376">"4G data limit reached"</string>
    -@@ -1636,6 +1648,7 @@
    -     <string name="search_language_hint" msgid="7042102592055108574">"Type language name"</string>
    -     <string name="language_picker_section_suggested" msgid="8414489646861640885">"Suggested"</string>
    -     <string name="language_picker_section_all" msgid="3097279199511617537">"All languages"</string>
    -+    <string name="region_picker_section_all" msgid="8966316787153001779">"All regions"</string>
    -     <string name="locale_search_menu" msgid="2560710726687249178">"Search"</string>
    -     <string name="work_mode_off_title" msgid="8954725060677558855">"Work mode is OFF"</string>
    -     <string name="work_mode_off_message" msgid="3286169091278094476">"Allow work profile to function, including apps, background sync and related features."</string>
    -diff --git a/core/res/res/values-en-rIN/strings.xml b/core/res/res/values-en-rIN/strings.xml
    -index 12b7aa5..c6e04d7 100644
    ---- a/core/res/res/values-en-rIN/strings.xml
    -+++ b/core/res/res/values-en-rIN/strings.xml
    -@@ -214,6 +214,7 @@
    -     <string name="global_actions" product="default" msgid="2406416831541615258">"Phone options"</string>
    -     <string name="global_action_lock" msgid="2844945191792119712">"Screen lock"</string>
    -     <string name="global_action_power_off" msgid="4471879440839879722">"Power off"</string>
    -+    <string name="global_action_emergency" msgid="7112311161137421166">"Emergency"</string>
    -     <string name="global_action_bug_report" msgid="7934010578922304799">"Bug report"</string>
    -     <string name="bugreport_title" msgid="2667494803742548533">"Take bug report"</string>
    -     <string name="bugreport_message" msgid="398447048750350456">"This will collect information about your current device state, to send as an email message. It will take a little time from starting the bug report until it is ready to be sent. Please be patient."</string>
    -@@ -1076,6 +1077,17 @@
    -     <skip />
    -     <string name="wifi_no_internet" msgid="8451173622563841546">"Wi-Fi has no Internet access"</string>
    -     <string name="wifi_no_internet_detailed" msgid="8083079241212301741">"Tap for options"</string>
    -+    <string name="network_switch_metered" msgid="4671730921726992671">"Switched to <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
    -+    <string name="network_switch_metered_detail" msgid="5325661434777870353">"Device uses <xliff:g id="NEW_NETWORK">%1$s</xliff:g> when <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> has no Internet access. Charges may apply."</string>
    -+    <string name="network_switch_metered_toast" msgid="5779283181685974304">"Switched from <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> to <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
    -+  <string-array name="network_switch_type_name">
    -+    <item msgid="2952042958050315394">"mobile data"</item>
    -+    <item msgid="75483255295529161">"Wi-Fi"</item>
    -+    <item msgid="6862614801537202646">"Bluetooth"</item>
    -+    <item msgid="5447331121797802871">"Ethernet"</item>
    -+    <item msgid="8257233890381651999">"VPN"</item>
    -+  </string-array>
    -+    <string name="network_switch_type_name_unknown" msgid="4552612897806660656">"an unknown network type"</string>
    -     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Couldn\'t connect to Wi-Fi"</string>
    -     <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" has a poor Internet connection."</string>
    -     <string name="wifi_connect_alert_title" msgid="8455846016001810172">"Allow connection?"</string>
    -@@ -1153,7 +1165,6 @@
    -     <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"Tap to select language and layout"</string>
    -     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
    -     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
    --    <string name="candidates_style" msgid="4333913089637062257"><u>"candidates"</u></string>
    -     <string name="ext_media_checking_notification_title" msgid="5734005953288045806">"Preparing <xliff:g id="NAME">%s</xliff:g>"</string>
    -     <string name="ext_media_checking_notification_message" msgid="4747432538578886744">"Checking for errors"</string>
    -     <string name="ext_media_new_notification_message" msgid="7589986898808506239">"New <xliff:g id="NAME">%s</xliff:g> detected"</string>
    -@@ -1232,8 +1243,9 @@
    -     <string name="vpn_text_long" msgid="4907843483284977618">"Connected to <xliff:g id="SESSION">%s</xliff:g>. Tap to manage the network."</string>
    -     <string name="vpn_lockdown_connecting" msgid="6443438964440960745">"Always-on VPN connecting…"</string>
    -     <string name="vpn_lockdown_connected" msgid="8202679674819213931">"Always-on VPN connected"</string>
    -+    <string name="vpn_lockdown_disconnected" msgid="4532298952570796327">"Always-on VPN disconnected"</string>
    -     <string name="vpn_lockdown_error" msgid="6009249814034708175">"Always-on VPN error"</string>
    --    <string name="vpn_lockdown_config" msgid="4655589351146766608">"Tap to configure"</string>
    -+    <string name="vpn_lockdown_config" msgid="5099330695245008680">"Tap to set up"</string>
    -     <string name="upload_file" msgid="2897957172366730416">"Choose file"</string>
    -     <string name="no_file_chosen" msgid="6363648562170759465">"No file chosen"</string>
    -     <string name="reset" msgid="2448168080964209908">"Reset"</string>
    -@@ -1317,7 +1329,7 @@
    -     <string name="storage_usb_drive_label" msgid="4501418548927759953">"<xliff:g id="MANUFACTURER">%s</xliff:g> USB drive"</string>
    -     <string name="storage_usb" msgid="3017954059538517278">"USB storage"</string>
    -     <string name="extract_edit_menu_button" msgid="8940478730496610137">"Edit"</string>
    --    <string name="data_usage_warning_title" msgid="1955638862122232342">"Data usage warning"</string>
    -+    <string name="data_usage_warning_title" msgid="3620440638180218181">"Data usage alert"</string>
    -     <string name="data_usage_warning_body" msgid="6660692274311972007">"Tap to view usage and settings."</string>
    -     <string name="data_usage_3g_limit_title" msgid="4361523876818447683">"2G-3G data limit reached"</string>
    -     <string name="data_usage_4g_limit_title" msgid="4609566827219442376">"4G data limit reached"</string>
    -@@ -1636,6 +1648,7 @@
    -     <string name="search_language_hint" msgid="7042102592055108574">"Type language name"</string>
    -     <string name="language_picker_section_suggested" msgid="8414489646861640885">"Suggested"</string>
    -     <string name="language_picker_section_all" msgid="3097279199511617537">"All languages"</string>
    -+    <string name="region_picker_section_all" msgid="8966316787153001779">"All regions"</string>
    -     <string name="locale_search_menu" msgid="2560710726687249178">"Search"</string>
    -     <string name="work_mode_off_title" msgid="8954725060677558855">"Work mode is OFF"</string>
    -     <string name="work_mode_off_message" msgid="3286169091278094476">"Allow work profile to function, including apps, background sync and related features."</string>
    -diff --git a/core/res/res/values-es-rUS/strings.xml b/core/res/res/values-es-rUS/strings.xml
    -index 136902b..ea1c1a5 100644
    ---- a/core/res/res/values-es-rUS/strings.xml
    -+++ b/core/res/res/values-es-rUS/strings.xml
    -@@ -214,6 +214,7 @@
    -     <string name="global_actions" product="default" msgid="2406416831541615258">"Opciones de dispositivo"</string>
    -     <string name="global_action_lock" msgid="2844945191792119712">"Bloqueo de pantalla"</string>
    -     <string name="global_action_power_off" msgid="4471879440839879722">"Apagar"</string>
    -+    <string name="global_action_emergency" msgid="7112311161137421166">"Emergencias"</string>
    -     <string name="global_action_bug_report" msgid="7934010578922304799">"Informe de errores"</string>
    -     <string name="bugreport_title" msgid="2667494803742548533">"Iniciar informe de errores"</string>
    -     <string name="bugreport_message" msgid="398447048750350456">"Se recopilará información sobre el estado actual de tu dispositivo, que se enviará por correo. Pasarán unos minutos desde que se inicie el informe de errores hasta que se envíe, por lo que te recomendamos que tengas paciencia."</string>
    -@@ -1076,6 +1077,17 @@
    -     <skip />
    -     <string name="wifi_no_internet" msgid="8451173622563841546">"La red Wi-Fi no tiene acceso a Internet"</string>
    -     <string name="wifi_no_internet_detailed" msgid="8083079241212301741">"Presiona para ver opciones"</string>
    -+    <string name="network_switch_metered" msgid="4671730921726992671">"Se cambió a <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
    -+    <string name="network_switch_metered_detail" msgid="5325661434777870353">"El dispositivo usa <xliff:g id="NEW_NETWORK">%1$s</xliff:g> cuando <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> no tiene acceso a Internet. Es posible que se apliquen cargos."</string>
    -+    <string name="network_switch_metered_toast" msgid="5779283181685974304">"Se cambió de <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> a <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
    -+  <string-array name="network_switch_type_name">
    -+    <item msgid="2952042958050315394">"datos móviles"</item>
    -+    <item msgid="75483255295529161">"Wi-Fi"</item>
    -+    <item msgid="6862614801537202646">"Bluetooth"</item>
    -+    <item msgid="5447331121797802871">"Ethernet"</item>
    -+    <item msgid="8257233890381651999">"VPN"</item>
    -+  </string-array>
    -+    <string name="network_switch_type_name_unknown" msgid="4552612897806660656">"un tipo de red desconocido"</string>
    -     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"No se pudo conectar a la red Wi-Fi."</string>
    -     <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" tiene una mala conexión a Internet."</string>
    -     <string name="wifi_connect_alert_title" msgid="8455846016001810172">"¿Permitir la conexión?"</string>
    -@@ -1153,7 +1165,6 @@
    -     <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"Presiona para seleccionar el idioma y el diseño"</string>
    -     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
    -     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
    --    <string name="candidates_style" msgid="4333913089637062257"><u>"candidatos"</u></string>
    -     <string name="ext_media_checking_notification_title" msgid="5734005953288045806">"Preparando el medio <xliff:g id="NAME">%s</xliff:g>"</string>
    -     <string name="ext_media_checking_notification_message" msgid="4747432538578886744">"Verificando errores"</string>
    -     <string name="ext_media_new_notification_message" msgid="7589986898808506239">"Se detectó un nuevo medio (<xliff:g id="NAME">%s</xliff:g>)."</string>
    -@@ -1232,8 +1243,9 @@
    -     <string name="vpn_text_long" msgid="4907843483284977618">"Conectado a <xliff:g id="SESSION">%s</xliff:g>. Pulsa para gestionar la red."</string>
    -     <string name="vpn_lockdown_connecting" msgid="6443438964440960745">"Estableciendo conexión con la VPN siempre activada..."</string>
    -     <string name="vpn_lockdown_connected" msgid="8202679674819213931">"Se estableció conexión con la VPN siempre activada."</string>
    -+    <string name="vpn_lockdown_disconnected" msgid="4532298952570796327">"Se desconectó la VPN siempre activada"</string>
    -     <string name="vpn_lockdown_error" msgid="6009249814034708175">"Se produjo un error al establecer conexión con la VPN siempre activada."</string>
    --    <string name="vpn_lockdown_config" msgid="4655589351146766608">"Presiona para configurar"</string>
    -+    <string name="vpn_lockdown_config" msgid="5099330695245008680">"Presiona para configurar"</string>
    -     <string name="upload_file" msgid="2897957172366730416">"Elegir archivo"</string>
    -     <string name="no_file_chosen" msgid="6363648562170759465">"No se seleccionó un archivo."</string>
    -     <string name="reset" msgid="2448168080964209908">"Restablecer"</string>
    -@@ -1317,7 +1329,7 @@
    -     <string name="storage_usb_drive_label" msgid="4501418548927759953">"Unidad USB de <xliff:g id="MANUFACTURER">%s</xliff:g>"</string>
    -     <string name="storage_usb" msgid="3017954059538517278">"Almacenamiento USB"</string>
    -     <string name="extract_edit_menu_button" msgid="8940478730496610137">"Editar"</string>
    --    <string name="data_usage_warning_title" msgid="1955638862122232342">"Advertencia de uso de datos"</string>
    -+    <string name="data_usage_warning_title" msgid="3620440638180218181">"Alerta por el uso de datos"</string>
    -     <string name="data_usage_warning_body" msgid="6660692274311972007">"Presiona para uso y opciones."</string>
    -     <string name="data_usage_3g_limit_title" msgid="4361523876818447683">"Límite de datos 2G-3G alcanzado"</string>
    -     <string name="data_usage_4g_limit_title" msgid="4609566827219442376">"Límite de datos 4G alcanzado"</string>
    -@@ -1636,6 +1648,7 @@
    -     <string name="search_language_hint" msgid="7042102592055108574">"Nombre del idioma"</string>
    -     <string name="language_picker_section_suggested" msgid="8414489646861640885">"Sugeridos"</string>
    -     <string name="language_picker_section_all" msgid="3097279199511617537">"Todos los idiomas"</string>
    -+    <string name="region_picker_section_all" msgid="8966316787153001779">"Todas las regiones"</string>
    -     <string name="locale_search_menu" msgid="2560710726687249178">"Búsqueda"</string>
    -     <string name="work_mode_off_title" msgid="8954725060677558855">"Modo de trabajo DESACTIVADO"</string>
    -     <string name="work_mode_off_message" msgid="3286169091278094476">"Permite que se active el perfil de trabajo, incluidas las apps, la sincronización en segundo plano y las funciones relacionadas."</string>
    -diff --git a/core/res/res/values-es/strings.xml b/core/res/res/values-es/strings.xml
    -index c4ebb02..c6d6663 100644
    ---- a/core/res/res/values-es/strings.xml
    -+++ b/core/res/res/values-es/strings.xml
    -@@ -214,6 +214,7 @@
    -     <string name="global_actions" product="default" msgid="2406416831541615258">"Opciones del teléfono"</string>
    -     <string name="global_action_lock" msgid="2844945191792119712">"Bloqueo de pantalla"</string>
    -     <string name="global_action_power_off" msgid="4471879440839879722">"Apagar"</string>
    -+    <string name="global_action_emergency" msgid="7112311161137421166">"Emergencia"</string>
    -     <string name="global_action_bug_report" msgid="7934010578922304799">"Informe de error"</string>
    -     <string name="bugreport_title" msgid="2667494803742548533">"Crear informe de errores"</string>
    -     <string name="bugreport_message" msgid="398447048750350456">"Se recopilará información sobre el estado actual de tu dispositivo y se enviará por correo electrónico. Pasarán unos minutos desde que empiece a generarse el informe de errores hasta que se envíe."</string>
    -@@ -1076,6 +1077,17 @@
    -     <skip />
    -     <string name="wifi_no_internet" msgid="8451173622563841546">"Wi-Fi sin acceso a Internet"</string>
    -     <string name="wifi_no_internet_detailed" msgid="8083079241212301741">"Toca para ver opciones"</string>
    -+    <string name="network_switch_metered" msgid="4671730921726992671">"Se ha cambiado a <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
    -+    <string name="network_switch_metered_detail" msgid="5325661434777870353">"El dispositivo utiliza <xliff:g id="NEW_NETWORK">%1$s</xliff:g> cuando <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> no tiene acceso a Internet. Es posible que se apliquen cargos."</string>
    -+    <string name="network_switch_metered_toast" msgid="5779283181685974304">"Se ha cambiado de <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> a <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
    -+  <string-array name="network_switch_type_name">
    -+    <item msgid="2952042958050315394">"datos móviles"</item>
    -+    <item msgid="75483255295529161">"Wi-Fi"</item>
    -+    <item msgid="6862614801537202646">"Bluetooth"</item>
    -+    <item msgid="5447331121797802871">"Ethernet"</item>
    -+    <item msgid="8257233890381651999">"VPN"</item>
    -+  </string-array>
    -+    <string name="network_switch_type_name_unknown" msgid="4552612897806660656">"tipo de red desconocido"</string>
    -     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"No se ha podido establecer conexión con la red Wi-Fi."</string>
    -     <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" tiene una conexión inestable a Internet."</string>
    -     <string name="wifi_connect_alert_title" msgid="8455846016001810172">"¿Permitir la conexión?"</string>
    -@@ -1153,7 +1165,6 @@
    -     <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"Toca para seleccionar el idioma y el diseño"</string>
    -     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
    -     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
    --    <string name="candidates_style" msgid="4333913089637062257"><u>"candidatos"</u></string>
    -     <string name="ext_media_checking_notification_title" msgid="5734005953288045806">"Preparando <xliff:g id="NAME">%s</xliff:g>"</string>
    -     <string name="ext_media_checking_notification_message" msgid="4747432538578886744">"Comprobando errores"</string>
    -     <string name="ext_media_new_notification_message" msgid="7589986898808506239">"Nueva <xliff:g id="NAME">%s</xliff:g> detectada"</string>
    -@@ -1232,8 +1243,9 @@
    -     <string name="vpn_text_long" msgid="4907843483284977618">"Conectado a <xliff:g id="SESSION">%s</xliff:g>. Toca para administrar la red."</string>
    -     <string name="vpn_lockdown_connecting" msgid="6443438964440960745">"Conectando VPN siempre activada…"</string>
    -     <string name="vpn_lockdown_connected" msgid="8202679674819213931">"VPN siempre activada conectada"</string>
    -+    <string name="vpn_lockdown_disconnected" msgid="4532298952570796327">"VPN siempre activada desconectada"</string>
    -     <string name="vpn_lockdown_error" msgid="6009249814034708175">"Error de VPN siempre activada"</string>
    --    <string name="vpn_lockdown_config" msgid="4655589351146766608">"Toca para configurar"</string>
    -+    <string name="vpn_lockdown_config" msgid="5099330695245008680">"Toca para configurar"</string>
    -     <string name="upload_file" msgid="2897957172366730416">"Seleccionar archivo"</string>
    -     <string name="no_file_chosen" msgid="6363648562170759465">"Archivo no seleccionado"</string>
    -     <string name="reset" msgid="2448168080964209908">"Restablecer"</string>
    -@@ -1317,7 +1329,7 @@
    -     <string name="storage_usb_drive_label" msgid="4501418548927759953">"Unidad USB <xliff:g id="MANUFACTURER">%s</xliff:g>"</string>
    -     <string name="storage_usb" msgid="3017954059538517278">"Almacenamiento USB"</string>
    -     <string name="extract_edit_menu_button" msgid="8940478730496610137">"Editar"</string>
    --    <string name="data_usage_warning_title" msgid="1955638862122232342">"Advertencia de uso de datos"</string>
    -+    <string name="data_usage_warning_title" msgid="3620440638180218181">"Alerta sobre el uso de datos"</string>
    -     <string name="data_usage_warning_body" msgid="6660692274311972007">"Toca para ver uso y ajustes."</string>
    -     <string name="data_usage_3g_limit_title" msgid="4361523876818447683">"Límite de datos 2G-3G alcanzado"</string>
    -     <string name="data_usage_4g_limit_title" msgid="4609566827219442376">"Límite de datos 4G alcanzado"</string>
    -@@ -1557,7 +1569,7 @@
    -     <string name="package_updated_device_owner" msgid="8856631322440187071">"Actualizado por tu administrador"</string>
    -     <string name="package_deleted_device_owner" msgid="7650577387493101353">"Eliminado por tu administrador"</string>
    -     <string name="battery_saver_description" msgid="1960431123816253034">"Para ayudar a mejorar la duración de la batería, la función de ahorro de energía reduce el rendimiento del dispositivo y limita la vibración, los servicios de ubicación y la mayor parte de la transmisión de datos en segundo plano. Es posible que las aplicaciones que se sincronizan, como las de correo y mensajes, no se actualicen a menos que las abras.\n\nLa función de ahorro de energía se desactiva automáticamente cuando el dispositivo se está cargando."</string>
    --    <string name="data_saver_description" msgid="6015391409098303235">"El Economizador de Datos evita que algunas aplicaciones envíen o reciban datos en segundo plano, lo que permite reducir el uso de datos. Una aplicación activa podrá acceder a los datos, aunque con menos frecuencia. Esto significa que, por ejemplo, algunas imágenes no se muestren hasta que no las toques."</string>
    -+    <string name="data_saver_description" msgid="6015391409098303235">"El ahorro de datos evita que algunas aplicaciones envíen o reciban datos en segundo plano, lo que permite reducir el uso de datos. Una aplicación activa podrá acceder a los datos, aunque con menos frecuencia. Esto significa que, por ejemplo, algunas imágenes no se muestren hasta que no las toques."</string>
    -     <string name="data_saver_enable_title" msgid="4674073932722787417">"¿Activar ahorro de datos?"</string>
    -     <string name="data_saver_enable_button" msgid="7147735965247211818">"Activar"</string>
    -     <plurals name="zen_mode_duration_minutes_summary" formatted="false" msgid="4367877408072000848">
    -@@ -1636,6 +1648,7 @@
    -     <string name="search_language_hint" msgid="7042102592055108574">"Nombre de idioma"</string>
    -     <string name="language_picker_section_suggested" msgid="8414489646861640885">"Sugeridos"</string>
    -     <string name="language_picker_section_all" msgid="3097279199511617537">"Todos los idiomas"</string>
    -+    <string name="region_picker_section_all" msgid="8966316787153001779">"Todas las regiones"</string>
    -     <string name="locale_search_menu" msgid="2560710726687249178">"Buscar"</string>
    -     <string name="work_mode_off_title" msgid="8954725060677558855">"Modo de trabajo desactivado"</string>
    -     <string name="work_mode_off_message" msgid="3286169091278094476">"Permite que se utilice el perfil de trabajo, incluidas las aplicaciones, la sincronización en segundo plano y las funciones relacionadas."</string>
    -diff --git a/core/res/res/values-et-rEE/strings.xml b/core/res/res/values-et-rEE/strings.xml
    -index 8922379..9263b59 100644
    ---- a/core/res/res/values-et-rEE/strings.xml
    -+++ b/core/res/res/values-et-rEE/strings.xml
    -@@ -214,6 +214,7 @@
    -     <string name="global_actions" product="default" msgid="2406416831541615258">"Telefonivalikud"</string>
    -     <string name="global_action_lock" msgid="2844945191792119712">"Ekraanilukk"</string>
    -     <string name="global_action_power_off" msgid="4471879440839879722">"Lülita välja"</string>
    -+    <string name="global_action_emergency" msgid="7112311161137421166">"Hädaabi"</string>
    -     <string name="global_action_bug_report" msgid="7934010578922304799">"Veaaruanne"</string>
    -     <string name="bugreport_title" msgid="2667494803742548533">"Veaaruande võtmine"</string>
    -     <string name="bugreport_message" msgid="398447048750350456">"Nii kogutakse teavet teie seadme praeguse oleku kohta, et saata see meilisõnumina. Enne kui saate veaaruande ära saata, võtab selle loomine natuke aega; varuge kannatust."</string>
    -@@ -251,7 +252,7 @@
    -     <string name="permgrouplab_sms" msgid="228308803364967808">"SMS"</string>
    -     <string name="permgroupdesc_sms" msgid="4656988620100940350">"saata ja vaadata SMS-sõnumeid"</string>
    -     <string name="permgrouplab_storage" msgid="1971118770546336966">"Mäluruum"</string>
    --    <string name="permgroupdesc_storage" msgid="637758554581589203">"juurde pääseda seadmesse salvestatud fotodele, meediale ja failidele"</string>
    -+    <string name="permgroupdesc_storage" msgid="637758554581589203">"juurde pääseda seadmesse salvestatud fotodele, meediasisule ja failidele"</string>
    -     <string name="permgrouplab_microphone" msgid="171539900250043464">"Mikrofon"</string>
    -     <string name="permgroupdesc_microphone" msgid="4988812113943554584">"heli salvestamine"</string>
    -     <string name="permgrouplab_camera" msgid="4820372495894586615">"Kaamera"</string>
    -@@ -1076,6 +1077,17 @@
    -     <skip />
    -     <string name="wifi_no_internet" msgid="8451173622563841546">"WiFi-l pole juurdepääsu Internetile"</string>
    -     <string name="wifi_no_internet_detailed" msgid="8083079241212301741">"Puudutage valikute nägemiseks"</string>
    -+    <string name="network_switch_metered" msgid="4671730921726992671">"Lülitati võrgule <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
    -+    <string name="network_switch_metered_detail" msgid="5325661434777870353">"Seade kasutab võrku <xliff:g id="NEW_NETWORK">%1$s</xliff:g>, kui võrgul <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> puudub Interneti-ühendus. Rakenduda võivad tasud."</string>
    -+    <string name="network_switch_metered_toast" msgid="5779283181685974304">"Lülitati võrgult <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> võrgule <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
    -+  <string-array name="network_switch_type_name">
    -+    <item msgid="2952042958050315394">"mobiilne andmeside"</item>
    -+    <item msgid="75483255295529161">"WiFi"</item>
    -+    <item msgid="6862614801537202646">"Bluetooth"</item>
    -+    <item msgid="5447331121797802871">"Ethernet"</item>
    -+    <item msgid="8257233890381651999">"VPN"</item>
    -+  </string-array>
    -+    <string name="network_switch_type_name_unknown" msgid="4552612897806660656">"tundmatu võrgutüüp"</string>
    -     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Ei saanud WiFi-ga ühendust"</string>
    -     <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" on halb Interneti-ühendus."</string>
    -     <string name="wifi_connect_alert_title" msgid="8455846016001810172">"Kas lubada ühendus?"</string>
    -@@ -1153,7 +1165,6 @@
    -     <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"Puudutage keele ja paigutuse valimiseks"</string>
    -     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSŠZŽTUVWÕÄÖÜXY"</string>
    -     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSŠZŽTUVWÕÄÖÜXY"</string>
    --    <string name="candidates_style" msgid="4333913089637062257"><u>"kandidaadid"</u></string>
    -     <string name="ext_media_checking_notification_title" msgid="5734005953288045806">"Üksuse <xliff:g id="NAME">%s</xliff:g> ettevalmistamine"</string>
    -     <string name="ext_media_checking_notification_message" msgid="4747432538578886744">"Vigade kontrollimine"</string>
    -     <string name="ext_media_new_notification_message" msgid="7589986898808506239">"Tuvastati uus üksus <xliff:g id="NAME">%s</xliff:g>"</string>
    -@@ -1232,8 +1243,9 @@
    -     <string name="vpn_text_long" msgid="4907843483284977618">"Ühendatud seansiga <xliff:g id="SESSION">%s</xliff:g>. Koputage võrgu haldamiseks"</string>
    -     <string name="vpn_lockdown_connecting" msgid="6443438964440960745">"Ühendamine alati sees VPN-iga …"</string>
    -     <string name="vpn_lockdown_connected" msgid="8202679674819213931">"Ühendatud alati sees VPN-iga"</string>
    -+    <string name="vpn_lockdown_disconnected" msgid="4532298952570796327">"Alati sees VPN pole ühendatud"</string>
    -     <string name="vpn_lockdown_error" msgid="6009249814034708175">"Alati sees VPN-i viga"</string>
    --    <string name="vpn_lockdown_config" msgid="4655589351146766608">"Puudutage seadistamiseks"</string>
    -+    <string name="vpn_lockdown_config" msgid="5099330695245008680">"Puudutage seadistamiseks"</string>
    -     <string name="upload_file" msgid="2897957172366730416">"Valige fail"</string>
    -     <string name="no_file_chosen" msgid="6363648562170759465">"Ühtegi faili pole valitud"</string>
    -     <string name="reset" msgid="2448168080964209908">"Lähtesta"</string>
    -@@ -1317,7 +1329,7 @@
    -     <string name="storage_usb_drive_label" msgid="4501418548927759953">"Tootja <xliff:g id="MANUFACTURER">%s</xliff:g> USB-ketas"</string>
    -     <string name="storage_usb" msgid="3017954059538517278">"USB-mäluseade"</string>
    -     <string name="extract_edit_menu_button" msgid="8940478730496610137">"Muuda"</string>
    --    <string name="data_usage_warning_title" msgid="1955638862122232342">"Andmete kasutamise hoiatus"</string>
    -+    <string name="data_usage_warning_title" msgid="3620440638180218181">"Andmekasutuse hoiatus"</string>
    -     <string name="data_usage_warning_body" msgid="6660692274311972007">"Puudutage kasutuse/seadete vaat."</string>
    -     <string name="data_usage_3g_limit_title" msgid="4361523876818447683">"2G-, 3G-andmeside limiit on täis"</string>
    -     <string name="data_usage_4g_limit_title" msgid="4609566827219442376">"4G-andmeside limiit on täis"</string>
    -@@ -1636,6 +1648,7 @@
    -     <string name="search_language_hint" msgid="7042102592055108574">"Sisestage keele nimi"</string>
    -     <string name="language_picker_section_suggested" msgid="8414489646861640885">"Soovitatud"</string>
    -     <string name="language_picker_section_all" msgid="3097279199511617537">"Kõik keeled"</string>
    -+    <string name="region_picker_section_all" msgid="8966316787153001779">"Kõik piirkonnad"</string>
    -     <string name="locale_search_menu" msgid="2560710726687249178">"Otsing"</string>
    -     <string name="work_mode_off_title" msgid="8954725060677558855">"Töörežiim on VÄLJA LÜLITATUD"</string>
    -     <string name="work_mode_off_message" msgid="3286169091278094476">"Lubatakse tööprofiili toimingud, sh rakendused, taustal sünkroonimine ja seotud funktsioonid."</string>
    -diff --git a/core/res/res/values-eu-rES/strings.xml b/core/res/res/values-eu-rES/strings.xml
    -index 7dc0877..97628fc 100644
    ---- a/core/res/res/values-eu-rES/strings.xml
    -+++ b/core/res/res/values-eu-rES/strings.xml
    -@@ -214,6 +214,7 @@
    -     <string name="global_actions" product="default" msgid="2406416831541615258">"Telefonoaren aukerak"</string>
    -     <string name="global_action_lock" msgid="2844945191792119712">"Pantailaren blokeoa"</string>
    -     <string name="global_action_power_off" msgid="4471879440839879722">"Itzali"</string>
    -+    <string name="global_action_emergency" msgid="7112311161137421166">"Larrialdiak"</string>
    -     <string name="global_action_bug_report" msgid="7934010578922304799">"Akatsen txostena"</string>
    -     <string name="bugreport_title" msgid="2667494803742548533">"Sortu akatsen txostena"</string>
    -     <string name="bugreport_message" msgid="398447048750350456">"Gailuaren uneko egoerari buruzko informazioa bilduko da, mezu elektroniko gisa bidaltzeko. Minutu batzuk igaroko dira akatsen txostena sortzen hasten denetik bidaltzeko prest egon arte. Itxaron, mesedez."</string>
    -@@ -742,7 +743,7 @@
    -     <string name="keyguard_accessibility_user_selector" msgid="1226798370913698896">"Erabiltzaile-hautatzailea"</string>
    -     <string name="keyguard_accessibility_status" msgid="8008264603935930611">"Egoera"</string>
    -     <string name="keyguard_accessibility_camera" msgid="8904231194181114603">"Kamera"</string>
    --    <string name="keygaurd_accessibility_media_controls" msgid="262209654292161806">"Multimedia-kontrolak"</string>
    -+    <string name="keygaurd_accessibility_media_controls" msgid="262209654292161806">"Multimedia kontrolatzeko aukerak"</string>
    -     <string name="keyguard_accessibility_widget_reorder_start" msgid="8736853615588828197">"Widgetak berrantolatzen hasi da."</string>
    -     <string name="keyguard_accessibility_widget_reorder_end" msgid="7170190950870468320">"Widgetak berrantolatu dira."</string>
    -     <string name="keyguard_accessibility_widget_deleted" msgid="4426204263929224434">"<xliff:g id="WIDGET_INDEX">%1$s</xliff:g> widgeta ezabatu da."</string>
    -@@ -1074,8 +1075,19 @@
    -     <string name="network_available_sign_in" msgid="1848877297365446605">"Hasi saioa sarean"</string>
    -     <!-- no translation found for network_available_sign_in_detailed (8000081941447976118) -->
    -     <skip />
    --    <string name="wifi_no_internet" msgid="8451173622563841546">"Wi-Fi konexioa ezin da Internetera konektatu"</string>
    -+    <string name="wifi_no_internet" msgid="8451173622563841546">"Wi-Fi eginbidea ezin da Internetera konektatu"</string>
    -     <string name="wifi_no_internet_detailed" msgid="8083079241212301741">"Sakatu aukerak ikusteko"</string>
    -+    <string name="network_switch_metered" msgid="4671730921726992671">"<xliff:g id="NETWORK_TYPE">%1$s</xliff:g> erabiltzen ari zara orain"</string>
    -+    <string name="network_switch_metered_detail" msgid="5325661434777870353">"<xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> Internetera konektatzeko gauza ez denean, <xliff:g id="NEW_NETWORK">%1$s</xliff:g> erabiltzen du gailuak. Agian kostuak ordaindu beharko dituzu."</string>
    -+    <string name="network_switch_metered_toast" msgid="5779283181685974304">"<xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> erabiltzen ari zinen, baina <xliff:g id="NEW_NETWORK">%2$s</xliff:g> erabiltzen ari zara orain"</string>
    -+  <string-array name="network_switch_type_name">
    -+    <item msgid="2952042958050315394">"datu-konexioa"</item>
    -+    <item msgid="75483255295529161">"Wi-Fi"</item>
    -+    <item msgid="6862614801537202646">"Bluetooth"</item>
    -+    <item msgid="5447331121797802871">"Ethernet"</item>
    -+    <item msgid="8257233890381651999">"VPN"</item>
    -+  </string-array>
    -+    <string name="network_switch_type_name_unknown" msgid="4552612897806660656">"sare mota ezezaguna"</string>
    -     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Ezin izan da Wi-Fi sarera konektatu"</string>
    -     <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" Interneteko konexio txarra du."</string>
    -     <string name="wifi_connect_alert_title" msgid="8455846016001810172">"Konektatzea baimendu nahi diozu?"</string>
    -@@ -1153,7 +1165,6 @@
    -     <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"Hizkuntza eta diseinua hautatzeko, sakatu hau"</string>
    -     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
    -     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
    --    <string name="candidates_style" msgid="4333913089637062257"><u>"hautagaiak"</u></string>
    -     <string name="ext_media_checking_notification_title" msgid="5734005953288045806">"<xliff:g id="NAME">%s</xliff:g> prestatzen"</string>
    -     <string name="ext_media_checking_notification_message" msgid="4747432538578886744">"Errorerik dagoen egiaztatzen"</string>
    -     <string name="ext_media_new_notification_message" msgid="7589986898808506239">"<xliff:g id="NAME">%s</xliff:g> berria hauteman da"</string>
    -@@ -1232,8 +1243,9 @@
    -     <string name="vpn_text_long" msgid="4907843483284977618">"<xliff:g id="SESSION">%s</xliff:g> saiora konektatuta. Sakatu sarea kudeatzeko."</string>
    -     <string name="vpn_lockdown_connecting" msgid="6443438964440960745">"Beti aktibatuta dagoen VPNa konektatzen…"</string>
    -     <string name="vpn_lockdown_connected" msgid="8202679674819213931">"Beti aktibatuta dagoen VPNa konektatu da"</string>
    -+    <string name="vpn_lockdown_disconnected" msgid="4532298952570796327">"Deskonektatu egin da beti aktibatuta dagoen VPN konexioa"</string>
    -     <string name="vpn_lockdown_error" msgid="6009249814034708175">"Beti aktibatuta dagoen VPN errorea"</string>
    --    <string name="vpn_lockdown_config" msgid="4655589351146766608">"Sakatu konfiguratzeko"</string>
    -+    <string name="vpn_lockdown_config" msgid="5099330695245008680">"Konfiguratzeko, sakatu hau"</string>
    -     <string name="upload_file" msgid="2897957172366730416">"Aukeratu fitxategia"</string>
    -     <string name="no_file_chosen" msgid="6363648562170759465">"Ez da fitxategirik aukeratu"</string>
    -     <string name="reset" msgid="2448168080964209908">"Berrezarri"</string>
    -@@ -1317,7 +1329,7 @@
    -     <string name="storage_usb_drive_label" msgid="4501418548927759953">"<xliff:g id="MANUFACTURER">%s</xliff:g> USB unitatea"</string>
    -     <string name="storage_usb" msgid="3017954059538517278">"USB memoria"</string>
    -     <string name="extract_edit_menu_button" msgid="8940478730496610137">"Editatu"</string>
    --    <string name="data_usage_warning_title" msgid="1955638862122232342">"Datuen erabilerari buruzko abisua"</string>
    -+    <string name="data_usage_warning_title" msgid="3620440638180218181">"Datu-erabilerari buruzko abisua"</string>
    -     <string name="data_usage_warning_body" msgid="6660692274311972007">"Sakatu erabilera eta ezarpenak ikusteko."</string>
    -     <string name="data_usage_3g_limit_title" msgid="4361523876818447683">"2-3 GB-ko mugara iritsi zara"</string>
    -     <string name="data_usage_4g_limit_title" msgid="4609566827219442376">"4 GB-ko mugara iritsi zara"</string>
    -@@ -1636,6 +1648,7 @@
    -     <string name="search_language_hint" msgid="7042102592055108574">"Adierazi hizkuntza"</string>
    -     <string name="language_picker_section_suggested" msgid="8414489646861640885">"Iradokitakoak"</string>
    -     <string name="language_picker_section_all" msgid="3097279199511617537">"Hizkuntza guztiak"</string>
    -+    <string name="region_picker_section_all" msgid="8966316787153001779">"Lurralde guztiak"</string>
    -     <string name="locale_search_menu" msgid="2560710726687249178">"Bilaketa"</string>
    -     <string name="work_mode_off_title" msgid="8954725060677558855">"Desaktibatuta dago laneko modua"</string>
    -     <string name="work_mode_off_message" msgid="3286169091278094476">"Baimendu laneko profilak funtzionatzea, besteak beste, aplikazioak, atzeko planoko sinkronizazioa eta erlazionatutako eginbideak."</string>
    -diff --git a/core/res/res/values-fa/strings.xml b/core/res/res/values-fa/strings.xml
    -index 5976ad1..128a66f 100644
    ---- a/core/res/res/values-fa/strings.xml
    -+++ b/core/res/res/values-fa/strings.xml
    -@@ -214,6 +214,7 @@
    -     <string name="global_actions" product="default" msgid="2406416831541615258">"گزینه‌های تلفن"</string>
    -     <string name="global_action_lock" msgid="2844945191792119712">"قفل صفحه"</string>
    -     <string name="global_action_power_off" msgid="4471879440839879722">"خاموش کردن"</string>
    -+    <string name="global_action_emergency" msgid="7112311161137421166">"اضطراری"</string>
    -     <string name="global_action_bug_report" msgid="7934010578922304799">"گزارش اشکال"</string>
    -     <string name="bugreport_title" msgid="2667494803742548533">"گرفتن گزارش اشکال"</string>
    -     <string name="bugreport_message" msgid="398447048750350456">"این گزارش اطلاعات مربوط به وضعیت دستگاه کنونی شما را جمع‌آوری می‌کند تا به صورت یک پیام رایانامه ارسال شود. از زمان شروع گزارش اشکال تا آماده شدن برای ارسال اندکی زمان می‌برد؛ لطفاً شکیبا باشید."</string>
    -@@ -924,9 +925,9 @@
    -       <item quantity="one">در <xliff:g id="COUNT_1">%d</xliff:g> سال</item>
    -       <item quantity="other">در <xliff:g id="COUNT_1">%d</xliff:g> سال</item>
    -     </plurals>
    --    <string name="VideoView_error_title" msgid="3534509135438353077">"مشکل در ویدیو"</string>
    --    <string name="VideoView_error_text_invalid_progressive_playback" msgid="3186670335938670444">"متأسفیم، این ویدیو برای پخش جریانی با این دستگاه معتبر نیست."</string>
    --    <string name="VideoView_error_text_unknown" msgid="3450439155187810085">"پخش این ویدیو ممکن نیست."</string>
    -+    <string name="VideoView_error_title" msgid="3534509135438353077">"مشکل در ویدئو"</string>
    -+    <string name="VideoView_error_text_invalid_progressive_playback" msgid="3186670335938670444">"متأسفیم، این ویدئو برای پخش جریانی با این دستگاه معتبر نیست."</string>
    -+    <string name="VideoView_error_text_unknown" msgid="3450439155187810085">"پخش این ویدئو ممکن نیست."</string>
    -     <string name="VideoView_error_button" msgid="2822238215100679592">"تأیید"</string>
    -     <string name="relative_time" msgid="1818557177829411417">"<xliff:g id="DATE">%1$s</xliff:g>، <xliff:g id="TIME">%2$s</xliff:g>"</string>
    -     <string name="noon" msgid="7245353528818587908">"ظهر"</string>
    -@@ -1076,6 +1077,17 @@
    -     <skip />
    -     <string name="wifi_no_internet" msgid="8451173622563841546">"‏Wi-Fi به اینترنت دسترسی ندارد"</string>
    -     <string name="wifi_no_internet_detailed" msgid="8083079241212301741">"برای گزینه‌ها ضربه بزنید"</string>
    -+    <string name="network_switch_metered" msgid="4671730921726992671">"به <xliff:g id="NETWORK_TYPE">%1$s</xliff:g> تغییر کرد"</string>
    -+    <string name="network_switch_metered_detail" msgid="5325661434777870353">"وقتی <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> دسترسی به اینترنت نداشته باشد، دستگاه از <xliff:g id="NEW_NETWORK">%1$s</xliff:g> استفاده می‌کند. ممکن است هزینه‌هایی اعمال شود."</string>
    -+    <string name="network_switch_metered_toast" msgid="5779283181685974304">"از <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> به <xliff:g id="NEW_NETWORK">%2$s</xliff:g> تغییر کرد"</string>
    -+  <string-array name="network_switch_type_name">
    -+    <item msgid="2952042958050315394">"داده شبکه تلفن همراه"</item>
    -+    <item msgid="75483255295529161">"Wi-Fi"</item>
    -+    <item msgid="6862614801537202646">"بلوتوث"</item>
    -+    <item msgid="5447331121797802871">"اترنت"</item>
    -+    <item msgid="8257233890381651999">"VPN"</item>
    -+  </string-array>
    -+    <string name="network_switch_type_name_unknown" msgid="4552612897806660656">"نوع شبکه نامشخص"</string>
    -     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"‏اتصال به Wi-Fi ممکن نیست"</string>
    -     <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" اتصال اینترنتی ضعیفی دارد."</string>
    -     <string name="wifi_connect_alert_title" msgid="8455846016001810172">"اتصال مجاز است؟"</string>
    -@@ -1153,7 +1165,6 @@
    -     <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"برای انتخاب زبان و چیدمان ضربه بزنید"</string>
    -     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
    -     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
    --    <string name="candidates_style" msgid="4333913089637062257"><u>"داوطلبین"</u></string>
    -     <string name="ext_media_checking_notification_title" msgid="5734005953288045806">"در حال آماده‌سازی <xliff:g id="NAME">%s</xliff:g>"</string>
    -     <string name="ext_media_checking_notification_message" msgid="4747432538578886744">"در حال بررسی برای خطاها"</string>
    -     <string name="ext_media_new_notification_message" msgid="7589986898808506239">"<xliff:g id="NAME">%s</xliff:g> جدید شناسایی شد"</string>
    -@@ -1232,8 +1243,9 @@
    -     <string name="vpn_text_long" msgid="4907843483284977618">"به <xliff:g id="SESSION">%s</xliff:g> متصل شد. برای مدیریت شبکه ضربه بزنید."</string>
    -     <string name="vpn_lockdown_connecting" msgid="6443438964440960745">"‏در حال اتصال VPN همیشه فعال…"</string>
    -     <string name="vpn_lockdown_connected" msgid="8202679674819213931">"‏VPN همیشه فعال متصل شد"</string>
    -+    <string name="vpn_lockdown_disconnected" msgid="4532298952570796327">"‏ارتباط VPN همیشه روشن قطع شد"</string>
    -     <string name="vpn_lockdown_error" msgid="6009249814034708175">"‏خطای VPN همیشه فعال"</string>
    --    <string name="vpn_lockdown_config" msgid="4655589351146766608">"جهت پیکربندی ضربه بزنید"</string>
    -+    <string name="vpn_lockdown_config" msgid="5099330695245008680">"برای راه‌اندازی ضربه بزنید"</string>
    -     <string name="upload_file" msgid="2897957172366730416">"انتخاب فایل"</string>
    -     <string name="no_file_chosen" msgid="6363648562170759465">"هیچ فایلی انتخاب نشد"</string>
    -     <string name="reset" msgid="2448168080964209908">"بازنشانی"</string>
    -@@ -1317,7 +1329,7 @@
    -     <string name="storage_usb_drive_label" msgid="4501418548927759953">"‏درایو USB ‏<xliff:g id="MANUFACTURER">%s</xliff:g>"</string>
    -     <string name="storage_usb" msgid="3017954059538517278">"‏حافظهٔ USB"</string>
    -     <string name="extract_edit_menu_button" msgid="8940478730496610137">"ویرایش"</string>
    --    <string name="data_usage_warning_title" msgid="1955638862122232342">"هشدار میزان استفاده از داده"</string>
    -+    <string name="data_usage_warning_title" msgid="3620440638180218181">"هشدار مصرف داده"</string>
    -     <string name="data_usage_warning_body" msgid="6660692274311972007">"برای مشاهده مصرف و تنظیمات ضربه بزنید."</string>
    -     <string name="data_usage_3g_limit_title" msgid="4361523876818447683">"‏به حد مجاز مصرف داده 2G-3G رسید"</string>
    -     <string name="data_usage_4g_limit_title" msgid="4609566827219442376">"‏به حد مجاز مصرف داده 4G رسید"</string>
    -@@ -1512,8 +1524,8 @@
    -     <string name="mediasize_japanese_kahu" msgid="6872696027560065173">"Kahu"</string>
    -     <string name="mediasize_japanese_kaku2" msgid="2359077233775455405">"Kaku2"</string>
    -     <string name="mediasize_japanese_you4" msgid="2091777168747058008">"You4"</string>
    --    <string name="mediasize_unknown_portrait" msgid="3088043641616409762">"عمودی ناشناس"</string>
    --    <string name="mediasize_unknown_landscape" msgid="4876995327029361552">"افقی ناشناس"</string>
    -+    <string name="mediasize_unknown_portrait" msgid="3088043641616409762">"عمودی نامشخص"</string>
    -+    <string name="mediasize_unknown_landscape" msgid="4876995327029361552">"افقی نامشخص"</string>
    -     <string name="write_fail_reason_cancelled" msgid="7091258378121627624">"لغو شد"</string>
    -     <string name="write_fail_reason_cannot_write" msgid="8132505417935337724">"خطا هنگام نوشتن محتوا"</string>
    -     <string name="reason_unknown" msgid="6048913880184628119">"نامعلوم"</string>
    -@@ -1636,6 +1648,7 @@
    -     <string name="search_language_hint" msgid="7042102592055108574">"نام زبان را تایپ کنید"</string>
    -     <string name="language_picker_section_suggested" msgid="8414489646861640885">"پیشنهادشده"</string>
    -     <string name="language_picker_section_all" msgid="3097279199511617537">"همه زبان‌ها"</string>
    -+    <string name="region_picker_section_all" msgid="8966316787153001779">"همه منطقه‌ها"</string>
    -     <string name="locale_search_menu" msgid="2560710726687249178">"جستجو"</string>
    -     <string name="work_mode_off_title" msgid="8954725060677558855">"حالت کاری خاموش است"</string>
    -     <string name="work_mode_off_message" msgid="3286169091278094476">"به نمایه کاری اجازه فعالیت ( شامل استفاده از برنامه‌ها، همگام‌سازی در پس‌زمینه و قابلیت‌های مرتبط) داده شود."</string>
    -diff --git a/core/res/res/values-fi/strings.xml b/core/res/res/values-fi/strings.xml
    -index b221750..c4c223b 100644
    ---- a/core/res/res/values-fi/strings.xml
    -+++ b/core/res/res/values-fi/strings.xml
    -@@ -214,6 +214,7 @@
    -     <string name="global_actions" product="default" msgid="2406416831541615258">"Puhelimen asetukset"</string>
    -     <string name="global_action_lock" msgid="2844945191792119712">"Näytön lukitus"</string>
    -     <string name="global_action_power_off" msgid="4471879440839879722">"Katkaise virta"</string>
    -+    <string name="global_action_emergency" msgid="7112311161137421166">"Hätäpuhelu"</string>
    -     <string name="global_action_bug_report" msgid="7934010578922304799">"Virheraportti"</string>
    -     <string name="bugreport_title" msgid="2667494803742548533">"Luo virheraportti"</string>
    -     <string name="bugreport_message" msgid="398447048750350456">"Toiminto kerää tietoja laitteen tilasta ja lähettää ne sähköpostitse. Virheraportti on valmis lähetettäväksi hetken kuluttua - kiitos kärsivällisyydestäsi."</string>
    -@@ -1076,6 +1077,17 @@
    -     <skip />
    -     <string name="wifi_no_internet" msgid="8451173622563841546">"Wi-Fi ei ole yhteydessä internetiin."</string>
    -     <string name="wifi_no_internet_detailed" msgid="8083079241212301741">"Näytä vaihtoehdot napauttamalla."</string>
    -+    <string name="network_switch_metered" msgid="4671730921726992671">"<xliff:g id="NETWORK_TYPE">%1$s</xliff:g> otettiin käyttöön"</string>
    -+    <string name="network_switch_metered_detail" msgid="5325661434777870353">"<xliff:g id="NEW_NETWORK">%1$s</xliff:g> otetaan käyttöön, kun <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> ei voi muodostaa yhteyttä internetiin. Veloitukset ovat mahdollisia."</string>
    -+    <string name="network_switch_metered_toast" msgid="5779283181685974304">"<xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> poistettiin käytöstä ja <xliff:g id="NEW_NETWORK">%2$s</xliff:g> otettiin käyttöön."</string>
    -+  <string-array name="network_switch_type_name">
    -+    <item msgid="2952042958050315394">"mobiilidata"</item>
    -+    <item msgid="75483255295529161">"Wi-Fi"</item>
    -+    <item msgid="6862614801537202646">"Bluetooth"</item>
    -+    <item msgid="5447331121797802871">"Ethernet"</item>
    -+    <item msgid="8257233890381651999">"VPN"</item>
    -+  </string-array>
    -+    <string name="network_switch_type_name_unknown" msgid="4552612897806660656">"tuntematon verkon tyyppi"</string>
    -     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Wi-Fi-yhteyden muodostaminen epäonnistui"</string>
    -     <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" : huono internetyhteys."</string>
    -     <string name="wifi_connect_alert_title" msgid="8455846016001810172">"Sallitaanko yhteys?"</string>
    -@@ -1153,7 +1165,6 @@
    -     <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"Valitse kieli ja asettelu koskettamalla."</string>
    -     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZÅÄÖ"</string>
    -     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
    --    <string name="candidates_style" msgid="4333913089637062257"><u>"kandidaatit"</u></string>
    -     <string name="ext_media_checking_notification_title" msgid="5734005953288045806">"Valmistellaan kohdetta <xliff:g id="NAME">%s</xliff:g>"</string>
    -     <string name="ext_media_checking_notification_message" msgid="4747432538578886744">"Tarkistetaan virheiden varalta."</string>
    -     <string name="ext_media_new_notification_message" msgid="7589986898808506239">"Uusi <xliff:g id="NAME">%s</xliff:g> on havaittu."</string>
    -@@ -1232,8 +1243,9 @@
    -     <string name="vpn_text_long" msgid="4907843483284977618">"Yhdistetty: <xliff:g id="SESSION">%s</xliff:g>. Hallinnoi verkkoa napauttamalla."</string>
    -     <string name="vpn_lockdown_connecting" msgid="6443438964440960745">"Yhdistetään aina käytössä olevaan VPN-verkkoon..."</string>
    -     <string name="vpn_lockdown_connected" msgid="8202679674819213931">"Yhdistetty aina käytössä olevaan VPN-verkkoon"</string>
    -+    <string name="vpn_lockdown_disconnected" msgid="4532298952570796327">"Aina käytössä olevan VPN:n yhteys on katkaistu"</string>
    -     <string name="vpn_lockdown_error" msgid="6009249814034708175">"Aina käytössä oleva VPN: virhe"</string>
    --    <string name="vpn_lockdown_config" msgid="4655589351146766608">"Määritä napauttamalla."</string>
    -+    <string name="vpn_lockdown_config" msgid="5099330695245008680">"Määritä koskettamalla."</string>
    -     <string name="upload_file" msgid="2897957172366730416">"Valitse tiedosto"</string>
    -     <string name="no_file_chosen" msgid="6363648562170759465">"Ei valittua tiedostoa"</string>
    -     <string name="reset" msgid="2448168080964209908">"Palauta"</string>
    -@@ -1317,7 +1329,7 @@
    -     <string name="storage_usb_drive_label" msgid="4501418548927759953">"USB-asema: <xliff:g id="MANUFACTURER">%s</xliff:g>"</string>
    -     <string name="storage_usb" msgid="3017954059538517278">"USB-tallennustila"</string>
    -     <string name="extract_edit_menu_button" msgid="8940478730496610137">"Muokkaa"</string>
    --    <string name="data_usage_warning_title" msgid="1955638862122232342">"Tiedonsiirtovaroitus"</string>
    -+    <string name="data_usage_warning_title" msgid="3620440638180218181">"Datankäyttövaroitus"</string>
    -     <string name="data_usage_warning_body" msgid="6660692274311972007">"Käyttö &amp; asetukset napauttamalla"</string>
    -     <string name="data_usage_3g_limit_title" msgid="4361523876818447683">"2G-3G-tietojen raja saavutettu"</string>
    -     <string name="data_usage_4g_limit_title" msgid="4609566827219442376">"4G-tietojen raja saavutettu"</string>
    -@@ -1636,6 +1648,7 @@
    -     <string name="search_language_hint" msgid="7042102592055108574">"Anna kielen nimi"</string>
    -     <string name="language_picker_section_suggested" msgid="8414489646861640885">"Ehdotukset"</string>
    -     <string name="language_picker_section_all" msgid="3097279199511617537">"Kaikki kielet"</string>
    -+    <string name="region_picker_section_all" msgid="8966316787153001779">"Kaikki alueet"</string>
    -     <string name="locale_search_menu" msgid="2560710726687249178">"Haku"</string>
    -     <string name="work_mode_off_title" msgid="8954725060677558855">"Työtila on pois käytöstä"</string>
    -     <string name="work_mode_off_message" msgid="3286169091278094476">"Sallii työprofiiliin toiminnan, esimerkiksi sovellukset ja taustasynkronoinnin."</string>
    -diff --git a/core/res/res/values-fr-rCA/strings.xml b/core/res/res/values-fr-rCA/strings.xml
    -index d9fbceb..e52eeda 100644
    ---- a/core/res/res/values-fr-rCA/strings.xml
    -+++ b/core/res/res/values-fr-rCA/strings.xml
    -@@ -214,6 +214,7 @@
    -     <string name="global_actions" product="default" msgid="2406416831541615258">"Options du téléphone"</string>
    -     <string name="global_action_lock" msgid="2844945191792119712">"Verrouillage de l\'écran"</string>
    -     <string name="global_action_power_off" msgid="4471879440839879722">"Éteindre"</string>
    -+    <string name="global_action_emergency" msgid="7112311161137421166">"Urgence"</string>
    -     <string name="global_action_bug_report" msgid="7934010578922304799">"Rapport de bogue"</string>
    -     <string name="bugreport_title" msgid="2667494803742548533">"Créer un rapport de bogue"</string>
    -     <string name="bugreport_message" msgid="398447048750350456">"Cela permet de recueillir des informations concernant l\'état actuel de votre appareil. Ces informations sont ensuite envoyées sous forme de courriel. Merci de patienter pendant la préparation du rapport de bogue. Cette opération peut prendre quelques instants."</string>
    -@@ -1076,6 +1077,17 @@
    -     <skip />
    -     <string name="wifi_no_internet" msgid="8451173622563841546">"Le réseau Wi-Fi ne dispose d\'aucun accès à Internet"</string>
    -     <string name="wifi_no_internet_detailed" msgid="8083079241212301741">"Touchez pour afficher les options"</string>
    -+    <string name="network_switch_metered" msgid="4671730921726992671">"Passé au réseau <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
    -+    <string name="network_switch_metered_detail" msgid="5325661434777870353">"L\'appareil utilise <xliff:g id="NEW_NETWORK">%1$s</xliff:g> quand <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> n\'a pas d\'accès à Internet. Des frais peuvent s\'appliquer."</string>
    -+    <string name="network_switch_metered_toast" msgid="5779283181685974304">"Passé du réseau <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> au <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
    -+  <string-array name="network_switch_type_name">
    -+    <item msgid="2952042958050315394">"données cellulaires"</item>
    -+    <item msgid="75483255295529161">"Wi-Fi"</item>
    -+    <item msgid="6862614801537202646">"Bluetooth"</item>
    -+    <item msgid="5447331121797802871">"Ethernet"</item>
    -+    <item msgid="8257233890381651999">"RPV"</item>
    -+  </string-array>
    -+    <string name="network_switch_type_name_unknown" msgid="4552612897806660656">"un type de réseau inconnu"</string>
    -     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Impossible de se connecter au Wi-Fi."</string>
    -     <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" dispose d\'une mauvaise connexion Internet."</string>
    -     <string name="wifi_connect_alert_title" msgid="8455846016001810172">"Autoriser la connexion?"</string>
    -@@ -1153,7 +1165,6 @@
    -     <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"Touchez pour sélectionner la langue et la configuration du clavier"</string>
    -     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
    -     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
    --    <string name="candidates_style" msgid="4333913089637062257"><u>"candidats"</u></string>
    -     <string name="ext_media_checking_notification_title" msgid="5734005953288045806">"Préparation de « <xliff:g id="NAME">%s</xliff:g> » en cours"</string>
    -     <string name="ext_media_checking_notification_message" msgid="4747432538578886744">"Recherche d\'erreurs en cours..."</string>
    -     <string name="ext_media_new_notification_message" msgid="7589986898808506239">"Une nouvelle mémoire « <xliff:g id="NAME">%s</xliff:g> » a été détectée"</string>
    -@@ -1232,8 +1243,9 @@
    -     <string name="vpn_text_long" msgid="4907843483284977618">"Connecté à <xliff:g id="SESSION">%s</xliff:g>. Appuyez ici pour gérer le réseau."</string>
    -     <string name="vpn_lockdown_connecting" msgid="6443438964440960745">"VPN permanent en cours de connexion…"</string>
    -     <string name="vpn_lockdown_connected" msgid="8202679674819213931">"VPN permanent connecté"</string>
    -+    <string name="vpn_lockdown_disconnected" msgid="4532298952570796327">"RPV permanent déconnecté"</string>
    -     <string name="vpn_lockdown_error" msgid="6009249814034708175">"Erreur du VPN permanent"</string>
    --    <string name="vpn_lockdown_config" msgid="4655589351146766608">"Touchez pour configurer"</string>
    -+    <string name="vpn_lockdown_config" msgid="5099330695245008680">"Touchez pour configurer"</string>
    -     <string name="upload_file" msgid="2897957172366730416">"Choisir un fichier"</string>
    -     <string name="no_file_chosen" msgid="6363648562170759465">"Aucun fichier sélectionné"</string>
    -     <string name="reset" msgid="2448168080964209908">"Réinitialiser"</string>
    -@@ -1317,7 +1329,7 @@
    -     <string name="storage_usb_drive_label" msgid="4501418548927759953">"Clé USB <xliff:g id="MANUFACTURER">%s</xliff:g>"</string>
    -     <string name="storage_usb" msgid="3017954059538517278">"Mémoire de stockage USB"</string>
    -     <string name="extract_edit_menu_button" msgid="8940478730496610137">"Modifier"</string>
    --    <string name="data_usage_warning_title" msgid="1955638862122232342">"Avertissement utilisation données"</string>
    -+    <string name="data_usage_warning_title" msgid="3620440638180218181">"Alerte d\'utilisation des données"</string>
    -     <string name="data_usage_warning_body" msgid="6660692274311972007">"Touch. pour aff. util. et param."</string>
    -     <string name="data_usage_3g_limit_title" msgid="4361523876818447683">"Limite de données 2G-3G atteinte"</string>
    -     <string name="data_usage_4g_limit_title" msgid="4609566827219442376">"Limite de données 4G atteinte"</string>
    -@@ -1636,6 +1648,7 @@
    -     <string name="search_language_hint" msgid="7042102592055108574">"Entrez la langue"</string>
    -     <string name="language_picker_section_suggested" msgid="8414489646861640885">"Suggestions"</string>
    -     <string name="language_picker_section_all" msgid="3097279199511617537">"Toutes les langues"</string>
    -+    <string name="region_picker_section_all" msgid="8966316787153001779">"Toutes les régions"</string>
    -     <string name="locale_search_menu" msgid="2560710726687249178">"Rechercher"</string>
    -     <string name="work_mode_off_title" msgid="8954725060677558855">"Le mode Travail est désactivé"</string>
    -     <string name="work_mode_off_message" msgid="3286169091278094476">"Autoriser le fonctionnement du profil professionnel, y compris les applications, la synchronisation en arrière-plan et les fonctionnalités associées."</string>
    -diff --git a/core/res/res/values-fr/strings.xml b/core/res/res/values-fr/strings.xml
    -index 6600f09..9da228e 100644
    ---- a/core/res/res/values-fr/strings.xml
    -+++ b/core/res/res/values-fr/strings.xml
    -@@ -214,6 +214,7 @@
    -     <string name="global_actions" product="default" msgid="2406416831541615258">"Options du téléphone"</string>
    -     <string name="global_action_lock" msgid="2844945191792119712">"Verrouillage de l\'écran"</string>
    -     <string name="global_action_power_off" msgid="4471879440839879722">"Éteindre"</string>
    -+    <string name="global_action_emergency" msgid="7112311161137421166">"Urgences"</string>
    -     <string name="global_action_bug_report" msgid="7934010578922304799">"Rapport de bug"</string>
    -     <string name="bugreport_title" msgid="2667494803742548533">"Créer un rapport de bug"</string>
    -     <string name="bugreport_message" msgid="398447048750350456">"Cela permet de recueillir des informations concernant l\'état actuel de votre appareil. Ces informations sont ensuite envoyées sous forme d\'e-mail. Merci de patienter pendant la préparation du rapport de bug. Cette opération peut prendre quelques instants."</string>
    -@@ -993,7 +994,7 @@
    -     <string name="noApplications" msgid="2991814273936504689">"Aucune application ne peut effectuer cette action."</string>
    -     <string name="aerr_application" msgid="250320989337856518">"<xliff:g id="APPLICATION">%1$s</xliff:g> a cessé de fonctionner."</string>
    -     <string name="aerr_process" msgid="6201597323218674729">"Le processus <xliff:g id="PROCESS">%1$s</xliff:g> a cessé de fonctionner."</string>
    --    <string name="aerr_application_repeated" msgid="3146328699537439573">"<xliff:g id="APPLICATION">%1$s</xliff:g> ne cesse de s\'arrêter."</string>
    -+    <string name="aerr_application_repeated" msgid="3146328699537439573">"<xliff:g id="APPLICATION">%1$s</xliff:g> s\'arrête systématiquement"</string>
    -     <string name="aerr_process_repeated" msgid="6235302956890402259">"Le processus \"<xliff:g id="PROCESS">%1$s</xliff:g>\" ne cesse de s\'arrêter."</string>
    -     <string name="aerr_restart" msgid="7581308074153624475">"Rouvrir l\'application"</string>
    -     <string name="aerr_report" msgid="5371800241488400617">"Envoyer des commentaires"</string>
    -@@ -1076,6 +1077,17 @@
    -     <skip />
    -     <string name="wifi_no_internet" msgid="8451173622563841546">"Le réseau Wi-Fi ne dispose d\'aucun accès à Internet."</string>
    -     <string name="wifi_no_internet_detailed" msgid="8083079241212301741">"Appuyez ici pour afficher des options."</string>
    -+    <string name="network_switch_metered" msgid="4671730921726992671">"Nouveau réseau : <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
    -+    <string name="network_switch_metered_detail" msgid="5325661434777870353">"L\'appareil utilise <xliff:g id="NEW_NETWORK">%1$s</xliff:g> lorsque <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> n\'a pas de connexion Internet. Des frais supplémentaires peuvent s\'appliquer."</string>
    -+    <string name="network_switch_metered_toast" msgid="5779283181685974304">"Ancien réseau : <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g>. Nouveau réseau : <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
    -+  <string-array name="network_switch_type_name">
    -+    <item msgid="2952042958050315394">"données mobiles"</item>
    -+    <item msgid="75483255295529161">"Wi-Fi"</item>
    -+    <item msgid="6862614801537202646">"Bluetooth"</item>
    -+    <item msgid="5447331121797802871">"Ethernet"</item>
    -+    <item msgid="8257233890381651999">"VPN"</item>
    -+  </string-array>
    -+    <string name="network_switch_type_name_unknown" msgid="4552612897806660656">"type de réseau inconnu"</string>
    -     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Impossible de se connecter au Wi-Fi."</string>
    -     <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" dispose d\'une mauvaise connexion Internet."</string>
    -     <string name="wifi_connect_alert_title" msgid="8455846016001810172">"Autoriser la connexion ?"</string>
    -@@ -1153,7 +1165,6 @@
    -     <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"Appuyer pour sélectionner la langue et la disposition"</string>
    -     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
    -     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
    --    <string name="candidates_style" msgid="4333913089637062257"><u>"candidats"</u></string>
    -     <string name="ext_media_checking_notification_title" msgid="5734005953288045806">"Préparation mémoire \"<xliff:g id="NAME">%s</xliff:g>\" en cours"</string>
    -     <string name="ext_media_checking_notification_message" msgid="4747432538578886744">"Recherche d\'erreurs"</string>
    -     <string name="ext_media_new_notification_message" msgid="7589986898808506239">"Une nouvelle mémoire de stockage \"<xliff:g id="NAME">%s</xliff:g>\" a été détectée."</string>
    -@@ -1232,8 +1243,9 @@
    -     <string name="vpn_text_long" msgid="4907843483284977618">"Connecté à <xliff:g id="SESSION">%s</xliff:g>. Appuyez ici pour gérer le réseau."</string>
    -     <string name="vpn_lockdown_connecting" msgid="6443438964440960745">"VPN permanent en cours de connexion…"</string>
    -     <string name="vpn_lockdown_connected" msgid="8202679674819213931">"VPN permanent connecté"</string>
    -+    <string name="vpn_lockdown_disconnected" msgid="4532298952570796327">"VPN permanent déconnecté"</string>
    -     <string name="vpn_lockdown_error" msgid="6009249814034708175">"Erreur du VPN permanent"</string>
    --    <string name="vpn_lockdown_config" msgid="4655589351146766608">"Appuyez ici pour configurer."</string>
    -+    <string name="vpn_lockdown_config" msgid="5099330695245008680">"Appuyer pour configurer"</string>
    -     <string name="upload_file" msgid="2897957172366730416">"Sélectionner un fichier"</string>
    -     <string name="no_file_chosen" msgid="6363648562170759465">"Aucun fichier sélectionné"</string>
    -     <string name="reset" msgid="2448168080964209908">"Réinitialiser"</string>
    -@@ -1317,7 +1329,7 @@
    -     <string name="storage_usb_drive_label" msgid="4501418548927759953">"Clé USB <xliff:g id="MANUFACTURER">%s</xliff:g>"</string>
    -     <string name="storage_usb" msgid="3017954059538517278">"Mémoire de stockage USB"</string>
    -     <string name="extract_edit_menu_button" msgid="8940478730496610137">"Modifier"</string>
    --    <string name="data_usage_warning_title" msgid="1955638862122232342">"Avertissement utilisation données"</string>
    -+    <string name="data_usage_warning_title" msgid="3620440638180218181">"Alerte de consommation des données"</string>
    -     <string name="data_usage_warning_body" msgid="6660692274311972007">"Appuyez pour conso/paramètres."</string>
    -     <string name="data_usage_3g_limit_title" msgid="4361523876818447683">"Limite de données 2G-3G atteinte"</string>
    -     <string name="data_usage_4g_limit_title" msgid="4609566827219442376">"Limite de données 4G atteinte"</string>
    -@@ -1558,7 +1570,7 @@
    -     <string name="package_deleted_device_owner" msgid="7650577387493101353">"Supprimé par votre administrateur"</string>
    -     <string name="battery_saver_description" msgid="1960431123816253034">"Pour améliorer l\'autonomie de la batterie, l\'économiseur de batterie réduit les performances et désactive le vibreur, les services de localisation et la plupart des données en arrière-plan. Les messageries électroniques ou autres applications utilisant la synchronisation pourraient ne pas se mettre à jour, sauf si vous les ouvrez.\n\nL\'économiseur de batterie s\'éteint automatiquement lorsque l\'appareil est en charge."</string>
    -     <string name="data_saver_description" msgid="6015391409098303235">"Pour réduire la consommation des données, l\'économiseur de données empêche certaines applications d\'envoyer ou de recevoir des données en arrière-plan. Ainsi, une application que vous utilisez actuellement peut accéder à des données, mais moins souvent. Par exemple, il se peut que les images ne s\'affichent pas tant que vous n\'appuyez pas dessus."</string>
    --    <string name="data_saver_enable_title" msgid="4674073932722787417">"Activer sauvegarde données ?"</string>
    -+    <string name="data_saver_enable_title" msgid="4674073932722787417">"Activer l\'économiseur de données ?"</string>
    -     <string name="data_saver_enable_button" msgid="7147735965247211818">"Activer"</string>
    -     <plurals name="zen_mode_duration_minutes_summary" formatted="false" msgid="4367877408072000848">
    -       <item quantity="one">Pendant %1$d minute (jusqu\'à <xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g>)</item>
    -@@ -1636,6 +1648,7 @@
    -     <string name="search_language_hint" msgid="7042102592055108574">"Saisissez la langue"</string>
    -     <string name="language_picker_section_suggested" msgid="8414489646861640885">"Recommandations"</string>
    -     <string name="language_picker_section_all" msgid="3097279199511617537">"Toutes les langues"</string>
    -+    <string name="region_picker_section_all" msgid="8966316787153001779">"Toutes les régions"</string>
    -     <string name="locale_search_menu" msgid="2560710726687249178">"Rechercher"</string>
    -     <string name="work_mode_off_title" msgid="8954725060677558855">"Mode professionnel DÉSACTIVÉ"</string>
    -     <string name="work_mode_off_message" msgid="3286169091278094476">"Autoriser le fonctionnement du profil professionnel, y compris les applications, la synchronisation en arrière-plan et les fonctionnalités associées."</string>
    -diff --git a/core/res/res/values-gl-rES/strings.xml b/core/res/res/values-gl-rES/strings.xml
    -index 8023edf..72757a6 100644
    ---- a/core/res/res/values-gl-rES/strings.xml
    -+++ b/core/res/res/values-gl-rES/strings.xml
    -@@ -214,6 +214,7 @@
    -     <string name="global_actions" product="default" msgid="2406416831541615258">"Opcións de teléfono"</string>
    -     <string name="global_action_lock" msgid="2844945191792119712">"Bloqueo da pantalla"</string>
    -     <string name="global_action_power_off" msgid="4471879440839879722">"Apagar"</string>
    -+    <string name="global_action_emergency" msgid="7112311161137421166">"Emerxencias"</string>
    -     <string name="global_action_bug_report" msgid="7934010578922304799">"Informe de erros"</string>
    -     <string name="bugreport_title" msgid="2667494803742548533">"Crear informe de erros"</string>
    -     <string name="bugreport_message" msgid="398447048750350456">"Este informe recompilará información acerca do estado actual do teu dispositivo para enviala en forma de mensaxe de correo electrónico. O informe de erros tardará un pouco en completarse desde o seu inicio ata que estea preparado para enviarse, polo que che recomendamos que teñas paciencia."</string>
    -@@ -598,7 +599,7 @@
    -     <string name="phoneTypeCallback" msgid="2712175203065678206">"Devolver chamada"</string>
    -     <string name="phoneTypeCar" msgid="8738360689616716982">"Coche"</string>
    -     <string name="phoneTypeCompanyMain" msgid="540434356461478916">"Empresa (ppal.)"</string>
    --    <string name="phoneTypeIsdn" msgid="8022453193171370337">"ISDN"</string>
    -+    <string name="phoneTypeIsdn" msgid="8022453193171370337">"RDSI"</string>
    -     <string name="phoneTypeMain" msgid="6766137010628326916">"Principal"</string>
    -     <string name="phoneTypeOtherFax" msgid="8587657145072446565">"Outro fax"</string>
    -     <string name="phoneTypeRadio" msgid="4093738079908667513">"Radio"</string>
    -@@ -1076,6 +1077,17 @@
    -     <skip />
    -     <string name="wifi_no_internet" msgid="8451173622563841546">"A wifi non ten acceso a Internet"</string>
    -     <string name="wifi_no_internet_detailed" msgid="8083079241212301741">"Toca para ver opcións."</string>
    -+    <string name="network_switch_metered" msgid="4671730921726992671">"Cambiouse a: <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
    -+    <string name="network_switch_metered_detail" msgid="5325661434777870353">"O dispositivo utiliza <xliff:g id="NEW_NETWORK">%1$s</xliff:g> cando <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> non ten acceso a Internet. Pódense aplicar cargos."</string>
    -+    <string name="network_switch_metered_toast" msgid="5779283181685974304">"Cambiouse de <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> a <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
    -+  <string-array name="network_switch_type_name">
    -+    <item msgid="2952042958050315394">"datos móbiles"</item>
    -+    <item msgid="75483255295529161">"wifi"</item>
    -+    <item msgid="6862614801537202646">"Bluetooth"</item>
    -+    <item msgid="5447331121797802871">"Ethernet"</item>
    -+    <item msgid="8257233890381651999">"VPN"</item>
    -+  </string-array>
    -+    <string name="network_switch_type_name_unknown" msgid="4552612897806660656">"un tipo de rede descoñecido"</string>
    -     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Non se puido conectar coa rede Wi-Fi"</string>
    -     <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" ten unha conexión a Internet deficiente."</string>
    -     <string name="wifi_connect_alert_title" msgid="8455846016001810172">"Queres permitir a conexión?"</string>
    -@@ -1153,7 +1165,6 @@
    -     <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"Toca para seleccionar o idioma e o deseño"</string>
    -     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNÑOPQRSTUVWXYZ"</string>
    -     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNÑOPQRSTUVWXYZ"</string>
    --    <string name="candidates_style" msgid="4333913089637062257"><u>"candidatos"</u></string>
    -     <string name="ext_media_checking_notification_title" msgid="5734005953288045806">"Preparando a <xliff:g id="NAME">%s</xliff:g>"</string>
    -     <string name="ext_media_checking_notification_message" msgid="4747432538578886744">"Comprobando se hai erros"</string>
    -     <string name="ext_media_new_notification_message" msgid="7589986898808506239">"Detectouse unha <xliff:g id="NAME">%s</xliff:g> nova"</string>
    -@@ -1232,8 +1243,9 @@
    -     <string name="vpn_text_long" msgid="4907843483284977618">"Conectado a <xliff:g id="SESSION">%s</xliff:g>. Toca aquí para xestionar a rede."</string>
    -     <string name="vpn_lockdown_connecting" msgid="6443438964440960745">"VPN sempre activada conectándose..."</string>
    -     <string name="vpn_lockdown_connected" msgid="8202679674819213931">"VPN sempre activada conectada"</string>
    -+    <string name="vpn_lockdown_disconnected" msgid="4532298952570796327">"Desconectouse a VPN sempre activada"</string>
    -     <string name="vpn_lockdown_error" msgid="6009249814034708175">"Erro na VPN sempre activada"</string>
    --    <string name="vpn_lockdown_config" msgid="4655589351146766608">"Toca para configurar"</string>
    -+    <string name="vpn_lockdown_config" msgid="5099330695245008680">"Tocar para configurar"</string>
    -     <string name="upload_file" msgid="2897957172366730416">"Escoller un ficheiro"</string>
    -     <string name="no_file_chosen" msgid="6363648562170759465">"Non se seleccionou ningún ficheiro"</string>
    -     <string name="reset" msgid="2448168080964209908">"Restablecer"</string>
    -@@ -1317,7 +1329,7 @@
    -     <string name="storage_usb_drive_label" msgid="4501418548927759953">"Unidade USB de <xliff:g id="MANUFACTURER">%s</xliff:g>"</string>
    -     <string name="storage_usb" msgid="3017954059538517278">"almacenamento USB"</string>
    -     <string name="extract_edit_menu_button" msgid="8940478730496610137">"Editar"</string>
    --    <string name="data_usage_warning_title" msgid="1955638862122232342">"Aviso de uso de datos"</string>
    -+    <string name="data_usage_warning_title" msgid="3620440638180218181">"Alerta de uso de datos"</string>
    -     <string name="data_usage_warning_body" msgid="6660692274311972007">"Toca para uso e configuración."</string>
    -     <string name="data_usage_3g_limit_title" msgid="4361523876818447683">"Límite de datos de 2G-3G acadado"</string>
    -     <string name="data_usage_4g_limit_title" msgid="4609566827219442376">"Límite de datos de 4G acadado"</string>
    -@@ -1636,6 +1648,7 @@
    -     <string name="search_language_hint" msgid="7042102592055108574">"Nome do idioma"</string>
    -     <string name="language_picker_section_suggested" msgid="8414489646861640885">"Suxeridos"</string>
    -     <string name="language_picker_section_all" msgid="3097279199511617537">"Todos os idiomas"</string>
    -+    <string name="region_picker_section_all" msgid="8966316787153001779">"Todas as rexións"</string>
    -     <string name="locale_search_menu" msgid="2560710726687249178">"Buscar"</string>
    -     <string name="work_mode_off_title" msgid="8954725060677558855">"Modo de traballo DESACTIVADO"</string>
    -     <string name="work_mode_off_message" msgid="3286169091278094476">"Permite que funcione o perfil de traballo, incluídas as aplicacións, a sincronización en segundo plano e as funcións relacionadas."</string>
    -diff --git a/core/res/res/values-gu-rIN/strings.xml b/core/res/res/values-gu-rIN/strings.xml
    -index 5c3bf93..a233361 100644
    ---- a/core/res/res/values-gu-rIN/strings.xml
    -+++ b/core/res/res/values-gu-rIN/strings.xml
    -@@ -214,6 +214,7 @@
    -     <string name="global_actions" product="default" msgid="2406416831541615258">"ફોન વિકલ્પો"</string>
    -     <string name="global_action_lock" msgid="2844945191792119712">"સ્ક્રીન લૉક"</string>
    -     <string name="global_action_power_off" msgid="4471879440839879722">"પાવર બંધ"</string>
    -+    <string name="global_action_emergency" msgid="7112311161137421166">"કટોકટી"</string>
    -     <string name="global_action_bug_report" msgid="7934010578922304799">"બગ રિપોર્ટ"</string>
    -     <string name="bugreport_title" msgid="2667494803742548533">"બગ રિપોર્ટ લો"</string>
    -     <string name="bugreport_message" msgid="398447048750350456">"આ, એક ઇ-મેઇલ સંદેશ તરીકે મોકલવા માટે, તમારા વર્તમાન ઉપકરણ સ્થિતિ વિશેની માહિતી એકત્રિત કરશે. એક બગ રિપોર્ટ પ્રારંભ કરીને તે મોકલવા માટે તૈયાર ન થઈ જાય ત્યાં સુધી તેમાં થોડો સમય લાગશે; કૃપા કરીને ધીરજ રાખો."</string>
    -@@ -1076,6 +1077,17 @@
    -     <skip />
    -     <string name="wifi_no_internet" msgid="8451173622563841546">"Wi-Fi ને કોઈ ઇન્ટરનેટ ઍક્સેસ નથી"</string>
    -     <string name="wifi_no_internet_detailed" msgid="8083079241212301741">"વિકલ્પો માટે ટૅપ કરો"</string>
    -+    <string name="network_switch_metered" msgid="4671730921726992671">"<xliff:g id="NETWORK_TYPE">%1$s</xliff:g> પર સ્વિચ કર્યું"</string>
    -+    <string name="network_switch_metered_detail" msgid="5325661434777870353">"જ્યારે <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> પાસે કોઈ ઇન્ટરનેટ ઍક્સેસ ન હોય ત્યારે ઉપકરણ <xliff:g id="NEW_NETWORK">%1$s</xliff:g> નો ઉપયોગ કરે છે. શુલ્ક લાગુ થઈ શકે છે."</string>
    -+    <string name="network_switch_metered_toast" msgid="5779283181685974304">"<xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> પરથી <xliff:g id="NEW_NETWORK">%2$s</xliff:g> પર સ્વિચ કર્યું"</string>
    -+  <string-array name="network_switch_type_name">
    -+    <item msgid="2952042958050315394">"સેલ્યુલર ડેટા"</item>
    -+    <item msgid="75483255295529161">"Wi-Fi"</item>
    -+    <item msgid="6862614801537202646">"Bluetooth"</item>
    -+    <item msgid="5447331121797802871">"ઇથરનેટ"</item>
    -+    <item msgid="8257233890381651999">"VPN"</item>
    -+  </string-array>
    -+    <string name="network_switch_type_name_unknown" msgid="4552612897806660656">"અજાણ્યો નેટવર્ક પ્રકાર"</string>
    -     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Wi-Fi સાથે કનેક્ટ કરી શકાયું નથી"</string>
    -     <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" નબળું ઇન્ટરનેટ કનેક્શન ધરાવે છે."</string>
    -     <string name="wifi_connect_alert_title" msgid="8455846016001810172">"કનેક્શનની મંજૂરી આપીએ?"</string>
    -@@ -1153,7 +1165,6 @@
    -     <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"ભાષા અને લેઆઉટ પસંદ કરવા માટે ટૅપ કરો"</string>
    -     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
    -     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
    --    <string name="candidates_style" msgid="4333913089637062257"><u>"ઉમેદવારો"</u></string>
    -     <string name="ext_media_checking_notification_title" msgid="5734005953288045806">"<xliff:g id="NAME">%s</xliff:g> ને તૈયાર કરી રહ્યું છે"</string>
    -     <string name="ext_media_checking_notification_message" msgid="4747432538578886744">"ભૂલો માટે તપાસી રહ્યું છે"</string>
    -     <string name="ext_media_new_notification_message" msgid="7589986898808506239">"નવું <xliff:g id="NAME">%s</xliff:g> મળ્યું"</string>
    -@@ -1232,8 +1243,9 @@
    -     <string name="vpn_text_long" msgid="4907843483284977618">"<xliff:g id="SESSION">%s</xliff:g> થી કનેક્ટ થયાં. નેટવર્કને સંચાલિત કરવા માટે ટૅપ કરો."</string>
    -     <string name="vpn_lockdown_connecting" msgid="6443438964440960745">"હંમેશા-ચાલુ VPN કનેક્ટ થઈ રહ્યું છે…"</string>
    -     <string name="vpn_lockdown_connected" msgid="8202679674819213931">"હંમેશા-ચાલુ VPN કનેક્ટ થયું"</string>
    -+    <string name="vpn_lockdown_disconnected" msgid="4532298952570796327">"હંમેશાં-ચાલુ VPN ડિસ્કનેક્ટ થયું"</string>
    -     <string name="vpn_lockdown_error" msgid="6009249814034708175">"હંમેશાં ચાલુ VPN ભૂલ"</string>
    --    <string name="vpn_lockdown_config" msgid="4655589351146766608">"ગોઠવવા માટે ટૅપ કરો"</string>
    -+    <string name="vpn_lockdown_config" msgid="5099330695245008680">"સેટ કરવા માટે ટૅપ કરો"</string>
    -     <string name="upload_file" msgid="2897957172366730416">"ફાઇલ પસંદ કરો"</string>
    -     <string name="no_file_chosen" msgid="6363648562170759465">"કોઈ ફાઇલ પસંદ કરેલી નથી"</string>
    -     <string name="reset" msgid="2448168080964209908">"ફરીથી સેટ કરો"</string>
    -@@ -1317,7 +1329,7 @@
    -     <string name="storage_usb_drive_label" msgid="4501418548927759953">"<xliff:g id="MANUFACTURER">%s</xliff:g> USB ડ્રાઇવ"</string>
    -     <string name="storage_usb" msgid="3017954059538517278">"USB સંગ્રહ"</string>
    -     <string name="extract_edit_menu_button" msgid="8940478730496610137">"સંપાદિત કરો"</string>
    --    <string name="data_usage_warning_title" msgid="1955638862122232342">"ડેટા વપરાશ ચેતવણી"</string>
    -+    <string name="data_usage_warning_title" msgid="3620440638180218181">"ડેટા વપરાશ ચેતવણી"</string>
    -     <string name="data_usage_warning_body" msgid="6660692274311972007">"વપરાશ અને સેટિંગ્સ જોવા ટૅપ કરો."</string>
    -     <string name="data_usage_3g_limit_title" msgid="4361523876818447683">"2G-3G ડેટા મર્યાદા પર પહોંચ્યાં"</string>
    -     <string name="data_usage_4g_limit_title" msgid="4609566827219442376">"4G ડેટા મર્યાદા સુધી પહોંચ્યાં"</string>
    -@@ -1636,6 +1648,7 @@
    -     <string name="search_language_hint" msgid="7042102592055108574">"ભાષાનું નામ ટાઇપ કરો"</string>
    -     <string name="language_picker_section_suggested" msgid="8414489646861640885">"સૂચવેલા"</string>
    -     <string name="language_picker_section_all" msgid="3097279199511617537">"બધી ભાષાઓ"</string>
    -+    <string name="region_picker_section_all" msgid="8966316787153001779">"તમામ પ્રદેશ"</string>
    -     <string name="locale_search_menu" msgid="2560710726687249178">"શોધ"</string>
    -     <string name="work_mode_off_title" msgid="8954725060677558855">"કાર્ય મોડ બંધ છે"</string>
    -     <string name="work_mode_off_message" msgid="3286169091278094476">"કાર્ય પ્રોફાઇલને ઍપ્લિકેશનો, પૃષ્ઠભૂમિ સમન્વયન અને સંબંધિત સુવિધાઓ સહિતનું કાર્ય કરવાની મંજૂરી આપો."</string>
    -diff --git a/core/res/res/values-hi/strings.xml b/core/res/res/values-hi/strings.xml
    -index bea243b..ea45c1a 100644
    ---- a/core/res/res/values-hi/strings.xml
    -+++ b/core/res/res/values-hi/strings.xml
    -@@ -214,6 +214,7 @@
    -     <string name="global_actions" product="default" msgid="2406416831541615258">"फ़ोन विकल्‍प"</string>
    -     <string name="global_action_lock" msgid="2844945191792119712">"स्‍क्रीन लॉक"</string>
    -     <string name="global_action_power_off" msgid="4471879440839879722">"पावर बंद"</string>
    -+    <string name="global_action_emergency" msgid="7112311161137421166">"आपातकाल"</string>
    -     <string name="global_action_bug_report" msgid="7934010578922304799">"बग रिपोर्ट"</string>
    -     <string name="bugreport_title" msgid="2667494803742548533">"बग रिपोर्ट प्राप्त करें"</string>
    -     <string name="bugreport_message" msgid="398447048750350456">"ईमेल संदेश के रूप में भेजने के लिए, इसके द्वारा आपके डिवाइस की वर्तमान स्थिति के बारे में जानकारी एकत्र की जाएगी. बग रिपोर्ट प्रारंभ करने से लेकर भेजने के लिए तैयार होने तक कुछ समय लगेगा; कृपया धैर्य रखें."</string>
    -@@ -295,9 +296,9 @@
    -     <string name="permlab_sendSms" msgid="7544599214260982981">"SMS संदेश भेजें और देखें"</string>
    -     <string name="permdesc_sendSms" msgid="7094729298204937667">"ऐप्स  को SMS संदेशों को भेजने देता है. इसके परिणामस्वरूप अप्रत्‍याशित शुल्‍क लागू हो सकते हैं. दुर्भावनापूर्ण ऐप्स  आपकी पुष्टि के बिना संदेश भेजकर आपका धन व्‍यय कर सकते हैं."</string>
    -     <string name="permlab_readSms" msgid="8745086572213270480">"अपने लेख संदेश (SMS या MMS) पढ़ें"</string>
    --    <string name="permdesc_readSms" product="tablet" msgid="2467981548684735522">"ऐप्स  को आपके टेबलेट या सिम कार्ड में संग्रहीत SMS संदेश पढ़ने देता है. इससे सामग्री या गोपनीयता पर ध्यान दिए बिना, ऐप्स  सभी SMS संदेश पढ़ सकता है."</string>
    --    <string name="permdesc_readSms" product="tv" msgid="5102425513647038535">"ऐप को आपके टीवी या सिम कार्ड पर संग्रहीत SMS संदेशों को पढ़ने की अनुमति देती है. इससे ऐप को सामग्री या गोपनीयता पर ध्‍यान दिए बिना, सभी SMS संदेशों को पढ़ने की अनुमति मिल जाती है."</string>
    --    <string name="permdesc_readSms" product="default" msgid="3695967533457240550">"ऐप्स  को आपके फ़ोन या सिम कार्ड में संग्रहीत SMS संदेश पढ़ने देता है. इससे सामग्री या गोपनीयता पर ध्यान दिए बिना, ऐप्स  सभी SMS संदेश पढ़ सकता है."</string>
    -+    <string name="permdesc_readSms" product="tablet" msgid="2467981548684735522">"ऐप्स  को आपके टेबलेट या सिम कार्ड में संग्रहीत SMS संदेश पढ़ने देता है. इससे सामग्री या निजता पर ध्यान दिए बिना, ऐप्स  सभी SMS संदेश पढ़ सकता है."</string>
    -+    <string name="permdesc_readSms" product="tv" msgid="5102425513647038535">"ऐप को आपके टीवी या सिम कार्ड पर संग्रहीत SMS संदेशों को पढ़ने की अनुमति देती है. इससे ऐप को सामग्री या निजता पर ध्‍यान दिए बिना, सभी SMS संदेशों को पढ़ने की अनुमति मिल जाती है."</string>
    -+    <string name="permdesc_readSms" product="default" msgid="3695967533457240550">"ऐप्स  को आपके फ़ोन या सिम कार्ड में संग्रहीत SMS संदेश पढ़ने देता है. इससे सामग्री या निजता पर ध्यान दिए बिना, ऐप्स  सभी SMS संदेश पढ़ सकता है."</string>
    -     <string name="permlab_receiveWapPush" msgid="5991398711936590410">"लेख संदेश (WAP) प्राप्त करें"</string>
    -     <string name="permdesc_receiveWapPush" msgid="748232190220583385">"ऐप्स  को WAP संदेशों को प्राप्‍त और संसाधित करने देता है. इस अनुमति में आपको भेजे गए संदेशों की निगरानी आपको दिखाए बिना करने और हटाने की क्षमता शामिल है."</string>
    -     <string name="permlab_getTasks" msgid="6466095396623933906">"चल रहे ऐप्स पुनर्प्राप्त करें"</string>
    -@@ -347,9 +348,9 @@
    -     <string name="permlab_bodySensors" msgid="4683341291818520277">"शरीर संवेदक एक्सेस करें (जैसे हृदय गति मॉनीटर)"</string>
    -     <string name="permdesc_bodySensors" product="default" msgid="4380015021754180431">"ऐप को आपकी शारीरिक स्‍थिति, जैसे आपकी हृदय गति पर नज़र रखने वाले संवेदकों का डेटा एक्‍सेस करने देती है."</string>
    -     <string name="permlab_readCalendar" msgid="5972727560257612398">"केलैंडर ईवेंट के साथ-साथ गोपनीय जानकारी पढ़ें"</string>
    --    <string name="permdesc_readCalendar" product="tablet" msgid="4216462049057658723">"ऐप्स  को मित्रों या सहकर्मियों के कैलेंडर इवेंट सहित, आपके टेबलेट पर संग्रहीत कैलेंडर इवेंट पढ़ने देता है. इससे गोपनीयता या संवेदनशीलता पर ध्यान दिए बिना, ऐप्स  आपके कैलेंडर डेटा को साझा कर सकता है या सहेज सकता है."</string>
    --    <string name="permdesc_readCalendar" product="tv" msgid="3191352452242394196">"ऐप को, मित्रों और सहकर्मियों के कैलेंडर ईवेंट सहित, आपके टीवी पर संग्रहीत सभी कैलेंडर ईवेंट पढ़ने देती है. इससे ऐप को गोपनीयता या संवेदनशीलता पर ध्‍यान दिए बिना, आपका कैलेडर डेटा साझा करने या सहेजने की अनुमति मिल जाती है."</string>
    --    <string name="permdesc_readCalendar" product="default" msgid="7434548682470851583">"ऐप्स  को मित्रों या सहकर्मियों के कैलेंडर इवेंट सहित, आपके फ़ोन पर संग्रहीत कैलेंडर इवेंट पढ़ने देता है. इससे गोपनीयता या संवेदनशीलता पर ध्यान दिए बिना, ऐप्स  आपके कैलेंडर डेटा को साझा कर सकता है या सहेज सकता है."</string>
    -+    <string name="permdesc_readCalendar" product="tablet" msgid="4216462049057658723">"ऐप्स  को मित्रों या सहकर्मियों के कैलेंडर इवेंट सहित, आपके टेबलेट पर संग्रहीत कैलेंडर इवेंट पढ़ने देता है. इससे निजता या संवेदनशीलता पर ध्यान दिए बिना, ऐप्स  आपके कैलेंडर डेटा को साझा कर सकता है या सहेज सकता है."</string>
    -+    <string name="permdesc_readCalendar" product="tv" msgid="3191352452242394196">"ऐप को, मित्रों और सहकर्मियों के कैलेंडर ईवेंट सहित, आपके टीवी पर संग्रहीत सभी कैलेंडर ईवेंट पढ़ने देती है. इससे ऐप को निजता या संवेदनशीलता पर ध्‍यान दिए बिना, आपका कैलेडर डेटा साझा करने या सहेजने की अनुमति मिल जाती है."</string>
    -+    <string name="permdesc_readCalendar" product="default" msgid="7434548682470851583">"ऐप्स  को मित्रों या सहकर्मियों के कैलेंडर इवेंट सहित, आपके फ़ोन पर संग्रहीत कैलेंडर इवेंट पढ़ने देता है. इससे निजता या संवेदनशीलता पर ध्यान दिए बिना, ऐप्स  आपके कैलेंडर डेटा को साझा कर सकता है या सहेज सकता है."</string>
    -     <string name="permlab_writeCalendar" msgid="8438874755193825647">"अपनी जानकारी के बि‍ना कैलेंडर ईवेंट जोड़ें या संशोधि‍त करें और अति‍थि‍यों को ईमेल भेजें"</string>
    -     <string name="permdesc_writeCalendar" product="tablet" msgid="6679035520113668528">"ऐप्स  को मित्रों या सहकर्मियों के ईवेंट के साथ ही वे ईवेंट जोड़ने, निकालने, बदलने देता है जिन्हें आप अपने टेबलेट पर संशोधित कर सकते हैं. इससे ऐप्स ,अपनी जानकारी के बिना उन संदेशों को भेज सकता है जो कैलेंडर स्वामियों की ओर से आते दिखाई देते हैं, या ईवेंट संशोधित कर सकता है."</string>
    -     <string name="permdesc_writeCalendar" product="tv" msgid="1273290605500902507">"ऐप को ऐसे ईवेंट जोड़ने, निकालने, बदलने देती है जिन्हें आप अपने डिवाइस पर बदल सकते हैं, जिनमें मित्रों या सहकर्मियों के ईवेंट शामिल हैं. इससे ऐप ऐसे संदेश भेज सकता है जो कैलेंडर स्वामी से आते हुए प्रतीत होते हैं या ऐप स्वामी की जानकारी के बिना ईवेंट बदल सकता है."</string>
    -@@ -1076,6 +1077,17 @@
    -     <skip />
    -     <string name="wifi_no_internet" msgid="8451173622563841546">"वाई-फ़ाई में कोई इंटरनेट ऐक्‍सेस नहीं है"</string>
    -     <string name="wifi_no_internet_detailed" msgid="8083079241212301741">"विकल्पों के लिए टैप करें"</string>
    -+    <string name="network_switch_metered" msgid="4671730921726992671">"<xliff:g id="NETWORK_TYPE">%1$s</xliff:g> पर ले जाया गया"</string>
    -+    <string name="network_switch_metered_detail" msgid="5325661434777870353">"<xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> में कोई इंटरनेट एक्‍सेस नहीं होने पर डिवाइस <xliff:g id="NEW_NETWORK">%1$s</xliff:g> का उपयोग करता है. शुल्क लिया जा सकता है."</string>
    -+    <string name="network_switch_metered_toast" msgid="5779283181685974304">"<xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> से <xliff:g id="NEW_NETWORK">%2$s</xliff:g> पर ले जाया गया"</string>
    -+  <string-array name="network_switch_type_name">
    -+    <item msgid="2952042958050315394">"सेल्युलर डेटा"</item>
    -+    <item msgid="75483255295529161">"वाई-फ़ाई"</item>
    -+    <item msgid="6862614801537202646">"ब्लूटूथ"</item>
    -+    <item msgid="5447331121797802871">"ईथरनेट"</item>
    -+    <item msgid="8257233890381651999">"VPN"</item>
    -+  </string-array>
    -+    <string name="network_switch_type_name_unknown" msgid="4552612897806660656">"अज्ञात नेटवर्क प्रकार"</string>
    -     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"वाई-फ़ाई  से कनेक्‍ट नहीं हो सका"</string>
    -     <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" के पास एक कमज़ोर इंटरनेट कनेक्‍शन है."</string>
    -     <string name="wifi_connect_alert_title" msgid="8455846016001810172">"कनेक्शन की अनुमति दें?"</string>
    -@@ -1153,7 +1165,6 @@
    -     <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"भाषा और लेआउट चुनने के लिए टैप करें"</string>
    -     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
    -     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
    --    <string name="candidates_style" msgid="4333913089637062257"><u>"उम्‍मीदवार"</u></string>
    -     <string name="ext_media_checking_notification_title" msgid="5734005953288045806">"<xliff:g id="NAME">%s</xliff:g> को तैयार किया जा रहा है"</string>
    -     <string name="ext_media_checking_notification_message" msgid="4747432538578886744">"त्रुटियों की जांच कर रहा है"</string>
    -     <string name="ext_media_new_notification_message" msgid="7589986898808506239">"नए <xliff:g id="NAME">%s</xliff:g> का पता लगा"</string>
    -@@ -1232,8 +1243,9 @@
    -     <string name="vpn_text_long" msgid="4907843483284977618">"<xliff:g id="SESSION">%s</xliff:g> से कनेक्‍ट किया गया. नेटवर्क प्रबंधित करने के लिए टैप करें."</string>
    -     <string name="vpn_lockdown_connecting" msgid="6443438964440960745">"हमेशा-चालू VPN कनेक्ट हो रहा है…"</string>
    -     <string name="vpn_lockdown_connected" msgid="8202679674819213931">"हमेशा-चालू VPN कनेक्ट है"</string>
    -+    <string name="vpn_lockdown_disconnected" msgid="4532298952570796327">"हमेशा-चालू VPN डिस्‍कनेक्‍ट है"</string>
    -     <string name="vpn_lockdown_error" msgid="6009249814034708175">"हमेशा-चालू VPN त्रुटि"</string>
    --    <string name="vpn_lockdown_config" msgid="4655589351146766608">"कॉन्फ़िगर करने के लिए टैप करें"</string>
    -+    <string name="vpn_lockdown_config" msgid="5099330695245008680">"सेट करने के लिए टैप करें"</string>
    -     <string name="upload_file" msgid="2897957172366730416">"फ़ाइल चुनें"</string>
    -     <string name="no_file_chosen" msgid="6363648562170759465">"कोई फ़ाइल चुनी नहीं गई"</string>
    -     <string name="reset" msgid="2448168080964209908">"रीसेट करें"</string>
    -@@ -1317,7 +1329,7 @@
    -     <string name="storage_usb_drive_label" msgid="4501418548927759953">"<xliff:g id="MANUFACTURER">%s</xliff:g> USB डिस्‍क"</string>
    -     <string name="storage_usb" msgid="3017954059538517278">"USB मेमोरी"</string>
    -     <string name="extract_edit_menu_button" msgid="8940478730496610137">"संपादित करें"</string>
    --    <string name="data_usage_warning_title" msgid="1955638862122232342">"डेटा उपयोग की चेतावनी"</string>
    -+    <string name="data_usage_warning_title" msgid="3620440638180218181">"डेटा उपयोग की सूचना"</string>
    -     <string name="data_usage_warning_body" msgid="6660692274311972007">"उपयोग व सेटिंग देखने हेतु टैप करें."</string>
    -     <string name="data_usage_3g_limit_title" msgid="4361523876818447683">"2G-3G डेटा सीमा पूर्ण हो गई"</string>
    -     <string name="data_usage_4g_limit_title" msgid="4609566827219442376">"4G डेटा सीमा पूर्ण हो गई"</string>
    -@@ -1636,6 +1648,7 @@
    -     <string name="search_language_hint" msgid="7042102592055108574">"भाषा का नाम लिखें"</string>
    -     <string name="language_picker_section_suggested" msgid="8414489646861640885">"सुझाए गए"</string>
    -     <string name="language_picker_section_all" msgid="3097279199511617537">"सभी भाषाएं"</string>
    -+    <string name="region_picker_section_all" msgid="8966316787153001779">"सभी क्षेत्र"</string>
    -     <string name="locale_search_menu" msgid="2560710726687249178">"खोजें"</string>
    -     <string name="work_mode_off_title" msgid="8954725060677558855">"कार्य मोड बंद है"</string>
    -     <string name="work_mode_off_message" msgid="3286169091278094476">"ऐप्स, पृष्ठभूमि समन्वयन और संबंधित सुविधाओं सहित कार्य प्रोफ़ाइल को काम करने की अनुमति दें"</string>
    -diff --git a/core/res/res/values-hr/strings.xml b/core/res/res/values-hr/strings.xml
    -index b181f6d..5f2d3d6 100644
    ---- a/core/res/res/values-hr/strings.xml
    -+++ b/core/res/res/values-hr/strings.xml
    -@@ -216,6 +216,7 @@
    -     <string name="global_actions" product="default" msgid="2406416831541615258">"Opcije telefona"</string>
    -     <string name="global_action_lock" msgid="2844945191792119712">"Zaključavanje zaslona"</string>
    -     <string name="global_action_power_off" msgid="4471879440839879722">"Isključi"</string>
    -+    <string name="global_action_emergency" msgid="7112311161137421166">"Hitno"</string>
    -     <string name="global_action_bug_report" msgid="7934010578922304799">"Izvješće o bugovima"</string>
    -     <string name="bugreport_title" msgid="2667494803742548533">"Izvješće o programskoj pogrešci"</string>
    -     <string name="bugreport_message" msgid="398447048750350456">"Time će se prikupiti podaci o trenutačnom stanju vašeg uređaja koje ćete nam poslati u e-poruci. Za pripremu izvješća o programskoj pogrešci potrebno je nešto vremena pa vas molimo za strpljenje."</string>
    -@@ -1101,6 +1102,17 @@
    -     <skip />
    -     <string name="wifi_no_internet" msgid="8451173622563841546">"Wi-Fi nema pristup internetu"</string>
    -     <string name="wifi_no_internet_detailed" msgid="8083079241212301741">"Dodirnite za opcije"</string>
    -+    <string name="network_switch_metered" msgid="4671730921726992671">"Prelazak na drugu mrežu: <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
    -+    <string name="network_switch_metered_detail" msgid="5325661434777870353">"Kada <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> nema pristup internetu, na uređaju se upotrebljava <xliff:g id="NEW_NETWORK">%1$s</xliff:g>. Moguća je naplata naknade."</string>
    -+    <string name="network_switch_metered_toast" msgid="5779283181685974304">"Mreža je promijenjena: <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> &gt; <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
    -+  <string-array name="network_switch_type_name">
    -+    <item msgid="2952042958050315394">"mobilni podaci"</item>
    -+    <item msgid="75483255295529161">"Wi-Fi"</item>
    -+    <item msgid="6862614801537202646">"Bluetooth"</item>
    -+    <item msgid="5447331121797802871">"Ethernet"</item>
    -+    <item msgid="8257233890381651999">"VPN"</item>
    -+  </string-array>
    -+    <string name="network_switch_type_name_unknown" msgid="4552612897806660656">"nepoznata vrsta mreže"</string>
    -     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Ne može se spojiti na Wi-Fi"</string>
    -     <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" ima lošu internetsku vezu."</string>
    -     <string name="wifi_connect_alert_title" msgid="8455846016001810172">"Dopustiti povezivanje?"</string>
    -@@ -1178,7 +1190,6 @@
    -     <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"Dodirnite da biste odabrali jezik i raspored"</string>
    -     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
    -     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
    --    <string name="candidates_style" msgid="4333913089637062257"><u>"kandidati"</u></string>
    -     <string name="ext_media_checking_notification_title" msgid="5734005953288045806">"Priprema uređaja <xliff:g id="NAME">%s</xliff:g>"</string>
    -     <string name="ext_media_checking_notification_message" msgid="4747432538578886744">"Traženje pogrešaka"</string>
    -     <string name="ext_media_new_notification_message" msgid="7589986898808506239">"Otkriven je novi uređaj <xliff:g id="NAME">%s</xliff:g>"</string>
    -@@ -1257,8 +1268,9 @@
    -     <string name="vpn_text_long" msgid="4907843483284977618">"Povezan sa sesijom <xliff:g id="SESSION">%s</xliff:g>. Dotaknite za upravljanje mrežom."</string>
    -     <string name="vpn_lockdown_connecting" msgid="6443438964440960745">"Povezivanje s uvijek uključenom VPN mrežom…"</string>
    -     <string name="vpn_lockdown_connected" msgid="8202679674819213931">"Povezan s uvijek uključenom VPN mrežom"</string>
    -+    <string name="vpn_lockdown_disconnected" msgid="4532298952570796327">"Prekinuta je veza s uvijek uključenom VPN mrežom"</string>
    -     <string name="vpn_lockdown_error" msgid="6009249814034708175">"Pogreška uvijek uključene VPN mreže"</string>
    --    <string name="vpn_lockdown_config" msgid="4655589351146766608">"Dodirnite da biste konfigurirali"</string>
    -+    <string name="vpn_lockdown_config" msgid="5099330695245008680">"Dodirnite za postavljanje"</string>
    -     <string name="upload_file" msgid="2897957172366730416">"Odaberite datoteku"</string>
    -     <string name="no_file_chosen" msgid="6363648562170759465">"Nema odabranih datoteka"</string>
    -     <string name="reset" msgid="2448168080964209908">"Ponovo postavi"</string>
    -@@ -1343,7 +1355,7 @@
    -     <string name="storage_usb_drive_label" msgid="4501418548927759953">"<xliff:g id="MANUFACTURER">%s</xliff:g> USB pogon"</string>
    -     <string name="storage_usb" msgid="3017954059538517278">"USB pohrana"</string>
    -     <string name="extract_edit_menu_button" msgid="8940478730496610137">"Uredi"</string>
    --    <string name="data_usage_warning_title" msgid="1955638862122232342">"Upozorenje o upotrebi podataka"</string>
    -+    <string name="data_usage_warning_title" msgid="3620440638180218181">"Upozorenje o upotrebi podataka"</string>
    -     <string name="data_usage_warning_body" msgid="6660692274311972007">"Dodirnite za upotrebu i postavke"</string>
    -     <string name="data_usage_3g_limit_title" msgid="4361523876818447683">"Dost. ogr. 2G–3G prijenosa pod."</string>
    -     <string name="data_usage_4g_limit_title" msgid="4609566827219442376">"Dost. ogr. 4G prijenosa podataka"</string>
    -@@ -1672,6 +1684,7 @@
    -     <string name="search_language_hint" msgid="7042102592055108574">"Unesite naziv jezika"</string>
    -     <string name="language_picker_section_suggested" msgid="8414489646861640885">"Predloženo"</string>
    -     <string name="language_picker_section_all" msgid="3097279199511617537">"Svi jezici"</string>
    -+    <string name="region_picker_section_all" msgid="8966316787153001779">"Sve regije"</string>
    -     <string name="locale_search_menu" msgid="2560710726687249178">"Pretraži"</string>
    -     <string name="work_mode_off_title" msgid="8954725060677558855">"Radni je način ISKLJUČEN"</string>
    -     <string name="work_mode_off_message" msgid="3286169091278094476">"Omogućuje radnom profilu da funkcionira, uključujući aplikacije, sinkronizaciju u pozadini i povezane značajke."</string>
    -diff --git a/core/res/res/values-hu/strings.xml b/core/res/res/values-hu/strings.xml
    -index aea12a6..cd3659a 100644
    ---- a/core/res/res/values-hu/strings.xml
    -+++ b/core/res/res/values-hu/strings.xml
    -@@ -214,6 +214,7 @@
    -     <string name="global_actions" product="default" msgid="2406416831541615258">"Telefonbeállítások"</string>
    -     <string name="global_action_lock" msgid="2844945191792119712">"Képernyő lezárása"</string>
    -     <string name="global_action_power_off" msgid="4471879440839879722">"Kikapcsolás"</string>
    -+    <string name="global_action_emergency" msgid="7112311161137421166">"Vészhívás"</string>
    -     <string name="global_action_bug_report" msgid="7934010578922304799">"Programhiba bejelentése"</string>
    -     <string name="bugreport_title" msgid="2667494803742548533">"Hibajelentés készítése"</string>
    -     <string name="bugreport_message" msgid="398447048750350456">"Ezzel információt fog gyűjteni az eszköz jelenlegi állapotáról, amelyet a rendszer e-mailben fog elküldeni. Kérjük, legyen türelemmel, amíg a hibajelentés elkészül, és küldhető állapotba kerül."</string>
    -@@ -1076,6 +1077,17 @@
    -     <skip />
    -     <string name="wifi_no_internet" msgid="8451173622563841546">"A Wi-Fi-hálózaton nincs internetkapcsolat"</string>
    -     <string name="wifi_no_internet_detailed" msgid="8083079241212301741">"Koppintson a beállítások megjelenítéséhez"</string>
    -+    <string name="network_switch_metered" msgid="4671730921726992671">"Átváltva erre: <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
    -+    <string name="network_switch_metered_detail" msgid="5325661434777870353">"<xliff:g id="NEW_NETWORK">%1$s</xliff:g> használata, ha nincs internetkapcsolat <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g>-kapcsolaton keresztül. A szolgáltató díjat számíthat fel."</string>
    -+    <string name="network_switch_metered_toast" msgid="5779283181685974304">"Átváltva <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g>-hálózatról erre: <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
    -+  <string-array name="network_switch_type_name">
    -+    <item msgid="2952042958050315394">"mobiladat"</item>
    -+    <item msgid="75483255295529161">"Wi-Fi"</item>
    -+    <item msgid="6862614801537202646">"Bluetooth"</item>
    -+    <item msgid="5447331121797802871">"Ethernet"</item>
    -+    <item msgid="8257233890381651999">"VPN"</item>
    -+  </string-array>
    -+    <string name="network_switch_type_name_unknown" msgid="4552612897806660656">"ismeretlen hálózati típus"</string>
    -     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Nem sikerült csatlakozni a Wi-Fi hálózathoz"</string>
    -     <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" rossz internetkapcsolattal rendelkezik."</string>
    -     <string name="wifi_connect_alert_title" msgid="8455846016001810172">"Engedélyezi a csatlakozást?"</string>
    -@@ -1153,7 +1165,6 @@
    -     <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"Koppintson a nyelv és a billentyűzetkiosztás kiválasztásához"</string>
    -     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
    -     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
    --    <string name="candidates_style" msgid="4333913089637062257"><u>"jelöltek"</u></string>
    -     <string name="ext_media_checking_notification_title" msgid="5734005953288045806">"<xliff:g id="NAME">%s</xliff:g> előkészítése"</string>
    -     <string name="ext_media_checking_notification_message" msgid="4747432538578886744">"Hibák keresése"</string>
    -     <string name="ext_media_new_notification_message" msgid="7589986898808506239">"Új <xliff:g id="NAME">%s</xliff:g> észlelve"</string>
    -@@ -1232,8 +1243,9 @@
    -     <string name="vpn_text_long" msgid="4907843483284977618">"Csatlakozva ide: <xliff:g id="SESSION">%s</xliff:g>. Érintse meg a hálózat kezeléséhez."</string>
    -     <string name="vpn_lockdown_connecting" msgid="6443438964440960745">"Csatlakozás a mindig bekapcsolt VPN-hez..."</string>
    -     <string name="vpn_lockdown_connected" msgid="8202679674819213931">"Csatlakozva a mindig bekapcsolt VPN-hez"</string>
    -+    <string name="vpn_lockdown_disconnected" msgid="4532298952570796327">"Kapcsolat bontva a mindig bekapcsolt VPN-nel"</string>
    -     <string name="vpn_lockdown_error" msgid="6009249814034708175">"Hiba a mindig bekapcsolt VPN-nel"</string>
    --    <string name="vpn_lockdown_config" msgid="4655589351146766608">"Koppintson a konfiguráláshoz"</string>
    -+    <string name="vpn_lockdown_config" msgid="5099330695245008680">"Koppintson ide a beállításhoz"</string>
    -     <string name="upload_file" msgid="2897957172366730416">"Fájl kiválasztása"</string>
    -     <string name="no_file_chosen" msgid="6363648562170759465">"Nincs fájl kiválasztva"</string>
    -     <string name="reset" msgid="2448168080964209908">"Alaphelyzet"</string>
    -@@ -1317,7 +1329,7 @@
    -     <string name="storage_usb_drive_label" msgid="4501418548927759953">"<xliff:g id="MANUFACTURER">%s</xliff:g> USB-meghajtó"</string>
    -     <string name="storage_usb" msgid="3017954059538517278">"USB-tár"</string>
    -     <string name="extract_edit_menu_button" msgid="8940478730496610137">"Szerkesztés"</string>
    --    <string name="data_usage_warning_title" msgid="1955638862122232342">"Adathasználati figyelmeztetés"</string>
    -+    <string name="data_usage_warning_title" msgid="3620440638180218181">"Adathasználati értesítés"</string>
    -     <string name="data_usage_warning_body" msgid="6660692274311972007">"Koppintson az adatokért."</string>
    -     <string name="data_usage_3g_limit_title" msgid="4361523876818447683">"2G-/3G-adatkorlát elérve"</string>
    -     <string name="data_usage_4g_limit_title" msgid="4609566827219442376">"4G-adatkorlát elérve"</string>
    -@@ -1636,6 +1648,7 @@
    -     <string name="search_language_hint" msgid="7042102592055108574">"Adja meg a nyelvet"</string>
    -     <string name="language_picker_section_suggested" msgid="8414489646861640885">"Javasolt"</string>
    -     <string name="language_picker_section_all" msgid="3097279199511617537">"Minden nyelv"</string>
    -+    <string name="region_picker_section_all" msgid="8966316787153001779">"Minden régió"</string>
    -     <string name="locale_search_menu" msgid="2560710726687249178">"Keresés"</string>
    -     <string name="work_mode_off_title" msgid="8954725060677558855">"A munka mód KI van kapcsolva"</string>
    -     <string name="work_mode_off_message" msgid="3286169091278094476">"Munkaprofil használatának engedélyezése, beleértve az alkalmazásokat, a háttérben való szinkronizálást és a kapcsolódó funkciókat."</string>
    -diff --git a/core/res/res/values-hy-rAM/strings.xml b/core/res/res/values-hy-rAM/strings.xml
    -index ba97468..160efff 100644
    ---- a/core/res/res/values-hy-rAM/strings.xml
    -+++ b/core/res/res/values-hy-rAM/strings.xml
    -@@ -214,6 +214,7 @@
    -     <string name="global_actions" product="default" msgid="2406416831541615258">"Հեռախոսի ընտրանքներ"</string>
    -     <string name="global_action_lock" msgid="2844945191792119712">"Էկրանի փական"</string>
    -     <string name="global_action_power_off" msgid="4471879440839879722">"Անջատել"</string>
    -+    <string name="global_action_emergency" msgid="7112311161137421166">"Շտապ կանչ"</string>
    -     <string name="global_action_bug_report" msgid="7934010578922304799">"Վրիպակի զեկույց"</string>
    -     <string name="bugreport_title" msgid="2667494803742548533">"Գրել սխալի զեկույց"</string>
    -     <string name="bugreport_message" msgid="398447048750350456">"Սա տեղեկություններ կհավաքագրի ձեր սարքի առկա կարգավիճակի մասին և կուղարկի այն էլեկտրոնային նամակով: Որոշակի ժամանակ կպահանջվի վրիպակի մասին զեկուցելու պահից սկսած մինչ ուղարկելը: Խնդրում ենք փոքր-ինչ համբերատար լինել:"</string>
    -@@ -249,17 +250,17 @@
    -     <string name="permgrouplab_calendar" msgid="5863508437783683902">"Օրացույց"</string>
    -     <string name="permgroupdesc_calendar" msgid="3889615280211184106">"օգտագործել օրացույցը"</string>
    -     <string name="permgrouplab_sms" msgid="228308803364967808">"Կարճ հաղորդագրություն"</string>
    --    <string name="permgroupdesc_sms" msgid="4656988620100940350">"ուղարկել և դիտել SMS հաղորդագրությունները"</string>
    -+    <string name="permgroupdesc_sms" msgid="4656988620100940350">"ուղարկել և դիտել SMS-ները"</string>
    -     <string name="permgrouplab_storage" msgid="1971118770546336966">"Պահոց"</string>
    --    <string name="permgroupdesc_storage" msgid="637758554581589203">"օգտագործել լուսանկարները, մեդիա ֆայլերը և ձեր սարքում պահվող այլ ֆայլերը"</string>
    -+    <string name="permgroupdesc_storage" msgid="637758554581589203">"օգտագործել լուսանկարները, մեդիա ֆայլերը և ձեր սարքում պահվող մյուս ֆայլերը"</string>
    -     <string name="permgrouplab_microphone" msgid="171539900250043464">"Բարձրախոս"</string>
    --    <string name="permgroupdesc_microphone" msgid="4988812113943554584">"ձայնագրում"</string>
    -+    <string name="permgroupdesc_microphone" msgid="4988812113943554584">"ձայնագրել"</string>
    -     <string name="permgrouplab_camera" msgid="4820372495894586615">"Ֆոտոխցիկ"</string>
    --    <string name="permgroupdesc_camera" msgid="3250611594678347720">"լուսանկարում և տեսագրում"</string>
    -+    <string name="permgroupdesc_camera" msgid="3250611594678347720">"լուսանկարել և տեսագրել"</string>
    -     <string name="permgrouplab_phone" msgid="5229115638567440675">"Հեռախոս"</string>
    --    <string name="permgroupdesc_phone" msgid="6234224354060641055">"հեռախոսազանգերի կատարում և կառավարում"</string>
    -+    <string name="permgroupdesc_phone" msgid="6234224354060641055">"կատարել զանգեր և կառավարել զանգերը"</string>
    -     <string name="permgrouplab_sensors" msgid="416037179223226722">"Մարմնի սենսորներ"</string>
    --    <string name="permgroupdesc_sensors" msgid="7147968539346634043">"օգտագործել ձեր հիմնական ֆիզիոլոգիական ցուցանիշների վերաբերյալ սենսորի տվյալները"</string>
    -+    <string name="permgroupdesc_sensors" msgid="7147968539346634043">"օգտագործել սենսորների տվյալները ձեր օրգանիզմի վիճակի մասին"</string>
    -     <string name="capability_title_canRetrieveWindowContent" msgid="3901717936930170320">"Առբերել պատուհանի բովանդակությունը"</string>
    -     <string name="capability_desc_canRetrieveWindowContent" msgid="3772225008605310672">"Ստուգեք պատուհանի բովանդակությունը, որի հետ փոխգործակցում եք:"</string>
    -     <string name="capability_title_canRequestTouchExploration" msgid="3108723364676667320">"Միացնել Հպման միջոցով հետազոտումը"</string>
    -@@ -673,7 +674,7 @@
    -     <string name="lockscreen_instructions_when_pattern_enabled" msgid="46154051614126049">"Ապակողպելու կամ շտապ կանչ անելու համար սեղմեք «Ընտրացանկ»"</string>
    -     <string name="lockscreen_instructions_when_pattern_disabled" msgid="686260028797158364">"Ապակողպելու համար սեղմեք Ցանկը:"</string>
    -     <string name="lockscreen_pattern_instructions" msgid="7478703254964810302">"Հավաքեք սխեման` ապակողպելու համար"</string>
    --    <string name="lockscreen_emergency_call" msgid="5298642613417801888">"Արտակարգ իրավիճակ"</string>
    -+    <string name="lockscreen_emergency_call" msgid="5298642613417801888">"Շտապ կանչ"</string>
    -     <string name="lockscreen_return_to_call" msgid="5244259785500040021">"Վերադառնալ զանգին"</string>
    -     <string name="lockscreen_pattern_correct" msgid="9039008650362261237">"Ճիշտ է:"</string>
    -     <string name="lockscreen_pattern_wrong" msgid="4317955014948108794">"Կրկին փորձեք"</string>
    -@@ -1057,8 +1058,8 @@
    -     <string name="volume_icon_description_incall" msgid="8890073218154543397">"Զանգի ձայնի բարձրություն"</string>
    -     <string name="volume_icon_description_media" msgid="4217311719665194215">"Մեդիա ձայնի բարձրություն"</string>
    -     <string name="volume_icon_description_notification" msgid="7044986546477282274">"Ծանուցումների ձայնի ուժգնությունը"</string>
    --    <string name="ringtone_default" msgid="3789758980357696936">"Լռելյայն զանգերանգ"</string>
    --    <string name="ringtone_default_with_actual" msgid="8129563480895990372">"Լռելյայն զանգերանգ (<xliff:g id="ACTUAL_RINGTONE">%1$s</xliff:g>)"</string>
    -+    <string name="ringtone_default" msgid="3789758980357696936">"Կանխադրված զանգերանգ"</string>
    -+    <string name="ringtone_default_with_actual" msgid="8129563480895990372">"Կանխադրված զանգերանգ (<xliff:g id="ACTUAL_RINGTONE">%1$s</xliff:g>)"</string>
    -     <string name="ringtone_silent" msgid="7937634392408977062">"Ոչ մեկը"</string>
    -     <string name="ringtone_picker_title" msgid="3515143939175119094">"Զանգերանգներ"</string>
    -     <string name="ringtone_unknown" msgid="5477919988701784788">"Անհայտ զանգերանգ"</string>
    -@@ -1076,6 +1077,17 @@
    -     <skip />
    -     <string name="wifi_no_internet" msgid="8451173622563841546">"Wi-Fi ցանցը համացանցի միացում չունի"</string>
    -     <string name="wifi_no_internet_detailed" msgid="8083079241212301741">"Հպեք՝ ընտրանքները տեսնելու համար"</string>
    -+    <string name="network_switch_metered" msgid="4671730921726992671">"Անցել է <xliff:g id="NETWORK_TYPE">%1$s</xliff:g> ցանցի"</string>
    -+    <string name="network_switch_metered_detail" msgid="5325661434777870353">"Եթե <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> ցանցն ինտերնետ կապ չունի, սարքն անցնում է <xliff:g id="NEW_NETWORK">%1$s</xliff:g> ցանցի: Կարող են վճարներ գանձվել:"</string>
    -+    <string name="network_switch_metered_toast" msgid="5779283181685974304">"<xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> ցանցից անցել է <xliff:g id="NEW_NETWORK">%2$s</xliff:g> ցանցի"</string>
    -+  <string-array name="network_switch_type_name">
    -+    <item msgid="2952042958050315394">"բջջային տվյալներ"</item>
    -+    <item msgid="75483255295529161">"Wi-Fi"</item>
    -+    <item msgid="6862614801537202646">"Bluetooth"</item>
    -+    <item msgid="5447331121797802871">"Ethernet"</item>
    -+    <item msgid="8257233890381651999">"VPN"</item>
    -+  </string-array>
    -+    <string name="network_switch_type_name_unknown" msgid="4552612897806660656">"ցանցի անհայտ տեսակ"</string>
    -     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Չհաջողվեց միանալ Wi-Fi-ին"</string>
    -     <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" ունի թույլ ինտերնետ կապ:"</string>
    -     <string name="wifi_connect_alert_title" msgid="8455846016001810172">"Թույլատրե՞լ կապը:"</string>
    -@@ -1153,7 +1165,6 @@
    -     <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"Հպեք՝ լեզուն և դասավորությունն ընտրելու համար"</string>
    -     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ԱԲԳԴԵԶԷԸԹԺԻԼԽԾԿՀՁՂՃՄՅՆՇՈՉՊՋՌՍՎՏՐՑՈՒՓՔԵւՕՖ"</string>
    -     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
    --    <string name="candidates_style" msgid="4333913089637062257"><u>"թեկնածուները"</u></string>
    -     <string name="ext_media_checking_notification_title" msgid="5734005953288045806">"<xliff:g id="NAME">%s</xliff:g>-ի նախապատրաստում"</string>
    -     <string name="ext_media_checking_notification_message" msgid="4747432538578886744">"Սխալների ստուգում"</string>
    -     <string name="ext_media_new_notification_message" msgid="7589986898808506239">"Հայտնաբերվել է նոր <xliff:g id="NAME">%s</xliff:g>"</string>
    -@@ -1232,8 +1243,9 @@
    -     <string name="vpn_text_long" msgid="4907843483284977618">"Կապակացված է <xliff:g id="SESSION">%s</xliff:g>-ին: Սեղմեք` ցանցը կառավարելու համար:"</string>
    -     <string name="vpn_lockdown_connecting" msgid="6443438964440960745">"Միշտ-միացված VPN-ը կապվում է..."</string>
    -     <string name="vpn_lockdown_connected" msgid="8202679674819213931">"Միշտ-առցանց VPN-ը կապակցված է"</string>
    -+    <string name="vpn_lockdown_disconnected" msgid="4532298952570796327">"«Միշտ միացված VPN»-ն անջատված է"</string>
    -     <string name="vpn_lockdown_error" msgid="6009249814034708175">"VPN սխալը միշտ միացված"</string>
    --    <string name="vpn_lockdown_config" msgid="4655589351146766608">"Հպեք՝ կազմաձևելու համար"</string>
    -+    <string name="vpn_lockdown_config" msgid="5099330695245008680">"Հպեք՝ կարգավորելու համար"</string>
    -     <string name="upload_file" msgid="2897957172366730416">"Ընտրել ֆայլը"</string>
    -     <string name="no_file_chosen" msgid="6363648562170759465">"Ոչ մի ֆայլ չի ընտրված"</string>
    -     <string name="reset" msgid="2448168080964209908">"Վերակայել"</string>
    -@@ -1317,7 +1329,7 @@
    -     <string name="storage_usb_drive_label" msgid="4501418548927759953">"USB սարքավար <xliff:g id="MANUFACTURER">%s</xliff:g>-ից"</string>
    -     <string name="storage_usb" msgid="3017954059538517278">"USB կրիչ"</string>
    -     <string name="extract_edit_menu_button" msgid="8940478730496610137">"Խմբագրել"</string>
    --    <string name="data_usage_warning_title" msgid="1955638862122232342">"Տվյալների օգտագործման նախազգուշացում"</string>
    -+    <string name="data_usage_warning_title" msgid="3620440638180218181">"Տվյալների օգտագործման զգուշացում"</string>
    -     <string name="data_usage_warning_body" msgid="6660692274311972007">"Հպեք և տեսեք օգտագործումը և կարգավորումները:"</string>
    -     <string name="data_usage_3g_limit_title" msgid="4361523876818447683">"2G-3G տվյալների սահմանաչափը սպառվել է"</string>
    -     <string name="data_usage_4g_limit_title" msgid="4609566827219442376">"4G տվյալների սահմանաչափը սպառվել է"</string>
    -@@ -1636,6 +1648,7 @@
    -     <string name="search_language_hint" msgid="7042102592055108574">"Մուտքագրեք լեզուն"</string>
    -     <string name="language_picker_section_suggested" msgid="8414489646861640885">"Առաջարկներ"</string>
    -     <string name="language_picker_section_all" msgid="3097279199511617537">"Բոլոր լեզուները"</string>
    -+    <string name="region_picker_section_all" msgid="8966316787153001779">"Բոլոր տարածաշրջանները"</string>
    -     <string name="locale_search_menu" msgid="2560710726687249178">"Որոնում"</string>
    -     <string name="work_mode_off_title" msgid="8954725060677558855">"Աշխատանքային ռեժիմն ԱՆՋԱՏՎԱԾ Է"</string>
    -     <string name="work_mode_off_message" msgid="3286169091278094476">"Միացնել աշխատանքային պրոֆիլը՝ հավելվածները, ֆոնային համաժամեցումը և առնչվող գործառույթները"</string>
    -diff --git a/core/res/res/values-in/strings.xml b/core/res/res/values-in/strings.xml
    -index 132789b..fefca0c 100644
    ---- a/core/res/res/values-in/strings.xml
    -+++ b/core/res/res/values-in/strings.xml
    -@@ -116,7 +116,7 @@
    -     <string name="roamingText5" msgid="7604063252850354350">"Roaming - Sistem Yang Dipilih"</string>
    -     <string name="roamingText6" msgid="2059440825782871513">"Roaming - Sistem Tersedia"</string>
    -     <string name="roamingText7" msgid="7112078724097233605">"Mitra Roaming - Alliance"</string>
    --    <string name="roamingText8" msgid="5989569778604089291">"Roaming - Mitra Premium"</string>
    -+    <string name="roamingText8" msgid="5989569778604089291">"Roaming - Partner Premium"</string>
    -     <string name="roamingText9" msgid="7969296811355152491">"Fungsionalitas Layanan Roaming - Penuh"</string>
    -     <string name="roamingText10" msgid="3992906999815316417">"Fungsionalitas Layanan Roaming - Sebagian"</string>
    -     <string name="roamingText11" msgid="4154476854426920970">"Spanduk Roaming Hidup"</string>
    -@@ -214,6 +214,7 @@
    -     <string name="global_actions" product="default" msgid="2406416831541615258">"Opsi telepon"</string>
    -     <string name="global_action_lock" msgid="2844945191792119712">"Kunci layar"</string>
    -     <string name="global_action_power_off" msgid="4471879440839879722">"Matikan daya"</string>
    -+    <string name="global_action_emergency" msgid="7112311161137421166">"Darurat"</string>
    -     <string name="global_action_bug_report" msgid="7934010578922304799">"Laporan bug"</string>
    -     <string name="bugreport_title" msgid="2667494803742548533">"Ambil laporan bug"</string>
    -     <string name="bugreport_message" msgid="398447048750350456">"Ini akan mengumpulkan informasi status perangkat Anda saat ini, untuk dikirimkan sebagai pesan email. Harap bersabar, mungkin perlu waktu untuk memulai laporan bug hingga siap dikirim."</string>
    -@@ -253,7 +254,7 @@
    -     <string name="permgrouplab_storage" msgid="1971118770546336966">"Penyimpanan"</string>
    -     <string name="permgroupdesc_storage" msgid="637758554581589203">"mengakses foto, media, dan file di perangkat"</string>
    -     <string name="permgrouplab_microphone" msgid="171539900250043464">"Mikrofon"</string>
    --    <string name="permgroupdesc_microphone" msgid="4988812113943554584">"rekam audio"</string>
    -+    <string name="permgroupdesc_microphone" msgid="4988812113943554584">"merekam audio"</string>
    -     <string name="permgrouplab_camera" msgid="4820372495894586615">"Kamera"</string>
    -     <string name="permgroupdesc_camera" msgid="3250611594678347720">"mengambil gambar dan merekam video"</string>
    -     <string name="permgrouplab_phone" msgid="5229115638567440675">"Telepon"</string>
    -@@ -1076,6 +1077,17 @@
    -     <skip />
    -     <string name="wifi_no_internet" msgid="8451173622563841546">"Wi-Fi tidak memiliki akses internet"</string>
    -     <string name="wifi_no_internet_detailed" msgid="8083079241212301741">"Ketuk untuk melihat opsi"</string>
    -+    <string name="network_switch_metered" msgid="4671730921726992671">"Dialihkan ke <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
    -+    <string name="network_switch_metered_detail" msgid="5325661434777870353">"Perangkat menggunakan <xliff:g id="NEW_NETWORK">%1$s</xliff:g> jika <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> tidak memiliki akses internet. Tarif mungkin berlaku."</string>
    -+    <string name="network_switch_metered_toast" msgid="5779283181685974304">"Dialihkan dari <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> ke <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
    -+  <string-array name="network_switch_type_name">
    -+    <item msgid="2952042958050315394">"data seluler"</item>
    -+    <item msgid="75483255295529161">"Wi-Fi"</item>
    -+    <item msgid="6862614801537202646">"Bluetooth"</item>
    -+    <item msgid="5447331121797802871">"Ethernet"</item>
    -+    <item msgid="8257233890381651999">"VPN"</item>
    -+  </string-array>
    -+    <string name="network_switch_type_name_unknown" msgid="4552612897806660656">"jenis jaringan yang tidak dikenal"</string>
    -     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Tidak dapat tersambung ke Wi-Fi"</string>
    -     <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" memiliki sambungan internet yang buruk."</string>
    -     <string name="wifi_connect_alert_title" msgid="8455846016001810172">"Izinkan hubungan?"</string>
    -@@ -1153,7 +1165,6 @@
    -     <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"Ketuk untuk memilih bahasa dan tata letak"</string>
    -     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
    -     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
    --    <string name="candidates_style" msgid="4333913089637062257"><u>"calon"</u></string>
    -     <string name="ext_media_checking_notification_title" msgid="5734005953288045806">"Menyiapkan <xliff:g id="NAME">%s</xliff:g>"</string>
    -     <string name="ext_media_checking_notification_message" msgid="4747432538578886744">"Memeriksa kesalahan"</string>
    -     <string name="ext_media_new_notification_message" msgid="7589986898808506239">"<xliff:g id="NAME">%s</xliff:g> baru terdeteksi"</string>
    -@@ -1232,8 +1243,9 @@
    -     <string name="vpn_text_long" msgid="4907843483284977618">"Tersambung ke <xliff:g id="SESSION">%s</xliff:g>. Ketuk untuk mengelola jaringan."</string>
    -     <string name="vpn_lockdown_connecting" msgid="6443438964440960745">"Menyambungkan VPN selalu aktif..."</string>
    -     <string name="vpn_lockdown_connected" msgid="8202679674819213931">"VPN selalu aktif tersambung"</string>
    -+    <string name="vpn_lockdown_disconnected" msgid="4532298952570796327">"VPN selalu aktif terputus"</string>
    -     <string name="vpn_lockdown_error" msgid="6009249814034708175">"Kesalahan VPN selalu aktif"</string>
    --    <string name="vpn_lockdown_config" msgid="4655589351146766608">"Ketuk untuk mengonfigurasi"</string>
    -+    <string name="vpn_lockdown_config" msgid="5099330695245008680">"Ketuk untuk menyiapkan"</string>
    -     <string name="upload_file" msgid="2897957172366730416">"Pilih file"</string>
    -     <string name="no_file_chosen" msgid="6363648562170759465">"Tidak ada file yang dipilih"</string>
    -     <string name="reset" msgid="2448168080964209908">"Setel ulang"</string>
    -@@ -1317,7 +1329,7 @@
    -     <string name="storage_usb_drive_label" msgid="4501418548927759953">"Drive USB <xliff:g id="MANUFACTURER">%s</xliff:g>"</string>
    -     <string name="storage_usb" msgid="3017954059538517278">"Penyimpanan USB"</string>
    -     <string name="extract_edit_menu_button" msgid="8940478730496610137">"Edit"</string>
    --    <string name="data_usage_warning_title" msgid="1955638862122232342">"Peringatan penggunaan data"</string>
    -+    <string name="data_usage_warning_title" msgid="3620440638180218181">"Lansiran penggunaan data"</string>
    -     <string name="data_usage_warning_body" msgid="6660692274311972007">"Ketuk untuk lihat penggunaan &amp; setelan."</string>
    -     <string name="data_usage_3g_limit_title" msgid="4361523876818447683">"Batas data 2G-3G terlampaui"</string>
    -     <string name="data_usage_4g_limit_title" msgid="4609566827219442376">"Batas data 4G terlampaui"</string>
    -@@ -1636,6 +1648,7 @@
    -     <string name="search_language_hint" msgid="7042102592055108574">"Ketik nama bahasa"</string>
    -     <string name="language_picker_section_suggested" msgid="8414489646861640885">"Disarankan"</string>
    -     <string name="language_picker_section_all" msgid="3097279199511617537">"Semua bahasa"</string>
    -+    <string name="region_picker_section_all" msgid="8966316787153001779">"Semua wilayah"</string>
    -     <string name="locale_search_menu" msgid="2560710726687249178">"Telusuri"</string>
    -     <string name="work_mode_off_title" msgid="8954725060677558855">"Mode kerja NONAKTIF"</string>
    -     <string name="work_mode_off_message" msgid="3286169091278094476">"Izinkan profil kerja berfungsi, termasuk aplikasi, sinkronisasi latar belakang, dan fitur terkait."</string>
    -diff --git a/core/res/res/values-is-rIS/strings.xml b/core/res/res/values-is-rIS/strings.xml
    -index a897ba8..cdc6d42 100644
    ---- a/core/res/res/values-is-rIS/strings.xml
    -+++ b/core/res/res/values-is-rIS/strings.xml
    -@@ -214,6 +214,7 @@
    -     <string name="global_actions" product="default" msgid="2406416831541615258">"Valkostir síma"</string>
    -     <string name="global_action_lock" msgid="2844945191792119712">"Skjálás"</string>
    -     <string name="global_action_power_off" msgid="4471879440839879722">"Slökkva"</string>
    -+    <string name="global_action_emergency" msgid="7112311161137421166">"Neyðarsímtal"</string>
    -     <string name="global_action_bug_report" msgid="7934010578922304799">"Villutilkynning"</string>
    -     <string name="bugreport_title" msgid="2667494803742548533">"Útbúa villutilkynningu"</string>
    -     <string name="bugreport_message" msgid="398447048750350456">"Þetta safnar upplýsingum um núverandi stöðu tækisins til að senda með tölvupósti. Það tekur smástund frá því villutilkynningin er ræst og þar til hún er tilbúin til sendingar – sýndu biðlund."</string>
    -@@ -1076,6 +1077,17 @@
    -     <skip />
    -     <string name="wifi_no_internet" msgid="8451173622563841546">"Wi-Fi netið er ekki með tengingu við internetið"</string>
    -     <string name="wifi_no_internet_detailed" msgid="8083079241212301741">"Ýttu til að sjá valkosti"</string>
    -+    <string name="network_switch_metered" msgid="4671730921726992671">"Skipt yfir á <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
    -+    <string name="network_switch_metered_detail" msgid="5325661434777870353">"Tækið notar <xliff:g id="NEW_NETWORK">%1$s</xliff:g> þegar <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> er ekki með internetaðgang. Gjöld geta átt við."</string>
    -+    <string name="network_switch_metered_toast" msgid="5779283181685974304">"Skipt úr <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> yfir í <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
    -+  <string-array name="network_switch_type_name">
    -+    <item msgid="2952042958050315394">"farsímagögn"</item>
    -+    <item msgid="75483255295529161">"Wi-Fi"</item>
    -+    <item msgid="6862614801537202646">"Bluetooth"</item>
    -+    <item msgid="5447331121797802871">"Ethernet"</item>
    -+    <item msgid="8257233890381651999">"VPN"</item>
    -+  </string-array>
    -+    <string name="network_switch_type_name_unknown" msgid="4552612897806660656">"óþekkt tegund netkerfis"</string>
    -     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Ekki var hægt að tengjast Wi-Fi"</string>
    -     <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" er með lélegt netsamband."</string>
    -     <string name="wifi_connect_alert_title" msgid="8455846016001810172">"Leyfa tengingu?"</string>
    -@@ -1153,7 +1165,6 @@
    -     <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"Ýttu til að velja tungumál og útlit"</string>
    -     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" AÁBCDÐEÉFGHIÍJKLMNOÓPQRSTUÚVWXYÝZÞÆÖ"</string>
    -     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789AÁBCDÐEÉFGHIÍJKLMNOÓPQRSTUÚVWXYÝZÞÆÖ"</string>
    --    <string name="candidates_style" msgid="4333913089637062257"><u>"möguleikar"</u></string>
    -     <string name="ext_media_checking_notification_title" msgid="5734005953288045806">"Undirbýr <xliff:g id="NAME">%s</xliff:g>"</string>
    -     <string name="ext_media_checking_notification_message" msgid="4747432538578886744">"Leitar að villum"</string>
    -     <string name="ext_media_new_notification_message" msgid="7589986898808506239">"Nýtt <xliff:g id="NAME">%s</xliff:g> fannst"</string>
    -@@ -1232,8 +1243,9 @@
    -     <string name="vpn_text_long" msgid="4907843483284977618">"Tengt við <xliff:g id="SESSION">%s</xliff:g>. Ýttu til að hafa umsjón með netinu."</string>
    -     <string name="vpn_lockdown_connecting" msgid="6443438964440960745">"Sívirkt VPN tengist…"</string>
    -     <string name="vpn_lockdown_connected" msgid="8202679674819213931">"Sívirkt VPN tengt"</string>
    -+    <string name="vpn_lockdown_disconnected" msgid="4532298952570796327">"Sívirkt VPN aftengt"</string>
    -     <string name="vpn_lockdown_error" msgid="6009249814034708175">"Villa í sívirku VPN"</string>
    --    <string name="vpn_lockdown_config" msgid="4655589351146766608">"Ýttu til að stilla"</string>
    -+    <string name="vpn_lockdown_config" msgid="5099330695245008680">"Ýttu til að setja upp"</string>
    -     <string name="upload_file" msgid="2897957172366730416">"Velja skrá"</string>
    -     <string name="no_file_chosen" msgid="6363648562170759465">"Engin skrá valin"</string>
    -     <string name="reset" msgid="2448168080964209908">"Endurstilla"</string>
    -@@ -1317,7 +1329,7 @@
    -     <string name="storage_usb_drive_label" msgid="4501418548927759953">"USB-drif frá <xliff:g id="MANUFACTURER">%s</xliff:g>"</string>
    -     <string name="storage_usb" msgid="3017954059538517278">"USB-geymsla"</string>
    -     <string name="extract_edit_menu_button" msgid="8940478730496610137">"Breyta"</string>
    --    <string name="data_usage_warning_title" msgid="1955638862122232342">"Viðvörun vegna gagnanotkunar"</string>
    -+    <string name="data_usage_warning_title" msgid="3620440638180218181">"Viðvörun um gagnanotkun"</string>
    -     <string name="data_usage_warning_body" msgid="6660692274311972007">"Ýttu fyrir uppl. og stillingar"</string>
    -     <string name="data_usage_3g_limit_title" msgid="4361523876818447683">"Gagnahámarki 2G og 3G náð"</string>
    -     <string name="data_usage_4g_limit_title" msgid="4609566827219442376">"Gagnahámarki 4G náð"</string>
    -@@ -1636,6 +1648,7 @@
    -     <string name="search_language_hint" msgid="7042102592055108574">"Sláðu inn heiti tungumáls"</string>
    -     <string name="language_picker_section_suggested" msgid="8414489646861640885">"Tillögur"</string>
    -     <string name="language_picker_section_all" msgid="3097279199511617537">"Öll tungumál"</string>
    -+    <string name="region_picker_section_all" msgid="8966316787153001779">"Öll svæði"</string>
    -     <string name="locale_search_menu" msgid="2560710726687249178">"Leita"</string>
    -     <string name="work_mode_off_title" msgid="8954725060677558855">"Slökkt á vinnusniði"</string>
    -     <string name="work_mode_off_message" msgid="3286169091278094476">"Leyfa virkni vinnusniðs, m.a. forrita, samstillingar í bakgrunni og tengdra eiginleika."</string>
    -diff --git a/core/res/res/values-it/strings.xml b/core/res/res/values-it/strings.xml
    -index 9cd74dc..b82470f 100644
    ---- a/core/res/res/values-it/strings.xml
    -+++ b/core/res/res/values-it/strings.xml
    -@@ -214,6 +214,7 @@
    -     <string name="global_actions" product="default" msgid="2406416831541615258">"Opzioni telefono"</string>
    -     <string name="global_action_lock" msgid="2844945191792119712">"Blocco schermo"</string>
    -     <string name="global_action_power_off" msgid="4471879440839879722">"Spegni"</string>
    -+    <string name="global_action_emergency" msgid="7112311161137421166">"Emergenza"</string>
    -     <string name="global_action_bug_report" msgid="7934010578922304799">"Segnalazione di bug"</string>
    -     <string name="bugreport_title" msgid="2667494803742548533">"Apri segnalazione bug"</string>
    -     <string name="bugreport_message" msgid="398447048750350456">"Verranno raccolte informazioni sullo stato corrente del dispositivo che saranno inviate sotto forma di messaggio email. Passerà un po\' di tempo prima che la segnalazione di bug aperta sia pronta per essere inviata; ti preghiamo di avere pazienza."</string>
    -@@ -1076,6 +1077,17 @@
    -     <skip />
    -     <string name="wifi_no_internet" msgid="8451173622563841546">"Connessione Wi-Fi priva di accesso Internet"</string>
    -     <string name="wifi_no_internet_detailed" msgid="8083079241212301741">"Tocca per le opzioni"</string>
    -+    <string name="network_switch_metered" msgid="4671730921726992671">"Passato a <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
    -+    <string name="network_switch_metered_detail" msgid="5325661434777870353">"Il dispositivo utilizza <xliff:g id="NEW_NETWORK">%1$s</xliff:g> quando <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> non ha accesso a Internet. Potrebbero essere applicati costi."</string>
    -+    <string name="network_switch_metered_toast" msgid="5779283181685974304">"Passato da <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> a <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
    -+  <string-array name="network_switch_type_name">
    -+    <item msgid="2952042958050315394">"rete dati"</item>
    -+    <item msgid="75483255295529161">"Wi-Fi"</item>
    -+    <item msgid="6862614801537202646">"Bluetooth"</item>
    -+    <item msgid="5447331121797802871">"Ethernet"</item>
    -+    <item msgid="8257233890381651999">"VPN"</item>
    -+  </string-array>
    -+    <string name="network_switch_type_name_unknown" msgid="4552612897806660656">"tipo di rete sconosciuto"</string>
    -     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Impossibile connettersi alla rete Wi-Fi"</string>
    -     <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" ha una connessione Internet debole."</string>
    -     <string name="wifi_connect_alert_title" msgid="8455846016001810172">"Consentire la connessione?"</string>
    -@@ -1153,7 +1165,6 @@
    -     <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"Tocca per selezionare la lingua e il layout"</string>
    -     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
    -     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
    --    <string name="candidates_style" msgid="4333913089637062257"><u>"candidati"</u></string>
    -     <string name="ext_media_checking_notification_title" msgid="5734005953288045806">"Preparazione della <xliff:g id="NAME">%s</xliff:g>"</string>
    -     <string name="ext_media_checking_notification_message" msgid="4747432538578886744">"Ricerca errori"</string>
    -     <string name="ext_media_new_notification_message" msgid="7589986898808506239">"Nuova <xliff:g id="NAME">%s</xliff:g> rilevata"</string>
    -@@ -1232,8 +1243,9 @@
    -     <string name="vpn_text_long" msgid="4907843483284977618">"Collegata a <xliff:g id="SESSION">%s</xliff:g>. Tocca per gestire la rete."</string>
    -     <string name="vpn_lockdown_connecting" msgid="6443438964440960745">"Connessione a VPN sempre attiva…"</string>
    -     <string name="vpn_lockdown_connected" msgid="8202679674819213931">"VPN sempre attiva connessa"</string>
    -+    <string name="vpn_lockdown_disconnected" msgid="4532298952570796327">"VPN sempre attiva disconnessa"</string>
    -     <string name="vpn_lockdown_error" msgid="6009249814034708175">"Errore VPN sempre attiva"</string>
    --    <string name="vpn_lockdown_config" msgid="4655589351146766608">"Tocca per configurare"</string>
    -+    <string name="vpn_lockdown_config" msgid="5099330695245008680">"Tocca per configurare"</string>
    -     <string name="upload_file" msgid="2897957172366730416">"Scegli file"</string>
    -     <string name="no_file_chosen" msgid="6363648562170759465">"Nessun file è stato scelto"</string>
    -     <string name="reset" msgid="2448168080964209908">"Reimposta"</string>
    -@@ -1317,7 +1329,7 @@
    -     <string name="storage_usb_drive_label" msgid="4501418548927759953">"Unità USB <xliff:g id="MANUFACTURER">%s</xliff:g>"</string>
    -     <string name="storage_usb" msgid="3017954059538517278">"Archivio USB"</string>
    -     <string name="extract_edit_menu_button" msgid="8940478730496610137">"Modifica"</string>
    --    <string name="data_usage_warning_title" msgid="1955638862122232342">"Avviso sull\'utilizzo dei dati"</string>
    -+    <string name="data_usage_warning_title" msgid="3620440638180218181">"Avviso sull\'utilizzo dei dati"</string>
    -     <string name="data_usage_warning_body" msgid="6660692274311972007">"Tocca per uso e impostazioni."</string>
    -     <string name="data_usage_3g_limit_title" msgid="4361523876818447683">"Limite di dati 2G-3G raggiunto"</string>
    -     <string name="data_usage_4g_limit_title" msgid="4609566827219442376">"Limite di dati 4G raggiunto"</string>
    -@@ -1636,6 +1648,7 @@
    -     <string name="search_language_hint" msgid="7042102592055108574">"Digita nome lingua"</string>
    -     <string name="language_picker_section_suggested" msgid="8414489646861640885">"Suggerite"</string>
    -     <string name="language_picker_section_all" msgid="3097279199511617537">"Tutte le lingue"</string>
    -+    <string name="region_picker_section_all" msgid="8966316787153001779">"Tutte le aree geografiche"</string>
    -     <string name="locale_search_menu" msgid="2560710726687249178">"Cerca"</string>
    -     <string name="work_mode_off_title" msgid="8954725060677558855">"Modalità Lavoro DISATTIVATA"</string>
    -     <string name="work_mode_off_message" msgid="3286169091278094476">"Attiva il profilo di lavoro, incluse app, sincronizzazione in background e funzioni correlate."</string>
    -diff --git a/core/res/res/values-iw/strings.xml b/core/res/res/values-iw/strings.xml
    -index bebe027..36c5205 100644
    ---- a/core/res/res/values-iw/strings.xml
    -+++ b/core/res/res/values-iw/strings.xml
    -@@ -218,6 +218,7 @@
    -     <string name="global_actions" product="default" msgid="2406416831541615258">"אפשרויות טלפון"</string>
    -     <string name="global_action_lock" msgid="2844945191792119712">"נעילת מסך"</string>
    -     <string name="global_action_power_off" msgid="4471879440839879722">"כיבוי"</string>
    -+    <string name="global_action_emergency" msgid="7112311161137421166">"חירום"</string>
    -     <string name="global_action_bug_report" msgid="7934010578922304799">"דיווח על באג"</string>
    -     <string name="bugreport_title" msgid="2667494803742548533">"שלח דיווח על באג"</string>
    -     <string name="bugreport_message" msgid="398447048750350456">"פעולה זו תאסוף מידע על מצב המכשיר הנוכחי שלך על מנת לשלוח אותו כהודעת אימייל. היא תימשך זמן קצר מרגע פתיחת דיווח הבאג ועד לשליחת ההודעה בפועל. אנא המתן בסבלנות."</string>
    -@@ -1126,6 +1127,17 @@
    -     <skip />
    -     <string name="wifi_no_internet" msgid="8451173622563841546">"‏אין ל-Wi-Fi גישה לאינטרנט"</string>
    -     <string name="wifi_no_internet_detailed" msgid="8083079241212301741">"הקש לקבלת אפשרויות"</string>
    -+    <string name="network_switch_metered" msgid="4671730921726992671">"מעבר אל <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
    -+    <string name="network_switch_metered_detail" msgid="5325661434777870353">"המכשיר משתמש ברשת <xliff:g id="NEW_NETWORK">%1$s</xliff:g> כשלרשת <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> אין גישה לאינטרנט. עשויים לחול חיובים."</string>
    -+    <string name="network_switch_metered_toast" msgid="5779283181685974304">"עבר מרשת <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> לרשת <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
    -+  <string-array name="network_switch_type_name">
    -+    <item msgid="2952042958050315394">"נתונים סלולריים"</item>
    -+    <item msgid="75483255295529161">"Wi-Fi"</item>
    -+    <item msgid="6862614801537202646">"Bluetooth"</item>
    -+    <item msgid="5447331121797802871">"Ethernet"</item>
    -+    <item msgid="8257233890381651999">"VPN"</item>
    -+  </string-array>
    -+    <string name="network_switch_type_name_unknown" msgid="4552612897806660656">"סוג רשת לא מזוהה"</string>
    -     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"‏אין אפשרות להתחבר ל-Wi-Fi"</string>
    -     <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" אינו מחובר היטב לאינטרנט."</string>
    -     <string name="wifi_connect_alert_title" msgid="8455846016001810172">"האם להתיר את החיבור?"</string>
    -@@ -1203,7 +1215,6 @@
    -     <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"הקש כדי לבחור שפה ופריסה"</string>
    -     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
    -     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
    --    <string name="candidates_style" msgid="4333913089637062257"><u>"מועמדים"</u></string>
    -     <string name="ext_media_checking_notification_title" msgid="5734005953288045806">"הכנת <xliff:g id="NAME">%s</xliff:g>"</string>
    -     <string name="ext_media_checking_notification_message" msgid="4747432538578886744">"בודק אם יש שגיאות"</string>
    -     <string name="ext_media_new_notification_message" msgid="7589986898808506239">"זוהה <xliff:g id="NAME">%s</xliff:g> חדש"</string>
    -@@ -1282,8 +1293,9 @@
    -     <string name="vpn_text_long" msgid="4907843483284977618">"מחובר אל <xliff:g id="SESSION">%s</xliff:g>. הקש כדי לנהל את הרשת."</string>
    -     <string name="vpn_lockdown_connecting" msgid="6443438964440960745">"‏ה-VPN שמופעל תמיד, מתחבר..."</string>
    -     <string name="vpn_lockdown_connected" msgid="8202679674819213931">"‏ה-VPN שפועל תמיד, מחובר"</string>
    -+    <string name="vpn_lockdown_disconnected" msgid="4532298952570796327">"‏חיבור תמידי ל-VPN מנותק"</string>
    -     <string name="vpn_lockdown_error" msgid="6009249814034708175">"‏שגיאת VPN שמופעל תמיד"</string>
    --    <string name="vpn_lockdown_config" msgid="4655589351146766608">"הקש כדי להגדיר"</string>
    -+    <string name="vpn_lockdown_config" msgid="5099330695245008680">"הקש כדי להגדיר"</string>
    -     <string name="upload_file" msgid="2897957172366730416">"בחר קובץ"</string>
    -     <string name="no_file_chosen" msgid="6363648562170759465">"לא נבחר קובץ"</string>
    -     <string name="reset" msgid="2448168080964209908">"איפוס"</string>
    -@@ -1362,14 +1374,14 @@
    -     <string name="action_menu_overflow_description" msgid="2295659037509008453">"אפשרויות נוספות"</string>
    -     <string name="action_bar_home_description_format" msgid="7965984360903693903">"‏%1$s‏, %2$s"</string>
    -     <string name="action_bar_home_subtitle_description_format" msgid="6985546530471780727">"‏%1$s‏, %2$s‏, %3$s"</string>
    --    <string name="storage_internal" msgid="3570990907910199483">"אחסון משותף פנימי"</string>
    -+    <string name="storage_internal" msgid="3570990907910199483">"אחסון שיתוף פנימי"</string>
    -     <string name="storage_sd_card" msgid="3282948861378286745">"‏כרטיס SD"</string>
    -     <string name="storage_sd_card_label" msgid="6347111320774379257">"‏כרטיס SD של <xliff:g id="MANUFACTURER">%s</xliff:g>"</string>
    -     <string name="storage_usb_drive" msgid="6261899683292244209">"‏כונן USB"</string>
    -     <string name="storage_usb_drive_label" msgid="4501418548927759953">"‏כונן USB של <xliff:g id="MANUFACTURER">%s</xliff:g>"</string>
    -     <string name="storage_usb" msgid="3017954059538517278">"‏אחסון USB"</string>
    -     <string name="extract_edit_menu_button" msgid="8940478730496610137">"ערוך"</string>
    --    <string name="data_usage_warning_title" msgid="1955638862122232342">"אזהרת שימוש בנתונים"</string>
    -+    <string name="data_usage_warning_title" msgid="3620440638180218181">"התראה לשימוש בנתונים"</string>
    -     <string name="data_usage_warning_body" msgid="6660692274311972007">"הקש כדי להציג נתוני שימוש והגדרות."</string>
    -     <string name="data_usage_3g_limit_title" msgid="4361523876818447683">"‏הגעת למגבלת הנתונים של 2G-3G"</string>
    -     <string name="data_usage_4g_limit_title" msgid="4609566827219442376">"‏הגעת למגבלת הנתונים של 4G"</string>
    -@@ -1708,6 +1720,7 @@
    -     <string name="search_language_hint" msgid="7042102592055108574">"הקלד שם שפה"</string>
    -     <string name="language_picker_section_suggested" msgid="8414489646861640885">"הצעות"</string>
    -     <string name="language_picker_section_all" msgid="3097279199511617537">"כל השפות"</string>
    -+    <string name="region_picker_section_all" msgid="8966316787153001779">"כל האזורים"</string>
    -     <string name="locale_search_menu" msgid="2560710726687249178">"חיפוש"</string>
    -     <string name="work_mode_off_title" msgid="8954725060677558855">"מצב העבודה כבוי"</string>
    -     <string name="work_mode_off_message" msgid="3286169091278094476">"אפשר לפרופיל העבודה לפעול, כולל אפליקציות, סנכרון ברקע ותכונות קשורות."</string>
    -diff --git a/core/res/res/values-ja/strings.xml b/core/res/res/values-ja/strings.xml
    -index b2a7bd2..5550900 100644
    ---- a/core/res/res/values-ja/strings.xml
    -+++ b/core/res/res/values-ja/strings.xml
    -@@ -214,6 +214,7 @@
    -     <string name="global_actions" product="default" msgid="2406416831541615258">"携帯電話オプション"</string>
    -     <string name="global_action_lock" msgid="2844945191792119712">"画面ロック"</string>
    -     <string name="global_action_power_off" msgid="4471879440839879722">"電源を切る"</string>
    -+    <string name="global_action_emergency" msgid="7112311161137421166">"緊急通報"</string>
    -     <string name="global_action_bug_report" msgid="7934010578922304799">"バグレポート"</string>
    -     <string name="bugreport_title" msgid="2667494803742548533">"バグレポートを取得"</string>
    -     <string name="bugreport_message" msgid="398447048750350456">"現在の端末の状態に関する情報が収集され、その内容がメールで送信されます。バグレポートが開始してから送信可能な状態となるまでには多少の時間がかかりますのでご了承ください。"</string>
    -@@ -374,7 +375,7 @@
    -     <string name="permdesc_callPhone" msgid="3740797576113760827">"電話番号への自動発信をアプリに許可します。これにより、予期せぬ発信や料金が発生する可能性があります。なお、緊急通報番号への発信は許可されません。悪意のあるアプリが確認なしで発信し、料金が発生する恐れがあります。"</string>
    -     <string name="permlab_accessImsCallService" msgid="3574943847181793918">"IMS通話サービスへのアクセス"</string>
    -     <string name="permdesc_accessImsCallService" msgid="8992884015198298775">"IMSサービスがユーザー操作なしで電話をかけることをアプリに許可します。"</string>
    --    <string name="permlab_readPhoneState" msgid="9178228524507610486">"端末のステータスとIDの読み取り"</string>
    -+    <string name="permlab_readPhoneState" msgid="9178228524507610486">"端末情報と ID の読み取り"</string>
    -     <string name="permdesc_readPhoneState" msgid="1639212771826125528">"端末の電話機能へのアクセスをアプリに許可します。これにより、電話番号、端末ID、通話中かどうか、通話相手の電話番号をアプリから特定できるようになります。"</string>
    -     <string name="permlab_wakeLock" product="tablet" msgid="1531731435011495015">"タブレットのスリープを無効化"</string>
    -     <string name="permlab_wakeLock" product="tv" msgid="2601193288949154131">"テレビのスリープを無効化"</string>
    -@@ -511,8 +512,8 @@
    -     <string name="permdesc_bindCarrierMessagingService" msgid="2762882888502113944">"携帯通信会社のSMSサービスのトップレベルインターフェースにバインドすることを所有者に許可します。通常のアプリでは不要です。"</string>
    -     <string name="permlab_bindCarrierServices" msgid="3233108656245526783">"携帯通信会社のサービスへのバインド"</string>
    -     <string name="permdesc_bindCarrierServices" msgid="1391552602551084192">"携帯通信会社のサービスにバインドすることを所有者に許可します。通常のアプリでは不要です。"</string>
    --    <string name="permlab_access_notification_policy" msgid="4247510821662059671">"[通知を非表示]へのアクセス"</string>
    --    <string name="permdesc_access_notification_policy" msgid="3296832375218749580">"[通知を非表示]の設定の読み取りと書き込みをアプリに許可します。"</string>
    -+    <string name="permlab_access_notification_policy" msgid="4247510821662059671">"マナーモードへのアクセス"</string>
    -+    <string name="permdesc_access_notification_policy" msgid="3296832375218749580">"マナーモード設定の読み取りと書き込みをアプリに許可します。"</string>
    -     <string name="policylab_limitPassword" msgid="4497420728857585791">"パスワードルールの設定"</string>
    -     <string name="policydesc_limitPassword" msgid="2502021457917874968">"画面ロックのパスワードとPINの長さと使用できる文字を制御します。"</string>
    -     <string name="policylab_watchLogin" msgid="914130646942199503">"画面ロック解除試行の監視"</string>
    -@@ -1076,6 +1077,17 @@
    -     <skip />
    -     <string name="wifi_no_internet" msgid="8451173622563841546">"Wi-Fiはインターネットに接続していません"</string>
    -     <string name="wifi_no_internet_detailed" msgid="8083079241212301741">"タップしてその他のオプションを表示"</string>
    -+    <string name="network_switch_metered" msgid="4671730921726992671">"「<xliff:g id="NETWORK_TYPE">%1$s</xliff:g>」に切り替えました"</string>
    -+    <string name="network_switch_metered_detail" msgid="5325661434777870353">"端末で「<xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g>」によるインターネット接続ができない場合に「<xliff:g id="NEW_NETWORK">%1$s</xliff:g>」を使用します。通信料が発生することがあります。"</string>
    -+    <string name="network_switch_metered_toast" msgid="5779283181685974304">"「<xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g>」から「<xliff:g id="NEW_NETWORK">%2$s</xliff:g>」に切り替えました"</string>
    -+  <string-array name="network_switch_type_name">
    -+    <item msgid="2952042958050315394">"モバイルデータ"</item>
    -+    <item msgid="75483255295529161">"Wi-Fi"</item>
    -+    <item msgid="6862614801537202646">"Bluetooth"</item>
    -+    <item msgid="5447331121797802871">"イーサネット"</item>
    -+    <item msgid="8257233890381651999">"VPN"</item>
    -+  </string-array>
    -+    <string name="network_switch_type_name_unknown" msgid="4552612897806660656">"不明なネットワーク タイプ"</string>
    -     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Wi-Fiに接続できませんでした"</string>
    -     <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" はインターネット接続に問題があります。"</string>
    -     <string name="wifi_connect_alert_title" msgid="8455846016001810172">"接続を許可しますか?"</string>
    -@@ -1153,7 +1165,6 @@
    -     <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"タップして言語とレイアウトを選択してください"</string>
    -     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
    -     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
    --    <string name="candidates_style" msgid="4333913089637062257"><u>"候補"</u></string>
    -     <string name="ext_media_checking_notification_title" msgid="5734005953288045806">"<xliff:g id="NAME">%s</xliff:g>を準備中"</string>
    -     <string name="ext_media_checking_notification_message" msgid="4747432538578886744">"エラーを確認中"</string>
    -     <string name="ext_media_new_notification_message" msgid="7589986898808506239">"新しい<xliff:g id="NAME">%s</xliff:g>が検出されました"</string>
    -@@ -1232,8 +1243,9 @@
    -     <string name="vpn_text_long" msgid="4907843483284977618">"<xliff:g id="SESSION">%s</xliff:g>に接続しました。ネットワークを管理するにはタップしてください。"</string>
    -     <string name="vpn_lockdown_connecting" msgid="6443438964440960745">"VPNに常時接続しています…"</string>
    -     <string name="vpn_lockdown_connected" msgid="8202679674819213931">"VPNに常時接続しました"</string>
    -+    <string name="vpn_lockdown_disconnected" msgid="4532298952570796327">"常時接続 VPN の接続を解除しました"</string>
    -     <string name="vpn_lockdown_error" msgid="6009249814034708175">"常時接続VPNのエラー"</string>
    --    <string name="vpn_lockdown_config" msgid="4655589351146766608">"タップして設定"</string>
    -+    <string name="vpn_lockdown_config" msgid="5099330695245008680">"設定するにはタップします"</string>
    -     <string name="upload_file" msgid="2897957172366730416">"ファイルを選択"</string>
    -     <string name="no_file_chosen" msgid="6363648562170759465">"ファイルが選択されていません"</string>
    -     <string name="reset" msgid="2448168080964209908">"リセット"</string>
    -@@ -1317,7 +1329,7 @@
    -     <string name="storage_usb_drive_label" msgid="4501418548927759953">"<xliff:g id="MANUFACTURER">%s</xliff:g>製USBドライブ"</string>
    -     <string name="storage_usb" msgid="3017954059538517278">"USBストレージ"</string>
    -     <string name="extract_edit_menu_button" msgid="8940478730496610137">"編集"</string>
    --    <string name="data_usage_warning_title" msgid="1955638862122232342">"データ使用の警告"</string>
    -+    <string name="data_usage_warning_title" msgid="3620440638180218181">"データ使用量に関する通知"</string>
    -     <string name="data_usage_warning_body" msgid="6660692274311972007">"タップして使用状況と設定を表示します。"</string>
    -     <string name="data_usage_3g_limit_title" msgid="4361523876818447683">"2G~3Gデータの上限に達しました"</string>
    -     <string name="data_usage_4g_limit_title" msgid="4609566827219442376">"4Gデータの上限に達しました"</string>
    -@@ -1595,10 +1607,10 @@
    -     <string name="zen_mode_until" msgid="7336308492289875088">"<xliff:g id="FORMATTEDTIME">%1$s</xliff:g>まで"</string>
    -     <string name="zen_mode_alarm" msgid="9128205721301330797">"<xliff:g id="FORMATTEDTIME">%1$s</xliff:g>(次のアラーム)まで"</string>
    -     <string name="zen_mode_forever" msgid="7420011936770086993">"ユーザーがOFFにするまで"</string>
    --    <string name="zen_mode_forever_dnd" msgid="3792132696572189081">"[通知を非表示]をOFFにするまで"</string>
    -+    <string name="zen_mode_forever_dnd" msgid="3792132696572189081">"マナーモードを OFF にするまで"</string>
    -     <string name="zen_mode_rule_name_combination" msgid="191109939968076477">"<xliff:g id="FIRST">%1$s</xliff:g>/<xliff:g id="REST">%2$s</xliff:g>"</string>
    -     <string name="toolbar_collapse_description" msgid="2821479483960330739">"折りたたむ"</string>
    --    <string name="zen_mode_feature_name" msgid="5254089399895895004">"通知を非表示"</string>
    -+    <string name="zen_mode_feature_name" msgid="5254089399895895004">"マナーモード"</string>
    -     <string name="zen_mode_downtime_feature_name" msgid="2626974636779860146">"ダウンタイム"</string>
    -     <string name="zen_mode_default_weeknights_name" msgid="3081318299464998143">"平日の夜"</string>
    -     <string name="zen_mode_default_weekends_name" msgid="2786495801019345244">"週末"</string>
    -@@ -1636,6 +1648,7 @@
    -     <string name="search_language_hint" msgid="7042102592055108574">"言語名を入力"</string>
    -     <string name="language_picker_section_suggested" msgid="8414489646861640885">"言語の候補"</string>
    -     <string name="language_picker_section_all" msgid="3097279199511617537">"すべての言語"</string>
    -+    <string name="region_picker_section_all" msgid="8966316787153001779">"すべての地域"</string>
    -     <string name="locale_search_menu" msgid="2560710726687249178">"検索"</string>
    -     <string name="work_mode_off_title" msgid="8954725060677558855">"Work モード OFF"</string>
    -     <string name="work_mode_off_message" msgid="3286169091278094476">"仕事用プロファイルで、アプリ、バックグラウンド同期などの関連機能の使用を許可します。"</string>
    -diff --git a/core/res/res/values-ka-rGE/strings.xml b/core/res/res/values-ka-rGE/strings.xml
    -index 0295ea5..a8fed8b 100644
    ---- a/core/res/res/values-ka-rGE/strings.xml
    -+++ b/core/res/res/values-ka-rGE/strings.xml
    -@@ -214,6 +214,7 @@
    -     <string name="global_actions" product="default" msgid="2406416831541615258">"ტელეფონის პარამეტრები"</string>
    -     <string name="global_action_lock" msgid="2844945191792119712">"ეკრანის დაბლოკვა"</string>
    -     <string name="global_action_power_off" msgid="4471879440839879722">"კვების გამორთვა"</string>
    -+    <string name="global_action_emergency" msgid="7112311161137421166">"საგანგებო სამსახურები"</string>
    -     <string name="global_action_bug_report" msgid="7934010578922304799">"ხარვეზის შესახებ ანგარიში"</string>
    -     <string name="bugreport_title" msgid="2667494803742548533">"შექმენით შეცდომის ანგარიში"</string>
    -     <string name="bugreport_message" msgid="398447048750350456">"იგი შეაგროვებს ინფორმაციას თქვენი მოწყობილობის ამჟამინდელი მდგომარეობის შესახებ, რათა ის ელფოსტის შეტყობინების სახით გააგზავნოს. ხარვეზის ანგარიშის მომზადებასა და შეტყობინების გაგზავნას გარკვეული დრო სჭირდება. გთხოვთ, მოითმინოთ."</string>
    -@@ -1076,6 +1077,17 @@
    -     <skip />
    -     <string name="wifi_no_internet" msgid="8451173622563841546">"Wi-Fi-ს არ აქვს ინტერნეტზე წვდომა"</string>
    -     <string name="wifi_no_internet_detailed" msgid="8083079241212301741">"შეეხეთ ვარიანტების სანახავად"</string>
    -+    <string name="network_switch_metered" msgid="4671730921726992671">"ახლა გამოიყენება <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
    -+    <string name="network_switch_metered_detail" msgid="5325661434777870353">"თუ <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> ინტერნეტთან კავშირს დაკარგავს, მოწყობილობის მიერ <xliff:g id="NEW_NETWORK">%1$s</xliff:g> იქნება გამოყენებული, რამაც შეიძლება დამატებითი ხარჯები გამოიწვიოს"</string>
    -+    <string name="network_switch_metered_toast" msgid="5779283181685974304">"ახლა გამოიყენება <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> (გამოიყენებოდა <xliff:g id="NEW_NETWORK">%2$s</xliff:g>)"</string>
    -+  <string-array name="network_switch_type_name">
    -+    <item msgid="2952042958050315394">"მობილური ინტერნეტი"</item>
    -+    <item msgid="75483255295529161">"Wi-Fi"</item>
    -+    <item msgid="6862614801537202646">"Bluetooth"</item>
    -+    <item msgid="5447331121797802871">"Ethernet"</item>
    -+    <item msgid="8257233890381651999">"VPN"</item>
    -+  </string-array>
    -+    <string name="network_switch_type_name_unknown" msgid="4552612897806660656">"უცნობი ტიპის ქსელი"</string>
    -     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Wi-Fi-თან დაკავშირება ვერ მოხერხდა"</string>
    -     <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" აქვს ცუდი ინტერნეტ კავშირი."</string>
    -     <string name="wifi_connect_alert_title" msgid="8455846016001810172">"გსურთ კავშირის დაშვება?"</string>
    -@@ -1153,7 +1165,6 @@
    -     <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"შეეხეთ ენისა და განლაგების ასარჩევად"</string>
    -     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
    -     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
    --    <string name="candidates_style" msgid="4333913089637062257"><u>"კანდიდატები"</u></string>
    -     <string name="ext_media_checking_notification_title" msgid="5734005953288045806">"<xliff:g id="NAME">%s</xliff:g>-ის მომზადება"</string>
    -     <string name="ext_media_checking_notification_message" msgid="4747432538578886744">"შეცდომების შემოწმება"</string>
    -     <string name="ext_media_new_notification_message" msgid="7589986898808506239">"აღმოჩენილია ახალი <xliff:g id="NAME">%s</xliff:g>"</string>
    -@@ -1232,8 +1243,9 @@
    -     <string name="vpn_text_long" msgid="4907843483284977618">"მიერთებულია <xliff:g id="SESSION">%s</xliff:g>-ზე. შეეხეთ ქსელის სამართავად."</string>
    -     <string name="vpn_lockdown_connecting" msgid="6443438964440960745">"მიმდინარეობს მუდმივად ჩართული VPN-ის მიერთება…"</string>
    -     <string name="vpn_lockdown_connected" msgid="8202679674819213931">"მუდმივად ჩართული VPN-ის მიერთებულია"</string>
    -+    <string name="vpn_lockdown_disconnected" msgid="4532298952570796327">"მუდმივად ჩართული VPN გათიშულია"</string>
    -     <string name="vpn_lockdown_error" msgid="6009249814034708175">"შეცდომა მუდამ VPN-ზე"</string>
    --    <string name="vpn_lockdown_config" msgid="4655589351146766608">"შეეხეთ პარამეტრების კონფიგურაციისთვის"</string>
    -+    <string name="vpn_lockdown_config" msgid="5099330695245008680">"შეეხეთ დასაყენებლად"</string>
    -     <string name="upload_file" msgid="2897957172366730416">"ფაილის არჩევა"</string>
    -     <string name="no_file_chosen" msgid="6363648562170759465">"ფაილი არჩეული არ არის"</string>
    -     <string name="reset" msgid="2448168080964209908">"საწყისზე დაბრუნება"</string>
    -@@ -1317,7 +1329,7 @@
    -     <string name="storage_usb_drive_label" msgid="4501418548927759953">"<xliff:g id="MANUFACTURER">%s</xliff:g> USB დისკი"</string>
    -     <string name="storage_usb" msgid="3017954059538517278">"USB მეხსიერება"</string>
    -     <string name="extract_edit_menu_button" msgid="8940478730496610137">"რედაქტირება"</string>
    --    <string name="data_usage_warning_title" msgid="1955638862122232342">"ინტერნეტის გამოყენების გაფრთხილება"</string>
    -+    <string name="data_usage_warning_title" msgid="3620440638180218181">"მონაცემთა მოხმარების გაფრთხილება"</string>
    -     <string name="data_usage_warning_body" msgid="6660692274311972007">"შეეხეთ მოხმარებისა და პარამეტრების სანახავად."</string>
    -     <string name="data_usage_3g_limit_title" msgid="4361523876818447683">"2G-3G მონაცემთა ლიმიტი ამოიწურა"</string>
    -     <string name="data_usage_4g_limit_title" msgid="4609566827219442376">"4G მონაცემთა ლიმიტი ამოიწურა"</string>
    -@@ -1636,6 +1648,7 @@
    -     <string name="search_language_hint" msgid="7042102592055108574">"აკრიფეთ ენის სახელი"</string>
    -     <string name="language_picker_section_suggested" msgid="8414489646861640885">"რეკომენდებული"</string>
    -     <string name="language_picker_section_all" msgid="3097279199511617537">"ყველა ენა"</string>
    -+    <string name="region_picker_section_all" msgid="8966316787153001779">"ყველა რეგიონი"</string>
    -     <string name="locale_search_menu" msgid="2560710726687249178">"ძიება"</string>
    -     <string name="work_mode_off_title" msgid="8954725060677558855">"სამსახურის რეჟიმი გამორთულია"</string>
    -     <string name="work_mode_off_message" msgid="3286169091278094476">"სამსახურის პროფილის მუშაობის დაშვება, მათ შორის, აპების, ფონური სინქრონიზაციის და დაკავშირებული ფუნქციების."</string>
    -diff --git a/core/res/res/values-kk-rKZ/strings.xml b/core/res/res/values-kk-rKZ/strings.xml
    -index b5931c1..00264ad 100644
    ---- a/core/res/res/values-kk-rKZ/strings.xml
    -+++ b/core/res/res/values-kk-rKZ/strings.xml
    -@@ -214,6 +214,7 @@
    -     <string name="global_actions" product="default" msgid="2406416831541615258">"Телефон опциялары"</string>
    -     <string name="global_action_lock" msgid="2844945191792119712">"Экранды құлыптау"</string>
    -     <string name="global_action_power_off" msgid="4471879440839879722">"Өшіру"</string>
    -+    <string name="global_action_emergency" msgid="7112311161137421166">"Төтенше жағдай"</string>
    -     <string name="global_action_bug_report" msgid="7934010578922304799">"Вирус туралы хабарлау"</string>
    -     <string name="bugreport_title" msgid="2667494803742548533">"Қате туралы есеп құру"</string>
    -     <string name="bugreport_message" msgid="398447048750350456">"Құрылғының қазіргі күйі туралы ақпаратты жинап, электрондық хабармен жібереді. Есеп әзір болғанша біраз уақыт кетеді, шыдай тұрыңыз."</string>
    -@@ -1076,6 +1077,17 @@
    -     <skip />
    -     <string name="wifi_no_internet" msgid="8451173622563841546">"Wi-Fi желісінде интернет байланысы жоқ"</string>
    -     <string name="wifi_no_internet_detailed" msgid="8083079241212301741">"Опциялар үшін түртіңіз"</string>
    -+    <string name="network_switch_metered" msgid="4671730921726992671">"<xliff:g id="NETWORK_TYPE">%1$s</xliff:g> желісіне ауысты"</string>
    -+    <string name="network_switch_metered_detail" msgid="5325661434777870353">"Құрылғы <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> желісінде интернетпен байланыс жоғалған жағдайда <xliff:g id="NEW_NETWORK">%1$s</xliff:g> желісін пайдаланады. Деректер ақысы алынуы мүмкін."</string>
    -+    <string name="network_switch_metered_toast" msgid="5779283181685974304">"<xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> желісінен <xliff:g id="NEW_NETWORK">%2$s</xliff:g> желісіне ауысты"</string>
    -+  <string-array name="network_switch_type_name">
    -+    <item msgid="2952042958050315394">"ұялы дерек"</item>
    -+    <item msgid="75483255295529161">"Wi-Fi"</item>
    -+    <item msgid="6862614801537202646">"Bluetooth"</item>
    -+    <item msgid="5447331121797802871">"Ethernet"</item>
    -+    <item msgid="8257233890381651999">"VPN"</item>
    -+  </string-array>
    -+    <string name="network_switch_type_name_unknown" msgid="4552612897806660656">"желі түрі белгісіз"</string>
    -     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Wi-Fi желісіне қосыла алмады"</string>
    -     <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" Интернет байланысы нашар."</string>
    -     <string name="wifi_connect_alert_title" msgid="8455846016001810172">"Қосылуға рұқсат ету керек пе?"</string>
    -@@ -1153,7 +1165,6 @@
    -     <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"Тіл мен пернетақта схемасын таңдау үшін түртіңіз"</string>
    -     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
    -     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
    --    <string name="candidates_style" msgid="4333913089637062257"><u>"үміткерлер"</u></string>
    -     <string name="ext_media_checking_notification_title" msgid="5734005953288045806">"<xliff:g id="NAME">%s</xliff:g> дайындалуда"</string>
    -     <string name="ext_media_checking_notification_message" msgid="4747432538578886744">"Қателер тексерілуде"</string>
    -     <string name="ext_media_new_notification_message" msgid="7589986898808506239">"Жаңа <xliff:g id="NAME">%s</xliff:g> анықталды"</string>
    -@@ -1232,8 +1243,9 @@
    -     <string name="vpn_text_long" msgid="4907843483284977618">"<xliff:g id="SESSION">%s</xliff:g> жүйесіне жалғанған. Желіні басқару үшін түріңіз."</string>
    -     <string name="vpn_lockdown_connecting" msgid="6443438964440960745">"Әрқашан қосылған ВЖЖ жалғануда…"</string>
    -     <string name="vpn_lockdown_connected" msgid="8202679674819213931">"Әрқашан қосылған ВЖЖ жалғанған"</string>
    -+    <string name="vpn_lockdown_disconnected" msgid="4532298952570796327">"Әрқашан қосулы VPN желісі ажыратылды"</string>
    -     <string name="vpn_lockdown_error" msgid="6009249814034708175">"Әрқашан қосылған ВЖЖ қателігі"</string>
    --    <string name="vpn_lockdown_config" msgid="4655589351146766608">"Конфигурациялау үшін түртіңіз"</string>
    -+    <string name="vpn_lockdown_config" msgid="5099330695245008680">"Реттеу үшін түртіңіз"</string>
    -     <string name="upload_file" msgid="2897957172366730416">"Файлды таңдау"</string>
    -     <string name="no_file_chosen" msgid="6363648562170759465">"Ешқандай файл таңдалмаған"</string>
    -     <string name="reset" msgid="2448168080964209908">"Қайта реттеу"</string>
    -@@ -1317,7 +1329,7 @@
    -     <string name="storage_usb_drive_label" msgid="4501418548927759953">"<xliff:g id="MANUFACTURER">%s</xliff:g> USB дискі"</string>
    -     <string name="storage_usb" msgid="3017954059538517278">"USB жады"</string>
    -     <string name="extract_edit_menu_button" msgid="8940478730496610137">"Өзгерту"</string>
    --    <string name="data_usage_warning_title" msgid="1955638862122232342">"Дерекқор қолдануға қатысты ескерту"</string>
    -+    <string name="data_usage_warning_title" msgid="3620440638180218181">"Деректер трафигі туралы ескерту"</string>
    -     <string name="data_usage_warning_body" msgid="6660692274311972007">"Трафик пен параметрлерді көру үшін түртіңіз."</string>
    -     <string name="data_usage_3g_limit_title" msgid="4361523876818447683">"2G-3G деректер шегіне жеттіңіз"</string>
    -     <string name="data_usage_4g_limit_title" msgid="4609566827219442376">"4G деректер шегіне жеттіңіз"</string>
    -@@ -1636,6 +1648,7 @@
    -     <string name="search_language_hint" msgid="7042102592055108574">"Тіл атауын теріңіз"</string>
    -     <string name="language_picker_section_suggested" msgid="8414489646861640885">"Ұсынылған"</string>
    -     <string name="language_picker_section_all" msgid="3097279199511617537">"Барлық тілдер"</string>
    -+    <string name="region_picker_section_all" msgid="8966316787153001779">"Барлық аймақтар"</string>
    -     <string name="locale_search_menu" msgid="2560710726687249178">"Іздеу"</string>
    -     <string name="work_mode_off_title" msgid="8954725060677558855">"Жұмыс режимі ӨШІРУЛІ"</string>
    -     <string name="work_mode_off_message" msgid="3286169091278094476">"Жұмыс профиліне, соның ішінде, қолданбаларға, фондық синхрондауға және қатысты мүмкіндіктерге жұмыс істеуге рұқсат ету."</string>
    -diff --git a/core/res/res/values-km-rKH/strings.xml b/core/res/res/values-km-rKH/strings.xml
    -index 71f8cba..feaef82 100644
    ---- a/core/res/res/values-km-rKH/strings.xml
    -+++ b/core/res/res/values-km-rKH/strings.xml
    -@@ -214,6 +214,7 @@
    -     <string name="global_actions" product="default" msgid="2406416831541615258">"ជម្រើស​ទូរស័ព្ទ"</string>
    -     <string name="global_action_lock" msgid="2844945191792119712">"ចាក់​សោ​អេក្រង់"</string>
    -     <string name="global_action_power_off" msgid="4471879440839879722">"បិទ"</string>
    -+    <string name="global_action_emergency" msgid="7112311161137421166">"អាសន្ន"</string>
    -     <string name="global_action_bug_report" msgid="7934010578922304799">"របាយការណ៍​កំហុស"</string>
    -     <string name="bugreport_title" msgid="2667494803742548533">"យក​របាយការណ៍​កំហុស"</string>
    -     <string name="bugreport_message" msgid="398447048750350456">"វា​នឹង​​ប្រមូល​ព័ត៌មាន​អំពី​ស្ថានភាព​ឧបករណ៍​របស់​អ្នក ដើម្បី​ផ្ញើ​ជា​សារ​អ៊ីមែល។ វា​នឹង​ចំណាយ​ពេល​តិច​ពី​ពេល​ចាប់ផ្ដើម​របាយការណ៍​រហូត​ដល់​ពេល​វា​រួចរាល់​ដើម្បី​ផ្ញើ សូម​អត់ធ្មត់។"</string>
    -@@ -1078,6 +1079,17 @@
    -     <skip />
    -     <string name="wifi_no_internet" msgid="8451173622563841546">"Wi-Fi មិនមានអ៊ិនធឺណិតនោះទេ"</string>
    -     <string name="wifi_no_internet_detailed" msgid="8083079241212301741">"ប៉ះសម្រាប់ជម្រើស"</string>
    -+    <string name="network_switch_metered" msgid="4671730921726992671">"បានប្តូរទៅ <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
    -+    <string name="network_switch_metered_detail" msgid="5325661434777870353">"ឧបករណ៍ប្រើ <xliff:g id="NEW_NETWORK">%1$s</xliff:g> នៅពេលដែល <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> គ្មានការតភ្ជាប់អ៊ីនធឺណិត។ អាចគិតប្រាក់លើការប្រើប្រាស់ទិន្នន័យ។"</string>
    -+    <string name="network_switch_metered_toast" msgid="5779283181685974304">"បានប្តូរពី <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> ទៅ <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
    -+  <string-array name="network_switch_type_name">
    -+    <item msgid="2952042958050315394">"ទិន្នន័យចល័ត"</item>
    -+    <item msgid="75483255295529161">"Wi-Fi"</item>
    -+    <item msgid="6862614801537202646">"ប៊្លូធូស"</item>
    -+    <item msgid="5447331121797802871">"អ៊ីសឺរណិត"</item>
    -+    <item msgid="8257233890381651999">"VPN"</item>
    -+  </string-array>
    -+    <string name="network_switch_type_name_unknown" msgid="4552612897806660656">"ប្រភេទបណ្តាញមិនស្គាល់"</string>
    -     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"មិន​​អាច​តភ្ជាប់​វ៉ាយហ្វាយ"</string>
    -     <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" មាន​ការ​តភ្ជាប់​អ៊ីនធឺណិត​មិន​ល្អ។"</string>
    -     <string name="wifi_connect_alert_title" msgid="8455846016001810172">"អនុញ្ញាត​ភ្ជាប់?"</string>
    -@@ -1155,7 +1167,6 @@
    -     <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"ប៉ះដើម្បីជ្រើសភាសា និងប្លង់"</string>
    -     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
    -     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
    --    <string name="candidates_style" msgid="4333913089637062257"><u>"បេក្ខជន"</u></string>
    -     <string name="ext_media_checking_notification_title" msgid="5734005953288045806">"កំពុងរៀបចំ <xliff:g id="NAME">%s</xliff:g>"</string>
    -     <string name="ext_media_checking_notification_message" msgid="4747432538578886744">"កំពុងពិនិត្យរកកំហុស"</string>
    -     <string name="ext_media_new_notification_message" msgid="7589986898808506239">"បានរកឃើញ <xliff:g id="NAME">%s</xliff:g> ថ្មី"</string>
    -@@ -1234,8 +1245,9 @@
    -     <string name="vpn_text_long" msgid="4907843483284977618">"បាន​ភ្ជាប់​ទៅ <xliff:g id="SESSION">%s</xliff:g> ។ ប៉ះ ដើម្បី​គ្រប់គ្រង​បណ្ដាញ។"</string>
    -     <string name="vpn_lockdown_connecting" msgid="6443438964440960745">"បើក​ការ​តភ្ជាប់ VPN ជា​និច្ច..។"</string>
    -     <string name="vpn_lockdown_connected" msgid="8202679674819213931">"ភ្ជាប់ VPN ជា​និច្ច"</string>
    -+    <string name="vpn_lockdown_disconnected" msgid="4532298952570796327">"បានផ្តាច់ VPN ដែលបើកជានិច្ច"</string>
    -     <string name="vpn_lockdown_error" msgid="6009249814034708175">"បើក​កំហុស VPN ជា​និច្ច"</string>
    --    <string name="vpn_lockdown_config" msgid="4655589351146766608">"ប៉ះដើម្បីកំណត់រចនាសម្ព័ន្ធ"</string>
    -+    <string name="vpn_lockdown_config" msgid="5099330695245008680">"ប៉ះដើម្បីដំឡើង"</string>
    -     <string name="upload_file" msgid="2897957172366730416">"ជ្រើស​​ឯកសារ"</string>
    -     <string name="no_file_chosen" msgid="6363648562170759465">"គ្មាន​ឯកសារ​បាន​ជ្រើស"</string>
    -     <string name="reset" msgid="2448168080964209908">"កំណត់​ឡើងវិញ"</string>
    -@@ -1319,7 +1331,7 @@
    -     <string name="storage_usb_drive_label" msgid="4501418548927759953">"ឧបករណ៍ផ្ទុក USB <xliff:g id="MANUFACTURER">%s</xliff:g>"</string>
    -     <string name="storage_usb" msgid="3017954059538517278">"ឧបករណ៍​ផ្ទុក​យូអេសប៊ី"</string>
    -     <string name="extract_edit_menu_button" msgid="8940478730496610137">"កែសម្រួល​"</string>
    --    <string name="data_usage_warning_title" msgid="1955638862122232342">"ការព្រមាន​ប្រើ​ទិន្នន័យ"</string>
    -+    <string name="data_usage_warning_title" msgid="3620440638180218181">"ការព្រមានអំពីការប្រើទិន្នន័យ"</string>
    -     <string name="data_usage_warning_body" msgid="6660692274311972007">"ប៉ះដើម្បីមើលការប្រើប្រាស់ និងការកំណត់"</string>
    -     <string name="data_usage_3g_limit_title" msgid="4361523876818447683">"បាន​ដល់​ដែន​កំណត់​ទិន្នន័យ 2G-3G"</string>
    -     <string name="data_usage_4g_limit_title" msgid="4609566827219442376">"បាន​ដល់​ដែន​កំណត់​ទិន្នន័យ 4G"</string>
    -@@ -1638,6 +1650,7 @@
    -     <string name="search_language_hint" msgid="7042102592055108574">"វាយបញ្ចូលឈ្មោះភាសា"</string>
    -     <string name="language_picker_section_suggested" msgid="8414489646861640885">"បាន​ស្នើ"</string>
    -     <string name="language_picker_section_all" msgid="3097279199511617537">"ភាសាទាំងអស់"</string>
    -+    <string name="region_picker_section_all" msgid="8966316787153001779">"តំបន់ទាំងអស់"</string>
    -     <string name="locale_search_menu" msgid="2560710726687249178">"ស្វែងរក"</string>
    -     <string name="work_mode_off_title" msgid="8954725060677558855">"របៀបការងារបានបិទ"</string>
    -     <string name="work_mode_off_message" msgid="3286169091278094476">"អនុញ្ញាតឲ្យប្រវត្តិរូបការងារដំណើរការ ដោយរាប់បញ្ចូលទាំងកម្មវិធី ការធ្វើសមកាលកម្មផ្ទៃខាងក្រោយ និងលក្ខណៈពិសេសដែលពាក់ព័ន្ធ។"</string>
    -diff --git a/core/res/res/values-kn-rIN/strings.xml b/core/res/res/values-kn-rIN/strings.xml
    -index 770af19..7cb97a7 100644
    ---- a/core/res/res/values-kn-rIN/strings.xml
    -+++ b/core/res/res/values-kn-rIN/strings.xml
    -@@ -172,7 +172,7 @@
    -       <item quantity="one">ಪ್ರಮಾಣಪತ್ರ ಅಂಗೀಕಾರಗಳನ್ನು ಸ್ಥಾಪಿಸಲಾಗಿದೆ</item>
    -       <item quantity="other">ಪ್ರಮಾಣಪತ್ರ ಅಂಗೀಕಾರಗಳನ್ನು ಸ್ಥಾಪಿಸಲಾಗಿದೆ</item>
    -     </plurals>
    --    <string name="ssl_ca_cert_noti_by_unknown" msgid="4475437862189850602">"ಅಜ್ಞಾತ ಥರ್ಡ್ ಪಾರ್ಟಿಯ ಪ್ರಕಾರ"</string>
    -+    <string name="ssl_ca_cert_noti_by_unknown" msgid="4475437862189850602">"ಅಪರಿಚಿತ ಥರ್ಡ್ ಪಾರ್ಟಿಯ ಪ್ರಕಾರ"</string>
    -     <string name="ssl_ca_cert_noti_by_administrator" msgid="550758088185764312">"ನಿಮ್ಮ ಕೆಲಸದ ಪ್ರೊಫೈಲ್ ನಿರ್ವಾಹಕರಿಂದ"</string>
    -     <string name="ssl_ca_cert_noti_managed" msgid="4030263497686867141">"<xliff:g id="MANAGING_DOMAIN">%s</xliff:g> ಪ್ರಕಾರ"</string>
    -     <string name="work_profile_deleted" msgid="5005572078641980632">"ಕೆಲಸದ ಪ್ರೊಫೈಲ್ ಅನ್ನು ಅಳಿಸಲಾಗಿದೆ"</string>
    -@@ -214,6 +214,7 @@
    -     <string name="global_actions" product="default" msgid="2406416831541615258">"ಫೋನ್ ಆಯ್ಕೆಗಳು"</string>
    -     <string name="global_action_lock" msgid="2844945191792119712">"ಸ್ಕ್ರೀನ್ ಲಾಕ್"</string>
    -     <string name="global_action_power_off" msgid="4471879440839879722">"ಪವರ್ ಆಫ್ ಮಾಡು"</string>
    -+    <string name="global_action_emergency" msgid="7112311161137421166">"ತುರ್ತು"</string>
    -     <string name="global_action_bug_report" msgid="7934010578922304799">"ದೋಷದ ವರದಿ"</string>
    -     <string name="bugreport_title" msgid="2667494803742548533">"ದೋಷ ವರದಿ ರಚಿಸಿ"</string>
    -     <string name="bugreport_message" msgid="398447048750350456">"ನಿಮ್ಮ ಸಾಧನದ ಪ್ರಸ್ತುತ ಸ್ಥಿತಿಯ ಕುರಿತು ಮಾಹಿತಿಯನ್ನು ಸಂಗ್ರಹಿಸಿಕೊಳ್ಳುವುದರ ಜೊತೆ ಇ-ಮೇಲ್ ರೂಪದಲ್ಲಿ ನಿಮಗೆ ರವಾನಿಸುತ್ತದೆ. ಇದು ದೋಷ ವರದಿಯನ್ನು ಪ್ರಾರಂಭಿಸಿದ ಸಮಯದಿಂದ ಅದನ್ನು ಕಳುಹಿಸುವವರೆಗೆ ಸ್ವಲ್ಪ ಸಮಯವನ್ನು ತೆಗೆದುಕೊಳ್ಳುತ್ತದೆ; ದಯವಿಟ್ಟು ತಾಳ್ಮೆಯಿಂದಿರಿ."</string>
    -@@ -814,9 +815,9 @@
    -     <string name="menu_space_shortcut_label" msgid="2410328639272162537">"space"</string>
    -     <string name="menu_enter_shortcut_label" msgid="2743362785111309668">"enter"</string>
    -     <string name="menu_delete_shortcut_label" msgid="3658178007202748164">"ಅಳಿಸು"</string>
    --    <string name="search_go" msgid="8298016669822141719">"ಹುಡುಕು"</string>
    -+    <string name="search_go" msgid="8298016669822141719">"ಹುಡುಕಿ"</string>
    -     <string name="search_hint" msgid="1733947260773056054">"ಹುಡುಕಿ…"</string>
    --    <string name="searchview_description_search" msgid="6749826639098512120">"ಹುಡುಕು"</string>
    -+    <string name="searchview_description_search" msgid="6749826639098512120">"ಹುಡುಕಿ"</string>
    -     <string name="searchview_description_query" msgid="5911778593125355124">"ಪ್ರಶ್ನೆಯನ್ನು ಹುಡುಕಿ"</string>
    -     <string name="searchview_description_clear" msgid="1330281990951833033">"ಪ್ರಶ್ನೆಯನ್ನು ತೆರವುಗೊಳಿಸು"</string>
    -     <string name="searchview_description_submit" msgid="2688450133297983542">"ಪ್ರಶ್ನೆಯನ್ನು ಸಲ್ಲಿಸು"</string>
    -@@ -979,8 +980,8 @@
    -     <string name="whichSendToApplication" msgid="8272422260066642057">"ಇದನ್ನು ಬಳಸಿಕೊಂಡು ಕಳುಹಿಸಿ"</string>
    -     <string name="whichSendToApplicationNamed" msgid="7768387871529295325">"%1$s ಬಳಸಿಕೊಂಡು ಕಳುಹಿಸಿ"</string>
    -     <string name="whichSendToApplicationLabel" msgid="8878962419005813500">"ಕಳುಹಿಸು"</string>
    --    <string name="whichHomeApplication" msgid="4307587691506919691">"ಹೋಮ್‌ ಅಪ್ಲಿಕೇಶನ್‌  ಆಯ್ಕೆಮಾಡಿ"</string>
    --    <string name="whichHomeApplicationNamed" msgid="4493438593214760979">"ಹೋಮ್‌ ಎಂಬಂತೆ %1$s ಅನ್ನು ಬಳಸಿ"</string>
    -+    <string name="whichHomeApplication" msgid="4307587691506919691">"ಮುಖಪುಟ‌ ಅಪ್ಲಿಕೇಶನ್‌  ಆಯ್ಕೆಮಾಡಿ"</string>
    -+    <string name="whichHomeApplicationNamed" msgid="4493438593214760979">"ಮುಖಪುಟ‌ ಎಂಬಂತೆ %1$s ಅನ್ನು ಬಳಸಿ"</string>
    -     <string name="whichHomeApplicationLabel" msgid="809529747002918649">"ಚಿತ್ರ ಕ್ಯಾಪ್ಚರ್ ಮಾಡಿ"</string>
    -     <string name="whichImageCaptureApplication" msgid="3680261417470652882">"ಇದರ ಜೊತೆಗೆ ಚಿತ್ರ ಕ್ಯಾಪ್ಚರ್ ಮಾಡಿ"</string>
    -     <string name="whichImageCaptureApplicationNamed" msgid="8619384150737825003">"%1$s ಜೊತೆ ಚಿತ್ರ ಕ್ಯಾಪ್ಚರ್ ಮಾಡಿ"</string>
    -@@ -1061,7 +1062,7 @@
    -     <string name="ringtone_default_with_actual" msgid="8129563480895990372">"ಡಿಫಾಲ್ಟ್ ರಿಂಗ್‌ಟೋನ್ (<xliff:g id="ACTUAL_RINGTONE">%1$s</xliff:g>)"</string>
    -     <string name="ringtone_silent" msgid="7937634392408977062">"ಯಾವುದೂ ಇಲ್ಲ"</string>
    -     <string name="ringtone_picker_title" msgid="3515143939175119094">"ರಿಂಗ್‌ಟೋನ್‌ಗಳು"</string>
    --    <string name="ringtone_unknown" msgid="5477919988701784788">"ಅಜ್ಞಾತ ರಿಂಗ್‌ಟೋನ್"</string>
    -+    <string name="ringtone_unknown" msgid="5477919988701784788">"ಅಪರಿಚಿತ ರಿಂಗ್‌ಟೋನ್"</string>
    -     <plurals name="wifi_available" formatted="false" msgid="7900333017752027322">
    -       <item quantity="one">ವೈ-ಫೈ ನೆಟ್‌ವರ್ಕ್‌ಗಳು ಲಭ್ಯವಿವೆ</item>
    -       <item quantity="other">ವೈ-ಫೈ ನೆಟ್‌ವರ್ಕ್‌ಗಳು ಲಭ್ಯವಿವೆ</item>
    -@@ -1076,6 +1077,17 @@
    -     <skip />
    -     <string name="wifi_no_internet" msgid="8451173622563841546">"ವೈ-ಫೈ ಯಾವುದೇ ಇಂಟರ್ನೆಟ್ ಪ್ರವೇಶವನ್ನು ಹೊಂದಿಲ್ಲ"</string>
    -     <string name="wifi_no_internet_detailed" msgid="8083079241212301741">"ಆಯ್ಕೆಗಳಿಗೆ ಟ್ಯಾಪ್ ಮಾಡಿ"</string>
    -+    <string name="network_switch_metered" msgid="4671730921726992671">"<xliff:g id="NETWORK_TYPE">%1$s</xliff:g> ಗೆ ಬದಲಾಯಿಸಲಾಗಿದೆ"</string>
    -+    <string name="network_switch_metered_detail" msgid="5325661434777870353">"<xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> ಇಂಟರ್ನೆಟ್ ಪ್ರವೇಶ ಹೊಂದಿಲ್ಲದಿರುವಾಗ, ಸಾಧನವು <xliff:g id="NEW_NETWORK">%1$s</xliff:g> ಬಳಸುತ್ತದೆ. ಶುಲ್ಕಗಳು ಅನ್ವಯವಾಗಬಹುದು."</string>
    -+    <string name="network_switch_metered_toast" msgid="5779283181685974304">"<xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> ರಿಂದ <xliff:g id="NEW_NETWORK">%2$s</xliff:g> ಗೆ ಬದಲಾಯಿಸಲಾಗಿದೆ"</string>
    -+  <string-array name="network_switch_type_name">
    -+    <item msgid="2952042958050315394">"ಸೆಲ್ಯುಲರ್ ಡೇಟಾ"</item>
    -+    <item msgid="75483255295529161">"ವೈ-ಫೈ"</item>
    -+    <item msgid="6862614801537202646">"ಬ್ಲೂಟೂತ್‌"</item>
    -+    <item msgid="5447331121797802871">"ಇಥರ್ನೆಟ್"</item>
    -+    <item msgid="8257233890381651999">"VPN"</item>
    -+  </string-array>
    -+    <string name="network_switch_type_name_unknown" msgid="4552612897806660656">"ಅಪರಿಚಿತ ನೆಟ್‌ವರ್ಕ್ ಪ್ರಕಾರ"</string>
    -     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"ವೈ-ಫೈ ಗೆ ಸಂಪರ್ಕಿಸಲು ಸಾಧ್ಯವಾಗುತ್ತಿಲ್ಲ"</string>
    -     <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" ಕಳಪೆ ಇಂಟರ್ನೆಟ್ ಸಂಪರ್ಕವನ್ನು ಹೊಂದಿದೆ."</string>
    -     <string name="wifi_connect_alert_title" msgid="8455846016001810172">"ಸಂಪರ್ಕವನ್ನು ಅನುಮತಿಸುವುದೇ?"</string>
    -@@ -1153,7 +1165,6 @@
    -     <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"ಭಾಷೆ ಮತ್ತು ವಿನ್ಯಾಸವನ್ನು ಆಯ್ಕೆ ಮಾಡಲು ಟ್ಯಾಪ್ ಮಾಡಿ"</string>
    -     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
    -     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
    --    <string name="candidates_style" msgid="4333913089637062257"><u>"ಅಭ್ಯರ್ಥಿಗಳು"</u></string>
    -     <string name="ext_media_checking_notification_title" msgid="5734005953288045806">"<xliff:g id="NAME">%s</xliff:g> ಅನ್ನು ಸಿದ್ಧಪಡಿಸಲಾಗುತ್ತಿದೆ"</string>
    -     <string name="ext_media_checking_notification_message" msgid="4747432538578886744">"ದೋಷಗಳನ್ನು ಪರಿಶೀಲಿಸಲಾಗುತ್ತಿದೆ"</string>
    -     <string name="ext_media_new_notification_message" msgid="7589986898808506239">"ಹೊಸ <xliff:g id="NAME">%s</xliff:g> ಪತ್ತೆಯಾಗಿದೆ"</string>
    -@@ -1200,7 +1211,7 @@
    -     <string name="tutorial_double_tap_to_zoom_message_short" msgid="1311810005957319690">"ಝೂಮ್‌ ನಿಯಂತ್ರಿಸಲು ಎರಡು ಬಾರಿ ಟ್ಯಾಪ್ ಮಾಡಿ"</string>
    -     <string name="gadget_host_error_inflating" msgid="4882004314906466162">"ವಿಜೆಟ್ ಸೇರಿಸಲು ಸಾಧ್ಯವಾಗುತ್ತಿಲ್ಲ."</string>
    -     <string name="ime_action_go" msgid="8320845651737369027">"ಹೋಗು"</string>
    --    <string name="ime_action_search" msgid="658110271822807811">"ಹುಡುಕು"</string>
    -+    <string name="ime_action_search" msgid="658110271822807811">"ಹುಡುಕಿ"</string>
    -     <string name="ime_action_send" msgid="2316166556349314424">"ಕಳುಹಿಸು"</string>
    -     <string name="ime_action_next" msgid="3138843904009813834">"ಮುಂದೆ"</string>
    -     <string name="ime_action_done" msgid="8971516117910934605">"ಮುಗಿದಿದೆ"</string>
    -@@ -1232,8 +1243,9 @@
    -     <string name="vpn_text_long" msgid="4907843483284977618">"<xliff:g id="SESSION">%s</xliff:g> ಗೆ ಸಂಪರ್ಕಗೊಂಡಿದೆ. ನೆಟ್‍ವರ್ಕ್ ನಿರ್ವಹಿಸಲು ಟ್ಯಾಪ್ ಮಾಡಿ."</string>
    -     <string name="vpn_lockdown_connecting" msgid="6443438964440960745">"ಯಾವಾಗಲೂ-ಆನ್ VPN ಸಂಪರ್ಕಗೊಳ್ಳುತ್ತಿದೆ…"</string>
    -     <string name="vpn_lockdown_connected" msgid="8202679674819213931">"ಯಾವಾಗಲೂ-ಆನ್ VPN ಸಂಪರ್ಕಗೊಂಡಿದೆ"</string>
    -+    <string name="vpn_lockdown_disconnected" msgid="4532298952570796327">"ಯಾವಾಗಲೂ-ಆನ್ VPN ಸಂಪರ್ಕ ಕಡಿತಗೊಳಿಸಲಾಗಿದೆ"</string>
    -     <string name="vpn_lockdown_error" msgid="6009249814034708175">"ಯಾವಾಗಲೂ-ಆನ್ VPN ದೋಷ"</string>
    --    <string name="vpn_lockdown_config" msgid="4655589351146766608">"ಕಾನ್ಫಿಗರ್ ಮಾಡಲು ಟ್ಯಾಪ್‌ ಮಾಡಿ"</string>
    -+    <string name="vpn_lockdown_config" msgid="5099330695245008680">"ಹೊಂದಿಸಲು ಟ್ಯಾಪ್ ಮಾಡಿ"</string>
    -     <string name="upload_file" msgid="2897957172366730416">"ಫೈಲ್ ಆಯ್ಕೆಮಾಡು"</string>
    -     <string name="no_file_chosen" msgid="6363648562170759465">"ಯಾವುದೇ ಫೈಲ್ ಆಯ್ಕೆ ಮಾಡಿಲ್ಲ"</string>
    -     <string name="reset" msgid="2448168080964209908">"ಮರುಹೊಂದಿಸು"</string>
    -@@ -1257,8 +1269,8 @@
    -     <string name="share" msgid="1778686618230011964">"ಹಂಚು"</string>
    -     <string name="find" msgid="4808270900322985960">"ಹುಡುಕಿ"</string>
    -     <string name="websearch" msgid="4337157977400211589">"ವೆಬ್ ಹುಡುಕಾಟ"</string>
    --    <string name="find_next" msgid="5742124618942193978">"ಮುಂದಿನದನ್ನು ಹುಡುಕು"</string>
    --    <string name="find_previous" msgid="2196723669388360506">"ಹಿಂದಿನದನ್ನು ಹುಡುಕು"</string>
    -+    <string name="find_next" msgid="5742124618942193978">"ಮುಂದಿನದನ್ನು ಹುಡುಕಿ"</string>
    -+    <string name="find_previous" msgid="2196723669388360506">"ಹಿಂದಿನದನ್ನು ಹುಡುಕಿ"</string>
    -     <string name="gpsNotifTicker" msgid="5622683912616496172">"<xliff:g id="NAME">%s</xliff:g> ಅವರಿಂದ ಸ್ಥಾನ ವಿನಂತಿ"</string>
    -     <string name="gpsNotifTitle" msgid="5446858717157416839">"ಸ್ಥಾನ ವಿನಂತಿ"</string>
    -     <string name="gpsNotifMessage" msgid="1374718023224000702">"<xliff:g id="NAME">%1$s</xliff:g> (<xliff:g id="SERVICE">%2$s</xliff:g>) ಅವರಿಂದ ವಿನಂತಿಸಲಾಗಿದೆ"</string>
    -@@ -1317,7 +1329,7 @@
    -     <string name="storage_usb_drive_label" msgid="4501418548927759953">"<xliff:g id="MANUFACTURER">%s</xliff:g> USB ಡ್ರೈವ್"</string>
    -     <string name="storage_usb" msgid="3017954059538517278">"USB ಸಂಗ್ರಹಣೆ"</string>
    -     <string name="extract_edit_menu_button" msgid="8940478730496610137">"ಎಡಿಟ್"</string>
    --    <string name="data_usage_warning_title" msgid="1955638862122232342">"ಡೇಟಾ ಬಳಕೆಯ ಎಚ್ಚರಿಕೆ"</string>
    -+    <string name="data_usage_warning_title" msgid="3620440638180218181">"ಡೇಟಾ ಬಳಕೆ ಎಚ್ಚರಿಕೆ"</string>
    -     <string name="data_usage_warning_body" msgid="6660692274311972007">"ಬಳಕೆ ಮತ್ತು ಸೆಟ್ಟಿಂಗ್‍ಗಳನ್ನು ವೀಕ್ಷಿಸಲು ಟ್ಯಾಪ್ ಮಾಡಿ."</string>
    -     <string name="data_usage_3g_limit_title" msgid="4361523876818447683">"2G-3G ಡೇಟಾ ಮೀತಿಯನ್ನು ತಲುಪಿದೆ"</string>
    -     <string name="data_usage_4g_limit_title" msgid="4609566827219442376">"4G ಡೇಟಾ ಮೀತಿಯನ್ನು ತಲುಪಿದೆ"</string>
    -@@ -1512,11 +1524,11 @@
    -     <string name="mediasize_japanese_kahu" msgid="6872696027560065173">"Kahu"</string>
    -     <string name="mediasize_japanese_kaku2" msgid="2359077233775455405">"Kaku2"</string>
    -     <string name="mediasize_japanese_you4" msgid="2091777168747058008">"You4"</string>
    --    <string name="mediasize_unknown_portrait" msgid="3088043641616409762">"ಅಜ್ಞಾತ ಪೋಟ್ರೇಟ್"</string>
    --    <string name="mediasize_unknown_landscape" msgid="4876995327029361552">"ಅಜ್ಞಾತ ಲ್ಯಾಂಡ್‌ಸ್ಕೇಪ್"</string>
    -+    <string name="mediasize_unknown_portrait" msgid="3088043641616409762">"ಅಪರಿಚಿತ ಪೋಟ್ರೇಟ್"</string>
    -+    <string name="mediasize_unknown_landscape" msgid="4876995327029361552">"ಅಪರಿಚಿತ ಲ್ಯಾಂಡ್‌ಸ್ಕೇಪ್"</string>
    -     <string name="write_fail_reason_cancelled" msgid="7091258378121627624">"ರದ್ದುಮಾಡಲಾಗಿದೆ"</string>
    -     <string name="write_fail_reason_cannot_write" msgid="8132505417935337724">"ವಿಷಯವನ್ನು ಬರೆಯುವಲ್ಲಿ ದೋಷ ಎದುರಾಗಿದೆ"</string>
    --    <string name="reason_unknown" msgid="6048913880184628119">"ಅಜ್ಞಾತ"</string>
    -+    <string name="reason_unknown" msgid="6048913880184628119">"ಅಪರಿಚಿತ"</string>
    -     <string name="reason_service_unavailable" msgid="7824008732243903268">"ಮುದ್ರಣ ಸೇವೆ ಸಕ್ರಿಯಗೊಂಡಿಲ್ಲ"</string>
    -     <string name="print_service_installed_title" msgid="2246317169444081628">"<xliff:g id="NAME">%s</xliff:g> ಸೇವೆಯನ್ನು ಸ್ಥಾಪಿಸಲಾಗಿದೆ"</string>
    -     <string name="print_service_installed_message" msgid="5897362931070459152">"ಸಕ್ರಿಯಗೊಳಿಸಲು ಟ್ಯಾಪ್ ಮಾಡಿ"</string>
    -@@ -1636,7 +1648,8 @@
    -     <string name="search_language_hint" msgid="7042102592055108574">"ಭಾಷೆ ಹೆಸರನ್ನು ಟೈಪ್ ಮಾಡಿ"</string>
    -     <string name="language_picker_section_suggested" msgid="8414489646861640885">"ಸೂಚಿತ ಭಾಷೆ"</string>
    -     <string name="language_picker_section_all" msgid="3097279199511617537">"ಎಲ್ಲಾ ಭಾಷೆಗಳು"</string>
    --    <string name="locale_search_menu" msgid="2560710726687249178">"ಹುಡುಕು"</string>
    -+    <string name="region_picker_section_all" msgid="8966316787153001779">"ಎಲ್ಲಾ ಪ್ರದೇಶಗಳು"</string>
    -+    <string name="locale_search_menu" msgid="2560710726687249178">"ಹುಡುಕಿ"</string>
    -     <string name="work_mode_off_title" msgid="8954725060677558855">"ಕೆಲಸದ ಮೋಡ್ ಆಫ್ ಆಗಿದೆ"</string>
    -     <string name="work_mode_off_message" msgid="3286169091278094476">"ಅಪ್ಲಿಕೇಶನ್‌ಗಳು, ಹಿನ್ನೆಲೆ ಸಿಂಕ್ ಮತ್ತು ಇತರ ಸಂಬಂಧಿತ ವೈಶಿಷ್ಟ್ಯಗಳು ಸೇರಿದಂತೆ ನಿಮ್ಮ ಕೆಲಸದ ಪ್ರೊಫೈಲ್‌‌ ಕಾರ್ಯನಿರ್ವಹಿಸಲು ಅನುಮತಿಸಿ."</string>
    -     <string name="work_mode_turn_on" msgid="2062544985670564875">"ಆನ್ ಮಾಡು"</string>
    -diff --git a/core/res/res/values-ko/strings.xml b/core/res/res/values-ko/strings.xml
    -index 5b446b4..b23a966 100644
    ---- a/core/res/res/values-ko/strings.xml
    -+++ b/core/res/res/values-ko/strings.xml
    -@@ -214,6 +214,7 @@
    -     <string name="global_actions" product="default" msgid="2406416831541615258">"휴대전화 옵션"</string>
    -     <string name="global_action_lock" msgid="2844945191792119712">"화면 잠금"</string>
    -     <string name="global_action_power_off" msgid="4471879440839879722">"종료"</string>
    -+    <string name="global_action_emergency" msgid="7112311161137421166">"긴급 전화"</string>
    -     <string name="global_action_bug_report" msgid="7934010578922304799">"버그 신고"</string>
    -     <string name="bugreport_title" msgid="2667494803742548533">"버그 신고"</string>
    -     <string name="bugreport_message" msgid="398447048750350456">"현재 기기 상태에 대한 정보를 수집하여 이메일 메시지로 전송합니다. 버그 신고를 시작하여 전송할 준비가 되려면 약간 시간이 걸립니다."</string>
    -@@ -243,7 +244,7 @@
    -     <string name="user_owner_label" msgid="1119010402169916617">"개인으로 전환"</string>
    -     <string name="managed_profile_label" msgid="5289992269827577857">"직장으로 전환"</string>
    -     <string name="permgrouplab_contacts" msgid="3657758145679177612">"주소록"</string>
    --    <string name="permgroupdesc_contacts" msgid="6951499528303668046">"주소록에 접근할 수 있도록"</string>
    -+    <string name="permgroupdesc_contacts" msgid="6951499528303668046">"주소록에 액세스"</string>
    -     <string name="permgrouplab_location" msgid="7275582855722310164">"위치"</string>
    -     <string name="permgroupdesc_location" msgid="1346617465127855033">"이 기기의 위치정보에 액세스"</string>
    -     <string name="permgrouplab_calendar" msgid="5863508437783683902">"캘린더"</string>
    -@@ -259,7 +260,7 @@
    -     <string name="permgrouplab_phone" msgid="5229115638567440675">"전화"</string>
    -     <string name="permgroupdesc_phone" msgid="6234224354060641055">"통화 상태를 관리하거나 전화를 걸 수 있도록"</string>
    -     <string name="permgrouplab_sensors" msgid="416037179223226722">"신체 센서"</string>
    --    <string name="permgroupdesc_sensors" msgid="7147968539346634043">"생체 신호에 관한 센서 데이터에 접근할 수 있도록"</string>
    -+    <string name="permgroupdesc_sensors" msgid="7147968539346634043">"생체 신호에 관한 센서 데이터에 액세스"</string>
    -     <string name="capability_title_canRetrieveWindowContent" msgid="3901717936930170320">"창 콘텐츠 가져오기"</string>
    -     <string name="capability_desc_canRetrieveWindowContent" msgid="3772225008605310672">"상호작용 중인 창의 콘텐츠를 검사합니다."</string>
    -     <string name="capability_title_canRequestTouchExploration" msgid="3108723364676667320">"터치하여 탐색 사용"</string>
    -@@ -1076,6 +1077,17 @@
    -     <skip />
    -     <string name="wifi_no_internet" msgid="8451173622563841546">"Wi-Fi가 인터넷에 연결되어 있지 않습니다."</string>
    -     <string name="wifi_no_internet_detailed" msgid="8083079241212301741">"탭하여 옵션 보기"</string>
    -+    <string name="network_switch_metered" msgid="4671730921726992671">"<xliff:g id="NETWORK_TYPE">%1$s</xliff:g>(으)로 전환"</string>
    -+    <string name="network_switch_metered_detail" msgid="5325661434777870353">"<xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g>이(가) 인터넷에 연결되지 않는 경우 기기에서 <xliff:g id="NEW_NETWORK">%1$s</xliff:g>을(를) 사용합니다. 요금이 부과될 수 있습니다."</string>
    -+    <string name="network_switch_metered_toast" msgid="5779283181685974304">"<xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g>에서 <xliff:g id="NEW_NETWORK">%2$s</xliff:g>(으)로 전환"</string>
    -+  <string-array name="network_switch_type_name">
    -+    <item msgid="2952042958050315394">"모바일 데이터"</item>
    -+    <item msgid="75483255295529161">"Wi-Fi"</item>
    -+    <item msgid="6862614801537202646">"블루투스"</item>
    -+    <item msgid="5447331121797802871">"이더넷"</item>
    -+    <item msgid="8257233890381651999">"VPN"</item>
    -+  </string-array>
    -+    <string name="network_switch_type_name_unknown" msgid="4552612897806660656">"알 수 없는 네트워크 유형"</string>
    -     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Wi-Fi에 연결할 수 없습니다"</string>
    -     <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" 인터넷 연결 상태가 좋지 않습니다."</string>
    -     <string name="wifi_connect_alert_title" msgid="8455846016001810172">"연결을 허용하시겠습니까?"</string>
    -@@ -1153,7 +1165,6 @@
    -     <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"탭하여 언어와 레이아웃을 선택하세요."</string>
    -     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
    -     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
    --    <string name="candidates_style" msgid="4333913089637062257"><u>"가능한 원인"</u></string>
    -     <string name="ext_media_checking_notification_title" msgid="5734005953288045806">"<xliff:g id="NAME">%s</xliff:g> 준비 중"</string>
    -     <string name="ext_media_checking_notification_message" msgid="4747432538578886744">"오류 확인 중"</string>
    -     <string name="ext_media_new_notification_message" msgid="7589986898808506239">"새로운 <xliff:g id="NAME">%s</xliff:g> 감지됨"</string>
    -@@ -1232,8 +1243,9 @@
    -     <string name="vpn_text_long" msgid="4907843483284977618">"<xliff:g id="SESSION">%s</xliff:g>에 연결되어 있습니다. 네트워크를 관리하려면 누르세요."</string>
    -     <string name="vpn_lockdown_connecting" msgid="6443438964440960745">"연결 유지 VPN에 연결하는 중…"</string>
    -     <string name="vpn_lockdown_connected" msgid="8202679674819213931">"연결 유지 VPN에 연결됨"</string>
    -+    <string name="vpn_lockdown_disconnected" msgid="4532298952570796327">"연결 유지 VPN 연결 해제됨"</string>
    -     <string name="vpn_lockdown_error" msgid="6009249814034708175">"연결 유지 VPN 오류"</string>
    --    <string name="vpn_lockdown_config" msgid="4655589351146766608">"설정하려면 탭하세요."</string>
    -+    <string name="vpn_lockdown_config" msgid="5099330695245008680">"탭하여 설정"</string>
    -     <string name="upload_file" msgid="2897957172366730416">"파일 선택"</string>
    -     <string name="no_file_chosen" msgid="6363648562170759465">"파일을 선택하지 않았습니다."</string>
    -     <string name="reset" msgid="2448168080964209908">"초기화"</string>
    -@@ -1310,14 +1322,14 @@
    -     <string name="action_menu_overflow_description" msgid="2295659037509008453">"옵션 더보기"</string>
    -     <string name="action_bar_home_description_format" msgid="7965984360903693903">"%1$s, %2$s"</string>
    -     <string name="action_bar_home_subtitle_description_format" msgid="6985546530471780727">"%1$s, %2$s, %3$s"</string>
    --    <string name="storage_internal" msgid="3570990907910199483">"내부 공유 저장공간"</string>
    -+    <string name="storage_internal" msgid="3570990907910199483">"내부 공유 저장용량"</string>
    -     <string name="storage_sd_card" msgid="3282948861378286745">"SD 카드"</string>
    -     <string name="storage_sd_card_label" msgid="6347111320774379257">"<xliff:g id="MANUFACTURER">%s</xliff:g> SD 카드"</string>
    -     <string name="storage_usb_drive" msgid="6261899683292244209">"USB 드라이브"</string>
    -     <string name="storage_usb_drive_label" msgid="4501418548927759953">"<xliff:g id="MANUFACTURER">%s</xliff:g> USB 드라이브"</string>
    -     <string name="storage_usb" msgid="3017954059538517278">"USB 저장소"</string>
    -     <string name="extract_edit_menu_button" msgid="8940478730496610137">"수정"</string>
    --    <string name="data_usage_warning_title" msgid="1955638862122232342">"데이터 사용 경고"</string>
    -+    <string name="data_usage_warning_title" msgid="3620440638180218181">"데이터 사용 알림"</string>
    -     <string name="data_usage_warning_body" msgid="6660692274311972007">"사용량 및 설정을 보려면 탭하세요."</string>
    -     <string name="data_usage_3g_limit_title" msgid="4361523876818447683">"2G-3G 데이터 한도에 도달함"</string>
    -     <string name="data_usage_4g_limit_title" msgid="4609566827219442376">"4G 데이터 한도에 도달함"</string>
    -@@ -1636,6 +1648,7 @@
    -     <string name="search_language_hint" msgid="7042102592055108574">"언어 이름 입력"</string>
    -     <string name="language_picker_section_suggested" msgid="8414489646861640885">"추천"</string>
    -     <string name="language_picker_section_all" msgid="3097279199511617537">"모든 언어"</string>
    -+    <string name="region_picker_section_all" msgid="8966316787153001779">"모든 지역"</string>
    -     <string name="locale_search_menu" msgid="2560710726687249178">"검색"</string>
    -     <string name="work_mode_off_title" msgid="8954725060677558855">"직장 모드가 사용 중지됨"</string>
    -     <string name="work_mode_off_message" msgid="3286169091278094476">"앱, 백그라운드 동기화 및 관련 기능을 포함한 직장 프로필이 작동하도록 허용"</string>
    -diff --git a/core/res/res/values-ky-rKG/strings.xml b/core/res/res/values-ky-rKG/strings.xml
    -index 0f82dcb..4f48a94 100644
    ---- a/core/res/res/values-ky-rKG/strings.xml
    -+++ b/core/res/res/values-ky-rKG/strings.xml
    -@@ -214,6 +214,7 @@
    -     <string name="global_actions" product="default" msgid="2406416831541615258">"Телефон мүмкүнчүлүктөрү"</string>
    -     <string name="global_action_lock" msgid="2844945191792119712">"Экран кулпусу"</string>
    -     <string name="global_action_power_off" msgid="4471879440839879722">"Кубатын өчүрүү"</string>
    -+    <string name="global_action_emergency" msgid="7112311161137421166">"Тез жардам"</string>
    -     <string name="global_action_bug_report" msgid="7934010578922304799">"Ката тууралуу билдирүү"</string>
    -     <string name="bugreport_title" msgid="2667494803742548533">"Ката тууралуу билдирүү түзүү"</string>
    -     <string name="bugreport_message" msgid="398447048750350456">"Бул сиздин түзмөгүңүздүн учурдагы абалын эмейл билдирүүсү катары жөнөтүш максатында маалымат чогултат. Ката тууралуу билдирүү түзүлүп башталып, жөнөтүлгөнгө чейин бир аз убакыт керек болот; сураныч, бир аз күтө туруңуз."</string>
    -@@ -1076,6 +1077,17 @@
    -     <skip />
    -     <string name="wifi_no_internet" msgid="8451173622563841546">"Wi-Fi тармагы Интернетке туташпай турат"</string>
    -     <string name="wifi_no_internet_detailed" msgid="8083079241212301741">"Параметрлерди ачуу үчүн таптап коюңуз"</string>
    -+    <string name="network_switch_metered" msgid="4671730921726992671">"<xliff:g id="NETWORK_TYPE">%1$s</xliff:g> тармагына которуштурулду"</string>
    -+    <string name="network_switch_metered_detail" msgid="5325661434777870353">"<xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> тармагы Интернетке туташпай турганда, түзмөгүңүз <xliff:g id="NEW_NETWORK">%1$s</xliff:g> тармагын колдонот. Акы алынышы мүмкүн."</string>
    -+    <string name="network_switch_metered_toast" msgid="5779283181685974304">"<xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> дегенден <xliff:g id="NEW_NETWORK">%2$s</xliff:g> тармагына которуштурулду"</string>
    -+  <string-array name="network_switch_type_name">
    -+    <item msgid="2952042958050315394">"мобилдик дайындар"</item>
    -+    <item msgid="75483255295529161">"Wi-Fi"</item>
    -+    <item msgid="6862614801537202646">"Bluetooth"</item>
    -+    <item msgid="5447331121797802871">"Ethernet"</item>
    -+    <item msgid="8257233890381651999">"VPN"</item>
    -+  </string-array>
    -+    <string name="network_switch_type_name_unknown" msgid="4552612897806660656">"белгисиз тармак түрү"</string>
    -     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Wi-Fi менен туташуу түзүлбөдү"</string>
    -     <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" хотспотунун интернет байланышы начар."</string>
    -     <string name="wifi_connect_alert_title" msgid="8455846016001810172">"Туташууга уруксатпы?"</string>
    -@@ -1153,7 +1165,6 @@
    -     <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"Тил жана калып тандоо үчүн таптап коюңуз"</string>
    -     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
    -     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
    --    <string name="candidates_style" msgid="4333913089637062257"><u>"талапкерлер"</u></string>
    -     <string name="ext_media_checking_notification_title" msgid="5734005953288045806">"<xliff:g id="NAME">%s</xliff:g> даярдалууда"</string>
    -     <string name="ext_media_checking_notification_message" msgid="4747432538578886744">"Каталар текшерилүүдө"</string>
    -     <string name="ext_media_new_notification_message" msgid="7589986898808506239">"Жаңы <xliff:g id="NAME">%s</xliff:g> аныкталды"</string>
    -@@ -1197,8 +1208,7 @@
    -     <string name="permdesc_readInstallSessions" msgid="2049771699626019849">"Колдонмого орнотуу сеанстарын окуу мүмкүнчүлүгүн берет. Ушуну менен, ал жигердүү топтом орнотууларынын чоо-жайын көрө алат."</string>
    -     <string name="permlab_requestInstallPackages" msgid="5782013576218172577">"орнотуу топтомдорун суроо"</string>
    -     <string name="permdesc_requestInstallPackages" msgid="5740101072486783082">"Колдонмо топтомдорду орнотууга уруксат сурай алат."</string>
    --    <!-- no translation found for tutorial_double_tap_to_zoom_message_short (1311810005957319690) -->
    --    <skip />
    -+    <string name="tutorial_double_tap_to_zoom_message_short" msgid="1311810005957319690">"Масштабдын параметрлерин өзгөртүү үчүн бул жерди эки жолу басыңыз."</string>
    -     <string name="gadget_host_error_inflating" msgid="4882004314906466162">"Виджетти кошуу мүмкүн болбоду."</string>
    -     <string name="ime_action_go" msgid="8320845651737369027">"Өтүү"</string>
    -     <string name="ime_action_search" msgid="658110271822807811">"Издөө"</string>
    -@@ -1229,14 +1239,13 @@
    -     <string name="notification_ranker_binding_label" msgid="774540592299064747">"Эскертмелердин маанилүүлүгүн баалоо кызматы"</string>
    -     <string name="vpn_title" msgid="19615213552042827">"VPN иштетилди"</string>
    -     <string name="vpn_title_long" msgid="6400714798049252294">"VPN <xliff:g id="APP">%s</xliff:g> аркылуу жандырылды"</string>
    --    <!-- no translation found for vpn_text (1610714069627824309) -->
    --    <skip />
    --    <!-- no translation found for vpn_text_long (4907843483284977618) -->
    --    <skip />
    -+    <string name="vpn_text" msgid="1610714069627824309">"Тармактын параметрлерин өзгөртүү үчүн бул жерди басыңыз."</string>
    -+    <string name="vpn_text_long" msgid="4907843483284977618">"<xliff:g id="SESSION">%s</xliff:g> сеансына туташуу ишке ашты. Желенин параметрлерин өзгөртүү үчүн бул жерди басыңыз."</string>
    -     <string name="vpn_lockdown_connecting" msgid="6443438964440960745">"Дайым иштеген VPN туташууда…"</string>
    -     <string name="vpn_lockdown_connected" msgid="8202679674819213931">"Дайым иштеген VPN туташтырылды"</string>
    -+    <string name="vpn_lockdown_disconnected" msgid="4532298952570796327">"Дайым иштеген VPN ажыратылды"</string>
    -     <string name="vpn_lockdown_error" msgid="6009249814034708175">"Дайым иштеген VPN\'де ката кетти"</string>
    --    <string name="vpn_lockdown_config" msgid="4655589351146766608">"Конфигурациялоо үчүн таптап коюңуз"</string>
    -+    <string name="vpn_lockdown_config" msgid="5099330695245008680">"Жөндөө үчүн таптаңыз"</string>
    -     <string name="upload_file" msgid="2897957172366730416">"Файл тандоо"</string>
    -     <string name="no_file_chosen" msgid="6363648562170759465">"Эч файл тандалган жок"</string>
    -     <string name="reset" msgid="2448168080964209908">"Баштапкы абалга келтирүү"</string>
    -@@ -1320,7 +1329,7 @@
    -     <string name="storage_usb_drive_label" msgid="4501418548927759953">"<xliff:g id="MANUFACTURER">%s</xliff:g> USB түзмөгү"</string>
    -     <string name="storage_usb" msgid="3017954059538517278">"USB эстутуму"</string>
    -     <string name="extract_edit_menu_button" msgid="8940478730496610137">"Өзгөртүү"</string>
    --    <string name="data_usage_warning_title" msgid="1955638862122232342">"Дайындарды колдонуу боюнча эскрт"</string>
    -+    <string name="data_usage_warning_title" msgid="3620440638180218181">"Дайындарды колдонууну чектөө"</string>
    -     <string name="data_usage_warning_body" msgid="6660692274311972007">"Колдонулушун жана жөндөөлөрүн көрүү үчүн таптаңыз."</string>
    -     <string name="data_usage_3g_limit_title" msgid="4361523876818447683">"2G-3G дайындар чегине жетти"</string>
    -     <string name="data_usage_4g_limit_title" msgid="4609566827219442376">"4G дайындар чегине жетти"</string>
    -@@ -1639,6 +1648,7 @@
    -     <string name="search_language_hint" msgid="7042102592055108574">"Тилди киргизиңиз"</string>
    -     <string name="language_picker_section_suggested" msgid="8414489646861640885">"Сунушталган"</string>
    -     <string name="language_picker_section_all" msgid="3097279199511617537">"Бардык тилдер"</string>
    -+    <string name="region_picker_section_all" msgid="8966316787153001779">"Бардык аймактар"</string>
    -     <string name="locale_search_menu" msgid="2560710726687249178">"Издөө"</string>
    -     <string name="work_mode_off_title" msgid="8954725060677558855">"Жумуш режими ӨЧҮРҮЛГӨН"</string>
    -     <string name="work_mode_off_message" msgid="3286169091278094476">"Жумуш профилин, ошондой эле колдонмолорду, фондо шайкештирүү жана ага байланыштуу функцияларды иштетиңиз."</string>
    -diff --git a/core/res/res/values-lo-rLA/strings.xml b/core/res/res/values-lo-rLA/strings.xml
    -index e2720c7..18f285f 100644
    ---- a/core/res/res/values-lo-rLA/strings.xml
    -+++ b/core/res/res/values-lo-rLA/strings.xml
    -@@ -214,6 +214,7 @@
    -     <string name="global_actions" product="default" msgid="2406416831541615258">"ໂຕເລືອກໂທລະສັບ"</string>
    -     <string name="global_action_lock" msgid="2844945191792119712">"ລັອກໜ້າຈໍ"</string>
    -     <string name="global_action_power_off" msgid="4471879440839879722">"ປິດ"</string>
    -+    <string name="global_action_emergency" msgid="7112311161137421166">"ສຸກເສີນ"</string>
    -     <string name="global_action_bug_report" msgid="7934010578922304799">"ລາຍງານຂໍ້ຜິດພາດ"</string>
    -     <string name="bugreport_title" msgid="2667494803742548533">"ໃຊ້ລາຍງານຂໍ້ບົກພ່ອງ"</string>
    -     <string name="bugreport_message" msgid="398447048750350456">"ນີ້ຈະເປັນການເກັບກຳຂໍ້ມູນກ່ຽວກັບ ສະຖານະປັດຈຸບັນຂອງອຸປະກອນທ່ານ ເພື່ອສົ່ງເປັນຂໍ້ຄວາມທາງອີເມວ. ມັນຈະໃຊ້ເວລາໜ້ອຍນຶ່ງ ໃນການເລີ່ມຕົ້ນການລາຍງານຂໍ້ຜິດພາດ ຈົນກວ່າຈະພ້ອມທີ່ຈະສົ່ງໄດ້, ກະລຸນາລໍຖ້າ."</string>
    -@@ -1076,6 +1077,17 @@
    -     <skip />
    -     <string name="wifi_no_internet" msgid="8451173622563841546">"Wi-Fi ບໍ່ມີການເຂົ້າເຖິງອິນເຕີເນັດ"</string>
    -     <string name="wifi_no_internet_detailed" msgid="8083079241212301741">"ແຕະເພື່ອເບິ່ງຕົວເລືອກ"</string>
    -+    <string name="network_switch_metered" msgid="4671730921726992671">"ສະຫຼັບໄປໃຊ້ <xliff:g id="NETWORK_TYPE">%1$s</xliff:g> ແລ້ວ"</string>
    -+    <string name="network_switch_metered_detail" msgid="5325661434777870353">"ອຸປະກອນຈະໃຊ້ <xliff:g id="NEW_NETWORK">%1$s</xliff:g> ເມື່ອ <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> ບໍ່ມີການເຊື່ອມຕໍ່ອິນເຕີເນັດ. ອາດມີການຮຽກເກັບຄ່າບໍລິການ."</string>
    -+    <string name="network_switch_metered_toast" msgid="5779283181685974304">"ສະຫຼັບຈາກ <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> ໄປໃຊ້ <xliff:g id="NEW_NETWORK">%2$s</xliff:g> ແລ້ວ"</string>
    -+  <string-array name="network_switch_type_name">
    -+    <item msgid="2952042958050315394">"ຂໍ້ມູນອິນເຕີເນັດມືຖື"</item>
    -+    <item msgid="75483255295529161">"Wi-Fi"</item>
    -+    <item msgid="6862614801537202646">"Bluetooth"</item>
    -+    <item msgid="5447331121797802871">"ອີເທີເນັດ"</item>
    -+    <item msgid="8257233890381651999">"VPN"</item>
    -+  </string-array>
    -+    <string name="network_switch_type_name_unknown" msgid="4552612897806660656">"ບໍ່ຮູ້ຈັກປະເພດເຄືອຂ່າຍ"</string>
    -     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"ບໍ່ສາມາດເຊື່ອມຕໍ່ Wi-Fi ໄດ້"</string>
    -     <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" ມີສັນຍານອິນເຕີເນັດທີ່ບໍ່ດີ."</string>
    -     <string name="wifi_connect_alert_title" msgid="8455846016001810172">"​ອະ​ນຸ​ຍາດ​ການ​ເຊື່ອມ​ຕໍ່ຫຼື​ບໍ່?"</string>
    -@@ -1153,7 +1165,6 @@
    -     <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"ແຕະເພື່ອເລືອກພາສາ ແລະ ໂຄງແປ້ນພິມ"</string>
    -     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
    -     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
    --    <string name="candidates_style" msgid="4333913089637062257"><u>"ຕົວເລືອກ"</u></string>
    -     <string name="ext_media_checking_notification_title" msgid="5734005953288045806">"ກຳ​ລັງ​ກຽມ <xliff:g id="NAME">%s</xliff:g>"</string>
    -     <string name="ext_media_checking_notification_message" msgid="4747432538578886744">"ກຳລັງກວດຫາຂໍ້ຜິດພາດ"</string>
    -     <string name="ext_media_new_notification_message" msgid="7589986898808506239">"ກວດ​ພົບ <xliff:g id="NAME">%s</xliff:g> ໃໝ່​ແລ້ວ"</string>
    -@@ -1232,8 +1243,9 @@
    -     <string name="vpn_text_long" msgid="4907843483284977618">"ເຊື່ອມຕໍ່ກັບ <xliff:g id="SESSION">%s</xliff:g> ແລ້ວ. ແຕະເພື່ອຈັດການເຄືອຂ່າຍ."</string>
    -     <string name="vpn_lockdown_connecting" msgid="6443438964440960745">"ກຳລັງເຊື່ອມຕໍ່ Always-on VPN…"</string>
    -     <string name="vpn_lockdown_connected" msgid="8202679674819213931">"ເຊື່ອມຕໍ່ VPN ແບບເປີດຕະຫຼອດເວລາແລ້ວ"</string>
    -+    <string name="vpn_lockdown_disconnected" msgid="4532298952570796327">"ຕັດການເຊື່ອມຕໍ່ VPN ແບບເປີດໃຊ້ຕະຫຼອດເວລາແລ້ວ"</string>
    -     <string name="vpn_lockdown_error" msgid="6009249814034708175">"VPN ແບບເປີດຕະຫຼອດເກີດຄວາມຜິດພາດ"</string>
    --    <string name="vpn_lockdown_config" msgid="4655589351146766608">"ແຕະເພື່ອຕັ້ງຄ່າ"</string>
    -+    <string name="vpn_lockdown_config" msgid="5099330695245008680">"ແຕະເພື່ອຕັ້ງຄ່າ"</string>
    -     <string name="upload_file" msgid="2897957172366730416">"ເລືອກໄຟລ໌"</string>
    -     <string name="no_file_chosen" msgid="6363648562170759465">"ບໍ່ໄດ້ເລືອກໄຟລ໌ເທື່ອ"</string>
    -     <string name="reset" msgid="2448168080964209908">"ຣີເຊັດ"</string>
    -@@ -1317,7 +1329,7 @@
    -     <string name="storage_usb_drive_label" msgid="4501418548927759953">"<xliff:g id="MANUFACTURER">%s</xliff:g> USB ດ​ຣ້າຍ"</string>
    -     <string name="storage_usb" msgid="3017954059538517278">"ບ່ອນຈັດເກັບຂໍ້ມູນ USB"</string>
    -     <string name="extract_edit_menu_button" msgid="8940478730496610137">"ແກ້ໄຂ"</string>
    --    <string name="data_usage_warning_title" msgid="1955638862122232342">"ເຕືອນກ່ຽວກັບການນຳໃຊ້ຂໍ້ມູນ"</string>
    -+    <string name="data_usage_warning_title" msgid="3620440638180218181">"ແຈ້ງເຕືອນການໃຊ້ອິນເຕີເນັດ"</string>
    -     <string name="data_usage_warning_body" msgid="6660692274311972007">"ແຕະເພື່ອເບິ່ງການນຳໃຊ້ ແລະ ການຕັ້ງຄ່າ."</string>
    -     <string name="data_usage_3g_limit_title" msgid="4361523876818447683">"ໃຊ້​ຂໍ້​ມູນ 2G-3G ຮອດ​ຈຳ​ນວນ​ທີ່​ຈຳ​ກັດ​ແລ້ວ"</string>
    -     <string name="data_usage_4g_limit_title" msgid="4609566827219442376">"ໃຊ້​ຂໍ້​ມູນ 4G ຮອດ​ຈຳ​ນວນ​ທີ່​ຈຳ​ກັດ​ແລ້ວ"</string>
    -@@ -1636,6 +1648,7 @@
    -     <string name="search_language_hint" msgid="7042102592055108574">"ພິມຊື່ພາສາ"</string>
    -     <string name="language_picker_section_suggested" msgid="8414489646861640885">"ແນະນຳ"</string>
    -     <string name="language_picker_section_all" msgid="3097279199511617537">"ທຸກພາ​ສາ​"</string>
    -+    <string name="region_picker_section_all" msgid="8966316787153001779">"ທຸກຂົງເຂດ"</string>
    -     <string name="locale_search_menu" msgid="2560710726687249178">"ຄົ້ນຫາ"</string>
    -     <string name="work_mode_off_title" msgid="8954725060677558855">"ໂໝດບ່ອນເຮັດວຽກປິດຢູ່"</string>
    -     <string name="work_mode_off_message" msgid="3286169091278094476">"ອະນຸຍາດໃຫ້ໂປຣໄຟລ໌ບ່ອນເຮັດວຽກສາມາດນຳໃຊ້ໄດ້ ເຊິ່ງຮວມທັງແອັບ, ການຊິ້ງຂໍ້ມູນໃນພື້ນຫຼັງ ແລະ ຄຸນສົມບັດທີ່ກ່ຽວຂ້ອງ."</string>
    -diff --git a/core/res/res/values-lt/strings.xml b/core/res/res/values-lt/strings.xml
    -index ab38c0c..9952a7c 100644
    ---- a/core/res/res/values-lt/strings.xml
    -+++ b/core/res/res/values-lt/strings.xml
    -@@ -218,6 +218,7 @@
    -     <string name="global_actions" product="default" msgid="2406416831541615258">"Telefono parinktys"</string>
    -     <string name="global_action_lock" msgid="2844945191792119712">"Ekrano užraktas"</string>
    -     <string name="global_action_power_off" msgid="4471879440839879722">"Išjungiamas maitinimas"</string>
    -+    <string name="global_action_emergency" msgid="7112311161137421166">"Skambutis pagalbos numeriu"</string>
    -     <string name="global_action_bug_report" msgid="7934010578922304799">"Pranešimas apie riktą"</string>
    -     <string name="bugreport_title" msgid="2667494803742548533">"Pranešti apie riktą"</string>
    -     <string name="bugreport_message" msgid="398447048750350456">"Bus surinkta informacija apie dabartinę įrenginio būseną ir išsiųsta el. pašto pranešimu. Šiek tiek užtruks, kol pranešimas apie riktą bus paruoštas siųsti; būkite kantrūs."</string>
    -@@ -1104,7 +1105,7 @@
    -     <string name="volume_icon_description_media" msgid="4217311719665194215">"Medijos garsumas"</string>
    -     <string name="volume_icon_description_notification" msgid="7044986546477282274">"Pranešimo apimtis"</string>
    -     <string name="ringtone_default" msgid="3789758980357696936">"Numatytasis skambėjimo tonas"</string>
    --    <string name="ringtone_default_with_actual" msgid="8129563480895990372">"Numatytasis skambėjimo tonas (<xliff:g id="ACTUAL_RINGTONE">%1$s</xliff:g>)"</string>
    -+    <string name="ringtone_default_with_actual" msgid="8129563480895990372">"Numatytasis skambėjimo tonas („<xliff:g id="ACTUAL_RINGTONE">%1$s</xliff:g>“)"</string>
    -     <string name="ringtone_silent" msgid="7937634392408977062">"Nėra"</string>
    -     <string name="ringtone_picker_title" msgid="3515143939175119094">"Skambėjimo tonai"</string>
    -     <string name="ringtone_unknown" msgid="5477919988701784788">"Nežinomas skambėjimo tonas"</string>
    -@@ -1126,6 +1127,17 @@
    -     <skip />
    -     <string name="wifi_no_internet" msgid="8451173622563841546">"„Wi-Fi“ tinkle nėra interneto ryšio"</string>
    -     <string name="wifi_no_internet_detailed" msgid="8083079241212301741">"Palieskite, kad būtų rodomos parinktys."</string>
    -+    <string name="network_switch_metered" msgid="4671730921726992671">"Perjungta į tinklą <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
    -+    <string name="network_switch_metered_detail" msgid="5325661434777870353">"Įrenginys naudoja tinklą <xliff:g id="NEW_NETWORK">%1$s</xliff:g> kai tinkle <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> nėra interneto ryšio. Gali būti taikomi mokesčiai."</string>
    -+    <string name="network_switch_metered_toast" msgid="5779283181685974304">"Perjungta iš tinklo <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> į tinklą <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
    -+  <string-array name="network_switch_type_name">
    -+    <item msgid="2952042958050315394">"mobiliojo ryšio duomenys"</item>
    -+    <item msgid="75483255295529161">"Wi-Fi"</item>
    -+    <item msgid="6862614801537202646">"Bluetooth"</item>
    -+    <item msgid="5447331121797802871">"Eternetas"</item>
    -+    <item msgid="8257233890381651999">"VPN"</item>
    -+  </string-array>
    -+    <string name="network_switch_type_name_unknown" msgid="4552612897806660656">"nežinomas tinklo tipas"</string>
    -     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Nepavyko prisijungti prie „Wi-Fi“"</string>
    -     <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" turi prastą interneto ryšį."</string>
    -     <string name="wifi_connect_alert_title" msgid="8455846016001810172">"Leisti prisijungti?"</string>
    -@@ -1203,7 +1215,6 @@
    -     <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"Palieskite, kad pasirinktumėte kalbą ir išdėstymą"</string>
    -     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" AĄBCČDEĘĖFGHIĮYJKLMNOPRSŠTUŲŪVZŽ"</string>
    -     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789AĄBCČDEĘĖFGHIĮYJKLMNOPRSŠTUŲŪVZŽ"</string>
    --    <string name="candidates_style" msgid="4333913089637062257"><u>"kandidatai"</u></string>
    -     <string name="ext_media_checking_notification_title" msgid="5734005953288045806">"Ruošiama <xliff:g id="NAME">%s</xliff:g>"</string>
    -     <string name="ext_media_checking_notification_message" msgid="4747432538578886744">"Tikrinama, ar nėra klaidų"</string>
    -     <string name="ext_media_new_notification_message" msgid="7589986898808506239">"Aptikta nauja <xliff:g id="NAME">%s</xliff:g>"</string>
    -@@ -1282,8 +1293,9 @@
    -     <string name="vpn_text_long" msgid="4907843483284977618">"Prisijungta prie <xliff:g id="SESSION">%s</xliff:g>. Jei norite valdyti tinklą, palieskite."</string>
    -     <string name="vpn_lockdown_connecting" msgid="6443438964440960745">"Prisijungiama prie visada įjungto VPN…"</string>
    -     <string name="vpn_lockdown_connected" msgid="8202679674819213931">"Prisijungta prie visada įjungto VPN"</string>
    -+    <string name="vpn_lockdown_disconnected" msgid="4532298952570796327">"Visada įjungtas VPN atjungtas"</string>
    -     <string name="vpn_lockdown_error" msgid="6009249814034708175">"Visada įjungto VPN klaida"</string>
    --    <string name="vpn_lockdown_config" msgid="4655589351146766608">"Palieskite, kad konfigūruotumėte"</string>
    -+    <string name="vpn_lockdown_config" msgid="5099330695245008680">"Palieskite, kad nustatytumėte"</string>
    -     <string name="upload_file" msgid="2897957172366730416">"Pasirinkti failą"</string>
    -     <string name="no_file_chosen" msgid="6363648562170759465">"Nepasirinktas joks failas"</string>
    -     <string name="reset" msgid="2448168080964209908">"Atstatyti"</string>
    -@@ -1369,7 +1381,7 @@
    -     <string name="storage_usb_drive_label" msgid="4501418548927759953">"„<xliff:g id="MANUFACTURER">%s</xliff:g>“ atmintukas"</string>
    -     <string name="storage_usb" msgid="3017954059538517278">"USB atmintis"</string>
    -     <string name="extract_edit_menu_button" msgid="8940478730496610137">"Redaguoti"</string>
    --    <string name="data_usage_warning_title" msgid="1955638862122232342">"Įspėjimas dėl duomenų naudojimo"</string>
    -+    <string name="data_usage_warning_title" msgid="3620440638180218181">"Duomenų naudojimo įspėjimas"</string>
    -     <string name="data_usage_warning_body" msgid="6660692274311972007">"Pal. ir perž. naud. i. bei nust."</string>
    -     <string name="data_usage_3g_limit_title" msgid="4361523876818447683">"Pasiektas 2G–3G duomenų apribojimas"</string>
    -     <string name="data_usage_4g_limit_title" msgid="4609566827219442376">"Pasiektas 4G duomenų apribojimas"</string>
    -@@ -1708,6 +1720,7 @@
    -     <string name="search_language_hint" msgid="7042102592055108574">"Įveskite kalbos pav."</string>
    -     <string name="language_picker_section_suggested" msgid="8414489646861640885">"Siūloma"</string>
    -     <string name="language_picker_section_all" msgid="3097279199511617537">"Visos kalbos"</string>
    -+    <string name="region_picker_section_all" msgid="8966316787153001779">"Visi regionai"</string>
    -     <string name="locale_search_menu" msgid="2560710726687249178">"Paieška"</string>
    -     <string name="work_mode_off_title" msgid="8954725060677558855">"Darbo režimas išjungtas"</string>
    -     <string name="work_mode_off_message" msgid="3286169091278094476">"Leisti veikti darbo profiliui, įskaitant programas, sinchronizavimą fone ir susijusias funkcijas."</string>
    -diff --git a/core/res/res/values-lv/strings.xml b/core/res/res/values-lv/strings.xml
    -index 35b699f..ff2e974 100644
    ---- a/core/res/res/values-lv/strings.xml
    -+++ b/core/res/res/values-lv/strings.xml
    -@@ -216,6 +216,7 @@
    -     <string name="global_actions" product="default" msgid="2406416831541615258">"Tālruņa opcijas"</string>
    -     <string name="global_action_lock" msgid="2844945191792119712">"Ekrāna bloķētājs"</string>
    -     <string name="global_action_power_off" msgid="4471879440839879722">"Strāvas padeve ir izslēgta."</string>
    -+    <string name="global_action_emergency" msgid="7112311161137421166">"Ārkārtas"</string>
    -     <string name="global_action_bug_report" msgid="7934010578922304799">"Kļūdu ziņojums"</string>
    -     <string name="bugreport_title" msgid="2667494803742548533">"Kļūdu ziņojuma sagatavošana"</string>
    -     <string name="bugreport_message" msgid="398447048750350456">"Veicot šo darbību, tiks apkopota informācija par jūsu ierīces pašreizējo stāvokli un nosūtīta e-pasta ziņojuma veidā. Kļūdu ziņojuma pabeigšanai un nosūtīšanai var būt nepieciešams laiks. Lūdzu, esiet pacietīgs."</string>
    -@@ -1101,6 +1102,17 @@
    -     <skip />
    -     <string name="wifi_no_internet" msgid="8451173622563841546">"Wi-Fi tīklā nav piekļuves internetam."</string>
    -     <string name="wifi_no_internet_detailed" msgid="8083079241212301741">"Pieskarieties, lai skatītu iespējas."</string>
    -+    <string name="network_switch_metered" msgid="4671730921726992671">"Pārslēdzās uz tīklu <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
    -+    <string name="network_switch_metered_detail" msgid="5325661434777870353">"Kad tīklā <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> nav piekļuves internetam, ierīcē tiek izmantots tīkls <xliff:g id="NEW_NETWORK">%1$s</xliff:g>. Var tikt piemērota maksa."</string>
    -+    <string name="network_switch_metered_toast" msgid="5779283181685974304">"Pārslēdzās no tīkla <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> uz tīklu <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
    -+  <string-array name="network_switch_type_name">
    -+    <item msgid="2952042958050315394">"mobilie dati"</item>
    -+    <item msgid="75483255295529161">"Wi-Fi"</item>
    -+    <item msgid="6862614801537202646">"Bluetooth"</item>
    -+    <item msgid="5447331121797802871">"Ethernet"</item>
    -+    <item msgid="8257233890381651999">"VPN"</item>
    -+  </string-array>
    -+    <string name="network_switch_type_name_unknown" msgid="4552612897806660656">"nezināms tīkla veids"</string>
    -     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Nevarēja izveidot savienojumu ar Wi-Fi."</string>
    -     <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" ir slikts interneta savienojums."</string>
    -     <string name="wifi_connect_alert_title" msgid="8455846016001810172">"Vai atļaut savienojumu?"</string>
    -@@ -1178,7 +1190,6 @@
    -     <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"Pieskarieties, lai atlasītu valodu un izkārtojumu"</string>
    -     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" AĀBCČDEĒFGĢHIĪJKĶLĻMNŅOPRSŠTUŪVZŽ"</string>
    -     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789AĀBCČDEĒFGĢHIĪJKĶLĻMNŅOPRSŠTUŪVZŽ"</string>
    --    <string name="candidates_style" msgid="4333913089637062257"><u>"kandidāti"</u></string>
    -     <string name="ext_media_checking_notification_title" msgid="5734005953288045806">"Notiek <xliff:g id="NAME">%s</xliff:g> sagatavošana"</string>
    -     <string name="ext_media_checking_notification_message" msgid="4747432538578886744">"Tiek meklētas kļūdas"</string>
    -     <string name="ext_media_new_notification_message" msgid="7589986898808506239">"Tika atrasta jauna <xliff:g id="NAME">%s</xliff:g>."</string>
    -@@ -1257,8 +1268,9 @@
    -     <string name="vpn_text_long" msgid="4907843483284977618">"Ir izveidots savienojums ar: <xliff:g id="SESSION">%s</xliff:g>. Pieskarieties, lai pārvaldītu tīklu."</string>
    -     <string name="vpn_lockdown_connecting" msgid="6443438964440960745">"Notiek savienojuma izveide ar vienmēr ieslēgtu VPN…"</string>
    -     <string name="vpn_lockdown_connected" msgid="8202679674819213931">"Izveidots savienojums ar vienmēr ieslēgtu VPN."</string>
    -+    <string name="vpn_lockdown_disconnected" msgid="4532298952570796327">"Vienmēr ieslēgts VPN ir atvienots"</string>
    -     <string name="vpn_lockdown_error" msgid="6009249814034708175">"Kļūda saistībā ar vienmēr ieslēgtu VPN"</string>
    --    <string name="vpn_lockdown_config" msgid="4655589351146766608">"Pieskarieties, lai konfigurētu."</string>
    -+    <string name="vpn_lockdown_config" msgid="5099330695245008680">"Pieskarieties, lai iestatītu."</string>
    -     <string name="upload_file" msgid="2897957172366730416">"Izvēlēties failu"</string>
    -     <string name="no_file_chosen" msgid="6363648562170759465">"Neviens fails nav izvēlēts"</string>
    -     <string name="reset" msgid="2448168080964209908">"Atiestatīt"</string>
    -@@ -1343,7 +1355,7 @@
    -     <string name="storage_usb_drive_label" msgid="4501418548927759953">"<xliff:g id="MANUFACTURER">%s</xliff:g> USB disks"</string>
    -     <string name="storage_usb" msgid="3017954059538517278">"USB atmiņa"</string>
    -     <string name="extract_edit_menu_button" msgid="8940478730496610137">"Rediģēt"</string>
    --    <string name="data_usage_warning_title" msgid="1955638862122232342">"Datu izmantošanas brīdinājums"</string>
    -+    <string name="data_usage_warning_title" msgid="3620440638180218181">"Brīdinājums par datu lietojumu"</string>
    -     <string name="data_usage_warning_body" msgid="6660692274311972007">"Piesk., lai sk. lietoj. un iest."</string>
    -     <string name="data_usage_3g_limit_title" msgid="4361523876818447683">"Sasniegts 2G-3G datu ierobež."</string>
    -     <string name="data_usage_4g_limit_title" msgid="4609566827219442376">"Sasniegts 4G datu ierobežojums"</string>
    -@@ -1672,6 +1684,7 @@
    -     <string name="search_language_hint" msgid="7042102592055108574">"Ierakstiet valodas nosaukumu"</string>
    -     <string name="language_picker_section_suggested" msgid="8414489646861640885">"Ieteiktās"</string>
    -     <string name="language_picker_section_all" msgid="3097279199511617537">"Visas valodas"</string>
    -+    <string name="region_picker_section_all" msgid="8966316787153001779">"Visi reģioni"</string>
    -     <string name="locale_search_menu" msgid="2560710726687249178">"Meklēt"</string>
    -     <string name="work_mode_off_title" msgid="8954725060677558855">"Darba režīms IZSLĒGTS"</string>
    -     <string name="work_mode_off_message" msgid="3286169091278094476">"Atļaujiet darboties darba profilam, tostarp lietotnēm, sinhronizācijai fonā un saistītajām funkcijām."</string>
    -diff --git a/core/res/res/values-mcc001/config.xml b/core/res/res/values-mcc001/config.xml
    -new file mode 100644
    -index 0000000..93cde03
    ---- /dev/null
    -+++ b/core/res/res/values-mcc001/config.xml
    -@@ -0,0 +1,21 @@
    -+<?xml version="1.0" encoding="utf-8"?>
    -+<!--
    -+/*
    -+** Copyright 2016, 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.
    -+*/
    -+-->
    -+<resources>
    -+    <bool name="config_use_sim_language_file">true</bool>
    -+</resources>
    -diff --git a/core/res/res/values-mcc222-mnc10/config.xml b/core/res/res/values-mcc222-mnc10/config.xml
    -index cd6e8c6..c819de2 100644
    ---- a/core/res/res/values-mcc222-mnc10/config.xml
    -+++ b/core/res/res/values-mcc222-mnc10/config.xml
    -@@ -28,29 +28,4 @@
    -     <string-array translatable="false" name="config_tether_apndata">
    -       <item>Tethering Internet,web.omnitel.it,,,,,,,,,222,10,,DUN</item>
    -     </string-array>
    --
    --    <string-array translatable="false" name="config_operatorConsideredNonRoaming">
    --        <item>21401</item>
    --        <item>21402</item>
    --        <item>21403</item>
    --        <item>21404</item>
    --        <item>21405</item>
    --        <item>21406</item>
    --        <item>21407</item>
    --        <item>21408</item>
    --        <item>21409</item>
    --        <item>21410</item>
    --        <item>21411</item>
    --        <item>21412</item>
    --        <item>21413</item>
    --        <item>21414</item>
    --        <item>21415</item>
    --        <item>21416</item>
    --        <item>21417</item>
    --        <item>21418</item>
    --        <item>21419</item>
    --        <item>21420</item>
    --        <item>21421</item>
    --    </string-array>
    --
    - </resources>
    -diff --git a/core/res/res/values-mcc232-mnc10/config.xml b/core/res/res/values-mcc232-mnc10/config.xml
    -new file mode 100644
    -index 0000000..bdf83016
    ---- /dev/null
    -+++ b/core/res/res/values-mcc232-mnc10/config.xml
    -@@ -0,0 +1,26 @@
    -+<?xml version="1.0" encoding="utf-8"?>
    -+<!--
    -+/*
    -+ ** Copyright 2016, 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.
    -+ */
    -+-->
    -+
    -+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
    -+    <!-- Don't use roaming icon for considered operators -->
    -+    <string-array translatable="false" name="config_operatorConsideredNonRoaming">
    -+        <item>23203</item>
    -+        <item>23205</item>
    -+    </string-array>
    -+</resources>
    -diff --git a/core/res/res/values-mcc232-mnc13/config.xml b/core/res/res/values-mcc232-mnc13/config.xml
    -new file mode 100644
    -index 0000000..2c14f87
    ---- /dev/null
    -+++ b/core/res/res/values-mcc232-mnc13/config.xml
    -@@ -0,0 +1,25 @@
    -+<?xml version="1.0" encoding="utf-8"?>
    -+<!--
    -+/*
    -+ ** Copyright 2016, 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.
    -+ */
    -+-->
    -+
    -+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
    -+    <!-- Don't use roaming icon for considered operators -->
    -+    <string-array translatable="false" name="config_operatorConsideredNonRoaming">
    -+        <item>23203</item>
    -+    </string-array>
    -+</resources>
    -diff --git a/core/res/res/values-mcc302-mnc220/config.xml b/core/res/res/values-mcc302-mnc220/config.xml
    -index d638b89..422f7c9 100644
    ---- a/core/res/res/values-mcc302-mnc220/config.xml
    -+++ b/core/res/res/values-mcc302-mnc220/config.xml
    -@@ -21,14 +21,6 @@
    -      for different hardware and product builds. -->
    - <resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
    - 
    --    <string-array translatable="false" name="config_operatorConsideredNonRoaming">
    --        <item>302370</item>
    --        <item>302610</item>
    --        <item>302660</item>
    --        <item>302720</item>
    --        <item>302780</item>
    --    </string-array>
    --
    -     <integer name="config_mobile_mtu">1410</integer>
    - 
    -     <!-- String containing the apn value for tethering.  May be overriden by secure settings
    -diff --git a/core/res/res/values-mcc302-mnc500/config.xml b/core/res/res/values-mcc302-mnc500/config.xml
    -new file mode 100644
    -index 0000000..77f6419
    ---- /dev/null
    -+++ b/core/res/res/values-mcc302-mnc500/config.xml
    -@@ -0,0 +1,25 @@
    -+<?xml version="1.0" encoding="utf-8"?>
    -+<!--
    -+/*
    -+ ** Copyright 2016, 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.
    -+ */
    -+-->
    -+
    -+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
    -+    <!-- Don't use roaming icon for considered operators -->
    -+    <string-array translatable="false" name="config_operatorConsideredNonRoaming">
    -+        <item>302</item>
    -+    </string-array>
    -+</resources>
    -diff --git a/core/res/res/values-mcc302-mnc510/config.xml b/core/res/res/values-mcc302-mnc510/config.xml
    -new file mode 100644
    -index 0000000..77f6419
    ---- /dev/null
    -+++ b/core/res/res/values-mcc302-mnc510/config.xml
    -@@ -0,0 +1,25 @@
    -+<?xml version="1.0" encoding="utf-8"?>
    -+<!--
    -+/*
    -+ ** Copyright 2016, 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.
    -+ */
    -+-->
    -+
    -+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
    -+    <!-- Don't use roaming icon for considered operators -->
    -+    <string-array translatable="false" name="config_operatorConsideredNonRoaming">
    -+        <item>302</item>
    -+    </string-array>
    -+</resources>
    -diff --git a/core/res/res/values-mcc722-mnc36/config.xml b/core/res/res/values-mcc722-mnc36/config.xml
    -new file mode 100644
    -index 0000000..daf5373
    ---- /dev/null
    -+++ b/core/res/res/values-mcc722-mnc36/config.xml
    -@@ -0,0 +1,25 @@
    -+<?xml version="1.0" encoding="utf-8"?>
    -+<!--
    -+/*
    -+** Copyright 2016, 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 my 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.
    -+*/
    -+-->
    -+
    -+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
    -+    <!-- Don't use roaming icon for considered operators -->
    -+    <string-array translatable="false" name="config_operatorConsideredNonRoaming">
    -+        <item>72234</item>
    -+    </string-array>
    -+</resources>
    -diff --git a/core/res/res/values-mk-rMK/strings.xml b/core/res/res/values-mk-rMK/strings.xml
    -index e0ec16a..eb86a77 100644
    ---- a/core/res/res/values-mk-rMK/strings.xml
    -+++ b/core/res/res/values-mk-rMK/strings.xml
    -@@ -214,6 +214,7 @@
    -     <string name="global_actions" product="default" msgid="2406416831541615258">"Опции на телефон"</string>
    -     <string name="global_action_lock" msgid="2844945191792119712">"Заклучи екран"</string>
    -     <string name="global_action_power_off" msgid="4471879440839879722">"Исклучи"</string>
    -+    <string name="global_action_emergency" msgid="7112311161137421166">"Итен случај"</string>
    -     <string name="global_action_bug_report" msgid="7934010578922304799">"Извештај за грешка"</string>
    -     <string name="bugreport_title" msgid="2667494803742548533">"Земи извештај за грешки"</string>
    -     <string name="bugreport_message" msgid="398447048750350456">"Ова ќе собира информации за моменталната состојба на вашиот уред, за да ги испрати како порака по е-пошта. Тоа ќе одземе малку време почнувајќи од извештајот за грешки додека не се подготви за праќање; бидете трпеливи."</string>
    -@@ -1076,6 +1077,17 @@
    -     <skip />
    -     <string name="wifi_no_internet" msgid="8451173622563841546">"Wi-Fi нема пристап на интернет"</string>
    -     <string name="wifi_no_internet_detailed" msgid="8083079241212301741">"Допрете за опции"</string>
    -+    <string name="network_switch_metered" msgid="4671730921726992671">"Префрлено на <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
    -+    <string name="network_switch_metered_detail" msgid="5325661434777870353">"Уредот користи <xliff:g id="NEW_NETWORK">%1$s</xliff:g> кога <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> нема пристап до интернет. Може да се наплатат трошоци."</string>
    -+    <string name="network_switch_metered_toast" msgid="5779283181685974304">"Префрлено од <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> на <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
    -+  <string-array name="network_switch_type_name">
    -+    <item msgid="2952042958050315394">"мобилен интернет"</item>
    -+    <item msgid="75483255295529161">"Wi-Fi"</item>
    -+    <item msgid="6862614801537202646">"Bluetooth"</item>
    -+    <item msgid="5447331121797802871">"Етернет"</item>
    -+    <item msgid="8257233890381651999">"VPN"</item>
    -+  </string-array>
    -+    <string name="network_switch_type_name_unknown" msgid="4552612897806660656">"непознат тип мрежа"</string>
    -     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Не можеше да се поврзе со Wi-Fi"</string>
    -     <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" има слаба конекција на интернет."</string>
    -     <string name="wifi_connect_alert_title" msgid="8455846016001810172">"Дозволете поврзување?"</string>
    -@@ -1153,7 +1165,6 @@
    -     <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"Допрете за избирање јазик и распоред"</string>
    -     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
    -     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
    --    <string name="candidates_style" msgid="4333913089637062257"><u>"кандидати"</u></string>
    -     <string name="ext_media_checking_notification_title" msgid="5734005953288045806">"Се подготвува <xliff:g id="NAME">%s</xliff:g>"</string>
    -     <string name="ext_media_checking_notification_message" msgid="4747432538578886744">"Се проверува за грешки"</string>
    -     <string name="ext_media_new_notification_message" msgid="7589986898808506239">"Откриена е нова <xliff:g id="NAME">%s</xliff:g>"</string>
    -@@ -1232,8 +1243,9 @@
    -     <string name="vpn_text_long" msgid="4907843483284977618">"Поврзани сте на <xliff:g id="SESSION">%s</xliff:g>. Допрете за да управувате со мрежата."</string>
    -     <string name="vpn_lockdown_connecting" msgid="6443438964440960745">"Поврзување со секогаш вклучена VPN..."</string>
    -     <string name="vpn_lockdown_connected" msgid="8202679674819213931">"Поврзани со секогаш вклучена VPN"</string>
    -+    <string name="vpn_lockdown_disconnected" msgid="4532298952570796327">"Секогаш вклучената VPN е неповрзана"</string>
    -     <string name="vpn_lockdown_error" msgid="6009249814034708175">"Грешка на секогаш вклучена VPN"</string>
    --    <string name="vpn_lockdown_config" msgid="4655589351146766608">"Допрете за конфигурирање"</string>
    -+    <string name="vpn_lockdown_config" msgid="5099330695245008680">"Допрете за да поставите"</string>
    -     <string name="upload_file" msgid="2897957172366730416">"Избери датотека"</string>
    -     <string name="no_file_chosen" msgid="6363648562170759465">"Не е избрана датотека"</string>
    -     <string name="reset" msgid="2448168080964209908">"Ресетирај"</string>
    -@@ -1319,7 +1331,7 @@
    -     <string name="storage_usb_drive_label" msgid="4501418548927759953">"<xliff:g id="MANUFACTURER">%s</xliff:g> УСБ-меморија"</string>
    -     <string name="storage_usb" msgid="3017954059538517278">"УСБ меморија"</string>
    -     <string name="extract_edit_menu_button" msgid="8940478730496610137">"Уреди"</string>
    --    <string name="data_usage_warning_title" msgid="1955638862122232342">"Опомена за потрошен интернет"</string>
    -+    <string name="data_usage_warning_title" msgid="3620440638180218181">"Известување за потрошен сообраќај"</string>
    -     <string name="data_usage_warning_body" msgid="6660692274311972007">"Допрете за употреба и поставки."</string>
    -     <string name="data_usage_3g_limit_title" msgid="4361523876818447683">"Постигна лимит за 2G-3G податоци"</string>
    -     <string name="data_usage_4g_limit_title" msgid="4609566827219442376">"Постигнат лимит за 4G податоци"</string>
    -@@ -1638,6 +1650,7 @@
    -     <string name="search_language_hint" msgid="7042102592055108574">"Внеси име на јазик"</string>
    -     <string name="language_picker_section_suggested" msgid="8414489646861640885">"Предложени"</string>
    -     <string name="language_picker_section_all" msgid="3097279199511617537">"Сите јазици"</string>
    -+    <string name="region_picker_section_all" msgid="8966316787153001779">"Сите региони"</string>
    -     <string name="locale_search_menu" msgid="2560710726687249178">"Пребарај"</string>
    -     <string name="work_mode_off_title" msgid="8954725060677558855">"Режимот на работа е ИСКЛУЧЕН"</string>
    -     <string name="work_mode_off_message" msgid="3286169091278094476">"Дозволете работниот профил да функционира, вклучувајќи ги апликациите, синхронизирањето во заднина и други поврзани функции."</string>
    -diff --git a/core/res/res/values-ml-rIN/strings.xml b/core/res/res/values-ml-rIN/strings.xml
    -index 39d493a..423db1d 100644
    ---- a/core/res/res/values-ml-rIN/strings.xml
    -+++ b/core/res/res/values-ml-rIN/strings.xml
    -@@ -214,6 +214,7 @@
    -     <string name="global_actions" product="default" msgid="2406416831541615258">"ഫോൺ ഓപ്‌ഷനുകൾ"</string>
    -     <string name="global_action_lock" msgid="2844945191792119712">"സ്‌ക്രീൻ ലോക്ക്"</string>
    -     <string name="global_action_power_off" msgid="4471879440839879722">"പവർ ഓഫാക്കുക"</string>
    -+    <string name="global_action_emergency" msgid="7112311161137421166">"അടിയന്തിരാവശ്യം"</string>
    -     <string name="global_action_bug_report" msgid="7934010578922304799">"ബഗ് റിപ്പോർട്ട്"</string>
    -     <string name="bugreport_title" msgid="2667494803742548533">"ബഗ് റിപ്പോർട്ട് എടുക്കുക"</string>
    -     <string name="bugreport_message" msgid="398447048750350456">"ഒരു ഇമെയിൽ സന്ദേശമായി അയയ്‌ക്കുന്നതിന്, ഇത് നിങ്ങളുടെ നിലവിലെ ഉപകരണ നിലയെക്കുറിച്ചുള്ള വിവരങ്ങൾ ശേഖരിക്കും. ബഗ് റിപ്പോർട്ട് ആരംഭിക്കുന്നതിൽ നിന്ന് ഇത് അയയ്‌ക്കാനായി തയ്യാറാകുന്നതുവരെ അൽപ്പസമയമെടുക്കും; ക്ഷമയോടെ കാത്തിരിക്കുക."</string>
    -@@ -1076,6 +1077,17 @@
    -     <skip />
    -     <string name="wifi_no_internet" msgid="8451173622563841546">"Wi-Fi-യിൽ ഇന്റർനെറ്റ് ആക്‌സസ് ഇല്ല."</string>
    -     <string name="wifi_no_internet_detailed" msgid="8083079241212301741">"ഓപ്ഷനുകൾക്ക് ടാപ്പുചെയ്യുക"</string>
    -+    <string name="network_switch_metered" msgid="4671730921726992671">"<xliff:g id="NETWORK_TYPE">%1$s</xliff:g> എന്നതിലേക്ക് മാറി"</string>
    -+    <string name="network_switch_metered_detail" msgid="5325661434777870353">"<xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> നെറ്റ്‌വർക്കിന് ഇന്റർനെറ്റ് ആക്സസ്സ് ഇല്ലാത്തപ്പോൾ ഉപകരണം <xliff:g id="NEW_NETWORK">%1$s</xliff:g> ഉപയോഗിക്കുന്നു. നിരക്കുകൾ ബാധകമായേക്കാം."</string>
    -+    <string name="network_switch_metered_toast" msgid="5779283181685974304">"<xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> നെറ്റ്‌വർക്കിൽ നിന്ന് <xliff:g id="NEW_NETWORK">%2$s</xliff:g> നെറ്റ്‌വർക്കിലേക്ക് മാറി"</string>
    -+  <string-array name="network_switch_type_name">
    -+    <item msgid="2952042958050315394">"സെല്ലുലാർ ഡാറ്റ"</item>
    -+    <item msgid="75483255295529161">"വൈഫൈ"</item>
    -+    <item msgid="6862614801537202646">"Bluetooth"</item>
    -+    <item msgid="5447331121797802871">"ഇതര്‍നെറ്റ്"</item>
    -+    <item msgid="8257233890381651999">"VPN"</item>
    -+  </string-array>
    -+    <string name="network_switch_type_name_unknown" msgid="4552612897806660656">"തിരിച്ചറിയാനാകാത്ത ഒരു നെറ്റ്‌വർക്ക് തരം"</string>
    -     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Wi-Fi-ലേക്ക് കണക്‌റ്റുചെയ്യാൻ കഴിഞ്ഞില്ല"</string>
    -     <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" മോശം ഇന്റർനെറ്റ് കണക്ഷനാണുള്ളത്."</string>
    -     <string name="wifi_connect_alert_title" msgid="8455846016001810172">"കണക്ഷൻ അനുവദിക്കണോ?"</string>
    -@@ -1153,7 +1165,6 @@
    -     <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"ഭാഷയും ലേഔട്ടും തിരഞ്ഞെടുക്കുന്നതിന് ടാപ്പുചെയ്യുക"</string>
    -     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
    -     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
    --    <string name="candidates_style" msgid="4333913089637062257"><u>"കാൻഡിഡേറ്റുകൾ"</u></string>
    -     <string name="ext_media_checking_notification_title" msgid="5734005953288045806">"<xliff:g id="NAME">%s</xliff:g> തയ്യാറാകുന്നു"</string>
    -     <string name="ext_media_checking_notification_message" msgid="4747432538578886744">"പിശകുകളുണ്ടോയെന്നു പരിശോധിക്കുന്നു"</string>
    -     <string name="ext_media_new_notification_message" msgid="7589986898808506239">"പുതിയ <xliff:g id="NAME">%s</xliff:g> എന്നതിനെ തിരിച്ചറിഞ്ഞു"</string>
    -@@ -1232,8 +1243,9 @@
    -     <string name="vpn_text_long" msgid="4907843483284977618">"<xliff:g id="SESSION">%s</xliff:g> എന്ന സെഷനിലേക്ക് കണക്റ്റുചെയ്തു. നെറ്റ്‌വർക്ക് മാനേജുചെയ്യാൻ ടാപ്പുചെയ്യുക."</string>
    -     <string name="vpn_lockdown_connecting" msgid="6443438964440960745">"എല്ലായ്‌പ്പോഴും ഓണായിരിക്കുന്ന VPN കണക്റ്റുചെയ്യുന്നു…"</string>
    -     <string name="vpn_lockdown_connected" msgid="8202679674819213931">"എല്ലായ്‌പ്പോഴും ഓണായിരിക്കുന്ന VPN കണക്റ്റുചെയ്‌തു"</string>
    -+    <string name="vpn_lockdown_disconnected" msgid="4532298952570796327">"\'എല്ലായ്‌പ്പോഴും ഓണായിരിക്കുന്ന VPN\' വിച്ഛേദിച്ചു"</string>
    -     <string name="vpn_lockdown_error" msgid="6009249814034708175">"എല്ലായ്‌പ്പോഴും ഓണായിരിക്കുന്ന VPN പിശക്"</string>
    --    <string name="vpn_lockdown_config" msgid="4655589351146766608">"കോൺഫിഗർ ചെയ്യുന്നതിന് ടാപ്പുചെയ്യുക"</string>
    -+    <string name="vpn_lockdown_config" msgid="5099330695245008680">"സജ്ജമാക്കാൻ ടാപ്പുചെയ്യുക"</string>
    -     <string name="upload_file" msgid="2897957172366730416">"ഫയല്‍‌ തിരഞ്ഞെടുക്കുക"</string>
    -     <string name="no_file_chosen" msgid="6363648562170759465">"ഫയലൊന്നും തിരഞ്ഞെടുത്തില്ല"</string>
    -     <string name="reset" msgid="2448168080964209908">"പുനഃസജ്ജമാക്കുക"</string>
    -@@ -1317,7 +1329,7 @@
    -     <string name="storage_usb_drive_label" msgid="4501418548927759953">"<xliff:g id="MANUFACTURER">%s</xliff:g> USB ഡ്രൈവ്"</string>
    -     <string name="storage_usb" msgid="3017954059538517278">"USB സ്റ്റോറേജ്"</string>
    -     <string name="extract_edit_menu_button" msgid="8940478730496610137">"എഡിറ്റുചെയ്യുക"</string>
    --    <string name="data_usage_warning_title" msgid="1955638862122232342">"ഡാറ്റ ഉപയോഗ മുന്നറിയിപ്പ്"</string>
    -+    <string name="data_usage_warning_title" msgid="3620440638180218181">"ഡാറ്റാ ഉപയോഗ മുന്നറിയിപ്പ്"</string>
    -     <string name="data_usage_warning_body" msgid="6660692274311972007">"ഉപയോഗവും ക്രമീകരണവും കാണാൻ ടാപ്പുചെയ്യുക."</string>
    -     <string name="data_usage_3g_limit_title" msgid="4361523876818447683">"2G-3G ഡാറ്റ പരിധിയിലെത്തി"</string>
    -     <string name="data_usage_4g_limit_title" msgid="4609566827219442376">"4G ഡാറ്റ പരിധിയിലെത്തി"</string>
    -@@ -1636,6 +1648,7 @@
    -     <string name="search_language_hint" msgid="7042102592055108574">"ഭാഷയുടെ പേര് ടൈപ്പുചെയ്യുക"</string>
    -     <string name="language_picker_section_suggested" msgid="8414489646861640885">"നിര്‍‌ദ്ദേശിച്ചത്"</string>
    -     <string name="language_picker_section_all" msgid="3097279199511617537">"എല്ലാ ഭാഷകളും"</string>
    -+    <string name="region_picker_section_all" msgid="8966316787153001779">"എല്ലാ പ്രദേശങ്ങളും"</string>
    -     <string name="locale_search_menu" msgid="2560710726687249178">"തിരയുക"</string>
    -     <string name="work_mode_off_title" msgid="8954725060677558855">"ഔദ്യോഗിക മോഡ് ഓഫാണ്"</string>
    -     <string name="work_mode_off_message" msgid="3286169091278094476">"ആപ്സും, പശ്ചാത്തല സമന്വയവും ബന്ധപ്പെട്ട ഫീച്ചറുകളും ഉൾപ്പെടെ, ഔദ്യോഗിക പ്രൊഫൈലിനെ പ്രവർത്തിക്കാൻ അനുവദിക്കുക."</string>
    -diff --git a/core/res/res/values-mn-rMN/strings.xml b/core/res/res/values-mn-rMN/strings.xml
    -index 5f384a1..f936b85 100644
    ---- a/core/res/res/values-mn-rMN/strings.xml
    -+++ b/core/res/res/values-mn-rMN/strings.xml
    -@@ -214,6 +214,7 @@
    -     <string name="global_actions" product="default" msgid="2406416831541615258">"Утасны сонголтууд"</string>
    -     <string name="global_action_lock" msgid="2844945191792119712">"Дэлгэцний түгжээ"</string>
    -     <string name="global_action_power_off" msgid="4471879440839879722">"Унтраах"</string>
    -+    <string name="global_action_emergency" msgid="7112311161137421166">"Яаралтай тусламж"</string>
    -     <string name="global_action_bug_report" msgid="7934010578922304799">"Алдаа мэдээллэх"</string>
    -     <string name="bugreport_title" msgid="2667494803742548533">"Согог репорт авах"</string>
    -     <string name="bugreport_message" msgid="398447048750350456">"Энэ таны төхөөрөмжийн одоогийн статусын талаарх мэдээллийг цуглуулах ба имэйл мессеж болгон илгээнэ. Алдааны мэдэгдлээс эхэлж илгээхэд бэлэн болоход хэсэг хугацаа зарцуулагдана тэвчээртэй байна уу."</string>
    -@@ -1076,6 +1077,17 @@
    -     <skip />
    -     <string name="wifi_no_internet" msgid="8451173622563841546">"Wi-Fi-д интернет холболт байхгүй байна"</string>
    -     <string name="wifi_no_internet_detailed" msgid="8083079241212301741">"Сонголт хийхийн тулд товшино уу"</string>
    -+    <string name="network_switch_metered" msgid="4671730921726992671">"<xliff:g id="NETWORK_TYPE">%1$s</xliff:g> руу шилжүүлсэн"</string>
    -+    <string name="network_switch_metered_detail" msgid="5325661434777870353">"<xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> интернэт холболтгүй үед төхөөрөмж <xliff:g id="NEW_NETWORK">%1$s</xliff:g>-г ашигладаг. Төлбөр гарч болзошгүй."</string>
    -+    <string name="network_switch_metered_toast" msgid="5779283181685974304">"<xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g>-с <xliff:g id="NEW_NETWORK">%2$s</xliff:g> руу шилжүүлсэн"</string>
    -+  <string-array name="network_switch_type_name">
    -+    <item msgid="2952042958050315394">"мобайл дата"</item>
    -+    <item msgid="75483255295529161">"Wi-Fi"</item>
    -+    <item msgid="6862614801537202646">"Bluetooth"</item>
    -+    <item msgid="5447331121797802871">"Этернэт"</item>
    -+    <item msgid="8257233890381651999">"VPN"</item>
    -+  </string-array>
    -+    <string name="network_switch_type_name_unknown" msgid="4552612897806660656">"сүлжээний тодорхойгүй төрөл"</string>
    -     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Wi-Fi-д холбогдож чадсангүй"</string>
    -     <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" Интернет холболт муу байна."</string>
    -     <string name="wifi_connect_alert_title" msgid="8455846016001810172">"Холболтыг зөвшөөрөх үү?"</string>
    -@@ -1153,7 +1165,6 @@
    -     <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"Хэл болон бүдүүвчийг сонгохын тулд дарна уу"</string>
    -     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
    -     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
    --    <string name="candidates_style" msgid="4333913089637062257"><u>"нэр дэвшигч"</u></string>
    -     <string name="ext_media_checking_notification_title" msgid="5734005953288045806">"<xliff:g id="NAME">%s</xliff:g>-ыг бэлдэж байна"</string>
    -     <string name="ext_media_checking_notification_message" msgid="4747432538578886744">"Алдааг шалгаж байна"</string>
    -     <string name="ext_media_new_notification_message" msgid="7589986898808506239">"Шинэ <xliff:g id="NAME">%s</xliff:g> илэрлээ"</string>
    -@@ -1232,8 +1243,9 @@
    -     <string name="vpn_text_long" msgid="4907843483284977618">"<xliff:g id="SESSION">%s</xliff:g>-д холбогдов. Сүлжээг удирдах бол товшино уу."</string>
    -     <string name="vpn_lockdown_connecting" msgid="6443438964440960745">"Байнгын VPN-д холбогдож байна..."</string>
    -     <string name="vpn_lockdown_connected" msgid="8202679674819213931">"Байнга VPN холбоотой"</string>
    -+    <string name="vpn_lockdown_disconnected" msgid="4532298952570796327">"Тогтмол асаалттай VPN салсан"</string>
    -     <string name="vpn_lockdown_error" msgid="6009249814034708175">"Байнгын VPN алдаа"</string>
    --    <string name="vpn_lockdown_config" msgid="4655589351146766608">"Тохируулахын тулд товшино уу"</string>
    -+    <string name="vpn_lockdown_config" msgid="5099330695245008680">"Тохируулахын тулд товшино уу"</string>
    -     <string name="upload_file" msgid="2897957172366730416">"Файл сонгох"</string>
    -     <string name="no_file_chosen" msgid="6363648562170759465">"Сонгосон файл байхгүй"</string>
    -     <string name="reset" msgid="2448168080964209908">"Бүгдийг цэвэрлэх"</string>
    -@@ -1317,7 +1329,7 @@
    -     <string name="storage_usb_drive_label" msgid="4501418548927759953">"<xliff:g id="MANUFACTURER">%s</xliff:g> USB диск"</string>
    -     <string name="storage_usb" msgid="3017954059538517278">"USB сан"</string>
    -     <string name="extract_edit_menu_button" msgid="8940478730496610137">"Засах"</string>
    --    <string name="data_usage_warning_title" msgid="1955638862122232342">"Дата хэрэглээний анхааруулга"</string>
    -+    <string name="data_usage_warning_title" msgid="3620440638180218181">"Дата ашиглалтын сануулга"</string>
    -     <string name="data_usage_warning_body" msgid="6660692274311972007">"Хэрэглээ, тохиргоог харах бол товш."</string>
    -     <string name="data_usage_3g_limit_title" msgid="4361523876818447683">"2G-3G дата хязгаарт хүрсэн"</string>
    -     <string name="data_usage_4g_limit_title" msgid="4609566827219442376">"4G дата хязгаарт хүрсэн"</string>
    -@@ -1634,6 +1646,7 @@
    -     <string name="search_language_hint" msgid="7042102592055108574">"Улсын хэлийг бичнэ үү"</string>
    -     <string name="language_picker_section_suggested" msgid="8414489646861640885">"Санал болгосон"</string>
    -     <string name="language_picker_section_all" msgid="3097279199511617537">"Бүх хэл"</string>
    -+    <string name="region_picker_section_all" msgid="8966316787153001779">"Бүх бүс нутаг"</string>
    -     <string name="locale_search_menu" msgid="2560710726687249178">"Хайх"</string>
    -     <string name="work_mode_off_title" msgid="8954725060677558855">"Ажлын горимыг УНТРААСАН байна"</string>
    -     <string name="work_mode_off_message" msgid="3286169091278094476">"Ажлын профайлд апп, дэвсгэр синхрончлол болон бусад холбоотой тохиргоог ажиллахыг зөвшөөрнө үү."</string>
    -diff --git a/core/res/res/values-mr-rIN/strings.xml b/core/res/res/values-mr-rIN/strings.xml
    -index 36d6f6a..8951643 100644
    ---- a/core/res/res/values-mr-rIN/strings.xml
    -+++ b/core/res/res/values-mr-rIN/strings.xml
    -@@ -214,6 +214,7 @@
    -     <string name="global_actions" product="default" msgid="2406416831541615258">"फोन पर्याय"</string>
    -     <string name="global_action_lock" msgid="2844945191792119712">"स्क्रीन लॉक"</string>
    -     <string name="global_action_power_off" msgid="4471879440839879722">"बंद"</string>
    -+    <string name="global_action_emergency" msgid="7112311161137421166">"आणीबाणी"</string>
    -     <string name="global_action_bug_report" msgid="7934010578922304799">"दोष अहवाल"</string>
    -     <string name="bugreport_title" msgid="2667494803742548533">"दोष अहवाल घ्या"</string>
    -     <string name="bugreport_message" msgid="398447048750350456">"ई-मेल संदेश म्हणून पाठविण्यासाठी, हे आपल्या वर्तमान डिव्हाइस स्थितीविषयी माहिती संकलित करेल. दोष अहवाल प्रारंभ करण्यापासून तो पाठविण्यापर्यंत थोडा वेळ लागेल; कृपया धीर धरा."</string>
    -@@ -1074,8 +1075,19 @@
    -     <string name="network_available_sign_in" msgid="1848877297365446605">"नेटवर्कवर साइन इन करा"</string>
    -     <!-- no translation found for network_available_sign_in_detailed (8000081941447976118) -->
    -     <skip />
    --    <string name="wifi_no_internet" msgid="8451173622563841546">"वाय-फाय मध्‍ये इंटरनेट प्रवेश नाही"</string>
    -+    <string name="wifi_no_internet" msgid="8451173622563841546">"वाय-फायवरून इंटरनेटवर प्रवेश नाही"</string>
    -     <string name="wifi_no_internet_detailed" msgid="8083079241212301741">"पर्यायांसाठी टॅप करा"</string>
    -+    <string name="network_switch_metered" msgid="4671730921726992671">"<xliff:g id="NETWORK_TYPE">%1$s</xliff:g> वर स्विच केले"</string>
    -+    <string name="network_switch_metered_detail" msgid="5325661434777870353">"<xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> कडे इंटरनेट प्रवेश नसताना डिव्हाइस <xliff:g id="NEW_NETWORK">%1$s</xliff:g> वापरतो. शुल्क लागू शकतील."</string>
    -+    <string name="network_switch_metered_toast" msgid="5779283181685974304">"<xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> वरून <xliff:g id="NEW_NETWORK">%2$s</xliff:g> वर स्विच केले"</string>
    -+  <string-array name="network_switch_type_name">
    -+    <item msgid="2952042958050315394">"मोबाइल डेटा"</item>
    -+    <item msgid="75483255295529161">"वाय-फाय"</item>
    -+    <item msgid="6862614801537202646">"ब्लूटुथ"</item>
    -+    <item msgid="5447331121797802871">"इथरनेट"</item>
    -+    <item msgid="8257233890381651999">"VPN"</item>
    -+  </string-array>
    -+    <string name="network_switch_type_name_unknown" msgid="4552612897806660656">"अज्ञात नेटवर्क प्रकार"</string>
    -     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"वाय-फाय ला कनेक्ट करू शकलो नाही"</string>
    -     <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" खराब इंटरनेट कनेक्शन आहे."</string>
    -     <string name="wifi_connect_alert_title" msgid="8455846016001810172">"कनेक्शनला अनुमती द्यायची?"</string>
    -@@ -1153,7 +1165,6 @@
    -     <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"भाषा आणि लेआउट निवडण्यासाठी टॅप करा"</string>
    -     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
    -     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
    --    <string name="candidates_style" msgid="4333913089637062257"><u>"उमेदवार"</u></string>
    -     <string name="ext_media_checking_notification_title" msgid="5734005953288045806">"<xliff:g id="NAME">%s</xliff:g> तयार करीत आहे"</string>
    -     <string name="ext_media_checking_notification_message" msgid="4747432538578886744">"त्रुटींसाठी तपासत आहे"</string>
    -     <string name="ext_media_new_notification_message" msgid="7589986898808506239">"नवीन <xliff:g id="NAME">%s</xliff:g> आढळले"</string>
    -@@ -1232,8 +1243,9 @@
    -     <string name="vpn_text_long" msgid="4907843483284977618">"<xliff:g id="SESSION">%s</xliff:g> शी कनेक्ट केले. नेटवर्क व्यवस्थापित करण्यासाठी टॅप करा."</string>
    -     <string name="vpn_lockdown_connecting" msgid="6443438964440960745">"VPN कनेक्ट करणे नेहमी-चालू…"</string>
    -     <string name="vpn_lockdown_connected" msgid="8202679674819213931">"VPN कनेक्ट केलेले नेहमी-चालू"</string>
    -+    <string name="vpn_lockdown_disconnected" msgid="4532298952570796327">"नेहमी-चालू असलेले VPN डिस्कनेक्ट केले"</string>
    -     <string name="vpn_lockdown_error" msgid="6009249814034708175">"VPN त्रुटी नेहमी-चालू"</string>
    --    <string name="vpn_lockdown_config" msgid="4655589351146766608">"कॉन्फिगर करण्यासाठी टॅप करा"</string>
    -+    <string name="vpn_lockdown_config" msgid="5099330695245008680">"सेट करण्यासाठी टॅप करा"</string>
    -     <string name="upload_file" msgid="2897957172366730416">"फाईल निवडा"</string>
    -     <string name="no_file_chosen" msgid="6363648562170759465">"फाईल निवडली नाही"</string>
    -     <string name="reset" msgid="2448168080964209908">"रीसेट करा"</string>
    -@@ -1317,7 +1329,7 @@
    -     <string name="storage_usb_drive_label" msgid="4501418548927759953">"<xliff:g id="MANUFACTURER">%s</xliff:g> USB ड्राइव्‍ह"</string>
    -     <string name="storage_usb" msgid="3017954059538517278">"USB संचयन"</string>
    -     <string name="extract_edit_menu_button" msgid="8940478730496610137">"संपादित करा"</string>
    --    <string name="data_usage_warning_title" msgid="1955638862122232342">"डेटा वापर चेतावणी"</string>
    -+    <string name="data_usage_warning_title" msgid="3620440638180218181">"डेटा वापर सूचना"</string>
    -     <string name="data_usage_warning_body" msgid="6660692274311972007">"वापर आणि सेटिंग्ज पाहण्यासाठी टॅप करा."</string>
    -     <string name="data_usage_3g_limit_title" msgid="4361523876818447683">"2G-3G डेटा मर्यादा गाठली"</string>
    -     <string name="data_usage_4g_limit_title" msgid="4609566827219442376">"4G डेटा मर्यादा गाठली"</string>
    -@@ -1636,6 +1648,7 @@
    -     <string name="search_language_hint" msgid="7042102592055108574">"भाषा नाव टाइप करा"</string>
    -     <string name="language_picker_section_suggested" msgid="8414489646861640885">"सूचित केलेले"</string>
    -     <string name="language_picker_section_all" msgid="3097279199511617537">"सर्व भाषा"</string>
    -+    <string name="region_picker_section_all" msgid="8966316787153001779">"सर्व प्रदेश"</string>
    -     <string name="locale_search_menu" msgid="2560710726687249178">"शोध"</string>
    -     <string name="work_mode_off_title" msgid="8954725060677558855">"कार्य मोड बंद आहे"</string>
    -     <string name="work_mode_off_message" msgid="3286169091278094476">"कार्य प्रोफाइलला अॅप्स, पार्श्वभूमी संकालन आणि संबंधित वैशिष्ट्यांच्या समावेशासह कार्य करण्याची परवानगी द्या."</string>
    -diff --git a/core/res/res/values-ms-rMY/strings.xml b/core/res/res/values-ms-rMY/strings.xml
    -index 7db5c74..e096aec 100644
    ---- a/core/res/res/values-ms-rMY/strings.xml
    -+++ b/core/res/res/values-ms-rMY/strings.xml
    -@@ -214,6 +214,7 @@
    -     <string name="global_actions" product="default" msgid="2406416831541615258">"Pilihan telefon"</string>
    -     <string name="global_action_lock" msgid="2844945191792119712">"Kunci skrin"</string>
    -     <string name="global_action_power_off" msgid="4471879440839879722">"Matikan kuasa"</string>
    -+    <string name="global_action_emergency" msgid="7112311161137421166">"Kecemasan"</string>
    -     <string name="global_action_bug_report" msgid="7934010578922304799">"Laporan pepijat"</string>
    -     <string name="bugreport_title" msgid="2667494803742548533">"Ambil laporan pepijat"</string>
    -     <string name="bugreport_message" msgid="398447048750350456">"Ini akan mengumpul maklumat tentang keadaan peranti semasa anda untuk dihantarkan sebagai mesej e-mel. Harap bersabar, mungkin perlu sedikit masa untuk memulakan laporan sehingga siap untuk dihantar."</string>
    -@@ -1076,6 +1077,17 @@
    -     <skip />
    -     <string name="wifi_no_internet" msgid="8451173622563841546">"Wi-Fi tiada akses Internet"</string>
    -     <string name="wifi_no_internet_detailed" msgid="8083079241212301741">"Ketik untuk mendapatkan pilihan"</string>
    -+    <string name="network_switch_metered" msgid="4671730921726992671">"Beralih kepada <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
    -+    <string name="network_switch_metered_detail" msgid="5325661434777870353">"Peranti menggunakan <xliff:g id="NEW_NETWORK">%1$s</xliff:g> apabila <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> tiada akses Internet. Bayaran mungkin dikenakan."</string>
    -+    <string name="network_switch_metered_toast" msgid="5779283181685974304">"Beralih daripada <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> kepada <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
    -+  <string-array name="network_switch_type_name">
    -+    <item msgid="2952042958050315394">"data selular"</item>
    -+    <item msgid="75483255295529161">"Wi-Fi"</item>
    -+    <item msgid="6862614801537202646">"Bluetooth"</item>
    -+    <item msgid="5447331121797802871">"Ethernet"</item>
    -+    <item msgid="8257233890381651999">"VPN"</item>
    -+  </string-array>
    -+    <string name="network_switch_type_name_unknown" msgid="4552612897806660656">"jenis rangkaian tidak diketahui"</string>
    -     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Tidak boleh menyambung kepada Wi-Fi"</string>
    -     <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" mempunyai sambungan internet yang kurang baik."</string>
    -     <string name="wifi_connect_alert_title" msgid="8455846016001810172">"Benarkan sambungan?"</string>
    -@@ -1153,7 +1165,6 @@
    -     <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"Ketik untuk memilih bahasa dan susun atur"</string>
    -     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
    -     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
    --    <string name="candidates_style" msgid="4333913089637062257"><u>"calon"</u></string>
    -     <string name="ext_media_checking_notification_title" msgid="5734005953288045806">"Menyediakan <xliff:g id="NAME">%s</xliff:g>"</string>
    -     <string name="ext_media_checking_notification_message" msgid="4747432538578886744">"Menyemak untuk mengesan ralat"</string>
    -     <string name="ext_media_new_notification_message" msgid="7589986898808506239">"<xliff:g id="NAME">%s</xliff:g> baharu dikesan"</string>
    -@@ -1232,8 +1243,9 @@
    -     <string name="vpn_text_long" msgid="4907843483284977618">"Bersambung kepada <xliff:g id="SESSION">%s</xliff:g>. Ketik untuk mengurus rangkaian."</string>
    -     <string name="vpn_lockdown_connecting" msgid="6443438964440960745">"VPN sentiasa hidup sedang disambungkan..."</string>
    -     <string name="vpn_lockdown_connected" msgid="8202679674819213931">"VPN sentiasa hidup telah disambungkan"</string>
    -+    <string name="vpn_lockdown_disconnected" msgid="4532298952570796327">"VPN sentiasa hidup diputuskan sambungannya"</string>
    -     <string name="vpn_lockdown_error" msgid="6009249814034708175">"Ralat VPN sentiasa hidup"</string>
    --    <string name="vpn_lockdown_config" msgid="4655589351146766608">"Ketik untuk membuat konfigurasi"</string>
    -+    <string name="vpn_lockdown_config" msgid="5099330695245008680">"Ketik untuk menyediakan"</string>
    -     <string name="upload_file" msgid="2897957172366730416">"Pilih fail"</string>
    -     <string name="no_file_chosen" msgid="6363648562170759465">"Tiada fail dipilih"</string>
    -     <string name="reset" msgid="2448168080964209908">"Tetapkan semula"</string>
    -@@ -1317,7 +1329,7 @@
    -     <string name="storage_usb_drive_label" msgid="4501418548927759953">"Pemacu USB <xliff:g id="MANUFACTURER">%s</xliff:g>"</string>
    -     <string name="storage_usb" msgid="3017954059538517278">"Storan USB"</string>
    -     <string name="extract_edit_menu_button" msgid="8940478730496610137">"Edit"</string>
    --    <string name="data_usage_warning_title" msgid="1955638862122232342">"Amaran penggunaan data"</string>
    -+    <string name="data_usage_warning_title" msgid="3620440638180218181">"Makluman penggunaan data"</string>
    -     <string name="data_usage_warning_body" msgid="6660692274311972007">"Ketik utk lihat p\'gunaan &amp; ttpn."</string>
    -     <string name="data_usage_3g_limit_title" msgid="4361523876818447683">"Mencapai had data 2G-3G"</string>
    -     <string name="data_usage_4g_limit_title" msgid="4609566827219442376">"Mencapai had data 4G"</string>
    -@@ -1636,6 +1648,7 @@
    -     <string name="search_language_hint" msgid="7042102592055108574">"Taipkan nama bahasa"</string>
    -     <string name="language_picker_section_suggested" msgid="8414489646861640885">"Dicadangkan"</string>
    -     <string name="language_picker_section_all" msgid="3097279199511617537">"Semua bahasa"</string>
    -+    <string name="region_picker_section_all" msgid="8966316787153001779">"Semua rantau"</string>
    -     <string name="locale_search_menu" msgid="2560710726687249178">"Cari"</string>
    -     <string name="work_mode_off_title" msgid="8954725060677558855">"Mod kerja DIMATIKAN"</string>
    -     <string name="work_mode_off_message" msgid="3286169091278094476">"Benarkan profil kerja berfungsi, termasuk apl, penyegerakan latar belakang dan ciri yang berkaitan."</string>
    -diff --git a/core/res/res/values-my-rMM/strings.xml b/core/res/res/values-my-rMM/strings.xml
    -index 077b889..80d331d 100644
    ---- a/core/res/res/values-my-rMM/strings.xml
    -+++ b/core/res/res/values-my-rMM/strings.xml
    -@@ -214,6 +214,7 @@
    -     <string name="global_actions" product="default" msgid="2406416831541615258">"ဖုန်းဆိုင်ရာရွေးချယ်မှုများ"</string>
    -     <string name="global_action_lock" msgid="2844945191792119712">"ဖုန်းမျက်နှာပြင်အား သော့ချရန်"</string>
    -     <string name="global_action_power_off" msgid="4471879440839879722">"ပါဝါပိတ်ရန်"</string>
    -+    <string name="global_action_emergency" msgid="7112311161137421166">"အရေးပေါ်"</string>
    -     <string name="global_action_bug_report" msgid="7934010578922304799">"အမှားရှာဖွေပြင်ဆင်မှုမှတ်တမ်း"</string>
    -     <string name="bugreport_title" msgid="2667494803742548533">"အမှားရှာဖွေပြင်ဆင်မှုမှတ်တမ်းအား ယူရန်"</string>
    -     <string name="bugreport_message" msgid="398447048750350456">"သင့်ရဲ့ လက်ရှိ စက်အခြေအနေ အချက်အလက်များကို အီးမေးလ် အနေဖြင့် ပေးပို့ရန် စုဆောင်းပါမည်။ အမှားရှာဖွေပြင်ဆင်မှုမှတ်တမ်းမှ ပေးပို့ရန် အသင့်ဖြစ်သည်အထိ အချိန် အနည်းငယ်ကြာမြင့်မှာ ဖြစ်သဖြင့် သည်းခံပြီး စောင့်ပါရန်"</string>
    -@@ -1076,6 +1077,17 @@
    -     <skip />
    -     <string name="wifi_no_internet" msgid="8451173622563841546">"ဝိုင်-ဖို်ငတွင် အင်တာနက် ဝင်ရောက်သုံးခွင့် မရှိပါ"</string>
    -     <string name="wifi_no_internet_detailed" msgid="8083079241212301741">"အခြားရွေးချယ်စရာများကိုကြည့်ရန် တို့ပါ"</string>
    -+    <string name="network_switch_metered" msgid="4671730921726992671">"<xliff:g id="NETWORK_TYPE">%1$s</xliff:g> သို့ ပြောင်းလိုက်ပြီ"</string>
    -+    <string name="network_switch_metered_detail" msgid="5325661434777870353">"စက်ပစ္စည်းသည် <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> ဖြင့် အင်တာနက် အသုံးမပြုနိုင်သည့်အချိန်တွင် <xliff:g id="NEW_NETWORK">%1$s</xliff:g> ကို သုံးပါသည်။ ဒေတာသုံးစွဲခ ကျသင့်နိုင်ပါသည်။"</string>
    -+    <string name="network_switch_metered_toast" msgid="5779283181685974304">"<xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> မှ <xliff:g id="NEW_NETWORK">%2$s</xliff:g> သို့ ပြောင်းလိုက်ပြီ"</string>
    -+  <string-array name="network_switch_type_name">
    -+    <item msgid="2952042958050315394">"ဆယ်လူလာဒေတာ"</item>
    -+    <item msgid="75483255295529161">"Wi-Fi"</item>
    -+    <item msgid="6862614801537202646">"ဘလူးတုသ်"</item>
    -+    <item msgid="5447331121797802871">"အီသာနက်"</item>
    -+    <item msgid="8257233890381651999">"VPN"</item>
    -+  </string-array>
    -+    <string name="network_switch_type_name_unknown" msgid="4552612897806660656">"အမည်မသိကွန်ရက်အမျိုးအစား"</string>
    -     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"ဝိုင်ဖိုင်ကိုချိတ်ဆက်မရပါ"</string>
    -     <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" အင်တာနက် ဆက်သွယ်မှု ကောင်းကောင်းမရှိပါ"</string>
    -     <string name="wifi_connect_alert_title" msgid="8455846016001810172">"ချိတ်ဆက်မှုကို ခွင့်ပြုမလား?"</string>
    -@@ -1153,7 +1165,6 @@
    -     <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"ဘာသာစကားနှင့် အသွင်အပြင်ရွေးချယ်ရန် တို့ပါ"</string>
    -     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
    -     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
    --    <string name="candidates_style" msgid="4333913089637062257"><u>"ရွေးချယ်ခံမည့်သူ"</u></string>
    -     <string name="ext_media_checking_notification_title" msgid="5734005953288045806">"<xliff:g id="NAME">%s</xliff:g> ပြင်ဆင်နေသည်"</string>
    -     <string name="ext_media_checking_notification_message" msgid="4747432538578886744">"အမှားအယွင်းများ စစ်ဆေးနေသည်"</string>
    -     <string name="ext_media_new_notification_message" msgid="7589986898808506239">"<xliff:g id="NAME">%s</xliff:g> အသစ်တွေ့ရှိပါသည်"</string>
    -@@ -1232,8 +1243,9 @@
    -     <string name="vpn_text_long" msgid="4907843483284977618">"<xliff:g id="SESSION">%s</xliff:g> သို့ ချိတ်ဆက်ထားသည်။ ကွန်ရက်ကို စီမံခန့်ခွဲရန် တို့ပါ။"</string>
    -     <string name="vpn_lockdown_connecting" msgid="6443438964440960745">"အမြဲတမ်းဖွင့်ထား VPN ဆက်သွယ်နေစဉ်…"</string>
    -     <string name="vpn_lockdown_connected" msgid="8202679674819213931">"အမြဲတမ်းဖွင့်ထား VPN ဆက်သွယ်မှုရှိ"</string>
    -+    <string name="vpn_lockdown_disconnected" msgid="4532298952570796327">"အမြဲတမ်းဖွင့်ထားရသော VPN ပြတ်တောက်နေသည်"</string>
    -     <string name="vpn_lockdown_error" msgid="6009249814034708175">"အမြဲတမ်းဖွင့်ထား VPN အမှား"</string>
    --    <string name="vpn_lockdown_config" msgid="4655589351146766608">"ပြင်ဆင်သတ်မှတ်ရန် တို့ပါ"</string>
    -+    <string name="vpn_lockdown_config" msgid="5099330695245008680">"ပြင်ဆင်သတ်မှတ်ရန် တို့ပါ"</string>
    -     <string name="upload_file" msgid="2897957172366730416">"ဖိုင်ရွေးချယ်ရန်"</string>
    -     <string name="no_file_chosen" msgid="6363648562170759465">"မည်သည့်ဖိုင်ကိုမှမရွေးပါ"</string>
    -     <string name="reset" msgid="2448168080964209908">"ပြန်လည်သတ်မှတ်ရန်"</string>
    -@@ -1317,7 +1329,7 @@
    -     <string name="storage_usb_drive_label" msgid="4501418548927759953">"<xliff:g id="MANUFACTURER">%s</xliff:g> USB ဒရိုက်ဗ်"</string>
    -     <string name="storage_usb" msgid="3017954059538517278">"USBဖြင့် သိမ်းဆည်း"</string>
    -     <string name="extract_edit_menu_button" msgid="8940478730496610137">"ပြင်ဆင်ရန်"</string>
    --    <string name="data_usage_warning_title" msgid="1955638862122232342">"ဒေတာအသုံးပြုမှုသတိပေးချက်"</string>
    -+    <string name="data_usage_warning_title" msgid="3620440638180218181">"ဒေတာအသုံးပြုမှုသတိပေးချက်"</string>
    -     <string name="data_usage_warning_body" msgid="6660692274311972007">"အသုံးပြုမှုနှင့် ဆက်တင်များကိုကြည့်ရန် တို့ပါ။"</string>
    -     <string name="data_usage_3g_limit_title" msgid="4361523876818447683">"2G-3G ဒေတာ ကန့်သတ်ချက် ပြည့်မီသွားပြီ"</string>
    -     <string name="data_usage_4g_limit_title" msgid="4609566827219442376">"4G ဒေတာ ကန့်သတ်ချက် ပြည့်မီသွားပြီ"</string>
    -@@ -1636,6 +1648,7 @@
    -     <string name="search_language_hint" msgid="7042102592055108574">"ဘာသာစကားအမည် ထည့်ပါ"</string>
    -     <string name="language_picker_section_suggested" msgid="8414489646861640885">"အကြံပြုထားသော"</string>
    -     <string name="language_picker_section_all" msgid="3097279199511617537">"ဘာသာစကားများအားလုံး"</string>
    -+    <string name="region_picker_section_all" msgid="8966316787153001779">"ဒေသအားလုံး"</string>
    -     <string name="locale_search_menu" msgid="2560710726687249178">"ရှာဖွေရန်"</string>
    -     <string name="work_mode_off_title" msgid="8954725060677558855">"အလုပ်မုဒ် ပိတ်ထားသည်"</string>
    -     <string name="work_mode_off_message" msgid="3286169091278094476">"အက်ပ်များ၊ နောက်ခံစင့်ခ်လုပ်ခြင်း၊ နှင့်သက်ဆိုင်သည့်အင်္ဂါရပ်များကို ဆောင်ရွက်ရန် အလုပ်ပရိုဖိုင်ကိုခွင့်ပြုပါ။"</string>
    -diff --git a/core/res/res/values-nb/strings.xml b/core/res/res/values-nb/strings.xml
    -index c9b275c..691da31 100644
    ---- a/core/res/res/values-nb/strings.xml
    -+++ b/core/res/res/values-nb/strings.xml
    -@@ -214,6 +214,7 @@
    -     <string name="global_actions" product="default" msgid="2406416831541615258">"Telefoninnstillinger"</string>
    -     <string name="global_action_lock" msgid="2844945191792119712">"Lås skjermen"</string>
    -     <string name="global_action_power_off" msgid="4471879440839879722">"Slå av"</string>
    -+    <string name="global_action_emergency" msgid="7112311161137421166">"Nødssituasjon"</string>
    -     <string name="global_action_bug_report" msgid="7934010578922304799">"Feilrapport"</string>
    -     <string name="bugreport_title" msgid="2667494803742548533">"Utfør feilrapport"</string>
    -     <string name="bugreport_message" msgid="398447048750350456">"Informasjon om tilstanden til enheten din samles inn og sendes som en e-post. Det tar litt tid fra du starter feilrapporten til e-posten er klar, så vær tålmodig."</string>
    -@@ -1076,6 +1077,17 @@
    -     <skip />
    -     <string name="wifi_no_internet" msgid="8451173622563841546">"Wi-Fi har ikke Internett-tilgang"</string>
    -     <string name="wifi_no_internet_detailed" msgid="8083079241212301741">"Trykk for å få alternativer"</string>
    -+    <string name="network_switch_metered" msgid="4671730921726992671">"Byttet til <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
    -+    <string name="network_switch_metered_detail" msgid="5325661434777870353">"Enheten bruker <xliff:g id="NEW_NETWORK">%1$s</xliff:g> når <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> ikke har Internett-tilgang. Avgifter kan påløpe."</string>
    -+    <string name="network_switch_metered_toast" msgid="5779283181685974304">"Byttet fra <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> til <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
    -+  <string-array name="network_switch_type_name">
    -+    <item msgid="2952042958050315394">"mobildata"</item>
    -+    <item msgid="75483255295529161">"Wi-Fi"</item>
    -+    <item msgid="6862614801537202646">"Bluetooth"</item>
    -+    <item msgid="5447331121797802871">"Ethernet"</item>
    -+    <item msgid="8257233890381651999">"VPN"</item>
    -+  </string-array>
    -+    <string name="network_switch_type_name_unknown" msgid="4552612897806660656">"en ukjent nettverkstype"</string>
    -     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Kan ikke koble til Wi-Fi"</string>
    -     <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" har en dårlig Internett-tilkobling."</string>
    -     <string name="wifi_connect_alert_title" msgid="8455846016001810172">"Vil du tillat tilkoblingen?"</string>
    -@@ -1153,7 +1165,6 @@
    -     <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"Trykk for å velge språk og layout"</string>
    -     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZÆØÅ"</string>
    -     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZÆØÅ"</string>
    --    <string name="candidates_style" msgid="4333913089637062257">"TAG_FONT"<u>"kandidater"</u>"CLOSE_FONT"</string>
    -     <string name="ext_media_checking_notification_title" msgid="5734005953288045806">"Forbereder <xliff:g id="NAME">%s</xliff:g>"</string>
    -     <string name="ext_media_checking_notification_message" msgid="4747432538578886744">"Sjekker for feil"</string>
    -     <string name="ext_media_new_notification_message" msgid="7589986898808506239">"<xliff:g id="NAME">%s</xliff:g> ble oppdaget"</string>
    -@@ -1232,8 +1243,9 @@
    -     <string name="vpn_text_long" msgid="4907843483284977618">"Koblet til <xliff:g id="SESSION">%s</xliff:g>. Trykk for å administrere nettverket."</string>
    -     <string name="vpn_lockdown_connecting" msgid="6443438964440960745">"Alltid-på VPN kobler til ..."</string>
    -     <string name="vpn_lockdown_connected" msgid="8202679674819213931">"Alltid-på VPN er tilkoblet"</string>
    -+    <string name="vpn_lockdown_disconnected" msgid="4532298952570796327">"Alltid på-VPN er frakoblet"</string>
    -     <string name="vpn_lockdown_error" msgid="6009249814034708175">"Alltid-på VPN-feil"</string>
    --    <string name="vpn_lockdown_config" msgid="4655589351146766608">"Trykk for å konfigurere"</string>
    -+    <string name="vpn_lockdown_config" msgid="5099330695245008680">"Trykk for å konfigurere"</string>
    -     <string name="upload_file" msgid="2897957172366730416">"Velg fil"</string>
    -     <string name="no_file_chosen" msgid="6363648562170759465">"Ingen fil er valgt"</string>
    -     <string name="reset" msgid="2448168080964209908">"Tilbakestill"</string>
    -@@ -1317,7 +1329,7 @@
    -     <string name="storage_usb_drive_label" msgid="4501418548927759953">"<xliff:g id="MANUFACTURER">%s</xliff:g> USB-stasjon"</string>
    -     <string name="storage_usb" msgid="3017954059538517278">"USB-lagring"</string>
    -     <string name="extract_edit_menu_button" msgid="8940478730496610137">"Rediger"</string>
    --    <string name="data_usage_warning_title" msgid="1955638862122232342">"Advarsel for høyt dataforbruk"</string>
    -+    <string name="data_usage_warning_title" msgid="3620440638180218181">"Varsel om databruk"</string>
    -     <string name="data_usage_warning_body" msgid="6660692274311972007">"Trykk for å se bruken og innstillingene."</string>
    -     <string name="data_usage_3g_limit_title" msgid="4361523876818447683">"Datagrensen for 2G-3G er nådd"</string>
    -     <string name="data_usage_4g_limit_title" msgid="4609566827219442376">"Datagrensen for 4G er nådd"</string>
    -@@ -1636,6 +1648,7 @@
    -     <string name="search_language_hint" msgid="7042102592055108574">"Skriv inn språknavn"</string>
    -     <string name="language_picker_section_suggested" msgid="8414489646861640885">"Foreslått"</string>
    -     <string name="language_picker_section_all" msgid="3097279199511617537">"Alle språk"</string>
    -+    <string name="region_picker_section_all" msgid="8966316787153001779">"Alle områder"</string>
    -     <string name="locale_search_menu" msgid="2560710726687249178">"Søk"</string>
    -     <string name="work_mode_off_title" msgid="8954725060677558855">"Jobbmodus er AV"</string>
    -     <string name="work_mode_off_message" msgid="3286169091278094476">"Slå på jobbprofilen, inkludert apper, synkronisering i bakgrunnen og relaterte funksjoner."</string>
    -diff --git a/core/res/res/values-ne-rNP/strings.xml b/core/res/res/values-ne-rNP/strings.xml
    -index a0dcfeb..3d5cfed 100644
    ---- a/core/res/res/values-ne-rNP/strings.xml
    -+++ b/core/res/res/values-ne-rNP/strings.xml
    -@@ -214,6 +214,7 @@
    -     <string name="global_actions" product="default" msgid="2406416831541615258">"फोन विकल्पहरू"</string>
    -     <string name="global_action_lock" msgid="2844945191792119712">"स्क्रिन बन्द"</string>
    -     <string name="global_action_power_off" msgid="4471879440839879722">"बन्द गर्नुहोस्"</string>
    -+    <string name="global_action_emergency" msgid="7112311161137421166">"आपतकालीन"</string>
    -     <string name="global_action_bug_report" msgid="7934010578922304799">"बग रिपोर्ट"</string>
    -     <string name="bugreport_title" msgid="2667494803742548533">"बग रिपोर्ट लिनुहोस्"</string>
    -     <string name="bugreport_message" msgid="398447048750350456">"एउटा इमेल सन्देशको रूपमा पठाउनलाई यसले तपाईँको हालैको उपकरणको अवस्थाको बारेमा सूचना जम्मा गर्ने छ। बग रिपोर्ट सुरु गरेदेखि पठाउन तयार नभएसम्म यसले केही समय लिन्छ; कृपया धैर्य गर्नुहोस्।"</string>
    -@@ -255,7 +256,7 @@
    -     <string name="permgrouplab_microphone" msgid="171539900250043464">"माइक्रोफोन"</string>
    -     <string name="permgroupdesc_microphone" msgid="4988812113943554584">"अडियो रेकर्ड गर्नुहोस्"</string>
    -     <string name="permgrouplab_camera" msgid="4820372495894586615">"क्यामेरा"</string>
    --    <string name="permgroupdesc_camera" msgid="3250611594678347720">"तस्बिर खिच्नुहोस् तथा भिडियो रेकर्ड गर्नुहोस्"</string>
    -+    <string name="permgroupdesc_camera" msgid="3250611594678347720">"तस्बिर खिच्नुका साथै भिडियो रेकर्ड गर्नुहोस्"</string>
    -     <string name="permgrouplab_phone" msgid="5229115638567440675">"फोन"</string>
    -     <string name="permgroupdesc_phone" msgid="6234224354060641055">"फोन कलहरू गर्नुहोस् र व्यवस्थापन गर्नुहोस्"</string>
    -     <string name="permgrouplab_sensors" msgid="416037179223226722">"शारीरिक सेन्सर"</string>
    -@@ -1082,6 +1083,17 @@
    -     <skip />
    -     <string name="wifi_no_internet" msgid="8451173622563841546">"Wi-Fi मा इन्टरनेट पहुँच छैन"</string>
    -     <string name="wifi_no_internet_detailed" msgid="8083079241212301741">"विकल्पहरूका लागि ट्याप गर्नुहोस्"</string>
    -+    <string name="network_switch_metered" msgid="4671730921726992671">"<xliff:g id="NETWORK_TYPE">%1$s</xliff:g> मा बदल्नुहोस्"</string>
    -+    <string name="network_switch_metered_detail" msgid="5325661434777870353">"<xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> मा इन्टरनेट माथिको पहुँच नहुँदा यन्त्रले <xliff:g id="NEW_NETWORK">%1$s</xliff:g> को प्रयोग गर्दछ। शुल्कहरू लागू हुन सक्छन्।"</string>
    -+    <string name="network_switch_metered_toast" msgid="5779283181685974304">"<xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> बाट <xliff:g id="NEW_NETWORK">%2$s</xliff:g> मा परिवर्तन गरियो"</string>
    -+  <string-array name="network_switch_type_name">
    -+    <item msgid="2952042958050315394">"सेलुलर डेटा"</item>
    -+    <item msgid="75483255295529161">"Wi-Fi"</item>
    -+    <item msgid="6862614801537202646">"ब्लुटुथ"</item>
    -+    <item msgid="5447331121797802871">"इथरनेट"</item>
    -+    <item msgid="8257233890381651999">"VPN"</item>
    -+  </string-array>
    -+    <string name="network_switch_type_name_unknown" msgid="4552612897806660656">"नेटवर्कको कुनै अज्ञात प्रकार"</string>
    -     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"वाइ-फाइसँग जडान गर्न सकेन"</string>
    -     <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" कमजोर इन्टरनेट जडान छ।"</string>
    -     <string name="wifi_connect_alert_title" msgid="8455846016001810172">"जडान अनुमति दिने हो?"</string>
    -@@ -1159,7 +1171,6 @@
    -     <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"भाषा र लेआउट चयन गर्न ट्याप गर्नुहोस्"</string>
    -     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
    -     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
    --    <string name="candidates_style" msgid="4333913089637062257"><u>"उम्मेदवार"</u></string>
    -     <string name="ext_media_checking_notification_title" msgid="5734005953288045806">"तयारी गर्दै <xliff:g id="NAME">%s</xliff:g>"</string>
    -     <string name="ext_media_checking_notification_message" msgid="4747432538578886744">"त्रुटिहरूको लागि जाँच गर्दै"</string>
    -     <string name="ext_media_new_notification_message" msgid="7589986898808506239">"नयाँ <xliff:g id="NAME">%s</xliff:g> भेटियो"</string>
    -@@ -1238,8 +1249,9 @@
    -     <string name="vpn_text_long" msgid="4907843483284977618">"<xliff:g id="SESSION">%s</xliff:g>सँग जोडिएको। नेटवर्क प्रबन्ध गर्न हान्नुहोस्।"</string>
    -     <string name="vpn_lockdown_connecting" msgid="6443438964440960745">"VPN जडान सधै जोड्दै…"</string>
    -     <string name="vpn_lockdown_connected" msgid="8202679674819213931">"सधैँ खुल्ला हुने VPN जोडिएको"</string>
    -+    <string name="vpn_lockdown_disconnected" msgid="4532298952570796327">"सधैँ-सक्रिय VPN लाई विच्छेद गरियो"</string>
    -     <string name="vpn_lockdown_error" msgid="6009249814034708175">"सधैँ भरि VPN त्रुटिमा"</string>
    --    <string name="vpn_lockdown_config" msgid="4655589351146766608">"कन्फिगर गर्न ट्याप गर्नुहोस्"</string>
    -+    <string name="vpn_lockdown_config" msgid="5099330695245008680">"सेट अप गर्न ट्याप गर्नुहोस्"</string>
    -     <string name="upload_file" msgid="2897957172366730416">"फाइल छान्नुहोस्"</string>
    -     <string name="no_file_chosen" msgid="6363648562170759465">"कुनै फाइल छानिएको छैन"</string>
    -     <string name="reset" msgid="2448168080964209908">"पुनःसेट गर्नु"</string>
    -@@ -1323,7 +1335,7 @@
    -     <string name="storage_usb_drive_label" msgid="4501418548927759953">"<xliff:g id="MANUFACTURER">%s</xliff:g> USB ड्राइभ"</string>
    -     <string name="storage_usb" msgid="3017954059538517278">"USB भण्डारण"</string>
    -     <string name="extract_edit_menu_button" msgid="8940478730496610137">"सम्पादन गर्नुहोस्"</string>
    --    <string name="data_usage_warning_title" msgid="1955638862122232342">"डेटाको प्रयोग चेतावनी"</string>
    -+    <string name="data_usage_warning_title" msgid="3620440638180218181">"डेटा प्रयोग बारे सतर्कता"</string>
    -     <string name="data_usage_warning_body" msgid="6660692274311972007">"प्रयोग र सेटिङहरू हेर्न ट्याप गर्नुहोस्।"</string>
    -     <string name="data_usage_3g_limit_title" msgid="4361523876818447683">"2G-3G डेटा सीमा पुग्यो"</string>
    -     <string name="data_usage_4g_limit_title" msgid="4609566827219442376">"4G डेटा सीमा पुग्यो"</string>
    -@@ -1642,6 +1654,7 @@
    -     <string name="search_language_hint" msgid="7042102592055108574">"भाषाको नाम टाइप गर्नुहोस्"</string>
    -     <string name="language_picker_section_suggested" msgid="8414489646861640885">"सुझाव दिइयो"</string>
    -     <string name="language_picker_section_all" msgid="3097279199511617537">"सम्पूर्ण भाषाहरू"</string>
    -+    <string name="region_picker_section_all" msgid="8966316787153001779">"सबै क्षेत्रहरू"</string>
    -     <string name="locale_search_menu" msgid="2560710726687249178">"खोज"</string>
    -     <string name="work_mode_off_title" msgid="8954725060677558855">"कार्य मोड बन्द छ"</string>
    -     <string name="work_mode_off_message" msgid="3286169091278094476">"अनुप्रयोग, पृष्ठभूमि सिंक र सम्बन्धित विशेषताहरू सहित, कार्य प्रोफाइललाई कार्य गर्न अनुमति दिनुहोस्।"</string>
    -diff --git a/core/res/res/values-nl/strings.xml b/core/res/res/values-nl/strings.xml
    -index d7f10d3..1f53e8d 100644
    ---- a/core/res/res/values-nl/strings.xml
    -+++ b/core/res/res/values-nl/strings.xml
    -@@ -214,6 +214,7 @@
    -     <string name="global_actions" product="default" msgid="2406416831541615258">"Telefoonopties"</string>
    -     <string name="global_action_lock" msgid="2844945191792119712">"Schermvergrendeling"</string>
    -     <string name="global_action_power_off" msgid="4471879440839879722">"Uitschakelen"</string>
    -+    <string name="global_action_emergency" msgid="7112311161137421166">"Noodgeval"</string>
    -     <string name="global_action_bug_report" msgid="7934010578922304799">"Foutenrapport"</string>
    -     <string name="bugreport_title" msgid="2667494803742548533">"Foutenrapport genereren"</string>
    -     <string name="bugreport_message" msgid="398447048750350456">"Hiermee worden gegevens over de huidige status van je apparaat verzameld en als e-mail verzonden. Wanneer u een foutenrapport start, duurt het even voordat het kan worden verzonden. Even geduld alstublieft."</string>
    -@@ -236,7 +237,7 @@
    -     <string name="global_action_voice_assist" msgid="7751191495200504480">"Spraakassistent"</string>
    -     <string name="global_action_lockdown" msgid="8751542514724332873">"Nu vergrendelen"</string>
    -     <string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999 +"</string>
    --    <string name="notification_hidden_text" msgid="1135169301897151909">"Inhoud verborgen"</string>
    -+    <string name="notification_hidden_text" msgid="1135169301897151909">"Content verborgen"</string>
    -     <string name="notification_hidden_by_policy_text" msgid="9004631276932584600">"Content verborgen op basis van beleid"</string>
    -     <string name="safeMode" msgid="2788228061547930246">"Veilige modus"</string>
    -     <string name="android_system_label" msgid="6577375335728551336">"Android-systeem"</string>
    -@@ -260,12 +261,12 @@
    -     <string name="permgroupdesc_phone" msgid="6234224354060641055">"bellen en telefoontjes beheren"</string>
    -     <string name="permgrouplab_sensors" msgid="416037179223226722">"Lichaamssensoren"</string>
    -     <string name="permgroupdesc_sensors" msgid="7147968539346634043">"toegang krijgen tot sensorgegevens over je vitale functies"</string>
    --    <string name="capability_title_canRetrieveWindowContent" msgid="3901717936930170320">"Inhoud van vensters ophalen"</string>
    --    <string name="capability_desc_canRetrieveWindowContent" msgid="3772225008605310672">"De inhoud inspecteren van een venster waarmee je interactie hebt."</string>
    -+    <string name="capability_title_canRetrieveWindowContent" msgid="3901717936930170320">"Content van vensters ophalen"</string>
    -+    <string name="capability_desc_canRetrieveWindowContent" msgid="3772225008605310672">"De content inspecteren van een venster waarmee je interactie hebt."</string>
    -     <string name="capability_title_canRequestTouchExploration" msgid="3108723364676667320">"\'Verkennen via aanraking\' inschakelen"</string>
    -     <string name="capability_desc_canRequestTouchExploration" msgid="7543249041581408313">"Aangetikte items worden hardop benoemd en het scherm kan worden verkend door middel van gebaren."</string>
    -     <string name="capability_title_canRequestEnhancedWebAccessibility" msgid="1739881766522594073">"Verbeterde internettoegankelijkheid inschakelen"</string>
    --    <string name="capability_desc_canRequestEnhancedWebAccessibility" msgid="7881063961507511765">"Er kunnen scripts worden geïnstalleerd om app-inhoud toegankelijker te maken."</string>
    -+    <string name="capability_desc_canRequestEnhancedWebAccessibility" msgid="7881063961507511765">"Er kunnen scripts worden geïnstalleerd om app-content toegankelijker te maken."</string>
    -     <string name="capability_title_canRequestFilterKeyEvents" msgid="2103440391902412174">"Tekst observeren die u typt"</string>
    -     <string name="capability_desc_canRequestFilterKeyEvents" msgid="7463135292204152818">"Omvat persoonlijke gegevens zoals creditcardnummers en wachtwoorden."</string>
    -     <string name="capability_title_canControlMagnification" msgid="3593493281059424855">"Schermvergroting bedienen"</string>
    -@@ -295,9 +296,9 @@
    -     <string name="permlab_sendSms" msgid="7544599214260982981">"sms\'jes verzenden en bekijken"</string>
    -     <string name="permdesc_sendSms" msgid="7094729298204937667">"Hiermee kan de app sms-berichten verzenden. Dit kan tot onverwachte kosten leiden. Schadelijke apps kunnen u geld kosten doordat ze zonder je bevestiging berichten kunnen verzenden."</string>
    -     <string name="permlab_readSms" msgid="8745086572213270480">"je tekstberichten (SMS of MMS) lezen"</string>
    --    <string name="permdesc_readSms" product="tablet" msgid="2467981548684735522">"Hiermee kan de app sms-berichten lezen die zijn opgeslagen op je tablet of simkaart. De app kan alle sms-berichten lezen, ongeacht inhoud of vertrouwelijkheid."</string>
    --    <string name="permdesc_readSms" product="tv" msgid="5102425513647038535">"Hiermee kan de app sms-berichten lezen die zijn opgeslagen op je tv of simkaart. De app kan alle sms-berichten lezen, ongeacht inhoud of vertrouwelijkheid."</string>
    --    <string name="permdesc_readSms" product="default" msgid="3695967533457240550">"Hiermee kan de app sms-berichten lezen die zijn opgeslagen op je telefoon of simkaart. De app kan alle sms-berichten lezen, ongeacht inhoud of vertrouwelijkheid."</string>
    -+    <string name="permdesc_readSms" product="tablet" msgid="2467981548684735522">"Hiermee kan de app sms-berichten lezen die zijn opgeslagen op je tablet of simkaart. De app kan alle sms-berichten lezen, ongeacht content of vertrouwelijkheid."</string>
    -+    <string name="permdesc_readSms" product="tv" msgid="5102425513647038535">"Hiermee kan de app sms-berichten lezen die zijn opgeslagen op je tv of simkaart. De app kan alle sms-berichten lezen, ongeacht content of vertrouwelijkheid."</string>
    -+    <string name="permdesc_readSms" product="default" msgid="3695967533457240550">"Hiermee kan de app sms-berichten lezen die zijn opgeslagen op je telefoon of simkaart. De app kan alle sms-berichten lezen, ongeacht content of vertrouwelijkheid."</string>
    -     <string name="permlab_receiveWapPush" msgid="5991398711936590410">"tekstberichten (WAP) ontvangen"</string>
    -     <string name="permdesc_receiveWapPush" msgid="748232190220583385">"Hiermee kan de app WAP-berichten ontvangen en verwerken. Dit betekent dat de app berichten die naar je apparaat zijn verzonden, kan bijhouden of verwijderen zonder deze aan u weer te geven."</string>
    -     <string name="permlab_getTasks" msgid="6466095396623933906">"actieve apps ophalen"</string>
    -@@ -459,12 +460,12 @@
    -     <string name="permdesc_writeSyncSettings" msgid="8956262591306369868">"Hiermee kan een app de synchronisatie-instellingen aanpassen voor een account. Deze toestemming kan bijvoorbeeld worden gebruikt om synchronisatie van de app Personen in te schakelen voor een account."</string>
    -     <string name="permlab_readSyncStats" msgid="7396577451360202448">"synchronisatiestatistieken lezen"</string>
    -     <string name="permdesc_readSyncStats" msgid="1510143761757606156">"Hiermee kan een app de synchronisatiestatistieken voor een account lezen, inclusief de geschiedenis van synchronisatie-activiteiten en hoeveel gegevens zijn gesynchroniseerd."</string>
    --    <string name="permlab_sdcardRead" product="nosdcard" msgid="367275095159405468">"de inhoud van je USB-opslag lezen"</string>
    --    <string name="permlab_sdcardRead" product="default" msgid="2188156462934977940">"de inhoud van je SD-kaart lezen"</string>
    --    <string name="permdesc_sdcardRead" product="nosdcard" msgid="3446988712598386079">"De app toestaan de inhoud van je USB-opslag te lezen."</string>
    --    <string name="permdesc_sdcardRead" product="default" msgid="2607362473654975411">"De app toestaan de inhoud van je SD-kaart te lezen."</string>
    --    <string name="permlab_sdcardWrite" product="nosdcard" msgid="8485979062254666748">"de inhoud van je USB-opslag aanpassen of verwijderen"</string>
    --    <string name="permlab_sdcardWrite" product="default" msgid="8805693630050458763">"de inhoud van je SD-kaart aanpassen of verwijderen"</string>
    -+    <string name="permlab_sdcardRead" product="nosdcard" msgid="367275095159405468">"de content van je USB-opslag lezen"</string>
    -+    <string name="permlab_sdcardRead" product="default" msgid="2188156462934977940">"de content van je SD-kaart lezen"</string>
    -+    <string name="permdesc_sdcardRead" product="nosdcard" msgid="3446988712598386079">"De app toestaan de content van je USB-opslag te lezen."</string>
    -+    <string name="permdesc_sdcardRead" product="default" msgid="2607362473654975411">"De app toestaan de content van je SD-kaart te lezen."</string>
    -+    <string name="permlab_sdcardWrite" product="nosdcard" msgid="8485979062254666748">"de content van je USB-opslag aanpassen of verwijderen"</string>
    -+    <string name="permlab_sdcardWrite" product="default" msgid="8805693630050458763">"de content van je SD-kaart aanpassen of verwijderen"</string>
    -     <string name="permdesc_sdcardWrite" product="nosdcard" msgid="6175406299445710888">"Hiermee kan de app schrijven naar de USB-opslag."</string>
    -     <string name="permdesc_sdcardWrite" product="default" msgid="4337417790936632090">"Hiermee kan de app schrijven naar de SD-kaart."</string>
    -     <string name="permlab_use_sip" msgid="2052499390128979920">"SIP-oproepen plaatsen/ontvangen"</string>
    -@@ -1076,6 +1077,17 @@
    -     <skip />
    -     <string name="wifi_no_internet" msgid="8451173622563841546">"Wifi-netwerk heeft geen internettoegang"</string>
    -     <string name="wifi_no_internet_detailed" msgid="8083079241212301741">"Tik voor opties"</string>
    -+    <string name="network_switch_metered" msgid="4671730921726992671">"Overgeschakeld naar <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
    -+    <string name="network_switch_metered_detail" msgid="5325661434777870353">"Apparaat gebruikt <xliff:g id="NEW_NETWORK">%1$s</xliff:g> wanneer <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> geen internetverbinding heeft. Er kunnen kosten in rekening worden gebracht."</string>
    -+    <string name="network_switch_metered_toast" msgid="5779283181685974304">"Overgeschakeld van <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> naar <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
    -+  <string-array name="network_switch_type_name">
    -+    <item msgid="2952042958050315394">"mobiele data"</item>
    -+    <item msgid="75483255295529161">"Wifi"</item>
    -+    <item msgid="6862614801537202646">"Bluetooth"</item>
    -+    <item msgid="5447331121797802871">"Ethernet"</item>
    -+    <item msgid="8257233890381651999">"VPN"</item>
    -+  </string-array>
    -+    <string name="network_switch_type_name_unknown" msgid="4552612897806660656">"een onbekend netwerktype"</string>
    -     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Kan geen verbinding maken met wifi"</string>
    -     <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" heeft een slechte internetverbinding."</string>
    -     <string name="wifi_connect_alert_title" msgid="8455846016001810172">"Verbinding toestaan?"</string>
    -@@ -1153,7 +1165,6 @@
    -     <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"Tik om een taal en indeling te selecteren"</string>
    -     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
    -     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
    --    <string name="candidates_style" msgid="4333913089637062257"><u>"kandidaten"</u></string>
    -     <string name="ext_media_checking_notification_title" msgid="5734005953288045806">"<xliff:g id="NAME">%s</xliff:g> voorbereiden"</string>
    -     <string name="ext_media_checking_notification_message" msgid="4747432538578886744">"Controleren op fouten"</string>
    -     <string name="ext_media_new_notification_message" msgid="7589986898808506239">"Nieuwe <xliff:g id="NAME">%s</xliff:g> gedetecteerd"</string>
    -@@ -1232,8 +1243,9 @@
    -     <string name="vpn_text_long" msgid="4907843483284977618">"Verbonden met <xliff:g id="SESSION">%s</xliff:g>. Tik om het netwerk te beheren."</string>
    -     <string name="vpn_lockdown_connecting" msgid="6443438964440960745">"Always-on VPN-verbinding maken…"</string>
    -     <string name="vpn_lockdown_connected" msgid="8202679674819213931">"Always-on VPN-verbinding"</string>
    -+    <string name="vpn_lockdown_disconnected" msgid="4532298952570796327">"Always-on VPN-verbinding ontkoppeld"</string>
    -     <string name="vpn_lockdown_error" msgid="6009249814034708175">"Fout met Always-on VPN"</string>
    --    <string name="vpn_lockdown_config" msgid="4655589351146766608">"Tik om te configureren"</string>
    -+    <string name="vpn_lockdown_config" msgid="5099330695245008680">"Tik om in te stellen"</string>
    -     <string name="upload_file" msgid="2897957172366730416">"Bestand kiezen"</string>
    -     <string name="no_file_chosen" msgid="6363648562170759465">"Geen bestand geselecteerd"</string>
    -     <string name="reset" msgid="2448168080964209908">"Resetten"</string>
    -@@ -1317,7 +1329,7 @@
    -     <string name="storage_usb_drive_label" msgid="4501418548927759953">"<xliff:g id="MANUFACTURER">%s</xliff:g> USB-drive"</string>
    -     <string name="storage_usb" msgid="3017954059538517278">"USB-opslag"</string>
    -     <string name="extract_edit_menu_button" msgid="8940478730496610137">"Bewerken"</string>
    --    <string name="data_usage_warning_title" msgid="1955638862122232342">"Waarschuwing v. gegevensgebruik"</string>
    -+    <string name="data_usage_warning_title" msgid="3620440638180218181">"Melding voor datagebruik"</string>
    -     <string name="data_usage_warning_body" msgid="6660692274311972007">"Tik voor gebruik en instellingen"</string>
    -     <string name="data_usage_3g_limit_title" msgid="4361523876818447683">"Gegevenslimiet van 2G-3G bereikt"</string>
    -     <string name="data_usage_4g_limit_title" msgid="4609566827219442376">"Gegevenslimiet van 4G bereikt"</string>
    -@@ -1515,7 +1527,7 @@
    -     <string name="mediasize_unknown_portrait" msgid="3088043641616409762">"Onbekend portret"</string>
    -     <string name="mediasize_unknown_landscape" msgid="4876995327029361552">"Onbekend landschap"</string>
    -     <string name="write_fail_reason_cancelled" msgid="7091258378121627624">"Geannuleerd"</string>
    --    <string name="write_fail_reason_cannot_write" msgid="8132505417935337724">"Fout bij schrijven van inhoud"</string>
    -+    <string name="write_fail_reason_cannot_write" msgid="8132505417935337724">"Fout bij schrijven van content"</string>
    -     <string name="reason_unknown" msgid="6048913880184628119">"onbekend"</string>
    -     <string name="reason_service_unavailable" msgid="7824008732243903268">"Afdrukservice niet ingeschakeld"</string>
    -     <string name="print_service_installed_title" msgid="2246317169444081628">"<xliff:g id="NAME">%s</xliff:g>-service geïnstalleerd"</string>
    -@@ -1636,6 +1648,7 @@
    -     <string name="search_language_hint" msgid="7042102592055108574">"Typ een taalnaam"</string>
    -     <string name="language_picker_section_suggested" msgid="8414489646861640885">"Voorgesteld"</string>
    -     <string name="language_picker_section_all" msgid="3097279199511617537">"Alle talen"</string>
    -+    <string name="region_picker_section_all" msgid="8966316787153001779">"Alle regio\'s"</string>
    -     <string name="locale_search_menu" msgid="2560710726687249178">"Zoeken"</string>
    -     <string name="work_mode_off_title" msgid="8954725060677558855">"Werkmodus is UIT"</string>
    -     <string name="work_mode_off_message" msgid="3286169091278094476">"Functioneren van werkprofiel toestaan, waaronder apps, synchronisatie op de achtergrond en gerelateerde functies."</string>
    -diff --git a/core/res/res/values-pa-rIN/strings.xml b/core/res/res/values-pa-rIN/strings.xml
    -index e717e69..9658e1e 100644
    ---- a/core/res/res/values-pa-rIN/strings.xml
    -+++ b/core/res/res/values-pa-rIN/strings.xml
    -@@ -214,6 +214,7 @@
    -     <string name="global_actions" product="default" msgid="2406416831541615258">"ਫੋਨ ਚੋਣਾਂ"</string>
    -     <string name="global_action_lock" msgid="2844945191792119712">"ਸਕ੍ਰੀਨ ਲੌਕ"</string>
    -     <string name="global_action_power_off" msgid="4471879440839879722">"ਪਾਵਰ ਬੰਦ"</string>
    -+    <string name="global_action_emergency" msgid="7112311161137421166">"ਸੰਕਟਕਾਲ"</string>
    -     <string name="global_action_bug_report" msgid="7934010578922304799">"ਬਗ ਰਿਪੋਰਟ"</string>
    -     <string name="bugreport_title" msgid="2667494803742548533">"ਬਗ ਰਿਪੋਰਟ ਲਓ"</string>
    -     <string name="bugreport_message" msgid="398447048750350456">"ਇਹ ਇੱਕ ਈ-ਮੇਲ ਸੁਨੇਹਾ ਭੇਜਣ ਲਈ, ਤੁਹਾਡੀ ਵਰਤਮਾਨ ਡੀਵਾਈਸ ਬਾਰੇ ਜਾਣਕਾਰੀ ਇਕੱਤਰ ਕਰੇਗਾ। ਬਗ ਰਿਪੋਰਟ ਸ਼ੁਰੂ ਕਰਨ ਵਿੱਚ ਥੋੜ੍ਹਾ ਸਮਾਂ ਲੱਗੇਗਾ ਜਦੋਂ ਤੱਕ ਇਹ ਭੇਜੇ ਜਾਣ ਲਈ ਤਿਆਰ ਨਾ ਹੋਵੇ, ਕਿਰਪਾ ਕਰਕੇ ਧੀਰਜ ਰੱਖੋ।"</string>
    -@@ -362,7 +363,7 @@
    -     <string name="permdesc_accessCoarseLocation" msgid="2538200184373302295">"ਐਪ ਨੂੰ ਤੁਹਾਡਾ ਅਨੁਮਾਨਿਤ ਨਿਰਧਾਰਿਤ ਸਥਾਨ ਪ੍ਰਾਪਤ ਕਰਨ ਦੀ ਆਗਿਆ ਦਿੰਦਾ ਹੈ। ਇਹ ਨਿਰਧਾਰਿਤ ਸਥਾਨ ਨੈੱਟਵਰਕ ਨਿਰਧਾਰਿਤ ਸਥਾਨ ਸਰੋਤ ਵਰਤਦੇ ਹੋਏ ਨਿਰਧਾਰਿਤ ਸਥਾਨ ਸੇਵਾਵਾਂ ਰਾਹੀਂ ਪ੍ਰਾਪਤ ਕੀਤਾ ਜਾਂਦਾ ਹੈ ਜਿਵੇਂ ਸੈਲ ਟਾਵਰ ਅਤੇ Wi-Fi. ਇਹ ਨਿਰਧਾਰਿਤ ਸਥਾਨ ਸੇਵਾਵਾਂ ਚਾਲੂ ਅਤੇ ਐਪ ਨੂੰ ਉਹਨਾਂ ਨੂੰ ਵਰਤਣ ਲਈ ਤੁਹਾਡੀ ਡੀਵਾਈਸ ਤੇ ਹੋਣੀਆਂ ਚਾਹੀਦੀਆਂ ਹਨ। ਐਪਸ ਇਸਦੀ ਵਰਤੋਂ ਇਹ ਅਨੁਮਾਨ ਲਗਾਉਣ ਲਈ ਕਰ ਸਕਦੇ ਹਨ ਕਿ ਤੁਸੀਂ ਕਿੱਥੇ ਹੋ।"</string>
    -     <string name="permlab_modifyAudioSettings" msgid="6095859937069146086">"ਆਪਣੀਆਂ ਔਡੀਓ ਸੈਟਿੰਗਾਂ ਬਦਲੋ"</string>
    -     <string name="permdesc_modifyAudioSettings" msgid="3522565366806248517">"ਔਪ ਨੂੰ ਗਲੋਬਲ ਔਡੀਓ ਸੈਟਿੰਗਾਂ ਸੰਸ਼ੋਧਿਤ ਕਰਨ ਦੀ ਆਗਿਆ ਦਿੰਦਾ ਹੈ ਜਿਵੇਂ ਵੌਲਿਊਮ ਅਤੇ ਆਊਟਪੁਟ ਲਈ ਕਿਹੜਾ ਸਪੀਕਰ ਵਰਤਿਆ ਜਾਂਦਾ ਹੈ।"</string>
    --    <string name="permlab_recordAudio" msgid="3876049771427466323">"ਔਡੀਓ ਰਿਕਾਰਡ ਕਰੋ"</string>
    -+    <string name="permlab_recordAudio" msgid="3876049771427466323">"ਔਡੀਓ ਰਿਕਾਰਡ ਕਰਨ"</string>
    -     <string name="permdesc_recordAudio" msgid="4906839301087980680">"ਐਪ ਨੂੰ ਮਾਈਕ੍ਰੋਫੋਨ ਨਾਲ ਔਡੀਓ ਰਿਕਾਰਡ ਕਰਨ ਦੀ ਆਗਿਆ ਦਿੰਦਾ ਹੈ। ਇਹ ਅਨੁਮਤੀ ਐਪ ਨੂੰ ਤੁਹਾਡੀ ਪੁਸ਼ਟੀ ਤੋਂ ਬਿਨਾਂ ਕਿਸੇ ਵੀ ਸਮੇਂ ਔਡੀਓ ਰਿਕਾਰਡ ਕਰਨ ਦੀ ਆਗਿਆ ਦਿੰਦੀ ਹੈ।"</string>
    -     <string name="permlab_sim_communication" msgid="2935852302216852065">"SIM ਨੂੰ ਕਮਾਂਡਾਂ ਭੇਜੋ"</string>
    -     <string name="permdesc_sim_communication" msgid="5725159654279639498">"ਐਪ ਨੂੰ SIM ਨੂੰ ਕਮਾਂਡਾਂ ਭੇਜਣ ਦੀ ਆਗਿਆ ਦਿੰਦਾ ਹੈ। ਇਹ ਬਹੁਤ ਘਾਤਕ ਹੈ।"</string>
    -@@ -1076,6 +1077,17 @@
    -     <skip />
    -     <string name="wifi_no_internet" msgid="8451173622563841546">"Wi-Fi ਦੀ ਕੋਈ ਇੰਟਰਨੈਟ ਪਹੁੰਚ ਨਹੀਂ ਹੈ"</string>
    -     <string name="wifi_no_internet_detailed" msgid="8083079241212301741">"ਵਿਕਲਪਾਂ ਲਈ ਟੈਪ ਕਰੋ"</string>
    -+    <string name="network_switch_metered" msgid="4671730921726992671">"ਬਦਲਕੇ <xliff:g id="NETWORK_TYPE">%1$s</xliff:g> ਲਿਆਂਦਾ ਗਿਆ"</string>
    -+    <string name="network_switch_metered_detail" msgid="5325661434777870353">"<xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> ਦੀ ਇੰਟਰਨੈੱਟ \'ਤੇ ਪਹੁੰਚ ਨਾ ਹੋਣ \'ਤੇ ਡੀਵਾਈਸ <xliff:g id="NEW_NETWORK">%1$s</xliff:g> ਦੀ ਵਰਤੋਂ ਕਰਦੀ ਹੈ। ਖਰਚੇ ਲਾਗੂ ਹੋ ਸਕਦੇ ਹਨ।"</string>
    -+    <string name="network_switch_metered_toast" msgid="5779283181685974304">"<xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> ਤੋਂ ਬਦਲਕੇ <xliff:g id="NEW_NETWORK">%2$s</xliff:g> \'ਤੇ ਕੀਤਾ ਗਿਆ"</string>
    -+  <string-array name="network_switch_type_name">
    -+    <item msgid="2952042958050315394">"ਸੈਲਿਊਲਰ ਡੈਟਾ"</item>
    -+    <item msgid="75483255295529161">"Wi-Fi"</item>
    -+    <item msgid="6862614801537202646">"ਬਲੂਟੁੱਥ"</item>
    -+    <item msgid="5447331121797802871">"ਈਥਰਨੈੱਟ"</item>
    -+    <item msgid="8257233890381651999">"VPN"</item>
    -+  </string-array>
    -+    <string name="network_switch_type_name_unknown" msgid="4552612897806660656">"ਇੱਕ ਅਗਿਆਤ ਨੈੱਟਵਰਕ ਕਿਸਮ"</string>
    -     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Wi-Fi ਨਾਲ ਕਨੈਕਟ ਨਹੀਂ ਕਰ ਸਕਿਆ"</string>
    -     <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" ਇਸਦਾ ਇੱਕ ਖ਼ਰਾਬ ਇੰਟਰਨੈਟ ਕਨੈਕਸ਼ਨ ਹੈ।"</string>
    -     <string name="wifi_connect_alert_title" msgid="8455846016001810172">"ਕੀ ਕਨੈਕਸ਼ਨ ਦੀ ਆਗਿਆ ਦੇਣੀ ਹੈ?"</string>
    -@@ -1153,7 +1165,6 @@
    -     <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"ਭਾਸ਼ਾ ਅਤੇ ਖਾਕਾ ਚੁਣਨ ਲਈ ਟੈਪ ਕਰੋ"</string>
    -     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
    -     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
    --    <string name="candidates_style" msgid="4333913089637062257"><u>"ਉਮੀਦਵਾਰ"</u></string>
    -     <string name="ext_media_checking_notification_title" msgid="5734005953288045806">"<xliff:g id="NAME">%s</xliff:g> ਤਿਆਰ ਹੋ ਰਿਹਾ ਹੈ"</string>
    -     <string name="ext_media_checking_notification_message" msgid="4747432538578886744">"ਤਰੁੱਟੀਆਂ ਦੀ ਜਾਂਚ ਕਰ ਰਿਹਾ ਹੈ"</string>
    -     <string name="ext_media_new_notification_message" msgid="7589986898808506239">"ਨਵੇਂ <xliff:g id="NAME">%s</xliff:g> ਦਾ ਪਤਾ ਲਗਾਇਆ ਗਿਆ"</string>
    -@@ -1232,8 +1243,9 @@
    -     <string name="vpn_text_long" msgid="4907843483284977618">"<xliff:g id="SESSION">%s</xliff:g> ਨਾਲ ਕਨੈਕਟ ਕੀਤਾ ਗਿਆ। ਨੈੱਟਵਰਕ ਦੇ ਪ੍ਰਬੰਧਨ ਲਈ ਟੈਪ ਕਰੋ।"</string>
    -     <string name="vpn_lockdown_connecting" msgid="6443438964440960745">"ਹਮੇਸ਼ਾਂ-ਚਾਲੂ VPN ਕਨੈਕਟ ਕਰ ਰਿਹਾ ਹੈ..."</string>
    -     <string name="vpn_lockdown_connected" msgid="8202679674819213931">"ਹਮੇਸ਼ਾਂ-ਚਾਲੂ VPN ਕਨੈਕਟ ਕੀਤਾ"</string>
    -+    <string name="vpn_lockdown_disconnected" msgid="4532298952570796327">"ਹਮੇਸ਼ਾ-ਚਾਲੂ VPN ਡਿਸਕਨੈਕਟ ਕੀਤਾ ਗਿਆ"</string>
    -     <string name="vpn_lockdown_error" msgid="6009249814034708175">"ਹਮੇਸ਼ਾਂ-ਚਾਲੂ VPN ਅਸ਼ੁੱਧੀ"</string>
    --    <string name="vpn_lockdown_config" msgid="4655589351146766608">"ਸੰਰੂਪਣ ਲਈ ਟੈਪ ਕਰੋ"</string>
    -+    <string name="vpn_lockdown_config" msgid="5099330695245008680">"ਸਥਾਪਤ ਕਰਨ ਲਈ ਟੈਪ ਕਰੋ"</string>
    -     <string name="upload_file" msgid="2897957172366730416">"ਫਾਈਲ ਚੁਣੋ"</string>
    -     <string name="no_file_chosen" msgid="6363648562170759465">"ਕੋਈ ਫਾਈਲ ਨਹੀਂ ਚੁਣੀ ਗਈ"</string>
    -     <string name="reset" msgid="2448168080964209908">"ਰੀਸੈੱਟ ਕਰੋ"</string>
    -@@ -1317,7 +1329,7 @@
    -     <string name="storage_usb_drive_label" msgid="4501418548927759953">"<xliff:g id="MANUFACTURER">%s</xliff:g> USB ਡ੍ਰਾਇਵ"</string>
    -     <string name="storage_usb" msgid="3017954059538517278">"USB ਸਟੋਰੇਜ"</string>
    -     <string name="extract_edit_menu_button" msgid="8940478730496610137">"ਸੰਪਾਦਿਤ ਕਰੋ"</string>
    --    <string name="data_usage_warning_title" msgid="1955638862122232342">"ਡੈਟਾ ਉਪਯੋਗ ਚਿਤਾਵਨੀ"</string>
    -+    <string name="data_usage_warning_title" msgid="3620440638180218181">"ਡੈਟਾ ਵਰਤੋਂ ਚੇਤਾਵਨੀ"</string>
    -     <string name="data_usage_warning_body" msgid="6660692274311972007">"ਵਰਤੋਂ ਅਤੇ ਸੈਟਿੰਗਾਂ ਨੂੰ ਵੇਖਣ ਲਈ ਟੈਪ ਕਰੋ।"</string>
    -     <string name="data_usage_3g_limit_title" msgid="4361523876818447683">"2G-3G ਡੈਟਾ ਸੀਮਾ ਪੂਰੀ ਹੋ ਗਈ"</string>
    -     <string name="data_usage_4g_limit_title" msgid="4609566827219442376">"4G ਡੈਟਾ ਸੀਮਾ ਪੂਰੀ ਹੋਈ"</string>
    -@@ -1636,6 +1648,7 @@
    -     <string name="search_language_hint" msgid="7042102592055108574">"ਭਾਸ਼ਾ ਨਾਮ ਟਾਈਪ ਕਰੋ"</string>
    -     <string name="language_picker_section_suggested" msgid="8414489646861640885">"ਸੁਝਾਈਆਂ ਗਈਆਂ"</string>
    -     <string name="language_picker_section_all" msgid="3097279199511617537">"ਸਾਰੀਆਂ ਭਾਸ਼ਾਵਾਂ"</string>
    -+    <string name="region_picker_section_all" msgid="8966316787153001779">"ਸਾਰੇ ਖੇਤਰ"</string>
    -     <string name="locale_search_menu" msgid="2560710726687249178">"ਖੋਜ"</string>
    -     <string name="work_mode_off_title" msgid="8954725060677558855">"ਕੰਮ ਮੋਡ ਬੰਦ ਹੈ"</string>
    -     <string name="work_mode_off_message" msgid="3286169091278094476">"ਐਪਾਂ, ਬੈਕਗ੍ਰਾਊਂਡ ਸਮਕਾਲੀਕਰਨ, ਅਤੇ ਸਬੰਧਿਤ ਵਿਸ਼ੇਸ਼ਤਾਵਾਂ ਸ਼ਾਮਲ ਕਰਦੇ ਹੋਏ ਕੰਮ ਪ੍ਰੋਫਾਈਲ ਨੂੰ ਕੰਮ ਕਰਨ ਦੀ ਮਨਜ਼ੂਰੀ ਦਿਓ।"</string>
    -diff --git a/core/res/res/values-pl/strings.xml b/core/res/res/values-pl/strings.xml
    -index d9e63a6..dbe29ee 100644
    ---- a/core/res/res/values-pl/strings.xml
    -+++ b/core/res/res/values-pl/strings.xml
    -@@ -218,6 +218,7 @@
    -     <string name="global_actions" product="default" msgid="2406416831541615258">"Opcje telefonu"</string>
    -     <string name="global_action_lock" msgid="2844945191792119712">"Blokada ekranu"</string>
    -     <string name="global_action_power_off" msgid="4471879440839879722">"Wyłącz"</string>
    -+    <string name="global_action_emergency" msgid="7112311161137421166">"Alarmowy"</string>
    -     <string name="global_action_bug_report" msgid="7934010578922304799">"Zgłoszenie błędu"</string>
    -     <string name="bugreport_title" msgid="2667494803742548533">"Zgłoś błąd"</string>
    -     <string name="bugreport_message" msgid="398447048750350456">"Informacje o bieżącym stanie urządzenia zostaną zebrane i wysłane e-mailem. Przygotowanie zgłoszenia błędu do wysłania chwilę potrwa, więc zachowaj cierpliwość."</string>
    -@@ -1126,6 +1127,17 @@
    -     <skip />
    -     <string name="wifi_no_internet" msgid="8451173622563841546">"Sieć Wi-Fi nie ma dostępu do internetu"</string>
    -     <string name="wifi_no_internet_detailed" msgid="8083079241212301741">"Kliknij, by wyświetlić opcje"</string>
    -+    <string name="network_switch_metered" msgid="4671730921726992671">"Zmieniono na połączenie typu <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
    -+    <string name="network_switch_metered_detail" msgid="5325661434777870353">"Urządzenie korzysta z połączenia typu <xliff:g id="NEW_NETWORK">%1$s</xliff:g>, gdy <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> nie dostępu do internetu. Mogą zostać naliczone opłaty."</string>
    -+    <string name="network_switch_metered_toast" msgid="5779283181685974304">"Przełączono z połączenia typu <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> na <xliff:g id="NEW_NETWORK">%2$s</xliff:g>."</string>
    -+  <string-array name="network_switch_type_name">
    -+    <item msgid="2952042958050315394">"komórkowa transmisja danych"</item>
    -+    <item msgid="75483255295529161">"Wi-Fi"</item>
    -+    <item msgid="6862614801537202646">"Bluetooth"</item>
    -+    <item msgid="5447331121797802871">"Ethernet"</item>
    -+    <item msgid="8257233890381651999">"VPN"</item>
    -+  </string-array>
    -+    <string name="network_switch_type_name_unknown" msgid="4552612897806660656">"nieznany typ sieci"</string>
    -     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Nie można połączyć się z siecią Wi-Fi."</string>
    -     <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" ma powolne połączenie internetowe."</string>
    -     <string name="wifi_connect_alert_title" msgid="8455846016001810172">"Zezwolić na połączenie?"</string>
    -@@ -1203,7 +1215,6 @@
    -     <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"Kliknij, by wybrać język i układ"</string>
    -     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" AĄBCĆDEĘFGHIJKLŁMNŃOÓPQRSŚTUVWXYZŹŻ"</string>
    -     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
    --    <string name="candidates_style" msgid="4333913089637062257"><u>"kandydaci"</u></string>
    -     <string name="ext_media_checking_notification_title" msgid="5734005953288045806">"Przygotowuję: <xliff:g id="NAME">%s</xliff:g>"</string>
    -     <string name="ext_media_checking_notification_message" msgid="4747432538578886744">"Sprawdzanie w poszukiwaniu błędów"</string>
    -     <string name="ext_media_new_notification_message" msgid="7589986898808506239">"Wykryto nowy nośnik: <xliff:g id="NAME">%s</xliff:g>"</string>
    -@@ -1282,8 +1293,9 @@
    -     <string name="vpn_text_long" msgid="4907843483284977618">"Nawiązano połączenie: <xliff:g id="SESSION">%s</xliff:g>. Dotknij, aby zarządzać siecią."</string>
    -     <string name="vpn_lockdown_connecting" msgid="6443438964440960745">"Łączę ze stałą siecią VPN…"</string>
    -     <string name="vpn_lockdown_connected" msgid="8202679674819213931">"Połączono ze stałą siecią VPN"</string>
    -+    <string name="vpn_lockdown_disconnected" msgid="4532298952570796327">"Rozłączono ze stałą siecią VPN"</string>
    -     <string name="vpn_lockdown_error" msgid="6009249814034708175">"Błąd stałej sieci VPN"</string>
    --    <string name="vpn_lockdown_config" msgid="4655589351146766608">"Kliknij, by skonfigurować"</string>
    -+    <string name="vpn_lockdown_config" msgid="5099330695245008680">"Kliknij, by skonfigurować"</string>
    -     <string name="upload_file" msgid="2897957172366730416">"Wybierz plik"</string>
    -     <string name="no_file_chosen" msgid="6363648562170759465">"Nie wybrano pliku"</string>
    -     <string name="reset" msgid="2448168080964209908">"Resetuj"</string>
    -@@ -1369,7 +1381,7 @@
    -     <string name="storage_usb_drive_label" msgid="4501418548927759953">"Dysk USB (<xliff:g id="MANUFACTURER">%s</xliff:g>)"</string>
    -     <string name="storage_usb" msgid="3017954059538517278">"Nośnik USB"</string>
    -     <string name="extract_edit_menu_button" msgid="8940478730496610137">"Edytuj"</string>
    --    <string name="data_usage_warning_title" msgid="1955638862122232342">"Ostrzeżenie o transmisji danych"</string>
    -+    <string name="data_usage_warning_title" msgid="3620440638180218181">"Alert transmisji danych"</string>
    -     <string name="data_usage_warning_body" msgid="6660692274311972007">"Kliknij, by wyświetlić użycie i ustawienia."</string>
    -     <string name="data_usage_3g_limit_title" msgid="4361523876818447683">"Osiągnięto limit danych 2G/3G"</string>
    -     <string name="data_usage_4g_limit_title" msgid="4609566827219442376">"Osiągnięto limit danych 4G"</string>
    -@@ -1708,6 +1720,7 @@
    -     <string name="search_language_hint" msgid="7042102592055108574">"Wpisz nazwę języka"</string>
    -     <string name="language_picker_section_suggested" msgid="8414489646861640885">"Sugerowane"</string>
    -     <string name="language_picker_section_all" msgid="3097279199511617537">"Wszystkie języki"</string>
    -+    <string name="region_picker_section_all" msgid="8966316787153001779">"Wszystkie kraje"</string>
    -     <string name="locale_search_menu" msgid="2560710726687249178">"Szukaj"</string>
    -     <string name="work_mode_off_title" msgid="8954725060677558855">"Tryb pracy jest WYŁĄCZONY"</string>
    -     <string name="work_mode_off_message" msgid="3286169091278094476">"Włącz profil do pracy, w tym aplikacje, synchronizację w tle i inne funkcje."</string>
    -diff --git a/core/res/res/values-pt-rBR/strings.xml b/core/res/res/values-pt-rBR/strings.xml
    -index eaaad25..4f3b09f 100644
    ---- a/core/res/res/values-pt-rBR/strings.xml
    -+++ b/core/res/res/values-pt-rBR/strings.xml
    -@@ -214,6 +214,7 @@
    -     <string name="global_actions" product="default" msgid="2406416831541615258">"Opções do telefone"</string>
    -     <string name="global_action_lock" msgid="2844945191792119712">"Bloquear tela"</string>
    -     <string name="global_action_power_off" msgid="4471879440839879722">"Desligar"</string>
    -+    <string name="global_action_emergency" msgid="7112311161137421166">"Emergência"</string>
    -     <string name="global_action_bug_report" msgid="7934010578922304799">"Relatório de bugs"</string>
    -     <string name="bugreport_title" msgid="2667494803742548533">"Obter relatório de bugs"</string>
    -     <string name="bugreport_message" msgid="398447048750350456">"Isto coletará informações sobre o estado atual do dispositivo para enviá-las em uma mensagem de e-mail. Após iniciar o relatório de bugs, será necessário aguardar algum tempo até que esteja pronto para ser enviado."</string>
    -@@ -1076,6 +1077,17 @@
    -     <skip />
    -     <string name="wifi_no_internet" msgid="8451173622563841546">"O Wi-Fi não tem acesso à Internet"</string>
    -     <string name="wifi_no_internet_detailed" msgid="8083079241212301741">"Toque para ver opções"</string>
    -+    <string name="network_switch_metered" msgid="4671730921726992671">"Alternado para <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
    -+    <string name="network_switch_metered_detail" msgid="5325661434777870353">"O dispositivo usa <xliff:g id="NEW_NETWORK">%1$s</xliff:g> quando <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> não tem acesso à Internet. Cobranças podem ser aplicadas."</string>
    -+    <string name="network_switch_metered_toast" msgid="5779283181685974304">"Alternado de <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> para <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
    -+  <string-array name="network_switch_type_name">
    -+    <item msgid="2952042958050315394">"dados da rede celular"</item>
    -+    <item msgid="75483255295529161">"Wi-Fi"</item>
    -+    <item msgid="6862614801537202646">"Bluetooth"</item>
    -+    <item msgid="5447331121797802871">"Ethernet"</item>
    -+    <item msgid="8257233890381651999">"VPN"</item>
    -+  </string-array>
    -+    <string name="network_switch_type_name_unknown" msgid="4552612897806660656">"um tipo de rede desconhecido"</string>
    -     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Não foi possível se conectar a redes Wi-Fi"</string>
    -     <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" tem uma conexão de baixa qualidade com a Internet."</string>
    -     <string name="wifi_connect_alert_title" msgid="8455846016001810172">"Permitir conexão?"</string>
    -@@ -1153,7 +1165,6 @@
    -     <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"Toque para selecionar o idioma e o layout"</string>
    -     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
    -     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
    --    <string name="candidates_style" msgid="4333913089637062257"><u>"candidatos"</u></string>
    -     <string name="ext_media_checking_notification_title" msgid="5734005953288045806">"Preparando <xliff:g id="NAME">%s</xliff:g>"</string>
    -     <string name="ext_media_checking_notification_message" msgid="4747432538578886744">"Procurando erros"</string>
    -     <string name="ext_media_new_notification_message" msgid="7589986898808506239">"Novo <xliff:g id="NAME">%s</xliff:g> detectado"</string>
    -@@ -1232,8 +1243,9 @@
    -     <string name="vpn_text_long" msgid="4907843483284977618">"Conectado a <xliff:g id="SESSION">%s</xliff:g>. Toque para gerenciar a rede."</string>
    -     <string name="vpn_lockdown_connecting" msgid="6443438964440960745">"VPN sempre ativa conectando..."</string>
    -     <string name="vpn_lockdown_connected" msgid="8202679674819213931">"VPN sempre ativa conectada"</string>
    -+    <string name="vpn_lockdown_disconnected" msgid="4532298952570796327">"VPN sempre ativa desconectada"</string>
    -     <string name="vpn_lockdown_error" msgid="6009249814034708175">"Erro na VPN sempre ativa"</string>
    --    <string name="vpn_lockdown_config" msgid="4655589351146766608">"Toque para configurar"</string>
    -+    <string name="vpn_lockdown_config" msgid="5099330695245008680">"Toque para configurar"</string>
    -     <string name="upload_file" msgid="2897957172366730416">"Escolher arquivo"</string>
    -     <string name="no_file_chosen" msgid="6363648562170759465">"Nenhum arquivo escolhido"</string>
    -     <string name="reset" msgid="2448168080964209908">"Redefinir"</string>
    -@@ -1317,7 +1329,7 @@
    -     <string name="storage_usb_drive_label" msgid="4501418548927759953">"Drive USB <xliff:g id="MANUFACTURER">%s</xliff:g>"</string>
    -     <string name="storage_usb" msgid="3017954059538517278">"Armazenamento USB"</string>
    -     <string name="extract_edit_menu_button" msgid="8940478730496610137">"Editar"</string>
    --    <string name="data_usage_warning_title" msgid="1955638862122232342">"Aviso sobre uso de dados"</string>
    -+    <string name="data_usage_warning_title" msgid="3620440638180218181">"Alerta de uso de dados"</string>
    -     <string name="data_usage_warning_body" msgid="6660692274311972007">"Toque para ver uso e config."</string>
    -     <string name="data_usage_3g_limit_title" msgid="4361523876818447683">"Limite de dados 2G-3G atingido"</string>
    -     <string name="data_usage_4g_limit_title" msgid="4609566827219442376">"Limite de dados 4G atingido"</string>
    -@@ -1636,6 +1648,7 @@
    -     <string name="search_language_hint" msgid="7042102592055108574">"Digitar nome do idioma"</string>
    -     <string name="language_picker_section_suggested" msgid="8414489646861640885">"Sugeridos"</string>
    -     <string name="language_picker_section_all" msgid="3097279199511617537">"Todos os idiomas"</string>
    -+    <string name="region_picker_section_all" msgid="8966316787153001779">"Todas as regiões"</string>
    -     <string name="locale_search_menu" msgid="2560710726687249178">"Pesquisa"</string>
    -     <string name="work_mode_off_title" msgid="8954725060677558855">"Modo de trabalho DESATIVADO"</string>
    -     <string name="work_mode_off_message" msgid="3286169091278094476">"Permitir que o perfil de trabalho funcione, incluindo apps, sincronização em segundo plano e recursos relacionados"</string>
    -diff --git a/core/res/res/values-pt-rPT/strings.xml b/core/res/res/values-pt-rPT/strings.xml
    -index ae115d8..64db1c2 100644
    ---- a/core/res/res/values-pt-rPT/strings.xml
    -+++ b/core/res/res/values-pt-rPT/strings.xml
    -@@ -214,6 +214,7 @@
    -     <string name="global_actions" product="default" msgid="2406416831541615258">"Opções do telefone"</string>
    -     <string name="global_action_lock" msgid="2844945191792119712">"Bloqueio de ecrã"</string>
    -     <string name="global_action_power_off" msgid="4471879440839879722">"Desligar"</string>
    -+    <string name="global_action_emergency" msgid="7112311161137421166">"Emergência"</string>
    -     <string name="global_action_bug_report" msgid="7934010578922304799">"Relatório de erros"</string>
    -     <string name="bugreport_title" msgid="2667494803742548533">"Criar relatório de erros"</string>
    -     <string name="bugreport_message" msgid="398447048750350456">"Será recolhida informação sobre o estado atual do seu dispositivo a enviar através de uma mensagem de email. Demorará algum tempo até que o relatório de erro esteja pronto para ser enviado. Aguarde um pouco."</string>
    -@@ -1076,6 +1077,17 @@
    -     <skip />
    -     <string name="wifi_no_internet" msgid="8451173622563841546">"O Wi-Fi não tem acesso à Internet"</string>
    -     <string name="wifi_no_internet_detailed" msgid="8083079241212301741">"Toque para obter mais opções"</string>
    -+    <string name="network_switch_metered" msgid="4671730921726992671">"Mudou para <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
    -+    <string name="network_switch_metered_detail" msgid="5325661434777870353">"O dispositivo utiliza <xliff:g id="NEW_NETWORK">%1$s</xliff:g> quando <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> não tem acesso à Internet. Podem ser aplicados custos."</string>
    -+    <string name="network_switch_metered_toast" msgid="5779283181685974304">"Mudou de <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> para <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
    -+  <string-array name="network_switch_type_name">
    -+    <item msgid="2952042958050315394">"dados móveis"</item>
    -+    <item msgid="75483255295529161">"Wi-Fi"</item>
    -+    <item msgid="6862614801537202646">"Bluetooth"</item>
    -+    <item msgid="5447331121797802871">"Ethernet"</item>
    -+    <item msgid="8257233890381651999">"VPN"</item>
    -+  </string-array>
    -+    <string name="network_switch_type_name_unknown" msgid="4552612897806660656">"um tipo de rede desconhecido"</string>
    -     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Não foi possível ligar a Wi-Fi"</string>
    -     <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" tem uma ligação à internet fraca."</string>
    -     <string name="wifi_connect_alert_title" msgid="8455846016001810172">"Permitir ligação?"</string>
    -@@ -1153,7 +1165,6 @@
    -     <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"Toque para selecionar o idioma e o esquema"</string>
    -     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
    -     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
    --    <string name="candidates_style" msgid="4333913089637062257"><u>"candidatos"</u></string>
    -     <string name="ext_media_checking_notification_title" msgid="5734005953288045806">"A preparar o <xliff:g id="NAME">%s</xliff:g>"</string>
    -     <string name="ext_media_checking_notification_message" msgid="4747432538578886744">"A verificar a presença de erros"</string>
    -     <string name="ext_media_new_notification_message" msgid="7589986898808506239">"Novo <xliff:g id="NAME">%s</xliff:g> detetado"</string>
    -@@ -1232,8 +1243,9 @@
    -     <string name="vpn_text_long" msgid="4907843483284977618">"Ligado a <xliff:g id="SESSION">%s</xliff:g>. Toque para gerir a rede."</string>
    -     <string name="vpn_lockdown_connecting" msgid="6443438964440960745">"A ligar VPN sempre ativa..."</string>
    -     <string name="vpn_lockdown_connected" msgid="8202679674819213931">"VPN sempre ativa ligada"</string>
    -+    <string name="vpn_lockdown_disconnected" msgid="4532298952570796327">"VPN sempre ativa desligada"</string>
    -     <string name="vpn_lockdown_error" msgid="6009249814034708175">"Erro da VPN sempre ativa"</string>
    --    <string name="vpn_lockdown_config" msgid="4655589351146766608">"Toque para configurar"</string>
    -+    <string name="vpn_lockdown_config" msgid="5099330695245008680">"Tocar para configurar"</string>
    -     <string name="upload_file" msgid="2897957172366730416">"Escolher ficheiro"</string>
    -     <string name="no_file_chosen" msgid="6363648562170759465">"Não foi selecionado nenhum ficheiro"</string>
    -     <string name="reset" msgid="2448168080964209908">"Repor"</string>
    -@@ -1310,14 +1322,14 @@
    -     <string name="action_menu_overflow_description" msgid="2295659037509008453">"Mais opções"</string>
    -     <string name="action_bar_home_description_format" msgid="7965984360903693903">"%1$s, %2$s"</string>
    -     <string name="action_bar_home_subtitle_description_format" msgid="6985546530471780727">"%1$s, %2$s, %3$s"</string>
    --    <string name="storage_internal" msgid="3570990907910199483">"Armazenamento interno partilhado"</string>
    -+    <string name="storage_internal" msgid="3570990907910199483">"Armazen. interno partilhado"</string>
    -     <string name="storage_sd_card" msgid="3282948861378286745">"Cartão SD"</string>
    -     <string name="storage_sd_card_label" msgid="6347111320774379257">"Cartão SD <xliff:g id="MANUFACTURER">%s</xliff:g>"</string>
    -     <string name="storage_usb_drive" msgid="6261899683292244209">"Unidade USB"</string>
    -     <string name="storage_usb_drive_label" msgid="4501418548927759953">"Unidade USB <xliff:g id="MANUFACTURER">%s</xliff:g>"</string>
    -     <string name="storage_usb" msgid="3017954059538517278">"Armazenamento USB"</string>
    -     <string name="extract_edit_menu_button" msgid="8940478730496610137">"Editar"</string>
    --    <string name="data_usage_warning_title" msgid="1955638862122232342">"Aviso de utilização de dados"</string>
    -+    <string name="data_usage_warning_title" msgid="3620440638180218181">"Alerta de utilização de dados"</string>
    -     <string name="data_usage_warning_body" msgid="6660692274311972007">"Toque para ver a utilização e definições"</string>
    -     <string name="data_usage_3g_limit_title" msgid="4361523876818447683">"Limite de dados 2G/3G atingido"</string>
    -     <string name="data_usage_4g_limit_title" msgid="4609566827219442376">"Limite de dados 4G atingido"</string>
    -@@ -1636,6 +1648,7 @@
    -     <string name="search_language_hint" msgid="7042102592055108574">"Intr. nome do idioma"</string>
    -     <string name="language_picker_section_suggested" msgid="8414489646861640885">"Sugeridos"</string>
    -     <string name="language_picker_section_all" msgid="3097279199511617537">"Todos os idiomas"</string>
    -+    <string name="region_picker_section_all" msgid="8966316787153001779">"Todas as regiões"</string>
    -     <string name="locale_search_menu" msgid="2560710726687249178">"Pesquisa"</string>
    -     <string name="work_mode_off_title" msgid="8954725060677558855">"Modo de trabalho DESATIVADO"</string>
    -     <string name="work_mode_off_message" msgid="3286169091278094476">"Permitir o funcionamento do perfil de trabalho, incluindo as aplicações, a sincronização em segundo plano e as funcionalidades relacionadas."</string>
    -diff --git a/core/res/res/values-pt/strings.xml b/core/res/res/values-pt/strings.xml
    -index eaaad25..4f3b09f 100644
    ---- a/core/res/res/values-pt/strings.xml
    -+++ b/core/res/res/values-pt/strings.xml
    -@@ -214,6 +214,7 @@
    -     <string name="global_actions" product="default" msgid="2406416831541615258">"Opções do telefone"</string>
    -     <string name="global_action_lock" msgid="2844945191792119712">"Bloquear tela"</string>
    -     <string name="global_action_power_off" msgid="4471879440839879722">"Desligar"</string>
    -+    <string name="global_action_emergency" msgid="7112311161137421166">"Emergência"</string>
    -     <string name="global_action_bug_report" msgid="7934010578922304799">"Relatório de bugs"</string>
    -     <string name="bugreport_title" msgid="2667494803742548533">"Obter relatório de bugs"</string>
    -     <string name="bugreport_message" msgid="398447048750350456">"Isto coletará informações sobre o estado atual do dispositivo para enviá-las em uma mensagem de e-mail. Após iniciar o relatório de bugs, será necessário aguardar algum tempo até que esteja pronto para ser enviado."</string>
    -@@ -1076,6 +1077,17 @@
    -     <skip />
    -     <string name="wifi_no_internet" msgid="8451173622563841546">"O Wi-Fi não tem acesso à Internet"</string>
    -     <string name="wifi_no_internet_detailed" msgid="8083079241212301741">"Toque para ver opções"</string>
    -+    <string name="network_switch_metered" msgid="4671730921726992671">"Alternado para <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
    -+    <string name="network_switch_metered_detail" msgid="5325661434777870353">"O dispositivo usa <xliff:g id="NEW_NETWORK">%1$s</xliff:g> quando <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> não tem acesso à Internet. Cobranças podem ser aplicadas."</string>
    -+    <string name="network_switch_metered_toast" msgid="5779283181685974304">"Alternado de <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> para <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
    -+  <string-array name="network_switch_type_name">
    -+    <item msgid="2952042958050315394">"dados da rede celular"</item>
    -+    <item msgid="75483255295529161">"Wi-Fi"</item>
    -+    <item msgid="6862614801537202646">"Bluetooth"</item>
    -+    <item msgid="5447331121797802871">"Ethernet"</item>
    -+    <item msgid="8257233890381651999">"VPN"</item>
    -+  </string-array>
    -+    <string name="network_switch_type_name_unknown" msgid="4552612897806660656">"um tipo de rede desconhecido"</string>
    -     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Não foi possível se conectar a redes Wi-Fi"</string>
    -     <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" tem uma conexão de baixa qualidade com a Internet."</string>
    -     <string name="wifi_connect_alert_title" msgid="8455846016001810172">"Permitir conexão?"</string>
    -@@ -1153,7 +1165,6 @@
    -     <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"Toque para selecionar o idioma e o layout"</string>
    -     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
    -     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
    --    <string name="candidates_style" msgid="4333913089637062257"><u>"candidatos"</u></string>
    -     <string name="ext_media_checking_notification_title" msgid="5734005953288045806">"Preparando <xliff:g id="NAME">%s</xliff:g>"</string>
    -     <string name="ext_media_checking_notification_message" msgid="4747432538578886744">"Procurando erros"</string>
    -     <string name="ext_media_new_notification_message" msgid="7589986898808506239">"Novo <xliff:g id="NAME">%s</xliff:g> detectado"</string>
    -@@ -1232,8 +1243,9 @@
    -     <string name="vpn_text_long" msgid="4907843483284977618">"Conectado a <xliff:g id="SESSION">%s</xliff:g>. Toque para gerenciar a rede."</string>
    -     <string name="vpn_lockdown_connecting" msgid="6443438964440960745">"VPN sempre ativa conectando..."</string>
    -     <string name="vpn_lockdown_connected" msgid="8202679674819213931">"VPN sempre ativa conectada"</string>
    -+    <string name="vpn_lockdown_disconnected" msgid="4532298952570796327">"VPN sempre ativa desconectada"</string>
    -     <string name="vpn_lockdown_error" msgid="6009249814034708175">"Erro na VPN sempre ativa"</string>
    --    <string name="vpn_lockdown_config" msgid="4655589351146766608">"Toque para configurar"</string>
    -+    <string name="vpn_lockdown_config" msgid="5099330695245008680">"Toque para configurar"</string>
    -     <string name="upload_file" msgid="2897957172366730416">"Escolher arquivo"</string>
    -     <string name="no_file_chosen" msgid="6363648562170759465">"Nenhum arquivo escolhido"</string>
    -     <string name="reset" msgid="2448168080964209908">"Redefinir"</string>
    -@@ -1317,7 +1329,7 @@
    -     <string name="storage_usb_drive_label" msgid="4501418548927759953">"Drive USB <xliff:g id="MANUFACTURER">%s</xliff:g>"</string>
    -     <string name="storage_usb" msgid="3017954059538517278">"Armazenamento USB"</string>
    -     <string name="extract_edit_menu_button" msgid="8940478730496610137">"Editar"</string>
    --    <string name="data_usage_warning_title" msgid="1955638862122232342">"Aviso sobre uso de dados"</string>
    -+    <string name="data_usage_warning_title" msgid="3620440638180218181">"Alerta de uso de dados"</string>
    -     <string name="data_usage_warning_body" msgid="6660692274311972007">"Toque para ver uso e config."</string>
    -     <string name="data_usage_3g_limit_title" msgid="4361523876818447683">"Limite de dados 2G-3G atingido"</string>
    -     <string name="data_usage_4g_limit_title" msgid="4609566827219442376">"Limite de dados 4G atingido"</string>
    -@@ -1636,6 +1648,7 @@
    -     <string name="search_language_hint" msgid="7042102592055108574">"Digitar nome do idioma"</string>
    -     <string name="language_picker_section_suggested" msgid="8414489646861640885">"Sugeridos"</string>
    -     <string name="language_picker_section_all" msgid="3097279199511617537">"Todos os idiomas"</string>
    -+    <string name="region_picker_section_all" msgid="8966316787153001779">"Todas as regiões"</string>
    -     <string name="locale_search_menu" msgid="2560710726687249178">"Pesquisa"</string>
    -     <string name="work_mode_off_title" msgid="8954725060677558855">"Modo de trabalho DESATIVADO"</string>
    -     <string name="work_mode_off_message" msgid="3286169091278094476">"Permitir que o perfil de trabalho funcione, incluindo apps, sincronização em segundo plano e recursos relacionados"</string>
    -diff --git a/core/res/res/values-ro/strings.xml b/core/res/res/values-ro/strings.xml
    -index 6198f12..192d9c1 100644
    ---- a/core/res/res/values-ro/strings.xml
    -+++ b/core/res/res/values-ro/strings.xml
    -@@ -216,6 +216,7 @@
    -     <string name="global_actions" product="default" msgid="2406416831541615258">"Opțiuni telefon"</string>
    -     <string name="global_action_lock" msgid="2844945191792119712">"Blocați ecranul"</string>
    -     <string name="global_action_power_off" msgid="4471879440839879722">"Opriți alimentarea"</string>
    -+    <string name="global_action_emergency" msgid="7112311161137421166">"Urgență"</string>
    -     <string name="global_action_bug_report" msgid="7934010578922304799">"Raport despre erori"</string>
    -     <string name="bugreport_title" msgid="2667494803742548533">"Executați un raport despre erori"</string>
    -     <string name="bugreport_message" msgid="398447048750350456">"Acest raport va colecta informații despre starea actuală a dispozitivului, pentru a le trimite într-un e-mail. Aveți răbdare după pornirea raportului despre erori până când va fi gata de trimis."</string>
    -@@ -1101,6 +1102,17 @@
    -     <skip />
    -     <string name="wifi_no_internet" msgid="8451173622563841546">"Rețeaua Wi-Fi nu are acces la internet"</string>
    -     <string name="wifi_no_internet_detailed" msgid="8083079241212301741">"Atingeți pentru opțiuni"</string>
    -+    <string name="network_switch_metered" msgid="4671730921726992671">"S-a comutat la <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
    -+    <string name="network_switch_metered_detail" msgid="5325661434777870353">"Dispozitivul folosește <xliff:g id="NEW_NETWORK">%1$s</xliff:g> când <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> nu are acces la internet. Se pot aplica taxe."</string>
    -+    <string name="network_switch_metered_toast" msgid="5779283181685974304">"S-a comutat de la <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> la <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
    -+  <string-array name="network_switch_type_name">
    -+    <item msgid="2952042958050315394">"date mobile"</item>
    -+    <item msgid="75483255295529161">"Wi-Fi"</item>
    -+    <item msgid="6862614801537202646">"Bluetooth"</item>
    -+    <item msgid="5447331121797802871">"Ethernet"</item>
    -+    <item msgid="8257233890381651999">"VPN"</item>
    -+  </string-array>
    -+    <string name="network_switch_type_name_unknown" msgid="4552612897806660656">"un tip de rețea necunoscut"</string>
    -     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Nu se poate conecta la Wi-Fi"</string>
    -     <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" are o conexiune la internet slabă."</string>
    -     <string name="wifi_connect_alert_title" msgid="8455846016001810172">"Permiteți conectarea?"</string>
    -@@ -1178,7 +1190,6 @@
    -     <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"Atingeți pentru a selecta limba și aspectul"</string>
    -     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
    -     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
    --    <string name="candidates_style" msgid="4333913089637062257"><u>"candidați"</u></string>
    -     <string name="ext_media_checking_notification_title" msgid="5734005953288045806">"Se pregătește <xliff:g id="NAME">%s</xliff:g>"</string>
    -     <string name="ext_media_checking_notification_message" msgid="4747432538578886744">"Se verifică dacă există erori"</string>
    -     <string name="ext_media_new_notification_message" msgid="7589986898808506239">"A fost detectat un nou <xliff:g id="NAME">%s</xliff:g>"</string>
    -@@ -1257,8 +1268,9 @@
    -     <string name="vpn_text_long" msgid="4907843483284977618">"Conectat la <xliff:g id="SESSION">%s</xliff:g>. Apăsați pentru a gestiona rețeaua."</string>
    -     <string name="vpn_lockdown_connecting" msgid="6443438964440960745">"Se efectuează conectarea la rețeaua VPN activată permanent…"</string>
    -     <string name="vpn_lockdown_connected" msgid="8202679674819213931">"Conectat(ă) la rețeaua VPN activată permanent"</string>
    -+    <string name="vpn_lockdown_disconnected" msgid="4532298952570796327">"Rețeaua VPN activată permanent a fost deconectată"</string>
    -     <string name="vpn_lockdown_error" msgid="6009249814034708175">"Eroare de rețea VPN activată permanent"</string>
    --    <string name="vpn_lockdown_config" msgid="4655589351146766608">"Atingeți ca să configurați"</string>
    -+    <string name="vpn_lockdown_config" msgid="5099330695245008680">"Atingeți pentru a configura"</string>
    -     <string name="upload_file" msgid="2897957172366730416">"Alegeți un fișier"</string>
    -     <string name="no_file_chosen" msgid="6363648562170759465">"Nu au fost găsite fișiere"</string>
    -     <string name="reset" msgid="2448168080964209908">"Resetați"</string>
    -@@ -1343,7 +1355,7 @@
    -     <string name="storage_usb_drive_label" msgid="4501418548927759953">"Unitate USB <xliff:g id="MANUFACTURER">%s</xliff:g>"</string>
    -     <string name="storage_usb" msgid="3017954059538517278">"Dsipozitiv de stocare USB"</string>
    -     <string name="extract_edit_menu_button" msgid="8940478730496610137">"Editați"</string>
    --    <string name="data_usage_warning_title" msgid="1955638862122232342">"Avertisment de utiliz. a datelor"</string>
    -+    <string name="data_usage_warning_title" msgid="3620440638180218181">"Alertă pentru utilizarea datelor"</string>
    -     <string name="data_usage_warning_body" msgid="6660692274311972007">"Atingeți ca să vedeți utilizarea/setările."</string>
    -     <string name="data_usage_3g_limit_title" msgid="4361523876818447683">"Ați atins limita de date 2G-3G"</string>
    -     <string name="data_usage_4g_limit_title" msgid="4609566827219442376">"Ați atins limita de date 4G"</string>
    -@@ -1672,6 +1684,7 @@
    -     <string name="search_language_hint" msgid="7042102592055108574">"Numele limbii"</string>
    -     <string name="language_picker_section_suggested" msgid="8414489646861640885">"Sugerate"</string>
    -     <string name="language_picker_section_all" msgid="3097279199511617537">"Toate limbile"</string>
    -+    <string name="region_picker_section_all" msgid="8966316787153001779">"Toate regiunile"</string>
    -     <string name="locale_search_menu" msgid="2560710726687249178">"Căutați"</string>
    -     <string name="work_mode_off_title" msgid="8954725060677558855">"Modul de serviciu e DEZACTIVAT"</string>
    -     <string name="work_mode_off_message" msgid="3286169091278094476">"Permiteți profilului de serviciu să funcționeze, inclusiv aplicațiile, sincronizarea în fundal și funcțiile asociate."</string>
    -diff --git a/core/res/res/values-ru/strings.xml b/core/res/res/values-ru/strings.xml
    -index 0ef96af..b1b14f9 100644
    ---- a/core/res/res/values-ru/strings.xml
    -+++ b/core/res/res/values-ru/strings.xml
    -@@ -218,6 +218,7 @@
    -     <string name="global_actions" product="default" msgid="2406416831541615258">"Параметры телефона"</string>
    -     <string name="global_action_lock" msgid="2844945191792119712">"Блокировка экрана"</string>
    -     <string name="global_action_power_off" msgid="4471879440839879722">"Отключить питание"</string>
    -+    <string name="global_action_emergency" msgid="7112311161137421166">"Экстренный вызов"</string>
    -     <string name="global_action_bug_report" msgid="7934010578922304799">"Отчет об ошибке"</string>
    -     <string name="bugreport_title" msgid="2667494803742548533">"Отчет об ошибке"</string>
    -     <string name="bugreport_message" msgid="398447048750350456">"Информация о текущем состоянии вашего устройства будет собрана и отправлена по электронной почте. Подготовка отчета займет некоторое время."</string>
    -@@ -1126,6 +1127,17 @@
    -     <skip />
    -     <string name="wifi_no_internet" msgid="8451173622563841546">"Сеть Wi-Fi не подключена к Интернету"</string>
    -     <string name="wifi_no_internet_detailed" msgid="8083079241212301741">"Нажмите, чтобы показать варианты."</string>
    -+    <string name="network_switch_metered" msgid="4671730921726992671">"Новое подключение: <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
    -+    <string name="network_switch_metered_detail" msgid="5325661434777870353">"Устройство использует <xliff:g id="NEW_NETWORK">%1$s</xliff:g>, если подключение к сети <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> недоступно. Может взиматься плата за передачу данных."</string>
    -+    <string name="network_switch_metered_toast" msgid="5779283181685974304">"Устройство отключено от сети <xliff:g id="NEW_NETWORK">%2$s</xliff:g> и теперь использует <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g>"</string>
    -+  <string-array name="network_switch_type_name">
    -+    <item msgid="2952042958050315394">"мобильные данные"</item>
    -+    <item msgid="75483255295529161">"Wi-Fi"</item>
    -+    <item msgid="6862614801537202646">"Bluetooth"</item>
    -+    <item msgid="5447331121797802871">"Ethernet"</item>
    -+    <item msgid="8257233890381651999">"VPN"</item>
    -+  </string-array>
    -+    <string name="network_switch_type_name_unknown" msgid="4552612897806660656">"неизвестный тип сети"</string>
    -     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Не удалось подключиться к сети Wi-Fi"</string>
    -     <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" – плохое интернет-соединение."</string>
    -     <string name="wifi_connect_alert_title" msgid="8455846016001810172">"Разрешить подключение?"</string>
    -@@ -1203,7 +1215,6 @@
    -     <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"Нажмите, чтобы выбрать язык и раскладку"</string>
    -     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
    -     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
    --    <string name="candidates_style" msgid="4333913089637062257"><u>"варианты"</u></string>
    -     <string name="ext_media_checking_notification_title" msgid="5734005953288045806">"Подготовка карты \"<xliff:g id="NAME">%s</xliff:g>\"…"</string>
    -     <string name="ext_media_checking_notification_message" msgid="4747432538578886744">"Поиск ошибок"</string>
    -     <string name="ext_media_new_notification_message" msgid="7589986898808506239">"Обнаружена новая карта \"<xliff:g id="NAME">%s</xliff:g>\""</string>
    -@@ -1282,8 +1293,9 @@
    -     <string name="vpn_text_long" msgid="4907843483284977618">"Подключено: \"<xliff:g id="SESSION">%s</xliff:g>\". Нажмите здесь, чтобы изменить настройки сети."</string>
    -     <string name="vpn_lockdown_connecting" msgid="6443438964440960745">"Подключение…"</string>
    -     <string name="vpn_lockdown_connected" msgid="8202679674819213931">"Подключено"</string>
    -+    <string name="vpn_lockdown_disconnected" msgid="4532298952570796327">"Отключено"</string>
    -     <string name="vpn_lockdown_error" msgid="6009249814034708175">"Ошибка"</string>
    --    <string name="vpn_lockdown_config" msgid="4655589351146766608">"Нажмите, чтобы настроить."</string>
    -+    <string name="vpn_lockdown_config" msgid="5099330695245008680">"Нажмите, чтобы настроить"</string>
    -     <string name="upload_file" msgid="2897957172366730416">"Выбрать файл"</string>
    -     <string name="no_file_chosen" msgid="6363648562170759465">"Не выбран файл"</string>
    -     <string name="reset" msgid="2448168080964209908">"Сбросить"</string>
    -@@ -1369,7 +1381,7 @@
    -     <string name="storage_usb_drive_label" msgid="4501418548927759953">"USB-накопитель <xliff:g id="MANUFACTURER">%s</xliff:g>"</string>
    -     <string name="storage_usb" msgid="3017954059538517278">"USB-накопитель"</string>
    -     <string name="extract_edit_menu_button" msgid="8940478730496610137">"Изменить"</string>
    --    <string name="data_usage_warning_title" msgid="1955638862122232342">"Осталось мало трафика"</string>
    -+    <string name="data_usage_warning_title" msgid="3620440638180218181">"Лимит на передачу данных"</string>
    -     <string name="data_usage_warning_body" msgid="6660692274311972007">"Нажмите, чтобы проверить трафик и настройки."</string>
    -     <string name="data_usage_3g_limit_title" msgid="4361523876818447683">"Достигнут лимит трафика 2G/3G"</string>
    -     <string name="data_usage_4g_limit_title" msgid="4609566827219442376">"Достигнут лимит трафика 4G"</string>
    -@@ -1708,6 +1720,7 @@
    -     <string name="search_language_hint" msgid="7042102592055108574">"Введите язык"</string>
    -     <string name="language_picker_section_suggested" msgid="8414489646861640885">"Рекомендуемые"</string>
    -     <string name="language_picker_section_all" msgid="3097279199511617537">"Все языки"</string>
    -+    <string name="region_picker_section_all" msgid="8966316787153001779">"Все регионы"</string>
    -     <string name="locale_search_menu" msgid="2560710726687249178">"Поиск"</string>
    -     <string name="work_mode_off_title" msgid="8954725060677558855">"Рабочий режим отключен"</string>
    -     <string name="work_mode_off_message" msgid="3286169091278094476">"Включить рабочий профиль: приложения, фоновую синхронизацию и связанные функции."</string>
    -diff --git a/core/res/res/values-si-rLK/strings.xml b/core/res/res/values-si-rLK/strings.xml
    -index 4f90b57..f3c8e7b 100644
    ---- a/core/res/res/values-si-rLK/strings.xml
    -+++ b/core/res/res/values-si-rLK/strings.xml
    -@@ -214,6 +214,7 @@
    -     <string name="global_actions" product="default" msgid="2406416831541615258">"දුරකථන විකල්ප"</string>
    -     <string name="global_action_lock" msgid="2844945191792119712">"තිර අගුල"</string>
    -     <string name="global_action_power_off" msgid="4471879440839879722">"බලය අක්‍රිය කරන්න"</string>
    -+    <string name="global_action_emergency" msgid="7112311161137421166">"හදිසි"</string>
    -     <string name="global_action_bug_report" msgid="7934010578922304799">"දෝෂ වර්තාව"</string>
    -     <string name="bugreport_title" msgid="2667494803742548533">"දෝෂ වාර්තාවක් ගන්න"</string>
    -     <string name="bugreport_message" msgid="398447048750350456">"ඊ-තැපැල් පණිවිඩයක් ලෙස යැවීමට මෙය ඔබගේ වත්මන් උපාංග තත්වය ගැන තොරතුරු එකතු කරනු ඇත. දෝෂ වාර්තාව ආරම්භ කර එය යැවීමට සූදානම් කරන තෙක් එයට කිසියම් කාලයක් ගතවනු ඇත; කරුණාකර ඉවසන්න."</string>
    -@@ -1078,6 +1079,17 @@
    -     <skip />
    -     <string name="wifi_no_internet" msgid="8451173622563841546">"Wi-Fi හට අන්තර්ජාල ප්‍රවේශය නැත"</string>
    -     <string name="wifi_no_internet_detailed" msgid="8083079241212301741">"විකල්ප සඳහා තට්ටු කරන්න"</string>
    -+    <string name="network_switch_metered" msgid="4671730921726992671">"<xliff:g id="NETWORK_TYPE">%1$s</xliff:g> වෙත මාරු විය"</string>
    -+    <string name="network_switch_metered_detail" msgid="5325661434777870353">"උපාංගය <xliff:g id="NEW_NETWORK">%1$s</xliff:g> <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> සඳහා අන්තර්ජාල ප්‍රවේශය නැති විට භාවිත කරයි. ගාස්තු අදාළ විය හැකිය."</string>
    -+    <string name="network_switch_metered_toast" msgid="5779283181685974304">"<xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> සිට <xliff:g id="NEW_NETWORK">%2$s</xliff:g> වෙත මාරු විය"</string>
    -+  <string-array name="network_switch_type_name">
    -+    <item msgid="2952042958050315394">"සෙලියුලර් දත්ත"</item>
    -+    <item msgid="75483255295529161">"Wi-Fi"</item>
    -+    <item msgid="6862614801537202646">"බ්ලූටූත්"</item>
    -+    <item msgid="5447331121797802871">"ඊතර්නෙට්"</item>
    -+    <item msgid="8257233890381651999">"VPN"</item>
    -+  </string-array>
    -+    <string name="network_switch_type_name_unknown" msgid="4552612897806660656">"නොදන්නා ජාල වර්ගයකි"</string>
    -     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Wi-Fi වෙත සම්බන්ධ විය නොහැක"</string>
    -     <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" දුබල අන්තර්ජාල සම්බන්ධතාවයක් ඇත."</string>
    -     <string name="wifi_connect_alert_title" msgid="8455846016001810172">"සම්බන්ධතාවයට ඉඩ දෙන්නද?"</string>
    -@@ -1155,7 +1167,6 @@
    -     <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"භාෂාව හා පිරිසැලසුම තේරීමට තට්ටු කරන්න"</string>
    -     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
    -     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
    --    <string name="candidates_style" msgid="4333913089637062257"><u>"අපේක්ෂකයන්"</u></string>
    -     <string name="ext_media_checking_notification_title" msgid="5734005953288045806">"<xliff:g id="NAME">%s</xliff:g> සූදානම් කරමින්"</string>
    -     <string name="ext_media_checking_notification_message" msgid="4747432538578886744">"වැරදි සඳහා පරීක්ෂා කරමින්"</string>
    -     <string name="ext_media_new_notification_message" msgid="7589986898808506239">"නව <xliff:g id="NAME">%s</xliff:g> අනාවරණය කරන ලදි"</string>
    -@@ -1234,8 +1245,9 @@
    -     <string name="vpn_text_long" msgid="4907843483284977618">"<xliff:g id="SESSION">%s</xliff:g> වෙත සම්බන්ධිතයි. ජාලය කළමනාකරණය කිරීමට තට්ටු කරන්න."</string>
    -     <string name="vpn_lockdown_connecting" msgid="6443438964440960745">"සැමවිටම VPN සම්බන්ධ වෙමින්…"</string>
    -     <string name="vpn_lockdown_connected" msgid="8202679674819213931">"නිරතුරුවම VPN සම්බන්ධ කර ඇත"</string>
    -+    <string name="vpn_lockdown_disconnected" msgid="4532298952570796327">"සැමවිට ක්‍රියාත්මක VPN විසන්ධි කරන ලදී"</string>
    -     <string name="vpn_lockdown_error" msgid="6009249814034708175">"සැමවිට සක්‍රිය VPN දෝෂය"</string>
    --    <string name="vpn_lockdown_config" msgid="4655589351146766608">"වින්‍යාස කිරීමට තට්ටු කරන්න"</string>
    -+    <string name="vpn_lockdown_config" msgid="5099330695245008680">"පිහිටුවීමට තට්ටු කරන්න"</string>
    -     <string name="upload_file" msgid="2897957172366730416">"ගොනුව තෝරන්න"</string>
    -     <string name="no_file_chosen" msgid="6363648562170759465">"ගොනුවක් තෝරාගෙන නැත"</string>
    -     <string name="reset" msgid="2448168080964209908">"යළි පිහිටුවන්න"</string>
    -@@ -1319,7 +1331,7 @@
    -     <string name="storage_usb_drive_label" msgid="4501418548927759953">"<xliff:g id="MANUFACTURER">%s</xliff:g> USB ධාවකය"</string>
    -     <string name="storage_usb" msgid="3017954059538517278">"USB ආචයනය"</string>
    -     <string name="extract_edit_menu_button" msgid="8940478730496610137">"සංස්කරණය කරන්න"</string>
    --    <string name="data_usage_warning_title" msgid="1955638862122232342">"දත්ත භාවිතා අවවාදය"</string>
    -+    <string name="data_usage_warning_title" msgid="3620440638180218181">"දත්ත භාවිතය ගැන ඇඟවීම"</string>
    -     <string name="data_usage_warning_body" msgid="6660692274311972007">"භාවිතය සහ සැකසීම් බැලීමට තට්ටු කරන්න."</string>
    -     <string name="data_usage_3g_limit_title" msgid="4361523876818447683">"2G-3G දත්ත සීමාවට ළඟාවී ඇත"</string>
    -     <string name="data_usage_4g_limit_title" msgid="4609566827219442376">"4G දත්ත සීමාවට ළඟාවී ඇත"</string>
    -@@ -1638,6 +1650,7 @@
    -     <string name="search_language_hint" msgid="7042102592055108574">"භාෂා නම ටයිප් කරන්න"</string>
    -     <string name="language_picker_section_suggested" msgid="8414489646861640885">"යෝජිත"</string>
    -     <string name="language_picker_section_all" msgid="3097279199511617537">"සියලු භාෂා"</string>
    -+    <string name="region_picker_section_all" msgid="8966316787153001779">"සියලු ප්‍රදේශ"</string>
    -     <string name="locale_search_menu" msgid="2560710726687249178">"සෙවීම"</string>
    -     <string name="work_mode_off_title" msgid="8954725060677558855">"වැඩ ප්‍රකාරය ක්‍රියාවිරහිතයි"</string>
    -     <string name="work_mode_off_message" msgid="3286169091278094476">"යෙදුම්, පසුබිම සමමුහුර්ත කිරීම, සහ සම්බන්ධිත විශේෂාංග ඇතුළුව, ක්‍රියා කිරීමට කාර්යාල පැතිකඩට ඉඩ දෙන්න"</string>
    -diff --git a/core/res/res/values-sk/strings.xml b/core/res/res/values-sk/strings.xml
    -index 0a48693..a94c3b4 100644
    ---- a/core/res/res/values-sk/strings.xml
    -+++ b/core/res/res/values-sk/strings.xml
    -@@ -218,6 +218,7 @@
    -     <string name="global_actions" product="default" msgid="2406416831541615258">"Možnosti telefónu"</string>
    -     <string name="global_action_lock" msgid="2844945191792119712">"Zámka obrazovky"</string>
    -     <string name="global_action_power_off" msgid="4471879440839879722">"Vypnúť"</string>
    -+    <string name="global_action_emergency" msgid="7112311161137421166">"Tiesňové volanie"</string>
    -     <string name="global_action_bug_report" msgid="7934010578922304799">"Hlásenie o chybách"</string>
    -     <string name="bugreport_title" msgid="2667494803742548533">"Vytvoriť hlásenie chyby"</string>
    -     <string name="bugreport_message" msgid="398447048750350456">"Týmto zhromaždíte informácie o aktuálnom stave zariadenia. Informácie je potom možné odoslať e-mailom, chvíľu však potrvá, kým bude hlásenie chyby pripravené na odoslanie. Prosíme vás preto o trpezlivosť."</string>
    -@@ -1126,6 +1127,17 @@
    -     <skip />
    -     <string name="wifi_no_internet" msgid="8451173622563841546">"Sieť Wi-Fi nemá prístup k internetu"</string>
    -     <string name="wifi_no_internet_detailed" msgid="8083079241212301741">"Klepnutím získate možnosti"</string>
    -+    <string name="network_switch_metered" msgid="4671730921726992671">"Prepnuté na sieť: <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
    -+    <string name="network_switch_metered_detail" msgid="5325661434777870353">"Keď sieť <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> nemá prístup k internetu, zariadenie používa sieť <xliff:g id="NEW_NETWORK">%1$s</xliff:g>. Môžu sa účtovať poplatky."</string>
    -+    <string name="network_switch_metered_toast" msgid="5779283181685974304">"Prepnuté zo siete <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> na sieť <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
    -+  <string-array name="network_switch_type_name">
    -+    <item msgid="2952042958050315394">"mobilné dáta"</item>
    -+    <item msgid="75483255295529161">"Wi-Fi"</item>
    -+    <item msgid="6862614801537202646">"Bluetooth"</item>
    -+    <item msgid="5447331121797802871">"Ethernet"</item>
    -+    <item msgid="8257233890381651999">"VPN"</item>
    -+  </string-array>
    -+    <string name="network_switch_type_name_unknown" msgid="4552612897806660656">"neznámy typ siete"</string>
    -     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Nepodarilo sa pripojiť k sieti Wi-Fi"</string>
    -     <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" má nekvalitné internetové pripojenie."</string>
    -     <string name="wifi_connect_alert_title" msgid="8455846016001810172">"Povoliť pripojenie?"</string>
    -@@ -1203,7 +1215,6 @@
    -     <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"Klepnutím vyberte jazyk a rozloženie"</string>
    -     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" AÁÄBCČDĎDZDŽEÉFGHCHIÍJKLĽMNŇOÓÔPRŔSŠTŤUÚVWXYÝZŽ"</string>
    -     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
    --    <string name="candidates_style" msgid="4333913089637062257"><u>"kandidáti"</u></string>
    -     <string name="ext_media_checking_notification_title" msgid="5734005953288045806">"Pripravuje sa úložisko <xliff:g id="NAME">%s</xliff:g>"</string>
    -     <string name="ext_media_checking_notification_message" msgid="4747432538578886744">"Prebieha kontrola chýb"</string>
    -     <string name="ext_media_new_notification_message" msgid="7589986898808506239">"Bolo zistené nové úložisko <xliff:g id="NAME">%s</xliff:g>"</string>
    -@@ -1282,8 +1293,9 @@
    -     <string name="vpn_text_long" msgid="4907843483284977618">"Pripojené k relácii <xliff:g id="SESSION">%s</xliff:g>. Po klepnutí môžete sieť spravovať."</string>
    -     <string name="vpn_lockdown_connecting" msgid="6443438964440960745">"Pripájanie k vždy zapnutej sieti VPN…"</string>
    -     <string name="vpn_lockdown_connected" msgid="8202679674819213931">"Pripojenie k vždy zapnutej sieti VPN"</string>
    -+    <string name="vpn_lockdown_disconnected" msgid="4532298952570796327">"Vždy zapnutá sieť VPN bola odpojená"</string>
    -     <string name="vpn_lockdown_error" msgid="6009249814034708175">"Chyba vždy zapnutej siete VPN"</string>
    --    <string name="vpn_lockdown_config" msgid="4655589351146766608">"Klepnutím spustíte konfiguráciu"</string>
    -+    <string name="vpn_lockdown_config" msgid="5099330695245008680">"Klepnutím prejdete do Nastavení"</string>
    -     <string name="upload_file" msgid="2897957172366730416">"Zvoliť súbor"</string>
    -     <string name="no_file_chosen" msgid="6363648562170759465">"Nie je vybratý žiadny súbor"</string>
    -     <string name="reset" msgid="2448168080964209908">"Obnoviť"</string>
    -@@ -1369,7 +1381,7 @@
    -     <string name="storage_usb_drive_label" msgid="4501418548927759953">"Disk USB <xliff:g id="MANUFACTURER">%s</xliff:g>"</string>
    -     <string name="storage_usb" msgid="3017954059538517278">"Ukladací priestor USB"</string>
    -     <string name="extract_edit_menu_button" msgid="8940478730496610137">"Upraviť"</string>
    --    <string name="data_usage_warning_title" msgid="1955638862122232342">"Upozornenie o využití dát"</string>
    -+    <string name="data_usage_warning_title" msgid="3620440638180218181">"Upozornenie na spotrebu dát"</string>
    -     <string name="data_usage_warning_body" msgid="6660692274311972007">"Klepnutím zobrazíte využitie a nastavenia."</string>
    -     <string name="data_usage_3g_limit_title" msgid="4361523876818447683">"Bol dosiahnutý limit 2G–3G"</string>
    -     <string name="data_usage_4g_limit_title" msgid="4609566827219442376">"Bol dosiahnutý limit 4G"</string>
    -@@ -1664,7 +1676,7 @@
    -     </plurals>
    -     <string name="zen_mode_until" msgid="7336308492289875088">"Do <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
    -     <string name="zen_mode_alarm" msgid="9128205721301330797">"Do <xliff:g id="FORMATTEDTIME">%1$s</xliff:g> (ďalší budík)"</string>
    --    <string name="zen_mode_forever" msgid="7420011936770086993">"Dokým túto funkciu nevypnete"</string>
    -+    <string name="zen_mode_forever" msgid="7420011936770086993">"Kým túto funkciu nevypnete"</string>
    -     <string name="zen_mode_forever_dnd" msgid="3792132696572189081">"Dokým nevypnete stav Nerušiť"</string>
    -     <string name="zen_mode_rule_name_combination" msgid="191109939968076477">"<xliff:g id="FIRST">%1$s</xliff:g> / <xliff:g id="REST">%2$s</xliff:g>"</string>
    -     <string name="toolbar_collapse_description" msgid="2821479483960330739">"Zbaliť"</string>
    -@@ -1708,6 +1720,7 @@
    -     <string name="search_language_hint" msgid="7042102592055108574">"Zadajte názov jazyka"</string>
    -     <string name="language_picker_section_suggested" msgid="8414489646861640885">"Navrhované"</string>
    -     <string name="language_picker_section_all" msgid="3097279199511617537">"Všetky jazyky"</string>
    -+    <string name="region_picker_section_all" msgid="8966316787153001779">"Všetky regióny"</string>
    -     <string name="locale_search_menu" msgid="2560710726687249178">"Vyhľadávanie"</string>
    -     <string name="work_mode_off_title" msgid="8954725060677558855">"Pracovný režim je VYPNUTÝ"</string>
    -     <string name="work_mode_off_message" msgid="3286169091278094476">"Povoľte fungovanie pracovného profilu vrátane aplikácií, synchronizácie na pozadí a súvisiacich funkcií."</string>
    -diff --git a/core/res/res/values-sl/strings.xml b/core/res/res/values-sl/strings.xml
    -index 7b8a03a..a19643b 100644
    ---- a/core/res/res/values-sl/strings.xml
    -+++ b/core/res/res/values-sl/strings.xml
    -@@ -218,6 +218,7 @@
    -     <string name="global_actions" product="default" msgid="2406416831541615258">"Možnosti telefona"</string>
    -     <string name="global_action_lock" msgid="2844945191792119712">"Zaklep zaslona"</string>
    -     <string name="global_action_power_off" msgid="4471879440839879722">"Izklopi"</string>
    -+    <string name="global_action_emergency" msgid="7112311161137421166">"Klic v sili"</string>
    -     <string name="global_action_bug_report" msgid="7934010578922304799">"Poročilo o napakah"</string>
    -     <string name="bugreport_title" msgid="2667494803742548533">"Ustvari poročilo o napakah"</string>
    -     <string name="bugreport_message" msgid="398447048750350456">"S tem bodo zbrani podatki o trenutnem stanju naprave, ki bodo poslani v e-poštnem sporočilu. Izvedba poročila o napakah in priprava trajata nekaj časa, zato bodite potrpežljivi."</string>
    -@@ -1126,6 +1127,17 @@
    -     <skip />
    -     <string name="wifi_no_internet" msgid="8451173622563841546">"Omrežje Wi-Fi nima dostopa do interneta"</string>
    -     <string name="wifi_no_internet_detailed" msgid="8083079241212301741">"Dotaknite se za možnosti"</string>
    -+    <string name="network_switch_metered" msgid="4671730921726992671">"Preklopljeno na omrežje vrste <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
    -+    <string name="network_switch_metered_detail" msgid="5325661434777870353">"Naprava uporabi omrežje vrste <xliff:g id="NEW_NETWORK">%1$s</xliff:g>, ko omrežje vrste <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> nima dostopa do interneta. Prenos podatkov se lahko zaračuna posebej."</string>
    -+    <string name="network_switch_metered_toast" msgid="5779283181685974304">"Preklopljeno z omrežja vrste <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> na omrežje vrste <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
    -+  <string-array name="network_switch_type_name">
    -+    <item msgid="2952042958050315394">"prenos podatkov v mobilnih omrežjih"</item>
    -+    <item msgid="75483255295529161">"Wi-Fi"</item>
    -+    <item msgid="6862614801537202646">"Bluetooth"</item>
    -+    <item msgid="5447331121797802871">"Ethernet"</item>
    -+    <item msgid="8257233890381651999">"VPN"</item>
    -+  </string-array>
    -+    <string name="network_switch_type_name_unknown" msgid="4552612897806660656">"neznana vrsta omrežja"</string>
    -     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Z omrežjem Wi-Fi se ni mogoče povezati"</string>
    -     <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" ima slabo internetno povezavo."</string>
    -     <string name="wifi_connect_alert_title" msgid="8455846016001810172">"Ali dovolite vzpostavitev povezave?"</string>
    -@@ -1203,7 +1215,6 @@
    -     <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"Dotaknite se, če želite izbrati jezik in postavitev."</string>
    -     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
    -     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
    --    <string name="candidates_style" msgid="4333913089637062257"><u>"kandidati"</u></string>
    -     <string name="ext_media_checking_notification_title" msgid="5734005953288045806">"Pripravljanje shrambe <xliff:g id="NAME">%s</xliff:g>"</string>
    -     <string name="ext_media_checking_notification_message" msgid="4747432538578886744">"Iskanje napak"</string>
    -     <string name="ext_media_new_notification_message" msgid="7589986898808506239">"Zaznana je bila nova shramba <xliff:g id="NAME">%s</xliff:g>"</string>
    -@@ -1282,8 +1293,9 @@
    -     <string name="vpn_text_long" msgid="4907843483284977618">"Povezan z mestom <xliff:g id="SESSION">%s</xliff:g>. Tapnite za upravljanje omrežja."</string>
    -     <string name="vpn_lockdown_connecting" msgid="6443438964440960745">"Povezovanje v stalno vklopljeno navidezno zasebno omrežje ..."</string>
    -     <string name="vpn_lockdown_connected" msgid="8202679674819213931">"Vzpostavljena povezava v stalno vklopljeno navidezno zasebno omrežje"</string>
    -+    <string name="vpn_lockdown_disconnected" msgid="4532298952570796327">"Povezava s stalno vklopljenim VPN-jem je prekinjena"</string>
    -     <string name="vpn_lockdown_error" msgid="6009249814034708175">"Napaka stalno vklopljenega navideznega zasebnega omrežja"</string>
    --    <string name="vpn_lockdown_config" msgid="4655589351146766608">"Dotanite se, če želite konfigurirati"</string>
    -+    <string name="vpn_lockdown_config" msgid="5099330695245008680">"Dotaknite se, če želite nastaviti"</string>
    -     <string name="upload_file" msgid="2897957172366730416">"Izberi datoteko"</string>
    -     <string name="no_file_chosen" msgid="6363648562170759465">"Nobena datoteka ni izbrana"</string>
    -     <string name="reset" msgid="2448168080964209908">"Ponastavi"</string>
    -@@ -1369,7 +1381,7 @@
    -     <string name="storage_usb_drive_label" msgid="4501418548927759953">"Pogon USB <xliff:g id="MANUFACTURER">%s</xliff:g>"</string>
    -     <string name="storage_usb" msgid="3017954059538517278">"Pomnilnik USB"</string>
    -     <string name="extract_edit_menu_button" msgid="8940478730496610137">"Uredi"</string>
    --    <string name="data_usage_warning_title" msgid="1955638862122232342">"Opozorilo o uporabi podatkov"</string>
    -+    <string name="data_usage_warning_title" msgid="3620440638180218181">"Opozorilo o preneseni količini podatkov"</string>
    -     <string name="data_usage_warning_body" msgid="6660692274311972007">"Dot. se za ogled upor. in nast."</string>
    -     <string name="data_usage_3g_limit_title" msgid="4361523876818447683">"Dosežena pod. omejitev za 2G/3G"</string>
    -     <string name="data_usage_4g_limit_title" msgid="4609566827219442376">"Dosežena pod. omejitev za 4G"</string>
    -@@ -1708,6 +1720,7 @@
    -     <string name="search_language_hint" msgid="7042102592055108574">"Vnesite ime jezika"</string>
    -     <string name="language_picker_section_suggested" msgid="8414489646861640885">"Predlagano"</string>
    -     <string name="language_picker_section_all" msgid="3097279199511617537">"Vsi jeziki"</string>
    -+    <string name="region_picker_section_all" msgid="8966316787153001779">"Vse regije"</string>
    -     <string name="locale_search_menu" msgid="2560710726687249178">"Išči"</string>
    -     <string name="work_mode_off_title" msgid="8954725060677558855">"Delovni način IZKLOPLJEN"</string>
    -     <string name="work_mode_off_message" msgid="3286169091278094476">"Dovoljeno delovanje delovnega profila, vključno z aplikacijami, sinhronizacijo v ozadju in povezanimi funkcijami."</string>
    -diff --git a/core/res/res/values-sq-rAL/strings.xml b/core/res/res/values-sq-rAL/strings.xml
    -index 05f0e59..624b004 100644
    ---- a/core/res/res/values-sq-rAL/strings.xml
    -+++ b/core/res/res/values-sq-rAL/strings.xml
    -@@ -214,6 +214,7 @@
    -     <string name="global_actions" product="default" msgid="2406416831541615258">"Opsionet e telefonit"</string>
    -     <string name="global_action_lock" msgid="2844945191792119712">"Kyçja e ekranit"</string>
    -     <string name="global_action_power_off" msgid="4471879440839879722">"Fik"</string>
    -+    <string name="global_action_emergency" msgid="7112311161137421166">"Urgjenca"</string>
    -     <string name="global_action_bug_report" msgid="7934010578922304799">"Raporti i defekteve në kod"</string>
    -     <string name="bugreport_title" msgid="2667494803742548533">"Merr raportin e defekteve në kod"</string>
    -     <string name="bugreport_message" msgid="398447048750350456">"Ky funksion mundëson mbledhjen e informacioneve mbi gjendjen aktuale të pajisjes për ta dërguar si mesazh mail-i. Do të duhet pak kohë nga nisja e raportit të defekteve në kod. Faleminderit për durimin."</string>
    -@@ -1076,6 +1077,17 @@
    -     <skip />
    -     <string name="wifi_no_internet" msgid="8451173622563841546">"Wi-Fi nuk ka qasje në internet"</string>
    -     <string name="wifi_no_internet_detailed" msgid="8083079241212301741">"Trokit për opsionet"</string>
    -+    <string name="network_switch_metered" msgid="4671730921726992671">"Kaloi te <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
    -+    <string name="network_switch_metered_detail" msgid="5325661434777870353">"Pajisja përdor <xliff:g id="NEW_NETWORK">%1$s</xliff:g> kur <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> nuk ka qasje në internet. Mund të zbatohen tarifa."</string>
    -+    <string name="network_switch_metered_toast" msgid="5779283181685974304">"Kaloi nga <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> te <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
    -+  <string-array name="network_switch_type_name">
    -+    <item msgid="2952042958050315394">"të dhënat celulare"</item>
    -+    <item msgid="75483255295529161">"Wi-Fi"</item>
    -+    <item msgid="6862614801537202646">"Bluetooth"</item>
    -+    <item msgid="5447331121797802871">"Eternet"</item>
    -+    <item msgid="8257233890381651999">"VPN"</item>
    -+  </string-array>
    -+    <string name="network_switch_type_name_unknown" msgid="4552612897806660656">"një lloj rrjeti i panjohur"</string>
    -     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Nuk mund të lidhej me Wi-Fi"</string>
    -     <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" ka një lidhje të dobët interneti."</string>
    -     <string name="wifi_connect_alert_title" msgid="8455846016001810172">"Të lejohet lidhja?"</string>
    -@@ -1153,7 +1165,6 @@
    -     <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"Trokit për të zgjedhur gjuhën dhe strukturën"</string>
    -     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
    -     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
    --    <string name="candidates_style" msgid="4333913089637062257"><u>"kandidatë"</u></string>
    -     <string name="ext_media_checking_notification_title" msgid="5734005953288045806">"Po përgatit <xliff:g id="NAME">%s</xliff:g>"</string>
    -     <string name="ext_media_checking_notification_message" msgid="4747432538578886744">"Po kontrollon për gabime"</string>
    -     <string name="ext_media_new_notification_message" msgid="7589986898808506239">"U zbulua karta e re <xliff:g id="NAME">%s</xliff:g>"</string>
    -@@ -1232,8 +1243,9 @@
    -     <string name="vpn_text_long" msgid="4907843483284977618">"Lidhur me <xliff:g id="SESSION">%s</xliff:g>. Trokit për të menaxhuar rrjetin."</string>
    -     <string name="vpn_lockdown_connecting" msgid="6443438964440960745">"Po lidh VPN-në për aktivizim të përhershëm…"</string>
    -     <string name="vpn_lockdown_connected" msgid="8202679674819213931">"VPN e lidhur në mënyrë të përhershme"</string>
    -+    <string name="vpn_lockdown_disconnected" msgid="4532298952570796327">"Rrjeti VPN gjithmonë aktiv u shkëput"</string>
    -     <string name="vpn_lockdown_error" msgid="6009249814034708175">"Gabimi VPN-je për aktivizimin e përhershëm"</string>
    --    <string name="vpn_lockdown_config" msgid="4655589351146766608">"Trokit për të konfiguruar"</string>
    -+    <string name="vpn_lockdown_config" msgid="5099330695245008680">"Trokit për ta konfiguruar"</string>
    -     <string name="upload_file" msgid="2897957172366730416">"Zgjidh skedarin"</string>
    -     <string name="no_file_chosen" msgid="6363648562170759465">"Nuk u zgjodh asnjë skedar"</string>
    -     <string name="reset" msgid="2448168080964209908">"Rivendos"</string>
    -@@ -1317,7 +1329,7 @@
    -     <string name="storage_usb_drive_label" msgid="4501418548927759953">"USB-ja nga <xliff:g id="MANUFACTURER">%s</xliff:g>"</string>
    -     <string name="storage_usb" msgid="3017954059538517278">"Hapësira ruajtëse e USB-së"</string>
    -     <string name="extract_edit_menu_button" msgid="8940478730496610137">"Redakto"</string>
    --    <string name="data_usage_warning_title" msgid="1955638862122232342">"Paralajmërim për përdorimin e të dhënave"</string>
    -+    <string name="data_usage_warning_title" msgid="3620440638180218181">"Sinjalizimi i të dhënave"</string>
    -     <string name="data_usage_warning_body" msgid="6660692274311972007">"Trokit për të parë përdorimin dhe cilësimet."</string>
    -     <string name="data_usage_3g_limit_title" msgid="4361523876818447683">"Kufiri i të dhënave 2G-3G u arrit"</string>
    -     <string name="data_usage_4g_limit_title" msgid="4609566827219442376">"Kufiri i të dhënave 4G u arrit"</string>
    -@@ -1636,6 +1648,7 @@
    -     <string name="search_language_hint" msgid="7042102592055108574">"Shkruaj emrin e gjuhës"</string>
    -     <string name="language_picker_section_suggested" msgid="8414489646861640885">"Sugjeruar"</string>
    -     <string name="language_picker_section_all" msgid="3097279199511617537">"Të gjitha gjuhët"</string>
    -+    <string name="region_picker_section_all" msgid="8966316787153001779">"Të gjitha rajonet"</string>
    -     <string name="locale_search_menu" msgid="2560710726687249178">"Kërko"</string>
    -     <string name="work_mode_off_title" msgid="8954725060677558855">"Modaliteti i punës është JOAKTIV"</string>
    -     <string name="work_mode_off_message" msgid="3286169091278094476">"Lejoje profilin e punës të funksionojë, duke përfshirë aplikacionet, sinkronizimin në sfond dhe funksionet e lidhura."</string>
    -diff --git a/core/res/res/values-sr/strings.xml b/core/res/res/values-sr/strings.xml
    -index 517d777..395b049 100644
    ---- a/core/res/res/values-sr/strings.xml
    -+++ b/core/res/res/values-sr/strings.xml
    -@@ -152,7 +152,7 @@
    -     <string name="httpErrorAuth" msgid="1435065629438044534">"Није могуће потврдити аутентичност."</string>
    -     <string name="httpErrorProxyAuth" msgid="1788207010559081331">"Потврда идентитета преко прокси сервера није успела."</string>
    -     <string name="httpErrorConnect" msgid="8714273236364640549">"Није могуће повезати се са сервером."</string>
    --    <string name="httpErrorIO" msgid="2340558197489302188">"Није могуће комуницирати са сервером. Покушајте поново касније."</string>
    -+    <string name="httpErrorIO" msgid="2340558197489302188">"Није могуће комуницирати са сервером. Пробајте поново касније."</string>
    -     <string name="httpErrorTimeout" msgid="4743403703762883954">"Веза са сервером је истекла."</string>
    -     <string name="httpErrorRedirectLoop" msgid="8679596090392779516">"Страница садржи превише веза за преусмеравање са сервера."</string>
    -     <string name="httpErrorUnsupportedScheme" msgid="5015730812906192208">"Протокол није подржан."</string>
    -@@ -160,7 +160,7 @@
    -     <string name="httpErrorBadUrl" msgid="3636929722728881972">"Страницу није могуће отворити зато што је URL адреса неважећа."</string>
    -     <string name="httpErrorFile" msgid="2170788515052558676">"Није могуће приступити датотеци."</string>
    -     <string name="httpErrorFileNotFound" msgid="6203856612042655084">"Није могуће пронаћи тражену датотеку."</string>
    --    <string name="httpErrorTooManyRequests" msgid="1235396927087188253">"Превише захтева се обрађује. Покушајте поново касније."</string>
    -+    <string name="httpErrorTooManyRequests" msgid="1235396927087188253">"Превише захтева се обрађује. Пробајте поново касније."</string>
    -     <string name="notification_title" msgid="8967710025036163822">"Грешка при пријављивању за <xliff:g id="ACCOUNT">%1$s</xliff:g>"</string>
    -     <string name="contentServiceSync" msgid="8353523060269335667">"Синхронизација"</string>
    -     <string name="contentServiceSyncNotificationTitle" msgid="397743349191901458">"Синхронизација"</string>
    -@@ -216,6 +216,7 @@
    -     <string name="global_actions" product="default" msgid="2406416831541615258">"Опције телефона"</string>
    -     <string name="global_action_lock" msgid="2844945191792119712">"Закључај екран"</string>
    -     <string name="global_action_power_off" msgid="4471879440839879722">"Искључи"</string>
    -+    <string name="global_action_emergency" msgid="7112311161137421166">"Хитни позив"</string>
    -     <string name="global_action_bug_report" msgid="7934010578922304799">"Извештај о грешци"</string>
    -     <string name="bugreport_title" msgid="2667494803742548533">"Направи извештај о грешци"</string>
    -     <string name="bugreport_message" msgid="398447048750350456">"Овим ће се прикупити информације о тренутном стању уређаја како би биле послате у поруци е-поште. Од започињања извештаја о грешци до тренутка за његово слање проћи ће неко време; будите стрпљиви."</string>
    -@@ -256,9 +257,9 @@
    -     <string name="permgrouplab_storage" msgid="1971118770546336966">"Складиште"</string>
    -     <string name="permgroupdesc_storage" msgid="637758554581589203">"приступа сликама, медијима и датотекама на уређају"</string>
    -     <string name="permgrouplab_microphone" msgid="171539900250043464">"Микрофон"</string>
    --    <string name="permgroupdesc_microphone" msgid="4988812113943554584">"снима аудио снимке"</string>
    -+    <string name="permgroupdesc_microphone" msgid="4988812113943554584">"снима аудио"</string>
    -     <string name="permgrouplab_camera" msgid="4820372495894586615">"Камера"</string>
    --    <string name="permgroupdesc_camera" msgid="3250611594678347720">"снима слике и видео снимке"</string>
    -+    <string name="permgroupdesc_camera" msgid="3250611594678347720">"снима слике и видео"</string>
    -     <string name="permgrouplab_phone" msgid="5229115638567440675">"Телефон"</string>
    -     <string name="permgroupdesc_phone" msgid="6234224354060641055">"упућује телефонске позиве и управља њима"</string>
    -     <string name="permgrouplab_sensors" msgid="416037179223226722">"Сензори за тело"</string>
    -@@ -439,19 +440,19 @@
    -     <string name="permdesc_manageFingerprint" msgid="178208705828055464">"Дозвољава апликацији да активира методе за додавање и брисање шаблона отисака прстију који ће се користити."</string>
    -     <string name="permlab_useFingerprint" msgid="3150478619915124905">"користи хардвер за отиске прстију"</string>
    -     <string name="permdesc_useFingerprint" msgid="9165097460730684114">"Дозвољава апликацији да користи хардвер за отиске прстију ради потврде аутентичности"</string>
    --    <string name="fingerprint_acquired_partial" msgid="735082772341716043">"Откривен је делимични отисак прста. Покушајте поново."</string>
    --    <string name="fingerprint_acquired_insufficient" msgid="4596546021310923214">"Није успела обрада отиска прста. Покушајте поново."</string>
    -+    <string name="fingerprint_acquired_partial" msgid="735082772341716043">"Откривен је делимични отисак прста. Пробајте поново."</string>
    -+    <string name="fingerprint_acquired_insufficient" msgid="4596546021310923214">"Није успела обрада отиска прста. Пробајте поново."</string>
    -     <string name="fingerprint_acquired_imager_dirty" msgid="1087209702421076105">"Сензор за отиске прстију је прљав. Очистите га и покушајте поново."</string>
    --    <string name="fingerprint_acquired_too_fast" msgid="6470642383109155969">"Пребрзо сте померили прст. Покушајте поново."</string>
    --    <string name="fingerprint_acquired_too_slow" msgid="59250885689661653">"Превише споро сте померили прст. Покушајте поново."</string>
    -+    <string name="fingerprint_acquired_too_fast" msgid="6470642383109155969">"Пребрзо сте померили прст. Пробајте поново."</string>
    -+    <string name="fingerprint_acquired_too_slow" msgid="59250885689661653">"Превише споро сте померили прст. Пробајте поново."</string>
    -   <string-array name="fingerprint_acquired_vendor">
    -   </string-array>
    -     <string name="fingerprint_error_hw_not_available" msgid="7955921658939936596">"Хардвер за отиске прстију није доступан."</string>
    -     <string name="fingerprint_error_no_space" msgid="1055819001126053318">"Није могуће сачувати отисак прста. Уклоните неки од постојећих отисака прстију."</string>
    --    <string name="fingerprint_error_timeout" msgid="3927186043737732875">"Временско ограничење за отисак прста је истекло. Покушајте поново."</string>
    -+    <string name="fingerprint_error_timeout" msgid="3927186043737732875">"Временско ограничење за отисак прста је истекло. Пробајте поново."</string>
    -     <string name="fingerprint_error_canceled" msgid="4402024612660774395">"Радња са отиском прста је отказана."</string>
    --    <string name="fingerprint_error_lockout" msgid="5536934748136933450">"Превише покушаја. Покушајте поново касније."</string>
    --    <string name="fingerprint_error_unable_to_process" msgid="6107816084103552441">"Покушајте поново."</string>
    -+    <string name="fingerprint_error_lockout" msgid="5536934748136933450">"Превише покушаја. Пробајте поново касније."</string>
    -+    <string name="fingerprint_error_unable_to_process" msgid="6107816084103552441">"Пробајте поново."</string>
    -     <string name="fingerprint_name_template" msgid="5870957565512716938">"Прст <xliff:g id="FINGERID">%d</xliff:g>"</string>
    -   <string-array name="fingerprint_error_vendor">
    -   </string-array>
    -@@ -679,8 +680,8 @@
    -     <string name="lockscreen_emergency_call" msgid="5298642613417801888">"Хитне службе"</string>
    -     <string name="lockscreen_return_to_call" msgid="5244259785500040021">"Назад на позив"</string>
    -     <string name="lockscreen_pattern_correct" msgid="9039008650362261237">"Тачно!"</string>
    --    <string name="lockscreen_pattern_wrong" msgid="4317955014948108794">"Покушајте поново"</string>
    --    <string name="lockscreen_password_wrong" msgid="5737815393253165301">"Покушајте поново"</string>
    -+    <string name="lockscreen_pattern_wrong" msgid="4317955014948108794">"Пробајте поново"</string>
    -+    <string name="lockscreen_password_wrong" msgid="5737815393253165301">"Пробајте поново"</string>
    -     <string name="lockscreen_storage_locked" msgid="9167551160010625200">"Откључај за све функције и податке"</string>
    -     <string name="faceunlock_multiple_failures" msgid="754137583022792429">"Премашен је највећи дозвољени број покушаја Откључавања лицем"</string>
    -     <string name="lockscreen_missing_sim_message_short" msgid="5099439277819215399">"Нема SIM картице"</string>
    -@@ -704,19 +705,19 @@
    -     <string name="lockscreen_sim_puk_locked_instructions" msgid="8127916255245181063">"Погледајте Кориснички водич или контактирајте Корисничку подршку."</string>
    -     <string name="lockscreen_sim_locked_message" msgid="8066660129206001039">"SIM картица је закључана."</string>
    -     <string name="lockscreen_sim_unlock_progress_dialog_message" msgid="595323214052881264">"Откључавање SIM картице…"</string>
    --    <string name="lockscreen_too_many_failed_attempts_dialog_message" msgid="6481623830344107222">"<xliff:g id="NUMBER_0">%1$d</xliff:g> пута сте неправилно нацртали шаблон за откључавање. \n\nПокушајте поново за <xliff:g id="NUMBER_1">%2$d</xliff:g> секунде(и)."</string>
    --    <string name="lockscreen_too_many_failed_password_attempts_dialog_message" msgid="2725973286239344555">"<xliff:g id="NUMBER_0">%1$d</xliff:g> пута сте погрешно унели лозинку. \n\nПокушајте поново за <xliff:g id="NUMBER_1">%2$d</xliff:g> секунде(и)."</string>
    --    <string name="lockscreen_too_many_failed_pin_attempts_dialog_message" msgid="6216672706545696955">"<xliff:g id="NUMBER_0">%1$d</xliff:g> пута сте погрешно унели PIN. \n\nПокушајте поново за <xliff:g id="NUMBER_1">%2$d</xliff:g> секунде(и)."</string>
    --    <string name="lockscreen_failed_attempts_almost_glogin" product="tablet" msgid="9191611984625460820">"<xliff:g id="NUMBER_0">%1$d</xliff:g> пута сте нетачно унели шаблон за откључавање. Након још <xliff:g id="NUMBER_1">%2$d</xliff:g> несупешна(их) покушаја, од вас ће бити затражено да откључате таблет помоћу података за пријављивање на Google.\n\n Покушајте поново за <xliff:g id="NUMBER_2">%3$d</xliff:g> секунде(и)."</string>
    --    <string name="lockscreen_failed_attempts_almost_glogin" product="tv" msgid="5316664559603394684">"Неисправно сте нацртали шаблон за откључавање <xliff:g id="NUMBER_0">%1$d</xliff:g> пута. После још <xliff:g id="NUMBER_1">%2$d</xliff:g> неуспешна(их) покушаја од вас ће бити затражено да откључате ТВ помоћу података за пријављивање на Google.\n\n Покушајте поново за <xliff:g id="NUMBER_2">%3$d</xliff:g> сек."</string>
    --    <string name="lockscreen_failed_attempts_almost_glogin" product="default" msgid="2590227559763762751">"<xliff:g id="NUMBER_0">%1$d</xliff:g> пута сте нетачно унели шаблон за откључавање. Након још <xliff:g id="NUMBER_1">%2$d</xliff:g> несупешна(их) покушаја, од вас ће бити затражено да откључате телефон помоћу података за пријављивање на Google.\n\n Покушајте поново за <xliff:g id="NUMBER_2">%3$d</xliff:g> секунде(и)."</string>
    -+    <string name="lockscreen_too_many_failed_attempts_dialog_message" msgid="6481623830344107222">"<xliff:g id="NUMBER_0">%1$d</xliff:g> пута сте неправилно нацртали шаблон за откључавање. \n\nПробајте поново за <xliff:g id="NUMBER_1">%2$d</xliff:g> секунде(и)."</string>
    -+    <string name="lockscreen_too_many_failed_password_attempts_dialog_message" msgid="2725973286239344555">"<xliff:g id="NUMBER_0">%1$d</xliff:g> пута сте погрешно унели лозинку. \n\nПробајте поново за <xliff:g id="NUMBER_1">%2$d</xliff:g> секунде(и)."</string>
    -+    <string name="lockscreen_too_many_failed_pin_attempts_dialog_message" msgid="6216672706545696955">"<xliff:g id="NUMBER_0">%1$d</xliff:g> пута сте погрешно унели PIN. \n\nПробајте поново за <xliff:g id="NUMBER_1">%2$d</xliff:g> секунде(и)."</string>
    -+    <string name="lockscreen_failed_attempts_almost_glogin" product="tablet" msgid="9191611984625460820">"<xliff:g id="NUMBER_0">%1$d</xliff:g> пута сте нетачно унели шаблон за откључавање. Након још <xliff:g id="NUMBER_1">%2$d</xliff:g> несупешна(их) покушаја, од вас ће бити затражено да откључате таблет помоћу података за пријављивање на Google.\n\n Пробајте поново за <xliff:g id="NUMBER_2">%3$d</xliff:g> секунде(и)."</string>
    -+    <string name="lockscreen_failed_attempts_almost_glogin" product="tv" msgid="5316664559603394684">"Неисправно сте нацртали шаблон за откључавање <xliff:g id="NUMBER_0">%1$d</xliff:g> пута. После још <xliff:g id="NUMBER_1">%2$d</xliff:g> неуспешна(их) покушаја од вас ће бити затражено да откључате ТВ помоћу података за пријављивање на Google.\n\n Пробајте поново за <xliff:g id="NUMBER_2">%3$d</xliff:g> сек."</string>
    -+    <string name="lockscreen_failed_attempts_almost_glogin" product="default" msgid="2590227559763762751">"<xliff:g id="NUMBER_0">%1$d</xliff:g> пута сте нетачно унели шаблон за откључавање. Након још <xliff:g id="NUMBER_1">%2$d</xliff:g> несупешна(их) покушаја, од вас ће бити затражено да откључате телефон помоћу података за пријављивање на Google.\n\n Пробајте поново за <xliff:g id="NUMBER_2">%3$d</xliff:g> секунде(и)."</string>
    -     <string name="lockscreen_failed_attempts_almost_at_wipe" product="tablet" msgid="6128106399745755604">"Неправилно сте покушали да откључате таблет <xliff:g id="NUMBER_0">%1$d</xliff:g> пута. Након још неуспешних покушаја (<xliff:g id="NUMBER_1">%2$d</xliff:g>) таблет ће бити ресетован на фабричка подешавања и сви кориснички подаци ће бити изгубљени."</string>
    -     <string name="lockscreen_failed_attempts_almost_at_wipe" product="tv" msgid="950408382418270260">"Покушали сте да откључате ТВ нетачно <xliff:g id="NUMBER_0">%1$d</xliff:g> пута. После још <xliff:g id="NUMBER_1">%2$d</xliff:g> неуспешна(их) покушаја ТВ ће бити ресетован на подразумевана фабричка подешавања и сви кориснички подаци ће бити изгубљени."</string>
    -     <string name="lockscreen_failed_attempts_almost_at_wipe" product="default" msgid="8603565142156826565">"Неисправно сте покушали да откључате телефон <xliff:g id="NUMBER_0">%1$d</xliff:g> пута. Након још неуспешних покушаја (<xliff:g id="NUMBER_1">%2$d</xliff:g>) телефон ће бити ресетован на фабричка подешавања и сви кориснички подаци ће бити изгубљени."</string>
    -     <string name="lockscreen_failed_attempts_now_wiping" product="tablet" msgid="280873516493934365">"Неисправно сте покушали да откључате таблет <xliff:g id="NUMBER">%d</xliff:g> пута. Таблет ће сада бити враћен на подразумевана фабричка подешавања."</string>
    -     <string name="lockscreen_failed_attempts_now_wiping" product="tv" msgid="3195755534096192191">"Покушали сте да откључате ТВ нетачно <xliff:g id="NUMBER">%d</xliff:g> пута. ТВ ће сада бити ресетован на подразумевана фабричка подешавања."</string>
    -     <string name="lockscreen_failed_attempts_now_wiping" product="default" msgid="3025504721764922246">"Неисправно сте покушали да откључате телефон <xliff:g id="NUMBER">%d</xliff:g> пута. Телефон ће сада бити враћен на подразумевана фабричка подешавања."</string>
    --    <string name="lockscreen_too_many_failed_attempts_countdown" msgid="6251480343394389665">"Покушајте поново за <xliff:g id="NUMBER">%d</xliff:g> секунде(и)."</string>
    -+    <string name="lockscreen_too_many_failed_attempts_countdown" msgid="6251480343394389665">"Пробајте поново за <xliff:g id="NUMBER">%d</xliff:g> секунде(и)."</string>
    -     <string name="lockscreen_forgot_pattern_button_text" msgid="2626999449610695930">"Заборавили сте шаблон?"</string>
    -     <string name="lockscreen_glogin_forgot_pattern" msgid="2588521501166032747">"Откључавање налога"</string>
    -     <string name="lockscreen_glogin_too_many_attempts" msgid="2751368605287288808">"Превише покушаја уноса шаблона"</string>
    -@@ -1101,6 +1102,17 @@
    -     <skip />
    -     <string name="wifi_no_internet" msgid="8451173622563841546">"Wi-Fi нема приступ интернету"</string>
    -     <string name="wifi_no_internet_detailed" msgid="8083079241212301741">"Додирните за опције"</string>
    -+    <string name="network_switch_metered" msgid="4671730921726992671">"Прешли сте на тип мреже <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
    -+    <string name="network_switch_metered_detail" msgid="5325661434777870353">"Уређај користи тип мреже <xliff:g id="NEW_NETWORK">%1$s</xliff:g> када тип мреже <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> нема приступ интернету. Можда ће се наплаћивати трошкови."</string>
    -+    <string name="network_switch_metered_toast" msgid="5779283181685974304">"Прешли сте са типа мреже <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> на тип мреже <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
    -+  <string-array name="network_switch_type_name">
    -+    <item msgid="2952042958050315394">"мобилни подаци"</item>
    -+    <item msgid="75483255295529161">"Wi-Fi"</item>
    -+    <item msgid="6862614801537202646">"Bluetooth"</item>
    -+    <item msgid="5447331121797802871">"Етернет"</item>
    -+    <item msgid="8257233890381651999">"VPN"</item>
    -+  </string-array>
    -+    <string name="network_switch_type_name_unknown" msgid="4552612897806660656">"непознат тип мреже"</string>
    -     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Није могуће повезати са Wi-Fi мрежом"</string>
    -     <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" има лошу интернет везу."</string>
    -     <string name="wifi_connect_alert_title" msgid="8455846016001810172">"Желите ли да дозволите повезивање?"</string>
    -@@ -1172,13 +1184,12 @@
    -     <string name="share_remote_bugreport_action" msgid="6249476773913384948">"ДЕЛИ"</string>
    -     <string name="decline_remote_bugreport_action" msgid="6230987241608770062">"ОДБИЈ"</string>
    -     <string name="select_input_method" msgid="8547250819326693584">"Промените тастатуру"</string>
    --    <string name="show_ime" msgid="2506087537466597099">"Задржи га на екрану док је физичка тастатура активна"</string>
    -+    <string name="show_ime" msgid="2506087537466597099">"Задржи је на екрану док је физичка тастатура активна"</string>
    -     <string name="hardware" msgid="194658061510127999">"Прикажи виртуелну тастатуру"</string>
    -     <string name="select_keyboard_layout_notification_title" msgid="597189518763083494">"Конфигуришите физичку тастатуру"</string>
    -     <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"Додирните да бисте изабрали језик и распоред"</string>
    -     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
    -     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
    --    <string name="candidates_style" msgid="4333913089637062257"><u>"кандидати"</u></string>
    -     <string name="ext_media_checking_notification_title" msgid="5734005953288045806">"<xliff:g id="NAME">%s</xliff:g> се припрема"</string>
    -     <string name="ext_media_checking_notification_message" msgid="4747432538578886744">"Проверава се да ли постоје грешке"</string>
    -     <string name="ext_media_new_notification_message" msgid="7589986898808506239">"Нови уређај <xliff:g id="NAME">%s</xliff:g> је откривен"</string>
    -@@ -1257,8 +1268,9 @@
    -     <string name="vpn_text_long" msgid="4907843483284977618">"Повезано са сесијом <xliff:g id="SESSION">%s</xliff:g>. Додирните да бисте управљали мрежом."</string>
    -     <string name="vpn_lockdown_connecting" msgid="6443438964440960745">"Повезивање стално укљученог VPN-а..."</string>
    -     <string name="vpn_lockdown_connected" msgid="8202679674819213931">"Стално укључени VPN је повезан"</string>
    -+    <string name="vpn_lockdown_disconnected" msgid="4532298952570796327">"Веза са стално укљученим VPN-ом је прекинута"</string>
    -     <string name="vpn_lockdown_error" msgid="6009249814034708175">"Грешка стално укљученог VPN-а"</string>
    --    <string name="vpn_lockdown_config" msgid="4655589351146766608">"Додирните да бисте конфигурисали"</string>
    -+    <string name="vpn_lockdown_config" msgid="5099330695245008680">"Додирните да бисте подесили"</string>
    -     <string name="upload_file" msgid="2897957172366730416">"Одабери датотеку"</string>
    -     <string name="no_file_chosen" msgid="6363648562170759465">"Није изабрана ниједна датотека"</string>
    -     <string name="reset" msgid="2448168080964209908">"Поново постави"</string>
    -@@ -1343,7 +1355,7 @@
    -     <string name="storage_usb_drive_label" msgid="4501418548927759953">"<xliff:g id="MANUFACTURER">%s</xliff:g> USB диск"</string>
    -     <string name="storage_usb" msgid="3017954059538517278">"USB меморија"</string>
    -     <string name="extract_edit_menu_button" msgid="8940478730496610137">"Измени"</string>
    --    <string name="data_usage_warning_title" msgid="1955638862122232342">"Упозорење о потрошњи података"</string>
    -+    <string name="data_usage_warning_title" msgid="3620440638180218181">"Обавештење о потрошњи података"</string>
    -     <string name="data_usage_warning_body" msgid="6660692274311972007">"Додирните за потрошњу и подешавања."</string>
    -     <string name="data_usage_3g_limit_title" msgid="4361523876818447683">"Нема више 2G-3G података"</string>
    -     <string name="data_usage_4g_limit_title" msgid="4609566827219442376">"Нема више 4G података"</string>
    -@@ -1409,7 +1421,7 @@
    -     <string name="kg_wrong_pattern" msgid="1850806070801358830">"Погрешан шаблон"</string>
    -     <string name="kg_wrong_password" msgid="2333281762128113157">"Погрешна лозинка"</string>
    -     <string name="kg_wrong_pin" msgid="1131306510833563801">"Погрешан PIN"</string>
    --    <string name="kg_too_many_failed_attempts_countdown" msgid="6358110221603297548">"Покушајте поново за <xliff:g id="NUMBER">%1$d</xliff:g> секунде(и)."</string>
    -+    <string name="kg_too_many_failed_attempts_countdown" msgid="6358110221603297548">"Пробајте поново за <xliff:g id="NUMBER">%1$d</xliff:g> секунде(и)."</string>
    -     <string name="kg_pattern_instructions" msgid="398978611683075868">"Нацртајте шаблон"</string>
    -     <string name="kg_sim_pin_instructions" msgid="2319508550934557331">"Унесите PIN SIM картице"</string>
    -     <string name="kg_pin_instructions" msgid="2377242233495111557">"Унесите PIN"</string>
    -@@ -1431,18 +1443,18 @@
    -     <string name="kg_login_invalid_input" msgid="5754664119319872197">"Неважеће корисничко име или лозинка."</string>
    -     <string name="kg_login_account_recovery_hint" msgid="5690709132841752974">"Заборавили сте корисничко име или лозинку?\nПосетите адресу "<b>"google.com/accounts/recovery"</b>"."</string>
    -     <string name="kg_login_checking_password" msgid="1052685197710252395">"Провера налога…"</string>
    --    <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"Унели сте нетачни PIN <xliff:g id="NUMBER_0">%1$d</xliff:g> пута. \n\nПокушајте поново за <xliff:g id="NUMBER_1">%2$d</xliff:g> секунде(и)."</string>
    --    <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"Унели сте нетачну лозинку <xliff:g id="NUMBER_0">%1$d</xliff:g> пута. \n\nПокушајте поново за <xliff:g id="NUMBER_1">%2$d</xliff:g> секунде(и)."</string>
    --    <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"Нацртали сте шаблон за откључавање нетачно <xliff:g id="NUMBER_0">%1$d</xliff:g> пута. \n\nПокушајте поново за <xliff:g id="NUMBER_1">%2$d</xliff:g> секунде(и)."</string>
    -+    <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"Унели сте нетачни PIN <xliff:g id="NUMBER_0">%1$d</xliff:g> пута. \n\nПробајте поново за <xliff:g id="NUMBER_1">%2$d</xliff:g> секунде(и)."</string>
    -+    <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"Унели сте нетачну лозинку <xliff:g id="NUMBER_0">%1$d</xliff:g> пута. \n\nПробајте поново за <xliff:g id="NUMBER_1">%2$d</xliff:g> секунде(и)."</string>
    -+    <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"Нацртали сте шаблон за откључавање нетачно <xliff:g id="NUMBER_0">%1$d</xliff:g> пута. \n\nПробајте поново за <xliff:g id="NUMBER_1">%2$d</xliff:g> секунде(и)."</string>
    -     <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="1575557200627128949">"Покушали сте да откључате таблет нетачно <xliff:g id="NUMBER_0">%1$d</xliff:g> пута. Након још <xliff:g id="NUMBER_1">%2$d</xliff:g> неуспешна(их) покушаја таблет ће бити ресетован на фабричка подешавања и сви кориснички подаци ће бити изгубљени."</string>
    -     <string name="kg_failed_attempts_almost_at_wipe" product="tv" msgid="5621231220154419413">"Покушали сте да откључате ТВ нетачно <xliff:g id="NUMBER_0">%1$d</xliff:g> пута. После још <xliff:g id="NUMBER_1">%2$d</xliff:g> неуспешна(их) покушаја ТВ ће бити ресетован на подразумевана фабричка подешавања и сви кориснички подаци ће бити изгубљени."</string>
    -     <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4051015943038199910">"Покушали сте да откључате телефон нетачно <xliff:g id="NUMBER_0">%1$d</xliff:g> пута. После још <xliff:g id="NUMBER_1">%2$d</xliff:g> неуспешна(их) покушаја телефон ће бити ресетован на фабричка подешавања и сви кориснички подаци ће бити изгубљени."</string>
    -     <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="2072996269148483637">"Покушали сте да откључате таблет нетачно <xliff:g id="NUMBER">%d</xliff:g> пута. Таблет ће сада бити враћен на подразумевана фабричка подешавања."</string>
    -     <string name="kg_failed_attempts_now_wiping" product="tv" msgid="4987878286750741463">"Покушали сте да откључате ТВ нетачно <xliff:g id="NUMBER">%d</xliff:g> пута. ТВ ће сада бити ресетован на подразумевана фабричка подешавања."</string>
    -     <string name="kg_failed_attempts_now_wiping" product="default" msgid="4817627474419471518">"Покушали сте да откључате телефон нетачно <xliff:g id="NUMBER">%d</xliff:g> пута. Телефон ће сада бити враћен на подразумевана фабричка подешавања."</string>
    --    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"Нацртали сте шаблон за откључавање нетачно <xliff:g id="NUMBER_0">%1$d</xliff:g> пута. После још <xliff:g id="NUMBER_1">%2$d</xliff:g> неуспешна(их) покушаја, од вас ће бити затражено да откључате таблет помоћу налога е-поште.\n\nПокушајте поново за <xliff:g id="NUMBER_2">%3$d</xliff:g> секунде(и)."</string>
    --    <string name="kg_failed_attempts_almost_at_login" product="tv" msgid="4224651132862313471">"Неисправно сте нацртали шаблон за откључавање <xliff:g id="NUMBER_0">%1$d</xliff:g> пута. После још <xliff:g id="NUMBER_1">%2$d</xliff:g> неуспешна(их) покушаја, од вас ће бити затражено да откључате ТВ помоћу налога е-поште.\n\n Покушајте поново за <xliff:g id="NUMBER_2">%3$d</xliff:g> сек."</string>
    --    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Нацртали сте шаблон за откључавање нетачно <xliff:g id="NUMBER_0">%1$d</xliff:g> пута. После још <xliff:g id="NUMBER_1">%2$d</xliff:g> неуспешна(их) покушаја, од вас ће бити затражено да откључате телефон помоћу налога е-поште.\n\nПокушајте поново за <xliff:g id="NUMBER_2">%3$d</xliff:g> секунде(и)."</string>
    -+    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"Нацртали сте шаблон за откључавање нетачно <xliff:g id="NUMBER_0">%1$d</xliff:g> пута. После још <xliff:g id="NUMBER_1">%2$d</xliff:g> неуспешна(их) покушаја, од вас ће бити затражено да откључате таблет помоћу налога е-поште.\n\nПробајте поново за <xliff:g id="NUMBER_2">%3$d</xliff:g> секунде(и)."</string>
    -+    <string name="kg_failed_attempts_almost_at_login" product="tv" msgid="4224651132862313471">"Неисправно сте нацртали шаблон за откључавање <xliff:g id="NUMBER_0">%1$d</xliff:g> пута. После још <xliff:g id="NUMBER_1">%2$d</xliff:g> неуспешна(их) покушаја, од вас ће бити затражено да откључате ТВ помоћу налога е-поште.\n\n Пробајте поново за <xliff:g id="NUMBER_2">%3$d</xliff:g> сек."</string>
    -+    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Нацртали сте шаблон за откључавање нетачно <xliff:g id="NUMBER_0">%1$d</xliff:g> пута. После још <xliff:g id="NUMBER_1">%2$d</xliff:g> неуспешна(их) покушаја, од вас ће бити затражено да откључате телефон помоћу налога е-поште.\n\nПробајте поново за <xliff:g id="NUMBER_2">%3$d</xliff:g> секунде(и)."</string>
    -     <string name="kg_text_message_separator" product="default" msgid="4160700433287233771">" – "</string>
    -     <string name="kg_reordering_delete_drop_target_text" msgid="7899202978204438708">"Уклони"</string>
    -     <string name="safe_media_volume_warning" product="default" msgid="2276318909314492312">"Желите да појачате звук изнад препорученог нивоа?\n\nСлушање гласне музике дуже време може да вам оштети слух."</string>
    -@@ -1553,14 +1565,14 @@
    -     <string name="restr_pin_enter_new_pin" msgid="5959606691619959184">"Нови PIN"</string>
    -     <string name="restr_pin_confirm_pin" msgid="8501523829633146239">"Потврдите нови PIN"</string>
    -     <string name="restr_pin_create_pin" msgid="8017600000263450337">"Направите PIN за измену ограничења"</string>
    --    <string name="restr_pin_error_doesnt_match" msgid="2224214190906994548">"PIN-ови се не подударају. Покушајте поново."</string>
    -+    <string name="restr_pin_error_doesnt_match" msgid="2224214190906994548">"PIN-ови се не подударају. Пробајте поново."</string>
    -     <string name="restr_pin_error_too_short" msgid="8173982756265777792">"PIN је прекратак. Мора да садржи најмање 4 цифре."</string>
    -     <plurals name="restr_pin_countdown" formatted="false" msgid="9061246974881224688">
    --      <item quantity="one">Покушајте поново за <xliff:g id="COUNT">%d</xliff:g> секунду</item>
    --      <item quantity="few">Покушајте поново за <xliff:g id="COUNT">%d</xliff:g> секунде</item>
    --      <item quantity="other">Покушајте поново за <xliff:g id="COUNT">%d</xliff:g> секунди</item>
    -+      <item quantity="one">Пробајте поново за <xliff:g id="COUNT">%d</xliff:g> секунду</item>
    -+      <item quantity="few">Пробајте поново за <xliff:g id="COUNT">%d</xliff:g> секунде</item>
    -+      <item quantity="other">Пробајте поново за <xliff:g id="COUNT">%d</xliff:g> секунди</item>
    -     </plurals>
    --    <string name="restr_pin_try_later" msgid="973144472490532377">"Покушајте поново касније"</string>
    -+    <string name="restr_pin_try_later" msgid="973144472490532377">"Пробајте поново касније"</string>
    -     <string name="immersive_cling_title" msgid="8394201622932303336">"Приказује се цео екран"</string>
    -     <string name="immersive_cling_description" msgid="3482371193207536040">"Да бисте изашли, превуците надоле одозго."</string>
    -     <string name="immersive_cling_positive" msgid="5016839404568297683">"Важи"</string>
    -@@ -1672,6 +1684,7 @@
    -     <string name="search_language_hint" msgid="7042102592055108574">"Унесите назив језика"</string>
    -     <string name="language_picker_section_suggested" msgid="8414489646861640885">"Предложени"</string>
    -     <string name="language_picker_section_all" msgid="3097279199511617537">"Сви језици"</string>
    -+    <string name="region_picker_section_all" msgid="8966316787153001779">"Сви региони"</string>
    -     <string name="locale_search_menu" msgid="2560710726687249178">"Претражи"</string>
    -     <string name="work_mode_off_title" msgid="8954725060677558855">"Режим за Work је ИСКЉУЧЕН"</string>
    -     <string name="work_mode_off_message" msgid="3286169091278094476">"Дозвољава профилу за Work да функционише, укључујући апликације, синхронизацију у позадини и сродне функције."</string>
    -diff --git a/core/res/res/values-sv/strings.xml b/core/res/res/values-sv/strings.xml
    -index cf1b19c..d43282d 100644
    ---- a/core/res/res/values-sv/strings.xml
    -+++ b/core/res/res/values-sv/strings.xml
    -@@ -214,6 +214,7 @@
    -     <string name="global_actions" product="default" msgid="2406416831541615258">"Telefonalternativ"</string>
    -     <string name="global_action_lock" msgid="2844945191792119712">"Skärmlås"</string>
    -     <string name="global_action_power_off" msgid="4471879440839879722">"Stäng av"</string>
    -+    <string name="global_action_emergency" msgid="7112311161137421166">"Nödsituation"</string>
    -     <string name="global_action_bug_report" msgid="7934010578922304799">"Felrapport"</string>
    -     <string name="bugreport_title" msgid="2667494803742548533">"Skapa felrapport"</string>
    -     <string name="bugreport_message" msgid="398447048750350456">"Nu hämtas information om aktuell status för enheten, som sedan skickas i ett e-postmeddelade. Det tar en liten stund innan felrapporten är färdig och kan skickas, så vi ber dig ha tålamod."</string>
    -@@ -671,7 +672,7 @@
    -     <string name="lockscreen_carrier_default" msgid="6169005837238288522">"Ingen tjänst"</string>
    -     <string name="lockscreen_screen_locked" msgid="7288443074806832904">"Skärmen har låsts."</string>
    -     <string name="lockscreen_instructions_when_pattern_enabled" msgid="46154051614126049">"Tryck på Menu om du vill låsa upp eller ringa nödsamtal."</string>
    --    <string name="lockscreen_instructions_when_pattern_disabled" msgid="686260028797158364">"Tryck på Menu om du vill låsa upp."</string>
    -+    <string name="lockscreen_instructions_when_pattern_disabled" msgid="686260028797158364">"Tryck på Menu för att låsa upp."</string>
    -     <string name="lockscreen_pattern_instructions" msgid="7478703254964810302">"Rita grafiskt lösenord för att låsa upp"</string>
    -     <string name="lockscreen_emergency_call" msgid="5298642613417801888">"Nödsamtal"</string>
    -     <string name="lockscreen_return_to_call" msgid="5244259785500040021">"Tillbaka till samtal"</string>
    -@@ -1076,6 +1077,17 @@
    -     <skip />
    -     <string name="wifi_no_internet" msgid="8451173622563841546">"Wi-Fi-nätverket är inte anslutet till internet"</string>
    -     <string name="wifi_no_internet_detailed" msgid="8083079241212301741">"Tryck för alternativ"</string>
    -+    <string name="network_switch_metered" msgid="4671730921726992671">"Byte av nätverk till <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
    -+    <string name="network_switch_metered_detail" msgid="5325661434777870353">"<xliff:g id="NEW_NETWORK">%1$s</xliff:g> används på enheten när det inte finns internetåtkomst via <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g>. Avgifter kan tillkomma."</string>
    -+    <string name="network_switch_metered_toast" msgid="5779283181685974304">"Byte av nätverk från <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> till <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
    -+  <string-array name="network_switch_type_name">
    -+    <item msgid="2952042958050315394">"mobildata"</item>
    -+    <item msgid="75483255295529161">"Wi-Fi"</item>
    -+    <item msgid="6862614801537202646">"Bluetooth"</item>
    -+    <item msgid="5447331121797802871">"Ethernet"</item>
    -+    <item msgid="8257233890381651999">"VPN"</item>
    -+  </string-array>
    -+    <string name="network_switch_type_name_unknown" msgid="4552612897806660656">"en okänd nätverkstyp"</string>
    -     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Det gick inte att ansluta till Wi-Fi"</string>
    -     <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" har en dålig Internetanslutning."</string>
    -     <string name="wifi_connect_alert_title" msgid="8455846016001810172">"Tillåt anslutning?"</string>
    -@@ -1153,7 +1165,6 @@
    -     <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"Tryck om du vill välja språk och layout"</string>
    -     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
    -     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
    --    <string name="candidates_style" msgid="4333913089637062257"><u>"kandidater"</u></string>
    -     <string name="ext_media_checking_notification_title" msgid="5734005953288045806">"Förbereder ditt <xliff:g id="NAME">%s</xliff:g>"</string>
    -     <string name="ext_media_checking_notification_message" msgid="4747432538578886744">"Söker efter fel"</string>
    -     <string name="ext_media_new_notification_message" msgid="7589986898808506239">"Nytt <xliff:g id="NAME">%s</xliff:g> har hittats"</string>
    -@@ -1232,8 +1243,9 @@
    -     <string name="vpn_text_long" msgid="4907843483284977618">"Ansluten till <xliff:g id="SESSION">%s</xliff:g>. Knacka lätt för att hantera nätverket."</string>
    -     <string name="vpn_lockdown_connecting" msgid="6443438964440960745">"Ansluter till Always-on VPN ..."</string>
    -     <string name="vpn_lockdown_connected" msgid="8202679674819213931">"Ansluten till Always-on VPN"</string>
    -+    <string name="vpn_lockdown_disconnected" msgid="4532298952570796327">"Always-on VPN har kopplats från"</string>
    -     <string name="vpn_lockdown_error" msgid="6009249814034708175">"Fel på Always-on VPN"</string>
    --    <string name="vpn_lockdown_config" msgid="4655589351146766608">"Tryck om du vill konfigurera"</string>
    -+    <string name="vpn_lockdown_config" msgid="5099330695245008680">"Tryck för att konfigurera"</string>
    -     <string name="upload_file" msgid="2897957172366730416">"Välj fil"</string>
    -     <string name="no_file_chosen" msgid="6363648562170759465">"Ingen fil har valts"</string>
    -     <string name="reset" msgid="2448168080964209908">"Återställ"</string>
    -@@ -1317,7 +1329,7 @@
    -     <string name="storage_usb_drive_label" msgid="4501418548927759953">"USB-enhet (<xliff:g id="MANUFACTURER">%s</xliff:g>)"</string>
    -     <string name="storage_usb" msgid="3017954059538517278">"USB-lagring"</string>
    -     <string name="extract_edit_menu_button" msgid="8940478730496610137">"Redigera"</string>
    --    <string name="data_usage_warning_title" msgid="1955638862122232342">"Varning angående dataanvändning"</string>
    -+    <string name="data_usage_warning_title" msgid="3620440638180218181">"Varning – dataanvändning"</string>
    -     <string name="data_usage_warning_body" msgid="6660692274311972007">"Visa användning och inställning."</string>
    -     <string name="data_usage_3g_limit_title" msgid="4361523876818447683">"Datagränsen för 2G-3G har uppnåtts"</string>
    -     <string name="data_usage_4g_limit_title" msgid="4609566827219442376">"Datagränsen för 4G har uppnåtts"</string>
    -@@ -1636,6 +1648,7 @@
    -     <string name="search_language_hint" msgid="7042102592055108574">"Ange språket"</string>
    -     <string name="language_picker_section_suggested" msgid="8414489646861640885">"Förslag"</string>
    -     <string name="language_picker_section_all" msgid="3097279199511617537">"Alla språk"</string>
    -+    <string name="region_picker_section_all" msgid="8966316787153001779">"Alla regioner"</string>
    -     <string name="locale_search_menu" msgid="2560710726687249178">"Söka"</string>
    -     <string name="work_mode_off_title" msgid="8954725060677558855">"Arbetsläget är inaktiverat"</string>
    -     <string name="work_mode_off_message" msgid="3286169091278094476">"Tillåt att jobbprofilen är aktiv, inklusive appar, bakgrundssynkronisering och andra tillhörande funktioner."</string>
    -@@ -1643,7 +1656,7 @@
    -     <string name="new_sms_notification_title" msgid="8442817549127555977">"Du har nya meddelanden"</string>
    -     <string name="new_sms_notification_content" msgid="7002938807812083463">"Öppna sms-appen och visa meddelandet"</string>
    -     <string name="user_encrypted_title" msgid="9054897468831672082">"Vissa funktioner är begränsade"</string>
    --    <string name="user_encrypted_message" msgid="4923292604515744267">"Tryck om du vill låsa upp"</string>
    -+    <string name="user_encrypted_message" msgid="4923292604515744267">"Tryck för att låsa upp"</string>
    -     <string name="user_encrypted_detail" msgid="5708447464349420392">"Användaruppgifterna är låsta"</string>
    -     <string name="profile_encrypted_detail" msgid="3700965619978314974">"Jobbprofilen är låst"</string>
    -     <string name="profile_encrypted_message" msgid="6964994232310195874">"Tryck och lås upp jobbprofilen"</string>
    -diff --git a/core/res/res/values-sw/strings.xml b/core/res/res/values-sw/strings.xml
    -index 3daaf93..cc750d6 100644
    ---- a/core/res/res/values-sw/strings.xml
    -+++ b/core/res/res/values-sw/strings.xml
    -@@ -212,6 +212,7 @@
    -     <string name="global_actions" product="default" msgid="2406416831541615258">"Chaguo za simu"</string>
    -     <string name="global_action_lock" msgid="2844945191792119712">"Funga skrini"</string>
    -     <string name="global_action_power_off" msgid="4471879440839879722">"Zima"</string>
    -+    <string name="global_action_emergency" msgid="7112311161137421166">"Dharura"</string>
    -     <string name="global_action_bug_report" msgid="7934010578922304799">"Ripoti ya hitilafu"</string>
    -     <string name="bugreport_title" msgid="2667494803742548533">"Chukua ripoti ya hitilafu"</string>
    -     <string name="bugreport_message" msgid="398447048750350456">"Hii itakusanya maelezo kuhusu hali ya kifaa chako kwa sasa, na itume kama barua pepe. Itachukua muda mfupi tangu ripoti ya hitilafu ianze kuzalishwa hadi iwe tayari kutumwa; vumilia."</string>
    -@@ -1074,6 +1075,17 @@
    -     <skip />
    -     <string name="wifi_no_internet" msgid="8451173622563841546">"Wi-Fi haina muunganisho wa intaneti"</string>
    -     <string name="wifi_no_internet_detailed" msgid="8083079241212301741">"Gonga ili upate chaguo"</string>
    -+    <string name="network_switch_metered" msgid="4671730921726992671">"Sasa inatumia <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
    -+    <string name="network_switch_metered_detail" msgid="5325661434777870353">"Kifaa hutumia <xliff:g id="NEW_NETWORK">%1$s</xliff:g> wakati <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> haina Intaneti. Huenda ukalipishwa."</string>
    -+    <string name="network_switch_metered_toast" msgid="5779283181685974304">"Imebadilisha mtandao kutoka <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> na sasa inatumia <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
    -+  <string-array name="network_switch_type_name">
    -+    <item msgid="2952042958050315394">"data ya simu za mkononi"</item>
    -+    <item msgid="75483255295529161">"Wi-Fi"</item>
    -+    <item msgid="6862614801537202646">"Bluetooth"</item>
    -+    <item msgid="5447331121797802871">"Ethaneti"</item>
    -+    <item msgid="8257233890381651999">"VPN"</item>
    -+  </string-array>
    -+    <string name="network_switch_type_name_unknown" msgid="4552612897806660656">"aina ya mtandao isiyojulikana"</string>
    -     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Haikuweza kuunganisha kwa Mtandao-Hewa"</string>
    -     <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" ina muunganisho duni wa Mtandao."</string>
    -     <string name="wifi_connect_alert_title" msgid="8455846016001810172">"Ungepenga kuruhusu muunganisho?"</string>
    -@@ -1151,7 +1163,6 @@
    -     <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"Gonga ili uchague lugha na muundo"</string>
    -     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
    -     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
    --    <string name="candidates_style" msgid="4333913089637062257"><u>"wagombeaji"</u></string>
    -     <string name="ext_media_checking_notification_title" msgid="5734005953288045806">"Inaandaa <xliff:g id="NAME">%s</xliff:g>"</string>
    -     <string name="ext_media_checking_notification_message" msgid="4747432538578886744">"Inakagua hitilafu"</string>
    -     <string name="ext_media_new_notification_message" msgid="7589986898808506239">"<xliff:g id="NAME">%s</xliff:g> mpya imegunduliwa"</string>
    -@@ -1230,8 +1241,9 @@
    -     <string name="vpn_text_long" msgid="4907843483284977618">"Imeunganishwa kwa <xliff:g id="SESSION">%s</xliff:g>. Gonga ili kudhibiti mtandao"</string>
    -     <string name="vpn_lockdown_connecting" msgid="6443438964440960745">"Kila mara VPN iliyowashwa inaunganishwa…"</string>
    -     <string name="vpn_lockdown_connected" msgid="8202679674819213931">"Kila mara VPN iliyowashwa imeunganishwa"</string>
    -+    <string name="vpn_lockdown_disconnected" msgid="4532298952570796327">"Iwe imeondoa VPN kila wakati"</string>
    -     <string name="vpn_lockdown_error" msgid="6009249814034708175">"Kila mara kuna hitilafu ya VPN iliyowashwa"</string>
    --    <string name="vpn_lockdown_config" msgid="4655589351146766608">"Gonga ili uweke mipangilio"</string>
    -+    <string name="vpn_lockdown_config" msgid="5099330695245008680">"Gonga ili uweke mipangilio"</string>
    -     <string name="upload_file" msgid="2897957172366730416">"Chagua faili"</string>
    -     <string name="no_file_chosen" msgid="6363648562170759465">"Hakuna faili iliyochaguliwa"</string>
    -     <string name="reset" msgid="2448168080964209908">"Weka upya"</string>
    -@@ -1315,7 +1327,7 @@
    -     <string name="storage_usb_drive_label" msgid="4501418548927759953">"Hifadhi ya USB iliyotengenezwa na <xliff:g id="MANUFACTURER">%s</xliff:g>"</string>
    -     <string name="storage_usb" msgid="3017954059538517278">"Hifadhi ya USB"</string>
    -     <string name="extract_edit_menu_button" msgid="8940478730496610137">"Badilisha"</string>
    --    <string name="data_usage_warning_title" msgid="1955638862122232342">"Onyo la matumizi ya data"</string>
    -+    <string name="data_usage_warning_title" msgid="3620440638180218181">"Tahadhari ya matumizi ya data"</string>
    -     <string name="data_usage_warning_body" msgid="6660692274311972007">"Gonga ili uangalie matumizi na mipangilio."</string>
    -     <string name="data_usage_3g_limit_title" msgid="4361523876818447683">"Kikomo data ya 2G-3G kimefikiwa"</string>
    -     <string name="data_usage_4g_limit_title" msgid="4609566827219442376">"Kikomo cha data ya 4G kimefikiwa"</string>
    -@@ -1634,6 +1646,7 @@
    -     <string name="search_language_hint" msgid="7042102592055108574">"Weka jina la lugha"</string>
    -     <string name="language_picker_section_suggested" msgid="8414489646861640885">"Inayopendekezwa"</string>
    -     <string name="language_picker_section_all" msgid="3097279199511617537">"Lugha zote"</string>
    -+    <string name="region_picker_section_all" msgid="8966316787153001779">"Maeneo yote"</string>
    -     <string name="locale_search_menu" msgid="2560710726687249178">"Tafuta"</string>
    -     <string name="work_mode_off_title" msgid="8954725060677558855">"Hali ya kazi IMEZIMWA"</string>
    -     <string name="work_mode_off_message" msgid="3286169091278094476">"Ruhusu wasifu wa kazini utumike, ikiwa ni pamoja na programu, usawazishaji wa chini chini na vipengele vinavyohusiana."</string>
    -diff --git a/core/res/res/values-ta-rIN/strings.xml b/core/res/res/values-ta-rIN/strings.xml
    -index e851399..20226e9 100644
    ---- a/core/res/res/values-ta-rIN/strings.xml
    -+++ b/core/res/res/values-ta-rIN/strings.xml
    -@@ -214,6 +214,7 @@
    -     <string name="global_actions" product="default" msgid="2406416831541615258">"தொலைபேசி விருப்பங்கள்"</string>
    -     <string name="global_action_lock" msgid="2844945191792119712">"திரைப் பூட்டு"</string>
    -     <string name="global_action_power_off" msgid="4471879440839879722">"முடக்கு"</string>
    -+    <string name="global_action_emergency" msgid="7112311161137421166">"அவசர அழைப்பு"</string>
    -     <string name="global_action_bug_report" msgid="7934010578922304799">"பிழை அறிக்கை"</string>
    -     <string name="bugreport_title" msgid="2667494803742548533">"பிழை அறிக்கையை எடு"</string>
    -     <string name="bugreport_message" msgid="398447048750350456">"உங்கள் நடப்புச் சாதன நிலையை மின்னஞ்சல் செய்தியாக அனுப்ப, அது குறித்த தகவலை இது சேகரிக்கும். பிழை அறிக்கையைத் தொடங்குவதில் இருந்து, அது அனுப்புவதற்குத் தயாராகும் வரை, இதற்குச் சிறிது நேரம் ஆகும்; பொறுமையாகக் காத்திருக்கவும்."</string>
    -@@ -1076,6 +1077,17 @@
    -     <skip />
    -     <string name="wifi_no_internet" msgid="8451173622563841546">"வைஃபை இணைய அணுகல் கொண்டிருக்கவில்லை"</string>
    -     <string name="wifi_no_internet_detailed" msgid="8083079241212301741">"விருப்பங்களுக்கு, தட்டவும்"</string>
    -+    <string name="network_switch_metered" msgid="4671730921726992671">"<xliff:g id="NETWORK_TYPE">%1$s</xliff:g>க்கு மாற்றப்பட்டது"</string>
    -+    <string name="network_switch_metered_detail" msgid="5325661434777870353">"<xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> இல் இணைய அணுகல் இல்லாததால், சாதனமானது <xliff:g id="NEW_NETWORK">%1$s</xliff:g>ஐப் பயன்படுத்துகிறது. கட்டணங்கள் விதிக்கப்படலாம்."</string>
    -+    <string name="network_switch_metered_toast" msgid="5779283181685974304">"<xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> இலிருந்து <xliff:g id="NEW_NETWORK">%2$s</xliff:g>க்கு மாற்றப்பட்டது"</string>
    -+  <string-array name="network_switch_type_name">
    -+    <item msgid="2952042958050315394">"செல்லுலார் தரவு"</item>
    -+    <item msgid="75483255295529161">"வைஃபை"</item>
    -+    <item msgid="6862614801537202646">"புளூடூத்"</item>
    -+    <item msgid="5447331121797802871">"ஈத்தர்நெட்"</item>
    -+    <item msgid="8257233890381651999">"VPN"</item>
    -+  </string-array>
    -+    <string name="network_switch_type_name_unknown" msgid="4552612897806660656">"தெரியாத நெட்வொர்க் வகை"</string>
    -     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"வைஃபை உடன் இணைக்க முடியவில்லை"</string>
    -     <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" இணைய இணைப்பு மோசமாக உள்ளது."</string>
    -     <string name="wifi_connect_alert_title" msgid="8455846016001810172">"இணைப்பை அனுமதிக்கவா?"</string>
    -@@ -1153,7 +1165,6 @@
    -     <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"மொழியையும் தளவமைப்பையும் தேர்ந்தெடுக்க, தட்டவும்"</string>
    -     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
    -     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
    --    <string name="candidates_style" msgid="4333913089637062257"><u>"கேன்டிடேட்ஸ்"</u></string>
    -     <string name="ext_media_checking_notification_title" msgid="5734005953288045806">"<xliff:g id="NAME">%s</xliff:g> தயாராகிறது"</string>
    -     <string name="ext_media_checking_notification_message" msgid="4747432538578886744">"பிழைகள் உள்ளதா எனப் பார்க்கிறது"</string>
    -     <string name="ext_media_new_notification_message" msgid="7589986898808506239">"புதிய <xliff:g id="NAME">%s</xliff:g> கண்டறியப்பட்டது"</string>
    -@@ -1232,8 +1243,9 @@
    -     <string name="vpn_text_long" msgid="4907843483284977618">"<xliff:g id="SESSION">%s</xliff:g> உடன் இணைக்கப்பட்டது. நெட்வொர்க்கை நிர்வகிக்க, தட்டவும்."</string>
    -     <string name="vpn_lockdown_connecting" msgid="6443438964440960745">"எப்போதும் இயங்கும் VPN உடன் இணைக்கிறது…"</string>
    -     <string name="vpn_lockdown_connected" msgid="8202679674819213931">"எப்போதும் இயங்கும் VPN இணைக்கப்பட்டது"</string>
    -+    <string name="vpn_lockdown_disconnected" msgid="4532298952570796327">"எப்போதும் இயங்கும் VPN துண்டிக்கப்பட்டது"</string>
    -     <string name="vpn_lockdown_error" msgid="6009249814034708175">"எப்போதும் இயங்கும் VPN பிழை"</string>
    --    <string name="vpn_lockdown_config" msgid="4655589351146766608">"உள்ளமைக்க, தட்டவும்"</string>
    -+    <string name="vpn_lockdown_config" msgid="5099330695245008680">"அமைக்க, தட்டவும்"</string>
    -     <string name="upload_file" msgid="2897957172366730416">"கோப்பைத் தேர்வுசெய்"</string>
    -     <string name="no_file_chosen" msgid="6363648562170759465">"எந்தக் கோப்பும் தேர்வுசெய்யப்படவில்லை"</string>
    -     <string name="reset" msgid="2448168080964209908">"மீட்டமை"</string>
    -@@ -1317,7 +1329,7 @@
    -     <string name="storage_usb_drive_label" msgid="4501418548927759953">"<xliff:g id="MANUFACTURER">%s</xliff:g> USB டிரைவ்"</string>
    -     <string name="storage_usb" msgid="3017954059538517278">"USB சேமிப்பிடம்"</string>
    -     <string name="extract_edit_menu_button" msgid="8940478730496610137">"திருத்து"</string>
    --    <string name="data_usage_warning_title" msgid="1955638862122232342">"தரவு பயன்பாட்டு எச்சரிக்கை"</string>
    -+    <string name="data_usage_warning_title" msgid="3620440638180218181">"தரவுப் பயன்பாடு குறித்த எச்சரிக்கை"</string>
    -     <string name="data_usage_warning_body" msgid="6660692274311972007">"தரவு உபயோகம், அமைப்புகளைப் பார்க்க, தட்டவும்."</string>
    -     <string name="data_usage_3g_limit_title" msgid="4361523876818447683">"2G-3G தரவு வரம்பைக் கடந்தது"</string>
    -     <string name="data_usage_4g_limit_title" msgid="4609566827219442376">"4G தரவு வரம்பைக் கடந்தது"</string>
    -@@ -1636,6 +1648,7 @@
    -     <string name="search_language_hint" msgid="7042102592055108574">"மொழி பெயரை உள்ளிடுக"</string>
    -     <string name="language_picker_section_suggested" msgid="8414489646861640885">"பரிந்துரைகள்"</string>
    -     <string name="language_picker_section_all" msgid="3097279199511617537">"எல்லா மொழிகளும்"</string>
    -+    <string name="region_picker_section_all" msgid="8966316787153001779">"எல்லா மண்டலங்களும்"</string>
    -     <string name="locale_search_menu" msgid="2560710726687249178">"தேடு"</string>
    -     <string name="work_mode_off_title" msgid="8954725060677558855">"பணிப் பயன்முறை முடக்கப்பட்டது"</string>
    -     <string name="work_mode_off_message" msgid="3286169091278094476">"செயல்பட, பணி சுயவிவரத்தை அனுமதி. இதில் பயன்பாடுகள், பின்னணி ஒத்திசைவு மற்றும் தொடர்புடைய அம்சங்கள் அடங்கும்."</string>
    -diff --git a/core/res/res/values-te-rIN/strings.xml b/core/res/res/values-te-rIN/strings.xml
    -index 7c48c8c..072b69b 100644
    ---- a/core/res/res/values-te-rIN/strings.xml
    -+++ b/core/res/res/values-te-rIN/strings.xml
    -@@ -214,6 +214,7 @@
    -     <string name="global_actions" product="default" msgid="2406416831541615258">"ఫోన్ ఎంపికలు"</string>
    -     <string name="global_action_lock" msgid="2844945191792119712">"స్క్రీన్ లాక్"</string>
    -     <string name="global_action_power_off" msgid="4471879440839879722">"పవర్ ఆఫ్ చేయి"</string>
    -+    <string name="global_action_emergency" msgid="7112311161137421166">"అత్యవసరం"</string>
    -     <string name="global_action_bug_report" msgid="7934010578922304799">"బగ్ నివేదిక"</string>
    -     <string name="bugreport_title" msgid="2667494803742548533">"బగ్ నివేదికను సిద్ధం చేయి"</string>
    -     <string name="bugreport_message" msgid="398447048750350456">"ఇది ఇ-మెయిల్ సందేశం రూపంలో పంపడానికి మీ ప్రస్తుత పరికర స్థితి గురించి సమాచారాన్ని సేకరిస్తుంది. బగ్ నివేదికను ప్రారంభించడం మొదలుకొని పంపడానికి సిద్ధం చేసే వరకు ఇందుకు కొంత సమయం పడుతుంది; దయచేసి ఓపిక పట్టండి."</string>
    -@@ -1076,6 +1077,17 @@
    -     <skip />
    -     <string name="wifi_no_internet" msgid="8451173622563841546">"Wi-Fiకి ఇంటర్నెట్ ప్రాప్యత లేదు"</string>
    -     <string name="wifi_no_internet_detailed" msgid="8083079241212301741">"ఎంపికల కోసం నొక్కండి"</string>
    -+    <string name="network_switch_metered" msgid="4671730921726992671">"<xliff:g id="NETWORK_TYPE">%1$s</xliff:g>కి మార్చబడింది"</string>
    -+    <string name="network_switch_metered_detail" msgid="5325661434777870353">"పరికరం <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g>కి ఇంటర్నెట్ ప్రాప్యత లేనప్పుడు <xliff:g id="NEW_NETWORK">%1$s</xliff:g>ని ఉపయోగిస్తుంది. ఛార్జీలు వర్తించవచ్చు."</string>
    -+    <string name="network_switch_metered_toast" msgid="5779283181685974304">"<xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> నుండి <xliff:g id="NEW_NETWORK">%2$s</xliff:g>కి మార్చబడింది"</string>
    -+  <string-array name="network_switch_type_name">
    -+    <item msgid="2952042958050315394">"సెల్యులార్ డేటా"</item>
    -+    <item msgid="75483255295529161">"Wi-Fi"</item>
    -+    <item msgid="6862614801537202646">"బ్లూటూత్"</item>
    -+    <item msgid="5447331121797802871">"ఈథర్‌నెట్"</item>
    -+    <item msgid="8257233890381651999">"VPN"</item>
    -+  </string-array>
    -+    <string name="network_switch_type_name_unknown" msgid="4552612897806660656">"తెలియని నెట్‌వర్క్ రకం"</string>
    -     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Wi-Fiకి కనెక్ట్ చేయడం సాధ్యపడలేదు"</string>
    -     <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" బలహీన ఇంటర్నెట్ కనెక్షన్‌ను కలిగి ఉంది."</string>
    -     <string name="wifi_connect_alert_title" msgid="8455846016001810172">"కనెక్షన్‌ని అనుమతించాలా?"</string>
    -@@ -1153,7 +1165,6 @@
    -     <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"భాష మరియు లేఅవుట్‌ను ఎంచుకోవడానికి నొక్కండి"</string>
    -     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
    -     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
    --    <string name="candidates_style" msgid="4333913089637062257"><u>"క్యాండిడేట్‌లు"</u></string>
    -     <string name="ext_media_checking_notification_title" msgid="5734005953288045806">"<xliff:g id="NAME">%s</xliff:g>ని సిద్ధం చేస్తోంది"</string>
    -     <string name="ext_media_checking_notification_message" msgid="4747432538578886744">"లోపాల కోసం తనిఖీ చేస్తోంది"</string>
    -     <string name="ext_media_new_notification_message" msgid="7589986898808506239">"కొత్త <xliff:g id="NAME">%s</xliff:g> గుర్తించబడింది"</string>
    -@@ -1232,8 +1243,9 @@
    -     <string name="vpn_text_long" msgid="4907843483284977618">"<xliff:g id="SESSION">%s</xliff:g>కు కనెక్ట్ చేయబడింది. నెట్‌వర్క్‌ను నిర్వహించడానికి నొక్కండి."</string>
    -     <string name="vpn_lockdown_connecting" msgid="6443438964440960745">"ఎల్లప్పుడూ-ఆన్‌లో ఉండే VPN కనెక్ట్ చేయబడుతోంది…"</string>
    -     <string name="vpn_lockdown_connected" msgid="8202679674819213931">"ఎల్లప్పుడూ-ఆన్‌లో ఉండే VPN కనెక్ట్ చేయబడింది"</string>
    -+    <string name="vpn_lockdown_disconnected" msgid="4532298952570796327">"ఎల్లప్పుడూ ఆన్‌లో ఉండే VPN డిస్‌కనెక్ట్ చేయబడింది"</string>
    -     <string name="vpn_lockdown_error" msgid="6009249814034708175">"ఎల్లప్పుడూ-ఆన్‌లో ఉండే VPN లోపం"</string>
    --    <string name="vpn_lockdown_config" msgid="4655589351146766608">"కాన్ఫిగర్ చేయడానికి నొక్కండి"</string>
    -+    <string name="vpn_lockdown_config" msgid="5099330695245008680">"సెటప్ చేయడానికి నొక్కండి"</string>
    -     <string name="upload_file" msgid="2897957172366730416">"ఫైల్‌ను ఎంచుకోండి"</string>
    -     <string name="no_file_chosen" msgid="6363648562170759465">"ఫైల్ ఎంచుకోబడలేదు"</string>
    -     <string name="reset" msgid="2448168080964209908">"రీసెట్ చేయి"</string>
    -@@ -1317,7 +1329,7 @@
    -     <string name="storage_usb_drive_label" msgid="4501418548927759953">"<xliff:g id="MANUFACTURER">%s</xliff:g> USB డ్రైవ్"</string>
    -     <string name="storage_usb" msgid="3017954059538517278">"USB నిల్వ"</string>
    -     <string name="extract_edit_menu_button" msgid="8940478730496610137">"సవరించు"</string>
    --    <string name="data_usage_warning_title" msgid="1955638862122232342">"డేటా వినియోగం హెచ్చరిక"</string>
    -+    <string name="data_usage_warning_title" msgid="3620440638180218181">"డేటా వినియోగ హెచ్చరిక"</string>
    -     <string name="data_usage_warning_body" msgid="6660692274311972007">"వినియోగం,సెట్టింగ్‌ల కోసం నొక్కండి"</string>
    -     <string name="data_usage_3g_limit_title" msgid="4361523876818447683">"2G-3G డేటా పరిమితిని చేరుకుంది"</string>
    -     <string name="data_usage_4g_limit_title" msgid="4609566827219442376">"4G డేటా పరిమితిని చేరుకుంది"</string>
    -@@ -1636,6 +1648,7 @@
    -     <string name="search_language_hint" msgid="7042102592055108574">"భాష పేరును టైప్ చేయండి"</string>
    -     <string name="language_picker_section_suggested" msgid="8414489646861640885">"సూచించినవి"</string>
    -     <string name="language_picker_section_all" msgid="3097279199511617537">"అన్ని భాషలు"</string>
    -+    <string name="region_picker_section_all" msgid="8966316787153001779">"అన్ని ప్రాంతాలు"</string>
    -     <string name="locale_search_menu" msgid="2560710726687249178">"శోధించు"</string>
    -     <string name="work_mode_off_title" msgid="8954725060677558855">"కార్యాలయ మోడ్ ఆఫ్ చేయబడింది"</string>
    -     <string name="work_mode_off_message" msgid="3286169091278094476">"అనువర్తనాలు, నేపథ్య సమకాలీకరణ మరియు సంబంధిత లక్షణాలతో సహా కార్యాలయ ప్రొఫైల్‌ను పని చేయడానికి అనుమతించండి."</string>
    -diff --git a/core/res/res/values-th/strings.xml b/core/res/res/values-th/strings.xml
    -index 90d9f9b..c251590 100644
    ---- a/core/res/res/values-th/strings.xml
    -+++ b/core/res/res/values-th/strings.xml
    -@@ -214,6 +214,7 @@
    -     <string name="global_actions" product="default" msgid="2406416831541615258">"ตัวเลือกโทรศัพท์"</string>
    -     <string name="global_action_lock" msgid="2844945191792119712">"ล็อกหน้าจอ"</string>
    -     <string name="global_action_power_off" msgid="4471879440839879722">"ปิดเครื่อง"</string>
    -+    <string name="global_action_emergency" msgid="7112311161137421166">"เหตุฉุกเฉิน"</string>
    -     <string name="global_action_bug_report" msgid="7934010578922304799">"รายงานข้อบกพร่อง"</string>
    -     <string name="bugreport_title" msgid="2667494803742548533">"ใช้รายงานข้อบกพร่อง"</string>
    -     <string name="bugreport_message" msgid="398447048750350456">"การดำเนินการนี้จะรวบรวมข้อมูลเกี่ยวกับสถานะปัจจุบันของอุปกรณ์ของคุณ โดยจะส่งไปในรูปแบบข้อความอีเมล อาจใช้เวลาสักครู่ตั้งแต่เริ่มการสร้างรายงานข้อบกพร่องจนกระทั่งเสร็จสมบูรณ์ โปรดอดทนรอ"</string>
    -@@ -1076,6 +1077,17 @@
    -     <skip />
    -     <string name="wifi_no_internet" msgid="8451173622563841546">"Wi-Fi ไม่สามารถเข้าถึงอินเทอร์เน็ต"</string>
    -     <string name="wifi_no_internet_detailed" msgid="8083079241212301741">"แตะเพื่อดูตัวเลือก"</string>
    -+    <string name="network_switch_metered" msgid="4671730921726992671">"เปลี่ยนเป็น <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
    -+    <string name="network_switch_metered_detail" msgid="5325661434777870353">"อุปกรณ์จะใช้ <xliff:g id="NEW_NETWORK">%1$s</xliff:g> เมื่อ <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> ไม่สามารถเข้าถึงอินเทอร์เน็ต อาจมีค่าบริการ"</string>
    -+    <string name="network_switch_metered_toast" msgid="5779283181685974304">"เปลี่ยนจาก <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> เป็น <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
    -+  <string-array name="network_switch_type_name">
    -+    <item msgid="2952042958050315394">"เน็ตมือถือ"</item>
    -+    <item msgid="75483255295529161">"Wi-Fi"</item>
    -+    <item msgid="6862614801537202646">"บลูทูธ"</item>
    -+    <item msgid="5447331121797802871">"อีเทอร์เน็ต"</item>
    -+    <item msgid="8257233890381651999">"VPN"</item>
    -+  </string-array>
    -+    <string name="network_switch_type_name_unknown" msgid="4552612897806660656">"ประเภทเครือข่ายที่ไม่รู้จัก"</string>
    -     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"ไม่สามารถเชื่อมต่อ WiFi"</string>
    -     <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" มีสัญญาณอินเทอร์เน็ตไม่ดี"</string>
    -     <string name="wifi_connect_alert_title" msgid="8455846016001810172">"อนุญาตการเชื่อมต่อใช่ไหม"</string>
    -@@ -1153,7 +1165,6 @@
    -     <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"แตะเพื่อเลือกภาษาและรูปแบบ"</string>
    -     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" กขฃคฅฆงจฉชซฌญฎฏฐฑฒณดตถทธนบปผฝพฟภมยรลวศษสหฬอฮ"</string>
    -     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" กขฃคฅฆงจฉชซฌญฎฏฐฑฒณดตถทธนบปผฝพฟภมยรลวศษสหฬอฮ"</string>
    --    <string name="candidates_style" msgid="4333913089637062257"><u>"ตัวเลือก"</u></string>
    -     <string name="ext_media_checking_notification_title" msgid="5734005953288045806">"กำลังเตรียม <xliff:g id="NAME">%s</xliff:g>"</string>
    -     <string name="ext_media_checking_notification_message" msgid="4747432538578886744">"กำลังตรวจหาข้อผิดพลาด"</string>
    -     <string name="ext_media_new_notification_message" msgid="7589986898808506239">"ตรวจพบ <xliff:g id="NAME">%s</xliff:g> ใหม่"</string>
    -@@ -1232,8 +1243,9 @@
    -     <string name="vpn_text_long" msgid="4907843483284977618">"เชื่อมต่อกับ <xliff:g id="SESSION">%s</xliff:g> แตะเพื่อจัดการเครือข่าย"</string>
    -     <string name="vpn_lockdown_connecting" msgid="6443438964440960745">"กำลังเชื่อมต่อ VPN แบบเปิดตลอดเวลา…"</string>
    -     <string name="vpn_lockdown_connected" msgid="8202679674819213931">"เชื่อมต่อ VPN แบบเปิดตลอดเวลาแล้ว"</string>
    -+    <string name="vpn_lockdown_disconnected" msgid="4532298952570796327">"ยกเลิกการเชื่อมต่อ VPN แบบเปิดตลอดเวลาแล้ว"</string>
    -     <string name="vpn_lockdown_error" msgid="6009249814034708175">"ข้อผิดพลาดของ VPN แบบเปิดตลอดเวลา"</string>
    --    <string name="vpn_lockdown_config" msgid="4655589351146766608">"แตะเพื่อกำหนดค่า"</string>
    -+    <string name="vpn_lockdown_config" msgid="5099330695245008680">"แตะเพื่อตั้งค่า"</string>
    -     <string name="upload_file" msgid="2897957172366730416">"เลือกไฟล์"</string>
    -     <string name="no_file_chosen" msgid="6363648562170759465">"ไม่ได้เลือกไฟล์ไว้"</string>
    -     <string name="reset" msgid="2448168080964209908">"รีเซ็ต"</string>
    -@@ -1317,7 +1329,7 @@
    -     <string name="storage_usb_drive_label" msgid="4501418548927759953">"ไดรฟ์ USB ของ <xliff:g id="MANUFACTURER">%s</xliff:g>"</string>
    -     <string name="storage_usb" msgid="3017954059538517278">"ที่เก็บข้อมูล USB"</string>
    -     <string name="extract_edit_menu_button" msgid="8940478730496610137">"แก้ไข"</string>
    --    <string name="data_usage_warning_title" msgid="1955638862122232342">"คำเตือนการใช้ข้อมูล"</string>
    -+    <string name="data_usage_warning_title" msgid="3620440638180218181">"การแจ้งเตือนการใช้อินเทอร์เน็ต"</string>
    -     <string name="data_usage_warning_body" msgid="6660692274311972007">"แตะเพื่อดูการใช้งานและการตั้งค่า"</string>
    -     <string name="data_usage_3g_limit_title" msgid="4361523876818447683">"ถึงขีดจำกัดข้อมูล 2G-3G แล้ว"</string>
    -     <string name="data_usage_4g_limit_title" msgid="4609566827219442376">"ถึงขีดจำกัดข้อมูล 4G แล้ว"</string>
    -@@ -1636,6 +1648,7 @@
    -     <string name="search_language_hint" msgid="7042102592055108574">"พิมพ์ชื่อภาษา"</string>
    -     <string name="language_picker_section_suggested" msgid="8414489646861640885">"แนะนำ"</string>
    -     <string name="language_picker_section_all" msgid="3097279199511617537">"ทุกภาษา"</string>
    -+    <string name="region_picker_section_all" msgid="8966316787153001779">"ภูมิภาคทั้งหมด"</string>
    -     <string name="locale_search_menu" msgid="2560710726687249178">"ค้นหา"</string>
    -     <string name="work_mode_off_title" msgid="8954725060677558855">"โหมดทำงานปิดอยู่"</string>
    -     <string name="work_mode_off_message" msgid="3286169091278094476">"อนุญาตให้โปรไฟล์งานทำงานได้ ซึ่งรวมถึงแอป การซิงค์ในพื้นหลัง และคุณลักษณะอื่นที่เกี่ยวข้อง"</string>
    -diff --git a/core/res/res/values-tl/strings.xml b/core/res/res/values-tl/strings.xml
    -index efb319f..b0d84ea 100644
    ---- a/core/res/res/values-tl/strings.xml
    -+++ b/core/res/res/values-tl/strings.xml
    -@@ -214,6 +214,7 @@
    -     <string name="global_actions" product="default" msgid="2406416831541615258">"Pagpipilian sa telepono"</string>
    -     <string name="global_action_lock" msgid="2844945191792119712">"Pag-lock sa screen"</string>
    -     <string name="global_action_power_off" msgid="4471879440839879722">"I-off"</string>
    -+    <string name="global_action_emergency" msgid="7112311161137421166">"Emergency"</string>
    -     <string name="global_action_bug_report" msgid="7934010578922304799">"Ulat sa bug"</string>
    -     <string name="bugreport_title" msgid="2667494803742548533">"Kunin ang ulat sa bug"</string>
    -     <string name="bugreport_message" msgid="398447048750350456">"Mangongolekta ito ng impormasyon tungkol sa kasalukuyang katayuan ng iyong device, na ipapadala bilang mensaheng e-mail. Gugugol ito ng kaunting oras mula sa pagsisimula ng ulat sa bug hanggang sa handa na itong maipadala; mangyaring magpasensya."</string>
    -@@ -1076,6 +1077,17 @@
    -     <skip />
    -     <string name="wifi_no_internet" msgid="8451173622563841546">"Walang access sa Internet ang Wi-Fi"</string>
    -     <string name="wifi_no_internet_detailed" msgid="8083079241212301741">"I-tap para sa mga opsyon"</string>
    -+    <string name="network_switch_metered" msgid="4671730921726992671">"Lumipat sa <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
    -+    <string name="network_switch_metered_detail" msgid="5325661434777870353">"Ginagamit ng device ang <xliff:g id="NEW_NETWORK">%1$s</xliff:g> kapag walang access sa Internet ang <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g>. Maaaring may mga malapat na singilin."</string>
    -+    <string name="network_switch_metered_toast" msgid="5779283181685974304">"Lumipat sa <xliff:g id="NEW_NETWORK">%2$s</xliff:g> mula sa <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g>"</string>
    -+  <string-array name="network_switch_type_name">
    -+    <item msgid="2952042958050315394">"cellular data"</item>
    -+    <item msgid="75483255295529161">"Wi-Fi"</item>
    -+    <item msgid="6862614801537202646">"Bluetooth"</item>
    -+    <item msgid="5447331121797802871">"Ethernet"</item>
    -+    <item msgid="8257233890381651999">"VPN"</item>
    -+  </string-array>
    -+    <string name="network_switch_type_name_unknown" msgid="4552612897806660656">"isang hindi kilalang uri ng network"</string>
    -     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Hindi makakonekta sa Wi-Fi"</string>
    -     <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" ay mayroong mahinang koneksyon sa Internet."</string>
    -     <string name="wifi_connect_alert_title" msgid="8455846016001810172">"Payagan ang kuneksyon?"</string>
    -@@ -1139,7 +1151,7 @@
    -     <string name="usb_accessory_notification_title" msgid="7848236974087653666">"Nakakonekta sa isang accessory ng USB"</string>
    -     <string name="usb_notification_message" msgid="3370903770828407960">"I-tap para sa higit pang mga opsyon."</string>
    -     <string name="adb_active_notification_title" msgid="6729044778949189918">"Konektado ang debugging ng USB"</string>
    --    <string name="adb_active_notification_message" msgid="4948470599328424059">"I-tap upang i-disable ang pagde-debug ng USB."</string>
    -+    <string name="adb_active_notification_message" msgid="4948470599328424059">"I-tap upang i-disable ang pag-debug ng USB."</string>
    -     <string name="taking_remote_bugreport_notification_title" msgid="6742483073875060934">"Kinukuha ang ulat ng bug…"</string>
    -     <string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"Gusto mo bang ibahagi ang ulat ng bug?"</string>
    -     <string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"Ibinabahagi ang ulat ng bug…"</string>
    -@@ -1153,7 +1165,6 @@
    -     <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"I-tap upang pumili ng wika at layout"</string>
    -     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
    -     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
    --    <string name="candidates_style" msgid="4333913089637062257"><u>"mga kandidato"</u></string>
    -     <string name="ext_media_checking_notification_title" msgid="5734005953288045806">"Inihahanda ang <xliff:g id="NAME">%s</xliff:g>"</string>
    -     <string name="ext_media_checking_notification_message" msgid="4747432538578886744">"Sinusuri para sa mga error"</string>
    -     <string name="ext_media_new_notification_message" msgid="7589986898808506239">"Na-detect ang bagong <xliff:g id="NAME">%s</xliff:g>"</string>
    -@@ -1232,8 +1243,9 @@
    -     <string name="vpn_text_long" msgid="4907843483284977618">"Nakakonekta sa <xliff:g id="SESSION">%s</xliff:g>. Tapikin upang pamahalaan ang network."</string>
    -     <string name="vpn_lockdown_connecting" msgid="6443438964440960745">"Kumukonekta ang Always-on VPN…"</string>
    -     <string name="vpn_lockdown_connected" msgid="8202679674819213931">"Nakakonekta ang Always-on VPN"</string>
    -+    <string name="vpn_lockdown_disconnected" msgid="4532298952570796327">"Hindi nakakonekta ang palaging naka-on na VPN"</string>
    -     <string name="vpn_lockdown_error" msgid="6009249814034708175">"Error sa Always-on VPN"</string>
    --    <string name="vpn_lockdown_config" msgid="4655589351146766608">"I-tap upang i-configure"</string>
    -+    <string name="vpn_lockdown_config" msgid="5099330695245008680">"I-tap upang i-set up"</string>
    -     <string name="upload_file" msgid="2897957172366730416">"Pumili ng file"</string>
    -     <string name="no_file_chosen" msgid="6363648562170759465">"Walang napiling file"</string>
    -     <string name="reset" msgid="2448168080964209908">"I-reset"</string>
    -@@ -1317,7 +1329,7 @@
    -     <string name="storage_usb_drive_label" msgid="4501418548927759953">"<xliff:g id="MANUFACTURER">%s</xliff:g> USB drive"</string>
    -     <string name="storage_usb" msgid="3017954059538517278">"USB storage"</string>
    -     <string name="extract_edit_menu_button" msgid="8940478730496610137">"I-edit"</string>
    --    <string name="data_usage_warning_title" msgid="1955638862122232342">"Babala sa paggamit ng data"</string>
    -+    <string name="data_usage_warning_title" msgid="3620440638180218181">"Alerto sa paggamit ng data"</string>
    -     <string name="data_usage_warning_body" msgid="6660692274311972007">"I-tap tingnan paggamit/setting."</string>
    -     <string name="data_usage_3g_limit_title" msgid="4361523876818447683">"Naabot na ang limitasyon sa 2G-3G data"</string>
    -     <string name="data_usage_4g_limit_title" msgid="4609566827219442376">"Naabot na ang limitasyon sa 4G data"</string>
    -@@ -1636,6 +1648,7 @@
    -     <string name="search_language_hint" msgid="7042102592055108574">"I-type ang wika"</string>
    -     <string name="language_picker_section_suggested" msgid="8414489646861640885">"Iminumungkahi"</string>
    -     <string name="language_picker_section_all" msgid="3097279199511617537">"Lahat ng wika"</string>
    -+    <string name="region_picker_section_all" msgid="8966316787153001779">"Lahat ng rehiyon"</string>
    -     <string name="locale_search_menu" msgid="2560710726687249178">"Maghanap"</string>
    -     <string name="work_mode_off_title" msgid="8954725060677558855">"NAKA-OFF ang work mode"</string>
    -     <string name="work_mode_off_message" msgid="3286169091278094476">"Payagang gumana ang profile sa trabaho, kasama na ang mga app, pag-sync sa background at mga may kaugnayang feature."</string>
    -diff --git a/core/res/res/values-tr/strings.xml b/core/res/res/values-tr/strings.xml
    -index 5a0776a..a089fd4 100644
    ---- a/core/res/res/values-tr/strings.xml
    -+++ b/core/res/res/values-tr/strings.xml
    -@@ -214,6 +214,7 @@
    -     <string name="global_actions" product="default" msgid="2406416831541615258">"Telefon seçenekleri"</string>
    -     <string name="global_action_lock" msgid="2844945191792119712">"Ekran kilidi"</string>
    -     <string name="global_action_power_off" msgid="4471879440839879722">"Kapat"</string>
    -+    <string name="global_action_emergency" msgid="7112311161137421166">"Acil durum"</string>
    -     <string name="global_action_bug_report" msgid="7934010578922304799">"Hata raporu"</string>
    -     <string name="bugreport_title" msgid="2667494803742548533">"Hata raporu al"</string>
    -     <string name="bugreport_message" msgid="398447048750350456">"Bu rapor, e-posta iletisi olarak göndermek üzere cihazınızın şu anki durumuyla ilgili bilgi toplar. Hata raporu başlatıldıktan sonra hazır olması biraz zaman alabilir, lütfen sabırlı olun."</string>
    -@@ -1076,6 +1077,17 @@
    -     <skip />
    -     <string name="wifi_no_internet" msgid="8451173622563841546">"Kablosuz bağlantıda İnternet erişimi yok"</string>
    -     <string name="wifi_no_internet_detailed" msgid="8083079241212301741">"Seçenekler için dokunun"</string>
    -+    <string name="network_switch_metered" msgid="4671730921726992671">"<xliff:g id="NETWORK_TYPE">%1$s</xliff:g> ağına geçildi"</string>
    -+    <string name="network_switch_metered_detail" msgid="5325661434777870353">"<xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> ağının İnternet erişimi olmadığında cihaz <xliff:g id="NEW_NETWORK">%1$s</xliff:g> ağını kullanır. Bunun için ödeme alınabilir."</string>
    -+    <string name="network_switch_metered_toast" msgid="5779283181685974304">"<xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> ağından <xliff:g id="NEW_NETWORK">%2$s</xliff:g> ağına geçildi"</string>
    -+  <string-array name="network_switch_type_name">
    -+    <item msgid="2952042958050315394">"hücresel veri"</item>
    -+    <item msgid="75483255295529161">"Kablosuz"</item>
    -+    <item msgid="6862614801537202646">"Bluetooth"</item>
    -+    <item msgid="5447331121797802871">"Ethernet"</item>
    -+    <item msgid="8257233890381651999">"VPN"</item>
    -+  </string-array>
    -+    <string name="network_switch_type_name_unknown" msgid="4552612897806660656">"bilinmeyen ağ türü"</string>
    -     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Kablosuz bağlantısı kurulamadı"</string>
    -     <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" İnternet bağlantısı zayıf."</string>
    -     <string name="wifi_connect_alert_title" msgid="8455846016001810172">"Bağlantıya izin verilsin mi?"</string>
    -@@ -1153,7 +1165,6 @@
    -     <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"Dili ve düzeni seçmek için hafifçe dokunun"</string>
    -     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
    -     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
    --    <string name="candidates_style" msgid="4333913089637062257"><u>"adaylar"</u></string>
    -     <string name="ext_media_checking_notification_title" msgid="5734005953288045806">"<xliff:g id="NAME">%s</xliff:g> hazırlanıyor"</string>
    -     <string name="ext_media_checking_notification_message" msgid="4747432538578886744">"Hatalar denetleniyor"</string>
    -     <string name="ext_media_new_notification_message" msgid="7589986898808506239">"Yeni <xliff:g id="NAME">%s</xliff:g> algılandı"</string>
    -@@ -1232,8 +1243,9 @@
    -     <string name="vpn_text_long" msgid="4907843483284977618">"<xliff:g id="SESSION">%s</xliff:g> oturumuna bağlı. Ağı yönetmek için hafifçe vurun."</string>
    -     <string name="vpn_lockdown_connecting" msgid="6443438964440960745">"Her zaman açık VPN\'ye bağlanılıyor…"</string>
    -     <string name="vpn_lockdown_connected" msgid="8202679674819213931">"Her zaman açık VPN\'ye bağlanıldı"</string>
    -+    <string name="vpn_lockdown_disconnected" msgid="4532298952570796327">"Her zaman açık VPN bağlantısı kesildi"</string>
    -     <string name="vpn_lockdown_error" msgid="6009249814034708175">"Her zaman açık VPN hatası"</string>
    --    <string name="vpn_lockdown_config" msgid="4655589351146766608">"Yapılandırmak için dokunun"</string>
    -+    <string name="vpn_lockdown_config" msgid="5099330695245008680">"Ayarlamak için dokunun"</string>
    -     <string name="upload_file" msgid="2897957172366730416">"Dosya seç"</string>
    -     <string name="no_file_chosen" msgid="6363648562170759465">"Seçili dosya yok"</string>
    -     <string name="reset" msgid="2448168080964209908">"Sıfırla"</string>
    -@@ -1317,7 +1329,7 @@
    -     <string name="storage_usb_drive_label" msgid="4501418548927759953">"<xliff:g id="MANUFACTURER">%s</xliff:g> USB sürücüsü"</string>
    -     <string name="storage_usb" msgid="3017954059538517278">"USB bellek"</string>
    -     <string name="extract_edit_menu_button" msgid="8940478730496610137">"Düzenle"</string>
    --    <string name="data_usage_warning_title" msgid="1955638862122232342">"Veri kullanım uyarısı"</string>
    -+    <string name="data_usage_warning_title" msgid="3620440638180218181">"Veri kullanımı uyarısı"</string>
    -     <string name="data_usage_warning_body" msgid="6660692274311972007">"Kul. ve ayar. gör. için dokunun."</string>
    -     <string name="data_usage_3g_limit_title" msgid="4361523876818447683">"2G-3G veri sınırına ulaşıldı"</string>
    -     <string name="data_usage_4g_limit_title" msgid="4609566827219442376">"4G veri sınırına ulaşıldı"</string>
    -@@ -1636,6 +1648,7 @@
    -     <string name="search_language_hint" msgid="7042102592055108574">"Dil adını yazın"</string>
    -     <string name="language_picker_section_suggested" msgid="8414489646861640885">"Önerilen"</string>
    -     <string name="language_picker_section_all" msgid="3097279199511617537">"Tüm diller"</string>
    -+    <string name="region_picker_section_all" msgid="8966316787153001779">"Tüm bölgeler"</string>
    -     <string name="locale_search_menu" msgid="2560710726687249178">"Ara"</string>
    -     <string name="work_mode_off_title" msgid="8954725060677558855">"İş modu KAPALI"</string>
    -     <string name="work_mode_off_message" msgid="3286169091278094476">"Uygulamalar, arka planda senkronizasyon ve ilgili özellikler dahil olmak üzere iş profilinin çalışmasına izin ver."</string>
    -diff --git a/core/res/res/values-uk/strings.xml b/core/res/res/values-uk/strings.xml
    -index 4810e37..704ade8 100644
    ---- a/core/res/res/values-uk/strings.xml
    -+++ b/core/res/res/values-uk/strings.xml
    -@@ -218,6 +218,7 @@
    -     <string name="global_actions" product="default" msgid="2406416831541615258">"Параметри телеф."</string>
    -     <string name="global_action_lock" msgid="2844945191792119712">"Заблок. екран"</string>
    -     <string name="global_action_power_off" msgid="4471879440839879722">"Вимкнути"</string>
    -+    <string name="global_action_emergency" msgid="7112311161137421166">"Екстрений виклик"</string>
    -     <string name="global_action_bug_report" msgid="7934010578922304799">"Звіт про помилки"</string>
    -     <string name="bugreport_title" msgid="2667494803742548533">"Звіт про помилку"</string>
    -     <string name="bugreport_message" msgid="398447048750350456">"Інформація про поточний стан вашого пристрою буде зібрана й надіслана електронною поштою. Підготовка звіту триватиме певний час."</string>
    -@@ -1103,8 +1104,8 @@
    -     <string name="volume_icon_description_incall" msgid="8890073218154543397">"Гучність сигналу виклику"</string>
    -     <string name="volume_icon_description_media" msgid="4217311719665194215">"Гучність медіа"</string>
    -     <string name="volume_icon_description_notification" msgid="7044986546477282274">"Гучність сповіщення"</string>
    --    <string name="ringtone_default" msgid="3789758980357696936">"Мелодія за умовч."</string>
    --    <string name="ringtone_default_with_actual" msgid="8129563480895990372">"Мелодія за умовч. (<xliff:g id="ACTUAL_RINGTONE">%1$s</xliff:g>)"</string>
    -+    <string name="ringtone_default" msgid="3789758980357696936">"Мелодія за умовчанням"</string>
    -+    <string name="ringtone_default_with_actual" msgid="8129563480895990372">"Мелодія за умовчанням (<xliff:g id="ACTUAL_RINGTONE">%1$s</xliff:g>)"</string>
    -     <string name="ringtone_silent" msgid="7937634392408977062">"Немає"</string>
    -     <string name="ringtone_picker_title" msgid="3515143939175119094">"Мелодії"</string>
    -     <string name="ringtone_unknown" msgid="5477919988701784788">"Невідома мелодія"</string>
    -@@ -1126,6 +1127,17 @@
    -     <skip />
    -     <string name="wifi_no_internet" msgid="8451173622563841546">"Мережа Wi-Fi не має доступу до Інтернету"</string>
    -     <string name="wifi_no_internet_detailed" msgid="8083079241212301741">"Торкніться, щоб відкрити опції"</string>
    -+    <string name="network_switch_metered" msgid="4671730921726992671">"Пристрій перейшов на мережу <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
    -+    <string name="network_switch_metered_detail" msgid="5325661434777870353">"Пристрій використовує мережу <xliff:g id="NEW_NETWORK">%1$s</xliff:g>, коли мережа <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> не має доступу до Інтернету. Може стягуватися плата."</string>
    -+    <string name="network_switch_metered_toast" msgid="5779283181685974304">"Пристрій перейшов з мережі <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> на мережу <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
    -+  <string-array name="network_switch_type_name">
    -+    <item msgid="2952042958050315394">"мобільний трафік"</item>
    -+    <item msgid="75483255295529161">"Wi-Fi"</item>
    -+    <item msgid="6862614801537202646">"Bluetooth"</item>
    -+    <item msgid="5447331121797802871">"Ethernet"</item>
    -+    <item msgid="8257233890381651999">"Мережа VPN"</item>
    -+  </string-array>
    -+    <string name="network_switch_type_name_unknown" msgid="4552612897806660656">"невідомий тип мережі"</string>
    -     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Не вдалося під’єднатися до мережі Wi-Fi"</string>
    -     <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" має погане з’єднання з Інтернетом."</string>
    -     <string name="wifi_connect_alert_title" msgid="8455846016001810172">"Дозволити з’єднання?"</string>
    -@@ -1203,7 +1215,6 @@
    -     <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"Торкніться, щоб вибрати мову та розкладку"</string>
    -     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" АБВГҐДЕЄЖЗИІЇЙКЛМНОПРСТУФХЦЧШЩЬЮЯ"</string>
    -     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789АБВГҐДЕЄЖЗИІЇЙКЛМНОПРСТУФХЦЧШЩЬЮЯ"</string>
    --    <string name="candidates_style" msgid="4333913089637062257"><u>"кандидати"</u></string>
    -     <string name="ext_media_checking_notification_title" msgid="5734005953288045806">"Підготовка пристрою пам’яті <xliff:g id="NAME">%s</xliff:g>"</string>
    -     <string name="ext_media_checking_notification_message" msgid="4747432538578886744">"Виявлення помилок"</string>
    -     <string name="ext_media_new_notification_message" msgid="7589986898808506239">"Виявлено новий пристрій пам’яті (<xliff:g id="NAME">%s</xliff:g>)"</string>
    -@@ -1282,8 +1293,9 @@
    -     <string name="vpn_text_long" msgid="4907843483284977618">"Під’єднано до <xliff:g id="SESSION">%s</xliff:g>. Торкніться, щоб керувати мережею."</string>
    -     <string name="vpn_lockdown_connecting" msgid="6443438964440960745">"Під’єднання до постійної мережі VPN…"</string>
    -     <string name="vpn_lockdown_connected" msgid="8202679674819213931">"Під’єднано до постійної мережі VPN"</string>
    -+    <string name="vpn_lockdown_disconnected" msgid="4532298952570796327">"Постійну мережу VPN від’єднано"</string>
    -     <string name="vpn_lockdown_error" msgid="6009249814034708175">"Помилка постійної мережі VPN"</string>
    --    <string name="vpn_lockdown_config" msgid="4655589351146766608">"Торкніться, щоб налаштувати"</string>
    -+    <string name="vpn_lockdown_config" msgid="5099330695245008680">"Торкніться, щоб налаштувати"</string>
    -     <string name="upload_file" msgid="2897957172366730416">"Виберіть файл"</string>
    -     <string name="no_file_chosen" msgid="6363648562170759465">"Не вибрано файл"</string>
    -     <string name="reset" msgid="2448168080964209908">"Віднов."</string>
    -@@ -1369,7 +1381,7 @@
    -     <string name="storage_usb_drive_label" msgid="4501418548927759953">"Носій USB (<xliff:g id="MANUFACTURER">%s</xliff:g>)"</string>
    -     <string name="storage_usb" msgid="3017954059538517278">"Носій USB"</string>
    -     <string name="extract_edit_menu_button" msgid="8940478730496610137">"Редагувати"</string>
    --    <string name="data_usage_warning_title" msgid="1955638862122232342">"Застереження про використ. даних"</string>
    -+    <string name="data_usage_warning_title" msgid="3620440638180218181">"Сповіщення про використ. трафіку"</string>
    -     <string name="data_usage_warning_body" msgid="6660692274311972007">"Переглянути дані та параметри."</string>
    -     <string name="data_usage_3g_limit_title" msgid="4361523876818447683">"Досягнуто ліміту даних 2G–3G"</string>
    -     <string name="data_usage_4g_limit_title" msgid="4609566827219442376">"Досягнуто ліміту даних 4G"</string>
    -@@ -1708,6 +1720,7 @@
    -     <string name="search_language_hint" msgid="7042102592055108574">"Введіть назву мови"</string>
    -     <string name="language_picker_section_suggested" msgid="8414489646861640885">"Пропоновані"</string>
    -     <string name="language_picker_section_all" msgid="3097279199511617537">"Усі мови"</string>
    -+    <string name="region_picker_section_all" msgid="8966316787153001779">"Усі регіони"</string>
    -     <string name="locale_search_menu" msgid="2560710726687249178">"Пошук"</string>
    -     <string name="work_mode_off_title" msgid="8954725060677558855">"Робочий профіль ВИМКНЕНО"</string>
    -     <string name="work_mode_off_message" msgid="3286169091278094476">"Увімкнути робочий профіль, зокрема додатки, фонову синхронізацію та пов’язані функції."</string>
    -diff --git a/core/res/res/values-ur-rPK/strings.xml b/core/res/res/values-ur-rPK/strings.xml
    -index f677132..24a03b2 100644
    ---- a/core/res/res/values-ur-rPK/strings.xml
    -+++ b/core/res/res/values-ur-rPK/strings.xml
    -@@ -214,6 +214,7 @@
    -     <string name="global_actions" product="default" msgid="2406416831541615258">"فون کے اختیارات"</string>
    -     <string name="global_action_lock" msgid="2844945191792119712">"اسکرین لاک"</string>
    -     <string name="global_action_power_off" msgid="4471879440839879722">"پاور آف"</string>
    -+    <string name="global_action_emergency" msgid="7112311161137421166">"ایمرجنسی"</string>
    -     <string name="global_action_bug_report" msgid="7934010578922304799">"بگ کی اطلاع"</string>
    -     <string name="bugreport_title" msgid="2667494803742548533">"بگ کی اطلاع لیں"</string>
    -     <string name="bugreport_message" msgid="398447048750350456">"ایک ای میل پیغام کے بطور بھیجنے کیلئے، یہ آپ کے موجودہ آلہ کی حالت کے بارے میں معلومات جمع کرے گا۔ بگ کی اطلاع شروع کرنے سے لے کر بھیجنے کیلئے تیار ہونے تک اس میں تھوڑا وقت لگے گا؛ براہ کرم تحمل سے کام لیں۔"</string>
    -@@ -1076,6 +1077,17 @@
    -     <skip />
    -     <string name="wifi_no_internet" msgid="8451173622563841546">"‏Wi-Fi کی انٹرنیٹ تک رسائی نہیں ہے"</string>
    -     <string name="wifi_no_internet_detailed" msgid="8083079241212301741">"اختیارات کیلئے تھپتھپائیں"</string>
    -+    <string name="network_switch_metered" msgid="4671730921726992671">"<xliff:g id="NETWORK_TYPE">%1$s</xliff:g> پر سوئچ ہو گیا"</string>
    -+    <string name="network_switch_metered_detail" msgid="5325661434777870353">"جب <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> کے پاس انٹرنیٹ تک رسائی نہ ہو تو آلہ <xliff:g id="NEW_NETWORK">%1$s</xliff:g> کو استعمال کرتا ہے۔ چارجز کا اطلاق ہو سکتا ہے۔"</string>
    -+    <string name="network_switch_metered_toast" msgid="5779283181685974304">"<xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> سے <xliff:g id="NEW_NETWORK">%2$s</xliff:g> پر سوئچ ہو گیا"</string>
    -+  <string-array name="network_switch_type_name">
    -+    <item msgid="2952042958050315394">"سیلولر ڈیٹا"</item>
    -+    <item msgid="75483255295529161">"Wi-Fi"</item>
    -+    <item msgid="6862614801537202646">"بلوٹوتھ"</item>
    -+    <item msgid="5447331121797802871">"ایتھرنیٹ"</item>
    -+    <item msgid="8257233890381651999">"VPN"</item>
    -+  </string-array>
    -+    <string name="network_switch_type_name_unknown" msgid="4552612897806660656">"نیٹ ورک کی نامعلوم قسم"</string>
    -     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"‏Wi-Fi سے مربوط نہیں ہو سکا"</string>
    -     <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" اس میں ایک کمزور انٹرنیٹ کنکشن ہے۔"</string>
    -     <string name="wifi_connect_alert_title" msgid="8455846016001810172">"کنکشن کی اجازت دیں؟"</string>
    -@@ -1153,7 +1165,6 @@
    -     <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"زبان اور لے آؤٹ منتخب کرنے کیلئے تھپتھپائیں"</string>
    -     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
    -     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
    --    <string name="candidates_style" msgid="4333913089637062257"><u>"امیدواران"</u></string>
    -     <string name="ext_media_checking_notification_title" msgid="5734005953288045806">"<xliff:g id="NAME">%s</xliff:g> تیار کیا جا رہا ہے"</string>
    -     <string name="ext_media_checking_notification_message" msgid="4747432538578886744">"خرابیوں کیلئے چیک کیا جا رہا ہے"</string>
    -     <string name="ext_media_new_notification_message" msgid="7589986898808506239">"نئے <xliff:g id="NAME">%s</xliff:g> کا پتا چلا"</string>
    -@@ -1232,8 +1243,9 @@
    -     <string name="vpn_text_long" msgid="4907843483284977618">"<xliff:g id="SESSION">%s</xliff:g> سے منسلک ہے۔ نیٹ ورک کا نظم کرنے کیلئے تھپتھپائیں۔"</string>
    -     <string name="vpn_lockdown_connecting" msgid="6443438964440960745">"‏ہمیشہ آن VPN مربوط ہو رہا ہے…"</string>
    -     <string name="vpn_lockdown_connected" msgid="8202679674819213931">"‏ہمیشہ آن VPN مربوط ہوگیا"</string>
    -+    <string name="vpn_lockdown_disconnected" msgid="4532298952570796327">"‏ہمیشہ آن VPN غیر منسلک ہو گیا"</string>
    -     <string name="vpn_lockdown_error" msgid="6009249814034708175">"‏ہمیشہ آن VPN کی خرابی"</string>
    --    <string name="vpn_lockdown_config" msgid="4655589351146766608">"کنفیگر کرنے کیلئے تھپتھپائیں"</string>
    -+    <string name="vpn_lockdown_config" msgid="5099330695245008680">"سیٹ اپ کرنے کیلئے تھپتھپائیں"</string>
    -     <string name="upload_file" msgid="2897957172366730416">"فائل منتخب کریں"</string>
    -     <string name="no_file_chosen" msgid="6363648562170759465">"کوئی فائل منتخب نہیں کی گئی"</string>
    -     <string name="reset" msgid="2448168080964209908">"دوبارہ ترتیب دیں"</string>
    -@@ -1317,7 +1329,7 @@
    -     <string name="storage_usb_drive_label" msgid="4501418548927759953">"‏<xliff:g id="MANUFACTURER">%s</xliff:g> USB ڈرائیو"</string>
    -     <string name="storage_usb" msgid="3017954059538517278">"‏USB اسٹوریج"</string>
    -     <string name="extract_edit_menu_button" msgid="8940478730496610137">"ترمیم کریں"</string>
    --    <string name="data_usage_warning_title" msgid="1955638862122232342">"ڈیٹا کے استعمال کی وارننگ"</string>
    -+    <string name="data_usage_warning_title" msgid="3620440638180218181">"ڈیٹا کے استعمال کا الرٹ"</string>
    -     <string name="data_usage_warning_body" msgid="6660692274311972007">"استعمال اور ترتیبات دیکھنے کیلئے تھپتھپائیں۔"</string>
    -     <string name="data_usage_3g_limit_title" msgid="4361523876818447683">"‏2G-3G ڈیٹا کی حد کو پہنچ گیا"</string>
    -     <string name="data_usage_4g_limit_title" msgid="4609566827219442376">"‏4G ڈیٹا کی حد کو پہنچ گیا"</string>
    -@@ -1636,6 +1648,7 @@
    -     <string name="search_language_hint" msgid="7042102592055108574">"زبان کا نام ٹائپ کریں"</string>
    -     <string name="language_picker_section_suggested" msgid="8414489646861640885">"تجویز کردہ"</string>
    -     <string name="language_picker_section_all" msgid="3097279199511617537">"سبھی زبانیں"</string>
    -+    <string name="region_picker_section_all" msgid="8966316787153001779">"تمام علاقے"</string>
    -     <string name="locale_search_menu" msgid="2560710726687249178">"تلاش"</string>
    -     <string name="work_mode_off_title" msgid="8954725060677558855">"کام موڈ آف ہے"</string>
    -     <string name="work_mode_off_message" msgid="3286169091278094476">"دفتری پروفائل کو کام کرنے دیں، بشمول ایپس، پس منظر کی مطابقت پذیری اور متعلقہ خصوصیات۔"</string>
    -diff --git a/core/res/res/values-uz-rUZ/strings.xml b/core/res/res/values-uz-rUZ/strings.xml
    -index 8fc6428..e5a2889 100644
    ---- a/core/res/res/values-uz-rUZ/strings.xml
    -+++ b/core/res/res/values-uz-rUZ/strings.xml
    -@@ -214,6 +214,7 @@
    -     <string name="global_actions" product="default" msgid="2406416831541615258">"Telefon sozlamalari"</string>
    -     <string name="global_action_lock" msgid="2844945191792119712">"Ekran qulfi"</string>
    -     <string name="global_action_power_off" msgid="4471879440839879722">"O‘chirish"</string>
    -+    <string name="global_action_emergency" msgid="7112311161137421166">"Favqulodda chaqiruv"</string>
    -     <string name="global_action_bug_report" msgid="7934010578922304799">"Nosozlik haqida ma’lumot berish"</string>
    -     <string name="bugreport_title" msgid="2667494803742548533">"Xatoliklar hisoboti"</string>
    -     <string name="bugreport_message" msgid="398447048750350456">"Qurilmangiz holati haqidagi ma’lumotlar to‘planib, e-pochta orqali yuboriladi. Hisobotni tayyorlash biroz vaqt olishi mumkin."</string>
    -@@ -1076,6 +1077,17 @@
    -     <skip />
    -     <string name="wifi_no_internet" msgid="8451173622563841546">"Wi-Fi tarmog‘ida internet aloqasi yo‘q"</string>
    -     <string name="wifi_no_internet_detailed" msgid="8083079241212301741">"Variantlarni ko‘rsatish uchun bosing"</string>
    -+    <string name="network_switch_metered" msgid="4671730921726992671">"<xliff:g id="NETWORK_TYPE">%1$s</xliff:g> tarmog‘iga ulanildi"</string>
    -+    <string name="network_switch_metered_detail" msgid="5325661434777870353">"Qurilma <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> tarmog‘ida internet o‘chganda, <xliff:g id="NEW_NETWORK">%1$s</xliff:g> tarmog‘iga ulaniladi. To‘lov olinishi mumkin."</string>
    -+    <string name="network_switch_metered_toast" msgid="5779283181685974304">"<xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> tarmog‘idan <xliff:g id="NEW_NETWORK">%2$s</xliff:g> tarmog‘iga o‘tildi"</string>
    -+  <string-array name="network_switch_type_name">
    -+    <item msgid="2952042958050315394">"mobil internet"</item>
    -+    <item msgid="75483255295529161">"Wi-Fi"</item>
    -+    <item msgid="6862614801537202646">"Bluetooth"</item>
    -+    <item msgid="5447331121797802871">"Ethernet"</item>
    -+    <item msgid="8257233890381651999">"VPN"</item>
    -+  </string-array>
    -+    <string name="network_switch_type_name_unknown" msgid="4552612897806660656">"noma’lum tarmoq turi"</string>
    -     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Wi-Fi’ga ulana olmadi"</string>
    -     <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" tezligi past Internetga ulangan."</string>
    -     <string name="wifi_connect_alert_title" msgid="8455846016001810172">"Ulanishga ruxsat berilsinmi?"</string>
    -@@ -1087,7 +1099,7 @@
    -     <string name="wifi_p2p_enabled_notification_title" msgid="2068321881673734886">"Wi-Fi Direct yoniq"</string>
    -     <string name="wifi_p2p_enabled_notification_message" msgid="8064677407830620023">"Sozlamalarni ochish uchun bosing"</string>
    -     <string name="accept" msgid="1645267259272829559">"Qabul qilish"</string>
    --    <string name="decline" msgid="2112225451706137894">"Rad qilish"</string>
    -+    <string name="decline" msgid="2112225451706137894">"Rad etish"</string>
    -     <string name="wifi_p2p_invitation_sent_title" msgid="1318975185112070734">"taklif jo‘natildi"</string>
    -     <string name="wifi_p2p_invitation_to_connect_title" msgid="4958803948658533637">"ulanish taklifi"</string>
    -     <string name="wifi_p2p_from_message" msgid="570389174731951769">"Kimdan:"</string>
    -@@ -1101,7 +1113,7 @@
    -     <string name="sms_control_title" msgid="7296612781128917719">"SMS xabarlar yuborilmoqda"</string>
    -     <string name="sms_control_message" msgid="3867899169651496433">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; katta miqdordagi SMS xabarlarini jo‘natmoqda. Ushbu ilovaga xabarlar jo‘natishni davom ettirishga ruxsat berasizmi?"</string>
    -     <string name="sms_control_yes" msgid="3663725993855816807">"Ruxsat berish"</string>
    --    <string name="sms_control_no" msgid="625438561395534982">"Rad qilish"</string>
    -+    <string name="sms_control_no" msgid="625438561395534982">"Rad etish"</string>
    -     <string name="sms_short_code_confirm_message" msgid="1645436466285310855">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; &lt;b&gt;<xliff:g id="DEST_ADDRESS">%2$s</xliff:g>&lt;/b&gt;ga xabar jo‘natishni xohlaydi."</string>
    -     <string name="sms_short_code_details" msgid="5873295990846059400">"Bunda, mobil hisobingizdan "<b>"to‘lov olinishi mumkin"</b>"."</string>
    -     <string name="sms_premium_short_code_details" msgid="7869234868023975"><b>"Bunda, mobil hisobingizdan to‘lov olinishi mumkin."</b></string>
    -@@ -1153,7 +1165,6 @@
    -     <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"Til va sxemani belgilash uchun bosing"</string>
    -     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
    -     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
    --    <string name="candidates_style" msgid="4333913089637062257"><u>"nomzodlar"</u></string>
    -     <string name="ext_media_checking_notification_title" msgid="5734005953288045806">"<xliff:g id="NAME">%s</xliff:g> tayyorlanmoqda"</string>
    -     <string name="ext_media_checking_notification_message" msgid="4747432538578886744">"Xatolar qidirilmoqda"</string>
    -     <string name="ext_media_new_notification_message" msgid="7589986898808506239">"Yangi <xliff:g id="NAME">%s</xliff:g> kartasi aniqlandi"</string>
    -@@ -1212,7 +1223,7 @@
    -     <string name="grant_credentials_permission_message_footer" msgid="3125211343379376561">"Ushbu so‘rovga ruxsat berishni xohlaysizmi?"</string>
    -     <string name="grant_permissions_header_text" msgid="6874497408201826708">"Ruxsat so‘rovi"</string>
    -     <string name="allow" msgid="7225948811296386551">"Ruxsat berish"</string>
    --    <string name="deny" msgid="2081879885755434506">"Rad qilish"</string>
    -+    <string name="deny" msgid="2081879885755434506">"Rad etish"</string>
    -     <string name="permission_request_notification_title" msgid="6486759795926237907">"Ruxsat so‘raldi"</string>
    -     <string name="permission_request_notification_with_subtitle" msgid="8530393139639560189">"<xliff:g id="ACCOUNT">%s</xliff:g> hisobi uchun\nruxsat so‘raldi"</string>
    -     <string name="forward_intent_to_owner" msgid="1207197447013960896">"Siz ushbu ilovadan ishchi profilingizdan tashqarida foydalanmoqdasiz"</string>
    -@@ -1232,8 +1243,9 @@
    -     <string name="vpn_text_long" msgid="4907843483284977618">"<xliff:g id="SESSION">%s</xliff:g> ulandi. Tarmoq sozlamalarini o‘zgartirish uchun bu yerni bosing."</string>
    -     <string name="vpn_lockdown_connecting" msgid="6443438964440960745">"Ulanmoqda…"</string>
    -     <string name="vpn_lockdown_connected" msgid="8202679674819213931">"Ulandi"</string>
    -+    <string name="vpn_lockdown_disconnected" msgid="4532298952570796327">"Doimiy VPN o‘chirildi"</string>
    -     <string name="vpn_lockdown_error" msgid="6009249814034708175">"Xato"</string>
    --    <string name="vpn_lockdown_config" msgid="4655589351146766608">"Sozlash uchun bosing"</string>
    -+    <string name="vpn_lockdown_config" msgid="5099330695245008680">"Sozlash uchun bosing"</string>
    -     <string name="upload_file" msgid="2897957172366730416">"Faylni tanlash"</string>
    -     <string name="no_file_chosen" msgid="6363648562170759465">"Hech qanday fayl tanlanmadi"</string>
    -     <string name="reset" msgid="2448168080964209908">"Asliga qaytarish"</string>
    -@@ -1317,7 +1329,7 @@
    -     <string name="storage_usb_drive_label" msgid="4501418548927759953">"<xliff:g id="MANUFACTURER">%s</xliff:g> USB xotira qurilmasi"</string>
    -     <string name="storage_usb" msgid="3017954059538517278">"USB xotira"</string>
    -     <string name="extract_edit_menu_button" msgid="8940478730496610137">"Tahrirlash"</string>
    --    <string name="data_usage_warning_title" msgid="1955638862122232342">"Trafik kam qoldi"</string>
    -+    <string name="data_usage_warning_title" msgid="3620440638180218181">"Trafik sarfi bo‘yicha ogohlantirish"</string>
    -     <string name="data_usage_warning_body" msgid="6660692274311972007">"Trafik sarfi va sozlamalarni ko‘rish uchun bosing."</string>
    -     <string name="data_usage_3g_limit_title" msgid="4361523876818447683">"2G-3G trafik chekloviga yetdi"</string>
    -     <string name="data_usage_4g_limit_title" msgid="4609566827219442376">"4G trafik chekloviga yetdi"</string>
    -@@ -1636,6 +1648,7 @@
    -     <string name="search_language_hint" msgid="7042102592055108574">"Til nomini kiriting"</string>
    -     <string name="language_picker_section_suggested" msgid="8414489646861640885">"Taklif etiladi"</string>
    -     <string name="language_picker_section_all" msgid="3097279199511617537">"Barcha tillar"</string>
    -+    <string name="region_picker_section_all" msgid="8966316787153001779">"Barcha hududlar"</string>
    -     <string name="locale_search_menu" msgid="2560710726687249178">"Qidiruv"</string>
    -     <string name="work_mode_off_title" msgid="8954725060677558855">"Ish rejimi O‘CHIQ"</string>
    -     <string name="work_mode_off_message" msgid="3286169091278094476">"Ishchi profilini yoqish: ilovalar, fonda sinxronlash va bog‘liq funksiyalar."</string>
    -diff --git a/core/res/res/values-vi/strings.xml b/core/res/res/values-vi/strings.xml
    -index a537b8f..0bbfe3b 100644
    ---- a/core/res/res/values-vi/strings.xml
    -+++ b/core/res/res/values-vi/strings.xml
    -@@ -214,6 +214,7 @@
    -     <string name="global_actions" product="default" msgid="2406416831541615258">"Tùy chọn điện thoại"</string>
    -     <string name="global_action_lock" msgid="2844945191792119712">"Khoá màn hình"</string>
    -     <string name="global_action_power_off" msgid="4471879440839879722">"Tắt nguồn"</string>
    -+    <string name="global_action_emergency" msgid="7112311161137421166">"Khẩn cấp"</string>
    -     <string name="global_action_bug_report" msgid="7934010578922304799">"Báo cáo lỗi"</string>
    -     <string name="bugreport_title" msgid="2667494803742548533">"Nhận báo cáo lỗi"</string>
    -     <string name="bugreport_message" msgid="398447048750350456">"Báo cáo này sẽ thu thập thông tin về tình trạng thiết bị hiện tại của bạn, để gửi dưới dạng thông báo qua email. Sẽ mất một chút thời gian kể từ khi bắt đầu báo cáo lỗi cho tới khi báo cáo sẵn sàng để gửi; xin vui lòng kiên nhẫn."</string>
    -@@ -1076,6 +1077,17 @@
    -     <skip />
    -     <string name="wifi_no_internet" msgid="8451173622563841546">"Wi-Fi không có quyền truy cập Internet"</string>
    -     <string name="wifi_no_internet_detailed" msgid="8083079241212301741">"Nhấn để biết tùy chọn"</string>
    -+    <string name="network_switch_metered" msgid="4671730921726992671">"Đã chuyển sang <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
    -+    <string name="network_switch_metered_detail" msgid="5325661434777870353">"Thiết bị sử dụng <xliff:g id="NEW_NETWORK">%1$s</xliff:g> khi <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> không có quyền truy cập Internet. Bạn có thể phải trả phí."</string>
    -+    <string name="network_switch_metered_toast" msgid="5779283181685974304">"Đã chuyển từ <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> sang <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
    -+  <string-array name="network_switch_type_name">
    -+    <item msgid="2952042958050315394">"dữ liệu di động"</item>
    -+    <item msgid="75483255295529161">"Wi-Fi"</item>
    -+    <item msgid="6862614801537202646">"Bluetooth"</item>
    -+    <item msgid="5447331121797802871">"Ethernet"</item>
    -+    <item msgid="8257233890381651999">"VPN"</item>
    -+  </string-array>
    -+    <string name="network_switch_type_name_unknown" msgid="4552612897806660656">"loại mạng không xác định"</string>
    -     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Không thể kết nối với Wi-Fi"</string>
    -     <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" có kết nối Internet không tốt."</string>
    -     <string name="wifi_connect_alert_title" msgid="8455846016001810172">"Cho phép kết nối?"</string>
    -@@ -1153,7 +1165,6 @@
    -     <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"Nhấn để chọn ngôn ngữ và bố cục"</string>
    -     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
    -     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
    --    <string name="candidates_style" msgid="4333913089637062257"><u>"ứng viên"</u></string>
    -     <string name="ext_media_checking_notification_title" msgid="5734005953288045806">"Đang chuẩn bị <xliff:g id="NAME">%s</xliff:g>"</string>
    -     <string name="ext_media_checking_notification_message" msgid="4747432538578886744">"Đang kiểm tra lỗi"</string>
    -     <string name="ext_media_new_notification_message" msgid="7589986898808506239">"Đã phát hiện <xliff:g id="NAME">%s</xliff:g> mới"</string>
    -@@ -1232,8 +1243,9 @@
    -     <string name="vpn_text_long" msgid="4907843483284977618">"Đã kết nối với <xliff:g id="SESSION">%s</xliff:g>. Chạm để quản lý mạng."</string>
    -     <string name="vpn_lockdown_connecting" msgid="6443438964440960745">"Đang kết nối VPN luôn bật…"</string>
    -     <string name="vpn_lockdown_connected" msgid="8202679674819213931">"Đã kết nối VPN luôn bật"</string>
    -+    <string name="vpn_lockdown_disconnected" msgid="4532298952570796327">"Đã ngắt kết nối VPN luôn bật"</string>
    -     <string name="vpn_lockdown_error" msgid="6009249814034708175">"Lỗi VPN luôn bật"</string>
    --    <string name="vpn_lockdown_config" msgid="4655589351146766608">"Nhấn để định cấu hình"</string>
    -+    <string name="vpn_lockdown_config" msgid="5099330695245008680">"Nhấn để thiết lập"</string>
    -     <string name="upload_file" msgid="2897957172366730416">"Chọn tệp"</string>
    -     <string name="no_file_chosen" msgid="6363648562170759465">"Không có tệp nào được chọn"</string>
    -     <string name="reset" msgid="2448168080964209908">"Đặt lại"</string>
    -@@ -1317,7 +1329,7 @@
    -     <string name="storage_usb_drive_label" msgid="4501418548927759953">"Ổ USB <xliff:g id="MANUFACTURER">%s</xliff:g>"</string>
    -     <string name="storage_usb" msgid="3017954059538517278">"Bộ lưu trữ USB"</string>
    -     <string name="extract_edit_menu_button" msgid="8940478730496610137">"Chỉnh sửa"</string>
    --    <string name="data_usage_warning_title" msgid="1955638862122232342">"Cảnh báo sử dụng dữ liệu"</string>
    -+    <string name="data_usage_warning_title" msgid="3620440638180218181">"Thông báo về sử dụng dữ liệu"</string>
    -     <string name="data_usage_warning_body" msgid="6660692274311972007">"Nhấn để xem sử dụng và cài đặt."</string>
    -     <string name="data_usage_3g_limit_title" msgid="4361523876818447683">"Đã đạt tới giới hạn dữ liệu 2G-3G"</string>
    -     <string name="data_usage_4g_limit_title" msgid="4609566827219442376">"Đã đạt tới giới hạn dữ liệu 4G"</string>
    -@@ -1636,6 +1648,7 @@
    -     <string name="search_language_hint" msgid="7042102592055108574">"Nhập tên ngôn ngữ"</string>
    -     <string name="language_picker_section_suggested" msgid="8414489646861640885">"Ðược đề xuất"</string>
    -     <string name="language_picker_section_all" msgid="3097279199511617537">"Tất cả ngôn ngữ"</string>
    -+    <string name="region_picker_section_all" msgid="8966316787153001779">"Tất cả khu vực"</string>
    -     <string name="locale_search_menu" msgid="2560710726687249178">"Tìm kiếm"</string>
    -     <string name="work_mode_off_title" msgid="8954725060677558855">"Chế độ làm việc đang TẮT"</string>
    -     <string name="work_mode_off_message" msgid="3286169091278094476">"Cho phép hồ sơ công việc hoạt động, bao gồm ứng dụng, đồng bộ hóa trong nền và các tính năng liên quan."</string>
    -diff --git a/core/res/res/values-watch/donottranslate.xml b/core/res/res/values-watch/donottranslate.xml
    -new file mode 100644
    -index 0000000..d247ff6
    ---- /dev/null
    -+++ b/core/res/res/values-watch/donottranslate.xml
    -@@ -0,0 +1,22 @@
    -+<?xml version="1.0" encoding="utf-8"?>
    -+<!-- Copyright (C) 2016 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.
    -+-->
    -+
    -+<resources>
    -+    <!-- DO NOT TRANSLATE Spans within this text are applied to style composing regions
    -+    within an EditText widget. The text content is ignored and not used.
    -+    Note: This is @color/material_deep_teal_200, cannot use @color references here. -->
    -+    <string name="candidates_style" translatable="false"><font color="#80cbc4">candidates</font></string>
    -+ </resources>
    -diff --git a/core/res/res/values-watch/styles_material.xml b/core/res/res/values-watch/styles_material.xml
    -index f5735e6..a9f6e22 100644
    ---- a/core/res/res/values-watch/styles_material.xml
    -+++ b/core/res/res/values-watch/styles_material.xml
    -@@ -88,9 +88,4 @@ please see styles_device_defaults.xml.
    -         <item name="virtualButtonPressedDrawable">?selectableItemBackground</item>
    -         <item name="descendantFocusability">blocksDescendants</item>
    -     </style>
    --
    --    <!-- DO NOTE TRANSLATE Spans within this text are applied to style composing regions
    --    within an EditText widget. The text content is ignored and not used.
    --    Note: This is @color/material_deep_teal_200, cannot use @color references here. -->
    --    <string name="candidates_style"><font color="#80cbc4">candidates</font></string>
    - </resources>
    -diff --git a/core/res/res/values-zh-rCN/strings.xml b/core/res/res/values-zh-rCN/strings.xml
    -index 8116ec0..98ae54c 100644
    ---- a/core/res/res/values-zh-rCN/strings.xml
    -+++ b/core/res/res/values-zh-rCN/strings.xml
    -@@ -195,7 +195,7 @@
    -     <string name="silent_mode_ring" msgid="8592241816194074353">"振铃器开启"</string>
    -     <string name="reboot_to_update_title" msgid="6212636802536823850">"Android 系统更新"</string>
    -     <string name="reboot_to_update_prepare" msgid="6305853831955310890">"正在准备更新…"</string>
    --    <string name="reboot_to_update_package" msgid="3871302324500927291">"正在处理更新文件包…"</string>
    -+    <string name="reboot_to_update_package" msgid="3871302324500927291">"正在处理更新软件包…"</string>
    -     <string name="reboot_to_update_reboot" msgid="6428441000951565185">"正在重新启动…"</string>
    -     <string name="reboot_to_reset_title" msgid="4142355915340627490">"恢复出厂设置"</string>
    -     <string name="reboot_to_reset_message" msgid="2432077491101416345">"正在重新启动…"</string>
    -@@ -214,6 +214,7 @@
    -     <string name="global_actions" product="default" msgid="2406416831541615258">"手机选项"</string>
    -     <string name="global_action_lock" msgid="2844945191792119712">"屏幕锁定"</string>
    -     <string name="global_action_power_off" msgid="4471879440839879722">"关机"</string>
    -+    <string name="global_action_emergency" msgid="7112311161137421166">"紧急呼救"</string>
    -     <string name="global_action_bug_report" msgid="7934010578922304799">"错误报告"</string>
    -     <string name="bugreport_title" msgid="2667494803742548533">"提交错误报告"</string>
    -     <string name="bugreport_message" msgid="398447048750350456">"这会收集有关当前设备状态的信息,并以电子邮件的形式进行发送。从开始生成错误报告到准备好发送需要一点时间,请耐心等待。"</string>
    -@@ -1076,6 +1077,17 @@
    -     <skip />
    -     <string name="wifi_no_internet" msgid="8451173622563841546">"此 WLAN 网络无法访问互联网"</string>
    -     <string name="wifi_no_internet_detailed" msgid="8083079241212301741">"点按即可查看相关选项"</string>
    -+    <string name="network_switch_metered" msgid="4671730921726992671">"已切换至<xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
    -+    <string name="network_switch_metered_detail" msgid="5325661434777870353">"设备会在无法连接到<xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g>时使用<xliff:g id="NEW_NETWORK">%1$s</xliff:g>(可能需要支付相应的费用)。"</string>
    -+    <string name="network_switch_metered_toast" msgid="5779283181685974304">"已从<xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g>切换至<xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
    -+  <string-array name="network_switch_type_name">
    -+    <item msgid="2952042958050315394">"移动数据网络"</item>
    -+    <item msgid="75483255295529161">"WLAN"</item>
    -+    <item msgid="6862614801537202646">"蓝牙"</item>
    -+    <item msgid="5447331121797802871">"以太网"</item>
    -+    <item msgid="8257233890381651999">"VPN"</item>
    -+  </string-array>
    -+    <string name="network_switch_type_name_unknown" msgid="4552612897806660656">"未知网络类型"</string>
    -     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"无法连接到WLAN"</string>
    -     <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" 互联网连接状况不佳。"</string>
    -     <string name="wifi_connect_alert_title" msgid="8455846016001810172">"要允许连接吗?"</string>
    -@@ -1153,7 +1165,6 @@
    -     <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"点按即可选择语言和布局"</string>
    -     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
    -     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
    --    <string name="candidates_style" msgid="4333913089637062257"><u>"候选"</u></string>
    -     <string name="ext_media_checking_notification_title" msgid="5734005953288045806">"正在准备<xliff:g id="NAME">%s</xliff:g>"</string>
    -     <string name="ext_media_checking_notification_message" msgid="4747432538578886744">"检查是否有错误"</string>
    -     <string name="ext_media_new_notification_message" msgid="7589986898808506239">"检测到新的<xliff:g id="NAME">%s</xliff:g>"</string>
    -@@ -1232,8 +1243,9 @@
    -     <string name="vpn_text_long" msgid="4907843483284977618">"已连接到<xliff:g id="SESSION">%s</xliff:g>。点按即可管理网络。"</string>
    -     <string name="vpn_lockdown_connecting" msgid="6443438964440960745">"正在连接到始终开启的 VPN…"</string>
    -     <string name="vpn_lockdown_connected" msgid="8202679674819213931">"已连接到始终开启的 VPN"</string>
    -+    <string name="vpn_lockdown_disconnected" msgid="4532298952570796327">"始终开启的 VPN 已断开连接"</string>
    -     <string name="vpn_lockdown_error" msgid="6009249814034708175">"始终开启的 VPN 出现错误"</string>
    --    <string name="vpn_lockdown_config" msgid="4655589351146766608">"点按即可进行配置"</string>
    -+    <string name="vpn_lockdown_config" msgid="5099330695245008680">"点按即可进行设置"</string>
    -     <string name="upload_file" msgid="2897957172366730416">"选择文件"</string>
    -     <string name="no_file_chosen" msgid="6363648562170759465">"未选定任何文件"</string>
    -     <string name="reset" msgid="2448168080964209908">"重置"</string>
    -@@ -1317,7 +1329,7 @@
    -     <string name="storage_usb_drive_label" msgid="4501418548927759953">"<xliff:g id="MANUFACTURER">%s</xliff:g> U 盘"</string>
    -     <string name="storage_usb" msgid="3017954059538517278">"USB存储器"</string>
    -     <string name="extract_edit_menu_button" msgid="8940478730496610137">"修改"</string>
    --    <string name="data_usage_warning_title" msgid="1955638862122232342">"流量警告"</string>
    -+    <string name="data_usage_warning_title" msgid="3620440638180218181">"流量消耗提醒"</string>
    -     <string name="data_usage_warning_body" msgid="6660692274311972007">"点按即可查看使用情况和设置。"</string>
    -     <string name="data_usage_3g_limit_title" msgid="4361523876818447683">"已达到2G-3G流量上限"</string>
    -     <string name="data_usage_4g_limit_title" msgid="4609566827219442376">"已达到4G流量上限"</string>
    -@@ -1636,6 +1648,7 @@
    -     <string name="search_language_hint" msgid="7042102592055108574">"输入语言名称"</string>
    -     <string name="language_picker_section_suggested" msgid="8414489646861640885">"建议语言"</string>
    -     <string name="language_picker_section_all" msgid="3097279199511617537">"所有语言"</string>
    -+    <string name="region_picker_section_all" msgid="8966316787153001779">"所有国家/地区"</string>
    -     <string name="locale_search_menu" msgid="2560710726687249178">"搜索"</string>
    -     <string name="work_mode_off_title" msgid="8954725060677558855">"工作模式已关闭"</string>
    -     <string name="work_mode_off_message" msgid="3286169091278094476">"启用工作资料,包括应用、后台同步和相关功能。"</string>
    -diff --git a/core/res/res/values-zh-rHK/strings.xml b/core/res/res/values-zh-rHK/strings.xml
    -index ef12eea..8e034a7 100644
    ---- a/core/res/res/values-zh-rHK/strings.xml
    -+++ b/core/res/res/values-zh-rHK/strings.xml
    -@@ -214,6 +214,7 @@
    -     <string name="global_actions" product="default" msgid="2406416831541615258">"手機選項"</string>
    -     <string name="global_action_lock" msgid="2844945191792119712">"螢幕鎖定"</string>
    -     <string name="global_action_power_off" msgid="4471879440839879722">"關閉"</string>
    -+    <string name="global_action_emergency" msgid="7112311161137421166">"緊急"</string>
    -     <string name="global_action_bug_report" msgid="7934010578922304799">"錯誤報告"</string>
    -     <string name="bugreport_title" msgid="2667494803742548533">"取得錯誤報告"</string>
    -     <string name="bugreport_message" msgid="398447048750350456">"這會收集您目前裝置狀態的相關資訊,並以電郵傳送給您。從開始建立錯誤報告到準備傳送需要一段時間,請耐心等候。"</string>
    -@@ -1076,6 +1077,17 @@
    -     <skip />
    -     <string name="wifi_no_internet" msgid="8451173622563841546">"Wi-Fi 並未連接互聯網"</string>
    -     <string name="wifi_no_internet_detailed" msgid="8083079241212301741">"輕按即可查看選項"</string>
    -+    <string name="network_switch_metered" msgid="4671730921726992671">"已切換至<xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
    -+    <string name="network_switch_metered_detail" msgid="5325661434777870353">"當<xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g>無法連線至互聯網時,裝置便會切換至<xliff:g id="NEW_NETWORK">%1$s</xliff:g>。可能需要支付額外費用。"</string>
    -+    <string name="network_switch_metered_toast" msgid="5779283181685974304">"已從<xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g>切換至<xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
    -+  <string-array name="network_switch_type_name">
    -+    <item msgid="2952042958050315394">"流動數據"</item>
    -+    <item msgid="75483255295529161">"Wi-Fi"</item>
    -+    <item msgid="6862614801537202646">"藍牙"</item>
    -+    <item msgid="5447331121797802871">"以太網"</item>
    -+    <item msgid="8257233890381651999">"VPN"</item>
    -+  </string-array>
    -+    <string name="network_switch_type_name_unknown" msgid="4552612897806660656">"不明網絡類型"</string>
    -     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"無法連線至 Wi-Fi"</string>
    -     <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" 互聯網連線欠佳。"</string>
    -     <string name="wifi_connect_alert_title" msgid="8455846016001810172">"允許連線?"</string>
    -@@ -1153,7 +1165,6 @@
    -     <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"輕按即可選取語言和鍵盤配置"</string>
    -     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
    -     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
    --    <string name="candidates_style" msgid="4333913089637062257"><u>"待選項目"</u></string>
    -     <string name="ext_media_checking_notification_title" msgid="5734005953288045806">"正在準備<xliff:g id="NAME">%s</xliff:g>"</string>
    -     <string name="ext_media_checking_notification_message" msgid="4747432538578886744">"正在檢查錯誤"</string>
    -     <string name="ext_media_new_notification_message" msgid="7589986898808506239">"已偵測到新<xliff:g id="NAME">%s</xliff:g>"</string>
    -@@ -1232,8 +1243,9 @@
    -     <string name="vpn_text_long" msgid="4907843483284977618">"已連線至 <xliff:g id="SESSION">%s</xliff:g>,輕按一下即可管理網絡。"</string>
    -     <string name="vpn_lockdown_connecting" msgid="6443438964440960745">"正在連線至永久連線的 VPN…"</string>
    -     <string name="vpn_lockdown_connected" msgid="8202679674819213931">"已連線至永久連線的 VPN"</string>
    -+    <string name="vpn_lockdown_disconnected" msgid="4532298952570796327">"永久連線的 VPN 已中斷"</string>
    -     <string name="vpn_lockdown_error" msgid="6009249814034708175">"永久連線的 VPN 發生錯誤"</string>
    --    <string name="vpn_lockdown_config" msgid="4655589351146766608">"輕觸即可設定"</string>
    -+    <string name="vpn_lockdown_config" msgid="5099330695245008680">"輕按即可設定"</string>
    -     <string name="upload_file" msgid="2897957172366730416">"選擇檔案"</string>
    -     <string name="no_file_chosen" msgid="6363648562170759465">"未選擇檔案"</string>
    -     <string name="reset" msgid="2448168080964209908">"重設"</string>
    -@@ -1317,7 +1329,7 @@
    -     <string name="storage_usb_drive_label" msgid="4501418548927759953">"<xliff:g id="MANUFACTURER">%s</xliff:g> USB 驅動器"</string>
    -     <string name="storage_usb" msgid="3017954059538517278">"USB 儲存裝置"</string>
    -     <string name="extract_edit_menu_button" msgid="8940478730496610137">"編輯"</string>
    --    <string name="data_usage_warning_title" msgid="1955638862122232342">"資料用量警告"</string>
    -+    <string name="data_usage_warning_title" msgid="3620440638180218181">"數據用量警告"</string>
    -     <string name="data_usage_warning_body" msgid="6660692274311972007">"輕按即可查看用量和設定。"</string>
    -     <string name="data_usage_3g_limit_title" msgid="4361523876818447683">"已達到 2G-3G 數據流量上限"</string>
    -     <string name="data_usage_4g_limit_title" msgid="4609566827219442376">"已達到 4G 數據流量上限"</string>
    -@@ -1636,6 +1648,7 @@
    -     <string name="search_language_hint" msgid="7042102592055108574">"輸入語言名稱"</string>
    -     <string name="language_picker_section_suggested" msgid="8414489646861640885">"建議"</string>
    -     <string name="language_picker_section_all" msgid="3097279199511617537">"所有語言"</string>
    -+    <string name="region_picker_section_all" msgid="8966316787153001779">"所有國家/地區"</string>
    -     <string name="locale_search_menu" msgid="2560710726687249178">"搜尋"</string>
    -     <string name="work_mode_off_title" msgid="8954725060677558855">"工作模式已關閉"</string>
    -     <string name="work_mode_off_message" msgid="3286169091278094476">"允許使用應用程式、背景同步及相關功能的工作設定檔。"</string>
    -diff --git a/core/res/res/values-zh-rTW/strings.xml b/core/res/res/values-zh-rTW/strings.xml
    -index 84e2c2c..82b4f6d 100644
    ---- a/core/res/res/values-zh-rTW/strings.xml
    -+++ b/core/res/res/values-zh-rTW/strings.xml
    -@@ -214,6 +214,7 @@
    -     <string name="global_actions" product="default" msgid="2406416831541615258">"電話選項"</string>
    -     <string name="global_action_lock" msgid="2844945191792119712">"螢幕鎖定"</string>
    -     <string name="global_action_power_off" msgid="4471879440839879722">"關機"</string>
    -+    <string name="global_action_emergency" msgid="7112311161137421166">"緊急電話"</string>
    -     <string name="global_action_bug_report" msgid="7934010578922304799">"錯誤報告"</string>
    -     <string name="bugreport_title" msgid="2667494803742548533">"取得錯誤報告"</string>
    -     <string name="bugreport_message" msgid="398447048750350456">"這會收集您目前裝置狀態的相關資訊,以便透過電子郵件傳送。從錯誤報告開始建立到準備傳送的這段過程可能需要一點時間,敬請耐心等候。"</string>
    -@@ -1076,6 +1077,17 @@
    -     <skip />
    -     <string name="wifi_no_internet" msgid="8451173622563841546">"Wi-Fi 網路沒有網際網路連線"</string>
    -     <string name="wifi_no_internet_detailed" msgid="8083079241212301741">"輕觸即可查看選項"</string>
    -+    <string name="network_switch_metered" msgid="4671730921726992671">"已切換至<xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
    -+    <string name="network_switch_metered_detail" msgid="5325661434777870353">"裝置會在無法連上 <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> 時切換至<xliff:g id="NEW_NETWORK">%1$s</xliff:g> (可能需要支付相關費用)。"</string>
    -+    <string name="network_switch_metered_toast" msgid="5779283181685974304">"已從 <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> 切換至<xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
    -+  <string-array name="network_switch_type_name">
    -+    <item msgid="2952042958050315394">"行動數據"</item>
    -+    <item msgid="75483255295529161">"Wi-Fi"</item>
    -+    <item msgid="6862614801537202646">"藍牙"</item>
    -+    <item msgid="5447331121797802871">"乙太網路"</item>
    -+    <item msgid="8257233890381651999">"VPN"</item>
    -+  </string-array>
    -+    <string name="network_switch_type_name_unknown" msgid="4552612897806660656">"不明的網路類型"</string>
    -     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"無法連線至 Wi-Fi"</string>
    -     <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" 的網際網路連線狀況不佳。"</string>
    -     <string name="wifi_connect_alert_title" msgid="8455846016001810172">"允許連線?"</string>
    -@@ -1153,7 +1165,6 @@
    -     <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"輕觸即可選取語言和版面配置"</string>
    -     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
    -     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
    --    <string name="candidates_style" msgid="4333913089637062257"><u>"待選項目"</u></string>
    -     <string name="ext_media_checking_notification_title" msgid="5734005953288045806">"正在準備「<xliff:g id="NAME">%s</xliff:g>」"</string>
    -     <string name="ext_media_checking_notification_message" msgid="4747432538578886744">"正在檢查錯誤"</string>
    -     <string name="ext_media_new_notification_message" msgid="7589986898808506239">"偵測到新的「<xliff:g id="NAME">%s</xliff:g>」"</string>
    -@@ -1232,8 +1243,9 @@
    -     <string name="vpn_text_long" msgid="4907843483284977618">"已連線至 <xliff:g id="SESSION">%s</xliff:g>,輕觸一下即可管理網路。"</string>
    -     <string name="vpn_lockdown_connecting" msgid="6443438964440960745">"正在連線至永久連線的 VPN…"</string>
    -     <string name="vpn_lockdown_connected" msgid="8202679674819213931">"已連線至永久連線的 VPN"</string>
    -+    <string name="vpn_lockdown_disconnected" msgid="4532298952570796327">"永久連線的 VPN 已中斷連線"</string>
    -     <string name="vpn_lockdown_error" msgid="6009249814034708175">"永久連線的 VPN 發生錯誤"</string>
    --    <string name="vpn_lockdown_config" msgid="4655589351146766608">"輕觸即可進行設定"</string>
    -+    <string name="vpn_lockdown_config" msgid="5099330695245008680">"輕觸即可進行設定"</string>
    -     <string name="upload_file" msgid="2897957172366730416">"選擇檔案"</string>
    -     <string name="no_file_chosen" msgid="6363648562170759465">"未選擇任何檔案"</string>
    -     <string name="reset" msgid="2448168080964209908">"重設"</string>
    -@@ -1317,7 +1329,7 @@
    -     <string name="storage_usb_drive_label" msgid="4501418548927759953">"<xliff:g id="MANUFACTURER">%s</xliff:g> USB 隨身碟"</string>
    -     <string name="storage_usb" msgid="3017954059538517278">"USB 儲存裝置"</string>
    -     <string name="extract_edit_menu_button" msgid="8940478730496610137">"編輯"</string>
    --    <string name="data_usage_warning_title" msgid="1955638862122232342">"數據用量警告"</string>
    -+    <string name="data_usage_warning_title" msgid="3620440638180218181">"數據用量警告"</string>
    -     <string name="data_usage_warning_body" msgid="6660692274311972007">"輕觸即可查看用量和設定。"</string>
    -     <string name="data_usage_3g_limit_title" msgid="4361523876818447683">"已達到 2G-3G 數據流量上限"</string>
    -     <string name="data_usage_4g_limit_title" msgid="4609566827219442376">"已達到 4G 數據流量上限"</string>
    -@@ -1636,6 +1648,7 @@
    -     <string name="search_language_hint" msgid="7042102592055108574">"請輸入語言名稱"</string>
    -     <string name="language_picker_section_suggested" msgid="8414489646861640885">"建議語言"</string>
    -     <string name="language_picker_section_all" msgid="3097279199511617537">"所有語言"</string>
    -+    <string name="region_picker_section_all" msgid="8966316787153001779">"所有地區"</string>
    -     <string name="locale_search_menu" msgid="2560710726687249178">"搜尋"</string>
    -     <string name="work_mode_off_title" msgid="8954725060677558855">"Work 模式已關閉"</string>
    -     <string name="work_mode_off_message" msgid="3286169091278094476">"啟用 Work 設定檔,包括應用程式、背景同步處理和相關功能。"</string>
    -diff --git a/core/res/res/values-zu/strings.xml b/core/res/res/values-zu/strings.xml
    -index 0c7af8d..20dfcc0 100644
    ---- a/core/res/res/values-zu/strings.xml
    -+++ b/core/res/res/values-zu/strings.xml
    -@@ -214,6 +214,7 @@
    -     <string name="global_actions" product="default" msgid="2406416831541615258">"Okukhethwa kukho kwefoni"</string>
    -     <string name="global_action_lock" msgid="2844945191792119712">"Ukuvala isikrini"</string>
    -     <string name="global_action_power_off" msgid="4471879440839879722">"Vala amandla"</string>
    -+    <string name="global_action_emergency" msgid="7112311161137421166">"Isimo esiphuthumayo"</string>
    -     <string name="global_action_bug_report" msgid="7934010578922304799">"Umbiko wephutha"</string>
    -     <string name="bugreport_title" msgid="2667494803742548533">"Thatha umbiko wesiphazamiso"</string>
    -     <string name="bugreport_message" msgid="398447048750350456">"Lokhu kuzoqoqa ulwazi mayelana nesimo samanje sedivayisi yakho, ukuthumela imilayezo ye-imeyili. Kuzothatha isikhathi esincane kusuka ekuqaleni umbiko wesiphazamiso uze ulungele ukuthunyelwa; sicela ubekezele."</string>
    -@@ -1076,6 +1077,17 @@
    -     <skip />
    -     <string name="wifi_no_internet" msgid="8451173622563841546">"I-Wi-Fi ayinakho ukufinyelela kwe-inthanethi"</string>
    -     <string name="wifi_no_internet_detailed" msgid="8083079241212301741">"Thepha ukuze uthole izinketho"</string>
    -+    <string name="network_switch_metered" msgid="4671730921726992671">"Kushintshelwe ku-<xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
    -+    <string name="network_switch_metered_detail" msgid="5325661434777870353">"Idivayisi isebenzisa i-<xliff:g id="NEW_NETWORK">%1$s</xliff:g> uma i-<xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> ingenakho ukufinyelela kwe-inthanethi. Izindleko zingasebenza."</string>
    -+    <string name="network_switch_metered_toast" msgid="5779283181685974304">"Kushintshelewe kusuka ku-<xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> kuya ku-<xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
    -+  <string-array name="network_switch_type_name">
    -+    <item msgid="2952042958050315394">"idatha yeselula"</item>
    -+    <item msgid="75483255295529161">"I-Wi-Fi"</item>
    -+    <item msgid="6862614801537202646">"I-Bluetooth"</item>
    -+    <item msgid="5447331121797802871">"I-Ethernet"</item>
    -+    <item msgid="8257233890381651999">"I-VPN"</item>
    -+  </string-array>
    -+    <string name="network_switch_type_name_unknown" msgid="4552612897806660656">"uhlobo olungaziwa lwenethiwekhi"</string>
    -     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Ayikwazanga ukuxhuma kwi-Wi-Fi"</string>
    -     <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" inoxhumano oluphansi lwe-inthanethi."</string>
    -     <string name="wifi_connect_alert_title" msgid="8455846016001810172">"Vumela ukuxhumeka?"</string>
    -@@ -1153,7 +1165,6 @@
    -     <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"Thepha ukuze ukhethe ulimi nesakhiwo"</string>
    -     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
    -     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
    --    <string name="candidates_style" msgid="4333913089637062257"><u>"abahlanganyeli"</u></string>
    -     <string name="ext_media_checking_notification_title" msgid="5734005953288045806">"Ilungiselela i-<xliff:g id="NAME">%s</xliff:g>"</string>
    -     <string name="ext_media_checking_notification_message" msgid="4747432538578886744">"Ihlolela amaphutha"</string>
    -     <string name="ext_media_new_notification_message" msgid="7589986898808506239">"I-<xliff:g id="NAME">%s</xliff:g> entsha itholiwe"</string>
    -@@ -1232,8 +1243,9 @@
    -     <string name="vpn_text_long" msgid="4907843483284977618">"Ixhume ku-<xliff:g id="SESSION">%s</xliff:g>. Thepha ukuphatha inethiwekhi."</string>
    -     <string name="vpn_lockdown_connecting" msgid="6443438964440960745">"I-VPN ehlala ikhanya iyaxhuma…"</string>
    -     <string name="vpn_lockdown_connected" msgid="8202679674819213931">"I-VPN ehlala ikhanya ixhunyiwe"</string>
    -+    <string name="vpn_lockdown_disconnected" msgid="4532298952570796327">"Njalo kuvuliwe i-VPN kunqamukile"</string>
    -     <string name="vpn_lockdown_error" msgid="6009249814034708175">"Iphutha le-VPN ehlala ikhanya"</string>
    --    <string name="vpn_lockdown_config" msgid="4655589351146766608">"Thinta ukuze umise"</string>
    -+    <string name="vpn_lockdown_config" msgid="5099330695245008680">"Thepha ukuze usethe"</string>
    -     <string name="upload_file" msgid="2897957172366730416">"Khetha ifayela"</string>
    -     <string name="no_file_chosen" msgid="6363648562170759465">"Ayikho ifayela ekhethiwe"</string>
    -     <string name="reset" msgid="2448168080964209908">"Setha kabusha"</string>
    -@@ -1317,7 +1329,7 @@
    -     <string name="storage_usb_drive_label" msgid="4501418548927759953">"<xliff:g id="MANUFACTURER">%s</xliff:g> idrayivu ye-USB"</string>
    -     <string name="storage_usb" msgid="3017954059538517278">"Isitoreji se-USB"</string>
    -     <string name="extract_edit_menu_button" msgid="8940478730496610137">"Hlela"</string>
    --    <string name="data_usage_warning_title" msgid="1955638862122232342">"Isexwayiso sokusetshenziswa kwedatha"</string>
    -+    <string name="data_usage_warning_title" msgid="3620440638180218181">"Izexwayiso zokusetshenziswa kwedatha"</string>
    -     <string name="data_usage_warning_body" msgid="6660692274311972007">"Thepha ukuze ubuke ukusetshenziswa nezilungiselelo."</string>
    -     <string name="data_usage_3g_limit_title" msgid="4361523876818447683">"2G-3G umkhawulo wedatha ufinyelelwe"</string>
    -     <string name="data_usage_4g_limit_title" msgid="4609566827219442376">"4G umkhawulo wedatha ufinyelelwe"</string>
    -@@ -1636,6 +1648,7 @@
    -     <string name="search_language_hint" msgid="7042102592055108574">"Thayipha igama lolimi"</string>
    -     <string name="language_picker_section_suggested" msgid="8414489646861640885">"Okuphakanyisiwe"</string>
    -     <string name="language_picker_section_all" msgid="3097279199511617537">"Zonke izilimi"</string>
    -+    <string name="region_picker_section_all" msgid="8966316787153001779">"Zonke izifunda"</string>
    -     <string name="locale_search_menu" msgid="2560710726687249178">"Sesha"</string>
    -     <string name="work_mode_off_title" msgid="8954725060677558855">"Imodi yomsebenzi IVALIWE"</string>
    -     <string name="work_mode_off_message" msgid="3286169091278094476">"Vumela iphrofayela yomsebenzi ukuze isebenze, efaka izinhlelo zokusebenza, ukuvumelanisa kwangemuva, nezici ezisondelene."</string>
    -diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
    -index 48e4201..30a1a28 100644
    ---- a/core/res/res/values/attrs.xml
    -+++ b/core/res/res/values/attrs.xml
    -@@ -4839,6 +4839,11 @@ i
    -         <!-- The list year's selected circle color in the list.
    -              {@deprecated No longer displayed.} -->
    -         <attr name="yearListSelectorColor" format="color" />
    -+
    -+        <!-- @hide Whether this time picker is being displayed within a dialog,
    -+             in which case it may ignore the requested time picker mode due to
    -+             space considerations. -->
    -+        <attr name="dialogMode" format="boolean" />
    -     </declare-styleable>
    - 
    -     <declare-styleable name="TwoLineListItem">
    -@@ -5167,6 +5172,11 @@ i
    -         <!-- The background color state list for the AM/PM selectors.
    -              {@deprecated Use headerBackground instead.}-->
    -         <attr name="amPmBackgroundColor" format="color" />
    -+
    -+        <!-- @hide Whether this time picker is being displayed within a dialog,
    -+             in which case it may ignore the requested time picker mode due to
    -+             space considerations. -->
    -+        <attr name="dialogMode" />
    -     </declare-styleable>
    - 
    -     <!-- ========================= -->
    -@@ -5313,6 +5323,21 @@ i
    -         <attr name="alpha" />
    -     </declare-styleable>
    - 
    -+    <!-- Drawable used to render according to the animation scale. Esp. when it is 0 due to battery
    -+         saver mode. It should contain one animatable drawable and one static drawable.
    -+         @hide -->
    -+    <declare-styleable name="AnimationScaleListDrawable">
    -+    </declare-styleable>
    -+
    -+    <!-- Attributes that can be assigned to a AnimationScaleListDrawable item.
    -+         @hide -->
    -+    <declare-styleable name="AnimationScaleListDrawableItem">
    -+        <!-- Reference to a drawable resource to use for the state. If not
    -+             given, the drawable must be defined by the first child tag. -->
    -+        <attr name="drawable" />
    -+    </declare-styleable>
    -+
    -+
    -     <!-- Drawable used to render a geometric shape, with a gradient or a solid color. -->
    -     <declare-styleable name="GradientDrawable">
    -         <!-- Indicates whether the drawable should intially be visible. -->
    -@@ -5342,7 +5367,10 @@ i
    -         <attr name="innerRadius" format="dimension" />
    -         <!-- Thickness of the ring. When defined, thicknessRatio is ignored. -->
    -         <attr name="thickness" format="dimension" />
    --        <!-- Indicates whether the drawable's level affects the way the gradient is drawn. -->
    -+        <!-- Whether the drawable level value (see
    -+             {@link android.graphics.drawable.Drawable#getLevel()}) is used to scale the shape.
    -+             Scaling behavior depends on the shape type. For "ring", the angle is scaled from 0 to
    -+             360. For all other types, there is no effect. The default value is true. -->
    -         <attr name="useLevel" />
    -         <!-- If set, specifies the color to apply to the drawable as a tint. By default,
    -              no tint is applied. May be a color state list. -->
    -@@ -5376,28 +5404,37 @@ i
    -     <declare-styleable name="GradientDrawableGradient">
    -         <!-- Start color of the gradient. -->
    -         <attr name="startColor" format="color" />
    --        <!-- Optional center color. For linear gradients, use centerX or centerY
    --             to place the center color. -->
    -+        <!-- Optional center color. For linear gradients, use centerX or centerY to place the center
    -+             color. -->
    -         <attr name="centerColor" format="color" />
    -         <!-- End color of the gradient. -->
    -         <attr name="endColor" format="color" />
    -+        <!-- Whether the drawable level value (see
    -+             {@link android.graphics.drawable.Drawable#getLevel()}) is used to scale the gradient.
    -+             Scaling behavior varies based on gradient type. For "linear", adjusts the ending
    -+             position along the gradient's axis of orientation. For "radial", adjusts the outer
    -+             radius. For "sweep", adjusts the ending angle. The default value is false. -->
    -         <attr name="useLevel" format="boolean" />
    --        <!-- Angle of the gradient. -->
    -+        <!-- Angle of the gradient, used only with linear gradient. Must be a multiple of 45 in the
    -+             range [0, 315]. -->
    -         <attr name="angle" format="float" />
    -         <!-- Type of gradient. The default type is linear. -->
    -         <attr name="type">
    --            <!-- Linear gradient. -->
    -+            <!-- Linear gradient extending across the center point. -->
    -             <enum name="linear" value="0" />
    --            <!-- Radial, or circular, gradient. -->
    -+            <!-- Radial gradient extending from the center point outward. -->
    -             <enum name="radial" value="1" />
    --            <!-- Sweep, or angled or diamond, gradient. -->
    -+            <!-- Sweep (or angular) gradient sweeping counter-clockwise around the center point. -->
    -             <enum name="sweep"  value="2" />
    -         </attr>
    --        <!-- X coordinate of the origin of the gradient within the shape. -->
    -+        <!-- X-position of the center point of the gradient within the shape as a fraction of the
    -+             width. The default value is 0.5. -->
    -         <attr name="centerX" format="float|fraction" />
    --        <!-- Y coordinate of the origin of the gradient within the shape. -->
    -+        <!-- Y-position of the center point of the gradient within the shape as a fraction of the
    -+             height. The default value is 0.5. -->
    -         <attr name="centerY" format="float|fraction" />
    --        <!-- Radius of the gradient, used only with radial gradient. -->
    -+        <!-- Radius of the gradient, used only with radial gradient. May be an explicit dimension
    -+             or a fractional value relative to the shape's minimum dimension. -->
    -         <attr name="gradientRadius" format="float|fraction|dimension" />
    -     </declare-styleable>
    - 
    -diff --git a/core/res/res/values/colors_material.xml b/core/res/res/values/colors_material.xml
    -index a864cf3..92426c6 100644
    ---- a/core/res/res/values/colors_material.xml
    -+++ b/core/res/res/values/colors_material.xml
    -@@ -61,7 +61,10 @@
    -     <color name="secondary_text_default_material_dark">#b3ffffff</color>
    - 
    -     <item name="hint_alpha_material_dark" format="float" type="dimen">0.50</item>
    --    <item name="hint_alpha_material_light" format="float" type="dimen">0.54</item>
    -+    <item name="hint_alpha_material_light" format="float" type="dimen">0.38</item>
    -+
    -+    <item name="hint_pressed_alpha_material_dark" format="float" type="dimen">0.70</item>
    -+    <item name="hint_pressed_alpha_material_light" format="float" type="dimen">0.54</item>
    - 
    -     <item name="disabled_alpha_material_light" format="float" type="dimen">0.26</item>
    -     <item name="disabled_alpha_material_dark" format="float" type="dimen">0.30</item>
    -diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
    -index 3dbcdaf..ae8edab 100644
    ---- a/core/res/res/values/config.xml
    -+++ b/core/res/res/values/config.xml
    -@@ -1661,6 +1661,12 @@
    -          turned off and the screen off animation has been performed. -->
    -     <bool name="config_dozeAfterScreenOff">false</bool>
    - 
    -+    <!-- Doze: should the TYPE_PICK_UP_GESTURE sensor be used as a pulse signal. -->
    -+    <bool name="config_dozePulsePickup">false</bool>
    -+
    -+    <!-- Type of the double tap sensor. Empty if double tap is not supported. -->
    -+    <string name="config_dozeDoubleTapSensorType" translatable="false"></string>
    -+
    -     <!-- Power Management: Specifies whether to decouple the auto-suspend state of the
    -          device from the display on/off state.
    - 
    -@@ -2158,6 +2164,11 @@
    -     <!-- Flag specifying whether VT is available on device -->
    -     <bool name="config_device_vt_available">false</bool>
    - 
    -+    <!-- Flag specifying whether the device will use the "allow_hold_in_ims_call" carrier config
    -+         option.  When false, the device will support holding of IMS calls, regardless of the
    -+         carrier config setting. -->
    -+    <bool name="config_device_respects_hold_carrier_config">true</bool>
    -+
    -     <!-- Flag specifying whether VT should be available for carrier: independent of
    -          carrier provisioning. If false: hard disabled. If true: then depends on carrier
    -          provisioning, availability etc -->
    -@@ -2300,8 +2311,8 @@
    -     <!-- An array of CDMA roaming indicators which means international roaming -->
    -     <integer-array translatable="false" name="config_cdma_international_roaming_indicators" />
    - 
    --    <!-- set the system language as value of EF LI/EF PL -->
    --    <bool name="config_use_sim_language_file">true</bool>
    -+    <!-- flag to indicate if EF LI/EF PL should be used for system language -->
    -+    <bool name="config_use_sim_language_file">false</bool>
    - 
    -     <!-- Use ERI text for network name on CDMA LTE -->
    -     <bool name="config_LTE_eri_for_network_name">true</bool>
    -@@ -2521,6 +2532,16 @@
    -     <!-- True if the device supports system navigation keys. -->
    -     <bool name="config_supportSystemNavigationKeys">false</bool>
    - 
    -+    <!-- emergency call number for the emergency affordance -->
    -+    <string name="config_emergency_call_number" translatable="false">112</string>
    -+
    -+    <!-- Do not translate. Mcc codes whose existence trigger the presence of emergency
    -+         affordances-->
    -+    <integer-array name="config_emergency_mcc_codes" translatable="false">
    -+        <item>404</item>
    -+        <item>405</item>
    -+    </integer-array>
    -+
    -     <!-- Package name for the device provisioning package. -->
    -     <string name="config_deviceProvisioningPackage"></string>
    - 
    -@@ -2540,4 +2561,15 @@
    -         <!-- Verizon requires any SMS that starts with //VZWVVM to be treated as a VVM SMS-->
    -         <item>310004,310010,310012,310013,310590,310890,310910,311110,311270,311271,311272,311273,311274,311275,311276,311277,311278,311279,311280,311281,311282,311283,311284,311285,311286,311287,311288,311289,311390,311480,311481,311482,311483,311484,311485,311486,311487,311488,311489;^//VZWVVM.*</item>
    -     </string-array>
    -+    <!-- This config is holding calling number conversion map - expected to convert to emergency
    -+         number. Formats for this config as below:
    -+         <item>[dialstring1],[dialstring2],[dialstring3]:[replacement]</item>
    -+
    -+         E.g. for Taiwan Type Approval, 110 and 119 should be converted to 112.
    -+         <item>110,119:112</item>
    -+    -->
    -+    <string-array translatable="false" name="config_convert_to_emergency_number_map" />
    -+
    -+    <!-- An array of packages for which notifications cannot be blocked. -->
    -+    <string-array translatable="false" name="config_nonBlockableNotificationPackages" />
    - </resources>
    -diff --git a/core/res/res/values/donottranslate.xml b/core/res/res/values/donottranslate.xml
    -index a139529..3a1679c 100644
    ---- a/core/res/res/values/donottranslate.xml
    -+++ b/core/res/res/values/donottranslate.xml
    -@@ -26,4 +26,7 @@
    -     <string name="icu_abbrev_wday_month_day_no_year">eeeMMMMd</string>
    -     <!-- @hide DO NOT TRANSLATE. date formatting pattern for system ui.-->
    -     <string name="system_ui_date_pattern">@string/icu_abbrev_wday_month_day_no_year</string>
    -+    <!-- @hide DO NOT TRANSLATE Spans within this text are applied to style composing regions
    -+    within an EditText widget. The text content is ignored and not used. -->
    -+    <string name="candidates_style" translatable="false"><u>candidates</u></string>
    - </resources>
    -diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
    -index 9002ed4..f42c9ed 100644
    ---- a/core/res/res/values/strings.xml
    -+++ b/core/res/res/values/strings.xml
    -@@ -486,6 +486,9 @@
    -     <!-- TODO: promote to separate string-->
    -     <string name="global_action_restart" translatable="false">@string/sim_restart_button</string>
    - 
    -+    <!-- label for item that starts emergency call -->
    -+    <string name="global_action_emergency">Emergency</string>
    -+
    -     <!-- label for item that generates a bug report in the phone options dialog -->
    -     <string name="global_action_bug_report">Bug report</string>
    - 
    -@@ -3122,8 +3125,6 @@
    -     <string name="fast_scroll_alphabet">\u0020ABCDEFGHIJKLMNOPQRSTUVWXYZ</string>
    -     <string name="fast_scroll_numeric_alphabet">\u00200123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ</string>
    - 
    --    <string name="candidates_style"><u>candidates</u></string>
    --
    -     <!-- External media notification strings -->
    -     <skip />
    - 
    -@@ -3326,10 +3327,12 @@
    -     <string name="vpn_lockdown_connecting">Always-on VPN connecting\u2026</string>
    -     <!-- Notification title when connected to lockdown VPN. -->
    -     <string name="vpn_lockdown_connected">Always-on VPN connected</string>
    -+    <!-- Notification title when not connected to lockdown VPN. -->
    -+    <string name="vpn_lockdown_disconnected">Always-on VPN disconnected</string>
    -     <!-- Notification title when error connecting to lockdown VPN. -->
    -     <string name="vpn_lockdown_error">Always-on VPN error</string>
    -     <!-- Notification body that indicates user can touch to configure lockdown VPN connection. -->
    --    <string name="vpn_lockdown_config">Tap to configure</string>
    -+    <string name="vpn_lockdown_config">Tap to set up</string>
    - 
    -     <!-- Localized strings for WebView -->
    -     <!-- Label for button in a WebView that will open a chooser to choose a file to upload -->
    -@@ -3550,8 +3553,8 @@
    -     <!-- Button text for the edit menu in input method extract mode. [CHAR LIMIT=16] -->
    -     <string name="extract_edit_menu_button">Edit</string>
    - 
    --    <!-- Notification title when data usage has exceeded warning threshold. [CHAR LIMIT=32] -->
    --    <string name="data_usage_warning_title">Data usage warning</string>
    -+    <!-- Notification title when data usage has exceeded warning threshold. [CHAR LIMIT=50] -->
    -+    <string name="data_usage_warning_title">Data usage alert</string>
    -     <!-- Notification body when data usage has exceeded warning threshold. [CHAR LIMIT=32] -->
    -     <string name="data_usage_warning_body">Tap to view usage and settings.</string>
    - 
    -@@ -4357,6 +4360,9 @@
    -     <string name="language_picker_section_suggested">Suggested</string>
    -     <!-- List section subheader for the language picker, containing a list of all languages available [CHAR LIMIT=30] -->
    -     <string name="language_picker_section_all">All languages</string>
    -+    <!-- List section subheader for the region picker, containing a list of all regions supported for the selected language.
    -+    Warning: this is a more 'neutral' term for 'country', not for the sub-divisions of a country. [CHAR LIMIT=30] -->
    -+    <string name="region_picker_section_all">All regions</string>
    - 
    -     <!-- Menu item in the locale menu  [CHAR LIMIT=30] -->
    -     <string name="locale_search_menu">Search</string>
    -diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
    -index def40db..826161e 100644
    ---- a/core/res/res/values/symbols.xml
    -+++ b/core/res/res/values/symbols.xml
    -@@ -1459,6 +1459,7 @@
    -   <java-symbol type="anim" name="dock_top_exit" />
    -   <java-symbol type="anim" name="dock_bottom_enter" />
    -   <java-symbol type="anim" name="dock_bottom_exit" />
    -+  <java-symbol type="anim" name="dock_bottom_exit_keyguard" />
    -   <java-symbol type="anim" name="dock_left_enter" />
    -   <java-symbol type="anim" name="dock_left_exit" />
    -   <java-symbol type="anim" name="dock_right_enter" />
    -@@ -1869,6 +1870,7 @@
    -   <java-symbol type="string" name="vpn_title_long" />
    -   <java-symbol type="string" name="vpn_lockdown_connecting" />
    -   <java-symbol type="string" name="vpn_lockdown_connected" />
    -+  <java-symbol type="string" name="vpn_lockdown_disconnected" />
    -   <java-symbol type="string" name="vpn_lockdown_error" />
    -   <java-symbol type="string" name="vpn_lockdown_config" />
    -   <java-symbol type="string" name="wallpaper_binding_label" />
    -@@ -1943,6 +1945,7 @@
    -   <java-symbol type="anim" name="lock_screen_behind_enter_fade_in" />
    -   <java-symbol type="anim" name="lock_screen_wallpaper_exit" />
    -   <java-symbol type="anim" name="launch_task_behind_source" />
    -+  <java-symbol type="anim" name="wallpaper_open_exit" />
    - 
    -   <java-symbol type="bool" name="config_alwaysUseCdmaRssi" />
    -   <java-symbol type="dimen" name="status_bar_icon_size" />
    -@@ -2212,6 +2215,7 @@
    -   <java-symbol type="bool" name="config_carrier_volte_provisioned" />
    -   <java-symbol type="bool" name="config_carrier_volte_tty_supported" />
    -   <java-symbol type="bool" name="config_device_vt_available" />
    -+  <java-symbol type="bool" name="config_device_respects_hold_carrier_config" />
    -   <java-symbol type="bool" name="config_carrier_vt_available" />
    -   <java-symbol type="bool" name="config_device_wfc_ims_available" />
    -   <java-symbol type="bool" name="config_carrier_wfc_ims_available" />
    -@@ -2505,6 +2509,7 @@
    -   <java-symbol type="menu" name="language_selection_list" />
    -   <java-symbol type="string" name="country_selection_title" />
    -   <java-symbol type="string" name="language_picker_section_all" />
    -+  <java-symbol type="string" name="region_picker_section_all" />
    -   <java-symbol type="string" name="language_picker_section_suggested" />
    -   <java-symbol type="string" name="language_selection_title" />
    -   <java-symbol type="string" name="search_language_hint" />
    -@@ -2659,6 +2664,13 @@
    - 
    -   <java-symbol type="string" name="lockscreen_storage_locked" />
    - 
    -+  <java-symbol type="string" name="global_action_emergency" />
    -+  <java-symbol type="string" name="config_emergency_call_number" />
    -+  <java-symbol type="array" name="config_emergency_mcc_codes" />
    -+
    -+  <java-symbol type="string" name="config_dozeDoubleTapSensorType" />
    -+  <java-symbol type="bool" name="config_dozePulsePickup" />
    -+
    -   <!-- Used for MimeIconUtils. -->
    -   <java-symbol type="drawable" name="ic_doc_apk" />
    -   <java-symbol type="drawable" name="ic_doc_audio" />
    -@@ -2695,4 +2707,13 @@
    - 
    -   <java-symbol type="drawable" name="ic_restart" />
    - 
    -+  <java-symbol type="drawable" name="emergency_icon" />
    -+
    -+  <java-symbol type="array" name="config_convert_to_emergency_number_map" />
    -+
    -+  <java-symbol type="array" name="config_nonBlockableNotificationPackages" />
    -+
    -+  <!-- Screen-size-dependent modes for picker dialogs. -->
    -+  <java-symbol type="integer" name="time_picker_mode" />
    -+  <java-symbol type="integer" name="date_picker_mode" />
    - </resources>
    -diff --git a/core/tests/coretests/AndroidManifest.xml b/core/tests/coretests/AndroidManifest.xml
    -index 2452cfd..4416402 100644
    ---- a/core/tests/coretests/AndroidManifest.xml
    -+++ b/core/tests/coretests/AndroidManifest.xml
    -@@ -1147,6 +1147,8 @@
    -         </activity>
    -         <activity android:name="com.android.internal.policy.PhoneWindowActionModeTestActivity">
    -         </activity>
    -+        <activity android:name="android.app.EmptyActivity">
    -+        </activity>
    - 
    -         <receiver android:name="android.app.activity.AbortReceiver">
    -             <intent-filter android:priority="1">
    -diff --git a/core/tests/coretests/src/android/app/EmptyActivity.java b/core/tests/coretests/src/android/app/EmptyActivity.java
    -new file mode 100644
    -index 0000000..fefd7b7
    ---- /dev/null
    -+++ b/core/tests/coretests/src/android/app/EmptyActivity.java
    -@@ -0,0 +1,21 @@
    -+/*
    -+ * Copyright (C) 2016 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 android.app;
    -+
    -+public class EmptyActivity extends Activity {
    -+}
    -diff --git a/core/tests/coretests/src/android/app/LoaderLifecycleTest.java b/core/tests/coretests/src/android/app/LoaderLifecycleTest.java
    -new file mode 100644
    -index 0000000..1850d57
    ---- /dev/null
    -+++ b/core/tests/coretests/src/android/app/LoaderLifecycleTest.java
    -@@ -0,0 +1,228 @@
    -+/*
    -+ * Copyright (C) 2016 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 android.app;
    -+
    -+import android.content.Context;
    -+import android.os.Handler;
    -+import android.os.Parcelable;
    -+import android.support.test.filters.MediumTest;
    -+import android.support.test.rule.ActivityTestRule;
    -+import android.support.test.runner.AndroidJUnit4;
    -+import android.util.ArrayMap;
    -+import org.junit.Rule;
    -+import org.junit.Test;
    -+import org.junit.runner.RunWith;
    -+
    -+import static junit.framework.TestCase.assertNotNull;
    -+import static junit.framework.TestCase.assertNotSame;
    -+import static junit.framework.TestCase.assertSame;
    -+
    -+@RunWith(AndroidJUnit4.class)
    -+public class LoaderLifecycleTest {
    -+    @Rule
    -+    public ActivityTestRule<EmptyActivity> mActivityRule =
    -+            new ActivityTestRule<>(EmptyActivity.class);
    -+    @Test
    -+    @MediumTest
    -+    public void loaderIdentityTest() throws Throwable{
    -+        mActivityRule.runOnUiThread(() -> {
    -+            final Handler h = new Handler();
    -+            final FragmentController fc1 = FragmentController.createController(
    -+                    new TestFragmentHostCallback(mActivityRule.getActivity(), h, 0));
    -+
    -+            fc1.attachHost(null);
    -+            fc1.dispatchCreate();
    -+
    -+            final FragmentManager fm1 = fc1.getFragmentManager();
    -+
    -+            final Fragment f1 = new Fragment();
    -+            fm1.beginTransaction().add(f1, "one").commitNow();
    -+
    -+            // Removing and re-adding a fragment completely will destroy its LoaderManager.
    -+            // Keep the first one here to confirm this later.
    -+            final LoaderManager lm1 = f1.getLoaderManager();
    -+
    -+            // Remove the fragment, add a second one, and re-add the first to
    -+            // force its internal index to change. The tests below should still remain consistent.
    -+            final Fragment f2 = new Fragment();
    -+            fm1.beginTransaction().remove(f1).commitNow();
    -+            fm1.beginTransaction().add(f2, "two").commitNow();
    -+            fm1.beginTransaction().add(f1, "one").commitNow();
    -+
    -+            // We'll check this to see if we get the same instance back later
    -+            // as passed through NonConfigurationInstance. If the keys stay consistent
    -+            // across fragment remove/re-add, this will be consistent.
    -+            final LoaderManager lm12 = f1.getLoaderManager();
    -+
    -+            assertNotSame("fully removed and re-added fragment got same LoaderManager", lm1, lm12);
    -+
    -+            fc1.dispatchActivityCreated();
    -+            fc1.noteStateNotSaved();
    -+            fc1.execPendingActions();
    -+            fc1.doLoaderStart();
    -+            fc1.dispatchStart();
    -+            fc1.reportLoaderStart();
    -+            fc1.dispatchResume();
    -+            fc1.execPendingActions();
    -+
    -+            // Bring the state back down to destroyed, simulating an activity restart
    -+            fc1.dispatchPause();
    -+            final Parcelable savedState = fc1.saveAllState();
    -+            fc1.doLoaderStop(true);
    -+            fc1.dispatchStop();
    -+            final FragmentManagerNonConfig nonconf = fc1.retainNestedNonConfig();
    -+
    -+            final ArrayMap<String, LoaderManager> loaderNonConfig = fc1.retainLoaderNonConfig();
    -+            assertNotNull("loaderNonConfig was null", loaderNonConfig);
    -+
    -+            fc1.dispatchDestroy();
    -+
    -+            // Create the new controller and restore state
    -+            final FragmentController fc2 = FragmentController.createController(
    -+                    new TestFragmentHostCallback(mActivityRule.getActivity(), h, 0));
    -+
    -+            final FragmentManager fm2 = fc2.getFragmentManager();
    -+
    -+            fc2.attachHost(null);
    -+            // Make sure nothing blows up on a null here
    -+            fc2.restoreLoaderNonConfig(null);
    -+            // for real this time
    -+            fc2.restoreLoaderNonConfig(loaderNonConfig);
    -+            fc2.restoreAllState(savedState, nonconf);
    -+            fc2.dispatchCreate();
    -+
    -+
    -+            fc2.dispatchActivityCreated();
    -+            fc2.noteStateNotSaved();
    -+            fc2.execPendingActions();
    -+            fc2.doLoaderStart();
    -+            fc2.dispatchStart();
    -+            fc2.reportLoaderStart();
    -+            fc2.dispatchResume();
    -+            fc2.execPendingActions();
    -+
    -+            // Test that the fragments are in the configuration we expect
    -+            final Fragment restoredOne = fm2.findFragmentByTag("one");
    -+            final LoaderManager lm2 = restoredOne.getLoaderManager();
    -+
    -+            assertSame("didn't get same LoaderManager instance back", lm2, lm12);
    -+
    -+            // Bring the state back down to destroyed before we finish the test
    -+            fc2.dispatchPause();
    -+            fc2.saveAllState();
    -+            fc2.dispatchStop();
    -+            fc2.dispatchDestroy();
    -+        });
    -+    }
    -+
    -+    @Test
    -+    @MediumTest
    -+    public void backStackLoaderIdentityTest() throws Throwable{
    -+        mActivityRule.runOnUiThread(() -> {
    -+            final Handler h = new Handler();
    -+            final FragmentHostCallback host1 =
    -+                    new TestFragmentHostCallback(mActivityRule.getActivity(), h, 0);
    -+            final FragmentController fc1 = FragmentController.createController(host1);
    -+
    -+            fc1.attachHost(null);
    -+            fc1.dispatchCreate();
    -+
    -+            final FragmentManager fm1 = fc1.getFragmentManager();
    -+
    -+            final Fragment f1 = new Fragment();
    -+            fm1.beginTransaction().add(f1, "one").commitNow();
    -+
    -+            final LoaderManager lm1 = f1.getLoaderManager();
    -+
    -+            // Put the fragment on the back stack.
    -+            fm1.beginTransaction().remove(f1).addToBackStack("backentry").commit();
    -+            fm1.executePendingTransactions();
    -+
    -+            fc1.dispatchActivityCreated();
    -+            fc1.noteStateNotSaved();
    -+            fc1.execPendingActions();
    -+            fc1.doLoaderStart();
    -+            fc1.dispatchStart();
    -+            fc1.reportLoaderStart();
    -+            fc1.dispatchResume();
    -+            fc1.execPendingActions();
    -+
    -+            // Bring the state back down to destroyed, simulating an activity restart
    -+            fc1.dispatchPause();
    -+            final Parcelable savedState = fc1.saveAllState();
    -+            fc1.doLoaderStop(true);
    -+            fc1.dispatchStop();
    -+            final FragmentManagerNonConfig nonconf = fc1.retainNestedNonConfig();
    -+
    -+            final ArrayMap<String, LoaderManager> loaderNonConfig = fc1.retainLoaderNonConfig();
    -+            assertNotNull("loaderNonConfig was null", loaderNonConfig);
    -+
    -+            fc1.dispatchDestroy();
    -+
    -+            // Create the new controller and restore state
    -+            final FragmentHostCallback host2 =
    -+                    new TestFragmentHostCallback(mActivityRule.getActivity(), h, 0);
    -+            final FragmentController fc2 = FragmentController.createController(host2);
    -+
    -+            final FragmentManager fm2 = fc2.getFragmentManager();
    -+
    -+            fc2.attachHost(null);
    -+            fc2.restoreLoaderNonConfig(loaderNonConfig);
    -+            fc2.restoreAllState(savedState, nonconf);
    -+            fc2.dispatchCreate();
    -+
    -+
    -+            fc2.dispatchActivityCreated();
    -+            fc2.noteStateNotSaved();
    -+            fc2.execPendingActions();
    -+            fc2.doLoaderStart();
    -+            fc2.dispatchStart();
    -+            fc2.reportLoaderStart();
    -+            fc2.dispatchResume();
    -+            fc2.execPendingActions();
    -+
    -+            assertNotSame("LoaderManager kept reference to old FragmentHostCallback",
    -+                    host1, lm1.getFragmentHostCallback());
    -+            assertSame("LoaderManager did not refrence new FragmentHostCallback",
    -+                    host2, lm1.getFragmentHostCallback());
    -+
    -+            // Test that the fragments are in the configuration we expect
    -+            final Fragment restoredOne = fm2.findFragmentByTag("one");
    -+            final LoaderManager lm2 = restoredOne.getLoaderManager();
    -+
    -+            assertSame("didn't get same LoaderManager instance back", lm2, lm1);
    -+
    -+            // Bring the state back down to destroyed before we finish the test
    -+            fc2.dispatchPause();
    -+            fc2.saveAllState();
    -+            fc2.dispatchStop();
    -+            fc2.dispatchDestroy();
    -+        });
    -+    }
    -+
    -+    public class TestFragmentHostCallback extends FragmentHostCallback<LoaderLifecycleTest> {
    -+        public TestFragmentHostCallback(Context context, Handler handler, int windowAnimations) {
    -+            super(context, handler, windowAnimations);
    -+        }
    -+
    -+        @Override
    -+        public LoaderLifecycleTest onGetHost() {
    -+            return LoaderLifecycleTest.this;
    -+        }
    -+    }
    -+}
    -diff --git a/core/tests/coretests/src/android/net/NetworkStatsTest.java b/core/tests/coretests/src/android/net/NetworkStatsTest.java
    -index 9074f8a..d48a67a 100644
    ---- a/core/tests/coretests/src/android/net/NetworkStatsTest.java
    -+++ b/core/tests/coretests/src/android/net/NetworkStatsTest.java
    -@@ -454,7 +454,7 @@ public class NetworkStatsTest extends TestCase {
    -             .addValues(underlyingIface, tunUid, SET_FOREGROUND, TAG_NONE, 0L, 0L, 0L, 0L, 0L);
    - 
    -         assertTrue(delta.migrateTun(tunUid, tunIface, underlyingIface));
    --        assertEquals(21, delta.size());
    -+        assertEquals(20, delta.size());
    - 
    -         // tunIface and TEST_IFACE entries are not changed.
    -         assertValues(delta, 0, tunIface, 10100, SET_DEFAULT, TAG_NONE, ROAMING_NO,
    -@@ -478,38 +478,89 @@ public class NetworkStatsTest extends TestCase {
    - 
    -         // Existing underlying Iface entries are updated
    -         assertValues(delta, 9, underlyingIface, 10100, SET_DEFAULT, TAG_NONE, ROAMING_NO,
    --                44783L, 54L, 13829L, 60L, 0L);
    -+                44783L, 54L, 14178L, 62L, 0L);
    -         assertValues(delta, 10, underlyingIface, 10100, SET_FOREGROUND, TAG_NONE, ROAMING_NO,
    -                 0L, 0L, 0L, 0L, 0L);
    - 
    -         // VPN underlying Iface entries are updated
    -         assertValues(delta, 11, underlyingIface, tunUid, SET_DEFAULT, TAG_NONE, ROAMING_NO,
    --                28304L, 27L, 1719L, 12L, 0L);
    -+                28304L, 27L, 1L, 2L, 0L);
    -         assertValues(delta, 12, underlyingIface, tunUid, SET_FOREGROUND, TAG_NONE, ROAMING_NO,
    -                 0L, 0L, 0L, 0L, 0L);
    - 
    -         // New entries are added for new application's underlying Iface traffic
    -         assertContains(delta, underlyingIface, 10120, SET_DEFAULT, TAG_NONE, ROAMING_NO,
    --                72667L, 197L, 41872L, 219L, 0L);
    -+                72667L, 197L, 43123L, 227L, 0L);
    -         assertContains(delta, underlyingIface, 10120, SET_FOREGROUND, TAG_NONE, ROAMING_NO,
    --                9297L, 17L, 3936, 19L, 0L);
    -+                9297L, 17L, 4054, 19L, 0L);
    -         assertContains(delta, underlyingIface, 10120, SET_DEFAULT, testTag1, ROAMING_NO,
    --                21691L, 41L, 13179L, 46L, 0L);
    -+                21691L, 41L, 13572L, 48L, 0L);
    -         assertContains(delta, underlyingIface, 10120, SET_FOREGROUND, testTag1, ROAMING_NO,
    --                1281L, 2L, 634L, 1L, 0L);
    -+                1281L, 2L, 653L, 1L, 0L);
    - 
    -         // New entries are added for debug purpose
    -         assertContains(delta, underlyingIface, 10100, SET_DBG_VPN_IN, TAG_NONE, ROAMING_NO,
    --                39605L, 46L, 11690, 49, 0);
    -+                39605L, 46L, 12039, 51, 0);
    -         assertContains(delta, underlyingIface, 10120, SET_DBG_VPN_IN, TAG_NONE, ROAMING_NO,
    --                81964, 214, 45808, 238, 0);
    --        assertContains(delta, underlyingIface, tunUid, SET_DBG_VPN_IN, TAG_NONE, ROAMING_NO,
    --                4983, 10, 1717, 10, 0);
    -+                81964, 214, 47177, 246, 0);
    -         assertContains(delta, underlyingIface, tunUid, SET_DBG_VPN_OUT, TAG_NONE, ROAMING_ALL,
    --                126552, 270, 59215, 297, 0);
    -+                121569, 260, 59216, 297, 0);
    - 
    -     }
    - 
    -+    // Tests a case where all of the data received by the tun0 interface is echo back into the tun0
    -+    // interface by the vpn app before it's sent out of the underlying interface. The VPN app should
    -+    // not be charged for the echoed data but it should still be charged for any extra data it sends
    -+    // via the underlying interface.
    -+    public void testMigrateTun_VpnAsLoopback() {
    -+        final int tunUid = 10030;
    -+        final String tunIface = "tun0";
    -+        final String underlyingIface = "wlan0";
    -+        NetworkStats delta = new NetworkStats(TEST_START, 9)
    -+            // 2 different apps sent/receive data via tun0.
    -+            .addValues(tunIface, 10100, SET_DEFAULT, TAG_NONE, 50000L, 25L, 100000L, 50L, 0L)
    -+            .addValues(tunIface, 20100, SET_DEFAULT, TAG_NONE, 500L, 2L, 200L, 5L, 0L)
    -+            // VPN package resends data through the tunnel (with exaggerated overhead)
    -+            .addValues(tunIface, tunUid, SET_DEFAULT, TAG_NONE, 240000, 100L, 120000L, 60L, 0L)
    -+            // 1 app already has some traffic on the underlying interface, the other doesn't yet
    -+            .addValues(underlyingIface, 10100, SET_DEFAULT, TAG_NONE, 1000L, 10L, 2000L, 20L, 0L)
    -+            // Traffic through the underlying interface via the vpn app.
    -+            // This test should redistribute this data correctly.
    -+            .addValues(underlyingIface, tunUid, SET_DEFAULT, TAG_NONE,
    -+                    75500L, 37L, 130000L, 70L, 0L);
    -+
    -+        assertTrue(delta.migrateTun(tunUid, tunIface, underlyingIface));
    -+        assertEquals(9, delta.size());
    -+
    -+        // tunIface entries should not be changed.
    -+        assertValues(delta, 0, tunIface, 10100, SET_DEFAULT, TAG_NONE, ROAMING_NO,
    -+                50000L, 25L, 100000L, 50L, 0L);
    -+        assertValues(delta, 1, tunIface, 20100, SET_DEFAULT, TAG_NONE, ROAMING_NO,
    -+                500L, 2L, 200L, 5L, 0L);
    -+        assertValues(delta, 2, tunIface, tunUid, SET_DEFAULT, TAG_NONE, ROAMING_NO,
    -+                240000L, 100L, 120000L, 60L, 0L);
    -+
    -+        // Existing underlying Iface entries are updated
    -+        assertValues(delta, 3, underlyingIface, 10100, SET_DEFAULT, TAG_NONE, ROAMING_NO,
    -+                51000L, 35L, 102000L, 70L, 0L);
    -+
    -+        // VPN underlying Iface entries are updated
    -+        assertValues(delta, 4, underlyingIface, tunUid, SET_DEFAULT, TAG_NONE, ROAMING_NO,
    -+                25000L, 10L, 29800L, 15L, 0L);
    -+
    -+        // New entries are added for new application's underlying Iface traffic
    -+        assertContains(delta, underlyingIface, 20100, SET_DEFAULT, TAG_NONE, ROAMING_NO,
    -+                500L, 2L, 200L, 5L, 0L);
    -+
    -+        // New entries are added for debug purpose
    -+        assertContains(delta, underlyingIface, 10100, SET_DBG_VPN_IN, TAG_NONE, ROAMING_NO,
    -+                50000L, 25L, 100000L, 50L, 0L);
    -+        assertContains(delta, underlyingIface, 20100, SET_DBG_VPN_IN, TAG_NONE, ROAMING_NO,
    -+                500, 2L, 200L, 5L, 0L);
    -+        assertContains(delta, underlyingIface, tunUid, SET_DBG_VPN_OUT, TAG_NONE, ROAMING_ALL,
    -+                50500L, 27L, 100200L, 55, 0);
    -+    }
    -+
    -     private static void assertContains(NetworkStats stats,  String iface, int uid, int set,
    -             int tag, int roaming, long rxBytes, long rxPackets, long txBytes, long txPackets,
    -             long operations) {
    -diff --git a/core/tests/coretests/src/android/os/FileUtilsTest.java b/core/tests/coretests/src/android/os/FileUtilsTest.java
    -index ac5abad..bd90079 100644
    ---- a/core/tests/coretests/src/android/os/FileUtilsTest.java
    -+++ b/core/tests/coretests/src/android/os/FileUtilsTest.java
    -@@ -297,6 +297,20 @@ public class FileUtilsTest extends AndroidTestCase {
    -                 FileUtils.buildUniqueFile(mTarget, "image/jpeg", "test.jpg"));
    -     }
    - 
    -+    public void testBuildUniqueFile_mimeless() throws Exception {
    -+        assertNameEquals("test.jpg", FileUtils.buildUniqueFile(mTarget, "test.jpg"));
    -+        new File(mTarget, "test.jpg").createNewFile();
    -+        assertNameEquals("test (1).jpg", FileUtils.buildUniqueFile(mTarget, "test.jpg"));
    -+
    -+        assertNameEquals("test", FileUtils.buildUniqueFile(mTarget, "test"));
    -+        new File(mTarget, "test").createNewFile();
    -+        assertNameEquals("test (1)", FileUtils.buildUniqueFile(mTarget, "test"));
    -+
    -+        assertNameEquals("test.foo.bar", FileUtils.buildUniqueFile(mTarget, "test.foo.bar"));
    -+        new File(mTarget, "test.foo.bar").createNewFile();
    -+        assertNameEquals("test.foo (1).bar", FileUtils.buildUniqueFile(mTarget, "test.foo.bar"));
    -+    }
    -+
    -     private static void assertNameEquals(String expected, File actual) {
    -         assertEquals(expected, actual.getName());
    -     }
    -diff --git a/core/tests/coretests/src/android/os/OsTests.java b/core/tests/coretests/src/android/os/OsTests.java
    -index 582bf1a..985fa4f 100644
    ---- a/core/tests/coretests/src/android/os/OsTests.java
    -+++ b/core/tests/coretests/src/android/os/OsTests.java
    -@@ -32,6 +32,7 @@ public class OsTests {
    -         suite.addTestSuite(IdleHandlerTest.class);
    -         suite.addTestSuite(MessageQueueTest.class);
    -         suite.addTestSuite(MessengerTest.class);
    -+        suite.addTestSuite(PatternMatcherTest.class);
    -         suite.addTestSuite(SystemPropertiesTest.class);
    - 
    -         return suite;
    -diff --git a/core/tests/coretests/src/android/os/PatternMatcherTest.java b/core/tests/coretests/src/android/os/PatternMatcherTest.java
    -new file mode 100644
    -index 0000000..9645ccc
    ---- /dev/null
    -+++ b/core/tests/coretests/src/android/os/PatternMatcherTest.java
    -@@ -0,0 +1,234 @@
    -+package android.os;
    -+
    -+import android.test.suitebuilder.annotation.SmallTest;
    -+import junit.framework.TestCase;
    -+import org.junit.runner.RunWith;
    -+import org.junit.Test;
    -+import org.junit.runners.JUnit4;
    -+
    -+@RunWith(JUnit4.class)
    -+@SmallTest
    -+public class PatternMatcherTest extends TestCase{
    -+
    -+    @Test
    -+    public void testAdvancedPatternMatchesAnyToken() {
    -+        PatternMatcher matcher = new PatternMatcher(".", PatternMatcher.PATTERN_ADVANCED_GLOB);
    -+        assertMatches("a", matcher);
    -+        assertMatches("b", matcher);
    -+        assertNotMatches("", matcher);
    -+    }
    -+
    -+    @Test
    -+    public void testAdvancedPatternMatchesSetToken() {
    -+        PatternMatcher matcher = new PatternMatcher("[a]", PatternMatcher.PATTERN_ADVANCED_GLOB);
    -+        assertMatches("a", matcher);
    -+        assertNotMatches("b", matcher);
    -+
    -+        matcher = new PatternMatcher("[.*+{}\\]\\\\[]", PatternMatcher.PATTERN_ADVANCED_GLOB);
    -+        assertMatches(".", matcher);
    -+        assertMatches("*", matcher);
    -+        assertMatches("+", matcher);
    -+        assertMatches("{", matcher);
    -+        assertMatches("}", matcher);
    -+        assertMatches("]", matcher);
    -+        assertMatches("\\", matcher);
    -+        assertMatches("[", matcher);
    -+    }
    -+
    -+    @Test
    -+    public void testAdvancedPatternMatchesSetCharacterClassToken() {
    -+        PatternMatcher matcher = new PatternMatcher("[a-z]", PatternMatcher.PATTERN_ADVANCED_GLOB);
    -+        assertMatches("a", matcher);
    -+        assertMatches("b", matcher);
    -+        assertNotMatches("A", matcher);
    -+        assertNotMatches("1", matcher);
    -+
    -+        matcher = new PatternMatcher("[a-z][0-9]", PatternMatcher.PATTERN_ADVANCED_GLOB);
    -+        assertMatches("a1", matcher);
    -+        assertNotMatches("1a", matcher);
    -+        assertNotMatches("aa", matcher);
    -+
    -+        matcher = new PatternMatcher("[z-a]", PatternMatcher.PATTERN_ADVANCED_GLOB);
    -+        assertNotMatches("a", matcher);
    -+        assertNotMatches("z", matcher);
    -+        assertNotMatches("A", matcher);
    -+
    -+        matcher = new PatternMatcher("[^0-9]", PatternMatcher.PATTERN_ADVANCED_GLOB);
    -+        assertMatches("a", matcher);
    -+        assertMatches("z", matcher);
    -+        assertMatches("A", matcher);
    -+        assertNotMatches("9", matcher);
    -+        assertNotMatches("5", matcher);
    -+        assertNotMatches("0", matcher);
    -+
    -+        assertPoorlyFormattedPattern("[]a]");
    -+        matcher = new PatternMatcher("[\\[a]", PatternMatcher.PATTERN_ADVANCED_GLOB);
    -+        assertMatches("a", matcher);
    -+        assertMatches("[", matcher);
    -+    }
    -+
    -+    @Test
    -+    public void testAdvancedPatternMatchesEscapedCharacters() {
    -+        PatternMatcher matcher = new PatternMatcher("\\.", PatternMatcher.PATTERN_ADVANCED_GLOB);
    -+        assertMatches(".", matcher);
    -+        assertNotMatches("a", matcher);
    -+        assertNotMatches("1", matcher);
    -+
    -+        matcher = new PatternMatcher("a\\+", PatternMatcher.PATTERN_ADVANCED_GLOB);
    -+        assertMatches("a+", matcher);
    -+        assertNotMatches("a", matcher);
    -+        assertNotMatches("aaaaa", matcher);
    -+
    -+        matcher = new PatternMatcher("[\\a-\\z]", PatternMatcher.PATTERN_ADVANCED_GLOB);
    -+        assertMatches("a", matcher);
    -+        assertMatches("z", matcher);
    -+        assertNotMatches("A", matcher);
    -+    }
    -+
    -+    @Test
    -+    public void testAdvancedPatternMatchesLiteralTokens() {
    -+        PatternMatcher matcher = new PatternMatcher("a", PatternMatcher.PATTERN_ADVANCED_GLOB);
    -+        assertNotMatches("", matcher);
    -+        assertMatches("a", matcher);
    -+        assertNotMatches("z", matcher);
    -+
    -+        matcher = new PatternMatcher("az", PatternMatcher.PATTERN_ADVANCED_GLOB);
    -+        assertNotMatches("", matcher);
    -+        assertMatches("az", matcher);
    -+        assertNotMatches("za", matcher);
    -+    }
    -+
    -+    @Test
    -+    public void testAdvancedPatternMatchesSetZeroOrMore() {
    -+        PatternMatcher matcher = new PatternMatcher("[a-z]*", PatternMatcher.PATTERN_ADVANCED_GLOB);
    -+
    -+        assertMatches("", matcher);
    -+        assertMatches("a", matcher);
    -+        assertMatches("abcdefg", matcher);
    -+        assertNotMatches("abc1", matcher);
    -+        assertNotMatches("1abc", matcher);
    -+    }
    -+
    -+    @Test
    -+    public void testAdvancedPatternMatchesSetOneOrMore() {
    -+        PatternMatcher matcher = new PatternMatcher("[a-z]+", PatternMatcher.PATTERN_ADVANCED_GLOB);
    -+
    -+        assertNotMatches("", matcher);
    -+        assertMatches("a", matcher);
    -+        assertMatches("abcdefg", matcher);
    -+        assertNotMatches("abc1", matcher);
    -+        assertNotMatches("1abc", matcher);
    -+    }
    -+
    -+
    -+    @Test
    -+    public void testAdvancedPatternMatchesSingleRange() {
    -+        PatternMatcher matcher = new PatternMatcher("[a-z]{1}",
    -+                PatternMatcher.PATTERN_ADVANCED_GLOB);
    -+
    -+        assertNotMatches("", matcher);
    -+        assertMatches("a", matcher);
    -+        assertMatches("z", matcher);
    -+        assertNotMatches("1", matcher);
    -+        assertNotMatches("aa", matcher);
    -+    }
    -+
    -+    @Test
    -+    public void testAdvancedPatternMatchesFullRange() {
    -+        PatternMatcher matcher = new PatternMatcher("[a-z]{1,5}",
    -+                PatternMatcher.PATTERN_ADVANCED_GLOB);
    -+
    -+        assertNotMatches("", matcher);
    -+        assertMatches("a", matcher);
    -+        assertMatches("zazaz", matcher);
    -+        assertNotMatches("azazaz", matcher);
    -+        assertNotMatches("11111", matcher);
    -+    }
    -+
    -+    @Test
    -+    public void testAdvancedPatternMatchesPartialRange() {
    -+        PatternMatcher matcher = new PatternMatcher("[a-z]{3,}",
    -+                PatternMatcher.PATTERN_ADVANCED_GLOB);
    -+
    -+        assertNotMatches("", matcher);
    -+        assertMatches("aza", matcher);
    -+        assertMatches("zazaz", matcher);
    -+        assertMatches("azazazazazaz", matcher);
    -+        assertNotMatches("aa", matcher);
    -+    }
    -+
    -+    @Test
    -+    public void testAdvancedPatternMatchesComplexPatterns() {
    -+        PatternMatcher matcher = new PatternMatcher(
    -+                "/[0-9]{4}/[0-9]{2}/[0-9]{2}/[a-zA-Z0-9_]+\\.html",
    -+                PatternMatcher.PATTERN_ADVANCED_GLOB);
    -+
    -+        assertNotMatches("", matcher);
    -+        assertMatches("/2016/09/07/got_this_working.html", matcher);
    -+        assertMatches("/2016/09/07/got_this_working2.html", matcher);
    -+        assertNotMatches("/2016/09/07/got_this_working2dothtml", matcher);
    -+        assertNotMatches("/2016/9/7/got_this_working.html", matcher);
    -+
    -+        matcher = new PatternMatcher(
    -+                "/b*a*bar.*",
    -+                PatternMatcher.PATTERN_ADVANCED_GLOB);
    -+
    -+        assertMatches("/babar", matcher);
    -+        assertMatches("/babarfff", matcher);
    -+        assertMatches("/bbaabarfff", matcher);
    -+        assertMatches("/babar?blah", matcher);
    -+        assertMatches("/baaaabar?blah", matcher);
    -+        assertNotMatches("?bar", matcher);
    -+        assertNotMatches("/bar", matcher);
    -+        assertNotMatches("/baz", matcher);
    -+        assertNotMatches("/ba/bar", matcher);
    -+        assertNotMatches("/barf", matcher);
    -+        assertNotMatches("/", matcher);
    -+        assertNotMatches("?blah", matcher);
    -+    }
    -+
    -+    @Test
    -+    public void testAdvancedPatternPoorFormatThrowsIllegalArgumentException() {
    -+        assertPoorlyFormattedPattern("[a-z");
    -+        assertPoorlyFormattedPattern("a{,4}");
    -+        assertPoorlyFormattedPattern("a{0,a}");
    -+        assertPoorlyFormattedPattern("a{\\1, 2}");
    -+        assertPoorlyFormattedPattern("[]");
    -+        assertPoorlyFormattedPattern("a{}");
    -+        assertPoorlyFormattedPattern("{3,4}");
    -+        assertPoorlyFormattedPattern("a+{3,4}");
    -+        assertPoorlyFormattedPattern("*.");
    -+        assertPoorlyFormattedPattern(".+*");
    -+        assertPoorlyFormattedPattern("a{3,4");
    -+        assertPoorlyFormattedPattern("[a");
    -+        assertPoorlyFormattedPattern("abc\\");
    -+        assertPoorlyFormattedPattern("+.");
    -+
    -+        StringBuilder charSet = new StringBuilder("[");
    -+        for (int i = 0; i < 1024; i++) {
    -+            charSet.append('a' + (i % 26));
    -+        }
    -+        charSet.append("]");
    -+        assertPoorlyFormattedPattern(charSet.toString());
    -+    }
    -+
    -+    private void assertMatches(String string, PatternMatcher matcher) {
    -+        assertTrue("'" + string + "' should match '" + matcher.toString() + "'",
    -+                matcher.match(string));
    -+    }
    -+
    -+    private void assertNotMatches(String string, PatternMatcher matcher) {
    -+        assertTrue("'" + string + "' should not match '" + matcher.toString() + "'",
    -+                !matcher.match(string));
    -+    }
    -+
    -+    private void assertPoorlyFormattedPattern(String format) {
    -+        try {
    -+            new PatternMatcher(format, PatternMatcher.PATTERN_ADVANCED_GLOB);
    -+        } catch (IllegalArgumentException e) {
    -+            return;// expected
    -+        }
    -+
    -+        fail("'" + format + "' was erroneously created");
    -+    }
    -+}
    -diff --git a/docs/html-intl/intl/es/about/versions/nougat/index.jd b/docs/html-intl/intl/es/about/versions/nougat/index.jd
    -index b30cc88..59afd81 100644
    ---- a/docs/html-intl/intl/es/about/versions/nougat/index.jd
    -+++ b/docs/html-intl/intl/es/about/versions/nougat/index.jd
    -@@ -7,16 +7,6 @@ header.hide=1
    - footer.hide=1
    - @jd:body
    - 
    --<script>
    --  $(document).ready(function() {
    --    if (useUpdatedTemplates) {
    --      $("#useUpdatedTemplates").css("display","block");
    --    } else {
    --      $("#useOldTemplates").css("display","block");
    --    }
    --  })
    --</script>
    --
    - <section class="dac-expand dac-hero dac-light">
    -   <div class="wrap" style="max-width:1100px;margin-top:0">
    -   <a href="{@docRoot}about/versions/nougat/android-7.0.html">
    -@@ -54,7 +44,7 @@ footer.hide=1
    -   </div>
    - </section>
    - 
    --<div id="useUpdatedTemplates" style="display:none" class="dac-section dac-slim dac-gray dac-expand">
    -+<div class="dac-section dac-slim dac-gray dac-expand">
    -   <div class="wrap dac-offset-parent">
    -     <a class="dac-fab dac-scroll-button" data-scroll-button href="#latest">
    -       <i class="dac-sprite dac-arrow-down-gray"></i>
    -@@ -76,26 +66,6 @@ footer.hide=1
    -   </div><!-- end .wrap -->
    - </div><!-- end .dac-actions -->
    - 
    --<div id="useOldTemplates" style="display:none;color:black" class="actions-bar dac-expand dac-invert">
    --  <div class="wrap dac-offset-parent">
    --
    --    <div class="actions">
    --      <div><a href="https://developer.android.com/preview/bug">
    --        <span class="dac-sprite dac-auto-chevron-large"></span>
    --        Informar un problema
    --      </a></div>
    --      <div><a href="{@docRoot}preview/support.html">
    --        <span class="dac-sprite dac-auto-chevron-large"></span>
    --        Consulta las notas de la versión
    --      </a></div>
    --      <div><a href="{@docRoot}preview/dev-community">
    --        <span class="dac-sprite dac-auto-chevron-large"></span>
    --        Únete a la comunidad de desarrolladores
    --        </a></div>
    --    </div><!-- end .actions -->
    --  </div><!-- end .wrap -->
    --</div>
    --
    - <section class="dac-section dac-light dac-small" id="latest"><div class="wrap">
    -   <h2 class="norule">Lo último</h2>
    -   <div class="resource-widget resource-flow-layout col-16"
    -diff --git a/docs/html-intl/intl/es/index.jd b/docs/html-intl/intl/es/index.jd
    -index e0d80c1..1ecf47c 100644
    ---- a/docs/html-intl/intl/es/index.jd
    -+++ b/docs/html-intl/intl/es/index.jd
    -@@ -5,16 +5,6 @@ page.customHeadTag=<meta name="google-site-verification" content="sa-bIAI6GKvct3
    - 
    - @jd:body
    - 
    --<script>
    --  $(document).ready(function() {
    --    if (useUpdatedTemplates) {
    --      $("#useUpdatedTemplates").css("display","block");
    --    } else {
    --      $("#useOldTemplates").css("display","block");
    --    }
    --  })
    --</script>
    --
    - <section class="dac-expand dac-hero" style="background-color:#b2dfdb;">
    -   <div class="wrap" style="max-width:1000px;margin-top:0">
    -     <div class="col-7of16 col-push-8of16">
    -@@ -44,7 +34,7 @@ page.customHeadTag=<meta name="google-site-verification" content="sa-bIAI6GKvct3
    -   </div>
    - </section>
    - 
    --<div id="useUpdatedTemplates" style="display:none" class="dac-section dac-slim dac-gray dac-expand">
    -+<div class="dac-section dac-slim dac-gray dac-expand">
    -   <div class="wrap dac-offset-parent">
    -     <a class="dac-fab dac-scroll-button" data-scroll-button href="#build-apps">
    -       <i class="dac-sprite dac-arrow-down-gray"></i>
    -@@ -72,28 +62,6 @@ page.customHeadTag=<meta name="google-site-verification" content="sa-bIAI6GKvct3
    -   </div><!-- end .wrap -->
    - </div><!-- end .dac-actions -->
    - 
    --<div id="useOldTemplates" style="display:none" class="actions-bar dac-expand dac-invert">
    --  <div class="wrap dac-offset-parent">
    --    <a class="dac-fab dac-scroll-button" data-scroll-button="" href="#build-apps">
    --      <i class="dac-sprite dac-arrow-down-gray"></i>
    --    </a>
    --    <div class="actions">
    --      <div><a href="{@docRoot}sdk/index.html">
    --        <span class="dac-sprite dac-auto-chevron-large"></span>
    --        Get the SDK
    --      </a></div>
    --      <div><a href="{@docRoot}samples/index.html">
    --        <span class="dac-sprite dac-auto-chevron-large"></span>
    --        Browse Samples
    --      </a></div>
    --      <div><a href="{@docRoot}distribute/stories/index.html">
    --        <span class="dac-sprite dac-auto-chevron-large"></span>
    --        Watch Stories
    --      </a></div>
    --    </div><!-- end .actions -->
    --  </div><!-- end .wrap -->
    --</div>
    --
    - <section class="dac-section dac-light" id="build-apps"><div class="wrap">
    -   <h1 class="dac-section-title">Build Beautiful Apps</h1>
    -   <div class="dac-section-subtitle">
    -diff --git a/docs/html-intl/intl/id/about/versions/marshmallow/android-6.0-testing.jd b/docs/html-intl/intl/id/about/versions/marshmallow/android-6.0-testing.jd
    -new file mode 100644
    -index 0000000..94bc74c
    ---- /dev/null
    -+++ b/docs/html-intl/intl/id/about/versions/marshmallow/android-6.0-testing.jd
    -@@ -0,0 +1,190 @@
    -+page.title=Panduan Pengujian
    -+page.image=images/cards/card-n-guide_2x.png
    -+meta.tags="preview", "testing"
    -+page.tags="preview", "developer preview"
    -+
    -+@jd:body
    -+
    -+<div id="tb-wrapper">
    -+  <div id="tb">
    -+    <h2>Dalam dokumen ini</h2>
    -+      <ol>
    -+        <li><a href="#runtime-permissions">Izin Pengujian</a></li>
    -+        <li><a href="#doze-standby">Menguji Istirahatkan dan Aplikasi Siaga</a></li>
    -+        <li><a href="#ids">Pencadangan Otomatis dan Identifier Perangkat</a></li>
    -+      </ol>
    -+  </div>
    -+</div>
    -+
    -+<p>
    -+  Android N memberi Anda kesempatan untuk memastikan aplikasi bekerja pada
    -+  platform versi berikutnya. Pratinjau ini berisi beberapa API dan perubahan perilaku yang bisa
    -+  memengaruhi aplikasi Anda, sebagaimana dijelaskan dalam <a href="{@docRoot}preview/api-overview.html">Ringkasan
    -+  API</a> dan <a href="{@docRoot}preview/behavior-changes.html">Perubahan Perilaku</a>. Dalam menguji
    -+  aplikasi dengan pratinjau, ada beberapa perubahan sistem spesifik yang harus Anda fokuskan untuk
    -+  memastikan pengguna mendapatkan pengalaman yang bagus.
    -+</p>
    -+
    -+<p>
    -+  Panduan ini menjelaskan apa dan bagaimana menguji fitur pratinjau dengan aplikasi Anda. Anda harus
    -+  mengutamakan pengujian fitur pratinjau spesifik ini, dikarenakan pengaruhnya yang besar pada
    -+  perilaku aplikasi Anda:
    -+</p>
    -+
    -+<ul>
    -+  <li><a href="#runtime-permissions">Izin</a>
    -+  </li>
    -+  <li><a href="#doze-standby">Istirahatkan dan Aplikasi Siaga</a>
    -+  </li>
    -+  <li><a href="#ids">Pencadangan Otomatis dan Identifier Perangkat</a></li>
    -+</ul>
    -+
    -+<p>
    -+  Untuk informasi selengkapnya tentang cara menyiapkan perangkat atau perangkat maya dengan citra sistem pratinjau
    -+  untuk pengujian, lihat <a href="{@docRoot}preview/setup-sdk.html">Menyiapkan
    -+Android N SDK</a>.
    -+</p>
    -+
    -+
    -+<h2 id="runtime-permissions">Izin Pengujian</h2>
    -+
    -+<p>
    -+  Model <a href="{@docRoot}preview/features/runtime-permissions.html">Izin</a> yang baru
    -+  mengubah cara alokasi izin untuk aplikasi Anda oleh pengguna. Sebagai ganti memberi semua
    -+  izin selama prosedur pemasangan, aplikasi Anda harus meminta izin kepada pengguna secara individual
    -+ pada waktu proses. Bagi pengguna, perilaku ini memberi kontrol yang lebih detail atas setiap aktivitas aplikasi, dan
    -+  juga konteks yang lebih untuk memahami sebab aplikasi meminta izin tertentu. Pengguna
    -+  bisa memberi atau mencabut izin yang diberikan pada suatu aplikasi secara individual kapan saja. Fitur
    -+  pratinjau ini kemungkinan besar memengaruhi perilaku aplikasi Anda dan mungkin menghambat fungsi beberapa
    -+  fitur aplikasi Anda, atau mengurangi kualitas kerjanya.
    -+</p>
    -+
    -+<p class="caution">
    -+  Perubahan ini memengaruhi semua aplikasi yang berjalan di platform baru, bahkan aplikasi yang tidak menargetkan versi
    -+  platform baru. Platform ini memberikan perilaku kompatibilitas terbatas untuk aplikasi lawas, namun Anda
    -+  harus mulai merencanakan migrasi aplikasi ke model izin baru sekarang juga, dengan tujuan
    -+  mempublikasikan versi terbaru aplikasi Anda saat peluncuran platform secara resmi.
    -+</p>
    -+
    -+
    -+<h3 id="permission-test-tips">Tip pengujian</h3>
    -+
    -+<p>
    -+  Gunakan tip berikut untuk membantu Anda merencanakan dan menjalankan pengujian aplikasi dengan
    -+  perilaku izin yang baru.
    -+</p>
    -+
    -+<ul>
    -+  <li>Identifikasi izin aplikasi Anda saat ini dan jalur kode terkait.</li>
    -+  <li>Uji alur pengguna pada semua layanan dan data yang dilindungi izin.</li>
    -+  <li>Uji dengan berbagai kombinasi izin yang diberikan/dicabut.</li>
    -+  <li>Gunakan alat bantu {@code adb} untuk mengelola izin dari baris perintah:
    -+    <ul>
    -+      <li>Cantumkan daftar izin dan status berdasarkan kelompok:
    -+        <pre>adb shell pm list permissions -d -g</pre>
    -+      </li>
    -+      <li>Beri atau cabut satu atau beberapa izin menggunakan sintaks berikut:<br>
    -+        <pre>adb shell pm [grant|revoke] &lt;permission.name&gt; ...</pre>
    -+      </li>
    -+    </ul>
    -+  </li>
    -+  <li>Analisis aplikasi Anda untuk layanan yang menggunakan izin.</li>
    -+</ul>
    -+
    -+<h3 id="permission-test-strategy">Strategi pengujian</h3>
    -+
    -+<p>
    -+  Perubahan izin memengaruhi struktur dan desain aplikasi Anda, begitu juga
    -+  pengalaman pengguna dan alur yang Anda sediakan untuk pengguna. Anda harus menilai penggunaan izin
    -+  aplikasi saat ini dan mulai merencanakan alur baru yang ingin ditawarkan. Rilis platform
    -+  resmi menyediakan perilaku kompatibilitas, namun Anda harus merencanakan pembaruan aplikasi dan tidak
    -+  bergantung pada perilaku ini.
    -+</p>
    -+
    -+<p>
    -+  Identifikasi izin yang sebenarnya diperlukan dan digunakan aplikasi Anda, kemudian temukan berbagai
    -+  jalur kode yang menggunakan layanan yang dilindungi izin. Anda bisa melakukan ini melalui kombinasi
    -+  pengujian pada platform baru dan analisis kode. Dalam pengujian, Anda harus fokus pada pemilihan
    -+ izin waktu proses dengan mengubah {@code targetSdkVersion} aplikasi ke versi pratinjau. Untuk
    -+  informasi selengkapnya, lihat <a href="{@docRoot}preview/setup-sdk.html#">Menyiapkan
    -+Android N SDK</a>.
    -+</p>
    -+
    -+<p>
    -+  Uji dengan berbagai kombinasi izin yang dicabut dan ditambahkan, untuk menyoroti alur pengguna yang
    -+  bergantung pada izin. Jika dependensi tidak jelas atau logis, Anda harus mempertimbangkan
    -+optimalisasi atau kompartementalisasi alur tersebut untuk mengeliminasi dependensi atau menjelaskan alasan
    -+  diperlukannya izin.
    -+</p>
    -+
    -+<p>
    -+  Untuk informasi selengkapnya tentang perilaku izin waktu proses, pengujian, dan praktik terbaik, lihat
    -+  halaman pratinjau <a href="{@docRoot}preview/features/runtime-permissions.html">Izin</a>
    -+  pengembang.
    -+</p>
    -+
    -+
    -+<h2 id="doze-standby">Menguji Istirahatkan dan Aplikasi Siaga</h2>
    -+
    -+<p>
    -+  Fitur penghematan daya Istirahatkan dan Aplikasi Siaga membatasi jumlah pemrosesan latar belakang yang
    -+  bisa dikerjakan aplikasi Anda saat perangkat dalam keadaan diam atau saat aplikasi Anda sedang tidak fokus. Pembatasan
    -+  yang dapat diberlakukan oleh sistem pada aplikasi termasuk akses jaringan terbatas atau tidak ada,
    -+  tugas latar belakang yang ditangguhkan, Pemberitahuan yang ditangguhkan, permintaan membangunkan yang diabaikan, serta alarm. Untuk memastikan
    -+  aplikasi Anda berperilaku dengan benar pada optimalisasi penghematan daya ini, Anda harus menguji aplikasi dengan
    -+ menyimulasikan keadaan baterai yang sedang tinggal sedikit ini.
    -+</p>
    -+
    -+<h4 id="doze">Menguji aplikasi Anda dengan Istirahatkan</h4>
    -+
    -+<p>Untuk menguji Istirahatkan dengan aplikasi Anda:</p>
    -+
    -+<ol>
    -+<li>Konfigurasikan perangkat keras atau perangkat maya dengan citra sistem Android N.</li>
    -+<li>Hubungkan perangkat dengan mesin pengembangan dan pasang aplikasi Anda.</li>
    -+<li>Jalankan aplikasi Anda dan biarkan aktif.</li>
    -+<li>Simulasikan perangkat yang sedang masuk ke dalam mode Istirahatkan dengan menjalankan perintah berikut:
    -+
    -+<pre>
    -+$ adb shell dumpsys battery unplug
    -+$ adb shell dumpsys deviceidle step
    -+$ adb shell dumpsys deviceidle -h
    -+</pre>
    -+
    -+  </li>
    -+  <li>Amati perilaku aplikasi Anda saat perangkat diaktifkan kembali. Pastikan aplikasi
    -+    pulih dengan baik saat perangkat keluar dari Istirahatkan.</li>
    -+</ol>
    -+
    -+
    -+<h4 id="standby">Menguji aplikasi dengan Aplikasi Siaga</h4>
    -+
    -+<p>Untuk menguji mode Aplikasi Siaga dengan aplikasi Anda:</p>
    -+
    -+<ol>
    -+  <li>Konfigurasikan perangkat keras atau perangkat maya dengan citra sistem Android N.</li>
    -+  <li>Hubungkan perangkat dengan mesin pengembangan dan pasang aplikasi Anda.</li>
    -+  <li>Jalankan aplikasi Anda dan biarkan aktif.</li>
    -+  <li>Simulasikan aplikasi yang sedang masuk ke dalam mode siaga dengan menjalankan perintah berikut:
    -+
    -+<pre>
    -+$ adb shell am broadcast -a android.os.action.DISCHARGING
    -+$ adb shell am set-idle &lt;packageName&gt; true
    -+</pre>
    -+
    -+  </li>
    -+  <li>Simulasikan membangunkan aplikasi Anda menggunakan perintah berikut:
    -+    <pre>$ adb shell am set-idle &lt;packageName&gt; false</pre>
    -+  </li>
    -+  <li>Amati perilaku aplikasi Anda saat dibangunkan. Pastikan aplikasi pulih dengan baik
    -+   dari mode siaga. Secara khusus, Anda harus memeriksa apakah Pemberitahuan aplikasi dan pekerjaan latar belakang
    -+   tetap berjalan sebagaimana yang diharapkan.</li>
    -+</ol>
    -+
    -+<h2 id="ids">Auto Backup for Apps dan Identifier Perangkat Spesifik</h2>
    -+
    -+<p>Jika aplikasi Anda mempertahankan identifier perangkat spesifik, seperti ID pendaftaran Google
    -+Cloud Messaging, dalam penyimpanan internal,
    -+pastikan Anda mengikuti praktik terbaik untuk mengecualikan lokasi
    -+penyimpanan dari pencadangan otomatis, seperti dijelaskan dalam <a href="{@docRoot}preview/backup/index.html">Auto
    -+Backup for Apps</a>. </p>
    -diff --git a/docs/html-intl/intl/id/about/versions/nougat/android-7.0-changes.jd b/docs/html-intl/intl/id/about/versions/nougat/android-7.0-changes.jd
    -new file mode 100644
    -index 0000000..af01cd2
    ---- /dev/null
    -+++ b/docs/html-intl/intl/id/about/versions/nougat/android-7.0-changes.jd
    -@@ -0,0 +1,610 @@
    -+page.title=Perubahan Perilaku
    -+page.keywords=pratinjau,sdk,kompatibilitas
    -+meta.tags="preview", "compatibility"
    -+page.tags="preview", "developer preview"
    -+page.image=images/cards/card-n-changes_2x.png
    -+@jd:body
    -+
    -+
    -+<div id="tb-wrapper">
    -+<div id="tb">
    -+
    -+<h2>Dalam dokumen ini</h2>
    -+
    -+<ol>
    -+  <li><a href="#perf">Peningkatan Kinerja</a>
    -+    <ol>
    -+      <li><a href="#doze">Istirahatkan</a></li>
    -+      <li><a href="#bg-opt">Optimalisasi Latar Belakang</a></li>
    -+    </ol>
    -+  </li>
    -+  <li><a href="#perm">Perubahan Izin</a>
    -+  </li>
    -+  <li><a href="#sharing-files">Berbagi File Antar Aplikasi</a></li>
    -+  <li><a href="#accessibility">Peningkatan Aksesibilitas</a>
    -+    <ol>
    -+      <li><a href="#screen-zoom">Perbesaran Layar</a></li>
    -+      <li><a href="#vision-settings">Vision Settings di Setup Wizard</a></li>
    -+    </ol>
    -+  </li>
    -+  <li><a href="#ndk">Penautan Aplikasi NDK ke Pustaka Platform</a></li>
    -+  <li><a href="#afw">Android for Work</a></li>
    -+  <li><a href="#annotations">Retensi Anotasi</a></li>
    -+  <li><a href="#other">Poin Penting Lainnya</a></li>
    -+</ol>
    -+
    -+<h2>Lihat Juga</h2>
    -+<ol>
    -+  <li><a href="{@docRoot}preview/api-overview.html">
    -+    Ringkasan Android N API</a></li>
    -+</ol>
    -+
    -+</div>
    -+</div>
    -+
    -+
    -+<p>
    -+  Bersama fitur dan kemampuan baru, Android N
    -+  menyertakan berbagai macam perubahan sistem dan perubahan perilaku API. Dokumen ini
    -+  menyoroti beberapa perubahan utama yang harus dipahami dan diperhitungkan
    -+  dalam aplikasi Anda.
    -+</p>
    -+
    -+<p>
    -+  Jika Anda sebelumnya telah mempublikasikan aplikasi untuk Android, ketahuilah bahwa aplikasi Anda
    -+  mungkin dipengaruhi oleh perubahan dalam platform.
    -+</p>
    -+
    -+
    -+<h2 id="perf">Baterai dan Memori</h2>
    -+
    -+<p>
    -+Android N menyertakan perubahan perilaku sistem yang bertujuan untuk meningkatkan daya tahan baterai
    -+perangkat dan mengurangi penggunaan RAM. Perubahan ini bisa memengaruhi akses aplikasi Anda ke
    -+sumber daya sistem, termasuk cara aplikasi Anda berinteraksi dengan aplikasi lain melalui
    -+intent implisit tertentu.
    -+</p>
    -+
    -+<h3 id="doze">Istirahatkan</h3>
    -+
    -+<p>
    -+  Diperkenalkan dalam Android 6.0 (API level 23), Istirahatkan meningkatkan daya tahan baterai dengan
    -+  menangguhkan aktivitas CPU dan jaringan bila pengguna tidak mencabut perangkat,
    -+  tidak bergerak, dan layar dinonaktifkan. Android N lebih
    -+  menyempurnakan Istirahatkan dengan menerapkan subset CPU dan pembatasan jaringan
    -+  bila perangkat dicabut dan layar dinonaktifkan, namun tidak harus
    -+  diam, misalnya, bila handset dibawa bepergian di saku pengguna.
    -+</p>
    -+
    -+
    -+<img src="{@docRoot}images/android-7.0/doze-diagram-1.png" alt="" height="251px" id="figure1" />
    -+<p class="img-caption">
    -+  <strong>Gambar 1.</strong> Ilustrasi tentang cara Istirahatkan menerapkan pembatasan
    -+  aktivitas sistem level pertama untuk meningkatkan daya tahan baterai.
    -+</p>
    -+
    -+<p>
    -+  Bila perangkat sedang menggunakan daya baterai, dan layar telah nonaktif selama jangka waktu
    -+  tertentu, perangkat akan memasuki Istirahatkan dan menerapkan subset pembatasan pertama: Perangkat
    -+  akan menutup akses jaringan aplikasi, serta menangguhkan pekerjaan dan sinkronisasi. Jika perangkat sedang
    -+  diam selama jangka waktu tertentu setelah memasuki Istirahatkan, sistem akan menerapkan
    -+  pembatasan Istirahatkan selebihnya terhadap alarm {@link android.os.PowerManager.WakeLock},
    -+  {@link android.app.AlarmManager}, GPS, dan pemindaian Wi-Fi. Tidak peduli
    -+  apakah sebagian atau semua pembatasan Istirahatkan diterapkan, sistem akan membangunkan
    -+  perangkat selama jeda pemeliharaan singkat, dan selama itu aplikasi diizinkan
    -+  mengakses jaringan dan bisa mengeksekusi semua pekerjaan/sinkronisasi yang telah ditangguhkan.
    -+</p>
    -+
    -+
    -+<img src="{@docRoot}images/android-7.0/doze-diagram-2.png" alt="" id="figure2" />
    -+<p class="img-caption">
    -+  <strong>Gambar 2.</strong> Ilustrasi tentang cara Istirahatkan menerapkan pembatasan
    -+  aktivitas sistem level kedua setelah perangkat diam selama jangka waktu tertentu.
    -+</p>
    -+
    -+<p>
    -+  Perhatikan, mengaktifkan layar atau mencolokkan steker perangkat akan mengeluarkan dari Istirahatkan
    -+  dan membuang pembatasan pemrosesan ini. Perilaku tambahan ini tidak
    -+  memengaruhi rekomendasi dan praktik terbaik dalam menyesuaikan aplikasi Anda dengan versi
    -+  Istirahatkan sebelumnya yang diperkenalkan dalam Android 6.0 (API level 23), seperti yang dibahas di
    -+  <a href="{@docRoot}training/monitoring-device-state/doze-standby.html">
    -+  Mengoptimalkan untuk Istirahatkan dan Aplikasi Siaga</a>. Anda tetap harus
    -+   mengikuti rekomendasi itu, seperti menggunakan Google Cloud Messaging (GCM) untuk
    -+  mengirim dan menerima pesan, serta mulai merencanakan pembaruan
    -+  untuk mengakomodasi perilaku Istirahatkan tambahan.
    -+</p>
    -+
    -+
    -+<h3 id="bg-opt">Project Svelte: Optimalisasi Latar Belakang</h3>
    -+
    -+<p>
    -+  Android N membuang tiga siaran implisit untuk membantu mengoptimalkan
    -+  penggunaan memori dan konsumsi daya. Perubahan ini penting karena siaran
    -+  implisit sering memulai aplikasi yang telah didaftarkan untuk mendengarkannya di
    -+  latar belakang. Membuang siaran ini bisa sangat menguntungkan
    -+  kinerja perangkat dan pengalaman pengguna.
    -+</p>
    -+
    -+<p>
    -+  Perangkat seluler seringkali mengalami perubahan konektivitas, seperti saat berpindah
    -+  antara Wi-Fi dan data seluler. Saat ini, aplikasi bisa memantau perubahan dalam
    -+  konektivitas dengan mendaftarkan suatu penerima untuk siaran implisit {@link
    -+  android.net.ConnectivityManager#CONNECTIVITY_ACTION} dalam manifes
    -+  mereka. Karena banyak aplikasi yang didaftarkan untuk menerima siaran ini, switch  jaringan tunggal
    -+  bisa menyebabkan semuanya aktif dan memproses siaran tersebut
    -+  secara bersamaan.
    -+</p>
    -+
    -+<p>
    -+  Demikian pula, dalam Android versi sebelumnya, aplikasi bisa mendaftar untuk menerima siaran implisit {@link
    -+  android.hardware.Camera#ACTION_NEW_PICTURE} dan {@link
    -+  android.hardware.Camera#ACTION_NEW_VIDEO} dari aplikasi lain, seperti
    -+  Kamera. Bila pengguna mengambil gambar dengan aplikasi Kamera, semua aplikasi ini akan aktif
    -+  untuk memproses siaran.
    -+</p>
    -+
    -+<p>
    -+  Untuk meminimalkan masalah ini, Android N menerapkan optimalisasi
    -+  berikut:
    -+</p>
    -+
    -+<ul>
    -+  <li>Aplikasi yang menargetkan Android N tidak menerima siaran {@link
    -+  android.net.ConnectivityManager#CONNECTIVITY_ACTION}, sekalipun
    -+  memiliki entri manifes untuk meminta pemberitahuan mengenai kejadian ini. Aplikasi
    -+  yang berjalan tetap bisa mendengarkan {@code CONNECTIVITY_CHANGE} pada thread utama
    -+  jika mereka meminta pemberitahuan dengan {@link android.content.BroadcastReceiver}.
    -+  </li>
    -+
    -+  <li>Aplikasi tidak bisa mengirim atau menerima siaran {@link
    -+  android.hardware.Camera#ACTION_NEW_PICTURE} atau {@link
    -+  android.hardware.Camera#ACTION_NEW_VIDEO}. Optimalisasi ini
    -+  memengaruhi semua aplikasi, bukan hanya aplikasi yang menargetkan Android N.
    -+  </li>
    -+</ul>
    -+
    -+<p>Jika aplikasi Anda menggunakan intent ini, Anda harus membuang dependensi padanya
    -+  secepat mungkin agar Anda bisa menargetkan perangkat Android N dengan benar.
    -+  Kerangka kerja Android menyediakan beberapa solusi untuk mengurangi kebutuhan akan
    -+  siaran implisit ini. Misalnya, {@link
    -+  android.app.job.JobScheduler} API menyediakan mekanisme yang tangguh untuk menjadwalkan
    -+  operasi jaringan bila kondisi yang ditetapkan, seperti koneksi ke jaringan
    -+  berbiaya tetap, terpenuhi. Anda juga dapat menggunakan {@link
    -+  android.app.job.JobScheduler} untuk bereaksi terhadap perubahan pada penyedia materi.
    -+</p>
    -+
    -+<p>
    -+  Untuk informasi selengkapnya tentang optimalisasi latar belakang di N dan cara menyesuaikan aplikasi Anda,
    -+  lihat <a href="{@docRoot}preview/features/background-optimization.html">Optimalisasi
    -+  Latar Belakang</a>.
    -+</p>
    -+
    -+<h2 id="perm">Perubahan Izin</h2>
    -+
    -+<p>
    -+  Android N menyertakan perubahan pada izin yang bisa memengaruhi aplikasi Anda.
    -+</p>
    -+
    -+<h3 id="permfilesys">Perubahan izin sistem file</h3>
    -+
    -+<p>
    -+  Guna meningkatkan keamanan file privat, direktori privat
    -+  aplikasi yang menargetkan Android N atau yang lebih tinggi memiliki akses terbatas (<code>0700</code>).
    -+  Pengaturan ini mencegah kebocoran metadata dari file privat, seperti ukuran
    -+  atau eksistensi. Perubahan izin ini memiliki beberapa efek samping:
    -+</p>
    -+
    -+<ul>
    -+  <li>
    -+    Izin file privat tidak boleh dianggap remeh oleh pemilik,
    -+    dan usaha untuk melakukannya menggunakan
    -+    {@link android.content.Context#MODE_WORLD_READABLE} dan/atau
    -+    {@link android.content.Context#MODE_WORLD_WRITEABLE}, akan memicu sebuah
    -+    {@link java.lang.SecurityException}.
    -+    <p class="note">
    -+      <strong>Catatan:</strong> Seperti sebelumnya, pembatasan ini tidak sepenuhnya diterapkan.
    -+      Aplikasi mungkin masih memodifikasi izin ke direktori privat mereka menggunakan
    -+      API asal atau {@link java.io.File File} API. Akan tetapi, kami sangat
    -+      tidak menyarankan Anda meremehkan izin direktori privat.
    -+    </p>
    -+  </li>
    -+  <li>
    -+    Meneruskan URI <code>file://</code> di luar domain paket dapat meninggalkan
    -+    penerima dengan jalur yang tidak bisa di akses. Karena itu, upaya untuk meneruskan URI
    -+    <code>file://</code> akan memicu
    -+    <code>FileUriExposedException</code>. Cara yang disarankan adalah
    -+    materi file privat menggunakan {@link
    -+    android.support.v4.content.FileProvider}.
    -+  </li>
    -+  <li>
    -+    {@link android.app.DownloadManager} tidak bisa lagi berbagi
    -+    file yang tersimpan secara privat berdasarkan nama file. Aplikasi lawas dapat mengakibatkan
    -+    jalur yang tidak dapat diakses saat mengakses {@link
    -+    android.app.DownloadManager#COLUMN_LOCAL_FILENAME}. Aplikasi yang menargetkan
    -+    Android N atau yang lebih tinggi akan memicu {@link java.lang.SecurityException} saat
    -+    berupaya mengakses
    -+    {@link android.app.DownloadManager#COLUMN_LOCAL_FILENAME}.
    -+    Aplikasi lawas yang menyetel lokasi unduhan ke lokasi publik dengan
    -+    menggunakan
    -+    {@link
    -+    android.app.DownloadManager.Request#setDestinationInExternalFilesDir
    -+    DownloadManager.Request.setDestinationInExternalFilesDir()} atau
    -+    {@link
    -+    android.app.DownloadManager.Request#setDestinationInExternalPublicDir
    -+    DownloadManager.Request.setDestinationInExternalPublicDir()}
    -+    tetap bisa mengakses jalur tersebut di
    -+    {@link android.app.DownloadManager#COLUMN_LOCAL_FILENAME}, akan tetapi,
    -+     metode ini sangat tidak disarankan. Cara yang disarankan untuk mengakses file
    -+    yang diekspos oleh {@link android.app.DownloadManager} adalah menggunakan
    -+    {@link android.content.ContentResolver#openFileDescriptor
    -+    ContentResolver.openFileDescriptor()}.
    -+  </li>
    -+</ul>
    -+
    -+<h2 id="sharing-files">Berbagi File Antar Aplikasi</h2>
    -+
    -+<p>
    -+Untuk aplikasi yang menargetkan Android N, kerangka kerja Android menerapkan
    -+kebijakan {@link android.os.StrictMode} API yang melarang mengekspos URI {@code file://}
    -+di luar aplikasi Anda. Jika sebuah intent berisi URI file meninggalkan aplikasi Anda, aplikasi tersebut akan gagal
    -+dengan pengecualian {@code FileUriExposedException}.
    -+</p>
    -+
    -+<p>
    -+Untuk berbagi file antar aplikasi, Anda harus mengirim URI {@code content://}
    -+dan memberikan izin akses sementara pada URI. Cara termudah untuk memberikan izin ini adalah dengan
    -+menggunakan kelas {@link android.support.v4.content.FileProvider}. Untuk informasi selengkapnya
    -+mengenai izin dan berbagi file,
    -+lihat <a href="{@docRoot}training/secure-file-sharing/index.html">Berbagi File</a>.
    -+</p>
    -+
    -+<h2 id="accessibility">Peningkatan Aksesibilitas</h2>
    -+
    -+<p>
    -+  Android N menyertakan perubahan yang bertujuan meningkatkan kegunaan
    -+  platform untuk pengguna dengan penglihatan yang rendah atau lemah. Perubahan ini umumnya tidak
    -+  memerlukan perubahan kode dalam aplikasi Anda, akan tetapi Anda harus memeriksa
    -+  fitur ini dan mengujinya dengan aplikasi untuk menilai kemungkinan dampaknya terhadap pengalaman
    -+  pengguna.
    -+</p>
    -+
    -+
    -+<h3 id="screen-zoom">Perbesaran Layar</h3>
    -+
    -+<p>
    -+  Android N memungkinkan pengguna menyetel <strong>Display size</strong> yang akan memperbesar
    -+  atau memperkecil semua elemen pada layar, sehingga meningkatkan aksesibilitas perangkat
    -+  bagi pengguna yang kurang melihat. Pengguna tidak bisa memperbesar layar melewati lebar layar
    -+  minimum <a href="http://developer.android.com/guide/topics/resources/providing-resources.html">
    -+  sw320dp</a>, yang merupakan lebar Nexus 4, yakni ponsel ukuran sedang pada umumnya.
    -+</p>
    -+
    -+<div class="cols">
    -+
    -+<div class="col-6">
    -+  <img src="{@docRoot}images/android-7.0/screen-zoom-1.png" alt="" height="XXX" id="figure1" />
    -+</div>
    -+<div class="col-6">
    -+  <img src="{@docRoot}images/android-7.0/screen-zoom-2.png" alt="" height="XXX" id="figure1" />
    -+</div>
    -+
    -+</div> <!-- end cols -->
    -+<p class="img-caption">
    -+  <strong>Gambar 3.</strong> Layar di sebelah kanan menampilkan efek
    -+ penambahan Display size perangkat yang menjalankan citra sistem Android N.
    -+</p>
    -+
    -+
    -+<p>
    -+  Bila kepadatan perangkat berubah, sistem akan memberi tahu aplikasi yang sedang berjalan dengan
    -+  cara berikut:
    -+</p>
    -+
    -+<ul>
    -+  <li>Jika aplikasi menargetkan API level 23 atau yang lebih rendah, sistem secara otomatis akan mematikan
    -+  semua proses latar belakang. Artinya, jika pengguna beralih dari
    -+  aplikasi tersebut untuk membuka layar <em>Settings</em> dan mengubah
    -+  setelan <strong>Display size</strong>, maka sistem akan mematikan aplikasi tersebut dengan cara yang
    -+  sama dengan saat memori tinggal sedikit. Jika aplikasi memiliki beberapa proses
    -+  latar depan, sistem akan memberi tahu proses tersebut mengenai perubahan konfigurasi seperti
    -+ dijelaskan dalam <a href="{@docRoot}guide/topics/resources/runtime-changes.html">Menangani Perubahan
    -+  Waktu Proses</a>, seolah-olah orientasi perangkat telah berubah.
    -+  </li>
    -+
    -+  <li>Jika sebuah aplikasi menargetkan Android N, semua prosesnya
    -+  (latar depan dan latar belakang) akan diberi tahu mengenai perubahan konfigurasi seperti
    -+  dijelaskan dalam <a href="{@docRoot}guide/topics/resources/runtime-changes.html">Menangani Perubahan
    -+  Waktu Proses</a>.
    -+  </li>
    -+</ul>
    -+
    -+<p>
    -+  Sebagian besar aplikasi tidak perlu melakukan perubahan untuk mendukung fitur ini, asalkan
    -+  aplikasi tersebut mengikuti praktik terbaik Android. Hal-hal tertentu yang harus diperiksa:
    -+</p>
    -+
    -+<ul>
    -+  <li>Uji aplikasi Anda pada perangkat dengan lebar layar <code><a href=
    -+  "{@docRoot}guide/topics/resources/providing-resources.html">sw320dp</a></code>
    -+  dan pastikan aplikasi berjalan dengan semestinya.
    -+  </li>
    -+
    -+  <li>Bila konfigurasi perangkat berubah, perbarui informasi cache
    -+  yang bergantung pada kepadatan, seperti bitmap di cache atau sumber daya yang dimuat dari
    -+  jaringan. Periksa perubahan konfigurasi bila aplikasi melanjutkan dari status dihentikan
    -+  sementara.
    -+    <p class="note">
    -+      <strong>Catatan:</strong> Catatan: Jika Anda meng-cache data yang bergantung pada konfigurasi, ada
    -+      baiknya untuk menyertakan metadata yang relevan seperti ukuran layar
    -+      atau kepadatan piksel yang sesuai untuk data tersebut. Menyimpan metadata ini memungkinkan Anda untuk
    -+      memutuskan apakah Anda perlu segarkan data cache setelah perubahan
    -+      konfigurasi.
    -+    </p>
    -+  </li>
    -+
    -+  <li>Hindari menetapkan dimensi dengan satuan px, karena satuan ini tidak diskalakan dengan
    -+  kepadatan layar. Sebagai gantinya, tetapkan dimensi dengan satuan <a href="{@docRoot}guide/practices/screens_support.html">piksel yang tidak bergantung kepadatan
    -+  </a> (<code>dp</code>).
    -+  </li>
    -+</ul>
    -+
    -+<h3 id="vision-settings">Vision Settings di Setup Wizard</h3>
    -+
    -+<p>
    -+  Android N menyertakan Vision Settings di layar Sambutan, di mana pengguna bisa
    -+  menyiapkan setelan aksesibilitas berikut pada perangkat baru:
    -+  <strong>Magnification gesture</strong>, <strong>Font size</strong>,
    -+  <strong>Display size</strong> dan <strong>TalkBack</strong>. Perubahan ini
    -+  meningkatkan visibilitas bug terkait dengan setelan layar yang berbeda. Untuk
    -+  mengurangi dampak fitur ini, Anda harus menguji aplikasi dengan setelan ini
    -+  diaktifkan. Anda bisa menemukannya pada <strong>Settings &gt;
    -+  Accessibility</strong>.
    -+</p>
    -+
    -+<h2 id="ndk">Penautan Aplikasi NDK ke Pustaka Platform</h2>
    -+
    -+<p>
    -+  Android N menyertakan perubahan ruang nama untuk mencegah pemuatan API non-publik.
    -+  Jika menggunakan NDK, Anda hanya boleh menggunakan API publik dari platform
    -+  Android. Menggunakan API non-publik dalam rilis Android resmi berikutnya
    -+  bisa menyebabkan aplikasi mogok.
    -+</p>
    -+
    -+<p>
    -+  Untuk memberi tahu Anda agar menggunakan API non-publik, aplikasi yang berjalan pada perangkat
    -+  Android N akan menghasilkan kesalahan dalam keluaran logcat bila aplikasi memanggil API non-publik.
    -+  Kesalahan ini juga ditampilkan di layar perangkat berupa pesan untuk membantu
    -+  meningkatkan kepedulian terhadap situasi ini. Anda harus memeriksa kode aplikasi untuk
    -+  membuang penggunaan API platform non-publik dan secara saksama menguji aplikasi Anda menggunakan
    -+  perangkat pratinjau atau emulator.
    -+</p>
    -+
    -+<p>
    -+  Jika aplikasi Anda bergantung pada pustaka platform, lihat dokumentasi NDK untuk
    -+  perbaikan tipikal guna menggantikan API privat umum dengan padanan API publik.
    -+  Anda mungkin juga menautkan ke pustaka platform tanpa menyadarinya,
    -+  terutama jika aplikasi Anda menggunakan pustaka yang merupakan bagian dari platform ini (seperti
    -+  <code>libpng</code>), namun bukan bagian dari NDK. Dalam hal itu, pastikan
    -+  APK Anda berisi semua file .so yang ingin ditautkan.
    -+</p>
    -+
    -+<p class="caution">
    -+  <strong>Perhatian:</strong> Beberapa pustaka pihak ketiga mungkin menautkan ke API
    -+  non-publik. Jika menggunakan pustaka ini, aplikasi Anda bisa mogok saat dijalankan
    -+  pada rilis resmi Android berikutnya.
    -+</p>
    -+
    -+<p>
    -+  Aplikasi tidak boleh bergantung pada atau menggunakan pustaka bawaan yang tidak disertakan dalam
    -+  NDK, karena bisa mengalami perubahan, atau dipindahkan dari satu rilis Android ke
    -+  rilis lainnya. Peralihan dari OpenSSL ke BoringSSL merupakan satu contoh dari perubahan semacam ini.
    -+  Selain itu, perangkat yang berbeda bisa menawarkan tingkat kompatibilitas yang berbeda, karena
    -+   tidak ada persyaratan kompatibilitas untuk pustaka platform yang tidak disertakan
    -+  dalam NDK. Jika Anda harus mengakses pustaka non-NDK pada perangkat yang lebih lama, jadikan
    -+  pemuatan bergantung pada level Android API.
    -+</p>
    -+
    -+<p>
    -+  Untuk membantu Anda mendiagnosis tipe masalah ini ada beberapa contoh kesalahan Java dan NDK
    -+  yang mungkin Anda temui saat berusaha membangun aplikasi dengan Android N:
    -+</p>
    -+
    -+<p>Contoh kesalahan Java:</p>
    -+<pre class="no-pretty-print">
    -+java.lang.UnsatisfiedLinkError: dlopen failed: library "/system/lib/libcutils.so"
    -+    is not accessible for the namespace "classloader-namespace"
    -+</pre>
    -+
    -+<p>Contoh kesalahan NDK:</p>
    -+<pre class="no-pretty-print">
    -+dlopen failed: cannot locate symbol "__system_property_get" referenced by ...
    -+</pre>
    -+
    -+
    -+<p>
    -+  Inilah beberapa perbaikan tipikal untuk aplikasi yang mengalami tipe kesalahan ini:
    -+</p>
    -+
    -+<ul>
    -+  <li>Penggunaan getJavaVM dan getJNIEnv dari libandroid_runtime.so bisa diganti
    -+  dengan fungsi JNI standar:
    -+<pre class="no-pretty-print">
    -+AndroidRuntime::getJavaVM -&gt; GetJavaVM from &lt;jni.h&gt;
    -+AndroidRuntime::getJNIEnv -&gt; JavaVM::GetEnv or
    -+JavaVM::AttachCurrentThread from &lt;jni.h&gt;.
    -+</pre>
    -+  </li>
    -+
    -+  <li>Penggunaan simbol {@code property_get} dari {@code libcutils.so} bisa
    -+    diganti dengan {@code alternative __system_property_get} publik.
    -+   Caranya, gunakan {@code __system_property_get} dengan menyertakan yang berikut:
    -+<pre>
    -+#include &lt;sys/system_properties.h&gt;
    -+</pre>
    -+  </li>
    -+
    -+  <li>Penggunaan simbol {@code SSL_ctrl} dari {@code libcrypto.so} harus
    -+    diganti dengan aplikasi versi lokal. Misalnya, Anda harus menautkan
    -+  {@code libcyrpto.a} secara statis dalam file {@code .so} atau menyertakan
    -+  {@code libcrypto.so} Anda sendiri secara dinamis dari BoringSSL atau OpenSSL dalam aplikasi Anda.
    -+  </li>
    -+</ul>
    -+
    -+<h2 id="afw">Android for Work</h2>
    -+<p>
    -+  Android N berisi perubahan untuk aplikasi yang menargetkan Android for Work, termasuk
    -+  perubahan pada pemasangan sertifikat, penyetelan ulang sandi, manajemen pengguna
    -+  tambahan, dan akses ke identifier perangkat. Jika Anda membangun aplikasi untuk
    -+  lingkungan Android for Work, Anda harus meninjau perubahan ini dan memodifikasi
    -+  aplikasi sebagaimana mestinya.
    -+</p>
    -+
    -+<ul>
    -+  <li>Anda harus pasang pemasang sertifikat yang didelegasikan sebelum DPC bisa
    -+  menyetelnya. Untuk aplikasi profil dan aplikasi pemilik perangkat yang menargetkan N SDK, Anda harus
    -+  pasang pemasang sertifikat yang didelegasikan sebelum pengontrol kebijakan
    -+  perangkat (DPC) memanggil
    -+  <code>DevicePolicyManager.setCertInstallerPackage()</code>. Jika pemasang
    -+  belum dipasang, sistem akan melontarkan
    -+  <code>IllegalArgumentException</code>.
    -+  </li>
    -+
    -+  <li>Pembatasan sandi penyetelan ulang untuk admin perangkat sekarang diterapkan ke pemilik
    -+  profil. Admin perangkat tidak bisa lagi menggunakan
    -+  {@code DevicePolicyManager.resetPassword()} untuk menghapus sandi atau mengubah
    -+  sandi yang sudah disetel. Admin perangkat tetap bisa menyetel sandi, namun hanya
    -+  bila perangkat belum memiliki sandi, PIN, atau pola.
    -+  </li>
    -+
    -+  <li>Pemilik perangkat dan profil bisa mengelola akun meskipun pembatasan
    -+  telah disetel. Pemilik perangkat dan pemilik profil bisa memanggil Account Management API
    -+  sekalipun pembatasan pengguna <code>DISALLOW_MODIFY_ACCOUNTS</code> diberlakukan.
    -+  </li>
    -+
    -+  <li>Pemilik perangkat bisa mengelola pengguna tambahan lebih mudah. Bila perangkat
    -+  berjalan dalam mode pemilik perangkat, maka pembatasan <code>DISALLOW_ADD_USER</code>
    -+  secara otomatis akan ditetapkan. Ini mencegah pengguna membuat pengguna tambahan yang
    -+  tidak terkelola. Selain itu, <code>CreateUser()</code> dan
    -+  <code>createAndInitializeUser()</code> metode tidak digunakan lagi; metode
    -+  <code>DevicePolicyManager.createAndManageUser()</code> telah menggantikannya.
    -+  </li>
    -+
    -+  <li>Pemilik perangkat bisa mengakses identifier perangkat. Pemilik perangkat bisa mengakses
    -+  alamat MAC Wi-Fi dari perangkat, menggunakan
    -+  <code>DevicePolicyManagewr.getWifiMacAddress()</code>. Jika Wi-Fi belum pernah
    -+  diaktifkan pada perangkat tersebut, metode ini akan mengembalikan nilai {@code null}.
    -+  </li>
    -+
    -+  <li>Setelan Mode Kerja mengontrol akses ke aplikasi kerja. Bila mode kerja tidak aktif, peluncur sistem
    -+  akan menunjukkan aplikasi kerja tidak tersedia dengan membuat warnanya jadi abu-abu. Mengaktifkan kembali
    -+ mode kerja akan memulihkan perilaku normal.
    -+</ul>
    -+
    -+<p>
    -+  Untuk informasi selengkapnya tentang perubahan Android for Work di Android N, lihat
    -+  <a href="{@docRoot}preview/features/afw.html">Pembaruan Android for Work</a>.
    -+</p>
    -+
    -+<h2 id="annotations">Retensi Anotasi</h2>
    -+
    -+<p>
    -+Android N memperbaiki bug dengan visibilitas anotasi diabaikan.
    -+Masalah ini mengaktifkan waktu proses untuk mengakses anotasi yang seharusnya tidak bisa
    -+dilakukan. Anotasi ini termasuk:
    -+</p>
    -+
    -+<ul>
    -+   <li>{@code VISIBILITY_BUILD}: Dimaksudkan agar hanya bisa terlihat pada waktu pembuatan.</li>
    -+   <li>{@code VISIBILITY_SYSTEM}: Dimaksud agar bisa terlihat pada waktu proses, namun hanya pada
    -+ sistem yang mendasarinya.</li>
    -+</ul>
    -+
    -+<p>
    -+Jika aplikasi Anda mengandalkan perilaku ini, tambahkan kebijakan retensi untuk anotasi yang harus
    -+tersedia di waktu proses. Caranya dengan menggunakan {@code @Retention(RetentionPolicy.RUNTIME)}.
    -+</p>
    -+
    -+<h2 id="other">Poin Penting Lainnya</h2>
    -+
    -+<ul>
    -+<li>Bila aplikasi berjalan pada Android N, namun menargetkan level API yang lebih rendah,
    -+dan pengguna mengubah ukuran tampilan, proses aplikasi akan dimatikan. Aplikasi
    -+harus dapat menangani skenario ini dengan lancar. Jika tidak, maka akan mogok
    -+bila pengguna memulihkannya dari Recents.
    -+
    -+<p>
    -+Anda harus menguji aplikasi untuk memastikan
    -+perilaku ini tidak terjadi.
    -+Anda bisa melakukannya dengan menyebabkan suatu mogok yang identik
    -+saat mematikan aplikasi secara manual melalui DDMS.
    -+</p>
    -+
    -+<p>
    -+Aplikasi yang menargetkan N dan yang di atasnya tidak secara otomatis dimatikan saat perubahan kepadatan;
    -+akan tetapi, aplikasi tersebut mungkin tetap merespons perubahan konfigurasi dengan buruk.
    -+</p>
    -+</li>
    -+
    -+<li>
    -+Aplikasi pada Android N harus mampu menangani perubahan konfigurasi dengan lancar,
    -+dan tidak boleh mengalami mogok pada start selanjutnya. Anda bisa memverifikasi perilaku aplikasi
    -+dengan mengubah ukuran font (<strong>Setting</strong> &gt;
    -+<strong>Display</strong> &gt; <strong>Font size</strong>), kemudian memulihkan
    -+aplikasi dari Recents.
    -+</li>
    -+
    -+<li>
    -+Dikarenakan adanya bug di versi Android sebelumnya, sistem tidak menandai penulisan
    -+  ke soket TCP di thread utama sebagai pelanggaran mode-ketat. Android N memperbaiki bug ini.
    -+Aplikasi yang menunjukkan perilaku ini kini melontarkan sebuah {@code android.os.NetworkOnMainThreadException}.
    -+Secara umum, melakukan operasi jaringan di thread utama tidak baik karena operasi ini
    -+biasanya memiliki latensi tinggi yang menyebabkan ANR dan jank.
    -+</li>
    -+
    -+<li>
    -+Kelompok metode {@code Debug.startMethodTracing()} kini default ke
    -+keluaran penyimpanan di direktori paket tertentu di penyimpanan bersama,
    -+sebagai ganti di level teratas
    -+kartu SD.  Berarti aplikasi tidak perlu lagi meminta izin {@code WRITE_EXTERNAL_STORAGE} untuk menggunakan API ini.
    -+</li>
    -+
    -+<li>
    -+Banyak platform API yang kini mulai memeriksa beban besar yang dikirim
    -+ke seluruh transaksi {@link android.os.Binder}, dan sistem
    -+kini melontarkan kembali {@code TransactionTooLargeExceptions}
    -+sebagai {@code RuntimeExceptions}, sebagai ganti logging secara diam-diam atau menyembunyikannya.  Satu contoh
    -+umum adalah menyimpan terlalu banyak data di
    -+{@link android.app.Activity#onSaveInstanceState Activity.onSaveInstanceState()},
    -+yang menyebabkan {@code ActivityThread.StopInfo} melontarkan
    -+{@code RuntimeException} bila aplikasi Anda menargetkan Android N.
    -+</li>
    -+
    -+<li>
    -+Jika sebuah aplikasi mengeposkan tugas {@link java.lang.Runnable} ke{@link android.view.View}, dan
    -+{@link android.view.View}
    -+tidak terpasang ke jendela, sistem
    -+akan mengantrekan tugas {@link java.lang.Runnable} dengan {@link android.view.View};
    -+tugas {@link java.lang.Runnable} tidak akan dieksekusi hingga
    -+{@link android.view.View} terpasang
    -+ke jendela. Perilaku ini mengatasi bug berikut:
    -+<ul>
    -+   <li>Jika sebuah aplikasi mengeposkan ke {@link android.view.View} dari thread selain thread UI jendela yang dimaksud,
    -+    maka {@link java.lang.Runnable} mungkin akan menjalankan thread yang salah.
    -+   </li>
    -+   <li>Jika tugas {@link java.lang.Runnable} diposkan dari thread selain
    -+   looper-thread, aplikasi bisa mengekspos tugas {@link java.lang.Runnable}.</li>
    -+</ul>
    -+</li>
    -+
    -+<li>
    -+Jika sebuah aplikasi di Android N dengan
    -+izin{@link android.Manifest.permission#DELETE_PACKAGES DELETE_PACKAGES}
    -+mencoba menghapus sebuah paket, namun sebuah aplikasi berbeda telah memasang paket itu,
    -+sistem akan memerlukan konfirmasi pengguna. Dalam skenario ini, aplikasi harus mengharapkan
    -+{@link android.content.pm.PackageInstaller#STATUS_PENDING_USER_ACTION STATUS_PENDING_USER_ACTION}
    -+sebagai status kembalian bila memanggil
    -+{@link android.content.pm.PackageInstaller#uninstall PackageInstaller.uninstall()}.
    -+</li>
    -+
    -+</ul>
    -+
    -diff --git a/docs/html-intl/intl/id/about/versions/nougat/android-7.0-samples.jd b/docs/html-intl/intl/id/about/versions/nougat/android-7.0-samples.jd
    -new file mode 100644
    -index 0000000..d31c0c0
    ---- /dev/null
    -+++ b/docs/html-intl/intl/id/about/versions/nougat/android-7.0-samples.jd
    -@@ -0,0 +1,85 @@
    -+page.title=Contoh
    -+page.tags="preview", "samples", "android"
    -+page.image=images/cards/card-n-samples_2x.png
    -+@jd:body
    -+
    -+<p>
    -+  Contoh kode berikut disediakan untuk Android N. Untuk
    -+  mengunduh contoh di Android Studio, pilih opsi menu <b>File &gt; Import
    -+  Samples</b>.
    -+</p>
    -+
    -+<p class="note">
    -+  <strong>Catatan:</strong> Proyek yang bisa diunduh ini didesain
    -+   untuk digunakan bersama Gradle dan Android Studio.
    -+</p>
    -+
    -+
    -+<h3 id="mw">Playground Multi-Jendela</h3>
    -+<img src="{@docRoot}images/android-7.0/sample-multiwindow.png" style="float: left; padding-right: 0.5em" height="250" width="156" />
    -+<p>
    -+  Contoh ini memperagakan cara memanfaatkan antarmuka pengguna
    -+  multi-jendela bersama aplikasi Anda.
    -+</p>
    -+<p>
    -+  <a href="https://github.com/googlesamples/android-MultiWindowPlayground">
    -+  Dapatkan di GitHub</a>
    -+</p>
    -+
    -+<div style="clear: both;"></div>
    -+<h3 id="an">Pemberitahuan Aktif</h3>
    -+<img src="{@docRoot}images/android-7.0/sample-activenotifications.png" style="float: left; padding-right: 0.5em" height="250" width="141" />
    -+<p>
    -+  Ini adalah contoh yang sudah ada sebelumnya, menampilkan layanan sederhana yang mengirimkan
    -+   pemberitahuan menggunakan NotificationCompat. Setiap percakapan yang belum dibaca dari pengguna
    -+  dikirimkan sebagai pemberitahuan berbeda.
    -+</p>
    -+<p>
    -+  Contoh ini telah diperbarui untuk memanfaatkan fitur pemberitahuan baru
    -+  yang tersedia di Android N.
    -+</p>
    -+<p>
    -+  <a href="https://github.com/googlesamples/android-ActiveNotifications">
    -+  Dapatkan di GitHub</a>
    -+</p>
    -+
    -+<div style="clear: both;"></div>
    -+<h3 id="ms">Layanan Perpesanan</h3>
    -+<img src="{@docRoot}images/android-7.0/sample-messagingservice.png" style="float: left; padding-right: 0.5em" height="250" width="150" />
    -+<p>
    -+  Ini adalah contoh yang telah ada sebelumnya yang memperagakan cara menggunakan
    -+  NotificationManager untuk memberi tahu jumlah pemberitahuan yang saat ini ditampilkan
    -+  oleh aplikasi.
    -+</p>
    -+<p>
    -+  Contoh ini telah diperbarui untuk memanfaatkan fitur pemberitahuan baru
    -+  yang tersedia di Android N.
    -+</p>
    -+<p>
    -+  <a href="https://github.com/googlesamples/android-MessagingService">
    -+  Dapatkan di GitHub</a>
    -+</p>
    -+
    -+<div style="clear: both;"></div>
    -+<h3 id="fbe">Direct Boot</h3>
    -+<img src="{@docRoot}images/android-7.0/sample-directboot.png" style="float: left; padding-right: 0.5em" height="250" width="141" />
    -+<p>
    -+  Contoh ini memperagakan cara menyimpan dan mengakses data dalam penyimpanan yang dienkripsi
    -+  dengan perangkat yang selalu tersedia saat perangkat booting.
    -+</p>
    -+<p>
    -+  <a href="https://github.com/googlesamples/android-DirectBoot">
    -+  Dapatkan di GitHub</a>
    -+</p>
    -+
    -+<div style="clear: both;"></div>
    -+<h3 id="sda">Scoped Directory Access</h3>
    -+<img src="{@docRoot}images/android-7.0/sample-scopeddirectoryaccess.png" style="float: left; padding-right: 0.5em" height="250" width="141" />
    -+<p>
    -+  Contoh ini memperagakan cara membaca dan menulis data dari direktori
    -+  spesifik, sekaligus meminta izin lebih sedikit.
    -+</p>
    -+<p>
    -+  <a href="https://github.com/googlesamples/android-ScopedDirectoryAccess">
    -+  Dapatkan di GitHub</a>
    -+</p>
    -diff --git a/docs/html-intl/intl/id/about/versions/nougat/android-7.0.jd b/docs/html-intl/intl/id/about/versions/nougat/android-7.0.jd
    -new file mode 100644
    -index 0000000..ff8af12
    ---- /dev/null
    -+++ b/docs/html-intl/intl/id/about/versions/nougat/android-7.0.jd
    -@@ -0,0 +1,1039 @@
    -+page.title=Android N for Developers
    -+meta.tags="preview", "androidn"
    -+page.tags="preview", "developer preview"
    -+page.image=images/cards/card-n-apis_2x.png
    -+@jd:body
    -+
    -+
    -+
    -+
    -+<div id="tb-wrapper">
    -+<div id="tb">
    -+  <h2>Fitur-fitur Utama bagi Pengembang</h2>
    -+  <ol>
    -+      <ul style="list-style-type:none;">
    -+        <li><a href="#multi-window_support">Dukungan Multi-Jendela</a></li>
    -+        <li><a href="#notification_enhancements">Pemberitahuan</a></li>
    -+        <li><a href="#jit_aot">Kompilasi JIT/AOT</a></li>
    -+        <li><a href="#quick_path_to_app_install">Jalur Cepat untuk Pasang Aplikasi</a></li>
    -+        <li><a href="#doze_on_the_go">Istirahatkan Kapan Saja</a></li>
    -+        <li><a href="#background_optimizations">Optimalisasi Latar Belakang</a></li>
    -+        <li><a href="#data_saver">Data Saver</a></li>
    -+        <li><a href="#vulkan">Vulkan API</a></li>
    -+        <li><a href="#tile_api">Quick Settings Tile API</a></li>
    -+        <li><a href="#number-blocking">Pemblokiran Nomor</a></li>
    -+        <li><a href="#call_screening">Penyaringan Panggilan</a></li>
    -+        <li><a href="#multi-locale_languages">Lokal dan Bahasa</a></li>
    -+        <li><a href="#emoji">Emoji Baru</a></li>
    -+        <li><a href="#icu4">ICU4J API di Android</a></li>
    -+        <li><a href="#gles_32">OpenGL ES 3.2 API</a></li>
    -+        <li><a href="#android_tv_recording">Perekaman Android TV</a></li>
    -+        <li><a href="#android_for_work">Android for Work</a></li>
    -+        <li><a href="#accessibility_enhancements">Aksesibilitas</a></li>
    -+        <li><a href="#direct_boot">Direct Boot</a></li>
    -+        <li><a href="#key_attestation">Key Attestation</a></li>
    -+        <li><a href="#network_security_config">Network Security Config</a></li>
    -+        <li><a href="#default_trusted_ca">CA Tepercaya Default</a></li>
    -+        <li><a href="#apk_signature_v2">APK Signature Scheme V2</a></li>
    -+        <li><a href="#scoped_directory_access">Scoped Directory Access</a></li>
    -+        <li><a href="#keyboard_shortcuts_helper">Keyboard Shortcuts Helper</a></li>
    -+        <li><a href="#sustained_performance_api">Sustained Performance API</a></li>
    -+        <li><a href="#vr">Dukungan VR</a></li>
    -+        <li><a href="#print_svc">Penyempurnaan Layanan Cetak</a></li>
    -+        <li><a href="#virtual_files">File Maya</a></li>
    -+        <li><a href="#framemetrics_api">FrameMetricsListener API</a></li>
    -+      </ol>
    -+</div>
    -+</div>
    -+
    -+
    -+
    -+<p>Android N masih dalam pengembangan aktif, namun Anda bisa mencobanya
    -+sekarang sebagai bagian dari N Developer Preview. Bagian-bagian di bawah ini akan menyoroti sebagian dari
    -+fitur baru untuk pengembang. </p>
    -+
    -+<p>
    -+  Pastikan memeriksa <a href="{@docRoot}preview/behavior-changes.html">Perubahan Perilaku</a> untuk mengetahui selengkapnya tentang
    -+  bagian-bagian perubahan platform yang bisa memengaruhi aplikasi Anda, lihatlah
    -+  panduan pengembang untuk mengetahui selengkapnya tentang fitur-fitur utama, dan unduh <a href="{@docRoot}preview/setup-sdk.html#docs-dl">Referensi API</a> untuk mengetahui detail tentang
    -+  API baru.
    -+</p>
    -+
    -+<h2 id="multi-window_support">Dukungan Multi-Jendela</h2>
    -+
    -+
    -+<p>Di Android N, kami memperkenalkan fitur multitasking baru dan yang banyak diminta
    -+ke dalam platform &mdash; dukungan multi-jendela. </p>
    -+
    -+  <p>Pengguna sekarang bisa membuka dua aplikasi sekaligus di layar. </p>
    -+  <ul>
    -+  <li>Pada ponsel dan tablet
    -+yang menjalankan Android N, pengguna bisa menjalankan dua aplikasi secara berdampingan atau
    -+satu aplikasi di atas yang lain dalam mode layar terbagi. Pengguna bisa mengubah ukuran aplikasi dengan menyeret
    -+pembagi di antara keduanya. </li>
    -+
    -+<li>Pada perangkat Android TV, aplikasi bisa menempatkan dirinya sendiri dalam <a href="{@docRoot}preview/features/picture-in-picture.html">mode
    -+gambar-dalam-gambar</a>, sehingga aplikasi bisa terus menampilkan materi sementara pengguna menjelajahi atau
    -+berinteraksi dengan aplikasi lain.</li>
    -+  </ul>
    -+
    -+<div class="col-4of10">
    -+<img src="{@docRoot}images/android-7.0/mw-portrait.png" alt="" style="height:460px;padding-left:1em;" id="img-split-screen" />
    -+<p class="img-caption">
    -+  <strong>Gambar 1.</strong> Aplikasi yang berjalan dalam mode layar terbagi.
    -+</p>
    -+
    -+  </div>
    -+
    -+<p>Khususnya pada tablet dan perangkat yang berlayar lebih besar lainnya, dukungan multi-jendela
    -+memberi Anda cara baru untuk memikat pengguna. Anda bahkan bisa mengaktifkan fitur seret-dan-lepas di
    -+aplikasi untuk memudahkan pengguna menyeret materi ke dan dari aplikasi &mdash; cara bagus
    -+untuk menyempurnakan pengalaman pengguna Anda. </p>
    -+
    -+<p>Tidak sulit menambahkan dukungan multi-jendela ke aplikasi Anda dan mengonfigurasi cara
    -+menangani tampilan multi-jendela. Misalnya, Anda bisa menetapkan dimensi
    -+minimum yang diizinkan aktivitas, sehingga mencegah pengguna mengubah ukuran aktivitas di bawah
    -+ukuran itu. Anda juga bisa menonaktifkan tampilan multi-jendela untuk aplikasi Anda, yang
    -+  akan memastikan sistem hanya menampilkan aplikasi dalam mode layar penuh.</p>
    -+
    -+<p>
    -+  Untuk informasi selengkapnya, lihat dokumentasi pengembang <a href="{@docRoot}preview/features/multi-window.html">Dukungan Multi-Jendela</a>.
    -+
    -+</p>
    -+
    -+<h2 id="notification_enhancements">Penyempurnaan Pemberitahuan</h2>
    -+
    -+<p>Di Android N kami telah mengubah desain pemberitahuan agar lebih mudah dan lebih cepat
    -+digunakan. Beberapa perubahan tersebut antara lain:</p>
    -+
    -+<ul>
    -+  <li>
    -+    <strong>Pembaruan template</strong>: Kami telah memperbarui template pemberitahuan untuk
    -+    lebih menekankan citra pahlawan dan avatar. Pengembang akan dapat
    -+   memanfaatkan template baru dengan penyesuaian kode yang minimal.
    -+  </li>
    -+
    -+  <li>
    -+    <strong>Penyesuaian gaya pesan</strong>: Anda bisa menyesuaikan lebih banyak
    -+    label antarmuka pengguna yang berkaitan dengan pemberitahuan Anda menggunakan kelas
    -+    <code>MessageStyle</code>. Anda bisa mengonfigurasi pesan, judul percakapan,
    -+    dan tampilan materi.
    -+  </li>
    -+
    -+  <li>
    -+    <strong>Bundel pemberitahuan</strong>: Sistem bisa mengelompokkan pesan,
    -+    misalnya menurut topik pesan, dan menampilkan kelompok pesan tersebut. Seorang pengguna bisa
    -+   bertindak, misalnya Tutup atau Arsipkan, atas pesan yang ditampilkan. Jika Anda sudah
    -+    mengimplementasikan pemberitahuan untuk Android Wear, Anda akan terbiasa dengan
    -+    model ini.
    -+  </li>
    -+
    -+  <li>
    -+    <strong>Balasan Langsung</strong>: Untuk aplikasi komunikasi real-time, sistem
    -+    Android mendukung balasan inline sehingga pengguna bisa dengan cepat membalas
    -+    SMS atau pesan teks secara langsung dari dalam antarmuka pemberitahuan.
    -+  </li>
    -+
    -+  <li>
    -+    <strong>Tampilan khusus</strong>: Dua API baru memungkinkan Anda memanfaatkan dekorasi sistem,
    -+    misalnya header pemberitahuan dan tindakan, saat menggunakan tampilan
    -+    khusus dalam pemberitahuan.
    -+  </li>
    -+</ul>
    -+
    -+<div class="col-4of12">
    -+  <img src="{@docRoot}images/android-7.0/notifications-1.png" alt="" style="padding:.5em;max-width:226px">
    -+</div>
    -+
    -+<div class="col-4of12">
    -+  <img src="{@docRoot}images/android-7.0/notifications-3.png" alt="" style="padding:.5em;max-width:226px">
    -+</div>
    -+
    -+<div class="col-4of12">
    -+  <img src="{@docRoot}images/android-7.0/notifications-2.png" alt="" style="padding:.5em;max-width:226px">
    -+</div>
    -+
    -+
    -+<p class="img-caption">
    -+  <strong>Gambar 2.</strong> Bundel pemberitahuan dan balasan langsung.
    -+</p>
    -+
    -+<p>Untuk mengetahui cara mengimplementasikan fitur-fitur
    -+  baru ini, lihat panduan <a href="{@docRoot}preview/features/notification-updates.html">Pemberitahuan</a>.
    -+</p>
    -+
    -+
    -+
    -+<h2 id="jit_aot">Kompilasi JIT/AOT yang dipandu profil</h2>
    -+
    -+<p>Di Android N, kami telah menambahkan compiler Just in Time (JIT) dengan pembuatan profil kode ke
    -+ART, yang memungkinkannya terus meningkatkan kinerja aplikasi Android saat
    -+dijalankan. Compiler JIT melengkapi compiler Ahead of Time (AOT) pada ART
    -+dan membantu memperbaiki kinerja waktu proses, menghemat ruang penyimpanan, dan mempercepat
    -+pembaruan aplikasi serta pembaruan sistem.</p>
    -+
    -+<p>Kompilasi yang dipandu profil memungkinkan ART mengelola kompilasi AOT/JIT untuk setiap aplikasi
    -+sesuai dengan penggunaan sebenarnya, serta kondisi pada perangkat. Misalnya
    -+,ART menyimpan profil setiap metode terbaik aplikasi dan bisa melakukan kompilasi lebih awal
    -+serta menyimpan sementara metode-metode tersebut di cache untuk mendapatkan kinerja terbaik. Hal ini membuat bagian lain dari aplikasi
    -+dibiarkan tidak dikompilasi hingga benar-benar digunakan.</p>
    -+
    -+<p>Di samping meningkatkan kinerja bagian-bagian penting aplikasi, kompilasi yang dipandu profil
    -+membantu mengurangi footprint RAM keseluruhan aplikasi, termasuk biner
    -+terkait. Fitur ini terutama penting pada perangkat dengan memori minim.</p>
    -+
    -+<p>ART mengelola kompilasi yang dipandu profil dengan cara yang meminimalkan dampak terhadap
    -+baterai perangkat. ART melakukan prakompilasi hanya bila perangkat sedang diam dan
    -+mengisi daya, sehingga menghemat waktu dan baterai dengan melakukan pekerjaan tersebut di awal.</p>
    -+
    -+<h2 id="quick_path_to_app_install">Jalur Cepat untuk Pasang Aplikasi</h2>
    -+
    -+<p>Salah satu manfaat paling nyata dari compiler JIT pada ART adalah kecepatan
    -+pemasnagan aplikasi dan pembaruan sistem. Bahkan aplikasi besar yang membutuhkan beberapa menit untuk
    -+dioptimalkan dan dipasang di Android 6.0 sekarang bisa dipasang hanya dalam hitungan
    -+detik. Pembaruan sistem juga lebih cepat, karena tidak ada lagi langkah optimalisasi. </p>
    -+
    -+<h2 id="doze_on_the_go">Istirahatkan Kapan Saja...</h2>
    -+
    -+<p>Android 6.0 memperkenalkan Istirahatkan, yaitu mode sistem yang menghemat baterai dengan menangguhkan
    -+aktivitas CPU dan jaringan di aplikasi bila perangkat sedang diam, misalnya saat
    -+diletakkan di atas meja atau dalam laci. </p>
    -+
    -+<p>Sekarang di Android N, Istirahatkan selangkah lebih maju dalam menghemat baterai kapan saja.
    -+Setiap kali layar mati dalam jangka waktu tertentu dan perangkat tidak terhubung ke sumber daya,
    -+Istirahatkan akan menerapkan subset pembatasan umum CPU dan jaringan pada aplikasi.
    -+Artinya pengguna bisa menghemat daya baterai meskipun perangkat dibawa di dalam
    -+tasnya.</p>
    -+
    -+
    -+<img src="/preview/images/doze-diagram-1.png" alt="" id="figure1" />
    -+<p class="img-caption">
    -+  <strong>Gambar 3.</strong> Istirahatkan sekarang menerapkan
    -+  pembatasan untuk meningkatkan daya tahan baterai bahkan saat perangkat sedang tidak diam.
    -+</p>
    -+
    -+
    -+<p>Tidak lama setelah layar dimatikan saat perangkat menggunakan daya baterai, Istirahatkan
    -+akan membatasi akses jaringan serta menangguhkan pekerjaan dan sinkronisasi. Selama jeda
    -+pemeliharaan, aplikasi diizinkan mengakses jaringan dan menjalankan semua
    -+pekerjaan/sinkronisasi yang ditangguhkan. Menyalakan layar atau mencolokkan perangkat akan mengeluarkan
    -+perangkat dari Istirahatkan.</p>
    -+
    -+<p>Bila perangkat dalam kondisi diam lagi, dengan layar mati dan menggunakan daya baterai selama
    -+jangka waktu tertentu, Istirahatkan akan menerapkan pembatasan CPU dan jaringan pada {@link
    -+android.os.PowerManager.WakeLock}, alarm {@link android.app.AlarmManager}, dan
    -+pemindaian GPS/Wi-Fi.</p>
    -+
    -+<p>Praktik terbaik untuk menyesuaikan aplikasi Anda dengan Istirahatkan adalah sama, baik
    -+perangkat sedang bergerak maupun diam, jadi jika Anda sudah memperbarui aplikasi untuk
    -+menjalankan Istirahatkan dengan lancar, berarti Anda sudah siap. Jika belum, mulailah <a href="{@docRoot}training/monitoring-device-state/doze-standby.html#assessing_your_app">menyesuaikan
    -+aplikasi Anda dengan Istirahatkan</a> sekarang juga.</p>
    -+
    -+<h2 id="background_optimizations">Project Svelte: Optimalisasi Latar Belakang</h2>
    -+
    -+<p>Project Svelte merupakan upaya berkelanjutan untuk meminimalkan penggunaan RAM oleh sistem dan aplikasi
    -+di semua jenis perangkat Android dalam ekosistem. Di Android N, Project
    -+Svelte berfokus pada optimalisasi cara aplikasi berjalan di latar belakang. </p>
    -+
    -+<p>Proses latar belakang merupakan bagian terpenting dari sebagian besar aplikasi. Bila ditangani dengan benar, proses
    -+ini bisa memberikan pengalaman pengguna yang mengagumkan &mdash; segera, cepat, dan sesuai konteks.
    -+Bila tidak ditangani dengan benar, proses latar belakang bisa menguras RAM (dan
    -+baterai) yang sebenarnya tidak perlu serta memengaruhi kinerja sistem untuk aplikasi lain. </p>
    -+
    -+<p>Sejak Android 5.0, {@link android.app.job.JobScheduler} telah menjadi
    -+cara yang disukai untuk melakukan pekerjaan latar belakang dengan cara yang baik
    -+bagi pengguna. Aplikasi bisa menjadwalkan pekerjaan sekaligus memungkinkan sistem mengoptimalkan berdasarkan
    -+kondisi memori, daya, dan konektivitas. JobScheduler menawarkan kontrol serta
    -+kemudahan, dan kami ingin semua aplikasi menggunakannya. </p>
    -+
    -+<p>
    -+  Opsi baik lainnya adalah <a href="https://developers.google.com/android/reference/com/google/android/gms/gcm/GcmNetworkManager">
    -+  <code>GCMNetworkManager</code></a>, bagian dari Google Play Services, yang
    -+  menawarkan penjadwalan pekerjaan serupa dengan kompatibilitas pada semua versi lawas
    -+  Android.
    -+</p>
    -+
    -+<p>Kami terus memperluas <code>JobScheduler</code> dan
    -+<code>GCMNetworkManager</code> untuk memenuhi lebih banyak
    -+kasus penggunaan Anda &mdash; misalnya, di Android N Anda sekarang bisa menjadwalkan pekerjaan
    -+latar belakang berdasarkan perubahan di Content Providers. Pada saat yang sama kami mulai
    -+menghilangkan beberapa pola lama yang bisa mengurangi kinerja sistem,
    -+terutama pada perangkat yang minim memori.</p>
    -+
    -+<p>Di Android N kami membuang tiga siaran implisit yang umum digunakan &mdash;
    -+ {@link android.net.ConnectivityManager#CONNECTIVITY_ACTION}, {@link
    -+  android.hardware.Camera#ACTION_NEW_PICTURE}, dan {@link
    -+  android.hardware.Camera#ACTION_NEW_VIDEO} &mdash; karena ketiganya bisa mengaktifkan
    -+proses latar belakang pada beberapa aplikasi sekaligus serta menguras memori dan baterai. Jika
    -+aplikasi Anda menerimanya, manfaatkan N Developer Preview untuk
    -+  beralih ke <code>JobScheduler</code> dan API terkait sebagai gantinya. </p>
    -+
    -+<p>
    -+  Lihat dokumentasi <a href="{@docRoot}preview/features/background-optimization.html">Optimalisasi
    -+  Latar Belakang</a> untuk mengetahui detailnya.
    -+</p>
    -+
    -+
    -+<h2 id="data_saver">Data Saver</h2>
    -+
    -+<div class="col-5of12" style="margin-right:1.5em;">
    -+<img src="{@docRoot}images/android-7.0/datasaver.png" style="border:2px solid #ddd">
    -+
    -+<p class="img-caption" style="padding-right:2em;">
    -+  <strong>Gambar 4.</strong> Data Saver di Settings.
    -+</p>
    -+  </div>
    -+
    -+<p>Selama penggunaan perangkat seluler, biaya paket data seluler biasanya
    -+  melebihi harga perangkat itu sendiri. Bagi banyak pengguna, data seluler adalah sumber daya
    -+mahal yang ingin mereka hemat. </p>
    -+
    -+<p>Android N memperkenalkan mode Data Saver, layanan sistem baru yang mengurangi
    -+penggunaan data seluler oleh aplikasi, baik saat roaming, mendekati akhir siklus tagihan,
    -+atau saat menggunakan paket data prabayar yang kecil. Data Saver memberi pengguna kemampuan mengontrol cara aplikasi
    -+menggunakan data seluler dan memungkinkan pengembang memberikan layanan yang lebih efisien bila Data
    -+Saver aktif. </p>
    -+
    -+<p>Bila pengguna mengaktifkan Data Saver di <strong>Settings</strong> dan perangkat
    -+dalam jaringan berkuota, sistem akan memblokir penggunaan data latar belakang dan memberi tahu aplikasi
    -+untuk menghemat penggunaan data latar depan &mdash; misalnya dengan membatasi
    -+kecepatan bit untuk streaming, mengurangi kualitas gambar, menangguhkan precaching optimistik,
    -+dan seterusnya. Pengguna bisa memasukkan aplikasi tertentu ke daftar putih untuk memungkinkan penggunaan data berkuota
    -+bila Data Saver diaktifkan.</p>
    -+
    -+<p>Android N memperluas {@link android.net.ConnectivityManager} untuk menyediakan cara pada aplikasi
    -+untuk <a href="{@docRoot}preview/features/data-saver.html#status">mengambil
    -+preferensi Data Saver pengguna</a> dan <a href="{@docRoot}preview/features/data-saver.html#monitor-changes">memantau
    -+perubahan preferensi</a>. Semua aplikasi harus memeriksa apakah pengguna telah mengaktifkan Data
    -+Saver dan berusaha membatasi penggunaan data latar belakang dan latar depan.</p>
    -+
    -+
    -+<h2 id="vulkan">Vulkan API</h2>
    -+
    -+<p>
    -+  Android N mengintegrasikan <a href="http://www.khronos.org/vulkan" class="external-link">Vulkan™</a>, sebuah API rendering 3D baru, ke dalam platform. Seperti
    -+  <a href="https://www.khronos.org/opengles/" class="external-link">OpenGL™
    -+  ES</a>, Vulkan merupakan standar terbuka untuk grafik 3D dan rendering yang dikelola
    -+  oleh Khronos Group.
    -+</p>
    -+
    -+<p>
    -+  Vulkan didesain dari nol untuk meminimalkan overhead CPU dalam driver,
    -+  dan memungkinkan aplikasi Anda mengontrol operasi GPU lebih langsung. Vulkan
    -+  juga memungkinkan paralelisasi yang lebih baik dengan mengizinkan beberapa thread menjalankan
    -+  pekerjaan seperti pembuatan buffer perintah sekaligus.
    -+</p>
    -+
    -+<p>
    -+  Pustaka dan alat pengembangan Vulkan telah dimasukkan ke dalam Android NDK. Ini
    -+  berisi:
    -+</p>
    -+
    -+<ul>
    -+  <li>Header
    -+  </li>
    -+
    -+  <li>Layer validasi (pustaka debug)
    -+  </li>
    -+
    -+  <li>SPIR-V shader compiler
    -+  </li>
    -+
    -+  <li>Pustaka kompilasi shader waktu proses SPIR-V
    -+  </li>
    -+</ul>
    -+
    -+<p>
    -+  Vulkan hanya tersedia untuk aplikasi pada perangkat dengan perangkat keras yang mendukung Vulkan,
    -+  seperti Nexus 5X, Nexus 6P, dan Nexus Player. Kami bekerja sama erat dengan mitra
    -+  agar secepatnya makin banyak perangkat yang dilengkapi Vulkan.
    -+</p>
    -+
    -+<p>
    -+  Untuk informasi selengkapnya, lihat <a href="{@docRoot}ndk/guides/graphics/index.html">dokumentasi API</a>.
    -+</p>
    -+
    -+<h2 id="tile_api">Quick Settings Tile API</h2>
    -+
    -+
    -+<div style="float:right;max-width:320px">
    -+<img src="{@docRoot}images/android-7.0/quicksettings.png" style="padding-left:1.5em;">
    -+
    -+<p class="img-caption" style="padding-left:2em;">
    -+  <strong>Gambar 5.</strong> Quick Settings Tile dalam bayangan pemberitahuan.
    -+</p>
    -+
    -+
    -+  </div><p>Quick Settings adalah cara populer dan mudah untuk mengekspos setelan dan tindakan utama,
    -+langsung dari bayangan pemberitahuan. Di Android N, kami telah memperluas lingkup
    -+Quick Settings untuk membuatnya lebih berguna dan praktis lagi. </p>
    -+
    -+<p>Kami telah menambahkan ruang lebih banyak untuk petak Quick Settings tambahan, yang bisa
    -+diakses pengguna di semua bagian area tampilan halaman bernomor dengan mengusap ke kiri atau kanan. Kami juga memberi pengguna
    -+kontrol untuk mengatur letak dan petak Quick Settings apa yang akan
    -+ditampilkan &mdash; pengguna bisa menambahkan atau memindahkan petak dengan menyeret dan melepasnya. </p>
    -+
    -+<p>Bagi pengembang, Android N juga menambahkan API baru yang memungkinkan Anda mendefinisikan
    -+  petak Quick Settings untuk memberi akses mudah kepada pengguna ke berbagai kontrol dan tindakan utama dalam aplikasi Anda.</p>
    -+
    -+<p>
    -+  Petak Quick Settings dicadangkan untuk kontrol atau tindakan yang
    -+  mendesak atau sering digunakan, dan tidak boleh digunakan sebagai pintasan untuk
    -+ membuka aplikasi.
    -+</p>
    -+
    -+<p>
    -+  Setelah mendefinisikan petak, Anda bisa menyediakannya kepada pengguna, yang bisa mereka tambahkan
    -+  ke Quick Settings cukup dengan seret dan lepas.
    -+</p>
    -+
    -+<p>
    -+  Untuk informasi tentang pembuatan petak aplikasi, lihat dokumentasi untuk
    -+  <code>android.service.quicksettings.Tile</code> dalam <a href="{@docRoot}preview/setup-sdk.html#docs-dl">Referensi API</a> yang bisa diunduh.
    -+</p>
    -+
    -+
    -+
    -+<h2 id="number-blocking">Pemblokiran Nomor</h2>
    -+
    -+<p>Android N sekarang mendukung pemblokiran nomor di platform dan menyediakan
    -+API kerangka kerja agar penyedia layanan bisa mengelola daftar nomor blokir. Aplikasi SMS
    -+default, aplikasi telepon default, dan aplikasi operator bisa membaca dari dan
    -+menulis ke daftar nomor blokir. Daftar ini tidak dapat diakses oleh aplikasi lain.</p>
    -+
    -+<p>Dengan membuat pemblokiran nomor sebagai fitur standar pada platformnya, Android menyediakan
    -+cara konsisten bagi aplikasi untuk mendukung pemblokiran nomor di berbagai
    -+perangkat. Manfaat lain yang bisa diperoleh aplikasi antara lain:</p>
    -+
    -+<ul>
    -+  <li> Nomor yang diblokir untuk panggilan juga akan diblokir untuk SMS
    -+  <li> Nomor yang diblokir tetap disimpan saat pengaturan ulang dan pada berbagai perangkat melalui fitur Backup &amp;
    -+Restore.
    -+  <li> Beberapa aplikasi sekaligus bisa menggunakan daftar nomor blokir yang sama.
    -+</ul>
    -+
    -+<p>Selain itu, dengan integrasi aplikasi operator melalui Android berarti operator bisa
    -+membaca daftar nomor blokir pada perangkat dan melakukan pemblokiran di sisi layanan
    -+bagi pengguna tersebut untuk menghentikan panggilan dan SMS yang tidak diinginkan
    -+agar tidak sampai ke pengguna lewat media apa pun, misalnya VOIP-endpoint atau meneruskan panggilan telepon.</p>
    -+
    -+<p>
    -+  Untuk informasi selengkapnya, lihat <code>android.provider.BlockedNumberContract</code>
    -+  dalam <a href="{@docRoot}preview/setup-sdk.html#docs-dl">Referensi
    -+  API</a> yang bisa diunduh.
    -+</p>
    -+
    -+<h2 id="call_screening">Penyaringan Panggilan</h2>
    -+
    -+<p>
    -+  Android N memungkinkan aplikasi telepon default untuk menyaring panggilan masuk. Aplikasi
    -+  telepon melakukannya dengan mengimplementasikan <code>CallScreeningService</code> baru,
    -+  yang memungkinkan aplikasi telepon untuk melakukan sejumlah tindakan berdasarkan
    -+  {@link android.telecom.Call.Details Call.Details} panggilan masuk, misalnya:
    -+</p>
    -+
    -+<ul>
    -+  <li> Menolak panggilan masuk
    -+  <li> Tidak mengizinkan panggilan tersebut disimpan ke log panggilan
    -+  <li> Tidak menampilkan pemberitahuan untuk panggilan tersebut kepada pengguna
    -+</ul>
    -+
    -+<p>
    -+  Untuk informasi selengkapnya, lihat <code>android.telecom.CallScreeningService</code>
    -+  dalam <a href="{@docRoot}preview/setup-sdk.html#docs-dl">Referensi
    -+  API</a> yang bisa diunduh.
    -+</p>
    -+
    -+
    -+<h2 id="multi-locale_languages">Dukungan Multilokal, Lebih Banyak Bahasa yang Didukung</h2>
    -+
    -+
    -+<p>Android N kini memungkinkan pengguna memilih <strong>banyak lokal</strong> di Settings,
    -+untuk mendukung kasus penggunaan dwibahasa dengan lebih baik. Aplikasi bisa menggunakan
    -+API baru untuk mendapatkan lokal pilihan pengguna kemudian menawarkan pengalaman pengguna
    -+yang lebih canggih untuk pengguna multilokal &mdash; seperti menampilkan hasil telusur dalam
    -+banyak bahasa dan tidak menawarkan untuk menerjemahkan halaman web dalam bahasa
    -+yang sudah diketahui pengguna.</p>
    -+
    -+<p>Bersama dukungan multilokal, Android N juga memperluas ragam bahasa
    -+yang tersedia untuk pengguna. Masing-masing ditawarkan lebih dari 25 varian untuk bahasa yang umum
    -+digunakan seperti Inggris, Spanyol, Prancis, dan Arab. Juga ditambahkan dukungan
    -+parsial untuk lebih dari 100 bahasa baru.</p>
    -+
    -+<p>Aplikasi bisa mendapatkan daftar lokal yang disetel oleh pengguna dengan memanggil
    -+<code>LocaleList.GetDefault()</code>.  Untuk mendukung jumlah lokal yang diperluas, Android N sedang
    -+ mengubah cara mengatasi masalah sumber daya. Pastikan Anda menguji dan memverifikasi bahwa aplikasi Anda
    -+berfungsi seperti yang diharapkan dengan logika resolusi sumber daya baru.</p>
    -+
    -+<p>Untuk mengetahui tentang perilaku resolusi sumber daya baru dan praktik terbaik yang
    -+harus Anda ikuti, lihat <a href="{@docRoot}preview/features/multilingual-support.html">Dukungan Multibahasa</a>.</p>
    -+
    -+
    -+<h2 id="emoji">Emoji Baru</h2>
    -+
    -+<p>
    -+  Android N memperkenalkan emoji tambahan dan fitur terkait emoji termasuk
    -+  emoji warna kulit dan dukungan untuk pemilih
    -+  variasi. Jika aplikasi Anda mendukung emoji,
    -+  ikuti panduan berikut untuk memanfaatkan fitur terkait emoji ini.
    -+</p>
    -+
    -+<ul>
    -+  <li>
    -+    <strong>Periksa apakah perangkat berisi emoji sebelum memasukannya.</strong>
    -+    Untuk memeriksa emoji mana yang terdapat di
    -+    font sistem, gunakan metode {@link android.graphics.Paint#hasGlyph(String)}.
    -+  </li>
    -+  <li>
    -+    <strong>Periksa apakah emoji mendukung pemilih variasi.</strong>
    -+    Pemilih variasi memungkinkan Anda
    -+    menampilkan emoji tertentu berwarna atau hitam-putih.
    -+    Pada perangkat seluler, aplikasi akan menghadirkan emoji berwarna daripada hitam-putih. Akan tetapi,
    -+    jika aplikasi Anda menampilkan emoji sebaris dengan teks, maka harus menggunakan variasi hitam-putih.
    -+    Untuk menentukan apakah sebuah emoji memiliki variasi, gunakan pemilih variasi.
    -+    Untuk daftar lengkap dari karakter dengan variasinya, tinjaulah bagian
    -+    <em>rangkaian variasi emoji</em> pada
    -+    <a class="external-link" href="http://www.unicode.org/Public/9.0.0/ucd/StandardizedVariants-9.0.0d1.txt">
    -+      dokumentasi Unicode mengenai variasi</a>.
    -+  </li>
    -+  <li>
    -+    <strong>Periksa apakah emoji mendukung warna kulit.</strong> Android N memungkinkan pengguna memodifikasi
    -+    warna kulit emoji yang dirender sesuai dengan preferensi mereka. Aplikasi keyboard harus menyediakan indikasi
    -+    visual untuk emoji yang memiliki beberapa warna kulit dan harus memungkinkan pengguna
    -+    memilih warna kulit yang mereka sukai. Untuk menentukan apakah emoji sistem memiliki
    -+    modifier warna kulit, gunakan metode {@link android.graphics.Paint#hasGlyph(String)}.
    -+ Anda bisa menentukan emoji mana yang menggunakan warna kulit dengan membaca
    -+    <a class="external-link" href="http://unicode.org/emoji/charts/full-emoji-list.html">
    -+     dokumentasi Unicode</a>.
    -+  </li>
    -+</ul>
    -+
    -+
    -+<h2 id="icu4">ICU4J API di Android</h2>
    -+
    -+<p>
    -+  Android N kini menawarkan subset <a href="http://site.icu-project.org/">ICU4J</a> API dalam kerangka kerja Android pada paket
    -+  <code>android.icu</code>. Migrasi mudah, dan biasanya hanya perlu
    -+  mengubah dari ruang nama <code>com.java.icu</code> ke
    -+  <code>android.icu</code>. Jika Anda sudah menggunakan bundel ICU4J dalam aplikasi,
    -+  maka beralih ke <code>android.icu</code> API yang disediakan dalam kerangka kerja
    -+  Android bisa menghasilkan penghematan besar dalam ukuran APK.
    -+</p>
    -+
    -+<p>
    -+  Untuk mengetahui selengkapnya tentang Android ICU4J API, lihat <a href="{@docRoot}preview/features/icu4j-framework.html">Dukungan ICU4J</a>.
    -+</p>
    -+
    -+
    -+
    -+<h2 id="gles_32">OpenGL&trade; ES 3.2 API</h2>
    -+
    -+<p>Android N menambahkan antarmuka kerangka kerja dan dukungan platform untuk OpenGL ES 3.2, termasuk:</p>
    -+
    -+<ul>
    -+  <li> Semua ekstensi dari <a class="external-link" href="https://www.khronos.org/registry/gles/extensions/ANDROID/ANDROID_extension_pack_es31a.txt">
    -+Android Extension Pack</a></a> (AEP) kecuali untuk <code>EXT_texture_sRGB_decode</code>.
    -+  <li> Floating-point framebuffer untuk HDR dan shading yang ditangguhkan.
    -+  <li> Panggilan draw BaseVertex agar batching dan streaming jadi lebih baik.
    -+  <li> Kontrol akses buffer yang tangguh untuk mengurangi overhead WebGL.
    -+</ul>
    -+
    -+<p>API kerangka kerja untuk OpenGL ES 3.2 di Android N dilengkapi dengan kelas
    -+  <code>GLES32</code>. Saat menggunakan OpenGL ES 3.2, pastikan
    -+mendeklarasikan persyaratan dalam file manifes Anda, dengan tag <code>&lt;uses-feature&gt;</code> dan
    -+atribut <code>android:glEsVersion</code>. </p>
    -+
    -+<p>Untuk informasi tentang menggunakan OpenGL ES, termasuk cara memeriksa versi
    -+OpenGL ES yang didukung perangkat saat waktu proses, lihat <a href="{@docRoot}guide/topics/graphics/opengl.html">Panduan OpenGL ES API</a>.</p>
    -+
    -+
    -+<h2 id="android_tv_recording">Perekaman Android TV</h2>
    -+
    -+<p>Android N menambahkan kemampuan untuk merekam dan memutar kembali materi dari layanan masukan
    -+Android TV melalui API perekaman baru.  Karena dibangun dengan API perekaman yang sudah
    -+ada, layanan masukan TV bisa mengontrol data saluran apa yang bisa direkam, cara menyimpan
    -+sesi rekaman, dan mengelola interaksi pengguna dengan materi rekaman. </p>
    -+
    -+<p>Untuk informasi selengkapnya, lihat <a href="{@docRoot}preview/features/tv-recording-api.html">API Perekaman Android TV</a>.</p>
    -+
    -+
    -+<h2 id="android_for_work">Android for Work</h2>
    -+
    -+<p>Android for Work menambahkan berbagai fitur dan API baru untuk perangkat yang menjalankan Android N.
    -+Beberapa fitur unggulannya ada di bawah ini &mdash; untuk mengetahui daftar lengkap perubahannya, lihat
    -+<a href="{@docRoot}preview/features/afw.html">Pembaruan Android for Work</a>.</p>
    -+
    -+<h3 id="work_profile_security_challenge">Pertanyaan Keamanan Profil Kerja </h3>
    -+
    -+<p>
    -+  Pemilik profil yang menargetkan N SDK
    -+  bisa menetapkan pertanyaan keamanan terpisah untuk aplikasi yang berjalan di
    -+  profil kerja. Pertanyaan kerja ditampilkan bila pengguna mencoba membuka
    -+  aplikasi kerja apa pun. Jawaban pertanyaan keamanan yang benar akan membuka
    -+  profil kerja dan mendekripsinya jika diperlukan. Untuk pemilik profil,
    -+  <code>ACTION_SET_NEW_PASSWORD</code> akan meminta pengguna untuk menetapkan pertanyaan
    -+  kerja, dan <code>ACTION_SET_NEW_PARENT_PROFILE_PASSWORD</code> meminta
    -+  pengguna menyetel kunci perangkat.
    -+</p>
    -+
    -+<p>
    -+  Pemilik profil bisa menyetel kebijakan kode sandi untuk pertanyaan kerja
    -+  (seperti berapa lama seharusnya PIN, atau apakah sidik jari bisa digunakan
    -+  untuk membuka kunci profil) menggunakan <code>setPasswordQuality()</code>,
    -+  <code>setPasswordMinimumLength()</code> dan metode terkait. Pemilik profil
    -+  juga bisa menyetel kunci perangkat, menggunakan instance <code>DevicePolicyManager</code>
    -+  yang dikembalikan oleh metode <code>getParentProfileInstance()</code>  baru.
    -+  Selain itu, pemilik profil bisa menyesuaikan layar kredensial untuk
    -+ pertanyaan kerja menggunakan metode baru <code>setOrganizationColor()</code> dan
    -+  <code>setOrganizationName()</code>.
    -+</p>
    -+<h3 id="turn_off_work">Menonaktifkan pekerjaan </h3>
    -+
    -+<p>Pada perangkat dengan profil kerja, pengguna bisa beralih mode kerja. Bila mode
    -+kerja dinonaktifkan, profil yang dikelola akan dinonaktifkan untuk sementara, yang akan menonaktifkan aplikasi
    -+profil kerja, sinkronisasi latar belakang, dan pemberitahuan. Termasuk aplikasi pemilik
    -+profil. Bila profil kerja dinonaktifkan, sistem akan menampilkan ikon status
    -+tetap untuk mengingatkan pengguna bahwa mereka tidak bisa meluncurkan aplikasi kerja. Peluncur
    -+menunjukkan bahwa aplikasi kerja dan widget tidak bisa diakses. </p>
    -+
    -+<h3 id="always_on_vpn">Always-On VPN </h3>
    -+
    -+<p>Pemilik perangkat dan pemilik profil bisa memastikan bahwa aplikasi kerja selalu menghubungkan
    -+melalui VPN yang ditetapkan. Sistem secara otomatis akan memulai VPN itu setelah booting
    -+perangkat.</p>
    -+
    -+<p>
    -+  Metode <code>DevicePolicyManager</code> baru adalah
    -+  <code>setAlwaysOnVpnPackage()</code> dan
    -+  <code>getAlwaysOnVpnPackage()</code>.
    -+</p>
    -+
    -+<p>Karena layanan VPN bisa diikat langsung oleh sistem tanpa interaksi
    -+aplikasi, klien VPN perlu menangani titik masuk baru untuk Always-On VPN. Seperti
    -+sebelumnya, layanan ditunjukkan ke sistem melalui
    -+tindakan pencocokan filter intent <code>android.net.VpnService</code>. </p>
    -+
    -+<p>
    -+  Pengguna bisa secara manual menyetel klien Always-On VPN yang mengimplementasikan
    -+  metode <code>VPNService</code> dalam pengguna utama dengan menggunakan
    -+  <strong>Settings&gt;More&gt;Vpn</strong>.
    -+</p>
    -+
    -+<h3 id="custom_provisioning">Penyediaan yang disesuaikan</h3>
    -+
    -+<p>
    -+  Aplikasi bisa menyesuaikan alur penyediaan pemilik profil dan pemilik perangkat
    -+  dengan warna dan logo perusahaan.
    -+  <code>DevicePolicyManager.EXTRA_PROVISIONING_MAIN_COLOR</code> menyesuaikan
    -+  warna alur. <code>DevicePolicyManager.EXTRA_PROVISIONING_LOGO_URI</code>
    -+  menyesuaikan alur dengan logo perusahaan.
    -+</p>
    -+
    -+<h2 id="accessibility_enhancements">Penyempurnaan Aksesibilitas</h2>
    -+
    -+<p>Android N saat ini menawarkan Vision Settings langsung di layar Sambutan untuk
    -+persiapan perangkat baru. Ini sangat memudahkan pengguna untuk menemukan dan mengonfigurasi
    -+fitur aksesibilitas pada perangkat mereka, termasuk isyarat perbesaran, ukuran
    -+font, ukuran layar, dan TalkBack. </p>
    -+
    -+<p>Dengan fitur aksesibilitas yang penempatannya semakin jelas, pengguna Anda
    -+kemungkinan besar akan mencoba aplikasi dengan fitur-fitur yang diaktifkan itu. Pastikan Anda menguji aplikasi
    -+lebih dini dengan mengaktifkan dahulu setelan ini. Anda bisa mengaktifkannya dari Settings &gt;
    -+Accessibility.</p>
    -+
    -+<p>Di Android N, layanan aksesibilitas sekarang bisa membantu pengguna yang mengalami gangguan
    -+motorik untuk menyentuh layar. API baru memungkinkan membangun layanan dengan
    -+fitur-fitur seperti pelacakan wajah, pelacakan mata, pemindaian titik, dan seterusnya, untuk
    -+memenuhi kebutuhan para pengguna tersebut.</p>
    -+
    -+<p>Untuk informasi selengkapnya, lihat <code>android.accessibilityservice.GestureDescription</code>
    -+ dalam <a href="{@docRoot}preview/setup-sdk.html#docs-dl">Referensi  API</a> yang bisa diunduh.</p>
    -+
    -+
    -+<h2 id="direct_boot">Direct Boot</h2>
    -+
    -+<p>Direct Boot memperbaiki waktu startup perangkat dan memungkinkan aplikasi
    -+yang telah didaftarkan memiliki fungsionalitas terbatas bahkan setelah boot ulang tak terduga.
    -+Misalnya, jika perangkat yang dienkripsi melakukan boot ulang selagi pengguna tidur,
    -+alarm terdaftar, pesan dan panggilan masuk sekarang bisa terus memberi tahu
    -+pengguna seperti biasa. Ini juga berarti layanan aksesibilitas bisa
    -+  segera tersedia setelah restart.</p>
    -+
    -+<p>Direct Boot memanfaatkan enkripsi berbasis file di Android N
    -+untuk mengaktifkan kebijakan enkripsi yang telah disesuaikan bagi sistem dan data aplikasi.
    -+Sistem akan menggunakan penyimpanan yang dienkripsi dengan perangkat untuk data sistem terpilih dan data
    -+aplikasi yang terdaftar secara eksplisit. Secara default, penyimpanan yang dienkripsi dengan kredensial digunakan untuk semua
    -+  data sistem lainnya, data pengguna, aplikasi, dan data aplikasi. </p>
    -+
    -+<p>Saat booting, sistem dimulai dalam mode terbatas dengan akses
    -+ke data yang dienkripsi dengan perangkat saja, dan tanpa akses umum ke aplikasi atau data.
    -+Jika Anda memiliki komponen yang ingin Anda jalankan dalam mode ini, Anda bisa mendaftarkannya
    -+dengan menyetel flag dalam manifes. Setelah restart, sistem akan mengaktifkan
    -+komponen terdaftar dengan menyiarkan intent <code>LOCKED_BOOT_COMPLETED</code>.
    -+ Sistem akan memastikan data aplikasi yang dienkripsi dengan perangkat tersedia
    -+sebelum membuka kunci. Semua data lainnya tidak tersedia sebelum Pengguna mengonfirmasi
    -+  kredensial layar kunci mereka untuk mendekripsinya. </p>
    -+
    -+Untuk informasi selengkapnya, lihat <a href="{@docRoot}preview/features/direct-boot.html">Direct Boot</a>.</p>
    -+</p>
    -+
    -+
    -+<h2 id="key_attestation">Key Attestation</h2>
    -+
    -+<p>Keystore yang didukung perangkat keras menyediakan metode yang jauh lebih aman untuk membuat, menyimpan,
    -+dan menggunakan kunci kriptografi pada perangkat Android. Keystore itu melindungi kunci dari
    -+kernel Linux, potensi kerentanan Android, dan ekstraksi
    -+dari perangkat yang di-root.</p>
    -+
    -+<p>Agar lebih mudah dan lebih aman dalam menggunakan keystore yang didukung perangkat keras,
    -+Android N memperkenalkan Key Attestation. Aplikasi dan perangkat-nonaktif bisa menggunakan Key
    -+Attestation untuk menentukan apakah penyandingan kunci RSA atau EC
    -+didukung perangkat keras, apa properti dari penyandingan kunci, dan batasan
    -+  apa yang diterapkan terhadap penggunaan dan validitasnya. </p>
    -+
    -+<p>Aplikasi dan layanan perangkat-nonaktif bisa meminta informasi tentang penyandingan kunci
    -+melalui sertifikat pengesahan X.509 yang harus ditandatangani dengan kunci
    -+pengesahan yang valid. Kunci pengesahan adalah kunci penandatanganan ECDSA yang
    -+telah diinjeksikan ke dalam keystore yang didukung perangkat keras pada perangkat saat di pabriknya.
    -+Karena itu, sertifikat pengesahan yang ditandatangani oleh kunci pengesahan yang
    -+valid akan mengonfirmasi keberadaan keystore yang didukung perangkat keras, bersama
    -+  detail pasangan kunci dalam keystore itu.</p>
    -+
    -+<p>Untuk memastikan perangkat ini menggunakan citra Android resmi yang
    -+aman dari pabrik, Key Attestation mengharuskan <a class="external-link" href="https://source.android.com/security/verifiedboot/verified-boot.html#bootloader_requirements">bootloader</a> perangkat
    -+menyediakan informasi berikut pada <a class="external-link" href="https://source.android.com/security/trusty/index.html">Trusted
    -+Execution Environment (TEE)</a>:</p>
    -+
    -+<ul>
    -+<li>Versi OS dan level patch yang dipasang pada perangkat</li>
    -+<li>Kunci publik <a href="https://source.android.com/security/verifiedboot/index.html" class="external-link">Verified Boot</a> dan status kunci</li>
    -+  </ul>
    -+
    -+<p>Untuk informasi selengkapnya tentang fitur keystore yang didukung perangkat keras,
    -+lihat panduan untuk <a href="https://source.android.com/security/keystore/" class="external-link">Keystore yang Didukung Perangkat Keras</a>.</p>
    -+
    -+<p>Selain Key Attestation, Android N juga memperkenalkan
    -+  kunci yang terikat sidik jari yang tidak dipanggil saat pendaftaran sidik jari.</p>
    -+
    -+<h2 id="network_security_config">Network Security Config</h2>
    -+
    -+<p>Di Android N, aplikasi bisa menyesuaikan perilaku koneksi aman mereka
    -+(HTTPS, TLS) secara aman, tanpa modifikasi kode, dengan menggunakan
    -+<em>Network Security Config</em> deklaratif sebagai ganti menggunakan API programatik
    -+konvensional yang rawan kesalahan (mis. X509TrustManager).</p>
    -+
    -+  <p>Fitur yang didukung:</p>
    -+<ul>
    -+<li><b>Trust-anchor khusus.</b> Memungkinkan aplikasi menyesuaikan
    -+Certificate Authorities (CA) mana yang dipercaya untuk koneksi amannya. Misalnya,
    -+mempercayai sertifikat tertentu yang ditandatangani sendiri atau set CA publik yang dibatasi.
    -+</li>
    -+<li><b>Penggantian hanya-debug.</b> Memungkinkan pengembang aplikasi dengan aman men-debug
    -+koneksi aman aplikasi mereka tanpa menambah risiko pada basis yang sudah
    -+dipasang.
    -+</li>
    -+<li><b>Berhenti dari lalu lintas cleartext.</b> Memungkinkan aplikasi melindungi dirinya sendiri dari
    -+penggunaan lalu lintas cleartext yang tidak disengaja.</li>
    -+<li><b>Penyematan sertifikat.</b> Sebuah fitur canggih yang memungkinkan aplikasi
    -+  membatasi kunci server mana yang dipercaya untuk koneksi aman.</li>
    -+</ul>
    -+
    -+<p>Untuk informasi selengkapnya, lihat <a href="{@docRoot}preview/features/security-config.html">Network Security
    -+Config</a>.</p>
    -+
    -+<h2 id="default_trusted_ca">Certificate Authority Tepercaya Default</h2>
    -+
    -+<p>Secara default, aplikasi yang menargetkan Android N hanya mempercayai sertifikat yang disediakan sistem
    -+dan tidak lagi mempercayai Certificate Authorities (CA) yang ditambahkan pengguna. Aplikasi yang menargetkan Android
    -+N dan ingin mempercayai CA yang ditambahkan pengguna harus menggunakan
    -+<a href="{@docRoot}preview/features/security-config.html">Network Security Config</a> untuk
    -+menetapkan cara mempercayai CA pengguna.</p>
    -+
    -+<h2 id="apk_signature_v2">APK Signature Scheme v2</h2>
    -+
    -+<p>
    -+  Android N memperkenalkan APK Signature Scheme v2, sebuah skema penandatanganan aplikasi baru yang
    -+  menawarkan waktu pasang aplikasi lebih cepat dan lebih banyak perlindungan terhadap perubahan
    -+ tidak sah pada file APK. Secara default, Android Studio 2.2 dan Android
    -+  Plugin untuk Gradle 2.2 menandatangani aplikasi Anda menggunakan APK Signature Scheme v2 dan
    -+  skema penandatanganan tradisional, yang menggunakan penandatanganan JAR.
    -+</p>
    -+
    -+<p>
    -+  Meskipun kami menyarankan untuk menerapkan APK Signature Scheme v2 pada aplikasi Anda, skema
    -+  baru ini tidak wajib. Jika aplikasi Anda tidak dibangun dengan benar saat menggunakan APK
    -+  Signature Scheme v2, Anda bisa menonaktifkan skema baru ini. Proses penonaktifan
    -+  menyebabkan Android Studio 2.2 dan Android Plugin untuk Gradle 2.2 menandatangani aplikasi Anda
    -+  menggunakan skema penandatanganan tradisional saja. Untuk menandatangani dengan
    -+ skema tradisional saja, buka file <code>build.gradle</code> level-modul, kemudian
    -+  tambahkan baris <code>v2SigningEnabled false</code> ke konfigurasi
    -+  penandatanganan rilis Anda:
    -+</p>
    -+
    -+<pre>
    -+  android {
    -+    ...
    -+    defaultConfig { ... }
    -+    signingConfigs {
    -+      release {
    -+        storeFile file("myreleasekey.keystore")
    -+        storePassword "password"
    -+        keyAlias "MyReleaseKey"
    -+        keyPassword "password"
    -+        <strong>v2SigningEnabled false</strong>
    -+      }
    -+    }
    -+  }
    -+</pre>
    -+
    -+<p class="caution"><strong>Perhatian: </strong> Jika Anda menandatangani aplikasi menggunakan APK
    -+  Signature Scheme v2 dan membuat perubahan lebih jauh pada aplikasi, tanda tangan aplikasi
    -+  menjadi tidak valid. Untuk alasan ini, gunakan alat seperti <code>zipalign</code>
    -+  sebelum menandatangani aplikasi Anda menggunakan APK Signature Scheme v2, bukan setelahnya.
    -+</p>
    -+
    -+<p>
    -+  Untuk informasi selengkapnya, baca dokumen Android Studio yang menjelaskan cara
    -+  <a href="{@docRoot}studio/publish/app-signing.html#release-mode">
    -+  menandatangani aplikasi</a> di Android Studio dan cara<a href="{@docRoot}studio/build/build-variants.html#signing"> mengonfigurasi
    -+  file build untuk menandatangani aplikasi</a> menggunakan Android Plugin untuk Gradle.
    -+</p>
    -+
    -+<h2 id="scoped_directory_access">Scoped Directory Access</h2>
    -+
    -+<p>Di Android N, aplikasi bisa menggunakan API baru untuk meminta akses ke direktori <a href="{@docRoot}guide/topics/data/data-storage.html#filesExternal">penyimpanan
    -+eksternal</a> tertentu, termasuk direktori di media lepas-pasang seperti kartu
    -+SD. API baru ini sangat menyederhanakan cara aplikasi Anda mengakses direktori
    -+penyimpanan eksternal standar, seperti direktori <code>Pictures</code>. Aplikasi
    -+seperti aplikasi foto bisa menggunakan API ini sebagai ganti menggunakan
    -+<code>READ_EXTERNAL_STORAGE</code>, yang memberikan akses ke semua direktori
    -+penyimpanan, atau Storage Access Framework, yang membuat pengguna mengarah ke
    -+direktori tersebut.</p>
    -+
    -+<p>Selain itu, API baru ini menyederhanakan langkah-langkah yang diambil pengguna untuk memberikan akses
    -+penyimpanan eksternal ke aplikasi Anda. Bila Anda menggunakan API baru, sistem akan menggunakan UI izin
    -+sederhana yang memperinci dengan jelas direktori apa yang aksesnya diminta
    -+oleh aplikasi.</p>
    -+
    -+<p>Untuk informasi selengkapnya, lihat dokumentasi pengembang
    -+<a href="{@docRoot}preview/features/scoped-folder-access.html">Scoped
    -+Directory Access</a>.</p>
    -+
    -+<h2 id="keyboard_shortcuts_helper">Keyboard Shortcuts Helper</h2>
    -+
    -+<p>
    -+Di Android N, pengguna bisa menekan "Alt + /" untuk memunculkan layar <em>Keyboard Shortcuts</em>
    -+yang menampilkan semua pintasan yang tersedia baik dari sistem maupun dari
    -+aplikasi yang sedang mendapatkan fokus. Ini diambil secara otomatis dari menu aplikasi
    -+jika tersedia, namun pengembang bisa menyediakan daftar pintasan yang telah disesuaikan
    -+untuk layar. Anda bisa melakukannya dengan mengganti metode
    -+<code>Activity.onProvideKeyboardShortcuts()</code> baru, yang dijelaskan dalam
    -+<a href="{@docRoot}preview/setup-sdk.html#docs-dl">Referensi API</a> yang bisa diunduh.
    -+</p>
    -+
    -+<p>
    -+Untuk memunculkan Keyboard Shortcuts Helper dari mana saja di aplikasi Anda,
    -+panggil {@code Activity.requestKeyboardShortcutsHelper()} untuk aktivitas terkait.
    -+</p>
    -+
    -+<h2 id="sustained_performance_api">Sustained Performance API</h2>
    -+
    -+<p>
    -+Kinerja bisa berfluktuasi secara dramatis untuk aplikasi yang berjalan lama, karena
    -+sistem melakukan throttle pada mesin sistem-di-chip saat komponen perangkat mencapai
    -+batas suhunya. Fluktuasi ini memberikan target bergerak bagi pengembang
    -+aplikasi yang sedang membuat aplikasi berkinerja tinggi dan berjalan lama.
    -+</p>
    -+
    -+<p>
    -+Untuk menangani batasan ini, Android N menyertakan dukungan untuk
    -+<em>mode kinerja kontinu</em>, yang memungkinkan OEM memberikan petunjuk mengenai kemampuan kinerja
    -+perangkat untuk aplikasi yang berjalan lama. Pengembang aplikasi
    -+bisa menggunakan petunjuk ini untuk menyesuaikan aplikasi agar kinerja perangkat bisa diprediksi
    -+dan pada level yang konsisten dalam jangka waktu lama.
    -+</p>
    -+
    -+<p>
    -+Pengembang aplikasi bisa mencoba API baru ini dalam N Developer Preview pada
    -+perangkat Nexus 6P saja. Untuk menggunakan fitur ini,
    -+setel flag jendela kinerja kontinu
    -+yang ingin Anda jalankan dalam mode kinerja kontinu. Setel flag ini menggunakan metode
    -+{@code Window.setSustainedPerformanceMode()}. Sistem secara otomatis
    -+akan menonaktifkan mode ini bila jendela tidak lagi mendapatkan fokus.
    -+</p>
    -+
    -+<h2 id="vr">Dukungan VR</h2>
    -+
    -+<p>
    -+Android N menambahkan dukungan platform dan optimalisasi untuk VR Mode baru yang memungkinkan
    -+pengembang membuat pengalaman VR berkualitas tinggi di seluler bagi para pengguna. Ada banyak perbaikan
    -+kinerja, termasuk akses ke inti CPU yang eksklusif untuk aplikasi VR.
    -+Di dalam aplikasi, Anda bisa memanfaatkan pelacakan kepala yang cerdas,
    -+dan pemberitahuan stereo yang bekerja untuk VR. Hal terpenting adalah Android N menyediakan
    -+grafis dengan latensi sangat rendah. Untuk informasi selengkapnya tentang membangun aplikasi VR untuk Android N,
    -+lihat <a href="https://developers.google.com/vr/android/">Google VR SDK untuk Android</a>.
    -+</p>
    -+
    -+
    -+<h2 id="print_svc">Penyempurnaan Layanan Cetak</h2>
    -+
    -+<p>
    -+  Di Android N, pengembang layanan cetak kini bisa menampilkan informasi tambahan
    -+  tentang masing-masing printer dan pekerjaan cetak.
    -+</p>
    -+
    -+<p>
    -+  Saat mendaftarkan masing-masing printer, layanan cetak kini bisa menyetel
    -+  ikon per printer dalam dua cara:
    -+</p>
    -+
    -+<ul>
    -+  <li>Anda bisa menyetel ikon dari ID sumber daya dengan memanggil
    -+  <code>PrinterInfo.Builder.setResourceIconId()</code>
    -+  </li>
    -+
    -+  <li>Anda bisa menampilkan ikon dari jaringan dengan memanggil
    -+  <code>PrinterInfo.Builder.setHasCustomPrinterIcon()</code>, dan menyetel sebuah
    -+ callback bila ikon diminta menggunakan
    -+  <code>android.printservice.PrinterDiscoverySession.onRequestCustomPrinterIcon()</code>
    -+  </li>
    -+</ul>
    -+
    -+<p>
    -+  Selain itu, Anda bisa menyediakan aktivitas per printer untuk menampilkan informasi
    -+  tambahan dengan memanggil <code>PrinterInfo.Builder.setInfoIntent()</code>.
    -+</p>
    -+
    -+<p>
    -+  Anda bisa menunjukkan kemajuan dan status pekerjaan cetak di
    -+  pemberitahuan pekerjaan cetak dengan memanggil masing-masing
    -+  <code>android.printservice.PrintJob.setProgress()</code> dan
    -+  <code>android.printservice.PrintJob.setStatus()</code>.
    -+</p>
    -+
    -+<p>
    -+  Untuk informasi selengkapnya tentang metode ini,lihat  dalam <a href="{@docRoot}preview/setup-sdk.html#docs-dl">Referensi  API</a> yang bisa diunduh.
    -+</p>
    -+
    -+<h2 id="framemetrics_api">FrameMetricsListener API</h2>
    -+
    -+<p>
    -+FrameMetricsListener API memungkinkan aplikasi untuk memantau
    -+kinerja rendering UI. API tersebut menyediakan kemampuan ini dengan mengekspos Pub/Sub API streaming
    -+untuk mentransfer info frame-timing untuk jendela aplikasi saat ini. Data yang dikembalikan
    -+setara dengan yang ditampilkan <code><a href="{@docRoot}tools/help/shell.html#shellcommands">adb shell</a>
    -+dumpsys gfxinfo framestats</code>, namun tidak dibatasi pada 120 bingkai.
    -+</p>
    -+
    -+<p>
    -+Anda bisa menggunakan FrameMetricsListener untuk mengukur kinerja UI
    -+level interaksi di produksi, tanpa koneksi USB. API
    -+ini memungkinkan pengumpulan data dengan granularitas lebih tinggi daripada
    -+{@code adb shell dumpsys gfxinfo}. Granularitas lebih tinggi ini dimungkinkan karena
    -+sistem bisa mengumpulkan data untuk interaksi tertentu di aplikasi; sistem
    -+tidak perlu merekam ringkasan global untuk keseluruhan kinerja
    -+aplikasi, atau mengosongkan status global yang ada. Anda bisa menggunakan kemampuan ini
    -+untuk mengumpulkan data kinerja dan menangkap regresi di kinerja UI
    -+untuk kasus penggunaan sungguhan di dalam aplikasi.
    -+</p>
    -+
    -+<p>
    -+Untuk memantau sebuah jendela, implementasikan metode callback <code>FrameMetricsListener.onMetricsAvailable()</code>
    -+dan daftarkan di jendela itu. Untuk informasi selengkapnya, lihat
    -+dokumentasi kelas {@code FrameMetricsListener} di
    -+<a href="{@docRoot}preview/setup-sdk.html#docs-dl">Referensi API</a> yang bisa diunduh.
    -+</p>
    -+
    -+<p>
    -+API menyediakan objek {@code FrameMetrics}, yang berisi data timing yang
    -+dilaporkan subsistem rendering untuk berbagai tahap pencapaian dalam daur hidup bingkai.
    -+Metrik yang didukung adalah: {@code UNKNOWN_DELAY_DURATION},
    -+{@code INPUT_HANDLING_DURATION}, {@code ANIMATION_DURATION},
    -+{@code LAYOUT_MEASURE_DURATION}, {@code DRAW_DURATION}, {@code SYNC_DURATION},
    -+{@code COMMAND_ISSUE_DURATION}, {@code SWAP_BUFFERS_DURATION},
    -+{@code TOTAL_DURATION}, dan {@code FIRST_DRAW_FRAME}.
    -+</p>
    -+
    -+
    -+<h2 id="virtual_files">File Maya</h2>
    -+
    -+<p>
    -+  Di versi Android sebelumnya, aplikasi Anda bisa menggunakan Storage Access
    -+  Framework untuk memungkinkan pengguna memilih file dari akun penyimpanan awan mereka,
    -+  seperti Google Drive. Akan tetapi, tidak ada cara untuk merepresentasikan file yang
    -+  tidak memiliki representasi bytecode langsung; setiap file diharuskan menyediakan
    -+  aliran masukan.
    -+</p>
    -+
    -+<p>
    -+  Android N menambahkan konsep <em>file maya</em> pada Storage Access
    -+  Framework. Fitur file maya memungkinkan
    -+  {@link android.provider.DocumentsProvider} Anda mengembalikan URI dokumen yang bisa
    -+  digunakan bersama intent {@link android.content.Intent#ACTION_VIEW} sekalipun
    -+  tidak memiliki representasi bytecode langsung. Android N juga memungkinkan Anda untuk
    -+  menyediakan format alternatif untuk file pengguna, maya atau dengan cara lain.
    -+</p>
    -+
    -+<p>
    -+  Untuk mendapatkan URI sebuah dokumen maya di aplikasi Anda, terlebih dahulu Anda membuat
    -+  {@link android.content.Intent} untuk membuka UI pemilih file. Karena aplikasi
    -+  tidak bisa membuka file maya secara langsung dengan menggunakan metode
    -+  {@link android.content.ContentResolver#openInputStream(Uri) openInputStream()},
    -+   aplikasi Anda tidak akan menerima file maya jika Anda memasukkan kategori
    -+  {@link android.content.Intent#CATEGORY_OPENABLE}.
    -+</p>
    -+
    -+<p>
    -+  Setelah pengguna menentukan pilihan, sistem akan memanggil metode
    -+  {@link android.app.Activity#onActivityResult onActivityResult()}.
    -+  Aplikasi Anda bisa mengambil URI file maya dan mendapatkan aliran masukan, seperti yang
    -+  diperagakan dalam cuplikan kode di bawah.
    -+</p>
    -+
    -+<pre>
    -+  // Other Activity code ...
    -+
    -+  final static private int REQUEST_CODE = 64;
    -+
    -+  // We listen to the OnActivityResult event to respond to the user's selection.
    -+  &#64;Override
    -+  public void onActivityResult(int requestCode, int resultCode,
    -+    Intent resultData) {
    -+      try {
    -+        if (requestCode == REQUEST_CODE &amp;&amp;
    -+            resultCode == Activity.RESULT_OK) {
    -+
    -+            Uri uri = null;
    -+
    -+            if (resultData != null) {
    -+                uri = resultData.getData();
    -+
    -+                ContentResolver resolver = getContentResolver();
    -+
    -+                // Before attempting to coerce a file into a MIME type,
    -+                // check to see what alternative MIME types are available to
    -+                // coerce this file into.
    -+                String[] streamTypes =
    -+                  resolver.getStreamTypes(uri, "*/*");
    -+
    -+                AssetFileDescriptor descriptor =
    -+                    resolver.openTypedAssetFileDescriptor(
    -+                        uri,
    -+                        streamTypes[0],
    -+                        null);
    -+
    -+                // Retrieve a stream to the virtual file.
    -+                InputStream inputStream = descriptor.createInputStream();
    -+            }
    -+        }
    -+      } catch (Exception ex) {
    -+        Log.e("EXCEPTION", "ERROR: ", ex);
    -+      }
    -+  }
    -+</pre>
    -+
    -+<p>
    -+  Untuk informasi selengkapnya tentang mengakses file pengguna, lihat
    -+  <a href="{@docRoot}guide/topics/providers/document-provider.html">Panduan Storage
    -+  Access Frameworks</a>.
    -+</p>
    -diff --git a/docs/html-intl/intl/id/about/versions/nougat/index.jd b/docs/html-intl/intl/id/about/versions/nougat/index.jd
    -new file mode 100644
    -index 0000000..212870a
    ---- /dev/null
    -+++ b/docs/html-intl/intl/id/about/versions/nougat/index.jd
    -@@ -0,0 +1,110 @@
    -+page.title=Android 7.0 Nougat
    -+page.tags="androidn","versions"
    -+meta.tags="android n", "nougat", "android 7.0"
    -+fullpage=true
    -+forcelocalnav=true
    -+header.hide=1
    -+footer.hide=1
    -+@jd:body
    -+
    -+<section class="dac-expand dac-hero dac-light">
    -+  <div class="wrap" style="max-width:1100px;margin-top:0">
    -+  <a href="{@docRoot}about/versions/nougat/android-7.0.html">
    -+    <div class="cols dac-hero-content" style="padding-bottom:1em;">
    -+
    -+      <div class="col-7of16 col-push-8of16" style="padding-left:2em">
    -+        <h1 class="dac-hero-title">Android 7.0 Nougat</h1>
    -+        <p class="dac-hero-description">
    -+          Bersiaplah menyambut Android Nougat!
    -+          <strong>Uji aplikasi Anda</strong> pada perangkat Nexus dan perangkat lainnya. Dukung perilaku sistem
    -+          baru untuk <strong>menghemat daya dan memori</strong>.
    -+          Tambah aplikasi Anda dengan <strong>UI multi-jendela</strong>,
    -+          <strong>pemberitahuan balasan langsung</strong> dan lainnya.
    -+        </p>
    -+
    -+        <a class="dac-hero-cta" href="{@docRoot}about/versions/nougat/android-7.0.html">
    -+          <span class="dac-sprite dac-auto-chevron"></span>
    -+          Mulai
    -+        </a>
    -+      </div>
    -+      <div class="col-7of16 col-pull-6of16 dac-hero-figure" style="margin-top:1.5em;padding-right:1.5em;">
    -+        <a  href="{@docRoot}about/versions/nougat/android-7.0.html">
    -+        <img class="dac-hero-image" src="{@docRoot}images/home/n-preview-hero.png"
    -+             srcset="{@docRoot}images/home/n-preview-hero.png 1x,
    -+             {@docRoot}images/home/n-preview-hero_2x.png 2x" />
    -+           </a>
    -+      </div>
    -+    </div></a>
    -+    <div class="dac-section dac-small">
    -+      <div class="resource-widget resource-flow-layout col-16"
    -+           data-query="collection:nougat/landing/resources"
    -+           data-cardSizes="6x2"
    -+           data-maxResults="3"></div>
    -+         </div>
    -+  </div>
    -+</section>
    -+
    -+
    -+<div class="dac-section dac-slim dac-gray dac-expand">
    -+  <div class="wrap dac-offset-parent">
    -+    <a class="dac-fab dac-scroll-button" data-scroll-button href="#latest">
    -+      <i class="dac-sprite dac-arrow-down-gray"></i>
    -+    </a>
    -+    <ul class="dac-actions">
    -+      <li class="dac-action">
    -+        <a class="dac-action-link" href="https://source.android.com/source/report-bugs.html">
    -+          <i class="dac-action-sprite dac-sprite dac-auto-chevron-large"></i>
    -+          Laporkan masalah
    -+        </a>
    -+      </li>
    -+      <li class="dac-action">
    -+        <a class="dac-action-link" href="{@docRoot}preview/dev-community">
    -+          <i class="dac-action-sprite dac-sprite dac-auto-chevron-large"></i>
    -+          Bergabunglah dengan komunitas pengembang
    -+        </a>
    -+      </li>
    -+    </ul>
    -+  </div><!-- end .wrap -->
    -+</div><!-- end .dac-actions -->
    -+
    -+<section class="dac-section dac-light dac-small" id="latest"><div class="wrap">
    -+  <h2 class="norule">Terbaru</h2>
    -+  <div class="resource-widget resource-flow-layout col-16"
    -+    data-query="type:blog+tag:androidn+tag:featured, type:youtube+tag:androidn+tag:featured"
    -+    data-sortOrder="-timestamp"
    -+    data-cardSizes="6x6"
    -+    data-items-per-page="6"
    -+    data-maxResults="15"
    -+    data-initial-results="3"></div>
    -+</div></section>
    -+
    -+<section class="dac-section dac-gray" id="videos"><div class="wrap">
    -+  <h1 class="dac-section-title">Videos</h1>
    -+  <div class="dac-section-subtitle">
    -+    New Android capabilities and the right way to use them in your apps.
    -+  </div>
    -+
    -+  <div class="resource-widget resource-flow-layout col-16"
    -+    data-query="collection:nougat/landing/videos/first,type:youtube+tag:androidn"
    -+    data-sortOrder="-timestamp"
    -+    data-cardSizes="6x6"
    -+    data-items-per-page="6"
    -+    data-maxResults="15"
    -+    data-initial-results="3">
    -+  </div>
    -+</div></section>
    -+
    -+<section class="dac-section dac-light" id="resources"><div class="wrap">
    -+  <h1 class="dac-section-title">Sumber Daya</h1>
    -+  <div class="dac-section-subtitle">
    -+    Informasi penting guna membantu mempersiapkan aplikasi untuk Android Nougat.
    -+  </div>
    -+
    -+  <div class="resource-widget resource-flow-layout col-16"
    -+       data-query="collection:nougat/landing/more"
    -+       data-cardSizes="6x6"
    -+       data-items-per-page="6"
    -+       data-maxResults="15"
    -+       data-initial-results="6"></div>
    -+  </div>
    -+</section>
    -\ No newline at end of file
    -diff --git a/docs/html-intl/intl/id/design/get-started/principles.jd b/docs/html-intl/intl/id/design/get-started/principles.jd
    -new file mode 100644
    -index 0000000..2a1d194
    ---- /dev/null
    -+++ b/docs/html-intl/intl/id/design/get-started/principles.jd
    -@@ -0,0 +1,307 @@
    -+page.title=Prinsip Desain Android
    -+@jd:body
    -+
    -+<p>Prinsip desain ini dikembangkan oleh dan untuk Tim Pengalaman Pengguna
    -+ Android agar selalu mempertimbangkan kepentingan pengguna.
    -+Untuk pengembang dan desainer Android, mereka terus
    -+meletakkan dasar pedoman desain yang lebih detail untuk beragam tipe
    -+perangkat.</p>
    -+
    -+<p>
    -+Perhatikan prinsip-prinsip ini saat Anda menerapkan
    -+kreativitas dan pemikiran desain sendiri. Menyimpang dengan sengaja.
    -+</p>
    -+
    -+<h2 id="enchant-me">Pikat Saya</h2>
    -+
    -+<div class="cols">
    -+  <div class="col-7">
    -+
    -+<h4 id="delight-me">Senangkan saya dengan cara yang mengejutkan</h4>
    -+<p>Permukaan yang cantik, animasi yang ditempatkan dengan hati-hati, atau efek suara di saat yang tepat sungguh menyenangkan untuk
    -+dinikmati. Efek yang lembut menimbulkan perasaan serba mudah dan kesadaran bahwa kekuatan yang
    -+bisa diandalkan ada dalam genggaman.</p>
    -+
    -+  </div>
    -+  <div class="col-6">
    -+
    -+    <img src="{@docRoot}design/media/principles_delight.png">
    -+
    -+  </div>
    -+</div>
    -+
    -+<div class="vspace size-2">&nbsp;</div>
    -+
    -+<div class="cols">
    -+  <div class="col-7">
    -+
    -+<h4 id="real-objects-more-fun">Objek sungguhan lebih menyenangkan daripada tombol dan menu</h4>
    -+<p>Biarkan orang langsung menyentuh dan memanipulasi objek dalam aplikasi Anda. Ini mengurangi upaya kognitif
    -+yang diperlukan untuk menjalankan tugas sekaligus membuatnya lebih memuaskan secara emosional.</p>
    -+
    -+  </div>
    -+  <div class="col-6">
    -+
    -+    <img src="{@docRoot}design/media/principles_real_objects.png">
    -+
    -+  </div>
    -+</div>
    -+
    -+<div class="vspace size-2">&nbsp;</div>
    -+
    -+<div class="cols">
    -+  <div class="col-7">
    -+
    -+<h4 id="make-it-mine">Biarkan saya memilikinya</h4>
    -+<p>Orang suka menambahkan sentuhan pribadi karena membantu mereka merasa betah dan memegang kendali. Memberikan
    -+default yang pantas dan indah, tetapi juga mempertimbangkan penyesuaian opsional yang menyenangkan, yang tidak mengganggu
    -+tugas utama.</p>
    -+
    -+  </div>
    -+  <div class="col-6">
    -+
    -+    <img src="{@docRoot}design/media/principles_make_it_mine.png">
    -+
    -+  </div>
    -+</div>
    -+
    -+<div class="vspace size-2">&nbsp;</div>
    -+
    -+<div class="cols">
    -+  <div class="col-7">
    -+
    -+<h4 id="get-to-know-me">Kenali saya</h4>
    -+<p>Pelajari preferensi orang dari waktu ke waktu. Daripada meminta mereka untuk membuat pilihan yang sama
    -+berulang-ulang, tempatkan pilihan sebelumnya agar mudah dijangkau.</p>
    -+
    -+  </div>
    -+  <div class="col-6">
    -+
    -+    <img src="{@docRoot}design/media/principles_get_to_know_me.png">
    -+
    -+  </div>
    -+</div>
    -+
    -+<h2 id="simplify-my-life">Sederhanakan Hidup Saya</h2>
    -+
    -+<div class="cols">
    -+  <div class="col-7">
    -+
    -+<h4 id="keep-it-brief">Persingkat</h4>
    -+<p>Gunakan frasa pendek dengan kata-kata sederhana. Orang cenderung melewatkan kalimat-kalimat panjang.</p>
    -+
    -+  </div>
    -+  <div class="col-6">
    -+
    -+    <img src="{@docRoot}design/media/principles_keep_it_brief.png">
    -+
    -+  </div>
    -+</div>
    -+
    -+<div class="vspace size-2">&nbsp;</div>
    -+
    -+<div class="cols">
    -+  <div class="col-7">
    -+
    -+<h4 id="pictures-faster-than-words">Gambar lebih cepat dibanding kata-kata</h4>
    -+<p>Pertimbangkan menggunakan gambar untuk menjelaskan gagasan. Gambar menarik perhatian orang dan bisa jauh lebih efisien
    -+dibanding kata-kata.</p>
    -+
    -+  </div>
    -+  <div class="col-6">
    -+
    -+    <img src="{@docRoot}design/media/principles_pictures.png">
    -+
    -+  </div>
    -+</div>
    -+
    -+<div class="vspace size-2">&nbsp;</div>
    -+
    -+<div class="cols">
    -+  <div class="col-7">
    -+
    -+<h4 id="decide-for-me">Putuskan untuk saya tetapi biarkan saya yang menentukan</h4>
    -+<p>Gunakan tebakan terbaik Anda dan bertindaklah daripada meminta terlebih dahulu. Terlalu banyak pilihan dan keputusan membuat orang
    -+tidak suka. Untuk berjaga-jaga jika Anda salah, izinkan 'pembatalan'.</p>
    -+
    -+  </div>
    -+  <div class="col-6">
    -+
    -+    <img src="{@docRoot}design/media/principles_decide_for_me.png">
    -+
    -+  </div>
    -+</div>
    -+
    -+<div class="vspace size-2">&nbsp;</div>
    -+
    -+<div class="cols">
    -+  <div class="col-7">
    -+
    -+<h4 id="only-show-when-i-need-it">Cukup tunjukkan yang saya perlukan ketika saya memerlukannya</h4>
    -+<p>Orang merasa kewalahan ketika melihat terlalu banyak hal sekaligus. Uraikan tugas dan informasi menjadi potongan-potongan
    -+kecil yang mudah dicerna. Sembunyikan opsi yang tidak perlu pada saat ini, dan ajari orang sambil jalan.</p>
    -+
    -+  </div>
    -+  <div class="col-6">
    -+
    -+    <img src="{@docRoot}design/media/principles_information_when_need_it.png">
    -+
    -+  </div>
    -+</div>
    -+
    -+<div class="vspace size-2">&nbsp;</div>
    -+
    -+<div class="cols">
    -+  <div class="col-7">
    -+
    -+<h4 id="always-know-where-i-am">Saya harus selalu tahu di mana saya berada</h4>
    -+<p>Beri orang kepercayaan diri bahwa mereka tahu di mana berada. Buat agar tempat-tempat dalam aplikasi Anda terlihat berbeda dan
    -+gunakan transisi untuk menunjukkan hubungan antar layar. Berikan umpan balik tentang tugas yang sedang berlangsung.</p>
    -+
    -+  </div>
    -+  <div class="col-6">
    -+
    -+    <img src="{@docRoot}design/media/principles_navigation.png">
    -+
    -+  </div>
    -+</div>
    -+
    -+<div class="vspace size-2">&nbsp;</div>
    -+
    -+<div class="cols">
    -+  <div class="col-7">
    -+
    -+<h4 id="never-lose-my-stuff">Jangan sekali-kali menghilangkan milik saya</h4>
    -+<p>Simpan apa yang telah susah-payah dibuat orang dan biarkan mereka mengaksesnya dari mana saja. Ingat pengaturan,
    -+sentuhan pribadi, dan kreasi lintas ponsel, tablet, dan komputer. Itu membuat pemutakhiran menjadi
    -+hal termudah di dunia.</p>
    -+
    -+  </div>
    -+  <div class="col-6">
    -+
    -+    <img src="{@docRoot}design/media/principles_never_lose_stuff.png">
    -+
    -+  </div>
    -+</div>
    -+
    -+<div class="vspace size-2">&nbsp;</div>
    -+
    -+<div class="cols">
    -+  <div class="col-7">
    -+
    -+<h4 id="looks-same-should-act-same">Jika terlihat sama, seharusnya fungsinya sama</h4>
    -+<p>Bantu orang merasakan perbedaan fungsional dengan membuat mereka terlihat berbeda daripada mirip.
    -+Hindari mode, yaitu tempat yang terlihat mirip tetapi berbeda fungsinya pada input yang sama.</p>
    -+
    -+  </div>
    -+  <div class="col-6">
    -+
    -+    <img src="{@docRoot}design/media/principles_looks_same.png">
    -+
    -+  </div>
    -+</div>
    -+
    -+<div class="vspace size-2">&nbsp;</div>
    -+
    -+<div class="cols">
    -+  <div class="col-7">
    -+
    -+<h4 id="interrupt-only-if-important">Sela saya jika penting saja</h4>
    -+<p>Layaknya asisten pribadi yang baik, lindungi orang dari detail yang tidak penting. Orang ingin tetap
    -+fokus, dan kecuali jika memang penting dan sensitif waktu, interupsi bisa melelahkan dan menjengkelkan.</p>
    -+
    -+  </div>
    -+  <div class="col-6">
    -+
    -+    <img src="{@docRoot}design/media/principles_important_interruption.png">
    -+
    -+  </div>
    -+</div>
    -+
    -+<h2 id="make-me-amazing">Buat Saya Terpesona</h2>
    -+
    -+<div class="cols">
    -+  <div class="col-7">
    -+
    -+<h4 id="give-me-tricks">Beri saya trik yang efektif di mana saja</h4>
    -+<p>Orang merasa senang ketika mereka memahami sendiri sesuatu. Jadikan aplikasi Anda lebih mudah dipelajari dengan
    -+memanfaatkan pola visual dan memori otot dari aplikasi Android lainnya. Misalnya, gerakan menggeser
    -+dapat menjadi pintasan navigasi yang bagus.</p>
    -+
    -+  </div>
    -+  <div class="col-6">
    -+
    -+    <img src="{@docRoot}design/media/principles_tricks.png">
    -+
    -+  </div>
    -+</div>
    -+
    -+<div class="vspace size-2">&nbsp;</div>
    -+
    -+<div class="cols">
    -+  <div class="col-7">
    -+
    -+<h4 id="its-not-my-fault">Bukan salah saya</h4>
    -+<p>Bersikap ramahlah dalam meminta orang untuk melakukan koreksi. Mereka ingin merasa pintar ketika menggunakan
    -+aplikasi Anda. Jika terjadi kesalahan, berikan petunjuk perbaikan yang jelas tetapi lepaskan mereka dari detail teknis.
    -+Jika Anda dapat memperbaikinya secara diam-diam, tentu lebih baik.</p>
    -+
    -+  </div>
    -+  <div class="col-6">
    -+
    -+    <img src="{@docRoot}design/media/principles_error.png">
    -+
    -+  </div>
    -+</div>
    -+
    -+<div class="vspace size-2">&nbsp;</div>
    -+
    -+<div class="cols">
    -+  <div class="col-7">
    -+
    -+<h4 id="sprinkle-encouragement">Berikan dorongan</h4>
    -+<p>Uraikan tugas-tugas rumit menjadi langkah-langkah kecil yang dapat dilakukan dengan mudah. Beri umpan balik tentang tindakan,
    -+meskipun hanya sesuatu yang sederhana.</p>
    -+
    -+  </div>
    -+  <div class="col-6">
    -+
    -+    <img src="{@docRoot}design/media/principles_sprinkle_encouragement.png">
    -+
    -+  </div>
    -+</div>
    -+
    -+<div class="vspace size-2">&nbsp;</div>
    -+
    -+<div class="cols">
    -+  <div class="col-7">
    -+
    -+<h4 id="do-heavy-lifting-for-me">Lakukan pekerjaan yang sulit untuk saya</h4>
    -+<p>Buatlah pemula merasa seperti ahli dengan memungkinkan mereka untuk melakukan hal-hal yang mereka pikir tidak akan bisa.
    -+Misalnya, pintasan yang menggabungkan beberapa efek foto dapat membuat foto amatir terlihat mengagumkan hanya
    -+dalam beberapa langkah.</p>
    -+
    -+  </div>
    -+  <div class="col-6">
    -+
    -+    <img src="{@docRoot}design/media/principles_heavy_lifting.png">
    -+
    -+  </div>
    -+</div>
    -+
    -+<div class="vspace size-2">&nbsp;</div>
    -+
    -+<div class="cols">
    -+  <div class="col-7">
    -+
    -+<h4 id="make-important-things-fast">Percepat hal penting</h4>
    -+<p>Tidak semua tindakan itu sama. Putuskan apa yang terpenting dalam aplikasi Anda dan permudah untuk menemukannya serta
    -+cepat untuk digunakan, seperti tombol rana pada kamera, atau tombol jeda pada pemutar musik.</p>
    -+
    -+  </div>
    -+  <div class="col-6">
    -+
    -+    <img src="{@docRoot}design/media/principles_make_important_fast.png">
    -+
    -+  </div>
    -+</div>
    -diff --git a/docs/html-intl/intl/id/design/material/index.jd b/docs/html-intl/intl/id/design/material/index.jd
    -new file mode 100644
    -index 0000000..0cb4dbc
    ---- /dev/null
    -+++ b/docs/html-intl/intl/id/design/material/index.jd
    -@@ -0,0 +1,186 @@
    -+page.title=Material Design for Android
    -+page.tags=Material,design
    -+page.type=design
    -+page.image=images/cards/design-material-for-android_2x.jpg
    -+
    -+@jd:body
    -+
    -+<!-- developer docs box -->
    -+<a class="notice-developers right" href="{@docRoot}training/material/index.html">
    -+  <div>
    -+    <h3>Dokumen Pengembang</h3>
    -+    <p>Membuat Aplikasi dengan Desain Bahan</p>
    -+  </div>
    -+</a>
    -+
    -+<!-- video box -->
    -+<a class="notice-developers-video" href="https://www.youtube.com/watch?v=p4gmvHyuZzw">
    -+<div>
    -+    <h3>Video</h3>
    -+    <p>Pengantar Desain Bahan</p>
    -+</div>
    -+</a>
    -+
    -+<!-- video box -->
    -+<a class="notice-developers-video" href="https://www.youtube.com/watch?v=YaG_ljfzeUw">
    -+<div>
    -+    <h3>Video</h3>
    -+    <p>Kertas dan Tinta: Bahan Penting</p>
    -+</div>
    -+</a>
    -+
    -+<!-- video box -->
    -+<a class="notice-developers-video" href="https://www.youtube.com/watch?v=XOcCOBe8PTc">
    -+<div>
    -+    <h3>Video</h3>
    -+    <p>Desain Bahan di Aplikasi Google I/O</p>
    -+</div>
    -+</a>
    -+
    -+
    -+
    -+<p itemprop="description">Desain bahan adalah panduan komprehensif untuk desain visual, gerak, dan
    -+interaksi lintas platform dan perangkat. Android kini menyertakan dukungan untuk
    -+aplikasi desain bahan. Untuk menggunakan desain bahan di aplikasi Android, ikuti panduan yang didefinisikan
    -+dalam <a href="http://www.google.com/design/spec">spesifikasi desain bahan</a> dan gunakan
    -+komponen dan fungsionalitas baru yang tersedia di Android 5.0 (API level 21) ke atas.</p>
    -+
    -+<p>Android menyediakan elemen berikut untuk membangun aplikasi desain bahan:</p>
    -+
    -+<ul>
    -+  <li>Tema baru</li>
    -+  <li>Widget baru untuk tampilan yang kompleks</li>
    -+  <li>API baru untuk animasi dan bayangan custom</li>
    -+</ul>
    -+
    -+<p>Untuk informasi selengkapnya tentang mengimplementasikan desain bahan pada Android, lihat
    -+<a href="{@docRoot}training/material/index.html">Membuat Aplikasi dengan Desain Bahan</a>.</p>
    -+
    -+
    -+<h3>Tema Bahan</h3>
    -+
    -+<p>Tema bahan menyediakan gaya baru untuk aplikasi Anda, widget sistem yang memungkinkan Anda mengatur
    -+palet warnanya, dan animasi default untuk umpan balik sentuh dan transisi aktivitas.</p>
    -+
    -+<!-- two columns -->
    -+<div style="width:700px;margin-top:25px;margin-bottom:20px">
    -+<div style="float:left;width:250px;margin-left:40px;margin-right:60px;">
    -+  <img src="{@docRoot}design/material/images/MaterialDark.png" width="500" height="238" />
    -+  <div style="width:140px;margin:0 auto">
    -+  <p style="margin-top:8px">Tema bahan gelap</p>
    -+  </div>
    -+</div>
    -+<div style="float:left;width:250px;margin-right:0px;">
    -+  <img src="{@docRoot}design/material/images/MaterialLight.png" width="500" height="238" />
    -+  <div style="width:140px;margin:0 auto">
    -+  <p style="margin-top:8px">Tema bahan terang</p>
    -+  </div>
    -+</div>
    -+<br style="clear:left"/>
    -+</div>
    -+
    -+<p>Untuk informasi selengkapnya, lihat <a href="{@docRoot}training/material/theme.html">Menggunakan Tema
    -+Bahan</a>.</p>
    -+
    -+
    -+<h3>Daftar dan Kartu</h3>
    -+
    -+<p>Android menyediakan dua widget baru untuk menampilkan kartu dan daftar dengan gaya desain bahan
    -+dan animasi:</p>
    -+
    -+<!-- two columns -->
    -+<div style="width:700px;margin-top:25px;margin-bottom:20px">
    -+<div style="float:left;width:250px;margin-left:40px;margin-right:60px;">
    -+  <img src="{@docRoot}design/material/images/list_mail.png" width="500" height="426" />
    -+  <p>Widget <code>RecyclerView</code> baru adalah versi <code>ListView</code>
    -+ yang lebih mudah dimasukkan dan mendukung beragam tipe layout serta memberikan peningkatan kinerja.</p>
    -+</div>
    -+<div style="float:left;width:250px;margin-right:0px;">
    -+  <img src="{@docRoot}design/material/images/card_travel.png" width="500" height="426" />
    -+  <p>Widget <code>CardView</code> baru memungkinkan Anda menampilkan potongan informasi penting dalam
    -+  kartu yang memiliki tampilan dan cara kerja yang konsisten.</p>
    -+</div>
    -+<br style="clear:left"/>
    -+</div>
    -+
    -+<p>Untuk informasi selengkapnya, lihat <a href="{@docRoot}training/material/lists-cards.html">Membuat Daftar
    -+dan Kartu</a>.</p>
    -+
    -+
    -+<h3>Bayangan Tampilan</h3>
    -+
    -+<p>Selain properti X dan Y, tampilan di Android kini memiliki
    -+properti Z. Properti baru ini mewakili ketinggian tampilan, yang menentukan:</p>
    -+
    -+<ul>
    -+<li>Ukuran bayangan: tampilan dengan nilai Z lebih tinggi menghasilkan bayangan lebih besar.</li>
    -+<li>Urutan penggambaran: tampilan dengan nilai Z lebih tinggi muncul di atas tampilan lainnya.</li>
    -+</ul>
    -+
    -+<div style="width:290px;margin-left:35px;float:right">
    -+  <div class="framed-nexus5-port-span-5">
    -+  <video class="play-on-hover" autoplay>
    -+    <source src="{@docRoot}design/material/videos/ContactsAnim.mp4"/>
    -+    <source src="{@docRoot}design/videos/ContactsAnim.webm"/>
    -+    <source src="{@docRoot}design/videos/ContactsAnim.ogv"/>
    -+  </video>
    -+  </div>
    -+  <div style="font-size:10pt;margin-left:20px;margin-bottom:30px">
    -+    <em>Untuk memutar ulang film, klik layar perangkat</em>
    -+  </div>
    -+</div>
    -+
    -+<p>Untuk informasi selengkapnya, lihat <a href="{@docRoot}training/material/shadows-clipping.html">Mendefinisikan
    -+Bayangan dan Memangkas Tampilan</a>.</p>
    -+
    -+
    -+<h3>Animasi</h3>
    -+
    -+<p>API animasi baru memungkinkan Anda membuat animasi custom untuk umpan balik sentuh dalam kontrol UI,
    -+perubahan status tampilan, dan transisi aktivitas.</p>
    -+
    -+<p>API ini memungkinkan Anda:</p>
    -+
    -+<ul>
    -+<li style="margin-bottom:15px">
    -+Merespons kejadian sentuh dalam tampilan Anda dengan animasi <strong>umpan balik sentuh</strong>.
    -+</li>
    -+<li style="margin-bottom:15px">
    -+Menyembunyikan dan memperlihatkan tampilan dengan animasi <strong>membuka melingkar</strong>.
    -+</li>
    -+<li style="margin-bottom:15px">
    -+Peralihan antar aktivitas dengan animasi <strong>transisi aktivitas</strong> custom.
    -+</li>
    -+<li style="margin-bottom:15px">
    -+Membuat animasi yang lebih alami dengan <strong>gerak melengkung</strong>.
    -+</li>
    -+<li style="margin-bottom:15px">
    -+Menganimasikan perubahan dalam satu atau beberapa properti tampilan dengan animasi <strong>perubahan status tampilan</strong>.
    -+</li>
    -+<li style="margin-bottom:15px">
    -+Menampilkan animasi di <strong>drawable daftar status</strong> di antara perubahan status tampilan.
    -+</li>
    -+</ul>
    -+
    -+<p>Animasi umpan balik sentuh dimasukkan ke dalam beberapa tampilan standar, misalnya tombol. API baru
    -+ini memungkinkan Anda menyesuaikan animasi ini dan menambahkannya ke tampilan custom Anda.</p>
    -+
    -+<p>Untuk informasi selengkapnya, lihat <a href="{@docRoot}training/material/animations.html">Mendefinisikan Animasi
    -+Custom</a>.</p>
    -+
    -+
    -+<h3>Drawable</h3>
    -+
    -+<p>Kemampuan baru untuk drawable ini membantu Anda mengimplementasikan aplikasi desain bahan:</p>
    -+
    -+<ul>
    -+<li><strong>Drawable vektor</strong> bisa diubah skalanya tanpa kehilangan definisi dan cocok
    -+untuk ikon satu-warna dalam-aplikasi.</li>
    -+<li><strong>Pewarnaan drawable</strong> memungkinkan Anda mendefinisikan bitmap sebagai alpha-mask dan mewarnainya
    -+saat runtime.</li>
    -+<li><strong>Ekstraksi warna</strong> memungkinkan Anda mengekstrak warna mencolok secara otomatis dari
    -+gambar bitmap.</li>
    -+</ul>
    -+
    -+<p>Untuk informasi selengkapnya, lihat <a href="{@docRoot}training/material/drawables.html">Bekerja dengan
    -+Drawable</a>.</p>
    -diff --git a/docs/html-intl/intl/id/design/patterns/compatibility.jd b/docs/html-intl/intl/id/design/patterns/compatibility.jd
    -new file mode 100644
    -index 0000000..cafaac4
    ---- /dev/null
    -+++ b/docs/html-intl/intl/id/design/patterns/compatibility.jd
    -@@ -0,0 +1,70 @@
    -+page.title=Kompatibilitas Mundur
    -+page.tags="support"
    -+page.metaDescription=Catatan tentang bagaimana Android 4.x menyesuaikan UI yang didesain untuk perangkat keras dan versi OS yang lebih lama.
    -+@jd:body
    -+
    -+<a class="notice-developers" href="{@docRoot}training/basics/supporting-devices/index.html">
    -+  <div>
    -+    <h3>Dokumen Pengembang</h3>
    -+    <p>Mendukung Perangkat Berbeda</p>
    -+  </div>
    -+</a>
    -+
    -+<p>Perubahan signifikan dalam Android 3.0 meliputi:</p>
    -+<ul>
    -+<li>Dihilangkannya tombol perangkat keras navigasi (Back, Menu, Search, Home) untuk membantu menangani navigasi
    -+  melalui kontrol maya (Back, Home, Recents).</li>
    -+<li>Pola yang tangguh untuk penggunaan menu pada action-bar.</li>
    -+</ul>
    -+<p>Android 4.0 membawa perubahan ini untuk tablet dengan platform ponsel.</p>
    -+
    -+<h2 id="older-hardware">Menyesuaikan Android 4.0 dengan Perangkat Keras dan Aplikasi yang Lebih Lama</h2>
    -+
    -+<div class="cols">
    -+  <div class="col-6">
    -+
    -+<h4>Ponsel dengan kontrol navigasi virtual</h4>
    -+<p>Aplikasi Android yang ditulis untuk Android 3.0 dan yang lebih baru menampilkan tindakan dalam action-bar. Tindakan yang tidak
    -+muat dalam action-bar atau tidak cukup penting untuk ditampilkan di tingkat atas akan muncul dalam
    -+action-overflow.</p>
    -+<p>Pengguna mengakses action-overflow dengan menyentuhnya dalam action-bar.</p>
    -+
    -+  </div>
    -+  <div class="col-7">
    -+
    -+    <img src="{@docRoot}design/media/compatibility_virtual_nav.png">
    -+
    -+  </div>
    -+</div>
    -+
    -+<div class="cols">
    -+  <div class="col-6">
    -+
    -+<h4>Ponsel dengan tombol navigasi fisik</h4>
    -+<p>Ponsel Android dengan tombol perangkat keras navigasi biasa tidak menampilkan baris navigasi virtual di
    -+bagian bawah layar. Sebagai gantinya, action-overflow tersedia dari tombol perangkat keras menu. Popup
    -+tindakan yang dihasilkan memiliki gaya yang sama dengan contoh sebelumnya, tetapi ditampilkan di bagian bawah layar.</p>
    -+
    -+  </div>
    -+  <div class="col-7">
    -+
    -+    <img src="{@docRoot}design/media/compatibility_physical_buttons.png">
    -+
    -+  </div>
    -+</div>
    -+
    -+<div class="cols">
    -+  <div class="col-6">
    -+
    -+<h4>Aplikasi lama pada ponsel dengan kontrol navigasi virtual</h4>
    -+<p>Bila Anda menjalankan aplikasi yang dibuat untuk Android 2.3 atau yang lebih lama pada ponsel
    -+dengan kontrol navigasi virtual, sebuah kontrol action-overflow akan muncul di sebelah kanan baris navigasi virtual. Anda
    -+dapat menyentuh kontrol itu untuk menampilkan tindakan aplikasi dalam gaya menu Android biasa.</p>
    -+
    -+  </div>
    -+  <div class="col-7">
    -+
    -+    <img src="{@docRoot}design/media/compatibility_legacy_apps.png">
    -+
    -+  </div>
    -+</div>
    -diff --git a/docs/html-intl/intl/id/design/patterns/confirming-acknowledging.jd b/docs/html-intl/intl/id/design/patterns/confirming-acknowledging.jd
    -new file mode 100644
    -index 0000000..d22e924
    ---- /dev/null
    -+++ b/docs/html-intl/intl/id/design/patterns/confirming-acknowledging.jd
    -@@ -0,0 +1,70 @@
    -+page.title=Mengonfirmasi &amp; Mengakui
    -+page.tags=dialog,toast,notification
    -+@jd:body
    -+
    -+<p>Dalam beberapa situasi, bila pengguna memanggil suatu tindakan dalam aplikasi Anda, ada baiknya <em>mengonfirmasi</em> atau <em>mengakui</em> tindakan itu melalui teks.</p>
    -+
    -+<div class="cols">
    -+  <div class="col-6">
    -+    <img src="{@docRoot}design/media/confirm_ack_confirming.png">
    -+    <p><strong>Mengonfirmasi</strong> adalah meminta pengguna untuk memverifikasi bahwa mereka benar-benar ingin melanjutkan tindakan yang baru saja mereka panggil. Dalam beberapa kasus, konfirmasi ditampilkan bersama-sama dengan peringatan atau informasi penting yang terkait dengan tindakan yang perlu mereka pertimbangkan.</p>
    -+  </div>
    -+  <div class="col-6">
    -+    <img src="{@docRoot}design/media/confirm_ack_acknowledge.png">
    -+    <p><strong>Mengakui</strong> adalah menampilkan teks untuk memberi tahu pengguna bahwa tindakan yang baru mereka panggil sudah dilakukan. Ini menghilangkan ketidakpastian tentang operasi implisit yang dilakukan sistem. Dalam beberapa kasus, pengakuan ditampilkan bersama dengan opsi untuk membatalkan tindakan.</p>
    -+  </div>
    -+</div>
    -+
    -+<p>Berkomunikasi pada pengguna dengan cara ini bisa membantu mengurangi ketidakpastian tentang hal-hal yang sudah atau akan terjadi. Mengonfirmasi atau mengakui juga dapat mencegah pengguna melakukan kesalahan yang akan mereka sesali.</p>
    -+
    -+<h2>Kapan Harus Mengonfirmasi atau Mengakui Tindakan Pengguna</h2>
    -+<p>Tidak semua tindakan memerlukan konfirmasi atau pengakuan. Gunakan bagan alur ini untuk memandu keputusan desain Anda.</p>
    -+<img src="{@docRoot}design/media/confirm_ack_flowchart.png">
    -+
    -+<h2>Mengonfirmasi</h2>
    -+<div class="cols">
    -+  <div class="col-6">
    -+    <h4>Contoh: Google Play Books</h4>
    -+    <img src="{@docRoot}design/media/confirm_ack_ex_books.png">
    -+    <p>Dalam contoh ini, pengguna telah meminta untuk menghapus sebuah buku dari perpustakaan Google Play mereka. Sebuah <a href="{@docRoot}design/building-blocks/dialogs.html#alerts">peringatan</a> muncul untuk mengonfirmasi tindakan ini karena perlu dipahami bahwa buku tersebut tidak akan tersedia lagi dari perangkat apa pun.</p>
    -+    <p>Saat membuat dialog konfirmasi, buat judul bermakna dengan mencerminkan tindakan yang diminta.</p>
    -+  </div>
    -+  <div class="col-7">
    -+    <h4>Contoh: Android Beam</h4>
    -+    <img src="{@docRoot}design/media/confirm_ack_ex_beam.png">
    -+    <p>Konfirmasi tidak harus ditampilkan dalam peringatan dengan dua tombol. Setelah menjalankan Android Beam, pengguna diminta untuk menyentuh konten yang akan dibagikan (dalam contoh ini, sebuah foto). Jika mereka memutuskan untuk tidak melanjutkan, mereka tinggal memindahkan ponsel.</p>
    -+  </div>
    -+</div>
    -+
    -+<h2>Mengakui</h2>
    -+<div class="cols">
    -+  <div class="col-6">
    -+    <h4>Contoh: Draf Gmail batal yang disimpan</h4>
    -+    <img src="{@docRoot}design/media/confirm_ack_ex_draftsave.png">
    -+    <p>Dalam contoh ini, jika pengguna menyusuri ke belakang atau ke atas dari layar pembuatan email di Gmail, sesuatu yang tak diharapkan bisa terjadi: draf saat itu akan disimpan secara otomatis. Pengakuan dalam bentuk pemberitahuan akan lebih jelas. Ini menghilang setelah beberapa detik.</p>
    -+    <p>Pembatalan tidak cocok di sini karena penyimpanan dilakukan oleh aplikasi, bukan pengguna. Cepat dan mudah untuk melanjutkan penulisan pesan dengan menyusuri daftar draf.</p>
    -+
    -+  </div>
    -+  <div class="col-6">
    -+    <h4>Contoh: Percakapan Gmail dihapus</h4>
    -+    <img src="{@docRoot}design/media/confirm_ack_draft_deleted.png">
    -+    <p>Setelah pengguna menghapus percakapan dari daftar dalam Gmail, sebuah pengakuan muncul tanpa opsi pembatalan. Pengakuan tetap ada sampai pengguna melakukan tindakan yang tidak berkaitan, seperti menggulir daftar.</p>
    -+  </div>
    -+</div>
    -+
    -+<h2>Tidak ada Konfirmasi atau Pengakuan</h2>
    -+<div class="cols">
    -+  <div class="col-6">
    -+    <h4>Contoh: memberikan +1</h4>
    -+    <img style="padding: 33px 0 30px;" src="{@docRoot}design/media/confirm_ack_ex_plus1.png">
    -+    <p><strong>Konfirmasi tidak diperlukan</strong>. Jika pengguna telah memberikan +1 secara tidak sengaja, tidak masalah. Mereka cukup menyentuh kembali tombol itu untuk membatalkan tindakan.</p>
    -+    <p><strong>Pengakuan tidak diperlukan</strong>. Pengguna akan melihat tombol +1 memantul dan berubah merah. Itu tanda yang sangat jelas.</p>
    -+  </div>
    -+  <div class="col-7">
    -+    <h4>Contoh: Menghapus aplikasi dari Layar Beranda</h4>
    -+    <img src="{@docRoot}design/media/confirm_ack_ex_removeapp.png">
    -+    <p><strong>Konfirmasi tidak diperlukan</strong>. Ini adalah tindakan yang disengaja: pengguna harus menyeret dan meletakkan sebuah item di atas target yang relatif besar dan terpisah. Karena itu, kecil kemungkinan terjadi ketidaksengajaan. Tetapi jika pengguna menyesali keputusan itu, maka hanya perlu beberapa detik untuk mengembalikannya lagi.</p>
    -+    <p><strong>Pengakuan tidak diperlukan</strong>. Pengguna akan mengetahui bahwa aplikasi itu tidak ada di Layar Beranda karena mereka menghilangkannya dengan cara menyeretnya.</p>
    -+
    -+  </div>
    -+</div>
    -diff --git a/docs/html-intl/intl/id/design/patterns/navigation.jd b/docs/html-intl/intl/id/design/patterns/navigation.jd
    -new file mode 100644
    -index 0000000..4915700
    ---- /dev/null
    -+++ b/docs/html-intl/intl/id/design/patterns/navigation.jd
    -@@ -0,0 +1,213 @@
    -+page.title=Navigasi dengan Back dan Up
    -+page.tags="navigation","activity","task","up navigation","back navigation"
    -+page.image=/design/media/navigation_between_siblings_gmail.png
    -+@jd:body
    -+
    -+<a class="notice-developers" href="{@docRoot}training/implementing-navigation/index.html">
    -+  <div>
    -+    <h3>Dokumen Pengembang</h3>
    -+    <p>Mengimplementasikan Navigasi yang Efektif</p>
    -+  </div>
    -+</a>
    -+
    -+<p itemprop="description">Navigasi yang konsisten merupakan komponen penting dari keseluruhan pengalaman pengguna. Hampir tidak ada yang lebih membingungkan
    -+pengguna selain navigasi dasar yang perilakunya tidak konsisten dan tidak sesuai harapan. Android 3.0
    -+memperkenalkan perubahan besar dalam perilaku navigasi global. Mengikuti dengan saksama
    -+panduan untuk Back dan Up akan membuat navigasi aplikasi Anda dapat diprediksi dan dapat diandalkan pengguna.</p>
    -+<p>Android 2.3 dan versi sebelumnya mengandalkan tombol <em>Back</em> sistem untuk mendukung navigasi dalam
    -+aplikasi. Dengan diperkenalkannya action-bar dalam Android 3.0, mekanisme navigasi kedua muncul:
    -+tombol <em>Up</em>, yang terdiri dari ikon aplikasi dan tanda panah yang menunjuk ke kiri.</p>
    -+
    -+<img src="{@docRoot}design/media/navigation_with_back_and_up.png">
    -+
    -+<h2 id="up-vs-back">Up vs. Back</h2>
    -+
    -+<p>Tombol Up digunakan untuk berpindah dalam aplikasi berdasarkan hubungan hierarki
    -+antar layar. Misalnya, jika layar A menampilkan daftar item, dan memilih sebuah item akan membuka
    -+layar B (yang menampilkan item tersebut secara lebih detail), maka layar B akan menawarkan tombol Up untuk
    -+kembali ke layar A.</p>
    -+<p>Jika suatu layar merupakan yang teratas dalam aplikasi (yaitu layar Home aplikasi), maka tidak perlu menampilkan tombol
    -+Up.</p>
    -+
    -+<p>Tombol Back sistem digunakan untuk berpindah, dalam urutan kronologis terbalik, melalui riwayat
    -+layar yang baru dibuka oleh pengguna. Biasanya ini berdasarkan hubungan sementara
    -+antar layar, dan bukan hierarki aplikasi.</p>
    -+
    -+<p>Bila layar yang dilihat sebelumnya juga merupakan induk hierarki dari layar yang sekarang, menekan tombol
    -+Back akan sama hasilnya dengan menekan tombol Up&mdash;ini adalah kejadian
    -+biasa. Akan tetapi, berbeda dengan tombol Up, yang memastikan pengguna tetap berada dalam aplikasi Anda, tombol Back
    -+dapat mengembalikan pengguna ke layar Home, atau bahkan ke aplikasi lain.</p>
    -+
    -+<img src="{@docRoot}design/media/navigation_up_vs_back_gmail.png">
    -+
    -+<p>Tombol Back juga mendukung beberapa perilaku yang tidak terkait langsung dengan navigasi antar layar:
    -+</p>
    -+<ul>
    -+<li>Menghilangkan jendela mengambang (dialog, popup)</li>
    -+<li>Menghilangkan action-bar kontekstual, dan menghapus sorotan dari item yang dipilih</li>
    -+<li>Menyembunyikan keyboard di layar (IME)</li>
    -+</ul>
    -+<h2 id="within-app">Navigasi Dalam Aplikasi Anda</h2>
    -+
    -+<h4>Berpindah ke layar yang memiliki beberapa titik masuk</h4>
    -+<p>Kadang-kadang layar tidak memiliki posisi pasti dalam hierarki aplikasi, dan bisa dimasuki
    -+dari berbagai titik masuk&mdash;seperti layar pengaturan yang dapat dibuka dari layar lain
    -+dalam aplikasi Anda. Dalam hal ini, tombol Up akan memilih untuk kembali ke layar pengarah, yang cara kerjanya
    -+sama dengan tombol Back.</p>
    -+<h4>Mengubah tampilan dalam layar</h4>
    -+<p>Mengubah opsi tampilan untuk layar tidak mengubah perilaku Up atau Back: layar tetap
    -+berada di tempat yang sama dalam hierarki aplikasi, dan tidak dibuat riwayat navigasi yang baru.</p>
    -+<p>Contoh perubahan tampilan tersebut adalah:</p>
    -+<ul>
    -+<li>Mengganti tampilan menggunakan tab dan/atau geser kiri dan kanan</li>
    -+<li>Mengubah tampilan menggunakan tarik-turun (alias tab turun)</li>
    -+<li>Memfilter daftar</li>
    -+<li>Menyortir daftar</li>
    -+<li>Mengubah karakteristik tampilan (seperti zoom)</li>
    -+</ul>
    -+<h4>Berpindah antar layar yang seinduk</h4>
    -+<p>Bila aplikasi Anda mendukung navigasi dari daftar item ke tampilan detail salah satu item tersebut, aplikasi
    -+juga sering diharapkan mendukung navigasi langsung dari item itu ke item sebelumnya atau
    -+sesudahnya dalam daftar. Misalnya, dalam Gmail, begitu mudah untuk bergeser ke kiri atau kanan dari sebuah percakapan
    -+untuk melihat percakapan yang lebih baru atau lebih lama dalam Inbox yang sama. Sama seperti saat mengubah tampilan dalam layar, navigasi
    -+ini tidak mengubah perilaku Up atau Back.</p>
    -+
    -+<img src="{@docRoot}design/media/navigation_between_siblings_gmail.png">
    -+
    -+<p>Akan tetapi, pengecualian khusus terhadap hal ini terjadi saat menjelajah di antara tampilan detail terkait yang tidak disatukan
    -+oleh daftar yang merujuknya&mdash;misalnya, saat menjelajahi Play Store di antara aplikasi dari
    -+pengembang yang sama, atau album dari artis yang sama. Dalam hal ini, mengikuti setiap tautan akan membuat
    -+riwayat, sehingga tombol Back akan menyusuri setiap layar yang dilihat sebelumnya. Tombol Up akan terus
    -+melewatkan semua layar terkait ini dan berpindah ke layar kontainer yang terakhir dilihat.</p>
    -+
    -+<img src="{@docRoot}design/media/navigation_between_siblings_market1.png">
    -+
    -+<p>Anda dapat menjadikan perilaku tombol Up lebih cerdas lagi berdasarkan pengetahuan Anda tentang tampilan
    -+detail. Dengan memperluas contoh Play Store dari atas, bayangkan pengguna yang telah berpindah dari Buku
    -+terakhir yang dilihat ke detail untuk adaptasi Film. Dalam hal itu, tombol Up dapat kembali ke kontainer
    -+(Movies) yang sebelumnya belum dilalui pengguna.</p>
    -+
    -+<img src="{@docRoot}design/media/navigation_between_siblings_market2.png">
    -+
    -+<h2 id="into-your-app">Navigasi ke Aplikasi Anda melalui Widget dan Pemberitahuan Layar Home</h2>
    -+
    -+<p>Anda bisa menggunakan widget atau pemberitahuan layar Home untuk membantu pengguna berpindah langsung ke layar
    -+jauh dalam hierarki aplikasi Anda. Misalnya, widget Inbox dan pemberitahuan pesan baru di Gmail dapat
    -+melewatkan layar Inbox, dan membawa pengguna langsung ke tampilan percakapan.</p>
    -+
    -+<p>Untuk kedua kasus ini, tangani tombol Up sebagai berikut:</p>
    -+
    -+<ul>
    -+<li><em>Jika layar tujuan biasanya dicapai dari satu layar tertentu dalam aplikasi
    -+Anda</em>, tombol Up akan mengarahkannya ke layar itu.</li>
    -+<li><em>Jika tidak</em>, tombol Up akan mengarahkan ke layar teratas ("Home") dari aplikasi Anda.</li>
    -+</ul>
    -+
    -+<p>Dalam hal tombol Back, Anda harus membuat navigasi lebih bisa diprediksi dengan menyisipkan ke dalam
    -+back-stack tugas path navigasi naik lengkap menuju layar teratas aplikasi. Ini memungkinkan pengguna
    -+yang lupa cara masuk ke aplikasi Anda untuk berpindah ke layar teratas aplikasi sebelum
    -+keluar.</p>
    -+
    -+<p>Sebagai contoh, widget layar Home di Gmail memiliki tombol untuk menuju langsung ke layar
    -+Compose. Tombol Up atau Back dari layar Compose akan membawa pengguna ke Inbox, dan dari sana tombol
    -+Back berlanjut ke Home.</p>
    -+
    -+<img src="{@docRoot}design/media/navigation_from_outside_back.png">
    -+
    -+<h4>Pemberitahuan tidak langsung</h4>
    -+
    -+<p>Jika aplikasi Anda perlu menampilkan informasi tentang beberapa kejadian sekaligus, aplikasi dapat menggunakan
    -+pemberitahuan tunggal yang mengarahkan pengguna ke layar antara. Layar ini merangkum semua
    -+kejadian tersebut, dan menyediakan path bagi pengguna untuk menjelajah ke dalam aplikasi. Pemberitahuan dengan gaya seperti ini
    -+disebut <em>pemberitahuan tidak langsung</em>.</p>
    -+
    -+<p>Berbeda dengan pemberitahuan standar (langsung), menekan tombol Back dari
    -+layar antara pada pemberitahuan tidak langsung akan mengembalikan pengguna ke titik pemicu pemberitahuan tersebut&mdash;tidak ada
    -+layar tambahan yang disisipkan ke dalam back-stack. Setelah pengguna melanjutkan ke dalam aplikasi dari
    -+layar antara, tombol Up dan Back akan berperilaku seperti pada pemberitahuan standar, sebagaimana dijelaskan di atas:
    -+menyusuri ke dalam aplikasi dan bukan kembali ke layar antara.</p>
    -+
    -+<p>Misalnya, anggaplah seorang pengguna di Gmail menerima pemberitahuan tidak langsung dari Kalender. Menyentuh
    -+pemberitahuan ini akan membuka layar antara, yang menampilkan pengingat beberapa macam
    -+kejadian. Menyentuh Back dari layar antara akan mengembalikan pengguna ke Gmail. Menyentuh kejadian
    -+tertentu akan membawa pengguna dari layar antara ke aplikasi Kalender lengkap untuk menampilkan detail
    -+kejadian. Dari detail kejadian, tombol Up dan Back akan mengarahkan ke tampilan Kalender tingkat atas.</p>
    -+
    -+<img src="{@docRoot}design/media/navigation_indirect_notification.png">
    -+
    -+<h4>Pemberitahuan pop-up</h4>
    -+
    -+<p><em>Pemberitahuan pop-up</em> akan melewatkan laci pemberitahuan, bukan muncul secara langsung di
    -+hadapan pengguna. Ini jarang digunakan, dan <strong>harus dicadangkan untuk peristiwa yang memerlukan respons tepat waktu
    -+dan diperlukan interupsi dari konteks pengguna</strong>. Misalnya,
    -+Talk menggunakan gaya ini untuk memberi tahu pengguna tentang ajakan dari teman untuk bergabung dalam chatting video, karena
    -+ajakan ini akan kedaluwarsa secara otomatis setelah beberapa detik.</p>
    -+
    -+<p>Dalam hal perilaku navigasi, pemberitahuan pop-up sangat mirip perilaku pemberitahuan
    -+tidak langsung pada layar antara. Tombol Back akan menghilangkan pemberitahuan pop-up. Jika pengguna berpindah
    -+dari pop-up ke aplikasi yang memberi tahu, tombol Up dan Back akan mengikuti aturan pemberitahuan standar,
    -+berpindah dalam aplikasi.</p>
    -+
    -+<img src="{@docRoot}design/media/navigation_popup_notification.png">
    -+
    -+<h2 id="between-apps">Navigasi Antar Aplikasi</h2>
    -+
    -+<p>Salah satu kekuatan dasar sistem Android adalah kemampuan aplikasi untuk saling
    -+mengaktifkan, sehingga pengguna dapat berpindah langsung dari satu aplikasi ke aplikasi lainnya. Misalnya, sebuah
    -+aplikasi yang perlu mengambil foto dapat mengaktifkan aplikasi Kamera, yang akan mengembalikan foto
    -+ke aplikasi perujuk. Ini sangat menguntungkan pengembang, yang bisa dengan mudah memanfaatkan
    -+kode dari aplikasi lain, maupun pengguna, yang menikmati pengalaman konsisten untuk tindakan yang biasa
    -+dilakukan.</p>
    -+
    -+<p>Untuk memahami navigasi antar aplikasi, maka perlu memahami perilaku kerangka kerja Android
    -+yang akan dibahas di bawah ini.</p>
    -+
    -+<h4>Aktivitas, tugas, dan intent</h4>
    -+
    -+<p>Dalam Android, <strong>aktivitas</strong> adalah komponen aplikasi yang mendefinisikan layar
    -+informasi dan semua tindakan terkait yang dapat dilakukan pengguna. Aplikasi Anda adalah kumpulan
    -+aktivitas, yang terdiri dari aktivitas yang Anda buat dan aktivitas yang Anda gunakan ulang dari aplikasi lain.</p>
    -+
    -+<p><strong>Tugas</strong> adalah urutan aktivitas yang diikuti pengguna untuk mencapai tujuan.
    -+Tugas tunggal dapat memanfaatkan aktivitas dari satu aplikasi saja, atau dapat memanfaatkan aktivitas dari sejumlah
    -+aplikasi berbeda.</p>
    -+
    -+<p><strong>Intent</strong> adalah mekanisme bagi satu aplikasi untuk memberi isyarat minta bantuan
    -+aplikasi lain dalam menjalankan suatu tindakan. Aktivitas aplikasi dapat menunjukkan intent
    -+ apa saja yang dapat diresponsnya. Untuk intent umum seperti "Share", pengguna mungkin telah menginstal beberapa aplikasi
    -+yang dapat memenuhi permintaan itu.</p>
    -+
    -+<h4>Contoh: berpindah antar aplikasi untuk mendukung berbagi</h4>
    -+
    -+<p>Untuk memahami cara kerja sama aktivitas, tugas, dan intent, perhatikan bagaimana sebuah aplikasi memungkinkan pengguna
    -+untuk berbagi konten dengan menggunakan aplikasi lain. Misalnya, membuka aplikasi Play Store dari Home akan memulai
    -+Task A baru (lihat gambar di bawah). Setelah menyusuri Play Store dan menyentuh buku yang dipromosikan
    -+untuk melihat detailnya, pengguna tetap berada dalam tugas yang sama, memperluasnya dengan menambahkan aktivitas. Memicu
    -+tindakan Share akan memberi tahu pengguna dengan dialog berisi daftar aktivitas (dari aplikasi berbeda)
    -+yang telah terdaftar untuk menangani intent Share.</p>
    -+
    -+<img src="{@docRoot}design/media/navigation_between_apps_inward.png">
    -+
    -+<p>Bila pengguna memilih untuk berbagi melalui Gmail, aktivitas penulisan di Gmail akan ditambahkan sebagai kelanjutan dari
    -+Task A&mdash;tidak ada tugas baru yang dibuat. Jika Gmail sedang menjalankan tugasnya di latar belakang, maka
    -+tidak akan terpengaruh.</p>
    -+
    -+<p>Dari aktivitas penulisan, mengirim pesan atau menyentuh tombol Back akan mengembalikan pengguna ke
    -+aktivitas detail buku tersebut. Penyentuhan tombol Back berikutnya akan terus mengarahkan kembali melalui Play
    -+Store, sampai akhirnya tiba di Home.</p>
    -+
    -+<img src="{@docRoot}design/media/navigation_between_apps_back.png">
    -+
    -+<p>Akan tetapi, dengan menyentuh tombol Up dari aktivitas penulisan, pengguna menunjukkan keinginan untuk tetap berada di
    -+Gmail. Aktivitas daftar percakapan Gmail muncul, Task B yang baru akan dibuat untuk itu. Tugas baru
    -+selalu terkait ke Home, maka menyentuh tombol Back dari daftar percakapan akan mengembalikan ke sana.</p>
    -+
    -+<img src="{@docRoot}design/media/navigation_between_apps_up.png">
    -+
    -+<p>Task A tetap berjalan di latar belakang, dan pengguna nanti dapat kembali ke sana (misalnya, melalui layar
    -+Recents). Jika Gmail sedang menjalankan tugasnya di latar belakang, maka itu akan digantikan
    -+dengan Task B&mdash;konteks sebelumnya akan diabaikan demi tujuan baru pengguna.</p>
    -+
    -+<p>Jika register aplikasi Anda menangani intent dengan aktivitas yang jauh di dalam hierarki aplikasi,
    -+lihat <a href="#into-your-app">Navigasi Aplikasi Anda melalui Widget Layar Home dan
    -+Pemberitahuan</a> untuk panduan mengenai cara menetapkan navigasi Up.</p>
    -diff --git a/docs/html-intl/intl/id/guide/components/activities.jd b/docs/html-intl/intl/id/guide/components/activities.jd
    -new file mode 100644
    -index 0000000..bbc061c
    ---- /dev/null
    -+++ b/docs/html-intl/intl/id/guide/components/activities.jd
    -@@ -0,0 +1,756 @@
    -+page.title=Aktivitas
    -+page.tags=aktivitas,intent
    -+@jd:body
    -+
    -+<div id="qv-wrapper">
    -+<div id="qv">
    -+<h2>Dalam dokumen ini</h2>
    -+<ol>
    -+  <li><a href="#Creating">Membuat Aktivitas</a>
    -+    <ol>
    -+      <li><a href="#UI">Mengimplementasikan antarmuka pengguna</a></li>
    -+      <li><a href="#Declaring">Mendeklarasikan aktivitas dalam manifes</a></li>
    -+    </ol>
    -+  </li>
    -+  <li><a href="#StartingAnActivity">Memulai Aktivitas</a>
    -+    <ol>
    -+      <li><a href="#StartingAnActivityForResult">Memulai aktivitas agar berhasil</a></li>
    -+    </ol>
    -+  </li>
    -+  <li><a href="#ShuttingDown">Mematikan Aktivitas</a></li>
    -+  <li><a href="#Lifecycle">Mengelola Daur Hidup Aktivitas</a>
    -+    <ol>
    -+      <li><a href="#ImplementingLifecycleCallbacks">Mengimplementasikan callback daur hidup</a></li>
    -+      <li><a href="#SavingActivityState">Menyimpan status aktivitas</a></li>
    -+      <li><a href="#ConfigurationChanges">Menangani perubahan konfigurasi</a></li>
    -+      <li><a href="#CoordinatingActivities">Mengoordinasikan aktivitas</a></li>
    -+    </ol>
    -+  </li>
    -+</ol>
    -+
    -+<h2>Kelas-kelas utama</h2>
    -+<ol>
    -+  <li>{@link android.app.Activity}</li>
    -+</ol>
    -+
    -+<h2>Lihat juga</h2>
    -+<ol>
    -+  <li><a href="{@docRoot}guide/components/tasks-and-back-stack.html">Tugas dan
    -+Back-Stack</a></li>
    -+</ol>
    -+
    -+</div>
    -+</div>
    -+
    -+
    -+
    -+<p>{@link android.app.Activity} adalah sebuah komponen aplikasi yang menyediakan layar yang digunakan
    -+pengguna untuk berinteraksi guna melakukan sesuatu, misalnya memilih nomor telepon, mengambil foto, mengirim email, atau
    -+menampilkan peta. Tiap aktivitas diberi sebuah jendela untuk menggambar antarmuka penggunanya. Jendela ini
    -+biasanya mengisi layar, namun mungkin lebih kecil daripada layar dan mengambang di atas
    -+jendela lain.</p>
    -+
    -+<p> Sebuah aplikasi biasanya terdiri atas beberapa aktivitas yang terikat secara longgar
    -+satu sama lain. Biasanya, satu aktivitas dalam aplikasi ditetapkan sebagai aktivitas "utama", yang
    -+ditampilkan kepada pengguna saat membuka aplikasi untuk pertama kali. Tiap
    -+aktivitas kemudian bisa memulai aktivitas lain untuk melakukan berbagai tindakan. Tiap kali
    -+aktivitas baru dimulai, aktivitas sebelumnya akan dihentikan, namun sistem mempertahankan aktivitas
    -+dalam sebuah tumpukan ("back-stack"). Bila sebuah aktivitas baru dimulai, aktivitas itu akan didorong ke atas back-stack dan
    -+mengambil fokus pengguna. Back-stack mematuhi mekanisme dasar tumpukan "masuk terakhir, keluar pertama",
    -+jadi, bila pengguna selesai dengan aktivitas saat ini dan menekan tombol <em>Back</em>, aktivitas
    -+akan dikeluarkan dari tumpukan (dan dimusnahkan) dan aktivitas sebelumnya akan dilanjutkan. (Back-stack
    -+dibahas selengkapnya dalam dokumen <a href="{@docRoot}guide/components/tasks-and-back-stack.html">Tugas
    -+dan Back-Stack</a>.)</p>
    -+
    -+<p>Bila aktivitas dihentikan karena ada aktivitas baru yang dimulai, aktivitas lama akan diberi tahu tentang perubahan status ini
    -+melalui metode callback daur hidupnya.
    -+Ada beberapa metode callback yang mungkin diterima aktivitas, karena sebuah perubahan dalam
    -+statusnya&mdash;apakah sistem sedang membuatnya, menghentikannya, melanjutkannya, atau menghapuskannya&mdash;dan
    -+masing-masing callback memberi Anda kesempatan melakukan pekerjaan tertentu yang
    -+sesuai untuk perubahan status itu. Misalnya, bila dihentikan, aktivitas Anda harus melepas
    -+objek besar, seperti koneksi jaringan atau database. Bila aktivitas dilanjutkan, Anda bisa
    -+memperoleh kembali sumber daya yang diperlukan dan melanjutkan tindakan yang terputus. Transisi status ini
    -+semuanya bagian dari daur hidup aktivitas.</p>
    -+
    -+<p>Bagian selebihnya dari dokumen ini membahas dasar-dasar cara membuat dan menggunakan aktivitas,
    -+yang meliputi satu pembahasan lengkap tentang cara kerja daur hidup aktivitas, sehingga Anda bisa dengan benar mengelola
    -+transisi di antara berbagai status aktivitas.</p>
    -+
    -+
    -+
    -+<h2 id="Creating">Membuat Aktivitas</h2>
    -+
    -+<p>Untuk membuat sebuah aktivitas, Anda harus membuat subkelas {@link android.app.Activity} (atau
    -+subkelasnya yang ada). Dalam subkelas itu, Anda perlu mengimplementasikan metode-metode callback yang
    -+dipanggil sistem saat aktivitas bertransisi di antara berbagai status daur hidupnya, misalnya saat
    -+aktivitas sedang dibuat, dihentikan, dilanjutkan, atau dimusnahkan. Dua metode callback
    -+terpenting adalah:</p>
    -+
    -+<dl>
    -+  <dt>{@link android.app.Activity#onCreate onCreate()}</dt>
    -+  <dd>Anda harus mengimplementasikan metode ini. Sistem memanggilnya saat membuat
    -+    aktivitas Anda. Dalam implementasi, Anda harus menginisialisasi komponen-komponen esensial
    -+aktivitas.
    -+    Yang terpenting, inilah tempat Anda harus memanggil {@link android.app.Activity#setContentView
    -+    setContentView()} untuk mendefinisikan layout untuk antarmuka pengguna aktivitas.</dd>
    -+  <dt>{@link android.app.Activity#onPause onPause()}</dt>
    -+  <dd>Sistem memanggil metode ini sebagai pertanda pertama bahwa pengguna sedang meninggalkan
    -+aktivitas Anda (walau itu tidak selalu berarti aktivitas sedang dimusnahkan). Inilah biasanya tempat Anda
    -+harus mengikat setiap perubahan yang harus dipertahankan selepas sesi pengguna saat ini (karena
    -+pengguna mungkin tidak kembali).</dd>
    -+</dl>
    -+
    -+<p>Ada beberapa metode callback daur hidup lainnya yang harus Anda gunakan untuk memberikan
    -+pengalaman pengguna yang mengalir di antara aktivitas dan menangani interupsi tidak terduga yang menyebabkan aktivitas Anda
    -+dihentikan dan bahkan dimusnahkan. Semua metode callback daur hidup akan dibahas nanti, di
    -+bagian tentang <a href="#Lifecycle">Mengelola Daur Hidup Aktivitas</a>.</p>
    -+
    -+
    -+
    -+<h3 id="UI">Mengimplementasikan antarmuka pengguna</h3>
    -+
    -+<p> Antarmuka pengguna aktivitas disediakan oleh hierarki objek&mdash;tampilan yang diturunkan
    -+dari kelas {@link android.view.View}.  Tiap tampilan mengontrol sebuah ruang persegi panjang tertentu
    -+dalam jendela aktivitas dan bisa merespons interaksi pengguna. Misalnya, sebuah tampilan mungkin berupa sebuah
    -+tombol yang mengawali suatu tindakan bila pengguna menyentuhnya.</p>
    -+
    -+<p>Android menyediakan sejumlah tampilan siap-dibuat yang bisa Anda gunakan untuk mendesain dan mengatur
    -+layout. "Widget" adalah tampilan yang menyediakan elemen-elemen visual (dan interaktif) untuk layar,
    -+misalnya tombol, bidang teks, kotak cek, atau sekadar sebuah gambar. "Layout" adalah tampilan yang diturunkan dari {@link
    -+android.view.ViewGroup} yang memberikan sebuah model layout unik untuk tampilan anaknya, misalnya
    -+layout linier, layout grid, atau layout relatif. Anda juga bisa mensubkelaskan kelas-kelas {@link android.view.View} dan
    -+{@link android.view.ViewGroup} (atau subkelas yang ada) untuk membuat widget dan
    -+layout Anda sendiri dan menerapkannya ke layout aktivitas Anda.</p>
    -+
    -+<p>Cara paling umum untuk mendefinisikan layout dengan menggunakan tampilan adalah dengan file layout XML yang disimpan dalam
    -+sumber daya aplikasi Anda. Dengan cara ini, Anda bisa memelihara desain antarmuka pengguna Anda secara terpisah dari
    -+kode yang mendefinisikan perilaku aktivitas. Anda bisa mengatur layout sebagai UI
    -+aktivitas Anda dengan {@link android.app.Activity#setContentView(int) setContentView()}, dengan meneruskan
    -+ID sumber daya untuk layout itu. Akan tetapi, Anda juga bisa membuat {@link android.view.View} baru dalam
    -+kode aktivitas dan membuat hierarki tampilan dengan menyisipkan {@link
    -+android.view.View} baru ke dalam {@link android.view.ViewGroup}, kemudian menggunakan layout itu dengan meneruskan akar
    -+{@link android.view.ViewGroup} ke {@link android.app.Activity#setContentView(View)
    -+setContentView()}.</p>
    -+
    -+<p>Untuk informasi tentang cara membuat antarmuka pengguna, lihat dokumentasi <a href="{@docRoot}guide/topics/ui/index.html">Antarmuka Pengguna</a>.</p>
    -+
    -+
    -+
    -+<h3 id="Declaring">Mendeklarasikan aktivitas dalam manifes</h3>
    -+
    -+<p>Anda harus mendeklarasikan aktivitas dalam file manifes agar file itu
    -+bisa diakses oleh sistem. Untuk mendeklarasikan aktivitas, bukalah file manifes Anda dan tambahkan sebuah elemen <a href="{@docRoot}guide/topics/manifest/activity-element.html">{@code &lt;activity&gt;}</a>
    -+sebagai anak elemen <a href="{@docRoot}guide/topics/manifest/application-element.html">{@code &lt;application&gt;}</a>
    -+. Misalnya:</p>
    -+
    -+<pre>
    -+&lt;manifest ... &gt;
    -+  &lt;application ... &gt;
    -+      &lt;activity android:name=".ExampleActivity" /&gt;
    -+      ...
    -+  &lt;/application ... &gt;
    -+  ...
    -+&lt;/manifest &gt;
    -+</pre>
    -+
    -+<p>Ada beberapa atribut lain yang bisa Anda sertakan dalam elemen ini, untuk mendefinisikan properti
    -+misalnya label untuk aktivitas, ikon untuk aktivitas, atau tema untuk memberi gaya ke
    -+UI aktivitas. Atribut <a href="{@docRoot}guide/topics/manifest/activity-element.html#nm">{@code android:name}</a>
    -+ adalah satu-satunya atribut yang diperlukan&mdash;atribut ini menetapkan nama kelas aktivitas. Setelah
    -+Anda mempublikasikan aplikasi, Anda tidak boleh mengubah nama ini, karena jika melakukannya, Anda bisa merusak
    -+sebagian fungsionalitas, misalnya pintasan aplikasi (bacalah posting blog berjudul <a href="http://android-developers.blogspot.com/2011/06/things-that-cannot-change.html">Things
    -+That Cannot Change</a>).</p>
    -+
    -+<p>Lihat acuan elemen <a href="{@docRoot}guide/topics/manifest/activity-element.html">{@code &lt;activity&gt;}</a>
    -+untuk informasi selengkapnya tentang cara mendeklarasikan aktivitas Anda dalam manifes.</p>
    -+
    -+
    -+<h4>Menggunakan filter intent</h4>
    -+
    -+<p>Elemen <a href="{@docRoot}guide/topics/manifest/activity-element.html">{@code
    -+&lt;activity&gt;}</a> juga bisa menetapkan berbagai filter intent&mdash;dengan menggunakan elemen <a href="{@docRoot}guide/topics/manifest/intent-filter-element.html">{@code
    -+&lt;intent-filter&gt;}</a> &mdash;untuk mendeklarasikan cara komponen aplikasi lain
    -+mengaktifkannya.</p>
    -+
    -+<p>Bila Anda membuat aplikasi baru dengan Android SDK Tools, aktivitas stub
    -+yang dibuat untuk Anda secara otomatis menyertakan filter intent yang mendeklarasikan respons
    -+aktivitas pada tindakan "main" (utama) dan harus diletakkan dalam kategori "launcher"). Filter intent
    -+terlihat seperti ini:</p>
    -+
    -+<pre>
    -+&lt;activity android:name=".ExampleActivity" android:icon="@drawable/app_icon"&gt;
    -+    &lt;intent-filter&gt;
    -+        &lt;action android:name="android.intent.action.MAIN" /&gt;
    -+        &lt;category android:name="android.intent.category.LAUNCHER" /&gt;
    -+    &lt;/intent-filter&gt;
    -+&lt;/activity&gt;
    -+</pre>
    -+
    -+<p>Elemen <a href="{@docRoot}guide/topics/manifest/action-element.html">{@code
    -+&lt;action&gt;}</a> menetapkan bahwa ini adalah titik masuk "main" ke aplikasi. Elemen <a href="{@docRoot}guide/topics/manifest/category-element.html">{@code
    -+&lt;category&gt;}</a> menetapkan bahwa aktivitas ini harus tercantum dalam launcher aplikasi
    -+sistem (untuk memungkinkan pengguna meluncurkan aktivitas ini).</p>
    -+
    -+<p>Jika Anda bermaksud agar aplikasi dimuat dengan sendirinya dan tidak memperbolehkan aplikasi lain
    -+mengaktifkan aktivitasnya, maka Anda tidak memerlukan filter intent lain. Hanya satu aktivitas yang boleh
    -+memiliki tindakan "main" dan kategori "launcher", seperti dalam contoh sebelumnya. Aktivitas yang
    -+tidak ingin Anda sediakan untuk aplikasi lain tidak boleh memiliki filter intent dan Anda bisa
    -+memulai sendiri aktivitas dengan menggunakan intent secara eksplisit (seperti dibahas di bagian berikut).</p>
    -+
    -+<p>Akan tetapi, jika ingin aktivitas Anda merespons intent implisit yang dikirim dari
    -+aplikasi lain (dan aplikasi Anda sendiri), maka Anda harus mendefinisikan filter intent tambahan untuk
    -+aktivitas. Untuk masing-masing tipe intent yang ingin direspons, Anda harus menyertakan sebuah <a href="{@docRoot}guide/topics/manifest/intent-filter-element.html">{@code
    -+&lt;intent-filter&gt;}</a> yang menyertakan elemen
    -+<a href="{@docRoot}guide/topics/manifest/action-element.html">{@code
    -+&lt;action&gt;}</a> dan, opsional, sebuah elemen <a href="{@docRoot}guide/topics/manifest/category-element.html">{@code
    -+&lt;category&gt;}</a> dan/atau elemen <a href="{@docRoot}guide/topics/manifest/data-element.html">{@code
    -+&lt;data&gt;}</a>. Elemen-elemen ini menetapkan tipe intent yang bisa
    -+direspons oleh aktivitas Anda.</p>
    -+
    -+<p>Untuk informasi selengkapnya tentang cara aktivitas Anda merespons intent, lihat dokumen <a href="{@docRoot}guide/components/intents-filters.html">Intent dan Filter Intent</a>.
    -+</p>
    -+
    -+
    -+
    -+<h2 id="StartingAnActivity">Memulai Aktivitas</h2>
    -+
    -+<p>Anda bisa memulai aktivitas lain dengan memanggil {@link android.app.Activity#startActivity
    -+  startActivity()}, dengan meneruskan sebuah {@link android.content.Intent} yang menjelaskan aktivitas
    -+  yang ingin Anda mulai. Intent menetapkan aktivitas persis yang ingin Anda mulai atau menjelaskan
    -+  tipe tindakan yang ingin Anda lakukan (dan sistem akan memilih aktivitas yang sesuai untuk Anda,
    -+yang bahkan
    -+  bisa berasal dari aplikasi berbeda). Intent juga bisa membawa sejumlah kecil data untuk
    -+  digunakan oleh aktivitas yang dimulai.</p>
    -+
    -+<p>Saat bekerja dalam aplikasi sendiri, Anda nanti akan sering meluncurkan aktivitas yang dikenal saja.
    -+ Anda bisa melakukannya dengan membuat intent yang mendefinisikan secara eksplisit aktivitas yang ingin Anda mulai,
    -+dengan menggunakan nama kelas. Misalnya, beginilah cara satu aktivitas memulai aktivitas lain bernama {@code
    -+SignInActivity}:</p>
    -+
    -+<pre>
    -+Intent intent = new Intent(this, SignInActivity.class);
    -+startActivity(intent);
    -+</pre>
    -+
    -+<p>Akan tetapi, aplikasi Anda mungkin juga perlu melakukan beberapa tindakan, misalnya mengirim email,
    -+  pesan teks, atau pembaruan status, dengan menggunakan data dari aktivitas Anda. Dalam hal ini, aplikasi Anda mungkin
    -+ tidak memiliki aktivitasnya sendiri untuk melakukan tindakan tersebut, sehingga Anda bisa memanfaatkan aktivitas
    -+  yang disediakan oleh aplikasi lain pada perangkat, yang bisa melakukan tindakan itu untuk Anda. Inilah saatnya
    -+intent benar-benar berharga&mdash;Anda bisa membuat intent yang menjelaskan tindakan yang ingin
    -+dilakukan dan sistem
    -+  akan meluncurkan aktivitas yang tepat dari aplikasi lain. Jika ada
    -+  beberapa aktivitas yang bisa menangani intent itu, pengguna bisa memilih aktivitas yang akan digunakan. Misalnya,
    -+  jika Anda ingin memperbolehkan pengguna mengirim pesan email, Anda bisa membuat
    -+  intent berikut:</p>
    -+
    -+<pre>
    -+Intent intent = new Intent(Intent.ACTION_SEND);
    -+intent.putExtra(Intent.EXTRA_EMAIL, recipientArray);
    -+startActivity(intent);
    -+</pre>
    -+
    -+<p>Ekstra {@link android.content.Intent#EXTRA_EMAIL} yang ditambahkan ke intent adalah sebuah larik string
    -+  alamat email yang menjadi tujuan pengiriman email. Bila aplikasi email merespons intent ini,
    -+ aplikasi itu akan membaca larik string yang disediakan dalam ekstra dan meletakkannya dalam bidang "to"
    -+  pada formulir penulisan email. Dalam situasi ini, aktivitas aplikasi email dimulai dan bila
    -+  pengguna selesai, aktivitas Anda akan dilanjutkan.</p>
    -+
    -+
    -+
    -+
    -+<h3 id="StartingAnActivityForResult">Memulai aktivitas agar berhasil</h3>
    -+
    -+<p>Kadang-kadang, Anda mungkin ingin menerima hasil dari aktivitas yang Anda mulai. Dalam hal itu,
    -+  mulailah aktivitas dengan memanggil {@link android.app.Activity#startActivityForResult
    -+  startActivityForResult()} (sebagai ganti {@link android.app.Activity#startActivity
    -+  startActivity()}). Untuk menerima hasil dari
    -+aktivitas selanjutnya nanti, implementasikan metode callback {@link android.app.Activity#onActivityResult onActivityResult()}
    -+. Bila aktivitas selanjutnya selesai, aktivitas akan mengembalikan hasil dalam {@link
    -+android.content.Intent} kepada metode {@link android.app.Activity#onActivityResult onActivityResult()}
    -+Anda.</p>
    -+
    -+<p>Misalnya, mungkin Anda ingin pengguna mengambil salah satu kontaknya, sehingga aktivitas Anda bisa
    -+melakukan sesuatu dengan informasi dalam kontak itu. Begini caranya membuat intent tersebut dan
    -+menangani hasilnya:</p>
    -+
    -+<pre>
    -+private void pickContact() {
    -+    // Create an intent to "pick" a contact, as defined by the content provider URI
    -+    Intent intent = new Intent(Intent.ACTION_PICK, Contacts.CONTENT_URI);
    -+    startActivityForResult(intent, PICK_CONTACT_REQUEST);
    -+}
    -+
    -+&#64;Override
    -+protected void onActivityResult(int requestCode, int resultCode, Intent data) {
    -+    // If the request went well (OK) and the request was PICK_CONTACT_REQUEST
    -+    if (resultCode == Activity.RESULT_OK &amp;&amp; requestCode == PICK_CONTACT_REQUEST) {
    -+        // Perform a query to the contact's content provider for the contact's name
    -+        Cursor cursor = getContentResolver().query(data.getData(),
    -+        new String[] {Contacts.DISPLAY_NAME}, null, null, null);
    -+        if (cursor.moveToFirst()) { // True if the cursor is not empty
    -+            int columnIndex = cursor.getColumnIndex(Contacts.DISPLAY_NAME);
    -+            String name = cursor.getString(columnIndex);
    -+            // Do something with the selected contact's name...
    -+        }
    -+    }
    -+}
    -+</pre>
    -+
    -+<p>Contoh ini menunjukkan logika dasar yang harus Anda gunakan dalam metode {@link
    -+android.app.Activity#onActivityResult onActivityResult()} Anda untuk menangani
    -+hasil aktivitas. Syarat pertama memeriksa apakah permintaan berhasil&mdash;jika ya, maka
    -+ {@code resultCode} akan berupa {@link android.app.Activity#RESULT_OK}&mdash;dan apakah permintaan
    -+yang direspons hasil ini dikenal&mdash;dalam hal ini, {@code requestCode} cocok dengan
    -+parameter kedua yang dikirim dengan {@link android.app.Activity#startActivityForResult
    -+startActivityForResult()}. Dari sana, kode akan menangani hasil aktivitas dengan membuat query
    -+data yang dihasilkan dalam{@link android.content.Intent} (parameter {@code data}).</p>
    -+
    -+<p>Yang terjadi adalah {@link
    -+android.content.ContentResolver} melakukan query terhadap penyedia konten, yang menghasilkan
    -+{@link android.database.Cursor} yang memperbolehkan data query dibaca. Untuk informasi selengkapnya, lihat dokumen
    -+<a href="{@docRoot}guide/topics/providers/content-providers.html">Penyedia Konten</a>.</p>
    -+
    -+<p>Untuk informasi selengkapnya tentang menggunakan intent, lihat dokumen <a href="{@docRoot}guide/components/intents-filters.html">Intent dan Filter
    -+Intent</a>.</p>
    -+
    -+
    -+<h2 id="ShuttingDown">Mematikan Aktivitas</h2>
    -+
    -+<p>Anda bisa mematikan aktivitas dengan memanggil metode {@link android.app.Activity#finish
    -+finish()}-nya. Anda juga bisa mematikan aktivitas terpisah yang sebelumnya Anda mulai dengan memanggil
    -+{@link android.app.Activity#finishActivity finishActivity()}.</p>
    -+
    -+<p class="note"><strong>Catatan:</strong> Pada umumnya, Anda tidak boleh secara eksplisit mengakhiri aktivitas
    -+dengan menggunakan metode-metode ini. Seperti yang dibahas di bagian berikut tentang daur hidup aktivitas,
    -+sistem Android mengelola hidup aktivitas untuk Anda, sehingga Anda tidak perlu menyelesaikan sendiri
    -+aktivitas tersebut. Memanggil metode-metode ini bisa berpengaruh negatif pada pengalaman
    -+pengguna yang diharapkan dan hanya boleh digunakan bila Anda benar-benar tidak ingin pengguna kembali ke
    -+instance aktivitas ini.</p>
    -+
    -+
    -+<h2 id="Lifecycle">Mengelola Daur Hidup Aktivitas</h2>
    -+
    -+<p>Mengelola daur hidup aktivitas dengan mengimplementasikan metode-metode callback sangat
    -+penting untuk mengembangkan
    -+aplikasi yang kuat dan fleksibel. Daur hidup aktivitas dipengaruhi langsung oleh kaitannya dengan
    -+aktivitas lain, tugasnya, serta back-stack.</p>
    -+
    -+<p>Pada dasarnya, sebuah aktivitas bisa berada dalam tiga status:</p>
    -+
    -+<dl>
    -+  <dt><i>Dilanjutkan</i></dt>
    -+    <dd>Aktivitas berada di latar depan layar dan mendapatkan fokus pengguna. (Status ini
    -+kadang-kadang disebut juga dengan "running" (berjalan).)</dd>
    -+
    -+  <dt><i>Dihentikan sementara</i></dt>
    -+    <dd>Aktivitas lain berada di latar depan dan mendapat fokus, namun aktivitas ini masih terlihat. Yakni,
    -+aktivitas lain terlihat di atas aplikasi ini dan aktivitas itu setengah transparan atau tidak
    -+menuutpi seluruh layar. Aktivitas yang dihentikan sementara adalah benar-benar hidup (objek {@link android.app.Activity}
    -+dipertahankan dalam memori, objek itu memelihara semua informasi status dan anggota, dan tetap dikaitkan dengan
    -+window manager), namun bisa dimatikan oleh sistem dalam situasi memori sangat rendah.</dd>
    -+
    -+  <dt><i>Dihentikan</i></dt>
    -+    <dd>Aktivitas ditutupi sepenuhnya oleh aktivitas lain (aktivitas sekarang berada di
    -+"latar belakang"). Aktivitas yang dihentikan juga masih hidup (objek {@link android.app.Activity}
    -+dipertahankan dalam memori, objek itu menjaga semua informasi status dan anggota, namun <em>tidak</em>
    -+dikaitkan dengan window manager). Akan tetapi, aktivitas tidak lagi terlihat bagi pengguna dan
    -+bisa dimatikan oleh sistem bila memori diperlukan di lain.</dd>
    -+</dl>
    -+
    -+<p>Jika aktivitas dihentikan sementara atau dihentikan, sistem bisa mengeluarkannya dari memori baik dengan memintanya agar
    -+diakhiri (memanggil metode {@link android.app.Activity#finish finish()}-nya), atau sekadar mematikan
    -+prosesnya.  Bila dibuka lagi (setelah diakhiri atau dimatikan), aktivitas harus dibuat dari
    -+awal.</p>
    -+
    -+
    -+
    -+<h3 id="ImplementingLifecycleCallbacks">Mengimplementasikan callback daur hidup</h3>
    -+
    -+<p>Saat bertransisi ke dalam dan ke luar berbagai status yang dijelaskan di atas, aktivitas diberi tahu
    -+melalui berbagai metode callback. Semua metode callback adalah sangkutan yang
    -+bisa Anda kesampingkan untuk melakukan pekerjaan yang sesuai saat status aktivitas Anda berubah. Aktivitas skeleton
    -+berikut menyertakan setiap metode daur hidup mendasar:</p>
    -+
    -+
    -+<pre>
    -+public class ExampleActivity extends Activity {
    -+    &#64;Override
    -+    public void {@link android.app.Activity#onCreate onCreate}(Bundle savedInstanceState) {
    -+        super.onCreate(savedInstanceState);
    -+        // The activity is being created.
    -+    }
    -+    &#64;Override
    -+    protected void {@link android.app.Activity#onStart onStart()} {
    -+        super.onStart();
    -+        // The activity is about to become visible.
    -+    }
    -+    &#64;Override
    -+    protected void {@link android.app.Activity#onResume onResume()} {
    -+        super.onResume();
    -+        // The activity has become visible (it is now "resumed").
    -+    }
    -+    &#64;Override
    -+    protected void {@link android.app.Activity#onPause onPause()} {
    -+        super.onPause();
    -+        // Another activity is taking focus (this activity is about to be "paused").
    -+    }
    -+    &#64;Override
    -+    protected void {@link android.app.Activity#onStop onStop()} {
    -+        super.onStop();
    -+        // The activity is no longer visible (it is now "stopped")
    -+    }
    -+    &#64;Override
    -+    protected void {@link android.app.Activity#onDestroy onDestroy()} {
    -+        super.onDestroy();
    -+        // The activity is about to be destroyed.
    -+    }
    -+}
    -+</pre>
    -+
    -+<p class="note"><strong>Catatan:</strong> Implementasi Anda terhadap metode-metode daur hidup ini harus
    -+selalu memanggil implementasi superkelas sebelum melakukan pekerjaan apa pun, seperti yang ditampilkan dalam contoh-contoh di atas.</p>
    -+
    -+<p>Bersama-sama, semua metode ini mendefinisikan seluruh daur hidup sebuah aktivitas. Dengan mengimplementasikan
    -+metode-metode ini, Anda bisa memantau tiga loop tersarang (nested loop) dalam daur hidup aktivitas: </p>
    -+
    -+<ul>
    -+<li><b>Seluruh masa hidup</b> aktivitas berlangsung antara panggilan ke {@link
    -+android.app.Activity#onCreate onCreate()} dan panggilan ke {@link
    -+android.app.Activity#onDestroy}. Aktivitas Anda harus melakukan penyiapan
    -+status "global" (misalnya mendefinisikan layout) dalam {@link android.app.Activity#onCreate onCreate()}, dan
    -+melepas semua sisa sumber daya dalam {@link android.app.Activity#onDestroy}. Misalnya, jika
    -+aktivitas Anda memiliki sebuah thread yang berjalan di latar belakang untuk mengunduh data dari jaringan, aktivitas itu bisa membuat
    -+thread itu dalam {@link android.app.Activity#onCreate onCreate()} kemudian menghentikan thread dalam {@link
    -+android.app.Activity#onDestroy}.</li>
    -+
    -+<li><p><b>Masa pakai terlihat</b> (visible lifetime) aktivitas berlangsung antara panggilan ke {@link
    -+android.app.Activity#onStart onStart()} dan panggilan ke {@link
    -+android.app.Activity#onStop onStop()}. Selama ini, pengguna bisa melihat aktivitas
    -+pada layar dan berinteraksi dengannya. Misalnya, {@link android.app.Activity#onStop onStop()} dipanggil
    -+bila sebuah aktivitas baru dimulai dan aktivitas ini tidak lagi terlihat. Di antara dua metode ini, Anda bisa
    -+memelihara sumber daya yang diperlukan untuk menampilkan aktivitas kepada pengguna. Misalnya, Anda bisa mendaftarkan sebuah
    -+{@link android.content.BroadcastReceiver} dalam {@link
    -+android.app.Activity#onStart onStart()} untuk memantau perubahan yang berdampak pada UI Anda, dan mencabut pendaftarannya
    -+dalam {@link android.app.Activity#onStop onStop()} bila pengguna tidak bisa lagi melihat apa yang sedang Anda
    -+tampilkan. Sistem bisa memanggil {@link android.app.Activity#onStart onStart()} dan {@link
    -+android.app.Activity#onStop onStop()} beberapa kali selama masa pakai aktivitas, sambil
    -+aktivitas berganti-ganti antara terlihat dan tersembunyi bagi pengguna.</p></li>
    -+
    -+<li><p><b>Masa pakai latar depan</b> aktivitas berlangsung antara panggilan ke {@link
    -+android.app.Activity#onResume onResume()} dan panggilan ke {@link android.app.Activity#onPause
    -+onPause()}. Selama waktu ini, aktivitas berada di depan semua aktivitas lain pada layar dan mendapatkan
    -+fokus input pengguna.  Aktivitas bisa sering bertransisi ke dalam dan ke luar latar depan&mdash;misalnya,
    -+ {@link android.app.Activity#onPause onPause()} dipanggil bila perangkat masuk ke mode tidur atau
    -+bila dialog muncul. Karena status ini bisa sering bertransisi, kode dalam dua metode ini harus
    -+cukup ringan untuk menghindari transisi lamban yang membuat pengguna menunggu.</p></li>
    -+</ul>
    -+
    -+<p>Gambar 1 mengilustrasikan loop dan path yang mungkin diambil sebuah aktivitas di antara status-status.
    -+Persegi panjang mewakili metode callback yang bisa Anda implementasikan untuk melakukan operasi saat
    -+aktivitas bertransisi di antara status. <p>
    -+
    -+<img src="{@docRoot}images/activity_lifecycle.png" alt="" />
    -+<p class="img-caption"><strong>Gambar 1.</strong> Daur hidup aktivitas.</p>
    -+
    -+<p>Metode-metode callback daur hidup yang sama tercantum dalam tabel 1, yang menjelaskan setiap metode callback
    -+secara lebih detail dan menentukan lokasinya masing-masing dalam
    -+daur hidup aktivitas keseluruhan, termasuk apakah sistem bisa mematikan aktivitas setelah
    -+metode callback selesai.</p>
    -+
    -+<p class="table-caption"><strong>Tabel 1.</strong> Rangkuman metode callback
    -+daur hidup aktivitas.</p>
    -+
    -+<table border="2" width="85%" frame="hsides" rules="rows">
    -+<colgroup align="left" span="3"></colgroup>
    -+<colgroup align="left"></colgroup>
    -+<colgroup align="center"></colgroup>
    -+<colgroup align="center"></colgroup>
    -+
    -+<thead>
    -+<tr><th colspan="3">Metode</th> <th>Keterangan</th> <th>Bisa dimatikan setelahnya?</th> <th>Berikutnya</th></tr>
    -+</thead>
    -+
    -+<tbody>
    -+<tr>
    -+  <td colspan="3" align="left"><code>{@link android.app.Activity#onCreate onCreate()}</code></td>
    -+  <td>Dipanggil saat aktivitas pertama kali dibuat.
    -+      Di sinilah Anda harus melakukan semua persiapan statis normal &mdash;
    -+      membuat tampilan, mengikat data ke daftar, dan sebagainya.  Metode ini diberi
    -+      sebuah objek Bundle yang berisi status aktivitas sebelumnya, jika
    -+      status itu tertangkap (lihat <a href="#actstate">Menyimpan Status Aktivitas</a>,
    -+      nanti).
    -+      <p>Selalu diikuti oleh {@code onStart()}.</p></td>
    -+  <td align="center">Tidak</td>
    -+      <td align="center">{@code onStart()}</td>
    -+</tr>
    -+
    -+<tr>
    -+   <td rowspan="5" style="border-left: none; border-right: none;">&nbsp;&nbsp;&nbsp;&nbsp;</td>
    -+   <td colspan="2" align="left"><code>{@link android.app.Activity#onRestart
    -+onRestart()}</code></td>
    -+   <td>Dipanggil setelah aktivitas dihentikan, tepat sebelum
    -+       dimulai lagi.
    -+       <p>Selalu diikuti oleh {@code onStart()}</p></td>
    -+   <td align="center">Tidak</td>
    -+   <td align="center">{@code onStart()}</td>
    -+</tr>
    -+
    -+<tr>
    -+   <td colspan="2" align="left"><code>{@link android.app.Activity#onStart onStart()}</code></td>
    -+   <td>Dipanggil tepat sebelum aktivitas menjadi terlihat bagi pengguna.
    -+       <p>Diikuti oleh {@code onResume()} jika aktivitas maju
    -+       ke latar depan, atau {@code onStop()} jika menjadi tersembunyi.</p></td>
    -+    <td align="center">Tidak</td>
    -+    <td align="center">{@code onResume()} <br/>atau<br/> {@code onStop()}</td>
    -+</tr>
    -+
    -+<tr>
    -+   <td rowspan="2" style="border-left: none;">&nbsp;&nbsp;&nbsp;&nbsp;</td>
    -+   <td align="left"><code>{@link android.app.Activity#onResume onResume()}</code></td>
    -+   <td>Dipanggil tepat sebelum aktivitas mulai
    -+       berinteraksi dengan pengguna.  Pada titik ini, aktivitas berada di
    -+       puncak tumpukan aktivitas, dengan input pengguna menuju kepadanya.
    -+       <p>Selalu diikuti oleh {@code onPause()}.</p></td>
    -+   <td align="center">Tidak</td>
    -+   <td align="center">{@code onPause()}</td>
    -+</tr>
    -+
    -+<tr>
    -+   <td align="left"><code>{@link android.app.Activity#onPause onPause()}</code></td>
    -+   <td>Dipanggil bila sistem akan memulai pelanjutan
    -+       aktivitas lain.  Metode ini biasanya digunakan untuk menerapkan (commit) perubahan yang tidak tersimpan pada
    -+       data persisten, menghentikan animasi dan hal-hal lain yang mungkin menghabiskan
    -+       CPU, dan sebagainya.  Metode ini harus melakukan apa saja yang dilakukannya dengan sangat cepat, karena
    -+       aktivitas berikutnya tidak akan dilanjutkan hingga aktivitas ini kembali.
    -+       <p>Diikuti oleh {@code onResume()} jika aktivitas
    -+       kembali ke depan, atau oleh {@code onStop()} jika menjadi
    -+       tidak terlihat bagi pengguna.</td>
    -+   <td align="center"><strong style="color:#800000">Ya</strong></td>
    -+   <td align="center">{@code onResume()} <br/>atau<br/> {@code onStop()}</td>
    -+</tr>
    -+
    -+<tr>
    -+   <td colspan="2" align="left"><code>{@link android.app.Activity#onStop onStop()}</code></td>
    -+   <td>Dipanggil bila aktivitas tidak lagi terlihat bagi pengguna.  Hal ini
    -+       bisa terjadi karena aktivitas sedang dimusnahkan, atau karena aktivitas lain
    -+       (aktivitas yang ada atau yang baru) telah dilanjutkan dan sedang menutupinya.
    -+       <p>Diikuti oleh {@code onRestart()} jika
    -+       aktivitas kembali untuk berinteraksi dengan pengguna, atau oleh
    -+       {@code onDestroy()} jika aktivitas ini akan menghilang.</p></td>
    -+   <td align="center"><strong style="color:#800000">Ya</strong></td>
    -+   <td align="center">{@code onRestart()} <br/>atau<br/> {@code onDestroy()}</td>
    -+</tr>
    -+
    -+<tr>
    -+   <td colspan="3" align="left"><code>{@link android.app.Activity#onDestroy
    -+onDestroy()}</code></td>
    -+   <td>Dipanggil sebelum aktivitas dimusnahkan.  Inilah panggilan terakhir
    -+       yang akan diterima aktivitas.  Metode ini bisa dipanggil karena
    -+       aktivitas selesai (seseorang memanggil <code>{@link android.app.Activity#finish
    -+       finish()}</code> padanya), atau karena sistem memusnahkan sementara
    -+       instance aktivitas ini untuk menghemat tempat.  Anda bisa membedakan
    -+       kedua skenario ini dengan metode <code>{@link
    -+       android.app.Activity#isFinishing isFinishing()}</code>.</td>
    -+   <td align="center"><strong style="color:#800000">Ya</strong></td>
    -+   <td align="center"><em>tidak ada</em></td>
    -+</tr>
    -+</tbody>
    -+</table>
    -+
    -+<p>Kolom berlabel "Bisa dimatikan setelahnya?" menunjukkan apakah sistem bisa
    -+atau tidak mematikan proses yang menjadi host aktivitas kapan saja <em>setelah metode kembali</em>, tanpa
    -+menjalankan baris lain pada kode aktivitas.  Tiga metode ini ditandai "ya": ({@link
    -+android.app.Activity#onPause
    -+onPause()}, {@link android.app.Activity#onStop onStop()}, dan {@link android.app.Activity#onDestroy
    -+onDestroy()}). Karena {@link android.app.Activity#onPause onPause()} adalah yang pertama
    -+dari tiga, begitu aktivitas dibuat, {@link android.app.Activity#onPause onPause()} adalah
    -+metode terakhir yang dipastikan akan dipanggil sebelum proses <em>bisa</em> dimatikan&mdash;jika
    -+sistem harus memulihkan memori dalam keadaan darurat, maka {@link
    -+android.app.Activity#onStop onStop()} dan {@link android.app.Activity#onDestroy onDestroy()} mungkin
    -+tidak dipanggil. Karena itu, Anda harus menggunakan {@link android.app.Activity#onPause onPause()} untuk menulis
    -+data persisten yang penting (misalnya hasil edit pengguna) ke penyimpanan. Akan tetapi, Anda harus selektif dalam hal
    -+informasi yang harus dipertahankan selama {@link android.app.Activity#onPause onPause()}, karena setiap
    -+prosedur pemblokiran dalam metode ini akan memblokir transisi ke aktivitas berikutnya dan memperlambat
    -+pengalaman pengguna.</p>
    -+
    -+<p> Metode-metode yang ditandai "Tidak" dalam kolom <b>Bisa dimatikan</b> melindungi proses yang menjadi host
    -+aktivitas dari dimatikan sejak saat metode dipanggil.  Jadi, aktivitas bisa dimatikan
    -+sejak {@link android.app.Activity#onPause onPause()} kembali hingga waktu
    -+{@link android.app.Activity#onResume onResume()} dipanggil. Aktivitas tidak akan lagi bisa dimatikan hingga
    -+{@link android.app.Activity#onPause onPause()} dipanggil lagi dan kembali. </p>
    -+
    -+<p class="note"><strong>Catatan:</strong> Aktivitas yang tidak "bisa dimatikan" secara teknis oleh
    -+definisi dalam tabel 1 masih bisa dimatikan oleh sistem&mdash;namun itu hany terjadi dalam
    -+situasi ekstrem bila tidak ada jalan lain. Kapan aktivitas bisa dimatikan
    -+akan dibahas selengkapnya dalam dokumen <a href="{@docRoot}guide/components/processes-and-threads.html">Proses dan
    -+Threading</a>.</p>
    -+
    -+
    -+<h3 id="SavingActivityState">Menyimpan status aktivitas</h3>
    -+
    -+<p>Pengantar untuk <a href="#Lifecycle">Mengelola Daur Hidup Aktivitas</a> secara ringkas menyebutkan
    -+bahwa
    -+bila aktivitas dihentikan sementara atau dihentikan, status aktivitas akan dipertahankan. Hal itu terjadi karena
    -+objek {@link android.app.Activity} masih ditahan dalam memori saat aktivitas dihentikan sementara atau
    -+dihentikan&mdash;semua informasi tentang anggota dan statusnya saat ini masih hidup. Jadi, setiap perubahan
    -+yang dibuat pengguna dalam aktivitas akan dipertahankan sehingga bila aktivitas kembali ke
    -+latar depan (bila "dilanjutkan"), perubahan itu masih ada.</p>
    -+
    -+<p>Akan tetapi, bila sistem memusnahkan aktivitas untuk memulihkan memori, objek {@link
    -+android.app.Activity} akan dimusnahkan, sehingga sistem tidak bisa sekadar melanjutkan aktivitas dengan status
    -+tidak berubah. Sebagai gantinya, sistem harus membuat ulang objek {@link android.app.Activity} jika pengguna
    -+menyusuri kembali ke aktivitas tersebut. Namun, pengguna tidak menyadari
    -+bahwa sistem memusnahkan aktivitas dan membuatnya kembali dan, karena itu, mungkin
    -+mengharapkan aktivitas untuk sama persis dengan sebelumnya. Dalam situasi ini, Anda bisa memastikan bahwa
    -+informasi penting tentang status aktivitas tetap terjaga dengan mengimplementasikan
    -+metode callback tambahan yang memungkinkan Anda menyimpan informasi tentang status aktivitas: {@link
    -+android.app.Activity#onSaveInstanceState onSaveInstanceState()}.</p>
    -+
    -+<p>Sistem memanggil {@link android.app.Activity#onSaveInstanceState onSaveInstanceState()}
    -+sebelum membuat aktivitas rawan terhadap pemusnahan. Sistem meneruskan ke metode ini
    -+sebuah {@link android.os.Bundle} tempat Anda bisa menyimpan
    -+informasi status tentang aktivitas sebagai pasangan nama-nilai, dengan menggunakan metode-metode misalnya {@link
    -+android.os.Bundle#putString putString()} dan {@link
    -+android.os.Bundle#putInt putInt()}. Kemudian, jika sistem mematikan proses aplikasi Anda
    -+dan pengguna menyusuri kembali ke aktivitas tersebut, sistem akan membuat kembali aktivitas dan meneruskan
    -+{@link android.os.Bundle} ke {@link android.app.Activity#onCreate onCreate()} maupun {@link
    -+android.app.Activity#onRestoreInstanceState onRestoreInstanceState()}. Dengan menggunakan salah satu
    -+metode ini, Anda bisa mengekstrak status tersimpan dari {@link android.os.Bundle} dan memulihkan
    -+status aktivitas. Jika tidak ada informasi status untuk dipulihkan, maka {@link
    -+android.os.Bundle} yang diteruskan kepada adalah Anda null (yang akan terjadi bila aktivitas dibuat untuk
    -+pertama kali).</p>
    -+
    -+<img src="{@docRoot}images/fundamentals/restore_instance.png" alt="" />
    -+<p class="img-caption"><strong>Gambar 2.</strong> Ada dua cara yang bisa digunakan aktivitas untuk kembali ke fokus pengguna
    -+dengan status tetap: aktivitas dimusnahkan, kemudian dibuat kembali, dan aktivitas harus memulihkan
    -+status yang disimpan sebelumnya, atau aktivitas dihentikan, kemudian dilanjutkan dengan status aktivitas
    -+tetap.</p>
    -+
    -+<p class="note"><strong>Catatan:</strong> Tidak ada jaminan bahwa {@link
    -+android.app.Activity#onSaveInstanceState onSaveInstanceState()} akan dipanggil sebelum
    -+aktivitas Anda dimusnahkan, karena bisa saja terjadi aktivitas tidak perlu menyimpan status
    -+(misalnya saat pengguna meninggalkan aktivitas Anda dengan menggunakan tombol <em>Back</em>, karena pengguna menutup aktivitas
    -+secara eksplisit
    -+). Jika sistem memanggil {@link android.app.Activity#onSaveInstanceState
    -+onSaveInstanceState()}, ini akan dilakukan sebelum {@link
    -+android.app.Activity#onStop onStop()} dan mungkin sebelum {@link android.app.Activity#onPause
    -+onPause()}.</p>
    -+
    -+<p>Akan tetapi, sekalipun Anda tidak melakukan apa-apa dan tidak mengimplementasikan {@link
    -+android.app.Activity#onSaveInstanceState onSaveInstanceState()}, beberapa status aktivitas
    -+akan dipulihkan oleh implementasi default {@link
    -+android.app.Activity#onSaveInstanceState onSaveInstanceState()} dalam kelas {@link android.app.Activity}. Khususnya,
    -+implementasi default akan memanggil metode {@link
    -+android.view.View#onSaveInstanceState onSaveInstanceState()} yang sesuai untuk setiap {@link
    -+android.view.View} dalam layout, yang memungkinkan setiap tampilan untuk memberi informasi tentang dirinya
    -+yang harus disimpan. Hampir setiap widget dalam kerangka kerja Android mengimplementasikan metode ini
    -+sebagaimana mestinya, sehingga setiap perubahan yang terlihat pada UI akan disimpan dan dipulihkan secara otomatis bila
    -+aktivitas Anda dibuat kembali. Misalnya, widget {@link android.widget.EditText} menyimpan teks apa saja
    -+yang dimasukkan oleh pengguna dan widget {@link android.widget.CheckBox} menyimpan baik teks itu diperiksa maupun
    -+tidak. Satu-satunya pekerjaan yang Anda perlukan adalah memberikan ID unik (dengan atribut <a href="{@docRoot}guide/topics/resources/layout-resource.html#idvalue">{@code android:id}</a>
    -+) untuk masing-masing widget yang ingin disimpan statusnya. Jika widget tidak memiliki ID, maka sistem
    -+tidak bisa menyimpan statusnya.</p>
    -+
    -+<div class="sidebox-wrapper">
    -+<div class="sidebox">
    -+<p>Anda juga bisa menghentikan secara eksplisit sebuah tampilan dalam layout Anda agar tidak menyimpan statusnya dengan mengatur atribut
    -+{@link android.R.attr#saveEnabled android:saveEnabled} ke {@code "false"} atau dengan memanggil
    -+metode {@link android.view.View#setSaveEnabled setSaveEnabled()}. Biasanya, Anda tidak boleh
    -+menonaktifkannya, namun Anda boleh melakukannya jika ingin memulihkan status UI aktivitas secara berbeda.</p>
    -+</div>
    -+</div>
    -+
    -+<p>Walaupun implementasi default {@link
    -+android.app.Activity#onSaveInstanceState onSaveInstanceState()} menyimpan informasi yang berguna tentang
    -+UI aktivitas, Anda mungkin masih perlu mengesampingkannya untuk menyimpan informasi tambahan.
    -+Misalnya, Anda mungkin perlu menyimpan nilai-nilai anggota yang berubah selama masa pakai aktivitas (yang
    -+mungkin berkorelasi dengan nilai-nilai yang dipulihkan dalam UI, namun anggota-anggota yang menyimpan nilai-nilai UI itu tidak
    -+dipulihkan, secara default).</p>
    -+
    -+<p>Karena implementasi default {@link
    -+android.app.Activity#onSaveInstanceState onSaveInstanceState()} membantu menyimpan status UI, jika
    -+Anda mengesampingkan metode ini untuk menyimpan informasi tambahan status, Anda harus selalu memanggil
    -+implementasi superkelas {@link android.app.Activity#onSaveInstanceState onSaveInstanceState()}
    -+sebelum melakukan pekerjaan apa pun. Demikian pula, Anda juga harus memanggil implementasi superkelas {@link
    -+android.app.Activity#onRestoreInstanceState onRestoreInstanceState()} jika Anda mengesampingkannya, sehingga
    -+implementasi default bisa memulihkan status tampilan.</p>
    -+
    -+<p class="note"><strong>Catatan:</strong> Karena {@link android.app.Activity#onSaveInstanceState
    -+onSaveInstanceState()} tidak dijamin
    -+akan dipanggil, Anda harus menggunakannya hanya untuk mencatat status aktivitas sementara (transient) (status
    -+UI)&mdash;Anda tidak boleh menggunakannya untuk menyimpan data persisten.  Sebagai gantinya, Anda harus menggunakan {@link
    -+android.app.Activity#onPause onPause()} untuk menyimpan data persisten (misalnya data yang harus disimpan
    -+ke database) saat pengguna meninggalkan aktivitas.</p>
    -+
    -+<p>Salah satu cara yang baik untuk menguji kemampuan aplikasi dalam memulihkan statusnya adalah cukup dengan memutar
    -+perangkat sehingga orientasi layarnya berubah. Bila orientasi layar berubah, sistem
    -+akan memusnahkan dan membuat kembali aktivitas untuk menerapkan sumber daya alternatif yang mungkin tersedia
    -+untuk konfigurasi layar baru. Karena alasan ini saja, sangat penting bahwa aktivitas Anda
    -+memulihkan statusnya secara lengkap saat dibuat kembali, karena pengguna memutar layar secara rutin saat
    -+menggunakan aplikasi.</p>
    -+
    -+
    -+<h3 id="ConfigurationChanges">Menangani perubahan konfigurasi</h3>
    -+
    -+<p>Sebagian konfigurasi perangkat bisa berubah saat runtime (misalnya orientasi layar, ketersediaan keyboard
    -+, dan bahasa). Bila terjadi perubahan demikian, Android akan membuat kembali aktivitas yang berjalan
    -+(sistem akan memanggil {@link android.app.Activity#onDestroy}, kemudian segera memanggil {@link
    -+android.app.Activity#onCreate onCreate()}). Perilaku ini
    -+didesain untuk membantu aplikasi Anda menyesuaikan diri dengan konfigurasi baru dengan cara memuat ulang
    -+aplikasi Anda secara otomatis dengan sumber daya alternatif yang telah Anda sediakan (misalnya layout yang berbeda untuk
    -+layar orientasi dan ukuran yang berbeda).</p>
    -+
    -+<p>Jika Anda mendesain aktivitas dengan benar untuk menangani restart karena perubahan orientasi layar dan
    -+memulihkan status aktivitas seperti yang dijelaskan di atas, aplikasi Anda akan lebih tahan terhadap
    -+kejadian tidak terduga lainnya dalam daur hidup aktivitas.</p>
    -+
    -+<p>Cara terbaik menangani restart tersebut adalah
    -+  menyimpan dan memulihkan status aktivitas Anda dengan menggunakan {@link
    -+  android.app.Activity#onSaveInstanceState onSaveInstanceState()} dan {@link
    -+android.app.Activity#onRestoreInstanceState onRestoreInstanceState()} (atau {@link
    -+android.app.Activity#onCreate onCreate()}), seperti yang dibahas di bagian sebelumnya.</p>
    -+
    -+<p>Untuk informasi selengkapnya tentang konfigurasi perubahan yang terjadi saat program berjalan dan cara menanganinya
    -+, bacalah panduan untuk <a href="{@docRoot}guide/topics/resources/runtime-changes.html">Menangani
    -+Perubahan Runtime</a>.</p>
    -+
    -+
    -+
    -+<h3 id="CoordinatingActivities">Mengoordinasikan aktivitas</h3>
    -+
    -+ <p>Bila suatu aktivitas memulai aktivitas lain, keduanya akan mengalami transisi daur hidup. Aktivitas pertama
    -+akan berhenti sementara dan berhenti sama sekali (walau tidak akan berhenti jika masih terlihat di latar belakang), saat
    -+aktivitas lain dibuat. Jika aktivitas-aktivitas ini berbagi data yang disimpan ke disk atau di tempat lain, Anda perlu
    -+memahami bahwa aktivitas pertama tidak dihentikan sepenuhnya sebelum aktivitas kedua dibuat.
    -+Sebagai gantinya, proses akan memulai aktivitas kedua secara tumpang tindih dengan proses penghentian
    -+aktivitas pertama.</p>
    -+
    -+<p>Urutan callback daur hidup didefinisikan dengan baik, khususnya bila kedua aktivitas berada dalam
    -+proses yang sama dan salah satunya memulai yang lain. Berikut ini adalah urutan operasi yang terjadi bila Aktivitas
    -+A memulai Aktivitas B: </p>
    -+
    -+<ol>
    -+<li>Metode {@link android.app.Activity#onPause onPause()} Aktivitas A berjalan.</li>
    -+
    -+<li>Metode-metode {@link android.app.Activity#onCreate onCreate()}, {@link
    -+android.app.Activity#onStart onStart()}, dan {@link android.app.Activity#onResume onResume()}
    -+Aktivitas B berjalan secara berurutan. (Aktivitas B sekarang mendapatkan fokus pengguna.)</li>
    -+
    -+<li>Kemudian, jika Aktivitas A tidak lagi terlihat di layar, metode {@link
    -+android.app.Activity#onStop onStop()}-nya akan dijalankan.</li>
    -+</ol>
    -+
    -+ <p>Urutan callback daur hidup yang bisa diramalkan ini memungkinkan Anda mengelola transisi
    -+informasi dari satu aktivitas ke aktivitas lainnya. Misalnya, jika Anda harus menulis ke database saat
    -+aktivitas pertama berhenti agar aktivitas berikutnya bisa membacanya, maka Anda harus menulis ke
    -+database selama {@link android.app.Activity#onPause onPause()} sebagai ganti selama {@link
    -+android.app.Activity#onStop onStop()}.</p>
    -+
    -+<!--
    -+<h2>Beginner's Path</h2>
    -+
    -+<p>For more information about how Android maintains a history of activities and
    -+enables user multitasking, continue with the <b><a
    -+href="{@docRoot}guide/components/tasks-and-back-stack.html">Tasks and Back
    -+Stack</a></b> document.</p>
    -+-->
    -diff --git a/docs/html-intl/intl/id/guide/components/bound-services.jd b/docs/html-intl/intl/id/guide/components/bound-services.jd
    -new file mode 100644
    -index 0000000..6e5e65a
    ---- /dev/null
    -+++ b/docs/html-intl/intl/id/guide/components/bound-services.jd
    -@@ -0,0 +1,658 @@
    -+page.title=Layanan Terikat
    -+parent.title=Layanan
    -+parent.link=services.html
    -+@jd:body
    -+
    -+
    -+<div id="qv-wrapper">
    -+<ol id="qv">
    -+<h2>Dalam dokumen ini</h2>
    -+<ol>
    -+  <li><a href="#Basics">Dasar-Dasar</a></li>
    -+  <li><a href="#Creating">Membuat Layanan Terikat</a>
    -+    <ol>
    -+      <li><a href="#Binder">Memperluas kelas Binder</a></li>
    -+      <li><a href="#Messenger">Menggunakan Messenger</a></li>
    -+    </ol>
    -+  </li>
    -+  <li><a href="#Binding">Mengikat ke Layanan</a></li>
    -+  <li><a href="#Lifecycle">Mengelola Daur Hidup Layanan Terikat</a></li>
    -+</ol>
    -+
    -+<h2>Kelas-kelas utama</h2>
    -+<ol>
    -+  <li>{@link android.app.Service}</li>
    -+  <li>{@link android.content.ServiceConnection}</li>
    -+  <li>{@link android.os.IBinder}</li>
    -+</ol>
    -+
    -+<h2>Contoh</h2>
    -+<ol>
    -+  <li><a href="{@docRoot}resources/samples/ApiDemos/src/com/example/android/apis/app/RemoteService.html">{@code
    -+      RemoteService}</a></li>
    -+  <li><a href="{@docRoot}resources/samples/ApiDemos/src/com/example/android/apis/app/LocalService.html">{@code
    -+      LocalService}</a></li>
    -+</ol>
    -+
    -+<h2>Lihat juga</h2>
    -+<ol>
    -+  <li><a href="{@docRoot}guide/components/services.html">Layanan</a></li>
    -+</ol>
    -+</div>
    -+
    -+
    -+<p>Layanan terikat adalah server di antarmuka klien-server. Layanan terikat memungkinkan komponen-komponen
    -+(seperti aktivitas) untuk diikat ke layanan, mengirim permintaan, menerima respons, dan bahkan melakukan
    -+komunikasi antarproses (IPC). Layanan terikat biasanya hidup hanya saat melayani
    -+komponen aplikasi lain dan tidak berjalan di latar belakang terus-menerus.</p>
    -+
    -+<p>Dokumen ini menampilkan cara membuat layanan terikat, termasuk cara mengikat
    -+ke layanan dari komponen aplikasi lain. Akan tetapi, Anda juga harus mengacu dokumen <a href="{@docRoot}guide/components/services.html">Layanan</a> untuk
    -+informasi tambahan tentang layanan secara umum, seperti cara menyampaikan pemberitahuan dari layanan, mengatur
    -+layanan agar berjalan di latar depan, dan lain-lain.</p>
    -+
    -+
    -+<h2 id="Basics">Dasar-Dasar</h2>
    -+
    -+<p>Layanan terikat adalah implementasi kelas {@link android.app.Service} yang memungkinkan
    -+aplikasi lain diikat padanya dan berinteraksi dengannya. Untuk menyediakan pengikatan bagi sebuah
    -+layanan, Anda harus mengimplementasikan metode callback {@link android.app.Service#onBind onBind()}. Metode ini
    -+menghasilkan objek {@link android.os.IBinder} yang mendefinisikan antarmuka pemprograman yang
    -+bisa digunakan klien untuk berinteraksi dengan layanan.</p>
    -+
    -+<div class="sidebox-wrapper">
    -+<div class="sidebox">
    -+  <h3>Mengikat ke Layanan yang Sudah Dimulai</h3>
    -+
    -+<p>Seperti dibahas dalam dokumen <a href="{@docRoot}guide/components/services.html">Layanan</a>
    -+, Anda bisa membuat layanan yang dimulai sekaligus diikat. Yakni, layanan bisa
    -+dimulai dengan memanggil {@link android.content.Context#startService startService()}, yang memungkinkan
    -+layanan berjalan terus-menerus, dan juga membolehkan klien untuk mengikat ke layanan dengan memanggil {@link
    -+android.content.Context#bindService bindService()}.
    -+  <p>Jika Anda mengizinkan layanan dimulai dan diikat, lalu ketika layanan telah
    -+dimulai, sistem <em>tidak</em> menghapus layanan ketika semua klien melepas ikatan. Sebagai gantinya, Anda harus
    -+menghentikan layanan secara eksplisit, dengan memanggil {@link android.app.Service#stopSelf stopSelf()} atau {@link
    -+android.content.Context#stopService stopService()}.</p>
    -+
    -+<p>Walaupun Anda biasanya harus mengimplementasikan {@link android.app.Service#onBind onBind()}
    -+<em>atau</em> {@link android.app.Service#onStartCommand onStartCommand()}, kadang-kadang perlu
    -+mengimplementasikan keduanya. Misalnya, sebuah pemutar musik bisa merasakan manfaatnya karena layanannya boleh berjalan
    -+terus-menerus dan juga menyediakan pengikatan. Dengan cara ini, sebuah aktivitas bisa memulai layanan untuk memutar beberapa
    -+lagu dan musik terus dimainkan sekalipun pengguna meninggalkan aplikasi. Lalu, bila pengguna
    -+kembali ke aplikasi, aktivitas bisa mengikat ke layanan untuk mendapatkan kembali kontrol atas pemutaran.</p>
    -+
    -+<p>Pastikan membaca bagian tentang <a href="#Lifecycle">Mengelola Daur Hidup Layanan
    -+Terikat</a>, untuk informasi selengkapnya tentang daur hidup layanan saat menambahkan pengikatan ke
    -+layanan yang sudah dimulai.</p>
    -+</div>
    -+</div>
    -+
    -+<p>Klien bisa mengikat ke layanan dengan memanggil {@link android.content.Context#bindService
    -+bindService()}. Bila itu dilakukan, klien harus menyediakan implementasi {@link
    -+android.content.ServiceConnection}, yang memantau koneksi dengan layanan. Metode {@link
    -+android.content.Context#bindService bindService()} kembali dengan serta-merta tanpa sebuah nilai, namun
    -+bila sistem Android membuat koneksi antara klien
    -+dan layanan, sistem akan memanggil {@link
    -+android.content.ServiceConnection#onServiceConnected onServiceConnected()} pada {@link
    -+android.content.ServiceConnection} untuk mengirim {@link android.os.IBinder} yang
    -+bisa digunakan klien untuk berkomunikasi dengan layanan.</p>
    -+
    -+<p>Beberapa klien bisa terhubung ke layanan dengan serentak. Akan tetapi, sistem akan memanggil metode
    -+{@link android.app.Service#onBind onBind()} layanan Anda untuk mengambil {@link android.os.IBinder} hanya
    -+bila klien pertama mengikat. Sistem lalu memberikan {@link android.os.IBinder} yang sama ke setiap
    -+klien tambahan yang mengikat, tanpa memanggil {@link android.app.Service#onBind onBind()} lagi.</p>
    -+
    -+<p>Bila klien terakhir melepas ikatan dari layanan, sistem akan menghapus layanan (kecuali jika
    -+layanan juga dimulai oleh {@link android.content.Context#startService startService()}).</p>
    -+
    -+<p>Bila Anda mengimplementasikan layanan terikat, yang terpenting adalah mendefinisikan antarmuka
    -+yang dihasilkan metode callback {@link android.app.Service#onBind onBind()} Anda. Ada sedikit
    -+cara mendefinisikan antarmuka {@link android.os.IBinder} layanan Anda dan bagian berikut
    -+akan membahas masing-masing teknik.</p>
    -+
    -+
    -+
    -+<h2 id="Creating">Membuat Layanan Terikat</h2>
    -+
    -+<p>Saat membuat layanan yang menyediakan pengikatan, Anda harus menyediakan {@link android.os.IBinder}
    -+yang menyediakan antarmuka pemrograman yang bisa digunakan klien untuk berinteraksi dengan layanan. Ada
    -+tiga cara untuk mendefinisikan antarmuka:</p>
    -+
    -+<dl>
    -+  <dt><a href="#Binder">Memperluas kelas Binder</a></dt>
    -+  <dd>Jika layanan Anda bersifat privat untuk aplikasi Anda sendiri dan berjalan dalam proses yang sama dengan klien
    -+(biasanya), Anda harus membuat antarmuka dengan memperluas kelas {@link android.os.Binder}
    -+dan menghasilkan instance dari
    -+{@link android.app.Service#onBind onBind()}. Klien akan menerima {@link android.os.Binder} dan
    -+bisa menggunakannya untuk mengakses langsung metode publik yang tersedia dalam implementasi {@link android.os.Binder}
    -+atau bahkan {@link android.app.Service}.
    -+  <p>Inilah teknik yang lebih disukai bila layanan Anda sekadar pekerja latar belakang untuk aplikasi Anda
    -+sendiri. Satu-satunya alasan tidak membuat antarmuka dengan cara ini adalah karena
    -+layanan Anda akan digunakan oleh aplikasi lain atau pada proses-proses terpisah.</dd>
    -+
    -+  <dt><a href="#Messenger">Menggunakan Messenger</a></dt>
    -+  <dd>Jika antarmuka Anda perlu bekerja lintas proses, Anda bisa membuat
    -+antarmuka untuk layanan dengan {@link android.os.Messenger}. Dengan cara ini, layanan
    -+mendefinisikan {@link android.os.Handler} yang akan merespons aneka tipe objek {@link
    -+android.os.Message}. {@link android.os.Handler}
    -+ini adalah dasar bagi {@link android.os.Messenger} yang nanti bisa berbagi {@link android.os.IBinder}
    -+dengan klien, sehingga memungkinkan klien mengirim perintah ke layanan dengan menggunakan objek {@link
    -+android.os.Message}. Selain itu, klien bisa mendefinisikan sendiri {@link android.os.Messenger}
    -+sehingga layanan bisa mengirim balik pesan.
    -+  <p>Inilah cara termudah melakukan komunikasi antarproses (IPC), karena {@link
    -+android.os.Messenger} akan mengantre semua permintaan ke dalam satu thread sehingga Anda tidak perlu mendesain
    -+layanan agar thread-safe.</p>
    -+  </dd>
    -+
    -+  <dt>Menggunakan AIDL</dt>
    -+  <dd>AIDL (Android Interface Definition Language) melakukan semua pekerjaan untuk mengurai objek menjadi
    -+primitif yang bisa dipahami dan diarahkan oleh sistem operasi ke berbagai proses untuk melakukan
    -+IPC. Teknik sebelumnya, dengan menggunakan {@link android.os.Messenger}, sebenarnya berdasarkan AIDL sebagai
    -+struktur yang mendasarinya. Seperti disebutkan di atas, {@link android.os.Messenger} membuat antrean
    -+semua permintaan klien dalam satu thread, sehingga layanan akan menerima permintaan satu per satu. Akan tetapi,
    -+jika ingin layanan Anda menangani beberapa permintaan sekaligus, Anda bisa menggunakan AIDL
    -+secara langsung. Dalam hal ini, layanan Anda harus mampu multi-thread dan dibuat thread-safe.
    -+  <p>Untuk menggunakan AIDL secara langsung, Anda harus
    -+membuat file {@code .aidl} yang mendefinisikan antarmuka pemrograman. Alat Android SDK menggunakan
    -+file ini untuk menghasilkan kelas abstrak yang mengimplementasikan antarmuka dan menangani IPC, yang nanti
    -+bisa Anda perluas dalam layanan.</p>
    -+  </dd>
    -+</dl>
    -+
    -+  <p class="note"><strong>Catatan:</strong> Umumnya aplikasi <strong>tidak boleh</strong> menggunakan AIDL untuk
    -+membuat layanan terikat, karena hal itu mungkin memerlukan kemampuan multi-thread dan
    -+bisa mengakibatkan implementasi yang lebih rumit. Dengan demikian, AIDL tidak cocok untuk sebagian besar aplikasi
    -+dan dokumen ini tidak membahas cara menggunakannya untuk layanan Anda. Jika Anda yakin perlu
    -+menggunakan AIDL secara langsung, lihat dokumen <a href="{@docRoot}guide/components/aidl.html">AIDL</a>
    -+.</p>
    -+
    -+
    -+
    -+
    -+<h3 id="Binder">Memperluas kelas Binder</h3>
    -+
    -+<p>Jika layanan Anda hanya digunakan oleh aplikasi lokal dan tidak perlu bekerja lintas proses,
    -+maka Anda bisa mengimplementasikan kelas {@link android.os.Binder} Anda sendiri yang memberi klien Anda
    -+akses langsung ke metode publik dalam layanan.</p>
    -+
    -+<p class="note"><strong>Catatan:</strong> Hal ini hanya berhasil jika klien dan layanan berada dalam
    -+aplikasi dan proses yang sama, suatu kondisi yang paling umum. Misalnya, cara ini sangat cocok untuk sebuah aplikasi musik
    -+yang perlu mengikat aktivitas ke layanannya sendiri, yakni memutar musik di
    -+latar belakang.</p>
    -+
    -+<p>Berikut cara menyiapkannya:</p>
    -+<ol>
    -+  <li>Dalam layanan Anda, buat sebuah instance {@link android.os.Binder} yang:
    -+    <ul>
    -+      <li>berisi metode publik yang bisa dipanggil klien</li>
    -+      <li>menghasilkan instance {@link android.app.Service} saat ini, yang memiliki metode publik yang
    -+bisa dipanggil klien</li>
    -+      <li>atau, menghasilkan instance kelas lain yang host-nya di layanan dengan metode publik yang
    -+bisa dipanggil klien</li>
    -+    </ul>
    -+  <li>Hasilkan instance {@link android.os.Binder} ini dari metode callback {@link
    -+android.app.Service#onBind onBind()}.</li>
    -+  <li>Di klien, terima {@link android.os.Binder} dari metode callback {@link
    -+android.content.ServiceConnection#onServiceConnected onServiceConnected()} dan
    -+buat panggilan ke layanan terikat dengan menggunakan metode yang disediakan.</li>
    -+</ol>
    -+
    -+<p class="note"><strong>Catatan:</strong> Alasan layanan dan klien harus berada dalam aplikasi yang sama
    -+adalah agar klien bisa mengkonversi objek yang dihasilkan dan memanggil API-nya dengan benar. Layanan
    -+dan klien juga harus berada dalam proses yang sama, karena teknik ini tidak melakukan
    -+pengarahan (marshalling) apa pun untuk lintas proses.</p>
    -+
    -+<p>Misalnya, berikut ini adalah layanan yang memberi klien akses ke metode-metode dalam layanan melalui
    -+implementasi {@link android.os.Binder}:</p>
    -+
    -+<pre>
    -+public class LocalService extends Service {
    -+    // Binder given to clients
    -+    private final IBinder mBinder = new LocalBinder();
    -+    // Random number generator
    -+    private final Random mGenerator = new Random();
    -+
    -+    /**
    -+     * Class used for the client Binder.  Because we know this service always
    -+     * runs in the same process as its clients, we don't need to deal with IPC.
    -+     */
    -+    public class LocalBinder extends Binder {
    -+        LocalService getService() {
    -+            // Return this instance of LocalService so clients can call public methods
    -+            return LocalService.this;
    -+        }
    -+    }
    -+
    -+    &#64;Override
    -+    public IBinder onBind(Intent intent) {
    -+        return mBinder;
    -+    }
    -+
    -+    /** method for clients */
    -+    public int getRandomNumber() {
    -+      return mGenerator.nextInt(100);
    -+    }
    -+}
    -+</pre>
    -+
    -+<p>{@code LocalBinder} menyediakan {@code getService()} metode bagi klien untuk mengambil
    -+instance {@code LocalService} saat ini. Cara ini memungkinkan klien memanggil metode publik dalam
    -+layanan. Misalnya, klien bisa memanggil {@code getRandomNumber()} dari layanan.</p>
    -+
    -+<p>Berikut ini adalah aktivitas yang mengikat ke {@code LocalService} dan memanggil {@code getRandomNumber()}
    -+bila tombol diklik:</p>
    -+
    -+<pre>
    -+public class BindingActivity extends Activity {
    -+    LocalService mService;
    -+    boolean mBound = false;
    -+
    -+    &#64;Override
    -+    protected void onCreate(Bundle savedInstanceState) {
    -+        super.onCreate(savedInstanceState);
    -+        setContentView(R.layout.main);
    -+    }
    -+
    -+    &#64;Override
    -+    protected void onStart() {
    -+        super.onStart();
    -+        // Bind to LocalService
    -+        Intent intent = new Intent(this, LocalService.class);
    -+        bindService(intent, mConnection, Context.BIND_AUTO_CREATE);
    -+    }
    -+
    -+    &#64;Override
    -+    protected void onStop() {
    -+        super.onStop();
    -+        // Unbind from the service
    -+        if (mBound) {
    -+            unbindService(mConnection);
    -+            mBound = false;
    -+        }
    -+    }
    -+
    -+    /** Called when a button is clicked (the button in the layout file attaches to
    -+      * this method with the android:onClick attribute) */
    -+    public void onButtonClick(View v) {
    -+        if (mBound) {
    -+            // Call a method from the LocalService.
    -+            // However, if this call were something that might hang, then this request should
    -+            // occur in a separate thread to avoid slowing down the activity performance.
    -+            int num = mService.getRandomNumber();
    -+            Toast.makeText(this, "number: " + num, Toast.LENGTH_SHORT).show();
    -+        }
    -+    }
    -+
    -+    /** Defines callbacks for service binding, passed to bindService() */
    -+    private ServiceConnection mConnection = new ServiceConnection() {
    -+
    -+        &#64;Override
    -+        public void onServiceConnected(ComponentName className,
    -+                IBinder service) {
    -+            // We've bound to LocalService, cast the IBinder and get LocalService instance
    -+            LocalBinder binder = (LocalBinder) service;
    -+            mService = binder.getService();
    -+            mBound = true;
    -+        }
    -+
    -+        &#64;Override
    -+        public void onServiceDisconnected(ComponentName arg0) {
    -+            mBound = false;
    -+        }
    -+    };
    -+}
    -+</pre>
    -+
    -+<p>Contoh di atas menampilkan cara klien mengikat ke layanan dengan menggunakan implementasi
    -+{@link android.content.ServiceConnection} dan callback {@link
    -+android.content.ServiceConnection#onServiceConnected onServiceConnected()}. Bagian
    -+berikut menyediakan informasi selengkapnya tentang proses pengikatan ke layanan.</p>
    -+
    -+<p class="note"><strong>Catatan:</strong> Contoh di atas tidak secara eksplisit melepas ikatan dari layanan,
    -+namun semua klien harus melepas ikatan pada waktu yang tepat (seperti saat aktivitas sedang jeda).</p>
    -+
    -+<p>Untuk contoh kode selengkapnya, lihat kelas <a href="{@docRoot}resources/samples/ApiDemos/src/com/example/android/apis/app/LocalService.html">{@code
    -+LocalService.java}</a> dan kelas <a href="{@docRoot}resources/samples/ApiDemos/src/com/example/android/apis/app/LocalServiceActivities.html">{@code
    -+LocalServiceActivities.java}</a> dalam <a href="{@docRoot}resources/samples/ApiDemos/index.html">ApiDemos</a>.</p>
    -+
    -+
    -+
    -+
    -+
    -+<h3 id="Messenger">Menggunakan Messenger</h3>
    -+
    -+<div class="sidebox-wrapper">
    -+<div class="sidebox">
    -+  <h4>Dibandingkan dengan AIDL</h4>
    -+  <p>Bila Anda perlu melakukan IPC, menggunakan {@link android.os.Messenger} untuk antarmuka
    -+lebih sederhana daripada mengimplementasikannya dengan AIDL, karena {@link android.os.Messenger} mengantre
    -+semua panggilan ke layanan, sementara antarmuka AIDL murni mengirim permintaan serentak ke
    -+layanan, yang nanti harus menangani multi-threading.</p>
    -+  <p>Untuk sebagian besar aplikasi, layanan tidak perlu melakukan multi-threading, jadi dengan menggunakan {@link
    -+android.os.Messenger} memungkinkan layanan menangani panggilan satu per satu. Jika
    -+layanan harus multi-thread, Anda harus menggunakan <a href="{@docRoot}guide/components/aidl.html">AIDL</a> untuk mendefinisikan antarmuka.</p>
    -+</div>
    -+</div>
    -+
    -+<p>Jika layanan perlu berkomunikasi dengan proses jauh, Anda bisa menggunakan
    -+{@link android.os.Messenger} untuk menyediakan antarmuka bagi layanan Anda. Teknik ini memungkinkan
    -+Anda melakukan komunikasi antarproses (IPC) tanpa harus menggunakan AIDL.</p>
    -+
    -+<p>Berikut ini rangkuman cara menggunakan {@link android.os.Messenger}:</p>
    -+
    -+<ul>
    -+  <li>Layanan mengimplementasikan {@link android.os.Handler} yang menerima callback untuk tiap
    -+panggilan dari klien.</li>
    -+  <li>{@link android.os.Handler} digunakan untuk membuat objek {@link android.os.Messenger}
    -+(yang merupakan acuan ke {@link android.os.Handler}).</li>
    -+  <li>{@link android.os.Messenger} membuat {@link android.os.IBinder} yang
    -+dikembalikan layanan ke klien dari {@link android.app.Service#onBind onBind()}.</li>
    -+  <li>Klien menggunakan {@link android.os.IBinder} untuk membuat instance {@link android.os.Messenger}
    -+(yang mengacu {@link android.os.Handler} layanan), yang digunakan klien untuk mengirim
    -+objek {@link android.os.Message} ke layanan.</li>
    -+  <li>Layanan menerima setiap {@link android.os.Message} dalam {@link
    -+android.os.Handler}&mdash;secara spesifik, dalam metode {@link android.os.Handler#handleMessage
    -+handleMessage()}.</li>
    -+</ul>
    -+
    -+
    -+<p>Dengan cara ini, tidak ada "metode" untuk dipanggil klien pada layanan. Sebagai gantinya,
    -+klien mengirim "pesan" (objek-objek {@link android.os.Message}) yang diterima layanan dalam
    -+{@link android.os.Handler}-nya.</p>
    -+
    -+<p>Berikut ini contoh layanan sederhana yang menggunakan antarmuka {@link android.os.Messenger}:</p>
    -+
    -+<pre>
    -+public class MessengerService extends Service {
    -+    /** Command to the service to display a message */
    -+    static final int MSG_SAY_HELLO = 1;
    -+
    -+    /**
    -+     * Handler of incoming messages from clients.
    -+     */
    -+    class IncomingHandler extends Handler {
    -+        &#64;Override
    -+        public void handleMessage(Message msg) {
    -+            switch (msg.what) {
    -+                case MSG_SAY_HELLO:
    -+                    Toast.makeText(getApplicationContext(), "hello!", Toast.LENGTH_SHORT).show();
    -+                    break;
    -+                default:
    -+                    super.handleMessage(msg);
    -+            }
    -+        }
    -+    }
    -+
    -+    /**
    -+     * Target we publish for clients to send messages to IncomingHandler.
    -+     */
    -+    final Messenger mMessenger = new Messenger(new IncomingHandler());
    -+
    -+    /**
    -+     * When binding to the service, we return an interface to our messenger
    -+     * for sending messages to the service.
    -+     */
    -+    &#64;Override
    -+    public IBinder onBind(Intent intent) {
    -+        Toast.makeText(getApplicationContext(), "binding", Toast.LENGTH_SHORT).show();
    -+        return mMessenger.getBinder();
    -+    }
    -+}
    -+</pre>
    -+
    -+<p>Perhatikan bahwa metode {@link android.os.Handler#handleMessage handleMessage()} dalam
    -+{@link android.os.Handler} adalah tempat layanan menerima {@link android.os.Message}
    -+yang masuk dan memutuskan aksi yang harus dilakukan, berdasarkan anggota {@link android.os.Message#what}.</p>
    -+
    -+<p>Klien tinggal membuat {@link android.os.Messenger} berdasarkan {@link
    -+android.os.IBinder} yang dihasilkan layanan dan mengirim pesan menggunakan {@link
    -+android.os.Messenger#send send()}. Misalnya, berikut ini adalah aktivitas sederhana yang mengikat ke
    -+layanan dan mengirim pesan {@code MSG_SAY_HELLO} ke layanan:</p>
    -+
    -+<pre>
    -+public class ActivityMessenger extends Activity {
    -+    /** Messenger for communicating with the service. */
    -+    Messenger mService = null;
    -+
    -+    /** Flag indicating whether we have called bind on the service. */
    -+    boolean mBound;
    -+
    -+    /**
    -+     * Class for interacting with the main interface of the service.
    -+     */
    -+    private ServiceConnection mConnection = new ServiceConnection() {
    -+        public void onServiceConnected(ComponentName className, IBinder service) {
    -+            // This is called when the connection with the service has been
    -+            // established, giving us the object we can use to
    -+            // interact with the service.  We are communicating with the
    -+            // service using a Messenger, so here we get a client-side
    -+            // representation of that from the raw IBinder object.
    -+            mService = new Messenger(service);
    -+            mBound = true;
    -+        }
    -+
    -+        public void onServiceDisconnected(ComponentName className) {
    -+            // This is called when the connection with the service has been
    -+            // unexpectedly disconnected -- that is, its process crashed.
    -+            mService = null;
    -+            mBound = false;
    -+        }
    -+    };
    -+
    -+    public void sayHello(View v) {
    -+        if (!mBound) return;
    -+        // Create and send a message to the service, using a supported 'what' value
    -+        Message msg = Message.obtain(null, MessengerService.MSG_SAY_HELLO, 0, 0);
    -+        try {
    -+            mService.send(msg);
    -+        } catch (RemoteException e) {
    -+            e.printStackTrace();
    -+        }
    -+    }
    -+
    -+    &#64;Override
    -+    protected void onCreate(Bundle savedInstanceState) {
    -+        super.onCreate(savedInstanceState);
    -+        setContentView(R.layout.main);
    -+    }
    -+
    -+    &#64;Override
    -+    protected void onStart() {
    -+        super.onStart();
    -+        // Bind to the service
    -+        bindService(new Intent(this, MessengerService.class), mConnection,
    -+            Context.BIND_AUTO_CREATE);
    -+    }
    -+
    -+    &#64;Override
    -+    protected void onStop() {
    -+        super.onStop();
    -+        // Unbind from the service
    -+        if (mBound) {
    -+            unbindService(mConnection);
    -+            mBound = false;
    -+        }
    -+    }
    -+}
    -+</pre>
    -+
    -+<p>Perhatikan bahwa contoh ini tidak menampilkan cara layanan merespons klien. Jika ingin
    -+layanan merespons, Anda juga perlu membuat {@link android.os.Messenger} di klien. Lalu
    -+saat menerima callback {@link android.content.ServiceConnection#onServiceConnected
    -+onServiceConnected()}, klien akan mengirim {@link android.os.Message} ke layanan yang berisi
    -+{@link android.os.Messenger} klien dalam parameter {@link android.os.Message#replyTo}
    -+metode {@link android.os.Messenger#send send()}.</p>
    -+
    -+<p>Anda bisa melihat contoh cara menyediakan pertukaran pesan dua arah dalam contoh <a href="{@docRoot}resources/samples/ApiDemos/src/com/example/android/apis/app/MessengerService.html">{@code
    -+MessengerService.java}</a> (layanan) dan <a href="{@docRoot}resources/samples/ApiDemos/src/com/example/android/apis/app/MessengerServiceActivities.html">{@code
    -+MessengerServiceActivities.java}</a> (klien).</p>
    -+
    -+
    -+
    -+
    -+
    -+<h2 id="Binding">Mengikat ke Layanan</h2>
    -+
    -+<p>Komponen-komponen aplikasi (klien) bisa mengikat ke layanan dengan memanggil
    -+{@link android.content.Context#bindService bindService()}. Sistem Android
    -+lalu memanggil metode {@link android.app.Service#onBind
    -+onBind()} layanan, yang menghasilkan {@link android.os.IBinder} untuk berinteraksi dengan layanan.</p>
    -+
    -+<p>Pengikatan ini bersifat asinkron. {@link android.content.Context#bindService
    -+bindService()} segera kembali dan <em>tidak</em> mengembalikan {@link android.os.IBinder} ke
    -+klien. Untuk menerima {@link android.os.IBinder}, klien harus membuat instance {@link
    -+android.content.ServiceConnection} dan meneruskannya ke {@link android.content.Context#bindService
    -+bindService()}. {@link android.content.ServiceConnection} berisi metode callback yang
    -+dipanggil sistem untuk mengirim {@link android.os.IBinder}.</p>
    -+
    -+<p class="note"><strong>Catatan:</strong> Hanya aktivitas, layanan, dan penyedia konten yang bisa mengikat
    -+ke layanan yang&mdash;Anda <strong>tidak bisa</strong> ikat ke layanan dari penerima siaran.</p>
    -+
    -+<p>Jadi, untuk mengikat ke layanan dari klien, Anda harus: </p>
    -+<ol>
    -+  <li>Mengimplementasikan {@link android.content.ServiceConnection}.
    -+    <p>Implementasi Anda harus mengesampingkan dua metode callback:</p>
    -+    <dl>
    -+      <dt>{@link android.content.ServiceConnection#onServiceConnected onServiceConnected()}</dt>
    -+        <dd>Sistem memanggil ini untuk mengirim {@link android.os.IBinder} yang dihasilkan oleh
    -+metode {@link android.app.Service#onBind onBind()} layanan.</dd>
    -+      <dt>{@link android.content.ServiceConnection#onServiceDisconnected
    -+onServiceDisconnected()}</dt>
    -+        <dd>Sistem Android memanggil ini bila koneksi ke layanan putus
    -+tanpa terduga, seperti ketika layanan mengalami crash atau dimatikan. Ini <em>tidak</em> dipanggil ketika
    -+klien melepas ikatan.</dd>
    -+    </dl>
    -+  </li>
    -+  <li>Panggil {@link
    -+android.content.Context#bindService bindService()}, dengan meneruskan implementasi {@link
    -+android.content.ServiceConnection}. </li>
    -+  <li>Bila sistem memanggil metode callback {@link android.content.ServiceConnection#onServiceConnected
    -+onServiceConnected()}, Anda bisa mulai membuat panggilan ke layanan, dengan menggunakan
    -+metode yang didefinisikan oleh antarmuka.</li>
    -+  <li>Untuk memutus koneksi dari layanan, panggil {@link
    -+android.content.Context#unbindService unbindService()}.
    -+    <p>Bila telah dimusnahkan (destroyed), klien Anda akan melepas ikatan dari layanan, namun Anda harus selalu melepas ikatan
    -+bila sudah selesai berinteraksi dengan layanan atau bila aktivitas Anda sedang jeda sehingga layanan bisa
    -+dimatikan saat tidak sedang digunakan. (Waktu yang tepat untuk mengikat dan melepas ikatan dibahas
    -+selengkapnya di bawah ini.)</p>
    -+  </li>
    -+</ol>
    -+
    -+<p>Misalnya, cuplikan berikut menghubungkan klien ke layanan yang dibuat di atas dengan
    -+<a href="#Binder">memperluas kelas Binder</a>, sehingga tinggal mengkonversi
    -+{@link android.os.IBinder} yang dihasilkan ke kelas {@code LocalService} dan meminta instance {@code
    -+LocalService}:</p>
    -+
    -+<pre>
    -+LocalService mService;
    -+private ServiceConnection mConnection = new ServiceConnection() {
    -+    // Called when the connection with the service is established
    -+    public void onServiceConnected(ComponentName className, IBinder service) {
    -+        // Because we have bound to an explicit
    -+        // service that is running in our own process, we can
    -+        // cast its IBinder to a concrete class and directly access it.
    -+        LocalBinder binder = (LocalBinder) service;
    -+        mService = binder.getService();
    -+        mBound = true;
    -+    }
    -+
    -+    // Called when the connection with the service disconnects unexpectedly
    -+    public void onServiceDisconnected(ComponentName className) {
    -+        Log.e(TAG, "onServiceDisconnected");
    -+        mBound = false;
    -+    }
    -+};
    -+</pre>
    -+
    -+<p>Dengan {@link android.content.ServiceConnection} ini, klien bisa mengikat ke layanan dengan meneruskannya
    -+ke {@link android.content.Context#bindService bindService()}. Misalnya:</p>
    -+
    -+<pre>
    -+Intent intent = new Intent(this, LocalService.class);
    -+bindService(intent, mConnection, Context.BIND_AUTO_CREATE);
    -+</pre>
    -+
    -+<ul>
    -+  <li>Parameter pertama {@link android.content.Context#bindService bindService()} adalah sebuah
    -+{@link android.content.Intent} yang secara eksplisit menyebutkan layanan yang akan diikat (walaupun intent
    -+boleh implisit).</li>
    -+<li>Parameter kedua adalah objek {@link android.content.ServiceConnection}.</li>
    -+<li>Parameter ketiga adalah tanda (flag) yang menunjukkan opsi pengikatan. Tanda ini biasanya harus {@link
    -+android.content.Context#BIND_AUTO_CREATE} agar dapat membuat layanan jika belum hidup.
    -+Nilai-nilai lain yang memungkinkan adalah {@link android.content.Context#BIND_DEBUG_UNBIND}
    -+dan {@link android.content.Context#BIND_NOT_FOREGROUND}, atau {@code 0} untuk tidak satu pun.</li>
    -+</ul>
    -+
    -+
    -+<h3>Catatan tambahan</h3>
    -+
    -+<p>Berikut ini beberapa catatan penting tentang mengikat ke layanan:</p>
    -+<ul>
    -+  <li>Anda harus selalu menjebak eksepsi {@link android.os.DeadObjectException}, yang dilontarkan
    -+bila koneksi terputus. Inilah satu-satunya eksepsi yang dilontarkan oleh metode jauh.</li>
    -+  <li>Objek adalah acuan yang dihitung lintas proses. </li>
    -+  <li>Anda biasanya harus memasangkan pengikatan dan pelepasan ikatan selama
    -+memasangkan momen membuat dan menghapus daur hidup klien. Misalnya:
    -+    <ul>
    -+      <li>Jika Anda hanya perlu berinteraksi dengan layanan saat aktivitas terlihat, Anda
    -+harus mengikat selama {@link android.app.Activity#onStart onStart()} dan melepas ikatan selama {@link
    -+android.app.Activity#onStop onStop()}.</li>
    -+      <li>Jika Anda ingin aktivitas menerima tanggapan bahkan saat dihentikan di
    -+latar belakang, Anda bisa mengikat selama {@link android.app.Activity#onCreate onCreate()} dan melepas ikatan
    -+selama {@link android.app.Activity#onDestroy onDestroy()}. Berhati-hatilah karena hal ini menyiratkan aktivitas
    -+Anda perlu menggunakan layanan selama dijalankan (sekalipun di latar belakang), jadi jika
    -+layanan berada dalam proses lain, Anda meningkatkan bobot proses dan semakin besar
    -+kemungkinan sistem akan mematikannya.</li>
    -+    </ul>
    -+    <p class="note"><strong>Catatan:</strong> Anda biasanya <strong>tidak</strong> boleh mengikat dan melepas ikatan
    -+selama {@link android.app.Activity#onResume onResume()} aktivitas Anda dan {@link
    -+android.app.Activity#onPause onPause()}, karena callback ini terjadi pada setiap transisi daur hidup
    -+dan Anda harus menjaga pemrosesan yang terjadi pada transisi ini tetap minim. Juga, jika
    -+banyak aktivitas dalam aplikasi Anda mengikat ke layanan yang sama dan ada transisi antara
    -+dua aktivitas, layanan bisa dimusnahkan dan dibuat lagi sambil aktivitas saat ini melepas ikatan
    -+(selama jeda) sebelum aktivitas berikutnya mengikat (selama lanjutkan). (Transisi aktivitas ini untuk cara
    -+aktivitas mengoordinasikan daur hidupnya dijelaskan dalam dokumen <a href="{@docRoot}guide/components/activities.html#CoordinatingActivities">Aktivitas</a>
    -+.)</p>
    -+</ul>
    -+
    -+<p>Untuk contoh kode selengkapnya, yang menampilkan cara mengikat ke layanan, lihat kelas <a href="{@docRoot}resources/samples/ApiDemos/src/com/example/android/apis/app/RemoteService.html">{@code
    -+RemoteService.java}</a> dalam <a href="{@docRoot}resources/samples/ApiDemos/index.html">ApiDemos</a>.</p>
    -+
    -+
    -+
    -+
    -+
    -+<h2 id="Lifecycle">Mengelola Daur Hidup Layanan Terikat</h2>
    -+
    -+<p>Bila layanan dilepas ikatannya dari semua klien, sistem Android akan menghapusnya (kecuali jika layanan juga
    -+dimulai dengan {@link android.app.Service#onStartCommand onStartCommand()}). Dengan demikian, Anda tidak harus
    -+mengelola daur hidup layanan jika layanan itu murni sebuah layanan
    -+terikat&mdash;yang dikelola sistem Android untuk Anda berdasarkan apakah layanan terikat ke klien atau tidak.</p>
    -+
    -+<p>Akan tetapi, Jika Anda memilih untuk mengimplementasikan metode callback {@link android.app.Service#onStartCommand
    -+onStartCommand()}, maka Anda harus menghentikan layanan secara eksplisit, karena layanan
    -+sekarang dianggap telah <em>dimulai</em>. Dalam hal ini, layanan akan berjalan hingga layanan
    -+menghentikan dirinya sendiri dengan {@link android.app.Service#stopSelf()} atau panggilan komponen lain {@link
    -+android.content.Context#stopService stopService()}, terlepas dari apakah layanan terikat ke
    -+klien atau tidak.</p>
    -+
    -+<p>Selain itu, jika layanan Anda telah dimulai dan menerima pengikatan, maka saat sistem memanggil
    -+metode {@link android.app.Service#onUnbind onUnbind()}, Anda bisa memilih untuk mengembalikan
    -+{@code true} jika ingin menerima panggilan ke {@link android.app.Service#onRebind
    -+onRebind()} bila nanti klien mengikat ke layanan (sebagai ganti menerima panggilan ke {@link
    -+android.app.Service#onBind onBind()}). {@link android.app.Service#onRebind
    -+onRebind()} akan menghasilkan void, namun klien tetap menerima {@link android.os.IBinder} dalam callback
    -+{@link android.content.ServiceConnection#onServiceConnected onServiceConnected()}.
    -+Di bawah ini adalah gambar 1 yang mengilustrasikan logika untuk jenis daur hidup ini.</p>
    -+
    -+
    -+<img src="{@docRoot}images/fundamentals/service_binding_tree_lifecycle.png" alt="" />
    -+<p class="img-caption"><strong>Gambar 1.</strong> Daur hidup untuk layanan yang dimulai
    -+dan juga memungkinkan pengikatan.</p>
    -+
    -+
    -+<p>Untuk informasi selengkapnya tentang daur hidup layanan yang telah dimulai, lihat dokumen <a href="{@docRoot}guide/components/services.html#Lifecycle">Layanan</a>.</p>
    -+
    -+
    -+
    -+
    -diff --git a/docs/html-intl/intl/id/guide/components/fragments.jd b/docs/html-intl/intl/id/guide/components/fragments.jd
    -new file mode 100644
    -index 0000000..9f7199c
    ---- /dev/null
    -+++ b/docs/html-intl/intl/id/guide/components/fragments.jd
    -@@ -0,0 +1,812 @@
    -+page.title=Fragmen
    -+parent.title=Aktivitas
    -+parent.link=activities.html
    -+@jd:body
    -+
    -+<div id="qv-wrapper">
    -+<div id="qv">
    -+  <h2>Dalam dokumen ini</h2>
    -+  <ol>
    -+    <li><a href="#Design">Filosofi Desain</a></li>
    -+    <li><a href="#Creating">Membuat Fragmen</a>
    -+      <ol>
    -+        <li><a href="#UI">Menambahkan antarmuka pengguna</a></li>
    -+        <li><a href="#Adding">Menambahkan fragmen ke aktivitas</a></li>
    -+      </ol>
    -+    </li>
    -+    <li><a href="#Managing">Mengelola Fragmen</a></li>
    -+    <li><a href="#Transactions">Melakukan Transaksi Fragmen</a></li>
    -+    <li><a href="#CommunicatingWithActivity">Berkomunikasi dengan Aktivitas</a>
    -+      <ol>
    -+        <li><a href="#EventCallbacks">Membuat callback kejadian pada aktivitas</a></li>
    -+        <li><a href="#ActionBar">Menambahkan item ke Action-Bar</a></li>
    -+      </ol>
    -+    </li>
    -+    <li><a href="#Lifecycle">Menangani Daur Hidup Fragmen</a>
    -+      <ol>
    -+        <li><a href="#CoordinatingWithActivity">Mengoordinasi dengan daur hidup aktivitas</a></li>
    -+      </ol>
    -+    </li>
    -+    <li><a href="#Example">Contoh</a></li>
    -+  </ol>
    -+
    -+  <h2>Kelas-kelas utama</h2>
    -+  <ol>
    -+    <li>{@link android.app.Fragment}</li>
    -+    <li>{@link android.app.FragmentManager}</li>
    -+    <li>{@link android.app.FragmentTransaction}</li>
    -+  </ol>
    -+
    -+  <h2>Lihat juga</h2>
    -+  <ol>
    -+    <li><a href="{@docRoot}training/basics/fragments/index.html">Membangun UI Dinamis dengan Fragmen</a></li>
    -+    <li><a href="{@docRoot}guide/practices/tablets-and-handsets.html">Mendukung Tablet
    -+dan Handset</a></li>
    -+  </ol>
    -+</div>
    -+</div>
    -+
    -+<p>{@link android.app.Fragment} mewakili perilaku atau bagian dari antarmuka pengguna dalam
    -+{@link android.app.Activity}. Anda bisa mengombinasikan beberapa fragmen dalam satu aktivitas untuk membangun UI
    -+multipanel dan menggunakan kembali sebuah fragmen dalam beberapa aktivitas. Anda bisa menganggap fragmen sebagai bagian
    -+modular dari aktivitas, yang memiliki daur hidup sendiri, menerima kejadian input sendiri, dan
    -+yang bisa Anda tambahkan atau hapus saat aktivitas berjalan (semacam "sub aktivitas" yang
    -+bisa digunakan kembali dalam aktivitas berbeda).</p>
    -+
    -+<p>Fragmen harus selalu tertanam dalam aktivitas dan daur hidup fragmen secara langsung
    -+dipengaruhi oleh daur hidup aktivitas host-nya. Misalnya, saat aktivitas dihentikan sementara,
    -+semua fragmen di dalamnya juga dihentikan sementara, dan bila aktivitas dimusnahkan, semua fragmen juga demikian. Akan tetapi, saat
    -+aktivitas berjalan (dalam <a href="{@docRoot}guide/components/activities.html#Lifecycle">status daur hidup</a> <em>dilanjutkan</em>, Anda bisa
    -+memanipulasi setiap fragmen secara terpisah, seperti menambah atau menghapusnya. Saat melakukan transaksi
    -+fragmen, Anda juga bisa menambahkannya ke back-stack yang dikelola oleh aktivitas
    -+&mdash;setiap entri back-stack merupakan record transaksi fragmen yang
    -+terjadi. Dengan back-stack pengguna dapat membalikkan transaksi fragmen (mengarah mundur),
    -+dengan menekan tombol <em>Back</em>.</p>
    -+
    -+<p>Bila Anda menambahkan fragmen sebagai bagian dari layout aktivitas, fragmen itu berada dalam {@link
    -+android.view.ViewGroup} di hierarki tampilan aktivitas tersebut dan fragmen mendefinisikan
    -+layout
    -+tampilannya sendiri. Anda bisa menyisipkan fragmen ke dalam layout aktivitas dengan mendeklarasikan fragmen dalam file layout aktivitas
    -+, sebagai elemen {@code &lt;fragment&gt;}, atau dari kode aplikasi dengan menambahkannya ke
    -+ {@link android.view.ViewGroup} yang ada. Akan tetapi, fragmen tidak harus menjadi bagian dari
    -+layout aktivitas; Anda juga bisa menggunakan fragmen tanpa UI-nya sendiri sebagai pekerja tak terlihat untuk
    -+aktivitas tersebut.</p>
    -+
    -+<p>Dokumen ini menjelaskan cara membangun aplikasi menggunakan fragmen, termasuk
    -+cara fragmen mempertahankan statusnya bila ditambahkan ke back-stack aktivitas, berbagi
    -+kejadian dengan aktivitas, dan fragmen lain dalam aktivitas, berkontribusi pada action-bar
    -+aktivitas, dan lainnya.</p>
    -+
    -+
    -+<h2 id="Design">Filosofi Desain</h2>
    -+
    -+<p>Android memperkenalkan fragmen di Android 3.0 (API level 11), terutama untuk mendukung desain UI yang lebih
    -+dinamis dan fleksibel pada layar besar, seperti tablet. Karena
    -+layar tablet jauh lebih besar daripada layar handset, maka lebih banyak ruang untuk mengombinasikan dan
    -+bertukar komponen UI. Fragmen memungkinkan desain seperti itu tanpa perlu mengelola perubahan
    -+kompleks pada hierarki tampilan. Dengan membagi layout aktivitas menjadi beberapa fragmen, Anda bisa
    -+mengubah penampilan aktivitas saat runtime dan mempertahankan perubahan itu di back-stack
    -+yang dikelola oleh aktivitas.</p>
    -+
    -+<p>Misalnya, aplikasi berita bisa menggunakan satu fragmen untuk menampilkan daftar artikel di
    -+sebelah kiri dan fragmen lainnya untuk menampilkan artikel di sebelah kanan&mdash;kedua fragmen ini muncul di satu
    -+aktivitas, berdampingan, dan masing-masing fragmen memiliki serangkaian metode callback daur hidup dan menangani kejadian input
    -+penggunanya sendiri. Sehingga, sebagai ganti menggunakan satu aktivitas untuk memilih
    -+artikel dan aktivitas lainnya untuk membaca artikel, pengguna bisa memilih artikel dan membaca semuanya dalam
    -+aktivitas yang sama, sebagaimana diilustrasikan dalam layout tablet pada gambar 1.</p>
    -+
    -+<p>Anda harus mendesain masing-masing fragmen sebagai komponen aktivitas modular dan bisa digunakan kembali. Yakni, karena
    -+setiap fragmen mendefinisikan layoutnya dan perilakunya dengan callback daur hidupnya sendiri, Anda bisa memasukkan
    -+satu fragmen dalam banyak aktivitas, sehingga Anda harus mendesainnya untuk digunakan kembali dan mencegah
    -+memanipulasi satu fragmen dari fragmen lain secara langsung. Ini terutama penting karena dengan
    -+fragmen modular Anda bisa mengubah kombinasi fragmen untuk ukuran layar berbeda. Saat mendesain aplikasi
    -+untuk mendukung tablet maupun handset, Anda bisa menggunakan kembali fragmen dalam
    -+konfigurasi layout berbeda untuk mengoptimalkan pengalaman pengguna berdasarkan ruang layar yang tersedia. Misalnya
    -+, pada handset, fragmen mungkin perlu dipisahkan untuk menyediakan UI panel tunggal
    -+bila lebih dari satu yang tidak cocok dalam aktivitas yang sama.</p>
    -+
    -+<img src="{@docRoot}images/fundamentals/fragments.png" alt="" />
    -+<p class="img-caption"><strong>Gambar 1.</strong> Contoh cara dua modul UI yang didefinisikan oleh
    -+ fragmen bisa digabungkan ke dalam satu aktivitas untuk desain tablet, namun dipisahkan untuk
    -+desain handset.</p>
    -+
    -+<p>Misalnya&mdash;untuk melanjutkan contoh aplikasi berita&mdash; aplikasi bisa menanamkan
    -+dua fragmen dalam <em>Aktivitas A</em>, saat berjalan pada perangkat berukuran tablet. Akan tetapi, pada
    -+layar berukuran handset, ruang untuk kedua fragmen tidak cukup, sehingga <em>Aktivitas A</em> hanya
    -+menyertakan fragmen untuk daftar artikel, dan saat pengguna memilih artikel,
    -+<em>Aktivitas B</em> akan dimulai, termasuk fragmen kedua untuk membaca artikel. Sehingga, aplikasi mendukung
    -+tablet dan handset dengan menggunakan kembali fragmen dalam kombinasi berbeda, seperti diilustrasikan dalam
    -+gambar 1.</p>
    -+
    -+<p>Untuk informasi selengkapnya tentang mendesain aplikasi menggunakan kombinasi fragmen berbeda
    -+untuk konfigurasi layar berbeda, lihat panduan untuk <a href="{@docRoot}guide/practices/tablets-and-handsets.html">Mendukung Tablet dan Handset</a>.</p>
    -+
    -+
    -+
    -+<h2 id="Creating">Membuat Fragmen</h2>
    -+
    -+<div class="figure" style="width:327px">
    -+<img src="{@docRoot}images/fragment_lifecycle.png" alt="" />
    -+<p class="img-caption"><strong>Gambar 2.</strong> Daur hidup fragmen (saat
    -+ aktivitasnya berjalan).</p>
    -+</div>
    -+
    -+<p>Untuk membuat fragmen, Anda harus membuat subkelas {@link android.app.Fragment} (atau
    -+subkelasnya yang ada). Kelas {@link android.app.Fragment} memiliki kode yang mirip seperti
    -+{@link android.app.Activity}. Kelas ini memiliki metode callback yang serupa dengan aktivitas, seperti
    -+ {@link android.app.Fragment#onCreate onCreate()}, {@link android.app.Fragment#onStart onStart()},
    -+{@link android.app.Fragment#onPause onPause()}, dan {@link android.app.Fragment#onStop onStop()}. Sebenarnya
    -+, jika Anda mengkonversi aplikasi Android saat ini untuk menggunakan fragmen, Anda mungkin cukup memindahkan
    -+kode dari metode callback aktivitas ke masing-masing metode callback
    -+fragmen.</p>
    -+
    -+<p>Biasanya, Anda harus mengimplementasikan setidaknya metode daur hidup berikut ini:</p>
    -+
    -+<dl>
    -+  <dt>{@link android.app.Fragment#onCreate onCreate()}</dt>
    -+  <dd>Sistem akan memanggilnya saat membuat fragmen. Dalam implementasi, Anda harus
    -+menginisialisasi komponen penting dari fragmen yang ingin dipertahankan saat fragmen
    -+dihentikan sementara atau dihentikan, kemudian dilanjutkan.</dd>
    -+  <dt>{@link android.app.Fragment#onCreateView onCreateView()}</dt>
    -+  <dd>Sistem akan memanggilnya saat fragmen menggambar antarmuka penggunanya
    -+untuk yang pertama kali. Untuk menggambar UI fragmen, Anda harus mengembalikan {@link android.view.View} dari metode
    -+ini yang menjadi akar layout fragmen. Hasil yang dikembalikan bisa berupa null jika
    -+fragmen tidak menyediakan UI.</dd>
    -+  <dt>{@link android.app.Activity#onPause onPause()}</dt>
    -+  <dd>Sistem akan memanggil metode ini sebagai indikasi pertama bahwa pengguna sedang meninggalkan
    -+fragmen Anda (walau itu tidak selalu berarti fragmen sedang dimusnahkan). Inilah biasanya tempat Anda
    -+harus mengikat setiap perubahan yang harus dipertahankan selepas sesi pengguna saat ini (karena
    -+pengguna mungkin tidak kembali).</dd>
    -+</dl>
    -+
    -+<p>Kebanyakan aplikasi harus mengimplementasikan setidaknya tiga metode ini untuk setiap fragmen, namun ada
    -+beberapa metode callback lain yang juga harus Anda gunakan untuk menangani berbagai tahap
    -+daur hidup fragmen. Semua metode callback daur hidup akan dibahas secara lebih detail, di bagian
    -+tentang <a href="#Lifecycle">Menangani Daur Hidup Fragmen</a>.</p>
    -+
    -+
    -+<p>Ada juga beberapa subkelas yang mungkin ingin diperpanjang, sebagai ganti kelas basis {@link
    -+android.app.Fragment}:</p>
    -+
    -+<dl>
    -+  <dt>{@link android.app.DialogFragment}</dt>
    -+  <dd>Menampilkan dialog mengambang. Penggunaan kelas ini untuk membuat dialog merupakan alternatif yang baik dari
    -+penggunaan metode helper dialog di kelas {@link android.app.Activity}, karena Anda bisa
    -+menyatukan dialog fragmen ke dalam back-stack fragmen yang dikelola oleh aktivitas,
    -+sehingga pengguna bisa kembali ke fragmen yang ditinggalkan.</dd>
    -+
    -+  <dt>{@link android.app.ListFragment}</dt>
    -+  <dd>Menampilkan daftar item yang dikelola oleh adaptor (seperti {@link
    -+android.widget.SimpleCursorAdapter}), serupa dengan {@link android.app.ListActivity}. Menampilkan
    -+beberapa metode pengelolaan daftar tampilan seperti callback {@link
    -+android.app.ListFragment#onListItemClick(ListView,View,int,long) onListItemClick()} untuk
    -+menangani kejadian klik.</dd>
    -+
    -+  <dt>{@link android.preference.PreferenceFragment}</dt>
    -+  <dd>Menampilkan hierarki objek {@link android.preference.Preference} sebagai daftar, serupa dengan
    -+{@link android.preference.PreferenceActivity}. Hal ini berguna saat membuat aktivitas
    -+"pengaturan" untuk aplikasi Anda.</dd>
    -+</dl>
    -+
    -+
    -+<h3 id="UI">Menambahkan antarmuka pengguna</h3>
    -+
    -+<p>Fragmen biasanya digunakan sebagai bagian dari antarmuka pengguna aktivitas dan menyumbangkan
    -+layoutnya sendiri ke aktivitas.</p>
    -+
    -+<p>Untuk menyediakan layout fragmen, Anda harus mengimplementasikan metode callback {@link
    -+android.app.Fragment#onCreateView onCreateView()}, yang dipanggil sistem Android
    -+bila tiba saatnya fragmen menggambar layoutnya. Implementasi Anda atas metode ini harus mengembalikan
    -+{@link android.view.View} yang menjadi akar layout fragmen.</p>
    -+
    -+<p class="note"><strong>Catatan:</strong> Jika fragmen adalah subkelas {@link
    -+android.app.ListFragment}, implementasi default akan mengembalikan {@link android.widget.ListView} dari
    -+{@link android.app.Fragment#onCreateView onCreateView()}, sehingga Anda tidak perlu mengimplementasikannya.</p>
    -+
    -+<p>Untuk mengembalikan layout dari {@link
    -+android.app.Fragment#onCreateView onCreateView()}, Anda bisa memekarkannya dari <a href="{@docRoot}guide/topics/resources/layout-resource.html">sumber daya layout</a> yang didefinisikan di XML. Untuk
    -+membantu melakukannya, {@link android.app.Fragment#onCreateView onCreateView()} menyediakan objek
    -+{@link android.view.LayoutInflater}.</p>
    -+
    -+<p>Misalnya, ini adalah subkelas {@link android.app.Fragment} yang memuat layout dari file
    -+{@code example_fragment.xml}:</p>
    -+
    -+<pre>
    -+public static class ExampleFragment extends Fragment {
    -+    &#64;Override
    -+    public View onCreateView(LayoutInflater inflater, ViewGroup container,
    -+                             Bundle savedInstanceState) {
    -+        // Inflate the layout for this fragment
    -+        return inflater.inflate(R.layout.example_fragment, container, false);
    -+    }
    -+}
    -+</pre>
    -+
    -+<div class="sidebox-wrapper">
    -+<div class="sidebox">
    -+  <h3>Membuat layout</h3>
    -+  <p>Dalam contoh di atas, {@code R.layout.example_fragment} merupakan acuan ke sumber daya layout
    -+bernama {@code example_fragment.xml} yang tersimpan dalam sumber daya aplikasi. Untuk informasi tentang cara
    -+membuat layout di XML, lihat dokumentasi
    -+<a href="{@docRoot}guide/topics/ui/index.html">Antarmuka Pengguna</a>.</p>
    -+</div>
    -+</div>
    -+
    -+<p>Parameter {@code container} yang diteruskan ke {@link android.app.Fragment#onCreateView
    -+onCreateView()} adalah induk {@link android.view.ViewGroup} (dari layout aktivitas) tempat
    -+layout fragmen
    -+akan disisipkan. Parameter {@code savedInstanceState} adalah {@link android.os.Bundle} yang
    -+menyediakan data tentang instance fragmen sebelumnya, jika fragmen dilanjutkan
    -+(status pemulihan dibahas selengkapnya di bagian tentang <a href="#Lifecycle">Menangani
    -+Daur Hidup Fragmen</a>).</p>
    -+
    -+<p>Metode {@link android.view.LayoutInflater#inflate(int,ViewGroup,boolean) inflate()} membutuhkan
    -+tiga argumen:</p>
    -+<ul>
    -+  <li>ID sumber daya layout yang ingin dimekarkan.</li>
    -+  <li>{@link android.view.ViewGroup} akan menjadi induk dari layout yang dimekarkan. {@code
    -+container} perlu diteruskan agar sistem menerapkan parameter layout ke tampilan akar layout
    -+yang dimekarkan, yang ditetapkan dalam tampilan induk yang akan dituju.</li>
    -+  <li>Boolean yang menunjukkan apakah layout akan dimekarkan harus ditempelkan pada {@link
    -+android.view.ViewGroup} (parameter kedua) selama pemekaran. (Dalam hal ini, ini
    -+salah karena sistem sudah memasukkan layout yang dimekarkan ke dalam {@code
    -+container}&mdash;meneruskan benar akan membuat tampilan grup yang berlebihan dalam layout akhir.)</li>
    -+</ul>
    -+
    -+<p>Anda kini telah melihat cara membuat fragmen yang menyediakan layout. Berikutnya, Anda perlu menambahkan
    -+fragmen ke aktivitas.</p>
    -+
    -+
    -+
    -+<h3 id="Adding">Menambahkan fragmen ke aktivitas</h3>
    -+
    -+<p>Biasanya, fragmen berkontribusi pada sebagian UI ke aktivitas host, yang ditanamkan sebagai
    -+bagian dari hierarki tampilan keseluruhan aktivitas. Ada dua cara untuk menambahkan fragmen ke layout
    -+aktivitas:</p>
    -+
    -+<ul>
    -+  <li><b>Deklarasikan fragmen dalam file layout aktivitas.</b>
    -+<p>Dalam hal ini, Anda bisa
    -+menetapkan properti layout fragmen seakan-akan sebuah tampilan. Misalnya, berikut ini adalah file
    -+layout untuk aktivitas dengan dua fragmen:</p>
    -+<pre>
    -+&lt;?xml version="1.0" encoding="utf-8"?&gt;
    -+&lt;LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    -+    android:orientation="horizontal"
    -+    android:layout_width="match_parent"
    -+    android:layout_height="match_parent"&gt;
    -+    &lt;fragment android:name="com.example.news.ArticleListFragment"
    -+            android:id="@+id/list"
    -+            android:layout_weight="1"
    -+            android:layout_width="0dp"
    -+            android:layout_height="match_parent" /&gt;
    -+    &lt;fragment android:name="com.example.news.ArticleReaderFragment"
    -+            android:id="@+id/viewer"
    -+            android:layout_weight="2"
    -+            android:layout_width="0dp"
    -+            android:layout_height="match_parent" /&gt;
    -+&lt;/LinearLayout&gt;
    -+</pre>
    -+  <p>Atribut {@code android:name} dalam {@code &lt;fragment&gt;} menetapkan kelas {@link
    -+android.app.Fragment} untuk dibuat instance-nya dalam layout.</p>
    -+
    -+<p>Saat sistem membuat layout aktivitas, sistem membuat instance setiap fragmen sebagaimana yang ditetapkan dalam layout
    -+dan memanggil metode {@link android.app.Fragment#onCreateView onCreateView()} masing-masing,
    -+untuk mengambil setiap fragmen. Sistem akan menyisipkan {@link android.view.View} yang dikembalikan langsung oleh fragmen,
    -+ menggantikan elemen {@code &lt;fragment&gt;}.</p>
    -+
    -+<div class="note">
    -+  <p><strong>Catatan:</strong> Setiap fragmen memerlukan identifier
    -+unik yang bisa digunakan sistem untuk memulihkan fragmen jika aktivitas dimulai kembali (dan identifier yang bisa digunakan menangkap
    -+fragmen untuk melakukan transaksi, seperti menghapusnya). Ada tiga cara untuk memberikan
    -+ID bagi fragmen:</p>
    -+  <ul>
    -+    <li>Memberikan atribut {@code android:id} bersama ID unik.</li>
    -+    <li>Memberikan atribut {@code android:tag} bersama string unik.</li>
    -+    <li>Jika Anda tidak memberikan dua hal tersebut, sistem akan menggunakan ID
    -+tampilan kontainer.</li>
    -+  </ul>
    -+</div>
    -+  </li>
    -+
    -+  <li><b>Atau, secara programatis tambahkan fragmen ke {@link android.view.ViewGroup} yang ada.</b>
    -+<p>Kapan saja saat aktivitas berjalan, Anda bisa menambahkan fragmen ke layout aktivitas. Anda
    -+cukup menetapkan {@link
    -+android.view.ViewGroup} di tempat memasukkan fragmen.</p>
    -+  <p>Untuk membuat transaksi fragmen dalam aktivitas (seperti menambah, menghapus, atau mengganti
    -+fragmen), Anda harus menggunakan API dari {@link android.app.FragmentTransaction}. Anda bisa mengambil instance
    -+ {@link android.app.FragmentTransaction} dari {@link android.app.Activity} seperti ini:</p>
    -+
    -+<pre>
    -+FragmentManager fragmentManager = {@link android.app.Activity#getFragmentManager()}
    -+FragmentTransaction fragmentTransaction = fragmentManager.{@link android.app.FragmentManager#beginTransaction()};
    -+</pre>
    -+
    -+<p>Selanjutnya Anda bisa menambahkan fragmen menggunakan metode {@link
    -+android.app.FragmentTransaction#add(int,Fragment) add()}, dengan menetapkan fragmen yang akan ditambahkan dan
    -+tampilan tempat menyisipkannya. Misalnya:</p>
    -+
    -+<pre>
    -+ExampleFragment fragment = new ExampleFragment();
    -+fragmentTransaction.add(R.id.fragment_container, fragment);
    -+fragmentTransaction.commit();
    -+</pre>
    -+
    -+  <p>Argumen pertama yang diteruskan ke {@link android.app.FragmentTransaction#add(int,Fragment) add()}
    -+ adalah {@link android.view.ViewGroup} tempat fragmen harus dimasukkan, yang ditetapkan oleh
    -+ID sumber daya, dan parameter kedua merupakan fragmen yang akan ditambahkan.</p>
    -+  <p>Setelah membuat perubahan dengan
    -+{@link android.app.FragmentTransaction}, Anda harus
    -+ memanggil {@link android.app.FragmentTransaction#commit} untuk menerapkan perubahan.</p>
    -+  </li>
    -+</ul>
    -+
    -+
    -+<h4 id="AddingWithoutUI">Menambahkan fragmen tanpa UI</h4>
    -+
    -+<p>Contoh di atas menampilkan cara menambahkan fragmen ke aktivitas untuk menyediakan UI. Akan tetapi,
    -+Anda juga bisa menggunakan fragmen untuk menyediakan perilaku latar belakang bagi aktivitas tanpa menampilkan UI
    -+tambahan.</p>
    -+
    -+<p>Untuk menambahkan fragmen tanpa UI, tambahkan fragmen dari aktivitas menggunakan {@link
    -+android.app.FragmentTransaction#add(Fragment,String)} (dengan menyediakan string unik "tag" untuk fragmen
    -+, bukan ID tampilan). Ini akan menambahkan fragmen, namun, karena tidak dikaitkan dengan tampilan
    -+dalam layout aktivitas, ini tidak akan menerima panggilan ke {@link
    -+android.app.Fragment#onCreateView onCreateView()}. Jadi Anda tidak perlu mengimplementasikan metode itu.</p>
    -+
    -+<p>Menyediakan tag string untuk fragmen tidak hanya untuk fragmen non-UI&mdash;Anda juga bisa
    -+menyediakan tag string untuk fragmen yang memiliki UI&mdash;namun jika fragmen tidak memiliki UI
    -+, maka tag string adalah satu-satunya cara untuk mengidentifikasinya. Jika Anda ingin mendapatkan fragmen dari
    -+aktivitas nantinya, Anda perlu menggunakan {@link android.app.FragmentManager#findFragmentByTag
    -+findFragmentByTag()}.</p>
    -+
    -+<p>Untuk contoh aktivitas yang menggunakan fragmen sebagai pekerja latar belakang, tanpa UI, lihat sampel {@code
    -+FragmentRetainInstance.java}, yang disertakan dalam sampel SDK (tersedia melalui
    -+Android SDK Manager) dan terletak di sistem Anda sebagai
    -+<code>&lt;sdk_root&gt;/APIDemos/app/src/main/java/com/example/android/apis/app/FragmentRetainInstance.java</code>.</p>
    -+
    -+
    -+
    -+<h2 id="Managing">Mengelola Fragmen</h2>
    -+
    -+<p>Untuk mengelola fragmen dalam aktivitas, Anda perlu menggunakan {@link android.app.FragmentManager}. Untuk
    -+mendapatkannya, panggil {@link android.app.Activity#getFragmentManager()} dari aktivitas Anda.</p>
    -+
    -+<p>Beberapa hal yang dapat Anda lakukan dengan {@link android.app.FragmentManager} antara lain:</p>
    -+
    -+<ul>
    -+  <li>Dapatkan fragmen yang ada di aktivitas dengan {@link
    -+android.app.FragmentManager#findFragmentById findFragmentById()} (untuk fragmen yang menyediakan UI dalam
    -+layout aktivitas) atau {@link android.app.FragmentManager#findFragmentByTag
    -+findFragmentByTag()} (untuk fragmen yang menyediakan atau tidak menyediakan UI).</li>
    -+  <li>Tarik fragmen dari back-stack, dengan {@link
    -+android.app.FragmentManager#popBackStack()} (mensimulasikan perintah <em>Back</em> oleh pengguna).</li>
    -+  <li>Daftarkan listener untuk perubahan pada back-stack, dengan {@link
    -+android.app.FragmentManager#addOnBackStackChangedListener addOnBackStackChangedListener()}.</li>
    -+</ul>
    -+
    -+<p>Untuk informasi selengkapnya tentang metode ini dan hal lainnya, lihat dokumentasi kelas {@link
    -+android.app.FragmentManager}.</p>
    -+
    -+<p>Seperti yang ditunjukkan di bagian sebelumnya, Anda juga bisa menggunakan {@link android.app.FragmentManager}
    -+untuk membuka {@link android.app.FragmentTransaction}, sehingga Anda bisa melakukan transaksi, seperti
    -+menambah dan menghapus fragmen.</p>
    -+
    -+
    -+<h2 id="Transactions">Melakukan Transaksi Fragmen</h2>
    -+
    -+<p>Fitur menarik terkait penggunaan fragmen di aktivitas adalah kemampuan menambah, menghapus, mengganti,
    -+dan melakukan tindakan lain dengannya, sebagai respons atas interaksi pengguna. Setiap set perubahan
    -+yang Anda lakukan untuk aktivitas disebut transaksi dan Anda bisa melakukan transaksi menggunakan API di {@link
    -+android.app.FragmentTransaction}. Anda juga bisa menyimpan setiap transaksi ke back-stack yang dikelola
    -+aktivitas, sehingga pengguna bisa mengarah mundur melalui perubahan fragmen (mirip mengarah
    -+mundur melalui aktivitas).</p>
    -+
    -+<p>Anda bisa mengambil instance {@link android.app.FragmentTransaction} dari {@link
    -+android.app.FragmentManager} seperti ini:</p>
    -+
    -+<pre>
    -+FragmentManager fragmentManager = {@link android.app.Activity#getFragmentManager()};
    -+FragmentTransaction fragmentTransaction = fragmentManager.{@link android.app.FragmentManager#beginTransaction()};
    -+</pre>
    -+
    -+<p>Setiap transaksi merupakan serangkaian perubahan yang ingin dilakukan pada waktu yang sama. Anda bisa
    -+mengatur semua perubahan yang ingin dilakukan untuk transaksi mana saja menggunakan metode seperti {@link
    -+android.app.FragmentTransaction#add add()}, {@link android.app.FragmentTransaction#remove remove()},
    -+dan {@link android.app.FragmentTransaction#replace replace()}. Kemudian, untuk menerapkan transaksi
    -+pada aktivitas, Anda harus memanggil {@link android.app.FragmentTransaction#commit()}.</p>
    -+</dl>
    -+
    -+<p>Akan tetapi, sebelum memanggil {@link
    -+android.app.FragmentTransaction#commit()}, Anda mungkin perlu memanggil {@link
    -+android.app.FragmentTransaction#addToBackStack addToBackStack()}, untuk menambahkan transaksi
    -+ke back-stack dari transaksi fragmen. Back-stack ini dikelola oleh aktivitas dan memungkinkan
    -+pengguna kembali ke status fragmen sebelumnya, dengan menekan tombol <em>Back</em>.</p>
    -+
    -+<p>Misalnya, berikut ini cara mengganti satu fragmen dengan yang fragmen yang lain, dan mempertahankan
    -+status sebelumnya di back-stack:</p>
    -+
    -+<pre>
    -+// Create new fragment and transaction
    -+Fragment newFragment = new ExampleFragment();
    -+FragmentTransaction transaction = getFragmentManager().beginTransaction();
    -+
    -+// Replace whatever is in the fragment_container view with this fragment,
    -+// and add the transaction to the back stack
    -+transaction.replace(R.id.fragment_container, newFragment);
    -+transaction.addToBackStack(null);
    -+
    -+// Commit the transaction
    -+transaction.commit();
    -+</pre>
    -+
    -+<p>Dalam contoh ini, {@code newFragment} menggantikan fragmen apa saja (jika ada) yang saat ini berada dalam
    -+kontainer layout yang diidentifikasi oleh ID {@code R.id.fragment_container}. Dengan memanggil @link
    -+android.app.FragmentTransaction#addToBackStack addToBackStack()}, transaksi yang diganti
    -+disimpan ke back-stack sehingga pengguna bisa membalikkan transaksi dan mengembalikan fragmen
    -+sebelumnya dengan menekan tombol <em>Back</em>.</p>
    -+
    -+<p>Jika Anda menambahkan beberapa perubahan pada transaksi (seperti {@link
    -+android.app.FragmentTransaction#add add()} atau {@link android.app.FragmentTransaction#remove
    -+remove()}) dan panggil {@link
    -+android.app.FragmentTransaction#addToBackStack addToBackStack()}, maka semua perubahan akan diterapkan
    -+sebelum Anda memanggil {@link android.app.FragmentTransaction#commit commit()} akan ditambahkan ke
    -+back-stack sebagai satu transaksi dan tombol <em>Back</em> akan membalikannya semua.</p>
    -+
    -+<p>Urutan menambahkan perubahan pada {@link android.app.FragmentTransaction} tidak berpengaruh,
    -+kecuali:</p>
    -+<ul>
    -+  <li>Anda harus memanggil {@link android.app.FragmentTransaction#commit()} paling akhir</li>
    -+  <li>Jika Anda menambahkan beberapa fragmen ke kontainer yang sama, maka
    -+urutan penambahannya akan menentukan urutan munculnya dalam hierarki tampilan</li>
    -+</ul>
    -+
    -+<p>Jika Anda tidak memanggil {@link android.app.FragmentTransaction#addToBackStack(String)
    -+addToBackStack()} saat melakukan transaksi yang menghapus fragmen, maka fragmen itu
    -+akan dimusnahkan bila transaksi diikat dan pengguna tidak bisa mengarah kembali ke sana. Sedangkan, jika
    -+Anda memanggil {@link android.app.FragmentTransaction#addToBackStack(String) addToBackStack()} saat
    -+menghapus fragmen, maka fragmen itu akan <em>dihentikan</em> dan akan dilanjutkan jika pengguna mengarah
    -+kembali.</p>
    -+
    -+<p class="note"><strong>Tip:</strong> Untuk setiap transaksi fragmen, Anda bisa menerapkan animasi
    -+transisi, dengan memanggil {@link android.app.FragmentTransaction#setTransition setTransition()} sebelum
    -+mengikatnya.</p>
    -+
    -+<p>Memanggil {@link android.app.FragmentTransaction#commit()} tidak akan langsung menjalankan
    -+transaksi. Namun sebuah jadwal akan dibuat untuk dijalankan pada thread UI aktivitas (thread "utama")
    -+begitu thread bisa melakukannya. Akan tetapi, jika perlu Anda bisa memanggil {@link
    -+android.app.FragmentManager#executePendingTransactions()} dari thread UI untuk segera
    -+mengeksekusi transaksi yang diserahkan oleh {@link android.app.FragmentTransaction#commit()}. Hal itu
    -+biasanya tidak perlu kecuali jika transaksi merupakan dependensi bagi pekerjaan dalam thread lain.</p>
    -+
    -+<p class="caution"><strong>Perhatian:</strong> Anda bisa mengikat transaksi menggunakan {@link
    -+android.app.FragmentTransaction#commit commit()} hanya sebelum aktivitas <a href="{@docRoot}guide/components/activities.html#SavingActivityState">menyimpan
    -+statusnya</a> (saat pengguna meninggalkan aktivitas). Jika Anda mencoba mengikatnya setelah itu,
    -+eksepsi akan dilontarkan. Ini karena status setelah pengikatan bisa hilang jika aktivitas
    -+perlu dipulihkan. Untuk situasi yang memperbolehkan Anda meniadakan pengikatan (commit), gunakan {@link
    -+android.app.FragmentTransaction#commitAllowingStateLoss()}.</p>
    -+
    -+
    -+
    -+
    -+<h2 id="CommunicatingWithActivity">Berkomunikasi dengan Aktivitas</h2>
    -+
    -+<p>Meskipun {@link android.app.Fragment} diimplementasikan sebagai objek yang tidak bergantung pada
    -+{@link android.app.Activity} dan bisa digunakan dalam banyak aktivitas, instance tertentu
    -+dari fragmen secara langsung terkait dengan aktivitas yang dimuatnya.</p>
    -+
    -+<p>Khususnya, fragmen bisa mengakses instance {@link android.app.Activity} dengan {@link
    -+android.app.Fragment#getActivity()} dan dengan mudah melakukan tugas-tugas seperti mencari tampilan dalam
    -+ layout aktivitas:</p>
    -+
    -+<pre>
    -+View listView = {@link android.app.Fragment#getActivity()}.{@link android.app.Activity#findViewById findViewById}(R.id.list);
    -+</pre>
    -+
    -+<p>Demikian pula, aktivitas Anda bisa memanggil metode di fragmen dengan meminta acuan ke
    -+{@link android.app.Fragment} dari {@link android.app.FragmentManager}, menggunakan {@link
    -+android.app.FragmentManager#findFragmentById findFragmentById()} atau {@link
    -+android.app.FragmentManager#findFragmentByTag findFragmentByTag()}. Misalnya:</p>
    -+
    -+<pre>
    -+ExampleFragment fragment = (ExampleFragment) getFragmentManager().findFragmentById(R.id.example_fragment);
    -+</pre>
    -+
    -+
    -+<h3 id="EventCallbacks">Membuat callback kejadian pada aktivitas</h3>
    -+
    -+<p>Dalam beberapa kasus, Anda mungkin perlu fragmen untuk berbagi kejadian dengan aktivitas. Cara yang baik untuk melakukannya
    -+adalah mendefinisikan antarmuka callback di dalam fragmen dan mengharuskan aktivitas host
    -+mengimplementasikannya. Saat aktivitas menerima callback melalui antarmuka, aktivitas akan bisa berbagi informasi itu
    -+dengan fragmen lain dalam layout jika perlu.</p>
    -+
    -+<p>Misalnya, jika sebuah aplikasi berita memiliki dua fragmen dalam aktivitas&mdash;satu untuk menampilkan daftar
    -+artikel (fragmen A) dan satu lagi untuk menampilkan artikel (fragmen B)&mdash;maka fragmen A harus
    -+memberi tahu aktivitas bila item daftar dipilih sehingga aktivitas bisa memberi tahu fragmen B untuk menampilkan artikel. Dalam
    -+hal ini, antarmuka {@code OnArticleSelectedListener} dideklarasikan di dalam fragmen A:</p>
    -+
    -+<pre>
    -+public static class FragmentA extends ListFragment {
    -+    ...
    -+    // Container Activity must implement this interface
    -+    public interface OnArticleSelectedListener {
    -+        public void onArticleSelected(Uri articleUri);
    -+    }
    -+    ...
    -+}
    -+</pre>
    -+
    -+<p>Selanjutnya aktivitas yang menjadi host fragmen akan mengimplementasikan antarmuka {@code OnArticleSelectedListener}
    -+ dan
    -+mengesampingkan {@code onArticleSelected()} untuk memberi tahu fragmen B mengenai kejadian dari fragmen A. Untuk memastikan
    -+bahwa aktivitas host mengimplementasikan antarmuka ini, metode callback fragmen A {@link
    -+android.app.Fragment#onAttach onAttach()} (yang dipanggil sistem saat menambahkan
    -+fragmen ke aktivitas) membuat instance {@code OnArticleSelectedListener} dengan
    -+membuat {@link android.app.Activity} yang diteruskan ke {@link android.app.Fragment#onAttach
    -+onAttach()}:</p>
    -+
    -+<pre>
    -+public static class FragmentA extends ListFragment {
    -+    OnArticleSelectedListener mListener;
    -+    ...
    -+    &#64;Override
    -+    public void onAttach(Activity activity) {
    -+        super.onAttach(activity);
    -+        try {
    -+            mListener = (OnArticleSelectedListener) activity;
    -+        } catch (ClassCastException e) {
    -+            throw new ClassCastException(activity.toString() + " must implement OnArticleSelectedListener");
    -+        }
    -+    }
    -+    ...
    -+}
    -+</pre>
    -+
    -+<p>Jika aktivitas belum mengimplementasikan antarmuka, maka fragmen akan melontarkan
    -+{@link java.lang.ClassCastException}.
    -+Jika berhasil, anggota {@code mListener} yang menyimpan acuan ke implementasi aktivitas
    -+{@code OnArticleSelectedListener}, sehingga fragmen A bisa berbagi kejadian dengan aktivitas, dengan memanggil metode
    -+yang didefinisikan oleh antarmuka {@code OnArticleSelectedListener}. Misalnya, jika fragmen A adalah
    -+ekstensi dari {@link android.app.ListFragment}, maka setiap kali
    -+pengguna mengklik item daftar, sistem akan memanggil {@link android.app.ListFragment#onListItemClick
    -+onListItemClick()} di fragmen, yang selanjutnya memanggil {@code onArticleSelected()} untuk berbagi
    -+kejadian dengan aktivitas:</p>
    -+
    -+<pre>
    -+public static class FragmentA extends ListFragment {
    -+    OnArticleSelectedListener mListener;
    -+    ...
    -+    &#64;Override
    -+    public void onListItemClick(ListView l, View v, int position, long id) {
    -+        // Append the clicked item's row ID with the content provider Uri
    -+        Uri noteUri = ContentUris.{@link android.content.ContentUris#withAppendedId withAppendedId}(ArticleColumns.CONTENT_URI, id);
    -+        // Send the event and Uri to the host activity
    -+        mListener.onArticleSelected(noteUri);
    -+    }
    -+    ...
    -+}
    -+</pre>
    -+
    -+<p>Parameter {@code id} yang diteruskan ke {@link
    -+android.app.ListFragment#onListItemClick onListItemClick()} merupakan ID baris dari item yang diklik,
    -+yang digunakan aktivitas (atau fragmen lain) untuk mengambil artikel dari {@link
    -+android.content.ContentProvider} aplikasi.</p>
    -+
    -+<p><!--To see a complete implementation of this kind of callback interface, see the <a
    -+href="{@docRoot}resources/samples/NotePad/index.html">NotePad sample</a>. -->Informasi selengkapnya tentang
    -+menggunakan penyedia konten tersedia dalam dokumen <a href="{@docRoot}guide/topics/providers/content-providers.html">Penyedia Konten</a>.</p>
    -+
    -+
    -+
    -+<h3 id="ActionBar">Menambahkan item ke Action-Bar</h3>
    -+
    -+<p>Fragmen Anda bisa menyumbangkan item menu ke <a href="{@docRoot}guide/topics/ui/menus.html#options-menu">Menu Opsi</a> aktivitas (dan, konsekuensinya, <a href="{@docRoot}guide/topics/ui/actionbar.html">Action-Bar</a>) dengan mengimplementasikan
    -+{@link android.app.Fragment#onCreateOptionsMenu(Menu,MenuInflater) onCreateOptionsMenu()}. Agar
    -+metode ini bisa menerima panggilan, Anda harus memanggil {@link
    -+android.app.Fragment#setHasOptionsMenu(boolean) setHasOptionsMenu()} selama {@link
    -+android.app.Fragment#onCreate(Bundle) onCreate()}, untuk menunjukkan bahwa fragmen
    -+ingin menambahkan item ke Menu Opsi (jika tidak, fragmen tidak akan menerima panggilan ke
    -+{@link android.app.Fragment#onCreateOptionsMenu onCreateOptionsMenu()}).</p>
    -+
    -+<p>Setiap item yang selanjutnya Anda tambahkan ke Menu Opsi dari fragmen akan ditambahkan ke item menu
    -+yang ada. Fragmen juga menerima callback ke {@link
    -+android.app.Fragment#onOptionsItemSelected(MenuItem) onOptionsItemSelected()} bila item menu
    -+dipilih.</p>
    -+
    -+<p>Anda juga bisa mendaftarkan tampilan dalam layout fragmen untuk menyediakan menu konteks dengan memanggil {@link
    -+android.app.Fragment#registerForContextMenu(View) registerForContextMenu()}. Bila pengguna
    -+membuka menu konteks, fragmen akan menerima panggilan ke {@link
    -+android.app.Fragment#onCreateContextMenu(ContextMenu,View,ContextMenu.ContextMenuInfo)
    -+onCreateContextMenu()}. Bila pengguna memilih item, fragmen akan menerima panggilan ke @link
    -+android.app.Fragment#onContextItemSelected(MenuItem) onContextItemSelected()}.</p>
    -+
    -+<p class="note"><strong>Catatan:</strong> Walaupun fragmen menerima callback pada item yang dipilih
    -+untuk setiap item menu yang ditambahkannya, aktivitaslah yang pertama kali menerima masing-masing callback saat pengguna
    -+memilih item menu. Jika implementasi aktivitas dari callback bila-item-dipilih,
    -+tidak menangani item yang dipilih, maka kejadian akan diteruskan ke callback fragmen. Ini berlaku
    -+untuk Menu Opsi dan menu konteks.</p>
    -+
    -+<p>Untuk informasi selengkapnya tentang menu, lihat panduan pengembang <a href="{@docRoot}guide/topics/ui/menus.html">Menu</a> dan <a href="{@docRoot}guide/topics/ui/actionbar.html">Action-Bar</a>.</p>
    -+
    -+
    -+
    -+
    -+<h2 id="Lifecycle">Menangani Daur Hidup Fragmen</h2>
    -+
    -+<div class="figure" style="width:350px">
    -+<img src="{@docRoot}images/activity_fragment_lifecycle.png" alt="" />
    -+<p class="img-caption"><strong>Gambar 3.</strong> Efek daur hidup aktivitas pada daur hidup
    -+fragmen.</p>
    -+</div>
    -+
    -+<p>Mengelola daur hidup fragmen mirip sekali dengan mengelola daur hidup aktivitas. Seperti
    -+aktivitas, fragmen bisa berada dalam tiga status:</p>
    -+
    -+<dl>
    -+  <dt><i>Dilanjutkan</i></dt>
    -+    <dd>Fragmen terlihat dalam aktivitas yang berjalan.</dd>
    -+
    -+  <dt><i>Dihentikan sementara</i></dt>
    -+    <dd>Aktivitas lain berada di latar depan dan memiliki fokus, namun aktivitas tempat fragmen berada
    -+masih terlihat (aktivitas latar depan sebagian terlihat atau tidak menutupi
    -+seluruh layar).</dd>
    -+
    -+  <dt><i>Dihentikan</i></dt>
    -+    <dd>Fragmen tidak terlihat. Aktivitas host telah dihentikan atau
    -+fragmen telah dihapus dari aktivitas namun ditambahkan ke back-stack. Fragmen yang dihentikan
    -+masih hidup (semua status dan informasi anggota masih disimpan oleh sistem). Akan tetapi, fragmen
    -+tidak terlihat lagi oleh pengguna dan akan dimatikan jika aktivitas dimatikan.</dd>
    -+</dl>
    -+
    -+<p>Seperti halnya aktivitas, Anda bisa mempertahankan status fragmen menggunakan {@link
    -+android.os.Bundle}, jika proses aktivitas dimatikan dan Anda harus memulihkan status
    -+fragmen bila aktivitas dibuat kembali. Anda bisa menyimpan status selama callback {@link
    -+android.app.Fragment#onSaveInstanceState onSaveInstanceState()} fragmen dan memulihkannya selama
    -+{@link android.app.Fragment#onCreate onCreate()}, {@link
    -+android.app.Fragment#onCreateView onCreateView()}, atau {@link
    -+android.app.Fragment#onActivityCreated onActivityCreated()}. Untuk informasi selengkapnya tentang menyimpan
    -+status, lihat dokumen <a href="{@docRoot}guide/components/activities.html#SavingActivityState">Aktivitas</a>
    -+.</p>
    -+
    -+<p>Perbedaan paling signifikan dalam daur hidup antara aktivitas dan fragmen ada
    -+pada cara penyimpanannya dalam back-stack masing-masing. Aktivitas ditempatkan ke back-stack aktivitas
    -+yang dikelola oleh sistem saat dihentikan, secara default (sehingga pengguna bisa mengarah kembali
    -+ke aktivitas dengan tombol <em>Back</em>, seperti yang dibahas dalam <a href="{@docRoot}guide/components/tasks-and-back-stack.html">Tugas dan Back-Stack</a>).
    -+Akan tetapi, fragmen yang ditempatkan ke back-stack dikelola oleh aktivitas host hanya saat
    -+Anda secara eksplisit meminta agar instance disimpan dengan memanggil {@link
    -+android.app.FragmentTransaction#addToBackStack(String) addToBackStack()} selama transaksi yang
    -+menghapus fragmen.</p>
    -+
    -+<p>Jika tidak, pengelolaan daur hidup fragmen mirip sekali dengan mengelola daur hidup
    -+aktivitas. Jadi, praktik yang sama untuk <a href="{@docRoot}guide/components/activities.html#Lifecycle">mengelola daur hidup
    -+aktivitas</a> juga berlaku untuk fragmen. Namun yang perlu juga Anda pahami adalah bagaimana hidup
    -+aktivitas memengaruhi hidup fragmen.</p>
    -+
    -+<p class="caution"><strong>Perhatian:</strong> Jika Anda memerlukan objek {@link android.content.Context}
    -+ dalam {@link android.app.Fragment}, Anda bisa memanggil {@link android.app.Fragment#getActivity()}.
    -+Akan tetapi, berhati-hatilah memanggil {@link android.app.Fragment#getActivity()} hanya bila fragmen
    -+terkait dengan aktivitas. Bila fragmen belum terkait, atau terlepas selama akhir daur
    -+hidupnya, {@link android.app.Fragment#getActivity()} akan kembali nol.</p>
    -+
    -+
    -+<h3 id="CoordinatingWithActivity">Mengoordinasi dengan daur hidup aktivitas</h3>
    -+
    -+<p>Daur hidup aktivitas tempat fragmen berada akan memengaruhi langsung siklus hidup
    -+fragmen sedemikian rupa sehingga setiap callback daur hidup aktivitas menghasilkan callback yang sama untuk masing-masing
    -+fragmen. Misalnya, bila aktivitas menerima {@link android.app.Activity#onPause}, masing-masing
    -+fragmen dalam aktivitas akan menerima {@link android.app.Fragment#onPause}.</p>
    -+
    -+<p>Namun fragmen memiliki beberapa callback daur hidup ekstra, yang menangani interaksi
    -+unik dengan aktivitas untuk melakukan tindakan seperti membangun dan memusnahkan UI fragmen. Metode callback
    -+tambahan ini adalah:</p>
    -+
    -+<dl>
    -+  <dt>{@link android.app.Fragment#onAttach onAttach()}</dt>
    -+    <dd>Dipanggil bila fragmen telah dikaitkan dengan aktivitas ({@link
    -+android.app.Activity} diteruskan di sini).</dd>
    -+  <dt>{@link android.app.Fragment#onCreateView onCreateView()}</dt>
    -+    <dd>Dipanggil untuk membuat hierarki tampilan yang dikaitkan dengan fragmen.</dd>
    -+  <dt>{@link android.app.Fragment#onActivityCreated onActivityCreated()}</dt>
    -+    <dd>Dipanggil bila metode {@link android.app.Activity#onCreate
    -+onCreate()} aktivitas telah dikembalikan.</dd>
    -+  <dt>{@link android.app.Fragment#onDestroyView onDestroyView()}</dt>
    -+    <dd>Dipanggil bila hierarki tampilan yang terkait dengan fragmen dihapus.</dd>
    -+  <dt>{@link android.app.Fragment#onDetach onDetach()}</dt>
    -+    <dd>Dipanggil bila fragmen diputuskan dari aktivitas.</dd>
    -+</dl>
    -+
    -+<p>Aliran daur hidup fragmen, karena dipengaruhi oleh aktivitas host-nya, diilustrasikan oleh
    -+gambar 3. Dalam gambar ini, Anda bisa melihat bagaimana setiap status aktivitas menentukan
    -+metode callback mana yang mungkin diterima fragmen. Misalnya, saat aktivitas menerima call back {@link
    -+android.app.Activity#onCreate onCreate()}, fragmen dalam aktivitas akan menerima tidak lebih
    -+dari callback {@link android.app.Fragment#onActivityCreated onActivityCreated()}.</p>
    -+
    -+<p>Setelah status aktivitas diteruskan kembali, Anda bisa bebas menambah dan menghapus fragmen untuk
    -+aktivitas tersebut. Sehingga, hanya saat aktivitas berada dalam status dilanjutkan, daur hidup fragmen bisa
    -+berubah secara independen.</p>
    -+
    -+<p>Akan tetapi, saat aktivitas meninggalkan status dilanjutkan, fragmen akan kembali didorong
    -+melalui daur hidupnya oleh aktivitas.</p>
    -+
    -+
    -+
    -+
    -+<h2 id="Example">Contoh</h2>
    -+
    -+<p>Untuk merangkum semua yang telah dibahas dalam dokumen ini, berikut ini contoh aktivitas
    -+yang menggunakan dua fragmen untuk membuat layout dua panel. Aktivitas di bawah ini menyertakan satu fragmen untuk
    -+menampilkan daftar putar Shakespeare dan fragmen lainnya menampilkan rangkuman pemutaran bila dipilih dari
    -+daftar. Aktivitas ini juga menunjukkan cara menyediakan konfigurasi fragmen berbeda,
    -+berdasarkan konfigurasi layar.</p>
    -+
    -+<p class="note"><strong>Catatan:</strong> Kode sumber lengkap untuk aktivitas ini tersedia di
    -+<a href="{@docRoot}resources/samples/ApiDemos/src/com/example/android/apis/app/FragmentLayout.html">{@code
    -+FragmentLayout.java}</a>.</p>
    -+
    -+<p>Aktivitas utama akan menerapkan layout seperti biasa, selama {@link
    -+android.app.Activity#onCreate onCreate()}:</p>
    -+
    -+{@sample development/samples/ApiDemos/src/com/example/android/apis/app/FragmentLayout.java main}
    -+
    -+<p>Layout yang diterapkan adalah {@code fragment_layout.xml}:</p>
    -+
    -+{@sample development/samples/ApiDemos/res/layout-land/fragment_layout.xml layout}
    -+
    -+<p>Dengan layout ini, sistem akan membuat instance {@code TitlesFragment} (yang mencantumkan
    -+judul) segera setelah aktivitas memuat layout, sementara {@link android.widget.FrameLayout}
    -+ (lokasi penempatan fragmen untuk menampilkan rangkuman pemutaran) menempati ruang di sisi kanan
    -+layar, namun pada awalnya masih kosong. Seperti yang akan Anda lihat di bawah ini, sampai pengguna memilih item
    -+dari daftar maka fragmen baru akan ditempatkan ke dalam {@link android.widget.FrameLayout}.</p>
    -+
    -+<p>Akan tetapi, tidak semua konfigurasi layar cukup lebar untuk menampilkan
    -+daftar putar dan rangkuman secara berdampingan. Sehingga, layout di atas hanya digunakan untuk konfigurasi
    -+layar mendatar, dengan menyimpannya di {@code res/layout-land/fragment_layout.xml}.</p>
    -+
    -+<p>Sehingga, bila layar berada dalam orientasi tegak, sistem akan menerapkan layout berikut, yang
    -+tersimpan di {@code res/layout/fragment_layout.xml}:</p>
    -+
    -+{@sample development/samples/ApiDemos/res/layout/fragment_layout.xml layout}
    -+
    -+<p>Layout ini hanya menyertakan {@code TitlesFragment}. Ini artinya saat perangkat berada dalam
    -+orientasi tegak, hanya judul daftar putar yang terlihat. Jadi, saat pengguna mengklik item
    -+daftar dalam konfigurasi ini, aplikasi akan memulai aktivitas baru untuk menampilkan rangkuman,
    -+sebagai ganti pemuatan fragmen kedua.</p>
    -+
    -+<p>Berikutnya, Anda bisa melihat bagaimana hal ini dilakukan dalam kelas fragmen. Pertama adalah {@code
    -+TitlesFragment}, yang menampilkan judul daftar putar Shakespeare. Fragmen ini membuat ekstensi {@link
    -+android.app.ListFragment} dan mengandalkannya itu untuk menangani sebagian besar pekerjaan tampilan daftar.</p>
    -+
    -+<p>Saat Anda memeriksa kode ini, perhatikan bahwa ada dua kemungkinan perilaku saat pengguna mengklik
    -+item daftar: bergantung pada layout mana yang aktif, bisa membuat dan menampilkan fragmen
    -+baru untuk menampilkan detail dalam aktivitas yang sama (menambahkan fragmen ke {@link
    -+android.widget.FrameLayout}), atau memulai aktivitas baru (tempat fragmen ditampilkan).</p>
    -+
    -+{@sample development/samples/ApiDemos/src/com/example/android/apis/app/FragmentLayout.java titles}
    -+
    -+<p>Fragmen kedua, {@code DetailsFragment} menampilkan rangkuman pemutaran untuk item yang dipilih dari
    -+daftar dari {@code TitlesFragment}:</p>
    -+
    -+{@sample development/samples/ApiDemos/src/com/example/android/apis/app/FragmentLayout.java details}
    -+
    -+<p>Ingatlah dari kelas {@code TitlesFragment}, bahwa, jika pengguna mengklik item daftar dan
    -+layout saat ini <em>tidak</em> menyertakan tampilan {@code R.id.details} (yaitu tempat
    -+{@code DetailsFragment} berada), maka aplikasi memulai aktivitas {@code DetailsActivity}
    -+untuk menampilkan konten item.</p>
    -+
    -+<p>Berikut ini adalah {@code DetailsActivity}, yang hanya menanamkan {@code DetailsFragment} untuk menampilkan rangkuman pemutaran
    -+yang dipilih saat layar dalam orientasi tegak:</p>
    -+
    -+{@sample development/samples/ApiDemos/src/com/example/android/apis/app/FragmentLayout.java
    -+details_activity}
    -+
    -+<p>Perhatikan bahwa aktivitas ini selesai sendiri jika konfigurasi mendatar, sehingga aktivitas utama
    -+bisa mengambil alih dan menampilkan {@code DetailsFragment} bersama {@code TitlesFragment}.
    -+Ini bisa terjadi jika pengguna memulai {@code DetailsActivity} saat dalam orientasi tegak, namun kemudian
    -+memutarnya menjadi mendatar (yang akan memulai lagi aktivitas saat ini).</p>
    -+
    -+
    -+<p>Untuk contoh lainnya mengenai penggunaan fragmen (dan file sumber lengkap untuk contoh ini),
    -+lihat aplikasi contoh Demo API yang tersedia di <a href="{@docRoot}resources/samples/ApiDemos/src/com/example/android/apis/app/index.html#Fragment">
    -+ApiDemos</a> (bisa diunduh dari <a href="{@docRoot}resources/samples/get.html">Komponen contoh SDK</a>).</p>
    -+
    -+
    -diff --git a/docs/html-intl/intl/id/guide/components/fundamentals.jd b/docs/html-intl/intl/id/guide/components/fundamentals.jd
    -new file mode 100644
    -index 0000000..2c925e9
    ---- /dev/null
    -+++ b/docs/html-intl/intl/id/guide/components/fundamentals.jd
    -@@ -0,0 +1,480 @@
    -+page.title=Dasar-Dasar Aplikasi
    -+@jd:body
    -+
    -+<div id="qv-wrapper">
    -+<div id="qv">
    -+
    -+<h2>Dalam dokumen ini</h2>
    -+<ol>
    -+<li><a href="#Components">Komponen Aplikasi</a>
    -+  <ol>
    -+    <li><a href="#ActivatingComponents">Mengaktifkan komponen</a></li>
    -+  </ol>
    -+</li>
    -+<li><a href="#Manifest">File Manifes</a>
    -+  <ol>
    -+    <li><a href="#DeclaringComponents">Mendeklarasikan komponen</a></li>
    -+    <li><a href="#DeclaringRequirements">Mendeklarasikan kebutuhan aplikasi</a></li>
    -+  </ol>
    -+</li>
    -+<li><a href="#Resources">Sumber Daya Aplikasi</a></li>
    -+</ol>
    -+</div>
    -+</div>
    -+
    -+<p>Aplikasi Android ditulis dalam bahasa pemrograman Java. Android SDK Tools mengkompilasi
    -+kode Anda&mdash;bersama data dan file sumber daya &mdash;ke dalam APK: <i>Paket Android</i>,
    -+yaitu file arsip berekstensi {@code .apk}. Satu file APK berisi semua konten
    -+aplikasi Android dan merupakan file yang digunakan perangkat berbasis Android untuk menginstal aplikasi.</p>
    -+
    -+<p>Setelah diinstal di perangkat, setiap aplikasi Android tinggal di sandbox keamanannya sendiri: </p>
    -+
    -+<ul>
    -+ <li>Sistem operasi Android merupakan sistem Linux multi-pengguna yang di dalamnya setiap
    -+aplikasi adalah pengguna berbeda.</li>
    -+
    -+<li>Secara default, sistem menetapkan ID pengguna Linux unik kepada setiap aplikasi (ID ini hanya
    -+ digunakan oleh sistem dan tidak diketahui aplikasi). Sistem menetapkan izin
    -+bagi semua file dalam aplikasi sehingga hanya ID pengguna yang diizinkan yang bisa mengaksesnya. </li>
    -+
    -+<li>Setiap proses memiliki mesin virtual (VM) sendiri, sehingga kode aplikasi yang berjalan secara terisolasi dari
    -+aplikasi lainnya.</li>
    -+
    -+<li>Secara default, setiap aplikasi berjalan dalam proses Linux-nya sendiri. Android memulai proses
    -+bila ada komponen aplikasi yang perlu dijalankan, kemudian mematikan proses bila tidak lagi diperlukan
    -+atau bila sistem harus memulihkan memori untuk digunakan aplikasi lain.</li>
    -+</ul>
    -+
    -+<p>Dengan cara ini, sistem Android mengimplementasikan <em>prinsip privilese minim</em>. Ini berarti,
    -+secara default aplikasi hanya memiliki akses ke komponen yang diperlukannya untuk melakukan pekerjaannya dan
    -+tidak lebih dari itu. Hal ini menghasilkan lingkungan yang sangat aman sehingga aplikasi tidak bisa mengakses bagian
    -+sistem bila tidak diberi izin.</p>
    -+
    -+<p>Akan tetapi, ada beberapa cara bagi aplikasi untuk berbagi data dengan aplikasi lain dan bagi aplikasi
    -+untuk mengakses layanan sistem:</p>
    -+
    -+<ul>
    -+  <li>Dua aplikasi bisa diatur untuk menggunakan ID pengguna Linux yang sama,
    -+dalam hal ini keduanya bisa saling mengakses file masing-masing.  Untuk menghemat sumber daya sistem, aplikasi dengan ID
    -+pengguna yang sama juga bisa diatur agar berjalan dalam proses Linux yang sama dan menggunakan VM yang sama (
    -+aplikasi juga harus ditandatangani dengan sertifikat yang sama).</li>
    -+  <li>Aplikasi bisa meminta izin akses ke data perangkat seperti kontak
    -+pengguna, pesan SMS, penyimpanan lepas-pasang (kartu SD), kamera, Bluetooth, dan lainnya. Semua
    -+izin aplikasi harus diberikan oleh pengguna saat menginstal.</li>
    -+</ul>
    -+
    -+<p>Hal tersebut mencakup dasar-dasar tentang cara aplikasi Android berada di dalam sistem. Bagian dokumen
    -+selanjutnya memperkenalkan Anda pada:</p>
    -+<ul>
    -+  <li>Komponen kerangka kerja inti yang mendefinisikan aplikasi.</li>
    -+  <li>File manifes tempat Anda mendeklarasikan komponen dan fitur yang diperlukan perangkat
    -+untuk aplikasi.</li>
    -+  <li>Sumber daya yang terpisah dari kode aplikasi dan memungkinkan
    -+aplikasi mengoptimalkan perilakunya untuk beragam konfigurasi perangkat.</li>
    -+</ul>
    -+
    -+
    -+
    -+<h2 id="Components">Komponen Aplikasi</h2>
    -+
    -+<p>Komponen aplikasi adalah blok pembangun penting dari aplikasi Android.
    -+Setiap komponen merupakan titik berbeda yang digunakan sistem untuk memasuki aplikasi. Tidak semua komponen
    -+merupakan titik masuk sebenarnya bagi pengguna dan sebagian saling bergantung, namun masing-masing komponen tersedia
    -+sebagai kesatuan sendiri dan memainkan peran tertentu&mdash;masing-masing merupakan
    -+blok pembangun unik yang mendefinisikan perilaku aplikasi secara keseluruhan.</p>
    -+
    -+<p>Ada empat macam tipe komponen aplikasi. Setiap tipe memiliki kegunaan tersendiri
    -+dan daur hidupnya sendiri yang mendefinisikan cara komponen dibuat dan dimusnahkan.</p>
    -+
    -+<p>Berikut ini empat tipe komponen aplikasi:</p>
    -+
    -+<dl>
    -+
    -+<dt><b>Aktivitas</b></dt>
    -+
    -+<dd>Sebuah <i>aktivitas</i> mewakili satu layar dengan antarmuka pengguna. Misalnya,
    -+aplikasi email mungkin memiliki satu aktivitas yang menampilkan daftar email
    -+baru, aktivitas lain untuk menulis email, dan aktivitas satunya lagi untuk membaca email. Walaupun
    -+semua aktivitas bekerja sama untuk membentuk pengalaman pengguna yang kohesif dalam aplikasi email,
    -+masing-masing tidak saling bergantung. Karenanya, aplikasi berbeda bisa memulai
    -+salah satu aktivitas ini (jika aplikasi email mengizinkannya). Misalnya, aplikasi kamera bisa memulai
    -+aktivitas dalam aplikasi email yang membuat email baru agar pengguna bisa berbagi gambar.
    -+
    -+<p>Aktivitas diimplementasikan sebagai subkelas {@link android.app.Activity} dan Anda bisa mengetahui selengkapnya
    -+tentang hal ini dalam panduan pengembang <a href="{@docRoot}guide/components/activities.html">Aktivitas</a>
    -+.</p>
    -+</dd>
    -+
    -+
    -+<dt><b>Layanan</b></dt>
    -+
    -+<dd>Sebuah <i>layanan</i> adalah komponen yang berjalan di latar belakang untuk melakukan
    -+operasi yang berjalan lama atau untuk melakukan pekerjaan bagi proses jarak jauh. Layanan
    -+tidak menyediakan antarmuka pengguna. Misalnya, sebuah layanan bisa memutar musik di latar belakang sementara
    -+pengguna berada dalam aplikasi lain, atau layanan bisa menarik data lewat jaringan tanpa
    -+memblokir interaksi pengguna dengan aktivitas. Komponen lain, seperti aktivitas, bisa memulai
    -+layanan dan membiarkannya berjalan atau mengikat layanan untuk berinteraksi dengannya.
    -+
    -+<p>Layanan diimplementasikan sebagai subkelas {@link android.app.Service} dan Anda bisa mengetahui selengkapnya
    -+tentang hal ini dalam panduan
    -+pengembang <a href="{@docRoot}guide/components/services.html">Layanan</a>.</p>
    -+</dd>
    -+
    -+
    -+<dt><b>Penyedia konten</b></dt>
    -+
    -+<dd>Sebuah <i>penyedia konten</i> mengelola seperangkat data-bersama aplikasi. Anda bisa menyimpan data
    -+dalam sistem file, database SQLite, di web, atau lokasi penyimpanan permanen lainnya
    -+yang bisa diakses aplikasi. Melalui penyedia konten, aplikasi lain bisa melakukan query atau bahkan
    -+memodifikasi data (jika penyedia konten mengizinkannya). Misalnya, sistem Android menyediakan penyedia
    -+konten yang mengelola informasi kontak pengguna. Karenanya, setiap aplikasi
    -+dengan izin yang sesuai bisa melakukan query mengenai bagian dari penyedia konten (seperti {@link
    -+android.provider.ContactsContract.Data}) untuk membaca dan menulis informasi tentang orang tertentu.
    -+
    -+<p>Penyedia konten juga berguna untuk membaca dan menulis data privat ke aplikasi Anda
    -+dan tidak dibagikan. Misalnya, aplikasi contoh <a href="{@docRoot}resources/samples/NotePad/index.html">Note Pad</a> menggunakan
    -+penyedia konten untuk menyimpan catatan.</p>
    -+
    -+<p>Penyedia konten diimplementasikan sebagai subkelas {@link android.content.ContentProvider}
    -+dan harus mengimplementasikan seperangkat standar API yang memungkinkan aplikasi
    -+lain melakukan transaksi. Untuk informasi selengkapnya, lihat panduan pengembang
    -+<a href="{@docRoot}guide/topics/providers/content-providers.html">Penyedia Konten</a>.</p>
    -+</dd>
    -+
    -+
    -+<dt><b>Penerima siaran</b></dt>
    -+
    -+<dd>Sebuah <i>penerima siaran</i> adalah komponen yang merespons pengumuman siaran dalam lingkup
    -+sistem.  Banyak siaran yang berasal dari sistem&mdash;misalnya, siaran yang mengumumkan bahwa
    -+layar telah dimatikan, baterai lemah, atau gambar telah direkam.
    -+Aplikasi juga bisa memulai siaran&mdash;misalnya untuk menginformasikan ke
    -+aplikasi lain bahwa sebagian data telah diunduh ke perangkat dan bisa digunakan aplikasi lain tersebut. Walaupun penerima
    -+siaran tidak menampilkan antarmuka pengguna, penerima bisa <a href="{@docRoot}guide/topics/ui/notifiers/notifications.html">membuat pemberitahuan baris status</a>
    -+untuk memberi tahu pengguna kapan kejadian siaran dilakukan. Meskipun penerima siaran umumnya cuma menjadi
    -+"gerbang" untuk komponen lain dan dimaksudkan untuk melakukan pekerjaan dalam jumlah sangat minim. Misalnya
    -+, penerima siaran bisa menjalankan layanan untuk melakukan beberapa pekerjaan berdasarkan kejadian.
    -+
    -+<p>Penerima siaran diimplementasikan sebagai subkelas {@link android.content.BroadcastReceiver}
    -+dan setiap siaran dikirim sebagai objek {@link android.content.Intent}. Untuk informasi selengkapnya,
    -+lihat kelas {@link android.content.BroadcastReceiver}.</p>
    -+</dd>
    -+
    -+</dl>
    -+
    -+
    -+
    -+<p>Aspek unik dari desain sistem Android adalah aplikasi mana pun bisa memulai
    -+komponen aplikasi lain. Misalnya, jika Anda menginginkan pengguna mengambil
    -+foto dengan kamera perangkat, bisa saja aplikasi lain yang melakukannya dan aplikasi
    -+Anda bisa menggunakannya, sebagai ganti mengembangkan aktivitas sendiri untuk mengambil foto. Anda tidak
    -+harus menyatukan atau bahkan menautkan ke kode dari aplikasi kamera.
    -+Sebagai gantinya, Anda tinggal memulai aktivitas di aplikasi kamera yang akan mengambil
    -+foto. Bila selesai, foto akan dikembalikan ke aplikasi sehingga Anda bisa menggunakannya. Bagi pengguna,
    -+kamera seakan menjadi bagian dari aplikasi Anda.</p>
    -+
    -+<p>Saat sistem memulai komponen, sistem akan memulai proses untuk aplikasi itu (jika
    -+belum berjalan) dan membuat instance kelas yang diperlukan untuk komponen. Misalnya, jika aplikasi Anda
    -+memulai aktivitas dalam aplikasi kamera yang mengambil foto, aktivitas itu akan
    -+berjalan dalam proses yang dimiliki oleh aplikasi kamera, bukan dalam proses aplikasi Anda.
    -+Karenanya, tidak seperti aplikasi di sebagian besar sistem lain, aplikasi Android tidak memiliki titik
    -+masuk tunggal (misalnya tidak ada fungsi {@code main()}).</p>
    -+
    -+<p>Karena sistem menjalankan setiap aplikasi dalam proses terpisah dengan izin file yang
    -+membatasi akses ke aplikasi lain, aplikasi Anda tidak bisa langsung mengaktifkan komponen dari aplikasi lain. Akan tetapi, sistem
    -+Android bisa melakukannya. Jadi, untuk mengaktifkan
    -+komponen dalam aplikasi lain, Anda harus mengirim pesan ke sistem yang menetapkan <em>intent</em> Anda untuk memulai
    -+komponen tertentu. Selanjutnya sistem akan mengaktifkan komponen untuk Anda.</p>
    -+
    -+
    -+<h3 id="ActivatingComponents">Mengaktifkan Komponen</h3>
    -+
    -+<p>Tiga dari empat tipe komponen&mdash;aktivitas, layanan, dan
    -+penerima siaran&mdash;diaktifkan oleh pesan asinkron yang disebut <em>intent</em>.
    -+Intent saling mengikat setiap komponen saat runtime (Anda bisa menganggapnya
    -+sebagai pembawa pesan yang meminta tindakan dari komponen lain), baik komponen itu milik aplikasi Anda
    -+atau milik aplikasi lain.</p>
    -+
    -+<p>Intent dibuat dengan objek {@link android.content.Intent}, yang mendefinisikan pesan untuk
    -+mengaktifkan komponen tertentu atau komponen <em>tipe</em> komponen tertentu&mdash;masing-masing intent
    -+bisa eksplisit atau implisit.</p>
    -+
    -+<p>Untuk aktivitas dan layanan, intent mendefinisikan tindakan yang akan dilakukan (misalnya, untuk "melihat" atau
    -+"mengirim" sesuatu) dan mungkin menetapkan URI data untuk ditindaklanjuti (salah satu hal yang mungkin perlu diketahui
    -+oleh komponen yang akan dimulai). Misalnya, intent mungkin menyampaikan permintaan suatu
    -+aktivitas untuk menampilkan gambar atau membuka halaman web. Dalam beberapa kasus, Anda bisa memulai
    -+aktivitas untuk menerima hasil, dalam hal ini, aktivitas juga akan mengembalikan hasil
    -+dalam {@link android.content.Intent} (misalnya Anda bisa mengeluarkan intent agar
    -+pengguna bisa memilih kontak pribadi dan memintanya dikembalikan kepada Anda&mdash;intent yang dikembalikan menyertakan URI yang
    -+menunjuk ke kontak yang dipilih).</p>
    -+
    -+<p>Untuk penerima siaran, intent hanya mendefinisikan
    -+pengumuman yang sedang disiarkan (misalnya, siaran untuk menunjukkan baterai perangkat hampir habis
    -+hanya menyertakan string tindakan yang menunjukkan "baterai hampir habis").</p>
    -+
    -+<p>Tipe komponen lainnya dan penyedia konten, tidak diaktifkan oleh intent. Melainkan
    -+diaktifkan saat ditargetkan oleh permintaan dari {@link android.content.ContentResolver}. Resolver
    -+konten menangani semua transaksi langsung dengan penyedia konten sehingga komponen yang melakukan
    -+transaksi dengan penyedia tidak perlu dan sebagai gantinya memanggil metode pada objek {@link
    -+android.content.ContentResolver}. Ini membuat lapisan abstraksi antara penyedia
    -+konten dan komponen yang meminta informasi (demi keamanan).</p>
    -+
    -+<p>Ada beberapa metode terpisah untuk mengaktifkan masing-masing tipe komponen:</p>
    -+<ul>
    -+  <li>Anda bisa memulai aktivitas (atau memberinya pekerjaan baru) dengan
    -+meneruskan {@link android.content.Intent} ke {@link android.content.Context#startActivity
    -+startActivity()} atau {@link android.app.Activity#startActivityForResult startActivityForResult()}
    -+(bila Anda ingin aktivitas mengembalikan hasil).</li>
    -+  <li>Anda bisa memulai layanan (atau memberikan instruksi baru ke layanan yang sedang berlangsung) dengan
    -+meneruskan {@link android.content.Intent} ke {@link android.content.Context#startService
    -+startService()}. Atau Anda bisa mengikat ke layanan dengan meneruskan {@link android.content.Intent} ke
    -+{@link android.content.Context#bindService bindService()}.</li>
    -+  <li>Anda bisa memulai siaran dengan meneruskan {@link android.content.Intent} ke metode seperti
    -+{@link android.content.Context#sendBroadcast(Intent) sendBroadcast()}, {@link
    -+android.content.Context#sendOrderedBroadcast(Intent, String) sendOrderedBroadcast()}, atau {@link
    -+android.content.Context#sendStickyBroadcast sendStickyBroadcast()}.</li>
    -+  <li>Anda bisa melakukan query ke penyedia konten dengan memanggil {@link
    -+android.content.ContentProvider#query query()} pada {@link android.content.ContentResolver}.</li>
    -+</ul>
    -+
    -+<p>Untuk informasi selengkapnya tentang menggunakan intent, lihat dokumen <a href="{@docRoot}guide/components/intents-filters.html">Intent dan Filter
    -+ Intent</a>. Informasi selengkapnya tentang mengaktifkan komponen
    -+tertentu juga tersedia dalam dokumen berikut: <a href="{@docRoot}guide/components/activities.html">Aktivitas</a>, <a href="{@docRoot}guide/components/services.html">Layanan</a>, {@link
    -+android.content.BroadcastReceiver} dan <a href="{@docRoot}guide/topics/providers/content-providers.html">Penyedia Konten</a>.</p>
    -+
    -+
    -+<h2 id="Manifest">File Manifes</h2>
    -+
    -+<p>Sebelum sistem Android bisa memulai komponen aplikasi, sistem harus mengetahui
    -+keberadaan komponen dengan membaca file {@code AndroidManifest.xml} aplikasi (file
    -+"manifes"). Aplikasi Anda harus mendeklarasikan semua komponennya dalam file ini, yang harus menjadi akar
    -+dari direktori proyek aplikasi.</p>
    -+
    -+<p>Manifes melakukan banyak hal selain mendeklarasikan komponen aplikasi,
    -+seperti:</p>
    -+<ul>
    -+  <li>Mengidentifikasi izin pengguna yang diperlukan aplikasi, seperti akses Internet atau
    -+akses-baca ke kontak pengguna.</li>
    -+  <li>Mendeklarasikan <a href="{@docRoot}guide/topics/manifest/uses-sdk-element.html#ApiLevels">API Level</a>
    -+ minimum yang diperlukan aplikasi, berdasarkan API yang digunakan aplikasi.</li>
    -+  <li>Mendeklarasikan fitur perangkat keras dan perangkat lunak yang diperlukan aplikasi, seperti kamera,
    -+layanan Bluetooth, atau layar multisentuh.</li>
    -+  <li>Pustaka API aplikasi perlu ditautkan (selain
    -+API kerangka kerja Android), seperti pustaka
    -+<a href="http://code.google.com/android/add-ons/google-apis/maps-overview.html">Google Maps.</a></li>
    -+  <li>Dan lainnya</li>
    -+</ul>
    -+
    -+
    -+<h3 id="DeclaringComponents">Mendeklarasikan komponen</h3>
    -+
    -+<p>Tugas utama manifes adalah menginformasikan komponen aplikasi pada sistem. Misalnya,
    -+file manifes bisa mendeklarasikan aktivitas sebagai berikut: </p>
    -+
    -+<pre>
    -+&lt;?xml version="1.0" encoding="utf-8"?&gt;
    -+&lt;manifest ... &gt;
    -+    &lt;application android:icon="@drawable/app_icon.png" ... &gt;
    -+        &lt;activity android:name="com.example.project.ExampleActivity"
    -+                  android:label="@string/example_label" ... &gt;
    -+        &lt;/activity&gt;
    -+        ...
    -+    &lt;/application&gt;
    -+&lt;/manifest&gt;</pre>
    -+
    -+<p>Dalam elemen <code><a
    -+href="{@docRoot}guide/topics/manifest/application-element.html">&lt;application&gt;</a></code>
    -+, atribut {@code android:icon} menunjuk ke sumber daya untuk ikon yang mengidentifikasi
    -+aplikasi.</p>
    -+
    -+<p>Dalam elemen <code><a
    -+href="{@docRoot}guide/topics/manifest/activity-element.html">&lt;activity&gt;</a></code>,
    -+atribut {@code android:name} menetapkan nama kelas yang sepenuhnya memenuhi syarat subkelas {@link
    -+android.app.Activity} dan atribut {@code android:label} menetapkan string yang akan
    -+digunakan sebagai label yang terlihat oleh pengguna untuk aktivitas tersebut.</p>
    -+
    -+<p>Anda harus mendeklarasikan semua komponen aplikasi dengan cara ini:</p>
    -+<ul>
    -+  <li>Elemen <code><a
    -+href="{@docRoot}guide/topics/manifest/activity-element.html">&lt;activity&gt;</a></code> untuk
    -+aktivitas</li>
    -+  <li>Elemen <code><a
    -+href="{@docRoot}guide/topics/manifest/service-element.html">&lt;service&gt;</a></code> untuk
    -+layanan</li>
    -+  <li>Elemen <code><a
    -+href="{@docRoot}guide/topics/manifest/receiver-element.html">&lt;receiver&gt;</a></code> untuk
    -+penerima siaran</li>
    -+  <li>Elemen <code><a
    -+href="{@docRoot}guide/topics/manifest/provider-element.html">&lt;provider&gt;</a></code> untuk
    -+penyedia konten</li>
    -+</ul>
    -+
    -+<p>Aktivitas, layanan, dan penyedia konten yang Anda sertakan dalam kode sumber, namun tidak
    -+dideklarasikan dalam manifes, tidak akan terlihat pada sistem dan, akibatnya, tidak pernah bisa berjalan.  Akan tetapi,
    -+penerima siaran
    -+bisa dideklarasikan dalam manifes atau dibuat secara dinamis dalam kode (sebagai objek
    -+{@link android.content.BroadcastReceiver}) dan didaftarkan pada sistem dengan memanggil
    -+{@link android.content.Context#registerReceiver registerReceiver()}.</p>
    -+
    -+<p>Untuk informasi selengkapnya tentang cara menstrukturkan file manifes untuk aplikasi Anda,
    -+lihat dokumentasi <a href="{@docRoot}guide/topics/manifest/manifest-intro.html">File AndroidManifest.xml</a>. </p>
    -+
    -+
    -+
    -+<h3 id="DeclaringComponentCapabilities">Mendeklarasikan kemampuan komponen</h3>
    -+
    -+<p>Seperti telah dibahas di atas, dalam <a href="#ActivatingComponents">Mengaktifkan Komponen</a>, Anda bisa menggunakan
    -+{@link android.content.Intent} untuk memulai aktivitas, layanan, dan penerima siaran. Anda bisa
    -+melakukannya dengan menamai komponen sasaran secara eksplisit (menggunakan nama kelas komponen) dalam intent. Akan tetapi,
    -+kemampuan intent sebenarnya ada pada konsep <em>intent implisit</em>. Intent implisit
    -+cuma menjelaskan tipe tindakan yang akan dilakukan (dan, secara opsional, data tempat Anda ingin
    -+melakukan tindakan) dan memungkinkan sistem untuk menemukan komponen pada perangkat yang bisa melakukan
    -+tindakan tersebut dan memulainya. Jika ada banyak komponen yang bisa melakukan tindakan yang dijelaskan oleh intent,
    -+maka pengguna bisa memilih komponen yang akan digunakan.</p>
    -+
    -+<p>Cara sistem mengidentifikasi komponen yang bisa merespons intent adalah dengan membandingkan
    -+intent yang diterima dengan <i>filter intent</i> yang disediakan dalam file manifes aplikasi lainnya pada
    -+perangkat.</p>
    -+
    -+<p>Bila mendeklarasikan aktivitas dalam manifes aplikasi, secara opsional Anda bisa menyertakan
    -+filter intent yang mendeklarasikan kemampuan aktivitas agar bisa merespons intent dari
    -+aplikasi lain. Anda bisa mendeklarasikan filter intent untuk komponen dengan
    -+menambahkan elemen <a href="{@docRoot}guide/topics/manifest/intent-filter-element.html">{@code
    -+&lt;intent-filter&gt;}</a> sebagai anak elemen deklarasi komponen.</p>
    -+
    -+<p>Misalnya, jika Anda telah membangun aplikasi email dengan aktivitas untuk menulis email baru, Anda bisa
    -+mendeklarasikan filter intent untuk merespons intent "kirim" (untuk mengirim email baru) seperti ini:</p>
    -+<pre>
    -+&lt;manifest ... >
    -+    ...
    -+    &lt;application ... &gt;
    -+        &lt;activity android:name="com.example.project.ComposeEmailActivity">
    -+            &lt;intent-filter>
    -+                &lt;action android:name="android.intent.action.SEND" />
    -+                &lt;data android:type="*/*" />
    -+                &lt;category android:name="android.intent.category.DEFAULT" />
    -+            &lt;/intent-filter>
    -+        &lt;/activity>
    -+    &lt;/application&gt;
    -+&lt;/manifest>
    -+</pre>
    -+
    -+<p>Kemudian, jika aplikasi lain membuat intent dengan tindakan {@link
    -+android.content.Intent#ACTION_SEND} dan meneruskannya ke {@link android.app.Activity#startActivity
    -+startActivity()}, sistem bisa memulai aktivitas Anda agar pengguna bisa menulis draf dan mengirim
    -+email.</p>
    -+
    -+<p>Untuk informasi selengkapnya tentang membuat filter intent, lihat dokumen <a href="{@docRoot}guide/components/intents-filters.html">Intent dan Filter Intent</a>.
    -+</p>
    -+
    -+
    -+
    -+<h3 id="DeclaringRequirements">Mendeklarasikan kebutuhan aplikasi</h3>
    -+
    -+<p>Ada berbagai macam perangkat yang didukung oleh Android dan tidak
    -+semuanya menyediakan fitur dan kemampuan yang sama. Agar aplikasi Anda tidak dihapus pada perangkat yang tidak memiliki
    -+fitur yang diperlukan aplikasi, Anda harus jelas mendefinisikan profil mengenai
    -+tipe perangkat yang didukung aplikasi dengan mendeklarasikan kebutuhan perangkat dan perangkat lunak dalam file
    -+manifes. Kebanyakan deklarasi ini hanya bersifat informasi dan sistem tidak
    -+membacanya, namun layanan eksternal seperti Google Play akan membacanya untuk menyediakan
    -+penyaringan bagi pengguna saat mereka mencari aplikasi dari perangkat.</p>
    -+
    -+<p>Misalnya, jika aplikasi memerlukan kamera dan menggunakan API yang disediakan dalam Android 2.1 (<a href="{@docRoot}guide/topics/manifest/uses-sdk-element.html#ApiLevels">API Level</a> 7)
    -+, Anda harus mendeklarasikannya sebagai kebutuhan dalam file manifes seperti ini:</p>
    -+
    -+<pre>
    -+&lt;manifest ... >
    -+    &lt;uses-feature android:name="android.hardware.camera.any"
    -+                  android:required="true" />
    -+    &lt;uses-sdk android:minSdkVersion="7" android:targetSdkVersion="19" />
    -+    ...
    -+&lt;/manifest>
    -+</pre>
    -+
    -+<p>Sekarang, perangkat yang <em>tidak</em> memiliki kamera dan menggunakan
    -+Android versi <em>lebih rendah</em> dari 2.1 tidak bisa menginstal aplikasi Anda dari Google Play.</p>
    -+
    -+<p>Akan tetapi, bisa juga mendeklarasikan bahwa aplikasi Anda menggunakan kamera, namun tidak
    -+<em>mengharuskannya</em>. Dalam hal itu, aplikasi Anda harus mengatur atribut <a href="{@docRoot}guide/topics/manifest/uses-feature-element.html#required">{@code required}</a>
    -+ ke {@code "false"} dan memeriksa saat runtime apakah
    -+perangkat memiliki kamera dan menonaktifkan setiap fitur kamera yang sesuai.</p>
    -+
    -+<p>Informasi selengkapnya tentang cara mengelola kompatibilitas aplikasi dengan
    -+perangkat yang berbeda disediakan dalam dokumen
    -+<a href="{@docRoot}guide/practices/compatibility.html">Kompatibilitas Perangkat</a>.</p>
    -+
    -+
    -+
    -+<h2 id="Resources">Sumber Daya Aplikasi</h2>
    -+
    -+<p>Aplikasi Android tidak hanya terdiri dari kode&mdash;Aplikasi memerlukan sumber daya yang
    -+terpisah dari kode sumber, seperti gambar, file audio, dan apa saja yang berkaitan dengan
    -+presentasi visual dari aplikasi. Misalnya, Anda harus mendefinisikan animasi, menu, gaya, warna,
    -+dan layout antarmuka pengguna aktivitas dengan file XML. Penggunaan sumber daya aplikasi
    -+mempermudah pembaruan berbagai karakteristik aplikasi Anda tanpa memodifikasi kode dan&mdash;dengan menyediakan
    -+seperangkat sumber daya alternatif&mdash;memungkinkan Anda mengoptimalkan aplikasi untuk berbagai konfigurasi
    -+perangkat berbeda (seperti bahasa dan ukuran layar yang berbeda).</p>
    -+
    -+<p>Untuk setiap sumber daya yang Anda sertakan dalam proyek Android, alat bawaan SDK akan mendefinisikan ID integer
    -+unik, yang bisa Anda gunakan untuk mengacu sumber daya dari kode aplikasi atau dari sumber daya lainnya yang
    -+didefinisikan dalam XML. Misalnya, jika aplikasi berisi file gambar bernama {@code
    -+logo.png} (disimpan dalam direktori {@code res/drawable/}), alat SDK akan menghasilkan ID sumber daya
    -+bernama {@code R.drawable.logo}, yang bisa Anda gunakan untuk mengacu gambar dan memasukkannya dalam
    -+antarmuka pengguna.</p>
    -+
    -+<p>Salah satu aspek paling penting dari penyediaan sumber daya yang terpisah dari
    -+kode sumber adalah kemampuan Anda menyediakan sumber daya alternatif untuk konfigurasi perangkat
    -+yang berbeda. Misalnya, dengan mendefinisikan string UI dalam XML, Anda bisa menerjemahkan string ke dalam
    -+bahasa lain dan menyimpan string itu dalam file terpisah. Kemudian, berdasarkan <em>qualifier</em>
    -+bahasa yang ditambahkan ke nama direktori sumber daya (seperti {@code res/values-fr/} untuk nilai
    -+string Prancis) dan pengaturan bahasa pengguna, sistem Android akan menerapkan string bahasa yang sesuai
    -+untuk UI Anda.</p>
    -+
    -+<p>Android mendukung banyak <em>qualifier</em> berbeda untuk sumber daya alternatif Anda. Qualifier
    -+adalah string pendek yang Anda sertakan dalam nama direktori sumber
    -+daya untuk mendefinisikan konfigurasi perangkat yang harus digunakan sumber daya tersebut. Contoh lainnya,
    -+Anda harus sering membuat layout berbeda untuk aktivitas, bergantung pada
    -+orientasi layar dan ukuran perangkat. Misalnya, saat layar perangkat dalam orientasi
    -+tegak, Anda mungkin ingin layout tombolnya vertikal, tetapi saat layar dalam orientasi
    -+mendatar, tombolnya harus sejajar horizontal. Untuk mengubah layout
    -+sesuai orientasi, Anda bisa mendefinisikan dua layout berbeda dan menerapkan qualifier yang
    -+tepat untuk setiap nama direktori layout. Kemudian, sistem secara otomatis menerapkan
    -+layout yang tepat sesuai dengan orientasi perangkat saat ini.</p>
    -+
    -+<p>Untuk informasi selengkapnya tentang berbagai jenis sumber daya yang bisa disertakan dalam aplikasi dan cara
    -+membuat sumber daya alternatif untuk konfigurasi perangkat berbeda, bacalah <a href="{@docRoot}guide/topics/resources/providing-resources.html">Menyediakan Sumber Daya</a>.</p>
    -+
    -+
    -+
    -+<div class="next-docs">
    -+<div class="col-6">
    -+  <h2 class="norule">Teruskan membaca tentang:</h2>
    -+  <dl>
    -+    <dt><a href="{@docRoot}guide/components/intents-filters.html">Intent dan Filter Intent</a>
    -+    </dt>
    -+    <dd>Informasi tentang cara menggunakan API {@link android.content.Intent} untuk
    -+ mengaktifkan komponen aplikasi, seperti aktivitas dan layanan, dan cara menyediakan komponen aplikasi
    -+ untuk digunakan oleh aplikasi lain.</dd>
    -+    <dt><a href="{@docRoot}guide/components/activities.html">Aktivitas</a></dt>
    -+    <dd>Informasi tentang cara membuat instance kelas {@link android.app.Activity},
    -+yang menyediakan layar tersendiri dalam aplikasi bersama antarmuka pengguna.</dd>
    -+    <dt><a href="{@docRoot}guide/topics/resources/providing-resources.html">Menyediakan Sumber Daya</a></dt>
    -+    <dd>Informasi tentang cara aplikasi Android disusun untuk memisahkan sumber daya aplikasi dari
    -+kode aplikasi, termasuk cara Anda bisa menyediakan sumber daya alternatif untuk
    -+konfigurasi perangkat tertentu.
    -+    </dd>
    -+  </dl>
    -+</div>
    -+<div class="col-6">
    -+  <h2 class="norule">Anda juga mungkin tertarik dengan:</h2>
    -+  <dl>
    -+    <dt><a href="{@docRoot}guide/practices/compatibility.html">Kompatibilitas Perangkat</a></dt>
    -+    <dd>Informasi tentang cara kerja Android pada berbagai tipe perangkat dan
    -+pengenalan mengenai cara mengoptimalkan aplikasi untuk setiap perangkat atau membatasi ketersediaan aplikasi Anda untuk
    -+perangkat berbeda.</dd>
    -+    <dt><a href="{@docRoot}guide/topics/security/permissions.html">Izin Sistem</a></dt>
    -+    <dd>Informasi tentang cara Android membatasi akses aplikasi pada API tertentu dengan sistem izin
    -+yang mengharuskan persetujuan pengguna agar aplikasi dapat menggunakan API tersebut.</dd>
    -+  </dl>
    -+</div>
    -+</div>
    -+
    -diff --git a/docs/html-intl/intl/id/guide/components/index.jd b/docs/html-intl/intl/id/guide/components/index.jd
    -new file mode 100644
    -index 0000000..de40b22
    ---- /dev/null
    -+++ b/docs/html-intl/intl/id/guide/components/index.jd
    -@@ -0,0 +1,57 @@
    -+page.title=Komponen Aplikasi
    -+page.landing=true
    -+page.landing.intro=Kerangka kerja aplikasi Android memungkinkan Anda membuat aplikasi yang kaya dan inovatif menggunakan seperangkat komponen yang dapat digunakan kembali. Bagian ini menjelaskan cara membangun komponen yang mendefinisikan blok pembangun aplikasi Anda dan cara menghubungkannya bersama menggunakan intent.
    -+page.metaDescription=Kerangka kerja aplikasi Android memungkinkan Anda membuat aplikasi yang kaya dan inovatif menggunakan seperangkat komponen yang dapat digunakan kembali. Bagian ini menjelaskan cara membangun komponen yang mendefinisikan blok pembangun aplikasi Anda dan cara menghubungkannya bersama menggunakan intent.
    -+page.landing.image=images/develop/app_components.png
    -+page.image=images/develop/app_components.png
    -+
    -+@jd:body
    -+
    -+<div class="landing-docs">
    -+
    -+  <div class="col-6">
    -+    <h3>Artikel Blog</h3>
    -+
    -+    <a href="http://android-developers.blogspot.com/2012/05/using-dialogfragments.html">
    -+      <h4>Menggunakan DialogFragments</h4>
    -+      <p>Dalam posting ini, saya akan menunjukkan cara menggunakan DialogFragments dengan pustaka dukungan v4 (untuk kompatibilitas mundur pada perangkat sebelum Honeycomb) untuk menunjukkan dialog edit sederhana dan mengembalikan hasil ke Aktivitas pemanggil menggunakan antarmuka.</p>
    -+    </a>
    -+
    -+    <a href="http://android-developers.blogspot.com/2011/03/fragments-for-all.html">
    -+      <h4>Fragmen Untuk Semua</h4>
    -+      <p>Hari ini kami telah merilis pustaka statis yang memperlihatkan API Fragment yang sama (serta LoaderManager baru dan beberapa kelas lain) agar aplikasi yang kompatibel dengan Android 1.6 atau yang lebih baru bisa menggunakan fragmen untuk membuat antarmuka pengguna yang kompatibel dengan tablet. </p>
    -+    </a>
    -+
    -+    <a href="http://android-developers.blogspot.com/2010/07/multithreading-for-performance.html">
    -+      <h4>Multithreading untuk Kinerja</h4>
    -+      <p>Praktik yang baik dalam membuat aplikasi yang responsif adalah memastikan thread UI utama Anda
    -+melakukan pekerjaan minimum. Setiap tugas yang berpotensi lama dan dapat membuat aplikasi mogok harus
    -+ditangani di thread berbeda.</p>
    -+    </a>
    -+  </div>
    -+
    -+  <div class="col-6">
    -+    <h3>Pelatihan</h3>
    -+
    -+    <a href="http://developer.android.com/training/basics/activity-lifecycle/index.html">
    -+      <h4>Mengelola Daur Hidup Aktivitas</h4>
    -+      <p>Bagian ini menjelaskan pentingnya metode callback daur hidup yang diterima setiap instance Aktivitas
    -+dan cara menggunakannya sehingga aktivitas Anda melakukan yang diharapkan pengguna dan tidak menghabiskan sumber daya sistem
    -+saat aktivitas tidak membutuhkannya.</p>
    -+    </a>
    -+
    -+    <a href="http://developer.android.com/training/basics/fragments/index.html">
    -+      <h4>Membangun UI Dinamis dengan Fragmen</h4>
    -+      <p>Bagian ini menunjukkan kepada Anda cara membuat pengalaman pengguna yang dinamis dengan fragmen dan mengoptimalkan
    -+pengalaman pengguna aplikasi Anda dengan berbagai ukuran layar, sekaligus terus mendukung
    -+perangkat yang menjalankan versi sebelumnya, sesudah versi Android 1.6.</p>
    -+    </a>
    -+
    -+    <a href="http://developer.android.com/training/sharing/index.html">
    -+      <h4>Berbagi Konten</h4>
    -+      <p>Bagian ini membahas beberapa cara umum untuk mengirim dan menerima konten antar
    -+aplikasi menggunakan API Intent dan objek ActionProvider.</p>
    -+    </a>
    -+  </div>
    -+
    -+</div>
    -diff --git a/docs/html-intl/intl/id/guide/components/intents-filters.jd b/docs/html-intl/intl/id/guide/components/intents-filters.jd
    -new file mode 100644
    -index 0000000..8e89b5d
    ---- /dev/null
    -+++ b/docs/html-intl/intl/id/guide/components/intents-filters.jd
    -@@ -0,0 +1,899 @@
    -+page.title=Intent dan Filter Intent
    -+page.tags="IntentFilter"
    -+@jd:body
    -+
    -+<div id="qv-wrapper">
    -+<div id="qv">
    -+
    -+<h2>Dalam dokumen ini</h2>
    -+<ol>
    -+  <li><a href="#Types">Tipe Intent</a></li>
    -+  <li><a href="#Building">Membangun Intent</a>
    -+    <ol>
    -+      <li><a href="#ExampleExplicit">Contoh intent eksplisit</a></li>
    -+      <li><a href="#ExampleSend">Contoh intent implisit</a></li>
    -+      <li><a href="#ForceChooser">Memaksakan pemilih aplikasi</a></li>
    -+    </ol>
    -+  </li>
    -+  <li><a href="#Receiving">Menerima Intent Implisit</a>
    -+    <ol>
    -+      <li><a href="#ExampleFilters">Contoh filter</a></li>
    -+    </ol>
    -+  </li>
    -+  <li><a href="#PendingIntent">Menggunakan Intent Tertunda</a></li>
    -+  <li><a href="#Resolution">Resolusi Intent</a>
    -+    <ol>
    -+      <li><a href="#ActionTest">Pengujian tindakan</a></li>
    -+      <li><a href="#CategoryTest">Pengujian kategori</a></li>
    -+      <li><a href="#DataTest">Pengujian data</a></li>
    -+      <li><a href="#imatch">Pencocokan intent</a></li>
    -+    </ol>
    -+  </li>
    -+</ol>
    -+
    -+<h2>Lihat juga</h2>
    -+<ol>
    -+<li><a href="{@docRoot}training/basics/intents/index.html">Berinteraksi dengan Aplikasi Lain</a></li>
    -+<li><a href="{@docRoot}training/sharing/index.html">Berbagi Konten</a></li>
    -+</ol>
    -+
    -+</div>
    -+</div>
    -+
    -+
    -+
    -+
    -+<p>{@link android.content.Intent} merupakan objek pertukaran pesan yang bisa Anda gunakan untuk meminta tindakan
    -+dari <a href="{@docRoot}guide/components/fundamentals.html#Components">komponen aplikasi</a> lain.
    -+Walaupun intent memudahkan komunikasi antarkomponen dalam beberapa cara, ada tiga
    -+kasus-penggunaan dasar:</p>
    -+
    -+<ul>
    -+<li><b>Untuk memulai aktivitas:</b>
    -+<p>{@link android.app.Activity} menyatakan satu layar dalam aplikasi. Anda bisa memulai instance
    -+baru {@link android.app.Activity} dengan meneruskan {@link android.content.Intent}
    -+ke {@link android.content.Context#startActivity startActivity()}. {@link android.content.Intent}
    -+menjelaskan aktivitas yang akan dimulai dan membawa data yang diperlukan.</p>
    -+
    -+<p>Jika Anda ingin menerima hasil dari aktivitas bila selesai,
    -+panggil {@link android.app.Activity#startActivityForResult
    -+startActivityForResult()}. Aktivitas Anda menerima hasil
    -+sebagai objek {@link android.content.Intent} terpisah dalam callback {@link
    -+android.app.Activity#onActivityResult onActivityResult()} aktivitas Anda.
    -+Untuk informasi selengkapnya, lihat panduan <a href="{@docRoot}guide/components/activities.html">Aktivitas</a>.</p></li>
    -+
    -+<li><b>Untuk memulai layanan:</b>
    -+<p>{@link android.app.Service} adalah komponen yang melakukan operasi di latar belakang
    -+tanpa antarmuka pengguna. Anda bisa memulai layanan untuk melakukan operasi satu-kali
    -+(misalnya mengunduh file) dengan meneruskan {@link android.content.Intent}
    -+ke {@link android.content.Context#startService startService()}. {@link android.content.Intent}
    -+menjelaskan layanan yang akan dimulai dan membawa data yang diperlukan.</p>
    -+
    -+<p>Jika layanan didesain dengan antarmuka pengguna klien-server, Anda bisa mengikat ke layanan
    -+dari komponen lain dengan meneruskan {@link android.content.Intent} ke {@link
    -+android.content.Context#bindService bindService()}</code>. Untuk informasi selengkapnya, lihat panduan <a href="{@docRoot}guide/components/services.html">Layanan</a>.</p></li>
    -+
    -+<li><b>Untuk mengirim siaran:</b>
    -+<p>Siaran adalah pesan yang bisa diterima aplikasi apa saja. Sistem menyampaikan beragam siaran
    -+untuk kejadian sistem, misalnya saat sistem booting atau saat perangkat mulai mengisi daya.
    -+Anda bisa mengirim siaran ke aplikasi lain dengan meneruskan {@link android.content.Intent}
    -+ke {@link android.content.Context#sendBroadcast(Intent) sendBroadcast()},
    -+{@link android.content.Context#sendOrderedBroadcast(Intent, String)
    -+sendOrderedBroadcast()}, atau {@link
    -+android.content.Context#sendStickyBroadcast sendStickyBroadcast()}.</p>
    -+</li>
    -+</ul>
    -+
    -+
    -+
    -+
    -+<h2 id="Types">Tipe Intent</h2>
    -+
    -+<p>Ada dua tipe intent:</p>
    -+
    -+<ul>
    -+<li><b>Intent eksplisit</b> menetapkan komponen untuk memulai dengan nama (
    -+nama kelas yang sepenuhnya memenuhi syarat). Anda biasanya akan menggunakan intent eksplisit untuk memulai sebuah komponen
    -+dalam aplikasi sendiri, karena Anda mengetahui nama kelas dari aktivitas atau layanan yang ingin dimulai.
    -+Misalnya, mulai aktivitas baru sebagai respons terhadap tindakan pengguna atau mulai layanan untuk mengunduh
    -+file di latar belakang.</li>
    -+
    -+<li><b>Intent implisit</b> tidak menetapkan komponen tertentu, melainkan mendeklarasikan tindakan umum
    -+yang dilakukan, yang memungkinkan komponen aplikasi lain untuk menanganinya. Misalnya, jika Anda ingin
    -+menampilkan sebuah lokasi di peta pada pengguna, Anda bisa menggunakan intent implisit untuk meminta aplikasi lain
    -+yang mampu untuk menunjukkan lokasi yang telah ditetapkan di peta tersebut.</li>
    -+</ul>
    -+
    -+<p>Saat Anda membuat intent eksplisit untuk memulai aktivitas atau layanan, sistem akan segera
    -+memulai komponen aplikasi yang telah ditetapkan dalam objek {@link android.content.Intent}.</p>
    -+
    -+<div class="figure" style="width:446px">
    -+<img src="{@docRoot}images/components/intent-filters@2x.png" width="446" alt="" />
    -+<p class="img-caption"><strong>Gambar 1.</strong> Ilustrasi yang menggambarkan cara intent implisit
    -+disampaikan melalui sistem untuk memulai aktivitas lain: <b>[1]</b> <em>Aktivitas A</em> membuat sebuah
    -+{@link android.content.Intent} dengan keterangan tindakan dan meneruskannya ke {@link
    -+android.content.Context#startActivity startActivity()}. <b>[2]</b> Sistem Android akan mencari semua
    -+aplikasi untuk filter intent yang cocok dengan intent tersebut. Bila cocok, <b>[3]</b> sistem akan
    -+memulai aktivitas mencocokkan (<em>Aktivitas B</em>) dengan memanggil metode {@link
    -+android.app.Activity#onCreate onCreate()} dan meneruskannya ke {@link android.content.Intent}.
    -+</p>
    -+</div>
    -+
    -+<p>Bila Anda membuat intent implisit, sistem Android akan menemukan komponen yang sesuai untuk memulai
    -+dengan membandingkan konten intent dengan <em>filter intent</em> yang dideklarasikan dalam <a href="{@docRoot}guide/topics/manifest/manifest-intro.html">file manifes</a> aplikasi lain di
    -+perangkat. Jika intent cocok dengan filter intent, sistem akan memulai komponen tersebut dan mengiriminya
    -+objek {@link android.content.Intent}. Jika banyak filter intent yang kompatibel, sistem
    -+menampilkan dialog sehingga pengguna bisa memilih aplikasi yang akan digunakan.</p>
    -+
    -+<p>Filter intent adalah ekspresi dalam file manifes aplikasi yang
    -+menetapkan tipe intent yang akan diterima
    -+komponen. Misalnya, dengan mendeklarasikan intent filter untuk aktivitas,
    -+Anda akan memungkinkan aplikasi lain untuk langsung memulai aktivitas Anda dengan intent tertentu.
    -+Demikian pula, jika Anda <em>tidak</em> mendeklarasikan filter intent untuk suatu aktivitas, maka aktivitas tersebut hanya bisa dimulai
    -+dengan intent eksplisit.</p>
    -+
    -+<p class="caution"><strong>Perhatian:</strong> Untuk memastikan aplikasi Anda aman, selalu gunakan intent
    -+eksplisit saat memulai {@link android.app.Service} dan jangan
    -+mendeklarasikan filter intent untuk layanan. Menggunakan intent implisit untuk memulai layanan akan menimbulkan
    -+bahaya keamanan karena Anda tidak bisa memastikan layanan apa yang akan merespons intent,
    -+dan pengguna tidak bisa melihat layanan mana yang dimulai. Mulai dari Android 5.0 (API level 21), sistem
    -+melontarkan eksepsi jika Anda memanggil {@link android.content.Context#bindService bindService()}
    -+dengan intent implisit.</p>
    -+
    -+
    -+
    -+
    -+
    -+<h2 id="Building">Membangun Intent</h2>
    -+
    -+<p>Objek {@link android.content.Intent} membawa informasi yang digunakan sistem Android
    -+untuk menentukan komponen mana yang akan dimulai (misalnya nama persis dari suatu komponen atau kategori
    -+komponen yang seharusnya menerima intent), ditambah informasi yang digunakan komponen penerima untuk
    -+melakukan tindakan dengan benar (misalnya tindakan yang harus dilakukan dan data yang harus diolah).</p>
    -+
    -+
    -+<p>Informasi utama yang dimuat dalam {@link android.content.Intent} adalah sebagai berikut:</p>
    -+
    -+<dl>
    -+
    -+<dt><b>Nama komponen</b></dt>
    -+<dd>Nama komponen yang akan dimulai.
    -+
    -+<p>Ini opsional, namun merupakan bagian informasi penting yang membuat intent
    -+menjadi <b>eksplisit</b>, yaitu intent harus dikirim hanya ke komponen aplikasi
    -+yang didefinisikan oleh nama komponen. Tanpa nama komponen, intent menjadi <b>implisit</b> dan
    -+sistem akan memutuskan komponen mana yang harus menerima intent berdasarkan informasi intent lain
    -+(misalnya tindakan, data, dan kategori&mdash;yang dijelaskan di bawah ini). Jadi jika Anda ingin memulai komponen
    -+tertentu dalam aplikasi, Anda harus menetapkan nama komponen tersebut.</p>
    -+
    -+<p class="note"><strong>Catatan:</strong> Saat memulai {@link android.app.Service}, Anda harus
    -+<strong>selalu menetapkan nama komponen</strong>. Jika tidak, maka Anda tidak bisa memastikan layanan apa
    -+yang akan merespons intent tersebut, dan pengguna tidak bisa melihat layanan mana yang dimulai.</p>
    -+
    -+<p>Bidang {@link android.content.Intent} ini adalah objek
    -+{@link android.content.ComponentName}, yang bisa Anda tetapkan menggunakan
    -+nama kelas yang sepenuhnya memenuhi syarat dari komponen target, termasuk nama paket aplikasi. Misalnya,
    -+{@code com.example.ExampleActivity}. Anda bisa mengatur nama komponen dengan {@link
    -+android.content.Intent#setComponent setComponent()}, {@link android.content.Intent#setClass
    -+setClass()}, {@link android.content.Intent#setClassName(String, String) setClassName()}, atau dengan konstruktor
    -+{@link android.content.Intent}.</p>
    -+
    -+</dd>
    -+
    -+<p><dt><b>Tindakan</b></dt>
    -+<dd>String yang menetapkan tindakan generik untuk dilakukan (misalnya <em>lihat</em> atau <em>pilih</em>).
    -+
    -+<p>Dalam hal intent siaran, ini adalah tindakan yang terjadi dan dilaporkan.
    -+Tindakan ini sangat menentukan bagaimana keseluruhan intent disusun&mdash;terutama
    -+apa yang dimuat dalam data dan ekstra.
    -+
    -+<p>Anda bisa menetapkan tindakan sendiri yang akan digunakan oleh intent dalam aplikasi Anda (atau digunakan oleh aplikasi
    -+lain untuk memanggil komponen dalam aplikasi Anda), namun Anda harus menggunakan konstanta tindakan
    -+yang didefinisikan oleh kelas {@link android.content.Intent} atau kelas kerangka kerja lain. Berikut ini adalah beberapa
    -+tindakan umum untuk memulai sebuah aktivitas:</p>
    -+
    -+<dl>
    -+<dt>{@link android.content.Intent#ACTION_VIEW}</dt>
    -+   <dd>Gunakan tindakan ini dalam intent dengan {@link
    -+   android.content.Context#startActivity startActivity()} saat Anda memiliki beberapa informasi yang
    -+ bisa ditampilkan aktivitas kepada pengguna, misalnya foto yang bisa dilihat dalam aplikasi galeri, atau alamat
    -+ yang bisa dilihat dalam aplikasi peta.</dd>
    -+
    -+<dt>{@link android.content.Intent#ACTION_SEND}</dt>
    -+   <dd>Juga dikenal dengan intent "berbagi", Anda harus menggunakannya dalam intent dengan {@link
    -+   android.content.Context#startActivity startActivity()} bila Anda memiliki data yang bisa digunakan pengguna untuk
    -+ berbagi melalui aplikasi lain, misalnya aplikasi email atau aplikasi jaringan sosial.</dd>
    -+</dl>
    -+
    -+<p>Lihat referensi kelas {@link android.content.Intent} untuk konstanta
    -+selengkapnya yang mendefinisikan tindakan generik.  Tindakan lain yang didefinisikan
    -+di tempat lain dalam kerangka kerja Android, misalnya dalam {@link android.provider.Settings} untuk tindakan
    -+yang membuka layar tertentu dalam aplikasi Settings di sistem.</p>
    -+
    -+<p>Anda bisa menetapkan tindakan untuk sebuah intent dengan {@link android.content.Intent#setAction
    -+setAction()} atau dengan konstruktor {@link android.content.Intent}.</p>
    -+
    -+<p>Jika mendefinisikan tindakan Anda sendiri, pastikan untuk memasukkan nama paket aplikasi Anda
    -+sebagai awalan. Misalnya:</p>
    -+<pre>static final String ACTION_TIMETRAVEL = "com.example.action.TIMETRAVEL";</pre>
    -+</dd>
    -+
    -+<dt><b>Data</b></dt>
    -+<dd>URI (objek {@link android.net.Uri}) yang mengacu data untuk diolah dan/atau
    -+tipe MIME dari data tersebut. Tipe data yang disediakan umumnya didikte oleh tindakan intent.
    -+Misalnya, jika tindakan merupakan {@link android.content.Intent#ACTION_EDIT}, data harus berisi
    -+URI dari dokumen untuk diedit.
    -+
    -+<p>Saat membuat intent,
    -+seringkali tipe data (tipe MIME-nya) selain URI perlu ditetapkan.
    -+Misalnya, aktivitas yang mampu menampilkan gambar mungkin tidak mampu
    -+memutar file audio, walaupun format URI mungkin serupa.
    -+Jadi menetapkan tipe MIME data Anda akan membantu sistem
    -+Android menemukan komponen terbaik untuk diterima intent.
    -+Akan tetapi, tipe MIME seringkali bisa diambil dari URI&mdash;terutama saat datanya merupakan URI
    -+{@code content:}, yang menunjukkan data tersebut berada di perangkat dan dikontrol oleh
    -+{@link android.content.ContentProvider}, yang membuat data tipe MIME terlihat di sistem.</p>
    -+
    -+<p>Untuk mengatur data URI saja, panggil {@link android.content.Intent#setData setData()}.
    -+Untuk mengatur tipe MIME saja, panggil {@link android.content.Intent#setType setType()}. Jika perlu, Anda
    -+bisa mengatur keduanya secara eksplisit dengan {@link
    -+android.content.Intent#setDataAndType setDataAndType()}.</p>
    -+
    -+<p class="caution"><strong>Perhatian:</strong> Jika ingin mengatur tipe URI dan MIME,
    -+<strong>jangan</strong> panggil {@link android.content.Intent#setData setData()} dan
    -+{@link android.content.Intent#setType setType()} karena mereka saling menghapuskan nilai satu sama lain.
    -+Selalu gunakan {@link android.content.Intent#setDataAndType setDataAndType()} untuk mengatur
    -+tipe URI maupun MIME.</p>
    -+</dd>
    -+
    -+<p><dt><b>Kategori</b></dt>
    -+<dd>String yang berisi informasi tambahan tentang jenis komponen
    -+yang harus menangani intent.  Keterangan kategori dalam jumlah berapa pun bisa
    -+dimasukkan dalam intent, namun sebagian besar intent tidak memerlukan kategori.
    -+Berikut ini adalah beberapa kategori umum:
    -+
    -+<dl>
    -+<dt>{@link android.content.Intent#CATEGORY_BROWSABLE}</dt>
    -+  <dd>Aktivitas target memungkinkannya dimulai oleh browser web untuk menampilkan data
    -+yang diacu oleh tautan&mdash;misalnya gambar atau pesan e-mail.
    -+  </dd>
    -+<dt>{@link android.content.Intent#CATEGORY_LAUNCHER}</dt>
    -+  <dd>Aktivitas tersebut adalah aktivitas awal dari sebuah tugas dan dicantumkan dalam
    -+       launcher aplikasi sistem.
    -+  </dd>
    -+</dl>
    -+
    -+<p>Lihat keterangan kelas {@link android.content.Intent} untuk mengetahui daftar lengkap
    -+kategori.</p>
    -+
    -+<p>Anda bisa menetapkan kategori dengan {@link android.content.Intent#addCategory addCategory()}.</p>
    -+</dd>
    -+</dl>
    -+
    -+
    -+<p>Properti yang tercantum di atas (nama komponen, tindakan, data, dan kategori) menyatakan
    -+karakteristik yang mendefinisikan intent. Dengan membaca properti ini, sistem Android
    -+mampu memutuskan komponen aplikasi yang harus dimulainya.</p>
    -+
    -+<p>Akan tetapi, intent bisa membawa informasi tambahan yang tidak memengaruhi
    -+cara intent ditetapkan pada komponen aplikasi. Intent juga bisa menyediakan:</p>
    -+
    -+<dl>
    -+<dt><b>Ekstra</b></dt>
    -+<dd>Pasangan nilai-kunci yang membawa informasi yang diperlukan untuk menghasilkan tindakan yang diminta.
    -+Seperti halnya beberapa tindakan menggunakan jenis tertentu URI data, beberapa tindakan juga menggunakan ekstra tertentu.
    -+
    -+<p>Anda bisa menambahkan data ekstra dengan beragam metode {@link android.content.Intent#putExtra putExtra()},
    -+masing-masing menerima dua parameter: nama kunci dan nilainya.
    -+Anda juga bisa membuat objek {@link android.os.Bundle} dengan semua data ekstra, kemudian memasukkan
    -+{@link android.os.Bundle} dalam {@link android.content.Intent} dengan {@link
    -+android.content.Intent#putExtras putExtras()}.</p>
    -+
    -+<p>Misalnya, saat membuat intent yang akan dikirimkan bersama email
    -+{@link android.content.Intent#ACTION_SEND}, Anda bisa menetapkan penerima "kepada" dengan kunci
    -+{@link android.content.Intent#EXTRA_EMAIL}, dan menetapkan "subjek" dengan kunci
    -+{@link android.content.Intent#EXTRA_SUBJECT}.</p>
    -+
    -+<p>Kelas {@link android.content.Intent} menetapkan beberapa konstanta {@code EXTRA_*}
    -+untuk tipe data standar. Jika Anda ingin mendeklarasikan kunci ekstra sendiri (untuk intent yang
    -+diterima aplikasi Anda), pastikan untuk memasukkan nama paket aplikasi
    -+sebagai awalan. Misalnya:</p>
    -+<pre>static final String EXTRA_GIGAWATTS = "com.example.EXTRA_GIGAWATTS";</pre>
    -+</dd>
    -+
    -+<dt><b>Flag</b></dt>
    -+<dd>Flag didefinisikan dalam kelas {@link android.content.Intent} yang berfungsi sebagai metadata untuk
    -+intent. Flag menginstruksikan cara meluncurkan aktivitas (misalnya,
    -+<a href="{@docRoot}guide/components/tasks-and-back-stack.html">tugas</a> mana yang harus dimiliki suatu aktivitas
    -+) dan cara memperlakukannya setelah diluncurkan (misalnya, apakah aktivitas tersebut masuk ke dalam daftar aktivitas
    -+terbaru) pada sistem Android.
    -+
    -+<p>Untuk informasi selengkapnya, lihat metode {@link android.content.Intent#setFlags setFlags()} .</p>
    -+</dd>
    -+
    -+</dl>
    -+
    -+
    -+
    -+
    -+<h3 id="ExampleExplicit">Contoh intent eksplisit</h3>
    -+
    -+<p>Intent eksplisit adalah intent yang Anda gunakan untuk meluncurkan komponen aplikasi tertentu, seperti
    -+aktivitas tertentu atau layanan dalam aplikasi Anda. Untuk membuat intent eksplisit, definisikan
    -+nama komponen untuk objek {@link android.content.Intent} &mdash;semua
    -+properti intent lain bersifat opsional.</p>
    -+
    -+<p>Misalnya, jika Anda ingin membangun layanan dalam aplikasi Anda, bernama {@code DownloadService},
    -+yang didesain untuk mengunduh file dari web, Anda bisa memulainya dengan kode berikut ini:</p>
    -+
    -+<pre>
    -+// Executed in an Activity, so 'this' is the {@link android.content.Context}
    -+// The fileUrl is a string URL, such as "http://www.example.com/image.png"
    -+Intent downloadIntent = new Intent(this, DownloadService.class);
    -+downloadIntent.setData({@link android.net.Uri#parse Uri.parse}(fileUrl));
    -+startService(downloadIntent);
    -+</pre>
    -+
    -+<p>Konstruktor {@link android.content.Intent#Intent(Context,Class)}
    -+ menyediakan {@link android.content.Context} aplikasi dan
    -+objek {@link java.lang.Class} pada komponen. Dengan demikian,
    -+intent ini memulai secara eksplisit kelas {@code DownloadService} dalam aplikasi.</p>
    -+
    -+<p>Untuk informasi selengkapnya tentang membangun dan memulai layanan, lihat panduan
    -+<a href="{@docRoot}guide/components/services.html">Layanan</a>.</p>
    -+
    -+
    -+
    -+
    -+<h3 id="ExampleSend">Contoh intent implisit</h3>
    -+
    -+<p>Intent implisit menetapkan tindakan yang bisa memanggil aplikasi pada perangkat yang mampu
    -+melakukan tindakan. Menggunakan intent implisit berguna bila aplikasi Anda tidak bisa melakukan
    -+tindakan, namun aplikasi lain mungkin bisa melakukannya dan Anda ingin pengguna untuk memilih aplikasi mana yang ingin digunakan.</p>
    -+
    -+<p>Misalnya, jika memiliki konten yang Anda ingin agar pengguna berbagi konten itu dengan orang lain, buatlah intent
    -+dengan tindakan {@link android.content.Intent#ACTION_SEND}
    -+dan tambahkan ekstra yang menetapkan konten yang akan dibagikan. Bila Anda memanggil
    -+{@link android.content.Context#startActivity startActivity()} dengan intent tersebut, pengguna bisa
    -+memilih aplikasi yang akan digunakan untuk berbagi konten.</p>
    -+
    -+<p class="caution"><strong>Perhatian:</strong> Ada kemungkinan pengguna tidak memiliki <em>suatu</em>
    -+aplikasi yang menangani intent implisit yang Anda kirimkan ke {@link android.content.Context#startActivity
    -+startActivity()}. Jika itu terjadi, panggilan akan gagal dan aplikasi Anda akan crash. Untuk memeriksa
    -+apakah aktivitas bisa menerima intent, panggil {@link android.content.Intent#resolveActivity
    -+resolveActivity()} pada objek {@link android.content.Intent} Anda. Jika hasilnya bukan nol,
    -+berarti setidaknya ada satu aplikasi yang bisa menangani intent tersebut dan aman untuk memanggil
    -+{@link android.content.Context#startActivity startActivity()}. Jika hasilnya nol,
    -+Anda tidak boleh menggunakan intent tersebut dan, jika memungkinkan, Anda harus menonaktifkan fitur yang mengeluarkan
    -+intent tersebut.</p>
    -+
    -+
    -+<pre>
    -+// Create the text message with a string
    -+Intent sendIntent = new Intent();
    -+sendIntent.setAction(Intent.ACTION_SEND);
    -+sendIntent.putExtra(Intent.EXTRA_TEXT, textMessage);
    -+sendIntent.setType("text/plain");
    -+
    -+// Verify that the intent will resolve to an activity
    -+if (sendIntent.resolveActivity(getPackageManager()) != null) {
    -+    startActivity(sendIntent);
    -+}
    -+</pre>
    -+
    -+<p class="note"><strong>Catatan:</strong> Dalam hal ini, URI tidak digunakan, namun tipe data intent
    -+dideklarasikan untuk menetapkan konten yang dibawa oleh ekstra.</p>
    -+
    -+
    -+<p>Saat {@link android.content.Context#startActivity startActivity()} dipanggil, sistem akan
    -+memeriksa semua aplikasi yang terinstal untuk menentukan aplikasi mana yang bisa menangani intent jenis ini (
    -+intent dengan tindakan {@link android.content.Intent#ACTION_SEND} dan yang membawa data
    -+"teks/polos"). Jika hanya ada satu aplikasi yang bisa menanganinya, aplikasi tersebut akan langsung terbuka dan diberi
    -+intent tersebut. Jika banyak aktivitas menerima intent, sistem akan
    -+menampilkan dialog sehingga pengguna bisa memilih aplikasi mana yang digunakan.</p>
    -+
    -+
    -+<div class="figure" style="width:200px">
    -+  <img src="{@docRoot}images/training/basics/intent-chooser.png" alt="">
    -+  <p class="img-caption"><strong>Gambar 2.</strong> Dialog pemilih.</p>
    -+</div>
    -+
    -+<h3 id="ForceChooser">Memaksakan pemilih aplikasi</h3>
    -+
    -+<p>Bila ada lebih dari satu aplikasi yang merespons intent implisit Anda,
    -+pengguna bisa memilih aplikasi mana yang digunakan dan membuat aplikasi tersebut pilihan default untuk
    -+tindakan tersebut. Ini sangat membantu saat melakukan tindakan di mana pengguna
    -+mungkin ingin menggunakan aplikasi yang sama untuk seterusnya, seperti saat membuka halaman web (pengguna
    -+biasanya memilih hanya satu browser web).</p>
    -+
    -+<p>Akan tetapi, jika ada banyak aplikasi yang bisa merespons intent tersebut dan pengguna mungkin ingin menggunakan aplikasi
    -+yang berbeda untuk setiap kalinya, Anda harus menampilkan dialog pemilih secara eksplisit. Dialog pemilih akan meminta
    -+pengguna memilih aplikasi yang akan digunakan untuk tindakan tertentu setiap kali (pengguna tidak bisa memilih aplikasi default untuk
    -+tindakan tersebut). Misalnya, saat aplikasi Anda melakukan "berbagi" dengan tindakan {@link
    -+android.content.Intent#ACTION_SEND}, pengguna mungkin ingin berbagi menggunakan aplikasi berbeda sesuai
    -+dengan situasi mereka saat itu, jadi Anda harus selalu menggunakan dialog pemilih, seperti yang ditampilkan dalam gambar 2.</p>
    -+
    -+
    -+
    -+
    -+<p>Untuk menampilkan pemilih, buatlah {@link android.content.Intent} menggunakan {@link
    -+android.content.Intent#createChooser createChooser()} dan teruskan ke {@link
    -+android.app.Activity#startActivity startActivity()}. Misalnya:</p>
    -+
    -+<pre>
    -+Intent sendIntent = new Intent(Intent.ACTION_SEND);
    -+...
    -+
    -+// Always use string resources for UI text.
    -+// This says something like "Share this photo with"
    -+String title = getResources().getString(R.string.chooser_title);
    -+// Create intent to show the chooser dialog
    -+Intent chooser = Intent.createChooser(sendIntent, title);
    -+
    -+// Verify the original intent will resolve to at least one activity
    -+if (sendIntent.resolveActivity(getPackageManager()) != null) {
    -+    startActivity(chooser);
    -+}
    -+</pre>
    -+
    -+<p>Ini menampilkan dialog dengan daftar aplikasi yang merespons intent yang diteruskan ke metode {@link
    -+android.content.Intent#createChooser createChooser()} dan menggunakan teks yang disediakan sebagai
    -+judul dialog.</p>
    -+
    -+
    -+
    -+
    -+
    -+
    -+
    -+
    -+
    -+<h2 id="Receiving">Menerima Intent Implisit</h2>
    -+
    -+<p>Untuk mengiklankan intent implisit yang bisa diterima aplikasi Anda, deklarasikan satu atau beberapa filter intent untuk
    -+tiap komponen aplikasi dengan elemen <a href="{@docRoot}guide/topics/manifest/intent-filter-element.html">{@code &lt;intent-filter&gt;}</a>
    -+dalam <a href="{@docRoot}guide/topics/manifest/manifest-intro.html">file manifes</a> Anda.
    -+Tiap filter intent menetapkan tipe intent yang diterimanya berdasarkan tindakan intent,
    -+data, dan kategori. Sistem akan mengirim intent implisit ke komponen aplikasi Anda hanya jika
    -+intent tersebut bisa diteruskan melalui salah satu filter intent.</p>
    -+
    -+<p class="note"><strong>Catatan:</strong> Intent eksplisit selalu dikirimkan ke targetnya,
    -+apa pun filter intent yang dideklarasikan komponen.</p>
    -+
    -+<p>Komponen aplikasi harus mendeklarasikan filter terpisah untuk setiap pekerjaan unik yang bisa dilakukannya.
    -+Misalnya, satu aktivitas dalam aplikasi galeri gambar bisa memiliki dua filter: satu filter
    -+untuk melihat gambar, dan filter lainnya untuk mengedit gambar. Bila aktivitas dimulai,
    -+aktivitas akan memeriksa {@link android.content.Intent} dan menentukan cara berperilaku berdasarkan informasi
    -+dalam {@link android.content.Intent} (misalnya menampilkan kontrol editor atau tidak).</p>
    -+
    -+<p>Tiap filter intent didefinisikan oleh elemen <a href="{@docRoot}guide/topics/manifest/intent-filter-element.html">{@code &lt;intent-filter&gt;}</a>
    -+dalam file manifes aplikasi, yang tersarang dalam komponen aplikasi terkait (seperti
    -+elemen <a href="{@docRoot}guide/topics/manifest/activity-element.html">{@code &lt;activity&gt;}</a>
    -+). Di dalam <a href="{@docRoot}guide/topics/manifest/intent-filter-element.html">{@code &lt;intent-filter&gt;}</a>,
    -+Anda bisa menetapkan tipe intent yang akan diterima dengan menggunakan salah satu atau beberapa
    -+dari tiga elemen ini:</p>
    -+
    -+<dl>
    -+<dt><a href="{@docRoot}guide/topics/manifest/action-element.html">{@code &lt;action&gt;}</a></dt>
    -+  <dd>Mendeklarasikan tindakan intent yang diterima, dalam atribut {@code name}. Nilai
    -+  haruslah nilai string literal dari tindakan, bukan konstanta kelas.</dd>
    -+<dt><a href="{@docRoot}guide/topics/manifest/data-element.html">{@code &lt;data&gt;}</a></dt>
    -+  <dd>Mendeklarasikan tipe data yang diterima, menggunakan salah satu atau beberapa atribut yang menetapkan beragam
    -+  aspek URI data (<code>scheme</code>, <code>host</code>, <code>port</code>,
    -+  <code>path</code>, dll.) dan tipe MIME.</dd>
    -+<dt><a href="{@docRoot}guide/topics/manifest/category-element.html">{@code &lt;category&gt;}</a></dt>
    -+  <dd>Mendeklarasikan kategori intent yang diterima, dalam atribut {@code name}. Nilai
    -+  haruslah nilai string literal dari tindakan, bukan konstanta kelas.
    -+
    -+  <p class="note"><strong>Catatan:</strong> Untuk menerima intent implisit, Anda
    -+  <strong>harus menyertakan</strong> kategori
    -+{@link android.content.Intent#CATEGORY_DEFAULT} dalam filter intent. Metode
    -+  {@link android.app.Activity#startActivity startActivity()}dan
    -+  {@link android.app.Activity#startActivityForResult startActivityForResult()} memperlakukan semua intent
    -+  seolah-olah mendeklarasikan kategori {@link android.content.Intent#CATEGORY_DEFAULT}.
    -+  Jika tidak mendeklarasikan kategori ini dalam filter intent Anda, tidak ada intent implisit yang ditetapkan untuk
    -+ aktivitas Anda.</p>
    -+  </dd>
    -+</dl>
    -+
    -+<p>Misalnya, ini adalah deklarasi aktivitas dengan filter intent yang diterima intent
    -+{@link android.content.Intent#ACTION_SEND} bila tipe data berupa teks:</p>
    -+
    -+<pre>
    -+&lt;activity android:name="ShareActivity">
    -+    &lt;intent-filter>
    -+        &lt;action android:name="android.intent.action.SEND"/>
    -+        &lt;category android:name="android.intent.category.DEFAULT"/>
    -+        &lt;data android:mimeType="text/plain"/>
    -+    &lt;/intent-filter>
    -+&lt;/activity>
    -+</pre>
    -+
    -+<p>Anda bisa membuat filter yang menyertakan lebih dari satu instance
    -+<a href="{@docRoot}guide/topics/manifest/action-element.html">{@code &lt;action&gt;}</a>,
    -+<a href="{@docRoot}guide/topics/manifest/data-element.html">{@code &lt;data&gt;}</a>, atau
    -+<a href="{@docRoot}guide/topics/manifest/category-element.html">{@code &lt;category&gt;}</a>.
    -+Jika Anda melakukannya, Anda hanya perlu memastikan bahwa komponen bisa menangani semua kombinasi
    -+elemen filter tersebut.</p>
    -+
    -+<p>Bila ingin menangani beragam jenis intent, namun hanya dalam kombinasi
    -+tindakan, data, dan tipe kategori tertentu, maka Anda harus membuat banyak filter intent.</p>
    -+
    -+
    -+<div class="sidebox-wrapper">
    -+<div class="sidebox">
    -+<h2>Membatasi akses ke komponen</h2>
    -+<p>Menggunakan filter intent bukanlah cara yang aman untuk mencegah aplikasi lain memulai
    -+komponen Anda. Walaupun filter intent membatasi komponen agar hanya merespons
    -+jenis intent implisit tertentu, aplikasi lain bisa saja memulai komponen aplikasi Anda
    -+dengan menggunakan intent eksplisit jika pengembangnya menentukan nama komponen Anda.
    -+Jika perlu <em>hanya aplikasi Anda sendiri</em> yang mampu memulai salah satu komponen,
    -+atur atribut <a href="{@docRoot}guide/topics/manifest/activity-element.html#exported">{@code
    -+exported}</a> ke {@code "false"} untuk komponen itu.
    -+</p>
    -+</div>
    -+</div>
    -+
    -+<p>Intent implisit diuji terhadap filter dengan membandingkan intent dengan masing-masing
    -+dari ketiga elemen. Agar dikirim ke komponen, intent harus lolos ketiga pengujian tersebut.
    -+Jika intent gagal dalam salah satu pengujian, sistem Android tidak akan mengirim intent ke
    -+komponen.  Akan tetapi, karena sebuah komponen dapat memiliki beberapa filter intent, intent yang tidak
    -+lolos melalui salah satu filter komponen mungkin akan lolos di filter lain.
    -+Informasi selengkapnya tentang cara sistem menetapkan intent disediakan dalam bagian di bawah ini
    -+tentang <a href="#Resolution">Resolusi Intent</a>.</p>
    -+
    -+<p class="caution"><strong>Perhatian:</strong> Untuk menghindari menjalankan
    -+{@link android.app.Service} aplikasi yang berbeda secara tidak sengaja, selalu gunakan intent eksplisit untuk memulai layanan Anda sendiri dan jangan
    -+deklarasikan filter intent untuk layanan Anda.</p>
    -+
    -+<p class="note"><strong>Catatan:</strong>
    -+Untuk semua aktivitas, Anda harus mendeklarasikan filter intent dalam file manifes.
    -+Akan tetapi, filter untuk penerima siaran bisa didaftarkan secara dinamis dengan memanggil
    -+{@link android.content.Context#registerReceiver(BroadcastReceiver, IntentFilter, String,
    -+Handler) registerReceiver()}. Anda nanti bisa mencabut pendaftaran penerima dengan {@link
    -+android.content.Context#unregisterReceiver unregisterReceiver()}. Dengan begitu aplikasi Anda
    -+bisa mendengarkan siaran tertentu hanya selama periode waktu yang telah ditetapkan saat aplikasi Anda
    -+berjalan.</p>
    -+
    -+
    -+
    -+
    -+
    -+
    -+
    -+<h3 id="ExampleFilters">Contoh filter</h3>
    -+
    -+<p>Untuk lebih memahami beberapa perilaku filter intent, lihatlah cuplikan berikut
    -+dari file manifes aplikasi berbagi di jaringan sosial.</p>
    -+
    -+<pre>
    -+&lt;activity android:name="MainActivity">
    -+    &lt;!-- This activity is the main entry, should appear in app launcher -->
    -+    &lt;intent-filter>
    -+        &lt;action android:name="android.intent.action.MAIN" />
    -+        &lt;category android:name="android.intent.category.LAUNCHER" />
    -+    &lt;/intent-filter>
    -+&lt;/activity>
    -+
    -+&lt;activity android:name="ShareActivity">
    -+    &lt;!-- This activity handles "SEND" actions with text data -->
    -+    &lt;intent-filter&gt;
    -+        &lt;action android:name="android.intent.action.SEND"/>
    -+        &lt;category android:name="android.intent.category.DEFAULT"/>
    -+        &lt;data android:mimeType="text/plain"/>
    -+    &lt;/intent-filter&gt;
    -+    &lt;!-- This activity also handles "SEND" and "SEND_MULTIPLE" with media data -->
    -+    &lt;intent-filter&gt;
    -+        &lt;action android:name="android.intent.action.SEND"/>
    -+        &lt;action android:name="android.intent.action.SEND_MULTIPLE"/>
    -+        &lt;category android:name="android.intent.category.DEFAULT"/>
    -+        &lt;data android:mimeType="application/vnd.google.panorama360+jpg"/>
    -+        &lt;data android:mimeType="image/*"/>
    -+        &lt;data android:mimeType="video/*"/>
    -+    &lt;/intent-filter&gt;
    -+&lt;/activity&gt;
    -+</pre>
    -+
    -+<p>Aktivitas pertama, {@code MainActivity}, merupakan titik masuk utama aplikasi&mdash;aplikasi yang
    -+terbuka saat pengguna meluncurkan aplikasi dengan ikon launcher:</p>
    -+<ul>
    -+  <li>Tindakan {@link android.content.Intent#ACTION_MAIN}
    -+  menunjukkan ini adalah titik masuk utama dan tidak mengharapkan data intent apa pun.</li>
    -+  <li>Kategori {@link android.content.Intent#CATEGORY_LAUNCHER} menunjukjkan bahwa ikon
    -+  aktivitas ini harus ditempatkan dalam launcher aplikasi sistem. Jika elemen <a href="{@docRoot}guide/topics/manifest/activity-element.html">{@code &lt;activity&gt;}</a>
    -+  tidak menetapkan ikon dengan{@code icon}, maka sistem akan menggunakan ikon dari elemen
    -+<a href="{@docRoot}guide/topics/manifest/application-element.html">{@code &lt;application&gt;}</a>.</li>
    -+</ul>
    -+<p>Keduanya harus dipasangkan bersama agar aktivitas muncul dalam launcher aplikasi.</p>
    -+
    -+<p>Aktivitas kedua, {@code ShareActivity}, dimaksudkan untuk memudahkan berbagi teks dan konten
    -+media. Walaupun pengguna mungkin memasuki aktivitas ini dengan mengarah ke aktivitas dari {@code MainActivity},
    -+pengguna juga bisa memasukkan {@code ShareActivity} secara langsung dari aplikasi lain yang mengeluarkan intent
    -+implisit yang cocok dengan salah satu dari kedua filter intent.</p>
    -+
    -+<p class="note"><strong>Catatan:</strong> Tipe MIME,
    -+<a href="https://developers.google.com/panorama/android/">{@code
    -+application/vnd.google.panorama360+jpg}</a>, merupakan tipe data khusus yang menetapkan
    -+foto panorama, yang bisa Anda tangani dengan API <a href="{@docRoot}reference/com/google/android/gms/panorama/package-summary.html">panorama
    -+Google</a>.</p>
    -+
    -+
    -+
    -+
    -+
    -+
    -+
    -+
    -+
    -+
    -+
    -+
    -+
    -+<h2 id="PendingIntent">Menggunakan Intent Tertunda</h2>
    -+
    -+<p>Objek {@link android.app.PendingIntent} merupakan pembungkus objek {@link
    -+android.content.Intent}. Tujuan utama {@link android.app.PendingIntent}
    -+adalah memberikan izin pada aplikasi asing
    -+untuk menggunakan {@link android.content.Intent} yang termuat seolah-olah dieksekusi dari
    -+proses aplikasi Anda sendiri.</p>
    -+
    -+<p>Kasus penggunaan utama untuk intent tertunda antara lain:</p>
    -+<ul>
    -+  <li>Mendeklarasikan intent untuk dieksekusi saat pengguna melakukan tindakan dengan <a href="{@docRoot}guide/topics/ui/notifiers/notifications.html">Pemberitahuan</a>
    -+  ({@link android.app.NotificationManager}
    -+  sistem Android akan mengeksekusi {@link android.content.Intent}) Anda.
    -+  <li>Mendeklarasikan intent untuk dieksekusi saat pengguna melakukan tindakan dengan
    -+<a href="{@docRoot}guide/topics/appwidgets/index.html">App Widget</a>
    -+  (aplikasi layar Home mengeksekusi {@link android.content.Intent}).
    -+  <li>Mendeklarasikan intent untuk dieksekusi di waktu yang telah ditetapkan di masa mendatang
    -+({@link android.app.AlarmManager}  sistem Android akan mengeksekusi {@link android.content.Intent}).
    -+</ul>
    -+
    -+<p>Karena setiap objek {@link android.content.Intent} didesain untuk ditangani oleh tipe
    -+tertentu dari komponen aplikasi (baik {@link android.app.Activity}, {@link android.app.Service}, maupun
    -+ {@link android.content.BroadcastReceiver}), jadi {@link android.app.PendingIntent} harus
    -+dibuat dengan pertimbangan yang sama. Saat menggunakan intent tertunda, aplikasi Anda tidak akan
    -+mengeksekusi intent dengan panggilan seperti {@link android.content.Context#startActivity
    -+startActivity()}. Anda harus mendeklarasikan tipe komponen yang dimaksud saat membuat
    -+{@link android.app.PendingIntent} dengan memanggil metode kreator masing-masing:</p>
    -+
    -+<ul>
    -+  <li>{@link android.app.PendingIntent#getActivity PendingIntent.getActivity()} untuk
    -+  {@link android.content.Intent} yang memulai {@link android.app.Activity}.</li>
    -+  <li>{@link android.app.PendingIntent#getService PendingIntent.getService()} untuk
    -+  {@link android.content.Intent} yang memulai {@link android.app.Service}.</li>
    -+  <li>{@link android.app.PendingIntent#getBroadcast PendingIntent.getBroadcast()} untuk
    -+  {@link android.content.Intent} yang memulai {@link android.content.BroadcastReceiver}.</li>
    -+</ul>
    -+
    -+<p>Kecuali jika aplikasi Anda <em>menerima</em> intent tertunda dari aplikasi lain,
    -+metode di atas untuk membuat {@link android.app.PendingIntent} menjadi satu-satunya metode
    -+{@link android.app.PendingIntent} yang mungkin Anda butuhkan.</p>
    -+
    -+<p>Tiap metode mengambil {@link android.content.Context} aplikasi saat itu,
    -+{@link android.content.Intent} yang ingin Anda bungkus, dan satu atau beberapa flag yang menetapkan
    -+cara penggunaan intent (misalnya apakah intent bisa digunakan lebih dari sekali).</p>
    -+
    -+<p>Informasi selengkapnya tentang intent tertunda disediakan pada dokumentasi untuk setiap
    -+kasus penggunaan yang bersangkutan, seperti dalam panduan API <a href="{@docRoot}guide/topics/ui/notifiers/notifications.html">Notifications</a>
    -+dan <a href="{@docRoot}guide/topics/appwidgets/index.html">App Widgets</a>.</p>
    -+
    -+
    -+
    -+
    -+
    -+
    -+
    -+<h2 id="Resolution">Resolusi Intent</h2>
    -+
    -+
    -+<p>Saat sistem menerima intent implisit yang memulai suatu aktivitas, sistem tersebut akan mencari
    -+aktivitas terbaik untuk intent dengan membandingkan intent dengan filter intent berdasarkan tiga aspek:</p>
    -+
    -+<ul>
    -+  <li>Tindakan intent
    -+  <li>Data intent (baik URI maupun tipe data)
    -+  <li>Kategori intent
    -+</ul>
    -+
    -+<p>Bagian berikut menjelaskan cara pencocokan intent dengan komponen yang sesuai
    -+sehubungan dengan cara pendeklarasian filter intent dalam file manifes aplikasi.</p>
    -+
    -+
    -+<h3 id="ActionTest">Pengujian tindakan</h3>
    -+
    -+<p>Untuk menetapkan tindakan intent yang diterima, filter intent bisa mendeklarasikan nol atau beberapa elemen
    -+<a href="{@docRoot}guide/topics/manifest/action-element.html">{@code
    -+&lt;action&gt;}</a>.  Misalnya:</p>
    -+
    -+<pre>
    -+&lt;intent-filter&gt;
    -+    &lt;action android:name="android.intent.action.EDIT" /&gt;
    -+    &lt;action android:name="android.intent.action.VIEW" /&gt;
    -+    ...
    -+&lt;/intent-filter&gt;
    -+</pre>
    -+
    -+<p>Untuk melewati filter ini, tindakan yang ditetapkan dalam {@link android.content.Intent}
    -+harus sesuai dengan salah satu tindakan yang tercantum dalam filter.</p>
    -+
    -+<p>Jika filter tidak mencantumkan tindakan apa pun, maka tidak ada intent
    -+yang dicocokkan, jadi semua intent gagal dalam pengujian. Akan tetapi, jika sebuah {@link android.content.Intent}
    -+tidak menetapkan suatu tindakan, maka akan lolos pengujian (asalkan filter
    -+berisi setidaknya satu tindakan).</p>
    -+
    -+
    -+
    -+<h3 id="CategoryTest">Pengujian kategori</h3>
    -+
    -+<p>Untuk menetapkan kategori intent yang diterima, filter intent bisa mendeklarasikan nol atau beberapa elemen
    -+<a href="{@docRoot}guide/topics/manifest/category-element.html">{@code
    -+&lt;category&gt;}</a>.  Misalnya:</p>
    -+
    -+<pre>
    -+&lt;intent-filter&gt;
    -+    &lt;category android:name="android.intent.category.DEFAULT" /&gt;
    -+    &lt;category android:name="android.intent.category.BROWSABLE" /&gt;
    -+    ...
    -+&lt;/intent-filter&gt;
    -+</pre>
    -+
    -+<p>Agar intent bisa lolos pengujian kategori, setiap kategori dalam {@link android.content.Intent}
    -+harus sesuai dengan kategori dalam filter. Kebalikannya tidak diperlukan&mdash;filter intent bisa
    -+mendeklarasikan kategori lebih banyak daripada yang ditetapkan dalam {@link android.content.Intent} dan
    -+{@link android.content.Intent} tetap akan lolos. Oleh karena itu, intent tanpa kategori harus
    -+selalu lolos pengujian ini, kategori apa pun yang dideklarasikan dalam filter.</p>
    -+
    -+<p class="note"><strong>Catatan:</strong>
    -+Android secara otomatis menerapkan kategori {@link android.content.Intent#CATEGORY_DEFAULT}
    -+untuk semua intent implisit yang diteruskan ke {@link
    -+android.content.Context#startActivity startActivity()} dan {@link
    -+android.app.Activity#startActivityForResult startActivityForResult()}.
    -+Jadi jika ingin aktivitas Anda menerima intent implisit, aktivitas tersebut harus
    -+menyertakan kategori untuk{@code "android.intent.category.DEFAULT"} dalam filter intent (seperti
    -+yang ditampilkan dalam contoh{@code &lt;intent-filter&gt;} sebelumnya.</p>
    -+
    -+
    -+
    -+<h3 id="DataTest">Pengujian data</h3>
    -+
    -+<p>Untuk menetapkan data intent yang diterima, filter intent bisa mendeklarasikan nol atau beberapa elemen
    -+<a href="{@docRoot}guide/topics/manifest/data-element.html">{@code
    -+&lt;data&gt;}</a>.  Misalnya:</p>
    -+
    -+<pre>
    -+&lt;intent-filter&gt;
    -+    &lt;data android:mimeType="video/mpeg" android:scheme="http" ... /&gt;
    -+    &lt;data android:mimeType="audio/mpeg" android:scheme="http" ... /&gt;
    -+    ...
    -+&lt;/intent-filter&gt;
    -+</pre>
    -+
    -+<p>Tiap elemen <code><a href="{@docRoot}guide/topics/manifest/data-element.html">&lt;data&gt;</a></code>
    -+bisa menetapkan struktur URI dan tipe data (tipe media MIME).  Ada atribut
    -+terpisah &mdash; {@code scheme}, {@code host}, {@code port},
    -+dan {@code path} &mdash; untuk setiap bagian URI:
    -+</p>
    -+
    -+<p style="margin-left: 2em">{@code &lt;scheme&gt;://&lt;host&gt;:&lt;port&gt;/&lt;path&gt;}</p>
    -+
    -+<p>
    -+Misalnya:
    -+</p>
    -+
    -+<p style="margin-left: 2em">{@code content://com.example.project:200/folder/subfolder/etc}</p>
    -+
    -+<p>Dalam URI ini, skemanya adalah {@code content}, host-nya adalah {@code com.example.project},
    -+port-nya adalah {@code 200}, dan path-nya adalah {@code folder/subfolder/etc}.
    -+</p>
    -+
    -+<p>Tiap atribut bersifat opsional dalam elemen <a href="{@docRoot}guide/topics/manifest/data-element.html">{@code &lt;data&gt;}</a>,
    -+namun ada dependensi linear:</p>
    -+<ul>
    -+  <li>Jika skema tidak ditetapkan, host akan diabaikan.</li>
    -+  <li>Jika host tidak ditetapkan, port akan diabaikan.</li>
    -+  <li>Jika skema dan host tidak ditetapkan, path akan diabaikan.</li>
    -+</ul>
    -+
    -+<p>Bila URI dalam intent dibandingkan dengan spesifikasi URI dalam filter,
    -+pembandingannya hanya dengan bagian URI yang disertakan dalam filter. Misalnya:</p>
    -+<ul>
    -+  <li>Jika sebuah filter menetapkan hanya satu skema, semua URI dengan skema tersebut akan cocok
    -+dengan filter.</li>
    -+  <li>Jika sebuah filter menetapkan satu skema dan satu otoritas namun tanpa path, semua URI
    -+dengan skema dan otoritas yang sama akan lolos dari filter, apa pun path-nya.</li>
    -+  <li>Jika sebuah filter menetapkan satu skema, otoritas dan path, hanya URI dengan skema,
    -+otoritas, dan path sama yang bisa lolos dari filter.</li>
    -+</ul>
    -+
    -+<p class="note"><strong>Catatan:</strong> Spesifikasi path bisa berisi
    -+wildcard bintang (*) untuk hanya mencocokkan nama path secara parsial.</p>
    -+
    -+<p>Pengujian data membandingkan URI maupun tipe MIME dalam intent dengan URI
    -+dan tipe MIME yang ditetapkan dalam filter.  Aturannya adalah sebagai berikut:
    -+</p>
    -+
    -+<ol type="a">
    -+<li>Intent yang tidak berisi URI maupun tipe MIME hanya akan lolos
    -+pengujian jika filter tersebut tidak menetapkan URI atau tipe MIME apa pun.</li>
    -+
    -+<li>Intent yang berisi URI namun tidak berisi tipe MIME (baik secara eksplisit maupun tidak langsung dari
    -+URI) hanya akan lolos pengujian jika URI-nya cocok dengan format URI filter
    -+dan filternya juga tidak menetapkan tipe MIME.</li>
    -+
    -+<li>Intent yang berisi tipe MIME namun tidak berisi URI hanya akan lolos pengujian
    -+jika filter mencantumkan tipe MIME yang sama dan tidak menetapkan format URI.</li>
    -+
    -+<li>Intent yang berisi URI maupun tipe MIME (baik secara eksplisit maupun tidak langsung dari
    -+URI) hanya akan lolos pengujian bagian tipe MIME jika
    -+tipe tersebut cocok dengan tipe yang dicantumkan dalam filter.  Ini akan lolos pengujian bagian URI
    -+jika URI-nya cocok dengan URI dalam filter atau memiliki {@code content:}
    -+atau URI {@code file:} dan filter tidak menetapkan URI. Dengan kata lain,
    -+komponen dianggap mendukung data {@code content:} dan {@code file:} jika
    -+filternya <em>hanya</em> mencantumkan tipe MIME.</p></li>
    -+</ol>
    -+
    -+<p>
    -+Aturan terakhir ini, aturan (d), mencerminkan harapan
    -+bahwa komponen mampu mendapatkan data lokal dari file atau penyedia konten.
    -+Oleh karena itu, filter mereka mencatumkan tipe data saja dan tidak secara eksplisit
    -+harus menamai skema {@code content:} dan {@code file:}.
    -+Ini adalah kasus umum.  Elemen <a href="{@docRoot}guide/topics/manifest/data-element.html">{@code &lt;data&gt;}</a>
    -+seperti berikut ini, misalnya, memberi tahu Android bahwa komponen bisa mengambil data gambar dari penyedia
    -+konten dan menampilkannya:
    -+</p>
    -+
    -+<pre>
    -+&lt;intent-filter&gt;
    -+    &lt;data android:mimeType="image/*" /&gt;
    -+    ...
    -+&lt;/intent-filter&gt;</pre>
    -+
    -+<p>
    -+Karena sebagian besar data yang tersedia dikeluarkan oleh penyedia konten, filter yang
    -+menetapkan tipe data namun bukan URI mungkin adalah yang paling umum.
    -+</p>
    -+
    -+<p>
    -+Konfigurasi umum yang lain adalah filter dengan skema dan tipe data.  Misalnya
    -+, elemen <a href="{@docRoot}guide/topics/manifest/data-element.html">{@code &lt;data&gt;}</a>
    -+ seperti berikut ini akan memberi tahu Android bahwa
    -+komponen bisa mengambil data video dari jaringan untuk melakukan tindakan:
    -+</p>
    -+
    -+<pre>
    -+&lt;intent-filter&gt;
    -+    &lt;data android:scheme="http" android:type="video/*" /&gt;
    -+    ...
    -+&lt;/intent-filter&gt;</pre>
    -+
    -+
    -+
    -+<h3 id="imatch">Pencocokan intent</h3>
    -+
    -+<p>Intent dicocokkan dengan filter intent selain untuk menemukan komponen
    -+target yang akan diaktifkan, juga untuk menemukan sesuatu tentang rangkaian
    -+komponen pada perangkat.  Misalnya, aplikasi Home akan menempatkan launcher aplikasi
    -+dengan mencari semua aktivitas dengan filter intent yang menetapkan tindakan
    -+{@link android.content.Intent#ACTION_MAIN} dan
    -+kategori {@link android.content.Intent#CATEGORY_LAUNCHER}.</p>
    -+
    -+<p>Aplikasi Anda bisa menggunakan pencocokan intent dengan cara serupa.
    -+{@link android.content.pm.PackageManager} memiliki seperangkat metode {@code query...()}
    -+yang mengembalikan semua komponen yang bisa menerima intent tertentu, dan
    -+serangkaian metode{@code resolve...()} serupa yang menentukan komponen
    -+terbaik untuk merespons intent.  Misalnya,
    -+{@link android.content.pm.PackageManager#queryIntentActivities
    -+queryIntentActivities()} akan mengembalikan daftar semua aktivitas yang bisa melakukan
    -+intent yang diteruskan sebagai argumen, dan {@link
    -+android.content.pm.PackageManager#queryIntentServices
    -+queryIntentServices()} akan mengembalikan daftar layanan serupa.
    -+Tidak ada metode yang akan mengaktifkan komponen; mereka hanya mencantumkan komponen yang
    -+bisa merespons.  Ada metode serupa,
    -+{@link android.content.pm.PackageManager#queryBroadcastReceivers
    -+queryBroadcastReceivers()}, untuk penerima siaran.
    -+</p>
    -+
    -+
    -+
    -+
    -diff --git a/docs/html-intl/intl/id/guide/components/loaders.jd b/docs/html-intl/intl/id/guide/components/loaders.jd
    -new file mode 100644
    -index 0000000..88093cc
    ---- /dev/null
    -+++ b/docs/html-intl/intl/id/guide/components/loaders.jd
    -@@ -0,0 +1,494 @@
    -+page.title=Aktivitas
    -+parent.title=Loader
    -+parent.link=activities.html
    -+@jd:body
    -+<div id="qv-wrapper">
    -+<div id="qv">
    -+    <h2>Dalam dokumen ini</h2>
    -+    <ol>
    -+    <li><a href="#summary">Rangkuman Loader API</a></li>
    -+    <li><a href="#app">Menggunakan Loader dalam Aplikasi</a>
    -+      <ol>
    -+        <li><a href="#requirements"></a></li>
    -+        <li><a href="#starting">Memulai Loader</a></li>
    -+        <li><a href="#restarting">Me-restart Loader</a></li>
    -+        <li><a href="#callback">Menggunakan Callback LoaderManager</a></li>
    -+      </ol>
    -+    </li>
    -+    <li><a href="#example">Contoh</a>
    -+       <ol>
    -+         <li><a href="#more_examples">Contoh Selengkapnya</a></li>
    -+        </ol>
    -+    </li>
    -+  </ol>
    -+
    -+  <h2>Kelas-kelas utama</h2>
    -+    <ol>
    -+      <li>{@link android.app.LoaderManager}</li>
    -+      <li>{@link android.content.Loader}</li>
    -+
    -+    </ol>
    -+
    -+    <h2>Contoh-contoh terkait</h2>
    -+   <ol>
    -+     <li> <a href="{@docRoot}resources/samples/ApiDemos/src/com/example/android/apis/app/LoaderCursor.html">
    -+LoaderCursor</a></li>
    -+     <li> <a href="{@docRoot}resources/samples/ApiDemos/src/com/example/android/apis/app/LoaderThrottle.html">
    -+LoaderThrottle</a></li>
    -+   </ol>
    -+  </div>
    -+</div>
    -+
    -+<p>Diperkenalkan di Android 3.0, loader memudahkan pemuatan data asinkron
    -+dalam aktivitas atau fragmen. Loader memiliki karakteristik ini:</p>
    -+  <ul>
    -+    <li>Loader tersedia untuk setiap {@link android.app.Activity} dan {@link
    -+android.app.Fragment}.</li>
    -+    <li>Loader menyediakan pemuatan data asinkron.</li>
    -+    <li>Loader memantau sumber data mereka dan memberikan hasil baru bila
    -+konten berubah.</li>
    -+    <li>Loader secara otomatis menghubungkan kembali ke kursor loader lalu saat
    -+dibuat kembali setelah perubahan konfigurasi. Karena itu, loader tidak perlu melakukan query ulang
    -+datanya.</li>
    -+  </ul>
    -+
    -+<h2 id="summary">Rangkuman Loader API</h2>
    -+
    -+<p>Ada beberapa kelas dan antarmuka yang mungkin dilibatkan dalam menggunakan
    -+loader pada aplikasi. Semuanya dirangkum dalam tabel ini:</p>
    -+
    -+<table>
    -+  <tr>
    -+    <th>Kelas/Antarmuka</th>
    -+    <th>Keterangan</th>
    -+  </tr>
    -+  <tr>
    -+    <td>{@link android.app.LoaderManager}</td>
    -+    <td>Kelas abstrak yang dikaitkan dengan {@link android.app.Activity} atau
    -+{@link android.app.Fragment} untuk mengelola satu atau beberapa instance {@link
    -+android.content.Loader}. Ini membantu aplikasi mengelola
    -+operasi berjalan lebih lama bersamaan dengan daur hidup {@link android.app.Activity}
    -+atau {@link android.app.Fragment}; penggunaan paling umumnya adalah dengan
    -+{@link android.content.CursorLoader}, akan tetapi aplikasi bebas menulis loader-nya
    -+ sendiri untuk memuat tipe data lainnya.
    -+    <br />
    -+    <br />
    -+    Hanya ada satu {@link android.app.LoaderManager} per aktivitas atau fragmen. Namun {@link android.app.LoaderManager} bisa memiliki
    -+beberapa loader.</td>
    -+  </tr>
    -+  <tr>
    -+    <td>{@link android.app.LoaderManager.LoaderCallbacks}</td>
    -+    <td>Antarmuka callback untuk klien berinteraksi dengan {@link
    -+android.app.LoaderManager}. Misalnya, Anda menggunakan metode callback {@link
    -+android.app.LoaderManager.LoaderCallbacks#onCreateLoader onCreateLoader()}
    -+untuk membuat loader baru.</td>
    -+  </tr>
    -+  <tr>
    -+    <td>{@link android.content.Loader}</td>
    -+    <td>Kelas abstrak yang melakukan pemuatan data asinkron. Ini
    -+adalah kelas dasar untuk loader. Biasanya Anda akan menggunakan {@link
    -+android.content.CursorLoader}, namun Anda bisa menerapkan subkelas sendiri. Selagi
    -+loader aktif, loader harus memantau sumber datanya dan memberikan hasil
    -+baru bila konten berubah. </td>
    -+  </tr>
    -+  <tr>
    -+    <td>{@link android.content.AsyncTaskLoader}</td>
    -+    <td>Loader abstrak yang menyediakan {@link android.os.AsyncTask} untuk melakukan pekerjaan.</td>
    -+  </tr>
    -+  <tr>
    -+    <td>{@link android.content.CursorLoader}</td>
    -+    <td>Subkelas {@link android.content.AsyncTaskLoader} yang meng-query
    -+{@link android.content.ContentResolver} dan mengembalikan {@link
    -+android.database.Cursor}. Kelas ini mengimplementasikan protokol {@link
    -+android.content.Loader} dengan cara standar untuk query kursor,
    -+yang dibuat berdasarkan {@link android.content.AsyncTaskLoader} untuk melakukan query kursor
    -+pada thread latar belakang agar tidak memblokir UI aplikasi. Menggunakan loader
    -+ini merupakan cara terbaik untuk memuat data secara asinkron dari {@link
    -+android.content.ContentProvider}, sebagai ganti melakukan query terkelola melalui
    -+fragmen atau API aktivitas.</td>
    -+  </tr>
    -+</table>
    -+
    -+<p>Kelas dan antarmuka dalam tabel di atas merupakan komponen
    -+esensial yang akan Anda gunakan untuk mengimplementasikan loader dalam aplikasi Anda. Anda tidak memerlukan semuanya
    -+untuk setiap loader yang dibuat, namun Anda akan selalu memerlukan acuan ke {@link
    -+android.app.LoaderManager} untuk memulai loader dan implementasi
    -+kelas {@link android.content.Loader} seperti {@link
    -+android.content.CursorLoader}. Bagian berikut ini menunjukkan kepada Anda cara menggunakan
    -+kelas dan antarmuka ini dalam aplikasi.</p>
    -+
    -+<h2 id ="app">Menggunakan Loader dalam Aplikasi</h2>
    -+<p>Bagian ini menjelaskan cara menggunakan loader dalam aplikasi Android. Aplikasi
    -+yang menggunakan loader biasanya berisi yang berikut ini:</p>
    -+<ul>
    -+  <li>{@link android.app.Activity} atau {@link android.app.Fragment}.</li>
    -+  <li>Instance {@link android.app.LoaderManager}.</li>
    -+  <li>{@link android.content.CursorLoader} akan memuat data yang didukung oleh {@link
    -+android.content.ContentProvider}. Atau, Anda dapat mengimplementasikan subkelas sendiri
    -+ dari {@link android.content.Loader} atau {@link android.content.AsyncTaskLoader} untuk
    -+memuat data dari beberapa sumber lain.</li>
    -+  <li>Implementasi untuk {@link android.app.LoaderManager.LoaderCallbacks}.
    -+Di sinilah Anda membuat loader baru dan mengelola acuan bagi loader
    -+yang ada.</li>
    -+<li>Cara menampilkan data loader, seperti {@link
    -+android.widget.SimpleCursorAdapter}.</li>
    -+  <li>Sumber data, seperti {@link android.content.ContentProvider}, saat menggunakan
    -+{@link android.content.CursorLoader}.</li>
    -+</ul>
    -+<h3 id="starting">Memulai Loader</h3>
    -+
    -+<p>{@link android.app.LoaderManager} mengelola satu atau beberapa instance {@link
    -+android.content.Loader} dalam {@link android.app.Activity} atau
    -+{@link android.app.Fragment}. Hanya ada satu {@link
    -+android.app.LoaderManager} per aktivitas atau fragmen.</p>
    -+
    -+<p>Anda biasanya
    -+memulai {@link android.content.Loader} dalam metode {@link
    -+android.app.Activity#onCreate onCreate()} aktivitas, atau dalam metode
    -+{@link android.app.Fragment#onActivityCreated onActivityCreated()} fragmen. Anda
    -+melakukannya dengan cara berikut ini:</p>
    -+
    -+<pre>// Prepare the loader.  Either re-connect with an existing one,
    -+// or start a new one.
    -+getLoaderManager().initLoader(0, null, this);</pre>
    -+
    -+<p>Metode {@link android.app.LoaderManager#initLoader initLoader()} mengambil
    -+parameter berikut:</p>
    -+<ul>
    -+  <li>ID unik yang mengidentifikasi loader. Dalam contoh ini, ID-nya adalah 0.</li>
    -+<li>Argumen opsional untuk dipasok ke loader
    -+pada saat pembuatan (dalam contoh ini <code>null</code>).</li>
    -+
    -+<li>Implementasi {@link android.app.LoaderManager.LoaderCallbacks}, yang
    -+akan dipanggil {@link android.app.LoaderManager} untuk melaporkan kejadian loader. Dalam contoh
    -+ini, kelas lokal mengimplementasikan antarmuka {@link
    -+android.app.LoaderManager.LoaderCallbacks}, sehingga meneruskan acuan
    -+ke dirinya sendiri, {@code this}.</li>
    -+</ul>
    -+<p>Panggilan {@link android.app.LoaderManager#initLoader initLoader()} memastikan bahwa loader
    -+telah dimulai dan aktif. Ia memiliki dua kemungkinan hasil:</p>
    -+<ul>
    -+  <li>Jika loader yang disebutkan oleh ID sudah ada, loader yang dibuat terakhir akan digunakan
    -+kembali.</li>
    -+  <li>Jika loader yang disebutkan oleh ID <em>tidak</em> ada,
    -+{@link android.app.LoaderManager#initLoader initLoader()} akan memicu metode
    -+{@link android.app.LoaderManager.LoaderCallbacks} {@link android.app.LoaderManager.LoaderCallbacks#onCreateLoader onCreateLoader()}.
    -+Di sinilah Anda mengimplementasikan kode untuk membuat instance dan mengembalikan loader baru.
    -+Untuk diskusi selengkapnya, lihat bagian <a href="#onCreateLoader">onCreateLoader</a>.</li>
    -+</ul>
    -+<p>Dalam hal ini, implementasi {@link android.app.LoaderManager.LoaderCallbacks}
    -+yang ditentukan akan dikaitkan dengan loader, dan akan dipanggil bila
    -+status loader berubah.  Jika saat panggilan ini status pemanggil sudah
    -+dimulai, dan loader yang diminta sudah ada dan telah menghasilkan
    -+datanya, maka sistem segera memanggil {@link
    -+android.app.LoaderManager.LoaderCallbacks#onLoadFinished onLoadFinished()}
    -+(selama {@link android.app.LoaderManager#initLoader initLoader()}),
    -+sehingga Anda harus siap bila hal ini terjadi. Lihat <a href="#onLoadFinished">
    -+onLoadFinished</a> untuk diskusi selengkapnya mengenai callback ini</p>
    -+
    -+<p>Perhatikan bahwa metode {@link android.app.LoaderManager#initLoader initLoader()}
    -+mengembalikan {@link android.content.Loader} yang dibuat, namun Anda tidak
    -+perlu menangkap acuan ke sana. {@link android.app.LoaderManager} mengelola
    -+masa hidup loader secara otomatis. {@link android.app.LoaderManager}
    -+memulai dan menghentikan pemuatan jika perlu, dan menjaga status loader
    -+dan konten terkaitnya. Seperti yang tersirat di sini, Anda akan jarang berinteraksi dengan loader
    -+secara langsung (meskipun misalnya menggunakan metode loader untuk menyempurnakan perilaku
    -+loader, lihat contoh <a href="{@docRoot}resources/samples/ApiDemos/src/com/example/android/apis/app/LoaderThrottle.html"> LoaderThrottle</a>).
    -+Anda paling sering akan menggunakan metode {@link
    -+android.app.LoaderManager.LoaderCallbacks} untuk mengintervensi proses
    -+pemuatan saat terjadi kejadian tertentu. Untuk diskusi selengkapnya mengenai topik ini, lihat <a href="#callback">Menggunakan Callback LoaderManager</a>.</p>
    -+
    -+<h3 id="restarting">Me-restart Loader</h3>
    -+
    -+<p>Bila Anda menggunakan {@link android.app.LoaderManager#initLoader initLoader()}, seperti
    -+ditampilkan di atas, loader yang ada akan digunakan dengan ID yang ditetapkan jika ada.
    -+Jika tidak ada, ID akan dibuat. Namun kadang-kadang Anda perlu membuang data lama
    -+dan mulai dari awal.</p>
    -+
    -+<p>Untuk membuang data lama, gunakan {@link
    -+android.app.LoaderManager#restartLoader restartLoader()}. Misalnya, implementasi
    -+{@link android.widget.SearchView.OnQueryTextListener} ini akan me-restart
    -+bila query pengguna berubah. Loader perlu di-restart
    -+agar dapat menggunakan filter pencarian yang telah direvisi untuk melakukan query baru:</p>
    -+
    -+<pre>
    -+public boolean onQueryTextChanged(String newText) {
    -+    // Called when the action bar search text has changed.  Update
    -+    // the search filter, and restart the loader to do a new query
    -+    // with this filter.
    -+    mCurFilter = !TextUtils.isEmpty(newText) ? newText : null;
    -+    getLoaderManager().restartLoader(0, null, this);
    -+    return true;
    -+}</pre>
    -+
    -+<h3 id="callback">Menggunakan Callback LoaderManager</h3>
    -+
    -+<p>{@link android.app.LoaderManager.LoaderCallbacks} adalah antarmuka callback
    -+yang memungkinkan klien berinteraksi dengan {@link android.app.LoaderManager}. </p>
    -+<p>Loader, khususnya {@link android.content.CursorLoader}, diharapkan
    -+mempertahankan datanya setelah dihentikan. Ini memungkinkan aplikasi mempertahankan
    -+datanya di aktivitas atau metode {@link android.app.Activity#onStop
    -+onStop()} fragmen dan {@link android.app.Activity#onStart onStart()}, sehingga
    -+bila pengguna kembali ke aplikasi, mereka tidak harus menunggu data
    -+dimuat kembali. Anda menggunakan metode {@link android.app.LoaderManager.LoaderCallbacks}
    -+untuk mengetahui waktu membuat loader baru, dan memberi tahu aplikasi kapan
    -+berhenti menggunakan data loader.</p>
    -+
    -+<p>{@link android.app.LoaderManager.LoaderCallbacks} berisi metode
    -+ini:</p>
    -+<ul>
    -+  <li>{@link android.app.LoaderManager.LoaderCallbacks#onCreateLoader onCreateLoader()} —
    -+Membuat instance dan mengembalikan {@link android.content.Loader} baru untuk ID yang diberikan.
    -+</li></ul>
    -+<ul>
    -+  <li> {@link android.app.LoaderManager.LoaderCallbacks#onLoadFinished onLoadFinished()}
    -+— Dipanggil bila loader yang dibuat sebelumnya selesai dimuat.
    -+</li></ul>
    -+<ul>
    -+  <li>{@link android.app.LoaderManager.LoaderCallbacks#onLoaderReset onLoaderReset()}
    -+    — Dipanggil bila loader yang dibuat sebelumnya sedang di-reset, sehingga datanya
    -+tidak tersedia.
    -+</li>
    -+</ul>
    -+<p>Metode ini dijelaskan lebih detail dalam bagian berikutnya.</p>
    -+
    -+<h4 id ="onCreateLoader">onCreateLoader</h4>
    -+
    -+<p>Saat Anda mencoba mengakses loader (misalnya, melalui {@link
    -+android.app.LoaderManager#initLoader initLoader()}), ia akan memeriksa untuk mengetahui adanya
    -+loader yang ditetapkan oleh ID. Jika tidak ada, ia akan memicu metode {@link
    -+android.app.LoaderManager.LoaderCallbacks} {@link
    -+android.app.LoaderManager.LoaderCallbacks#onCreateLoader onCreateLoader()}. Di
    -+sinilah Anda membuat loader baru. Biasanya ini adalah {@link
    -+android.content.CursorLoader}, namun Anda bisa mengimplementasikan sendiri subkelas {@link
    -+android.content.Loader}. </p>
    -+
    -+<p>Dalam contoh ini, metode callback {@link
    -+android.app.LoaderManager.LoaderCallbacks#onCreateLoader onCreateLoader()}
    -+ akan membuat {@link android.content.CursorLoader}. Anda harus membuat
    -+{@link android.content.CursorLoader} menggunakan metode konstruktornya, yang
    -+memerlukan set informasi lengkap untuk melakukan query ke {@link
    -+android.content.ContentProvider}. Secara khusus, ia memerlukan:</p>
    -+<ul>
    -+  <li><em>uri</em> — URI untuk konten yang akan diambil. </li>
    -+  <li><em>projection</em> — Daftar berisi kolom yang akan dikembalikan. Meneruskan
    -+<code>null</code> akan mengembalikan semua kolom, jadi tidak efisien. </li>
    -+  <li><em>selection</em> — Filter yang mendeklarasikan baris yang akan dikembalikan,
    -+diformat sebagai klausa SQL WHERE (tidak termasuk WHERE itu sendiri). Meneruskan
    -+<code>null</code> akan mengembalikan semua baris untuk URI yang diberikan. </li>
    -+  <li><em>selectionArgs</em> — Anda dapat menyertakan ?s dalam pilihan, yang akan
    -+digantikan dengan nilai dari <em>selectionArgs</em>, agar muncul dalam
    -+pilihan. Nilai-nilai akan diikat sebagai String. </li>
    -+  <li><em>sortOrder</em> — Cara menyusun baris, diformat sebagai klausa SQL
    -+ORDER BY (tidak termasuk ORDER BY itu sendiri). Meneruskan <code>null</code> akan
    -+menggunakan urutan sortir default, yang mungkin tidak berurutan.</li>
    -+</ul>
    -+<p>Misalnya:</p>
    -+<pre>
    -+ // If non-null, this is the current filter the user has provided.
    -+String mCurFilter;
    -+...
    -+public Loader&lt;Cursor&gt; onCreateLoader(int id, Bundle args) {
    -+    // This is called when a new Loader needs to be created.  This
    -+    // sample only has one Loader, so we don't care about the ID.
    -+    // First, pick the base URI to use depending on whether we are
    -+    // currently filtering.
    -+    Uri baseUri;
    -+    if (mCurFilter != null) {
    -+        baseUri = Uri.withAppendedPath(Contacts.CONTENT_FILTER_URI,
    -+                  Uri.encode(mCurFilter));
    -+    } else {
    -+        baseUri = Contacts.CONTENT_URI;
    -+    }
    -+
    -+    // Now create and return a CursorLoader that will take care of
    -+    // creating a Cursor for the data being displayed.
    -+    String select = &quot;((&quot; + Contacts.DISPLAY_NAME + &quot; NOTNULL) AND (&quot;
    -+            + Contacts.HAS_PHONE_NUMBER + &quot;=1) AND (&quot;
    -+            + Contacts.DISPLAY_NAME + &quot; != '' ))&quot;;
    -+    return new CursorLoader(getActivity(), baseUri,
    -+            CONTACTS_SUMMARY_PROJECTION, select, null,
    -+            Contacts.DISPLAY_NAME + &quot; COLLATE LOCALIZED ASC&quot;);
    -+}</pre>
    -+<h4 id="onLoadFinished">onLoadFinished</h4>
    -+
    -+<p>Metode ini dipanggil bila loader yang dibuat sebelumnya selesai dimuat.
    -+Metode ini dijamin dipanggil sebelum pelepasan data terakhir
    -+yang disediakan untuk loader ini.  Di titik ini Anda harus menyingkirkan semua penggunaan
    -+data lama (karena akan segera dilepas), namun jangan melepas sendiri
    -+data tersebut karena loader memilikinya dan akan menanganinya.</p>
    -+
    -+
    -+<p>Loader akan melepas data setelah mengetahui bahwa aplikasi tidak
    -+lagi menggunakannya.  Misalnya, jika data adalah kursor dari {@link
    -+android.content.CursorLoader}, Anda tidak boleh memanggil {@link
    -+android.database.Cursor#close close()} sendiri. Jika kursor ditempatkan
    -+dalam {@link android.widget.CursorAdapter}, Anda harus menggunakan metode {@link
    -+android.widget.SimpleCursorAdapter#swapCursor swapCursor()} agar
    -+{@link android.database.Cursor} lama tidak ditutup. Misalnya:</p>
    -+
    -+<pre>
    -+// This is the Adapter being used to display the list's data.<br
    -+/>SimpleCursorAdapter mAdapter;
    -+...
    -+
    -+public void onLoadFinished(Loader&lt;Cursor&gt; loader, Cursor data) {
    -+    // Swap the new cursor in.  (The framework will take care of closing the
    -+    // old cursor once we return.)
    -+    mAdapter.swapCursor(data);
    -+}</pre>
    -+
    -+<h4 id="onLoaderReset">onLoaderReset</h4>
    -+
    -+<p>Metode ini dipanggil bila loader yang dibuat sebelumnya sedang di-reset, sehingga datanya
    -+tidak tersedia. Callback ini memungkinkan Anda mengetahui
    -+kapan data akan dilepas sehingga dapat menghapus acuannya ke callback.  </p>
    -+<p>Implementasi ini memanggil
    -+{@link android.widget.SimpleCursorAdapter#swapCursor swapCursor()}
    -+dengan nilai <code>null</code>:</p>
    -+
    -+<pre>
    -+// This is the Adapter being used to display the list's data.
    -+SimpleCursorAdapter mAdapter;
    -+...
    -+
    -+public void onLoaderReset(Loader&lt;Cursor&gt; loader) {
    -+    // This is called when the last Cursor provided to onLoadFinished()
    -+    // above is about to be closed.  We need to make sure we are no
    -+    // longer using it.
    -+    mAdapter.swapCursor(null);
    -+}</pre>
    -+
    -+
    -+<h2 id="example">Contoh</h2>
    -+
    -+<p>Sebagai contoh, berikut ini adalah implementasi penuh {@link
    -+android.app.Fragment} yang menampilkan {@link android.widget.ListView} berisi
    -+hasil query terhadap penyedia konten kontak. Ia menggunakan {@link
    -+android.content.CursorLoader} untuk mengelola query pada penyedia.</p>
    -+
    -+<p>Agar aplikasi dapat mengakses kontak pengguna, seperti yang ditampilkan dalam contoh ini,
    -+manifesnya harus menyertakan izin
    -+{@link android.Manifest.permission#READ_CONTACTS READ_CONTACTS}.</p>
    -+
    -+<pre>
    -+public static class CursorLoaderListFragment extends ListFragment
    -+        implements OnQueryTextListener, LoaderManager.LoaderCallbacks&lt;Cursor&gt; {
    -+
    -+    // This is the Adapter being used to display the list's data.
    -+    SimpleCursorAdapter mAdapter;
    -+
    -+    // If non-null, this is the current filter the user has provided.
    -+    String mCurFilter;
    -+
    -+    @Override public void onActivityCreated(Bundle savedInstanceState) {
    -+        super.onActivityCreated(savedInstanceState);
    -+
    -+        // Give some text to display if there is no data.  In a real
    -+        // application this would come from a resource.
    -+        setEmptyText(&quot;No phone numbers&quot;);
    -+
    -+        // We have a menu item to show in action bar.
    -+        setHasOptionsMenu(true);
    -+
    -+        // Create an empty adapter we will use to display the loaded data.
    -+        mAdapter = new SimpleCursorAdapter(getActivity(),
    -+                android.R.layout.simple_list_item_2, null,
    -+                new String[] { Contacts.DISPLAY_NAME, Contacts.CONTACT_STATUS },
    -+                new int[] { android.R.id.text1, android.R.id.text2 }, 0);
    -+        setListAdapter(mAdapter);
    -+
    -+        // Prepare the loader.  Either re-connect with an existing one,
    -+        // or start a new one.
    -+        getLoaderManager().initLoader(0, null, this);
    -+    }
    -+
    -+    @Override public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
    -+        // Place an action bar item for searching.
    -+        MenuItem item = menu.add(&quot;Search&quot;);
    -+        item.setIcon(android.R.drawable.ic_menu_search);
    -+        item.setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM);
    -+        SearchView sv = new SearchView(getActivity());
    -+        sv.setOnQueryTextListener(this);
    -+        item.setActionView(sv);
    -+    }
    -+
    -+    public boolean onQueryTextChange(String newText) {
    -+        // Called when the action bar search text has changed.  Update
    -+        // the search filter, and restart the loader to do a new query
    -+        // with this filter.
    -+        mCurFilter = !TextUtils.isEmpty(newText) ? newText : null;
    -+        getLoaderManager().restartLoader(0, null, this);
    -+        return true;
    -+    }
    -+
    -+    @Override public boolean onQueryTextSubmit(String query) {
    -+        // Don't care about this.
    -+        return true;
    -+    }
    -+
    -+    @Override public void onListItemClick(ListView l, View v, int position, long id) {
    -+        // Insert desired behavior here.
    -+        Log.i(&quot;FragmentComplexList&quot;, &quot;Item clicked: &quot; + id);
    -+    }
    -+
    -+    // These are the Contacts rows that we will retrieve.
    -+    static final String[] CONTACTS_SUMMARY_PROJECTION = new String[] {
    -+        Contacts._ID,
    -+        Contacts.DISPLAY_NAME,
    -+        Contacts.CONTACT_STATUS,
    -+        Contacts.CONTACT_PRESENCE,
    -+        Contacts.PHOTO_ID,
    -+        Contacts.LOOKUP_KEY,
    -+    };
    -+    public Loader&lt;Cursor&gt; onCreateLoader(int id, Bundle args) {
    -+        // This is called when a new Loader needs to be created.  This
    -+        // sample only has one Loader, so we don't care about the ID.
    -+        // First, pick the base URI to use depending on whether we are
    -+        // currently filtering.
    -+        Uri baseUri;
    -+        if (mCurFilter != null) {
    -+            baseUri = Uri.withAppendedPath(Contacts.CONTENT_FILTER_URI,
    -+                    Uri.encode(mCurFilter));
    -+        } else {
    -+            baseUri = Contacts.CONTENT_URI;
    -+        }
    -+
    -+        // Now create and return a CursorLoader that will take care of
    -+        // creating a Cursor for the data being displayed.
    -+        String select = &quot;((&quot; + Contacts.DISPLAY_NAME + &quot; NOTNULL) AND (&quot;
    -+                + Contacts.HAS_PHONE_NUMBER + &quot;=1) AND (&quot;
    -+                + Contacts.DISPLAY_NAME + &quot; != '' ))&quot;;
    -+        return new CursorLoader(getActivity(), baseUri,
    -+                CONTACTS_SUMMARY_PROJECTION, select, null,
    -+                Contacts.DISPLAY_NAME + &quot; COLLATE LOCALIZED ASC&quot;);
    -+    }
    -+
    -+    public void onLoadFinished(Loader&lt;Cursor&gt; loader, Cursor data) {
    -+        // Swap the new cursor in.  (The framework will take care of closing the
    -+        // old cursor once we return.)
    -+        mAdapter.swapCursor(data);
    -+    }
    -+
    -+    public void onLoaderReset(Loader&lt;Cursor&gt; loader) {
    -+        // This is called when the last Cursor provided to onLoadFinished()
    -+        // above is about to be closed.  We need to make sure we are no
    -+        // longer using it.
    -+        mAdapter.swapCursor(null);
    -+    }
    -+}</pre>
    -+<h3 id="more_examples">Contoh Selengkapnya</h3>
    -+
    -+<p>Ada beberapa contoh berbeda dalam <strong>ApiDemos</strong> yang
    -+mengilustrasikan cara menggunakan loader:</p>
    -+<ul>
    -+  <li><a href="{@docRoot}resources/samples/ApiDemos/src/com/example/android/apis/app/LoaderCursor.html">
    -+LoaderCursor</a> — Versi lengkap dari
    -+cuplikan yang ditampilkan di atas.</li>
    -+  <li><a href="{@docRoot}resources/samples/ApiDemos/src/com/example/android/apis/app/LoaderThrottle.html"> LoaderThrottle</a> — Contoh cara penggunaan throttling untuk
    -+mengurangi jumlah query dari penyedia konten saat datanya berubah.</li>
    -+</ul>
    -+
    -+<p>Untuk informasi tentang mengunduh dan menginstal contoh SDK, lihat <a href="http://developer.android.com/resources/samples/get.html"> Mendapatkan
    -+Contoh</a>. </p>
    -+
    -diff --git a/docs/html-intl/intl/id/guide/components/processes-and-threads.jd b/docs/html-intl/intl/id/guide/components/processes-and-threads.jd
    -new file mode 100644
    -index 0000000..cdab715
    ---- /dev/null
    -+++ b/docs/html-intl/intl/id/guide/components/processes-and-threads.jd
    -@@ -0,0 +1,411 @@
    -+page.title=Proses dan Thread
    -+page.tags=daur hidup,latar belakang
    -+
    -+@jd:body
    -+
    -+<div id="qv-wrapper">
    -+<div id="qv">
    -+
    -+<h2>Dalam dokumen ini</h2>
    -+<ol>
    -+<li><a href="#Processes">Proses</a>
    -+  <ol>
    -+    <li><a href="#Lifecycle">Daur hidup proses</a></li>
    -+  </ol>
    -+</li>
    -+<li><a href="#Threads">Thread</a>
    -+  <ol>
    -+    <li><a href="#WorkerThreads">Thread pekerja</a></li>
    -+    <li><a href="#ThreadSafe">Metode thread-safe</a></li>
    -+  </ol>
    -+</li>
    -+<li><a href="#IPC">Komunikasi antarproses</a></li>
    -+</ol>
    -+
    -+</div>
    -+</div>
    -+
    -+<p>Bila komponen aplikasi dimulai dan tidak ada komponen aplikasi lain yang
    -+berjalan, sistem Android akan memulai proses Linux baru untuk aplikasi dengan satu thread
    -+eksekusi. Secara default, semua komponen aplikasi yang sama berjalan dalam proses dan
    -+thread yang sama (disebut thread "utama"). Jika komponen aplikasi dimulai dan sudah ada
    -+proses untuk aplikasi itu (karena komponen lain dari aplikasi itu sudah ada), maka komponen
    -+akan dimulai dalam proses itu dan menggunakan thread eksekusi yang sama. Akan tetapi, Anda bisa
    -+mengatur komponen berbeda di aplikasi agar berjalan di proses terpisah, dan Anda bisa membuat thread tambahan untuk
    -+setiap proses.</p>
    -+
    -+<p>Dokumen ini membahas cara kerja proses dan thread di aplikasi Android.</p>
    -+
    -+
    -+<h2 id="Processes">Proses</h2>
    -+
    -+<p>Secara default, semua komponen aplikasi yang sama berjalan dalam proses yang sama dan kebanyakan
    -+aplikasi tidak boleh mengubah ini. Akan tetapi, jika Anda merasa perlu mengontrol proses milik
    -+komponen tertentu, Anda dapat melakukannya dalam file manifes.</p>
    -+
    -+<p>Entri manifes untuk setiap tipe elemen komponen&mdash;<a href="{@docRoot}guide/topics/manifest/activity-element.html">{@code
    -+&lt;activity&gt;}</a>, <a href="{@docRoot}guide/topics/manifest/service-element.html">{@code
    -+&lt;service&gt;}</a>, <a href="{@docRoot}guide/topics/manifest/receiver-element.html">{@code
    -+&lt;receiver&gt;}</a>, dan <a href="{@docRoot}guide/topics/manifest/provider-element.html">{@code
    -+&lt;provider&gt;}</a>&mdash;mendukung atribut {@code android:process} yang bisa menetapkan
    -+dalam proses mana komponen harus dijalankan. Anda bisa mengatur atribut ini agar setiap komponen
    -+berjalan dalam prosesnya sendiri atau agar beberapa komponen menggunakan proses yang sama sementara yang lainnya tidak.  Anda juga bisa mengatur
    -+{@code android:process} agar komponen aplikasi yang berbeda berjalan dalam proses yang sama
    -+&mdash;sepanjang aplikasi menggunakan ID Linux yang sama dan ditandatangani
    -+dengan sertifikat yang sama.</p>
    -+
    -+<p>Elemen <a href="{@docRoot}guide/topics/manifest/application-element.html">{@code
    -+&lt;application&gt;}</a> juga mendukung atribut {@code android:process}, untuk mengatur
    -+nilai default yang berlaku bagi semua komponen.</p>
    -+
    -+<p>Android bisa memutuskan untuk mematikan proses pada waktu tertentu, bila memori tinggal sedikit dan diperlukan oleh
    -+proses lain yang lebih mendesak untuk melayani pengguna. Komponen
    -+aplikasi yang berjalan dalam proses yang dimatikan maka sebagai konsekuensinya juga akan dimusnahkan.  Proses dimulai
    -+kembali untuk komponen itu bila ada lagi pekerjaan untuk mereka lakukan.</p>
    -+
    -+<p>Saat memutuskan proses yang akan dimatikan, sistem Android akan mempertimbangkan kepentingan relatifnya bagi
    -+pengguna.  Misalnya, sistem lebih mudah menghentikan proses yang menjadi host aktivitas yang tidak
    -+ lagi terlihat di layar, dibandingkan dengan proses yang menjadi host aktivitas yang terlihat. Karena itu, keputusan
    -+untuk menghentikan proses bergantung pada keadaan komponen yang berjalan dalam proses tersebut. Aturan
    -+yang digunakan untuk menentukan proses yang akan dihentikan dibahas di bawah ini. </p>
    -+
    -+
    -+<h3 id="Lifecycle">Daur hidup proses</h3>
    -+
    -+<p>Sistem Android mencoba mempertahankan proses aplikasi selama mungkin, namun
    -+pada akhirnya perlu menghapus proses lama untuk mengambil kembali memori bagi proses baru atau yang lebih penting.  Untuk
    -+menentukan proses yang akan
    -+dipertahankan dan yang harus dimatikan, sistem menempatkan setiap proses ke dalam "hierarki prioritas" berdasarkan
    -+komponen yang berjalan dalam proses dan status komponen tersebut.  Proses yang memiliki
    -+prioritas terendah akan dimatikan terlebih dahulu, kemudian yang terendah berikutnya, dan seterusnya, jika perlu
    -+untuk memulihkan sumber daya sistem.</p>
    -+
    -+<p>Ada lima tingkatan dalam hierarki prioritas. Daftar berikut berisi beberapa
    -+tipe proses berdasarkan urutan prioritas (proses pertama adalah yang <em>terpenting</em> dan
    -+<em>dimatikan terakhir</em>):</p>
    -+
    -+<ol>
    -+  <li><b>Proses latar depan</b>
    -+    <p>Proses yang diperlukan untuk aktivitas yang sedang dilakukan pengguna.  Proses
    -+dianggap berada di latar depan jika salah satu kondisi berikut terpenuhi:</p>
    -+
    -+      <ul>
    -+        <li>Proses menjadi host {@link android.app.Activity} yang berinteraksi dengan pengguna dengan metode ({@link
    -+android.app.Activity}{@link android.app.Activity#onResume onResume()} telah
    -+dipanggil).</li>
    -+
    -+        <li>Proses menjadi host {@link android.app.Service} yang terikat dengan aktivitas yang sedang berinteraksi dengan
    -+pengguna.</li>
    -+
    -+        <li>Proses menjadi host {@link android.app.Service} yang berjalan "di latar depan"&mdash;
    -+layanan telah memanggil{@link android.app.Service#startForeground startForeground()}.
    -+
    -+        <li>Proses menjadi host {@link android.app.Service} yang menjalankan salah satu callback
    -+daur hidupnya ({@link android.app.Service#onCreate onCreate()}, {@link android.app.Service#onStart
    -+onStart()}, atau {@link android.app.Service#onDestroy onDestroy()}).</li>
    -+
    -+        <li>Proses menjadi host {@link android.content.BroadcastReceiver} yang menjalankan metode {@link
    -+        android.content.BroadcastReceiver#onReceive onReceive()}-nya.</li>
    -+    </ul>
    -+
    -+    <p>Secara umum, hanya ada beberapa proses latar depan pada waktu yang diberikan.  Proses dimatikan hanya sebagai
    -+upaya terakhir&mdash; jika memori hampir habis sehingga semuanya tidak bisa terus berjalan.  Pada umumnya, pada
    -+titik itu, perangkat dalam keadaan memory paging, sehingga menghentikan beberapa proses latar depan
    -+diperlukan agar antarmuka pengguna tetap responsif.</p></li>
    -+
    -+  <li><b>Proses yang terlihat</b>
    -+    <p>Proses yang tidak memiliki komponen latar depan, namun masih bisa
    -+memengaruhi apa yang dilihat pengguna di layar. Proses dianggap terlihat jika salah satu kondisi
    -+berikut terpenuhi:</p>
    -+
    -+      <ul>
    -+        <li>Proses ini menjadi host {@link android.app.Activity} yang tidak berada di latar depan, namun masih
    -+terlihat oleh penggunanya (metode {@link android.app.Activity#onPause onPause()} telah dipanggil).
    -+Ini bisa terjadi, misalnya, jika aktivitas latar depan memulai dialog, sehingga
    -+aktivitas sebelumnya terlihat berada di belakangnya.</li>
    -+
    -+        <li>Proses menjadi host {@link android.app.Service} yang terikat dengan aktivitas yang terlihat (atau latar
    -+depan)</li>
    -+      </ul>
    -+
    -+      <p>Proses yang terlihat dianggap sangat penting dan tidak akan dimatikan kecuali jika hal itu
    -+diperlukan agar semua proses latar depan tetap berjalan. </p>
    -+    </li>
    -+
    -+  <li><b>Proses layanan</b>
    -+    <p>Proses yang menjalankan layanan yang telah dimulai dengan metode {@link
    -+android.content.Context#startService startService()} dan tidak termasuk dalam salah satu dari dua kategori
    -+yang lebih tinggi. Walaupun proses pelayanan tidak langsung terkait dengan semua yang dilihat oleh pengguna, proses ini
    -+umumnya melakukan hal-hal yang dipedulikan pengguna (seperti memutar musik di latar belakang
    -+atau mengunduh data di jaringan), jadi sistem membuat proses tetap berjalan kecuali memori tidak cukup untuk
    -+mempertahankannya bersama semua proses latar depan dan proses yang terlihat. </p>
    -+  </li>
    -+
    -+  <li><b>Proses latar belakang</b>
    -+    <p>Proses yang menampung aktivitas yang saat ini tidak terlihat oleh pengguna (metode
    -+{@link android.app.Activity#onStop onStop()} aktivitas telah dipanggil). Proses ini tidak memiliki dampak
    -+langsung pada pengalaman pengguna, dan sistem bisa menghentikannya kapan saja untuk memperoleh kembali memori bagi
    -+proses latar depan, proses yang terlihat,
    -+atau proses layanan. Biasanya ada banyak proses latar belakang yang berjalan, sehingga disimpan
    -+dalam daftar LRU (least recently used atau paling sedikit digunakan) untuk memastikan bahwa proses dengan aktivitas yang paling baru
    -+terlihat oleh pengguna sebagai yang terakhir untuk dimatikan. Jika aktivitas mengimplementasikan metode
    -+ daur hidupnya dengan benar, dan menyimpan statusnya saat ini, menghentikan prosesnya tidak akan memiliki efek
    -+yang terlihat pada pengalaman pengguna, karena ketika pengguna kembali ke aktivitas, aktivitas itu memulihkan
    -+semua statusnya yang terlihat. Lihat dokumen <a href="{@docRoot}guide/components/activities.html#SavingActivityState">Aktivitas</a>
    -+ untuk mendapatkan informasi tentang menyimpan dan memulihkan status.</p>
    -+  </li>
    -+
    -+  <li><b>Proses kosong</b>
    -+    <p>Sebuah proses yang tidak berisi komponen aplikasi aktif apa pun.  Alasan satu-satunya mempertahankan proses
    -+seperti ini tetap hidup adalah untuk keperluan caching, meningkatkan waktu mulai (startup) bila
    -+nanti komponen perlu dijalankan di dalamnya.  Sistem sering menghentikan proses ini untuk menyeimbangkan sumber
    -+daya sistem secara keseluruhan antara proses cache dan cache kernel yang mendasarinya.</p>
    -+  </li>
    -+</ol>
    -+
    -+
    -+  <p>Android sebisa mungkin memeringkat proses setinggi
    -+mungkin, berdasarkan prioritas komponen yang sedang aktif dalam proses.  Misalnya, jika suatu proses menjadi host sebuah layanan dan
    -+aktivitas yang terlihat, proses akan diperingkat sebagai proses yang terlihat, bukan sebagai proses layanan.</p>
    -+
    -+  <p>Selain itu, peringkat proses dapat meningkat karena adanya proses lain yang bergantung padanya
    -+&mdash;proses yang melayani proses lain tidak bisa diperingkat lebih rendah daripada proses yang
    -+sedang dilayaninya. Misalnya, jika penyedia konten dalam proses A melayani klien dalam proses B, atau
    -+jika layanan dalam proses A terikat dengan komponen dalam proses B, proses A selalu dipertimbangkan sebagai paling rendah
    -+prioritasnya dibandingkan dengan proses B.</p>
    -+
    -+  <p>Karena proses yang menjalankan layanan diperingkat lebih tinggi daripada aktivitas latar belakang,
    -+aktivitas yang memulai operasi yang berjalan lama mungkin lebih baik memulai <a href="{@docRoot}guide/components/services.html">layanan</a> untuk operasi itu, daripada hanya
    -+membuat thread pekerja&mdash;khususnya jika operasi mungkin akan berlangsung lebih lama daripada aktivitas.
    -+ Misalnya, aktivitas yang mengunggah gambar ke situs web harus memulai layanan
    -+untuk mengunggah sehingga unggahan bisa terus berjalan di latar belakang meskipun pengguna meninggalkan aktivitas tersebut.
    -+Menggunakan layanan akan memastikan operasi paling tidak memiliki prioritas "proses layanan",
    -+apa pun yang terjadi pada aktivitas. Ini menjadi alasan yang sama yang membuat penerima siaran harus
    -+menjalankan layanan daripada hanya menempatkan operasi yang menghabiskan waktu di thread.</p>
    -+
    -+
    -+
    -+
    -+<h2 id="Threads">Thread</h2>
    -+
    -+<p>Bila aplikasi diluncurkan, sistem akan membuat thread eksekusi untuk aplikasi tersebut, yang diberi nama,
    -+"main". Thread ini sangat penting karena bertugas mengirim kejadian ke widget
    -+antarmuka pengguna yang sesuai, termasuk kejadian menggambar. Ini juga merupakan thread yang
    -+membuat aplikasi berinteraksi dengan komponen dari Android UI toolkit (komponen dari paket {@link
    -+android.widget} dan {@link android.view}). Karena itu, thread 'main' juga terkadang
    -+disebut thread UI.</p>
    -+
    -+<p>Sistem ini <em>tidak</em> membuat thread terpisah untuk setiap instance komponen. Semua
    -+komponen yang berjalan di proses yang sama akan dibuat instance-nya dalam thread UI, dan sistem akan memanggil
    -+setiap komponen yang dikirim dari thread itu. Akibatnya, metode yang merespons callback sistem
    -+ (seperti {@link android.view.View#onKeyDown onKeyDown()} untuk melaporkan tindakan pengguna atau metode callback daur hidup)
    -+ selalu berjalan di thread UI proses.</p>
    -+
    -+<p>Misalnya saat pengguna menyentuh tombol pada layar, thread UI aplikasi akan mengirim kejadian
    -+sentuh ke widget, yang selanjutnya menetapkan status ditekan dan mengirim permintaan yang tidak divalidasi ke
    -+antrean kejadian. Thread UI akan menghapus antrean permintaan dan memberi tahu widget bahwa widget harus menggambar
    -+dirinya sendiri.</p>
    -+
    -+<p>Saat aplikasi melakukan pekerjaan intensif sebagai respons terhadap interaksi pengguna, model
    -+thread tunggal ini bisa menghasilkan kinerja yang buruk kecuali jika Anda mengimplementasikan aplikasi dengan benar. Khususnya jika
    -+ semua terjadi di thread UI, melakukan operasi yang panjang seperti akses ke jaringan atau query
    -+database akan memblokir seluruh UI. Bila thread diblokir, tidak ada kejadian yang bisa dikirim,
    -+termasuk kejadian menggambar. Dari sudut pandang pengguna, aplikasi
    -+tampak mogok (hang). Lebih buruk lagi, jika thread UI diblokir selama lebih dari beberapa detik
    -+(saat ini sekitar 5 detik) pengguna akan ditampilkan dialog "<a href="http://developer.android.com/guide/practices/responsiveness.html">aplikasi tidak
    -+merespons</a>" (ANR) yang populer karena reputasi buruknya. Pengguna nanti bisa memutuskan untuk keluar dari aplikasi dan menghapus aplikasi
    -+jika mereka tidak suka.</p>
    -+
    -+<p>Selain itu, toolkit Android UI <em>bukan</em> thread-safe. Jadi, Anda tidak harus memanipulasi
    -+UI dari thread pekerja&mdash;Anda harus melakukan semua manipulasi pada antarmuka pengguna dari thread
    -+UI. Sehingga hanya ada dua aturan untuk model thread tunggal Android:</p>
    -+
    -+<ol>
    -+<li>Jangan memblokir thread UI
    -+<li>Jangan mengakses toolkit Android UI dari luar thread UI
    -+</ol>
    -+
    -+<h3 id="WorkerThreads">Thread pekerja</h3>
    -+
    -+<p>Karena model thread tunggal yang dijelaskan di atas, Anda dilarang memblokir thread
    -+UI demi daya respons UI aplikasi. Jika memiliki operasi untuk dijalankan
    -+yang tidak seketika, Anda harus memastikan untuk melakukannya di thread terpisah (thread "latar belakang" atau
    -+thread "pekerja").</p>
    -+
    -+<p>Misalnya, berikut ini beberapa kode untuk listener klik yang mengunduh gambar dari
    -+thread terpisah dan menampilkannya dalam {@link android.widget.ImageView}:</p>
    -+
    -+<pre>
    -+public void onClick(View v) {
    -+    new Thread(new Runnable() {
    -+        public void run() {
    -+            Bitmap b = loadImageFromNetwork("http://example.com/image.png");
    -+            mImageView.setImageBitmap(b);
    -+        }
    -+    }).start();
    -+}
    -+</pre>
    -+
    -+<p>Awalnya hal ini tampak bekerja dengan baik, karena menciptakan thread baru untuk menangani
    -+operasi jaringan. Akan tetapi, hal tersebut melanggar aturan kedua model thread tunggal: <em>jangan mengakses
    -+ toolkit Android UI dari luar thread UI</em>&mdash;sampel ini memodifikasi {@link
    -+android.widget.ImageView} dari thread pekerja sebagai ganti thread UI. Ini bisa
    -+mengakibatkan perilaku yang tidak terdefinisi dan tidak diharapkan, yang bisa menyulitkan dan menghabiskan waktu untuk melacaknya.</p>
    -+
    -+<p>Untuk memperbaiki masalah ini, Android menawarkan beberapa cara untuk mengakses thread UI dari
    -+thread lainnya. Berikut ini daftar metode yang bisa membantu:</p>
    -+
    -+<ul>
    -+<li>{@link android.app.Activity#runOnUiThread(java.lang.Runnable)
    -+Activity.runOnUiThread(Runnable)}</li>
    -+<li>{@link android.view.View#post(java.lang.Runnable) View.post(Runnable)}</li>
    -+<li>{@link android.view.View#postDelayed(java.lang.Runnable, long) View.postDelayed(Runnable,
    -+long)}</li>
    -+</ul>
    -+
    -+<p>Misalnya, Anda bisa memperbaiki kode di atas dengan menggunakan metode {@link
    -+android.view.View#post(java.lang.Runnable) View.post(Runnable)}:</p>
    -+
    -+<pre>
    -+public void onClick(View v) {
    -+    new Thread(new Runnable() {
    -+        public void run() {
    -+            final Bitmap bitmap = loadImageFromNetwork("http://example.com/image.png");
    -+            mImageView.post(new Runnable() {
    -+                public void run() {
    -+                    mImageView.setImageBitmap(bitmap);
    -+                }
    -+            });
    -+        }
    -+    }).start();
    -+}
    -+</pre>
    -+
    -+<p>Kini implementasi ini thread-safe: operasi jaringan dilakukan terpisah dari thread
    -+ sementara {@link android.widget.ImageView} dimanipulasi dari thread UI.</p>
    -+
    -+<p>Akan tetapi, karena operasi semakin kompleks, jenis kode seperti ini bisa semakin rumit
    -+dan sulit dipertahankan. Untuk menangani interaksi yang lebih kompleks dengan thread pekerja, Anda bisa mempertimbangkan
    -+ penggunaan {@link android.os.Handler}di thread pekerja, untuk memproses pesan yang dikirim dari
    -+ thread UI. Mungkin solusi terbaiknya adalah memperpanjang kelas {@link android.os.AsyncTask},
    -+yang akan menyederhanakan eksekusi tugas-tugas thread pekerja yang perlu berinteraksi dengan UI.</p>
    -+
    -+
    -+<h4 id="AsyncTask">Menggunakan AsyncTask</h4>
    -+
    -+<p>Dengan {@link android.os.AsyncTask}, Anda bisa melakukan pekerjaan asinkron pada antarmuka
    -+pengguna. AsyncTask memblokir operasi di thread pekerja kemudian mempublikasikan hasilnya
    -+di thread UI, tanpa mengharuskan Anda untuk menangani sendiri thread dan/atau handler sendiri.</p>
    -+
    -+<p>Untuk menggunakannya, Anda harus menempatkan {@link android.os.AsyncTask} sebagai subkelas dan mengimplementasikan metode callback {@link
    -+android.os.AsyncTask#doInBackground doInBackground()} yang berjalan di kumpulan
    -+thread latar belakang. Untuk memperbarui UI, Anda harus mengimplementasikan {@link
    -+android.os.AsyncTask#onPostExecute onPostExecute()}, yang memberikan hasil dari {@link
    -+android.os.AsyncTask#doInBackground doInBackground()} dan berjalan di thread UI, jadi Anda bisa
    -+memperbarui UI dengan aman. Selanjutnya Anda bisa menjalankan tugas dengan memanggil {@link android.os.AsyncTask#execute execute()}
    -+dari thread UI.</p>
    -+
    -+<p>Misalnya, Anda bisa mengimplementasikan contoh sebelumnya menggunakan {@link android.os.AsyncTask} dengan cara
    -+ini:</p>
    -+
    -+<pre>
    -+public void onClick(View v) {
    -+    new DownloadImageTask().execute("http://example.com/image.png");
    -+}
    -+
    -+private class DownloadImageTask extends AsyncTask&lt;String, Void, Bitmap&gt; {
    -+    /** The system calls this to perform work in a worker thread and
    -+      * delivers it the parameters given to AsyncTask.execute() */
    -+    protected Bitmap doInBackground(String... urls) {
    -+        return loadImageFromNetwork(urls[0]);
    -+    }
    -+
    -+    /** The system calls this to perform work in the UI thread and delivers
    -+      * the result from doInBackground() */
    -+    protected void onPostExecute(Bitmap result) {
    -+        mImageView.setImageBitmap(result);
    -+    }
    -+}
    -+</pre>
    -+
    -+<p>Kini UI aman dan kode jadi lebih sederhana, karena memisahkan pekerjaan ke
    -+dalam bagian-bagian yang harus dilakukan pada thread pekerja dan thread UI.</p>
    -+
    -+<p>Anda harus membaca acuan {@link android.os.AsyncTask} untuk memahami sepenuhnya
    -+cara menggunakan kelas ini, namun berikut ini ikhtisar singkat cara kerjanya:</p>
    -+
    -+<ul>
    -+<li>Anda bisa menetapkan tipe parameter, nilai kemajuan, dan nilai
    -+ akhir tugas, dengan menggunakan generik</li>
    -+<li>Metode {@link android.os.AsyncTask#doInBackground doInBackground()} berjalan secara otomatis pada
    -+thread pekerja</li>
    -+<li>{@link android.os.AsyncTask#onPreExecute onPreExecute()}, {@link
    -+android.os.AsyncTask#onPostExecute onPostExecute()}, dan {@link
    -+android.os.AsyncTask#onProgressUpdate onProgressUpdate()} semuanya dipanggil pada thread UI</li>
    -+<li>Nilai yang dikembalikan oleh {@link android.os.AsyncTask#doInBackground doInBackground()} akan dikirim ke
    -+{@link android.os.AsyncTask#onPostExecute onPostExecute()}</li>
    -+<li>Anda bisa memangil {@link android.os.AsyncTask#publishProgress publishProgress()} setiap saat di {@link
    -+android.os.AsyncTask#doInBackground doInBackground()} untuk mengeksekusi {@link
    -+android.os.AsyncTask#onProgressUpdate onProgressUpdate()} pada thread UI</li>
    -+<li>Anda bisa membatalkan tugas ini kapan saja, dari thread mana saja</li>
    -+</ul>
    -+
    -+<p class="caution"><strong>Perhatian:</strong> Masalah lain yang mungkin Anda temui saat menggunakan
    -+thread pekerja adalah restart tak terduga dalam aktivitas karena <a href="{@docRoot}guide/topics/resources/runtime-changes.html">perubahan konfigurasi runtime</a>
    -+ (seperti saat pengguna mengubah orientasi layar), yang bisa memusnahkan thread pekerja. Untuk
    -+melihat cara mempertahankan tugas selama restart ini dan cara membatalkan
    -+tugas dengan benar saat aktivitas dimusnahkan, lihat kode sumber untuk aplikasi sampel <a href="http://code.google.com/p/shelves/">Shelves</a>.</p>
    -+
    -+
    -+<h3 id="ThreadSafe">Metode thread-safe</h3>
    -+
    -+<p> Dalam beberapa situasi, metode yang Anda implementasikan bisa dipanggil dari lebih dari satu thread,
    -+dan karena itu harus ditulis agar menjadi thread-safe. </p>
    -+
    -+<p>Ini terutama terjadi untuk metode yang bisa dipanggil dari jauh &mdash;seperti metode dalam <a href="{@docRoot}guide/components/bound-services.html">layanan terikat</a>. Bila sebuah panggilan pada
    -+metode yang dijalankan dalam {@link android.os.IBinder} berasal dari proses yang sama di mana
    -+{@link android.os.IBinder IBinder} berjalan, metode ini akan dieksekusi di thread pemanggil.
    -+Akan tetapi, bila panggilan berasal proses lain, metode akan dieksekusi dalam thread yang dipilih dari
    -+ kumpulan (pool) thread yang dipertahankan sistem dalam proses yang sama seperti{@link android.os.IBinder
    -+IBinder} (tidak dieksekusi dalam thread UI proses).  Misalnya, karena metode
    -+{@link android.app.Service#onBind onBind()} layanan akan dipanggil dari thread UI
    -+proses layanan, metode yang diimplementasikan dalam objek yang dikembalikan {@link android.app.Service#onBind
    -+onBind()} (misalnya, subkelas yang mengimplementasikan metode RPC) akan dipanggil dari thread
    -+di pool. Karena layanan bisa memiliki lebih dari satu klien, maka lebih dari satu pool thread bisa melibatkan
    -+ metode {@link android.os.IBinder IBinder} yang sama sekaligus. Metode {@link android.os.IBinder
    -+IBinder} karenanya harus diimplementasikan sebagai thread-safe.</p>
    -+
    -+<p> Penyedia konten juga bisa menerima permintaan data yang berasal dalam proses lain.
    -+Meskipun kelas {@link android.content.ContentResolver} dan {@link android.content.ContentProvider}
    -+ menyembunyikan detail cara komunikasi antarproses dikelola, metode {@link
    -+android.content.ContentProvider} yang merespons permintaan itu&mdash;metode {@link
    -+android.content.ContentProvider#query query()}, {@link android.content.ContentProvider#insert
    -+insert()}, {@link android.content.ContentProvider#delete delete()}, {@link
    -+android.content.ContentProvider#update update()}, dan {@link android.content.ContentProvider#getType
    -+getType()}&mdash; dipanggil dari pool thread pada proses penyedia konten, bukan thread UI
    -+untuk proses tersebut.  Mengingat metode ini bisa dipanggil dari thread mana pun
    -+sekaligus, metode-metode ini juga harus diimplementasikan sebagai thread-safe. </p>
    -+
    -+
    -+<h2 id="IPC">Komunikasi Antarproses</h2>
    -+
    -+<p>Android menawarkan mekanisme komunikasi antarproses (IPC) menggunakan panggilan prosedur jauh
    -+ (RPC), yang mana metode ini dipanggil oleh aktivitas atau komponen aplikasi lain, namun dieksekusi dari
    -+jauh (di proses lain), bersama hasil yang dikembalikan ke
    -+pemanggil. Ini mengharuskan penguraian panggilan metode dan datanya ke tingkat yang bisa
    -+dipahami sistem operasi, mentransmisikannya dari proses lokal dan ruang alamat untuk proses jauh
    -+dan ruang proses, kemudian merakit kembali dan menetapkannya kembali di sana.  Nilai-nilai yang dikembalikan
    -+akan ditransmisikan dalam arah berlawanan.  Android menyediakan semua kode untuk melakukan transaksi IPC
    -+ ini, sehingga Anda bisa fokus pada pendefinisian dan implementasi antarmuka pemrograman RPC. </p>
    -+
    -+<p>Untuk melakukan IPC, aplikasi Anda harus diikat ke layanan, dengan menggunakan {@link
    -+android.content.Context#bindService bindService()}. Untuk informasi selengkapnya, lihat panduan pengembang <a href="{@docRoot}guide/components/services.html">Layanan</a>.</p>
    -+
    -+
    -+<!--
    -+<h2>Beginner's Path</h2>
    -+
    -+<p>For information about how to perform work in the background for an indefinite period of time
    -+(without a user interface), continue with the <b><a
    -+href="{@docRoot}guide/components/services.html">Services</a></b> document.</p>
    -+-->
    -diff --git a/docs/html-intl/intl/id/guide/components/recents.jd b/docs/html-intl/intl/id/guide/components/recents.jd
    -new file mode 100644
    -index 0000000..286fdc1
    ---- /dev/null
    -+++ b/docs/html-intl/intl/id/guide/components/recents.jd
    -@@ -0,0 +1,256 @@
    -+page.title=Layar Ikhtisar
    -+page.tags="recents","overview"
    -+
    -+@jd:body
    -+
    -+<div id="qv-wrapper">
    -+<div id="qv">
    -+
    -+  <h2>Dalam dokumen ini</h2>
    -+  <ol>
    -+    <li><a href="#adding">Menambahkan Tugas ke Layar Ikhtisar</a>
    -+      <ol>
    -+        <li><a href="#flag-new-doc">Menggunakan flag Intent untuk menambahkan tugas</a></li>
    -+        <li><a href="#attr-doclaunch">Menggunakan atribut Aktivitas untuk menambahkan tugas</a></li>
    -+      </ol>
    -+    </li>
    -+    <li><a href="#removing">Menghapus Tugas</a>
    -+      <ol>
    -+        <li><a href="#apptask-remove">Menggunakan kelas AppTask untuk menghapus tugas</a></li>
    -+        <li><a href="#retain-finished">Mempertahankan tugas yang telah selesai</a></li>
    -+      </ol>
    -+    </li>
    -+  </ol>
    -+
    -+  <h2>Kelas-kelas utama</h2>
    -+  <ol>
    -+    <li>{@link android.app.ActivityManager.AppTask}</li>
    -+    <li>{@link android.content.Intent}</li>
    -+  </ol>
    -+
    -+  <h2>Kode contoh</h2>
    -+  <ol>
    -+    <li><a href="{@docRoot}samples/DocumentCentricApps/index.html">Aplikasi yang berorientasi dokumen</a></li>
    -+  </ol>
    -+
    -+</div>
    -+</div>
    -+
    -+<p>Layar ikhtisar (juga disebut sebagai layar terbaru, daftar tugas terbaru, atau aplikasi terbaru)
    -+UI tingkat sistem yang mencantumkan <a href="{@docRoot}guide/components/activities.html">
    -+aktivitas</a> dan <a href="{@docRoot}guide/components/tasks-and-back-stack.html">tugas</a> yang baru saja diakses. Pengguna
    -+bisa menyusuri daftar ini dan memilih satu tugas untuk dilanjutkan, atau pengguna bisa menghapus tugas dari
    -+daftar dengan gerakan mengusap. Dengan dirilisnya Android 5.0 (API level 21), beberapa instance aktivitas yang
    -+sama yang berisi dokumen berbeda dapat muncul sebagai tugas di layar ikhtisar. Misalnya,
    -+Google Drive mungkin memiliki satu tugas untuk setiap beberapa dokumen Google. Setiap dokumen muncul sebagai
    -+tugas dalam layar ikhtisar.</p>
    -+
    -+<img src="{@docRoot}images/components/recents.png" alt="" width="284" />
    -+<p class="img-caption"><strong>Gambar 1.</strong> Layar ikhtisar menampilkan tiga dokumen
    -+Google Drive, masing-masing dinyatakan sebagai tugas terpisah.</p>
    -+
    -+<p>Biasanya Anda harus mengizinkan sistem mendefinisikan cara menyatakan tugas dan
    -+aktivitas di layar ikhtisar, dan Anda tidak perlu memodifikasi perilaku ini.
    -+Akan tetapi, aplikasi Anda dapat menentukan cara dan waktu munculnya aktivitas di layar ikhtisar. Kelas
    -+{@link android.app.ActivityManager.AppTask} memungkinkan Anda mengelola tugas, dan flag
    -+ aktivitas kelas {@link android.content.Intent} memungkinkan Anda menentukan kapan aktivitas ditambahkan atau dihapus dari
    -+layar ikhtisar. Selain itu, atribut <code><a href="{@docRoot}guide/topics/manifest/activity-element.html">
    -+&lt;activity&gt;</a></code> memungkinkan Anda menetapkan perilaku di manifes.</p>
    -+
    -+<h2 id="adding">Menambahkan Tugas ke Layar Ikhtisar</h2>
    -+
    -+<p>Penggunaan flag kelas {@link android.content.Intent} untuk menambahkan tugas memberi kontrol lebih besar
    -+atas waktu dan cara dokumen dibuka atau dibuka kembali di layar ikhtisar. Bila menggunakan atribut
    -+<code><a href="{@docRoot}guide/topics/manifest/activity-element.html">&lt;activity&gt;</a></code>
    -+, Anda dapat memilih antara selalu membuka dokumen dalam tugas baru atau menggunakan kembali tugas
    -+yang ada untuk dokumen tersebut.</p>
    -+
    -+<h3 id="flag-new-doc">Menggunakan flag Intent untuk menambahkan tugas</h3>
    -+
    -+<p>Bila membuat dokumen baru untuk aktivitas, Anda memanggil metode
    -+{@link android.app.ActivityManager.AppTask#startActivity(android.content.Context, android.content.Intent, android.os.Bundle) startActivity()}
    -+ dari kelas {@link android.app.ActivityManager.AppTask}, dengan meneruskannya ke intent yang
    -+menjalankan aktivitas tersebut. Untuk menyisipkan jeda logis agar sistem memperlakukan aktivitas Anda sebagai tugas
    -+baru di layar ikhtisar, teruskan flag {@link android.content.Intent#FLAG_ACTIVITY_NEW_DOCUMENT}
    -+dalam metode {@link android.content.Intent#addFlags(int) addFlags()} dari {@link android.content.Intent}
    -+yang memulai aktivitas itu.</p>
    -+
    -+<p class="note"><strong>Catatan:</strong> Flag {@link android.content.Intent#FLAG_ACTIVITY_NEW_DOCUMENT}
    -+menggantikan flag {@link android.content.Intent#FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET},
    -+yang tidak digunakan lagi pada Android 5.0 (API level 21).</p>
    -+
    -+<p>Jika Anda menetapkan flag {@link android.content.Intent#FLAG_ACTIVITY_MULTIPLE_TASK} saat membuat
    -+dokumen baru, sistem akan selalu membuat tugas baru dengan aktivitas target sebagai akar.
    -+Dengan pengaturan ini, dokumen yang sama dapat dibuka di lebih dari satu tugas. Kode berikut memperagakan
    -+cara aktivitas utama melakukannya:</p>
    -+
    -+<p class="code-caption"><a href="{@docRoot}samples/DocumentCentricApps/index.html">
    -+DocumentCentricActivity.java</a></p>
    -+<pre>
    -+public void createNewDocument(View view) {
    -+      final Intent newDocumentIntent = newDocumentIntent();
    -+      if (useMultipleTasks) {
    -+          newDocumentIntent.addFlags(Intent.FLAG_ACTIVITY_MULTIPLE_TASK);
    -+      }
    -+      startActivity(newDocumentIntent);
    -+  }
    -+
    -+  private Intent newDocumentIntent() {
    -+      boolean useMultipleTasks = mCheckbox.isChecked();
    -+      final Intent newDocumentIntent = new Intent(this, NewDocumentActivity.class);
    -+      newDocumentIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_DOCUMENT);
    -+      newDocumentIntent.putExtra(KEY_EXTRA_NEW_DOCUMENT_COUNTER, incrementAndGet());
    -+      return newDocumentIntent;
    -+  }
    -+
    -+  private static int incrementAndGet() {
    -+      Log.d(TAG, "incrementAndGet(): " + mDocumentCounter);
    -+      return mDocumentCounter++;
    -+  }
    -+}
    -+</pre>
    -+
    -+<p class="note"><strong>Catatan:</strong> Aktivitas yang dimulai dengan flag {@code FLAG_ACTIVITY_NEW_DOCUMENT}
    -+ harus telah menetapkan nilai atribut {@code android:launchMode="standard"} (default) dalam
    -+manifes.</p>
    -+
    -+<p>Bila aktivitas utama memulai aktivitas baru, sistem akan mencari tugas yang intent
    -+-nya cocok dengan nama komponen intent dalam tugas-tugas yang sudah ada dan mencari aktivitas dalam data Intent. Jika tugas
    -+tidak ditemukan, atau intent ada dalam flag {@link android.content.Intent#FLAG_ACTIVITY_MULTIPLE_TASK}
    -+, tugas baru akan dibuat dengan aktivitas tersebut sebagai akarnya. Jika ditemukan, sistem akan
    -+mengedepankan tugas itu dan meneruskan intent baru ke {@link android.app.Activity#onNewIntent onNewIntent()}.
    -+Aktivitas baru akan mendapatkan intent dan membuat dokumen baru di layar ikhtisar, seperti dalam
    -+contoh berikut:</p>
    -+
    -+<p class="code-caption"><a href="{@docRoot}samples/DocumentCentricApps/index.html">
    -+NewDocumentActivity.java</a></p>
    -+<pre>
    -+&#64;Override
    -+protected void onCreate(Bundle savedInstanceState) {
    -+    super.onCreate(savedInstanceState);
    -+    setContentView(R.layout.activity_new_document);
    -+    mDocumentCount = getIntent()
    -+            .getIntExtra(DocumentCentricActivity.KEY_EXTRA_NEW_DOCUMENT_COUNTER, 0);
    -+    mDocumentCounterTextView = (TextView) findViewById(
    -+            R.id.hello_new_document_text_view);
    -+    setDocumentCounterText(R.string.hello_new_document_counter);
    -+}
    -+
    -+&#64;Override
    -+protected void onNewIntent(Intent intent) {
    -+    super.onNewIntent(intent);
    -+    /* If FLAG_ACTIVITY_MULTIPLE_TASK has not been used, this activity
    -+    is reused to create a new document.
    -+     */
    -+    setDocumentCounterText(R.string.reusing_document_counter);
    -+}
    -+</pre>
    -+
    -+
    -+<h3 id="#attr-doclaunch">Menggunakan atribut Aktivitas untuk menambahkan tugas</h3>
    -+
    -+<p>Aktivitas juga dapat menetapkan dalam manifesnya agar selalu dimulai ke dalam tugas baru dengan menggunakan
    -+atribut <code><a href="{@docRoot}guide/topics/manifest/activity-element.html">&lt;activity&gt;</a></code>
    -+, <a href="{@docRoot}guide/topics/manifest/activity-element.html#dlmode">
    -+{@code android:documentLaunchMode}</a>. Atribut ini memiliki empat nilai yang menghasilkan efek berikut
    -+bila pengguna membuka dokumen dengan aplikasi:</p>
    -+
    -+<dl>
    -+  <dt>"{@code intoExisting}"</dt>
    -+  <dd>Aktivitas menggunakan kembali tugas yang ada untuk dokumen tersebut. Ini sama dengan mengatur flag
    -+ {@link android.content.Intent#FLAG_ACTIVITY_NEW_DOCUMENT} <em>tanpa</em> mengatur flag
    -+ {@link android.content.Intent#FLAG_ACTIVITY_MULTIPLE_TASK}, seperti dijelaskan dalam
    -+ <a href="#flag-new-doc">Menggunakan flag Intent untuk menambahkan tugas</a>, di atas.</dd>
    -+
    -+  <dt>"{@code always}"</dt>
    -+  <dd>Aktivitas ini membuat tugas baru untuk dokumen, meski dokumen sudah dibuka. Menggunakan
    -+ nilai ini sama dengan menetapkan flag {@link android.content.Intent#FLAG_ACTIVITY_NEW_DOCUMENT}
    -+ maupun {@link android.content.Intent#FLAG_ACTIVITY_MULTIPLE_TASK}.</dd>
    -+
    -+  <dt>"{@code none”}"</dt>
    -+  <dd>Aktivitas ini tidak membuat tugas baru untuk dokumen. Layar ikhtisar memperlakukan
    -+ aktivitas seperti itu secara default: satu tugas ditampilkan untuk aplikasi, yang
    -+dilanjutkan dari aktivitas apa pun yang terakhir dipanggil pengguna.</dd>
    -+
    -+  <dt>"{@code never}"</dt>
    -+  <dd>Aktivitas ini tidak membuat tugas baru untuk dokumen. Mengatur nilai ini akan mengesampingkan
    -+ perilaku flag {@link android.content.Intent#FLAG_ACTIVITY_NEW_DOCUMENT}
    -+ dan {@link android.content.Intent#FLAG_ACTIVITY_MULTIPLE_TASK}, jika salah satunya ditetapkan di
    -+intent, dan layar ikhtisar menampilkan satu tugas untuk aplikasi, yang dilanjutkan dari
    -+ aktivitas apa pun yang terakhir dipanggil pengguna.</dd>
    -+</dl>
    -+
    -+<p class="note"><strong>Catatan:</strong> Untuk nilai selain {@code none} dan {@code never},
    -+aktivitas harus didefinisikan dengan {@code launchMode="standard"}. Jika atribut ini tidak ditetapkan, maka
    -+{@code documentLaunchMode="none"} akan digunakan.</p>
    -+
    -+<h2 id="removing">Menghapus Tugas</h2>
    -+
    -+<p>Secara default, tugas dokumen secara otomatis dihapus dari layar ikhtisar bila aktivitasnya
    -+selesai. Anda bisa mengesampingkan perilaku ini dengan kelas {@link android.app.ActivityManager.AppTask},
    -+dengan flag {@link android.content.Intent} atau atribut <code><a href="{@docRoot}guide/topics/manifest/activity-element.html">
    -+&lt;activity&gt;</a></code>.</p>
    -+
    -+<p>Kapan saja Anda bisa mengecualikan tugas dari layar ikhtisar secara keseluruhan dengan menetapkan atribut
    -+<code><a href="{@docRoot}guide/topics/manifest/activity-element.html">&lt;activity&gt;</a></code>
    -+, <a href="{@docRoot}guide/topics/manifest/activity-element.html#exclude">
    -+{@code android:excludeFromRecents}</a> hingga {@code true}.</p>
    -+
    -+<p>Anda bisa menetapkan jumlah maksimum tugas yang dapat disertakan aplikasi Anda dalam layar ikhtisar dengan menetapkan
    -+atribut <code><a href="{@docRoot}guide/topics/manifest/activity-element.html">&lt;activity&gt;</a></code>
    -+ <a href="{@docRoot}guide/topics/manifest/activity-element.html#maxrecents">{@code android:maxRecents}
    -+</a> ke satu nilai integer. Nilai default-nya adalah 16. Bila telah mencapai jumlah maksimum, tugas yang terakhir
    -+digunakan akan dihapus dari layar ikhtisar. Nilai maksimum {@code android:maxRecents}
    -+ adalah 50 (25 pada perangkat dengan memori sedikit); nilai yang kurang dari 1 tidak berlaku.</p>
    -+
    -+<h3 id="#apptask-remove">Menggunakan kelas AppTask untuk menghapus tugas</h3>
    -+
    -+<p>Dalam aktivitas yang membuat tugas baru di layar ikhtisar, Anda bisa
    -+menetapkan kapan menghapus tugas dan menyelesaikan semua aktivitas yang terkait dengannya
    -+dengan memanggil metode {@link android.app.ActivityManager.AppTask#finishAndRemoveTask() finishAndRemoveTask()}.</p>
    -+
    -+<p class="code-caption"><a href="{@docRoot}samples/DocumentCentricApps/index.html">
    -+NewDocumentActivity.java</a></p>
    -+<pre>
    -+public void onRemoveFromRecents(View view) {
    -+    // The document is no longer needed; remove its task.
    -+    finishAndRemoveTask();
    -+}
    -+</pre>
    -+
    -+<p class="note"><strong>Catatan:</strong> Penggunaan metode
    -+{@link android.app.ActivityManager.AppTask#finishAndRemoveTask() finishAndRemoveTask()}
    -+akan mengesampingkan penggunaan tag {@link android.content.Intent#FLAG_ACTIVITY_RETAIN_IN_RECENTS}, seperti
    -+dibahas di bawah ini.</p>
    -+
    -+<h3 id="#retain-finished">Mempertahankan tugas yang telah selesai</h3>
    -+
    -+<p>Jika Anda ingin mempertahankan tugas di layar ikhtisar, sekalipun aktivitas sudah selesai, teruskan
    -+flag {@link android.content.Intent#FLAG_ACTIVITY_RETAIN_IN_RECENTS} dalam metode
    -+{@link android.content.Intent#addFlags(int) addFlags()} dari Intent yang memulai aktivitas itu.</p>
    -+
    -+<p class="code-caption"><a href="{@docRoot}samples/DocumentCentricApps/index.html">
    -+DocumentCentricActivity.java</a></p>
    -+<pre>
    -+private Intent newDocumentIntent() {
    -+    final Intent newDocumentIntent = new Intent(this, NewDocumentActivity.class);
    -+    newDocumentIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_DOCUMENT |
    -+      android.content.Intent.FLAG_ACTIVITY_RETAIN_IN_RECENTS);
    -+    newDocumentIntent.putExtra(KEY_EXTRA_NEW_DOCUMENT_COUNTER, incrementAndGet());
    -+    return newDocumentIntent;
    -+}
    -+</pre>
    -+
    -+<p>Untuk memperoleh efek yang sama, tetapkan atribut
    -+<code><a href="{@docRoot}guide/topics/manifest/activity-element.html">&lt;activity&gt;</a></code>
    -+ <a href="{@docRoot}guide/topics/manifest/activity-element.html#autoremrecents">
    -+{@code android:autoRemoveFromRecents}</a> hingga {@code false}. Nilai default-nya adalah {@code true}
    -+untuk aktivitas dokumen, dan {@code false} untuk aktivitas biasa. Penggunaan atribut ini akan mengesampingkan flag
    -+{@link android.content.Intent#FLAG_ACTIVITY_RETAIN_IN_RECENTS}, yang telah dibahas sebelumnya.</p>
    -+
    -+
    -+
    -+
    -+
    -+
    -+
    -diff --git a/docs/html-intl/intl/id/guide/components/services.jd b/docs/html-intl/intl/id/guide/components/services.jd
    -new file mode 100644
    -index 0000000..b36e565
    ---- /dev/null
    -+++ b/docs/html-intl/intl/id/guide/components/services.jd
    -@@ -0,0 +1,813 @@
    -+page.title=Layanan
    -+@jd:body
    -+
    -+<div id="qv-wrapper">
    -+<ol id="qv">
    -+<h2>Dalam dokumen ini</h2>
    -+<ol>
    -+<li><a href="#Basics">Dasar-Dasar</a></li>
    -+<ol>
    -+  <li><a href="#Declaring">Mendeklarasikan layanan dalam manifes</a></li>
    -+</ol>
    -+<li><a href="#CreatingAService">Membuat Layanan yang Sudah Dimulai</a>
    -+  <ol>
    -+    <li><a href="#ExtendingIntentService">Memperluas kelas IntentService</a></li>
    -+    <li><a href="#ExtendingService">Memperluas kelas Layanan</a></li>
    -+    <li><a href="#StartingAService">Memulai layanan</a></li>
    -+    <li><a href="#Stopping">Menghentikan layanan</a></li>
    -+  </ol>
    -+</li>
    -+<li><a href="#CreatingBoundService">Membuat Layanan Terikat</a></li>
    -+<li><a href="#Notifications">Mengirim Pemberitahuan ke Pengguna</a></li>
    -+<li><a href="#Foreground">Menjalankan Layanan di Latar Depan</a></li>
    -+<li><a href="#Lifecycle">Mengelola Daur Hidup Layanan</a>
    -+<ol>
    -+  <li><a href="#LifecycleCallbacks">Mengimplementasikan callback daur hidup</a></li>
    -+</ol>
    -+</li>
    -+</ol>
    -+
    -+<h2>Kelas-kelas utama</h2>
    -+<ol>
    -+  <li>{@link android.app.Service}</li>
    -+  <li>{@link android.app.IntentService}</li>
    -+</ol>
    -+
    -+<h2>Contoh</h2>
    -+<ol>
    -+  <li><a href="{@docRoot}resources/samples/ApiDemos/src/com/example/android/apis/app/ServiceStartArguments.html">{@code
    -+      ServiceStartArguments}</a></li>
    -+  <li><a href="{@docRoot}resources/samples/ApiDemos/src/com/example/android/apis/app/LocalService.html">{@code
    -+      LocalService}</a></li>
    -+</ol>
    -+
    -+<h2>Lihat juga</h2>
    -+<ol>
    -+<li><a href="{@docRoot}guide/components/bound-services.html">Layanan Terikat</a></li>
    -+</ol>
    -+
    -+</div>
    -+
    -+
    -+<p>{@link android.app.Service} adalah sebuah komponen aplikasi yang bisa melakukan
    -+operasi yang berjalan lama di latar belakang dan tidak menyediakan antarmuka pengguna. Komponen
    -+aplikasi lain bisa memulai layanan dan komponen aplikasi tersebut akan terus berjalan
    -+di latar belakang walaupun pengguna beralih ke aplikasi lain. Selain itu, komponen bisa mengikat ke layanan
    -+untuk berinteraksi dengannya dan bahkan melakukan komunikasi antarproses (IPC). Misalnya, layanan mungkin
    -+menangani transaksi jaringan, memutar musik, melakukan file I/O, atau berinteraksi dengan penyedia konten
    -+dari latar belakang.</p>
    -+
    -+<p>Ada dua bentuk dasar layanan:</p>
    -+
    -+<dl>
    -+  <dt>Sudah Dimulai</dt>
    -+  <dd>Layanan "sudah dimulai" bila komponen aplikasi (misalnya aktivitas) memulainya dengan
    -+memanggil {@link android.content.Context#startService startService()}. Sesudah dimulai, layanan
    -+bisa berjalan terus-menerus di latar belakang walaupun komponen yang memulainya telah dimusnahkan. Biasanya,
    -+layanan yang sudah dimulai akan melakukan operasi tunggal dan tidak mengembalikan hasil ke pemanggilnya.
    -+Misalnya, layanan bisa mengunduh atau mengunggah file melalui jaringan. Bila operasi selesai,
    -+layanan seharusnya berhenti sendiri.</dd>
    -+  <dt>Terikat</dt>
    -+  <dd>Layanan "terikat" bila komponen aplikasi mengikat kepadanya dengan memanggil {@link
    -+android.content.Context#bindService bindService()}. Layanan terikat menawarkan antarmuka
    -+klien-server yang memungkinkan komponen berinteraksi dengan layanan tersebut, mengirim permintaan, mendapatkan hasil dan bahkan
    -+melakukannya pada sejumlah proses dengan komunikasi antarproses (IPC). Layanan terikat hanya berjalan selama
    -+ada komponen aplikasi lain yang terikat padanya. Sejumlah komponen bisa terikat pada layanan secara bersamaan,
    -+namun bila semuanya melepas ikatan, layanan tersebut akan dimusnahkan.</dd>
    -+</dl>
    -+
    -+<p>Walaupun dokumentasi ini secara umum membahas kedua jenis layanan secara terpisah, layanan
    -+Anda bisa menggunakan keduanya&mdash;layanan bisa dimulai (untuk berjalan terus-menerus) sekaligus memungkinkan pengikatan.
    -+Cukup mengimplementasikan dua metode callback: {@link
    -+android.app.Service#onStartCommand onStartCommand()} untuk memungkinkan komponen memulainya dan {@link
    -+android.app.Service#onBind onBind()} untuk memungkinkan pengikatan.</p>
    -+
    -+<p>Apakah aplikasi Anda sudah dimulai, terikat, atau keduanya, semua komponen aplikasi
    -+bisa menggunakan layanan (bahkan dari aplikasi terpisah), demikian pula semua komponen bisa menggunakan
    -+suatu aktivitas&mdash;dengan memulainya dengan {@link android.content.Intent}. Akan tetapi, Anda bisa mendeklarasikan
    -+layanan sebagai privat, pada file manifes, dan memblokir akses dari aplikasi lain. Hal ini
    -+dibahas selengkapnya di bagian tentang <a href="#Declaring">Mendeklarasikan layanan dalam
    -+manifes</a>.</p>
    -+
    -+<p class="caution"><strong>Perhatian:</strong> Layanan berjalan di
    -+thread utama proses yang menjadi host-nya&mdash;layanan <strong>tidak</strong> membuat thread-nya sendiri
    -+dan <strong>tidak</strong> berjalan pada proses terpisah (kecuali bila Anda tentukan demikian). Artinya,
    -+jika layanan Anda akan melakukan pekerjaan yang membutuhkan tenaga CPU besar atau operasi yang memblokir (seperti
    -+pemutaran MP3 atau jaringan), Anda perlu membuat thread baru dalam layanan untuk melakukan pekerjaan tersebut. Dengan menggunakan
    -+thread terpisah, Anda mengurangi risiko terjadinya kesalahan Aplikasi Tidak Merespons (Application Not Responding/ANR) dan
    -+thread utama aplikasi bisa tetap dikhususkan pada interaksi pengguna dengan aktivitas Anda.</p>
    -+
    -+
    -+<h2 id="Basics">Dasar-Dasar</h2>
    -+
    -+<div class="sidebox-wrapper">
    -+<div class="sidebox">
    -+  <h3>Haruskah menggunakan layanan atau thread?</h3>
    -+  <p>Layanan sekadar komponen yang bisa berjalan di latar belakang walaupun pengguna sedang tidak
    -+berinteraksi dengan aplikasi Anda. Sehingga, Anda harus membuat layanan bila memang itu
    -+yang dibutuhkan.</p>
    -+  <p>Bila Anda perlu melakukan pekerjaan di luar thread utama, namun hanya bila pengguna sedang berinteraksi
    -+dengan aplikasi, maka Anda harus membuat thread baru sebagai ganti layanan baru. Misalnya,
    -+bila Anda ingin memutar musik, namun hanya saat aktivitas Anda berjalan, Anda bisa membuat
    -+thread dalam {@link android.app.Activity#onCreate onCreate()}, mulai menjalankannya di {@link
    -+android.app.Activity#onStart onStart()}, kemudian menghentikannya di {@link android.app.Activity#onStop
    -+onStop()}. Pertimbangkan juga untuk menggunakan {@link android.os.AsyncTask} atau {@link android.os.HandlerThread},
    -+sebagai ganti kelas {@link java.lang.Thread} yang lazim digunakan. Lihat dokumen <a href="{@docRoot}guide/components/processes-and-threads.html#Threads">Proses dan
    -+Threading</a> untuk informasi selengkapnya tentang thread.</p>
    -+  <p>Ingatlah jika menggunakan layanan, layanan tersebut tetap berjalan di thread utama aplikasi Anda secara
    -+default, jadi Anda harus tetap membuat thread baru dalam layanan bila layanan tersebut melakukan operasi yang intensif
    -+atau operasi yang memblokir.</p>
    -+</div>
    -+</div>
    -+
    -+<p>Untuk membuat layanan, Anda harus membuat subkelas {@link android.app.Service} (atau
    -+salah satu dari subkelasnya yang ada). Dalam implementasi, Anda perlu mengesampingkan sebagian metode callback yang
    -+menangani aspek utama daur hidup layanan dan memberikan mekanisme bagi komponen untuk mengikat
    -+pada layanan, bila dibutuhkan. Metode callback terpenting yang perlu Anda kesampingkan adalah:</p>
    -+
    -+<dl>
    -+  <dt>{@link android.app.Service#onStartCommand onStartCommand()}</dt>
    -+    <dd>Sistem akan memanggil metode ini bila komponen lain, misalnya aktivitas,
    -+meminta dimulainya layanan, dengan memanggil {@link android.content.Context#startService
    -+startService()}. Setelah metode ini dieksekusi, layanan akan dimulai dan bisa berjalan di
    -+latar belakang terus-menerus. Jika mengimplementasikan ini, Anda bertanggung jawab menghentikan layanan bila
    -+bila pekerjaannya selesai, dengan memanggil {@link android.app.Service#stopSelf stopSelf()} atau {@link
    -+android.content.Context#stopService stopService()}. (Jika hanya ingin menyediakan pengikatan, Anda tidak
    -+perlu mengimplementasikan metode ini.)</dd>
    -+  <dt>{@link android.app.Service#onBind onBind()}</dt>
    -+    <dd>Sistem akan memanggil metode ini bila komponen lain ingin mengikat pada
    -+layanan (misalnya untuk melakukan RPC), dengan memanggil {@link android.content.Context#bindService
    -+bindService()}. Dalam mengimplementasikan metode ini, Anda harus menyediakan antarmuka yang digunakan
    -+klien untuk berkomunikasi dengan layanan, dengan mengembalikan {@link android.os.IBinder}. Anda harus selalu
    -+mengimplementasikan metode ini, namun jika tidak ingin mengizinkan pengikatan, Anda perlu mengembalikan null.</dd>
    -+  <dt>{@link android.app.Service#onCreate()}</dt>
    -+    <dd>Sistem memanggil metode ini bila layanan dibuat untuk pertama kalinya, untuk melakukan prosedur
    -+penyiapan satu kali (sebelum memanggil {@link android.app.Service#onStartCommand onStartCommand()} atau
    -+{@link android.app.Service#onBind onBind()}). Bila layanan sudah berjalan, metode ini tidak
    -+dipanggil.</dd>
    -+  <dt>{@link android.app.Service#onDestroy()}</dt>
    -+    <dd>Sistem memanggil metode ini bila layanan tidak lagi digunakan dan sedang dimusnahkan.
    -+Layanan Anda perlu mengimplementasikannya untuk membersihkan sumber daya seperti thread, listener
    -+terdaftar, penerima, dll. Ini adalah panggilan terakhir yang diterima layanan.</dd>
    -+</dl>
    -+
    -+<p>Bila komponen memulai layanan dengan memanggil {@link
    -+android.content.Context#startService startService()} (yang menyebabkan panggilan ke {@link
    -+android.app.Service#onStartCommand onStartCommand()}), maka layanan
    -+terus berjalan hingga terhenti sendiri dengan {@link android.app.Service#stopSelf()} atau bila komponen
    -+lain menghentikannya dengan memanggil {@link android.content.Context#stopService stopService()}.</p>
    -+
    -+<p>Bila komponen memanggil
    -+{@link android.content.Context#bindService bindService()} untuk membuat layanan (dan {@link
    -+android.app.Service#onStartCommand onStartCommand()} <em>tidak</em> dipanggil), maka layanan hanya berjalan
    -+selama komponen terikat kepadanya. Setelah layanan dilepas ikatannya dari semua klien,
    -+sistem akan menghancurkannya.</p>
    -+
    -+<p>Sistem Android akan menghentikan paksa layanan hanya bila memori tinggal sedikit dan sistem harus memulihkan
    -+sumber daya sistem untuk aktivitas yang mendapatkan fokus pengguna. Jika layanan terikat pada suatu aktivitas yang mendapatkan
    -+fokus pengguna, layanan tersebut lebih kecil kemungkinannya untuk dimatikan, dan jika layanan dideklarasikan untuk <a href="#Foreground">berjalan di latar depan</a> (akan dibahas kemudian), maka sudah hampir pasti ia tidak akan dimatikan.
    -+Sebaliknya, bila layanan sudah dimulai dan berjalan lama, maka sistem akan menurunkan posisinya
    -+dalam daftar tugas latar belakang seiring waktu dan layanan akan sangat rentan untuk
    -+dimatikan&mdash;bila layanan Anda dimulai, maka Anda harus mendesainnya agar bisa menangani restart
    -+oleh sistem dengan baik. Jika sistem mematikan layanan Anda, layanan akan dimulai kembali begitu sumber daya
    -+kembali tersedia (tetapi ini juga bergantung pada nilai yang Anda kembalikan dari {@link
    -+android.app.Service#onStartCommand onStartCommand()}, sebagaimana akan dibahas nanti). Untuk informasi selengkapnya
    -+tentang kapan sistem mungkin akan memusnahkan layanan, lihat dokumen
    -+<a href="{@docRoot}guide/components/processes-and-threads.html">Proses dan Threading</a>.</p>
    -+
    -+<p>Dalam bagian selanjutnya, Anda akan melihat bagaimana membuat masing-masing tipe layanan dan cara menggunakannya
    -+dari komponen aplikasi lain.</p>
    -+
    -+
    -+
    -+<h3 id="Declaring">Mendeklarasikan layanan dalam manifes</h3>
    -+
    -+<p>Sebagaimana aktivitas (dan komponen lainnya), Anda harus mendeklarasikan semua layanan dalam file manifes
    -+aplikasi Anda.</p>
    -+
    -+<p>Untuk mendeklarasikan layanan Anda, tambahkan sebuah elemen <a href="{@docRoot}guide/topics/manifest/service-element.html">{@code &lt;service&gt;}</a>
    -+sebagai anak
    -+elemen <a href="{@docRoot}guide/topics/manifest/application-element.html">{@code &lt;application&gt;}</a>. Misalnya:</p>
    -+
    -+<pre>
    -+&lt;manifest ... &gt;
    -+  ...
    -+  &lt;application ... &gt;
    -+      &lt;service android:name=".ExampleService" /&gt;
    -+      ...
    -+  &lt;/application&gt;
    -+&lt;/manifest&gt;
    -+</pre>
    -+
    -+<p>Lihat acuan elemen <a href="{@docRoot}guide/topics/manifest/service-element.html">{@code &lt;service&gt;}</a>
    -+untuk informasi selengkapnya tentang cara mendeklarasikan layanan Anda dalam manifes.</p>
    -+
    -+<p>Ada atribut lain yang bisa Anda sertakan dalam elemen <a href="{@docRoot}guide/topics/manifest/service-element.html">{@code &lt;service&gt;}</a> untuk
    -+mendefinisikan properti seperti izin yang dibutuhkan untuk memulai layanan dan proses
    -+tempat berjalannya layanan. <a href="{@docRoot}guide/topics/manifest/service-element.html#nm">{@code android:name}</a> adalah satu-satunya atribut yang diperlukan
    -+&mdash;atribut tersebut menetapkan nama kelas layanan. Setelah
    -+mempublikasikan aplikasi, Anda tidak boleh mengubah nama ini, karena jika melakukannya, Anda bisa merusak
    -+kode karena dependensi terhadap intent eksplisit untuk memulai atau mengikat layanan (bacalah posting blog berjudul <a href="http://android-developers.blogspot.com/2011/06/things-that-cannot-change.html">Things
    -+That Cannot Change</a>).
    -+
    -+<p>Untuk memastikan aplikasi Anda aman, <strong>selalu gunakan intent eksplisit saat memulai atau mengikat
    -+{@link android.app.Service} Anda</strong> dan jangan mendeklarasikan filter intent untuk layanan. Jika
    -+Anda perlu membiarkan adanya ambiguitas tentang layanan mana yang dimulai, Anda bisa
    -+menyediakan filter intent bagi layanan dan tidak memasukkan nama komponen pada {@link
    -+android.content.Intent}, namun Anda juga harus menyesuaikan paket bagi intent tersebut dengan {@link
    -+android.content.Intent#setPackage setPackage()}, yang memberikan klarifikasi memadai bagi
    -+target layanan.</p>
    -+
    -+<p>Anda juga bisa memastikan layanan tersedia hanya bagi aplikasi Anda dengan
    -+menyertakan atribut <a href="{@docRoot}guide/topics/manifest/service-element.html#exported">{@code android:exported}</a>
    -+dan mengaturnya ke {@code "false"}. Hal ini efektif menghentikan aplikasi lain agar tidak memulai
    -+layanan Anda, bahkan saat menggunakan intent eksplisit.</p>
    -+
    -+
    -+
    -+
    -+<h2 id="CreatingStartedService">Membuat Layanan yang Sudah Dimulai</h2>
    -+
    -+<p>Layanan yang sudah dimulai adalah layanan yang dimulai komponen lain dengan memanggil {@link
    -+android.content.Context#startService startService()}, yang menyebabkan panggilan ke metode
    -+{@link android.app.Service#onStartCommand onStartCommand()} layanan.</p>
    -+
    -+<p>Bila layanan sudah dimulai, layanan tersebut memiliki daur hidup yang tidak bergantung pada
    -+komponen yang memulainya dan bisa berjalan terus-menerus di latar belakang walaupun
    -+komponen yang memulainya dimusnahkan. Dengan sendirinya, layanan akan berhenti sendiri bila pekerjaannya
    -+selesai dengan memanggil {@link android.app.Service#stopSelf stopSelf()}, atau komponen lain bisa menghentikannya
    -+dengan memanggil {@link android.content.Context#stopService stopService()}.</p>
    -+
    -+<p>Komponen aplikasi seperti aktivitas bisa memulai layanan dengan memanggil {@link
    -+android.content.Context#startService startService()} dan meneruskan {@link android.content.Intent}
    -+yang menetapkan layanan dan menyertakan data untuk digunakan layanan. Layanan menerima
    -+{@link android.content.Intent} ini dalam metode {@link android.app.Service#onStartCommand
    -+onStartCommand()}.</p>
    -+
    -+<p>Sebagai contoh, anggaplah aktivitas perlu menyimpan data ke database online. Aktivitas tersebut bisa
    -+memulai layanan pendamping dan mengiriminya data untuk disimpan dengan meneruskan intent ke {@link
    -+android.content.Context#startService startService()}. Layanan akan menerima intent dalam {@link
    -+android.app.Service#onStartCommand onStartCommand()}, menghubungkan ke Internet dan melakukan
    -+transaksi database. Bila transaksi selesai, layanan akan berhenti sendiri dan
    -+dimusnahkan.</p>
    -+
    -+<p class="caution"><strong>Perhatian:</strong> Layanan berjalan dalam proses yang sama dengan aplikasi
    -+tempatnya dideklarasikan dan dalam thread utama aplikasi tersebut, secara default. Jadi, bila layanan Anda
    -+melakukan operasi yang intensif atau operasi pemblokiran saat pengguna berinteraksi dengan aktivitas dari
    -+aplikasi yang sama, layanan akan memperlambat kinerja aktivitas. Agar tidak memengaruhi
    -+kinerja aplikasi, Anda harus memulai thread baru di dalam layanan.</p>
    -+
    -+<p>Biasanya, ada dua kelas yang bisa Anda perluas untuk membuat layanan yang sudah dimulai:</p>
    -+<dl>
    -+  <dt>{@link android.app.Service}</dt>
    -+  <dd>Ini adalah kelas dasar untuk semua layanan. Bila memperluas kelas ini, Anda perlu
    -+membuat thread baru sebagai tempat melaksanakan semua pekerjaan layanan tersebut, karena layanan
    -+menggunakan thread utama aplikasi Anda secara default, dan hal ini bisa memperlambat
    -+kinerja aktivitas yang dijalankan aplikasi Anda.</dd>
    -+  <dt>{@link android.app.IntentService}</dt>
    -+  <dd>Ini adalah subkelas {@link android.app.Service} yang menggunakan thread pekerja untuk menangani
    -+semua permintaan memulai, satu per satu. Ini adalah pilihan terbaik jika Anda tidak mengharuskan layanan
    -+menangani beberapa permintaan sekaligus. Anda cukup mengimplementasikan {@link
    -+android.app.IntentService#onHandleIntent onHandleIntent()}, yang menerima intent untuk setiap
    -+permintaan memulai agar bisa melakukan pekerjaan latar belakang.</dd>
    -+</dl>
    -+
    -+<p>Bagian selanjutnya membahas cara mengimplementasikan layanan Anda menggunakan
    -+salah satu dari kelas-kelas ini.</p>
    -+
    -+
    -+<h3 id="ExtendingIntentService">Memperluas kelas IntentService</h3>
    -+
    -+<p>Mengingat kebanyakan layanan yang sudah dimulai tidak perlu menangani beberapa permintaan
    -+sekaligus (yang bisa berupa skenario multi-threading berbahaya), mungkin Anda sebaiknya mengimplementasikan
    -+layanan menggunakan kelas {@link android.app.IntentService}.</p>
    -+
    -+<p>Berikut ini yang dilakukan {@link android.app.IntentService}:</p>
    -+
    -+<ul>
    -+  <li>Membuat thread pekerja default yang menjalankan semua intent yang disampaikan ke {@link
    -+android.app.Service#onStartCommand onStartCommand()} terpisah dari thread utama aplikasi
    -+Anda.</li>
    -+  <li>Membuat antrean pekerjaan yang meneruskan intent satu per satu ke implementasi {@link
    -+android.app.IntentService#onHandleIntent onHandleIntent()}, sehingga Anda tidak perlu
    -+mengkhawatirkan multi-threading.</li>
    -+  <li>Menghentikan layanan setelah semua permintaan memulai telah ditangani, jadi Anda tidak perlu memanggil
    -+{@link android.app.Service#stopSelf}.</li>
    -+  <li>Menyediakan implementasi default {@link android.app.IntentService#onBind onBind()} yang
    -+mengembalikan null.</li>
    -+  <li>Menyediakan implementasi default {@link android.app.IntentService#onStartCommand
    -+onStartCommand()} yang mengirimkan intent ke antrean pekerjaan kemudian ke implementasi {@link
    -+android.app.IntentService#onHandleIntent onHandleIntent()} Anda.</li>
    -+</ul>
    -+
    -+<p>Oleh karena itu, Anda hanya perlu mengimplementasikan {@link
    -+android.app.IntentService#onHandleIntent onHandleIntent()} untuk melakukan pekerjaan yang diberikan oleh
    -+klien. (Akan tetapi, Anda juga perlu menyediakan konstruktor kecil bagi layanan.)</p>
    -+
    -+<p>Berikut ini contoh implementasi {@link android.app.IntentService}:</p>
    -+
    -+<pre>
    -+public class HelloIntentService extends IntentService {
    -+
    -+  /**
    -+   * A constructor is required, and must call the super {@link android.app.IntentService#IntentService}
    -+   * constructor with a name for the worker thread.
    -+   */
    -+  public HelloIntentService() {
    -+      super("HelloIntentService");
    -+  }
    -+
    -+  /**
    -+   * The IntentService calls this method from the default worker thread with
    -+   * the intent that started the service. When this method returns, IntentService
    -+   * stops the service, as appropriate.
    -+   */
    -+  &#64;Override
    -+  protected void onHandleIntent(Intent intent) {
    -+      // Normally we would do some work here, like download a file.
    -+      // For our sample, we just sleep for 5 seconds.
    -+      long endTime = System.currentTimeMillis() + 5*1000;
    -+      while (System.currentTimeMillis() &lt; endTime) {
    -+          synchronized (this) {
    -+              try {
    -+                  wait(endTime - System.currentTimeMillis());
    -+              } catch (Exception e) {
    -+              }
    -+          }
    -+      }
    -+  }
    -+}
    -+</pre>
    -+
    -+<p>Anda hanya memerlukan: konstruktor dan implementasi {@link
    -+android.app.IntentService#onHandleIntent onHandleIntent()}.</p>
    -+
    -+<p>Jika Anda memutuskan untuk juga mengesampingkan metode callback lain, seperti {@link
    -+android.app.IntentService#onCreate onCreate()}, {@link
    -+android.app.IntentService#onStartCommand onStartCommand()}, atau {@link
    -+android.app.IntentService#onDestroy onDestroy()}, pastikan memanggil implementasi super, sehingga
    -+{@link android.app.IntentService} bisa menangani hidup thread pekerja dengan baik.</p>
    -+
    -+<p>Misalnya, {@link android.app.IntentService#onStartCommand onStartCommand()} harus mengembalikan
    -+implementasi default (yang merupakan cara penyampaian intent ke {@link
    -+android.app.IntentService#onHandleIntent onHandleIntent()}):</p>
    -+
    -+<pre>
    -+&#64;Override
    -+public int onStartCommand(Intent intent, int flags, int startId) {
    -+    Toast.makeText(this, "service starting", Toast.LENGTH_SHORT).show();
    -+    return super.onStartCommand(intent,flags,startId);
    -+}
    -+</pre>
    -+
    -+<p>Selain {@link android.app.IntentService#onHandleIntent onHandleIntent()}, satu-satunya metode lain
    -+yang tidak mengharuskan Anda memanggil super kelas adalah {@link android.app.IntentService#onBind
    -+onBind()} (namun Anda hanya perlu mengimplementasikannya bila layanan mengizinkan pengikatan).</p>
    -+
    -+<p>Dalam bagian berikutnya, Anda akan melihat bagaimana layanan serupa diimplementasikan saat
    -+memperluas kelas {@link android.app.Service} basis, yang membutuhkan kode lebih banyak lagi, namun mungkin
    -+cocok jika Anda perlu menangani beberapa permintaan memulai sekaligus.</p>
    -+
    -+
    -+<h3 id="ExtendingService">Memperluas kelas Layanan</h3>
    -+
    -+<p>Seperti telah Anda lihat di bagian sebelumnya, menggunakan {@link android.app.IntentService} membuat
    -+implementasi layanan yang sudah dimulai jadi sangat sederhana. Namun, bila Anda mengharuskan layanan untuk
    -+melakukan multi-threading (sebagai ganti memproses permintaan memulai melalui antrean pekerjaan), maka Anda
    -+bisa memperluas kelas {@link android.app.Service} untuk menangani masing-masing intent.</p>
    -+
    -+<p>Sebagai perbandingan, contoh kode berikut ini adalah implementasi kelas {@link
    -+android.app.Service} yang melakukan pekerjaan yang persis sama dengan contoh di atas menggunakan {@link
    -+android.app.IntentService}. Artinya, untuk setiap permintaan memulai, kode tersebut akan menggunakan thread pekerja
    -+untuk melakukan pekerjaan dan memproses permintaan satu per satu.</p>
    -+
    -+<pre>
    -+public class HelloService extends Service {
    -+  private Looper mServiceLooper;
    -+  private ServiceHandler mServiceHandler;
    -+
    -+  // Handler that receives messages from the thread
    -+  private final class ServiceHandler extends Handler {
    -+      public ServiceHandler(Looper looper) {
    -+          super(looper);
    -+      }
    -+      &#64;Override
    -+      public void handleMessage(Message msg) {
    -+          // Normally we would do some work here, like download a file.
    -+          // For our sample, we just sleep for 5 seconds.
    -+          long endTime = System.currentTimeMillis() + 5*1000;
    -+          while (System.currentTimeMillis() &lt; endTime) {
    -+              synchronized (this) {
    -+                  try {
    -+                      wait(endTime - System.currentTimeMillis());
    -+                  } catch (Exception e) {
    -+                  }
    -+              }
    -+          }
    -+          // Stop the service using the startId, so that we don't stop
    -+          // the service in the middle of handling another job
    -+          stopSelf(msg.arg1);
    -+      }
    -+  }
    -+
    -+  &#64;Override
    -+  public void onCreate() {
    -+    // Start up the thread running the service.  Note that we create a
    -+    // separate thread because the service normally runs in the process's
    -+    // main thread, which we don't want to block.  We also make it
    -+    // background priority so CPU-intensive work will not disrupt our UI.
    -+    HandlerThread thread = new HandlerThread("ServiceStartArguments",
    -+            Process.THREAD_PRIORITY_BACKGROUND);
    -+    thread.start();
    -+
    -+    // Get the HandlerThread's Looper and use it for our Handler
    -+    mServiceLooper = thread.getLooper();
    -+    mServiceHandler = new ServiceHandler(mServiceLooper);
    -+  }
    -+
    -+  &#64;Override
    -+  public int onStartCommand(Intent intent, int flags, int startId) {
    -+      Toast.makeText(this, "service starting", Toast.LENGTH_SHORT).show();
    -+
    -+      // For each start request, send a message to start a job and deliver the
    -+      // start ID so we know which request we're stopping when we finish the job
    -+      Message msg = mServiceHandler.obtainMessage();
    -+      msg.arg1 = startId;
    -+      mServiceHandler.sendMessage(msg);
    -+
    -+      // If we get killed, after returning from here, restart
    -+      return START_STICKY;
    -+  }
    -+
    -+  &#64;Override
    -+  public IBinder onBind(Intent intent) {
    -+      // We don't provide binding, so return null
    -+      return null;
    -+  }
    -+
    -+  &#64;Override
    -+  public void onDestroy() {
    -+    Toast.makeText(this, "service done", Toast.LENGTH_SHORT).show();
    -+  }
    -+}
    -+</pre>
    -+
    -+<p>Seperti yang bisa Anda lihat, ini membutuhkan lebih banyak pekerjaan daripada menggunakan {@link android.app.IntentService}.</p>
    -+
    -+<p>Akan tetapi, karena Anda menangani sendiri setiap panggilan ke {@link android.app.Service#onStartCommand
    -+onStartCommand()}, Anda bisa melakukan beberapa permintaan sekaligus. Itu bukan yang
    -+dilakukan contoh ini, namun jika itu yang diinginkan, Anda bisa membuat thread baru untuk setiap
    -+permintaan dan langsung menjalankannya (sebagai ganti menunggu permintaan sebelumnya selesai).</p>
    -+
    -+<p>Perhatikan bahwa metode {@link android.app.Service#onStartCommand onStartCommand()} harus mengembalikan
    -+integer. Integer tersebut merupakan nilai yang menjelaskan cara sistem melanjutkan layanan dalam
    -+kejadian yang dimatikan oleh sistem (sebagaimana dibahas di atas, implementasi default {@link
    -+android.app.IntentService} menangani hal ini untuk Anda, walaupun Anda bisa memodifikasinya). Nilai yang dikembalikan
    -+dari {@link android.app.Service#onStartCommand onStartCommand()} harus berupa salah satu
    -+konstanta berikut ini:</p>
    -+
    -+<dl>
    -+  <dt>{@link android.app.Service#START_NOT_STICKY}</dt>
    -+    <dd>Jika sistem mematikan layanan setelah {@link android.app.Service#onStartCommand
    -+onStartCommand()} dikembalikan, <em>jangan</em> membuat lagi layanan tersebut, kecuali jika ada intent
    -+tertunda yang akan disampaikan. Inilah pilihan teraman untuk menghindari menjalankan layanan Anda
    -+bila tidak diperlukan dan bila aplikasi Anda bisa me-restart pekerjaan yang belum selesai.</dd>
    -+  <dt>{@link android.app.Service#START_STICKY}</dt>
    -+    <dd>Jika sistem mematikan layanan setelah {@link android.app.Service#onStartCommand
    -+onStartCommand()} dikembalikan, buat kembali layanan dan panggil {@link
    -+android.app.Service#onStartCommand onStartCommand()}, namun <em>jangan</em> menyampaikan ulang intent terakhir.
    -+Sebagai gantinya, sistem akan memanggil {@link android.app.Service#onStartCommand onStartCommand()} dengan
    -+intent null, kecuali jika ada intent tertunda untuk memulai layanan, dan dalam hal ini,
    -+intent tersebut disampaikan. Ini cocok bagi pemutar media (atau layanan serupa) yang tidak
    -+mengeksekusi perintah, namun berjalan terus-menerus dan menunggu pekerjaan.</dd>
    -+  <dt>{@link android.app.Service#START_REDELIVER_INTENT}</dt>
    -+    <dd>Jika sistem mematikan layanan setelah {@link android.app.Service#onStartCommand
    -+onStartCommand()} kembali, buat kembali layanan dan panggil {@link
    -+android.app.Service#onStartCommand onStartCommand()} dengan intent terakhir yang disampaikan ke
    -+layanan. Intent yang tertunda akan disampaikan pada gilirannya. Ini cocok bagi layanan yang
    -+aktif melakukan pekerjaan yang harus segera dilanjutkan, misalnya mengunduh file.</dd>
    -+</dl>
    -+<p>Untuk detail selengkapnya tentang nilai pengembalian ini, lihat dokumentasi acuan untuk setiap
    -+konstanta.</p>
    -+
    -+
    -+
    -+<h3 id="StartingAService">Memulai Layanan</h3>
    -+
    -+<p>Anda bisa memulai layanan dari aktivitas atau komponen aplikasi lain dengan meneruskan
    -+{@link android.content.Intent} (yang menetapkan layanan yang akan dimulai) ke {@link
    -+android.content.Context#startService startService()}. Sistem Android akan memanggil metode {@link
    -+android.app.Service#onStartCommand onStartCommand()} layanan dan meneruskan {@link
    -+android.content.Intent} padanya. (Jangan sekali-kali memanggil {@link android.app.Service#onStartCommand
    -+onStartCommand()} secara langsung.)</p>
    -+
    -+<p>Misalnya, aktivitas bisa memulai contoh layanan di bagian sebelumnya ({@code
    -+HelloSevice}) menggunakan intent eksplisit dengan {@link android.content.Context#startService
    -+startService()}:</p>
    -+
    -+<pre>
    -+Intent intent = new Intent(this, HelloService.class);
    -+startService(intent);
    -+</pre>
    -+
    -+<p>Metode {@link android.content.Context#startService startService()} segera kembali dan
    -+sistem Android akan memanggil metode {@link android.app.Service#onStartCommand
    -+onStartCommand()} layanan. Jika layanan belum berjalan, sistem mula-mula memanggil {@link
    -+android.app.Service#onCreate onCreate()}, kemudian memanggil {@link android.app.Service#onStartCommand
    -+onStartCommand()}.</p>
    -+
    -+<p>Jika layanan juga tidak menyediakan pengikatan, intent yang disampaikan dengan {@link
    -+android.content.Context#startService startService()} adalah satu-satunya mode komunikasi antara
    -+komponen aplikasi dan layanan. Akan tetapi, jika Anda ingin agar layanan mengirimkan hasilnya kembali, maka
    -+klien yang memulai layanan bisa membuat {@link android.app.PendingIntent} untuk siaran
    -+(dengan {@link android.app.PendingIntent#getBroadcast getBroadcast()}) dan menyampaikannya ke layanan
    -+dalam {@link android.content.Intent} yang memulai layanan. Layanan kemudian bisa menggunakan
    -+siaran untuk menyampaikan hasil.</p>
    -+
    -+<p>Beberapa permintaan untuk memulai layanan menghasilkan beberapa panggilan pula ke
    -+{@link android.app.Service#onStartCommand onStartCommand()} layanan. Akan tetapi, hanya satu permintaan untuk menghentikan
    -+layanan (dengan {@link android.app.Service#stopSelf stopSelf()} atau {@link
    -+android.content.Context#stopService stopService()}) dibutuhkan untuk menghentikannya.</p>
    -+
    -+
    -+<h3 id="Stopping">Menghentikan layanan</h3>
    -+
    -+<p>Layanan yang sudah dimulai harus mengelola daur hidupnya sendiri. Artinya, sistem tidak menghentikan atau
    -+memusnahkan layanan kecuali jika harus memulihkan memori sistem dan layanan
    -+terus berjalan setelah {@link android.app.Service#onStartCommand onStartCommand()} kembali. Jadi,
    -+layanan tersebut harus berhenti sendiri dengan memanggil {@link android.app.Service#stopSelf stopSelf()} atau
    -+komponen lain bisa menghentikannya dengan memanggil {@link android.content.Context#stopService stopService()}.</p>
    -+
    -+<p>Setelah diminta untuk berhenti dengan {@link android.app.Service#stopSelf stopSelf()} atau {@link
    -+android.content.Context#stopService stopService()}, sistem akan menghapus layanan
    -+secepatnya.</p>
    -+
    -+<p>Akan tetapi, bila layanan Anda menangani beberapa permintaan ke {@link
    -+android.app.Service#onStartCommand onStartCommand()} sekaligus, Anda tidak boleh menghentikan
    -+layanan bila Anda baru selesai memproses permintaan memulai, karena setelah itu mungkin Anda sudah menerima permintaan memulai
    -+yang baru (berhenti pada permintaan pertama akan menghentikan permintaan kedua). Untuk menghindari
    -+masalah ini, Anda bisa menggunakan {@link android.app.Service#stopSelf(int)} untuk memastikan bahwa permintaan
    -+Anda untuk menghentikan layanan selalu berdasarkan pada permintaan memulai terbaru. Artinya, bila Anda memanggil {@link
    -+android.app.Service#stopSelf(int)}, Anda akan meneruskan ID permintaan memulai (<code>startId</code>
    -+yang disampaikan ke {@link android.app.Service#onStartCommand onStartCommand()}) yang terkait dengan permintaan berhenti
    -+Anda. Kemudian jika layanan menerima permintaan memulai baru sebelum Anda bisa memanggil {@link
    -+android.app.Service#stopSelf(int)}, maka ID tidak akan sesuai dan layanan tidak akan berhenti.</p>
    -+
    -+<p class="caution"><strong>Perhatian:</strong> Aplikasi Anda perlu menghentikan layanannya
    -+bila selesai bekerja untuk menghindari pemborosan sumber daya sistem dan tenaga baterai. Jika perlu,
    -+komponen lain bisa menghentikan layanan secara eksplisit dengan memanggil {@link
    -+android.content.Context#stopService stopService()}. Bahkan jika Anda mengaktifkan pengikatan bagi layanan,
    -+Anda harus selalu menghentikan layanan sendiri jika layanan tersebut menerima panggilan ke {@link
    -+android.app.Service#onStartCommand onStartCommand()}.</p>
    -+
    -+<p>Untuk informasi selengkapnya tentang daur hidup layanan, lihat bagian di bawah ini tentang <a href="#Lifecycle">Mengelola Daur Hidup Layanan</a>.</p>
    -+
    -+
    -+
    -+<h2 id="CreatingBoundService">Membuat Layanan Terikat</h2>
    -+
    -+<p>Layanan terikat adalah layanan yang memungkinkan komponen aplikasi untuk mengikatnya dengan memanggil {@link
    -+android.content.Context#bindService bindService()} guna membuat koneksi yang berlangsung lama
    -+(dan umumnya tidak mengizinkan komponen untuk <em>memulainya</em> dengan memanggil {@link
    -+android.content.Context#startService startService()}).</p>
    -+
    -+<p>Anda sebaiknya membuat layanan terikat bila ingin berinteraksi dengan layanan dari aktivitas
    -+dan komponen lain dalam aplikasi Anda atau mengeskpos sebagian fungsionalitas aplikasi Anda ke
    -+ke aplikasi lain, melalui komunikasi antarproses (IPC).</p>
    -+
    -+<p>Untuk membuat layanan terikat, Anda harus mengimplementasikan metode callback {@link
    -+android.app.Service#onBind onBind()} untuk mengembalikan {@link android.os.IBinder} yang
    -+mendefinisikan antarmuka bagi komunikasi dengan layanan. Komponen aplikasi lain kemudian bisa memanggil
    -+{@link android.content.Context#bindService bindService()} untuk mengambil antarmuka dan
    -+mulai memanggil metode pada layanan. Layanan hanya hidup untuk melayani komponen aplikasi yang
    -+terikat padanya, jadi bila tidak ada komponen yang terikat pada layanan, sistem akan memusnahkannya
    -+(Anda <em>tidak</em> perlu menghentikan layanan terikat seperti halnya bila layanan dimulai
    -+melalui {@link android.app.Service#onStartCommand onStartCommand()}).</p>
    -+
    -+<p>Untuk membuat layanan terikat, hal yang perlu dilakukan pertama kali adalah mendefinisikan antarmuka yang menetapkan
    -+cara klien berkomunikasi dengan layanan. Antarmuka antara layanan
    -+dan klien ini harus berupa implementasi {@link android.os.IBinder} dan yang harus dikembalikan
    -+layanan Anda dari metode callback {@link android.app.Service#onBind
    -+onBind()}. Setelah menerima {@link android.os.IBinder}, klien bisa mulai
    -+berinteraksi dengan layanan melalui antarmuka tersebut.</p>
    -+
    -+<p>Beberapa klien bisa mengikat ke layanan sekaligus. Bila klien selesai berinteraksi dengan
    -+layanan, klien akan memanggil {@link android.content.Context#unbindService unbindService()} untuk melepas ikatan. Bila
    -+tidak ada klien yang terikat pada layanan, sistem akan menghapus layanan tersebut.</p>
    -+
    -+<p>Ada beberapa cara untuk mengimplementasikan layanan terikat dan implementasinya lebih
    -+rumit daripada layanan yang sudah dimulai, jadi layanan terikat dibahas dalam dokumen
    -+terpisah tentang <a href="{@docRoot}guide/components/bound-services.html">Layanan Terikat</a>.</p>
    -+
    -+
    -+
    -+<h2 id="Notifications">Mengirim Pemberitahuan ke Pengguna</h2>
    -+
    -+<p>Setelah berjalan, layanan bisa memberi tahu pengguna tentang suatu kejadian menggunakan <a href="{@docRoot}guide/topics/ui/notifiers/toasts.html">Pemberitahuan Toast</a> atau <a href="{@docRoot}guide/topics/ui/notifiers/notifications.html">Pemberitahuan Baris Status</a>.</p>
    -+
    -+<p>Pemberitahuan Toast adalah pesan yang muncul sebentar pada permukaan jendela saat ini
    -+kemudian menghilang, sementara pemberitahuan baris status memberikan ikon di baris status dengan
    -+pesan yang bisa dipilih oleh pengguna untuk melakukan suatu tindakan (misalnya memulai suatu aktivitas).</p>
    -+
    -+<p>Biasanya, pemberitahuan baris status adalah teknik terbaik bila ada pekerjaan latar belakang yang sudah selesai
    -+(misalnya file selesai
    -+diunduh) dan pengguna kini bisa menggunakannya. Bila pengguna memilih pemberitahuan dari
    -+tampilan diperluas, pemberitahuan akan bisa memulai aktivitas (misalnya menampilkan file yang baru diunduh).</p>
    -+
    -+<p>Lihat panduan pengembang <a href="{@docRoot}guide/topics/ui/notifiers/toasts.html">Pemberitahuan Toast</a> atau <a href="{@docRoot}guide/topics/ui/notifiers/notifications.html">Pemberitahuan Baris Status</a>
    -+untuk informasi selengkapnya.</p>
    -+
    -+
    -+
    -+<h2 id="Foreground">Menjalankan Layanan di Latar Depan</h2>
    -+
    -+<p>Layanan latar depan adalah layanan yang dianggap sebagai sesuatu yang
    -+diketahui secara aktif oleh pengguna, jadi bukan sesuatu yang akan dihapus oleh sistem bila memori menipis. Sebuah
    -+layanan latar depan harus memberikan pemberitahuan bagi baris status, yang ditempatkan pada
    -+heading "Ongoing" yang artinya pemberitahuan tersebut tidak bisa diabaikan kecuali jika layanan
    -+dihentikan atau dihapus dari latar depan.</p>
    -+
    -+<p>Misalnya, pemutar musik yang memutar musik dari suatu layanan harus diatur untuk berjalan di
    -+latar depan, karena pengguna mengetahui operasi tersebut
    -+secara eksplisit. Pemberitahuan di baris status bisa menunjukkan lagu saat ini dan memungkinkan
    -+pengguna untuk menjalankan suatu aktivitas untuk berinteraksi dengan pemutar musik.</p>
    -+
    -+<p>Untuk meminta agar layanan Anda berjalan di latar depan, panggil {@link
    -+android.app.Service#startForeground startForeground()}. Metode ini memerlukan dua parameter: sebuah integer
    -+yang mengidentifikasi pemberitahuan secara unik dan {@link
    -+android.app.Notification} untuk baris status. Misalnya:</p>
    -+
    -+<pre>
    -+Notification notification = new Notification(R.drawable.icon, getText(R.string.ticker_text),
    -+        System.currentTimeMillis());
    -+Intent notificationIntent = new Intent(this, ExampleActivity.class);
    -+PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, notificationIntent, 0);
    -+notification.setLatestEventInfo(this, getText(R.string.notification_title),
    -+        getText(R.string.notification_message), pendingIntent);
    -+startForeground(ONGOING_NOTIFICATION_ID, notification);
    -+</pre>
    -+
    -+<p class="caution"><strong>Perhatian:</strong> ID integer yang Anda berikan ke {@link
    -+android.app.Service#startForeground startForeground()} tidak boleh 0.</p>
    -+
    -+
    -+<p>Untuk menghapus layanan dari latar depan, panggil {@link
    -+android.app.Service#stopForeground stopForeground()}. Metode ini memerlukan boolean, yang menunjukkan
    -+apakah pemberitahuan baris status juga akan dihapus. Metode ini <em>tidak</em> menghentikan
    -+layanan. Akan tetapi, jika Anda menghentikan layanan saat masih berjalan di latar depan
    -+maka pemberitahuan juga akan dihapus.</p>
    -+
    -+<p>Untuk informasi selengkapnya tentang pemberitahuan, lihat <a href="{@docRoot}guide/topics/ui/notifiers/notifications.html">Membuat Pemberitahuan
    -+Baris Status</a>.</p>
    -+
    -+
    -+
    -+<h2 id="Lifecycle">Mengelola Daur Hidup Layanan</h2>
    -+
    -+<p>Daur hidup layanan jauh lebih sederhana daripada daur hidup aktivitas. Akan tetapi, lebih penting lagi adalah
    -+memerhatikan dengan cermat bagaimana layanan Anda dibuat dan dimusnahkan, karena suatu layanan
    -+bisa berjalan di latar belakang tanpa disadari oleh pengguna.</p>
    -+
    -+<p>Daur hidup layanan&mdash;dari saat dibuat hingga dimusnahkan&mdash;bisa mengikuti
    -+dua path berbeda:</p>
    -+
    -+<ul>
    -+<li>Layanan yang sudah dimulai
    -+  <p>Layanan dibuat bila komponen lain memanggil {@link
    -+android.content.Context#startService startService()}. Layanan kemudian berjalan terus-menerus dan harus
    -+berhenti sendiri dengan memanggil {@link
    -+android.app.Service#stopSelf() stopSelf()}. Komponen lain juga bisa menghentikan
    -+layanan dengan memanggil {@link android.content.Context#stopService
    -+stopService()}. Bila layanan dihentikan, sistem akan menghancurkannya.</p></li>
    -+
    -+<li>Layanan terikat
    -+  <p>Layanan dibuat bila komponen lain (klien) memanggil {@link
    -+android.content.Context#bindService bindService()}. Klien kemudian berkomunikasi dengan layanan
    -+melalui antarmuka {@link android.os.IBinder}. Klien bisa menutup koneksi dengan memanggil
    -+{@link android.content.Context#unbindService unbindService()}. Sejumlah klien bisa mengikat pada
    -+layanan yang sama dan bila semuanya melepas ikatan, sistem akan memusnahkan layanan tersebut. (Layanan
    -+<em>tidak</em> perlu berhenti sendiri.)</p></li>
    -+</ul>
    -+
    -+<p>Kedua path tersebut tidak benar-benar terpisah. Artinya, Anda bisa mengikat ke layanan yang sudah
    -+dimulai dengan {@link android.content.Context#startService startService()}. Misalnya, layanan
    -+musik latar belakang bisa dimulai dengan memanggil {@link android.content.Context#startService
    -+startService()} dengan {@link android.content.Intent} yang mengidentifikasi musik yang akan diputar. Kemudian,
    -+mungkin saat pengguna ingin mengontrol pemutar musik atau mendapatkan informasi
    -+tentang lagu yang diputar, aktivitas bisa mengikat ke layanan dengan memanggil {@link
    -+android.content.Context#bindService bindService()}. Dalam kasus seperti ini, {@link
    -+android.content.Context#stopService stopService()} atau {@link android.app.Service#stopSelf
    -+stopSelf()} tidak menghentikan layanan sampai semua klien melepas ikatan. </p>
    -+
    -+
    -+<h3 id="LifecycleCallbacks">Mengimplementasikan callback daur hidup</h3>
    -+
    -+<p>Seperti halnya aktivitas, layanan memiliki metode callback daur hidup yang bisa Anda implementasikan
    -+untuk memantau perubahan status layanan dan melakukan pekerjaan pada waktu yang tepat. Layanan skeleton
    -+berikut memperagakan setiap metode daur hidup:</p>
    -+
    -+<pre>
    -+public class ExampleService extends Service {
    -+    int mStartMode;       // indicates how to behave if the service is killed
    -+    IBinder mBinder;      // interface for clients that bind
    -+    boolean mAllowRebind; // indicates whether onRebind should be used
    -+
    -+    &#64;Override
    -+    public void {@link android.app.Service#onCreate onCreate}() {
    -+        // The service is being created
    -+    }
    -+    &#64;Override
    -+    public int {@link android.app.Service#onStartCommand onStartCommand}(Intent intent, int flags, int startId) {
    -+        // The service is starting, due to a call to {@link android.content.Context#startService startService()}
    -+        return <em>mStartMode</em>;
    -+    }
    -+    &#64;Override
    -+    public IBinder {@link android.app.Service#onBind onBind}(Intent intent) {
    -+        // A client is binding to the service with {@link android.content.Context#bindService bindService()}
    -+        return <em>mBinder</em>;
    -+    }
    -+    &#64;Override
    -+    public boolean {@link android.app.Service#onUnbind onUnbind}(Intent intent) {
    -+        // All clients have unbound with {@link android.content.Context#unbindService unbindService()}
    -+        return <em>mAllowRebind</em>;
    -+    }
    -+    &#64;Override
    -+    public void {@link android.app.Service#onRebind onRebind}(Intent intent) {
    -+        // A client is binding to the service with {@link android.content.Context#bindService bindService()},
    -+        // after onUnbind() has already been called
    -+    }
    -+    &#64;Override
    -+    public void {@link android.app.Service#onDestroy onDestroy}() {
    -+        // The service is no longer used and is being destroyed
    -+    }
    -+}
    -+</pre>
    -+
    -+<p class="note"><strong>Catatan:</strong> Tidak seperti metode callback daur hidup aktivitas, Anda
    -+<em>tidak</em> perlu memanggil implementasi superkelas metode callback tersebut.</p>
    -+
    -+<img src="{@docRoot}images/service_lifecycle.png" alt="" />
    -+<p class="img-caption"><strong>Gambar 2.</strong> Daur hidup layanan. Diagram di sebelah kiri
    -+menampilkan daur hidup bila layanan dibuat dengan {@link android.content.Context#startService
    -+startService()} dan diagram di sebelah kanan menampilkan daur hidup bila layanan dibuat
    -+dengan {@link android.content.Context#bindService bindService()}.</p>
    -+
    -+<p>Dengan mengimplementasikan metode-metode ini, Anda bisa memantau dua loop tersarang (nested loop) daur hidup layanan: </p>
    -+
    -+<ul>
    -+<li><strong>Seluruh masa pakai</strong> layanan terjadi antara saat {@link
    -+android.app.Service#onCreate onCreate()} dipanggil dan saat {@link
    -+android.app.Service#onDestroy} kembali. Seperti halnya aktivitas, layanan melakukan penyiapan awal di
    -+{@link android.app.Service#onCreate onCreate()} dan melepaskan semua sisa sumber daya yang ada di {@link
    -+android.app.Service#onDestroy onDestroy()}.  Misalnya,
    -+layanan pemutar musik bisa membuat thread tempat musik akan diputar dalam {@link
    -+android.app.Service#onCreate onCreate()}, kemudian menghentikan thread tersebut dalam {@link
    -+android.app.Service#onDestroy onDestroy()}.
    -+
    -+<p>Metode {@link android.app.Service#onCreate onCreate()} dan {@link android.app.Service#onDestroy
    -+onDestroy()} diperlukan semua layanan, baik yang
    -+dibuat oleh {@link android.content.Context#startService startService()} maupun {@link
    -+android.content.Context#bindService bindService()}.</p></li>
    -+
    -+<li><strong>Masa pakai aktif</strong> layanan dimulai dengan panggilan ke {@link
    -+android.app.Service#onStartCommand onStartCommand()} atau {@link android.app.Service#onBind onBind()}.
    -+Masing-masing metode diberikan {@link
    -+android.content.Intent} yang diteruskan ke {@link android.content.Context#startService
    -+startService()} atau {@link android.content.Context#bindService bindService()}.
    -+<p>Jika layanan telah dimulai, masa pakai aktif akan berakhir pada saat yang sama dengan
    -+berakhirnya seluruh masa pakai (layanan masih aktif bahkan setelah {@link android.app.Service#onStartCommand
    -+onStartCommand()} kembali). Jika layanan tersebut terikat, masa pakai aktifnya akan berakhir bila {@link
    -+android.app.Service#onUnbind onUnbind()} kembali.</p>
    -+</li>
    -+</ul>
    -+
    -+<p class="note"><strong>Catatan:</strong> Meskipun layanan yang sudah dimulai dihentikan dengan panggilan ke
    -+{@link android.app.Service#stopSelf stopSelf()} atau {@link
    -+android.content.Context#stopService stopService()}, tidak ada callback tersendiri bagi
    -+layanan tersebut (tidak ada callback {@code onStop()}). Jadi, kecuali jika layanan terikat ke klien,
    -+sistem akan memusnahkannya bila layanan dihentikan&mdash;{@link
    -+android.app.Service#onDestroy onDestroy()} adalah satu-satunya callback yang diterima.</p>
    -+
    -+<p>Gambar 2 mengilustrasikan metode callback yang lazim bagi suatu layanan. Walaupun gambar tersebut memisahkan
    -+layanan yang dibuat oleh {@link android.content.Context#startService startService()} dari layanan
    -+yang dibuat oleh {@link android.content.Context#bindService bindService()}, ingatlah
    -+bahwa suatu layanan, bagaimana pun dimulainya, bisa memungkinkan klien mengikat padanya.
    -+Jadi, suatu layanan yang awalnya dimulai dengan {@link android.app.Service#onStartCommand
    -+onStartCommand()} (oleh klien yang memanggil {@link android.content.Context#startService startService()})
    -+masih bisa menerima panggilan ke {@link android.app.Service#onBind onBind()} (bila klien memanggil
    -+{@link android.content.Context#bindService bindService()}).</p>
    -+
    -+<p>Untuk informasi selengkapnya tentang membuat layanan yang menyediakan pengikatan, lihat dokumen <a href="{@docRoot}guide/components/bound-services.html">Layanan Terikat</a>,
    -+yang menyertakan informasi selengkapnya tentang metode callback {@link android.app.Service#onRebind onRebind()}
    -+di bagian tentang <a href="{@docRoot}guide/components/bound-services.html#Lifecycle">Mengelola Daur Hidup
    -+Layanan Terikat</a>.</p>
    -+
    -+
    -+<!--
    -+<h2>Beginner's Path</h2>
    -+
    -+<p>To learn how to query data from the system or other applications (such as contacts or media
    -+stored on the device), continue with the <b><a
    -+href="{@docRoot}guide/topics/providers/content-providers.html">Content Providers</a></b>
    -+document.</p>
    -+-->
    -diff --git a/docs/html-intl/intl/id/guide/components/tasks-and-back-stack.jd b/docs/html-intl/intl/id/guide/components/tasks-and-back-stack.jd
    -new file mode 100644
    -index 0000000..4c344ae
    ---- /dev/null
    -+++ b/docs/html-intl/intl/id/guide/components/tasks-and-back-stack.jd
    -@@ -0,0 +1,578 @@
    -+page.title=Tugas dan Back-Stack
    -+parent.title=Aktivitas
    -+parent.link=activities.html
    -+@jd:body
    -+
    -+<div id="qv-wrapper">
    -+<div id="qv">
    -+
    -+<h2>Dalam dokumen ini</h2>
    -+<ol>
    -+<li><a href="#ActivityState">Menyimpan Status Aktivitas</a></li></li>
    -+<li><a href="#ManagingTasks">Mengelola Tugas</a>
    -+  <ol>
    -+    <li><a href="#TaskLaunchModes">Mendefinisikan mode peluncuran</a></li>
    -+    <li><a href="#Affinities">Menangani afinitas</a></li>
    -+    <li><a href="#Clearing">Menghapus back-stack</a></li>
    -+    <li><a href="#Starting">Memulai tugas</a></li>
    -+  </ol>
    -+</li>
    -+</ol>
    -+
    -+<h2>Artikel</h2>
    -+<ol>
    -+  <li><a href="http://android-developers.blogspot.com/2010/04/multitasking-android-way.html">
    -+  Multitasking Ala Android</a></li>
    -+</ol>
    -+
    -+<h2>Lihat juga</h2>
    -+<ol>
    -+  <li><a href="{@docRoot}design/patterns/navigation.html">Desain Android:
    -+Navigasi</a></li>
    -+  <li><a href="{@docRoot}guide/topics/manifest/activity-element.html">Elemen manifes
    -+{@code &lt;activity&gt;}</a></li>
    -+  <li><a href="{@docRoot}guide/components/recents.html">Layar Ikhtisar</a></li>
    -+</ol>
    -+</div>
    -+</div>
    -+
    -+
    -+<p>Sebuah aplikasi biasanya berisi beberapa <a href="{@docRoot}guide/components/activities.html">aktivitas</a>. Setiap aktivitas
    -+harus didesain dengan jenis tindakan tertentu yang bisa dilakukan pengguna dan bisa memulai aktivitas
    -+lain. Misalnya, aplikasi email mungkin memiliki satu aktivitas untuk menampilkan daftar pesan baru.
    -+Bila pengguna memilih sebuah pesan, aktivitas baru akan terbuka untuk melihat pesan tersebut.</p>
    -+
    -+<p>Aktivitas bahkan bisa memulai aktivitas yang ada dalam aplikasi lain di perangkat. Misalnya
    -+, jika aplikasi Anda ingin mengirim pesan email, Anda bisa mendefinisikan intent untuk melakukan tindakan
    -+"kirim" dan menyertakan sejumlah data, seperti alamat email dan pesan. Aktivitas dari aplikasi
    -+lain yang mendeklarasikan dirinya untuk menangani jenis intent ini akan terbuka. Dalam hal ini, intent
    -+tersebut untuk mengirim email, sehingga aktivitas "menulis" pada aplikasi email akan dimulai (jika beberapa aktivitas
    -+mendukung intent yang sama, maka sistem akan memungkinkan pengguna memilih mana yang akan digunakan). Bila email telah
    -+dikirim, aktivitas Anda akan dilanjutkan dan seolah-olah aktivitas email adalah bagian dari aplikasi Anda. Meskipun
    -+aktivitas mungkin dari aplikasi yang berbeda, Android akan tetap mempertahankan pengalaman pengguna yang mulus
    -+dengan menjalankan kedua aktivitas dalam <em>tugas</em> yang sama.</p>
    -+
    -+<p>Tugas adalah kumpulan aktivitas yang berinteraksi dengan pengguna
    -+saat melakukan pekerjaan tertentu. Aktivitas tersebut diatur dalam tumpukan (<em>back-stack</em>), dalam
    -+urutan membuka setiap aktivitas.</p>
    -+
    -+<!-- SAVE FOR WHEN THE FRAGMENT DOC IS ADDED
    -+<div class="sidebox-wrapper">
    -+<div class="sidebox">
    -+<h3>Adding fragments to a task's back stack</h3>
    -+
    -+<p>Your activity can also include {@link android.app.Fragment}s to the back stack. For example,
    -+suppose you have a two-pane layout using fragments, one of which is a list view (fragment A) and the
    -+other being a layout to display an item from the list (fragment B). When the user selects an item
    -+from the list, fragment B is replaced by a new fragment (fragment C). In this case, it might be
    -+desireable for the user to navigate back to reveal fragment B, using the <em>Back</em> button.</p>
    -+<p>In order to add fragment B to the back stack so that this is possible, you must call {@link
    -+android.app.FragmentTransaction#addToBackStack addToBackStack()} before you {@link
    -+android.app.FragmentTransaction#commit()} the transaction that replaces fragment B with fragment
    -+C.</p>
    -+<p>For more information about using fragments and adding them to the back stack, see the {@link
    -+android.app.Fragment} class documentation.</p>
    -+
    -+</div>
    -+</div>
    -+-->
    -+
    -+<p>Layar Home perangkat adalah tempat memulai hampir semua tugas. Bila pengguna menyentuh ikon di launcher
    -+aplikasi
    -+(atau pintasan pada layar Home), tugas aplikasi tersebut akan muncul pada latar depan. Jika tidak ada
    -+tugas untuk aplikasi (aplikasi tidak digunakan baru-baru ini), maka tugas baru
    -+akan dibuat dan aktivitas "utama" untuk aplikasi tersebut akan terbuka sebagai aktivitas akar dalam back-stack.</p>
    -+
    -+<p>Bila aktivitas saat ini dimulai lagi, aktivitas baru akan didorong ke atas back-stack dan
    -+mengambil fokus. Aktivitas sebelumnya tetap dalam back-stack, namun dihentikan. Bila aktivitas
    -+dihentikan, sistem akan mempertahankan status antarmuka penggunanya saat ini. Bila pengguna menekan tombol
    -+<em>Back</em>
    -+, aktivitas saat ini akan dikeluarkan dari atas back-stack (aktivitas dimusnahkan) dan
    -+ aktivitas sebelumnya dilanjutkan (status UI sebelumnya dipulihkan). Aktivitas dalam back-stack
    -+tidak pernah disusun ulang, hanya didorong dan dikeluarkan dari back-stack&mdash;yang didorong ke back-stack saat dimulai oleh
    -+aktivitas saat ini dan dikeluarkan bila pengguna meninggalkannya menggunakan tombol <em>Back</em>. Dengan demikian,
    -+back-stack
    -+beroperasi sebagai struktur objek "masuk terakhir, keluar pertama". Gambar 1 melukiskan perilaku
    -+ini dengan jangka waktu yang menunjukkan kemajuan antar aktivitas beserta
    -+back-stack pada setiap waktu.</p>
    -+
    -+<img src="{@docRoot}images/fundamentals/diagram_backstack.png" alt="" />
    -+<p class="img-caption"><strong>Gambar 1.</strong> Representasi tentang cara setiap aktivitas baru dalam
    -+tugas menambahkan item ke back-stack. Bila pengguna menekan tombol <em>Back</em>, aktivitas
    -+saat ini
    -+akan dimusnahkan dan aktivitas sebelumnya dilanjutkan.</p>
    -+
    -+
    -+<p>Jika pengguna terus menekan <em>Back</em>, maka setiap aktivitas dalam back-stack akan dikeluarkan untuk
    -+menampilkan
    -+yang sebelumnya, sampai pengguna kembali ke layar Home (atau aktivitas mana pun yang sedang dijalankan saat tugas
    -+dimulai. Bila semua aktivitas telah dihapus dari back-stack, maka tugas tidak akan ada lagi.</p>
    -+
    -+<div class="figure" style="width:287px">
    -+<img src="{@docRoot}images/fundamentals/diagram_multitasking.png" alt="" /> <p
    -+class="img-caption"><strong>Gambar 2.</strong> Dua tugas: Tugas B menerima interaksi pengguna
    -+di latar depan, sedangkan Tugas A di latar belakang, menunggu untuk dilanjutkan.</p>
    -+</div>
    -+<div class="figure" style="width:215px">
    -+  <img src="{@docRoot}images/fundamentals/diagram_multiple_instances.png" alt="" /> <p
    -+class="img-caption"><strong>Gambar 3.</strong> Satu aktivitas dibuat instance-nya beberapa kali.</p>
    -+</div>
    -+
    -+<p>Tugas adalah unit kohesif yang bisa dipindahkan ke "latar belakang" bila pengguna memulai tugas baru atau masuk ke
    -+layar Home, melalui tombol<em>Home</em>. Sementara di latar belakang, semua aktivitas dalam
    -+tugas
    -+dihentikan, namun back-stack untuk tugas tidak berubah&mdash;tugas kehilangan fokus saat
    -+tugas lain berlangsung, seperti yang ditampilkan dalam gambar 2. Kemudian, tugas bisa kembali ke "latar depan" agar pengguna
    -+bisa melanjutkan tugas di tempat menghentikannya. Anggaplah, misalnya, tugas saat ini (Tugas A) memiliki tiga
    -+aktivitas dalam back-stack&mdash;dua pada aktivitas saat ini. Pengguna menekan tombol <em>Home</em>
    -+, kemudian
    -+memulai aplikasi baru dari launcher aplikasi. Bila muncul layar Home, Tugas A akan beralih
    -+ke latar belakang. Bila aplikasi baru dimulai, sistem akan memulai tugas untuk aplikasi tersebut
    -+(Tugas B) dengan back-stack aktivitas sendiri. Setelah berinteraksi dengan aplikasi
    -+tersebut, pengguna akan kembali ke Home lagi dan memilih aplikasi yang semula
    -+memulai Tugas A. Sekarang, Tugas A muncul di
    -+latar depan&mdash;ketiga aktivitas dalam back-stack tidak berubah dan aktivitas di atas
    -+back-stack akan dilanjutkan. Pada
    -+titik ini pengguna juga bisa beralih kembali ke Tugas B dengan masuk ke Home dan memilih ikon aplikasi
    -+yang memulai tugas tersebut (atau dengan memilih tugas aplikasi dari
    -+<a href="{@docRoot}guide/components/recents.html">layar ikhtisar</a>).
    -+Ini adalah contoh dari melakukan multitasking di Android.</p>
    -+
    -+<p class="note"><strong>Catatan:</strong> Beberapa tugas bisa berlangsung di latar belakang secara bersamaan.
    -+Akan tetapi, jika pengguna menjalankan banyak tugas di latar belakang sekaligus, sistem mungkin mulai
    -+menghapus aktivitas latar belakang untuk memulihkan memori, yang akan menyebabkan status aktivitas hilang.
    -+Lihat bagian berikut tentang <a href="#ActivityState">Status aktivitas</a>.</p>
    -+
    -+<p>Karena aktivitas di back-stack tidak pernah diatur ulang, jika aplikasi Anda memungkinkan
    -+pengguna untuk memulai aktivitas tertentu dari lebih dari satu aktivitas, instance baru
    -+aktivitas tersebut akan dibuat dan didorong ke back-stack (bukannya memunculkan instance sebelumnya dari
    -+aktivitas ke atas). Dengan demikian, satu aktivitas pada aplikasi Anda mungkin dibuat beberapa
    -+kali (bahkan dari beberapa tugas), seperti yang ditampilkan dalam gambar 3. Dengan demikian, jika pengguna mengarahkan mundur
    -+menggunakan tombol <em>Back</em>, setiap instance aktivitas ini akan ditampilkan dalam urutan saat
    -+dibuka (masing-masing
    -+dengan status UI sendiri). Akan tetapi, Anda bisa memodifikasi perilaku ini jika tidak ingin aktivitas
    -+dibuat instance-nya lebih dari sekali. Caranya dibahas di bagian selanjutnya tentang <a href="#ManagingTasks">Mengelola Tugas</a>.</p>
    -+
    -+
    -+<p>Untuk meringkas perilaku default aktivitas dan tugas:</p>
    -+
    -+<ul>
    -+  <li>Bila Aktivitas A memulai Aktivitas B, Aktivitas A dihentikan, namun sistem mempertahankan statusnya
    -+(seperti posisi gulir dan teks yang dimasukkan ke dalam formulir).
    -+Jika pengguna menekan tombol <em>Back</em> saat dalam Aktivitas B, Aktivitas A akan dilanjutkan dengan status
    -+yang dipulihkan.</li>
    -+  <li>Bila pengguna meninggalkan tugas dengan menekan tombol <em>Home</em> aktivitas saat ini akan
    -+dihentikan dan
    -+tugas beralih ke latar belakang. Sistem akan mempertahankan status setiap aktivitas dalam tugas. Jika
    -+nanti pengguna melanjutkan tugas dengan memilih ikon launcher yang memulai tugas, tugas tersebut akan
    -+beralih ke latar depan dan melanjutkan aktivitas di atas back-stack.</li>
    -+  <li>Jika pengguna menekan tombol <em>Back</em>, aktivitas saat ini akan dikeluarkan dari back-stack
    -+dan
    -+dimusnahkan. Aktivitas sebelumnya dalam back-stack akan dilanjutkan. Bila suatu aktivitas dimusnahkan, sistem
    -+<em>tidak akan</em>mempertahankan status aktivitas.</li>
    -+  <li>Aktivitas bisa dibuat instance-nya beberapa kali, bahkan dari tugas-tugas lainnya.</li>
    -+</ul>
    -+
    -+
    -+<div class="note design">
    -+<p><strong>Desain Navigasi</strong></p>
    -+  <p>Untuk mengetahui selengkapnya tentang cara kerja navigasi aplikasi di Android, baca panduan <a href="{@docRoot}design/patterns/navigation.html">Navigasi</a> Desain Android.</p>
    -+</div>
    -+
    -+
    -+<h2 id="ActivityState">Menyimpan Status Aktivitas</h2>
    -+
    -+<p>Seperti dibahas di atas, perilaku default sistem akan mempertahankan status aktivitas bila
    -+dihentikan. Dengan cara ini, bila pengguna mengarah kembali ke aktivitas sebelumnya, antarmuka pengguna akan muncul
    -+seperti saat ditinggalkan. Akan tetapi, Anda bisa&mdash;dan <strong>harus</strong>&mdash;secara proaktif mempertahankan
    -+status aktivitas menggunakan metode callback, jika aktivitas ini dimusnahkan dan harus
    -+dibuat kembali.</p>
    -+
    -+<p>Bila sistem menghentikan salah satu aktivitas (seperti saat aktivitas baru dimulai atau tugas
    -+dipindah ke latar belakang), sistem mungkin memusnahkan aktivitas sepenuhnya jika perlu memulihkan
    -+memori sistem. Bila hal ini terjadi, informasi tentang status aktivitas akan hilang. Jika hal ini terjadi, sistem
    -+masih
    -+mengetahui bahwa aktivitas memiliki tempat di back-stack, namun saat aktivitas tersebut dibawa ke bagian teratas
    -+back-stack, sistem harus membuatnya kembali (bukan melanjutkannya). Untuk
    -+menghindari hilangnya pekerjaan pengguna, Anda harus secara proaktif mempertahankannya dengan menerapkan metode callback
    -+{@link android.app.Activity#onSaveInstanceState onSaveInstanceState()}
    -+dalam aktivitas.</p>
    -+
    -+<p>Untuk informasi selengkapnya tentang cara menyimpan status aktivitas Anda, lihat dokumen
    -+<a href="{@docRoot}guide/components/activities.html#SavingActivityState">Aktivitas</a>.</p>
    -+
    -+
    -+
    -+<h2 id="ManagingTasks">Mengelola Tugas</h2>
    -+
    -+<p>Cara Android mengelola tugas dan back-stack, seperti yang dijelaskan di atas&mdash;dengan menempatkan semua
    -+aktivitas yang dimulai secara berurutan dalam tugas yang sama dan dalam back-stack "masuk terakhir, keluar pertama"&mdash;berfungsi
    -+dengan baik untuk kebanyakan aplikasi dan Anda tidak perlu khawatir tentang cara mengaitkan aktivitas
    -+dengan tugas atau cara penempatannya di back-stack. Akan tetapi, Anda bisa memutuskan apakah ingin menyela
    -+perilaku normal. Mungkin Anda ingin agar suatu aktivitas dalam aplikasi untuk memulai tugas baru bila telah
    -+dimulai (sebagai ganti menempatkannya dalam tugas saat ini); atau, bila memulai aktivitas, Anda ingin
    -+memajukan instance yang ada (sebagai ganti membuat instance
    -+baru pada bagian teratas back-stack); atau, Anda ingin back-stack dihapus dari semua
    -+aktivitas selain untuk aktivitas akar bila pengguna meninggalkan tugas.</p>
    -+
    -+<p>Anda bisa melakukan semua ini dan lainnya, dengan atribut dalam elemen manifes
    -+<a href="{@docRoot}guide/topics/manifest/activity-element.html">{@code &lt;activity&gt;}</a>
    -+dan dengan flag pada intent yang Anda teruskan ke
    -+{@link android.app.Activity#startActivity startActivity()}.</p>
    -+
    -+<p>Dalam hal ini, atribut<a href="{@docRoot}guide/topics/manifest/activity-element.html">
    -+{@code &lt;activity&gt;}</a> utama yang bisa Anda gunakan adalah:</p>
    -+
    -+<ul class="nolist">
    -+  <li><a href="{@docRoot}guide/topics/manifest/activity-element.html#aff">
    -+  {@code taskAffinity}</a></li>
    -+  <li><a href="{@docRoot}guide/topics/manifest/activity-element.html#lmode">
    -+  {@code launchMode}</a></li>
    -+  <li><a href="{@docRoot}guide/topics/manifest/activity-element.html#reparent">
    -+  {@code allowTaskReparenting}</a></li>
    -+  <li><a href="{@docRoot}guide/topics/manifest/activity-element.html#clear">
    -+  {@code clearTaskOnLaunch}</a></li>
    -+  <li><a href="{@docRoot}guide/topics/manifest/activity-element.html#always">
    -+  {@code alwaysRetainTaskState}</a></li>
    -+  <li><a href="{@docRoot}guide/topics/manifest/activity-element.html#finish">
    -+  {@code finishOnTaskLaunch}</a></li>
    -+</ul>
    -+
    -+<p>Dan flag intent utama yang bisa Anda gunakan adalah:</p>
    -+
    -+<ul class="nolist">
    -+  <li>{@link android.content.Intent#FLAG_ACTIVITY_NEW_TASK}</li>
    -+  <li>{@link android.content.Intent#FLAG_ACTIVITY_CLEAR_TOP}</li>
    -+  <li>{@link android.content.Intent#FLAG_ACTIVITY_SINGLE_TOP}</li>
    -+</ul>
    -+
    -+<p>Dalam bagian berikut, Anda akan melihat cara menggunakan beberapa atribut manifes ini dan flag
    -+intent untuk mendefinisikan cara mengaitkan aktivitas dengan tugas dan cara perilakunya di back-stack.</p>
    -+
    -+<p>Juga, pertimbangan cara menyatakan dan mengelola tugas dan aktivitas
    -+dibahas secara terpisah di layar ikhtisar. Lihat <a href="{@docRoot}guide/components/recents.html">Layar Ikhtisar</a>
    -+untuk informasi selengkapnya. Biasanya Anda harus mengizinkan sistem mendefinisikan cara menyatakan tugas dan
    -+aktivitas di layar ikhtisar, dan Anda tidak perlu memodifikasi perilaku ini.</p>
    -+
    -+<p class="caution"><strong>Perhatian:</strong> Kebanyakan aplikasi tidak harus menyela perilaku
    -+default untuk aktivitas dan tugas. Jika merasa bahwa aktivitas Anda perlu memodifikasi
    -+perilaku default, lakukan dengan hati-hati dan pastikan menguji kegunaan aktivitas selama
    -+dijalankan dan saat mengarahkan kembali ke sana dari aktivitas dan tugas lain dengan tombol <em>Back</em>.
    -+Pastikan menguji perilaku navigasi yang mungkin bertentangan dengan perilaku yang diharapkan pengguna.</p>
    -+
    -+
    -+<h3 id="TaskLaunchModes">Mendefinisikan mode peluncuran</h3>
    -+
    -+<p>Mode peluncuran memungkinkan Anda mendefinisikan cara mengaitkan instance baru dari suatu aktivitas dengan
    -+tugas saat ini. Anda bisa mendefinisikan beragam mode peluncuran dalam dua cara:</p>
    -+<ul class="nolist">
    -+  <li><a href="#ManifestForTasks">Menggunakan file manifes</a>
    -+    <p>Bila Anda mendeklarasikan aktivitas dalam file manifes, Anda bisa menetapkan cara mengaitkan aktivitas
    -+dengan tugas-tugas saat mulai.</li>
    -+  <li><a href="#IntentFlagsForTasks">Menggunakan flag intent</a>
    -+    <p>Saat memanggil{@link android.app.Activity#startActivity startActivity()},
    -+Anda bisa menyertakan flag dalam {@link android.content.Intent} yang menyatakan cara (atau
    -+apakah) aktivitas baru tersebut harus dikaitkan dengan tugas saat ini.</p></li>
    -+</ul>
    -+
    -+<p>Dengan demikian, jika Aktivitas A memulai Aktivitas B, Aktivitas B bisa mendefinisikan dalam manifesnya cara
    -+mengaitkan dengan tugas saat ini (jika sama sekali) dan Aktivitas A juga bisa meminta cara mengaitkan Aktivitas B
    -+dengan tugas saat ini. Jika kedua aktivitas mendefinisikan cara mengaitkan Aktivitas B
    -+dengan tugas, maka permintaan Aktivitas A (sebagaimana didefinisikan dalam intent) lebih dihargai daripada
    -+permintaan Aktivitas B (sebagaimana didefinisikan dalam manifesnya).</p>
    -+
    -+<p class="note"><strong>Catatan:</strong> Beberapa mode peluncuran yang tersedia untuk file manifes
    -+tidak tersedia sebagai flag untuk intent dan, juga, beberapa mode peluncuran yang tersedia sebagai flag
    -+untuk intent tidak bisa didefinisikan dalam manifest.</p>
    -+
    -+
    -+<h4 id="ManifestForTasks">Menggunakan file manifes</h4>
    -+
    -+<p>Saat mendeklarasikan aktivitas dalam file manifes, Anda bisa menetapkan cara mengaitkan aktivitas
    -+dengan tugas menggunakan <a href="{@docRoot}guide/topics/manifest/activity-element.html">{@code &lt;activity&gt;}</a>
    -+melalui atribut <a href="{@docRoot}guide/topics/manifest/activity-element.html#lmode">{@code
    -+launchMode}</a> elemen.</p>
    -+
    -+<p>Atribut <a href="{@docRoot}guide/topics/manifest/activity-element.html#lmode">{@code
    -+launchMode}</a> menetapkan instruksi tentang cara meluncurkan aktivitas
    -+ke dalam tugas. Ada empat macam mode peluncuran yang bisa Anda tetapkan ke atribut
    -+<code><a href="{@docRoot}guide/topics/manifest/activity-element.html#lmode">launchMode</a></code>
    -+:</p>
    -+
    -+<dl>
    -+<dt>{@code "standard"} (mode default)</dt>
    -+  <dd>Default. Sistem membuat instance baru aktivitas dalam tugas yang
    -+akan menjadi tempat memulainya dan mengarahkan intent ke sana. Aktivitas ini bisa dibuat instance-nya beberapa kali,
    -+masing-masing instance bisa dimiliki oleh tugas berbeda, dan satu tugas bisa memiliki beberapa instance.</dd>
    -+<dt>{@code "singleTop"}</dt>
    -+  <dd>Jika instance aktivitas sudah ada di bagian teratas tugas saat ini, sistem
    -+akan mengarahkan intent ke instance tersebut melalui panggilan ke metode {@link
    -+android.app.Activity#onNewIntent onNewIntent()}, bukan membuat instance baru dari
    -+aktivitas tersebut. Aktivitas bisa dibuat instance-nya beberapa kali, masing-masing instance bisa dimiliki
    -+oleh tugas berbeda, dan satu tugas bisa memiliki beberapa instance (namun hanya jika
    -+aktivitas di bagian teratas back-stack <em>bukan</em> instance yang ada dari aktivitas tersebut).
    -+  <p>Misalnya, anggaplah back-stack tugas terdiri dari aktivitas A akar dengan aktivitas B, C,
    -+dan D di bagian teratas (back-stack adalah A-B-C-D; D yang teratas). Intent masuk untuk aktivitas tipe D.
    -+Jika D memiliki mode peluncuran {@code "standard"} default, instance baru dari kelas ini akan diluncurkan dan
    -+back-stack menjadi A-B-C-D-D. Namun, jika mode peluncuran D adalah {@code "singleTop"}, instance
    -+yang ada dari D akan menerima intent melalui {@link
    -+android.app.Activity#onNewIntent onNewIntent()}, karena ada di bagian teratas back-stack&mdash;
    -+back-stack tetap A-B-C-D. Akan tetapi, jika intent masuk untuk aktivitas tipe B, maka
    -+instance B baru akan ditambahkan ke back-stack, sekalipun mode peluncuran adalah{@code "singleTop"}.</p>
    -+  <p class="note"><strong>Catatan:</strong> Bila instance dari aktivitas baru telah dibuat,
    -+pengguna bisa menekan tombol <em>Back</em> untuk kembali ke aktivitas sebelumnya. Namun bila instance
    -+yang ada dari
    -+aktivitas menangani intent baru, pengguna tidak bisa menekan tombol <em>Back</em> untuk kembali ke
    -+status
    -+aktivitas sebelum intent baru masuk di {@link android.app.Activity#onNewIntent
    -+onNewIntent()}.</p>
    -+</dd>
    -+
    -+<dt>{@code "singleTask"}</dt>
    -+  <dd>Sistem membuat tugas baru dan membuat instance aktivitas di akar tugas baru.
    -+Akan tetapi, jika instance aktivitas sudah ada dalam tugas terpisah, sistem akan mengarahkan
    -+intent ke instance yang ada melalui panggilan ke metode {@link
    -+android.app.Activity#onNewIntent onNewIntent()}, bukan membuat instance baru. Hanya
    -+boleh ada satu instance aktivitas untuk setiap kalinya.
    -+  <p class="note"><strong>Catatan:</strong> Meskipun aktivitas dimulai di tugas baru, tombol
    -+<em>Back</em> tetap akan mengembalikan pengguna ke aktivitas sebelumnya.</p></dd>
    -+<dt>{@code "singleInstance"}.</dt>
    -+  <dd>Sama seperti {@code "singleTask"}, namun sistem tidak meluncurkan aktivitas lain ke
    -+tugas yang menyimpan instance. Aktivitas selalu satu dan satu-satunya anggota dari tugasnya;
    -+aktivitas apa pun yang dimulai dengan ini akan dibuka di tugas yang terpisah.</dd>
    -+</dl>
    -+
    -+
    -+<p>Sebagai contoh lainnya, aplikasi Browser Android mendeklarasikan bahwa aktivitas browser web harus
    -+selalu dibuka dalam tugasnya sendiri&mdash;dengan menetapkan mode pembuka {@code singleTask} dalam elemen<a href="{@docRoot}guide/topics/manifest/activity-element.html">{@code &lt;activity&gt;}</a>.
    -+Ini berarti bahwa jika aplikasi Anda mengeluarkan
    -+intent untuk membuka Browser Android, aktivitasnya <em>tidak</em> akan ditempatkan dalam tugas
    -+yang sama seperti aplikasi Anda. Sebagai gantinya, tugas baru akan dimulai untuk Browser atau, jika Browser
    -+sudah memiliki tugas yang berjalan di latar belakang, tugas tersebut akan dimajukan untuk menangani intent
    -+baru.</p>
    -+
    -+<p>Baik aktivitas dimulai dalam tugas baru atau maupun dalam tugas yang sama seperti aktivitas yang memulainya, tombol
    -+<em>Back</em> selalu membawa pengguna ke aktivitas sebelumnya. Akan tetapi, jika
    -+Anda memulai aktivitas yang menetapkan mode pembuka {@code singleTask}, maka jika instance
    -+aktivitas tersebut ada dalam tugas latar belakang, seluruh tugas tersebut akan dibawa ke latar depan. Pada titik
    -+ini, back-stack sekarang menyertakan semua aktivitas dari tugas yang dimajukan, di atas
    -+back-stack. Gambar 4 mengilustrasikan tipe skenario ini.</p>
    -+
    -+<img src="{@docRoot}images/fundamentals/diagram_backstack_singletask_multiactivity.png" alt="" />
    -+<p class="img-caption"><strong>Gambar 4.</strong> Representasi tentang cara aktivitas dengan
    -+mode pembuka "singleTask" ditambahkan ke back-stack. Jika aktivitas tersebut sudah menjadi bagian dari
    -+tugas latar belakang dengan back-stack sendiri, maka seluruh back-stack juga
    -+dimajukan, di atas tugas saat ini.</p>
    -+
    -+<p>Untuk informasi selengkapnya tentang menggunakan mode pembuka dalam file manifes, lihat dokumentasi elemen
    -+<code><a href="{@docRoot}guide/topics/manifest/activity-element.html">&lt;activity&gt;</a></code>
    -+, di mana atribut {@code launchMode} dan nilai-nilai yang diterima
    -+akan dibahas selengkapnya.</p>
    -+
    -+<p class="note"><strong>Catatan:</strong> Perilaku yang Anda tentukan untuk aktivitas dengan atribut <a href="{@docRoot}guide/topics/manifest/activity-element.html#lmode">{@code launchMode}</a>
    -+bisa dikesampingkan dengan flag yang disertakan bersama intent yang memulai aktivitas Anda, seperti dibahas dalam
    -+bagian berikutnya.</p>
    -+
    -+
    -+
    -+<h4 id="#IntentFlagsForTasks">Menggunakan flag Intent</h4>
    -+
    -+<p>Saat memulai aktivitas, Anda bisa memodifikasi asosiasi default aktivitas pada tugasnya
    -+ dengan menyertakan flag dalam intent yang Anda kirimkan ke {@link
    -+android.app.Activity#startActivity startActivity()}. Flag yang bisa Anda gunakan untuk memodifikasi perilaku default
    -+adalah:</p>
    -+
    -+<p>
    -+  <dt>{@link android.content.Intent#FLAG_ACTIVITY_NEW_TASK}</dt>
    -+    <dd>Memulai aktivitas dalam tugas baru. Jika tugas sudah dijalankan untuk aktivitas yang sekarang
    -+Anda mulai, tugas tersebut akan dibawa ke latar depan dengan status terakhir yang dipulihkan dan aktivitas
    -+akan menerima intent baru dalam {@link android.app.Activity#onNewIntent onNewIntent()}.
    -+    <p>Ini menghasilkan perilaku yang sama dengan nilai {@code "singleTask"} <a href="{@docRoot}guide/topics/manifest/activity-element.html#lmode">{@code launchMode}</a>
    -+yang dibahas di bagian sebelumnya.</p></dd>
    -+  <dt>{@link android.content.Intent#FLAG_ACTIVITY_SINGLE_TOP}</dt>
    -+    <dd>Jika aktivitas yang dimulai adalah aktivitas saat ini (di bagian teratas back-stack), maka
    -+instance yang ada akan menerima panggilan ke {@link android.app.Activity#onNewIntent onNewIntent()}
    -+sebagai ganti membuat instance baru aktivitas.
    -+    <p>Ini menghasilkan perilaku yang sama dengan nilai {@code "singleTop"} <a href="{@docRoot}guide/topics/manifest/activity-element.html#lmode">{@code launchMode}</a>
    -+yang dibahas di bagian sebelumnya.</p></dd>
    -+  <dt>{@link android.content.Intent#FLAG_ACTIVITY_CLEAR_TOP}</dt>
    -+    <dd>Jika aktivitas yang dimulai sudah berjalan dalam tugas saat ini, maka sebagai
    -+ganti meluncurkan instance baru aktivitas tersebut, semua kegiatan lain di atasnya akan
    -+dimusnahkan dan intent ini akan disampaikan ke instance aktivitas yang dilanjutkan (sekarang di atas),
    -+melalui {@link android.app.Activity#onNewIntent onNewIntent()}).
    -+    <p>Tidak ada nilai untuk atribut <a href="{@docRoot}guide/topics/manifest/activity-element.html#lmode">{@code launchMode}</a>
    -+ yang menghasilkan perilaku ini.</p>
    -+    <p>{@code FLAG_ACTIVITY_CLEAR_TOP} paling sering digunakan bersama dengan
    -+    {@code FLAG_ACTIVITY_NEW_TASK}.
    -+Bila digunakan bersama-sama, flag ini adalah cara penempatan aktivitas yang ada
    -+dalam tugas lain dan meletakkannya dalam posisi yang memungkinkannya merespons intent. </p>
    -+    <p class="note"><strong>Catatan:</strong> Jika mode pembuka aktivitas yang didesain adalah
    -+{@code "standard"},
    -+ini juga akan dihapus dari back-stack dan instance baru akan diluncurkan di tempatnya untuk menangani
    -+intent yang masuk.  Itu karena instance baru selalu dibuat untuk intent baru bila
    -+mode peluncuran adalah {@code "standard"}. </p>
    -+</dd>
    -+</dl>
    -+
    -+
    -+
    -+
    -+
    -+<h3 id="Affinities">Menangani afinitas</h3>
    -+
    -+<p><em>Afinitas</em> menunjukkan tugas mana yang disukai aktivitas untuk dimiliki. Secara default, semua
    -+aktivitas aplikasi yang sama memiliki afinitas untuk satu sama lain. Jadi, secara default, semua
    -+aktivitas dalam aplikasi yang sama lebih menyukai berada dalam tugas yang sama. Akan tetapi, Anda bisa memodifikasi
    -+afinitas default untuk suatu aktivitas. Aktivitas yang didefinisikan dalam
    -+aplikasi yang berbeda bisa berbagi afinitas, atau aktivitas yang didefinisikan dalam aplikasi yang sama bisa
    -+diberi afinitas tugas yang berbeda.</p>
    -+
    -+<p>Anda bisa memodifikasi afinitas untuk setiap yang diberikan
    -+dengan atribut <a href="{@docRoot}guide/topics/manifest/activity-element.html#aff">{@code taskAffinity}</a>
    -+elemen <a href="{@docRoot}guide/topics/manifest/activity-element.html">{@code &lt;activity&gt;}</a>.</p>
    -+
    -+<p>Atribut <a href="{@docRoot}guide/topics/manifest/activity-element.html#aff">{@code taskAffinity}</a>
    -+mengambil nilai string, yang harus unik dari nama paket default
    -+yang dideklarasikan dalam elemen <a href="{@docRoot}guide/topics/manifest/manifest-element.html">
    -+{@code &lt;manifest&gt;}
    -+</a>, karena sistem menggunakan nama untuk mengidentifikasi afinitas
    -+tugas default untuk aplikasi.</p>
    -+
    -+<p>Afinitas berperan dalam dua keadaan:</p>
    -+<ul>
    -+  <li>Bila intent yang meluncurkan aktivitas berisi flag
    -+  {@link android.content.Intent#FLAG_ACTIVITY_NEW_TASK}
    -+.
    -+
    -+<p>Aktivitas baru, secara default, diluncurkan ke dalam tugas aktivitas
    -+yang disebut {@link android.app.Activity#startActivity startActivity()}. Ini didorong ke back-stack
    -+yang sama seperti caller.  Akan tetapi, jika intent yang diteruskan ke
    -+{@link android.app.Activity#startActivity startActivity()}
    -+berisi flag {@link android.content.Intent#FLAG_ACTIVITY_NEW_TASK}
    -+, maka sistem akan mencari tugas yang berbeda untuk menampung aktivitas baru. Sering kali, itu adalah tugas baru.
    -+Akan tetapi, tidak harus demikian.  Jika sudah ada tugas lama dengan afinitas yang sama seperti
    -+aktivitas baru, aktivitas ini akan diluncurkan ke dalam tugas tersebut.  Jika tidak, tugas baru akan dimulai.</p>
    -+
    -+<p>Jika flag ini menyebabkan aktivitas memulai tugas baru dan pengguna menekan tombol <em>Home</em>
    -+untuk meninggalkannya,
    -+harus ada cara bagi pengguna untuk mengarahkan kembali ke tugas. Beberapa entitas (seperti
    -+notification manager) selalu memulai aktivitas dalam tugas eksternal, tidak pernah sebagai bagian dari miliknya sendiri, jadi
    -+selalu menempatkan {@code FLAG_ACTIVITY_NEW_TASK} dalam intent yang diteruskan ke
    -+{@link android.app.Activity#startActivity startActivity()}.
    -+Jika Anda memiliki aktivitas yang bisa dipanggil melalui
    -+entitas eksternal yang mungkin menggunakan flag ini, hati-hatilah karena pengguna memiliki cara independen untuk kembali
    -+ke tugas yang telah dimulai, seperti dengan ikon launcher (aktivitas akar dari tugas
    -+memiliki filter intent {@link android.content.Intent#CATEGORY_LAUNCHER}; lihat bagian <a href="#Starting">Memulai tugas</a> di bawah ini).</p>
    -+</li>
    -+
    -+  <li>Bila aktivitas memiliki atribut <a href="{@docRoot}guide/topics/manifest/activity-element.html#reparent">
    -+{@code allowTaskReparenting}</a> sendiri yang diatur ke {@code "true"}.
    -+  <p>Dalam hal ini, aktivitas bisa berpindah dari tugas yang dimulainya ke tugas yang afinitasnya
    -+dimilikinya, bila tugas tersebut di bawa ke latar depan.</p>
    -+  <p>Misalnya, anggaplah sebuah aktivitas melaporkan kondisi cuaca di sejumlah kota terpilih
    -+yang didefinisikan sebagai bagian dari aplikasi perjalanan.  Aktivitas memiliki afinitas yang sama dengan aktivitas lain dalam aplikasi
    -+yang sama (afinitas aplikasi default) dan aktivitas ini memungkinkan re-parenting dengan atribut ini.
    -+Bila salah satu aktivitas Anda memulai aktivitas laporan cuaca, awalnya aktivitas ini dimiliki oleh tugas
    -+yang sama dengan aktivitas Anda. Akan tetapi, bila tugas aplikasi perjalanan di bawa ke latar depan,
    -+aktivitas laporan cuaca akan ditetapkan kembali ke tugas itu dan ditampilkan di dalamnya.</p>
    -+</li>
    -+</ul>
    -+
    -+<p class="note"><strong>Tip:</strong> Jika file {@code .apk} berisi lebih dari satu "aplikasi"
    -+dari sudut pandang pengguna, Anda mungkin perlu menggunakan atribut <a href="{@docRoot}guide/topics/manifest/activity-element.html#aff">{@code taskAffinity}</a>
    -+ untuk menetapkan afinitas berbeda pada aktivitas yang terkait dengan setiap "aplikasi".</p>
    -+
    -+
    -+
    -+<h3 id="Clearing">Menghapus back-stack</h3>
    -+
    -+<p>Jika pengguna meninggalkan tugas dalam waktu yang lama, sistem akan menghapus tugas semua aktivitas kecuali
    -+aktivitas akar.  Bila pengguna kembali ke tugas itu lagi, hanya aktivitas akar yang akan dipulihkan.
    -+Sistem berperilaku seperti ini, karena, setelah sekian waktu, pengguna mungkin telah mengabaikan
    -+apa yang mereka kerjakan sebelum dan kembali ke tugas itu untuk memulai sesuatu yang baru. </p>
    -+
    -+<p>Ada beberapa atribut aktivitas yang bisa Anda gunakan untuk memodifikasi perilaku ini: </p>
    -+
    -+<dl>
    -+<dt><code><a
    -+href="{@docRoot}guide/topics/manifest/activity-element.html#always">alwaysRetainTaskState</a></code>
    -+</dt>
    -+<dd>Jika atribut ini ditetapkan ke {@code "true"} dalam aktivitas akar tugas,
    -+perilaku default yang baru dijelaskan tidak akan terjadi.
    -+ Tugas akan mempertahankan semua aktivitas dalam back-stack bahkan setelah sekian lama.</dd>
    -+
    -+<dt><code><a
    -+href="{@docRoot}guide/topics/manifest/activity-element.html#clear">clearTaskOnLaunch</a></code></dt>
    -+<dd>Jika atribut ini diatur ke {@code "true"} dalam aktivitas akar tugas, back-
    -+stack akan dihapus hingga aktivitas akar bila pengguna meninggalkan tugas
    -+dan kembali lagi.  Dengan kata lain, ini adalah lawan dari
    -+<a href="{@docRoot}guide/topics/manifest/activity-element.html#always">
    -+{@code alwaysRetainTaskState}</a>. Pengguna selalu kembali ke tugas dengan
    -+status awalnya, walaupun hanya sebentar meninggalkan tugas.</dd>
    -+
    -+<dt><code><a
    -+href="{@docRoot}guide/topics/manifest/activity-element.html#finish">finishOnTaskLaunch</a></code>
    -+</dt>
    -+<dd>Atribut ini seperti <a href="{@docRoot}guide/topics/manifest/activity-element.html#clear">{@code clearTaskOnLaunch}</a>,
    -+namun beroperasi pada
    -+satu aktivitas, bukan pada seluruh tugas.  Hal ini juga bisa menyebabkan aktivitas
    -+hilang, termasuk aktivitas akar.  Bila ini diatur ke {@code "true"},
    -+aktivitas akan tetap menjadi bagian dari tugas hanya untuk sesi saat ini.  Jika pengguna
    -+keluar dan kemudian kembali ke tugas tersebut, tugas tidak akan ada lagi.</dd>
    -+</dl>
    -+
    -+
    -+
    -+
    -+<h3 id="Starting">Memulai tugas</h3>
    -+
    -+<p>Anda bisa mengatur aktivitas sebagai titik masuk untuk tugas dengan memberikan filter intent dengan
    -+{@code "android.intent.action.MAIN"} sebagai tindakan yang ditetapkan dan
    -+{@code "android.intent.category.LAUNCHER"}
    -+sebagai kategori yang ditetapkan. Misalnya:</p>
    -+
    -+<pre>
    -+&lt;activity ... &gt;
    -+    &lt;intent-filter ... &gt;
    -+        &lt;action android:name="android.intent.action.MAIN" /&gt;
    -+        &lt;category android:name="android.intent.category.LAUNCHER" /&gt;
    -+    &lt;/intent-filter&gt;
    -+    ...
    -+&lt;/activity&gt;
    -+</pre>
    -+
    -+<p>Filter intent semacam ini akan menyebabkan ikon dan label untuk
    -+aktivitas ditampilkan dalam launcher aplikasi, yang akan memberi cara kepada pengguna untuk meluncurkan aktivitas dan
    -+kembali ke tugas yang dibuatnya kapan saja setelah ia telah diluncurkan.
    -+</p>
    -+
    -+<p>Kemampuan kedua ini penting: Pengguna harus bisa meninggalkan tugas dan kemudian kembali ke tugas tersebut
    -+nanti dengan menggunakan launcher aktivitas ini. Karena itu, kedua <a href="#LaunchModes">mode
    -+pembuka</a> yang menandai aktivitas selalu memulai tugas, {@code "singleTask"} dan
    -+{@code "singleInstance"}, hanya boleh digunakan bila aktivitas memiliki filter
    -+{@link android.content.Intent#ACTION_MAIN}
    -+dan {@link android.content.Intent#CATEGORY_LAUNCHER}. Bayangkan, misalnya, apa yang akan
    -+terjadi jika filter tidak ada: Intent meluncurkan aktivitas{@code "singleTask"}, memulai
    -+tugas yang baru, dan pengguna menghabiskan lebih banyak waktu mengerjakan tugas tersebut. Pengguna kemudian menekan tombol
    -+<em>Home</em>. Tugas kini dikirim ke latar belakang dan tidak terlihat. Sekarang pengguna tidak memiliki cara untuk kembali
    -+ke tugas tersebut, karena tidak dinyatakan dalam launcher aplikasi.</p>
    -+
    -+<p>Untuk kasus-kasus di mana Anda tidak ingin pengguna bisa kembali ke aktivitas, atur dalam
    -+<code><a href="{@docRoot}guide/topics/manifest/activity-element.html">&lt;activity&gt;</a></code>
    -+ pada
    -+<a href="{@docRoot}guide/topics/manifest/activity-element.html#finish">{@code finishOnTaskLaunch}</a>
    -+elemen ke {@code "true"} (lihat <a href="#Clearing">Menghapus back-stack</a>).</p>
    -+
    -+<p>Informasi lebih jauh tentang cara menyatakan dan mengelola tugas dan aktivitas dalam
    -+layar ikhtisar tersedia dalam<a href="{@docRoot}guide/components/recents.html">
    -+Layar Ikhtisar</a>.</p>
    -+
    -+<!--
    -+<h2>Beginner's Path</h2>
    -+
    -+<p>For more information about how to use intents to
    -+activate other application components and publish the intents to which your components
    -+respond, continue with the <b><a
    -+href="{@docRoot}guide/components/intents-filters.html">Intents and Intent
    -+Filters</a></b> document.</p>
    -+-->
    -diff --git a/docs/html-intl/intl/id/guide/index.jd b/docs/html-intl/intl/id/guide/index.jd
    -new file mode 100644
    -index 0000000..f24fab6
    ---- /dev/null
    -+++ b/docs/html-intl/intl/id/guide/index.jd
    -@@ -0,0 +1,74 @@
    -+page.title=Pengantar Android
    -+
    -+@jd:body
    -+
    -+
    -+<div class="sidebox" style="width:220px"><!-- width to match col-4 below -->
    -+<p>Untuk mempelajari cara kerja aplikasi, mulailah dengan
    -+<a href="{@docRoot}guide/components/fundamentals.html">Dasar-Dasar Aplikasi</a>.</p>
    -+<p>Untuk langsung memulai pemrograman, bacalah <a href="{@docRoot}training/basics/firstapp/index.html">Membangun Aplikasi Pertama Anda.</a></p>
    -+</div>
    -+
    -+<p>Android menyediakan kerangka kerja aplikasi yang kaya dan memungkinkan Anda membangun aplikasi dan permainan
    -+inovatif untuk perangkat seluler di lingkungan bahasa pemrograman Java. Dokumen yang tercantum di navigasi
    -+sebelah kiri menyediakan detail tentang cara membangun aplikasi menggunakan berbagai API Android.</p>
    -+
    -+<p>Jika Anda masih baru dengan pengembangan Android, Anda perlu memahami
    -+konsep dasar berikut mengenai kerangka kerja aplikasi Android:</p>
    -+
    -+
    -+<div class="landing-banner">
    -+
    -+<div class="col-6">
    -+
    -+<h4>Aplikasi menyediakan beberapa titik masuk</h4>
    -+
    -+<p>Aplikasi Android dibangun sebagai kombinasi beragam komponen yang bisa dipanggil
    -+satu per satu. Misalnya, satu <em>aktivitas</em> individual menyediakan satu
    -+layar untuk antarmuka pengguna, dan <em>layanan</em> yang secara terpisah melakukan
    -+tugas di latar belakang.</p>
    -+
    -+<p>Dari satu komponen Anda dapat memulai komponen lainnya menggunakan <em>intent</em>. Anda bahkan dapat memulai
    -+satu komponen dalam aplikasi berbeda, seperti aktivitas dalam aplikasi peta untuk menampilkan alamat. Model ini
    -+menyediakan beberapa titik masuk untuk aplikasi tunggal dan memungkinkan setiap aplikasi untuk berfungsi sebagai "default"
    -+pengguna bagi tindakan yang dapat dipanggil aplikasi lain.</p>
    -+
    -+
    -+<p><b>Ketahui selengkapnya:</b></p>
    -+<ul class="nolist">
    -+<li><a href="{@docRoot}guide/components/fundamentals.html">Dasar-Dasar Aplikasi</a>
    -+<li><a href="{@docRoot}guide/components/intents-filters.html">Intent dan Filter Intent</a>
    -+<li><a href="{@docRoot}guide/components/activities.html">Aktivitas</a>
    -+</ul>
    -+
    -+</div>
    -+
    -+
    -+<div class="col-6">
    -+
    -+<h4>Aplikasi beradaptasi dengan perangkat berbeda</h4>
    -+
    -+<p>Android menyediakan kerangka kerja aplikasi adaptif yang memungkinkan Anda menyediakan sumber daya unik
    -+bagi konfigurasi perangkat yang berbeda-beda. Misalnya, Anda bisa membuat berbagai file layout
    -+XML untuk ukuran layar yang berbeda-beda dan sistem akan menentukan
    -+layout yang akan diterapkan berdasarkan ukuran layar perangkat yang ada saat ini.</p>
    -+
    -+<p>Anda dapat melakukan query ketersediaan fitur perangkat saat dijalankan (runtime) jika ada fitur aplikasi yang memerlukan
    -+perangkat keras spesifik seperti kamera. Jika diperlukan, Anda juga bisa mendeklarasikan fitur yang dibutuhkan aplikasi
    -+agar pasar aplikasi seperti Google Play Store tidak mengizinkan instalasi pada perangkat yang tidak
    -+mendukung fitur itu.</p>
    -+
    -+
    -+<p><b>Ketahui selengkapnya:</b></p>
    -+<ul class="nolist">
    -+<li><a href="{@docRoot}guide/practices/compatibility.html">Kompatibilitas Perangkat</a>
    -+<li><a href="{@docRoot}guide/topics/resources/overview.html">Ikhtisar Sumber Daya</a>
    -+<li><a href="{@docRoot}guide/topics/ui/overview.html">Ikhtisar Antarmuka Pengguna</a>
    -+</ul>
    -+
    -+</div>
    -+
    -+</div><!-- end landing-banner -->
    -+
    -+
    -+
    -diff --git a/docs/html-intl/intl/id/guide/platform/j8-jack.jd b/docs/html-intl/intl/id/guide/platform/j8-jack.jd
    -new file mode 100644
    -index 0000000..4389184
    ---- /dev/null
    -+++ b/docs/html-intl/intl/id/guide/platform/j8-jack.jd
    -@@ -0,0 +1,197 @@
    -+page.title=Fitur Bahasa Java 8
    -+page.keywords="android N", "Java 8", "Jack"
    -+@jd:body
    -+
    -+<div id="qv-wrapper">
    -+  <div id="qv">
    -+    <ol>
    -+      <li>
    -+        <a href="#supported-features">API dan Fitur Bahasa Java 8 yang didukung</a>
    -+      </li>
    -+      <li>
    -+        <a href="#configuration">Mengaktifkan Fitur Java 8 dan Jack Toolchain</a>
    -+      </li>
    -+    </ol>
    -+  </div>
    -+</div>
    -+
    -+<p>Android N memperkenalkan dukungan untuk fitur bahasa Java 8
    -+  yang bisa Anda gunakan saat mengembangkan aplikasi yang menargetkan Android N.
    -+  Halaman ini menjelaskan fitur bahasa baru yang didukung dalam Android N
    -+  Preview, cara menyiapkan proyek Anda dengan benar untuk menggunakannya, dan setiap masalah
    -+  yang diketahui yang mungkin Anda temui.
    -+</p>
    -+
    -+<p>Untuk mulai menggunakan fitur-fitur ini, Anda perlu mengunduh dan menyiapkan Android
    -+Studio 2.1 dan Android N Preview SDK, yang menyertakan
    -+Jack toolchain yang diperlukan dan Plugin Android untuk Gradle yang telah diperbarui. Jika Anda belum
    -+memasang Android N Preview SDK, lihat <a href="{@docRoot}preview/setup-sdk.html">Menyiapkan Pengembangan untuk Android N</a>.</p>
    -+
    -+
    -+
    -+<p class="note">
    -+  <strong>Catatan:</strong> Menggunakan fitur bahasa Java 8 yang baru bukanlah
    -+  persyaratan untuk mengembangkan aplikasi yang menargetkan platform Android N. Jika Anda
    -+  tidak ingin menulis kode dengan fitur bahasa Java 8, Anda bisa membiarkan nilai kompatibilitas
    -+  sumber dan target proyek disetel ke Java 7, namun Anda tetap harus
    -+  mengompilasi dengan JDK 8 untuk membangun pada platform Android N.
    -+</p>
    -+
    -+<h2 id="supported-features">
    -+  API dan Fitur Bahasa Java 8 yang Didukung
    -+</h2>
    -+
    -+<p>
    -+  Saat ini tidak semua fitur bahasa Java 8 didukung Android. Akan tetapi,
    -+  fitur berikut sekarang tersedia saat mengembangkan aplikasi yang menargetkan
    -+  Android N Preview:
    -+</p>
    -+
    -+<ul>
    -+  <li>
    -+    <a class="external-link" href="https://docs.oracle.com/javase/tutorial/java/IandI/defaultmethods.html">Metode
    -+    antarmuka default dan statis</a>
    -+  </li>
    -+
    -+  <li>
    -+    <a class="external-link" href="https://docs.oracle.com/javase/tutorial/java/javaOO/lambdaexpressions.html">
    -+    Ekspresi Lambda</a> (juga tersedia pada API level 23 dan yang lebih rendah)
    -+  </li>
    -+
    -+  <li>
    -+    <a class="external-link" href="https://docs.oracle.com/javase/tutorial/java/annotations/repeating.html">Anotasi
    -+    yang bisa diulang</a>
    -+  </li>
    -+
    -+  <li>
    -+    <a class="external-link" href="https://docs.oracle.com/javase/tutorial/java/javaOO/methodreferences.html">
    -+    Referensi Metode</a> (juga tersedia pada API level 23 dan yang lebih rendah)
    -+  </li>
    -+</ul>
    -+
    -+<p class="note">
    -+  <strong>Catatan:</strong> Untuk menguji ekspresi lambda dan referensi metode pada
    -+  Android versi sebelumnya, bukalah file {@code build.gradle}
    -+  Anda, serta setel {@code compileSdkVersion} dan {@code targetSdkVersion} ke 23 atau
    -+  yang lebih rendah. Anda tetap perlu <a href="#configuration">mengaktifkan Jack
    -+  toolchain</a> untuk menggunakan fitur Java 8 ini.
    -+</p>
    -+
    -+<p>
    -+  Selain itu, API fitur bahasa Java 8 berikut ini sekarang tersedia:
    -+</p>
    -+
    -+<ul>
    -+  <li>Reflection API dan API terkait bahasa:
    -+    <ul>
    -+      <li>
    -+        <a class="external-link" href="https://docs.oracle.com/javase/8/docs/api/java/lang/FunctionalInterface.html">
    -+        {@code java.lang.FunctionalInterface}</a>
    -+      </li>
    -+
    -+      <li>
    -+        <a class="external-link" href="https://docs.oracle.com/javase/8/docs/api/java/lang/annotation/Repeatable.html">
    -+        {@code java.lang.annotation.Repeatable}</a>
    -+      </li>
    -+
    -+      <li>
    -+        <a class="external-link" href="https://docs.oracle.com/javase/8/docs/api/java/lang/reflect/Method.html#isDefault--">
    -+        {@code java.lang.reflect.Method.isDefault()}</a>
    -+      </li>
    -+
    -+      <li>dan Reflection API yang terkait dengan anotasi yang bisa diulang, seperti
    -+     <a class="external-link" href="https://docs.oracle.com/javase/8/docs/api/java/lang/reflect/AnnotatedElement.html#getAnnotationsByType-java.lang.Class-">
    -+{@code AnnotatedElement.getAnnotationsByType(Class)}</a>
    -+      </li>
    -+    </ul>
    -+  </li>
    -+
    -+  <li>Utility API:
    -+    <ul>
    -+      <li>
    -+        <a class="external-link" href="https://docs.oracle.com/javase/8/docs/api/java/util/function/package-summary.html">
    -+        {@code java.util.function}</a>
    -+      </li>
    -+
    -+      <li>
    -+        <a class="external-link" href="https://docs.oracle.com/javase/8/docs/api/java/util/stream/package-summary.html">
    -+        {@code java.util.stream}</a>
    -+      </li>
    -+    </ul>
    -+  </li>
    -+</ul>
    -+
    -+<h2 id="configuration">
    -+  Mengaktifkan Fitur Java 8 dan Jack Toolchain
    -+</h2>
    -+
    -+<p>
    -+  Agar dapat menggunakan fitur bahasa Java 8 yang baru, Anda juga perlu menggunakan
    -+  <a class="external-link" href="https://source.android.com/source/jack.html">Jack toolchain</a> yang baru.  Toolchain Android
    -+ yang baru ini mengompilasi sumber bahasa Java menjadi dex
    -+  bytecode yang bisa dibaca Android, memiliki format  pustaka {@code .jack} sendiri, dan menyediakan sebagian besar fitur toolchain
    -+  sebagai bagian dari alat bantu tunggal: pengemasan ulang, penciutan, pengaburan, dan
    -+  multidex.
    -+</p>
    -+
    -+<p>Inilah perbandingan dua toolchain yang digunakan untuk membangun file Android DEX:</p>
    -+<ul>
    -+  <li>Toolchain javac lawas:<br>
    -+  <b>javac</b> ({@code .java} --&gt; {@code .class}) --&gt; <b>dx</b> ({@code
    -+ .class} --&gt; {@code .dex})
    -+  </li>
    -+
    -+  <li>Jack Toolchain baru:<br>
    -+  <b>Jack</b> ({@code .java} --&gt; {@code .jack} --&gt; {@code .dex})
    -+  </li>
    -+</ul>
    -+
    -+<h3>
    -+  Mengonfigurasi Gradle
    -+</h3>
    -+
    -+<p>
    -+  Untuk mengaktifkan fitur bahasa Java 8 dan Jack bagi proyek Anda, masukkan
    -+  yang berikut dalam file {@code build.gradle} level modul Anda:
    -+</p>
    -+
    -+<pre>
    -+android {
    -+  ...
    -+  defaultConfig {
    -+    ...
    -+    jackOptions {
    -+      enabled true
    -+    }
    -+  }
    -+  compileOptions {
    -+    sourceCompatibility JavaVersion.VERSION_1_8
    -+    targetCompatibility JavaVersion.VERSION_1_8
    -+  }
    -+}
    -+</pre>
    -+
    -+<h3 id="known-issues">
    -+  Masalah yang Diketahui
    -+</h3>
    -+
    -+<p>
    -+  <a href="{@docRoot}tools/building/building-studio.html#instant-run">Instant
    -+  Run</a> saat ini tidak berfungsi pada Jack dan akan dinonaktifkan saat menggunakan
    -+  toolchain baru.
    -+</p>
    -+
    -+<p>Karena Jack tidak menghasilkan file kelas antara saat mengompilasi sebuah
    -+aplikasi, alat yang bergantung pada file-file ini sekarang tidak berfungsi pada Jack. Beberapa
    -+contoh alat ini adalah:</p>
    -+
    -+<ul>
    -+  <li>Pendeteksi lint yang beroperasi pada file kelas
    -+  </li>
    -+
    -+  <li>Alat dan pustaka yang mewajibkan file kelas aplikasi (misalnya
    -+pengujian instrumentasi dengan JaCoCo)
    -+  </li>
    -+</ul>
    -+
    -+<p>Jika Anda menemukan masalah lain saat menggunakan Jack, <a href="http://tools.android.com/filing-bugs">laporkan bug</a>.</p>
    -\ No newline at end of file
    -diff --git a/docs/html-intl/intl/id/guide/topics/manifest/manifest-intro.jd b/docs/html-intl/intl/id/guide/topics/manifest/manifest-intro.jd
    -new file mode 100644
    -index 0000000..050abf4
    ---- /dev/null
    -+++ b/docs/html-intl/intl/id/guide/topics/manifest/manifest-intro.jd
    -@@ -0,0 +1,517 @@
    -+page.title=Manifes Aplikasi
    -+@jd:body
    -+
    -+<div id="qv-wrapper">
    -+<div id="qv">
    -+
    -+<h2>Dalam dokumen ini</h2>
    -+<ol>
    -+<li><a href="#filestruct">Struktur File Manifes</a></li>
    -+<li><a href="#filec">Konvensi File</a>
    -+<li><a href="#filef">Fitur File</a>
    -+	<ol>
    -+	<li><a href="#ifs">Filter Intent</a></li>
    -+	<li><a href="#iconlabel">Ikon dan Label</a></li>
    -+	<li><a href="#perms">Izin</a></li>
    -+	<li><a href="#libs">Pustaka</a></li>
    -+	</ol></li>
    -+</ol>
    -+</div>
    -+</div>
    -+
    -+<p>
    -+  Setiap aplikasi harus memiliki file AndroidManifest.xml (bernama persis seperti ini) di direktori akar.
    -+ <span itemprop="description">File manifes
    -+ menyediakan informasi penting tentang aplikasi ke sistem Android,
    -+ informasi yang harus dimiliki sistem agar bisa menjalankan setiap kode
    -+aplikasi.</span> Di antaranya, manifes melakukan hal berikut ini:
    -+</p>
    -+
    -+<ul>
    -+<li>Menamai paket Java untuk aplikasi.
    -+Nama paket berfungsi sebagai identifier unik untuk aplikasi.</li>
    -+
    -+<li>Menjelaskan berbagai komponen aplikasi&mdash;aktivitas,
    -+ layanan, penerima siaran, dan penyedia konten
    -+yang membentuk aplikasi.  Menamai kelas yang mengimplementasikan setiap komponen dan
    -+mempublikasikan kemampuannya (misalnya, pesan {@link android.content.Intent
    -+Intent} mana yang bisa ditanganinya).  Deklarasi ini memberi tahu sistem Android mengenai
    -+komponennya dan dalam kondisi apa bisa diluncurkan.</li>
    -+
    -+<li>Menentukan proses yang akan menjadi host komponen aplikasi.</li>
    -+
    -+<li>Mendeklarasikan izin aplikasi mana yang harus dimiliki untuk
    -+mengakses bagian yang dilindungi pada API dan berinteraksi dengan aplikasi lain.</li>
    -+
    -+<li>Juga mendeklarasikan izin lain yang harus dimiliki untuk
    -+untuk berinteraksi dengan komponen aplikasi.</li>
    -+
    -+<li>Mencantumkan daftar kelas {@link android.app.Instrumentation} yang memberikan
    -+profil dan informasi lain saat aplikasi berjalan.  Deklarasi ini
    -+hanya ada di manifes saat aplikasi dibuat dan diuji;
    -+ deklarasi dihapus sebelum aplikasi dipublikasikan.</li>
    -+
    -+<li>Mendeklarasikan tingkat minimum API Android yang diperlukan
    -+aplikasi.</li>
    -+
    -+<li>Mencantumkan daftar pustaka yang harus ditautkan aplikasi.</li>
    -+</ul>
    -+
    -+
    -+<h2 id="filestruct">Struktur File Manifes</h2>
    -+
    -+<p>
    -+Diagram di bawah ini menampilkan struktur umum file manifes dan setiap
    -+elemen yang bisa ditampungnya.  Setiap elemen, bersama
    -+atributnya, didokumentasikan secara lengkap dalam file terpisah.  Untuk melihat
    -+informasi terperinci tentang setiap elemen, klik nama elemen dalam diagram,
    -+dalam daftar abjad elemen yang mengikuti diagram, atau penyebutan nama
    -+elemen lainnya.
    -+</p>
    -+
    -+<pre>
    -+&lt;?xml version="1.0" encoding="utf-8"?&gt;
    -+
    -+<a href="{@docRoot}guide/topics/manifest/manifest-element.html">&lt;manifest&gt;</a>
    -+
    -+    <a href="{@docRoot}guide/topics/manifest/uses-permission-element.html">&lt;uses-permission /&gt;</a>
    -+    <a href="{@docRoot}guide/topics/manifest/permission-element.html">&lt;permission /&gt;</a>
    -+    <a href="{@docRoot}guide/topics/manifest/permission-tree-element.html">&lt;permission-tree /&gt;</a>
    -+    <a href="{@docRoot}guide/topics/manifest/permission-group-element.html">&lt;permission-group /&gt;</a>
    -+    <a href="{@docRoot}guide/topics/manifest/instrumentation-element.html">&lt;instrumentation /&gt;</a>
    -+    <a href="{@docRoot}guide/topics/manifest/uses-sdk-element.html">&lt;uses-sdk /&gt;</a>
    -+    <a href="{@docRoot}guide/topics/manifest/uses-configuration-element.html">&lt;uses-configuration /&gt;</a>  <!-- ##api level 3## -->
    -+    <a href="{@docRoot}guide/topics/manifest/uses-feature-element.html">&lt;uses-feature /&gt;</a>  <!-- ##api level 4## -->
    -+    <a href="{@docRoot}guide/topics/manifest/supports-screens-element.html">&lt;supports-screens /&gt;</a>  <!-- ##api level 4## -->
    -+    <a href="{@docRoot}guide/topics/manifest/compatible-screens-element.html">&lt;compatible-screens /&gt;</a>  <!-- ##api level 9## -->
    -+    <a href="{@docRoot}guide/topics/manifest/supports-gl-texture-element.html">&lt;supports-gl-texture /&gt;</a>  <!-- ##api level 11## -->
    -+
    -+    <a href="{@docRoot}guide/topics/manifest/application-element.html">&lt;application&gt;</a>
    -+
    -+        <a href="{@docRoot}guide/topics/manifest/activity-element.html">&lt;activity&gt;</a>
    -+            <a href="{@docRoot}guide/topics/manifest/intent-filter-element.html">&lt;intent-filter&gt;</a>
    -+                <a href="{@docRoot}guide/topics/manifest/action-element.html">&lt;action /&gt;</a>
    -+                <a href="{@docRoot}guide/topics/manifest/category-element.html">&lt;category /&gt;</a>
    -+                <a href="{@docRoot}guide/topics/manifest/data-element.html">&lt;data /&gt;</a>
    -+            <a href="{@docRoot}guide/topics/manifest/intent-filter-element.html">&lt;/intent-filter&gt;</a>
    -+            <a href="{@docRoot}guide/topics/manifest/meta-data-element.html">&lt;meta-data /&gt;</a>
    -+        <a href="{@docRoot}guide/topics/manifest/activity-element.html">&lt;/activity&gt;</a>
    -+
    -+        <a href="{@docRoot}guide/topics/manifest/activity-alias-element.html">&lt;activity-alias&gt;</a>
    -+            <a href="{@docRoot}guide/topics/manifest/intent-filter-element.html">&lt;intent-filter&gt;</a> . . . <a href="{@docRoot}guide/topics/manifest/intent-filter-element.html">&lt;/intent-filter&gt;</a>
    -+            <a href="{@docRoot}guide/topics/manifest/meta-data-element.html">&lt;meta-data /&gt;</a>
    -+        <a href="{@docRoot}guide/topics/manifest/activity-alias-element.html">&lt;/activity-alias&gt;</a>
    -+
    -+        <a href="{@docRoot}guide/topics/manifest/service-element.html">&lt;service&gt;</a>
    -+            <a href="{@docRoot}guide/topics/manifest/intent-filter-element.html">&lt;intent-filter&gt;</a> . . . <a href="{@docRoot}guide/topics/manifest/intent-filter-element.html">&lt;/intent-filter&gt;</a>
    -+            <a href="{@docRoot}guide/topics/manifest/meta-data-element.html">&lt;meta-data/&gt;</a>
    -+        <a href="{@docRoot}guide/topics/manifest/service-element.html">&lt;/service&gt;</a>
    -+
    -+        <a href="{@docRoot}guide/topics/manifest/receiver-element.html">&lt;receiver&gt;</a>
    -+            <a href="{@docRoot}guide/topics/manifest/intent-filter-element.html">&lt;intent-filter&gt;</a> . . . <a href="{@docRoot}guide/topics/manifest/intent-filter-element.html">&lt;/intent-filter&gt;</a>
    -+            <a href="{@docRoot}guide/topics/manifest/meta-data-element.html">&lt;meta-data /&gt;</a>
    -+        <a href="{@docRoot}guide/topics/manifest/receiver-element.html">&lt;/receiver&gt;</a>
    -+
    -+        <a href="{@docRoot}guide/topics/manifest/provider-element.html">&lt;provider&gt;</a>
    -+            <a href="{@docRoot}guide/topics/manifest/grant-uri-permission-element.html">&lt;grant-uri-permission /&gt;</a>
    -+            <a href="{@docRoot}guide/topics/manifest/meta-data-element.html">&lt;meta-data /&gt;</a>
    -+            <a href="{@docRoot}guide/topics/manifest/path-permission-element.html">&lt;path-permission /&gt;</a>
    -+        <a href="{@docRoot}guide/topics/manifest/provider-element.html">&lt;/provider&gt;</a>
    -+
    -+        <a href="{@docRoot}guide/topics/manifest/uses-library-element.html">&lt;uses-library /&gt;</a>
    -+
    -+    <a href="{@docRoot}guide/topics/manifest/application-element.html">&lt;/application&gt;</a>
    -+
    -+<a href="{@docRoot}guide/topics/manifest/manifest-element.html">&lt;/manifest&gt;</a>
    -+</pre>
    -+
    -+<p>
    -+Semua elemen yang bisa muncul dalam file manifes tercantum di bawah ini
    -+dalam urutan abjad.  Ini adalah satu-satunya elemen legal; Anda tidak bisa
    -+menambahkan elemen atau atribut sendiri.
    -+</p>
    -+
    -+<p style="margin-left: 2em">
    -+<code><a href="{@docRoot}guide/topics/manifest/action-element.html">&lt;action&gt;</a></code>
    -+<br/><code><a href="{@docRoot}guide/topics/manifest/activity-element.html">&lt;activity&gt;</a></code>
    -+<br/><code><a href="{@docRoot}guide/topics/manifest/activity-alias-element.html">&lt;activity-alias&gt;</a></code>
    -+<br/><code><a href="{@docRoot}guide/topics/manifest/application-element.html">&lt;application&gt;</a></code>
    -+<br/><code><a href="{@docRoot}guide/topics/manifest/category-element.html">&lt;category&gt;</a></code>
    -+<br/><code><a href="{@docRoot}guide/topics/manifest/data-element.html">&lt;data&gt;</a></code>
    -+<br/><code><a href="{@docRoot}guide/topics/manifest/grant-uri-permission-element.html">&lt;grant-uri-permission&gt;</a></code>
    -+<br/><code><a href="{@docRoot}guide/topics/manifest/instrumentation-element.html">&lt;instrumentation&gt;</a></code>
    -+<br/><code><a href="{@docRoot}guide/topics/manifest/intent-filter-element.html">&lt;intent-filter&gt;</a></code>
    -+<br/><code><a href="{@docRoot}guide/topics/manifest/manifest-element.html">&lt;manifest&gt;</a></code>
    -+<br/><code><a href="{@docRoot}guide/topics/manifest/meta-data-element.html">&lt;meta-data&gt;</a></code>
    -+<br/><code><a href="{@docRoot}guide/topics/manifest/permission-element.html">&lt;permission&gt;</a></code>
    -+<br/><code><a href="{@docRoot}guide/topics/manifest/permission-group-element.html">&lt;permission-group&gt;</a></code>
    -+<br/><code><a href="{@docRoot}guide/topics/manifest/permission-tree-element.html">&lt;permission-tree&gt;</a></code>
    -+<br/><code><a href="{@docRoot}guide/topics/manifest/provider-element.html">&lt;provider&gt;</a></code>
    -+<br/><code><a href="{@docRoot}guide/topics/manifest/receiver-element.html">&lt;receiver&gt;</a></code>
    -+<br/><code><a href="{@docRoot}guide/topics/manifest/service-element.html">&lt;service&gt;</a></code>
    -+<br/><code><a href="{@docRoot}guide/topics/manifest/supports-screens-element.html">&lt;supports-screens&gt;</a></code>  <!-- ##api level 4## -->
    -+<br/><code><a href="{@docRoot}guide/topics/manifest/uses-configuration-element.html">&lt;uses-configuration&gt;</a></code>  <!-- ##api level 3## -->
    -+<br/><code><a href="{@docRoot}guide/topics/manifest/uses-feature-element.html">&lt;uses-feature&gt;</a></code>  <!-- ##api level 4## -->
    -+<br/><code><a href="{@docRoot}guide/topics/manifest/uses-library-element.html">&lt;uses-library&gt;</a></code>
    -+<br/><code><a href="{@docRoot}guide/topics/manifest/uses-permission-element.html">&lt;uses-permission&gt;</a></code>
    -+<br/><code><a href="{@docRoot}guide/topics/manifest/uses-sdk-element.html">&lt;uses-sdk&gt;</a></code>
    -+</p>
    -+
    -+
    -+
    -+
    -+<h2 id="filec">Konvensi File</h2>
    -+
    -+<p>
    -+Sebagian konvensi dan aturan berlaku secara umum untuk semua elemen
    -+dan atribut di manifes:
    -+</p>
    -+
    -+<dl>
    -+<dt><b>Elemen</b></dt>
    -+<dd>Hanya elemen
    -+<code><a href="{@docRoot}guide/topics/manifest/manifest-element.html">&lt;manifest&gt;</a></code> dan
    -+<code><a href="{@docRoot}guide/topics/manifest/application-element.html">&lt;application&gt;</a></code>
    -+yang diwajibkan, masing-masing harus ada dan hanya boleh terjadi sekali.
    -+Umumnya elemen lain bisa terjadi berkali-kali atau sama sekali tidak terjadi &mdash; meskipun
    -+setidaknya sebagian dari elemen itu harus ada untuk agar manifes mencapai sesuatu yang
    -+berarti.
    -+
    -+<p>
    -+Jika elemen tidak berisi apa pun, berarti elemen itu berisi elemen lain.
    -+Semua nilai diatur melalui atribut, bukan sebagai data karakter dalam elemen.
    -+</p>
    -+
    -+<p>
    -+Elemen yang sama tingkatan umumnya tidak diurutkan.  Misalnya, elemen
    -+<code><a href="{@docRoot}guide/topics/manifest/activity-element.html">&lt;activity&gt;</a></code>,
    -+<code><a href="{@docRoot}guide/topics/manifest/provider-element.html">&lt;provider&gt;</a></code>, dan
    -+<code><a href="{@docRoot}guide/topics/manifest/service-element.html">&lt;service&gt;</a></code>
    -+bisa dicampur dalam urutan apa pun.  (Elemen
    -+<code><a href="{@docRoot}guide/topics/manifest/activity-alias-element.html">&lt;activity-alias&gt;</a></code>
    -+ merupakan eksepsi untuk aturan ini:  Elemen ini harus mengikuti
    -+<code><a href="{@docRoot}guide/topics/manifest/activity-element.html">&lt;activity&gt;</a></code>
    -+ini aliasnya.)
    -+</p></dd>
    -+
    -+<dt><b>Atribut</b></dt>
    -+<dd>Secara formal, semua atribut opsional.  Akan tetapi, ada sebagian
    -+yang harus ditetapkan agar elemen bisa mencapai tujuannya.  Gunakan
    -+dokumentasi sebagai panduan.  Bagi atribut yang benar-benar opsional, ini menyebutkan
    -+nilai default atau menyatakan apa yang terjadi jika tidak ada spesifikasi.
    -+
    -+<p>Selain untuk beberapa atribut elemen akar
    -+<code><a href="{@docRoot}guide/topics/manifest/manifest-element.html">&lt;manifest&gt;</a></code>,
    -+ semua nama atribut dimulai dengan awalan {@code android:} &mdash;
    -+misalnya, {@code android:alwaysRetainTaskState}.  Karena awalan ini universal, dokumentasi umumnya meniadakannya saat mengacu atribut
    -+dengan nama.
    -+</p></dd>
    -+
    -+<dt><b>Mendeklarasikan nama kelas</b></dt>
    -+<dd>Banyak elemen berhubungan dengan objek Java, termasuk elemen
    -+aplikasi itu sendiri (elemen
    -+<code><a href="{@docRoot}guide/topics/manifest/application-element.html">&lt;application&gt;</a></code>
    -+) dan aktivitas komponen &mdash; utamanya
    -+(<code><a href="{@docRoot}guide/topics/manifest/activity-element.html">&lt;activity&gt;</a></code>),
    -+layanan
    -+(<code><a href="{@docRoot}guide/topics/manifest/service-element.html">&lt;service&gt;</a></code>),
    -+penerima siaran
    -+(<code><a href="{@docRoot}guide/topics/manifest/receiver-element.html">&lt;receiver&gt;</a></code>),
    -+dan penyedia konten
    -+(<code><a href="{@docRoot}guide/topics/manifest/provider-element.html">&lt;provider&gt;</a></code>).
    -+
    -+<p>
    -+Jika mendefinisikan subkelas, seperti yang selalu Anda definisikan untuk kelas komponen
    -+({@link android.app.Activity}, {@link android.app.Service},
    -+{@link android.content.BroadcastReceiver}, dan {@link android.content.ContentProvider}),
    -+subkelas dideklarasikan melalui atribut {@code name}.  Nama harus menyertakan tujuan
    -+paket lengkap.
    -+Misalnya, subkelas {@link android.app.Service} mungkin dideklarasikan sebagai berikut:
    -+</p>
    -+
    -+<pre>&lt;manifest . . . &gt;
    -+    &lt;application . . . &gt;
    -+        &lt;service android:name="com.example.project.SecretService" . . . &gt;
    -+            . . .
    -+        &lt;/service&gt;
    -+        . . .
    -+    &lt;/application&gt;
    -+&lt;/manifest&gt;</pre>
    -+
    -+<p>
    -+Akan tetapi, sebagai shorthand, jika karakter pertama string adalah titik,
    -+string akan ditambahkan ke nama paket aplikasi (seperti yang ditetapkan dalam elemen
    -+<code><a href="{@docRoot}guide/topics/manifest/manifest-element.html">&lt;manifest&gt;</a></code>
    -+ melalui atribut
    -+<code><a href="{@docRoot}guide/topics/manifest/manifest-element.html#package">package</a></code>
    -+).  Penetapan berikut sama dengan di atas:
    -+</p>
    -+
    -+<pre>&lt;manifest package="com.example.project" . . . &gt;
    -+    &lt;application . . . &gt;
    -+        &lt;service android:name=".SecretService" . . . &gt;
    -+            . . .
    -+        &lt;/service&gt;
    -+        . . .
    -+    &lt;/application&gt;
    -+&lt;/manifest&gt;</pre>
    -+
    -+<p>
    -+Saat memulai komponen, Android akan membuat instance subkelas yang diberi nama.
    -+Jika subkelas tidak ditetapkan, maka akak dibuat instance kelas dasar.
    -+</p></dd>
    -+
    -+<dt><b>Banyak nilai</b></dt>
    -+<dd>Jika lebih dari satu nilai yang dapat ditetapkan, elemen ini hampir selalu
    -+diulangi, bukan menampilkan daftar banyak nilai dalam satu elemen.
    -+Misalnya, filter intent dapat mencantumkan beberapa tindakan:
    -+
    -+<pre>&lt;intent-filter . . . &gt;
    -+    &lt;action android:name="android.intent.action.EDIT" /&gt;
    -+    &lt;action android:name="android.intent.action.INSERT" /&gt;
    -+    &lt;action android:name="android.intent.action.DELETE" /&gt;
    -+    . . .
    -+&lt;/intent-filter&gt;</pre></dd>
    -+
    -+<dt><b>Nilai sumber daya</b></dt>
    -+<dd>Beberapa atribut memiliki nilai yang bisa ditampilkan kepada pengguna &mdash; misalnya
    -+, label dan ikon aktivitas.  Nilai atribut ini
    -+harus dilokalkan dan karenanya ditetapkan dari sumber daya atau tema.  Nilai sumber
    -+daya dinyatakan dalam format berikut,</p>
    -+
    -+<p style="margin-left: 2em">{@code @[<i>package</i>:]<i>type</i>:<i>name</i>}</p>
    -+
    -+<p>
    -+dalam hal ini nama <i>package</i> boleh dihilangkan jika sumber daya ada dalam paket yang sama dengan
    -+dengan aplikasi, <i>type</i> adalah tipe sumber daya &mdash; seperti "string" atau
    -+"drawable" &mdash; dan <i>name</i> adalah nama yang mengidentifikasi sumber daya tertentu.
    -+Misalnya:
    -+</p>
    -+
    -+<pre>&lt;activity android:icon="@drawable/smallPic" . . . &gt</pre>
    -+
    -+<p>
    -+Nilai tema diekspresikan dengan cara yang sama, namun dengan awal '{@code ?}'
    -+dan bukan '{@code @}':
    -+</p>
    -+
    -+<p style="margin-left: 2em">{@code ?[<i>package</i>:]<i>type</i>:<i>name</i>}
    -+</p></dd>
    -+
    -+<dt><b>Nilai-nilai string</b></dt>
    -+<dd>Bila nilai atribut adalah string, dua garis miring kiri ('{@code \\}')
    -+harus digunakan untuk meninggalkan karakter &mdash; misalnya, '{@code \\n}' untuk
    -+baris baru atau '{@code \\uxxxx}' untuk karakter Unicode.</dd>
    -+</dl>
    -+
    -+
    -+<h2 id="filef">Fitur File</h2>
    -+
    -+<p>
    -+Bagian berikut menjelaskan cara menerapkan sebagian fitur Android
    -+dalam file manifest.
    -+</p>
    -+
    -+
    -+<h3 id="ifs">Filter Intent</h3>
    -+
    -+<p>
    -+Komponen inti dari aplikasi (aktivitasnya, layanannya, dan penerima
    -+siaran) diaktifkan oleh <i>intent</i>.  Intent adalah
    -+sekumpulan informasi (objek {@link android.content.Intent}) yang menjelaskan
    -+tindakan yang diinginkan &mdash; termasuk data yang akan ditindaklanjuti, kategori
    -+komponen yang harus melakukan tindakan, dan petunjuk terkait lainnya.
    -+Android mencari komponen yang sesuai untuk merespons intent, meluncurkan
    -+instance komponen baru jika diperlukan, dan meneruskannya ke
    -+objek Intent.
    -+</p>
    -+
    -+<p>
    -+Komponen mengiklankan kemampuannya &mdash; jenis intent yang bisa diresponsnya
    -+ &mdash; melalui <i>filter intent</i>.  Karena sistem Android
    -+harus mempelajari intent yang dapat ditangani komponen sebelum meluncurkan komponen,
    -+filter intent ditetapkan dalam manifes sebagai elemen
    -+<code><a href="{@docRoot}guide/topics/manifest/intent-filter-element.html">&lt;intent-filter&gt;</a></code>
    -+.  Sebuah komponen dapat memiliki filter dalam jumlah berapa saja, masing-masing menjelaskan
    -+kemampuan yang berbeda.
    -+</p>
    -+
    -+<p>
    -+Intent yang secara eksplisit menamai komponen target akan mengaktifkan komponen itu;
    -+filter tidak berperan.  Namun intent yang tidak menetapkan target
    -+dengan nama dapat mengaktifkan komponen hanya jika dapat melewati salah satu filter
    -+komponen.
    -+</p>
    -+
    -+<p>
    -+Untuk informasi tentang cara objek Intent diuji terhadap filter intent,
    -+lihat dokumen terpisah,
    -+<a href="{@docRoot}guide/components/intents-filters.html">Intent
    -+dan Filter Intent</a>.
    -+</p>
    -+
    -+
    -+<h3 id="iconlabel">Ikon dan Label</h3>
    -+
    -+<p>
    -+Sejumlah elemen memiliki atribut {@code icon} dan {@code label} untuk
    -+ikon kecil dan label teks yang bisa ditampilkan kepada pengguna.  Sebagian ada juga yang memiliki atribut
    -+{@code description}untuk teks penjelasan yang lebih panjang yang juga bisa
    -+ditampilkan pada layar.  Misalnya, elemen
    -+<code><a href="{@docRoot}guide/topics/manifest/permission-element.html">&lt;permission&gt;</a></code>
    -+ memiliki ketiga atribut ini, jadi saat pengguna ditanya apakah akan
    -+memberi izin bagi aplikasi yang memintanya, ikon yang mewakili
    -+izin, nama izin, dan keterangan yang
    -+mengikutinya bisa ditampilkan kepada pengguna.
    -+</p>
    -+
    -+<p>
    -+Dalam setiap kasus, ikon dan label yang ditetapkan dalam elemen yang memuatnya menjadi
    -+{@code icon} default dan pengaturan {@code label} untuk semua subelemen kontainer ini.
    -+Karena itu, ikon dan label yang ditetapkan dalam elemen
    -+<code><a href="{@docRoot}guide/topics/manifest/application-element.html">&lt;application&gt;</a></code>
    -+adalah ikon dan label default untuk setiap komponen aplikasi.
    -+Demikian pula, ikon dan label yang ditetapkan untuk komponen &mdash; misalnya, elemen
    -+<code><a href="{@docRoot}guide/topics/manifest/activity-element.html">&lt;activity&gt;</a></code>
    -+&mdash; adalah pengaturan default untuk setiap elemen komponen
    -+<code><a href="{@docRoot}guide/topics/manifest/intent-filter-element.html">&lt;intent-filter&gt;</a></code>
    -+.  Jika elemen
    -+<code><a href="{@docRoot}guide/topics/manifest/application-element.html">&lt;application&gt;</a></code>
    -+menetapkan label, namun suatu aktivitas dan filter intent-nya tidak menetapkan label,
    -+maka label aplikasi akan dianggap sama-sama sebagai label aktvitas dan
    -+filter intent.
    -+</p>
    -+
    -+<p>
    -+Ikon dan label yang ditetapkan untuk filter intent digunakan untuk mewakili komponen
    -+kapan saja komponen ditampilkan kepada pengguna saat memenuhi fungsi yang
    -+diiklankan oleh filter.  Misalnya, filter dengan pengaturan
    -+"{@code android.intent.action.MAIN}" dan
    -+"{@code android.intent.category.LAUNCHER}" mengiklankan aktivitas
    -+sebagai aktivitas yang memulai aplikasi&mdash;, yaitu
    -+sebagai salah satu aktivitas yang harus ditampilkan dalam launcher aplikasi.  Ikon dan label yang
    -+diatur dalam filter karenanya adalah ikon dan label yang ditampilkan dalam launcher.
    -+</p>
    -+
    -+
    -+<h3 id="perms">Izin</h3>
    -+
    -+<p>
    -+Sebuah <i>izin</i> adalah pembatasan yang membatasi akses ke bagian
    -+kode atau ke data pada perangkat.   Pembatasan diberlakukan untuk melindungi data dan kode
    -+penting yang bisa disalahgunakan untuk mengganggu atau merusak pengalaman pengguna.
    -+</p>
    -+
    -+<p>
    -+Setiap izin diidentifikasi melalui label yang unik.  Sering kali, label menunjukkan
    -+tindakan yang dibatasi.  Misalnya, berikut ini adalah beberapa izin yang didefinisikan
    -+oleh Android:
    -+</p>
    -+
    -+<p style="margin-left: 2em">{@code android.permission.CALL_EMERGENCY_NUMBERS}
    -+<br/>{@code android.permission.READ_OWNER_DATA}
    -+<br/>{@code android.permission.SET_WALLPAPER}
    -+<br/>{@code android.permission.DEVICE_POWER}</p>
    -+
    -+<p>
    -+Sebuah fitur bisa dilindungi paling banyak oleh satu izin.
    -+</p>
    -+
    -+<p>
    -+Jika aplikasi memerlukan akses ke fitur yang dilindungi oleh izin,
    -+aplikasi harus mendeklarasikan bahwa aplikasi memerlukan izin itu dengan elemen
    -+<code><a href="{@docRoot}guide/topics/manifest/uses-permission-element.html">&lt;uses-permission&gt;</a></code>
    -+ dalam manifes.  Kemudian, bila aplikasi telah diinstal pada
    -+perangkat, installer akan menentukan apakah izin yang diminta akan diberikan atau tidak
    -+dengan memeriksa otoritas yang menandatangani
    -+sertifikat aplikasi dan, dalam beberapa kasus, bertanya pada pengguna.
    -+Jika izin diberikan, aplikasi tersebut bisa menggunakan
    -+fitur yang dilindungi.  Jika tidak, upaya aplikasi untuk mengakses fitur tersebut akan gagal
    -+tanpa ada pemberitahuan apa pun kepada pengguna.
    -+</p>
    -+
    -+<p>
    -+Aplikasi juga bisa melindungi komponennya sendiri (aktivitas, layanan,
    -+penerima siaran, dan penyedia konten) dengan izin.  Aplikasi bisa menerapkan
    -+izin mana pun yang didefinisikan oleh Android (tercantum dalam
    -+{@link android.Manifest.permission android.Manifest.permission}) atau dideklarasikan
    -+oleh aplikasi lain.  Atau aplikasi bisa mendefinisikannya sendiri.  Izin baru dideklarasikan
    -+dengan elemen
    -+<code><a href="{@docRoot}guide/topics/manifest/permission-element.html">&lt;permission&gt;</a></code>
    -+.  Misalnya, aktivitas dapat dilindungi sebagai berikut:
    -+</p>
    -+
    -+<pre>
    -+&lt;manifest . . . &gt;
    -+    &lt;permission android:name="com.example.project.DEBIT_ACCT" . . . /&gt;
    -+    &lt;uses-permission android:name="com.example.project.DEBIT_ACCT" /&gt;
    -+    . . .
    -+    &lt;application . . .&gt;
    -+        &lt;activity android:name="com.example.project.FreneticActivity"
    -+                  android:permission="com.example.project.DEBIT_ACCT"
    -+                  . . . &gt;
    -+            . . .
    -+        &lt;/activity&gt;
    -+    &lt;/application&gt;
    -+&lt;/manifest&gt;
    -+</pre>
    -+
    -+<p>
    -+Perhatikan, dalam contoh ini izin {@code DEBIT_ACCT} tidak hanya
    -+dideklarasikan dengan elemen
    -+<code><a href="{@docRoot}guide/topics/manifest/permission-element.html">&lt;permission&gt;</a></code>
    -+, penggunaannya juga diminta dengan elemen
    -+<code><a href="{@docRoot}guide/topics/manifest/uses-permission-element.html">&lt;uses-permission&gt;</a></code>
    -+.  Penggunaannya harus diminta agar komponen
    -+aplikasi lainnya bisa menjalankan aktivitas yang dilindungi, meskipun perlindungan itu
    -+diberlakukan oleh aplikasi itu sendiri.
    -+</p>
    -+
    -+<p>
    -+Dalam contoh yang sama, jika atribut {@code permission} ditetapkan
    -+untuk izin yang dideklarasikan di tempat lain
    -+lain (seperti {@code android.permission.CALL_EMERGENCY_NUMBERS}, maka atribut
    -+tidak perlu mendeklarasikannya lagi dengan elemen
    -+<code><a href="{@docRoot}guide/topics/manifest/permission-element.html">&lt;permission&gt;</a></code>
    -+.  Akan tetapi, penggunaannya masih perlu dengan
    -+<code><a href="{@docRoot}guide/topics/manifest/uses-permission-element.html">&lt;uses-permission&gt;</a></code>.
    -+</p>
    -+
    -+<p>
    -+Elemen
    -+<code><a href="{@docRoot}guide/topics/manifest/permission-tree-element.html">&lt;permission-tree&gt;</a></code>
    -+mendeklarasikan namespace untuk grup izin yang akan didefinisikan dalam
    -+kode.  Dan
    -+<code><a href="{@docRoot}guide/topics/manifest/permission-group-element.html">&lt;permission-group&gt;</a></code>
    -+mendefinisikan label untuk seperangkat izin (yang sama-sama dideklarasikan dalam manifes dengan elemen
    -+<code><a href="{@docRoot}guide/topics/manifest/permission-element.html">&lt;permission&gt;</a></code>
    -+dan yang dideklarasikan di tempat lain).  Ini hanya memengaruhi cara izin
    -+dikelompokkan saat ditampilkan kepada pengguna.  Elemen
    -+<code><a href="{@docRoot}guide/topics/manifest/permission-group-element.html">&lt;permission-group&gt;</a></code>
    -+ tidak menetapkan izin mana dimiliki grup;
    -+elemen hanya memberi nama grup.  Izin ditempatkan dalam grup
    -+dengan memberikan nama grup ke elemen
    -+<code><a href="{@docRoot}guide/topics/manifest/permission-element.html">&lt;permission&gt;</a></code>
    -+ melalui atribut
    -+<code><a href="{@docRoot}guide/topics/manifest/permission-element.html#pgroup">permissionGroup</a></code>
    -+.
    -+</p>
    -+
    -+
    -+<h3 id="libs">Pustaka</h3>
    -+
    -+<p>
    -+Setiap aplikasi ditautkan dengan pustaka default Android, yang
    -+menyertakan paket dasar untuk membangun aplikasi (dengan kelas umum
    -+seperti Activity, Service, Intent, View, Button, Application, ContentProvider,
    -+dan sebagainya).
    -+</p>
    -+
    -+<p>
    -+Akan tetapi, sebagian paket berada dalam pustakanya sendiri.  Jika aplikasi Anda
    -+menggunakan kode salah satu paket ini, aplikasi secara eksplisit meminta untuk ditautkan dengan
    -+paket tersebut.  Manifes harus berisi elemen
    -+<code><a href="{@docRoot}guide/topics/manifest/uses-library-element.html">&lt;uses-library&gt;</a></code> yang
    -+terpisah untuk menamai setiap pustaka.  (Nama pustaka bisa ditemukan
    -+dalam dokumentasi paket.)
    -+</p>
    -diff --git a/docs/html-intl/intl/id/guide/topics/providers/calendar-provider.jd b/docs/html-intl/intl/id/guide/topics/providers/calendar-provider.jd
    -new file mode 100644
    -index 0000000..3058815
    ---- /dev/null
    -+++ b/docs/html-intl/intl/id/guide/topics/providers/calendar-provider.jd
    -@@ -0,0 +1,1184 @@
    -+page.title=Penyedia Kalender
    -+@jd:body
    -+
    -+<div id="qv-wrapper">
    -+<div id="qv">
    -+    <h2>Dalam dokumen ini</h2>
    -+    <ol>
    -+  <li><a href="#overview">Dasar-Dasar</a></li>
    -+  <li><a href="#manifest">Izin Pengguna</a></li>
    -+  <li><a href="#calendar">Tabel kalender</a>
    -+<ol>
    -+      <li><a href="#query">Membuat query kalender</a></li>
    -+      <li><a href="#modify-calendar">Memodifikasi kalender</a></li>
    -+      <li><a href="#insert-calendar">Menyisipkan kalender</a></li>
    -+    </ol>
    -+  </li>
    -+  <li><a href="#events">Tabel Events</a>
    -+<ol>
    -+      <li><a href="#add-event">Menambahkan Kejadian</a></li>
    -+      <li><a href="#update-event">Memperbarui Kejadian</a></li>
    -+      <li><a href="#delete-event">Menghapus Kejadian</a></li>
    -+    </ol>
    -+  </li>
    -+  <li><a href="#attendees">Tabel peserta</a>
    -+<ol>
    -+      <li><a href="#add-attendees">Menambahkan Peserta</a></li>
    -+    </ol>
    -+  </li>
    -+  <li><a href="#reminders">Tabel pengingat</a>
    -+<ol>
    -+      <li><a href="#add-reminders">Menambahkan Pengingat</a></li>
    -+    </ol>
    -+  </li>
    -+  <li><a href="#instances">Tabel Instances</a>
    -+  <ol>
    -+      <li><a href="#query-instances">Membuat query tabel Instance</a></li>
    -+  </ol></li>
    -+  <li><a href="#intents">Intent Kalender</a>
    -+  <ol>
    -+      <li><a href="#intent-insert">Menggunakan intent untuk menyisipkan kejadian</a></li>
    -+      <li><a href="#intent-edit">Menggunakan intent untuk mengedit kejadian</a></li>
    -+      <li><a href="#intent-view">Menggunakan intent untuk menampilkan data kalender</a></li>
    -+    </ol>
    -+  </li>
    -+
    -+  <li><a href="#sync-adapter">Adaptor Sinkronisasi</a></li>
    -+</ol>
    -+
    -+    <h2>Kelas-kelas utama</h2>
    -+    <ol>
    -+      <li>{@link android.provider.CalendarContract.Calendars}</li>
    -+      <li>{@link android.provider.CalendarContract.Events}</li>
    -+      <li>{@link android.provider.CalendarContract.Attendees}</li>
    -+      <li>{@link android.provider.CalendarContract.Reminders}</li>
    -+    </ol>
    -+</div>
    -+</div>
    -+
    -+<p>Penyedia Kalender adalah repository untuk kejadian kalender seorang pengguna. API
    -+Penyedia Kalender memungkinkan Anda melakukan query, menyisipkan, memperbarui, dan menghapus
    -+pada kalender, kejadian, peserta, pengingat, dan seterusnya.</p>
    -+
    -+
    -+<p>API Penyedia Kalender bisa digunakan oleh aplikasi dan adaptor sinkronisasi. Aturannya
    -+bervariasi menurut tipe program yang membuat panggilan. Dokumen ini
    -+terutama berfokus pada penggunaan API Penyedia Kalender sebagai sebuah aplikasi. Untuk
    -+pembahasan ragam adaptor sinkronisasi, lihat
    -+<a href="#sync-adapter">Adaptor Sinkronisasi</a>.</p>
    -+
    -+
    -+<p>Biasanya, untuk membaca atau menulis data kalender, manifes aplikasi harus
    -+berisi izin yang sesuai, yang dijelaskan dalam <a href="#manifest">Izin
    -+Pengguna</a>. Untuk mempermudah dilakukannya operasi umum,
    -+Penyedia Kalender menyediakan satu set intent, seperti dijelaskan dalam <a href="#intents">Intent
    -+Kalender</a>. Semua intent ini membawa pengguna ke aplikasi Kalender untuk menyisipkan, menampilkan,
    -+dan mengedit kejadian. Pengguna berinteraksi dengan aplikasi Kalender kemudian
    -+kembali ke aplikasi semula. Jadi, aplikasi Anda tidak perlu meminta izin,
    -+juga tidak perlu menyediakan antarmuka pengguna untuk menampilkan atau membuat kejadian.</p>
    -+
    -+<h2 id="overview">Dasar-Dasar</h2>
    -+
    -+<p><a href="{@docRoot}guide/topics/providers/content-providers.html">Penyedia konten</a> menyimpan data dan menjadikannya bisa diakses oleh
    -+aplikasi. Penyedia konten yang ditawarkan oleh platform Android (termasuk Penyedia Kalender) biasanya mengekspos data sebagai satu set tabel berdasarkan
    -+model database relasional, dengan tiap baris berupa record dan tiap kolom berupa data
    -+yang memiliki tipe dan arti tertentu. Melalui API Penyedia Kalender, aplikasi
    -+dan adaptor sinkronisasi bisa mendapatkan akses baca/tulis ke tabel-tabel database yang menyimpan
    -+data kalender seorang pengguna.</p>
    -+
    -+<p>Setiap penyedia konten membuka sebuah URI publik (yang dibungkus sebagai objek
    -+{@link android.net.Uri}
    -+) yang mengidentifikasikan set datanya secara unik.  Penyedia konten yang mengontrol
    -+ beberapa set data (beberapa tabel) mengekspos URI terpisah untuk tiap set.  Semua
    -+URI untuk penyedia diawali dengan string "content://".  String ini
    -+mengidentifikasi data sebagai dikontrol oleh penyedia konten. Penyedia Kalender
    -+mendefinisikan konstanta untuk URI masing-masing kelas (tabel). URI ini
    -+memiliki format <code><em>&lt;class&gt;</em>.CONTENT_URI</code>. Misalnya,
    -+{@link android.provider.CalendarContract.Events#CONTENT_URI Events.CONTENT_URI}.</p>
    -+
    -+<p>Gambar 1 menampilkan representasi grafis model data Penyedia Kalender. Gambar ini menampilkan
    -+tabel dan bidang utama yang saling berkaitan.</p>
    -+
    -+<img src="{@docRoot}images/providers/datamodel.png" alt="Calendar Provider Data Model" />
    -+<p class="img-caption"><strong>Gambar 1.</strong> Model data Penyedia Kalender.</p>
    -+
    -+<p>Seorang pengguna bisa memiliki beberapa kalender, dan kalender yang berbeda bisa dikaitkan dengan tipe akun yang berbeda (Google Calendar, Exchange, dan seterusnya).</p>
    -+
    -+<p>{@link android.provider.CalendarContract} mendefinisikan model data dari informasi yang terkait dengan kalender dan kejadian. Data ini disimpan di sejumlah tabel, yang dicantumkan di bawah ini.</p>
    -+
    -+<table>
    -+  <tr>
    -+    <th>Tabel (Kelas)</th>
    -+    <th>Keterangan</th>
    -+  </tr>
    -+  <tr>
    -+    <td><p>{@link android.provider.CalendarContract.Calendars}</p></td>
    -+
    -+    <td>Tabel ini menyimpan
    -+informasi khusus kalender. Tiap baris dalam tabel ini berisi data untuk
    -+satu kalender, seperti nama, warna, informasi sinkronisasi, dan seterusnya.</td>
    -+  </tr>
    -+  <tr>
    -+    <td>{@link android.provider.CalendarContract.Events}</td>
    -+
    -+    <td>Tabel ini menyimpan
    -+informasi khusus kejadian. Tiap baris dalam tabel ini berisi informasi untuk satu
    -+kejadian&mdash;misalnya, judul kejadian, lokasi, waktu mulai, waktu
    -+selesai, dan seterusnya. Kejadian bisa terjadi satu kali atau bisa berulang beberapa kali. Peserta,
    -+pengingat, dan properti perluasan disimpan dalam tabel terpisah.
    -+Masing-masing memiliki sebuah {@link android.provider.CalendarContract.AttendeesColumns#EVENT_ID}
    -+yang mengacu {@link android.provider.BaseColumns#_ID} dalam tabel Events.</td>
    -+
    -+  </tr>
    -+  <tr>
    -+    <td>{@link android.provider.CalendarContract.Instances}</td>
    -+
    -+    <td>Tabel ini menyimpan
    -+waktu mulai dan waktu selesai setiap bentuk kejadian. Tiap baris dalam tabel ini
    -+mewakili satu bentuk kejadian. Untuk kejadian satu kali ada pemetaan 1:1
    -+antara instance dan kejadian. Untuk kejadian berulang, beberapa baris akan dibuat
    -+secara otomatis yang sesuai dengan beberapa kejadian itu.</td>
    -+  </tr>
    -+  <tr>
    -+    <td>{@link android.provider.CalendarContract.Attendees}</td>
    -+
    -+    <td>Tabel ini menyimpan
    -+informasi peserta (tamu) kejadian. Tiap baris mewakili satu tamu
    -+kejadian. Ini menetapkan tipe tamu dan respons kehadiran tamu
    -+untuk kejadian.</td>
    -+  </tr>
    -+  <tr>
    -+    <td>{@link android.provider.CalendarContract.Reminders}</td>
    -+
    -+    <td>Tabel ini menyimpan
    -+data peringatan/pemberitahuan. Tiap baris mewakili satu peringatan untuk sebuah kejadian. Sebuah
    -+kejadian bisa memiliki beberapa pengingat. Jumlah maksimum pengingat per kejadian
    -+ditetapkan dalam
    -+{@link android.provider.CalendarContract.CalendarColumns#MAX_REMINDERS},
    -+yang diatur oleh adaptor sinkronisasi yang
    -+memiliki kalender yang diberikan. Pengingat ditetapkan dalam menit sebelum kejadian
    -+dan memiliki metode yang menentukan cara pengguna akan diperingatkan.</td>
    -+  </tr>
    -+
    -+</table>
    -+
    -+<p>API Penyedia Kalender didesain agar luwes dan tangguh. Sementara itu
    -+, Anda perlu memberikan pengalaman pengguna akhir yang baik dan
    -+melindungi integritas kalender dan datanya. Untuk mencapainya, berikut ini adalah
    -+beberapa hal yang harus diingat saat menggunakan API ini:</p>
    -+
    -+<ul>
    -+
    -+<li><strong>Menyisipkan, memperbarui, dan menampilkan kejadian kalender.</strong> Untuk menyisipkan, mengubah, dan membaca kejadian secara langsung dari Penyedia Kalender, Anda memerlukan <a href="#manifest">izin</a> yang sesuai. Akan tetapi, jika Anda tidak sedang membuat aplikasi atau adaptor sinkronisasi kalender berfitur lengkap, maka tidak perlu meminta izin. Sebagai gantinya, Anda bisa menggunakan intent yang didukung oleh aplikasi Kalender Android untuk menyerahkan operasi baca dan tulis ke aplikasi itu. Bila menggunakan intent, aplikasi Anda akan mengirim pengguna ke aplikasi Kalender untuk melakukan operasi yang diinginkan
    -+dalam sebuah formulir yang sudah diisi. Setelah operasi selesai, formulir dikembalikan ke aplikasi Anda.
    -+Dengan mendesain aplikasi untuk melakukan operasi umum melalui Kalender,
    -+Anda akan memberi pengguna sebuah antarmuka pengguna yang konsisten dan tangguh. Inilah
    -+pendekatan yang disarankan. Untuk informasi selengkapnya, lihat <a href="#intents">Intent
    -+Kalender</a>.</p>
    -+
    -+
    -+<li><strong>Adaptor sinkronisasi.</strong> Adaptor sinkronisasi menyinkronkan data kalender
    -+pada perangkat pengguna dengan server atau sumber data lain. Dalam tabel
    -+{@link android.provider.CalendarContract.Calendars} dan
    -+{@link android.provider.CalendarContract.Events},
    -+ada kolom yang dicadangkan untuk digunakan adaptor sinkronisasi.
    -+Penyedia dan aplikasi tidak boleh memodifikasinya. Sebenarnya, tabel-tabel itu tidak
    -+terlihat kecuali jika diakses sebagai adaptor sinkronisasi. Untuk informasi selengkapnya tentang
    -+adaptor sinkronisasi, lihat <a href="#sync-adapter">Adaptor Sinkronisasi</a>.</li>
    -+
    -+</ul>
    -+
    -+
    -+<h2 id="manifest">Izin Pengguna</h2>
    -+
    -+<p>Untuk membaca data kalender, aplikasi harus menyertakan izin {@link
    -+android.Manifest.permission#READ_CALENDAR} dalam file manifesnya. File
    -+harus menyertakan izin {@link android.Manifest.permission#WRITE_CALENDAR}
    -+untuk menghapus, menyisipkan, atau memperbarui data kalender:</p>
    -+
    -+<pre>
    -+&lt;?xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot;?&gt;
    -+&lt;manifest xmlns:android=&quot;http://schemas.android.com/apk/res/android&quot;...&gt;
    -+    &lt;uses-sdk android:minSdkVersion=&quot;14&quot; /&gt;
    -+    &lt;uses-permission android:name=&quot;android.permission.READ_CALENDAR&quot; /&gt;
    -+    &lt;uses-permission android:name=&quot;android.permission.WRITE_CALENDAR&quot; /&gt;
    -+    ...
    -+&lt;/manifest&gt;
    -+</pre>
    -+
    -+
    -+<h2 id="calendar">Tabel Kalender</h2>
    -+
    -+<p>Tabel {@link android.provider.CalendarContract.Calendars} berisi data
    -+untuk tiap kalender. Kolom-kolom
    -+berikut ini bisa ditulisi oleh aplikasi maupun <a href="#sync-adapter">adaptor sinkronisasi</a>.
    -+Untuk mengetahui daftar lengkap bidang-bidang yang didukung, lihat
    -+acuan {@link android.provider.CalendarContract.Calendars}.</p>
    -+<table>
    -+  <tr>
    -+    <th>Konstanta</th>
    -+    <th>Keterangan</th>
    -+  </tr>
    -+  <tr>
    -+    <td>{@link android.provider.CalendarContract.Calendars#NAME}</td>
    -+    <td>Nama kalender.</td>
    -+  </tr>
    -+  <tr>
    -+    <td>{@link android.provider.CalendarContract.Calendars#CALENDAR_DISPLAY_NAME}</td>
    -+    <td>Nama kalender ini yang ditampilkan kepada pengguna.</td>
    -+  </tr>
    -+  <tr>
    -+    <td>{@link android.provider.CalendarContract.Calendars#VISIBLE}</td>
    -+
    -+    <td>Sebuah boolean yang menunjukkan apakah kalender dipilih untuk ditampilkan. Nilai
    -+0 menunjukkan bahwa kejadian yang terkait dengan kalender ini tidak boleh
    -+ditampilkan.  Nilai 1 menunjukkan bahwa kejadian yang terkait dengan kalender ini harus
    -+ditampilkan. Nilai ini memengaruhi pembuatan baris dalam tabel {@link
    -+android.provider.CalendarContract.Instances}.</td>
    -+
    -+
    -+  </tr>
    -+  <tr>
    -+    <td>{@link android.provider.CalendarContract.CalendarColumns#SYNC_EVENTS}</td>
    -+
    -+    <td>Sebuah boolean yang menunjukkan apakah kalender harus disinkronkan dan apakah
    -+kejadiannya harus disimpan pada perangkat. Nilai 0 berarti jangan menyinkronkan kalender ini atau
    -+simpan kejadiannya pada perangkat.  Nilai 1 berarti menyinkronkan kejadian untuk kalender ini
    -+dan simpan kejadiannya pada perangkat.</td>
    -+  </tr>
    -+</table>
    -+
    -+<h3 id="query">Membuat query kalender</h3>
    -+
    -+<p>Berikut ini adalah contoh yang menampilkan cara mendapatkan kalender yang dimiliki oleh
    -+pengguna tertentu. Untuk memudahkan, dalam contoh ini, operasi query ditampilkan dalam
    -+thread antarmuka pengguna ("thread utama"). Dalam praktiknya, hal ini harus dilakukan dalam
    -+thread asinkron, sebagai ganti pada thread utama. Untuk diskusi selengkapnya, lihat
    -+<a href="{@docRoot}guide/components/loaders.html">Loader</a>. Jika Anda tidak sekadar
    -+membaca data melainkan memodifikasinya, lihat {@link android.content.AsyncQueryHandler}.
    -+</p>
    -+
    -+
    -+<pre>
    -+// Projection array. Creating indices for this array instead of doing
    -+// dynamic lookups improves performance.
    -+public static final String[] EVENT_PROJECTION = new String[] {
    -+    Calendars._ID,                           // 0
    -+    Calendars.ACCOUNT_NAME,                  // 1
    -+    Calendars.CALENDAR_DISPLAY_NAME,         // 2
    -+    Calendars.OWNER_ACCOUNT                  // 3
    -+};
    -+
    -+// The indices for the projection array above.
    -+private static final int PROJECTION_ID_INDEX = 0;
    -+private static final int PROJECTION_ACCOUNT_NAME_INDEX = 1;
    -+private static final int PROJECTION_DISPLAY_NAME_INDEX = 2;
    -+private static final int PROJECTION_OWNER_ACCOUNT_INDEX = 3;</pre>
    -+
    -+
    -+<div class="sidebox-wrapper"> <div class="sidebox"> <h3>Mengapa Anda harus menyertakan
    -+ACCOUNT_TYPE?</h3> <p>Jika Anda membuat query pada {@link
    -+android.provider.CalendarContract.Calendars#ACCOUNT_NAME
    -+Calendars.ACCOUNT_NAME}, Anda juga harus menyertakan
    -+{@link android.provider.CalendarContract.Calendars#ACCOUNT_TYPE Calendars.ACCOUNT_TYPE}
    -+dalam pemilihan. Itu karena akun yang bersangkutan
    -+hanya dianggap unik mengingat <code>ACCOUNT_NAME</code> dan
    -+<code>ACCOUNT_TYPE</code>-nya. <code>ACCOUNT_TYPE</code> adalah string yang sesuai dengan
    -+autentikator akun yang digunakan bila akun didaftarkan dengan
    -+{@link android.accounts.AccountManager}. Ada juga sebuah tipe akun khusus yang disebut {@link
    -+android.provider.CalendarContract#ACCOUNT_TYPE_LOCAL} untuk kalender
    -+yang tidak terkait dengan akun perangkat. Akun {@link
    -+android.provider.CalendarContract#ACCOUNT_TYPE_LOCAL} tidak
    -+disinkronkan.</p> </div> </div>
    -+
    -+
    -+<p> Di bagian berikutnya pada contoh ini, Anda akan membuat query. Pemilihan
    -+akan menetapkan kriteria untuk query. Dalam contoh ini, query mencari
    -+kalender yang memiliki <code>ACCOUNT_NAME</code>
    -+"sampleuser@google.com", <code>ACCOUNT_TYPE</code>
    -+"com.google", dan <code>OWNER_ACCOUNT</code>
    -+"sampleuser@google.com". Jika Anda ingin melihat semua kalender yang
    -+telah ditampilkan pengguna, bukan hanya kalender yang dimiliki pengguna, hilangkan <code>OWNER_ACCOUNT</code>.
    -+Query tersebut akan menghasilkan objek {@link android.database.Cursor}
    -+yang bisa Anda gunakan untuk menyusuri set hasil yang dikembalikan oleh
    -+query database. Untuk diskusi selengkapnya tentang penggunaan query dalam penyedia konten,
    -+lihat <a href="{@docRoot}guide/topics/providers/content-providers.html">Penyedia Kalender</a>.</p>
    -+
    -+
    -+<pre>// Run query
    -+Cursor cur = null;
    -+ContentResolver cr = getContentResolver();
    -+Uri uri = Calendars.CONTENT_URI;
    -+String selection = "((" + Calendars.ACCOUNT_NAME + " = ?) AND ("
    -+                        + Calendars.ACCOUNT_TYPE + " = ?) AND ("
    -+                        + Calendars.OWNER_ACCOUNT + " = ?))";
    -+String[] selectionArgs = new String[] {"sampleuser@gmail.com", "com.google",
    -+        "sampleuser@gmail.com"};
    -+// Submit the query and get a Cursor object back.
    -+cur = cr.query(uri, EVENT_PROJECTION, selection, selectionArgs, null);</pre>
    -+
    -+<p>Bagian berikutnya ini menggunakan kursor untuk merunut set hasil. Bagian ini menggunakan
    -+konstanta yang disiapkan pada awal contoh ini untuk menghasilkan nilai-nilai
    -+bagi tiap bidang.</p>
    -+
    -+<pre>// Use the cursor to step through the returned records
    -+while (cur.moveToNext()) {
    -+    long calID = 0;
    -+    String displayName = null;
    -+    String accountName = null;
    -+    String ownerName = null;
    -+
    -+    // Get the field values
    -+    calID = cur.getLong(PROJECTION_ID_INDEX);
    -+    displayName = cur.getString(PROJECTION_DISPLAY_NAME_INDEX);
    -+    accountName = cur.getString(PROJECTION_ACCOUNT_NAME_INDEX);
    -+    ownerName = cur.getString(PROJECTION_OWNER_ACCOUNT_INDEX);
    -+
    -+    // Do something with the values...
    -+
    -+   ...
    -+}
    -+</pre>
    -+
    -+<h3 id="modify-calendar">Memodifikasi kalender</h3>
    -+
    -+<p>Untuk melakukan pembaruan kalender, Anda bisa menyediakan {@link
    -+android.provider.BaseColumns#_ID} kalender itu baik sebagai ID yang ditambahkan ke
    -+URI
    -+
    -+({@link android.content.ContentUris#withAppendedId(android.net.Uri,long) withAppendedId()})
    -+atau sebagai item pemilihan pertama. Pemilihan
    -+harus diawali dengan <code>&quot;_id=?&quot;</code>, dan
    -+<code>selectionArg</code> pertama harus berupa {@link
    -+android.provider.BaseColumns#_ID} kalender.
    -+Anda juga bisa melakukan pembaruan dengan menuliskan kode ID dalam URI. Contoh ini mengubah
    -+nama tampilan kalender dengan pendekatan
    -+({@link android.content.ContentUris#withAppendedId(android.net.Uri,long) withAppendedId()})
    -+:</p>
    -+
    -+<pre>private static final String DEBUG_TAG = "MyActivity";
    -+...
    -+long calID = 2;
    -+ContentValues values = new ContentValues();
    -+// The new display name for the calendar
    -+values.put(Calendars.CALENDAR_DISPLAY_NAME, &quot;Trevor's Calendar&quot;);
    -+Uri updateUri = ContentUris.withAppendedId(Calendars.CONTENT_URI, calID);
    -+int rows = getContentResolver().update(updateUri, values, null, null);
    -+Log.i(DEBUG_TAG, &quot;Rows updated: &quot; + rows);</pre>
    -+
    -+<h3 id="insert-calendar">Menyisipkan kalender</h2>
    -+
    -+<p>Kalender didesain untuk dikelola terutama oleh sebuah adaptor sinkronisasi, sehingga Anda
    -+hanya boleh menyisipkan kalender baru sebagai adaptor sinkronisasi. Biasanya,
    -+aplikasi hanya bisa membuat perubahan semu pada kalender, misalnya mengubah nama tampilan. Jika
    -+perlu membuat sebuah kalender lokal, aplikasi bisa melakukannya dengan melakukan
    -+penyisipan kalender sebagai adaptor sinkronisasi, menggunakan {@link
    -+android.provider.CalendarContract.SyncColumns#ACCOUNT_TYPE} dari {@link
    -+android.provider.CalendarContract#ACCOUNT_TYPE_LOCAL}.
    -+{@link android.provider.CalendarContract#ACCOUNT_TYPE_LOCAL}
    -+adalah sebuah tipe akun khusus untuk kalender yang tidak
    -+terkait dengan akun perangkat. Kalender tipe ini tidak disinkronkan dengan server. Untuk
    -+diskusi tentang adaptor sinkronisasi, lihat <a href="#sync-adapter">Adaptor Sinkronisasi</a>.</p>
    -+
    -+<h2 id="events">Tabel Events</h2>
    -+
    -+<p>Tabel {@link android.provider.CalendarContract.Events} berisi detail
    -+untuk tiap kejadian. Untuk menambah, memperbarui, atau menghapus kejadian, aplikasi harus
    -+menyertakan izin {@link android.Manifest.permission#WRITE_CALENDAR} dalam
    -+<a href="#manifest">file manifesnya</a>.</p>
    -+
    -+<p>Kolom-kolom Events berikut ini bisa ditulis oleh aplikasi maupun
    -+adaptor sinkronisasi. Untuk mengetahui daftar lengkap bidang-bidang yang didukung, lihat acuan {@link
    -+android.provider.CalendarContract.Events}.</p>
    -+
    -+<table>
    -+  <tr>
    -+    <th>Konstanta</th>
    -+    <th>Keterangan</th>
    -+  </tr>
    -+  <tr>
    -+    <td>{@link android.provider.CalendarContract.EventsColumns#CALENDAR_ID}</td>
    -+    <td>{@link android.provider.BaseColumns#_ID} kalender yang dimiliki kejadian.</td>
    -+  </tr>
    -+  <tr>
    -+    <td>{@link android.provider.CalendarContract.EventsColumns#ORGANIZER}</td>
    -+    <td>Email pengatur (pemilik) kejadian.</td>
    -+  </tr>
    -+  <tr>
    -+    <td>{@link android.provider.CalendarContract.EventsColumns#TITLE}</td>
    -+    <td>Judul kejadian.</td>
    -+  </tr>
    -+  <tr>
    -+    <td>{@link android.provider.CalendarContract.EventsColumns#EVENT_LOCATION}</td>
    -+    <td>Tempat kejadian. </td>
    -+  </tr>
    -+  <tr>
    -+    <td>{@link android.provider.CalendarContract.EventsColumns#DESCRIPTION}</td>
    -+    <td>Keterangan kejadian.</td>
    -+  </tr>
    -+  <tr>
    -+    <td>{@link android.provider.CalendarContract.EventsColumns#DTSTART}</td>
    -+    <td>Waktu mulai kejadian dalam milidetik UTC sejak waktu patokan. </td>
    -+  </tr>
    -+  <tr>
    -+    <td>{@link android.provider.CalendarContract.EventsColumns#DTEND}</td>
    -+    <td>Waktu selesai kejadian dalam milidetik UTC sejak waktu patokan. </td>
    -+  </tr>
    -+  <tr>
    -+    <td>{@link android.provider.CalendarContract.EventsColumns#EVENT_TIMEZONE}</td>
    -+    <td>Zona waktu kejadian.</td>
    -+  </tr>
    -+  <tr>
    -+    <td>{@link android.provider.CalendarContract.EventsColumns#EVENT_END_TIMEZONE}</td>
    -+    <td>Zona waktu untuk waktu selesai kejadian.</td>
    -+  </tr>
    -+  <tr>
    -+    <td>{@link android.provider.CalendarContract.EventsColumns#DURATION}</td>
    -+
    -+    <td>Durasi kejadian dalam format <a href="http://tools.ietf.org/html/rfc5545#section-3.8.2.5">RFC5545</a>.
    -+Misalnya, nilai <code>&quot;PT1H&quot;</code> menyatakan bahwa kejadian
    -+akan berlangsung satu jam, dan nilai <code>&quot;P2W&quot;</code> menunjukkan
    -+durasi 2 minggu. </td>
    -+
    -+
    -+  </tr>
    -+  <tr>
    -+    <td>{@link android.provider.CalendarContract.EventsColumns#ALL_DAY}</td>
    -+
    -+    <td>Nilai 1 menunjukkan kejadian ini memakan waktu sehari penuh, seperti yang didefinisikan oleh
    -+zona waktu lokal. Nilai 0 menunjukkan kejadian adalah kejadian biasa yang mungkin dimulai
    -+dan selesai pada sembarang waktu selama suatu hari.</td>
    -+
    -+
    -+  </tr>
    -+
    -+
    -+  <tr>
    -+    <td>{@link android.provider.CalendarContract.EventsColumns#RRULE}</td>
    -+
    -+    <td>Aturan perulangan untuk format kejadian. Misalnya,
    -+<code>&quot;FREQ=WEEKLY;COUNT=10;WKST=SU&quot;</code>. Anda bisa menemukan
    -+contoh selengkapnya <a href="http://tools.ietf.org/html/rfc5545#section-3.8.5.3">di sini</a>.</td>
    -+
    -+  </tr>
    -+
    -+  <tr>
    -+    <td>{@link android.provider.CalendarContract.EventsColumns#RDATE}</td>
    -+    <td>Tanggal perulangan kejadian.
    -+    Anda biasanya menggunakan {@link android.provider.CalendarContract.EventsColumns#RDATE}
    -+    bersama dengan {@link android.provider.CalendarContract.EventsColumns#RRULE}
    -+    untuk mendefinisikan satu set agregat
    -+kejadian berulang. Untuk diskusi selengkapnya, lihat <a href="http://tools.ietf.org/html/rfc5545#section-3.8.5.2">Spesifikasi RFC5545</a>.</td>
    -+</tr>
    -+
    -+  <tr>
    -+    <td>{@link android.provider.CalendarContract.EventsColumns#AVAILABILITY}</td>
    -+
    -+    <td>Jika kejadian ini dihitung sebagai waktu sibuk atau waktu bebas yang bisa
    -+dijadwalkan. </td>
    -+
    -+  </tr>
    -+  <tr>
    -+    <td>{@link android.provider.CalendarContract.EventsColumns#GUESTS_CAN_MODIFY}</td>
    -+    <td>Apakah tamu bisa memodifikasi kejadian atau tidak. </td>
    -+  </tr>
    -+  <tr>
    -+    <td>{@link android.provider.CalendarContract.EventsColumns#GUESTS_CAN_INVITE_OTHERS}</td>
    -+    <td>Apakah tamu bisa mengundang tamu lain atau tidak. </td>
    -+  </tr>
    -+  <tr>
    -+    <td>{@link android.provider.CalendarContract.EventsColumns#GUESTS_CAN_SEE_GUESTS}</td>
    -+    <td>Apakah tamu bisa membaca daftar peserta atau tidak.</td>
    -+  </tr>
    -+</table>
    -+
    -+<h3 id="add-event">Menambahkan Kejadian</h3>
    -+
    -+<p>Bila aplikasi Anda menyisipkan kejadian baru, sebaiknya Anda menggunakan
    -+Intent {@link android.content.Intent#ACTION_INSERT INSERT}, seperti dijelaskan dalam <a href="#intent-insert">Menggunakan intent untuk menyisipkan kejadian</a>. Akan tetapi, jika
    -+perlu, Anda bisa menyisipkan kejadian secara langsung. Bagian ini menjelaskan
    -+caranya.</p>
    -+
    -+
    -+<p>Berikut ini adalah aturan untuk menyisipkan kejadian baru: </p>
    -+<ul>
    -+
    -+  <li>Anda harus menyertakan {@link
    -+android.provider.CalendarContract.EventsColumns#CALENDAR_ID} dan {@link
    -+android.provider.CalendarContract.EventsColumns#DTSTART}.</li>
    -+
    -+<li>Anda harus menyertakan {@link
    -+android.provider.CalendarContract.EventsColumns#EVENT_TIMEZONE}. Untuk mendapatkan daftar
    -+ID zona waktu yang diinstal pada sistem, gunakan {@link
    -+java.util.TimeZone#getAvailableIDs()}. Perhatikan bahwa aturan ini tidak berlaku jika
    -+Anda menyisipkan kejadian melalui Intent {@link
    -+android.content.Intent#ACTION_INSERT INSERT}, yang dijelaskan dalam <a href="#intent-insert">Menggunakan intent untuk menyisipkan kejadian</a>&mdash;dalam
    -+skenario itu, sebuah zona waktu default akan diberikan.</li>
    -+
    -+  <li>Untuk kejadian tidak-berulang, Anda harus menyertakan {@link
    -+android.provider.CalendarContract.EventsColumns#DTEND}. </li>
    -+
    -+
    -+  <li>Untuk kejadian berulang, Anda harus menyertakan sebuah {@link
    -+android.provider.CalendarContract.EventsColumns#DURATION} selain {@link
    -+android.provider.CalendarContract.EventsColumns#RRULE} atau {@link
    -+android.provider.CalendarContract.EventsColumns#RDATE}. Perhatikan bahwa aturan ini tidak berlaku jika
    -+Anda menyisipkan kejadian melalui Intent {@link
    -+android.content.Intent#ACTION_INSERT INSERT}, yang dijelaskan dalam <a href="#intent-insert">Menggunakan intent untuk menyisipkan kejadian</a>&mdash;dalam
    -+skenario itu, Anda bisa menggunakan {@link
    -+android.provider.CalendarContract.EventsColumns#RRULE} bersama {@link android.provider.CalendarContract.EventsColumns#DTSTART} dan {@link android.provider.CalendarContract.EventsColumns#DTEND}, dan aplikasi Calendar
    -+akan mengubahnya menjadi durasi secara otomatis.</li>
    -+
    -+</ul>
    -+
    -+<p>Berikut ini adalah contoh penyisipan kejadian. Penyisipan ini dilakukan dalam thread UI
    -+demi kemudahan. Dalam praktiknya, penyisipan dan pembaruan harus dilakukan di
    -+thread asinkron untuk memindahkan tindakan ke dalam thread latar belakang. Untuk
    -+informasi selengkapnya, lihat {@link android.content.AsyncQueryHandler}.</p>
    -+
    -+
    -+<pre>
    -+long calID = 3;
    -+long startMillis = 0;
    -+long endMillis = 0;
    -+Calendar beginTime = Calendar.getInstance();
    -+beginTime.set(2012, 9, 14, 7, 30);
    -+startMillis = beginTime.getTimeInMillis();
    -+Calendar endTime = Calendar.getInstance();
    -+endTime.set(2012, 9, 14, 8, 45);
    -+endMillis = endTime.getTimeInMillis();
    -+...
    -+
    -+ContentResolver cr = getContentResolver();
    -+ContentValues values = new ContentValues();
    -+values.put(Events.DTSTART, startMillis);
    -+values.put(Events.DTEND, endMillis);
    -+values.put(Events.TITLE, &quot;Jazzercise&quot;);
    -+values.put(Events.DESCRIPTION, &quot;Group workout&quot;);
    -+values.put(Events.CALENDAR_ID, calID);
    -+values.put(Events.EVENT_TIMEZONE, "America/Los_Angeles");
    -+Uri uri = cr.insert(Events.CONTENT_URI, values);
    -+
    -+// get the event ID that is the last element in the Uri
    -+long eventID = Long.parseLong(uri.getLastPathSegment());
    -+//
    -+// ... do something with event ID
    -+//
    -+//</pre>
    -+
    -+<p class="note"><strong>Catatan:</strong> Perhatikan cara contoh ini menangkap ID kejadian
    -+setelah kejadian dibuat. Inilah cara termudah untuk mendapatkan ID kejadian. Anda akan sering
    -+memerlukan ID kejadian untuk melakukan operasi kalender lainnya&mdash;misalnya, untuk menambahkan
    -+peserta atau pengingat ke kejadian.</p>
    -+
    -+
    -+<h3 id="update-event">Memperbarui Kejadian</h3>
    -+
    -+<p>Bila aplikasi Anda ingin memperbolehkan pengguna mengedit kejadian, sebaiknya
    -+gunakan Intent {@link android.content.Intent#ACTION_EDIT EDIT}, seperti
    -+dijelaskan dalam <a href="#intent-edit">Menggunakan intent untuk mengedit kejadian</a>.
    -+Akan tetapi, jika perlu, Anda bisa mengedit kejadian secara langsung. Untuk melakukan pembaruan
    -+suatu kejadian, Anda bisa memberikan <code>_ID</code>
    -+kejadian itu sebagai ID yang ditambahkan ke URI ({@link
    -+android.content.ContentUris#withAppendedId(android.net.Uri,long) withAppendedId()})
    -+atau sebagai item pemilihan pertama.
    -+Pemilihan harus dimulai dengan <code>&quot;_id=?&quot;</code>, dan
    -+<code>selectionArg</code> yang pertama harus berupa <code>_ID</code> kejadian. Anda juga bisa
    -+melakukan pembaruan dengan menggunakan pemilihan tanpa ID. Berikut ini adalah contoh pembaruan
    -+kejadian. Contoh ini mengubah judul kejadian dengan pendekatan
    -+{@link android.content.ContentUris#withAppendedId(android.net.Uri,long) withAppendedId()}
    -+:</p>
    -+
    -+
    -+<pre>private static final String DEBUG_TAG = "MyActivity";
    -+...
    -+long eventID = 188;
    -+...
    -+ContentResolver cr = getContentResolver();
    -+ContentValues values = new ContentValues();
    -+Uri updateUri = null;
    -+// The new title for the event
    -+values.put(Events.TITLE, &quot;Kickboxing&quot;);
    -+updateUri = ContentUris.withAppendedId(Events.CONTENT_URI, eventID);
    -+int rows = getContentResolver().update(updateUri, values, null, null);
    -+Log.i(DEBUG_TAG, &quot;Rows updated: &quot; + rows);  </pre>
    -+
    -+<h3 id="delete-event">Menghapus Kejadian</h3>
    -+
    -+<p>Anda bisa menghapus kejadian dengan {@link
    -+android.provider.BaseColumns#_ID} sebagai ID yang ditambahkan pada URI, atau dengan
    -+pemilihan standar. Jika Anda menggunakan ID yang ditambahkan, Anda tidak bisa melakukan pemilihan.
    -+Ada dua versi penghapusan: sebagai aplikasi dan sebagai adaptor sinkronisasi. Penghapusan
    -+aplikasi mengatur kolom yang <em>dihapus</em> ke 1. Flag ini yang memberi tahu
    -+adaptor sinkronisasi bahwa baris telah dihapus dan bahwa penghapusan ini harus
    -+diberitahukan ke server. Penghapusan adaptor sinkronisasi menghapus kejadian dari
    -+database bersama semua data terkaitnya. Berikut ini adalah contoh aplikasi
    -+yang menghapus kejadian melalui {@link android.provider.BaseColumns#_ID}-nya:</p>
    -+
    -+
    -+<pre>private static final String DEBUG_TAG = "MyActivity";
    -+...
    -+long eventID = 201;
    -+...
    -+ContentResolver cr = getContentResolver();
    -+ContentValues values = new ContentValues();
    -+Uri deleteUri = null;
    -+deleteUri = ContentUris.withAppendedId(Events.CONTENT_URI, eventID);
    -+int rows = getContentResolver().delete(deleteUri, null, null);
    -+Log.i(DEBUG_TAG, &quot;Rows deleted: &quot; + rows);
    -+</pre>
    -+
    -+<h2 id="attendees">Tabel Peserta</h2>
    -+
    -+<p>Tiap baris tabel {@link android.provider.CalendarContract.Attendees}
    -+mewakili satu peserta atau tamu dari sebuah kejadian. Memanggil
    -+{@link android.provider.CalendarContract.Reminders#query(android.content.ContentResolver, long, java.lang.String[]) query()}
    -+akan menghasilkan daftar peserta untuk
    -+kejadian dengan {@link android.provider.CalendarContract.AttendeesColumns#EVENT_ID} yang diberikan.
    -+{@link android.provider.CalendarContract.AttendeesColumns#EVENT_ID} ini
    -+harus cocok dengan {@link
    -+android.provider.BaseColumns#_ID} kejadian tertentu.</p>
    -+
    -+<p>Tabel berikut mencantumkan
    -+bidang-bidang yang bisa ditulis. Saat menyisipkan peserta baru, Anda harus menyertakan semuanya
    -+kecuali <code>ATTENDEE_NAME</code>.
    -+</p>
    -+
    -+
    -+<table>
    -+  <tr>
    -+    <th>Konstanta</th>
    -+    <th>Keterangan</th>
    -+  </tr>
    -+  <tr>
    -+    <td>{@link android.provider.CalendarContract.AttendeesColumns#EVENT_ID}</td>
    -+    <td>ID kejadian.</td>
    -+  </tr>
    -+  <tr>
    -+    <td>{@link android.provider.CalendarContract.AttendeesColumns#ATTENDEE_NAME}</td>
    -+    <td>Nama peserta.</td>
    -+  </tr>
    -+  <tr>
    -+    <td>{@link android.provider.CalendarContract.AttendeesColumns#ATTENDEE_EMAIL}</td>
    -+    <td>Alamat email peserta.</td>
    -+  </tr>
    -+  <tr>
    -+    <td>{@link android.provider.CalendarContract.AttendeesColumns#ATTENDEE_RELATIONSHIP}</td>
    -+    <td><p>Hubungan peserta dengan kejadian. Salah satu dari:</p>
    -+      <ul>
    -+        <li>{@link android.provider.CalendarContract.AttendeesColumns#RELATIONSHIP_ATTENDEE}</li>
    -+        <li>{@link android.provider.CalendarContract.AttendeesColumns#RELATIONSHIP_NONE}</li>
    -+        <li>{@link android.provider.CalendarContract.AttendeesColumns#RELATIONSHIP_ORGANIZER}</li>
    -+        <li>{@link android.provider.CalendarContract.AttendeesColumns#RELATIONSHIP_PERFORMER}</li>
    -+        <li>{@link android.provider.CalendarContract.AttendeesColumns#RELATIONSHIP_SPEAKER}</li>
    -+    </ul>
    -+    </td>
    -+  </tr>
    -+  <tr>
    -+    <td>{@link android.provider.CalendarContract.AttendeesColumns#ATTENDEE_TYPE}</td>
    -+    <td><p>Tipe peserta. Salah satu dari: </p>
    -+      <ul>
    -+        <li>{@link android.provider.CalendarContract.AttendeesColumns#TYPE_REQUIRED}</li>
    -+        <li>{@link android.provider.CalendarContract.AttendeesColumns#TYPE_OPTIONAL}</li>
    -+    </ul></td>
    -+  </tr>
    -+  <tr>
    -+    <td>{@link android.provider.CalendarContract.AttendeesColumns#ATTENDEE_STATUS}</td>
    -+    <td><p>Status kehadiran peserta. Salah satu dari:</p>
    -+      <ul>
    -+        <li>{@link android.provider.CalendarContract.AttendeesColumns#ATTENDEE_STATUS_ACCEPTED}</li>
    -+        <li>{@link android.provider.CalendarContract.AttendeesColumns#ATTENDEE_STATUS_DECLINED}</li>
    -+        <li>{@link android.provider.CalendarContract.AttendeesColumns#ATTENDEE_STATUS_INVITED}</li>
    -+        <li>{@link android.provider.CalendarContract.AttendeesColumns#ATTENDEE_STATUS_NONE}</li>
    -+        <li>{@link android.provider.CalendarContract.AttendeesColumns#ATTENDEE_STATUS_TENTATIVE}</li>
    -+    </ul></td>
    -+  </tr>
    -+</table>
    -+
    -+<h3 id="add-attendees">Menambahkan Peserta</h3>
    -+
    -+<p>Berikut ini adalah contoh yang menambahkan satu peserta ke kejadian. Perhatikan bahwa
    -+{@link android.provider.CalendarContract.AttendeesColumns#EVENT_ID}
    -+diperlukan:</p>
    -+
    -+<pre>
    -+long eventID = 202;
    -+...
    -+ContentResolver cr = getContentResolver();
    -+ContentValues values = new ContentValues();
    -+values.put(Attendees.ATTENDEE_NAME, &quot;Trevor&quot;);
    -+values.put(Attendees.ATTENDEE_EMAIL, &quot;trevor@example.com&quot;);
    -+values.put(Attendees.ATTENDEE_RELATIONSHIP, Attendees.RELATIONSHIP_ATTENDEE);
    -+values.put(Attendees.ATTENDEE_TYPE, Attendees.TYPE_OPTIONAL);
    -+values.put(Attendees.ATTENDEE_STATUS, Attendees.ATTENDEE_STATUS_INVITED);
    -+values.put(Attendees.EVENT_ID, eventID);
    -+Uri uri = cr.insert(Attendees.CONTENT_URI, values);
    -+</pre>
    -+
    -+<h2 id="reminders">Tabel Pengingat</h2>
    -+
    -+<p>Tiap baris tabel {@link android.provider.CalendarContract.Reminders}
    -+mewakili satu pengingat untuk sebuah kejadian. Memanggil
    -+{@link android.provider.CalendarContract.Reminders#query(android.content.ContentResolver, long, java.lang.String[]) query()} akan menghasilkan daftar pengingat untuk
    -+kejadian dengan
    -+{@link android.provider.CalendarContract.AttendeesColumns#EVENT_ID} yang diberikan.</p>
    -+
    -+
    -+<p>Tabel berikut mencantumkan bidang-bidang yang bisa ditulis untuk pengingat. Semua bidang harus
    -+disertakan saat menyisipkan pengingat baru. Perhatikan bahwa adaptor sinkronisasi menetapkan
    -+tipe pengingat yang didukungnya dalam tabel {@link
    -+android.provider.CalendarContract.Calendars}. Lihat
    -+{@link android.provider.CalendarContract.CalendarColumns#ALLOWED_REMINDERS}
    -+untuk detailnya.</p>
    -+
    -+
    -+<table>
    -+  <tr>
    -+    <th>Konstanta</th>
    -+    <th>Keterangan</th>
    -+  </tr>
    -+  <tr>
    -+    <td>{@link android.provider.CalendarContract.RemindersColumns#EVENT_ID}</td>
    -+    <td>ID kejadian.</td>
    -+  </tr>
    -+  <tr>
    -+    <td>{@link android.provider.CalendarContract.RemindersColumns#MINUTES}</td>
    -+    <td>Menit yang ditunggu untuk memicu kejadian pengingat.</td>
    -+  </tr>
    -+  <tr>
    -+    <td>{@link android.provider.CalendarContract.RemindersColumns#METHOD}</td>
    -+    <td><p>Metode alarm, seperti yang diatur pada server. Salah satu dari:</p>
    -+      <ul>
    -+        <li>{@link android.provider.CalendarContract.RemindersColumns#METHOD_ALERT}</li>
    -+        <li>{@link android.provider.CalendarContract.RemindersColumns#METHOD_DEFAULT}</li>
    -+        <li>{@link android.provider.CalendarContract.RemindersColumns#METHOD_EMAIL}</li>
    -+        <li>{@link android.provider.CalendarContract.RemindersColumns#METHOD_SMS}</li>
    -+    </ul></td>
    -+  </tr>
    -+</table>
    -+
    -+<h3 id="add-reminders">Menambahkan Pengingat</h3>
    -+
    -+<p>Contoh ini menambahkan pengingat ke kejadian. Pengingat dipicu 15
    -+menit sebelum kejadian.</p>
    -+<pre>
    -+long eventID = 221;
    -+...
    -+ContentResolver cr = getContentResolver();
    -+ContentValues values = new ContentValues();
    -+values.put(Reminders.MINUTES, 15);
    -+values.put(Reminders.EVENT_ID, eventID);
    -+values.put(Reminders.METHOD, Reminders.METHOD_ALERT);
    -+Uri uri = cr.insert(Reminders.CONTENT_URI, values);</pre>
    -+
    -+<h2 id="instances">Tabel Instances</h2>
    -+
    -+<p>Tabel
    -+{@link android.provider.CalendarContract.Instances} menyimpan
    -+waktu mulai dan waktu selesai kejadian. Tiap baris dalam tabel ini
    -+mewakili satu bentuk kejadian. Tabel instance tidak bisa ditulis dan hanya
    -+menyediakan sebuah cara untuk membuat query kejadian. </p>
    -+
    -+<p>Tabel berikut mencantumkan beberapa bidang yang bisa Anda query untuk suatu instance. Perhatikan
    -+bahwa zona waktu didefinisikan oleh
    -+{@link android.provider.CalendarContract.CalendarCache#KEY_TIMEZONE_TYPE}
    -+dan
    -+{@link android.provider.CalendarContract.CalendarCache#KEY_TIMEZONE_INSTANCES}.</p>
    -+
    -+
    -+<table>
    -+  <tr>
    -+    <th>Konstanta</th>
    -+    <th>Keterangan</th>
    -+  </tr>
    -+  <tr>
    -+    <td>{@link android.provider.CalendarContract.Instances#BEGIN}</td>
    -+    <td>Waktu mulai instance, dalam milidetik UTC.</td>
    -+  </tr>
    -+  <tr>
    -+    <td>{@link android.provider.CalendarContract.Instances#END}</td>
    -+    <td>Waktu selesai instance, dalam milidetik UTC.</td>
    -+  </tr>
    -+  <tr>
    -+    <td>{@link android.provider.CalendarContract.Instances#END_DAY}</td>
    -+
    -+    <td>Hari selesai Julian dari instance, relatif terhadap
    -+zona waktu Kalender.
    -+
    -+</td>
    -+  </tr>
    -+  <tr>
    -+    <td>{@link android.provider.CalendarContract.Instances#END_MINUTE}</td>
    -+
    -+    <td>Menit selesai dari instance yang diukur dari tengah malam di zona waktu
    -+Kalender.</td>
    -+
    -+  </tr>
    -+  <tr>
    -+    <td>{@link android.provider.CalendarContract.Instances#EVENT_ID}</td>
    -+    <td>Kejadian <code>_ID</code> untuk instance ini.</td>
    -+  </tr>
    -+    <tr>
    -+    <td>{@link android.provider.CalendarContract.Instances#START_DAY}</td>
    -+    <td>Hari mulai Julian dari instance, relatif terhadap zona waktu Kalender.
    -+ </td>
    -+  </tr>
    -+  <tr>
    -+    <td>{@link android.provider.CalendarContract.Instances#START_MINUTE}</td>
    -+
    -+    <td>Menit mulai dari instance yang diukur dari tengah malam, relatif terhadap
    -+zona waktu Kalender.
    -+</td>
    -+
    -+  </tr>
    -+
    -+</table>
    -+
    -+<h3 id="query-instances">Membuat query tabel Instance</h3>
    -+
    -+<p>Untuk membuat query tabel Instances, Anda perlu menetapkan rentang waktu query
    -+dalam URI. Dalam contoh ini, {@link android.provider.CalendarContract.Instances}
    -+mendapatkan akses ke bidang {@link
    -+android.provider.CalendarContract.EventsColumns#TITLE} melalui
    -+implementasi antarmuka {@link android.provider.CalendarContract.EventsColumns}-nya.
    -+Dengan kata lain, {@link
    -+android.provider.CalendarContract.EventsColumns#TITLE} dihasilkan melalui
    -+tampilan database, bukan melalui query terhadap tabel {@link
    -+android.provider.CalendarContract.Instances} mentah.</p>
    -+
    -+<pre>
    -+private static final String DEBUG_TAG = "MyActivity";
    -+public static final String[] INSTANCE_PROJECTION = new String[] {
    -+    Instances.EVENT_ID,      // 0
    -+    Instances.BEGIN,         // 1
    -+    Instances.TITLE          // 2
    -+  };
    -+
    -+// The indices for the projection array above.
    -+private static final int PROJECTION_ID_INDEX = 0;
    -+private static final int PROJECTION_BEGIN_INDEX = 1;
    -+private static final int PROJECTION_TITLE_INDEX = 2;
    -+...
    -+
    -+// Specify the date range you want to search for recurring
    -+// event instances
    -+Calendar beginTime = Calendar.getInstance();
    -+beginTime.set(2011, 9, 23, 8, 0);
    -+long startMillis = beginTime.getTimeInMillis();
    -+Calendar endTime = Calendar.getInstance();
    -+endTime.set(2011, 10, 24, 8, 0);
    -+long endMillis = endTime.getTimeInMillis();
    -+
    -+Cursor cur = null;
    -+ContentResolver cr = getContentResolver();
    -+
    -+// The ID of the recurring event whose instances you are searching
    -+// for in the Instances table
    -+String selection = Instances.EVENT_ID + " = ?";
    -+String[] selectionArgs = new String[] {"207"};
    -+
    -+// Construct the query with the desired date range.
    -+Uri.Builder builder = Instances.CONTENT_URI.buildUpon();
    -+ContentUris.appendId(builder, startMillis);
    -+ContentUris.appendId(builder, endMillis);
    -+
    -+// Submit the query
    -+cur =  cr.query(builder.build(),
    -+    INSTANCE_PROJECTION,
    -+    selection,
    -+    selectionArgs,
    -+    null);
    -+
    -+while (cur.moveToNext()) {
    -+    String title = null;
    -+    long eventID = 0;
    -+    long beginVal = 0;
    -+
    -+    // Get the field values
    -+    eventID = cur.getLong(PROJECTION_ID_INDEX);
    -+    beginVal = cur.getLong(PROJECTION_BEGIN_INDEX);
    -+    title = cur.getString(PROJECTION_TITLE_INDEX);
    -+
    -+    // Do something with the values.
    -+    Log.i(DEBUG_TAG, "Event:  " + title);
    -+    Calendar calendar = Calendar.getInstance();
    -+    calendar.setTimeInMillis(beginVal);
    -+    DateFormat formatter = new SimpleDateFormat("MM/dd/yyyy");
    -+    Log.i(DEBUG_TAG, "Date: " + formatter.format(calendar.getTime()));
    -+    }
    -+ }</pre>
    -+
    -+<h2 id="intents">Intent Kalender</h2>
    -+<p>Aplikasi Anda tidak memerlukan <a href="#manifest">izin</a> untuk membaca dan menulis data kalender. Sebagai gantinya, aplikasi bisa menggunakan intent yang didukung oleh aplikasi Kalender Android untuk menyerahkan operasi baca dan tulis ke aplikasi itu. Tabel berikut mencantumkan intent yang didukung oleh Penyedia Kalender:</p>
    -+<table>
    -+  <tr>
    -+    <th>Tindakan</th>
    -+    <th>URI</th>
    -+
    -+    <th>Keterangan</th>
    -+    <th>Ekstra</th>
    -+  </tr>
    -+  <tr>
    -+    <td><br>
    -+    {@link android.content.Intent#ACTION_VIEW VIEW} <br></td>
    -+    <td><p><code>content://com.android.calendar/time/&lt;ms_since_epoch&gt;</code></p>
    -+    Anda juga bisa mengacu ke URI dengan
    -+{@link android.provider.CalendarContract#CONTENT_URI CalendarContract.CONTENT_URI}.
    -+Untuk contoh yang menggunakan intent ini, lihat <a href="{@docRoot}guide/topics/providers/calendar-provider.html#intent-view">Menggunakan intent untuk menampilkan data kalender</a>.
    -+
    -+    </td>
    -+    <td>Membuka kalender pada waktu yang ditetapkan oleh <code>&lt;ms_since_epoch&gt;</code>.</td>
    -+    <td>Tidak ada.</td>
    -+  </tr>
    -+  <tr>
    -+    <td><p>{@link android.content.Intent#ACTION_VIEW VIEW} </p>
    -+
    -+     </td>
    -+    <td><p><code>content://com.android.calendar/events/&lt;event_id&gt;</code></p>
    -+
    -+    Anda juga bisa mengacu ke URI dengan
    -+{@link android.provider.CalendarContract.Events#CONTENT_URI Events.CONTENT_URI}.
    -+Untuk contoh yang menggunakan intent ini, lihat <a href="{@docRoot}guide/topics/providers/calendar-provider.html#intent-view">Menggunakan intent untuk menampilkan data kalender</a>.
    -+
    -+    </td>
    -+    <td>Menampilkan kejadian yang ditetapkan oleh <code>&lt;event_id&gt;</code>.</td>
    -+
    -+    <td>{@link android.provider.CalendarContract#EXTRA_EVENT_BEGIN_TIME CalendarContract.EXTRA_EVENT_BEGIN_TIME}<br>
    -+      <br>
    -+      <br>
    -+    {@link android.provider.CalendarContract#EXTRA_EVENT_END_TIME CalendarContract.EXTRA_EVENT_END_TIME}</td>
    -+  </tr>
    -+
    -+  <tr>
    -+    <td>{@link android.content.Intent#ACTION_EDIT EDIT} </td>
    -+    <td><p><code>content://com.android.calendar/events/&lt;event_id&gt;</code></p>
    -+
    -+  Anda juga bisa mengacu ke URI dengan
    -+{@link android.provider.CalendarContract.Events#CONTENT_URI Events.CONTENT_URI}.
    -+Untuk contoh penggunaan intent ini, lihat <a href="{@docRoot}guide/topics/providers/calendar-provider.html#intent-edit">Menggunakan intent untuk mengedit kejadian</a>.
    -+
    -+
    -+    </td>
    -+    <td>Mengedit kejadian yang ditetapkan oleh <code>&lt;event_id&gt;</code>.</td>
    -+
    -+    <td>{@link android.provider.CalendarContract#EXTRA_EVENT_BEGIN_TIME CalendarContract.EXTRA_EVENT_BEGIN_TIME}<br>
    -+      <br>
    -+      <br>
    -+    {@link android.provider.CalendarContract#EXTRA_EVENT_END_TIME CalendarContract.EXTRA_EVENT_END_TIME}</td>
    -+  </tr>
    -+
    -+  <tr>
    -+    <td>{@link android.content.Intent#ACTION_EDIT EDIT} <br>
    -+    <br>
    -+    {@link android.content.Intent#ACTION_INSERT INSERT} </td>
    -+    <td><p><code>content://com.android.calendar/events</code></p>
    -+
    -+   Anda juga bisa mengacu ke URI dengan
    -+{@link android.provider.CalendarContract.Events#CONTENT_URI Events.CONTENT_URI}.
    -+Untuk contoh penggunaan intent ini, lihat <a href="{@docRoot}guide/topics/providers/calendar-provider.html#intent-insert">Menggunakan intent untuk menyisipkan kejadian</a>.
    -+
    -+    </td>
    -+
    -+    <td>Membuat sebuah kejadian.</td>
    -+    <td>Ekstra apa saja yang tercantum dalam tabel di bawah.</td>
    -+  </tr>
    -+</table>
    -+
    -+<p>Tabel berikut mencantumkan ekstra intent yang didukung oleh Penyedia Kalender:
    -+</p>
    -+<table>
    -+  <tr>
    -+    <th>Ekstra Intent</th>
    -+    <th>Keterangan</th>
    -+  </tr>
    -+  <tr>
    -+    <td>{@link android.provider.CalendarContract.EventsColumns#TITLE Events.TITLE}</td>
    -+    <td>Nama kejadian.</td>
    -+  </tr>
    -+  <tr>
    -+
    -+    <td>{@link android.provider.CalendarContract#EXTRA_EVENT_BEGIN_TIME
    -+CalendarContract.EXTRA_EVENT_BEGIN_TIME}</td>
    -+    <td>Waktu mulai kejadian dalam milidetik sejak waktu patokan.</td>
    -+  </tr>
    -+  <tr>
    -+    <td>{@link android.provider.CalendarContract#EXTRA_EVENT_END_TIME
    -+CalendarContract.EXTRA_EVENT_END_TIME}</td>
    -+
    -+    <td>Waktu selesai kejadian dalam milidetik sejak waktu patokan.</td>
    -+  </tr>
    -+  <tr>
    -+    <td>{@link android.provider.CalendarContract#EXTRA_EVENT_ALL_DAY
    -+CalendarContract.EXTRA_EVENT_ALL_DAY}</td>
    -+
    -+    <td>Sebuah boolean yang menunjukkan bahwa kejadian sehari penuh. Nilai bisa
    -+<code>true</code> atau <code>false</code>.</td> </tr>
    -+  <tr>
    -+    <td>{@link android.provider.CalendarContract.EventsColumns#EVENT_LOCATION
    -+Events.EVENT_LOCATION}</td>
    -+
    -+    <td>Lokasi kejadian.</td>
    -+  </tr>
    -+  <tr>
    -+    <td>{@link android.provider.CalendarContract.EventsColumns#DESCRIPTION
    -+Events.DESCRIPTION}</td>
    -+
    -+    <td>Keterangan kejadian.</td>
    -+  </tr>
    -+  <tr>
    -+    <td>
    -+    {@link android.content.Intent#EXTRA_EMAIL Intent.EXTRA_EMAIL}</td>
    -+    <td>Alamat email mereka yang harus diundang berupa daftar yang dipisahkan koma.</td>
    -+  </tr>
    -+  <tr>
    -+    <td>
    -+    {@link android.provider.CalendarContract.EventsColumns#RRULE Events.RRULE}</td>
    -+    <td>Aturan perulangan kejadian.</td>
    -+  </tr>
    -+  <tr>
    -+    <td>
    -+    {@link android.provider.CalendarContract.EventsColumns#ACCESS_LEVEL
    -+Events.ACCESS_LEVEL}</td>
    -+
    -+    <td>Apakah kejadian bersifat privat atau publik.</td>
    -+  </tr>
    -+  <tr>
    -+    <td>{@link android.provider.CalendarContract.EventsColumns#AVAILABILITY
    -+Events.AVAILABILITY}</td>
    -+
    -+    <td>Jika kejadian ini dihitung sebagai waktu sibuk atau waktu bebas yang bisa dijadwalkan.</td>
    -+
    -+</table>
    -+<p>Bagian berikut menjelaskan cara menggunakan semua intent ini.</p>
    -+
    -+
    -+<h3 id="intent-insert">Menggunakan intent untuk menyisipkan kejadian</h3>
    -+
    -+<p>Penggunaan Intent {@link android.content.Intent#ACTION_INSERT INSERT}
    -+akan memungkinkan aplikasi Anda menyerahkan tugas penyisipan kejadian ke Kalender itu sendiri.
    -+Dengan pendekatan ini, aplikasi Anda bahkan tidak perlu menyertakan izin {@link
    -+android.Manifest.permission#WRITE_CALENDAR} dalam <a href="#manifest">file manifesnya</a>.</p>
    -+
    -+
    -+<p>Bila pengguna menjalankan aplikasi yang menggunakan pendekatan ini, aplikasi akan mengirim
    -+izin ke Kalender untuk menyelesaikan penambahan kejadian. Intent {@link
    -+android.content.Intent#ACTION_INSERT INSERT} menggunakan bidang-bidang ekstra
    -+untuk mengisi formulir lebih dahulu dengan detail kejadian dalam Kalender. Pengguna nanti bisa
    -+membatalkan kejadian, mengedit formulir sebagaimana diperlukan, atau menyimpan kejadian ke
    -+kalender mereka.</p>
    -+
    -+
    -+
    -+<p>Berikut ini adalah cuplikan kode yang menjadwalkan kejadian pada tanggal 19 Januari 2012, yang berjalan
    -+dari 7:30 pagi hingga 8:30 pagi Perhatikan hal-hal berikut tentang cuplikan kode ini:</p>
    -+
    -+<ul>
    -+  <li>Cuplikan kode ini menetapkan {@link android.provider.CalendarContract.Events#CONTENT_URI Events.CONTENT_URI}
    -+  sebagai URI-nya.</li>
    -+
    -+  <li>Cuplikan kode ini menggunakan bidang-bidang ekstra {@link
    -+android.provider.CalendarContract#EXTRA_EVENT_BEGIN_TIME
    -+CalendarContract.EXTRA_EVENT_BEGIN_TIME} dan {@link
    -+android.provider.CalendarContract#EXTRA_EVENT_END_TIME
    -+CalendarContract.EXTRA_EVENT_END_TIME} untuk mengisi dahulu formulir
    -+dengan waktu kejadian. Nilai-nilai untuk waktu ini harus dalam milidetik UTC
    -+sejak waktu patokan.</li>
    -+
    -+  <li>Cuplikan kode ini menggunakan bidang ekstra {@link android.content.Intent#EXTRA_EMAIL Intent.EXTRA_EMAIL}
    -+untuk memberikan daftar undangan yang dipisah koma, yang ditetapkan melalui alamat email.</li>
    -+
    -+</ul>
    -+<pre>
    -+Calendar beginTime = Calendar.getInstance();
    -+beginTime.set(2012, 0, 19, 7, 30);
    -+Calendar endTime = Calendar.getInstance();
    -+endTime.set(2012, 0, 19, 8, 30);
    -+Intent intent = new Intent(Intent.ACTION_INSERT)
    -+        .setData(Events.CONTENT_URI)
    -+        .putExtra(CalendarContract.EXTRA_EVENT_BEGIN_TIME, beginTime.getTimeInMillis())
    -+        .putExtra(CalendarContract.EXTRA_EVENT_END_TIME, endTime.getTimeInMillis())
    -+        .putExtra(Events.TITLE, &quot;Yoga&quot;)
    -+        .putExtra(Events.DESCRIPTION, &quot;Group class&quot;)
    -+        .putExtra(Events.EVENT_LOCATION, &quot;The gym&quot;)
    -+        .putExtra(Events.AVAILABILITY, Events.AVAILABILITY_BUSY)
    -+        .putExtra(Intent.EXTRA_EMAIL, &quot;rowan@example.com,trevor@example.com&quot;);
    -+startActivity(intent);
    -+</pre>
    -+
    -+<h3 id="intent-edit">Menggunakan intent untuk mengedit kejadian</h3>
    -+
    -+<p>Anda bisa memperbarui kejadian secara langsung, seperti dijelaskan dalam <a href="#update-event">Memperbarui kejadian</a>. Namun penggunaan Intent {@link
    -+android.content.Intent#ACTION_EDIT EDIT} memungkinkan aplikasi yang
    -+tidak memiliki izin untuk menyerahkan pengeditan kejadian ke aplikasi Kalender.
    -+Bila pengguna selesai mengedit kejadian dalam Kalender, pengguna akan dikembalikan ke
    -+aplikasi semula.</p> <p>Berikut ini adalah contoh intent yang mengatur
    -+judul baru bagi kejadian yang ditetapkan dan memungkinkan pengguna mengedit kejadian dalam Kalender.</p>
    -+
    -+
    -+<pre>long eventID = 208;
    -+Uri uri = ContentUris.withAppendedId(Events.CONTENT_URI, eventID);
    -+Intent intent = new Intent(Intent.ACTION_EDIT)
    -+    .setData(uri)
    -+    .putExtra(Events.TITLE, &quot;My New Title&quot;);
    -+startActivity(intent);</pre>
    -+
    -+<h3 id="intent-view">Menggunakan intent untuk menampilkan data kalender</h3>
    -+<p>Penyedia Kalender menyediakan dua cara menggunakan Intent {@link android.content.Intent#ACTION_VIEW VIEW}:</p>
    -+<ul>
    -+  <li>Untuk membuka Kalender pada tanggal tertentu.</li>
    -+  <li>Untuk menampilkan sebuah kejadian.</li>
    -+
    -+</ul>
    -+<p>Berikut ini adalah contoh yang menampilkan cara membuka Kalender pada tanggal tertentu:</p>
    -+<pre>// A date-time specified in milliseconds since the epoch.
    -+long startMillis;
    -+...
    -+Uri.Builder builder = CalendarContract.CONTENT_URI.buildUpon();
    -+builder.appendPath(&quot;time&quot;);
    -+ContentUris.appendId(builder, startMillis);
    -+Intent intent = new Intent(Intent.ACTION_VIEW)
    -+    .setData(builder.build());
    -+startActivity(intent);</pre>
    -+
    -+<p>Berikut ini adalah contoh yang menampilkan cara membuka kejadian untuk menampilkan:</p>
    -+<pre>long eventID = 208;
    -+...
    -+Uri uri = ContentUris.withAppendedId(Events.CONTENT_URI, eventID);
    -+Intent intent = new Intent(Intent.ACTION_VIEW)
    -+   .setData(uri);
    -+startActivity(intent);
    -+</pre>
    -+
    -+
    -+<h2 id="sync-adapter">Adaptor Sinkronisasi</h2>
    -+
    -+
    -+<p>Hanya ada perbedaan kecil dalam cara aplikasi dan adaptor sinkronisasi
    -+mengakses Penyedia Kalender:</p>
    -+
    -+<ul>
    -+  <li>Adaptor sinkronisasi perlu menetapkan bahwa dirinya sebuah adaptor sinkronisasi dengan mengatur {@link android.provider.CalendarContract#CALLER_IS_SYNCADAPTER} ke <code>true</code>.</li>
    -+
    -+
    -+  <li>Adaptor sinkronisasi perlu memberikan {@link
    -+android.provider.CalendarContract.SyncColumns#ACCOUNT_NAME} dan {@link
    -+android.provider.CalendarContract.SyncColumns#ACCOUNT_TYPE} sebagai parameter query dalam URI. </li>
    -+
    -+  <li>Adaptor sinkronisasi memiliki akses tulis ke lebih banyak kolom daripada aplikasi atau widget.
    -+  Misalnya, aplikasi hanya bisa mengubah sedikit karakteristik kalender,
    -+  misalnya nama, nama tampilan, pengaturan visibilitas, dan apakah kalender
    -+  disinkronkan atau tidak. Sebagai perbandingan, adaptor sinkronisasi bisa mengakses bukan hanya kolom-kolom itu, namun banyak kolom lainnya,
    -+  misalnya warna kalender, zona waktu, tingkat akses, lokasi, dan seterusnya.
    -+Akan tetapi, adaptor sinkronisasi dibatasi pada <code>ACCOUNT_NAME</code> dan
    -+<code>ACCOUNT_TYPE</code> yang ditetapkannya.</li> </ul>
    -+
    -+<p>Berikut ini adalah metode pembantu yang bisa Anda gunakan untuk menghasilkan URI bagi penggunaan dengan adaptor sinkronisasi:</p>
    -+<pre> static Uri asSyncAdapter(Uri uri, String account, String accountType) {
    -+    return uri.buildUpon()
    -+        .appendQueryParameter(android.provider.CalendarContract.CALLER_IS_SYNCADAPTER,&quot;true&quot;)
    -+        .appendQueryParameter(Calendars.ACCOUNT_NAME, account)
    -+        .appendQueryParameter(Calendars.ACCOUNT_TYPE, accountType).build();
    -+ }
    -+</pre>
    -+<p>Untuk contoh implementasi adaptor sinkronisasi (yang tidak terkait secara khusus dengan Kalender), lihat
    -+<a href="{@docRoot}resources/samples/SampleSyncAdapter/index.html">SampleSyncAdapter</a>.
    -diff --git a/docs/html-intl/intl/id/guide/topics/providers/contacts-provider.jd b/docs/html-intl/intl/id/guide/topics/providers/contacts-provider.jd
    -new file mode 100644
    -index 0000000..994c56b
    ---- /dev/null
    -+++ b/docs/html-intl/intl/id/guide/topics/providers/contacts-provider.jd
    -@@ -0,0 +1,2356 @@
    -+page.title=Penyedia Kontak
    -+@jd:body
    -+<div id="qv-wrapper">
    -+<div id="qv">
    -+<h2>Tampilan Cepat</h2>
    -+<ul>
    -+    <li>Repository informasi Android tentang orang.</li>
    -+    <li>
    -+        Sinkronisasi dengan web.
    -+    </li>
    -+    <li>
    -+        Mengintegrasikan data aliran sosial.
    -+    </li>
    -+</ul>
    -+<h2>Dalam dokumen ini</h2>
    -+<ol>
    -+    <li>
    -+        <a href="#InformationTypes">Organisasi Penyedia Kontak</a>
    -+    </li>
    -+    <li>
    -+        <a href="#RawContactBasics">Kontak mentah</a>
    -+    </li>
    -+    <li>
    -+        <a href="#DataBasics">Data</a>
    -+    </li>
    -+    <li>
    -+        <a href="#ContactBasics">Kontak</a>
    -+    </li>
    -+    <li>
    -+        <a href="#Sources">Data Dari Adaptor Sinkronisasi</a>
    -+    </li>
    -+    <li>
    -+        <a href="#Permissions">Izin yang Diperlukan</a>
    -+    </li>
    -+    <li>
    -+        <a href="#UserProfile">Profil Pengguna</a>
    -+    </li>
    -+    <li>
    -+        <a href="#ContactsProviderMetadata">Metadata Penyedia Kontak</a>
    -+    </li>
    -+    <li>
    -+        <a href="#Access">Akses Penyedia Kontak</a>
    -+    <li>
    -+    </li>
    -+    <li>
    -+        <a href="#SyncAdapters">Adaptor Sinkronisasi Penyedia Kontak</a>
    -+    </li>
    -+    <li>
    -+        <a href="#SocialStream">Data Aliran Sosial</a>
    -+    </li>
    -+    <li>
    -+        <a href="#AdditionalFeatures">Fitur Tambahan Penyedia Kontak</a>
    -+    </li>
    -+</ol>
    -+<h2>Kelas-kelas utama</h2>
    -+<ol>
    -+    <li>{@link android.provider.ContactsContract.Contacts}</li>
    -+    <li>{@link android.provider.ContactsContract.RawContacts}</li>
    -+    <li>{@link android.provider.ContactsContract.Data}</li>
    -+    <li>{@code android.provider.ContactsContract.StreamItems}</li>
    -+</ol>
    -+<h2>Contoh-Contoh Terkait</h2>
    -+<ol>
    -+    <li>
    -+        <a href="{@docRoot}resources/samples/ContactManager/index.html">
    -+        Contact Manager
    -+        </a>
    -+    </li>
    -+    <li>
    -+        <a href="{@docRoot}resources/samples/SampleSyncAdapter/index.html">
    -+        Contoh Adaptor Sinkronisasi</a>
    -+    </li>
    -+</ol>
    -+<h2>Lihat Juga</h2>
    -+<ol>
    -+    <li>
    -+        <a href="{@docRoot}guide/topics/providers/content-provider-basics.html">
    -+        Dasar-Dasar Penyedia Konten
    -+        </a>
    -+    </li>
    -+</ol>
    -+</div>
    -+</div>
    -+<p>
    -+    Penyedia Kontak adalah komponen Android yang tangguh dan fleksibel dalam mengelola
    -+ repository data pusat tentang orang di perangkat. Penyedia Kontak adalah sumber data
    -+ yang Anda lihat dalam aplikasi kontak perangkat, dan Anda juga bisa mengakses datanya dalam aplikasi
    -+    Anda sendiri serta mentransfer data antara perangkat dan layanan online. Penyedia mengakomodasi
    -+    berbagai sumber data dan mencoba mengelola data sebanyak mungkin untuk setiap orang, sehingga
    -+   organisasinya menjadi kompleks. Karena itu, API penyedia menyertakan
    -+    satu set kelas kontrak dan antarmuka ekstensif yang membantu pengambilan dan
    -+    modifikasi data.
    -+</p>
    -+<p>
    -+    Panduan ini menjelaskan hal-hal berikut:
    -+</p>
    -+    <ul>
    -+        <li>
    -+            Struktur penyedia dasar.
    -+        </li>
    -+        <li>
    -+            Cara mengambil data dari penyedia.
    -+        </li>
    -+        <li>
    -+            Cara memodifikasi data di penyedia.
    -+        </li>
    -+        <li>
    -+            Cara menulis adaptor sinkronisasi untuk menyinkronkan data dari server Anda ke
    -+            Penyedia Kontak.
    -+        </li>
    -+    </ul>
    -+<p>
    -+    Panduan ini beranggapan bahwa Anda mengetahui dasar-dasar penyedia konten Android. Untuk mengetahui selengkapnya
    -+    tentang penyedia konten Android, bacalah
    -+    panduan<a href="{@docRoot}guide/topics/providers/content-provider-basics.html">
    -+    Dasar-Dasar Penyedia Konten</a>. Contoh aplikasi
    -+    <a href="{@docRoot}resources/samples/SampleSyncAdapter/index.html">Sample Sync Adapter</a>
    -+    adalah contoh penggunaan adaptor sinkronisasi untuk mentransfer data antara Penyedia Kontak
    -+    dan contoh aplikasi yang memiliki host di Google Web Services.
    -+</p>
    -+<h2 id="InformationTypes">Organisasi Penyedia Kontak</h2>
    -+<p>
    -+    Penyedia Kontak adalah komponen penyedia konten Android. Komponen ini memelihara tiga tipe
    -+    data tentang seseorang, masing-masing disesuaikan dengan tabel yang ditawarkan oleh penyedia, seperti
    -+    yang terlihat dalam gambar 1:
    -+</p>
    -+<img src="{@docRoot}images/providers/contacts_structure.png" alt="" height="364" id="figure1" />
    -+<p class="img-caption">
    -+  <strong>Gambar 1.</strong> Struktur tabel Penyedia Kontak.
    -+</p>
    -+<p>
    -+    Ketiga tabel disebut secara umum menurut nama kelas kontrak. Kelas
    -+    mendefinisikan konstanta untuk URI konten, nama kolom, dan nilai kolom yang digunakan oleh tabel-tabel:
    -+</p>
    -+<dl>
    -+    <dt>
    -+        Tabel {@link android.provider.ContactsContract.Contacts}
    -+    </dt>
    -+    <dd>
    -+        Baris mewakili orang yang berbeda, berdasarkan agregrasi baris kontak mentah.
    -+    </dd>
    -+    <dt>
    -+        Tabel {@link android.provider.ContactsContract.RawContacts}
    -+    </dt>
    -+    <dd>
    -+        Baris berisi rangkuman data seseorang, untuk tipe dan akun pengguna tertentu.
    -+    </dd>
    -+    <dt>
    -+        Tabel {@link android.provider.ContactsContract.Data}
    -+    </dt>
    -+    <dd>
    -+        Baris berisi data untuk kontak mentah, seperti alamat email atau nomor telepon.
    -+    </dd>
    -+</dl>
    -+<p>
    -+    Tabel lain yang diwakili oleh kelas kontrak dalam {@link android.provider.ContactsContract}
    -+    adalah tabel tambahan yang digunakan Penyedia Kontak untuk mengelola operasinya atau mendukung
    -+    fungsi tertentu dalam kontak atau aplikasi telepon perangkat.
    -+</p>
    -+<h2 id="RawContactBasics">Kontak mentah</h2>
    -+<p>
    -+    Kontak mentah mewakili data seseorang yang berasal dari satu tipe akun dan nama
    -+  akun. Karena Penyedia Kontak memungkinkan lebih dari satu layanan online sebagai sumber
    -+    data untuk satu orang, Penyedia Kontak memungkinkan multikontak mentah untuk orang yang sama.
    -+    Multikontak mentah juga memungkinkan seorang pengguna mengombinasikan data seseorang dari lebih dari satu akun
    -+    bertipe akun yang sama.
    -+</p>
    -+<p>
    -+    Sebagian besar data untuk kontak mentah tidak disimpan dalam
    -+    tabel {@link android.provider.ContactsContract.RawContacts}. Sebagai gantinya, data tersebut disimpan dalam satu atau beberapa baris
    -+    dalam tabel {@link android.provider.ContactsContract.Data}. Setiap baris data memiliki kolom
    -+    {@link android.provider.ContactsContract.DataColumns#RAW_CONTACT_ID Data.RAW_CONTACT_ID} yang
    -+    berisi nilai {@code android.provider.BaseColumns#_ID RawContacts._ID} dari
    -+    baris {@link android.provider.ContactsContract.RawContacts} induknya.
    -+</p>
    -+<h3 id="RawContactsColumns">Kolom-kolom kontak mentah yang penting</h3>
    -+<p>
    -+    Kolom-kolom penting dalam tabel {@link android.provider.ContactsContract.RawContacts}
    -+    tercantum pada tabel 1. Bacalah catatan yang diberikan setelah tabel:
    -+</p>
    -+<p class="table-caption" id="table1">
    -+    <strong>Tabel 1.</strong> Kolom-kolom kontak mentah yang penting.
    -+</p>
    -+<table>
    -+    <tr>
    -+        <th scope="col">Nama kolom</th>
    -+        <th scope="col">Kegunaan</th>
    -+        <th scope="col">Catatan</th>
    -+    </tr>
    -+    <tr>
    -+        <td>
    -+            {@link android.provider.ContactsContract.SyncColumns#ACCOUNT_NAME}
    -+        </td>
    -+        <td>
    -+            Nama akun untuk tipe akun yang merupakan sumber kontak mentah ini.
    -+            Misalnya, nama akun dari akun Google adalah salah satu alamat Gmail
    -+   pemilik perangkat. Lihat entri berikutnya untuk
    -+            {@link android.provider.ContactsContract.SyncColumns#ACCOUNT_TYPE} untuk informasi
    -+            selengkapnya.
    -+        </td>
    -+        <td>
    -+            Format nama ini khusus untuk tipe akun ini. Format ini tidak
    -+            harus alamat email.
    -+        </td>
    -+    </tr>
    -+    <tr>
    -+        <td>
    -+            {@link android.provider.ContactsContract.SyncColumns#ACCOUNT_TYPE}
    -+        </td>
    -+        <td>
    -+            Tipe akun yang merupakan sumber kontak mentah ini. Misalnya, tipe
    -+           akun dari akun Google adalah <code>com.google</code>. Selalu batasi tipe akun Anda
    -+            dengan identifier domain untuk domain yang Anda miliki atau kontrol. Hal ini akan memastikan bahwa tipe
    -+            akun Anda bersifat unik.
    -+        </td>
    -+        <td>
    -+            Tipe akun yang menawarkan data kontak biasanya memiliki adaptor sinkronisasi terkait yang
    -+            menyinkronkan dengan Penyedia Kontak.
    -+    </tr>
    -+    <tr>
    -+        <td>
    -+            {@link android.provider.ContactsContract.RawContactsColumns#DELETED}
    -+        </td>
    -+        <td>
    -+            Flag "deleted" untuk kontak mentah.
    -+        </td>
    -+        <td>
    -+            Flag ini memungkinkan Penyedia Kontak memelihara baris secara internal hingga adaptor
    -+            sinkronisasi bisa menghapus baris dari server mereka dan akhirnya menghapus baris
    -+            dari repository.
    -+        </td>
    -+    </tr>
    -+</table>
    -+<h4>Catatan</h4>
    -+<p>
    -+    Berikut ini adalah catatan penting tentang
    -+    tabel {@link android.provider.ContactsContract.RawContacts}:
    -+</p>
    -+<ul>
    -+    <li>
    -+        Nama kontak mentah tidak disimpan di barisnya dalam
    -+        {@link android.provider.ContactsContract.RawContacts}. Sebagai gantinya, nama tersebut disimpan dalam
    -+         tabel {@link android.provider.ContactsContract.Data}, pada
    -+        baris {@link android.provider.ContactsContract.CommonDataKinds.StructuredName}. Kontak mentah
    -+        hanya memiliki satu baris dari tipe ini dalam tabel {@link android.provider.ContactsContract.Data}.
    -+    </li>
    -+    <li>
    -+        <strong>Perhatian:</strong> Untuk menggunakan data akun sendiri dalam baris kontak mentah, akun harus
    -+        didaftarkan lebih dahulu dengan {@link android.accounts.AccountManager}. Caranya, mintalah
    -+        pengguna untuk menambahkan tipe akun dan nama akun ke dalam daftar akun. Jika Anda tidak
    -+        melakukannya, Penyedia Kontak secara otomatis akan menghapus baris kontak mentah Anda.
    -+        <p>
    -+            Misalnya, Anda menginginkan aplikasi memelihara data kontak untuk layanan berbasis web
    -+            dengan domain {@code com.example.dataservice}, dan akun pengguna untuk layanan Anda
    -+            adalah {@code becky.sharp@dataservice.example.com}, pengguna harus menambahkan lebih dahulu "type"
    -+            akun ({@code com.example.dataservice}) dan "name" akun
    -+            ({@code becky.smart@dataservice.example.com}) sebelum aplikasi Anda bisa menambahkan baris kontak mentah.
    -+            Anda bisa menjelaskan ketentuan ini kepada pengguna dalam dokumentasi, atau meminta
    -+            pengguna untuk menambahkan tipe dan nama, atau keduanya. Tipe akun dan nama akun
    -+            dijelaskan lebih detail di bagian berikutnya.
    -+    </li>
    -+</ul>
    -+<h3 id="RawContactsExample">Sumber data kontak mentah</h3>
    -+<p>
    -+    Untuk memahami cara kerja kontak mentah, perhatikan pengguna "Emily Dickinson" yang mendefinisikan
    -+    tiga akun pengguna berikut pada perangkatnya:
    -+</p>
    -+<ul>
    -+    <li><code>emily.dickinson@gmail.com</code></li>
    -+    <li><code>emilyd@gmail.com</code></li>
    -+    <li>Akun Twitter "belle_of_amherst"</li>
    -+</ul>
    -+<p>
    -+    Pengguna ini telah mengaktifkan <em>Sync Contacts</em> untuk ketiga akun dalam pengaturan
    -+    <em>Accounts</em>.
    -+</p>
    -+<p>
    -+    Anggaplah Emily Dickinson membuka jendela browser, masuk ke Gmail sebagai
    -+    <code>emily.dickinson@gmail.com</code>, membuka
    -+    Contacts, dan menambahkan "Thomas Higginson". Kemudian, ia masuk ke Gmail sebagai
    -+    <code>emilyd@gmail.com</code> dan mengirimkan email kepada "Thomas Higginson", yang
    -+    menambahkan Thomas secara otomatis sebagai kontak. Ia juga mengikuti "colonel_tom" (ID Twitter Thomas Higginson) di
    -+    Twitter.
    -+</p>
    -+<p>
    -+    Penyedia Kontak membuat tiga kontak mentah akibat pekerjaan ini:
    -+</p>
    -+<ol>
    -+    <li>
    -+        Kontak mentah untuk "Thomas Higginson" yang dikaitkan dengan <code>emily.dickinson@gmail.com</code>.
    -+        Tipe akun penggunanya adalah Google.
    -+    </li>
    -+    <li>
    -+        Kontak mentah kedua untuk "Thomas Higginson" yang dikaitkan dengan <code>emilyd@gmail.com</code>.
    -+        Tipe akun pengguna juga Google. Ada kontak mentah kedua
    -+       meskipun nama tersebut identik dengan nama sebelumnya karena orang bersangkutan ditambahkan untuk
    -+        akun pengguna yang berbeda.
    -+    </li>
    -+    <li>
    -+        Kontak mentah ketiga untuk "Thomas Higginson" yang dikaitkan dengan "belle_of_amherst". Tipe
    -+        akun penggunanya adalah Twitter.
    -+    </li>
    -+</ol>
    -+<h2 id="DataBasics">Data</h2>
    -+<p>
    -+    Seperti yang telah disebutkan, data untuk kontak mentah disimpan dalam
    -+    baris {@link android.provider.ContactsContract.Data} yang ditautkan dengan nilai
    -+    <code>_ID</code> kontak mentah. Cara ini memungkinkan satu kontak mentah memiliki beberapa instance tipe data
    -+    yang sama dengan alamat email atau nomor telepon. Misalnya, jika
    -+    "Thomas Higginson" untuk {@code emilyd@gmail.com} (baris kontak mentah untuk Thomas Higginson
    -+   yang dikaitkan dengan akun Google <code>emilyd@gmail.com</code>) memiliki alamat email rumah
    -+    <code>thigg@gmail.com</code> dan alamat email kerja
    -+    <code>thomas.higginson@gmail.com</code>, Penyedia Kontak akan menyimpan dua baris alamat
    -+    email dan menautkan keduanya ke kontak mentah.
    -+</p>
    -+<p>
    -+    Perhatikan bahwa tipe data yang berbeda disimpan dalam satu tabel ini. Baris-baris nama tampilan,
    -+    nomor telepon, email, alamat surat, foto, dan data situs web semuanya bisa ditemukan dalam
    -+    tabel {@link android.provider.ContactsContract.Data}. Untuk membantu mengelola ini,
    -+    tabel {@link android.provider.ContactsContract.Data} memiliki beberapa kolom dengan nama deskriptif,
    -+    dalam kolom lain dengan nama generik. Konten kolom bernama deskriptif memiliki arti yang sama
    -+    terlepas dari tipe data dalam barisnya, sedangkan konten kolom bernama generik memiliki
    -+    arti yang berbeda-beda sesuai dengan tipe data.
    -+</p>
    -+<h3 id="DescriptiveColumns">Nama kolom deskriptif</h3>
    -+<p>
    -+    Beberapa contoh nama kolom deskriptif adalah:
    -+</p>
    -+<dl>
    -+    <dt>
    -+        {@link android.provider.ContactsContract.Data#RAW_CONTACT_ID}
    -+    </dt>
    -+    <dd>
    -+        Nilai kolom <code>_ID</code> kontak mentah untuk data ini.
    -+    </dd>
    -+    <dt>
    -+        {@link android.provider.ContactsContract.Data#MIMETYPE}
    -+    </dt>
    -+    <dd>
    -+        Tipe data yang disimpan dalam baris ini, dinyatakan berupa tipe MIME custom. Penyedia Kontak
    -+        menggunakan tipe MIME yang didefinisikan dalam subkelas
    -+        {@link android.provider.ContactsContract.CommonDataKinds}. Tipe MIME ini adalah sumber terbuka,
    -+        dan bisa digunakan oleh setiap aplikasi atau adaptor sinkronisasi yang bisa digunakan bersama Penyedia Kontak.
    -+    </dd>
    -+    <dt>
    -+        {@link android.provider.ContactsContract.DataColumns#IS_PRIMARY}
    -+    </dt>
    -+    <dd>
    -+        Jika tipe baris data ini bisa terjadi lebih dari satu kali untuk suatu kontak mentah,
    -+        kolom {@link android.provider.ContactsContract.DataColumns#IS_PRIMARY}
    -+        menandai baris data yang berisi data utama untuk tipe itu. Misalnya, jika
    -+        pengguna menekan lama sebuah nomor telepon untuk kontak dan memilih <strong>Set default</strong>,
    -+       maka baris {@link android.provider.ContactsContract.Data} yang berisi angka itu
    -+        mengatur kolom {@link android.provider.ContactsContract.DataColumns#IS_PRIMARY}-nya ke suatu
    -+        nilai bukan nol.
    -+    </dd>
    -+</dl>
    -+<h3 id="GenericColumns">Nama kolom generik</h3>
    -+<p>
    -+    Ada 15 kolom generik bernama <code>DATA1</code> hingga
    -+    <code>DATA15</code> yang tersedia secara umum dan empat kolom generik
    -+    tambahan <code>SYNC1</code> hingga <code>SYNC4</code> yang harus digunakan hanya oleh adaptor
    -+    sinkronisasi. Konstanta nama kolom generik selalu berfungsi, terlepas dari tipe
    -+    data dalam baris .
    -+</p>
    -+<p>
    -+    Kolom <code>DATA1</code> diindeks.  Penyedia Kontak selalu menggunakan kolom ini untuk
    -+    data yang diharapkan penyedia akan menjadi target yang paling sering dari suatu query. Misalnya,
    -+    dalam baris email, kolom ini berisi alamat email sebenarnya.
    -+</p>
    -+<p>
    -+    Sesuai konvensi, kolom <code>DATA15</code> dicadangkan untuk menyimpan data Binary Large Object
    -+    (BLOB) seperti thumbnail foto.
    -+</p>
    -+<h3 id="TypeSpecificNames">Nama kolom bertipe spesifik</h3>
    -+<p>
    -+    Guna memudahkan pekerjaan dengan kolom untuk tipe baris tertentu, Penyedia Kontak
    -+    juga menyediakan konstanta nama kolom bertipe spesifik, yang didefinisikan dalam subkelas
    -+    {@link android.provider.ContactsContract.CommonDataKinds}. Konstanta cuma memberikan nama
    -+    konstanta yang berbeda ke nama kolom yang sama, yang membantu Anda mengakses data dalam baris
    -+    bertipe spesifik.
    -+</p>
    -+<p>
    -+    Misalnya, kelas {@link android.provider.ContactsContract.CommonDataKinds.Email} mendefinisikan
    -+    konstanta nama kolom bertipe spesifik untuk baris {@link android.provider.ContactsContract.Data}
    -+    yang memiliki tipe MIME
    -+    {@link android.provider.ContactsContract.CommonDataKinds.Email#CONTENT_ITEM_TYPE
    -+    Email.CONTENT_ITEM_TYPE}. Kelas ini berisi konstanta
    -+    {@link android.provider.ContactsContract.CommonDataKinds.Email#ADDRESS} untuk kolom
    -+    alamat email. Nilai sesungguhnya dari
    -+    {@link android.provider.ContactsContract.CommonDataKinds.Email#ADDRESS} adalah "data1", yang
    -+    sama dengan nama generik kolom.
    -+</p>
    -+<p class="caution">
    -+    <strong>Perhatian:</strong> Jangan tambahkan data custom Anda sendiri ke
    -+    tabel {@link android.provider.ContactsContract.Data} dengan menggunakan baris yang memiliki salah satu
    -+    tipe MIME yang telah didefinisikan penyedia. Jika melakukannya, Anda bisa kehilangan data atau menyebabkan penyedia
    -+    gagal berfungsi. Misalnya, Anda seharusnya tidak menambahkan baris bertipe MIME
    -+    {@link android.provider.ContactsContract.CommonDataKinds.Email#CONTENT_ITEM_TYPE
    -+    Email.CONTENT_ITEM_TYPE} yang berisi nama pengguna sebagai ganti alamat email dalam
    -+    kolom <code>DATA1</code>. Jika Anda menggunakan tipe MIME custom sendiri untuk baris bersangkutan, maka Anda bebas
    -+    untuk mendefinisikan nama kolom bertipe spesifik dan menggunakan kolom sekehendak Anda.
    -+</p>
    -+<p>
    -+    Gambar 2 menampilkan cara kolom deskriptif dan kolom data muncul dalam
    -+    baris {@link android.provider.ContactsContract.Data}, dan cara nama kolom bertipe spesifik "melapisi"
    -+    nama kolom generik
    -+</p>
    -+<img src="{@docRoot}images/providers/data_columns.png" alt="How type-specific column names map to generic column names" height="311" id="figure2" />
    -+<p class="img-caption">
    -+  <strong>Gambar 2.</strong> Nama kolom bertipe spesifik dan nama kolom generik.
    -+</p>
    -+<h3 id="ColumnMaps">Kelas nama kolom bertipe spesifik</h3>
    -+<p>
    -+    Tabel 2 berisi daftar kelas nama kolom bertipe spesifik yang paling umum digunakan:
    -+</p>
    -+<p class="table-caption" id="table2">
    -+  <strong>Tabel 2.</strong> Kelas nama kolom bertipe spesifik</p>
    -+<table>
    -+  <tr>
    -+    <th scope="col">Kelas pemetaan</th>
    -+    <th scope="col">Tipe data</th>
    -+    <th scope="col">Catatan</th>
    -+  </tr>
    -+  <tr>
    -+    <td>{@link android.provider.ContactsContract.CommonDataKinds.StructuredName}</td>
    -+    <td>Data nama untuk kontak mentah yang dikaitkan dengan baris data ini.</td>
    -+    <td>Kontak mentah hanya memiliki salah satu baris ini.</td>
    -+  </tr>
    -+  <tr>
    -+    <td>{@link android.provider.ContactsContract.CommonDataKinds.Photo}</td>
    -+    <td>Foto utama untuk kontak mentah yang dikaitkan dengan baris data ini.</td>
    -+    <td>Kontak mentah hanya memiliki salah satu baris ini.</td>
    -+  </tr>
    -+  <tr>
    -+    <td>{@link android.provider.ContactsContract.CommonDataKinds.Email}</td>
    -+    <td>Alamat email untuk kontak mentah yang dikaitkan dengan baris data ini.</td>
    -+    <td>Kontak mentah bisa memiliki beberapa alamat email.</td>
    -+  </tr>
    -+  <tr>
    -+    <td>{@link android.provider.ContactsContract.CommonDataKinds.StructuredPostal}</td>
    -+    <td>Alamat pos untuk kontak mentah yang dikaitkan dengan baris data ini.</td>
    -+    <td>Kontak mentah bisa memiliki beberapa alamat email.</td>
    -+  </tr>
    -+  <tr>
    -+    <td>{@link android.provider.ContactsContract.CommonDataKinds.GroupMembership}</td>
    -+    <td>Identifier yang menautkan kontak mentah ke salah satu grup dalam Penyedia Kontak.</td>
    -+    <td>
    -+        Grup adalah fitur opsional pada tipe akun dan nama akun. Grup dijelaskan
    -+       lebih detail di bagian <a href="#Groups">Grup kontak</a>.
    -+    </td>
    -+  </tr>
    -+</table>
    -+<h3 id="ContactBasics">Kontak</h3>
    -+<p>
    -+    Penyedia Kontak mengombinasikan baris kontak mentah di semua tipe akun dan nama akun
    -+    untuk membentuk <strong>kontak</strong>. Hal ini memudahkan menampilkan dan memodifikasi semua data
    -+    yang telah dikumpulkan pengguna untuk seseorang. Penyedia Kontak mengelola pembuatan baris
    -+    kontak baru, dan agregasi kontak mentah dengan baris kontak yang ada. Baik aplikasi maupun adaptor sinkronisasi
    -+    tidak boleh menambahkan kontak dan sebagian kolom dalam baris kontak yang bersifat hanya baca.
    -+</p>
    -+<p class="note">
    -+    <strong>Catatan:</strong> Jika Anda mencoba menambahkan kontak ke Penyedia Kontak dengan
    -+    {@link android.content.ContentResolver#insert(Uri,ContentValues) insert()}, Anda akan mendapatkan
    -+    eksepsi {@link java.lang.UnsupportedOperationException}. Jika Anda mencoba memperbarui sebuah kolom
    -+   yang tercantum sebagai "hanya-baca", pembaruan akan diabaikan.
    -+</p>
    -+<p>
    -+    Penyedia Kontak membuat kontak baru untuk merespons penambahan kontak mentah baru
    -+    yang tidak cocok dengan kontak yang ada. Penyedia juga melakukan ini jika data
    -+    kontak mentah yang ada berubah sehingga tidak lagi cocok dengan kontak yang
    -+    sebelumnya dihubungkan. Jika aplikasi atau adaptor sinkronisasi membuat kontak mentah baru yang
    -+    <em>memang</em> cocok dengan kontak yang ada, kontak mentah baru akan diagregasikan ke kontak
    -+    yang ada.
    -+</p>
    -+<p>
    -+    Penyedia Kontak menautkan baris kontak ke baris kontak mentahnya dengan kolom
    -+    <code>_ID</code> dari baris kontak dalam tabel {@link android.provider.ContactsContract.Contacts Contacts}.
    -+ Kolom <code>CONTACT_ID</code> tabel kontak mentah
    -+    {@link android.provider.ContactsContract.RawContacts} berisi nilai <code>_ID</code> untuk
    -+    baris kontak yang dikaitkan dengan tiap baris kontak mentah.
    -+</p>
    -+<p>
    -+    Tabel {@link android.provider.ContactsContract.Contacts} juga memiliki kolom
    -+    {@code android.provider.ContactsContract.ContactsColumns#LOOKUP_KEY} yang merupakan
    -+    tautan "permanen" ke baris kontak. Karena memelihara kontak
    -+    secara otomatis, Penyedia Kontak bisa mengubah nilai {@code android.provider.BaseColumns#_ID} baris kontak
    -+    untuk merespons agregasi atau sinkronisasi. Sekalipun ini terjadi, URI konten
    -+    {@link android.provider.ContactsContract.Contacts#CONTENT_LOOKUP_URI} yang dikombinasikan dengan
    -+    {@code android.provider.ContactsContract.ContactsColumns#LOOKUP_KEY} kontak akan tetap
    -+    menunjuk ke baris kontak itu, sehingga Anda bisa menggunakan
    -+    {@code android.provider.ContactsContract.ContactsColumns#LOOKUP_KEY}
    -+   untuk memelihara tautan ke kontak "favorit", dan seterusnya. Kolom ini memiliki formatnya sendiri, yang
    -+    tidak terkait dengan format kolom {@code android.provider.BaseColumns#_ID}.
    -+</p>
    -+<p>
    -+    Gambar 3 menampilkan cara ketiga tabel utama terkait satu sama lain.
    -+</p>
    -+<img src="{@docRoot}images/providers/contacts_tables.png" alt="Contacts provider main tables" height="514" id="figure4" />
    -+<p class="img-caption">
    -+  <strong>Gambar 3.</strong> Hubungan tabel Contacts, Raw Contacts, dan Details.
    -+</p>
    -+<h2 id="Sources">Data Dari Adaptor Sinkronisasi</h2>
    -+<p>
    -+    Pengguna memasukkan data kontak secara langsung ke dalam perangkat, namun data juga mengalir masuk ke Penyedia Kontak
    -+    dari layanan web melalui <strong>adaptor sinkronisasi</strong>, yang mengotomatiskan
    -+    transfer data antara perangkat dan layanan. Adaptor sinkronisasi berjalan di latar belakang
    -+    di bawah kontrol sistem, dan memanggil metode {@link android.content.ContentResolver}
    -+   untuk mengelola data.
    -+</p>
    -+<p>
    -+    Di Android, layanan web yang digunakan adaptor sinkronisasi diidentifikasi melalui tipe akun.
    -+    Setiap adaptor sinkronisasi bekerja dengan satu tipe akun, tetapi bisa mendukung beberapa nama akun untuk
    -+    tipe itu. Tipe akun dan nama akun dijelaskan secara singkat di bagian
    -+    <a href="#RawContactsExample">Sumber data kontak mentah</a>. Definisi berikut menyediakan
    -+    detail selengkapnya, dan menjelaskan cara tipe dan nama akun berkaitan dengan adaptor sinkronisasi dan layanan.
    -+</p>
    -+<dl>
    -+    <dt>
    -+        Tipe akun
    -+    </dt>
    -+    <dd>
    -+        Mengidentifikasi layanan tempat pengguna menyimpan data. Sering kali, pengguna harus
    -+        mengautentikasi diri dengan layanan. Misalnya, Google Contacts adalah tipe akun, yang diidentifikasi
    -+        dengan kode <code>google.com</code>. Nilai ini sesuai dengan tipe akun yang digunakan oleh
    -+        {@link android.accounts.AccountManager}.
    -+    </dd>
    -+    <dt>
    -+        Nama akun
    -+    </dt>
    -+    <dd>
    -+        Mengidentifikasi akun atau login tertentu untuk suatu tipe akun. Akun Google Contacts
    -+        sama dengan akun Google, yang memiliki alamat email sebagai nama akun.
    -+        Layanan lain mungkin menggunakan nama pengguna satu-kata atau identitas berupa angka.
    -+    </dd>
    -+</dl>
    -+<p>
    -+    Tipe akun tidak harus unik. Pengguna boleh mengonfigurasi beberapa akun Google Contacts
    -+    dan mengunduh data ke Penyedia Kontak; ini mungkin terjadi jika pengguna memiliki satu set
    -+    kontak pribadi untuk satu nama akun pribadi, dan satu set lagi untuk pekerjaan. Nama akun
    -+    biasanya unik. Bersama-sama, keduanya mengidentifikasi aliran data tertentu antara Penyedia Kontak dan
    -+    layanan eksternal.
    -+</p>
    -+<p>
    -+    Jika Anda ingin mentransfer data layanan ke Penyedia Kontak, Anda perlu menulis
    -+    adaptor sinkronisasi sendiri. Hal ini dijelaskan lebih detail di bagian
    -+    <a href="#SyncAdapters">Adaptor Sinkronisasi Penyedia Kontak</a>.
    -+</p>
    -+<p>
    -+    Gambar 4 menampilkan cara Penyedia Kontak dimasukkan ke dalam aliran data
    -+    tentang orang. Dalam kotak bertanda "sync adapters", setiap adaptor diberi label menurut tipe akunnya.
    -+</p>
    -+<img src="{@docRoot}images/providers/ContactsDataFlow.png" alt="Flow of data about people" height="252" id="figure5" />
    -+<p class="img-caption">
    -+  <strong>Gambar 4.</strong> Aliran data Penyedia Kontak.
    -+</p>
    -+<h2 id="Permissions">Izin yang Diperlukan</h2>
    -+<p>
    -+    Aplikasi yang ingin mengakses Penyedia Kontak harus meminta izin
    -+   berikut:
    -+</p>
    -+<dl>
    -+    <dt>Akses baca ke satu atau beberapa tabel</dt>
    -+    <dd>
    -+        {@link android.Manifest.permission#READ_CONTACTS}, yang ditetapkan dalam
    -+        <code>AndroidManifest.xml</code> dengan elemen
    -+        <code><a href="{@docRoot}guide/topics/manifest/uses-permission-element.html">
    -+        &lt;uses-permission&gt;</a></code> sebagai
    -+        <code>&lt;uses-permission android:name="android.permission.READ_CONTACTS"&gt;</code>.
    -+    </dd>
    -+    <dt>Akses tulis ke satu atau beberapa tabel</dt>
    -+    <dd>
    -+        {@link android.Manifest.permission#WRITE_CONTACTS}, yang ditetapkan dalam
    -+        <code>AndroidManifest.xml</code> dengan elemen
    -+        <code><a href="{@docRoot}guide/topics/manifest/uses-permission-element.html">
    -+        &lt;uses-permission&gt;</a></code> sebagai
    -+        <code>&lt;uses-permission android:name="android.permission.WRITE_CONTACTS"&gt;</code>.
    -+    </dd>
    -+</dl>
    -+<p>
    -+    Izin ini tidak diperluas ke data profil pengguna. Profil pengguna dan izin
    -+   yang diperlukan dibahas di bagian berikut,
    -+    <a href="#UserProfile">Profil Pengguna</a>.
    -+</p>
    -+<p>
    -+    Ingatlah bahwa data kontak pengguna bersifat pribadi dan sensitif. Pengguna mempersoalkan
    -+    privasinya, sehingga tidak ingin aplikasi mengumpulkan data tentang diri atau kontak mereka.
    -+    Jika alasan Anda memerlukan izin untuk mengakses data kontak tidak jelas, pengguna mungkin memberi
    -+    aplikasi Anda peringkat rendah atau langsung menolak menginstalnya.
    -+</p>
    -+<h2 id="UserProfile">Profil Pengguna</h2>
    -+<p>
    -+    Tabel {@link android.provider.ContactsContract.Contacts} berisi satu baris yang berisi
    -+    data profil untuk pengguna perangkat. Data ini menjelaskan data perangkat  <code>user</code> bukannya
    -+    salah satu kontak pengguna. Baris kontak profil ditautkan ke baris
    -+     kontak mentah untuk setiap sistem yang menggunakan profil.
    -+    Setiap baris kontak mentah profil bisa memiliki beberapa baris data. Konstanta untuk mengakses profil
    -+    pengguna tersedia dalam kelas {@link android.provider.ContactsContract.Profile}.
    -+</p>
    -+<p>
    -+    Akses ke profil pengguna memerlukan izin khusus. Selain itu, izin
    -+    {@link android.Manifest.permission#READ_CONTACTS} dan
    -+    {@link android.Manifest.permission#WRITE_CONTACTS} diperlukan untuk membaca dan menulis, akses
    -+    ke profil pengguna memerlukan masing-masing izin {@code android.Manifest.permission#READ_PROFILE} dan
    -+    {@code android.Manifest.permission#WRITE_PROFILE} untuk akses baca dan tulis.
    -+
    -+</p>
    -+<p>
    -+    Ingatlah bahwa Anda harus mempertimbangkan profil pengguna bersifat sensitif. Izin
    -+    {@code android.Manifest.permission#READ_PROFILE} memungkinkan Anda mengakses data yang mengidentifikasi secara pribadi
    -+    pengguna perangkat. Pastikan memberi tahu pengguna alasan
    -+    Anda memerlukan izin akses profil pengguna dalam keterangan aplikasi Anda.
    -+</p>
    -+<p>
    -+    Untuk mengambil baris kontak berisi profil pengguna,
    -+    panggil {@link android.content.ContentResolver#query(Uri,String[], String, String[], String)
    -+    ContentResolver.query()}. Atur URI konten ke
    -+    {@link android.provider.ContactsContract.Profile#CONTENT_URI} dan jangan sediakan
    -+    kriteria pemilihan apa pun. Anda juga bisa menggunakan URI konten ini sebagai URI dasar untuk mengambil kontak
    -+    mentah atau data untuk profil. Misalnya, cuplikan kode ini mengambil data untuk profil:
    -+</p>
    -+<pre>
    -+// Sets the columns to retrieve for the user profile
    -+mProjection = new String[]
    -+    {
    -+        Profile._ID,
    -+        Profile.DISPLAY_NAME_PRIMARY,
    -+        Profile.LOOKUP_KEY,
    -+        Profile.PHOTO_THUMBNAIL_URI
    -+    };
    -+
    -+// Retrieves the profile from the Contacts Provider
    -+mProfileCursor =
    -+        getContentResolver().query(
    -+                Profile.CONTENT_URI,
    -+                mProjection ,
    -+                null,
    -+                null,
    -+                null);
    -+</pre>
    -+<p class="note">
    -+    <strong>Catatan:</strong> Jika Anda mengambil beberapa baris kontak, dan ingin menentukan apakah salah satu baris
    -+    adalah profil pengguna, uji
    -+    kolom {@link android.provider.ContactsContract.ContactsColumns#IS_USER_PROFILE} pada baris tersebut. Kolom ini
    -+    diatur ke "1" jika kontak adalah profil pengguna.
    -+</p>
    -+<h2 id="ContactsProviderMetadata">Metadata Penyedia Kontak</h2>
    -+<p>
    -+    Penyedia Kontak mengelola data yang mencatat status data kontak dalam
    -+    repository. Metadata repository ini disimpan di berbagai tempat, termasuk baris-baris tabel
    -+    Raw Contacts, Data, dan Contacts,
    -+    tabel {@link android.provider.ContactsContract.Settings}, dan
    -+    tabel {@link android.provider.ContactsContract.SyncState}. Tabel berikut menampilkan
    -+    efek setiap potongan metadata ini:
    -+</p>
    -+<p class="table-caption" id="table3">
    -+  <strong>Tabel 3.</strong> Metadata di Penyedia Kontak</p>
    -+<table>
    -+    <tr>
    -+        <th scope="col">Tabel</th>
    -+        <th scope="col">Kolom</th>
    -+        <th scope="col">Nilai</th>
    -+        <th scope="col">Arti</th>
    -+    </tr>
    -+    <tr>
    -+        <td rowspan="2">{@link android.provider.ContactsContract.RawContacts}</td>
    -+        <td rowspan="2">{@link android.provider.ContactsContract.SyncColumns#DIRTY}</td>
    -+        <td>"0" - tidak berubah sejak sinkronisasi terakhir.</td>
    -+        <td rowspan="2">
    -+            Menandai kontak mentah yang berubah pada perangkat dan telah disinkronkan kembali ke
    -+           server. Nilai diatur secara otomatis oleh Penyedia Kontak bila aplikasi
    -+            Android memperbarui baris.
    -+            <p>
    -+                Adaptor sinkronisasi yang memodifikasi kontak mentah atau tabel data harus selalu menambahkan
    -+                string {@link android.provider.ContactsContract#CALLER_IS_SYNCADAPTER} ke
    -+                URI konten yang digunakannya. Ini mencegah penyedia menandai baris sebagai kotor.
    -+                Sebaliknya, modifikasi oleh adaptor sinkronisasi tampak seperti modifikasi lokal dan
    -+                dikirim ke server, meskipun server adalah sumber modifikasi.
    -+            </p>
    -+        </td>
    -+    </tr>
    -+    <tr>
    -+            <td>"1" - berubah sejak sinkronisasi terakhir, harus disinkronkan kembali ke server.</td>
    -+    </tr>
    -+    <tr>
    -+        <td>{@link android.provider.ContactsContract.RawContacts}</td>
    -+        <td>{@link android.provider.ContactsContract.SyncColumns#VERSION}</td>
    -+        <td>Nomor versi baris ini.</td>
    -+        <td>
    -+            Penyedia Kontak menambahkan nilai ini secara otomatis bila baris atau
    -+            data terkaitnya berubah.
    -+        </td>
    -+    </tr>
    -+    <tr>
    -+        <td>{@link android.provider.ContactsContract.Data}</td>
    -+        <td>{@link android.provider.ContactsContract.DataColumns#DATA_VERSION}</td>
    -+        <td>Nomor versi baris ini.</td>
    -+        <td>
    -+            Penyedia Kontak menambahkan nilai ini secara otomatis bila baris data
    -+            berubah.
    -+        </td>
    -+    </tr>
    -+    <tr>
    -+        <td>{@link android.provider.ContactsContract.RawContacts}</td>
    -+        <td>{@link android.provider.ContactsContract.SyncColumns#SOURCE_ID}</td>
    -+        <td>
    -+            Nilai string yang mengidentifikasi secara unik kontak mentah ini ke akun tempat
    -+            kontak dibuat.
    -+        </td>
    -+        <td>
    -+            Bila adaptor sinkronisasi membuat kontak mentah baru, kolom ini harus diatur ke
    -+            ID unik server untuk kontak mentah itu. Bila aplikasi Android membuat kontak mentah
    -+            baru, aplikasi harus membiarkan kolom ini kosong. Ini mengisyaratkan pada adaptor
    -+            sinkronisasi bahwa adaptor harus membuat kontak mentah baru pada server, dan mendapatkan
    -+            nilai untuk {@link android.provider.ContactsContract.SyncColumns#SOURCE_ID}.
    -+            <p>
    -+                Khususnya, id sumber harus <strong>unik</strong> untuk setiap tipe
    -+                akun dan stabil di semua sinkronisasi:
    -+            </p>
    -+                <ul>
    -+                    <li>
    -+                        Unik: Setiap kontak mentah untuk satu akun harus memiliki id sumbernya sendiri. Jika Anda
    -+                        tidak memberlakukan aturan ini, masalah akan timbul dalam aplikasi kontak.
    -+                        Perhatikan bahwa dua kontak mentah untuk tipe akun yang <em>sama</em> boleh memiliki
    -+                       id sumber yang sama. Misalnya, kontak mentah "Thomas Higginson" untuk
    -+                        akun {@code emily.dickinson@gmail.com} boleh memiliki id sumber
    -+                        yang sama dengan kontak mentah "Thomas Higginson" untuk akun
    -+                        {@code emilyd@gmail.com}.
    -+                    </li>
    -+                    <li>
    -+                        Stabil: Id sumber adalah bagian tetap dari data layanan online untuk
    -+                        kontak mentah. Misalnya, jika pengguna membersihkan Contacts Storage dari
    -+                        pengaturan aplikasi dan menyinkronkan ulang, kontak mentah yang dipulihkan akan memiliki id sumber
    -+                        yang sama dengan sebelumnya. Jika Anda tidak memberlakukan hal ini, pintasan akan berhenti
    -+                        berfungsi.
    -+                    </li>
    -+                </ul>
    -+        </td>
    -+    </tr>
    -+    <tr>
    -+        <td rowspan="2">{@link android.provider.ContactsContract.Groups}</td>
    -+        <td rowspan="2">{@link android.provider.ContactsContract.GroupsColumns#GROUP_VISIBLE}</td>
    -+        <td>"0" - Kontak dalam grup ini tidak boleh terlihat dalam UI aplikasi Android.</td>
    -+        <td>
    -+            Kolom ini digunakan untuk kompatibilitas dengan server yang memungkinkan pengguna menyembunyikan kontak dalam
    -+            grup tertentu.
    -+        </td>
    -+    </tr>
    -+    <tr>
    -+        <td>"1" - Kontak dalam grup ini boleh terlihat dalam UI aplikasi.</td>
    -+    </tr>
    -+    <tr>
    -+        <td rowspan="2">{@link android.provider.ContactsContract.Settings}</td>
    -+        <td rowspan="2">
    -+            {@link android.provider.ContactsContract.SettingsColumns#UNGROUPED_VISIBLE}</td>
    -+        <td>
    -+            "0" - Untuk akun dan tipe akun ini, kontak yang bukan milik grup
    -+            tidak akan terlihat pada UI aplikasi Android.
    -+        </td>
    -+        <td rowspan="2">
    -+            Secara default, kontak tidak terlihat jika tidak satu pun kontak mentahnya milik grup
    -+            (Keanggotaan grup untuk kontak mentah ditandai oleh satu atau beberapa baris
    -+            {@link android.provider.ContactsContract.CommonDataKinds.GroupMembership}
    -+            dalam tabel {@link android.provider.ContactsContract.Data}).
    -+            Dengan mengatur flag ini dalam baris tabel {@link android.provider.ContactsContract.Settings}
    -+            untuk tipe akun dan akun, Anda bisa memaksakan kontak tanpa grup agar terlihat.
    -+            Satu kegunaan flag ini adalah menampilkan kontak dari server yang tidak menggunakan grup.
    -+        </td>
    -+    </tr>
    -+    <tr>
    -+        <td>
    -+            "1" - Untuk akun dan tipe akun ini, kontak yang bukan milik grup
    -+            akan terlihat pada UI aplikasi.
    -+        </td>
    -+
    -+    </tr>
    -+    <tr>
    -+        <td>{@link android.provider.ContactsContract.SyncState}</td>
    -+        <td>(semua)</td>
    -+        <td>
    -+            Gunakan tabel ini untuk menyimpan metadata bagi adaptor sinkronisasi Anda.
    -+        </td>
    -+        <td>
    -+            Dengan tabel ini, Anda bisa menyimpan status sinkronisasi dan data lain yang terkait dengan sinkronisasi secara persisten pada
    -+            perangkat.
    -+        </td>
    -+    </tr>
    -+</table>
    -+<h2 id="Access">Akses Penyedia Kontak</h2>
    -+<p>
    -+    Bagian ini menjelaskan panduan untuk mengakses data dari Penyedia Kontak, yang berfokus pada
    -+    hal-hal berikut:
    -+</p>
    -+<ul>
    -+    <li>
    -+        Query entitas.
    -+    </li>
    -+    <li>
    -+        Modifikasi batch.
    -+    </li>
    -+    <li>
    -+        Pengambilan dan modifikasi dengan intent.
    -+    </li>
    -+    <li>
    -+        Integritas data.
    -+    </li>
    -+</ul>
    -+<p>
    -+    Membuat modifikasi dari adaptor sinkronisasi juga secara lebih detail di bagian
    -+    <a href="#SyncAdapters">Adaptor Sinkronisasi Penyedia Kontak</a>.
    -+</p>
    -+<h3 id="Entities">Membuat query entitas</h3>
    -+<p>
    -+    Karena disusun secara hierarki, tabel-tabel Penyedia Kontak sering kali berguna untuk
    -+    mengambil baris dan semua baris "anak" yang ditautkan dengannya. Misalnya, untuk menampilkan
    -+    semua informasi untuk satu orang, Anda mungkin ingin mengambil semua
    -+    baris {@link android.provider.ContactsContract.RawContacts} untuk satu baris
    -+    {@link android.provider.ContactsContract.Contacts}, atau semua
    -+    baris {@link android.provider.ContactsContract.CommonDataKinds.Email} untuk satu baris
    -+    {@link android.provider.ContactsContract.RawContacts}. Untuk memudahkan hal ini, Penyedia Kontak
    -+    menawarkan konstruksi <strong>entitas</strong>, yang berfungsi seperti gabungan database di antara
    -+    tabel-tabel.
    -+</p>
    -+<p>
    -+    Entitas adalah seperti tabel yang terdiri atas kolom-kolom terpilih dari tabel induk dan tabel anaknya.
    -+    Bila membuat query sebuah entitas, Anda memberikan proyeksi dan kriteria pencarian berdasarkan kolom-kolom
    -+    yang tersedia dari entitas itu. Hasilnya adalah sebuah {@link android.database.Cursor} yang
    -+    berisi satu baris untuk setiap baris tabel anak yang diambil. Misalnya, jika Anda membuat query
    -+    {@link android.provider.ContactsContract.Contacts.Entity} untuk satu nama kontak
    -+    dan semua baris {@link android.provider.ContactsContract.CommonDataKinds.Email} untuk semua
    -+    kontak mentah bagi nama itu, Anda akan mendapatkan kembali {@link android.database.Cursor} berisi satu baris
    -+    untuk setiap baris {@link android.provider.ContactsContract.CommonDataKinds.Email}.
    -+</p>
    -+<p>
    -+    Entitas menyederhanakan query. Dengan entitas, Anda bisa mengambil semua data kontak untuk satu
    -+    kontak atau kontak mentah sekaligus, sebagai ganti harus membuat query tabel induk terlebih dahulu untuk mendapatkan
    -+    ID, lalu harus membuat query tabel anak dengan ID itu. Selain itu, Penyedia Kontak akan memproses
    -+    query terhadap entitas dalam satu transaksi, yang memastikan bahwa data yang diambil
    -+    konsisten secara internal.
    -+</p>
    -+<p class="note">
    -+    <strong>Catatan:</strong> Entitas biasanya tidak berisi semua kolom tabel induk dan
    -+    anak. Jika Anda mencoba menggunakan nama kolom yang tidak ada dalam daftar konstanta
    -+    nama kolom untuk entitas, Anda akan mendapatkan {@link java.lang.Exception}.
    -+</p>
    -+<p>
    -+    Cuplikan berikut menampilkan cara mengambil semua baris kontak mentah untuk sebuah kontak. Cuplikan ini
    -+    adalah bagian dari aplikasi lebih besar yang memiliki dua aktivitas, "main" dan "detail". Aktivitas utama
    -+    menampilkan daftar baris kontak; bila pengguna memilih satu baris, aktivitas akan mengirimkan ID-nya ke aktivitas
    -+    detail. Aktivitas detail menggunakan{@link android.provider.ContactsContract.Contacts.Entity}
    -+    untuk menampilkan semua baris data dari semua kontak mentah yang dikaitkan dengan kontak
    -+    terpilih.
    -+</p>
    -+<p>
    -+    Cuplikan ini diambil dari aktivitas "detail":
    -+</p>
    -+<pre>
    -+...
    -+    /*
    -+     * Appends the entity path to the URI. In the case of the Contacts Provider, the
    -+     * expected URI is content://com.google.contacts/#/entity (# is the ID value).
    -+     */
    -+    mContactUri = Uri.withAppendedPath(
    -+            mContactUri,
    -+            ContactsContract.Contacts.Entity.CONTENT_DIRECTORY);
    -+
    -+    // Initializes the loader identified by LOADER_ID.
    -+    getLoaderManager().initLoader(
    -+            LOADER_ID,  // The identifier of the loader to initialize
    -+            null,       // Arguments for the loader (in this case, none)
    -+            this);      // The context of the activity
    -+
    -+    // Creates a new cursor adapter to attach to the list view
    -+    mCursorAdapter = new SimpleCursorAdapter(
    -+            this,                        // the context of the activity
    -+            R.layout.detail_list_item,   // the view item containing the detail widgets
    -+            mCursor,                     // the backing cursor
    -+            mFromColumns,                // the columns in the cursor that provide the data
    -+            mToViews,                    // the views in the view item that display the data
    -+            0);                          // flags
    -+
    -+    // Sets the ListView's backing adapter.
    -+    mRawContactList.setAdapter(mCursorAdapter);
    -+...
    -+&#64;Override
    -+public Loader&lt;Cursor&gt; onCreateLoader(int id, Bundle args) {
    -+
    -+    /*
    -+     * Sets the columns to retrieve.
    -+     * RAW_CONTACT_ID is included to identify the raw contact associated with the data row.
    -+     * DATA1 contains the first column in the data row (usually the most important one).
    -+     * MIMETYPE indicates the type of data in the data row.
    -+     */
    -+    String[] projection =
    -+        {
    -+            ContactsContract.Contacts.Entity.RAW_CONTACT_ID,
    -+            ContactsContract.Contacts.Entity.DATA1,
    -+            ContactsContract.Contacts.Entity.MIMETYPE
    -+        };
    -+
    -+    /*
    -+     * Sorts the retrieved cursor by raw contact id, to keep all data rows for a single raw
    -+     * contact collated together.
    -+     */
    -+    String sortOrder =
    -+            ContactsContract.Contacts.Entity.RAW_CONTACT_ID +
    -+            " ASC";
    -+
    -+    /*
    -+     * Returns a new CursorLoader. The arguments are similar to
    -+     * ContentResolver.query(), except for the Context argument, which supplies the location of
    -+     * the ContentResolver to use.
    -+     */
    -+    return new CursorLoader(
    -+            getApplicationContext(),  // The activity's context
    -+            mContactUri,              // The entity content URI for a single contact
    -+            projection,               // The columns to retrieve
    -+            null,                     // Retrieve all the raw contacts and their data rows.
    -+            null,                     //
    -+            sortOrder);               // Sort by the raw contact ID.
    -+}
    -+</pre>
    -+<p>
    -+    Bila selesai dimuat, {@link android.app.LoaderManager} akan memicu callback ke
    -+    {@link android.app.LoaderManager.LoaderCallbacks#onLoadFinished(Loader, D)
    -+    onLoadFinished()}. Salah satu argumen masuk pada metode ini adalah
    -+    {@link android.database.Cursor} bersama hasil query. Dalam aplikasi Anda sendiri, Anda bisa memperoleh
    -+    data dari {@link android.database.Cursor} ini untuk menampilkannya atau menggunakannya lebih jauh.
    -+</p>
    -+<h3 id="Transactions">Modifikasi batch</h3>
    -+<p>
    -+    Bila memungkinkan, Anda harus menyisipkan, memperbarui, dan menghapus data dalam Penyedia Kontak dengan
    -+    "batch mode", dengan membuat {@link java.util.ArrayList} dari
    -+    objek-objek {@link android.content.ContentProviderOperation} dan memanggil
    -+    {@link android.content.ContentResolver#applyBatch(String, ArrayList) applyBatch()}. Karena
    -+    Penyedia Kontak menjalankan semua operasi dalam satu
    -+    {@link android.content.ContentResolver#applyBatch(String, ArrayList) applyBatch()} transaksi,
    -+    modifikasi Anda tidak akan pernah meninggalkan repository kontak dalam keadaan
    -+    tidak konsisten. Modifikasi batch juga memudahkan penyisipan kontak mentah dan data detailnya
    -+    sekaligus.
    -+</p>
    -+<p class="note">
    -+    <strong>Catatan:</strong> Untuk memodifikasi <em>satu</em> kontak mentah, pertimbangkan untuk mengirim intent ke
    -+    aplikasi kontak perangkat daripada menangani modifikasi dalam aplikasi Anda.
    -+    Cara ini dijelaskan lebih detail di bagian
    -+    <a href="#Intents">Pengambilan dan modifikasi dengan intent</a>.
    -+</p>
    -+<h4>Yield point</h4>
    -+<p>
    -+    Modifikasi batch yang berisi operasi dalam jumlah besar bisa memblokir proses lain,
    -+    yang mengakibatkan pengalaman pengguna yang buruk secara keseluruhan. Untuk menata semua modifikasi yang ingin Anda
    -+    jalankan dalam sesedikit mungkin daftar terpisah, sambil mencegah modifikasi dari
    -+    memblokir sistem, Anda harus menetapkan <strong>yield point</strong> untuk satu atau beberapa operasi.
    -+    Yield point (titik hasil) adalah objek {@link android.content.ContentProviderOperation} yang mengatur
    -+    nilai {@link android.content.ContentProviderOperation#isYieldAllowed()}-nya ke
    -+    <code>true</code>. Bila menemui yield point, Penyedia Kontak akan menghentikan pekerjaannya untuk
    -+    membiarkan proses lain berjalan dan menutup transaksi saat ini. Bila dimulai lagi, penyedia akan
    -+    melanjutkan dengan operasi berikutnya di {@link java.util.ArrayList} dan memulai transaksi
    -+    baru.
    -+</p>
    -+<p>
    -+    Yield point memang menyebabkan lebih dari satu transaksi per panggilan ke
    -+    {@link android.content.ContentResolver#applyBatch(String, ArrayList) applyBatch()}. Karena
    -+    itu, Anda harus menetapkan yield point pada operasi terakhir untuk satu set baris terkait.
    -+    Misalnya, Anda harus menetapkan yield point pada operasi terakhir di satu set yang menambahkan
    -+    baris kontak mentah dan baris data terkait, atau operasi terakhir untuk satu set baris yang terkait
    -+    dengan satu kontak.
    -+</p>
    -+<p>
    -+    Yield point juga merupakan unit operasi atomis. Semua akses antara dua yield point bisa
    -+    saja berhasil atau gagal sebagai satu unit. Jika Anda mengatur yield point, operasi
    -+    atomis terkecil adalah seluruh batch operasi. Jika menggunakan yield point, Anda akan mencegah
    -+    operasi menurunkan kinerja sistem, sekaligus memastikan subset
    -+    operasi bersifat atomis.
    -+</p>
    -+<h4>Acuan balik modifikasi</h4>
    -+<p>
    -+    Saat Anda menyisipkan baris kontak mentah baru dan baris data terkaitnya sebagai satu set
    -+    objek {@link android.content.ContentProviderOperation}, Anda harus menautkan baris data ke
    -+    baris kontak mentah dengan memasukkan nilai
    -+    {@code android.provider.BaseColumns#_ID} kontak mentah sebagai
    -+    nilai {@link android.provider.ContactsContract.DataColumns#RAW_CONTACT_ID}. Akan tetapi, nilai
    -+    ini tidak tersedia saat Anda membuat {@link android.content.ContentProviderOperation}
    -+    untuk baris data, karena Anda belum menerapkan
    -+    {@link android.content.ContentProviderOperation} untuk baris kontak mentah. Solusinya,
    -+     kelas {@link android.content.ContentProviderOperation.Builder} memiliki metode
    -+    {@link android.content.ContentProviderOperation.Builder#withValueBackReference(String, int) withValueBackReference()}.
    -+    Metode ini memungkinkan Anda menyisipkan atau mengubah kolom dengan
    -+    hasil dari operasi sebelumnya.
    -+</p>
    -+<p>
    -+    Metode {@link android.content.ContentProviderOperation.Builder#withValueBackReference(String, int) withValueBackReference()}
    -+    memiliki dua argumen:
    -+</p>
    -+    <dl>
    -+        <dt>
    -+            <code>key</code>
    -+        </dt>
    -+        <dd>
    -+            Kunci dari pasangan kunci-nilai. Nilai argumen ini harus berupa nama kolom
    -+            dalam tabel yang Anda modifikasi.
    -+        </dd>
    -+        <dt>
    -+            <code>previousResult</code>
    -+        </dt>
    -+        <dd>
    -+            Indeks berbasis 0 dari nilai pada larik
    -+            objek {@link android.content.ContentProviderResult} dari
    -+            {@link android.content.ContentResolver#applyBatch(String, ArrayList) applyBatch()}. Saat
    -+            operasi batch diterapkan, hasil tiap operasi akan disimpan dalam
    -+            larik hasil antara. Nilai <code>previousResult</code> adalah indeks
    -+            dari salah satu hasil ini, yang diambil dan disimpan bersama nilai <code>key</code>.
    -+ Cara ini memungkinkan Anda menyisipkan record kontak mentah baru dan mendapatkan kembali nilai
    -+            {@code android.provider.BaseColumns#_ID}-nya, lalu membuat "acuan balik" ke
    -+            nilai itu saat Anda menambahkan baris {@link android.provider.ContactsContract.Data}.
    -+            <p>
    -+                Seluruh larik hasil dibuat saat Anda memanggil
    -+                {@link android.content.ContentResolver#applyBatch(String, ArrayList) applyBatch()} untuk pertama kali,
    -+                dengan ukuran setara dengan ukuran {@link java.util.ArrayList} dari
    -+                objek {@link android.content.ContentProviderOperation} yang Anda sediakan. Akan tetapi, semua
    -+                elemen dalam larik hasil diatur ke <code>null</code>, dan jika Anda mencoba
    -+                melakukan acuan balik ke hasil untuk operasi yang belum diterapkan,
    -+{@link android.content.ContentProviderOperation.Builder#withValueBackReference(String, int) withValueBackReference()}
    -+                akan mengeluarkan {@link java.lang.Exception}.
    -+
    -+            </p>
    -+        </dd>
    -+    </dl>
    -+<p>
    -+    Cuplikan kode berikut menampilkan cara menyisipkan kontak mentah baru dan data secara batch. Cuplikan kode ini
    -+    menyertakan kode yang menetapkan yield point dan menggunakan acuan balik. Cuplikan kode ini adalah
    -+    versi perluasan dari metode<code>createContacEntry()</code>, yang merupakan bagian dari kelas
    -+    <code>ContactAdder</code> dalam
    -+    aplikasi contoh <code><a href="{@docRoot}resources/samples/ContactManager/index.html">
    -+    Contact Manager</a></code>.
    -+</p>
    -+<p>
    -+    Cuplikan pertama mengambil data kontak dari UI. Pada saat ini, pengguna sudah
    -+    memilih akun tempat kontak mentah baru harus ditambahkan.
    -+</p>
    -+<pre>
    -+// Creates a contact entry from the current UI values, using the currently-selected account.
    -+protected void createContactEntry() {
    -+    /*
    -+     * Gets values from the UI
    -+     */
    -+    String name = mContactNameEditText.getText().toString();
    -+    String phone = mContactPhoneEditText.getText().toString();
    -+    String email = mContactEmailEditText.getText().toString();
    -+
    -+    int phoneType = mContactPhoneTypes.get(
    -+            mContactPhoneTypeSpinner.getSelectedItemPosition());
    -+
    -+    int emailType = mContactEmailTypes.get(
    -+            mContactEmailTypeSpinner.getSelectedItemPosition());
    -+</pre>
    -+<p>
    -+    Cuplikan berikutnya membuat operasi untuk menyisipkan baris kontak mentah ke dalam
    -+    tabel {@link android.provider.ContactsContract.RawContacts}:
    -+</p>
    -+<pre>
    -+    /*
    -+     * Prepares the batch operation for inserting a new raw contact and its data. Even if
    -+     * the Contacts Provider does not have any data for this person, you can't add a Contact,
    -+     * only a raw contact. The Contacts Provider will then add a Contact automatically.
    -+     */
    -+
    -+     // Creates a new array of ContentProviderOperation objects.
    -+    ArrayList&lt;ContentProviderOperation&gt; ops =
    -+            new ArrayList&lt;ContentProviderOperation&gt;();
    -+
    -+    /*
    -+     * Creates a new raw contact with its account type (server type) and account name
    -+     * (user's account). Remember that the display name is not stored in this row, but in a
    -+     * StructuredName data row. No other data is required.
    -+     */
    -+    ContentProviderOperation.Builder op =
    -+            ContentProviderOperation.newInsert(ContactsContract.RawContacts.CONTENT_URI)
    -+            .withValue(ContactsContract.RawContacts.ACCOUNT_TYPE, mSelectedAccount.getType())
    -+            .withValue(ContactsContract.RawContacts.ACCOUNT_NAME, mSelectedAccount.getName());
    -+
    -+    // Builds the operation and adds it to the array of operations
    -+    ops.add(op.build());
    -+</pre>
    -+<p>
    -+    Berikutnya, kode akan membuat baris data untuk baris-baris nama tampilan, telepon, dan email.
    -+</p>
    -+<p>
    -+    Setiap objek pembangun operasi menggunakan
    -+    {@link android.content.ContentProviderOperation.Builder#withValueBackReference(String, int) withValueBackReference()}
    -+    untuk mendapatkan
    -+    {@link android.provider.ContactsContract.DataColumns#RAW_CONTACT_ID}. Acuan menunjuk
    -+    balik ke objek {@link android.content.ContentProviderResult} dari operasi pertama,
    -+    yang menambahkan baris kontak mentah dan mengembalikan nilai {@code android.provider.BaseColumns#_ID}
    -+    barunya. Hasilnya, setiap data ditautkan secara otomatis oleh
    -+    {@link android.provider.ContactsContract.DataColumns#RAW_CONTACT_ID}-nya
    -+    ke baris {@link android.provider.ContactsContract.RawContacts} baru yang memilikinya.
    -+</p>
    -+<p>
    -+    Objek {@link android.content.ContentProviderOperation.Builder} yang menambahkan baris email
    -+    diberi flag {@link android.content.ContentProviderOperation.Builder#withYieldAllowed(boolean)
    -+    withYieldAllowed()}, yang mengatur yield point:
    -+</p>
    -+<pre>
    -+    // Creates the display name for the new raw contact, as a StructuredName data row.
    -+    op =
    -+            ContentProviderOperation.newInsert(ContactsContract.Data.CONTENT_URI)
    -+            /*
    -+             * withValueBackReference sets the value of the first argument to the value of
    -+             * the ContentProviderResult indexed by the second argument. In this particular
    -+             * call, the raw contact ID column of the StructuredName data row is set to the
    -+             * value of the result returned by the first operation, which is the one that
    -+             * actually adds the raw contact row.
    -+             */
    -+            .withValueBackReference(ContactsContract.Data.RAW_CONTACT_ID, 0)
    -+
    -+            // Sets the data row's MIME type to StructuredName
    -+            .withValue(ContactsContract.Data.MIMETYPE,
    -+                    ContactsContract.CommonDataKinds.StructuredName.CONTENT_ITEM_TYPE)
    -+
    -+            // Sets the data row's display name to the name in the UI.
    -+            .withValue(ContactsContract.CommonDataKinds.StructuredName.DISPLAY_NAME, name);
    -+
    -+    // Builds the operation and adds it to the array of operations
    -+    ops.add(op.build());
    -+
    -+    // Inserts the specified phone number and type as a Phone data row
    -+    op =
    -+            ContentProviderOperation.newInsert(ContactsContract.Data.CONTENT_URI)
    -+            /*
    -+             * Sets the value of the raw contact id column to the new raw contact ID returned
    -+             * by the first operation in the batch.
    -+             */
    -+            .withValueBackReference(ContactsContract.Data.RAW_CONTACT_ID, 0)
    -+
    -+            // Sets the data row's MIME type to Phone
    -+            .withValue(ContactsContract.Data.MIMETYPE,
    -+                    ContactsContract.CommonDataKinds.Phone.CONTENT_ITEM_TYPE)
    -+
    -+            // Sets the phone number and type
    -+            .withValue(ContactsContract.CommonDataKinds.Phone.NUMBER, phone)
    -+            .withValue(ContactsContract.CommonDataKinds.Phone.TYPE, phoneType);
    -+
    -+    // Builds the operation and adds it to the array of operations
    -+    ops.add(op.build());
    -+
    -+    // Inserts the specified email and type as a Phone data row
    -+    op =
    -+            ContentProviderOperation.newInsert(ContactsContract.Data.CONTENT_URI)
    -+            /*
    -+             * Sets the value of the raw contact id column to the new raw contact ID returned
    -+             * by the first operation in the batch.
    -+             */
    -+            .withValueBackReference(ContactsContract.Data.RAW_CONTACT_ID, 0)
    -+
    -+            // Sets the data row's MIME type to Email
    -+            .withValue(ContactsContract.Data.MIMETYPE,
    -+                    ContactsContract.CommonDataKinds.Email.CONTENT_ITEM_TYPE)
    -+
    -+            // Sets the email address and type
    -+            .withValue(ContactsContract.CommonDataKinds.Email.ADDRESS, email)
    -+            .withValue(ContactsContract.CommonDataKinds.Email.TYPE, emailType);
    -+
    -+    /*
    -+     * Demonstrates a yield point. At the end of this insert, the batch operation's thread
    -+     * will yield priority to other threads. Use after every set of operations that affect a
    -+     * single contact, to avoid degrading performance.
    -+     */
    -+    op.withYieldAllowed(true);
    -+
    -+    // Builds the operation and adds it to the array of operations
    -+    ops.add(op.build());
    -+</pre>
    -+<p>
    -+    Cuplikan terakhir menampilkan panggilan ke
    -+    {@link android.content.ContentResolver#applyBatch(String, ArrayList) applyBatch()} yang
    -+    menyisipkan baris-baris kontak mentah dan data baru.
    -+</p>
    -+<pre>
    -+    // Ask the Contacts Provider to create a new contact
    -+    Log.d(TAG,"Selected account: " + mSelectedAccount.getName() + " (" +
    -+            mSelectedAccount.getType() + ")");
    -+    Log.d(TAG,"Creating contact: " + name);
    -+
    -+    /*
    -+     * Applies the array of ContentProviderOperation objects in batch. The results are
    -+     * discarded.
    -+     */
    -+    try {
    -+
    -+            getContentResolver().applyBatch(ContactsContract.AUTHORITY, ops);
    -+    } catch (Exception e) {
    -+
    -+            // Display a warning
    -+            Context ctx = getApplicationContext();
    -+
    -+            CharSequence txt = getString(R.string.contactCreationFailure);
    -+            int duration = Toast.LENGTH_SHORT;
    -+            Toast toast = Toast.makeText(ctx, txt, duration);
    -+            toast.show();
    -+
    -+            // Log exception
    -+            Log.e(TAG, "Exception encountered while inserting contact: " + e);
    -+    }
    -+}
    -+</pre>
    -+<p>
    -+    Operasi batch juga memungkinkan Anda menerapkan <strong>kontrol konkurensi optimistis</strong>,
    -+    sebuah metode yang menerapkan transaksi modifikasi tanpa harus mengunci repository yang mendasari.
    -+    Untuk menggunakan metode ini, terapkan transaksi dan periksa modifikasi lain yang
    -+    mungkin telah dibuat bersamaan. Jika ternyata modifikasi tidak konsisten, Anda
    -+    mengembalikan transaksi ke kondisi semula dan mencobanya kembali.
    -+</p>
    -+<p>
    -+    Kontrol konkurensi optimistis berguna untuk perangkat seluler, apabila hanya ada satu pengguna setiap
    -+   kalinya, dan akses simultan ke repository data jarang terjadi. Karena penguncian tidak digunakan,
    -+    tidak ada waktu yang terbuang untuk memasang kunci atau menunggu transaksi lain untuk melepas kunci.
    -+</p>
    -+<p>
    -+    Untuk menggunakan kontrol konkurensi optimistis saat memperbarui satu baris
    -+    {@link android.provider.ContactsContract.RawContacts}, ikuti langkah-langkah ini:
    -+</p>
    -+<ol>
    -+    <li>
    -+        Ambil kolom {@link android.provider.ContactsContract.SyncColumns#VERSION}
    -+        kontak mentah bersama data lain yang Anda ambil.
    -+    </li>
    -+    <li>
    -+        Buat sebuah objek {@link android.content.ContentProviderOperation.Builder} yang cocok untuk
    -+        memberlakukan batasan, dengan menggunakan metode
    -+        {@link android.content.ContentProviderOperation#newAssertQuery(Uri)}. Untuk URI konten,
    -+        gunakan {@link android.provider.ContactsContract.RawContacts#CONTENT_URI
    -+        RawContacts.CONTENT_URI}
    -+        dengan {@code android.provider.BaseColumns#_ID} kontak mentah yang ditambahkan padanya.
    -+    </li>
    -+    <li>
    -+        Untuk objek {@link android.content.ContentProviderOperation.Builder}, panggil
    -+        {@link android.content.ContentProviderOperation.Builder#withValue(String, Object)
    -+        withValue()} untuk membandingkan kolom {@link android.provider.ContactsContract.SyncColumns#VERSION}
    -+        dengan nomor versi yang baru saja Anda ambil.
    -+    </li>
    -+    <li>
    -+        Untuk {@link android.content.ContentProviderOperation.Builder} yang sama, panggil
    -+        {@link android.content.ContentProviderOperation.Builder#withExpectedCount(int)
    -+        withExpectedCount()} untuk memastikan bahwa hanya satu baris yang diuji oleh pernyataan ini.
    -+    </li>
    -+    <li>
    -+        Panggil {@link android.content.ContentProviderOperation.Builder#build()} untuk membuat
    -+        objek {@link android.content.ContentProviderOperation}, kemudian tambahkan objek ini sebagai
    -+        objek pertama di {@link java.util.ArrayList} yang Anda teruskan ke
    -+        {@link android.content.ContentResolver#applyBatch(String, ArrayList) applyBatch()}.
    -+    </li>
    -+    <li>
    -+        Terapkan transaksi batch.
    -+    </li>
    -+</ol>
    -+<p>
    -+    Jika baris kontak mentah diperbarui oleh operasi lain antara waktu Anda membaca baris dan
    -+    waktu Anda mencoba memodifikasinya, "asert" {@link android.content.ContentProviderOperation}
    -+    akan gagal, dan seluruh batch operasi akan dibatalkan. Anda nanti bisa memilih untuk mencoba ulang
    -+    batch atau melakukan tindakan lain.
    -+</p>
    -+<p>
    -+    Cuplikan berikut memperagakan cara membuat "asert"
    -+    {@link android.content.ContentProviderOperation} setelah membuat query satu kontak mentah yang menggunakan
    -+     {@link android.content.CursorLoader}:
    -+</p>
    -+<pre>
    -+/*
    -+ * The application uses CursorLoader to query the raw contacts table. The system calls this method
    -+ * when the load is finished.
    -+ */
    -+public void onLoadFinished(Loader&lt;Cursor&gt; loader, Cursor cursor) {
    -+
    -+    // Gets the raw contact's _ID and VERSION values
    -+    mRawContactID = cursor.getLong(cursor.getColumnIndex(BaseColumns._ID));
    -+    mVersion = cursor.getInt(cursor.getColumnIndex(SyncColumns.VERSION));
    -+}
    -+
    -+...
    -+
    -+// Sets up a Uri for the assert operation
    -+Uri rawContactUri = ContentUris.withAppendedId(RawContacts.CONTENT_URI, mRawContactID);
    -+
    -+// Creates a builder for the assert operation
    -+ContentProviderOperation.Builder assertOp = ContentProviderOperation.netAssertQuery(rawContactUri);
    -+
    -+// Adds the assertions to the assert operation: checks the version and count of rows tested
    -+assertOp.withValue(SyncColumns.VERSION, mVersion);
    -+assertOp.withExpectedCount(1);
    -+
    -+// Creates an ArrayList to hold the ContentProviderOperation objects
    -+ArrayList ops = new ArrayList&lt;ContentProviderOperationg&gt;;
    -+
    -+ops.add(assertOp.build());
    -+
    -+// You would add the rest of your batch operations to "ops" here
    -+
    -+...
    -+
    -+// Applies the batch. If the assert fails, an Exception is thrown
    -+try
    -+    {
    -+        ContentProviderResult[] results =
    -+                getContentResolver().applyBatch(AUTHORITY, ops);
    -+
    -+    } catch (OperationApplicationException e) {
    -+
    -+        // Actions you want to take if the assert operation fails go here
    -+    }
    -+</pre>
    -+<h3 id="Intents">Pengambilan dan modifikasi dengan intent</h3>
    -+<p>
    -+    Mengirimkan intent ke aplikasi kontak perangkat memungkinkan Anda mengakses Penyedia Kontak
    -+    secara tidak langsung. Intent akan memulai UI aplikasi kontak perangkat, tempat pengguna bisa
    -+    melakukan pekerjaan yang terkait dengan kontak. Dengan tipe akses ini, pengguna bisa:
    -+    <ul>
    -+        <li>Memilih kontak dari daftar dan meneruskannya ke aplikasi untuk pekerjaan lebih jauh.</li>
    -+        <li>Mengedit data kontak yang ada.</li>
    -+        <li>Memasukkan kontak mentah baru untuk akun mereka.</li>
    -+        <li>Menghapus kontak atau data kontak.</li>
    -+    </ul>
    -+<p>
    -+    Jika pengguna menyisipkan atau memperbarui data, Anda bisa mengumpulkan data lebih dahulu dan mengirimkannya sebagai
    -+    bagian dari intent.
    -+</p>
    -+<p>
    -+    Bila Anda menggunakan intent untuk mengakses Penyedia Kontak melalui aplikasi kontak perangkat, Anda
    -+    tidak perlu menulis UI atau kode sendiri untuk mengakses penyedia. Anda juga tidak harus
    -+   meminta izin untuk membaca dari atau menulis ke penyedia. Aplikasi kontak perangkat bisa
    -+    mendelegasikan izin membaca untuk kontak kepada Anda, dan karena Anda membuat modifikasi pada
    -+    penyedia melalui aplikasi lain, Anda tidak perlu memiliki izin menulis.
    -+</p>
    -+<p>
    -+    Proses umum pengiriman intent untuk mengakses penyedia dijelaskan secara detail dalam panduan
    -+    <a href="{@docRoot}guide/topics/providers/content-provider-basics.html">
    -+    Dasar-Dasar Penyedia Konten</a> di bagian "Akses data melalui intent". Tindakan,
    -+    tipe MIME, dan nilai data yang Anda gunakan untuk tugas yang tersedia dirangkum dalam Tabel 4, sedangkan
    -+    nilai ekstra yang bisa Anda gunakan bersama
    -+    {@link android.content.Intent#putExtra(String, String) putExtra()} tercantum dalam
    -+    dokumentasi acuan untuk {@link android.provider.ContactsContract.Intents.Insert}:
    -+</p>
    -+<p class="table-caption" id="table4">
    -+  <strong>Tabel 4.</strong> Intent Penyedia Kontak.
    -+</p>
    -+<table style="width:75%">
    -+    <tr>
    -+        <th scope="col" style="width:10%">Tugas</th>
    -+        <th scope="col" style="width:5%">Tindakan</th>
    -+        <th scope="col" style="width:10%">Data</th>
    -+        <th scope="col" style="width:10%">Tipe MIME</th>
    -+        <th scope="col" style="width:25%">Catatan</th>
    -+    </tr>
    -+    <tr>
    -+        <td><strong>Memilih kontak dari daftar</strong></td>
    -+        <td>{@link android.content.Intent#ACTION_PICK}</td>
    -+        <td>
    -+            Salah satu dari:
    -+            <ul>
    -+                <li>
    -+{@link android.provider.ContactsContract.Contacts#CONTENT_URI Contacts.CONTENT_URI},
    -+                    yang menampilkan daftar kontak.
    -+                </li>
    -+                <li>
    -+{@link android.provider.ContactsContract.CommonDataKinds.Phone#CONTENT_URI Phone.CONTENT_URI},
    -+                    yang menampilkan daftar nomor telepon untuk kontak mentah.
    -+                </li>
    -+                <li>
    -+{@link android.provider.ContactsContract.CommonDataKinds.StructuredPostal#CONTENT_URI
    -+StructuredPostal.CONTENT_URI},
    -+                    yang menampilkan daftar alamat pos untuk kontak mentah.
    -+                </li>
    -+                <li>
    -+{@link android.provider.ContactsContract.CommonDataKinds.Email#CONTENT_URI Email.CONTENT_URI},
    -+                    yang menampilkan daftar alamat email untuk kontak baru.
    -+                </li>
    -+            </ul>
    -+        </td>
    -+        <td>
    -+            Tidak digunakan
    -+        </td>
    -+        <td>
    -+            Menampilkan daftar kontak mentah atau daftar data dari kontak mentah, sesuai dengan tipe
    -+            URI konten yang Anda sediakan.
    -+            <p>
    -+                Panggil
    -+         {@link android.app.Activity#startActivityForResult(Intent, int) startActivityForResult()},
    -+                yang menghasilkan URI konten dari baris terpilih. Bentuk URI adalah
    -+                URI konten tabel dengan <code>LOOKUP_ID</code> baris yang ditambahkan padanya.
    -+                Aplikasi kontak perangkat mendelegasikan izin membaca dan menulis untuk URI konten ini
    -+                selama masa pakai aktivitas Anda. Lihat panduan
    -+                <a href="{@docRoot}guide/topics/providers/content-provider-basics.html">
    -+                Dasar-Dasar Penyedia Konten</a> untuk detail selengkapnya.
    -+            </p>
    -+        </td>
    -+    </tr>
    -+    <tr>
    -+        <td><strong>Menyisipkan kontak mentah baru</strong></td>
    -+        <td>{@link android.provider.ContactsContract.Intents.Insert#ACTION Insert.ACTION}</td>
    -+        <td>N/A</td>
    -+        <td>
    -+            {@link android.provider.ContactsContract.RawContacts#CONTENT_TYPE
    -+            RawContacts.CONTENT_TYPE}, tipe MIME untuk satu set kontak mentah.
    -+        </td>
    -+        <td>
    -+            Menampilkan layar <strong>Add Contact</strong> aplikasi kontak perangkat. Nilai
    -+            ekstra yang Anda tambahkan ke intent akan ditampilkan. Jika dikirimkan bersama
    -+        {@link android.app.Activity#startActivityForResult(Intent, int) startActivityForResult()},
    -+            URI konten dari kontak mentah yang baru saja ditambahkan akan dikembalikan ke
    -+            {@link android.app.Activity#onActivityResult(int, int, Intent) onActivityResult()}
    -+           metode callback aktivitas Anda pada argumen {@link android.content.Intent}, di
    -+            bidang "data". Untuk mendapatkan nilainya, panggil {@link android.content.Intent#getData()}.
    -+        </td>
    -+    </tr>
    -+    <tr>
    -+        <td><strong>Mengedit kontak</strong></td>
    -+        <td>{@link android.content.Intent#ACTION_EDIT}</td>
    -+        <td>
    -+            {@link android.provider.ContactsContract.Contacts#CONTENT_LOOKUP_URI} untuk
    -+            kontak. Aktivitas editor memungkinkan pengguna mengedit setiap data yang dikaitkan
    -+            dengan kontak ini.
    -+        </td>
    -+        <td>
    -+            {@link android.provider.ContactsContract.Contacts#CONTENT_ITEM_TYPE
    -+            Contacts.CONTENT_ITEM_TYPE}, kontak tunggal.</td>
    -+        <td>
    -+            Menampilkan layar Edit Contact dalam aplikasi kontak. Nilai ekstra yang Anda tambahkan
    -+            ke intent akan ditampilkan. Bila pengguna mengklik <strong>Done</strong> untuk menyimpan
    -+            hasil edit, aktivitas Anda kembali ke latar depan.
    -+        </td>
    -+    </tr>
    -+    <tr>
    -+        <td><strong>Menampilkan picker yang juga bisa menambahkan data.</strong></td>
    -+        <td>{@link android.content.Intent#ACTION_INSERT_OR_EDIT}</td>
    -+        <td>
    -+            N/A
    -+        </td>
    -+        <td>
    -+            {@link android.provider.ContactsContract.Contacts#CONTENT_ITEM_TYPE}
    -+        </td>
    -+         <td>
    -+            Intent ini selalu menampilkan layar picker aplikasi kontak. Pengguna bisa memilih
    -+            kontak untuk diedit, atau menambahkan kontak baru. Layar edit atau layar tambah
    -+            akan muncul, sesuai dengan pilihan pengguna, dan data ekstra yang Anda kirimkan dalam intent
    -+            akan ditampilkan. Jika aplikasi Anda menampilkan data kontak seperti email atau nomor telepon, gunakan
    -+            intent ini untuk memungkinkan pengguna menambahkan data ke kontak yang ada.
    -+
    -+            <p class="note">
    -+                <strong>Catatan:</strong> Tidak perlu mengirimkan nilai nama dalam ekstra intent ini,
    -+                karena pengguna selalu mengambil nama yang ada atau menambahkan nama baru. Lebih-lebih,
    -+                jika Anda mengirimkan nama, dan pengguna memilih untuk melakukan edit, aplikasi kontak akan
    -+                menampilkan nama yang Anda kirimkan, yang menimpa nilai sebelumnya. Jika pengguna tidak
    -+                menyadari hal ini dan menyimpan hasil edit, nilai lama akan hilang.
    -+            </p>
    -+         </td>
    -+    </tr>
    -+</table>
    -+<p>
    -+    Aplikasi kontak perangkat tidak memperbolehkan Anda menghapus kontak mentah atau datanya dengan
    -+    intent. Sebagai gantinya, untuk menghapus kontak mentah, gunakan
    -+    {@link android.content.ContentResolver#delete(Uri, String, String[]) ContentResolver.delete()}
    -+    atau {@link android.content.ContentProviderOperation#newDelete(Uri)
    -+    ContentProviderOperation.newDelete()}.
    -+</p>
    -+<p>
    -+    Cuplikan berikut menampilkan cara menyusun dan mengirimkan intent yang menyisipkan kontak dan data
    -+    mentah baru:
    -+</p>
    -+<pre>
    -+// Gets values from the UI
    -+String name = mContactNameEditText.getText().toString();
    -+String phone = mContactPhoneEditText.getText().toString();
    -+String email = mContactEmailEditText.getText().toString();
    -+
    -+String company = mCompanyName.getText().toString();
    -+String jobtitle = mJobTitle.getText().toString();
    -+
    -+// Creates a new intent for sending to the device's contacts application
    -+Intent insertIntent = new Intent(ContactsContract.Intents.Insert.ACTION);
    -+
    -+// Sets the MIME type to the one expected by the insertion activity
    -+insertIntent.setType(ContactsContract.RawContacts.CONTENT_TYPE);
    -+
    -+// Sets the new contact name
    -+insertIntent.putExtra(ContactsContract.Intents.Insert.NAME, name);
    -+
    -+// Sets the new company and job title
    -+insertIntent.putExtra(ContactsContract.Intents.Insert.COMPANY, company);
    -+insertIntent.putExtra(ContactsContract.Intents.Insert.JOB_TITLE, jobtitle);
    -+
    -+/*
    -+ * Demonstrates adding data rows as an array list associated with the DATA key
    -+ */
    -+
    -+// Defines an array list to contain the ContentValues objects for each row
    -+ArrayList&lt;ContentValues&gt; contactData = new ArrayList&lt;ContentValues&gt;();
    -+
    -+
    -+/*
    -+ * Defines the raw contact row
    -+ */
    -+
    -+// Sets up the row as a ContentValues object
    -+ContentValues rawContactRow = new ContentValues();
    -+
    -+// Adds the account type and name to the row
    -+rawContactRow.put(ContactsContract.RawContacts.ACCOUNT_TYPE, mSelectedAccount.getType());
    -+rawContactRow.put(ContactsContract.RawContacts.ACCOUNT_NAME, mSelectedAccount.getName());
    -+
    -+// Adds the row to the array
    -+contactData.add(rawContactRow);
    -+
    -+/*
    -+ * Sets up the phone number data row
    -+ */
    -+
    -+// Sets up the row as a ContentValues object
    -+ContentValues phoneRow = new ContentValues();
    -+
    -+// Specifies the MIME type for this data row (all data rows must be marked by their type)
    -+phoneRow.put(
    -+        ContactsContract.Data.MIMETYPE,
    -+        ContactsContract.CommonDataKinds.Phone.CONTENT_ITEM_TYPE
    -+);
    -+
    -+// Adds the phone number and its type to the row
    -+phoneRow.put(ContactsContract.CommonDataKinds.Phone.NUMBER, phone);
    -+
    -+// Adds the row to the array
    -+contactData.add(phoneRow);
    -+
    -+/*
    -+ * Sets up the email data row
    -+ */
    -+
    -+// Sets up the row as a ContentValues object
    -+ContentValues emailRow = new ContentValues();
    -+
    -+// Specifies the MIME type for this data row (all data rows must be marked by their type)
    -+emailRow.put(
    -+        ContactsContract.Data.MIMETYPE,
    -+        ContactsContract.CommonDataKinds.Email.CONTENT_ITEM_TYPE
    -+);
    -+
    -+// Adds the email address and its type to the row
    -+emailRow.put(ContactsContract.CommonDataKinds.Email.ADDRESS, email);
    -+
    -+// Adds the row to the array
    -+contactData.add(emailRow);
    -+
    -+/*
    -+ * Adds the array to the intent's extras. It must be a parcelable object in order to
    -+ * travel between processes. The device's contacts app expects its key to be
    -+ * Intents.Insert.DATA
    -+ */
    -+insertIntent.putParcelableArrayListExtra(ContactsContract.Intents.Insert.DATA, contactData);
    -+
    -+// Send out the intent to start the device's contacts app in its add contact activity.
    -+startActivity(insertIntent);
    -+</pre>
    -+<h3 id="DataIntegrity">Integritas data</h3>
    -+<p>
    -+    Karena repository kontak berisi data penting dan sensitif yang diharapkan pengguna agar
    -+    benar dan terbaru. Penyedia Kontak memiliki aturan yang didefinisikan dengan baik demi integritas data. Anda
    -+    bertanggung jawab untuk mematuhi aturan ini saat memodifikasi data kontak. Aturan-aturan penting itu
    -+    dicantumkan di sini:
    -+</p>
    -+<dl>
    -+    <dt>
    -+        Selalu tambahkan baris {@link android.provider.ContactsContract.CommonDataKinds.StructuredName}
    -+        untuk setiap baris {@link android.provider.ContactsContract.RawContacts} yang Anda tambahkan.
    -+    </dt>
    -+    <dd>
    -+        Baris {@link android.provider.ContactsContract.RawContacts} tanpa
    -+        baris {@link android.provider.ContactsContract.CommonDataKinds.StructuredName} dalam
    -+        tabel {@link android.provider.ContactsContract.Data} bisa menyebabkan masalah selama
    -+       agregasi.
    -+    </dd>
    -+    <dt>
    -+        Selalu tautkan baris {@link android.provider.ContactsContract.Data} baru ke baris
    -+        {@link android.provider.ContactsContract.RawContacts} induknya.
    -+    </dt>
    -+    <dd>
    -+        Baris {@link android.provider.ContactsContract.Data} yang tidak ditautkan ke
    -+        {@link android.provider.ContactsContract.RawContacts} tidak akan terlihat dalam aplikasi kontak
    -+        perangkat, dan itu bisa menimbulkan masalah dengan adaptor sinkronisasi.
    -+    </dd>
    -+    <dt>
    -+        Ubah data hanya untuk kontak mentah yang Anda miliki.
    -+    </dt>
    -+    <dd>
    -+        Ingatlah bahwa Penyedia Kontak biasanya mengelola data dari berbagai
    -+        tipe akun/layanan online. Anda harus memastikan bahwa aplikasi Anda hanya memodifikasi
    -+        atau menghapus data untuk baris milik Anda, dan bahwa aplikasi hanya menyisipkan data dengan
    -+        tipe akun dan nama yang Anda kontrol.
    -+    </dd>
    -+    <dt>
    -+        Selalu gunakan konstanta yang didefinisikan dalam {@link android.provider.ContactsContract} dan
    -+        subkelasnya untuk otoritas, URI konten, URI path, nama kolom, tipe MIME, dan
    -+        nilai {@link android.provider.ContactsContract.CommonDataKinds.CommonColumns#TYPE}.
    -+    </dt>
    -+    <dd>
    -+        Menggunakan konstanta ini membantu Anda menghindari kesalahan. Anda juga akan diberi tahu dengan peringatan
    -+        compiler jika salah satu konstanta sudah usang.
    -+    </dd>
    -+</dl>
    -+<h3 id="CustomData">Baris data custom</h3>
    -+<p>
    -+    Dengan membuat dan menggunakan tipe MIME custom sendiri, Anda bisa menyisipkan, mengedit, menghapus, dan mengambil
    -+    baris data sendiri dalam tabel {@link android.provider.ContactsContract.Data}. Baris Anda
    -+    dibatasi untuk menggunakan kolom yang didefinisikan dalam
    -+    {@link android.provider.ContactsContract.DataColumns}, meskipun Anda bisa memetakan nama kolom
    -+    bertipe spesifik sendiri ke nama kolom default. Dalam aplikasi kontak perangkat,
    -+    data untuk baris Anda ditampilkan, tetapi tidak bisa diedit atau dihapus, dan pengguna tidak bisa menambahkan
    -+    data lain. Untuk memudahkan pengguna mengubah baris data custom Anda, Anda harus menyediakan aktivitas
    -+    editor dalam aplikasi Anda sendiri.
    -+</p>
    -+<p>
    -+    Untuk menampilkan data custom, sediakan file <code>contacts.xml</code> berisi elemen
    -+    <code>&lt;ContactsAccountType&gt;</code> dan satu atau beberapa elemen anak
    -+    <code>&lt;ContactsDataKind&gt;</code>. Hal ini dijelaskan lebih detail di
    -+    bagian <a href="#SocialStreamDataKind"><code>&lt;ContactsDataKind&gt; element</code></a>.
    -+</p>
    -+<p>
    -+    Untuk mengetahui selengkapnya tentang tipe MIME custom, bacalah panduan
    -+    <a href="{@docRoot}guide/topics/providers/content-provider-creating.html">
    -+    Membuat Penyedia Konten</a>.
    -+</p>
    -+<h2 id="SyncAdapters">Adaptor Sinkronisasi Penyedia Kontak</h2>
    -+<p>
    -+    Penyedia Kontak didesain khusus untuk menangani <strong>sinkronisasi</strong>
    -+    data kontak antara perangkat dan layanan online. Hal ini memungkinkan pengguna mengunduh
    -+    data yang ada dari perangkat baru dan mengunggah data yang ada ke akun baru.
    -+    Sinkronisasi juga memastikan bahwa pengguna memiliki data terbaru, apa pun
    -+    sumber penambahan dan perubahan itu. Keuntungan lain dari sinkronisasi adalah membuat
    -+    data kontak tersedia sekalipun perangkat tidak terhubung ke jaringan.
    -+</p>
    -+<p>
    -+    Walaupun Anda bisa menerapkan sinkronisasi dengan berbagai cara, sistem Android menyediakan
    -+    kerangka kerja sinkronisasi plug-in yang mengotomatiskan tugas-tugas berikut:
    -+    <ul>
    -+
    -+    <li>
    -+        Memeriksa ketersediaan jaringan.
    -+    </li>
    -+    <li>
    -+        Menjadwalkan dan menjalankan sinkronisasi, berdasarkan preferensi pengguna.
    -+    </li>
    -+    <li>
    -+        Memulai kembali sinkronisasi yang telah berhenti.
    -+    </li>
    -+    </ul>
    -+<p>
    -+    Untuk menggunakan kerangka kerja ini, Anda harus menyediakan plug-in adaptor sinkronisasi. Setiap adaptor sinkronisasi bersifat unik bagi
    -+    layanan dan penyedia konten, tetapi mampu menangani beberapa nama akun untuk layanan yang sama. Kerangka
    -+    kerja ini juga memungkinkan beberapa adaptor sinkronisasi untuk layanan dan penyedia yang sama.
    -+</p>
    -+<h3 id="SyncClassesFiles">Kelas dan file adaptor sinkronisasi</h3>
    -+<p>
    -+    Anda mengimplementasikan adaptor sinkronisasi sebagai subkelas
    -+    {@link android.content.AbstractThreadedSyncAdapter} dan menginstalnya sebagai bagian dari aplikasi
    -+    Android. Sistem akan mempelajari adaptor sinkronisasi dari elemen-elemen di manifes
    -+     aplikasi Anda dan dari file XML khusus yang ditunjuk oleh manifes. File XML mendefinisikan
    -+    tipe akun untuk layanan online dan otoritas untuk penyedia konten, yang bersama-sama
    -+    mengidentifikasi adaptor secara unik. Adaptor sinkronisasi tidak menjadi aktif hingga pengguna menambahkan
    -+    akun untuk tipe akun adaptor sinkronisasi dan memungkinkan sinkronisasi untuk penyedia
    -+    konten yang disinkronkan dengan adaptor sinkronisasi.  Pada saat itu, sistem mulai mengelola adaptor,
    -+    memanggilnya seperlunya untuk menyinkronkan antara penyedia konten dan server.
    -+</p>
    -+<p class="note">
    -+    <strong>Catatan:</strong> Menggunakan tipe akun sebagai bagian dari identifikasi adaptor sinkronisasi memungkinkan
    -+    sistem mendeteksi dan menghimpun adaptor-adaptor sinkronisasi yang mengakses berbagai layanan dari
    -+    organisasi yang sama. Misalnya, adaptor sinkronisasi untuk semua layanan online Google semuanya memiliki tipe akun
    -+    yang sama <code>com.google</code>. Bila pengguna menambahkan akun Google ke perangkatnya, semua
    -+    adaptor sinkronisasi yang terinstal untuk layanan Google akan dicantumkan bersama; setiap adaptor sinkronisasi
    -+    yang tercantum akan menyinkronkan diri dengan berbagai penyedia konten pada perangkat.
    -+</p>
    -+<p>
    -+    Karena sebagian besar layanan mengharuskan pengguna untuk memeriksa identitas sebelum mengakses
    -+    data, sistem Android menawarkan kerangka kerja autentikasi yang serupa dengan, dan sering kali
    -+    digunakan bersama, kerangka kerja adaptor sinkronisasi. Kerangka kerja autentikasi menggunakan
    -+    autentikator plug-in yang merupakan subkelas
    -+    {@link android.accounts.AbstractAccountAuthenticator}. Autentikator memeriksa
    -+    identitas pengguna dalam langkah-langkah berikut:
    -+    <ol>
    -+        <li>
    -+            Mengumpulkan nama pengguna, kata sandi, atau informasi serupa (
    -+            <strong>kredensial</strong> pengguna).
    -+        </li>
    -+        <li>
    -+            Mengirimkan kredensial ke layanan
    -+        </li>
    -+        <li>
    -+            Memeriksa balasan layanan.
    -+        </li>
    -+    </ol>
    -+<p>
    -+    Jika layanan menerima kredensial, autentikator bisa
    -+    menyimpan kredensial itu untuk digunakan nanti. Karena kerangka kerja autentikator plug-in,
    -+    {@link android.accounts.AccountManager} bisa menyediakan akses ke setiap token autentikasi yang didukung suatu autentikator
    -+    dan dipilihnya untuk diekspos, seperti token autentikasi OAuth2.
    -+</p>
    -+<p>
    -+    Meskipun autentikasi tidak diharuskan, sebagian besar layanan kontak menggunakannya.
    -+    Akan tetapi, Anda tidak wajib menggunakan kerangka kerja autentikasi Android untuk melakukan autentikasi.
    -+</p>
    -+<h3 id="SyncAdapterImplementing">Implementasi adaptor sinkronisasi</h3>
    -+<p>
    -+    Untuk mengimplementasikan adaptor sinkronisasi bagi Penyedia Kontak, perlu Anda memulai dengan membuat
    -+    aplikasi Android yang berisi elemen-elemen berikut:
    -+</p>
    -+    <dl>
    -+        <dt>
    -+            Komponen {@link android.app.Service} yang merespons permintaan sistem untuk
    -+            mengikat ke adaptor sinkronisasi.
    -+        </dt>
    -+        <dd>
    -+            Bila sistem ingin menjalankan sinkronisasi, sistem akan memanggil metode
    -+            {@link android.app.Service#onBind(Intent) onBind()} layanan untuk mendapatkan
    -+            {@link android.os.IBinder} bagi adaptor sinkronisasi. Hal ini memungkinkan sistem melakukan
    -+            panggilan lintas proses ke metode adaptor.
    -+            <p>
    -+                Dalam contoh aplikasi <a href="{@docRoot}resources/samples/SampleSyncAdapter/index.html">
    -+               Sample Sync Adapter</a>, nama kelas layanan ini adalah
    -+                <code>com.example.android.samplesync.syncadapter.SyncService</code>.
    -+            </p>
    -+        </dd>
    -+        <dt>
    -+            Adaptor sinkronisasi yang sesungguhnya, diimplementasikan sebagai subkelas konkret dari
    -+            {@link android.content.AbstractThreadedSyncAdapter}.
    -+        </dt>
    -+        <dd>
    -+            Kelas ini melakukan pekerjaan mengunduh data dari server, mengunggah data ke
    -+            perangkat, dan menyelesaikan konflik. Pekerjaan utama adaptor
    -+            diselesaikan dengan metode {@link android.content.AbstractThreadedSyncAdapter#onPerformSync(
    -+            Account, Bundle, String, ContentProviderClient, SyncResult)
    -+            onPerformSync()}. Instance kelas ini harus dibuat sebagai singleton.
    -+            <p>
    -+                Dalam contoh aplikasi <a href="{@docRoot}resources/samples/SampleSyncAdapter/index.html">
    -+               Sample Sync Adapter</a>, adaptor sinkronisasi didefinisikan dalam kelas
    -+                <code>com.example.android.samplesync.syncadapter.SyncAdapter</code>.
    -+            </p>
    -+        </dd>
    -+        <dt>
    -+            Subkelas {@link android.app.Application}.
    -+        </dt>
    -+        <dd>
    -+            Kelas ini berfungsi sebagai pabrik untuk singleton adaptor sinkronisasi. Gunakan
    -+            metode {@link android.app.Application#onCreate()} untuk membuat instance adaptor sinkronisasi , dan
    -+            menyediakan metode "getter" statis untuk mengembalikan singleton ke
    -+            metode {@link android.app.Service#onBind(Intent) onBind()} dari layanan
    -+            adaptor sinkronisasi.
    -+        </dd>
    -+        <dt>
    -+            <strong>Opsional:</strong> Komponen {@link android.app.Service} yang merespons
    -+            permintaan dari sistem untuk autentikasi pengguna.
    -+        </dt>
    -+        <dd>
    -+            {@link android.accounts.AccountManager} memulai layanan ini untuk memulai proses
    -+            autentikasi. Metode {@link android.app.Service#onCreate()} layanan membuat instance
    -+            objek autentikator. Bila sistem ingin mengautentikasi akun pengguna untuk
    -+            adaptor sinkronisasi aplikasi, sistem akan memanggil metode
    -+{@link android.app.Service#onBind(Intent) onBind()}            layanan guna mendapatkan
    -+            {@link android.os.IBinder} bagi autentikator. Hal ini memungkinkan sistem melakukan
    -+            panggilan lintas proses ke metode autentikator.
    -+            <p>
    -+                Dalam contoh aplikasi <a href="{@docRoot}resources/samples/SampleSyncAdapter/index.html">
    -+               Sample Sync Adapter</a>, nama kelas layanan ini adalah
    -+                <code>com.example.android.samplesync.authenticator.AuthenticationService</code>.
    -+            </p>
    -+        </dd>
    -+        <dt>
    -+            <strong>Opsional:</strong> Subkelas konkret
    -+            {@link android.accounts.AbstractAccountAuthenticator} yang menangani permintaan
    -+            autentikasi.
    -+        </dt>
    -+        <dd>
    -+            Kelas ini menyediakan metode yang dipicu {@link android.accounts.AccountManager}
    -+            untuk mengautentikasi kredensial pengguna dengan layanan. Detail
    -+            proses autentikasi sangat bervariasi, berdasarkan teknologi server yang digunakan. Anda harus
    -+            mengacu ke dokumentasi bagi perangkat lunak server untuk mengetahui selengkapnya tentang autentikasi.
    -+            <p>
    -+                Dalam contoh aplikasi <a href="{@docRoot}resources/samples/SampleSyncAdapter/index.html">
    -+               Sample Sync Adapter</a>, autentikator didefinisikan dalam kelas
    -+                <code>com.example.android.samplesync.authenticator.Authenticator</code>.
    -+            </p>
    -+        </dd>
    -+        <dt>
    -+            File XML yang mendefinisikan adaptor sinkronisasi dan autentikator bagi sistem.
    -+        </dt>
    -+        <dd>
    -+            Komponen-komponen layanan adaptor sinkronisasi dan autentikator
    -+            didefinisikan dalam elemen-elemen
    -+<code>&lt;<a href="{@docRoot}guide/topics/manifest/service-element.html">service</a>&gt;</code>
    -+            di manifes aplikasi. Elemen-elemen ini
    -+            berisi
    -+<code>&lt;<a href="{@docRoot}guide/topics/manifest/meta-data-element.html">meta-data</a>&gt;</code>
    -+elemen anak yang menyediakan data tertentu ke
    -+            sistem:
    -+            <ul>
    -+                <li>
    -+                    Elemen
    -+<code>&lt;<a href="{@docRoot}guide/topics/manifest/meta-data-element.html">meta-data</a>&gt;</code>
    -+                    untuk layanan adaptor sinkronisasi menunjuk ke
    -+                    file XML <code>res/xml/syncadapter.xml</code>. Pada gilirannya, file ini mendefinisikan
    -+                    URI untuk layanan web yang akan disinkronkan dengan Penyedia Kontak,
    -+                    dan tipe akun untuk layanan web.
    -+                </li>
    -+                <li>
    -+                    <strong>Opsional:</strong> Elemen
    -+<code>&lt;<a href="{@docRoot}guide/topics/manifest/meta-data-element.html">meta-data</a>&gt;</code>
    -+                   untuk autentikator menunjuk ke file XML
    -+                    <code>res/xml/authenticator.xml</code>. Pada gilirannya, file ini menetapkan
    -+                    tipe akun yang didukung autentikator, serta sumber daya UI yang
    -+                    muncul selama proses autentikasi. Tipe akun yang ditetapkan dalam elemen ini
    -+                    harus sama dengan tipe akun yang ditetapkan untuk adaptor
    -+                    sinkronisasi.
    -+                </li>
    -+            </ul>
    -+        </dd>
    -+    </dl>
    -+<h2 id="SocialStream">Data Aliran Sosial</h2>
    -+<p>
    -+    Tabel-tabel {@code android.provider.ContactsContract.StreamItems} dan
    -+    {@code android.provider.ContactsContract.StreamItemPhotos}
    -+    mengelola data yang masuk dari jaringan sosial. Anda bisa menulis adaptor sinkronisasi yang menambahkan data aliran
    -+    dari jaringan Anda sendiri ke tabel-tabel ini, atau Anda bisa membaca data aliran dari tabel-tabel ini dan
    -+    menampilkannya dalam aplikasi sendiri, atau keduanya. Dengan fitur-fitur ini, layanan dan aplikasi
    -+    jaringan sosial Anda bisa diintegrasikan ke dalam pengalaman jaringan sosial Android.
    -+</p>
    -+<h3 id="StreamText">Teks aliran sosial</h3>
    -+<p>
    -+    Item aliran selalu dikaitkan dengan kontak mentah.
    -+    {@code android.provider.ContactsContract.StreamItemsColumns#RAW_CONTACT_ID} menautkan ke
    -+    nilai <code>_ID</code> untuk kontak mentah. Tipe akun dan nama akun kontak
    -+    mentah juga disimpan dalam baris item aliran.
    -+</p>
    -+<p>
    -+    Simpanlah data dari aliran Anda dalam kolom-kolom berikut:
    -+</p>
    -+<dl>
    -+    <dt>
    -+        {@code android.provider.ContactsContract.StreamItemsColumns#ACCOUNT_TYPE}
    -+    </dt>
    -+    <dd>
    -+        <strong>Diperlukan.</strong> Tipe akun pengguna untuk kontak mentah yang dikaitkan dengan
    -+        item aliran ini. Ingatlah untuk mengatur nilai ini saat Anda menyisipkan item aliran.
    -+    </dd>
    -+    <dt>
    -+        {@code android.provider.ContactsContract.StreamItemsColumns#ACCOUNT_NAME}
    -+    </dt>
    -+    <dd>
    -+        <strong>Diperlukan.</strong> Nama akun pengguna untuk kontak mentah yang dikaitkan dengan
    -+        item aliran ini. Ingatlah untuk mengatur nilai ini saat Anda menyisipkan item aliran.
    -+    </dd>
    -+    <dt>
    -+        Kolom identifier
    -+    </dt>
    -+    <dd>
    -+        <strong>Diperlukan.</strong> Anda harus memasukkan kolom identifier berikut saat
    -+        menyisipkan item aliran:
    -+        <ul>
    -+            <li>
    -+                {@code android.provider.ContactsContract.StreamItemsColumns#CONTACT_ID}:
    -+                Nilai {@code android.provider.BaseColumns#_ID} kontak yang dikaitkan dengan item aliran
    -+                ini.
    -+            </li>
    -+            <li>
    -+                {@code android.provider.ContactsContract.StreamItemsColumns#CONTACT_LOOKUP_KEY}:
    -+                Nilai {@code android.provider.ContactsContract.ContactsColumns#LOOKUP_KEY}
    -+                kontak yang dikaitkan dengan item aliran ini.
    -+            </li>
    -+            <li>
    -+                {@code android.provider.ContactsContract.StreamItemsColumns#RAW_CONTACT_ID}:
    -+                Nilai {@code android.provider.BaseColumns#_ID} kontak mentah yang dikaitkan dengan item aliran
    -+                ini.
    -+            </li>
    -+        </ul>
    -+    </dd>
    -+    <dt>
    -+        {@code android.provider.ContactsContract.StreamItemsColumns#COMMENTS}
    -+    </dt>
    -+    <dd>
    -+        Opsional. Menyimpan informasi rangkuman yang bisa Anda tampilkan di awal item aliran.
    -+    </dd>
    -+    <dt>
    -+        {@code android.provider.ContactsContract.StreamItemsColumns#TEXT}
    -+    </dt>
    -+    <dd>
    -+        Teks item aliran, baik konten yang diposting oleh sumber item,
    -+        maupun keterangan beberapa tindakan yang menghasilkan item aliran. Kolom ini bisa berisi
    -+        sembarang gambar sumber daya pemformatan dan tertanam yang bisa dirender oleh
    -+        {@link android.text.Html#fromHtml(String) fromHtml()}. Penyedia bisa memotong atau
    -+        menghapus konten yang panjang, tetapi penyedia akan mencoba menghindari memutus tag.
    -+    </dd>
    -+    <dt>
    -+        {@code android.provider.ContactsContract.StreamItemsColumns#TIMESTAMP}
    -+    </dt>
    -+    <dd>
    -+        String teks berisi waktu item aliran yang disisipkan atau diperbarui, berupa
    -+        <em>milidetik</em> sejak waktu patokan. Aplikasi yang menyisipkan atau memperbarui item aliran
    -+        bertanggung jawab memelihara kolom ini; aplikasi tidak dipelihara secara otomatis oleh
    -+        Penyedia Kontak.
    -+    </dd>
    -+</dl>
    -+<p>
    -+    Untuk menampilkan informasi pengidentifikasi item aliran Anda, gunakan
    -+    {@code android.provider.ContactsContract.StreamItemsColumns#RES_ICON},
    -+    {@code android.provider.ContactsContract.StreamItemsColumns#RES_LABEL}, dan
    -+    {@code android.provider.ContactsContract.StreamItemsColumns#RES_PACKAGE} untuk menautkan ke sumber daya
    -+    dalam aplikasi Anda.
    -+</p>
    -+<p>
    -+    Tabel {@code android.provider.ContactsContract.StreamItems} juga berisi kolom-kolom
    -+    {@code android.provider.ContactsContract.StreamItemsColumns#SYNC1} hingga
    -+    {@code android.provider.ContactsContract.StreamItemsColumns#SYNC4} untuk penggunaan eksklusif oleh
    -+    adaptor sinkronisasi.
    -+</p>
    -+<h3 id="StreamPhotos">Foto aliran sosial</h3>
    -+<p>
    -+   Tabel {@code android.provider.ContactsContract.StreamItemPhotos} menyimpan foto-foto yang dikaitkan
    -+   dengan item aliran. Kolom
    -+{@code android.provider.ContactsContract.StreamItemPhotosColumns#STREAM_ITEM_ID}   tabel ini
    -+   menautkan ke nilai dalam kolom {@code android.provider.BaseColumns#_ID}
    -+   tabel {@code android.provider.ContactsContract.StreamItems}. Acuan foto disimpan dalam
    -+   tabel pada kolom-kolom ini:
    -+</p>
    -+<dl>
    -+    <dt>
    -+        Kolom {@code android.provider.ContactsContract.StreamItemPhotos#PHOTO} (BLOB).
    -+    </dt>
    -+    <dd>
    -+        Representasi biner foto, yang diubah ukurannya oleh penyedia untuk penyimpanan dan tampilan.
    -+        Kolom ini tersedia untuk kompatibilitas ke belakang dengan versi Penyedia Kontak
    -+        sebelumnya yang menggunakannya untuk menyimpan foto. Akan tetapi, pada versi saat ini
    -+        Anda tidak boleh menggunakan kolom ini untuk menyimpan foto. Sebagai gantinya, gunakan
    -+         {@code android.provider.ContactsContract.StreamItemPhotosColumns#PHOTO_FILE_ID} atau
    -+        {@code android.provider.ContactsContract.StreamItemPhotosColumns#PHOTO_URI} (keduanya
    -+        dijelaskan dalam poin-poin berikut) untuk menyimpan foto di file. Kolom ini sekarang
    -+        berisi thumbnail foto, yang tersedia untuk dibaca.
    -+    </dd>
    -+    <dt>
    -+        {@code android.provider.ContactsContract.StreamItemPhotosColumns#PHOTO_FILE_ID}
    -+    </dt>
    -+    <dd>
    -+        Identifier numerik foto untuk kontak mentah. Tambahkan nilai ini ke konstanta
    -+        {@link android.provider.ContactsContract.DisplayPhoto#CONTENT_URI DisplayPhoto.CONTENT_URI}
    -+        untuk mendapatkan URI konten yang menunjuk ke satu file foto, kemudian panggil
    -+        {@link android.content.ContentResolver#openAssetFileDescriptor(Uri, String)
    -+        openAssetFileDescriptor()} untuk mendapatkan handle ke file foto.
    -+    </dd>
    -+    <dt>
    -+        {@code android.provider.ContactsContract.StreamItemPhotosColumns#PHOTO_URI}
    -+    </dt>
    -+    <dd>
    -+        URI konten menunjuk langsung ke file foto untuk foto yang diwakili oleh baris ini.
    -+        Panggillah {@link android.content.ContentResolver#openAssetFileDescriptor(Uri, String)
    -+        openAssetFileDescriptor()} dengan URI ini untuk mendapatkan handle ke file foto.
    -+    </dd>
    -+</dl>
    -+<h3 id="SocialStreamTables">Menggunakan tabel aliran sosial</h3>
    -+<p>
    -+    Tabel-tabel ini sama fungsinya dengan tabel-tabel utama lainnya dalam Penyedia Kontak, kecuali:
    -+</p>
    -+    <ul>
    -+        <li>
    -+            Tabel-tabel ini memerlukan izin akses tambahan. Untuk membaca dari tabel, aplikasi Anda
    -+            harus memiliki izin {@code android.Manifest.permission#READ_SOCIAL_STREAM}. Untuk memodifikasi
    -+            tabel, aplikasi Anda harus memiliki izin
    -+            {@code android.Manifest.permission#WRITE_SOCIAL_STREAM}.
    -+        </li>
    -+        <li>
    -+            Untuk tabel {@code android.provider.ContactsContract.StreamItems}, jumlah baris
    -+            yang disimpan bagi setiap kontak mentah adalah terbatas. Setelah batasnya tercapai,
    -+            Penyedia Kontak akan membuat ruang untuk baris item aliran baru dengan menghapus secara otomatis
    -+            baris yang memiliki
    -+            {@code android.provider.ContactsContract.StreamItemsColumns#TIMESTAMP} terlama. Untuk mendapatkan
    -+            batas, keluarkan query ke URI konten
    -+            {@code android.provider.ContactsContract.StreamItems#CONTENT_LIMIT_URI}. Anda bisa membiarkan
    -+            semua argumen selain URI konten diatur ke <code>null</code>. Query
    -+            menghasilkan sebuah Kursor yang berisi baris tunggal, dengan kolom tunggal
    -+            {@code android.provider.ContactsContract.StreamItems#MAX_ITEMS}.
    -+        </li>
    -+    </ul>
    -+
    -+<p>
    -+    Kelas {@code android.provider.ContactsContract.StreamItems.StreamItemPhotos} mendefinisikan
    -+    subtabel {@code android.provider.ContactsContract.StreamItemPhotos} yang berisi
    -+    baris foto untuk satu item aliran.
    -+</p>
    -+<h3 id="SocialStreamInteraction">Interaksi aliran sosial</h3>
    -+<p>
    -+    Data aliran sosial yang dikelola oleh Penyedia Kontak, bersama aplikasi kontak
    -+    perangkat, menawarkan cara andal untuk menghubungkan sistem jaringan sosial Anda
    -+    dengan kontak yang ada. Tersedia fitur-fitur berikut:
    -+</p>
    -+    <ul>
    -+        <li>
    -+            Dengan menyinkronkan layanan jaringan sosial ke Penyedia Kontak dengan adaptor
    -+            sinkronisasi, Anda bisa mengambil aktivitas terbaru untuk kontak pengguna dan menyimpannya dalam tabel-tabel
    -+             {@code android.provider.ContactsContract.StreamItems} dan
    -+            {@code android.provider.ContactsContract.StreamItemPhotos} untuk digunakan nanti.
    -+        </li>
    -+        <li>
    -+            Selain sinkronisasi rutin, Anda bisa memicu adaptor sinkronisasi agar mengambil
    -+            data tambahan bila pengguna memilih sebuah kontak untuk ditampilkan. Hal ini memungkinkan adaptor sinkronisasi Anda
    -+            mengambil foto resolusi tinggi dan item aliran terbaru untuk kontak.
    -+        </li>
    -+        <li>
    -+            Dengan mendaftarkan pemberitahuan pada aplikasi kontak perangkat dan Penyedia Kontak,
    -+            Anda bisa <em>menerima</em> intent saat kontak ditampilkan, dan pada saat itu
    -+            memperbarui status kontak dari layanan Anda. Pendekatan ini mungkin lebih cepat dan menggunakan
    -+            bandwidth lebih sedikit daripada melakukan sinkronisasi penuh dengan adaptor sinkronisasi.
    -+        </li>
    -+        <li>
    -+            Pengguna bisa menambahkan kontak ke layanan jaringan sosial Anda sambil melihat kontak
    -+            dalam aplikasi kontak perangkat. Anda mengaktifkannya dengan fitur "invite contact",
    -+            yang Anda aktifkan dengan kombinasi aktivitas yang menambahkan kontak yang ada ke jaringan
    -+           Anda, dan file XML yang menyediakan aplikasi kontak perangkat dan
    -+            Penyedia Kontak dengan detail aplikasi Anda.
    -+        </li>
    -+    </ul>
    -+<p>
    -+    Sinkronisasi rutin item aliran dengan Penyedia Kontak sama dengan
    -+    sinkronisasi lainnya. Untuk mengetahui selengkapnya tentang sinkronisasi, lihat bagian
    -+    <a href="#SyncAdapters">Adaptor Sinkronisasi Penyedia Kontak</a>. Mendaftarkan pemberitahuan dan
    -+    mengundang kontak dibahas dalam dua bagian berikutnya.
    -+</p>
    -+<h4>Pendaftaran untuk menangani tampilan jaringan sosial</h4>
    -+<p>
    -+    Untuk mendaftarkan adaptor sinkronisasi agar menerima pemberitahuan saat pengguna menampilkan kontak
    -+    yang dikelola oleh adaptor sinkronisasi Anda:
    -+</p>
    -+<ol>
    -+    <li>
    -+        Buat file yang bernama <code>contacts.xml</code> dalam direktori <code>res/xml/</code>
    -+        proyek Anda. Jika sudah memiliki file ini, langkah ini boleh dilewati.
    -+    </li>
    -+    <li>
    -+        Dalam file ini, tambahkan elemen
    -+<code>&lt;ContactsAccountType xmlns:android="http://schemas.android.com/apk/res/android"&gt;</code>.
    -+        Jika elemen ini sudah ada, langkah ini boleh dilewati.
    -+    </li>
    -+    <li>
    -+        Untuk mendaftarkan layanan yang diberitahukan saat pengguna membuka halaman detail kontak dalam
    -+        aplikasi kontak perangkat, tambahkan atribut
    -+        <code>viewContactNotifyService="<em>serviceclass</em>"</code> ke elemen, dengan
    -+        <code><em>serviceclass</em></code> sebagai nama kelas mutlak (fully qualified) dari layanan
    -+        yang seharusnya menerima intent dari aplikasi kontak perangkat. Untuk layanan
    -+        notifier, gunakan kelas yang memperluas {@link android.app.IntentService}, guna memudahkan layanan
    -+        untuk menerima intent. Data dalam intent yang masuk berisi URI konten dari kontak
    -+        mentah yang diklik pengguna. Untuk layanan notifier, Anda bisa mengikatnya ke kemudian memanggil
    -+        adaptor sinkronisasi Anda untuk memperbarui data bagi kontak mentah.
    -+    </li>
    -+</ol>
    -+<p>
    -+    Untuk mendaftarkan aktivitas agar dipanggil saat pengguna mengklik item aliran atau foto atau keduanya:
    -+</p>
    -+<ol>
    -+    <li>
    -+        Buat file yang bernama <code>contacts.xml</code> dalam direktori <code>res/xml/</code>
    -+        proyek Anda. Jika sudah memiliki file ini, langkah ini boleh dilewati.
    -+    </li>
    -+    <li>
    -+        Dalam file ini, tambahkan elemen
    -+<code>&lt;ContactsAccountType xmlns:android="http://schemas.android.com/apk/res/android"&gt;</code>.
    -+        Jika elemen ini sudah ada, langkah ini boleh dilewati.
    -+    </li>
    -+    <li>
    -+        Untuk mendaftarkan salah satu aktivitas Anda guna menangani klik oleh pengguna pada item aliran dalam
    -+        aplikasi kontak perangkat, tambahkan atribut
    -+        <code>viewStreamItemActivity="<em>activityclass</em>"</code> ke elemen, dengan
    -+        <code><em>activityclass</em></code> sebagai nama kelas mutlak (fully-qualified) dari aktivitas
    -+        yang harus menerima intent dari aplikasi kontak perangkat.
    -+    </li>
    -+    <li>
    -+        Untuk mendaftarkan salah satu aktivitas Anda guna menangani klik oleh pengguna pada foto aliran dalam
    -+        aplikasi kontak perangkat, tambahkan atribut
    -+        <code>viewStreamItemPhotoActivity="<em>activityclass</em>"</code> ke elemen, dengan
    -+        <code><em>activityclass</em></code> adalah kelas nama mutlak aktivitas
    -+        yang harus menerima intent dari aplikasi kontak perangkat.
    -+    </li>
    -+</ol>
    -+<p>
    -+    Elemen <code>&lt;ContactsAccountType&gt;</code> dijelaskan lebih detail di
    -+    bagian <a href="#SocialStreamAcctType">Elemen &lt;ContactsAccountType&gt;</a>.
    -+</p>
    -+<p>
    -+    Intent yang masuk berisi URI konten dari materi atau foto yang diklik pengguna.
    -+    Untuk mendapatkan aktivitas terpisah bagi item teks dan foto, gunakan kedua atribut dalam file yang sama.
    -+</p>
    -+<h4>Berinteraksi dengan layanan jaringan sosial Anda</h4>
    -+<p>
    -+    Pengguna tidak harus meninggalkan aplikasi perangkat kontak untuk mengundang kontak ke situs
    -+    jaringan sosial Anda. Sebagai gantinya, Anda bisa meminta aplikasi kontak perangkat mengirimkan intent untuk mengundang
    -+    kontak ke salah satu aktivitas Anda. Untuk mempersiapkannya:
    -+</p>
    -+<ol>
    -+    <li>
    -+        Buat file yang bernama <code>contacts.xml</code> dalam direktori <code>res/xml/</code>
    -+        proyek Anda. Jika sudah memiliki file ini, langkah ini boleh dilewati.
    -+    </li>
    -+    <li>
    -+        Dalam file ini, tambahkan elemen
    -+<code>&lt;ContactsAccountType xmlns:android="http://schemas.android.com/apk/res/android"&gt;</code>.
    -+        Jika elemen ini sudah ada, langkah ini boleh dilewati.
    -+    </li>
    -+    <li>
    -+        Tambahkan atribut-atribut berikut:
    -+        <ul>
    -+            <li><code>inviteContactActivity="<em>activityclass</em>"</code></li>
    -+            <li>
    -+                <code>inviteContactActionLabel="&#64;string/<em>invite_action_label</em>"</code>
    -+            </li>
    -+        </ul>
    -+        Nilai <code><em>activityclass</em></code> adalah nama kelas mutlak
    -+        aktivitas yang harus menerima intent ini. Nilai <code><em>invite_action_label</em></code>
    -+        adalah string teks yang ditampilkan dalam menu <strong>Add Connection</strong> dalam
    -+        aplikasi kontak perangkat.
    -+    </li>
    -+</ol>
    -+<p class="note">
    -+    <strong>Catatan:</strong> <code>ContactsSource</code> adalah nama tag yang sudah usang untuk
    -+    <code>ContactsAccountType</code>.
    -+</p>
    -+<h3 id="ContactsFile">Acuan contacts.xml</h3>
    -+<p>
    -+    File <code>contacts.xml</code> berisi elemen XML yang mengontrol interaksi adaptor sinkronisasi
    -+    Anda dan aplikasi dengan aplikasi kontak dan Penyedia Kontak. Elemen-elemen ini
    -+    dijelaskan di bagian-bagian selanjutnya.
    -+</p>
    -+<h4 id="SocialStreamAcctType">Elemen &lt;ContactsAccountType&gt;</h4>
    -+<p>
    -+    Elemen <code>&lt;ContactsAccountType&gt;</code> mengontrol interaksi aplikasi
    -+    Anda dengan aplikasi kontak. Sintaksnya adalah sebagai berikut:
    -+</p>
    -+<pre>
    -+&lt;ContactsAccountType
    -+        xmlns:android="http://schemas.android.com/apk/res/android"
    -+        inviteContactActivity="<em>activity_name</em>"
    -+        inviteContactActionLabel="<em>invite_command_text</em>"
    -+        viewContactNotifyService="<em>view_notify_service</em>"
    -+        viewGroupActivity="<em>group_view_activity</em>"
    -+        viewGroupActionLabel="<em>group_action_text</em>"
    -+        viewStreamItemActivity="<em>viewstream_activity_name</em>"
    -+        viewStreamItemPhotoActivity="<em>viewphotostream_activity_name</em>"&gt;
    -+</pre>
    -+<p>
    -+    <strong>dimuat dalam:</strong>
    -+</p>
    -+<p>
    -+    <code>res/xml/contacts.xml</code>
    -+</p>
    -+<p>
    -+    <strong>bisa berisi:</strong>
    -+</p>
    -+<p>
    -+    <strong><code>&lt;ContactsDataKind&gt;</code></strong>
    -+</p>
    -+<p>
    -+    <strong>Keterangan:</strong>
    -+</p>
    -+<p>
    -+    Mendeklarasikan komponen Android dan label UI yang memungkinkan pengguna mengundang salah satu kontak ke
    -+    jaringan sosial, memberi tahu pengguna bila salah satu aliran jaringan sosial diperbarui, dan
    -+    seterusnya.
    -+</p>
    -+<p>
    -+    Perhatikan bahwa awalan atribut <code>android:</code> tidak perlu untuk atribut-atribut
    -+    <code>&lt;ContactsAccountType&gt;</code>.
    -+</p>
    -+<p>
    -+    <strong>Atribut:</strong>
    -+</p>
    -+<dl>
    -+    <dt>{@code inviteContactActivity}</dt>
    -+    <dd>
    -+        Nama kelas mutlak aktivitas dalam aplikasi yang Anda ingin
    -+        aktifkan bila pengguna memilih <strong>Add connection</strong> dari aplikasi kontak
    -+        perangkat.
    -+    </dd>
    -+    <dt>{@code inviteContactActionLabel}</dt>
    -+    <dd>
    -+        String teks yang ditampilkan untuk aktivitas yang ditetapkan dalam
    -+        {@code inviteContactActivity}, dalam menu <strong>Add connection</strong>.
    -+        Misalnya, Anda bisa menggunakan string "Ikuti di jaringan saya". Anda bisa menggunakan identifier sumber daya
    -+        string untuk tabel ini.
    -+    </dd>
    -+    <dt>{@code viewContactNotifyService}</dt>
    -+    <dd>
    -+        Nama kelas mutlak layanan dalam aplikasi Anda yang harus menerima
    -+        pemberitahuan saat pengguna menampilkan kontak. Pemberitahuan ini dikirimkan oleh aplikasi kontak
    -+        perangkat; hal ini memungkinkan aplikasi Anda menunda operasi yang banyak memproses data
    -+        hingga dibutuhkan. Misalnya, aplikasi Anda bisa merespons pemberitahuan ini
    -+        dengan membaca dalam dan menampilkan foto resolusi tinggi kontak dan item aliran sosial
    -+        terbaru. Fitur ini dijelaskan lebih detail di bagian
    -+        <a href="#SocialStreamInteraction">Interaksi aliran sosial</a>. Anda bisa melihat
    -+        contoh layanan pemberitahuan dalam file <code>NotifierService.java</code> dalam contoh aplikasi
    -+        <a href="{@docRoot}resources/samples/SampleSyncAdapter/index.html">Sample Sync Adapter</a>.
    -+
    -+    </dd>
    -+    <dt>{@code viewGroupActivity}</dt>
    -+    <dd>
    -+        Nama kelas mutlak aktivitas dalam aplikasi yang bisa menampilkan
    -+        informasi grup. Bila pengguna mengklik label grup dalam aplikasi
    -+        kontak perangkat, UI aktivitas ini akan ditampilkan.
    -+    </dd>
    -+    <dt>{@code viewGroupActionLabel}</dt>
    -+    <dd>
    -+        Label yang ditampilkan aplikasi kontak untuk kontrol UI yang memungkinkan
    -+        pengguna melihat grup dalam aplikasi Anda.
    -+        <p>
    -+            Misalnya, jika Anda menginstal aplikasi Google+ di perangkat dan menyinkronkan
    -+            Google+ dengan aplikasi kontak, Anda akan melihat lingkaran Google+ tercantum sebagai grup
    -+            dalam tab <strong>Groups</strong> aplikasi kontak Anda. Jika Anda mengklik
    -+            lingkaran Google+, Anda akan melihat orang-orang di lingkaran itu tercantum sebagai satu "grup". Di atas
    -+            tampilan, Anda akan melihat ikon Google+; jika mengklik ikon itu, kontrol akan beralih ke
    -+            aplikasi Google+. Aplikasi kontak melakukan ini dengan
    -+            {@code viewGroupActivity}, yang menggunakan ikon Google+ sebagai nilai
    -+            {@code viewGroupActionLabel}.
    -+        </p>
    -+        <p>
    -+            Identifier sumber daya string diperbolehkan untuk atribut ini.
    -+        </p>
    -+    </dd>
    -+    <dt>{@code viewStreamItemActivity}</dt>
    -+    <dd>
    -+        Nama kelas mutlak aktivitas dalam aplikasi Anda
    -+        yang diluncurkan aplikasi kontak perangkat bila pengguna mengklik item aliran untuk kontak mentah.
    -+    </dd>
    -+    <dt>{@code viewStreamItemPhotoActivity}</dt>
    -+    <dd>
    -+        Nama kelas mutlak aktivitas yang diluncurkan
    -+        aplikasi kontak perangkat bila pengguna mengklik foto dalam item aliran
    -+        untuk kontak mentah.
    -+    </dd>
    -+</dl>
    -+<h4 id="SocialStreamDataKind">Elemen &lt;ContactsDataKind&gt;</h4>
    -+<p>
    -+    Elemen <code>&lt;ContactsDataKind&gt;</code> mengontrol tampilan baris data custom
    -+    aplikasi Anda dalam UI aplikasi kontak. Sintaksnya adalah sebagai berikut:
    -+</p>
    -+<pre>
    -+&lt;ContactsDataKind
    -+        android:mimeType="<em>MIMEtype</em>"
    -+        android:icon="<em>icon_resources</em>"
    -+        android:summaryColumn="<em>column_name</em>"
    -+        android:detailColumn="<em>column_name</em>"&gt;
    -+</pre>
    -+<p>
    -+    <strong>dimuat dalam:</strong>
    -+</p>
    -+<code>&lt;ContactsAccountType&gt;</code>
    -+<p>
    -+    <strong>Keterangan:</strong>
    -+</p>
    -+<p>
    -+    Gunakan elemen ini untuk memerintahkan aplikasi kontak agar menampilkan konten baris data custom sebagai
    -+    bagian dari detail kontak mentah. Setiap elemen anak <code>&lt;ContactsDataKind&gt;</code>
    -+    <code>&lt;ContactsAccountType&gt;</code> mewakili tipe baris data custom yang
    -+    ditambahkan adaptor sinkronisasi Anda ke tabel {@link android.provider.ContactsContract.Data}. Tambahkan satu
    -+    elemen <code>&lt;ContactsDataKind&gt;</code> untuk setiap tipe MIME custom yang Anda gunakan. Anda tidak harus
    -+    menambahkan elemen jika Anda memiliki baris data custom yang datanya tidak ingin ditampilkan.
    -+</p>
    -+<p>
    -+    <strong>Atribut:</strong>
    -+</p>
    -+<dl>
    -+    <dt>{@code android:mimeType}</dt>
    -+    <dd>
    -+        Tipe MIME custom yang telah Anda definisikan untuk salah satu tipe baris data custom dalam
    -+        tabel {@link android.provider.ContactsContract.Data}. Misalnya, nilai
    -+        <code>vnd.android.cursor.item/vnd.example.locationstatus</code> bisa berupa tipe MIME
    -+       custom untuk baris data yang mencatat lokasi kontak yang terakhir diketahui.
    -+    </dd>
    -+    <dt>{@code android:icon}</dt>
    -+    <dd>
    -+
    -+        <a href="{@docRoot}guide/topics/resources/drawable-resource.html">Sumber daya drawable</a>
    -+        Android yang ditampilkan aplikasi kontak di samping data Anda. Gunakan ini untuk menunjukkan kepada
    -+        pengguna bahwa data berasal dari layanan Anda.
    -+    </dd>
    -+    <dt>{@code android:summaryColumn}</dt>
    -+    <dd>
    -+        Nama kolom untuk yang pertama dari dua nilai yang diambil dari baris data. Nilai
    -+        ditampilkan sebagai baris pertama entri untuk baris data ini. Baris pertama
    -+        dimaksudkan untuk digunakan sebagai rangkuman data, tetapi itu bersifat opsional. Lihat juga
    -+        <a href="#detailColumn">android:detailColumn</a>.
    -+    </dd>
    -+    <dt>{@code android:detailColumn}</dt>
    -+    <dd>
    -+        Nama kolom untuk yang kedua dari dua nilai yang diambil dari baris data. Nilai
    -+        ditampilkan sebagai baris kedua entri untuk baris data ini. Lihat juga
    -+        {@code android:summaryColumn}.
    -+    </dd>
    -+</dl>
    -+<h2 id="AdditionalFeatures">Fitur Tambahan Penyedia Kontak</h2>
    -+<p>
    -+    Di samping fitur-fitur utama yang dijelaskan di bagian sebelumnya, Penyedia Kontak menawarkan
    -+   fitur-fitur berguna ini untuk digunakan bersama data kontak:
    -+</p>
    -+    <ul>
    -+       <li>Grup kontak</li>
    -+       <li>Fitur foto</li>
    -+    </ul>
    -+<h3 id="Groups">Grup kontak</h3>
    -+<p>
    -+    Penyedia Kontak secara opsional bisa melabeli kumpulan kontak terkait dengan data
    -+    <strong>grup</strong>. Jika server yang dikaitkan dengan akun pengguna
    -+    ingin mempertahankan grup, adaptor sinkronisasi untuk tipe akun dari akun itu harus mentransfer
    -+    data grup antara Penyedia Kontak dan server. Bila pengguna menambahkan kontak baru ke
    -+    server, kemudian memasukkan kontak ini dalam grup baru, adaptor sinkronisasi harus menambahkan grup baru
    -+    ke tabel {@link android.provider.ContactsContract.Groups}. Grup atau grup-grup yang memiliki kontak
    -+    disimpan dalam tabel {@link android.provider.ContactsContract.Data}, dengan menggunakan
    -+    tipe MIME {@link android.provider.ContactsContract.CommonDataKinds.GroupMembership}.
    -+</p>
    -+<p>
    -+    Jika Anda mendesain adaptor sinkronisasi yang akan menambahkan data kontak mentah dari
    -+    server ke Penyedia Kontak, dan Anda tidak menggunakan grup, maka Anda harus memberi tahu
    -+    penyedia itu agar membuat data Anda terlihat. Dalam kode yang dijalankan bila pengguna menambahkan akun
    -+    ke perangkat, perbarui baris {@link android.provider.ContactsContract.Settings}
    -+    yang ditambahkan Penyedia Kontak untuk akunnya. Dalam baris ini, atur nilai kolom
    -+    {@link android.provider.ContactsContract.SettingsColumns#UNGROUPED_VISIBLE
    -+    Settings.UNGROUPED_VISIBLE} ke 1. Bila melakukannya, Penyedia Kontak akan selalu
    -+    membuat data kontak Anda terlihat, meskipun Anda tidak menggunakan grup.
    -+</p>
    -+<h3 id="Photos">Foto kontak</h3>
    -+<p>
    -+    Tabel {@link android.provider.ContactsContract.Data} menyimpan foto sebagai baris dengan tipe MIME
    -+    {@link android.provider.ContactsContract.CommonDataKinds.Photo#CONTENT_ITEM_TYPE
    -+    Photo.CONTENT_ITEM_TYPE}. Kolom
    -+    {@link android.provider.ContactsContract.RawContactsColumns#CONTACT_ID} baris yang ditautkan ke
    -+    kolom {@code android.provider.BaseColumns#_ID} kontak mentah yang memiliki kolom itu.
    -+    Kelas {@link android.provider.ContactsContract.Contacts.Photo} mendefinisikan subtabel
    -+    {@link android.provider.ContactsContract.Contacts} yang berisi informasi foto untuk foto
    -+    utama kontak, yang merupakan foto utama dari kontak mentah utama kontak itu. Demikian pula,
    -+    kelas {@link android.provider.ContactsContract.RawContacts.DisplayPhoto} mendefinisikan subtabel
    -+    {@link android.provider.ContactsContract.RawContacts} yang berisi informasi foto untuk
    -+    foto utama kontak mentah.
    -+</p>
    -+<p>
    -+    Dokumentasi acuan untuk {@link android.provider.ContactsContract.Contacts.Photo} dan
    -+    {@link android.provider.ContactsContract.RawContacts.DisplayPhoto} berisi contoh-contoh
    -+    pengambilan informasi foto. Tidak ada kelas praktis untuk mengambil
    -+    thumbnail utama kontak mentah, tetapi Anda bisa mengirim query ke
    -+    tabel {@link android.provider.ContactsContract.Data}, dengan memilih
    -+    {@code android.provider.BaseColumns#_ID} kontak mentah,
    -+    {@link android.provider.ContactsContract.CommonDataKinds.Photo#CONTENT_ITEM_TYPE
    -+    Photo.CONTENT_ITEM_TYPE}, dan kolom {@link android.provider.ContactsContract.Data#IS_PRIMARY}
    -+    untuk menemukan baris foto utama kontak mentah.
    -+</p>
    -+<p>
    -+    Data aliran sosial untuk seseorang bisa juga disertai foto. Data ini disimpan dalam
    -+    tabel {@code android.provider.ContactsContract.StreamItemPhotos}, yang dijelaskan lebih detail
    -+    di bagian <a href="#StreamPhotos">Foto aliran sosial</a>.
    -+</p>
    -diff --git a/docs/html-intl/intl/id/guide/topics/providers/content-provider-basics.jd b/docs/html-intl/intl/id/guide/topics/providers/content-provider-basics.jd
    -new file mode 100644
    -index 0000000..4af9277
    ---- /dev/null
    -+++ b/docs/html-intl/intl/id/guide/topics/providers/content-provider-basics.jd
    -@@ -0,0 +1,1196 @@
    -+page.title=Dasar-Dasar Penyedia Konten
    -+@jd:body
    -+<div id="qv-wrapper">
    -+<div id="qv">
    -+<!-- In this document -->
    -+<h2>Dalam dokumen ini</h2>
    -+<ol>
    -+    <li>
    -+        <a href="#Basics">Ikhtisar</a>
    -+        <ol>
    -+            <li>
    -+                <a href="#ClientProvider">Mengakses penyedia</a>
    -+            </li>
    -+            <li>
    -+                <a href="#ContentURIs">URI Konten</a>
    -+            </li>
    -+        </ol>
    -+    </li>
    -+    <li>
    -+        <a href="#SimpleQuery">Mengambil Data dari Penyedia</a>
    -+        <ol>
    -+            <li>
    -+                <a href="#RequestPermissions">Meminta izin akses baca</a>
    -+            </li>
    -+            <li>
    -+                <a href="#Query">Membuat query</a>
    -+            </li>
    -+            <li>
    -+                <a href="#DisplayResults">Menampilkan hasil query</a>
    -+            </li>
    -+            <li>
    -+                <a href="#GettingResults">Mendapatkan data dari hasil query</a>
    -+            </li>
    -+        </ol>
    -+    </li>
    -+    <li>
    -+        <a href="#Permissions">Izin Penyedia Konten</a>
    -+    </li>
    -+    <li>
    -+        <a href="#Modifications">Menyisipkan, Memperbarui, dan Menghapus Data</a>
    -+        <ol>
    -+            <li>
    -+                <a href="#Inserting">Menyisipkan data</a>
    -+            </li>
    -+            <li>
    -+                <a href="#Updating">Memperbarui data</a>
    -+            </li>
    -+            <li>
    -+                <a href="#Deleting">Menghapus data</a>
    -+            </li>
    -+        </ol>
    -+    </li>
    -+    <li>
    -+        <a href="#DataTypes">Tipe Data Penyedia</a>
    -+    </li>
    -+    <li>
    -+        <a href="#AltForms">Bentuk-Bentuk Alternatif Akses Penyedia</a>
    -+        <ol>
    -+            <li>
    -+                <a href="#Batch">Akses batch</a>
    -+            </li>
    -+            <li>
    -+                <a href="#Intents">Akses data melalui intent</a>
    -+            </li>
    -+        </ol>
    -+    </li>
    -+    <li>
    -+        <a href="#ContractClasses">Kelas-kelas Kontrak</a>
    -+    </li>
    -+    <li>
    -+        <a href="#MIMETypeReference">Acuan Tipe MIME</a>
    -+    </li>
    -+</ol>
    -+
    -+    <!-- Key Classes -->
    -+<h2>Kelas-kelas utama</h2>
    -+    <ol>
    -+        <li>
    -+            {@link android.content.ContentProvider}
    -+        </li>
    -+        <li>
    -+            {@link android.content.ContentResolver}
    -+        </li>
    -+        <li>
    -+            {@link android.database.Cursor}
    -+        </li>
    -+        <li>
    -+            {@link android.net.Uri}
    -+        </li>
    -+    </ol>
    -+
    -+    <!-- Related Samples -->
    -+<h2>Contoh-Contoh Terkait</h2>
    -+    <ol>
    -+        <li>
    -+        <a href="{@docRoot}resources/samples/ApiDemos/src/com/example/android/apis/view/List2.html">
    -+        Kursor (Orang)</a>
    -+        </li>
    -+        <li>
    -+        <a href="{@docRoot}resources/samples/ApiDemos/src/com/example/android/apis/view/List7.html">
    -+        Kursor (Telepon)</a>
    -+        </li>
    -+    </ol>
    -+
    -+    <!-- See also -->
    -+<h2>Lihat juga</h2>
    -+    <ol>
    -+        <li>
    -+            <a href="{@docRoot}guide/topics/providers/content-provider-creating.html">
    -+            Membuat Penyedia Konten</a>
    -+        </li>
    -+        <li>
    -+            <a href="{@docRoot}guide/topics/providers/calendar-provider.html">
    -+            Penyedia Kalender</a>
    -+        </li>
    -+    </ol>
    -+</div>
    -+</div>
    -+
    -+    <!-- Intro paragraphs -->
    -+<p>
    -+    Penyedia konten mengelola akses ke repository data pusat. Penyedia
    -+    adalah bagian dari aplikasi Android, yang sering menyediakan UI-nya sendiri untuk menggunakan
    -+    data. Akan tetapi, penyedia konten terutama dimaksudkan untuk digunakan oleh
    -+    aplikasi lain, yang mengakses penyedia itu melalui objek klien penyedia. Bersama-sama, penyedia
    -+    dan klien penyedia menawarkan antarmuka standar yang konsisten ke data yang juga menangani
    -+    komunikasi antar-proses dan akses data aman.
    -+</p>
    -+<p>
    -+    Topik ini menerangkan dasar-dasar dari hal-hal berikut:
    -+</p>
    -+    <ul>
    -+        <li>Cara kerja penyedia konten.</li>
    -+        <li>API yang Anda gunakan untuk mengambil data dari penyedia konten.</li>
    -+        <li>API yang Anda gunakan untuk menyisipkan, memperbarui, atau menghapus data dalam penyedia konten.</li>
    -+        <li>Fitur API lainnya yang memudahkan kita menggunakan penyedia.</li>
    -+    </ul>
    -+
    -+    <!-- Basics -->
    -+<h2 id="Basics">Ikhtisar</h2>
    -+<p>
    -+    Penyedia konten menyajikan data ke aplikasi eksternal sebagai satu atau beberapa tabel yang
    -+    serupa dengan tabel-tabel yang ditemukan dalam database relasional. Sebuah baris mewakili instance beberapa tipe
    -+    data yang dikumpulkan penyedia, dan tiap kolom dalam baris mewakili sepotong
    -+    data yang dikumpulkan untuk sebuah instance.
    -+</p>
    -+<p>
    -+    Misalnya, salah satu penyedia bawaan di platform Android adalah kamus pengguna, yang
    -+    menyimpan ejaan kata-kata tidak-standar yang ingin disimpan pengguna. Tabel 1 mengilustrasikan
    -+    wujud data yang mungkin ada dalam tabel penyedia ini:
    -+</p>
    -+<p class="table-caption">
    -+    <strong>Tabel 1:</strong> Contoh tabel kamus pengguna.
    -+</p>
    -+<table id="table1" style="width: 50%;">
    -+    <tr>
    -+        <th style="width:20%" align="center" scope="col">word</th>
    -+        <th style="width:20%" align="center" scope="col">app id</th>
    -+        <th style="width:20%" align="center" scope="col">frequency</th>
    -+        <th style="width:20%" align="center" scope="col">locale</th>
    -+        <th style="width:20%" align="center" scope="col">_ID</th>
    -+    </tr>
    -+    <tr>
    -+        <td align="center" scope="row">mapreduce</td>
    -+        <td align="center">user1</td>
    -+        <td align="center">100</td>
    -+        <td align="center">en_US</td>
    -+        <td align="center">1</td>
    -+    </tr>
    -+    <tr>
    -+        <td align="center" scope="row">precompiler</td>
    -+        <td align="center">user14</td>
    -+        <td align="center">200</td>
    -+        <td align="center">fr_FR</td>
    -+        <td align="center">2</td>
    -+    </tr>
    -+    <tr>
    -+        <td align="center" scope="row">applet</td>
    -+        <td align="center">user2</td>
    -+        <td align="center">225</td>
    -+        <td align="center">fr_CA</td>
    -+        <td align="center">3</td>
    -+    </tr>
    -+    <tr>
    -+        <td align="center" scope="row">const</td>
    -+        <td align="center">user1</td>
    -+        <td align="center">255</td>
    -+        <td align="center">pt_BR</td>
    -+        <td align="center">4</td>
    -+    </tr>
    -+    <tr>
    -+        <td align="center" scope="row">int</td>
    -+        <td align="center">user5</td>
    -+        <td align="center">100</td>
    -+        <td align="center">en_UK</td>
    -+        <td align="center">5</td>
    -+    </tr>
    -+</table>
    -+<p>
    -+    Dalam tabel 1, tiap baris mewakili instance sebuah kata yang mungkin tidak
    -+    ditemukan dalam kamus standar. Tiap kolom mewakili beberapa data untuk kata itu, misalnya
    -+    bahasa lokal tempat kata itu ditemukan kali pertama. Header kolom adalah nama kolom yang disimpan dalam
    -+    penyedia. Untuk mengacu ke bahasa lokal suatu baris, Anda mengacu ke kolom <code>locale</code>-nya. Untuk
    -+    penyedia ini, kolom <code>_ID</code> berfungsi sebagai "kunci utama" kolom yang
    -+    dipelihara oleh penyedia secara otomatis.
    -+</p>
    -+<p class="note">
    -+    <strong>Catatan:</strong> Penyedia tidak diharuskan memiliki kunci utama, dan tidak diharuskan
    -+    menggunakan <code>_ID</code> sebagai nama kolom kunci utama jika kunci itu ada. Akan tetapi,
    -+    jika Anda ingin mengikat data dari penyedia ke {@link android.widget.ListView}, salah satu
    -+    nama kolom harus <code>_ID</code>. Ketentuan ini dijelaskan secara lebih detail di bagian
    -+    <a href="#DisplayResults">Menampilkan hasil query</a>.
    -+</p>
    -+<h3 id="ClientProvider">Mengakses penyedia</h3>
    -+<p>
    -+    Aplikasi mengakses data dari penyedia konten dengan
    -+    sebuah objek klien {@link android.content.ContentResolver}. Objek ini memiliki metode yang memanggil
    -+    metode dengan nama identik dalam objek penyedia, instance salah satu
    -+    subkelas konkret dari {@link android.content.ContentProvider}. Metode-metode
    -+    {@link android.content.ContentResolver} menyediakan fungsi-fungsi dasar
    -+    "CRUD" (create, retrieve, update, dan delete) pada penyimpanan yang persisten.
    -+</p>
    -+<p>
    -+    Objek {@link android.content.ContentResolver} dalam
    -+    proses aplikasi klien dan objek {@link android.content.ContentProvider} dalam aplikasi yang memiliki
    -+    penyedia itu secara otomatis akan menangani komunikasi antar-proses.
    -+    {@link android.content.ContentProvider} juga berfungsi sebagai lapisan abstraksi antara
    -+    repository datanya dan penampilan eksternal data sebagai tabel.
    -+</p>
    -+<p class="note">
    -+    <strong>Catatan:</strong> Untuk mengakses penyedia, aplikasi Anda biasanya harus meminta
    -+    izin tertentu dalam file manifesnya. Hal ini dijelaskan lebih detail di bagian
    -+    <a href="#Permissions">Izin Penyedia Konten</a>
    -+</p>
    -+<p>
    -+    Misalnya, untuk mendapatkan daftar kata dan lokalnya dari Penyedia Kamus Pengguna,
    -+    Anda memanggil {@link android.content.ContentResolver#query ContentResolver.query()}.
    -+    Metode {@link android.content.ContentResolver#query query()} memanggil
    -+    metode {@link android.content.ContentProvider#query ContentProvider.query()} yang didefinisikan oleh
    -+    Penyedia Kamus Pengguna. Baris-baris kode berikut menunjukkan sebuah
    -+    panggilan {@link android.content.ContentResolver#query ContentResolver.query()}:
    -+<p>
    -+<pre>
    -+// Queries the user dictionary and returns results
    -+mCursor = getContentResolver().query(
    -+    UserDictionary.Words.CONTENT_URI,   // The content URI of the words table
    -+    mProjection,                        // The columns to return for each row
    -+    mSelectionClause                    // Selection criteria
    -+    mSelectionArgs,                     // Selection criteria
    -+    mSortOrder);                        // The sort order for the returned rows
    -+</pre>
    -+<p>
    -+    Tabel 2 menampilkan cara argumen untuk
    -+    {@link android.content.ContentResolver#query
    -+    query(Uri,projection,selection,selectionArgs,sortOrder)} cocok dengan sebuah pernyataan SELECT di SQL:
    -+</p>
    -+<p class="table-caption">
    -+    <strong>Tabel 2:</strong> Query() dibandingkan dengan query SQL.
    -+</p>
    -+<table id="table2" style="width: 75%;">
    -+    <tr>
    -+        <th style="width:25%" align="center" scope="col">Argumen query()</th>
    -+        <th style="width:25%" align="center" scope="col">Kata kunci/parameter SELECT</th>
    -+        <th style="width:50%" align="center" scope="col">Catatan</th>
    -+    </tr>
    -+    <tr>
    -+        <td align="center"><code>Uri</code></td>
    -+        <td align="center"><code>FROM <em>table_name</em></code></td>
    -+        <td><code>Uri</code> memetakan ke tabel dalam penyedia yang bernama <em>table_name</em>.</td>
    -+    </tr>
    -+    <tr>
    -+        <td align="center"><code>projection</code></td>
    -+        <td align="center"><code><em>col,col,col,...</em></code></td>
    -+        <td>
    -+            <code>projection</code> adalah satu larik kolom yang harus disertakan untuk tiap baris
    -+            yang diambil.
    -+        </td>
    -+    </tr>
    -+    <tr>
    -+        <td align="center"><code>selection</code></td>
    -+        <td align="center"><code>WHERE <em>col</em> = <em>value</em></code></td>
    -+        <td><code>selection</code> menetapkan kriteria untuk memilih baris.</td>
    -+    </tr>
    -+    <tr>
    -+        <td align="center"><code>selectionArgs</code></td>
    -+        <td align="center">
    -+            (Tidak ada padanan persis. Argumen pemilihan mengganti <code>?</code> placeholder dalam
    -+            klausa pemilihan.)
    -+        </td>
    -+    </tr>
    -+    <tr>
    -+        <td align="center"><code>sortOrder</code></td>
    -+        <td align="center"><code>ORDER BY <em>col,col,...</em></code></td>
    -+        <td>
    -+            <code>sortOrder</code> menetapkan urutan munculnya baris dalam
    -+            {@link android.database.Cursor} yang dihasilkan.
    -+        </td>
    -+    </tr>
    -+</table>
    -+<h3 id="ContentURIs">URI Konten</h3>
    -+<p>
    -+    <strong>URI konten</strong> adalah URI yang mengidentifikasi data dalam penyedia. URI Konten
    -+    menyertakan nama simbolis seluruh penyedia (<strong>otoritas</strong>nya) dan sebuah
    -+    nama yang menunjuk ke tabel (<strong>path</strong>). Bila Anda memanggil
    -+    metode klien untuk mengakses tabel dalam penyedia, URI konten untuk tabel itu adalah salah satu
    -+    argumennya.
    -+</p>
    -+<p>
    -+    Dalam baris kode sebelumnya, konstanta
    -+    {@link android.provider.UserDictionary.Words#CONTENT_URI} mengandung URI konten dari
    -+    tabel "words" kamus pengguna. Objek {@link android.content.ContentResolver}
    -+    akan mengurai otoritas URI, dan menggunakannya untuk "mengetahui" penyedia dengan
    -+    membandingkan otoritas tersebut dengan sebuah tabel sistem berisi penyedia yang dikenal.
    -+{@link android.content.ContentResolver}    kemudian bisa mengirim argumen query ke penyedia
    -+    yang benar.
    -+</p>
    -+<p>
    -+    {@link android.content.ContentProvider} menggunakan bagian path dari URI konten untuk memilih
    -+    tabel yang akan diakses. Penyedia biasanya memiliki <strong>path</strong> untuk tiap tabel yang dieksposnya.
    -+</p>
    -+<p>
    -+    Dalam baris kode sebelumnya, URI lengkap untuk tabel "words" adalah:
    -+</p>
    -+<pre>
    -+content://user_dictionary/words
    -+</pre>
    -+<p>
    -+    dalam hal ini string <code>user_dictionary</code> adalah otoritas penyedia, dan string
    -+    <code>words</code> adalah path tabel. String
    -+    <code>content://</code> (<strong>skema</strong>) selalu ada,
    -+    dan mengidentifikasinya sebagai URI konten.
    -+</p>
    -+<p>
    -+    Banyak penyedia yang memperbolehkan Anda mengakses satu baris dalam tabel dengan menambahkan sebuah ID nilai
    -+    ke akhir URI. Misalnya, untuk mengambil sebuah baris yang <code>_ID</code>-nya adalah
    -+    <code>4</code> dari kamus pengguna, Anda bisa menggunakan URI konten ini:
    -+</p>
    -+<pre>
    -+Uri singleUri = ContentUris.withAppendedId(UserDictionary.Words.CONTENT_URI,4);
    -+</pre>
    -+<p>
    -+    Anda akan sering menggunakan nilai-nilai ID bila telah mengambil satu set baris kemudian ingin memperbarui atau menghapus
    -+    salah satunya.
    -+</p>
    -+<p class="note">
    -+    <strong>Catatan:</strong> Kelas-kelas {@link android.net.Uri} dan {@link android.net.Uri.Builder}
    -+    berisi metode praktis untuk membangun objek dari string URI yang tersusun dengan baik.
    -+{@link android.content.ContentUris}    berisi metode praktis untuk menambahkan nilai ID ke
    -+    URI. Cuplikan kode sebelumnya menggunakan {@link android.content.ContentUris#withAppendedId
    -+    withAppendedId()} untuk menambahkan id ke URI konten User Dictionary.
    -+</p>
    -+
    -+
    -+    <!-- Retrieving Data from the Provider -->
    -+<h2 id="SimpleQuery">Mengambil Data dari Penyedia</h2>
    -+<p>
    -+    Bagian ini menerangkan cara mengambil data dari penyedia, dengan menggunakan Penyedia Kamus Pengguna
    -+    sebagai contoh.
    -+</p>
    -+<p class="note">
    -+    Demi kejelasan, cuplikan kode di bagian ini memanggil
    -+    {@link android.content.ContentResolver#query ContentResolver.query()} pada "UI thread"". Akan tetapi, dalam
    -+    kode sesungguhnya, Anda harus melakukan query secara asinkron pada sebuah thread terpisah. Satu cara melakukannya
    -+    adalah menggunakan kelas {@link android.content.CursorLoader}, yang dijelaskan
    -+    lebih detail dalam panduan <a href="{@docRoot}guide/components/loaders.html">
    -+    Loader</a>. Juga, baris-baris kode tersebut hanyalah cuplikan; tidak menunjukkan sebuah aplikasi
    -+     lengkap.
    -+</p>
    -+<p>
    -+    Untuk mengambil data dari penyedia, ikutilah langkah-langkah dasar ini:
    -+</p>
    -+<ol>
    -+   <li>
    -+        Minta izin akses baca untuk penyedia itu.
    -+   </li>
    -+   <li>
    -+        Definisikan kode yang mengirim query ke penyedia.
    -+   </li>
    -+</ol>
    -+<h3 id="RequestPermissions">Meminta izin akses baca</h3>
    -+<p>
    -+    Untuk mengambil data dari penyedia, aplikasi Anda memerlukan "izin akses baca" untuk
    -+    penyedia itu. Anda tidak bisa meminta izin ini saat runtime; sebagai gantinya, Anda harus menetapkan bahwa
    -+    Anda memerlukan izin ini dalam manifes, dengan menggunakan elemen
    -+<code><a href="{@docRoot}guide/topics/manifest/uses-permission-element.html">&lt;uses-permission&gt;</a></code>
    -+    dan nama persis izin yang didefinisikan oleh
    -+    penyedia itu. Bila menetapkan elemen ini dalam manifes, Anda secara efektif "meminta"
    -+    izin ini untuk aplikasi Anda. Bila pengguna menginstal aplikasi Anda, mereka secara implisit akan memberikan
    -+    permintaan ini.
    -+</p>
    -+<p>
    -+    Untuk menemukan nama persis dari izin akses baca untuk penyedia yang sedang Anda gunakan, serta
    -+    nama-nama izin akses lain yang digunakan oleh penyedia, lihatlah dalam
    -+    dokumentasi penyedia.
    -+</p>
    -+<p>
    -+    Peran izin dalam yang mengakses penyedia dijelaskan lebih detail di bagian
    -+    <a href="#Permissions">Izin Penyedia Konten</a>.
    -+</p>
    -+<p>
    -+    Penyedia Kamus Pengguna mendefinisikan izin
    -+    <code>android.permission.READ_USER_DICTIONARY</code> dalam file manifesnya, sehingga
    -+    aplikasi yang ingin membaca dari penyedia itu harus meminta izin ini.
    -+</p>
    -+<!-- Constructing the query -->
    -+<h3 id="Query">Membuat query</h3>
    -+<p>
    -+    Langkah berikutnya dalam mengambil data penyedia adalah membuat query. Cuplikan kode pertama ini
    -+    mendefinisikan beberapa variabel untuk mengakses Penyedia Kamus Pengguna:
    -+</p>
    -+<pre class="prettyprint">
    -+
    -+// A "projection" defines the columns that will be returned for each row
    -+String[] mProjection =
    -+{
    -+    UserDictionary.Words._ID,    // Contract class constant for the _ID column name
    -+    UserDictionary.Words.WORD,   // Contract class constant for the word column name
    -+    UserDictionary.Words.LOCALE  // Contract class constant for the locale column name
    -+};
    -+
    -+// Defines a string to contain the selection clause
    -+String mSelectionClause = null;
    -+
    -+// Initializes an array to contain selection arguments
    -+String[] mSelectionArgs = {""};
    -+
    -+</pre>
    -+<p>
    -+    Cuplikan berikutnya menampilkan cara menggunakan
    -+    {@link android.content.ContentResolver#query ContentResolver.query()}, dengan menggunakan Penyedia Kamus Pengguna
    -+    sebagai contoh. Query klien penyedia serupa dengan query SQL, dan berisi satu
    -+    set kolom yang akan dihasilkan, satu set kriteria pemilihan, dan urutan sortir.
    -+</p>
    -+<p>
    -+    Set kolom yang harus dikembalikan query disebut dengan <strong>proyeksi</strong>
    -+    (variabel <code>mProjection</code>).
    -+</p>
    -+<p>
    -+    Ekspresi yang menetapkan baris yang harus diambil dipecah menjadi klausa pemilihan dan
    -+    argumen pemilihan. Klausa pemilihan adalah kombinasi ekspresi logis dan boolean,
    -+    nama kolom, dan nilai (variabel <code>mSelectionClause</code>). Jika Anda menetapkan
    -+    parameter <code>?</code> yang bisa diganti, sebagai ganti nilai, metode query akan mengambil nilai
    -+    dari larik argumen pemilihan (variabel <code>mSelectionArgs</code>).
    -+</p>
    -+<p>
    -+    Dalam cuplikan berikutnya, jika pengguna tidak memasukkan sebuah kata, klausa pemilihan akan diatur ke
    -+    <code>null</code>, dan query menghasilkan semua kata dalam penyedia. Jika pengguna memasukkan
    -+    sebuah kata, klausa pemilihan akan diatur ke <code>UserDictionary.Words.WORD + " = ?"</code> dan
    -+    elemen pertama larik argumen pemilihan diatur ke kata yang dimasukkan pengguna.
    -+</p>
    -+<pre class="prettyprint">
    -+/*
    -+ * This defines a one-element String array to contain the selection argument.
    -+ */
    -+String[] mSelectionArgs = {""};
    -+
    -+// Gets a word from the UI
    -+mSearchString = mSearchWord.getText().toString();
    -+
    -+// Remember to insert code here to check for invalid or malicious input.
    -+
    -+// If the word is the empty string, gets everything
    -+if (TextUtils.isEmpty(mSearchString)) {
    -+    // Setting the selection clause to null will return all words
    -+    mSelectionClause = null;
    -+    mSelectionArgs[0] = "";
    -+
    -+} else {
    -+    // Constructs a selection clause that matches the word that the user entered.
    -+    mSelectionClause = UserDictionary.Words.WORD + " = ?";
    -+
    -+    // Moves the user's input string to the selection arguments.
    -+    mSelectionArgs[0] = mSearchString;
    -+
    -+}
    -+
    -+// Does a query against the table and returns a Cursor object
    -+mCursor = getContentResolver().query(
    -+    UserDictionary.Words.CONTENT_URI,  // The content URI of the words table
    -+    mProjection,                       // The columns to return for each row
    -+    mSelectionClause                   // Either null, or the word the user entered
    -+    mSelectionArgs,                    // Either empty, or the string the user entered
    -+    mSortOrder);                       // The sort order for the returned rows
    -+
    -+// Some providers return null if an error occurs, others throw an exception
    -+if (null == mCursor) {
    -+    /*
    -+     * Insert code here to handle the error. Be sure not to use the cursor! You may want to
    -+     * call android.util.Log.e() to log this error.
    -+     *
    -+     */
    -+// If the Cursor is empty, the provider found no matches
    -+} else if (mCursor.getCount() &lt; 1) {
    -+
    -+    /*
    -+     * Insert code here to notify the user that the search was unsuccessful. This isn't necessarily
    -+     * an error. You may want to offer the user the option to insert a new row, or re-type the
    -+     * search term.
    -+     */
    -+
    -+} else {
    -+    // Insert code here to do something with the results
    -+
    -+}
    -+</pre>
    -+<p>
    -+    Query ini analog dengan pernyataan SQL:
    -+</p>
    -+<pre>
    -+SELECT _ID, word, locale FROM words WHERE word = &lt;userinput&gt; ORDER BY word ASC;
    -+</pre>
    -+<p>
    -+    Dalam pernyataan SQL ini, nama kolom yang sesungguhnya digunakan sebagai ganti konstanta kelas kontrak.
    -+</p>
    -+<h4 id="Injection">Melindungi dari input merusak</h4>
    -+<p>
    -+    Jika data dikelola oleh penyedia konten berada dalam database SQL, memasukkan data tak dipercaya eksternal
    -+    ke dalam pernyataan SQL mentah bisa menyebabkan injeksi SQL.
    -+</p>
    -+<p>
    -+    Perhatikan klausa pemilihan ini:
    -+</p>
    -+<pre>
    -+// Constructs a selection clause by concatenating the user's input to the column name
    -+String mSelectionClause =  "var = " + mUserInput;
    -+</pre>
    -+<p>
    -+    Jika melakukannya, Anda akan membuat pengguna menyambungkan SQL merusak ke pernyataan SQL Anda.
    -+    Misalnya, pengguna bisa memasukkan "nothing; DROP TABLE *;"  untuk <code>mUserInput</code>, yang
    -+    akan menghasilkan klausa pemilihan <code>var = nothing; DROP TABLE *;</code>. Karena
    -+    klausa pemilihan diperlakukan sebagai pernyataan SQL, hal ini bisa menyebabkan penyedia itu menghapus semua
    -+    tabel dalam database SQLite yang mendasarinya (kecuali penyedia disiapkan untuk menangkap upaya
    -+    <a href="http://en.wikipedia.org/wiki/SQL_injection">injeksi SQL</a>).
    -+</p>
    -+<p>
    -+    Untuk menghindari masalah ini, gunakan klausa pemilihan yang menggunakan <code>?</code> sebagai
    -+    parameter yang bisa diganti dan larik argumen pemilihan yang terpisah. Bila Anda melakukannya, input pengguna
    -+    akan dibatasi secara langsung pada query agar tidak ditafsirkan sebagai bagian dari pernyataan SQL.
    -+    Karena tidak diperlakukan sebagai SQL, input pengguna tidak bisa menyuntikkan SQL merusak. Sebagai ganti menggunakan
    -+    penyambungan untuk menyertakan input pengguna, gunakan klausa pemilihan ini:
    -+</p>
    -+<pre>
    -+// Constructs a selection clause with a replaceable parameter
    -+String mSelectionClause =  "var = ?";
    -+</pre>
    -+<p>
    -+    Buat larik argumen pemilihan seperti ini:
    -+</p>
    -+<pre>
    -+// Defines an array to contain the selection arguments
    -+String[] selectionArgs = {""};
    -+</pre>
    -+<p>
    -+    Masukkan nilai dalam larik argumen pemilihan seperti ini:
    -+</p>
    -+<pre>
    -+// Sets the selection argument to the user's input
    -+selectionArgs[0] = mUserInput;
    -+</pre>
    -+<p>
    -+    Sebuah klausa pemilihan yang menggunakan <code>?</code> sebagai parameter yang bisa diganti dan sebuah larik
    -+    argumen pemilihan adalah cara yang lebih disukai untuk menyebutkan pemilihan, sekalipun penyedia tidak
    -+    dibuat berdasarkan database SQL.
    -+</p>
    -+<!-- Displaying the results -->
    -+<h3 id="DisplayResults">Menampilkan hasil query</h3>
    -+<p>
    -+    Metode klien {@link android.content.ContentResolver#query ContentResolver.query()} selalu
    -+    menghasilkan {@link android.database.Cursor} berisi kolom-kolom yang ditetapkan oleh
    -+    proyeksi query untuk baris yang cocok dengan kriteria pemilihan query. Objek
    -+    {@link android.database.Cursor} menyediakan akses baca acak ke baris dan kolom yang
    -+    dimuatnya. Dengan metode {@link android.database.Cursor}, Anda bisa mengulang baris-baris dalam
    -+    hasil, menentukan tipe data tiap kolom, mengambil data dari kolom, dan memeriksa
    -+    properti lain dari hasil. Beberapa implementasi {@link android.database.Cursor}
    -+    akan memperbarui objek secara otomatis bila data penyedia berubah, atau memicu metode dalam objek pengamat
    -+    bila {@link android.database.Cursor} berubah, atau keduanya.
    -+</p>
    -+<p class="note">
    -+    <strong>Catatan:</strong> Penyedia bisa membatasi akses ke kolom berdasarkan sifat
    -+    objek yang membuat query. Misalnya, Penyedia Kontak membatasi akses untuk beberapa kolom pada
    -+    adaptor sinkronisasi, sehingga tidak akan mengembalikannya ke aktivitas atau layanan.
    -+</p>
    -+<p>
    -+    Jika tidak ada baris yang cocok dengan kriteria pemilihan, penyedia
    -+    akan mengembalikan objek {@link android.database.Cursor} dengan
    -+    {@link android.database.Cursor#getCount Cursor.getCount()} adalah 0 (kursor kosong).
    -+</p>
    -+<p>
    -+    Jika terjadi kesalahan internal, hasil query akan bergantung pada penyedia tertentu. Penyedia bisa
    -+    memilih untuk menghasilkan <code>null</code>, atau melontarkan {@link java.lang.Exception}.
    -+</p>
    -+<p>
    -+    Karena {@link android.database.Cursor} adalah "daftar" baris, cara yang cocok untuk menampilkan
    -+    konten {@link android.database.Cursor} adalah mengaitkannya dengan {@link android.widget.ListView}
    -+    melalui {@link android.widget.SimpleCursorAdapter}.
    -+</p>
    -+<p>
    -+    Cuplikan berikut melanjutkan kode dari cuplikan sebelumnya. Cuplikan ini membuat
    -+    objek {@link android.widget.SimpleCursorAdapter} berisi {@link android.database.Cursor}
    -+    yang diambil oleh query, dan mengatur objek ini menjadi adaptor bagi
    -+    {@link android.widget.ListView}:
    -+</p>
    -+<pre class="prettyprint">
    -+// Defines a list of columns to retrieve from the Cursor and load into an output row
    -+String[] mWordListColumns =
    -+{
    -+    UserDictionary.Words.WORD,   // Contract class constant containing the word column name
    -+    UserDictionary.Words.LOCALE  // Contract class constant containing the locale column name
    -+};
    -+
    -+// Defines a list of View IDs that will receive the Cursor columns for each row
    -+int[] mWordListItems = { R.id.dictWord, R.id.locale};
    -+
    -+// Creates a new SimpleCursorAdapter
    -+mCursorAdapter = new SimpleCursorAdapter(
    -+    getApplicationContext(),               // The application's Context object
    -+    R.layout.wordlistrow,                  // A layout in XML for one row in the ListView
    -+    mCursor,                               // The result from the query
    -+    mWordListColumns,                      // A string array of column names in the cursor
    -+    mWordListItems,                        // An integer array of view IDs in the row layout
    -+    0);                                    // Flags (usually none are needed)
    -+
    -+// Sets the adapter for the ListView
    -+mWordList.setAdapter(mCursorAdapter);
    -+</pre>
    -+<p class="note">
    -+    <strong>Catatan:</strong> Untuk mendukung {@link android.widget.ListView} dengan
    -+    {@link android.database.Cursor}, kursor harus berisi kolom bernama <code>_ID</code>.
    -+    Karena itu, query yang ditampilkan sebelumnya mengambil kolom <code>_ID</code> untuk
    -+    tabel "words", walaupun {@link android.widget.ListView} tidak menampilkannya.
    -+    Pembatasan ini juga menjelaskan mengapa sebagian besar penyedia memiliki kolom <code>_ID</code> untuk masing-masing
    -+    tabelnya.
    -+</p>
    -+
    -+        <!-- Getting data from query results -->
    -+<h3 id="GettingResults">Mendapatkan data dari hasil query</h3>
    -+<p>
    -+    Daripada sekadar menampilkan hasil query, Anda bisa menggunakannya untuk tugas-tugas lain. Misalnya,
    -+    Anda bisa mengambil ejaan dari kamus pengguna kemudian mencarinya dalam
    -+    penyedia lain. Caranya, ulangi baris-baris dalam {@link android.database.Cursor}:
    -+</p>
    -+<pre class="prettyprint">
    -+
    -+// Determine the column index of the column named "word"
    -+int index = mCursor.getColumnIndex(UserDictionary.Words.WORD);
    -+
    -+/*
    -+ * Only executes if the cursor is valid. The User Dictionary Provider returns null if
    -+ * an internal error occurs. Other providers may throw an Exception instead of returning null.
    -+ */
    -+
    -+if (mCursor != null) {
    -+    /*
    -+     * Moves to the next row in the cursor. Before the first movement in the cursor, the
    -+     * "row pointer" is -1, and if you try to retrieve data at that position you will get an
    -+     * exception.
    -+     */
    -+    while (mCursor.moveToNext()) {
    -+
    -+        // Gets the value from the column.
    -+        newWord = mCursor.getString(index);
    -+
    -+        // Insert code here to process the retrieved word.
    -+
    -+        ...
    -+
    -+        // end of while loop
    -+    }
    -+} else {
    -+
    -+    // Insert code here to report an error if the cursor is null or the provider threw an exception.
    -+}
    -+</pre>
    -+<p>
    -+    Implementasi {@link android.database.Cursor} berisi beberapa metode "get" untuk
    -+    mengambil berbagai tipe data dari objek. Misalnya, cuplikan sebelumnya
    -+    menggunakan {@link android.database.Cursor#getString getString()}. Implementasi juga memiliki
    -+    metode {@link android.database.Cursor#getType getType()} yang menghasilkan nilai yang menunjukkan
    -+    tipe data kolom.
    -+</p>
    -+
    -+
    -+    <!-- Requesting permissions -->
    -+<h2 id="Permissions">Izin Penyedia Konten</h2>
    -+<p>
    -+    Aplikasi penyedia bisa menetapkan izin yang harus dimiliki aplikasi lain untuk
    -+    mengakses data penyedia. Izin ini akan memastikan bahwa pengguna mengetahui data
    -+    yang coba diakses oleh aplikasi. Berdasarkan ketentuan penyedia, aplikasi lain
    -+    meminta izin yang diperlukannya untuk mengakses penyedia. Pengguna akhir akan melihat
    -+    izin yang diminta saat menginstal aplikasi.
    -+</p>
    -+<p>
    -+    Jika aplikasi penyedia tidak menetapkan izin apa pun, maka aplikasi lain tidak memiliki
    -+    akses ke data penyedia. Akan tetapi, komponen-komponen dalam aplikasi penyedia selalu memiliki
    -+    akses penuh untuk baca dan tulis, izin apa pun yang ditetapkan.
    -+</p>
    -+<p>
    -+    Seperti disebutkan sebelumnya, Penyedia Kamus Pengguna mensyaratkan izin
    -+    <code>android.permission.READ_USER_DICTIONARY</code> untuk mengambil data darinya.
    -+    Penyedia memiliki izin <code>android.permission.WRITE_USER_DICTIONARY</code>
    -+    yang terpisah untuk menyisipkan, memperbarui, atau menghapus data.
    -+</p>
    -+<p>
    -+    Untuk mendapatkan izin yang diperlukan untuk mengakses penyedia, aplikasi memintanya dengan elemen
    -+<code><a href="{@docRoot}guide/topics/manifest/uses-permission-element.html">&lt;uses-permission&gt;</a></code>
    -+    dalam file manifesnya. Bila Android Package Manager memasang aplikasi, pengguna
    -+    harus menyetujui semua izin yang diminta aplikasi. Jika pengguna menyetujui semuanya,
    -+    Package Manager akan melanjutkan instalasi; jika pengguna tidak menyetujui, Package Manager
    -+    akan membatalkan instalasi.
    -+</p>
    -+<p>
    -+    Elemen
    -+<code><a href="{@docRoot}guide/topics/manifest/uses-permission-element.html">&lt;uses-permission&gt;</a></code>
    -+    berikut meminta akses baca ke Penyedia Kamus Pengguna:
    -+</p>
    -+<pre>
    -+    &lt;uses-permission android:name="android.permission.READ_USER_DICTIONARY"&gt;
    -+</pre>
    -+<p>
    -+    Dampak izin pada akses penyedia dijelaskan secara lebih detail dalam panduan
    -+    <a href="{@docRoot}guide/topics/security/security.html">Keamanan dan Izin</a>.
    -+</p>
    -+
    -+
    -+<!-- Inserting, Updating, and Deleting Data -->
    -+<h2 id="Modifications">Menyisipkan, Memperbarui, dan Menghapus Data</h2>
    -+<p>
    -+    Lewat cara yang sama dengan cara mengambil data dari penyedia, Anda juga menggunakan interaksi antara
    -+    klien penyedia dan {@link android.content.ContentProvider} penyedia untuk memodifikasi data.
    -+    Anda memanggil metode {@link android.content.ContentResolver} dengan argumen yang diteruskan ke
    -+    metode {@link android.content.ContentProvider} yang sesuai. Penyedia dan klien penyedia
    -+    menangani secara otomatis keamanan dan komunikasi antar-proses.
    -+</p>
    -+<h3 id="Inserting">Menyisipkan data</h3>
    -+<p>
    -+    Untuk menyisipkan data ke penyedia, Anda memanggil metode
    -+    {@link android.content.ContentResolver#insert ContentResolver.insert()}.
    -+ Metode ini menyisipkan sebuah baris baru ke penyedia itu dan menghasilkan URI konten untuk baris itu.
    -+    Cuplikan ini menampilkan cara menyisipkan sebuah kata baru ke Penyedia Kamus Pengguna:
    -+</p>
    -+<pre class="prettyprint">
    -+// Defines a new Uri object that receives the result of the insertion
    -+Uri mNewUri;
    -+
    -+...
    -+
    -+// Defines an object to contain the new values to insert
    -+ContentValues mNewValues = new ContentValues();
    -+
    -+/*
    -+ * Sets the values of each column and inserts the word. The arguments to the "put"
    -+ * method are "column name" and "value"
    -+ */
    -+mNewValues.put(UserDictionary.Words.APP_ID, "example.user");
    -+mNewValues.put(UserDictionary.Words.LOCALE, "en_US");
    -+mNewValues.put(UserDictionary.Words.WORD, "insert");
    -+mNewValues.put(UserDictionary.Words.FREQUENCY, "100");
    -+
    -+mNewUri = getContentResolver().insert(
    -+    UserDictionary.Word.CONTENT_URI,   // the user dictionary content URI
    -+    mNewValues                          // the values to insert
    -+);
    -+</pre>
    -+<p>
    -+    Data untuk baris baru masuk ke dalam satu objek {@link android.content.ContentValues}, yang
    -+    serupa bentuknya dengan kursor satu-baris. Kolom dalam objek ini tidak perlu memiliki
    -+    tipe data yang sama, dan jika Anda tidak ingin menetapkan nilai sama sekali, Anda bisa mengatur kolom
    -+    ke <code>null</code> dengan menggunakan {@link android.content.ContentValues#putNull ContentValues.putNull()}.
    -+</p>
    -+<p>
    -+    Cuplikan ini tidak menambahkan kolom <code>_ID</code>, karena kolom ini dipelihara
    -+    secara otomatis. Penyedia menetapkan sebuah nilai unik <code>_ID</code> ke setiap baris yang
    -+    ditambahkan. Penyedia biasanya menggunakan nilai ini sebagai kunci utama tabel.
    -+</p>
    -+<p>
    -+    URI konten yang dihasilkan dalam <code>newUri</code> akan mengidentifikasi baris yang baru ditambahkan, dengan
    -+    format berikut:
    -+</p>
    -+<pre>
    -+content://user_dictionary/words/&lt;id_value&gt;
    -+</pre>
    -+<p>
    -+    <code>&lt;id_value&gt;</code> adalah konten <code>_ID</code> untuk baris baru.
    -+    Kebanyakan penyedia bisa mendeteksi bentuk URI konten ini secara otomatis kemudian melakukan
    -+    operasi yang diminta pada baris tersebut.
    -+</p>
    -+<p>
    -+    Untuk mendapatkan nilai <code>_ID</code> dari {@link android.net.Uri} yang dihasilkan, panggil
    -+    {@link android.content.ContentUris#parseId ContentUris.parseId()}.
    -+</p>
    -+<h3 id="Updating">Memperbarui data</h3>
    -+<p>
    -+    Untuk memperbarui sebuah baris, gunakan objek {@link android.content.ContentValues} dengan
    -+    nilai-nilai yang diperbarui, persis seperti yang Anda lakukan pada penyisipan, dan kriteria pemilihan persis seperti yang Anda lakukan pada query.
    -+    Metode klien yang Anda gunakan adalah
    -+    {@link android.content.ContentResolver#update ContentResolver.update()}. Anda hanya perlu menambahkan
    -+    nilai-nilai ke objek {@link android.content.ContentValues} untuk kolom yang sedang Anda perbarui. Jika Anda
    -+    ingin membersihkan konten kolom, aturlah nilai ke <code>null</code>.
    -+</p>
    -+<p>
    -+    Cuplikan berikut mengubah semua baris yang kolom lokalnya memiliki bahasa "en" ke
    -+    lokal <code>null</code>. Nilai hasil adalah jumlah baris yang diperbarui:
    -+</p>
    -+<pre>
    -+// Defines an object to contain the updated values
    -+ContentValues mUpdateValues = new ContentValues();
    -+
    -+// Defines selection criteria for the rows you want to update
    -+String mSelectionClause = UserDictionary.Words.LOCALE +  "LIKE ?";
    -+String[] mSelectionArgs = {"en_%"};
    -+
    -+// Defines a variable to contain the number of updated rows
    -+int mRowsUpdated = 0;
    -+
    -+...
    -+
    -+/*
    -+ * Sets the updated value and updates the selected words.
    -+ */
    -+mUpdateValues.putNull(UserDictionary.Words.LOCALE);
    -+
    -+mRowsUpdated = getContentResolver().update(
    -+    UserDictionary.Words.CONTENT_URI,   // the user dictionary content URI
    -+    mUpdateValues                       // the columns to update
    -+    mSelectionClause                    // the column to select on
    -+    mSelectionArgs                      // the value to compare to
    -+);
    -+</pre>
    -+<p>
    -+    Anda juga harus membersihkan input pengguna bila memanggil
    -+    {@link android.content.ContentResolver#update ContentResolver.update()}. Untuk mengetahui selengkapnya tentang
    -+    hal ini, bacalah bagian <a href="#Injection">Melindungi dari input merusak</a>.
    -+</p>
    -+<h3 id="Deleting">Menghapus data</h3>
    -+<p>
    -+    Menghapus baris serupa dengan mengambil baris data: Anda menetapkan kriteria pemilihan untuk baris
    -+    yang ingin Anda hapus dan metode klien akan menghasilkan jumlah baris yang dihapus.
    -+    Cuplikan berikut menghapus baris yang appid-nya sama dengan "user". Metode menghasilkan
    -+    jumlah baris yang dihapus.
    -+</p>
    -+<pre>
    -+
    -+// Defines selection criteria for the rows you want to delete
    -+String mSelectionClause = UserDictionary.Words.APP_ID + " LIKE ?";
    -+String[] mSelectionArgs = {"user"};
    -+
    -+// Defines a variable to contain the number of rows deleted
    -+int mRowsDeleted = 0;
    -+
    -+...
    -+
    -+// Deletes the words that match the selection criteria
    -+mRowsDeleted = getContentResolver().delete(
    -+    UserDictionary.Words.CONTENT_URI,   // the user dictionary content URI
    -+    mSelectionClause                    // the column to select on
    -+    mSelectionArgs                      // the value to compare to
    -+);
    -+</pre>
    -+<p>
    -+    Anda juga harus membersihkan input pengguna bila memanggil
    -+    {@link android.content.ContentResolver#delete ContentResolver.delete()}. Untuk mengetahui selengkapnya tentang
    -+    hal ini, bacalah bagian <a href="#Injection">Melindungi dari input merusak</a>.
    -+</p>
    -+<!-- Provider Data Types -->
    -+<h2 id="DataTypes">Tipe Data Penyedia</h2>
    -+<p>
    -+    Penyedia konten bisa menawarkan berbagai tipe data. Penyedia Kamus Pengguna hanya menawarkan
    -+    teks, namun penyedia juga bisa menawarkan format berikut:
    -+</p>
    -+    <ul>
    -+        <li>
    -+            integer
    -+        </li>
    -+        <li>
    -+            long integer (long)
    -+        </li>
    -+        <li>
    -+            floating point
    -+        </li>
    -+        <li>
    -+            long floating point (double)
    -+        </li>
    -+    </ul>
    -+<p>
    -+    Tipe data lain yang sering digunakan penyedia adalah Binary Large OBject (BLOB) yang diimplementasikan sebagai
    -+    larik byte 64 KB. Anda bisa melihat tipe data yang tersedia dengan memperhatikan metode "get"
    -+    kelas {@link android.database.Cursor}.
    -+</p>
    -+<p>
    -+    Tipe data tiap kolom dalam penyedia biasanya tercantum dalam dokumentasinya.
    -+    Tipe data untuk Penyedia Kamus Pengguna tercantum dalam dokumentasi acuan
    -+    untuk kelas kontraknya {@link android.provider.UserDictionary.Words} (kelas kontrak
    -+    dijelaskan di bagian <a href="#ContractClasses">Kelas-kelas Kontrak</a>).
    -+    Anda juga bisa menentukan tipe data dengan memanggil {@link android.database.Cursor#getType
    -+    Cursor.getType()}.
    -+</p>
    -+<p>
    -+    Penyedia juga memelihara informasi tipe data MIME untuk tiap URI konten yang didefinisikannya. Anda bisa
    -+    menggunakan informasi tipe MIME untuk mengetahui apakah aplikasi Anda bisa menangani data yang
    -+    disediakan penyedia, atau memilih tipe penanganan berdasarkan tipe MIME. Anda biasanya memerlukan
    -+    tipe MIME saat menggunakan penyedia yang berisi
    -+    struktur atau file data yang kompleks. Misalnya, tabel {@link android.provider.ContactsContract.Data}
    -+    dalam Penyedia Kontak menggunakan tipe MIME untuk memberi label tipe data kontak yang disimpan di tiap
    -+    baris. Untuk mendapatkan tipe MIME yang sesuai dengan URI konten, panggil
    -+    {@link android.content.ContentResolver#getType ContentResolver.getType()}.
    -+</p>
    -+<p>
    -+    Bagian <a href="#MIMETypeReference">Acuan Tipe MIME</a> menerangkan
    -+    sintaks tipe MIME baik yang standar maupun custom.
    -+</p>
    -+
    -+
    -+<!-- Alternative Forms of Provider Access -->
    -+<h2 id="AltForms">Bentuk-Bentuk Alternatif Akses Penyedia</h2>
    -+<p>
    -+    Tiga bentuk alternatif akses penyedia adalah penting dalam pengembangan aplikasi:
    -+</p>
    -+<ul>
    -+    <li>
    -+        <a href="#Batch">Akses batch</a>: Anda bisa membuat sebuah batch panggilan akses dengan metode-metode dalam
    -+        kelas {@link android.content.ContentProviderOperation}, kemudian menerapkannya dengan
    -+        {@link android.content.ContentResolver#applyBatch ContentResolver.applyBatch()}.
    -+    </li>
    -+    <li>
    -+        Query asinkron: Anda harus melakukan query dalam thread terpisah. Satu cara melakukannya adalah
    -+        menggunakan objek {@link android.content.CursorLoader}. Contoh-contoh dalam panduan
    -+        <a href="{@docRoot}guide/components/loaders.html">Loader</a> memperagakan
    -+        cara melakukannya.
    -+    </li>
    -+    <li>
    -+        <a href="#Intents">Akses data melalui intent</a>: Walaupun tidak bisa mengirim intent
    -+        ke penyedia secara langsung, Anda bisa mengirim intent ke aplikasi penyedia, yang
    -+        biasanya paling lengkap dibekali untuk memodifikasi data penyedia.
    -+    </li>
    -+</ul>
    -+<p>
    -+    Akses batch dan modifikasi melalui intent dijelaskan dalam bagian-bagian berikut.
    -+</p>
    -+<h3 id="Batch">Akses batch</h3>
    -+<p>
    -+    Akses batch ke penyedia berguna untuk menyisipkan baris dalam jumlah besar, atau menyisipkan
    -+    baris ke dalam beberapa tabel dalam panggilan metode yang sama, atau biasanya melakukan satu set
    -+    operasi lintas batas proses sebagai transaksi (operasi atomik).
    -+</p>
    -+<p>
    -+    Untuk mengakses penyedia dalam "mode batch",
    -+    buat satu larik objek {@link android.content.ContentProviderOperation}, kemudian
    -+    kirim larik itu ke penyedia konten dengan
    -+    {@link android.content.ContentResolver#applyBatch ContentResolver.applyBatch()}. Anda meneruskan
    -+    <em>otoritas</em> penyedia konten ke metode ini, daripada URI konten tertentu.
    -+    Ini memungkinkan tiap objek {@link android.content.ContentProviderOperation} dalam larik untuk bekerja
    -+    terhadap tabel yang berbeda. Panggilan ke {@link android.content.ContentResolver#applyBatch
    -+    ContentResolver.applyBatch()} menghasilkan satu larik hasil.
    -+</p>
    -+<p>
    -+    Keterangan kelas kontrak {@link android.provider.ContactsContract.RawContacts}
    -+    menyertakan cuplikan kode yang memperagakan penyisipan batch. Contoh aplikasi
    -+    <a href="{@docRoot}resources/samples/ContactManager/index.html">Contacts Manager</a>
    -+    berisi contoh akses batch dalam file sumber <code>ContactAdder.java</code>-nya
    -+.
    -+</p>
    -+<div class="sidebox-wrapper">
    -+<div class="sidebox">
    -+<h2>Menampilkan data dengan aplikasi pembantu</h2>
    -+<p>
    -+    Jika aplikasi Anda <em>memang</em> memiliki izin akses, Anda masih mungkin perlu menggunakan
    -+    intent untuk menampilkan data dalam aplikasi lain. Misalnya, aplikasi Kalender menerima
    -+    intent {@link android.content.Intent#ACTION_VIEW}, yang menampilkan tanggal atau kejadian tertentu.
    -+    Hal ini memungkinkan Anda menampilkan informasi kalender tanpa harus membuat UI sendiri.
    -+    Untuk mengetahui selengkapnya tentang fitur ini, lihat panduan
    -+    <a href="{@docRoot}guide/topics/providers/calendar-provider.html">Penyedia Kalender</a>.
    -+</p>
    -+<p>
    -+    Aplikasi yang Anda kirimi intent tidak harus aplikasi
    -+    yang terkait dengan penyedia. Misalnya, Anda bisa mengambil satu kontak dari
    -+    Penyedia Kontak, kemudian mengirim intent {@link android.content.Intent#ACTION_VIEW}
    -+    berisi URI konten untuk gambar kontak itu ke penampil gambar.
    -+</p>
    -+</div>
    -+</div>
    -+<h3 id="Intents">Akses data melalui intent</h3>
    -+<p>
    -+    Intent bisa menyediakan akses tidak langsung ke penyedia konten. Anda memperbolehkan pengguna mengakses
    -+    data dalam penyedia sekalipun aplikasi Anda tidak memiliki izin akses, baik dengan
    -+    mendapatkan intent yang dihasilkan aplikasi yang memiliki izin, atau dengan mengaktifkan
    -+    aplikasi yang memiliki izin dan membiarkan pengguna melakukan pekerjaan di dalamnya.
    -+</p>
    -+<h4>Mendapatkan akses dengan izin sementara</h4>
    -+<p>
    -+    Anda bisa mengakses data dalam penyedia konten, sekalipun tidak memiliki
    -+    izin akses yang sesuai, dengan mengirimkan intent ke aplikasi yang memang memiliki izin dan
    -+    menerima hasil berupa intent berisi izin "URI".
    -+    Inilah izin untuk URI konten tertentu yang berlaku hingga aktivitas yang menerima
    -+    izin selesai. Aplikasi yang memiliki izin tetap akan memberikan
    -+    izin sementara dengan mengatur flag dalam intent yang dihasilkan:
    -+</p>
    -+<ul>
    -+    <li>
    -+        <strong>Izin baca:</strong>
    -+        {@link android.content.Intent#FLAG_GRANT_READ_URI_PERMISSION}
    -+    </li>
    -+    <li>
    -+        <strong>Izin tulis:</strong>
    -+        {@link android.content.Intent#FLAG_GRANT_WRITE_URI_PERMISSION}
    -+    </li>
    -+</ul>
    -+<p class="note">
    -+    <strong>Catatan:</strong> Flag ini tidak memberikan akses baca atau tulis umum ke penyedia
    -+    yang otoritasnya dimuat dalam URI konten. Aksesnya hanya untuk URI itu sendiri.
    -+</p>
    -+<p>
    -+    Penyedia mendefinisikan izin URI untuk URI konten dalam manifesnya, dengan menggunakan atribut
    -+<code><a href="{@docRoot}guide/topics/manifest/provider-element.html#gprmsn">android:grantUriPermission</a></code>
    -+    dari elemen
    -+<code><a href="{@docRoot}guide/topics/manifest/provider-element.html">&lt;provider&gt;</a></code>
    -+,   serta elemen anak
    -+<code><a href="{@docRoot}guide/topics/manifest/grant-uri-permission-element.html">&lt;grant-uri-permission&gt;</a></code>
    -+    dari elemen
    -+<code><a href="{@docRoot}guide/topics/manifest/provider-element.html">&lt;provider&gt;</a></code>.
    -+ Mekanisme izin URI dijelaskan secara lebih detail dalam panduan
    -+    <a href="{@docRoot}guide/topics/security/security.html">Keamanan dan Izin</a>,
    -+    di bagian "Izin URI".
    -+</p>
    -+<p>
    -+    Misalnya, Anda bisa mengambil data untuk satu kontak di Penyedia Kontak, sekalipun tidak
    -+    memiliki izin {@link android.Manifest.permission#READ_CONTACTS}. Anda mungkin ingin melakukan
    -+    ini dalam aplikasi yang mengirim kartu ucapan elektronik ke seorang kenalan pada hari ulang tahunnya. Sebagai ganti
    -+    meminta {@link android.Manifest.permission#READ_CONTACTS}, yang memberi Anda akses ke semua
    -+    kontak pengguna dan semua informasinya, Anda lebih baik membiarkan pengguna mengontrol
    -+    kontak-kontak yang akan digunakan oleh aplikasi Anda. Caranya, gunakan proses berikut:
    -+</p>
    -+<ol>
    -+    <li>
    -+        Aplikasi Anda akan mengirim intent berisi tindakan
    -+        {@link android.content.Intent#ACTION_PICK} dan tipe MIME "contacts"
    -+        {@link android.provider.ContactsContract.RawContacts#CONTENT_ITEM_TYPE}, dengan menggunakan
    -+        metode {@link android.app.Activity#startActivityForResult
    -+        startActivityForResult()}.
    -+    </li>
    -+    <li>
    -+        Karena intent ini cocok dengan filter intent untuk
    -+        aktivitas "pemilihan" aplikasi People, aktivitas akan muncul ke latar depan.
    -+    </li>
    -+    <li>
    -+        Dalam aktivitas pemilihan, pengguna memilih sebuah
    -+        kontak untuk diperbarui. Bila ini terjadi, aktivitas pemilihan akan memanggil
    -+        {@link android.app.Activity#setResult setResult(resultcode, intent)}
    -+        untuk membuat intent yang akan diberikan kembali ke aplikasi Anda. Intent itu berisi URI konten
    -+        kontak yang dipilih pengguna, dan flag "extras"
    -+        {@link android.content.Intent#FLAG_GRANT_READ_URI_PERMISSION}. Semua flag ini memberikan
    -+        izin URI ke aplikasi Anda untuk membaca data kontak yang ditunjuk oleh
    -+        URI konten. Aktivitas pemilihan kemudian memanggil {@link android.app.Activity#finish()} untuk
    -+        mengembalikan kontrol ke aplikasi Anda.
    -+    </li>
    -+    <li>
    -+        Aktivitas Anda akan kembali ke latar depan, dan sistem memanggil metode
    -+        {@link android.app.Activity#onActivityResult onActivityResult()}
    -+        aktivitas Anda. Metode ini menerima intent yang dihasilkan oleh aktivitas pemilihan dalam
    -+        aplikasi People.
    -+    </li>
    -+    <li>
    -+        Dengan URI konten dari intent yang dihasilkan, Anda bisa membaca data kontak
    -+        dari Penyedia Kontak, sekalipun Anda tidak meminta izin akses baca tetap
    -+        ke penyedia dalam manifes Anda. Anda kemudian bisa mendapatkan informasi hari ulang tahun si kontak
    -+        atau alamat emailnya, kemudian mengirim kartu ucapan elektronik.
    -+    </li>
    -+</ol>
    -+<h4>Menggunakan aplikasi lain</h4>
    -+<p>
    -+    Satu cara mudah agar pengguna bisa memodifikasi data yang izin aksesnya tidak Anda miliki adalah
    -+    mengaktifkan aplikasi yang memiliki izin dan membiarkan pengguna melakukan pekerjaannya di sana.
    -+</p>
    -+<p>
    -+    Misalnya, aplikasi Kalender menerima
    -+    intent {@link android.content.Intent#ACTION_INSERT}, yang memungkinkan Anda mengaktifkan
    -+    UI penyisipan aplikasi itu. Anda bisa meneruskan data "extras" dalam intent ini, yang
    -+    digunakan aplikasi untuk mengisi dahulu UI-nya. Karena kejadian berulang memiliki sintaks yang rumit,
    -+    cara yang lebih disukai untuk menyisipkan kejadian ke dalam Penyedia Kalender adalah mengaktifkan aplikasi Kalender dengan
    -+    {@link android.content.Intent#ACTION_INSERT}, kemudian membiarkan pengguna menyisipkan kejadian di sana.
    -+</p>
    -+<!-- Contract Classes -->
    -+<h2 id="ContractClasses">Kelas-kelas Kontrak</h2>
    -+<p>
    -+    Kelas kontrak mendefinisikan konstanta yang membantu aplikasi menggunakan URI konten, nama
    -+    kolom, tindakan intent, dan fitur lain pada penyedia konten. Kelas kontrak tidak
    -+    disertakan secara otomatis bersama penyedia; pengembang penyedia harus mendefinisikannya kemudian
    -+    membuatnya tersedia bagi pengembang lain. Banyak penyedia yang disertakan pada platform Android
    -+    memiliki kelas kontrak yang sesuai dalam {@link android.provider} paketnya.
    -+</p>
    -+<p>
    -+    Misalnya, Penyedia Kamus Pengguna memiliki kelas kontrak
    -+    {@link android.provider.UserDictionary} yang berisi URI konten dan konstanta nama kolom. URI
    -+    konten untuk tabel "words" didefinisikan dalam konstanta
    -+    {@link android.provider.UserDictionary.Words#CONTENT_URI UserDictionary.Words.CONTENT_URI}.
    -+    Kelas {@link android.provider.UserDictionary.Words} juga berisi konstanta nama kolom,
    -+    yang digunakan dalam cuplikan contoh pada panduan ini. Misalnya, sebuah proyeksi query bisa
    -+    didefinisikan sebagai:
    -+</p>
    -+<pre>
    -+String[] mProjection =
    -+{
    -+    UserDictionary.Words._ID,
    -+    UserDictionary.Words.WORD,
    -+    UserDictionary.Words.LOCALE
    -+};
    -+</pre>
    -+<p>
    -+    Kelas kontrak lain adalah {@link android.provider.ContactsContract} untuk Penyedia Kontak.
    -+    Dokumentasi acuan untuk kelas ini menyertakan contoh cuplikan kode. Salah satu
    -+    subkelasnya, {@link android.provider.ContactsContract.Intents.Insert}, adalah
    -+    kelas kontrak yang berisi konstanta untuk intent dan data intent.
    -+</p>
    -+
    -+
    -+<!-- MIME Type Reference -->
    -+<h2 id="MIMETypeReference">Acuan Tipe MIME</h2>
    -+<p>
    -+    Penyedia konten bisa menghasilkan tipe media MIME standar, atau string tipe MIME custom, atau keduanya.
    -+</p>
    -+<p>
    -+    Tipe MIME memiliki format
    -+</p>
    -+<pre>
    -+<em>type</em>/<em>subtype</em>
    -+</pre>
    -+<p>
    -+    Misalnya, tipe MIME <code>text/html</code> yang dikenal luas memiliki tipe <code>text</code> dan
    -+    subtipe <code>html</code>. Jika penyedia menghasilkan tipe ini untuk sebuah URI, artinya
    -+    query dengan URI itu akan menghasilkan teks berisi tag HTML.
    -+</p>
    -+<p>
    -+    String tipe MIME custom, yang juga disebut dengan tipe MIME "khusus vendor", memiliki nilai-nilai
    -+    <em>tipe</em> dan <em>subtipe</em> yang lebih kompleks. Nilai <em>tipe</em> selalu
    -+</p>
    -+<pre>
    -+vnd.android.cursor.<strong>dir</strong>
    -+</pre>
    -+<p>
    -+    untuk beberapa baris, atau
    -+</p>
    -+<pre>
    -+vnd.android.cursor.<strong>item</strong>
    -+</pre>
    -+<p>
    -+    untuk satu baris.
    -+</p>
    -+<p>
    -+    <em>Subtipe</em> adalah khusus penyedia. Penyedia bawaan Android biasanya memiliki subtipe
    -+    sederhana. Misalnya, bila aplikasi Contacts membuat satu baris untuk nomor telepon,
    -+    aplikasi akan mengatur tipe MIME berikut di baris itu:
    -+</p>
    -+<pre>
    -+vnd.android.cursor.item/phone_v2
    -+</pre>
    -+<p>
    -+    Perhatikan bahwa nilai subtipe adalah sekadar <code>phone_v2</code>.
    -+</p>
    -+<p>
    -+    Pengembang penyedia lain bisa membuat pola subtipe sendiri berdasarkan
    -+    otoritas dan nama-nama tabel penyedia. Misalnya, perhatikan penyedia yang berisi jadwal kereta api.
    -+    Otoritas penyedia adalah <code>com.example.trains</code>, dan berisi tabel-tabel
    -+    Line1, Line2, dan Line3. Untuk merespons URI konten
    -+</p>
    -+<p>
    -+<pre>
    -+content://com.example.trains/Line1
    -+</pre>
    -+<p>
    -+    untuk tabel Line1, penyedia menghasilkan tipe MIME
    -+</p>
    -+<pre>
    -+vnd.android.cursor.<strong>dir</strong>/vnd.example.line1
    -+</pre>
    -+<p>
    -+     Untuk merespons URI konten
    -+</p>
    -+<pre>
    -+content://com.example.trains/Line2/5
    -+</pre>
    -+<p>
    -+    untuk baris 5 di tabel Line2, penyedia menghasilkan tipe MIME
    -+</p>
    -+<pre>
    -+vnd.android.cursor.<strong>item</strong>/vnd.example.line2
    -+</pre>
    -+<p>
    -+    Kebanyakan penyedia konten mendefinisikan konstanta kelas kontrak untuk tipe MIME yang digunakannya. Kelas kontrak
    -+    {@link android.provider.ContactsContract.RawContacts} pada Penyedia Kontak
    -+    misalnya, mendefinisikan konstanta
    -+    {@link android.provider.ContactsContract.RawContacts#CONTENT_ITEM_TYPE} untuk tipe MIME
    -+    baris kontak mentah tunggal.
    -+</p>
    -+<p>
    -+    URI konten untuk baris-baris tunggal dijelaskan di bagian
    -+    <a href="#ContentURIs">URI Konten</a>.
    -+</p>
    -diff --git a/docs/html-intl/intl/id/guide/topics/providers/content-provider-creating.jd b/docs/html-intl/intl/id/guide/topics/providers/content-provider-creating.jd
    -new file mode 100644
    -index 0000000..7fbc613
    ---- /dev/null
    -+++ b/docs/html-intl/intl/id/guide/topics/providers/content-provider-creating.jd
    -@@ -0,0 +1,1214 @@
    -+page.title=Membuat Penyedia Konten
    -+@jd:body
    -+<div id="qv-wrapper">
    -+<div id="qv">
    -+
    -+
    -+<h2>Dalam dokumen ini</h2>
    -+<ol>
    -+    <li>
    -+        <a href="#DataStorage">Mendesain Penyimpanan Data</a>
    -+    </li>
    -+    <li>
    -+        <a href="#ContentURI">Mendesain URI Konten</a>
    -+    </li>
    -+    <li>
    -+        <a href="#ContentProvider">Mengimplementasikan Kelas ContentProvider</a>
    -+        <ol>
    -+            <li>
    -+                <a href="#RequiredAccess">Metode-Metode yang Diperlukan</a>
    -+            </li>
    -+            <li>
    -+                <a href="#Query">Mengimplementasikan metode query()</a>
    -+            </li>
    -+            <li>
    -+                <a href="#Insert">Mengimplementasikan metode insert()</a>
    -+            </li>
    -+            <li>
    -+                <a href="#Delete">Mengimplementasikan metode delete()</a>
    -+            </li>
    -+            <li>
    -+                <a href="#Update">Mengimplementasikan metode update()</a>
    -+            </li>
    -+            <li>
    -+                <a href="#OnCreate">Mengimplementasikan metode onCreate()</a>
    -+            </li>
    -+        </ol>
    -+    </li>
    -+    <li>
    -+        <a href="#MIMETypes">Mengimplementasikan Tipe MIME Penyedia Konten</a>
    -+        <ol>
    -+            <li>
    -+                <a href="#TableMIMETypes">Tipe MIME untuk tabel</a>
    -+            </li>
    -+            <li>
    -+                <a href="#FileMIMETypes">Tipe MIME untuk file</a>
    -+            </li>
    -+        </ol>
    -+    </li>
    -+    <li>
    -+        <a href="#ContractClass">Mengimplementasikan Kelas Kontrak</a>
    -+    </li>
    -+    <li>
    -+        <a href="#Permissions">Mengimplementasikan Izin Penyedia Konten</a>
    -+    </li>
    -+    <li>
    -+        <a href="#ProviderElement">Elemen &lt;provider&gt;</a>
    -+    </li>
    -+    <li>
    -+        <a href="#Intents">Intent dan Akses Data</a>
    -+    </li>
    -+</ol>
    -+<h2>Kelas-kelas utama</h2>
    -+    <ol>
    -+        <li>
    -+            {@link android.content.ContentProvider}
    -+        </li>
    -+        <li>
    -+            {@link android.database.Cursor}
    -+        </li>
    -+        <li>
    -+            {@link android.net.Uri}
    -+        </li>
    -+    </ol>
    -+<h2>Contoh-Contoh Terkait</h2>
    -+    <ol>
    -+        <li>
    -+            <a href="{@docRoot}resources/samples/NotePad/index.html">
    -+                Aplikasi contoh Note Pad
    -+            </a>
    -+        </li>
    -+    </ol>
    -+<h2>Lihat juga</h2>
    -+    <ol>
    -+        <li>
    -+            <a href="{@docRoot}guide/topics/providers/content-provider-basics.html">
    -+            Dasar-Dasar Penyedia Konten</a>
    -+        </li>
    -+        <li>
    -+            <a href="{@docRoot}guide/topics/providers/calendar-provider.html">
    -+            Penyedia Kalender</a>
    -+        </li>
    -+    </ol>
    -+</div>
    -+</div>
    -+
    -+
    -+<p>
    -+    Penyedia konten mengelola akses ke repository data pusat. Anda mengimplementasikan
    -+    penyedia sebagai satu atau beberapa kelas dalam aplikasi Android, bersama elemen-elemen dalam
    -+    file manifes. Salah satu kelas Anda mengimplementasikan subkelas
    -+    {@link android.content.ContentProvider}, yang merupakan antarmuka antara penyedia Anda dan
    -+    aplikasi lain. Walaupun penyedia konten dimaksudkan untuk menyediakan data bagi
    -+    aplikasi lain, Anda tentu saja bisa memiliki aktivitas dalam aplikasi yang memungkinkan pengguna
    -+    melakukan query dan memodifikasi data yang dikelola oleh penyedia Anda.
    -+</p>
    -+<p>
    -+    Bagian selebihnya dalam topik ini adalah daftar langkah-langkah dasar untuk membangun penyedia konten dan daftar
    -+    API yang akan digunakan.
    -+</p>
    -+
    -+
    -+<!-- Before You Start Building -->
    -+<h2 id="BeforeYouStart">Sebelum Anda Mulai Membangun</h2>
    -+<p>
    -+    Sebelum Anda mulai membangun penyedia, lakukanlah hal-hal berikut:
    -+</p>
    -+<ol>
    -+    <li>
    -+        <strong>Putuskan apakah Anda memerlukan penyedia konten</strong>. Anda perlu membangun sebuah
    -+        penyedia konten jika ingin menyediakan salah satu atau beberapa dari fitur berikut:
    -+        <ul>
    -+            <li>Anda ingin menawarkan data atau file yang kompleks ke aplikasi lain.</li>
    -+            <li>Anda ingin memungkinkan pengguna menyalin data yang kompleks dari aplikasi Anda ke dalam aplikasi lain.</li>
    -+            <li>Anda ingin menyediakan saran pencarian custom dengan menggunakan kerangka kerja pencarian.</li>
    -+        </ul>
    -+    <p>
    -+        Anda <em>tidak</em> mengharuskan penyedia untuk menggunakan database SQLite jika hanya digunakan dalam
    -+        aplikasi sendiri.
    -+    </p>
    -+    </li>
    -+    <li>
    -+        Jika Anda belum siap melakukannya, bacalah topik
    -+        <a href="{@docRoot}guide/topics/providers/content-provider-basics.html">
    -+        Dasar-Dasar Penyedia Konten</a> untuk mengetahui selengkapnya tentang penyedia.
    -+    </li>
    -+</ol>
    -+<p>
    -+    Berikutnya, ikuti langkah-langkah ini untuk membangun penyedia:
    -+</p>
    -+<ol>
    -+    <li>
    -+        Desain penyimpanan mentah untuk data Anda. Penyedia konten menawarkan data dengan dua cara:
    -+        <dl>
    -+            <dt>
    -+                Data file
    -+            </dt>
    -+            <dd>
    -+                Data yang biasanya masuk ke dalam file, misalnya
    -+                foto, audio, atau video. Simpan file dalam ruang privat
    -+                aplikasi Anda. Untuk merespons permintaan file dari aplikasi lain,
    -+                penyedia Anda bisa menawarkan handle ke file tersebut.
    -+            </dd>
    -+            <dt>
    -+                Data "terstruktur"
    -+            </dt>
    -+            <dd>
    -+                Data yang biasanya masuk ke dalam database, larik, atau struktur serupa.
    -+                Simpan data dalam bentuk yang kompatibel dengan tabel berisi baris dan kolom. Baris
    -+                mewakili entitas, misalnya satu orang atau satu barang inventori. Kolom mewakili
    -+                beberapa data untuk entitas itu, misalnya nama orang atau harga barang. Cara umum untuk
    -+                menyimpan tipe data ini adalah dalam database SQLite, namun Anda bisa menggunakan tipe
    -+                penyimpanan apa saja yang persisten. Untuk mengetahui selengkapnya tentang tipe penyimpanan yang tersedia di
    -+                sistem Android, lihat bagian <a href="#DataStorage">
    -+                Mendesain Penyimpanan Data</a>.
    -+            </dd>
    -+        </dl>
    -+    </li>
    -+    <li>
    -+        Definisikan sebuah implementasi konkret kelas {@link android.content.ContentProvider} dan
    -+        metode yang diperlukannya. Kelas ini adalah antarmuka antara data Anda dan bagian selebihnya pada
    -+        sistem Android. Untuk informasi selengkapnya tentang kelas ini, lihat bagian
    -+        <a href="#ContentProvider">Mengimplementasikan Kelas ContentProvider</a>.
    -+    </li>
    -+    <li>
    -+        Definisikan string otoritas, semua URI isinya, dan nama-nama kolom penyedia. Jika Anda ingin
    -+        penyedia aplikasi menangani intent, definisikan juga semua tindakan intent, data ekstra,
    -+        dan flag. Definisikan juga izin yang akan Anda syaratkan terhadap aplikasi yang ingin
    -+        mengakses data Anda. Anda harus mempertimbangkan pendefinisian semua nilai ini sebagai konstanta di
    -+        kelas kontrak terpisah; nantinya, Anda bisa mengekspos kelas ini kepada pengembang lain. Untuk
    -+        informasi selengkapnya tentang URI konten, lihat
    -+        bagian <a href="#ContentURI">Mendesain URI Konten</a>.
    -+        Untuk informasi selengkapnya tentang intent, lihat
    -+        bagian <a href="#Intents">Intent dan Akses Data</a>.
    -+    </li>
    -+    <li>
    -+        Tambahkan bagian opsional lainnya, seperti data contoh atau implementasi
    -+        {@link android.content.AbstractThreadedSyncAdapter} yang bisa menyinkronkan data antara
    -+        penyedia dan data berbasis cloud.
    -+    </li>
    -+</ol>
    -+
    -+
    -+<!-- Designing Data Storage -->
    -+<h2 id="DataStorage">Mendesain Penyimpanan Data</h2>
    -+<p>
    -+    Penyedia konten adalah antarmuka ke data yang disimpan dalam format terstruktur. Sebelum membuat
    -+    antarmuka, Anda harus memutuskan cara menyimpan data. Anda bisa menyimpan data dalam bentuk apa saja yang Anda
    -+    sukai, kemudian mendesain antarmuka untuk membaca dan menulis data yang diperlukan.
    -+</p>
    -+<p>
    -+    Berikut ini adalah beberapa teknologi penyimpanan data yang tersedia di Android:
    -+</p>
    -+<ul>
    -+    <li>
    -+        Sistem Android menyertakan API database SQLite yang digunakan penyedia Android sendiri
    -+        untuk menyimpan data berorientasi tabel. Kelas
    -+        {@link android.database.sqlite.SQLiteOpenHelper} membantu Anda membuat database, dan kelas
    -+        {@link android.database.sqlite.SQLiteDatabase} adalah kelas dasar untuk mengakses
    -+        database.
    -+        <p>
    -+            Ingatlah bahwa Anda tidak harus menggunakan database untuk mengimplementasikan repository. Penyedia
    -+            muncul secara eksternal sebagai satu set tabel, yang serupa dengan sebuah database relasional, namun ini
    -+            bukan persyaratan untuk implementasi internal penyedia.
    -+        </p>
    -+    </li>
    -+    <li>
    -+        Untuk menyimpan file data, Android memiliki beragam API berorientasi file.
    -+        Untuk mengetahui selengkapnya tentang penyimpanan file, bacalah topik
    -+        <a href="{@docRoot}guide/topics/data/data-storage.html">Penyimpanan Data</a>. Jika Anda sedang
    -+        mendesain penyedia yang menawarkan data yang terkait dengan media seperti musik atau video, Anda bisa
    -+        memiliki penyedia yang mengombinasikan data tabel dan file.
    -+    </li>
    -+    <li>
    -+        Untuk bekerja dengan data berbasis jaringan, gunakan kelas-kelas dalam {@link java.net} dan
    -+        {@link android.net}. Anda juga bisa menyinkronkan data berbasis jaringan dengan penyimpanan data lokal
    -+        seperti database, kemudian menawarkan data sebagai tabel atau file.
    -+        Aplikasi contoh <a href="{@docRoot}resources/samples/SampleSyncAdapter/index.html">
    -+        Sample Sync Adapter</a> memperagakan tipe sinkronisasi ini.
    -+    </li>
    -+</ul>
    -+<h3 id="DataDesign">
    -+    Pertimbangan desain data
    -+</h3>
    -+<p>
    -+    Berikut ini adalah beberapa tip untuk mendesain struktur data penyedia:
    -+</p>
    -+<ul>
    -+    <li>
    -+        Data tabel harus selalu memiliki kolom "kunci utama" yang dipelihara oleh penyedia
    -+        sebagai nilai numerik unik untuk setiap baris. Anda bisa menggunakan nilai ini untuk menautkan baris ke
    -+        baris yang terkait dalam tabel lain (dengan menggunakannya sebagai "kunci asing"). Walaupun Anda bisa menggunakan nama
    -+        apa saja untuk kolom ini, menggunakan {@link android.provider.BaseColumns#_ID BaseColumns._ID} adalah
    -+        pilihan terbaik, karena menautkan hasil query penyedia dengan
    -+        {@link android.widget.ListView} mensyaratkan bahwa salah satu kolom yang diambil memiliki nama
    -+        <code>_ID</code>.
    -+    </li>
    -+    <li>
    -+        Jika Anda ingin untuk menyediakan gambar bitmap atau potongan data berorientasi file lainnya yang berukuran sangat besar, simpanlah
    -+        data dalam sebuah file kemudian sediakan secara tidak langsung sebagai ganti menyimpannya secara langsung dalam
    -+        tabel. Jika melakukannya, Anda perlu memberi tahu pengguna penyedia Anda bahwa mereka perlu menggunakan metode file
    -+        {@link android.content.ContentResolver} untuk mengakses data.
    -+    </li>
    -+    <li>
    -+        Gunakan tipe data Binary Large OBject (BLOB) untuk menyimpan data yang bervariasi ukurannya atau memiliki
    -+        struktur yang beragam. Misalnya, Anda bisa menggunakan sebuah kolom BLOB untuk menyimpan
    -+        <a href="http://code.google.com/p/protobuf">buffer protokol</a> atau
    -+        <a href="http://www.json.org">struktur JSON</a>.
    -+        <p>
    -+            Anda juga bisa menggunakan BLOB untuk mengimplementasikan tabel yang <em>tidak bergantung skema</em>. Dalam
    -+            tipe tabel ini, Anda mendefinisikan kolom kunci utama, kolom tipe MIME, dan satu atau beberapa
    -+            kolom generik sebagai BLOB. Arti dari data dalam kolom-kolom BLOB ditunjukkan
    -+            oleh nilai dalam kolom tipe MIME. Cara ini memungkinkan Anda menyimpan berbagai tipe baris dalam
    -+            tabel yang sama. Tabel "data"
    -+            {@link android.provider.ContactsContract.Data} Penyedia Kontak adalah contoh tabel yang tidak bergantung skema
    -+            tersebut.
    -+        </p>
    -+    </li>
    -+</ul>
    -+<!-- Designing Content URIs -->
    -+<h2 id="ContentURI">Mendesain URI Konten</h2>
    -+<p>
    -+    <strong>URI konten</strong> adalah URI yang mengidentifikasi data dalam penyedia. URI Konten
    -+    berisi nama simbolis seluruh penyedia (<strong>otoritas</strong>nya) dan sebuah
    -+    nama yang menunjuk ke tabel atau file (<strong>path</strong>). Bagian id opsional menunjuk ke
    -+    satu baris dalam tabel. Setiap metode akses data
    -+    {@link android.content.ContentProvider} memiliki sebuah URI konten sebagai argumen; hal ini memungkinkan Anda
    -+    menentukan tabel, baris, atau file yang akan diakses.
    -+</p>
    -+<p>
    -+    Dasar-dasar URI konten dijelaskan dalam topik
    -+    <a href="{@docRoot}guide/topics/providers/content-provider-basics.html">
    -+    Dasar-Dasar Penyedia Konten</a>.
    -+</p>
    -+<h3>Mendesain otoritas</h3>
    -+<p>
    -+    Penyedia biasanya memiliki otoritas tunggal, yang berfungsi sebagai nama internal Android-nya. Untuk
    -+    menghindari konflik dengan penyedia lain, Anda harus menggunakan kepemilikan domain internet (secara terbalik)
    -+    sebagai basis otoritas penyedia Anda. Karena saran ini juga berlaku untuk
    -+    nama-nama paket Android, Anda bisa mendefinisikan otoritas penyedia sebagai perluasan dari nama
    -+    paket yang berisi penyedia. Misalnya, jika nama paket Android Anda adalah
    -+    <code>com.example.&lt;appname&gt;</code>, Anda harus memberikan penyedia Anda
    -+    otoritas <code>com.example.&lt;appname&gt;.provider</code>.
    -+</p>
    -+<h3>Mendesain struktur path</h3>
    -+<p>
    -+    Pengembang biasanya membuat URI konten dari otoritas dengan menambahkan path yang menunjuk ke
    -+    masing-masing tabel. Misalnya, jika Anda memiliki dua tabel <em>table1</em> dan
    -+    <em>table2</em>, Anda mengombinasikan otoritas dari contoh sebelumnya untuk menghasilkan
    -+    URI konten
    -+    <code>com.example.&lt;appname&gt;.provider/table1</code> dan
    -+    <code>com.example.&lt;appname&gt;.provider/table2</code>. Path tidak
    -+    dibatasi pada segmen tunggal, dan tidak harus berupa tabel untuk masing-masing tingkat path.
    -+</p>
    -+<h3>Menangani ID URI konten</h3>
    -+<p>
    -+    Berdasarkan standar, penyedia menawarkan akses ke satu baris dalam tabel dengan menerima URI konten
    -+    dengan sebuah nilai ID untuk baris itu di akhir URI. Juga berdasarkan standar, penyedia mencocokkan
    -+    nilai ID dengan kolom <code>_ID</code> tabel, dan melakukan akses yang diminta terhadap baris
    -+    yang cocok.
    -+</p>
    -+<p>
    -+    Standar ini memudahkan pola desain umum untuk aplikasi yang mengakses penyedia. Aplikasi
    -+    melakukan query terhadap penyedia dan menampilkan {@link android.database.Cursor} yang dihasilkan
    -+    dalam {@link android.widget.ListView} dengan menggunakan {@link android.widget.CursorAdapter}.
    -+    Definisi {@link android.widget.CursorAdapter} mengharuskan salah satu kolom dalam
    -+    {@link android.database.Cursor} berupa <code>_ID</code>
    -+</p>
    -+<p>
    -+    Pengguna kemudian mengambil salah satu baris yang ditampilkan dari UI untuk menemukan atau memodifikasi
    -+    data. Aplikasi mengambil baris yang sesuai dari {@link android.database.Cursor} yang mendukung
    -+    {@link android.widget.ListView}, mengambil nilai <code>_ID</code> untuk baris ini, menambahkannya ke
    -+    URI konten, dan mengirim permintaan akses ke penyedia. Penyedia nanti bisa melakukan
    -+    query atau modifikasi terhadap baris yang persis diambil pengguna.
    -+</p>
    -+<h3>Pola URI konten</h3>
    -+<p>
    -+    Untuk membantu Anda memilih tindakan yang diambil bagi URI konten yang masuk, API penyedia menyertakan
    -+    kelas praktis {@link android.content.UriMatcher}, yang memetakan "pola-pola" URI konten ke
    -+    nilai-nilai integer. Anda bisa menggunakan nilai-nilai integer dalam pernyataan <code>switch</code> yang
    -+    memilih tindakan yang diinginkan untuk URI konten atau URI yang cocok dengan pola tertentu.
    -+</p>
    -+<p>
    -+    Pola URI konten mencocokkan dengan URI konten menggunakan karakter wildcard:
    -+</p>
    -+    <ul>
    -+        <li>
    -+            <strong><code>*</code>:</strong> Mencocokkan string yang memiliki karakter yang sah dengan panjang berapa saja.
    -+        </li>
    -+        <li>
    -+            <strong><code>#</code>:</strong> Mencocokkan string karakter numerik dengan panjang berapa saja.
    -+        </li>
    -+    </ul>
    -+<p>
    -+    Sebagai contoh desain dan pemrograman penanganan URI konten, perhatikan penyedia dengan
    -+    otoritas <code>com.example.app.provider</code> yang mengenali URI konten berikut
    -+    yang menunjuk ke tabel-tabel:
    -+</p>
    -+<ul>
    -+    <li>
    -+        <code>content://com.example.app.provider/table1</code>: Tabel bernama <code>table1</code>.
    -+    </li>
    -+    <li>
    -+        <code>content://com.example.app.provider/table2/dataset1</code>: Tabel bernama
    -+        <code>dataset1</code>.
    -+    </li>
    -+    <li>
    -+        <code>content://com.example.app.provider/table2/dataset2</code>: Tabel bernama
    -+        <code>dataset2</code>.
    -+    </li>
    -+    <li>
    -+        <code>content://com.example.app.provider/table3</code>: Tabel bernama <code>table3</code>.
    -+    </li>
    -+</ul>
    -+<p>
    -+    Penyedia juga mengenali URI konten ini jika baris ID ditambahkan ke URI,
    -+    misalnya <code>content://com.example.app.provider/table3/1</code> untuk baris yang diidentifikasi oleh
    -+    <code>1</code> dalam <code>table3</code>.
    -+</p>
    -+<p>
    -+    Pola-pola URI konten berikut akan menjadi mungkin:
    -+</p>
    -+<dl>
    -+    <dt>
    -+        <code>content://com.example.app.provider/*</code>
    -+    </dt>
    -+    <dd>
    -+        Mencocokkan URI konten di penyedia.
    -+    </dd>
    -+    <dt>
    -+        <code>content://com.example.app.provider/table2/*</code>:
    -+    </dt>
    -+    <dd>
    -+        Mencocokkan URI konten untuk tabel-tabel <code>dataset1</code>
    -+        dan <code>dataset2</code>, namun tidak mencocokkan URI konten untuk <code>table1</code> atau
    -+        <code>table3</code>.
    -+    </dd>
    -+    <dt>
    -+        <code>content://com.example.app.provider/table3/#</code>: Mencocokkan URI konten
    -+        untuk satu baris di <code>table3</code>, misalnya
    -+        <code>content://com.example.app.provider/table3/6</code> untuk baris yang diidentifikasi oleh
    -+        <code>6</code>.
    -+    </dt>
    -+</dl>
    -+<p>
    -+    Cuplikan kode berikut menunjukkan cara kerja metode di {@link android.content.UriMatcher}.
    -+    Kode ini menangani URI seluruh tabel secara berbeda dengan URI untuk
    -+    satu baris, menggunakan pola URI konten
    -+    <code>content://&lt;authority&gt;/&lt;path&gt;</code> untuk tabel, dan
    -+    <code>content://&lt;authority&gt;/&lt;path&gt;/&lt;id&gt;</code> untuk satu baris.
    -+</p>
    -+<p>
    -+    Metode {@link android.content.UriMatcher#addURI(String, String, int) addURI()} memetakan
    -+    otoritas dan path ke nilai integer. Metode {@link android.content.UriMatcher#match(Uri)
    -+    match()} menghasilkan nilai integer URI. Pernyataan <code>switch</code>
    -+    memilih antara melakukan query seluruh tabel dan melakukan query satu record:
    -+</p>
    -+<pre class="prettyprint">
    -+public class ExampleProvider extends ContentProvider {
    -+...
    -+    // Creates a UriMatcher object.
    -+    private static final UriMatcher sUriMatcher;
    -+...
    -+    /*
    -+     * The calls to addURI() go here, for all of the content URI patterns that the provider
    -+     * should recognize. For this snippet, only the calls for table 3 are shown.
    -+     */
    -+...
    -+    /*
    -+     * Sets the integer value for multiple rows in table 3 to 1. Notice that no wildcard is used
    -+     * in the path
    -+     */
    -+    sUriMatcher.addURI("com.example.app.provider", "table3", 1);
    -+
    -+    /*
    -+     * Sets the code for a single row to 2. In this case, the "#" wildcard is
    -+     * used. "content://com.example.app.provider/table3/3" matches, but
    -+     * "content://com.example.app.provider/table3 doesn't.
    -+     */
    -+    sUriMatcher.addURI("com.example.app.provider", "table3/#", 2);
    -+...
    -+    // Implements ContentProvider.query()
    -+    public Cursor query(
    -+        Uri uri,
    -+        String[] projection,
    -+        String selection,
    -+        String[] selectionArgs,
    -+        String sortOrder) {
    -+...
    -+        /*
    -+         * Choose the table to query and a sort order based on the code returned for the incoming
    -+         * URI. Here, too, only the statements for table 3 are shown.
    -+         */
    -+        switch (sUriMatcher.match(uri)) {
    -+
    -+
    -+            // If the incoming URI was for all of table3
    -+            case 1:
    -+
    -+                if (TextUtils.isEmpty(sortOrder)) sortOrder = "_ID ASC";
    -+                break;
    -+
    -+            // If the incoming URI was for a single row
    -+            case 2:
    -+
    -+                /*
    -+                 * Because this URI was for a single row, the _ID value part is
    -+                 * present. Get the last path segment from the URI; this is the _ID value.
    -+                 * Then, append the value to the WHERE clause for the query
    -+                 */
    -+                selection = selection + "_ID = " uri.getLastPathSegment();
    -+                break;
    -+
    -+            default:
    -+            ...
    -+                // If the URI is not recognized, you should do some error handling here.
    -+        }
    -+        // call the code to actually do the query
    -+    }
    -+</pre>
    -+<p>
    -+    Kelas lainnya, {@link android.content.ContentUris}, menyediakan metode praktis untuk menggunakan
    -+    bagian <code>id</code> URI konten. Kelas-kelas {@link android.net.Uri} dan
    -+    {@link android.net.Uri.Builder} menyertakan metode praktis untuk mengurai
    -+    objek {@link android.net.Uri} yang ada dan membuat objek baru.
    -+</p>
    -+
    -+<!-- Implementing the ContentProvider class -->
    -+<h2 id="ContentProvider">Mengimplementasikan Kelas ContentProvider</h2>
    -+<p>
    -+    Instance {@link android.content.ContentProvider} mengelola akses
    -+    ke satu set data terstruktur dengan menangani permintaan dari aplikasi lain. Semua bentuk
    -+    akses pada akhirnya akan memanggil {@link android.content.ContentResolver}, yang kemudian memanggil
    -+    metode konkret {@link android.content.ContentProvider} untuk mendapatkan akses.
    -+</p>
    -+<h3 id="RequiredAccess">Metode-metode yang diperlukan</h3>
    -+<p>
    -+    Kelas abstrak {@link android.content.ContentProvider} mendefinisikan enam metode abstrak yang
    -+    harus Anda implementasikan sebagai bagian dari subkelas konkret Anda sendiri. Semua metode ini kecuali
    -+    {@link android.content.ContentProvider#onCreate() onCreate()} dipanggil oleh aplikasi klien
    -+    yang berupaya mengakses penyedia konten Anda:
    -+</p>
    -+<dl>
    -+    <dt>
    -+        {@link android.content.ContentProvider#query(Uri, String[], String, String[], String)
    -+        query()}
    -+    </dt>
    -+    <dd>
    -+        Mengambil data dari penyedia Anda. Menggunakan argumen untuk memilih tabel yang akan
    -+        di-query, baris dan kolom yang akan dihasilkan, dan urutan sortir hasilnya.
    -+        Menghasilkan data berupa objek {@link android.database.Cursor}.
    -+    </dd>
    -+    <dt>
    -+        {@link android.content.ContentProvider#insert(Uri, ContentValues) insert()}
    -+    </dt>
    -+    <dd>
    -+        Menyisipkan baris baru ke dalam penyedia Anda. Menggunakan argumen untuk memilih
    -+        tabel tujuan dan mendapatkan nilai-nilai kolom yang akan digunakan. Menghasilkan URI konten untuk
    -+        baris yang baru disisipkan.
    -+    </dd>
    -+    <dt>
    -+        {@link android.content.ContentProvider#update(Uri, ContentValues, String, String[])
    -+        update()}
    -+    </dt>
    -+    <dd>
    -+        Memperbarui baris yang ada di penyedia Anda. Menggunakan argumen untuk memilih tabel dan baris
    -+        yang akan diperbarui dan mendapatkan nilai-nilai kolom yang diperbarui. Menghasilkan jumlah baris yang diperbarui.
    -+    </dd>
    -+    <dt>
    -+        {@link android.content.ContentProvider#delete(Uri, String, String[]) delete()}
    -+    </dt>
    -+    <dd>
    -+        Menghapus baris dari penyedia Anda. Menggunakan argumen untuk memilih tabel dan baris yang akan
    -+        dihapus. Menghasilkan jumlah baris yang dihapus.
    -+    </dd>
    -+    <dt>
    -+        {@link android.content.ContentProvider#getType(Uri) getType()}
    -+    </dt>
    -+    <dd>
    -+        Menghasilkan tipe MIME yang sesuai dengan URI konten. Metode ini dijelaskan lebih detail
    -+        di bagian <a href="#MIMETypes">Mengimplementasikan Tipe MIME Penyedia Konten</a>.
    -+    </dd>
    -+    <dt>
    -+        {@link android.content.ContentProvider#onCreate() onCreate()}
    -+    </dt>
    -+    <dd>
    -+        Inisialisasi penyedia Anda. Sistem Android memanggil metode ini segera setelah
    -+        membuat penyedia Anda. Perhatikan bahwa penyedia Anda tidak dibuat hingga
    -+        objek {@link android.content.ContentResolver} mencoba mengaksesnya.
    -+    </dd>
    -+</dl>
    -+<p>
    -+    Perhatikan bahwa metode-metode ini memiliki signature yang sama dengan
    -+    metode-metode {@link android.content.ContentResolver} yang sama namanya.
    -+</p>
    -+<p>
    -+    Implementasi metode-metode ini harus memperhitungkan hal-hal berikut:
    -+</p>
    -+<ul>
    -+    <li>
    -+        Semua metode ini kecuali {@link android.content.ContentProvider#onCreate() onCreate()}
    -+        bisa dipanggil oleh beberapa thread sekaligus, jadi harus thread-safe (aman untuk thread). Untuk mengetahui
    -+        selengkapnya tentang multi-thread, lihat topik
    -+        <a href="{@docRoot}guide/components/processes-and-threads.html">
    -+        Proses dan Thread</a>.
    -+    </li>
    -+    <li>
    -+        Hindari melakukan operasi yang lama dalam {@link android.content.ContentProvider#onCreate()
    -+        onCreate()}. Tunda inisialisasi tugas hingga benar-benar diperlukan.
    -+        Bagian <a href="#OnCreate">Mengimplementasikan metode onCreate()</a>
    -+        membahas hal ini secara lebih detail.
    -+    </li>
    -+    <li>
    -+        Walaupun harus mengimplementasikan metode-metode ini, kode Anda tidak harus melakukan apa pun selain
    -+        tipe data yang diharapkan. Misalnya, Anda mungkin ingin mencegah aplikasi lain
    -+        menyisipkan data ke dalam beberapa tabel. Caranya, Anda bisa mengabaikan panggilan ke
    -+        {@link android.content.ContentProvider#insert(Uri, ContentValues) insert()} dan menghasilkan
    -+        0.
    -+    </li>
    -+</ul>
    -+<h3 id="Query">Mengimplementasikan metode query()</h3>
    -+<p>
    -+    Metode
    -+    {@link android.content.ContentProvider#query(Uri, String[], String, String[], String)
    -+    ContentProvider.query()} harus menghasilkan objek {@link android.database.Cursor}, atau jika
    -+    gagal, melontarkan {@link java.lang.Exception}. Jika menggunakan database SQLite sebagai
    -+    penyimpanan data, Anda bisa mengembalikan{@link android.database.Cursor} yang dikembalikan oleh salah satu metode
    -+    <code>query()</code> dari kelas {@link android.database.sqlite.SQLiteDatabase}.
    -+    Jika query tidak mencocokkan baris apa pun, Anda harus mengembalikan instance {@link android.database.Cursor}
    -+    yang metode {@link android.database.Cursor#getCount()}-nya mengembalikan 0.
    -+    Anda harus mengembalikan <code>null</code> hanya jika terjadi kesalahan internal selama proses query.
    -+</p>
    -+<p>
    -+    Jika Anda tidak menggunakan database SQLite sebagai penyimpanan data, gunakan salah satu subkelas konkret
    -+    {@link android.database.Cursor}. Misalnya, kelas {@link android.database.MatrixCursor}
    -+    mengimplementasikan kursor dengan masing-masing baris berupa larik {@link java.lang.Object}. Dengan kelas ini,
    -+    gunakan {@link android.database.MatrixCursor#addRow(Object[]) addRow()} untuk menambahkan baris baru.
    -+</p>
    -+<p>
    -+    Ingatlah bahwa sistem Android harus mampu mengomunikasikan {@link java.lang.Exception}
    -+    lintas batas proses. Android bisa melakukannya untuk eksepsi berikut yang mungkin berguna
    -+    dalam menangani kesalahan query:
    -+</p>
    -+<ul>
    -+    <li>
    -+        {@link java.lang.IllegalArgumentException} (Anda bisa saja melontarkannya jika penyedia Anda
    -+        menerima URI konten yang tidak sah)
    -+    </li>
    -+    <li>
    -+        {@link java.lang.NullPointerException}
    -+    </li>
    -+</ul>
    -+<h3 id="Insert">Mengimplementasikan metode insert()</h3>
    -+<p>
    -+    Metode {@link android.content.ContentProvider#insert(Uri, ContentValues) insert()} menambahkan satu
    -+    baris baru ke tabel yang sesuai, dengan menggunakan nilai-nilai dalam argumen {@link android.content.ContentValues}.
    -+ Jika kolom nama tidak ada dalam argumen {@link android.content.ContentValues}, Anda
    -+    mungkin perlu menyediakan nilai default untuknya, baik dalam kode penyedia atau dalam skema database
    -+    Anda.
    -+</p>
    -+<p>
    -+    Metode ini harus mengembalikan URI konten untuk baris baru. Untuk membuatnya, tambahkan nilai
    -+    <code>_ID</code> baris baru (atau kunci utama lainnya) ke tabel URI konten, dengan menggunakan
    -+    {@link android.content.ContentUris#withAppendedId(Uri, long) withAppendedId()}.
    -+</p>
    -+<h3 id="Delete">Mengimplementasikan metode delete()</h3>
    -+<p>
    -+    Metode {@link android.content.ContentProvider#delete(Uri, String, String[]) delete()}
    -+    tidak harus menghapus baris-baris dari penyimpanan data Anda secara fisik. Jika menggunakan adaptor sinkronisasi
    -+    bersama penyedia, Anda harus mempertimbangkan penandaan baris yang dihapus
    -+    dengan flag "delete"; bukan menghilangkan baris itu sepenuhnya. Adaptor sinkronisasi bisa
    -+    memeriksa baris yang dihapus dan menghilangkannya dari server sebelum menghapusnya dari penyedia.
    -+</p>
    -+<h3 id="Update">Mengimplementasikan metode update()</h3>
    -+<p>
    -+    Metode {@link android.content.ContentProvider#update(Uri, ContentValues, String, String[])
    -+    update()} mengambil argumen {@link android.content.ContentValues} yang sama dengan yang digunakan oleh
    -+    {@link android.content.ContentProvider#insert(Uri, ContentValues) insert()}, dan
    -+    argumen-argumen <code>selection</code> dan <code>selectionArgs</code> yang sama dengan yang digunakan oleh
    -+    {@link android.content.ContentProvider#delete(Uri, String, String[]) delete()} dan
    -+    {@link android.content.ContentProvider#query(Uri, String[], String, String[], String)
    -+    ContentProvider.query()}. Hal ini bisa memungkinkan Anda menggunakan kembali kode di antara metode-metode ini.
    -+</p>
    -+<h3 id="OnCreate">Mengimplementasikan metode onCreate()</h3>
    -+<p>
    -+    Sistem Android memanggil {@link android.content.ContentProvider#onCreate()
    -+    onCreate()} saat memulai penyedia. Anda harus melakukan tugas-tugas inisialisasi yang berjalan cepat saja
    -+    dalam metode ini, serta menunda pembuatan database dan pemuatan data hingga penyedia benar-benar
    -+    menerima permintaan terhadap data. Jika Anda melakukan tugas yang memakan waktu dalam
    -+    {@link android.content.ContentProvider#onCreate() onCreate()}, Anda akan memperlambat
    -+    startup penyedia. Pada gilirannya, hal ini akan memperlambat respons dari penyedia terhadap
    -+    aplikasi lain.
    -+</p>
    -+<p>
    -+    Misalnya, jika menggunakan database SQLite, Anda bisa membuat
    -+    sebuah objek {@link android.database.sqlite.SQLiteOpenHelper} baru di
    -+    {@link android.content.ContentProvider#onCreate() ContentProvider.onCreate()},
    -+    kemudian membuat tabel-tabel SQL saat pertama kali membuka database itu. Untuk memperlancar hal ini,
    -+    saat pertama Anda memanggil {@link android.database.sqlite.SQLiteOpenHelper#getWritableDatabase
    -+    getWritableDatabase()}, metode ini memanggil metode
    -+    {@link android.database.sqlite.SQLiteOpenHelper#onCreate(SQLiteDatabase)
    -+    SQLiteOpenHelper.onCreate()} secara otomatis.
    -+</p>
    -+<p>
    -+    Dua cuplikan berikut memperagakan interaksi antara
    -+    {@link android.content.ContentProvider#onCreate() ContentProvider.onCreate()} dan
    -+    {@link android.database.sqlite.SQLiteOpenHelper#onCreate(SQLiteDatabase)
    -+    SQLiteOpenHelper.onCreate()}. Cuplikan pertama adalah implementasi
    -+    {@link android.content.ContentProvider#onCreate() ContentProvider.onCreate()}:
    -+</p>
    -+<pre class="prettyprint">
    -+public class ExampleProvider extends ContentProvider
    -+
    -+    /*
    -+     * Defines a handle to the database helper object. The MainDatabaseHelper class is defined
    -+     * in a following snippet.
    -+     */
    -+    private MainDatabaseHelper mOpenHelper;
    -+
    -+    // Defines the database name
    -+    private static final String DBNAME = "mydb";
    -+
    -+    // Holds the database object
    -+    private SQLiteDatabase db;
    -+
    -+    public boolean onCreate() {
    -+
    -+        /*
    -+         * Creates a new helper object. This method always returns quickly.
    -+         * Notice that the database itself isn't created or opened
    -+         * until SQLiteOpenHelper.getWritableDatabase is called
    -+         */
    -+        mOpenHelper = new MainDatabaseHelper(
    -+            getContext(),        // the application context
    -+            DBNAME,              // the name of the database)
    -+            null,                // uses the default SQLite cursor
    -+            1                    // the version number
    -+        );
    -+
    -+        return true;
    -+    }
    -+
    -+    ...
    -+
    -+    // Implements the provider's insert method
    -+    public Cursor insert(Uri uri, ContentValues values) {
    -+        // Insert code here to determine which table to open, handle error-checking, and so forth
    -+
    -+        ...
    -+
    -+        /*
    -+         * Gets a writeable database. This will trigger its creation if it doesn't already exist.
    -+         *
    -+         */
    -+        db = mOpenHelper.getWritableDatabase();
    -+    }
    -+}
    -+</pre>
    -+<p>
    -+    Cuplikan berikutnya adalah implementasi
    -+    {@link android.database.sqlite.SQLiteOpenHelper#onCreate(SQLiteDatabase)
    -+    SQLiteOpenHelper.onCreate()}, yang menyertakan kelas helper:
    -+</p>
    -+<pre class="prettyprint">
    -+...
    -+// A string that defines the SQL statement for creating a table
    -+private static final String SQL_CREATE_MAIN = "CREATE TABLE " +
    -+    "main " +                       // Table's name
    -+    "(" +                           // The columns in the table
    -+    " _ID INTEGER PRIMARY KEY, " +
    -+    " WORD TEXT"
    -+    " FREQUENCY INTEGER " +
    -+    " LOCALE TEXT )";
    -+...
    -+/**
    -+ * Helper class that actually creates and manages the provider's underlying data repository.
    -+ */
    -+protected static final class MainDatabaseHelper extends SQLiteOpenHelper {
    -+
    -+    /*
    -+     * Instantiates an open helper for the provider's SQLite data repository
    -+     * Do not do database creation and upgrade here.
    -+     */
    -+    MainDatabaseHelper(Context context) {
    -+        super(context, DBNAME, null, 1);
    -+    }
    -+
    -+    /*
    -+     * Creates the data repository. This is called when the provider attempts to open the
    -+     * repository and SQLite reports that it doesn't exist.
    -+     */
    -+    public void onCreate(SQLiteDatabase db) {
    -+
    -+        // Creates the main table
    -+        db.execSQL(SQL_CREATE_MAIN);
    -+    }
    -+}
    -+</pre>
    -+
    -+
    -+<!-- Implementing ContentProvider MIME Types -->
    -+<h2 id="MIMETypes">Mengimplementasikan Tipe MIME Penyedia Konten</h2>
    -+<p>
    -+    Kelas {@link android.content.ContentProvider} memiliki dua metode untuk menghasilkan tipe-tipe MIME:
    -+</p>
    -+<dl>
    -+    <dt>
    -+        {@link android.content.ContentProvider#getType(Uri) getType()}
    -+    </dt>
    -+    <dd>
    -+        Salah satu metode wajib yang harus Anda implementasikan untuk setiap penyedia.
    -+    </dd>
    -+    <dt>
    -+        {@link android.content.ContentProvider#getStreamTypes(Uri, String) getStreamTypes()}
    -+    </dt>
    -+    <dd>
    -+        Sebuah metode yang diharapkan untuk Anda implementasikan jika penyedia Anda menawarkan file.
    -+    </dd>
    -+</dl>
    -+<h3 id="TableMIMETypes">Tipe MIME untuk tabel</h3>
    -+<p>
    -+    Metode {@link android.content.ContentProvider#getType(Uri) getType()} mengembalikan
    -+    {@link java.lang.String} dengan format MIME yang menjelaskan tipe data yang dikembalikan oleh
    -+    argumen URI konten. Argumen {@link android.net.Uri} bisa berupa pola, bukannya URI tertentu;
    -+    dalam hal ini, Anda harus mengembalikan tipe data terkait URI konten yang cocok dengan
    -+    polanya.
    -+</p>
    -+<p>
    -+    Untuk tipe data umum misalnya teks, HTML, atau JPEG,
    -+    {@link android.content.ContentProvider#getType(Uri) getType()} harus mengembalikan
    -+    tipe MIME standar untuk data itu. Daftar lengkap tipe standar ini tersedia di situs web
    -+    <a href="http://www.iana.org/assignments/media-types/index.htm">IANA MIME Media Types</a>.
    -+
    -+</p>
    -+<p>
    -+    Untuk URI konten yang menunjuk ke baris atau baris-baris data tabel,
    -+    {@link android.content.ContentProvider#getType(Uri) getType()} harus mengembalikan
    -+    tipe MIME dalam format MIME khusus vendor Android:
    -+</p>
    -+<ul>
    -+    <li>
    -+        Bagian tipe: <code>vnd</code>
    -+    </li>
    -+    <li>
    -+        Bagian subtipe:
    -+        <ul>
    -+            <li>
    -+    Jika pola URI adalah untuk satu baris: <code>android.cursor.<strong>item</strong>/</code>
    -+            </li>
    -+            <li>
    -+    Jika pola URI adalah untuk lebih dari satu baris: <code>android.cursor.<strong>dir</strong>/</code>
    -+            </li>
    -+        </ul>
    -+    </li>
    -+    <li>
    -+        Bagian khusus penyedia: <code>vnd.&lt;name&gt;</code>.<code>&lt;type&gt;</code>
    -+        <p>
    -+            Anda menyediakan <code>&lt;name&gt;</code> dan <code>&lt;type&gt;</code>.
    -+            Nilai <code>&lt;name&gt;</code> harus unik secara global,
    -+            dan nilai <code>&lt;type&gt;</code> harus unik bagi pola URI
    -+            yang sesuai. Pilihan tepat untuk <code>&lt;name&gt;</code> adalah nama perusahaan Anda atau
    -+            sebagian dari nama paket Android aplikasi Anda. Pilihan tepat untuk
    -+            <code>&lt;type&gt;</code> adalah string yang mengidentifikasi tabel yang terkait dengan
    -+            URI.
    -+        </p>
    -+
    -+    </li>
    -+</ul>
    -+<p>
    -+    Misalnya, jika otoritas penyedia adalah
    -+    <code>com.example.app.provider</code>, dan penyedia mengekspos tabel bernama
    -+    <code>table1</code>, tipe MIME untuk beberapa baris dalam <code>table1</code> adalah:
    -+</p>
    -+<pre>
    -+vnd.android.cursor.<strong>dir</strong>/vnd.com.example.provider.table1
    -+</pre>
    -+<p>
    -+    Untuk satu baris <code>table1</code>, tipe MIME adalah:
    -+</p>
    -+<pre>
    -+vnd.android.cursor.<strong>item</strong>/vnd.com.example.provider.table1
    -+</pre>
    -+<h3 id="FileMIMETypes">Tipe MIME untuk file</h3>
    -+<p>
    -+    Jika penyedia Anda menawarkan file, implementasikan
    -+    {@link android.content.ContentProvider#getStreamTypes(Uri, String) getStreamTypes()}.
    -+    Metode ini menghasilkan larik {@link java.lang.String} tipe MIME untuk file
    -+    yang bisa dikembalikan penyedia Anda untuk URI konten bersangkutan. Anda harus memfilter tipe MIME yang Anda tawarkan dengan argumen filter
    -+    tipe MIME, sehingga Anda hanya mengembalikan tipe MIME yang ingin ditangani klien.
    -+</p>
    -+<p>
    -+    Misalnya, perhatikan penyedia yang menawarkan gambar foto sebagai file dalam format <code>.jpg</code>,
    -+    <code>.png</code>, dan <code>.gif</code>.
    -+    Jika aplikasi memanggil {@link android.content.ContentResolver#getStreamTypes(Uri, String)
    -+    ContentResolver.getStreamTypes()} dengan string filter <code>image/*</code> (sesuatu yang
    -+    merupakan "gambar"),
    -+    maka metode {@link android.content.ContentProvider#getStreamTypes(Uri, String)
    -+    ContentProvider.getStreamTypes()} harus mengembalikan larik:
    -+</p>
    -+<pre>
    -+{ &quot;image/jpeg&quot;, &quot;image/png&quot;, &quot;image/gif&quot;}
    -+</pre>
    -+<p>
    -+    Jika aplikasi tertarik pada file <code>.jpg</code>, maka aplikasi bisa memanggil
    -+    {@link android.content.ContentResolver#getStreamTypes(Uri, String)
    -+    ContentResolver.getStreamTypes()} dengan string filter <code>*\/jpeg</code>, dan
    -+    {@link android.content.ContentProvider#getStreamTypes(Uri, String)
    -+    ContentProvider.getStreamTypes()} harus mengembalikan:
    -+<pre>
    -+{&quot;image/jpeg&quot;}
    -+</pre>
    -+<p>
    -+    Jika penyedia Anda tidak menawarkan tipe MIME apa pun yang diminta dalam string filter,
    -+    {@link android.content.ContentProvider#getStreamTypes(Uri, String) getStreamTypes()}
    -+    harus mengembalikan <code>null</code>.
    -+</p>
    -+
    -+
    -+<!--  Implementing a Contract Class -->
    -+<h2 id="ContractClass">Mengimplementasikan Kelas Kontrak</h2>
    -+<p>
    -+    Kelas kontrak adalah kelas <code>public final</code> yang berisi definisi konstanta untuk URI, nama kolom, tipe MIME, dan
    -+metadata lain yang melekat ke penyedia. Kelas
    -+    membentuk sebuah kontrak antara penyedia dan aplikasi lain dengan memastikan bahwa penyedia
    -+    bisa diakses dengan benar sekalipun ada perubahan pada nilai URI sesungguhnya, nama kolom,
    -+    dan seterusnya.
    -+</p>
    -+<p>
    -+    Kelas kontrak juga membantu pengembang karena kelas ini biasanya memiliki nama-nama simbolik untuk konstantanya,
    -+    sehingga memperkecil kemungkinan pengembang menggunakan nilai yang salah untuk nama kolom atau URI. Karena berupa
    -+    kelas, kelas ini bisa berisi dokumentasi Javadoc. Lingkungan pengembangan terpadu (IDE) seperti
    -+    Eclipse secara otomatis bisa melengkapi nama-nama konstanta dari kelas kontrak dan menampilkan Javadoc untuk
    -+    konstanta.
    -+</p>
    -+<p>
    -+    Pengembang tidak bisa mengakses file kelas milik kelas kontrak dari aplikasi Anda, namun bisa
    -+    mengompilasinya secara statis ke dalam aplikasi mereka dari file <code>.jar</code> yang Anda sediakan.
    -+</p>
    -+<p>
    -+    Kelas {@link android.provider.ContactsContract} dan kelas-kelas tersarangnya adalah contoh
    -+    kelas kontrak.
    -+</p>
    -+<h2 id="Permissions">Mengimplementasikan Izin Penyedia Konten</h2>
    -+<p>
    -+    Izin dan akses untuk semua aspek sistem Android dijelaskan secara detail dalam
    -+    topik <a href="{@docRoot}guide/topics/security/security.html">Keamanan dan Izin</a>.
    -+    Topik <a href="{@docRoot}guide/topics/data/data-storage.html">Penyimpanan Data</a> juga
    -+    menjelaskan keamanan dan izin terkait dengan berbagai tipe penyimpanan.
    -+    Singkatnya, poin-poin pentingnya adalah:
    -+</p>
    -+<ul>
    -+    <li>
    -+        Secara default, file data yang disimpan pada penyimpanan internal perangkat bersifat privat bagi
    -+        aplikasi dan penyedia Anda.
    -+    </li>
    -+    <li>
    -+        Database {@link android.database.sqlite.SQLiteDatabase} yang Anda buat bersifat privat bagi
    -+        aplikasi dan penyedia Anda.
    -+    </li>
    -+    <li>
    -+        Secara default, file data yang Anda simpan ke penyimpanan eksternal bersifat <em>publik</em> dan
    -+        <em>bisa dibaca secara global</em>. Anda tidak bisa menggunakan penyedia konten untuk membatasi akses ke file dalam
    -+        penyimpanan eksternal, karena aplikasi lain bisa menggunakan panggilan API untuk membaca dan menulis ke file tersebut.
    -+    </li>
    -+    <li>
    -+        Panggilan metode untuk membuka atau membuat file atau database SQLite pada
    -+        penyimpanan internal perangkat Anda berpotensi memberikan akses baca maupun tulis ke semua aplikasi lain. Jika Anda
    -+        menggunakan file atau database internal sebagai repository penyedia, dan Anda memberinya
    -+        akses "world-readable" (bisa dibaca secara global) atau "world-writeable" (bisa ditulis secara global), izin yang Anda atur untuk penyedia dalam
    -+        manifesnya tidak akan melindungi data Anda. Akses default untuk file dan database dalam
    -+        penyimpanan internal adalah "privat", dan untuk repository penyedia, tidak boleh Anda ubah.
    -+    </li>
    -+</ul>
    -+<p>
    -+    Jika Anda ingin menggunakan izin penyedia konten untuk mengontrol akses ke data Anda, maka Anda harus
    -+    menyimpan data Anda dalam file internal, database SQLite, atau "cloud" (misalnya,
    -+    di server jauh), dan Anda harus membuat file dan database tetap privat bagi aplikasi Anda.
    -+</p>
    -+<h3>Mengimplementasikan izin</h3>
    -+<p>
    -+    Semua aplikasi bisa membaca dari atau menulis ke penyedia Anda, sekalipun data yang mendasari adalah
    -+    privat, karena secara default penyedia Anda tidak mengatur izin. Untuk mengubahnya,
    -+    atur izin untuk penyedia dalam file manifes, dengan menggunakan atribut atau elemen anak
    -+    dari elemen <code><a href="{@docRoot}guide/topics/manifest/provider-element.html">
    -+    &lt;provider&gt;</a></code>. Anda bisa mengatur izin yang berlaku pada seluruh penyedia,
    -+    atau pada tabel tertentu, atau bahkan pada record tertentu, atau ketiganya.
    -+</p>
    -+<p>
    -+    Anda mendefinisikan izin untuk penyedia dengan satu atau beberapa elemen
    -+    <code><a href="{@docRoot}guide/topics/manifest/permission-element.html">
    -+    &lt;permission&gt;</a></code> dalam file manifes. Untuk membuat
    -+    izin unik bagi penyedia, gunakan scoping (pengaturan lingkup) bergaya Java untuk
    -+    atribut <code><a href="{@docRoot}guide/topics/manifest/permission-element.html#nm">
    -+    android:name</a></code>. Misalnya, beri nama izin membaca dengan
    -+    <code>com.example.app.provider.permission.READ_PROVIDER</code>.
    -+
    -+</p>
    -+<p>
    -+    Daftar berikut menjelaskan lingkup penyedia izin, mulai dengan
    -+    izin yang berlaku pada seluruh penyedia kemudian menjadi semakin sempit.
    -+    Izin yang lebih sempit akan didahulukan daripada izin yang berlingkup lebih luas:
    -+</p>
    -+<dl>
    -+    <dt>
    -+        Izin baca-tulis tunggal tingkat penyedia
    -+    </dt>
    -+    <dd>
    -+        Suatu izin yang mengontrol akses baca-tulis bagi seluruh penyedia, ditetapkan
    -+        dengan atribut <code><a href="{@docRoot}guide/topics/manifest/provider-element.html#prmsn">
    -+        android:permission</a></code> dari
    -+        elemen <code><a href="{@docRoot}guide/topics/manifest/provider-element.html">
    -+        &lt;provider&gt;</a></code>.
    -+    </dd>
    -+    <dt>
    -+        Izin baca-tulis terpisah tingkat penyedia
    -+    </dt>
    -+    <dd>
    -+        Satu izin baca dan satu izin tulis untuk seluruh penyedia. Anda menetapkan keduanya
    -+        dengan atribut <code><a href="{@docRoot}guide/topics/manifest/provider-element.html#rprmsn">
    -+        android:readPermission</a></code> dan
    -+        <code><a href="{@docRoot}guide/topics/manifest/provider-element.html#wprmsn">
    -+        android:writePermission</a></code> dari elemen
    -+        <code><a href="{@docRoot}guide/topics/manifest/provider-element.html">
    -+        &lt;provider&gt;</a></code>. Kedua izin akan didahulukan daripada izin yang diharuskan oleh
    -+        <code><a href="{@docRoot}guide/topics/manifest/provider-element.html#prmsn">
    -+        android:permission</a></code>.
    -+    </dd>
    -+    <dt>
    -+        Izin tingkat path
    -+    </dt>
    -+    <dd>
    -+        Izin baca, tulis, atau baca/tulis untuk URI konten dalam penyedia Anda. Anda menetapkan
    -+        tiap URI yang ingin dikontrol dengan elemen anak
    -+        <code><a href="{@docRoot}guide/topics/manifest/path-permission-element.html">
    -+        &lt;path-permission&gt;</a></code> dari
    -+        elemen <code><a href="{@docRoot}guide/topics/manifest/provider-element.html">
    -+        &lt;provider&gt;</a></code>. Untuk setiap URI konten yang ditetapkan, Anda bisa menetapkan
    -+        satu izin baca/tulis, satu izin baca, atau satu izin tulis, atau ketiganya. Izin baca dan
    -+        tulis akan didahulukan daripada izin baca/tulis. Juga,
    -+        izin tingkat path akan didahulukan daripada izin tingkat penyedia.
    -+    </dd>
    -+    <dt>
    -+        Izin sementara
    -+    </dt>
    -+    <dd>
    -+        Tingkat izin yang memberikan akses sementara ke aplikasi, sekalipun aplikasi itu
    -+        tidak memiliki izin yang biasanya diminta. Fitur akses
    -+         sementara mengurangi jumlah izin yang harus diminta aplikasi dalam
    -+        manifesnya. Bila Anda mengaktifkan izin sementara, satu-satunya aplikasi yang memerlukan
    -+        izin "permanen" untuk penyedia adalah aplikasi yang mengakses terus-menerus semua
    -+        data Anda.
    -+        <p>
    -+            Perhatikan izin yang Anda perlukan untuk mengimplementasikan penyedia dan aplikasi email, bila Anda
    -+            ingin memperbolehkan aplikasi penampil gambar dari luar menampilkan lampiran foto dari
    -+            penyedia Anda. Untuk memberikan akses yang diperlukan kepada penampil gambar tanpa mengharuskan izin,
    -+            siapkan izin sementara untuk URI konten bagi foto. Desainlah aplikasi email Anda agar
    -+            bila pengguna ingin menampilkan foto, aplikasi itu akan mengirim intent berisi
    -+            URI konten foto dan flag izin ke penampil gambar. Penampil gambar nanti bisa
    -+            melakukan query penyedia email untuk mengambil foto, sekalipun penampil itu tidak
    -+            memiliki izin baca normal untuk penyedia Anda.
    -+        </p>
    -+        <p>
    -+            Untuk mengaktifkan izin sementara, atur atribut
    -+            <code><a href="{@docRoot}guide/topics/manifest/provider-element.html#gprmsn">
    -+            android:grantUriPermissions</a></code> dari
    -+            elemen <code><a href="{@docRoot}guide/topics/manifest/provider-element.html">
    -+            &lt;provider&gt;</a></code>, atau tambahkan satu atau beberapa elemen anak
    -+            <code><a href="{@docRoot}guide/topics/manifest/grant-uri-permission-element.html">
    -+            &lt;grant-uri-permission&gt;</a></code> ke
    -+            elemen <code><a href="{@docRoot}guide/topics/manifest/provider-element.html">
    -+            &lt;provider&gt;</a></code> Anda. Jika menggunakan izin sementara, Anda harus memanggil
    -+            {@link android.content.Context#revokeUriPermission(Uri, int)
    -+            Context.revokeUriPermission()} kapan saja Anda menghilangkan dukungan untuk URI konten dari
    -+            penyedia, dan URI konten dikaitkan dengan izin sementara.
    -+        </p>
    -+        <p>
    -+            Nilai atribut menentukan seberapa banyak penyedia Anda yang dijadikan bisa diakses.
    -+            Jika atribut diatur ke <code>true</code>, maka sistem akan memberikan
    -+            izin sementara kepada seluruh penyedia, dengan mengesampingkan izin lain yang diharuskan
    -+            oleh izin tingkat penyedia atau tingkat path.
    -+        </p>
    -+        <p>
    -+            Jika flag ini diatur ke <code>false</code>, maka Anda harus menambahkan elemen-elemen anak
    -+            <code><a href="{@docRoot}guide/topics/manifest/grant-uri-permission-element.html">
    -+            &lt;grant-uri-permission&gt;</a></code> ke
    -+            elemen <code><a href="{@docRoot}guide/topics/manifest/provider-element.html">
    -+            &lt;provider&gt;</a></code> Anda. Tiap elemen anak menetapkan URI konten atau
    -+            URI yang telah diberi akses sementara.
    -+        </p>
    -+        <p>
    -+            Untuk mendelegasikan akses sementara ke sebuah aplikasi, intent harus berisi
    -+            {@link android.content.Intent#FLAG_GRANT_READ_URI_PERMISSION} atau flag
    -+            {@link android.content.Intent#FLAG_GRANT_WRITE_URI_PERMISSION}, atau keduanya. Keduanya
    -+            diatur dengan metode {@link android.content.Intent#setFlags(int) setFlags()}.
    -+        </p>
    -+        <p>
    -+            Jika atribut <code><a href="{@docRoot}guide/topics/manifest/provider-element.html#gprmsn">
    -+            android:grantUriPermissions</a></code> tidak ada, atribut ini diasumsikan sebagai
    -+            <code>false</code>.
    -+        </p>
    -+    </dd>
    -+</dl>
    -+
    -+
    -+
    -+<!-- The Provider Element -->
    -+<h2 id="ProviderElement">Elemen &lt;provider&gt;</h2>
    -+<p>
    -+    Seperti halnya komponen {@link android.app.Activity} dan {@link android.app.Service},
    -+    subkelas {@link android.content.ContentProvider}
    -+    harus didefinisikan dalam file manifes untuk aplikasinya, dengan menggunakan elemen
    -+    <code><a href="{@docRoot}guide/topics/manifest/provider-element.html">
    -+    &lt;provider&gt;</a></code>. Sistem Android mendapatkan informasi berikut dari
    -+    elemen:
    -+<dl>
    -+    <dt>
    -+        Otoritas
    -+        (<a href="{@docRoot}guide/topics/manifest/provider-element.html#auth">{@code
    -+        android:authorities}</a>)
    -+    </dt>
    -+    <dd>
    -+        Nama-nama simbolik yang mengidentifikasi seluruh penyedia dalam sistem. Atribut
    -+        ini dijelaskan lebih detail di bagian
    -+        <a href="#ContentURI">Mendesain URI Konten</a>.
    -+    </dd>
    -+    <dt>
    -+        Nama kelas penyedia
    -+        (<code>
    -+<a href="{@docRoot}guide/topics/manifest/provider-element.html#nm">android:name</a>
    -+        </code>)
    -+    </dt>
    -+    <dd>
    -+        Kelas yang mengimplementasikan {@link android.content.ContentProvider}. Kelas ini
    -+        dijelaskan lebih detail di bagian
    -+        <a href="#ContentProvider">Mengimplementasikan Kelas ContentProvider</a>.
    -+    </dd>
    -+    <dt>
    -+        Izin
    -+    </dt>
    -+    <dd>
    -+        Atribut-atribut yang menetapkan izin yang harus dimiliki aplikasi lain untuk mengakses
    -+        data penyedia:
    -+        <ul>
    -+            <li>
    -+                <code><a href="{@docRoot}guide/topics/manifest/provider-element.html#gprmsn">
    -+                android:grantUriPermssions</a></code>: Flag izin sementara.
    -+            </li>
    -+            <li>
    -+                <code><a href="{@docRoot}guide/topics/manifest/provider-element.html#prmsn">
    -+                android:permission</a></code>: Izin baca/tulis tunggal untuk tingkat penyedia.
    -+            </li>
    -+            <li>
    -+                <code><a href="{@docRoot}guide/topics/manifest/provider-element.html#rprmsn">
    -+                android:readPermission</a></code>: Izin baca untuk tingkat penyedia.
    -+            </li>
    -+            <li>
    -+                <code><a href="{@docRoot}guide/topics/manifest/provider-element.html#wprmsn">
    -+                android:writePermission</a></code>: Izin tulis untuk tingkat penyedia.
    -+            </li>
    -+        </ul>
    -+        <p>
    -+            Izin dan atribut-atribut yang sesuai dijelaskan lebih detail
    -+            di bagian
    -+            <a href="#Permissions">Mengimplementasikan Izin Penyedia Konten</a>.
    -+        </p>
    -+    </dd>
    -+    <dt>
    -+        Atribut-atribut startup dan kontrol
    -+    </dt>
    -+    <dd>
    -+        Atribut-atribut ini menentukan cara dan waktu sistem Android memulai penyedia,
    -+        karakteristik proses penyedia, dan pengaturan runtime lainnya:
    -+        <ul>
    -+            <li>
    -+                <code><a href="{@docRoot}guide/topics/manifest/provider-element.html#enabled">
    -+                android:enabled</a></code>: Flag yang memperbolehkan sistem untuk memulai penyedia.
    -+            </li>
    -+              <li>
    -+                <code><a href="{@docRoot}guide/topics/manifest/provider-element.html#exported">
    -+                android:exported</a></code>: Flag yang memperbolehkan aplikasi lain untuk menggunakan penyedia ini.
    -+            </li>
    -+            <li>
    -+                <code><a href="{@docRoot}guide/topics/manifest/provider-element.html#init">
    -+                android:initOrder</a></code>: Urutan yang digunakan untuk memulai penyedia ini,
    -+                relatif terhadap penyedia lain dalam proses yang sama.
    -+            </li>
    -+            <li>
    -+                <code><a href="{@docRoot}guide/topics/manifest/provider-element.html#multi">
    -+                android:multiProcess</a></code>: Flag yang memperbolehkan sistem untuk memulai penyedia
    -+                dalam proses yang sama dengan proses klien pemanggil.
    -+            </li>
    -+            <li>
    -+                <code><a href="{@docRoot}guide/topics/manifest/provider-element.html#proc">
    -+                android:process</a></code>: Nama proses tempat penyedia harus
    -+                berjalan.
    -+            </li>
    -+            <li>
    -+                <code><a href="{@docRoot}guide/topics/manifest/provider-element.html#sync">
    -+                android:syncable</a></code>: Flag yang menunjukkan bahwa data penyedia harus
    -+                disinkronkan dengan data di server.
    -+            </li>
    -+        </ul>
    -+        <p>
    -+            Atribut-atribut ini didokumentasikan dengan lengkap dalam topik panduan pengembang untuk elemen
    -+            <code><a href="{@docRoot}guide/topics/manifest/provider-element.html">
    -+            &lt;provider&gt;</a></code>.
    -+
    -+        </p>
    -+    </dd>
    -+    <dt>
    -+        Atribut-atribut informatif
    -+    </dt>
    -+    <dd>
    -+        Ikon dan label opsional untuk penyedia:
    -+        <ul>
    -+            <li>
    -+                <code><a href="{@docRoot}guide/topics/manifest/provider-element.html#icon">
    -+                android:icon</a></code>: Sumber daya drawable, berisi ikon untuk penyedia.
    -+                Ikon ini muncul di sebelah label penyedia dalam daftar aplikasi dalam menu
    -+                <em>Settings</em> &gt; <em>Apps</em> &gt; <em>All</em>.
    -+            </li>
    -+            <li>
    -+                <code><a href="{@docRoot}guide/topics/manifest/provider-element.html#label">
    -+                android:label</a></code>: Label informatif yang menjelaskan penyedia atau
    -+                datanya, atau keduanya. Label ini muncul dalam daftar aplikasi di
    -+                <em>Settings</em> &gt; <em>Apps</em> &gt; <em>All</em>.
    -+            </li>
    -+        </ul>
    -+        <p>
    -+            Atribut-atribut ini didokumentasikan dengan lengkap dalam topik panduan pengembang untuk elemen
    -+            <code><a href="{@docRoot}guide/topics/manifest/provider-element.html">
    -+            &lt;provider&gt;</a></code>.
    -+        </p>
    -+    </dd>
    -+</dl>
    -+
    -+<!-- Intent Access -->
    -+<h2 id="Intents">Intent dan Akses Data</h2>
    -+<p>
    -+    Aplikasi bisa mengakses penyedia konten secara tidak langsung dengan sebuah {@link android.content.Intent}.
    -+    Aplikasi tidak memanggil satu pun dari metode-metode {@link android.content.ContentResolver} atau
    -+    {@link android.content.ContentProvider}. Sebagai gantinya, aplikasi mengirim intent yang memulai aktivitas,
    -+    yang sering kali merupakan bagian dari aplikasi penyedia sendiri. Aktivitas tujuan bertugas
    -+    mengambil dan menampilkan data dalam UI-nya. Bergantung pada tindakan dalam intent,
    -+    aktivitas tujuan juga bisa meminta pengguna untuk membuat modifikasi pada data penyedia.
    -+    Intent juga bisa berisi data "ekstra" yang menampilkan aktivitas tujuan
    -+    dalam UI; pengguna nanti memiliki pilihan untuk mengubah data ini sebelum menggunakannya untuk mengubah
    -+    data di penyedia.
    -+</p>
    -+<p>
    -+
    -+</p>
    -+<p>
    -+    Anda mungkin perlu menggunakan akses intent guna membantu memastikan integritas data. Penyedia Anda mungkin bergantung
    -+    pada data yang disisipkan, diperbarui, dan dihapusnya sesuai dengan logika bisnis yang didefinisikan dengan ketat. Jika
    -+    demikian halnya, memperbolehkan aplikasi lain mengubah data Anda secara langsung bisa menyebabkan
    -+    data yang tidak sah. Jika Anda ingin pengembang menggunakan akses intent, pastikan untuk mendokumentasikannya secara saksama.
    -+    Jelaskan kepada mereka alasan akses intent yang menggunakan UI aplikasi Anda sendiri adalah lebih baik daripada mencoba
    -+    memodifikasi data dengan kode mereka.
    -+</p>
    -+<p>
    -+    Menangani sebuah intent masuk yang ingin memodifikasi data penyedia Anda tidak berbeda dengan
    -+    menangani intent lainnya. Anda bisa mengetahui selengkapnya tentang penggunaan intent dengan membaca topik
    -+    <a href="{@docRoot}guide/components/intents-filters.html">Intent dan Filter Intent</a>.
    -+</p>
    -diff --git a/docs/html-intl/intl/id/guide/topics/providers/content-providers.jd b/docs/html-intl/intl/id/guide/topics/providers/content-providers.jd
    -new file mode 100644
    -index 0000000..2dcd55e
    ---- /dev/null
    -+++ b/docs/html-intl/intl/id/guide/topics/providers/content-providers.jd
    -@@ -0,0 +1,108 @@
    -+page.title=Penyedia konten
    -+@jd:body
    -+<div id="qv-wrapper">
    -+<div id="qv">
    -+
    -+
    -+<!-- In this document -->
    -+<h2>Topik</h2>
    -+<ol>
    -+    <li>
    -+        <a href="{@docRoot}guide/topics/providers/content-provider-basics.html">
    -+        Dasar-Dasar Penyedia Konten</a>
    -+    </li>
    -+    <li>
    -+        <a href="{@docRoot}guide/topics/providers/content-provider-creating.html">
    -+        Membuat Penyedia Konten</a>
    -+    </li>
    -+    <li>
    -+        <a href="{@docRoot}guide/topics/providers/calendar-provider.html">Penyedia Kalender</a>
    -+    </li>
    -+    <li>
    -+        <a href="{@docRoot}guide/topics/providers/contacts-provider.html">Penyedia Kontak</a>
    -+    </li>
    -+</ol>
    -+
    -+    <!-- Related Samples -->
    -+<h2>Contoh-Contoh Terkait</h2>
    -+    <ol>
    -+        <li>
    -+            <a href="{@docRoot}resources/samples/ContactManager/index.html">
    -+            Aplikasi Contact Manager</a>
    -+        </li>
    -+        <li>
    -+        <a href="{@docRoot}resources/samples/ApiDemos/src/com/example/android/apis/view/List2.html">
    -+        "Kursor (Orang)"
    -+        </a>
    -+        </li>
    -+        <li>
    -+        <a href="{@docRoot}resources/samples/ApiDemos/src/com/example/android/apis/view/List7.html">
    -+        "Kursor (Telepon)"</a>
    -+        </li>
    -+        <li>
    -+            <a href="{@docRoot}resources/samples/SampleSyncAdapter/index.html">
    -+            Contoh Adaptor Sinkronisasi</a>
    -+        </li>
    -+    </ol>
    -+</div>
    -+</div>
    -+<p>
    -+    Penyedia konten mengelola akses ke set data terstruktur. Penyedia ini membungkus
    -+ data, dan menyediakan mekanisme untuk mendefinisikan keamanan data. Penyedia konten adalah antarmuka
    -+ standar yang menghubungkan data dalam satu proses dengan kode yang berjalan dalam proses lain.
    -+</p>
    -+<p>
    -+    Bila Anda ingin mengakses data di penyedia konten, Anda menggunakan
    -+ {@link android.content.ContentResolver} objek dalam
    -+ {@link android.content.Context} aplikasi untuk berkomunikasi dengan penyedia sebagai klien.
    -+    Objek {@link android.content.ContentResolver} berkomunikasi dengan objek penyedia, yakni
    -+ instance kelas yang mengimplementasikan {@link android.content.ContentProvider}. Objek penyedia
    -+ menerima permintaan data dari klien, melakukan tindakan yang diminta, dan
    -+ mengembalikan hasilnya.
    -+</p>
    -+<p>
    -+    Anda tidak perlu mengembangkan penyedia sendiri jika tidak bermaksud untuk berbagi data dengan
    -+ aplikasi lain. Akan tetapi, Anda memerlukan penyedia buatan sendiri untuk menyediakan saran pencarian custom
    -+ dalam aplikasi Anda sendiri. Anda juga memerlukan penyedia sendiri jika ingin menyalin dan
    -+menempelkan data atau file yang kompleks dari aplikasi Anda ke aplikasi lain.
    -+</p>
    -+<p>
    -+    Android sendiri berisi penyedia konten yang mengelola data seperti informasi audio, video, gambar, dan
    -+ kontak pribadi. Anda bisa melihat sebagian informasi ini tercantum dalam dokumentasi
    -+ acuan untuk paket
    -+ <code><a href="{@docRoot}reference/android/provider/package-summary.html">android.provider</a>
    -+    </code>. Dengan beberapa batasan, semua penyedia ini bisa diakses oleh aplikasi Android
    -+ apa saja.
    -+</p><p>
    -+    Topik-topik berikut menjelaskan penyedia konten secara lebih detail:
    -+</p>
    -+<dl>
    -+    <dt>
    -+        <strong><a href="{@docRoot}guide/topics/providers/content-provider-basics.html">
    -+        Dasar-Dasar Penyedia Konten</a></strong>
    -+    </dt>
    -+    <dd>
    -+        Cara mengakses data di penyedia konten bila data disusun dalam tabel.
    -+    </dd>
    -+    <dt>
    -+        <strong><a href="{@docRoot}guide/topics/providers/content-provider-creating.html">
    -+        Membuat Penyedia Konten</a></strong>
    -+    </dt>
    -+    <dd>
    -+        Cara membuat penyedia konten sendiri.
    -+    </dd>
    -+    <dt>
    -+        <strong><a href="{@docRoot}guide/topics/providers/calendar-provider.html">
    -+        Penyedia Kalender</a></strong>
    -+    </dt>
    -+    <dd>
    -+        Cara mengakses Penyedia Kalender yang merupakan bagian dari platform Android.
    -+    </dd>
    -+    <dt>
    -+        <strong><a href="{@docRoot}guide/topics/providers/contacts-provider.html">
    -+        Penyedia Kontak</a></strong>
    -+    </dt>
    -+    <dd>
    -+        Cara mengakses Penyedia Kontak yang merupakan bagian dari platform Android.
    -+    </dd>
    -+</dl>
    -diff --git a/docs/html-intl/intl/id/guide/topics/providers/document-provider.jd b/docs/html-intl/intl/id/guide/topics/providers/document-provider.jd
    -new file mode 100644
    -index 0000000..f857467
    ---- /dev/null
    -+++ b/docs/html-intl/intl/id/guide/topics/providers/document-provider.jd
    -@@ -0,0 +1,916 @@
    -+page.title=Storage Access Framework
    -+@jd:body
    -+<div id="qv-wrapper">
    -+<div id="qv">
    -+
    -+<h2>Dalam dokumen ini
    -+ <a href="#" onclick="hideNestedItems('#toc44',this);return false;" class="header-toggle">
    -+        <span class="more">tampilkan maksimal</span>
    -+        <span class="less" style="display:none">tampilkan minimal</span></a></h2>
    -+<ol id="toc44" class="hide-nested">
    -+    <li>
    -+        <a href="#overview">Ikhtisar</a>
    -+    </li>
    -+    <li>
    -+        <a href="#flow">Arus Kontrol</a>
    -+    </li>
    -+    <li>
    -+        <a href="#client">Menulis Aplikasi Klien</a>
    -+        <ol>
    -+        <li><a href="#search">Mencari dokumen</a></li>
    -+        <li><a href="#process">Memproses hasil</a></li>
    -+        <li><a href="#metadata">Memeriksa metadata dokumen</a></li>
    -+        <li><a href="#open">Membuka dokumen</a></li>
    -+        <li><a href="#create">Membuat dokumen baru</a></li>
    -+        <li><a href="#delete">Menghapus dokumen</a></li>
    -+        <li><a href="#edit">Mengedit dokumen</a></li>
    -+        <li><a href="#permissions">Mempertahankan izin</a></li>
    -+        </ol>
    -+    </li>
    -+    <li><a href="#custom">Menulis Penyedia Dokumen Custom</a>
    -+        <ol>
    -+        <li><a href="#manifest">Manifes</a></li>
    -+        <li><a href="#contract">Kontrak</a></li>
    -+        <li><a href="#subclass">Subkelas DocumentsProvider</a></li>
    -+        <li><a href="#security">Keamanan</a></li>
    -+        </ol>
    -+    </li>
    -+
    -+</ol>
    -+<h2>Kelas-kelas utama</h2>
    -+<ol>
    -+    <li>{@link android.provider.DocumentsProvider}</li>
    -+    <li>{@link android.provider.DocumentsContract}</li>
    -+</ol>
    -+
    -+<h2>Video</h2>
    -+
    -+<ol>
    -+    <li><a href="http://www.youtube.com/watch?v=zxHVeXbK1P4">
    -+DevBytes: Android 4.4 Storage Access Framework: Penyedia</a></li>
    -+     <li><a href="http://www.youtube.com/watch?v=UFj9AEz0DHQ">
    -+DevBytes: Android 4.4 Storage Access Framework: Klien</a></li>
    -+</ol>
    -+
    -+
    -+<h2>Contoh Kode</h2>
    -+
    -+<ol>
    -+    <li><a href="{@docRoot}samples/StorageProvider/index.html">
    -+Penyedia Penyimpanan</a></li>
    -+     <li><a href="{@docRoot}samples/StorageClient/index.html">
    -+Klien Penyimpanan</a></li>
    -+</ol>
    -+
    -+<h2>Lihat Juga</h2>
    -+<ol>
    -+    <li>
    -+        <a href="{@docRoot}guide/topics/providers/content-provider-basics.html">
    -+        Dasar-Dasar Penyedia Konten
    -+        </a>
    -+    </li>
    -+</ol>
    -+
    -+</div>
    -+</div>
    -+
    -+
    -+<p>Android 4.4 (API level 19) memperkenalkan Storage Access Framework (SAF, Kerangka Kerja Akses Penyimpanan). SAF
    -+ memudahkan pengguna menyusuri dan membuka dokumen, gambar, dan file lainnya
    -+di semua penyedia penyimpanan dokumen pilihannya. UI standar yang mudah digunakan
    -+memungkinkan pengguna menyusuri file dan mengakses yang terbaru dengan cara konsisten di antara berbagai aplikasi dan penyedia.</p>
    -+
    -+<p>Layanan penyimpanan cloud atau lokal bisa dilibatkan dalam ekosistem ini dengan mengimplementasikan sebuah
    -+{@link android.provider.DocumentsProvider} yang membungkus layanannya. Aplikasi klien
    -+yang memerlukan akses ke dokumen sebuah penyedia bisa berintegrasi dengan SAF cukup dengan beberapa
    -+baris kode.</p>
    -+
    -+<p>SAF terdiri dari berikut ini:</p>
    -+
    -+<ul>
    -+<li><strong>Penyedia dokumen</strong>&mdash;Penyedia konten yang memungkinkan
    -+layanan penyimpanan (seperti Google Drive) untuk menampilkan file yang dikelolanya. Penyedia dokumen
    -+diimplementasikan sebagai subkelas dari kelas {@link android.provider.DocumentsProvider}.
    -+Skema penyedia dokumen berdasarkan hierarki file biasa,
    -+walaupun cara penyedia dokumen Anda secara fisik menyimpan data adalah terserah Anda.
    -+Platform Android terdiri dari beberapa penyedia dokumen bawaan, seperti
    -+Downloads, Images, dan Videos.</li>
    -+
    -+<li><strong>Aplikasi klien</strong>&mdash;Aplikasi custom yang memanggil intent
    -+{@link android.content.Intent#ACTION_OPEN_DOCUMENT} dan/atau
    -+{@link android.content.Intent#ACTION_CREATE_DOCUMENT} dan menerima
    -+file yang dihasilkan penyedia dokumen.</li>
    -+
    -+<li><strong>Picker</strong>&mdash;UI sistem yang memungkinkan pengguna mengakses dokumen dari semua
    -+penyedia dokumen yang memenuhi kriteria pencarian aplikasi klien.</li>
    -+</ul>
    -+
    -+<p>Beberapa fitur yang disediakan oleh SAF adalah sebagai berikut:</p>
    -+<ul>
    -+<li>Memungkinkan pengguna menyusuri konten dari semua penyedia dokumen, bukan hanya satu aplikasi.</li>
    -+<li>Memungkinkan aplikasi Anda memiliki akses jangka panjang dan tetap ke
    -+ dokumen yang dimiliki oleh penyedia dokumen. Melalui akses ini pengguna bisa menambah, mengedit,
    -+ menyimpan, dan menghapus file pada penyedia.</li>
    -+<li>Mendukung banyak akun pengguna dan akar jangka pendek seperti penyedia penyimpanan
    -+USB, yang hanya muncul jika drive itu dipasang. </li>
    -+</ul>
    -+
    -+<h2 id ="overview">Ikhtisar</h2>
    -+
    -+<p>SAF berpusat di seputar penyedia konten yang merupakan
    -+subkelas dari kelas {@link android.provider.DocumentsProvider}. Dalam <em>penyedia dokumen</em>, data
    -+distrukturkan sebagai hierarki file biasa:</p>
    -+<p><img src="{@docRoot}images/providers/storage_datamodel.png" alt="data model" /></p>
    -+<p class="img-caption"><strong>Gambar 1.</strong> Model data penyedia dokumen. Root menunjuk ke satu Document,
    -+yang nanti memulai pemekaran seluruh pohon.</p>
    -+
    -+<p>Perhatikan yang berikut ini:</p>
    -+<ul>
    -+
    -+<li>Setiap penyedia dokumen melaporkan satu atau beberapa
    -+"akar" yang merupakan titik awal penyusuran pohon dokumen.
    -+Masing-masing akar memiliki sebuah {@link android.provider.DocumentsContract.Root#COLUMN_ROOT_ID} yang unik,
    -+dan menunjuk ke satu dokumen (satu direktori)
    -+yang mewakili konten di bawah akar itu.
    -+Akar sengaja dibuat dinamis untuk mendukung kasus penggunaan seperti multiakun,
    -+perangkat penyimpanan USB jangka pendek, atau masuk/keluar pengguna.</li>
    -+
    -+<li>Di bawah tiap akar terdapat satu dokumen. Dokumen itu menunjuk ke dokumen-dokumen 1-ke-<em>N</em>,
    -+yang nanti masing-masing bisa menunjuk ke dokumen 1-ke-<em>N</em>. </li>
    -+
    -+<li>Tiap backend penyimpanan memunculkan
    -+masing-masing file dan direktori dengan mengacunya lewat sebuah
    -+{@link android.provider.DocumentsContract.Document#COLUMN_DOCUMENT_ID} yang unik.
    -+ID dokumen harus unik dan tidak berubah setelah dibuat, karena ID ini digunakan untuk
    -+URI persisten yang diberikan pada saat reboot perangkat.</li>
    -+
    -+
    -+<li>Dokumen bisa berupa file yang bisa dibuka (dengan tipe MIME tertentu), atau
    -+direktori yang berisi dokumen tambahan (dengan tipe MIME
    -+{@link android.provider.DocumentsContract.Document#MIME_TYPE_DIR}).</li>
    -+
    -+<li>Tiap dokumen bisa mempunyai kemampuan berbeda, sebagaimana yang dijelaskan oleh
    -+{@link android.provider.DocumentsContract.Document#COLUMN_FLAGS COLUMN_FLAGS}.
    -+Misalnya, {@link android.provider.DocumentsContract.Document#FLAG_SUPPORTS_WRITE},
    -+{@link android.provider.DocumentsContract.Document#FLAG_SUPPORTS_DELETE}, dan
    -+{@link android.provider.DocumentsContract.Document#FLAG_SUPPORTS_THUMBNAIL}.
    -+{@link android.provider.DocumentsContract.Document#COLUMN_DOCUMENT_ID} yang sama bisa
    -+dimasukkan dalam beberapa direktori.</li>
    -+</ul>
    -+
    -+<h2 id="flow">Arus Kontrol</h2>
    -+<p>Seperti dinyatakan di atas, model data penyedia dokumen dibuat berdasarkan hierarki file
    -+biasa. Akan tetapi, Anda bisa menyimpan secara fisik data dengan cara apa pun yang disukai,
    -+selama data bisa diakses melalui API {@link android.provider.DocumentsProvider}. Misalnya, Anda
    -+bisa menggunakan penyimpanan cloud berbasis tag untuk data Anda.</p>
    -+
    -+<p>Gambar 2 menampilkan contoh cara aplikasi foto bisa menggunakan SAF
    -+untuk mengakses data tersimpan:</p>
    -+<p><img src="{@docRoot}images/providers/storage_dataflow.png" alt="app" /></p>
    -+
    -+<p class="img-caption"><strong>Gambar 2.</strong> Arus Storage Access Framework</p>
    -+
    -+<p>Perhatikan yang berikut ini:</p>
    -+<ul>
    -+
    -+<li>Di SAF, penyedia dan klien tidak berinteraksi
    -+secara langsung. Klien meminta izin untuk berinteraksi
    -+dengan file (yakni, membaca, mengedit, membuat, atau menghapus file).</li>
    -+
    -+<li>Interaksi dimulai bila sebuah aplikasi (dalam contoh ini adalah aplikasi foto) mengeluarkan intent
    -+{@link android.content.Intent#ACTION_OPEN_DOCUMENT} atau {@link android.content.Intent#ACTION_CREATE_DOCUMENT}. Intent bisa berisi filter
    -+untuk mempersempit kriteria&mdash;misalnya, "beri saya semua file yang bisa dibuka
    -+yang memiliki tipe MIME 'gambar'".</li>
    -+
    -+<li>Setelah intent dibuat, picker sistem akan pergi ke setiap penyedia yang terdaftar
    -+dan menunjukkan kepada pengguna akar konten yang cocok.</li>
    -+
    -+<li>Picker memberi pengguna antarmuka standar untuk mengakses dokumen,
    -+walaupun penyedia dokumen dasar bisa sangat berbeda. Misalnya, gambar 2
    -+menunjukkan penyedia Google Drive, penyedia USB, dan penyedia cloud.</li>
    -+</ul>
    -+
    -+<p>Gambar 3 menunjukkan picker yang di digunakan pengguna mencari gambar telah memilih
    -+akun Google Drive:</p>
    -+
    -+<p><img src="{@docRoot}images/providers/storage_picker.png" width="340" alt="picker" style="border:2px solid #ddd" /></p>
    -+
    -+<p class="img-caption"><strong>Gambar 3.</strong> Picker</p>
    -+
    -+<p>Bila pengguna memilih Google Drive, gambar-gambar akan ditampilkan, seperti yang ditampilkan dalam
    -+gambar 4. Dari titik itu, pengguna bisa berinteraksi dengan gambar dengan cara apa pun
    -+yang didukung oleh penyedia dan aplikasi klien.
    -+
    -+<p><img src="{@docRoot}images/providers/storage_photos.png" width="340" alt="picker" style="border:2px solid #ddd" /></p>
    -+
    -+<p class="img-caption"><strong>Gambar 4.</strong> Gambar</p>
    -+
    -+<h2 id="client">Menulis Aplikasi Klien</h2>
    -+
    -+<p>Pada Android 4.3 dan yang lebih rendah, jika Anda ingin aplikasi mengambil file dari
    -+aplikasi lain, aplikasi Anda harus memanggil intent seperti {@link android.content.Intent#ACTION_PICK}
    -+atau {@link android.content.Intent#ACTION_GET_CONTENT}. Pengguna nanti harus memilih
    -+satu aplikasi yang akan digunakan untuk mengambil file dan aplikasi yang dipilih harus menyediakan antarmuka pengguna
    -+bagi untuk menyusuri dan mengambil dari file yang tersedia. </p>
    -+
    -+<p>Pada Android 4.4 dan yang lebih tinggi, Anda mempunyai opsi tambahan dalam menggunakan intent
    -+{@link android.content.Intent#ACTION_OPEN_DOCUMENT},
    -+yang menampilkan UI picker yang dikontrol oleh sistem yang memungkinkan pengguna
    -+menyusuri semua file yang disediakan aplikasi lain. Dari satu UI ini, pengguna
    -+bisa mengambil file dari aplikasi apa saja yang didukung.</p>
    -+
    -+<p>{@link android.content.Intent#ACTION_OPEN_DOCUMENT}
    -+tidak dimaksudkan untuk menjadi pengganti {@link android.content.Intent#ACTION_GET_CONTENT}.
    -+Yang harus Anda gunakan bergantung pada kebutuhan aplikasi:</p>
    -+
    -+<ul>
    -+<li>Gunakan {@link android.content.Intent#ACTION_GET_CONTENT} jika Anda ingin aplikasi
    -+cuma membaca/mengimpor data. Dengan pendekatan ini, aplikasi akan mengimpor salinan data,
    -+misalnya file gambar.</li>
    -+
    -+<li>Gunakan {@link android.content.Intent#ACTION_OPEN_DOCUMENT} jika Anda ingin aplikasi
    -+memiliki akses jangka panjang dan jangka pendek ke dokumen yang dimiliki oleh penyedia
    -+dokumen. Contohnya adalah aplikasi pengeditan foto yang memungkinkan pengguna mengedit
    -+gambar yang tersimpan dalam penyedia dokumen. </li>
    -+
    -+</ul>
    -+
    -+
    -+<p>Bagian ini menjelaskan cara menulis aplikasi klien berdasarkan
    -+{@link android.content.Intent#ACTION_OPEN_DOCUMENT} dan
    -+intent {@link android.content.Intent#ACTION_CREATE_DOCUMENT}.</p>
    -+
    -+
    -+<h3 id="search">Mencari dokumen</h3>
    -+
    -+<p>
    -+Cuplikan berikut menggunakan {@link android.content.Intent#ACTION_OPEN_DOCUMENT}
    -+untuk mencari penyedia dokumen yang
    -+berisi file gambar:</p>
    -+
    -+<pre>private static final int READ_REQUEST_CODE = 42;
    -+...
    -+/**
    -+ * Fires an intent to spin up the &quot;file chooser&quot; UI and select an image.
    -+ */
    -+public void performFileSearch() {
    -+
    -+    // ACTION_OPEN_DOCUMENT is the intent to choose a file via the system's file
    -+    // browser.
    -+    Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT);
    -+
    -+    // Filter to only show results that can be &quot;opened&quot;, such as a
    -+    // file (as opposed to a list of contacts or timezones)
    -+    intent.addCategory(Intent.CATEGORY_OPENABLE);
    -+
    -+    // Filter to show only images, using the image MIME data type.
    -+    // If one wanted to search for ogg vorbis files, the type would be &quot;audio/ogg&quot;.
    -+    // To search for all documents available via installed storage providers,
    -+    // it would be &quot;*/*&quot;.
    -+    intent.setType(&quot;image/*&quot;);
    -+
    -+    startActivityForResult(intent, READ_REQUEST_CODE);
    -+}</pre>
    -+
    -+<p>Perhatikan yang berikut ini:</p>
    -+<ul>
    -+<li>Saat aplikasi mengeluarkan intent {@link android.content.Intent#ACTION_OPEN_DOCUMENT}
    -+, aplikasi akan menjalankan picker yang menampilkan semua penyedia dokumen yang cocok.</li>
    -+
    -+<li>Menambahkan kategori {@link android.content.Intent#CATEGORY_OPENABLE} ke
    -+intent akan menyaring hasil agar hanya menampilkan dokumen yang bisa dibuka, seperti file gambar.</li>
    -+
    -+<li>Pernyataan {@code intent.setType("image/*")} menyaring lebih jauh agar hanya
    -+menampilkan dokumen yang memiliki tipe data MIME gambar.</li>
    -+</ul>
    -+
    -+<h3 id="results">Memproses Hasil</h3>
    -+
    -+<p>Setelah pengguna memilih dokumen di picker,
    -+{@link android.app.Activity#onActivityResult onActivityResult()} akan dipanggil.
    -+URI yang menunjuk ke dokumen yang dipilih dimasukkan dalam parameter {@code resultData}
    -+. Ekstrak URI dengan {@link android.content.Intent#getData getData()}.
    -+Setelah mendapatkannya, Anda bisa menggunakannya untuk mengambil dokumen yang diinginkan pengguna. Misalnya
    -+:</p>
    -+
    -+<pre>&#64;Override
    -+public void onActivityResult(int requestCode, int resultCode,
    -+        Intent resultData) {
    -+
    -+    // The ACTION_OPEN_DOCUMENT intent was sent with the request code
    -+    // READ_REQUEST_CODE. If the request code seen here doesn't match, it's the
    -+    // response to some other intent, and the code below shouldn't run at all.
    -+
    -+    if (requestCode == READ_REQUEST_CODE && resultCode == Activity.RESULT_OK) {
    -+        // The document selected by the user won't be returned in the intent.
    -+        // Instead, a URI to that document will be contained in the return intent
    -+        // provided to this method as a parameter.
    -+        // Pull that URI using resultData.getData().
    -+        Uri uri = null;
    -+        if (resultData != null) {
    -+            uri = resultData.getData();
    -+            Log.i(TAG, "Uri: " + uri.toString());
    -+            showImage(uri);
    -+        }
    -+    }
    -+}
    -+</pre>
    -+
    -+<h3 id="metadata">Memeriksa metadata dokumen</h3>
    -+
    -+<p>Setelah Anda memiliki URI untuk dokumen, Anda akan mendapatkan akses ke metadatanya. Cuplikan
    -+ini memegang metadata sebuah dokumen yang disebutkan oleh URI, dan mencatatnya:</p>
    -+
    -+<pre>public void dumpImageMetaData(Uri uri) {
    -+
    -+    // The query, since it only applies to a single document, will only return
    -+    // one row. There's no need to filter, sort, or select fields, since we want
    -+    // all fields for one document.
    -+    Cursor cursor = getActivity().getContentResolver()
    -+            .query(uri, null, null, null, null, null);
    -+
    -+    try {
    -+    // moveToFirst() returns false if the cursor has 0 rows.  Very handy for
    -+    // &quot;if there's anything to look at, look at it&quot; conditionals.
    -+        if (cursor != null &amp;&amp; cursor.moveToFirst()) {
    -+
    -+            // Note it's called &quot;Display Name&quot;.  This is
    -+            // provider-specific, and might not necessarily be the file name.
    -+            String displayName = cursor.getString(
    -+                    cursor.getColumnIndex(OpenableColumns.DISPLAY_NAME));
    -+            Log.i(TAG, &quot;Display Name: &quot; + displayName);
    -+
    -+            int sizeIndex = cursor.getColumnIndex(OpenableColumns.SIZE);
    -+            // If the size is unknown, the value stored is null.  But since an
    -+            // int can't be null in Java, the behavior is implementation-specific,
    -+            // which is just a fancy term for &quot;unpredictable&quot;.  So as
    -+            // a rule, check if it's null before assigning to an int.  This will
    -+            // happen often:  The storage API allows for remote files, whose
    -+            // size might not be locally known.
    -+            String size = null;
    -+            if (!cursor.isNull(sizeIndex)) {
    -+                // Technically the column stores an int, but cursor.getString()
    -+                // will do the conversion automatically.
    -+                size = cursor.getString(sizeIndex);
    -+            } else {
    -+                size = &quot;Unknown&quot;;
    -+            }
    -+            Log.i(TAG, &quot;Size: &quot; + size);
    -+        }
    -+    } finally {
    -+        cursor.close();
    -+    }
    -+}
    -+</pre>
    -+
    -+<h3 id="open-client">Membuka dokumen</h3>
    -+
    -+<p>Setelah mendapatkan URI dokumen, Anda bisa membuka dokumen atau melakukan apa saja
    -+yang diinginkan padanya.</p>
    -+
    -+<h4>Bitmap</h4>
    -+
    -+<p>Berikut ini adalah contoh cara membuka {@link android.graphics.Bitmap}:</p>
    -+
    -+<pre>private Bitmap getBitmapFromUri(Uri uri) throws IOException {
    -+    ParcelFileDescriptor parcelFileDescriptor =
    -+            getContentResolver().openFileDescriptor(uri, "r");
    -+    FileDescriptor fileDescriptor = parcelFileDescriptor.getFileDescriptor();
    -+    Bitmap image = BitmapFactory.decodeFileDescriptor(fileDescriptor);
    -+    parcelFileDescriptor.close();
    -+    return image;
    -+}
    -+</pre>
    -+
    -+<p>Perhatikan bahwa Anda tidak boleh melakukan operasi ini pada thread UI. Lakukan hal ini di latar belakang
    -+, dengan menggunakan {@link android.os.AsyncTask}. Setelah membuka bitmap, Anda
    -+bisa menampilkannya dalam {@link android.widget.ImageView}.
    -+</p>
    -+
    -+<h4>Mendapatkan InputStream</h4>
    -+
    -+<p>Berikut ini adalah contoh cara mendapatkan {@link java.io.InputStream} dari URI. Dalam cuplikan ini
    -+, baris-baris file dibaca ke dalam sebuah string:</p>
    -+
    -+<pre>private String readTextFromUri(Uri uri) throws IOException {
    -+    InputStream inputStream = getContentResolver().openInputStream(uri);
    -+    BufferedReader reader = new BufferedReader(new InputStreamReader(
    -+            inputStream));
    -+    StringBuilder stringBuilder = new StringBuilder();
    -+    String line;
    -+    while ((line = reader.readLine()) != null) {
    -+        stringBuilder.append(line);
    -+    }
    -+    fileInputStream.close();
    -+    parcelFileDescriptor.close();
    -+    return stringBuilder.toString();
    -+}
    -+</pre>
    -+
    -+<h3 id="create">Membuat dokumen baru</h3>
    -+
    -+<p>Aplikasi Anda bisa membuat dokumen baru dalam penyedia dokumen dengan menggunakan intent
    -+{@link android.content.Intent#ACTION_CREATE_DOCUMENT}
    -+. Untuk membuat file, Anda memberikan satu tipe MIME dan satu nama file pada intent, dan
    -+menjalankannya dengan kode permintaan yang unik. Selebihnya akan diurus untuk Anda:</p>
    -+
    -+
    -+<pre>
    -+// Here are some examples of how you might call this method.
    -+// The first parameter is the MIME type, and the second parameter is the name
    -+// of the file you are creating:
    -+//
    -+// createFile("text/plain", "foobar.txt");
    -+// createFile("image/png", "mypicture.png");
    -+
    -+// Unique request code.
    -+private static final int WRITE_REQUEST_CODE = 43;
    -+...
    -+private void createFile(String mimeType, String fileName) {
    -+    Intent intent = new Intent(Intent.ACTION_CREATE_DOCUMENT);
    -+
    -+    // Filter to only show results that can be &quot;opened&quot;, such as
    -+    // a file (as opposed to a list of contacts or timezones).
    -+    intent.addCategory(Intent.CATEGORY_OPENABLE);
    -+
    -+    // Create a file with the requested MIME type.
    -+    intent.setType(mimeType);
    -+    intent.putExtra(Intent.EXTRA_TITLE, fileName);
    -+    startActivityForResult(intent, WRITE_REQUEST_CODE);
    -+}
    -+</pre>
    -+
    -+<p>Setelah membuat dokumen baru, Anda bisa mendapatkan URI-nya dalam
    -+{@link android.app.Activity#onActivityResult onActivityResult()}, sehingga Anda
    -+bisa terus menulis ke dokumen itu.</p>
    -+
    -+<h3 id="delete">Menghapus dokumen</h3>
    -+
    -+<p>Jika Anda memiliki URI dokumen dan
    -+{@link android.provider.DocumentsContract.Document#COLUMN_FLAGS Document.COLUMN_FLAGS}
    -+ dokumen berisi
    -+{@link android.provider.DocumentsContract.Document#FLAG_SUPPORTS_DELETE SUPPORTS_DELETE},
    -+Anda bisa menghapus dokumen tersebut. Misalnya:</p>
    -+
    -+<pre>
    -+DocumentsContract.deleteDocument(getContentResolver(), uri);
    -+</pre>
    -+
    -+<h3 id="edit">Mengedit dokumen</h3>
    -+
    -+<p>Anda bisa menggunakan SAF untuk mengedit dokumen teks langsung di tempatnya.
    -+Cuplikan ini memicu
    -+intent {@link android.content.Intent#ACTION_OPEN_DOCUMENT} dan menggunakan
    -+kategori {@link android.content.Intent#CATEGORY_OPENABLE} untuk menampilkan
    -+dokumen yang bisa dibuka saja. Ini akan menyaring lebih jauh untuk menampilkan file teks saja:</p>
    -+
    -+<pre>
    -+private static final int EDIT_REQUEST_CODE = 44;
    -+/**
    -+ * Open a file for writing and append some text to it.
    -+ */
    -+ private void editDocument() {
    -+    // ACTION_OPEN_DOCUMENT is the intent to choose a file via the system's
    -+    // file browser.
    -+    Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT);
    -+
    -+    // Filter to only show results that can be &quot;opened&quot;, such as a
    -+    // file (as opposed to a list of contacts or timezones).
    -+    intent.addCategory(Intent.CATEGORY_OPENABLE);
    -+
    -+    // Filter to show only text files.
    -+    intent.setType(&quot;text/plain&quot;);
    -+
    -+    startActivityForResult(intent, EDIT_REQUEST_CODE);
    -+}
    -+</pre>
    -+
    -+<p>Berikutnya, dari {@link android.app.Activity#onActivityResult onActivityResult()}
    -+(lihat <a href="#results">Memproses hasil</a>) Anda bisa memanggil kode untuk mengedit.
    -+Cuplikan berikut mendapatkan {@link java.io.FileOutputStream}
    -+dari {@link android.content.ContentResolver}. Secara default, snipet menggunakan mode “tulis”.
    -+Inilah praktik terbaik untuk meminta jumlah akses minimum yang Anda perlukan, jadi jangan meminta
    -+baca/tulis jika yang Anda perlukan hanyalah tulis:</p>
    -+
    -+<pre>private void alterDocument(Uri uri) {
    -+    try {
    -+        ParcelFileDescriptor pfd = getActivity().getContentResolver().
    -+                openFileDescriptor(uri, "w");
    -+        FileOutputStream fileOutputStream =
    -+                new FileOutputStream(pfd.getFileDescriptor());
    -+        fileOutputStream.write(("Overwritten by MyCloud at " +
    -+                System.currentTimeMillis() + "\n").getBytes());
    -+        // Let the document provider know you're done by closing the stream.
    -+        fileOutputStream.close();
    -+        pfd.close();
    -+    } catch (FileNotFoundException e) {
    -+        e.printStackTrace();
    -+    } catch (IOException e) {
    -+        e.printStackTrace();
    -+    }
    -+}</pre>
    -+
    -+<h3 id="permissions">Mempertahankan izin</h3>
    -+
    -+<p>Bila aplikasi Anda membuka file untuk membaca atau menulis, sistem akan memberi
    -+aplikasi Anda izin URI untuk file itu. Pemberian ini berlaku hingga perangkat pengguna di-restart.
    -+Namun anggaplah aplikasi Anda adalah aplikasi pengeditan gambar, dan Anda ingin pengguna bisa
    -+mengakses 5 gambar terakhir yang dieditnya, langsung dari aplikasi Anda. Jika perangkat pengguna telah
    -+di-restart, maka Anda harus mengirim pengguna kembali ke picker sistem untuk menemukan
    -+file, hal ini jelas tidak ideal.</p>
    -+
    -+<p>Untuk mencegah terjadinya hal ini, Anda bisa mempertahankan izin yang diberikan
    -+sistem ke aplikasi Anda. Secara efektif, aplikasi Anda akan "mengambil" pemberian izin URI yang bisa dipertahankan
    -+yang ditawarkan oleh sistem. Hal ini memberi pengguna akses kontinu ke file
    -+melalui aplikasi Anda, sekalipun perangkat telah di-restart:</p>
    -+
    -+
    -+<pre>final int takeFlags = intent.getFlags()
    -+            &amp; (Intent.FLAG_GRANT_READ_URI_PERMISSION
    -+            | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
    -+// Check for the freshest data.
    -+getContentResolver().takePersistableUriPermission(uri, takeFlags);</pre>
    -+
    -+<p>Ada satu langkah akhir. Anda mungkin telah menyimpan
    -+URI terbaru yang diakses aplikasi, namun URI itu mungkin tidak lagi valid,&mdash;aplikasi lain
    -+mungkin telah menghapus atau memodifikasi dokumen. Karena itu, Anda harus selalu memanggil
    -+{@code getContentResolver().takePersistableUriPermission()} untuk memeriksa
    -+data terbaru.</p>
    -+
    -+<h2 id="custom">Menulis Penyedia Dokumen Custom</h2>
    -+
    -+<p>
    -+Jika Anda sedang mengembangkan aplikasi yang menyediakan layanan penyimpanan untuk file (misalnya
    -+layanan penyimpanan cloud), Anda bisa menyediakan file melalui
    -+SAF dengan menulis penyedia dokumen custom.  Bagian ini menjelaskan
    -+caranya.</p>
    -+
    -+
    -+<h3 id="manifest">Manifes</h3>
    -+
    -+<p>Untuk mengimplementasikan penyedia dokumen custom, tambahkan yang berikut ini ke manifes aplikasi
    -+Anda:</p>
    -+<ul>
    -+
    -+<li>Target berupa API level 19 atau yang lebih tinggi.</li>
    -+
    -+<li>Elemen <code>&lt;provider&gt;</code> yang mendeklarasikan penyedia penyimpanan custom
    -+Anda. </li>
    -+
    -+<li>Nama penyedia Anda, yaitu nama kelasnya, termasuk nama paket.
    -+Misalnya: <code>com.example.android.storageprovider.MyCloudProvider</code>.</li>
    -+
    -+<li>Nama otoritas Anda, yaitu nama paket Anda (dalam contoh ini,
    -+<code>com.example.android.storageprovider</code>) plus tipe penyedia konten
    -+(<code>documents</code>). Misalnya, {@code com.example.android.storageprovider.documents}.</li>
    -+
    -+<li>Atribut <code>android:exported</code> yang diatur ke <code>&quot;true&quot;</code>.
    -+Anda harus mengekspor penyedia sehingga aplikasi lain bisa membacanya.</li>
    -+
    -+<li>Atribut <code>android:grantUriPermissions</code> yang diatur ke
    -+<code>&quot;true&quot;</code>. Pengaturan ini memungkinkan sistem memberi aplikasi lain akses
    -+ke konten dalam penyedia Anda. Untuk pembahasan cara mempertahankan pemberian bagi
    -+dokumen tertentu, lihat <a href="#permissions">Mempertahankan izin</a>.</li>
    -+
    -+<li>Izin {@code MANAGE_DOCUMENTS}. Secara default, penyedia tersedia
    -+bagi siapa saja. Menambahkan izin ini akan membatasi penyedia Anda pada sistem.
    -+Pembatasan ini penting untuk keamanan.</li>
    -+
    -+<li>Atribut {@code android:enabled} yang diatur ke nilai boolean didefinisikan dalam file
    -+sumber daya. Tujuan atribut ini adalah menonaktifkan penyedia pada perangkat yang menjalankan Android 4.3 atau yang lebih rendah.
    -+Misalnya, {@code android:enabled="@bool/atLeastKitKat"}. Selain
    -+memasukkan atribut ini dalam manifes, Anda perlu melakukan hal-hal berikut:
    -+<ul>
    -+<li>Dalam file sumber daya {@code bool.xml} Anda di bawah {@code res/values/}, tambahkan
    -+baris ini: <pre>&lt;bool name=&quot;atLeastKitKat&quot;&gt;false&lt;/bool&gt;</pre></li>
    -+
    -+<li>Dalam file sumber daya {@code bool.xml} Anda di bawah {@code res/values-v19/}, tambahkan
    -+baris ini: <pre>&lt;bool name=&quot;atLeastKitKat&quot;&gt;true&lt;/bool&gt;</pre></li>
    -+</ul></li>
    -+
    -+<li>Sebuah filter intent berisi tindakan
    -+{@code android.content.action.DOCUMENTS_PROVIDER}, agar penyedia Anda
    -+muncul dalam picker saat sistem mencari penyedia.</li>
    -+
    -+</ul>
    -+<p>Berikut ini adalah kutipan contoh manifes berisi penyedia yang:</p>
    -+
    -+<pre>&lt;manifest... &gt;
    -+    ...
    -+    &lt;uses-sdk
    -+        android:minSdkVersion=&quot;19&quot;
    -+        android:targetSdkVersion=&quot;19&quot; /&gt;
    -+        ....
    -+        &lt;provider
    -+            android:name=&quot;com.example.android.storageprovider.MyCloudProvider&quot;
    -+            android:authorities=&quot;com.example.android.storageprovider.documents&quot;
    -+            android:grantUriPermissions=&quot;true&quot;
    -+            android:exported=&quot;true&quot;
    -+            android:permission=&quot;android.permission.MANAGE_DOCUMENTS&quot;
    -+            android:enabled=&quot;&#64;bool/atLeastKitKat&quot;&gt;
    -+            &lt;intent-filter&gt;
    -+                &lt;action android:name=&quot;android.content.action.DOCUMENTS_PROVIDER&quot; /&gt;
    -+            &lt;/intent-filter&gt;
    -+        &lt;/provider&gt;
    -+    &lt;/application&gt;
    -+
    -+&lt;/manifest&gt;</pre>
    -+
    -+<h4 id="43">Mendukung perangkat yang menjalankan Android 4.3 dan yang lebih rendah</h4>
    -+
    -+<p>Intent
    -+{@link android.content.Intent#ACTION_OPEN_DOCUMENT} hanya tersedia
    -+pada perangkat yang menjalankan Android 4.4 dan yang lebih tinggi.
    -+Jika ingin aplikasi Anda mendukung {@link android.content.Intent#ACTION_GET_CONTENT}
    -+untuk mengakomodasi perangkat yang menjalankan Android 4.3 dan yang lebih rendah, Anda harus
    -+menonaktifkan filter inten {@link android.content.Intent#ACTION_GET_CONTENT} dalam
    -+manifes untuk perangkat yang menjalankan Android 4.4 atau yang lebih tinggi. Penyedia
    -+dokumen dan {@link android.content.Intent#ACTION_GET_CONTENT} harus dianggap
    -+saling eksklusif. Jika Anda mendukung keduanya sekaligus, aplikasi Anda akan
    -+muncul dua kali dalam UI picker sistem, yang menawarkan dua cara mengakses
    -+data tersimpan Anda. Hal ini akan membingungkan pengguna.</p>
    -+
    -+<p>Berikut ini adalah cara yang disarankan untuk menonaktifkan
    -+filter intent {@link android.content.Intent#ACTION_GET_CONTENT} untuk perangkat
    -+yang menjalankan Android versi 4.4 atau yang lebih tinggi:</p>
    -+
    -+<ol>
    -+<li>Dalam file sumber daya {@code bool.xml} Anda di bawah {@code res/values/}, tambahkan
    -+baris ini: <pre>&lt;bool name=&quot;atMostJellyBeanMR2&quot;&gt;true&lt;/bool&gt;</pre></li>
    -+
    -+<li>Dalam file sumber daya {@code bool.xml} Anda di bawah {@code res/values-v19/}, tambahkan
    -+baris ini: <pre>&lt;bool name=&quot;atMostJellyBeanMR2&quot;&gt;false&lt;/bool&gt;</pre></li>
    -+
    -+<li>Tambahkan
    -+<a href="{@docRoot}guide/topics/manifest/activity-alias-element.html">alias
    -+aktivitas</a> untuk menonaktifkan filter intent {@link android.content.Intent#ACTION_GET_CONTENT}
    -+bagi versi 4.4 (API level 19) dan yang lebih tinggi. Misalnya:
    -+
    -+<pre>
    -+&lt;!-- This activity alias is added so that GET_CONTENT intent-filter
    -+     can be disabled for builds on API level 19 and higher. --&gt;
    -+&lt;activity-alias android:name=&quot;com.android.example.app.MyPicker&quot;
    -+        android:targetActivity=&quot;com.android.example.app.MyActivity&quot;
    -+        ...
    -+        android:enabled=&quot;@bool/atMostJellyBeanMR2&quot;&gt;
    -+    &lt;intent-filter&gt;
    -+        &lt;action android:name=&quot;android.intent.action.GET_CONTENT&quot; /&gt;
    -+        &lt;category android:name=&quot;android.intent.category.OPENABLE&quot; /&gt;
    -+        &lt;category android:name=&quot;android.intent.category.DEFAULT&quot; /&gt;
    -+        &lt;data android:mimeType=&quot;image/*&quot; /&gt;
    -+        &lt;data android:mimeType=&quot;video/*&quot; /&gt;
    -+    &lt;/intent-filter&gt;
    -+&lt;/activity-alias&gt;
    -+</pre>
    -+</li>
    -+</ol>
    -+<h3 id="contract">Kontrak</h3>
    -+
    -+<p>Biasanya bila Anda menulis penyedia konten custom, salah satu tugas adalah
    -+mengimplementasikan kelas kontrak, seperti dijelaskan dalam panduan pengembang
    -+<a href="{@docRoot}guide/topics/providers/content-provider-creating.html#ContractClass">
    -+Penyedia Konten</a>. Kelas kontrak adalah kelas {@code public final}
    -+yang berisi definisi konstanta untuk URI, nama kolom, tipe MIME, dan
    -+metadata lain yang berkenaan dengan penyedia. SAF
    -+menyediakan kelas-kelas kontrak ini untuk Anda, jadi Anda tidak perlu menulisnya
    -+sendiri:</p>
    -+
    -+<ul>
    -+   <li>{@link android.provider.DocumentsContract.Document}</li>
    -+   <li>{@link android.provider.DocumentsContract.Root}</li>
    -+</ul>
    -+
    -+<p>Misalnya, berikut ini adalah kolom-kolom yang bisa Anda hasilkan di kursor bila
    -+penyedia dokumen Anda membuat query dokumen atau akar:</p>
    -+
    -+<pre>private static final String[] DEFAULT_ROOT_PROJECTION =
    -+        new String[]{Root.COLUMN_ROOT_ID, Root.COLUMN_MIME_TYPES,
    -+        Root.COLUMN_FLAGS, Root.COLUMN_ICON, Root.COLUMN_TITLE,
    -+        Root.COLUMN_SUMMARY, Root.COLUMN_DOCUMENT_ID,
    -+        Root.COLUMN_AVAILABLE_BYTES,};
    -+private static final String[] DEFAULT_DOCUMENT_PROJECTION = new
    -+        String[]{Document.COLUMN_DOCUMENT_ID, Document.COLUMN_MIME_TYPE,
    -+        Document.COLUMN_DISPLAY_NAME, Document.COLUMN_LAST_MODIFIED,
    -+        Document.COLUMN_FLAGS, Document.COLUMN_SIZE,};
    -+</pre>
    -+
    -+<h3 id="subclass">Subkelas DocumentsProvider</h3>
    -+
    -+<p>Langkah berikutnya dalam menulis penyedia dokumen custom adalah menjadikan
    -+kelas abstrak sebagai subkelas {@link android.provider.DocumentsProvider}. Setidaknya, Anda perlu
    -+ mengimplementasikan metode berikut:</p>
    -+
    -+<ul>
    -+<li>{@link android.provider.DocumentsProvider#queryRoots queryRoots()}</li>
    -+
    -+<li>{@link android.provider.DocumentsProvider#queryChildDocuments queryChildDocuments()}</li>
    -+
    -+<li>{@link android.provider.DocumentsProvider#queryDocument queryDocument()}</li>
    -+
    -+<li>{@link android.provider.DocumentsProvider#openDocument openDocument()}</li>
    -+</ul>
    -+
    -+<p>Hanya inilah metode yang diwajibkan kepada Anda secara ketat untuk diimplementasikan, namun ada
    -+banyak lagi yang mungkin Anda inginkan. Lihat {@link android.provider.DocumentsProvider}
    -+untuk detailnya.</p>
    -+
    -+<h4 id="queryRoots">Mengimplementasikan queryRoots</h4>
    -+
    -+<p>Implementasi {@link android.provider.DocumentsProvider#queryRoots
    -+queryRoots()} oleh Anda harus menghasilkan {@link android.database.Cursor} yang menunjuk ke semua
    -+direktori akar penyedia dokumen, dengan menggunakan kolom-kolom yang didefinisikan dalam
    -+{@link android.provider.DocumentsContract.Root}.</p>
    -+
    -+<p>Dalam cuplikan berikut, parameter {@code projection} mewakili bidang-bidang
    -+tertentu yang ingin didapatkan kembali oleh pemanggil. Cuplikan ini membuat kursor baru
    -+dan menambahkan satu baris ke satu akar&mdash; kursor, satu direktori level atas, seperti
    -+Downloads atau Images.  Kebanyakan penyedia hanya mempunyai satu akar. Anda bisa mempunyai lebih dari satu,
    -+misalnya, jika ada banyak akun pengguna. Dalam hal itu, cukup tambahkan sebuah
    -+baris kedua ke kursor.</p>
    -+
    -+<pre>
    -+&#64;Override
    -+public Cursor queryRoots(String[] projection) throws FileNotFoundException {
    -+
    -+    // Create a cursor with either the requested fields, or the default
    -+    // projection if "projection" is null.
    -+    final MatrixCursor result =
    -+            new MatrixCursor(resolveRootProjection(projection));
    -+
    -+    // If user is not logged in, return an empty root cursor.  This removes our
    -+    // provider from the list entirely.
    -+    if (!isUserLoggedIn()) {
    -+        return result;
    -+    }
    -+
    -+    // It's possible to have multiple roots (e.g. for multiple accounts in the
    -+    // same app) -- just add multiple cursor rows.
    -+    // Construct one row for a root called &quot;MyCloud&quot;.
    -+    final MatrixCursor.RowBuilder row = result.newRow();
    -+    row.add(Root.COLUMN_ROOT_ID, ROOT);
    -+    row.add(Root.COLUMN_SUMMARY, getContext().getString(R.string.root_summary));
    -+
    -+    // FLAG_SUPPORTS_CREATE means at least one directory under the root supports
    -+    // creating documents. FLAG_SUPPORTS_RECENTS means your application's most
    -+    // recently used documents will show up in the &quot;Recents&quot; category.
    -+    // FLAG_SUPPORTS_SEARCH allows users to search all documents the application
    -+    // shares.
    -+    row.add(Root.COLUMN_FLAGS, Root.FLAG_SUPPORTS_CREATE |
    -+            Root.FLAG_SUPPORTS_RECENTS |
    -+            Root.FLAG_SUPPORTS_SEARCH);
    -+
    -+    // COLUMN_TITLE is the root title (e.g. Gallery, Drive).
    -+    row.add(Root.COLUMN_TITLE, getContext().getString(R.string.title));
    -+
    -+    // This document id cannot change once it's shared.
    -+    row.add(Root.COLUMN_DOCUMENT_ID, getDocIdForFile(mBaseDir));
    -+
    -+    // The child MIME types are used to filter the roots and only present to the
    -+    //  user roots that contain the desired type somewhere in their file hierarchy.
    -+    row.add(Root.COLUMN_MIME_TYPES, getChildMimeTypes(mBaseDir));
    -+    row.add(Root.COLUMN_AVAILABLE_BYTES, mBaseDir.getFreeSpace());
    -+    row.add(Root.COLUMN_ICON, R.drawable.ic_launcher);
    -+
    -+    return result;
    -+}</pre>
    -+
    -+<h4 id="queryChildDocuments">Mengimplementasikan queryChildDocuments</h4>
    -+
    -+<p>Implementasi
    -+{@link android.provider.DocumentsProvider#queryChildDocuments queryChildDocuments()}
    -+oleh Anda harus menghasilkan {@link android.database.Cursor} yang menunjuk ke semua file dalam
    -+direktori yang ditentukan, dengan menggunakan kolom-kolom yang didefinisikan dalam
    -+{@link android.provider.DocumentsContract.Document}.</p>
    -+
    -+<p>Metode ini akan dipanggil bila Anda memilih akar aplikasi dalam picker UI.
    -+Metode mengambil dokumen anak dari direktori di bawah akar.  Metode ini bisa dipanggil pada level apa saja dalam
    -+hierarki file, bukan hanya akar. Cuplikan ini
    -+membuat kursor baru dengan kolom-kolom yang diminta, lalu menambahkan informasi tentang
    -+setiap anak langsung dalam direktori induk ke kursor.
    -+Satu anak bisa berupa gambar, direktori lain&mdash;file apa saja:</p>
    -+
    -+<pre>&#64;Override
    -+public Cursor queryChildDocuments(String parentDocumentId, String[] projection,
    -+                              String sortOrder) throws FileNotFoundException {
    -+
    -+    final MatrixCursor result = new
    -+            MatrixCursor(resolveDocumentProjection(projection));
    -+    final File parent = getFileForDocId(parentDocumentId);
    -+    for (File file : parent.listFiles()) {
    -+        // Adds the file's display name, MIME type, size, and so on.
    -+        includeFile(result, null, file);
    -+    }
    -+    return result;
    -+}
    -+</pre>
    -+
    -+<h4 id="queryDocument">Mengimplementasikan queryDocument</h4>
    -+
    -+<p>Implementasi
    -+{@link android.provider.DocumentsProvider#queryDocument queryDocument()}
    -+oleh Anda harus menghasilkan {@link android.database.Cursor} yang menunjuk ke file yang disebutkan,
    -+dengan menggunakan kolom-kolom yang didefinisikan dalam {@link android.provider.DocumentsContract.Document}.
    -+</p>
    -+
    -+<p>Metode {@link android.provider.DocumentsProvider#queryDocument queryDocument()}
    -+menghasilkan informasi yang sama yang diteruskan dalam
    -+{@link android.provider.DocumentsProvider#queryChildDocuments queryChildDocuments()},
    -+namun untuk file tertentu:</p>
    -+
    -+
    -+<pre>&#64;Override
    -+public Cursor queryDocument(String documentId, String[] projection) throws
    -+        FileNotFoundException {
    -+
    -+    // Create a cursor with the requested projection, or the default projection.
    -+    final MatrixCursor result = new
    -+            MatrixCursor(resolveDocumentProjection(projection));
    -+    includeFile(result, documentId, null);
    -+    return result;
    -+}
    -+</pre>
    -+
    -+<h4 id="openDocument">Mengimplementasikan openDocument</h4>
    -+
    -+<p>Anda harus mengimplementasikan {@link android.provider.DocumentsProvider#openDocument
    -+openDocument()} untuk menghasilkan {@link android.os.ParcelFileDescriptor} yang mewakili
    -+file yang disebutkan. Aplikasi lain bisa menggunakan {@link android.os.ParcelFileDescriptor}
    -+yang dihasilkan untuk mengalirkan data. Sistem memanggil metode ini setelah pengguna memilih file
    -+dan aplikasi klien meminta akses ke file itu dengan memanggil
    -+{@link android.content.ContentResolver#openFileDescriptor openFileDescriptor()}.
    -+Misalnya:</p>
    -+
    -+<pre>&#64;Override
    -+public ParcelFileDescriptor openDocument(final String documentId,
    -+                                         final String mode,
    -+                                         CancellationSignal signal) throws
    -+        FileNotFoundException {
    -+    Log.v(TAG, &quot;openDocument, mode: &quot; + mode);
    -+    // It's OK to do network operations in this method to download the document,
    -+    // as long as you periodically check the CancellationSignal. If you have an
    -+    // extremely large file to transfer from the network, a better solution may
    -+    // be pipes or sockets (see ParcelFileDescriptor for helper methods).
    -+
    -+    final File file = getFileForDocId(documentId);
    -+
    -+    final boolean isWrite = (mode.indexOf('w') != -1);
    -+    if(isWrite) {
    -+        // Attach a close listener if the document is opened in write mode.
    -+        try {
    -+            Handler handler = new Handler(getContext().getMainLooper());
    -+            return ParcelFileDescriptor.open(file, accessMode, handler,
    -+                        new ParcelFileDescriptor.OnCloseListener() {
    -+                &#64;Override
    -+                public void onClose(IOException e) {
    -+
    -+                    // Update the file with the cloud server. The client is done
    -+                    // writing.
    -+                    Log.i(TAG, &quot;A file with id &quot; +
    -+                    documentId + &quot; has been closed!
    -+                    Time to &quot; +
    -+                    &quot;update the server.&quot;);
    -+                }
    -+
    -+            });
    -+        } catch (IOException e) {
    -+            throw new FileNotFoundException(&quot;Failed to open document with id &quot;
    -+            + documentId + &quot; and mode &quot; + mode);
    -+        }
    -+    } else {
    -+        return ParcelFileDescriptor.open(file, accessMode);
    -+    }
    -+}
    -+</pre>
    -+
    -+<h3 id="security">Keamanan</h3>
    -+
    -+<p>Anggaplah penyedia dokumen Anda sebuah layanan penyimpanan cloud yang dilindungi kata sandi
    -+dan Anda ingin memastikan bahwa pengguna sudah login sebelum Anda mulai berbagi file mereka.
    -+Apakah yang harus dilakukan aplikasi Anda jika pengguna tidak login?  Solusinya adalah menghasilkan
    -+akar nol dalam implementasi {@link android.provider.DocumentsProvider#queryRoots
    -+queryRoots()} Anda. Yakni, sebuah kursor akar kosong:</p>
    -+
    -+<pre>
    -+public Cursor queryRoots(String[] projection) throws FileNotFoundException {
    -+...
    -+    // If user is not logged in, return an empty root cursor.  This removes our
    -+    // provider from the list entirely.
    -+    if (!isUserLoggedIn()) {
    -+        return result;
    -+}
    -+</pre>
    -+
    -+<p>Langkah lainnya adalah memanggil {@code getContentResolver().notifyChange()}.
    -+Ingat {@link android.provider.DocumentsContract}?  Kita menggunakannya untuk membuat
    -+URI ini. Cuplikan berikut memberi tahu sistem untuk membuat query akar penyedia dokumen Anda
    -+kapan saja status login pengguna berubah. Jika pengguna tidak
    -+login, panggilan ke {@link android.provider.DocumentsProvider#queryRoots queryRoots()} akan menghasilkan
    -+kursor kosong, seperti yang ditampilkan di atas. Cara ini akan memastikan bahwa dokumen penyedia hanya
    -+tersedia jika pengguna login ke penyedia itu.</p>
    -+
    -+<pre>private void onLoginButtonClick() {
    -+    loginOrLogout();
    -+    getContentResolver().notifyChange(DocumentsContract
    -+            .buildRootsUri(AUTHORITY), null);
    -+}
    -+</pre>
    -\ No newline at end of file
    -diff --git a/docs/html-intl/intl/id/guide/topics/resources/accessing-resources.jd b/docs/html-intl/intl/id/guide/topics/resources/accessing-resources.jd
    -new file mode 100644
    -index 0000000..6774557
    ---- /dev/null
    -+++ b/docs/html-intl/intl/id/guide/topics/resources/accessing-resources.jd
    -@@ -0,0 +1,337 @@
    -+page.title=Mengakses Sumber Daya
    -+parent.title=Sumber Daya Aplikasi
    -+parent.link=index.html
    -+@jd:body
    -+
    -+<div id="qv-wrapper">
    -+<div id="qv">
    -+  <h2>Tampilan Cepat</h2>
    -+  <ul>
    -+    <li>Sumber daya bisa diacu dari kode dengan menggunakan integer dari {@code R.java}, seperti
    -+{@code R.drawable.myimage}</li>
    -+    <li>Sumber daya bisa diacu dari sumber daya dengan menggunakan sintaks XML khusus, seperti {@code
    -+&#64;drawable/myimage}</li>
    -+    <li>Anda juga bisa mengakses sumber daya aplikasi Anda dengan berbagai metode di
    -+{@link android.content.res.Resources}</li>
    -+  </ul>
    -+
    -+  <h2>Kelas-Kelas Utama</h2>
    -+  <ol>
    -+    <li>{@link android.content.res.Resources}</li>
    -+  </ol>
    -+
    -+  <h2>Dalam dokumen ini</h2>
    -+  <ol>
    -+    <li><a href="#ResourcesFromCode">Mengakses Sumber Daya dari Kode</a></li>
    -+    <li><a href="#ResourcesFromXml">Mengakses Sumber Daya dari XML</a>
    -+      <ol>
    -+        <li><a href="#ReferencesToThemeAttributes">Mengacu atribut gaya</a></li>
    -+      </ol>
    -+    </li>
    -+    <li><a href="#PlatformResources">Mengakses Sumber Daya Platform</a></li>
    -+  </ol>
    -+
    -+  <h2>Lihat juga</h2>
    -+  <ol>
    -+    <li><a href="providing-resources.html">Menyediakan Sumber Daya</a></li>
    -+    <li><a href="available-resources.html">Tipe Sumber Daya</a></li>
    -+  </ol>
    -+</div>
    -+</div>
    -+
    -+
    -+
    -+
    -+<p>Setelah Anda menyediakan sumber daya dalam aplikasi Anda (yang dibicarakan di <a href="providing-resources.html">Menyediakan Sumber Daya</a>), Anda bisa menerapkannya dengan
    -+mengacu ID sumber dayanya. Semua ID sumber daya didefinisikan di kelas {@code R} proyek Anda, yang
    -+dihasilkan oleh alat {@code aapt} secara otomatis.</p>
    -+
    -+<p>Bila aplikasi Anda dikompilasi, {@code aapt} akan membuat kelas {@code R}, yang berisi
    -+ID sumber daya untuk semua sumber daya dalam direktori {@code
    -+res/} Anda. Untuk masing-masing tipe sumber daya, ada subkelas {@code R} (misalnya,
    -+{@code R.drawable} untuk semua sumber daya yang bisa ditarik), dan untuk masing-masing sumber daya dari tipe itu, ada satu integer statis
    -+ (misalnya, {@code R.drawable.icon}). Integer ini adalah ID sumber daya yang bisa Anda gunakan
    -+untuk mengambil sumber daya Anda.</p>
    -+
    -+<p>Walaupun kelas {@code R} adalah tempat menyebutkan ID sumber daya, Anda tidak perlu
    -+melihat ke sana untuk menemukan ID sumber daya. ID sumber daya selalu terdiri dari:</p>
    -+<ul>
    -+  <li><em>Tipe sumber daya</em>: Masing-masing sumber daya dikelompokkan menjadi "tipe", misalnya {@code
    -+string}, {@code drawable}, dan {@code layout}. Untuk mengetahui selengkapnya tentang berbagai tipe, lihat <a href="available-resources.html">Tipe Sumber Daya</a>.
    -+  </li>
    -+  <li><em>Nama sumber daya</em>, bisa berupa: nama file,
    -+tidak termasuk ekstensi; atau nilai dalam atribut {@code android:name} XML, jika
    -+sumber daya itu sebuah nilai sederhana (misalnya sebuah string).</li>
    -+</ul>
    -+
    -+<p>Ada dua cara untuk mengakses sumber daya:</p>
    -+<ul>
    -+  <li><strong>Dalam kode:</strong> Menggunakan integer statis dari subkelas dari kelas {@code R}
    -+, misalnya:
    -+    <pre class="classic no-pretty-print">R.string.hello</pre>
    -+    <p>{@code string} adalah tipe sumber daya dan {@code hello} adalah nama sumber daya. Ada banyak
    -+API Android yang bisa mengakses sumber daya Anda bila Anda menyediakan ID sumber daya dengan format ini. Lihat
    -+<a href="#ResourcesFromCode">Mengakses Sumber Daya dalam Kode</a>.</p>
    -+  </li>
    -+  <li><strong>Dalam XML:</strong> Menggunakan sebuah sintaks XML khusus yang juga berkaitan dengan
    -+ID sumber daya yang didefinisikan dalam kelas {@code R}, misalnya:
    -+    <pre class="classic no-pretty-print">&#64;string/hello</pre>
    -+    <p>{@code string} adalah tipe sumber daya dan {@code hello} adalah nama sumber daya. Anda bisa menggunakan
    -+sintaks ini dalam sumber daya XML di mana saja Anda ingin menyediakan sebuah nilai dalam sebuah sumber daya. Lihat <a href="#ResourcesFromXml">Mengakses Sumber Daya dari XML</a>.</p>
    -+  </li>
    -+</ul>
    -+
    -+
    -+
    -+<h2 id="ResourcesFromCode">Mengakses Sumber Daya dalam Kode </h2>
    -+
    -+<p>Anda bisa menggunakan sumber daya dalam kode dengan menyalurkan ID sumber daya sebagai sebuah parameter metode. Misalnya,
    -+ Anda bisa mengatur sebuah {@link android.widget.ImageView} agar menggunakan sumber daya{@code res/drawable/myimage.png}
    -+dengan menggunakan {@link android.widget.ImageView#setImageResource(int) setImageResource()}:</p>
    -+<pre>
    -+ImageView imageView = (ImageView) findViewById(R.id.myimageview);
    -+imageView.setImageResource(<strong>R.drawable.myimage</strong>);
    -+</pre>
    -+
    -+<p>Anda juga bisa mengambil tiap sumber daya dengan menggunakan berbagai metode di {@link
    -+android.content.res.Resources}, di mana Anda bisa mendapatkan instance
    -+ {@link android.content.Context#getResources()}.</p>
    -+
    -+<div class="sidebox-wrapper">
    -+<div class="sidebox">
    -+<h2>Akses ke File Asli</h2>
    -+
    -+<p>Walaupun tidak lazim, Anda mungkin perlu mengakses file dan direktori asli Anda. Jika demikian, maka
    -+menyimpan file Anda di {@code res/} tidak akan berhasil, karena satu-satunya cara untuk membaca sebuah sumber daya dari
    -+{@code res/} adalah dengan ID sumber daya. Sebagai gantinya, Anda bisa menyimpan sumber daya dalam direktori
    -+{@code assets/}.</p>
    -+<p>File yang tersimpan di direktori {@code assets/} <em>tidak</em> diberi ID
    -+sumber daya, sehingga Anda tidak bisa mengacunya melalui kelas {@code R} atau dari sumber daya XML. Sebagai gantinya, Anda bisa melakukan
    -+query file di direktori {@code assets/} seperti sebuah sistem file biasa dan membaca data mentah dengan menggunakan
    -+{@link android.content.res.AssetManager}.</p>
    -+<p>Akan tetapi, jika yang Anda butuhkan hanya kemampuan membaca data mentah (misalnya sebuah file video atau audio),
    -+maka simpanlah file itu di direktori {@code res/raw/} dan baca aliran byte dengan menggunakan {@link
    -+android.content.res.Resources#openRawResource(int) openRawResource()}.</p>
    -+
    -+</div>
    -+</div>
    -+
    -+
    -+<h3>Sintaks</h3>
    -+
    -+<p>Inilah sintaks untuk mengacu sumber daya dalam kode:</p>
    -+
    -+<pre class="classic no-pretty-print">
    -+[<em>&lt;package_name&gt;</em>.]R.<em>&lt;resource_type&gt;</em>.<em>&lt;resource_name&gt;</em>
    -+</pre>
    -+
    -+<ul>
    -+  <li><em> {@code &lt;package_name&gt;}</em>adalah nama paket yang di dalamnya terdapat sumber daya (tidak
    -+dibutuhkan bila mengacu sumber daya dari paket Anda sendiri).</li>
    -+  <li><em>{@code &lt;resource_type&gt;}</em> adalah subkelas {@code R} untuk tipe sumber daya.</li>
    -+  <li><em>{@code &lt;resource_name&gt;}</em> bisa berupa nama file sumber daya
    -+tanpa ekstensi atau nilai atribut {@code android:name} dalam elemen XML (untuk nilai
    -+sederhana).</li>
    -+</ul>
    -+<p>Lihat <a href="available-resources.html">Tipe Sumber Daya</a> untuk
    -+informasi selengkapnya tentang masing-masing tipe sumber daya dan cara mengacunya.</p>
    -+
    -+
    -+<h3>Kasus penggunaan</h3>
    -+
    -+<p>Ada banyak metode yang menerima parameter ID sumber daya dan Anda bisa mengambil sumber daya dengan menggunakan
    -+metode di {@link android.content.res.Resources}. Anda bisa mengambil instance {@link
    -+android.content.res.Resources} dengan {@link android.content.Context#getResources
    -+Context.getResources()}.</p>
    -+
    -+
    -+<p>Berikut adalah beberapa contoh cara mengakses sumber daya dalam kode:</p>
    -+
    -+<pre>
    -+// Load a background for the current screen from a drawable resource
    -+{@link android.app.Activity#getWindow()}.{@link
    -+android.view.Window#setBackgroundDrawableResource(int)
    -+setBackgroundDrawableResource}(<strong>R.drawable.my_background_image</strong>) ;
    -+
    -+// Set the Activity title by getting a string from the Resources object, because
    -+//  this method requires a CharSequence rather than a resource ID
    -+{@link android.app.Activity#getWindow()}.{@link android.view.Window#setTitle(CharSequence)
    -+setTitle}(getResources().{@link android.content.res.Resources#getText(int)
    -+getText}(<strong>R.string.main_title</strong>));
    -+
    -+// Load a custom layout for the current screen
    -+{@link android.app.Activity#setContentView(int)
    -+setContentView}(<strong>R.layout.main_screen</strong>);
    -+
    -+// Set a slide in animation by getting an Animation from the Resources object
    -+mFlipper.{@link android.widget.ViewAnimator#setInAnimation(Animation)
    -+setInAnimation}(AnimationUtils.loadAnimation(this,
    -+        <strong>R.anim.hyperspace_in</strong>));
    -+
    -+// Set the text on a TextView object using a resource ID
    -+TextView msgTextView = (TextView) findViewById(<strong>R.id.msg</strong>);
    -+msgTextView.{@link android.widget.TextView#setText(int)
    -+setText}(<strong>R.string.hello_message</strong>);
    -+</pre>
    -+
    -+
    -+<p class="caution"><strong>Perhatian:</strong> Anda tidak boleh memodifikasi file {@code
    -+R.java} secara manual&mdash;, ini dihasilkan oleh alat {@code aapt} bila proyek Anda telah
    -+dikompilasi. Perubahan apa pun akan ditimpa bila nanti Anda mengompilasi.</p>
    -+
    -+
    -+
    -+<h2 id="ResourcesFromXml">Mengakses Sumber Daya dari XML</h2>
    -+
    -+<p>Anda bisa mendefinisikan nilai untuk beberapa atribut dan elemen XML dengan menggunakan
    -+acuan ke sumber daya yang ada. Anda akan sering melakukannya saat membuat file layout, untuk
    -+memasok string dan gambar bagi widget Anda.</p>
    -+
    -+<p>Misalnya, jika Anda menambahkan sebuah {@link android.widget.Button} ke layout, Anda harus menggunakan
    -+sebuah <a href="string-resource.html">sumber daya string</a> bagi teks tombolnya:</p>
    -+
    -+<pre>
    -+&lt;Button
    -+    android:layout_width="fill_parent"
    -+    android:layout_height="wrap_content"
    -+    android:text="<strong>@string/submit</strong>" /&gt;
    -+</pre>
    -+
    -+
    -+<h3>Sintaks</h3>
    -+
    -+<p>Berikut adalah sintaks untuk mengacu sumber daya di sumber daya XML:</p>
    -+
    -+<pre class="classic no-pretty-print">
    -+&#64;[<em>&lt;package_name&gt;</em>:]<em>&lt;resource_type&gt;</em>/<em>&lt;resource_name&gt;</em>
    -+</pre>
    -+
    -+<ul>
    -+  <li>{@code &lt;package_name&gt;} adalah nama paket yang di dalamnya terdapat sumber daya (tidak
    -+dibutuhkan bila mengacu sumber daya dari paket yang sama)</li>
    -+  <li>{@code &lt;resource_type&gt;} adalah subkelas
    -+{@code R} untuk tipe sumber daya</li>
    -+  <li>{@code &lt;resource_name&gt;} bisa berupa nama file sumber daya
    -+tanpa ekstensi atau nilai atribut {@code android:name} dalam elemen XML (untuk nilai
    -+sederhana).</li>
    -+</ul>
    -+
    -+<p>Lihat <a href="available-resources.html">Tipe Sumber Daya</a> untuk
    -+informasi selengkapnya tentang masing-masing tipe sumber daya dan cara mengacunya.</p>
    -+
    -+
    -+<h3>Kasus penggunaan</h3>
    -+
    -+<p>Dalam beberapa kasus, Anda harus menggunakan sumber daya untuk suatu nilai dalam XML (misalnya, untuk menerapkan gambar yang bisa ditarik
    -+pada widget), namun Anda juga bisa menggunakan sumber daya di XML mana saja yang menerima nilai sederhana. Misalnya, jika
    -+Anda mempunyai file sumber daya berikut yang berisi <a href="more-resources.html#Color">sumber daya warna</a> dan <a href="string-resource.html">sumber daya string</a>:</p>
    -+
    -+<pre>
    -+&lt;?xml version="1.0" encoding="utf-8"?>
    -+&lt;resources>
    -+   &lt;color name="opaque_red">#f00&lt;/color>
    -+   &lt;string name="hello">Hello!&lt;/string>
    -+&lt;/resources>
    -+</pre>
    -+
    -+<p>Anda bisa menggunakan sumber daya ini dalam file layout berikut untuk mengatur warna teks dan
    -+string teks:</p>
    -+
    -+<pre>
    -+&lt;?xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot;?&gt;
    -+&lt;EditText xmlns:android=&quot;http://schemas.android.com/apk/res/android&quot;
    -+    android:layout_width=&quot;fill_parent&quot;
    -+    android:layout_height=&quot;fill_parent&quot;
    -+    android:textColor=&quot;<strong>&#64;color/opaque_red</strong>&quot;
    -+    android:text=&quot;<strong>&#64;string/hello</strong>&quot; /&gt;
    -+</pre>
    -+
    -+<p>Dalam hal ini, Anda tidak perlu menyebutkan nama paket dalam sumber daya acuan karena
    -+sumber daya berasal dari paket Anda sendiri. Untuk
    -+mengacu sumber daya sistem, Anda perlu memasukkan nama paketnya. Misalnya:</p>
    -+
    -+<pre>
    -+&lt;?xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot;?&gt;
    -+&lt;EditText xmlns:android=&quot;http://schemas.android.com/apk/res/android&quot;
    -+    android:layout_width=&quot;fill_parent&quot;
    -+    android:layout_height=&quot;fill_parent&quot;
    -+    android:textColor=&quot;<strong>&#64;android:color/secondary_text_dark</strong>&quot;
    -+    android:text=&quot;&#64;string/hello&quot; /&gt;
    -+</pre>
    -+
    -+<p class="note"><strong>Catatan:</strong> Anda harus menggunakan sumber daya string sepanjang
    -+waktu, sehingga aplikasi Anda bisa dilokalkan untuk bahasa lain.
    -+Untuk informasi tentang cara menciptakan
    -+sumber daya alternatif (seperti string lokal), lihat <a href="providing-resources.html#AlternativeResources">Menyediakan Sumber Daya Alternatif
    -+</a>. Untuk panduan lengkap melokalkan aplikasi Anda ke bahasa lain,
    -+lihat <a href="localization.html">Pelokalan</a>.</p>
    -+
    -+<p>Anda bahkan bisa menggunakan sumber daya dalam XML untuk membuat alias. Misalnya, Anda bisa membuat
    -+sumber daya yang bisa ditarik yang merupakan alias bagi sumber daya yang bisa ditarik lainnya:</p>
    -+
    -+<pre>
    -+&lt;?xml version="1.0" encoding="utf-8"?>
    -+&lt;bitmap xmlns:android="http://schemas.android.com/apk/res/android"
    -+    android:src="@drawable/other_drawable" />
    -+</pre>
    -+
    -+<p>Hal ini terdengar berlebihan, namun bisa sangat berguna saat menggunakan sumber daya alternatif. Baca selengkapnya tentang
    -+<a href="providing-resources.html#AliasResources">Membuat sumber daya alias</a>.</p>
    -+
    -+
    -+
    -+<h3 id="ReferencesToThemeAttributes">Mengacu atribut gaya</h3>
    -+
    -+<p>Sumber daya atribut gaya memungkinkan Anda mengacu nilai
    -+suatu atribut dalam tema yang diterapkan saat ini. Dengan mengacu sebuah atribut gaya memungkinkan Anda
    -+menyesuaikan tampilan elemen UI dengan mengatur gayanya agar cocok dengan beragam variasi standar yang dipasok oleh
    -+tema saat ini, sebagai ganti memasok nilai yang ditanamkan (hard-coded). Mengacu sebuah atribut gaya
    -+pada dasarnya adalah "gunakan gaya yang didefinisikan oleh atribut ini, dalam tema saat ini".</p>
    -+
    -+<p>Untuk mengacu sebuah atribut gaya, sintaks namanya hampir sama dengan format sumber daya normal
    -+, namun sebagai ganti simbol @ ({@code @}), gunakan sebuah tanda tanya ({@code ?}), dan
    -+porsi tipe sumber daya bersifat opsional. Sebagai contoh:</p>
    -+
    -+<pre class="classic">
    -+?[<em>&lt;package_name&gt;</em>:][<em>&lt;resource_type&gt;</em>/]<em>&lt;resource_name&gt;</em>
    -+</pre>
    -+
    -+<p>Misalnya, begini cara Anda mengacu suatu atribut untuk mengatur warna teks agar cocok dengan
    -+warna teks "utama" tema sistem:</p>
    -+
    -+<pre>
    -+&lt;EditText id=&quot;text&quot;
    -+    android:layout_width=&quot;fill_parent&quot;
    -+    android:layout_height=&quot;wrap_content&quot;
    -+    android:textColor=&quot;<strong>?android:textColorSecondary</strong>&quot;
    -+    android:text=&quot;&#64;string/hello_world&quot; /&gt;
    -+</pre>
    -+
    -+<p>Di sini, atribut {@code android:textColor} menyebutkan nama atribut gaya
    -+dalam tema saat ini. Android kini menggunakan nilai yang diterapkan pada atribut gaya {@code android:textColorSecondary}
    -+sebagai nilai untuk {@code android:textColor} dalam widget ini. Karena alat sumber daya
    -+mengetahui bahwa atribut sumber daya diharapkan dalam konteks ini,
    -+maka Anda tidak perlu menyatakan tipenyanya secara eksplisit (yang akan berupa
    -+<code>?android:attr/textColorSecondary</code>)&mdash;Anda bisa mengecualikan tipe {@code attr}.</p>
    -+
    -+
    -+
    -+
    -+<h2 id="PlatformResources">Mengakses Sumber Daya Platform</h2>
    -+
    -+<p>Android berisi sejumlah sumber daya standar, seperti gaya, tema, dan layout. Untuk
    -+mengakses semua sumber daya ini, tetapkan acuan sumber daya Anda dengan nama paket
    -+<code>android</code>. Misalnya, Android menyediakan sumber daya layout yang bisa Anda gunakan untuk
    -+item daftar dalam{@link android.widget.ListAdapter}:</p>
    -+
    -+<pre>
    -+{@link android.app.ListActivity#setListAdapter(ListAdapter)
    -+setListAdapter}(new {@link
    -+android.widget.ArrayAdapter}&lt;String&gt;(this, <strong>android.R.layout.simple_list_item_1</strong>, myarray));
    -+</pre>
    -+
    -+<p>Dalam contoh ini, {@link android.R.layout#simple_list_item_1} adalah sumber daya layout yang didefinisikan oleh
    -+platform untuk item di {@link android.widget.ListView}. Anda bisa menggunakannya sebagai ganti menciptakan
    -+layout sendiri untuk item daftar. Untuk informasi selengkapnya, lihat panduan pengembang
    -+<a href="{@docRoot}guide/topics/ui/layout/listview.html">List View</a>.</p>
    -+
    -diff --git a/docs/html-intl/intl/id/guide/topics/resources/overview.jd b/docs/html-intl/intl/id/guide/topics/resources/overview.jd
    -new file mode 100644
    -index 0000000..def4932
    ---- /dev/null
    -+++ b/docs/html-intl/intl/id/guide/topics/resources/overview.jd
    -@@ -0,0 +1,103 @@
    -+page.title=Ikhtisar Sumber Daya
    -+@jd:body
    -+
    -+<div id="qv-wrapper">
    -+<div id="qv">
    -+  <h2>Topik</h2>
    -+  <ol>
    -+    <li><a href="providing-resources.html">Menyediakan Sumber Daya</a></li>
    -+    <li><a href="accessing-resources.html">Mengakses Sumber Daya</a></li>
    -+    <li><a href="runtime-changes.html">Menangani Perubahan Runtime</a></li>
    -+    <li><a href="localization.html">Pelokalan</a></li>
    -+  </ol>
    -+
    -+  <h2>Acuan</h2>
    -+  <ol>
    -+    <li><a href="available-resources.html">Tipe Sumber Daya</a></li>
    -+  </ol>
    -+</div>
    -+</div>
    -+
    -+
    -+<p>Anda harus selalu mengeksternalkan sumber daya seperti gambar dan string dari kode
    -+aplikasi, agar Anda bisa memeliharanya secara independen. Mengeksternalkan
    -+sumber daya juga membuat Anda dapat menyediakan sumber daya alternatif yang mendukung konfigurasi
    -+perangkat tertentu seperti bahasa atau ukuran layar yang berbeda, yang semakin penting
    -+seiring semakin banyak tersedianya perangkat berbasis Android dengan konfigurasi berbeda. Untuk
    -+memberikan kompatibilitas dengan konfigurasi berbeda, Anda harus menata sumber daya dalam
    -+direktori {@code res/} proyek Anda, menggunakan berbagai subdirektori yang mengelompokkan sumber daya menurut tipe
    -+dan konfigurasinya.</p>
    -+
    -+<div class="figure" style="width:429px">
    -+<img src="{@docRoot}images/resources/resource_devices_diagram1.png" height="167" alt="" />
    -+<p class="img-caption">
    -+<strong>Gambar 1.</strong> Dua perangkat berbeda, masing-masing menggunakan layout default
    -+(aplikasi tidak menyediakan layout alternatif).</p>
    -+</div>
    -+
    -+<div class="figure" style="width:429px">
    -+<img src="{@docRoot}images/resources/resource_devices_diagram2.png" height="167" alt="" />
    -+<p class="img-caption">
    -+<strong>Gambar 2.</strong> Dua perangkat berbeda, masing-masing menggunakan layout berbeda yang tersedia untuk
    -+ukuran layar berbeda.</p>
    -+</div>
    -+
    -+<p>Bagi setiap tipe sumber daya, Anda bisa menetapkan sumber daya <em>default</em> dan sumber daya
    -+<em>alternatif</em> untuk aplikasi Anda:</p>
    -+<ul>
    -+  <li>Sumber daya default adalah sumber daya yang harus digunakan apa pun
    -+konfigurasi perangkatnya atau jika tidak ada sumber daya alternatif yang sesuai
    -+dengan konfigurasi saat ini.</li>
    -+  <li>Sumber daya alternatif adalah sumber daya yang Anda desain untuk digunakan dengan
    -+konfigurasi tertentu. Untuk menetapkan bahwa satu kelompok sumber daya ditujukan bagi konfigurasi tertentu,
    -+tambahkan qualifier konfigurasi yang sesuai ke nama direktori.</li>
    -+</ul>
    -+
    -+<p>Misalnya, walaupun layout
    -+UI default Anda disimpan dalam direktori {@code res/layout/}, Anda dapat menetapkan layout berbeda
    -+untuk digunakan saat layar dalam orientasi lanskap, dengan menyimpannya dalam direktori {@code res/layout-land/}
    -+. Android secara otomatis memberlakukan sumber daya yang sesuai dengan mencocokkan konfigurasi perangkat
    -+saat ini dengan nama direktori sumber daya.</p>
    -+
    -+<p>Gambar 1 mengilustrasikan cara sistem memberlakukan layout yang sama untuk
    -+dua perangkat berbeda saat sumber daya alternatif tidak tersedia. Gambar 2 menunjukkan
    -+aplikasi yang sama saat menambahkan sumber daya layout alternatif untuk layar yang lebih besar.</p>
    -+
    -+<p>Dokumen-dokumen berikut berisi panduan lengkap mengenai cara menata sumber daya aplikasi,
    -+menetapkan sumber daya alternatif, mengaksesnya dalam aplikasi, dan banyak lagi:</p>
    -+
    -+<dl>
    -+  <dt><strong><a href="providing-resources.html">Menyediakan Sumber Daya</a></strong></dt>
    -+  <dd>Jenis sumber daya yang dapat Anda sediakan dalam aplikasi, tempat menyimpannya, dan cara membuat sumber daya
    -+alternatif untuk konfigurasi perangkat tertentu.</dd>
    -+  <dt><strong><a href="accessing-resources.html">Mengakses Sumber Daya</a></strong></dt>
    -+  <dd>Cara menggunakan sumber daya yang telah Anda sediakan, baik dengan mengacunya dari kode
    -+aplikasi Anda atau dari sumber daya XML lainnya.</dd>
    -+  <dt><strong><a href="runtime-changes.html">Menangani Perubahan Runtime</a></strong></dt>
    -+  <dd>Cara mengelola perubahan konfigurasi yang terjadi saat Aktivitas Anda berjalan.</dd>
    -+  <dt><strong><a href="localization.html">Pelokalan</a></strong></dt>
    -+  <dd>Panduan dari pengalaman untuk melokalkan aplikasi menggunakan sumber daya alternatif. Walaupun ini
    -+hanya satu penggunaan tertentu dari sumber daya alternatif, hal ini sangat penting dalam meraih pengguna lebih
    -+banyak.</dd>
    -+  <dt><strong><a href="available-resources.html">Tipe Sumber Daya</a></strong></dt>
    -+  <dd>Acuan dari berbagai tipe sumber daya yang dapat Anda sediakan, menjelaskan elemen-elemen XML,
    -+atribut, dan sintaksnya. Misalnya, acuan ini menunjukkan kepada Anda cara membuat sumber daya untuk
    -+menu aplikasi, drawable, animasi, dan lainnya.</dd>
    -+</dl>
    -+
    -+<!--
    -+<h2>Raw Assets</h2>
    -+
    -+<p>An alternative to saving files in {@code res/} is to save files in the {@code
    -+assets/} directory. This should only be necessary if you need direct access to original files and
    -+directories by name. Files saved in the {@code assets/} directory will not be given a resource
    -+ID, so you can't reference them through the {@code R} class or from XML resources. Instead, you can
    -+query data in the {@code assets/} directory like an ordinary file system, search through the
    -+directory and
    -+read raw data using {@link android.content.res.AssetManager}. For example, this can be more useful
    -+when dealing with textures for a game. However, if you only need to read raw data from a file
    -+(such as a video or audio file), then you should save files into the {@code res/raw/} directory and
    -+then read a stream of bytes using {@link android.content.res.Resources#openRawResource(int)}. This
    -+is uncommon, but if you need direct access to original files in {@code assets/}, refer to the {@link
    -+android.content.res.AssetManager} documentation.</p>
    -+-->
    -diff --git a/docs/html-intl/intl/id/guide/topics/resources/providing-resources.jd b/docs/html-intl/intl/id/guide/topics/resources/providing-resources.jd
    -new file mode 100644
    -index 0000000..9bccd24
    ---- /dev/null
    -+++ b/docs/html-intl/intl/id/guide/topics/resources/providing-resources.jd
    -@@ -0,0 +1,1094 @@
    -+page.title=Menyediakan Sumber Daya
    -+parent.title=Sumber Daya Aplikasi
    -+parent.link=index.html
    -+@jd:body
    -+
    -+<div id="qv-wrapper">
    -+<div id="qv">
    -+  <h2>Tampilan Cepat</h2>
    -+  <ul>
    -+    <li>Berbagai tipe sumber daya termasuk dalam subdirektori {@code res/}</li>
    -+    <li>Sumber daya alternatif menyediakan file sumber daya dengan konfigurasi tertentu</li>
    -+    <li>Sertakan selalu sumber daya default agar aplikasi Anda tidak bergantung pada
    -+konfigurasi perangkat tertentu</li>
    -+  </ul>
    -+  <h2>Dalam dokumen ini</h2>
    -+  <ol>
    -+    <li><a href="#ResourceTypes">Mengelompokkan Tipe Sumber Daya</a></li>
    -+    <li><a href="#AlternativeResources">Menyediakan Sumber Daya Alternatif</a>
    -+      <ol>
    -+        <li><a href="#QualifierRules">Aturan penamaan qualifier</a></li>
    -+        <li><a href="#AliasResources">Membuat sumber daya alias</a></li>
    -+      </ol>
    -+    </li>
    -+    <li><a href="#Compatibility">Menyediakan Kompatibilitas Perangkat Terbaik dengan Sumber Daya</a></li>
    -+    <li><a href="#BestMatch">Cara Android Menemukan Sumber Daya yang Paling Cocok</a></li>
    -+  </ol>
    -+
    -+  <h2>Lihat juga</h2>
    -+  <ol>
    -+    <li><a href="accessing-resources.html">Mengakses Sumber Daya</a></li>
    -+    <li><a href="available-resources.html">Tipe Sumber Daya</a></li>
    -+    <li><a href="{@docRoot}guide/practices/screens_support.html">Mendukung Beberapa
    -+Layar</a></li>
    -+  </ol>
    -+</div>
    -+</div>
    -+
    -+<p>Anda harus selalu mengeksternalkan sumber daya aplikasi seperti gambar dan string dari kode
    -+, agar Anda bisa memeliharanya secara independen. Anda juga harus menyediakan sumber daya alternatif untuk
    -+konfigurasi perangkat tertentu, dengan mengelompokkannya dalam direktori sumber daya bernama khusus. Saat
    -+runtime, Android menggunakan sumber daya yang sesuai berdasarkan konfigurasi saat ini. Misalnya, Anda mungkin
    -+ingin menyediakan layout UI berbeda bergantung pada ukuran layar atau string berbeda bergantung pada
    -+pengaturan bahasa.</p>
    -+
    -+<p>Setelah mengeksternalkan sumber daya aplikasi, Anda dapat mengaksesnya menggunakan
    -+ID sumber daya yang dibuat dalam kelas {@code R} proyek Anda. Cara menggunakan
    -+sumber daya dalam aplikasi dibahas dalam <a href="accessing-resources.html">Mengakses
    -+Sumber Daya</a>. Dokumen ini menampilkan cara mengelompokkan sumber daya
    -+dalam proyek Android Anda dan menyediakan sumber daya alternatif untuk konfigurasi perangkat tertentu.</p>
    -+
    -+
    -+<h2 id="ResourceTypes">Mengelompokkan Tipe Sumber Daya</h2>
    -+
    -+<p>Anda harus menempatkan setiap tipe sumber daya dalam subdirektori spesifik pada direktori
    -+{@code res/} proyek. Misalnya, inilah hierarki file untuk proyek sederhana:</p>
    -+
    -+<pre class="classic no-pretty-print">
    -+MyProject/
    -+    src/  <span style="color:black">
    -+        MyActivity.java  </span>
    -+    res/
    -+        drawable/  <span style="color:black">
    -+            graphic.png  </span>
    -+        layout/  <span style="color:black">
    -+            main.xml
    -+            info.xml</span>
    -+        mipmap/  <span style="color:black">
    -+            icon.png </span>
    -+        values/  <span style="color:black">
    -+            strings.xml  </span>
    -+</pre>
    -+
    -+<p>Seperti yang Anda lihat dalam contoh ini, direktori {@code res/} berisi semua sumber daya (dalam
    -+subdirektori): sumber daya gambar, dua sumber daya layout, direktori {@code mipmap/} untuk ikon
    -+launcher, dan satu file sumber daya string. Nama direktori
    -+sumber daya penting dan dijelaskan dalam tabel 1.</p>
    -+
    -+<p class="note"><strong>Catatan:</strong> Untuk informasi selengkapnya tentang menggunakan folder mipmap, lihat
    -+<a href="{@docRoot}tools/projects/index.html#mipmap">Mengelola Ikhtisar Proyek</a>.</p>
    -+
    -+<p class="table-caption" id="table1"><strong>Tabel 1.</strong> Direktori sumber daya
    -+didukung dalam direktori proyek {@code res/}.</p>
    -+
    -+<table>
    -+  <tr>
    -+    <th scope="col">Direktori</th>
    -+    <th scope="col">Tipe Sumber Daya</th>
    -+  </tr>
    -+
    -+  <tr>
    -+    <td><code>animator/</code></td>
    -+    <td>File XML yang mendefinisikan <a href="{@docRoot}guide/topics/graphics/prop-animation.html">animasi
    -+properti</a>.</td>
    -+  </tr>
    -+
    -+  <tr>
    -+    <td><code>anim/</code></td>
    -+    <td>File XML yang mendefinisikan <a href="{@docRoot}guide/topics/graphics/view-animation.html#tween-animation">animasi
    -+tween</a>. (Animasi properti juga dapat disimpan dalam direktori ini, namun
    -+direktori {@code animator/} lebih disukai bagi animasi properti agar kedua tipe
    -+ini dapat dibedakan.)</td>
    -+  </tr>
    -+
    -+  <tr>
    -+    <td><code>color/</code></td>
    -+    <td>File XML yang mendefinisikan daftar status warna. Lihat <a href="color-list-resource.html">Sumber Daya
    -+Daftar Status Warna</a></td>
    -+  </tr>
    -+
    -+  <tr>
    -+    <td><code>drawable/</code></td>
    -+
    -+    <td><p>File bitmap ({@code .png}, {@code .9.png}, {@code .jpg}, {@code .gif}) atau file XML yang
    -+dikompilasi menjadi subtipe sumber daya drawable berikut:</p>
    -+      <ul>
    -+        <li>File bitmap</li>
    -+        <li>Nine-Patches (bitmap yang dapat diubah ukurannya)</li>
    -+        <li>Daftar status</li>
    -+        <li>Bentuk</li>
    -+        <li>Drawable animasi</li>
    -+        <li>Drawable lainnya</li>
    -+      </ul>
    -+      <p>Lihat <a href="drawable-resource.html">Sumber Daya Drawable</a>.</p>
    -+    </td>
    -+  </tr>
    -+
    -+  <tr>
    -+    <td><code>mipmap/</code></td>
    -+    <td>File drawable untuk densitas ikon launcher yang berbeda. Untuk informasi selengkapnya tentang
    -+ mengelola ikon launcher dengan folder {@code mipmap/}, lihat
    -+<a href="{@docRoot}tools/project/index.html#mipmap">Mengelola Ikhtisar Proyek</a>.</td>
    -+  </tr>
    -+
    -+  <tr>
    -+    <td><code>layout/</code></td>
    -+    <td>File XML yang mendefinisikan layout antarmuka pengguna.
    -+        Lihat <a href="layout-resource.html">Sumber Daya Layout</a>.</td>
    -+  </tr>
    -+
    -+  <tr>
    -+    <td><code>menu/</code></td>
    -+    <td>File XML yang mendefinisikan menu aplikasi, seperti Menu Opsi, Menu Konteks, atau Sub
    -+Menu. Lihat <a href="menu-resource.html">Sumber Daya Menu</a>.</td>
    -+  </tr>
    -+
    -+  <tr>
    -+    <td><code>raw/</code></td>
    -+    <td><p>File tak didukung yang akan disimpan dalam bentuk mentah. Untuk membuka sumber daya ini dengan
    -+{@link java.io.InputStream} mentah, panggil {@link android.content.res.Resources#openRawResource(int)
    -+Resources.openRawResource()} dengan ID sumber daya, yaitu {@code R.raw.<em>filename</em>}.</p>
    -+      <p>Akan tetapi, jika Anda butuh akses ke nama file asli dan hierarki file, Anda bisa mempertimbangkan
    -+untuk menyimpan beberapa sumber daya dalam direktori {@code
    -+assets/} (sebagai ganti {@code res/raw/}). File dalam {@code assets/} tidak diberi
    -+ID sumber daya, jadi Anda bisa membacanya hanya dengan menggunakan {@link android.content.res.AssetManager}.</p></td>
    -+  </tr>
    -+
    -+  <tr>
    -+    <td><code>values/</code></td>
    -+    <td><p>File XML yang berisi nilai-nilai sederhana, seperti string, integer, dan warna.</p>
    -+      <p>Walaupun file sumber daya XML dalam subdirektori {@code res/} lainnya mendefinisikan satu sumber daya
    -+berdasarkan nama file XML, file dalam direktori {@code values/} menggambarkan beberapa sumber daya.
    -+Untuk file dalam direktori ini, setiap anak elemen {@code &lt;resources&gt;} mendefinisikan satu sumber
    -+daya. Misalnya, elemen {@code &lt;string&gt;} membuat sumber daya
    -+{@code R.string} dan elemen {@code &lt;color&gt;} membuat sumber daya {@code R.color}
    -+.</p>
    -+      <p>Karena setiap sumber daya didefinisikan dengan elemen XML-nya sendiri, Anda bisa bebas menamai file
    -+ini dan menempatkan tipe sumber daya berbeda dalam satu file. Akan tetapi, agar jelas, Anda mungkin
    -+perlu menempatkan tipe sumber daya unik dalam file berbeda. Misalnya, berikut ini adalah beberapa ketentuan
    -+penamaan file untuk sumber daya yang dapat Anda buat dalam direktori ini:</p>
    -+      <ul>
    -+        <li>arrays.xml untuk larik sumber daya tipe (<a href="more-resources.html#TypedArray">larik bertipe</a>).</li>
    -+        <li>colors.xml untuk <a href="more-resources.html#Color">nilai warna</a></li>
    -+        <li>dimens.xml untuk <a href="more-resources.html#Dimension">nilai dimensi</a>.</li>
    -+        <li>strings.xml untuk <a href="string-resource.html">nilai
    -+string</a>.</li>
    -+        <li>styles.xml untuk <a href="style-resource.html">gaya</a>.</li>
    -+      </ul>
    -+      <p>Lihat <a href="string-resource.html">Sumber Daya String</a>,
    -+        <a href="style-resource.html">Sumber Daya Gaya</a>, dan
    -+        <a href="more-resources.html">Tipe Sumber Daya Lainnya</a>.</p>
    -+    </td>
    -+  </tr>
    -+
    -+  <tr>
    -+    <td><code>xml/</code></td>
    -+    <td>File XML tak didukung yang bisa dibaca saat runtime dengan memanggil {@link
    -+android.content.res.Resources#getXml(int) Resources.getXML()}. Berbagai file konfigurasi XML
    -+harus disimpan di sini, seperti <a href="{@docRoot}guide/topics/search/searchable-config.html">konfigurasi yang dapat dicari</a>.
    -+<!-- or preferences configuration. --></td>
    -+  </tr>
    -+</table>
    -+
    -+<p class="caution"><strong>Perhatian:</strong> Jangan menyimpan file sumber daya secara langsung dalam
    -+direktori {@code res/}&mdash; karena akan menyebabkan kesalahan compiler.</p>
    -+
    -+<p>Untuk informasi selengkapnya tentang tipe sumber daya tertentu, lihat dokumentasi <a href="available-resources.html">Tipe Sumber Daya</a>.</p>
    -+
    -+<p>Sumber daya yang disimpan dalam subdirektori yang didefinisikan dalam tabel 1 adalah sumber daya
    -+"default" Anda. Berarti sumber daya ini mendefinisikan desain default dan konten untuk aplikasi Anda.
    -+Akan tetapi, beberapa tipe perangkat berbasis Android mungkin memanggil tipe sumber daya yang berbeda.
    -+Misalnya, jika perangkat memiliki layar yang lebih besar daripada layar normal, maka Anda harus
    -+menyediakan sumber daya layout berbeda yang memanfaatkan ruang layar yang lebih besar. Atau, jika perangkat
    -+memiliki pengaturan bahasa berbeda, maka Anda harus menyediakan sumber daya string berbeda yang menerjemahkan teks dalam
    -+antarmuka pengguna Anda. Untuk menyediakan sumber daya berbeda ini bagi
    -+konfigurasi perangkat yang berbeda, Anda harus menyediakan sumber daya alternatif, selain sumber
    -+daya default.</p>
    -+
    -+
    -+<h2 id="AlternativeResources">Menyediakan Sumber Daya Alternatif</h2>
    -+
    -+
    -+<div class="figure" style="width:429px">
    -+<img src="{@docRoot}images/resources/resource_devices_diagram2.png" height="167" alt="" />
    -+<p class="img-caption">
    -+<strong>Gambar 1.</strong> Dua perangkat berbeda, masing-masing menggunakan sumber daya layout berbeda.</p>
    -+</div>
    -+
    -+<p>Hampir setiap aplikasi harus menyediakan sumber daya alternatif untuk mendukung konfigurasi
    -+perangkat tertentu. Misalnya, Anda harus menyertakan sumber daya drawable alternatif untuk densitas layar
    -+berbeda dan sumber daya string alternatif untuk bahasa yang berbeda. Saat runtime, Android
    -+akan mendeteksi konfigurasi perangkat aktif dan memuat
    -+sumber daya yang sesuai untuk aplikasi Anda.</p>
    -+
    -+<p>Untuk menyebutkan alternatif konfigurasi tertentu untuk satu set sumber daya:</p>
    -+<ol>
    -+  <li>Buat direktori baru dalam {@code res/} yang dinamai dalam bentuk {@code
    -+<em>&lt;resources_name&gt;</em>-<em>&lt;config_qualifier&gt;</em>}.
    -+    <ul>
    -+      <li><em>{@code &lt;resources_name&gt;}</em> adalah nama direktori dari sumber daya default
    -+terkait (didefinisikan dalam tabel 1).</li>
    -+      <li><em>{@code &lt;qualifier&gt;}</em> adalah nama yang menetapkan konfigurasi individu
    -+yang akan digunakan sumber daya ini (didefinisikan dalam tabel 2).</li>
    -+    </ul>
    -+    <p>Anda bisa menambahkan lebih dari satu <em>{@code &lt;qualifier&gt;}</em>. Pisahkan masing-masing
    -+dengan tanda hubung.</p>
    -+    <p class="caution"><strong>Perhatian:</strong> Saat menambahkan beberapa qualifier, Anda
    -+harus menempatkannya dalam urutan yang sama dengan yang tercantum dalam tabel 2. Jika urutan qualifier
    -+salah, sumber daya akan diabaikan.</p>
    -+  </li>
    -+  <li>Simpan masing-masing sumber daya alternatif dalam direktori baru ini. File sumber daya harus dinamai
    -+sama persis dengan file sumber daya default.</li>
    -+</ol>
    -+
    -+<p>Misalnya, berikut ini beberapa sumber daya default dan sumber daya alternatif:</p>
    -+
    -+<pre class="classic no-pretty-print">
    -+res/
    -+    drawable/   <span style="color:black">
    -+        icon.png
    -+        background.png    </span>
    -+    drawable-hdpi/  <span style="color:black">
    -+        icon.png
    -+        background.png  </span>
    -+</pre>
    -+
    -+<p>Qualifier {@code hdpi} menunjukkan bahwa sumber daya dalam direktori itu diperuntukkan bagi perangkat dengan
    -+layar densitas tinggi. Gambar di masing-masing direktori drawable memiliki ukuran untuk densitas layar
    -+tertentu, namun nama filenya persis
    -+sama. Dengan demikian, ID sumber daya yang Anda gunakan untuk mengacu gambar {@code icon.png} atau @code
    -+background.png} selalu sama, namun Android memilih
    -+versi masing-masing sumber daya yang paling cocok dengan perangkat saat ini, dengan membandingkan informasi konfigurasi
    -+perangkat dengan qualifier dalam nama direktori sumber daya.</p>
    -+
    -+<p>Android mendukung beberapa qualifier konfigurasi dan Anda dapat
    -+menambahkan beberapa qualifier ke satu nama direktori, dengan memisahkan setiap qualifier dengan tanda hubung. Tabel 2
    -+berisi daftar qualifier konfigurasi yang valid, dalam urutan prioritas&mdash;jika Anda menggunakan beberapa
    -+qualifier sebagai direktori sumber daya, Anda harus menambahkannya ke nama direktori sesuai urutan
    -+yang tercantum dalam tabel.</p>
    -+
    -+
    -+<p class="table-caption" id="table2"><strong>Tabel 2.</strong> Nama-nama
    -+qualifier konfigurasi.</p>
    -+<table>
    -+    <tr>
    -+        <th>Konfigurasi</th>
    -+        <th>Nilai-nilai Qualifier</th>
    -+        <th>Keterangan</th>
    -+    </tr>
    -+    <tr id="MccQualifier">
    -+      <td>MCC dan MNC</td>
    -+      <td>Contoh:<br/>
    -+        <code>mcc310</code><br/>
    -+        <code><nobr>mcc310-mnc004</nobr></code><br/>
    -+        <code>mcc208-mnc00</code><br/>
    -+        dll.
    -+      </td>
    -+      <td>
    -+        <p>Kode negara seluler (MCC), bisa diikuti dengan kode jaringan seluler (MNC)
    -+ dari kartu SIM dalam perangkat. Misalnya, <code>mcc310</code> adalah AS untuk operator mana saja,
    -+ <code>mcc310-mnc004</code> adalah AS untuk Verizon, dan <code>mcc208-mnc00</code> Prancis untuk
    -+Orange.</p>
    -+        <p>Jika perangkat menggunakan koneksi radio (ponsel GSM), nilai-nilai MCC dan MNC berasal
    -+dari kartu SIM.</p>
    -+        <p>Anda juga dapat menggunakan MNC saja (misalnya, untuk menyertakan sumber daya legal
    -+spesifik untuk negara itu di aplikasi Anda). Jika Anda perlu menetapkan hanya berdasarkan bahasa, maka gunakan qualifier
    -+<em>bahasa dan wilayah</em> sebagai gantinya (akan dibahas nanti). Jika Anda memutuskan untuk menggunakan qualifier MCC dan
    -+MNC, Anda harus melakukannya dengan hati-hati dan menguji apakah qualifier itu berjalan sesuai harapan.</p>
    -+        <p>Lihat juga bidang konfigurasi {@link
    -+android.content.res.Configuration#mcc}, dan {@link
    -+android.content.res.Configuration#mnc}, yang masing-masing menunjukkan kode negara seluler saat ini
    -+dan kode jaringan seluler.</p>
    -+      </td>
    -+    </tr>
    -+    <tr id="LocaleQualifier">
    -+      <td>Bahasa dan wilayah</td>
    -+      <td>Contoh:<br/>
    -+        <code>en</code><br/>
    -+        <code>fr</code><br/>
    -+        <code>en-rUS</code><br/>
    -+        <code>fr-rFR</code><br/>
    -+        <code>fr-rCA</code><br/>
    -+        dll.
    -+      </td>
    -+      <td><p>Bahasa didefinisikan oleh kode bahasa dua huruf <a href="http://www.loc.gov/standards/iso639-2/php/code_list.php">ISO
    -+639-1</a>, bisa juga diikuti dengan kode wilayah
    -+dua huruf <a href="http://www.iso.org/iso/en/prods-services/iso3166ma/02iso-3166-code-lists/list-en1.html">ISO
    -+3166-1-alpha-2</a> (diawali dengan huruf kecil "{@code r}").
    -+        </p><p>
    -+        Kode <em>tidak</em> membedakan huruf besar atau kecil; awalan {@code r} akan digunakan untuk
    -+membedakan bagian wilayah.
    -+        Anda tidak bisa menetapkan wilayah saja.</p>
    -+        <p>Ini bisa berubah selama masa pakai
    -+aplikasi Anda jika pengguna mengubah bahasanya dalam pengaturan sistem. Lihat <a href="runtime-changes.html">Menangani Perubahan Runtime</a> untuk informasi tentang
    -+bagaimana hal ini dapat memengaruhi aplikasi Anda selama runtime.</p>
    -+        <p>Lihat <a href="localization.html">Pelokalan</a> untuk panduan lengkap melokalkan
    -+aplikasi Anda ke bahasa lain.</p>
    -+        <p>Lihat juga bidang konfigurasi {@link android.content.res.Configuration#locale} yang menunjukkan
    -+bahasa setempat yang digunakan saat ini.</p>
    -+      </td>
    -+    </tr>
    -+    <tr id="LayoutDirectionQualifier">
    -+      <td>Arah Layout</td>
    -+      <td><code>ldrtl</code><br/>
    -+        <code>ldltr</code><br/>
    -+      </td>
    -+      <td><p>Arah layout aplikasi Anda. {@code ldrtl} berarti "arah layout dari kanan ke kiri".
    -+ {@code ldltr} berarti "arah layout dari kiri ke kanan" dan merupakan nilai implisit default.
    -+      </p>
    -+      <p>Ini bisa berlaku untuk sumber daya mana pun seperti layout, drawable, atau nilai-nilai.
    -+      </p>
    -+      <p>Misalnya, jika Anda ingin memberikan beberapa layout khusus untuk bahasa Arab dan beberapa
    -+layout umum untuk setiap bahasa lainnya yang menggunakan "kanan-ke-kiri" lainnya (seperti bahasa Persia atau Ibrani) maka Anda akan memiliki:
    -+      </p>
    -+<pre class="classic no-pretty-print">
    -+res/
    -+    layout/   <span style="color:black">
    -+        main.xml  </span>(Default layout)
    -+    layout-ar/  <span style="color:black">
    -+        main.xml  </span>(Specific layout for Arabic)
    -+    layout-ldrtl/  <span style="color:black">
    -+        main.xml  </span>(Any "right-to-left" language, except
    -+                  for Arabic, because the "ar" language qualifier
    -+                  has a higher precedence.)
    -+</pre>
    -+        <p class="note"><strong>Catatan:</strong> Untuk mengaktifkan fitur
    -+layout kanan-ke-kiri untuk aplikasi, Anda harus mengatur <a href="{@docRoot}guide/topics/manifest/application-element.html#supportsrtl">{@code
    -+        supportsRtl}</a> ke {@code "true"} dan mengatur <a href="{@docRoot}guide/topics/manifest/uses-sdk-element.html#target">{@code targetSdkVersion}</a> ke 17 atau yang lebih tinggi.</p>
    -+        <p><em>Ditambahkan dalam API level 17.</em></p>
    -+      </td>
    -+    </tr>
    -+    <tr id="SmallestScreenWidthQualifier">
    -+      <td>smallestWidth</td>
    -+      <td><code>sw&lt;N&gt;dp</code><br/><br/>
    -+        Contoh:<br/>
    -+        <code>sw320dp</code><br/>
    -+        <code>sw600dp</code><br/>
    -+        <code>sw720dp</code><br/>
    -+        dll.
    -+      </td>
    -+      <td>
    -+        <p>Ukuran dasar layar, sebagaimana yang ditunjukkan oleh dimensi terpendek dari area layar
    -+yang tersedia. Secara spesifik, smallestWidth perangkat adalah yang terpendek dari
    -+tinggi dan lebar layar yang tersedia (Anda dapat menganggapnya sebagai "lebar terkecil yang memungkinkan" untuk layar). Anda bisa
    -+menggunakan qualifier ini untuk memastikan bahwa, apa pun orientasi layar saat ini, aplikasi
    -+Anda memiliki paling tidak {@code &lt;N&gt;} dps dari lebar yang tersedia untuk UI-nya.</p>
    -+        <p>Misalnya, jika layout mengharuskan dimensi layar terkecilnya setiap saat paling tidak
    -+600 dp, maka Anda dapat menggunakan qualifer ini untuk membuat sumber daya layout, {@code
    -+res/layout-sw600dp/}. Sistem akan menggunakan sumber daya ini hanya bila dimensi layar terkecil yang
    -+tersedia paling tidak 600 dp, tanpa mempertimbangkan apakah sisi 600 dp adalah tinggi atau
    -+lebar yang dipersepsikan pengguna. SmallestWidth adalah karakteristik ukuran layar tetap dari perangkat; <strong>smallestWidth
    -+perangkat tidak berubah saat orientasi layar berubah</strong>.</p>
    -+        <p>SmallestWidth perangkat memperhitungkan dekorasi layar dan UI sistem. Misalnya
    -+, jika perangkat memiliki beberapa elemen UI persisten pada layar yang menghitung ruang di sepanjang
    -+sumbu smallestWidth, sistem akan mendeklarasikan smallestWidth lebih kecil daripada ukuran layar sebenarnya,
    -+karena itu adalah piksel layar yang tidak tersedia untuk UI Anda. Sehingga nilai yang Anda
    -+gunakan haruslah merupakan dimensi terkecil sebenarnya yang <em>dibutuhkan oleh layout Anda</em> (biasanya, nilai ini adalah
    -+"lebar terkecil" yang didukung layout Anda, apa pun orientasi layar saat ini).</p>
    -+        <p>Sebagian nilai yang mungkin Anda gunakan untuk ukuran layar umum:</p>
    -+        <ul>
    -+          <li>320, untuk perangkat berkonfigurasi layar seperti:
    -+            <ul>
    -+              <li>240x320 ldpi (handset QVGA)</li>
    -+              <li>320x480 mdpi (handset)</li>
    -+              <li>480x800 hdpi (handset densitas tinggi)</li>
    -+            </ul>
    -+          </li>
    -+          <li>480, untuk layar seperti 480x800 mdpi (tablet/handset).</li>
    -+          <li>600, untuk layar seperti 600x1024 mdpi (tablet 7").</li>
    -+          <li>720, untuk layar seperti 720x1280 mdpi (tablet 10").</li>
    -+        </ul>
    -+        <p>Bila aplikasi Anda menyediakan beberapa direktori sumber daya dengan nilai yang berbeda untuk
    -+qualifier smallestWidth terkecil, sistem akan menggunakan nilai terdekat dengan (tanpa melebihi)
    -+smallestWidth perangkat. </p>
    -+        <p><em>Ditambahkan dalam API level 13.</em></p>
    -+        <p>Lihat juga atribut <a href="{@docRoot}guide/topics/manifest/supports-screens-element.html#requiresSmallest">{@code
    -+android:requiresSmallestWidthDp}</a>, yang mendeklarasikan smallestWidth minimum yang
    -+kompatibel dengan aplikasi Anda, dan bidang konfigurasi {@link
    -+android.content.res.Configuration#smallestScreenWidthDp}, yang menyimpan nilai
    -+smallestWidth perangkat.</p>
    -+        <p>Untuk informasi selengkapnya tentang mendesain untuk layar berbeda dan menggunakan
    -+qualifier ini, lihat panduan pengembang <a href="{@docRoot}guide/practices/screens_support.html">Mendukung
    -+Multi Layar</a>.</p>
    -+      </td>
    -+    </tr>
    -+    <tr id="ScreenWidthQualifier">
    -+      <td>Lebar yang tersedia</td>
    -+      <td><code>w&lt;N&gt;dp</code><br/><br/>
    -+        Contoh:<br/>
    -+        <code>w720dp</code><br/>
    -+        <code>w1024dp</code><br/>
    -+        dll.
    -+      </td>
    -+      <td>
    -+        <p>Menetapkan lebar layar minimum yang tersedia, di unit {@code dp} yang
    -+menggunakan sumber daya&mdash;yang didefinisikan oleh nilai <code>&lt;N&gt;</code>.  Nilai konfigurasi ini
    -+ akan berubah bila orientasi
    -+berubah antara lanskap dan potret agar cocok dengan lebar sebenarnya saat ini.</p>
    -+        <p>Bila aplikasi Anda menyediakan beberapa direktori sumber daya dengan nilai yang berbeda
    -+ untuk konfigurasi ini, sistem akan menggunakan nilai terdekat dengan (tanpa melebihi)
    -+ lebar layar perangkat saat ini.  Nilai
    -+di sini memperhitungkan dekorasi layar akun, jadi jika perangkat memiliki beberapa
    -+elemen UI persisten di tepi kiri atau kanan, layar
    -+menggunakan nilai lebar yang lebih kecil daripada ukuran layar sebenarnya, yang memperhitungkan
    -+elemen UI ini dan mengurangi ruang aplikasi yang tersedia.</p>
    -+        <p><em>Ditambahkan dalam API level 13.</em></p>
    -+        <p>Lihat juga bidang konfigurasi {@link android.content.res.Configuration#screenWidthDp}
    -+ yang menyimpan lebar layar saat ini.</p>
    -+        <p>Untuk informasi selengkapnya tentang mendesain untuk layar berbeda dan menggunakan
    -+qualifier ini, lihat panduan pengembang <a href="{@docRoot}guide/practices/screens_support.html">Mendukung
    -+Multi Layar</a>.</p>
    -+      </td>
    -+    </tr>
    -+    <tr id="ScreenHeightQualifier">
    -+      <td>Tinggi yang tersedia</td>
    -+      <td><code>h&lt;N&gt;dp</code><br/><br/>
    -+        Contoh:<br/>
    -+        <code>h720dp</code><br/>
    -+        <code>h1024dp</code><br/>
    -+        dll.
    -+      </td>
    -+      <td>
    -+        <p>Menetapkan tinggi layar minimum yang tersedia, dalam satuan "dp" yang harus digunakan
    -+sumber daya &mdash;bersama nilai yang didefinisikan oleh <code>&lt;N&gt;</code>.  Nilai konfigurasi ini
    -+ akan berubah saat orientasi
    -+berubah antara lanskap dan potret agar cocok dengan tinggi sebenarnya saat ini.</p>
    -+        <p>Bila aplikasi menyediakan beberapa direktori sumber daya dengan nilai yang berbeda
    -+ untuk konfigurasi ini, sistem akan menggunakan nilai yang terdekat dengan (tanpa melebihi)
    -+ tinggi layar perangkat saat ini.  Nilai
    -+di sini memperhitungkan dekorasi layar akun, jadi jika perangkat memiliki beberapa
    -+elemen UI persisten di tepi atas atau bawah, layar akan
    -+menggunakan nilai tinggi yang lebih kecil daripada ukuran layar sebenarnya, memperhitungkan
    -+elemen UI ini dan mengurangi ruang aplikasi yang tersedia.  Dekorasi
    -+layar yang tidak tetap (misalnya baris status (status-bar) telepon yang bisa
    -+disembunyikan saat layar penuh) di sini <em>tidak</em> diperhitungkan, demikian pula
    -+dekorasi jendela seperti baris judul (title-bar)atau baris tindakan (action-bar), jadi aplikasi harus disiapkan
    -+untuk menangani ruang yang agak lebih kecil daripada yang ditetapkan.
    -+        <p><em>Ditambahkan dalam API level 13.</em></p>
    -+        <p>Lihat juga bidang konfigurasi {@link android.content.res.Configuration#screenHeightDp}
    -+ yang menyimpan lebar layar saat ini.</p>
    -+        <p>Untuk informasi selengkapnya tentang mendesain untuk layar berbeda dan menggunakan
    -+qualifier ini, lihat panduan pengembang <a href="{@docRoot}guide/practices/screens_support.html">Mendukung
    -+Multi Layar</a>.</p>
    -+      </td>
    -+    </tr>
    -+    <tr id="ScreenSizeQualifier">
    -+      <td>Ukuran layar</td>
    -+      <td>
    -+        <code>small</code><br/>
    -+        <code>normal</code><br/>
    -+        <code>large</code><br/>
    -+        <code>xlarge</code>
    -+      </td>
    -+      <td>
    -+        <ul class="nolist">
    -+        <li>{@code small}: Layar yang berukuran serupa dengan
    -+layar QVGA densitas rendah. Ukuran layout minimum untuk layar kecil
    -+adalah sekitar 320x426 satuan dp.  Misalnya QVGA densitas rendah
    -+dan VGA densitas tinggi.</li>
    -+        <li>{@code normal}: Layar yang berukuran serupa dengan
    -+layar HVGA densitas sedang. Ukuran layout minimum untuk
    -+layar normal adalah sekitar 320x470 satuan dp.  Contoh layar seperti itu adalah
    -+WQVGA densitas rendah, HVGA densitas sedang, WVGA
    -+     densitas tinggi.</li>
    -+        <li>{@code large}: Layar yang berukuran serupa dengan
    -+layar VGA densitas sedang.
    -+        Ukuran layout minimum untuk layar besar adalah sekitar 480x640 satuan dp.
    -+        Misalnya layar VGA dan WVGA densitas sedang.</li>
    -+        <li>{@code xlarge}: Layar yang jauh lebih besar dari layar HVGA
    -+densitas sedang tradisional. Ukuran layout minimum untuk
    -+layar ekstra besar adalah sekitar 720x960 satuan dp.  Perangkat dengan layar ekstra besar
    -+seringkali terlalu besar untuk dibawa dalam saku dan kemungkinan besar
    -+ berupa perangkat bergaya tablet. <em>Ditambahkan dalam API level 9.</em></li>
    -+        </ul>
    -+        <p class="note"><strong>Catatan:</strong> Menggunakan qualifier ukuran tidak berarti bahwa
    -+sumber daya <em>hanya</em> untuk layar ukuran itu saja. Jika Anda tidak menyediakan sumber
    -+daya alternatif dengan qualifier yang lebih cocok dengan konfigurasi perangkat saat ini, sistem dapat menggunakan sumber daya
    -+mana saja yang <a href="#BestMatch">paling cocok</a>.</p>
    -+        <p class="caution"><strong>Perhatian:</strong> Jika semua sumber daya Anda menggunakan
    -+qualifier yang berukuran <em>lebih besar</em> daripada layar saat ini, sistem <strong>tidak</strong> akan menggunakannya dan aplikasi
    -+Anda akan crash saat runtime (misalnya, jika semua sumber daya layout ditandai dengan qualifier {@code
    -+xlarge}, namun perangkat memiliki ukuran layar normal).</p>
    -+        <p><em>Ditambahkan dalam API level 4.</em></p>
    -+
    -+        <p>Lihat <a href="{@docRoot}guide/practices/screens_support.html">Mendukung Beberapa
    -+Layar</a> untuk informasi selengkapnya.</p>
    -+        <p>Lihat juga bidang konfigurasi {@link android.content.res.Configuration#screenLayout},
    -+ yang menunjukkan apakah layar berukuran kecil, normal, atau
    -+besar.</p>
    -+      </td>
    -+    </tr>
    -+    <tr id="ScreenAspectQualifier">
    -+      <td>Aspek layar</td>
    -+      <td>
    -+        <code>long</code><br/>
    -+        <code>notlong</code>
    -+      </td>
    -+      <td>
    -+        <ul class="nolist">
    -+          <li>{@code long}: Layar panjang, seperti WQVGA, WVGA, FWVGA</li>
    -+          <li>{@code notlong}: Layar tidak panjang, seperti QVGA, HVGA, dan VGA</li>
    -+        </ul>
    -+        <p><em>Ditambahkan dalam API level 4.</em></p>
    -+        <p>Ini berdasarkan sepenuhnya pada rasio aspek layar (layar "panjang" lebih lebar). Ini
    -+tidak ada kaitannya dengan orientasi layar.</p>
    -+        <p>Lihat juga bidang konfigurasi {@link android.content.res.Configuration#screenLayout},
    -+ yang menunjukkan apakah layar panjang.</p>
    -+      </td>
    -+    </tr>
    -+    <tr id="OrientationQualifier">
    -+      <td>Orientasi layar</td>
    -+      <td>
    -+        <code>port</code><br/>
    -+        <code>land</code>  <!-- <br/>
    -+        <code>square</code>  -->
    -+      </td>
    -+      <td>
    -+        <ul class="nolist">
    -+          <li>{@code port}: Perangkat dalam orientasi potret (vertikal)</li>
    -+          <li>{@code land}: Perangkat dalam orientasi lanskap (horizontal)</li>
    -+          <!-- Square mode is currently not used. -->
    -+        </ul>
    -+        <p>Ini bisa berubah selama masa pakai aplikasi Anda jika pengguna memutar
    -+layar. Lihat <a href="runtime-changes.html">Menangani Perubahan Runtime</a> untuk
    -+ informasi tentang bagaimana hal ini memengaruhi aplikasi Anda selama runtime.</p>
    -+        <p>Lihat juga bidang konfigurasi {@link android.content.res.Configuration#orientation},
    -+yang menunjukkan orientasi perangkat saat ini.</p>
    -+      </td>
    -+    </tr>
    -+    <tr id="UiModeQualifier">
    -+      <td>Mode UI</td>
    -+      <td>
    -+        <code>car</code><br/>
    -+        <code>desk</code><br/>
    -+        <code>television</code><br/>
    -+        <code>appliance</code>
    -+        <code>watch</code>
    -+      </td>
    -+      <td>
    -+        <ul class="nolist">
    -+          <li>{@code car}: Perangkat sedang menampilkan di dudukan perangkat di mobil</li>
    -+          <li>{@code desk}: Perangkat sedang menampilkan di dudukan perangkat di meja</li>
    -+          <li>{@code television}: Perangkat sedang menampilkan di televisi, yang menyediakan
    -+pengalaman "sepuluh kaki" dengan UI-nya pada layar besar yang berada jauh dari pengguna,
    -+terutama diorientasikan seputar DPAD atau
    -+interaksi non-pointer lainnya</li>
    -+          <li>{@code appliance}: Perangkat berlaku sebagai
    -+alat, tanpa tampilan</li>
    -+          <li>{@code watch}: Perangkat memiliki tampilan dan dikenakan di pergelangan tangan</li>
    -+        </ul>
    -+        <p><em>Ditambahkan dalam API level 8, televisi ditambahkan dalam API 13, jam ditambahkan dalam API 20.</em></p>
    -+        <p>Untuk informasi tentang cara aplikasi merespons saat perangkat dimasukkan
    -+ke dalam atau dilepaskan dari dudukannya, bacalah <a href="{@docRoot}training/monitoring-device-state/docking-monitoring.html">Menentukan
    -+dan Memantau Kondisi dan Tipe Dudukan</a>.</p>
    -+        <p>Ini bisa berubah selama masa pakai aplikasi jika pengguna menempatkan perangkat di
    -+dudukannya. Anda dapat mengaktifkan atau menonaktifkan sebagian mode ini menggunakan {@link
    -+android.app.UiModeManager}. Lihat <a href="runtime-changes.html">Menangani Perubahan Runtime</a> untuk
    -+informasi tentang bagaimana hal ini memengaruhi aplikasi Anda selama runtime.</p>
    -+      </td>
    -+    </tr>
    -+    <tr id="NightQualifier">
    -+      <td>Mode malam</td>
    -+      <td>
    -+        <code>night</code><br/>
    -+        <code>notnight</code>
    -+      </td>
    -+      <td>
    -+        <ul class="nolist">
    -+          <li>{@code night}: Waktu malam</li>
    -+          <li>{@code notnight}: Waktu siang</li>
    -+        </ul>
    -+        <p><em>Ditambahkan dalam API level 8.</em></p>
    -+        <p>Ini bisa berubah selama masa pakai aplikasi jika mode malam dibiarkan dalam
    -+mode otomatis (default), dalam hal ini perubahan mode berdasarkan pada waktu hari.  Anda dapat mengaktifkan
    -+atau menonaktifkan mode ini menggunakan {@link android.app.UiModeManager}. Lihat <a href="runtime-changes.html">Menangani Perubahan Runtime</a> untuk informasi tentang bagaimana hal ini memengaruhi
    -+aplikasi Anda selama runtime.</p>
    -+      </td>
    -+    </tr>
    -+    <tr id="DensityQualifier">
    -+      <td>Densitas piksel layar (dpi)</td>
    -+      <td>
    -+        <code>ldpi</code><br/>
    -+        <code>mdpi</code><br/>
    -+        <code>hdpi</code><br/>
    -+        <code>xhdpi</code><br/>
    -+        <code>xxhdpi</code><br/>
    -+        <code>xxxhdpi</code><br/>
    -+        <code>nodpi</code><br/>
    -+        <code>tvdpi</code>
    -+      </td>
    -+      <td>
    -+        <ul class="nolist">
    -+          <li>{@code ldpi}: Layar densitas rendah; sekitar 120 dpi.</li>
    -+          <li>{@code mdpi}: Layar densitas sedang (pada HVGA tradisional); sekitar 160 dpi.
    -+</li>
    -+          <li>{@code hdpi}: Layar densitas tinggi; sekitar 240 dpi.</li>
    -+          <li>{@code xhdpi}: Layar densitas ekstra tinggi; sekitar 320 dpi. <em>Ditambahkan dalam API
    -+Level 8.</em></li>
    -+          <li>{@code xxhdpi}: Layar densitas ekstra-ekstra-tinggi; sekitar 480 dpi. <em>Ditambahkan dalam API
    -+Level 16.</em></li>
    -+          <li>{@code xxxhdpi}: Densitas ekstra-ekstra-ekstra-tinggi (hanya ikon launcher,
    -+lihat <a href="{@docRoot}guide/practices/screens_support.html#xxxhdpi-note">catatan</a>
    -+ dalam <em>Mendukung Beberapa Layar</em>); sekitar 640 dpi. <em>Ditambahkan dalam API
    -+Level 18.</em></li>
    -+          <li>{@code nodpi}: Ini bisa digunakan untuk sumber daya bitmap yang tidak ingin Anda
    -+skalakan agar sama dengan densitas perangkat.</li>
    -+          <li>{@code tvdpi}: Layar antara mdpi dan hdpi; sekitar 213 dpi. Ini
    -+tidak dianggap sebagai kelompok densitas "utama". Sebagian besar ditujukan untuk televisi dan kebanyakan
    -+aplikasi tidak memerlukannya &mdash;asalkan sumber daya mdpi dan hdpi cukup untuk sebagian besar aplikasi dan
    -+sistem akan menskalakan sebagaimana mestinya. Qualifier ini diperkenalkan pada API level 13.</li>
    -+        </ul>
    -+        <p>Terdapat rasio skala 3:4:6:8:12:16 antara enam densitas utama (dengan mengabaikan densitas
    -+tvdpi). Jadi bitmap 9x9 di ldpi adalah 12x12 di mdpi, 18x18 di hdpi, 24x24 di xhdpi dan seterusnya.
    -+</p>
    -+        <p>Jika Anda memutuskan bahwa sumber daya gambar tidak terlihat cukup baik di televisi
    -+atau perangkat tertentu lainnya dan ingin mencoba sumber daya tvdpi, faktor skalanya adalah 1,33*mdpi. Misalnya,
    -+gambar 100px x 100px untuk layar mdpi harus 133px x 133px untuk tvdpi.</p>
    -+        <p class="note"><strong>Catatan:</strong> Menggunakan qualifier densitas tidak berarti bahwa
    -+sumber daya <em>hanya</em> untuk layar dengan ukuran itu saja. Jika Anda tidak menyediakan sumber
    -+daya alternatif dengan qualifier yang lebih cocok dengan konfigurasi perangkat saat ini, sistem dapat menggunakan sumber daya
    -+mana saja yang <a href="#BestMatch">paling cocok</a>.</p>
    -+        <p>Lihat <a href="{@docRoot}guide/practices/screens_support.html">Mendukung Beberapa
    -+Layar</a> untuk informasi selengkapnya tentang cara menangani densitas layar yang berbeda dan cara Android
    -+menurunkan skala bitmap Anda agar sesuai dengan densitas saat ini.</p>
    -+       </td>
    -+    </tr>
    -+    <tr id="TouchscreenQualifier">
    -+      <td>Tipe layar sentuh</td>
    -+      <td>
    -+        <code>notouch</code><br/>
    -+        <code>finger</code>
    -+      </td>
    -+      <td>
    -+        <ul class="nolist">
    -+          <li>{@code notouch}: Perangkat tidak memiliki layar sentuh.</li>
    -+          <li>{@code finger}: Perangkat memiliki layar sentuh yang dimaksudkan untuk
    -+digunakan melalui interaksi dengan jari pengguna.</li>
    -+        </ul>
    -+        <p>Lihat juga bidang konfigurasi {@link android.content.res.Configuration#touchscreen}, yang
    -+menunjukkan tipe layar sentuh pada perangkat.</p>
    -+      </td>
    -+    </tr>
    -+    <tr id="KeyboardAvailQualifier">
    -+      <td>Ketersediaan keyboard</td>
    -+      <td>
    -+        <code>keysexposed</code><br/>
    -+        <code>keyshidden</code><br/>
    -+        <code>keyssoft</code>
    -+      </td>
    -+      <td>
    -+        <ul class="nolist">
    -+          <li>{@code keysexposed}: Perangkat menyediakan keyboard. Jika perangkat mengaktifkan
    -+keyboard perangkat lunak (kemungkinan), ini dapat digunakan bahkan saat keyboard fisik
    -+<em>tidak</em> diekspos kepada pengguna, meskipun perangkat tidak memiliki keyboard fisik. Jika keyboard
    -+perangkat lunak tidak disediakan atau dinonaktifkan, maka ini hanya digunakan bila
    -+keyboard fisik diekspos.</li>
    -+          <li>{@code keyshidden}: Perangkat memiliki keyboard fisik yang tersedia
    -+tetapi tersembunyi <em>dan</em> perangkat <em>tidak</em> mengaktifkan keyboard perangkat lunak.</li>
    -+          <li>{@code keyssoft}: Perangkat mengaktifkan keyboard perangkat lunak,
    -+baik itu terlihat maupun tidak.</li>
    -+        </ul>
    -+        <p>Jika Anda menyediakan sumber daya <code>keysexposed</code>, namun bukan sumber daya <code>keyssoft</code>
    -+, sistem akan menggunakan sumber daya <code>keysexposed</code> baik keyboard
    -+terlihat atau tidak, asalkan sistem telah mengaktifkan keyboard perangkat lunak.</p>
    -+        <p>Ini bisa berubah selama masa pakai aplikasi jika pengguna membuka keyboard
    -+fisik. Lihat <a href="runtime-changes.html">Menangani Perubahan Runtime</a> untuk informasi tentang bagaimana
    -+hal ini memengaruhi aplikasi Anda selama runtime.</p>
    -+        <p>Lihat juga bidang konfigurasi {@link
    -+android.content.res.Configuration#hardKeyboardHidden} dan {@link
    -+android.content.res.Configuration#keyboardHidden}, yang menunjukkan visibilitas
    -+keyboard fisik dan visibilitas segala jenis keyboard (termasuk keyboard perangkat lunak), masing-masing.</p>
    -+      </td>
    -+    </tr>
    -+    <tr id="ImeQualifier">
    -+      <td>Metode input teks utama</td>
    -+      <td>
    -+        <code>nokeys</code><br/>
    -+        <code>qwerty</code><br/>
    -+        <code>12key</code>
    -+      </td>
    -+      <td>
    -+        <ul class="nolist">
    -+          <li>{@code nokeys}: Perangkat tidak memiliki tombol fisik untuk input teks.</li>
    -+          <li>{@code qwerty}: Perangkat memiliki keyboard fisik qwerty, baik terlihat maupun tidak pada
    -+pengguna
    -+.</li>
    -+          <li>{@code 12key}: Perangkat memiliki keyboard fisik 12 tombol, baik terlihat maupun tidak
    -+pada pengguna.</li>
    -+        </ul>
    -+        <p>Lihat juga bidang konfigurasi {@link android.content.res.Configuration#keyboard},
    -+yang menunjukkan metode utama input teks yang tersedia.</p>
    -+      </td>
    -+    </tr>
    -+    <tr id="NavAvailQualifier">
    -+      <td>Ketersediaan tombol navigasi</td>
    -+      <td>
    -+        <code>navexposed</code><br/>
    -+        <code>navhidden</code>
    -+      </td>
    -+      <td>
    -+        <ul class="nolist">
    -+          <li>{@code navexposed}: Tombol navigasi tersedia bagi pengguna.</li>
    -+          <li>{@code navhidden}: Tombol navigasi tidak tersedia (misalnya di balik penutup yang
    -+ditutup).</li>
    -+        </ul>
    -+        <p>Ini bisa berubah selama masa pakai aplikasi jika pengguna menyingkap tombol
    -+navigasi. Lihat <a href="runtime-changes.html">Menangani Perubahan Runtime</a> untuk
    -+informasi tentang bagaimana hal ini memengaruhi aplikasi Anda selama runtime.</p>
    -+        <p>Lihat juga bidang konfigurasi {@link android.content.res.Configuration#navigationHidden}, yang menunjukkan
    -+apakah tombol navigasi disembunyikan.</p>
    -+      </td>
    -+    </tr>
    -+    <tr id="NavigationQualifier">
    -+      <td>Metode navigasi non-sentuh utama</td>
    -+      <td>
    -+        <code>nonav</code><br/>
    -+        <code>dpad</code><br/>
    -+        <code>trackball</code><br/>
    -+        <code>wheel</code>
    -+      </td>
    -+      <td>
    -+        <ul class="nolist">
    -+          <li>{@code nonav}: Perangkat tidak memiliki fasilitas navigasi selain menggunakan
    -+layar sentuh.</li>
    -+          <li>{@code dpad}: Perangkat memiliki pad pengarah (directional pad / d-pad) untuk navigasi.</li>
    -+          <li>{@code trackball}: Perangkat memiliki trackball untuk navigasi.</li>
    -+          <li>{@code wheel}: Perangkat memiliki roda pengarah (directional wheel) untuk navigasi (tidak umum).</li>
    -+        </ul>
    -+        <p>Lihat juga bidang konfigurasi {@link android.content.res.Configuration#navigation},
    -+yang menunjukkan tipe metode navigasi yang tersedia.</p>
    -+      </td>
    -+    </tr>
    -+<!-- DEPRECATED
    -+    <tr>
    -+      <td>Screen dimensions</td>
    -+      <td>Examples:<br/>
    -+        <code>320x240</code><br/>
    -+        <code>640x480</code><br/>
    -+        etc.
    -+      </td>
    -+      <td>
    -+        <p>The larger dimension must be specified first. <strong>This configuration is deprecated
    -+and should not be used</strong>. Instead use "screen size," "wider/taller screens," and "screen
    -+orientation" described above.</p>
    -+      </td>
    -+    </tr>
    -+-->
    -+    <tr id="VersionQualifier">
    -+      <td>Versi Platform (level API)</td>
    -+      <td>Contoh:<br/>
    -+        <code>v3</code><br/>
    -+        <code>v4</code><br/>
    -+        <code>v7</code><br/>
    -+        dll.</td>
    -+      <td>
    -+        <p>Level API yang didukung perangkat. Misalnya, <code>v1</code> untuk API level
    -+1 (perangkat dengan Android 1.0 atau yang lebih tinggi) dan <code>v4</code> untuk API level 4 (perangkat dengan Android
    -+1.6 atau yang lebih tinggi). Lihat dokumen <a href="{@docRoot}guide/topics/manifest/uses-sdk-element.html#ApiLevels">Level API Android</a> untuk informasi selengkapnya
    -+tentang nilai-nilai ini.</p>
    -+      </td>
    -+    </tr>
    -+</table>
    -+
    -+
    -+<p class="note"><strong>Catatan:</strong> Sebagian qualifier konfigurasi telah ditambahkan sejak Android
    -+1.0, jadi tidak semua versi Android mendukung semua qualifier. Menggunakan qualifier baru secara implisit
    -+akan menambahkan qualifier versi platform sehingga perangkat yang lebih lama pasti mengabaikannya. Misalnya, menggunakan qualifier
    -+<code>w600dp</code> secara otomatis akan menyertakan qualifier <code>v13</code>, karena
    -+qualifier lebar yang tersedia baru di API level 13. Untuk menghindari masalah, selalu sertakan satu set
    -+sumber daya default (satu set sumber daya <em>tanpa qualifier</em>). Untuk informasi selengkapnya, lihat
    -+bagian tentang <a href="#Compatibility">Menyediakan Kompatibilitas Perangkat Terbaik dengan
    -+Sumber Daya</a>.</p>
    -+
    -+
    -+
    -+<h3 id="QualifierRules">Aturan penamaan qualifier</h3>
    -+
    -+<p>Inilah beberapa aturan tentang penggunaan nama qualifier konfigurasi:</p>
    -+
    -+<ul>
    -+    <li>Anda bisa menetapkan beberapa qualifier untuk satu set sumber daya, yang dipisahkan dengan tanda hubung. Misalnya,
    -+<code>drawable-en-rUS-land</code> berlaku untuk perangkat bahasa Inggris-AS dalam orientasi
    -+lanskap.</li>
    -+    <li>Qualifier harus dalam urutan seperti yang tercantum dalam <a href="#table2">tabel 2</a>.
    -+Misalnya:
    -+      <ul>
    -+        <li>Salah: <code>drawable-hdpi-port/</code></li>
    -+        <li>Benar: <code>drawable-port-hdpi/</code></li>
    -+      </ul>
    -+    </li>
    -+    <li>Direktori sumber daya alternatif tidak bisa digunakan. Misalnya, Anda tidak bisa memiliki
    -+<code>res/drawable/drawable-en/</code>.</li>
    -+    <li>Nilai tidak membedakan huruf besar maupun kecil.  Compiler sumber daya mengubah nama direktori
    -+menjadi huruf kecil sebelum pemrosesan untuk menghindari masalah pada sistem file yang membedakan
    -+huruf kecil dan besar. Setiap penggunaan huruf besar dalam nama hanyalah demi keterbacaan.</li>
    -+    <li>Hanya didukung satu nilai untuk setiap tipe qualifier. Misalnya, jika Anda ingin menggunakan
    -+file drawable yang sama untuk Spanyol dan Prancis, Anda <em>tidak bisa</em> memiliki direktori bernama
    -+<code>drawable-rES-rFR/</code>. Sebagai gantinya, Anda perlu dua direktori sumber daya, seperti
    -+<code>drawable-rES/</code> dan <code>drawable-rFR/</code>, berisi file yang sesuai.
    -+Akan tetapi, Anda tidak harus benar-benar menggandakan file yang sama di kedua lokasi. Sebagai gantinya, Anda
    -+bisa membuat alias ke satu sumber daya. Lihat <a href="#AliasResources">Membuat
    -+sumber daya alias</a> di bawah ini.</li>
    -+</ul>
    -+
    -+<p>Setelah Anda menyimpan sumber daya alternatif ke dalam direktori yang diberi nama dengan
    -+qualifier ini, Android secara otomatis menerapkan sumber daya dalam
    -+aplikasi Anda berdasarkan pada konfigurasi perangkat saat ini. Setiap kali sumber daya diminta, Android akan memeriksa direktori sumber daya
    -+alternatif berisi file sumber daya yang diminta, lalu <a href="#BestMatch">mencari sumber daya yang
    -+paling cocok</a>(dibahas di bawah). Jika tidak ada sumber daya alternatif yang cocok
    -+dengan konfigurasi perangkat tertentu, Android akan menggunakan sumber daya default terkait (set
    -+sumber daya untuk tipe sumber daya tertentu yang tidak termasuk qualifier
    -+konfigurasi).</p>
    -+
    -+
    -+
    -+<h3 id="AliasResources">Membuat sumber daya alias</h3>
    -+
    -+<p>Bila memiliki sumber daya yang ingin Anda gunakan untuk lebih dari satu konfigurasi
    -+perangkat (namun tidak ingin menyediakannya sebagai sumber daya default), Anda tidak perlu menempatkan sumber daya
    -+yang sama di lebih dari satu direktori sumber daya alternatif. Sebagai gantinya, (dalam beberapa kasus) Anda bisa membuat
    -+sumber daya alternatif
    -+yang berfungsi sebagai alias untuk sumber daya yang disimpan dalam direktori sumber daya default.</p>
    -+
    -+<p class="note"><strong>Catatan:</strong> Tidak semua sumber daya menawarkan mekanisme yang memungkinkan Anda
    -+membuat alias ke sumber daya lain. Khususnya, animasi, menu, raw, dan
    -+sumber daya lain yang tidak ditetapkan dalam direktori {@code xml/} tidak menawarkan fitur ini.</p>
    -+
    -+<p>Misalnya, bayangkan Anda memiliki ikon aplikasi {@code icon.png}, dan membutuhkan versi uniknya
    -+untuk lokal berbeda. Akan tetapi, dua lokal, bahasa Inggris-Kanada dan bahasa Prancis-Kanada, harus menggunakan
    -+versi yang sama. Anda mungkin berasumsi bahwa Anda perlu menyalin gambar
    -+yang sama ke dalam direktori sumber daya baik untuk bahasa Inggris-Kanada maupun bahasa Prancis-Kanada, namun
    -+bukan demikian. Sebagai gantinya, Anda bisa menyimpan gambar yang sama-sama digunakan sebagai {@code icon_ca.png} (nama
    -+apa saja selain {@code icon.png}) dan memasukkannya
    -+dalam direktori default {@code res/drawable/}. Lalu buat file {@code icon.xml} dalam {@code
    -+res/drawable-en-rCA/} dan {@code res/drawable-fr-rCA/} yang mengacu ke sumber daya {@code icon_ca.png}
    -+yang menggunakan elemen {@code &lt;bitmap&gt;}. Hal ini memungkinkan Anda menyimpan satu versi saja dari
    -+file PNG dan dua file XML kecil yang menunjuk ke sana. (Contoh file XML ditampilkan di bawah.)</p>
    -+
    -+
    -+<h4>Drawable</h4>
    -+
    -+<p>Untuk membuat alias ke drawable yang ada, gunakan elemen {@code &lt;bitmap&gt;}.
    -+Misalnya:</p>
    -+
    -+<pre>
    -+&lt;?xml version="1.0" encoding="utf-8"?>
    -+&lt;bitmap xmlns:android="http://schemas.android.com/apk/res/android"
    -+    android:src="@drawable/icon_ca" />
    -+</pre>
    -+
    -+<p>Jika Anda menyimpan file ini sebagai {@code icon.xml} (dalam direktori sumber daya alternatif, seperti
    -+{@code res/drawable-en-rCA/}), maka file akan dikompilasi menjadi sumber daya yang dapat Anda acu
    -+sebagai {@code R.drawable.icon}, namun sebenarnya merupakan alias untuk sumber daya {@code
    -+R.drawable.icon_ca} (yang disimpan dalam {@code res/drawable/}).</p>
    -+
    -+
    -+<h4>Layout</h4>
    -+
    -+<p>Untuk membuat alias ke layout yang ada, gunakan elemen {@code &lt;include&gt;},
    -+yang dibungkus dalam {@code &lt;merge&gt;}. Misalnya:</p>
    -+
    -+<pre>
    -+&lt;?xml version="1.0" encoding="utf-8"?>
    -+&lt;merge>
    -+    &lt;include layout="@layout/main_ltr"/>
    -+&lt;/merge>
    -+</pre>
    -+
    -+<p>Jika Anda menyimpan file ini sebagai {@code main.xml}, file akan dikompilasi menjadi sumber daya yang dapat Anda acu
    -+sebagai {@code R.layout.main}, namun sebenarnya merupakan alias untuk sumber daya {@code R.layout.main_ltr}
    -+.</p>
    -+
    -+
    -+<h4>String dan nilai-nilai sederhana lainnya</h4>
    -+
    -+<p>Untuk membuat alias ke string yang ada, cukup gunakan ID sumber daya
    -+dari string yang diinginkan sebagai nilai untuk string baru. Misalnya:</p>
    -+
    -+<pre>
    -+&lt;?xml version="1.0" encoding="utf-8"?>
    -+&lt;resources>
    -+    &lt;string name="hello">Hello&lt;/string>
    -+    &lt;string name="hi">@string/hello&lt;/string>
    -+&lt;/resources>
    -+</pre>
    -+
    -+<p>Sumber daya {@code R.string.hi} sekarang merupakan alias untuk {@code R.string.hello}.</p>
    -+
    -+<p> <a href="{@docRoot}guide/topics/resources/more-resources.html">Nilai sederhana lainnya</a> sama
    -+cara kerjanya. Misalnya, sebuah warna:</p>
    -+
    -+<pre>
    -+&lt;?xml version="1.0" encoding="utf-8"?>
    -+&lt;resources>
    -+    &lt;color name="yellow">#f00&lt;/color>
    -+    &lt;color name="highlight">@color/red&lt;/color>
    -+&lt;/resources>
    -+</pre>
    -+
    -+
    -+
    -+
    -+<h2 id="Compatibility">Menyediakan Kompatibilitas Perangkat Terbaik dengan Sumber Daya</h2>
    -+
    -+<p>Agar aplikasi Anda mendukung beberapa konfigurasi perangkat,
    -+Anda harus selalu menyediakan sumber daya default untuk setiap tipe sumber daya yang menggunakan aplikasi Anda.</p>
    -+
    -+<p>Misalnya, jika aplikasi Anda mendukung beberapa bahasa, sertakan selalu direktori {@code
    -+values/} (tempat string Anda disimpan) <em>tanpa</em> <a href="#LocaleQualifier">qualifier bahasa dan wilayah</a>. Jika sebaliknya Anda menempatkan semua file
    -+string dalam direktori yang memiliki qualifier bahasa dan wilayah, maka aplikasi Anda akan crash saat berjalan
    -+pada perangkat yang telah diatur ke bahasa yang tidak didukung string Anda. Namun asalkan Anda menyediakan sumber daya default
    -+{@code values/}, aplikasi akan berjalan lancar (meskipun pengguna
    -+tidak memahami bahasa itu&mdash;, ini lebih baik daripada crash).</p>
    -+
    -+<p>Demikian pula, jika Anda menyediakan sumber daya layout berbeda berdasarkan orientasi layar, Anda harus
    -+memilih satu orientasi sebagai default. Misalnya, sebagai ganti menyediakan sumber daya dalam {@code
    -+layout-land/} untuk lanskap dan {@code layout-port/} untuk potret, biarkan salah satu sebagai default, seperti
    -+{@code layout/} untuk lanskap dan {@code layout-port/} untuk potret.</p>
    -+
    -+<p>Sumber daya default perlu disediakan bukan hanya karena aplikasi mungkin berjalan pada
    -+konfigurasi yang belum Anda antisipasi, namun juga karena versi baru Android terkadang menambahkan
    -+qualifier konfigurasi yang tidak didukung oleh versi lama. Jika Anda menggunakan qualifier sumber daya baru,
    -+namun mempertahankan kompatibilitas kode dengan versi Android yang lebih lama, maka saat versi lama
    -+Android menjalankan aplikasi, aplikasi itu akan crash jika Anda tidak menyediakan sumber daya default, aplikasi
    -+tidak bisa menggunakan sumber daya yang dinamai dengan qualifier baru. Misalnya, jika <a href="{@docRoot}guide/topics/manifest/uses-sdk-element.html#min">{@code
    -+minSdkVersion}</a> Anda diatur ke 4, dan Anda memenuhi syarat semua sumber daya drawable dengan menggunakan <a href="#NightQualifier">mode malam</a> ({@code night} atau {@code notnight}, yang ditambahkan di API
    -+Level 8), maka perangkat API level 4 tidak bisa mengakses sumber daya drawable dan akan crash. Dalam hal
    -+ini, Anda mungkin ingin {@code notnight} menjadi sumber daya default, jadi Anda harus mengecualikan
    -+qualifier itu agar sumber daya drawable Anda ada dalam {@code drawable/} atau {@code drawable-night/}.</p>
    -+
    -+<p>Jadi, agar bisa menyediakan kompatibilitas perangkat terbaik, sediakan selalu sumber daya
    -+default untuk sumber daya yang diperlukan aplikasi Anda untuk berjalan dengan benar. Selanjutnya buatlah sumber daya
    -+alternatif untuk konfigurasi perangkat tertentu dengan menggunakan qualifier konfigurasi.</p>
    -+
    -+<p>Ada satu eksepsi untuk aturan ini: Jika <a href="{@docRoot}guide/topics/manifest/uses-sdk-element.html#min">{@code minSdkVersion}</a> aplikasi Anda adalah 4 atau
    -+lebih, Anda <em>tidak</em> memerlukan sumber daya drawable default saat menyediakan sumber daya
    -+drawable alternatif dengan qualifier <a href="#DensityQualifier">densitas layar</a>. Tanpa sumber daya
    -+drawable default sekali pun, Android bisa menemukan yang paling cocok di antara densitas layar alternatif dan menskalakan
    -+bitmap sesuai kebutuhan. Akan tetapi, demi pengalaman terbaik pada semua jenis perangkat, Anda harus
    -+menyediakan drawable alternatif untuk ketiga tipe densitas.</p>
    -+
    -+
    -+
    -+<h2 id="BestMatch">Cara Android Menemukan Sumber Daya yang Paling Cocok</h2>
    -+
    -+<p>Saat Anda meminta sumber daya yang Anda berikan alternatifnya, Android akan memilih
    -+sumber daya alternatif yang akan digunakan saat runtime, bergantung pada konfigurasi perangkat saat ini. Untuk
    -+mendemonstrasikan cara Android memilih sumber daya alternatif, anggaplah direktori drawable berikut
    -+masing-masing berisi versi berbeda dari gambar yang sama:</p>
    -+
    -+<pre class="classic no-pretty-print">
    -+drawable/
    -+drawable-en/
    -+drawable-fr-rCA/
    -+drawable-en-port/
    -+drawable-en-notouch-12key/
    -+drawable-port-ldpi/
    -+drawable-port-notouch-12key/
    -+</pre>
    -+
    -+<p>Dan anggaplah yang berikut ini merupakan konfigurasi perangkatnya:</p>
    -+
    -+<p style="margin-left:1em;">
    -+Lokal = <code>en-GB</code> <br/>
    -+Orientasi layar = <code>port</code> <br/>
    -+Densitas piksel layar = <code>hdpi</code> <br/>
    -+Tipe layar sentuh = <code>notouch</code> <br/>
    -+Metode input teks utama = <code>12key</code>
    -+</p>
    -+
    -+<p>Dengan membandingkan konfigurasi perangkat dengan sumber daya alternatif yang tersedia, Android akan memilih
    -+drawable dari {@code drawable-en-port}.</p>
    -+
    -+<p>Sistem akan menentukan keputusannya mengenai sumber daya yang akan digunakan dengan logika
    -+berikut:</p>
    -+
    -+
    -+<div class="figure" style="width:371px">
    -+<img src="{@docRoot}images/resources/res-selection-flowchart.png" alt="" height="471" />
    -+<p class="img-caption"><strong>Gambar 2.</strong> Bagan alur cara Android menemukan
    -+sumber daya yang paling cocok.</p>
    -+</div>
    -+
    -+
    -+<ol>
    -+  <li>Menghapus file sumber daya yang bertentangan dengan konfigurasi perangkat.
    -+    <p>Direktori <code>drawable-fr-rCA/</code> dihapus karena bertentangan
    -+dengan lokal <code>en-GB</code>.</p>
    -+<pre class="classic no-pretty-print">
    -+drawable/
    -+drawable-en/
    -+<strike>drawable-fr-rCA/</strike>
    -+drawable-en-port/
    -+drawable-en-notouch-12key/
    -+drawable-port-ldpi/
    -+drawable-port-notouch-12key/
    -+</pre>
    -+<p class="note"><strong>Eksepsi:</strong> Densitas piksel layar adalah satu qualifier yang
    -+tidak dihapus karena bertentangan. Meskipun densitas layar perangkat adalah hdpi,
    -+<code>drawable-port-ldpi/</code> tidak dihapus karena setiap densitas layar
    -+dianggap cocok untuk saat ini. Informasi selengkapnya tersedia dalam dokumen <a href="{@docRoot}guide/practices/screens_support.html">Mendukung Beberapa
    -+Layar</a>.</p></li>
    -+
    -+  <li>Pilih qualifier berkedudukan tertinggi (berikutnya) dalam daftar (<a href="#table2">tabel 2</a>).
    -+(Mulai dengan MCC, lalu pindah ke bawah.) </li>
    -+  <li>Apakah salah satu direktori sumber daya menyertakan qualifier ini?  </li>
    -+    <ul>
    -+      <li>Jika Tidak, kembali ke langkah 2 dan lihat qualifier berikutnya. (Dalam contoh,
    -+jawabannya adalah "tidak" hingga qualifier bahasa tercapai.)</li>
    -+      <li>Jika Ya, lanjutkan ke langkah 4.</li>
    -+    </ul>
    -+  </li>
    -+
    -+  <li>Hapus direktori sumber daya yang tidak menyertakan qualifier ini. Dalam contoh, sistem
    -+menghapus semua direktori yang tidak menyertakan qualifier bahasa:</li>
    -+<pre class="classic no-pretty-print">
    -+<strike>drawable/</strike>
    -+drawable-en/
    -+drawable-en-port/
    -+drawable-en-notouch-12key/
    -+<strike>drawable-port-ldpi/</strike>
    -+<strike>drawable-port-notouch-12key/</strike>
    -+</pre>
    -+<p class="note"><strong>Eksepsi:</strong> Jika qualifier yang dimaksud adalah densitas piksel layar,
    -+Android akan memilih opsi yang paling cocok dengan densitas layar perangkat.
    -+Secara umum, Android lebih suka menurunkan skala gambar asli yang lebih besar daripada menaikkan skala
    -+atas gambar asli yang lebih kecil. Lihat <a href="{@docRoot}guide/practices/screens_support.html">Mendukung Beberapa
    -+Layar</a>.</p>
    -+  </li>
    -+
    -+  <li>Kembali dan ulangi langkah 2, 3, dan 4 hingga tersisa satu direktori. Dalam contoh ini, orientasi
    -+layar adalah qualifier berikutnya yang memiliki kecocokan.
    -+Jadi, sumber daya yang tidak menetapkan orientasi layar akan dihapus:
    -+<pre class="classic no-pretty-print">
    -+<strike>drawable-en/</strike>
    -+drawable-en-port/
    -+<strike>drawable-en-notouch-12key/</strike>
    -+</pre>
    -+<p>Direktori yang tersisa adalah {@code drawable-en-port}.</p>
    -+  </li>
    -+</ol>
    -+
    -+<p>Meskipun prosedur dijalankan untuk setiap sumber daya yang diminta, sistem akan mengoptimalkan beberapa aspek
    -+lebih lanjut. Satu optimalisasi tersebut adalah bahwa setelah konfigurasi perangkat diketahui, sistem mungkin
    -+akan menghapus sumber daya alternatif yang sama sekali tidak cocok. Misalnya, jika bahasa konfigurasi
    -+adalah bahasa Inggris ("en"), maka setiap direktori sumber daya yang memiliki qualifier bahasa akan diatur ke
    -+selain bahasa Inggris tidak akan pernah disertakan dalam pool sumber daya yang diperiksa (meskipun
    -+direktori sumber daya <em>tanpa</em> qualifier bahasa masih disertakan).</p>
    -+
    -+<p>Saat memilih sumber daya berdasarkan qualifier ukuran layar, sistem akan menggunakan
    -+sumber daya yang didesain untuk layar yang lebih kecil daripada layar saat ini jika tidak ada sumber daya yang lebih cocok
    -+(misalnya, layar ukuran besar akan menggunakan sumber daya layar ukuran normal jika diperlukan). Akan tetapi,
    -+jika satu-satunya sumber daya yang tersedia <em>lebih besar</em> daripada layar saat ini, sistem
    -+<strong>tidak</strong> akan menggunakannya dan aplikasi Anda akan crash jika tidak ada sumber daya lain yang cocok dengan konfigurasi
    -+perangkat (misalnya, jika semua sumber daya layout ditandai dengan qualifier {@code xlarge},
    -+namun perangkat memiliki ukuran layar normal).</p>
    -+
    -+<p class="note"><strong>Catatan:</strong> <em>Kedudukan</em> qualifier (dalam <a href="#table2">tabel 2</a>) lebih penting
    -+daripada jumlah qualifier yang benar-benar pas dengan perangkat. Misalnya, dalam langkah 4 di atas, pilihan
    -+terakhir pada daftar berisi tiga qualifier yang bebar-benar cocok dengan perangkat (orientasi, tipe
    -+layar sentuh, dan metode input), sementara <code>drawable-en</code> hanya memiliki satu parameter yang cocok
    -+(bahasa). Akan tetapi, bahasa memiliki kedudukan lebih tinggi dari pada qualifier lainnya, sehingga
    -+<code>drawable-port-notouch-12key</code> tidak masuk.</p>
    -+
    -+<p>Untuk mengetahui selengkapnya tentang cara menggunakan sumber daya dalam aplikasi, lanjutkan ke <a href="accessing-resources.html">Mengakses Sumber Daya</a>.</p>
    -diff --git a/docs/html-intl/intl/id/guide/topics/resources/runtime-changes.jd b/docs/html-intl/intl/id/guide/topics/resources/runtime-changes.jd
    -new file mode 100644
    -index 0000000..09ad60c
    ---- /dev/null
    -+++ b/docs/html-intl/intl/id/guide/topics/resources/runtime-changes.jd
    -@@ -0,0 +1,281 @@
    -+page.title=Menangani Perubahan Runtime
    -+page.tags=aktivitas,daur hidup
    -+@jd:body
    -+
    -+<div id="qv-wrapper">
    -+<div id="qv">
    -+
    -+  <h2>Dalam dokumen ini</h2>
    -+  <ol>
    -+    <li><a href="#RetainingAnObject">Mempertahankan Objek Selama Perubahan Konfigurasi</a></li>
    -+    <li><a href="#HandlingTheChange">Menangani Sendiri Perubahan Konfigurasi</a>
    -+  </ol>
    -+
    -+  <h2>Lihat juga</h2>
    -+  <ol>
    -+    <li><a href="providing-resources.html">Menyediakan Sumber Daya</a></li>
    -+    <li><a href="accessing-resources.html">Mengakses Sumber Daya</a></li>
    -+    <li><a href="http://android-developers.blogspot.com/2009/02/faster-screen-orientation-change.html">Perubahan
    -+ Orientasi Layar yang Lebih Cepat</a></li>
    -+  </ol>
    -+</div>
    -+</div>
    -+
    -+<p>Sebagian konfigurasi perangkat bisa berubah selama runtime
    -+(seperti orientasi layar, ketersediaan keyboard, dan bahasa). Saat perubahan demikian terjadi,
    -+Android akan me-restart
    -+{@link android.app.Activity} yang berjalan ({@link android.app.Activity#onDestroy()} dipanggil, diikuti oleh {@link
    -+android.app.Activity#onCreate(Bundle) onCreate()}). Perilaku restart didesain untuk membantu
    -+aplikasi Anda beradaptasi dengan konfigurasi baru melalui pemuatan kembali aplikasi Anda secara otomatis dengan
    -+sumber daya alternatif sumber yang sesuai dengan konfigurasi perangkat baru.</p>
    -+
    -+<p>Untuk menangani restart dengan benar, aktivitas Anda harus mengembalikan
    -+statusnya seperti semula melalui <a href="{@docRoot}guide/components/activities.html#Lifecycle">Daur hidup
    -+aktivitas</a> normal, dalam hal ini Android akan memanggil
    -+{@link android.app.Activity#onSaveInstanceState(Bundle) onSaveInstanceState()} sebelum menghentikan
    -+aktivitas Anda sehingga Anda dapat menyimpan data mengenai status aplikasi. Selanjutnya Anda bisa mengembalikan status
    -+selama {@link android.app.Activity#onCreate(Bundle) onCreate()} atau {@link
    -+android.app.Activity#onRestoreInstanceState(Bundle) onRestoreInstanceState()}.</p>
    -+
    -+<p>Untuk menguji bahwa aplikasi me-restart sendiri dengan status tak berubah, Anda harus
    -+memanggil perubahan konfigurasi (seperti mengubah orientasi layar) saat melakukan berbagai
    -+tugas dalam aplikasi. Aplikasi Anda harus dapat me-restart setiap saat tanpa kehilangan
    -+data pengguna atau status untuk menangani kejadian seperti perubahan konfigurasi atau bila pengguna menerima panggilan telepon
    -+masuk lalu kembali ke aplikasi setelah proses
    -+aplikasi Anda dimusnahkan. Untuk mengetahui cara mengembalikan status aktivitas, bacalah tentang <a href="{@docRoot}guide/components/activities.html#Lifecycle">Daur hidup aktivitas</a>.</p>
    -+
    -+<p>Akan tetapi, Anda mungkin menemui situasi ketika me-restart aplikasi dan
    -+mengembalikan data dalam jumlah besar malah menjadi mahal dan menghasilkan pengalaman pengguna yang buruk. Dalam situasi
    -+demikian, Anda memiliki dua opsi lain:</p>
    -+
    -+<ol type="a">
    -+  <li><a href="#RetainingAnObject">Mempertahankan objek selama perubahan konfigurasi</a>
    -+  <p>Izinkan aktivitas Anda me-restart saat konfigurasi berubah, namun bawa objek
    -+berstatus (stateful) ke instance baru aktivitas Anda.</p>
    -+
    -+  </li>
    -+  <li><a href="#HandlingTheChange">Menangani sendiri perubahan konfigurasi</a>
    -+  <p>Cegah sistem me-restart aktivitas selama perubahan konfigurasi
    -+tertentu, namun terima callback saat konfigurasi benar-benar berubah, agar Anda bisa memperbarui
    -+aktivitas secara manual bila diperlukan.</p>
    -+  </li>
    -+</ol>
    -+
    -+
    -+<h2 id="RetainingAnObject">Mempertahankan Objek Selama Perubahan Konfigurasi</h2>
    -+
    -+<p>Jika me-restart aktivitas mengharuskan pemulihan seperangkat data dalam jumlah besar, menghubungkan kembali koneksi
    -+jaringan, atau melakukan operasi intensif lainnya, maka restart penuh karena perubahan konfigurasi mungkin
    -+menjadi pengalaman pengguna yang lambat. Selain itu, Anda mungkin tidak bisa sepenuhnya mengembalikan status
    -+aktivitas dengan {@link android.os.Bundle} yang disimpan sistem untuk Anda dengan callback {@link
    -+android.app.Activity#onSaveInstanceState(Bundle) onSaveInstanceState()}&mdash;itu tidaklah
    -+didesain untuk membawa objek besar (seperti bitmap) dan data di dalamnya harus diserialkan kemudian
    -+dinon-serialkan, yang bisa menghabiskan banyak memori dan membuat perubahan konfigurasi menjadi lambat. Dalam situasi
    -+demikian, Anda bisa meringankan beban memulai kembali aktivitas Anda dengan mempertahankan {@link
    -+android.app.Fragment} saat aktivitas Anda di-restart karena perubahan konfigurasi. Fragmen ini
    -+bisa berisi acuan ke objek stateful yang ingin Anda pertahankan.</p>
    -+
    -+<p>Bila sistem Android menghentikan aktivitas Anda karena perubahan konfigurasi, fragmen
    -+aktivitas yang telah ditandai untuk dipertahankan tidak akan dimusnahkan. Anda dapat menambahkan fragmen tersebut ke
    -+aktivitas untuk mempertahankan objek stateful.</p>
    -+
    -+<p>Untuk mempertahankan objek stateful dalam fragmen selama perubahan konfigurasi runtime:</p>
    -+
    -+<ol>
    -+  <li>Perluas kelas {@link android.app.Fragment} dan deklarasikan referensi ke objek stateful
    -+Anda.</li>
    -+  <li>Panggil {@link android.app.Fragment#setRetainInstance(boolean)} saat fragmen dibuat.
    -+      </li>
    -+  <li>Tambahkan fragmen ke aktivitas.</li>
    -+  <li>Gunakan {@link android.app.FragmentManager} untuk mengambil fragmen saat aktivitas
    -+di-restart.</li>
    -+</ol>
    -+
    -+<p>Misalnya, definisikan fragmen sebagai berikut:</p>
    -+
    -+<pre>
    -+public class RetainedFragment extends Fragment {
    -+
    -+    // data object we want to retain
    -+    private MyDataObject data;
    -+
    -+    // this method is only called once for this fragment
    -+    &#64;Override
    -+    public void onCreate(Bundle savedInstanceState) {
    -+        super.onCreate(savedInstanceState);
    -+        // retain this fragment
    -+        setRetainInstance(true);
    -+    }
    -+
    -+    public void setData(MyDataObject data) {
    -+        this.data = data;
    -+    }
    -+
    -+    public MyDataObject getData() {
    -+        return data;
    -+    }
    -+}
    -+</pre>
    -+
    -+<p class="caution"><strong>Perhatian:</strong> Meskipun bisa menyimpan objek apa saja, Anda
    -+sama sekali tidak boleh meneruskan objek yang terkait dengan {@link android.app.Activity}, seperti {@link
    -+android.graphics.drawable.Drawable}, {@link android.widget.Adapter}, {@link android.view.View}
    -+atau objek lainnya mana pun yang terkait dengan {@link android.content.Context}. Jika Anda melakukannya, hal tersebut akan
    -+membocorkan semua tampilan dan sumber daya instance aktivitas semula. (Sumber daya yang bocor
    -+berarti bahwa aplikasi Anda tetap menyimpannya dan tidak bisa dijadikan kumpulan sampah, sehingga bisa banyak
    -+memori yang hilang.)</p>
    -+
    -+<p>Selanjutnya gunakan {@link android.app.FragmentManager} untuk menambahkan fragmen ke aktivitas.
    -+Anda bisa memperoleh objek data dari fragmen saat aktivitas memulai kembali selama perubahan
    -+konfigurasi runtime. Misalnya, definisikan aktivitas Anda sebagai berikut:</p>
    -+
    -+<pre>
    -+public class MyActivity extends Activity {
    -+
    -+    private RetainedFragment dataFragment;
    -+
    -+    &#64;Override
    -+    public void onCreate(Bundle savedInstanceState) {
    -+        super.onCreate(savedInstanceState);
    -+        setContentView(R.layout.main);
    -+
    -+        // find the retained fragment on activity restarts
    -+        FragmentManager fm = getFragmentManager();
    -+        dataFragment = (DataFragment) fm.findFragmentByTag(“data”);
    -+
    -+        // create the fragment and data the first time
    -+        if (dataFragment == null) {
    -+            // add the fragment
    -+            dataFragment = new DataFragment();
    -+            fm.beginTransaction().add(dataFragment, “data”).commit();
    -+            // load the data from the web
    -+            dataFragment.setData(loadMyData());
    -+        }
    -+
    -+        // the data is available in dataFragment.getData()
    -+        ...
    -+    }
    -+
    -+    &#64;Override
    -+    public void onDestroy() {
    -+        super.onDestroy();
    -+        // store the data in the fragment
    -+        dataFragment.setData(collectMyLoadedData());
    -+    }
    -+}
    -+</pre>
    -+
    -+<p>Dalam contoh ini, {@link android.app.Activity#onCreate(Bundle) onCreate()} menambahkan fragmen
    -+atau mengembalikan referensinya. {@link android.app.Activity#onCreate(Bundle) onCreate()} juga
    -+menyimpan objek stateful dalam instance fragmen.
    -+{@link android.app.Activity#onDestroy() onDestroy()} akan memperbarui objek stateful dalam
    -+instance fragmen yang dipertahankan.</p>
    -+
    -+
    -+
    -+
    -+
    -+<h2 id="HandlingTheChange">Menangani Sendiri Perubahan Konfigurasi</h2>
    -+
    -+<p>Jika aplikasi Anda tidak memerlukan pembaruan sumber daya selama perubahan konfigurasi
    -+tertentu <em>dan</em> Anda memiliki keterbatasan kinerja yang mengharuskan Anda untuk
    -+menghindari restart aktivitas, maka Anda bisa mendeklarasikan agar aktivitas Anda menangani sendiri perubahan
    -+konfigurasinya, sehingga mencegah sistem me-restart aktivitas.</p>
    -+
    -+<p class="note"><strong>Catatan:</strong> Menangani sendiri perubahan konfigurasi bisa jauh lebih
    -+mempersulit penggunaan sumber daya alternatif, karena sistem tidak menerapkannya secara otomatis
    -+untuk Anda. Teknik ini harus dianggap sebagai usaha terakhir bila Anda harus menghindari restart
    -+karena perubahan konfigurasi dan tidak disarankan untuk sebagian besar aplikasi.</p>
    -+
    -+<p>Untuk mendeklarasikan agar aktivitas Anda menangani perubahan konfigurasi, edit elemen <a href="{@docRoot}guide/topics/manifest/activity-element.html">{@code &lt;activity&gt;}</a> yang sesuai
    -+dalam file manifes Anda agar menyertakan atribut <a href="{@docRoot}guide/topics/manifest/activity-element.html#config">{@code
    -+android:configChanges}</a> dengan nilai yang mewakili konfigurasi yang ingin
    -+ditangani. Nilai yang memungkinkan tercantum dalam dokumentasi untuk atribut <a href="{@docRoot}guide/topics/manifest/activity-element.html#config">{@code
    -+android:configChanges}</a> (nilai paling sering digunakan adalah {@code "orientation"} untuk
    -+mencegah restart saat orientasi layar berubah dan {@code "keyboardHidden"} untuk mencegah
    -+restart saat ketersediaan keyboard berubah).  Anda dapat mendeklarasikan beberapa nilai konfigurasi
    -+dalam atribut dengan memisahkannya menggunakan karakter pipa {@code |}.</p>
    -+
    -+<p>Misalnya, kode manifes berikut menyatakan aktivitas yang menangani
    -+perubahan orientasi layar maupun perubahan ketersediaan keyboard:</p>
    -+
    -+<pre>
    -+&lt;activity android:name=".MyActivity"
    -+          android:configChanges="orientation|keyboardHidden"
    -+          android:label="@string/app_name">
    -+</pre>
    -+
    -+<p>Sekarang, bila salah satu konfigurasi ini berubah, {@code MyActivity} tidak akan me-restart.
    -+Sebagai gantinya, {@code MyActivity} akan menerima panggilan ke {@link
    -+android.app.Activity#onConfigurationChanged(Configuration) onConfigurationChanged()}. Metode ini
    -+meneruskan objek {@link android.content.res.Configuration} yang menetapkan
    -+konfigurasi perangkat baru. Dengan membaca bidang-bidang dalam {@link android.content.res.Configuration},
    -+Anda dapat menentukan konfigurasi baru dan membuat perubahan yang sesuai dengan memperbarui
    -+sumber daya yang digunakan dalam antarmuka. Pada saat
    -+metode ini dipanggil, objek {@link android.content.res.Resources} aktivitas Anda akan diperbarui untuk
    -+mengembalikan sumber daya berdasarkan konfigurasi baru, jadi Anda bisa dengan mudah
    -+me-reset elemen UI tanpa membuat sistem me-restart aktivitas Anda.</p>
    -+
    -+<p class="caution"><strong>Perhatian:</strong> Mulai Android 3.2 (API level 13), <strong>
    -+"ukuran layar" juga berubah</strong> bila perangkat beralih orientasi antara potret
    -+dan lanskap. Jadi jika Anda tidak ingin runtime di-restart karena perubahan orientasi saat mengembangkan
    -+API level 13 atau yang lebih tinggi (sebagaimana dideklarasikan oleh atribut <a href="{@docRoot}guide/topics/manifest/uses-sdk-element.html#min">{@code minSdkVersion}</a> dan <a href="{@docRoot}guide/topics/manifest/uses-sdk-element.html#target">{@code targetSdkVersion}</a>
    -+), Anda harus menyertakan nilai {@code "screenSize"} selain nilai {@code
    -+"orientation"}. Yaitu Anda harus mendeklarasikan {@code
    -+android:configChanges="orientation|screenSize"}. Akan tetapi, jika aplikasi Anda menargetkan API level
    -+12 atau yang lebih rendah, maka aktivitas Anda akan selalu menangani sendiri perubahan konfigurasi ini (perubahan
    -+konfigurasi ini tidak me-restart aktivitas Anda, bahkan saat berjalan pada perangkat Android 3.2 atau yang lebih tinggi).</p>
    -+
    -+<p>Misalnya, implementasi {@link
    -+android.app.Activity#onConfigurationChanged(Configuration) onConfigurationChanged()} berikut akan
    -+memeriksa orientasi perangkat saat ini:</p>
    -+
    -+<pre>
    -+&#64;Override
    -+public void onConfigurationChanged(Configuration newConfig) {
    -+    super.onConfigurationChanged(newConfig);
    -+
    -+    // Checks the orientation of the screen
    -+    if (newConfig.orientation == Configuration.ORIENTATION_LANDSCAPE) {
    -+        Toast.makeText(this, "landscape", Toast.LENGTH_SHORT).show();
    -+    } else if (newConfig.orientation == Configuration.ORIENTATION_PORTRAIT){
    -+        Toast.makeText(this, "portrait", Toast.LENGTH_SHORT).show();
    -+    }
    -+}
    -+</pre>
    -+
    -+<p>Objek {@link android.content.res.Configuration} mewakili semua konfigurasi
    -+saat ini, tidak hanya konfigurasi yang telah berubah. Seringkali Anda tidak perlu memperhatikan dengan persis bagaimana
    -+konfigurasi berubah dan cukup menetapkan kembali semua sumber daya yang memberikan alternatif untuk
    -+konfigurasi sedang ditangani. Misalnya, karena objek {@link
    -+android.content.res.Resources} sekarang diperbarui, Anda dapat me-reset
    -+setiap {@link android.widget.ImageView} dengan {@link android.widget.ImageView#setImageResource(int)
    -+setImageResource()}
    -+dan sumber daya yang sesuai untuk konfigurasi baru yang digunakan (seperti dijelaskan dalam <a href="providing-resources.html#AlternateResources">Menyediakan Sumber Daya</a>).</p>
    -+
    -+<p>Perhatikan bahwa nilai-nilai dari bidang {@link
    -+android.content.res.Configuration} adalah integer yang sesuai dengan konstanta spesifik
    -+dari kelas {@link android.content.res.Configuration}. Untuk dokumentasi tentang konstanta
    -+yang harus digunakan di setiap bidang, lihat bidang yang sesuai dalam referensi {@link
    -+android.content.res.Configuration}.</p>
    -+
    -+<p class="note"><strong>Ingatlah:</strong> Saat mendeklarasikan aktivitas untuk menangani perubahan
    -+konfigurasi, Anda bertanggung jawab untuk me-reset setiap elemen yang alternatifnya Anda berikan. Jika Anda
    -+mendeklarasikan aktivitas untuk menangani perubahan orientasi dan memiliki gambar yang harus berubah
    -+antara lanskap dan potret, Anda harus menetapkan kembali setiap sumber daya elemen selama {@link
    -+android.app.Activity#onConfigurationChanged(Configuration) onConfigurationChanged()}.</p>
    -+
    -+<p>Jika Anda tidak perlu memperbarui aplikasi berdasarkan perubahan
    -+konfigurasi ini, sebagai gantinya Anda bisa saja <em>tidak</em> mengimplementasikan {@link
    -+android.app.Activity#onConfigurationChanged(Configuration) onConfigurationChanged()}. Dalam
    -+hal ini, semua sumber daya yang digunakan sebelum perubahan konfigurasi akan tetap digunakan
    -+dan Anda hanya menghindari restart aktivitas. Akan tetapi, aplikasi Anda harus selalu
    -+bisa dimatikan dan di-restart dengan status sebelumnya tetap utuh, sehingga Anda jangan menganggap teknik
    -+ini sebagai jalan keluar untuk mempertahankan status selama daur hidup aktivitas normal. Tidak hanya
    -+karena ada perubahan konfigurasi lainnya yang tidak bisa Anda cegah untuk me-restart aplikasi, namun
    -+juga karena Anda harus menangani kejadian seperti saat pengguna meninggalkan aplikasi dan
    -+dimusnahkan sebelum pengguna kembali ke aplikasi.</p>
    -+
    -+<p>Untuk informasi selengkapnya tentang perubahan konfigurasi yang bisa Anda tangani dalam aktivitas, lihat dokumentasi <a href="{@docRoot}guide/topics/manifest/activity-element.html#config">{@code
    -+android:configChanges}</a> dan kelas {@link android.content.res.Configuration}
    -+.</p>
    -diff --git a/docs/html-intl/intl/id/guide/topics/ui/controls.jd b/docs/html-intl/intl/id/guide/topics/ui/controls.jd
    -new file mode 100644
    -index 0000000..3ebf48b
    ---- /dev/null
    -+++ b/docs/html-intl/intl/id/guide/topics/ui/controls.jd
    -@@ -0,0 +1,90 @@
    -+page.title=Kontrol Input
    -+parent.title=Antarmuka Pengguna
    -+parent.link=index.html
    -+@jd:body
    -+
    -+<div class="figure" style="margin:0">
    -+  <img src="{@docRoot}images/ui/ui-controls.png" alt="" style="margin:0" />
    -+</div>
    -+
    -+<p>Kontrol input adalah komponen interaktif dalam antarmuka pengguna aplikasi Anda. Android menyediakan
    -+aneka ragam kontrol yang bisa Anda gunakan dalam UI, seperti tombol, bidang teks, bilah pencarian,
    -+kotak cek, tombol zoom, tombol toggle, dan masih banyak lagi.</p>
    -+
    -+<p>Menambahkan sebuah kontrol input ke UI adalah semudah menambahkan satu elemen XML ke <a href="{@docRoot}guide/topics/ui/declaring-layout.html">layout XML</a>. Misalnya, inilah sebuah
    -+layout dengan satu bidang teks dan satu tombol:</p>
    -+
    -+<pre style="clear:right">
    -+&lt;?xml version="1.0" encoding="utf-8"?>
    -+&lt;LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    -+    android:layout_width="fill_parent"
    -+    android:layout_height="fill_parent"
    -+    android:orientation="horizontal">
    -+    &lt;EditText android:id="@+id/edit_message"
    -+        android:layout_weight="1"
    -+        android:layout_width="0dp"
    -+        android:layout_height="wrap_content"
    -+        android:hint="@string/edit_message" />
    -+    &lt;Button android:id="@+id/button_send"
    -+        android:layout_width="wrap_content"
    -+        android:layout_height="wrap_content"
    -+        android:text="@string/button_send"
    -+        android:onClick="sendMessage" />
    -+&lt;/LinearLayout>
    -+</pre>
    -+
    -+<p>Tiap kontrol input mendukung satu set kejadian input sehingga Anda bisa menangani berbagai kejadian seperti saat
    -+pengguna memasukkan teks atau menyentuh tombol.</p>
    -+
    -+
    -+<h2 id="CommonControls">Kontrol Umum</h2>
    -+<p>Berikut adalah daftar beberapa kontrol umum yang bisa Anda gunakan dalam aplikasi. Ikuti tautan ini untuk mengetahui
    -+selengkapnya tentang penggunaannya masing-masing.</p>
    -+
    -+<p class="note"><strong>Catatan:</strong> Android menyediakan beberapa kontrol lain yang tidak tercantum
    -+di sini. Telusuri paket {@link android.widget} untuk mengetahui selengkapnya. Jika aplikasi Anda memerlukan
    -+semacam kontrol input tertentu, Anda bisa membangun <a href="{@docRoot}guide/topics/ui/custom-components.html">komponen custom</a> sendiri.</p>
    -+
    -+<table>
    -+    <tr>
    -+        <th scope="col">Tipe Kontrol</th>
    -+        <th scope="col">Keterangan</th>
    -+	<th scope="col">Kelas Terkait</th>
    -+    </tr>
    -+    <tr>
    -+        <td><a href="controls/button.html">Tombol</a></td>
    -+        <td>Tombol tekan yang bisa ditekan, atau diklik, oleh pengguna untuk melakukan suatu tindakan.</td>
    -+	<td>{@link android.widget.Button Button} </td>
    -+    </tr>
    -+    <tr>
    -+        <td><a href="controls/text.html">Bidang teks</a></td>
    -+        <td>Bidang teks yang bisa diedit. Anda bisa menggunakan widget <code>AutoCompleteTextView</code> untuk membuat widget entri teks yang menyediakan saran pelengkapan otomatis</td>
    -+	<td>{@link android.widget.EditText EditText}, {@link android.widget.AutoCompleteTextView}</td>
    -+    </tr>
    -+    <tr>
    -+        <td><a href="controls/checkbox.html">Kotak cek</a></td>
    -+        <td>Switch aktif/nonaktif yang bisa diubah oleh pengguna. Anda harus menggunakan kotak cek saat menampilkan sekumpulan opsi yang bisa dipilih pengguna dan bila keduanya mungkin terjadi bersamaan.</td>
    -+	<td>{@link android.widget.CheckBox CheckBox} </td>
    -+    </tr>
    -+    <tr>
    -+        <td><a href="controls/radiobutton.html">Tombol radio</a></td>
    -+        <td>Mirip dengan kotak cek, hanya saja cuma satu opsi yang bisa dipilih dalam kumpulan tersebut.</td>
    -+	<td>{@link android.widget.RadioGroup RadioGroup}
    -+	<br>{@link android.widget.RadioButton RadioButton} </td>
    -+    </tr>
    -+    <tr>
    -+        <td><a href="controls/togglebutton.html" style="white-space:nowrap">Tombol toggle</a></td>
    -+        <td>Tombol aktif/nonaktif dengan indikator cahaya.</td>
    -+	<td>{@link android.widget.ToggleButton ToggleButton} </td>
    -+    </tr>
    -+    <tr>
    -+        <td><a href="controls/spinner.html">Spinner</a></td>
    -+        <td>Daftar tarik-turun yang memungkinkan pengguna memilih salah satu dari serangkaian nilai.</td>
    -+	<td>{@link android.widget.Spinner Spinner} </td>
    -+    </tr>
    -+    <tr>
    -+        <td><a href="controls/pickers.html">Picker</a></td>
    -+        <td>Dialog bagi pengguna untuk memilih satu nilai dari satu kumpulan dengan menggunakan tombol naik/turun atau dengan gerakan mengusap. Gunakan widget <code>DatePicker</code>code&gt; untuk memasukkan nilai tanggal (bulan, hari, tahun) atau widget <code>TimePicker</code> untuk memasukkan nilai waktu (jam, menit, AM/PM), yang akan diformat secara otomatis untuk lokasi pengguna tersebut.</td>
    -+	<td>{@link android.widget.DatePicker}, {@link android.widget.TimePicker}</td>
    -+    </tr>
    -+</table>
    -diff --git a/docs/html-intl/intl/id/guide/topics/ui/declaring-layout.jd b/docs/html-intl/intl/id/guide/topics/ui/declaring-layout.jd
    -new file mode 100644
    -index 0000000..1c8a0d6
    ---- /dev/null
    -+++ b/docs/html-intl/intl/id/guide/topics/ui/declaring-layout.jd
    -@@ -0,0 +1,492 @@
    -+page.title=Layout
    -+page.tags=view,viewgroup
    -+@jd:body
    -+
    -+<div id="qv-wrapper">
    -+<div id="qv">
    -+  <h2>Dalam dokumen ini</h2>
    -+<ol>
    -+  <li><a href="#write">Tulis XML</a></li>
    -+  <li><a href="#load">Muat Sumber Daya XML</a></li>
    -+  <li><a href="#attributes">Atribut</a>
    -+    <ol>
    -+      <li><a href="#id">ID</a></li>
    -+      <li><a href="#layout-params">Parameter Layout</a></li>
    -+    </ol>
    -+  </li>
    -+  <li><a href="#Position">Posisi Layout</a></li>
    -+  <li><a href="#SizePaddingMargins">Ukuran, Pengisi, dan Margin</a></li>
    -+  <li><a href="#CommonLayouts">Layout Umum</a></li>
    -+  <li><a href="#AdapterViews">Membangun Layout dengan Adaptor</a>
    -+    <ol>
    -+      <li><a href="#FillingTheLayout">Mengisi tampilan adaptor dengan data</a></li>
    -+      <li><a href="#HandlingUserSelections">Menangani kejadian klik</a></li>
    -+    </ol>
    -+  </li>
    -+</ol>
    -+
    -+  <h2>Kelas-kelas utama</h2>
    -+  <ol>
    -+    <li>{@link android.view.View}</li>
    -+    <li>{@link android.view.ViewGroup}</li>
    -+    <li>{@link android.view.ViewGroup.LayoutParams}</li>
    -+  </ol>
    -+
    -+  <h2>Lihat juga</h2>
    -+  <ol>
    -+    <li><a href="{@docRoot}training/basics/firstapp/building-ui.html">Membangun Antarmuka Pengguna
    -+Sederhana</a></li> </div>
    -+</div>
    -+
    -+<p>Layout mendefinisikan struktur visual untuk antarmuka pengguna, seperti UI sebuah <a href="{@docRoot}guide/components/activities.html">aktivitas</a> atau <a href="{@docRoot}guide/topics/appwidgets/index.html">widget aplikasi</a>.
    -+Anda dapat mendeklarasikan layout dengan dua cara:</p>
    -+<ul>
    -+<li><strong>Deklarasikan elemen UI dalam XML</strong>. Android menyediakan sebuah kosakata XML
    -+sederhana yang sesuai dengan kelas dan subkelas View, seperti halnya untuk widget dan layout.</li>
    -+<li><strong>Buat instance elemen layout saat runtime</strong>. Aplikasi Anda
    -+bisa membuat objek View dan ViewGroup (dan memanipulasi propertinya) lewat program. </li>
    -+</ul>
    -+
    -+<p>Kerangka kerja Android memberi Anda fleksibilitas untuk menggunakan salah satu atau kedua metode ini guna mendeklarasikan dan mengelola UI aplikasi Anda. Misalnya, Anda bisa mendeklarasikan layout default aplikasi Anda dalam XML, termasuk elemen-elemen layar yang akan muncul di dalamnya dan di propertinya. Anda nanti bisa menambahkan kode dalam aplikasi yang akan memodifikasi status objek layar, termasuk yang dideklarasikan dalam XML, saat runtime. </p>
    -+
    -+<div class="sidebox-wrapper">
    -+<div class="sidebox">
    -+  <ul>
    -+  <li><a href="{@docRoot}tools/sdk/eclipse-adt.html">ADT
    -+  Plugin for Eclipse</a> menawarkan preview layout XML &mdash;
    -+ Anda dengan file XML yang dibuka, pilih tab <strong>Layout</strong>.</li>
    -+  <li>Anda juga harus mencoba alat
    -+  <a href="{@docRoot}tools/debugging/debugging-ui.html#hierarchyViewer">Hierarchy Viewer</a>,
    -+ untuk merunut layout &mdash; alat ini akan menampilkan nilai-nilai properti layout,
    -+  menggambar bentuk kerangka dengan indikator pengisi/margin, dan tampilan yang dirender penuh selagi
    -+  Anda merunut pada emulator atau perangkat.</li>
    -+  <li>Alat <a href="{@docRoot}tools/debugging/debugging-ui.html#layoutopt">layoutopt</a> memungkinkan
    -+  Anda menganalisis layout dan hierarki dengan untuk mengetahui ketidakefisienan atau masalah lainnya.</li>
    -+</div>
    -+</div>
    -+
    -+<p>Keuntungan mendeklarasikan UI dalam XML adalah karena hal ini memungkinkan Anda memisahkan penampilan aplikasi dari kode yang mengontrol perilakunya dengan lebih baik. Keterangan UI Anda bersifat eksternal bagi kode aplikasi Anda, yang berarti bahwa Anda bisa memodifikasi atau menyesuaikannya tanpa harus memodifikasi dan mengompilasi ulang kode sumber. Misalnya, Anda bisa membuat layout XML untuk berbagai orientasi layar, berbagai ukuran layar perangkat, dan berbagai bahasa. Selain itu, mendeklarasikan layout dalam XML akan mempermudah Anda memvisualisasikan struktur UI, sehingga lebih mudah merunut masalahnya. Karena itu, dokumen ini berfokus pada upaya mengajari Anda cara mendeklarasikan layout dalam XML. Jika Anda
    -+tertarik dalam membuat instance objek View saat runtime, lihat referensi kelas {@link android.view.ViewGroup} dan
    -+{@link android.view.View}.</p>
    -+
    -+<p>Secara umum, kosakata XML untuk mendeklarasikan elemen UI mengikuti dengan sangat mirip struktur serta penamaan kelas dan metode, dengan nama elemen dipadankan dengan nama kelas dan nama atribut dipadankan dengan metode. Sebenarnya, pemadanan ini kerap kali begitu jelas sehingga Anda bisa menebak atribut XML yang berpadanan dengan sebuah metode kelas, atau menebak kelas yang berpadanan dengan sebuah elemen XML. Akan tetapi, perhatikan bahwa tidak semua kosakata identik. Dalam beberapa kasus, ada sedikit perbedaan penamaan. Misalnya
    -+, elemen EditText memiliki atribut <code>text</code> yang berpadanan dengan
    -+<code>EditText.setText()</code>. </p>
    -+
    -+<p class="note"><strong>Tip:</strong> Ketahui selengkapnya berbagai tipe layout dalam <a href="{@docRoot}guide/topics/ui/layout-objects.html">Objek
    -+Layout Umum</a>. Ada juga sekumpulan tutorial tentang cara membangun berbagai layout dalam panduan tutorial
    -+<a href="{@docRoot}resources/tutorials/views/index.html">Hello Views</a>.</p>
    -+
    -+<h2 id="write">Tulis XML</h2>
    -+
    -+<p>Dengan menggunakan kosakata XML Android, Anda bisa mendesain secara cepat layout UI dan elemen layar yang dimuatnya, sama dengan cara membuat halaman web dalam HTML &mdash; dengan serangkaian elemen tersarang. </p>
    -+
    -+<p>Tiap file layout harus berisi persis satu elemen akar, yang harus berupa sebuah objek View atau ViewGroup. Setelah mendefinisikan elemen akar, Anda bisa menambahkan objek atau widget layout tambahan sebagai elemen anak untuk membangun hierarki View yang mendefinisikan layout Anda secara bertahap. Misalnya, inilah layout XML yang menggunakan {@link android.widget.LinearLayout}
    -+vertikal untuk menyimpan {@link android.widget.TextView} dan {@link android.widget.Button}:</p>
    -+<pre>
    -+&lt;?xml version="1.0" encoding="utf-8"?>
    -+&lt;LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    -+              android:layout_width="match_parent"
    -+              android:layout_height="match_parent"
    -+              android:orientation="vertical" >
    -+    &lt;TextView android:id="@+id/text"
    -+              android:layout_width="wrap_content"
    -+              android:layout_height="wrap_content"
    -+              android:text="Hello, I am a TextView" />
    -+    &lt;Button android:id="@+id/button"
    -+            android:layout_width="wrap_content"
    -+            android:layout_height="wrap_content"
    -+            android:text="Hello, I am a Button" />
    -+&lt;/LinearLayout>
    -+</pre>
    -+
    -+<p>Setelah Anda mendeklarasikan layout dalam XML, simpanlah file dengan ekstensi <code>.xml</code>,
    -+dalam direktori <code>res/layout/</code> proyek Android, sehingga nanti bisa dikompilasi dengan benar. </p>
    -+
    -+<p>Informasi selengkapnya tentang sintaks untuk file XML layout tersedia dalam dokumen <a href="{@docRoot}guide/topics/resources/layout-resource.html">Sumber Daya Layout</a>.</p>
    -+
    -+<h2 id="load">Muat Sumber Daya XML</h2>
    -+
    -+<p>Saat mengompilasi aplikasi, masing-masing file layout XML akan dikompilasi dalam sebuah sumber daya
    -+{@link android.view.View}. Anda harus memuat sumber daya layout dari kode aplikasi, dalam implementasi
    -+callback {@link android.app.Activity#onCreate(android.os.Bundle) Activity.onCreate()}.
    -+Lakukan dengan memanggil <code>{@link android.app.Activity#setContentView(int) setContentView()}</code>,
    -+dengan meneruskan acuan ke sumber daya layout berupa:
    -+<code>R.layout.<em>layout_file_name</em></code>.
    -+Misalnya, jika XML layout Anda disimpan sebagai <code>main_layout.xml</code>, Anda akan memuatnya
    -+untuk Activity seperti ini:</p>
    -+<pre>
    -+public void onCreate(Bundle savedInstanceState) {
    -+    super.onCreate(savedInstanceState);
    -+    setContentView(R.layout.main_layout);
    -+}
    -+</pre>
    -+
    -+<p>Metode callback <code>onCreate()</code> dalam Activity dipanggil oleh kerangka kerja Android saat
    -+Activity Anda dijalankan (lihat diskusi tentang daur hidup, dalam dokumen
    -+<a href="{@docRoot}guide/components/activities.html#Lifecycle">Aktivitas</a>
    -+).</p>
    -+
    -+
    -+<h2 id="attributes">Atribut</h2>
    -+
    -+<p>Setiap objek View dan ViewGroup mendukung variasi atribut XML-nya sendiri.
    -+Sebagian atribut bersifat spesifik untuk objek View (misalnya, TextView mendukung atribut <code>textSize</code>
    -+), namun atribut ini juga diwarisi oleh sembarang objek View yang dapat memperluas kelas ini.
    -+Sebagian atribut bersifat umum untuk semua objek View, karena diwarisi dari kelas View akar (seperti
    -+atribut <code>id</code>). Dan, atribut lain dianggap sebagai "parameter layout" yaitu
    -+atribut yang menjelaskan orientasi layout tertentu dari objek View, seperti yang didefinisikan oleh objek ViewGroup induk
    -+dari objek itu.</p>
    -+
    -+<h3 id="id">ID</h3>
    -+
    -+<p>Objek View apa saja dapat memiliki ID integer yang dikaitkan dengannya, untuk mengidentifikasi secara unik View dalam pohon.
    -+Bila aplikasi dikompilasi, ID ini akan diacu sebagai integer, namun ID biasanya
    -+ditetapkan dalam file XML layout sebagai string, dalam atribut <code>id</code>.
    -+Ini atribut XML yang umum untuk semua objek View
    -+(yang didefinisikan oleh kelas {@link android.view.View}) dan Anda akan sering sekali menggunakannya.
    -+Sintaks untuk ID dalam tag XML adalah:</p>
    -+<pre>android:id="&#64;+id/my_button"</pre>
    -+
    -+<p>Simbol "at" (@) pada awal string menunjukkan parser XML harus mengurai dan memperluas
    -+ID string selebihnya dan mengenalinya sebagai ID sumber daya. Simbol tanda tambah (+) berarti ini nama sumber daya baru yang harus
    -+dibuat dan ditambahkan ke sumber daya kita (dalam file <code>R.java</code>). Ada sejumlah sumber daya ID lain yang
    -+ditawarkan oleh kerangka kerja Android. Saat mengacu sebuah ID sumber daya Android, Anda tidak memerlukan simbol tanda tambah,
    -+namun harus menambahkan namespace paket <code>android</code>, sehingga:</p>
    -+<pre>android:id="&#64;android:id/empty"</pre>
    -+<p>Dengan namespace paket <code>android</code> yang tersedia, kita sekarang mengacu ID dari kelas sumber daya <code>android.R</code>
    -+, daripada kelas sumber daya lokal.</p>
    -+
    -+<p>Untuk membuat tampilan dan mengacunya dari aplikasi, pola yang umum adalah:</p>
    -+<ol>
    -+  <li>Mendefinisikan tampilan/widget dalam file layout dan memberinya ID unik:
    -+<pre>
    -+&lt;Button android:id="&#64;+id/my_button"
    -+        android:layout_width="wrap_content"
    -+        android:layout_height="wrap_content"
    -+        android:text="&#64;string/my_button_text"/>
    -+</pre>
    -+  </li>
    -+  <li>Kemudian buat instance objek tampilan dan tangkap instance itu dari layout
    -+(biasanya dalam metode <code>{@link android.app.Activity#onCreate(Bundle) onCreate()}</code>):
    -+<pre>
    -+Button myButton = (Button) findViewById(R.id.my_button);
    -+</pre>
    -+  </li>
    -+</ol>
    -+<p>Mendefinisikan ID untuk objek tampilan adalah penting saat membuat {@link android.widget.RelativeLayout}.
    -+Dalam layout relatif, tampilan saudara bisa mendefinisikan layout secara relatif terhadap tampilan saudara lainnya,
    -+yang diacu melalui ID unik.</p>
    -+<p>ID tidak perlu unik di seluruh pohon, namun harus
    -+unik di bagian pohon yang Anda cari (yang mungkin sering kali seluruh pohon, jadi lebih baik
    -+benar-benar unik bila memungkinkan).</p>
    -+
    -+
    -+<h3 id="layout-params">Parameter Layout</h3>
    -+
    -+<p>Atribut layout XML bernama <code>layout_<em>something</em></code> mendefinisikan
    -+parameter layout View yang cocok untuk ViewGroup tempatnya berada.</p>
    -+
    -+<p>Setiap kelas ViewGroup mengimplementasikan kelas tersarang yang memperluas {@link
    -+android.view.ViewGroup.LayoutParams}. Subkelas ini
    -+berisi tipe properti yang mendefinisikan ukuran dan posisi masing-masing tampilan anak, sebagaimana
    -+mestinya untuk grup tampilan. Seperti yang bisa Anda lihat dalam gambar 1,
    -+grup tampilan induk mendefinisikan parameter layout untuk masing-masing tampilan anak (termasuk grup tampilan anak).</p>
    -+
    -+<img src="{@docRoot}images/layoutparams.png" alt="" />
    -+<p class="img-caption"><strong>Gambar 1.</strong> Visualisasi hierarki tampilan dengan parameter layout
    -+yang dikaitkan dengan tiap tampilan.</p>
    -+
    -+<p>Perhatikan bahwa setiap subkelas LayoutParams memiliki sintaksnya sendiri untuk menetapkan
    -+nilai-nilai. Tiap elemen anak harus mendefinisikan LayoutParams yang semestinya bagi induknya,
    -+meskipun elemen itu bisa juga mendefinisikan LayoutParams untuk anak-anaknya sendiri. </p>
    -+
    -+<p>Semua grup tampilan berisi lebar dan tinggi (<code>layout_width</code> dan
    -+<code>layout_height</code>), dan masing-masing tampilan harus mendefinisikannya. Banyak
    -+LayoutParams yang juga menyertakan margin dan border opsional. <p>
    -+
    -+<p>Anda bisa menetapkan lebar dan tinggi dengan ukuran persis, meskipun Anda mungkin
    -+tidak ingin sering-sering melakukannya. Lebih sering, Anda akan menggunakan salah satu konstanta ini untuk
    -+mengatur lebar atau tinggi: </p>
    -+
    -+<ul>
    -+  <li><var>wrap_content</var> memberi tahu tampilan Anda agar menyesuaikan sendiri ukurannya dengan dimensi
    -+yang dibutuhkan oleh isinya.</li>
    -+  <li><var>match_parent</var> (bernama <var>fill_parent</var> sebelum API Level 8)
    -+memberi tahu tampilan Anda agar menjadi sebesar yang diperbolehkan oleh grup tampilan induknya.</li>
    -+</ul>
    -+
    -+<p>Secara umum, menetapkan lebar dan tinggi layout dengan satuan mutlak seperti
    -+piksel tidaklah disarankan. Melainkan dengan menggunakan ukuran relatif seperti
    -+satuan piksel yang tidak bergantung pada kerapatan (<var>dp</var>), <var>wrap_content</var>, atau
    -+<var>match_parent</var>, adalah sebuah pendekatan yang lebih baik, karena membantu memastikan bahwa
    -+aplikasi Anda akan ditampilkan dengan benar pada berbagai ukuran layar perangkat.
    -+Tipe ukuran yang diterima didefinisikan dalam dokumen
    -+<a href="{@docRoot}guide/topics/resources/available-resources.html#dimension">
    -+Sumber Daya yang Tersedia</a>.</p>
    -+
    -+
    -+<h2 id="Position">Posisi Layout</h2>
    -+   <p>
    -+   Geometri tampilan adalah persegi panjang. Sebuah tampilan memiliki lokasi,
    -+   yang dinyatakan berupa sepasang koordinat <em>kiri</em> dan <em>atas</em>, dan
    -+   dua dimensi, yang dinyatakan berupa lebar dan tinggi. Satuan untuk lokasi
    -+   dan dimensi adalah piksel.
    -+   </p>
    -+
    -+   <p>
    -+   Lokasi tampilan dapat diambil dengan memanggil metode
    -+   {@link android.view.View#getLeft()} dan {@link android.view.View#getTop()}. Metode terdahulu menghasilkan koordinat kiri, atau X,
    -+   persegi panjang yang mewakili tampilan. Metode selanjutnya menghasilkan koordinat
    -+   atas, atau Y, persegi panjang yang mewakili tampilan. Kedua metode ini
    -+   menghasilkan lokasi tampilan relatif terhadap induknya. Misalnya,
    -+   bila <code>getLeft()</code> menghasilkan 20, berarti tampilan berlokasi 20 piksel ke
    -+   kanan dari tepi kiri induk langsungnya.
    -+   </p>
    -+
    -+   <p>
    -+   Selain itu, beberapa metode praktis ditawarkan untuk menghindari komputasi yang tidak perlu,
    -+   yakni {@link android.view.View#getRight()} dan {@link android.view.View#getBottom()}.
    -+   Kedua metode ini menghasilkan koordinat tepi kanan dan bawah
    -+   persegi panjang yang mewakili tampilan. Misalnya, memanggil {@link android.view.View#getRight()}
    -+   serupa dengan komputasi berikut: <code>getLeft() + getWidth()</code>.
    -+   </p>
    -+
    -+
    -+<h2 id="SizePaddingMargins">Ukuran, Pengisi, dan Margin</h2>
    -+   <p>
    -+   Ukuran tampilan dinyatakan dengan lebar dan tinggi. Tampilan sebenarnya
    -+   memiliki dua pasang nilai lebar dan tinggi.
    -+   </p>
    -+
    -+   <p>
    -+   Sepasang pertama disebut <em>lebar terukur</em> dan
    -+   <em>tinggi terukur</em>. Dimensi ini mendefinisikan seberapa besar tampilan yang diinginkan
    -+   dalam induknya. Dimensi
    -+   terukur bisa diperoleh dengan memanggil {@link android.view.View#getMeasuredWidth()}
    -+   dan {@link android.view.View#getMeasuredHeight()}.
    -+   </p>
    -+
    -+   <p>
    -+   Sepasang kedua cukup disebut dengan <em>lebar</em> dan <em>tinggi</em>, atau
    -+   kadang-kadang <em>lebar penggambaran</em> dan <em>tinggi penggambaran</em>. Dimensi-dimensi ini
    -+   mendefinisikan ukuran tampilan sebenarnya pada layar, saat digambar dan
    -+   setelah layout. Nilai-nilai ini mungkin, namun tidak harus, berbeda dengan
    -+   lebar dan tinggi terukur. Lebar dan tinggi bisa diperoleh dengan memanggil
    -+   {@link android.view.View#getWidth()} dan {@link android.view.View#getHeight()}.
    -+   </p>
    -+
    -+   <p>
    -+   Untuk mengukur dimensinya, tampilan akan memperhitungkan pengisinya (padding). Pengisi
    -+   dinyatakan dalam piksel untuk bagian kiri, atas, kanan, dan bawah tampilan.
    -+   Pengisi bisa digunakan untuk meng-offset isi tampilan dengan
    -+   piksel dalam jumlah tertentu. Misalnya, pengisi kiri sebesar 2 akan mendorong isi tampilan sebanyak
    -+   2 piksel ke kanan dari tepi kiri. Pengisi bisa diatur menggunakan
    -+   metode {@link android.view.View#setPadding(int, int, int, int)} dan diketahui dengan memanggil
    -+   {@link android.view.View#getPaddingLeft()}, {@link android.view.View#getPaddingTop()},
    -+   {@link android.view.View#getPaddingRight()}, dan {@link android.view.View#getPaddingBottom()}.
    -+   </p>
    -+
    -+   <p>
    -+   Meskipun bisa mendefinisikan pengisi, tampilan tidak menyediakan dukungan untuk
    -+   margin. Akan tetapi, grup tampilan menyediakan dukungan tersebut. Lihat
    -+   {@link android.view.ViewGroup} dan
    -+   {@link android.view.ViewGroup.MarginLayoutParams} untuk informasi lebih jauh.
    -+   </p>
    -+
    -+   <p>Untuk informasi selengkapnya tentang dimensi, lihat
    -+   <a href="{@docRoot}guide/topics/resources/more-resources.html#Dimension">Nilai-Nilai Dimensi</a>.
    -+   </p>
    -+
    -+
    -+
    -+
    -+
    -+
    -+<style type="text/css">
    -+div.layout {
    -+  float:left;
    -+  width:200px;
    -+  margin:0 0 20px 20px;
    -+}
    -+div.layout.first {
    -+  margin-left:0;
    -+  clear:left;
    -+}
    -+</style>
    -+
    -+
    -+
    -+
    -+<h2 id="CommonLayouts">Layout Umum</h2>
    -+
    -+<p>Tiap subkelas dari kelas {@link android.view.ViewGroup} menyediakan cara unik untuk menampilkan
    -+tampilan yang Anda sarangkan di dalamnya. Di bawah ini adalah beberapa tipe layout lebih umum yang dibuat
    -+ke dalam platform Android.</p>
    -+
    -+<p class="note"><strong>Catatan:</strong> Walaupun Anda bisa menyarangkan satu atau beberapa layout dalam
    -+layout lain untuk mendapatkan desain UI, Anda harus berusaha menjaga hierarki layout sedangkal
    -+mungkin. Layout Anda akan digambar lebih cepat jika memiliki layout tersarang yang lebih sedikit (hierarki tampilan yang melebar
    -+lebih baik daripada hierarki tampilan yang dalam).</p>
    -+
    -+<!--
    -+<h2 id="framelayout">FrameLayout</h2>
    -+<p>{@link android.widget.FrameLayout FrameLayout} is the simplest type of layout
    -+object. It's basically a blank space on your screen that you can
    -+later fill with a single object &mdash; for example, a picture that you'll swap in and out.
    -+All child elements of the FrameLayout are pinned to the top left corner of the screen; you cannot
    -+specify a different location for a child view. Subsequent child views will simply be drawn over
    -+previous ones,
    -+partially or totally obscuring them (unless the newer object is transparent).
    -+</p>
    -+-->
    -+
    -+
    -+<div class="layout first">
    -+  <h4><a href="layout/linear.html">Layout Linier</a></h4>
    -+  <a href="layout/linear.html"><img src="{@docRoot}images/ui/linearlayout-small.png" alt="" /></a>
    -+  <p>Layout yang mengatur anak-anaknya menjadi satu baris horizontal atau vertikal. Layout ini
    -+  akan membuat scrollbar jika panjang jendela melebihi panjang layar.</p>
    -+</div>
    -+
    -+<div class="layout">
    -+  <h4><a href="layout/relative.html">Layout Relatif</a></h4>
    -+  <a href="layout/relative.html"><img src="{@docRoot}images/ui/relativelayout-small.png" alt="" /></a>
    -+  <p>Memungkinkan Anda menentukan lokasi objek anak relatif terhadap satu sama lain (anak A di
    -+kiri anak B) atau terhadap induk (disejajarkan dengan atas induknya).</p>
    -+</div>
    -+
    -+<div class="layout">
    -+  <h4><a href="{@docRoot}guide/webapps/webview.html">Tampilan Web</a></h4>
    -+  <a href="{@docRoot}guide/webapps/webview.html"><img src="{@docRoot}images/ui/webview-small.png" alt="" /></a>
    -+  <p>Menampilkan halaman web.</p>
    -+</div>
    -+
    -+
    -+
    -+
    -+<h2 id="AdapterViews" style="clear:left">Membangun Layout dengan Adaptor</h2>
    -+
    -+<p>Bila isi layout bersifat dinamis atau tidak dipastikan sebelumnya, Anda bisa menggunakan layout yang menjadi
    -+subkelas {@link android.widget.AdapterView} untuk mengisi layout dengan tampilan saat runtime.
    -+Subkelas dari kelas {@link android.widget.AdapterView} menggunakan {@link android.widget.Adapter} untuk
    -+mengikat data ke layoutnya. {@link android.widget.Adapter} berfungsi sebagai penghubung antara sumber data
    -+dan layout{@link android.widget.AdapterView}&mdash;{@link android.widget.Adapter}
    -+menarik data (dari suatu sumber seperti larik (array) atau query database) dan mengubah setiap entri
    -+menjadi tampilan yang bisa ditambahkan ke dalam layout {@link android.widget.AdapterView}.</p>
    -+
    -+<p>Layout umum yang didukung oleh adaptor meliputi:</p>
    -+
    -+<div class="layout first">
    -+  <h4><a href="layout/listview.html">Tampilan Daftar</a></h4>
    -+  <a href="layout/listview.html"><img src="{@docRoot}images/ui/listview-small.png" alt="" /></a>
    -+  <p>Menampilkan daftar kolom tunggal yang bergulir.</p>
    -+</div>
    -+
    -+<div class="layout">
    -+  <h4><a href="layout/gridview.html">Tampilan Petak</a></h4>
    -+  <a href="layout/gridview.html"><img src="{@docRoot}images/ui/gridview-small.png" alt="" /></a>
    -+  <p>Menampilkan petak bergulir yang terdiri atas kolom dan baris.</p>
    -+</div>
    -+
    -+
    -+
    -+<h3 id="FillingTheLayout" style="clear:left">Mengisi tampilan adaptor dengan data</h3>
    -+
    -+<p>Anda bisa mengisi {@link android.widget.AdapterView} seperti {@link android.widget.ListView} atau
    -+{@link android.widget.GridView} dengan mengikat instance {@link android.widget.AdapterView} ke
    -+{@link android.widget.Adapter}, yang akan mengambil data dari sumber eksternal dan membuat {@link
    -+android.view.View} yang mewakili tiap entri data.</p>
    -+
    -+<p>Android menyediakan beberapa subkelas {@link android.widget.Adapter} yang berguna untuk
    -+menarik berbagai jenis data dan membangun tampilan untuk {@link android.widget.AdapterView}. Dua
    -+ adaptor yang paling umum adalah:</p>
    -+
    -+<dl>
    -+  <dt>{@link android.widget.ArrayAdapter}</dt>
    -+    <dd>Gunakan adaptor ini bila sumber data Anda berupa larik. Secara default, {@link
    -+android.widget.ArrayAdapter} akan membuat tampilan untuk tiap elemen larik dengan memanggil {@link
    -+java.lang.Object#toString()} pada tiap elemen dan menempatkan isinya dalam {@link
    -+android.widget.TextView}.
    -+      <p>Misalnya, jika Anda memiliki satu larik string yang ingin ditampilkan dalam {@link
    -+android.widget.ListView}, buatlah {@link android.widget.ArrayAdapter} baru dengan konstruktor
    -+untuk menentukan layout setiap string dan larik string:</p>
    -+<pre>
    -+ArrayAdapter&lt;String> adapter = new ArrayAdapter&lt;String>(this,
    -+        android.R.layout.simple_list_item_1, myStringArray);
    -+</pre>
    -+<p>Argumen-argumen untuk konstruktor ini adalah:</p>
    -+<ul>
    -+  <li>{@link android.content.Context} aplikasi Anda</li>
    -+  <li>Layout yang berisi {@link android.widget.TextView} untuk tiap string dalam larik</li>
    -+  <li>Larik string</li>
    -+</ul>
    -+<p>Kemudian tinggal panggil
    -+{@link android.widget.ListView#setAdapter setAdapter()} pada {@link android.widget.ListView} Anda:</p>
    -+<pre>
    -+ListView listView = (ListView) findViewById(R.id.listview);
    -+listView.setAdapter(adapter);
    -+</pre>
    -+
    -+      <p>Untuk menyesuaikan penampilan setiap item, Anda bisa mengesampingkan metode {@link
    -+java.lang.Object#toString()} bagi objek dalam larik Anda. Atau, untuk membuat tampilan tiap
    -+elemen selain {@link android.widget.TextView} (misalnya, jika Anda menginginkan
    -+{@link android.widget.ImageView} bagi setiap item larik), perluas kelas {@link
    -+android.widget.ArrayAdapter} dan kesampingkan {@link android.widget.ArrayAdapter#getView
    -+getView()} agar memberikan tipe tampilan yang Anda inginkan bagi tiap item.</p>
    -+
    -+</dd>
    -+
    -+  <dt>{@link android.widget.SimpleCursorAdapter}</dt>
    -+    <dd>Gunakan adaptor ini bila data Anda berasal dari {@link android.database.Cursor}. Saat
    -+menggunakan {@link android.widget.SimpleCursorAdapter}, Anda harus menentukan layout yang akan digunakan untuk tiap
    -+baris dalam {@link android.database.Cursor} dan di kolom mana di {@link android.database.Cursor}
    -+harus memasukkan tampilan layout. Misalnya, jika Anda ingin untuk membuat daftar
    -+nama orang dan nomor telepon, Anda bisa melakukan query yang menghasilkan {@link
    -+android.database.Cursor} yang berisi satu baris untuk tiap orang dan kolom-kolom untuk nama dan
    -+nomor. Selanjutnya Anda membuat larik string yang menentukan kolom dari {@link
    -+android.database.Cursor} yang Anda inginkan dalam layout untuk setiap hasil dan larik integer yang menentukan
    -+tampilan yang sesuai untuk menempatkan masing-masing kolom:</p>
    -+<pre>
    -+String[] fromColumns = {ContactsContract.Data.DISPLAY_NAME,
    -+                        ContactsContract.CommonDataKinds.Phone.NUMBER};
    -+int[] toViews = {R.id.display_name, R.id.phone_number};
    -+</pre>
    -+<p>Bila Anda membuat instance {@link android.widget.SimpleCursorAdapter}, teruskan layout yang akan digunakan untuk
    -+setiap hasil, {@link android.database.Cursor} yang berisi hasil tersebut, dan dua larik ini:</p>
    -+<pre>
    -+SimpleCursorAdapter adapter = new SimpleCursorAdapter(this,
    -+        R.layout.person_name_and_number, cursor, fromColumns, toViews, 0);
    -+ListView listView = getListView();
    -+listView.setAdapter(adapter);
    -+</pre>
    -+<p>{@link android.widget.SimpleCursorAdapter} kemudian membuat tampilan untuk tiap baris dalam
    -+{@link android.database.Cursor} dengan layout yang disediakan dengan memasukkan setiap item {@code
    -+fromColumns} ke dalam tampilan {@code toViews} yang sesuai.</p></dd>
    -+</dl>
    -+
    -+
    -+<p>Jika, selama aplikasi berjalan, Anda mengubah data sumber yang dibaca oleh
    -+adaptor, maka Anda harus memanggil {@link android.widget.ArrayAdapter#notifyDataSetChanged()}. Hal ini akan
    -+memberi tahu tampilan yang bersangkutan bahwa data telah berubah dan tampilan harus memperbarui dirinya sendiri.</p>
    -+
    -+
    -+
    -+<h3 id="HandlingUserSelections">Menangani kejadian klik</h3>
    -+
    -+<p>Anda bisa merespons kejadian klik pada setiap item dalam {@link android.widget.AdapterView} dengan
    -+menerapkan antarmuka {@link android.widget.AdapterView.OnItemClickListener}. Misalnya:</p>
    -+
    -+<pre>
    -+// Create a message handling object as an anonymous class.
    -+private OnItemClickListener mMessageClickedHandler = new OnItemClickListener() {
    -+    public void onItemClick(AdapterView parent, View v, int position, long id) {
    -+        // Do something in response to the click
    -+    }
    -+};
    -+
    -+listView.setOnItemClickListener(mMessageClickedHandler);
    -+</pre>
    -+
    -+
    -+
    -diff --git a/docs/html-intl/intl/id/guide/topics/ui/dialogs.jd b/docs/html-intl/intl/id/guide/topics/ui/dialogs.jd
    -new file mode 100644
    -index 0000000..06a25ac
    ---- /dev/null
    -+++ b/docs/html-intl/intl/id/guide/topics/ui/dialogs.jd
    -@@ -0,0 +1,798 @@
    -+page.title=Dialog
    -+page.tags=alertdialog,dialogfragment
    -+
    -+@jd:body
    -+
    -+
    -+
    -+<div id="qv-wrapper">
    -+  <div id="qv">
    -+    <h2>Dalam dokumen ini</h2>
    -+<ol>
    -+  <li><a href="#DialogFragment">Membuat Fragmen Dialog</a></li>
    -+  <li><a href="#AlertDialog">Membuat Dialog Peringatan</a>
    -+    <ol>
    -+      <li><a href="#AddingButtons">Menambahkan tombol</a></li>
    -+      <li><a href="#AddingAList">Menambahkan daftar</a></li>
    -+      <li><a href="#CustomLayout">Membuat Layout Custom</a></li>
    -+    </ol>
    -+  </li>
    -+  <li><a href="#PassingEvents">Meneruskan Kejadian Kembali ke Host Dialog</a></li>
    -+  <li><a href="#ShowingADialog">Menampilkan Dialog</a></li>
    -+  <li><a href="#FullscreenDialog">Menampilkan Dialog sebagai Layar Penuh atau Fragmen Tertanam</a>
    -+    <ol>
    -+      <li><a href="#ActivityAsDialog">Menampilkan aktivitas sebagai dialog pada layar besar</a></li>
    -+    </ol>
    -+  </li>
    -+  <li><a href="#DismissingADialog">Menutup Dialog</a></li>
    -+</ol>
    -+
    -+    <h2>Kelas-kelas utama</h2>
    -+    <ol>
    -+      <li>{@link android.app.DialogFragment}</li>
    -+      <li>{@link android.app.AlertDialog}</li>
    -+    </ol>
    -+
    -+    <h2>Lihat juga</h2>
    -+    <ol>
    -+      <li><a href="{@docRoot}design/building-blocks/dialogs.html">Panduan desain dialog</a></li>
    -+      <li><a href="{@docRoot}guide/topics/ui/controls/pickers.html">Picker</a> (dialog Tanggal/Waktu)</li>
    -+    </ol>
    -+  </div>
    -+</div>
    -+
    -+<p>Dialog adalah jendela kecil yang meminta pengguna untuk
    -+membuat keputusan atau memasukkan informasi tambahan. Dialog tidak mengisi layar dan
    -+biasanya digunakan untuk kejadian modal yang mengharuskan pengguna untuk melakukan tindakan sebelum bisa melanjutkan.</p>
    -+
    -+<div class="note design">
    -+<p><strong>Desain Dialog</strong></p>
    -+  <p>Untuk informasi tentang cara mendesain dialog, termasuk saran
    -+  untuk bahasa, bacalah panduan Desain <a href="{@docRoot}design/building-blocks/dialogs.html">dialog</a>.</p>
    -+</div>
    -+
    -+<img src="{@docRoot}images/ui/dialogs.png" />
    -+
    -+<p>Kelas {@link android.app.Dialog} adalah kelas basis untuk dialog, namun Anda
    -+harus menghindari pembuatan instance {@link android.app.Dialog} secara langsung.
    -+Sebagai gantinya, gunakan salah satu subkelas berikut:</p>
    -+<dl>
    -+  <dt>{@link android.app.AlertDialog}</dt>
    -+  <dd>Dialog yang bisa menampilkan judul, hingga tiga tombol, daftar
    -+    item yang dapat dipilih, atau layout custom.</dd>
    -+  <dt>{@link android.app.DatePickerDialog} atau {@link android.app.TimePickerDialog}</dt>
    -+  <dd>Dialog berisi UI yang sudah didefinisikan dan memungkinkan pengguna memilih tanggal atau waktu.</dd>
    -+</dl>
    -+
    -+<div class="sidebox">
    -+<h2>Hindari ProgressDialog</h2>
    -+<p>Android menyertakan kelas dialog lain yang disebut
    -+{@link android.app.ProgressDialog} yang menampilkan dialog berisi progress-bar. Akan tetapi, jika Anda
    -+perlu menunjukkan kemajuan pemuatan ataupun kemajuan yang tidak pasti, maka Anda harus mengikuti
    -+panduan desain untuk <a href="{@docRoot}design/building-blocks/progress.html">Kemajuan &amp;
    -+Aktivitas</a> dan menggunakan {@link android.widget.ProgressBar} dalam layout Anda.</p>
    -+</div>
    -+
    -+<p>Kelas-kelas ini mendefinisikan gaya dan struktur dialog Anda, namun Anda harus
    -+menggunakan {@link android.support.v4.app.DialogFragment} sebagai kontainer dialog Anda.
    -+Kelas {@link android.support.v4.app.DialogFragment} menyediakan semua kontrol yang Anda
    -+perlukan untuk membuat dialog dan mengelola penampilannya, sebagai ganti memanggil metode
    -+pada objek {@link android.app.Dialog}.</p>
    -+
    -+<p>Menggunakan {@link android.support.v4.app.DialogFragment} untuk mengelola dialog
    -+akan memastikan bahwa kelas itu menangani kejadian daur hidup
    -+dengan benar seperti ketika pengguna menekan tombol <em>Back</em> atau memutar layar. Kelas {@link
    -+android.support.v4.app.DialogFragment} juga memungkinkan Anda menggunakan ulang dialog UI sebagai
    -+komponen yang bisa ditanamkan dalam UI yang lebih besar, persis seperti {@link
    -+android.support.v4.app.Fragment} tradisional (seperti saat Anda ingin dialog UI muncul berbeda
    -+pada layar besar dan kecil).</p>
    -+
    -+<p>Bagian-bagian berikutnya dalam panduan ini akan menjelaskan cara menggunakan {@link
    -+android.support.v4.app.DialogFragment} yang dikombinasikan dengan objek {@link android.app.AlertDialog}
    -+. Jika Anda ingin membuat picker tanggal atau waktu, Anda harus membaca panduan
    -+<a href="{@docRoot}guide/topics/ui/controls/pickers.html">Picker</a>.</p>
    -+
    -+<p class="note"><strong>Catatan:</strong>
    -+Karena kelas {@link android.app.DialogFragment} mulanya ditambahkan pada
    -+Android 3.0 (API level 11), dokumen ini menjelaskan cara menggunakan kelas {@link
    -+android.support.v4.app.DialogFragment} yang disediakan bersama <a href="{@docRoot}tools/support-library/index.html">Pustaka Dukungan</a>. Dengan menambahkan pustaka ini
    -+ke aplikasi, Anda bisa menggunakan {@link android.support.v4.app.DialogFragment} dan berbagai
    -+API lain pada perangkat yang menjalankan Android 1.6 atau yang lebih tinggi. Jika versi minimum yang didukung aplikasi Anda
    -+adalah API level 11 atau yang lebih tinggi, maka Anda bisa menggunakan versi kerangka kerja {@link
    -+android.app.DialogFragment}, namun ketahuilah bahwa tautan dalam dokumen ini adalah untuk API
    -+pustaka dukungan. Saat menggunakan pustaka dukungan,
    -+pastikan Anda mengimpor kelas <code>android.support.v4.app.DialogFragment</code>
    -+dan <em>bukan</em> <code>android.app.DialogFragment</code>.</p>
    -+
    -+
    -+<h2 id="DialogFragment">Membuat Fragmen Dialog</h2>
    -+
    -+<p>Anda bisa menghasilkan beragam rancangan dialog&mdash;termasuk
    -+layout custom dan desain yang dijelaskan dalam panduan desain <a href="{@docRoot}design/building-blocks/dialogs.html">Dialog</a>
    -+&mdash;dengan memperluas
    -+{@link android.support.v4.app.DialogFragment} dan membuat {@link android.app.AlertDialog}
    -+dalam metode callback {@link android.support.v4.app.DialogFragment#onCreateDialog
    -+onCreateDialog()}.</p>
    -+
    -+<p>Misalnya, berikut ini sebuah {@link android.app.AlertDialog} dasar yang dikelola dalam
    -+{@link android.support.v4.app.DialogFragment}:</p>
    -+
    -+<pre>
    -+public class FireMissilesDialogFragment extends DialogFragment {
    -+    &#64;Override
    -+    public Dialog onCreateDialog(Bundle savedInstanceState) {
    -+        // Use the Builder class for convenient dialog construction
    -+        AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
    -+        builder.setMessage(R.string.dialog_fire_missiles)
    -+               .setPositiveButton(R.string.fire, new DialogInterface.OnClickListener() {
    -+                   public void onClick(DialogInterface dialog, int id) {
    -+                       // FIRE ZE MISSILES!
    -+                   }
    -+               })
    -+               .setNegativeButton(R.string.cancel, new DialogInterface.OnClickListener() {
    -+                   public void onClick(DialogInterface dialog, int id) {
    -+                       // User cancelled the dialog
    -+                   }
    -+               });
    -+        // Create the AlertDialog object and return it
    -+        return builder.create();
    -+    }
    -+}
    -+</pre>
    -+
    -+<div class="figure" style="width:290px;margin:0 0 0 20px">
    -+<img src="{@docRoot}images/ui/dialog_buttons.png" alt="" />
    -+<p class="img-caption"><strong>Gambar 1.</strong>
    -+Dialog dengan satu pesan dan dua tombol tindakan.</p>
    -+</div>
    -+
    -+<p>Sekarang, bila Anda membuat instance kelas ini dan memanggil {@link
    -+android.support.v4.app.DialogFragment#show show()} pada objek itu, dialog akan muncul seperti
    -+yang ditampilkan dalam gambar 1.</p>
    -+
    -+<p>Bagian berikutnya menjelaskan lebih jauh tentang penggunaan API {@link android.app.AlertDialog.Builder}
    -+untuk membuat dialog.</p>
    -+
    -+<p>Bergantung pada seberapa rumit dialog tersebut, Anda bisa menerapkan berbagai metode callback lain
    -+dalam {@link android.support.v4.app.DialogFragment}, termasuk semua
    -+<a href="{@docRoot}guide/components/fragments.html#Lifecycle">metode daur hidup fragmen</a> dasar.
    -+
    -+
    -+
    -+
    -+
    -+<h2 id="AlertDialog">Membuat Dialog Peringatan</h2>
    -+
    -+
    -+<p>Kelas {@link android.app.AlertDialog} memungkinkan Anda membuat berbagai desain dialog dan
    -+seringkali satu-satunya kelas dialog yang akan Anda perlukan.
    -+Seperti yang ditampilkan dalam gambar 2, ada tiga area pada dialog peringatan:</p>
    -+
    -+<div class="figure" style="width:311px;margin-top:0">
    -+<img src="{@docRoot}images/ui/dialogs_regions.png" alt="" style="margin-bottom:0" />
    -+<p class="img-caption"><strong>Gambar 2.</strong> Layout dialog.</p>
    -+</div>
    -+
    -+<ol>
    -+<li><b>Judul</b>
    -+  <p>Area ini opsional dan hanya boleh digunakan bila area konten
    -+  ditempati oleh pesan terperinci, daftar, atau layout custom. Jika Anda perlu menyatakan
    -+  pesan atau pertanyaan sederhana (seperti dialog dalam gambar 1), Anda tidak memerlukan judul.</li>
    -+<li><b>Area konten</b>
    -+  <p>Area ini bisa menampilkan pesan, daftar, atau layout custom lainnya.</p></li>
    -+<li><b>Tombol tindakan</b>
    -+  <p>Tidak boleh ada lebih dari tiga tombol tindakan dalam sebuah dialog.</p></li>
    -+</ol>
    -+
    -+<p>Kelas {@link android.app.AlertDialog.Builder}
    -+ menyediakan API yang memungkinkan Anda membuat {@link android.app.AlertDialog}
    -+dengan jenis konten ini, termasuk layout custom.</p>
    -+
    -+<p>Untuk membuat {@link android.app.AlertDialog}:</p>
    -+
    -+<pre>
    -+<b>// 1. Instantiate an {@link android.app.AlertDialog.Builder} with its constructor</b>
    -+AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
    -+
    -+<b>// 2. Chain together various setter methods to set the dialog characteristics</b>
    -+builder.setMessage(R.string.dialog_message)
    -+       .setTitle(R.string.dialog_title);
    -+
    -+<b>// 3. Get the {@link android.app.AlertDialog} from {@link android.app.AlertDialog.Builder#create()}</b>
    -+AlertDialog dialog = builder.create();
    -+</pre>
    -+
    -+<p>Topik-topik selanjutnya menampilkan cara mendefinisikan berbagai atribut dialog dengan menggunakan
    -+kelas {@link android.app.AlertDialog.Builder}.</p>
    -+
    -+
    -+
    -+
    -+<h3 id="AddingButtons">Menambahkan tombol</h3>
    -+
    -+<p>Untuk menambahkan tombol tindakan seperti dalam gambar 2,
    -+panggil metode {@link android.app.AlertDialog.Builder#setPositiveButton setPositiveButton()} dan
    -+{@link android.app.AlertDialog.Builder#setNegativeButton setNegativeButton()}:</p>
    -+
    -+<pre style="clear:right">
    -+AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
    -+// Add the buttons
    -+builder.setPositiveButton(R.string.ok, new DialogInterface.OnClickListener() {
    -+           public void onClick(DialogInterface dialog, int id) {
    -+               // User clicked OK button
    -+           }
    -+       });
    -+builder.setNegativeButton(R.string.cancel, new DialogInterface.OnClickListener() {
    -+           public void onClick(DialogInterface dialog, int id) {
    -+               // User cancelled the dialog
    -+           }
    -+       });
    -+// Set other dialog properties
    -+...
    -+
    -+// Create the AlertDialog
    -+AlertDialog dialog = builder.create();
    -+</pre>
    -+
    -+<p>Metode <code>set...Button()</code> mengharuskan adanya judul bagi tombol (disediakan
    -+oleh suatu <a href="{@docRoot}guide/topics/resources/string-resource.html">sumber daya string</a>) dan
    -+{@link android.content.DialogInterface.OnClickListener} yang mendefinisikan tindakan yang diambil
    -+bila pengguna menekan tombol.</p>
    -+
    -+<p>Ada tiga macam tombol tindakan yang Anda bisa tambahkan:</p>
    -+<dl>
    -+  <dt>Positif</dt>
    -+  <dd>Anda harus menggunakan tipe ini untuk menerima dan melanjutkan tindakan (tindakan "OK").</dd>
    -+  <dt>Negatif</dt>
    -+  <dd>Anda harus menggunakan tipe ini untuk membatalkan tindakan.</dd>
    -+  <dt>Netral</dt>
    -+  <dd>Anda harus menggunakan tipe ini bila pengguna mungkin tidak ingin melanjutkan tindakan,
    -+  namun tidak ingin membatalkan. Tipe ini muncul antara tombol positif dan
    -+tombol negatif. Misalnya, tindakan bisa berupa "Ingatkan saya nanti".</dd>
    -+</dl>
    -+
    -+<p>Anda hanya bisa menambahkan salah satu tipe tombol ke {@link
    -+android.app.AlertDialog}. Artinya, Anda tidak bisa memiliki lebih dari satu tombol "positif".</p>
    -+
    -+
    -+
    -+<div class="figure" style="width:290px;margin:0 0 0 40px">
    -+<img src="{@docRoot}images/ui/dialog_list.png" alt="" />
    -+<p class="img-caption"><strong>Gambar 3.</strong>
    -+Dialog dengan satu judul dan daftar.</p>
    -+</div>
    -+
    -+<h3 id="AddingAList">Menambahkan daftar</h3>
    -+
    -+<p>Ada tiga macam daftar yang tersedia pada API {@link android.app.AlertDialog}:</p>
    -+<ul>
    -+<li>Daftar pilihan tunggal biasa</li>
    -+<li>Daftar pilihan tunggal persisten (tombol radio)</li>
    -+<li>Daftar pilihan ganda persisten (kotak cek)</li>
    -+</ul>
    -+
    -+<p>Untuk membuat daftar pilihan tunggal seperti dalam gambar 3,
    -+gunakan metode {@link android.app.AlertDialog.Builder#setItems setItems()}:</p>
    -+
    -+<pre style="clear:right">
    -+&#64;Override
    -+public Dialog onCreateDialog(Bundle savedInstanceState) {
    -+    AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
    -+    builder.setTitle(R.string.pick_color)
    -+           .setItems(R.array.colors_array, new DialogInterface.OnClickListener() {
    -+               public void onClick(DialogInterface dialog, int which) {
    -+               // The 'which' argument contains the index position
    -+               // of the selected item
    -+           }
    -+    });
    -+    return builder.create();
    -+}
    -+</pre>
    -+
    -+<p>Karena daftar muncul dalam area konten dialog,
    -+dialog tidak bisa menampilkan pesan dan daftar sekaligus dan Anda harus menetapkan judul untuk
    -+dialog dengan {@link android.app.AlertDialog.Builder#setTitle setTitle()}.
    -+Untuk menentukan item daftar, panggil {@link
    -+android.app.AlertDialog.Builder#setItems setItems()}, dengan meneruskan larik.
    -+Atau, Anda bisa menetapkan daftar menggunakan {@link
    -+android.app.AlertDialog.Builder#setAdapter setAdapter()}. Hal ini memungkinkan Anda mendukung daftar
    -+dengan data dinamis (seperti dari database) dengan menggunakan {@link android.widget.ListAdapter}.</p>
    -+
    -+<p>Jika Anda memilih untuk mendukung daftar dengan {@link android.widget.ListAdapter},
    -+selalu gunakan sebuah {@link android.support.v4.content.Loader} agar konten dimuat
    -+secara asinkron. Hal ini dijelaskan lebih jauh dalam panduan
    -+<a href="{@docRoot}guide/topics/ui/declaring-layout.html#AdapterViews">Membuat Layout
    -+dengan Adaptor</a> dan <a href="{@docRoot}guide/components/loaders.html">Loader</a>
    -+.</p>
    -+
    -+<p class="note"><strong>Catatan:</strong> Secara default, menyentuh sebuah item daftar akan menutup dialog,
    -+kecuali Anda menggunakan salah satu daftar pilihan persisten berikut ini.</p>
    -+
    -+<div class="figure" style="width:290px;margin:-30px 0 0 40px">
    -+<img src="{@docRoot}images/ui/dialog_checkboxes.png" />
    -+<p class="img-caption"><strong>Gambar 4.</strong>
    -+Daftar item pilihan ganda.</p>
    -+</div>
    -+
    -+
    -+<h4 id="Checkboxes">Menambahkan daftar pilihan ganda atau pilihan tunggal persisten</h4>
    -+
    -+<p>Untuk menambahkan daftar item pilihan ganda (kotak cek) atau
    -+item pilihan tunggal (tombol radio), gunakan masing-masing metode
    -+{@link android.app.AlertDialog.Builder#setMultiChoiceItems(Cursor,String,String,
    -+DialogInterface.OnMultiChoiceClickListener) setMultiChoiceItems()}, atau
    -+{@link android.app.AlertDialog.Builder#setSingleChoiceItems(int,int,DialogInterface.OnClickListener)
    -+setSingleChoiceItems()}.</p>
    -+
    -+<p>Misalnya, berikut ini cara membuat daftar pilihan ganda seperti
    -+yang ditampilkan dalam gambar 4 yang menyimpan item
    -+yang dipilih dalam {@link java.util.ArrayList}:</p>
    -+
    -+<pre style="clear:right">
    -+&#64;Override
    -+public Dialog onCreateDialog(Bundle savedInstanceState) {
    -+    mSelectedItems = new ArrayList();  // Where we track the selected items
    -+    AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
    -+    // Set the dialog title
    -+    builder.setTitle(R.string.pick_toppings)
    -+    // Specify the list array, the items to be selected by default (null for none),
    -+    // and the listener through which to receive callbacks when items are selected
    -+           .setMultiChoiceItems(R.array.toppings, null,
    -+                      new DialogInterface.OnMultiChoiceClickListener() {
    -+               &#64;Override
    -+               public void onClick(DialogInterface dialog, int which,
    -+                       boolean isChecked) {
    -+                   if (isChecked) {
    -+                       // If the user checked the item, add it to the selected items
    -+                       mSelectedItems.add(which);
    -+                   } else if (mSelectedItems.contains(which)) {
    -+                       // Else, if the item is already in the array, remove it
    -+                       mSelectedItems.remove(Integer.valueOf(which));
    -+                   }
    -+               }
    -+           })
    -+    // Set the action buttons
    -+           .setPositiveButton(R.string.ok, new DialogInterface.OnClickListener() {
    -+               &#64;Override
    -+               public void onClick(DialogInterface dialog, int id) {
    -+                   // User clicked OK, so save the mSelectedItems results somewhere
    -+                   // or return them to the component that opened the dialog
    -+                   ...
    -+               }
    -+           })
    -+           .setNegativeButton(R.string.cancel, new DialogInterface.OnClickListener() {
    -+               &#64;Override
    -+               public void onClick(DialogInterface dialog, int id) {
    -+                   ...
    -+               }
    -+           });
    -+
    -+    return builder.create();
    -+}
    -+</pre>
    -+
    -+<p>Walaupun daftar tradisional maupun daftar dengan tombol radio
    -+menyediakan tindakan "pilihan tunggal", Anda harus menggunakan {@link
    -+android.app.AlertDialog.Builder#setSingleChoiceItems(int,int,DialogInterface.OnClickListener)
    -+setSingleChoiceItems()} jika ingin mempertahankan pilihan pengguna.
    -+Yakni, jika nanti membuka dialog lagi untuk menunjukkan pilihan pengguna,
    -+maka Anda perlu membuat daftar dengan tombol radio.</p>
    -+
    -+
    -+
    -+
    -+
    -+<h3 id="CustomLayout">Membuat Layout Custom</h3>
    -+
    -+<div class="figure" style="width:290px;margin:-30px 0 0 40px">
    -+<img src="{@docRoot}images/ui/dialog_custom.png" alt="" />
    -+<p class="img-caption"><strong>Gambar 5.</strong> Layout dialog custom.</p>
    -+</div>
    -+
    -+<p>Jika Anda menginginkan layout custom dalam dialog, buatlah layout dan tambahkan ke
    -+{@link android.app.AlertDialog} dengan memanggil {@link
    -+android.app.AlertDialog.Builder#setView setView()} pada objek {@link
    -+android.app.AlertDialog.Builder} Anda.</p>
    -+
    -+<p>Secara default, layout custom akan mengisi jendela dialog, namun Anda masih bisa
    -+menggunakan metode {@link android.app.AlertDialog.Builder} untuk menambahkan tombol dan judul.</p>
    -+
    -+<p>Misalnya, berikut ini adalah file layout untuk dialog dalam Gambar 5:</p>
    -+
    -+<p style="clear:right" class="code-caption">res/layout/dialog_signin.xml</p>
    -+<pre>
    -+&lt;LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    -+    android:orientation="vertical"
    -+    android:layout_width="wrap_content"
    -+    android:layout_height="wrap_content">
    -+    &lt;ImageView
    -+        android:src="@drawable/header_logo"
    -+        android:layout_width="match_parent"
    -+        android:layout_height="64dp"
    -+        android:scaleType="center"
    -+        android:background="#FFFFBB33"
    -+        android:contentDescription="@string/app_name" />
    -+    &lt;EditText
    -+        android:id="@+id/username"
    -+        android:inputType="textEmailAddress"
    -+        android:layout_width="match_parent"
    -+        android:layout_height="wrap_content"
    -+        android:layout_marginTop="16dp"
    -+        android:layout_marginLeft="4dp"
    -+        android:layout_marginRight="4dp"
    -+        android:layout_marginBottom="4dp"
    -+        android:hint="@string/username" />
    -+    &lt;EditText
    -+        android:id="@+id/password"
    -+        android:inputType="textPassword"
    -+        android:layout_width="match_parent"
    -+        android:layout_height="wrap_content"
    -+        android:layout_marginTop="4dp"
    -+        android:layout_marginLeft="4dp"
    -+        android:layout_marginRight="4dp"
    -+        android:layout_marginBottom="16dp"
    -+        android:fontFamily="sans-serif"
    -+        android:hint="@string/password"/>
    -+&lt;/LinearLayout>
    -+</pre>
    -+
    -+<p class="note"><strong>Tip:</strong> Secara default, bila Anda telah mengatur sebuah elemen {@link android.widget.EditText}
    -+agar menggunakan tipe input {@code "textPassword"}, keluarga font akan diatur ke spasi tunggal, sehingga
    -+Anda harus mengubah keluarga font ke {@code "sans-serif"} sehingga kedua bidang teks menggunakan
    -+gaya font yang cocok.</p>
    -+
    -+<p>Untuk memekarkan layout dalam {@link android.support.v4.app.DialogFragment} Anda,
    -+ambillah {@link android.view.LayoutInflater} dengan
    -+{@link android.app.Activity#getLayoutInflater()} dan panggil
    -+{@link android.view.LayoutInflater#inflate inflate()}, dengan parameter pertama
    -+adalah ID sumber daya layout dan parameter kedua adalah tampilan induk untuk layout.
    -+Selanjutnya Anda bisa memanggil {@link android.app.AlertDialog#setView setView()}
    -+untuk menempatkan layout dalam dialog.</p>
    -+
    -+<pre>
    -+&#64;Override
    -+public Dialog onCreateDialog(Bundle savedInstanceState) {
    -+    AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
    -+    // Get the layout inflater
    -+    LayoutInflater inflater = getActivity().getLayoutInflater();
    -+
    -+    // Inflate and set the layout for the dialog
    -+    // Pass null as the parent view because its going in the dialog layout
    -+    builder.setView(inflater.inflate(R.layout.dialog_signin, null))
    -+    // Add action buttons
    -+           .setPositiveButton(R.string.signin, new DialogInterface.OnClickListener() {
    -+               &#64;Override
    -+               public void onClick(DialogInterface dialog, int id) {
    -+                   // sign in the user ...
    -+               }
    -+           })
    -+           .setNegativeButton(R.string.cancel, new DialogInterface.OnClickListener() {
    -+               public void onClick(DialogInterface dialog, int id) {
    -+                   LoginDialogFragment.this.getDialog().cancel();
    -+               }
    -+           });
    -+    return builder.create();
    -+}
    -+</pre>
    -+
    -+<div class="note">
    -+<p><strong>Tip:</strong> Jika Anda menginginkan dialog custom,
    -+Anda bisa menampilkan {@link android.app.Activity} sebagai dialog
    -+daripada menggunakan API {@link android.app.Dialog}. Cukup buat satu aktivitas dan mengatur temanya ke
    -+{@link android.R.style#Theme_Holo_Dialog Theme.Holo.Dialog}
    -+di elemen manifes <a href="{@docRoot}guide/topics/manifest/activity-element.html">{@code
    -+&lt;activity&gt;}</a>:</p>
    -+
    -+<pre>
    -+&lt;activity android:theme="&#64;android:style/Theme.Holo.Dialog" >
    -+</pre>
    -+<p>Demikian saja. Aktivitas sekarang ditampilkan dalam jendela dialog, sebagai ganti layar penuh.</p>
    -+</div>
    -+
    -+
    -+
    -+<h2 id="PassingEvents">Meneruskan Kejadian Kembali ke Host Dialog</h2>
    -+
    -+<p>Bila pengguna menyentuh salah satu tombol tindakan dialog atau memilih satu item dari daftarnya,
    -+{@link android.support.v4.app.DialogFragment} Anda bisa melakukan sendiri tindakan yang diperlukan
    -+, namun sering kali Anda perlu mengirim kejadian itu ke aktivitas atau fragmen yang
    -+membuka dialog. Caranya, definisikan antarmuka dengan sebuah metode untuk masing-masing tipe kejadian klik.
    -+Lalu implementasikan antarmuka itu dalam komponen host yang akan
    -+menerima kejadian tindakan dari dialog.</p>
    -+
    -+<p>Misalnya, berikut ini adalah {@link android.support.v4.app.DialogFragment} yang mendefinisikan
    -+antarmuka yang akan digunakan untuk mengirim kembali suatu kejadian ke aktivitas host:</p>
    -+
    -+<pre>
    -+public class NoticeDialogFragment extends DialogFragment {
    -+
    -+    /* The activity that creates an instance of this dialog fragment must
    -+     * implement this interface in order to receive event callbacks.
    -+     * Each method passes the DialogFragment in case the host needs to query it. */
    -+    public interface NoticeDialogListener {
    -+        public void onDialogPositiveClick(DialogFragment dialog);
    -+        public void onDialogNegativeClick(DialogFragment dialog);
    -+    }
    -+
    -+    // Use this instance of the interface to deliver action events
    -+    NoticeDialogListener mListener;
    -+
    -+    // Override the Fragment.onAttach() method to instantiate the NoticeDialogListener
    -+    &#64;Override
    -+    public void onAttach(Activity activity) {
    -+        super.onAttach(activity);
    -+        // Verify that the host activity implements the callback interface
    -+        try {
    -+            // Instantiate the NoticeDialogListener so we can send events to the host
    -+            mListener = (NoticeDialogListener) activity;
    -+        } catch (ClassCastException e) {
    -+            // The activity doesn't implement the interface, throw exception
    -+            throw new ClassCastException(activity.toString()
    -+                    + " must implement NoticeDialogListener");
    -+        }
    -+    }
    -+    ...
    -+}
    -+</pre>
    -+
    -+<p>Aktivitas yang menjadi host dialog tersebut akan membuat instance dialog
    -+dengan konstruktor fragmen dialog dan menerima kejadian dialog
    -+melalui implementasi antarmuka {@code NoticeDialogListener}:</p>
    -+
    -+<pre>
    -+public class MainActivity extends FragmentActivity
    -+                          implements NoticeDialogFragment.NoticeDialogListener{
    -+    ...
    -+
    -+    public void showNoticeDialog() {
    -+        // Create an instance of the dialog fragment and show it
    -+        DialogFragment dialog = new NoticeDialogFragment();
    -+        dialog.show(getSupportFragmentManager(), "NoticeDialogFragment");
    -+    }
    -+
    -+    // The dialog fragment receives a reference to this Activity through the
    -+    // Fragment.onAttach() callback, which it uses to call the following methods
    -+    // defined by the NoticeDialogFragment.NoticeDialogListener interface
    -+    &#64;Override
    -+    public void onDialogPositiveClick(DialogFragment dialog) {
    -+        // User touched the dialog's positive button
    -+        ...
    -+    }
    -+
    -+    &#64;Override
    -+    public void onDialogNegativeClick(DialogFragment dialog) {
    -+        // User touched the dialog's negative button
    -+        ...
    -+    }
    -+}
    -+</pre>
    -+
    -+<p>Karena aktivitas host mengimplementasikan {@code NoticeDialogListener}&mdash;yang
    -+diberlakukan oleh metode callback {@link android.support.v4.app.Fragment#onAttach onAttach()}
    -+di atas,&mdash;fragmen dialog bisa menggunakan
    -+metode callback antarmuka untuk mengirimkan kejadian klik ke aktivitas:</p>
    -+
    -+<pre>
    -+public class NoticeDialogFragment extends DialogFragment {
    -+    ...
    -+
    -+    &#64;Override
    -+    public Dialog onCreateDialog(Bundle savedInstanceState) {
    -+        // Build the dialog and set up the button click handlers
    -+        AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
    -+        builder.setMessage(R.string.dialog_fire_missiles)
    -+               .setPositiveButton(R.string.fire, new DialogInterface.OnClickListener() {
    -+                   public void onClick(DialogInterface dialog, int id) {
    -+                       // Send the positive button event back to the host activity
    -+                       mListener.onDialogPositiveClick(NoticeDialogFragment.this);
    -+                   }
    -+               })
    -+               .setNegativeButton(R.string.cancel, new DialogInterface.OnClickListener() {
    -+                   public void onClick(DialogInterface dialog, int id) {
    -+                       // Send the negative button event back to the host activity
    -+                       mListener.onDialogNegativeClick(NoticeDialogFragment.this);
    -+                   }
    -+               });
    -+        return builder.create();
    -+    }
    -+}
    -+</pre>
    -+
    -+
    -+
    -+<h2 id="ShowingADialog">Menampilkan Dialog</h2>
    -+
    -+<p>Bila Anda ingin menampilkan dialog, buatlah instance {@link
    -+android.support.v4.app.DialogFragment} dan panggil {@link android.support.v4.app.DialogFragment#show
    -+show()}, dengan meneruskan {@link android.support.v4.app.FragmentManager} dan nama tag
    -+untuk fragmen dialognya.</p>
    -+
    -+<p>Anda bisa mendapatkan {@link android.support.v4.app.FragmentManager} dengan memanggil
    -+{@link android.support.v4.app.FragmentActivity#getSupportFragmentManager()} dari
    -+ {@link android.support.v4.app.FragmentActivity} atau {@link
    -+android.support.v4.app.Fragment#getFragmentManager()} dari {@link
    -+android.support.v4.app.Fragment}. Misalnya:</p>
    -+
    -+<pre>
    -+public void confirmFireMissiles() {
    -+    DialogFragment newFragment = new FireMissilesDialogFragment();
    -+    newFragment.show(getSupportFragmentManager(), "missiles");
    -+}
    -+</pre>
    -+
    -+<p>Argumen kedua, {@code "missiles"}, adalah nama tag unik yang digunakan sistem untuk menyimpan
    -+dan memulihkan status fragmen bila diperlukan. Tag ini juga memungkinkan Anda mendapatkan handle ke
    -+fragmen dengan memanggil {@link android.support.v4.app.FragmentManager#findFragmentByTag
    -+findFragmentByTag()}.</p>
    -+
    -+
    -+
    -+
    -+<h2 id="FullscreenDialog">Menampilkan Dialog sebagai Layar Penuh atau Fragmen Tertanam</h2>
    -+
    -+<p>Anda mungkin memiliki desain UI yang di dalamnya Anda ingin UI muncul sebagai dialog dalam beberapa
    -+situasi, namun sebagai layar penuh atau fragmen tertanam dalam situasi lain (mungkin bergantung pada apakah
    -+perangkat memiliki layar besar atau layar kecil). Kelas {@link android.support.v4.app.DialogFragment}
    -+menawarkan fleksibilitas ini karena masih bisa berperilaku sebagai {@link
    -+android.support.v4.app.Fragment} yang bisa ditanamkan.</p>
    -+
    -+<p>Akan tetapi, dalam hal ini Anda tidak bisa menggunakan {@link android.app.AlertDialog.Builder AlertDialog.Builder}
    -+atau objek {@link android.app.Dialog} lain untuk membangun dialog. Jika
    -+Anda ingin {@link android.support.v4.app.DialogFragment}
    -+bisa ditanamkan, Anda harus mendefinisikan dialog UI dalam layout, lalu memuat layout itu dalam metode callback
    -+{@link android.support.v4.app.DialogFragment#onCreateView
    -+onCreateView()}.</p>
    -+
    -+<p>Berikut ini adalah contoh {@link android.support.v4.app.DialogFragment} yang bisa muncul sebagai
    -+dialog maupun fragmen yang bisa ditanamkan (menggunakan layout bernama <code>purchase_items.xml</code>):</p>
    -+
    -+<pre>
    -+public class CustomDialogFragment extends DialogFragment {
    -+    /** The system calls this to get the DialogFragment's layout, regardless
    -+        of whether it's being displayed as a dialog or an embedded fragment. */
    -+    &#64;Override
    -+    public View onCreateView(LayoutInflater inflater, ViewGroup container,
    -+            Bundle savedInstanceState) {
    -+        // Inflate the layout to use as dialog or embedded fragment
    -+        return inflater.inflate(R.layout.purchase_items, container, false);
    -+    }
    -+
    -+    /** The system calls this only when creating the layout in a dialog. */
    -+    &#64;Override
    -+    public Dialog onCreateDialog(Bundle savedInstanceState) {
    -+        // The only reason you might override this method when using onCreateView() is
    -+        // to modify any dialog characteristics. For example, the dialog includes a
    -+        // title by default, but your custom layout might not need it. So here you can
    -+        // remove the dialog title, but you must call the superclass to get the Dialog.
    -+        Dialog dialog = super.onCreateDialog(savedInstanceState);
    -+        dialog.requestWindowFeature(Window.FEATURE_NO_TITLE);
    -+        return dialog;
    -+    }
    -+}
    -+</pre>
    -+
    -+<p>Dan berikut ini adalah beberapa kode yang memutuskan apakah akan menampilkan fragmen sebagai dialog
    -+atau UI layar penuh, berdasarkan ukuran layar:</p>
    -+
    -+<pre>
    -+public void showDialog() {
    -+    FragmentManager fragmentManager = getSupportFragmentManager();
    -+    CustomDialogFragment newFragment = new CustomDialogFragment();
    -+
    -+    if (mIsLargeLayout) {
    -+        // The device is using a large layout, so show the fragment as a dialog
    -+        newFragment.show(fragmentManager, "dialog");
    -+    } else {
    -+        // The device is smaller, so show the fragment fullscreen
    -+        FragmentTransaction transaction = fragmentManager.beginTransaction();
    -+        // For a little polish, specify a transition animation
    -+        transaction.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN);
    -+        // To make it fullscreen, use the 'content' root view as the container
    -+        // for the fragment, which is always the root view for the activity
    -+        transaction.add(android.R.id.content, newFragment)
    -+                   .addToBackStack(null).commit();
    -+    }
    -+}
    -+</pre>
    -+
    -+<p>Untuk informasi selengkapnya tentang melakukan transaksi fragmen, lihat panduan
    -+<a href="{@docRoot}guide/components/fragments.html">Fragmen</a>.</p>
    -+
    -+<p>Dalam contoh ini, nilai boolean <code>mIsLargeLayout</code> menentukan apakah perangkat saat ini
    -+harus menggunakan desain layout besar aplikasi (dan dengan demikian menampilkan fragmen ini sebagai dialog, bukan
    -+layar penuh). Cara terbaik untuk mengatur jenis boolean ini adalah mendeklarasikan
    -+<a href="{@docRoot}guide/topics/resources/more-resources.html#Bool">nilai sumber daya boolean</a>
    -+dengan nilai <a href="{@docRoot}guide/topics/resources/providing-resources.html#AlternativeResources">sumber daya alternatif</a> untuk berbagai ukuran layar. Misalnya, berikut ini adalah dua
    -+versi sumber daya boolean untuk berbagai ukuran layar:</p>
    -+
    -+<p class="code-caption">res/values/bools.xml</p>
    -+<pre>
    -+&lt;!-- Default boolean values -->
    -+&lt;resources>
    -+    &lt;bool name="large_layout">false&lt;/bool>
    -+&lt;/resources>
    -+</pre>
    -+
    -+<p class="code-caption">res/values-large/bools.xml</p>
    -+<pre>
    -+&lt;!-- Large screen boolean values -->
    -+&lt;resources>
    -+    &lt;bool name="large_layout">true&lt;/bool>
    -+&lt;/resources>
    -+</pre>
    -+
    -+<p>Selanjutnya Anda bisa menetapkan nilai {@code mIsLargeLayout} selama
    -+metode {@link android.app.Activity#onCreate onCreate()} aktivitas:</p>
    -+
    -+<pre>
    -+boolean mIsLargeLayout;
    -+
    -+&#64;Override
    -+public void onCreate(Bundle savedInstanceState) {
    -+    super.onCreate(savedInstanceState);
    -+    setContentView(R.layout.activity_main);
    -+
    -+    mIsLargeLayout = getResources().getBoolean(R.bool.large_layout);
    -+}
    -+</pre>
    -+
    -+
    -+
    -+<h3 id="ActivityAsDialog">Menampilkan aktivitas sebagai dialog pada layar besar</h3>
    -+
    -+<p>Sebagai ganti menampilkan dialog berupa UI layar penuh saat di layar kecil, Anda bisa memperoleh
    -+hasil yang sama dengan menampilkan {@link android.app.Activity} sebagai dialog saat di
    -+layar besar. Pendekatan yang Anda pilih bergantung pada desain aplikasi, namun
    -+menampilkan aktivitas sebagai dialog sering kali berguna bila aplikasi Anda sudah didesain untuk
    -+layar kecil dan Anda ingin meningkatkan pengalaman pada tablet dengan menampilkan aktivitas berjangka pendek
    -+sebagai dialog.</p>
    -+
    -+<p>Untuk menampilkan aktivitas sebagai dialog hanya saat di layar besar,
    -+terapkan tema {@link android.R.style#Theme_Holo_DialogWhenLarge Theme.Holo.DialogWhenLarge}
    -+ pada elemen manifes <a href="{@docRoot}guide/topics/manifest/activity-element.html">{@code
    -+&lt;activity&gt;}</a>:</p>
    -+
    -+<pre>
    -+&lt;activity android:theme="&#64;android:style/Theme.Holo.DialogWhenLarge" >
    -+</pre>
    -+
    -+<p>Untuk informasi selengkapnya tentang mengatur gaya aktivitas Anda dengan tema, lihat panduan <a href="{@docRoot}guide/topics/ui/themes.html">Gaya dan Tema</a>.</p>
    -+
    -+
    -+
    -+<h2 id="DismissingADialog">Menutup Dialog</h2>
    -+
    -+<p>Bila pengguna menyentuh salah satu tombol tindakan yang dibuat dengan
    -+{@link android.app.AlertDialog.Builder}, sistem akan menutup dialog untuk Anda.</p>
    -+
    -+<p>Sistem juga menutup dialog bila pengguna menyentuh sebuah item dalam daftar dialog, kecuali
    -+bila daftar itu menggunakan tombol radio atau kotak cek. Jika tidak, Anda bisa menutup dialog secara manual
    -+dengan memanggil {@link android.support.v4.app.DialogFragment#dismiss()} pada {@link
    -+android.support.v4.app.DialogFragment} Anda.</p>
    -+
    -+<p>Jika Anda perlu melakukan
    -+tindakan tertentu saat dialog menghilang, Anda bisa menerapkan metode {@link
    -+android.support.v4.app.DialogFragment#onDismiss onDismiss()} dalam {@link
    -+android.support.v4.app.DialogFragment} Anda.</p>
    -+
    -+<p>Anda juga bisa <em>membatalkan</em> dialog. Ini merupakan kejadian khusus yang menunjukkan bahwa pengguna
    -+secara eksplisit meninggalkan dialog tanpa menyelesaikan tugas. Hal ini terjadi jika pengguna menekan tombol
    -+<em>Back</em>, menyentuh layar di luar area dialog,
    -+atau jika Anda secara eksplisit memanggil {@link android.app.Dialog#cancel()} pada {@link
    -+android.app.Dialog} (seperti saat merespons tombol "Cancel" dalam dialog).</p>
    -+
    -+<p>Seperti yang ditampilkan dalam contoh di atas, Anda bisa merespons kejadian batal dengan menerapkan
    -+{@link android.support.v4.app.DialogFragment#onCancel onCancel()} dalam kelas {@link
    -+android.support.v4.app.DialogFragment} Anda.</p>
    -+
    -+<p class="note"><strong>Catatan:</strong> Sistem akan memanggil
    -+{@link android.support.v4.app.DialogFragment#onDismiss onDismiss()} pada tiap kejadian yang
    -+memanggil callback {@link android.support.v4.app.DialogFragment#onCancel onCancel()}. Akan tetapi,
    -+jika Anda memanggil {@link android.app.Dialog#dismiss Dialog.dismiss()} atau {@link
    -+android.support.v4.app.DialogFragment#dismiss DialogFragment.dismiss()},
    -+sistem akan memanggil {@link android.support.v4.app.DialogFragment#onDismiss onDismiss()} <em>namun
    -+bukan</em> {@link android.support.v4.app.DialogFragment#onCancel onCancel()}. Jadi biasanya Anda harus
    -+memanggil {@link android.support.v4.app.DialogFragment#dismiss dismiss()} bila pengguna menekan tombol
    -+<em>positif</em> dalam dialog untuk menghilangkan tampilan dialog.</p>
    -+
    -+
    -diff --git a/docs/html-intl/intl/id/guide/topics/ui/menus.jd b/docs/html-intl/intl/id/guide/topics/ui/menus.jd
    -new file mode 100644
    -index 0000000..1ee0244
    ---- /dev/null
    -+++ b/docs/html-intl/intl/id/guide/topics/ui/menus.jd
    -@@ -0,0 +1,1031 @@
    -+page.title=Menu
    -+parent.title=Antarmuka Pengguna
    -+parent.link=index.html
    -+@jd:body
    -+
    -+<div id="qv-wrapper">
    -+<div id="qv">
    -+  <h2>Dalam dokumen ini</h2>
    -+<ol>
    -+  <li><a href="#xml">Mendefinisikan Menu dalam XML</a></li>
    -+  <li><a href="#options-menu">Membuat Menu Opsi</a>
    -+    <ol>
    -+      <li><a href="#RespondingOptionsMenu">Menangani kejadian klik</a></li>
    -+      <li><a href="#ChangingTheMenu">Mengubah item menu saat runtime</a></li>
    -+    </ol>
    -+  </li>
    -+  <li><a href="#context-menu">Membuat Menu Kontekstual</a>
    -+    <ol>
    -+      <li><a href="#FloatingContextMenu">Membuat menu konteks mengambang</a></li>
    -+      <li><a href="#CAB">Menggunakan mode tindakan kontekstual</a></li>
    -+    </ol>
    -+  </li>
    -+  <li><a href="#PopupMenu">Membuat Menu Popup</a>
    -+    <ol>
    -+      <li><a href="#PopupEvents">Menangani kejadian klik</a></li>
    -+    </ol>
    -+  </li>
    -+  <li><a href="#groups">Membuat Grup Menu</a>
    -+    <ol>
    -+      <li><a href="#checkable">Menggunakan item menu yang bisa diberi tanda cek</a></li>
    -+    </ol>
    -+  </li>
    -+  <li><a href="#intents">Menambahkan Item Menu Berdasarkan Intent</a>
    -+    <ol>
    -+      <li><a href="#AllowingToAdd">Memungkinkan aktivitas Anda ditambahkan ke menu lain</a></li>
    -+    </ol>
    -+  </li>
    -+</ol>
    -+
    -+  <h2>Kelas-kelas utama</h2>
    -+  <ol>
    -+    <li>{@link android.view.Menu}</li>
    -+    <li>{@link android.view.MenuItem}</li>
    -+    <li>{@link android.view.ContextMenu}</li>
    -+    <li>{@link android.view.ActionMode}</li>
    -+  </ol>
    -+
    -+  <h2>Lihat juga</h2>
    -+  <ol>
    -+    <li><a href="{@docRoot}guide/topics/ui/actionbar.html">Action-Bar</a></li>
    -+    <li><a href="{@docRoot}guide/topics/resources/menu-resource.html">Sumber Daya Menu</a></li>
    -+    <li><a href="http://android-developers.blogspot.com/2012/01/say-goodbye-to-menu-button.html">Ucapkan
    -+Selamat Tinggal pada Tombol Menu</a></li>
    -+  </ol>
    -+</div>
    -+</div>
    -+
    -+<p>Menu adalah komponen antarmuka pengguna yang lazim dalam banyak tipe aplikasi. Untuk menyediakan pengalaman pengguna yang sudah akrab
    -+dan konsisten, Anda harus menggunakan API {@link android.view.Menu} untuk menyajikan
    -+tindakan dan opsi lain dalam aktivitas kepada pengguna.</p>
    -+
    -+<p>Mulai dengan Android 3.0 (API level 11), perangkat berbasis Android tidak perlu lagi
    -+menyediakan tombol <em>Menu</em> tersendiri. Dengan perubahan ini, aplikasi Android harus bermigrasi dari
    -+dependensi pada panel menu 6 item biasa, dan sebagai ganti menyediakan action-bar untuk menyajikan
    -+berbagai tindakan pengguna yang lazim.</p>
    -+
    -+<p>Walaupun desain dan pengalaman pengguna untuk sebagian item menu telah berubah, semantik untuk mendefinisikan
    -+serangkaian tindakan dan opsi masih berdasarkan pada API {@link android.view.Menu}. Panduan ini
    -+menampilkan cara membuat tiga tipe dasar penyajian menu atau tindakan pada semua
    -+versi Android:</p>
    -+
    -+<dl>
    -+  <dt><strong>Menu opsi dan action-bar</strong></dt>
    -+    <dd><a href="#options-menu">Menu opsi</a> adalah kumpulan item menu utama untuk suatu
    -+aktivitas. Inilah tempat Anda harus menempatkan tindakan yang berdampak global pada aplikasi, seperti
    -+"Cari", "Tulis email", dan "Pengaturan".
    -+  <p>Jika Anda mengembangkan aplikasi untuk Android 2.3 atau yang lebih rendah, pengguna bisa
    -+menampilkan panel menu opsi dengan menekan tombol <em>Menu</em>.</p>
    -+  <p>Pada Android 3.0 dan yang lebih tinggi, item menu opsi disajikan melalui <a href="{@docRoot}guide/topics/ui/actionbar.html">action-bar</a> sebagai kombinasi item tindakan
    -+di layar dan opsi overflow. Mulai dengan Android 3.0, tombol <em>Menu</em> dihilangkan (sebagian
    -+perangkat
    -+tidak memilikinya), sehingga Anda harus bermigrasi ke penggunaan action-bar untuk menyediakan akses ke tindakan dan
    -+opsi lainnya.</p>
    -+  <p>Lihat bagian tentang <a href="#options-menu">Membuat Menu Opsi</a>.</p>
    -+    </dd>
    -+
    -+  <dt><strong>Menu konteks dan mode tindakan kontekstual</strong></dt>
    -+
    -+   <dd>Menu konteks adalah <a href="#FloatingContextMenu">menu mengambang</a> yang muncul saat
    -+pengguna mengklik lama pada suatu elemen. Menu ini menyediakan tindakan yang memengaruhi konten atau
    -+bingkai konteks yang dipilih.
    -+  <p>Saat mengembangkan aplikasi untuk Android 3.0 dan yang lebih tinggi, sebagai gantinya Anda harus menggunakan <a href="#CAB">mode tindakan kontekstual</a> untuk memungkinkan tindakan pada konten yang dipilih. Mode ini menampilkan
    -+item tindakan yang memengaruhi konten yang dipilih dalam baris di bagian atas layar dan memungkinkan pengguna
    -+memilih beberapa item sekaligus.</p>
    -+  <p>Lihat bagian tentang <a href="#context-menu">Membuat Menu Kontekstual</a>.</p>
    -+</dd>
    -+
    -+  <dt><strong>Menu popup</strong></dt>
    -+    <dd>Menu popup menampilkan daftar item secara vertikal yang dipasang pada tampilan yang
    -+memanggil menu. Ini cocok untuk menyediakan kelebihan tindakan yang terkait dengan konten tertentu atau
    -+untuk menyediakan opsi bagi bagian kedua dari suatu perintah. Tindakan di menu popup
    -+<strong>tidak</strong> boleh memengaruhi secara langsung konten yang bersangkutan&mdash;yang diperuntukkan bagi
    -+tindakan kontekstual. Melainkan, menu popup adalah untuk tindakan tambahan yang terkait dengan wilayah konten dalam
    -+aktivitas Anda.
    -+  <p>Lihat bagian tentang <a href="#PopupMenu">Membuat Menu Popup</a>.</p>
    -+</dd>
    -+</dl>
    -+
    -+
    -+
    -+<h2 id="xml">Mendefinisikan Menu dalam XML</h2>
    -+
    -+<p>Untuk semua tipe menu, Android menyediakan sebuah format XML standar untuk mendefinisikan item menu.
    -+Sebagai ganti membuat menu dalam kode aktivitas, Anda harus mendefinisikan menu dan semua itemnya dalam
    -+<a href="{@docRoot}guide/topics/resources/menu-resource.html">sumber daya menu</a> XML. Anda kemudian bisa
    -+memekarkan sumber daya menu (memuatnya sebagai objek {@link android.view.Menu}) dalam aktivitas atau
    -+fragmen.</p>
    -+
    -+<p>Menggunakan sumber daya menu adalah praktik yang baik karena beberapa alasan:</p>
    -+<ul>
    -+  <li>Memvisualisasikan struktur menu dalam XML menjadi lebih mudah.</li>
    -+  <li>Cara ini memisahkan konten untuk menu dari kode perilaku aplikasi Anda.</li>
    -+  <li>Cara ini memungkinkan Anda membuat konfigurasi menu alternatif untuk berbagai versi platform,
    -+ukuran layar, dan konfigurasi lainnya dengan memanfaatkan kerangka kerja <a href="{@docRoot}guide/topics/resources/index.html">sumber daya aplikasi</a>.</li>
    -+</ul>
    -+
    -+<p>Untuk mendefinisikan menu, buatlah sebuah file XML dalam direktori <code>res/menu/</code>
    -+proyek dan buat menu dengan elemen-elemen berikut:</p>
    -+<dl>
    -+  <dt><code>&lt;menu></code></dt>
    -+    <dd>Mendefinisikan {@link android.view.Menu}, yang merupakan sebuah kontainer untuk item menu. Elemen
    -+<code>&lt;menu></code> harus menjadi simpul akar untuk file dan bisa menampung salah satu atau beberapa dari elemen
    -+<code>&lt;item></code> dan <code>&lt;group></code>.</dd>
    -+
    -+  <dt><code>&lt;item></code></dt>
    -+    <dd>Membuat {@link android.view.MenuItem}, yang mewakili satu item menu. Elemen ini
    -+bisa berisi elemen <code>&lt;menu></code> tersarang guna untuk membuat submenu.</dd>
    -+
    -+  <dt><code>&lt;group></code></dt>
    -+    <dd>Kontainer opsional tak terlihat untuk elemen-elemen {@code &lt;item&gt;}. Kontainer ini memungkinkan Anda
    -+mengelompokkan item menu untuk berbagi properti seperti status aktif dan visibilitas. Untuk informasi
    -+selengkapnya, lihat bagian tentang <a href="#groups">Membuat Grup Menu</a>.</dd>
    -+</dl>
    -+
    -+
    -+<p>Berikut ini adalah contoh menu bernama <code>game_menu.xml</code>:</p>
    -+<pre>
    -+&lt;?xml version="1.0" encoding="utf-8"?&gt;
    -+&lt;menu xmlns:android="http://schemas.android.com/apk/res/android"&gt;
    -+    &lt;item android:id="@+id/new_game"
    -+          android:icon="@drawable/ic_new_game"
    -+          android:title="@string/new_game"
    -+          android:showAsAction="ifRoom"/&gt;
    -+    &lt;item android:id="@+id/help"
    -+          android:icon="@drawable/ic_help"
    -+          android:title="@string/help" /&gt;
    -+&lt;/menu&gt;
    -+</pre>
    -+
    -+<p>Elemen <code>&lt;item></code> mendukung beberapa atribut yang bisa Anda gunakan untuk mendefinisikan penampilan dan perilaku
    -+item. Item menu di atas mencakup atribut berikut:</p>
    -+
    -+<dl>
    -+  <dt>{@code android:id}</dt>
    -+    <dd>ID sumber daya unik bagi item, yang memungkinkan aplikasi mengenali item
    -+bila pengguna memilihnya.</dd>
    -+  <dt>{@code android:icon}</dt>
    -+    <dd>Acuan ke drawable untuk digunakan sebagai ikon item.</dd>
    -+  <dt>{@code android:title}</dt>
    -+    <dd>Acuan ke string untuk digunakan sebagai judul item.</dd>
    -+  <dt>{@code android:showAsAction}</dt>
    -+    <dd>Menetapkan waktu dan cara item ini muncul sebagai item tindakan di <a href="{@docRoot}guide/topics/ui/actionbar.html">action-bar</a>.</dd>
    -+</dl>
    -+
    -+<p>Ini adalah atribut-atribut terpenting yang harus Anda gunakan, namun banyak lagi yang tersedia.
    -+Untuk informasi tentang semua atribut yang didukung, lihat dokumen <a href="{@docRoot}guide/topics/resources/menu-resource.html">Sumber Daya Menu</a>.</p>
    -+
    -+<p>Anda bisa menambahkan submenu ke sebuah item di menu (kecuali submenu) apa saja dengan menambahkan elemen {@code &lt;menu&gt;}
    -+sebagai anak {@code &lt;item&gt;}. Submenu berguna saat aplikasi Anda memiliki banyak
    -+fungsi yang bisa ditata ke dalam topik-topik, seperti item dalam sebuah baris menu aplikasi PC (File,
    -+Edit, Lihat, dsb.). Misalnya:</p>
    -+
    -+<pre>
    -+&lt;?xml version="1.0" encoding="utf-8"?&gt;
    -+&lt;menu xmlns:android="http://schemas.android.com/apk/res/android"&gt;
    -+    &lt;item android:id="@+id/file"
    -+          android:title="@string/file" &gt;
    -+        &lt;!-- "file" submenu --&gt;
    -+        &lt;menu&gt;
    -+            &lt;item android:id="@+id/create_new"
    -+                  android:title="@string/create_new" /&gt;
    -+            &lt;item android:id="@+id/open"
    -+                  android:title="@string/open" /&gt;
    -+        &lt;/menu&gt;
    -+    &lt;/item&gt;
    -+&lt;/menu&gt;
    -+</pre>
    -+
    -+<p>Untuk menggunakan menu dalam aktivitas, Anda perlu memekarkan sumber daya menu (mengonversi sumber daya XML
    -+menjadi objek yang bisa diprogram) dengan menggunakan {@link android.view.MenuInflater#inflate(int,Menu)
    -+MenuInflater.inflate()}. Di bagian berikut, Anda akan melihat cara memekarkan menu untuk tiap
    -+tipe menu.</p>
    -+
    -+
    -+
    -+<h2 id="options-menu">Membuat Menu Opsi</h2>
    -+
    -+<div class="figure" style="width:200px;margin:0">
    -+  <img src="{@docRoot}images/options_menu.png" height="333" alt="" />
    -+  <p class="img-caption"><strong>Gambar 1.</strong> Menu opsi di
    -+Browser, pada Android 2.3.</p>
    -+</div>
    -+
    -+<p>Menu opsi adalah tempat Anda harus menyertakan tindakan dan opsi lain yang relevan dengan
    -+konteks aktivitas saat ini, seperti "Cari", "Tulis email", dan "Pengaturan".</p>
    -+
    -+<p>Tempat item dalam menu opsi muncul di layar bergantung pada versi aplikasi yang Anda
    -+kembangkan:</p>
    -+
    -+<ul>
    -+  <li>Jika Anda mengembangkan aplikasi untuk <strong>Android 2.3.x (API level 10) atau
    -+yang lebih rendah</strong>, konten menu opsi muncul pada bagian bawah layar bila pengguna
    -+menekan tombol <em>Menu</em>, seperti yang ditampilkan dalam gambar 1. Bila dibuka, bagian yang terlihat pertama adalah
    -+menu
    -+ikon, yang menampung hingga enam item menu. Jika menu Anda menyertakan lebih dari enam item, Android akan meletakkan
    -+item keenam dan sisanya ke dalam menu kelebihan, yang bisa dibuka pengguna dengan memilih
    -+<em>More</em>.</li>
    -+
    -+  <li>Jika Anda mengembangkan aplikasi untuk <strong>Android 3.0 (API level 11) dan
    -+yang lebih tinggi</strong>, item menu opsi tersedia dalam <a href="{@docRoot}guide/topics/ui/actionbar.html">action-bar</a>. Secara default, sistem
    -+meletakkan semua item dalam kelebihan tindakan, yang bisa ditampilkan pengguna dengan ikon kelebihan tindakan di
    -+sisi kanan action-bar (atau dengan menekan tombol <em>Menu</em> perangkat, jika tersedia). Untuk
    -+mengaktifkan
    -+akses cepat ke tindakan penting, Anda bisa mempromosikan beberapa item agar muncul pada action-bar dengan menambahkan
    -+{@code android:showAsAction="ifRoom"} ke elemen-elemen {@code &lt;item&gt;} yang bersangkutan (lihat gambar
    -+2). <p>Untuk informasi selengkapnya tentang item tindakan dan perilaku action-bar lainnya, lihat panduan <a href="{@docRoot}guide/topics/ui/actionbar.html">Action-Bar</a>. </p>
    -+<p class="note"><strong>Catatan:</strong> Sekalipun Anda <em>tidak</em> mengembangkan aplikasi untuk Android 3.0 atau
    -+yang lebih tinggi, Anda bisa membuat layout action-bar sendiri untuk mendapatkan efek serupa. Untuk contoh cara
    -+mendukung versi Android yang lebih lama dengan action-bar, lihat contoh <a href="{@docRoot}resources/samples/ActionBarCompat/index.html">Kompatibilitas Action-Bar</a>
    -+.</p>
    -+</li>
    -+</ul>
    -+
    -+<img src="{@docRoot}images/ui/actionbar.png" alt="" />
    -+<p class="img-caption"><strong>Gambar 2.</strong> Action-bar dari aplikasi <a href="{@docRoot}resources/samples/HoneycombGallery/index.html">Honeycomb Gallery</a>, yang menampilkan
    -+tab-tab navigasi dan item tindakan kamera (plus tombol kelebihan tindakan).</p>
    -+
    -+<p>Anda bisa mendeklarasikan item untuk menu opsi dari subkelas {@link android.app.Activity}
    -+atau subkelas {@link android.app.Fragment}. Jika aktivitas maupun fragmen Anda
    -+mendeklarasikan item menu opsi, keduanya akan dikombinasikan dalam UI. Item aktivitas akan muncul
    -+lebih dahulu, diikuti oleh item tiap fragmen sesuai dengan urutan penambahan fragmen ke
    -+aktivitas. Jika perlu, Anda bisa menyusun ulang item menu dengan atribut {@code android:orderInCategory}
    -+dalam setiap {@code &lt;item&gt;} yang perlu Anda pindahkan.</p>
    -+
    -+<p>Untuk menetapkan menu opsi suatu aktivitas, kesampingkan {@link
    -+android.app.Activity#onCreateOptionsMenu(Menu) onCreateOptionsMenu()} (fragmen-fragmen menyediakan
    -+callback {@link android.app.Fragment#onCreateOptionsMenu onCreateOptionsMenu()} sendiri). Dalam metode ini
    -+, Anda bisa memekarkan sumber daya menu (<a href="#xml">yang didefinisikan dalam XML</a>) menjadi {@link
    -+android.view.Menu} yang disediakan dalam callback. Misalnya:</p>
    -+
    -+<pre>
    -+&#64;Override
    -+public boolean onCreateOptionsMenu(Menu menu) {
    -+    MenuInflater inflater = {@link android.app.Activity#getMenuInflater()};
    -+    inflater.inflate(R.menu.game_menu, menu);
    -+    return true;
    -+}
    -+</pre>
    -+
    -+<p>Anda juga bisa menambahkan item menu dengan menggunakan {@link android.view.Menu#add(int,int,int,int)
    -+add()} dan mengambil item dengan {@link android.view.Menu#findItem findItem()} untuk merevisi propertinya
    -+dengan API {@link android.view.MenuItem}.</p>
    -+
    -+<p>Jika Anda mengembangkan aplikasi untuk Android 2.3.x dan yang lebih rendah, sistem akan memanggil {@link
    -+android.app.Activity#onCreateOptionsMenu(Menu) onCreateOptionsMenu()} untuk membuat menu opsi
    -+bila pengguna membuka menu untuk pertama kali. Jika Anda mengembangkan aplikasi untuk Android 3.0 dan yang lebih tinggi,
    -+sistem akan memanggil {@link android.app.Activity#onCreateOptionsMenu(Menu) onCreateOptionsMenu()} saat
    -+memulai aktivitas, untuk menampilkan item menu pada action-bar.</p>
    -+
    -+
    -+
    -+<h3 id="RespondingOptionsMenu">Menangani kejadian klik</h3>
    -+
    -+<p>Bila pengguna memilih item dari menu opsi (termasuk item tindakan dalam action-bar),
    -+sistem akan memanggil metode {@link android.app.Activity#onOptionsItemSelected(MenuItem)
    -+onOptionsItemSelected()} aktivitas Anda. Metode ini meneruskan {@link android.view.MenuItem} yang dipilih. Anda
    -+bisa mengidentifikasi item dengan memanggil {@link android.view.MenuItem#getItemId()}, yang menghasilkan
    -+ID unik untuk item menu itu (yang didefinisikan oleh atribut {@code android:id} dalam sumber daya menu atau dengan
    -+integer yang diberikan ke metode {@link android.view.Menu#add(int,int,int,int) add()}). Anda bisa mencocokkan
    -+ID ini dengan item menu yang diketahui untuk melakukan tindakan yang sesuai. Misalnya:</p>
    -+
    -+<pre>
    -+&#64;Override
    -+public boolean onOptionsItemSelected(MenuItem item) {
    -+    // Handle item selection
    -+    switch (item.getItemId()) {
    -+        case R.id.new_game:
    -+            newGame();
    -+            return true;
    -+        case R.id.help:
    -+            showHelp();
    -+            return true;
    -+        default:
    -+            return super.onOptionsItemSelected(item);
    -+    }
    -+}
    -+</pre>
    -+
    -+<p>Bila Anda berhasil menangani sebuah item menu, kembalikan {@code true}. Jika tidak menangani item menu
    -+, Anda harus memanggil implementasi superkelas {@link
    -+android.app.Activity#onOptionsItemSelected(MenuItem) onOptionsItemSelected()} (implementasi default
    -+menghasilkan false).</p>
    -+
    -+<p>Jika aktivitas Anda menyertakan fragmen, sistem akan memanggil lebih dahulu {@link
    -+android.app.Activity#onOptionsItemSelected(MenuItem) onOptionsItemSelected()} untuk aktivitas, kemudian
    -+untuk setiap fragmen (sesuai dengan urutan penambahan fragmen) hingga satu fragmen mengembalikan
    -+{@code true} atau semua fragmen telah dipanggil.</p>
    -+
    -+<p class="note"><strong>Tip:</strong> Android 3.0 menambahkan kemampuan mendefinisikan perilaku on-click
    -+untuk item menu dalam XML, dengan menggunakan atribut {@code android:onClick}. Nilai atribut
    -+harus berupa nama metode yang didefinisikan aktivitas dengan menggunakan menu. Metode
    -+harus bersifat publik dan menerima satu parameter {@link android.view.MenuItem}&mdash;bila sistem
    -+memanggilnya, metode ini akan meneruskan item menu yang dipilih. Untuk informasi selengkapnya dan contoh, lihat dokumen <a href="{@docRoot}guide/topics/resources/menu-resource.html">Sumber Daya Menu</a>.</p>
    -+
    -+<p class="note"><strong>Tip:</strong> Jika aplikasi Anda berisi banyak aktivitas dan
    -+sebagian menyediakan menu opsi yang sama, pertimbangkan untuk membuat
    -+aktivitas yang tidak mengimplementasikan apa-apa kecuali metode {@link android.app.Activity#onCreateOptionsMenu(Menu)
    -+onCreateOptionsMenu()} dan {@link android.app.Activity#onOptionsItemSelected(MenuItem)
    -+onOptionsItemSelected()}. Kemudian perluas kelas ini untuk setiap aktivitas yang harus menggunakan
    -+menu opsi yang sama. Dengan begini, Anda bisa mengelola satu set kode untuk menangani tindakan menu
    -+dan setiap kelas turunan mewarisi perilaku menu.
    -+Jika ingin menambahkan item menu ke salah satu aktivitas turunan,
    -+kesampingkan {@link android.app.Activity#onCreateOptionsMenu(Menu)
    -+onCreateOptionsMenu()} dalam aktivitas itu. Panggil {@code super.onCreateOptionsMenu(menu)} agar
    -+item menu asli dibuat, kemudian tambahkan item menu yang baru dengan {@link
    -+android.view.Menu#add(int,int,int,int) menu.add()}. Anda juga bisa mengesampingkan
    -+perilaku superkelas untuk setiap item menu.</p>
    -+
    -+
    -+<h3 id="ChangingTheMenu">Mengubah item menu saat runtime</h3>
    -+
    -+<p>Setelah sistem memanggil {@link android.app.Activity#onCreateOptionsMenu(Menu)
    -+onCreateOptionsMenu()}, sistem akan mempertahankan instance {@link android.view.Menu} yang Anda tempatkan dan
    -+tidak akan memanggil {@link android.app.Activity#onCreateOptionsMenu(Menu) onCreateOptionsMenu()}
    -+lagi kecuali menu diinvalidkan karena suatu alasan. Akan tetapi, Anda harus menggunakan {@link
    -+android.app.Activity#onCreateOptionsMenu(Menu) onCreateOptionsMenu()} hanya untuk membuat
    -+status menu awal dan tidak untuk membuat perubahan selama daur hidup aktivitas.</p>
    -+
    -+<p>Jika Anda ingin mengubah menu opsi berdasarkan
    -+kejadian yang terjadi selama daur hidup aktivitas, Anda bisa melakukannya dalam metode
    -+{@link android.app.Activity#onPrepareOptionsMenu(Menu) onPrepareOptionsMenu()}. Metode ini
    -+meneruskan objek {@link android.view.Menu} sebagaimana adanya saat ini sehingga Anda bisa mengubahnya,
    -+seperti menambah, menghapus, atau menonaktifkan item. (Fragmen juga menyediakan callback {@link
    -+android.app.Fragment#onPrepareOptionsMenu onPrepareOptionsMenu()}.)</p>
    -+
    -+<p>Pada Android 2.3.x dan yang lebih rendah, sistem akan memanggil {@link
    -+android.app.Activity#onPrepareOptionsMenu(Menu)
    -+onPrepareOptionsMenu()} setiap kali pengguna membuka menu opsi (menekan tombol <em>Menu</em>
    -+).</p>
    -+
    -+<p>Pada Android 3.0 dan yang lebih tinggi, menu opsi dianggap sebagai selalu terbuka saat item menu
    -+ditampilkan pada action-bar. Bila ada kejadian dan Anda ingin melakukan pembaruan menu, Anda harus
    -+memanggil {@link android.app.Activity#invalidateOptionsMenu invalidateOptionsMenu()} untuk meminta
    -+sistem memanggil {@link android.app.Activity#onPrepareOptionsMenu(Menu) onPrepareOptionsMenu()}.</p>
    -+
    -+<p class="note"><strong>Catatan:</strong>
    -+Anda tidak boleh mengubah item dalam menu opsi berdasarkan {@link android.view.View} yang saat ini
    -+difokus. Saat dalam mode sentuh (bila pengguna tidak sedang menggunakan trackball atau d-pad), tampilan
    -+tidak bisa mengambil fokus, sehingga Anda tidak boleh menggunakan fokus sebagai dasar untuk mengubah
    -+item dalam menu opsi. Jika Anda ingin menyediakan item menu yang peka konteks pada {@link
    -+android.view.View}, gunakan <a href="#context-menu">Menu Konteks</a>.</p>
    -+
    -+
    -+
    -+
    -+<h2 id="context-menu">Membuat Menu Kontekstual</h2>
    -+
    -+<div class="figure" style="width:420px;margin-top:-1em">
    -+  <img src="{@docRoot}images/ui/menu-context.png" alt="" />
    -+  <p class="img-caption"><strong>Gambar 3.</strong> Cuplikan layar menu konteks mengambang (kiri)
    -+dan action-bar kontekstual (kanan).</p>
    -+</div>
    -+
    -+<p>Menu kontekstual menawarkan tindakan yang memengaruhi item atau bingkai konteks tertentu dalam UI. Anda
    -+bisa menyediakan menu konteks untuk setiap tampilan, tetapi menu ini paling sering digunakan untuk item pada {@link
    -+android.widget.ListView}, {@link android.widget.GridView}, atau kumpulan tampilan lainnya yang bisa digunakan
    -+pengguna untuk melakukan tindakan langsung pada setiap item.</p>
    -+
    -+<p>Ada dua cara menyediakan tindakan kontekstual:</p>
    -+<ul>
    -+  <li>Dalam <a href="#FloatingContextMenu">menu konteks mengambang</a>. Menu muncul sebagai
    -+daftar item menu mengambang (serupa dengan dialog) bila pengguna mengklik lama (menekan dan
    -+menahan) pada tampilan yang mendeklarasikan dukungan bagi menu konteks. Pengguna bisa melakukan
    -+tindakan kontekstual pada satu item untuk setiap kalinya.</li>
    -+
    -+  <li>Dalam <a href="#CAB">mode tindakan kontekstual</a>. Mode ini adalah implementasi sistem
    -+{@link android.view.ActionMode} yang menampilkan <em>action-bar kontekstual</em> di bagian atas
    -+layar dengan item tindakan yang memengaruhi item(-item) yang dipilih. Bila mode ini aktif, pengguna
    -+bisa melakukan tindakan pada beberapa item sekaligus (jika aplikasi Anda mengizinkannya).</li>
    -+</ul>
    -+
    -+<p class="note"><strong>Catatan:</strong> Mode tindakan kontekstual tersedia pada Android 3.0 (API
    -+level 11) dan yang lebih tinggi dan merupakan teknik yang lebih disukai untuk menampilkan tindakan kontekstual bila
    -+tersedia. Jika aplikasi Anda mendukung versi yang lebih rendah daripada 3.0, maka Anda harus mundur ke
    -+menu konteks mengambang pada perangkat-perangkat itu.</p>
    -+
    -+
    -+<h3 id="FloatingContextMenu">Membuat menu konteks mengambang</h3>
    -+
    -+<p>Untuk menyediakan menu konteks mengambang:</p>
    -+<ol>
    -+  <li>Daftarkan {@link android.view.View} ke menu konteks yang harus dikaitkan dengan
    -+memanggil {@link android.app.Activity#registerForContextMenu(View) registerForContextMenu()} dan teruskan
    -+{@link android.view.View} ke menu itu.
    -+  <p>Jika aktivitas Anda menggunakan {@link android.widget.ListView} atau {@link android.widget.GridView} dan
    -+Anda ingin setiap item untuk menyediakan menu konteks yang sama, daftarkan semua item ke menu konteks dengan
    -+meneruskan {@link android.widget.ListView} atau {@link android.widget.GridView} ke {@link
    -+android.app.Activity#registerForContextMenu(View) registerForContextMenu()}.</p>
    -+</li>
    -+
    -+  <li>Implementasikan metode {@link
    -+android.view.View.OnCreateContextMenuListener#onCreateContextMenu onCreateContextMenu()}
    -+dalam {@link android.app.Activity} atau {@link android.app.Fragment} Anda.
    -+  <p>Bila tampilan yang terdaftar menerima kejadian klik-lama, sistem akan memanggil metode {@link
    -+android.view.View.OnCreateContextMenuListener#onCreateContextMenu onCreateContextMenu()}
    -+Anda. Inilah tempat Anda mendefinisikan item menu, biasanya dengan memekarkan sumber daya menu. Misalnya:
    -+</p>
    -+<pre>
    -+&#64;Override
    -+public void onCreateContextMenu(ContextMenu menu, View v,
    -+                                ContextMenuInfo menuInfo) {
    -+    super.onCreateContextMenu(menu, v, menuInfo);
    -+    MenuInflater inflater = getMenuInflater();
    -+    inflater.inflate(R.menu.context_menu, menu);
    -+}
    -+</pre>
    -+
    -+<p>{@link android.view.MenuInflater} memungkinkan Anda untuk memekarkan menu konteks <a href="{@docRoot}guide/topics/resources/menu-resource.html">sumber daya menu</a>. Parameter metode callback
    -+menyertakan {@link android.view.View}
    -+yang dipilih pengguna dan objek {@link android.view.ContextMenu.ContextMenuInfo} yang menyediakan
    -+informasi tambahan tentang item yang dipilih. Jika aktivitas Anda memiliki beberapa tampilan yang masing-masingnya menyediakan
    -+menu konteks berbeda, Anda bisa menggunakan parameter ini untuk menentukan menu konteks yang harus
    -+dimekarkan.</p>
    -+</li>
    -+
    -+<li>Implementasikan {@link android.app.Activity#onContextItemSelected(MenuItem)
    -+onContextItemSelected()}.
    -+  <p>Bila pengguna memilih item menu, sistem akan memanggil metode ini sehingga Anda bisa melakukan
    -+tindakan yang sesuai. Misalnya:</p>
    -+
    -+<pre>
    -+&#64;Override
    -+public boolean onContextItemSelected(MenuItem item) {
    -+    AdapterContextMenuInfo info = (AdapterContextMenuInfo) item.getMenuInfo();
    -+    switch (item.getItemId()) {
    -+        case R.id.edit:
    -+            editNote(info.id);
    -+            return true;
    -+        case R.id.delete:
    -+            deleteNote(info.id);
    -+            return true;
    -+        default:
    -+            return super.onContextItemSelected(item);
    -+    }
    -+}
    -+</pre>
    -+
    -+<p>Metode {@link android.view.MenuItem#getItemId()} melakukan query ID untuk
    -+item menu yang dipilih, yang harus Anda tetapkan ke setiap item menu dalam XML dengan menggunakan atribut {@code
    -+android:id}, seperti yang ditampilkan di bagian tentang <a href="#xml">Mendefinisikan Menu dalam
    -+XML</a>.</p>
    -+
    -+<p>Bila Anda berhasil menangani sebuah item menu, kembalikan {@code true}. Jika tidak menangani item menu,
    -+Anda harus meneruskan item menu ke implementasi superkelas. Jika aktivitas Anda menyertakan fragmen,
    -+aktivitas akan menerima callback ini lebih dahulu. Dengan memanggil superkelas bila tidak ditangani, sistem
    -+meneruskan kejadian ke metode callback di setiap fragmen, satu per satu (sesuai dengan urutan
    -+penambahan fragmen) hingga {@code true} atau {@code false} dikembalikan. (Implementasi default
    -+untuk {@link android.app.Activity} dan {@code android.app.Fragment} mengembalikan {@code
    -+false}, sehingga Anda harus selalu memanggil superkelas bila tidak ditangani.)</p>
    -+</li>
    -+</ol>
    -+
    -+
    -+<h3 id="CAB">Menggunakan mode tindakan kontekstual</h3>
    -+
    -+<p>Mode tindakan kontekstual adalah implementasi sistem {@link android.view.ActionMode} yang
    -+memfokuskan interaksi pengguna pada upaya melakukan tindakan kontekstual. Bila seorang
    -+pengguna mengaktifkan mode ini dengan memilih item, <em>action-bar kontekstual</em> akan muncul di bagian atas
    -+layar untuk menampilkan tindakan yang bisa dilakukan pengguna pada item yang dipilih saat ini. Selagi mode ini
    -+diaktifkan, pengguna bisa memilih beberapa item (jika Anda mengizinkan), membatalkan pilihan item, dan melanjutkan
    -+penelusuran dalam aktivitas (sebanyak yang ingin Anda izinkan). Mode tindakan dinonaktifkan
    -+dan action-bar kontekstual menghilang bila pengguna membatalkan pilihan semua item, menekan tombol BACK,
    -+atau memilih tindakan <em>Done</em> di sisi kiri action-bar.</p>
    -+
    -+<p class="note"><strong>Catatan:</strong> Action-bar kontekstual tidak harus
    -+terkait dengan <a href="{@docRoot}guide/topics/ui/actionbar.html">action-bar</a>. Action-bar ini beroperasi
    -+secara independen, walaupun action-bar kontekstual secara visual mengambil alih
    -+posisi action-bar.</p>
    -+
    -+<p>Jika Anda mengembangkan aplikasi untuk Android 3.0 (API level 11) atau yang lebih tinggi, Anda
    -+biasanya harus menggunakan mode tindakan kontekstual untuk menampilkan tindakan kontekstual, sebagai ganti <a href="#FloatingContextMenu">menu konteks mengambang</a>.</p>
    -+
    -+<p>Untuk tampilan yang menyediakan tindakan kontekstual, Anda biasanya harus memanggil mode tindakan kontekstual
    -+pada salah satu dari dua kejadian (atau keduanya):</p>
    -+<ul>
    -+  <li>Pengguna mengklik-lama pada tampilan.</li>
    -+  <li>Pengguna memilih kotak cek atau komponen UI yang serupa dalam tampilan.</li>
    -+</ul>
    -+
    -+<p>Cara aplikasi memanggil mode tindakan kontekstual dan mendefinisikan perilaku setiap
    -+tindakan bergantung pada desain Anda. Pada dasarnya ada dua desain:</p>
    -+<ul>
    -+  <li>Untuk tindakan kontekstual pada tampilan individual dan tak didukung.</li>
    -+  <li>Untuk tindakan kontekstual batch pada grup item dalam {@link
    -+android.widget.ListView} atau {@link android.widget.GridView} (memungkinkan pengguna memilih beberapa
    -+item dan melakukan tindakan pada semua item itu).</li>
    -+</ul>
    -+
    -+<p>Bagian berikut ini menjelaskan penyiapan yang diperlukan untuk setiap skenario.</p>
    -+
    -+
    -+<h4 id="CABforViews">Mengaktifkan mode tindakan kontekstual untuk tampilan individual</h4>
    -+
    -+<p>Jika Anda ingin memanggil mode tindakan kontekstual hanya bila pengguna memilih
    -+tampilan tertentu, Anda harus:</p>
    -+<ol>
    -+  <li>Mengimplementasikan antarmuka {@link android.view.ActionMode.Callback}. Dalam metode callback-nya, Anda
    -+bisa menetapkan tindakan untuk action-bar kontekstual, merespons kejadian klik pada item tindakan, dan
    -+menangani kejadian daur hidup lainnya untuk mode tindakan itu.</li>
    -+  <li>Memanggil {@link android.app.Activity#startActionMode startActionMode()} bila Anda ingin menampilkan
    -+action-bar (seperti saat pengguna mengklik-lama pada tampilan).</li>
    -+</ol>
    -+
    -+<p>Misalnya:</p>
    -+
    -+<ol>
    -+  <li>Implementasikan antarmuka {@link android.view.ActionMode.Callback ActionMode.Callback}:
    -+<pre>
    -+private ActionMode.Callback mActionModeCallback = new ActionMode.Callback() {
    -+
    -+    // Called when the action mode is created; startActionMode() was called
    -+    &#64;Override
    -+    public boolean onCreateActionMode(ActionMode mode, Menu menu) {
    -+        // Inflate a menu resource providing context menu items
    -+        MenuInflater inflater = mode.getMenuInflater();
    -+        inflater.inflate(R.menu.context_menu, menu);
    -+        return true;
    -+    }
    -+
    -+    // Called each time the action mode is shown. Always called after onCreateActionMode, but
    -+    // may be called multiple times if the mode is invalidated.
    -+    &#64;Override
    -+    public boolean onPrepareActionMode(ActionMode mode, Menu menu) {
    -+        return false; // Return false if nothing is done
    -+    }
    -+
    -+    // Called when the user selects a contextual menu item
    -+    &#64;Override
    -+    public boolean onActionItemClicked(ActionMode mode, MenuItem item) {
    -+        switch (item.getItemId()) {
    -+            case R.id.menu_share:
    -+                shareCurrentItem();
    -+                mode.finish(); // Action picked, so close the CAB
    -+                return true;
    -+            default:
    -+                return false;
    -+        }
    -+    }
    -+
    -+    // Called when the user exits the action mode
    -+    &#64;Override
    -+    public void onDestroyActionMode(ActionMode mode) {
    -+        mActionMode = null;
    -+    }
    -+};
    -+</pre>
    -+
    -+<p>Perhatikan bahwa kejadian callback ini hampir persis sama dengan callback untuk <a href="#options-menu">menu opsi</a>, hanya saja setiap callback ini juga meneruskan objek {@link
    -+android.view.ActionMode} yang terkait dengan kejadian. Anda bisa menggunakan API {@link
    -+android.view.ActionMode} untuk membuat berbagai perubahan pada CAB, seperti merevisi judul dan
    -+subjudul dengan {@link android.view.ActionMode#setTitle setTitle()} dan {@link
    -+android.view.ActionMode#setSubtitle setSubtitle()} (berguna untuk menunjukkan jumlah item
    -+yang dipilih).</p>
    -+
    -+<p>Juga perhatikan bahwa contoh di atas mengatur variabel {@code mActionMode} ke nol bila
    -+mode tindakan dimusnahkan. Dalam langkah berikutnya, Anda akan melihat cara variabel diinisialisasi dan kegunaan menyimpan
    -+variabel anggota dalam aktivitas atau fragmen.</p>
    -+</li>
    -+
    -+  <li>Panggil {@link android.app.Activity#startActionMode startActionMode()} untuk mengaktifkan
    -+mode tindakan kontekstual bila sesuai, seperti saat merespons klik-lama pada {@link
    -+android.view.View}:</p>
    -+
    -+<pre>
    -+someView.setOnLongClickListener(new View.OnLongClickListener() {
    -+    // Called when the user long-clicks on someView
    -+    public boolean onLongClick(View view) {
    -+        if (mActionMode != null) {
    -+            return false;
    -+        }
    -+
    -+        // Start the CAB using the ActionMode.Callback defined above
    -+        mActionMode = getActivity().startActionMode(mActionModeCallback);
    -+        view.setSelected(true);
    -+        return true;
    -+    }
    -+});
    -+</pre>
    -+
    -+<p>Bila Anda memanggil {@link android.app.Activity#startActionMode startActionMode()}, sistem akan mengembalikan
    -+{@link android.view.ActionMode} yang dibuat. Dengan menyimpannya dalam variabel anggota, Anda bisa
    -+membuat perubahan ke action-bar kontekstual sebagai respons terhadap kejadian lainnya. Dalam contoh di atas,
    -+{@link android.view.ActionMode} digunakan untuk memastikan bahwa instance {@link android.view.ActionMode}
    -+tidak dibuat kembali jika sudah aktif, dengan memeriksa apakah anggota bernilai nol sebelum memulai
    -+mode tindakan.</p>
    -+</li>
    -+</ol>
    -+
    -+
    -+
    -+<h4 id="CABforListView">Mengaktifkan tindakan kontekstual batch dalam ListView atau GridView</h4>
    -+
    -+<p>Jika Anda memiliki sekumpulan item dalam {@link android.widget.ListView} atau {@link
    -+android.widget.GridView} (atau ekstensi {@link android.widget.AbsListView} lainnya) dan ingin
    -+mengizinkan pengguna melakukan tindakan batch, Anda harus:</p>
    -+
    -+<ul>
    -+  <li>Mengimplementasikan antarmuka {@link android.widget.AbsListView.MultiChoiceModeListener} dan mengaturnya
    -+untuk grup tampilan dengan {@link android.widget.AbsListView#setMultiChoiceModeListener
    -+setMultiChoiceModeListener()}. Dalam metode callback listener, Anda bisa menetapkan tindakan
    -+untuk action-bar kontekstual, merespons kejadian klik pada item tindakan, dan menangani callback lainnya
    -+yang diwarisi dari antarmuka {@link android.view.ActionMode.Callback}.</li>
    -+
    -+  <li>Panggil {@link android.widget.AbsListView#setChoiceMode setChoiceMode()} dengan argumen {@link
    -+android.widget.AbsListView#CHOICE_MODE_MULTIPLE_MODAL}.</li>
    -+</ul>
    -+
    -+<p>Misalnya:</p>
    -+
    -+<pre>
    -+ListView listView = getListView();
    -+listView.setChoiceMode(ListView.CHOICE_MODE_MULTIPLE_MODAL);
    -+listView.setMultiChoiceModeListener(new MultiChoiceModeListener() {
    -+
    -+    &#64;Override
    -+    public void onItemCheckedStateChanged(ActionMode mode, int position,
    -+                                          long id, boolean checked) {
    -+        // Here you can do something when items are selected/de-selected,
    -+        // such as update the title in the CAB
    -+    }
    -+
    -+    &#64;Override
    -+    public boolean onActionItemClicked(ActionMode mode, MenuItem item) {
    -+        // Respond to clicks on the actions in the CAB
    -+        switch (item.getItemId()) {
    -+            case R.id.menu_delete:
    -+                deleteSelectedItems();
    -+                mode.finish(); // Action picked, so close the CAB
    -+                return true;
    -+            default:
    -+                return false;
    -+        }
    -+    }
    -+
    -+    &#64;Override
    -+    public boolean onCreateActionMode(ActionMode mode, Menu menu) {
    -+        // Inflate the menu for the CAB
    -+        MenuInflater inflater = mode.getMenuInflater();
    -+        inflater.inflate(R.menu.context, menu);
    -+        return true;
    -+    }
    -+
    -+    &#64;Override
    -+    public void onDestroyActionMode(ActionMode mode) {
    -+        // Here you can make any necessary updates to the activity when
    -+        // the CAB is removed. By default, selected items are deselected/unchecked.
    -+    }
    -+
    -+    &#64;Override
    -+    public boolean onPrepareActionMode(ActionMode mode, Menu menu) {
    -+        // Here you can perform updates to the CAB due to
    -+        // an {@link android.view.ActionMode#invalidate} request
    -+        return false;
    -+    }
    -+});
    -+</pre>
    -+
    -+<p>Demikian saja. Kini bila pengguna memilih item dengan klik-lama, sistem akan memanggil metode {@link
    -+android.widget.AbsListView.MultiChoiceModeListener#onCreateActionMode onCreateActionMode()}
    -+dan menampilkan action-bar kontekstual bersama tindakan yang ditetapkan. Saat
    -+action-bar kontekstual terlihat, pengguna bisa memilih item tambahan.</p>
    -+
    -+<p>Dalam beberapa kasus di mana tindakan kontekstual menyediakan item tindakan umum, Anda mungkin
    -+ingin menambahkan kotak cek atau elemen UI serupa yang memungkinkan pengguna memilih item, karena pengguna
    -+mungkin tidak menemukan perilaku klik-lama. Bila pengguna memilih kotak cek itu, Anda
    -+bisa memanggil mode tindakan kontekstual dengan mengatur item daftar yang bersangkutan ke
    -+status diberi tanda cek dengan {@link android.widget.AbsListView#setItemChecked setItemChecked()}.</p>
    -+
    -+
    -+
    -+
    -+<h2 id="PopupMenu">Membuat Menu Popup</h2>
    -+
    -+<div class="figure" style="width:220px">
    -+<img src="{@docRoot}images/ui/popupmenu.png" alt="" />
    -+<p><strong>Gambar 4.</strong> Menu popup dalam aplikasi Gmail, dikaitkan pada
    -+tombol kelebihan di sudut kanan atas.</p>
    -+</div>
    -+
    -+<p>{@link android.widget.PopupMenu} adalah menu modal yang dikaitkan pada {@link android.view.View}.
    -+Menu ini muncul di bawah tampilan jangkar jika ada ruang, atau di atas tampilan jika tidak ada. Menu ini berguna untuk:</p>
    -+<ul>
    -+  <li>Menyediakan menu bergaya kelebihan (overflow) untuk tindakan yang <em>berkaitan dengan</em> konten tertentu (seperti
    -+header email Gmail, yang ditampilkan dalam gambar 4).
    -+    <p class="note"><strong>Catatan:</strong> Ini tidak sama dengan menu konteks, yang umumnya
    -+untuk tindakan yang <em>memengaruhi</em> konten yang dipilih. Untuk tindakan yang memengaruhi
    -+konten yang dipilih, gunakan <a href="#CAB">mode tindakan kontekstual</a> atau <a href="#FloatingContextMenu">menu konteks mengambang</a>.</p></li>
    -+  <li>Menyediakan bagian kedua dari kalimat perintah (seperti tombol bertanda "Tambah"
    -+yang menghasilkan menu popup dengan berbagai opsi "Tambah").</li>
    -+  <li>Menyediakan daftar menurun yang serupa dengan {@link android.widget.Spinner} yang tidak mempertahankan
    -+pilihan persisten.</li>
    -+</ul>
    -+
    -+
    -+<p class="note"><strong>Catatan:</strong> {@link android.widget.PopupMenu} tersedia dengan API
    -+level 11 dan yang lebih tinggi.</p>
    -+
    -+<p>Jika Anda <a href="#xml">mendefinisikan menu dalam XML</a>, berikut ini adalah cara Anda menampilkan menu popup:</p>
    -+<ol>
    -+  <li>Buat instance {@link android.widget.PopupMenu} bersama konstruktornya, yang mengambil
    -+aplikasi saat ini {@link android.content.Context} dan {@link android.view.View} yang akan menjadi tempat mengaitkan
    -+menu.</li>
    -+  <li>Gunakan {@link android.view.MenuInflater} untuk memekarkan sumber daya menu Anda ke dalam objek {@link
    -+android.view.Menu} yang dikembalikan oleh {@link
    -+android.widget.PopupMenu#getMenu() PopupMenu.getMenu()}. Pada API level 14 ke atas, Anda bisa menggunakan
    -+{@link android.widget.PopupMenu#inflate PopupMenu.inflate()} sebagai gantinya.</li>
    -+  <li>Panggil {@link android.widget.PopupMenu#show() PopupMenu.show()}.</li>
    -+</ol>
    -+
    -+<p>Misalnya, berikut ini adalah tombol dengan atribut {@link android.R.attr#onClick android:onClick}
    -+yang menampilkan menu popup:</p>
    -+
    -+<pre>
    -+&lt;ImageButton
    -+    android:layout_width="wrap_content"
    -+    android:layout_height="wrap_content"
    -+    android:src="@drawable/ic_overflow_holo_dark"
    -+    android:contentDescription="@string/descr_overflow_button"
    -+    android:onClick="showPopup" />
    -+</pre>
    -+
    -+<p>Aktivitas nanti bisa menampilkan menu popup seperti ini:</p>
    -+
    -+<pre>
    -+public void showPopup(View v) {
    -+    PopupMenu popup = new PopupMenu(this, v);
    -+    MenuInflater inflater = popup.getMenuInflater();
    -+    inflater.inflate(R.menu.actions, popup.getMenu());
    -+    popup.show();
    -+}
    -+</pre>
    -+
    -+<p>Dalam API level 14 dan yang lebih tinggi, Anda bisa menggabungkan dua baris yang memekarkan menu dengan {@link
    -+android.widget.PopupMenu#inflate PopupMenu.inflate()}.</p>
    -+
    -+<p>Menu akan menghilang bila pengguna memilih item atau menyentuh di luar
    -+area menu. Anda bisa mendengarkan kejadian menghilangkan dengan menggunakan {@link
    -+android.widget.PopupMenu.OnDismissListener}.</p>
    -+
    -+<h3 id="PopupEvents">Menangani kejadian klik</h3>
    -+
    -+<p>Untuk melakukan suatu
    -+tindakan bila pengguna memilih item menu, Anda harus mengimplementasikan antarmuka {@link
    -+android.widget.PopupMenu.OnMenuItemClickListener} dan mendaftarkannya pada {@link
    -+android.widget.PopupMenu} dengan memanggil {@link android.widget.PopupMenu#setOnMenuItemClickListener
    -+setOnMenuItemclickListener()}. Bila pengguna memilih item, sistem akan memanggil callback {@link
    -+android.widget.PopupMenu.OnMenuItemClickListener#onMenuItemClick onMenuItemClick()} dalam
    -+antarmuka Anda.</p>
    -+
    -+<p>Misalnya:</p>
    -+
    -+<pre>
    -+public void showMenu(View v) {
    -+    PopupMenu popup = new PopupMenu(this, v);
    -+
    -+    // This activity implements OnMenuItemClickListener
    -+    popup.setOnMenuItemClickListener(this);
    -+    popup.inflate(R.menu.actions);
    -+    popup.show();
    -+}
    -+
    -+&#64;Override
    -+public boolean onMenuItemClick(MenuItem item) {
    -+    switch (item.getItemId()) {
    -+        case R.id.archive:
    -+            archive(item);
    -+            return true;
    -+        case R.id.delete:
    -+            delete(item);
    -+            return true;
    -+        default:
    -+            return false;
    -+    }
    -+}
    -+</pre>
    -+
    -+
    -+<h2 id="groups">Membuat Grup Menu</h2>
    -+
    -+<p>Grup menu adalah sekumpulan item menu yang sama-sama memiliki ciri (trait) tertentu. Dengan grup, Anda
    -+bisa:</p>
    -+<ul>
    -+  <li>Menampilkan atau menyembunyikan semua item dengan {@link android.view.Menu#setGroupVisible(int,boolean)
    -+setGroupVisible()}</li>
    -+  <li>Mengaktifkan atau mennonaktifkan semua item dengan {@link android.view.Menu#setGroupEnabled(int,boolean)
    -+setGroupEnabled()}</li>
    -+  <li>Menetapkan apakah semua item bisa diberi tanda cek dengan {@link
    -+android.view.Menu#setGroupCheckable(int,boolean,boolean) setGroupCheckable()}</li>
    -+</ul>
    -+
    -+<p>Anda bisa membuat grup dengan menyarangkan elemen-elemen {@code &lt;item&gt;} dalam elemen {@code &lt;group&gt;}
    -+dalam sumber daya menu atau dengan menetapkan ID grup dengan metode {@link
    -+android.view.Menu#add(int,int,int,int) add()}.</p>
    -+
    -+<p>Berikut ini adalah contoh sumber daya menu yang berisi sebuah grup:</p>
    -+
    -+<pre>
    -+&lt;?xml version="1.0" encoding="utf-8"?&gt;
    -+&lt;menu xmlns:android="http://schemas.android.com/apk/res/android"&gt;
    -+    &lt;item android:id="@+id/menu_save"
    -+          android:icon="@drawable/menu_save"
    -+          android:title="@string/menu_save" /&gt;
    -+    &lt;!-- menu group --&gt;
    -+    &lt;group android:id="@+id/group_delete"&gt;
    -+        &lt;item android:id="@+id/menu_archive"
    -+              android:title="@string/menu_archive" /&gt;
    -+        &lt;item android:id="@+id/menu_delete"
    -+              android:title="@string/menu_delete" /&gt;
    -+    &lt;/group&gt;
    -+&lt;/menu&gt;
    -+</pre>
    -+
    -+<p>Item yang berada dalam grup akan muncul pada level yang sama dengan item pertama&mdash;ketiga item
    -+dalam menu adalah bersaudara. Akan tetapi, Anda bisa memodifikasi ciri kedua
    -+item dalam grup dengan mengacu ID grup dan menggunakan metode yang tercantum di atas. Sistem
    -+juga tidak akan memisahkan item yang telah dikelompokkan. Misalnya, jika Anda mendeklarasikan {@code
    -+android:showAsAction="ifRoom"} untuk tiap item, item tersebut akan muncul dalam
    -+action-bar atau dalam kelebihan tindakan.</p>
    -+
    -+
    -+<h3 id="checkable">Menggunakan item menu yang bisa diberi tanda cek</h3>
    -+
    -+<div class="figure" style="width:200px">
    -+  <img src="{@docRoot}images/radio_buttons.png" height="333" alt="" />
    -+  <p class="img-caption"><strong>Gambar 5.</strong> Cuplikan layar submenu dengan
    -+item yang bisa diberi tanda cek.</p>
    -+</div>
    -+
    -+<p>Menu bisa digunakan sebagai antarmuka untuk mengaktifkan dan menonaktifkan opsi, menggunakan kotak cek untuk
    -+opsi mandiri, atau tombol radio untuk grup
    -+opsi yang saling eksklusif. Gambar 5 menampilkan submenu dengan item yang bisa diberi tanda cek dengan
    -+tombol radio.</p>
    -+
    -+<p class="note"><strong>Catatan:</strong> Item menu dalam Icon Menu (dari menu opsi) tidak bisa
    -+menampilkan kotak cek atau tombol radio. Jika Anda memilih untuk membuat item dalam Icon Menu yang bisa diberi tanda cek,
    -+Anda harus menandai status diberi tanda cek secara manual dengan menukar ikon dan/atau teks
    -+tiap kali statusnya berubah.</p>
    -+
    -+<p>Anda bisa mendefinisikan perilaku yang bisa diberi tanda cek untuk tiap item menu dengan menggunakan atribut {@code
    -+android:checkable} dalam elemen {@code &lt;item&gt;}, atau untuk seluruh grup dengan
    -+atribut {@code android:checkableBehavior} dalam elemen {@code &lt;group&gt;}. Misalnya
    -+, semua item dalam grup menu ini bisa diberi tanda cek dengan tombol radio:</p>
    -+
    -+<pre>
    -+&lt;?xml version="1.0" encoding="utf-8"?&gt;
    -+&lt;menu xmlns:android="http://schemas.android.com/apk/res/android"&gt;
    -+    &lt;group android:checkableBehavior="single"&gt;
    -+        &lt;item android:id="@+id/red"
    -+              android:title="@string/red" /&gt;
    -+        &lt;item android:id="@+id/blue"
    -+              android:title="@string/blue" /&gt;
    -+    &lt;/group&gt;
    -+&lt;/menu&gt;
    -+</pre>
    -+
    -+<p>Atribut {@code android:checkableBehavior} menerima:
    -+<dl>
    -+  <dt>{@code single}</dt>
    -+    <dd>Hanya satu item dari grup ini yang bisa diberi tanda cek (tombol radio)</dd>
    -+  <dt>{@code all}</dt>
    -+    <dd>Semua item bisa diberi tanda cek (kotak cek)</dd>
    -+  <dt>{@code none}</dt>
    -+    <dd>Tidak ada item yang bisa diberi tanda cek</dd>
    -+</dl>
    -+
    -+<p>Anda bisa menerapkan status diberi tanda cek default pada suatu item dengan menggunakan atribut {@code android:checked} dalam
    -+elemen {@code &lt;item&gt;} dan mengubahnya dalam kode dengan metode {@link
    -+android.view.MenuItem#setChecked(boolean) setChecked()}.</p>
    -+
    -+<p>Bila item yang bisa diberi tanda cek dipilih, sistem akan memanggil metode callback setiap item yang dipilih
    -+(seperti {@link android.app.Activity#onOptionsItemSelected(MenuItem) onOptionsItemSelected()}). Di sinilah
    -+Anda harus mengatur status kotak cek itu, karena kotak cek atau tombol radio tidak
    -+mengubah statusnya secara otomatis. Anda bisa melakukan query status saat ini suatu item (seperti sebelum
    -+pengguna memilihnya) dengan {@link android.view.MenuItem#isChecked()} kemudian mengatur status diberi tanda cek dengan
    -+{@link android.view.MenuItem#setChecked(boolean) setChecked()}. Misalnya:</p>
    -+
    -+<pre>
    -+&#64;Override
    -+public boolean onOptionsItemSelected(MenuItem item) {
    -+    switch (item.getItemId()) {
    -+        case R.id.vibrate:
    -+        case R.id.dont_vibrate:
    -+            if (item.isChecked()) item.setChecked(false);
    -+            else item.setChecked(true);
    -+            return true;
    -+        default:
    -+            return super.onOptionsItemSelected(item);
    -+    }
    -+}
    -+</pre>
    -+
    -+<p>Jika Anda tidak mengatur status diberi tanda cek dengan cara ini, maka status item (kotak cek atau
    -+tombol radio) yang terlihat tidak akan
    -+berubah bila pengguna memilihnya. Bila Anda telah mengatur status, aktivitas akan menjaga status diberi tanda cek
    -+suatu item sehingga bila nanti pengguna membuka menu, status diberi tanda cek yang Anda
    -+atur akan terlihat.</p>
    -+
    -+<p class="note"><strong>Catatan:</strong>
    -+Item menu yang bisa diberi tanda cek dimaksudkan untuk digunakan hanya atas dasar per sesi dan tidak disimpan setelah
    -+aplikasi dimusnahkan. Jika Anda memiliki pengaturan aplikasi yang ingin disimpan untuk pengguna,
    -+Anda harus menyimpan data dengan menggunakan <a href="{@docRoot}guide/topics/data/data-storage.html#pref">Shared Preferences</a>.</p>
    -+
    -+
    -+
    -+<h2 id="intents">Menambahkan Item Menu Berdasarkan Intent</h2>
    -+
    -+<p>Kadang-kadang Anda ingin supaya item menu menjalankan aktivitas dengan menggunakan {@link android.content.Intent}
    -+(baik aktivitas berada dalam aplikasi Anda maupun di aplikasi lain). Bila Anda mengetahui intent
    -+yang ingin digunakan dan memiliki item menu tertentu yang harus memulai intent, Anda bisa mengeksekusi
    -+intent dengan {@link android.app.Activity#startActivity(Intent) startActivity()} selama
    -+metode callback bila-item-dipilih yang sesuai (seperti callback {@link
    -+android.app.Activity#onOptionsItemSelected(MenuItem) onOptionsItemSelected()}).</p>
    -+
    -+<p>Akan tetapi, jika Anda tidak yakin apakah perangkat pengguna
    -+berisi aplikasi yang menangani intent, maka menambahkan item menu yang memanggilnya bisa mengakibatkan
    -+item menu tidak berfungsi, karena intent tidak bisa diterjemahkan menjadi
    -+aktivitas. Untuk mengatasi hal ini, Android memungkinkan Anda menambahkan item menu secara dinamis ke menu
    -+bila Android menemukan aktivitas pada perangkat yang menangani intent Anda.</p>
    -+
    -+<p>Untuk menambahkan item menu berdasarkan aktivitas tersedia yang menerima intent:</p>
    -+<ol>
    -+  <li>Definisikan
    -+intent dengan kategori {@link android.content.Intent#CATEGORY_ALTERNATIVE} dan/atau
    -+{@link android.content.Intent#CATEGORY_SELECTED_ALTERNATIVE}, plus kebutuhan lainnya.</li>
    -+  <li>Panggil {@link
    -+android.view.Menu#addIntentOptions(int,int,int,ComponentName,Intent[],Intent,int,MenuItem[])
    -+Menu.addIntentOptions()}. Android kemudian akan mencari setiap aplikasi yang bisa melakukan intent
    -+dan menambahkannya ke menu Anda.</li>
    -+</ol>
    -+
    -+<p>Jika tidak ada aplikasi terinstal
    -+yang memenuhi intent, maka tidak ada item menu yang ditambahkan.</p>
    -+
    -+<p class="note"><strong>Catatan:</strong>
    -+{@link android.content.Intent#CATEGORY_SELECTED_ALTERNATIVE} digunakan untuk menangani
    -+elemen yang saat ini dipilih pada layar. Jadi, metode hanya digunakan saat membuat Menu dalam {@link
    -+android.app.Activity#onCreateContextMenu(ContextMenu,View,ContextMenuInfo)
    -+onCreateContextMenu()}.</p>
    -+
    -+<p>Misalnya:</p>
    -+
    -+<pre>
    -+&#64;Override
    -+public boolean onCreateOptionsMenu(Menu menu){
    -+    super.onCreateOptionsMenu(menu);
    -+
    -+    // Create an Intent that describes the requirements to fulfill, to be included
    -+    // in our menu. The offering app must include a category value of Intent.CATEGORY_ALTERNATIVE.
    -+    Intent intent = new Intent(null, dataUri);
    -+    intent.addCategory(Intent.CATEGORY_ALTERNATIVE);
    -+
    -+    // Search and populate the menu with acceptable offering applications.
    -+    menu.addIntentOptions(
    -+         R.id.intent_group,  // Menu group to which new items will be added
    -+         0,      // Unique item ID (none)
    -+         0,      // Order for the items (none)
    -+         this.getComponentName(),   // The current activity name
    -+         null,   // Specific items to place first (none)
    -+         intent, // Intent created above that describes our requirements
    -+         0,      // Additional flags to control items (none)
    -+         null);  // Array of MenuItems that correlate to specific items (none)
    -+
    -+    return true;
    -+}</pre>
    -+
    -+<p>Untuk setiap aktivitas yang diketahui menyediakan filter intent yang cocok dengan intent yang didefinisikan, item menu
    -+akan ditambahkan, menggunakan nilai dalam filter intent <code>android:label</code> sebagai
    -+judul item menu dan ikon aplikasi sebagai ikon item menu. Metode
    -+{@link android.view.Menu#addIntentOptions(int,int,int,ComponentName,Intent[],Intent,int,MenuItem[])
    -+addIntentOptions()} mengembalikan jumlah item menu yang ditambahkan.</p>
    -+
    -+<p class="note"><strong>Catatan:</strong> Bila Anda memanggil {@link
    -+android.view.Menu#addIntentOptions(int,int,int,ComponentName,Intent[],Intent,int,MenuItem[])
    -+addIntentOptions()}, metode ini akan mengesampingkan setiap dan semua item menu menurut grup menu yang ditetapkan dalam argumen
    -+pertama.</p>
    -+
    -+
    -+<h3 id="AllowingToAdd">Memungkinkan aktivitas Anda ditambahkan ke menu lain</h3>
    -+
    -+<p>Anda juga bisa menawarkan layanan aktivitas Anda pada aplikasi lainnya, sehingga
    -+aplikasi Anda bisa disertakan dalam menu aplikasi lain (membalik peran yang dijelaskan di atas).</p>
    -+
    -+<p>Agar bisa dimasukkan dalam menu aplikasi lain, Anda perlu mendefinisikan
    -+filter intent seperti biasa, tetapi pastikan menyertakan nilai-nilai {@link android.content.Intent#CATEGORY_ALTERNATIVE}
    -+dan/atau {@link android.content.Intent#CATEGORY_SELECTED_ALTERNATIVE} untuk
    -+kategori filter intent. Misalnya:</p>
    -+<pre>
    -+&lt;intent-filter label="&#64;string/resize_image">
    -+    ...
    -+    &lt;category android:name="android.intent.category.ALTERNATIVE" />
    -+    &lt;category android:name="android.intent.category.SELECTED_ALTERNATIVE" />
    -+    ...
    -+&lt;/intent-filter>
    -+</pre>
    -+
    -+<p>Baca selengkapnya tentang penulisan filter intent dalam dokumen
    -+<a href="/guide/components/intents-filters.html">Intent dan Filter Intent</a>.</p>
    -+
    -+<p>Untuk contoh aplikasi yang menggunakan teknik ini, lihat contoh kode
    -+<a href="{@docRoot}resources/samples/NotePad/src/com/example/android/notepad/NoteEditor.html">Note
    -+Pad</a>.</p>
    -diff --git a/docs/html-intl/intl/id/guide/topics/ui/multi-window.jd b/docs/html-intl/intl/id/guide/topics/ui/multi-window.jd
    -new file mode 100644
    -index 0000000..5e7b3d9
    ---- /dev/null
    -+++ b/docs/html-intl/intl/id/guide/topics/ui/multi-window.jd
    -@@ -0,0 +1,589 @@
    -+page.title=Dukungan Multi-Jendela
    -+page.metaDescription=Dukungan baru di Android N untuk menampilkan lebih dari satu aplikasi sekaligus.
    -+page.keywords="multi-window", "android N", "split screen", "free-form"
    -+
    -+@jd:body
    -+
    -+<div id="tb-wrapper">
    -+  <div id="tb">
    -+    <h2>Dalam dokumen ini</h2>
    -+      <ol>
    -+        <li><a href="#overview">Ringkasan</a></li>
    -+        <li><a href="#lifecycle">Daur Hidup Multi-Jendela</a></li>
    -+        <li><a href="#configuring">Mengonfigurasi Aplikasi Anda untuk Mode
    -+              Multi-Jendela</a></li>
    -+        <li><a href="#running">Menjalankan Aplikasi Anda dalam Mode Multi-Jendela</a></li>
    -+        <li><a href="#testing">Menguji Dukungan Multi-Jendela Aplikasi Anda</a></li>
    -+      </ol>
    -+    <h2>Lihat Juga</h2>
    -+      <ol>
    -+        <li><a class="external-link" href="https://github.com/googlesamples/android-MultiWindowPlayground">Aplikasi contoh Playground
    -+          Multi-Jendela</a></li>
    -+        <li><a class="external-link" href="https://medium.com/google-developers/5-tips-for-preparing-for-multi-window-in-android-n-7bed803dda64">Lima Tip untuk Mempersiapkan Multi-Jendela di Android N</a></li>
    -+      </ol>
    -+  </div>
    -+</div>
    -+
    -+<p>
    -+  Android N menambahkan dukungan untuk menampilkan lebih dari satu aplikasi
    -+  sekaligus. Pada perangkat genggam, dua aplikasi bisa berjalan berdampingan atau
    -+  atas-bawah dalam mode <em>layar terbagi</em>. Pada perangkat TV, aplikasi bisa
    -+  menggunakan mode <em>gambar-dalam-gambar</em> untuk melanjutkan pemutaran video selagi pengguna
    -+  berinteraksi dengan aplikasi lain.
    -+</p>
    -+
    -+<p>
    -+  Jika Anda membangun aplikasi Anda dengan N Preview SDK, Anda bisa mengonfigurasi cara aplikasi
    -+  menangani tampilan multi-jendela. Misalnya, Anda bisa menetapkan dimensi
    -+  minimum yang diizinkan aktivitas Anda. Anda juga bisa menonaktifkan tampilan multi-jendela untuk
    -+   aplikasi, sehingga memastikan sistem hanya menampilkan aplikasi Anda dalam mode
    -+  layar penuh.
    -+</p>
    -+
    -+<h2 id="overview">Ringkasan</h2>
    -+
    -+<p>
    -+  Android N memungkinkan beberapa aplikasi berbagi layar sekaligus. Misalnya,
    -+  pengguna bisa membagi layar, melihat halaman web di sisi kiri
    -+  sambil menulis email di sisi kanan. Pengalaman pengguna bergantung pada
    -+  perangkat:
    -+</p>
    -+
    -+<ul>
    -+  <li>Perangkat genggam yang menjalankan Android N menawarkan mode
    -+  layar terbagi. Di mode ini, sistem mengisi layar dengan dua aplikasi, menampilkannya secara
    -+  berdampingan atau atas-bawah. Pengguna bisa menyeret garis pembagi
    -+   yang memisahkan keduanya untuk membuat satu aplikasi lebih besar dan yang lainnya lebih kecil.
    -+  </li>
    -+
    -+  <li>Pada Nexus Player yang menjalankan Android N, aplikasi bisa menempatkan diri
    -+  dalam <a href="picture-in-picture.html">mode gambar-dalam-gambar</a>, yang memungkinkannya
    -+  untuk terus menampilkan materi selagi pengguna menjelajahi atau berinteraksi dengan
    -+   aplikasi lain.
    -+  </li>
    -+
    -+  <li>Produsen perangkat berukuran lebih besar bisa memilih untuk mengaktifkan mode
    -+ bentuk bebas, di mana pengguna bisa bebas mengubah ukuran setiap aktivitas. Jika
    -+  produsen mengaktifkan fitur ini, perangkat akan menawarkan mode bentuk bebas sebagai tambahan
    -+  untuk mode layar terbagi.
    -+  </li>
    -+</ul>
    -+
    -+<img src="{@docRoot}images/android-7.0/mw-splitscreen.png" alt="" width="650" srcset="{@docRoot}images/android-7.0/mw-splitscreen.png 1x,
    -+    {@docRoot}images/android-7.0/mw-splitscreen_2x.png 2x," id="img-split-screen" />
    -+<p class="img-caption">
    -+  <strong>Gambar 1.</strong> Dua aplikasi berjalan berdampingan dalam mode layar terbagi.
    -+</p>
    -+
    -+<p>
    -+  Pengguna bisa beralih ke mode multi-jendela dengan cara berikut:
    -+</p>
    -+
    -+<ul>
    -+  <li>Jika pengguna membuka <a href="{@docRoot}guide/components/recents.html">layar
    -+  Ringkasan</a> dan menekan lama pada
    -+  judul aktivitas, mereka bisa menyeret aktivitas itu ke bagian yang disorot pada layar
    -+  untuk menempatkan aktivitas dalam mode multi-jendela.
    -+  </li>
    -+
    -+  <li>Jika pengguna menekan lama pada tombol Ringkasan, perangkat akan menempatkan
    -+   aktivitas saat ini dalam mode multi-jendela, dan membuka layar Ringkasan guna
    -+  memungkinkan pengguna memilih aktivitas lain untuk berbagi layar.
    -+  </li>
    -+</ul>
    -+
    -+<p>
    -+  Pengguna bisa <a href="{@docRoot}guide/topics/ui/drag-drop.html">seret dan
    -+  lepas</a> data dari aktivitas satu ke aktivitas lain sewaktu aktivitas berbagi
    -+  layar. (Sebelumnya, pengguna hanya bisa menyeret dan melepas data dalam aktivitas
    -+  tunggal.)
    -+</p>
    -+
    -+<h2 id="lifecycle">Daur Hidup Multi-Jendela</h2>
    -+
    -+<p>
    -+  Mode multi-jendela tidak mengubah <a href="{@docRoot}training/basics/activity-lifecycle/index.html">daur hidup
    -+  aktivitas</a>.
    -+</p>
    -+
    -+<p>
    -+  Dalam mode multi-jendela, hanya aktivitas yang paling sering digunakan pengguna
    -+  yang akan aktif pada waktu tertentu. Aktivitas ini dianggap <em>teratas</em>.
    -+  Semua aktivitas lainnya dalam keadaan berhenti sementara, sekalipun terlihat.
    -+  Akan tetapi, sistem memberikan aktivitas, yang berhenti-sementara-namun-terlihat ini, prioritas lebih tinggi
    -+   daripada aktivitas yang tidak terlihat. Jika pengguna berinteraksi dengan salah satu
    -+  aktivitas yang berhenti sementara, aktivitas tersebut akan dilanjutkan kembali, dan aktivitas
    -+  teratas sebelumnya akan dihentikan sementara.
    -+</p>
    -+
    -+<p class="note">
    -+  <strong>Catatan:</strong> Dalam mode multi-jendela, aplikasi bisa berada dalam keadaan berhenti sementara
    -+  dan masih terlihat oleh pengguna. Sebuah aplikasi mungkin perlu melanjutkan aktivitasnya
    -+   bahkan saat berhenti sementara. Misalnya, aplikasi pemutar video yang ada dalam
    -+   mode berhenti sementara namun terlihat harus tetap menampilkan videonya. Karena alasan
    -+  ini, kami menyarankan aktivitas yang memutar video <em>tidak</em> menghentikan sementara video
    -+   dalam handler {@link android.app.Activity#onPause onPause()} mereka.
    -+  Sebagai gantinya, aktivitas itu harus menghentikan sementara video di {@link android.app.Activity#onStop
    -+  onStop()}, dan melanjutkan pemutaran di {@link android.app.Activity#onStart
    -+  onStart()}.
    -+</p>
    -+
    -+<p>
    -+  Bila pengguna menempatkan aplikasi dalam mode multi-jendela, sistem akan memberi tahu
    -+   aktivitas tersebut mengenai perubahan konfigurasi, sebagaimana ditetapkan dalam <a href="{@docRoot}guide/topics/resources/runtime-changes.html">Menangani Perubahan
    -+  Waktu Proses</a>. Hal ini juga terjadi ketika pengguna mengubah skala aplikasi, atau menempatkan kembali aplikasi
    -+  ke mode layar penuh.
    -+  Pada dasarnya, perubahan ini memiliki implikasi daur hidup aktivitas yang sama
    -+  seperti saat sistem memberi tahu aplikasi bahwa perangkat telah beralih
    -+  dari mode potret ke mode lanskap, kecuali dimensi perangkat
    -+  telah berubah sebagai ganti bertukar posisi. Seperti yang dibahas di <a href="{@docRoot}guide/topics/resources/runtime-changes.html">Menangani Perubahan
    -+  Waktu Proses</a>, aktivitas Anda bisa menangani perubahan konfigurasi itu sendiri, atau
    -+   mengizinkan sistem memusnahkan aktivitas dan membuatnya kembali dengan dimensi
    -+  baru.
    -+</p>
    -+
    -+<p>
    -+  Jika pengguna mengubah ukuran jendela dan membuat dimensinya lebih besar, sistem
    -+   akan mengubah ukuran aktivitas untuk menyesuaikan dengan tindakan pengguna dan mengeluarkan <a href="{@docRoot}guide/topics/resources/runtime-changes.html">perubahan waktu proses</a>
    -+  bila diperlukan. Jika aplikasi tertinggal dibandingkan gambar di area yang baru diekspos,
    -+  sistem untuk sementara mengisi area tersebut dengan warna yang ditetapkan oleh atribut {@link
    -+  android.R.attr#windowBackground windowBackground} atau dengan atribut gaya
    -+  <code>windowBackgroundFallback</code> secara default.
    -+</p>
    -+
    -+<h2 id="configuring">Mengonfigurasi Aplikasi Anda untuk Mode Multi-Jendela</h2>
    -+
    -+<p>
    -+  Jika aplikasi Anda menargetkan Android N, Anda bisa mengonfigurasi bagaimana dan
    -+  apakah aktivitas aplikasi Anda mendukung tampilan multi-jendela. Anda bisa menyetel
    -+  atribut dalam manifes untuk mengontrol ukuran dan layoutnya.
    -+  Setelan atribut aktivitas root berlaku pada semua aktivitas
    -+   dalam tumpukan tugasnya. Misalnya, jika aktivitas root memiliki
    -+  <code>android:resizeableActivity</code> yang disetel ke true, maka semua aktivitas
    -+  dalam tumpukan tugas bisa diubah ukurannya.
    -+</p>
    -+
    -+<p class="note">
    -+  <strong>Catatan:</strong> Jika Anda membangun aplikasi multi-orientasi dengan versi
    -+  SDK lebih rendah dari Android N, dan pengguna menggunakan aplikasi
    -+   dalam mode multi-jendela, sistem akan mengubah ukuran aplikasi secara paksa. Sistem akan menampilkan kotak
    -+  dialog yang memperingatkan pengguna bahwa aplikasi mungkin berperilaku tidak terduga. Sistem
    -+   <em>tidak</em> mengubah ukuran aplikasi yang berorientasi tetap; jika
    -+  pengguna berusaha membuka  aplikasi berorientasi tetap saat mode multi-jendela,
    -+  aplikasi akan menggunakan seluruh layar.
    -+</p>
    -+
    -+<h4 id="resizeableActivity">android:resizeableActivity</h4>
    -+<p>
    -+  Setel atribut ini dalam manifes <code>&lt;activity&gt;</code> Anda atau simpul
    -+  <code>&lt;application&gt;</code> untuk mengaktifkan atau menonaktifkan tampilan
    -+   multi-jendela:
    -+</p>
    -+
    -+<pre>
    -+android:resizeableActivity=["true" | "false"]
    -+</pre>
    -+
    -+<p>
    -+  Jika atribut ini disetel ke true, aktivitas bisa dijalankan di
    -+  mode layar terbagi dan mode bentuk bebas. Jika atribut ini disetel ke false, aktivitas
    -+  tidak akan mendukung mode multi-jendela. Jika nilai ini false, dan pengguna
    -+  berusaha memulai aktivitas dalam mode multi-jendela, aktivitas akan menggunakan
    -+   layar penuh.
    -+</p>
    -+
    -+<p>
    -+  Jika aplikasi Anda menargetkan Android N, namun Anda tidak menetapkan nilai
    -+  untuk atribut ini, nilai atribut default adalah true.
    -+</p>
    -+
    -+<h4 id="supportsPictureInPicture">android:supportsPictureInPicture</h4>
    -+
    -+<p>
    -+  Setel atribut ini dalam simpul <code>&lt;activity&gt;</code> manifes Anda untuk
    -+  menunjukkan apakah aktivitas mendukung tampilan gambar-dalam-gambar. Atribut ini
    -+  diabaikan jika <code>android:resizeableActivity</code> bernilai false.
    -+</p>
    -+
    -+<pre>
    -+android:supportsPictureInPicture=["true" | "false"]
    -+</pre>
    -+
    -+<h3 id="layout">Atribut layout</h3>
    -+
    -+<p>
    -+  Dengan Android N, elemen manifes <code>&lt;layout&gt;</code>
    -+  mendukung beberapa atribut yang memengaruhi cara aktivitas berperilaku dalam
    -+  mode multi-jendela:
    -+</p>
    -+
    -+<dl>
    -+  <dt>
    -+    <code>android:defaultWidth</code>
    -+  </dt>
    -+
    -+  <dd>
    -+    Lebar default aktivitas saat dijalankan dalam mode bentuk bebas.
    -+  </dd>
    -+
    -+  <dt>
    -+    <code>android:defaultHeight</code>
    -+  </dt>
    -+
    -+  <dd>
    -+    Tinggi default aktivitas saat dijalankan dalam mode bentuk bebas.
    -+  </dd>
    -+
    -+  <dt>
    -+    <code>android:gravity</code>
    -+  </dt>
    -+
    -+  <dd>
    -+    Penempatan awal dari aktivitas saat dibuka dalam mode bentuk bebas. Lihat referensi
    -+    {@link android.view.Gravity} untuk mengetahui nilai yang cocok.
    -+  </dd>
    -+
    -+  <dt>
    -+    <code>android:minimalHeight</code>, <code>android:minimalWidth</code>
    -+  </dt>
    -+
    -+  <dd>
    -+    Tinggi dan lebar minimum untuk aktivitas dalam mode layar terbagi
    -+    dan mode bentuk bebas. Jika pengguna memindahkan pembagi dalam mode layar terbagi
    -+    untuk membuat aktivitas lebih kecil dari minimum yang ditetapkan, sistem akan memangkas
    -+   aktivitas sesuai dengan ukuran yang diminta pengguna.
    -+  </dd>
    -+</dl>
    -+
    -+<p>
    -+  Misalnya, kode berikut menampilkan cara menetapkan ukuran dan lokasi default
    -+  aktivitas, dan ukuran minimumnya, bila aktivitas ditampilkan dalam
    -+   mode bentuk bebas:
    -+</p>
    -+
    -+<pre>
    -+&lt;activity android:name=".MyActivity"&gt;
    -+    &lt;layout android:defaultHeight="500dp"
    -+          android:defaultWidth="600dp"
    -+          android:gravity="top|end"
    -+          android:minimalHeight="450dp"
    -+          android:minimalWidth="300dp" /&gt;
    -+&lt;/activity&gt;
    -+</pre>
    -+
    -+<h2 id="running">Menjalankan Aplikasi Anda dalam Mode Multi-Jendela</h2>
    -+
    -+<p>
    -+  Android N menawarkan fungsionalitas baru untuk mendukung aplikasi yang bisa berjalan
    -+  dalam mode multi-jendela.
    -+</p>
    -+
    -+<h3 id="disabled-features">Fitur yang dinonaktifkan dalam mode multi-jendela</h3>
    -+
    -+<p>
    -+  Fitur tertentu akan dinonaktifkan atau diabaikan bila perangkat berada dalam mode
    -+  multi-jendela, karena dianggap tidak logis bagi suatu aktivitas yang mungkin berbagi
    -+  layar perangkat dengan aktivitas atau aplikasi lainnya. Fitur tersebut meliputi:
    -+
    -+<ul>
    -+  <li>Beberapa opsi penyesuaian di <a href="{@docRoot}training/system-ui/index.html">System UI</a>
    -+  dinonaktifkan; misalnya, aplikasi tidak bisa menyembunyikan bilah status
    -+  jika tidak berjalan dalam mode layar penuh.
    -+  </li>
    -+
    -+  <li>Sistem akan mengabaikan perubahan pada atribut <code><a href=
    -+  "{@docRoot}guide/topics/manifest/activity-element.html#screen"
    -+  >android:screenOrientation</a></code>.
    -+  </li>
    -+</ul>
    -+
    -+<h3 id="change-notification">Pemberitahuan perubahan multi-jendela dan melakukan kueri</h3>
    -+
    -+<p>
    -+  Metode baru berikut telah ditambahkan ke kelas {@link android.app.Activity}
    -+  untuk mendukung tampilan multi-jendela. Untuk mengetahui detail tentang setiap
    -+  metode, lihat <a href="{@docRoot}preview/setup-sdk.html#docs-dl">Referensi N
    -+ Preview SDK</a>.
    -+</p>
    -+
    -+<dl>
    -+  <dt>
    -+    <code>Activity.isInMultiWindowMode()</code>
    -+  </dt>
    -+
    -+  <dd>
    -+    Panggil untuk mengetahui apakah aktivitas berada dalam mode multi-jendela.
    -+  </dd>
    -+
    -+  <dt>
    -+    <code>Activity.isInPictureInPictureMode()</code>
    -+  </dt>
    -+
    -+  <dd>
    -+    Panggil untuk mengetahui apakah aktivitas berada dalam mode gambar-dalam-gambar.
    -+
    -+    <p class="note">
    -+      <strong>Catatan:</strong> Mode gambar-dalam-gambar adalah kasus khusus pada
    -+      mode multi-jendela. Jika <code>myActivity.isInPictureInPictureMode()</code>
    -+     mengembalikan nilai true, maka <code>myActivity.isInMultiWindowMode()</code> juga
    -+      mengembalikan nilai true.
    -+    </p>
    -+  </dd>
    -+
    -+  <dt>
    -+    <code>Activity.onMultiWindowModeChanged()</code>
    -+  </dt>
    -+
    -+  <dd>
    -+    Sistem akan memanggil metode ini bila aktivitas masuk atau keluar dari
    -+    mode multi-jendela. Sistem akan meneruskan ke metode sebuah nilai true jika
    -+   aktivitas tersebut memasuki mode multi-jendela, dan nilai false jika aktivitas
    -+     tersebut meninggalkan mode multi-jendela.
    -+  </dd>
    -+
    -+  <dt>
    -+    <code>Activity.onPictureInPictureModeChanged()</code>
    -+  </dt>
    -+
    -+  <dd>
    -+    Sistem akan memanggil metode ini bila aktivitas masuk atau keluar dari
    -+    mode gambar-dalam-gambar. Sistem akan meneruskan ke metode sebuah nilai true jika
    -+   aktivitas tersebut memasuki mode gambar-dalam-gambar, dan nilai false jika aktivitas
    -+     tersebut meninggalkan mode gambar-dalam-gambar.
    -+  </dd>
    -+</dl>
    -+
    -+<p>
    -+  Ada juga versi {@link android.app.Fragment} untuk setiap
    -+  metode ini, misalnya <code>Fragment.isInMultiWindowMode()</code>.
    -+</p>
    -+
    -+<h3 id="entering-pip">Memasuki mode gambar-dalam-gambar</h3>
    -+
    -+<p>
    -+  Untuk menempatkan aktivitas dalam mode gambar-dalam-gambar, panggil metode baru
    -+  <code>Activity.enterPictureInPictureMode()</code>. Metode ini tidak berpengaruh jika
    -+   perangkat tidak mendukung mode gambar-dalam-gambar. Untuk informasi selengkapnya,
    -+   lihat dokumentasi <a href="picture-in-picture.html">Gambar-dalam-Gambar</a>.
    -+</p>
    -+
    -+<h3 id="launch">Meluncurkan Aktivitas Baru dalam Mode Multi-Jendela</h3>
    -+
    -+<p>
    -+  Bila meluncurkan aktivitas baru, Anda bisa memberi petunjuk pada sistem bahwa aktivitas
    -+  baru harus ditampilkan bersebelahan dengan aktivitas yang sedang aktif, jika memungkinkan. Caranya,
    -+  gunakan flag
    -+  <code>Intent.FLAG_ACTIVITY_LAUNCH_TO_ADJACENT</code>. Meneruskan
    -+  flag ini akan meminta perilaku berikut:
    -+</p>
    -+
    -+<ul>
    -+  <li>Jika perangkat berada dalam mode layar terbagi, sistem akan berupaya membuat
    -+  aktivitas baru di sebelah aktivitas yang meluncurkannya, sehingga kedua aktivitas tersebut
    -+  berbagi layar. Tidak ada jaminan sistem mampu melakukannya, namun sistem akan
    -+  membuat aktivitas bersebelahan jika memungkinkan.
    -+  </li>
    -+
    -+  <li>Jika perangkat tidak berada dalam mode layar terbagi, flag ini tidak akan berpengaruh.
    -+  </li>
    -+</ul>
    -+
    -+<p>
    -+  Jika perangkat dalam mode bentuk bebas dan Anda menjalankan aktivitas baru, Anda bisa
    -+  menetapkan dimensi aktivitas baru dan lokasi layar dengan memanggil
    -+  <code>ActivityOptions.setLaunchBounds()</code>. Metode ini tidak berpengaruh jika
    -+  perangkat tidak berada dalam mode multi-jendela.
    -+</p>
    -+
    -+<p class="note">
    -+  <strong>Catatan:</strong> Jika Anda meluncurkan aktivitas dalam tumpukan tugas, aktivitas
    -+  tersebut akan menggantikan aktivitas pada layar, dengan mewarisi semua
    -+   properti multi-jendelanya. Jika Anda ingin meluncurkan aktivitas baru sebagai jendela
    -+  terpisah dalam mode multi-jendela, Anda harus meluncurkannya dalam tumpukan tugas baru.
    -+</p>
    -+
    -+<h3 id="dnd">Mendukung seret dan lepas</h3>
    -+
    -+<p>
    -+  Pengguna bisa <a href="{@docRoot}guide/topics/ui/drag-drop.html">menyeret dan
    -+  melepas</a> data dari satu aktivitas ke aktivitas yang lain selagi kedua aktivitas
    -+  berbagi layar. (Sebelumnya, pengguna hanya bisa menyeret dan melepas data dalam
    -+   aktivitas tunggal.) Karena alasan ini, Anda mungkin perlu menambahkan fungsionalitas
    -+  seret dan lepas ke aplikasi jika aplikasi saat ini belum mendukungnya.
    -+</p>
    -+
    -+<p>
    -+  N Preview SDK menambahkan paket <a href="{@docRoot}reference/android/view/package-summary.html"><code>android.view</code></a>
    -+  untuk mendukung seret dan lepas lintas-aplikasi. Untuk mengetahui detail tentang kelas dan metode
    -+  berikut, lihat <a href="{@docRoot}preview/setup-sdk.html#docs-dl">Referensi N
    -+  Preview SDK</a>.
    -+</p>
    -+
    -+<dl>
    -+  <dt>
    -+    <code>android.view.DropPermissions</code>
    -+  </dt>
    -+
    -+  <dd>
    -+    Objek token bertanggung jawab menetapkan izin yang diberikan kepada aplikasi
    -+    yang menerima pelepasan tersebut.
    -+  </dd>
    -+
    -+  <dt>
    -+    <code>View.startDragAndDrop()</code>
    -+  </dt>
    -+
    -+  <dd>
    -+    Alias baru untuk {@link android.view.View#startDrag View.startDrag()}. Untuk
    -+    mengaktifkan seret dan lepas lintas-aktivitas, teruskan flag baru
    -+    <code>View.DRAG_FLAG_GLOBAL</code>. Jika Anda perlu memberikan izin URI ke
    -+    aktivitas penerima, teruskan flag baru,
    -+    <code>View.DRAG_FLAG_GLOBAL_URI_READ</code> atau
    -+    <code>View.DRAG_FLAG_GLOBAL_URI_WRITE</code>, sebagaimana mestinya.
    -+  </dd>
    -+
    -+  <dt>
    -+    <code>View.cancelDragAndDrop()</code>
    -+  </dt>
    -+
    -+  <dd>
    -+    Membatalkan operasi seret yang sedang berlangsung. Hanya bisa dipanggil oleh
    -+    aplikasi yang menghasilkan operasi seret.
    -+  </dd>
    -+
    -+  <dt>
    -+    <code>View.updateDragShadow()</code>
    -+  </dt>
    -+
    -+  <dd>
    -+    Menggantikan bayangan penyeretan untuk operasi seret yang sedang berlangsung. Hanya
    -+    bisa dipanggil oleh aplikasi yang menghasilkan operasi seret.
    -+  </dd>
    -+
    -+  <dt>
    -+    <code>Activity.requestDropPermissions()</code>
    -+  </dt>
    -+
    -+  <dd>
    -+    Meminta izin untuk URI materi yang diteruskan dengan {@link
    -+    android.content.ClipData} yang terdapat dalam {@link android.view.DragEvent}.
    -+  </dd>
    -+</dl>
    -+
    -+<h2 id="testing">Menguji Dukungan Multi-Jendela Aplikasi Anda</h2>
    -+
    -+<p>
    -+  Apakah Anda memperbarui aplikasi untuk Android N atau tidak, Anda harus
    -+  verifikasi bagaimana perilakunya di mode multi-jendela saat pengguna mencoba untuk menjalankannya
    -+  dalam mode multi-jendela pada perangkat yang menjalankan Android N.
    -+</p>
    -+
    -+<h3 id="configuring">Mengonfigurasi Perangkat Pengujian</h3>
    -+
    -+<p>
    -+  Jika Anda pasang Android N pada perangkat, mode
    -+  layar terbagi secara otomatis didukung.
    -+</p>
    -+
    -+<h3 id="test-non-n">Jika aplikasi Anda tidak dibangun dengan N Preview SDK</h3>
    -+
    -+<p>
    -+  Jika Anda tidak membangun aplikasi dengan N Preview SDK dan pengguna berupaya menggunakan
    -+  aplikasi dalam mode multi-jendela, sistem secara paksa akan mengubah ukuran aplikasi kecuali jika aplikasi
    -+  mendeklarasikan orientasi tetap.
    -+</p>
    -+
    -+<p>
    -+  Jika aplikasi Anda tidak mendeklarasikan orientasi tetap, Anda harus meluncurkan aplikasi
    -+  pada perangkat yang menjalankan Android N dan berupaya menempatkan aplikasi tersebut dalam
    -+  mode layar terbagi. Verifikasi pengalaman pengguna
    -+  bisa diterima bila aplikasi secara paksa diubah ukurannya.
    -+</p>
    -+
    -+<p>
    -+  Jika aplikasi mendeklarasikan orientasi tetap, Anda harus berupaya menempatkan aplikasi dalam
    -+  mode multi-jendela. Verifikasi apakah saat Anda melakukannya, aplikasi tetap berada dalam
    -+  mode layar penuh.
    -+</p>
    -+
    -+<h3 id="test-mw">Jika Anda mendukung mode multi-jendela</h3>
    -+
    -+<p>
    -+  Jika Anda membuat aplikasi Anda dengan N Preview SDK dan belum menonaktifkan
    -+  dukungan multi-jendela, verifikasi perilaku berikut dalam mode layar terbagi
    -+   dan mode bentuk bebas.
    -+</p>
    -+
    -+<ul>
    -+  <li>Luncurkan aplikasi dalam mode layar penuh, kemudian beralih ke mode multi-jendela dengan
    -+   menekan lama pada tombol Ringkasan. Verifikasi apakah aplikasi beralih dengan benar.
    -+  </li>
    -+
    -+  <li>Jalankan aplikasi secara langsung dalam mode multi-jendela, dan verifikasi aplikasi
    -+  diluncurkan dengan benar. Anda bisa meluncurkan aplikasi dalam mode multi-jendela dengan menekan
    -+  tombol Ringkasan, kemudian menekan lama baris judul pada aplikasi Anda dan menyeretnya
    -+  ke salah satu area yang disorot di layar.
    -+  </li>
    -+
    -+  <li>Ubah ukuran aplikasi Anda dalam mode layar terbagi dengan menyeret garis pembagi.
    -+  Verifikasi apakah aplikasi mengubah ukuran tanpa mogok, dan apakah elemen UI yang diperlukan
    -+  terlihat.
    -+  </li>
    -+
    -+  <li>Jika Anda telah menetapkan dimensi minimum aplikasi, cobalah untuk mengubah ukuran
    -+  aplikasi di bawah dimensi tersebut. Verifikasi apakah Anda tidak bisa mengubah ukuran aplikasi menjadi
    -+  lebih kecil dari minimum yang ditetapkan.
    -+  </li>
    -+
    -+  <li>Melalui semua pengujian, verifikasi apakah kinerja aplikasi Anda bisa diterima. Misalnya,
    -+  verifikasi apakah tidak ada jeda yang terlalu lama untuk memperbarui UI setelah
    -+  aplikasi diubah ukurannya.
    -+  </li>
    -+</ul>
    -+
    -+<h4 id="test-checklist">Daftar periksa pengujian</h4>
    -+
    -+<p>
    -+  Untuk verifikasi kinerja aplikasi Anda dalam mode multi-jendela, cobalah operasi
    -+  berikut. Anda harus mencoba semua operasi ini dalam mode layar terbagi dan
    -+   dan mode multi-jendela, kecuali jika dinyatakan berbeda.
    -+</p>
    -+
    -+<ul>
    -+  <li>Masuki dan tinggalkan mode multi-jendela.
    -+  </li>
    -+
    -+  <li>Beralih dari aplikasi Anda ke aplikasi lain, dan verifikasi apakah aplikasi berperilaku
    -+   sebagaimana mestinya saat terlihat namun tidak aktif. Misalnya, jika aplikasi Anda
    -+   sedang memutar video, verifikasi apakah video terus diputar selagi pengguna
    -+  berinteraksi dengan aplikasi lain.
    -+  </li>
    -+
    -+  <li>Dalam mode layar terbagi, cobalah menggeser garis pembagi untuk membuat aplikasi
    -+  Anda menjadi lebih besar dan lebih kecil. Coba operasi ini dalam konfigurasi berdampingan dan
    -+  atas-bawah. Verifikasi apakah aplikasi tidak mogok,
    -+  fungsionalitas penting bisa terlihat, dan operasi mengubah ukuran tidak memakan waktu terlalu
    -+  lama.
    -+  </li>
    -+
    -+  <li>Lakukan beberapa operasi ubah ukuran berturut-turut dalam waktu cepat. Verifikasi apakah
    -+  aplikasi Anda tidak mogok atau mengalami kebocoran memori. Untuk informasi tentang memeriksa penggunaan memori
    -+  aplikasi Anda, lihat <a href="{@docRoot}tools/debugging/debugging-memory.html">
    -+  Menyelidiki Penggunaan RAM Anda</a>.
    -+  </li>
    -+
    -+  <li>Gunakan aplikasi secara normal di sejumlah konfigurasi jendela yang berbeda, dan
    -+  verifikasi apakah aplikasi berperilaku sebagaimana mestinya. Verifikasi apakah teks terbaca, dan apakah
    -+  elemen UI tidak terlalu kecil untuk interaksi.
    -+  </li>
    -+</ul>
    -+
    -+<h3 id="test-disabled-mw">Jika Anda telah menonaktifkan dukungan multi-jendela</h3>
    -+
    -+<p>
    -+  Jika Anda menonaktifkan dukungan multi-jendela dengan menyetel
    -+  <code>android:resizableActivity="false"</code>, Anda harus menjalankan aplikasi pada
    -+  perangkat yang menjalankan Android N dan berusaha menempatkan aplikasi dalam
    -+  mode bentuk bebas dan mode layar terbagi. Verifikasi apakah saat Anda melakukannya, aplikasi tetap berada dalam
    -+  mode layar penuh.
    -+</p>
    -diff --git a/docs/html-intl/intl/id/guide/topics/ui/notifiers/notifications.jd b/docs/html-intl/intl/id/guide/topics/ui/notifiers/notifications.jd
    -new file mode 100644
    -index 0000000..bb48b80
    ---- /dev/null
    -+++ b/docs/html-intl/intl/id/guide/topics/ui/notifiers/notifications.jd
    -@@ -0,0 +1,979 @@
    -+page.title=Pemberitahuan
    -+@jd:body
    -+
    -+<div id="qv-wrapper">
    -+<div id="qv">
    -+<h2>Dalam dokumen ini</h2>
    -+<ol>
    -+  <li><a href="#Design">Pertimbangan Desain</a></li>
    -+  <li><a href="#CreateNotification">Membuat Pemberitahuan</a>
    -+    <ol>
    -+      <li><a href="#Required">Isi pemberitahuan yang diperlukan</a></li>
    -+      <li><a href="#Optional">Isi dan pengaturan pemberitahuan opsional</a></li>
    -+      <li><a href="#Actions">Tindakan pemberitahuan</a></li>
    -+      <li><a href="#Priority">Prioritas pemberitahuan</a></li>
    -+      <li><a href="#SimpleNotification">Membuat pemberitahuan sederhana</a></li>
    -+      <li><a href="#ApplyStyle">Menerapkan layout yang diperluas pada pemberitahuan</a></li>
    -+      <li><a href="#Compatibility">Menangani kompatibilitas</a></li>
    -+    </ol>
    -+  </li>
    -+  <li><a href="#Managing">Mengelola Pemberitahuan</a>
    -+    <ol>
    -+      <li><a href="#Updating">Memperbarui pemberitahuan</a></li>
    -+      <li><a href="#Removing">Menghapus pemberitahuan</a></li>
    -+    </ol>
    -+  </li>
    -+  <li><a href="#NotificationResponse">Mempertahankan Navigasi saat Memulai Aktivitas</a>
    -+    <ol>
    -+      <li><a href="#DirectEntry">Menyiapkan PendingIntent aktivitas biasa</a></li>
    -+      <li><a href="#ExtendedNotification">Menyiapkan PendingIntent aktivitas khusus</a></li>
    -+    </ol>
    -+  </li>
    -+  <li><a href="#Progress">Menampilkan Kemajuan dalam Pemberitahuan</a>
    -+    <ol>
    -+      <li><a href="#FixedProgress">Menampilkan indikator kemajuan berdurasi tetap</a></li>
    -+      <li><a href="#ActivityIndicator">Menampilkan indikator aktivitas berlanjut</a></li>
    -+    </ol>
    -+  </li>
    -+  <li><a href="#metadata">Metadata Pemberitahuan</a></li>
    -+  <li><a href="#Heads-up">Pemberitahuan Pendahuluan</a></li>
    -+  <li><a href="#lockscreenNotification">Pemberitahuan Layar Kunci</a></li>
    -+    <ol>
    -+      <li><a href="#visibility">Mengatur Visibilitas</a></li>
    -+      <li><a href="#controllingMedia">Mengontrol Pemutaran Media pada Layar Kunci</a></li>
    -+    </ol>
    -+  <li><a href="#CustomNotification">Layout Pemberitahuan Custom</a></li>
    -+</ol>
    -+
    -+    <h2>Kelas-kelas utama</h2>
    -+    <ol>
    -+        <li>{@link android.app.NotificationManager}</li>
    -+        <li>{@link android.support.v4.app.NotificationCompat}</li>
    -+    </ol>
    -+    <h2>Video</h2>
    -+    <ol>
    -+        <li>
    -+            <a href="http://www.youtube.com/watch?v=Yc8YrVc47TI&amp;feature=player_detailpage#t=1672s">
    -+            Pemberitahuan di 4.1</a>
    -+        </li>
    -+    </ol>
    -+<h2>Lihat juga</h2>
    -+<ol>
    -+    <li>
    -+        <a href="{@docRoot}design/patterns/notifications.html">Desain Android: Pemberitahuan</a>
    -+    </li>
    -+</ol>
    -+</div>
    -+</div>
    -+<p>
    -+    Pemberitahuan adalah pesan yang bisa Anda tampilkan kepada pengguna di luar
    -+    UI normal aplikasi. Bila Anda memberi tahu sistem untuk mengeluarkan pemberitahuan, pemberitahuan akan muncul lebih dahulu sebagai ikon dalam
    -+    <strong>area pemberitahuan</strong>. Untuk melihat detail pemberitahuan, pengguna membuka
    -+    <strong>laci pemberitahuan</strong>. Baik area pemberitahuan maupun laci pemberitahuan
    -+    adalah area-area yang dikontrol sistem yang bisa dilihat pengguna kapan saja.
    -+</p>
    -+<img id="figure1" src="{@docRoot}images/ui/notifications/notification_area.png" height="" alt="" />
    -+<p class="img-caption">
    -+    <strong>Gambar 1.</strong> Pemberitahuan di area pemberitahuan.
    -+</p>
    -+<img id="figure2" src="{@docRoot}images/ui/notifications/notification_drawer.png" width="280px" alt="" />
    -+<p class="img-caption">
    -+    <strong>Gambar 2.</strong> Pemberitahuan di laci pemberitahuan.
    -+</p>
    -+
    -+<p class="note"><strong>Catatan:</strong> Kecuali disebutkan, panduan ini mengacu pada
    -+kelas {@link android.support.v4.app.NotificationCompat.Builder NotificationCompat.Builder}
    -+dalam <a href="{@docRoot}tools/support-library/index.html">Support Library</a> versi 4.
    -+Kelas {@link android.app.Notification.Builder Notification.Builder} telah ditambahkan pada Android
    -+3.0 (API level 11).</p>
    -+
    -+<h2 id="Design">Pertimbangan Desain</h2>
    -+
    -+<p>Pemberitahuan, sebagai bagian penting dari antarmuka pengguna Android, memiliki panduan desainnya sendiri.
    -+Perubahan desain materi yang diperkenalkan dalam Android 5.0 (API level 21) adalah sangat
    -+penting, dan Anda harus meninjau pelatihan <a href="{@docRoot}training/material/index.html">Desain Bahan</a>
    -+untuk informasi selengkapnya. Untuk mengetahui cara mendesain pemberitahuan dan interaksinya, bacalah panduan desain
    -+<a href="{@docRoot}design/patterns/notifications.html">Pemberitahuan</a>.</p>
    -+
    -+<h2 id="CreateNotification">Membuat Pemberitahuan</h2>
    -+
    -+<p>Anda menetapkan informasi dan tindakan UI bagi pemberitahuan dalam
    -+objek {@link android.support.v4.app.NotificationCompat.Builder NotificationCompat.Builder}.
    -+Untuk membuat pemberitahuan itu sendiri, panggil
    -+{@link android.support.v4.app.NotificationCompat.Builder#build NotificationCompat.Builder.build()},
    -+yang akan mengembalikan objek {@link android.app.Notification} berisi spesifikasi Anda. Untuk mengeluarkan
    -+pemberitahuan, Anda meneruskan objek {@link android.app.Notification} ke sistem dengan memanggil
    -+{@link android.app.NotificationManager#notify NotificationManager.notify()}.</p>
    -+
    -+<h3 id="Required">Isi pemberitahuan yang diperlukan</h3>
    -+<p>
    -+    Objek {@link android.app.Notification} <em>harus</em> berisi yang berikut ini:
    -+</p>
    -+<ul>
    -+    <li>
    -+        Ikon kecil, yang diatur dengan
    -+        {@link android.support.v4.app.NotificationCompat.Builder#setSmallIcon setSmallIcon()}
    -+    </li>
    -+    <li>
    -+        Judul, yang diatur dengan
    -+        {@link android.support.v4.app.NotificationCompat.Builder#setContentTitle setContentTitle()}
    -+    </li>
    -+    <li>
    -+        Teks detail, yang diatur dengan
    -+        {@link android.support.v4.app.NotificationCompat.Builder#setContentText setContentText()}
    -+    </li>
    -+</ul>
    -+<h3 id="Optional">Isi dan pengaturan pemberitahuan opsional</h3>
    -+<p>
    -+    Semua isi dan pengaturan pemberitahuan lainnya bersifat opsional. Untuk mengetahui selengkapnya tentang semua itu,
    -+    lihat dokumentasi acuan untuk {@link android.support.v4.app.NotificationCompat.Builder}.
    -+</p>
    -+<!-- ------------------------------------------------------------------------------------------ -->
    -+<h3 id="Actions">Tindakan pemberitahuan</h3>
    -+<p>
    -+    Walaupun bersifat opsional, Anda harus menambahkan setidaknya satu tindakan pada pemberitahuan.
    -+    Tindakan memungkinkan pengguna beralih langsung dari pemberitahuan ke
    -+    {@link android.app.Activity} dalam aplikasi Anda, tempat pengguna bisa melihat satu atau beberapa kejadian
    -+    atau melakukan pekerjaan lebih jauh.
    -+</p>
    -+<p>
    -+    Pemberitahuan bisa menyediakan beberapa tindakan sekaligus. Anda harus selalu mendefinisikan tindakan yang
    -+    akan diaktifkan bila pengguna mengklik pemberitahuan; biasanya tindakan ini akan membuka
    -+    {@link android.app.Activity} dalam aplikasi Anda. Anda juga bisa menambahkan tombol pada pemberitahuan
    -+    yang melakukan tindakan tambahan seperti mendiamkan alarm atau segera merespons
    -+    pesan teks; fitur ini tersedia mulai Android 4.1. Jika menggunakan tombol tindakan tambahan, Anda
    -+    juga harus membuat fungsionalitasnya tersedia dalam {@link android.app.Activity} di aplikasi Anda; lihat
    -+    bagian <a href="#Compatibility">Menangani kompatibilitas</a> untuk detail selengkapnya.
    -+</p>
    -+<p>
    -+    Dalam {@link android.app.Notification}, tindakan itu sendiri didefinisikan oleh
    -+    {@link android.app.PendingIntent} berisi
    -+    {@link android.content.Intent} yang memulai
    -+    {@link android.app.Activity} dalam aplikasi Anda. Untuk mengaitkan
    -+    {@link android.app.PendingIntent} dengan gestur, panggil metode
    -+    {@link android.support.v4.app.NotificationCompat.Builder} yang sesuai. Misalnya, jika ingin memulai
    -+    {@link android.app.Activity} bila pengguna mengklik teks pemberitahuan pada
    -+    laci pemberitahuan, tambahkan {@link android.app.PendingIntent} dengan memanggil
    -+    {@link android.support.v4.app.NotificationCompat.Builder#setContentIntent setContentIntent()}.
    -+</p>
    -+<p>
    -+    Memulai {@link android.app.Activity} bila pengguna mengklik pemberitahuan adalah
    -+    skenario tindakan yang paling umum. Anda juga bisa memulai {@link android.app.Activity} bila pengguna
    -+    menghilangkan pemberitahuan. Dalam Android 4.1 dan yang lebih baru, Anda bisa memulai
    -+    {@link android.app.Activity} dari tombol tindakan. Untuk mengetahui selengkapnya, bacalah panduan acuan untuk
    -+    {@link android.support.v4.app.NotificationCompat.Builder}.
    -+</p>
    -+<!-- ------------------------------------------------------------------------------------------ -->
    -+<h3 id="Priority">Prioritas pemberitahuan</h3>
    -+<p>
    -+    Jika diinginkan, Anda bisa mengatur prioritas pemberitahuan. Prioritas berfungsi
    -+    sebagai petunjuk bagi UI perangkat tentang cara menampilkan pemberitahuan.
    -+    Untuk mengatur prioritas pemberitahuan, panggil {@link
    -+    android.support.v4.app.NotificationCompat.Builder#setPriority(int)
    -+    NotificationCompat.Builder.setPriority()} dan teruskan salah satu konstanta prioritas {@link
    -+    android.support.v4.app.NotificationCompat}. Ada
    -+    lima level prioritas, mulai dari {@link
    -+    android.support.v4.app.NotificationCompat#PRIORITY_MIN} (-2) hingga {@link
    -+    android.support.v4.app.NotificationCompat#PRIORITY_MAX} (2); jika tidak diatur,
    -+    prioritas default akan ditetapkan {@link
    -+    android.support.v4.app.NotificationCompat#PRIORITY_DEFAULT} (0).
    -+</p>
    -+<p> Untuk informasi tentang mengatur level prioritas, lihat "Mengatur
    -+    dan mengelola prioritas pemberitahuan dengan benar" dalam panduan
    -+Desain <a href="{@docRoot}design/patterns/notifications.html">Pemberitahuan</a>.
    -+</p>
    -+<!-- ------------------------------------------------------------------------------------------ -->
    -+<h3 id="SimpleNotification">Membuat pemberitahuan sederhana</h3>
    -+<p>
    -+    Cuplikan berikut mengilustrasikan pemberitahuan sederhana yang menetapkan aktivitas untuk dibuka bila
    -+    pengguna mengklik pemberitahuan. Perhatikan bahwa kode ini membuat
    -+    objek {@link android.support.v4.app.TaskStackBuilder} dan menggunakannya untuk membuat
    -+    {@link android.app.PendingIntent} untuk tindakan. Pola ini dijelaskan secara lebih detail
    -+    di bagian <a href="#NotificationResponse">
    -+    Mempertahankan Navigasi saat Memulai Aktivitas</a>:
    -+</p>
    -+<pre>
    -+NotificationCompat.Builder mBuilder =
    -+        new NotificationCompat.Builder(this)
    -+        .setSmallIcon(R.drawable.notification_icon)
    -+        .setContentTitle("My notification")
    -+        .setContentText("Hello World!");
    -+// Creates an explicit intent for an Activity in your app
    -+Intent resultIntent = new Intent(this, ResultActivity.class);
    -+
    -+// The stack builder object will contain an artificial back stack for the
    -+// started Activity.
    -+// This ensures that navigating backward from the Activity leads out of
    -+// your application to the Home screen.
    -+TaskStackBuilder stackBuilder = TaskStackBuilder.create(this);
    -+// Adds the back stack for the Intent (but not the Intent itself)
    -+stackBuilder.addParentStack(ResultActivity.class);
    -+// Adds the Intent that starts the Activity to the top of the stack
    -+stackBuilder.addNextIntent(resultIntent);
    -+PendingIntent resultPendingIntent =
    -+        stackBuilder.getPendingIntent(
    -+            0,
    -+            PendingIntent.FLAG_UPDATE_CURRENT
    -+        );
    -+mBuilder.setContentIntent(resultPendingIntent);
    -+NotificationManager mNotificationManager =
    -+    (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
    -+// mId allows you to update the notification later on.
    -+mNotificationManager.notify(mId, mBuilder.build());
    -+</pre>
    -+<p>Demikian saja. Pengguna Anda kini telah diberi tahu.</p>
    -+<!-- ------------------------------------------------------------------------------------------ -->
    -+<h3 id="ApplyStyle">Menerapkan layout yang diperluas pada pemberitahuan</h3>
    -+<p>
    -+    Agar pemberitahuan muncul dalam tampilan yang diperluas, buat dahulu
    -+    objek {@link android.support.v4.app.NotificationCompat.Builder} dengan opsi tampilan normal
    -+    yang Anda inginkan. Berikutnya, panggil {@link android.support.v4.app.NotificationCompat.Builder#setStyle
    -+    Builder.setStyle()}  dengan objek layout yang diperluas sebagai argumennya.
    -+</p>
    -+<p>
    -+    Ingatlah bahwa pemberitahuan yang diperluas tidak tersedia pada platform-platform sebelum Android 4.1. Untuk
    -+    mengetahui cara menangani pemberitahuan untuk Android 4.1 dan untuk platform-platform sebelumnya, bacalah
    -+    bagian <a href="#Compatibility">Menangani kompatibilitas</a>.
    -+</p>
    -+<p>
    -+    Misalnya, cuplikan kode berikut memperagakan cara mengubah pemberitahuan yang dibuat
    -+    dalam cuplikan sebelumnya untuk menggunakan layout yang diperluas:
    -+</p>
    -+<pre>
    -+NotificationCompat.Builder mBuilder = new NotificationCompat.Builder(this)
    -+    .setSmallIcon(R.drawable.notification_icon)
    -+    .setContentTitle("Event tracker")
    -+    .setContentText("Events received")
    -+NotificationCompat.InboxStyle inboxStyle =
    -+        new NotificationCompat.InboxStyle();
    -+String[] events = new String[6];
    -+// Sets a title for the Inbox in expanded layout
    -+inboxStyle.setBigContentTitle("Event tracker details:");
    -+...
    -+// Moves events into the expanded layout
    -+for (int i=0; i &lt; events.length; i++) {
    -+
    -+    inboxStyle.addLine(events[i]);
    -+}
    -+// Moves the expanded layout object into the notification object.
    -+mBuilder.setStyle(inBoxStyle);
    -+...
    -+// Issue the notification here.
    -+</pre>
    -+
    -+<h3 id="Compatibility">Menangani kompatibilitas</h3>
    -+
    -+<p>
    -+    Tidak semua fitur pemberitahuan tersedia untuk versi tertentu, walaupun
    -+    metode untuk mengaturnya ada dalam kelas pustaka dukungan
    -+    {@link android.support.v4.app.NotificationCompat.Builder NotificationCompat.Builder}.
    -+    Misalnya, tombol tindakan, yang bergantung pada pemberitahuan yang diperluas, hanya muncul pada Android
    -+    4.1 dan lebih tinggi, karena pemberitahuan yang diperluas itu sendiri hanya tersedia pada
    -+    Android 4.1 dan yang lebih tinggi.
    -+</p>
    -+<p>
    -+    Untuk memastikan kompatibilitas terbaik, buatlah pemberitahuan dengan
    -+    {@link android.support.v4.app.NotificationCompat NotificationCompat} dan subkelasnya,
    -+    khususnya {@link android.support.v4.app.NotificationCompat.Builder
    -+    NotificationCompat.Builder}. Selain itu, ikutilah proses ini bila Anda mengimplementasikan pemberitahuan:
    -+</p>
    -+<ol>
    -+    <li>
    -+        Sediakan semua fungsionalitas pemberitahuan kepada semua pengguna, terlepas dari versi
    -+        yang mereka gunakan. Caranya, pastikan semua fungsionalitas tersedia dari
    -+        {@link android.app.Activity} dalam aplikasi Anda. Anda mungkin perlu menambahkan sebuah
    -+        {@link android.app.Activity} baru untuk melakukannya.
    -+        <p>
    -+            Misalnya, jika Anda ingin menggunakan
    -+            {@link android.support.v4.app.NotificationCompat.Builder#addAction addAction()} untuk
    -+            menyediakan kontrol yang menghentikan dan memulai pemutaran media, implementasikan dahulu
    -+            kontrol ini pada {@link android.app.Activity} dalam aplikasi Anda.
    -+        </p>
    -+    </li>
    -+    <li>
    -+        Pastikan semua pengguna bisa memperoleh fungsionalitas dalam {@link android.app.Activity},
    -+        dengan memulainya bila pengguna mengklik pemberitahuan. Caranya,
    -+        buatlah {@link android.app.PendingIntent}
    -+        untuk {@link android.app.Activity}. Panggil
    -+        {@link android.support.v4.app.NotificationCompat.Builder#setContentIntent
    -+        setContentIntent()} untuk menambahkan {@link android.app.PendingIntent} pada pemberitahuan.
    -+    </li>
    -+    <li>
    -+        Kini tambahkan fitur pemberitahuan diperluas yang ingin Anda gunakan pada pemberitahuan. Ingatlah
    -+        bahwa setiap fungsionalitas yang Anda tambahkan juga harus tersedia dalam {@link android.app.Activity}
    -+        yang akan dimulai bila pengguna mengklik pemberitahuan.
    -+    </li>
    -+</ol>
    -+
    -+
    -+<!-- ------------------------------------------------------------------------------------------ -->
    -+<!-- ------------------------------------------------------------------------------------------ -->
    -+<h2 id="Managing">Mengelola Pemberitahuan</h2>
    -+<p>
    -+    Bila perlu mengeluarkan pemberitahuan beberapa kali untuk tipe kejadian yang sama,
    -+hindari membuat pemberitahuan yang sama sekali baru. Sebagai gantinya, Anda harus mempertimbangkan untuk memperbarui
    -+    pemberitahuan sebelumnya, baik dengan mengubah sebagian nilainya atau dengan menambahkan nilai, atau keduanya.
    -+</p>
    -+<p>
    -+    Misalnya, Gmail akan memberi tahu pengguna bila ada email baru dengan menambah hitungan
    -+    pesan tidak terbaca dan dengan menambahkan rangkuman tiap email ke pemberitahuan. Ini disebut dengan
    -+    "stacking" (menumpuk) pemberitahuan; hal ini dijelaskan lebih detail dalam panduan
    -+    Desain <a href="{@docRoot}design/patterns/notifications.html">Pemberitahuan</a>.
    -+</p>
    -+<p class="note">
    -+    <strong>Catatan:</strong> Fitur Gmail ini mensyaratkan layout "kotak masuk" diperluas, yang merupakan
    -+    bagian dari fitur pemberitahuan diperluas yang tersedia mulai Android 4.1.
    -+</p>
    -+<p>
    -+    Bagian berikut menjelaskan cara memperbarui pemberitahuan dan cara menghapusnya.
    -+</p>
    -+<h3 id="Updating">Memperbarui pemberitahuan</h3>
    -+<p>
    -+    Untuk menyiapkan pemberitahuan agar bisa diperbarui, keluarkan pemberitahuan bersama ID pemberitahuan dengan
    -+    memanggil {@link android.app.NotificationManager#notify(int, android.app.Notification) NotificationManager.notify()}.
    -+    Untuk memperbarui pemberitahuan ini setelah Anda
    -+    mengeluarkan, memperbarui, atau membuat objek {@link android.support.v4.app.NotificationCompat.Builder},
    -+    buat objek {@link android.app.Notification} darinya, dan keluarkan
    -+    {@link android.app.Notification} bersama ID yang sama dengan yang Anda gunakan sebelumnya. Jika
    -+    pemberitahuan sebelumnya tetap terlihat, sistem akan memperbaruinya dari konten
    -+    objek {@link android.app.Notification}. Jika pemberitahuan sebelumnya telah dihilangkan, sebuah
    -+    pemberitahuan baru akan dibuat.
    -+</p>
    -+<p>
    -+    Cuplikan berikut memperagakan pemberitahuan yang diperbarui untuk mencerminkan
    -+    jumlah kejadian yang telah terjadi. Cuplikan ini menumpuk pemberitahuan, yang menampilkan rangkuman:
    -+</p>
    -+<pre>
    -+mNotificationManager =
    -+        (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
    -+// Sets an ID for the notification, so it can be updated
    -+int notifyID = 1;
    -+mNotifyBuilder = new NotificationCompat.Builder(this)
    -+    .setContentTitle("New Message")
    -+    .setContentText("You've received new messages.")
    -+    .setSmallIcon(R.drawable.ic_notify_status)
    -+numMessages = 0;
    -+// Start of a loop that processes data and then notifies the user
    -+...
    -+    mNotifyBuilder.setContentText(currentText)
    -+        .setNumber(++numMessages);
    -+    // Because the ID remains unchanged, the existing notification is
    -+    // updated.
    -+    mNotificationManager.notify(
    -+            notifyID,
    -+            mNotifyBuilder.build());
    -+...
    -+</pre>
    -+
    -+<!-- ------------------------------------------------------------------------------------------ -->
    -+<h3 id="Removing">Menghapus pemberitahuan</h3>
    -+<p>
    -+    Pemberitahuan tetap terlihat hingga salah satu kejadian berikut terjadi:
    -+</p>
    -+<ul>
    -+    <li>
    -+        Pengguna menghilangkan pemberitahuan satu per satu atau dengan menggunakan "Clear All" (jika
    -+        pemberitahuan bisa dihapus).
    -+    </li>
    -+    <li>
    -+        Pengguna mengklik pemberitahuan, dan Anda memanggil
    -+        {@link android.support.v4.app.NotificationCompat.Builder#setAutoCancel setAutoCancel()} bila
    -+        Anda telah membuat pemberitahuan.
    -+    </li>
    -+    <li>
    -+        Anda memanggil {@link android.app.NotificationManager#cancel(int) cancel()} untuk
    -+        ID pemberitahuan tertentu. Metode ini juga menghapus pemberitahuan yang berjalan.
    -+    </li>
    -+    <li>
    -+        Anda memanggil {@link android.app.NotificationManager#cancelAll() cancelAll()}, yang menghapus
    -+        semua pemberitahuan yang dikeluarkan sebelumnya.
    -+    </li>
    -+</ul>
    -+<!-- ------------------------------------------------------------------------------------------ -->
    -+<!-- ------------------------------------------------------------------------------------------ -->
    -+<h2 id="NotificationResponse">Mempertahankan Navigasi saat Memulai Aktivitas</h2>
    -+<p>
    -+    Bila memulai {@link android.app.Activity} dari pemberitahuan, Anda harus mempertahankan
    -+    pengalaman navigasi yang diharapkan pengguna. Mengklik <i>Back</i> harus membawa pengguna kembali melalui
    -+    aliran pekerjaan normal aplikasi ke layar Home, dan mengklik <i>Recents</i> harus menampilkan
    -+    {@link android.app.Activity} sebagai tugas terpisah. Untuk mempertahankan pengalaman navigasi, Anda
    -+    harus memulai {@link android.app.Activity} dalam tugas baru. Cara menyiapkan
    -+    {@link android.app.PendingIntent} untuk memberi Anda tugas baru bergantung pada sifat
    -+    {@link android.app.Activity} yang Anda mulai. Ada dua situasi umum:
    -+</p>
    -+<dl>
    -+    <dt>
    -+        Aktivitas rutin
    -+    </dt>
    -+    <dd>
    -+        Anda memulai {@link android.app.Activity} yang merupakan bagian dari aliran pekerjaan normal
    -+        aplikasi. Dalam situasi ini, siapkan {@link android.app.PendingIntent} untuk
    -+        memulai tugas baru, dan sediakan {@link android.app.PendingIntent} bersama back-stack
    -+        yang meniru perilaku <i>Back</i> biasa.
    -+        <p>
    -+            Pemberitahuan dari aplikasi Gmail memperagakan hal ini. Bila Anda mengklik pemberitahuan untuk
    -+            satu pesan email, Anda akan melihat pesan itu sendiri. Menyentuh <b>Back</b> akan membawa Anda
    -+            kembali melalui Gmail ke layar Home, persis seperti jika memasuki Gmail dari
    -+            layar Home bukannya memasukinya dari pemberitahuan.
    -+        </p>
    -+        <p>
    -+            Hal ini terjadi terlepas dari aplikasi tempat Anda berada saat menyentuh
    -+            pemberitahuan. Misalnya, jika Anda dalam Gmail sedang menulis pesan, dan Anda mengklik
    -+            pemberitahuan untuk satu email, Anda akan segera dibawa ke email itu. Menyentuh <i>Back</i>
    -+            akan membawa Anda ke kotak masuk kemudian layar Home, bukannya membawa Anda ke
    -+            pesan yang sedang ditulis.
    -+        </p>
    -+    </dd>
    -+    <dt>
    -+        Aktivitas khusus
    -+    </dt>
    -+    <dd>
    -+        Pengguna hanya melihat {@link android.app.Activity} ini jika dimulai dari pemberitahuan.
    -+        Dalam beberapa hal, {@link android.app.Activity} akan memperluas pemberitahuan dengan menyediakan
    -+        informasi yang akan sulit untuk ditampilkan dalam pemberitahuan itu sendiri. Untuk situasi ini,
    -+        siapkan {@link android.app.PendingIntent} untuk dimulai dalam tugas baru. Tidak perlu
    -+        membuat back-stack, karena {@link android.app.Activity} yang dimulai bukan bagian dari
    -+        aliran aktivitas aplikasi. Mengklik <i>Back</i> tetap akan membawa pengguna ke
    -+        layar Home.
    -+    </dd>
    -+</dl>
    -+<!-- ------------------------------------------------------------------------------------------ -->
    -+<h3 id="DirectEntry">Menyiapkan PendingIntent aktivitas biasa</h3>
    -+<p>
    -+    Untuk menyiapkan {@link android.app.PendingIntent} yang memulai entri langsung
    -+    {@link android.app.Activity}, ikuti langkah-langkah ini:
    -+</p>
    -+<ol>
    -+    <li>
    -+        Definisikan hierarki {@link android.app.Activity} aplikasi Anda dalam manifes.
    -+        <ol style="list-style-type: lower-alpha;">
    -+            <li>
    -+                Tambahkan dukungan untuk Android 4.0.3 dan yang terdahulu. Caranya, tetapkan induk
    -+                {@link android.app.Activity} yang Anda mulai dengan menambahkan elemen
    -+<code><a href="{@docRoot}guide/topics/manifest/meta-data-element.html">&lt;meta-data&gt;</a></code>
    -+                sebagai anak
    -+<code><a href="{@docRoot}guide/topics/manifest/activity-element.html">&lt;activity&gt;</a></code>.
    -+                <p>
    -+                    Untuk elemen ini, atur
    -+<code><a href="{@docRoot}guide/topics/manifest/meta-data-element.html#nm">android:name</a>="android.support.PARENT_ACTIVITY"</code>.
    -+                    Atur
    -+<code><a href="{@docRoot}guide/topics/manifest/meta-data-element.html#val">android:value</a>="&lt;parent_activity_name&gt;"</code>
    -+                    dengan <code>&lt;parent_activity_name&gt;</code> sebagai nilai
    -+<code><a href="{@docRoot}guide/topics/manifest/meta-data-element.html#nm">android:name</a></code>
    -+                    untuk elemen induk
    -+<code><a href="{@docRoot}guide/topics/manifest/activity-element.html">&lt;activity&gt;</a></code>
    -+. Lihat XML berikut sebagai contoh.
    -+                </p>
    -+            </li>
    -+            <li>
    -+                Juga tambahkan dukungan untuk Android 4.1 dan yang lebih baru. Caranya, tambahkan atribut
    -+<code><a href="{@docRoot}guide/topics/manifest/activity-element.html#parent">android:parentActivityName</a></code>
    -+                 pada elemen
    -+<code><a href="{@docRoot}guide/topics/manifest/activity-element.html">&lt;activity&gt;</a></code>
    -+                dari {@link android.app.Activity} yang Anda mulai.
    -+            </li>
    -+        </ol>
    -+        <p>
    -+            XML akhir akan terlihat seperti ini:
    -+        </p>
    -+<pre>
    -+&lt;activity
    -+    android:name=".MainActivity"
    -+    android:label="&#64;string/app_name" &gt;
    -+    &lt;intent-filter&gt;
    -+        &lt;action android:name="android.intent.action.MAIN" /&gt;
    -+        &lt;category android:name="android.intent.category.LAUNCHER" /&gt;
    -+    &lt;/intent-filter&gt;
    -+&lt;/activity&gt;
    -+&lt;activity
    -+    android:name=".ResultActivity"
    -+    android:parentActivityName=".MainActivity"&gt;
    -+    &lt;meta-data
    -+        android:name="android.support.PARENT_ACTIVITY"
    -+        android:value=".MainActivity"/&gt;
    -+&lt;/activity&gt;
    -+</pre>
    -+    </li>
    -+    <li>
    -+        Buat back-stack berdasarkan {@link android.content.Intent} yang memulai
    -+        {@link android.app.Activity}:
    -+        <ol style="list-style-type: lower-alpha;">
    -+            <li>
    -+                Buat {@link android.content.Intent} untuk memulai {@link android.app.Activity}.
    -+            </li>
    -+            <li>
    -+                Buat stack-builder (pembangun tumpukan) dengan memanggil {@link android.app.TaskStackBuilder#create
    -+                TaskStackBuilder.create()}.
    -+            </li>
    -+            <li>
    -+                Tambahkan back-stack ke stack-builder dengan memanggil
    -+                {@link android.support.v4.app.TaskStackBuilder#addParentStack addParentStack()}.
    -+                Untuk setiap {@link android.app.Activity} dalam hierarki yang telah Anda definisikan dalam
    -+                manifes, back-stack berisi objek {@link android.content.Intent} yang
    -+                memulai {@link android.app.Activity}. Metode ini juga menambahkan flag yang memulai
    -+                back-stack dalam tugas baru.
    -+                <p class="note">
    -+                    <strong>Catatan:</strong> Walaupun argumen untuk
    -+                    {@link android.support.v4.app.TaskStackBuilder#addParentStack addParentStack()}
    -+                    adalah acuan ke {@link android.app.Activity} yang dimulai, panggilan metode
    -+                    tidak akan menambahkan {@link android.content.Intent} yang memulai
    -+                    {@link android.app.Activity}. Sebagai gantinya, hal itu ditangani dalam langkah berikutnya.
    -+                </p>
    -+            </li>
    -+            <li>
    -+                Tambahkan {@link android.content.Intent} yang memulai {@link android.app.Activity}
    -+                dari pemberitahuan, dengan memanggil
    -+                {@link android.support.v4.app.TaskStackBuilder#addNextIntent addNextIntent()}.
    -+                Teruskan {@link android.content.Intent} yang Anda buat dalam langkah pertama sebagai
    -+                argumen ke
    -+                {@link android.support.v4.app.TaskStackBuilder#addNextIntent addNextIntent()}.
    -+            </li>
    -+            <li>
    -+                Jika perlu, tambahkan argumen ke objek {@link android.content.Intent} pada
    -+                back-stack dengan memanggil {@link android.support.v4.app.TaskStackBuilder#editIntentAt
    -+                TaskStackBuilder.editIntentAt()}. Kadang-kadang perlu memastikan apakah
    -+                {@link android.app.Activity} target menampilkan data bermakna saat pengguna menelusurinya
    -+                dengan menggunakan <i>Back</i>.
    -+            </li>
    -+            <li>
    -+                Dapatkan {@link android.app.PendingIntent} untuk back-stack ini dengan memanggil
    -+                {@link android.support.v4.app.TaskStackBuilder#getPendingIntent getPendingIntent()}.
    -+                Anda nanti bisa menggunakan {@link android.app.PendingIntent} ini sebagai argumen untuk
    -+                {@link android.support.v4.app.NotificationCompat.Builder#setContentIntent
    -+                setContentIntent()}.
    -+            </li>
    -+        </ol>
    -+     </li>
    -+</ol>
    -+<p>
    -+    Cuplikan kode berikut memperagakan prosesnya:
    -+</p>
    -+<pre>
    -+...
    -+Intent resultIntent = new Intent(this, ResultActivity.class);
    -+TaskStackBuilder stackBuilder = TaskStackBuilder.create(this);
    -+// Adds the back stack
    -+stackBuilder.addParentStack(ResultActivity.class);
    -+// Adds the Intent to the top of the stack
    -+stackBuilder.addNextIntent(resultIntent);
    -+// Gets a PendingIntent containing the entire back stack
    -+PendingIntent resultPendingIntent =
    -+        stackBuilder.getPendingIntent(0, PendingIntent.FLAG_UPDATE_CURRENT);
    -+...
    -+NotificationCompat.Builder builder = new NotificationCompat.Builder(this);
    -+builder.setContentIntent(resultPendingIntent);
    -+NotificationManager mNotificationManager =
    -+    (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
    -+mNotificationManager.notify(id, builder.build());
    -+</pre>
    -+<!-- ------------------------------------------------------------------------------------------ -->
    -+<h3 id="ExtendedNotification">Menyiapkan PendingIntent aktivitas khusus</h3>
    -+<p>
    -+    Bagian berikut menjelaskan cara menyiapkan aktivitas khusus
    -+    {@link android.app.PendingIntent}.
    -+</p>
    -+<p>
    -+    {@link android.app.Activity} khusus tidak memerlukan back-stack, sehingga Anda tidak perlu
    -+    mendefinisikan hierarki {@link android.app.Activity}-nya dalam manifes, dan Anda tidak perlu
    -+    memanggil
    -+    {@link android.support.v4.app.TaskStackBuilder#addParentStack  addParentStack()} untuk membuat
    -+    back-stack. Sebagai gantinya, gunakan manifes untuk menyiapkan opsi tugas {@link android.app.Activity},
    -+    dan buat {@link android.app.PendingIntent} dengan memanggil
    -+    {@link android.app.PendingIntent#getActivity getActivity()}:
    -+</p>
    -+<ol>
    -+    <li>
    -+        Dalam manifes, tambahkan atribut berikut pada elemen
    -+<code><a href="{@docRoot}guide/topics/manifest/activity-element.html">&lt;activity&gt;</a></code>
    -+        untuk {@link android.app.Activity}
    -+        <dl>
    -+            <dt>
    -+<code><a href="{@docRoot}guide/topics/manifest/activity-element.html#nm">android:name</a>="<i>activityclass</i>"</code>
    -+            </dt>
    -+            <dd>
    -+                Nama kelas mutlak (fully qualified) aktivitas.
    -+            </dd>
    -+            <dt>
    -+<code><a href="{@docRoot}guide/topics/manifest/activity-element.html#aff">android:taskAffinity</a>=""</code>
    -+            </dt>
    -+            <dd>
    -+                Dikombinasikan dengan flag
    -+                {@link android.content.Intent#FLAG_ACTIVITY_NEW_TASK FLAG_ACTIVITY_NEW_TASK}
    -+                yang Anda atur dalam kode, ini memastikan bahwa {@link android.app.Activity} ini tidak
    -+                masuk ke dalam tugas default aplikasi. Setiap tugas yang ada yang memiliki
    -+                afinitas default aplikasi tidak terpengaruh.
    -+            </dd>
    -+            <dt>
    -+<code><a href="{@docRoot}guide/topics/manifest/activity-element.html#exclude">android:excludeFromRecents</a>="true"</code>
    -+            </dt>
    -+            <dd>
    -+                Mengecualikan tugas baru dari <i>Recents</i>, sehingga pengguna tidak bisa tanpa sengaja
    -+                mengarahkan kembali.
    -+            </dd>
    -+        </dl>
    -+        <p>
    -+            Cuplikan ini menampilkan elemen:
    -+        </p>
    -+<pre>
    -+&lt;activity
    -+    android:name=".ResultActivity"
    -+...
    -+    android:launchMode="singleTask"
    -+    android:taskAffinity=""
    -+    android:excludeFromRecents="true"&gt;
    -+&lt;/activity&gt;
    -+...
    -+</pre>
    -+    </li>
    -+    <li>
    -+        Buat dan keluarkan pemberitahuan:
    -+        <ol style="list-style-type: lower-alpha;">
    -+            <li>
    -+                Buat {@link android.content.Intent} yang memulai
    -+                {@link android.app.Activity}.
    -+            </li>
    -+            <li>
    -+                Atur {@link android.app.Activity} untuk dimulai dalam tugas kosong yang baru dengan memanggil
    -+                {@link android.content.Intent#setFlags setFlags()} dengan flag
    -+                {@link android.content.Intent#FLAG_ACTIVITY_NEW_TASK FLAG_ACTIVITY_NEW_TASK}
    -+                dan
    -+                {@link android.content.Intent#FLAG_ACTIVITY_CLEAR_TASK FLAG_ACTIVITY_CLEAR_TASK}.
    -+            </li>
    -+            <li>
    -+                Atur setiap opsi lain yang Anda perlukan untuk {@link android.content.Intent}.
    -+            </li>
    -+            <li>
    -+                Buat {@link android.app.PendingIntent} dari {@link android.content.Intent}
    -+                dengan memanggil {@link android.app.PendingIntent#getActivity getActivity()}.
    -+                Anda nanti bisa menggunakan {@link android.app.PendingIntent} ini sebagai argumen untuk
    -+                {@link android.support.v4.app.NotificationCompat.Builder#setContentIntent
    -+                setContentIntent()}.
    -+            </li>
    -+        </ol>
    -+    <p>
    -+        Cuplikan kode berikut memperagakan prosesnya:
    -+    </p>
    -+<pre>
    -+// Instantiate a Builder object.
    -+NotificationCompat.Builder builder = new NotificationCompat.Builder(this);
    -+// Creates an Intent for the Activity
    -+Intent notifyIntent =
    -+        new Intent(this, ResultActivity.class);
    -+// Sets the Activity to start in a new, empty task
    -+notifyIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
    -+                        | Intent.FLAG_ACTIVITY_CLEAR_TASK);
    -+// Creates the PendingIntent
    -+PendingIntent notifyPendingIntent =
    -+        PendingIntent.getActivity(
    -+        this,
    -+        0,
    -+        notifyIntent,
    -+        PendingIntent.FLAG_UPDATE_CURRENT
    -+);
    -+
    -+// Puts the PendingIntent into the notification builder
    -+builder.setContentIntent(notifyPendingIntent);
    -+// Notifications are issued by sending them to the
    -+// NotificationManager system service.
    -+NotificationManager mNotificationManager =
    -+    (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
    -+// Builds an anonymous Notification object from the builder, and
    -+// passes it to the NotificationManager
    -+mNotificationManager.notify(id, builder.build());
    -+</pre>
    -+    </li>
    -+</ol>
    -+<!-- ------------------------------------------------------------------------------------------ -->
    -+<!-- ------------------------------------------------------------------------------------------ -->
    -+<h2 id="Progress">Menampilkan Kemajuan dalam Pemberitahuan</h2>
    -+<p>
    -+    Pemberitahuan bisa menyertakan indikator kemajuan beranimasi yang menampilkan status
    -+operasi yang berjalan kepada pengguna. Jika Anda bisa memperkirakan lamanya operasi berlangsung dan berapa banyak
    -+    yang sudah selesai pada suatu waktu, gunakan bentuk indikator yang "pasti"
    -+    (baris kemajuan). Jika Anda tidak bisa memperkirakan lamanya operasi, gunakan
    -+    bentuk indikator "tidak pasti" (indikator aktivitas).
    -+</p>
    -+<p>
    -+    Indikator kemajuan ditampilkan bersama implementasi platform
    -+    kelas {@link android.widget.ProgressBar}.
    -+</p>
    -+<p>
    -+    Untuk menggunakan indikator kemajuan pada platform mulai dari Android 4.0, panggil
    -+    {@link android.support.v4.app.NotificationCompat.Builder#setProgress setProgress()}. Untuk
    -+    versi sebelumnya, Anda harus membuat layout pemberitahuan custom sendiri yang
    -+menyertakan tampilan {@link android.widget.ProgressBar}.
    -+</p>
    -+<p>
    -+    Bagian berikut ini menjelaskan cara menampilkan kemajuan dalam pemberitahuan dengan menggunakan
    -+    {@link android.support.v4.app.NotificationCompat.Builder#setProgress setProgress()}.
    -+</p>
    -+<!-- ------------------------------------------------------------------------------------------ -->
    -+<h3 id="FixedProgress">Menampilkan indikator kemajuan berdurasi tetap</h3>
    -+<p>
    -+    Untuk menampilkan baris kemajuan pasti, tambahkan baris itu ke pemberitahuan dengan memanggil
    -+    {@link android.support.v4.app.NotificationCompat.Builder#setProgress
    -+    setProgress(max, progress, false)}, kemudian keluarkan pemberitahuan. Selagi operasi berlangsung,
    -+    tambah <code>progress</code>, dan perbarui pemberitahuan. Di akhir operasi,
    -+    <code>progress</code> harus sama dengan <code>max</code>. Satu cara umum memanggil
    -+    {@link android.support.v4.app.NotificationCompat.Builder#setProgress setProgress()}
    -+    adalah mengatur <code>max</code> ke 100, kemudian tambah <code>progress</code> sebagai
    -+     nilai "persen selesai"untuk operasi itu.
    -+</p>
    -+<p>
    -+    Anda bisa membiarkan baris kemajuan ditampilkan saat operasi selesai, atau menghilangkannya. Dalam
    -+    hal apa pun, ingatlah memperbarui teks pemberitahuan untuk menampilkan bahwa operasi telah selesai.
    -+    Untuk menghapus baris kemajuan, panggil
    -+    {@link android.support.v4.app.NotificationCompat.Builder#setProgress
    -+    setProgress(0, 0, false)}. Misalnya:
    -+</p>
    -+<pre>
    -+...
    -+mNotifyManager =
    -+        (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
    -+mBuilder = new NotificationCompat.Builder(this);
    -+mBuilder.setContentTitle("Picture Download")
    -+    .setContentText("Download in progress")
    -+    .setSmallIcon(R.drawable.ic_notification);
    -+// Start a lengthy operation in a background thread
    -+new Thread(
    -+    new Runnable() {
    -+        &#64;Override
    -+        public void run() {
    -+            int incr;
    -+            // Do the "lengthy" operation 20 times
    -+            for (incr = 0; incr &lt;= 100; incr+=5) {
    -+                    // Sets the progress indicator to a max value, the
    -+                    // current completion percentage, and "determinate"
    -+                    // state
    -+                    mBuilder.setProgress(100, incr, false);
    -+                    // Displays the progress bar for the first time.
    -+                    mNotifyManager.notify(0, mBuilder.build());
    -+                        // Sleeps the thread, simulating an operation
    -+                        // that takes time
    -+                        try {
    -+                            // Sleep for 5 seconds
    -+                            Thread.sleep(5*1000);
    -+                        } catch (InterruptedException e) {
    -+                            Log.d(TAG, "sleep failure");
    -+                        }
    -+            }
    -+            // When the loop is finished, updates the notification
    -+            mBuilder.setContentText("Download complete")
    -+            // Removes the progress bar
    -+                    .setProgress(0,0,false);
    -+            mNotifyManager.notify(ID, mBuilder.build());
    -+        }
    -+    }
    -+// Starts the thread by calling the run() method in its Runnable
    -+).start();
    -+</pre>
    -+
    -+<!-- ------------------------------------------------------------------------------------------ -->
    -+<h3 id="ActivityIndicator">Menampilkan indikator aktivitas berlanjut</h3>
    -+<p>
    -+    Untuk menampilkan indikator aktivitas tidak pasti, tambahkan aktivitas ke pemberitahuan dengan
    -+    {@link android.support.v4.app.NotificationCompat.Builder#setProgress setProgress(0, 0, true)}
    -+    (dua argumen pertama akan diabaikan), dan keluarkan pemberitahuan. Hasilnya adalah indikator
    -+    yang memiliki gaya yang sama dengan baris kemajuan, hanya saja animasinya terus berjalan.
    -+</p>
    -+<p>
    -+    Keluarkan pemberitahuan di awal operasi. Animasi akan berjalan hingga Anda
    -+    memodifikasi pemberitahuan. Bila operasi selesai, panggil
    -+    {@link android.support.v4.app.NotificationCompat.Builder#setProgress setProgress(0, 0, false)}
    -+    kemudian perbarui pemberitahuan untuk menghapus indikator aktivitas.
    -+    Selalu lakukan ini; jika makan animasi akan terus berjalan sekalipun operasi telah selesai. Juga
    -+    ingatlah mengubah teks pemberitahuan untuk menunjukkan bahwa operasi telah selesai.
    -+</p>
    -+<p>
    -+    Untuk melihat cara kerja indikator aktivitas, lihat cuplikan terdahulu. Cari lokasi baris-baris berikut:
    -+</p>
    -+<pre>
    -+// Sets the progress indicator to a max value, the current completion
    -+// percentage, and "determinate" state
    -+mBuilder.setProgress(100, incr, false);
    -+// Issues the notification
    -+mNotifyManager.notify(0, mBuilder.build());
    -+</pre>
    -+<p>
    -+    Ganti baris yang telah Anda temukan dengan baris berikut:
    -+</p>
    -+<pre>
    -+ // Sets an activity indicator for an operation of indeterminate length
    -+mBuilder.setProgress(0, 0, true);
    -+// Issues the notification
    -+mNotifyManager.notify(0, mBuilder.build());
    -+</pre>
    -+
    -+<h2 id="metadata">Metadata Pemberitahuan</h2>
    -+
    -+<p>Pemberitahuan dapat disortir sesuai metadata yang Anda tetapkan dengan
    -+metode {@link android.support.v4.app.NotificationCompat.Builder} berikut:</p>
    -+
    -+<ul>
    -+    <li>{@link android.support.v4.app.NotificationCompat.Builder#setCategory(java.lang.String) setCategory()}
    -+    memberi tahu sistem cara menangani pemberitahuan aplikasi Anda bila perangkat berada dalam mode Priority
    -+    (misalnya, jika pemberitahuan menyatakan suatu panggilan masuk, pesan instan, atau alarm).</li>
    -+    <li>{@link android.support.v4.app.NotificationCompat.Builder#setPriority(int) setPriority()} menyebabkan
    -+    pemberitahuan dengan bidang prioritas diatur ke {@code PRIORITY_MAX} atau {@code PRIORITY_HIGH}
    -+    muncul dalam jendela kecil mengambang jika pemberitahuan juga memiliki suara atau getaran.</li>
    -+    <li>{@link android.support.v4.app.NotificationCompat.Builder#addPerson(java.lang.String) addPerson()}
    -+    memungkinkan Anda menambahkan daftar orang ke pemberitahuan. Aplikasi Anda bisa menggunakannya untuk memberi isyarat pada
    -+    sistem bahwa sistem harus mengelompokkan bersama pemberitahuan dari orang-orang yang ditetapkan, atau memberi peringkat lebih penting pada pemberitahuan
    -+    untuk orang-orang ini.</li>
    -+</ul>
    -+
    -+<div class="figure" style="width:230px">
    -+  <img src="{@docRoot}images/ui/notifications/heads-up.png" alt="" width="" height="" id="figure3" />
    -+  <p class="img-caption">
    -+    <strong>Gambar 3.</strong> Aktivitas layar penuh yang menampilkan pemberitahuan pendahuluan
    -+  </p>
    -+</div>
    -+
    -+<h2 id="Heads-up">Pemberitahuan Pendahuluan</h2>
    -+
    -+<p>Dengan Android 5.0 (API level 21), pemberitahuan bisa muncul dalam jendela kecil mengambang
    -+(yang disebut juga dengan <em>pemberitahuan pendahuluan</em>) saat perangkat aktif
    -+(yakni, perangkat dibuka kuncinya dan layarnya menyala). Pemberitahuan ini
    -+muncul seperti bentuk ringkas pemberitahuan Anda, hanya saja
    -+pemberitahuan pendahuluan juga menampilkan tombol tindakan. Pengguna bisa menindaklanjuti atau mengabaikan,
    -+pemberitahuan pendahuluan tanpa meninggalkan aplikasi saat ini.</p>
    -+
    -+<p>Contoh-contoh kondisi yang dapat memicu pemberitahuan pendahuluan antara lain:</p>
    -+
    -+<ul>
    -+  <li>Aktivitas pengguna berada dalam mode layar penuh (aplikasi menggunakan
    -+{@link android.app.Notification#fullScreenIntent}), atau</li>
    -+  <li>Pemberitahuan memiliki prioritas tinggi dan menggunakan nada dering atau
    -+    getaran</li>
    -+</ul>
    -+
    -+<h2 id="lockscreenNotification">Pemberitahuan Layar Kunci</h2>
    -+
    -+<p>Dengan rilis Android 5.0 (API level 21), pemberitahuan kini dapat muncul pada
    -+layar kunci. Aplikasi Anda bisa menggunakan fungsionalitas ini untuk menyediakan kontrol pemutaran media dan
    -+tindakan umum lainnya. Pengguna bisa memilih lewat Settings apakah akan menampilkan pemberitahuan pada layar kunci, dan
    -+Anda bisa mendesain apakah pemberitahuan aplikasi akan terlihat pada layar kunci.</p>
    -+
    -+<h3 id="visibility">Mengatur Visibilitas</h3>
    -+
    -+<p>Aplikasi Anda bisa mengatur level detail terlihat pada pemberitahuan yang ditampilkan di
    -+layar kunci aman. Anda memanggil {@link android.support.v4.app.NotificationCompat.Builder#setVisibility(int) setVisibility()}
    -+dan menetapkan salah satu nilai berikut:</p>
    -+
    -+<ul>
    -+    <li>{@link android.support.v4.app.NotificationCompat#VISIBILITY_PUBLIC} menampilkan isi lengkap
    -+    pemberitahuan.</li>
    -+    <li>{@link android.support.v4.app.NotificationCompat#VISIBILITY_SECRET} tidak menampilkan bagian apa pun dari
    -+    pemberitahuan ini pada layar kunci.</li>
    -+    <li>{@link android.support.v4.app.NotificationCompat#VISIBILITY_PRIVATE} menampilkan informasi dasar,
    -+    misalnya ikon dan judul isi pemberitahuan, namun menyembunyikan isi lengkap pemberitahuan.</li>
    -+</ul>
    -+
    -+<p>Bila {@link android.support.v4.app.NotificationCompat#VISIBILITY_PRIVATE} telah diatur, Anda juga bisa
    -+menyediakan versi alternatif isi pemberitahuan yang menyembunyikan detail tertentu. Misalnya,
    -+aplikasi SMS dapat menampilkan pemberitahuan yang menampilkan <em>Anda memiliki 3 pesan teks baru</em>, namun menyembunyikan
    -+isi dan pengirim pesan. Untuk menyediakan pemberitahuan alternatif ini, buat dahulu pemberitahuan
    -+pengganti menggunakan {@link android.support.v4.app.NotificationCompat.Builder}. Bila Anda membuat
    -+objek pemberitahuan privat, lampirkan pemberitahuan pengganti melalui metode
    -+{@link android.support.v4.app.NotificationCompat.Builder#setPublicVersion(android.app.Notification) setPublicVersion()}
    -+.</p>
    -+
    -+<h3 id="controllingMedia">Mengontrol Pemutaran Media pada Layar Kunci</h3>
    -+
    -+<p>Dalam Android 5.0 (API level 21) layar kunci tidak lagi menampilkan kontrol media
    -+berdasarkan {@link android.media.RemoteControlClient}, yang sekarang telah dihilangkan. Sebagai gantinya, gunakan
    -+template {@link android.app.Notification.MediaStyle} dengan metode
    -+{@link android.app.Notification.Builder#addAction(android.app.Notification.Action) addAction()}
    -+, yang mengubah tindakan menjadi ikon yang bisa diklik.</p>
    -+
    -+<p class="note"><strong>Catatan:</strong> Template dan metode {@link android.app.Notification.Builder#addAction(android.app.Notification.Action) addAction()}
    -+tidak disertakan dalam pustaka dukungan, sehingga fitur-fitur ini berjalan pada Android 5.0 dan yang lebih tinggi
    -+saja.</p>
    -+
    -+<p>Untuk menampilkan kontrol pemutaran media di layar kunci dalam Android 5.0, atur visibilitas
    -+ke {@link android.support.v4.app.NotificationCompat#VISIBILITY_PUBLIC}, seperti dijelaskan di atas. Kemudian tambahkan
    -+tindakan dan atur template {@link android.app.Notification.MediaStyle}, seperti dijelaskan dalam contoh kode
    -+berikut:</p>
    -+
    -+<pre>
    -+Notification notification = new Notification.Builder(context)
    -+    // Show controls on lock screen even when user hides sensitive content.
    -+    .setVisibility(Notification.VISIBILITY_PUBLIC)
    -+    .setSmallIcon(R.drawable.ic_stat_player)
    -+    // Add media control buttons that invoke intents in your media service
    -+    .addAction(R.drawable.ic_prev, "Previous", prevPendingIntent) // #0
    -+    .addAction(R.drawable.ic_pause, "Pause", pausePendingIntent)  // #1
    -+    .addAction(R.drawable.ic_next, "Next", nextPendingIntent)     // #2
    -+    // Apply the media style template
    -+    .setStyle(new Notification.MediaStyle()
    -+    .setShowActionsInCompactView(1 /* #1: pause button */)
    -+    .setMediaSession(mMediaSession.getSessionToken())
    -+    .setContentTitle("Wonderful music")
    -+    .setContentText("My Awesome Band")
    -+    .setLargeIcon(albumArtBitmap)
    -+    .build();
    -+</pre>
    -+
    -+<p class="note"><strong>Catatan:</strong> Dihilangkannya {@link android.media.RemoteControlClient}
    -+memiliki implikasi lebih jauh untuk mengontrol media. Lihat
    -+<a href="{@docRoot}about/versions/android-5.0.html#MediaPlaybackControl">Kontrol Pemutaran Media</a>
    -+untuk informasi selengkapnya tentang API baru untuk mengelola sesi media dan mengontrol pemutaran.</p>
    -+
    -+
    -+<!-- ------------------------------------------------------------------------------------------ -->
    -+<h2 id="CustomNotification">Layout Pemberitahuan Custom</h2>
    -+<p>
    -+    Kerangka kerja pemberitahuan memungkinkan Anda mendefinisikan layout pemberitahuan custom, yang
    -+    mendefinisikan penampilan pemberitahuan dalam objek {@link android.widget.RemoteViews}.
    -+    Pemberitahuan dengan layout custom serupa pemberitahuan normal, namun dibuat berdasarkan
    -+    {@link android.widget.RemoteViews} yang didefinisikan dalam file layout XML.
    -+</p>
    -+<p>
    -+    Tinggi yang tersedia untuk layout pemberitahuan custom bergantung pada tampilan pemberitahuan. Layout
    -+    tampilan normal dibatasi hingga 64 dp, dan layout tampilan yang diperluas dibatasi hingga 256 dp.
    -+</p>
    -+<p>
    -+    Untuk mendefinisikan layout pemberitahuan custom, mulailah dengan membuat instance
    -+    objek {@link android.widget.RemoteViews} yang memekarkan file layout XML. Kemudian,
    -+    sebagai ganti memanggil metode seperti
    -+    {@link android.support.v4.app.NotificationCompat.Builder#setContentTitle setContentTitle()},
    -+    panggil {@link android.support.v4.app.NotificationCompat.Builder#setContent setContent()}. Untuk mengatur
    -+    detail isi pemberitahuan custom, gunakan metode dalam
    -+    {@link android.widget.RemoteViews} untuk mengatur nilai anak tampilan:
    -+</p>
    -+<ol>
    -+    <li>
    -+        Buat layout XML untuk pemberitahuan di file terpisah. Anda bisa menggunakan nama file
    -+apa saja yang diinginkan, namun Anda harus menggunakan ekstensi <code>.xml</code>
    -+    </li>
    -+    <li>
    -+        Dalam aplikasi Anda, gunakan metode {@link android.widget.RemoteViews} untuk mendefinisikan
    -+        ikon dan teks pemberitahuan. Masukkan objek {@link android.widget.RemoteViews} ini ke dalam
    -+        {@link android.support.v4.app.NotificationCompat.Builder} Anda dengan memanggil
    -+        {@link android.support.v4.app.NotificationCompat.Builder#setContent setContent()}. Hindari
    -+        mengatur {@link android.graphics.drawable.Drawable} latar belakang pada
    -+        objek {@link android.widget.RemoteViews} Anda, karena warna teks bisa menjadi tidak terbaca.
    -+    </li>
    -+</ol>
    -+<p>
    -+    Kelas {@link android.widget.RemoteViews} juga menyertakan metode yang bisa Anda gunakan untuk
    -+    menambahkan {@link android.widget.Chronometer} atau {@link android.widget.ProgressBar}
    -+dengan mudah ke layout pemberitahuan Anda. Untuk informasi selengkapnya tentang cara membuat layout custom
    -+    pemberitahuan Anda, lihat dokumentasi acuan {@link android.widget.RemoteViews}.
    -+</p>
    -+<p class="caution">
    -+    <strong>Perhatian:</strong> Bila Anda menggunakan layout pemberitahuan custom, berhati-hatilah
    -+    untuk memastikan bahwa layout custom itu bekerja pada berbagai orientasi dan resolusi perangkat. Walaupun
    -+    berlaku bagi semua layout View, nasihat ini khususnya penting untuk pemberitahuan karena
    -+    ruang di laci pemberitahuan sangat terbatas. Jangan buat layout custom terlalu
    -+    kompleks, dan pastikan mengujinya di berbagai konfigurasi.
    -+</p>
    -+<!-- ------------------------------------------------------------------------------------------ -->
    -+<h4>Menggunakan sumber daya gaya untuk teks pemberitahuan custom</h4>
    -+<p>
    -+    Selalu gunakan sumber daya gaya untuk teks pemberitahuan custom. Warna latar belakang
    -+    pemberitahuan bisa bervariasi di berbagai perangkat dan versi, dan menggunakan sumber daya gaya
    -+    membantu Anda menangani hal ini. Mulai Android 2.3, sistem mendefinisikan sebuah gaya untuk
    -+    teks layout pemberitahuan standar. Jika Anda menggunakan gaya yang sama dalam aplikasi yang menargetkan Android
    -+    2.3 atau yang lebih tinggi, Anda akan memastikan bahwa teks terlihat pada latar belakang tampilan.
    -+</p>
    -diff --git a/docs/html-intl/intl/id/guide/topics/ui/overview.jd b/docs/html-intl/intl/id/guide/topics/ui/overview.jd
    -new file mode 100644
    -index 0000000..ca8b420
    ---- /dev/null
    -+++ b/docs/html-intl/intl/id/guide/topics/ui/overview.jd
    -@@ -0,0 +1,71 @@
    -+page.title=Ikhtisar UI
    -+@jd:body
    -+
    -+
    -+<p>Semua elemen antarmuka pengguna dalam aplikasi Android dibangun menggunakan objek {@link android.view.View} dan
    -+{@link android.view.ViewGroup}. {@link android.view.View} adalah objek yang menarik
    -+sesuatu di layar dan dapat berinteraksi dengan pengguna. {@link android.view.ViewGroup} merupakan sebuah
    -+objek yang menyimpan objek {@link android.view.View} lainnya (dan {@link android.view.ViewGroup}) untuk
    -+mendefinisikan layout antarmuka.</p>
    -+
    -+<p>Android menyediakan sekumpulan subkelas {@link android.view.View} dan {@link
    -+android.view.ViewGroup} yang menawarkan kontrol input umum (seperti tombol dan bidang
    -+teks) serta berbagai model layout (seperti layout linear atau relatif).</p>
    -+
    -+
    -+<h2 id="Layout">Layout Antarmuka Pengguna</h2>
    -+
    -+<p>Antarmuka pengguna untuk setiap komponen aplikasi Anda didefinisikan menggunakan hierarki objek {link
    -+android.view.View} dan {@link android.view.ViewGroup}, seperti yang ditampilkan dalam gambar 1. Setiap kelompok tampilan
    -+merupakan kontainer tak terlihat yang mengelola tampilan anak, sementara tampilan anak ini dapat menjadi kontrol
    -+input atau widget lain yang
    -+menarik sebagian dari UI. Pohon hierarki ini bisa sederhana atau bisa juga kompleks bergantung kebutuhan
    -+(namun yang sederhana paling baik untuk kinerja).</p>
    -+
    -+<img src="{@docRoot}images/viewgroup.png" alt="" />
    -+<p class="img-caption"><strong>Gambar 1.</strong> Ilustrasi dari hierarki tampilan, yang mendefinisikan layout
    -+UI.</p>
    -+
    -+<p>Untuk mendeklarasikan layout, Anda dapat menyediakan objek {@link android.view.View} dalam kode dan mulai
    -+membangun pohon, namun cara termudah dan terefektif untuk mendefinisikan layout adalah dengan file XML.
    -+XML menawarkan struktur layout yang dapat dibaca manusia, serupa dengan HTML.</p>
    -+
    -+<p>Nama elemen XML untuk tampilan sesuai dengan kelas Android yang diwakilinya. Dengan demikian elemen
    -+<code>&lt;TextView&gt;</code> membuat widget {@link android.widget.TextView} dalam UI Anda,
    -+dan elemen <code>&lt;LinearLayout&gt;</code> membuat kelompok tampilan {@link android.widget.LinearLayout}
    -+. </p>
    -+
    -+<p>Misalnya, layout vertikal sederhana dengan tampilan teks dan tombol akan tampak seperti ini:</p>
    -+<pre>
    -+&lt;?xml version="1.0" encoding="utf-8"?>
    -+&lt;LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    -+              android:layout_width="fill_parent"
    -+              android:layout_height="fill_parent"
    -+              android:orientation="vertical" >
    -+    &lt;TextView android:id="@+id/text"
    -+              android:layout_width="wrap_content"
    -+              android:layout_height="wrap_content"
    -+              android:text="I am a TextView" />
    -+    &lt;Button android:id="@+id/button"
    -+            android:layout_width="wrap_content"
    -+            android:layout_height="wrap_content"
    -+            android:text="I am a Button" />
    -+&lt;/LinearLayout>
    -+</pre>
    -+
    -+<p>Saat Anda memuat sumber daya layout di aplikasi, Android akan menginisialisasi setiap simpul layout menjadi
    -+objek runtime yang bisa Anda gunakan untuk mendefinisikan perilaku tambahan, query status objek, atau memodifikasi
    -+layout.</p>
    -+
    -+<p>Untuk mendapatkan panduan lengkap mengenai pembuatan layout UI, lihat <a href="declaring-layout.html">Layout
    -+XML</a>.
    -+
    -+
    -+<h2 id="UIComponents">Komponen Antarmuka Pengguna</h2>
    -+
    -+<p>Anda tidak harus membuat semua UI menggunakan objek {@link android.view.View} dan {link
    -+android.view.ViewGroup}. Android menyediakan beberapa komponen aplikasi yang menawarkan
    -+layout UI standar yang tinggal Anda definisikan kontennya. Komponen UI ini masing-masing
    -+memiliki set API unik yang dijelaskan dalam masing-masing dokumennya, seperti <a href="{@docRoot}guide/topics/ui/actionbar.html">Action-Bar</a>, <a href="{@docRoot}guide/topics/ui/dialogs.html">Dialog</a>, dan <a href="{@docRoot}guide/topics/ui/notifiers/notifications.html">Pemberitahuan Status</a>.</p>
    -+
    -+
    -diff --git a/docs/html-intl/intl/id/guide/topics/ui/settings.jd b/docs/html-intl/intl/id/guide/topics/ui/settings.jd
    -new file mode 100644
    -index 0000000..89be52f
    ---- /dev/null
    -+++ b/docs/html-intl/intl/id/guide/topics/ui/settings.jd
    -@@ -0,0 +1,1202 @@
    -+page.title=Pengaturan
    -+page.tags=preference,preferenceactivity,preferencefragment
    -+
    -+@jd:body
    -+
    -+
    -+<div id="qv-wrapper">
    -+<div id="qv">
    -+
    -+<h2>Dalam dokumen ini</h2>
    -+<ol>
    -+  <li><a href="#Overview">Ikhtisar</a>
    -+    <ol>
    -+      <li><a href="#SettingTypes">Preferensi</a></li>
    -+    </ol>
    -+  </li>
    -+  <li><a href="#DefiningPrefs">Mendefinisikan Preferensi dalam XML</a>
    -+    <ol>
    -+      <li><a href="#Groups">Membuat grup pengaturan</a></li>
    -+      <li><a href="#Intents">Menggunakan intent</a></li>
    -+    </ol>
    -+  </li>
    -+  <li><a href="#Activity">Membuat Aktivitas Preferensi</a></li>
    -+  <li><a href="#Fragment">Menggunakan Fragmen Preferensi</a></li>
    -+  <li><a href="#Defaults">Mengatur Nilai Default</a></li>
    -+  <li><a href="#PreferenceHeaders">Menggunakan Header Preferensi</a>
    -+    <ol>
    -+      <li><a href="#CreateHeaders">Membuat file header</a></li>
    -+      <li><a href="#DisplayHeaders">Menampilkan header</a></li>
    -+      <li><a href="#BackCompatHeaders">Mendukung versi yang lebih lama dengan header preferensi</a></li>
    -+    </ol>
    -+  </li>
    -+  <li><a href="#ReadingPrefs">Preferensi Membaca</a>
    -+    <ol>
    -+      <li><a href="#Listening">Mendengarkan perubahan preferensi</a></li>
    -+    </ol>
    -+  </li>
    -+  <li><a href="#NetworkUsage">Mengelola Penggunaan Jaringan</a></li>
    -+  <li><a href="#Custom">Membangun Preferensi Custom</a>
    -+    <ol>
    -+      <li><a href="#CustomSelected">Menetapkan antarmuka pengguna</a></li>
    -+      <li><a href="#CustomSave">Menyimpan nilai pengaturan</a></li>
    -+      <li><a href="#CustomInitialize">Menginisialisasi nilai saat ini</a></li>
    -+      <li><a href="#CustomDefault">Menyediakan nilai default</a></li>
    -+      <li><a href="#CustomSaveState">Menyimpan dan memulihkan status Preferensi</a></li>
    -+    </ol>
    -+  </li>
    -+</ol>
    -+
    -+<h2>Kelas-kelas utama</h2>
    -+<ol>
    -+  <li>{@link android.preference.Preference}</li>
    -+  <li>{@link android.preference.PreferenceActivity}</li>
    -+  <li>{@link android.preference.PreferenceFragment}</li>
    -+</ol>
    -+
    -+
    -+<h2>Lihat juga</h2>
    -+<ol>
    -+  <li><a href="{@docRoot}design/patterns/settings.html">Panduan desain pengaturan</a></li>
    -+</ol>
    -+</div>
    -+</div>
    -+
    -+
    -+
    -+
    -+<p>Aplikasi sering kali menyertakan pengaturan yang memungkinkan pengguna memodifikasi fitur dan perilaku aplikasi. Misalnya,
    -+beberapa aplikasi memungkinkan pengguna untuk menetapkan apakah pemberitahuan diaktifkan atau menetapkan seberapa sering
    -+aplikasi menyinkronkan data dengan cloud.</p>
    -+
    -+<p>Jika ingin menyediakan pengaturan untuk aplikasi, Anda harus menggunakan
    -+API Android {@link android.preference.Preference} untuk membangun antarmuka yang konsisten dengan
    -+pengalaman pengguna di aplikasi Android yang lain (termasuk pengaturan sistem). Dokumen ini menjelaskan
    -+cara membangun pengaturan aplikasi Anda menggunakan API {@link android.preference.Preference}.</p>
    -+
    -+<div class="note design">
    -+<p><strong>Desain Pengaturan</strong></p>
    -+  <p>Untuk informasi tentang cara mendesain pengaturan Anda, bacalah panduan desain <a href="{@docRoot}design/patterns/settings.html">Pengaturan</a>.</p>
    -+</div>
    -+
    -+
    -+<img src="{@docRoot}images/ui/settings/settings.png" alt="" width="435" />
    -+<p class="img-caption"><strong>Gambar 1.</strong> Cuplikan layar dari pengaturan
    -+aplikasi Messaging Android. Memilih item yang didefinisikan oleh {@link android.preference.Preference}
    -+akan membuka antarmuka untuk mengubah pengaturan.</p>
    -+
    -+
    -+
    -+
    -+<h2 id="Overview">Ikhtisar</h2>
    -+
    -+<p>Sebagai ganti menggunakan objek {@link android.view.View} untuk membangun antarmuka pengguna, pengaturan
    -+dibangun menggunakan berbagai subkelas dari kelas {@link android.preference.Preference} yang Anda
    -+deklarasikan dalam file XML.</p>
    -+
    -+<p>Objek {@link android.preference.Preference} adalah blok pembangun untuk pengaturan
    -+tunggal. Setiap {@link android.preference.Preference} muncul sebagai item dalam daftar dan menyediakan UI
    -+yang sesuai bagi pengguna untuk memodifikasi pengaturan. Misalnya, {@link
    -+android.preference.CheckBoxPreference} membuat item daftar yang menampilkan kotak cek, dan {@link
    -+android.preference.ListPreference} membuat item yang membuka dialog berisi daftar pilihan.</p>
    -+
    -+<p>Setiap {@link android.preference.Preference} yang Anda tambahkan memiliki pasangan nilai-kunci yang sesuai yang
    -+digunakan sistem untuk menyimpan pengaturan dalam file {@link android.content.SharedPreferences}
    -+default untuk pengaturan aplikasi Anda. Bila pengguna mengubah pengaturan, sistem akan memperbarui nilai
    -+yang bersangkutan dalam file {@link android.content.SharedPreferences} untuk Anda. Satu-satunya saat di mana Anda harus
    -+berinteraksi langsung dengan file {@link android.content.SharedPreferences} yang terkait adalah bila Anda
    -+perlu membaca nilai untuk menentukan perilaku aplikasi berdasarkan pengaturan pengguna.</p>
    -+
    -+<p>Nilai yang tersimpan di {@link android.content.SharedPreferences} untuk setiap pengaturan bisa berupa
    -+tipe data berikut:</p>
    -+
    -+<ul>
    -+  <li>Boolean</li>
    -+  <li>Float</li>
    -+  <li>Int</li>
    -+  <li>Long</li>
    -+  <li>String</li>
    -+  <li>String {@link java.util.Set}</li>
    -+</ul>
    -+
    -+<p>Oleh karena UI pengaturan aplikasi Anda dibangun menggunakan objek {@link android.preference.Preference}
    -+sebagai ganti
    -+objek {@link android.view.View}, Anda perlu menggunakan {@link android.app.Activity} khusus atau
    -+subkelas {@link android.app.Fragment} untuk menampilkan pengaturan daftar:</p>
    -+
    -+<ul>
    -+  <li>Jika aplikasi Anda mendukung versi Android yang lebih lama dari 3.0 (API level 10 dan yang lebih rendah), Anda harus
    -+membangun aktivitas sebagai ekstensi dari kelas {@link android.preference.PreferenceActivity}.</li>
    -+  <li>Pada Android 3.0 dan yang lebih baru, sebaiknya Anda menggunakan {@link android.app.Activity} biasa
    -+yang menjadi host {@link android.preference.PreferenceFragment} yang menampilkan pengaturan aplikasi Anda.
    -+Akan tetapi, Anda juga bisa menggunakan {@link android.preference.PreferenceActivity} untuk membuat layout dua panel
    -+bagi layar besar bila Anda memiliki beberapa grup pengaturan.</li>
    -+</ul>
    -+
    -+<p>Cara mengatur {@link android.preference.PreferenceActivity} Anda dan instance {@link
    -+android.preference.PreferenceFragment} dibahas di bagian tentang <a href="#Activity">Membuat Aktivitas Preferensi</a> dan <a href="#Fragment">Menggunakan
    -+Fragmen Preferensi</a>.</p>
    -+
    -+
    -+<h3 id="SettingTypes">Preferensi</h3>
    -+
    -+<p>Setiap pengaturan untuk aplikasi Anda diwakili oleh subkelas khusus dari kelas {@link
    -+android.preference.Preference}. Setiap subkelas menyertakan seperangkat properti utama yang memungkinkan Anda
    -+untuk menetapkan berbagai hal seperti judul pengaturan dan nilai default. Setiap subkelas juga menyediakan
    -+antarmuka pengguna dan properti khusus miliknya sendiri. Misalnya, gambar 1 menampilkan cuplikan layar dari
    -+ pengaturan aplikasi Messaging. Setiap item daftar dalam layar pengaturan didukung oleh objek {@link
    -+android.preference.Preference} berbeda.</p>
    -+
    -+<p>Beberapa preferensi yang paling umum adalah:</p>
    -+
    -+<dl>
    -+  <dt>{@link android.preference.CheckBoxPreference}</dt>
    -+  <dd>Menampilkan item dengan kotak cek untuk pengaturan yang diaktifkan atau dinonaktifkan. Nilai
    -+tersimpan adalah boolean (<code>true</code> jika diberi tanda cek).</dd>
    -+
    -+  <dt>{@link android.preference.ListPreference}</dt>
    -+  <dd>Membuka dialog berisi daftar tombol radio. Nilai
    -+tersimpan bisa berupa tipe nilai apa pun yang didukung (tercantum di atas).</dd>
    -+
    -+  <dt>{@link android.preference.EditTextPreference}</dt>
    -+  <dd>Membuka dialog berisi widget {@link android.widget.EditText}. Nilai tersimpan adalah {@link
    -+java.lang.String}.</dd>
    -+</dl>
    -+
    -+<p>Lihat kelas {@link android.preference.Preference} untuk mengetahui daftar subkelas lain dan
    -+propertinya.</p>
    -+
    -+<p>Tentu saja, kelas bawaan tidak mengakomodasi setiap kebutuhan dan aplikasi Anda mungkin memerlukan
    -+sesuatu yang lebih khusus. Misalnya, platform saat ini tidak menyediakan kelas {@link
    -+android.preference.Preference} untuk mengambil nomor atau tanggal. Anda mungkin perlu mendefinisikan
    -+subkelas {@link android.preference.Preference} sendiri. Untuk bantuan melakukannya, lihat bagian tentang <a href="#Custom">Membangun Preferensi Custom</a>.</p>
    -+
    -+
    -+
    -+<h2 id="DefiningPrefs">Mendefinisikan Preferensi dalam XML</h2>
    -+
    -+<p>Meskipun bisa membuat instance objek {@link android.preference.Preference} baru saat runtime, Anda
    -+harus mendefinisikan daftar pengaturan dalam XML dengan hierarki objek
    -+{@link android.preference.Preference}. Menggunakan file XML untuk mendefinisikan sekumpulan pengaturan lebih disukai karena file
    -+menyediakan struktur yang mudah dibaca dan diperbarui. Selain itu, pengaturan aplikasi Anda
    -+umumnya telah ditetapkan sebelumnya, meskipun Anda masih bisa memodifikasi kumpulan tersebut saat runtime.</p>
    -+
    -+<p>Setiap subkelas {@link android.preference.Preference} bisa dideklarasikan dengan elemen XML yang
    -+cocok dengan nama kelas, seperti {@code &lt;CheckBoxPreference&gt;}.</p>
    -+
    -+<p>Anda harus menyimpan file XML dalam direktori {@code res/xml/}. Meskipun bisa memberi nama file
    -+sesuka Anda, biasanya file diberi nama {@code preferences.xml}. Biasanya Anda hanya memerlukan satu file,
    -+karena cabang di hierarki (yang membuka daftar pengaturanny sendiri) dideklarasikan menggunakan instance
    -+tersarang {@link android.preference.PreferenceScreen}.</p>
    -+
    -+<p class="note"><strong>Catatan:</strong> Jika ingin membuat layout multipanel untuk
    -+pengaturan, Anda memerlukan file XML terpisah untuk setiap fragmen.</p>
    -+
    -+<p>Simpul akar untuk file XML harus merupakan elemen {@link android.preference.PreferenceScreen
    -+&lt;PreferenceScreen&gt;}. Dalam elemen inilah tempat Anda menambahkan setiap {@link
    -+android.preference.Preference}. Setiap anak yang Anda tambahkan dalam elemen
    -+{@link android.preference.PreferenceScreen &lt;PreferenceScreen&gt;} akan tampak sebagai item
    -+tunggal dalam daftar pengaturan.</p>
    -+
    -+<p>Misalnya:</p>
    -+
    -+<pre>
    -+&lt;?xml version="1.0" encoding="utf-8"?>
    -+&lt;PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android">
    -+    &lt;CheckBoxPreference
    -+        android:key="pref_sync"
    -+        android:title="@string/pref_sync"
    -+        android:summary="@string/pref_sync_summ"
    -+        android:defaultValue="true" />
    -+    &lt;ListPreference
    -+        android:dependency="pref_sync"
    -+        android:key="pref_syncConnectionType"
    -+        android:title="@string/pref_syncConnectionType"
    -+        android:dialogTitle="@string/pref_syncConnectionType"
    -+        android:entries="@array/pref_syncConnectionTypes_entries"
    -+        android:entryValues="@array/pref_syncConnectionTypes_values"
    -+        android:defaultValue="@string/pref_syncConnectionTypes_default" />
    -+&lt;/PreferenceScreen>
    -+</pre>
    -+
    -+<p>Dalam contoh ini, terdapat {@link android.preference.CheckBoxPreference} dan {@link
    -+android.preference.ListPreference}. Kedua item tersebut menyertakan tiga atribut berikut:</p>
    -+
    -+<dl>
    -+  <dt>{@code android:key}</dt>
    -+  <dd>Atribut ini diperlukan untuk preferensi yang mempertahankan nilai data. Ini menetapkan kunci
    -+unik (string) yang digunakan sistem saat menyimpan nilai pengaturan ini dalam {@link
    -+android.content.SharedPreferences}.
    -+  <p>Instance satu-satunya di mana atribut ini <em>tidak diperlukan</em> adalah bila preferensi berupa
    -+{@link android.preference.PreferenceCategory} atau {@link android.preference.PreferenceScreen}, atau
    -+preferensi menetapkan {@link android.content.Intent} untuk dipanggil (dengan elemen <a href="#Intents">{@code &lt;intent&gt;}</a>) atau {@link android.app.Fragment} untuk ditampilkan (dengan atribut <a href="{@docRoot}reference/android/preference/Preference.html#attr_android:fragment">{@code
    -+android:fragment}</a>).</p>
    -+  </dd>
    -+  <dt>{@code android:title}</dt>
    -+  <dd>Ini menyediakan nama pengaturan yang bisa dilihat oleh pengguna.</dd>
    -+  <dt>{@code android:defaultValue}</dt>
    -+  <dd>Ini menetapkan nilai awal yang harus diatur sistem dalam file {@link
    -+android.content.SharedPreferences}. Anda harus memberikan nilai default untuk semua
    -+pengaturan.</dd>
    -+</dl>
    -+
    -+<p>Untuk informasi tentang semua atribut lain yang didukung, lihat dokumentasi {@link
    -+android.preference.Preference} (dan subkelas masing-masing).</p>
    -+
    -+
    -+<div class="figure" style="width:300px">
    -+  <img src="{@docRoot}images/ui/settings/settings-titles.png" alt="" />
    -+  <p class="img-caption"><strong>Gambar 2.</strong> Mengatur kategori
    -+    dengan judul. <br/><b>1.</b> Kategori ditetapkan oleh elemen {@link
    -+android.preference.PreferenceCategory &lt;PreferenceCategory&gt;}. <br/><b>2.</b> Judul
    -+ditetapkan dengan atribut {@code android:title}.</p>
    -+</div>
    -+
    -+
    -+<p>Bila daftar pengaturan Anda melebihi sekitar 10 item, Anda mungkin perlu menambahkan judul untuk
    -+mendefinisikan grup pengaturan atau menampilkan grup tersebut di
    -+layar terpisah. Opsi ini dijelaskan di bagian berikut.</p>
    -+
    -+
    -+<h3 id="Groups">Membuat grup pengaturan</h3>
    -+
    -+<p>Jika Anda menampilkan daftar 10 pengaturan atau lebih, pengguna
    -+mungkin akan kesulitan dalam memindai, memahami dan memprosesnya. Anda bisa mengatasinya dengan
    -+membagi sebagian atau semua pengaturan ke dalam beberapa grup, yang secara efektif akan mengubah satu daftar panjang menjadi beberapa daftar
    -+yang lebih pendek. Suatu grup pengaturan terkait bisa ditampilkan dalam salah satu dari dua cara:</p>
    -+
    -+<ul>
    -+  <li><a href="#Titles">Menggunakan judul</a></li>
    -+  <li><a href="#Subscreens">Menggunakan sublayar</a></li>
    -+</ul>
    -+
    -+<p>Anda bisa menggunakan salah satu atau keduanya untuk mengelola pengaturan aplikasi Anda. Saat
    -+memutuskan mana yang akan digunakan dan cara membagi pengaturan, Anda harus mengikuti pedoman dalam
    -+Panduan <a href="{@docRoot}design/patterns/settings.html">Pengaturan</a> Desain Android.</p>
    -+
    -+
    -+<h4 id="Titles">Menggunakan judul</h4>
    -+
    -+<p>Jika ingin menyediakan divider dengan heading di antara grup pengaturan (seperti yang ditampilkan dalam gambar 2),
    -+tempatkan setiap grup objek {@link android.preference.Preference} di dalam {@link
    -+android.preference.PreferenceCategory}.</p>
    -+
    -+<p>Misalnya:</p>
    -+
    -+<pre>
    -+&lt;PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android">
    -+    &lt;PreferenceCategory
    -+        android:title="&#64;string/pref_sms_storage_title"
    -+        android:key="pref_key_storage_settings">
    -+        &lt;CheckBoxPreference
    -+            android:key="pref_key_auto_delete"
    -+            android:summary="&#64;string/pref_summary_auto_delete"
    -+            android:title="&#64;string/pref_title_auto_delete"
    -+            android:defaultValue="false"... />
    -+        &lt;Preference
    -+            android:key="pref_key_sms_delete_limit"
    -+            android:dependency="pref_key_auto_delete"
    -+            android:summary="&#64;string/pref_summary_delete_limit"
    -+            android:title="&#64;string/pref_title_sms_delete"... />
    -+        &lt;Preference
    -+            android:key="pref_key_mms_delete_limit"
    -+            android:dependency="pref_key_auto_delete"
    -+            android:summary="&#64;string/pref_summary_delete_limit"
    -+            android:title="&#64;string/pref_title_mms_delete" ... />
    -+    &lt;/PreferenceCategory>
    -+    ...
    -+&lt;/PreferenceScreen>
    -+</pre>
    -+
    -+
    -+<h4 id="Subscreens">Menggunakan sublayar</h4>
    -+
    -+<p>Jika ingin menempatkan grup pengaturan ke dalam sublayar (seperti yang ditampilkan dalam gambar 3), tempatkan grup
    -+objek {@link android.preference.Preference} di dalam {@link
    -+android.preference.PreferenceScreen}.</p>
    -+
    -+<img src="{@docRoot}images/ui/settings/settings-subscreen.png" alt="" />
    -+<p class="img-caption"><strong>Gambar 3.</strong> Mengatur sublayar. Elemen {@code
    -+&lt;PreferenceScreen&gt;}
    -+membuat item yang, bila dipilih, akan membuka daftar terpisah untuk menampilkan pengaturan tersarang.</p>
    -+
    -+<p>Misalnya:</p>
    -+
    -+<pre>
    -+&lt;PreferenceScreen  xmlns:android="http://schemas.android.com/apk/res/android">
    -+    &lt;!-- opens a subscreen of settings -->
    -+    &lt;PreferenceScreen
    -+        android:key="button_voicemail_category_key"
    -+        android:title="&#64;string/voicemail"
    -+        android:persistent="false">
    -+        &lt;ListPreference
    -+            android:key="button_voicemail_provider_key"
    -+            android:title="&#64;string/voicemail_provider" ... />
    -+        &lt;!-- opens another nested subscreen -->
    -+        &lt;PreferenceScreen
    -+            android:key="button_voicemail_setting_key"
    -+            android:title="&#64;string/voicemail_settings"
    -+            android:persistent="false">
    -+            ...
    -+        &lt;/PreferenceScreen>
    -+        &lt;RingtonePreference
    -+            android:key="button_voicemail_ringtone_key"
    -+            android:title="&#64;string/voicemail_ringtone_title"
    -+            android:ringtoneType="notification" ... />
    -+        ...
    -+    &lt;/PreferenceScreen>
    -+    ...
    -+&lt;/PreferenceScreen>
    -+</pre>
    -+
    -+
    -+<h3 id="Intents">Menggunakan intent</h3>
    -+
    -+<p>Dalam beberapa kasus, Anda mungkin ingin item preferensi untuk membuka beberapa aktivitas sebagai ganti
    -+layar pengaturan, seperti browser web untuk melihat halaman web. Untuk memanggil {@link
    -+android.content.Intent} saat pengguna memilih item preferensi, tambahkan elemen {@code &lt;intent&gt;}
    -+sebagai anak dari elemen {@code &lt;Preference&gt;} yang bersangkutan.</p>
    -+
    -+<p>Misalnya, berikut ini cara menggunakan item preferensi untuk membuka halaman web:</p>
    -+
    -+<pre>
    -+&lt;Preference android:title="@string/prefs_web_page" >
    -+    &lt;intent android:action="android.intent.action.VIEW"
    -+            android:data="http://www.example.com" />
    -+&lt;/Preference>
    -+</pre>
    -+
    -+<p>Anda bisa membuat intent implisit maupun eksplisit menggunakan atribut berikut:</p>
    -+
    -+<dl>
    -+  <dt>{@code android:action}</dt>
    -+    <dd>Tindakan yang akan ditetapkan, sesuai metode
    -+{@link android.content.Intent#setAction setAction()}.</dd>
    -+  <dt>{@code android:data}</dt>
    -+    <dd>Data yang akan ditetapkan, sesuai metode {@link android.content.Intent#setData setData()}.</dd>
    -+  <dt>{@code android:mimeType}</dt>
    -+    <dd>Tipe MIME yang akan ditetapkan, sesuai metode
    -+{@link android.content.Intent#setType setType()}.</dd>
    -+  <dt>{@code android:targetClass}</dt>
    -+    <dd>Bagian kelas dari nama komponen, sesuai metode {@link android.content.Intent#setComponent
    -+setComponent()}.</dd>
    -+  <dt>{@code android:targetPackage}</dt>
    -+    <dd>Bagian paket dari nama komponen, sesuai metode {@link
    -+android.content.Intent#setComponent setComponent()}.</dd>
    -+</dl>
    -+
    -+
    -+
    -+<h2 id="Activity">Membuat Aktivitas Preferensi</h2>
    -+
    -+<p>Untuk menampilkan pengaturan Anda dalam suatu aktivitas, perluas kelas {@link
    -+android.preference.PreferenceActivity}. Ini adalah ekstensi dari kelas {@link
    -+android.app.Activity} biasa yang menampilkan daftar pengaturan berdasarkan hierarki objek {@link
    -+android.preference.Preference}. {@link android.preference.PreferenceActivity}
    -+secara otomatis mempertahankan pengaturan yang dikaitkan dengan setiap {@link
    -+android.preference.Preference} bila pengguna membuat perubahan.</p>
    -+
    -+<p class="note"><strong>Catatan:</strong> Jika Anda mengembangkan aplikasi untuk Android 3.0 dan
    -+yang lebih tinggi, sebaiknya gunakan {@link android.preference.PreferenceFragment}. Pindah ke bagian
    -+berikutnya tentang <a href="#Fragment">Menggunakan Fragmen Preferensi</a>.</p>
    -+
    -+<p>Hal paling penting untuk diingat adalah jangan memuat layout tampilan selama callback {@link
    -+android.preference.PreferenceActivity#onCreate onCreate()}. Sebagai gantinya, panggil {@link
    -+android.preference.PreferenceActivity#addPreferencesFromResource addPreferencesFromResource()} untuk
    -+menambahkan preferensi yang telah Anda deklarasikan dalam file XML ke aktivitas. Misalnya, berikut ini adalah kode minimum
    -+polos yang diperlukan untuk {@link android.preference.PreferenceActivity} fungsional:</p>
    -+
    -+<pre>
    -+public class SettingsActivity extends PreferenceActivity {
    -+    &#64;Override
    -+    public void onCreate(Bundle savedInstanceState) {
    -+        super.onCreate(savedInstanceState);
    -+        addPreferencesFromResource(R.xml.preferences);
    -+    }
    -+}
    -+</pre>
    -+
    -+<p>Ini sebenarnya kode yang cukup untuk beberapa aplikasi, karena segera setelah pengguna memodifikasi preferensi,
    -+sistem akan menyimpan perubahan tersebut ke file {@link android.content.SharedPreferences} default yang
    -+bisa dibaca oleh komponen aplikasi Anda lainnya bila Anda perlu memeriksa pengaturan pengguna. Akan tetapi,
    -+banyak aplikasi, yang memerlukan kode lebih sedikit untuk mendengarkan perubahan yang terjadi pada preferensi.
    -+Untuk informasi tentang mendengarkan perubahan di file {@link android.content.SharedPreferences},
    -+lihat bagian tentang <a href="#ReadingPrefs">Preferensi Membaca</a>.</p>
    -+
    -+
    -+
    -+
    -+<h2 id="Fragment">Menggunakan Fragmen Preferensi</h2>
    -+
    -+<p>Jika Anda mengembangkan Android 3.0 (API level 11) dan yang lebih tinggi, Anda harus menggunakan {@link
    -+android.preference.PreferenceFragment} untuk menampilkan daftar objek {@link android.preference.Preference}
    -+Anda. Anda bisa menambahkan {@link android.preference.PreferenceFragment} ke aktivitas apa pun,&mdash;Anda tidak
    -+perlu menggunakan {@link android.preference.PreferenceActivity}.</p>
    -+
    -+<p><a href="{@docRoot}guide/components/fragments.html">Fragmen</a> menyediakan arsitektur yang lebih
    -+fleksibel untuk aplikasi Anda, dibandingkan hanya menggunakan aktivitas, apa pun jenis
    -+aktivitas yang Anda bangun. Dengan sendirinya, kami menyarankan Anda menggunakan {@link
    -+android.preference.PreferenceFragment} untuk mengontrol tampilan pengaturan Anda sebagai ganti {@link
    -+android.preference.PreferenceActivity} bila memungkinkan.</p>
    -+
    -+<p>Implementasi {@link android.preference.PreferenceFragment} Anda bisa semudah
    -+mendefinisikan metode {@link android.preference.PreferenceFragment#onCreate onCreate()} untuk memuat
    -+file preferensi dengan {@link android.preference.PreferenceFragment#addPreferencesFromResource
    -+addPreferencesFromResource()}. Misalnya:</p>
    -+
    -+<pre>
    -+public static class SettingsFragment extends PreferenceFragment {
    -+    &#64;Override
    -+    public void onCreate(Bundle savedInstanceState) {
    -+        super.onCreate(savedInstanceState);
    -+
    -+        // Load the preferences from an XML resource
    -+        addPreferencesFromResource(R.xml.preferences);
    -+    }
    -+    ...
    -+}
    -+</pre>
    -+
    -+<p>Anda nanti bisa menambahkan fragmen ini ke {@link android.app.Activity} seperti yang Anda lakukan untuk
    -+{@link android.app.Fragment} lainnya. Misalnya:</p>
    -+
    -+<pre>
    -+public class SettingsActivity extends Activity {
    -+    &#64;Override
    -+    protected void onCreate(Bundle savedInstanceState) {
    -+        super.onCreate(savedInstanceState);
    -+
    -+        // Display the fragment as the main content.
    -+        getFragmentManager().beginTransaction()
    -+                .replace(android.R.id.content, new SettingsFragment())
    -+                .commit();
    -+    }
    -+}
    -+</pre>
    -+
    -+<p class="note"><strong>Catatan:</strong> {@link android.preference.PreferenceFragment} tidak memiliki
    -+objek {@link android.content.Context} sendiri. Jika memerlukan objek {@link android.content.Context}
    -+, Anda bisa memanggil {@link android.app.Fragment#getActivity()}. Akan tetapi, berhati-hatilah untuk memanggil
    -+{@link android.app.Fragment#getActivity()} hanya bila fragmen telah dikaitkan dengan aktivitas. Bila
    -+fragmen belum dikaitkan, atau terlepas saat akhir daur hidupnya, {@link
    -+android.app.Fragment#getActivity()} akan mengembalikan nol.</p>
    -+
    -+
    -+<h2 id="Defaults">Mengatur Nilai Default</h2>
    -+
    -+<p>Preferensi yang Anda buat mungkin mendefinisikan beberapa perilaku penting untuk aplikasi, jadi Anda
    -+perlu menginisialisasi file {@link android.content.SharedPreferences} yang terkait dengan
    -+nilai default untuk setiap {@link android.preference.Preference} bila pengguna menggunakan aplikasi
    -+Anda untuk pertama kali.</p>
    -+
    -+<p>Hal pertama yang harus Anda lakukan adalah menetapkan nilai default untuk setiap objek {@link
    -+android.preference.Preference}
    -+di file XML Anda menggunakan atribut {@code android:defaultValue}. Nilainya bisa berupa tipe data
    -+apa saja yang sesuai untuk objek {@link android.preference.Preference} bersangkutan. Misalnya:
    -+</p>
    -+
    -+<pre>
    -+&lt;!-- default value is a boolean -->
    -+&lt;CheckBoxPreference
    -+    android:defaultValue="true"
    -+    ... />
    -+
    -+&lt;!-- default value is a string -->
    -+&lt;ListPreference
    -+    android:defaultValue="@string/pref_syncConnectionTypes_default"
    -+    ... />
    -+</pre>
    -+
    -+<p>Kemudian, dari metode {@link android.app.Activity#onCreate onCreate()} dalam aktivitas utama aplikasi
    -+Anda&mdash;dan dalam aktivitas lainnya yang digunakan pengguna untuk masuk ke aplikasi Anda untuk pertama kali
    -+&mdash;panggil {@link android.preference.PreferenceManager#setDefaultValues
    -+setDefaultValues()}:</p>
    -+
    -+<pre>
    -+PreferenceManager.setDefaultValues(this, R.xml.advanced_preferences, false);
    -+</pre>
    -+
    -+<p>Memanggil ini selama {@link android.app.Activity#onCreate onCreate()} akan memastikan aplikasi
    -+Anda diinisialisasi dengan pengaturan default, yang mungkin perlu
    -+dibaca oleh aplikasi Anda untuk menentukan beberapa perilaku (seperti apakah akan mengunduh data pada
    -+jaringan seluler).</p>
    -+
    -+<p>Metode ini membutuhkan tiga argumen:</p>
    -+<ul>
    -+  <li>{@link android.content.Context} aplikasi Anda.</li>
    -+  <li>ID sumber daya untuk file XML preferensi yang ingin Anda atur nilai defaultnya.</li>
    -+  <li>Boolean menunjukkan apakah nilai default harus diatur lebih dari satu kali.
    -+<p>Bila <code>false</code>, sistem akan mengatur nilai default hanya jika metode ini belum pernah
    -+dipanggil sebelumnya (atau {@link android.preference.PreferenceManager#KEY_HAS_SET_DEFAULT_VALUES}
    -+dalam file preferensi berbagi nilai default salah).</p></li>
    -+</ul>
    -+
    -+<p>Selama Anda mengatur argumen ketiga ke <code>false</code>, Anda bisa dengan aman memanggil metode ini
    -+setiap kali aktivitas Anda memulai tanpa mengesampingkan preferensi tersimpan pengguna dengan mengatur ulang preferensi tersebut ke
    -+default. Akan tetapi, jika mengatur ke <code>true</code>, Anda akan mengesampingkan nilai
    -+sebelumnya dengan default.</p>
    -+
    -+
    -+
    -+<h2 id="PreferenceHeaders">Menggunakan Header Preferensi</h2>
    -+
    -+<p>Dalam kasus yang jarang terjadi, Anda mungkin perlu mendesain pengaturan agar layar pertama
    -+hanya menampilkan daftar <a href="#Subscreens">sublayar</a> (seperti dalam aplikasi Setting pada sistem,
    -+seperti yang ditampilkan dalam gambar 4 dan 5). Bila mengembangkan desain seperti itu untuk Android 3.0 dan yang lebih tinggi, Anda
    -+harus menggunakan fitur "header" yang baru di Android 3.0, sebagai ganti membangun sublayar dengan elemen
    -+{@link android.preference.PreferenceScreen} tersarang.</p>
    -+
    -+<p>Untuk membangun pengaturan dengan header, Anda perlu:</p>
    -+<ol>
    -+  <li>Memisahkan setiap grup pengaturan ke dalam instance {@link
    -+android.preference.PreferenceFragment} terpisah. Ini berarti, setiap grup pengaturan memerlukan file XML
    -+terpisah.</li>
    -+  <li>Membuat file header XML yang mencantumkan daftar setiap grup pengaturan dan mendeklarasikan fragmen mana
    -+yang berisi daftar pengaturan yang sesuai.</li>
    -+  <li>Memperluas kelas {@link android.preference.PreferenceActivity} untuk menjadi host pengaturan Anda.</li>
    -+  <li>Mengimplementasikan callback {@link
    -+android.preference.PreferenceActivity#onBuildHeaders onBuildHeaders()} untuk menetapkan file
    -+header.</li>
    -+</ol>
    -+
    -+<p>Manfaat besar dalam menggunakan desain ini adalah karena {@link android.preference.PreferenceActivity}
    -+secara otomatis akan menampilkan layout dua panel yang ditampilkan dalam gambar 4 bila dijalankan pada layar besar.</p>
    -+
    -+<p>Bahkan jika aplikasi Anda mendukung versi Android yang lebih lama dari 3.0, Anda bisa membangun
    -+aplikasi untuk menggunakan {@link android.preference.PreferenceFragment} bagi presentasi dua panel pada perangkat
    -+yang lebih baru sementara tetap mendukung hierarki multilayar biasa pada perangkat
    -+yang lebih lama (lihat bagian tentang <a href="#BackCompatHeaders">Mendukung versi yang lebih lama dengan
    -+header preferensi</a>).</p>
    -+
    -+<img src="{@docRoot}images/ui/settings/settings-headers-tablet.png" alt="" />
    -+<p class="img-caption"><strong>Gambar 4.</strong> Layout dua panel dengan header. <br/><b>1.</b> Header
    -+didefinisikan dengan file header XML. <br/><b>2.</b> Setiap grup pengaturan didefinisikan dengan
    -+{@link android.preference.PreferenceFragment} yang ditetapkan oleh elemen {@code &lt;header&gt;} dalam
    -+file header.</p>
    -+
    -+<img src="{@docRoot}images/ui/settings/settings-headers-handset.png" alt="" />
    -+<p class="img-caption"><strong>Gambar 5.</strong> Perangkat handset dengan header pengaturan. Bila sebuah
    -+item dipilih, {@link android.preference.PreferenceFragment} terkait akan menggantikan
    -+header.</p>
    -+
    -+
    -+<h3 id="CreateHeaders" style="clear:left">Membuat file header</h3>
    -+
    -+<p>Setiap grup pengaturan dalam daftar header Anda akan ditetapkan oleh elemen {@code &lt;header&gt;}
    -+tunggal dalam elemen {@code &lt;preference-headers&gt;} akar. Misalnya:</p>
    -+
    -+<pre>
    -+&lt;?xml version="1.0" encoding="utf-8"?>
    -+&lt;preference-headers xmlns:android="http://schemas.android.com/apk/res/android">
    -+    &lt;header
    -+        android:fragment="com.example.prefs.SettingsActivity$SettingsFragmentOne"
    -+        android:title="@string/prefs_category_one"
    -+        android:summary="@string/prefs_summ_category_one" />
    -+    &lt;header
    -+        android:fragment="com.example.prefs.SettingsActivity$SettingsFragmentTwo"
    -+        android:title="@string/prefs_category_two"
    -+        android:summary="@string/prefs_summ_category_two" >
    -+        &lt;!-- key/value pairs can be included as arguments for the fragment. -->
    -+        &lt;extra android:name="someKey" android:value="someHeaderValue" />
    -+    &lt;/header>
    -+&lt;/preference-headers>
    -+</pre>
    -+
    -+<p>Dengan atribut {@code android:fragment}, setiap header mendeklarasikan instance {@link
    -+android.preference.PreferenceFragment} yang harus terbuka saat pengguna memilih header.</p>
    -+
    -+<p>Elemen {@code &lt;extras&gt;} memungkinkan Anda meneruskan pasangan nilai-kunci ke fragmen di {@link
    -+android.os.Bundle}. Fragmen bisa mengambil argumen dengan memanggil {@link
    -+android.app.Fragment#getArguments()}. Anda bisa meneruskan argumen ke fragmen dengan berbagai
    -+alasan, namun satu alasan yang baik adalah untuk menggunakan kembali subkelas yang sama dari {@link
    -+android.preference.PreferenceFragment} untuk setiap grup dan menggunakan argumen untuk menetapkan file
    -+XML preferensi mana yang harus dimuat fragmen.</p>
    -+
    -+<p>Misalnya, ada fragmen yang bisa digunakan ulang untuk berbagai grup pengaturan, bila setiap
    -+header mendefinisikan argumen {@code &lt;extra&gt;} dengan kunci {@code "settings"}:</p>
    -+
    -+<pre>
    -+public static class SettingsFragment extends PreferenceFragment {
    -+    &#64;Override
    -+    public void onCreate(Bundle savedInstanceState) {
    -+        super.onCreate(savedInstanceState);
    -+
    -+        String settings = getArguments().getString("settings");
    -+        if ("notifications".equals(settings)) {
    -+            addPreferencesFromResource(R.xml.settings_wifi);
    -+        } else if ("sync".equals(settings)) {
    -+            addPreferencesFromResource(R.xml.settings_sync);
    -+        }
    -+    }
    -+}
    -+</pre>
    -+
    -+
    -+
    -+<h3 id="DisplayHeaders">Menampilkan header</h3>
    -+
    -+<p>Untuk menampilkan header preferensi, Anda harus mengimplementasikan metode callback {@link
    -+android.preference.PreferenceActivity#onBuildHeaders onBuildHeaders()} dan memanggil
    -+{@link android.preference.PreferenceActivity#loadHeadersFromResource
    -+loadHeadersFromResource()}. Misalnya:</p>
    -+
    -+<pre>
    -+public class SettingsActivity extends PreferenceActivity {
    -+    &#64;Override
    -+    public void onBuildHeaders(List&lt;Header> target) {
    -+        loadHeadersFromResource(R.xml.preference_headers, target);
    -+    }
    -+}
    -+</pre>
    -+
    -+<p>Bila pengguna memilih item dari daftar header, sistem akan membuka {@link
    -+android.preference.PreferenceFragment} terkait.</p>
    -+
    -+<p class="note"><strong>Catatan:</strong> Saat menggunakan header preferensi, subkelas {@link
    -+android.preference.PreferenceActivity} Anda tidak perlu mengimplementasikan metode {@link
    -+android.preference.PreferenceActivity#onCreate onCreate()}, karena tugas
    -+yang diperlukan untuk aktivitas hanyalah memuat header.</p>
    -+
    -+
    -+<h3 id="BackCompatHeaders">Mendukung versi yang lebih lama dengan header preferensi</h3>
    -+
    -+<p>Jika aplikasi Anda mendukung versi Android yang lebih lama dari 3.0, Anda tetap bisa menggunakan header untuk
    -+menyediakan layout dua panel saat berjalan pada Android 3.0 dan yang lebih tinggi. Anda hanya perlu membuat
    -+file XML preferensi tambahan yang menggunakan elemen {@link android.preference.Preference
    -+&lt;Preference&gt;} dasar yang berperilaku seperti item header (untuk digunakan oleh Android
    -+versi yang lebih lama).</p>
    -+
    -+<p>Akan tetapi, sebagai ganti membuka {@link android.preference.PreferenceScreen} baru, setiap elemen {@link
    -+android.preference.Preference &lt;Preference&gt;} mengirimkan {@link android.content.Intent} ke
    -+{@link android.preference.PreferenceActivity} yang menetapkan file XML preferensi mana yang
    -+akan dimuat.</p>
    -+
    -+<p>Misalnya, ini adalah file XML untuk header preferensi yang menggunakan Android 3.0
    -+dan yang lebih tinggi ({@code res/xml/preference_headers.xml}):</p>
    -+
    -+<pre>
    -+&lt;preference-headers xmlns:android="http://schemas.android.com/apk/res/android">
    -+    &lt;header
    -+        android:fragment="com.example.prefs.SettingsFragmentOne"
    -+        android:title="@string/prefs_category_one"
    -+        android:summary="@string/prefs_summ_category_one" />
    -+    &lt;header
    -+        android:fragment="com.example.prefs.SettingsFragmentTwo"
    -+        android:title="@string/prefs_category_two"
    -+        android:summary="@string/prefs_summ_category_two" />
    -+&lt;/preference-headers>
    -+</pre>
    -+
    -+<p>Dan ini adalah file preferensi yang menyediakan header yang sama untuk versi yang lebih lama dari
    -+Android 3.0 ({@code res/xml/preference_headers_legacy.xml}):</p>
    -+
    -+<pre>
    -+&lt;PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android">
    -+    &lt;Preference
    -+        android:title="@string/prefs_category_one"
    -+        android:summary="@string/prefs_summ_category_one"  >
    -+        &lt;intent
    -+            android:targetPackage="com.example.prefs"
    -+            android:targetClass="com.example.prefs.SettingsActivity"
    -+            android:action="com.example.prefs.PREFS_ONE" />
    -+    &lt;/Preference>
    -+    &lt;Preference
    -+        android:title="@string/prefs_category_two"
    -+        android:summary="@string/prefs_summ_category_two" >
    -+        &lt;intent
    -+            android:targetPackage="com.example.prefs"
    -+            android:targetClass="com.example.prefs.SettingsActivity"
    -+            android:action="com.example.prefs.PREFS_TWO" />
    -+    &lt;/Preference>
    -+&lt;/PreferenceScreen>
    -+</pre>
    -+
    -+<p>Karena dukungan untuk {@code &lt;preference-headers&gt;} telah ditambahkan di Android 3.0, sistem akan memanggil
    -+{@link android.preference.PreferenceActivity#onBuildHeaders onBuildHeaders()} di {@link
    -+android.preference.PreferenceActivity} hanya saat berjalan pada Android 3.0 atau yang lebih tinggi. Untuk memuat
    -+file header "lama" ({@code preference_headers_legacy.xml}), Anda harus memeriksa versi Android
    -+dan, jika versi tersebut lebih lama dari Android 3.0 ({@link
    -+android.os.Build.VERSION_CODES#HONEYCOMB}), panggil {@link
    -+android.preference.PreferenceActivity#addPreferencesFromResource addPreferencesFromResource()} untuk
    -+memuat file header lama. Misalnya:</p>
    -+
    -+<pre>
    -+&#64;Override
    -+public void onCreate(Bundle savedInstanceState) {
    -+    super.onCreate(savedInstanceState);
    -+    ...
    -+
    -+    if (Build.VERSION.SDK_INT &lt; Build.VERSION_CODES.HONEYCOMB) {
    -+        // Load the legacy preferences headers
    -+        addPreferencesFromResource(R.xml.preference_headers_legacy);
    -+    }
    -+}
    -+
    -+// Called only on Honeycomb and later
    -+&#64;Override
    -+public void onBuildHeaders(List&lt;Header> target) {
    -+   loadHeadersFromResource(R.xml.preference_headers, target);
    -+}
    -+</pre>
    -+
    -+<p>Satu-satunya hal yang perlu dilakukan adalah menangani {@link android.content.Intent} yang diteruskan ke
    -+aktivitas untuk mengidentifikasi file preferensi yang akan dimuat. Jadi ambillah tindakan intent dan bandingkan dengan
    -+string tindakan yang diketahui yang telah Anda gunakan dalam tag {@code &lt;intent&gt;} XML preferensi:</p>
    -+
    -+<pre>
    -+final static String ACTION_PREFS_ONE = "com.example.prefs.PREFS_ONE";
    -+...
    -+
    -+&#64;Override
    -+public void onCreate(Bundle savedInstanceState) {
    -+    super.onCreate(savedInstanceState);
    -+
    -+    String action = getIntent().getAction();
    -+    if (action != null &amp;&amp; action.equals(ACTION_PREFS_ONE)) {
    -+        addPreferencesFromResource(R.xml.preferences);
    -+    }
    -+    ...
    -+
    -+    else if (Build.VERSION.SDK_INT &lt; Build.VERSION_CODES.HONEYCOMB) {
    -+        // Load the legacy preferences headers
    -+        addPreferencesFromResource(R.xml.preference_headers_legacy);
    -+    }
    -+}
    -+</pre>
    -+
    -+<p>Ketahuilah bahwa panggilan berturut-turut ke {@link
    -+android.preference.PreferenceActivity#addPreferencesFromResource addPreferencesFromResource()} akan
    -+menumpuk semua preferensi ke dalam satu daftar, jadi pastikan bahwa ini hanya dipanggil sekali dengan mengikatkan syarat
    -+ke pernyataan else-if.</p>
    -+
    -+
    -+
    -+
    -+
    -+<h2 id="ReadingPrefs">Preferensi Membaca</h2>
    -+
    -+<p>Secara default, semua preferensi aplikasi Anda disimpan ke file yang bisa diakses dari mana saja
    -+di dalam aplikasi dengan memanggil metode statis {@link
    -+android.preference.PreferenceManager#getDefaultSharedPreferences
    -+PreferenceManager.getDefaultSharedPreferences()}. Ini akan mengembalikan objek {@link
    -+android.content.SharedPreferences} berisi semua pasangan nilai-kunci yang terkait
    -+dengan objek {@link android.preference.Preference} yang digunakan di {@link
    -+android.preference.PreferenceActivity} Anda.</p>
    -+
    -+<p>Misalnya, inilah cara membaca salah satu nilai preferensi dari aktivitas lain dalam aplikasi
    -+Anda:</p>
    -+
    -+<pre>
    -+SharedPreferences sharedPref = PreferenceManager.getDefaultSharedPreferences(this);
    -+String syncConnPref = sharedPref.getString(SettingsActivity.KEY_PREF_SYNC_CONN, "");
    -+</pre>
    -+
    -+
    -+
    -+<h3 id="Listening">Mendengarkan perubahan preferensi</h3>
    -+
    -+<p>Ada beberapa alasan yang membuat Anda perlu mendapatkan pemberitahuan segera setelah pengguna mengubah salah satu
    -+preferensi. Untuk menerima callback saat perubahan terjadi pada salah satu preferensi,
    -+implementasikan antarmuka {@link android.content.SharedPreferences.OnSharedPreferenceChangeListener
    -+SharedPreference.OnSharedPreferenceChangeListener} dan daftarkan listener untuk objek
    -+{@link android.content.SharedPreferences} dengan memanggil {@link
    -+android.content.SharedPreferences#registerOnSharedPreferenceChangeListener
    -+registerOnSharedPreferenceChangeListener()}.</p>
    -+
    -+<p>Antarmuka hanya memiliki satu metode callback, {@link
    -+android.content.SharedPreferences.OnSharedPreferenceChangeListener#onSharedPreferenceChanged
    -+onSharedPreferenceChanged()}, dan mungkin lebih mudah mengimplementasikan antarmuka sebagai bagian dari
    -+aktivitas Anda. Misalnya:</p>
    -+
    -+<pre>
    -+public class SettingsActivity extends PreferenceActivity
    -+                              implements OnSharedPreferenceChangeListener {
    -+    public static final String KEY_PREF_SYNC_CONN = "pref_syncConnectionType";
    -+    ...
    -+
    -+    public void onSharedPreferenceChanged(SharedPreferences sharedPreferences,
    -+        String key) {
    -+        if (key.equals(KEY_PREF_SYNC_CONN)) {
    -+            Preference connectionPref = findPreference(key);
    -+            // Set summary to be the user-description for the selected value
    -+            connectionPref.setSummary(sharedPreferences.getString(key, ""));
    -+        }
    -+    }
    -+}
    -+</pre>
    -+
    -+<p>Dalam contoh ini, metode akan memeriksa apakah pengaturan yang diubah adalah untuk kunci preferensi yang diketahui. Ini akan
    -+memanggil {@link android.preference.PreferenceActivity#findPreference findPreference()} untuk mendapatkan objek
    -+{@link android.preference.Preference} yang diubah agar bisa memodifikasi rangkuman item
    -+menjadi keterangan pada pilihan pengguna. Ini berarti, bila pengaturan adalah {@link
    -+android.preference.ListPreference} atau pengaturan multipilihan, Anda harus memanggil {@link
    -+android.preference.Preference#setSummary setSummary()} bila pengaturan berubah ke tampilkan
    -+status saat ini (seperti pengaturan Sleep yang ditampilkan dalam gambar 5).</p>
    -+
    -+<p class="note"><strong>Catatan:</strong> Seperti dijelaskan dalam dokumen Desain Android tentang <a href="{@docRoot}design/patterns/settings.html">Pengaturan</a>, kami merekomendasikan Anda untuk memperbarui
    -+rangkuman {@link android.preference.ListPreference} setiap kali pengguna mengubah preferensi untuk
    -+menjelaskan pengaturan saat ini.</p>
    -+
    -+<p>Untuk manajemen daur hidup yang baik di aktivitas, kami merekomendasikan Anda untuk mendaftarkan dan mencabut pendaftaran
    -+{@link android.content.SharedPreferences.OnSharedPreferenceChangeListener} selama callback {@link
    -+android.app.Activity#onResume} dan {@link android.app.Activity#onPause}:</p>
    -+
    -+<pre>
    -+&#64;Override
    -+protected void onResume() {
    -+    super.onResume();
    -+    getPreferenceScreen().getSharedPreferences()
    -+            .registerOnSharedPreferenceChangeListener(this);
    -+}
    -+
    -+&#64;Override
    -+protected void onPause() {
    -+    super.onPause();
    -+    getPreferenceScreen().getSharedPreferences()
    -+            .unregisterOnSharedPreferenceChangeListener(this);
    -+}
    -+</pre>
    -+
    -+<p class="caution"><strong>Perhatian:</strong> Bila Anda memanggil {@link
    -+android.content.SharedPreferences#registerOnSharedPreferenceChangeListener
    -+registerOnSharedPreferenceChangeListener()}, pengelola preferensi saat ini tidak akan
    -+menyimpan referensi kuat ke listener. Anda harus menyimpan referensi
    -+kuat bagi listener, atau referensi akan rentan terhadap pengumpulan sampah. Kami
    -+merekomendasikan Anda untuk mempertahankan referensi bagi listener dalam data instance objek
    -+yang akan ada selama Anda memerlukan listener tersebut.</p>
    -+
    -+<p>Misalnya, dalam kode berikut, caller tidak menyimpan referensi ke
    -+listener. Akibatnya, listener akan dikenakan pengumpulan sampah,
    -+dan suatu saat nanti akan gagal:</p>
    -+
    -+<pre>
    -+prefs.registerOnSharedPreferenceChangeListener(
    -+  // Bad! The listener is subject to garbage collection!
    -+  new SharedPreferences.OnSharedPreferenceChangeListener() {
    -+  public void onSharedPreferenceChanged(SharedPreferences prefs, String key) {
    -+    // listener implementation
    -+  }
    -+});
    -+</pre>
    -+
    -+<p>Sebagai gantinya, simpan referensi ke listener dalam bidang data instance
    -+objek yang akan ada selama listener dibutuhkan:</p>
    -+
    -+<pre>
    -+SharedPreferences.OnSharedPreferenceChangeListener listener =
    -+    new SharedPreferences.OnSharedPreferenceChangeListener() {
    -+  public void onSharedPreferenceChanged(SharedPreferences prefs, String key) {
    -+    // listener implementation
    -+  }
    -+};
    -+prefs.registerOnSharedPreferenceChangeListener(listener);
    -+</pre>
    -+
    -+<h2 id="NetworkUsage">Mengelola Penggunaan Jaringan</h2>
    -+
    -+
    -+<p>Mulai Android 4.0, aplikasi Settings untuk sistem memungkinkan pengguna melihat seberapa besar
    -+data jaringan yang digunakan aplikasi mereka saat berada di latar depan dan latar belakang. Kemudian pengguna bisa
    -+menonaktifkan penggunaan data latar belakang untuk aplikasi individual. Agar pengguna tidak menonaktifkan akses
    -+aplikasi ke data dari latar belakang, Anda harus menggunakan koneksi data secara efisien dan mengizinkan
    -+pengguna untuk menyaring penggunaan data aplikasi melalui pengaturan aplikasi Anda.<p>
    -+
    -+<p>Misalnya, Anda bisa mengizinkan pengguna untuk mengontrol seberapa sering aplikasi menyinkronkan data, apakah aplikasi
    -+hanya melakukan pengunggahan/pengunduhan bila ada Wi-Fi, apakah aplikasi menggunakan data saat roaming, dll. Dengan
    -+tersedianya kontrol ini bagi pengguna, mereka kemungkinan besar tidak akan menonaktifkan akses aplikasi ke data
    -+saat mendekati batas yang mereka tetapkan dalam Settings pada sistem, karena mereka bisa mengontrol secara tepat
    -+seberapa besar data yang digunakan aplikasi Anda.</p>
    -+
    -+<p>Setelah menambahkan preferensi yang diperlukan dalam {@link android.preference.PreferenceActivity} Anda
    -+untuk mengontrol kebiasaan data aplikasi, Anda harus menambahkan filter intent untuk {@link
    -+android.content.Intent#ACTION_MANAGE_NETWORK_USAGE} dalam file manifes Anda. Misalnya:</p>
    -+
    -+<pre>
    -+&lt;activity android:name="SettingsActivity" ... >
    -+    &lt;intent-filter>
    -+       &lt;action android:name="android.intent.action.MANAGE_NETWORK_USAGE" />
    -+       &lt;category android:name="android.intent.category.DEFAULT" />
    -+    &lt;/intent-filter>
    -+&lt;/activity>
    -+</pre>
    -+
    -+<p>Filter intent ini menunjukkan pada sistem bahwa ini adalah aktivitas yang mengontrol penggunaan
    -+data aplikasi Anda. Jadi, saat pengguna memeriksa seberapa banyak data yang digunakan oleh aplikasi dari
    -+aplikasi Settings pada sistem, tombol <em>View application settings</em> akan tersedia dan menjalankan
    -+{@link android.preference.PreferenceActivity} sehingga pengguna bisa menyaring seberapa besar data yang digunakan
    -+aplikasi Anda.</p>
    -+
    -+
    -+
    -+
    -+
    -+
    -+
    -+<h2 id="Custom">Membangun Preferensi Custom</h2>
    -+
    -+<p>Kerangka kerja Android menyertakan berbagai subkelas {@link android.preference.Preference} yang
    -+memungkinkan Anda membangun UI untuk beberapa macam tipe pengaturan.
    -+Akan tetapi, Anda mungkin menemukan pengaturan yang diperlukan bila tidak ada solusi bawaan, seperti
    -+picker nomor atau picker tanggal. Dalam hal demikian, Anda akan perlu membuat preferensi custom dengan memperluas
    -+kelas {@link android.preference.Preference} atau salah satu subkelas lainnya.</p>
    -+
    -+<p>Bila memperluas kelas {@link android.preference.Preference}, ada beberapa hal
    -+penting yang perlu Anda lakukan:</p>
    -+
    -+<ul>
    -+  <li>Menetapkan antarmuka pengguna yang akan muncul saat pengguna memilih pengaturan.</li>
    -+  <li>Menyimpan nilai pengaturan bila perlu.</li>
    -+  <li>Menginisialisasi {@link android.preference.Preference} dengan nilai saat ini (atau default)
    -+bila muncul di tampilan.</li>
    -+  <li>Menyediakan nilai default bila diminta oleh sistem.</li>
    -+  <li>Jika {@link android.preference.Preference} menyediakan UI sendiri (seperti dialog), simpan
    -+dan pulihkan status untuk menangani perubahan daur hidup (seperti saat pengguna memutar layar).</li>
    -+</ul>
    -+
    -+<p>Bagian berikut menjelaskan cara melakukan setiap tugas ini.</p>
    -+
    -+
    -+
    -+<h3 id="CustomSelected">Menetapkan antarmuka pengguna</h3>
    -+
    -+  <p>Jika secara langsung memperluas kelas {@link android.preference.Preference}, Anda perlu mengimplementasikan
    -+{@link android.preference.Preference#onClick()} untuk mendefinisikan tindakan yang terjadi bila pengguna
    -+memilih item tersebut. Akan tetapi, sebagian besar pengaturan custom memperluas {@link android.preference.DialogPreference} untuk
    -+menampilkan dialog, sehingga menyederhanakan prosedur. Bila memperluas {@link
    -+android.preference.DialogPreference}, Anda harus memanggil {@link
    -+android.preference.DialogPreference#setDialogLayoutResource setDialogLayoutResourcs()} selama di
    -+konstruktor kelas untuk menetapkan layout dialog.</p>
    -+
    -+  <p>Misalnya, beri ini konstruktor untuk {@link
    -+android.preference.DialogPreference} custom yang mendeklarasikan layout dan menetapkan teks untuk tombol dialog
    -+negatif dan positif default:</p>
    -+
    -+<pre>
    -+public class NumberPickerPreference extends DialogPreference {
    -+    public NumberPickerPreference(Context context, AttributeSet attrs) {
    -+        super(context, attrs);
    -+
    -+        setDialogLayoutResource(R.layout.numberpicker_dialog);
    -+        setPositiveButtonText(android.R.string.ok);
    -+        setNegativeButtonText(android.R.string.cancel);
    -+
    -+        setDialogIcon(null);
    -+    }
    -+    ...
    -+}
    -+</pre>
    -+
    -+
    -+
    -+<h3 id="CustomSave">Menyimpan nilai pengaturan</h3>
    -+
    -+<p>Anda bisa menyimpan nilai pengaturan kapan saja dengan memanggil salah satu metode {@code persist*()} kelas {@link
    -+android.preference.Preference}, seperti {@link
    -+android.preference.Preference#persistInt persistInt()} jika nilai pengaturan adalah integer atau
    -+{@link android.preference.Preference#persistBoolean persistBoolean()} untuk menyimpan boolean.</p>
    -+
    -+<p class="note"><strong>Catatan:</strong> Setiap {@link android.preference.Preference} hanya bisa menyimpan satu
    -+tipe data, jadi Anda harus menggunakan metode {@code persist*()} yang tepat untuk tipe data yang digunakan
    -+oleh {@link android.preference.Preference} custom Anda.</p>
    -+
    -+<p>Bila Anda memilih untuk mempertahankannya, pengaturan bisa bergantung pada kelas {@link
    -+android.preference.Preference} yang Anda perluas. Jika Anda memperluas {@link
    -+android.preference.DialogPreference}, maka Anda harus mempertahankan nilai hanya jika dialog
    -+tertutup karena hasil positif (pengguna memilih tombol "OK").</p>
    -+
    -+<p>Bila {@link android.preference.DialogPreference} tertutup, sistem akan memanggil metode {@link
    -+android.preference.DialogPreference#onDialogClosed onDialogClosed()}. Metode mencakup argumen
    -+boolean yang menetapkan apakah hasil pengguna "positif"&mdash;jika nilainya
    -+<code>true</code>, maka pengguna memilih tombol positif dan Anda harus menyimpan nilai baru. Misalnya:
    -+</p>
    -+
    -+<pre>
    -+&#64;Override
    -+protected void onDialogClosed(boolean positiveResult) {
    -+    // When the user selects "OK", persist the new value
    -+    if (positiveResult) {
    -+        persistInt(mNewValue);
    -+    }
    -+}
    -+</pre>
    -+
    -+<p>Dalam contoh ini, <code>mNewValue</code> adalah anggota kelas yang menampung nilai
    -+pengaturan saat ini. Memanggil {@link android.preference.Preference#persistInt persistInt()} akan menyimpan nilai
    -+ke file {@link android.content.SharedPreferences} (secara otomatis menggunakan kunci yang
    -+ditetapkan dalam file XML untuk {@link android.preference.Preference} ini).</p>
    -+
    -+
    -+<h3 id="CustomInitialize">Menginisialisasi nilai saat ini</h3>
    -+
    -+<p>Bila sistem menambahkan {@link android.preference.Preference} Anda ke layar, ia
    -+akan memanggil {@link android.preference.Preference#onSetInitialValue onSetInitialValue()} untuk memberi tahu
    -+Anda apakah pengaturan memiliki nilai yang dipertahankan. Jika tidak ada nilai yang dipertahankan, panggilan ini
    -+akan menyediakan nilai default bagi Anda.</p>
    -+
    -+<p>Metode {@link android.preference.Preference#onSetInitialValue onSetInitialValue()} akan meneruskan
    -+boolean, <code>restorePersistedValue</code>, untuk menunjukkan apakah nilai dipertahankan
    -+untuk pengaturan. Jika <code>true</code>, maka Anda harus mengambil nilai yang dipertahankan dengan memanggil
    -+salah satu metode {@code getPersisted*()} kelas {@link
    -+android.preference.Preference}, seperti {@link
    -+android.preference.Preference#getPersistedInt getPersistedInt()} untuk nilai integer. Anda biasanya
    -+perlu mengambil nilai yang dipertahankan agar bisa memperbarui UI dengan benar untuk merefleksikan
    -+nilai yang tersimpan sebelumnya.</p>
    -+
    -+<p>Jika <code>restorePersistedValue</code> adalah <code>false</code>, maka Anda
    -+harus menggunakan nilai default yang diteruskan dalam argumen kedua.</p>
    -+
    -+<pre>
    -+&#64;Override
    -+protected void onSetInitialValue(boolean restorePersistedValue, Object defaultValue) {
    -+    if (restorePersistedValue) {
    -+        // Restore existing state
    -+        mCurrentValue = this.getPersistedInt(DEFAULT_VALUE);
    -+    } else {
    -+        // Set default state from the XML attribute
    -+        mCurrentValue = (Integer) defaultValue;
    -+        persistInt(mCurrentValue);
    -+    }
    -+}
    -+</pre>
    -+
    -+<p>Setiap metode {@code getPersisted*()} memerlukan argumen yang menetapkan
    -+nilai default untuk digunakan jika tidak ada nilai yang dipertahankan atau kunci tidak ada. Dalam contoh
    -+di atas, konstanta lokal yang digunakan untuk menetapkan nilai default dalam kasus {@link
    -+android.preference.Preference#getPersistedInt getPersistedInt()} tidak bisa mengembalikan nilai yang dipertahankan.</p>
    -+
    -+<p class="caution"><strong>Perhatian:</strong> Anda <strong>tidak bisa</strong> menggunakan
    -+<code>defaultValue</code> sebagai nilai default dalam metode {@code getPersisted*()}, karena
    -+nilainya selalu nol bila <code>restorePersistedValue</code> adalah <code>true</code>.</p>
    -+
    -+
    -+<h3 id="CustomDefault">Menyediakan nilai default</h3>
    -+
    -+<p>Jika instance kelas {@link android.preference.Preference} Anda menetapkan nilai default
    -+(dengan atribut {@code android:defaultValue}), maka
    -+sistem akan memanggil {@link android.preference.Preference#onGetDefaultValue
    -+onGetDefaultValue()} bila membuat instance objek untuk mengambil nilai. Anda harus mengimplementasikan
    -+metode ini agar sistem bisa menyimpan nilai default dalam {@link
    -+android.content.SharedPreferences}. Misalnya:</p>
    -+
    -+<pre>
    -+&#64;Override
    -+protected Object onGetDefaultValue(TypedArray a, int index) {
    -+    return a.getInteger(index, DEFAULT_VALUE);
    -+}
    -+</pre>
    -+
    -+<p>Argumen metode menyediakan semua hal yang Anda perlukan: larik atribut dan posisi
    -+indeks dari {@code android:defaultValue}, yang harus Anda ambil. Alasan Anda harus
    -+mengimplementasikan metode ini untuk mengekstrak nilai default dari atribut adalah karena Anda harus menetapkan
    -+nilai default lokal untuk atribut jika nilai tidak didefinisikan.</p>
    -+
    -+
    -+
    -+<h3 id="CustomSaveState">Menyimpan dan memulihkan status Preferensi</h3>
    -+
    -+<p>Seperti halnya {@link android.view.View} di layout, subkelas {@link android.preference.Preference}
    -+Anda bertanggung jawab menyimpan dan memulihkan statusnya jika aktivitas atau fragmen
    -+di-restart (seperti saat pengguna memutar layar). Untuk menyimpan
    -+dan memulihkan status kelas {@link android.preference.Preference} dengan benar, Anda harus mengimplementasikan
    -+metode callback daur hidup {@link android.preference.Preference#onSaveInstanceState
    -+onSaveInstanceState()} dan {@link
    -+android.preference.Preference#onRestoreInstanceState onRestoreInstanceState()}.</p>
    -+
    -+<p>Status {@link android.preference.Preference} Anda didefinisikan oleh objek yang mengimplementasikan
    -+antarmuka {@link android.os.Parcelable}. Kerangka kerja Android menyediakan objek seperti itu untuk Anda gunakan
    -+sebagai titik mulai untuk mendefinisikan objek status Anda: kelas {@link
    -+android.preference.Preference.BaseSavedState}.</p>
    -+
    -+<p>Untuk mendefinisikan cara kelas {@link android.preference.Preference} menyimpan statusnya, Anda harus
    -+memperluas kelas {@link android.preference.Preference.BaseSavedState}. Anda hanya perlu mengesampingkan
    -+ beberapa metode dan mendefinisikan objek {@link android.preference.Preference.BaseSavedState#CREATOR}
    -+.</p>
    -+
    -+<p>Untuk sebagian besar aplikasi, Anda bisa menyalin implementasi berikut dan cukup mengubah baris yang
    -+menangani {@code value} jika subkelas {@link android.preference.Preference} Anda menyimpan tipe
    -+data selain integer.</p>
    -+
    -+<pre>
    -+private static class SavedState extends BaseSavedState {
    -+    // Member that holds the setting's value
    -+    // Change this data type to match the type saved by your Preference
    -+    int value;
    -+
    -+    public SavedState(Parcelable superState) {
    -+        super(superState);
    -+    }
    -+
    -+    public SavedState(Parcel source) {
    -+        super(source);
    -+        // Get the current preference's value
    -+        value = source.readInt();  // Change this to read the appropriate data type
    -+    }
    -+
    -+    &#64;Override
    -+    public void writeToParcel(Parcel dest, int flags) {
    -+        super.writeToParcel(dest, flags);
    -+        // Write the preference's value
    -+        dest.writeInt(value);  // Change this to write the appropriate data type
    -+    }
    -+
    -+    // Standard creator object using an instance of this class
    -+    public static final Parcelable.Creator&lt;SavedState> CREATOR =
    -+            new Parcelable.Creator&lt;SavedState>() {
    -+
    -+        public SavedState createFromParcel(Parcel in) {
    -+            return new SavedState(in);
    -+        }
    -+
    -+        public SavedState[] newArray(int size) {
    -+            return new SavedState[size];
    -+        }
    -+    };
    -+}
    -+</pre>
    -+
    -+<p>Dengan implementasi {@link android.preference.Preference.BaseSavedState} di atas yang ditambahkan
    -+ke aplikasi Anda (biasanya sebagai subkelas dari subkelas {@link android.preference.Preference}), Anda
    -+nanti perlu mengimplementasikan metode {@link android.preference.Preference#onSaveInstanceState
    -+onSaveInstanceState()} dan {@link
    -+android.preference.Preference#onRestoreInstanceState onRestoreInstanceState()} untuk subkelas
    -+{@link android.preference.Preference} Anda.</p>
    -+
    -+<p>Misalnya:</p>
    -+
    -+<pre>
    -+&#64;Override
    -+protected Parcelable onSaveInstanceState() {
    -+    final Parcelable superState = super.onSaveInstanceState();
    -+    // Check whether this Preference is persistent (continually saved)
    -+    if (isPersistent()) {
    -+        // No need to save instance state since it's persistent,
    -+        // use superclass state
    -+        return superState;
    -+    }
    -+
    -+    // Create instance of custom BaseSavedState
    -+    final SavedState myState = new SavedState(superState);
    -+    // Set the state's value with the class member that holds current
    -+    // setting value
    -+    myState.value = mNewValue;
    -+    return myState;
    -+}
    -+
    -+&#64;Override
    -+protected void onRestoreInstanceState(Parcelable state) {
    -+    // Check whether we saved the state in onSaveInstanceState
    -+    if (state == null || !state.getClass().equals(SavedState.class)) {
    -+        // Didn't save the state, so call superclass
    -+        super.onRestoreInstanceState(state);
    -+        return;
    -+    }
    -+
    -+    // Cast state to custom BaseSavedState and pass to superclass
    -+    SavedState myState = (SavedState) state;
    -+    super.onRestoreInstanceState(myState.getSuperState());
    -+
    -+    // Set this Preference's widget to reflect the restored state
    -+    mNumberPicker.setValue(myState.value);
    -+}
    -+</pre>
    -+
    -diff --git a/docs/html-intl/intl/id/guide/topics/ui/ui-events.jd b/docs/html-intl/intl/id/guide/topics/ui/ui-events.jd
    -new file mode 100644
    -index 0000000..0307b34
    ---- /dev/null
    -+++ b/docs/html-intl/intl/id/guide/topics/ui/ui-events.jd
    -@@ -0,0 +1,291 @@
    -+page.title=Kejadian Input
    -+parent.title=Antarmuka Pengguna
    -+parent.link=index.html
    -+@jd:body
    -+
    -+<div id="qv-wrapper">
    -+<div id="qv">
    -+  <h2>Dalam dokumen ini</h2>
    -+  <ol>
    -+    <li><a href="#EventListeners">Event Listener</a></li>
    -+    <li><a href="#EventHandlers">Event Handler</a></li>
    -+    <li><a href="#TouchMode">Mode Sentuh</a></li>
    -+    <li><a href="#HandlingFocus">Menangani Fokus</a></li>
    -+  </ol>
    -+
    -+</div>
    -+</div>
    -+
    -+<p>Di Android, ada lebih dari satu cara untuk mencegat kejadian dari interaksi pengguna dengan aplikasi Anda.
    -+Saat mempertimbangkan kejadian dalam antarmuka pengguna Anda, pendekatannya adalah menangkap kejadian
    -+dari objek View tertentu yang digunakan pengguna untuk berinteraksi. Kelas View menyediakan sarana untuk melakukannya.</p>
    -+
    -+<p>Dalam berbagai kelas View yang akan digunakan untuk menyusun layout, Anda mungkin melihat beberapa metode callback
    -+publik yang tampak berguna untuk kejadian UI. Metode ini dipanggil oleh kerangka kerja Android ketika masing-masing
    -+tindakan terjadi pada objek itu. Misalnya, bila View (seperti Button/Tombol) disentuh,
    -+metode <code>onTouchEvent()</code> akan dipanggil pada objek itu. Akan tetapi, untuk mencegatnya, Anda harus memperluas
    -+kelas dan mengesampingkan metode itu. Akan tetapi, memperluas setiap objek View
    -+untuk menangani kejadian seperti itu tidaklah praktis. Karena itulah kelas View juga berisi
    -+sekumpulan antarmuka tersarang dengan callback yang jauh lebih mudah didefinisikan. Antarmuka ini,
    -+yang disebut <a href="#EventListeners">event listener</a>, merupakan tiket Anda untuk menangkap interaksi pengguna dengan UI.</p>
    -+
    -+<p>Walaupun Anda akan lebih sering menggunakan event listener ini untuk interaksi pengguna,
    -+mungkin ada saatnya Anda ingin memperluas kelas View, untuk membuat komponen custom.
    -+Mungkin Anda ingin memperluas kelas {@link android.widget.Button}
    -+untuk membuat sesuatu yang lebih menarik. Dalam hal ini, Anda akan dapat mendefinisikan perilaku kejadian default untuk kelas Anda dengan menggunakan
    -+kelas <a href="#EventHandlers">event handler</a>.</p>
    -+
    -+
    -+<h2 id="EventListeners">Event Listener</h2>
    -+
    -+<p>Event listener merupakan antarmuka di kelas {@link android.view.View} yang berisi metode
    -+callback tunggal. Metode ini akan dipanggil oleh kerangka kerja Android bila View yang
    -+telah didaftarkan dengan listener dipicu oleh interaksi pengguna dengan item dalam UI.</p>
    -+
    -+<p>Yang juga disertakan dalam antarmuka event listener adalah metode callback berikut ini:</p>
    -+
    -+<dl>
    -+  <dt><code>onClick()</code></dt>
    -+    <dd>Dari {@link android.view.View.OnClickListener}.
    -+    Ini dipanggil baik saat pengguna menyentuh item
    -+ (bila dalam mode sentuh), maupun memfokuskan pada item dengan tombol navigasi atau trackball dan
    -+menekan tombol "enter" yang sesuai atau menekan trackball.</dd>
    -+  <dt><code>onLongClick()</code></dt>
    -+    <dd>Dari {@link android.view.View.OnLongClickListener}.
    -+    Ini dipanggil baik saat pengguna menyentuh dan menahan item (bila dalam mode sentuh),
    -+maupun memfokuskan pada item dengan tombol navigasi atau trackball dan
    -+menekan serta menahan tombol "enter" yang sesuai atau menekan dan menahan trackball (selama satu detik).</dd>
    -+  <dt><code>onFocusChange()</code></dt>
    -+    <dd>Dari {@link android.view.View.OnFocusChangeListener}.
    -+    Ini dipanggil saat pengguna menyusuri ke atau dari item, dengan menggunakan tombol navigasi atau trackball.</dd>
    -+  <dt><code>onKey()</code></dt>
    -+    <dd>Dari {@link android.view.View.OnKeyListener}.
    -+    Ini dipanggil saat pengguna memfokuskan pada item dan menekan atau melepas tombol fisik pada perangkat.</dd>
    -+  <dt><code>onTouch()</code></dt>
    -+    <dd>Dari {@link android.view.View.OnTouchListener}.
    -+    Ini dipanggil saat pengguna melakukan tindakan yang digolongkan sebagai kejadian sentuh, termasuk penekanan, pelepasan,
    -+atau gerak perpindahan pada layar (dalam batasan item itu).</dd>
    -+  <dt><code>onCreateContextMenu()</code></dt>
    -+    <dd>Dari {@link android.view.View.OnCreateContextMenuListener}.
    -+    Ini dipanggil saat Menu Konteks sedang dibuat (akibat "klik lama" terus-menerus). Lihat diskusi
    -+tentang menu konteks di panduan pengembang <a href="{@docRoot}guide/topics/ui/menus.html#context-menu">Menu</a>.
    -+</dd>
    -+</dl>
    -+
    -+<p>Metode ini satu-satunya yang menempati antarmukanya masing-masing. Untuk mendefinisikan salah satu metode ini
    -+dan menangani kejadian Anda, implementasikan antarmuka tersarang dalam Aktivitas Anda atau definisikan sebagai kelas anonim.
    -+Kemudian, teruskan satu
    -+instance implementasi Anda pada masing-masing metode <code>View.set...Listener()</code>. (Misalnya, panggil
    -+<code>{@link android.view.View#setOnClickListener(View.OnClickListener) setOnClickListener()}</code>
    -+dan teruskan implementasi {@link android.view.View.OnClickListener OnClickListener} Anda.)</p>
    -+
    -+<p>Contoh di bawah menunjukkan cara mendaftarkan on-click listener untuk Button. </p>
    -+
    -+<pre>
    -+// Create an anonymous implementation of OnClickListener
    -+private OnClickListener mCorkyListener = new OnClickListener() {
    -+    public void onClick(View v) {
    -+      // do something when the button is clicked
    -+    }
    -+};
    -+
    -+protected void onCreate(Bundle savedValues) {
    -+    ...
    -+    // Capture our button from layout
    -+    Button button = (Button)findViewById(R.id.corky);
    -+    // Register the onClick listener with the implementation above
    -+    button.setOnClickListener(mCorkyListener);
    -+    ...
    -+}
    -+</pre>
    -+
    -+<p>Anda juga akan merasa lebih praktis mengimplementasikan OnClickListener sebagai bagian dari Aktivitas.
    -+Ini akan menghindari beban kelas ekstra dan alokasi objek. Misalnya:</p>
    -+<pre>
    -+public class ExampleActivity extends Activity implements OnClickListener {
    -+    protected void onCreate(Bundle savedValues) {
    -+        ...
    -+        Button button = (Button)findViewById(R.id.corky);
    -+        button.setOnClickListener(this);
    -+    }
    -+
    -+    // Implement the OnClickListener callback
    -+    public void onClick(View v) {
    -+      // do something when the button is clicked
    -+    }
    -+    ...
    -+}
    -+</pre>
    -+
    -+<p>Perhatikan bahwa callback <code>onClick()</code> dalam contoh di atas tidak memiliki
    -+nilai hasil, namun beberapa metode event listener lainnya harus mengembalikan boolean. Sebabnya
    -+bergantung pada kejadian. Untuk sebagian yang mengembalikan boolean, ini sebabnya:</p>
    -+<ul>
    -+  <li><code>{@link android.view.View.OnLongClickListener#onLongClick(View) onLongClick()}</code> -
    -+    Ini mengembalikan boolean untuk menunjukkan apakah Anda telah menggunakan kejadian dan tidak boleh dibawa lebih jauh.
    -+    Yaitu, mengembalikan <em>benar</em> untuk menunjukkan apakah Anda telah menangani kejadian dan semestinya berhenti di sini;
    -+    mengembalikan <em>salah</em> jika Anda tidak menanganinya dan/atau kejadian semestinya berlanjut ke
    -+    on-click listener lainnya.</li>
    -+  <li><code>{@link android.view.View.OnKeyListener#onKey(View,int,KeyEvent) onKey()}</code> -
    -+    Ini mengembalikan boolean untuk menunjukkan apakah Anda telah menggunakan kejadian dan tidak boleh dibawa lebih jauh.
    -+    Yaitu, mengembalikan <em>benar</em> untuk menunjukkan apakah Anda telah menangani kejadian dan semestinya berhenti di sini;
    -+    mengembalikan <em>salah</em> jika Anda tidak menanganinya dan/atau kejadian semestinya berlanjut ke
    -+    on-key listener lainnya.</li>
    -+  <li><code>{@link android.view.View.OnTouchListener#onTouch(View,MotionEvent) onTouch()}</code> -
    -+    Ini mengembalikan boolean untuk menunjukkan apakah listener Anda telah menggunakan kejadian ini. Yang penting adalah
    -+kejadian ini bisa memiliki beberapa tindakan yang saling mengikuti. Jadi, jika Anda mengembalikan <em>salah</em>saat
    -+kejadian tindakan turun diterima, itu menunjukkan bahwa Anda belum menggunakan kejadian itu dan juga
    -+tidak tertarik dengan tindakan berikutnya dari kejadian ini. Karena itu, Anda tidak akan diminta untuk melakukan tindakan
    -+ lainnya dalam kejadian, seperti gerakan jari, atau kejadian tindakan naik yang akan terjadi.</li>
    -+</ul>
    -+
    -+<p>Ingatlah bahwa kejadian tombol fisik selalu disampaikan ke View yang sedang difokus. Kejadian ini dikirim mulai dari atas
    -+hierarki View, kemudian turun hingga tujuan yang sesuai. Jika View Anda (atau anak View Anda)
    -+saat ini sedang fokus, maka Anda dapat melihat kejadian berpindah melalui metode.<code>{@link android.view.View#dispatchKeyEvent(KeyEvent)
    -+dispatchKeyEvent()}</code> Sebagai pengganti untuk menangkap kejadian penting melalui View, Anda juga dapat menerima
    -+semua kejadian dalam Aktivitas Anda dengan <code>{@link android.app.Activity#onKeyDown(int,KeyEvent) onKeyDown()}</code>
    -+dan <code>{@link android.app.Activity#onKeyUp(int,KeyEvent) onKeyUp()}</code>.</p>
    -+
    -+<p>Selain itu, saat memikirkan tentang input teks aplikasi Anda, ingatlah bahwa banyak perangkat yang hanya memiliki
    -+metode input perangkat lunak. Metode seperti itu tidak harus berbasis tombol; sebagian mungkin menggunakan input suara, tulisan tangan, dan seterusnya. Meskipun
    -+metode input menyajikan antarmuka seperti keyboard, itu umumnya <strong>tidak</strong> memicu keluarga kejadian
    -+<code>{@link android.app.Activity#onKeyDown(int,KeyEvent) onKeyDown()}</code>. Anda sama sekali tidak boleh
    -+membangun UI yang mengharuskan penekanan tombol tertentu dikontrol kecuali jika Anda ingin membatasi aplikasi Anda pada perangkat yang memiliki
    -+keyboard fisik. Khususnya, jangan mengandalkan metode ini untuk memvalidasi input saat pengguna menekan tombol
    -+enter; melainkan, gunakan tindakan seperti {@link android.view.inputmethod.EditorInfo#IME_ACTION_DONE} untuk menandai
    -+metode input mengenai reaksi yang diharapkan aplikasi Anda, sehingga bisa mengubah UI-nya secara signifikan. Hindari anggapan
    -+tentang bagaimana metode input perangkat lunak seharusnya bekerja dan percayalah bahwa metode akan menyediakan teks yang sudah diformat bagi aplikasi Anda.</p>
    -+
    -+<p class="note"><strong>Catatan:</strong> Android akan memanggil event handler terlebih dahulu kemudian handler
    -+default yang sesuai dari definisi kelas. Karena itu, mengembalikan <em>benar</em> dari event listener ini akan menghentikan
    -+penyebaran kejadian ke event listener lain dan juga akan memblokir callback ke
    -+event handler default di View. Pastikan bahwa Anda ingin mengakhiri kejadian saat mengembalikan <em>true</em>.</p>
    -+
    -+
    -+<h2 id="EventHandlers">Event Handler</h2>
    -+
    -+<p>Jika Anda membuat komponen custom dari View, maka Anda dapat mendefinisikan penggunaan beberapa
    -+metode callback sebagai event handler default.
    -+Dalam dokumen tentang <a href="{@docRoot}guide/topics/ui/custom-components.html">Komponen
    -+Custom</a>, Anda akan melihat penggunaan beberapa callback umum untuk penanganan kejadian,
    -+termasuk:</p>
    -+<ul>
    -+  <li><code>{@link  android.view.View#onKeyDown}</code> - Dipanggil bila terjadi kejadian tombol baru.</li>
    -+  <li><code>{@link  android.view.View#onKeyUp}</code> - Dipanggil bila terjadi kejadian tombol naik.</li>
    -+  <li><code>{@link  android.view.View#onTrackballEvent}</code> - Dipanggil bila terjadi kejadian gerakan trackball.</li>
    -+  <li><code>{@link  android.view.View#onTouchEvent}</code> - Dipanggil bila terjadi kejadian gerakan layar sentuh.</li>
    -+  <li><code>{@link  android.view.View#onFocusChanged}</code> - Dipanggil bila View memperoleh atau kehilangan fokus.</li>
    -+</ul>
    -+<p>Ada beberapa metode lain yang harus Anda ketahui, yang bukan bagian dari kelas View,
    -+namun bisa berdampak langsung pada kemampuan Anda menangani kejadian. Jadi, saat mengelola kejadian yang lebih kompleks dalam
    -+layout, pertimbangkanlah metode-metode lain ini:</p>
    -+<ul>
    -+  <li><code>{@link  android.app.Activity#dispatchTouchEvent(MotionEvent)
    -+    Activity.dispatchTouchEvent(MotionEvent)}</code> - Ini memungkinkan {@link
    -+    android.app.Activity} Anda mencegat semua kejadian sentuh sebelum dikirim ke jendela.</li>
    -+  <li><code>{@link  android.view.ViewGroup#onInterceptTouchEvent(MotionEvent)
    -+    ViewGroup.onInterceptTouchEvent(MotionEvent)}</code> - Ini memungkinkan {@link
    -+    android.view.ViewGroup} memantau kejadian saat dikirim ke View anak.</li>
    -+  <li><code>{@link  android.view.ViewParent#requestDisallowInterceptTouchEvent(boolean)
    -+    ViewParent.requestDisallowInterceptTouchEvent(boolean)}</code> - Panggil ini
    -+    pada View induk untuk menunjukan larangan mencegat kejadian sentuh dengan <code>{@link
    -+    android.view.ViewGroup#onInterceptTouchEvent(MotionEvent)}</code>.</li>
    -+</ul>
    -+
    -+<h2 id="TouchMode">Mode Sentuh</h2>
    -+<p>
    -+Saat pengguna menyusuri antarmuka pengguna dengan tombol pengarah atau trackball, Anda
    -+perlu memberikan fokus pada item tindakan (seperti tombol) agar pengguna bisa mengetahui apa
    -+yang akan menerima input.  Akan tetapi jika perangkat memiliki kemampuan sentuh, dan pengguna
    -+mulai berinteraksi dengan antarmuka dengan menyentuhnya, maka Anda tidak perlu lagi
    -+menyorot item, atau memfokuskan pada View tertentu.  Karena itu, ada mode
    -+untuk interaksi yang bernama "mode sentuh".
    -+</p>
    -+<p>
    -+Untuk perangkat berkemampuan sentuh, setelah pengguna menyentuh layar, perangkat
    -+akan masuk ke mode sentuh.  Dari sini dan selanjutnya, hanya View dengan
    -+{@link android.view.View#isFocusableInTouchMode} benar yang akan dapat difokus, seperti widget pengedit teks.
    -+View lain yang dapat disentuh, seperti tombol, tidak akan difokus bila disentuh; View ini akan
    -+langsung memicu on-click listener bila ditekan.
    -+</p>
    -+<p>
    -+Kapan saja pengguna menekan tombol pengarah atau menggulir dengan trackball, perangkat akan
    -+keluar dari mode sentuh, dan mencari tampilan untuk difokuskan. Kini pengguna bisa melanjutkan interaksi
    -+dengan antarmuka pengguna tanpa menyentuh layar.
    -+</p>
    -+<p>
    -+Status mode sentuh dipertahankan di seluruh sistem (semua jendela dan aktivitas).
    -+Untuk query status saat ini, Anda bisa memanggil
    -+{@link android.view.View#isInTouchMode} untuk mengetahui apakah perangkat saat ini sedang dalam mode sentuh.
    -+</p>
    -+
    -+
    -+<h2 id="HandlingFocus">Menangani Fokus</h2>
    -+
    -+<p>Kerangka kerja ini akan menangani gerakan fokus rutin sebagai respons input pengguna.
    -+Ini termasuk mengubah fokus saat View dihapus atau disembunyikan, atau saat tersedia View
    -+baru. View menunjukkan kesediaannya untuk mengambil fokus
    -+melalui metode <code>{@link android.view.View#isFocusable()}</code>. Untuk mengubah apakah View bisa mengambil
    -+fokus, panggil <code>{@link android.view.View#setFocusable(boolean) setFocusable()}</code>.  Saat dalam mode sentuh,
    -+Anda dapat me-query apakah View memungkinkan fokus dengan <code>{@link android.view.View#isFocusableInTouchMode()}</code>.
    -+Anda bisa mengubahnya dengan <code>{@link android.view.View#setFocusableInTouchMode(boolean) setFocusableInTouchMode()}</code>.
    -+</p>
    -+
    -+<p>Gerakan fokus berdasarkan pada algoritma yang mencari tetangga terdekat dalam
    -+arah yang diberikan. Dalam kasus yang jarang terjadi, algoritma default mungkin
    -+tidak cocok dengan perilaku yang diinginkan pengembang. Dalam situasi ini, Anda bisa memberikan
    -+pengesampingan eksplisit dengan mengikuti atribut XML berikut dalam file layout:
    -+<var>nextFocusDown</var>, <var>nextFocusLeft</var>, <var>nextFocusRight</var>, dan
    -+<var>nextFocusUp</var>. Tambahkan salah satu atribut ini ke View <em>dari</em> mana fokus
    -+meninggalkan. Definisikan nilai atribut untuk menjadi ID View
    -+<em>ke</em> mana fokus harus diberikan. Misalnya:</p>
    -+<pre>
    -+&lt;LinearLayout
    -+    android:orientation="vertical"
    -+    ... >
    -+  &lt;Button android:id="@+id/top"
    -+          android:nextFocusUp="@+id/bottom"
    -+          ... />
    -+  &lt;Button android:id="@+id/bottom"
    -+          android:nextFocusDown="@+id/top"
    -+          ... />
    -+&lt;/LinearLayout>
    -+</pre>
    -+
    -+<p>Biasanya, dalam layout vertikal ini, navigasi ke atas dari Button pertama tidak akan membawa ke
    -+mana pun, tidak pula akan menyusuri ke bawah dari Button kedua. Karena sekarang Button atas telah
    -+mendefinisikan Button bawah sebagai <var>nextFocusUp</var> (dan sebaliknya), fokus navigasi akan
    -+silih berganti dari atas ke bawah dan bawah ke atas.</p>
    -+
    -+<p>Jika Anda ingin mendeklarasikan View sebagai dapat difokus dalam UI (bila biasanya tidak dapat difokus),
    -+tambahkan atribut XML <code>android:focusable</code> ke View, dalam deklarasi layout Anda.
    -+Atur nilai <var>true</var>. Anda juga bisa mendeklarasikan View
    -+sebagai dapat difokus saat dalam Mode Sentuh dengan <code>android:focusableInTouchMode</code>.</p>
    -+<p>Untuk meminta View tertentu difokus, panggil <code>{@link android.view.View#requestFocus()}</code>.</p>
    -+<p>Untuk mendengarkan kejadian fokus (diberi tahu bila View menerima atau kehilangan fokus), gunakan
    -+<code>{@link android.view.View.OnFocusChangeListener#onFocusChange(View,boolean) onFocusChange()}</code>
    -+, seperti yang dibahas di bagian <a href="#EventListeners">Event Listener</a>, di atas.</p>
    -+
    -+
    -+
    -+<!--
    -+<h2 is="EventCycle">Event Cycle</h2>
    -+   <p>The basic cycle of a View is as follows:</p>
    -+   <ol>
    -+    <li>An event comes in and is dispatched to the appropriate View. The View
    -+    handles the event and notifies any listeners.</li>
    -+    <li>If, in the course of processing the event, the View's bounds may need
    -+    to be changed, the View will call {@link android.view.View#requestLayout()}.</li>
    -+    <li>Similarly, if in the course of processing the event the View's appearance
    -+    may need to be changed, the View will call {@link android.view.View#invalidate()}.</li>
    -+    <li>If either {@link android.view.View#requestLayout()} or {@link android.view.View#invalidate()} were called,
    -+    the framework will take care of measuring, laying out, and drawing the tree
    -+    as appropriate.</li>
    -+   </ol>
    -+
    -+   <p class="note"><strong>Note:</strong> The entire View tree is single threaded. You must always be on
    -+   the UI thread when calling any method on any View.
    -+   If you are doing work on other threads and want to update the state of a View
    -+   from that thread, you should use a {@link android.os.Handler}.
    -+   </p>
    -+-->
    -diff --git a/docs/html-intl/intl/id/training/articles/direct-boot.jd b/docs/html-intl/intl/id/training/articles/direct-boot.jd
    -new file mode 100644
    -index 0000000..a7e3cf3
    ---- /dev/null
    -+++ b/docs/html-intl/intl/id/training/articles/direct-boot.jd
    -@@ -0,0 +1,181 @@
    -+page.title=Direct Boot
    -+page.keywords=pratinjau,sdk,direct boot
    -+page.tags=androidn
    -+page.image=images/cards/card-nyc_2x.jpg
    -+
    -+@jd:body
    -+
    -+<div id="tb-wrapper">
    -+<div id="tb">
    -+  <h2>Dalam dokumen ini</h2>
    -+  <ol>
    -+    <li><a href="#run">Meminta Akses untuk Berjalan Selama Direct Boot</a></li>
    -+    <li><a href="#access">Mengakses Penyimpanan yang Dienkripsi dengan Perangkat</a></li>
    -+    <li><a href="#notification">Mendapatkan Pemberitahuan saat Pengguna Membuka Kunci</a></li>
    -+    <li><a href="#migrating">Migrasi Data yang Ada</a></li>
    -+    <li><a href="#testing">Menguji Aplikasi Peka Enkripsi Anda</a></li>
    -+  </ol>
    -+</div>
    -+</div>
    -+
    -+<p>Android N berjalan dalam mode <i>Direct Boot</i> yang aman
    -+bila perangkat telah dihidupkan namun pengguna tidak membuka
    -+kunci perangkat. Untuk mendukung hal ini, sistem menyediakan dua lokasi penyimpanan untuk data:</p>
    -+
    -+<ul>
    -+<li><i>Penyimpanan yang dienkripsi dengan kredensial</i>, yang merupakan lokasi penyimpanan default
    -+dan hanya tersedia setelah pengguna membuka kunci perangkat.</li>
    -+<li><i>Penyimpanan yang dienkripsi dengan perangkat</i>, yang merupakan lokasi penyimpanan yang tersedia
    -+selama mode Direct Boot dan setelah pengguna membuka kunci perangkat.</li>
    -+</ul>
    -+
    -+<p>Secara default, aplikasi tidak berjalan selama mode Direct Boot.
    -+Jika aplikasi Anda perlu melakukan tindakan selama mode Direct Boot, Anda bisa mendaftarkan
    -+komponen aplikasi yang harus dijalankan selama mode ini. Beberapa kasus penggunaan umum
    -+untuk aplikasi yang perlu dijalankan selama mode Direct Boot antara lain:</p>
    -+
    -+<ul>
    -+<li>Aplikasi yang telah menjadwalkan pemberitahuan, seperti aplikasi
    -+beker.</li>
    -+<li>Aplikasi yang menyediakan pemberitahuan pengguna yang penting, seperti aplikasi SMS.</li>
    -+<li>Aplikasi yang menyediakan layanan aksesibilitas, seperti TalkBack.</li>
    -+</ul>
    -+
    -+<p>Jika aplikasi Anda perlu mengakses data saat dijalankan dalam mode Direct Boot, gunakan
    -+penyimpanan yang dienkripsi dengan perangkat. Penyimpanan yang dienkripsi dengan perangkat berisi data
    -+yang dienkripsi dengan kunci yang hanya tersedia setelah perangkat melakukan
    -+booting yang berhasil diverifikasi.</p>
    -+
    -+<p>Untuk data yang harus dienkripsi dengan kunci yang dikaitkan dengan kredensial
    -+pengguna, seperti PIN atau kata sandi, gunakan penyimpanan yang dienkripsi dengan kredensial.
    -+Penyimpanan yang dienkripsi dengan kredensial hanya tersedia setelah pengguna berhasil
    -+membuka kunci perangkat, hingga saat pengguna menghidupkan ulang perangkat lagi. Jika
    -+pengguna mengaktifkan layar kunci setelah membuka kunci perangkat, hal ini tidak akan mengunci
    -+penyimpanan yang dienkripsi dengan kredensial.</p>
    -+
    -+<h2 id="run">Meminta Akses untuk Berjalan Selama Direct Boot</h2>
    -+
    -+<p>Aplikasi harus mendaftarkan komponennya pada sistem agar
    -+bisa berjalan selama mode Direct Boot atau mengakses
    -+penyimpanan yang dienkripsi dengan perangkat. Aplikasi mendaftar pada sistem dengan menandai komponen sebagai
    -+<i>peka enkripsi</i>. Untuk menandai komponen Anda sebagai peka enkripsi, setel atribut
    -+<code>android:directBootAware</code> ke true dalam manifes Anda.<p>
    -+
    -+<p>Komponen yang peka enkripsi bisa mendaftar untuk menerima pesan siaran
    -+<code>LOCKED_BOOT_COMPLETED</code> dari
    -+sistem bila perangkat telah dihidupkan ulang. Pada tahap ini
    -+penyimpanan yang dienkripsi dengan perangkat akan tersedia, dan komponen Anda bisa mengeksekusi tugas-tugas yang perlu
    -+dijalankan selama mode Direct Boot, seperti memicu alarm yang terjadwal.</p>
    -+
    -+<p>Cuplikan kode berikut adalah contoh cara mendaftarkan
    -+{@link android.content.BroadcastReceiver} sebagai peka enkripsi, dan menambahkan sebuah
    -+filter intent untuk <code>LOCKED_BOOT_COMPLETED</code>, dalam manifes aplikasi:</p>
    -+
    -+<pre>
    -+&lt;receiver
    -+  android:directBootAware="true" &gt;
    -+  ...
    -+  &lt;intent-filter&gt;
    -+    &lt;action android:name="android.intent.action.LOCKED_BOOT_COMPLETED" /&gt;
    -+  &lt;/intent-filter&gt;
    -+&lt;/receiver&gt;
    -+</pre>
    -+
    -+<p>Setelah pengguna membuka kunci perangkat, semua komponen bisa mengakses
    -+penyimpanan yang dienkripsi dengan perangkat serta penyimpanan yang dienkripsi dengan kredensial.</p>
    -+
    -+<h2 id="access">Mengakses Penyimpanan yang Dienkripsi dengan Perangkat</h2>
    -+
    -+<p>Untuk mengakses penyimpanan yang dienkripsi dengan perangkat, buat instance
    -+{@link android.content.Context} kedua dengan memanggil
    -+<code>Context.createDeviceProtectedStorageContext()</code>. Semua panggilan
    -+API penyimpanan yang dibuat menggunakan konteks ini mengakses penyimpanan yang dienkripsi dengan perangkat. Contoh
    -+berikut mengakses penyimpanan yang dienkripsi dengan perangkat dan membuka file data aplikasi
    -+yang ada:</p>
    -+
    -+<pre>
    -+Context directBootContext = appContext.createDeviceProtectedStorageContext();
    -+// Access appDataFilename that lives in device encrypted storage
    -+FileInputStream inStream = directBootContext.openFileInput(appDataFilename);
    -+// Use inStream to read content...
    -+</pre>
    -+
    -+<p>Gunakan penyimpanan yang dienkripsi dengan perangkat hanya untuk
    -+informasi yang harus bisa diakses selama mode Direct Boot.
    -+Jangan gunakan penyimpanan yang dienkripsi dengan perangkat sebagai penyimpanan terenkripsi serba guna.
    -+Untuk informasi pengguna yang bersifat pribadi, atau data terenkripsi yang tidak diperlukan selama
    -+mode Direct Boot, gunakan penyimpanan yang dienkripsi dengan kredensial.</p>
    -+
    -+<h2 id="notification">Mendapatkan Pemberitahuan saat Pengguna Membuka Kunci</h2>
    -+
    -+<p>Setelah pengguna membuka kunci perangkat setelah restart, aplikasi Anda bisa beralih untuk
    -+mengakses penyimpanan yang dienkripsi dengan kredensial dan menggunakan layanan sistem biasa yang
    -+bergantung pada kredensial pengguna.</p>
    -+
    -+<p>Agar diberi tahu bila pengguna membuka kunci perangkat setelah boot ulang,
    -+daftarkan {@link android.content.BroadcastReceiver} dari komponen yang berjalan
    -+untuk mendengarkan pesan <code>ACTION_USER_UNLOCKED</code>. Atau, Anda bisa
    -+menerima pesan {@link android.content.Intent#ACTION_BOOT_COMPLETED
    -+ACTION_BOOT_COMPLETED} yang ada, yang sekarang menunjukkan bahwa perangkat telah dihidupkan dan
    -+pengguna telah membuka kunci perangkat.</p>
    -+
    -+<p>Anda bisa langsung kueri apakah pengguna telah membuka kunci perangkat dengan memanggil
    -+<code>UserManager.isUserUnlocked()</code>.</p>
    -+
    -+<h2 id="migrating">Migrasi Data yang Ada</h2>
    -+
    -+<p>Jika pengguna memperbarui perangkat mereka untuk menggunakan mode Direct Boot,
    -+data Anda yang ada mungkin perlu dipindahkan ke penyimpanan yang dienkripsi dengan perangkat. Gunakan
    -+<code>Context.moveSharedPreferencesFrom()</code> dan
    -+<code>Context.moveDatabaseFrom()</code> untuk memindahkan data preferensi dan
    -+basis data antara penyimpanan yang dienkripsi dengan kredensial dan penyimpanan yang dienkripsi dengan perangkat.</p>
    -+
    -+<p>Pertimbangkan dengan baik saat memutuskan data apa yang akan dipindahkan dari
    -+penyimpanan yang dienkripsi dengan kredensial ke penyimpanan yang dienkripsi dengan perangkat. Anda sebaiknya tidak memindahkan
    -+informasi pengguna yang bersifat rahasia, seperti kata sandi atau token otorisasi, ke
    -+penyimpanan yang dienkripsi dengan perangkat. Dalam beberapa skenario, Anda mungkin perlu mengelola
    -+set data terpisah pada dua tempat penyimpanan yang dienkripsi.</p>
    -+
    -+<h2 id="testing">Menguji Aplikasi Peka Enkripsi Anda</h2>
    -+
    -+<p>Uji aplikasi peka enkripsi Anda menggunakan mode Direct Boot baru. Ada
    -+dua cara untuk mengaktifkan Direct Boot.</p>
    -+
    -+<p class="caution"><strong>Perhatian:</strong> Mengaktifkan Direct Boot
    -+akan menghapus semua data pengguna pada perangkat.</p>
    -+
    -+<p>Pada perangkat yang didukung dengan Android N terpasang, aktifkan
    -+Direct Boot dengan melakukan salah satu hal berikut:</p>
    -+
    -+<ul>
    -+<li>Pada perangkat, aktifkan <b>Developer options</b> jika Anda belum melakukannya dengan
    -+masuk ke <b>Settings &gt; About phone</b>, dan menyentuh <b>Build number</b>
    -+tujuh kali. Setelah layar Developer options terbuka, masuk ke
    -+<b>Settings &gt; Developer options</b> dan pilih
    -+<b>Convert to file encryption</b>.</li>
    -+<li>Gunakan perintah shell adb berikut untuk mengaktifkan mode Direct Boot:
    -+<pre class="no-pretty-print">
    -+$ adb reboot-bootloader
    -+$ fastboot --wipe-and-use-fbe
    -+</pre>
    -+</li>
    -+</ul>
    -+
    -+<p>Mode emulasi Direct Boot juga tersedia, jika Anda perlu mengganti
    -+mode pada perangkat pengujian. Mode emulasi sebaiknya hanya digunakan selama
    -+pengembangan dan bisa menyebabkan kehilangan data. Untuk mengaktifkan mode emulasi Direct Boot,
    -+setel pola kunci pada perangkat, pilih "No thanks" jika ditanya mengenai
    -+layar start-up aman saat menetapkan pola kunci, kemudian gunakan
    -+perintah shell adb berikut:</p>
    -+
    -+<pre class="no-pretty-print">
    -+$ adb shell sm set-emulate-fbe true
    -+</pre>
    -+
    -+<p>Untuk menonaktifkan mode emulasi Direct Boot, gunakan perintah berikut:</p>
    -+
    -+<pre class="no-pretty-print">
    -+$ adb shell sm set-emulate-fbe false
    -+</pre>
    -+
    -+<p>Menggunakan perintah ini akan menyebabkan perangkat melakukan boot ulang.</p>
    -diff --git a/docs/html-intl/intl/id/training/articles/scoped-directory-access.jd b/docs/html-intl/intl/id/training/articles/scoped-directory-access.jd
    -new file mode 100644
    -index 0000000..30aed6f
    ---- /dev/null
    -+++ b/docs/html-intl/intl/id/training/articles/scoped-directory-access.jd
    -@@ -0,0 +1,148 @@
    -+page.title=Scoped Directory Access
    -+page.keywords=pratinjau,sdk,scoped directory access
    -+page.tags=androidn
    -+
    -+@jd:body
    -+
    -+<div id="tb-wrapper">
    -+<div id="tb">
    -+  <h2>Dalam dokumen ini</h2>
    -+  <ol>
    -+    <li><a href="#accessing">Mengakses Direktori Penyimpanan Eksternal</a></li>
    -+    <li><a href="#removable">Mengakses Direktori pada Media Lepas-Pasang</a></li>
    -+    <li><a href="#best">Praktik Terbaik</a></li>
    -+  </ol>
    -+</div>
    -+</div>
    -+
    -+<p>Aplikasi seperti aplikasi foto biasanya hanya memerlukan akses ke direktori tertentu dalam
    -+penyimpanan eksternal, seperti direktori <code>Pictures</code>. Pendekatan
    -+yang ada dalam mengakses penyimpanan eksternal tidak didesain untuk memberi kemudahan
    -+akses direktori tertarget untuk tipe aplikasi ini. Misalnya:</p>
    -+
    -+<ul>
    -+<li>Meminta {@link android.Manifest.permission#READ_EXTERNAL_STORAGE}
    -+atau {@link android.Manifest.permission#WRITE_EXTERNAL_STORAGE} dalam manifes Anda
    -+akan memungkinkan akses ke semua direktori publik pada penyimpanan eksternal, yang mungkin
    -+lebih banyak akses dari yang dibutuhkan aplikasi Anda.</li>
    -+<li>Menggunakan
    -+<a href="{@docRoot}guide/topics/providers/document-provider.html">Storage
    -+Access Framework</a> biasanya membuat pengguna Anda memilih direktori
    -+melalui UI sistem, yang tidak diperlukan jika aplikasi Anda selalu mengakses
    -+direktori eksternal yang sama.</li>
    -+</ul>
    -+
    -+<p>Android N menyediakan API baru yang disederhanakan untuk mengakses
    -+direktori penyimpanan eksternal umum. </p>
    -+
    -+<h2 id="accessing">Mengakses Direktori Penyimpanan Eksternal</h2>
    -+
    -+<p>Gunakan kelas <code>StorageManager</code> untuk mendapatkan instance
    -+<code>StorageVolume</code> yang tepat. Kemudian, buat intent dengan memanggil metode
    -+<code>StorageVolume.createAccessIntent()</code> dari instance itu.
    -+Gunakan intent ini untuk mengakses direktori penyimpanan eksternal. Untuk mendapatkan daftar
    -+semua volume yang tersedia, termasuk volume media lepas-pasang, gunakan
    -+<code>StorageManager.getVolumesList()</code>.</p>
    -+
    -+<p>Jika Anda memiliki informasi tentang file spesifik, gunakan
    -+<code>StorageManager.getStorageVolume(File)</code> untuk mendapatkan
    -+<code>StorageVolume</code> yang berisi file tersebut. Panggil
    -+<code>createAccessIntent()</code> pada <code>StorageVolume</code> ini untuk mengakses
    -+direktori penyimpanan eksternal untuk file tersebut.</p>
    -+
    -+<p>
    -+Di volume kedua, seperti kartu SD eksternal, teruskan null saat memanggil
    -+<code>StorageVolume.createAccessIntent()</code> untuk meminta akses ke seluruh
    -+volume, sebagai ganti direktori spesifik.
    -+<code>StorageVolume.createAccessIntent()</code> akan mengembalikan null jika Anda meneruskan
    -+null ke volume utama, atau jika Anda meneruskan nama direktori yang tidak valid.
    -+</p>
    -+
    -+<p>Cuplikan kode berikut adalah contoh cara membuka direktori
    -+<code>Pictures</code> dalam penyimpanan bersama utama:</p>
    -+
    -+<pre>
    -+StorageManager sm = (StorageManager)getSystemService(Context.STORAGE_SERVICE);
    -+StorageVolume volume = sm.getPrimaryVolume();
    -+Intent intent = volume.createAccessIntent(Environment.DIRECTORY_PICTURES);
    -+startActivityForResult(intent, request_code);
    -+</pre>
    -+
    -+<p>Sistem ini mencoba untuk memberikan akses ke direktori eksternal, dan jika
    -+diperlukan mengonfirmasi akses dengan pengguna menggunakan UI yang disederhanakan:</p>
    -+
    -+<img src="{@docRoot}images/android-7.0/scoped-directory-access-framed.png" srcset="{@docRoot}images/android-7.0/scoped-directory-access-framed.png 1x,
    -+{@docRoot}images/android-7.0/scoped-directory-access-framed_2x.png 2x" />
    -+<p class="img-caption"><strong>Gambar 1.</strong> Sebuah aplikasi yang meminta
    -+akses ke direktori Pictures.</p>
    -+
    -+<p>Jika pengguna memberi akses, sistem akan memanggil penggantian
    -+<code>onActivityResult()</code> Anda dengan kode hasil
    -+<code>Activity.RESULT_OK</code>, dan data intent yang berisi URI. Gunakan
    -+URI yang disediakan untuk mengakses informasi direktori, serupa dengan menggunakan URI
    -+yang dikembalikan oleh
    -+<a href="{@docRoot}guide/topics/providers/document-provider.html">Storage
    -+Access Framework</a>.</p>
    -+
    -+<p>Jika pengguna tidak memberi akses, sistem akan memanggil penggantian
    -+<code>onActivityResult()</code> Anda dengan kode hasil
    -+<code>Activity.RESULT_CANCELED</code>, dan data intent nol.</p>
    -+
    -+<p class="note"><b>Catatan</b>: Mendapatkan akses ke direktori eksternal tertentu
    -+juga akan memperoleh akses ke subdirektori dalam direktori tersebut.</p>
    -+
    -+<h2 id="removable">Mengakses Direktori pada Media Lepas-Pasang</h2>
    -+
    -+<p>Untuk menggunakan Scoped Directory Access guna mengakses direktori pada media lepas-pasang,
    -+pertama tambahkan {@link android.content.BroadcastReceiver} yang akan mendengarkan pemberitahuan
    -+{@link android.os.Environment#MEDIA_MOUNTED}, misalnya:</p>
    -+
    -+<pre>
    -+&lt;receiver
    -+    android:name=".MediaMountedReceiver"
    -+    android:enabled="true"
    -+    android:exported="true" &gt;
    -+    &lt;intent-filter&gt;
    -+        &lt;action android:name="android.intent.action.MEDIA_MOUNTED" /&gt;
    -+        &lt;data android:scheme="file" /&gt;
    -+    &lt;/intent-filter&gt;
    -+&lt;/receiver&gt;
    -+</pre>
    -+
    -+<p>Bila pengguna memasang media lepas-pasang, seperti kartu SD, sistem akan mengirimkan pemberitahuan
    -+{@link android.os.Environment#MEDIA_MOUNTED}. Pemberitahuan ini
    -+memberikan sebuah objek <code>StorageVolume</code> dalam data intent yang bisa
    -+Anda gunakan untuk mengakses direktori pada media lepas-pasang. Contoh berikut
    -+mengakses direktori <code>Pictures</code> pada media lepas-pasang:</p>
    -+
    -+<pre>
    -+// BroadcastReceiver has already cached the MEDIA_MOUNTED
    -+// notification Intent in mediaMountedIntent
    -+StorageVolume volume = (StorageVolume)
    -+    mediaMountedIntent.getParcelableExtra(StorageVolume.EXTRA_STORAGE_VOLUME);
    -+volume.createAccessIntent(Environment.DIRECTORY_PICTURES);
    -+startActivityForResult(intent, request_code);
    -+</pre>
    -+
    -+<h2 id="best">Praktik Terbaik</h2>
    -+
    -+<p>Bila memungkinkan, pertahankan URI akses direktori eksternal sehingga Anda tidak perlu
    -+berulang kali meminta akses ke pengguna. Setelah pengguna memberikan akses, panggil
    -+<code>getContentResolver().takePersistableUriPermssion()</code> bersama
    -+URI akses direktori. Sistem akan mempertahankan URI dan permintaan
    -+akses berikutnya akan mengembalikan <code>RESULT_OK</code> dan tidak menampilkan UI konfirmasi kepada
    -+pengguna.</p>
    -+
    -+<p>Jika pengguna menolak akses ke direktori eksternal, jangan langsung
    -+meminta akses lagi. Berulang kali meminta akses akan menghasilkan pengalaman
    -+pengguna yang buruk. Jika permintaan ditolak oleh pengguna, dan aplikasi meminta akses
    -+lagi, UI akan menampilkan kotak centang <b>Don't ask again</b>:</p>
    -+
    -+<img src="{@docRoot}images/android-7.0/scoped-directory-access-dont-ask.png" srcset="{@docRoot}images/android-7.0/scoped-directory-access-dont-ask.png 1x,
    -+{@docRoot}images/android-7.0/scoped-directory-access-dont-ask_2x.png 2x" />
    -+<p class="img-caption"><strong>Gambar 1.</strong> Sebuah aplikasi membuat
    -+permintaan kedua untuk mengakses media lepas-pasang.</p>
    -+
    -+<p>Jika pengguna memilih <b>Don't ask again</b> dan menolak permintaan,
    -+semua permintaan berikutnya untuk direktori yang diberikan dari aplikasi
    -+Anda secara otomatis akan ditolak, dan tidak ada UI permintaan yang akan ditampilkan ke pengguna.</p>
    -\ No newline at end of file
    -diff --git a/docs/html-intl/intl/id/training/articles/security-config.jd b/docs/html-intl/intl/id/training/articles/security-config.jd
    -new file mode 100644
    -index 0000000..e13429d
    ---- /dev/null
    -+++ b/docs/html-intl/intl/id/training/articles/security-config.jd
    -@@ -0,0 +1,747 @@
    -+page.title=Konfigurasi Keamanan Jaringan
    -+page.keywords=androidn,keamanan,jaringan
    -+page.image=images/cards/card-nyc_2x.jpg
    -+
    -+@jd:body
    -+
    -+<div id="tb-wrapper">
    -+<div id="tb">
    -+
    -+<h2>Dalam dokumen ini</h2>
    -+<ol>
    -+  <li><a href="#manifest">Menambahkan File Konfigurasi Keamanan</a></li>
    -+  <li><a href="#CustomTrust">Menyesuaikan CA Tepercaya</a>
    -+      <ol>
    -+      <li><a href="#ConfigCustom">Mengonfigurasi CA Tepercaya Khusus</a></li>
    -+      <li><a href="#LimitingCas">Membatasi Set CA Tepercaya</a></li>
    -+      <li><a href="#TrustingAdditionalCas">Mempercayai CA Tambahan</a></li>
    -+      </ol>
    -+  </li>
    -+  <li><a href="#TrustingDebugCa">CA Debug Saja</a></li>
    -+  <li><a href="#UsesCleartextTraffic">Berhenti dari Lalu Lintas Cleartext</a></li>
    -+  <li><a href="#CertificatePinning">Menyematkan Sertifikat</a></li>
    -+  <li><a href="#ConfigInheritance">Perilaku Pewarisan Konfigurasi</a></li>
    -+  <li><a href="#FileFormat">Format File Konfigurasi</a></li>
    -+</ol>
    -+</div>
    -+</div>
    -+
    -+
    -+<p>
    -+  Android N menyertakan fitur
    -+  Network Security Configuration yang memungkinkan aplikasi menyesuaikan setelan keamanan jaringan mereka dalam
    -+  file konfigurasi deklaratif yang aman tanpa memodifikasi kode aplikasi. Setelan ini bisa
    -+  dikonfigurasi untuk domain dan aplikasi tertentu. Kemampuan
    -+  utama fitur ini adalah sebagai berikut:
    -+</p>
    -+
    -+<ul>
    -+  <li>
    -+    <b>Trust-anchor khusus:</b> Menyesuaikan Certificate Authorities (CA) mana
    -+    yang dipercaya untuk koneksi aman aplikasi. Misalnya,
    -+    mempercayai sertifikat tertentu yang ditandatangani sendiri atau membatasi
    -+    set CA umum yang dipercaya aplikasi.
    -+  </li>
    -+
    -+  <li>
    -+    <b>Penggantian hanya-debug:</b> Men-debug secara aman koneksi aman dalam aplikasi
    -+    tanpa menambahkan risiko pada basis yang telah dipasang.
    -+  </li>
    -+
    -+  <li>
    -+    <b>Berhenti dari lalu lintas cleartext:</b> Melindungi aplikasi dari
    -+    penggunaan lalu lintas cleartext secara tidak sengaja.
    -+  </li>
    -+
    -+  <li>
    -+    <b>Penyematan sertifikat:</b> Membatasi koneksi aman aplikasi ke
    -+    sertifikat tertentu.
    -+  </li>
    -+</ul>
    -+
    -+
    -+<h2 id="manifest">Menambahkan File Konfigurasi Keamanan</h2>
    -+
    -+<p>
    -+  Fitur Network Security Configuration menggunakan file XML tempat Anda menetapkan
    -+  setelan untuk aplikasi. Anda harus menyertakan sebuah entri dalam manifes aplikasi
    -+  untuk menunjuk ke file ini. Kutipan kode berikut dari sebuah manifes
    -+  yang memperagakan cara membuat entri ini:
    -+</p>
    -+
    -+<pre>
    -+&lt;?xml version="1.0" encoding="utf-8"?&gt;
    -+&lt;manifest ... &gt;
    -+  &lt;application ... &gt;
    -+    &lt;meta-data android:name="android.security.net.config"
    -+               android:resource="@xml/network_security_config" /&gt;
    -+    ...
    -+  &lt;/application&gt;
    -+&lt;/manifest&gt;
    -+</pre>
    -+
    -+<h2 id="CustomTrust">Menyesuaikan CA Tepercaya</h2>
    -+
    -+<p>
    -+  Aplikasi mungkin perlu mempercayai set CA khusus sebagai ganti default
    -+  platform. Alasannya yang paling umum adalah:
    -+</p>
    -+
    -+<ul>
    -+  <li>Menghubungkan ke host dengan otoritas sertifikat khusus (ditandatangani sendiri,
    -+  dikeluarkan oleh CA internal, dll).
    -+  </li>
    -+
    -+  <li>Membatasi set CA hanya untuk CA yang Anda percaya sebagai ganti setiap CA
    -+  yang sudah terpasang.
    -+  </li>
    -+
    -+  <li>Mempercayai CA tambahan yang tidak disertakan dalam sistem.
    -+  </li>
    -+</ul>
    -+
    -+<p>
    -+  Secara default koneksi (mis. TLS, HTTPS) aman dari semua aplikasi mempercayai
    -+  CA yang telah dipasang oleh sistem, dan aplikasi yang menargetkan API level 23
    -+  (Android M) ke bawah, juga mempercayai penyimpanan CA yang ditambahkan pengguna secara default. Aplikasi
    -+  bisa menyesuaikan koneksinya menggunakan {@code base-config} (untuk
    -+  penyesuaian lebar-aplikasi) atau {@code domain-config} (untuk penyesuaian
    -+  per-domain).
    -+</p>
    -+
    -+
    -+<h3 id="ConfigCustom">Mengonfigurasi CA Khusus</h3>
    -+
    -+<p>
    -+  Anggaplah Anda ingin menghubungkan ke host Anda yang menggunakan sertifikat
    -+  SSL yang ditandatangani sendiri atau ke host yang sertifikat SSL-nya dikeluarkan oleh CA non-publik
    -+  yang Anda percaya, seperti CA internal perusahaan Anda.
    -+</p>
    -+
    -+<p>
    -+  <code>res/xml/network_security_config.xml</code>:
    -+<pre>
    -+&lt;?xml version="1.0" encoding="utf-8"?&gt;
    -+&lt;network-security-config&gt;
    -+    &lt;domain-config&gt;
    -+        &lt;domain includeSubdomains="true"&gt;example.com&lt;/domain&gt;
    -+        &lt;trust-anchors&gt;
    -+            &lt;certificates src="@raw/my_ca"/&gt;
    -+        &lt;/trust-anchors&gt;
    -+    &lt;/domain-config&gt;
    -+&lt;/network-security-config&gt;
    -+</pre>
    -+</p>
    -+
    -+<p>
    -+  Menambahkan sertifikat CA yang ditandatangani sendiri atau sertifikat CA non-publik, dalam format PEM atau DER, ke
    -+  {@code res/raw/my_ca}.
    -+</p>
    -+
    -+
    -+<h3 id="LimitingCas">Membatasi Set CA Tepercaya</h3>
    -+
    -+<p>
    -+  Aplikasi yang tidak ingin mempercayai semua CA yang dipercaya oleh sistem
    -+  sebagai gantinya bisa menetapkan set CA sendiri yang telah dikurangi untuk dipercaya. Ini akan melindungi
    -+  aplikasi dari sertifikat palsu yang dikeluarkan oleh selain CA.
    -+</p>
    -+
    -+<p>
    -+  Konfigurasi untuk membatasi set CA tepercaya mirip dengan <a href="#TrustingACustomCa">mempercayai CA khusus</a> untuk domain tertentu selain
    -+  beberapa CA disediakan dalam sumber daya.
    -+</p>
    -+
    -+<p>
    -+<code>res/xml/network_security_config.xml</code>:
    -+<pre>
    -+&lt;?xml version="1.0" encoding="utf-8"?&gt;
    -+&lt;network-security-config&gt;
    -+    &lt;domain-config&gt;
    -+        &lt;domain includeSubdomains="true"&gt;secure.example.com&lt;/domain&gt;
    -+        &lt;domain includeSubdomains="true"&gt;cdn.example.com&lt;/domain&gt;
    -+        &lt;trust-anchors&gt;
    -+            &lt;certificates src="@raw/trusted_roots"/&gt;
    -+        &lt;/trust-anchors&gt;
    -+    &lt;/domain-config&gt;
    -+&lt;/network-security-config&gt;
    -+</pre>
    -+</p>
    -+
    -+<p>
    -+  Menambahkan CA tepercaya, dalam format PEM atau DER, ke {@code res/raw/trusted_roots}.
    -+  Perhatikan, jika menggunakan format PEM, file <em>hanya</em> boleh berisi data PEM
    -+  dan tidak ada teks tambahan. Anda juga bisa menyediakan beberapa elemen
    -+  <a href="#certificates"><code>&lt;certificates&gt;</code></a>
    -+sebagai ganti satu elemen.
    -+</p>
    -+
    -+
    -+<h3 id="TrustingAdditionalCas">
    -+  Mempercayai CA Tambahan
    -+</h3>
    -+
    -+<p>
    -+  Sebuah aplikasi mungkin perlu mempercayai CA tambahan yang tidak dipercaya oleh sistem,
    -+  hal ini bisa disebabkan karena sistem belum menyertakan CA atau CA tidak
    -+  memenuhi persyaratan untuk memasukkan ke dalam sistem Android. Aplikasi
    -+  bisa melakukannya dengan menetapkan beberapa sumber sertifikat untuk
    -+  konfigurasi.
    -+</p>
    -+<p>
    -+<code>res/xml/network_security_config.xml</code>:
    -+<pre>
    -+&lt;?xml version="1.0" encoding="utf-8"?&gt;
    -+&lt;network-security-config&gt;
    -+    &lt;base-config&gt;
    -+        &lt;trust-anchors&gt;
    -+            &lt;certificates src="@raw/extracas"/&gt;
    -+            &lt;certificates src="system"/&gt;
    -+        &lt;/trust-anchors&gt;
    -+    &lt;/base-config&gt;
    -+&lt;/network-security-config&gt;
    -+</pre>
    -+</p>
    -+
    -+
    -+<h2 id="TrustingDebugCa">Mengonfigurasi CA untuk Debug</h2>
    -+
    -+<p>
    -+  Saat men-debug aplikasi yang terhubung melalui HTTPS, Anda mungkin perlu
    -+  menghubungkan ke server pengembangan lokal, yang tidak memiliki sertifikat
    -+  SSL untuk server produksi Anda. Untuk mendukungnya tanpa
    -+  memodifikasi kode aplikasi, Anda bisa menetapkan CA hanya-debug
    -+  yang <i>hanya</i> dipercaya bila <a href="{@docRoot}guide/topics/manifest/application-element.html#debug">
    -+android:debuggable</a>
    -+  adalah {@code true} dengan menggunakan {@code debug-overrides}. Biasanya IDE dan alat
    -+  build menyetel flag ini secara otomatis untuk build non-rilis.
    -+</p>
    -+
    -+<p>
    -+  Ini lebih aman daripada kode kondisional biasa karena, sebagai tindakan
    -+  pencegahan keamanan, toko aplikasi tidak menerima aplikasi yang ditandai
    -+  bisa-di-debug.
    -+</p>
    -+
    -+<p>
    -+<code>res/xml/network_security_config.xml</code>:
    -+<pre>
    -+&lt;?xml version="1.0" encoding="utf-8"?&gt;
    -+&lt;network-security-config&gt;
    -+    &lt;debug-overrides&gt;
    -+        &lt;trust-anchors&gt;
    -+            &lt;certificates src="@raw/debug_cas"/&gt;
    -+        &lt;/trust-anchors&gt;
    -+    &lt;/debug-overrides&gt;
    -+&lt;/network-security-config&gt;
    -+</pre>
    -+</p>
    -+
    -+
    -+<h2 id="UsesCleartextTraffic">Berhenti dari Lalu Lintas Cleartext</h2>
    -+
    -+<p>
    -+  Aplikasi bermaksud menyambung ke tujuan hanya menggunakan koneksi
    -+ aman dapat memilih keluar dari dukungan cleartext (menggunakan protokol
    -+ HTTP yang tidak terenkripsi sebagai ganti HTTPS) ke tujuan tersebut. Opsi ini akan membantu mencegah
    -+  regresi tidak disengaja dalam aplikasi karena perubahan dalam URL yang disediakan oleh sumber-sumber
    -+  eksternal seperti server backend.
    -+  Lihat {@link android.security.NetworkSecurityPolicy#isCleartextTrafficPermitted
    -+  NetworkSecurityPolicy.isCleartextTrafficPermitted()} untuk detail selengkapnya.
    -+</p>
    -+
    -+<p>
    -+  Misalnya, aplikasi mungkin ingin memastikan semua koneksi ke {@code
    -+  secure.example.com} selalu dilakukan melalui HTTPS untuk melindungi lalu lintas sensitif
    -+  dari jaringan yang berbahaya.
    -+</p>
    -+
    -+<p>
    -+<code>res/xml/network_security_config.xml</code>:
    -+<pre>
    -+&lt;?xml version="1.0" encoding="utf-8"?&gt;
    -+&lt;network-security-config&gt;
    -+    &lt;domain-config usesCleartextTraffic="false"&gt;
    -+        &lt;domain includeSubdomains="true"&gt;secure.example.com&lt;/domain&gt;
    -+    &lt;/domain-config&gt;
    -+&lt;/network-security-config&gt;
    -+</pre>
    -+</p>
    -+
    -+
    -+<h2 id="CertificatePinning">Menyematkan Sertifikat</h2>
    -+
    -+<p>
    -+  Biasanya aplikasi mempercayai semua CA yang telah terpasang. Jika salah satu dari CA ini
    -+  mengeluarkan sertifikat palsu, aplikasi akan berisiko terkena serangan
    -+  MiTM. Beberapa aplikasi memilih untuk membatasi set sertifikat yang mereka terima
    -+  baik dengan membatasi set CA yang mereka percaya atau dengan menyematkan sertifikat.
    -+</p>
    -+
    -+<p>
    -+  Penyematan sertifikat dilakukan dengan memberikan seperangkat sertifikat dengan hash
    -+  kunci publik (SubjectPublicKeyInfo pada sertifikat X.509). Rantai
    -+  sertifikat nanti hanya berlaku jika rantai sertifikat berisi setidaknya salah satu
    -+  dari kunci publik yang disematkan.
    -+</p>
    -+
    -+<p>
    -+  Perhatikan, saat menggunakan penyematan sertifikat, Anda harus selalu menyertakan kunci
    -+  cadangan sehingga jika Anda terpaksa beralih ke kunci baru, atau mengubah CA (saat
    -+  menyematkan ke sertifikat CA atau perantara CA tersebut), konektivitas
    -+  aplikasi Anda tidak terpengaruh. Jika tidak, Anda harus mendorong
    -+  pembaruan ke aplikasi tersebut untuk memulihkan konektivitas.
    -+</p>
    -+
    -+<p>
    -+  Selain itu dimungkinkan juga menyetel waktu habis masa berlaku untuk pin setelah
    -+  penyematan tidak dilakukan. Hal ini membantu mencegah masalah konektivitas dalam
    -+  aplikasi yang belum diperbarui. Akan tetapi, menyetel waktu kedaluwarsa
    -+  pada pin mungkin akan membuat penyematan bisa diabaikan.
    -+</p>
    -+
    -+<p>
    -+<code>res/xml/network_security_config.xml</code>:
    -+<pre>
    -+&lt;?xml version="1.0" encoding="utf-8"?&gt;
    -+&lt;network-security-config&gt;
    -+    &lt;domain-config&gt;
    -+        &lt;domain includeSubdomains="true"&gt;example.com&lt;/domain&gt;
    -+        &lt;pin-set expiration="2018-01-01"&gt;
    -+            &lt;pin digest="SHA-256"&gt;7HIpactkIAq2Y49orFOOQKurWxmmSFZhBCoQYcRhJ3Y=&lt;/pin&gt;
    -+            &lt;!-- backup pin --&gt
    -+            &lt;pin digest="SHA-256"&gt;fwza0LRMXouZHRC8Ei+4PyuldPDcf3UKgO/04cDM1oE=&lt;/pin&gt;
    -+        &lt;/pin-set&gt;
    -+    &lt;/domain-config&gt;
    -+&lt;/network-security-config&gt;
    -+</pre>
    -+</p>
    -+
    -+
    -+<h2 id="ConfigInheritance">Perilaku Pewarisan Konfigurasi</h2>
    -+
    -+<p>
    -+  Nilai yang tidak disetel dalam konfigurasi tertentu akan diwariskan. Perilaku ini memungkinkan konfigurasi
    -+  yang lebih kompleks sambil menjaga file konfigurasi tetap terbaca.
    -+</p>
    -+
    -+<p>
    -+  Jika nilai tidak disetel dalam entri tertentu maka nilai dari entri berikutnya yang lebih
    -+  umum akan digunakan. Nilai yang tidak disetel dalam {@code domain-config} akan
    -+  diambil dari {@code domain-config} induk, jika tersarang, atau dari {@code
    -+  base-config} jika tidak. Nilai yang tidak disetel dalam {@code base-config} akan menggunakan
    -+  nilai default platform.
    -+</p>
    -+
    -+<p>
    -+  Misalnya pertimbangkan, bila semua koneksi ke subdomain {@code
    -+  example.com} harus menggunakan set CA khusus. Selain itu, lalu lintas cleartext ke
    -+  domain ini diizinkan <em>kecuali</em> saat menghubungkan ke {@code
    -+  secure.example.com}. Dengan menyarangkan konfigurasi untuk {@code
    -+  secure.example.com} dalam konfigurasi untuk {@code example.com},
    -+  {@code trust-anchors} tidak perlu digandakan.
    -+</p>
    -+
    -+<p>
    -+<code>res/xml/network_security_config.xml</code>:
    -+<pre>
    -+&lt;?xml version="1.0" encoding="utf-8"?&gt;
    -+&lt;network-security-config&gt;
    -+    &lt;domain-config&gt;
    -+        &lt;domain includeSubdomains="true"&gt;example.com&lt;/domain&gt;
    -+        &lt;trust-anchors&gt;
    -+            &lt;certificates src="@raw/my_ca"/&gt;
    -+        &lt;/trust-anchors&gt;
    -+        &lt;domain-config cleartextTrafficPermitted="false"&gt;
    -+            &lt;domain includeSubdomains="true"&gt;secure.example.com&lt;/domain&gt;
    -+        &lt;/domain-config&gt;
    -+    &lt;/domain-config&gt;
    -+&lt;/network-security-config&gt;
    -+</pre>
    -+</p>
    -+
    -+
    -+<h2 id="FileFormat">Format File Konfigurasi</h2>
    -+
    -+<p>
    -+  Fitur Network Security Configuration menggunakan format file XML.
    -+  Struktur keseluruhan file ditampilkan dalam contoh kode berikut:
    -+</p>
    -+
    -+<pre>
    -+&lt;?xml version="1.0" encoding="utf-8"?&gt;
    -+&lt;network-security-config&gt;
    -+    &lt;base-config&gt;
    -+        &lt;trust-anchors&gt;
    -+            &lt;certificates src="..."/&gt;
    -+            ...
    -+        &lt;/trust-anchors&gt;
    -+    &lt;/base-config&gt;
    -+
    -+    &lt;domain-config&gt;
    -+        &lt;domain&gt;android.com&lt;/domain&gt;
    -+        ...
    -+        &lt;trust-anchors&gt;
    -+            &lt;certificates src="..."/&gt;
    -+            ...
    -+        &lt;/trust-anchors&gt;
    -+        &lt;pin-set&gt;
    -+            &lt;pin digest="..."&gt;...&lt;/pin&gt;
    -+            ...
    -+        &lt;/pin-set&gt;
    -+    &lt;/domain-config&gt;
    -+    ...
    -+    &lt;debug-overrides&gt;
    -+        &lt;trust-anchors&gt;
    -+            &lt;certificates src="..."/&gt;
    -+            ...
    -+        &lt;/trust-anchors&gt;
    -+    &lt;/debug-overrides&gt;
    -+&lt;/network-security-config&gt;
    -+</pre>
    -+
    -+<p>
    -+  Bagian berikut menjelaskan sintaks dan detail lainnya dari format
    -+  file.
    -+</p>
    -+
    -+<h3 id="network-security-config">
    -+  &lt;network-security-config&gt;
    -+</h3>
    -+
    -+<dl class="xml">
    -+  <dt>
    -+    bisa berisi:
    -+  </dt>
    -+
    -+  <dd>
    -+    0 atau 1 <code><a href="#base-config">&lt;base-config&gt;</a></code><br>
    -+    Sejumlah <code><a href=
    -+    "#domain-config">&lt;domain-config&gt;</a></code><br>
    -+    0 atau 1 <code><a href="#debug-overrides">&lt;debug-overrides&gt;</a></code>
    -+  </dd>
    -+</dl>
    -+
    -+<h3 id="base-config">
    -+  &lt;base-config&gt;
    -+</h3>
    -+
    -+<dl class="xml">
    -+  <dt>
    -+    sintaks:
    -+  </dt>
    -+</dl>
    -+
    -+<pre class="stx">
    -+&lt;base-config <a href=
    -+"#usesCleartextTraffic">usesCleartextTraffic</a>=["true" | "false"]&gt;
    -+    ...
    -+&lt;/base-config&gt;
    -+</pre>
    -+<dl class="xml">
    -+  <dt>
    -+    bisa berisi:
    -+  </dt>
    -+
    -+  <dd>
    -+    <code><a href="#trust-anchors">&lt;trust-anchors&gt;</a></code>
    -+  </dd>
    -+
    -+  <dt>
    -+    keterangan:
    -+  </dt>
    -+
    -+  <dd>
    -+    Konfigurasi default yang digunakan oleh semua koneksi yang tujuannya tidak
    -+    tercakup oleh <a href="#domain-config"><code>domain-config</code></a>.
    -+
    -+<p>
    -+  Nilai yang tidak disetel akan menggunakan nilai default platform. Konfigurasi
    -+  default untuk aplikasi yang menargetkan API level 24 ke atas:
    -+</p>
    -+
    -+<pre>
    -+&lt;base-config usesCleartextTraffic="true"&gt;
    -+    &lt;trust-anchors&gt;
    -+        &lt;certificates src="system" /&gt;
    -+    &lt;/trust-anchors&gt;
    -+&lt;/base-config&gt;
    -+</pre>
    -+Konfigurasi default untuk aplikasi yang menargetkan API level 23 ke bawah:
    -+<pre>
    -+&lt;base-config usesCleartextTraffic="true"&gt;
    -+    &lt;trust-anchors&gt;
    -+        &lt;certificates src="system" /&gt;
    -+        &lt;certificates src="user" /&gt;
    -+    &lt;/trust-anchors&gt;
    -+&lt;/base-config&gt;
    -+</pre>
    -+
    -+  </dd>
    -+</dl>
    -+
    -+<h3 id="domain-config">&lt;domain-config&gt;</h3>
    -+<dl class="xml">
    -+<dt>sintaks:</dt>
    -+<dd>
    -+<pre class="stx">&lt;domain-config <a href="#usesCleartextTraffic">usesCleartextTraffic</a>=["true" | "false"]&gt;
    -+    ...
    -+&lt;/domain-config&gt;</pre>
    -+</dd>
    -+
    -+<dt>Bisa Berisi:</dt>
    -+
    -+<dd>
    -+1 atau beberapa <code><a href="#domain">&lt;domain&gt;</a></code>
    -+<br/>0 atau 1 <code><a href="#trust-anchors">&lt;trust-anchors&gt;</a></code>
    -+<br/>0 atau 1 <code><a href="#pin-set">&lt;pin-set&gt;</code></a>
    -+<br/>Sejumlah <code>&lt;domain-config&gt;</code> tersarang</dd>
    -+
    -+<dt>Keterangan</dt>
    -+<dd>Konfigurasi yang digunakan untuk koneksi ke tujuan tertentu seperti didefinisikan oleh elemen {@code domain}.
    -+
    -+<p>Perhatikan, jika beberapa elemen {@code domain-config} mencakup suatu tujuan, konfigurasi dengan aturan domain paling spesifik (terpanjang) yang cocok
    -+akan digunakan.</p></dd>
    -+</dl>
    -+
    -+
    -+<h3 id="domain">&lt;domain&gt;</h3>
    -+
    -+<dl class="xml">
    -+  <dt>
    -+    sintaks:
    -+  </dt>
    -+
    -+  <dd>
    -+    <pre class="stx">
    -+&lt;domain includeSubdomains=["true" | "false"]&gt;example.com&lt;/domain&gt;
    -+</pre>
    -+  </dd>
    -+
    -+  <dt>
    -+    Atribut:
    -+  </dt>
    -+
    -+  <dd>
    -+    <dl class="attr">
    -+      <dt>
    -+        {@code includeSubdomains}
    -+      </dt>
    -+
    -+      <dd>
    -+        Jika {@code "true"} maka aturan domain ini akan dicocokkan dengan domain dan semua
    -+        subdomain, termasuk subdomain dari subdomain, jika tidak peraturan hanya
    -+        diterapkan pada kecocokan yang persis tepat.
    -+      </dd>
    -+    </dl>
    -+  </dd>
    -+
    -+  <dt>
    -+    Keterangan:
    -+  </dt>
    -+</dl>
    -+
    -+<h3 id="debug-overrides">&lt;debug-overrides&gt;</h3>
    -+
    -+<dl class="xml">
    -+  <dt>
    -+    sintaks:
    -+  </dt>
    -+
    -+  <dd>
    -+    <pre class="stx">
    -+&lt;debug-overrides&gt;
    -+    ...
    -+&lt;/debug-overrides&gt;
    -+</pre>
    -+  </dd>
    -+
    -+  <dt>
    -+    Bisa Berisi:
    -+  </dt>
    -+
    -+  <dd>
    -+    0 atau 1 <code><a href="#trust-anchors">&lt;trust-anchors&gt;</a></code>
    -+  </dd>
    -+
    -+  <dt>
    -+    Keterangan:
    -+  </dt>
    -+
    -+  <dd>
    -+    Pengesampingan yang akan diterapkan bila <a href="{@docRoot}guide/topics/manifest/application-element.html#debug">android:debuggable</a>
    -+    adalah {@code "true"} yang biasanya terjadi untuk build non-rilis
    -+    yang dihasilkan oleh alat IDE dan build. Trust-anchor yang ditetapkan dalam {@code
    -+    debug-overrides} akan ditambahkan ke semua konfigurasi lainnya dan penyematan
    -+    sertifikat tidak dilakukan bila rantai sertifikat server menggunakan satu dari
    -+    trust-anchor hanya-debug ini. Jika <a href="{@docRoot}guide/topics/manifest/application-element.html#debug">android:debuggable</a>
    -+    adalah {@code "false"} maka bagian ini akan diabaikan sepenuhnya.
    -+  </dd>
    -+</dl>
    -+
    -+<h3 id="trust-anchors">&lt;trust-anchors&gt;</h3>
    -+<dl class="xml">
    -+  <dt>
    -+    sintaks:
    -+  </dt>
    -+
    -+  <dd>
    -+    <pre class="stx">
    -+&lt;trust-anchors&gt;
    -+...
    -+&lt;/trust-anchors&gt;
    -+</pre>
    -+  </dd>
    -+
    -+  <dt>
    -+    Bisa Berisi:
    -+  </dt>
    -+
    -+  <dd>
    -+    Sejumlah <code><a href="#certificates">&lt;certificates&gt;</a></code>
    -+  </dd>
    -+
    -+  <dt>
    -+    Keterangan:
    -+  </dt>
    -+
    -+  <dd>
    -+    Set trust-anchor untuk koneksi aman.
    -+  </dd>
    -+</dl>
    -+
    -+
    -+<h3 id="certificates">&lt;certificates&gt;</h3>
    -+<dl class="xml">
    -+<dt>sintaks:</dt>
    -+<dd><pre class="stx">&lt;certificates src=["system" | "user" | "<i>raw resource</i>"]
    -+              overridePins=["true" | "false"] /&gt;
    -+</pre></dd>
    -+<dt>keterangan:</dt>
    -+<dd>Set sertifikat X.509 untuk elemen {@code trust-anchors}.</dd>
    -+
    -+<dt>atribut:</dt>
    -+<dd><dl class="attr">
    -+<dt>{@code src}</dt>
    -+<dd>
    -+Sumber sertifikat CA, bisa salah satu dari
    -+<ul>
    -+  <li>ID sumber daya mentah yang menunjuk ke file berisi sertifikat X.509.
    -+  Sertifikat harus dikodekan dalam format DER atau PEM. Dalam hal sertifikat
    -+  PEM, file <em>tidak boleh</em> berisi data tambahan non-PEM seperti
    -+  komentar.
    -+  </li>
    -+
    -+  <li>{@code "system"} untuk sertifikat CA sistem yang telah terpasang.
    -+  </li>
    -+
    -+  <li>{@code "user"} untuk sertifikat CA yang ditambahkan pengguna.
    -+  </li>
    -+</ul>
    -+</dd>
    -+
    -+<dt>{@code overridePins}</dt>
    -+<dd>
    -+  <p>
    -+    Menetapkan apakah CA dari sumber akan mengabaikan penyematan sertifikat. Jika {@code
    -+    "true"} kemudian rangkaian sertifikat melalui salah satu CA dari
    -+    sumber ini maka tidak dilakukan penyematan. Hal ini bisa berguna untuk debug CA
    -+    atau untuk mendukung dengan memungkinkan pengguna melakukan MiTM atas lalu lintas aman aplikasi Anda.
    -+  </p>
    -+
    -+  <p>
    -+    Default-nya adalah {@code "false"} kecuali jika ditetapkan dalam elemen {@code debug-overrides},
    -+    dalam hal demikian default-nya adalah {@code "true"}.
    -+  </p>
    -+</dd>
    -+</dl>
    -+</dd>
    -+
    -+
    -+<h3 id="pin-set">&lt;pin-set&gt;</h3>
    -+
    -+<dl class="xml">
    -+  <dt>
    -+    sintaks:
    -+  </dt>
    -+
    -+  <dd>
    -+<pre class="stx">
    -+&lt;pin-set expiration="date"&gt;
    -+...
    -+&lt;/pin-set&gt;
    -+</pre>
    -+  </dd>
    -+
    -+  <dt>
    -+    Bisa Berisi:
    -+  </dt>
    -+
    -+  <dd>
    -+    Sejumlah <code><a href="#pin">&lt;pin&gt;</a></code>
    -+  </dd>
    -+
    -+  <dt>
    -+    Keterangan:
    -+  </dt>
    -+
    -+  <dd>
    -+    Satu set pin kunci publik. Agar koneksi aman bisa dipercaya, salah satu
    -+    kunci publik dalam rantai kepercayaan harus berada dalam set pin. Lihat
    -+    <code><a href="#pin">&lt;pin&gt;</a></code> untuk mengetahui format pin.
    -+  </dd>
    -+
    -+  <dt>
    -+    Atribut:
    -+  </dt>
    -+
    -+  <dd>
    -+    <dl class="attr">
    -+      <dt>
    -+        {@code expiration}
    -+      </dt>
    -+
    -+      <dd>
    -+        Tanggal, dalam format {@code yyyy-MM-dd}, pada saat dan setelah pin
    -+        kedaluwarsa, sehingga menonaktifkan penyematan. Jika atribut tidak disetel maka
    -+        pin tidak kedaluwarsa.
    -+        <p>
    -+          Tanggal kedaluwarsa membantu mencegah masalah konektivitas di aplikasi yang
    -+          tidak mengambil pembaruan untuk set pin mereka, misalnya karena pengguna
    -+          menonaktifkan pembaruan aplikasi.
    -+        </p>
    -+      </dd>
    -+    </dl>
    -+  </dd>
    -+</dl>
    -+
    -+<h3 id="pin">&lt;pin&gt;</h3>
    -+<dl class="xml">
    -+  <dt>
    -+    sintaks:
    -+  </dt>
    -+
    -+  <dd>
    -+<pre class="stx">
    -+&lt;pin digest=["SHA-256"]&gt;base64 encoded digest of X.509
    -+    SubjectPublicKeyInfo (SPKI)&lt;/pin&gt;
    -+</pre>
    -+  </dd>
    -+
    -+  <dt>
    -+    Atribut:
    -+  </dt>
    -+
    -+  <dd>
    -+    <dl class="attr">
    -+      <dt>
    -+        {@code digest}
    -+      </dt>
    -+
    -+      <dd>
    -+        Algoritme intisari yang digunakan untuk menghasilkan pin. Saat ini, hanya
    -+        {@code "SHA-256"} yang didukung.
    -+      </dd>
    -+    </dl>
    -+  </dd>
    -+</dl>
    -diff --git a/docs/html-intl/intl/id/training/basics/network-ops/data-saver.jd b/docs/html-intl/intl/id/training/basics/network-ops/data-saver.jd
    -new file mode 100644
    -index 0000000..abd4e43
    ---- /dev/null
    -+++ b/docs/html-intl/intl/id/training/basics/network-ops/data-saver.jd
    -@@ -0,0 +1,234 @@
    -+page.title=Data Saver
    -+metaDescription=Optimalisasi penggunaan data yang diaktifkan pengguna.
    -+page.keywords="android N", "data usage", "metered network"
    -+page.image=images/cards/card-nyc_2x.jpg
    -+@jd:body
    -+
    -+<div id="tb-wrapper">
    -+  <div id="tb">
    -+    <h2>
    -+      Dalam dokumen ini
    -+    </h2>
    -+
    -+    <ol>
    -+      <li>
    -+        <a href="#status">Memeriksa Preferensi Data Saver</a>
    -+        <ol>
    -+          <li>
    -+            <a href="#request-whitelist">Meminta izin daftar putih</a>
    -+          </li>
    -+        </ol>
    -+      </li>
    -+
    -+      <li>
    -+        <a href="#monitor-changes">Memantau Perubahan pada Preferensi
    -+        Data Saver</a>
    -+      </li>
    -+
    -+      <li>
    -+        <a href="#testing">Menguji dengan Perintah Android Debug Bridge</a>
    -+      </li>
    -+    </ol>
    -+  </div>
    -+</div>
    -+
    -+<p>
    -+  Selama penggunaan ponsel cerdas, biaya paket data seluler bisa saja
    -+  melebihi harga perangkat itu sendiri. Di N Developer Preview, pengguna bisa
    -+  mengaktifkan Data Saver berdasarkan lingkup perangkat untuk menghemat data, baik saat
    -+  roaming, mendekati akhir siklus penagihan, atau pada paket data prabayar kecil.
    -+</p>
    -+
    -+<p>
    -+  Bila pengguna mengaktifkan Data Saver di <strong>Settings</strong> dan perangkat
    -+  berada dalam jaringan berkuota, sistem akan memblokir penggunaan data latar belakang dan memberi tahu
    -+  aplikasi untuk menghemat penggunaan data latar depan bila memungkinkan. Pengguna bisa
    -+  memasukkan aplikasi tertentu ke daftar putih untuk memungkinkan penggunaan data berkuota bila Data
    -+  Saver diaktifkan.
    -+</p>
    -+
    -+<p>
    -+  N Developer Preview memperluas {@link android.net.ConnectivityManager}
    -+  API untuk menyediakan cara pada aplikasi untuk <a href="#status">menerima preferensi Data Saver
    -+  pengguna</a> dan <a href="#monitor-changes">memantau perubahan
    -+  preferensi</a>. Hal ini dianggap praktik terbaik bagi aplikasi untuk memeriksa apakah
    -+  pengguna telah mengaktifkan DataSaver dan berusaha membatasi penggunaan data latar depan dan
    -+  data latar belakang.
    -+</p>
    -+
    -+<h2 id="status">
    -+  Memeriksa Preferensi Data Saver
    -+</h2>
    -+
    -+<p>
    -+  Di N Developer Preview, aplikasi bisa menggunakan {@link
    -+  android.net.ConnectivityManager} API untuk menentukan pembatasan penggunaan data
    -+  apa yang sedang diterapkan. Metode {@code getRestrictBackgroundStatus()}
    -+  akan mengembalikan salah satu dari nilai berikut:
    -+</p>
    -+
    -+<dl>
    -+  <dt>
    -+    {@code RESTRICT_BACKGROUND_STATUS_DISABLED}
    -+  </dt>
    -+
    -+  <dd>
    -+    Data Saver dinonaktifkan.
    -+  </dd>
    -+
    -+  <dt>
    -+    {@code RESTRICT_BACKGROUND_STATUS_ENABLED}
    -+  </dt>
    -+
    -+  <dd>
    -+    Pengguna telah mengaktifkan Data Saver untuk aplikasi ini. Aplikasi harus berusaha membatasi
    -+    penggunaan data di latar depan dan dengan halus menangani pembatasan penggunaan
    -+    data latar belakang.
    -+  </dd>
    -+
    -+  <dt>
    -+    {@code RESTRICT_BACKGROUND_STATUS_WHITELISTED}
    -+  </dt>
    -+
    -+  <dd>
    -+    Pengguna telah mengaktifkan Data Saver namun aplikasi telah dimasukkan dalam daftar putih. Aplikasi harus
    -+    tetap berusaha membatasi penggunaan data latar belakang dan latar depan.
    -+  </dd>
    -+</dl>
    -+
    -+<p>
    -+  Hal ini dianggap praktik terbaik untuk membatasi penggunaan data bila perangkat
    -+  terhubung ke jaringan berkuota, meskipun Data Saver telah dinonaktifkan atau aplikasi
    -+  telah dimasukkan dalam daftar putih. Kode contoh berikut menggunakan {@link
    -+  android.net.ConnectivityManager#isActiveNetworkMetered
    -+  ConnectivityManager.isActiveNetworkMetered()} dan {@code
    -+  ConnectivityManager.getRestrictBackgroundStatus()} untuk menentukan berapa banyak data
    -+  yang harus digunakan aplikasi:
    -+</p>
    -+
    -+<pre>
    -+ConnectivityManager connMgr = (ConnectivityManager)
    -+        getSystemService(Context.CONNECTIVITY_SERVICE);
    -+// Checks if the device is on a metered network
    -+if (connMgr.isActiveNetworkMetered()) {
    -+  // Checks user’s Data Saver settings.
    -+  switch (connMgr.getRestrictBackgroundStatus()) {
    -+    case RESTRICT_BACKGROUND_STATUS_ENABLED:
    -+    // Background data usage is blocked for this app. Wherever possible,
    -+    // the app should also use less data in the foreground.
    -+
    -+    case RESTRICT_BACKGROUND_STATUS_WHITELISTED:
    -+    // The app is whitelisted. Wherever possible,
    -+    // the app should use less data in the foreground and background.
    -+
    -+    case RESTRICT_BACKGROUND_STATUS_DISABLED:
    -+    // Data Saver is disabled. Since the device is connected to a
    -+    // metered network, the app should use less data wherever possible.
    -+  }
    -+} else {
    -+  // The device is not on a metered network.
    -+  // Use data as required to perform syncs, downloads, and updates.
    -+}
    -+</pre>
    -+
    -+<h3 id="request-whitelist">
    -+  Meminta izin daftar putih
    -+</h3>
    -+
    -+<p>
    -+  Jika aplikasi Anda perlu menggunakan data di latar belakang, aplikasi bisa meminta izin
    -+  daftar putih dengan mengirim
    -+  <code>Settings.ACTION_IGNORE_BACKGROUND_DATA_RESTRICTIONS_SETTINGS</code>
    -+  yang mengandung URI dari nama paket aplikasi Anda: misalnya,
    -+  <code>package:MY_APP_ID</code>.
    -+</p>
    -+
    -+<p>
    -+  Mengirim intent dan URI akan membuka aplikasi <strong>Settings</strong> dan
    -+  menampilkan setelan penggunaan data untuk aplikasi Anda. Pengguna nanti bisa memutuskan apakah akan
    -+  mengaktifkan data latar belakang untuk aplikasi Anda. Sebelum Anda mengirim intent ini, sebaiknya
    -+  tanyakan kepada pengguna terlebih dahulu apakah mereka ingin membuka aplikasi
    -+  <strong>Settings</strong> untuk keperluan mengaktifkan penggunaan
    -+  data latar belakang.
    -+</p>
    -+
    -+<h2 id="monitor-changes">
    -+  Memantau Perubahan pada Preferensi Data Saver
    -+</h2>
    -+
    -+<p>
    -+  Aplikasi bisa memantau perubahan pada preferensi Data Saver dengan membuat {@link
    -+  android.content.BroadcastReceiver} untuk memantau {@code
    -+  ConnectivityManager.ACTION_RESTRICT_BACKGROUND_CHANGED} dan secara dinamis
    -+  mendaftarkan penerima pada {@link android.content.Context#registerReceiver
    -+  Context.registerReceiver()}. Bila menerima siaran ini, aplikasi harus
    -+  <a href="#status">memeriksa apakah preferensi Data Saver baru memengaruhi
    -+  izinnya</a> dengan memanggil {@code
    -+  ConnectivityManager.getRestrictBackgroundStatus()}.
    -+</p>
    -+
    -+<p class="note">
    -+  <strong>Catatan:</strong> Sistem hanya mengirim siaran ini ke aplikasi yang
    -+  secara dinamis mendaftar padanya dengan {@link
    -+  android.content.Context#registerReceiver Context.registerReceiver()}. Aplikasi
    -+  yang mendaftar untuk menerima siaran ini dalam manifes mereka
    -+  tidak akan menerimanya.
    -+</p>
    -+
    -+<h2 id="testing">
    -+  Menguji dengan Perintah Android Debug Bridge
    -+</h2>
    -+
    -+<a href="{@docRoot}tools/help/adb.html">Android Debug Bridge (ADB)</a>
    -+menyediakan beberapa perintah yang bisa Anda gunakan untuk memeriksa dan
    -+mengonfigurasi izin jaringan:
    -+
    -+<dl>
    -+  <dt>
    -+    <code>$ adb shell dumpsys netpolicy</code>
    -+  </dt>
    -+
    -+  <dd>
    -+    Menghasilkan laporan berisi setelan pembatasan jaringan latar belakang
    -+    global saat ini, UID paket saat ini di daftar putih, dan izin jaringan
    -+    untuk paket yang diketahui lainnya.
    -+  </dd>
    -+
    -+  <dt>
    -+    <code>$ adb shell cmd netpolicy</code>
    -+  </dt>
    -+
    -+  <dd>
    -+    Menampilkan daftar lengkap dari perintah Network Policy Manager (netpolicy).
    -+  </dd>
    -+
    -+  <dt>
    -+    <code>$ adb shell cmd netpolicy set restrict-background
    -+    &lt;boolean&gt;</code>
    -+  </dt>
    -+
    -+  <dd>
    -+    Mengaktifkan atau menonaktifkan mode Data Saver saat meneruskan <code>true</code> atau
    -+ <code>false</code>, masing-masing.
    -+  </dd>
    -+
    -+  <dt>
    -+    <code>$ adb shell cmd netpolicy add restrict-background-whitelist
    -+    &lt;UID&gt;</code>
    -+  </dt>
    -+
    -+  <dd>
    -+    Menambahkan UID paket tertentu ke daftar putih untuk mengizinkan penggunaan data berkuota
    -+  di latar belakang.
    -+  </dd>
    -+
    -+  <dt>
    -+    <code>$ adb shell cmd netpolicy remove restrict-background-whitelist
    -+    &lt;UID&gt;</code>
    -+  </dt>
    -+
    -+  <dd>
    -+    Membuang UID paket tertentu dari daftar putih untuk memblokir
    -+    penggunaan data berkuota di latar belakang saat Data Saver diaktifkan.
    -+  </dd>
    -+</dl>
    -diff --git a/docs/html-intl/intl/id/training/material/animations.jd b/docs/html-intl/intl/id/training/material/animations.jd
    -new file mode 100644
    -index 0000000..e57a03f
    ---- /dev/null
    -+++ b/docs/html-intl/intl/id/training/material/animations.jd
    -@@ -0,0 +1,550 @@
    -+page.title=Mendefinisikan Animasi Custom
    -+
    -+@jd:body
    -+
    -+<div id="tb-wrapper">
    -+<div id="tb">
    -+<h2>Pelajaran ini mengajarkan Anda cara</h2>
    -+<ol>
    -+  <li><a href="#Touch">Menyesuaikan Umpan Balik Sentuh</a></li>
    -+  <li><a href="#Reveal">Menggunakan Reveal Effect</a></li>
    -+  <li><a href="#Transitions">Menyesuaikan Transisi Aktivitas</a></li>
    -+  <li><a href="#ViewState">Menganimasikan Perubahan Status Tampilan</a></li>
    -+  <li><a href="#AnimVector">Menganimasikan Drawable Vektor</a></li>
    -+</ol>
    -+<h2>Anda juga harus membaca</h2>
    -+<ul>
    -+  <li><a href="http://www.google.com/design/spec">Spesifikasi desain bahan</a></li>
    -+  <li><a href="{@docRoot}design/material/index.html">Desain bahan di Android</a></li>
    -+</ul>
    -+</div>
    -+</div>
    -+
    -+
    -+<p>Animasi dalam desain bahan memberi pengguna umpan balik tentang tindakannya dan menyediakan
    -+kesinambungan visual saat pengguna berinteraksi dengan aplikasi Anda. Tema bahan menyediakan beberapa animasi default
    -+untuk tombol dan transisi aktivitas, dan Android 5.0 (API level 21) ke atas memungkinkan Anda menyesuaikan
    -+animasi ini dan membuat yang baru:</p>
    -+
    -+<ul>
    -+<li>Umpan balik sentuh</li>
    -+<li>Singkap Melingkar</li>
    -+<li>Transisi aktivitas</li>
    -+<li>Gerakan melengkung</li>
    -+<li>Perubahan status tampilan</li>
    -+</ul>
    -+
    -+
    -+<h2 id="Touch">Menyesuaikan Umpan Balik Sentuh</h2>
    -+
    -+<p>Umpan balik sentuh dalam desain bahan menyediakan konfirmasi visual seketika pada
    -+titik kontak bila pengguna berinteraksi dengan elemen UI. Animasi umpan balik sentuh default
    -+untuk tombol menggunakan kelas {@link android.graphics.drawable.RippleDrawable} baru, yang bertransisi
    -+di antara berbagai status dengan efek riak.</p>
    -+
    -+<p>Di sebagian besar kasus, Anda harus menerapkan fungsionalitas ini dalam XML tampilan dengan menetapkan
    -+latar belakang tampilan sebagai:</p>
    -+
    -+<ul>
    -+<li><code>?android:attr/selectableItemBackground</code> untuk riak berbatas.</li>
    -+<li><code>?android:attr/selectableItemBackgroundBorderless</code> untuk riak yang meluas ke luar
    -+tampilan. Latar belakang ini akan digambar di atas, dan dibatasi oleh, induk tampilan terdekat dengan
    -+latar belakang non-null.</li>
    -+</ul>
    -+
    -+<p class="note"><strong>Catatan:</strong> <code>selectableItemBackgroundBorderless</code> adalah
    -+atribut baru yang diperkenalkan di API level 21.</p>
    -+
    -+
    -+<p>Atau, Anda bisa mendefinisikan {@link android.graphics.drawable.RippleDrawable}
    -+sebagai sumber daya XML dengan menggunakan elemen <code>ripple</code>.</p>
    -+
    -+<p>Anda bisa menetapkan warna ke objek-objek {@link android.graphics.drawable.RippleDrawable}. Untuk mengubah
    -+warna default umpan balik sentuh, gunakan atribut <code>android:colorControlHighlight</code>
    -+tema.</p>
    -+
    -+<p>Untuk informasi selengkapnya, lihat referensi API bagi kelas {@link
    -+android.graphics.drawable.RippleDrawable}.</p>
    -+
    -+
    -+<h2 id="Reveal">Menggunakan Reveal Effect</h2>
    -+
    -+<p>Animasi singkap memberi pengguna kesinambungan visual saat menampilkan atau menyembunyikan sekelompok
    -+elemen UI. Metode {@link android.view.ViewAnimationUtils#createCircularReveal
    -+ViewAnimationUtils.createCircularReveal()} memungkinkan Anda menganimasikan lingkaran terpangkas
    -+untuk memperlihatkan atau menyembunyikan tampilan.</p>
    -+
    -+<p>Untuk memperlihatkan tampilan yang sebelumnya tidak terlihat dengan menggunakan efek ini:</p>
    -+
    -+<pre>
    -+// previously invisible view
    -+View myView = findViewById(R.id.my_view);
    -+
    -+// get the center for the clipping circle
    -+int cx = (myView.getLeft() + myView.getRight()) / 2;
    -+int cy = (myView.getTop() + myView.getBottom()) / 2;
    -+
    -+// get the final radius for the clipping circle
    -+int finalRadius = Math.max(myView.getWidth(), myView.getHeight());
    -+
    -+// create the animator for this view (the start radius is zero)
    -+Animator anim =
    -+    ViewAnimationUtils.createCircularReveal(myView, cx, cy, 0, finalRadius);
    -+
    -+// make the view visible and start the animation
    -+myView.setVisibility(View.VISIBLE);
    -+anim.start();
    -+</pre>
    -+
    -+<p>Untuk menyembunyikan sebuah tampilan yang sebelumnya terlihat dengan menggunakan efek ini:</p>
    -+
    -+<pre>
    -+// previously visible view
    -+final View myView = findViewById(R.id.my_view);
    -+
    -+// get the center for the clipping circle
    -+int cx = (myView.getLeft() + myView.getRight()) / 2;
    -+int cy = (myView.getTop() + myView.getBottom()) / 2;
    -+
    -+// get the initial radius for the clipping circle
    -+int initialRadius = myView.getWidth();
    -+
    -+// create the animation (the final radius is zero)
    -+Animator anim =
    -+    ViewAnimationUtils.createCircularReveal(myView, cx, cy, initialRadius, 0);
    -+
    -+// make the view invisible when the animation is done
    -+anim.addListener(new AnimatorListenerAdapter() {
    -+    &#64;Override
    -+    public void onAnimationEnd(Animator animation) {
    -+        super.onAnimationEnd(animation);
    -+        myView.setVisibility(View.INVISIBLE);
    -+    }
    -+});
    -+
    -+// start the animation
    -+anim.start();
    -+</pre>
    -+
    -+
    -+<h2 id="Transitions">Menyesuaikan Transisi Aktivitas</h2>
    -+
    -+<!-- shared transition video -->
    -+<div style="width:290px;margin-left:35px;float:right">
    -+  <div class="framed-nexus5-port-span-5">
    -+  <video class="play-on-hover" autoplay="">
    -+    <source src="{@docRoot}design/material/videos/ContactsAnim.mp4">
    -+    <source src="{@docRoot}design/material/videos/ContactsAnim.webm">
    -+    <source src="{@docRoot}design/material/videos/ContactsAnim.ogv">
    -+  </video>
    -+  </div>
    -+  <div style="font-size:10pt;margin-left:20px;margin-bottom:30px">
    -+    <p class="img-caption" style="margin-top:3px;margin-bottom:10px"><strong>Gambar 1</strong> - Transisi
    -+    dengan elemen bersama.</p>
    -+    <em>Untuk memutar ulang film, klik layar perangkat</em>
    -+  </div>
    -+</div>
    -+
    -+<p>Transisi aktivitas dalam aplikasi desain bahan memberikan koneksi visual antar berbagai status
    -+melalui gerakan dan transformasi di antara elemen umum. Anda bisa menetapkan animasi custom untuk
    -+masuk ke dan keluar dari transisi dan untuk transisi elemen bersama di antara aktivitas.</p>
    -+
    -+<ul>
    -+<li>Transisi <strong>masuk</strong> menentukan cara tampilan di aktivitas memasuki suatu babak.
    -+misalnya, dalam transisi masuk <em>explode</em>, tampilan memasuki babak dari sisi luar
    -+dan melayang masuk ke arah tengah layar.</li>
    -+
    -+<li>Transisi <strong>keluar</strong> menentukan cara tampilan di aktivitas keluar dari suatu babak. Misalnya
    -+, dalam transisi keluar <em>explode</em>, tampilan akan keluar dari babak dari bagian
    -+tengahnya.</li>
    -+
    -+<li>Transisi <strong>elemen bersama</strong> menentukan cara menggunakan bersama suatu tampilan
    -+oleh dua transisi aktivitas di antara aktivitas-aktivitas ini. Misalnya, jika dua aktivitas memiliki
    -+gambar yang sama dengan posisi dan ukuran berbeda, transisi elemen bersama <em>changeImageTransform</em>
    -+mentransformasikan dan menskalakan gambar secara mulus di antara aktivitas-aktivitas ini.</li>
    -+</ul>
    -+
    -+<p>Android 5.0 (API level 21) mendukung transisi masuk dan transisi keluar ini:</p>
    -+
    -+<ul>
    -+<li><em>explode</em> - Memindahkan tampilan masuk ke atau keluar dari tengah babak.</li>
    -+<li><em>slide</em> - Memindahkan tampilan masuk ke atau keluar dari salah satu tepi babak.</li>
    -+<li><em>fade</em> - Menambahkan atau menghapus tampilan dari babak dengan mengubah opasitasnya.</li>
    -+</ul>
    -+
    -+<p>Transisi apa pun yang memperluas kelas {@link android.transition.Visibility} didukung
    -+sebagai transisi masuk atau transisi keluar. Untuk informasi selengkapnya, lihat referensi API untuk kelas
    -+{@link android.transition.Transition}.</p>
    -+
    -+<p>Android 5.0 (API level 21) juga mendukung transisi elemen bersama ini:</p>
    -+
    -+<ul>
    -+<li><em>changeBounds</em> - Menganimasikan perubahan pada batas-batas layout tampilan target.</li>
    -+<li><em>changeClipBounds</em> - Menganimasikan perubahan pada batas-batas pemangkasan tampilan target.</li>
    -+<li><em>changeTransform</em> - Menganimasikan perubahan pada skala dan rotasi tampilan target.</li>
    -+<li><em>changeImageTransform</em> - Menganimasikan perubahan pada ukuran dan skala gambar target.</li>
    -+</ul>
    -+
    -+<p>Bila Anda mengaktifkan transisi aktivitas dalam aplikasi, transisi memudar-silang default akan
    -+diaktifkan di antara aktivitas masuk dan aktivitas keluar.</p>
    -+
    -+<img src="{@docRoot}training/material/images/SceneTransition.png" alt="" width="600" height="405" style="margin-top:20px" />
    -+<p class="img-caption">
    -+  <strong>Gambar 2</strong> - Transisi babak dengan satu elemen bersama.
    -+</p>
    -+
    -+<h3>Menetapkan transisi custom</h3>
    -+
    -+<p>Pertama, aktifkan transisi konten jendela dengan atribut <code>android:windowContentTransitions</code>
    -+bila Anda mendefinisikan gaya yang mewarisi tema bahan. Anda juga bisa menetapkan
    -+transisi-transisi masuk, keluar, dan elemen bersama dalam definisi gaya:</p>
    -+
    -+<pre>
    -+&lt;style name="BaseAppTheme" parent="android:Theme.Material">
    -+  &lt;!-- enable window content transitions -->
    -+  &lt;item name="android:windowContentTransitions">true&lt;/item>
    -+
    -+  &lt;!-- specify enter and exit transitions -->
    -+  &lt;item name="android:windowEnterTransition">@transition/explode&lt;/item>
    -+  &lt;item name="android:windowExitTransition">@transition/explode&lt;/item>
    -+
    -+  &lt;!-- specify shared element transitions -->
    -+  &lt;item name="android:windowSharedElementEnterTransition">
    -+    &#64;transition/change_image_transform&lt;/item>
    -+  &lt;item name="android:windowSharedElementExitTransition">
    -+    &#64;transition/change_image_transform&lt;/item>
    -+&lt;/style>
    -+</pre>
    -+
    -+<p>Transisi <code>change_image_transform</code> dalam contoh ini didefinisikan sebagai berikut:</p>
    -+
    -+<pre>
    -+&lt;!-- res/transition/change_image_transform.xml -->
    -+&lt;!-- (see also Shared Transitions below) -->
    -+&lt;transitionSet xmlns:android="http://schemas.android.com/apk/res/android">
    -+  &lt;changeImageTransform/>
    -+&lt;/transitionSet>
    -+</pre>
    -+
    -+<p>Elemen <code>changeImageTransform</code> menunjukkan
    -+kelas {@link android.transition.ChangeImageTransform}. Untuk informasi selengkapnya, lihat referensi
    -+API untuk {@link android.transition.Transition}.</p>
    -+
    -+<p>Sebaliknya, untuk mengaktifkan transisi konten jendela dalam kode Anda, panggil
    -+metode {@link android.view.Window#requestFeature Window.requestFeature()}:</p>
    -+
    -+<pre>
    -+// inside your activity (if you did not enable transitions in your theme)
    -+getWindow().requestFeature(Window.FEATURE_CONTENT_TRANSITIONS);
    -+
    -+// set an exit transition
    -+getWindow().setExitTransition(new Explode());
    -+</pre>
    -+
    -+<p>Untuk menetapkan transisi dalam kode Anda, panggil metode-metode ini dengan objek {@link
    -+android.transition.Transition}:</p>
    -+
    -+<ul>
    -+  <li>{@link android.view.Window#setEnterTransition Window.setEnterTransition()}</li>
    -+  <li>{@link android.view.Window#setExitTransition Window.setExitTransition()}</li>
    -+  <li>{@link android.view.Window#setSharedElementEnterTransition
    -+      Window.setSharedElementEnterTransition()}</li>
    -+  <li>{@link android.view.Window#setSharedElementExitTransition
    -+      Window.setSharedElementExitTransition()}</li>
    -+</ul>
    -+
    -+<p>Metode {@link android.view.Window#setExitTransition setExitTransition()} dan {@link
    -+android.view.Window#setSharedElementExitTransition setSharedElementExitTransition()} mendefinisikan
    -+transisi keluar untuk aktivitas yang memanggil. Metode {@link android.view.Window#setEnterTransition
    -+setEnterTransition()} dan {@link android.view.Window#setSharedElementEnterTransition
    -+setSharedElementEnterTransition()} mendefinisikan transisi masuk untuk aktivitas yang dipanggil.</p>
    -+
    -+<p>Untuk mendapatkan efek penuh sebuah transisi, Anda harus mengaktifkan transisi konten jendela pada
    -+aktivitas yang memanggil maupun aktivitas yang dipanggil. Jika tidak, aktivitas yang memanggil akan memulai transisi keluar,
    -+namun kemudian Anda akan melihat transisi jendela (seperti mengelupas atau memudar).</p>
    -+
    -+<p>Untuk memulai transisi masuk sesegera mungkin, gunakan metode
    -+{@link android.view.Window#setAllowEnterTransitionOverlap Window.setAllowEnterTransitionOverlap()}
    -+pada aktivitas yang dipanggil. Ini memungkinkan Anda mendapatkan transisi masuk yang lebih dramatis.</p>
    -+
    -+<h3>Memulai aktivitas dengan menggunakan transisi</h3>
    -+
    -+<p>Jika Anda mengaktifkan transisi dan mengatur transisi keluar untuk aktivitas, transisi itu akan diaktifkan
    -+bila Anda menjalankan aktivitas lain sebagai berikut:</p>
    -+
    -+<pre>
    -+startActivity(intent,
    -+              ActivityOptions.makeSceneTransitionAnimation(this).toBundle());
    -+</pre>
    -+
    -+<p>Jika Anda telah mengatur transisi masuk untuk aktivitas kedua, transisi juga akan diaktifkan
    -+bila aktivitas dimulai. Untuk menonaktifkan transisi bila Anda memulai aktivitas lain, sediakan
    -+bundel opsi <code>null</code>.</p>
    -+
    -+<h3>Memulai aktivitas dengan satu elemen bersama</h3>
    -+
    -+<p>Untuk membuat animasi transisi layar di antara dua aktivitas yang memiliki satu elemen bersama:</p>
    -+
    -+<ol>
    -+<li>Aktifkan transisi konten jendela dalam tema Anda.</li>
    -+<li>Tetapkan transisi elemen bersama dalam gaya Anda.</li>
    -+<li>Definisikan transisi Anda sebagai sumber daya XML.</li>
    -+<li>Tetapkan nama umum pada elemen bersama dalam kedua layout dengan
    -+    atribut <code>android:transitionName</code>.</li>
    -+<li>Gunakan metode {@link android.app.ActivityOptions#makeSceneTransitionAnimation
    -+ActivityOptions.makeSceneTransitionAnimation()}.</li>
    -+</ol>
    -+
    -+<pre>
    -+// get the element that receives the click event
    -+final View imgContainerView = findViewById(R.id.img_container);
    -+
    -+// get the common element for the transition in this activity
    -+final View androidRobotView = findViewById(R.id.image_small);
    -+
    -+// define a click listener
    -+imgContainerView.setOnClickListener(new View.OnClickListener() {
    -+    &#64;Override
    -+    public void onClick(View view) {
    -+        Intent intent = new Intent(this, Activity2.class);
    -+        // create the transition animation - the images in the layouts
    -+        // of both activities are defined with android:transitionName="robot"
    -+        ActivityOptions options = ActivityOptions
    -+            .makeSceneTransitionAnimation(this, androidRobotView, "robot");
    -+        // start the new activity
    -+        startActivity(intent, options.toBundle());
    -+    }
    -+});
    -+</pre>
    -+
    -+<p>Untuk tampilan dinamis bersama yang Anda hasilkan dalam kode, gunakan
    -+metode {@link android.view.View#setTransitionName View.setTransitionName()} untuk menetapkan
    -+nama elemen umum di kedua aktivitas.</p>
    -+
    -+<p>Untuk membalik animasi transisi babak bila Anda menyelesaikan aktivitas kedua, panggil metode
    -+{@link android.app.Activity#finishAfterTransition Activity.finishAfterTransition()}
    -+sebagai ganti {@link android.app.Activity#finish Activity.finish()}.</p>
    -+
    -+<h3>Memulai aktivitas dengan beberapa elemen bersama</h3>
    -+
    -+<p>Untuk membuat animasi transisi babak antara dua aktivitas yang memiliki lebih dari satu
    -+elemen bersama, definisikan elemen bersama di kedua layout dengan atribut <code>android:transitionName</code>
    -+ (atau gunakan metode {@link android.view.View#setTransitionName View.setTransitionName()}
    -+di kedua aktivitas), dan buat sebuah objek {@link android.app.ActivityOptions} sebagai berikut:</p>
    -+
    -+<pre>
    -+ActivityOptions options = ActivityOptions.makeSceneTransitionAnimation(this,
    -+        Pair.create(view1, "agreedName1"),
    -+        Pair.create(view2, "agreedName2"));
    -+</pre>
    -+
    -+
    -+<h2 id="CurvedMotion">Menggunakan Gerakan Melengkung</h2>
    -+
    -+<p>Animasi dalam desain bahan mengandalkan kurva untuk pola interpolasi waktu dan
    -+gerakan spasial. Dengan Android 5.0 (API level 21) ke atas, Anda bisa mendefinisikan kurva pewaktuan custom dan
    -+pola gerakan melengkung untuk animasi.</p>
    -+
    -+<p>Kelas {@link android.view.animation.PathInterpolator} adalah interpolator baru berdasarkan sebuah
    -+kurva Bézier atau objek {@link android.graphics.Path}. Interpolator ini menetapkan kurva gerakan
    -+dalam bujur sangkar 1x1, dengan titik-titik jangkar di (0,0) dan (1,1) dan titik-titik kontrol sebagaimana ditetapkan menggunakan
    -+argumen konstruktor. Anda juga bisa mendefinisikan interpolator path sebagai sumber daya XML:</p>
    -+
    -+<pre>
    -+&lt;pathInterpolator xmlns:android="http://schemas.android.com/apk/res/android"
    -+    android:controlX1="0.4"
    -+    android:controlY1="0"
    -+    android:controlX2="1"
    -+    android:controlY2="1"/>
    -+</pre>
    -+
    -+<p>Sistem menyediakan sumber daya XML untuk tiga kurva dasar dalam
    -+spesifikasi desain bahan:</p>
    -+
    -+<ul>
    -+  <li><code>&#64;interpolator/fast_out_linear_in.xml</code></li>
    -+  <li><code>&#64;interpolator/fast_out_slow_in.xml</code></li>
    -+  <li><code>&#64;interpolator/linear_out_slow_in.xml</code></li>
    -+</ul>
    -+
    -+<p>Anda bisa meneruskan objek {@link android.view.animation.PathInterpolator} ke metode {@link
    -+android.animation.Animator#setInterpolator Animator.setInterpolator()}.</p>
    -+
    -+<p>Kelas {@link android.animation.ObjectAnimator} memiliki konstruktor-konstruktor baru yang memungkinkan Anda menganimasikan
    -+koordinat bersama sebuah path dengan menggunakan dua atau beberapa properti sekaligus. Misalnya, animator berikut
    -+menggunakan objek {@link android.graphics.Path} untuk menganimasikan properti X dan Y sebuah tampilan:</p>
    -+
    -+<pre>
    -+ObjectAnimator mAnimator;
    -+mAnimator = ObjectAnimator.ofFloat(view, View.X, View.Y, path);
    -+...
    -+mAnimator.start();
    -+</pre>
    -+
    -+
    -+<h2 id="ViewState">Menganimasikan Perubahan Status Tampilan</h2>
    -+
    -+<p>Kelas {@link android.animation.StateListAnimator} memungkinkan Anda mendefinisikan animator yang berjalan bila
    -+status tampilan berubah. Contoh berikut menampilkan cara mendefinisikan {@link
    -+android.animation.StateListAnimator} sebagai sumber daya XML:</p>
    -+
    -+<pre>
    -+&lt;!-- animate the translationZ property of a view when pressed -->
    -+&lt;selector xmlns:android="http://schemas.android.com/apk/res/android">
    -+  &lt;item android:state_pressed="true">
    -+    &lt;set>
    -+      &lt;objectAnimator android:propertyName="translationZ"
    -+        android:duration="@android:integer/config_shortAnimTime"
    -+        android:valueTo="2dp"
    -+        android:valueType="floatType"/>
    -+        &lt;!-- you could have other objectAnimator elements
    -+             here for "x" and "y", or other properties -->
    -+    &lt;/set>
    -+  &lt;/item>
    -+  &lt;item android:state_enabled="true"
    -+    android:state_pressed="false"
    -+    android:state_focused="true">
    -+    &lt;set>
    -+      &lt;objectAnimator android:propertyName="translationZ"
    -+        android:duration="100"
    -+        android:valueTo="0"
    -+        android:valueType="floatType"/>
    -+    &lt;/set>
    -+  &lt;/item>
    -+&lt;/selector>
    -+</pre>
    -+
    -+<p>Untuk menyertakan animasi status tampilan custom ke tampilan, definisikan animator menggunakan
    -+elemen <code>selector</code> dalam sumber daya file XML sebagaimana dalam contoh ini, dan tetapkan ke
    -+tampilan Anda dengan atribut <code>android:stateListAnimator</code>. Untuk menetapkan animator daftar status
    -+ke sebuah tampilan dalam kode Anda, gunakan metode {@link android.animation.AnimatorInflater#loadStateListAnimator
    -+AnimationInflater.loadStateListAnimator()}, dan tetapkan animator ke tampilan dengan
    -+metode {@link android.view.View#setStateListAnimator View.setStateListAnimator()}.</p>
    -+
    -+<p>Bila tema Anda memperluas tema bahan, tombol-tombol akan memiliki animasi Z secara default. Untuk menghindari
    -+perilaku ini di tombol Anda, aturlah atribut <code>android:stateListAnimator</code> ke
    -+<code>@null</code>.</p>
    -+
    -+<p>Kelas {@link android.graphics.drawable.AnimatedStateListDrawable} memungkinkan Anda membuat drawable
    -+yang menampilkan animasi di antara perubahan status tampilan terkait. Sebagian widget sistem di
    -+Android 5.0 menggunakan animasi ini secara default. Contoh berikut menampilkan cara
    -+mendefinisikan {@link android.graphics.drawable.AnimatedStateListDrawable} sebagai sumber daya XML:</p>
    -+
    -+<pre>
    -+&lt;!-- res/drawable/myanimstatedrawable.xml -->
    -+&lt;animated-selector
    -+    xmlns:android="http://schemas.android.com/apk/res/android">
    -+
    -+    &lt;!-- provide a different drawable for each state-->
    -+    &lt;item android:id="@+id/pressed" android:drawable="@drawable/drawableP"
    -+        android:state_pressed="true"/>
    -+    &lt;item android:id="@+id/focused" android:drawable="@drawable/drawableF"
    -+        android:state_focused="true"/>
    -+    &lt;item android:id="@id/default"
    -+        android:drawable="@drawable/drawableD"/>
    -+
    -+    &lt;!-- specify a transition -->
    -+    &lt;transition android:fromId="@+id/default" android:toId="@+id/pressed">
    -+        &lt;animation-list>
    -+            &lt;item android:duration="15" android:drawable="@drawable/dt1"/>
    -+            &lt;item android:duration="15" android:drawable="@drawable/dt2"/>
    -+            ...
    -+        &lt;/animation-list>
    -+    &lt;/transition>
    -+    ...
    -+&lt;/animated-selector>
    -+</pre>
    -+
    -+
    -+<h2 id="AnimVector">Menganimasikan Drawable Vektor</h2>
    -+
    -+<p><a href="{@docRoot}training/material/drawables.html#VectorDrawables">Drawable Vektor </a>
    -+bisa diubah skalanya tanpa kehilangan definisi. Kelas {@link android.graphics.drawable.AnimatedVectorDrawable}
    -+memungkinkan Anda menganimasikan properti drawable vektor.</p>
    -+
    -+<p>Anda biasanya mendefinisikan drawable vektor yang dianimasikan dalam tiga file XML:</p>
    -+
    -+<ul>
    -+<li>Drawable vektor dengan elemen <code>&lt;vector&gt;</code> dalam
    -+<code>res/drawable/</code></li>
    -+<li>Drawable vektor animasi dengan elemen <code>&lt;animated-vector&gt;</code> dalam
    -+<code>res/drawable/</code></li>
    -+<li>Satu atau beberapa animator objek dengan elemen <code>&lt;objectAnimator&gt;</code> dalam
    -+<code>res/anim/</code></li>
    -+</ul>
    -+
    -+<p>Drawable vektor yang dianimasikan bisa menganimasikan atribut elemen <code>&lt;group&gt;</code> dan
    -+<code>&lt;path&gt;</code>. Elemen <code>&lt;group&gt;</code> mendefinisikan satu set
    -+path atau subgrup, dan elemen <code>&lt;path&gt;</code> mendefinisikan path yang harus digambar.</p>
    -+
    -+<p>Bila Anda mendefinisikan drawable vektor yang ingin dianimasikan, gunakan atribut <code>android:name</code>
    -+untuk menetapkan nama unik ke grup dan path, sehingga Anda bisa merujuknya dari
    -+definisi animator Anda. Misalnya:</p>
    -+
    -+<pre>
    -+&lt;!-- res/drawable/vectordrawable.xml -->
    -+&lt;vector xmlns:android="http://schemas.android.com/apk/res/android"
    -+    android:height="64dp"
    -+    android:width="64dp"
    -+    android:viewportHeight="600"
    -+    android:viewportWidth="600">
    -+    &lt;group
    -+        <strong>android:name="rotationGroup"</strong>
    -+        android:pivotX="300.0"
    -+        android:pivotY="300.0"
    -+        android:rotation="45.0" >
    -+        &lt;path
    -+            <strong>android:name="v"</strong>
    -+            android:fillColor="#000000"
    -+            android:pathData="M300,70 l 0,-70 70,70 0,0 -70,70z" />
    -+    &lt;/group>
    -+&lt;/vector>
    -+</pre>
    -+
    -+<p>Definisi drawable vektor yang dianimasikan merujuk pada grup dan path dalam drawable vektor
    -+berdasarkan namanya:</p>
    -+
    -+<pre>
    -+&lt;!-- res/drawable/animvectordrawable.xml -->
    -+&lt;animated-vector xmlns:android="http://schemas.android.com/apk/res/android"
    -+  android:drawable="@drawable/vectordrawable" >
    -+    &lt;target
    -+        android:name="rotationGroup"
    -+        android:animation="@anim/rotation" />
    -+    &lt;target
    -+        android:name="v"
    -+        android:animation="@anim/path_morph" />
    -+&lt;/animated-vector>
    -+</pre>
    -+
    -+<p>Definisi animasi menyatakan objek {@link android.animation.ObjectAnimator} atau {@link
    -+android.animation.AnimatorSet}. Animator pertama dalam contoh ini memutar
    -+grup target sebanyak 360 derajat:</p>
    -+
    -+<pre>
    -+&lt;!-- res/anim/rotation.xml -->
    -+&lt;objectAnimator
    -+    android:duration="6000"
    -+    android:propertyName="rotation"
    -+    android:valueFrom="0"
    -+    android:valueTo="360" />
    -+</pre>
    -+
    -+<p>Animator kedua dalam contoh ini perlahan-lahan mengubah bentuk path drawable vektor dari satu bentuk ke
    -+bentuk yang lain. Kedua path harus kompatibel untuk morphing: keduanya harus memiliki jumlah perintah yang sama
    -+dan jumlah parameter yang sama untuk setiap perintah.</p>
    -+
    -+<pre>
    -+&lt;!-- res/anim/path_morph.xml -->
    -+&lt;set xmlns:android="http://schemas.android.com/apk/res/android">
    -+    &lt;objectAnimator
    -+        android:duration="3000"
    -+        android:propertyName="pathData"
    -+        android:valueFrom="M300,70 l 0,-70 70,70 0,0   -70,70z"
    -+        android:valueTo="M300,70 l 0,-70 70,0  0,140 -70,0 z"
    -+        android:valueType="pathType" />
    -+&lt;/set>
    -+</pre>
    -+
    -+<p>Untuk informasi selengkapnya, lihat referensi API bagi {@link
    -+android.graphics.drawable.AnimatedVectorDrawable}.</p>
    -diff --git a/docs/html-intl/intl/id/training/material/compatibility.jd b/docs/html-intl/intl/id/training/material/compatibility.jd
    -new file mode 100644
    -index 0000000..ef444c3
    ---- /dev/null
    -+++ b/docs/html-intl/intl/id/training/material/compatibility.jd
    -@@ -0,0 +1,168 @@
    -+page.title=Mempertahankan Kompatibilitas
    -+
    -+@jd:body
    -+
    -+<div id="tb-wrapper">
    -+<div id="tb">
    -+<h2>Pelajaran ini mengajarkan Anda cara</h2>
    -+<ol>
    -+  <li><a href="#Theme">Mendefinisikan Gaya Alternatif</a></li>
    -+  <li><a href="#Layouts">Menyediakan Layout Alternatif</a></li>
    -+  <li><a href="#SupportLib">Menggunakan Support Library</a></li>
    -+  <li><a href="#CheckVersion">Memeriksa Versi Sistem</a></li>
    -+</ol>
    -+<h2>Anda juga harus membaca</h2>
    -+<ul>
    -+  <li><a href="http://www.google.com/design/spec">Spesifikasi desain bahan</a></li>
    -+  <li><a href="{@docRoot}design/material/index.html">Desain bahan di Android</a></li>
    -+</ul>
    -+</div>
    -+</div>
    -+
    -+
    -+<p>Sebagian fitur desain bahan seperti tema bahan dan transisi aktivitas custom
    -+hanya tersedia pada Android 5.0 (API level 21) ke atas. Akan tetapi, Anda bisa mendesain aplikasi untuk menggunakan
    -+fitur-fitur ini saat dijalankan pada perangkat yang mendukung desain bahan dan tetap kompatibel
    -+dengan perangkat yang menjalankan rilis Android sebelumnya.</p>
    -+
    -+
    -+<h2 id="Theme">Mendefinisikan Gaya Alternatif</h2>
    -+
    -+<p>Anda bisa mengonfigurasi aplikasi untuk menggunakan tema bahan pada perangkat yang mendukungnya dan mengembalikan
    -+ke tema lama pada perangkat yang menjalankan versi Android terdahulu:</p>
    -+
    -+<ol>
    -+<li>Definisikan tema yang mewarisi tema lama (seperti Holo) di
    -+    <code>res/values/styles.xml</code>.</li>
    -+<li>Definisikan tema bernama sama yang mewarisi tema bahan di
    -+    <code>res/values-v21/styles.xml</code>.</li>
    -+<li>Atur tema ini sebagai tema aplikasi Anda dalam file manifes.</li>
    -+</ol>
    -+
    -+<p class="note"><strong>Catatan:</strong>
    -+Jika aplikasi Anda menggunakan tema bahan namun tidak menyediakan tema alternatif dengan cara ini,
    -+aplikasi itu tidak akan berjalan pada versi Android sebelum 5.0.
    -+</p>
    -+
    -+
    -+<h2 id="Layouts">Menyediakan Layout Alternatif</h2>
    -+
    -+<p>Jika layout yang Anda desain sesuai dengan panduan desain bahan tidak menggunakan salah satu
    -+atribut XML baru yang diperkenalkan di Android 5.0 (API level 21), layout itu akan berfungsi pada
    -+versi Android sebelumnya. Jika tidak, Anda bisa menyediakan layout alternatif. Anda juga bisa menyediakan
    -+layout alternatif untuk menyesuaikan cara aplikasi ditampilkan pada versi Android terdahulu.</p>
    -+
    -+<p>Buatlah file layout untuk Android 5.0 (API level 21) dalam <code>res/layout-v21/</code> dan
    -+file layout alternatif untuk versi Android terdahulu dalam <code>res/layout/</code>.
    -+Misalnya, <code>res/layout/my_activity.xml</code> adalah layout alternatif untuk
    -+<code>res/layout-v21/my_activity.xml</code>.</p>
    -+
    -+<p>Untuk menghindari duplikasi kode, definisikan gaya dalam <code>res/values/</code>, modifikasi
    -+gaya di <code>res/values-v21/</code> untuk API baru, dan gunakan pewarisan gaya, dengan mendefinisikan
    -+gaya dasar di <code>res/values/</code> dan mewarisi gaya di <code>res/values-v21/</code>.</p>
    -+
    -+
    -+<h2 id="SupportLib">Menggunakan Support Library</h2>
    -+
    -+<p><a href="{@docRoot}tools/support-library/features.html#v7">v7 Support Library</a>
    -+r21 ke atas menyertakan fitur desain bahan berikut:</p>
    -+
    -+<ul>
    -+<li><a href="{@docRoot}training/material/theme.html">Gaya desain bahan</a> untuk beberapa widget sistem
    -+    bila Anda menerapkan salah satu tema <code>Theme.AppCompat</code>.</li>
    -+<li><a href="{@docRoot}training/material/theme.html#ColorPalette">Atribut tema palet warna</a>
    -+    dalam tema <code>Theme.AppCompat</code>.</li>
    -+<li>Widget {@link android.support.v7.widget.RecyclerView} untuk <a href="{@docRoot}training/material/lists-cards.html#RecyclerView">
    -+menampilkan kumpulan data.</a></li>
    -+<li>Widget {@link android.support.v7.widget.CardView} untuk <a href="{@docRoot}training/material/lists-cards.html#CardView">membuat kartu</a>.</li>
    -+<li>Kelas {@link android.support.v7.graphics.Palette} untuk <a href="{@docRoot}training/material/drawables.html#ColorExtract">mengekstrak warna mencolok dari
    -+    gambar</a>.</li>
    -+</ul>
    -+
    -+<h3>Widget sistem</h3>
    -+
    -+<p>Tema-tema <code>Theme.AppCompat</code> menyediakan gaya desain bahan untuk widget ini:</p>
    -+
    -+<ul>
    -+  <li>{@link android.widget.EditText}</li>
    -+  <li>{@link android.widget.Spinner}</li>
    -+  <li>{@link android.widget.CheckBox}</li>
    -+  <li>{@link android.widget.RadioButton}</li>
    -+  <li>{@link android.support.v7.widget.SwitchCompat}</li>
    -+  <li>{@link android.widget.CheckedTextView}</li>
    -+</ul>
    -+
    -+<h3>Palet Warna</h3>
    -+
    -+<p>Untuk memperoleh gaya desain bahan dan menyesuaikan palet warna dengan Android v7 Support
    -+Library, terapkan salah satu tema <code>Theme.AppCompat</code>:</p>
    -+
    -+<pre>
    -+&lt;!-- extend one of the Theme.AppCompat themes -->
    -+&lt;style name="Theme.MyTheme" parent="Theme.AppCompat.Light">
    -+    &lt;!-- customize the color palette -->
    -+    &lt;item name="colorPrimary">@color/material_blue_500&lt;/item>
    -+    &lt;item name="colorPrimaryDark">@color/material_blue_700&lt;/item>
    -+    &lt;item name="colorAccent">@color/material_green_A200&lt;/item>
    -+&lt;/style>
    -+</pre>
    -+
    -+<h3>Daftar dan Kartu</h3>
    -+
    -+<p>Widget {@link android.support.v7.widget.RecyclerView} dan {@link
    -+android.support.v7.widget.CardView} tersedia di versi Android terdahulu melalui
    -+Android v7 Support Library dengan pembatasan ini:</p>
    -+<ul>
    -+<li>{@link android.support.v7.widget.CardView} memundurkan ke implementasi bayangan terprogram
    -+    dengan menggunakan pengisi tambahan.</li>
    -+<li>{@link android.support.v7.widget.CardView} tidak memangkas tampilan anaknya yang berpotongan
    -+    dengan sudut melengkung.</li>
    -+</ul>
    -+
    -+
    -+<h3>Dependensi</h3>
    -+
    -+<p>Untuk menggunakan fitur-fitur ini di versi Android sebelum 5.0 (API level 21), sertakan
    -+Android v7 Support Library dalam proyek Anda sebagai <a href="{@docRoot}sdk/installing/studio-build.html#dependencies">dependensi Gradle</a>:</p>
    -+
    -+<pre>
    -+dependencies {
    -+    compile 'com.android.support:appcompat-v7:21.0.+'
    -+    compile 'com.android.support:cardview-v7:21.0.+'
    -+    compile 'com.android.support:recyclerview-v7:21.0.+'
    -+}
    -+</pre>
    -+
    -+
    -+<h2 id="CheckVersion">Memeriksa Versi Sistem</h2>
    -+
    -+<p>Fitur berikut hanya tersedia di Android 5.0 (API level 21) ke atas:</p>
    -+
    -+<ul>
    -+<li>Transisi aktivitas</li>
    -+<li>Umpan balik sentuh</li>
    -+<li>Animasi membuka</li>
    -+<li>Animasi berbasis path</li>
    -+<li>Drawable vektor</li>
    -+<li>Pewarnaan drawable</li>
    -+</ul>
    -+
    -+<p>Untuk menjaga kompatibilitas dengan versi Android terdahulu, periksa {@link
    -+android.os.Build.VERSION#SDK_INT version} sistem saat runtime sebelum Anda memanggil API untuk salah satu
    -+fitur ini:</p>
    -+
    -+<pre>
    -+// Check if we're running on Android 5.0 or higher
    -+if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
    -+    // Call some material design APIs here
    -+} else {
    -+    // Implement this feature without material design
    -+}
    -+</pre>
    -+
    -+<p class="note"><strong>Catatan:</strong> Untuk menetapkan versi Android yang didukung aplikasi Anda,
    -+gunakan atribut <code>android:minSdkVersion</code> dan <code>android:targetSdkVersion</code>
    -+dalam file manifes. Untuk menggunakan fitur desain bahan di Android 5.0, atur
    -+atribut <code>android:targetSdkVersion</code> ke <code>21</code>. Untuk informasi selengkapnya, lihat
    -+panduan <a href="{@docRoot}guide/topics/manifest/uses-sdk-element.html">API
    -+&lt;uses-sdk&gt;</a>.</p>
    -diff --git a/docs/html-intl/intl/id/training/material/drawables.jd b/docs/html-intl/intl/id/training/material/drawables.jd
    -new file mode 100644
    -index 0000000..493abd4
    ---- /dev/null
    -+++ b/docs/html-intl/intl/id/training/material/drawables.jd
    -@@ -0,0 +1,126 @@
    -+page.title=Bekerja dengan Drawable
    -+
    -+@jd:body
    -+
    -+<div id="tb-wrapper">
    -+<div id="tb">
    -+<h2>Pelajaran ini mengajarkan Anda cara</h2>
    -+<ol>
    -+  <li><a href="#DrawableTint">Mewarnai Sumber Daya Drawable</a></li>
    -+  <li><a href="#ColorExtract">Mengekstrak Warna Mencolok dari Gambar</a></li>
    -+  <li><a href="#VectorDrawables">Membuat Drawable Vektor</a></li>
    -+</ol>
    -+<h2>Anda juga harus membaca</h2>
    -+<ul>
    -+  <li><a href="http://www.google.com/design/spec">Spesifikasi desain bahan</a></li>
    -+  <li><a href="{@docRoot}design/material/index.html">Desain bahan di Android</a></li>
    -+</ul>
    -+</div>
    -+</div>
    -+
    -+<p>Kemampuan berikut untuk drawable membantu Anda mengimplementasikan desain bahan dalam aplikasi Anda:</p>
    -+
    -+<ul>
    -+<li>Pewarnaan drawable</li>
    -+<li>Ekstraksi warna mencolok</li>
    -+<li>Drawable vektor</li>
    -+</ul>
    -+
    -+<p>Pelajaran ini menampilkan cara menggunakan fitur-fitur ini dalam aplikasi Anda.</p>
    -+
    -+
    -+<h2 id="DrawableTint">Mewarnai Sumber Daya Drawable</h2>
    -+
    -+<p>Dengan Android 5.0 (API level 21) ke atas, Anda bisa mewarnai bitmap dan sembilan-tambalan yang didefinisikan sebagai
    -+alpha-mask. Anda bisa mewarnainya dengan sumber daya warna atau atribut tema yang mencocokkan ke
    -+sumber daya warna (misalnya, <code>?android:attr/colorPrimary</code>). Biasanya, Anda membuat aset ini
    -+hanya sekali dan mewarnainya secara otomatis agar cocok dengan tema Anda.</p>
    -+
    -+<p>Anda bisa menerapkan warna ke objek {@link android.graphics.drawable.BitmapDrawable} atau {@link
    -+android.graphics.drawable.NinePatchDrawable} dengan metode {@code setTint()}. Anda juga bisa
    -+mengatur warna dan mode dalam layout dengan atribut <code>android:tint</code> dan
    -+<code>android:tintMode</code>.</p>
    -+
    -+
    -+<h2 id="ColorExtract">Mengekstrak Warna Mencolok dari Gambar</h2>
    -+
    -+<p>Android Support Library r21 ke atas menyertakan kelas {@link
    -+android.support.v7.graphics.Palette}, yang memungkinkan Anda mengekstrak warna mencolok dari gambar.
    -+Kelas ini mengekstrak warna mencolok berikut:</p>
    -+
    -+<ul>
    -+<li>Menyala</li>
    -+<li>Menyala pekat</li>
    -+<li>Menyala pucat</li>
    -+<li>Pudar</li>
    -+<li>Pudar pekat</li>
    -+<li>Pudar pucat</li>
    -+</ul>
    -+
    -+<p>Untuk mengekstrak warna-warna ini, teruskan objek {@link android.graphics.Bitmap} ke
    -+metode statis {@link android.support.v7.graphics.Palette#generate Palette.generate()} dalam
    -+thread latar belakang tempat Anda memuat gambar. Jika Anda tidak bisa menggunakan thread itu, panggil metode
    -+{@link android.support.v7.graphics.Palette#generateAsync Palette.generateAsync()} dan
    -+sediakan listener sebagai gantinya.</p>
    -+
    -+<p>Anda bisa mengambil warna mencolok dari gambar dengan metode getter di kelas
    -+<code>Palette</code>, misalnya <code>Palette.getVibrantColor</code>.</p>
    -+
    -+<p>Untuk menggunakan kelas {@link android.support.v7.graphics.Palette} dalam proyek Anda, tambahkan
    -+<a href="{@docRoot}sdk/installing/studio-build.html#dependencies">dependensi Gradle</a> berikut ke
    -+modul aplikasi Anda:</p>
    -+
    -+<pre>
    -+dependencies {
    -+    ...
    -+    compile 'com.android.support:palette-v7:21.0.0'
    -+}
    -+</pre>
    -+
    -+<p>Untuk informasi selengkapnya, lihat referensi API untuk kelas {@link android.support.v7.graphics.Palette}.
    -+</p>
    -+
    -+
    -+<h2 id="VectorDrawables">Membuat Drawable Vektor</h2>
    -+
    -+<!-- video box -->
    -+<a class="notice-developers-video" href="https://www.youtube.com/watch?v=wlFVIIstKmA" style="margin-top:18px">
    -+<div>
    -+    <h3>Video</h3>
    -+    <p>Grafis Vektor Android</p>
    -+</div>
    -+</a>
    -+
    -+<p>Di Android 5.0 (API Level 21) ke atas, Anda bisa mendefinisikan drawable vektor, yang berubah skala tanpa
    -+kehilangan definisi. Anda hanya memerlukan satu file aset per gambar vektor, bukan file aset untuk
    -+setiap densitas layar seperti pada gambar bitmap. Untuk membuat gambar vektor, Anda mendefinisikan detail
    -+bentuknya dalam sebuah elemen XML <code>&lt;vector&gt;</code>.</p>
    -+
    -+<p>Contoh berikut mendefinisikan gambar vektor berbentuk hati:</p>
    -+
    -+<pre>
    -+&lt;!-- res/drawable/heart.xml -->
    -+&lt;vector xmlns:android="http://schemas.android.com/apk/res/android"
    -+    &lt;!-- intrinsic size of the drawable -->
    -+    android:height="256dp"
    -+    android:width="256dp"
    -+    &lt;!-- size of the virtual canvas -->
    -+    android:viewportWidth="32"
    -+    android:viewportHeight="32">
    -+
    -+  &lt;!-- draw a path -->
    -+  &lt;path android:fillColor="#8fff"
    -+      android:pathData="M20.5,9.5
    -+                        c-1.955,0,-3.83,1.268,-4.5,3
    -+                        c-0.67,-1.732,-2.547,-3,-4.5,-3
    -+                        C8.957,9.5,7,11.432,7,14
    -+                        c0,3.53,3.793,6.257,9,11.5
    -+                        c5.207,-5.242,9,-7.97,9,-11.5
    -+                        C25,11.432,23.043,9.5,20.5,9.5z" />
    -+&lt;/vector>
    -+</pre>
    -+
    -+<p>Gambar vektor direpresentasikan di Android sebagai objek {@link android.graphics.drawable.VectorDrawable}.
    -+ Untuk informasi selengkapnya tentang sintaks <code>pathData</code>, lihat <a href="http://www.w3.org/TR/SVG11/paths.html#PathData">Referensi Path SVG</a>. Untuk informasi selengkapnya
    -+tentang menganimasikan properti drawable vektor, lihat
    -+<a href="{@docRoot}training/material/animations.html#AnimVector">Menganimasikan Drawable Vektor</a>.</p>
    -diff --git a/docs/html-intl/intl/id/training/material/get-started.jd b/docs/html-intl/intl/id/training/material/get-started.jd
    -new file mode 100644
    -index 0000000..1a551a9
    ---- /dev/null
    -+++ b/docs/html-intl/intl/id/training/material/get-started.jd
    -@@ -0,0 +1,171 @@
    -+page.title=Memulai
    -+
    -+@jd:body
    -+
    -+<div id="tb-wrapper">
    -+<div id="tb">
    -+<h2>Pelajaran ini mengajarkan Anda cara</h2>
    -+<ol>
    -+  <li><a href="#ApplyTheme">Menerapkan Tema Bahan</a></li>
    -+  <li><a href="#Layouts">Mendesain Layout Anda</a></li>
    -+  <li><a href="#Depth">Menetapkan Ketinggian di Tampilan Anda</a></li>
    -+  <li><a href="#ListsCards">Membuat Daftar dan Kartu</a></li>
    -+  <li><a href="#Animations">Menyesuaikan Animasi Anda</a></li>
    -+</ol>
    -+<h2>Anda juga harus membaca</h2>
    -+<ul>
    -+  <li><a href="http://www.google.com/design/spec">Spesifikasi desain bahan</a></li>
    -+  <li><a href="{@docRoot}design/material/index.html">Desain bahan di Android</a></li>
    -+</ul>
    -+</div>
    -+</div>
    -+
    -+
    -+<p>Untuk membuat aplikasi dengan desain bahan:</p>
    -+
    -+<ol>
    -+  <li style="margin-bottom:10px">
    -+    Tinjaulah <a href="http://www.google.com/design/spec">spesifikasi desain bahan</a>.</li>
    -+  <li style="margin-bottom:10px">
    -+    Terapkan <strong>tema</strong> bahan ke aplikasi Anda.</li>
    -+  <li style="margin-bottom:10px">
    -+    Buat <strong>layout</strong> agar mengikuti panduan desain bahan.</li>
    -+  <li style="margin-bottom:10px">
    -+    Tetapkan <strong>ketinggian</strong> tampilan Anda untuk menghasilkan bayangan.</li>
    -+  <li style="margin-bottom:10px">
    -+    Gunakan <strong>widget</strong> sistem untuk daftar dan kartu.</li>
    -+  <li style="margin-bottom:10px">
    -+    Sesuaikan <strong>animasi</strong> di aplikasi Anda.</li>
    -+</ol>
    -+
    -+<h3>Mempertahankan kompatibilitas mundur</h3>
    -+
    -+<p>Anda bisa menambahkan banyak fitur desain bahan ke aplikasi sekaligus mempertahankan kompatibilitas dengan
    -+versi Android sebelum 5.0. Untuk informasi selengkapnya, lihat
    -+<a href="{@docRoot}training/material/compatibility.html">Mempertahankan Kompatibilitas</a>.</p>
    -+
    -+<h3>Memperbarui aplikasi dengan desain bahan</h3>
    -+
    -+<p>Untuk memperbarui aplikasi yang ada guna memasukkan desain bahan, perbarui layout Anda dengan mengikuti
    -+panduan desain bahan. Juga pastikan memasukkan kedalaman, umpan balik sentuh, dan
    -+animasi.</p>
    -+
    -+<h3>Membuat aplikasi baru dengan desain bahan</h3>
    -+
    -+<p>Jika Anda sedang membuat aplikasi baru dengan fitur desain bahan, <a href="http://www.google.com/design/spec">panduan desain bahan</a> akan memberi Anda
    -+kerangka kerja desain yang kohesif. Ikuti panduan itu dan gunakan fungsionalitas baru di
    -+kerangka kerja Android untuk mendesain dan mengembangkan aplikasi Anda.</p>
    -+
    -+
    -+<h2 id="ApplyTheme">Menerapkan Tema Bahan</h2>
    -+
    -+<p>Untuk menerapkan tema bahan dalam aplikasi Anda, tetapkan gaya yang mewarisi
    -+<code>android:Theme.Material</code>:</p>
    -+
    -+<pre>
    -+&lt;!-- res/values/styles.xml -->
    -+&lt;resources>
    -+  &lt;!-- your theme inherits from the material theme -->
    -+  &lt;style name="AppTheme" parent="android:Theme.Material">
    -+    &lt;!-- theme customizations -->
    -+  &lt;/style>
    -+&lt;/resources>
    -+</pre>
    -+
    -+<p>Tema bahan menyediakan widget sistem terbaru yang memungkinkan Anda mengatur palet warnanya dan
    -+animasi default untuk umpan balik sentuh dan transisi aktivitas. Untuk detail selengkapnya, lihat
    -+<a href="{@docRoot}training/material/theme.html">Menggunakan Tema Bahan</a>.</p>
    -+
    -+
    -+<h2 id="Layouts">Mendesain Layout Anda</h2>
    -+
    -+<p>Selain menerapkan dan menyesuaikan tema bahan, layout Anda harus mematuhi
    -+<a href="http://www.google.com/design/spec">panduan desain bahan</a>. Bila Anda mendesain
    -+layout, berikan perhatian khusus pada hal-hal berikut:</p>
    -+
    -+<ul>
    -+<li>Petak patokan</li>
    -+<li>Garis utama</li>
    -+<li>Pengaturan Jarak</li>
    -+<li>Ukuran target sentuh</li>
    -+<li>Struktur layout</li>
    -+</ul>
    -+
    -+
    -+<h2 id="Depth">Menetapkan Ketinggian di Tampilan Anda</h2>
    -+
    -+<p>Tampilan bisa menghasilkan bayangan, dan nilai ketinggian tampilan
    -+menentukan ukuran bayangan dan urutan penggambarannya. Untuk mengatur ketinggian tampilan, gunakan
    -+atribut <code>android:elevation</code> dalam layout:</p>
    -+
    -+<pre>
    -+&lt;TextView
    -+    android:id="&#64;+id/my_textview"
    -+    android:layout_width="wrap_content"
    -+    android:layout_height="wrap_content"
    -+    android:text="&#64;string/next"
    -+    android:background="&#64;color/white"
    -+    android:elevation="5dp" />
    -+</pre>
    -+
    -+<p>Properti <code>translationZ</code> baru memungkinkan Anda membuat animasi yang mencerminkan
    -+perubahan sementara pada ketinggian tampilan. Perubahan ketinggian bisa berguna saat
    -+<a href="{@docRoot}training/material/animations.html#ViewState">merespons
    -+gerakan sentuh</a>.</p>
    -+
    -+<p>Untuk detail selengkapnya, lihat <a href="{@docRoot}training/material/shadows-clipping.html">Mendefinisikan
    -+Bayangan dan Memangkas Tampilan</a>.</p>
    -+
    -+
    -+<h2 id="ListsCards">Membuat Daftar dan Kartu</h2>
    -+
    -+<p>{@link android.support.v7.widget.RecyclerView} adalah versi {@link
    -+android.widget.ListView} yang lebih mudah dimasukkan dan mendukung beragam tipe layout serta memberikan peningkatan kinerja.
    -+{@link android.support.v7.widget.CardView} memungkinkan Anda menampilkan potongan informasi dalam kartu dengan
    -+tampilan konsisten di seluruh aplikasi. Contoh kode berikut memperagakan cara menyertakan
    -+{@link android.support.v7.widget.CardView} dalam layout Anda:</p>
    -+
    -+<pre>
    -+&lt;android.support.v7.widget.CardView
    -+    android:id="&#64;+id/card_view"
    -+    android:layout_width="200dp"
    -+    android:layout_height="200dp"
    -+    card_view:cardCornerRadius="3dp">
    -+    ...
    -+&lt;/android.support.v7.widget.CardView>
    -+</pre>
    -+
    -+<p>Untuk informasi selengkapnya, lihat <a href="{@docRoot}training/material/lists-cards.html">Membuat Daftar
    -+dan Kartu</a>.</p>
    -+
    -+
    -+<h2 id="Animations">Menyesuaikan Animasi Anda</h2>
    -+
    -+<p>Android 5.0 (API level 21) menyertakan API baru untuk membuat animasi custom di aplikasi Anda.
    -+Misalnya, Anda bisa mengaktifkan transisi aktivitas dan mendefinisikan transisi keluar di
    -+aktivitas:</p>
    -+
    -+<pre>
    -+public class MyActivity extends Activity {
    -+
    -+    &#64;Override
    -+    protected void onCreate(Bundle savedInstanceState) {
    -+        super.onCreate(savedInstanceState);
    -+        // enable transitions
    -+        getWindow().requestFeature(Window.FEATURE_CONTENT_TRANSITIONS);
    -+        setContentView(R.layout.activity_my);
    -+    }
    -+
    -+    public void onSomeButtonClicked(View view) {
    -+        getWindow().setExitTransition(new Explode());
    -+        Intent intent = new Intent(this, MyOtherActivity.class);
    -+        startActivity(intent,
    -+                      ActivityOptions
    -+                          .makeSceneTransitionAnimation(this).toBundle());
    -+    }
    -+}
    -+</pre>
    -+
    -+<p>Bila Anda memulai aktivitas lain dari aktivitas ini, transisi keluar akan diaktifkan.</p>
    -+
    -+<p>Untuk mengetahui selengkapnya tentang API animasi yang baru, lihat <a href="{@docRoot}training/material/animations.html">Mendefinisikan Animasi Custom</a>.</p>
    -diff --git a/docs/html-intl/intl/id/training/material/index.jd b/docs/html-intl/intl/id/training/material/index.jd
    -new file mode 100644
    -index 0000000..53697d2
    ---- /dev/null
    -+++ b/docs/html-intl/intl/id/training/material/index.jd
    -@@ -0,0 +1,60 @@
    -+page.title=Desain Bahan untuk Pengembang
    -+page.image=images/cards/material_2x.png
    -+page.metaDescription=Pelajari cara menerapkan desain bahan pada aplikasi Anda.
    -+
    -+
    -+@jd:body
    -+
    -+<div id="tb-wrapper">
    -+<div id="tb">
    -+  <h2>Dependensi dan Prasyarat</h2>
    -+  <ul>
    -+    <li>Android 5.0 (API Level 21)</li>
    -+  </ul>
    -+</div>
    -+</div>
    -+
    -+<p>Desain bahan adalah panduan komprehensif untuk desain visual, gerak, dan interaksi di
    -+berbagai platform dan perangkat. Untuk menggunakan desain bahan di aplikasi Android, ikuti panduan
    -+yang dijelaskan dalam
    -+<a href="http://www.google.com/design/spec/material-design/introduction.html">spesifikasi desain bahan
    -+</a> dan gunakan komponen serta fungsionalitas baru yang tersedia di Android 5.0
    -+(API level 21).</p>
    -+
    -+<p>Kelas ini menampilkan kepada Anda cara membuat aplikasi desain bahan dengan elemen-elemen berikut:</p>
    -+
    -+<ul>
    -+<li>Tema bahan</li>
    -+<li>Widget untuk kartu dan daftar</li>
    -+<li>Bayangan custom dan pemangkasan tampilan</li>
    -+<li>Drawable vektor</li>
    -+<li>Animasi custom</li>
    -+</ul>
    -+
    -+<p>Kelas ini juga mengajarkan cara mempertahankan kompatibilitas dengan versi Android sebelum
    -+5.0 (API level 21) bila Anda menggunakan fitur desain bahan dalam aplikasi.</p>
    -+
    -+<h2>Pelajaran</h2>
    -+
    -+<dl>
    -+  <dt><a href="{@docRoot}training/material/get-started.html">Memulai</a></dt>
    -+  <dd>Pelajari cara memperbarui aplikasi Anda dengan fitur desain bahan.</dd>
    -+
    -+  <dt><a href="{@docRoot}training/material/theme.html">Menggunakan Tema Bahan</a></dt>
    -+  <dd>Pelajari cara menerapkan gaya desain bahan pada aplikasi Anda.</dd>
    -+
    -+  <dt><a href="{@docRoot}training/material/lists-cards.html">Membuat Daftar dan Kartu</a></dt>
    -+  <dd>Pelajari cara membuat daftar dan kartu dengan tampilan dan cara kerja yang konsisten menggunakan widget sistem.</dd>
    -+
    -+  <dt><a href="{@docRoot}training/material/shadows-clipping.html">Mendefinisikan Bayangan dan Memangkas Tampilan</a></dt>
    -+  <dd>Pelajari cara mengatur elevasi tampilan Anda untuk membuat bayangan custom dan cara memangkas tampilan.</dd>
    -+
    -+  <dt><a href="{@docRoot}training/material/drawables.html">Bekerja dengan Drawable</a></dt>
    -+  <dd>Pelajari cara membuat drawable vektor dan cara mewarnai sumber daya drawable.</dd>
    -+
    -+  <dt><a href="{@docRoot}training/material/animations.html">Mendefinisikan Animasi Custom</a></dt>
    -+  <dd>Pelajari cara membuat animasi custom untuk tampilan dan transisi aktivitas dengan elemen bersama.</dd>
    -+
    -+  <dt><a href="{@docRoot}training/material/compatibility.html">Mempertahankan Kompatibilitas</a></dt>
    -+  <dd>Pelajari cara mempertahankan kompatibilitas dengan versi platform sebelum Android 5.0.</dd>
    -+</dl>
    -diff --git a/docs/html-intl/intl/id/training/material/lists-cards.jd b/docs/html-intl/intl/id/training/material/lists-cards.jd
    -new file mode 100644
    -index 0000000..46dd19a
    ---- /dev/null
    -+++ b/docs/html-intl/intl/id/training/material/lists-cards.jd
    -@@ -0,0 +1,266 @@
    -+page.title=Membuat Daftar dan Kartu
    -+
    -+@jd:body
    -+
    -+<div id="tb-wrapper">
    -+<div id="tb">
    -+<h2>Pelajaran ini mengajarkan Anda cara</h2>
    -+<ol>
    -+  <li><a href="#RecyclerView">Membuat Daftar</a></li>
    -+  <li><a href="#CardView">Membuat Kartu</a></li>
    -+  <li><a href="#Dependencies">Menambahkan Dependensi</a></li>
    -+</ol>
    -+<h2>Anda juga harus membaca</h2>
    -+<ul>
    -+  <li><a href="http://www.google.com/design/spec">Spesifikasi desain bahan</a></li>
    -+  <li><a href="{@docRoot}design/material/index.html">Desain bahan di Android</a></li>
    -+</ul>
    -+</div>
    -+</div>
    -+
    -+
    -+<p>Untuk membuat daftar dan kartu yang kompleks dengan gaya desain bahan di aplikasi, Anda bisa menggunakan widget
    -+{@link android.support.v7.widget.RecyclerView} dan {@link android.support.v7.widget.CardView}.
    -+</p>
    -+
    -+
    -+<h2 id="RecyclerView">Membuat Daftar</h2>
    -+
    -+<p>Widget {@link android.support.v7.widget.RecyclerView} adalah
    -+versi {@link android.widget.ListView} yang lebih maju dan fleksibel. Widget ini adalah kontainer untuk menampilkan set data
    -+besar yang bisa digulir secara sangat efisien dengan mempertahankan tampilan dalam jumlah terbatas. Gunakan
    -+widget {@link android.support.v7.widget.RecyclerView} bila Anda memiliki kumpulan data dengan elemen
    -+yang berubah saat runtime berdasarkan tindakan pengguna atau kejadian jaringan.</p>
    -+
    -+<p>Kelas {@link android.support.v7.widget.RecyclerView} menyederhanakan penampilan dan penanganan
    -+set data yang besar dengan menyediakan:</p>
    -+
    -+<ul>
    -+  <li>Pengelola layout untuk memosisikan item</li>
    -+  <li>Animasi default untuk operasi item umum, misalnya penghapusan atau penambahan item</li>
    -+</ul>
    -+
    -+<p>Anda juga memiliki keluwesan untuk mendefinisikan pengelola layout custom dan animasi untuk widget {@link
    -+android.support.v7.widget.RecyclerView}.</p>
    -+
    -+<img src="{@docRoot}training/material/images/RecyclerView.png" alt="" width="550" height="106" />
    -+<p class="img-caption">
    -+<strong>Gambar 1</strong>. Widget <code>RecyclerView</code>.
    -+</p>
    -+
    -+<p>Untuk menggunakan widget {@link android.support.v7.widget.RecyclerView}, Anda harus menetapkan
    -+adaptor dan pengelola layout. Untuk membuat adaptor, perluas kelas {@link
    -+android.support.v7.widget.RecyclerView.Adapter RecyclerView.Adapter}. Detail
    -+implementasi bergantung pada detail set data Anda dan tipe tampilan. Untuk informasi selengkapnya,
    -+ lihat <a href="#RVExamples">contoh-contoh</a> di bawah.</p>
    -+
    -+<div style="float:right">
    -+<img src="{@docRoot}design/material/images/list_mail.png" alt="" width="250" height="426" />
    -+<p class="img-caption" style="margin-left:8px">
    -+<strong>Gambar 2</strong> - Daftar berisi <code>RecyclerView</code>.
    -+</p>
    -+</div>
    -+
    -+<p><strong>Pengelola layout</strong> memosisikan tampilan item dalam {@link
    -+android.support.v7.widget.RecyclerView} dan menentukan waktu untuk menggunakan ulang tampilan item yang tidak
    -+lagi terlihat oleh pengguna. Untuk menggunakan ulang (atau <em>mendaur ulang</em>) tampilan, pengelola layout bisa meminta
    -+adaptor untuk mengganti konten tampilan dengan elemen lain dalam dataset. Mendaur ulang
    -+tampilan dengan cara ini akan meningkatkan kinerja karena menghindari pembuatan tampilan yang tidak diperlukan atau
    -+melakukan pencarian {@link android.app.Activity#findViewById findViewById()} yang mahal.</p>
    -+
    -+<p>{@link android.support.v7.widget.RecyclerView} menyediakan semua pengelola layout bawaan ini:</p>
    -+
    -+<ul>
    -+<li>{@link android.support.v7.widget.LinearLayoutManager} menampilkan item dalam
    -+daftar gulir vertikal atau horizontal.</li>
    -+<li>{@link android.support.v7.widget.GridLayoutManager} menampilkan item dalam petak.</li>
    -+<li>{@link android.support.v7.widget.StaggeredGridLayoutManager} menampilkan item dalam petak zigzag.</li>
    -+</ul>
    -+
    -+<p>Untuk membuat pengelola layout custom, perluas kelas {@link
    -+android.support.v7.widget.RecyclerView.LayoutManager RecyclerView.LayoutManager}.</p>
    -+
    -+<h3>Animasi</h3>
    -+
    -+<p>Animasi untuk menambahkan dan menghapus item diaktifkan secara default di {@link
    -+android.support.v7.widget.RecyclerView}. Untuk menyesuaikan animasi ini, perluas kelas
    -+{@link android.support.v7.widget.RecyclerView.ItemAnimator RecyclerView.ItemAnimator}dan gunakan
    -+metode {@link android.support.v7.widget.RecyclerView#setItemAnimator RecyclerView.setItemAnimator()}.
    -+</p>
    -+
    -+<h3 id="RVExamples">Contoh</h3>
    -+
    -+<p>Contoh kode berikut memperagakan cara menambahkan
    -+{@link android.support.v7.widget.RecyclerView} ke layout:</p>
    -+
    -+<pre>
    -+&lt;!-- A RecyclerView with some commonly used attributes -->
    -+&lt;android.support.v7.widget.RecyclerView
    -+    android:id="@+id/my_recycler_view"
    -+    android:scrollbars="vertical"
    -+    android:layout_width="match_parent"
    -+    android:layout_height="match_parent"/>
    -+</pre>
    -+
    -+<p>Begitu Anda menambahkan widget {@link android.support.v7.widget.RecyclerView} ke layout,
    -+dapatkan pengatur atau handle objek itu, hubungkan dengan pengelola layout, dan sertakan adaptor untuk data
    -+yang akan ditampilkan:</p>
    -+
    -+<pre>
    -+public class MyActivity extends Activity {
    -+    private RecyclerView mRecyclerView;
    -+    private RecyclerView.Adapter mAdapter;
    -+    private RecyclerView.LayoutManager mLayoutManager;
    -+
    -+    &#64;Override
    -+    protected void onCreate(Bundle savedInstanceState) {
    -+        super.onCreate(savedInstanceState);
    -+        setContentView(R.layout.my_activity);
    -+        mRecyclerView = (RecyclerView) findViewById(R.id.my_recycler_view);
    -+
    -+        // use this setting to improve performance if you know that changes
    -+        // in content do not change the layout size of the RecyclerView
    -+        mRecyclerView.setHasFixedSize(true);
    -+
    -+        // use a linear layout manager
    -+        mLayoutManager = new LinearLayoutManager(this);
    -+        mRecyclerView.setLayoutManager(mLayoutManager);
    -+
    -+        // specify an adapter (see also next example)
    -+        mAdapter = new MyAdapter(myDataset);
    -+        mRecyclerView.setAdapter(mAdapter);
    -+    }
    -+    ...
    -+}
    -+</pre>
    -+
    -+<p>Adaptor menyediakan akses ke item dataset Anda, membuat tampilan untuk item, dan
    -+mengganti konten sebagian tampilan dengan item data baru bila item semula tidak lagi
    -+terlihat. Contoh kode berikut menampilkan implementasi sederhana untuk sebuah dataset yang terdiri dari
    -+larik string yang ditampilkan dengan menggunakan widget {@link android.widget.TextView}:</p>
    -+
    -+<pre>
    -+public class MyAdapter extends RecyclerView.Adapter&lt;MyAdapter.ViewHolder> {
    -+    private String[] mDataset;
    -+
    -+    // Provide a reference to the views for each data item
    -+    // Complex data items may need more than one view per item, and
    -+    // you provide access to all the views for a data item in a view holder
    -+    public static class ViewHolder extends RecyclerView.ViewHolder {
    -+        // each data item is just a string in this case
    -+        public TextView mTextView;
    -+        public ViewHolder(TextView v) {
    -+            super(v);
    -+            mTextView = v;
    -+        }
    -+    }
    -+
    -+    // Provide a suitable constructor (depends on the kind of dataset)
    -+    public MyAdapter(String[] myDataset) {
    -+        mDataset = myDataset;
    -+    }
    -+
    -+    // Create new views (invoked by the layout manager)
    -+    &#64;Override
    -+    public MyAdapter.ViewHolder onCreateViewHolder(ViewGroup parent,
    -+                                                   int viewType) {
    -+        // create a new view
    -+        View v = LayoutInflater.from(parent.getContext())
    -+                               .inflate(R.layout.my_text_view, parent, false);
    -+        // set the view's size, margins, paddings and layout parameters
    -+        ...
    -+        ViewHolder vh = new ViewHolder(v);
    -+        return vh;
    -+    }
    -+
    -+    // Replace the contents of a view (invoked by the layout manager)
    -+    &#64;Override
    -+    public void onBindViewHolder(ViewHolder holder, int position) {
    -+        // - get element from your dataset at this position
    -+        // - replace the contents of the view with that element
    -+        holder.mTextView.setText(mDataset[position]);
    -+
    -+    }
    -+
    -+    // Return the size of your dataset (invoked by the layout manager)
    -+    &#64;Override
    -+    public int getItemCount() {
    -+        return mDataset.length;
    -+    }
    -+}
    -+</pre>
    -+
    -+
    -+<div style="float:right;margin-top:15px;margin-left:30px">
    -+<img src="{@docRoot}design/material/images/card_travel.png" alt="" width="225" height="383">
    -+<p class="img-caption" style="margin-left:12px">
    -+<strong>Gambar 3</strong>. Contoh kartu.
    -+</p>
    -+</div>
    -+
    -+<h2 id="CardView">Membuat Kartu</h2>
    -+
    -+<p>{@link android.support.v7.widget.CardView} memperluas kelas {@link android.widget.FrameLayout}
    -+dan memungkinkan Anda menampilkan informasi dalam kartu yang memiliki tampilan konsisten lintas platform. Widget {@link
    -+android.support.v7.widget.CardView} bisa memiliki bayangan dan sudut membulat.</p>
    -+
    -+<p>Untuk membuat kartu dengan bayangan, gunakan atribut <code>card_view:cardElevation</code>.
    -+{@link android.support.v7.widget.CardView} menggunakan elevasi nyata dan bayangan dinamis pada Android 5.0
    -+(API level 21) ke atas dan memundurkan ke implementasi bayangan terprogram pada versi terdahulu.
    -+Untuk informasi selengkapnya, lihat <a href="{@docRoot}training/material/compatibility.html">Mempertahankan
    -+Kompatibilitas</a>.</p>
    -+
    -+<p>Gunakan properti-properti ini untuk menyesuaikan penampilan
    -+widget {@link android.support.v7.widget.CardView}:</p>
    -+
    -+<ul>
    -+  <li>Untuk mengatur radius sudut pada layout Anda, gunakan atribut <code>card_view:cardCornerRadius</code>.
    -+</li>
    -+  <li>Untuk mengatur radius sudut dalam kode Anda, gunakan metode <code>CardView.setRadius</code>.</li>
    -+  <li>Untuk mengatur warna latar belakang kartu, gunakan atribut <code>card_view:cardBackgroundColor</code>.
    -+</li>
    -+</ul>
    -+
    -+<p>Contoh kode berikut menampilkan cara menyertakan widget {@link android.support.v7.widget.CardView}
    -+dalam layout:</p>
    -+
    -+<pre>
    -+&lt;LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    -+    xmlns:tools="http://schemas.android.com/tools"
    -+    xmlns:card_view="http://schemas.android.com/apk/res-auto"
    -+    ... >
    -+    &lt;!-- A CardView that contains a TextView -->
    -+    &lt;android.support.v7.widget.CardView
    -+        xmlns:card_view="http://schemas.android.com/apk/res-auto"
    -+        android:id="@+id/card_view"
    -+        android:layout_gravity="center"
    -+        android:layout_width="200dp"
    -+        android:layout_height="200dp"
    -+        card_view:cardCornerRadius="4dp">
    -+
    -+        &lt;TextView
    -+            android:id="@+id/info_text"
    -+            android:layout_width="match_parent"
    -+            android:layout_height="match_parent" />
    -+    &lt;/android.support.v7.widget.CardView>
    -+&lt;/LinearLayout>
    -+</pre>
    -+
    -+<p>Untuk informasi selengkapnya, lihat referensi API untuk {@link android.support.v7.widget.CardView}.</p>
    -+
    -+
    -+<h2 id="Dependencies">Menambahkan Dependensi</h2>
    -+
    -+<p>Widget {@link android.support.v7.widget.RecyclerView} dan {@link android.support.v7.widget.CardView}
    -+adalah bagian dari <a href="{@docRoot}tools/support-library/features.html#v7">v7 Support
    -+Library</a>. Untuk menggunakan widget dalam proyek Anda, tambahkan
    -+<a href="{@docRoot}sdk/installing/studio-build.html#dependencies">dependensi Gradle</a> ini ke
    -+modul aplikasi Anda:</p>
    -+
    -+<pre>
    -+dependencies {
    -+    ...
    -+    compile 'com.android.support:cardview-v7:21.0.+'
    -+    compile 'com.android.support:recyclerview-v7:21.0.+'
    -+}
    -+</pre>
    -diff --git a/docs/html-intl/intl/id/training/material/shadows-clipping.jd b/docs/html-intl/intl/id/training/material/shadows-clipping.jd
    -new file mode 100644
    -index 0000000..5431926
    ---- /dev/null
    -+++ b/docs/html-intl/intl/id/training/material/shadows-clipping.jd
    -@@ -0,0 +1,133 @@
    -+page.title=Mendefinisikan Bayangan dan Memangkas Tampilan
    -+
    -+@jd:body
    -+
    -+<div id="tb-wrapper">
    -+<div id="tb">
    -+<h2>Pelajaran ini mengajarkan Anda cara</h2>
    -+<ol>
    -+  <li><a href="#Elevation">Menetapkan Elevasi pada Tampilan Anda</a></li>
    -+  <li><a href="#Shadows">Menyesuaikan Bayangan dan Garis Luar Tampilan</a></li>
    -+  <li><a href="#Clip">Memangkas Tampilan</a></li>
    -+</ol>
    -+<h2>Anda juga harus membaca</h2>
    -+<ul>
    -+  <li><a href="http://www.google.com/design/spec">Spesifikasi desain bahan</a></li>
    -+  <li><a href="{@docRoot}design/material/index.html">Desain bahan di Android</a></li>
    -+</ul>
    -+</div>
    -+</div>
    -+
    -+<p>Desain bahan memperkenalkan elevasi untuk elemen-elemen UI. Elevasi membantu pengguna memahami
    -+arti penting relatif masing-masing elemen dan memfokuskan perhatian pada tugas yang ada.</p>
    -+
    -+<p>Elevasi tampilan, yang dinyatakan dengan properti Z, menentukan tampilan visual
    -+bayangannya: tampilan dengan nilai Z lebih tinggi menghasilkan bayangan lebih besar dan lebih halus. Tampilan dengan nilai Z lebih tinggi menutupi
    -+tampilan dengan nilai Z lebih rendah; akan tetapi, nilai Z tampilan tidak memengaruhi ukuran tampilan.</p>
    -+
    -+<p>Bayangan digambar oleh induk tampilan yang dinaikkan, sehingga terkena pemangkasan standar tampilan,
    -+yang dipangkas oleh induk secara default.</p>
    -+
    -+<p>Elevasi juga berguna untuk membuat animasi tempat memunculkan widget untuk sementara di atas
    -+bidang tampilan saat melakukan beberapa tindakan.</p>
    -+
    -+<p>Untuk informasi selengkapnya tentang elevasi dalam desain bahan, lihat
    -+<a href="http://www.google.com/design/spec/what-is-material/objects-in-3d-space.html">Objek
    -+di ruang 3D</a>.</p>
    -+
    -+
    -+<h2 id="Elevation">Menetapkan Elevasi pada Tampilan Anda</h2>
    -+
    -+<p>Nilai Z untuk tampilan memiliki dua komponen:
    -+
    -+<ul>
    -+<li>Elevasi: Komponen statis.</li>
    -+<li>Transformasi: Komponen dinamis yang digunakan untuk animasi.</li>
    -+</ul>
    -+
    -+<p><code>Z = elevation + translationZ</code></p>
    -+
    -+<img src="{@docRoot}training/material/images/shadows-depth.png" width="580" height="261" alt="" />
    -+<p class="img-caption"><strong>Gambar 1</strong> - Bayangan untuk berbagai elevasi tampilan.</p>
    -+
    -+<p>Untuk mengatur elevasi tampilan dalam definisi layout, gunakan atribut <code>android:elevation</code>.
    -+ Untuk mengatur elevasi tampilan dalam kode aktivitas, gunakan
    -+metode {@link android.view.View#setElevation View.setElevation()}.</p>
    -+
    -+<p>Untuk mengatur transformasi tampilan, gunakan metode {@link android.view.View#setTranslationZ
    -+View.setTranslationZ()}.</p>
    -+
    -+<p>Metode {@link android.view.ViewPropertyAnimator#z ViewPropertyAnimator.z()} dan {@link
    -+android.view.ViewPropertyAnimator#translationZ ViewPropertyAnimator.translationZ()} yang baru memudahkan
    -+Anda menganimasikan elevasi tampilan. Untuk informasi selengkapnya, lihat referensi API untuk
    -+{@link android.view.ViewPropertyAnimator} dan panduan pengembang <a href="{@docRoot}guide/topics/graphics/prop-animation.html">Animasi Properti</a>.
    -+</p>
    -+
    -+<p>Anda juga bisa menggunakan {@link android.animation.StateListAnimator}
    -+untuk menetapkan animasi ini secara deklaratif. Ini khususnya berguna bila
    -+perubahan status memicu animasi, seperti saat seorang pengguna menekan tombol. Untuk informasi selengkapnya, lihat
    -+<a href="{@docRoot}training/material/animations.html#ViewState">Menganimasikan Perubahan Status Tampilan</a>.</p>
    -+
    -+<p>Nilai Z diukur dengan satuan dp (density-independent pixel).</p>
    -+
    -+
    -+<h2 id="Shadows">Menyesuaikan Bayangan dan Garis Luar Tampilan</h2>
    -+
    -+<p>Batas-batas drawable latar belakang tampilan menentukan bentuk default bayangannya.
    -+<strong>Garis luar</strong> menyatakan bentuk luar objek grafis dan mendefinisikan
    -+bidang riak untuk umpan balik sentuh.</p>
    -+
    -+<p>Perhatikan tampilan ini, yang didefinisikan dengan drawable latar belakang:</p>
    -+
    -+<pre>
    -+&lt;TextView
    -+    android:id="@+id/myview"
    -+    ...
    -+    android:elevation="2dp"
    -+    android:background="@drawable/myrect" />
    -+</pre>
    -+
    -+<p>Drawable latar belakang didefinisikan sebagai persegi panjang dengan sudut membulat:</p>
    -+
    -+<pre>
    -+&lt;!-- res/drawable/myrect.xml -->
    -+&lt;shape xmlns:android="http://schemas.android.com/apk/res/android"
    -+       android:shape="rectangle">
    -+    &lt;solid android:color="#42000000" />
    -+    &lt;corners android:radius="5dp" />
    -+&lt;/shape>
    -+</pre>
    -+
    -+<p>Tampilan ini menghasilkan bayangan dengan sudut membulat, karena drawable latar belakang mendefinisikan
    -+garis luar tampilan. Memberikan garis luar custom akan mengesampingkan bentuk default bayangan tampilan.</p>
    -+
    -+<p>Untuk mendefinisikan garis luar custom suatu tampilan dalam kode Anda:<p>
    -+
    -+<ol>
    -+<li>Perluas kelas {@link android.view.ViewOutlineProvider}.</li>
    -+<li>Kesampingkan metode {@link android.view.ViewOutlineProvider#getOutline getOutline()}.</li>
    -+<li>Tetapkan penyedia garis luar baru untuk tampilan Anda dengan metode {@link
    -+android.view.View#setOutlineProvider View.setOutlineProvider()}.</li>
    -+</ol>
    -+
    -+<p>Anda bisa membuat garis luar lonjong dan persegi panjang yang bersudut membulat dengan menggunakan metode dalam
    -+kelas {@link android.graphics.Outline}. Penyedia garis luar default untuk tampilan memperoleh garis luar
    -+dari latar belakang tampilan. Untuk mencegah tampilan menghasilkan bayangan, atur penyedia garis luarnya
    -+ke <code>null</code>.</p>
    -+
    -+
    -+<h2 id="Clip">Memangkas Tampilan</h2>
    -+
    -+<p>Memangkas tampilan memudahkan Anda mengubah bentuk tampilan. Anda bisa memangkas tampilan agar
    -+konsistensi dengan elemen desain lainnya atau mengubah bentuk tampilan untuk merespons input pengguna.
    -+Anda bisa memangkas tampilan hingga area garis luarnya dengan menggunakan metode {@link android.view.View#setClipToOutline
    -+View.setClipToOutline()} atau atribut <code>android:clipToOutline</code>. Hanya
    -+garis-garis luar persegi panjang, lingkaran, dan persegi panjang bersudut bulat yang mendukung pemangkasan, seperti yang ditentukan oleh
    -+metode {@link android.graphics.Outline#canClip Outline.canClip()}.</p>
    -+
    -+<p>Untuk memangkas tampilan ke bentuk drawable, atur drawable sebagai latar belakang tampilan
    -+(seperti yang ditampilkan di atas) dan panggil metode {@link android.view.View#setClipToOutline View.setClipToOutline()}.
    -+</p>
    -+
    -+<p>Memangkas tampilan adalah operasi yang mahal; jadi, jangan animasikan bentuk yang Anda gunakan
    -+untuk memangkas tampilan. Untuk memperoleh efek ini, gunakan animasi <a href="{@docRoot}training/material/animations.html#Reveal">Reveal Effect</a>.</p>
    -diff --git a/docs/html-intl/intl/id/training/material/theme.jd b/docs/html-intl/intl/id/training/material/theme.jd
    -new file mode 100644
    -index 0000000..5acdcd2
    ---- /dev/null
    -+++ b/docs/html-intl/intl/id/training/material/theme.jd
    -@@ -0,0 +1,131 @@
    -+page.title=Menggunakan Tema Bahan
    -+
    -+@jd:body
    -+
    -+<div id="tb-wrapper">
    -+<div id="tb">
    -+<h2>Pelajaran ini mengajarkan Anda cara</h2>
    -+<ol>
    -+  <li><a href="#ColorPalette">Menyesuaikan Palet Warna</a></li>
    -+  <li><a href="#StatusBar">Menyesuaikan Baris Status</a></li>
    -+  <li><a href="#Inheritance">Tampilan Setiap Tema</a></li>
    -+</ol>
    -+<h2>Anda juga harus membaca</h2>
    -+<ul>
    -+  <li><a href="http://www.google.com/design/spec">Spesifikasi desain bahan</a></li>
    -+  <li><a href="{@docRoot}design/material/index.html">Desain bahan di Android</a></li>
    -+</ul>
    -+</div>
    -+</div>
    -+
    -+
    -+<p>Tema bahan yang baru menyediakan:</p>
    -+
    -+<ul>
    -+  <li>Widget sistem yang memungkinkan Anda mengatur palet warnanya</li>
    -+  <li>Animasi umpan balik sentuh untuk widget sistem</li>
    -+  <li>Animasi transisi aktivitas</li>
    -+</ul>
    -+
    -+<p>Anda bisa menyesuaikan tampilan tema bahan
    -+sesuai dengan identitas merek Anda dengan palet warna yang Anda kontrol. Anda bisa mewarnai action-bar dan
    -+baris status dengan menggunakan atribut tema, seperti yang ditampilkan dalam <a href="#fig3">Gambar 3</a>.</p>
    -+
    -+<p>Widget sistem memiliki desain baru dan animasi umpan balik sentuh. Anda bisa menyesuaikan
    -+palet warna, animasi umpan balik sentuh, dan transisi aktivitas untuk aplikasi.</p>
    -+
    -+<p>Tema bahan didefinisikan sebagai:</p>
    -+
    -+<ul>
    -+  <li><code>@android:style/Theme.Material</code> (versi gelap)</li>
    -+  <li><code>@android:style/Theme.Material.Light</code> (versi terang)</li>
    -+  <li><code>@android:style/Theme.Material.Light.DarkActionBar</code></li>
    -+</ul>
    -+
    -+<p>Untuk daftar gaya bahan yang bisa Anda gunakan, lihat referensi API untuk
    -+{@link android.R.style R.style}.</p>
    -+
    -+<!-- two columns, dark/light material theme example -->
    -+<div style="width:700px;margin-top:25px;margin-bottom:10px">
    -+<div style="float:left;width:250px;margin-left:40px;margin-right:60px;">
    -+  <img src="{@docRoot}design/material/images/MaterialDark.png" width="500" height="238">
    -+  <div style="width:170px;margin:0 auto">
    -+  <p style="margin-top:8px;font-size:12px"><strong>Gambar 1</strong>. Tema bahan gelap</p>
    -+  </div>
    -+</div>
    -+<div style="float:left;width:250px;margin-right:0px;">
    -+  <img src="{@docRoot}design/material/images/MaterialLight.png" width="500" height="238">
    -+  <div style="width:170px;margin:0 auto">
    -+  <p style="margin-top:8px;font-size:12px"><strong>Gambar 2</strong>. Tema bahan terang</p>
    -+  </div>
    -+</div>
    -+<br style="clear:left">
    -+</div>
    -+
    -+<p class="note">
    -+<strong>Catatan:</strong> Tema bahan hanya tersedia di Android 5.0 (API level 21)
    -+ke atas. <a href="{@docRoot}tools/support-library/features.html#v7">v7 Support Library</a>
    -+menyediakan tema dengan gaya desain bahan untuk beberapa widget dan dukungan untuk menyesuaikan
    -+palet warna. Untuk informasi selengkapnya, lihat
    -+<a href="{@docRoot}training/material/compatibility.html">Mempertahankan Kompatibilitas</a>.
    -+</p>
    -+
    -+
    -+<h2 id="ColorPalette">Menyesuaikan Palet Warna</h2>
    -+
    -+<p style="margin-bottom:30px">Untuk menyesuaikan warna dasar tema agar cocok dengan merek Anda, definisikan
    -+warna custom menggunakan atribut tema saat Anda mewariskan dari tema bahan:</p>
    -+
    -+<pre>
    -+&lt;resources>
    -+  &lt;!-- inherit from the material theme -->
    -+  &lt;style name="AppTheme" parent="android:Theme.Material">
    -+    &lt;!-- Main theme colors -->
    -+    &lt;!--   your app branding color for the app bar -->
    -+    &lt;item name="android:colorPrimary">@color/primary&lt;/item>
    -+    &lt;!--   darker variant for the status bar and contextual app bars -->
    -+    &lt;item name="android:colorPrimaryDark">@color/primary_dark&lt;/item>
    -+    &lt;!--   theme UI controls like checkboxes and text fields -->
    -+    &lt;item name="android:colorAccent">@color/accent&lt;/item>
    -+  &lt;/style>
    -+&lt;/resources>
    -+</pre>
    -+
    -+<div style="float:right;margin-left:25px;margin-top:20px;margin-bottom:10px" id="fig3">
    -+<img src="{@docRoot}training/material/images/ThemeColors.png" width="250" height="445" />
    -+<p class="img-caption" style="margin-bottom:0px">
    -+<strong>Gambar 3.</strong> Menyesuaikan tema bahan.</p>
    -+</div>
    -+
    -+
    -+<h2 id="StatusBar">Menyesuaikan Baris Status</h2>
    -+
    -+<p>Tema bahan memungkinkan Anda menyesuaikan baris status dengan mudah; jadi Anda bisa menetapkan
    -+warna yang cocok dengan merek Anda dan memberikan kontras yang cukup untuk menampilkan ikon status putih. Untuk
    -+mengatur warna custom bagi baris status, gunakan atribut <code>android:statusBarColor</code> bila
    -+Anda memperluas tema bahan. Secara default, <code>android:statusBarColor</code> mewarisi
    -+nilai <code>android:colorPrimaryDark</code>.</p>
    -+
    -+<p>Anda juga bisa menggambar sendiri di belakang baris status. Misalnya, jika Anda ingin menampilkan
    -+baris status secara transparan di atas foto, dengan gradasi gelap yang halus untuk memastikan
    -+ikon status putih tetap terlihat. Caranya, atur atribut <code>android:statusBarColor</code> ke
    -+<code>&#64;android:color/transparent</code> dan sesuaikan flag jendela seperti yang diperlukan. Anda juga bisa
    -+menggunakan metode {@link android.view.Window#setStatusBarColor Window.setStatusBarColor()} untuk
    -+animasi atau pemudaran.</p>
    -+
    -+<p class="note">
    -+<strong>Catatan:</strong> Baris status harus selalu memiliki delineasi yang jelas dari
    -+toolbar utama, kecuali bila Anda menampilkan gambar detail atau konten media tepi-ke-tepi di belakang
    -+baris ini dan bila Anda menggunakan gradasi untuk memastikan ikon tetap terlihat.
    -+</p>
    -+
    -+<p>Bila Anda menyesuaikan baris navigasi dan baris status, jadikan keduanya transparan atau modifikasi
    -+baris status saja. Baris navigasi harus tetap hitam di semua kasus lainnya.</p>
    -+
    -+
    -+<h2 id="Inheritance">Tampilan Setiap Tema</h3>
    -+
    -+<p>Elemen dalam definisi layout XML bisa menetapkan atribut <code>android:theme</code>,
    -+yang merujuk sumber daya tema. Atribut ini memodifikasi tema untuk elemen itu dan setiap
    -+elemen anak, yang berguna untuk mengubah palet warna tema dalam porsi tertentu
    -+pada antarmuka.</p>
    -diff --git a/docs/html-intl/intl/id/training/tv/playback/picture-in-picture.jd b/docs/html-intl/intl/id/training/tv/playback/picture-in-picture.jd
    -new file mode 100644
    -index 0000000..41af6de
    ---- /dev/null
    -+++ b/docs/html-intl/intl/id/training/tv/playback/picture-in-picture.jd
    -@@ -0,0 +1,213 @@
    -+page.title=Gambar-dalam-gambar
    -+page.keywords=pratinjau,sdk,PIP,Gambar-dalam-gambar
    -+page.tags=androidn
    -+
    -+@jd:body
    -+
    -+<div id="tb-wrapper">
    -+<div id="tb">
    -+
    -+<h2>Dalam dokumen ini</h2>
    -+<ol>
    -+  <li><a href="#declaring">Mendeklarasikan Bahwa Aktivitas Anda Mendukung
    -+Gambar-dalam-gambar</a></li>
    -+  <li><a href="#pip_button">Mengalihkan Aktivitas Anda ke Gambar-dalam-gambar</a>
    -+</li>
    -+  <li><a href="#handling_ui">Menangani UI Selama Gambar-dalam-gambar</a>
    -+</li>
    -+  <li><a href="#continuing_playback">Melanjutkan Pemutaran Video Saat dalam
    -+Gambar-dalam-gambar</a></li>
    -+  <li><a href="#single_playback">Menggunakan Aktivitas Pemutaran Tunggal untuk
    -+ Gambar-dalam-gambar</a></li>
    -+  <li><a href="#best">Praktik Terbaik</a></li>
    -+</ol>
    -+
    -+<h2>Lihat Juga</h2>
    -+<ol>
    -+  <li><a href="{@docRoot}preview/features/multi-window.html">Dukungan
    -+Multi-Jendela</a></li>
    -+</ol>
    -+
    -+</div>
    -+</div>
    -+
    -+<p>Di Android N, pengguna Android TV sekarang bisa menonton video
    -+dalam jendela yang disematkan di sudut layar saat menyusuri
    -+aplikasi. Mode gambar-dalam-gambar (PIP) memungkinkan aplikasi menjalankan aktivitas
    -+video dalam jendela yang disematkan selagi aktivitas lain tetap berjalan di
    -+latar belakang. Jendela PIP memungkinkan pengguna melakukan multitasking saat menggunakan aplikasi Anda, yang
    -+membantu pengguna menjadi lebih produktif.</p>
    -+
    -+<p>Aplikasi Anda bisa memutuskan kapan memicu mode PIP. Inilah beberapa contoh
    -+kapan memasuki mode PIP:</p>
    -+
    -+<ul>
    -+<li>Aplikasi Anda bisa memindahkan video ke dalam mode PIP bila pengguna mengarah
    -+mundur dari video untuk menjelajah materi lainnya.</li>
    -+<li>Aplikasi Anda bisa mengalihkan video ke dalam mode PIP selagi pengguna menonton akhir episode
    -+dari materi. Layar utama menampilkan informasi
    -+promosi atau rangkuman tentang episode berikutnya dalam seri tersebut.</li>
    -+<li>Aplikasi Anda bisa menyediakan suatu cara bagi pengguna untuk mengantre materi tambahan selagi
    -+mereka menonton video. Video terus dimainkan dalam mode PIP selagi layar
    -+utama menampilkan aktivitas pemilihan materi.</li>
    -+</ul>
    -+
    -+<p>Jendela PIP memiliki luas 240x135 dp dan ditampilkan di layer paling atas pada salah satu
    -+dari empat sudut layar, yang dipilih oleh sistem. Pengguna bisa memunculkan
    -+menu PIP yang memungkinkan mereka untuk beralih mode dari jendela PIP ke layar penuh, atau menutup jendela
    -+PIP, dengan menekan dan menahan tombol <b>Beranda</b> pada remote. Jika video
    -+lain mulai diputar pada layar utama, jendela PIP secara otomatis
    -+ditutup. Pengguna juga bisa menutup jendela PIP melalui Recents.</p>
    -+
    -+<img src="{@docRoot}images/android-7.0/pip-active.png" />
    -+<p class="img-caption"><strong>Gambar 1.</strong> Video
    -+Gambar-dalam-gambar terlihat di sudut layar selagi pengguna menjelajahi materi pada layar
    -+utama.</p>
    -+
    -+<p>PIP memanfaatkan API multi-jendela yang tersedia di Android N untuk
    -+menyediakan jendela hamparan video yang disematkan. Untuk menambahkan PIP ke aplikasi, Anda harus
    -+mendaftarkan aktivitas yang mendukung PIP, mengalihkan aktivitas Anda ke mode PIP bila
    -+diperlukan, serta memastikan elemen UI disembunyikan dan pemutaran video berlanjut bila
    -+aktivitas dalam mode PIP.</p>
    -+
    -+<h2 id="declaring">Mendeklarasikan Bahwa Aktivitas Anda Mendukung Gambar-dalam-gambar</h2>
    -+
    -+<p>Secara default, sistem tidak secara otomatis mendukung PIP untuk aplikasi.
    -+Jika Anda ingin mendukung PIP dalam aplikasi, daftarkan aktivitas
    -+video Anda dalam manifes dengan menyetel
    -+<code>android:supportsPictureInPicture</code> dan
    -+<code>android:resizeableActivity</code> ke <code>true</code>. Juga, tetapkan
    -+bahwa aktivitas Anda menangani perubahan konfigurasi layout sehingga aktivitas
    -+Anda tidak diluncurkan ulang saat terjadi perubahan layout selama transisi mode PIP.</p>
    -+
    -+<pre>
    -+&lt;activity android:name="VideoActivity"
    -+    android:resizeableActivity="true"
    -+    android:supportsPictureInPicture="true"
    -+    android:configChanges=
    -+        "screenSize|smallestScreenSize|screenLayout|orientation"
    -+    ...
    -+</pre>
    -+
    -+<p>Saat mendaftarkan aktivitas Anda, ingatlah bahwa dalam mode PIP aktivitas
    -+Anda akan ditampilkan pada jendela hamparan kecil pada layar TV. Aktivitas
    -+pemutaran video dengan UI minimal akan memberikan pengalaman pengguna terbaik. Aktivitas yang
    -+mengandung elemen UI kecil mungkin tidak memberikan pengalaman pengguna yang baik
    -+ketika beralih ke mode PIP, karena pengguna tidak dapat melihat elemen UI secara jelas
    -+di jendela PIP.</p>
    -+
    -+<h2 id="pip_button">Mengalihkan Aktivitas Anda ke Gambar-dalam-gambar</h2>
    -+
    -+Bila Anda perlu untuk mengalihkan aktivitas ke mode PIP, panggil
    -+<code>Activity.enterPictureInPictureMode()</code>. Contoh berikut mengalihkan
    -+ke mode PIP bila pengguna memilih tombol PIP khusus pada baris
    -+kontrol media:</p>
    -+
    -+<pre>
    -+&#64;Override
    -+public void onActionClicked(Action action) {
    -+    if (action.getId() == R.id.lb_control_picture_in_picture) {
    -+        getActivity().enterPictureInPictureMode();
    -+        return;
    -+    }
    -+    ...
    -+</pre>
    -+
    -+<p>Menambahkan tombol PIP ke baris kontrol media Anda akan memungkinkan pengguna dengan mudah beralih
    -+ke mode PIP selagi mengontrol pemutaran video.</p>
    -+
    -+<img src="{@docRoot}images/android-7.0/pip-button.png" />
    -+<p class="img-caption"><strong>Gambar 1.</strong> Tombol
    -+gambar-dalam-gambar pada baris kontrol media.</p>
    -+
    -+<p>Android N menyertakan kelas
    -+<code>PlaybackControlsRow.PictureInPictureAction</code> baru yang mendefinisikan
    -+tindakan PIP baris kontrol dan menggunakan ikon PIP.</p>
    -+
    -+<h2 id="handling_ui">Menangani UI Selama Gambar-dalam-gambar</h2>
    -+
    -+<p>Bila aktivitas memasuki mode PIP, aktivitas Anda seharusnya hanya menampilkan pemutaran
    -+video. Buang elemen UI sebelum aktivitas Anda memasuki PIP,
    -+dan pulihkan elemen ini bila aktivitas Anda beralih ke layar penuh lagi.
    -+Ganti <code>Activity.onPictureInPictureModeChanged()</code> atau
    -+<code>Fragment.onPictureInPictureModeChanged()</code> dan aktifkan atau
    -+nonaktifkan elemen UI saat diperlukan, misalnya:</p>
    -+
    -+<pre>
    -+&#64;Override
    -+public void onPictureInPictureModeChanged(boolean isInPictureInPictureMode) {
    -+    if (isInPictureInPictureMode) {
    -+        // Hide the controls in picture-in-picture mode.
    -+        ...
    -+    } else {
    -+        // Restore the playback UI based on the playback status.
    -+        ...
    -+    }
    -+}
    -+</pre>
    -+
    -+<h2 id="continuing_playback">Melanjutkan Pemutaran Video Saat dalam
    -+Gambar-dalam-gambar</h2>
    -+
    -+<p>Bila aktivitas Anda beralih ke PIP, sistem akan menganggap aktivitas tersebut berada dalam
    -+keadaan berhenti sementara, dan akan memanggil metode <code>onPause()</code> aktivitas Anda. Pemutaran
    -+video tidak boleh berhenti sementara dan harus terus diputar jika aktivitas tersebut
    -+berhenti sementara karena mode PIP. Periksa PIP dalam metode
    -+<code>onPause()</code> aktivitas Anda dan tangani pemutaran dengan tepat,
    -+misalnya:</p>
    -+
    -+<pre>
    -+&#64;Override
    -+public void onPause() {
    -+    // If called while in PIP mode, do not pause playback
    -+    if (isInPictureInPictureMode()) {
    -+        // Continue playback
    -+        ...
    -+    }
    -+    // If paused but not in PIP, pause playback if necessary
    -+    ...
    -+}
    -+</pre>
    -+
    -+<p>Bila aktivitas meninggalkan mode PIP dan kembali ke mode layar penuh, sistem
    -+akan melanjutkan aktivitas Anda dan memanggil metode <code>onResume()</code>.</p>
    -+
    -+<h2 id="single_playback">Menggunakan Aktivitas Pemutaran Tunggal untuk
    -+ Gambar-dalam-gambar</h2>
    -+
    -+<p>Di aplikasi Anda, seorang pengguna bisa memilih video baru saat menyusuri materi di
    -+layar utama, selagi aktivitas pemutaran video dalam mode PIP. Putar
    -+video baru di aktivitas pemutaran yang ada dalam mode layar penuh, sebagai ganti
    -+meluncurkan aktivitas baru yang dapat membingungkan pengguna.</p>
    -+
    -+<p>Guna memastikan aktivitas tunggal digunakan untuk permintaan pemutaran video dan
    -+beralih ke atau dari mode PIP bila dibutuhkan, setel
    -+<code>android:launchMode</code> aktivitas ke <code>singleTask</code> dalam manifes Anda:
    -+</p>
    -+
    -+<pre>
    -+&lt;activity android:name="VideoActivity"
    -+    ...
    -+    android:supportsPictureInPicture="true"
    -+    android:launchMode="singleTask"
    -+    ...
    -+</pre>
    -+
    -+<p>Di aktivitas Anda, ganti {@link android.app.Activity#onNewIntent
    -+Activity.onNewIntent()} dan tangani video baru, yang akan menghentikan pemutaran video
    -+jika diperlukan.</p>
    -+
    -+<h2 id="best">Praktik Terbaik</h2>
    -+
    -+<p>PIP ditujukan untuk aktivitas yang memutar video layar penuh. Saat mengalihkan
    -+aktivitas Anda ke mode PIP, hindari menampilkan apa pun selain materi video.
    -+Pantau saat aktivitas Anda memasuki mode PIP dan sembunyikan elemen UI, seperti dijelaskan
    -+dalam <a href="#handling_ui">Menangani UI Selama Gambar-dalam-gambar</a>.</p>
    -+
    -+<p>Karena jendela PIP ditampilkan sebagai jendela mengambang di sudut
    -+layar, Anda harus menghindari menampilkan informasi penting di layar utama
    -+di area mana saja yang bisa terhalang oleh jendela PIP.</p>
    -+
    -+<p>Bila aktivitas ada berada dalam mode PIP, secara default aktivitas itu tidak mendapatkan fokus masukan. Untuk
    -+menerima kejadian masukan saat dalam mode PIP, gunakan
    -+<code>MediaSession.setMediaButtonReceiver()</code>.</p>
    -diff --git a/docs/html-intl/intl/id/training/tv/tif/content-recording.jd b/docs/html-intl/intl/id/training/tv/tif/content-recording.jd
    -new file mode 100644
    -index 0000000..3389dbf
    ---- /dev/null
    -+++ b/docs/html-intl/intl/id/training/tv/tif/content-recording.jd
    -@@ -0,0 +1,142 @@
    -+page.title=Perekaman TV
    -+page.keywords=pratinjau,sdk,tv,perekaman
    -+page.tags=androidn
    -+page.image=images/cards/card-nyc_2x.jpg
    -+
    -+@jd:body
    -+
    -+<div id="tb-wrapper">
    -+<div id="tb">
    -+  <h2>Dalam dokumen ini</h2>
    -+  <ol>
    -+    <li><a href="#supporting">Menunjukkan Dukungan untuk Perekaman</a></li>
    -+    <li><a href="#recording">Merekam Sesi</a></li>
    -+    <li><a href="#errors">Menangani Kesalahan Perekaman</a></li>
    -+    <li><a href="#sessions">Mengelola Sesi yang Direkam</a></li>
    -+    <li><a href="#best">Praktik Terbaik</a></li>
    -+  </ol>
    -+</div>
    -+</div>
    -+
    -+<p>Layanan masukan TV memungkinkan pengguna menghentikan sementara dan melanjutkan pemutaran saluran melalui
    -+API perekaman. Android N telah berkembang hingga ke perekaman
    -+dengan memungkinkan pengguna menyimpan beberapa sesi rekaman.</p>
    -+
    -+<p>Pengguna bisa menjadwalkan rekaman terlebih dahulu, atau memulai rekaman sambil menonton
    -+suatu acara. Setelah sistem menyimpan rekaman, pengguna bisa menjelajah, menata,
    -+dan memutar kembali rekaman tersebut menggunakan aplikasi TV di sistem.</p>
    -+
    -+<p>Jika Anda ingin menyediakan fungsi perekaman untuk layanan masukan TV,
    -+Anda harus menunjukkan pada sistem bahwa aplikasi Anda mendukung perekaman, mengimplementasikan
    -+kemampuan merekam program, menangani dan mengomunikasikan kesalahan yang muncul
    -+selama perekaman, dan mengelola sesi perekaman Anda.</p>
    -+
    -+<p class="note"><strong>Catatan:</strong> Aplikasi Live Channels belum
    -+menyediakan cara bagi pengguna untuk membuat atau mengakses perekaman. Hingga dibuat perubahan
    -+di aplikasi Live Channels, mungkin sulit menguji sepenuhnya pengalaman
    -+perekaman untuk layanan masukan TV Anda.</p>
    -+
    -+<h2 id="supporting">Menunjukkan Dukungan untuk Perekaman</h2>
    -+
    -+<p>Untuk memberi tahu sistem bahwa layanan masukan TV Anda mendukung perekaman, setel
    -+atribut <code>android:canRecord</code> di file XML metadata layanan Anda
    -+ke <code>true</code>:
    -+</p>
    -+
    -+<pre>
    -+&lt;tv-input xmlns:android="http://schemas.android.com/apk/res/android"
    -+  <b>android:canRecord="true"</b>
    -+  android:setupActivity="com.example.sampletvinput.SampleTvInputSetupActivity" /&gt;
    -+</pre>
    -+
    -+<p>Untuk informasi selengkapnya mengenai layanan file metadata, lihat
    -+<a href="{@docRoot}training/tv/tif/tvinput.html#manifest">Mendeklarasikan Layanan Masukan TV Anda
    -+di Manifes</a>.
    -+</p>
    -+
    -+<p>Atau, Anda bisa menunjukkan dukungan perekaman dalam kode Anda menggunakan
    -+langkah-langkah ini:</p>
    -+
    -+<ol>
    -+<li>Dalam metode <code>TvInputService.onCreate()</code> Anda, buat objek
    -+<code>TvInputInfo</code> baru menggunakan kelas <code>TvInputInfo.Builder</code>.
    -+</li>
    -+<li>Saat membuat objek <code>TvInputInfo</code> baru, panggil
    -+<code>setCanRecord(true)</code> sebelum memanggil <code>build()</code> untuk
    -+ menunjukkan layanan Anda mendukung perekaman.</li>
    -+<li>Daftarkan objek <code>TvInputInfo</code> Anda pada sistem dengan memanggil
    -+<code>TvInputManager.updateTvInputInfo()</code>.</li>
    -+</ol>
    -+
    -+<h2 id="recording">Merekam Sesi</h2>
    -+
    -+<p>Setelah layanan masukan TV Anda mendaftar bahwa mendukung fungsionalitas
    -+perekaman, sistem akan memanggil
    -+<code>TvInputService.onCreateRecordingSession()</code> bila perlu untuk mengakses
    -+implementasi perekaman aplikasi Anda. Implementasikan subkelas
    -+<code>TvInputService.RecordingSession</code> Anda sendiri dan kembalikan
    -+bila callback <code>onCreateRecordingSession()</code> dipicu.
    -+ Subkelas ini bertanggung jawab mengalihkan ke saluran data yang benar,
    -+merekam data yang diminta, dan memberitahukan status perekaman serta kesalahan ke
    -+sistem.</p>
    -+
    -+<p>Bila sistem memanggil <code>RecordingSession.onTune()</code>, dengan meneruskan
    -+URI saluran, setel ke saluran yang ditetapkan URI. Beri tahu sistem bahwa
    -+aplikasi Anda telah disetel ke saluran yang diinginkan dengan memanggil <code>notifyTuned()</code>,
    -+atau, jika aplikasi Anda tidak bisa disetel ke saluran yang tepat, panggil
    -+<code>notifyError()</code>.</p>
    -+
    -+<p>Sistem berikutnya akan memanggil callback <code>RecordingSession.onStartRecording()</code>.
    -+ Aplikasi Anda harus segera mulai merekam. Bila sistem memanggil
    -+callback ini, sistem mungkin akan memberikan URI yang berisi informasi tentang program
    -+yang akan direkam. Bila perekaman selesai, Anda perlu menyalin data
    -+ini ke tabel data <code>RecordedPrograms</code>.</p>
    -+
    -+<p>Terakhir, sistem akan memanggil <code>RecordingSession.onStopRecording()</code>.
    -+Pada tahap ini, aplikasi Anda harus segera berhenti merekam. Anda juga perlu
    -+membuat entri dalam tabel <code>RecordedPrograms</code>. Entri ini harus
    -+menyertakan URI data sesi yang direkam dalam kolom
    -+<code>RecordedPrograms.COLUMN_RECORDING_DATA_URI</code>, dan informasi
    -+program yang diberikan sistem dalam panggilan awal ke
    -+<code>onStartRecording()</code>.</p>
    -+
    -+<p>Untuk detail selengkapnya tentang cara mengakses tabel <code>RecordedPrograms</code>
    -+lihat <a href="#sessions">Mengelola Sesi yang Direkam</a>.</p>
    -+
    -+<h2 id="errors">Menangani Kesalahan Perekaman</h2>
    -+
    -+<p>Jika terjadi kesalahan selama perekaman, yang menghasilkan data terekam yang tidak bisa digunakan,
    -+beri tahu sistem dengan memanggil <code>RecordingSession.notifyError()</code>.
    -+Begitu juga, Anda bisa memanggil <code>notifyError()</code> setelah sesi rekaman dibuat
    -+agar sistem mengetahui bahwa aplikasi Anda tidak bisa lagi merekam sesi.</p>
    -+
    -+<p>Jika terjadi kesalahan selama perekaman, namun Anda ingin menyediakan rekaman parsial
    -+yang bisa digunakan pengguna untuk pemutaran, panggil
    -+<code>RecordingSession.notifyRecordingStopped()</code> untuk memungkinkan sistem
    -+menggunakan sesi parsial.</p>
    -+
    -+<h2 id="sessions">Mengelola Sesi yang Direkam</h2>
    -+
    -+<p>Sistem menyimpan informasi untuk semua sesi yang direkam dari semua
    -+aplikasi saluran yang mampu merekam dalam tabel penyedia materi <code>TvContract.RecordedPrograms</code>.
    -+ Informasi ini bisa diakses lewat URI materi
    -+<code>RecordedPrograms.Uri</code>. Gunakan API penyedia materi untuk
    -+membaca, menambahkan, dan menghapus entri dari tabel ini.</p>
    -+
    -+<p>Untuk informasi selengkapnya tentang menangani data penyedia materi, lihat
    -+<a href="{@docRoot}guide/topics/providers/content-provider-basics.html">
    -+Dasar-Dasar Penyedia Materi</a>.</p>
    -+
    -+<h2 id="best">Praktik Terbaik</h2>
    -+
    -+<p>Perangkat TV mungkin memiliki penyimpanan terbatas, jadi pertimbangkan sebaik mungkin saat
    -+mengalokasikan penyimpanan untuk menyimpan sesi rekaman. Gunakan
    -+<code>RecordingCallback.onError(RECORDING_ERROR_INSUFFICIENT_SPACE)</code> bila
    -+tidak cukup ruang untuk menyimpan sesi rekaman.</p>
    -+
    -+<p>Bila pengguna memulai perekaman, Anda harus memulai perekaman data
    -+secepatnya. Untuk memfasilitasinya, selesaikan setiap tugas yang memakan waktu di awal,
    -+seperti mengakses dan mengalokasikan ruang penyimpanan, saat sistem memanggil callback
    -+<code>onCreateRecordingSession()</code>. Hal ini akan memungkinkan Anda memulai
    -+perekaman dengan segera bila callback <code>onStartRecording()</code>
    -+dipicu.</p>
    -diff --git a/docs/html-intl/intl/in/about/versions/nougat/index.jd b/docs/html-intl/intl/in/about/versions/nougat/index.jd
    -index 5234f91..212870a 100644
    ---- a/docs/html-intl/intl/in/about/versions/nougat/index.jd
    -+++ b/docs/html-intl/intl/in/about/versions/nougat/index.jd
    -@@ -7,16 +7,6 @@ header.hide=1
    - footer.hide=1
    - @jd:body
    - 
    --<script>
    --  $(document).ready(function() {
    --    if (useUpdatedTemplates) {
    --      $("#useUpdatedTemplates").css("display","block");
    --    } else {
    --      $("#useOldTemplates").css("display","block");
    --    }
    --  })
    --</script>
    --
    - <section class="dac-expand dac-hero dac-light">
    -   <div class="wrap" style="max-width:1100px;margin-top:0">
    -   <a href="{@docRoot}about/versions/nougat/android-7.0.html">
    -@@ -55,7 +45,7 @@ footer.hide=1
    - </section>
    - 
    - 
    --<div id="useUpdatedTemplates" style="display:none" class="dac-section dac-slim dac-gray dac-expand">
    -+<div class="dac-section dac-slim dac-gray dac-expand">
    -   <div class="wrap dac-offset-parent">
    -     <a class="dac-fab dac-scroll-button" data-scroll-button href="#latest">
    -       <i class="dac-sprite dac-arrow-down-gray"></i>
    -@@ -77,26 +67,6 @@ footer.hide=1
    -   </div><!-- end .wrap -->
    - </div><!-- end .dac-actions -->
    - 
    --<div id="useOldTemplates" style="display:none;color:black" class="actions-bar dac-expand dac-invert">
    --  <div class="wrap dac-offset-parent">
    --
    --    <div class="actions">
    --      <div><a href="https://developer.android.com/preview/bug">
    --        <span class="dac-sprite dac-auto-chevron-large"></span>
    --        Laporkan masalah
    --          </a></div>
    --      <div><a href="{@docRoot}preview/support.html">
    --        <span class="dac-sprite dac-auto-chevron-large"></span>
    --        Lihat catatan rilis
    --          </a></div>
    --      <div><a href="{@docRoot}preview/dev-community">
    --        <span class="dac-sprite dac-auto-chevron-large"></span>
    --        Bergabunglah dengan komunitas pengembang
    --          </a></div>
    --    </div><!-- end .actions -->
    --  </div><!-- end .wrap -->
    --</div>
    --
    - <section class="dac-section dac-light dac-small" id="latest"><div class="wrap">
    -   <h2 class="norule">Terbaru</h2>
    -   <div class="resource-widget resource-flow-layout col-16"
    -diff --git a/docs/html-intl/intl/ja/about/versions/nougat/index.jd b/docs/html-intl/intl/ja/about/versions/nougat/index.jd
    -index 5881cf6..7c5fe5d 100644
    ---- a/docs/html-intl/intl/ja/about/versions/nougat/index.jd
    -+++ b/docs/html-intl/intl/ja/about/versions/nougat/index.jd
    -@@ -7,16 +7,6 @@ header.hide=1
    - footer.hide=1
    - @jd:body
    - 
    --<script>
    --  $(document).ready(function() {
    --    if (useUpdatedTemplates) {
    --      $("#useUpdatedTemplates").css("display","block");
    --    } else {
    --      $("#useOldTemplates").css("display","block");
    --    }
    --  })
    --</script>
    --
    - <section class="dac-expand dac-hero dac-light">
    -   <div class="wrap" style="max-width:1100px;margin-top:0">
    -   <a href="{@docRoot}about/versions/nougat/android-7.0.html">
    -@@ -55,7 +45,7 @@ footer.hide=1
    - </section>
    - 
    - 
    --<div id="useUpdatedTemplates" style="display:none" class="dac-section dac-slim dac-gray dac-expand">
    -+<div class="dac-section dac-slim dac-gray dac-expand">
    -   <div class="wrap dac-offset-parent">
    -     <a class="dac-fab dac-scroll-button" data-scroll-button href="#latest">
    -       <i class="dac-sprite dac-arrow-down-gray"></i>
    -@@ -77,26 +67,6 @@ footer.hide=1
    -   </div><!-- end .wrap -->
    - </div><!-- end .dac-actions -->
    - 
    --<div id="useOldTemplates" style="display:none;color:black" class="actions-bar dac-expand dac-invert">
    --  <div class="wrap dac-offset-parent">
    --
    --    <div class="actions">
    --      <div><a href="https://developer.android.com/preview/bug">
    --        <span class="dac-sprite dac-auto-chevron-large"></span>
    --        問題の報告</a>
    --</div>
    --      <div><a href="{@docRoot}preview/support.html">
    --        <span class="dac-sprite dac-auto-chevron-large"></span>
    --        リリースノートの確認</a>
    --</div>
    --      <div><a href="{@docRoot}preview/dev-community">
    --        <span class="dac-sprite dac-auto-chevron-large"></span>
    --        開発者コミュニティに参加</a>
    --</div>
    --    </div><!-- end .actions -->
    --  </div><!-- end .wrap -->
    --</div>
    --
    - <section class="dac-section dac-light dac-small" id="latest"><div class="wrap">
    -   <h2 class="norule">新着</h2>
    -   <div class="resource-widget resource-flow-layout col-16"
    -diff --git a/docs/html-intl/intl/ja/index.jd b/docs/html-intl/intl/ja/index.jd
    -index ba73c41..3220f19 100644
    ---- a/docs/html-intl/intl/ja/index.jd
    -+++ b/docs/html-intl/intl/ja/index.jd
    -@@ -5,16 +5,6 @@ page.customHeadTag=<meta name="google-site-verification" content="sa-bIAI6GKvct3
    - 
    - @jd:body
    - 
    --<script>
    --  $(document).ready(function() {
    --    if (useUpdatedTemplates) {
    --      $("#useUpdatedTemplates").css("display","block");
    --    } else {
    --      $("#useOldTemplates").css("display","block");
    --    }
    --  })
    --</script>
    --
    - <section class="dac-expand dac-hero" style="background-color:#b2dfdb;">
    -   <div class="wrap" style="max-width:1000px;margin-top:0">
    -     <div class="col-7of16 col-push-8of16">
    -@@ -44,7 +34,7 @@ page.customHeadTag=<meta name="google-site-verification" content="sa-bIAI6GKvct3
    -   </div>
    - </section>
    - 
    --<div id="useUpdatedTemplates" style="display:none" class="dac-section dac-slim dac-gray dac-expand">
    -+<div class="dac-section dac-slim dac-gray dac-expand">
    -   <div class="wrap dac-offset-parent">
    -     <a class="dac-fab dac-scroll-button" data-scroll-button href="#build-apps">
    -       <i class="dac-sprite dac-arrow-down-gray"></i>
    -@@ -72,28 +62,6 @@ page.customHeadTag=<meta name="google-site-verification" content="sa-bIAI6GKvct3
    -   </div><!-- end .wrap -->
    - </div><!-- end .dac-actions -->
    - 
    --<div id="useOldTemplates" style="display:none" class="actions-bar dac-expand dac-invert">
    --  <div class="wrap dac-offset-parent">
    --    <a class="dac-fab dac-scroll-button" data-scroll-button="" href="#build-apps">
    --      <i class="dac-sprite dac-arrow-down-gray"></i>
    --    </a>
    --    <div class="actions">
    --      <div><a href="{@docRoot}sdk/index.html">
    --        <span class="dac-sprite dac-auto-chevron-large"></span>
    --        Get the SDK
    --      </a></div>
    --      <div><a href="{@docRoot}samples/index.html">
    --        <span class="dac-sprite dac-auto-chevron-large"></span>
    --        Browse Samples
    --      </a></div>
    --      <div><a href="{@docRoot}distribute/stories/index.html">
    --        <span class="dac-sprite dac-auto-chevron-large"></span>
    --        Watch Stories
    --      </a></div>
    --    </div><!-- end .actions -->
    --  </div><!-- end .wrap -->
    --</div>
    --
    - <section class="dac-section dac-light" id="build-apps"><div class="wrap">
    -   <h1 class="dac-section-title">Build Beautiful Apps</h1>
    -   <div class="dac-section-subtitle">
    -diff --git a/docs/html-intl/intl/ko/about/versions/nougat/index.jd b/docs/html-intl/intl/ko/about/versions/nougat/index.jd
    -index 6ed065b..20561a4 100644
    ---- a/docs/html-intl/intl/ko/about/versions/nougat/index.jd
    -+++ b/docs/html-intl/intl/ko/about/versions/nougat/index.jd
    -@@ -7,16 +7,6 @@ header.hide=1
    - footer.hide=1
    - @jd:body
    - 
    --<script>
    --  $(document).ready(function() {
    --    if (useUpdatedTemplates) {
    --      $("#useUpdatedTemplates").css("display","block");
    --    } else {
    --      $("#useOldTemplates").css("display","block");
    --    }
    --  })
    --</script>
    --
    - <section class="dac-expand dac-hero dac-light">
    -   <div class="wrap" style="max-width:1100px;margin-top:0">
    -   <a href="{@docRoot}about/versions/nougat/android-7.0.html">
    -@@ -54,7 +44,7 @@ footer.hide=1
    -   </div>
    - </section>
    - 
    --<div id="useUpdatedTemplates" style="display:none" class="dac-section dac-slim dac-gray dac-expand">
    -+<div class="dac-section dac-slim dac-gray dac-expand">
    -   <div class="wrap dac-offset-parent">
    -     <a class="dac-fab dac-scroll-button" data-scroll-button href="#latest">
    -       <i class="dac-sprite dac-arrow-down-gray"></i>
    -@@ -76,26 +66,6 @@ footer.hide=1
    -   </div><!-- end .wrap -->
    - </div><!-- end .dac-actions -->
    - 
    --<div id="useOldTemplates" style="display:none;color:black" class="actions-bar dac-expand dac-invert">
    --  <div class="wrap dac-offset-parent">
    --
    --    <div class="actions">
    --      <div><a href="https://developer.android.com/preview/bug">
    --        <span class="dac-sprite dac-auto-chevron-large"></span>
    --        문제 보고
    --      </a></div>
    --      <div><a href="{@docRoot}preview/support.html">
    --        <span class="dac-sprite dac-auto-chevron-large"></span>
    --        릴리스 노트 보기
    --        </a></div>
    --      <div><a href="{@docRoot}preview/dev-community">
    --        <span class="dac-sprite dac-auto-chevron-large"></span>
    --        개발자 커뮤니티 가입
    --      </a></div>
    --    </div><!-- end .actions -->
    --  </div><!-- end .wrap -->
    --</div>
    --
    - <section class="dac-section dac-light dac-small" id="latest"><div class="wrap">
    -   <h2 class="norule">최신</h2>
    -   <div class="resource-widget resource-flow-layout col-16"
    -diff --git a/docs/html-intl/intl/ko/guide/topics/providers/content-provider-basics.jd b/docs/html-intl/intl/ko/guide/topics/providers/content-provider-basics.jd
    -index 68ed568..0f58b79 100644
    ---- a/docs/html-intl/intl/ko/guide/topics/providers/content-provider-basics.jd
    -+++ b/docs/html-intl/intl/ko/guide/topics/providers/content-provider-basics.jd
    -@@ -891,7 +891,7 @@ mRowsDeleted = getContentResolver().delete(
    -     사용자 사전 제공자의 데이터 유형은 제공자의 계약 클래스
    - {@link android.provider.UserDictionary.Words}의 참조 문서에 나열되어 있습니다(계약 클래스는
    - <a href="#ContractClasses">계약 클래스</a> 섹션에 설명되어 있습니다).
    --    @link android.database.Cursor#getType
    -+    {@link android.database.Cursor#getType
    -     Cursor.getType()}을 호출해서도 데이터 유형을 결정할 수 있습니다.
    - </p>
    - <p>
    -diff --git a/docs/html-intl/intl/ko/index.jd b/docs/html-intl/intl/ko/index.jd
    -index e102411..b459df7 100644
    ---- a/docs/html-intl/intl/ko/index.jd
    -+++ b/docs/html-intl/intl/ko/index.jd
    -@@ -5,16 +5,6 @@ page.customHeadTag=<meta name="google-site-verification" content="sa-bIAI6GKvct3
    - 
    - @jd:body
    - 
    --<script>
    --  $(document).ready(function() {
    --    if (useUpdatedTemplates) {
    --      $("#useUpdatedTemplates").css("display","block");
    --    } else {
    --      $("#useOldTemplates").css("display","block");
    --    }
    --  })
    --</script>
    --
    - <section class="dac-expand dac-hero" style="background-color:#b2dfdb;">
    -   <div class="wrap" style="max-width:1000px;margin-top:0">
    -     <div class="col-7of16 col-push-8of16">
    -@@ -44,7 +34,7 @@ page.customHeadTag=<meta name="google-site-verification" content="sa-bIAI6GKvct3
    -   </div>
    - </section>
    - 
    --<div id="useUpdatedTemplates" style="display:none" class="dac-section dac-slim dac-gray dac-expand">
    -+<div class="dac-section dac-slim dac-gray dac-expand">
    -   <div class="wrap dac-offset-parent">
    -     <a class="dac-fab dac-scroll-button" data-scroll-button href="#build-apps">
    -       <i class="dac-sprite dac-arrow-down-gray"></i>
    -@@ -72,28 +62,6 @@ page.customHeadTag=<meta name="google-site-verification" content="sa-bIAI6GKvct3
    -   </div><!-- end .wrap -->
    - </div><!-- end .dac-actions -->
    - 
    --<div id="useOldTemplates" style="display:none" class="actions-bar dac-expand dac-invert">
    --  <div class="wrap dac-offset-parent">
    --    <a class="dac-fab dac-scroll-button" data-scroll-button="" href="#build-apps">
    --      <i class="dac-sprite dac-arrow-down-gray"></i>
    --    </a>
    --    <div class="actions">
    --      <div><a href="{@docRoot}sdk/index.html">
    --        <span class="dac-sprite dac-auto-chevron-large"></span>
    --        Get the SDK
    --      </a></div>
    --      <div><a href="{@docRoot}samples/index.html">
    --        <span class="dac-sprite dac-auto-chevron-large"></span>
    --        Browse Samples
    --      </a></div>
    --      <div><a href="{@docRoot}distribute/stories/index.html">
    --        <span class="dac-sprite dac-auto-chevron-large"></span>
    --        Watch Stories
    --      </a></div>
    --    </div><!-- end .actions -->
    --  </div><!-- end .wrap -->
    --</div>
    --
    - <section class="dac-section dac-light" id="build-apps"><div class="wrap">
    -   <h1 class="dac-section-title">Build Beautiful Apps</h1>
    -   <div class="dac-section-subtitle">
    -diff --git a/docs/html-intl/intl/pt-br/about/versions/nougat/index.jd b/docs/html-intl/intl/pt-br/about/versions/nougat/index.jd
    -index c7aee2a..ff44f6a 100644
    ---- a/docs/html-intl/intl/pt-br/about/versions/nougat/index.jd
    -+++ b/docs/html-intl/intl/pt-br/about/versions/nougat/index.jd
    -@@ -7,16 +7,6 @@ header.hide=1
    - footer.hide=1
    - @jd:body
    - 
    --<script>
    --  $(document).ready(function() {
    --    if (useUpdatedTemplates) {
    --      $("#useUpdatedTemplates").css("display","block");
    --    } else {
    --      $("#useOldTemplates").css("display","block");
    --    }
    --  })
    --</script>
    --
    - <section class="dac-expand dac-hero dac-light">
    -   <div class="wrap" style="max-width:1100px;margin-top:0">
    -   <a href="{@docRoot}about/versions/nougat/android-7.0.html">
    -@@ -54,7 +44,7 @@ footer.hide=1
    -   </div>
    - </section>
    - 
    --<div id="useUpdatedTemplates" style="display:none" class="dac-section dac-slim dac-gray dac-expand">
    -+<div class="dac-section dac-slim dac-gray dac-expand">
    -   <div class="wrap dac-offset-parent">
    -     <a class="dac-fab dac-scroll-button" data-scroll-button href="#latest">
    -       <i class="dac-sprite dac-arrow-down-gray"></i>
    -diff --git a/docs/html-intl/intl/pt-br/index.jd b/docs/html-intl/intl/pt-br/index.jd
    -index 3c8f75d..b15ecc8 100644
    ---- a/docs/html-intl/intl/pt-br/index.jd
    -+++ b/docs/html-intl/intl/pt-br/index.jd
    -@@ -5,16 +5,6 @@ page.customHeadTag=<meta name="google-site-verification" content="sa-bIAI6GKvct3
    - 
    - @jd:body
    - 
    --<script>
    --  $(document).ready(function() {
    --    if (useUpdatedTemplates) {
    --      $("#useUpdatedTemplates").css("display","block");
    --    } else {
    --      $("#useOldTemplates").css("display","block");
    --    }
    --  })
    --</script>
    --
    - <section class="dac-expand dac-hero" style="background-color:#b2dfdb;">
    -   <div class="wrap" style="max-width:1000px;margin-top:0">
    -     <div class="col-7of16 col-push-8of16">
    -@@ -44,7 +34,7 @@ page.customHeadTag=<meta name="google-site-verification" content="sa-bIAI6GKvct3
    -   </div>
    - </section>
    - 
    --<div id="useUpdatedTemplates" style="display:none" class="dac-section dac-slim dac-gray dac-expand">
    -+<div class="dac-section dac-slim dac-gray dac-expand">
    -   <div class="wrap dac-offset-parent">
    -     <a class="dac-fab dac-scroll-button" data-scroll-button href="#build-apps">
    -       <i class="dac-sprite dac-arrow-down-gray"></i>
    -@@ -72,28 +62,6 @@ page.customHeadTag=<meta name="google-site-verification" content="sa-bIAI6GKvct3
    -   </div><!-- end .wrap -->
    - </div><!-- end .dac-actions -->
    - 
    --<div id="useOldTemplates" style="display:none" class="actions-bar dac-expand dac-invert">
    --  <div class="wrap dac-offset-parent">
    --    <a class="dac-fab dac-scroll-button" data-scroll-button="" href="#build-apps">
    --      <i class="dac-sprite dac-arrow-down-gray"></i>
    --    </a>
    --    <div class="actions">
    --      <div><a href="{@docRoot}sdk/index.html">
    --        <span class="dac-sprite dac-auto-chevron-large"></span>
    --        Get the SDK
    --      </a></div>
    --      <div><a href="{@docRoot}samples/index.html">
    --        <span class="dac-sprite dac-auto-chevron-large"></span>
    --        Browse Samples
    --      </a></div>
    --      <div><a href="{@docRoot}distribute/stories/index.html">
    --        <span class="dac-sprite dac-auto-chevron-large"></span>
    --        Watch Stories
    --      </a></div>
    --    </div><!-- end .actions -->
    --  </div><!-- end .wrap -->
    --</div>
    --
    - <section class="dac-section dac-light" id="build-apps"><div class="wrap">
    -   <h1 class="dac-section-title">Build Beautiful Apps</h1>
    -   <div class="dac-section-subtitle">
    -diff --git a/docs/html-intl/intl/ru/about/versions/nougat/index.jd b/docs/html-intl/intl/ru/about/versions/nougat/index.jd
    -index 1103166..0365061 100644
    ---- a/docs/html-intl/intl/ru/about/versions/nougat/index.jd
    -+++ b/docs/html-intl/intl/ru/about/versions/nougat/index.jd
    -@@ -7,16 +7,6 @@ header.hide=1
    - footer.hide=1
    - @jd:body
    - 
    --<script>
    --  $(document).ready(function() {
    --    if (useUpdatedTemplates) {
    --      $("#useUpdatedTemplates").css("display","block");
    --    } else {
    --      $("#useOldTemplates").css("display","block");
    --    }
    --  })
    --</script>
    --
    - <section class="dac-expand dac-hero dac-light">
    -   <div class="wrap" style="max-width:1100px;margin-top:0">
    -   <a href="{@docRoot}about/versions/nougat/android-7.0.html">
    -@@ -54,7 +44,7 @@ footer.hide=1
    -   </div>
    - </section>
    - 
    --<div id="useUpdatedTemplates" style="display:none" class="dac-section dac-slim dac-gray dac-expand">
    -+<div class="dac-section dac-slim dac-gray dac-expand">
    -   <div class="wrap dac-offset-parent">
    -     <a class="dac-fab dac-scroll-button" data-scroll-button href="#latest">
    -       <i class="dac-sprite dac-arrow-down-gray"></i>
    -@@ -76,26 +66,6 @@ footer.hide=1
    -   </div><!-- end .wrap -->
    - </div><!-- end .dac-actions -->
    - 
    --<div id="useOldTemplates" style="display:none;color:black" class="actions-bar dac-expand dac-invert">
    --  <div class="wrap dac-offset-parent">
    --
    --    <div class="actions">
    --      <div><a href="https://developer.android.com/preview/bug">
    --        <span class="dac-sprite dac-auto-chevron-large"></span>
    --        Сообщить о проблеме
    --        </a></div>
    --      <div><a href="{@docRoot}preview/support.html">
    --        <span class="dac-sprite dac-auto-chevron-large"></span>
    --        См. примечания к выпуску
    --        </a></div>
    --      <div><a href="{@docRoot}preview/dev-community">
    --        <span class="dac-sprite dac-auto-chevron-large"></span>
    --        Вступить в сообщество разработчиков
    --        </a></div>
    --    </div><!-- end .actions -->
    --  </div><!-- end .wrap -->
    --</div>
    --
    - <section class="dac-section dac-light dac-small" id="latest"><div class="wrap">
    -   <h2 class="norule">Latest</h2>
    -   <div class="resource-widget resource-flow-layout col-16"
    -diff --git a/docs/html-intl/intl/ru/index.jd b/docs/html-intl/intl/ru/index.jd
    -index b3f3cc2..83a506e 100644
    ---- a/docs/html-intl/intl/ru/index.jd
    -+++ b/docs/html-intl/intl/ru/index.jd
    -@@ -5,16 +5,6 @@ page.customHeadTag=<meta name="google-site-verification" content="sa-bIAI6GKvct3
    - 
    - @jd:body
    - 
    --<script>
    --  $(document).ready(function() {
    --    if (useUpdatedTemplates) {
    --      $("#useUpdatedTemplates").css("display","block");
    --    } else {
    --      $("#useOldTemplates").css("display","block");
    --    }
    --  })
    --</script>
    --
    - <section class="dac-expand dac-hero" style="background-color:#b2dfdb;">
    -   <div class="wrap" style="max-width:1000px;margin-top:0">
    -     <div class="col-7of16 col-push-8of16">
    -@@ -44,7 +34,7 @@ page.customHeadTag=<meta name="google-site-verification" content="sa-bIAI6GKvct3
    -   </div>
    - </section>
    - 
    --<div id="useUpdatedTemplates" style="display:none" class="dac-section dac-slim dac-gray dac-expand">
    -+<div class="dac-section dac-slim dac-gray dac-expand">
    -   <div class="wrap dac-offset-parent">
    -     <a class="dac-fab dac-scroll-button" data-scroll-button href="#build-apps">
    -       <i class="dac-sprite dac-arrow-down-gray"></i>
    -@@ -72,28 +62,6 @@ page.customHeadTag=<meta name="google-site-verification" content="sa-bIAI6GKvct3
    -   </div><!-- end .wrap -->
    - </div><!-- end .dac-actions -->
    - 
    --<div id="useOldTemplates" style="display:none" class="actions-bar dac-expand dac-invert">
    --  <div class="wrap dac-offset-parent">
    --    <a class="dac-fab dac-scroll-button" data-scroll-button="" href="#build-apps">
    --      <i class="dac-sprite dac-arrow-down-gray"></i>
    --    </a>
    --    <div class="actions">
    --      <div><a href="{@docRoot}sdk/index.html">
    --        <span class="dac-sprite dac-auto-chevron-large"></span>
    --        Get the SDK
    --      </a></div>
    --      <div><a href="{@docRoot}samples/index.html">
    --        <span class="dac-sprite dac-auto-chevron-large"></span>
    --        Browse Samples
    --      </a></div>
    --      <div><a href="{@docRoot}distribute/stories/index.html">
    --        <span class="dac-sprite dac-auto-chevron-large"></span>
    --        Watch Stories
    --      </a></div>
    --    </div><!-- end .actions -->
    --  </div><!-- end .wrap -->
    --</div>
    --
    - <section class="dac-section dac-light" id="build-apps"><div class="wrap">
    -   <h1 class="dac-section-title">Build Beautiful Apps</h1>
    -   <div class="dac-section-subtitle">
    -diff --git a/docs/html-intl/intl/vi/about/versions/nougat/index.jd b/docs/html-intl/intl/vi/about/versions/nougat/index.jd
    -index 58b4b5f..2d57fa6 100644
    ---- a/docs/html-intl/intl/vi/about/versions/nougat/index.jd
    -+++ b/docs/html-intl/intl/vi/about/versions/nougat/index.jd
    -@@ -7,16 +7,6 @@ header.hide=1
    - footer.hide=1
    - @jd:body
    - 
    --<script>
    --  $(document).ready(function() {
    --    if (useUpdatedTemplates) {
    --      $("#useUpdatedTemplates").css("display","block");
    --    } else {
    --      $("#useOldTemplates").css("display","block");
    --    }
    --  })
    --</script>
    --
    - <section class="dac-expand dac-hero dac-light">
    -   <div class="wrap" style="max-width:1100px;margin-top:0">
    -   <a href="{@docRoot}about/versions/nougat/android-7.0.html">
    -@@ -55,7 +45,7 @@ footer.hide=1
    - </section>
    - 
    - 
    --<div id="useUpdatedTemplates" style="display:none" class="dac-section dac-slim dac-gray dac-expand">
    -+<div class="dac-section dac-slim dac-gray dac-expand">
    -   <div class="wrap dac-offset-parent">
    -     <a class="dac-fab dac-scroll-button" data-scroll-button href="#latest">
    -       <i class="dac-sprite dac-arrow-down-gray"></i>
    -@@ -77,26 +67,6 @@ footer.hide=1
    -   </div><!-- end .wrap -->
    - </div><!-- end .dac-actions -->
    - 
    --<div id="useOldTemplates" style="display:none;color:black" class="actions-bar dac-expand dac-invert">
    --  <div class="wrap dac-offset-parent">
    --
    --    <div class="actions">
    --      <div><a href="https://developer.android.com/preview/bug">
    --        <span class="dac-sprite dac-auto-chevron-large"></span>
    --        Báo cáo vấn đề
    --      </a></div>
    --      <div><a href="{@docRoot}preview/support.html">
    --        <span class="dac-sprite dac-auto-chevron-large"></span>
    --        Xem ghi chú phát hành
    --      </a></div>
    --      <div><a href="{@docRoot}preview/dev-community">
    --        <span class="dac-sprite dac-auto-chevron-large"></span>
    --        Tham gia cộng đồng nhà phát triển
    --      </a></div>
    --    </div><!-- end .actions -->
    --  </div><!-- end .wrap -->
    --</div>
    --
    - <section class="dac-section dac-light dac-small" id="latest"><div class="wrap">
    -   <h2 class="norule">Latest</h2>
    -   <div class="resource-widget resource-flow-layout col-16"
    -diff --git a/docs/html-intl/intl/zh-cn/about/versions/nougat/index.jd b/docs/html-intl/intl/zh-cn/about/versions/nougat/index.jd
    -index c1eb423..5619de8 100644
    ---- a/docs/html-intl/intl/zh-cn/about/versions/nougat/index.jd
    -+++ b/docs/html-intl/intl/zh-cn/about/versions/nougat/index.jd
    -@@ -7,16 +7,6 @@ header.hide=1
    - footer.hide=1
    - @jd:body
    - 
    --<script>
    --  $(document).ready(function() {
    --    if (useUpdatedTemplates) {
    --      $("#useUpdatedTemplates").css("display","block");
    --    } else {
    --      $("#useOldTemplates").css("display","block");
    --    }
    --  })
    --</script>
    --
    - <section class="dac-expand dac-hero dac-light">
    -   <div class="wrap" style="max-width:1100px;margin-top:0">
    -   <a href="{@docRoot}about/versions/nougat/android-7.0.html">
    -@@ -55,7 +45,7 @@ footer.hide=1
    - </section>
    - 
    - 
    --<div id="useUpdatedTemplates" style="display:none" class="dac-section dac-slim dac-gray dac-expand">
    -+<div class="dac-section dac-slim dac-gray dac-expand">
    -   <div class="wrap dac-offset-parent">
    -     <a class="dac-fab dac-scroll-button" data-scroll-button href="#latest">
    -       <i class="dac-sprite dac-arrow-down-gray"></i>
    -@@ -77,26 +67,6 @@ footer.hide=1
    -   </div><!-- end .wrap -->
    - </div><!-- end .dac-actions -->
    - 
    --<div id="useOldTemplates" style="display:none;color:black" class="actions-bar dac-expand dac-invert">
    --  <div class="wrap dac-offset-parent">
    --
    --    <div class="actions">
    --      <div><a href="https://developer.android.com/preview/bug">
    --        <span class="dac-sprite dac-auto-chevron-large"></span>
    --        报告问题
    --      </a></div>
    --      <div><a href="{@docRoot}preview/support.html">
    --        <span class="dac-sprite dac-auto-chevron-large"></span>
    --        查阅版本说明
    --      </a></div>
    --      <div><a href="{@docRoot}preview/dev-community">
    --        <span class="dac-sprite dac-auto-chevron-large"></span>
    --        加入开发者社区</a>
    --</div>
    --    </div><!-- end .actions -->
    --  </div><!-- end .wrap -->
    --</div>
    --
    - <section class="dac-section dac-light dac-small" id="latest"><div class="wrap">
    -   <h2 class="norule">最新</h2>
    -   <div class="resource-widget resource-flow-layout col-16"
    -diff --git a/docs/html-intl/intl/zh-cn/distribute/tools/promote/badges.jd b/docs/html-intl/intl/zh-cn/distribute/tools/promote/badges.jd
    -index 1c82161..cc1234d 100644
    ---- a/docs/html-intl/intl/zh-cn/distribute/tools/promote/badges.jd
    -+++ b/docs/html-intl/intl/zh-cn/distribute/tools/promote/badges.jd
    -@@ -35,7 +35,7 @@ div.button-row input {
    -   vertical-align: middle;
    -   margin: 0 5px 0 0;
    - }
    --#jd-content div.button-row img {
    -+#body-content div.button-row img {
    -   margin: 0;
    -   vertical-align: middle;
    - }
    -diff --git a/docs/html-intl/intl/zh-cn/index.jd b/docs/html-intl/intl/zh-cn/index.jd
    -index 8872d16..c1a5d6f 100644
    ---- a/docs/html-intl/intl/zh-cn/index.jd
    -+++ b/docs/html-intl/intl/zh-cn/index.jd
    -@@ -5,16 +5,6 @@ page.customHeadTag=<meta name="google-site-verification" content="sa-bIAI6GKvct3
    - 
    - @jd:body
    - 
    --<script>
    --  $(document).ready(function() {
    --    if (useUpdatedTemplates) {
    --      $("#useUpdatedTemplates").css("display","block");
    --    } else {
    --      $("#useOldTemplates").css("display","block");
    --    }
    --  })
    --</script>
    --
    - <section class="dac-expand dac-hero" style="background-color:#b2dfdb;">
    -   <div class="wrap" style="max-width:1000px;margin-top:0">
    -     <div class="col-7of16 col-push-8of16">
    -@@ -44,7 +34,7 @@ page.customHeadTag=<meta name="google-site-verification" content="sa-bIAI6GKvct3
    -   </div>
    - </section>
    - 
    --<div id="useUpdatedTemplates" style="display:none" class="dac-section dac-slim dac-gray dac-expand">
    -+<div class="dac-section dac-slim dac-gray dac-expand">
    -   <div class="wrap dac-offset-parent">
    -     <a class="dac-fab dac-scroll-button" data-scroll-button href="#build-apps">
    -       <i class="dac-sprite dac-arrow-down-gray"></i>
    -@@ -72,28 +62,6 @@ page.customHeadTag=<meta name="google-site-verification" content="sa-bIAI6GKvct3
    -   </div><!-- end .wrap -->
    - </div><!-- end .dac-actions -->
    - 
    --<div id="useOldTemplates" style="display:none" class="actions-bar dac-expand dac-invert">
    --  <div class="wrap dac-offset-parent">
    --    <a class="dac-fab dac-scroll-button" data-scroll-button="" href="#build-apps">
    --      <i class="dac-sprite dac-arrow-down-gray"></i>
    --    </a>
    --    <div class="actions">
    --      <div><a href="{@docRoot}sdk/index.html">
    --        <span class="dac-sprite dac-auto-chevron-large"></span>
    --        Get the SDK
    --      </a></div>
    --      <div><a href="{@docRoot}samples/index.html">
    --        <span class="dac-sprite dac-auto-chevron-large"></span>
    --        Browse Samples
    --      </a></div>
    --      <div><a href="{@docRoot}distribute/stories/index.html">
    --        <span class="dac-sprite dac-auto-chevron-large"></span>
    --        Watch Stories
    --      </a></div>
    --    </div><!-- end .actions -->
    --  </div><!-- end .wrap -->
    --</div>
    --
    - <section class="dac-section dac-light" id="build-apps"><div class="wrap">
    -   <h1 class="dac-section-title">Build Beautiful Apps</h1>
    -   <div class="dac-section-subtitle">
    -diff --git a/docs/html-intl/intl/zh-tw/about/versions/nougat/index.jd b/docs/html-intl/intl/zh-tw/about/versions/nougat/index.jd
    -index d4db467..ae9e164 100644
    ---- a/docs/html-intl/intl/zh-tw/about/versions/nougat/index.jd
    -+++ b/docs/html-intl/intl/zh-tw/about/versions/nougat/index.jd
    -@@ -7,16 +7,6 @@ header.hide=1
    - footer.hide=1
    - @jd:body
    - 
    --<script>
    --  $(document).ready(function() {
    --    if (useUpdatedTemplates) {
    --      $("#useUpdatedTemplates").css("display","block");
    --    } else {
    --      $("#useOldTemplates").css("display","block");
    --    }
    --  })
    --</script>
    --
    - <section class="dac-expand dac-hero dac-light">
    -   <div class="wrap" style="max-width:1100px;margin-top:0">
    -   <a href="{@docRoot}about/versions/nougat/android-7.0.html">
    -@@ -55,7 +45,7 @@ footer.hide=1
    - </section>
    - 
    - 
    --<div id="useUpdatedTemplates" style="display:none" class="dac-section dac-slim dac-gray dac-expand">
    -+<div class="dac-section dac-slim dac-gray dac-expand">
    -   <div class="wrap dac-offset-parent">
    -     <a class="dac-fab dac-scroll-button" data-scroll-button href="#latest">
    -       <i class="dac-sprite dac-arrow-down-gray"></i>
    -@@ -77,26 +67,6 @@ footer.hide=1
    -   </div><!-- end .wrap -->
    - </div><!-- end .dac-actions -->
    - 
    --<div id="useOldTemplates" style="display:none;color:black" class="actions-bar dac-expand dac-invert">
    --  <div class="wrap dac-offset-parent">
    --
    --    <div class="actions">
    --      <div><a href="https://developer.android.com/preview/bug">
    --        <span class="dac-sprite dac-auto-chevron-large"></span>
    --        回報問題</a>
    --</div>
    --      <div><a href="{@docRoot}preview/support.html">
    --        <span class="dac-sprite dac-auto-chevron-large"></span>
    --        查看版本資訊</a>
    --</div>
    --      <div><a href="{@docRoot}preview/dev-community">
    --        <span class="dac-sprite dac-auto-chevron-large"></span>
    --        加入開發人員社群</a>
    --</div>
    --    </div><!-- end .actions -->
    --  </div><!-- end .wrap -->
    --</div>
    --
    - <section class="dac-section dac-light dac-small" id="latest"><div class="wrap">
    -   <h2 class="norule">Latest</h2>
    -   <div class="resource-widget resource-flow-layout col-16"
    -diff --git a/docs/html-intl/intl/zh-tw/guide/components/intents-filters.jd b/docs/html-intl/intl/zh-tw/guide/components/intents-filters.jd
    -index d3edac3..7e61f5e 100644
    ---- a/docs/html-intl/intl/zh-tw/guide/components/intents-filters.jd
    -+++ b/docs/html-intl/intl/zh-tw/guide/components/intents-filters.jd
    -@@ -76,7 +76,7 @@ android.content.Context#bindService bindService()} 來繫結至另一個元件
    - <li><b>如何傳送廣播:</b>
    - <p>廣播是指任何應用程式都可接收的訊息。系統會傳送各種系統事件廣播,例如系統開機或裝置開始充電。
    - 您可以將 {@link android.content.Intent} 傳送至 {@link android.content.Context#sendBroadcast(Intent) sendBroadcast()}、
    --{@link android.content.Context#sendOrderedBroadcast(Intent, String) 或{@link
    -+{@link android.content.Context#sendOrderedBroadcast(Intent, String)} 或{@link
    - android.content.Context#sendStickyBroadcast sendStickyBroadcast()},以向其他應用程式傳送廣播。
    - 
    - 
    -diff --git a/docs/html-intl/intl/zh-tw/index.jd b/docs/html-intl/intl/zh-tw/index.jd
    -index 540801a..022df77 100644
    ---- a/docs/html-intl/intl/zh-tw/index.jd
    -+++ b/docs/html-intl/intl/zh-tw/index.jd
    -@@ -5,16 +5,6 @@ page.customHeadTag=<meta name="google-site-verification" content="sa-bIAI6GKvct3
    - 
    - @jd:body
    - 
    --<script>
    --  $(document).ready(function() {
    --    if (useUpdatedTemplates) {
    --      $("#useUpdatedTemplates").css("display","block");
    --    } else {
    --      $("#useOldTemplates").css("display","block");
    --    }
    --  })
    --</script>
    --
    - <section class="dac-expand dac-hero" style="background-color:#b2dfdb;">
    -   <div class="wrap" style="max-width:1000px;margin-top:0">
    -     <div class="col-7of16 col-push-8of16">
    -@@ -44,7 +34,7 @@ page.customHeadTag=<meta name="google-site-verification" content="sa-bIAI6GKvct3
    -   </div>
    - </section>
    - 
    --<div id="useUpdatedTemplates" style="display:none" class="dac-section dac-slim dac-gray dac-expand">
    -+<div class="dac-section dac-slim dac-gray dac-expand">
    -   <div class="wrap dac-offset-parent">
    -     <a class="dac-fab dac-scroll-button" data-scroll-button href="#build-apps">
    -       <i class="dac-sprite dac-arrow-down-gray"></i>
    -@@ -72,28 +62,6 @@ page.customHeadTag=<meta name="google-site-verification" content="sa-bIAI6GKvct3
    -   </div><!-- end .wrap -->
    - </div><!-- end .dac-actions -->
    - 
    --<div id="useOldTemplates" style="display:none" class="actions-bar dac-expand dac-invert">
    --  <div class="wrap dac-offset-parent">
    --    <a class="dac-fab dac-scroll-button" data-scroll-button="" href="#build-apps">
    --      <i class="dac-sprite dac-arrow-down-gray"></i>
    --    </a>
    --    <div class="actions">
    --      <div><a href="{@docRoot}sdk/index.html">
    --        <span class="dac-sprite dac-auto-chevron-large"></span>
    --        Get the SDK
    --      </a></div>
    --      <div><a href="{@docRoot}samples/index.html">
    --        <span class="dac-sprite dac-auto-chevron-large"></span>
    --        Browse Samples
    --      </a></div>
    --      <div><a href="{@docRoot}distribute/stories/index.html">
    --        <span class="dac-sprite dac-auto-chevron-large"></span>
    --        Watch Stories
    --      </a></div>
    --    </div><!-- end .actions -->
    --  </div><!-- end .wrap -->
    --</div>
    --
    - <section class="dac-section dac-light" id="build-apps"><div class="wrap">
    -   <h1 class="dac-section-title">Build Beautiful Apps</h1>
    -   <div class="dac-section-subtitle">
    -diff --git a/docs/html/_redirects.yaml b/docs/html/_redirects.yaml
    -index 1557dce..7daf85c 100644
    ---- a/docs/html/_redirects.yaml
    -+++ b/docs/html/_redirects.yaml
    -@@ -1,6 +1,8 @@
    - # For information about this file's format, see
    - # https://developers.google.com/internal/publishing/redirects
    - redirects:
    -+- from: /guide/topics/fundamentals/fragments.html
    -+  to: /guide/components/fragments.html
    - - from: /about/versions/index.html
    -   to: /about/index.html
    - - from: /about/versions/api-levels.html
    -@@ -41,8 +43,8 @@ redirects:
    -   to: /studio/intro/update.html
    - - from: /sdk/ndk/overview.html
    -   to: /ndk/index.html
    --- from: /sdk/ndk/
    --  to: /ndk/
    -+- from: /sdk/ndk/...
    -+  to: /ndk/...
    - - from: /go/vulkan
    -   to: /ndk/guides/graphics/index.html
    - - from: /tools/sdk/win-usb.html
    -@@ -101,18 +103,18 @@ redirects:
    -   to: /training/testing/unit-testing/index.html
    - - from: /training/activity-testing/activity-functional-testing.html
    -   to: /training/testing/ui-testing/index.html
    --- from: /guide/market/
    --  to: /google/play/
    -+- from: /guide/market/...
    -+  to: /google/play/...
    - - from: /guide/google/play/services.html
    -   to: https://developers.google.com/android/guides/overview
    --- from: /guide/google/
    --  to: /google/
    --- from: /training/id-auth/...
    -+- from: /guide/google/...
    -+  to: /google/...
    -+- from: /training/id-auth/
    -   to: /google/auth/http-auth.html
    - - from: /google/play-services/auth.html
    -   to: https://developers.google.com/android/guides/http-auth
    - - from: /google/play-services/games.html
    --  to: https://developers.google.com/games/services/
    -+  to: https://developers.google.com/games/services
    - - from: /google/play-services/location.html
    -   to: /training/location/index.html
    - - from: /google/play-services/plus.html
    -@@ -120,21 +122,21 @@ redirects:
    - - from: /google/play-services/maps.html
    -   to: /training/maps/index.html
    - - from: /google/play-services/drive.html
    --  to: https://developers.google.com/drive/android/
    -+  to: https://developers.google.com/drive/android
    - - from: /google/play-services/cast.html
    --  to: https://developers.google.com/cast/
    -+  to: https://developers.google.com/cast
    - - from: /google/play-services/ads.html
    --  to: https://developers.google.com/mobile-ads-sdk/
    -+  to: https://developers.google.com/mobile-ads-sdk
    - - from: /google/play-services/wallet.html
    --  to: https://developers.google.com/wallet/instant-buy/
    -+  to: https://developers.google.com/wallet/instant-buy
    - - from: /google/play-services/id.html
    -   to: https://developers.google.com/android/reference/com/google/android/gms/ads/identifier/AdvertisingIdClient
    - - from: /google/play/safetynet/...
    -   to: /training/safetynet/index.html
    - - from: /google/gcm/...
    --  to: https://developers.google.com/cloud-messaging/
    -+  to: https://developers.google.com/cloud-messaging/...
    - - from: /google/gcs/...
    --  to: https://developers.google.com/datastore/
    -+  to: https://developers.google.com/datastore/...
    - - from: /google/play-services/safetynet.html
    -   to: /training/safetynet/index.html
    - - from: /google/play/billing/v2/api.html
    -@@ -158,29 +160,29 @@ redirects:
    - - from: /guide/developing/tools/aidl.html
    -   to: /guide/components/aidl.html
    - - from: /guide/developing/tools/...
    --  to: /studio/command-line/
    -+  to: /studio/command-line/...
    - - from: /guide/developing/...
    --  to: /studio/
    -+  to: /studio/...
    - - from: /tools/aidl.html
    -   to: /guide/components/aidl.html
    - - from: /guide/market/publishing/multiple-apks.html
    -   to: /google/play/publishing/multiple-apks.html
    - - from: /guide/publishing/publishing.html
    -   to: /distribute/tools/launch-checklist.html
    --- from: /guide/publishing/
    -+- from: /guide/publishing/...
    -   to: /studio/publish/index.html
    - - from: /guide/topics/fundamentals.html
    -   to: /guide/components/fundamentals.html
    - - from: /guide/topics/intents/intents-filters.html
    -   to: /guide/components/intents-filters.html
    --- from: /guide/topics/fundamentals/
    --  to: /guide/components/
    -+- from: /guide/topics/fundamentals/...
    -+  to: /guide/components/...
    - - from: /guide/topics/clipboard/copy-paste.html
    -   to: /guide/topics/text/copy-paste.html
    - - from: /guide/topics/ui/notifiers/index.html
    -   to: /guide/topics/ui/notifiers/notifications.html
    --- from: /guide/topics/wireless/
    --  to: /guide/topics/connectivity/
    -+- from: /guide/topics/wireless/...
    -+  to: /guide/topics/connectivity/...
    - - from: /guide/topics/drawing/...
    -   to: /guide/topics/graphics/opengl.html
    - - from: /guide/topics/connectivity/usb/adk.html
    -@@ -217,8 +219,8 @@ redirects:
    -   to: /training/articles/security-tips.html
    - - from: /guide/appendix/market-filters.html
    -   to: /google/play/filters.html
    --- from: /guide/topics/testing/
    --  to: /studio/test/
    -+- from: /guide/topics/testing/...
    -+  to: /studio/test/...
    - - from: /guide/topics/graphics/animation.html
    -   to: /guide/topics/graphics/overview.html
    - - from: /guide/topics/graphics/renderscript/compute.html
    -@@ -235,24 +237,24 @@ redirects:
    -   to: /guide/topics/renderscript/reference/overview.html
    - - from: /guide/topics/location/obtaining-user-location.html
    -   to: /guide/topics/location/strategies.html
    --- from: /guide/topics/nfc/
    --  to: /guide/topics/connectivity/nfc/
    --- from: /guide/topics/wireless/
    --  to: /guide/topics/connectivity/
    --- from: /guide/topics/network/
    --  to: /guide/topics/connectivity/
    -+- from: /guide/topics/nfc/...
    -+  to: /guide/topics/connectivity/nfc/...
    -+- from: /guide/topics/wireless/...
    -+  to: /guide/topics/connectivity/...
    -+- from: /guide/topics/network/...
    -+  to: /guide/topics/connectivity/...
    - - from: /resources/articles/creating-input-method.html
    -   to: /guide/topics/text/creating-input-method.html
    - - from: /resources/articles/spell-checker-framework.html
    -   to: /guide/topics/text/spell-checker-framework.html
    --- from: /resources/tutorials/notepad/
    -+- from: /resources/tutorials/notepad/...
    -   to: https://developer.android.com/training/basics/firstapp/index.html
    --- from: /resources/faq/
    --  to: /guide/faq/
    -+- from: /resources/faq/...
    -+  to: /guide/faq/...
    - - from: /resources/tutorials/hello-world.html
    -   to: /training/basics/firstapp/index.html
    --- from: /guide/practices/design/
    --  to: /guide/practices/
    -+- from: /guide/practices/design/...
    -+  to: /guide/practices/...
    - - from: /guide/practices/accessibility.html
    -   to: /guide/topics/ui/accessibility/index.html
    - - from: /guide/practices/app-design/performance.html
    -@@ -287,6 +289,8 @@ redirects:
    -   to: /design/patterns/app-structure.html
    - - from: /guide/practices/ui_guidelines/menu_design.html
    -   to: /design/patterns/actionbar.html
    -+- from: /design/patterns/accessibility.html
    -+  to: https://material.google.com/usability/accessibility.html
    - - from: /design/get-started/ui-overview.html
    -   to: /design/handhelds/index.html
    - - from: /design/building-blocks/buttons.html
    -@@ -361,8 +365,8 @@ redirects:
    -   to: /training/wearables/notifications/pages.html
    - - from: /wear/notifications/stacks.html
    -   to: /training/wearables/notifications/stacks.html
    --- from: /reference/android/preview/support/
    --  to: /reference/android/support/
    -+- from: /reference/android/preview/support/...
    -+  to: /reference/android/support/...
    - - from: /wear/license.html
    -   to: /wear/index.html
    - - from: /resources/dashboard/...
    -@@ -371,8 +375,8 @@ redirects:
    -   to: /support.html
    - - from: /community/index.html
    -   to: /support.html
    --- from: /guide/tutorials/
    --  to: /resources/tutorials/
    -+- from: /guide/tutorials/...
    -+  to: /resources/tutorials/...
    - - from: /resources/tutorials/views/hello-linearlayout.html
    -   to: /guide/topics/ui/layout/linear.html
    - - from: /resources/tutorials/views/hello-relativelayout.html
    -@@ -412,11 +416,9 @@ redirects:
    - - from: /resources/samples/...
    -   to: /samples/index.html
    - - from: /resources/...
    --  to: /training/
    -+  to: /training/...
    - - from: /tools/samples/index.html
    -   to: /samples/index.html
    --- from: /guide/publishing/publishing.html\#BuildaButton
    --  to: https://play.google.com/intl/en_us/badges/
    - - from: /distribute/essentials/best-practices/games.html
    -   to: /distribute/googleplay/guide.html
    - - from: /distribute/essentials/best-practices/apps.html
    -@@ -430,13 +432,19 @@ redirects:
    - - from: /training/cloudsync/aesync.html
    -   to: /google/gcm/index.html
    - - from: /training/cloudsync/index.html
    --  to: /training/backup/index.html
    --- from: /training/basics/location/
    --  to: /training/location/
    -+  to: /guide/topics/data/backup.html
    -+- from: /training/backup/index.html
    -+  to: /guide/topics/data/backup.html
    -+- from: /training/backup/autosyncapi.html
    -+  to: /guide/topics/data/autobackup.html
    -+- from: /training/backup/backupapi.html
    -+  to: /guide/topics/data/keyvaluebackup.html
    -+- from: /training/basics/location/...
    -+  to: /training/location/...
    - - from: /training/monetization/index.html
    -   to: /distribute/monetize/index.html
    - - from: /training/monetization/ads-and-ux.html
    --  to: https://developers.google.com/mobile-ads-sdk/
    -+  to: https://developers.google.com/mobile-ads-sdk/index.html
    - - from: /training/notepad/...
    -   to: https://developer.android.com/training/basics/firstapp/index.html
    - - from: /training/basics/actionbar/setting-up.html
    -@@ -447,8 +455,8 @@ redirects:
    -   to: /training/appbar/index.html
    - - from: /distribute/open.html
    -   to: /distribute/tools/open-distribution.html
    --- from: /distribute/googleplay/promote/
    --  to: /distribute/tools/promote/
    -+- from: /distribute/googleplay/promote/...
    -+  to: /distribute/tools/promote/...
    - - from: /distribute/googleplay/publish/preparing.html
    -   to: /distribute/tools/launch-checklist.html
    - - from: /distribute/googleplay/publish/index.html
    -@@ -477,8 +485,8 @@ redirects:
    -   to: /distribute/monetize/index.html
    - - from: /distribute/googleplay/about/distribution.html
    -   to: /distribute/googleplay/developer-console.html
    --- from: /distribute/googleplay/spotlight/
    --  to: /distribute/stories/
    -+- from: /distribute/googleplay/spotlight/...
    -+  to: /distribute/stories/...
    - - from: /distribute/stories/localization.html
    -   to: /distribute/stories/index.html
    - - from: /distribute/stories/tablets.html
    -@@ -540,11 +548,11 @@ redirects:
    - - from: /videos/index.html
    -   to: /develop/index.html
    - - from: /live/index.html
    --  to: https://developers.google.com/live/
    --- from: /intl/zh-CN/
    --  to: /intl/zh-cn/
    --- from: /intl/zh-TW/
    --  to: /intl/zh-tw/
    -+  to: https://developers.google.com/live/index.html
    -+- from: /intl/zh-CN/...
    -+  to: /intl/zh-cn/...
    -+- from: /intl/zh-TW/...
    -+  to: /intl/zh-tw/...
    - - from: /4.2
    -   to: /about/versions/android-4.2.html
    - - from: /4.1
    -@@ -553,111 +561,111 @@ redirects:
    -   to: /about/versions/android-4.0.html
    - - from: /5
    -   to: /about/versions/android-5.0.html
    --- from: /5/
    -+- from: /5/...
    -   to: /about/versions/android-5.0.html
    - 
    - - from: /m
    -   to: /about/versions/marshmallow/index.html
    --- from: /m/
    -+- from: /m/...
    -   to: /about/versions/marshmallow/index.html
    - - from: /mm
    -   to: /about/versions/marshmallow/index.html
    --- from: /mm/
    -+- from: /mm/...
    -   to: /about/versions/marshmallow/index.html
    - - from: /marshmallow
    -   to: /about/versions/marshmallow/index.html
    --- from: /marshmallow/
    -+- from: /marshmallow/...
    -   to: /about/versions/marshmallow/index.html
    - 
    - - from: /l
    -   to: /about/versions/lollipop.html
    --- from: /l/
    -+- from: /l/...
    -   to: /about/versions/lollipop.html
    - - from: /ll
    -   to: /about/versions/lollipop.html
    --- from: /ll/
    -+- from: /ll/...
    -   to: /about/versions/lollipop.html
    - - from: /lp
    -   to: /about/versions/lollipop.html
    --- from: /lp/
    -+- from: /lp/...
    -   to: /about/versions/lollipop.html
    - - from: /lollipop
    -   to: /about/versions/lollipop.html
    --- from: /lollipop/
    -+- from: /lollipop/...
    -   to: /about/versions/lollipop.html
    - 
    - - from: /k
    -   to: /about/versions/kitkat.html
    --- from: /k/
    -+- from: /k/...
    -   to: /about/versions/kitkat.html
    - - from: /kk
    -   to: /about/versions/kitkat.html
    --- from: /kk/
    -+- from: /kk/...
    -   to: /about/versions/kitkat.html
    - - from: /kitkat
    -   to: /about/versions/kitkat.html
    --- from: /kitkat/
    -+- from: /kitkat/...
    -   to: /about/versions/kitkat.html
    - 
    - - from: /j
    -   to: /about/versions/jelly-bean.html
    --- from: /j/
    -+- from: /j/...
    -   to: /about/versions/jelly-bean.html
    - - from: /jj
    -   to: /about/versions/jelly-bean.html
    --- from: /jj/
    -+- from: /jj/...
    -   to: /about/versions/jelly-bean.html
    - - from: /jellybean
    -   to: /about/versions/jelly-bean.html
    --- from: /jellybean/
    -+- from: /jellybean/...
    -   to: /about/versions/jelly-bean.html
    - 
    - - from: /i
    -   to: /about/versions/android-4.0-highlights.html
    --- from: /i/
    -+- from: /i/...
    -   to: /about/versions/android-4.0-highlights.html
    - - from: /ics
    -   to: /about/versions/android-4.0-highlights.html
    --- from: /ics/
    -+- from: /ics/...
    -   to: /about/versions/android-4.0-highlights.html
    - - from: /icecreamsandwich
    -   to: /about/versions/android-4.0-highlights.html
    --- from: /icecreamsandwich/
    -+- from: /icecreamsandwich/...
    -   to: /about/versions/android-4.0-highlights.html
    - 
    - - from: /%2B
    -   to: https://plus.google.com/108967384991768947849/posts
    --- from: /%2B/
    -+- from: /%2B/...
    -   to: https://plus.google.com/108967384991768947849/posts
    - - from: /blog
    --  to: https://android-developers.blogspot.com/
    -+  to: https://android-developers.blogspot.com
    - - from: /stats
    -   to: /about/dashboards/index.html
    - - from: /youtube
    -   to: https://www.youtube.com/user/androiddevelopers
    - - from: /playbadge
    --  to: https://play.google.com/intl/en_us/badges/
    --- from: /playbadge/
    --  to: https://play.google.com/intl/en_us/badges/
    -+  to: https://play.google.com/intl/en_us/badges
    -+- from: /playbadge/...
    -+  to: https://play.google.com/intl/en_us/badges/...
    - - from: /distribute/tools/promote/badges.html
    --  to: https://play.google.com/intl/en_us/badges/
    -+  to: https://play.google.com/intl/en_us/badges
    - - from: /deviceart
    -   to: /distribute/tools/promote/device-art.html
    --- from: /deviceart/
    -+- from: /deviceart/...
    -   to: /distribute/tools/promote/device-art.html
    - - from: /distribute/promote/device-art.html
    -   to: /distribute/tools/promote/device-art.html
    - - from: /edu/signup
    -   to: https://services.google.com/fb/forms/playedu
    --- from: /edu/signup/
    -+- from: /edu/signup/...
    -   to: https://services.google.com/fb/forms/playedu
    - - from: /edu
    -   to: /distribute/googleplay/edu/about.html
    --- from: /edu/
    -+- from: /edu/...
    -   to: /distribute/googleplay/edu/about.html
    - - from: /families
    -   to: /distribute/googleplay/families/about.html
    --- from: /families/
    -+- from: /families/...
    -   to: /distribute/googleplay/families/about.html
    - - from: /preview/google-play-services-wear.html
    -   to: /training/building-wearables.html
    -@@ -713,9 +721,9 @@ redirects:
    -   to: /training/material/animations.html
    - - from: /preview/material/compatibility.html
    -   to: /training/material/compatibility.html
    --- from: /preview/material/
    -+- from: /preview/material/...
    -   to: /design/material/index.html
    --- from: /auto/overview/
    -+- from: /auto/overview/...
    -   to: /training/auto/start/index.html
    - - from: /training/location/activity-recognition.html
    -   to: /training/location/index.html
    -@@ -738,9 +746,9 @@ redirects:
    - - from: /training/enterprise/work-policy-ctrl.html
    -   to: https://developers.google.com/android/work/build-dpc
    - - from: /distribute/tools/promote/badge-files.html
    --  to: https://play.google.com/intl/en_us/badges/
    -+  to: https://play.google.com/intl/en_us/badges
    - - from: /google/gcm/...
    --  to: https://developers.google.com/cloud-messaging/
    -+  to: https://developers.google.com/cloud-messaging
    - - from: /training/cloudsync/gcm.html
    -   to: /training/cloudsync/index.html
    - 
    -@@ -796,29 +804,32 @@ redirects:
    - - from: /preview/features/app-linking.html
    -   to: /training/app-links/index.html
    - - from: /preview/backup/index.html
    --  to: /training/backup/autosyncapi.html
    -+  to: /guide/topics/data/backup/autobackup.html
    - - from: /preview/features/power-mgmt.html
    -   to: /training/monitoring-device-state/doze-standby.html
    - - from: /preview/dev-community
    --  to: https://plus.google.com/communities/103655397235276743411
    -+  to: https://plus.google.com/communities/105153134372062985968
    - - from: /preview/bug
    -   to: https://source.android.com/source/report-bugs.html
    --- from: /preview/bug/
    -+- from: /preview/bug/...
    -   to: https://source.android.com/source/report-bugs.html
    - - from: /preview/bugreport
    -   to: https://source.android.com/source/report-bugs.html
    --- from: /preview/bugreport/
    -+- from: /preview/bugreport/...
    -   to: https://source.android.com/source/report-bugs.html
    - - from: /preview/bugs
    -   to: https://code.google.com/p/android/issues/list?can=2&q=label%3ADevPreview-N
    --- from: /preview/bugs/
    -+- from: /preview/bugs/...
    -   to: https://code.google.com/p/android/issues/list?can=2&q=label%3ADevPreview-N
    - - from: /preview/bugreports
    -   to: https://code.google.com/p/android/issues/list?can=2&q=label%3ADevPreview-N
    --- from: /preview/bugreports/
    -+- from: /preview/bugreports/...
    -   to: https://code.google.com/p/android/issues/list?can=2&q=label%3ADevPreview-N
    -+- from: /preview/setup-sdk.html
    -+  to: /studio/index.html
    - - from: /2016/03/first-preview-of-android-n-developer.html
    -   to: http://android-developers.blogspot.com/2016/03/first-preview-of-android-n-developer.html
    -+
    - - from: /reference/org/apache/http/...
    -   to: /about/versions/marshmallow/android-6.0-changes.html#behavior-apache-http-client
    - - from: /shareables/...
    -@@ -839,6 +850,10 @@ redirects:
    -   to: /topic/performance/power/network/gather-data.html
    - - from: /training/performance/battery/network/index.html
    -   to: /topic/performance/power/network/index.html
    -+- from: /training/articles/memory.html
    -+  to: /topic/performance/memory.html
    -+- from: /topic/performance/optimizing-view-hierarchies.html
    -+  to: /topic/performance/rendering/optimizing-view-hierarchies.html
    - 
    - # Redirects for the new [dac]/topic/libraries/ area
    - 
    -@@ -1153,92 +1168,132 @@ redirects:
    - # Vanity urls
    - - from: /background_optimizations
    -   to: /preview/features/background-optimization.html
    --- from: /background_optimizations/
    -+- from: /background_optimizations/...
    -   to: /preview/features/background-optimization.html
    - - from: /bgopt
    -   to: /preview/features/background-optimization.html
    --- from: /bgopt/
    -+- from: /bgopt/...
    -   to: /preview/features/background-optimization.html
    - 
    - 
    - 
    - # Android Studio help button redirects
    - - from: /r/studio-ui/vector-asset-studio.html
    --  to: /studio/write/vector-asset-studio.html?utm_medium=android-studio
    -+  to: /studio/write/vector-asset-studio.html?utm_source=android-studio
    - - from: /r/studio-ui/image-asset-studio.html
    --  to: /studio/write/image-asset-studio.html?utm_medium=android-studio
    -+  to: /studio/write/image-asset-studio.html?utm_source=android-studio
    - - from: /r/studio-ui/project-structure.html
    --  to: /studio/projects/index.html?utm_medium=android-studio
    -+  to: /studio/projects/index.html?utm_source=android-studio
    - - from: /r/studio-ui/android-monitor.html
    --  to: /studio/profile/android-monitor.html?utm_medium=android-studio
    -+  to: /studio/profile/android-monitor.html?utm_source=android-studio
    - - from: /r/studio-ui/am-logcat.html
    --  to: /studio/debug/am-logcat.html?utm_medium=android-studio
    -+  to: /studio/debug/am-logcat.html?utm_source=android-studio
    - - from: /r/studio-ui/am-memory.html
    --  to: /studio/profile/am-memory.html?utm_medium=android-studio
    -+  to: /studio/profile/am-memory.html?utm_source=android-studio
    - - from: /r/studio-ui/am-cpu.html
    --  to: /studio/profile/am-cpu.html?utm_medium=android-studio
    -+  to: /studio/profile/am-cpu.html?utm_source=android-studio
    - - from: /r/studio-ui/am-gpu.html
    --  to: /studio/profile/am-gpu.html?utm_medium=android-studio
    -+  to: /studio/profile/am-gpu.html?utm_source=android-studio
    - - from: /r/studio-ui/am-network.html
    --  to: /studio/profile/am-network.html?utm_medium=android-studio
    -+  to: /studio/profile/am-network.html?utm_source=android-studio
    - - from: /r/studio-ui/am-hprof.html
    --  to: /studio/profile/am-hprof.html?utm_medium=android-studio
    -+  to: /studio/profile/am-hprof.html?utm_source=android-studio
    - - from: /r/studio-ui/am-allocation.html
    --  to: /studio/profile/am-allocation.html?utm_medium=android-studio
    -+  to: /studio/profile/am-allocation.html?utm_source=android-studio
    - - from: /r/studio-ui/am-methodtrace.html
    --  to: /studio/profile/am-methodtrace.html?utm_medium=android-studio
    -+  to: /studio/profile/am-methodtrace.html?utm_source=android-studio
    - - from: /r/studio-ui/am-sysinfo.html
    --  to: /studio/profile/am-sysinfo.html?utm_medium=android-studio
    -+  to: /studio/profile/am-sysinfo.html?utm_source=android-studio
    - - from: /r/studio-ui/am-screenshot.html
    --  to: /studio/debug/am-screenshot.html?utm_medium=android-studio
    -+  to: /studio/debug/am-screenshot.html?utm_source=android-studio
    - - from: /r/studio-ui/am-video.html
    --  to: /studio/debug/am-video.html?utm_medium=android-studio
    -+  to: /studio/debug/am-video.html?utm_source=android-studio
    - - from: /r/studio-ui/avd-manager.html
    --  to: /studio/run/managing-avds.html?utm_medium=android-studio
    -+  to: /studio/run/managing-avds.html?utm_source=android-studio
    - - from: /r/studio-ui/rundebugconfig.html
    --  to: /studio/run/rundebugconfig.html?utm_medium=android-studio
    -+  to: /studio/run/rundebugconfig.html?utm_source=android-studio
    - - from: /r/studio-ui/devicechooser.html
    --  to: /studio/run/emulator.html?utm_medium=android-studio
    -+  to: /studio/run/emulator.html?utm_source=android-studio
    - - from: /r/studio-ui/virtualdeviceconfig.html
    --  to: /studio/run/managing-avds.html?utm_medium=android-studio
    -+  to: /studio/run/managing-avds.html?utm_source=android-studio
    - - from: /r/studio-ui/emulator.html
    --  to: /studio/run/emulator.html?utm_medium=android-studio
    -+  to: /studio/run/emulator.html?utm_source=android-studio
    - - from: /r/studio-ui/instant-run.html
    --  to: /studio/run/index.html?utm_medium=android-studio#instant-run
    -+  to: /studio/run/index.html?utm_source=android-studio#instant-run
    - - from: /r/studio-ui/test-recorder.html
    --  to: http://tools.android.com/tech-docs/test-recorder
    -+  to: /studio/test/espresso-test-recorder.html?utm_source=android-studio
    - - from: /r/studio-ui/export-licenses.html
    -   to: http://tools.android.com/tech-docs/new-build-system/license
    - - from: /r/studio-ui/experimental-to-stable-gradle.html
    -   to: http://tools.android.com/tech-docs/new-build-system/gradle-experimental/experimental-to-stable-gradle
    - - from: /r/studio-ui/sdk-manager.html
    --  to: /studio/intro/update.html?utm_medium=android-studio#sdk-manager
    -+  to: /studio/intro/update.html?utm_source=android-studio#sdk-manager
    - - from: /r/studio-ui/newjclass.html
    --  to: /studio/write/create-java-class.html?utm_medium=android-studio
    -+  to: /studio/write/create-java-class.html?utm_source=android-studio
    - - from: /r/studio-ui/menu-help.html
    --  to: /studio/intro/index.html?utm_medium=android-studio
    -+  to: /studio/intro/index.html?utm_source=android-studio
    - - from: /r/studio-ui/menu-start.html
    --  to: /training/index.html?utm_medium=android-studio
    -+  to: /training/index.html?utm_source=android-studio
    - - from: /r/studio-ui/run-with-work-profile.html
    --  to: /studio/run/index.html#ir-work-profile?utm_medium=android-studio
    -+  to: /studio/run/index.html?utm_source=android-studio#ir-work-profile
    - - from: /r/studio-ui/am-gpu-debugger.html
    --  to: /studio/profile/am-gpu.html?utm_medium=android-studio
    -+  to: /studio/debug/am-gpu-debugger.html?utm_source=android-studio
    - - from: /r/studio-ui/theme-editor.html
    --  to: /studio/write/theme-editor.html?utm_medium=android-studio
    -+  to: /studio/write/theme-editor.html?utm_source=android-studio
    - - from: /r/studio-ui/translations-editor.html
    --  to: /studio/write/translations-editor.html?utm_medium=android-studio
    -+  to: /studio/write/translations-editor.html?utm_source=android-studio
    - - from: /r/studio-ui/debug.html
    --  to: /studio/debug/index.html?utm_medium=android-studio
    -+  to: /studio/debug/index.html?utm_source=android-studio
    - - from: /r/studio-ui/run.html
    --  to: /studio/run/index.html?utm_medium=android-studio
    -+  to: /studio/run/index.html?utm_source=android-studio
    - - from: /r/studio-ui/layout-editor.html
    --  to: /studio/write/layout-editor.html?utm_medium=android-studio
    -+  to: /studio/write/layout-editor.html?utm_source=android-studio
    - - from: /r/studio-ui/project-window.html
    --  to: /studio/projects/index.html?utm_medium=android-studio
    -+  to: /studio/projects/index.html?utm_source=android-studio
    - - from: /r/studio-ui/lint-inspection-results.html
    --  to: /studio/write/lint.html?utm_medium=android-studio
    -+  to: /studio/write/lint.html?utm_source=android-studio
    - - from: /r/studio-ui/gradle-console.html
    --  to: /studio/run/index.html#gradle-console?utm_medium=android-studio
    -+  to: /studio/run/index.html?utm_source=android-studio#gradle-console
    -+- from: /r/studio-ui/app-indexing-test.html
    -+  to: /studio/write/app-link-indexing.html#appindexingtest?utm_source=android-studio
    -+- from: /r/studio-ui/vcs.html
    -+  to: /studio/intro/index.html#version_control_basics?utm_source=android-studio
    -+- from: /r/studio-ui/create-new-module.html
    -+  to: /studio/projects/index.html#ApplicationModules?utm_source=android-studio
    -+- from: /r/studio-ui/build-variants.html
    -+  to: /studio/run/index.html#changing-variant?utm_source=android-studio
    -+- from: /r/studio-ui/generate-signed-apk.html
    -+  to: /studio/publish/app-signing.html#release-mode?utm_source=android-studio
    -+- from: /r/studio-ui/import-project-vcs.html
    -+  to: /studio/projects/create-project.html#ImportAProject?utm_source=android-studio
    -+- from: /r/studio-ui/apk-analyzer.html
    -+  to: /studio/build/apk-analyzer.html?utm_source=android-studio
    -+- from: /r/studio-ui/breakpoints.html
    -+  to: /studio/debug/index.html#breakPointsView?utm_source=android-studio
    -+- from: /r/studio-ui/attach-debugger-to-process.html
    -+  to: /studio/debug/index.html?utm_source=android-studio
    -+- from: /r/studio-ui/import-sample.html
    -+  to: /samples/index.html?utm_source=android-studio
    -+- from: /r/studio-ui/import-module.html
    -+  to: /studio/projects/add-app-module.html#ImportAModule?utm_source=android-studio
    -+- from: /r/studio-ui/import-project.html
    -+  to: /studio/projects/create-project.html#ImportAProject?utm_source=android-studio
    -+- from: /r/studio-ui/create-project.html
    -+  to: /studio/projects/create-project.html?utm_source=android-studio
    -+- from: /r/studio-ui/new-activity.html
    -+  to: /studio/projects/template.html?utm_source=android-studio
    -+- from: /r/studio-ui/new-resource-file.html
    -+  to: /studio/write/add-resources.html?utm_source=android-studio
    -+- from: /r/studio-ui/new-resource-dir.html
    -+  to: /studio/write/add-resources.html#add_a_resource_directory?utm_source=android-studio
    -+- from: /r/studio-ui/configure-component.html
    -+  to: /studio/write/add-resources.html?utm_source=android-studio
    -+- from: /r/studio-ui/ninepatch.html
    -+  to: /studio/write/draw9patch.html?utm_source=android-studio
    -+- from: /r/studio-ui/firebase-assistant.html
    -+  to: /studio/write/firebase.html?utm_source=android-studio
    -+- from: /r/studio-ui/ir-flight-recorder.html
    -+  to: /studio/run/index.html?utm_source=android-studio#submit-feedback
    - 
    - # Redirects from (removed) N Preview documentation
    - - from: /preview/features/afw.html
    -@@ -1281,4 +1336,3 @@ redirects:
    -   to: /topic/performance/background-optimization.html
    - - from: /preview/features/data-saver.html
    -   to: /training/basics/network-ops/data-saver.html
    --
    -diff --git a/docs/html/about/dashboards/index.jd b/docs/html/about/dashboards/index.jd
    -index f5d23e8..2721c85 100644
    ---- a/docs/html/about/dashboards/index.jd
    -+++ b/docs/html/about/dashboards/index.jd
    -@@ -59,7 +59,7 @@ Platform Versions</a>.</p>
    - </div>
    - 
    - 
    --<p style="clear:both"><em>Data collected during a 7-day period ending on August 1, 2016.
    -+<p style="clear:both"><em>Data collected during a 7-day period ending on September 5, 2016.
    - <br/>Any versions with less than 0.1% distribution are not shown.</em>
    - </p>
    - 
    -@@ -81,7 +81,7 @@ Screens</a>.</p>
    - </div>
    - 
    - 
    --<p style="clear:both"><em>Data collected during a 7-day period ending on August 1, 2016.
    -+<p style="clear:both"><em>Data collected during a 7-day period ending on September 5, 2016.
    - 
    - <br/>Any screen configurations with less than 0.1% distribution are not shown.</em></p>
    - 
    -@@ -101,7 +101,7 @@ support for any lower version (for example, support for version 2.0 also implies
    - 
    - 
    - <img alt="" style="float:right"
    --src="//chart.googleapis.com/chart?chl=GL%202.0%7CGL%203.0%7CGL%203.1&chf=bg%2Cs%2C00000000&chd=t%3A46.0%2C42.6%2C11.4&chco=c4df9b%2C6fad0c&cht=p&chs=400x250">
    -+src="//chart.googleapis.com/chart?chl=GL%202.0%7CGL%203.0%7CGL%203.1&chf=bg%2Cs%2C00000000&chd=t%3A44.9%2C42.3%2C12.8&chco=c4df9b%2C6fad0c&cht=p&chs=400x250">
    - 
    - <p>To declare which version of OpenGL ES your application requires, you should use the {@code
    - android:glEsVersion} attribute of the <a
    -@@ -119,21 +119,21 @@ uses.</p>
    - </tr>
    - <tr>
    - <td>2.0</td>
    --<td>46.0%</td>
    -+<td>44.9%</td>
    - </tr>
    - <tr>
    - <td>3.0</td>
    --<td>42.6%</td>
    -+<td>42.3%</td>
    - </tr>
    - <tr>
    - <td>3.1</td>
    --<td>11.4%</td>
    -+<td>12.8%</td>
    - </tr>
    - </table>
    - 
    - 
    - 
    --<p style="clear:both"><em>Data collected during a 7-day period ending on August 1, 2016</em></p>
    -+<p style="clear:both"><em>Data collected during a 7-day period ending on September 5, 2016</em></p>
    - 
    - 
    - 
    -@@ -147,19 +147,19 @@ var SCREEN_DATA =
    -       "Large": {
    -         "hdpi": "0.5",
    -         "ldpi": "0.2",
    --        "mdpi": "4.3",
    -+        "mdpi": "4.1",
    -         "tvdpi": "2.1",
    -         "xhdpi": "0.5"
    -       },
    -       "Normal": {
    --        "hdpi": "40.0",
    --        "mdpi": "3.8",
    --        "tvdpi": "0.1",
    --        "xhdpi": "27.3",
    -+        "hdpi": "39.5",
    -+        "mdpi": "3.5",
    -+        "tvdpi": "0.2",
    -+        "xhdpi": "28.4",
    -         "xxhdpi": "15.5"
    -       },
    -       "Small": {
    --        "ldpi": "1.8"
    -+        "ldpi": "1.6"
    -       },
    -       "Xlarge": {
    -         "hdpi": "0.3",
    -@@ -167,8 +167,8 @@ var SCREEN_DATA =
    -         "xhdpi": "0.7"
    -       }
    -     },
    --    "densitychart": "//chart.googleapis.com/chart?chd=t%3A2.0%2C11.0%2C2.2%2C40.8%2C28.5%2C15.5&chf=bg%2Cs%2C00000000&chl=ldpi%7Cmdpi%7Ctvdpi%7Chdpi%7Cxhdpi%7Cxxhdpi&cht=p&chs=400x250&chco=c4df9b%2C6fad0c",
    --    "layoutchart": "//chart.googleapis.com/chart?chd=t%3A3.9%2C7.6%2C86.7%2C1.8&chf=bg%2Cs%2C00000000&chl=Xlarge%7CLarge%7CNormal%7CSmall&cht=p&chs=400x250&chco=c4df9b%2C6fad0c"
    -+    "densitychart": "//chart.googleapis.com/chart?chl=ldpi%7Cmdpi%7Ctvdpi%7Chdpi%7Cxhdpi%7Cxxhdpi&chd=t%3A1.8%2C10.5%2C2.3%2C40.4%2C29.6%2C15.5&chf=bg%2Cs%2C00000000&chco=c4df9b%2C6fad0c&cht=p&chs=400x250",
    -+    "layoutchart": "//chart.googleapis.com/chart?chl=Xlarge%7CLarge%7CNormal%7CSmall&chd=t%3A3.9%2C7.4%2C87.2%2C1.6&chf=bg%2Cs%2C00000000&chco=c4df9b%2C6fad0c&cht=p&chs=400x250"
    -   }
    - ];
    - 
    -@@ -176,7 +176,7 @@ var SCREEN_DATA =
    - var VERSION_DATA =
    - [
    -   {
    --    "chart": "//chart.googleapis.com/chart?chd=t%3A0.1%2C1.7%2C1.6%2C16.7%2C29.2%2C35.5%2C15.2&chf=bg%2Cs%2C00000000&chl=Froyo%7CGingerbread%7CIce%20Cream%20Sandwich%7CJelly%20Bean%7CKitKat%7CLollipop%7CMarshmallow&cht=p&chs=500x250&chco=c4df9b%2C6fad0c",
    -+    "chart": "//chart.googleapis.com/chart?chl=Froyo%7CGingerbread%7CIce%20Cream%20Sandwich%7CJelly%20Bean%7CKitKat%7CLollipop%7CMarshmallow&chd=t%3A0.1%2C1.5%2C1.4%2C15.6%2C27.7%2C35.0%2C18.7&chf=bg%2Cs%2C00000000&chco=c4df9b%2C6fad0c&cht=p&chs=500x250",
    -     "data": [
    -       {
    -         "api": 8,
    -@@ -186,47 +186,47 @@ var VERSION_DATA =
    -       {
    -         "api": 10,
    -         "name": "Gingerbread",
    --        "perc": "1.7"
    -+        "perc": "1.5"
    -       },
    -       {
    -         "api": 15,
    -         "name": "Ice Cream Sandwich",
    --        "perc": "1.6"
    -+        "perc": "1.4"
    -       },
    -       {
    -         "api": 16,
    -         "name": "Jelly Bean",
    --        "perc": "6.0"
    -+        "perc": "5.6"
    -       },
    -       {
    -         "api": 17,
    -         "name": "Jelly Bean",
    --        "perc": "8.3"
    -+        "perc": "7.7"
    -       },
    -       {
    -         "api": 18,
    -         "name": "Jelly Bean",
    --        "perc": "2.4"
    -+        "perc": "2.3"
    -       },
    -       {
    -         "api": 19,
    -         "name": "KitKat",
    --        "perc": "29.2"
    -+        "perc": "27.7"
    -       },
    -       {
    -         "api": 21,
    -         "name": "Lollipop",
    --        "perc": "14.1"
    -+        "perc": "13.1"
    -       },
    -       {
    -         "api": 22,
    -         "name": "Lollipop",
    --        "perc": "21.4"
    -+        "perc": "21.9"
    -       },
    -       {
    -         "api": 23,
    -         "name": "Marshmallow",
    --        "perc": "15.2"
    -+        "perc": "18.7"
    -       }
    -     ]
    -   }
    -diff --git a/docs/html/about/versions/_project.yaml b/docs/html/about/versions/_project.yaml
    -new file mode 100644
    -index 0000000..3f0e85e
    ---- /dev/null
    -+++ b/docs/html/about/versions/_project.yaml
    -@@ -0,0 +1,6 @@
    -+name: "Versions"
    -+home_url: /about/versions/
    -+description: "Android, the world's most popular mobile platform"
    -+content_license: cc3-apache2
    -+buganizer_id: 30209417
    -+parent_project_metadata_path: /about/_project.yaml
    -diff --git a/docs/html/about/versions/android-1.5.jd b/docs/html/about/versions/android-1.5.jd
    -index 45a27ee..6db5472 100644
    ---- a/docs/html/about/versions/android-1.5.jd
    -+++ b/docs/html/about/versions/android-1.5.jd
    -@@ -101,7 +101,7 @@ function toggleDiv(link) {
    - .toggleable.closed .toggleme {
    -   display:none;
    - }
    --#jd-content .toggle-img {
    -+#body-content .toggle-img {
    -   margin:0;
    - }
    - </style>
    -diff --git a/docs/html/about/versions/android-1.6-highlights.jd b/docs/html/about/versions/android-1.6-highlights.jd
    -index 9179579..f594449 100644
    ---- a/docs/html/about/versions/android-1.6-highlights.jd
    -+++ b/docs/html/about/versions/android-1.6-highlights.jd
    -@@ -6,8 +6,8 @@ sdk.date=September 2009
    - 
    - 
    - <style type="text/css">
    --#jd-content div.screenshot,
    --#jd-content div.video {
    -+#body-content div.screenshot,
    -+#body-content div.video {
    -   float:right;
    -   clear:right;
    -   padding:15px 70px;
    -@@ -15,11 +15,11 @@ sdk.date=September 2009
    -   font-weight:bold;
    -   line-height:1.7em;
    - }
    --#jd-content div.video {
    -+#body-content div.video {
    -   padding-top:0;
    -   margin-top:-15px;
    - }
    --#jd-content div.screenshot img {
    -+#body-content div.screenshot img {
    -   margin:0;
    - }
    - </style>
    -diff --git a/docs/html/about/versions/android-1.6.jd b/docs/html/about/versions/android-1.6.jd
    -index 970c343..a84c225 100755
    ---- a/docs/html/about/versions/android-1.6.jd
    -+++ b/docs/html/about/versions/android-1.6.jd
    -@@ -103,7 +103,7 @@ function toggleDiv(link) {
    - .toggleable.closed .toggleme {
    -   display:none;
    - }
    --#jd-content .toggle-img {
    -+#body-content .toggle-img {
    -   margin:0;
    - }
    - </style>
    -diff --git a/docs/html/about/versions/android-2.0-highlights.jd b/docs/html/about/versions/android-2.0-highlights.jd
    -index 3f7e1c8..017b16f 100644
    ---- a/docs/html/about/versions/android-2.0-highlights.jd
    -+++ b/docs/html/about/versions/android-2.0-highlights.jd
    -@@ -6,8 +6,8 @@ sdk.date=October 2009
    - 
    - 
    - <style type="text/css">
    --#jd-content div.screenshot,
    --#jd-content div.video {
    -+#body-content div.screenshot,
    -+#body-content div.video {
    -   float:right;
    -   clear:right;
    -   padding:15px 60px;
    -@@ -15,15 +15,15 @@ sdk.date=October 2009
    -   font-weight:bold;
    -   line-height:1.7em;
    - }
    --#jd-content div.video {
    -+#body-content div.video {
    -   padding-top:0;
    -   margin-top:-15px;
    - }
    --#jd-content div.screenshot.second {
    -+#body-content div.screenshot.second {
    -   clear:none;
    -   padding:15px 0 15px 60px;
    - }
    --#jd-content div.screenshot img {
    -+#body-content div.screenshot img {
    -   margin:0;
    -   border:1px solid #ccc;
    - }
    -diff --git a/docs/html/about/versions/android-2.0.1.jd b/docs/html/about/versions/android-2.0.1.jd
    -index b0f4db6..21bfa65 100644
    ---- a/docs/html/about/versions/android-2.0.1.jd
    -+++ b/docs/html/about/versions/android-2.0.1.jd
    -@@ -99,7 +99,7 @@ padding: .25em 1em;
    - .toggleable.closed .toggleme {
    -   display:none;
    - }
    --#jd-content .toggle-img {
    -+#body-content .toggle-img {
    -   margin:0;
    - }
    - </style>
    -diff --git a/docs/html/about/versions/android-2.0.jd b/docs/html/about/versions/android-2.0.jd
    -index 0323686..8029633 100644
    ---- a/docs/html/about/versions/android-2.0.jd
    -+++ b/docs/html/about/versions/android-2.0.jd
    -@@ -92,7 +92,7 @@ padding: .25em 1em;
    - .toggleable.closed .toggleme {
    -   display:none;
    - }
    --#jd-content .toggle-img {
    -+#body-content .toggle-img {
    -   margin:0;
    - }
    - </style>
    -diff --git a/docs/html/about/versions/android-2.2-highlights.jd b/docs/html/about/versions/android-2.2-highlights.jd
    -index afbf26b..37a7a82 100644
    ---- a/docs/html/about/versions/android-2.2-highlights.jd
    -+++ b/docs/html/about/versions/android-2.2-highlights.jd
    -@@ -5,32 +5,32 @@ excludeFromSuggestions=true
    - 
    - 
    - <style type="text/css">
    --#jd-content {
    -+#body-content {
    -   max-width:800px;
    - }
    --#jd-content div.screenshot {
    -+#body-content div.screenshot {
    -   float:left;
    -   clear:left;
    -   padding:15px 30px 15px 0;
    - }
    --#jd-content div.video {
    -+#body-content div.video {
    -   float:right;
    -   padding:0 60px 40px;
    -   margin-top:-15px;
    - }
    --#jd-content table.columns {
    -+#body-content table.columns {
    -   margin:0 0 1em 0;
    - }
    --#jd-content table.columns td {
    -+#body-content table.columns td {
    -   padding:0;
    - }
    --#jd-content table.columns td+td {
    -+#body-content table.columns td+td {
    -   padding:0 2em;
    - }
    --#jd-content table.columns td img {
    -+#body-content table.columns td img {
    -   margin:0;
    - }
    --#jd-content table.columns td+td>*:first-child {
    -+#body-content table.columns td+td>*:first-child {
    -   margin-top:-2em;
    - }
    - .green {
    -diff --git a/docs/html/about/versions/android-2.3-highlights.jd b/docs/html/about/versions/android-2.3-highlights.jd
    -index 582bce9..013ec7f 100644
    ---- a/docs/html/about/versions/android-2.3-highlights.jd
    -+++ b/docs/html/about/versions/android-2.3-highlights.jd
    -@@ -4,31 +4,31 @@ page.title=Gingerbread
    - 
    - 
    - <style type="text/css">
    --#jd-content {
    -+#body-content {
    -   max-width:1200px;
    - }
    --#jd-content div.screenshot {
    -+#body-content div.screenshot {
    -   float:left;
    -   clear:left;
    -   padding:15px 30px 15px 0;
    - }
    --#jd-content div.video {
    -+#body-content div.video {
    -   float:right;
    -   padding:0 0 0 40px;
    - }
    --#jd-content table.columns {
    -+#body-content table.columns {
    -   margin:0 0 1em 0;
    - }
    --#jd-content table.columns td {
    -+#body-content table.columns td {
    -   padding:0;
    - }
    --#jd-content table.columns td+td {
    -+#body-content table.columns td+td {
    -   padding:0 2em;
    - }
    --#jd-content table.columns td img {
    -+#body-content table.columns td img {
    -   margin:0;
    - }
    --#jd-content table.columns td+td>*:first-child {
    -+#body-content table.columns td+td>*:first-child {
    -   margin-top:-2em;
    - }
    - .green {
    -diff --git a/docs/html/about/versions/android-3.0-highlights.jd b/docs/html/about/versions/android-3.0-highlights.jd
    -index e9d2b39..50d4667 100644
    ---- a/docs/html/about/versions/android-3.0-highlights.jd
    -+++ b/docs/html/about/versions/android-3.0-highlights.jd
    -@@ -4,31 +4,31 @@ page.title=Honeycomb
    - 
    - 
    - <style type="text/css">
    --#jd-content {
    -+#body-content {
    -   max-width:1200px;
    - }
    --#jd-content div.screenshot {
    -+#body-content div.screenshot {
    -   float:left;
    -   clear:left;
    -   padding:15px 30px 15px 0;
    - }
    --#jd-content div.video {
    -+#body-content div.video {
    -   float:right;
    -   padding:0 60px 40px;
    - }
    --#jd-content table.columns {
    -+#body-content table.columns {
    -   margin:0 0 1em 0;
    - }
    --#jd-content table.columns td {
    -+#body-content table.columns td {
    -   padding:0;
    - }
    --#jd-content table.columns td+td {
    -+#body-content table.columns td+td {
    -   padding:0 2em;
    - }
    --#jd-content table.columns td img {
    -+#body-content table.columns td img {
    -   margin:0;
    - }
    --#jd-content table.columns td+td>*:first-child {
    -+#body-content table.columns td+td>*:first-child {
    -   margin-top:-2em;
    - }
    - .green {
    -diff --git a/docs/html/about/versions/android-3.1-highlights.jd b/docs/html/about/versions/android-3.1-highlights.jd
    -index 2a70698..22df372 100644
    ---- a/docs/html/about/versions/android-3.1-highlights.jd
    -+++ b/docs/html/about/versions/android-3.1-highlights.jd
    -@@ -4,31 +4,31 @@ page.title=Honeycomb MR1
    - 
    - 
    - <style type="text/css">
    --#jd-content {
    -+#body-content {
    -   max-width:1200px;
    - }
    --#jd-content div.screenshot {
    -+#body-content div.screenshot {
    -   float:left;
    -   clear:left;
    -   padding:15px 30px 15px 0;
    - }
    --#jd-content div.video {
    -+#body-content div.video {
    -   float:right;
    -   padding:0 60px 40px;
    - }
    --#jd-content table.columns {
    -+#body-content table.columns {
    -   margin:0 0 1em 0;
    - }
    --#jd-content table.columns td {
    -+#body-content table.columns td {
    -   padding:0;
    - }
    --#jd-content table.columns td+td {
    -+#body-content table.columns td+td {
    -   padding:0 2em;
    - }
    --#jd-content table.columns td img {
    -+#body-content table.columns td img {
    -   margin:0;
    - }
    --#jd-content table.columns td+td>*:first-child {
    -+#body-content table.columns td+td>*:first-child {
    -   margin-top:-2em;
    - }
    - .green {
    -diff --git a/docs/html/about/versions/android-4.0-highlights.jd b/docs/html/about/versions/android-4.0-highlights.jd
    -index c980af6..57eb2a3 100755
    ---- a/docs/html/about/versions/android-4.0-highlights.jd
    -+++ b/docs/html/about/versions/android-4.0-highlights.jd
    -@@ -4,31 +4,31 @@ page.title=Ice Cream Sandwich
    - 
    - 
    - <style type="text/css">
    --#jd-content {
    -+#body-content {
    -   max-width:1024px;
    - }
    --#jd-content div.screenshot {
    -+#body-content div.screenshot {
    -   float:left;
    -   clear:left;
    -   padding:15px 30px 15px 0;
    - }
    --#jd-content div.video {
    -+#body-content div.video {
    -   float:right;
    -   padding:0 0 40px 60px;
    - }
    --#jd-content table.columns {
    -+#body-content table.columns {
    -   margin:0 0 1em 0;
    - }
    --#jd-content table.columns td {
    -+#body-content table.columns td {
    -   padding:0;
    - }
    --#jd-content table.columns td+td {
    -+#body-content table.columns td+td {
    -   padding:0 2em;
    - }
    --#jd-content table.columns td img {
    -+#body-content table.columns td img {
    -   margin:0;
    - }
    --#jd-content table.columns td+td>*:first-child {
    -+#body-content table.columns td+td>*:first-child {
    -   margin-top:-2em;
    - }
    - .green {
    -diff --git a/docs/html/about/versions/android-4.0.jd b/docs/html/about/versions/android-4.0.jd
    -index bf68584..48afcd4 100644
    ---- a/docs/html/about/versions/android-4.0.jd
    -+++ b/docs/html/about/versions/android-4.0.jd
    -@@ -631,8 +631,8 @@ Bluetooth connection.</p>
    - <p>A new package, {@link android.net.wifi.p2p}, contains all the APIs for performing peer-to-peer
    - connections with Wi-Fi. The primary class you need to work with is {@link
    - android.net.wifi.p2p.WifiP2pManager}, which you can acquire by calling {@link
    --android.app.Activity#getSystemService(java.lang.String) getSystemService(WIFI_P2P_SERVICE)}.
    --The {@link android.net.wifi.p2p.WifiP2pManager} includes APIs that allow you to:</p>
    -+android.app.Activity#getSystemService getSystemService(WIFI_P2P_SERVICE)}. The {@link
    -+android.net.wifi.p2p.WifiP2pManager} includes APIs that allow you to:</p>
    - <ul>
    - <li>Initialize your application for P2P connections by calling {@link
    - android.net.wifi.p2p.WifiP2pManager#initialize initialize()}</li>
    -@@ -798,7 +798,7 @@ text content to the {@link android.view.accessibility.AccessibilityEvent} if the
    - android.R.attr#contentDescription android:contentDescription} text is missing or
    - insufficient. To add more text description to the
    - {@link android.view.accessibility.AccessibilityEvent}, call {@link
    --android.view.accessibility.AccessibilityRecord#getText()}.{@link java.util.List#add add()}.</p>
    -+android.view.accessibility.AccessibilityEvent#getText()}.{@link java.util.List#add add()}.</p>
    - </li>
    -   <li>At this point, the {@link android.view.View} passes the event up the view hierarchy by calling
    - {@link android.view.ViewGroup#requestSendAccessibilityEvent requestSendAccessibilityEvent()} on the
    -diff --git a/docs/html/about/versions/android-4.2.jd b/docs/html/about/versions/android-4.2.jd
    -index ac84d0f..34fa1d4 100755
    ---- a/docs/html/about/versions/android-4.2.jd
    -+++ b/docs/html/about/versions/android-4.2.jd
    -@@ -213,9 +213,9 @@ setScreenBright(true)} allows you to instead set the display at its usual bright
    - <p>Android now allows your app to display unique content on additional screens that are connected
    - to the user’s device over either a wired connection or Wi-Fi.
    -  To create unique content for a secondary display, extend the {@link android.app.Presentation}
    --class and implement the {@link android.app.Dialog#onCreate onCreate()} callback. Within
    --{@link android.app.Dialog#onCreate onCreate()}, specify your UI for the secondary display
    --by calling {@link android.app.Dialog#setContentView setContentView()}.
    -+class and implement the {@link android.app.Presentation#onCreate onCreate()} callback. Within
    -+{@link android.app.Presentation#onCreate onCreate()}, specify your UI for the secondary display
    -+by calling {@link android.app.Presentation#setContentView setContentView()}.
    - As an extension of the {@link android.app.Dialog} class, the {@link
    - android.app.Presentation} class provides the region in which your app can display a unique UI on the
    - secondary display.</p>
    -@@ -241,13 +241,13 @@ appear on the secondary display.</p>
    - 
    - <p>To detect at runtime when a new display has been connected, create an instance of {@link
    - android.media.MediaRouter.SimpleCallback} in which you implement the {@link
    --android.media.MediaRouter.Callback#onRoutePresentationDisplayChanged
    -+android.media.MediaRouter.SimpleCallback#onRoutePresentationDisplayChanged
    - onRoutePresentationDisplayChanged()} callback method, which the system will call when a new
    - presentation display is connected. Then register the {@link
    - android.media.MediaRouter.SimpleCallback} by passing it to {@link
    - android.media.MediaRouter#addCallback MediaRouter.addCallback()} along with the {@link
    - android.media.MediaRouter#ROUTE_TYPE_LIVE_VIDEO} route type. When you receive a call to
    --{@link android.media.MediaRouter.Callback#onRoutePresentationDisplayChanged
    -+{@link android.media.MediaRouter.SimpleCallback#onRoutePresentationDisplayChanged
    - onRoutePresentationDisplayChanged()}, simply call {@link
    - android.media.MediaRouter#getSelectedRoute MediaRouter.getSelectedRoute()} as mentioned above.</p>
    - 
    -@@ -262,7 +262,7 @@ applied to your application or activity.</p>
    - likely a different screen density. Because the screen characteristics may different, you should
    - provide resources that are optimized specifically for such larger displays. If you need
    - to request additional resources from your {@link
    --android.app.Presentation}, call {@link android.app.Dialog#getContext()}{@link
    -+android.app.Presentation}, call {@link android.app.Presentation#getContext()}{@link
    - android.content.Context#getResources .getResources()} to get the {@link
    - android.content.res.Resources} object corresponding to the display. This provides
    - the appropriate resources from your app that are best suited for the
    -@@ -510,7 +510,7 @@ common operations for you such as:</p>
    -   <p>To use a script intrinsic, call the static <code>create()</code> method of each instrinsic
    -   to create an instance of the script. You then call the available <code>set()</code>
    -   methods of each script intrinsic to set any necessary inputs and options.
    --  Finally, call the {@link android.renderscript.Script#forEach forEach()}</code>
    -+  Finally, call the {@link android.renderscript.ScriptC#forEach forEach()}</code>
    -   method to execute the script.</p>
    -   </dd>
    - 
    -diff --git a/docs/html/about/versions/android-4.3.jd b/docs/html/about/versions/android-4.3.jd
    -index 34a701b..547b2f8 100644
    ---- a/docs/html/about/versions/android-4.3.jd
    -+++ b/docs/html/about/versions/android-4.3.jd
    -@@ -907,7 +907,7 @@ external data.</p>
    - 
    - <p>To track changes to inserts and updates, you can now include the {@link android.provider.ContactsContract.ContactsColumns#CONTACT_LAST_UPDATED_TIMESTAMP} parameter with your selection to query only the contacts that have changed since the last time you queried the provider.</p>
    - 
    --<p>To track which contacts have been deleted, the new table {@link android.provider.ContactsContract.DeletedContacts} provides a log of contacts that have been deleted (but each contact deleted is held in this table for a limited time). Similar to {@link android.provider.ContactsContract.ContactsColumns#CONTACT_LAST_UPDATED_TIMESTAMP}, you can use the new selection parameter, {@link android.provider.ContactsContract.DeletedContactsColumns#CONTACT_DELETED_TIMESTAMP} to check which contacts have been deleted since the last time you queried the provider. The table also contains the constant {@link android.provider.ContactsContract.DeletedContacts#DAYS_KEPT_MILLISECONDS} containing the number of days (in milliseconds) that the log will be kept.</p>
    -+<p>To track which contacts have been deleted, the new table {@link android.provider.ContactsContract.DeletedContacts} provides a log of contacts that have been deleted (but each contact deleted is held in this table for a limited time). Similar to {@link android.provider.ContactsContract.ContactsColumns#CONTACT_LAST_UPDATED_TIMESTAMP}, you can use the new selection parameter, {@link android.provider.ContactsContract.DeletedContacts#CONTACT_DELETED_TIMESTAMP} to check which contacts have been deleted since the last time you queried the provider. The table also contains the constant {@link android.provider.ContactsContract.DeletedContacts#DAYS_KEPT_MILLISECONDS} containing the number of days (in milliseconds) that the log will be kept.</p>
    - 
    - <p>Additionally, the Contacts Provider now broadcasts the {@link
    - android.provider.ContactsContract.Intents#CONTACTS_DATABASE_CREATED} action when the user
    -diff --git a/docs/html/about/versions/marshmallow/android-6.0-changes.jd b/docs/html/about/versions/marshmallow/android-6.0-changes.jd
    -index 65c976b..b44142e 100644
    ---- a/docs/html/about/versions/marshmallow/android-6.0-changes.jd
    -+++ b/docs/html/about/versions/marshmallow/android-6.0-changes.jd
    -@@ -280,7 +280,7 @@ change fixes a problem where Dalvik was checking access rules incorrectly in pre
    - If your app uses the
    - {@link java.lang.reflect.Constructor#newInstance(java.lang.Object...) newInstance()} method and you
    - want to override access checks, call the
    --{@link java.lang.reflect.AccessibleObject#setAccessible(boolean) setAccessible()} method with the input
    -+{@link java.lang.reflect.Constructor#setAccessible(boolean) setAccessible()} method with the input
    - parameter set to {@code true}. If your app uses the
    - <a href="{@docRoot}tools/support-library/features.html#v7-appcompat">v7 appcompat library</a> or the
    - <a href="{@docRoot}tools/support-library/features.html#v7-recyclerview">v7 recyclerview library</a>,
    -diff --git a/docs/html/about/versions/nougat/android-7.0-changes.jd b/docs/html/about/versions/nougat/android-7.0-changes.jd
    -index 84a56d0..cb92f19 100644
    ---- a/docs/html/about/versions/nougat/android-7.0-changes.jd
    -+++ b/docs/html/about/versions/nougat/android-7.0-changes.jd
    -@@ -182,8 +182,8 @@ certain implicit intents.
    - </p>
    - 
    - <p>
    --  For more information about background optimizations in N and how to adapt your app,
    --  see <a href=
    -+  For more information about background optimizations in Android 7.0 (API level
    -+  24) and how to adapt your app, see <a href=
    -   "{@docRoot}preview/features/background-optimization.html">Background
    -   Optimizations</a>.
    - </p>
    -@@ -427,12 +427,13 @@ see <a href="{@docRoot}training/secure-file-sharing/index.html">Sharing Files</a
    -   released apps, a set of libraries that see significant use—such as
    -   <code>libandroid_runtime.so</code>, <code>libcutils.so</code>,
    -   <code>libcrypto.so</code>, and <code>libssl.so</code>—are temporarily
    --  accessible on N for apps targeting API level 23 or lower. If your app loads
    --  one of these libraries, logcat generates a warning and a toast appears on the
    --  target device to notify you. If you see these warnings, you should update
    --  your app to either include its own copy of those libraries or only use the
    --  public NDK APIs. Future releases of the Android platform may restrict the use
    --  of private libraries altogether and cause your app to crash.
    -+  accessible on Android 7.0 (API level 24) for apps targeting API level 23 or
    -+  lower. If your app loads one of these libraries, logcat generates a warning
    -+  and a toast appears on the target device to notify you. If you see these
    -+  warnings, you should update your app to either include its own copy of those
    -+  libraries or only use the public NDK APIs. Future releases of the Android
    -+  platform may restrict the use of private libraries altogether and cause your
    -+  app to crash.
    - </p>
    - 
    - <p>
    -@@ -441,9 +442,9 @@ see <a href="{@docRoot}training/secure-file-sharing/index.html">Sharing Files</a
    -   <code>System.loadLibrary</code> and <code>dlopen(3)</code> both return
    -   <code>NULL</code>, and may cause your app to crash. You should review your
    -   app code to remove use of private platform APIs and thoroughly test your apps
    --  using a preview device or emulator. If you are unsure whether your app uses
    --  private libraries, you can <a href="#ndk-errors">check logcat</a> to identify
    --  the runtime error.
    -+  using a device or emulator running Android 7.0 (API level 24). If you are
    -+  unsure whether your app uses private libraries, you can <a href=
    -+  "#ndk-errors">check logcat</a> to identify the runtime error.
    - </p>
    - 
    - <p>
    -@@ -454,11 +455,6 @@ see <a href="{@docRoot}training/secure-file-sharing/index.html">Sharing Files</a
    - 
    - <table id="ndk-table">
    -   <col width="15%">
    --  <col width="15%">
    --  <col width="15%">
    --  <col width="20%">
    --  <col width="20%">
    --  <col width="20%">
    -   <tr>
    -     <th scope="col">
    -       Libraries
    -@@ -470,10 +466,7 @@ see <a href="{@docRoot}training/secure-file-sharing/index.html">Sharing Files</a
    -       Runtime access via dynamic linker
    -     </th>
    -     <th scope="col">
    --      N Developer Preview behavior
    --    </th>
    --    <th scope="col">
    --      Final N Release behavior
    -+      Android 7.0 (API level 24) behavior
    -     </th>
    -     <th scope="col">
    -       Future Android platform behavior
    -@@ -500,10 +493,6 @@ see <a href="{@docRoot}training/secure-file-sharing/index.html">Sharing Files</a
    -   <td style="background-color:#DCEDC8">
    -     Works as expected
    -   </td>
    --
    --  <td style="background-color:#DCEDC8">
    --    Works as expected
    --  </td>
    - </tr>
    - 
    - <tr>
    -@@ -520,11 +509,6 @@ see <a href="{@docRoot}training/secure-file-sharing/index.html">Sharing Files</a
    -   </td>
    - 
    -   <td style="background-color:#FFF9C4">
    --      Works as expected, but you receive a logcat warning and a message on the
    --      target device.
    --  </td>
    --
    --  <td style="background-color:#FFF9C4">
    -     Works as expected, but you receive a logcat warning.
    -   </td>
    - 
    -@@ -553,10 +537,6 @@ see <a href="{@docRoot}training/secure-file-sharing/index.html">Sharing Files</a
    -   <td style="background-color:#ffcdd2">
    -     Runtime error
    -   </td>
    --
    --  <td style="background-color:#ffcdd2">
    --    Runtime error
    --  </td>
    - </tr>
    - 
    - <tr>
    -@@ -579,10 +559,6 @@ see <a href="{@docRoot}training/secure-file-sharing/index.html">Sharing Files</a
    -   <td style="background-color:#ffcdd2">
    -     Runtime error
    -   </td>
    --
    --  <td style="background-color:#ffcdd2">
    --    Runtime error
    --  </td>
    - </tr>
    - </table>
    - 
    -@@ -699,8 +675,8 @@ JavaVM::AttachCurrentThread from &lt;jni.h&gt;.
    - 
    - <ul>
    -   <li>You must install a delegated certificate installer before the DPC can set
    --  it. For both profile and device-owner apps targeting the N SDK, you should
    --  install the delegated certificate installer before the device policy
    -+  it. For both profile and device-owner apps targeting Android 7.0 (API level 24),
    -+  you should install the delegated certificate installer before the device policy
    -   controller (DPC) calls
    -   <code>DevicePolicyManager.setCertInstallerPackage()</code>. If the installer
    -   is not already installed, the system throws an
    -@@ -747,12 +723,13 @@ JavaVM::AttachCurrentThread from &lt;jni.h&gt;.
    -   DER-encoded format under a .crt or .cer file extension.
    -   </li>
    - 
    --  <li>Starting in Android 7.0, fingerprint enrollment and storage are managed per user.
    --  If a profile owner’s Device Policy Client (DPC) targets pre-N on an N device,
    --  the user is still able to set fingerprint on the device, but work
    --  applications cannot access device fingerprint. When the DPC targets N and
    --  above, the user can set fingerprint specifically for work profile by going to
    --  <strong>Settings &gt; Security &gt; Work profile security</strong>.
    -+  <li>Starting in Android 7.0, fingerprint enrollment and storage are managed
    -+  per user. If a profile owner’s Device Policy Client (DPC) targets API level
    -+  23 (or lower) on a device running Android 7.0 (API level 24), the user is
    -+  still able to set fingerprint on the device, but work applications cannot
    -+  access device fingerprint. When the DPC targets API level 24 and above, the user can set
    -+  fingerprint specifically for work profile by going to <strong>Settings &gt;
    -+  Security &gt; Work profile security</strong>.
    -   </li>
    - 
    -   <li>A new encryption status <code>ENCRYPTION_STATUS_ACTIVE_PER_USER</code> is
    -@@ -822,8 +799,9 @@ when killing the app manually via DDMS.
    - </p>
    - 
    - <p>
    --Apps targeting N and above are not automatically killed on density changes;
    --however, they may still respond poorly to configuration changes.
    -+  Apps targeting Android 7.0 (API level 24) and above are not automatically
    -+  killed on density changes; however, they may still respond poorly to
    -+  configuration changes.
    - </p>
    - </li>
    - 
    -diff --git a/docs/html/about/versions/nougat/android-7.0-samples.jd b/docs/html/about/versions/nougat/android-7.0-samples.jd
    -index e283a7a..ff63bef 100644
    ---- a/docs/html/about/versions/nougat/android-7.0-samples.jd
    -+++ b/docs/html/about/versions/nougat/android-7.0-samples.jd
    -@@ -6,7 +6,7 @@ page.image=images/cards/card-n-samples_2x.png
    - 
    - <p>
    -   Use the code samples below to learn about Android 7.0 capabilities and APIs. To
    --  download the samples in Android Studio, select the <b>File &gt; Import
    -+  download the samples in Android Studio, select the <b>File &gt; New &gt; Import
    -   Samples</b> menu option.
    - </p>
    - 
    -diff --git a/docs/html/about/versions/nougat/android-7.0.jd b/docs/html/about/versions/nougat/android-7.0.jd
    -index 1ca540c..8ef8bd6 100644
    ---- a/docs/html/about/versions/nougat/android-7.0.jd
    -+++ b/docs/html/about/versions/nougat/android-7.0.jd
    -@@ -44,7 +44,7 @@ page.image=images/cards/card-n-apis_2x.png
    -         <li><a href="#vr">VR Support</a></li>
    -         <li><a href="#print_svc">Print Service Enhancements</a></li>
    -         <li><a href="#virtual_files">Virtual Files</a></li>
    --        <li><a href="#framemetrics_api">FrameMetricsListener API</a></li>
    -+        <li><a href="#framemetrics_api">Frame Metrics API</a></li>
    -       </ol>
    - </div>
    - </div>
    -@@ -434,9 +434,8 @@ displayed &mdash; users can add or move tiles just by dragging and dropping them
    - </p>
    - 
    - <p>
    --  For information about creating an app tile, see the documentation for
    --  <code>android.service.quicksettings.Tile</code> in the downloadable <a href=
    --  "{@docRoot}preview/setup-sdk.html#docs-dl">API Reference</a>.
    -+  For information about creating an app tile, see the reference documentation
    -+  for {@link android.service.quicksettings.Tile Tile}.
    - </p>
    - 
    - 
    -@@ -465,9 +464,8 @@ for the user in order to stop unwanted calls and texts from reaching the user
    - through any medium, such as a VOIP endpoint or forwarding phones.</p>
    - 
    - <p>
    --  For more information, see <code>android.provider.BlockedNumberContract</code>
    --  in the downloadable <a href="{@docRoot}preview/setup-sdk.html#docs-dl">API
    --  Reference</a>.
    -+  For more information, see the reference documentation for
    -+  {@link android.provider.BlockedNumberContract BlockedNumberContract}.
    - </p>
    - 
    - <h2 id="call_screening">Call Screening</h2>
    -@@ -486,9 +484,8 @@ through any medium, such as a VOIP endpoint or forwarding phones.</p>
    - </ul>
    - 
    - <p>
    --  For more information, see <code>android.telecom.CallScreeningService</code>
    --  in the downloadable <a href="{@docRoot}preview/setup-sdk.html#docs-dl">API
    --  Reference</a>.
    -+  For more information, see the reference documentation for
    -+  {@link android.telecom.CallScreeningService CallScreeningService}.
    - </p>
    - 
    - 
    -@@ -780,8 +777,9 @@ impairments to touch the screen. The new API allows building services with
    - features such as face-tracking, eye-tracking, point scanning, and so on, to
    - meet the needs of those users.</p>
    - 
    --<p>For more information, see <code>android.accessibilityservice.GestureDescription</code>
    --  in the downloadable <a href="{@docRoot}preview/setup-sdk.html#docs-dl">API Reference</a>.</p>
    -+<p>For more information, see the reference documentation for
    -+{@link android.accessibilityservice.GestureDescription GestureDescription}.
    -+</p>
    - 
    - 
    - <h2 id="direct_boot">Direct Boot</h2>
    -@@ -972,9 +970,8 @@ Directory Access</a> developer documentation.</p>
    -   from the system and from the app in focus. The system retrieves these
    -   shortcuts automatically from the app’s menu if the shortcuts exist. You can
    -   also provide your own fine-tuned shortcuts lists for the screen. You can do
    --  this by overriding the new <code>Activity.onProvideKeyboardShortcuts()</code>
    --  method, described in the downloadable <a href=
    --  "{@docRoot}preview/setup-sdk.html#docs-dl">API Reference</a>.
    -+  this by overriding the {@link android.view.Window.Callback#onProvideKeyboardShortcuts
    -+  onProvideKeyboardShortcuts()} method.
    - </p>
    - 
    - <p class="note">
    -@@ -986,7 +983,8 @@ Directory Access</a> developer documentation.</p>
    - 
    - <p>
    -   To trigger Keyboard Shortcuts Helper from anywhere in your app, call
    --  {@code Activity.requestKeyboardShortcutsHelper()} for the relevant activity.
    -+  {@link android.app.Activity#requestShowKeyboardShortcuts requestShowKeyboardShortcuts()}
    -+  from the relevant activity.
    - </p>
    - 
    - <h2 id="custom_pointer_api">
    -@@ -1062,37 +1060,32 @@ see the <a href="https://developers.google.com/vr/android/">Google VR SDK for An
    - 
    - <ul>
    -   <li>You can set an icon from a resource ID by calling
    --  <code>PrinterInfo.Builder.setResourceIconId()</code>
    -+  {@link android.print.PrinterInfo.Builder#setIconResourceId setIconResourceId()}.
    -   </li>
    - 
    -   <li>You can show an icon from the network by calling
    --  <code>PrinterInfo.Builder.setHasCustomPrinterIcon()</code>, and setting a
    --  callback for when the icon is requested using
    --  <code>android.printservice.PrinterDiscoverySession.onRequestCustomPrinterIcon()</code>
    -+  {@link android.print.PrinterInfo.Builder#setHasCustomPrinterIcon setHasCustomPrinterIcon()},
    -+  and setting a callback for when the icon is requested using
    -+  {@link android.printservice.PrinterDiscoverySession#onRequestCustomPrinterIcon onRequestCustomPrinterIcon()}.
    -   </li>
    - </ul>
    - 
    - <p>
    -   In addition, you can provide a per-printer activity to display additional
    --  information by calling <code>PrinterInfo.Builder.setInfoIntent()</code>.
    -+  information by calling {@link android.print.PrinterInfo.Builder#setInfoIntent setInfoIntent()}.
    - </p>
    - 
    - <p>
    -   You can indicate the progress and status of print jobs in the print job
    -   notification by calling
    --  <code>android.printservice.PrintJob.setProgress()</code> and
    --  <code>android.printservice.PrintJob.setStatus()</code>, respectively.
    --</p>
    --
    --<p>
    --  For more information about these methods, see the downloadable <a href=
    --  "{@docRoot}preview/setup-sdk.html#docs-dl">API Reference</a>.
    -+  {@link android.printservice.PrintJob#setProgress setProgress()} and
    -+  {@link android.printservice.PrintJob#setStatus setStatus()}, respectively.
    - </p>
    - 
    --<h2 id="framemetrics_api">FrameMetricsListener API</h2>
    -+<h2 id="framemetrics_api">Frame Metrics API</h2>
    - 
    - <p>
    --The FrameMetricsListener API allows an app to monitor its UI rendering
    -+The Frame Metrics API allows an app to monitor its UI rendering
    - performance. The API provides this capability by exposing a streaming Pub/Sub API to transfer frame
    - timing info for the app's current window. The data returned is
    - equivalent to that which <code><a href="{@docRoot}tools/help/shell.html#shellcommands">adb shell</a>
    -@@ -1100,7 +1093,7 @@ dumpsys gfxinfo framestats</code> displays, but is not limited to the past 120 f
    - </p>
    - 
    - <p>
    --You can use FrameMetricsListener to measure interaction-level UI
    -+You can use the Frame Metrics API to measure interaction-level UI
    - performance in production, without a USB connection. This API
    - allows collection of data at a much higher granularity than does
    - {@code adb shell dumpsys gfxinfo}. This higher granularity is possible because
    -@@ -1112,16 +1105,15 @@ for real use cases within an app.
    - </p>
    - 
    - <p>
    --To monitor a window, implement the <code>FrameMetricsListener.onMetricsAvailable()</code>
    --callback method and register it on that window. For more information, refer to
    --the {@code FrameMetricsListener} class documentation in
    --the downloadable <a href="{@docRoot}preview/setup-sdk.html#docs-dl">API Reference</a>.
    -+To monitor a window, implement the
    -+{@link android.view.Window.OnFrameMetricsAvailableListener#onFrameMetricsAvailable OnFrameMetricsAvailableListener.onFrameMetricsAvailable()}
    -+callback method and register it on that window.
    - </p>
    - 
    - <p>
    --The API provides a {@code FrameMetrics} object, which contains timing data that
    --the rendering subsystem reports for various milestones in a frame lifecycle.
    --The supported metrics are: {@code UNKNOWN_DELAY_DURATION},
    -+The API provides a {@link android.view.FrameMetrics FrameMetrics} object, which
    -+contains timing data that the rendering subsystem reports for various milestones
    -+in a frame lifecycle. The supported metrics are: {@code UNKNOWN_DELAY_DURATION},
    - {@code INPUT_HANDLING_DURATION}, {@code ANIMATION_DURATION},
    - {@code LAYOUT_MEASURE_DURATION}, {@code DRAW_DURATION}, {@code SYNC_DURATION},
    - {@code COMMAND_ISSUE_DURATION}, {@code SWAP_BUFFERS_DURATION},
    -diff --git a/docs/html/about/versions/nougat/index.jd b/docs/html/about/versions/nougat/index.jd
    -index 30a3576..8661d77 100644
    ---- a/docs/html/about/versions/nougat/index.jd
    -+++ b/docs/html/about/versions/nougat/index.jd
    -@@ -7,16 +7,6 @@ header.hide=1
    - footer.hide=1
    - @jd:body
    - 
    --<script>
    --  $(document).ready(function() {
    --    if (useUpdatedTemplates) {
    --      $("#useUpdatedTemplates").css("display","block");
    --    } else {
    --      $("#useOldTemplates").css("display","block");
    --    }
    --  })
    --</script>
    --
    - <section class="dac-expand dac-hero dac-light">
    -   <div class="wrap" style="max-width:1100px;margin-top:0">
    -   <a href="{@docRoot}about/versions/nougat/android-7.0.html">
    -@@ -54,8 +44,7 @@ footer.hide=1
    -   </div>
    - </section>
    - 
    --
    --<div id="useUpdatedTemplates" style="display:none" class="dac-section dac-slim dac-gray dac-expand">
    -+<div class="dac-section dac-slim dac-gray dac-expand">
    -   <div class="wrap dac-offset-parent">
    -     <a class="dac-fab dac-scroll-button" data-scroll-button href="#latest">
    -       <i class="dac-sprite dac-arrow-down-gray"></i>
    -@@ -77,26 +66,6 @@ footer.hide=1
    -   </div><!-- end .wrap -->
    - </div><!-- end .dac-actions -->
    - 
    --<div id="useOldTemplates" style="display:none;color:black" class="actions-bar dac-expand dac-invert">
    --  <div class="wrap dac-offset-parent">
    --
    --    <div class="actions">
    --      <div><a href="https://developer.android.com/preview/bug">
    --        <span class="dac-sprite dac-auto-chevron-large"></span>
    --        Report an issue
    --      </a></div>
    --      <div><a href="{@docRoot}preview/support.html">
    --        <span class="dac-sprite dac-auto-chevron-large"></span>
    --        See release notes
    --      </a></div>
    --      <div><a href="{@docRoot}preview/dev-community">
    --        <span class="dac-sprite dac-auto-chevron-large"></span>
    --        Join dev community
    --      </a></div>
    --    </div><!-- end .actions -->
    --  </div><!-- end .wrap -->
    --</div>
    --
    - <section class="dac-section dac-light dac-small" id="latest"><div class="wrap">
    -   <h2 class="norule">Latest</h2>
    -   <div class="resource-widget resource-flow-layout col-16"
    -diff --git a/docs/html/auto/_project.yaml b/docs/html/auto/_project.yaml
    -new file mode 100644
    -index 0000000..fc4ab2b
    ---- /dev/null
    -+++ b/docs/html/auto/_project.yaml
    -@@ -0,0 +1,6 @@
    -+name: "Auto"
    -+home_url: /auto/
    -+description: "Let drivers listen to and control content in your music and other audio apps."
    -+content_license: cc3-apache2
    -+buganizer_id: 30209417
    -+parent_project_metadata_path: /about/_project.yaml
    -diff --git a/docs/html/auto/index.jd b/docs/html/auto/index.jd
    -index e6fde38..3ebd87d 100644
    ---- a/docs/html/auto/index.jd
    -+++ b/docs/html/auto/index.jd
    -@@ -10,7 +10,7 @@ nonavpage=true
    - 
    - <style>
    - .fullpage>#footer,
    --#jd-content>.content-footer.wrap {
    -+#body-content>.content-footer.wrap {
    -   display:none;
    - }
    - .img-logo {
    -diff --git a/docs/html/design/_book.yaml b/docs/html/design/_book.yaml
    -index 18b4719..8ffa9a4 100644
    ---- a/docs/html/design/_book.yaml
    -+++ b/docs/html/design/_book.yaml
    -@@ -117,8 +117,6 @@ toc:
    -     path: /design/patterns/pure-android.html
    -   - title: Compatibility
    -     path: /design/patterns/compatibility.html
    --  - title: Accessibility
    --    path: /design/patterns/accessibility.html
    -   - title: Help
    -     path: /design/patterns/help.html
    - 
    -diff --git a/docs/html/design/patterns/accessibility.jd b/docs/html/design/patterns/accessibility.jd
    -deleted file mode 100644
    -index b910294..0000000
    ---- a/docs/html/design/patterns/accessibility.jd
    -+++ /dev/null
    -@@ -1,98 +0,0 @@
    --page.title=Accessibility
    --page.tags="accessibility","navigation","input"
    --page.metaDescription=Design an app that's universally accessible to people with visual impairment, color deficiency, hearing loss, and limited dexterity.
    --@jd:body
    --
    --<a class="notice-designers-material"
    --  href="http://www.google.com/design/spec/usability/accessibility.html">
    --  <div>
    --    <h3>Material Design</h3>
    --    <p>Accessibility<p>
    --  </div>
    --</a>
    --
    --<a class="notice-developers" href="{@docRoot}training/accessibility/index.html">
    --  <div>
    --    <h3>Developer Docs</h3>
    --    <p>Implementing Accessibility</p>
    --  </div>
    --</a>
    --
    --<p>One of Android's missions is to organize the world's information and make it universally accessible and useful. Accessibility is the measure of how successfully a product can be used by people with varying abilities. Our mission applies to all users-including people with disabilities such as visual impairment, color deficiency, hearing loss, and limited dexterity.</p>
    --<p><a href="https://www.google.com/#hl=en&q=universal+design&fp=1">Universal design</a> is the practice of making products that are inherently accessible to all users, regardless of ability. The Android design patterns were created in accordance with universal design principles, and following them will help your app meet basic usability standards. Adhering to universal design and enabling Android's accessibility tools will make your app as accessible as possible.</p>
    --<p>Robust support for accessibility will increase your app's user base. It may also be required for adoption by some organizations.</p>
    --<p><a href="http://www.google.com/accessibility/">Learn more about Google and accessibility.</a></p>
    --
    --<h2 id="tools">Android's Accessibility Tools</h2>
    --<p>Android includes several features that support access for users with visual impairments; they don't require drastic visual changes to your app.</p>
    --
    --<ul>
    --  <li><strong><a href="https://play.google.com/store/apps/details?id=com.google.android.marvin.talkback">TalkBack</a></strong> is a pre-installed screen reader service provided by Google. It uses spoken feedback to describe the results of actions such as launching an app, and events such as notifications.</li>
    --  <li><strong>Explore by Touch</strong> is a system feature that works with TalkBack, allowing you to touch your device's screen and hear what's under your finger via spoken feedback. This feature is helpful to users with low vision.</li>
    --  <li><strong>Accessibility settings</strong> let you modify your device's display and sound options, such as increasing the text size, changing the speed at which text is spoken, and more.</li>
    --</ul>
    --
    --<p>Some users use hardware or software directional controllers (such as a D-pad, trackball, keyboard) to jump from selection to selection on a screen. They interact with the structure of your app in a linear fashion, similar to 4-way remote control navigation on a television.</p>
    --
    --<h2 id="tools">Guidelines</h2>
    --<p>The Android design principle "I should always know where I am" is key for accessibility concerns. As a user navigates through an application, they need feedback and a mental model of where they are. All users benefit from a strong sense of information hierarchy and an architecture that makes sense. Most users benefit from visual and haptic feedback during their navigation (such as labels, colors, icons, touch feedback) Low vision users benefit from explicit verbal descriptions and large visuals with high contrast.</p>
    --<p>As you design your app, think about the labels and notations needed to navigate your app by sound. When using Explore by Touch, the user enables an invisible but audible layer of structure in your application. Like any other aspect of app design, this structure can be simple, elegant, and robust. The following are Android's recommended guidelines to enable effective navigation for all users.</p>
    --
    --<h4>Make navigation intuitive</h4>
    --<p>Design well-defined, clear task flows with minimal navigation steps, especially for major user tasks. Make sure those tasks are navigable via focus controls. </p>
    --
    --<h4>Use recommended touch target sizes</h4>
    --<p>48 dp is the recommended touch target size for on screen elements. Read about <a href="{@docRoot}design/style/metrics-grids.html">Android Metrics and Grids</a> to learn about implementation strategies to help most of your users. For certain users, it may be appropriate to use larger touch targets. An example of this is educational apps, where buttons larger than the minimum recommendations are appropriate for children with developing motor skills and people with manual dexterity challenges.</p>
    --
    --
    --<h4>Label visual UI elements meaningfully</h4>
    --<p>In your wireframes, <a href="{@docRoot}guide/topics/ui/accessibility/apps.html#label-ui">label functional UI components</a> that have no visible text. Those components might be buttons, icons, tabs with icons, and icons with state (like stars). Developers can use the <code><a href="{@docRoot}guide/topics/ui/accessibility/apps.html#label-ui">contentDescription</a></code> attribute to set the label.</p>
    --
    --<div class ="cols">
    --    <div class="col-8">
    --      <img src="{@docRoot}design/media/accessibility_contentdesc.png">
    --    </div>
    --    <div class="col-5 with-callouts">
    --      <ol>
    --        <li class="value-1">group</li>
    --        <li class="value-2">all contacts</li>
    --        <li class="value-3">favorites</li>
    --        <li class="value-4">search</li>
    --        <li class="value-5">action overflow button</li>
    --        <li class="value-6">
    --          <em>when starred:</em> remove from favorites </br>
    --          <em>when not starred:</em> add to favorties</li>
    --        <li class="value-7">action overflow button</li>
    --        <li class="value-8">text message</li>
    --      </ol>
    --  </div>
    --</div>
    --
    --<h4>Provide alternatives to affordances that time out</h4>
    --<p>Your app may have icons or controls that disappear after a certain amount of time. For example, five seconds after starting a video, playback controls may fade from the screen.</p>
    --
    --<p>Due to the way that TalkBack works, those controls are not read out loud unless they are focused on. If they fade out from the screen quickly, your user may not even be aware that they are available. Therefore, make sure that you are not relying on timed out controls for high priority task flows. (This is a good universal design guideline too.) If the controls enable an important function, make sure that the user can turn on the controls again and/or their function is duplicated elsewhere. You can also change the behavior of your app when accessibility services are turned on. Your developer may be able to make sure that timed-out controls won't disappear.</p>
    --
    --<h4>Use standard framework controls or enable TalkBack for custom controls</h4>
    --<p>Standard Android framework controls work automatically with accessibility services and have ContentDescriptions built in by default.</p>
    --
    --<p>An oft-overlooked system control is font size. Users can turn on a system-wide large font size in Settings; using the default system font size in your application will enable the user's preferences in your app as well. To enable system font size in your app, mark text and their associated containers to be measured in <a href="{@docRoot}guide/practices/screens_support.html#screen-independence">scale pixels</a>.</p>
    --
    --<p>Also, keep in mind that when users have large fonts enabled or speak a different language than you, their type might be larger than the space you've allotted for it. Read <a href="{@docRoot}design/style/devices-displays.html">Devices and Displays</a> and <a href="http://developer.android.com/guide/practices/screens_support.html">Supporting Multiple Screens</a> for design strategies.</p>
    --
    --<p>If you use custom controls, Android has the developer tools in place to allow adherence to the above guidelines and provide meaningful descriptions about the UI. Provide adequate notation on your wireframes and direct your developer to the <a href="{@docRoot}guide/topics/ui/accessibility/apps.html#custom-views">Custom Views</a> documentation.</p>
    --
    --<h4>Try it out yourself</h4>
    --<p>Turn on the TalkBack service in <strong>Settings > Accessibility</strong> and navigate your application using directional controls or eyes-free navigation.</p>
    --
    --
    --
    --<h2>Checklist</h2>
    --<ul>
    --  <li>Make navigation intuitive</li>
    --  <li>Use recommended touch target sizes</li>
    --  <li>Label visual UI elements meaningfully</li>
    --  <li>Provide alternatives to affordances that time out</li>
    --  <li>Use standard framework controls or enable TalkBack for custom controls</li>
    --  <li>Try it out yourself</li>
    --</ul>
    -diff --git a/docs/html/develop/index.jd b/docs/html/develop/index.jd
    -index bd933f4..564dbf9 100644
    ---- a/docs/html/develop/index.jd
    -+++ b/docs/html/develop/index.jd
    -@@ -14,29 +14,36 @@ excludeFromSuggestions=true
    -   <div class="wrap">
    -     <div class="cols dac-hero-content">
    -       <div class="col-1of2 col-push-1of2 dac-hero-figure">
    --        <img class="dac-hero-image" src="/images/develop/hero_image_studio5_2x.png" srcset="/images/develop/hero_image_studio5.png 1x, /images/develop/hero_image_studio5_2x.png 2x">
    -+        <img class="dac-hero-image" style="padding-top:32px"
    -+          src="/images/develop/hero-layout-editor_2x.png"
    -+          srcset="/images/develop/hero-layout-editor_2x.png 2x,
    -+                  /images/develop/hero-layout-editor.png 1x">
    -       </div>
    -       <div class="col-1of2 col-pull-1of2" style="margin-bottom:40px">
    -         <h1 class="dac-hero-title">
    -             <a style="color:inherit" href="{@docRoot}studio/index.html">
    --            Android Studio 2.1,<br>now available!</a></h1>
    -+            Android Studio 2.2</a></h1>
    - 
    --<p class="dac-hero-description">Android Studio provides the fastest tools for
    --building apps on every type of Android device.</p>
    -+<p class="dac-hero-description">There are 20+ new features in this release
    -+focused on helping you code faster and smarter. With Android Studio 2.2 you
    -+can:</p>
    - 
    --<p class="dac-hero-description">The latest version, Android Studio 2.1, adds
    --support for N Preview development on top of the faster Android Emulator and
    --Instant Run feature from 2.0.</p>
    -+<ul class="dac-hero-description">
    -+  <li>Develop your app user interface faster with the new Layout Editor &amp;
    -+    Constraint Layout</li>
    -+  <li>Develop smarter with the APK analyzer &amp; expanded code analysis</li>
    -+  <li>Develop with the the latest Android 7.0 Nougat APIs &amp; features</li>
    -+</ul>
    - 
    - <p style="margin-top:24px">
    -     <a class="dac-hero-cta" href="{@docRoot}studio/index.html">
    -       <span class="dac-sprite dac-auto-chevron"></span>
    --      Get Android Studio
    -+      Get Android Studio 2.2
    -     </a>
    -   &nbsp;&nbsp;&nbsp;&nbsp;<wbr>
    --    <a class="dac-hero-cta" href="{@docRoot}studio/releases/index.html">
    -+    <a class="dac-hero-cta" href="{@docRoot}studio/features.html">
    -     <span class="dac-sprite dac-auto-chevron"></span>
    --    See the release notes</a>
    -+    See more features</a>
    - </p>
    - 
    -       </div>
    -diff --git a/docs/html/distribute/essentials/quality/wear.jd b/docs/html/distribute/essentials/quality/wear.jd
    -index 34c6cc5..be48491 100644
    ---- a/docs/html/distribute/essentials/quality/wear.jd
    -+++ b/docs/html/distribute/essentials/quality/wear.jd
    -@@ -42,6 +42,13 @@ page.image=/distribute/images/gp-wear-quality.png
    -   understand the basic implementation requirements for a Wear app.
    - </p>
    - 
    -+<p>
    -+  This document helps you assess basic aspects of quality in your Wear app through a
    -+  compact set of functional and user interface quality criteria.
    -+   Make sure to check out the <a href="https://developer.android.com/wear/preview/index.html">Wear 2.0 preview</a>
    -+  documentation to get ready for the next version of Android Wear.
    -+</p>
    -+
    - <p class="caution">
    -   <strong>Important:</strong> To ensure a great user experience, apps for wearables must meet
    -   specific requirements for usability. Only apps that meet the following quality criteria will
    -@@ -50,8 +57,8 @@ page.image=/distribute/images/gp-wear-quality.png
    - </p>
    - 
    - <p class="note">
    -- <strong>Note:</strong> For information about how to publish your Wear apps in Google Play, see <a
    -- href="{@docRoot}distribute/googleplay/wear.html">Distributing to Android Wear</a>.
    -+  <strong>Note:</strong> For information about how to publish your Wear apps in Google Play, see <a
    -+  href="{@docRoot}distribute/googleplay/wear.html">Distributing to Android Wear</a>.
    - </p>
    - 
    - <div class="headerLine">
    -@@ -67,6 +74,19 @@ page.image=/distribute/images/gp-wear-quality.png
    -   functional behavior.
    - </p>
    - 
    -+<p class="caution">
    -+  <strong>Important:</strong> To learn about how Wear 2.0 platform changes may affect
    -+   your apps, see the <a href="https://developer.android.com/wear/preview/index.html">Wear 2.0 preview</a>
    -+   documentation.
    -+</p>
    -+
    -+<p class="note">
    -+  <strong>Note:</strong> The symbol &#10008; is used in the table below to indicate
    -+  quality criteria that are not required for the corresponding Wear version.
    -+</p>
    -+
    -+<p class="table-caption"><strong>Table 1</strong>. Functional criteria.
    -+</p>
    - 
    - <table>
    - <tr>
    -@@ -79,6 +99,12 @@ page.image=/distribute/images/gp-wear-quality.png
    -   <th>
    -     Description
    -   </th>
    -+  <th>
    -+    Wear 1.0
    -+  </th>
    -+  <th>
    -+    Wear 2.0
    -+  </th>
    - </tr>
    - 
    - <tr>
    -@@ -96,6 +122,12 @@ page.image=/distribute/images/gp-wear-quality.png
    -       (<a href="{@docRoot}training/building-wearables.html">Learn how</a>)
    -     </p>
    -   </td>
    -+  <td>
    -+    &#10004;
    -+  </td>
    -+  <td>
    -+    &#10004;
    -+  </td>
    - </tr>
    - 
    - <tr>
    -@@ -107,6 +139,12 @@ page.image=/distribute/images/gp-wear-quality.png
    -       App has Wear functionality that is visible to the user.
    -     </p>
    -   </td>
    -+  <td>
    -+    &#10004;
    -+  </td>
    -+  <td>
    -+    &#10004;
    -+  </td>
    - </tr>
    - 
    - <tr>
    -@@ -118,6 +156,12 @@ page.image=/distribute/images/gp-wear-quality.png
    -       Wear functionality works as expected or as described in the app's Google Play Store listing.
    -     </p>
    -   </td>
    -+  <td>
    -+    &#10004;
    -+  </td>
    -+  <td>
    -+    &#10004;
    -+  </td>
    - </tr>
    - 
    - <tr>
    -@@ -135,6 +179,12 @@ page.image=/distribute/images/gp-wear-quality.png
    -       (<a href="{@docRoot}training/wearables/apps/packaging.html">Learn how</a>)
    -     </p>
    -   </td>
    -+  <td>
    -+    &#10004;
    -+  </td>
    -+  <td>
    -+    &#10008;
    -+  </td>
    - </tr>
    - 
    - <tr>
    -@@ -152,6 +202,12 @@ page.image=/distribute/images/gp-wear-quality.png
    -       (<a href="{@docRoot}training/wearables/notifications/index.html">Learn how</a>)
    -     </p>
    -   </td>
    -+  <td>
    -+    &#10004;
    -+  </td>
    -+  <td>
    -+    &#10008;
    -+  </td>
    - </tr>
    - 
    - <tr>
    -@@ -164,6 +220,12 @@ page.image=/distribute/images/gp-wear-quality.png
    -       (<a href="{@docRoot}training/wearables/notifications/voice-input.html">Learn how</a>)
    -     </p>
    -   </td>
    -+  <td>
    -+    &#10004;
    -+  </td>
    -+  <td>
    -+    &#10008;
    -+  </td>
    - </tr>
    - 
    - <tr>
    -@@ -176,6 +238,12 @@ page.image=/distribute/images/gp-wear-quality.png
    -       (<a href="{@docRoot}training/wearables/notifications/stacks.html">Learn how</a>)
    -     </p>
    -   </td>
    -+  <td>
    -+    &#10004;
    -+  </td>
    -+  <td>
    -+    &#10008;
    -+  </td>
    - </tr>
    - 
    - <tr>
    -@@ -193,6 +261,12 @@ page.image=/distribute/images/gp-wear-quality.png
    -       (<a href="{@docRoot}training/wearables/ui/exit.html">Learn how</a>)
    -     </p>
    -   </td>
    -+  <td>
    -+    &#10004;
    -+  </td>
    -+  <td>
    -+    &#10008;
    -+  </td>
    - </tr>
    - 
    - <tr>
    -@@ -206,6 +280,12 @@ page.image=/distribute/images/gp-wear-quality.png
    -       (<a href="{@docRoot}training/wearables/ui/exit.html">Learn how</a>)
    -     </p>
    -   </td>
    -+  <td>
    -+    &#10004;
    -+  </td>
    -+  <td>
    -+    &#10008;
    -+  </td>
    - </tr>
    - 
    - <tr>
    -@@ -222,6 +302,12 @@ page.image=/distribute/images/gp-wear-quality.png
    -       (<a href="{@docRoot}training/wearables/watch-faces/index.html">Learn how</a>)
    -     </p>
    -   </td>
    -+  <td>
    -+    &#10004;
    -+  </td>
    -+  <td>
    -+    &#10008;
    -+  </td>
    - </tr>
    - 
    - </table>
    -@@ -245,8 +331,15 @@ data-sortorder="-timestamp" data-cardsizes="6x2" data-maxresults="6">
    - <p>
    -   These criteria ensure that your app follows critical design and interaction patterns to provide a
    -   consistent, intuitive, and enjoyable user experience on wearables.
    -+
    -+</p>
    -+<p clase="note">
    -+  <strong>Note:</strong> The symbol &#10008; is used in the table below to indicate
    -+  quality criteria that are not required for the corresponding Wear version.
    - </p>
    - 
    -+<p class="table-caption"><strong>Table 2</strong>. Visual criteria.
    -+</p>
    - <table>
    - 
    - <tr>
    -@@ -259,6 +352,12 @@ data-sortorder="-timestamp" data-cardsizes="6x2" data-maxresults="6">
    -   <th>
    -     Description
    -   </th>
    -+  <th>
    -+    Wear 1.0
    -+  </th>
    -+  <th>
    -+    Wear 2.0
    -+  </th>
    - </tr>
    - 
    - <tr>
    -@@ -277,6 +376,12 @@ data-sortorder="-timestamp" data-cardsizes="6x2" data-maxresults="6">
    -       (<a href="{@docRoot}training/wearables/ui/layouts.html">Learn how</a>)
    -     </p>
    -   </td>
    -+  <td>
    -+    &#10004;
    -+  </td>
    -+  <td>
    -+    &#10004;
    -+  </td>
    - </tr>
    - 
    - <tr>
    -@@ -292,6 +397,13 @@ data-sortorder="-timestamp" data-cardsizes="6x2" data-maxresults="6">
    -       (<a href="{@docRoot}training/wearables/ui/layouts.html">Learn how</a>)
    -     </p>
    -   </td>
    -+  <td>
    -+    &#10004;
    -+  </td>
    -+  <td>
    -+    &#10004;
    -+  </td>
    -+
    - </tr>
    - 
    - <tr>
    -@@ -304,6 +416,12 @@ data-sortorder="-timestamp" data-cardsizes="6x2" data-maxresults="6">
    -       (<a href="{@docRoot}design/wear/style.html#Typography">Learn how</a>)
    -     </p>
    -   </td>
    -+  <td>
    -+    &#10004;
    -+  </td>
    -+  <td>
    -+    &#10004;
    -+  </td>
    - </tr>
    - 
    - <tr>
    -@@ -320,6 +438,12 @@ data-sortorder="-timestamp" data-cardsizes="6x2" data-maxresults="6">
    -       (<a href="{@docRoot}guide/topics/manifest/intent-filter-element.html">Learn how</a>)
    -     </p>
    -   </td>
    -+  <td>
    -+    &#10004;
    -+  </td>
    -+  <td>
    -+    &#10008;
    -+  </td>
    - </tr>
    - 
    - <tr>
    -@@ -336,6 +460,12 @@ data-sortorder="-timestamp" data-cardsizes="6x2" data-maxresults="6">
    -       (<a href="{@docRoot}design/wear/patterns.html#Countdown">Learn how</a>)
    -     </p>
    -   </td>
    -+  <td>
    -+    &#10004;
    -+  </td>
    -+  <td>
    -+    &#10004;
    -+  </td>
    - </tr>
    - 
    - <tr>
    -@@ -350,6 +480,12 @@ data-sortorder="-timestamp" data-cardsizes="6x2" data-maxresults="6">
    -       (<a href="{@docRoot}design/wear/style.html#Assets">Learn how</a>)
    -     </p>
    -   </td>
    -+  <td>
    -+    &#10004;
    -+  </td>
    -+  <td>
    -+    &#10008;
    -+  </td>
    - </tr>
    - 
    - <tr>
    -@@ -363,6 +499,12 @@ data-sortorder="-timestamp" data-cardsizes="6x2" data-maxresults="6">
    -       (<a href="{@docRoot}training/wearables/notifications/creating.html#ActionButtons">Learn how</a>)
    -     </p>
    -   </td>
    -+  <td>
    -+    &#10004;
    -+  </td>
    -+  <td>
    -+    &#10004;
    -+  </td>
    - </tr>
    - 
    - <tr>
    -@@ -375,6 +517,12 @@ data-sortorder="-timestamp" data-cardsizes="6x2" data-maxresults="6">
    -       (<a href="{@docRoot}design/wear/style.html#Branding">Learn how</a>)
    -     </p>
    -   </td>
    -+  <td>
    -+    &#10004;
    -+  </td>
    -+  <td>
    -+    &#10008;
    -+  </td>
    - </tr>
    - 
    - <tr>
    -@@ -387,6 +535,12 @@ data-sortorder="-timestamp" data-cardsizes="6x2" data-maxresults="6">
    -       (<a href="{@docRoot}training/wearables/notifications/creating.html#AddWearableFeatures">Learn how</a>)
    -     </p>
    -   </td>
    -+  <td>
    -+    &#10004;
    -+  </td>
    -+  <td>
    -+    &#10008;
    -+  </td>
    - </tr>
    - 
    - <tr>
    -@@ -403,6 +557,12 @@ data-sortorder="-timestamp" data-cardsizes="6x2" data-maxresults="6">
    -       (<a href="https://support.google.com/googleplay/android-developer/answer/1078870?hl=en">Learn how</a>)
    -     </p>
    -   </td>
    -+  <td>
    -+    &#10004;
    -+  </td>
    -+  <td>
    -+    &#10004;
    -+  </td>
    - </tr>
    - 
    - 
    -diff --git a/docs/html/distribute/index.jd b/docs/html/distribute/index.jd
    -index 424983d..3d75758 100644
    ---- a/docs/html/distribute/index.jd
    -+++ b/docs/html/distribute/index.jd
    -@@ -9,16 +9,6 @@ page.metaDescription=The most visited store in the world for Android apps. Cloud
    - 
    - @jd:body
    - 
    --<script>
    --  $(document).ready(function() {
    --    if (useUpdatedTemplates) {
    --      $("#useUpdatedTemplates").css("display","block");
    --    } else {
    --      $("#useOldTemplates").css("display","block");
    --    }
    --  })
    --</script>
    --
    - <div class="dac-hero-carousel" data-carousel-query="collection:distribute/landing/carousel">
    - </div>
    - 
    -@@ -28,18 +18,7 @@ page.metaDescription=The most visited store in the world for Android apps. Cloud
    -   </a>
    - </div>
    - 
    --<section id="useOldTemplates" style="display:none" class="dac-section dac-gray dac-small" id="latest"><div class="wrap">
    --  <h2 class="norule">Latest</h2>
    --  <div class="resource-widget resource-flow-layout col-16"
    --      data-query="type:youtube+tag:googleplay+tag:developerstory+tag:featured, type:blog+tag:googleplay+tag:distribute+tag:featured"
    --      data-sortOrder="-timestamp"
    --      data-cardSizes="6x6"
    --      data-maxResults="3"
    --      data-items-per-page="6"
    --      data-initial-results="3"></div>
    --</div></section>
    --
    --<section id="useUpdatedTemplates" style="display:none" class="dac-section dac-gray dac-small" id="latest"><div class="wrap">
    -+<section class="dac-section dac-gray dac-small" id="latest"><div class="wrap">
    -   <h2 class="norule">Latest</h2>
    - 
    -   <div class="dac-filter dac-filter-section" data-filter="#latest-resources">
    -diff --git a/docs/html/distribute/stories/apps.jd b/docs/html/distribute/stories/apps.jd
    -index 76e9f5a..47f4f7f 100644
    ---- a/docs/html/distribute/stories/apps.jd
    -+++ b/docs/html/distribute/stories/apps.jd
    -@@ -25,8 +25,7 @@ page.metaDescription=How app developers are making use of localization, tablet f
    -   <h2 class="norule">Articles</h2>
    - 
    -   <div class="resource-widget resource-flow-layout col-16"
    --      data-query="type:distribute+tag:developerstory+tag:apps"
    --      data-sortOrder="-timestamp"
    -+      data-query="collection:distribute/stories/apps/docs"
    -       data-cardSizes="6x6"
    -       data-items-per-page="15"
    -       data-initial-results="6"></div>
    -diff --git a/docs/html/distribute/stories/apps/condenast-shopping.jd b/docs/html/distribute/stories/apps/condenast-shopping.jd
    -new file mode 100644
    -index 0000000..37c2b1f
    ---- /dev/null
    -+++ b/docs/html/distribute/stories/apps/condenast-shopping.jd
    -@@ -0,0 +1,76 @@
    -+page.title=Glamour.de Connects Offline and Online Shopping Experiences with Google Play Billing
    -+page.metaDescription=Cond&eacute; Nast improves features on its Glamour app.
    -+page.tags="developerstory", "apps", "googleplay"
    -+page.image=images/cards/distribute/stories/glamour.png
    -+page.timestamp=null
    -+
    -+@jd:body
    -+
    -+
    -+<h3>Background</h3>
    -+
    -+<div class="figure">
    -+  <img src="{@docRoot}images/distribute/stories/glamour-icon.png" />
    -+</div>
    -+
    -+<p>
    -+  Glamour is one of the main
    -+  <a class="external-link"
    -+  href="https://play.google.com/store/apps/developer?id=Cond%C3%A9%20Nast%20Verlag%20GmbH&hl=en">
    -+  Cond&eacute; Nast</a> traditional brands. Every year, Glamour hosts a
    -+  successful shopping event called
    -+  <a class="external-link"
    -+  href="https://play.google.com/store/apps/details?id=de.glamour.android&e=-EnableAppDetailsPageRedesign">
    -+  <em>GLAMOUR Shopping-Week</em></a> in Germany, Austria, and Switzerland.
    -+  This event has always been print-focused, as readers received a shopping
    -+  card with the magazine to redeem discounts in selected shops, both offline
    -+  and online, for one week.
    -+</p>
    -+
    -+<p>
    -+  In March 2016, Glamour digitized this experience.
    -+</p>
    -+
    -+<h3>What they did</h3>
    -+
    -+<p>
    -+  To make the most of <em>GLAMOUR Shopping-Week</em>, Cond&eacute; Nast relaunched the
    -+  <a class="external-link"
    -+  href="https://play.google.com/store/apps/details?id=de.condenast.glamourde&e=-EnableAppDetailsPageRedesign">
    -+  GLAMOUR app</a> with a more appealing design and an improved user experience:
    -+<ul>
    -+  <li>The main features updated for the shopping week included a shop finder, online offers, and
    -+      a digital shopping card.</li>
    -+  <li>The current e-paper magazine was made available through the app and sold via Google Play
    -+      Billing.</li>
    -+  <li>They offered readers the in-app purchase of digital shopping cards and activation codes
    -+      through Google Play Billing. Readers can activate digital shopping cards via in-app
    -+      purchases or with the print shopping card activation code.</li>
    -+  <li>The online and offline shopping experience was also supported by online shopping discount
    -+      codes in the app or offline through the shop finder.</li>
    -+</ul>
    -+</p>
    -+
    -+<h3>Results</h3>
    -+
    -+<p>
    -+  The offline and online combination resulted in positive engagement both in terms of app
    -+  installs and sales:
    -+<ul>
    -+  <li>There were 130,000 new app downloads, and 100,000 users enabled location access to use
    -+      the shop finder.</li>
    -+  <li><strong>Sessions increased by 140%</strong> compared to previous weeks. Session length
    -+      doubled and <strong>the number of active users grew by five times</strong>.</li>
    -+  <li>12,000 in-app purchases were generated, increasing general e-paper sales by six times,
    -+      which resulted in <strong>an increase in total magazine circulation</strong>.</li>
    -+  <li>The digital shopping card was shown more than 200,000 times to redeem offers in shops.</li>
    -+</ul>
    -+</p>
    -+
    -+<h3>Get started</h3>
    -+
    -+<p>
    -+  Find out more about
    -+  <a href="https://developer.android.com/google/play/billing/billing_overview.html">
    -+  in-app purchases</a>.
    -+</p>
    -\ No newline at end of file
    -diff --git a/docs/html/distribute/stories/apps/drupe-communications.jd b/docs/html/distribute/stories/apps/drupe-communications.jd
    -new file mode 100644
    -index 0000000..4284077
    ---- /dev/null
    -+++ b/docs/html/distribute/stories/apps/drupe-communications.jd
    -@@ -0,0 +1,98 @@
    -+page.title=drupe Launches Android First and Finds Global Success with Beta Testing
    -+page.metaDescription=Drupe uses beta testing to increase its global reach.
    -+page.tags="developerstory", "apps", "googleplay"
    -+page.image=images/cards/distribute/stories/drupe.jpg
    -+page.timestamp=1468901832
    -+
    -+@jd:body
    -+
    -+<div class="figure">
    -+  <img src="{@docRoot}images/distribute/stories/drupe-icon.png" />
    -+</div>
    -+
    -+<h3>
    -+  Background
    -+</h3>
    -+
    -+<p>
    -+  In 2015, <a class="external-link" href=
    -+  "https://play.google.com/store/apps/dev?id=8486231504544197967">
    -+  drupe mobile</a>, founded by Assaf Ziv and Barak Witkowski, launched the
    -+  <a class="external-link" href=
    -+  "https://play.google.com/store/apps/details?id=mobi.drupe.app">drupe app</a>
    -+  on Android first. With a unique, people-first approach, their communications
    -+  app is focused on reinventing the way people use their phone to do basic
    -+  actions. By constantly improving and expanding their cross-app
    -+  functionality, the app is used globally and was recently awarded Google
    -+  Play’s Editor’s Choice recognition.
    -+</p>
    -+
    -+<h3>
    -+  What they did
    -+</h3>
    -+
    -+<dl>
    -+  <dt><strong>Android openness</strong></dt>
    -+  <dd>From the start, drupe knew Android was their ideal mobile platform.
    -+  <em>"Thanks to the openness of the system, we can build a truly native
    -+  experience on Android. The real way to supply a people-centric experience
    -+  requires such an openness, not always existing on other platforms,"</em>
    -+  said Barak Witkowski, co-founder and CEO of drupe. Key to their innovative
    -+  approach, drupe uses the current context of the user to show them the
    -+  right contacts and actions to optimize the drupe experience.</dd>
    -+
    -+<div class="figure">
    -+  <img src="{@docRoot}images/distribute/stories/drupe-screenshot.png">
    -+</div>
    -+
    -+  <dt><strong>Beta testing</strong></dt>
    -+  <dd>They have a large community of 20,000 <em>druper</em> beta users on
    -+  Android, which has been critical to their success. To minimize risk and seek
    -+  feedback from valued users, the team built beta testing into their regular
    -+  development process. By having a dialogue with users worldwide, they are able
    -+  to gauge interest in new app versions, collect feature requests, and more.
    -+  This has helped the team achieve a 99.7% crash-free user ratio, as well
    -+  as verify new versions in real-life scenarios, on various devices, before
    -+  full launch.</dd>
    -+
    -+  <dt><strong>Going global</strong></dt>
    -+  <dd>With initial focus on building a high quality app, drupe then set out
    -+  to take advantage of Android’s global scale. Key to their international
    -+  growth, the app is now translated in 17 languages, and the store listing
    -+  page is available in 28 languages. This led to an increase in conversion
    -+  and retention rates. Additionally, when entering India, the team noticed
    -+  several user reviews requesting integration with a specific messaging app
    -+  widely used in the Indian market. Through a combination of this integration,
    -+  adding Hindi language translation, and other new features, drupe saw improved
    -+  performance. In six months, <strong>daily active users increased 300%, and
    -+  actions per average daily user increased 25% in the Indian
    -+  market</strong>.</dd>
    -+</dl>
    -+
    -+<h3>
    -+  Results
    -+</h3>
    -+
    -+<p>
    -+  Drupe’s focus on innovation and building a truly contextual and intuitive
    -+  app proved to be a model of success for attaining growth in both engagement
    -+  and new global reach. The team has continued to increase its relevance
    -+  through feedback loops and feature adoptions. <strong>This has led to 700%
    -+  growth in daily active users, and 550% growth in number of interactions
    -+  triggered via drupe</strong> in the past six months. The team is focused on
    -+  enhancing their recommendation engine to add even more contextual abilities
    -+  for their users while continuing to grow a successful business on Google
    -+  Play.
    -+</p>
    -+
    -+<h3>
    -+  Get started
    -+</h3>
    -+
    -+<p>
    -+  Learn more about
    -+  <a href="{@docRoot}distribute/engage/beta.html">beta testing</a>
    -+  and find out how to
    -+  <a href="{@docRoot}distribute/tools/localization-checklist.html">
    -+  localize your app</a> to create a high-quality experience for global users.
    -+</p>
    -\ No newline at end of file
    -diff --git a/docs/html/distribute/stories/apps/economist-espresso.jd b/docs/html/distribute/stories/apps/economist-espresso.jd
    -new file mode 100644
    -index 0000000..441393b
    ---- /dev/null
    -+++ b/docs/html/distribute/stories/apps/economist-espresso.jd
    -@@ -0,0 +1,70 @@
    -+page.title=The Economist Espresso Increases Ratings by Launching Rating Requests
    -+page.metaDescription=The Economist improves ratings through user participation.
    -+page.tags="developerstory", "apps", "googleplay"
    -+page.image=images/cards/distribute/stories/economist-espresso.png
    -+page.timestamp=null
    -+
    -+@jd:body
    -+
    -+
    -+<h3>Background</h3>
    -+
    -+<div class="figure">
    -+  <img src="{@docRoot}images/distribute/stories/economist-espresso-icon.png" />
    -+</div>
    -+
    -+<p>
    -+  <a class="external-link" href="https://play.google.com/store/apps/details?id=uk.co.economist">
    -+  The Economist</a> launched the
    -+  <a class="external-link" href="https://play.google.com/store/apps/details?id=com.economist.darwin">
    -+  Espresso</a> app in November 2014. Espresso offers a morning briefing from the editors of The
    -+  Economist, six days a week. Delivered to readers’ mobile phones first thing in the morning, it
    -+  provides an overview of the global agenda for the coming day. It informs readers about what to
    -+  look out for in business, finance, and politics, and most importantly, what to make of it.
    -+</p>
    -+
    -+<p>
    -+  While the app received a lot of positive feedback from users on traditional customer support
    -+  channels, it received less feedback through direct app reviews. The Economist decided to run
    -+  tests to increase app reviews, resulting in improved ratings.
    -+
    -+<h3>What they did</h3>
    -+
    -+<p>
    -+  In April 2016, The Economist began testing to determine if asking for reviews would improve
    -+  user participation. They introduced rating requests into the app whereby users received a
    -+  notification asking them to rate the app while using it.
    -+</p>
    -+
    -+<p>
    -+  They prompted only users who had fully experienced the app, notifying those who had read more
    -+  than 25 articles after using it for more than a week. The prompt text was branded:
    -+  <em>Are you enjoying the Economist Espresso?</em> Upon clicking <em>yes</em>, the user was
    -+  taken to the Google Play store to review and rate the app.
    -+
    -+<h3>Results</h3>
    -+
    -+<p>
    -+  By capturing readers’ feedback in the Play store, The Economist was able to share the goodwill
    -+  and positive sentiment, <strong>further increasing its star rating and the number of app
    -+  installs</strong>.
    -+</p>
    -+
    -+<p>
    -+  After just one week following the launch of rating requests, The Espresso app's star rating
    -+  increased by 5%, with <strong>the average number of ratings received growing 40 times</strong>.
    -+</p>
    -+
    -+<h3>Get started</h3>
    -+
    -+<p>
    -+  Find out more about
    -+  <a class="external-link" href="https://support.google.com/googleplay/android-developer/answer/138230">
    -+  ratings and reviews</a>.
    -+</p>
    -+
    -+<p>
    -+  Get best practices for news publishers in
    -+  <a class="external-link" href="https://play.google.com/store/books/details/Google_Inc_The_News_Publisher_Playbook_for_Android?id=O7T3CwAAQBAJ&hl=en_GB&e=-EnableAppDetailsPageRedesign">
    -+  The News Publisher Playbook (for Android development)</a>.
    -+</p>
    -\ No newline at end of file
    -diff --git a/docs/html/distribute/stories/apps/expressen-sports.jd b/docs/html/distribute/stories/apps/expressen-sports.jd
    -new file mode 100644
    -index 0000000..b53cb62
    ---- /dev/null
    -+++ b/docs/html/distribute/stories/apps/expressen-sports.jd
    -@@ -0,0 +1,57 @@
    -+page.title=Expressen Sport App Improves Content Engagement with New Onboarding and Navigation
    -+page.metaDescription=Expressen enhances their Sport app.
    -+page.tags="developerstory", "apps", "googleplay"
    -+page.image=images/cards/distribute/stories/expressen-sport.png
    -+page.timestamp=null
    -+
    -+@jd:body
    -+
    -+
    -+<h3>Background</h3>
    -+
    -+<div class="figure">
    -+  <img src="{@docRoot}images/distribute/stories/expressen-icon.png" />
    -+</div>
    -+
    -+<p>
    -+  In January 2016,
    -+  <a class="external-link" href="https://play.google.com/store/apps/details?id=se.expressen.launcher&hl=en">
    -+  Expressen</a> launched a new sports app to reach sports enthusiasts directly
    -+  and to better optimize the app for sports content. They decided to analyze
    -+  users' behavior by looking at user paths in existing sports content,
    -+  combined with user research and testing various prototypes with real users.
    -+  They found that readers have different needs and preferences. For example,
    -+  some people like a specific sport, league, or player that others have no
    -+  interest in. Following these results, they integrated two main changes to
    -+  increase appeal to different types of readers.
    -+</p>
    -+
    -+<h3>What they did</h3>
    -+
    -+<p>
    -+  Expressen introduced a new onboarding flow that allows users to select the
    -+  type of push notifications they want to subscribe to. They also implemented
    -+  contextual navigation where the top header navigational links change,
    -+  showing the most relevant links to the reader at that moment in time. For
    -+  example, if you're reading about football, relevant links about that sport
    -+  are displayed.
    -+</p>
    -+
    -+<h3>Results</h3>
    -+
    -+<p>
    -+  After the new release of the app, <strong>results showed a higher opt-in
    -+  rate for push notifications in the Sport app (+16.9%)</strong> compared to
    -+  their main app, and content consumption increased +7% for page views and
    -+  +8.3% for video views.
    -+</p>
    -+
    -+<h3>Get started</h3>
    -+
    -+<p>
    -+  Learn more about the
    -+  <a href="https://developer.android.com/training/tv/playback/onboarding.html?hl=mk">
    -+  user onboarding flow</a> and find out how to
    -+  <a href="https://developer.android.com/design/patterns/navigation.html">
    -+  implement contextual navigation</a>.
    -+</p>
    -\ No newline at end of file
    -diff --git a/docs/html/distribute/stories/apps/lifesum-health.jd b/docs/html/distribute/stories/apps/lifesum-health.jd
    -new file mode 100644
    -index 0000000..2d3f203
    ---- /dev/null
    -+++ b/docs/html/distribute/stories/apps/lifesum-health.jd
    -@@ -0,0 +1,60 @@
    -+page.title=Lifesum Doubles Retention of Google Fit Users Following Integration on Android
    -+page.metaDescription=Lifesum integrates Google Fit into their app.
    -+page.tags="developerstory", "apps", "googleplay"
    -+page.image=images/cards/distribute/stories/lifesum.png
    -+page.timestamp=null
    -+
    -+@jd:body
    -+
    -+
    -+<h3>Background</h3>
    -+
    -+<div class="figure">
    -+  <img src="{@docRoot}images/distribute/stories/lifesum-icon.png" />
    -+</div>
    -+
    -+<p>
    -+  <a class="external-link" href="https://play.google.com/store/apps/details?id=com.sillens.shapeupclub">
    -+  Lifesum</a> is a health and fitness app from Sweden that was launched on Android in 2012.
    -+  Since then, the app has had more than five million installs on Android, and Lifesum collaborated
    -+  with Google for the launch of <a class="external-link" href="http://www.google.com/fit/">
    -+  Google Fit</a> in 2014. Google Fit soon became a key component of user activity outside the
    -+  app and has enabled Lifesum to scale partner integrations, accelerate development cycle, and
    -+  increase user satisfaction and engagement.
    -+</p>
    -+
    -+<h3>What they did</h3>
    -+
    -+<p>
    -+  Lifesum integrated Google Fit APIs to gather more insightful data, leading to a shift in
    -+  focus from simply gathering large amounts of user data to actual analysis of it. Google Fit has
    -+  also made direct integrations with partners much easier to scale and sometimes even
    -+  unnecessary, and has largely reduced app development time. Lifesum used findings from the
    -+  integration to launch their second app, <em>Movesum</em>, a step-counter app that imports steps
    -+  and calories and displays the information in a fun way. Thanks to the integration, the app was
    -+  developed in just two weeks.
    -+</p>
    -+
    -+<h3>Results</h3>
    -+
    -+<p>
    -+  Lifesum’s users now actively request integration with Google Fit, resulting in an improvement
    -+  in the app's ratings and reviews on the Google Play store. Engagement is also much higher for
    -+  Google Fit-connected users, whose <strong>retention rate is twice that of other Android
    -+  users</strong>. User retention on Android is 5-10% better than on other platforms.
    -+</p>
    -+
    -+<p>
    -+  Joakim Hammer, Android developer at Lifesum, says "Google Fit is our infrastructure for
    -+  integrating with other apps. It's great for the user as it increases the trustworthiness of the
    -+  data. Personally, it’s been a great experience leading the integration. The implementation was
    -+  fast and easy, and it has helped us with everything from product development and user
    -+  engagement, to partnerships."
    -+</p>
    -+
    -+<h3>Get started</h3>
    -+
    -+<p>
    -+  Find out more about <a class="external-link" href="https://developers.google.com/fit/">
    -+  The Google Fit SDK</a>.
    -+</p>
    -\ No newline at end of file
    -diff --git a/docs/html/distribute/stories/apps/noom-health.jd b/docs/html/distribute/stories/apps/noom-health.jd
    -new file mode 100644
    -index 0000000..c99efac
    ---- /dev/null
    -+++ b/docs/html/distribute/stories/apps/noom-health.jd
    -@@ -0,0 +1,115 @@
    -+page.title=Noom Grows International Revenue by 80% Through Localization on Google Play
    -+page.metaDescription=Noom increases revenue by localizing their app.
    -+page.tags="developerstory", "apps", "googleplay"
    -+page.image=images/cards/distribute/stories/noom.jpg
    -+page.timestamp=1468901832
    -+
    -+@jd:body
    -+
    -+<div class="figure">
    -+  <img src="{@docRoot}images/distribute/stories/noom-icon.png" />
    -+</div>
    -+
    -+<h3>
    -+  Background
    -+</h3>
    -+
    -+<p>
    -+  With a mission to help people live healthier lives,
    -+  <a class="external-link" href=
    -+  "https://play.google.com/store/apps/developer?id=Noom+Inc.">Noom</a> guides
    -+  their users through behavior change programs to create lifestyle habits and
    -+  target global health challenges. Available initially on Google Play,
    -+  Android first and Noom have achieved success expanding to international
    -+  markets, taking advantage of the broad reach of Android.
    -+</p>
    -+
    -+<h3>
    -+  What they did
    -+</h3>
    -+
    -+<p>
    -+  Launching first in the US, Noom created a series of programs tailored to
    -+  their users’ specific <a class="external-link" href=
    -+  "https://play.google.com/store/apps/details?id=com.wsl.noom">
    -+  health goals</a>. Key to their approach is offering a holistic solution,
    -+  including simple personalized tasks, progress tracking, meal feedback, and
    -+  support from both personal coaches and peers. The team has a strategic
    -+  approach to expanding their user base globally. Noom localized their app to
    -+  better connect with users in the following areas:
    -+</p>
    -+
    -+<ul>
    -+  <li><strong>Localized product</strong>
    -+    <ul style="list-style: none;">
    -+    <li>In addition to translating their app to five languages and their store
    -+      listing page to 11 languages, Noom conducted extensive analysis to
    -+      determine the right financial model tailored to each international
    -+      market. This included evaluation of their competitive landscape and
    -+      local health and wellness spending behavior, in addition to running
    -+      pricing experiments to determine the optimal offering between
    -+      subscriptions, IAPs, or a premium app.</li>
    -+    </ul>
    -+  </li>
    -+
    -+  <li><strong>Localized cuisines</strong>
    -+    <ul style="list-style: none;">
    -+    <li>When Noom started researching the Korean, Japanese, German, and Latin
    -+      American markets, they immediately focused on localizing their food
    -+      database. Using a combination of local food editors, existing food
    -+      databases, and user suggestions, their app now includes local cuisine
    -+      and popular packaged food brands, offering a simpler and more
    -+      comprehensive experience for users.</li>
    -+    </ul>
    -+  </li>
    -+
    -+  <li><strong>Localized coaches</strong>
    -+    <ul style="list-style: none;">
    -+    <li>Hiring local coaches not only removed language barriers, but also
    -+      reduced response times as they are located within the same time zone
    -+      as their users. Using various notification types, Noom has increased
    -+      user engagement by three to four times.</li>
    -+    </ul>
    -+  </li>
    -+</ul>
    -+
    -+<img src="{@docRoot}images/distribute/stories/noom-screenshot.png">
    -+  <p class="img-caption">
    -+  <strong>Figure 1.</strong> German Play Store listing page, Korean recipes,
    -+  and Japanese meal plan
    -+  </p>
    -+
    -+<h3>
    -+  Results
    -+</h3>
    -+
    -+<p>
    -+  <em>"Android's global focus and great localization tooling made the decision
    -+  to go global much easier. Localization to new markets has been a consistent
    -+  growth driver at Noom,"</em> said Artem Petakov, co-founder and President
    -+  at Noom.
    -+</p>
    -+
    -+<p>
    -+  Over the last three years, Noom’s localization efforts led to an <strong>80%
    -+  increase in international revenue growth on Android</strong>. In Japan
    -+  alone, <strong>revenue increased more than 480%</strong> during the same
    -+  time period. To identify future expansion opportunities, the team looks
    -+  towards countries with strong Android penetration and install growth
    -+  using the English product and plans to apply their localization methods to
    -+  achieve even greater success.
    -+</p>
    -+
    -+<h3>
    -+  Get started
    -+</h3>
    -+
    -+<p>
    -+  Learn more about <a class="external-link" href=
    -+  "https://material.google.com/patterns/notifications.html">Notifications</a>,
    -+  and find out about
    -+  <a href="{@docRoot}distribute/tools/localization-checklist.html">
    -+  app localization</a> and how to
    -+  <a href="{@docRoot}distribute/users/expand-to-new-markets.html">
    -+  Expand Into New Markets</a>.
    -+</p>
    -\ No newline at end of file
    -diff --git a/docs/html/distribute/stories/games.jd b/docs/html/distribute/stories/games.jd
    -index daaac0d..cd31aae 100644
    ---- a/docs/html/distribute/stories/games.jd
    -+++ b/docs/html/distribute/stories/games.jd
    -@@ -25,8 +25,7 @@ page.metaDescription=How game studios are using Google Play game services to del
    -   <h2 class="norule">Articles</h2>
    - 
    -   <div class="resource-widget resource-flow-layout col-16"
    --      data-query="type:distribute+tag:developerstory+tag:games"
    --      data-sortOrder="-timestamp"
    -+      data-query="collection:distribute/stories/games/docs"
    -       data-cardSizes="6x6"
    -       data-items-per-page="15"
    -       data-initial-results="6"></div>
    -diff --git a/docs/html/distribute/stories/games/animoca-star-girl.jd b/docs/html/distribute/stories/games/animoca-star-girl.jd
    -new file mode 100644
    -index 0000000..a38eed2
    ---- /dev/null
    -+++ b/docs/html/distribute/stories/games/animoca-star-girl.jd
    -@@ -0,0 +1,89 @@
    -+page.title=Star Girl Increases In-App Purchases by 3.5X Through More Flexible Minimum Pricing on Google Play
    -+page.metaDescription=Star Girl Increases In-App Purchases by 3.5X.
    -+page.tags="developerstory", "games", "googleplay", "google play"
    -+page.image=images/cards/distribute/stories/animoca.jpg
    -+
    -+@jd:body
    -+
    -+<style type="text/css">
    -+  span.positive{
    -+    color:green;
    -+    font-size: 125%;
    -+    font-weight:bold;">
    -+  }
    -+  span.negative{
    -+    color:red;
    -+    font-size: 125%;
    -+    font-weight:bold;">
    -+  }
    -+</style>
    -+
    -+<h3>Background</h3>
    -+
    -+<div class="figure">
    -+  <img src="{@docRoot}images/distribute/stories/animoca-logo.png" />
    -+</div>
    -+
    -+<p>
    -+  <a class="external-link"
    -+  href="https://play.google.com/store/apps/details?id=com.animoca.google.starGirl&hl=en&e=-EnableAppDetailsPageRedesign">
    -+  Star Girl</a> is a series of SIM/role playing games published by <a class="external-link"
    -+  href="https://play.google.com/store/apps/dev?id=8271704752057011334&hl=en&e=-EnableAppDetailsPageRedesign">
    -+  Animoca</a>, a Hong Kong based game developer. The Star Girl series has more than 70 million
    -+  downloads and is localized in 18 languages. With a fast-growing user base in markets
    -+  including SEA, India, and Latin America, Animoca is exploring ways to effectively increase
    -+  monetization with a localized pricing strategy.
    -+</p>
    -+
    -+<h3>What they did</h3>
    -+
    -+<p>
    -+ Following the introduction of
    -+ <a class="external-link" href="http://android-developers.blogspot.com/2015/11/minimum-purchase-price-for-apps-and-in.html">
    -+ more flexible minimum pricing</a> in November 2015, Animoca took the opportunity to test
    -+ sachet pricing models across Thailand, Malaysia, Philippines, Indonesia, Brazil, and Russia:
    -+</p>
    -+
    -+<p>
    -+ <img src="{@docRoot}images/distribute/stories/animoca-flow.jpg" />
    -+</p>
    -+
    -+<p>
    -+ Animoca created a new sachet SKU, which offered 100 diamonds and 5,000 coins, at the new lower
    -+ minimum price available in these markets. The new SKU is approximately 60% cheaper than the
    -+ previous minimum-priced product and is accessible only through geo-targeted, in-game
    -+ banners in localized languages.
    -+</p>
    -+
    -+<h3>Results</h3>
    -+
    -+<div class="figure">
    -+ <img src="{@docRoot}images/distribute/stories/animoca-graph.jpg" />
    -+</div>
    -+
    -+<p>
    -+ The changes to minimum prices across these markets resulted in positive results, with the
    -+ number of transactions increasing 3.5X in the three months following launch.
    -+</p>
    -+
    -+<p>
    -+ Also, 90% of these transactions were first-time new buyers, half of which
    -+ followed up with purchases of regular packages. This helps to create a more sustainable revenue
    -+ impact, as described by Yusuf Goolamabbas, CTO of Animoca:
    -+</p>
    -+
    -+<p>
    -+ <em>“Sachet marketing has made IAPs more affordable to users in emerging markets. We are seeing
    -+ significant growth in new buyers as well as returning buyers and a positive impact on revenue in
    -+ emerging markets.”</em>
    -+</p>
    -+
    -+<h3>Get started</h3>
    -+
    -+<p>
    -+ <a class="external-link" href="https://support.google.com/googleplay/android-developer/answer/6334373?hl=en-GB">
    -+ Learn more about flexible minimum pricing</a> and
    -+ <a class="external-link" href="http://g.co/play/playbook-dac-writtenstudies-evergreen">
    -+ get the Playbook for Developers app</a> to grow your business and improve
    -+ monetization with Google Play.
    -+</p>
    -\ No newline at end of file
    -diff --git a/docs/html/distribute/stories/games/happy-labs-experiment.jd b/docs/html/distribute/stories/games/happy-labs-experiment.jd
    -new file mode 100644
    -index 0000000..e317e21
    ---- /dev/null
    -+++ b/docs/html/distribute/stories/games/happy-labs-experiment.jd
    -@@ -0,0 +1,105 @@
    -+page.title=Happy Labs Increases Installs by 32% on Google Play with Store Listing Experiments
    -+page.metaDescription=Happy Labs Increases Installs by 32%.
    -+page.tags="developerstory", "games", "googleplay", "google play"
    -+page.image=images/cards/distribute/stories/happylabs-logo.png
    -+
    -+@jd:body
    -+
    -+<style type="text/css">
    -+  span.positive{
    -+    color:green;
    -+    font-size: 125%;
    -+    font-weight:bold;">
    -+  }
    -+  span.negative{
    -+    color:red;
    -+    font-size: 125%;
    -+    font-weight:bold;">
    -+  }
    -+</style>
    -+
    -+<h3>Background</h3>
    -+
    -+<div class="figure">
    -+  <img src="{@docRoot}images/distribute/stories/happylabs-logo.png" />
    -+</div>
    -+
    -+<p>
    -+  <a class="external-link"
    -+  href="https://play.google.com/store/apps/dev?id=5211519071117278745&hl=en">
    -+  Happy Labs</a>, founded in 2012, is a successful game developer in Southeast Asia with 13
    -+  game titles and over 30 million downloads. Its flagship free-to-play virtual sim game,
    -+  <a class="external-link"
    -+  href="https://play.google.com/store/apps/dev?id=5211519071117278745&hl=en">Happy Pet Story</a>,
    -+  launched in February 2016 and is designed for female gamers of all ages.
    -+</p>
    -+
    -+<p>
    -+ Following the announcement of Store Listing Experiments in May, Happy Labs decided to test
    -+ variations of their game icon and screenshots to optimize their store listing.
    -+</p>
    -+
    -+<h3>What they did</h3>
    -+
    -+<p>
    -+ Happy Labs used the Store Listing Experiments feature in the Google Play Developer Console to
    -+ test three new variations of their new game icon. Encouraged by early results, they then
    -+ optimized the game screenshots displayed in their store listing.
    -+</p>
    -+
    -+<h3>Results</h3>
    -+
    -+<p>
    -+ The results showed that the new icon, <em>Sweet Bubbles</em> without a frame, outperformed
    -+ the initial <em>Mojo</em> icon and two other variants, with a 38.6% increase in installs:
    -+</p>
    -+
    -+<p>
    -+ <img src="{@docRoot}images/distribute/stories/happylabs-happy_pet_icon.png" />
    -+</p>
    -+
    -+<p>
    -+ Based on these findings, Happy Labs changed the Happy Pet Story icon to the new image globally
    -+ on Google Play.
    -+</p>
    -+
    -+<p>
    -+ Following the positive icon testing results, Happy Labs ran global store listing experiments
    -+ with a combination of screenshots from their store listing over a five week period. They then took
    -+ their best performing screenshots from the experiments and tested them across three specific
    -+ countries: Indonesia, Thailand, and Japan. The results showed an average increase of 19.87% in
    -+ installs.
    -+</p>
    -+
    -+<p>
    -+ Migrating from the original images to the variants shown in the following figure increased organic
    -+ installs in Thailand by 13.9%:
    -+</p>
    -+
    -+<p>
    -+ <img src="{@docRoot}images/distribute/stories/happylabs-variant.png" />
    -+</p>
    -+
    -+<p>
    -+ With the combination of both store listing experiments, Happy Pet Story saw an average increase of
    -+ 32% in month-on-month organic daily downloads globally, as described by Jeffrey Chee, CEO of Happy
    -+ Labs:
    -+</p>
    -+
    -+<p>
    -+ <em>“Store listing experiments have been an invaluable tool for us in optimizing our Play store
    -+ presence. I am really happy that we were able to get an uplift of 32% in organic installs with
    -+ minimal investment in terms of resources.”</em>
    -+</p>
    -+
    -+<h3>Get started</h3>
    -+
    -+<p>
    -+ Learn how to run
    -+ <a class="external-link" href="https://support.google.com/googleplay/android-developer/answer/6227309">
    -+ Store Listing Experiments</a> and read our best practices for
    -+ <a href="https://developer.android.com/distribute/users/experiments.html">
    -+ running successful experiments</a>. For more best practices on growing your business with Google
    -+ Play, <a class="external-link" href="http://g.co/play/playbook-dac-writtenstudies-evergreen">
    -+ get the Playbook for Developers app</a>.
    -+</p>
    -\ No newline at end of file
    -diff --git a/docs/html/distribute/stories/games/playlab-puzzles.jd b/docs/html/distribute/stories/games/playlab-puzzles.jd
    -new file mode 100644
    -index 0000000..ef1ccff
    ---- /dev/null
    -+++ b/docs/html/distribute/stories/games/playlab-puzzles.jd
    -@@ -0,0 +1,87 @@
    -+page.title=Playlab Increases Juice Cubes Conversions by 25% with Store Listing Experiments
    -+page.metaDescription=Playlab uses store listing experiments to refresh their Juice Cubes icon.
    -+page.tags="developerstory", "apps", "googleplay"
    -+page.image=images/cards/distribute/stories/playlab.jpg
    -+page.timestamp=1468901832
    -+
    -+@jd:body
    -+
    -+<div class="figure">
    -+  <img src="{@docRoot}images/distribute/stories/playlab-icon.png" />
    -+</div>
    -+
    -+<h3>
    -+  Background
    -+</h3>
    -+
    -+<p>
    -+  <a class="external-link" href=
    -+  "https://play.google.com/store/apps/dev?id=9190927840679184784&e=-EnableAppDetailsPageRedesign">
    -+  Playlab</a> is a game developer and publisher based in Hong Kong, with
    -+  production studios in Bangkok and Manila. Playlab apps include
    -+  <a class="external-link" href=
    -+  "https://play.google.com/store/apps/details?id=ppl.unity.JuiceCubesBeta">
    -+  Juice Cubes</a>, <a class="external-link" href=
    -+  "https://play.google.com/store/apps/details?id=ppl.unity.junglecubes">
    -+  Jungle Cubes</a>, and <a class="external-link" href=
    -+  "https://play.google.com/store/apps/details?id=ppl.cocos2dx.ranchrun&hl=en">
    -+  Ranch Run</a>.
    -+
    -+  Released in 2013, <a class="external-link" href=
    -+  "https://play.google.com/store/apps/details?id=ppl.unity.JuiceCubesBeta">
    -+  Juice Cubes</a> is a strategy puzzle game with over 25 million downloads
    -+  worldwide and over 100,000 five-star reviews on Google Play. The game has
    -+  gained success in Southeast Asian markets such as Indonesia and Thailand,
    -+  and in Western markets such as the US, Australia, the UK, and Canada.
    -+</p>
    -+
    -+<h3>
    -+  What they did
    -+</h3>
    -+
    -+<p>
    -+  As part of Juice Cubes’ content update in April 2016, Playlab decided to
    -+  refresh its Play Store icon and test whether different icons could increase
    -+  their conversion rate.
    -+</p>
    -+
    -+<p>
    -+  Playlab used the <em>Store Listing Experiments</em> feature on the Google
    -+  Play Developer Console to test three variations of their new game icon.
    -+</p>
    -+
    -+<h3>
    -+  Results
    -+</h3>
    -+
    -+<p>
    -+  Within three days of running the store listing experiment, Playlab saw
    -+  positive results which led them to make an informed decision to change the
    -+  current icon to the best-performing version. Variant C outperformed the
    -+  initial control icon and the two other variants, with a <strong>25% increase
    -+  in installs</strong>. One month after applying the best-performing icon,
    -+  Juice Cubes continued to see a 25% increase in the number of conversions
    -+  from store visitors who made organic installs.
    -+</p>
    -+
    -+<img src="{@docRoot}images/distribute/stories/playlab-screenshot.png">
    -+
    -+<p>
    -+  <em>"Google Play Store Listing Experiments offer a fast, easy, and free way
    -+  to do A/B testing on an icon. The data provided after each test helped us
    -+  to make a decision really quickly. The best part is the team no longer needs
    -+  so many resources to decide which icon to use because we can let the
    -+  users decide."</em> said Jakob Lykkegaard, CEO and co-founder of Playlab.
    -+</p>
    -+
    -+<h3>
    -+  Get started
    -+</h3>
    -+
    -+<p>
    -+  Learn how to use <a class="external-link" href=
    -+  "https://support.google.com/googleplay/android-developer/answer/6227309">
    -+  A/B testing</a> and find out more about how to run
    -+  <a href="{@docRoot}distribute/users/experiments.html">
    -+  store listing experiments</a> on Google Play.
    -+</p>
    -\ No newline at end of file
    -diff --git a/docs/html/distribute/stories/index.jd b/docs/html/distribute/stories/index.jd
    -index 1adc5ae..7d84ce4 100644
    ---- a/docs/html/distribute/stories/index.jd
    -+++ b/docs/html/distribute/stories/index.jd
    -@@ -4,16 +4,6 @@ page.metaDescription=Android developers, their apps, and their successes with An
    - 
    - @jd:body
    - 
    --<script>
    --  $(document).ready(function() {
    --    if (useUpdatedTemplates) {
    --      $("#useUpdatedTemplates").css("display","block");
    --    } else {
    --      $("#useOldTemplates").css("display","block");
    --    }
    --  })
    --</script>
    --
    - <p>Android developers, their apps, and their successes with Android and Google Play.</p>
    - 
    - <section class="dac-section dac-small" id="latest-apps"><div class="wrap">
    -@@ -31,11 +21,11 @@ page.metaDescription=Android developers, their apps, and their successes with An
    -   <h3 class="norule">Articles</h3>
    - 
    -   <div class="resource-widget resource-flow-layout col-16"
    --      data-query="type:distribute+tag:developerstory+tag:apps"
    --      data-sortOrder="-timestamp"
    -+      data-query="collection:distribute/stories/apps/docs"
    -       data-cardSizes="6x6"
    -       data-items-per-page="15"
    -       data-initial-results="6"></div>
    -+
    - </div></section>
    - 
    - <section class="dac-section dac-small" id="latest-games"><div class="wrap">
    -@@ -53,9 +43,9 @@ page.metaDescription=Android developers, their apps, and their successes with An
    -   <h3 class="norule">Articles</h3>
    - 
    -   <div class="resource-widget resource-flow-layout col-16"
    --      data-query="type:distribute+tag:developerstory+tag:games"
    --      data-sortOrder="-timestamp"
    -+      data-query="collection:distribute/stories/games/docs"
    -       data-cardSizes="6x6"
    -       data-items-per-page="15"
    -       data-initial-results="6"></div>
    -+
    - </div></section>
    -diff --git a/docs/html/distribute/tools/promote/brand.jd b/docs/html/distribute/tools/promote/brand.jd
    -index 409dfdd..ba2bed7 100644
    ---- a/docs/html/distribute/tools/promote/brand.jd
    -+++ b/docs/html/distribute/tools/promote/brand.jd
    -@@ -34,30 +34,31 @@ marketing for review.</p>
    -     <ul>
    -     <li>Android&trade; should have a trademark symbol the first time it appears in a creative.</li>
    -     <li>Android should always be capitalized and is never plural or possessive.</li>
    --    <li>"Android" cannot be used in names of applications or accessory products,
    --    including phones, tablets, TVs, speakers, headphones, watches, and other devices. Instead use "for Android".
    -+    <li>"Android", or anything confusingly similar to "Android", cannot be used
    -+    in names of applications or accessory products, including phones, tablets, TVs,
    -+    speakers, headphones, watches, and other devices. Instead, use "for Android".
    -       <ul>
    --        <li><span style="color:red">Incorrect</span>: "Android MediaPlayer"</li>
    -+        <li><span style="color:red">Incorrect</span>: "Android MediaPlayer" or "Ndroid MediaPlayer"</li>
    -         <li><span style="color:green">Correct</span>: "MediaPlayer for Android"</li>
    -       </ul>
    --      <p>If used with your logo, "for Android" should be no larger than 90% of your logo’s size.
    --      First instance of this use should be followed by a TM symbol, "for Android&trade;".</p>
    -+      <p>If used with your logo, "for Android" should be no larger than 90% of your logo's size.
    -+      The first instance of this use should be followed by a TM symbol: "for Android&trade;".</p>
    -     </li>
    --    <li>"Android TV", "Android Wear" and "Android Auto" may only be used to identify or market
    -+    <li>"Android TV", "Android Wear", and "Android Auto" may only be used to identify or market
    -       products or services with prior approval.  Use "for Android" or "with Android" for all
    --      other Android-based products
    -+      other Android-based products.
    -       <ul>
    -         <li><span style="color:red">Incorrect</span>: "Android TV Streaming Stick",
    -           "Streaming Stick with Android TV"</li>
    -         <li><span style="color:green">Correct</span>: "Streaming Stick with Android"</li>
    -       </ul>
    -       <p>If used with your logo, "for Android" or "with Android" should be no larger than 90% of
    --        your logo’s size. First instance of this use should be followed by a TM symbol,
    -+        your logo's size. The first instance of this use should be followed by a TM symbol:
    -         "for Android&trade;".</p>
    -     </li>
    --    <li>Android may be used as a descriptor, as long as it is followed by a
    --        proper generic term. (Think of "Android" as a term used in place of
    --        "the Android platform.")
    -+    <li>Android may be used as a descriptor in text, as long as it is followed by a
    -+        proper generic term and is not the name of your product, app, or service.
    -+        Think of "Android" as a term used in place of "the Android platform."
    -       <ul>
    -         <li><span style="color:red">Incorrect</span>: "Android MediaPlayer" or "Android XYZ app"</li>
    -         <li><span style="color:green">Correct</span>: "Android features" or "Android applications"</li>
    -@@ -100,7 +101,9 @@ used according to terms described in the Creative Commons 3.0 Attribution Licens
    - <h4 style="clear:right">Android logo</h4>
    - 
    - <div style="float:right;width:210px;margin-left:30px;margin-top:-10px">
    --  <img alt="" src="{@docRoot}images/brand/android_logo_no.png">
    -+  <img alt="" src="{@docRoot}images/brand/android_logo_no.png"
    -+    srcset="{@docRoot}images/brand/android_logo_no.png 1x,
    -+    {@docRoot}images/brand/android_logo_no_2x.png 2x">
    - </div>
    - 
    - <p>The Android logo may not be used.</p>
    -diff --git a/docs/html/distribute/users/build-buzz.jd b/docs/html/distribute/users/build-buzz.jd
    -index 7bc6f6c..65aa44a 100644
    ---- a/docs/html/distribute/users/build-buzz.jd
    -+++ b/docs/html/distribute/users/build-buzz.jd
    -@@ -28,9 +28,6 @@ page.tags="users, growth, promotion"
    -     Link to Your Apps in Google Play
    -   </h2>
    - 
    --
    --</div>
    --
    - <p>
    -   After publishing your apps, you can take Android users directly to your
    -   app/games detail page on Google Play by <a href=
    -@@ -64,9 +61,6 @@ page.tags="users, growth, promotion"
    -     Use the Google Play Badge
    -   </h2>
    - 
    --
    --</div>
    --
    - <div class="figure" style="margin:0 3em;">
    -   <img src="{@docRoot}images/gp-build-buzz-uplift-1.png">
    - </div>
    -diff --git a/docs/html/google/play/billing/billing_admin.jd b/docs/html/google/play/billing/billing_admin.jd
    -index 292cfcc..9936489 100644
    ---- a/docs/html/google/play/billing/billing_admin.jd
    -+++ b/docs/html/google/play/billing/billing_admin.jd
    -@@ -51,9 +51,9 @@ apps. You can sell an item using Google Play's in-app billing feature only if th
    - listed on an app's product list. Each app has its own product list; you cannot sell
    - items that appear on another app's product list.</p>
    - 
    --<p>You can access an app's product list by opening the <strong>In-app Products</strong>
    -+<p>You can access an app's product list by opening the <em>In-app Products</em>
    - page for an app that is listed in your developer account. The link to the
    --<strong>In-app Products</strong> page appears only if you have a Google payments merchant
    -+<em>In-app Products</em> page appears only if you have a Google payments merchant
    - account and the app's manifest includes the
    - <code>com.android.vending.BILLING</code> permission. For more information about this
    - permission, see <a href="{@docRoot}google/play/billing/billing_integrate.html#billing-permission">
    -@@ -73,7 +73,7 @@ uploading an unpublished draft version. This functionality is no longer
    - supported; instead, you must publish it to the alpha or beta distribution
    - channel. For more information, see <a
    - href="{@docRoot}google/play/billing/billing_testing.html#draft_apps">Draft Apps
    --are No Longer Supported</a>.
    -+are No Longer Supported</a>.</p>
    - 
    - <p>In addition, an app package can have only one product list. If you create a product
    - list for an app, and you use the <a
    -@@ -82,8 +82,8 @@ more than one APK for that app, the product list applies to all APK versions tha
    - associated with the app listing. You cannot create individual product lists for each APK if
    - you are using the multiple APK feature.</p>
    - 
    --<p>You can add items to a product list two ways: you can add items one at a time on the <strong>In-app
    --Products</strong> page, or you can add a batch of items by importing the items from a
    -+<p>You can add items to a product list two ways: you can add items one at a time on the <em>In-app
    -+Products</em> page, or you can add a batch of items by importing the items from a
    - comma-separated values (CSV) file. Adding items one at a time is useful if your
    - app has only a few in-app items or you are adding only a few items to a
    - product list for testing purposes. The CSV file method is useful if your app has a large
    -@@ -100,14 +100,14 @@ number of in-app items.</p>
    - 
    - <ol>
    -   <li><a href="http://play.google.com/apps/publish">Log in</a> to your publisher account.</li>
    --  <li>In the <strong>All applications</strong> panel, click on the
    --  app name, then open the <strong>In-app Products</strong> page.</li>
    -+  <li>In the <em>All applications</em> panel, click on the
    -+  app name, then open the <em>In-app Products</em> page.</li>
    -   <li><p>Click <strong>Add new product</strong>. After you provide the product type and ID for the item you are
    -   selling, click <strong>Continue</strong>.</p>
    -   <dl>
    -       <dt>Product Type</dt>
    -       <dd>
    --        <p>The product type can be <strong>Managed product</strong> or <strong>Subscription</strong>. You cannot
    -+        <p>The product type can be "Managed product" or "Subscription." You cannot
    -         change an item's product type after you create the item. For more information, see
    -         <a href="#billing-purchase-type">Choosing a Product Type</a>.</p>
    -         <p class="note"><strong>Note: </strong>For subscription items, you cannot change the
    -@@ -169,7 +169,7 @@ number of in-app items.</p>
    -         <p>You can also change prices for other currencies manually, but you can do
    -           this only if a currency is used in one of the target countries for your
    -           app. You can specify target countries for your app on the
    --          <strong>Pricing &amp; Distribution</strong> page in the Google Play
    -+          <em>Pricing &amp; Distribution</em> page in the Google Play
    -           Developer Console.</p>
    -       </dd>
    -     </dl>
    -@@ -187,235 +187,412 @@ number of in-app items.</p>
    - 
    - <h3 id="billing-bulk-add">Adding a batch of items to a product list</h3>
    - 
    --<p>To add a batch of items to a product list using a CSV file, you first need to create your CSV
    --file. The data values that you specify in the CSV file represent the same data values you specify
    --manually through the In-app Products UI (see <a href="#billing-form-add">Adding items one at a time
    --to a product list</a>).
    -+<p>To add a batch of items to a product list using a CSV file, you first need to
    -+create your CSV file. The data values that you specify in the CSV file represent
    -+the options that you set when adding in-app products to a product list using the
    -+Google Play Developer Console UI. For more information about using this UI, see
    -+<a href="#billing-form-add">Adding items one at a time to a product list</a>.
    - 
    --<p>If you are importing and exporting CSV files with in-app products, keep
    --country-specific pricing in mind. If you use auto-fill, you can provide a
    --tax-exclusive default price, and tax-inclusive prices will be auto-filled. If you
    --do not use auto-fill, prices you provide must include tax.</p>
    -+<p class="note"><strong>Note:</strong> Batch upload of in-app product lists
    -+containing subscriptions is not supported. Also, when updating existing items in
    -+a batch upload, you cannot include changes to in-app products that are linked to
    -+a <a href="#pricing-template">pricing template</a>.</p>
    - 
    --<p class="note"><strong>Note:</strong> Batch upload of product lists containing
    --subscriptions is not supported. Also, when updating existing items in a batch
    --upload, you cannot include changes to in-app products that are linked to a
    --<a href="#pricing-template">pricing template</a>.</p>
    --
    --<p>To import the items that are specified in your CSV file, do the following:</p>
    -+<p>To import the in-app products that are specified in your CSV file, do the
    -+following:</p>
    - 
    - <ol>
    --  <li><a href="http://play.google.com/apps/publish">Log in</a> to your publisher account.</li>
    --  <li>In the <strong>All applications</strong> panel, select the app
    --  name, then open the <strong>In-app Products</strong> page.</li>
    --  <li>On the In-app Products List page, click <strong>Import/Export</strong>
    --  &gt; <strong>Import in-app products from CSV file</strong>, then select your
    --  CSV file.
    --    <p>The CSV file must be on your local computer or on a local disk that is connected to your
    --    computer.</p>
    --  </li>
    --  <li>Select the <strong>Overwrite</strong> checkbox if you want to overwrite existing items in
    --  your product list.
    --    <p>This option overwrites values of existing items only if the value of the <em>product_id</em>
    --    in the CSV file matches the In-app Product ID for an existing item in the product list.
    --    Overwriting doesn't delete items that are on a product list but not present in the CSV
    --    file.</p>
    -+  <li>
    -+    <a href="http://play.google.com/apps/publish">Log in</a> to your
    -+    publisher account.
    -+  </li>
    -+  <li>In the <em>All applications</em> panel, select the app
    -+  name, then open the <em>In-app Products</em> page.</li>
    -+  <li>
    -+    <p>On the <em>In-app Products</em> page, click
    -+    <strong>Import/Export</strong> &gt; <strong>Import in-app products from CSV
    -+    file</strong> to open the <em>Import In-app Products</em> dialog.</p>
    -+  </li>
    -+  <li>
    -+    <p>
    -+      If you want to overwrite existing in-app products in your product list
    -+      during the import process, select the <strong>Overwrite existing
    -+      products</strong> checkbox.
    -+    </p>
    -+    <p>
    -+      This option overwrites values of existing items only if the value of the
    -+      <code>Product ID</code> in the CSV file matches the in-app product ID for
    -+      an existing in-app product in the product list. The overwriting process
    -+      doesn't delete in-app products that exist in a product list but aren't
    -+      included in the CSV file
    -+    </p>
    -+    <p class="note"><strong>Note: </strong>If you choose not to overwrite
    -+    existing items, the <code>Product ID</code> given to each item in the CSV
    -+    file must be different from any of the <code>Product ID</code> values
    -+    assigned to existing in-app products.
    -+    </p>
    -+  </li>
    -+  <li>
    -+    Select <strong>Browse files</strong>, then choose the CSV file that contains
    -+    the items you want to import. The CSV file must be stored locally.
    -   </li>
    - </ol>
    - 
    --<p>You can also export an existing product list to a CSV file by clicking <strong>Export to CSV
    --</strong> on the In-app Product List page. This is useful if you have manually added items to
    --a product list and you want to start managing the product list through a CSV file.</p>
    -+<p>
    -+  You can also export an existing product list to a CSV file by clicking
    -+  <strong>Import/Export</strong> &gt; <strong>Export in-app products to CSV file
    -+  </strong> on the <em>In-app Products page</em>. This is useful if you have
    -+  used the UI to add in-app products to your app but you want to start managing
    -+  the product list through a CSV file instead.
    -+</p>
    - 
    - <h4 id="billing-bulk-format">Formatting batches of items</h4>
    - 
    --<p>The CSV file uses commas (,) and semicolons (;) to separate data values.
    --Commas are used to separate primary data values, and semicolons are used to
    --separate subvalues. For example, the syntax for the CSV file is as follows:</p>
    -+<p>
    -+  The CSV file uses commas (<code>,</code>) and semicolons (<code>;</code>) to
    -+  separate data values. Commas are used to separate primary data values, and
    -+  semicolons are used to separate subvalues. Each item must appear entirely on a
    -+  single line within the CSV file.
    -+</p>
    -+<p>
    -+  When creating a CSV file that represents a list of items, you must specify the
    -+  CSV syntax on the first row, followed by the items themselves on subsequent
    -+  rows, as shown in the following example:
    -+</p>
    -+
    -+<pre class="no-pretty-print">
    -+Product ID,Published State,Purchase Type,Auto Translate,Locale; Title; Description,Auto Fill Prices,Price,Pricing Template ID
    -+basic_sleeping_potion,published,managed_by_android,false,en_US; Basic Sleeping Potion; Puts small creatures to sleep.; es_ES; Poción básica de dormir; Causa las criaturas pequeñas ir a dormir.,false,,4637138456024710495
    -+standard_sleeping_potion,published,managed_by_android,false,en_US; Standard Sleeping Potion; Puts all creatures to sleep for 2 minutes.,true, 1990000,
    -+invisibility_potion,published,managed_by_android,false,en_US; Invisibility Potion; Invisible to all enemies for 5 minutes.,false, US; 1990000; BR; 6990000; RU; 129000000; IN; 130000000; ID; 27000000000; MX; 37000000;
    -+</pre>
    - 
    --<p>"<em>product_id</em>","<em>publish_state</em>","<em>purchase_type</em>","<em>autotranslate</em>
    --","<em>locale</em>; <em>title</em>; <em>description</em>","<em>autofill</em>","<em>country</em>;
    --<em>price</em>"
    -+<p>
    -+  This example contains details for three items, each of which represents an
    -+  in-app product:
    - </p>
    -+<ul>
    -+  <li>
    -+    The first item defines a title and description for the <code>en_US</code>
    -+    and <code>es_ES</code> locales. A pricing template defines the item's
    -+    price.
    -+  </li>
    -+  <li>
    -+    The second item doesn't use a pricing template. Instead, it specifies a
    -+    price for the default country (US). The Google Play Developer Console
    -+    uses current exchange rates and locally relevant pricing patterns to
    -+    automatically set the prices in all other countries where the app is
    -+    distributed.
    -+  </li>
    -+  <li>
    -+    The third item also doesn't use a pricing template. The item's price is
    -+    specified manually for each country where the app is distributed.
    -+  </li>
    -+</ul>
    - 
    --<p>Descriptions and usage details are provided below.</p>
    -+<p>
    -+  Each row in a CSV file can contain the following values, though at least one
    -+  of these values is undefined in each row:
    -+</p>
    - 
    - <dl>
    --  <dt>product_id</dt>
    -+  <dt><code>Product ID</code></dt>
    -   <dd>
    --    This is equivalent to the In-app Product ID setting in the In-app Products UI. If you specify
    --    a <em>product_id</em> that already exists in a product list, and you choose to overwrite
    --    the product list while importing the CSV file, the data for the existing item is overwritten with
    --    the values specified in the CSV file. The overwrite feature does not delete items that are on a
    --    product list but not present in the CSV file.
    -+    <p>
    -+      Setting this value in the CSV file has the same effect as entering a
    -+      <em>Product ID</em> when creating a new in-app product.
    -+    </p>
    -+    <p>
    -+      If you specify a <code>Product ID</code> assigned to an in-app product that already
    -+      exists in a product list, and you've checked the <strong>Overwrite
    -+      existing products</strong> checkbox in the <em>Import In-app Products</em>
    -+      dialog, the data for the existing in-app product is overwritten with the
    -+      values that you specify in the CSV file.
    -+    </p>
    -   </dd>
    --  <dt>publish_state</dt>
    -+  <dt><code>Publish State</code></dt>
    -   <dd>
    --    This is equivalent to the Publishing State setting in the In-app Products UI. Can be <code>
    --    published</code> or <code>unpublished</code>.
    -+    <p>
    -+      This value must be set to <code>published</code>
    -+      or <code>unpublished</code>.
    -+    </p>
    -+    <p>
    -+      Setting this value to <code>published</code> has the same effect as
    -+      navigating to an item's <em>Managed Product Details</em> page and choosing
    -+      <strong>Active</strong> in the drop-down list next to the in-app product's
    -+      title and product ID. Setting the value to <code>unpublished</code>
    -+      has the same effect as choosing <strong>Inactive</strong> in the same
    -+      drop-down list.
    -+    </p>
    -   </dd>
    --  <dt>purchase_type</dt>
    -+  <dt><code>Purchase Type</code></dt>
    -   <dd>
    --    This is equivalent to the Product Type setting in the In-app Products UI. Can be <code>
    --    managed_by_android</code>, which is equivalent to <strong>Managed per user account
    --    </strong> in the In-app Products UI, or <code>managed_by_publisher</code>, which is equivalent
    --    to <strong>Unmanaged</strong> in the In-app Products UI.
    -+    <p>
    -+      This value must be set to <code>managed_by_android</code> because batch
    -+      upload of product lists containing subscriptions is not supported.
    -+    </p>
    -+    <p>
    -+      Setting this value to <code>managed_by_android</code> has the same effect
    -+      as selecting <strong>Managed product</strong> in the <em>Add New
    -+      Product</em> dialog when creating an in-app product.
    -+    </p>
    -   </dd>
    --  <dt>autotranslate</dt>
    -+  <dt><code>Auto Translate</code></dt>
    -   <dd>
    --    This is equivalent to selecting the <strong>Fill fields with auto translation</strong>
    --    checkbox in the In-app Products UI. Can be <code>true</code> or <code>false</code>.
    -+    <p>
    -+      This value must be set to <code>false</code> because auto-translation of
    -+      in-app product details isn't supported.
    -+    </p>
    -+    <p>
    -+      If you want to provide translations of an in-app product's title and
    -+      description, you need to specify these translations explicitly within the
    -+      <code>Locale</code> value.
    -+    </p>
    -   </dd>
    --  <dt>locale</dt>
    -+  <dt><code>Locale</code>, <code>Title</code>, and <code>Description</code></dt>
    -   <dd>
    --    <p>This is equivalent to the Language setting in the In-app Products UI. You must have an entry
    --    for the default locale. The default locale must be the first entry in the list of
    --    locales, and it must include a <em>title</em> and <em>description</em>. If you want to provide
    --    translated versions of the <em>title</em> and <em>description</em> in addition to the default,
    --    you must use the following syntax rules:</p>
    --    <ul>
    -+    <p>
    -+      If you include only one locale for an item, you must specify your app's
    -+      default locale and the item's default title and description:
    -+    </p>
    -+
    -+<pre class="no-pretty-print">
    -+<var>app_default_locale</var>; <var>item_default_title</var>; <var>item_default_description</var>;
    -+</pre>
    -+
    -+    <p>
    -+      Setting these values has the same effect as performing the following
    -+      sequence of actions:
    -+    </p>
    -+    <ol>
    -       <li>
    --      <p>If <em>autotranslate</em> is <code>true</code>, you must specify the default locale,
    --      default title, default description, and other locales using the following format:</p>
    --      <p>"true,"<em>default_locale</em>; <em>default_locale_title</em>;
    --      <em>default_locale_description</em>; <em>locale_2</em>;    <em>locale_3</em>, ..."</p>
    -+        Choosing a default language when you add a new app to your
    -+        publisher account.
    -       </li>
    -       <li>
    --      <p>If <em>autotranslate</em> is <code>false</code>, you must specify the default locale,
    --      default title, and default description as well as the translated titles and descriptions using
    --      the following format:</p>
    --      <p>"false,"<em>default_locale</em>; <em>default_locale_title</em>;
    --      <em>default_locale_description</em>; <em>locale_2</em>; <em>locale_2_title</em>;
    --      <em>local_2_description</em>; <em>locale_3</em>; <em>locale_3_title</em>;
    --       <em>locale_3_description</em>; ..."</p>
    -+        Navigating to an in-app product's <em>Managed Product Details</em> page.
    -       </li>
    --    </ul>
    --    <p>See table 1 for a list of the language codes you can use with the <em>locale</em> field.</p>
    --  </dd>
    --  <dt>title</dt>
    --  <dd>
    --    This is equivalent to the Title setting in the In-app Products UI. If the <em>title</em>
    --    contains a semicolon, it must be escaped with a backslash (for example, <code>\;</code>). Also, a backslash
    --    must be escaped with a backslash (for example, <code>\\</code>).
    --  </dd>
    --  <dt>description</dt>
    --  <dd>
    --    This is equivalent to the Description in the In-app Products UI. If the <em>description</em>
    --    contains a semicolon, it must be escaped with a backslash (for example, <code>\;</code>). Also, a backslash
    --    must be escaped with a backslash (for example, <code>\\</code>).
    -+      <li>
    -+        Specifying the in-app product's default title and description.
    -+      </li>
    -+    </ol>
    -+    <p>
    -+      When setting the <code>Locale</code> value, you can use any of the
    -+      language codes that appear within the <em>Add Your Own Translations</em>
    -+      dialog. You can access this dialog by navigating to an in-app product's
    -+      <em>Managed Product Details</em> page and clicking <strong>Add
    -+      translations</strong> or <strong>Manage translations</strong>.
    -+    </p>
    -+    <p class="note">
    -+      <strong>Note: </strong>When specifying the <code>Title</code> and
    -+      <code>Description</code> values, use backslashes to escape the semicolon
    -+      (<code>\;</code>) and backslash (<code>\\</code>) characters.
    -+    </p>
    -+    <p>
    -+      If you want to include translated versions of the item's title and
    -+      description, you must list the default locale, title, and description,
    -+      followed by the locales, titles, and descriptions for each translation.
    -+      In the following example, the in-app product uses <code>en_US</code>
    -+      (United States English) as the default locale and <code>es_ES</code>
    -+      (Spain Spanish) as a translation:
    -+    </p>
    -+<pre class="no-pretty-print">
    -+en_US; Invisibility Cloak; Makes you invisible.; es_ES; Capote Invisible; Se vuelven invisible.
    -+</pre>
    -+    <p class="note">
    -+      <strong>Note: </strong>An app contains a single default language, but each
    -+      in-app product maintains its own list of translations. Therefore, although
    -+      the first locale in each item's <code>Locale</code> value must be the same
    -+      throughout the CSV file, the other locales can differ from one item to
    -+      another.
    -+    </p>
    -+    <p>
    -+      Providing values for multiple translations has the same effect as
    -+      performing the following sequence of actions:
    -+    </p>
    -+    <ol>
    -+      <li>
    -+        Navigating to an in-app product's <em>Managed Product Details</em> page.
    -+      </li>
    -+      <li>
    -+        Clicking <strong>Add translations</strong>.
    -+      </li>
    -+      <li>
    -+        Selecting the languages for the translations and clicking
    -+        <strong>Add</strong>.
    -+      </li>
    -+      <li>
    -+        Choosing one of the languages you added in the previous step.
    -+      </li>
    -+      <li>
    -+        Specifying a new title and description, which serve as translations into
    -+        the selected language.
    -+      </li>
    -+      <li>
    -+        Repeating steps 4 and 5 to add translations into all other non-default
    -+        languages.
    -+      </li>
    -+    </ol>
    -   </dd>
    --  <dt>autofill</dt>
    -+  <dt><code>Auto Fill Prices</code>, <code>Country</code>, and
    -+  <code>Price</code></dt>
    -   <dd>
    --    <p>This is equivalent to clicking <strong>Auto Fill</strong> in the In-app Products UI. Can be
    --    <code>true</code> or <code>false</code>. The syntax for specifying the <em>country</em>
    --    and <em>price</em> varies depending on which <em>autofill</em> setting you use:</p>
    -+    <p>
    -+      You can set <code>Auto Fill Prices</code> to <code>true</code> or
    -+      <code>false</code>.
    -+      If an in-app product uses a <a href="#pricing-template">pricing
    -+      template</a>, you should set <code>Auto Fill Prices</code> to
    -+      <code>false</code>, and you shouldn't set a value for the
    -+      <code>Price</code>.
    -+    </p>
    -+    <p class="note">
    -+      <strong>Note: </strong>When you specify an item's price in a CSV file, you
    -+      provide a price in <em>micro-units</em>, where 1,000,000 micro-units is
    -+      equivalent to 1 unit of real currency.
    -+    </p>
    -+    <p>
    -+      The following sections describe how the value of
    -+      <code>Auto Fill Prices</code> affects the syntax and meaning of the
    -+      <code>Country</code> and <code>Price</code> values.
    -+    </p>
    -+    <h5>Using auto-filled prices</h5>
    -+    <p>
    -+      If you set <code>Auto Fill Prices</code> to <code>true</code>, you specify
    -+      only the item's default price; you don't include a <code>Country</code>
    -+      value. Setting <code>Auto Fill Prices</code> to <code>true</code> has the
    -+      same effect as performing the following sequence of actions:
    -+    </p>
    -+    <ol>
    -+      <li>
    -+        Navigating to an in-app product's <em>Managed Product Details</em> page.
    -+      </li>
    -+      <li>
    -+        Selecting <strong>Edit</strong> in the <em>Price</em> section.
    -+      </li>
    -+      <li>
    -+        Entering a default, tax-exclusive price. Auto-filled prices include tax.
    -+      </li>
    -+      <li>
    -+        Clicking the checkbox next to <em>COUNTRY</em> in the <em>Edit Local
    -+        Prices</em> dialog that appears.
    -+      </li>
    -+      <li>
    -+        Selecting <strong>Refresh exchange rates</strong>.
    -+      </li>
    -+      <li>
    -+        Selecting <strong>Apply</strong>.
    -+      </li>
    -+    </ol>
    -+    <p>
    -+      For example, under the following conditions:
    -+    </p>
    -     <ul>
    -+      <li>Your app's default locale is <code>en_US</code>.</li>
    -+      <li>An in-app product's default, tax-exclusive price is $1.99.</li>
    -+      <li>You want the prices for other countries auto-filled.</li>
    -+    </ul>
    -+    <p>
    -+      ...you'd set the values of <code>Auto Fill Prices</code> and
    -+      <code>Price</code> at the end of a row in the CSV file as follows:
    -+    </p>
    -+
    -+<pre class="no-pretty-print">
    -+true,1990000,
    -+</pre>
    -+
    -+    <h5>Not using auto-filled prices</h5>
    -+    <p>
    -+      If you set <code>Auto Fill Prices</code> to <code>false</code> instead,
    -+      you specify a series of <code>Country</code> and <code>Price</code>
    -+      values for all countries where you distribute your app, including the country corresponding to your app's default locale.
    -+      Each <code>Country</code> value is the two-letter uppercase <a
    -+      class="external-link"
    -+      href="https://en.wikipedia.org/wiki/ISO_3166-1_alpha-2">ISO country
    -+      code</a> that represents a country where your app is distributed.
    -+    </p>
    -+    <p class="note">
    -+      <strong>Note: </strong>You must provide a country code and price for each
    -+      country that your app is targeting. To view and edit the list of countries
    -+      that your app targets, open your app's <em>Pricing &amp; Distribution</em>
    -+      page.
    -+    </p>
    -+    <p>
    -+      Each <code>Price</code> value represents the cost of the item in
    -+      micro-units of the currency used in that country. Setting <code>Auto Fill
    -+      Prices</code> to <code>false</code> has the same effect as performing
    -+      the following sequence of actions:
    -+    </p>
    -+    <ol>
    -+      <li>
    -+        Navigating to an in-app product's <em>Managed Product Details</em> page.
    -+      </li>
    -+      <li>
    -+        Selecting <strong>Edit</strong> in the <em>Price</em> section.
    -+      </li>
    -       <li>
    --        <p>If <em>autofill</em> is set to <code>true</code>, you need to specify only the default
    --        price in your home currency, and you must use this syntax:</p>
    --        <p>"true","<em>default_price_in_home_currency</em>"
    -+        Explicitly setting tax-inclusive prices for different countries in the
    -+        <em>Edit Local Prices</em> dialog that appears.
    -       </li>
    -       <li>
    --        <p>If <em>autofill</em> is set to <code>false</code>, you need to specify a <em>country</em>
    --        and a <em>price</em> for each currency, and you must use the following syntax:</p>
    --        <p>"false", "<em>home_country</em>; <em>default_price_in_home_currency</em>; <em>country_2</em>;
    --        <em>country_2_price</em>; <em>country_3</em>; <em>country_3_price</em>; ..."</p>
    -+        Selecting <strong>Apply</strong>.
    -       </li>
    -+    </ol>
    -+    <p>
    -+      For example, if you're offering your app for the following prices (all
    -+      taxes included) in other countries:
    -+    </p>
    -+    <ul>
    -+      <li>R$6.99 in Brazil.</li>
    -+      <li>129&nbsp;&#8381; in Russia.</li>
    -+      <li>&#8377;130 in India.</li>
    -+      <li>Rp&nbsp;27,000 in Indonesia.</li>
    -+      <li>$37 in Mexico.</li>
    -     </ul>
    --    <p class="note"><strong>Note: </strong>If you use an <em>autofill</em> value of <code>false</code>
    --    and set country prices manually, you must incorporate country-specific
    --    pricing patterns, including tax rates, into the prices you provide.</p>
    --  </dd>
    --  <dt>country</dt>
    --  <dd>
    --    The country for which you are specifying a price. You can only list countries that your
    --    app is targeting. The country codes are two-letter uppercase
    --    ISO country codes (such as "US"), as defined by
    --    <a href="http://en.wikipedia.org/wiki/ISO_3166-1_alpha-2">ISO 3166-2</a>.
    -+    <p>
    -+      ...you'd set the values of <code>Auto Fill Prices</code>,
    -+      <code>Country</code>, and <code>Price</code> at the end of a row in the
    -+      CSV file as follows:
    -+    </p>
    -+
    -+<pre class="no-pretty-print">
    -+false, BR; 6990000; RU; 129000000; IN; 130000000; ID; 27000000000; MX; 37000000;
    -+</pre>
    -+
    -   </dd>
    --  <dt>price</dt>
    -+  <dt><code>Pricing Template ID</code></dt>
    -   <dd>
    --    This is equivalent to the Price in the In-app Products UI. The price must be specified in
    --    micro-units. To convert a currency value to micro-units, you multiply the real value by
    --    1,000,000.
    --    For example, if you want to sell an in-app item for $1.99, you specify <code>1990000</code> in the
    --    <em>price</em> field.
    -+  <p>
    -+    If an item is linked to a pricing template, you should set <code>Auto Fill
    -+    Prices</code> to <code>false</code>, and you shouldn't set a value for the
    -+    <code>Price</code> column. If the item isn't linked to a pricing template,
    -+    you shouldn't set a value for the <code>Pricing Template ID</code>; instead,
    -+    you should set <code>Auto Fill Prices</code>, <code>Country</code>, and
    -+    <code>Price</code> based on how you want to set the in-app product's prices.
    -+  </p>
    -+  <p>
    -+    Setting this value has the same effect as navigating to an in-app product's
    -+    <em>Managed Product Details</em> page and linking the product's price to the
    -+    pricing template that has the same pricing template ID as the one specified
    -+    in the CSV file. This pricing template ID appears underneath a pricing
    -+    template's name on the <em>Pricing template</em> page.
    -+  </p>
    -+  <p>
    -+    If you import a CSV file, and you've checked the <strong>Overwrite existing
    -+    products</strong> checkbox in the <em>Import In-app Products</em> dialog,
    -+    you can update the links between in-app products and pricing templates. To
    -+    link the product to a specific pricing template, set the <code>Pricing
    -+    Template ID</code> value to that pricing template's ID. To unlink an in-app
    -+    product from all pricing templates, don't set a value for its <code>Pricing
    -+    Template ID</code>.
    -+  </p>
    -+  <p>
    -+    You can link up to 100 app prices or in-app product prices to a particular
    -+    pricing template. Therefore, don't specify the same <code>Pricing Template
    -+    ID</code> value in more than 100 rows of a CSV file.
    -+  </p>
    -   </dd>
    - </dl>
    - 
    --<p class="table-caption" id="language-table"><strong>Table 1.</strong> Language codes you can use
    --with the <em>locale</em> field.</p>
    --
    --<table>
    --
    --<tr>
    --<th>Language</th>
    --<th>Code</th>
    --<th>Language</th>
    --<th>Code</th>
    --</tr>
    --<tr>
    --<td>Chinese</td>
    --<td>zh_TW</td>
    --<td>Italian</td>
    --<td>it_IT</td>
    --</tr>
    --<tr>
    --<td>Czech</td>
    --<td>cs_CZ</td>
    --<td>Japanese</td>
    --<td>ja_JP</td>
    --</tr>
    --<tr>
    --<td>Danish</td>
    --<td>da_DK</td>
    --<td>Korean</td>
    --<td>ko_KR</td>
    --</tr>
    --<tr>
    --<td>Dutch</td>
    --<td>nl_NL</td>
    --<td>Norwegian</td>
    --<td>no_NO</td>
    --</tr>
    --<tr>
    --<td>English</td>
    --<td>en_US</td>
    --<td>Polish</td>
    --<td>pl_PL</td>
    --</tr>
    --<tr>
    --<td>French</td>
    --<td>fr_FR</td>
    --<td>Portuguese</td>
    --<td>pt_PT</td>
    --</tr>
    --<tr>
    --<td>Finnish</td>
    --<td>fi_FI</td>
    --<td>Russian</td>
    --<td>ru_RU</td>
    --</tr>
    --<tr>
    --<td>German</td>
    --<td>de_DE</td>
    --<td>Spanish</td>
    --<td>es_ES</td>
    --</tr>
    --<tr>
    --<td>Hebrew</td>
    --<td>iw_IL</td>
    --<td>Swedish</td>
    --<td>sv_SE</td>
    --</tr>
    --<tr>
    --<td>Hindi</td>
    --<td>hi_IN</td>
    --<td>--</td>
    --<td>--</td>
    --</tr>
    --</table>
    --
    - <h2 id="pricing-template">
    -   Pricing Templates
    - </h2>
    -@@ -432,8 +609,12 @@ with the <em>locale</em> field.</p>
    - 
    - <p>
    -   When creating a pricing template, you provide new pricing information that you
    --  can apply to paid apps and in-app products. To add a pricing template, do the
    --  following:
    -+  can apply to paid apps and in-app products. You can link the prices of up to
    -+  100 apps and in-app products to a single pricing template.
    -+</p>
    -+
    -+<p>
    -+  To add a pricing template, do the following:
    - </p>
    - 
    - <ol>
    -@@ -442,14 +623,14 @@ with the <em>locale</em> field.</p>
    -     account.
    -   </li>
    - 
    --  <li>In the <strong>Settings</strong> panel, open the <strong>Pricing
    --  template</strong> page.
    -+  <li>In the <em>Settings</em> panel, open the <em>Pricing
    -+  template</em> page.
    -   </li>
    - 
    -   <li>
    -     <p>
    --      If you are adding your first pricing template, the <strong>Add a Pricing
    --      Template</strong> banner appears. Select <strong>Add template</strong> to
    -+      If you are adding your first pricing template, the <em>Add a Pricing
    -+      Template</em> banner appears. Select <strong>Add template</strong> to
    -       create a new template. The new template's <em>Pricing</em> tab appears.
    -     </p>
    - 
    -@@ -510,8 +691,8 @@ with the <em>locale</em> field.</p>
    -     account.
    -   </li>
    - 
    --  <li>In the <strong>Settings</strong> panel, open the <strong>Pricing
    --  template</strong> page. This page shows the list of pricing templates you have
    -+  <li>In the <em>Settings</em> panel, open the <em>Pricing
    -+  template</em> page. This page shows the list of pricing templates you have
    -   created for your account.
    -   </li>
    - 
    -@@ -571,8 +752,8 @@ with the <em>locale</em> field.</p>
    -     account.
    -   </li>
    - 
    --  <li>In the <strong>All applications</strong> panel, select the app name, then
    --  open the <strong>In-app Products</strong> page.
    -+  <li>In the <em>All applications</em> panel, select the app name, then
    -+  open the <em>In-app Products</em> page.
    -   </li>
    - 
    -   <li>Choose the in-app product that you want to link to a pricing template.
    -@@ -591,7 +772,7 @@ with the <em>locale</em> field.</p>
    - 
    - <p>
    -   To link the price of a paid app to a pricing template, you follow a similar
    --  process on the app's <strong>Pricing &amp; Distribution</strong> page.
    -+  process on the app's <em>Pricing &amp; Distribution</em> page.
    - </p>
    - 
    - <h3 id="delete-linked-item">
    -@@ -623,7 +804,7 @@ with the <em>locale</em> field.</p>
    -   <li>Select the app that contains the in-app product you want to delete.
    -   </li>
    - 
    --  <li>Open the app's <strong>In-app Products</strong> page.
    -+  <li>Open the app's <em>In-app Products</em> page.
    -   </li>
    - 
    -   <li>Choose the in-app product that you want to delete.
    -@@ -697,8 +878,8 @@ with the <em>locale</em> field.</p>
    -     account.
    -   </li>
    - 
    --  <li>In the <strong>Settings</strong> panel, open the <strong>Pricing
    --  template</strong> page, which shows the list of pricing templates you have
    -+  <li>In the <em>Settings</em> panel, open the <em>Pricing
    -+  template</em> page, which shows the list of pricing templates you have
    -   created for your account.
    -   </li>
    - 
    -@@ -712,15 +893,15 @@ with the <em>locale</em> field.</p>
    -   </li>
    - </ol>
    - 
    --<h2 id="billing-purchase-type">Choosing a Product Type</h3>
    -+<h2 id="billing-purchase-type">Choosing a Product Type</h2>
    - 
    - <p>An item's product type controls how Google Play manages the purchase of the item. The supported
    - product types include "managed product" and "subscription." Since support for different product
    - types can vary among versions of the In-app Billing API, make sure that you choose a product
    --type that's valid for the version of the In-app Billing API that your app uses. </p>
    -+type that's valid for the version of the In-app Billing API that your app uses.</p>
    - 
    - <p>For details, refer to the documentation for the <a
    --href="{@docRoot}google/play/billing/api.html#producttype">In-app Billing API</a>.
    -+href="{@docRoot}google/play/billing/api.html#producttype">In-app Billing API</a>.</p>
    - 
    - <h2 id="billing-refunds">Handling Refunds</h2>
    - 
    -@@ -748,9 +929,10 @@ you at the conclusion of the purchase flow, as the value of the
    - intent.</p>
    - 
    - <p class="note">
    --  <strong>Note:</strong> Test purchases don't have an <code>orderId</code>
    --  field. To track test transactions, you use the <code>purchaseToken</code>
    --  field instead. For more information about working with test purchases, see <a
    -+  <strong>Note:</strong> When a user completes a test purchase, the
    -+  <code>orderId</code> field remains blank. To track test transactions, use
    -+  the <code>purchaseToken</code> field instead. For more information about
    -+  working with test purchases, see <a
    -   href="{@docRoot}google/play/billing/billing_testing.html">Testing In-app
    -   Billing</a>.
    - </p>
    -@@ -765,14 +947,14 @@ assigned and managed by Google.</p>
    - 
    - <p>For transactions dated 5 December 2012 or later, Google payments assigns a
    - Merchant Order Number (rather than a Google Order Number) and reports the Merchant
    --Order Number as the value of <code>orderId</code>. Here's an
    -+Order Number as the value of <code>orderID</code>. Here's an
    - example:</p>
    - 
    - <pre>"orderId" : "GPA.1234-5678-9012-34567"</pre>
    - 
    - <p>For transactions dated previous to 5 December 2012, Google checkout assigned
    - a Google Order Number and reported that number as the value of
    --<code>orderId</code>. Here's an example of an <code>orderId</code> holding a
    -+<code>orderID</code>. Here's an example of an <code>orderID</code> holding a
    - Google Order Number:</p>
    - 
    - <pre>"orderId" : "556515565155651"</pre>
    -@@ -819,8 +1001,8 @@ app.</p>
    - 
    - <p>To locate the key for an app, follow these steps:</p>
    - <ol>
    --  <li>Open the <strong>All applications</strong> panel.</li>
    --  <li>Click on the app name, then open the <strong>Services &amp; APIs</strong>
    -+  <li>Open the <em>All applications</em> panel.</li>
    -+  <li>Click on the app name, then open the <em>Services &amp; APIs</em>
    -   page.</li>
    -   <li>Scroll down to the section of the page labeled Your License Key for This
    -   Application, as shown in figure 5.</li>
    -@@ -835,7 +1017,7 @@ for apps that depend on the (former) developer key. </p>
    -   width="700" alt="">
    -   <figcaption>
    -     <b>Figure 5. </b>You can find the license key for each app on the
    --    <strong>Services &amp; APIs</strong> page.
    -+    <em>Services &amp; APIs</em> page.
    -   </figcaption>
    - </figure>
    - 
    -diff --git a/docs/html/google/play/billing/billing_integrate.jd b/docs/html/google/play/billing/billing_integrate.jd
    -index 5d6b3a8..506a440 100755
    ---- a/docs/html/google/play/billing/billing_integrate.jd
    -+++ b/docs/html/google/play/billing/billing_integrate.jd
    -@@ -9,18 +9,18 @@ page.tags="inapp, billing, iap"
    -   <h2>In this document</h2>
    -   <ol>
    -     <li><a href="#billing-add-aidl">Adding the AIDL file</a></li>
    --    <li><a href="#billing-permission">Updating Your Manifest</a></li>
    -+    <li><a href="#billing-permission">Updating your manifest</a></li>
    -     <li><a href="#billing-service">Creating a ServiceConnection</a></li>
    --    <li><a href="#billing-requests">Making In-app Billing Requests</a>
    -+    <li><a href="#billing-requests">Making In-app Billing requests</a>
    -        <ol>
    --       <li><a href="#QueryDetails">Querying Items Available for Purchase</a><li>
    --       <li><a href="#Purchase">Purchasing an Item</a></li>
    --       <li><a href="#QueryPurchases">Querying Purchased Items</a></li>
    --       <li><a href="#Consume">Consuming a Purchase</a></li>
    --       <li><a href="#Subs">Implementing Subscriptions</a></li>
    -+       <li><a href="#QueryDetails">Querying items available for purchase</a><li>
    -+       <li><a href="#Purchase">Purchasing an item</a></li>
    -+       <li><a href="#QueryPurchases">Querying purchased items</a></li>
    -+       <li><a href="#Consume">Consuming a purchase</a></li>
    -+       <li><a href="#Subs">Implementing subscriptions</a></li>
    -        </ol>
    -     </li>
    --    <li><a href="#billing-security">Securing Your App</a>
    -+    <li><a href="#billing-security">Securing your app</a>
    -   </ol>
    -   <h2>Reference</h2>
    -   <ol>
    -@@ -42,7 +42,7 @@ page.tags="inapp, billing, iap"
    -   In-app Billing on Google Play provides a straightforward, simple interface
    -   for sending In-app Billing requests and managing In-app Billing transactions
    -   using Google Play. The information below covers the basics of how to make
    --  calls from your application to the In-app Billing service using the Version 3
    -+  calls from your application to the In-app Billing service using the In-app Billing Version 3
    -   API.
    - </p>
    - 
    -@@ -51,26 +51,25 @@ page.tags="inapp, billing, iap"
    -   your application, see the <a href=
    -   "{@docRoot}training/in-app-billing/index.html">Selling In-app Products</a>
    -   training class. The training class provides a complete sample In-app Billing
    --  application, including convenience classes to handle key tasks related to
    --  setting up your connection, sending billing requests and processing responses
    -+  application, including convenience classes to handle key tasks that are related to
    -+  setting up your connection, sending billing requests, processing responses
    -   from Google Play, and managing background threading so that you can make
    -   In-app Billing calls from your main activity.
    - </p>
    - 
    - <p>
    --  Before you start, be sure that you read the <a href=
    -+  Before you start, read the <a href=
    -   "{@docRoot}google/play/billing/billing_overview.html">In-app Billing
    --  Overview</a> to familiarize yourself with concepts that will make it easier
    -+  Overview</a> to familiarize yourself with concepts that make it easier
    -   for you to implement In-app Billing.
    - </p>
    - 
    --<p>To implement In-app Billing in your application, you need to do the
    --following:</p>
    -+<p>Complete these steps to implement In-app Billing in your application:</p>
    - 
    - <ol>
    -   <li>Add the In-app Billing library to your project.</li>
    -   <li>Update your {@code AndroidManifest.xml} file.</li>
    --  <li>Create a {@code ServiceConnection} and bind it to
    -+  <li>Create a {@code ServiceConnection} and bind it to the
    - {@code IInAppBillingService}.</li>
    -   <li>Send In-app Billing requests from your application to
    - {@code IInAppBillingService}.</li>
    -@@ -79,55 +78,56 @@ following:</p>
    - 
    - <h2 id="billing-add-aidl">Adding the AIDL file to your project</h2>
    - 
    --<p>{@code IInAppBillingService.aidl} is an Android Interface Definition
    -+<p>The {@code IInAppBillingService.aidl} is an Android Interface Definition
    - Language (AIDL) file that defines the interface to the In-app Billing Version
    --3 service. You will use this interface to make billing requests by invoking IPC
    -+3 service. You can use this interface to make billing requests by invoking IPC
    - method calls.</p>
    --<p>To get the AIDL file:</p>
    -+
    -+<p>Complete these steps to get the AIDL file:</p>
    - <ol>
    - <li>Open the <a href="{@docRoot}tools/help/sdk-manager.html">Android SDK Manager</a>.</li>
    - <li>In the SDK Manager, expand the {@code Extras} section.</li>
    - <li>Select <strong>Google Play Billing Library</strong>.</li>
    - <li>Click <strong>Install packages</strong> to complete the download.</li>
    - </ol>
    --<p>The {@code IInAppBillingService.aidl} file will be installed to {@code <sdk>/extras/google/play_billing/}.</p>
    -+<p>The {@code IInAppBillingService.aidl} file will be installed to {@code &lt;sdk&gt;/extras/google/play_billing/}.</p>
    - 
    --<p>To add the AIDL to your project:</p>
    -+<p>Complete these steps to add the AIDL to your project:</p>
    - 
    - <ol>
    --  <li>First, download the Google Play Billing Library to your Android project:
    -+  <li>Download the Google Play Billing Library to your Android project:
    -       <ol type="a">
    -       <li>Select <strong>Tools > Android > SDK Manager</strong>.</li>
    -       <li>Under <strong>Appearance & Behavior > System Settings > Android SDK</strong>,
    -           select the <em>SDK Tools</em> tab to select and download <em>Google Play Billing
    -           Library</em>.</li></ol>
    - 
    --  <li>Next, copy the {@code IInAppBillingService.aidl} file to your project.
    -+  <li>Copy the {@code IInAppBillingService.aidl} file to your project.
    -     <ul>
    --      <li>If you are using Android Studio:
    -+      <li>If you are using Android Studio, complete these steps to copy the file:
    -         <ol type="a">
    -           <li>Navigate to {@code src/main} in the Project tool window.</li>
    - 
    --          <li>Select <strong>File > New > Directory</strong> and enter {@code aidl} in the
    --          <em>New Directory</em> window, then select <strong>OK</strong>.
    -+          <li>Select <strong>File > New > Directory</strong>, enter {@code aidl} in the
    -+          <em>New Directory</em> window, and select <strong>OK</strong>.
    - 
    --          <li>Select <strong>File > New > Package</strong> and enter
    --          {@code com.android.vending.billing} in the <em>New Package</em> window, then select
    -+          <li>Select <strong>File > New > Package</strong>, enter
    -+          {@code com.android.vending.billing} in the <em>New Package</em> window, and select
    -           <strong>OK</strong>.</li>
    - 
    -           <li>Using your operating system file explorer, navigate to
    --          {@code <sdk>/extras/google/play_billing/}, copy the
    -+          {@code &lt;sdk&gt;/extras/google/play_billing/}, copy the
    -           {@code IInAppBillingService.aidl} file, and paste it into the
    -           {@code com.android.vending.billing} package in your project.
    -           </li>
    -         </ol>
    -       </li>
    - 
    --      <li>If you are developing in a non-Android Studio environment: Create the
    --      following directory {@code /src/com/android/vending/billing} and copy the
    --      {@code IInAppBillingService.aidl} file into this directory. Put the AIDL
    --      file into your project and use the Gradle tool to build your project so that
    --      the <code>IInAppBillingService.java</code> file gets generated.
    -+      <li>If you are developing in a non-Android Studio environment, create the
    -+      following directory: {@code /src/com/android/vending/billing}. Copy the
    -+      {@code IInAppBillingService.aidl} file into this directory. Place the AIDL
    -+      file in your project and use the Gradle tool to build your project so that
    -+      the <code>IInAppBillingService.java</code> file is generated.
    -       </li>
    -     </ul>
    -   </li>
    -@@ -137,16 +137,16 @@ method calls.</p>
    -   </li>
    - </ol>
    - 
    --<h2 id="billing-permission">Updating Your App's Manifest</h2>
    -+<h2 id="billing-permission">Updating your app's manifest</h2>
    - 
    - <p>
    -   In-app billing relies on the Google Play application, which handles all
    --  communication between your application and the Google Play server. To use the
    -+  of the communication between your application and the Google Play server. To use the
    -   Google Play application, your application must request the proper permission.
    -   You can do this by adding the {@code com.android.vending.BILLING} permission
    -   to your AndroidManifest.xml file. If your application does not declare the
    -   In-app Billing permission, but attempts to send billing requests, Google Play
    --  will refuse the requests and respond with an error.
    -+  refuses the requests and responds with an error.
    - </p>
    - 
    - <p>
    -@@ -182,7 +182,7 @@ method calls.</p>
    -   onServiceDisconnected} and {@link
    -   android.content.ServiceConnection#onServiceConnected onServiceConnected}
    -   methods to get a reference to the {@code IInAppBillingService} instance after
    --  a connection has been established.
    -+  a connection is established.
    - </p>
    - 
    - <pre>
    -@@ -208,20 +208,25 @@ ServiceConnection mServiceConn = new ServiceConnection() {
    -   bindService} method. Pass the method an {@link android.content.Intent} that
    -   references the In-app Billing service and an instance of the {@link
    -   android.content.ServiceConnection} that you created, and explicitly set the
    --  Intent's target package name to <code>com.android.vending</code> — the
    -+  Intent's target package name to <code>com.android.vending</code>&mdash;the
    -   package name of Google Play app.
    - </p>
    - 
    - <p class="caution">
    -   <strong>Caution:</strong> To protect the security of billing transactions,
    --  always make sure to explicitly set the intent's target package name to
    -+  always explicitly set the intent's target package name to
    -   <code>com.android.vending</code>, using {@link
    --  android.content.Intent#setPackage(java.lang.String) setPackage()} as shown in
    --  the example below. Setting the package name explicitly ensures that
    -+  android.content.Intent#setPackage(java.lang.String) setPackage()}.
    -+  Setting the package name explicitly ensures that
    -   <em>only</em> the Google Play app can handle billing requests from your app,
    -   preventing other apps from intercepting those requests.
    - </p>
    - 
    -+<p>
    -+  The following code sample demonstrates how to set the intent's target package
    -+  to protect the security of transactions:
    -+</p>
    -+
    - <pre>&#64;Override
    - public void onCreate(Bundle savedInstanceState) {
    -   super.onCreate(savedInstanceState);
    -@@ -233,6 +238,13 @@ public void onCreate(Bundle savedInstanceState) {
    - }
    - </pre>
    - 
    -+<p class="caution"><strong>Caution</strong>: To ensure that your app is secure, always use an
    -+explicit intent when starting a {@link android.app.Service} and do not declare intent filters for
    -+your services. Using an implicit intent to start a service is a security hazard because you cannot
    -+be certain of the service that will respond to the intent, and the user cannot see which service
    -+starts. Beginning with Android 5.0 (API level 21), the system throws an exception if you call
    -+{@link android.content.Context#bindService bindService()} with an implicit intent.</p>
    -+
    - <p>
    -   You can now use the mService reference to communicate with the Google Play
    -   service.
    -@@ -242,10 +254,14 @@ public void onCreate(Bundle savedInstanceState) {
    -   <strong>Important:</strong> Remember to unbind from the In-app Billing
    -   service when you are done with your {@link android.app.Activity}. If you
    -   don’t unbind, the open service connection could cause your device’s
    --  performance to degrade. This example shows how to perform the unbind
    -+  performance to degrade.
    -+</p>
    -+
    -+<p>
    -+  This example shows how to perform the unbind
    -   operation on a service connection to In-app Billing called {@code
    -   mServiceConn} by overriding the activity’s {@link
    --  android.app.Activity#onDestroy onDestroy} method.
    -+  android.app.Activity#onDestroy onDestroy} method:
    - </p>
    - 
    - <pre>
    -@@ -264,29 +280,29 @@ public void onDestroy() {
    -   "{@docRoot}training/in-app-billing/preparing-iab-app.html">Selling In-app
    -   Products</a> training class and associated sample.
    - </p>
    --<h2 id="billing-requests">Making In-app Billing Requests</h2>
    -+<h2 id="billing-requests">Making In-app Billing requests</h2>
    - <p>
    --  Once your application is connected to Google Play, you can initiate purchase
    -+  After your application is connected to Google Play, you can initiate purchase
    -   requests for in-app products. Google Play provides a checkout interface for
    --  users to enter their payment method, so your application does not need to
    -+  users to enter their payment method, so your application doesn't need to
    -   handle payment transactions directly. When an item is purchased, Google Play
    -   recognizes that the user has ownership of that item and prevents the user
    -   from purchasing another item with the same product ID until it is consumed.
    --  You can control how the item is consumed in your application, and notify
    -+  You can control how the item is consumed in your application and notify
    -   Google Play to make the item available for purchase again. You can also query
    --  Google Play to quickly retrieve the list of purchases that were made by the
    --  user. This is useful, for example, when you want to restore the user's
    -+  Google Play to quickly retrieve the list of purchases that the
    -+  user made. This is useful, for example, when you want to restore the user's
    -   purchases when your user launches your app.
    - </p>
    - 
    --<h3 id="QueryDetails">Querying for Items Available for Purchase</h3>
    -+<h3 id="QueryDetails">Querying for items available for purchase</h3>
    - 
    - <p>
    -   In your application, you can query the item details from Google Play using
    -   the In-app Billing Version 3 API. To pass a request to the In-app Billing
    --  service, first create a {@link android.os.Bundle} that contains a String
    -+  service, create a {@link android.os.Bundle} that contains a String
    -   {@link java.util.ArrayList} of product IDs with key "ITEM_ID_LIST", where
    --  each string is a product ID for an purchasable item.
    -+  each string is a product ID for an purchasable item. Here is an example:
    - </p>
    - 
    - <pre>
    -@@ -299,9 +315,9 @@ querySkus.putStringArrayList(“ITEM_ID_LIST”, skuList);
    - 
    - <p>
    -   To retrieve this information from Google Play, call the {@code getSkuDetails}
    --  method on the In-app Billing Version 3 API, and pass the method the In-app
    -+  method on the In-app Billing Version 3 API and pass the In-app
    -   Billing API version (“3”), the package name of your calling app, the purchase
    --  type (“inapp”), and the {@link android.os.Bundle} that you created.
    -+  type (“inapp”), and the {@link android.os.Bundle} that you created, into the method:
    - </p>
    - 
    - <pre>
    -@@ -310,35 +326,35 @@ Bundle skuDetails = mService.getSkuDetails(3,
    - </pre>
    - 
    - <p>
    --  If the request is successful, the returned {@link android.os.Bundle}has a
    -+  If the request is successful, the returned {@link android.os.Bundle} has a
    -   response code of {@code BILLING_RESPONSE_RESULT_OK} (0).
    - </p>
    - 
    - <p class="note">
    --  <strong>Warning:</strong> Do not call the {@code getSkuDetails} method on the
    --  main thread. Calling this method triggers a network request which could block
    -+  <strong>Warning:</strong> Don't call the {@code getSkuDetails} method on the
    -+  main thread. Calling this method triggers a network request that could block
    -   your main thread. Instead, create a separate thread and call the {@code
    --  getSkuDetails} method from inside that thread.
    -+  getSkuDetails} method from inside of that thread.
    - </p>
    - 
    - <p>
    --  To see all the possible response codes from Google Play, see <a href=
    -+  To view all of the possible response codes from Google Play, see <a href=
    -   "{@docRoot}google/play/billing/billing_reference.html#billing-codes">In-app
    -   Billing Reference</a>.
    - </p>
    - 
    - <p>
    -   The query results are stored in a String ArrayList with key {@code
    --  DETAILS_LIST}. The purchase information is stored in the String in JSON
    --  format. To see the types of product detail information that are returned, see
    -+  DETAILS_LIST}. The purchase information is stored within the String in JSON
    -+  format. To view the types of product detail information that are returned, see
    -   <a href=
    -   "{@docRoot}google/play/billing/billing_reference.html#getSkuDetails">In-app
    -   Billing Reference</a>.
    - </p>
    - 
    - <p>
    --  In this example, you are retrieving the prices for your in-app items from the
    --  skuDetails {@link android.os.Bundle} returned from the previous code snippet.
    -+  In this example shows how to retrieve the prices for your in-app items from the
    -+  skuDetails {@link android.os.Bundle} that is returned from the previous code snippet:
    - </p>
    - 
    - <pre>
    -@@ -357,15 +373,15 @@ if (response == 0) {
    - }
    - </pre>
    - 
    --<h3 id="Purchase">Purchasing an Item</h3>
    -+<h3 id="Purchase">Purchasing an item</h3>
    - <p>
    -   To start a purchase request from your app, call the {@code getBuyIntent}
    --  method on the In-app Billing service. Pass in to the method the In-app
    -+  method on the In-app Billing service. Pass the In-app
    -   Billing API version (“3”), the package name of your calling app, the product
    -   ID for the item to purchase, the purchase type (“inapp” or "subs"), and a
    --  {@code developerPayload} String. The {@code developerPayload} String is used
    -+  {@code developerPayload} String into the method. The {@code developerPayload} String is used
    -   to specify any additional arguments that you want Google Play to send back
    --  along with the purchase information.
    -+  along with the purchase information. Here is an example:
    - </p>
    - 
    - <pre>
    -@@ -377,10 +393,13 @@ Bundle buyIntentBundle = mService.getBuyIntent(3, getPackageName(),
    -   If the request is successful, the returned {@link android.os.Bundle} has a
    -   response code of {@code BILLING_RESPONSE_RESULT_OK} (0) and a {@link
    -   android.app.PendingIntent} that you can use to start the purchase flow. To
    --  see all the possible response codes from Google Play, see <a href=
    -+  view all of the possible response codes from Google Play, see <a href=
    -   "{@docRoot}google/play/billing/billing_reference.html#billing-codes">In-app
    --  Billing Reference</a>. Next, extract a {@link android.app.PendingIntent} from
    --  the response {@link android.os.Bundle} with key {@code BUY_INTENT}.
    -+  Billing Reference</a>.
    -+
    -+<p>
    -+  The next step is to extract a {@link android.app.PendingIntent} from
    -+  the response {@link android.os.Bundle} with key {@code BUY_INTENT}, as shown here:
    - </p>
    - 
    - <pre>
    -@@ -390,8 +409,8 @@ PendingIntent pendingIntent = buyIntentBundle.getParcelable("BUY_INTENT");
    - <p>
    -   To complete the purchase transaction, call the {@link
    -   android.app.Activity#startIntentSenderForResult startIntentSenderForResult}
    --  method and use the {@link android.app.PendingIntent} that you created. In
    --  this example, you are using an arbitrary value of 1001 for the request code.
    -+  method and use the {@link android.app.PendingIntent} that you created. This
    -+  example uses an arbitrary value of 1001 for the request code:
    - </p>
    - 
    - <pre>
    -@@ -404,9 +423,9 @@ startIntentSenderForResult(pendingIntent.getIntentSender(),
    -   Google Play sends a response to your {@link android.app.PendingIntent} to the
    -   {@link android.app.Activity#onActivityResult onActivityResult} method of your
    -   application. The {@link android.app.Activity#onActivityResult
    --  onActivityResult} method will have a result code of {@code
    --  Activity.RESULT_OK} (1) or {@code Activity.RESULT_CANCELED} (0). To see the
    --  types of order information that is returned in the response {@link
    -+  onActivityResult} method has a result code of {@code
    -+  Activity.RESULT_OK} (1) or {@code Activity.RESULT_CANCELED} (0). To view the
    -+  types of order information that are returned in the response {@link
    -   android.content.Intent}, see <a href=
    -   "{@docRoot}google/play/billing/billing_reference.html#getBuyIntent">In-app
    -   Billing Reference</a>.
    -@@ -415,7 +434,7 @@ startIntentSenderForResult(pendingIntent.getIntentSender(),
    - <p>
    -   The purchase data for the order is a String in JSON format that is mapped to
    -   the {@code INAPP_PURCHASE_DATA} key in the response {@link
    --  android.content.Intent}, for example:
    -+  android.content.Intent}. Here is an example:
    - </p>
    - 
    - <pre>
    -@@ -436,13 +455,13 @@ startIntentSenderForResult(pendingIntent.getIntentSender(),
    -   long. Pass this entire token to other methods, such as when you consume the
    -   purchase, as described in <a href=
    -   "{@docRoot}training/in-app-billing/purchase-iab-products.html#Consume">Consume
    --  a Purchase</a>. Do not abbreviate or truncate this token; you must save and
    -+  a Purchase</a>. Don't abbreviate or truncate this token; you must save and
    -   return the entire token.
    - </p>
    - 
    - <p>
    --  Continuing from the previous example, you get the response code, purchase
    --  data, and signature from the response {@link android.content.Intent}.
    -+  Continuing from the previous example, you receive the response code, purchase
    -+  data, and signature from the response {@link android.content.Intent}:
    - </p>
    - 
    - <pre>
    -@@ -472,23 +491,23 @@ protected void onActivityResult(int requestCode, int resultCode, Intent data) {
    - <p class="note">
    -   <strong>Security Recommendation:</strong> When you send a purchase request,
    -   create a String token that uniquely identifies this purchase request and
    --  include this token in the {@code developerPayload}.You can use a randomly
    --  generated string as the token. When you receive the purchase response from
    --  Google Play, make sure to check the returned data signature, the {@code
    -+  include this token in the {@code developerPayload}. You can use a randomly-generated
    -+  string as the token. When you receive the purchase response from
    -+  Google Play, ensure that you check the returned data signature, the {@code
    -   orderId}, and the {@code developerPayload} String. For added security, you
    --  should perform the checking on your own secure server. Make sure to verify
    -+  should perform the checking on your own secure server. Verify
    -   that the {@code orderId} is a unique value that you have not previously
    --  processed, and the {@code developerPayload} String matches the token that you
    -+  processed and that the {@code developerPayload} String matches the token that you
    -   sent previously with the purchase request.
    - </p>
    - 
    --<h3 id="QueryPurchases">Querying for Purchased Items</h3>
    -+<h3 id="QueryPurchases">Querying for purchased items</h3>
    - 
    - <p>
    --  To retrieve information about purchases made by a user from your app, call
    -+  To retrieve information about purchases that are made by a user from your app, call
    -   the {@code getPurchases} method on the In-app Billing Version 3 service. Pass
    --  in to the method the In-app Billing API version (“3”), the package name of
    --  your calling app, and the purchase type (“inapp” or "subs").
    -+  the In-app Billing API version (“3”), the package name of
    -+  your calling app, and the purchase type (“inapp” or "subs") into the method. Here is an example:
    - </p>
    - 
    - <pre>
    -@@ -507,18 +526,18 @@ Bundle ownedItems = mService.getPurchases(3, getPackageName(), "inapp", null);
    -   To improve performance, the In-app Billing service returns only up to 700
    -   products that are owned by the user when {@code getPurchase} is first called.
    -   If the user owns a large number of products, Google Play includes a String
    --  token mapped to the key {@code INAPP_CONTINUATION_TOKEN} in the response
    -+  token that is mapped to the key {@code INAPP_CONTINUATION_TOKEN} in the response
    -   {@link android.os.Bundle} to indicate that more products can be retrieved.
    --  Your application can then make a subsequent {@code getPurchases} call, and
    -+  Your application can then make a subsequent {@code getPurchases} call and
    -   pass in this token as an argument. Google Play continues to return a
    -   continuation token in the response {@link android.os.Bundle} until all
    --  products that are owned by the user has been sent to your app.
    -+  of the products that are owned by the user are sent to your app.
    - </p>
    - 
    --<p>For more information about the data returned by {@code getPurchases}, see
    -+<p>For more information about the data that is returned by {@code getPurchases}, see
    -   <a href="{@docRoot}google/play/billing/billing_reference.html#getPurchases">
    -   In-app Billing Reference</a>. The following example shows how you can
    --  retrieve this data from the response.
    -+  retrieve this data from the response:
    - </p>
    - 
    - <pre>
    -@@ -548,26 +567,26 @@ if (response == 0) {
    - </pre>
    - 
    - 
    --<h3 id="Consume">Consuming a Purchase</h3>
    -+<h3 id="Consume">Consuming a purchase</h3>
    - 
    - <p>
    -   You can use the In-app Billing Version 3 API to track the ownership of
    -   purchased in-app products in Google Play. Once an in-app product is
    --  purchased, it is considered to be "owned" and cannot be purchased from Google
    -+  purchased, it is considered to be <em>owned</em> and cannot be purchased from Google
    -   Play. You must send a consumption request for the in-app product before
    -   Google Play makes it available for purchase again.
    - </p>
    - 
    --<p class="caution">
    -+<p class="note">
    -   <strong>Important</strong>: Managed in-app products are consumable, but
    -   subscriptions are not.
    - </p>
    - 
    - <p>
    --  How you use the consumption mechanism in your app is up to you. Typically,
    --  you would implement consumption for in-app products with temporary benefits
    -+  The way that you use the consumption mechanism in your app is up to you. Typically,
    -+  you implement consumption for in-app products with temporary benefits
    -   that users may want to purchase multiple times (for example, in-game currency
    --  or equipment). You would typically not want to implement consumption for
    -+  or equipment). You typically don't want to implement consumption for
    -   in-app products that are purchased once and provide a permanent effect (for
    -   example, a premium upgrade).
    - </p>
    -@@ -576,21 +595,21 @@ if (response == 0) {
    -   To record a purchase consumption, send the {@code consumePurchase} method to
    -   the In-app Billing service and pass in the {@code purchaseToken} String value
    -   that identifies the purchase to be removed. The {@code purchaseToken} is part
    --  of the data returned in the {@code INAPP_PURCHASE_DATA} String by the Google
    --  Play service following a successful purchase request. In this example, you
    --  are recording the consumption of a product that is identified with the {@code
    --  purchaseToken} in the {@code token} variable.
    -+  of the data that is returned in the {@code INAPP_PURCHASE_DATA} String by the Google
    -+  Play service following a successful purchase request. This example
    -+  records the consumption of a product that is identified with the {@code
    -+  purchaseToken} in the {@code token} variable:
    - </p>
    - 
    - <pre>
    - int response = mService.consumePurchase(3, getPackageName(), token);
    - </pre>
    - 
    --<p class="note">
    --  <strong>Warning:</strong> Do not call the {@code consumePurchase} method on
    --  the main thread. Calling this method triggers a network request which could
    -+<p class="caution">
    -+  <strong>Warning:</strong> Don't call the {@code consumePurchase} method on
    -+  the main thread. Calling this method triggers a network request that could
    -   block your main thread. Instead, create a separate thread and call the {@code
    --  consumePurchase} method from inside that thread.
    -+  consumePurchase} method from inside of that thread.
    - </p>
    - 
    - <p>
    -@@ -600,20 +619,20 @@ int response = mService.consumePurchase(3, getPackageName(), token);
    -   purchased.
    - </p>
    - 
    --<p class="note">
    --  <strong>Security Recommendation:</strong> You must send a consumption request
    -+<p class="caution">
    -+  <strong>Security Recommendation:</strong> Send a consumption request
    -   before provisioning the benefit of the consumable in-app purchase to the
    --  user. Make sure that you have received a successful consumption response from
    -+  user. Ensure that you receive a successful consumption response from
    -   Google Play before you provision the item.
    - </p>
    - 
    --<h3 id="Subs">Implementing Subscriptions</h3>
    -+<h3 id="Subs">Implementing subscriptions</h3>
    - 
    - <p>Launching a purchase flow for a subscription is similar to launching the
    - purchase flow for a product, with the exception that the product type must be set
    - to "subs". The purchase result is delivered to your Activity's
    - {@link android.app.Activity#onActivityResult onActivityResult} method, exactly
    --as in the case of in-app products.</p>
    -+as in the case of in-app products. Here is an example:</p>
    - 
    - <pre>
    - Bundle bundle = mService.getBuyIntent(3, "com.example.myapp",
    -@@ -629,18 +648,18 @@ if (bundle.getInt(RESPONSE_CODE) == BILLING_RESPONSE_RESULT_OK) {
    - </pre>
    - 
    - <p>To query for active subscriptions, use the {@code getPurchases} method, again
    --with the product type parameter set to "subs".</p>
    -+with the product type parameter set to "subs":</p>
    - 
    - <pre>
    - Bundle activeSubs = mService.getPurchases(3, "com.example.myapp",
    -                    "subs", continueToken);
    - </pre>
    - 
    --<p>The call returns a {@code Bundle} with all the active subscriptions owned by
    --the user. Once a subscription expires without renewal, it will no longer appear
    -+<p>The call returns a {@code Bundle} with all of the active subscriptions that are owned by
    -+the user. When a subscription expires without renewal, it no longer appears
    - in the returned {@code Bundle}.</p>
    - 
    --<h2 id="billing-security">Securing Your Application</h2>
    -+<h2 id="billing-security">Securing your application</h2>
    - 
    - <p>To help ensure the integrity of the transaction information that is sent to
    - your application, Google Play signs the JSON string that contains the response
    -@@ -648,21 +667,21 @@ data for a purchase order. Google Play uses the private key that is associated
    - with your application in the Developer Console to create this signature. The
    - Developer Console generates an RSA key pair for each application.<p>
    - 
    --<p class="note"><strong>Note:</strong>To find the public key portion of this key
    --pair, open your application's details in the Developer Console, then click on
    --<strong>Services &amp; APIs</strong>, and look at the field titled
    -+<p class="note"><strong>Note:</strong> To find the public key portion of this key
    -+pair, open your application's details in the Developer Console, click
    -+<strong>Services &amp; APIs</strong>, and review the field titled
    - <strong>Your License Key for This Application</strong>.</p>
    - 
    --<p>The Base64-encoded RSA public key generated by Google Play is in binary
    -+<p>The Base64-encoded RSA public key that is generated by Google Play is in binary
    - encoded, X.509 subjectPublicKeyInfo DER SEQUENCE format. It is the same public
    - key that is used with Google Play licensing.</p>
    - 
    --<p>When your application receives this signed response you can
    -+<p>When your application receives this signed response, you can
    - use the public key portion of your RSA key pair to verify the signature.
    --By performing signature verification you can detect responses that have
    -+By performing signature verification, you can detect any responses that have
    - been tampered with or that have been spoofed. You can perform this signature
    - verification step in your application; however, if your application connects
    --to a secure remote server then we recommend that you perform the signature
    -+to a secure remote server, Google recommends that you perform the signature
    - verification on that server.</p>
    - 
    - <p>For more information about best practices for security and design, see <a
    -diff --git a/docs/html/google/play/filters.jd b/docs/html/google/play/filters.jd
    -index 50cc807..a73b17f 100644
    ---- a/docs/html/google/play/filters.jd
    -+++ b/docs/html/google/play/filters.jd
    -@@ -382,9 +382,12 @@ characteristics that affect filtering on Google Play.</p>
    -   suspended, users will not be able to reinstall or update it, even if it appears in their Downloads.</p> </td></tr>
    -   <tr>
    -   <td valign="top">Priced
    --    Status</td> <td valign="top"><p>Not all users can see paid apps. To show paid apps, a device
    --must have a SIM card and be running Android 1.1 or later, and it must be in a
    --country (as determined by SIM carrier) in which paid apps are available.</p></td>
    -+    Status</td> <td valign="top"><p>Not all users can see paid apps. To show
    -+    paid apps, a device must be running Android 1.1 or later, and it must be in
    -+    a country where paid apps are available. If a device has a SIM card, the SIM
    -+    carrier determines whether paid apps are available. If a device doesn't have
    -+    a SIM card, the device's IP address is used to determine whether the device
    -+    is in a country where paid apps are available.</p></td>
    - </tr> <tr>
    -   <td valign="top">Country Targeting</td> <td valign="top"> <p>When you upload your app to
    -     Google Play, you can select the countries in which to distribute your app
    -diff --git a/docs/html/guide/_book.yaml b/docs/html/guide/_book.yaml
    -index 20ee483..f09fe77 100644
    ---- a/docs/html/guide/_book.yaml
    -+++ b/docs/html/guide/_book.yaml
    -@@ -396,14 +396,16 @@ toc:
    -     path: /guide/topics/data/data-storage.html
    -   - title: Data Backup
    -     path: /guide/topics/data/backup.html
    -+    section:
    -+    - title: Auto Backup
    -+      path: /guide/topics/data/autobackup.html
    -+    - title: Key/Value Backup
    -+      path: /guide/topics/data/keyvaluebackup.html
    -+    - title: Testing Backup and Restore
    -+      path: /guide/topics/data/testingbackup.html
    -   - title: App Install Location
    -     path: /guide/topics/data/install-location.html
    - 
    --- title: Libraries
    --  path: /topic/libraries/index.html
    --  section:
    --  - include: /topic/libraries/_book.yaml
    --
    - - title: Administration
    -   path: /guide/topics/admin/index.html
    -   section:
    -diff --git a/docs/html/guide/components/activities.jd b/docs/html/guide/components/activities.jd
    -index 9443924..e757288 100644
    ---- a/docs/html/guide/components/activities.jd
    -+++ b/docs/html/guide/components/activities.jd
    -@@ -624,8 +624,8 @@ android.app.Activity#onSaveInstanceState onSaveInstanceState()}.</p>
    - before making the activity vulnerable to destruction. The system passes this method
    - a {@link android.os.Bundle} in which you can save
    - state information about the activity as name-value pairs, using methods such as {@link
    --android.os.BaseBundle#putString putString()} and {@link
    --android.os.BaseBundle#putInt putInt()}. Then, if the system kills your application
    -+android.os.Bundle#putString putString()} and {@link
    -+android.os.Bundle#putInt putInt()}. Then, if the system kills your application
    - process and the user navigates back to your activity, the system recreates the activity and passes
    - the {@link android.os.Bundle} to both {@link android.app.Activity#onCreate onCreate()} and {@link
    - android.app.Activity#onRestoreInstanceState onRestoreInstanceState()}. Using either of these
    -diff --git a/docs/html/guide/components/bound-services.jd b/docs/html/guide/components/bound-services.jd
    -index f71ba87..2ee2061 100644
    ---- a/docs/html/guide/components/bound-services.jd
    -+++ b/docs/html/guide/components/bound-services.jd
    -@@ -8,19 +8,19 @@ parent.link=services.html
    - <ol id="qv">
    - <h2>In this document</h2>
    - <ol>
    --  <li><a href="#Basics">The Basics</a></li>
    --  <li><a href="#Creating">Creating a Bound Service</a>
    -+  <li><a href="#Basics">The basics</a></li>
    -+  <li><a href="#Creating">Creating a bound service</a>
    -     <ol>
    -       <li><a href="#Binder">Extending the Binder class</a></li>
    -       <li><a href="#Messenger">Using a Messenger</a></li>
    -     </ol>
    -   </li>
    --  <li><a href="#Binding">Binding to a Service</a>
    -+  <li><a href="#Binding">Binding to a service</a>
    -     <ol>
    -       <li><a href="#Additional_Notes">Additional notes</a></li>
    -     </ol>
    -   </li>
    --  <li><a href="#Lifecycle">Managing the Lifecycle of a Bound Service</a></li>
    -+  <li><a href="#Lifecycle">Managing the lifecycle of a bound service</a></li>
    - </ol>
    - 
    - <h2>Key classes</h2>
    -@@ -32,9 +32,13 @@ parent.link=services.html
    - 
    - <h2>Samples</h2>
    - <ol>
    --  <li><a href="{@docRoot}resources/samples/ApiDemos/src/com/example/android/apis/app/RemoteService.html">{@code
    -+  <li><a
    -+ href="{@docRoot}resources/samples/ApiDemos/src/com/example/android/apis/app/RemoteService.html">
    -+  {@code
    -       RemoteService}</a></li>
    --  <li><a href="{@docRoot}resources/samples/ApiDemos/src/com/example/android/apis/app/LocalService.html">{@code
    -+  <li><a
    -+ href="{@docRoot}resources/samples/ApiDemos/src/com/example/android/apis/app/LocalService.html">
    -+ {@code
    -       LocalService}</a></li>
    - </ol>
    - 
    -@@ -45,19 +49,23 @@ parent.link=services.html
    - </div>
    - 
    - 
    --<p>A bound service is the server in a client-server interface. A bound service allows components
    --(such as activities) to bind to the service, send requests, receive responses, and even perform
    -+<p>A bound service is the server in a client-server interface. It allows components
    -+(such as activities) to bind to the service, send requests, receive responses, and perform
    - interprocess communication (IPC). A bound service typically lives only while it serves another
    - application component and does not run in the background indefinitely.</p>
    - 
    --<p>This document shows you how to create a bound service, including how to bind
    --to the service from other application components. However, you should also refer to the <a
    --href="{@docRoot}guide/components/services.html">Services</a> document for additional
    --information about services in general, such as how to deliver notifications from a service, set
    --the service to run in the foreground, and more.</p>
    -+<p class="note"><strong>Note:</strong> If your app targets Android 5.0 (API level 21) or later,
    -+it's recommended that you use the {@link android.app.job.JobScheduler} to execute background
    -+ services. For more information about {@link android.app.job.JobScheduler}, see its
    -+ {@link android.app.job.JobScheduler API-reference documentation}.</p>
    - 
    -+<p>This document describes how to create a bound service, including how to bind
    -+to the service from other application components. For additional information about services in
    -+ general, such as how to deliver notifications from a service and set the service to run
    -+ in the foreground, refer to the <a href="{@docRoot}guide/components/services.html">
    -+ Services</a> document.</p>
    - 
    --<h2 id="Basics">The Basics</h2>
    -+<h2 id="Basics">The basics</h2>
    - 
    - <p>A bound service is an implementation of the {@link android.app.Service} class that allows
    - other applications to bind to it and interact with it. To provide binding for a
    -@@ -67,57 +75,61 @@ clients can use to interact with the service.</p>
    - 
    - <div class="sidebox-wrapper">
    - <div class="sidebox">
    --  <h3>Binding to a Started Service</h3>
    -+  <h3>Binding to a started service</h3>
    - 
    - <p>As discussed in the <a href="{@docRoot}guide/components/services.html">Services</a>
    --document, you can create a service that is both started and bound. That is, the service can be
    --started by calling {@link android.content.Context#startService startService()}, which allows the
    --service to run indefinitely, and also allow a client to bind to the service by calling {@link
    -+document, you can create a service that is both started and bound. That is, you can start a
    -+ service by calling {@link android.content.Context#startService startService()}, which allows the
    -+service to run indefinitely, and you can also allow a client to bind to the service by
    -+ calling {@link
    - android.content.Context#bindService bindService()}.
    -   <p>If you do allow your service to be started and bound, then when the service has been
    --started, the system does <em>not</em> destroy the service when all clients unbind. Instead, you must
    --explicitly stop the service, by calling {@link android.app.Service#stopSelf stopSelf()} or {@link
    -+started, the system does <em>not</em> destroy the service when all clients unbind.
    -+ Instead, you must
    -+explicitly stop the service by calling {@link android.app.Service#stopSelf stopSelf()} or {@link
    - android.content.Context#stopService stopService()}.</p>
    - 
    --<p>Although you should usually implement either {@link android.app.Service#onBind onBind()}
    --<em>or</em> {@link android.app.Service#onStartCommand onStartCommand()}, it's sometimes necessary to
    -+<p>Although you usually implement either {@link android.app.Service#onBind onBind()}
    -+<em>or</em> {@link android.app.Service#onStartCommand onStartCommand()}, it's sometimes
    -+ necessary to
    - implement both. For example, a music player might find it useful to allow its service to run
    - indefinitely and also provide binding. This way, an activity can start the service to play some
    - music and the music continues to play even if the user leaves the application. Then, when the user
    --returns to the application, the activity can bind to the service to regain control of playback.</p>
    -+returns to the application, the activity can bind to the service to regain control of
    -+ playback.</p>
    - 
    --<p>Be sure to read the section about <a href="#Lifecycle">Managing the Lifecycle of a Bound
    --Service</a>, for more information about the service lifecycle when adding binding to a
    --started service.</p>
    -+<p>For more information about the service lifecycle when adding binding to a started service,
    -+ see <a href="#Lifecycle">Managing the lifecycle of a bound Service</a>.</p>
    - </div>
    - </div>
    - 
    --<p>A client can bind to the service by calling {@link android.content.Context#bindService
    -+<p>A client can bind to a service by calling {@link android.content.Context#bindService
    - bindService()}. When it does, it must provide an implementation of {@link
    - android.content.ServiceConnection}, which monitors the connection with the service. The {@link
    --android.content.Context#bindService bindService()} method returns immediately without a value, but
    -+android.content.Context#bindService bindService()} method returns immediately without a
    -+ value, but
    - when the Android system creates the connection between the
    - client and service, it calls {@link
    - android.content.ServiceConnection#onServiceConnected onServiceConnected()} on the {@link
    - android.content.ServiceConnection}, to deliver the {@link android.os.IBinder} that
    - the client can use to communicate with the service.</p>
    - 
    --<p>Multiple clients can connect to the service at once. However, the system calls your service's
    --{@link android.app.Service#onBind onBind()} method to retrieve the {@link android.os.IBinder} only
    -+<p>Multiple clients can connect to a service simultaneously. However, the system calls your service's
    -+{@link android.app.Service#onBind onBind()} method to retrieve the
    -+ {@link android.os.IBinder} only
    - when the first client binds. The system then delivers the same {@link android.os.IBinder} to any
    --additional clients that bind, without calling {@link android.app.Service#onBind onBind()} again.</p>
    -+additional clients that bind, without calling {@link android.app.Service#onBind onBind()}
    -+ again.</p>
    - 
    --<p>When the last client unbinds from the service, the system destroys the service (unless the
    --service was also started by {@link android.content.Context#startService startService()}).</p>
    -+<p>When the last client unbinds from the service, the system destroys the service, unless the
    -+service was also started by {@link android.content.Context#startService startService()}.</p>
    - 
    --<p>When you implement your bound service, the most important part is defining the interface
    --that your {@link android.app.Service#onBind onBind()} callback method returns. There are a few
    --different ways you can define your service's {@link android.os.IBinder} interface and the following
    --section discusses each technique.</p>
    -+<p>The most important part of your bound service implementation is defining the interface
    -+that your {@link android.app.Service#onBind onBind()} callback method returns. The following
    -+section discusses several different ways that you can define your service's
    -+ {@link android.os.IBinder} interface.</p>
    - 
    --
    --
    --<h2 id="Creating">Creating a Bound Service</h2>
    -+<h2 id="Creating">Creating a bound service</h2>
    - 
    - <p>When creating a service that provides binding, you must provide an {@link android.os.IBinder}
    - that provides the programming interface that clients can use to interact with the service. There
    -@@ -125,12 +137,14 @@ are three ways you can define the interface:</p>
    - 
    - <dl>
    -   <dt><a href="#Binder">Extending the Binder class</a></dt>
    --  <dd>If your service is private to your own application and runs in the same process as the client
    --(which is common), you should create your interface by extending the {@link android.os.Binder} class
    -+  <dd>If your service is private to your own application and runs in the same process
    -+  as the client
    -+(which is common), you should create your interface by extending the {@link android.os.Binder}
    -+ class
    - and returning an instance of it from
    - {@link android.app.Service#onBind onBind()}. The client receives the {@link android.os.Binder} and
    - can use it to directly access public methods available in either the {@link android.os.Binder}
    --implementation or even the {@link android.app.Service}.
    -+implementation or the {@link android.app.Service}.
    -   <p>This is the preferred technique when your service is merely a background worker for your own
    - application. The only reason you would not create your interface this way is because
    - your service is used by other applications or across separate processes.</dd>
    -@@ -143,20 +157,20 @@ android.os.Message} objects. This {@link android.os.Handler}
    - is the basis for a {@link android.os.Messenger} that can then share an {@link android.os.IBinder}
    - with the client, allowing the client to send commands to the service using {@link
    - android.os.Message} objects. Additionally, the client can define a {@link android.os.Messenger} of
    --its own so the service can send messages back.
    -+its own, so the service can send messages back.
    -   <p>This is the simplest way to perform interprocess communication (IPC), because the {@link
    - android.os.Messenger} queues all requests into a single thread so that you don't have to design
    - your service to be thread-safe.</p>
    -   </dd>
    - 
    --  <dt>Using AIDL</dt>
    --  <dd>AIDL (Android Interface Definition Language) performs all the work to decompose objects into
    --primitives that the operating system can understand and marshall them across processes to perform
    -+  <dt><a href="{@docRoot}guide/components/aidl.html">Using AIDL</a></dt>
    -+  <dd>Android Interface Definition Language (AIDL) decomposes objects into
    -+primitives that the operating system can understand and marshals them across processes to perform
    - IPC. The previous technique, using a {@link android.os.Messenger}, is actually based on AIDL as
    - its underlying structure. As mentioned above, the {@link android.os.Messenger} creates a queue of
    - all the client requests in a single thread, so the service receives requests one at a time. If,
    - however, you want your service to handle multiple requests simultaneously, then you can use AIDL
    --directly. In this case, your service must be capable of multi-threading and be built thread-safe.
    -+directly. In this case, your service must be thread-safe and capable of multi-threading.
    -   <p>To use AIDL directly, you must
    - create an {@code .aidl} file that defines the programming interface. The Android SDK tools use
    - this file to generate an abstract class that implements the interface and handles IPC, which you
    -@@ -164,19 +178,18 @@ can then extend within your service.</p>
    -   </dd>
    - </dl>
    - 
    --  <p class="note"><strong>Note:</strong> Most applications <strong>should not</strong> use AIDL to
    -+  <p class="note"><strong>Note:</strong> Most applications <em>shouldn't</em> use AIDL to
    - create a bound service, because it may require multithreading capabilities and
    --can result in a more complicated implementation. As such, AIDL is not suitable for most applications
    -+can result in a more complicated implementation. As such, AIDL is not suitable for
    -+ most applications
    - and this document does not discuss how to use it for your service. If you're certain that you need
    - to use AIDL directly, see the <a href="{@docRoot}guide/components/aidl.html">AIDL</a>
    - document.</p>
    - 
    --
    --
    --
    - <h3 id="Binder">Extending the Binder class</h3>
    - 
    --<p>If your service is used only by the local application and does not need to work across processes,
    -+<p>If your service is used only by the local application and does not need to
    -+ work across processes,
    - then you can implement your own {@link android.os.Binder} class that provides your client direct
    - access to public methods in the service.</p>
    - 
    -@@ -187,13 +200,14 @@ background.</p>
    - 
    - <p>Here's how to set it up:</p>
    - <ol>
    --  <li>In your service, create an instance of {@link android.os.Binder} that either:
    -+  <li>In your service, create an instance of {@link android.os.Binder} that does
    -+  one of the following:
    -     <ul>
    --      <li>contains public methods that the client can call</li>
    --      <li>returns the current {@link android.app.Service} instance, which has public methods the
    --client can call</li>
    --      <li>or, returns an instance of another class hosted by the service with public methods the
    --client can call</li>
    -+      <li>Contains public methods that the client can call.</li>
    -+      <li>Returns the current {@link android.app.Service} instance, which has public methods the
    -+client can call.</li>
    -+      <li>Returns an instance of another class hosted by the service with public methods the
    -+client can call.</li>
    -     </ul>
    -   <li>Return this instance of {@link android.os.Binder} from the {@link
    - android.app.Service#onBind onBind()} callback method.</li>
    -@@ -202,12 +216,13 @@ android.content.ServiceConnection#onServiceConnected onServiceConnected()} callb
    - make calls to the bound service using the methods provided.</li>
    - </ol>
    - 
    --<p class="note"><strong>Note:</strong> The reason the service and client must be in the same
    --application is so the client can cast the returned object and properly call its APIs. The service
    -+<p class="note"><strong>Note:</strong> The service and client must be in the same
    -+application so that the client can cast the returned object and properly call its APIs.
    -+ The service
    - and client must also be in the same process, because this technique does not perform any
    --marshalling across processes.</p>
    -+marshaling across processes.</p>
    - 
    --<p>For example, here's a service that provides clients access to methods in the service through
    -+<p>For example, here's a service that provides clients with access to methods in the service through
    - a {@link android.os.Binder} implementation:</p>
    - 
    - <pre>
    -@@ -316,32 +331,30 @@ section provides more information about this process of binding to the service.<
    - <p class="note"><strong>Note:</strong> In the example above, the
    - {@link android.app.Activity#onStop onStop()} method unbinds the client from the service. Clients
    - should unbind from services at appropriate times, as discussed in
    --<a href="#Additional_Notes">Additional Notes</a>.
    -+<a href="#Additional_Notes">Additional notes</a>.
    - </p>
    - 
    - <p>For more sample code, see the <a
    --href="{@docRoot}resources/samples/ApiDemos/src/com/example/android/apis/app/LocalService.html">{@code
    -+href="{@docRoot}resources/samples/ApiDemos/src/com/example/android/apis/app/LocalService.html">
    -+{@code
    - LocalService.java}</a> class and the <a
    --href="{@docRoot}resources/samples/ApiDemos/src/com/example/android/apis/app/LocalServiceActivities.html">{@code
    -+href="{@docRoot}resources/samples/ApiDemos/src/com/example/android/apis/app/LocalServiceActivities.html">
    -+{@code
    - LocalServiceActivities.java}</a> class in <a
    - href="{@docRoot}resources/samples/ApiDemos/index.html">ApiDemos</a>.</p>
    - 
    --
    --
    --
    --
    - <h3 id="Messenger">Using a Messenger</h3>
    - 
    - <div class="sidebox-wrapper">
    - <div class="sidebox">
    -   <h4>Compared to AIDL</h4>
    -   <p>When you need to perform IPC, using a {@link android.os.Messenger} for your interface is
    --simpler than implementing it with AIDL, because {@link android.os.Messenger} queues
    --all calls to the service, whereas, a pure AIDL interface sends simultaneous requests to the
    -+simpler than using AIDL, because {@link android.os.Messenger} queues
    -+all calls to the service. A pure AIDL interface sends simultaneous requests to the
    - service, which must then handle multi-threading.</p>
    -   <p>For most applications, the service doesn't need to perform multi-threading, so using a {@link
    - android.os.Messenger} allows the service to handle one call at a time. If it's important
    --that your service be multi-threaded, then you should use <a
    -+that your service be multi-threaded, use <a
    - href="{@docRoot}guide/components/aidl.html">AIDL</a> to define your interface.</p>
    - </div>
    - </div>
    -@@ -352,10 +365,11 @@ you to perform interprocess communication (IPC) without the need to use AIDL.</p
    - 
    - <p>Here's a summary of how to use a {@link android.os.Messenger}:</p>
    - 
    --<ul>
    -+<ol>
    -   <li>The service implements a {@link android.os.Handler} that receives a callback for each
    - call from a client.</li>
    --  <li>The {@link android.os.Handler} is used to create a {@link android.os.Messenger} object
    -+  <li>The service uses the {@link android.os.Handler} to create a {@link android.os.Messenger}
    -+  object
    - (which is a reference to the {@link android.os.Handler}).</li>
    -   <li>The {@link android.os.Messenger} creates an {@link android.os.IBinder} that the service
    - returns to clients from {@link android.app.Service#onBind onBind()}.</li>
    -@@ -365,11 +379,12 @@ returns to clients from {@link android.app.Service#onBind onBind()}.</li>
    -   <li>The service receives each {@link android.os.Message} in its {@link
    - android.os.Handler}&mdash;specifically, in the {@link android.os.Handler#handleMessage
    - handleMessage()} method.</li>
    --</ul>
    -+</ol>
    - 
    - 
    --<p>In this way, there are no "methods" for the client to call on the service. Instead, the
    --client delivers "messages" ({@link android.os.Message} objects) that the service receives in
    -+<p>In this way, there are no <em>methods</em> for the client to call on the service. Instead, the
    -+client delivers <em>messages</em> ({@link android.os.Message} objects) that the service
    -+ receives in
    - its {@link android.os.Handler}.</p>
    - 
    - <p>Here's a simple example service that uses a {@link android.os.Messenger} interface:</p>
    -@@ -488,41 +503,42 @@ public class ActivityMessenger extends Activity {
    - }
    - </pre>
    - 
    --<p>Notice that this example does not show how the service can respond to the client. If you want the
    --service to respond, then you need to also create a {@link android.os.Messenger} in the client. Then
    --when the client receives the {@link android.content.ServiceConnection#onServiceConnected
    -+<p>Notice that this example does not show how the service can respond to the client.
    -+ If you want the
    -+service to respond, you need to also create a {@link android.os.Messenger} in the client.
    -+When the client receives the {@link android.content.ServiceConnection#onServiceConnected
    - onServiceConnected()} callback, it sends a {@link android.os.Message} to the service that includes
    - the client's {@link android.os.Messenger} in the {@link android.os.Message#replyTo} parameter
    - of the {@link android.os.Messenger#send send()} method.</p>
    - 
    - <p>You can see an example of how to provide two-way messaging in the <a
    --href="{@docRoot}resources/samples/ApiDemos/src/com/example/android/apis/app/MessengerService.html">{@code
    -+href="{@docRoot}resources/samples/ApiDemos/src/com/example/android/apis/app/MessengerService.html">
    -+{@code
    - MessengerService.java}</a> (service) and <a
    --href="{@docRoot}resources/samples/ApiDemos/src/com/example/android/apis/app/MessengerServiceActivities.html">{@code
    -+href="{@docRoot}resources/samples/ApiDemos/src/com/example/android/apis/app/MessengerServiceActivities.html">
    -+{@code
    - MessengerServiceActivities.java}</a> (client) samples.</p>
    - 
    --
    --
    --
    --
    --<h2 id="Binding">Binding to a Service</h2>
    -+<h2 id="Binding">Binding to a service</h2>
    - 
    - <p>Application components (clients) can bind to a service by calling
    - {@link android.content.Context#bindService bindService()}. The Android
    - system then calls the service's {@link android.app.Service#onBind
    --onBind()} method, which returns an {@link android.os.IBinder} for interacting with the service.</p>
    -+onBind()} method, which returns an {@link android.os.IBinder} for interacting with
    -+ the service.</p>
    - 
    --<p>The binding is asynchronous. {@link android.content.Context#bindService
    --bindService()} returns immediately and does <em>not</em> return the {@link android.os.IBinder} to
    --the client. To receive the {@link android.os.IBinder}, the client must create an instance of {@link
    -+<p>The binding is asynchronous, and {@link android.content.Context#bindService
    -+bindService()} returns immediately without <em>not</em> returning the {@link android.os.IBinder} to
    -+the client. To receive the {@link android.os.IBinder}, the client must create an
    -+ instance of {@link
    - android.content.ServiceConnection} and pass it to {@link android.content.Context#bindService
    - bindService()}. The {@link android.content.ServiceConnection} includes a callback method that the
    - system calls to deliver the {@link android.os.IBinder}.</p>
    - 
    - <p class="note"><strong>Note:</strong> Only activities, services, and content providers can bind
    --to a service&mdash;you <strong>cannot</strong> bind to a service from a broadcast receiver.</p>
    -+to a service&mdash;you <strong>can't</strong> bind to a service from a broadcast receiver.</p>
    - 
    --<p>So, to bind to a service from your client, you must: </p>
    -+<p>To bind to a service from your client, follow these steps: </p>
    - <ol>
    -   <li>Implement {@link android.content.ServiceConnection}.
    -     <p>Your implementation must override two callback methods:</p>
    -@@ -533,7 +549,8 @@ the service's {@link android.app.Service#onBind onBind()} method.</dd>
    -       <dt>{@link android.content.ServiceConnection#onServiceDisconnected
    - onServiceDisconnected()}</dt>
    -         <dd>The Android system calls this when the connection to the service is unexpectedly
    --lost, such as when the service has crashed or has been killed. This is <em>not</em> called when the
    -+lost, such as when the service has crashed or has been killed. This is <em>not</em>
    -+ called when the
    - client unbinds.</dd>
    -     </dl>
    -   </li>
    -@@ -548,12 +565,12 @@ android.content.Context#unbindService unbindService()}.
    -   <p>If your client is still bound to a service when your app destroys the client, destruction
    - causes the client to unbind. It is better practice to unbind the client as soon as it is done
    - interacting with the service. Doing so allows the idle service to shut down. For more information
    --about appropriate times to bind and unbind, see <a href="#Additional_Notes">Additional Notes</a>.
    -+about appropriate times to bind and unbind, see <a href="#Additional_Notes">Additional notes</a>.
    - </p>
    -   </li>
    - </ol>
    - 
    --<p>For example, the following snippet connects the client to the service created above by
    -+<p>The following example connects the client to the service created above by
    - <a href="#Binder">extending the Binder class</a>, so all it must do is cast the returned
    - {@link android.os.IBinder} to the {@code LocalService} class and request the {@code
    - LocalService} instance:</p>
    -@@ -579,8 +596,9 @@ private ServiceConnection mConnection = new ServiceConnection() {
    - };
    - </pre>
    - 
    --<p>With this {@link android.content.ServiceConnection}, the client can bind to a service by passing
    --it to {@link android.content.Context#bindService bindService()}. For example:</p>
    -+<p>With this {@link android.content.ServiceConnection}, the client can bind to a service
    -+ by passing
    -+it to {@link android.content.Context#bindService bindService()}, as shown in the following example:</p>
    - 
    - <pre>
    - Intent intent = new Intent(this, LocalService.class);
    -@@ -589,11 +607,21 @@ bindService(intent, mConnection, Context.BIND_AUTO_CREATE);
    - 
    - <ul>
    -   <li>The first parameter of {@link android.content.Context#bindService bindService()} is an
    --{@link android.content.Intent} that explicitly names the service to bind (thought the intent
    --could be implicit).</li>
    -+{@link android.content.Intent} that explicitly names the service to bind.
    -+<p class="caution"><strong>Caution:</strong> If you use an intent to bind to a
    -+ {@link android.app.Service}, ensure that your app is secure by using an <a href="{@docRoot}guide/components/intents-filters.html#Types">explicit</a>
    -+intent. Using an implicit intent to start a service is a
    -+security hazard because you can't be certain what service will respond to the intent,
    -+and the user can't see which service starts. Beginning with Android 5.0 (API level 21),
    -+ the system
    -+throws an exception if you call {@link android.content.Context#bindService bindService()}
    -+with an implicit intent.</p>
    -+</li>
    -+
    - <li>The second parameter is the {@link android.content.ServiceConnection} object.</li>
    - <li>The third parameter is a flag indicating options for the binding. It should usually be {@link
    --android.content.Context#BIND_AUTO_CREATE} in order to create the service if its not already alive.
    -+android.content.Context#BIND_AUTO_CREATE} in order to create the service if it's not already
    -+ alive.
    - Other possible values are {@link android.content.Context#BIND_DEBUG_UNBIND}
    - and {@link android.content.Context#BIND_NOT_FOREGROUND}, or {@code 0} for none.</li>
    - </ul>
    -@@ -606,10 +634,11 @@ and {@link android.content.Context#BIND_NOT_FOREGROUND}, or {@code 0} for none.<
    -   <li>You should always trap {@link android.os.DeadObjectException} exceptions, which are thrown
    - when the connection has broken. This is the only exception thrown by remote methods.</li>
    -   <li>Objects are reference counted across processes. </li>
    --  <li>You should usually pair the binding and unbinding during
    --matching bring-up and tear-down moments of the client's lifecycle. For example:
    -+  <li>You usually pair the binding and unbinding during
    -+matching bring-up and tear-down moments of the client's lifecycle, as described in the
    -+ following examples:
    -     <ul>
    --      <li>If you only need to interact with the service while your activity is visible, you
    -+      <li>If you need to interact with the service only while your activity is visible, you
    - should bind during {@link android.app.Activity#onStart onStart()} and unbind during {@link
    - android.app.Activity#onStop onStop()}.</li>
    -       <li>If you want your activity to receive responses even while it is stopped in the
    -@@ -619,33 +648,34 @@ activity needs to use the service the entire time it's running (even in the back
    - the service is in another process, then you increase the weight of the process and it becomes
    - more likely that the system will kill it.</li>
    -     </ul>
    --    <p class="note"><strong>Note:</strong> You should usually <strong>not</strong> bind and unbind
    -+    <p class="note"><strong>Note:</strong> You <em>don't</em> usually bind and unbind
    - during your activity's {@link android.app.Activity#onResume onResume()} and {@link
    --android.app.Activity#onPause onPause()}, because these callbacks occur at every lifecycle transition
    -+android.app.Activity#onPause onPause()}, because these callbacks occur at every
    -+ lifecycle transition
    - and you should keep the processing that occurs at these transitions to a minimum. Also, if
    --multiple activities in your application bind to the same service and there is a transition between
    --two of those activities, the service may be destroyed and recreated as the current activity unbinds
    --(during pause) before the next one binds (during resume). (This activity transition for how
    -+multiple activities in your application bind to the same service and there is a
    -+ transition between
    -+two of those activities, the service may be destroyed and recreated as the current
    -+ activity unbinds
    -+(during pause) before the next one binds (during resume). This activity transition for how
    - activities coordinate their lifecycles is described in the <a
    - href="{@docRoot}guide/components/activities.html#CoordinatingActivities">Activities</a>
    --document.)</p>
    -+document.</p>
    - </ul>
    - 
    - <p>For more sample code, showing how to bind to a service, see the <a
    --href="{@docRoot}resources/samples/ApiDemos/src/com/example/android/apis/app/RemoteService.html">{@code
    -+href="{@docRoot}resources/samples/ApiDemos/src/com/example/android/apis/app/RemoteService.html">
    -+{@code
    - RemoteService.java}</a> class in <a
    - href="{@docRoot}resources/samples/ApiDemos/index.html">ApiDemos</a>.</p>
    - 
    --
    --
    --
    --
    --<h2 id="Lifecycle">Managing the Lifecycle of a Bound Service</h2>
    -+<h2 id="Lifecycle">Managing the lifecycle of a bound service</h2>
    - 
    - <p>When a service is unbound from all clients, the Android system destroys it (unless it was also
    - started with {@link android.app.Service#onStartCommand onStartCommand()}). As such, you don't have
    - to manage the lifecycle of your service if it's purely a bound
    --service&mdash;the Android system manages it for you based on whether it is bound to any clients.</p>
    -+service&mdash;the Android system manages it for you based on whether it is bound to
    -+ any clients.</p>
    - 
    - <p>However, if you choose to implement the {@link android.app.Service#onStartCommand
    - onStartCommand()} callback method, then you must explicitly stop the service, because the
    -@@ -660,17 +690,11 @@ your {@link android.app.Service#onUnbind onUnbind()} method, you can optionally
    - onRebind()} the next time a client binds to the service. {@link android.app.Service#onRebind
    - onRebind()} returns void, but the client still receives the {@link android.os.IBinder} in its
    - {@link android.content.ServiceConnection#onServiceConnected onServiceConnected()} callback.
    --Below, figure 1 illustrates the logic for this kind of lifecycle.</p>
    --
    -+The following figure illustrates the logic for this kind of lifecycle.</p>
    - 
    - <img src="{@docRoot}images/fundamentals/service_binding_tree_lifecycle.png" alt="" />
    - <p class="img-caption"><strong>Figure 1.</strong> The lifecycle for a service that is started
    - and also allows binding.</p>
    - 
    --
    - <p>For more information about the lifecycle of a started service, see the <a
    - href="{@docRoot}guide/components/services.html#Lifecycle">Services</a> document.</p>
    --
    --
    --
    --
    -diff --git a/docs/html/guide/components/fundamentals.jd b/docs/html/guide/components/fundamentals.jd
    -index ed3ba7d..eaa82c8 100644
    ---- a/docs/html/guide/components/fundamentals.jd
    -+++ b/docs/html/guide/components/fundamentals.jd
    -@@ -6,28 +6,29 @@ page.title=Application Fundamentals
    - 
    - <h2>In this document</h2>
    - <ol>
    --<li><a href="#Components">App Components</a>
    -+<li><a href="#Components">App components</a>
    -   <ol>
    -     <li><a href="#ActivatingComponents">Activating components</a></li>
    -   </ol>
    - </li>
    --<li><a href="#Manifest">The Manifest File</a>
    -+<li><a href="#Manifest">The manifest file</a>
    -   <ol>
    -     <li><a href="#DeclaringComponents">Declaring components</a></li>
    -     <li><a href="#DeclaringRequirements">Declaring app requirements</a></li>
    -   </ol>
    - </li>
    --<li><a href="#Resources">App Resources</a></li>
    -+<li><a href="#Resources">App resources</a></li>
    - </ol>
    - </div>
    - </div>
    - 
    - <p>Android apps are written in the Java programming language. The Android SDK tools compile
    --your code&mdash;along with any data and resource files&mdash;into an APK: an <i>Android package</i>,
    -+your code along with any data and resource files into an APK, an <i>Android package</i>,
    - which is an archive file with an {@code .apk} suffix. One APK file contains all the contents
    - of an Android app and is the file that Android-powered devices use to install the app.</p>
    - 
    --<p>Once installed on a device, each Android app lives in its own security sandbox: </p>
    -+<p>Each Android app lives in its own security sandbox, protected by
    -+ the following Android security features: </p>
    - 
    - <ul>
    -  <li>The Android operating system is a multi-user Linux system in which each app is a
    -@@ -40,54 +41,61 @@ app so that only the user ID assigned to that app can access them. </li>
    - <li>Each process has its own virtual machine (VM), so an app's code runs in isolation from
    - other apps.</li>
    - 
    --<li>By default, every app runs in its own Linux process. Android starts the process when any
    --of the app's components need to be executed, then shuts down the process when it's no longer
    -+<li>By default, every app runs in its own Linux process. The Android system starts
    -+ the process when any
    -+of the app's components need to be executed, and then shuts down the process
    -+ when it's no longer
    - needed or when the system must recover memory for other apps.</li>
    - </ul>
    - 
    --<p>In this way, the Android system implements the <em>principle of least privilege</em>. That is,
    -+<p>The Android system implements the <em>principle of least privilege</em>. That is,
    - each app, by default, has access only to the components that it requires to do its work and
    - no more. This creates a very secure environment in which an app cannot access parts of
    --the system for which it is not given permission.</p>
    --
    --<p>However, there are ways for an app to share data with other apps and for an
    -+the system for which it is not given permission. However, there are ways for an app to share
    -+ data with other apps and for an
    - app to access system services:</p>
    - 
    - <ul>
    -   <li>It's possible to arrange for two apps to share the same Linux user ID, in which case
    - they are able to access each other's files.  To conserve system resources, apps with the
    --same user ID can also arrange to run in the same Linux process and share the same VM (the
    --apps must also be signed with the same certificate).</li>
    -+same user ID can also arrange to run in the same Linux process and share the same VM. The
    -+apps must also be signed with the same certificate.</li>
    -   <li>An app can request permission to access device data such as the user's
    --contacts, SMS messages, the mountable storage (SD card), camera, Bluetooth, and more. The user has
    -+contacts, SMS messages, the mountable storage (SD card), camera, and Bluetooth. The user has
    - to explicitly grant these permissions. For more information, see
    - <a href="{@docRoot}training/permissions/index.html">Working with System Permissions</a>.</li>
    - </ul>
    - 
    --<p>That covers the basics regarding how an Android app exists within the system. The rest of
    --this document introduces you to:</p>
    -+<p>The rest of this document introduces the following concepts:</p>
    - <ul>
    -   <li>The core framework components that define your app.</li>
    --  <li>The manifest file in which you declare components and required device features for your
    -+  <li>The manifest file in which you declare the components and the required device
    -+  features for your
    - app.</li>
    --  <li>Resources that are separate from the app code and allow your app to
    -+  <li>Resources that are separate from the app code and that allow your app to
    - gracefully optimize its behavior for a variety of device configurations.</li>
    - </ul>
    - 
    - 
    - 
    --<h2 id="Components">App Components</h2>
    -+<h2 id="Components">App components</h2>
    - 
    - <p>App components are the essential building blocks of an Android app. Each
    - component is a different point through which the system can enter your app. Not all
    --components are actual entry points for the user and some depend on each other, but each one exists
    --as its own entity and plays a specific role&mdash;each one is a unique building block that
    --helps define your app's overall behavior.</p>
    --
    --<p>There are four different types of app components. Each type serves a distinct purpose
    --and has a distinct lifecycle that defines how the component is created and destroyed.</p>
    -+components are actual entry points for the user and some depend on each other,
    -+ but each one exists
    -+as its own entity and plays a specific role.</p>
    - 
    --<p>Here are the four types of app components:</p>
    -+<p>There are four different types of app components:
    -+<ul>
    -+<li>Activities.</li>
    -+<li>Services.</li>
    -+<li>Content providers.</li>
    -+<li>Broadcast receivers.</li>
    -+</ul></p>
    -+Each type serves a distinct purpose
    -+and has a distinct lifecycle that defines how the component is created and destroyed.
    -+ The following sections describe the four types of app components.</p>
    - 
    - <dl>
    - 
    -@@ -98,11 +106,12 @@ an email app might have one activity that shows a list of new
    - emails, another activity to compose an email, and another activity for reading emails. Although
    - the activities work together to form a cohesive user experience in the email app, each one
    - is independent of the others. As such, a different app can start any one of these
    --activities (if the email app allows it). For example, a camera app can start the
    --activity in the email app that composes new mail, in order for the user to share a picture.
    -+activities if the email app allows it. For example, a camera app can start the
    -+activity in the email app that composes new mail to allow the user to share a picture.
    - 
    --<p>An activity is implemented as a subclass of {@link android.app.Activity} and you can learn more
    --about it in the <a href="{@docRoot}guide/components/activities.html">Activities</a>
    -+<p>An activity is implemented as a subclass of {@link android.app.Activity}. You can learn more
    -+about  {@link android.app.Activity} in the
    -+ <a href="{@docRoot}guide/components/activities.html">Activities</a>
    - developer guide.</p>
    - </dd>
    - 
    -@@ -111,13 +120,16 @@ developer guide.</p>
    - 
    - <dd>A <i>service</i> is a component that runs in the background to perform long-running
    - operations or to perform work for remote processes. A service
    --does not provide a user interface. For example, a service might play music in the background while
    -+does not provide a user interface. For example, a service might play music in the
    -+ background while
    - the user is in a different app, or it might fetch data over the network without
    --blocking user interaction with an activity. Another component, such as an activity, can start the
    -+blocking user interaction with an activity. Another component, such as an activity,
    -+ can start the
    - service and let it run or bind to it in order to interact with it.
    - 
    --<p>A service is implemented as a subclass of {@link android.app.Service} and you can learn more
    --about it in the <a href="{@docRoot}guide/components/services.html">Services</a> developer
    -+<p>A service is implemented as a subclass of {@link android.app.Service}. You can learn more
    -+about  {@link android.app.Service} in the <a href="{@docRoot}guide/components/services.html">
    -+Services</a> developer
    - guide.</p>
    - </dd>
    - 
    -@@ -125,12 +137,14 @@ guide.</p>
    - <dt><b>Content providers</b></dt>
    - 
    - <dd>A <i>content provider</i> manages a shared set of app data. You can store the data in
    --the file system, an SQLite database, on the web, or any other persistent storage location your
    --app can access. Through the content provider, other apps can query or even modify
    --the data (if the content provider allows it). For example, the Android system provides a content
    -+the file system, in a SQLite database, on the web, or on any other persistent storage
    -+ location that your
    -+app can access. Through the content provider, other apps can query or modify
    -+the data if the content provider allows it. For example, the Android system provides a content
    - provider that manages the user's contact information. As such, any app with the proper
    --permissions can query part of the content provider (such as {@link
    --android.provider.ContactsContract.Data}) to read and write information about a particular person.
    -+permissions can query part of the content provider, such as {@link
    -+android.provider.ContactsContract.Data}, to read and write information about
    -+ a particular person.
    - 
    - <p>Content providers are also useful for reading and writing data that is private to your
    - app and not shared. For example, the <a
    -@@ -148,15 +162,17 @@ guide.</p>
    - <dt><b>Broadcast receivers</b></dt>
    - 
    - <dd>A <i>broadcast receiver</i> is a component that responds to system-wide broadcast
    --announcements.  Many broadcasts originate from the system&mdash;for example, a broadcast announcing
    -+announcements.  Many broadcasts originate from the system&mdash;for example,
    -+ a broadcast announcing
    - that the screen has turned off, the battery is low, or a picture was captured.
    - Apps can also initiate broadcasts&mdash;for example, to let other apps know that
    --some data has been downloaded to the device and is available for them to use. Although broadcast
    -+some data has been downloaded to the device and is available for them to use.
    -+ Although broadcast
    - receivers don't display a user interface, they may <a
    - href="{@docRoot}guide/topics/ui/notifiers/notifications.html">create a status bar notification</a>
    - to alert the user when a broadcast event occurs. More commonly, though, a broadcast receiver is
    --just a "gateway" to other components and is intended to do a very minimal amount of work. For
    --instance, it might initiate a service to perform some work based on the event.
    -+just a <em>gateway</em> to other components and is intended to do a very minimal amount of work.
    -+ For instance, it might initiate a service to perform some work based on the event.
    - 
    - <p>A broadcast receiver is implemented as a subclass of {@link android.content.BroadcastReceiver}
    - and each broadcast is delivered as an {@link android.content.Intent} object. For more information,
    -@@ -170,52 +186,59 @@ see the {@link android.content.BroadcastReceiver} class.</p>
    - <p>A unique aspect of the Android system design is that any app can start another
    - app’s component. For example, if you want the user to capture a
    - photo with the device camera, there's probably another app that does that and your
    --app can use it, instead of developing an activity to capture a photo yourself. You don't
    -+app can use it instead of developing an activity to capture a photo yourself. You don't
    - need to incorporate or even link to the code from the camera app.
    - Instead, you can simply start the activity in the camera app that captures a
    - photo. When complete, the photo is even returned to your app so you can use it. To the user,
    - it seems as if the camera is actually a part of your app.</p>
    - 
    --<p>When the system starts a component, it starts the process for that app (if it's not
    --already running) and instantiates the classes needed for the component. For example, if your
    -+<p>When the system starts a component, it starts the process for that app if it's not
    -+already running and instantiates the classes needed for the component. For example, if your
    - app starts the activity in the camera app that captures a photo, that activity
    - runs in the process that belongs to the camera app, not in your app's process.
    - Therefore, unlike apps on most other systems, Android apps don't have a single entry
    --point (there's no {@code main()} function, for example).</p>
    -+point (there's no {@code main()} function).</p>
    - 
    - <p>Because the system runs each app in a separate process with file permissions that
    - restrict access to other apps, your app cannot directly activate a component from
    --another app. The Android system, however, can. So, to activate a component in
    --another app, you must deliver a message to the system that specifies your <em>intent</em> to
    -+another app. However, the Android system can. To activate a component in
    -+another app, deliver a message to the system that specifies your <em>intent</em> to
    - start a particular component. The system then activates the component for you.</p>
    - 
    - 
    --<h3 id="ActivatingComponents">Activating Components</h3>
    -+<h3 id="ActivatingComponents">Activating components</h3>
    - 
    - <p>Three of the four component types&mdash;activities, services, and
    - broadcast receivers&mdash;are activated by an asynchronous message called an <em>intent</em>.
    --Intents bind individual components to each other at runtime (you can think of them
    --as the messengers that request an action from other components), whether the component belongs
    -+Intents bind individual components to each other at runtime. You can think of them
    -+as the messengers that request an action from other components, whether the component belongs
    - to your app or another.</p>
    - 
    -+<p class="note"><strong>Note:</strong> If your app targets Android 5.0 (API level 21) or later,
    -+ use the {@link android.app.job.JobScheduler} to execute background
    -+ services. For more information about using this class, see the
    -+ {@link android.app.job.JobScheduler} reference documentation.</p>
    -+
    - <p>An intent is created with an {@link android.content.Intent} object, which defines a message to
    --activate either a specific component or a specific <em>type</em> of component&mdash;an intent
    --can be either explicit or implicit, respectively.</p>
    -+activate either a specific component (explicit intent) or a specific <em>type</em> of component
    -+ (implicit intent).</p>
    - 
    --<p>For activities and services, an intent defines the action to perform (for example, to "view" or
    --"send" something) and may specify the URI of the data to act on (among other things that the
    --component being started might need to know). For example, an intent might convey a request for an
    -+<p>For activities and services, an intent defines the action to perform (for example, to
    -+ <em>view</em> or
    -+<em>send</em> something) and may specify the URI of the data to act on, among other things that the
    -+component being started might need to know. For example, an intent might convey a request for an
    - activity to show an image or to open a web page. In some cases, you can start an
    --activity to receive a result, in which case, the activity also returns
    --the result in an {@link android.content.Intent} (for example, you can issue an intent to let
    --the user pick a personal contact and have it returned to you&mdash;the return intent includes a
    --URI pointing to the chosen contact).</p>
    -+activity to receive a result, in which case the activity also returns
    -+the result in an {@link android.content.Intent}. For example, you can issue an intent to let
    -+the user pick a personal contact and have it returned to you. The return intent includes a
    -+URI pointing to the chosen contact.</p>
    - 
    - <p>For broadcast receivers, the intent simply defines the
    --announcement being broadcast (for example, a broadcast to indicate the device battery is low
    --includes only a known action string that indicates "battery is low").</p>
    -+announcement being broadcast. For example, a broadcast to indicate the device battery is low
    -+includes only a known action string that indicates <em>battery is low</em>.</p>
    - 
    --<p>The other component type, content provider, is not activated by intents. Rather, it is
    -+<p>Unlike activities, services, and broadcast receivers, content providers are not activated
    -+ by intents. Rather, they are
    - activated when targeted by a request from a {@link android.content.ContentResolver}. The content
    - resolver handles all direct transactions with the content provider so that the component that's
    - performing transactions with the provider doesn't need to and instead calls methods on the {@link
    -@@ -224,15 +247,19 @@ provider and the component requesting information (for security).</p>
    - 
    - <p>There are separate methods for activating each type of component:</p>
    - <ul>
    --  <li>You can start an activity (or give it something new to do) by
    -+  <li>You can start an activity or give it something new to do by
    - passing an {@link android.content.Intent} to {@link android.content.Context#startActivity
    - startActivity()} or {@link android.app.Activity#startActivityForResult startActivityForResult()}
    - (when you want the activity to return a result).</li>
    --  <li>You can start a service (or give new instructions to an ongoing service) by
    -+
    -+
    -+  <li>With Android 5.0 (API level 21) and later, you can start a service with
    -+  {@link android.app.job.JobScheduler}. For earlier Android versions, you can start
    -+  a service (or give new instructions to an ongoing service) by
    - passing an {@link android.content.Intent} to {@link android.content.Context#startService
    --startService()}. Or you can bind to the service by passing an {@link android.content.Intent} to
    --{@link android.content.Context#bindService bindService()}.</li>
    --  <li>You can initiate a broadcast by passing an {@link android.content.Intent} to methods like
    -+startService()}. You can bind to the service by passing an {@link android.content.Intent} to
    -+{@link android.content.Context#bindService bindService()}. </li>
    -+  <li>You can initiate a broadcast by passing an {@link android.content.Intent} to methods such as
    - {@link android.content.Context#sendBroadcast(Intent) sendBroadcast()}, {@link
    - android.content.Context#sendOrderedBroadcast(Intent, String) sendOrderedBroadcast()}, or {@link
    - android.content.Context#sendStickyBroadcast sendStickyBroadcast()}.</li>
    -@@ -242,35 +269,35 @@ android.content.ContentProvider#query query()} on a {@link android.content.Conte
    - 
    - <p>For more information about using intents, see the <a
    - href="{@docRoot}guide/components/intents-filters.html">Intents and
    --Intent Filters</a> document. More information about activating specific components is also provided
    --in the following documents: <a
    --href="{@docRoot}guide/components/activities.html">Activities</a>, <a
    --href="{@docRoot}guide/components/services.html">Services</a>, {@link
    --android.content.BroadcastReceiver} and <a
    --href="{@docRoot}guide/topics/providers/content-providers.html">Content Providers</a>.</p>
    --
    -+Intent Filters</a> document.
    -+ The following documents provide more information about activating specifc components:
    -+ <a href="{@docRoot}guide/components/activities.html">Activities</a>,
    -+ <a href="{@docRoot}guide/components/services.html">Services
    -+ {@link android.content.BroadcastReceiver}, and
    -+ <a ref="{@docRoot}guide/topics/providers/content-providers.html">Content Providers</a>.</p>
    - 
    --<h2 id="Manifest">The Manifest File</h2>
    -+<h2 id="Manifest">The manifest file</h2>
    - 
    - <p>Before the Android system can start an app component, the system must know that the
    --component exists by reading the app's {@code AndroidManifest.xml} file (the "manifest"
    --file). Your app must declare all its components in this file, which must be at the root of
    --the app project directory.</p>
    -+component exists by reading the app's <em>manifest file</em>, {@code AndroidManifest.xml}.
    -+ Your app must declare all its components in this file, which must be at the root of the
    -+ app project directory.</p>
    - 
    - <p>The manifest does a number of things in addition to declaring the app's components,
    --such as:</p>
    -+such as the following:</p>
    - <ul>
    --  <li>Identify any user permissions the app requires, such as Internet access or
    -+  <li>Identifies any user permissions the app requires, such as Internet access or
    - read-access to the user's contacts.</li>
    --  <li>Declare the minimum <a href="{@docRoot}guide/topics/manifest/uses-sdk-element.html#ApiLevels">API Level</a>
    -+  <li>Declares the minimum
    -+  <a href="{@docRoot}guide/topics/manifest/uses-sdk-element.html#ApiLevels">API Level</a>
    - required by the app, based on which APIs the app uses.</li>
    --  <li>Declare hardware and software features used or required by the app, such as a camera,
    -+  <li>Declares hardware and software features used or required by the app, such as a camera,
    - bluetooth services, or a multitouch screen.</li>
    --  <li>API libraries the app needs to be linked against (other than the Android framework
    -+  <li>Declares API libraries the app needs to be linked against (other than the Android framework
    - APIs), such as the <a
    --href="http://code.google.com/android/add-ons/google-apis/maps-overview.html">Google Maps
    --library</a>.</li>
    --  <li>And more</li>
    -+href="http://code.google.com/android/add-ons/google-apis/maps-overview.html">
    -+Google Maps library</a>.</li>
    -+
    - </ul>
    - 
    - 
    -@@ -301,47 +328,59 @@ the {@code android:name} attribute specifies the fully qualified class name of t
    - android.app.Activity} subclass and the {@code android:label} attribute specifies a string
    - to use as the user-visible label for the activity.</p>
    - 
    --<p>You must declare all app components this way:</p>
    -+<p>You must declare all app components using the following elements:</p>
    - <ul>
    -   <li><code><a
    - href="{@docRoot}guide/topics/manifest/activity-element.html">&lt;activity&gt;</a></code> elements
    --for activities</li>
    -+for activities.</li>
    -   <li><code><a
    - href="{@docRoot}guide/topics/manifest/service-element.html">&lt;service&gt;</a></code> elements for
    --services</li>
    -+services.</li>
    -   <li><code><a
    - href="{@docRoot}guide/topics/manifest/receiver-element.html">&lt;receiver&gt;</a></code> elements
    --for broadcast receivers</li>
    -+for broadcast receivers.</li>
    -   <li><code><a
    - href="{@docRoot}guide/topics/manifest/provider-element.html">&lt;provider&gt;</a></code> elements
    --for content providers</li>
    -+for content providers.</li>
    - </ul>
    - 
    - <p>Activities, services, and content providers that you include in your source but do not declare
    - in the manifest are not visible to the system and, consequently, can never run.  However,
    - broadcast
    --receivers can be either declared in the manifest or created dynamically in code (as
    --{@link android.content.BroadcastReceiver} objects) and registered with the system by calling
    -+receivers can be either declared in the manifest or created dynamically in code as
    -+{@link android.content.BroadcastReceiver} objects and registered with the system by calling
    - {@link android.content.Context#registerReceiver registerReceiver()}.</p>
    - 
    - <p>For more about how to structure the manifest file for your app, see <a
    - href="{@docRoot}guide/topics/manifest/manifest-intro.html">The AndroidManifest.xml File</a>
    - documentation. </p>
    - 
    -+<h3 id="DeclaringComponentCapabilities">Declaring component capabilities</h3>
    - 
    -+<p>As discussed above, in <a href="#ActivatingComponents">Activating components</a>, you can use an
    -+{@link android.content.Intent} to start activities, services, and broadcast receivers.
    - 
    --<h3 id="DeclaringComponentCapabilities">Declaring component capabilities</h3>
    - 
    --<p>As discussed above, in <a href="#ActivatingComponents">Activating Components</a>, you can use an
    --{@link android.content.Intent} to start activities, services, and broadcast receivers. You can do so
    --by explicitly naming the target component (using the component class name) in the intent. However,
    --the real power of intents lies in the concept of <em>implicit intents</em>. An implicit intent
    --simply describes the type of action to perform (and, optionally, the data upon which you’d like to
    --perform the action) and allows the system to find a component on the device that can perform the
    --action and start it. If there are multiple components that can perform the action described by the
    --intent, then the user selects which one to use.</p>
    - 
    --<p>The way the system identifies the components that can respond to an intent is by comparing the
    -+You can use an {@link android.content.Intent}
    -+ by explicitly naming the target component (using the component class name) in the intent.
    -+ You can also use an implicit intent, which
    -+describes the type of action to perform and, optionally, the data upon which you’d like to
    -+perform the action. The implicit intent allows the system to find a component on the device
    -+ that can perform the
    -+action and start it. If there are multiple components that can perform the action described by the
    -+intent, the user selects which one to use.</p>
    -+
    -+<p class="caution"><strong>Caution:</strong> If you use an intent to start a
    -+ {@link android.app.Service}, ensure that your app is secure by using an
    -+ <a href="{@docRoot}guide/components/intents-filters.html#Types">explicit</a>
    -+intent. Using an implicit intent to start a service is a
    -+security hazard because you cannot be certain what service will respond to the intent,
    -+and the user cannot see which service starts. Beginning with Android 5.0 (API level 21), the system
    -+throws an exception if you call {@link android.content.Context#bindService bindService()}
    -+with an implicit intent. Do not declare intent filters for your services. </p>
    -+
    -+<p>The system identifies the components that can respond to an intent by comparing the
    - intent received to the <i>intent filters</i> provided in the manifest file of other apps on
    - the device.</p>
    - 
    -@@ -351,8 +390,9 @@ from other apps. You can declare an intent filter for your component by
    - adding an <a href="{@docRoot}guide/topics/manifest/intent-filter-element.html">{@code
    - <intent-filter>}</a> element as a child of the component's declaration element.</p>
    - 
    --<p>For example, if you've built an email app with an activity for composing a new email, you can
    --declare an intent filter to respond to "send" intents (in order to send a new email) like this:</p>
    -+<p>For example, if you build an email app with an activity for composing a new email, you can
    -+declare an intent filter to respond to "send" intents (in order to send a new email),
    -+ as shown in the following example:</p>
    - <pre>
    - &lt;manifest ... >
    -     ...
    -@@ -368,8 +408,9 @@ declare an intent filter to respond to "send" intents (in order to send a new em
    - &lt;/manifest>
    - </pre>
    - 
    --<p>Then, if another app creates an intent with the {@link
    --android.content.Intent#ACTION_SEND} action and passes it to {@link android.app.Activity#startActivity
    -+<p>If another app creates an intent with the {@link
    -+android.content.Intent#ACTION_SEND} action and passes it to
    -+ {@link android.app.Activity#startActivity
    - startActivity()}, the system may start your activity so the user can draft and send an
    - email.</p>
    - 
    -@@ -382,7 +423,7 @@ href="{@docRoot}guide/components/intents-filters.html">Intents and Intent Filter
    - <h3 id="DeclaringRequirements">Declaring app requirements</h3>
    - 
    - <p>There are a variety of devices powered by Android and not all of them provide the
    --same features and capabilities. In order to prevent your app from being installed on devices
    -+same features and capabilities. To prevent your app from being installed on devices
    - that lack features needed by your app, it's important that you clearly define a profile for
    - the types of devices your app supports by declaring device and software requirements in your
    - manifest file. Most of these declarations are informational only and the system does not read
    -@@ -391,7 +432,7 @@ for users when they search for apps from their device.</p>
    - 
    - <p>For example, if your app requires a camera and uses APIs introduced in Android 2.1 (<a
    - href="{@docRoot}guide/topics/manifest/uses-sdk-element.html#ApiLevels">API Level</a> 7),
    --you should declare these as requirements in your manifest file like this:</p>
    -+you must declare these as requirements in your manifest file as shown in the following example:</p>
    - 
    - <pre>
    - &lt;manifest ... >
    -@@ -402,10 +443,10 @@ you should declare these as requirements in your manifest file like this:</p>
    - &lt;/manifest>
    - </pre>
    - 
    --<p>Now, devices that do <em>not</em> have a camera and have an
    --Android version <em>lower</em> than 2.1 cannot install your app from Google Play.</p>
    --
    --<p>However, you can also declare that your app uses the camera, but does not
    -+<p>With the declarations shown in the example, devices that do <em>not</em> have a
    -+ camera and have an
    -+Android version <em>lower</em> than 2.1 cannot install your app from Google Play.
    -+ However, you can declare that your app uses the camera, but does not
    - <em>require</em> it. In that case, your app must set the <a href=
    - "{@docRoot}guide/topics/manifest/uses-feature-element.html#required">{@code required}</a>
    - attribute to {@code "false"} and check at runtime whether
    -@@ -417,15 +458,15 @@ document.</p>
    - 
    - 
    - 
    --<h2 id="Resources">App Resources</h2>
    -+<h2 id="Resources">App resources</h2>
    - 
    - <p>An Android app is composed of more than just code&mdash;it requires resources that are
    - separate from the source code, such as images, audio files, and anything relating to the visual
    --presentation of the app. For example, you should define animations, menus, styles, colors,
    -+presentation of the app. For example, you can define animations, menus, styles, colors,
    - and the layout of activity user interfaces with XML files. Using app resources makes it easy
    --to update various characteristics of your app without modifying code and&mdash;by providing
    --sets of alternative resources&mdash;enables you to optimize your app for a  variety of
    --device configurations (such as different languages and screen sizes).</p>
    -+to update various characteristics of your app without modifying code. Providing
    -+sets of alternative resources enables you to optimize your app for a variety of
    -+device configurations, such as different languages and screen sizes.</p>
    - 
    - <p>For every resource that you include in your Android project, the SDK build tools define a unique
    - integer ID, which you can use to reference the resource from your app code or from
    -@@ -435,20 +476,22 @@ named {@code R.drawable.logo}, which you can use to reference the image and inse
    - user interface.</p>
    - 
    - <p>One of the most important aspects of providing resources separate from your source code
    --is the ability for you to provide alternative resources for different device
    --configurations. For example, by defining UI strings in XML, you can translate the strings into other
    --languages and save those strings in separate files. Then, based on a language <em>qualifier</em>
    -+is the ability to provide alternative resources for different device
    -+configurations. For example, by defining UI strings in XML, you can translate
    -+ the strings into other
    -+languages and save those strings in separate files. Then Android applies the
    -+ appropriate language strings
    -+to your UI based on a language <em>qualifier</em>
    - that you append to the resource directory's name (such as {@code res/values-fr/} for French string
    --values) and the user's language setting, the Android system applies the appropriate language strings
    --to your UI.</p>
    -+values) and the user's language setting.</p>
    - 
    - <p>Android supports many different <em>qualifiers</em> for your alternative resources. The
    - qualifier is a short string that you include in the name of your resource directories in order to
    --define the device configuration for which those resources should be used. As another
    --example, you should often create different layouts for your activities, depending on the
    --device's screen orientation and size. For example, when the device screen is in portrait
    -+define the device configuration for which those resources should be used. For
    -+example, you should create different layouts for your activities, depending on the
    -+device's screen orientation and size. When the device screen is in portrait
    - orientation (tall), you might want a layout with buttons to be vertical, but when the screen is in
    --landscape orientation (wide), the buttons should be aligned horizontally. To change the layout
    -+landscape orientation (wide), the buttons could be aligned horizontally. To change the layout
    - depending on the orientation, you can define two different layouts and apply the appropriate
    - qualifier to each layout's directory name. Then, the system automatically applies the appropriate
    - layout depending on the current device orientation.</p>
    -@@ -465,15 +508,15 @@ create alternative resources for different device configurations, read <a href=
    -   <dl>
    -     <dt><a href="{@docRoot}guide/components/intents-filters.html">Intents and Intent Filters</a>
    -     </dt>
    --    <dd>Information about how to use the {@link android.content.Intent} APIs to
    -+    <dd>How to use the {@link android.content.Intent} APIs to
    -     activate app components, such as activities and services, and how to make your app components
    -     available for use by other apps.</dd>
    -     <dt><a href="{@docRoot}guide/components/activities.html">Activities</a></dt>
    --    <dd>Information about how to create an instance of the {@link android.app.Activity} class,
    -+    <dd>How to create an instance of the {@link android.app.Activity} class,
    -     which provides a distinct screen in your application with a user interface.</dd>
    -     <dt><a
    - href="{@docRoot}guide/topics/resources/providing-resources.html">Providing Resources</a></dt>
    --    <dd>Information about how Android apps are structured to separate app resources from the
    -+    <dd>How Android apps are structured to separate app resources from the
    -    app code, including how you can provide alternative resources for specific device
    -    configurations.
    -     </dd>
    -@@ -484,14 +527,13 @@ href="{@docRoot}guide/topics/resources/providing-resources.html">Providing Resou
    -   <dl>
    -     <dt><a href="{@docRoot}guide/practices/compatibility.html"
    -         >Device Compatibility</a></dt>
    --    <dd>Information about Android works on different types of devices and an introduction
    -+    <dd>How Android works on different types of devices and an introduction
    -     to how you can optimize your app for each device or restrict your app's availability
    -     to different devices.</dd>
    -     <dt><a href="{@docRoot}guide/topics/security/permissions.html"
    -         >System Permissions</a></dt>
    --    <dd>Information about how Android restricts app access to certain APIs with a permission
    -+    <dd>How Android restricts app access to certain APIs with a permission
    -     system that requires the user's consent for your app to use those APIs.</dd>
    -   </dl>
    - </div>
    - </div>
    --
    -diff --git a/docs/html/guide/components/intents-common.jd b/docs/html/guide/components/intents-common.jd
    -index e6c9fc6..47174d2 100644
    ---- a/docs/html/guide/components/intents-common.jd
    -+++ b/docs/html/guide/components/intents-common.jd
    -@@ -2155,7 +2155,7 @@ that are available.</p>
    - <p><b>Example intent:</b></p>
    - <pre>
    - public void openWifiSettings() {
    --    Intent intent = new Intent(Intent.ACTION_WIFI_SETTINGS);
    -+    Intent intent = new Intent(Settings.ACTION_WIFI_SETTINGS);
    -     if (intent.resolveActivity(getPackageManager()) != null) {
    -         startActivity(intent);
    -     }
    -diff --git a/docs/html/guide/components/intents-filters.jd b/docs/html/guide/components/intents-filters.jd
    -index d1d8c78..8f41bc3 100644
    ---- a/docs/html/guide/components/intents-filters.jd
    -+++ b/docs/html/guide/components/intents-filters.jd
    -@@ -7,21 +7,21 @@ page.tags="IntentFilter"
    - 
    - <h2>In this document</h2>
    - <ol>
    --  <li><a href="#Types">Intent Types</a></li>
    --  <li><a href="#Building">Building an Intent</a>
    -+  <li><a href="#Types">Intent types</a></li>
    -+  <li><a href="#Building">Building an intent</a>
    -     <ol>
    -       <li><a href="#ExampleExplicit">Example explicit intent</a></li>
    -       <li><a href="#ExampleSend">Example implicit intent</a></li>
    -       <li><a href="#ForceChooser">Forcing an app chooser</a></li>
    -     </ol>
    -   </li>
    --  <li><a href="#Receiving">Receiving an Implicit Intent</a>
    -+  <li><a href="#Receiving">Receiving an implicit intent</a>
    -     <ol>
    -       <li><a href="#ExampleFilters">Example filters</a></li>
    -     </ol>
    -   </li>
    --  <li><a href="#PendingIntent">Using a Pending Intent</a></li>
    --  <li><a href="#Resolution">Intent Resolution</a>
    -+  <li><a href="#PendingIntent">Using a pending intent</a></li>
    -+  <li><a href="#Resolution">Intent resolution</a>
    -     <ol>
    -       <li><a href="#ActionTest">Action test</a></li>
    -       <li><a href="#CategoryTest">Category test</a></li>
    -@@ -46,13 +46,14 @@ page.tags="IntentFilter"
    - <p>An {@link android.content.Intent} is a messaging object you can use to request an action
    - from another <a href="{@docRoot}guide/components/fundamentals.html#Components">app component</a>.
    - Although intents facilitate communication between components in several ways, there are three
    --fundamental use-cases:</p>
    -+fundamental use cases:</p>
    - 
    - <ul>
    --<li><b>To start an activity:</b>
    -+<li><b>Starting an activity</b>
    - <p>An {@link android.app.Activity} represents a single screen in an app. You can start a new
    - instance of an {@link android.app.Activity} by passing an {@link android.content.Intent}
    --to {@link android.content.Context#startActivity startActivity()}. The {@link android.content.Intent}
    -+to {@link android.content.Context#startActivity startActivity()}.
    -+ The {@link android.content.Intent}
    - describes the activity to start and carries any necessary data.</p>
    - 
    - <p>If you want to receive a result from the activity when it finishes,
    -@@ -63,10 +64,16 @@ android.app.Activity#onActivityResult onActivityResult()} callback.
    - For more information, see the <a
    - href="{@docRoot}guide/components/activities.html">Activities</a> guide.</p></li>
    - 
    --<li><b>To start a service:</b>
    -+<li><b>Starting a service</b>
    - <p>A {@link android.app.Service} is a component that performs operations in the background
    --without a user interface. You can start a service to perform a one-time operation
    --(such as download a file) by passing an {@link android.content.Intent}
    -+without a user interface. With Android 5.0 (API level 21) and later, you can start a service
    -+ with {@link android.app.job.JobScheduler}. For more information
    -+ about {@link android.app.job.JobScheduler}, see its
    -+    {@link android.app.job.JobScheduler API-reference documentation}.</p>
    -+<p>For versions earlier than Android 5.0 (API level 21), you can start a service by using
    -+methods of the  {@link android.app.Service} class. You can start a service
    -+ to perform a one-time operation
    -+(such as downloading a file) by passing an {@link android.content.Intent}
    - to {@link android.content.Context#startService startService()}. The {@link android.content.Intent}
    - describes the service to start and carries any necessary data.</p>
    - 
    -@@ -75,7 +82,7 @@ from another component by passing an {@link android.content.Intent} to {@link
    - android.content.Context#bindService bindService()}</code>. For more information, see the <a
    - href="{@docRoot}guide/components/services.html">Services</a> guide.</p></li>
    - 
    --<li><b>To deliver a broadcast:</b>
    -+<li><b>Delivering a broadcast</b>
    - <p>A broadcast is a message that any app can receive. The system delivers various
    - broadcasts for system events, such as when the system boots up or the device starts charging.
    - You can deliver a broadcast to other apps by passing an {@link android.content.Intent}
    -@@ -89,7 +96,7 @@ android.content.Context#sendStickyBroadcast sendStickyBroadcast()}.</p>
    - 
    - 
    - 
    --<h2 id="Types">Intent Types</h2>
    -+<h2 id="Types">Intent types</h2>
    - 
    - <p>There are two types of intents:</p>
    - 
    -@@ -97,7 +104,7 @@ android.content.Context#sendStickyBroadcast sendStickyBroadcast()}.</p>
    - <li><b>Explicit intents</b> specify the component to start by name (the
    - fully-qualified class name). You'll typically use an explicit intent to start a component in
    - your own app, because you know the class name of the activity or service you want to start. For
    --example, start a new activity in response to a user action or start a service to download
    -+example, you can start a new activity in response to a user action or start a service to download
    - a file in the background.</li>
    - 
    - <li><b>Implicit intents</b> do not name a specific component, but instead declare a general action
    -@@ -106,12 +113,13 @@ show the user a location on a map, you can use an implicit intent to request tha
    - app show a specified location on a map.</li>
    - </ul>
    - 
    --<p>When you create an explicit intent to start an activity or service, the system immediately
    -+<p>Figure 1 shows how an intent is delivered to start an activity. When you create an
    -+ explicit intent to start an activity or service, the system immediately
    - starts the app component specified in the {@link android.content.Intent} object.</p>
    - 
    - <div class="figure" style="width:446px">
    - <img src="{@docRoot}images/components/intent-filters@2x.png" width="446" alt=""/>
    --<p class="img-caption"><strong>Figure 1.</strong> Illustration of how an implicit intent is
    -+<p class="img-caption"><strong>Figure 1.</strong> How an implicit intent is
    - delivered through the system to start another activity: <b>[1]</b> <em>Activity A</em> creates an
    - {@link android.content.Intent} with an action description and passes it to {@link
    - android.content.Context#startActivity startActivity()}. <b>[2]</b> The Android System searches all
    -@@ -135,11 +143,12 @@ you make it possible for other apps to directly start your activity with a certa
    - Likewise, if you do <em>not</em> declare any intent filters for an activity, then it can be started
    - only with an explicit intent.</p>
    - 
    --<p class="caution"><strong>Caution:</strong> To ensure your app is secure, always use an explicit
    -+<p class="caution"><strong>Caution:</strong> To ensure that your app is secure, always
    -+ use an explicit
    - intent when starting a {@link android.app.Service} and do not
    - declare intent filters for your services. Using an implicit intent to start a service is a
    --security hazard because you cannot be certain what service will respond to the intent,
    --and the user cannot see which service starts. Beginning with Android 5.0 (API level 21), the system
    -+security hazard because you can't be certain what service will respond to the intent,
    -+and the user can't see which service starts. Beginning with Android 5.0 (API level 21), the system
    - throws an exception if you call {@link android.content.Context#bindService bindService()}
    - with an implicit intent.</p>
    - 
    -@@ -147,7 +156,7 @@ with an implicit intent.</p>
    - 
    - 
    - 
    --<h2 id="Building">Building an Intent</h2>
    -+<h2 id="Building">Building an intent</h2>
    - 
    - <p>An {@link android.content.Intent} object carries information that the Android system uses
    - to determine which component to start (such as the exact component name or component
    -@@ -163,22 +172,23 @@ order to properly perform the action (such as the action to take and the data to
    - <dd>The name of the component to start.
    - 
    - <p>This is optional, but it's the critical piece of information that makes an intent
    --<b>explicit</b>, meaning that the intent should be delivered only to the app component
    --defined by the component name. Without a component name, the intent is <b>implicit</b> and the
    -+<em>explicit</em>, meaning that the intent should be delivered only to the app component
    -+defined by the component name. Without a component name, the intent is <em>implicit</em> and the
    - system decides which component should receive the intent based on the other intent information
    --(such as the action, data, and category&mdash;described below). So if you need to start a specific
    -+(such as the action, data, and category&mdash;described below). If you need to start a specific
    - component in your app, you should specify the component name.</p>
    - 
    --<p class="note"><strong>Note:</strong> When starting a {@link android.app.Service}, you should
    --<strong>always specify the component name</strong>. Otherwise, you cannot be certain what service
    -+<p class="note"><strong>Note:</strong> When starting a {@link android.app.Service},
    -+ <em>always specify the component name</em>. Otherwise, you cannot be certain what service
    - will respond to the intent, and the user cannot see which service starts.</p>
    - 
    - <p>This field of the {@link android.content.Intent} is a
    - {@link android.content.ComponentName} object, which you can specify using a fully
    --qualified class name of the target component, including the package name of the app. For example,
    -+qualified class name of the target component, including the package name of the app, for example,
    - {@code com.example.ExampleActivity}. You can set the component name with {@link
    - android.content.Intent#setComponent setComponent()}, {@link android.content.Intent#setClass
    --setClass()}, {@link android.content.Intent#setClassName(String, String) setClassName()}, or with the
    -+setClass()}, {@link android.content.Intent#setClassName(String, String) setClassName()},
    -+ or with the
    - {@link android.content.Intent} constructor.</p>
    - 
    - </dd>
    -@@ -188,10 +198,10 @@ setClass()}, {@link android.content.Intent#setClassName(String, String) setClass
    - 
    - <p>In the case of a broadcast intent, this is the action that took place and is being reported.
    - The action largely determines how the rest of the intent is structured&mdash;particularly
    --what is contained in the data and extras.
    -+the information that is contained in the data and extras.
    - 
    - <p>You can specify your own actions for use by intents within your app (or for use by other
    --apps to invoke components in your app), but you should usually use action constants
    -+apps to invoke components in your app), but you usually specify action constants
    - defined by the {@link android.content.Intent} class or other framework classes. Here are some
    - common actions for starting an activity:</p>
    - 
    -@@ -203,7 +213,7 @@ common actions for starting an activity:</p>
    -    view in a map app.</dd>
    - 
    - <dt>{@link android.content.Intent#ACTION_SEND}</dt>
    --   <dd>Also known as the "share" intent, you should use this in an intent with {@link
    -+   <dd>Also known as the <em>share</em> intent, you should use this in an intent with {@link
    -    android.content.Context#startActivity startActivity()} when you have some data that the user can
    -    share through another app, such as an email app or social sharing app.</dd>
    - </dl>
    -@@ -217,12 +227,13 @@ that open specific screens in the system's Settings app.</p>
    - setAction()} or with an {@link android.content.Intent} constructor.</p>
    - 
    - <p>If you define your own actions, be sure to include your app's package name
    --as a prefix. For example:</p>
    -+as a prefix, as shown in the following example:</p>
    - <pre>static final String ACTION_TIMETRAVEL = "com.example.action.TIMETRAVEL";</pre>
    - </dd>
    - 
    - <dt><b>Data</b></dt>
    --<dd>The URI (a {@link android.net.Uri} object) that references the data to be acted on and/or the
    -+<dd>The URI (a {@link android.net.Uri} object) that references the data to
    -+ be acted on and/or the
    - MIME type of that data. The type of data supplied is generally dictated by the intent's action. For
    - example, if the action is {@link android.content.Intent#ACTION_EDIT}, the data should contain the
    - URI of the document to edit.
    -@@ -231,10 +242,11 @@ URI of the document to edit.
    - it's often important to specify the type of data (its MIME type) in addition to its URI.
    - For example, an activity that's able to display images probably won't be able
    - to play an audio file, even though the URI formats could be similar.
    --So specifying the MIME type of your data helps the Android
    -+Specifying the MIME type of your data helps the Android
    - system find the best component to receive your intent.
    - However, the MIME type can sometimes be inferred from the URI&mdash;particularly when the data is a
    --{@code content:} URI, which indicates the data is located on the device and controlled by a
    -+{@code content:} URI. A {@code content:} URI indicates the data is located on the device
    -+ and controlled by a
    - {@link android.content.ContentProvider}, which makes the data MIME type visible to the system.</p>
    - 
    - <p>To set only the data URI, call {@link android.content.Intent#setData setData()}.
    -@@ -243,7 +255,7 @@ can set both explicitly with {@link
    - android.content.Intent#setDataAndType setDataAndType()}.</p>
    - 
    - <p class="caution"><strong>Caution:</strong> If you want to set both the URI and MIME type,
    --<strong>do not</strong> call {@link android.content.Intent#setData setData()} and
    -+<em>don't</em> call {@link android.content.Intent#setData setData()} and
    - {@link android.content.Intent#setType setType()} because they each nullify the value of the other.
    - Always use {@link android.content.Intent#setDataAndType setDataAndType()} to set both
    - URI and MIME type.</p>
    -@@ -258,7 +270,7 @@ Here are some common categories:
    - <dl>
    - <dt>{@link android.content.Intent#CATEGORY_BROWSABLE}</dt>
    -   <dd>The target activity allows itself to be started by a web browser to display data
    --       referenced by a link&mdash;such as an image or an e-mail message.
    -+       referenced by a link, such as an image or an e-mail message.
    -   </dd>
    - <dt>{@link android.content.Intent#CATEGORY_LAUNCHER}</dt>
    -   <dd>The activity is the initial activity of a task and is listed in
    -@@ -276,14 +288,14 @@ categories.</p>
    - 
    - <p>These properties listed above (component name, action, data, and category) represent the
    - defining characteristics of an intent. By reading these properties, the Android system
    --is able to resolve which app component it should start.</p>
    --
    --<p>However, an intent can carry additional information that does not affect
    --how it is resolved to an app component. An intent can also supply:</p>
    -+is able to resolve which app component it should start. However, an intent can carry
    -+ additional information that does not affect
    -+how it is resolved to an app component. An intent can also supply the following information:</p>
    - 
    - <dl>
    - <dt><b>Extras</b></dt>
    --<dd>Key-value pairs that carry additional information required to accomplish the requested action.
    -+<dd>Key-value pairs that carry additional information required to accomplish
    -+ the requested action.
    - Just as some actions use particular kinds of data URIs, some actions also use particular extras.
    - 
    - <p>You can add extra data with various {@link android.content.Intent#putExtra putExtra()} methods,
    -@@ -293,21 +305,22 @@ the {@link android.os.Bundle} in the {@link android.content.Intent} with {@link
    - android.content.Intent#putExtras putExtras()}.</p>
    - 
    - <p>For example, when creating an intent to send an email with
    --{@link android.content.Intent#ACTION_SEND}, you can specify the "to" recipient with the
    --{@link android.content.Intent#EXTRA_EMAIL} key, and specify the "subject" with the
    -+{@link android.content.Intent#ACTION_SEND}, you can specify the <em>to</em> recipient with the
    -+{@link android.content.Intent#EXTRA_EMAIL} key, and specify the <em>subject</em> with the
    - {@link android.content.Intent#EXTRA_SUBJECT} key.</p>
    - 
    - <p>The {@link android.content.Intent} class specifies many {@code EXTRA_*} constants
    - for standardized data types. If you need to declare your own extra keys (for intents that
    - your app receives), be sure to include your app's package name
    --as a prefix. For example:</p>
    -+as a prefix, as shown in the following example:</p>
    - <pre>static final String EXTRA_GIGAWATTS = "com.example.EXTRA_GIGAWATTS";</pre>
    - </dd>
    - 
    - <dt><b>Flags</b></dt>
    --<dd>Flags defined in the {@link android.content.Intent} class that function as metadata for the
    -+<dd>Flags are defined in the {@link android.content.Intent} class that function as metadata for the
    - intent. The flags may instruct the Android system how to launch an activity (for example, which
    --<a href="{@docRoot}guide/components/tasks-and-back-stack.html">task</a> the activity should belong
    -+<a href="{@docRoot}guide/components/tasks-and-back-stack.html">task</a>
    -+ the activity should belong
    - to) and how to treat it after it's launched (for example, whether it belongs in the list of recent
    - activities).
    - 
    -@@ -354,7 +367,8 @@ this intent explicitly starts the {@code DownloadService} class in the app.</p>
    - to perform the action. Using an implicit intent is useful when your app cannot perform the
    - action, but other apps probably can and you'd like the user to pick which app to use.</p>
    - 
    --<p>For example, if you have content you want the user to share with other people, create an intent
    -+<p>For example, if you have content that you want the user to share with other people,
    -+ create an intent
    - with the {@link android.content.Intent#ACTION_SEND} action
    - and add extras that specify the content to share. When you call
    - {@link android.content.Context#startActivity startActivity()} with that intent, the user can
    -@@ -362,13 +376,15 @@ pick an app through which to share the content.</p>
    - 
    - <p class="caution"><strong>Caution:</strong> It's possible that a user won't have <em>any</em>
    - apps that handle the implicit intent you send to {@link android.content.Context#startActivity
    --startActivity()}. If that happens, the call will fail and your app will crash. To verify
    -+startActivity()}. If that happens, the call fails and your app crashes. To verify
    - that an activity will receive the intent, call {@link android.content.Intent#resolveActivity
    - resolveActivity()} on your {@link android.content.Intent} object. If the result is non-null,
    --then there is at least one app that can handle the intent and it's safe to call
    -+ there is at least one app that can handle the intent and it's safe to call
    - {@link android.content.Context#startActivity startActivity()}. If the result is null,
    --you should not use the intent and, if possible, you should disable the feature that issues
    --the intent.</p>
    -+ do not use the intent and, if possible, you should disable the feature that issues
    -+the intent. The following example shows how to verify that the intent resolves
    -+to an activity. This example doesn't use a URI, but the intent's data type
    -+is declared to specify the content carried by the extras.</p>
    - 
    - 
    - <pre>
    -@@ -384,8 +400,7 @@ if (sendIntent.resolveActivity(getPackageManager()) != null) {
    - }
    - </pre>
    - 
    --<p class="note"><strong>Note:</strong> In this case, a URI is not used, but the intent's data type
    --is declared to specify the content carried by the extras.</p>
    -+
    - 
    - 
    - <p>When {@link android.content.Context#startActivity startActivity()} is called, the system
    -@@ -393,7 +408,7 @@ examines all of the installed apps to determine which ones can handle this kind
    - intent with the {@link android.content.Intent#ACTION_SEND} action and that carries "text/plain"
    - data). If there's only one app that can handle it, that app opens immediately and is given the
    - intent. If multiple activities accept the intent, the system
    --displays a dialog so the user can pick which app to use..</p>
    -+displays a dialog such as the one shown in Figure 2, so the user can pick which app to use.</p>
    - 
    - 
    - <div class="figure" style="width:200px">
    -@@ -405,23 +420,26 @@ displays a dialog so the user can pick which app to use..</p>
    - 
    - <p>When there is more than one app that responds to your implicit intent,
    - the user can select which app to use and make that app the default choice for the
    --action. This is nice when performing an action for which the user
    --probably wants to use the same app from now on, such as when opening a web page (users
    --often prefer just one web browser) .</p>
    -+action. The ability to select a default is helpful when performing an action for which the user
    -+probably wants to use the same app every time, such as when opening a web page (users
    -+often prefer just one web browser).</p>
    - 
    - <p>However, if multiple apps can respond to the intent and the user might want to use a different
    - app each time, you should explicitly show a chooser dialog. The chooser dialog asks the
    --user to select which app to use for the action every time (the user cannot select a default app for
    -+user to select which app to use for the action (the user cannot select a default app for
    - the action). For example, when your app performs "share" with the {@link
    - android.content.Intent#ACTION_SEND} action, users may want to share using a different app depending
    --on their current situation, so you should always use the chooser dialog, as shown in figure 2.</p>
    -+on their current situation, so you should always use the chooser dialog, as shown in Figure 2.</p>
    - 
    - 
    - 
    - 
    - <p>To show the chooser, create an {@link android.content.Intent} using {@link
    - android.content.Intent#createChooser createChooser()} and pass it to {@link
    --android.app.Activity#startActivity startActivity()}. For example:</p>
    -+android.app.Activity#startActivity startActivity()}, as shown in the following example.
    -+ This example displays a dialog with a list of apps that respond to the intent passed to the {@link
    -+android.content.Intent#createChooser createChooser()} method and uses the supplied text as the
    -+dialog title.</p>
    - 
    - <pre>
    - Intent sendIntent = new Intent(Intent.ACTION_SEND);
    -@@ -439,26 +457,16 @@ if (sendIntent.resolveActivity(getPackageManager()) != null) {
    - }
    - </pre>
    - 
    --<p>This displays a dialog with a list of apps that respond to the intent passed to the {@link
    --android.content.Intent#createChooser createChooser()} method and uses the supplied text as the
    --dialog title.</p>
    --
    --
    - 
    - 
    --
    --
    --
    --
    --
    --<h2 id="Receiving">Receiving an Implicit Intent</h2>
    -+<h2 id="Receiving">Receiving an implicit intent</h2>
    - 
    - <p>To advertise which implicit intents your app can receive, declare one or more intent filters for
    - each of your app components with an <a href=
    --"{@docRoot}guide/topics/manifest/intent-filter-element.html">{@code <intent-filter>}</a>
    -+"{@docRoot}guide/topics/manifest/intent-filter-element.html">{@code &lt;intent-filter&gt;}</a>
    - element in your <a href="{@docRoot}guide/topics/manifest/manifest-intro.html">manifest file</a>.
    - Each intent filter specifies the type of intents it accepts based on the intent's action,
    --data, and category. The system will deliver an implicit intent to your app component only if the
    -+data, and category. The system delivers an implicit intent to your app component only if the
    - intent can pass through one of your intent filters.</p>
    - 
    - <p class="note"><strong>Note:</strong> An explicit intent is always delivered to its target,
    -@@ -471,28 +479,28 @@ it inspects the {@link android.content.Intent} and decides how to behave based o
    - in the {@link android.content.Intent} (such as to show the editor controls or not).</p>
    - 
    - <p>Each intent filter is defined by an <a
    --href="{@docRoot}guide/topics/manifest/intent-filter-element.html">{@code <intent-filter>}</a>
    -+href="{@docRoot}guide/topics/manifest/intent-filter-element.html">{@code &lt;intent-filter>}</a>
    - element in the app's manifest file, nested in the corresponding app component (such
    --as an <a href="{@docRoot}guide/topics/manifest/activity-element.html">{@code <activity>}</a>
    -+as an <a href="{@docRoot}guide/topics/manifest/activity-element.html">{@code &lt;activity>}</a>
    - element). Inside the <a
    --href="{@docRoot}guide/topics/manifest/intent-filter-element.html">{@code <intent-filter>}</a>,
    -+href="{@docRoot}guide/topics/manifest/intent-filter-element.html">{@code &lt;intent-filter>}</a>,
    - you can specify the type of intents to accept using one or more
    - of these three elements:</p>
    - 
    - <dl>
    --<dt><a href="{@docRoot}guide/topics/manifest/action-element.html">{@code <action>}</a></dt>
    -+<dt><a href="{@docRoot}guide/topics/manifest/action-element.html">{@code &lt;action>}</a></dt>
    -   <dd>Declares the intent action accepted, in the {@code name} attribute. The value
    -   must be the literal string value of an action, not the class constant.</dd>
    --<dt><a href="{@docRoot}guide/topics/manifest/data-element.html">{@code <data>}</a></dt>
    -+<dt><a href="{@docRoot}guide/topics/manifest/data-element.html">{@code &lt;data>}</a></dt>
    -   <dd>Declares the type of data accepted, using one or more attributes that specify various
    -   aspects of the data URI (<code>scheme</code>, <code>host</code>, <code>port</code>,
    --  <code>path</code>, etc.) and MIME type.</dd>
    --<dt><a href="{@docRoot}guide/topics/manifest/category-element.html">{@code <category>}</a></dt>
    -+  <code>path</code>) and MIME type.</dd>
    -+<dt><a href="{@docRoot}guide/topics/manifest/category-element.html">{@code &lt;category>}</a></dt>
    -   <dd>Declares the intent category accepted, in the {@code name} attribute. The value
    -   must be the literal string value of an action, not the class constant.
    - 
    --  <p class="note"><strong>Note:</strong> In order to receive implicit intents, you
    --  <strong>must include</strong> the
    -+  <p class="note"><strong>Note:</strong> To receive implicit intents, you
    -+  <em>must include</em> the
    -   {@link android.content.Intent#CATEGORY_DEFAULT} category in the intent filter. The methods
    -   {@link android.app.Activity#startActivity startActivity()} and
    -   {@link android.app.Activity#startActivityForResult startActivityForResult()} treat all intents
    -@@ -515,12 +523,12 @@ of these three elements:</p>
    - &lt;/activity>
    - </pre>
    - 
    --<p>It's okay to create a filter that includes more than one instance of
    --<a href="{@docRoot}guide/topics/manifest/action-element.html">{@code <action>}</a>,
    --<a href="{@docRoot}guide/topics/manifest/data-element.html">{@code <data>}</a>, or
    --<a href="{@docRoot}guide/topics/manifest/category-element.html">{@code <category>}</a>.
    --If you do, you simply need to be certain that the component can handle any and all combinations
    --of those filter elements.</p>
    -+<p>You can create a filter that includes more than one instance of
    -+<a href="{@docRoot}guide/topics/manifest/action-element.html">{@code &lt;action>}</a>,
    -+<a href="{@docRoot}guide/topics/manifest/data-element.html">{@code &lt;data>}</a>, or
    -+<a href="{@docRoot}guide/topics/manifest/category-element.html">{@code &lt;category>}</a>.
    -+If you do, you need to be certain that the component can handle any and all
    -+combinations of those filter elements.</p>
    - 
    - <p>When you want to handle multiple kinds of intents, but only in specific combinations of
    - action, data, and category type, then you need to create multiple intent filters.</p>
    -@@ -569,8 +577,8 @@ is running.</p>
    - 
    - <h3 id="ExampleFilters">Example filters</h3>
    - 
    --<p>To better understand some of the intent filter behaviors, look at the following snippet
    --from the manifest file of a social-sharing app.</p>
    -+<p>To demonstrate some of the intent filter behaviors, here is an example
    -+from the manifest file of a social-sharing app:</p>
    - 
    - <pre>
    - &lt;activity android:name="MainActivity">
    -@@ -607,9 +615,9 @@ opens when the user initially launches the app with the launcher icon:</p>
    -   indicates this is the main entry point and does not expect any intent data.</li>
    -   <li>The {@link android.content.Intent#CATEGORY_LAUNCHER} category indicates that this activity's
    -   icon should be placed in the system's app launcher. If the <a
    --  href="{@docRoot}guide/topics/manifest/activity-element.html">{@code <activity>}</a> element
    -+  href="{@docRoot}guide/topics/manifest/activity-element.html">{@code &lt;activity>}</a> element
    -   does not specify an icon with {@code icon}, then the system uses the icon from the <a
    --  href="{@docRoot}guide/topics/manifest/application-element.html">{@code <application>}</a>
    -+  href="{@docRoot}guide/topics/manifest/application-element.html">{@code &lt;application>}</a>
    -   element.</li>
    - </ul>
    - <p>These two must be paired together in order for the activity to appear in the app launcher.</p>
    -@@ -620,7 +628,7 @@ they can also enter {@code ShareActivity} directly from another app that issues
    - intent matching one of the two intent filters.</p>
    - 
    - <p class="note"><strong>Note:</strong> The MIME type,
    --<a href="https://developers.google.com/panorama/android/">{@code
    -+<a href="https://developers.google.com/panorama/android/" class="external-link">{@code
    - application/vnd.google.panorama360+jpg}</a>, is a special data type that specifies
    - panoramic photos, which you can handle with the <a
    - href="{@docRoot}reference/com/google/android/gms/panorama/package-summary.html">Google
    -@@ -638,7 +646,7 @@ panorama</a> APIs.</p>
    - 
    - 
    - 
    --<h2 id="PendingIntent">Using a Pending Intent</h2>
    -+<h2 id="PendingIntent">Using a pending intent</h2>
    - 
    - <p>A {@link android.app.PendingIntent} object is a wrapper around an {@link
    - android.content.Intent} object. The primary purpose of a {@link android.app.PendingIntent}
    -@@ -646,25 +654,25 @@ is to grant permission to a foreign application
    - to use the contained {@link android.content.Intent} as if it were executed from your
    - app's own process.</p>
    - 
    --<p>Major use cases for a pending intent include:</p>
    -+<p>Major use cases for a pending intent include the following:</p>
    - <ul>
    --  <li>Declare an intent to be executed when the user performs an action with your <a
    -+  <li>Declaring an intent to be executed when the user performs an action with your <a
    -   href="{@docRoot}guide/topics/ui/notifiers/notifications.html">Notification</a>
    -   (the Android system's {@link android.app.NotificationManager}
    -   executes the {@link android.content.Intent}).
    --  <li>Declare an intent to be executed when the user performs an action with your
    -+  <li>Declaring an intent to be executed when the user performs an action with your
    -   <a href="{@docRoot}guide/topics/appwidgets/index.html">App Widget</a>
    -   (the Home screen app executes the {@link android.content.Intent}).
    --  <li>Declare an intent to be executed at a specified time in the future (the Android
    -+  <li>Declaring an intent to be executed at a specified future time (the Android
    -   system's {@link android.app.AlarmManager} executes the {@link android.content.Intent}).
    - </ul>
    - 
    --<p>Because each {@link android.content.Intent} object is designed to be handled by a specific
    -+<p>Just as each {@link android.content.Intent} object is designed to be handled by a specific
    - type of app component (either an {@link android.app.Activity}, a {@link android.app.Service}, or
    - a {@link android.content.BroadcastReceiver}), so too must a {@link android.app.PendingIntent} be
    --created with the same consideration. When using a pending intent, your app will not
    -+created with the same consideration. When using a pending intent, your app doesn't
    - execute the intent with a call such as {@link android.content.Context#startActivity
    --startActivity()}. You must instead declare the intended component type when you create the
    -+startActivity()}. Instead, you must declare the intended component type when you create the
    - {@link android.app.PendingIntent} by calling the respective creator method:</p>
    - 
    - <ul>
    -@@ -677,14 +685,14 @@ startActivity()}. You must instead declare the intended component type when you
    - </ul>
    - 
    - <p>Unless your app is <em>receiving</em> pending intents from other apps,
    --the above methods to create a {@link android.app.PendingIntent} are the only
    --{@link android.app.PendingIntent} methods you'll probably ever need.</p>
    -+the above methods to create a {@link android.app.PendingIntent} are probably the only
    -+{@link android.app.PendingIntent} methods you'll ever need.</p>
    - 
    - <p>Each method takes the current app {@link android.content.Context}, the
    - {@link android.content.Intent} you want to wrap, and one or more flags that specify
    - how the intent should be used (such as whether the intent can be used more than once).</p>
    - 
    --<p>More information about using pending intents is provided with the documentation for each
    -+<p>For more information about using pending intents, see the documentation for each
    - of the respective use cases, such as in the <a
    - href="{@docRoot}guide/topics/ui/notifiers/notifications.html">Notifications</a>
    - and <a href="{@docRoot}guide/topics/appwidgets/index.html">App Widgets</a> API guides.</p>
    -@@ -695,27 +703,27 @@ and <a href="{@docRoot}guide/topics/appwidgets/index.html">App Widgets</a> API g
    - 
    - 
    - 
    --<h2 id="Resolution">Intent Resolution</h2>
    -+<h2 id="Resolution">Intent resolution</h2>
    - 
    - 
    - <p>When the system receives an implicit intent to start an activity, it searches for the
    --best activity for the intent by comparing the intent to intent filters based on three aspects:</p>
    -+best activity for the intent by comparing the it to intent filters based on three aspects:</p>
    - 
    - <ul>
    --  <li>The intent action
    --  <li>The intent data (both URI and data type)
    --  <li>The intent category
    -+  <li>Action.
    -+  <li>Data (both URI and data type).
    -+  <li>Category.
    - </ul>
    - 
    --<p>The following sections describe how intents are matched to the appropriate component(s)
    --in terms of how the intent filter is declared in an app's manifest file.</p>
    -+<p>The following sections describe how intents are matched to the appropriate components
    -+according to the intent filter declaration in an app's manifest file.</p>
    - 
    - 
    - <h3 id="ActionTest">Action test</h3>
    - 
    - <p>To specify accepted intent actions, an intent filter can declare zero or more
    - <a href="{@docRoot}guide/topics/manifest/action-element.html">{@code
    --<action>}</a> elements.  For example:</p>
    -+&lt;action&gt;}</a> elements, as shown in the following example:</p>
    - 
    - <pre>
    - &lt;intent-filter&gt;
    -@@ -725,13 +733,13 @@ in terms of how the intent filter is declared in an app's manifest file.</p>
    - &lt;/intent-filter&gt;
    - </pre>
    - 
    --<p>To get through this filter, the action specified in the {@link android.content.Intent}
    -+<p>To pass this filter, the action specified in the {@link android.content.Intent}
    -   must match one of the actions listed in the filter.</p>
    - 
    - <p>If the filter does not list any actions, there is nothing for an
    - intent to match, so all intents fail the test. However, if an {@link android.content.Intent}
    --does not specify an action, it will pass the test (as long as the filter
    --contains at least one action).</p>
    -+does not specify an action, it passes the test as long as the filter
    -+contains at least one action.</p>
    - 
    - 
    - 
    -@@ -739,7 +747,7 @@ contains at least one action).</p>
    - 
    - <p>To specify accepted intent categories, an intent filter can declare zero or more
    - <a href="{@docRoot}guide/topics/manifest/category-element.html">{@code
    --<category>}</a> elements.  For example:</p>
    -+<category>}</a> elements, as shown in the following example:</p>
    - 
    - <pre>
    - &lt;intent-filter&gt;
    -@@ -752,17 +760,17 @@ contains at least one action).</p>
    - <p>For an intent to pass the category test, every category in the {@link android.content.Intent}
    - must match a category in the filter. The reverse is not necessary&mdash;the intent filter may
    - declare more categories than are specified in the {@link android.content.Intent} and the
    --{@link android.content.Intent} will still pass. Therefore, an intent with no categories should
    --always pass this test, regardless of what categories are declared in the filter.</p>
    -+{@link android.content.Intent} still passes. Therefore, an intent with no categories
    -+always passes this test, regardless of what categories are declared in the filter.</p>
    - 
    - <p class="note"><strong>Note:</strong>
    --Android automatically applies the the {@link android.content.Intent#CATEGORY_DEFAULT} category
    -+Android automatically applies the {@link android.content.Intent#CATEGORY_DEFAULT} category
    - to all implicit intents passed to {@link
    - android.content.Context#startActivity startActivity()} and {@link
    - android.app.Activity#startActivityForResult startActivityForResult()}.
    --So if you want your activity to receive implicit intents, it must
    --include a category for {@code "android.intent.category.DEFAULT"} in its intent filters (as
    --shown in the previous {@code <intent-filter>} example.</p>
    -+If you want your activity to receive implicit intents, it must
    -+include a category for {@code "android.intent.category.DEFAULT"} in its intent filters, as
    -+shown in the previous {@code &lt;intent-filter>} example.</p>
    - 
    - 
    - 
    -@@ -770,7 +778,7 @@ shown in the previous {@code <intent-filter>} example.</p>
    - 
    - <p>To specify accepted intent data, an intent filter can declare zero or more
    - <a href="{@docRoot}guide/topics/manifest/data-element.html">{@code
    --<data>}</a> elements.  For example:</p>
    -+&lt;data&gt;}</a> elements, as shown in the following example:</p>
    - 
    - <pre>
    - &lt;intent-filter&gt;
    -@@ -781,15 +789,16 @@ shown in the previous {@code <intent-filter>} example.</p>
    - </pre>
    - 
    - <p>Each <code><a href="{@docRoot}guide/topics/manifest/data-element.html">&lt;data&gt;</a></code>
    --element can specify a URI structure and a data type (MIME media type).  There are separate
    --attributes &mdash; {@code scheme}, {@code host}, {@code port},
    --and {@code path} &mdash; for each part of the URI:
    -+element can specify a URI structure and a data type (MIME media type).
    -+ Each part of the URI is a separate
    -+attribute: {@code scheme}, {@code host}, {@code port},
    -+and {@code path}:
    - </p>
    - 
    --<p style="margin-left: 2em">{@code <scheme>://<host>:<port>/<path>}</p>
    -+<p style="margin-left: 2em">{@code &lt;scheme>://&lt;host>:&lt;port>/&lt;path>}</p>
    - 
    - <p>
    --For example:
    -+The following example shows possible values for these attributes:
    - </p>
    - 
    - <p style="margin-left: 2em">{@code content://com.example.project:200/folder/subfolder/etc}</p>
    -@@ -799,7 +808,7 @@ the port is {@code 200}, and the path is {@code folder/subfolder/etc}.
    - </p>
    - 
    - <p>Each of these attributes is optional in a <a
    --href="{@docRoot}guide/topics/manifest/data-element.html">{@code <data>}</a> element,
    -+href="{@docRoot}guide/topics/manifest/data-element.html">{@code &lt;data>}</a> element,
    - but there are linear dependencies:</p>
    - <ul>
    -   <li>If a scheme is not specified, the host is ignored.</li>
    -@@ -842,17 +851,17 @@ type matches a type listed in the filter.  It passes the URI part of the test
    - either if its URI matches a URI in the filter or if it has a {@code content:}
    - or {@code file:} URI and the filter does not specify a URI.  In other words,
    - a component is presumed to support {@code content:} and {@code file:} data if
    --its filter lists <em>only</em> a MIME type.</p></li>
    -+its filter lists <em>only</em> a MIME type.</li>
    - </ol>
    - 
    - <p>
    - This last rule, rule (d), reflects the expectation
    - that components are able to get local data from a file or content provider.
    --Therefore, their filters can list just a data type and do not need to explicitly
    -+Therefore, their filters can list just a data type and don't need to explicitly
    - name the {@code content:} and {@code file:} schemes.
    --This is a typical case.  A <a
    --href="{@docRoot}guide/topics/manifest/data-element.html">{@code <data>}</a> element
    --like the following, for example, tells Android that the component can get image data from a content
    -+The following example shows a typical case in which a <a
    -+href="{@docRoot}guide/topics/manifest/data-element.html">{@code &lt;data>}</a> element
    -+ tells Android that the component can get image data from a content
    - provider and display it:
    - </p>
    - 
    -@@ -863,14 +872,15 @@ provider and display it:
    - &lt;/intent-filter&gt;</pre>
    - 
    - <p>
    --Because most available data is dispensed by content providers, filters that
    --specify a data type but not a URI are perhaps the most common.
    -+Filters that
    -+specify a data type but not a URI are perhaps the most common because most available
    -+ data is dispensed by content providers.
    - </p>
    - 
    - <p>
    --Another common configuration is filters with a scheme and a data type.  For
    -+Another common configuration is a filter with a scheme and a data type.  For
    - example, a <a
    --href="{@docRoot}guide/topics/manifest/data-element.html">{@code <data>}</a>
    -+href="{@docRoot}guide/topics/manifest/data-element.html">{@code &lt;data>}</a>
    - element like the following tells Android that
    - the component can retrieve video data from the network in order to perform the action:
    - </p>
    -@@ -894,7 +904,7 @@ by finding all the  activities with intent filters that specify the
    - 
    - <p>Your application can use intent matching in a similar way.
    - The {@link android.content.pm.PackageManager} has a set of {@code query...()}
    --methods that return all components that can accept a particular intent, and
    -+methods that return all components that can accept a particular intent and
    - a similar series of {@code resolve...()} methods that determine the best
    - component to respond to an intent.  For example,
    - {@link android.content.pm.PackageManager#queryIntentActivities
    -@@ -907,7 +917,3 @@ can respond.  There's a similar method,
    - {@link android.content.pm.PackageManager#queryBroadcastReceivers
    - queryBroadcastReceivers()}, for broadcast receivers.
    - </p>
    --
    --
    --
    --
    -diff --git a/docs/html/guide/components/services.jd b/docs/html/guide/components/services.jd
    -index e646a17..a7ed718 100644
    ---- a/docs/html/guide/components/services.jd
    -+++ b/docs/html/guide/components/services.jd
    -@@ -5,11 +5,11 @@ page.title=Services
    - <ol id="qv">
    - <h2>In this document</h2>
    - <ol>
    --<li><a href="#Basics">The Basics</a></li>
    -+<li><a href="#Basics">The basics</a></li>
    - <ol>
    -   <li><a href="#Declaring">Declaring a service in the manifest</a></li>
    - </ol>
    --<li><a href="#CreatingAService">Creating a Started Service</a>
    -+<li><a href="#CreatingAService">Creating a started service</a>
    -   <ol>
    -     <li><a href="#ExtendingIntentService">Extending the IntentService class</a></li>
    -     <li><a href="#ExtendingService">Extending the Service class</a></li>
    -@@ -17,10 +17,10 @@ page.title=Services
    -     <li><a href="#Stopping">Stopping a service</a></li>
    -   </ol>
    - </li>
    --<li><a href="#CreatingBoundService">Creating a Bound Service</a></li>
    --<li><a href="#Notifications">Sending Notifications to the User</a></li>
    --<li><a href="#Foreground">Running a Service in the Foreground</a></li>
    --<li><a href="#Lifecycle">Managing the Lifecycle of a Service</a>
    -+<li><a href="#CreatingBoundService">Creating a bound service</a></li>
    -+<li><a href="#Notifications">Sending notifications to the user</a></li>
    -+<li><a href="#Foreground">Running a service in the foreground</a></li>
    -+<li><a href="#Lifecycle">Managing the lifecycle of a service</a>
    - <ol>
    -   <li><a href="#LifecycleCallbacks">Implementing the lifecycle callbacks</a></li>
    - </ol>
    -@@ -48,70 +48,80 @@ page.title=Services
    - 
    - </div>
    - 
    --
    - <p>A {@link android.app.Service} is an application component that can perform
    --long-running operations in the background and does not provide a user interface. Another
    --application component can start a service and it will continue to run in the background even if the
    -+long-running operations in the background, and it does not provide a user interface. Another
    -+application component can start a service, and it continues to run in the background even if the
    - user switches to another application. Additionally, a component can bind to a service to
    --interact with it and even perform interprocess communication (IPC). For example, a service might
    -+interact with it and even perform interprocess communication (IPC). For example, a service can
    - handle network transactions, play music, perform file I/O, or interact with a content provider, all
    - from the background.</p>
    - 
    --<p>A service can essentially take two forms:</p>
    -+<p>These are the three different types of services:</p>
    - 
    - <dl>
    -+  <dt>Scheduled</dt>
    -+  <dd>A service is <em>scheduled</em> when an API such as the {@link android.app.job.JobScheduler},
    -+  introduced in Android 5.0 (API level 21), launches the service. You can use the
    -+  {@link android.app.job.JobScheduler} by registering jobs and specifying their requirements for
    -+  network and timing. The system then gracefully schedules the jobs for execution at the
    -+  appropriate times. The {@link android.app.job.JobScheduler} provides many methods to define
    -+  service-execution conditions.
    -+    <p class="note"><strong>Note:</strong> If your app targets Android 5.0 (API level 21), Google
    -+    recommends that you use the {@link android.app.job.JobScheduler} to execute background
    -+    services. For more information about using this class, see the
    -+    {@link android.app.job.JobScheduler} reference documentation.</p></dd>
    -   <dt>Started</dt>
    --  <dd>A service is "started" when an application component (such as an activity) starts it by
    --calling {@link android.content.Context#startService startService()}. Once started, a service
    --can run in the background indefinitely, even if the component that started it is destroyed. Usually,
    --a started service performs a single operation and does not return a result to the caller.
    --For example, it might download or upload a file over the network. When the operation is done, the
    --service should stop itself.</dd>
    -+  <dd>A service is <em>started</em> when an application component (such as an activity)
    -+  calls {@link android.content.Context#startService startService()}. After it's started, a
    -+  service can run in the background indefinitely, even if the component that started it is
    -+  destroyed. Usually, a started service performs a single operation and does not return a result to
    -+  the caller. For example, it can download or upload a file over the network. When the operation is
    -+  complete, the service should stop itself.</dd>
    -   <dt>Bound</dt>
    --  <dd>A service is "bound" when an application component binds to it by calling {@link
    --android.content.Context#bindService bindService()}. A bound service offers a client-server
    --interface that allows components to interact with the service, send requests, get results, and even
    --do so across processes with interprocess communication (IPC). A bound service runs only as long as
    --another application component is bound to it. Multiple components can bind to the service at once,
    --but when all of them unbind, the service is destroyed.</dd>
    -+  <dd>A service is <em>bound</em> when an application component binds to it by calling {@link
    -+  android.content.Context#bindService bindService()}. A bound service offers a client-server
    -+  interface that allows components to interact with the service, send requests, receive results,
    -+  and even do so across processes with interprocess communication (IPC). A bound service runs only
    -+  as long as another application component is bound to it. Multiple components can bind to the
    -+  service at once, but when all of them unbind, the service is destroyed.</dd>
    - </dl>
    - 
    --<p>Although this documentation generally discusses these two types of services separately, your
    --service can work both ways&mdash;it can be started (to run indefinitely) and also allow binding.
    --It's simply a matter of whether you implement a couple callback methods: {@link
    -+<p>Although this documentation generally discusses started and bound services separately,
    -+your service can work both ways&mdash;it can be started (to run indefinitely) and also allow
    -+binding. It's simply a matter of whether you implement a couple of callback methods: {@link
    - android.app.Service#onStartCommand onStartCommand()} to allow components to start it and {@link
    - android.app.Service#onBind onBind()} to allow binding.</p>
    - 
    - <p>Regardless of whether your application is started, bound, or both, any application component
    --can use the service (even from a separate application), in the same way that any component can use
    -+can use the service (even from a separate application) in the same way that any component can use
    - an activity&mdash;by starting it with an {@link android.content.Intent}. However, you can declare
    --the service as private, in the manifest file, and block access from other applications. This is
    --discussed more in the section about <a href="#Declaring">Declaring the service in the
    -+the service as <em>private</em> in the manifest file and block access from other applications.
    -+This is discussed more in the section about <a href="#Declaring">Declaring the service in the
    - manifest</a>.</p>
    - 
    - <p class="caution"><strong>Caution:</strong> A service runs in the
    --main thread of its hosting process&mdash;the service does <strong>not</strong> create its own thread
    --and does <strong>not</strong> run in a separate process (unless you specify otherwise). This means
    --that, if your service is going to do any CPU intensive work or blocking operations (such as MP3
    --playback or networking), you should create a new thread within the service to do that work. By using
    --a separate thread, you will reduce the risk of Application Not Responding (ANR) errors and the
    --application's main thread can remain dedicated to user interaction with your activities.</p>
    --
    -+main thread of its hosting process; the service does <strong>not</strong> create its own
    -+thread and does <strong>not</strong> run in a separate process unless you specify otherwise. If
    -+your service is going to perform any CPU-intensive work or blocking operations, such as MP3
    -+playback or networking, you should create a new thread within the service to complete that work.
    -+By using a separate thread, you can reduce the risk of Application Not Responding (ANR) errors,
    -+and the application's main thread can remain dedicated to user interaction with your
    -+activities.</p>
    - 
    --<h2 id="Basics">The Basics</h2>
    -+<h2 id="Basics">The basics</h2>
    - 
    - <div class="sidebox-wrapper">
    - <div class="sidebox">
    -   <h3>Should you use a service or a thread?</h3>
    --  <p>A service is simply a component that can run in the background even when the user is not
    --interacting with your application. Thus, you should create a service only if that is what you
    -+  <p>A service is simply a component that can run in the background, even when the user is not
    -+interacting with your application, so you should create a service only if that is what you
    - need.</p>
    --  <p>If you need to perform work outside your main thread, but only while the user is interacting
    --with your application, then you should probably instead create a new thread and not a service. For
    --example, if you want to play some music, but only while your activity is running, you might create
    -+  <p>If you must perform work outside of your main thread, but only while the user is interacting
    -+with your application, you should instead create a new thread. For example, if you want to
    -+play some music, but only while your activity is running, you might create
    - a thread in {@link android.app.Activity#onCreate onCreate()}, start running it in {@link
    --android.app.Activity#onStart onStart()}, then stop it in {@link android.app.Activity#onStop
    --onStop()}. Also consider using {@link android.os.AsyncTask} or {@link android.os.HandlerThread},
    -+android.app.Activity#onStart onStart()}, and stop it in {@link android.app.Activity#onStop
    -+onStop()}. Also consider using {@link android.os.AsyncTask} or {@link android.os.HandlerThread}
    - instead of the traditional {@link java.lang.Thread} class. See the <a
    - href="{@docRoot}guide/components/processes-and-threads.html#Threads">Processes and
    - Threading</a> document for more information about threads.</p>
    -@@ -121,78 +131,81 @@ blocking operations.</p>
    - </div>
    - </div>
    - 
    --<p>To create a service, you must create a subclass of {@link android.app.Service} (or one
    --of its existing subclasses). In your implementation, you need to override some callback methods that
    --handle key aspects of the service lifecycle and provide a mechanism for components to bind to
    --the service, if appropriate. The most important callback methods you should override are:</p>
    -+<p>To create a service, you must create a subclass of {@link android.app.Service} or use one
    -+of its existing subclasses. In your implementation, you must override some callback methods that
    -+handle key aspects of the service lifecycle and provide a mechanism that allows the components to
    -+bind to the service, if appropriate. These are the most important callback methods that you should
    -+override:</p>
    - 
    - <dl>
    -   <dt>{@link android.app.Service#onStartCommand onStartCommand()}</dt>
    --    <dd>The system calls this method when another component, such as an activity,
    --requests that the service be started, by calling {@link android.content.Context#startService
    --startService()}. Once this method executes, the service is started and can run in the
    -+    <dd>The system invokes this method by calling {@link android.content.Context#startService
    -+startService()} when another component (such as an activity) requests that the service be started.
    -+When this method executes, the service is started and can run in the
    - background indefinitely. If you implement this, it is your responsibility to stop the service when
    --its work is done, by calling {@link android.app.Service#stopSelf stopSelf()} or {@link
    --android.content.Context#stopService stopService()}. (If you only want to provide binding, you don't
    --need to implement this method.)</dd>
    -+its work is complete by calling {@link android.app.Service#stopSelf stopSelf()} or {@link
    -+android.content.Context#stopService stopService()}. If you only want to provide binding, you don't
    -+need to implement this method.</dd>
    -   <dt>{@link android.app.Service#onBind onBind()}</dt>
    --    <dd>The system calls this method when another component wants to bind with the
    --service (such as to perform RPC), by calling {@link android.content.Context#bindService
    --bindService()}. In your implementation of this method, you must provide an interface that clients
    --use to communicate with the service, by returning an {@link android.os.IBinder}. You must always
    --implement this method, but if you don't want to allow binding, then you should return null.</dd>
    -+    <dd>The system invokes this method by calling {@link android.content.Context#bindService
    -+bindService()} when another component wants to bind with the service (such as to perform RPC).
    -+In your implementation of this method, you must provide an interface that clients
    -+use to communicate with the service by returning an {@link android.os.IBinder}. You must always
    -+implement this method; however, if you don't want to allow binding, you should return
    -+null.</dd>
    -   <dt>{@link android.app.Service#onCreate()}</dt>
    --    <dd>The system calls this method when the service is first created, to perform one-time setup
    --procedures (before it calls either {@link android.app.Service#onStartCommand onStartCommand()} or
    -+    <dd>The system invokes this method to perform one-time setup procedures when the service is
    -+initially created (before it calls either
    -+{@link android.app.Service#onStartCommand onStartCommand()} or
    - {@link android.app.Service#onBind onBind()}). If the service is already running, this method is not
    - called.</dd>
    -   <dt>{@link android.app.Service#onDestroy()}</dt>
    --    <dd>The system calls this method when the service is no longer used and is being destroyed.
    -+    <dd>The system invokes this method when the service is no longer used and is being destroyed.
    - Your service should implement this to clean up any resources such as threads, registered
    --listeners, receivers, etc. This is the last call the service receives.</dd>
    -+listeners, or receivers. This is the last call that the service receives.</dd>
    - </dl>
    - 
    - <p>If a component starts the service by calling {@link
    - android.content.Context#startService startService()} (which results in a call to {@link
    --android.app.Service#onStartCommand onStartCommand()}), then the service
    --remains running until it stops itself with {@link android.app.Service#stopSelf()} or another
    -+android.app.Service#onStartCommand onStartCommand()}), the service
    -+continues to run until it stops itself with {@link android.app.Service#stopSelf()} or another
    - component stops it by calling {@link android.content.Context#stopService stopService()}.</p>
    - 
    - <p>If a component calls
    --{@link android.content.Context#bindService bindService()} to create the service (and {@link
    --android.app.Service#onStartCommand onStartCommand()} is <em>not</em> called), then the service runs
    --only as long as the component is bound to it. Once the service is unbound from all clients, the
    --system destroys it.</p>
    -+{@link android.content.Context#bindService bindService()} to create the service and {@link
    -+android.app.Service#onStartCommand onStartCommand()} is <em>not</em> called, the service runs
    -+only as long as the component is bound to it. After the service is unbound from all of its clients,
    -+the system destroys it.</p>
    - 
    --<p>The Android system will force-stop a service only when memory is low and it must recover system
    -+<p>The Android system force-stops a service only when memory is low and it must recover system
    - resources for the activity that has user focus. If the service is bound to an activity that has user
    --focus, then it's less likely to be killed, and if the service is declared to <a
    --href="#Foreground">run in the foreground</a> (discussed later), then it will almost never be killed.
    --Otherwise, if the service was started and is long-running, then the system will lower its position
    --in the list of background tasks over time and the service will become highly susceptible to
    --killing&mdash;if your service is started, then you must design it to gracefully handle restarts
    -+focus, it's less likely to be killed; if the service is declared to <a
    -+href="#Foreground">run in the foreground</a>, it's rarely killed.
    -+If the service is started and is long-running, the system lowers its position
    -+in the list of background tasks over time, and the service becomes highly susceptible to
    -+killing&mdash;if your service is started, you must design it to gracefully handle restarts
    - by the system. If the system kills your service, it restarts it as soon as resources become
    --available again (though this also depends on the value you return from {@link
    --android.app.Service#onStartCommand onStartCommand()}, as discussed later). For more information
    -+available, but this also depends on the value that you return from {@link
    -+android.app.Service#onStartCommand onStartCommand()}. For more information
    - about when the system might destroy a service, see the <a
    - href="{@docRoot}guide/components/processes-and-threads.html">Processes and Threading</a>
    - document.</p>
    - 
    --<p>In the following sections, you'll see how you can create each type of service and how to use
    --it from other application components.</p>
    --
    --
    -+<p>In the following sections, you'll see how you can create the
    -+{@link android.content.Context#startService startService()} and
    -+{@link android.content.Context#bindService bindService()} service methods, as well as how to use
    -+them from other application components.</p>
    - 
    - <h3 id="Declaring">Declaring a service in the manifest</h3>
    - 
    --<p>Like activities (and other components), you must declare all services in your application's
    --manifest file.</p>
    -+<p>You must declare all services in your application's
    -+manifest file, just as you do for activities and other components.</p>
    - 
    - <p>To declare your service, add a <a
    --href="{@docRoot}guide/topics/manifest/service-element.html">{@code <service>}</a> element
    -+href="{@docRoot}guide/topics/manifest/service-element.html">{@code &lt;service&gt;}</a> element
    - as a child of the <a
    --href="{@docRoot}guide/topics/manifest/application-element.html">{@code <application>}</a>
    --element. For example:</p>
    -+href="{@docRoot}guide/topics/manifest/application-element.html">{@code &lt;application&gt;}</a>
    -+element. Here is an example:</p>
    - 
    - <pre>
    - &lt;manifest ... &gt;
    -@@ -205,48 +218,44 @@ element. For example:</p>
    - </pre>
    - 
    - <p>See the <a
    --href="{@docRoot}guide/topics/manifest/service-element.html">{@code <service>}</a> element
    -+href="{@docRoot}guide/topics/manifest/service-element.html">{@code &lt;service&gt;}</a> element
    - reference for more information about declaring your service in the manifest.</p>
    - 
    --<p>There are other attributes you can include in the <a
    --href="{@docRoot}guide/topics/manifest/service-element.html">{@code <service>}</a> element to
    --define properties such as permissions required to start the service and the process in
    -+<p>There are other attributes that you can include in the <a
    -+href="{@docRoot}guide/topics/manifest/service-element.html">{@code &lt;service&gt;}</a> element to
    -+define properties such as the permissions that are required to start the service and the process in
    - which the service should run. The <a
    - href="{@docRoot}guide/topics/manifest/service-element.html#nm">{@code android:name}</a>
    --attribute is the only required attribute&mdash;it specifies the class name of the service. Once
    --you publish your application, you should not change this name, because if you do, you risk breaking
    -+attribute is the only required attribute&mdash;it specifies the class name of the service. After
    -+you publish your application, leave this name unchanged to avoid the risk of breaking
    - code due to dependence on explicit intents to start or bind the service (read the blog post, <a
    - href="http://android-developers.blogspot.com/2011/06/things-that-cannot-change.html">Things
    - That Cannot Change</a>).
    - 
    --<p>To ensure your app is secure, <strong>always use an explicit intent when starting or binding
    --your {@link android.app.Service}</strong> and do not declare intent filters for the service. If
    --it's critical that you allow for some amount of ambiguity as to which service starts, you can
    --supply intent filters for your services and exclude the component name from the {@link
    --android.content.Intent}, but you then must set the package for the intent with {@link
    --android.content.Intent#setPackage setPackage()}, which provides sufficient disambiguation for the
    --target service.</p>
    -+<p class="caution"><strong>Caution</strong>: To ensure that your app is secure, always use an
    -+explicit intent when starting a {@link android.app.Service} and do not declare intent filters for
    -+your services. Using an implicit intent to start a service is a security hazard because you cannot
    -+be certain of the service that will respond to the intent, and the user cannot see which service
    -+starts. Beginning with Android 5.0 (API level 21), the system throws an exception if you call
    -+{@link android.content.Context#bindService bindService()} with an implicit intent.</p>
    - 
    --<p>Additionally, you can ensure that your service is available to only your app by
    -+<p>You can ensure that your service is available to only your app by
    - including the <a
    - href="{@docRoot}guide/topics/manifest/service-element.html#exported">{@code android:exported}</a>
    --attribute and setting it to {@code "false"}. This effectively stops other apps from starting your
    -+attribute and setting it to {@code false}. This effectively stops other apps from starting your
    - service, even when using an explicit intent.</p>
    - 
    --
    --
    --
    --<h2 id="CreatingStartedService">Creating a Started Service</h2>
    -+<h2 id="CreatingStartedService">Creating a started service</h2>
    - 
    - <p>A started service is one that another component starts by calling {@link
    --android.content.Context#startService startService()}, resulting in a call to the service's
    -+android.content.Context#startService startService()}, which results in a call to the service's
    - {@link android.app.Service#onStartCommand onStartCommand()} method.</p>
    - 
    - <p>When a service is started, it has a lifecycle that's independent of the
    --component that started it and the service can run in the background indefinitely, even if
    -+component that started it. The service can run in the background indefinitely, even if
    - the component that started it is destroyed. As such, the service should stop itself when its job
    --is done by calling {@link android.app.Service#stopSelf stopSelf()}, or another component can stop it
    --by calling {@link android.content.Context#stopService stopService()}.</p>
    -+is complete by calling {@link android.app.Service#stopSelf stopSelf()}, or another component can
    -+stop it by calling {@link android.content.Context#stopService stopService()}.</p>
    - 
    - <p>An application component such as an activity can start the service by calling {@link
    - android.content.Context#startService startService()} and passing an {@link android.content.Intent}
    -@@ -254,65 +263,65 @@ that specifies the service and includes any data for the service to use. The ser
    - this {@link android.content.Intent} in the {@link android.app.Service#onStartCommand
    - onStartCommand()} method.</p>
    - 
    --<p>For instance, suppose an activity needs to save some data to an online database. The activity can
    --start a companion service and deliver it the data to save by passing an intent to {@link
    -+<p>For instance, suppose an activity needs to save some data to an online database. The activity
    -+can start a companion service and deliver it the data to save by passing an intent to {@link
    - android.content.Context#startService startService()}. The service receives the intent in {@link
    --android.app.Service#onStartCommand onStartCommand()}, connects to the Internet and performs the
    --database transaction. When the transaction is done, the service stops itself and it is
    -+android.app.Service#onStartCommand onStartCommand()}, connects to the Internet, and performs the
    -+database transaction. When the transaction is complete, the service stops itself and is
    - destroyed.</p>
    - 
    - <p class="caution"><strong>Caution:</strong> A service runs in the same process as the application
    --in which it is declared and in the main thread of that application, by default. So, if your service
    -+in which it is declared and in the main thread of that application by default. If your service
    - performs intensive or blocking operations while the user interacts with an activity from the same
    --application, the service will slow down activity performance. To avoid impacting application
    --performance, you should start a new thread inside the service.</p>
    -+application, the service slows down activity performance. To avoid impacting application
    -+performance, start a new thread inside the service.</p>
    - 
    - <p>Traditionally, there are two classes you can extend to create a started service:</p>
    -+
    - <dl>
    -   <dt>{@link android.app.Service}</dt>
    --  <dd>This is the base class for all services. When you extend this class, it's important that
    --you create a new thread in which to do all the service's work, because the service uses your
    --application's main thread, by default, which could slow the performance of any activity your
    -+  <dd>This is the base class for all services. When you extend this class, it's important to
    -+create a new thread in which the service can complete all of its work; the service uses your
    -+application's main thread by default, which can slow the performance of any activity that your
    - application is running.</dd>
    -   <dt>{@link android.app.IntentService}</dt>
    --  <dd>This is a subclass of {@link android.app.Service} that uses a worker thread to handle all
    --start requests, one at a time. This is the best option if you don't require that your service
    --handle multiple requests simultaneously. All you need to do is implement {@link
    -+  <dd>This is a subclass of {@link android.app.Service} that uses a worker thread to handle all of
    -+the start requests, one at a time. This is the best option if you don't require that your service
    -+handle multiple requests simultaneously. Implement {@link
    - android.app.IntentService#onHandleIntent onHandleIntent()}, which receives the intent for each
    --start request so you can do the background work.</dd>
    -+start request so that you can complete the background work.</dd>
    - </dl>
    - 
    - <p>The following sections describe how you can implement your service using either one for these
    - classes.</p>
    - 
    --
    - <h3 id="ExtendingIntentService">Extending the IntentService class</h3>
    - 
    --<p>Because most started services don't need to handle multiple requests simultaneously
    --(which can actually be a dangerous multi-threading scenario), it's probably best if you
    -+<p>Because most of the started services don't need to handle multiple requests simultaneously
    -+(which can actually be a dangerous multi-threading scenario), it's best that you
    - implement your service using the {@link android.app.IntentService} class.</p>
    - 
    --<p>The {@link android.app.IntentService} does the following:</p>
    -+<p>The {@link android.app.IntentService} class does the following:</p>
    - 
    - <ul>
    --  <li>Creates a default worker thread that executes all intents delivered to {@link
    --android.app.Service#onStartCommand onStartCommand()} separate from your application's main
    -+  <li>It creates a default worker thread that executes all of the intents that are delivered to
    -+{@link android.app.Service#onStartCommand onStartCommand()}, separate from your application's main
    - thread.</li>
    -   <li>Creates a work queue that passes one intent at a time to your {@link
    - android.app.IntentService#onHandleIntent onHandleIntent()} implementation, so you never have to
    - worry about multi-threading.</li>
    --  <li>Stops the service after all start requests have been handled, so you never have to call
    -+  <li>Stops the service after all of the start requests are handled, so you never have to call
    - {@link android.app.Service#stopSelf}.</li>
    --  <li>Provides default implementation of {@link android.app.IntentService#onBind onBind()} that
    --returns null.</li>
    -+  <li>Provides a default implementation of {@link android.app.IntentService#onBind onBind()}
    -+  that returns null.</li>
    -   <li>Provides a default implementation of {@link android.app.IntentService#onStartCommand
    - onStartCommand()} that sends the intent to the work queue and then to your {@link
    - android.app.IntentService#onHandleIntent onHandleIntent()} implementation.</li>
    - </ul>
    - 
    --<p>All this adds up to the fact that all you need to do is implement {@link
    --android.app.IntentService#onHandleIntent onHandleIntent()} to do the work provided by the
    --client. (Though, you also need to provide a small constructor for the service.)</p>
    -+<p>To complete the work that is provided by the client, implement {@link
    -+android.app.IntentService#onHandleIntent onHandleIntent()}.
    -+However, you also need to provide a small constructor for the service.</p>
    - 
    - <p>Here's an example implementation of {@link android.app.IntentService}:</p>
    - 
    -@@ -352,12 +361,12 @@ android.app.IntentService#onHandleIntent onHandleIntent()}.</p>
    - <p>If you decide to also override other callback methods, such as {@link
    - android.app.IntentService#onCreate onCreate()}, {@link
    - android.app.IntentService#onStartCommand onStartCommand()}, or {@link
    --android.app.IntentService#onDestroy onDestroy()}, be sure to call the super implementation, so
    -+android.app.IntentService#onDestroy onDestroy()}, be sure to call the super implementation so
    - that the {@link android.app.IntentService} can properly handle the life of the worker thread.</p>
    - 
    - <p>For example, {@link android.app.IntentService#onStartCommand onStartCommand()} must return
    --the default implementation (which is how the intent gets delivered to {@link
    --android.app.IntentService#onHandleIntent onHandleIntent()}):</p>
    -+the default implementation, which is how the intent is delivered to {@link
    -+android.app.IntentService#onHandleIntent onHandleIntent()}:</p>
    - 
    - <pre>
    - &#64;Override
    -@@ -369,22 +378,21 @@ public int onStartCommand(Intent intent, int flags, int startId) {
    - 
    - <p>Besides {@link android.app.IntentService#onHandleIntent onHandleIntent()}, the only method
    - from which you don't need to call the super class is {@link android.app.IntentService#onBind
    --onBind()} (but you only need to implement that if your service allows binding).</p>
    -+onBind()}. You need to implement this only if your service allows binding.</p>
    - 
    - <p>In the next section, you'll see how the same kind of service is implemented when extending
    --the base {@link android.app.Service} class, which is a lot more code, but which might be
    -+the base {@link android.app.Service} class, which uses more code, but might be
    - appropriate if you need to handle simultaneous start requests.</p>
    - 
    --
    - <h3 id="ExtendingService">Extending the Service class</h3>
    - 
    --<p>As you saw in the previous section, using {@link android.app.IntentService} makes your
    -+<p>Using {@link android.app.IntentService} makes your
    - implementation of a started service very simple. If, however, you require your service to
    --perform multi-threading (instead of processing start requests through a work queue), then you
    -+perform multi-threading (instead of processing start requests through a work queue), you
    - can extend the {@link android.app.Service} class to handle each intent.</p>
    - 
    --<p>For comparison, the following example code is an implementation of the {@link
    --android.app.Service} class that performs the exact same work as the example above using {@link
    -+<p>For comparison, the following example code shows an implementation of the {@link
    -+android.app.Service} class that performs the same work as the previous example using {@link
    - android.app.IntentService}. That is, for each start request, it uses a worker thread to perform the
    - job and processes only one request at a time.</p>
    - 
    -@@ -460,20 +468,20 @@ public class HelloService extends Service {
    - 
    - <p>However, because you handle each call to {@link android.app.Service#onStartCommand
    - onStartCommand()} yourself, you can perform multiple requests simultaneously. That's not what
    --this example does, but if that's what you want, then you can create a new thread for each
    --request and run them right away (instead of waiting for the previous request to finish).</p>
    -+this example does, but if that's what you want, you can create a new thread for each
    -+request and run them right away instead of waiting for the previous request to finish.</p>
    - 
    - <p>Notice that the {@link android.app.Service#onStartCommand onStartCommand()} method must return an
    - integer. The integer is a value that describes how the system should continue the service in the
    --event that the system kills it (as discussed above, the default implementation for {@link
    --android.app.IntentService} handles this for you, though you are able to modify it). The return value
    -+event that the system kills it. The default implementation for {@link
    -+android.app.IntentService} handles this for you, but you are able to modify it. The return value
    - from {@link android.app.Service#onStartCommand onStartCommand()} must be one of the following
    - constants:</p>
    - 
    - <dl>
    -   <dt>{@link android.app.Service#START_NOT_STICKY}</dt>
    -     <dd>If the system kills the service after {@link android.app.Service#onStartCommand
    --onStartCommand()} returns, <em>do not</em> recreate the service, unless there are pending
    -+onStartCommand()} returns, <em>do not</em> recreate the service unless there are pending
    - intents to deliver. This is the safest option to avoid running your service when not necessary
    - and when your application can simply restart any unfinished jobs.</dd>
    -   <dt>{@link android.app.Service#START_STICKY}</dt>
    -@@ -481,9 +489,9 @@ and when your application can simply restart any unfinished jobs.</dd>
    - onStartCommand()} returns, recreate the service and call {@link
    - android.app.Service#onStartCommand onStartCommand()}, but <em>do not</em> redeliver the last intent.
    - Instead, the system calls {@link android.app.Service#onStartCommand onStartCommand()} with a
    --null intent, unless there were pending intents to start the service, in which case,
    -+null intent unless there are pending intents to start the service. In that case,
    - those intents are delivered. This is suitable for media players (or similar services) that are not
    --executing commands, but running indefinitely and waiting for a job.</dd>
    -+executing commands but are running indefinitely and waiting for a job.</dd>
    -   <dt>{@link android.app.Service#START_REDELIVER_INTENT}</dt>
    -     <dd>If the system kills the service after {@link android.app.Service#onStartCommand
    - onStartCommand()} returns, recreate the service and call {@link
    -@@ -494,35 +502,35 @@ actively performing a job that should be immediately resumed, such as downloadin
    - <p>For more details about these return values, see the linked reference documentation for each
    - constant.</p>
    - 
    --
    --
    --<h3 id="StartingAService">Starting a Service</h3>
    -+<h3 id="StartingAService">Starting a service</h3>
    - 
    - <p>You can start a service from an activity or other application component by passing an
    - {@link android.content.Intent} (specifying the service to start) to {@link
    - android.content.Context#startService startService()}. The Android system calls the service's {@link
    - android.app.Service#onStartCommand onStartCommand()} method and passes it the {@link
    --android.content.Intent}. (You should never call {@link android.app.Service#onStartCommand
    --onStartCommand()} directly.)</p>
    -+android.content.Intent}.
    -+
    -+<p class="note"><strong>Note</strong>: Never call
    -+{@link android.app.Service#onStartCommand onStartCommand()} directly.</p>
    - 
    - <p>For example, an activity can start the example service in the previous section ({@code
    - HelloService}) using an explicit intent with {@link android.content.Context#startService
    --startService()}:</p>
    -+startService()}, as shown here:</p>
    - 
    - <pre>
    - Intent intent = new Intent(this, HelloService.class);
    - startService(intent);
    - </pre>
    - 
    --<p>The {@link android.content.Context#startService startService()} method returns immediately and
    -+<p>The {@link android.content.Context#startService startService()} method returns immediately, and
    - the Android system calls the service's {@link android.app.Service#onStartCommand
    - onStartCommand()} method. If the service is not already running, the system first calls {@link
    --android.app.Service#onCreate onCreate()}, then calls {@link android.app.Service#onStartCommand
    --onStartCommand()}.</p>
    -+android.app.Service#onCreate onCreate()}, and then it calls
    -+{@link android.app.Service#onStartCommand onStartCommand()}.</p>
    - 
    --<p>If the service does not also provide binding, the intent delivered with {@link
    -+<p>If the service does not also provide binding, the intent that is delivered with {@link
    - android.content.Context#startService startService()} is the only mode of communication between the
    --application component and the service. However, if you want the service to send a result back, then
    -+application component and the service. However, if you want the service to send a result back,
    - the client that starts the service can create a {@link android.app.PendingIntent} for a broadcast
    - (with {@link android.app.PendingIntent#getBroadcast getBroadcast()}) and deliver it to the service
    - in the {@link android.content.Intent} that starts the service. The service can then use the
    -@@ -533,109 +541,102 @@ broadcast to deliver a result.</p>
    - the service (with {@link android.app.Service#stopSelf stopSelf()} or {@link
    - android.content.Context#stopService stopService()}) is required to stop it.</p>
    - 
    --
    - <h3 id="Stopping">Stopping a service</h3>
    - 
    - <p>A started service must manage its own lifecycle. That is, the system does not stop or
    - destroy the service unless it must recover system memory and the service
    --continues to run after {@link android.app.Service#onStartCommand onStartCommand()} returns. So,
    --the service must stop itself by calling {@link android.app.Service#stopSelf stopSelf()} or another
    -+continues to run after {@link android.app.Service#onStartCommand onStartCommand()} returns. The
    -+service must stop itself by calling {@link android.app.Service#stopSelf stopSelf()}, or another
    - component can stop it by calling {@link android.content.Context#stopService stopService()}.</p>
    - 
    - <p>Once requested to stop with {@link android.app.Service#stopSelf stopSelf()} or {@link
    - android.content.Context#stopService stopService()}, the system destroys the service as soon as
    - possible.</p>
    - 
    --<p>However, if your service handles multiple requests to {@link
    --android.app.Service#onStartCommand onStartCommand()} concurrently, then you shouldn't stop the
    --service when you're done processing a start request, because you might have since received a new
    -+<p>If your service handles multiple requests to {@link
    -+android.app.Service#onStartCommand onStartCommand()} concurrently, you shouldn't stop the
    -+service when you're done processing a start request, as you might have received a new
    - start request (stopping at the end of the first request would terminate the second one). To avoid
    - this problem, you can use {@link android.app.Service#stopSelf(int)} to ensure that your request to
    - stop the service is always based on the most recent start request. That is, when you call {@link
    - android.app.Service#stopSelf(int)}, you pass the ID of the start request (the <code>startId</code>
    - delivered to {@link android.app.Service#onStartCommand onStartCommand()}) to which your stop request
    --corresponds. Then if the service received a new start request before you were able to call {@link
    --android.app.Service#stopSelf(int)}, then the ID will not match and the service will not stop.</p>
    -+corresponds. Then, if the service receives a new start request before you are able to call {@link
    -+android.app.Service#stopSelf(int)}, the ID does not match and the service does not stop.</p>
    - 
    --<p class="caution"><strong>Caution:</strong> It's important that your application stops its services
    --when it's done working, to avoid wasting system resources and consuming battery power. If necessary,
    --other components can stop the service by calling {@link
    -+<p class="caution"><strong>Caution:</strong> To avoid wasting system resources and consuming
    -+battery power, ensure that your application stops its services when it's done working.
    -+If necessary, other components can stop the service by calling {@link
    - android.content.Context#stopService stopService()}. Even if you enable binding for the service,
    --you must always stop the service yourself if it ever received a call to {@link
    -+you must always stop the service yourself if it ever receives a call to {@link
    - android.app.Service#onStartCommand onStartCommand()}.</p>
    - 
    - <p>For more information about the lifecycle of a service, see the section below about <a
    - href="#Lifecycle">Managing the Lifecycle of a Service</a>.</p>
    - 
    --
    --
    --<h2 id="CreatingBoundService">Creating a Bound Service</h2>
    -+<h2 id="CreatingBoundService">Creating a bound service</h2>
    - 
    - <p>A bound service is one that allows application components to bind to it by calling {@link
    --android.content.Context#bindService bindService()} in order to create a long-standing connection
    --(and generally does not allow components to <em>start</em> it by calling {@link
    --android.content.Context#startService startService()}).</p>
    -+android.content.Context#bindService bindService()} to create a long-standing connection.
    -+It generally doesn't allow components to <em>start</em> it by calling {@link
    -+android.content.Context#startService startService()}.</p>
    - 
    --<p>You should create a bound service when you want to interact with the service from activities
    -+<p>Create a bound service when you want to interact with the service from activities
    - and other components in your application or to expose some of your application's functionality to
    --other applications, through interprocess communication (IPC).</p>
    -+other applications through interprocess communication (IPC).</p>
    - 
    --<p>To create a bound service, you must implement the {@link
    -+<p>To create a bound service, implement the {@link
    - android.app.Service#onBind onBind()} callback method to return an {@link android.os.IBinder} that
    - defines the interface for communication with the service. Other application components can then call
    - {@link android.content.Context#bindService bindService()} to retrieve the interface and
    - begin calling methods on the service. The service lives only to serve the application component that
    --is bound to it, so when there are no components bound to the service, the system destroys it
    --(you do <em>not</em> need to stop a bound service in the way you must when the service is started
    --through {@link android.app.Service#onStartCommand onStartCommand()}).</p>
    -+is bound to it, so when there are no components bound to the service, the system destroys it.
    -+You do <em>not</em> need to stop a bound service in the same way that you must when the service is
    -+started through {@link android.app.Service#onStartCommand onStartCommand()}.</p>
    - 
    --<p>To create a bound service, the first thing you must do is define the interface that specifies
    --how a client can communicate with the service. This interface between the service
    -+<p>To create a bound service, you must define the interface that specifies how a client can
    -+communicate with the service. This interface between the service
    - and a client must be an implementation of {@link android.os.IBinder} and is what your service must
    - return from the {@link android.app.Service#onBind
    --onBind()} callback method. Once the client receives the {@link android.os.IBinder}, it can begin
    -+onBind()} callback method. After the client receives the {@link android.os.IBinder}, it can begin
    - interacting with the service through that interface.</p>
    - 
    --<p>Multiple clients can bind to the service at once. When a client is done interacting with the
    --service, it calls {@link android.content.Context#unbindService unbindService()} to unbind. Once
    --there are no clients bound to the service, the system destroys the service.</p>
    -+<p>Multiple clients can bind to the service simultaneously. When a client is done interacting with
    -+the service, it calls {@link android.content.Context#unbindService unbindService()} to unbind.
    -+When there are no clients bound to the service, the system destroys the service.</p>
    - 
    --<p>There are multiple ways to implement a bound service and the implementation is more
    --complicated than a started service, so the bound service discussion appears in a separate
    --document about <a
    -+<p>There are multiple ways to implement a bound service, and the implementation is more
    -+complicated than a started service. For these reasons, the bound service discussion appears in a
    -+separate document about <a
    - href="{@docRoot}guide/components/bound-services.html">Bound Services</a>.</p>
    - 
    -+<h2 id="Notifications">Sending notifications to the user</h2>
    - 
    --
    --<h2 id="Notifications">Sending Notifications to the User</h2>
    --
    --<p>Once running, a service can notify the user of events using <a
    -+<p>When a service is running, it can notify the user of events using <a
    - href="{@docRoot}guide/topics/ui/notifiers/toasts.html">Toast Notifications</a> or <a
    - href="{@docRoot}guide/topics/ui/notifiers/notifications.html">Status Bar Notifications</a>.</p>
    - 
    --<p>A toast notification is a message that appears on the surface of the current window for a
    --moment then disappears, while a status bar notification provides an icon in the status bar with a
    -+<p>A toast notification is a message that appears on the surface of the current window for only a
    -+moment before disappearing. A status bar notification provides an icon in the status bar with a
    - message, which the user can select in order to take an action (such as start an activity).</p>
    - 
    --<p>Usually, a status bar notification is the best technique when some background work has completed
    --(such as a file completed
    --downloading) and the user can now act on it. When the user selects the notification from the
    --expanded view, the notification can start an activity (such as to view the downloaded file).</p>
    -+<p>Usually, a status bar notification is the best technique to use when background work such as
    -+a file download has completed, and the user can now act on it. When the user
    -+selects the notification from the expanded view, the notification can start an activity
    -+(such as to display the downloaded file).</p>
    - 
    - <p>See the <a
    - href="{@docRoot}guide/topics/ui/notifiers/toasts.html">Toast Notifications</a> or <a
    - href="{@docRoot}guide/topics/ui/notifiers/notifications.html">Status Bar Notifications</a>
    - developer guides for more information.</p>
    - 
    -+<h2 id="Foreground">Running a service in the foreground</h2>
    - 
    --
    --<h2 id="Foreground">Running a Service in the Foreground</h2>
    --
    --<p>A foreground service is a service that's considered to be something the
    --user is actively aware of and thus not a candidate for the system to kill when low on memory. A
    -+<p>A foreground service is a service that the
    -+user is actively aware of and is not a candidate for the system to kill when low on memory. A
    - foreground service must provide a notification for the status bar, which is placed under the
    --"Ongoing" heading, which means that the notification cannot be dismissed unless the service is
    --either stopped or removed from the foreground.</p>
    -+<em>Ongoing</em> heading. This means that the notification cannot be dismissed unless the service
    -+is either stopped or removed from the foreground.</p>
    - 
    - <p>For example, a music player that plays music from a service should be set to run in the
    - foreground, because the user is explicitly aware
    -@@ -643,9 +644,9 @@ of its operation. The notification in the status bar might indicate the current
    - the user to launch an activity to interact with the music player.</p>
    - 
    - <p>To request that your service run in the foreground, call {@link
    --android.app.Service#startForeground startForeground()}. This method takes two parameters: an integer
    --that uniquely identifies the notification and the {@link
    --android.app.Notification} for the status bar. For example:</p>
    -+android.app.Service#startForeground startForeground()}. This method takes two parameters: an
    -+integer that uniquely identifies the notification and the {@link
    -+android.app.Notification} for the status bar. Here is an example:</p>
    - 
    - <pre>
    - Notification notification = new Notification(R.drawable.icon, getText(R.string.ticker_text),
    -@@ -657,30 +658,27 @@ notification.setLatestEventInfo(this, getText(R.string.notification_title),
    - startForeground(ONGOING_NOTIFICATION_ID, notification);
    - </pre>
    - 
    --<p class="caution"><strong>Caution:</strong> The integer ID you give to {@link
    -+<p class="caution"><strong>Caution:</strong> The integer ID that you give to {@link
    - android.app.Service#startForeground startForeground()} must not be 0.</p>
    - 
    --
    - <p>To remove the service from the foreground, call {@link
    --android.app.Service#stopForeground stopForeground()}. This method takes a boolean, indicating
    -+android.app.Service#stopForeground stopForeground()}. This method takes a boolean, which indicates
    - whether to remove the status bar notification as well. This method does <em>not</em> stop the
    --service. However, if you stop the service while it's still running in the foreground, then the
    -+service. However, if you stop the service while it's still running in the foreground, the
    - notification is also removed.</p>
    - 
    - <p>For more information about notifications, see <a
    - href="{@docRoot}guide/topics/ui/notifiers/notifications.html">Creating Status Bar
    - Notifications</a>.</p>
    - 
    -+<h2 id="Lifecycle">Managing the lifecycle of a service</h2>
    - 
    -+<p>The lifecycle of a service is much simpler than that of an activity. However, it's even more
    -+important that you pay close attention to how your service is created and destroyed because a
    -+service can run in the background without the user being aware.</p>
    - 
    --<h2 id="Lifecycle">Managing the Lifecycle of a Service</h2>
    --
    --<p>The lifecycle of a service is much simpler than that of an activity. However, it's even more important
    --that you pay close attention to how your service is created and destroyed, because a service
    --can run in the background without the user being aware.</p>
    --
    --<p>The service lifecycle&mdash;from when it's created to when it's destroyed&mdash;can follow two
    --different paths:</p>
    -+<p>The service lifecycle&mdash;from when it's created to when it's destroyed&mdash;can follow
    -+either of these two paths:</p>
    - 
    - <ul>
    - <li>A started service
    -@@ -689,27 +687,26 @@ android.content.Context#startService startService()}. The service then runs inde
    - stop itself by calling {@link
    - android.app.Service#stopSelf() stopSelf()}. Another component can also stop the
    - service by calling {@link android.content.Context#stopService
    --stopService()}. When the service is stopped, the system destroys it..</p></li>
    -+stopService()}. When the service is stopped, the system destroys it.</p></li>
    - 
    - <li>A bound service
    -   <p>The service is created when another component (a client) calls {@link
    - android.content.Context#bindService bindService()}. The client then communicates with the service
    - through an {@link android.os.IBinder} interface. The client can close the connection by calling
    - {@link android.content.Context#unbindService unbindService()}. Multiple clients can bind to
    --the same service and when all of them unbind, the system destroys the service. (The service
    --does <em>not</em> need to stop itself.)</p></li>
    -+the same service and when all of them unbind, the system destroys the service. The service
    -+does <em>not</em> need to stop itself.</p></li>
    - </ul>
    - 
    --<p>These two paths are not entirely separate. That is, you can bind to a service that was already
    --started with {@link android.content.Context#startService startService()}. For example, a background
    --music service could be started by calling {@link android.content.Context#startService
    -+<p>These two paths are not entirely separate. You can bind to a service that is already
    -+started with {@link android.content.Context#startService startService()}. For example, you can
    -+start a background music service by calling {@link android.content.Context#startService
    - startService()} with an {@link android.content.Intent} that identifies the music to play. Later,
    - possibly when the user wants to exercise some control over the player or get information about the
    - current song, an activity can bind to the service by calling {@link
    --android.content.Context#bindService bindService()}. In cases like this, {@link
    -+android.content.Context#bindService bindService()}. In cases such as this, {@link
    - android.content.Context#stopService stopService()} or {@link android.app.Service#stopSelf
    --stopSelf()} does not actually stop the service until all clients unbind. </p>
    --
    -+stopSelf()} doesn't actually stop the service until all of the clients unbind.</p>
    - 
    - <h3 id="LifecycleCallbacks">Implementing the lifecycle callbacks</h3>
    - 
    -@@ -763,20 +760,30 @@ shows the lifecycle when the service is created with {@link android.content.Cont
    - startService()} and the diagram on the right shows the lifecycle when the service is created
    - with {@link android.content.Context#bindService bindService()}.</p>
    - 
    --<p>By implementing these methods, you can monitor two nested loops of the service's lifecycle: </p>
    -+<p>Figure 2 illustrates the typical callback methods for a service. Although the figure separates
    -+services that are created by {@link android.content.Context#startService startService()} from those
    -+created by {@link android.content.Context#bindService bindService()}, keep
    -+in mind that any service, no matter how it's started, can potentially allow clients to bind to it.
    -+A service that was initially started with {@link android.app.Service#onStartCommand
    -+onStartCommand()} (by a client calling {@link android.content.Context#startService startService()})
    -+can still receive a call to {@link android.app.Service#onBind onBind()} (when a client calls
    -+{@link android.content.Context#bindService bindService()}).</p>
    -+
    -+<p>By implementing these methods, you can monitor these two nested loops of the service's
    -+lifecycle:</p>
    - 
    - <ul>
    --<li>The <strong>entire lifetime</strong> of a service happens between the time {@link
    --android.app.Service#onCreate onCreate()} is called and the time {@link
    -+<li>The <strong>entire lifetime</strong> of a service occurs between the time that {@link
    -+android.app.Service#onCreate onCreate()} is called and the time that {@link
    - android.app.Service#onDestroy} returns. Like an activity, a service does its initial setup in
    - {@link android.app.Service#onCreate onCreate()} and releases all remaining resources in {@link
    --android.app.Service#onDestroy onDestroy()}.  For example, a
    --music playback service could create the thread where the music will be played in {@link
    --android.app.Service#onCreate onCreate()}, then stop the thread in {@link
    -+android.app.Service#onDestroy onDestroy()}. For example, a
    -+music playback service can create the thread where the music is played in {@link
    -+android.app.Service#onCreate onCreate()}, and then it can stop the thread in {@link
    - android.app.Service#onDestroy onDestroy()}.
    - 
    --<p>The {@link android.app.Service#onCreate onCreate()} and {@link android.app.Service#onDestroy
    --onDestroy()} methods are called for all services, whether
    -+<p class="note"><strong>Note</strong>: The {@link android.app.Service#onCreate onCreate()}
    -+and {@link android.app.Service#onDestroy onDestroy()} methods are called for all services, whether
    - they're created by {@link android.content.Context#startService startService()} or {@link
    - android.content.Context#bindService bindService()}.</p></li>
    - 
    -@@ -784,8 +791,8 @@ android.content.Context#bindService bindService()}.</p></li>
    - android.app.Service#onStartCommand onStartCommand()} or {@link android.app.Service#onBind onBind()}.
    - Each method is handed the {@link
    - android.content.Intent} that was passed to either {@link android.content.Context#startService
    --startService()} or {@link android.content.Context#bindService bindService()}, respectively.
    --<p>If the service is started, the active lifetime ends the same time that the entire lifetime
    -+startService()} or {@link android.content.Context#bindService bindService()}.
    -+<p>If the service is started, the active lifetime ends at the same time that the entire lifetime
    - ends (the service is still active even after {@link android.app.Service#onStartCommand
    - onStartCommand()} returns). If the service is bound, the active lifetime ends when {@link
    - android.app.Service#onUnbind onUnbind()} returns.</p>
    -@@ -795,26 +802,16 @@ android.app.Service#onUnbind onUnbind()} returns.</p>
    - <p class="note"><strong>Note:</strong> Although a started service is stopped by a call to
    - either {@link android.app.Service#stopSelf stopSelf()} or {@link
    - android.content.Context#stopService stopService()}, there is not a respective callback for the
    --service (there's no {@code onStop()} callback). So, unless the service is bound to a client,
    -+service (there's no {@code onStop()} callback). Unless the service is bound to a client,
    - the system destroys it when the service is stopped&mdash;{@link
    - android.app.Service#onDestroy onDestroy()} is the only callback received.</p>
    - 
    --<p>Figure 2 illustrates the typical callback methods for a service. Although the figure separates
    --services that are created by {@link android.content.Context#startService startService()} from those
    --created by {@link android.content.Context#bindService bindService()}, keep
    --in mind that any service, no matter how it's started, can potentially allow clients to bind to it.
    --So, a service that was initially started with {@link android.app.Service#onStartCommand
    --onStartCommand()} (by a client calling {@link android.content.Context#startService startService()})
    --can still receive a call to {@link android.app.Service#onBind onBind()} (when a client calls
    --{@link android.content.Context#bindService bindService()}).</p>
    --
    - <p>For more information about creating a service that provides binding, see the <a
    - href="{@docRoot}guide/components/bound-services.html">Bound Services</a> document,
    - which includes more information about the {@link android.app.Service#onRebind onRebind()}
    - callback method in the section about <a
    --href="{@docRoot}guide/components/bound-services.html#Lifecycle">Managing the Lifecycle of
    --a Bound Service</a>.</p>
    --
    -+href="{@docRoot}guide/components/bound-services.html#Lifecycle">Managing the lifecycle of
    -+a bound service</a>.</p>
    - 
    - <!--
    - <h2>Beginner's Path</h2>
    -diff --git a/docs/html/guide/guide_toc.cs b/docs/html/guide/guide_toc.cs
    -index 9257a76..8fe3f20 100644
    ---- a/docs/html/guide/guide_toc.cs
    -+++ b/docs/html/guide/guide_toc.cs
    -@@ -545,9 +545,16 @@
    -          <li><a href="<?cs var:toroot ?>guide/topics/data/data-storage.html">
    -             <span class="en">Storage Options</span>
    -            </a></li>
    --        <li><a href="<?cs var:toroot ?>guide/topics/data/backup.html">
    -+        <li class="nav-section">
    -+          <div class="nav-section-header"><a href="<?cs var:toroot ?>guide/topics/data/backup.html">
    -             <span class="en">Data Backup</span>
    --          </a></li>
    -+          </a></div>
    -+          <ul>
    -+            <li><a href="<?cs var:toroot ?>guide/topics/data/autobackup.html">Auto Backup</a></li>
    -+            <li><a href="<?cs var:toroot ?>guide/topics/data/keyvaluebackup.html">Key/Value Backup</a></li>
    -+            <li><a href="<?cs var:toroot ?>guide/topics/data/testingbackup.html">Testing Backup and Restore</a></li>
    -+          </ul>
    -+        </li>
    -         <li><a href="<?cs var:toroot ?>guide/topics/data/install-location.html">
    -             <span class="en">App Install Location</span>
    -           </a></li>
    -diff --git a/docs/html/guide/topics/connectivity/nfc/nfc.jd b/docs/html/guide/topics/connectivity/nfc/nfc.jd
    -index 520f520..881a75f 100644
    ---- a/docs/html/guide/topics/connectivity/nfc/nfc.jd
    -+++ b/docs/html/guide/topics/connectivity/nfc/nfc.jd
    -@@ -487,19 +487,22 @@ intent. The following example checks for the {@link android.nfc.NfcAdapter#ACTIO
    - intent and gets the NDEF messages from an intent extra.</p>
    - 
    - <pre>
    --public void onResume() {
    --    super.onResume();
    -+&#64;Override
    -+protected void onNewIntent(Intent intent) {
    -+    super.onNewIntent(intent);
    -     ...
    --    if (NfcAdapter.ACTION_NDEF_DISCOVERED.equals(getIntent().getAction())) {
    --        Parcelable[] rawMsgs = intent.getParcelableArrayExtra(NfcAdapter.EXTRA_NDEF_MESSAGES);
    --        if (rawMsgs != null) {
    --            msgs = new NdefMessage[rawMsgs.length];
    --            for (int i = 0; i &lt; rawMsgs.length; i++) {
    --                msgs[i] = (NdefMessage) rawMsgs[i];
    -+    if (intent != null &amp;&amp; NfcAdapter.ACTION_NDEF_DISCOVERED.equals(intent.getAction())) {
    -+        Parcelable[] rawMessages =
    -+            intent.getParcelableArrayExtra(NfcAdapter.EXTRA_NDEF_MESSAGES);
    -+        if (rawMessages != null) {
    -+            NdefMessage[] messages = new NdefMessage[rawMessages.length];
    -+            for (int i = 0; i < rawMessages.length; i++) {
    -+                messages[i] = (NdefMessage) rawMessages[i];
    -             }
    -+            // Process the messages array.
    -+            ...
    -         }
    -     }
    --    //process the msgs array
    - }
    - </pre>
    - 
    -diff --git a/docs/html/guide/topics/data/autobackup.jd b/docs/html/guide/topics/data/autobackup.jd
    -new file mode 100644
    -index 0000000..3be09d7
    ---- /dev/null
    -+++ b/docs/html/guide/topics/data/autobackup.jd
    -@@ -0,0 +1,257 @@
    -+page.title=Auto Backup for Apps
    -+page.tags=backup, marshmallow, androidm
    -+page.keywords=backup, autobackup
    -+page.image=images/cards/card-auto-backup_2x.png
    -+
    -+@jd:body
    -+
    -+<div id="qv-wrapper">
    -+<div id="qv">
    -+  <h2>In this document</h2>
    -+  <ol>
    -+    <li><a href="#Files">Files that are backed up</a></li>
    -+    <li><a href="#BackupLocation">Backup location</a></li>
    -+    <li><a href="#BackupSchedule">Backup schedule</a></li>
    -+    <li><a href="#RestoreSchedule">Restore schedule</a></li>
    -+    <li><a href="#EnablingAutoBackup">Enabling and disabling Auto Backup</a></li>
    -+    <li><a href="#IncludingFiles">Including and excluding files</a><ul>
    -+      <li><a href="#XMLSyntax">XML config syntax</a></li>
    -+    </ul></li>
    -+    <li><a href="#ImplementingBackupAgent">Implementing BackupAgent</a></li>
    -+  </ol>
    -+
    -+  <h2>Key classes</h2>
    -+  <ol>
    -+    <li>{@link android.app.backup.BackupAgent}</li>
    -+    <li><a href="{@docRoot}reference/android/R.attr.html">R.attr</a></li>
    -+  </ol>
    -+
    -+</div>
    -+</div>
    -+
    -+Since Android 6.0 (API 23), Android has offered the <em>Auto Backup for Apps</em> feature as
    -+a way for developers to quickly add backup functionality to their apps. Auto
    -+Backup preserves app data by uploading it to the user’s Google Drive account.
    -+The amount of data is limited to 25MB per user of your app and there is no
    -+charge for storing backup data.
    -+
    -+<h2 id="Files">Files that are backed up</h2>
    -+<p>By default, Auto Backup includes files in most of the directories that are
    -+assigned to your app by the system:
    -+<ul>
    -+  <li>Shared preferences files.
    -+  <li>Files in the directory returned by {@link android.content.Context#getFilesDir()}.
    -+  <li>Files in the directory returned by {@link android.content.Context#getDatabasePath(String)},
    -+    which also includes files created with the
    -+    {@link android.database.sqlite.SQLiteOpenHelper} class.
    -+  <li>Files in directories created with {@link android.content.Context#getDir(String,int)}.
    -+  <li>Files on external storage in the directory returned by
    -+    {@link android.content.Context#getExternalFilesDir(String)}.</li></ul>
    -+
    -+<p>Auto Backup excludes files in directories returned by
    -+  {@link android.content.Context#getCacheDir()},
    -+  {@link android.content.Context#getCodeCacheDir()}, or
    -+  {@link android.content.Context#getNoBackupFilesDir()}. The files saved
    -+  in these locations are only needed temporarily, or are intentionally
    -+  excluded from backup operations.
    -+
    -+<p>You can configure your app to include and exclude particular files.
    -+For more information, see the <a href="#IncludingFiles">Include and exclude files</a>
    -+section.
    -+
    -+<h2 id="BackupLocation">Backup location</h2>
    -+<p>Backup data is stored in a private folder in the user's Google Drive account,
    -+limited to 25MB per app. The saved data does not count towards the user's
    -+personal Google Drive quota. Only the most recent backup is stored. When a
    -+backup is made, the previous backup (if one exists) is deleted.
    -+
    -+<p>Users can see a list of apps that have been backed up in the Google Drive app under
    -+<strong>Settings -> Auto Backup for apps -> Manage backup</strong>. The
    -+backup data cannot be read by the user or other applications on the device.
    -+
    -+<p>Backups from each device-setup-lifetime are stored in separate datasets
    -+as shown in the following examples:
    -+<ul>
    -+  <li>If the user owns two devices, then a backup dataset exists for each device.
    -+  <li>If the user factory resets a device and then sets up the device with the
    -+    same account, the backup is stored in a new dataset. Obsolete datasets are
    -+    automatically deleted after a period of inactivity.</li></ul>
    -+
    -+<p class="caution"><strong>Caution:</strong> Once the amount of data reaches
    -+25MB, the app is banned from sending data to the
    -+cloud, even if the amount of data later falls under the 25MB threshold. The ban
    -+affects only the offending device (not other devices that the user owns) and
    -+lasts for the entire device-setup-lifetime. For example, if the user removes and
    -+reinstalls the application, the ban is still in effect. The ban is lifted when
    -+the user performs factory reset on the device.
    -+
    -+<h2 id="BackupSchedule">Backup schedule</h2>
    -+<p>Backups occur automatically when all of the following conditions are met:
    -+<ul>
    -+  <li>The user has enabled backup on the device in <strong>Settings</strong> >
    -+    <strong>Backup &amp; Reset</strong>.
    -+  <li>At least 24 hours have elapsed since the last backup.
    -+  <li>The device is idle and charging.
    -+  <li>The device is connected to a Wi-Fi network. If the device is never connected
    -+    to a wifi network, then Auto Backup never occurs.</li></ul>
    -+
    -+<p>In practice, these conditions occur roughly every night. To conserve network
    -+bandwidth, upload takes place only if app data has changed.
    -+
    -+<p>During Auto Backup, the system shuts down the app to make sure it is no longer
    -+writing to the file system. By default, the backup system ignores apps that are
    -+running in the foreground because users would notice their apps being shut down.
    -+You can override the default behavior by setting the
    -+<a href="{@docRoot}reference/android/R.attr.html#backupInForeground">backupInForeground</a>
    -+attribute to true.
    -+
    -+<p>To simplify testing, Android includes tools that let you manually initiate
    -+a backup of your app. For more information, see
    -+<a href="{@docRoot}guide/topics/data/testingbackup.html">Testing Backup and Restore</a>.
    -+
    -+<h2 id="RestoreSchedule">Restore schedule</h2>
    -+<p>Data is restored whenever the app is installed, either from the Play store,
    -+during device setup (when the system installs previously installed apps), or
    -+from running adb install. The restore operation occurs after the APK is
    -+installed, but before the app is available to be launched by the user.
    -+
    -+<p>During the initial device setup wizard, the user is shown a list of available backup
    -+datasets and is asked which one to restore the data from. Whichever backup
    -+dataset is selected becomes the ancestral dataset for the device. The device can
    -+restore from either its own backups or the ancestral dataset. The device
    -+prioritize its own backup if backups from both sources are available. If the
    -+user didn't go through the device setup wizard, then the device can restore only from
    -+its own backups.
    -+
    -+<p>To simplify testing, Android includes tools that let you manually initiate
    -+a restore of your app. For more information, see
    -+<a href="{@docRoot}guide/topics/data/testingbackup.html">Testing Backup and Restore</a>.
    -+
    -+<h2 id="EnablingAutoBackup">Enabling and disabling backup</h2>
    -+<p>Apps that target Android 6.0 (API level 23) or higher automatically participate
    -+in Auto Backup. This is because the
    -+<a href="{@docRoot}reference/android/R.attr.html#allowBackup">android:allowBackup</a>
    -+attribute, which enables/disables backup, defaults to <code>true</code> if omitted.
    -+To avoid confusion, we recommend you explicitly set the attribute in the <code>&lt;application></code>
    -+element of your <code>AndroidManifest.xml</code>. For example:
    -+
    -+<pre class="prettyprint">&lt;application ...
    -+    android:allowBackup="true">
    -+&lt;/app></pre>
    -+
    -+<p>To disable Auto Backup, add either of the following attributes to the
    -+application element in your manifest file:
    -+
    -+<ul>
    -+  <li>set <code>android:allowBackup</code> to <code>false</code>. This completely disables data
    -+    backup. You may want to disable backups when your app can recreate its state
    -+    through some other mechanism or when your app deals with sensitive
    -+    information that should not be backed up.</li>
    -+  <li>set <code>android:allowBackup</code> to <code>true</code> and
    -+    <code>android:fullBackupOnly</code> to <code>false</code>. With these settings,
    -+    your app always participates in Key/Value Backup, even when running on devices that
    -+    support Auto Backup.</li></ul>
    -+
    -+<h2 id="IncludingFiles">Including and excluding files</h2>
    -+<p>By default, the system backs up almost all app data. For more information,
    -+see <a href="#Files">Files that are backed up</a>. This section shows you how to
    -+define custom XML rules to control what gets backed up.
    -+
    -+<ol>
    -+  <li>In <code>AndroidManifest.xml</code>, add the <a href="{@docRoot}reference/android/R.attr.html#fullBackupContent">android:fullBackupContent</a> attribute to the
    -+  <code>&lt;application></code> element. This attribute points to an XML file that contains backup
    -+  rules. For example:
    -+  <pre class="prettyprint">&lt;application ...
    -+    android:fullBackupContent="@xml/my_backup_rules">
    -+  &lt;/app></pre></li>
    -+  <li>Create an XML file called <code>my_backup_rules.xml</code> in the <code>res/xml/</code> directory. Inside the file, add rules with the <code>&lt;include></code> and <code>&lt;exclude></code> elements. The following sample backs up all shared preferences except <code>device.xml</code>:
    -+  <pre>&lt;?xml version="1.0" encoding="utf-8"?>
    -+&lt;full-backup-content>
    -+    &lt;include domain="sharedpref" path="."/>
    -+    &lt;exclude domain="sharedpref" path="device.xml"/>
    -+&lt;/full-backup-content></pre></li>
    -+
    -+<h3 id="XMLSyntax">XML Config Syntax</h3>
    -+<p>The XML syntax for the configuration file is shown below:
    -+
    -+<pre class="prettyprint">&lt;full-backup-content>
    -+    &lt;include domain=["file" | "database" | "sharedpref" | "external" | "root"]
    -+    path="string" />
    -+    &lt;exclude domain=["file" | "database" | "sharedpref" | "external" | "root"]
    -+    path="string" />
    -+&lt;/full-backup-content></pre>
    -+
    -+<p>Inside the <code>&lt;full-backup-content></code> tag, you can define <code>&lt;include></code> and <code>&lt;exclude></code>
    -+elements:
    -+
    -+<ul>
    -+  <li><code>&lt;include></code> - Specifies a file or folder to backup. By default, Auto Backup
    -+includes almost all app files. If you specify an &lt;include> element, the system
    -+no longer includes any files by default and backs up <em>only the files
    -+specified</em>. To include multiple files, use multiple &lt;include> elements.
    -+  <p>note: Files in directories returned by <code>getCacheDir()</code>, <code>getCodeCacheDir()</code>, or
    -+<code>getNoBackupFilesDir()</code> are always excluded even if you try to include them.</li>
    -+
    -+  <li><code>&lt;exclude></code> - Specifies a file or folder to exclude during backup. Here are
    -+some files that are typically excluded from backup: <ul>
    -+    <li>Files that have device specific identifiers, either issued by a server or
    -+generated on the device. For example, <a href="https://developers.google.com/cloud-messaging/android/start">Google Cloud Messaging (GCM)</a> needs to
    -+generate a registration token every time a user installs your app on a new
    -+device. If the old registration token is restored, the app may behave
    -+unexpectedly.
    -+    <li>Account credentials or other sensitive information. Consider asking the
    -+user to reauthenticate the first time they launch a restored app rather than
    -+allowing for storage of such information in the backup.
    -+    <li>Files related to app debugging, such as <a href="{@docRoot}studio/run/index.html#instant-run">instant run files</a>. To exclude instant run files, add the rule <code>&lt;exclude
    -+domain="file" path="instant-run"/></code>
    -+    <li>Large files that cause the app to exceed the 25MB backup quota.</li> </ul>
    -+  </li> </ul>
    -+
    -+<p class="note"><strong>Note:</strong> If your configuration file specifies both elements, then the
    -+backup contains everything captured by the <code>&lt;include></code> elements minus the
    -+resources named in the <code>&lt;exclude></code> elements. In other words,
    -+<code>&lt;exclude></code> takes precedence.
    -+
    -+<p>Each element must include the following two attributes:
    -+<ul>
    -+  <li><code>domain</code> - specifies the location of resource. Valid values for this attribute
    -+include the following: <ul>
    -+    <li><code>root</code> - the directory on the filesystem where all private files belonging to
    -+this app are stored.
    -+    <li><code>file</code> - directories returned by {@link android.content.Context#getFilesDir()}.
    -+    <li><code>database</code> - directories returned by {@link android.content.Context#getDatabasePath(String) getDatabasePath()}.
    -+Databases created with {@link android.database.sqlite.SQLiteOpenHelper}
    -+are stored here.
    -+    <li><code>sharedpref</code> - the directory where {@link android.content.SharedPreferences}
    -+are stored.
    -+    <li><code>external</code> the directory returned by {@link android.content.Context#getExternalFilesDir(String) getExternalFilesDir()}
    -+    <p>Note: You cannot backup files outside of these locations.</li></ul>
    -+  <li><code>path</code>: Specifies a file or folder to include in or exclude from backup. Note
    -+that: <ul>
    -+    <li>This attribute does not support wildcard or regex syntax.
    -+    <li>You can use <code>.</code> to reference the current directory, however, you cannot
    -+reference the parent directory <code>..</code> for security reasons.
    -+    <li>If you specify a directory, then the rule applies to all files in the
    -+directory and recursive sub-directories.</li></ul></li></ul>
    -+
    -+<h2 id="ImplementingBackupAgent">Implementing BackupAgent</h2>
    -+<p>Apps that implement Auto Backup do not need to implement {@link android.app.backup.BackupAgent}. However, you can optionally implement a custom {@link android.app.backup.BackupAgent}. Typically, there are two reasons for doing this:
    -+<ul>
    -+  <li>You want to receive notification of backup events such as,
    -+{@link android.app.backup.BackupAgent#onRestoreFinished()} or {@link android.app.backup.BackupAgent#onQuotaExceeded(long,long)}. These callback methods are executed
    -+even if the app is not running.
    -+<li>You can't easily express the set of files you want to backup with XML rules.
    -+In these very rare cases, you can implement a BackupAgent that overrides {@link android.app.backup.BackupAgent#onFullBackup(FullBackupDataOutput)} to
    -+store what you want. To retain the system's default implementation, call the
    -+corresponding method on the superclass with <code>super.onFullBackup()</code>.</li></ul>
    -+
    -+<p class="note"><strong>Note:</strong> Your <code>BackupAgent</code> must
    -+implement the abstract methods
    -+{@link android.app.backup.BackupAgent#onBackup(ParcelFileDescriptor,BackupDataOutput,ParcelFileDescriptor) onBackup()}
    -+and {@link android.app.backup.BackupAgent#onRestore(BackupDataInput,int,ParcelFileDescriptor) onRestore()}.
    -+Those methods are used for Key/Value Backup. So if
    -+you are not using Key/Value Backup, implement those methods and leave them blank.
    -+
    -+<p>For more information, see
    -+<a href="{@docRoot}guide/topics/data/keyvaluebackup.html#BackupAgent">Extending
    -+BackupAgent</a>.
    -\ No newline at end of file
    -diff --git a/docs/html/guide/topics/data/backup.jd b/docs/html/guide/topics/data/backup.jd
    -index 619c790..a688c6e 100644
    ---- a/docs/html/guide/topics/data/backup.jd
    -+++ b/docs/html/guide/topics/data/backup.jd
    -@@ -1,930 +1,34 @@
    --page.title=Data Backup
    --@jd:body
    --
    --
    --<div id="qv-wrapper">
    --<div id="qv">
    --
    --  <h2>Quickview</h2>
    --  <ul>
    --    <li>Back up the user's data to the cloud in case the user loses it</li>
    --    <li>If the user upgrades to a new Android-powered device, your app can restore the user's
    --data onto the new device</li>
    --    <li>Easily back up SharedPreferences and private files with BackupAgentHelper</li>
    --    <li>Requires API Level 8</li>
    --  </ul>
    --
    --  <h2>In this document</h2>
    --  <ol>
    --    <li><a href="#Basics">The Basics</a></li>
    --    <li><a href="#BackupManifest">Declaring the Backup Agent in Your Manifest</a></li>
    --    <li><a href="#BackupKey">Registering for Android Backup Service</a></li>
    --    <li><a href="#BackupAgent">Extending BackupAgent</a>
    --      <ol>
    --        <li><a href="#RequiredMethods">Required Methods</a></li>
    --        <li><a href="#PerformingBackup">Performing backup</a></li>
    --        <li><a href="#PerformingRestore">Performing restore</a></li>
    --      </ol>
    --    </li>
    --    <li><a href="#BackupAgentHelper">Extending BackupAgentHelper</a>
    --      <ol>
    --        <li><a href="#SharedPreferences">Backing up SharedPreferences</a></li>
    --        <li><a href="#Files">Backing up Private Files</a></li>
    --      </ol>
    --    </li>
    --    <li><a href="#RestoreVersion">Checking the Restore Data Version</a></li>
    --    <li><a href="#RequestingBackup">Requesting Backup</a></li>
    --    <li><a href="#RequestingRestore">Requesting Restore</a></li>
    --    <li><a href="#Testing">Testing Your Backup Agent</a></li>
    --  </ol>
    --
    --  <h2>Key classes</h2>
    --  <ol>
    --    <li>{@link android.app.backup.BackupManager}</li>
    --    <li>{@link android.app.backup.BackupAgent}</li>
    --    <li>{@link android.app.backup.BackupAgentHelper}</li>
    --  </ol>
    --
    --  <h2>See also</h2>
    --  <ol>
    --    <li><a href="{@docRoot}tools/help/bmgr.html">{@code bmgr} tool</a></li>
    --  </ol>
    --
    --</div>
    --</div>
    --
    --<p>Android's {@link android.app.backup backup} service allows you to copy your persistent
    --application data to remote "cloud" storage, in order to provide a restore point for the
    --application data and settings. If a user performs a factory reset or converts to a new
    --Android-powered device, the system automatically restores your backup data when the application
    --is re-installed. This way, your users don't need to reproduce their previous data or
    --application settings. This process is completely transparent to the user and does not affect the
    --functionality or user experience in your application.</p>
    --
    --<p>During a backup operation (which your application can request), Android's Backup Manager ({@link
    --android.app.backup.BackupManager}) queries your application for backup data, then hands it to
    --a backup transport, which then delivers the data to the cloud storage. During a
    --restore operation, the Backup Manager retrieves the backup data from the backup transport and
    --returns it to your application so your application can restore the data to the device. It's
    --possible for your application to request a restore, but that shouldn't be necessary&mdash;Android
    --automatically performs a restore operation when your application is installed and there exists
    --backup data associated with the user. The primary scenario in which backup data is restored is when
    --a user resets their device or upgrades to a new device and their previously installed
    --applications are re-installed.</p>
    --
    --<p class="note"><strong>Note:</strong> The backup service is <em>not</em> designed for
    --synchronizing application data with other clients or saving data that you'd like to access during
    --the normal application lifecycle. You cannot read or write backup data on demand and cannot access
    --it in any way other than through the APIs provided by the Backup Manager.</p>
    --
    --<p>The backup transport is the client-side component of Android's backup framework, which is
    --customizable by
    --the device manufacturer and service provider. The backup transport may differ from device to device
    --and which backup transport is available on any given device is transparent to your application. The
    --Backup Manager APIs isolate your application from the actual backup transport available on a given
    --device&mdash;your application communicates with the Backup Manager through a fixed set of APIs,
    --regardless of the underlying transport.</p>
    --
    --<p>Data backup is <em>not</em> guaranteed to be available on all Android-powered
    --devices. However, your application is not adversely affected in the event
    --that a device does not provide a backup transport. If you believe that users will benefit from data
    --backup in your application, then you can implement it as described in this document, test it, then
    --publish your application without any concern about which devices actually perform backup. When your
    --application runs on a device that does not provide a backup transport, your application operates
    --normally, but will not receive callbacks from the Backup Manager to backup data.</p>
    --
    --<p>Although you cannot know what the current transport is, you are always assured that your
    --backup data cannot be read by other applications on the device. Only the Backup Manager and backup
    --transport have access to the data you provide during a backup operation.</p>
    --
    --<p class="caution"><strong>Caution:</strong> Because the cloud storage and transport service can
    --differ from device to device, Android makes no guarantees about the security of your data while
    --using backup. You should always be cautious about using backup to store sensitive data, such as
    --usernames and passwords.</p>
    --
    --
    --<h2 id="Basics">The Basics</h2>
    --
    --<p>To backup your application data, you need to implement a backup agent. Your backup
    --agent is called by the Backup Manager to provide the data you want to back up. It is also called
    --to restore your backup data when the application is re-installed. The Backup Manager handles all
    --your data transactions with the cloud storage (using the backup transport) and your backup agent
    --handles all your data transactions on the device.</p>
    --
    --<p>To implement a backup agent, you must:</p>
    --
    --<ol>
    --  <li>Declare your backup agent in your manifest file with the <a
    --href="{@docRoot}guide/topics/manifest/application-element.html#agent">{@code
    --android:backupAgent}</a> attribute.</li>
    --  <li>Register your application with a backup service. Google offers <a
    --href="http://code.google.com/android/backup/index.html">Android Backup Service</a> as a backup
    --service for most Android-powered devices, which requires that you register your application in
    --order for it to work. Any other backup services available might also require you to register
    --in order to store your data on their servers.</li>
    --  <li>Define a backup agent by either:</p>
    --    <ol type="a">
    --      <li><a href="#BackupAgent">Extending BackupAgent</a>
    --        <p>The {@link android.app.backup.BackupAgent} class provides the central interface with
    --which your application communicates with the Backup Manager. If you extend this class
    --directly, you must override {@link
    --android.app.backup.BackupAgent#onBackup(ParcelFileDescriptor,BackupDataOutput,ParcelFileDescriptor)
    --onBackup()} and {@link
    --android.app.backup.BackupAgent#onRestore(BackupDataInput,int,ParcelFileDescriptor)
    --onRestore()} to handle the backup and restore operations for your data.</p>
    --        <p><em>Or</em></p>
    --      <li><a href="#BackupAgentHelper">Extending BackupAgentHelper</a>
    --        <p>The {@link android.app.backup.BackupAgentHelper} class provides a convenient
    --wrapper around the {@link android.app.backup.BackupAgent} class, which minimizes the amount of code
    --you need to write. In your {@link android.app.backup.BackupAgentHelper}, you must use one or more
    --"helper" objects, which automatically backup and restore certain types of data, so that you do not
    --need to implement {@link
    --android.app.backup.BackupAgent#onBackup(ParcelFileDescriptor,BackupDataOutput,ParcelFileDescriptor)
    --onBackup()} and {@link
    --android.app.backup.BackupAgent#onRestore(BackupDataInput,int,ParcelFileDescriptor)
    --onRestore()}.</p>
    --        <p>Android currently provides backup helpers that will backup and restore complete files
    --from {@link android.content.SharedPreferences} and <a
    --href="{@docRoot}guide/topics/data/data-storage.html#filesInternal">internal storage</a>.</p>
    --      </li>
    --    </ol>
    --  </li>
    --</ol>
    --
    --
    --
    --<h2 id="BackupManifest">Declaring the Backup Agent in Your Manifest</h2>
    --
    --<p>This is the easiest step, so once you've decided on the class name for your backup agent, declare
    --it in your manifest with the <a
    --href="{@docRoot}guide/topics/manifest/application-element.html#agent">{@code
    --android:backupAgent}</a> attribute in the <a
    --href="{@docRoot}guide/topics/manifest/application-element.html">{@code
    --<application>}</a> tag.</p>
    --
    --<p>For example:</p>
    --
    --<pre>
    --&lt;manifest ... &gt;
    --    ...
    --    &lt;application android:label="MyApplication"
    --                 <b>android:backupAgent="MyBackupAgent"</b>&gt;
    --        &lt;activity ... &gt;
    --            ...
    --        &lt;/activity&gt;
    --    &lt;/application&gt;
    --&lt;/manifest&gt;
    --</pre>
    --
    --<p>Another attribute you might want to use is <a
    --href="{@docRoot}guide/topics/manifest/application-element.html#restoreany">{@code
    --android:restoreAnyVersion}</a>. This attribute takes a boolean value to indicate whether you
    --want to restore the application data regardless of the current application version compared to the
    --version that produced the backup data. (The default value is "{@code false}".) See <a
    --href="#RestoreVersion">Checking the Restore Data Version</a> for more information.</p>
    --
    --<p class="note"><strong>Note:</strong> The backup service and the APIs you must use are
    --available only on devices running API Level 8 (Android 2.2) or greater, so you should also
    --set your <a
    --href="{@docRoot}guide/topics/manifest/uses-sdk-element.html#min">{@code android:minSdkVersion}</a>
    --attribute to "8".</p>
    --
    --
    --
    --
    --<h2 id="BackupKey">Registering for Android Backup Service</h2>
    --
    --<p>Google provides a backup transport with <a
    --href="http://code.google.com/android/backup/index.html">Android Backup Service</a> for most
    --Android-powered devices running Android 2.2 or greater.</p>
    --
    --<p>In order for your application to perform backup using Android Backup Service, you must
    --register your application with the service to receive a Backup Service Key, then
    --declare the Backup Service Key in your Android manifest.</p>
    --
    --<p>To get your Backup Service Key, <a
    --href="http://code.google.com/android/backup/signup.html">register for Android Backup Service</a>.
    --When you register, you will be provided a Backup Service Key and the appropriate {@code
    --<meta-data>} XML code for your Android manifest file, which you must include as a child of the
    --{@code <application>} element. For example:</p>
    --
    --<pre>
    --&lt;application android:label="MyApplication"
    --             android:backupAgent="MyBackupAgent"&gt;
    --    ...
    --    &lt;meta-data android:name="com.google.android.backup.api_key"
    --        android:value="AEdPqrEAAAAIDaYEVgU6DJnyJdBmU7KLH3kszDXLv_4DIsEIyQ" /&gt;
    --&lt;/application&gt;
    --</pre>
    --
    --<p>The <code>android:name</code> must be <code>"com.google.android.backup.api_key"</code> and
    --the <code>android:value</code> must be the Backup Service Key received from the Android Backup
    --Service registration.</p>
    --
    --<p>If you have multiple applications, you must register each one, using the respective package
    --name.</p>
    --
    --<p class="note"><strong>Note:</strong> The backup transport provided by Android Backup Service is
    --not guaranteed to be available
    --on all Android-powered devices that support backup. Some devices might support backup
    --using a different transport, some devices might not support backup at all, and there is no way for
    --your application to know what transport is used on the device. However, if you implement backup for
    --your application, you should always include a Backup Service Key for Android Backup Service so
    --your application can perform backup when the device uses the Android Backup Service transport. If
    --the device does not use Android Backup Service, then the {@code <meta-data>} element with the
    --Backup Service Key is ignored.</p>
    --
    --
    --
    --
    --<h2 id="BackupAgent">Extending BackupAgent</h2>
    --
    --<p>Most applications shouldn't need to extend the {@link android.app.backup.BackupAgent} class
    --directly, but should instead <a href="#BackupAgentHelper">extend BackupAgentHelper</a> to take
    --advantage of the built-in helper classes that automatically backup and restore your files. However,
    --you might want to extend {@link android.app.backup.BackupAgent} directly if you need to:</p>
    --<ul>
    --  <li>Version your data format. For instance, if you anticipate the need to revise the
    --format in which you write your application data, you can build a backup agent to cross-check your
    --application version during a restore operation and perform any necessary compatibility work if the
    --version on the device is different than that of the backup data. For more information, see <a
    --href="#RestoreVersion">Checking the Restore Data Version</a>.</li>
    --  <li>Instead of backing up an entire file, you can specify the portions of data the should be
    --backed up and how each portion is then restored to the device. (This can also help you manage
    --different versions, because you read and write your data as unique entities, rather than
    --complete files.)</li>
    --  <li>Back up data in a database. If you have an SQLite database that you want to restore when
    --the user re-installs your application, you need to build a custom {@link
    --android.app.backup.BackupAgent} that reads the appropriate data during a backup operation, then
    --create your table and insert the data during a restore operation.</li>
    --</ul>
    --
    --<p>If you don't need to perform any of the tasks above and want to back up complete files from
    --{@link android.content.SharedPreferences} or <a
    --href="{@docRoot}guide/topics/data/data-storage.html#filesInternal">internal storage</a>, you
    --should skip to <a href="#BackupAgentHelper">Extending BackupAgentHelper</a>.</p>
    --
    --
    --
    --<h3 id="RequiredMethods">Required Methods</h3>
    --
    --<p>When you create a backup agent by extending {@link android.app.backup.BackupAgent}, you
    --must implement the following callback methods:</p>
    --
    --<dl>
    --  <dt>{@link
    --android.app.backup.BackupAgent#onBackup(ParcelFileDescriptor,BackupDataOutput,ParcelFileDescriptor)
    --onBackup()}</dt>
    --    <dd>The Backup Manager calls this method after you <a href="#RequestingBackup">request a
    --backup</a>. In this method, you read your application data from the device and pass the data you
    --want to back up to the Backup Manager, as described below in <a href="#PerformingBackup">Performing
    --backup</a>.</dd>
    --
    --  <dt>{@link
    --android.app.backup.BackupAgent#onRestore(BackupDataInput,int,ParcelFileDescriptor)
    --onRestore()}</dt>
    --    <dd>The Backup Manager calls this method during a restore operation (you can <a
    --href="#RequestingRestore">request a restore</a>, but the system automatically performs restore when
    --the user re-installs your application). When it calls this method, the Backup Manager delivers your
    --backup data, which you then restore to the device, as described below in <a
    --href="#PerformingRestore">Performing restore</a>.</dd>
    --</dl>
    --
    --
    --
    --<h3 id="PerformingBackup">Performing backup</h3>
    --
    --
    --<p>When it's time to back up your application data, the Backup Manager calls your {@link
    --android.app.backup.BackupAgent#onBackup(ParcelFileDescriptor,BackupDataOutput,ParcelFileDescriptor)
    --onBackup()} method. This is where you must provide your application data to the Backup Manager so
    --it can be saved to cloud storage.</p>
    --
    --<p>Only the Backup Manager can call your backup agent's {@link
    --android.app.backup.BackupAgent#onBackup(ParcelFileDescriptor,BackupDataOutput,ParcelFileDescriptor)
    --onBackup()} method. Each time that your application data changes and you want to perform a backup,
    --you must request a backup operation by calling {@link
    --android.app.backup.BackupManager#dataChanged()} (see <a href="#RequestingBackup">Requesting
    --Backup</a> for more information). A backup request does not result in an immediate call to your
    --{@link
    --android.app.backup.BackupAgent#onBackup(ParcelFileDescriptor,BackupDataOutput,ParcelFileDescriptor)
    --onBackup()} method. Instead, the Backup Manager waits for an appropriate time, then performs
    --backup for all applications that have requested a backup since the last backup was performed.</p>
    --
    --<p class="note"><strong>Tip:</strong> While developing your application, you can initiate an
    --immediate backup operation from the Backup Manager with the <a
    --href="{@docRoot}tools/help/bmgr.html">{@code bmgr} tool</a>.</p>
    --
    --<p>When the Backup Manager calls your {@link
    --android.app.backup.BackupAgent#onBackup(ParcelFileDescriptor,BackupDataOutput,ParcelFileDescriptor)
    --onBackup()} method, it passes three parameters:</p>
    --
    --<dl>
    --  <dt>{@code oldState}</dt>
    --    <dd>An open, read-only {@link android.os.ParcelFileDescriptor} pointing to the last backup
    --state provided by your application. This is not the backup data from cloud storage, but a
    --local representation of the data that was backed up the last time {@link
    --android.app.backup.BackupAgent#onBackup(ParcelFileDescriptor,BackupDataOutput,ParcelFileDescriptor)
    --onBackup()} was called (as defined by {@code newState}, below, or from {@link
    --android.app.backup.BackupAgent#onRestore(BackupDataInput,int,ParcelFileDescriptor)
    --onRestore()}&mdash;more about this in the next section). Because {@link
    --android.app.backup.BackupAgent#onBackup(ParcelFileDescriptor,BackupDataOutput,ParcelFileDescriptor)
    --onBackup()} does not allow you to read existing backup data in
    --the cloud storage, you can use this local representation to determine whether your data has changed
    --since the last backup.</dd>
    --  <dt>{@code data}</dt>
    --    <dd>A {@link android.app.backup.BackupDataOutput} object, which you use to deliver your backup
    --data to the Backup Manager.</dd>
    --  <dt>{@code newState}</dt>
    --    <dd>An open, read/write {@link android.os.ParcelFileDescriptor} pointing to a file in which
    --you must write a representation of the data that you delivered to {@code data} (a representation
    --can be as simple as the last-modified timestamp for your file). This object is
    --returned as {@code oldState} the next time the Backup Manager calls your {@link
    --android.app.backup.BackupAgent#onBackup(ParcelFileDescriptor,BackupDataOutput,ParcelFileDescriptor)
    --onBackup()} method. If you do not write your backup data to {@code newState}, then {@code oldState}
    --will point to an empty file next time Backup Manager calls {@link
    --android.app.backup.BackupAgent#onBackup(ParcelFileDescriptor,BackupDataOutput,ParcelFileDescriptor)
    --onBackup()}.</dd>
    --</dl>
    --
    --<p>Using these parameters, you should implement your {@link
    --android.app.backup.BackupAgent#onBackup(ParcelFileDescriptor,BackupDataOutput,ParcelFileDescriptor)
    --onBackup()} method to do the following:</p>
    --
    --<ol>
    --  <li>Check whether your data has changed since the last backup by comparing {@code oldState} to
    --your current data. How you read data in {@code oldState} depends on how you originally wrote it to
    --{@code newState} (see step 3). The easiest way to record the state of a file is with its
    --last-modified timestamp. For example, here's how you can read and compare a timestamp from {@code
    --oldState}:
    --    <pre>
    --// Get the oldState input stream
    --FileInputStream instream = new FileInputStream(oldState.getFileDescriptor());
    --DataInputStream in = new DataInputStream(instream);
    --
    --try {
    --    // Get the last modified timestamp from the state file and data file
    --    long stateModified = in.readLong();
    --    long fileModified = mDataFile.lastModified();
    --
    --    if (stateModified != fileModified) {
    --        // The file has been modified, so do a backup
    --        // Or the time on the device changed, so be safe and do a backup
    --    } else {
    --        // Don't back up because the file hasn't changed
    --        return;
    --    }
    --} catch (IOException e) {
    --    // Unable to read state file... be safe and do a backup
    --}
    --</pre>
    --    <p>If nothing has changed and you don't need to back up, skip to step 3.</p>
    --  </li>
    --  <li>If your data has changed, compared to {@code oldState}, write the current data to
    --{@code data} to back it up to the cloud storage.
    --    <p>You must write each chunk of data as an "entity" in the {@link
    --android.app.backup.BackupDataOutput}. An entity is a flattened binary data
    --record that is identified by a unique key string. Thus, the data set that you back up is
    --conceptually a set of key-value pairs.</p>
    --    <p>To add an entity to your backup data set, you must:</p>
    --    <ol>
    --      <li>Call {@link android.app.backup.BackupDataOutput#writeEntityHeader(String,int)
    --writeEntityHeader()}, passing a unique string key for the data you're about to write and the data
    --size.</li>
    --      <li>Call {@link android.app.backup.BackupDataOutput#writeEntityData(byte[],int)
    --writeEntityData()}, passing a byte buffer that contains your data and the number of bytes to write
    --from the buffer (which should match the size passed to {@link
    --android.app.backup.BackupDataOutput#writeEntityHeader(String,int) writeEntityHeader()}).</li>
    --    </ol>
    --    <p>For example, the following code flattens some data into a byte stream and writes it into a
    --single entity:</p>
    --    <pre>
    --// Create buffer stream and data output stream for our data
    --ByteArrayOutputStream bufStream = new ByteArrayOutputStream();
    --DataOutputStream outWriter = new DataOutputStream(bufStream);
    --// Write structured data
    --outWriter.writeUTF(mPlayerName);
    --outWriter.writeInt(mPlayerScore);
    --// Send the data to the Backup Manager via the BackupDataOutput
    --byte[] buffer = bufStream.toByteArray();
    --int len = buffer.length;
    --data.writeEntityHeader(TOPSCORE_BACKUP_KEY, len);
    --data.writeEntityData(buffer, len);
    --</pre>
    --    <p>Perform this for each piece of data that you want to back up. How you divide your data into
    --entities is up to you (and you might use just one entity).</p>
    --  </li>
    --  <li>Whether or not you perform a backup (in step 2), write a representation of the current data to
    --the {@code newState} {@link android.os.ParcelFileDescriptor}. The Backup Manager retains this object
    --locally as a representation of the data that is currently backed up. It passes this back to you as
    --{@code oldState} the next time it calls {@link
    --android.app.backup.BackupAgent#onBackup(ParcelFileDescriptor,BackupDataOutput,ParcelFileDescriptor)
    --onBackup()} so you can determine whether another backup is necessary (as handled in step 1). If you
    --do not write the current data state to this file, then
    --{@code oldState} will be empty during the next callback.
    --    <p>The following example saves a representation of the current data into {@code newState} using
    --the file's last-modified timestamp:</p>
    --    <pre>
    --FileOutputStream outstream = new FileOutputStream(newState.getFileDescriptor());
    --DataOutputStream out = new DataOutputStream(outstream);
    --
    --long modified = mDataFile.lastModified();
    --out.writeLong(modified);
    --</pre>
    --  </li>
    --</ol>
    --
    --<p class="caution"><strong>Caution:</strong> If your application data is saved to a file, make sure
    --that you use synchronized statements while accessing the file so that your backup agent does not
    --read the file while an Activity in your application is also writing the file.</p>
    --
    --
    --
    --
    --<h3 id="PerformingRestore">Performing restore</h3>
    --
    --<p>When it's time to restore your application data, the Backup Manager calls your backup
    --agent's {@link android.app.backup.BackupAgent#onRestore(BackupDataInput,int,ParcelFileDescriptor)
    --onRestore()} method. When it calls this method, the Backup Manager delivers your backup data so
    --you can restore it onto the device.</p>
    --
    --<p>Only the Backup Manager can call {@link
    --android.app.backup.BackupAgent#onRestore(BackupDataInput,int,ParcelFileDescriptor)
    --onRestore()}, which happens automatically when the system installs your application and
    --finds existing backup data. However, you can request a restore operation for
    --your application by calling {@link
    --android.app.backup.BackupManager#requestRestore(RestoreObserver) requestRestore()} (see <a
    --href="#RequestingRestore">Requesting restore</a> for more information).</p>
    --
    --<p class="note"><strong>Note:</strong> While developing your application, you can also request a
    --restore operation with the <a href="{@docRoot}tools/help/bmgr.html">{@code bmgr}
    --tool</a>.</p>
    --
    --<p>When the Backup Manager calls your {@link
    --android.app.backup.BackupAgent#onRestore(BackupDataInput,int,ParcelFileDescriptor)
    --onRestore()} method, it passes three parameters:</p>
    --
    --<dl>
    --  <dt>{@code data}</dt>
    --    <dd>A {@link android.app.backup.BackupDataInput}, which allows you to read your backup
    --data.</dd>
    --  <dt>{@code appVersionCode}</dt>
    --    <dd>An integer representing the value of your application's <a
    --href="{@docRoot}guide/topics/manifest/manifest-element.html#vcode">{@code android:versionCode}</a>
    --manifest attribute, as it was when this data was backed up. You can use this to cross-check the
    --current application version and determine if the data format is compatible. For more
    --information about using this to handle different versions of restore data, see the section
    --below about <a href="#RestoreVersion">Checking the Restore Data Version</a>.</dd>
    --  <dt>{@code newState}</dt>
    --    <dd>An open, read/write {@link android.os.ParcelFileDescriptor} pointing to a file in which
    --you must write the final backup state that was provided with {@code data}. This object is
    --returned as {@code oldState} the next time {@link
    --android.app.backup.BackupAgent#onBackup(ParcelFileDescriptor,BackupDataOutput,ParcelFileDescriptor)
    --onBackup()} is called. Recall that you must also write the same {@code newState} object in the
    --{@link
    --android.app.backup.BackupAgent#onBackup(ParcelFileDescriptor,BackupDataOutput,ParcelFileDescriptor)
    --onBackup()} callback&mdash;also doing it here ensures that the {@code oldState} object given to
    --{@link
    --android.app.backup.BackupAgent#onBackup(ParcelFileDescriptor,BackupDataOutput,ParcelFileDescriptor)
    --onBackup()} is valid even the first time {@link
    --android.app.backup.BackupAgent#onBackup(ParcelFileDescriptor,BackupDataOutput,ParcelFileDescriptor)
    --onBackup()} is called after the device is restored.</dd>
    --</dl>
    --
    --<p>In your implementation of {@link
    --android.app.backup.BackupAgent#onRestore(BackupDataInput,int,ParcelFileDescriptor)
    --onRestore()}, you should call {@link android.app.backup.BackupDataInput#readNextHeader()} on the
    --{@code data} to iterate
    --through all entities in the data set. For each entity found, do the following:</p>
    --
    --<ol>
    --  <li>Get the entity key with {@link android.app.backup.BackupDataInput#getKey()}.</li>
    --  <li>Compare the entity key to a list of known key values that you should have declared as static
    --final strings inside your {@link android.app.backup.BackupAgent} class. When the key matches one of
    --your known key strings, enter into a statement to extract the entity data and save it to the device:
    --    <ol>
    --      <li>Get the entity data size with {@link
    --android.app.backup.BackupDataInput#getDataSize()} and create a byte array of that size.</li>
    --      <li>Call {@link android.app.backup.BackupDataInput#readEntityData(byte[],int,int)
    --readEntityData()} and pass it the byte array, which is where the data will go, and specify the
    --start offset and the size to read.</li>
    --      <li>Your byte array is now full and you can read the data and write it to the device
    --however you like.</li>
    --    </ol>
    --  </li>
    --  <li>After you read and write your data back to the device, write the state of your data to the
    --{@code newState} parameter the same as you do during {@link
    --android.app.backup.BackupAgent#onBackup(ParcelFileDescriptor,BackupDataOutput,ParcelFileDescriptor)
    --onBackup()}.
    --</ol>
    -+page.title=Backing up App Data to the Cloud
    -+page.tags=cloud,sync,backup
    - 
    --<p>For example, here's how you can restore the data backed up by the example in the previous
    --section:</p>
    --
    --<pre>
    --&#64;Override
    --public void onRestore(BackupDataInput data, int appVersionCode,
    --                      ParcelFileDescriptor newState) throws IOException {
    --    // There should be only one entity, but the safest
    --    // way to consume it is using a while loop
    --    while (data.readNextHeader()) {
    --        String key = data.getKey();
    --        int dataSize = data.getDataSize();
    --
    --        // If the key is ours (for saving top score). Note this key was used when
    --        // we wrote the backup entity header
    --        if (TOPSCORE_BACKUP_KEY.equals(key)) {
    --            // Create an input stream for the BackupDataInput
    --            byte[] dataBuf = new byte[dataSize];
    --            data.readEntityData(dataBuf, 0, dataSize);
    --            ByteArrayInputStream baStream = new ByteArrayInputStream(dataBuf);
    --            DataInputStream in = new DataInputStream(baStream);
    --
    --            // Read the player name and score from the backup data
    --            mPlayerName = in.readUTF();
    --            mPlayerScore = in.readInt();
    --
    --            // Record the score on the device (to a file or something)
    --            recordScore(mPlayerName, mPlayerScore);
    --        } else {
    --            // We don't know this entity key. Skip it. (Shouldn't happen.)
    --            data.skipEntityData();
    --        }
    --    }
    --
    --    // Finally, write to the state blob (newState) that describes the restored data
    --    FileOutputStream outstream = new FileOutputStream(newState.getFileDescriptor());
    --    DataOutputStream out = new DataOutputStream(outstream);
    --    out.writeUTF(mPlayerName);
    --    out.writeInt(mPlayerScore);
    --}
    --</pre>
    --
    --<p>In this example, the {@code appVersionCode} parameter passed to {@link
    --android.app.backup.BackupAgent#onRestore onRestore()} is not used. However, you might want to use
    --it if you've chosen to perform backup when the user's version of the application has actually moved
    --backward (for example, the user went from version 1.5 of your app to 1.0). For more information, see
    --the section about <a href="#RestoreVersion">Checking the Restore Data Version</a>.</p>
    --
    --<div class="special">
    --<p>For an example implementation of {@link android.app.backup.BackupAgent}, see the <a
    --href="{@docRoot}resources/samples/BackupRestore/src/com/example/android/backuprestore/ExampleAgent.html">{@code
    --ExampleAgent}</a> class in the <a
    --href="{@docRoot}resources/samples/BackupRestore/index.html">Backup and Restore</a> sample
    --application.</p>
    --</div>
    --
    --
    --
    --
    --
    --
    --<h2 id="BackupAgentHelper">Extending BackupAgentHelper</h2>
    --
    --<p>You should build your backup agent using {@link android.app.backup.BackupAgentHelper} if you want
    --to back up complete files (from either {@link android.content.SharedPreferences} or <a
    --href="{@docRoot}guide/topics/data/data-storage.html#filesInternal">internal storage</a>).
    --Building your backup agent with {@link android.app.backup.BackupAgentHelper} requires far less
    --code than extending {@link android.app.backup.BackupAgent}, because you don't have to implement
    --{@link
    --android.app.backup.BackupAgent#onBackup(ParcelFileDescriptor,BackupDataOutput,ParcelFileDescriptor)
    --onBackup()} and {@link
    --android.app.backup.BackupAgent#onRestore(BackupDataInput,int,ParcelFileDescriptor)
    --onRestore()}.</p>
    --
    --<p>Your implementation of {@link android.app.backup.BackupAgentHelper} must
    --use one or more backup helpers. A backup helper is a specialized
    --component that {@link android.app.backup.BackupAgentHelper} summons to perform backup and
    --restore operations for a particular type of data. The Android framework currently provides two
    --different helpers:</p>
    --<ul>
    --  <li>{@link android.app.backup.SharedPreferencesBackupHelper} to backup {@link
    --android.content.SharedPreferences} files.</li>
    --  <li>{@link android.app.backup.FileBackupHelper} to backup files from <a
    --href="{@docRoot}guide/topics/data/data-storage.html#filesInternal">internal storage</a>.</li>
    --</ul>
    --
    --<p>You can include multiple helpers in your {@link android.app.backup.BackupAgentHelper}, but only
    --one helper is needed for each data type. That is, if you have multiple {@link
    --android.content.SharedPreferences} files, then you need only one {@link
    --android.app.backup.SharedPreferencesBackupHelper}.</p>
    --
    --<p>For each helper you want to add to your {@link android.app.backup.BackupAgentHelper}, you must do
    --the following during your {@link android.app.backup.BackupAgent#onCreate()} method:</p>
    --<ol>
    --  <li>Instantiate in instance of the desired helper class. In the class constructor, you must
    --specify the appropriate file(s) you want to backup.</li>
    --  <li>Call {@link android.app.backup.BackupAgentHelper#addHelper(String,BackupHelper) addHelper()}
    --to add the helper to your {@link android.app.backup.BackupAgentHelper}.</li>
    --</ol>
    --
    --<p>The following sections describe how to create a backup agent using each of the available
    --helpers.</p>
    --
    --
    --
    --<h3 id="SharedPreferences">Backing up SharedPreferences</h3>
    --
    --<p>When you instantiate a {@link android.app.backup.SharedPreferencesBackupHelper}, you must
    --include the name of one or more {@link android.content.SharedPreferences} files.</p>
    --
    --<p>For example, to back up a {@link android.content.SharedPreferences} file named
    --"user_preferences", a complete backup agent using {@link android.app.backup.BackupAgentHelper} looks
    --like this:</p>
    --
    --<pre>
    --public class MyPrefsBackupAgent extends BackupAgentHelper {
    --    // The name of the SharedPreferences file
    --    static final String PREFS = "user_preferences";
    --
    --    // A key to uniquely identify the set of backup data
    --    static final String PREFS_BACKUP_KEY = "prefs";
    --
    --    // Allocate a helper and add it to the backup agent
    --    &#64;Override
    --    public void onCreate() {
    --        SharedPreferencesBackupHelper helper =
    --                new SharedPreferencesBackupHelper(this, PREFS);
    --        addHelper(PREFS_BACKUP_KEY, helper);
    --    }
    --}
    --</pre>
    --
    --<p>That's it! That's your entire backup agent. The {@link
    --android.app.backup.SharedPreferencesBackupHelper} includes all the code
    --needed to backup and restore a {@link android.content.SharedPreferences} file.</p>
    --
    --<p>When the Backup Manager calls {@link
    --android.app.backup.BackupAgent#onBackup(ParcelFileDescriptor,BackupDataOutput,ParcelFileDescriptor)
    --onBackup()} and {@link
    --android.app.backup.BackupAgent#onRestore(BackupDataInput,int,ParcelFileDescriptor)
    --onRestore()}, {@link android.app.backup.BackupAgentHelper} calls your backup helpers to perform
    --backup and restore for your specified files.</p>
    --
    --<p class="note"><strong>Note:</strong> {@link android.content.SharedPreferences} are threadsafe, so
    --you can safely read and write the shared preferences file from your backup agent and
    --other activities.</p>
    --
    --
    --
    --<h3 id="Files">Backing up other files</h3>
    --
    --<p>When you instantiate a {@link android.app.backup.FileBackupHelper}, you must include the name of
    --one or more files that are saved to your application's <a
    --href="{@docRoot}guide/topics/data/data-storage.html#filesInternal">internal storage</a>
    --(as specified by {@link android.content.ContextWrapper#getFilesDir()}, which is the same
    --location where {@link android.content.Context#openFileOutput(String,int) openFileOutput()} writes
    --files).</p>
    --
    --<p>For example, to backup two files named "scores" and "stats," a backup agent using {@link
    --android.app.backup.BackupAgentHelper} looks like this:</p>
    --
    --<pre>
    --public class MyFileBackupAgent extends BackupAgentHelper {
    --    // The name of the file
    --    static final String TOP_SCORES = "scores";
    --    static final String PLAYER_STATS = "stats";
    --
    --    // A key to uniquely identify the set of backup data
    --    static final String FILES_BACKUP_KEY = "myfiles";
    --
    --    // Allocate a helper and add it to the backup agent
    --    &#64;Override
    --    public void onCreate() {
    --        FileBackupHelper helper = new FileBackupHelper(this,
    --                TOP_SCORES, PLAYER_STATS);
    --        addHelper(FILES_BACKUP_KEY, helper);
    --    }
    --}
    --</pre>
    --
    --<p>The {@link android.app.backup.FileBackupHelper} includes all the code necessary to backup and
    --restore files that are saved to your application's <a
    --href="{@docRoot}guide/topics/data/data-storage.html#filesInternal">internal storage</a>..</p>
    --
    --<p>However, reading and writing to files on internal storage is <strong>not threadsafe</strong>. To
    --ensure that your backup agent does not read or write your files at the same time as your activities,
    --you must use synchronized statements each time you perform a read or write. For example,
    --in any Activity where you read and write the file, you need an object to use as the intrinsic
    --lock for the synchronized statements:</p>
    --
    --<pre>
    --// Object for intrinsic lock
    --static final Object sDataLock = new Object();
    --</pre>
    --
    --<p>Then create a synchronized statement with this lock each time you read or write the files. For
    --example, here's a synchronized statement for writing the latest score in a game to a file:</p>
    --
    --<pre>
    --try {
    --    synchronized (MyActivity.sDataLock) {
    --        File dataFile = new File({@link android.content.Context#getFilesDir()}, TOP_SCORES);
    --        RandomAccessFile raFile = new RandomAccessFile(dataFile, "rw");
    --        raFile.writeInt(score);
    --    }
    --} catch (IOException e) {
    --    Log.e(TAG, "Unable to write to file");
    --}
    --</pre>
    --
    --<p>You should synchronize your read statements with the same lock.</p>
    --
    --<p>Then, in your {@link android.app.backup.BackupAgentHelper}, you must override {@link
    --android.app.backup.BackupAgent#onBackup(ParcelFileDescriptor,BackupDataOutput,ParcelFileDescriptor)
    --onBackup()} and {@link
    --android.app.backup.BackupAgent#onRestore(BackupDataInput,int,ParcelFileDescriptor)
    --onRestore()} to synchronize the backup and restore operations with the same
    --intrinsic lock. For example, the {@code MyFileBackupAgent} example from above needs the following
    --methods:</p>
    --
    --<pre>
    --&#64;Override
    --public void onBackup(ParcelFileDescriptor oldState, BackupDataOutput data,
    --          ParcelFileDescriptor newState) throws IOException {
    --    // Hold the lock while the FileBackupHelper performs backup
    --    synchronized (MyActivity.sDataLock) {
    --        super.onBackup(oldState, data, newState);
    --    }
    --}
    --
    --&#64;Override
    --public void onRestore(BackupDataInput data, int appVersionCode,
    --        ParcelFileDescriptor newState) throws IOException {
    --    // Hold the lock while the FileBackupHelper restores the file
    --    synchronized (MyActivity.sDataLock) {
    --        super.onRestore(data, appVersionCode, newState);
    --    }
    --}
    --</pre>
    --
    --<p>That's it. All you need to do is add your {@link android.app.backup.FileBackupHelper} in the
    --{@link android.app.backup.BackupAgent#onCreate()} method and override {@link
    --android.app.backup.BackupAgent#onBackup(ParcelFileDescriptor,BackupDataOutput,ParcelFileDescriptor)
    --onBackup()} and {@link
    --android.app.backup.BackupAgent#onRestore(BackupDataInput,int,ParcelFileDescriptor)
    --onRestore()} to synchronize read and write operations.</p>
    --
    --<div class="special">
    --<p>For an example implementation of {@link
    --android.app.backup.BackupAgentHelper} with {@link android.app.backup.FileBackupHelper}, see the
    --{@code FileHelperExampleAgent} class in the <a
    --href="{@docRoot}resources/samples/BackupRestore/index.html">Backup and Restore</a> sample
    --application.</p>
    --</div>
    --
    --
    --
    --
    --
    --
    --<h2 id="RestoreVersion">Checking the Restore Data Version</h2>
    --
    --<p>When the Backup Manager saves your data to cloud storage, it automatically includes the version
    --of your application, as defined by your manifest file's <a
    --href="{@docRoot}guide/topics/manifest/manifest-element.html#vcode">{@code android:versionCode}</a>
    --attribute. Before the Backup Manager calls your backup agent to restore your data, it
    --looks at the <a
    --href="{@docRoot}guide/topics/manifest/manifest-element.html#vcode">{@code
    --android:versionCode}</a> of the installed application and compares it to the value
    --recorded in the restore data set. If the version recorded in the restore data set is
    --<em>newer</em> than the application version on the device, then the user has downgraded their
    --application. In this case, the Backup Manager will abort the restore operation for your application
    --and not call your {@link
    --android.app.backup.BackupAgent#onRestore(BackupDataInput,int,ParcelFileDescriptor) onRestore()}
    --method, because the restore set is considered meaningless to an older version.</p>
    --
    --<p>You can override this behavior with the <a
    --href="{@docRoot}guide/topics/manifest/application-element.html#restoreany">{@code
    --android:restoreAnyVersion}</a> attribute. This attribute is either "{@code true}" or "{@code
    --false}" to indicate whether you want to restore the application regardless of the restore set
    --version. The default value is "{@code false}". If you define this to be "{@code true}" then the
    --Backup Manager will ignore the <a
    --href="{@docRoot}guide/topics/manifest/manifest-element.html#vcode">{@code android:versionCode}</a>
    --and call your {@link
    --android.app.backup.BackupAgent#onRestore(BackupDataInput,int,ParcelFileDescriptor) onRestore()}
    --method in all cases. In doing so, you can manually check for the version difference in your {@link
    --android.app.backup.BackupAgent#onRestore(BackupDataInput,int,ParcelFileDescriptor) onRestore()}
    --method and take any steps necessary to make the data compatible if the versions conflict.</p>
    --
    --<p>To help you handle different versions during a restore operation, the {@link
    --android.app.backup.BackupAgent#onRestore(BackupDataInput,int,ParcelFileDescriptor) onRestore()}
    --method passes you the version code included with the restore data set as the {@code appVersionCode}
    --parameter. You can then query the current application's version code with the {@link
    --android.content.pm.PackageInfo#versionCode PackageInfo.versionCode} field. For example:</p>
    --
    --<pre>
    --PackageInfo info;
    --try {
    --    String name = {@link android.content.ContextWrapper#getPackageName() getPackageName}();
    --    info = {@link android.content.ContextWrapper#getPackageManager
    --getPackageManager}().{@link android.content.pm.PackageManager#getPackageInfo(String,int)
    --getPackageInfo}(name,0);
    --} catch (NameNotFoundException nnfe) {
    --    info = null;
    --}
    --
    --int version;
    --if (info != null) {
    --    version = info.versionCode;
    --}
    --</pre>
    --
    --<p>Then simply compare the {@code version} acquired from {@link android.content.pm.PackageInfo}
    --to the {@code appVersionCode} passed into {@link
    --android.app.backup.BackupAgent#onRestore(BackupDataInput,int,ParcelFileDescriptor) onRestore()}.
    --</p>
    --
    --<p class="caution"><strong>Caution:</strong> Be certain you understand the consequences of setting
    --<a href="{@docRoot}guide/topics/manifest/application-element.html#restoreany">{@code
    --android:restoreAnyVersion}</a> to "{@code true}" for your application. If each version of your
    --application that supports backup does not properly account for variations in your data format during
    --{@link
    --android.app.backup.BackupAgent#onRestore(BackupDataInput,int,ParcelFileDescriptor) onRestore()},
    --then the data on the device could be saved in a format incompatible with the version currently
    --installed on the device.</p>
    --
    --
    --
    --<h2 id="RequestingBackup">Requesting Backup</h2>
    --
    --<p>You can request a backup operation at any time by calling {@link
    --android.app.backup.BackupManager#dataChanged()}. This method notifies the Backup Manager that you'd
    --like to backup your data using your backup agent. The Backup Manager then calls your backup
    --agent's {@link
    --android.app.backup.BackupAgent#onBackup(ParcelFileDescriptor,BackupDataOutput,ParcelFileDescriptor)
    --onBackup()} method at an opportune time in the future. Typically, you should
    --request a backup each time your data changes (such as when the user changes an application
    --preference that you'd like to back up). If you call {@link
    --android.app.backup.BackupManager#dataChanged()} several times consecutively, before the Backup
    --Manager requests a backup from your agent, your agent still receives just one call to {@link
    --android.app.backup.BackupAgent#onBackup(ParcelFileDescriptor,BackupDataOutput,ParcelFileDescriptor)
    --onBackup()}.</p>
    --
    --<p class="note"><strong>Note:</strong> While developing your application, you can request a
    --backup and initiate an immediate backup operation with the <a
    --href="{@docRoot}tools/help/bmgr.html">{@code bmgr}
    --tool</a>.</p>
    --
    --
    --<h2 id="RequestingRestore">Requesting Restore</h2>
    --
    --<p>During the normal life of your application, you shouldn't need to request a restore operation.
    --They system automatically checks for backup data and performs a restore when your application is
    --installed. However, you can manually request a restore operation by calling {@link
    --android.app.backup.BackupManager#requestRestore(RestoreObserver) requestRestore()}, if necessary. In
    --which case, the Backup Manager calls your {@link
    --android.app.backup.BackupAgent#onRestore(BackupDataInput,int,ParcelFileDescriptor) onRestore()}
    --implementation, passing the data from the current set of backup data.</p>
    --
    --<p class="note"><strong>Note:</strong> While developing your application, you can request a
    --restore operation with the <a href="{@docRoot}tools/help/bmgr.html">{@code bmgr}
    --tool</a>.</p>
    --
    --
    --<h2 id="Testing">Testing Your Backup Agent</h2>
    --
    --<p>Once you've implemented your backup agent, you can test the backup and restore functionality
    --with the following procedure, using <a
    --href="{@docRoot}tools/help/bmgr.html">{@code bmgr}</a>.</p>
    --
    --<ol>
    --  <li>Install your application on a suitable Android system image
    --    <ul>
    --      <li>If using the emulator, create and use an AVD with Android 2.2 (API Level 8).</li>
    --      <li>If using a device, the device must be running Android 2.2 or greater and have Google
    --Play built in.</li>
    --    </ul>
    --  </li>
    --  <li>Ensure that backup is enabled
    --    <ul>
    --      <li>If using the emulator, you can enable backup with the following command from your SDK
    --{@code tools/} path:
    --<pre class="no-pretty-print">adb shell bmgr enable true</pre>
    --      </li>
    --      <li>If using a device, open the system <b>Settings</b>, select
    --      <b>Backup & reset</b>, then enable
    --      <b>Back up my data</b> and <b>Automatic restore</b>.</li>
    --    </ul>
    --  </li>
    --  <li>Open your application and initialize some data
    --    <p>If you've properly implemented backup in your application, then it should request a
    --backup each time the data changes. For example, each time the user changes some data, your app
    --should call {@link android.app.backup.BackupManager#dataChanged()}, which adds a backup request to
    --the Backup Manager queue. For testing purposes, you can also make a request with the following
    --{@code bmgr} command:</p>
    --<pre class="no-pretty-print">adb shell bmgr backup <em>your.package.name</em></pre>
    --  </li>
    --  <li>Initiate a backup operation:
    --<pre class="no-pretty-print">adb shell bmgr run</pre>
    --    <p>This forces the Backup Manager to perform all backup requests that are in its
    --queue.</p>
    --  <li>Uninstall your application:
    --<pre class="no-pretty-print">adb uninstall <em>your.package.name</em></pre>
    --  </li>
    --  <li>Re-install your application.</li>
    --</ol>
    --
    --<p>If your backup agent is successful, all the data you initialized in step 4 is restored.</p>
    -+startpage=true
    - 
    -+@jd:body
    - 
    -+<p>Users often invest significant time and effort creating data and setting
    -+preferences within apps. Preserving that data for users if they replace a broken
    -+device or upgrade to a new one is an important part of ensuring a great user
    -+experience. This section covers techniques for backing up data to the cloud so
    -+that users can restore their data.
    -+
    -+<p>Android provides two ways for apps to backup their data to the cloud:
    -+<a href="{@docRoot}guide/topics/data/autobackup.html">Auto Backup for Apps</a> and
    -+<a href="{@docRoot}guide/topics/data/keyvaluebackup.html">Key/Value Backup</a>.
    -+Auto Backup, which is available starting API 23, preserves app data by uploading
    -+it to the user’s Google Drive account. The Key/Value Backup feature (formerly
    -+known as the Backup API and the Android Backup Service) preserves app data by
    -+uploading it to the <a href="{@docRoot}google/backup/index.html">Android Backup Service</a>.
    -+
    -+<p>Generally, we recommend Auto Backup because it requires no work to implement.
    -+Apps that target Android 6.0 (API level 23) or higher are automatically enabled
    -+for Auto Backup. The Auto Backup feature does have some limitations in terms of
    -+what data it can backup and it's availability on Android 6.0 and higher devices.
    -+Consider using the Key/Value Backup feature if you have more specific needs for
    -+backing up your app data. For more information, see <a href="{@docRoot}guide/topics/data/keyvaluebackup.html#Comparison">Comparison of Key/Value and Auto Backup</a></p>
    -+
    -+<p class="note"><strong>Note:</strong> These data backup features are not designed for synchronizing app data with other clients or
    -+saving data that you'd like to access during the normal application lifecycle.
    -+You cannot read or write backup data on demand. For synchronizing app data, see
    -+<a href="{@docRoot}training/sync-adapters/index.html">Transferring
    -+Data Using Sync Adapters</a> or <a href="https://developers.google.com/drive/android/">Google Drive Android
    -+API</a>.
    -\ No newline at end of file
    -diff --git a/docs/html/guide/topics/data/images/backup-framework.png b/docs/html/guide/topics/data/images/backup-framework.png
    -new file mode 100644
    -index 0000000..2ba2e612
    -Binary files /dev/null and b/docs/html/guide/topics/data/images/backup-framework.png differ
    -diff --git a/docs/html/guide/topics/data/index.jd b/docs/html/guide/topics/data/index.jd
    -index 3872825..2365f18 100644
    ---- a/docs/html/guide/topics/data/index.jd
    -+++ b/docs/html/guide/topics/data/index.jd
    -@@ -5,21 +5,3 @@ page.landing.image=
    - 
    - @jd:body
    - 
    --<div class="landing-docs">
    --
    --
    --  <div class="col-12">
    --    <h3>Training</h3>
    --
    --    <a href="{@docRoot}training/backup/index.html">
    --      <h4>Backing up App Data to the Cloud</h4>
    --      <p>
    --        This class covers techniques for backing up data to the cloud so that
    --        users can restore their data when recovering from a data loss (such as a
    --        factory reset) or installing your application on a new device.
    --      </p>
    --    </a>
    --
    --  </div>
    --
    --</div>
    -diff --git a/docs/html/guide/topics/data/keyvaluebackup.jd b/docs/html/guide/topics/data/keyvaluebackup.jd
    -new file mode 100644
    -index 0000000..c7c5e2f
    ---- /dev/null
    -+++ b/docs/html/guide/topics/data/keyvaluebackup.jd
    -@@ -0,0 +1,884 @@
    -+page.title=Key/Value Backup
    -+page.tags=backup, marshmallow, androidm
    -+page.keywords=backup, kvbackup
    -+
    -+@jd:body
    -+
    -+<div id="qv-wrapper">
    -+<div id="qv">
    -+  <h2>In this document</h2>
    -+  <ol>
    -+    <li><a href="#Comparison">Comparison to Auto Backup</a></li>
    -+    <li><a href="#ImplementingBackup">Implementing Key/Value Backup</a></li>
    -+
    -+    <li><a href="#BackupManifest">Declaring the backup agent in your manifest</a></li>
    -+    <li><a href="#BackupKey">Registering for Android Backup Service</a></li>
    -+    <li><a href="#BackupAgent">Extending BackupAgent</a>
    -+      <ol>
    -+        <li><a href="#RequiredMethods">Required methods</a></li>
    -+        <li><a href="#PerformingBackup">Performing backup</a></li>
    -+        <li><a href="#PerformingRestore">Performing restore</a></li>
    -+      </ol>
    -+    </li>
    -+    <li><a href="#BackupAgentHelper">Extending BackupAgentHelper</a>
    -+      <ol>
    -+        <li><a href="#SharedPreferences">Backing up SharedPreferences</a></li>
    -+        <li><a href="#Files">Backing up private files</a></li>
    -+      </ol>
    -+    </li>
    -+    <li><a href="#RestoreVersion">Checking the restore data version</a></li>
    -+    <li><a href="#RequestingBackup">Requesting backup</a></li>
    -+    <li><a href="#RequestingRestore">Requesting restore</a></li>
    -+    <li><a href="#Migrating">Migrating to Auto Backup</a></li>
    -+  </ol>
    -+
    -+  <h2>Key classes</h2>
    -+  <ol>
    -+    <li>{@link android.app.backup.BackupManager}</li>
    -+    <li>{@link android.app.backup.BackupAgent}</li>
    -+    <li>{@link android.app.backup.BackupAgentHelper}</li>
    -+  </ol>
    -+
    -+</div>
    -+</div>
    -+
    -+
    -+<p>Since Android 2.2 (API 8), Android has offered the <em>Key/Value Backup</em>
    -+feature as a way for developers to backup app data to the cloud. The Key/Value
    -+Backup feature (formerly known as the Backup API and the Android Backup Service)
    -+preserves app data by uploading it to
    -+<a href="{@docRoot}google/backup/index.html">Android Backup Service</a>.
    -+The amount of data is limited to 5MB per user of your app and there is
    -+no charge for storing backup data.
    -+
    -+<p class="note"><strong>Note:</strong> If your app implements Key/Value Backup
    -+and targets API 23 or higher, you should set
    -+<a href="{@docRoot}reference/android/R.attr.html#fullBackupOnly">android:fullBackupOnly</a>.
    -+This attribute indicates whether or not to use Auto Backup on devices where it is available.
    -+
    -+<h2 id="Comparison">Comparison to Auto Backup</h2>
    -+<p>Like Auto Backup, Key/Value Backups are restored automatically whenever the app
    -+is installed. The following table describes some of the key differences between Key/Value Backup and Auto Backup:
    -+
    -+<table>
    -+  <tr>
    -+   <th>Key/Value Backup</th>
    -+   <th>Auto Backup</th>
    -+  </tr>
    -+  <tr>
    -+   <td>Available in API 8, Android 2.2</td>
    -+   <td>Available in API 23, Android 6.0</td>
    -+  </tr>
    -+  <tr>
    -+   <td>Apps must implement a {@link android.app.backup.BackupAgent}. The backup agent defines what data to backup and how to
    -+restore data.</td>
    -+   <td>By default, Auto Backup includes almost all of the app's files. You can
    -+use XML to include and exclude files. Under the hood, Auto Backup relies on a
    -+backup agent that is built into the framework.</td>
    -+  </tr>
    -+  <tr>
    -+   <td>Apps must issue a request when there is data
    -+that is ready to be backed up. Requests
    -+from multiple apps are batched and executed every few hours.</td>
    -+   <td>Backups happen automatically roughly once a day.</td>
    -+  </tr>
    -+  <tr>
    -+   <td>Backup data can be transmitted via wifi or cellular data.</td>
    -+   <td>Backup data is tranmitted only via wifi. If the device is never connected to a
    -+wifi network, then Auto Backup never occurs.</td>
    -+  </tr>
    -+  <tr>
    -+   <td>Apps are not shut down during backup.</td>
    -+   <td>The system shuts down the app during backup.</td>
    -+  </tr>
    -+  <tr>
    -+   <td>Backup data is stored in <a href="{@docRoot}google/backup/index.html">Android Backup Service</a> limited to 5MB per app.</td>
    -+   <td>Backup data is stored in the user's Google Drive limited to 25MB per app.</td>
    -+  </tr>
    -+  <tr>
    -+   <td>Related API methods are not filed based:<ul>
    -+      <li>{@link android.app.backup.BackupAgent#onBackup(ParcelFileDescriptor, BackupDataOutput, ParcelFileDescriptor) onBackup()}
    -+      <li>{@link android.app.backup.BackupAgent#onRestore(BackupDataInput, int, ParcelFileDescriptor) onRestore()}</ul></td>
    -+   <td>Related API methods are filed based:<ul>
    -+<li>{@link android.app.backup.BackupAgent#onFullBackup(FullBackupDataOutput) onFullBackup()}
    -+<li>{@link android.app.backup.BackupAgent#onRestoreFile(ParcelFileDescriptor,long,File,int,long,long) onRestoreFile()}</ul></td>
    -+  </tr>
    -+</table>
    -+
    -+<h2 id="ImplementingBackup">Implementing Key/Value Backup</h2>
    -+<p>To backup your application data, you need to implement a backup agent. Your backup
    -+agent is called by the Backup Manager both during backup and restore.</p>
    -+
    -+<p>To implement a backup agent, you must:</p>
    -+
    -+<ol>
    -+  <li>Declare your backup agent in your manifest file with the <a
    -+href="{@docRoot}guide/topics/manifest/application-element.html#agent">{@code
    -+android:backupAgent}</a> attribute.</li>
    -+  <li>Register your application with <a href="{@docRoot}google/backup/index.html">Android
    -+   Backup Service</a></li>
    -+  <li>Define a backup agent by either:</p>
    -+    <ol type="a">
    -+      <li><a href="#BackupAgent">Extending BackupAgent</a>
    -+        <p>The {@link android.app.backup.BackupAgent} class provides the central interface with
    -+which your application communicates with the Backup Manager. If you extend this class
    -+directly, you must override {@link
    -+android.app.backup.BackupAgent#onBackup(ParcelFileDescriptor,BackupDataOutput,ParcelFileDescriptor)
    -+onBackup()} and {@link
    -+android.app.backup.BackupAgent#onRestore(BackupDataInput,int,ParcelFileDescriptor)
    -+onRestore()} to handle the backup and restore operations for your data.</p>
    -+        <p><em>Or</em></p>
    -+      <li><a href="#BackupAgentHelper">Extending BackupAgentHelper</a>
    -+        <p>The {@link android.app.backup.BackupAgentHelper} class provides a convenient
    -+wrapper around the {@link android.app.backup.BackupAgent} class, which minimizes the amount of code
    -+you need to write. In your {@link android.app.backup.BackupAgentHelper}, you must use one or more
    -+"helper" objects, which automatically backup and restore certain types of data, so that you do not
    -+need to implement {@link
    -+android.app.backup.BackupAgent#onBackup(ParcelFileDescriptor,BackupDataOutput,ParcelFileDescriptor)
    -+onBackup()} and {@link
    -+android.app.backup.BackupAgent#onRestore(BackupDataInput,int,ParcelFileDescriptor)
    -+onRestore()}.</p>
    -+        <p>Android currently provides backup helpers that will backup and restore complete files
    -+from {@link android.content.SharedPreferences} and <a
    -+href="{@docRoot}guide/topics/data/data-storage.html#filesInternal">internal storage</a>.</p>
    -+      </li>
    -+    </ol>
    -+  </li>
    -+</ol>
    -+
    -+<h2 id="BackupManifest">Declaring the backup agent in your manifest</h2>
    -+
    -+<p>This is the easiest step, so once you've decided on the class name for your backup agent, declare
    -+it in your manifest with the <a
    -+href="{@docRoot}guide/topics/manifest/application-element.html#agent">{@code
    -+android:backupAgent}</a> attribute in the <a
    -+href="{@docRoot}guide/topics/manifest/application-element.html">{@code
    -+<application>}</a> tag.</p>
    -+
    -+<p>For example:</p>
    -+
    -+<pre>
    -+&lt;manifest ... &gt;
    -+    ...
    -+    &lt;application android:label="MyApplication"
    -+                 <b>android:backupAgent="MyBackupAgent"</b>&gt;
    -+        &lt;activity ... &gt;
    -+            ...
    -+        &lt;/activity&gt;
    -+    &lt;/application&gt;
    -+&lt;/manifest&gt;
    -+</pre>
    -+
    -+<p>Another attribute you might want to use is <a
    -+href="{@docRoot}guide/topics/manifest/application-element.html#restoreany">{@code
    -+android:restoreAnyVersion}</a>. This attribute takes a boolean value to indicate whether you
    -+want to restore the application data regardless of the current application version compared to the
    -+version that produced the backup data. (The default value is "{@code false}".) See <a
    -+href="#RestoreVersion">Checking the Restore Data Version</a> for more information.</p>
    -+
    -+<p class="note"><strong>Note:</strong> The backup service and the APIs you must use are
    -+available only on devices running API Level 8 (Android 2.2) or greater, so you should also
    -+set your <a
    -+href="{@docRoot}guide/topics/manifest/uses-sdk-element.html#min">{@code android:minSdkVersion}</a>
    -+attribute to "8".</p>
    -+
    -+
    -+
    -+
    -+<h2 id="BackupKey">Registering for Android Backup Service</h2>
    -+
    -+<p>Google provides a backup transport with <a
    -+href="{@docRoot}google/backup/index.html">Android Backup Service</a> for most
    -+Android-powered devices running Android 2.2 or greater.</p>
    -+
    -+<p>In order for your application to perform backup using Android Backup Service, you must
    -+register your application with the service to receive a Backup Service Key, then
    -+declare the Backup Service Key in your Android manifest.</p>
    -+
    -+<p>To get your Backup Service Key, <a
    -+href="{@docRoot}google/backup/signup.html">register for Android Backup Service</a>.
    -+When you register, you will be provided a Backup Service Key and the appropriate {@code
    -+<meta-data>} XML code for your Android manifest file, which you must include as a child of the
    -+{@code <application>} element. For example:</p>
    -+
    -+<pre>
    -+&lt;application android:label="MyApplication"
    -+             android:backupAgent="MyBackupAgent"&gt;
    -+    ...
    -+    &lt;meta-data android:name="com.google.android.backup.api_key"
    -+        android:value="AEdPqrEAAAAIDaYEVgU6DJnyJdBmU7KLH3kszDXLv_4DIsEIyQ" /&gt;
    -+&lt;/application&gt;
    -+</pre>
    -+
    -+<p>The <code>android:name</code> must be <code>"com.google.android.backup.api_key"</code> and
    -+the <code>android:value</code> must be the Backup Service Key received from the Android Backup
    -+Service registration.</p>
    -+
    -+<p>If you have multiple applications, you must register each one, using the respective package
    -+name.</p>
    -+
    -+<p class="note"><strong>Note:</strong> The backup transport provided by Android Backup Service is
    -+not guaranteed to be available
    -+on all Android-powered devices that support backup. Some devices might support backup
    -+using a different transport, some devices might not support backup at all, and there is no way for
    -+your application to know what transport is used on the device. However, if you implement backup for
    -+your application, you should always include a Backup Service Key for Android Backup Service so
    -+your application can perform backup when the device uses the Android Backup Service transport. If
    -+the device does not use Android Backup Service, then the {@code <meta-data>} element with the
    -+Backup Service Key is ignored.</p>
    -+
    -+
    -+
    -+
    -+<h2 id="BackupAgent">Extending BackupAgent</h2>
    -+
    -+<p>Most applications shouldn't need to extend the {@link android.app.backup.BackupAgent} class
    -+directly, but should instead <a href="#BackupAgentHelper">extend BackupAgentHelper</a> to take
    -+advantage of the built-in helper classes that automatically backup and restore your files. However,
    -+you might want to extend {@link android.app.backup.BackupAgent} directly if you need to:</p>
    -+<ul>
    -+  <li>Version your data format. For instance, if you anticipate the need to revise the
    -+format in which you write your application data, you can build a backup agent to cross-check your
    -+application version during a restore operation and perform any necessary compatibility work if the
    -+version on the device is different than that of the backup data. For more information, see <a
    -+href="#RestoreVersion">Checking the Restore Data Version</a>.</li>
    -+  <li>Instead of backing up an entire file, you can specify the portions of data the should be
    -+backed up and how each portion is then restored to the device. (This can also help you manage
    -+different versions, because you read and write your data as unique entities, rather than
    -+complete files.)</li>
    -+  <li>Back up data in a database. If you have an SQLite database that you want to restore when
    -+the user re-installs your application, you need to build a custom {@link
    -+android.app.backup.BackupAgent} that reads the appropriate data during a backup operation, then
    -+create your table and insert the data during a restore operation.</li>
    -+</ul>
    -+
    -+<p>If you don't need to perform any of the tasks above and want to back up complete files from
    -+{@link android.content.SharedPreferences} or <a
    -+href="{@docRoot}guide/topics/data/data-storage.html#filesInternal">internal storage</a>, you
    -+should skip to <a href="#BackupAgentHelper">Extending BackupAgentHelper</a>.</p>
    -+
    -+
    -+
    -+<h3 id="RequiredMethods">Required methods</h3>
    -+
    -+<p>When you create a backup agent by extending {@link android.app.backup.BackupAgent}, you
    -+must implement the following callback methods:</p>
    -+
    -+<dl>
    -+  <dt>{@link
    -+android.app.backup.BackupAgent#onBackup(ParcelFileDescriptor,BackupDataOutput,ParcelFileDescriptor)
    -+onBackup()}</dt>
    -+    <dd>The Backup Manager calls this method after you <a href="#RequestingBackup">request a
    -+backup</a>. In this method, you read your application data from the device and pass the data you
    -+want to back up to the Backup Manager, as described below in <a href="#PerformingBackup">Performing
    -+backup</a>.</dd>
    -+
    -+  <dt>{@link
    -+android.app.backup.BackupAgent#onRestore(BackupDataInput,int,ParcelFileDescriptor)
    -+onRestore()}</dt>
    -+    <dd>The Backup Manager calls this method during a restore operation (you can <a
    -+href="#RequestingRestore">request a restore</a>, but the system automatically performs restore when
    -+the user re-installs your application). When it calls this method, the Backup Manager delivers your
    -+backup data, which you then restore to the device, as described below in <a
    -+href="#PerformingRestore">Performing restore</a>.</dd>
    -+</dl>
    -+
    -+
    -+
    -+<h3 id="PerformingBackup">Performing backup</h3>
    -+
    -+
    -+<p>When it's time to back up your application data, the Backup Manager calls your {@link
    -+android.app.backup.BackupAgent#onBackup(ParcelFileDescriptor,BackupDataOutput,ParcelFileDescriptor)
    -+onBackup()} method. This is where you must provide your application data to the Backup Manager so
    -+it can be saved to cloud storage.</p>
    -+
    -+<p>Only the Backup Manager can call your backup agent's {@link
    -+android.app.backup.BackupAgent#onBackup(ParcelFileDescriptor,BackupDataOutput,ParcelFileDescriptor)
    -+onBackup()} method. Each time that your application data changes and you want to perform a backup,
    -+you must request a backup operation by calling {@link
    -+android.app.backup.BackupManager#dataChanged()} (see <a href="#RequestingBackup">Requesting
    -+Backup</a> for more information). A backup request does not result in an immediate call to your
    -+{@link
    -+android.app.backup.BackupAgent#onBackup(ParcelFileDescriptor,BackupDataOutput,ParcelFileDescriptor)
    -+onBackup()} method. Instead, the Backup Manager waits for an appropriate time, then performs
    -+backup for all applications that have requested a backup since the last backup was performed.</p>
    -+
    -+<p class="note"><strong>Tip:</strong> While developing your application, you can initiate an
    -+immediate backup operation from the Backup Manager with the <a
    -+href="{@docRoot}tools/help/bmgr.html">{@code bmgr} tool</a>.</p>
    -+
    -+<p>When the Backup Manager calls your {@link
    -+android.app.backup.BackupAgent#onBackup(ParcelFileDescriptor,BackupDataOutput,ParcelFileDescriptor)
    -+onBackup()} method, it passes three parameters:</p>
    -+
    -+<dl>
    -+  <dt>{@code oldState}</dt>
    -+    <dd>An open, read-only {@link android.os.ParcelFileDescriptor} pointing to the last backup
    -+state provided by your application. This is not the backup data from cloud storage, but a
    -+local representation of the data that was backed up the last time {@link
    -+android.app.backup.BackupAgent#onBackup(ParcelFileDescriptor,BackupDataOutput,ParcelFileDescriptor)
    -+onBackup()} was called (as defined by {@code newState}, below, or from {@link
    -+android.app.backup.BackupAgent#onRestore(BackupDataInput,int,ParcelFileDescriptor)
    -+onRestore()}&mdash;more about this in the next section). Because {@link
    -+android.app.backup.BackupAgent#onBackup(ParcelFileDescriptor,BackupDataOutput,ParcelFileDescriptor)
    -+onBackup()} does not allow you to read existing backup data in
    -+the cloud storage, you can use this local representation to determine whether your data has changed
    -+since the last backup.</dd>
    -+  <dt>{@code data}</dt>
    -+    <dd>A {@link android.app.backup.BackupDataOutput} object, which you use to deliver your backup
    -+data to the Backup Manager.</dd>
    -+  <dt>{@code newState}</dt>
    -+    <dd>An open, read/write {@link android.os.ParcelFileDescriptor} pointing to a file in which
    -+you must write a representation of the data that you delivered to {@code data} (a representation
    -+can be as simple as the last-modified timestamp for your file). This object is
    -+returned as {@code oldState} the next time the Backup Manager calls your {@link
    -+android.app.backup.BackupAgent#onBackup(ParcelFileDescriptor,BackupDataOutput,ParcelFileDescriptor)
    -+onBackup()} method. If you do not write your backup data to {@code newState}, then {@code oldState}
    -+will point to an empty file next time Backup Manager calls {@link
    -+android.app.backup.BackupAgent#onBackup(ParcelFileDescriptor,BackupDataOutput,ParcelFileDescriptor)
    -+onBackup()}.</dd>
    -+</dl>
    -+
    -+<p>Using these parameters, you should implement your {@link
    -+android.app.backup.BackupAgent#onBackup(ParcelFileDescriptor,BackupDataOutput,ParcelFileDescriptor)
    -+onBackup()} method to do the following:</p>
    -+
    -+<ol>
    -+  <li>Check whether your data has changed since the last backup by comparing {@code oldState} to
    -+your current data. How you read data in {@code oldState} depends on how you originally wrote it to
    -+{@code newState} (see step 3). The easiest way to record the state of a file is with its
    -+last-modified timestamp. For example, here's how you can read and compare a timestamp from {@code
    -+oldState}:
    -+    <pre>
    -+// Get the oldState input stream
    -+FileInputStream instream = new FileInputStream(oldState.getFileDescriptor());
    -+DataInputStream in = new DataInputStream(instream);
    -+
    -+try {
    -+    // Get the last modified timestamp from the state file and data file
    -+    long stateModified = in.readLong();
    -+    long fileModified = mDataFile.lastModified();
    -+
    -+    if (stateModified != fileModified) {
    -+        // The file has been modified, so do a backup
    -+        // Or the time on the device changed, so be safe and do a backup
    -+    } else {
    -+        // Don't back up because the file hasn't changed
    -+        return;
    -+    }
    -+} catch (IOException e) {
    -+    // Unable to read state file... be safe and do a backup
    -+}
    -+</pre>
    -+    <p>If nothing has changed and you don't need to back up, skip to step 3.</p>
    -+  </li>
    -+  <li>If your data has changed, compared to {@code oldState}, write the current data to
    -+{@code data} to back it up to the cloud storage.
    -+    <p>You must write each chunk of data as an "entity" in the {@link
    -+android.app.backup.BackupDataOutput}. An entity is a flattened binary data
    -+record that is identified by a unique key string. Thus, the data set that you back up is
    -+conceptually a set of key-value pairs.</p>
    -+    <p>To add an entity to your backup data set, you must:</p>
    -+    <ol>
    -+      <li>Call {@link android.app.backup.BackupDataOutput#writeEntityHeader(String,int)
    -+writeEntityHeader()}, passing a unique string key for the data you're about to write and the data
    -+size.</li>
    -+      <li>Call {@link android.app.backup.BackupDataOutput#writeEntityData(byte[],int)
    -+writeEntityData()}, passing a byte buffer that contains your data and the number of bytes to write
    -+from the buffer (which should match the size passed to {@link
    -+android.app.backup.BackupDataOutput#writeEntityHeader(String,int) writeEntityHeader()}).</li>
    -+    </ol>
    -+    <p>For example, the following code flattens some data into a byte stream and writes it into a
    -+single entity:</p>
    -+    <pre>
    -+// Create buffer stream and data output stream for our data
    -+ByteArrayOutputStream bufStream = new ByteArrayOutputStream();
    -+DataOutputStream outWriter = new DataOutputStream(bufStream);
    -+// Write structured data
    -+outWriter.writeUTF(mPlayerName);
    -+outWriter.writeInt(mPlayerScore);
    -+// Send the data to the Backup Manager via the BackupDataOutput
    -+byte[] buffer = bufStream.toByteArray();
    -+int len = buffer.length;
    -+data.writeEntityHeader(TOPSCORE_BACKUP_KEY, len);
    -+data.writeEntityData(buffer, len);
    -+</pre>
    -+    <p>Perform this for each piece of data that you want to back up. How you divide your data into
    -+entities is up to you (and you might use just one entity).</p>
    -+  </li>
    -+  <li>Whether or not you perform a backup (in step 2), write a representation of the current data to
    -+the {@code newState} {@link android.os.ParcelFileDescriptor}. The Backup Manager retains this object
    -+locally as a representation of the data that is currently backed up. It passes this back to you as
    -+{@code oldState} the next time it calls {@link
    -+android.app.backup.BackupAgent#onBackup(ParcelFileDescriptor,BackupDataOutput,ParcelFileDescriptor)
    -+onBackup()} so you can determine whether another backup is necessary (as handled in step 1). If you
    -+do not write the current data state to this file, then
    -+{@code oldState} will be empty during the next callback.
    -+    <p>The following example saves a representation of the current data into {@code newState} using
    -+the file's last-modified timestamp:</p>
    -+    <pre>
    -+FileOutputStream outstream = new FileOutputStream(newState.getFileDescriptor());
    -+DataOutputStream out = new DataOutputStream(outstream);
    -+
    -+long modified = mDataFile.lastModified();
    -+out.writeLong(modified);
    -+</pre>
    -+  </li>
    -+</ol>
    -+
    -+<p class="caution"><strong>Caution:</strong> If your application data is saved to a file, make sure
    -+that you use synchronized statements while accessing the file so that your backup agent does not
    -+read the file while an Activity in your application is also writing the file.</p>
    -+
    -+
    -+
    -+
    -+<h3 id="PerformingRestore">Performing restore</h3>
    -+
    -+<p>When it's time to restore your application data, the Backup Manager calls your backup
    -+agent's {@link android.app.backup.BackupAgent#onRestore(BackupDataInput,int,ParcelFileDescriptor)
    -+onRestore()} method. When it calls this method, the Backup Manager delivers your backup data so
    -+you can restore it onto the device.</p>
    -+
    -+<p>Only the Backup Manager can call {@link
    -+android.app.backup.BackupAgent#onRestore(BackupDataInput,int,ParcelFileDescriptor)
    -+onRestore()}, which happens automatically when the system installs your application and
    -+finds existing backup data. However, you can request a restore operation for
    -+your application by calling {@link
    -+android.app.backup.BackupManager#requestRestore(RestoreObserver) requestRestore()} (see <a
    -+href="#RequestingRestore">Requesting restore</a> for more information).</p>
    -+
    -+<p class="note"><strong>Note:</strong> While developing your application, you can also request a
    -+restore operation with the <a href="{@docRoot}tools/help/bmgr.html">{@code bmgr}
    -+tool</a>.</p>
    -+
    -+<p>When the Backup Manager calls your {@link
    -+android.app.backup.BackupAgent#onRestore(BackupDataInput,int,ParcelFileDescriptor)
    -+onRestore()} method, it passes three parameters:</p>
    -+
    -+<dl>
    -+  <dt>{@code data}</dt>
    -+    <dd>A {@link android.app.backup.BackupDataInput}, which allows you to read your backup
    -+data.</dd>
    -+  <dt>{@code appVersionCode}</dt>
    -+    <dd>An integer representing the value of your application's <a
    -+href="{@docRoot}guide/topics/manifest/manifest-element.html#vcode">{@code android:versionCode}</a>
    -+manifest attribute, as it was when this data was backed up. You can use this to cross-check the
    -+current application version and determine if the data format is compatible. For more
    -+information about using this to handle different versions of restore data, see the section
    -+below about <a href="#RestoreVersion">Checking the Restore Data Version</a>.</dd>
    -+  <dt>{@code newState}</dt>
    -+    <dd>An open, read/write {@link android.os.ParcelFileDescriptor} pointing to a file in which
    -+you must write the final backup state that was provided with {@code data}. This object is
    -+returned as {@code oldState} the next time {@link
    -+android.app.backup.BackupAgent#onBackup(ParcelFileDescriptor,BackupDataOutput,ParcelFileDescriptor)
    -+onBackup()} is called. Recall that you must also write the same {@code newState} object in the
    -+{@link
    -+android.app.backup.BackupAgent#onBackup(ParcelFileDescriptor,BackupDataOutput,ParcelFileDescriptor)
    -+onBackup()} callback&mdash;also doing it here ensures that the {@code oldState} object given to
    -+{@link
    -+android.app.backup.BackupAgent#onBackup(ParcelFileDescriptor,BackupDataOutput,ParcelFileDescriptor)
    -+onBackup()} is valid even the first time {@link
    -+android.app.backup.BackupAgent#onBackup(ParcelFileDescriptor,BackupDataOutput,ParcelFileDescriptor)
    -+onBackup()} is called after the device is restored.</dd>
    -+</dl>
    -+
    -+<p>In your implementation of {@link
    -+android.app.backup.BackupAgent#onRestore(BackupDataInput,int,ParcelFileDescriptor)
    -+onRestore()}, you should call {@link android.app.backup.BackupDataInput#readNextHeader()} on the
    -+{@code data} to iterate
    -+through all entities in the data set. For each entity found, do the following:</p>
    -+
    -+<ol>
    -+  <li>Get the entity key with {@link android.app.backup.BackupDataInput#getKey()}.</li>
    -+  <li>Compare the entity key to a list of known key values that you should have declared as static
    -+final strings inside your {@link android.app.backup.BackupAgent} class. When the key matches one of
    -+your known key strings, enter into a statement to extract the entity data and save it to the device:
    -+    <ol>
    -+      <li>Get the entity data size with {@link
    -+android.app.backup.BackupDataInput#getDataSize()} and create a byte array of that size.</li>
    -+      <li>Call {@link android.app.backup.BackupDataInput#readEntityData(byte[],int,int)
    -+readEntityData()} and pass it the byte array, which is where the data will go, and specify the
    -+start offset and the size to read.</li>
    -+      <li>Your byte array is now full and you can read the data and write it to the device
    -+however you like.</li>
    -+    </ol>
    -+  </li>
    -+  <li>After you read and write your data back to the device, write the state of your data to the
    -+{@code newState} parameter the same as you do during {@link
    -+android.app.backup.BackupAgent#onBackup(ParcelFileDescriptor,BackupDataOutput,ParcelFileDescriptor)
    -+onBackup()}.
    -+</ol>
    -+
    -+<p>For example, here's how you can restore the data backed up by the example in the previous
    -+section:</p>
    -+
    -+<pre>
    -+&#64;Override
    -+public void onRestore(BackupDataInput data, int appVersionCode,
    -+                      ParcelFileDescriptor newState) throws IOException {
    -+    // There should be only one entity, but the safest
    -+    // way to consume it is using a while loop
    -+    while (data.readNextHeader()) {
    -+        String key = data.getKey();
    -+        int dataSize = data.getDataSize();
    -+
    -+        // If the key is ours (for saving top score). Note this key was used when
    -+        // we wrote the backup entity header
    -+        if (TOPSCORE_BACKUP_KEY.equals(key)) {
    -+            // Create an input stream for the BackupDataInput
    -+            byte[] dataBuf = new byte[dataSize];
    -+            data.readEntityData(dataBuf, 0, dataSize);
    -+            ByteArrayInputStream baStream = new ByteArrayInputStream(dataBuf);
    -+            DataInputStream in = new DataInputStream(baStream);
    -+
    -+            // Read the player name and score from the backup data
    -+            mPlayerName = in.readUTF();
    -+            mPlayerScore = in.readInt();
    -+
    -+            // Record the score on the device (to a file or something)
    -+            recordScore(mPlayerName, mPlayerScore);
    -+        } else {
    -+            // We don't know this entity key. Skip it. (Shouldn't happen.)
    -+            data.skipEntityData();
    -+        }
    -+    }
    -+
    -+    // Finally, write to the state blob (newState) that describes the restored data
    -+    FileOutputStream outstream = new FileOutputStream(newState.getFileDescriptor());
    -+    DataOutputStream out = new DataOutputStream(outstream);
    -+    out.writeUTF(mPlayerName);
    -+    out.writeInt(mPlayerScore);
    -+}
    -+</pre>
    -+
    -+<p>In this example, the {@code appVersionCode} parameter passed to {@link
    -+android.app.backup.BackupAgent#onRestore onRestore()} is not used. However, you might want to use
    -+it if you've chosen to perform backup when the user's version of the application has actually moved
    -+backward (for example, the user went from version 1.5 of your app to 1.0). For more information, see
    -+the section about <a href="#RestoreVersion">Checking the Restore Data Version</a>.</p>
    -+
    -+<div class="special">
    -+<p>For an example implementation of {@link android.app.backup.BackupAgent}, see the <a
    -+href="{@docRoot}resources/samples/BackupRestore/src/com/example/android/backuprestore/ExampleAgent.html">{@code
    -+ExampleAgent}</a> class in the <a
    -+href="{@docRoot}resources/samples/BackupRestore/index.html">Backup and Restore</a> sample
    -+application.</p>
    -+</div>
    -+
    -+
    -+
    -+
    -+
    -+
    -+<h2 id="BackupAgentHelper">Extending BackupAgentHelper</h2>
    -+
    -+<p>You should build your backup agent using {@link android.app.backup.BackupAgentHelper} if you want
    -+to back up complete files (from either {@link android.content.SharedPreferences} or <a
    -+href="{@docRoot}guide/topics/data/data-storage.html#filesInternal">internal storage</a>).
    -+Building your backup agent with {@link android.app.backup.BackupAgentHelper} requires far less
    -+code than extending {@link android.app.backup.BackupAgent}, because you don't have to implement
    -+{@link
    -+android.app.backup.BackupAgent#onBackup(ParcelFileDescriptor,BackupDataOutput,ParcelFileDescriptor)
    -+onBackup()} and {@link
    -+android.app.backup.BackupAgent#onRestore(BackupDataInput,int,ParcelFileDescriptor)
    -+onRestore()}.</p>
    -+
    -+<p>Your implementation of {@link android.app.backup.BackupAgentHelper} must
    -+use one or more backup helpers. A backup helper is a specialized
    -+component that {@link android.app.backup.BackupAgentHelper} summons to perform backup and
    -+restore operations for a particular type of data. The Android framework currently provides two
    -+different helpers:</p>
    -+<ul>
    -+  <li>{@link android.app.backup.SharedPreferencesBackupHelper} to backup {@link
    -+android.content.SharedPreferences} files.</li>
    -+  <li>{@link android.app.backup.FileBackupHelper} to backup files from <a
    -+href="{@docRoot}guide/topics/data/data-storage.html#filesInternal">internal storage</a>.</li>
    -+</ul>
    -+
    -+<p>You can include multiple helpers in your {@link android.app.backup.BackupAgentHelper}, but only
    -+one helper is needed for each data type. That is, if you have multiple {@link
    -+android.content.SharedPreferences} files, then you need only one {@link
    -+android.app.backup.SharedPreferencesBackupHelper}.</p>
    -+
    -+<p>For each helper you want to add to your {@link android.app.backup.BackupAgentHelper}, you must do
    -+the following during your {@link android.app.backup.BackupAgent#onCreate()} method:</p>
    -+<ol>
    -+  <li>Instantiate in instance of the desired helper class. In the class constructor, you must
    -+specify the appropriate file(s) you want to backup.</li>
    -+  <li>Call {@link android.app.backup.BackupAgentHelper#addHelper(String,BackupHelper) addHelper()}
    -+to add the helper to your {@link android.app.backup.BackupAgentHelper}.</li>
    -+</ol>
    -+
    -+<p>The following sections describe how to create a backup agent using each of the available
    -+helpers.</p>
    -+
    -+
    -+
    -+<h3 id="SharedPreferences">Backing up SharedPreferences</h3>
    -+
    -+<p>When you instantiate a {@link android.app.backup.SharedPreferencesBackupHelper}, you must
    -+include the name of one or more {@link android.content.SharedPreferences} files.</p>
    -+
    -+<p>For example, to back up a {@link android.content.SharedPreferences} file named
    -+"user_preferences", a complete backup agent using {@link android.app.backup.BackupAgentHelper} looks
    -+like this:</p>
    -+
    -+<pre>
    -+public class MyPrefsBackupAgent extends BackupAgentHelper {
    -+    // The name of the SharedPreferences file
    -+    static final String PREFS = "user_preferences";
    -+
    -+    // A key to uniquely identify the set of backup data
    -+    static final String PREFS_BACKUP_KEY = "prefs";
    -+
    -+    // Allocate a helper and add it to the backup agent
    -+    &#64;Override
    -+    public void onCreate() {
    -+        SharedPreferencesBackupHelper helper =
    -+                new SharedPreferencesBackupHelper(this, PREFS);
    -+        addHelper(PREFS_BACKUP_KEY, helper);
    -+    }
    -+}
    -+</pre>
    -+
    -+<p>That's it! That's your entire backup agent. The {@link
    -+android.app.backup.SharedPreferencesBackupHelper} includes all the code
    -+needed to backup and restore a {@link android.content.SharedPreferences} file.</p>
    -+
    -+<p>When the Backup Manager calls {@link
    -+android.app.backup.BackupAgent#onBackup(ParcelFileDescriptor,BackupDataOutput,ParcelFileDescriptor)
    -+onBackup()} and {@link
    -+android.app.backup.BackupAgent#onRestore(BackupDataInput,int,ParcelFileDescriptor)
    -+onRestore()}, {@link android.app.backup.BackupAgentHelper} calls your backup helpers to perform
    -+backup and restore for your specified files.</p>
    -+
    -+<p class="note"><strong>Note:</strong> The methods of {@link android.content.SharedPreferences}
    -+are threadsafe, so
    -+you can safely read and write the shared preferences file from your backup agent and
    -+other activities.</p>
    -+
    -+
    -+
    -+<h3 id="Files">Backing up other files</h3>
    -+
    -+<p>When you instantiate a {@link android.app.backup.FileBackupHelper}, you must include the name of
    -+one or more files that are saved to your application's <a
    -+href="{@docRoot}guide/topics/data/data-storage.html#filesInternal">internal storage</a>
    -+(as specified by {@link android.content.ContextWrapper#getFilesDir()}, which is the same
    -+location where {@link android.content.Context#openFileOutput(String,int) openFileOutput()} writes
    -+files).</p>
    -+
    -+<p>For example, to backup two files named "scores" and "stats," a backup agent using {@link
    -+android.app.backup.BackupAgentHelper} looks like this:</p>
    -+
    -+<pre>
    -+public class MyFileBackupAgent extends BackupAgentHelper {
    -+    // The name of the file
    -+    static final String TOP_SCORES = "scores";
    -+    static final String PLAYER_STATS = "stats";
    -+
    -+    // A key to uniquely identify the set of backup data
    -+    static final String FILES_BACKUP_KEY = "myfiles";
    -+
    -+    // Allocate a helper and add it to the backup agent
    -+    &#64;Override
    -+    public void onCreate() {
    -+        FileBackupHelper helper = new FileBackupHelper(this,
    -+                TOP_SCORES, PLAYER_STATS);
    -+        addHelper(FILES_BACKUP_KEY, helper);
    -+    }
    -+}
    -+</pre>
    -+
    -+<p>The {@link android.app.backup.FileBackupHelper} includes all the code necessary to backup and
    -+restore files that are saved to your application's <a
    -+href="{@docRoot}guide/topics/data/data-storage.html#filesInternal">internal storage</a>..</p>
    -+
    -+<p>However, reading and writing to files on internal storage is <strong>not threadsafe</strong>. To
    -+ensure that your backup agent does not read or write your files at the same time as your activities,
    -+you must use synchronized statements each time you perform a read or write. For example,
    -+in any Activity where you read and write the file, you need an object to use as the intrinsic
    -+lock for the synchronized statements:</p>
    -+
    -+<pre>
    -+// Object for intrinsic lock
    -+static final Object sDataLock = new Object();
    -+</pre>
    -+
    -+<p>Then create a synchronized statement with this lock each time you read or write the files. For
    -+example, here's a synchronized statement for writing the latest score in a game to a file:</p>
    -+
    -+<pre>
    -+try {
    -+    synchronized (MyActivity.sDataLock) {
    -+        File dataFile = new File({@link android.content.Context#getFilesDir()}, TOP_SCORES);
    -+        RandomAccessFile raFile = new RandomAccessFile(dataFile, "rw");
    -+        raFile.writeInt(score);
    -+    }
    -+} catch (IOException e) {
    -+    Log.e(TAG, "Unable to write to file");
    -+}
    -+</pre>
    -+
    -+<p>You should synchronize your read statements with the same lock.</p>
    -+
    -+<p>Then, in your {@link android.app.backup.BackupAgentHelper}, you must override {@link
    -+android.app.backup.BackupAgent#onBackup(ParcelFileDescriptor,BackupDataOutput,ParcelFileDescriptor)
    -+onBackup()} and {@link
    -+android.app.backup.BackupAgent#onRestore(BackupDataInput,int,ParcelFileDescriptor)
    -+onRestore()} to synchronize the backup and restore operations with the same
    -+intrinsic lock. For example, the {@code MyFileBackupAgent} example from above needs the following
    -+methods:</p>
    -+
    -+<pre>
    -+&#64;Override
    -+public void onBackup(ParcelFileDescriptor oldState, BackupDataOutput data,
    -+          ParcelFileDescriptor newState) throws IOException {
    -+    // Hold the lock while the FileBackupHelper performs backup
    -+    synchronized (MyActivity.sDataLock) {
    -+        super.onBackup(oldState, data, newState);
    -+    }
    -+}
    -+
    -+&#64;Override
    -+public void onRestore(BackupDataInput data, int appVersionCode,
    -+        ParcelFileDescriptor newState) throws IOException {
    -+    // Hold the lock while the FileBackupHelper restores the file
    -+    synchronized (MyActivity.sDataLock) {
    -+        super.onRestore(data, appVersionCode, newState);
    -+    }
    -+}
    -+</pre>
    -+
    -+<p>That's it. All you need to do is add your {@link android.app.backup.FileBackupHelper} in the
    -+{@link android.app.backup.BackupAgent#onCreate()} method and override {@link
    -+android.app.backup.BackupAgent#onBackup(ParcelFileDescriptor,BackupDataOutput,ParcelFileDescriptor)
    -+onBackup()} and {@link
    -+android.app.backup.BackupAgent#onRestore(BackupDataInput,int,ParcelFileDescriptor)
    -+onRestore()} to synchronize read and write operations.</p>
    -+
    -+<div class="special">
    -+<p>For an example implementation of {@link
    -+android.app.backup.BackupAgentHelper} with {@link android.app.backup.FileBackupHelper}, see the
    -+{@code FileHelperExampleAgent} class in the <a
    -+href="{@docRoot}resources/samples/BackupRestore/index.html">Backup and Restore</a> sample
    -+application.</p>
    -+</div>
    -+
    -+
    -+
    -+
    -+
    -+
    -+<h2 id="RestoreVersion">Checking the restore data version</h2>
    -+
    -+<p>When the Backup Manager saves your data to cloud storage, it automatically includes the version
    -+of your application, as defined by your manifest file's <a
    -+href="{@docRoot}guide/topics/manifest/manifest-element.html#vcode">{@code android:versionCode}</a>
    -+attribute. Before the Backup Manager calls your backup agent to restore your data, it
    -+looks at the <a
    -+href="{@docRoot}guide/topics/manifest/manifest-element.html#vcode">{@code
    -+android:versionCode}</a> of the installed application and compares it to the value
    -+recorded in the restore data set. If the version recorded in the restore data set is
    -+<em>newer</em> than the application version on the device, then the user has downgraded their
    -+application. In this case, the Backup Manager will abort the restore operation for your application
    -+and not call your {@link
    -+android.app.backup.BackupAgent#onRestore(BackupDataInput,int,ParcelFileDescriptor) onRestore()}
    -+method, because the restore set is considered meaningless to an older version.</p>
    -+
    -+<p>You can override this behavior with the <a
    -+href="{@docRoot}guide/topics/manifest/application-element.html#restoreany">{@code
    -+android:restoreAnyVersion}</a> attribute. This attribute is either "{@code true}" or "{@code
    -+false}" to indicate whether you want to restore the application regardless of the restore set
    -+version. The default value is "{@code false}". If you define this to be "{@code true}" then the
    -+Backup Manager will ignore the <a
    -+href="{@docRoot}guide/topics/manifest/manifest-element.html#vcode">{@code android:versionCode}</a>
    -+and call your {@link
    -+android.app.backup.BackupAgent#onRestore(BackupDataInput,int,ParcelFileDescriptor) onRestore()}
    -+method in all cases. In doing so, you can manually check for the version difference in your {@link
    -+android.app.backup.BackupAgent#onRestore(BackupDataInput,int,ParcelFileDescriptor) onRestore()}
    -+method and take any steps necessary to make the data compatible if the versions conflict.</p>
    -+
    -+<p>To help you handle different versions during a restore operation, the {@link
    -+android.app.backup.BackupAgent#onRestore(BackupDataInput,int,ParcelFileDescriptor) onRestore()}
    -+method passes you the version code included with the restore data set as the {@code appVersionCode}
    -+parameter. You can then query the current application's version code with the {@link
    -+android.content.pm.PackageInfo#versionCode PackageInfo.versionCode} field. For example:</p>
    -+
    -+<pre>
    -+PackageInfo info;
    -+try {
    -+    String name = {@link android.content.ContextWrapper#getPackageName() getPackageName}();
    -+    info = {@link android.content.ContextWrapper#getPackageManager
    -+getPackageManager}().{@link android.content.pm.PackageManager#getPackageInfo(String,int)
    -+getPackageInfo}(name,0);
    -+} catch (NameNotFoundException nnfe) {
    -+    info = null;
    -+}
    -+
    -+int version;
    -+if (info != null) {
    -+    version = info.versionCode;
    -+}
    -+</pre>
    -+
    -+<p>Then simply compare the {@code version} acquired from {@link android.content.pm.PackageInfo}
    -+to the {@code appVersionCode} passed into {@link
    -+android.app.backup.BackupAgent#onRestore(BackupDataInput,int,ParcelFileDescriptor) onRestore()}.
    -+</p>
    -+
    -+<p class="caution"><strong>Caution:</strong> Be certain you understand the consequences of setting
    -+<a href="{@docRoot}guide/topics/manifest/application-element.html#restoreany">{@code
    -+android:restoreAnyVersion}</a> to "{@code true}" for your application. If each version of your
    -+application that supports backup does not properly account for variations in your data format during
    -+{@link
    -+android.app.backup.BackupAgent#onRestore(BackupDataInput,int,ParcelFileDescriptor) onRestore()},
    -+then the data on the device could be saved in a format incompatible with the version currently
    -+installed on the device.</p>
    -+
    -+
    -+
    -+<h2 id="RequestingBackup">Requesting backup</h2>
    -+
    -+<p>You can request a backup operation at any time by calling {@link
    -+android.app.backup.BackupManager#dataChanged()}. This method notifies the Backup Manager that you'd
    -+like to backup your data using your backup agent. The Backup Manager then calls your backup
    -+agent's {@link
    -+android.app.backup.BackupAgent#onBackup(ParcelFileDescriptor,BackupDataOutput,ParcelFileDescriptor)
    -+onBackup()} method at an opportune time in the future. Typically, you should
    -+request a backup each time your data changes (such as when the user changes an application
    -+preference that you'd like to back up). If you call {@link
    -+android.app.backup.BackupManager#dataChanged()} several times consecutively, before the Backup
    -+Manager requests a backup from your agent, your agent still receives just one call to {@link
    -+android.app.backup.BackupAgent#onBackup(ParcelFileDescriptor,BackupDataOutput,ParcelFileDescriptor)
    -+onBackup()}.</p>
    -+
    -+<p class="note"><strong>Note:</strong> While developing your application, you can request a
    -+backup and initiate an immediate backup operation with the <a
    -+href="{@docRoot}tools/help/bmgr.html">{@code bmgr}
    -+tool</a>.</p>
    -+
    -+
    -+<h2 id="RequestingRestore">Requesting restore</h2>
    -+
    -+<p>During the normal life of your application, you shouldn't need to request a restore operation.
    -+They system automatically checks for backup data and performs a restore when your application is
    -+installed. However, you can manually request a restore operation by calling {@link
    -+android.app.backup.BackupManager#requestRestore(RestoreObserver) requestRestore()}, if necessary. In
    -+which case, the Backup Manager calls your {@link
    -+android.app.backup.BackupAgent#onRestore(BackupDataInput,int,ParcelFileDescriptor) onRestore()}
    -+implementation, passing the data from the current set of backup data.</p>
    -+
    -+<p class="note"><strong>Note:</strong> While developing your application, you can request a
    -+restore operation with the <a href="{@docRoot}tools/help/bmgr.html">{@code bmgr}
    -+tool</a>.</p>
    -+
    -+
    -+<h2 id="Migrating">Migrating to Auto Backup</h2>
    -+<p>You can transition your app to full-data backups by setting <a href="{@docRoot}reference/android/R.attr.html#fullBackupOnly">android:fullBackupOnly</a> to <code>true</code> in the <code>&lt;application></code> element in the manifest file. When
    -+running on a device with Android 5.1 (API level 22) or lower, your app ignores
    -+this value in the manifest, and continues performing Key/Value Backups. When
    -+running on a device with Android 6.0 (API level 23) or higher, your app performs
    -+Auto Backup instead of Key/Value Backup.
    -\ No newline at end of file
    -diff --git a/docs/html/guide/topics/data/testingbackup.jd b/docs/html/guide/topics/data/testingbackup.jd
    -new file mode 100644
    -index 0000000..6ff5837
    ---- /dev/null
    -+++ b/docs/html/guide/topics/data/testingbackup.jd
    -@@ -0,0 +1,181 @@
    -+page.title=Testing Backup and Restore
    -+page.tags=backup, marshmallow, androidm
    -+page.keywords=backup, restore, testing
    -+
    -+@jd:body
    -+
    -+<div id="qv-wrapper">
    -+<div id="qv">
    -+  <h2>In this document</h2>
    -+  <ol>
    -+    <li><a href="#HowBackupWorks">How backup works</a></li>
    -+    <li><a href="#Prerequisites">Prerequisites</a></li>
    -+    <li><a href="#Preparing">Preparing your device or emulator</a></li>
    -+    <li><a href="#TestingBackup">Testing backup</a></li>
    -+    <li><a href="#TestingRestore">Testing restore</a></li>
    -+    <li><a href="#Troubleshooting">Troubleshooting</a></li>
    -+  </ol>
    -+
    -+</div>
    -+</div>
    -+
    -+<p>This page shows you how to manually trigger Auto Backup, Key/Value Backup, and restore operations to
    -+ensure your app saves and restores data properly.
    -+
    -+<h2 id="HowBackupWorkso">How backup works</h2>
    -+<p>The section describes various pieces in the Android backup framework and how they
    -+interact with apps that support Auto Backup and Key/Value Backup. During the app
    -+development phase, most of the inner working of the framework were abstracted away, so you didn't need to know this information. However, during the
    -+testing phase, an understanding of these concepts is important.
    -+
    -+<p>The following diagram illustrates how data flows during backup and restore:
    -+
    -+<img src="images/backup-framework.png" alt="backup-framework">
    -+
    -+<p>The <em>Backup Manager Service</em> is an Android system
    -+service which orchestrates and initiates backup and restore operations. The service
    -+is accessible through the {@link android.app.backup.BackupManager}
    -+API. During a backup operation, the service queries your app for backup data,
    -+then hands it to the <em>backup transport</em>, which then archives the data.
    -+During a restore operation, the backup manager service retrieves the backup data
    -+from the backup transport and restores the data to the device.
    -+
    -+<p><em>Backup Transports</em> are Android components that are responsible
    -+for storing and retrieving backups. An Android device can have zero or more
    -+backup transports, but only one of those transports can be marked active. The
    -+available backup transports may differ from device to device (due to
    -+customizations by device manufacturers and service providers), but most Google
    -+Play enabled devices ship with the following transports:
    -+</p><ul>
    -+<li><strong>Google GMS Transport</strong>(default) - the active backup
    -+transport on most devices, part of <a href="https://www.android.com/gms/">Google Mobile Services</a>. This documentation assumes that users are using the
    -+Google GMS transport. This transport stores Auto Backup data in a private folder in the
    -+user's Google Drive account. Key/Value Backup data is stored in the <a href="{@docRoot}google/backup/index.html">Android Backup Service</a>.
    -+<li><strong>Local Transport</strong> - stores backup data locally on the device.
    -+This transport is typically used for development/debugging purposes and is not
    -+useful in the real world.</li></ul>
    -+
    -+<p>If a device does not have any backup transports, then the data cannot be
    -+backed up. Your app is not adversely affected.
    -+
    -+<p class="caution"><strong>Caution:</strong> Because the backup transport
    -+can differ from device to device, Android cannot guarantee the security
    -+of your data while using backup. Be cautious about using backup to store
    -+sensitive data, such as usernames and passwords.
    -+
    -+<h2 id="Prerequisites">Prerequisites</h2>
    -+<p>You need to know a bit about the following tools:
    -+
    -+<ul>
    -+  <li><a href="{@docRoot}studio/command-line/adb.html">adb</a>
    -+- to run commands on the device or emulator
    -+  <li><a href="{@docRoot}studio/command-line/bmgr.html">bmgr</a> - to
    -+perform various backup and restore operations
    -+  <li><a href="{@docRoot}studio/command-line/logcat.html">logcat</a>
    -+- to see the output of backup and restore operations.</li></ul>
    -+
    -+<h2 id="Preparing">Preparing your device or
    -+emulator</h2>
    -+<p>Prepare your device or emulator for backup testing by working through the
    -+following checklist:
    -+<ul>
    -+  <li>For Auto Backup, check that you are using a device or emulator running
    -+Android 6.0 (API level 23) or higher.</li>
    -+  <li>For Key/Value Backup, check that you are using a device or emulator running
    -+Android 2.2 (API level 8) or higher.</li>
    -+  <li>Check that backup and restore is enabled on the device or emulator. There
    -+are two ways to check: <ul>
    -+    <li>On the device, go to <strong>Settings -> Backup &amp; Restore</strong>.
    -+    <li>From adb shell, run <code>bmgr enable</code></li></ul>
    -+    <p>On physical devices, backup and restore is typically enabled during the
    -+initial setup wizard. Emulators do not run the setup wizard, so don't forget to
    -+enable backup and specify a backup account in device settings.
    -+  <li>Make sure the GMS Backup Transport is available and active by running the
    -+command from adb shell:
    -+  <pre class="prettyprint">$ bmgr list transports</pre>
    -+  <p>Then, check the console for the following output:
    -+  <pre class="prettyprint">android/com.android.internal.backup.LocalTransport
    -+* com.google.android.gms/.backup.BackupTransportService</pre>
    -+  <p>Physical devices without Google Play and emulators without Google APIs
    -+might not include the GMS Backup Transport. This article assumes you are using
    -+the GMS Backup Transport. You can test backup and restore with other backup
    -+transports, but the procedure and output can differ.
    -+</ul>
    -+
    -+<h2 id="TestingBackup">Testing backup</h2>
    -+<p>To initiate a backup of your app, run the following command:
    -+
    -+<pre class="prettyprint">$ bmgr backupnow &lt;PACKAGE></pre>
    -+
    -+<p>The <code>backupnow</code> command runs either a Key/Value Backup or Auto Backup depending on
    -+the package's manifest declarations. Check logcat to see the output of the
    -+backup procedure. For example:
    -+
    -+<pre class="prettyprint">D/BackupManagerService: fullTransportBackup()
    -+I/GmsBackupTransport: Attempt to do full backup on &lt;PACKAGE>
    -+
    -+---- or ----
    -+
    -+V/BackupManagerService: Scheduling immediate backup pass
    -+D/PerformBackupTask: starting key/value Backup of BackupRequest{pkg=&lt;PACKAGE>}
    -+</pre>
    -+
    -+<p>If the <code>backupnow</code> command is not available on your device, you need to run one
    -+of the following commands:
    -+<ul>
    -+  <li>For Auto Backups, run: <code>bmgr fullbackup &lt;PACKAGE></code>
    -+  <li>For Key/Value Backups, schedule and run your backup with the following
    -+commands:
    -+  <pre class="prettyprint">$ bmgr backup &lt;PACKAGE>
    -+$ bmgr run</pre>
    -+  <p><code>bmgr backup</code> adds your app to the Backup Manager's queue. <code>bmgr run</code> initiates the
    -+backup operation, which forces the Backup Manager to perform all backup requests
    -+that are in its queue.
    -+  </li></ul>
    -+
    -+<h2 id="TestingRestore">Testing restore</h2>
    -+<p>To manually initiate a restore, run the following command:
    -+
    -+<pre class="prettyprint">$ bmgr restore &lt;PACKAGE></pre>
    -+
    -+<p>Warning: This action stops your app and wipes its data before performing the
    -+restore operation.
    -+
    -+<p>Then, check logcat to see the output of the restore procedure. For example:
    -+
    -+<pre class="prettyprint">V/BackupManagerService: beginRestoreSession: pkg=&lt;PACKAGE> transport=null
    -+V/RestoreSession: restorePackage pkg=&lt;PACKAGE> token=368abb4465c5c683
    -+...
    -+I/BackupManagerService: Restore complete.
    -+</pre>
    -+
    -+<p>You also can test automatic restore for your app by uninstalling and
    -+reinstalling your app either with <code>adb</code> or through the Google
    -+Play Store app.
    -+
    -+<h2 id="Troubleshooting">Troubleshooting</h2>
    -+<p><strong>Exceeded Quota</strong>
    -+
    -+<p>If you see the the following messages in logcat:
    -+
    -+<pre class="prettyprint">I/PFTBT: Transport rejected backup of &lt;PACKAGE>, skipping
    -+
    -+--- or ---
    -+
    -+I/PFTBT: Transport quota exceeded for package: &lt;PACKAGE>
    -+</pre>
    -+
    -+<p>Your app has exceeded the quota and has been banned from backing up
    -+data on this device. To lift the ban, either factory reset your device or change
    -+the backup account.
    -+
    -+<p><strong>Full Backup Not Possible</strong>
    -+
    -+<p>If you see the the following message in logcat:
    -+
    -+<pre class="prettyprint">I/BackupManagerService: Full backup not currently possible -- key/value backup not yet run?
    -+</pre>
    -+
    -+<p>The fullbackup operation failed because no Key/Value Backup operation has yet
    -+occurred on the device. Trigger a Key/Value Backup with the command <code>bmgr
    -+run </code>and then try again.
    -\ No newline at end of file
    -diff --git a/docs/html/guide/topics/graphics/2d-graphics.jd b/docs/html/guide/topics/graphics/2d-graphics.jd
    -index 9cae53c..d7dd038 100644
    ---- a/docs/html/guide/topics/graphics/2d-graphics.jd
    -+++ b/docs/html/guide/topics/graphics/2d-graphics.jd
    -@@ -21,6 +21,7 @@ parent.link=index.html
    -     </li>
    -     <li><a href="#shape-drawable">Shape Drawable</a></li>
    -     <li><a href="#nine-patch">Nine-patch</a></li>
    -+    <li><a href="#vector-drawable">Vector Drawables</a></li>
    -   </ol>
    - 
    -   <h2>See also</h2>
    -@@ -428,58 +429,66 @@ state
    -          of the object it's attached to.
    -          -->
    - 
    --         <h2 id="nine-patch">Nine-patch</h2>
    --
    --         <p>A {@link android.graphics.drawable.NinePatchDrawable} graphic is a stretchable bitmap
    --image,           which Android
    --           will automatically resize to accommodate the contents of the View in which you have
    --placed it as the           background.
    --           An example use of a NinePatch is the backgrounds used by standard Android buttons &mdash;
    --           buttons must stretch to accommodate strings of various lengths. A NinePatch drawable is a
    --standard           PNG
    --           image that includes an extra 1-pixel-wide border. It must be saved with the extension
    --           <code>.9.png</code>,
    --           and saved into the <code>res/drawable/</code> directory of your project.
    --         </p>
    --         <p>
    --           The border is used to define the stretchable and static areas of
    --           the image. You indicate a stretchable section by drawing one (or more) 1-pixel-wide
    --           black line(s) in the left and top part of the border (the other border pixels should
    --           be fully transparent or white). You can have as many stretchable sections as you want:
    --           their relative size stays the same, so the largest sections always remain the largest.
    --         </p>
    --         <p>
    --           You can also define an optional drawable section of the image (effectively,
    --           the padding lines) by drawing a line on the right and bottom lines.
    --           If a View object sets the NinePatch as its background and then specifies the
    --           View's text, it will stretch itself so that all the text fits inside only
    --           the area designated by the right and bottom lines (if included). If the
    --           padding lines are not included, Android uses the left and top lines to
    --           define this drawable area.
    --         </p>
    --         <p>To clarify the difference between the different lines, the left and top lines define
    --           which pixels of the image are allowed to be replicated in order to stretch the image.
    --           The bottom and right lines define the relative area within the image that the contents
    --           of the View are allowed to lie within.</p>
    --         <p>
    --           Here is a sample NinePatch file used to define a button:
    --         </p>
    --         <img src="{@docRoot}images/ninepatch_raw.png" alt="" />
    --
    --         <p>This NinePatch defines one stretchable area with the left and top lines
    --           and the drawable area with the bottom and right lines. In the top image, the dotted grey
    --           lines identify the regions of the image that will be replicated in order to stretch the
    --image. The           pink
    --           rectangle in the bottom image identifies the region in which the contents of the View are
    --allowed.
    --           If the contents don't fit in this region, then the image will be stretched so that they
    --do.
    -+<h2 id="nine-patch">Nine-patch</h2>
    -+
    -+<p>
    -+  A {@link android.graphics.drawable.NinePatchDrawable} graphic is a
    -+  stretchable bitmap image, which Android will automatically resize to
    -+  accommodate the contents of the View in which you have placed it as the
    -+  background. An example use of a NinePatch is the backgrounds used by
    -+  standard Android buttons — buttons must stretch to accommodate strings of
    -+  various lengths. A NinePatch drawable is a standard PNG image that includes
    -+  an extra 1-pixel-wide border. It must be saved with the extension
    -+  <code>.9.png</code>, and saved into the <code>res/drawable/</code> directory
    -+  of your project.
    - </p>
    - 
    --<p>The <a href="{@docRoot}tools/help/draw9patch.html">Draw 9-patch</a> tool offers
    --   an extremely handy way to create your NinePatch images, using a WYSIWYG graphics editor. It
    --even raises warnings if the region you've defined for the stretchable area is at risk of
    --producing drawing artifacts as a result of the pixel replication.
    -+<p>
    -+  The border is used to define the stretchable and static areas of the image.
    -+  You indicate a stretchable section by drawing one (or more) 1-pixel-wide
    -+  black line(s) in the left and top part of the border (the other border
    -+  pixels should be fully transparent or white). You can have as many
    -+  stretchable sections as you want: their relative size stays the same, so the
    -+  largest sections always remain the largest.
    -+</p>
    -+
    -+<p>
    -+  You can also define an optional drawable section of the image (effectively,
    -+  the padding lines) by drawing a line on the right and bottom lines. If a
    -+  View object sets the NinePatch as its background and then specifies the
    -+  View's text, it will stretch itself so that all the text fits inside only
    -+  the area designated by the right and bottom lines (if included). If the
    -+  padding lines are not included, Android uses the left and top lines to
    -+  define this drawable area.
    -+</p>
    -+
    -+<p>
    -+  To clarify the difference between the different lines, the left and top
    -+  lines define which pixels of the image are allowed to be replicated in order
    -+  to stretch the image. The bottom and right lines define the relative area
    -+  within the image that the contents of the View are allowed to lie within.
    -+</p>
    -+
    -+<p>
    -+  Here is a sample NinePatch file used to define a button:
    -+</p>
    -+<img src="{@docRoot}images/ninepatch_raw.png" alt="">
    -+<p>
    -+  This NinePatch defines one stretchable area with the left and top lines and
    -+  the drawable area with the bottom and right lines. In the top image, the
    -+  dotted grey lines identify the regions of the image that will be replicated
    -+  in order to stretch the image. The pink rectangle in the bottom image
    -+  identifies the region in which the contents of the View are allowed. If the
    -+  contents don't fit in this region, then the image will be stretched so that
    -+  they do.
    -+</p>
    -+
    -+<p>
    -+  The <a href="{@docRoot}tools/help/draw9patch.html">Draw 9-patch</a> tool
    -+  offers an extremely handy way to create your NinePatch images, using a
    -+  WYSIWYG graphics editor. It even raises warnings if the region you've
    -+  defined for the stretchable area is at risk of producing drawing artifacts
    -+  as a result of the pixel replication.
    - </p>
    - 
    - <h3>Example XML</h3>
    -@@ -516,3 +525,265 @@ stretches to accommodate it.
    - </p>
    - 
    - <img src="{@docRoot}images/ninepatch_examples.png" alt=""/>
    -+
    -+<h2 id="vector-drawable">
    -+  Vector Drawables
    -+</h2>
    -+
    -+<p>
    -+  A {@link android.graphics.drawable.VectorDrawable} graphic replaces multiple
    -+  PNG assets with a single vector graphic. The vector graphic is defined in an
    -+  XML file as a set of points, lines, and curves along with its associated
    -+  color information.
    -+</p>
    -+
    -+<p>
    -+  The major advantage of using a vector graphic is image scalability. Using
    -+  vector graphics resizes the same file for different screen densities without
    -+  loss of image quality. This results in smaller APK files and less developer
    -+  maintenance. You can also use vector images for animation by using multiple
    -+  XML files instead of multiple images for each display resolution.
    -+</p>
    -+
    -+<p>
    -+  Let's go through an example to understand the benefits. An image of size 100
    -+  x 100 dp may render good quality on a smaller display resolution. On larger
    -+  devices, the app might want to use a 400 x 400 dp version of the image.
    -+  Normally, developers create multiple versions of an asset to cater to
    -+  different screen densities. This approach consumes more development efforts,
    -+  and results in a larger APK, which takes more space on the device.
    -+</p>
    -+
    -+<p>
    -+  As of Android 5.0 (API level 21), there are two classes that support vector
    -+  graphics as a drawable resource: {@link
    -+  android.graphics.drawable.VectorDrawable} and {@link
    -+  android.graphics.drawable.AnimatedVectorDrawable}. For more information
    -+  about using the VectorDrawable and the AnimatedVectorDrawable classes, read
    -+  the <a href="#vector-drawable-class">About VectorDrawable class</a> and
    -+  <a href="#animated-vector-drawable-class">About AnimatedVectorDrawable
    -+  class</a> sections.
    -+</p>
    -+
    -+<h3 id="vector-drawable-class">About VectorDrawable class</h3>
    -+<p>
    -+  {@link android.graphics.drawable.VectorDrawable} defines a static drawable
    -+  object. Similar to the SVG format, each vector graphic is defined as a tree
    -+  hierachy, which is made up of <code>path</code> and <code>group</code> objects.
    -+  Each <code>path</code> contains the geometry of the object's outline and
    -+  <code>group</code> contains details for transformation. All paths are drawn
    -+  in the same order as they appear in the XML file.
    -+</p>
    -+
    -+<img src="{@docRoot}images/guide/topics/graphics/vectorpath.png" alt=""/>
    -+<p class="img-caption">
    -+  <strong>Figure 1.</strong> Sample hierarchy of a vector drawable asset
    -+</p>
    -+
    -+
    -+<p>
    -+  The <a href="{@docRoot}studio/write/vector-asset-studio.html">Vector Asset
    -+  Studio</a> tool offers a simple way to add a vector graphic to the project
    -+  as an XML file.
    -+</p>
    -+
    -+<h4>
    -+  Example XML
    -+</h4>
    -+
    -+<p>
    -+  Here is a sample <code>VectorDrawable</code> XML file that renders an image
    -+  of a battery in the charging mode.
    -+</p>
    -+
    -+<pre>
    -+&lt;!-- res/drawable/battery_charging.xml --&gt;
    -+&lt;vector xmlns:android="http://schemas.android.com/apk/res/android"
    -+    &lt;!-- intrinsic size of the drawable --&gt;
    -+    android:height="24dp"
    -+    android:width="24dp"
    -+    &lt;!-- size of the virtual canvas --&gt;
    -+    android:viewportWidth="24.0"
    -+    android:viewportHeight="24.0"&gt;
    -+   &lt;group
    -+         android:name="rotationGroup"
    -+         android:pivotX="10.0"
    -+         android:pivotY="10.0"
    -+         android:rotation="15.0" &gt;
    -+      &lt;path
    -+        android:name="vect"
    -+        android:fillColor="#FF000000"
    -+        android:pathData="M15.67,4H14V2h-4v2H8.33C7.6,4 7,4.6 7,5.33V9h4.93L13,7v2h4V5.33C17,4.6 16.4,4 15.67,4z"
    -+        android:fillAlpha=".3"/&gt;
    -+      &lt;path
    -+        android:name="draw"
    -+        android:fillColor="#FF000000"
    -+        android:pathData="M13,12.5h2L11,20v-5.5H9L11.93,9H7v11.67C7,21.4 7.6,22 8.33,22h7.33c0.74,0 1.34,-0.6 1.34,-1.33V9h-4v3.5z"/&gt;
    -+   &lt;/group&gt;
    -+&lt;/vector&gt;
    -+</pre>
    -+
    -+<p>This XML renders the following image:
    -+</p>
    -+
    -+<img src=
    -+"{@docRoot}images/guide/topics/graphics/ic_battery_charging_80_black_24dp.png"
    -+alt=""/>
    -+
    -+<h3 id="animated-vector-drawable-class">
    -+  About AnimatedVectorDrawable class
    -+</h3>
    -+
    -+<p>
    -+  {@link android.graphics.drawable.AnimatedVectorDrawable
    -+  AnimatedVectorDrawable} adds animation to the properties of a vector
    -+  graphic. You can define an animated vector graphic as three separate
    -+  resource files or as a single XML file defining the entire drawable. Let's
    -+  look at both the approaches for better understanding: <a href=
    -+  "#multiple-files">Multiple XML files</a> and <a href="#single-file">Single
    -+  XML file</a>.
    -+</p>
    -+
    -+<h4 id="multiple-files">
    -+  Multiple XML files
    -+</h4>
    -+<p>
    -+  By using this approach, you can define three separate XML files:
    -+
    -+<ul>
    -+  <li>A {@link android.graphics.drawable.VectorDrawable} XML file.
    -+  </li>
    -+
    -+  <li>
    -+  An {@link android.graphics.drawable.AnimatedVectorDrawable} XML file that
    -+defines the target {@link android.graphics.drawable.VectorDrawable}, the
    -+target paths and groups to animate, the properties, and the animations defined
    -+as {@link android.animation.ObjectAnimator ObjectAnimator} objects or {@link
    -+android.animation.AnimatorSet AnimatorSet} objects.
    -+  </li>
    -+
    -+  <li>An animator XML file.
    -+  </li>
    -+</ul>
    -+</p>
    -+
    -+<h5>
    -+  Example of multiple XML files
    -+</h5>
    -+<p>
    -+  The following XML files demonstrate the animation of a vector graphic.
    -+
    -+<ul>
    -+  <li>VectorDrawable's XML file: <code>vd.xml</code>
    -+  </li>
    -+
    -+  <li style="list-style: none; display: inline">
    -+<pre>
    -+&lt;vector xmlns:android="http://schemas.android.com/apk/res/android"
    -+   android:height="64dp"
    -+   android:width="64dp"
    -+   android:viewportHeight="600"
    -+   android:viewportWidth="600" &gt;
    -+   &lt;group
    -+      android:name="rotationGroup"
    -+      android:pivotX="300.0"
    -+      android:pivotY="300.0"
    -+      android:rotation="45.0" &gt;
    -+      &lt;path
    -+         android:name="vectorPath"
    -+         android:fillColor="#000000"
    -+         android:pathData="M300,70 l 0,-70 70,70 0,0 -70,70z" /&gt;
    -+   &lt;/group&gt;
    -+&lt;/vector&gt;
    -+</pre>
    -+  </li>
    -+
    -+  <li>AnimatedVectorDrawable's XML file: <code>avd.xml</code>
    -+  </li>
    -+
    -+  <li style="list-style: none; display: inline">
    -+<pre>
    -+&lt;animated-vector xmlns:android="http://schemas.android.com/apk/res/android"
    -+   android:drawable="@drawable/vd" &gt;
    -+     &lt;target
    -+         android:name="rotationGroup"
    -+         android:animation="@anim/rotation" /&gt;
    -+     &lt;target
    -+         android:name="vectorPath"
    -+         android:animation="@anim/path_morph" /&gt;
    -+&lt;/animated-vector&gt;
    -+</pre>
    -+  </li>
    -+
    -+  <li>Animator XML files that are used in the AnimatedVectorDrawable's XML
    -+  file: <code>rotation.xml</code> and <code>path_morph.xml</code>
    -+  </li>
    -+
    -+  <li style="list-style: none; display: inline">
    -+<pre>
    -+&lt;objectAnimator
    -+   android:duration="6000"
    -+   android:propertyName="rotation"
    -+   android:valueFrom="0"
    -+   android:valueTo="360" /&gt;
    -+</pre>
    -+
    -+<pre>
    -+&lt;set xmlns:android="http://schemas.android.com/apk/res/android"&gt;
    -+   &lt;objectAnimator
    -+      android:duration="3000"
    -+      android:propertyName="pathData"
    -+      android:valueFrom="M300,70 l 0,-70 70,70 0,0   -70,70z"
    -+      android:valueTo="M300,70 l 0,-70 70,0  0,140 -70,0 z"
    -+      android:valueType="pathType"/&gt;
    -+&lt;/set&gt;
    -+</pre>
    -+  </li>
    -+</ul>
    -+</p>
    -+<h4 id="single-file">
    -+  Single XML file
    -+</h4>
    -+
    -+<p>
    -+  By using this approach, you can merge the related XML files into a single
    -+  XML file through the XML Bundle Format. At the time of building the app, the
    -+  <code>aapt</code> tag creates separate resources and references them in the
    -+  animated vector. This approach requires Build Tools 24 or higher, and the
    -+  output is backward compatible.
    -+</p>
    -+
    -+<h5>
    -+  Example of a single XML file
    -+</h5>
    -+<pre>
    -+&lt;animated-vector
    -+    xmlns:android="http://schemas.android.com/apk/res/android"
    -+    xmlns:aapt="http://schemas.android.com/aapt"&gt;
    -+    &lt;aapt:attr name="android:drawable"&gt;
    -+        &lt;vector
    -+            android:width="24dp"
    -+            android:height="24dp"
    -+            android:viewportWidth="24"
    -+            android:viewportHeight="24"&gt;
    -+            &lt;path
    -+                android:name="root"
    -+                android:strokeWidth="2"
    -+                android:strokeLineCap="square"
    -+                android:strokeColor="?android:colorControlNormal"
    -+                android:pathData="M4.8,13.4 L9,17.6 M10.4,16.2 L19.6,7" /&gt;
    -+        &lt;/vector&gt;
    -+    &lt;/aapt:attr&gt;
    -+    &lt;target android:name="root"&gt;
    -+        &lt;aapt:attr name="android:animation"&gt;
    -+            &lt;objectAnimator
    -+                android:propertyName="pathData"
    -+                android:valueFrom="M4.8,13.4 L9,17.6 M10.4,16.2 L19.6,7"
    -+                android:valueTo="M6.4,6.4 L17.6,17.6 M6.4,17.6 L17.6,6.4"
    -+                android:duration="300"
    -+                android:interpolator="@android:interpolator/fast_out_slow_in"
    -+                android:valueType="pathType" /&gt;
    -+        &lt;/aapt:attr&gt;
    -+    &lt;/target&gt;
    -+&lt;/animated-vector&gt;
    -+</pre>
    -\ No newline at end of file
    -diff --git a/docs/html/guide/topics/location/strategies.jd b/docs/html/guide/topics/location/strategies.jd
    -index 2dfed2c..548ed9c 100755
    ---- a/docs/html/guide/topics/location/strategies.jd
    -+++ b/docs/html/guide/topics/location/strategies.jd
    -@@ -133,36 +133,69 @@ notifications and the third is the minimum change in distance between notificati
    - both to zero requests location notifications as frequently as possible. The last parameter is your
    - {@link android.location.LocationListener}, which receives callbacks for location updates.</p>
    - 
    --<p>To request location updates from the GPS provider,
    --substitute <code>GPS_PROVIDER</code> for <code>NETWORK_PROVIDER</code>. You can also request
    --location updates from both the GPS and the Network Location Provider by calling {@link
    --android.location.LocationManager#requestLocationUpdates requestLocationUpdates()} twice&mdash;once
    --for <code>NETWORK_PROVIDER</code> and once for <code>GPS_PROVIDER</code>.</p>
    -+<p>To request location updates from the GPS provider, use {@link
    -+android.location.LocationManager#GPS_PROVIDER} instead of {@link
    -+android.location.LocationManager#NETWORK_PROVIDER}. You can also request
    -+location updates from both the GPS and the Network Location Provider by calling
    -+{@link android.location.LocationManager#requestLocationUpdates
    -+requestLocationUpdates()} twice&mdash;once for {@link
    -+android.location.LocationManager#NETWORK_PROVIDER} and once for {@link
    -+android.location.LocationManager#GPS_PROVIDER}.</p>
    - 
    - 
    - <h3 id="Permission">Requesting User Permissions</h3>
    - 
    --<p>In order to receive location updates from <code>NETWORK_PROVIDER</code> or
    --<code>GPS_PROVIDER</code>, you must request user permission by declaring either the {@code
    --ACCESS_COARSE_LOCATION} or {@code ACCESS_FINE_LOCATION} permission, respectively, in your Android
    --manifest file. For example:</p>
    -+<p>
    -+  In order to receive location updates from {@link
    -+  android.location.LocationManager#NETWORK_PROVIDER} or {@link
    -+  android.location.LocationManager#GPS_PROVIDER}, you must request the user's
    -+  permission by declaring either the {@code ACCESS_COARSE_LOCATION} or {@code
    -+  ACCESS_FINE_LOCATION} permission, respectively, in your Android manifest file.
    -+  Without these permissions, your application will fail at runtime when
    -+  requesting location updates.
    -+</p>
    -+
    -+<p>
    -+  If you are using both {@link
    -+  android.location.LocationManager#NETWORK_PROVIDER} and {@link
    -+  android.location.LocationManager#GPS_PROVIDER}, then you need to request only
    -+  the {@code ACCESS_FINE_LOCATION} permission, because it includes permission
    -+  for both providers. Permission for {@code ACCESS_COARSE_LOCATION} allows
    -+  access only to {@link android.location.LocationManager#NETWORK_PROVIDER}.
    -+</p>
    -+
    -+<p id="location-feature-caution" class="caution">
    -+  <strong>Caution:</strong> If your app targets Android 5.0 (API level 21) or
    -+  higher, you <em>must</em> declare that your app uses the
    -+  <code>android.hardware.location.network</code> or
    -+  <code>android.hardware.location.gps</code> hardware feature in the manifest
    -+  file, depending on whether your app receives location updates from {@link
    -+  android.location.LocationManager#NETWORK_PROVIDER} or from {@link
    -+  android.location.LocationManager#GPS_PROVIDER}. If your app receives location
    -+  information from either of these location provider sources, you need to
    -+  declare that the app uses these hardware features in your app manifest.
    -+  On devices running verions prior to Android 5.0 (API 21), requesting the
    -+  {@code ACCESS_FINE_LOCATION} or {@code ACCESS_COARSE_LOCATION} permission
    -+  includes an implied request for location hardware features. However,
    -+  requesting those permissions <em>does not</em> automatically request location
    -+  hardware features on Android 5.0 (API level 21) and higher.
    -+</p>
    - 
    -+<p>
    -+   The following code sample demonstrates how to declare the permission and
    -+   hardware feature in the manifest file of an app that reads data from the
    -+   device's GPS:
    -+</p>
    - <pre>
    - &lt;manifest ... &gt;
    -     &lt;uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" /&gt;
    -     ...
    -+    &lt;!-- Needed only if your app targets Android 5.0 (API level 21) or higher. --&gt;
    -+    &lt;uses-feature android:name="android.hardware.location.gps" /&gt;
    -+    ...
    - &lt;/manifest&gt;
    - </pre>
    - 
    --<p>Without these permissions, your application will fail at runtime when requesting
    --location updates.</p>
    --
    --<p class="note"><strong>Note:</strong> If you are using both <code>NETWORK_PROVIDER</code> and
    --<code>GPS_PROVIDER</code>, then you need to request only the {@code ACCESS_FINE_LOCATION}
    --permission, because it includes permission for both providers. (Permission for {@code
    --ACCESS_COARSE_LOCATION} includes permission only for <code>NETWORK_PROVIDER</code>.)</p>
    --
    --
    - <h2 id="BestPerformance">Defining a Model for the Best Performance</h2>
    - 
    -   <p>Location-based applications are now commonplace, but due to the less than optimal
    -@@ -404,9 +437,10 @@ don't have a device, you can still test your location-based features by mocking
    - the Android emulator. There are three different ways to send your application mock location
    - data: using Android Studio, DDMS, or the "geo" command in the emulator console.</p>
    - 
    --<p class="note"><strong>Note:</strong> Providing mock location data is injected as GPS location
    --data, so you must request location updates from <code>GPS_PROVIDER</code> in order for mock location
    --data to work.</p>
    -+<p class="note"><strong>Note:</strong> Providing mock location data is injected
    -+as GPS location data, so you must request location updates from {@link
    -+android.location.LocationManager#GPS_PROVIDER} in order for mock location data
    -+to work.</p>
    - 
    - <h3 id="MockAVD">Using Android Studio</h3>
    - 
    -diff --git a/docs/html/guide/topics/manifest/meta-data-element.jd b/docs/html/guide/topics/manifest/meta-data-element.jd
    -index 945b116..2d1bdfe 100644
    ---- a/docs/html/guide/topics/manifest/meta-data-element.jd
    -+++ b/docs/html/guide/topics/manifest/meta-data-element.jd
    -@@ -60,7 +60,7 @@ Java-style naming convention &mdash; for example,
    - <dt><a name="rsrc"></a>{@code android:resource}</dt>
    - <dd>A reference to a resource.  The ID of the resource is the value assigned
    - to the item.  The ID can be retrieved from the meta-data Bundle by the
    --{@link android.os.BaseBundle#getInt Bundle.getInt()} method.</dd>
    -+{@link android.os.Bundle#getInt Bundle.getInt()} method.</dd>
    - 
    - <dt><a name="val"></a>{@code android:value}</dt>
    - <dd>The value assigned to the item.  The data types that can be assigned as values and the Bundle methods that  components use to retrieve those values are listed in the following table:
    -@@ -72,17 +72,17 @@ to the item.  The ID can be retrieved from the meta-data Bundle by the
    - </tr><tr>
    -   <td>String value, using double backslashes ({@code \\}) to escape characters
    -       &mdash; such as "{@code \\n}" and "{@code \\uxxxxx}" for a Unicode character.</td>
    --  <td>{@link android.os.BaseBundle#getString(String) getString()}</td>
    -+  <td>{@link android.os.Bundle#getString(String) getString()}</td>
    - </tr><tr>
    -   <td>Integer value, such as "{@code 100}"</td>
    --  <td>{@link android.os.BaseBundle#getInt(String) getInt()}</td>
    -+  <td>{@link android.os.Bundle#getInt(String) getInt()}</td>
    - </tr><tr>
    -   <td>Boolean value, either "{@code true}" or "{@code false}"</td>
    --  <td>{@link android.os.BaseBundle#getBoolean(String) getBoolean()}</td>
    -+  <td>{@link android.os.Bundle#getBoolean(String) getBoolean()}</td>
    - </tr><tr>
    -   <td>Color value, in the form "{@code #rgb}", "{@code #argb}",
    -       "{@code #rrggbb}", or "{@code #aarrggbb}"</td>
    --  <td>{@link android.os.BaseBundle#getInt(String) getInt()}</td>
    -+  <td>{@link android.os.Bundle#getInt(String) getInt()}</td>
    - </tr><tr>
    -   <td>Float value, such as "{@code 1.23}"</td>
    -   <td>{@link android.os.Bundle#getFloat(String) getFloat()}</td>
    -diff --git a/docs/html/guide/topics/manifest/provider-element.jd b/docs/html/guide/topics/manifest/provider-element.jd
    -index 1947849..0e729c3 100644
    ---- a/docs/html/guide/topics/manifest/provider-element.jd
    -+++ b/docs/html/guide/topics/manifest/provider-element.jd
    -@@ -215,17 +215,15 @@ it can also be set as a raw string.
    - </p></dd>
    - 
    - <dt><a name="multi"></a>{@code android:multiprocess}</dt>
    --<dd>Whether or not an instance of the content provider can be created in
    --every client process &mdash; "{@code true}" if instances can run in multiple
    --processes, and "{@code false}" if not.  The default value is "{@code false}".
    --
    --<p>
    --Normally, a content provider is instantiated in the process of the
    --application that defined it.  However, if this flag is set to "{@code true}",
    --the system can create an instance in every process where there's a client
    --that wants to interact with it, thus avoiding the overhead of interprocess
    --communication.
    --</p></dd>
    -+<dd>If the app runs in multiple processes, this attribute determines whether
    -+multiple instances of the content provder are created. If <code>true</code>,
    -+each of the app's processes has its own content provider object. If
    -+<code>false</code>, the app's processes share only one content provider object.
    -+The default value is <code>false</code>.
    -+
    -+<p>Setting this flag to <code>true</code> may improve performance by reducing
    -+the overhead of interprocess communication, but it also increases the memory
    -+footprint of each process.</p></dd>
    - 
    - <dt><a name="nm"></a>{@code android:name}</dt>
    - <dd>The name of the class that implements the content provider, a subclass of
    -diff --git a/docs/html/guide/topics/manifest/receiver-element.jd b/docs/html/guide/topics/manifest/receiver-element.jd
    -index 800ee8a..c866047 100644
    ---- a/docs/html/guide/topics/manifest/receiver-element.jd
    -+++ b/docs/html/guide/topics/manifest/receiver-element.jd
    -@@ -33,8 +33,18 @@ There are two ways to make a broadcast receiver known to the system:  One is
    - declare it in the manifest file with this element.  The other is to create
    - the receiver dynamically in code and register it with the <code>{@link
    - android.content.Context#registerReceiver Context.registerReceiver()}</code>
    --method.  See the {@link android.content.BroadcastReceiver} class description
    --for more on dynamically created receivers.
    -+method. For more information about how to dynamically create receivers, see the
    -+{@link android.content.BroadcastReceiver} class description.
    -+</p>
    -+
    -+<p class="warning">
    -+    <strong>Warning:</strong> Limit how many broadcast
    -+    receivers you set in your app. Having too many broadcast receivers can
    -+    affect your app's performance and the battery life of users' devices.
    -+    For more information about APIs you can use instead of the
    -+    {@link android.content.BroadcastReceiver} class for scheduling background
    -+    work, see
    -+    <a href="/topic/performance/background-optimization.html">Background Optimizations</a>.
    - </p></dd>
    - 
    - <dt>attributes:</dt>
    -diff --git a/docs/html/guide/topics/manifest/uses-feature-element.jd b/docs/html/guide/topics/manifest/uses-feature-element.jd
    -index 9b32244..843fe1c 100755
    ---- a/docs/html/guide/topics/manifest/uses-feature-element.jd
    -+++ b/docs/html/guide/topics/manifest/uses-feature-element.jd
    -@@ -512,10 +512,11 @@ You can find your unsigned <code>.apk</code> in the
    - 
    - <li>Next, locate the <code>aapt</code> tool, if it is not already in your PATH.
    - If you are using SDK Tools r8 or higher, you can find <code>aapt</code> in the
    --<code>&lt;<em>SDK</em>&gt;/platform-tools/</code> directory.
    -+<code>&lt;<em>SDK</em>&gt;/build-tools/&lt;<em>tools version number</em>&gt;</code>
    -+directory.
    - <p class="note"><strong>Note:</strong> You must use the version of
    --<code>aapt</code> that is provided for the latest Platform-Tools component available. If
    --you do not have the latest Platform-Tools component, download it using the <a
    -+<code>aapt</code> that is provided for the latest Build-Tools component available. If
    -+you do not have the latest Build-Tools component, download it using the <a
    - href="{@docRoot}studio/intro/update.html">Android SDK Manager</a>.
    - </p></li>
    - <li>Run <code>aapt</code> using this syntax: </li>
    -@@ -1666,6 +1667,15 @@ densities: '160'
    - 
    - <pre>&lt;uses-feature android:name="android.hardware.camera" android:required="false" /&gt;</pre>
    - 
    -+<p class="caution">
    -+  <strong>Caution:</strong> If your app targets Android 5.0 (API level 21) or
    -+  higher and uses the <code>ACCESS_COARSE_LOCATION</code> or
    -+  <code>ACCESS_FINE_LOCATION</code> permission in order to receive location
    -+  updates from the network or a GPS, respectively, you must also explicitly
    -+  declare that your app uses the <code>android.hardware.location.network</code>
    -+  or <code>android.hardware.location.gps</code> hardware features.
    -+</p>
    -+
    - <p class="table-caption" id="permissions-features">
    -   <strong>Table 2. </strong>Device permissions that imply device hardware use.
    - </p>
    -@@ -1717,14 +1727,29 @@ densities: '160'
    - </tr>
    - <tr>
    -   <td><code>ACCESS_COARSE_LOCATION</code></td>
    --  <td><code>android.hardware.location.network</code> <em>and</em>
    --<br><code>android.hardware.location</code></td>
    -+  <td>
    -+    <p>
    -+      <code>android.hardware.location</code>
    -+    </p>
    -+    <p>
    -+      <code>android.hardware.location.network</code>
    -+      (Only when target API level is 20 or lower.)
    -+    </p>
    -+  </td>
    - <!--  <td></td> -->
    - </tr>
    - <tr>
    -   <td><code>ACCESS_FINE_LOCATION</code></td>
    --  <td><code>android.hardware.location.gps</code> <em>and</em>
    --<br><code>android.hardware.location</code></td>
    -+  <td>
    -+    <p>
    -+      <code>android.hardware.location</code>
    -+    </p>
    -+    <p>
    -+      <code>android.hardware.location.gps</code>
    -+      (Only when target API level is 20 or lower.)
    -+    </p>
    -+  </td>
    -+
    - <!--  <td></td> -->
    - </tr>
    - 
    -diff --git a/docs/html/guide/topics/media/camera.jd b/docs/html/guide/topics/media/camera.jd
    -index 4995a13..383b6c1 100644
    ---- a/docs/html/guide/topics/media/camera.jd
    -+++ b/docs/html/guide/topics/media/camera.jd
    -@@ -154,10 +154,16 @@ application must request the audio capture permission.
    - &lt;uses-permission android:name="android.permission.RECORD_AUDIO" /&gt;
    - </pre>
    -   </li>
    --  <li><strong>Location Permission</strong> - If your application tags images with GPS location
    --information, you must request location permission:
    -+  <li>
    -+    <p><strong>Location Permission</strong> - If your application tags images
    -+    with GPS location information, you must request the {@code ACCESS_FINE_LOCATION}
    -+    permission. Note that, if your app targets Android 5.0 (API level 21) or
    -+    higher, you also need to declare that your app uses the device's GPS:</p>
    - <pre>
    - &lt;uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" /&gt;
    -+...
    -+&lt;!-- Needed only if your app targets Android 5.0 (API level 21) or higher. --&gt;
    -+&lt;uses-feature android:name="android.hardware.location.gps" /&gt;
    - </pre>
    - <p>For more information about getting user location, see
    - <a href="{@docRoot}guide/topics/location/strategies.html">Location Strategies</a>.</p>
    -diff --git a/docs/html/guide/topics/providers/calendar-provider.jd b/docs/html/guide/topics/providers/calendar-provider.jd
    -index 01a1bfc..485f3c1 100644
    ---- a/docs/html/guide/topics/providers/calendar-provider.jd
    -+++ b/docs/html/guide/topics/providers/calendar-provider.jd
    -@@ -278,9 +278,9 @@ private static final int PROJECTION_OWNER_ACCOUNT_INDEX = 3;</pre>
    - 
    - <div class="sidebox-wrapper"> <div class="sidebox"> <h3>Why must you include
    - ACCOUNT_TYPE?</h3> <p>If you query on a {@link
    --android.provider.CalendarContract.SyncColumns#ACCOUNT_NAME
    -+android.provider.CalendarContract.Calendars#ACCOUNT_NAME
    - Calendars.ACCOUNT_NAME}, you must also include
    --{@link android.provider.CalendarContract.SyncColumns#ACCOUNT_TYPE Calendars.ACCOUNT_TYPE}
    -+{@link android.provider.CalendarContract.Calendars#ACCOUNT_TYPE Calendars.ACCOUNT_TYPE}
    - in the selection. That is because a given account is
    - only considered unique given both its <code>ACCOUNT_NAME</code> and its
    - <code>ACCOUNT_TYPE</code>. The <code>ACCOUNT_TYPE</code> is the string corresponding to the
    -diff --git a/docs/html/guide/topics/providers/contacts-provider.jd b/docs/html/guide/topics/providers/contacts-provider.jd
    -index ac855aa..2b14558 100644
    ---- a/docs/html/guide/topics/providers/contacts-provider.jd
    -+++ b/docs/html/guide/topics/providers/contacts-provider.jd
    -@@ -329,13 +329,13 @@ page.title=Contacts Provider
    - </p>
    - <dl>
    -     <dt>
    --        {@link android.provider.ContactsContract.DataColumns#RAW_CONTACT_ID}
    -+        {@link android.provider.ContactsContract.Data#RAW_CONTACT_ID}
    -     </dt>
    -     <dd>
    -         The value of the <code>_ID</code> column of the raw contact for this data.
    -     </dd>
    -     <dt>
    --        {@link android.provider.ContactsContract.DataColumns#MIMETYPE}
    -+        {@link android.provider.ContactsContract.Data#MIMETYPE}
    -     </dt>
    -     <dd>
    -         The type of data stored in this row, expressed as a custom MIME type. The Contacts Provider
    -@@ -2351,7 +2351,7 @@ child elements that provide specific data to the
    -     {@link android.provider.ContactsContract.Data} table, selecting on the raw contact's
    -     {@link android.provider.BaseColumns#_ID}, the
    -     {@link android.provider.ContactsContract.CommonDataKinds.Photo#CONTENT_ITEM_TYPE
    --    Photo.CONTENT_ITEM_TYPE}, and the {@link android.provider.ContactsContract.DataColumns#IS_PRIMARY}
    -+    Photo.CONTENT_ITEM_TYPE}, and the {@link android.provider.ContactsContract.Data#IS_PRIMARY}
    -     column to find the raw contact's primary photo row.
    - </p>
    - <p>
    -diff --git a/docs/html/guide/topics/providers/content-provider-creating.jd b/docs/html/guide/topics/providers/content-provider-creating.jd
    -index ec6909c..59dc108 100755
    ---- a/docs/html/guide/topics/providers/content-provider-creating.jd
    -+++ b/docs/html/guide/topics/providers/content-provider-creating.jd
    -@@ -460,7 +460,7 @@ public class ExampleProvider extends ContentProvider {
    -                  * present. Get the last path segment from the URI; this is the _ID value.
    -                  * Then, append the value to the WHERE clause for the query
    -                  */
    --                selection = selection + "_ID = " uri.getLastPathSegment();
    -+                selection = selection + "_ID = " + uri.getLastPathSegment();
    -                 break;
    - 
    -             default:
    -diff --git a/docs/html/guide/topics/renderscript/reference/rs_allocation_create.jd b/docs/html/guide/topics/renderscript/reference/rs_allocation_create.jd
    -new file mode 100644
    -index 0000000..2defca3
    ---- /dev/null
    -+++ b/docs/html/guide/topics/renderscript/reference/rs_allocation_create.jd
    -@@ -0,0 +1,1060 @@
    -+page.title=RenderScript Allocation Creation Functions
    -+
    -+@jd:body
    -+
    -+<div class='renderscript'>
    -+<h2>Overview</h2>
    -+<p> The functions below are used to create allocations from within a script.
    -+These functions can be called directly or indirectly from an invokable
    -+function. It is an error if any control flow can result in calling these functions
    -+from a RenderScript kernel function.
    -+</p>
    -+<h2>Summary</h2>
    -+<table class='jd-sumtable'><tbody>
    -+  <tr><th colspan='2'>Functions</th></tr>
    -+  <tr class='alt-color api apilevel-1'>
    -+    <td class='jd-linkcol'>
    -+      <a href='rs_allocation_create.html#android_rs:rsCreateAllocation'>rsCreateAllocation</a>
    -+    </td>
    -+    <td class='jd-descrcol' width='100%'>
    -+      Creates an <a href={@docRoot}guide/topics/renderscript/reference/rs_object_types.html#android_rs:rs_allocation>rs_allocation</a> object of given <a href={@docRoot}guide/topics/renderscript/reference/rs_object_types.html#android_rs:rs_type>rs_type</a>
    -+    </td>
    -+  </tr>
    -+  <tr class='alt-color api apilevel-1'>
    -+    <td class='jd-linkcol'>
    -+      <a href='rs_allocation_create.html#android_rs:rsCreateElement'>rsCreateElement</a>
    -+    </td>
    -+    <td class='jd-descrcol' width='100%'>
    -+      Creates an <a href={@docRoot}guide/topics/renderscript/reference/rs_object_types.html#android_rs:rs_element>rs_element</a> object of the specified data type
    -+    </td>
    -+  </tr>
    -+  <tr class='alt-color api apilevel-1'>
    -+    <td class='jd-linkcol'>
    -+      <a href='rs_allocation_create.html#android_rs:rsCreatePixelElement'>rsCreatePixelElement</a>
    -+    </td>
    -+    <td class='jd-descrcol' width='100%'>
    -+      Creates an <a href={@docRoot}guide/topics/renderscript/reference/rs_object_types.html#android_rs:rs_element>rs_element</a> object of the specified data type and data kind
    -+    </td>
    -+  </tr>
    -+  <tr class='alt-color api apilevel-1'>
    -+    <td class='jd-linkcol'>
    -+      <a href='rs_allocation_create.html#android_rs:rsCreateType'>rsCreateType</a>
    -+    </td>
    -+    <td class='jd-descrcol' width='100%'>
    -+      Creates an <a href={@docRoot}guide/topics/renderscript/reference/rs_object_types.html#android_rs:rs_type>rs_type</a> object with the specified <a href={@docRoot}guide/topics/renderscript/reference/rs_object_types.html#android_rs:rs_element>rs_element</a> and shape attributes
    -+    </td>
    -+  </tr>
    -+  <tr class='alt-color api apilevel-1'>
    -+    <td class='jd-linkcol'>
    -+      <a href='rs_allocation_create.html#android_rs:rsCreateVectorElement'>rsCreateVectorElement</a>
    -+    </td>
    -+    <td class='jd-descrcol' width='100%'>
    -+      Creates an <a href={@docRoot}guide/topics/renderscript/reference/rs_object_types.html#android_rs:rs_element>rs_element</a> object of the specified data type and vector width
    -+    </td>
    -+  </tr>
    -+</tbody></table>
    -+<h2>Functions</h2>
    -+<a name='android_rs:rsCreateAllocation'></a>
    -+<div class='jd-details'>
    -+  <h4 class='jd-details-title'>
    -+    <span class='sympad'>rsCreateAllocation</span>
    -+    <span class='normal'>: Creates an <a href={@docRoot}guide/topics/renderscript/reference/rs_object_types.html#android_rs:rs_allocation>rs_allocation</a> object of given <a href={@docRoot}guide/topics/renderscript/reference/rs_object_types.html#android_rs:rs_type>rs_type</a></span>
    -+  </h4>
    -+  <div class='jd-details-descr'>
    -+    <table class='jd-tagtable'><tbody>
    -+      <tr>
    -+        <td><a href='rs_object_types.html#android_rs:rs_allocation'>rs_allocation</a> rsCreateAllocation(<a href='rs_object_types.html#android_rs:rs_type'>rs_type</a> type);
    -+</td>
    -+        <td>    Added in <a href='http://developer.android.com/guide/topics/manifest/uses-sdk-element.html#ApiLevels'>API level 24</a>
    -+        </td>
    -+      </tr>
    -+      <tr>
    -+        <td><a href='rs_object_types.html#android_rs:rs_allocation'>rs_allocation</a> rsCreateAllocation(<a href='rs_object_types.html#android_rs:rs_type'>rs_type</a> type, <a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> usage);
    -+</td>
    -+        <td>    Added in <a href='http://developer.android.com/guide/topics/manifest/uses-sdk-element.html#ApiLevels'>API level 24</a>
    -+        </td>
    -+      </tr>
    -+      <tr>
    -+        <td><a href='rs_object_types.html#android_rs:rs_allocation'>rs_allocation</a> rsCreateAllocation_char(<a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimX);
    -+</td>
    -+        <td>    Added in <a href='http://developer.android.com/guide/topics/manifest/uses-sdk-element.html#ApiLevels'>API level 24</a>
    -+        </td>
    -+      </tr>
    -+      <tr>
    -+        <td><a href='rs_object_types.html#android_rs:rs_allocation'>rs_allocation</a> rsCreateAllocation_char(<a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimX, <a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimY);
    -+</td>
    -+        <td>    Added in <a href='http://developer.android.com/guide/topics/manifest/uses-sdk-element.html#ApiLevels'>API level 24</a>
    -+        </td>
    -+      </tr>
    -+      <tr>
    -+        <td><a href='rs_object_types.html#android_rs:rs_allocation'>rs_allocation</a> rsCreateAllocation_char(<a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimX, <a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimY, <a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimZ);
    -+</td>
    -+        <td>    Added in <a href='http://developer.android.com/guide/topics/manifest/uses-sdk-element.html#ApiLevels'>API level 24</a>
    -+        </td>
    -+      </tr>
    -+      <tr>
    -+        <td><a href='rs_object_types.html#android_rs:rs_allocation'>rs_allocation</a> rsCreateAllocation_char2(<a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimX);
    -+</td>
    -+        <td>    Added in <a href='http://developer.android.com/guide/topics/manifest/uses-sdk-element.html#ApiLevels'>API level 24</a>
    -+        </td>
    -+      </tr>
    -+      <tr>
    -+        <td><a href='rs_object_types.html#android_rs:rs_allocation'>rs_allocation</a> rsCreateAllocation_char2(<a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimX, <a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimY);
    -+</td>
    -+        <td>    Added in <a href='http://developer.android.com/guide/topics/manifest/uses-sdk-element.html#ApiLevels'>API level 24</a>
    -+        </td>
    -+      </tr>
    -+      <tr>
    -+        <td><a href='rs_object_types.html#android_rs:rs_allocation'>rs_allocation</a> rsCreateAllocation_char2(<a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimX, <a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimY, <a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimZ);
    -+</td>
    -+        <td>    Added in <a href='http://developer.android.com/guide/topics/manifest/uses-sdk-element.html#ApiLevels'>API level 24</a>
    -+        </td>
    -+      </tr>
    -+      <tr>
    -+        <td><a href='rs_object_types.html#android_rs:rs_allocation'>rs_allocation</a> rsCreateAllocation_char3(<a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimX);
    -+</td>
    -+        <td>    Added in <a href='http://developer.android.com/guide/topics/manifest/uses-sdk-element.html#ApiLevels'>API level 24</a>
    -+        </td>
    -+      </tr>
    -+      <tr>
    -+        <td><a href='rs_object_types.html#android_rs:rs_allocation'>rs_allocation</a> rsCreateAllocation_char3(<a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimX, <a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimY);
    -+</td>
    -+        <td>    Added in <a href='http://developer.android.com/guide/topics/manifest/uses-sdk-element.html#ApiLevels'>API level 24</a>
    -+        </td>
    -+      </tr>
    -+      <tr>
    -+        <td><a href='rs_object_types.html#android_rs:rs_allocation'>rs_allocation</a> rsCreateAllocation_char3(<a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimX, <a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimY, <a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimZ);
    -+</td>
    -+        <td>    Added in <a href='http://developer.android.com/guide/topics/manifest/uses-sdk-element.html#ApiLevels'>API level 24</a>
    -+        </td>
    -+      </tr>
    -+      <tr>
    -+        <td><a href='rs_object_types.html#android_rs:rs_allocation'>rs_allocation</a> rsCreateAllocation_char4(<a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimX);
    -+</td>
    -+        <td>    Added in <a href='http://developer.android.com/guide/topics/manifest/uses-sdk-element.html#ApiLevels'>API level 24</a>
    -+        </td>
    -+      </tr>
    -+      <tr>
    -+        <td><a href='rs_object_types.html#android_rs:rs_allocation'>rs_allocation</a> rsCreateAllocation_char4(<a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimX, <a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimY);
    -+</td>
    -+        <td>    Added in <a href='http://developer.android.com/guide/topics/manifest/uses-sdk-element.html#ApiLevels'>API level 24</a>
    -+        </td>
    -+      </tr>
    -+      <tr>
    -+        <td><a href='rs_object_types.html#android_rs:rs_allocation'>rs_allocation</a> rsCreateAllocation_char4(<a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimX, <a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimY, <a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimZ);
    -+</td>
    -+        <td>    Added in <a href='http://developer.android.com/guide/topics/manifest/uses-sdk-element.html#ApiLevels'>API level 24</a>
    -+        </td>
    -+      </tr>
    -+      <tr>
    -+        <td><a href='rs_object_types.html#android_rs:rs_allocation'>rs_allocation</a> rsCreateAllocation_double(<a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimX);
    -+</td>
    -+        <td>    Added in <a href='http://developer.android.com/guide/topics/manifest/uses-sdk-element.html#ApiLevels'>API level 24</a>
    -+        </td>
    -+      </tr>
    -+      <tr>
    -+        <td><a href='rs_object_types.html#android_rs:rs_allocation'>rs_allocation</a> rsCreateAllocation_double(<a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimX, <a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimY);
    -+</td>
    -+        <td>    Added in <a href='http://developer.android.com/guide/topics/manifest/uses-sdk-element.html#ApiLevels'>API level 24</a>
    -+        </td>
    -+      </tr>
    -+      <tr>
    -+        <td><a href='rs_object_types.html#android_rs:rs_allocation'>rs_allocation</a> rsCreateAllocation_double(<a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimX, <a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimY, <a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimZ);
    -+</td>
    -+        <td>    Added in <a href='http://developer.android.com/guide/topics/manifest/uses-sdk-element.html#ApiLevels'>API level 24</a>
    -+        </td>
    -+      </tr>
    -+      <tr>
    -+        <td><a href='rs_object_types.html#android_rs:rs_allocation'>rs_allocation</a> rsCreateAllocation_double2(<a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimX);
    -+</td>
    -+        <td>    Added in <a href='http://developer.android.com/guide/topics/manifest/uses-sdk-element.html#ApiLevels'>API level 24</a>
    -+        </td>
    -+      </tr>
    -+      <tr>
    -+        <td><a href='rs_object_types.html#android_rs:rs_allocation'>rs_allocation</a> rsCreateAllocation_double2(<a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimX, <a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimY);
    -+</td>
    -+        <td>    Added in <a href='http://developer.android.com/guide/topics/manifest/uses-sdk-element.html#ApiLevels'>API level 24</a>
    -+        </td>
    -+      </tr>
    -+      <tr>
    -+        <td><a href='rs_object_types.html#android_rs:rs_allocation'>rs_allocation</a> rsCreateAllocation_double2(<a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimX, <a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimY, <a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimZ);
    -+</td>
    -+        <td>    Added in <a href='http://developer.android.com/guide/topics/manifest/uses-sdk-element.html#ApiLevels'>API level 24</a>
    -+        </td>
    -+      </tr>
    -+      <tr>
    -+        <td><a href='rs_object_types.html#android_rs:rs_allocation'>rs_allocation</a> rsCreateAllocation_double3(<a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimX);
    -+</td>
    -+        <td>    Added in <a href='http://developer.android.com/guide/topics/manifest/uses-sdk-element.html#ApiLevels'>API level 24</a>
    -+        </td>
    -+      </tr>
    -+      <tr>
    -+        <td><a href='rs_object_types.html#android_rs:rs_allocation'>rs_allocation</a> rsCreateAllocation_double3(<a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimX, <a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimY);
    -+</td>
    -+        <td>    Added in <a href='http://developer.android.com/guide/topics/manifest/uses-sdk-element.html#ApiLevels'>API level 24</a>
    -+        </td>
    -+      </tr>
    -+      <tr>
    -+        <td><a href='rs_object_types.html#android_rs:rs_allocation'>rs_allocation</a> rsCreateAllocation_double3(<a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimX, <a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimY, <a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimZ);
    -+</td>
    -+        <td>    Added in <a href='http://developer.android.com/guide/topics/manifest/uses-sdk-element.html#ApiLevels'>API level 24</a>
    -+        </td>
    -+      </tr>
    -+      <tr>
    -+        <td><a href='rs_object_types.html#android_rs:rs_allocation'>rs_allocation</a> rsCreateAllocation_double4(<a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimX);
    -+</td>
    -+        <td>    Added in <a href='http://developer.android.com/guide/topics/manifest/uses-sdk-element.html#ApiLevels'>API level 24</a>
    -+        </td>
    -+      </tr>
    -+      <tr>
    -+        <td><a href='rs_object_types.html#android_rs:rs_allocation'>rs_allocation</a> rsCreateAllocation_double4(<a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimX, <a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimY);
    -+</td>
    -+        <td>    Added in <a href='http://developer.android.com/guide/topics/manifest/uses-sdk-element.html#ApiLevels'>API level 24</a>
    -+        </td>
    -+      </tr>
    -+      <tr>
    -+        <td><a href='rs_object_types.html#android_rs:rs_allocation'>rs_allocation</a> rsCreateAllocation_double4(<a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimX, <a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimY, <a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimZ);
    -+</td>
    -+        <td>    Added in <a href='http://developer.android.com/guide/topics/manifest/uses-sdk-element.html#ApiLevels'>API level 24</a>
    -+        </td>
    -+      </tr>
    -+      <tr>
    -+        <td><a href='rs_object_types.html#android_rs:rs_allocation'>rs_allocation</a> rsCreateAllocation_float(<a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimX);
    -+</td>
    -+        <td>    Added in <a href='http://developer.android.com/guide/topics/manifest/uses-sdk-element.html#ApiLevels'>API level 24</a>
    -+        </td>
    -+      </tr>
    -+      <tr>
    -+        <td><a href='rs_object_types.html#android_rs:rs_allocation'>rs_allocation</a> rsCreateAllocation_float(<a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimX, <a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimY);
    -+</td>
    -+        <td>    Added in <a href='http://developer.android.com/guide/topics/manifest/uses-sdk-element.html#ApiLevels'>API level 24</a>
    -+        </td>
    -+      </tr>
    -+      <tr>
    -+        <td><a href='rs_object_types.html#android_rs:rs_allocation'>rs_allocation</a> rsCreateAllocation_float(<a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimX, <a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimY, <a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimZ);
    -+</td>
    -+        <td>    Added in <a href='http://developer.android.com/guide/topics/manifest/uses-sdk-element.html#ApiLevels'>API level 24</a>
    -+        </td>
    -+      </tr>
    -+      <tr>
    -+        <td><a href='rs_object_types.html#android_rs:rs_allocation'>rs_allocation</a> rsCreateAllocation_float2(<a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimX);
    -+</td>
    -+        <td>    Added in <a href='http://developer.android.com/guide/topics/manifest/uses-sdk-element.html#ApiLevels'>API level 24</a>
    -+        </td>
    -+      </tr>
    -+      <tr>
    -+        <td><a href='rs_object_types.html#android_rs:rs_allocation'>rs_allocation</a> rsCreateAllocation_float2(<a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimX, <a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimY);
    -+</td>
    -+        <td>    Added in <a href='http://developer.android.com/guide/topics/manifest/uses-sdk-element.html#ApiLevels'>API level 24</a>
    -+        </td>
    -+      </tr>
    -+      <tr>
    -+        <td><a href='rs_object_types.html#android_rs:rs_allocation'>rs_allocation</a> rsCreateAllocation_float2(<a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimX, <a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimY, <a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimZ);
    -+</td>
    -+        <td>    Added in <a href='http://developer.android.com/guide/topics/manifest/uses-sdk-element.html#ApiLevels'>API level 24</a>
    -+        </td>
    -+      </tr>
    -+      <tr>
    -+        <td><a href='rs_object_types.html#android_rs:rs_allocation'>rs_allocation</a> rsCreateAllocation_float3(<a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimX);
    -+</td>
    -+        <td>    Added in <a href='http://developer.android.com/guide/topics/manifest/uses-sdk-element.html#ApiLevels'>API level 24</a>
    -+        </td>
    -+      </tr>
    -+      <tr>
    -+        <td><a href='rs_object_types.html#android_rs:rs_allocation'>rs_allocation</a> rsCreateAllocation_float3(<a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimX, <a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimY);
    -+</td>
    -+        <td>    Added in <a href='http://developer.android.com/guide/topics/manifest/uses-sdk-element.html#ApiLevels'>API level 24</a>
    -+        </td>
    -+      </tr>
    -+      <tr>
    -+        <td><a href='rs_object_types.html#android_rs:rs_allocation'>rs_allocation</a> rsCreateAllocation_float3(<a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimX, <a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimY, <a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimZ);
    -+</td>
    -+        <td>    Added in <a href='http://developer.android.com/guide/topics/manifest/uses-sdk-element.html#ApiLevels'>API level 24</a>
    -+        </td>
    -+      </tr>
    -+      <tr>
    -+        <td><a href='rs_object_types.html#android_rs:rs_allocation'>rs_allocation</a> rsCreateAllocation_float4(<a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimX);
    -+</td>
    -+        <td>    Added in <a href='http://developer.android.com/guide/topics/manifest/uses-sdk-element.html#ApiLevels'>API level 24</a>
    -+        </td>
    -+      </tr>
    -+      <tr>
    -+        <td><a href='rs_object_types.html#android_rs:rs_allocation'>rs_allocation</a> rsCreateAllocation_float4(<a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimX, <a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimY);
    -+</td>
    -+        <td>    Added in <a href='http://developer.android.com/guide/topics/manifest/uses-sdk-element.html#ApiLevels'>API level 24</a>
    -+        </td>
    -+      </tr>
    -+      <tr>
    -+        <td><a href='rs_object_types.html#android_rs:rs_allocation'>rs_allocation</a> rsCreateAllocation_float4(<a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimX, <a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimY, <a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimZ);
    -+</td>
    -+        <td>    Added in <a href='http://developer.android.com/guide/topics/manifest/uses-sdk-element.html#ApiLevels'>API level 24</a>
    -+        </td>
    -+      </tr>
    -+      <tr>
    -+        <td><a href='rs_object_types.html#android_rs:rs_allocation'>rs_allocation</a> rsCreateAllocation_half(<a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimX);
    -+</td>
    -+        <td>    Added in <a href='http://developer.android.com/guide/topics/manifest/uses-sdk-element.html#ApiLevels'>API level 24</a>
    -+        </td>
    -+      </tr>
    -+      <tr>
    -+        <td><a href='rs_object_types.html#android_rs:rs_allocation'>rs_allocation</a> rsCreateAllocation_half(<a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimX, <a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimY);
    -+</td>
    -+        <td>    Added in <a href='http://developer.android.com/guide/topics/manifest/uses-sdk-element.html#ApiLevels'>API level 24</a>
    -+        </td>
    -+      </tr>
    -+      <tr>
    -+        <td><a href='rs_object_types.html#android_rs:rs_allocation'>rs_allocation</a> rsCreateAllocation_half(<a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimX, <a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimY, <a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimZ);
    -+</td>
    -+        <td>    Added in <a href='http://developer.android.com/guide/topics/manifest/uses-sdk-element.html#ApiLevels'>API level 24</a>
    -+        </td>
    -+      </tr>
    -+      <tr>
    -+        <td><a href='rs_object_types.html#android_rs:rs_allocation'>rs_allocation</a> rsCreateAllocation_half2(<a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimX);
    -+</td>
    -+        <td>    Added in <a href='http://developer.android.com/guide/topics/manifest/uses-sdk-element.html#ApiLevels'>API level 24</a>
    -+        </td>
    -+      </tr>
    -+      <tr>
    -+        <td><a href='rs_object_types.html#android_rs:rs_allocation'>rs_allocation</a> rsCreateAllocation_half2(<a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimX, <a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimY);
    -+</td>
    -+        <td>    Added in <a href='http://developer.android.com/guide/topics/manifest/uses-sdk-element.html#ApiLevels'>API level 24</a>
    -+        </td>
    -+      </tr>
    -+      <tr>
    -+        <td><a href='rs_object_types.html#android_rs:rs_allocation'>rs_allocation</a> rsCreateAllocation_half2(<a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimX, <a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimY, <a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimZ);
    -+</td>
    -+        <td>    Added in <a href='http://developer.android.com/guide/topics/manifest/uses-sdk-element.html#ApiLevels'>API level 24</a>
    -+        </td>
    -+      </tr>
    -+      <tr>
    -+        <td><a href='rs_object_types.html#android_rs:rs_allocation'>rs_allocation</a> rsCreateAllocation_half3(<a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimX);
    -+</td>
    -+        <td>    Added in <a href='http://developer.android.com/guide/topics/manifest/uses-sdk-element.html#ApiLevels'>API level 24</a>
    -+        </td>
    -+      </tr>
    -+      <tr>
    -+        <td><a href='rs_object_types.html#android_rs:rs_allocation'>rs_allocation</a> rsCreateAllocation_half3(<a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimX, <a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimY);
    -+</td>
    -+        <td>    Added in <a href='http://developer.android.com/guide/topics/manifest/uses-sdk-element.html#ApiLevels'>API level 24</a>
    -+        </td>
    -+      </tr>
    -+      <tr>
    -+        <td><a href='rs_object_types.html#android_rs:rs_allocation'>rs_allocation</a> rsCreateAllocation_half3(<a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimX, <a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimY, <a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimZ);
    -+</td>
    -+        <td>    Added in <a href='http://developer.android.com/guide/topics/manifest/uses-sdk-element.html#ApiLevels'>API level 24</a>
    -+        </td>
    -+      </tr>
    -+      <tr>
    -+        <td><a href='rs_object_types.html#android_rs:rs_allocation'>rs_allocation</a> rsCreateAllocation_half4(<a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimX);
    -+</td>
    -+        <td>    Added in <a href='http://developer.android.com/guide/topics/manifest/uses-sdk-element.html#ApiLevels'>API level 24</a>
    -+        </td>
    -+      </tr>
    -+      <tr>
    -+        <td><a href='rs_object_types.html#android_rs:rs_allocation'>rs_allocation</a> rsCreateAllocation_half4(<a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimX, <a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimY);
    -+</td>
    -+        <td>    Added in <a href='http://developer.android.com/guide/topics/manifest/uses-sdk-element.html#ApiLevels'>API level 24</a>
    -+        </td>
    -+      </tr>
    -+      <tr>
    -+        <td><a href='rs_object_types.html#android_rs:rs_allocation'>rs_allocation</a> rsCreateAllocation_half4(<a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimX, <a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimY, <a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimZ);
    -+</td>
    -+        <td>    Added in <a href='http://developer.android.com/guide/topics/manifest/uses-sdk-element.html#ApiLevels'>API level 24</a>
    -+        </td>
    -+      </tr>
    -+      <tr>
    -+        <td><a href='rs_object_types.html#android_rs:rs_allocation'>rs_allocation</a> rsCreateAllocation_int(<a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimX);
    -+</td>
    -+        <td>    Added in <a href='http://developer.android.com/guide/topics/manifest/uses-sdk-element.html#ApiLevels'>API level 24</a>
    -+        </td>
    -+      </tr>
    -+      <tr>
    -+        <td><a href='rs_object_types.html#android_rs:rs_allocation'>rs_allocation</a> rsCreateAllocation_int(<a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimX, <a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimY);
    -+</td>
    -+        <td>    Added in <a href='http://developer.android.com/guide/topics/manifest/uses-sdk-element.html#ApiLevels'>API level 24</a>
    -+        </td>
    -+      </tr>
    -+      <tr>
    -+        <td><a href='rs_object_types.html#android_rs:rs_allocation'>rs_allocation</a> rsCreateAllocation_int(<a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimX, <a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimY, <a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimZ);
    -+</td>
    -+        <td>    Added in <a href='http://developer.android.com/guide/topics/manifest/uses-sdk-element.html#ApiLevels'>API level 24</a>
    -+        </td>
    -+      </tr>
    -+      <tr>
    -+        <td><a href='rs_object_types.html#android_rs:rs_allocation'>rs_allocation</a> rsCreateAllocation_int2(<a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimX);
    -+</td>
    -+        <td>    Added in <a href='http://developer.android.com/guide/topics/manifest/uses-sdk-element.html#ApiLevels'>API level 24</a>
    -+        </td>
    -+      </tr>
    -+      <tr>
    -+        <td><a href='rs_object_types.html#android_rs:rs_allocation'>rs_allocation</a> rsCreateAllocation_int2(<a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimX, <a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimY);
    -+</td>
    -+        <td>    Added in <a href='http://developer.android.com/guide/topics/manifest/uses-sdk-element.html#ApiLevels'>API level 24</a>
    -+        </td>
    -+      </tr>
    -+      <tr>
    -+        <td><a href='rs_object_types.html#android_rs:rs_allocation'>rs_allocation</a> rsCreateAllocation_int2(<a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimX, <a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimY, <a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimZ);
    -+</td>
    -+        <td>    Added in <a href='http://developer.android.com/guide/topics/manifest/uses-sdk-element.html#ApiLevels'>API level 24</a>
    -+        </td>
    -+      </tr>
    -+      <tr>
    -+        <td><a href='rs_object_types.html#android_rs:rs_allocation'>rs_allocation</a> rsCreateAllocation_int3(<a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimX);
    -+</td>
    -+        <td>    Added in <a href='http://developer.android.com/guide/topics/manifest/uses-sdk-element.html#ApiLevels'>API level 24</a>
    -+        </td>
    -+      </tr>
    -+      <tr>
    -+        <td><a href='rs_object_types.html#android_rs:rs_allocation'>rs_allocation</a> rsCreateAllocation_int3(<a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimX, <a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimY);
    -+</td>
    -+        <td>    Added in <a href='http://developer.android.com/guide/topics/manifest/uses-sdk-element.html#ApiLevels'>API level 24</a>
    -+        </td>
    -+      </tr>
    -+      <tr>
    -+        <td><a href='rs_object_types.html#android_rs:rs_allocation'>rs_allocation</a> rsCreateAllocation_int3(<a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimX, <a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimY, <a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimZ);
    -+</td>
    -+        <td>    Added in <a href='http://developer.android.com/guide/topics/manifest/uses-sdk-element.html#ApiLevels'>API level 24</a>
    -+        </td>
    -+      </tr>
    -+      <tr>
    -+        <td><a href='rs_object_types.html#android_rs:rs_allocation'>rs_allocation</a> rsCreateAllocation_int4(<a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimX);
    -+</td>
    -+        <td>    Added in <a href='http://developer.android.com/guide/topics/manifest/uses-sdk-element.html#ApiLevels'>API level 24</a>
    -+        </td>
    -+      </tr>
    -+      <tr>
    -+        <td><a href='rs_object_types.html#android_rs:rs_allocation'>rs_allocation</a> rsCreateAllocation_int4(<a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimX, <a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimY);
    -+</td>
    -+        <td>    Added in <a href='http://developer.android.com/guide/topics/manifest/uses-sdk-element.html#ApiLevels'>API level 24</a>
    -+        </td>
    -+      </tr>
    -+      <tr>
    -+        <td><a href='rs_object_types.html#android_rs:rs_allocation'>rs_allocation</a> rsCreateAllocation_int4(<a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimX, <a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimY, <a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimZ);
    -+</td>
    -+        <td>    Added in <a href='http://developer.android.com/guide/topics/manifest/uses-sdk-element.html#ApiLevels'>API level 24</a>
    -+        </td>
    -+      </tr>
    -+      <tr>
    -+        <td><a href='rs_object_types.html#android_rs:rs_allocation'>rs_allocation</a> rsCreateAllocation_long(<a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimX);
    -+</td>
    -+        <td>    Added in <a href='http://developer.android.com/guide/topics/manifest/uses-sdk-element.html#ApiLevels'>API level 24</a>
    -+        </td>
    -+      </tr>
    -+      <tr>
    -+        <td><a href='rs_object_types.html#android_rs:rs_allocation'>rs_allocation</a> rsCreateAllocation_long(<a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimX, <a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimY);
    -+</td>
    -+        <td>    Added in <a href='http://developer.android.com/guide/topics/manifest/uses-sdk-element.html#ApiLevels'>API level 24</a>
    -+        </td>
    -+      </tr>
    -+      <tr>
    -+        <td><a href='rs_object_types.html#android_rs:rs_allocation'>rs_allocation</a> rsCreateAllocation_long(<a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimX, <a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimY, <a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimZ);
    -+</td>
    -+        <td>    Added in <a href='http://developer.android.com/guide/topics/manifest/uses-sdk-element.html#ApiLevels'>API level 24</a>
    -+        </td>
    -+      </tr>
    -+      <tr>
    -+        <td><a href='rs_object_types.html#android_rs:rs_allocation'>rs_allocation</a> rsCreateAllocation_long2(<a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimX);
    -+</td>
    -+        <td>    Added in <a href='http://developer.android.com/guide/topics/manifest/uses-sdk-element.html#ApiLevels'>API level 24</a>
    -+        </td>
    -+      </tr>
    -+      <tr>
    -+        <td><a href='rs_object_types.html#android_rs:rs_allocation'>rs_allocation</a> rsCreateAllocation_long2(<a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimX, <a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimY);
    -+</td>
    -+        <td>    Added in <a href='http://developer.android.com/guide/topics/manifest/uses-sdk-element.html#ApiLevels'>API level 24</a>
    -+        </td>
    -+      </tr>
    -+      <tr>
    -+        <td><a href='rs_object_types.html#android_rs:rs_allocation'>rs_allocation</a> rsCreateAllocation_long2(<a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimX, <a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimY, <a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimZ);
    -+</td>
    -+        <td>    Added in <a href='http://developer.android.com/guide/topics/manifest/uses-sdk-element.html#ApiLevels'>API level 24</a>
    -+        </td>
    -+      </tr>
    -+      <tr>
    -+        <td><a href='rs_object_types.html#android_rs:rs_allocation'>rs_allocation</a> rsCreateAllocation_long3(<a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimX);
    -+</td>
    -+        <td>    Added in <a href='http://developer.android.com/guide/topics/manifest/uses-sdk-element.html#ApiLevels'>API level 24</a>
    -+        </td>
    -+      </tr>
    -+      <tr>
    -+        <td><a href='rs_object_types.html#android_rs:rs_allocation'>rs_allocation</a> rsCreateAllocation_long3(<a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimX, <a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimY);
    -+</td>
    -+        <td>    Added in <a href='http://developer.android.com/guide/topics/manifest/uses-sdk-element.html#ApiLevels'>API level 24</a>
    -+        </td>
    -+      </tr>
    -+      <tr>
    -+        <td><a href='rs_object_types.html#android_rs:rs_allocation'>rs_allocation</a> rsCreateAllocation_long3(<a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimX, <a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimY, <a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimZ);
    -+</td>
    -+        <td>    Added in <a href='http://developer.android.com/guide/topics/manifest/uses-sdk-element.html#ApiLevels'>API level 24</a>
    -+        </td>
    -+      </tr>
    -+      <tr>
    -+        <td><a href='rs_object_types.html#android_rs:rs_allocation'>rs_allocation</a> rsCreateAllocation_long4(<a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimX);
    -+</td>
    -+        <td>    Added in <a href='http://developer.android.com/guide/topics/manifest/uses-sdk-element.html#ApiLevels'>API level 24</a>
    -+        </td>
    -+      </tr>
    -+      <tr>
    -+        <td><a href='rs_object_types.html#android_rs:rs_allocation'>rs_allocation</a> rsCreateAllocation_long4(<a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimX, <a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimY);
    -+</td>
    -+        <td>    Added in <a href='http://developer.android.com/guide/topics/manifest/uses-sdk-element.html#ApiLevels'>API level 24</a>
    -+        </td>
    -+      </tr>
    -+      <tr>
    -+        <td><a href='rs_object_types.html#android_rs:rs_allocation'>rs_allocation</a> rsCreateAllocation_long4(<a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimX, <a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimY, <a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimZ);
    -+</td>
    -+        <td>    Added in <a href='http://developer.android.com/guide/topics/manifest/uses-sdk-element.html#ApiLevels'>API level 24</a>
    -+        </td>
    -+      </tr>
    -+      <tr>
    -+        <td><a href='rs_object_types.html#android_rs:rs_allocation'>rs_allocation</a> rsCreateAllocation_short(<a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimX);
    -+</td>
    -+        <td>    Added in <a href='http://developer.android.com/guide/topics/manifest/uses-sdk-element.html#ApiLevels'>API level 24</a>
    -+        </td>
    -+      </tr>
    -+      <tr>
    -+        <td><a href='rs_object_types.html#android_rs:rs_allocation'>rs_allocation</a> rsCreateAllocation_short(<a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimX, <a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimY);
    -+</td>
    -+        <td>    Added in <a href='http://developer.android.com/guide/topics/manifest/uses-sdk-element.html#ApiLevels'>API level 24</a>
    -+        </td>
    -+      </tr>
    -+      <tr>
    -+        <td><a href='rs_object_types.html#android_rs:rs_allocation'>rs_allocation</a> rsCreateAllocation_short(<a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimX, <a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimY, <a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimZ);
    -+</td>
    -+        <td>    Added in <a href='http://developer.android.com/guide/topics/manifest/uses-sdk-element.html#ApiLevels'>API level 24</a>
    -+        </td>
    -+      </tr>
    -+      <tr>
    -+        <td><a href='rs_object_types.html#android_rs:rs_allocation'>rs_allocation</a> rsCreateAllocation_short2(<a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimX);
    -+</td>
    -+        <td>    Added in <a href='http://developer.android.com/guide/topics/manifest/uses-sdk-element.html#ApiLevels'>API level 24</a>
    -+        </td>
    -+      </tr>
    -+      <tr>
    -+        <td><a href='rs_object_types.html#android_rs:rs_allocation'>rs_allocation</a> rsCreateAllocation_short2(<a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimX, <a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimY);
    -+</td>
    -+        <td>    Added in <a href='http://developer.android.com/guide/topics/manifest/uses-sdk-element.html#ApiLevels'>API level 24</a>
    -+        </td>
    -+      </tr>
    -+      <tr>
    -+        <td><a href='rs_object_types.html#android_rs:rs_allocation'>rs_allocation</a> rsCreateAllocation_short2(<a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimX, <a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimY, <a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimZ);
    -+</td>
    -+        <td>    Added in <a href='http://developer.android.com/guide/topics/manifest/uses-sdk-element.html#ApiLevels'>API level 24</a>
    -+        </td>
    -+      </tr>
    -+      <tr>
    -+        <td><a href='rs_object_types.html#android_rs:rs_allocation'>rs_allocation</a> rsCreateAllocation_short3(<a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimX);
    -+</td>
    -+        <td>    Added in <a href='http://developer.android.com/guide/topics/manifest/uses-sdk-element.html#ApiLevels'>API level 24</a>
    -+        </td>
    -+      </tr>
    -+      <tr>
    -+        <td><a href='rs_object_types.html#android_rs:rs_allocation'>rs_allocation</a> rsCreateAllocation_short3(<a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimX, <a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimY);
    -+</td>
    -+        <td>    Added in <a href='http://developer.android.com/guide/topics/manifest/uses-sdk-element.html#ApiLevels'>API level 24</a>
    -+        </td>
    -+      </tr>
    -+      <tr>
    -+        <td><a href='rs_object_types.html#android_rs:rs_allocation'>rs_allocation</a> rsCreateAllocation_short3(<a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimX, <a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimY, <a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimZ);
    -+</td>
    -+        <td>    Added in <a href='http://developer.android.com/guide/topics/manifest/uses-sdk-element.html#ApiLevels'>API level 24</a>
    -+        </td>
    -+      </tr>
    -+      <tr>
    -+        <td><a href='rs_object_types.html#android_rs:rs_allocation'>rs_allocation</a> rsCreateAllocation_short4(<a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimX);
    -+</td>
    -+        <td>    Added in <a href='http://developer.android.com/guide/topics/manifest/uses-sdk-element.html#ApiLevels'>API level 24</a>
    -+        </td>
    -+      </tr>
    -+      <tr>
    -+        <td><a href='rs_object_types.html#android_rs:rs_allocation'>rs_allocation</a> rsCreateAllocation_short4(<a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimX, <a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimY);
    -+</td>
    -+        <td>    Added in <a href='http://developer.android.com/guide/topics/manifest/uses-sdk-element.html#ApiLevels'>API level 24</a>
    -+        </td>
    -+      </tr>
    -+      <tr>
    -+        <td><a href='rs_object_types.html#android_rs:rs_allocation'>rs_allocation</a> rsCreateAllocation_short4(<a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimX, <a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimY, <a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimZ);
    -+</td>
    -+        <td>    Added in <a href='http://developer.android.com/guide/topics/manifest/uses-sdk-element.html#ApiLevels'>API level 24</a>
    -+        </td>
    -+      </tr>
    -+      <tr>
    -+        <td><a href='rs_object_types.html#android_rs:rs_allocation'>rs_allocation</a> rsCreateAllocation_uchar(<a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimX);
    -+</td>
    -+        <td>    Added in <a href='http://developer.android.com/guide/topics/manifest/uses-sdk-element.html#ApiLevels'>API level 24</a>
    -+        </td>
    -+      </tr>
    -+      <tr>
    -+        <td><a href='rs_object_types.html#android_rs:rs_allocation'>rs_allocation</a> rsCreateAllocation_uchar(<a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimX, <a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimY);
    -+</td>
    -+        <td>    Added in <a href='http://developer.android.com/guide/topics/manifest/uses-sdk-element.html#ApiLevels'>API level 24</a>
    -+        </td>
    -+      </tr>
    -+      <tr>
    -+        <td><a href='rs_object_types.html#android_rs:rs_allocation'>rs_allocation</a> rsCreateAllocation_uchar(<a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimX, <a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimY, <a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimZ);
    -+</td>
    -+        <td>    Added in <a href='http://developer.android.com/guide/topics/manifest/uses-sdk-element.html#ApiLevels'>API level 24</a>
    -+        </td>
    -+      </tr>
    -+      <tr>
    -+        <td><a href='rs_object_types.html#android_rs:rs_allocation'>rs_allocation</a> rsCreateAllocation_uchar2(<a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimX);
    -+</td>
    -+        <td>    Added in <a href='http://developer.android.com/guide/topics/manifest/uses-sdk-element.html#ApiLevels'>API level 24</a>
    -+        </td>
    -+      </tr>
    -+      <tr>
    -+        <td><a href='rs_object_types.html#android_rs:rs_allocation'>rs_allocation</a> rsCreateAllocation_uchar2(<a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimX, <a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimY);
    -+</td>
    -+        <td>    Added in <a href='http://developer.android.com/guide/topics/manifest/uses-sdk-element.html#ApiLevels'>API level 24</a>
    -+        </td>
    -+      </tr>
    -+      <tr>
    -+        <td><a href='rs_object_types.html#android_rs:rs_allocation'>rs_allocation</a> rsCreateAllocation_uchar2(<a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimX, <a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimY, <a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimZ);
    -+</td>
    -+        <td>    Added in <a href='http://developer.android.com/guide/topics/manifest/uses-sdk-element.html#ApiLevels'>API level 24</a>
    -+        </td>
    -+      </tr>
    -+      <tr>
    -+        <td><a href='rs_object_types.html#android_rs:rs_allocation'>rs_allocation</a> rsCreateAllocation_uchar3(<a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimX);
    -+</td>
    -+        <td>    Added in <a href='http://developer.android.com/guide/topics/manifest/uses-sdk-element.html#ApiLevels'>API level 24</a>
    -+        </td>
    -+      </tr>
    -+      <tr>
    -+        <td><a href='rs_object_types.html#android_rs:rs_allocation'>rs_allocation</a> rsCreateAllocation_uchar3(<a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimX, <a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimY);
    -+</td>
    -+        <td>    Added in <a href='http://developer.android.com/guide/topics/manifest/uses-sdk-element.html#ApiLevels'>API level 24</a>
    -+        </td>
    -+      </tr>
    -+      <tr>
    -+        <td><a href='rs_object_types.html#android_rs:rs_allocation'>rs_allocation</a> rsCreateAllocation_uchar3(<a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimX, <a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimY, <a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimZ);
    -+</td>
    -+        <td>    Added in <a href='http://developer.android.com/guide/topics/manifest/uses-sdk-element.html#ApiLevels'>API level 24</a>
    -+        </td>
    -+      </tr>
    -+      <tr>
    -+        <td><a href='rs_object_types.html#android_rs:rs_allocation'>rs_allocation</a> rsCreateAllocation_uchar4(<a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimX);
    -+</td>
    -+        <td>    Added in <a href='http://developer.android.com/guide/topics/manifest/uses-sdk-element.html#ApiLevels'>API level 24</a>
    -+        </td>
    -+      </tr>
    -+      <tr>
    -+        <td><a href='rs_object_types.html#android_rs:rs_allocation'>rs_allocation</a> rsCreateAllocation_uchar4(<a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimX, <a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimY);
    -+</td>
    -+        <td>    Added in <a href='http://developer.android.com/guide/topics/manifest/uses-sdk-element.html#ApiLevels'>API level 24</a>
    -+        </td>
    -+      </tr>
    -+      <tr>
    -+        <td><a href='rs_object_types.html#android_rs:rs_allocation'>rs_allocation</a> rsCreateAllocation_uchar4(<a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimX, <a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimY, <a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimZ);
    -+</td>
    -+        <td>    Added in <a href='http://developer.android.com/guide/topics/manifest/uses-sdk-element.html#ApiLevels'>API level 24</a>
    -+        </td>
    -+      </tr>
    -+      <tr>
    -+        <td><a href='rs_object_types.html#android_rs:rs_allocation'>rs_allocation</a> rsCreateAllocation_uint(<a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimX);
    -+</td>
    -+        <td>    Added in <a href='http://developer.android.com/guide/topics/manifest/uses-sdk-element.html#ApiLevels'>API level 24</a>
    -+        </td>
    -+      </tr>
    -+      <tr>
    -+        <td><a href='rs_object_types.html#android_rs:rs_allocation'>rs_allocation</a> rsCreateAllocation_uint(<a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimX, <a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimY);
    -+</td>
    -+        <td>    Added in <a href='http://developer.android.com/guide/topics/manifest/uses-sdk-element.html#ApiLevels'>API level 24</a>
    -+        </td>
    -+      </tr>
    -+      <tr>
    -+        <td><a href='rs_object_types.html#android_rs:rs_allocation'>rs_allocation</a> rsCreateAllocation_uint(<a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimX, <a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimY, <a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimZ);
    -+</td>
    -+        <td>    Added in <a href='http://developer.android.com/guide/topics/manifest/uses-sdk-element.html#ApiLevels'>API level 24</a>
    -+        </td>
    -+      </tr>
    -+      <tr>
    -+        <td><a href='rs_object_types.html#android_rs:rs_allocation'>rs_allocation</a> rsCreateAllocation_uint2(<a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimX);
    -+</td>
    -+        <td>    Added in <a href='http://developer.android.com/guide/topics/manifest/uses-sdk-element.html#ApiLevels'>API level 24</a>
    -+        </td>
    -+      </tr>
    -+      <tr>
    -+        <td><a href='rs_object_types.html#android_rs:rs_allocation'>rs_allocation</a> rsCreateAllocation_uint2(<a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimX, <a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimY);
    -+</td>
    -+        <td>    Added in <a href='http://developer.android.com/guide/topics/manifest/uses-sdk-element.html#ApiLevels'>API level 24</a>
    -+        </td>
    -+      </tr>
    -+      <tr>
    -+        <td><a href='rs_object_types.html#android_rs:rs_allocation'>rs_allocation</a> rsCreateAllocation_uint2(<a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimX, <a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimY, <a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimZ);
    -+</td>
    -+        <td>    Added in <a href='http://developer.android.com/guide/topics/manifest/uses-sdk-element.html#ApiLevels'>API level 24</a>
    -+        </td>
    -+      </tr>
    -+      <tr>
    -+        <td><a href='rs_object_types.html#android_rs:rs_allocation'>rs_allocation</a> rsCreateAllocation_uint3(<a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimX);
    -+</td>
    -+        <td>    Added in <a href='http://developer.android.com/guide/topics/manifest/uses-sdk-element.html#ApiLevels'>API level 24</a>
    -+        </td>
    -+      </tr>
    -+      <tr>
    -+        <td><a href='rs_object_types.html#android_rs:rs_allocation'>rs_allocation</a> rsCreateAllocation_uint3(<a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimX, <a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimY);
    -+</td>
    -+        <td>    Added in <a href='http://developer.android.com/guide/topics/manifest/uses-sdk-element.html#ApiLevels'>API level 24</a>
    -+        </td>
    -+      </tr>
    -+      <tr>
    -+        <td><a href='rs_object_types.html#android_rs:rs_allocation'>rs_allocation</a> rsCreateAllocation_uint3(<a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimX, <a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimY, <a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimZ);
    -+</td>
    -+        <td>    Added in <a href='http://developer.android.com/guide/topics/manifest/uses-sdk-element.html#ApiLevels'>API level 24</a>
    -+        </td>
    -+      </tr>
    -+      <tr>
    -+        <td><a href='rs_object_types.html#android_rs:rs_allocation'>rs_allocation</a> rsCreateAllocation_uint4(<a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimX);
    -+</td>
    -+        <td>    Added in <a href='http://developer.android.com/guide/topics/manifest/uses-sdk-element.html#ApiLevels'>API level 24</a>
    -+        </td>
    -+      </tr>
    -+      <tr>
    -+        <td><a href='rs_object_types.html#android_rs:rs_allocation'>rs_allocation</a> rsCreateAllocation_uint4(<a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimX, <a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimY);
    -+</td>
    -+        <td>    Added in <a href='http://developer.android.com/guide/topics/manifest/uses-sdk-element.html#ApiLevels'>API level 24</a>
    -+        </td>
    -+      </tr>
    -+      <tr>
    -+        <td><a href='rs_object_types.html#android_rs:rs_allocation'>rs_allocation</a> rsCreateAllocation_uint4(<a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimX, <a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimY, <a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimZ);
    -+</td>
    -+        <td>    Added in <a href='http://developer.android.com/guide/topics/manifest/uses-sdk-element.html#ApiLevels'>API level 24</a>
    -+        </td>
    -+      </tr>
    -+      <tr>
    -+        <td><a href='rs_object_types.html#android_rs:rs_allocation'>rs_allocation</a> rsCreateAllocation_ulong(<a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimX);
    -+</td>
    -+        <td>    Added in <a href='http://developer.android.com/guide/topics/manifest/uses-sdk-element.html#ApiLevels'>API level 24</a>
    -+        </td>
    -+      </tr>
    -+      <tr>
    -+        <td><a href='rs_object_types.html#android_rs:rs_allocation'>rs_allocation</a> rsCreateAllocation_ulong(<a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimX, <a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimY);
    -+</td>
    -+        <td>    Added in <a href='http://developer.android.com/guide/topics/manifest/uses-sdk-element.html#ApiLevels'>API level 24</a>
    -+        </td>
    -+      </tr>
    -+      <tr>
    -+        <td><a href='rs_object_types.html#android_rs:rs_allocation'>rs_allocation</a> rsCreateAllocation_ulong(<a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimX, <a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimY, <a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimZ);
    -+</td>
    -+        <td>    Added in <a href='http://developer.android.com/guide/topics/manifest/uses-sdk-element.html#ApiLevels'>API level 24</a>
    -+        </td>
    -+      </tr>
    -+      <tr>
    -+        <td><a href='rs_object_types.html#android_rs:rs_allocation'>rs_allocation</a> rsCreateAllocation_ulong2(<a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimX);
    -+</td>
    -+        <td>    Added in <a href='http://developer.android.com/guide/topics/manifest/uses-sdk-element.html#ApiLevels'>API level 24</a>
    -+        </td>
    -+      </tr>
    -+      <tr>
    -+        <td><a href='rs_object_types.html#android_rs:rs_allocation'>rs_allocation</a> rsCreateAllocation_ulong2(<a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimX, <a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimY);
    -+</td>
    -+        <td>    Added in <a href='http://developer.android.com/guide/topics/manifest/uses-sdk-element.html#ApiLevels'>API level 24</a>
    -+        </td>
    -+      </tr>
    -+      <tr>
    -+        <td><a href='rs_object_types.html#android_rs:rs_allocation'>rs_allocation</a> rsCreateAllocation_ulong2(<a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimX, <a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimY, <a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimZ);
    -+</td>
    -+        <td>    Added in <a href='http://developer.android.com/guide/topics/manifest/uses-sdk-element.html#ApiLevels'>API level 24</a>
    -+        </td>
    -+      </tr>
    -+      <tr>
    -+        <td><a href='rs_object_types.html#android_rs:rs_allocation'>rs_allocation</a> rsCreateAllocation_ulong3(<a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimX);
    -+</td>
    -+        <td>    Added in <a href='http://developer.android.com/guide/topics/manifest/uses-sdk-element.html#ApiLevels'>API level 24</a>
    -+        </td>
    -+      </tr>
    -+      <tr>
    -+        <td><a href='rs_object_types.html#android_rs:rs_allocation'>rs_allocation</a> rsCreateAllocation_ulong3(<a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimX, <a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimY);
    -+</td>
    -+        <td>    Added in <a href='http://developer.android.com/guide/topics/manifest/uses-sdk-element.html#ApiLevels'>API level 24</a>
    -+        </td>
    -+      </tr>
    -+      <tr>
    -+        <td><a href='rs_object_types.html#android_rs:rs_allocation'>rs_allocation</a> rsCreateAllocation_ulong3(<a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimX, <a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimY, <a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimZ);
    -+</td>
    -+        <td>    Added in <a href='http://developer.android.com/guide/topics/manifest/uses-sdk-element.html#ApiLevels'>API level 24</a>
    -+        </td>
    -+      </tr>
    -+      <tr>
    -+        <td><a href='rs_object_types.html#android_rs:rs_allocation'>rs_allocation</a> rsCreateAllocation_ulong4(<a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimX);
    -+</td>
    -+        <td>    Added in <a href='http://developer.android.com/guide/topics/manifest/uses-sdk-element.html#ApiLevels'>API level 24</a>
    -+        </td>
    -+      </tr>
    -+      <tr>
    -+        <td><a href='rs_object_types.html#android_rs:rs_allocation'>rs_allocation</a> rsCreateAllocation_ulong4(<a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimX, <a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimY);
    -+</td>
    -+        <td>    Added in <a href='http://developer.android.com/guide/topics/manifest/uses-sdk-element.html#ApiLevels'>API level 24</a>
    -+        </td>
    -+      </tr>
    -+      <tr>
    -+        <td><a href='rs_object_types.html#android_rs:rs_allocation'>rs_allocation</a> rsCreateAllocation_ulong4(<a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimX, <a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimY, <a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimZ);
    -+</td>
    -+        <td>    Added in <a href='http://developer.android.com/guide/topics/manifest/uses-sdk-element.html#ApiLevels'>API level 24</a>
    -+        </td>
    -+      </tr>
    -+      <tr>
    -+        <td><a href='rs_object_types.html#android_rs:rs_allocation'>rs_allocation</a> rsCreateAllocation_ushort(<a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimX);
    -+</td>
    -+        <td>    Added in <a href='http://developer.android.com/guide/topics/manifest/uses-sdk-element.html#ApiLevels'>API level 24</a>
    -+        </td>
    -+      </tr>
    -+      <tr>
    -+        <td><a href='rs_object_types.html#android_rs:rs_allocation'>rs_allocation</a> rsCreateAllocation_ushort(<a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimX, <a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimY);
    -+</td>
    -+        <td>    Added in <a href='http://developer.android.com/guide/topics/manifest/uses-sdk-element.html#ApiLevels'>API level 24</a>
    -+        </td>
    -+      </tr>
    -+      <tr>
    -+        <td><a href='rs_object_types.html#android_rs:rs_allocation'>rs_allocation</a> rsCreateAllocation_ushort(<a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimX, <a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimY, <a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimZ);
    -+</td>
    -+        <td>    Added in <a href='http://developer.android.com/guide/topics/manifest/uses-sdk-element.html#ApiLevels'>API level 24</a>
    -+        </td>
    -+      </tr>
    -+      <tr>
    -+        <td><a href='rs_object_types.html#android_rs:rs_allocation'>rs_allocation</a> rsCreateAllocation_ushort2(<a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimX);
    -+</td>
    -+        <td>    Added in <a href='http://developer.android.com/guide/topics/manifest/uses-sdk-element.html#ApiLevels'>API level 24</a>
    -+        </td>
    -+      </tr>
    -+      <tr>
    -+        <td><a href='rs_object_types.html#android_rs:rs_allocation'>rs_allocation</a> rsCreateAllocation_ushort2(<a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimX, <a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimY);
    -+</td>
    -+        <td>    Added in <a href='http://developer.android.com/guide/topics/manifest/uses-sdk-element.html#ApiLevels'>API level 24</a>
    -+        </td>
    -+      </tr>
    -+      <tr>
    -+        <td><a href='rs_object_types.html#android_rs:rs_allocation'>rs_allocation</a> rsCreateAllocation_ushort2(<a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimX, <a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimY, <a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimZ);
    -+</td>
    -+        <td>    Added in <a href='http://developer.android.com/guide/topics/manifest/uses-sdk-element.html#ApiLevels'>API level 24</a>
    -+        </td>
    -+      </tr>
    -+      <tr>
    -+        <td><a href='rs_object_types.html#android_rs:rs_allocation'>rs_allocation</a> rsCreateAllocation_ushort3(<a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimX);
    -+</td>
    -+        <td>    Added in <a href='http://developer.android.com/guide/topics/manifest/uses-sdk-element.html#ApiLevels'>API level 24</a>
    -+        </td>
    -+      </tr>
    -+      <tr>
    -+        <td><a href='rs_object_types.html#android_rs:rs_allocation'>rs_allocation</a> rsCreateAllocation_ushort3(<a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimX, <a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimY);
    -+</td>
    -+        <td>    Added in <a href='http://developer.android.com/guide/topics/manifest/uses-sdk-element.html#ApiLevels'>API level 24</a>
    -+        </td>
    -+      </tr>
    -+      <tr>
    -+        <td><a href='rs_object_types.html#android_rs:rs_allocation'>rs_allocation</a> rsCreateAllocation_ushort3(<a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimX, <a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimY, <a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimZ);
    -+</td>
    -+        <td>    Added in <a href='http://developer.android.com/guide/topics/manifest/uses-sdk-element.html#ApiLevels'>API level 24</a>
    -+        </td>
    -+      </tr>
    -+      <tr>
    -+        <td><a href='rs_object_types.html#android_rs:rs_allocation'>rs_allocation</a> rsCreateAllocation_ushort4(<a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimX);
    -+</td>
    -+        <td>    Added in <a href='http://developer.android.com/guide/topics/manifest/uses-sdk-element.html#ApiLevels'>API level 24</a>
    -+        </td>
    -+      </tr>
    -+      <tr>
    -+        <td><a href='rs_object_types.html#android_rs:rs_allocation'>rs_allocation</a> rsCreateAllocation_ushort4(<a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimX, <a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimY);
    -+</td>
    -+        <td>    Added in <a href='http://developer.android.com/guide/topics/manifest/uses-sdk-element.html#ApiLevels'>API level 24</a>
    -+        </td>
    -+      </tr>
    -+      <tr>
    -+        <td><a href='rs_object_types.html#android_rs:rs_allocation'>rs_allocation</a> rsCreateAllocation_ushort4(<a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimX, <a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimY, <a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimZ);
    -+</td>
    -+        <td>    Added in <a href='http://developer.android.com/guide/topics/manifest/uses-sdk-element.html#ApiLevels'>API level 24</a>
    -+        </td>
    -+      </tr>
    -+    </tbody></table>
    -+  </div>
    -+  <div class='jd-tagdata'>    <h5 class='jd-tagtitle'>Parameters</h5>
    -+    <table class='jd-tagtable'><tbody>
    -+    <tr><th>type</th><td>Type of the allocation</td></tr>
    -+    <tr><th>usage</th><td>How the allocation should be used. A valid value is either of the following or their combination:<br>RS_ALLOCATION_USAGE_GRAPHICS_TEXTURE,<br>RS_ALLOCATION_USAGE_SCRIPT.</td></tr>
    -+    <tr><th>mipmap</th><td>A boolean flag indicating if the allocation is mipmapped and has multiple levels of detail (LoD).</td></tr>
    -+    <tr><th>dimX</th><td>Size on dimension x. Must be non zero.</td></tr>
    -+    <tr><th>dimY</th><td>Size on dimension y. 0 for single-dimension allocations.</td></tr>
    -+    <tr><th>dimZ</th><td>Size on dimension z. 0 for single-dimension and two-dimension allocations.</td></tr>
    -+    </tbody></table>
    -+  </div>
    -+  <div class='jd-tagdata jd-tagdescr'>
    -+<p>  Creates an rs_allocation object of the given rs_type and for the specified usages.
    -+</p>
    -+
    -+<p>  RS_ALLOCATION_USAGE_SCRIPT and RS_ALLOCATION_USAGE_GRAPHICS_TEXTURE are the
    -+ only supported usage flags for Allocations created from within a RenderScript
    -+ script.
    -+</p>
    -+
    -+<p>  You can also use rsCreateAllocation_<type><width> wrapper functions to directly
    -+ create allocations of scalar and vector numerical types without creating
    -+ intermediate rs_element or rs_type objects.
    -+</p>
    -+
    -+<p>  For example, rsCreateAllocation_int4() returns an Allocation of int4 data type of
    -+ specified dimensions.
    -+</p>
    -+  </div>
    -+</div>
    -+
    -+<a name='android_rs:rsCreateElement'></a>
    -+<div class='jd-details'>
    -+  <h4 class='jd-details-title'>
    -+    <span class='sympad'>rsCreateElement</span>
    -+    <span class='normal'>: Creates an <a href={@docRoot}guide/topics/renderscript/reference/rs_object_types.html#android_rs:rs_element>rs_element</a> object of the specified data type</span>
    -+  </h4>
    -+  <div class='jd-details-descr'>
    -+    <table class='jd-tagtable'><tbody>
    -+      <tr>
    -+        <td><a href='rs_object_types.html#android_rs:rs_element'>rs_element</a> rsCreateElement(<a href='rs_object_types.html#android_rs:rs_data_type'>rs_data_type</a> data_type);
    -+</td>
    -+        <td>    Added in <a href='http://developer.android.com/guide/topics/manifest/uses-sdk-element.html#ApiLevels'>API level 24</a>
    -+        </td>
    -+      </tr>
    -+    </tbody></table>
    -+  </div>
    -+  <div class='jd-tagdata'>    <h5 class='jd-tagtitle'>Parameters</h5>
    -+    <table class='jd-tagtable'><tbody>
    -+    <tr><th>data_type</th><td>Data type of the Element</td></tr>
    -+    </tbody></table>
    -+  </div>
    -+  <div class='jd-tagdata jd-tagdescr'>
    -+<p>  Creates an rs_element object of the specified data type.  The data kind of
    -+ the element will be set to RS_KIND_USER and vector width will be set to 1,
    -+ indicating non-vector.
    -+</p>
    -+  </div>
    -+</div>
    -+
    -+<a name='android_rs:rsCreatePixelElement'></a>
    -+<div class='jd-details'>
    -+  <h4 class='jd-details-title'>
    -+    <span class='sympad'>rsCreatePixelElement</span>
    -+    <span class='normal'>: Creates an <a href={@docRoot}guide/topics/renderscript/reference/rs_object_types.html#android_rs:rs_element>rs_element</a> object of the specified data type and data kind</span>
    -+  </h4>
    -+  <div class='jd-details-descr'>
    -+    <table class='jd-tagtable'><tbody>
    -+      <tr>
    -+        <td><a href='rs_object_types.html#android_rs:rs_element'>rs_element</a> rsCreatePixelElement(<a href='rs_object_types.html#android_rs:rs_data_type'>rs_data_type</a> data_type, <a href='rs_object_types.html#android_rs:rs_data_kind'>rs_data_kind</a> data_kind);
    -+</td>
    -+        <td>    Added in <a href='http://developer.android.com/guide/topics/manifest/uses-sdk-element.html#ApiLevels'>API level 24</a>
    -+        </td>
    -+      </tr>
    -+    </tbody></table>
    -+  </div>
    -+  <div class='jd-tagdata'>    <h5 class='jd-tagtitle'>Parameters</h5>
    -+    <table class='jd-tagtable'><tbody>
    -+    <tr><th>data_type</th><td>Data type of the Element</td></tr>
    -+    <tr><th>data_kind</th><td>Data kind of the Element</td></tr>
    -+    </tbody></table>
    -+  </div>
    -+  <div class='jd-tagdata jd-tagdescr'>
    -+<p>  Creates an rs_element object of the specified data type and data kind. The
    -+ vector width of the rs_element object will be set to 1, indicating non-vector.
    -+</p>
    -+  </div>
    -+</div>
    -+
    -+<a name='android_rs:rsCreateType'></a>
    -+<div class='jd-details'>
    -+  <h4 class='jd-details-title'>
    -+    <span class='sympad'>rsCreateType</span>
    -+    <span class='normal'>: Creates an <a href={@docRoot}guide/topics/renderscript/reference/rs_object_types.html#android_rs:rs_type>rs_type</a> object with the specified <a href={@docRoot}guide/topics/renderscript/reference/rs_object_types.html#android_rs:rs_element>rs_element</a> and shape attributes</span>
    -+  </h4>
    -+  <div class='jd-details-descr'>
    -+    <table class='jd-tagtable'><tbody>
    -+      <tr>
    -+        <td><a href='rs_object_types.html#android_rs:rs_type'>rs_type</a> rsCreateType(<a href='rs_object_types.html#android_rs:rs_element'>rs_element</a> element, <a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimX);
    -+</td>
    -+        <td>    Added in <a href='http://developer.android.com/guide/topics/manifest/uses-sdk-element.html#ApiLevels'>API level 24</a>
    -+        </td>
    -+      </tr>
    -+      <tr>
    -+        <td><a href='rs_object_types.html#android_rs:rs_type'>rs_type</a> rsCreateType(<a href='rs_object_types.html#android_rs:rs_element'>rs_element</a> element, <a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimX, <a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimY);
    -+</td>
    -+        <td>    Added in <a href='http://developer.android.com/guide/topics/manifest/uses-sdk-element.html#ApiLevels'>API level 24</a>
    -+        </td>
    -+      </tr>
    -+      <tr>
    -+        <td><a href='rs_object_types.html#android_rs:rs_type'>rs_type</a> rsCreateType(<a href='rs_object_types.html#android_rs:rs_element'>rs_element</a> element, <a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimX, <a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimY, <a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimZ);
    -+</td>
    -+        <td>    Added in <a href='http://developer.android.com/guide/topics/manifest/uses-sdk-element.html#ApiLevels'>API level 24</a>
    -+        </td>
    -+      </tr>
    -+      <tr>
    -+        <td><a href='rs_object_types.html#android_rs:rs_type'>rs_type</a> rsCreateType(<a href='rs_object_types.html#android_rs:rs_element'>rs_element</a> element, <a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimX, <a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimY, <a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> dimZ, bool mipmaps, bool faces, <a href='rs_object_types.html#android_rs:rs_yuv_format'>rs_yuv_format</a> yuv_format);
    -+</td>
    -+        <td>    Added in <a href='http://developer.android.com/guide/topics/manifest/uses-sdk-element.html#ApiLevels'>API level 24</a>
    -+        </td>
    -+      </tr>
    -+    </tbody></table>
    -+  </div>
    -+  <div class='jd-tagdata'>    <h5 class='jd-tagtitle'>Parameters</h5>
    -+    <table class='jd-tagtable'><tbody>
    -+    <tr><th>element</th><td>An <a href={@docRoot}guide/topics/renderscript/reference/rs_object_types.html#android_rs:rs_element>rs_element</a> object that specifies the cell data type of an allocation.</td></tr>
    -+    <tr><th>dimX</th><td>Size on dimension x. Must be non zero.</td></tr>
    -+    <tr><th>dimY</th><td>Size on dimension y. 0 for single-dimension allocations.</td></tr>
    -+    <tr><th>dimZ</th><td>Size on dimension z. 0 for single-dimension and two-dimension allocations.</td></tr>
    -+    <tr><th>mipmaps</th><td>A boolean flag indicating if the allocation is mipmapped and has multiple levels of detail (LoD).</td></tr>
    -+    <tr><th>faces</th><td>A boolean flag indicating if the allocation is a cubemap that has cube faces.</td></tr>
    -+    <tr><th>yuv_format</th><td>Tye YUV layout.</td></tr>
    -+    </tbody></table>
    -+  </div>
    -+  <div class='jd-tagdata jd-tagdescr'>
    -+<p>  Creates an rs_type object with the specified element and shape attributes.
    -+</p>
    -+
    -+<p>  dimX specifies the size of the X dimension.
    -+</p>
    -+
    -+<p>  dimY, if present and non-zero, indicates that the Y dimension is present and
    -+ indicates its size.
    -+</p>
    -+
    -+<p>  dimZ, if present and non-zero, indicates that the Z dimension is present and
    -+ indicates its size.
    -+</p>
    -+
    -+<p>  mipmaps indicates the presence of level of detail (LOD).
    -+</p>
    -+
    -+<p>  faces indicates the  presence of cubemap faces.
    -+</p>
    -+
    -+<p>  yuv_format indicates the associated YUV format (or RS_YUV_NONE).
    -+</p>
    -+  </div>
    -+</div>
    -+
    -+<a name='android_rs:rsCreateVectorElement'></a>
    -+<div class='jd-details'>
    -+  <h4 class='jd-details-title'>
    -+    <span class='sympad'>rsCreateVectorElement</span>
    -+    <span class='normal'>: Creates an <a href={@docRoot}guide/topics/renderscript/reference/rs_object_types.html#android_rs:rs_element>rs_element</a> object of the specified data type and vector width</span>
    -+  </h4>
    -+  <div class='jd-details-descr'>
    -+    <table class='jd-tagtable'><tbody>
    -+      <tr>
    -+        <td><a href='rs_object_types.html#android_rs:rs_element'>rs_element</a> rsCreateVectorElement(<a href='rs_object_types.html#android_rs:rs_data_type'>rs_data_type</a> data_type, <a href='rs_value_types.html#android_rs:uint32_t'>uint32_t</a> vector_width);
    -+</td>
    -+        <td>    Added in <a href='http://developer.android.com/guide/topics/manifest/uses-sdk-element.html#ApiLevels'>API level 24</a>
    -+        </td>
    -+      </tr>
    -+    </tbody></table>
    -+  </div>
    -+  <div class='jd-tagdata'>    <h5 class='jd-tagtitle'>Parameters</h5>
    -+    <table class='jd-tagtable'><tbody>
    -+    <tr><th>data_type</th><td>Data type of the Element</td></tr>
    -+    <tr><th>vector_width</th><td>Vector width</td></tr>
    -+    </tbody></table>
    -+  </div>
    -+  <div class='jd-tagdata jd-tagdescr'>
    -+<p>  Creates an rs_element object of the specified data type and vector width.
    -+ Value of vector_width must be 2, 3 or 4.  The data kind of the rs_element object will
    -+ be set to RS_KIND_USER.
    -+</p>
    -+  </div>
    -+</div>
    -+
    -+</div>
    -diff --git a/docs/html/guide/topics/renderscript/reference/rs_for_each.jd b/docs/html/guide/topics/renderscript/reference/rs_for_each.jd
    -index 9ba5614..8b19ba6 100644
    ---- a/docs/html/guide/topics/renderscript/reference/rs_for_each.jd
    -+++ b/docs/html/guide/topics/renderscript/reference/rs_for_each.jd
    -@@ -1,10 +1,10 @@
    --page.title=RenderScript Kernel Invocation Functions and Types
    -+page.title=RenderScript Kernel Launch Functions and Types
    - 
    - @jd:body
    - 
    - <div class='renderscript'>
    - <h2>Overview</h2>
    --<p> The <a href='rs_for_each.html#android_rs:rsForEach'>rsForEach</a>() function can be used to invoke the root kernel of a script.
    -+<p> The <a href='rs_for_each.html#android_rs:rsForEach'>rsForEach</a>() and <a href='rs_for_each.html#android_rs:rsForEachWithOptions'>rsForEachWithOptions</a>() functions are used to launch foreach kernels.
    - </p>
    - 
    - <p> The other functions are used to get the characteristics of the invocation of
    -@@ -24,6 +24,14 @@ a <a href='rs_for_each.html#android_rs:rs_kernel_context'>rs_kernel_context</a>
    -   </tr>
    -   <tr class='alt-color api apilevel-1'>
    -     <td class='jd-linkcol'>
    -+      <a href='rs_for_each.html#android_rs:rs_kernel'>rs_kernel</a>
    -+    </td>
    -+    <td class='jd-descrcol' width='100%'>
    -+      Handle to a kernel function
    -+    </td>
    -+  </tr>
    -+  <tr class='alt-color api apilevel-1'>
    -+    <td class='jd-linkcol'>
    -       <a href='rs_for_each.html#android_rs:rs_kernel_context'>rs_kernel_context</a>
    -     </td>
    -     <td class='jd-descrcol' width='100%'>
    -@@ -46,7 +54,15 @@ a <a href='rs_for_each.html#android_rs:rs_kernel_context'>rs_kernel_context</a>
    -       <a href='rs_for_each.html#android_rs:rsForEach'>rsForEach</a>
    -     </td>
    -     <td class='jd-descrcol' width='100%'>
    --      Invoke the root kernel of a script
    -+      Launches a kernel
    -+    </td>
    -+  </tr>
    -+  <tr class='alt-color api apilevel-1'>
    -+    <td class='jd-linkcol'>
    -+      <a href='rs_for_each.html#android_rs:rsForEachWithOptions'>rsForEachWithOptions</a>
    -+    </td>
    -+    <td class='jd-descrcol' width='100%'>
    -+      Launches a kernel with options
    -     </td>
    -   </tr>
    -   <tr class='alt-color api apilevel-1'>
    -@@ -198,6 +214,21 @@ locality when the processing is distributed over multiple cores.
    -   </div>
    - </div>
    - 
    -+<a name='android_rs:rs_kernel'></a>
    -+<div class='jd-details'>
    -+  <h4 class='jd-details-title'>
    -+    <span class='sympad'>rs_kernel</span>
    -+    <span class='normal'>: Handle to a kernel function</span>
    -+  </h4>
    -+  <div class='jd-details-descr'>
    -+<p>A typedef of: void*&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Added in <a href='http://developer.android.com/guide/topics/manifest/uses-sdk-element.html#ApiLevels'>API level 24</a>
    -+</p>
    -+<p>  An opaque type for a function that is defined with the kernel attribute.  A value
    -+ of this type can be used in a <a href='rs_for_each.html#android_rs:rsForEach'>rsForEach</a> call to launch a kernel.
    -+</p>
    -+  </div>
    -+</div>
    -+
    - <a name='android_rs:rs_kernel_context'></a>
    - <div class='jd-details'>
    -   <h4 class='jd-details-title'>
    -@@ -249,7 +280,7 @@ versions, it will also be used to provide hint on how to best iterate over
    - the cells.
    - </p>
    - 
    --<p> The Start fields are inclusive and the End fields are exclusive.  E.g. to iterate
    -+<p> The Start fields are inclusive and the End fields are exclusive.  For example, to iterate
    - over cells 4, 5, 6, and 7 in the X dimension, set xStart to 4 and xEnd to 8.
    - </p>
    -   </div>
    -@@ -260,14 +291,20 @@ over cells 4, 5, 6, and 7 in the X dimension, set xStart to 4 and xEnd to 8.
    - <div class='jd-details'>
    -   <h4 class='jd-details-title'>
    -     <span class='sympad'>rsForEach</span>
    --    <span class='normal'>: Invoke the root kernel of a script</span>
    -+    <span class='normal'>: Launches a kernel</span>
    -   </h4>
    -   <div class='jd-details-descr'>
    -     <table class='jd-tagtable'><tbody>
    -       <tr>
    -+        <td>void rsForEach(<a href='rs_for_each.html#android_rs:rs_kernel'>rs_kernel</a> kernel, ... ...);
    -+</td>
    -+        <td>    Added in <a href='http://developer.android.com/guide/topics/manifest/uses-sdk-element.html#ApiLevels'>API level 24</a>
    -+        </td>
    -+      </tr>
    -+      <tr>
    -         <td>void rsForEach(<a href='rs_object_types.html#android_rs:rs_script'>rs_script</a> script, <a href='rs_object_types.html#android_rs:rs_allocation'>rs_allocation</a> input, <a href='rs_object_types.html#android_rs:rs_allocation'>rs_allocation</a> output);
    - </td>
    --        <td>    Added in <a href='http://developer.android.com/guide/topics/manifest/uses-sdk-element.html#ApiLevels'>API level 14</a>
    -+        <td>    <a href='http://developer.android.com/guide/topics/manifest/uses-sdk-element.html#ApiLevels'>API level 14 - 23</a>
    -         </td>
    -       </tr>
    -       <tr>
    -@@ -300,35 +337,89 @@ over cells 4, 5, 6, and 7 in the X dimension, set xStart to 4 and xEnd to 8.
    -     <table class='jd-tagtable'><tbody>
    -     <tr><th>script</th><td>Script to call.</td></tr>
    -     <tr><th>input</th><td>Allocation to source data from.</td></tr>
    --    <tr><th>output</th><td>Allocation to write date into.</td></tr>
    -+    <tr><th>output</th><td>Allocation to write data into.</td></tr>
    -     <tr><th>usrData</th><td>User defined data to pass to the script.  May be NULL.</td></tr>
    -     <tr><th>sc</th><td>Extra control information used to select a sub-region of the allocation to be processed or suggest a walking strategy.  May be NULL.</td></tr>
    -     <tr><th>usrDataLen</th><td>Size of the userData structure.  This will be used to perform a shallow copy of the data if necessary.</td></tr>
    -+    <tr><th>kernel</th><td>Function designator of the kernel function to call, which must be defined with the kernel attribute.</td></tr>
    -+    <tr><th>...</th><td>Input and output allocations</td></tr>
    -     </tbody></table>
    -   </div>
    -   <div class='jd-tagdata jd-tagdescr'>
    --<p> Invoke the kernel named "root" of the specified script.  Like other kernels, this root()
    --function will be invoked repeatedly over the cells of the specificed allocation, filling
    --the output allocation with the results.
    -+<p> Runs the kernel over zero or more input allocations. They are passed after the
    -+<a href='rs_for_each.html#android_rs:rs_kernel'>rs_kernel</a> argument. If the specified kernel returns a value, an output allocation
    -+must be specified as the last argument. All input allocations,
    -+and the output allocation if it exists, must have the same dimensions.
    - </p>
    - 
    --<p> When rsForEach is called, the root script is launched immediately.  rsForEach returns
    --only when the script has completed and the output allocation is ready to use.
    -+<p> This is a synchronous function. A call to this function only returns after all
    -+the work has completed. If the kernel
    -+function returns any value, the call waits until all results have been written
    -+to the output allocation.
    - </p>
    - 
    --<p> The rs_script argument is typically initialized using a global variable set from Java.
    -+<p> Up to API level 23, the kernel is implicitly specified as the kernel named
    -+"root" in the specified script, and only a single input allocation can be used.
    -+Starting in API level 24, an arbitrary kernel function can be used,
    -+as specified by the kernel argument.
    -+The kernel must be defined in the current script. In addition, more than one
    -+input can be used.
    - </p>
    - 
    --<p> The kernel can be invoked with just an input allocation or just an output allocation.
    --This can be done by defining an rs_allocation variable and not initializing it.  E.g.<code><br/>
    --rs_script gCustomScript;<br/>
    --void specializedProcessing(rs_allocation in) {<br/>
    --&nbsp;&nbsp;rs_allocation ignoredOut;<br/>
    --&nbsp;&nbsp;rsForEach(gCustomScript, in, ignoredOut);<br/>
    --}<br/></code>
    -+<p> For example,<code><br/>
    -+float __attribute__((kernel)) square(float a) {<br/>
    -+&nbsp;&nbsp;return a * a;<br/>
    -+}<br/>
    -+<br/>
    -+void compute(rs_allocation ain, rs_allocation aout) {<br/>
    -+&nbsp;&nbsp;rsForEach(square, ain, aout);<br/>
    -+}<br/>
    -+<br/></code>
    -+</p>
    -+  </div>
    -+</div>
    -+
    -+<a name='android_rs:rsForEachWithOptions'></a>
    -+<div class='jd-details'>
    -+  <h4 class='jd-details-title'>
    -+    <span class='sympad'>rsForEachWithOptions</span>
    -+    <span class='normal'>: Launches a kernel with options</span>
    -+  </h4>
    -+  <div class='jd-details-descr'>
    -+    <table class='jd-tagtable'><tbody>
    -+      <tr>
    -+        <td>void rsForEachWithOptions(<a href='rs_for_each.html#android_rs:rs_kernel'>rs_kernel</a> kernel, <a href='rs_for_each.html#android_rs:rs_script_call_t'>rs_script_call_t</a>* options, ... ...);
    -+</td>
    -+        <td>    Added in <a href='http://developer.android.com/guide/topics/manifest/uses-sdk-element.html#ApiLevels'>API level 24</a>
    -+        </td>
    -+      </tr>
    -+    </tbody></table>
    -+  </div>
    -+  <div class='jd-tagdata'>    <h5 class='jd-tagtitle'>Parameters</h5>
    -+    <table class='jd-tagtable'><tbody>
    -+    <tr><th>kernel</th><td>Function designator to a function that is defined with the kernel attribute.</td></tr>
    -+    <tr><th>options</th><td>Launch options</td></tr>
    -+    <tr><th>...</th><td>Input and output allocations</td></tr>
    -+    </tbody></table>
    -+  </div>
    -+  <div class='jd-tagdata jd-tagdescr'>
    -+<p> Launches kernel in a way similar to <a href='rs_for_each.html#android_rs:rsForEach'>rsForEach</a>. However, instead of processing
    -+all cells in the input, this function only processes cells in the subspace of
    -+the index space specified in options. With the index space explicitly specified
    -+by options, no input or output allocation is required for a kernel launch using
    -+this API. If allocations are passed in, they must match the number of arguments
    -+and return value expected by the kernel function. The output allocation is
    -+present if and only if the kernel has a non-void return value.
    - </p>
    - 
    --<p> If both input and output allocations are specified, they must have the same dimensions.
    -+<p> For example,<code><br/>
    -+   rs_script_call_t opts = {0};<br/>
    -+   opts.xStart = 0;<br/>
    -+   opts.xEnd = dimX;<br/>
    -+   opts.yStart = 0;<br/>
    -+   opts.yEnd = dimY / 2;<br/>
    -+   rsForEachWithOptions(foo, &opts, out, out);<br/>
    -+</code>
    - </p>
    -   </div>
    - </div>
    -@@ -359,7 +450,7 @@ over and rarely used indices, like the Array0 index.
    - </p>
    - 
    - <p> You can access the kernel context by adding a special parameter named "context" of
    --type rs_kernel_context to your kernel function.  E.g.<br/>
    -+type rs_kernel_context to your kernel function.  For example,<br/>
    - <code>short RS_KERNEL myKernel(short value, uint32_t x, rs_kernel_context context) {<br/>
    - &nbsp;&nbsp;// The current index in the common x, y, z dimensions are accessed by<br/>
    - &nbsp;&nbsp;// adding these variables as arguments.  For the more rarely used indices<br/>
    -@@ -644,7 +735,7 @@ over and rarely used indices, like the Array0 index.
    - </p>
    - 
    - <p> You can access it by adding a special parameter named "context" of
    --type rs_kernel_context to your kernel function.  E.g.<br/>
    -+type rs_kernel_context to your kernel function.  For example,<br/>
    - <code>int4 RS_KERNEL myKernel(int4 value, rs_kernel_context context) {<br/>
    - &nbsp;&nbsp;uint32_t size = rsGetDimX(context); //...<br/></code>
    - </p>
    -diff --git a/docs/html/guide/topics/resources/drawable-resource.jd b/docs/html/guide/topics/resources/drawable-resource.jd
    -index aae0cba..4587ae4 100644
    ---- a/docs/html/guide/topics/resources/drawable-resource.jd
    -+++ b/docs/html/guide/topics/resources/drawable-resource.jd
    -@@ -1270,7 +1270,7 @@ the right edge, a right gravity clips the left edge, and neither clips both edge
    - progressively reveal the image:</p>
    - <pre>
    - ImageView imageview = (ImageView) findViewById(R.id.image);
    --ClipDrawable drawable = (ClipDrawable) imageview.getDrawable();
    -+ClipDrawable drawable = (ClipDrawable) imageview.getBackground();
    - drawable.setLevel(drawable.getLevel() + 1000);
    - </pre>
    - 
    -diff --git a/docs/html/guide/topics/resources/multilingual-support.jd b/docs/html/guide/topics/resources/multilingual-support.jd
    -index 8d8484b..28699fe 100644
    ---- a/docs/html/guide/topics/resources/multilingual-support.jd
    -+++ b/docs/html/guide/topics/resources/multilingual-support.jd
    -@@ -88,15 +88,17 @@ today.</p>
    - 
    - <h2 id="postN">Improvements to Resource-Resolution Strategy</h2>
    - <p>Android 7.0 (API level 24) brings more robust resource resolution, and
    -- finds better fallbacks automatically. However, to speed up resolution and
    -- improve
    -+ finds better fallbacks automatically.
    -+ However, to speed up resolution and improve
    -  maintainability, you should store resources in the most common parent dialect.
    -- For example, if you were storing Spanish resources in the {@code es-US}
    -- directory
    -- before, move them into the {@code es-419} directory, which contains Latin
    -- American Spanish.
    -- Similarly, if you have resource strings in a folder named {@code en-GB}, rename
    -- the folder to {@code en-001} (international English), because the most common
    -+ For example, if you were storing Spanish resources
    -+ in the {@code values-es-rUS} directory
    -+ before, move them into the {@code values-b+es+419} directory,
    -+ which contains Latin American Spanish.
    -+ Similarly, if you have resource strings in a
    -+ directory named {@code values-en-rGB}, rename
    -+ the directory to {@code values-b+en+001} (International
    -+ English), because the most common
    -  parent for <code>en-GB</code> strings is {@code en-001}.
    -  The following examples explain why these practices improve performance and
    - reliability of resource resolution.</p>
    -diff --git a/docs/html/guide/topics/search/search-dialog.jd b/docs/html/guide/topics/search/search-dialog.jd
    -index 8278ab1..4d6b400 100644
    ---- a/docs/html/guide/topics/search/search-dialog.jd
    -+++ b/docs/html/guide/topics/search/search-dialog.jd
    -@@ -699,7 +699,7 @@ public boolean onCreateOptionsMenu(Menu menu) {
    -     inflater.inflate(R.menu.options_menu, menu);
    - 
    -     // Get the SearchView and set the searchable configuration
    --    SearchManager searchManager = (SearchManager) {@link android.app.Activity#getSystemService(java.lang.String) getSystemService()}(Context.SEARCH_SERVICE);
    -+    SearchManager searchManager = (SearchManager) {@link android.app.Activity#getSystemService getSystemService}(Context.SEARCH_SERVICE);
    -     SearchView searchView = (SearchView) menu.findItem(R.id.menu_search).getActionView();
    -     // Assumes current activity is the searchable activity
    -     searchView.setSearchableInfo(searchManager.getSearchableInfo({@link android.app.Activity#getComponentName()}));
    -diff --git a/docs/html/guide/topics/ui/accessibility/apps.jd b/docs/html/guide/topics/ui/accessibility/apps.jd
    -index c415762..ab8c792 100644
    ---- a/docs/html/guide/topics/ui/accessibility/apps.jd
    -+++ b/docs/html/guide/topics/ui/accessibility/apps.jd
    -@@ -298,7 +298,7 @@ then the {@link android.view.View#dispatchPopulateAccessibilityEvent
    - dispatchPopulateAccessibilityEvent()} method for each child of this view. In order to support
    - accessibility services on revisions of Android <em>prior</em> to 4.0 (API Level 14) you
    - <em>must</em> override this method and populate {@link
    --android.view.accessibility.AccessibilityRecord#getText} with descriptive text for your custom
    -+android.view.accessibility.AccessibilityEvent#getText} with descriptive text for your custom
    - view, which is spoken by accessibility services, such as TalkBack.</dd>
    - 
    -   <dt>{@link android.view.View#onPopulateAccessibilityEvent onPopulateAccessibilityEvent()}</dt>
    -diff --git a/docs/html/guide/topics/ui/accessibility/services.jd b/docs/html/guide/topics/ui/accessibility/services.jd
    -index d08022e..dbc69ef 100644
    ---- a/docs/html/guide/topics/ui/accessibility/services.jd
    -+++ b/docs/html/guide/topics/ui/accessibility/services.jd
    -@@ -79,22 +79,15 @@ must also request the {@link android.Manifest.permission#BIND_ACCESSIBILITY_SERV
    - as shown in the following sample:</p>
    - 
    - <pre>
    --&lt;manifest&gt;
    --  ...
    --  &lt;uses-permission ... /&gt;
    --  ...
    -   &lt;application&gt;
    --    ...
    -     &lt;service android:name=&quot;.MyAccessibilityService&quot;
    --        android:label=&quot;@string/accessibility_service_label&quot;
    --        android:permission=&quot;android.permission.BIND_ACCESSIBILITY_SERVICE&quot&gt;
    -+        android:permission="android.permission.BIND_ACCESSIBILITY_SERVICE"
    -+        android:label=&quot;@string/accessibility_service_label&quot;&gt;
    -       &lt;intent-filter&gt;
    -         &lt;action android:name=&quot;android.accessibilityservice.AccessibilityService&quot; /&gt;
    -       &lt;/intent-filter&gt;
    -     &lt;/service&gt;
    --    &lt;uses-permission android:name="android.permission.BIND_ACCESSIBILITY_SERVICE" /&gt;
    -   &lt;/application&gt;
    --&lt;/manifest&gt;
    - </pre>
    - 
    - <p>These declarations are required for all accessibility services deployed on Android 1.6 (API Level
    -@@ -205,7 +198,7 @@ from when the service is started
    - while it is running ({@link android.accessibilityservice.AccessibilityService#onAccessibilityEvent
    - onAccessibilityEvent()},
    - {@link android.accessibilityservice.AccessibilityService#onInterrupt onInterrupt()}) to when it is
    --shut down ({@link android.app.Service#onUnbind onUnbind()}).</p>
    -+shut down ({@link android.accessibilityservice.AccessibilityService#onUnbind onUnbind()}).</p>
    - 
    - <ul>
    -   <li>{@link android.accessibilityservice.AccessibilityService#onServiceConnected
    -@@ -231,7 +224,7 @@ service.</li>
    - providing, usually in response to a user action such as moving focus to a different control. This
    - method may be called many times over the lifecycle of your service.</li>
    - 
    --  <li>{@link android.app.Service#onUnbind onUnbind()} - (optional)
    -+  <li>{@link android.accessibilityservice.AccessibilityService#onUnbind onUnbind()} - (optional)
    - This method is called when the system is about to shutdown the accessibility service. Use this
    - method to do any one-time shutdown procedures, including de-allocating user feedback system
    - services, such as the audio manager or device vibrator.</li>
    -@@ -283,7 +276,7 @@ retrieve the set of {@link android.view.accessibility.AccessibilityRecord} objec
    - to the {@link android.view.accessibility.AccessibilityEvent} passed to you by the system. This level
    - of detail provides more context for the event that triggered your accessibility service.</li>
    - 
    --  <li>{@link android.view.accessibility.AccessibilityRecord#getSource
    -+  <li>{@link android.view.accessibility.AccessibilityEvent#getSource
    - AccessibilityEvent.getSource()} - This method returns an {@link
    - android.view.accessibility.AccessibilityNodeInfo} object. This object allows you to request view
    - layout hierarchy (parents and children) of the component that originated the accessibility event.
    -@@ -296,10 +289,10 @@ user information to your accessibility service. For this reason, your service mu
    - level of access through the accessibility <a href="#service-config">service configuration XML</a>
    - file, by including the {@code canRetrieveWindowContent} attribute and setting it to {@code true}. If
    - you do not include this setting in your service configuration xml file, calls to {@link
    --android.view.accessibility.AccessibilityRecord#getSource getSource()} fail.</p>
    -+android.view.accessibility.AccessibilityEvent#getSource getSource()} fail.</p>
    - 
    - <p class="note"><strong>Note:</strong> In Android 4.1 (API Level 16) and higher, the
    --{@link android.view.accessibility.AccessibilityRecord#getSource getSource()} method,
    -+{@link android.view.accessibility.AccessibilityEvent#getSource getSource()} method,
    - as well as {@link android.view.accessibility.AccessibilityNodeInfo#getChild
    - AccessibilityNodeInfo.getChild()} and
    - {@link android.view.accessibility.AccessibilityNodeInfo#getParent getParent()}, return only
    -@@ -372,7 +365,7 @@ public class MyAccessibilityService extends AccessibilityService {
    -   <a href="#service-config">service configuration file</a>. When events are received by your
    -   service, it can then retrieve the
    -   {@link android.view.accessibility.AccessibilityNodeInfo} object from the event using
    --  {@link android.view.accessibility.AccessibilityRecord#getSource getSource()}.
    -+  {@link android.view.accessibility.AccessibilityEvent#getSource getSource()}.
    -   With the {@link android.view.accessibility.AccessibilityNodeInfo} object, your service can then
    -   explore the view hierarchy to determine what action to take and then act for the user using
    -   {@link android.view.accessibility.AccessibilityNodeInfo#performAction performAction()}.</p>
    -diff --git a/docs/html/guide/topics/ui/controls/togglebutton.jd b/docs/html/guide/topics/ui/controls/togglebutton.jd
    -index e0549ec..181647c 100644
    ---- a/docs/html/guide/topics/ui/controls/togglebutton.jd
    -+++ b/docs/html/guide/topics/ui/controls/togglebutton.jd
    -@@ -14,6 +14,7 @@ page.tags=switch,togglebutton
    -   <ol>
    -     <li>{@link android.widget.ToggleButton}</li>
    -     <li>{@link android.widget.Switch}</li>
    -+    <li>{@link android.support.v7.widget.SwitchCompat}</li>
    -     <li>{@link android.widget.CompoundButton}</li>
    -   </ol>
    - </div>
    -@@ -21,9 +22,12 @@ page.tags=switch,togglebutton
    - 
    - <p>A toggle button allows the user to change a setting between two states.</p>
    - 
    --<p>You can add a basic toggle button to your layout with the {@link android.widget.ToggleButton}
    --object. Android 4.0 (API level 14) introduces another kind of toggle button called a switch that
    --provides a slider control, which you can add with a {@link android.widget.Switch} object.</p>
    -+<p>You can add a basic toggle button to your layout with the
    -+{@link android.widget.ToggleButton} object. Android 4.0 (API level 14)
    -+introduces another kind of toggle button called a switch that provides a slider
    -+control, which you can add with a {@link android.widget.Switch} object.
    -+{@link android.support.v7.widget.SwitchCompat} is a version of the Switch
    -+widget which runs on devices back to API 7.</p>
    - 
    - <p>
    -   If you need to change a button's state yourself, you can use the {@link
    -diff --git a/docs/html/guide/topics/ui/declaring-layout.jd b/docs/html/guide/topics/ui/declaring-layout.jd
    -index ecdcfdc..bf0db57 100755
    ---- a/docs/html/guide/topics/ui/declaring-layout.jd
    -+++ b/docs/html/guide/topics/ui/declaring-layout.jd
    -@@ -423,7 +423,7 @@ ArrayAdapter&lt;String> adapter = new ArrayAdapter&lt;String>(this,
    -   <li>The string array</li>
    - </ul>
    - <p>Then simply call
    --{@link android.widget.AdapterView#setAdapter setAdapter()} on your {@link android.widget.ListView}:</p>
    -+{@link android.widget.ListView#setAdapter setAdapter()} on your {@link android.widget.ListView}:</p>
    - <pre>
    - ListView listView = (ListView) findViewById(R.id.listview);
    - listView.setAdapter(adapter);
    -diff --git a/docs/html/guide/topics/ui/dialogs.jd b/docs/html/guide/topics/ui/dialogs.jd
    -index 52cd1a0..7ab4ca5 100644
    ---- a/docs/html/guide/topics/ui/dialogs.jd
    -+++ b/docs/html/guide/topics/ui/dialogs.jd
    -@@ -643,7 +643,7 @@ android.support.v4.app.Fragment}.</p>
    - or other {@link android.app.Dialog} objects to build the dialog in this case. If
    - you want the {@link android.support.v4.app.DialogFragment} to be
    - embeddable, you must define the dialog's UI in a layout, then load the layout in the
    --{@link android.support.v4.app.Fragment#onCreateView
    -+{@link android.support.v4.app.DialogFragment#onCreateView
    - onCreateView()} callback.</p>
    - 
    - <p>Here's an example {@link android.support.v4.app.DialogFragment} that can appear as either a
    -diff --git a/docs/html/guide/topics/ui/drag-drop.jd b/docs/html/guide/topics/ui/drag-drop.jd
    -index 8871c87..8e4297f 100644
    ---- a/docs/html/guide/topics/ui/drag-drop.jd
    -+++ b/docs/html/guide/topics/ui/drag-drop.jd
    -@@ -152,7 +152,7 @@ DraggableDot.java</a> in <a href="{@docRoot}resources/samples/ApiDemos/index.htm
    -     drag event listeners or callback methods of each View in the layout. The listeners or callback
    -     methods can use the metadata to decide if they want to accept the data when it is dropped.
    -     If the user drops the data over a View object, and that View object's listener or callback
    --    method has previously told the system that it wants to accept the drop, then the system sends
    -+    method has previously told the system that it wants to accept the data, then the system sends
    -     the data to the listener or callback method in a drag event.
    - </p>
    - <p>
    -@@ -226,7 +226,8 @@ DraggableDot.java</a> in <a href="{@docRoot}resources/samples/ApiDemos/index.htm
    -     </dt>
    -     <dd>
    -         The user releases the drag shadow within the bounding box of a View that can accept the
    --        data. The system sends the View object's listener a drag event with action type
    -+        data, but not within its descendant view that can accept the data. The system sends the View
    -+        object's listener a drag event with action type
    -         {@link android.view.DragEvent#ACTION_DROP}. The drag event contains the data that was
    -         passed to the system in the call to
    -         {@link android.view.View#startDrag(ClipData,View.DragShadowBuilder,Object,int) startDrag()}
    -@@ -317,6 +318,10 @@ DraggableDot.java</a> in <a href="{@docRoot}resources/samples/ApiDemos/index.htm
    -             application calls
    - {@link android.view.View#startDrag(ClipData,View.DragShadowBuilder,Object,int) startDrag()} and
    -             gets a drag shadow.
    -+            <p>
    -+                If the listener wants to continue receiving drag events for this operation, it must
    -+                return boolean <code>true</code> to the system.
    -+            </p>
    -         </td>
    -     </tr>
    -     <tr>
    -@@ -324,9 +329,7 @@ DraggableDot.java</a> in <a href="{@docRoot}resources/samples/ApiDemos/index.htm
    -         <td>
    -             A View object's drag event listener receives this event action type when the drag shadow
    -             has just entered the bounding box of the View. This is the first event action type the
    --            listener receives when the drag shadow enters the bounding box. If the listener wants to
    --            continue receiving drag events for this operation, it must return boolean
    --            <code>true</code> to the system.
    -+            listener receives when the drag shadow enters the bounding box.
    -         </td>
    -     </tr>
    -     <tr>
    -@@ -334,7 +337,8 @@ DraggableDot.java</a> in <a href="{@docRoot}resources/samples/ApiDemos/index.htm
    -         <td>
    -             A View object's drag event listener receives this event action type after it receives a
    -             {@link android.view.DragEvent#ACTION_DRAG_ENTERED} event while the drag shadow is
    --            still within the bounding box of the View.
    -+            still within the bounding box of the View and not within a descendant view that can
    -+            accept the data.
    -         </td>
    -     </tr>
    -     <tr>
    -@@ -343,7 +347,8 @@ DraggableDot.java</a> in <a href="{@docRoot}resources/samples/ApiDemos/index.htm
    -             A View object's drag event listener receives this event action type after it receives a
    -             {@link android.view.DragEvent#ACTION_DRAG_ENTERED} and at least one
    -             {@link android.view.DragEvent#ACTION_DRAG_LOCATION} event, and after the user has moved
    --            the drag shadow outside the bounding box of the View.
    -+            the drag shadow outside the bounding box of the View or into a descendant view that can
    -+            accept the data.
    -         </td>
    -     </tr>
    -     <tr>
    -@@ -395,7 +400,7 @@ DraggableDot.java</a> in <a href="{@docRoot}resources/samples/ApiDemos/index.htm
    -         <td style="text-align: center;">X</td>
    -         <td style="text-align: center;">X</td>
    -         <td style="text-align: center;">X</td>
    --        <td style="text-align: center;">&nbsp;</td>
    -+        <td style="text-align: center;">X</td>
    -         <td style="text-align: center;">&nbsp;</td>
    -         <td style="text-align: center;">&nbsp;</td>
    -     </tr>
    -@@ -711,8 +716,7 @@ imageView.setOnLongClickListener(new View.OnLongClickListener() {
    -         If the listener can accept a drop, it should return <code>true</code>. This tells
    -         the system to continue to send drag events to the listener.
    -         If it can't accept a drop, it should return <code>false</code>, and the system
    --        will stop sending drag events until it sends out
    --        {@link android.view.DragEvent#ACTION_DRAG_ENDED}.
    -+        will stop sending drag events for the current drag operation.
    -     </li>
    - </ol>
    - <p>
    -@@ -754,7 +758,8 @@ imageView.setOnLongClickListener(new View.OnLongClickListener() {
    -     <li>
    -         {@link android.view.DragEvent#ACTION_DRAG_EXITED}:  This event is sent to a listener that
    -         previously received {@link android.view.DragEvent#ACTION_DRAG_ENTERED}, after
    --        the drag shadow is no longer within the bounding box of the listener's View.
    -+        the drag shadow is no longer within the bounding box of the listener's View or it's within
    -+        the bounding box of a descendant view that can accept the data.
    -     </li>
    - </ul>
    - <p>
    -diff --git a/docs/html/guide/topics/ui/layout/gridview.jd b/docs/html/guide/topics/ui/layout/gridview.jd
    -index 4ed6ff5..13467ae 100644
    ---- a/docs/html/guide/topics/ui/layout/gridview.jd
    -+++ b/docs/html/guide/topics/ui/layout/gridview.jd
    -@@ -81,7 +81,7 @@ public void onCreate(Bundle savedInstanceState) {
    -   <p>After the {@code main.xml} layout is set for the content view, the
    - {@link android.widget.GridView} is captured from the layout with {@link
    - android.app.Activity#findViewById(int)}. The {@link
    --android.widget.AdapterView#setAdapter(T) setAdapter()} method then sets a custom adapter ({@code
    -+android.widget.GridView#setAdapter(T) setAdapter()} method then sets a custom adapter ({@code
    - ImageAdapter}) as the source for all items to be displayed in the grid. The {@code ImageAdapter} is
    - created in the next step.</p>
    - <p>To do something when an item in the grid is clicked, the {@link
    -@@ -170,7 +170,7 @@ the height and width for the View&mdash;this ensures that, no matter the size of
    - image is resized and cropped to fit in these dimensions, as appropriate.</li>
    -   <li>{@link android.widget.ImageView#setScaleType(ImageView.ScaleType)} declares that images should
    - be cropped toward the center (if necessary).</li>
    --  <li>{@link android.view.View#setPadding(int,int,int,int)} defines the padding for all
    -+  <li>{@link android.widget.ImageView#setPadding(int,int,int,int)} defines the padding for all
    - sides. (Note that, if the images have different aspect-ratios, then less
    - padding will cause more cropping of the image if it does not match
    - the dimensions given to the ImageView.)</li>
    -diff --git a/docs/html/guide/topics/ui/menus.jd b/docs/html/guide/topics/ui/menus.jd
    -index 38f6e21..3325c0e 100644
    ---- a/docs/html/guide/topics/ui/menus.jd
    -+++ b/docs/html/guide/topics/ui/menus.jd
    -@@ -682,7 +682,7 @@ listView.setMultiChoiceModeListener(new MultiChoiceModeListener() {
    - </pre>
    - 
    - <p>That's it. Now when the user selects an item with a long-click, the system calls the {@link
    --android.view.ActionMode.Callback#onCreateActionMode onCreateActionMode()}
    -+android.widget.AbsListView.MultiChoiceModeListener#onCreateActionMode onCreateActionMode()}
    - method and displays the contextual action bar with the specified actions. While the contextual
    - action bar is visible, users can select additional items.</p>
    - 
    -diff --git a/docs/html/guide/topics/ui/multi-window.jd b/docs/html/guide/topics/ui/multi-window.jd
    -index dede557..bab582d 100644
    ---- a/docs/html/guide/topics/ui/multi-window.jd
    -+++ b/docs/html/guide/topics/ui/multi-window.jd
    -@@ -215,7 +215,7 @@ android:resizeableActivity=["true" | "false"]
    -   Set this attribute in your manifest's <a href=
    -   "{@docRoot}guide/topics/manifest/activity-element"><code>&lt;activity&gt;</code></a>
    -   node to indicate whether the activity supports <a href=
    --  "{@docRoot}training/tv/playback/picture-in-picture.jd">Picture-in-Picture</a>
    -+  "{@docRoot}training/tv/playback/picture-in-picture.html">Picture-in-Picture</a>
    -   display. This attribute is ignored if <code>android:resizeableActivity</code>
    -   is false.
    - </p>
    -diff --git a/docs/html/images/brand/android_logo_no.png b/docs/html/images/brand/android_logo_no.png
    -index 8de22d8..946bc49 100644
    -Binary files a/docs/html/images/brand/android_logo_no.png and b/docs/html/images/brand/android_logo_no.png differ
    -diff --git a/docs/html/images/brand/android_logo_no_2x.png b/docs/html/images/brand/android_logo_no_2x.png
    -new file mode 100644
    -index 0000000..8434c79
    -Binary files /dev/null and b/docs/html/images/brand/android_logo_no_2x.png differ
    -diff --git a/docs/html/images/cards/distribute/stories/animoca.jpg b/docs/html/images/cards/distribute/stories/animoca.jpg
    -new file mode 100644
    -index 0000000..1886bce
    -Binary files /dev/null and b/docs/html/images/cards/distribute/stories/animoca.jpg differ
    -diff --git a/docs/html/images/cards/distribute/stories/drupe.jpg b/docs/html/images/cards/distribute/stories/drupe.jpg
    -new file mode 100644
    -index 0000000..5295695
    -Binary files /dev/null and b/docs/html/images/cards/distribute/stories/drupe.jpg differ
    -diff --git a/docs/html/images/cards/distribute/stories/economist-espresso.png b/docs/html/images/cards/distribute/stories/economist-espresso.png
    -new file mode 100644
    -index 0000000..923bf57
    -Binary files /dev/null and b/docs/html/images/cards/distribute/stories/economist-espresso.png differ
    -diff --git a/docs/html/images/cards/distribute/stories/expressen-sport.png b/docs/html/images/cards/distribute/stories/expressen-sport.png
    -new file mode 100644
    -index 0000000..842ed3d
    -Binary files /dev/null and b/docs/html/images/cards/distribute/stories/expressen-sport.png differ
    -diff --git a/docs/html/images/cards/distribute/stories/glamour.png b/docs/html/images/cards/distribute/stories/glamour.png
    -new file mode 100644
    -index 0000000..770b03f
    -Binary files /dev/null and b/docs/html/images/cards/distribute/stories/glamour.png differ
    -diff --git a/docs/html/images/cards/distribute/stories/happylabs-logo.png b/docs/html/images/cards/distribute/stories/happylabs-logo.png
    -new file mode 100644
    -index 0000000..ea20e71
    -Binary files /dev/null and b/docs/html/images/cards/distribute/stories/happylabs-logo.png differ
    -diff --git a/docs/html/images/cards/distribute/stories/lifesum.png b/docs/html/images/cards/distribute/stories/lifesum.png
    -new file mode 100644
    -index 0000000..3975ff2
    -Binary files /dev/null and b/docs/html/images/cards/distribute/stories/lifesum.png differ
    -diff --git a/docs/html/images/cards/distribute/stories/noom.jpg b/docs/html/images/cards/distribute/stories/noom.jpg
    -new file mode 100644
    -index 0000000..dde18a2
    -Binary files /dev/null and b/docs/html/images/cards/distribute/stories/noom.jpg differ
    -diff --git a/docs/html/images/cards/distribute/stories/playlab.jpg b/docs/html/images/cards/distribute/stories/playlab.jpg
    -new file mode 100644
    -index 0000000..3b641e6
    -Binary files /dev/null and b/docs/html/images/cards/distribute/stories/playlab.jpg differ
    -diff --git a/docs/html/images/develop/hero-layout-editor.png b/docs/html/images/develop/hero-layout-editor.png
    -new file mode 100644
    -index 0000000..195150e
    -Binary files /dev/null and b/docs/html/images/develop/hero-layout-editor.png differ
    -diff --git a/docs/html/images/develop/hero-layout-editor_2x.png b/docs/html/images/develop/hero-layout-editor_2x.png
    -new file mode 100644
    -index 0000000..60c3d24
    -Binary files /dev/null and b/docs/html/images/develop/hero-layout-editor_2x.png differ
    -diff --git a/docs/html/images/distribute/stories/animoca-flow.jpg b/docs/html/images/distribute/stories/animoca-flow.jpg
    -new file mode 100644
    -index 0000000..d2aa2f6
    -Binary files /dev/null and b/docs/html/images/distribute/stories/animoca-flow.jpg differ
    -diff --git a/docs/html/images/distribute/stories/animoca-graph.jpg b/docs/html/images/distribute/stories/animoca-graph.jpg
    -new file mode 100644
    -index 0000000..c2a42f4
    -Binary files /dev/null and b/docs/html/images/distribute/stories/animoca-graph.jpg differ
    -diff --git a/docs/html/images/distribute/stories/animoca-logo.png b/docs/html/images/distribute/stories/animoca-logo.png
    -new file mode 100644
    -index 0000000..4b5b6b5
    -Binary files /dev/null and b/docs/html/images/distribute/stories/animoca-logo.png differ
    -diff --git a/docs/html/images/distribute/stories/drupe-icon.png b/docs/html/images/distribute/stories/drupe-icon.png
    -new file mode 100644
    -index 0000000..1b75cca
    -Binary files /dev/null and b/docs/html/images/distribute/stories/drupe-icon.png differ
    -diff --git a/docs/html/images/distribute/stories/drupe-screenshot.png b/docs/html/images/distribute/stories/drupe-screenshot.png
    -new file mode 100644
    -index 0000000..6fd4445
    -Binary files /dev/null and b/docs/html/images/distribute/stories/drupe-screenshot.png differ
    -diff --git a/docs/html/images/distribute/stories/economist-espresso-icon.png b/docs/html/images/distribute/stories/economist-espresso-icon.png
    -new file mode 100644
    -index 0000000..923bf57
    -Binary files /dev/null and b/docs/html/images/distribute/stories/economist-espresso-icon.png differ
    -diff --git a/docs/html/images/distribute/stories/expressen-icon.png b/docs/html/images/distribute/stories/expressen-icon.png
    -new file mode 100644
    -index 0000000..4547ce7
    -Binary files /dev/null and b/docs/html/images/distribute/stories/expressen-icon.png differ
    -diff --git a/docs/html/images/distribute/stories/glamour-icon.png b/docs/html/images/distribute/stories/glamour-icon.png
    -new file mode 100644
    -index 0000000..770b03f
    -Binary files /dev/null and b/docs/html/images/distribute/stories/glamour-icon.png differ
    -diff --git a/docs/html/images/distribute/stories/happylabs-happy_pet_icon.png b/docs/html/images/distribute/stories/happylabs-happy_pet_icon.png
    -new file mode 100644
    -index 0000000..9b24c4a
    -Binary files /dev/null and b/docs/html/images/distribute/stories/happylabs-happy_pet_icon.png differ
    -diff --git a/docs/html/images/distribute/stories/happylabs-logo.png b/docs/html/images/distribute/stories/happylabs-logo.png
    -new file mode 100644
    -index 0000000..ea20e71
    -Binary files /dev/null and b/docs/html/images/distribute/stories/happylabs-logo.png differ
    -diff --git a/docs/html/images/distribute/stories/happylabs-variant.png b/docs/html/images/distribute/stories/happylabs-variant.png
    -new file mode 100644
    -index 0000000..3ce5342
    -Binary files /dev/null and b/docs/html/images/distribute/stories/happylabs-variant.png differ
    -diff --git a/docs/html/images/distribute/stories/lifesum-icon.png b/docs/html/images/distribute/stories/lifesum-icon.png
    -new file mode 100644
    -index 0000000..3975ff2
    -Binary files /dev/null and b/docs/html/images/distribute/stories/lifesum-icon.png differ
    -diff --git a/docs/html/images/distribute/stories/noom-icon.png b/docs/html/images/distribute/stories/noom-icon.png
    -new file mode 100644
    -index 0000000..a853218
    -Binary files /dev/null and b/docs/html/images/distribute/stories/noom-icon.png differ
    -diff --git a/docs/html/images/distribute/stories/noom-screenshot.png b/docs/html/images/distribute/stories/noom-screenshot.png
    -new file mode 100644
    -index 0000000..0293eea
    -Binary files /dev/null and b/docs/html/images/distribute/stories/noom-screenshot.png differ
    -diff --git a/docs/html/images/distribute/stories/playlab-icon.png b/docs/html/images/distribute/stories/playlab-icon.png
    -new file mode 100644
    -index 0000000..af80183
    -Binary files /dev/null and b/docs/html/images/distribute/stories/playlab-icon.png differ
    -diff --git a/docs/html/images/distribute/stories/playlab-screenshot.png b/docs/html/images/distribute/stories/playlab-screenshot.png
    -new file mode 100644
    -index 0000000..42ffb6a
    -Binary files /dev/null and b/docs/html/images/distribute/stories/playlab-screenshot.png differ
    -diff --git a/docs/html/images/guide/topics/graphics/ic_battery_charging_80_black_24dp.png b/docs/html/images/guide/topics/graphics/ic_battery_charging_80_black_24dp.png
    -new file mode 100644
    -index 0000000..44a4e86
    -Binary files /dev/null and b/docs/html/images/guide/topics/graphics/ic_battery_charging_80_black_24dp.png differ
    -diff --git a/docs/html/images/guide/topics/graphics/vectorpath.png b/docs/html/images/guide/topics/graphics/vectorpath.png
    -new file mode 100644
    -index 0000000..592bab6
    -Binary files /dev/null and b/docs/html/images/guide/topics/graphics/vectorpath.png differ
    -diff --git a/docs/html/images/tools/sdk-manager-support-libs.png b/docs/html/images/tools/sdk-manager-support-libs.png
    -deleted file mode 100644
    -index cb4cea5..0000000
    -Binary files a/docs/html/images/tools/sdk-manager-support-libs.png and /dev/null differ
    -diff --git a/docs/html/images/tools/studio-sdk-manager-packages.png b/docs/html/images/tools/studio-sdk-manager-packages.png
    -deleted file mode 100644
    -index 79ea912..0000000
    -Binary files a/docs/html/images/tools/studio-sdk-manager-packages.png and /dev/null differ
    -diff --git a/docs/html/images/training/ctl-config.png b/docs/html/images/training/ctl-config.png
    -index 82f63c8..3a4f738 100644
    -Binary files a/docs/html/images/training/ctl-config.png and b/docs/html/images/training/ctl-config.png differ
    -diff --git a/docs/html/images/training/tv/playback/onboarding-fragment-diagram.png b/docs/html/images/training/tv/playback/onboarding-fragment-diagram.png
    -new file mode 100644
    -index 0000000..5839a50
    -Binary files /dev/null and b/docs/html/images/training/tv/playback/onboarding-fragment-diagram.png differ
    -diff --git a/docs/html/images/training/tv/playback/onboarding-fragment.png b/docs/html/images/training/tv/playback/onboarding-fragment.png
    -new file mode 100644
    -index 0000000..5b7da55
    -Binary files /dev/null and b/docs/html/images/training/tv/playback/onboarding-fragment.png differ
    -diff --git a/docs/html/images/training/tv/playback/onboarding-fragment_2x.png b/docs/html/images/training/tv/playback/onboarding-fragment_2x.png
    -new file mode 100644
    -index 0000000..0034be4
    -Binary files /dev/null and b/docs/html/images/training/tv/playback/onboarding-fragment_2x.png differ
    -diff --git a/docs/html/index.jd b/docs/html/index.jd
    -index dc59b71..78fc848 100644
    ---- a/docs/html/index.jd
    -+++ b/docs/html/index.jd
    -@@ -6,16 +6,6 @@ nonavpage=true
    - 
    - @jd:body
    - 
    --<script>
    --  $(document).ready(function() {
    --    if (useUpdatedTemplates) {
    --      $("#useUpdatedTemplates").css("display","block");
    --    } else {
    --      $("#useOldTemplates").css("display","block");
    --    }
    --  })
    --</script>
    --
    - <section class="dac-expand dac-hero" style="background-color:#b2dfdb;">
    -   <div class="wrap" style="max-width:1000px;margin-top:0">
    -     <div class="col-7of16 col-push-8of16">
    -@@ -45,7 +35,7 @@ nonavpage=true
    -   </div>
    - </section>
    - 
    --<div id="useUpdatedTemplates" style="display:none" class="dac-section dac-slim dac-gray dac-expand">
    -+<div class="dac-section dac-slim dac-gray dac-expand">
    -   <div class="wrap dac-offset-parent">
    -     <a class="dac-fab dac-scroll-button" data-scroll-button href="#build-apps">
    -       <i class="dac-sprite dac-arrow-down-gray"></i>
    -@@ -73,27 +63,44 @@ nonavpage=true
    -   </div><!-- end .wrap -->
    - </div><!-- end .dac-actions -->
    - 
    --<div id="useOldTemplates" style="display:none" class="actions-bar dac-expand dac-invert">
    --  <div class="wrap dac-offset-parent">
    --    <a class="dac-fab dac-scroll-button" data-scroll-button="" href="#build-apps">
    --      <i class="dac-sprite dac-arrow-down-gray"></i>
    -+
    -+<section class="dac-expand dac-hero" style="background-color:#FFF0B4;">
    -+  <div class="wrap" style="max-width:1000px;margin-top:0;overflow:auto">
    -+    <div class="col-7of16 col-push-8of16 dac-hero-figure">
    -+      <a href="/studio/index.html">
    -+        <img class="dac-hero-image" style="padding-top:24px"
    -+          src="/studio/images/hero_image_studio_2-2_2x.png">
    -+      </a>
    -+    </div>
    -+    <div class="col-7of16 col-pull-6of16">
    -+        <h1 class="dac-hero-title" style="color:#004d40">Android Studio 2.2</h1>
    -+
    -+<p class="dac-hero-description" style="color:#004d40">Packed with 20+ new
    -+features, Android Studio 2.2 focuses on speed, smarts, and Android platform
    -+support.</p>
    -+
    -+<p class="dac-hero-description" style="color:#004d40">Develop faster with
    -+features such as the new Layout Editor, and develop smarter with the new APK
    -+analyzer, expanded code analysis and more.</p>
    -+
    -+<p class="dac-hero-description" style="color:#004d40">Plus, this update
    -+includes support for all the latest developer features in Android 7.0 Nougat,
    -+with an updated emulator to test them all out.</p>
    -+
    -+<p style="margin-top:24px">
    -+   <a class="dac-hero-cta" href="/studio/index.html" style="color:#004d40">
    -+      <span class="dac-sprite dac-auto-chevron"></span>
    -+      Get Android Studio 2.2
    -     </a>
    --    <div class="actions">
    --      <div><a href="{@docRoot}studio/index.html">
    --        <span class="dac-sprite dac-auto-chevron-large"></span>
    --        Get Android Studio
    --      </a></div>
    --      <div><a href="{@docRoot}samples/index.html">
    --        <span class="dac-sprite dac-auto-chevron-large"></span>
    --        Browse Samples
    --      </a></div>
    --      <div><a href="{@docRoot}distribute/stories/index.html">
    --        <span class="dac-sprite dac-auto-chevron-large"></span>
    --        Watch Stories
    --      </a></div>
    --    </div><!-- end .actions -->
    --  </div><!-- end .wrap -->
    --</div>
    -+  &nbsp;&nbsp;&nbsp;&nbsp;<wbr>
    -+   <a class="dac-hero-cta" href="/studio/features.html" style="color:#004d40">
    -+    <span class="dac-sprite dac-auto-chevron"></span>
    -+    See more features</a>
    -+</p>
    -+    </div>
    -+  </div>
    -+</section>
    -+
    - 
    - <section class="dac-section dac-light" id="build-apps"><div class="wrap">
    -   <h1 class="dac-section-title">Build Beautiful Apps</h1>
    -diff --git a/docs/html/jd_collections.js b/docs/html/jd_collections.js
    -deleted file mode 100644
    -index 3ceddf2..0000000
    ---- a/docs/html/jd_collections.js
    -+++ /dev/null
    -@@ -1,1935 +0,0 @@
    --/*
    -- * THIS FILE IS DEPRECATED.
    -- *
    -- * Please add and edit resource collections in jd_extras_<lang>.js
    -- * where lang matches the language code appropriate for the resource.
    -- * Last sync'd with jd_extras_<lang>.js on 29 Apr 2016.
    -- *
    -- */
    --var RESOURCE_COLLECTIONS = {
    --  "index/carousel": {
    --    "title": "",
    --    "resources": [
    --      "about/versions/lollipop.html"
    --    ]
    --  },
    --  "index/primary": {
    --    "title": "",
    --    "resources": [
    --      "training/building-wearables.html",
    --      "training/material/index.html",
    --      "studio/index.html"
    --    ]
    --  },
    --  "index/secondary/carousel": {
    --    "title": "",
    --    "resources": [
    --      "http://www.youtube.com/watch?v=9m6MoBM-sFI",
    --      "http://www.youtube.com/watch?v=Pms0pcyPbAM",
    --      "http://www.youtube.com/watch?v=e7t3svG9PTk",
    --      "http://www.youtube.com/watch?v=J3IvOfvH1ys"
    --    ]
    --  },
    --  "index/multiscreen": {
    --    "title": "",
    --    "resources": [
    --      "wear/index.html",
    --      "tv/index.html",
    --      "auto/index.html"
    --    ]
    --  },
    --  "index/primary/zhcn": {
    --    "title": "",
    --    "resources": [
    --      "intl/zh-cn/resources.html",
    --      "intl/zh-cn/distribute/tools/launch-checklist.html",
    --      "intl/zh-cn/distribute/tools/localization-checklist.html"
    --    ]
    --  },
    --  "design/landing/latest": {
    --    "title": "",
    --    "resources": [
    --      "https://www.youtube.com/watch?v=p4gmvHyuZzw",
    --      "https://www.youtube.com/watch?v=YaG_ljfzeUw",
    --      "https://www.youtube.com/watch?v=XOcCOBe8PTc"
    --    ]
    --  },
    --  "design/landing/materialdesign": {
    --    "title": "",
    --    "resources": [
    --      "https://www.google.com/design/spec/animation/",
    --      "https://www.google.com/design/spec/style/",
    --      "https://www.google.com/design/spec/layout/",
    --      "https://www.google.com/design/spec/components/",
    --      "https://www.google.com/design/spec/patterns/",
    --      "https://www.google.com/design/spec/usability/"
    --    ]
    --  },
    --  "design/landing/pureandroid": {
    --    "title": "",
    --    "resources": [
    --      "design/get-started/creative-vision.html",
    --      "design/material/index.html",
    --      "training/material/index.html",
    --      "design/patterns/pure-android.html",
    --      "design/patterns/new.html",
    --      "design/devices.html"
    --    ]
    --  },
    --  "design/landing/resources": {
    --    "title": "",
    --    "resources": [
    --      "https://www.google.com/design/spec/resources/color-palettes.html",
    --      "https://www.google.com/design/spec/resources/layout-templates.html",
    --      "https://www.google.com/design/spec/resources/sticker-sheets-icons.html",
    --      "https://www.google.com/design/spec/resources/roboto-noto-fonts.html",
    --      "https://www.google.com/design/icons/index.html",
    --      "design/downloads/index.html#Wear"
    --    ]
    --  },
    --  "develop/landing/mainlinks": {
    --    "title": "",
    --    "resources": [
    --      "tools/studio/index.html",
    --      "samples/new/index.html",
    --      "tools/projects/templates.html"
    --    ]
    --  },
    --  "develop/landing/latest": {
    --    "title": "",
    --    "resources": [
    --      "https://android-developers.blogspot.com/2015/04/new-android-code-samples.html",
    --      "https://android-developers.blogspot.com/2015/04/android-support-library-221.html",
    --      "https://android-developers.blogspot.com/2015/03/a-new-reference-app-for-multi-device.html"
    --    ]
    --  },
    --  "develop/landing/devpatterns": {
    --    "title": "",
    --    "resources": [
    --      "https://www.youtube.com/watch?v=kmUGLURRPkI",
    --      "https://www.youtube.com/watch?v=HGElAW224dE",
    --      "https://www.youtube.com/watch?v=zQekzaAgIlQ"
    --    ]
    --  },
    --  "develop/landing/performance": {
    --    "title": "",
    --    "resources": [
    --      "https://www.youtube.com/watch?v=fEEulSk1kNY",
    --      "https://www.youtube.com/watch?v=-3ry8PxcJJA",
    --      "https://www.youtube.com/watch?v=_kKTGK-Cb_4"
    --    ]
    --  },
    --  "develop/landing/buildwithgoogle": {
    --    "title": "",
    --    "resources": [
    --    ]
    --  },
    --  "develop/landing/ubicomp": {
    --    "title": "",
    --    "resources": [
    --      "https://www.youtube.com/watch?v=AK38PJZmIW8&list=PLWz5rJ2EKKc-kIrPiq098QH9dOle-fLef",
    --      "https://www.youtube.com/watch?v=6K_jxccHv5M&index=1&list=PLOU2XLYxmsILFBfx66ens76VMLMEPJAB0",
    --      "https://www.youtube.com/watch?v=ctiaVxgclsg&list=PLWz5rJ2EKKc9BdE_PSLNIGjXXr3h_orXM"
    --    ]
    --  },
    --  "develop/landing/tools": {
    --    "title": "",
    --    "resources": [
    --      "https://www.youtube.com/watch?v=K2dodTXARqc&list=PLWz5rJ2EKKc8I9gHTMh5yKkwRRGE8BjbQ",
    --      "https://www.youtube.com/watch?v=cD7NPxuuXYY&list=PLWz5rJ2EKKc8I9gHTMh5yKkwRRGE8BjbQ",
    --      "https://www.youtube.com/watch?v=JLLnhwtDoHw&list=PLWz5rJ2EKKc8I9gHTMh5yKkwRRGE8BjbQ",
    --      "https://www.youtube.com/watch?v=2I6fuD20qlY&list=PLWz5rJ2EKKc8I9gHTMh5yKkwRRGE8BjbQ",
    --      "https://www.youtube.com/watch?v=5Be2mJzP-Uw&list=PLWz5rJ2EKKc9e0d55YHgJFHXNZbGHEXJX"
    --    ]
    --  },
    --  "preview/landing/resources": {
    --    "title": "",
    --    "resources": [
    --      "preview/overview.html",
    --      "preview/api-overview.html",
    --      "preview/behavior-changes.html",
    --      "preview/setup-sdk.html",
    --      "preview/samples.html",
    --      "preview/support.html"
    --    ]
    --  },
    --  "preview/landing/more": {
    --    "title": "",
    --    "resources": [
    --      "https://www.youtube.com/watch?v=CsulIu3UaUM",
    --      "preview/features/multi-window.html",
    --      "preview/features/notification-updates.html",
    --      "preview/features/background-optimization.html",
    --      "preview/features/data-saver.html",
    --      "preview/features/direct-boot.html",
    --      "preview/features/icu4j-framework.html",
    --      "preview/features/multilingual-support.html",
    --      "preview/features/scoped-folder-access.html",
    --      "preview/features/picture-in-picture.html",
    --      "preview/features/tv-recording-api.html"
    --    ]
    --  },
    --  "wear/preview/landing": {
    --    "title": "",
    --    "resources": [
    --      "wear/preview/api-overview.html",
    --      "wear/preview/downloads.html",
    --      "wear/preview/start.html"
    --    ]
    --  },
    --  "wear/preview/landing/resources": {
    --    "title": "",
    --    "resources": [
    --      "wear/preview/features/complications.html",
    --      "wear/preview/features/notifications.html",
    --      "wear/preview/features/ui-nav-actions.html"
    --    ]
    --  },
    --  "google/landing/services": {
    --    "title": "",
    --    "resources": [
    --      "https://developers.google.com/analytics/devguides/collection/android/",
    --      "https://developers.google.com/maps/documentation/android/",
    --      "https://developers.google.com/identity/sign-in/android/",
    --      "https://developers.google.com/mobile-ads-sdk/download",
    --      "https://developers.google.com/cloud-messaging/gcm",
    --      "https://developers.google.com/app-indexing/"
    --    ]
    --  },
    --  "google/landing/videos": {
    --    "title": "",
    --    "resources": [
    --      "https://www.youtube.com/watch?v=M3Udfu6qidk&list=PLWz5rJ2EKKc9Qk1_iCZNbBp6adYnJf9Vf",
    --      "https://www.youtube.com/watch?v=FOn64iqlphk&list=PLWz5rJ2EKKc9Qk1_iCZNbBp6adYnJf9Vf",
    --      "https://www.youtube.com/watch?v=F0Kh_RnSM0w&list=PLWz5rJ2EKKc9Qk1_iCZNbBp6adYnJf9Vf",
    --      "https://www.youtube.com/watch?v=fvtMtfCuEpw&list=PLWz5rJ2EKKc9Qk1_iCZNbBp6adYnJf9Vf"
    --    ]
    --  },
    --  "google/landing/googleplay": {
    --    "title": "",
    --    "resources": [
    --      "google/play/billing/index.html",
    --      "google/play/billing/billing_subscriptions.html",
    --      "google/play/developer-api.html"
    --    ]
    --  },
    --  "develop/landing/courses": {
    --    "title": "",
    --    "resources": [
    --      "https://www.udacity.com/course/ud849",
    --      "https://www.udacity.com/course/ud853",
    --      "https://www.udacity.com/course/ud825",
    --      "https://www.udacity.com/android",
    --      "https://www.udacity.com/course/ud855",
    --      "https://www.udacity.com/course/ud875A",
    --      "https://www.udacity.com/course/ud875B",
    --      "https://www.udacity.com/course/ud875C",
    --      "https://www.udacity.com/course/ud876--1",
    --      "https://www.udacity.com/course/ud876--2",
    --      "https://www.udacity.com/course/ud876--3",
    --      "https://www.udacity.com/course/ud876--4",
    --      "https://www.udacity.com/course/ud876--5",
    --      "https://www.udacity.com/course/ud862",
    --      "https://www.udacity.com/course/ud837",
    --      "https://www.udacity.com/course/ud867"
    --    ]
    --  },
    --  "distribute/landing/carousel": {
    --    "title": "",
    --    "resources": [
    --    "distribute/googleplay/guide.html",
    --    "https://www.youtube.com/watch?v=JrR6o5tYMWQ",
    --    "https://www.youtube.com/watch?v=B6ydLpkhq04&list=PLOU2XLYxmsIKLNUPiFCWVtcO7mZRZ9MmS",
    --    "https://www.youtube.com/watch?v=yJisuP94lHU",
    --    ]
    --  },
    --  "distribute/landing/googleplay": {
    --    "title": "",
    --    "resources": [
    --      "distribute/googleplay/about.html",
    --      "distribute/googleplay/developer-console.html",
    --      "distribute/googleplay/index.html#opportunities"
    --    ]
    --  },
    --  "distribute/landing/more": {
    --    "title": "",
    --    "resources": [
    --      "distribute/users/promote-with-ads.html",
    --      "distribute/monetize/ads.html",
    --      "distribute/analyze/index.html",
    --      "distribute/engage/deep-linking.html",
    --      "distribute/engage/easy-signin.html",
    --      "https://cloud.google.com/docs/"
    --    ]
    --  },
    --  "distribute/edu/videos/stories": {
    --    "title": "",
    --    "resources": [
    --      "https://www.youtube.com/watch?v=Idu7VcTTXfk",
    --      "https://www.youtube.com/watch?v=iokH4SAIfRw"
    --    ]
    --  },
    --  "distribute/edu/videos/bestpractices": {
    --    "title": "",
    --    "resources": [
    --      "https://www.youtube.com/watch?v=iulXz8QTD1g",
    --      "https://www.youtube.com/watch?v=IKhU180eJMo",
    --      "https://www.youtube.com/watch?v=_AZ6UcPz-_g",
    --      "https://www.youtube.com/watch?v=Eh2adsAyTKc"
    --    ]
    --  },
    --  "distribute/edu/videos/experience": {
    --    "title": "",
    --    "resources": [
    --      "https://youtu.be/vzvpcEffvaE"
    --    ]
    --  },
    --/*  "launch/static": {
    --    "title": "",
    --    "resources": [
    --      "https://www.youtube.com/watch?v=1RIz-cmTQB4",
    --      "https://www.youtube.com/watch?v=MVBMWDzyHAI",
    --      "https://android-developers.blogspot.com/2013/11/app-translation-service-now-available.html",
    --      "https://android-developers.blogspot.com/2013/10/more-visibility-for-tablet-apps-in.html",
    --      "https://android-developers.blogspot.com/2013/11/bring-your-apps-into-classroom-with.html",
    --      "distribute/essentials/quality/tablets.html",
    --      "distribute/users/build-buzz.html",
    --      "distribute/monetize/premium.html",
    --      "distribute/monetize/freemium.html",
    --      "distribute/monetize/ads.html",
    --      "distribute/essentials/best-practices/apps.html",
    --      "distribute/essentials/best-practices/games.html",
    --      "distribute/users/know-your-user.html",
    --      "distribute/googleplay/developer-console.html"
    --    ]
    --  }, */
    --  "launch/static/ja": {
    --    "title": "",
    --    "resources": [
    --      "https://www.youtube.com/watch?v=xelYnWcYkuE",
    --      "https://www.youtube.com/playlist?list=PLCOC_kP3nqGIHEgwm9mybvA04Vn4Cg9nn",
    --      "https://googledevjp.blogspot.jp/2014/12/android-wear.html",
    --      "https://googledevjp.blogspot.jp/2014/12/android-studio-10.html",
    --      "https://googledevjp.blogspot.jp/2014/12/google-play-65.html",
    --      "intl/ja/distribute/googleplay/developer-console.html#alpha-beta",
    --      "intl/ja/distribute/googleplay/guide.html",
    --      "intl/ja/distribute/essentials/quality/core.html",
    --      "https://support.google.com/googleplay/android-developer/answer/4430948?hl=ja",
    --      "intl/ja/support.html",
    --      "intl/ja/distribute/essentials/quality/wear.html",
    --      "intl/ja/training/tv/start/index.html",
    --      "https://googleforwork-japan.blogspot.jp/2014/12/gcp-google-cloud-platform-rpg-gcp.html",
    --      "intl/ja/distribute/monetize/ads.html"
    --    ]
    --  },
    --  "launch/static/ko": {
    --    "title": "",
    --    "resources": [
    --      "https://www.youtube.com/watch?v=7X9Ue0Nfdh4&index=2&list=PL_WJkTbDHdBksDBRoqfeyLchEQqBAOlNl",
    --      "https://www.youtube.com/watch?v=83FpwuschCQ",
    --      "https://googledevkr.blogspot.com/2014/11/android50guidefordevelopers.html",
    --      "https://googledevkr.blogspot.com/2014/10/material-design-on-android-checklist.html",
    --      "https://googledevkr.blogspot.com/2014/10/appcompat-v21-material-design-for-pre.html",
    --      "intl/ko/distribute/googleplay/developer-console.html#alpha-beta",
    --      "intl/ko/distribute/googleplay/guide.html",
    --      "intl/ko/distribute/essentials/quality/core.html",
    --      "https://support.google.com/googleplay/android-developer/answer/4430948?hl=ko",
    --      "intl/ko/support.html",
    --      "intl/ko/distribute/essentials/quality/wear.html",
    --      "intl/ko/tv/index.html",
    --      "intl/ko/google/play-services/games.html",
    --      "intl/ko/distribute/monetize/ads.html"
    --    ]
    --  },
    --  "distribute/gp/gplanding": {
    --    "resources": [
    --      "distribute/googleplay/about.html",
    --      "distribute/googleplay/start.html",
    --      "distribute/googleplay/developer-console.html"
    --    ]
    --  },
    --  "distribute/gp/gpfelanding": {
    --    "resources": [
    --      "distribute/googleplay/wear.html",
    --      "distribute/googleplay/tv.html",
    --      "distribute/googleplay/auto.html",
    --      "distribute/googleplay/families/about.html",
    --      "distribute/googleplay/work/about.html",
    --      "distribute/googleplay/edu/about.html",
    --      "distribute/googleplay/cast.html",
    --      "distribute/googleplay/cardboard.html",
    --      "distribute/googleplay/guide.html"
    --    ]
    --  },
    --  "distribute/googleplay/gpfw": {
    --    "resources": [
    --      "https://www.android.com/work/",
    --      "https://www.youtube.com/watch?v=jQWB_-o1kz4&list=PLOU2XLYxmsIKAK2Bhv19H2THwF-22O5WX",
    --      "work/index.html"
    --    ]
    --  },
    --  "distribute/essentials": {
    --    "resources": [
    --      "distribute/essentials/quality/core.html",
    --      "distribute/essentials/quality/tablets.html",
    --      "distribute/essentials/quality/tv.html",
    --      "distribute/essentials/quality/wear.html",
    --      "distribute/essentials/quality/auto.html",
    --      "distribute/essentials/quality/billions.html"
    --    ]
    --  },
    --  "distribute/essentials/zhcn": {
    --    "resources": [
    --      "intl/zh-cn/distribute/essentials/quality/core.html",
    --      "intl/zh-cn/distribute/essentials/quality/tablets.html",
    --      "distribute/essentials/quality/tv.html",
    --      "distribute/essentials/quality/wear.html",
    --      "https://developers.google.com/edu/guidelines",
    --      "distribute/essentials/optimizing-your-app.html"
    --    ]
    --  },
    --  "distribute/users": {
    --    "title": "",
    --    "resources": [
    --      "distribute/users/your-listing.html",
    --      "distribute/users/promote-with-ads.html",
    --      "distribute/googleplay/index.html#opportunities",
    --      "distribute/analyze/improve-roi.html",
    --      "distribute/users/expand-to-new-markets.html",
    --      "distribute/analyze/index.html",
    --      "distribute/users/app-invites.html",
    --      "distribute/users/ota-installs.html",
    --      "distribute/users/youtube.html",
    --      "distribute/users/house-ads.html",
    --      "distribute/users/experiments.html",
    --      "distribute/users/user-acquisition.html",
    --      "distribute/users/banners.html",
    --      "distribute/users/beta.html"
    --    ]
    --  },
    --  "distribute/engagelanding": {
    --    "resources": [
    --      "distribute/engage/intents.html",
    --      "distribute/engage/widgets.html",
    --      "distribute/engage/translate.html",
    --      "distribute/engage/notifications.html",
    --      "distribute/engage/deep-linking.html",
    --      "distribute/engage/ads.html",
    --      "distribute/engage/game-services.html",
    --      "distribute/engage/easy-signin.html",
    --      "distribute/analyze/build-better-apps.html",
    --      "distribute/engage/gcm.html",
    --      "distribute/engage/beta.html",
    --      "distribute/engage/nearby.html"
    --    ]
    --  },
    --  "distribute/monetize": {
    --    "resources": [
    --      "distribute/monetize/premium.html",
    --      "distribute/monetize/freemium.html",
    --      "distribute/monetize/subscriptions.html",
    --      "distribute/monetize/ads.html",
    --      "distribute/monetize/ecommerce.html",
    --      "distribute/monetize/payments.html",
    --      "distribute/monetize/conversions.html",
    --      "distribute/analyze/understand-user-value.html",
    --    ]
    --  },
    --  "distribute/analyzelanding": {
    --    "resources": [
    --      "distribute/analyze/start.html",
    --      "distribute/analyze/measure.html",
    --      "distribute/analyze/understand-user-value.html",
    --      "distribute/analyze/improve-roi.html",
    --      "distribute/analyze/build-better-apps.html",
    --      "distribute/analyze/google-services.html"
    --    ]
    --  },
    --  "distribute/analyzestart": {
    --    "resources": [
    --      "https://analyticsacademy.withgoogle.com/course04",
    --      "google/play-services/index.html",
    --      "https://developers.google.com/analytics/solutions/mobile-implementation-guide",
    --      "https://developers.google.com/analytics/devguides/collection/android/",
    --      "https://www.google.com/tagmanager/",
    --      "https://github.com/googleanalytics/google-analytics-plugin-for-unity"
    --    ]
    --  },
    --  "distribute/analyzemeasure": {
    --    "resources": [
    --
    --      "https://developers.google.com/analytics/solutions/mobile-implementation-guide",
    --      "https://developers.google.com/analytics/devguides/collection/android/v4/enhanced-ecommerce",
    --      "https://support.google.com/analytics/answer/1032415",
    --      "https://developers.google.com/analytics/devguides/collection/android/v4/events",
    --      "https://developers.google.com/analytics/devguides/collection/android/v4/customdimsmets",
    --      "https://developers.google.com/analytics/devguides/collection/android/v4/user-id"
    --    ]
    --  },
    --  "distribute/analyzeunderstand": {
    --    "resources": [
    --      "https://developers.google.com/analytics/devguides/collection/android/v4/display-features",
    --      "https://support.google.com/analytics/answer/3123906",
    --      "https://support.google.com/analytics/answer/2568874?ref_topic=6012392",
    --      "https://developers.google.com/analytics/devguides/collection/android/v4/enhanced-ecommerce",
    --      "https://support.google.com/analytics/answer/1032415",
    --    ]
    --  },
    --  "distribute/analyzeimprove": {
    --    "resources": [
    --
    --      "https://developers.google.com/analytics/devguides/collection/android/v4/campaigns",
    --      "https://support.google.com/analytics/answer/2956981",
    --      "https://support.google.com/analytics/answer/1033961",
    --      "https://developers.google.com/analytics/devguides/collection/android/v4/campaigns#google-play-url-builder",
    --      "https://developers.google.com/analytics/solutions/mobile-campaign-deep-link"
    --    ]
    --  },
    --  "distribute/analyzebuild": {
    --    "resources": [
    --      "https://support.google.com/tagmanager/answer/6003007",
    --      "https://support.google.com/analytics/answer/2785577",
    --      "https://support.google.com/analytics/answer/1151300"
    --    ]
    --  },
    --  "distribute/analyzeact": {
    --    "resources": [
    --      "https://support.google.com/analytics/answer/2611268",
    --      "https://support.google.com/analytics/answer/1033961",
    --      "https://support.google.com/admob/answer/3508177",
    --      "https://support.google.com/analytics/answer/2956981",
    --      "https://support.google.com/tagmanager/answer/6003007"
    --    ]
    --  },
    --  "distribute/essentials/guidelines": {
    --    "title": "",
    --    "resources": [
    --      "distribute/essentials/quality/core.html",
    --      "distribute/essentials/quality/tablets.html",
    --      "distribute/essentials/quality/wear.html",
    --      "distribute/essentials/quality/tv.html",
    --      "distribute/essentials/quality/auto.html",
    --      "distribute/essentials/quality/billions.html"
    --    ]
    --  },
    --  "distribute/essentials/tools": {
    --    "title": "",
    --    "resources": [
    --      "distribute/tools/launch-checklist.html",
    --      "distribute/tools/localization-checklist.html",
    --      "https://support.google.com/googleplay/android-developer",
    --      "distribute/tools/promote/brand.html",
    --      "distribute/tools/promote/device-art.html",
    --      "https://play.google.com/intl/en_us/badges/",
    --      "distribute/tools/promote/linking.html",
    --      "distribute/tools/open-distribution.html",
    --      "about/dashboards/index.html"
    --    ]
    --  },
    --  "distribute/tools/checklists": {
    --    "title": "",
    --    "resources": [
    --      "distribute/tools/launch-checklist.html",
    --      "distribute/tools/localization-checklist.html"
    --    ]
    --  },
    --  "distribute/tools/checklists/zhcn": {
    --    "title": "",
    --    "resources": [
    --      "intl/zh-cn/distribute/tools/launch-checklist.html",
    --      "intl/zh-cn/distribute/tools/localization-checklist.html"
    --    ]
    --  },
    --  "distribute/tools/promote": {
    --    "resources": [
    --      "distribute/tools/promote/device-art.html",
    --      "https://play.google.com/intl/en_us/badges/",
    --      "distribute/tools/promote/linking.html"
    --    ]
    --  },
    --  "distribute/tools/promote/zhcn": {
    --    "resources": [
    --      "intl/zh-cn/distribute/tools/promote/device-art.html",
    --      "https://play.google.com/intl/en_us/badges/",
    --      "intl/zh-cn/distribute/tools/promote/linking.html"
    --    ]
    --  },
    --  "distribute/tools/support": {
    --    "title": "Google Play",
    --    "resources": [
    --      "https://support.google.com/googleplay/android-developer",
    --      "https://support.google.com/googleplay/android-developer/answer/4430948",
    --      "support.html"
    --    ]
    --  },
    --  "distribute/tools/support/zhcn": {
    --    "title": "Google Play",
    --    "resources": [
    --      "https://support.google.com/googleplay/android-developer?hl=zh-Hans",
    --      "https://support.google.com/googleplay/android-developer/answer/4430948?hl=zh-Hans",
    --      "support.html"
    --    ]
    --  },
    --  "distribute/tools/news": {
    --    "title": "",
    --    "resources": [
    --      "https://android-developers.blogspot.com/",
    --      "https://plus.google.com/+AndroidDevelopers/"
    --    ]
    --  },
    --  "distribute/tools/more": {
    --    "title": "Google Play",
    --    "resources": [
    --      "distribute/tools/promote/brand.html",
    --      "distribute/tools/open-distribution.html",
    --      "about/dashboards/index.html"
    --    ]
    --  },
    --  "distribute/tools/more/zhcn": {
    --    "title": "Google Play",
    --    "resources": [
    --      "intl/zh-cn/distribute/tools/promote/brand.html",
    --      "distribute/tools/open-distribution.html",
    --      "about/dashboards/index.html"
    --    ]
    --  },
    --  "distribute/googleplay": {
    --    "title": "Google Play",
    --    "resources": [
    --      "distribute/googleplay/developer-console.html",
    --      "distribute/essentials/best-practices/apps.html",
    --      "distribute/tools/launch-checklist.html",
    --      "distribute/essentials/best-practices/games.html",
    --    ]
    --  },
    --  "distribute/googleplay/gettingstarted": {
    --    "title": "Get Started",
    --    "resources": [
    --      "distribute/googleplay/developer-console.html",
    --      "https://support.google.com/googleplay/android-developer/answer/113468",
    --      "https://support.google.com/googleplay/android-developer/answer/138294",
    --      "https://support.google.com/googleplay/android-developer"
    --    ]
    --  },
    --  "distribute/googleplay/developerconsole/related": {
    --    "title": "Developer Console",
    --    "resources": [
    --      "google/play/billing/index.html",
    --      "https://support.google.com/googleplay/android-developer/answer/138294"
    --    ]
    --  },
    --  "distribute/googleplay/beta": {
    --    "title": "Alpha and Beta Testing",
    --    "resources": [
    --      "https://support.google.com/googleplay/android-developer/answer/3131213",
    --      "https://support.google.com/googleplay/android-developer/answer/3131213#games",
    --      "distribute/googleplay/experiments.html"
    --    ]
    --  },
    --  "distribute/googleplay/experiments/successes": {
    --    "title": "Store Listing Experiment successes",
    --    "resources": [
    --    ]
    --  },
    --  "distribute/googleplay/experiments/related": {
    --    "title": "Store Listing Experiments",
    --    "resources": [
    --      "https://support.google.com/googleplay/android-developer/answer/6227309",
    --      "https://www.youtube.com/watch?v=B6ydLpkhq04",
    --      "https://support.google.com/tagmanager/answer/6003007"
    --    ]
    --  },
    --  "distribute/googleplay/banners/related": {
    --    "title": "App Install Banners",
    --    "resources": [
    --      "https://developers.google.com/web/updates/2015/03/increasing-engagement-with-app-install-banners-in-chrome-for-android#native"
    --    ]
    --  },
    --  "distribute/googleplay/useracquisition/related": {
    --    "title": "User Acquisition",
    --    "resources": [
    --      "https://support.google.com/googleplay/android-developer/answer/6263332"
    --    ]
    --  },
    --  "distribute/googleplay/cast": {
    --    "title": "Google Cast",
    --    "resources": [
    --      "https://developers.google.com/cast/docs/ux_guidelines",
    --      "https://developers.google.com/cast/docs/android_sender",
    --      "https://www.github.com/googlecast"
    --    ]
    --  },
    --  "distribute/googleplay/cardboard": {
    --    "title": "Google Cast",
    --    "resources": [
    --      "https://www.google.com/get/cardboard/get-cardboard/",
    --      "https://developers.google.com/cardboard/android/download",
    --      "https://www.google.com/design/spec-vr"
    --    ]
    --  },
    --  "distribute/googleplay/gpfe/highlight": {
    --    "title": "About Google Play for Education",
    --    "resources": [
    --      "https://youtu.be/vzvpcEffvaE"
    --    ]
    --  },
    --  "distribute/googleplay/gpfe/dev/about": {
    --    "title": "About Google Play for Education / Developers",
    --    "resources": [
    --      "distribute/googleplay/edu/start.html",
    --      "https://developers.google.com/edu/guidelines",
    --      "https://developers.google.com/edu/faq",
    --      "distribute/essentials/quality/tablets.html",
    --      "https://developers.google.com/edu/",
    --      "https://www.google.com/edu/tablets/#tablets-family"
    --    ]
    --  },
    --  "distribute/googleplay/gpfe/dev": {
    --    "title": "About Google Play for Education / Developers",
    --    "resources": [
    --      "distribute/googleplay/edu/about.html",
    --      "https://developers.google.com/edu/guidelines",
    --      "distribute/essentials/quality/tablets.html",
    --      "distribute/googleplay/developer-console.html",
    --      "https://play.google.com/about/developer-distribution-agreement-addendum.html",
    --    ]
    --  },
    --  "distribute/googleplay/aboutgpfe/educators/about": {
    --    "title": "About Google Play for Education / Educators",
    --    "resources": [
    --      "https://www.google.com/edu/tablets/",
    --      "https://www.youtube.com/watch?v=haEmsMo0f3w"
    --    ]
    --  },
    --  "distribute/googleplay/aboutgpfe/educators": {
    --    "title": "About Google Play for Education / Educators",
    --    "resources": [
    --      "https://www.google.com/edu/tablets/",
    --      "https://youtu.be/vzvpcEffvaE"
    --    ]
    --  },
    --  "distribute/googleplay/gettingstartedgpfe/educators": {
    --    "title": "About Google Play for Education / Educators",
    --    "resources": [
    --      "https://www.google.com/edu/tablets/",
    --      "https://youtu.be/vzvpcEffvaE"
    --    ]
    --  },
    --  "distribute/essentials/eduessentials/developers": {
    --    "title": "",
    --    "resources": [
    --      "distribute/googleplay/developer-console.html",
    --      "distribute/googleplay/edu/start.html",
    --      "https://developers.google.com/edu/faq"
    --    ]
    --  },
    --  "distribute/essentials/eduessentials/educators": {
    --    "title": "",
    --    "resources": [
    --      "https://www.google.com/edu/tablets/",
    --      "distribute/essentials/quality/tablets.html",
    --    ]
    --  },
    --  "distribute/essentials/optimizing": {
    --    "title": "Optimizing Your App",
    --    "resources": [
    --      "design/index.html",
    --      "training/articles/perf-anr.html",
    --      "https://android-developers.blogspot.com/2013/10/improved-app-insight-by-linking-google.html"
    --     ]
    --  },
    --  "distribute/users/appinvites": {
    --    "title": "",
    --    "resources": [
    --      "https://developers.google.com/app-invites/",
    --      "https://developers.google.com/identity/sign-in/android/",
    --      "https://developers.google.com/app-indexing/"
    --    ]
    --  },
    --  "distribute/users/knowyouruser": {
    --    "title": "",
    --    "resources": [
    --      "distribute/essentials/optimizing-your-app.html",
    --      "http://www.youtube.com/watch?v=RRelFvc6Czo",
    --      "distribute/stories/games/rvappstudios-zombie.html"
    --    ]
    --  },
    --  "distribute/users/promotewithads": {
    --    "title": "",
    --    "resources": [
    --      "https://support.google.com/adwords/answer/6032059",
    --      "https://support.google.com/adwords/answer/6032073",
    --      "https://support.google.com/adwords/answer/6167164",
    --      "https://support.google.com/adwords/answer/6167162"
    --    ]
    --  },
    --  "distribute/users/nearby": {
    --    "title": "",
    --    "resources": [
    --      "https://developers.google.com/nearby/",
    --      "https://www.youtube.com/watch?v=hultDpBS22s",
    --      "https://developers.google.com/beacons"
    --    ]
    --  },
    --  "distribute/users/buildbuzz": {
    --    "title": "",
    --    "resources": [
    --      "https://play.google.com/intl/en_us/badges/",
    --      "distribute/tools/promote/linking.html",
    --      "distribute/tools/promote/device-art.html",
    --      "https://plus.google.com/+GooglePlay"
    --    ]
    --  },
    --  "distribute/users/createagreatlisting": {
    --    "title": "",
    --    "resources": [
    --      "https://support.google.com/googleplay/android-developer/answer/1078870",
    --      "https://android-developers.blogspot.com/2011/10/android-market-featured-image.html",
    --      "distribute/tools/launch-checklist.html",
    --      "https://android-developers.blogspot.com/2013/07/making-beautiful-android-app-icons.html",
    --      "https://android-developers.blogspot.com/2012/12/localize-your-promotional-graphics-on.html",
    --      "https://android-developers.blogspot.com/2013/10/making-your-app-content-more-accessible.html"
    --    ]
    --  },
    --  "distribute/users/buildcommunity": {
    --    "title": "",
    --    "resources": [
    --      "distribute/googleplay/developer-console.html",
    --      "https://support.google.com/groups/answer/46601",
    --      "https://support.google.com/plus/topic/2888488",
    --      "https://www.youtube.com/yt/dev/"
    --    ]
    --  },
    --  "distribute/users/appindexing": {
    --    "title": "",
    --    "resources": [
    --      "https://developers.google.com/app-indexing/",
    --      "https://developers.google.com/app-indexing/webmasters/details",
    --      "distribute/engage/deep-linking.html",
    --      "training/app-indexing/index.html"
    --    ]
    --  },
    --  "distribute/users/otas": {
    --    "title": "",
    --    "resources": [
    --      "https://developers.google.com/identity/sign-in/android/",
    --      "https://developers.google.com/+/features/play-installs",
    --      "https://developers.google.com/+/features/analytics"
    --    ]
    --  },
    --  "distribute/users/houseads": {
    --    "title": "",
    --    "resources": [
    --      "https://support.google.com/admob/topic/2784623",
    --      "https://developers.google.com/mobile-ads-sdk/download",
    --      "https://support.google.com/googleplay/android-developer/topic/2985714",
    --      "https://analyticsacademy.withgoogle.com/mobile-app",
    --      "https://support.google.com/analytics/answer/2611404",
    --      "https://support.google.com/admob/answer/3111064"
    --    ]
    --  },
    --  "distribute/users/youtube": {
    --    "title": "",
    --    "resources": [
    --      "https://support.google.com/youtube/answer/6140493",
    --      "https://support.google.com/youtube/answer/2797387"
    --    ]
    --  },
    --  "distribute/toolsreference/bestpractices/apps": {
    --    "title": "",
    --    "resources": [
    --      "distribute/googleplay/developer-console.html",
    --      "https://android-developers.blogspot.com/"
    --    ]
    --  },
    --  "distribute/toolsreference/bestpractices/games": {
    --    "title": "",
    --    "resources": [
    --      "google/play-services/games.html",
    --      "https://android-developers.blogspot.com/",
    --      "distribute/googleplay/developer-console.html",
    --      "https://www.youtube.com/watch?v=1RIz-cmTQB4"
    --    ]
    --  },
    --  "distribute/essentials/corequalityguidelines/visualdesign": {
    --    "title": "",
    --    "resources": [
    --      "design/index.html",
    --      "design/patterns/navigation.html",
    --      "design/patterns/actionbar.html",
    --      "design/style/iconography.html"
    --    ]
    --  },
    --  "distribute/essentials/corequalityguidelines/functionality": {
    --    "title": "",
    --    "resources": [
    --      "https://android-developers.blogspot.com/2011/11/making-android-games-that-play-nice.html",
    --      "guide/components/tasks-and-back-stack.html",
    --      "training/basics/activity-lifecycle/recreating.html"
    --    ]
    --  },
    --  "distribute/essentials/tvqualityguidelines/visualdesign": {
    --    "title": "",
    --    "resources": [
    --      "design/tv/index.html",
    --      "training/tv/start/index.html"
    --    ]
    --  },
    --  "distribute/essentials/tvqualityguidelines/functionality": {
    --    "title": "",
    --    "resources": [
    --      "training/tv/start/hardware.html",
    --      "training/tv/games/index.html"
    --    ]
    --  },
    --  "distribute/essentials/wearqualityguidelines/visualdesign": {
    --    "title": "",
    --    "resources": [
    --      "design/wear/index.html",
    --      "training/building-wearables.html",
    --      "training/wearables/ui/index.html"
    --    ]
    --  },
    --  "distribute/essentials/wearqualityguidelines/functionality": {
    --    "title": "",
    --    "resources": [
    --      "training/wearables/notifications/index.html",
    --      "training/wearables/apps/index.html",
    --      "training/wearables/notifications/voice-input.html"
    --    ]
    --  },
    --    "distribute/essentials/autoqualityguidelines/visualdesign": {
    --    "title": "",
    --    "resources": [
    --      "training/auto/messaging/index.html",
    --      "training/auto/start/index.html"
    --    ]
    --  },
    --  "distribute/essentials/core/performance": {
    --    "title": "",
    --    "resources": [
    --      "https://android-developers.blogspot.com/2010/12/new-gingerbread-api-strictmode.html",
    --      "training/articles/perf-anr.html",
    --      "https://android-developers.blogspot.com/2010/07/multithreading-for-performance.html"
    --    ]
    --  },
    --  "distribute/essentials/core/play": {
    --    "title": "",
    --    "resources": [
    --      "distribute/tools/launch-checklist.html",
    --      "https://play.google.com/about/developer-content-policy.html?hl=zh-Hans",
    --      "https://support.google.com/googleplay/android-developer/answer/188189?hl=zh-Hans",
    --      "https://support.google.com/googleplay/android-developer/answer/1078870?hl=zh-Hans",
    --      "https://android-developers.blogspot.com/2011/10/android-market-featured-image.html",
    --      "https://support.google.com/googleplay/android-developer/answer/113477?hl=zh-Hans"
    --    ]
    --  },
    --  "distribute/essentials/core/play/zhcn": {
    --    "title": "",
    --    "resources": [
    --      "intl/zh-cn/distribute/tools/launch-checklist.html",
    --      "https://play.google.com/about/developer-content-policy.html",
    --      "https://support.google.com/googleplay/android-developer/answer/188189?hl=zh-Hans",
    --      "https://support.google.com/googleplay/android-developer/answer/1078870?hl=zh-Hans",
    --      "https://android-developers.blogspot.com/2011/10/android-market-featured-image.html",
    --      "https://support.google.com/googleplay/android-developer/answer/113477?hl=zh-Hans"
    --    ]
    --  },
    --  "distribute/essentials/tabletguidelines/optimize": {
    --    "title": "",
    --    "resources": [
    --      "design/style/metrics-grids.html",
    --      "design/style/devices-displays.html",
    --      "guide/practices/screens_support.html",
    --      //"guide/practices/screens_support.html#ConfigurationExamples",
    --    ]
    --  },
    --  "distribute/essentials/tabletguidelines/extrascreen": {
    --    "title": "",
    --    "resources": [
    --      "design/patterns/multi-pane-layouts.html",
    --      "training/design-navigation/multiple-sizes.html",
    --      "training/multiscreen/index.html",
    --    ]
    --  },
    --  "distribute/essentials/tabletguidelines/assets": {
    --    "title": "",
    --    "resources": [
    --      "design/style/iconography.html",
    --      "guide/topics/resources/providing-resources.html",
    --      "guide/practices/screens_support.html",
    --      "training/basics/supporting-devices/screens.html"
    --    ]
    --  },
    --  "distribute/essentials/tabletguidelines/fonts": {
    --    "title": "",
    --    "resources": [
    --      "design/style/metrics-grids.html",
    --      "design/style/typography.html",
    --      "guide/practices/screens_support.html",
    --      "training/multiscreen/screendensities.html"
    --    ]
    --  },
    --  "distribute/essentials/tabletguidelines/widgets": {
    --    "title": "",
    --    "resources": [
    --      "guide/topics/appwidgets/index.html#MetaData",
    --      "guide/topics/appwidgets/index.html",
    --      "design/patterns/widgets.html"
    --    ]
    --  },
    --  "distribute/essentials/tabletguidelines/versions": {
    --    "title": "",
    --    "resources": [
    --      "guide/topics/manifest/uses-sdk-element.html#ApiLevels",
    --      "guide/topics/manifest/uses-sdk-element.html",
    --      "training/basics/supporting-devices/platforms.html"
    --    ]
    --  },
    --  "distribute/essentials/tabletguidelines/hardware": {
    --    "title": "",
    --    "resources": [
    --      "guide/topics/manifest/uses-feature-element.html",
    --      "guide/topics/manifest/uses-feature-element.html#testing"
    --    ]
    --  },
    -- "distribute/essentials/tabletguidelines/tabletscreens": {
    --    "title": "",
    --    "resources": [
    --      "guide/practices/screens_support.html#DeclaringScreenSizeSupport",
    --      "guide/practices/screens_support.html"
    --    ]
    --  },
    --  "distribute/essentials/tabletguidelines/showcase": {
    --    "title": "",
    --    "resources": [
    --      "distribute/tools/launch-checklist.html",
    --      "https://play.google.com/apps/publish/",
    --      "https://play.google.com/intl/en_us/badges/",
    --      "distribute/tools/promote/device-art.html"
    --    ]
    --  },
    --  "distribute/essentials/tabletguidelines/showcase/zhcn": {
    --    "title": "",
    --    "resources": [
    --      "intl/zh-cn/distribute/tools/launch-checklist.html",
    --      "https://play.google.com/apps/publish/?hl=zh-Hans",
    --      "https://play.google.com/intl/en_us/badges/",
    --      "intl/zh-cn/distribute/tools/promote/device-art.html"
    --    ]
    --  },
    --  "distribute/essentials/tabletguidelines/googleplay": {
    --    "title": "",
    --    "resources": [
    --      "https://android-developers.blogspot.com/2013/10/more-visibility-for-tablet-apps-in.html",
    --      "google/play/filters.html"
    --    ]
    --  },
    -- "distribute/essentials/billionsquality/connectivity": {
    --    "title": "",
    --    "resources": [
    --      "training/basics/network-ops/managing.html",
    --      "training/monitoring-device-state/connectivity-monitoring.html",
    --      "guide/topics/providers/content-providers.html"
    --    ]
    --  },
    --  "distribute/essentials/billionsquality/capability": {
    --    "title": "",
    --    "resources": [
    --      "guide/practices/screens_support.html",
    --      "training/multiscreen/screendensities.html",
    --      "training/articles/memory.html"
    --    ]
    --  },
    --  "distribute/essentials/billionsquality/cost": {
    --    "title": "",
    --    "resources": [
    --      "https://medium.com/@wkalicinski/smallerapk-part-6-image-optimization-zopfli-webp-4c462955647d#.23hlddo3x",
    --      "training/basics/network-ops/managing.html"
    --    ]
    --  },
    --  "distribute/essentials/billionsquality/consumption": {
    --    "title": "",
    --    "resources": [
    --      "training/efficient-downloads/efficient-network-access.html",
    --      "training/monitoring-device-state/index.html"
    --    ]
    --  },
    --  "distribute/essentials/billionsquality/content": {
    --    "title": "",
    --    "resources": [
    --      "training/material/animations.html#Touch",
    --      "training/articles/perf-anr.html",
    --      "training/improving-layouts/index.html"
    --    ]
    --  },
    --  "distribute/essentials/tabletguidelines": {
    --    "title": "",
    --    "resources": [
    --      "distribute/essentials/quality/core.html",
    --      "https://android-developers.blogspot.com/2013/10/more-visibility-for-tablet-apps-in.html",
    --      "distribute/tools/launch-checklist.html",
    --      "distribute/tools/promote/device-art.html"
    --    ]
    --  },
    --  "distribute/getusers/notifications": {
    --    "title": "",
    --    "resources": [
    --      "distribute/engage/gcm.html",
    --      "https://play.google.com/about/developer-content-policy.html"
    --    ]
    --  },
    --  "distribute/engage/analytics": {
    --    "title": "",
    --    "resources": [
    --      "https://www.google.com/analytics/mobile/",
    --      "https://android-developers.blogspot.com/2013/10/improved-app-insight-by-linking-google.html",
    --      "https://developers.google.com/analytics/devguides/collection/android/"
    --    ]
    --  },
    --  "distribute/engage/widgets": {
    --    "title": "",
    --    "resources": [
    --      "design/patterns/widgets.html",
    --      "guide/topics/appwidgets/index.html"
    --    ]
    --  },
    --  "distribute/engage/translate": {
    --    "title": "",
    --    "resources": [
    --      "https://support.google.com/l10n/answer/6359997"
    --    ]
    --  },
    --  "distribute/engage/reengage": {
    --    "title": "",
    --    "resources": [
    --      "https://support.google.com/adwords/answer/6032073",
    --      "distribute/engage/deep-linking.html",
    --      "https://support.google.com/adwords/answer/6167162",
    --      "distribute/users/promote-with-ads.html"
    --    ]
    --  },
    --  "distribute/engage/appindexing": {
    --    "title": "",
    --    "resources": [
    --      "distribute/engage/intents.html",
    --      "distribute/engage/deep-linking.html",
    --      "training/app-indexing/index.html"
    --    ]
    --  },
    --  "distribute/engage/intents": {
    --    "title": "",
    --    "resources": [
    --      "guide/components/intents-filters.html",
    --      "distribute/engage/deep-linking.html",
    --      "distribute/engage/ads.html"
    --    ]
    --  },
    --  "distribute/getusers/expandnewmarkets": {
    --    "title": "",
    --    "resources": [
    --      "distribute/tools/localization-checklist.html",
    --      "https://support.google.com/googleplay/android-developer/table/3541286",
    --      "https://play.google.com/intl/en_us/badges/",
    --      "distribute/tools/promote/device-art.html",
    --      "https://www.youtube.com/watch?v=SkHHPf3EdzE"
    --    ]
    --  },
    --  "distribute/engage/gcm": {
    --    "title": "",
    --    "resources": [
    --      "https://developers.google.com/cloud-messaging/gcm",
    --      "https://developers.google.com/cloud-messaging/android/client",
    --    ]
    --  },
    --  "distribute/engage/gamesservices/related": {
    --    "title": "",
    --    "resources": [
    --      "https://developers.google.com/games/services/",
    --      "distribute/analyze/start.html",
    --      "distribute/googleplay/cardboard.html",
    --      "https://www.google.com/admob/"
    --    ]
    --  },
    --  "distribute/engage/gplus": {
    --    "title": "",
    --    "resources": [
    --      "distribute/users/ota-installs.html",
    --      "https://developers.google.com/identity/sign-in/android/people",
    --      "https://developers.google.com/+/mobile/android/"
    --    ]
    --  },
    --  "distribute/engage/community": {
    --    "title": "",
    --    "resources": [
    --      "distribute/users/build-community.html",
    --      "distribute/engage/video.html"
    --    ]
    --  },
    --  "distribute/engage/deeplinks": {
    --    "title": "",
    --    "resources": [
    --      "distribute/engage/easy-signin.html",
    --      "https://developers.google.com/app-indexing/",
    --      "https://developers.google.com/+/mobile/android/share/interactive-post"
    --    ]
    --  },
    --  "distribute/engage/appupdates": {
    --    "title": "",
    --    "resources": [
    --      "distribute/essentials/optimizing-your-app.html",
    --      "distribute/tools/launch-checklist.html",
    --      "distribute/googleplay/developer-console.html"
    --    ]
    --  },
    --  "distribute/engage/video/more": {
    --    "title": "",
    --    "resources": [
    --      "https://www.youtube.com/yt/dev/",
    --      "distribute/essentials/best-practices/games.html",
    --      "https://www.youtube.com/watch?v=RRelFvc6Czo"
    --    ]
    --  },
    --  "distribute/engage/community": {
    --    "title": "",
    --    "resources": [
    --      "distribute/users/build-community.html",
    --      "distribute/engage/video.html"
    --    ]
    --  },
    --  "distribute/engage/kiwi": {
    --    "title": "",
    --    "resources": [
    --      "https://www.youtube.com/watch?v=WWArLD6nqrk"
    --    ]
    --  },
    --  "distribute/toolsreference/gpfefaq": {
    --    "title": "",
    --    "resources": [
    --      "https://www.google.com/edu/tablets/",
    --      "distribute/googleplay/edu/start.html",
    --      "https://play.google.com/about/developer-distribution-agreement-addendum.html",
    --      "distribute/essentials/quality/core.html",
    --      "distribute/essentials/quality/tablets.html"
    --    ]
    --  },
    --  "distribute/toolsreference/localizationchecklist/identifylocales": {
    --    "title": "",
    --    "resources": [
    --      "https://support.google.com/googleplay/android-developer/answer/138294"
    --    ]
    --  },
    --  "distribute/toolsreference/localizationchecklist/identifylocales/zhcn": {
    --    "title": "",
    --    "resources": [
    --      "https://support.google.com/googleplay/android-developer/answer/138294?hl=zh-Hans"
    --    ]
    --  },
    --  "distribute/tools/loc/designforloc": {
    --    "title": "",
    --    "resources": [
    --      "https://android-developers.blogspot.com/2013/03/native-rtl-support-in-android-42.html",
    --      "guide/topics/resources/string-resource.html#Plurals",
    --      "guide/topics/resources/string-resource.html",
    --      "reference/java/util/Locale.html"
    --    ]
    --  },
    --  "distribute/toolsreference/localizationchecklist/managestrings": {
    --    "title": "",
    --    "resources": [
    --      "guide/topics/resources/string-resource.html",
    --      "design/style/writing.html",
    --      "https://en.wikipedia.org/wiki/XLIFF"
    --    ]
    --  },
    --  "distribute/toolsreference/localizationchecklist/managestrings/zhcn": {
    --    "title": "",
    --    "resources": [
    --      "guide/topics/resources/string-resource.html",
    --      "intl/zh-cn/design/style/writing.html",
    --      "https://en.wikipedia.org/wiki/XLIFF"
    --    ]
    --  },
    --  "distribute/toolsreference/localizationchecklist/preplaunch": {
    --    "title": "",
    --    "resources": [
    --      "https://play.google.com/intl/en_us/badges/",
    --      "distribute/tools/promote/device-art.html"
    --    ]
    --  },
    --  "distribute/toolsreference/localizationchecklist/preplaunch/zhcn": {
    --    "title": "",
    --    "resources": [
    --      "https://play.google.com/intl/en_us/badges/",
    --      "intl/zh-cn/distribute/tools/promote/device-art.html"
    --    ]
    --  },
    --  "distribute/toolsreference/localizationchecklist/supportlaunch": {
    --    "title": "",
    --    "resources": [
    --      "distribute/tools/launch-checklist.html",
    --    ]
    --  },
    --  "distribute/toolsreference/localizationchecklist/supportlaunch/zhcn": {
    --    "title": "",
    --    "resources": [
    --      "intl/zh-cn/distribute/tools/launch-checklist.html",
    --    ]
    --  },
    --  "distribute/toolsreference/launchchecklist/understanding": {
    --    "title": "",
    --    "resources": [
    --      "tools/publishing/publishing_overview.html",
    --      "tools/publishing/preparing.html"
    --    ]
    --  },
    --  "distribute/toolsreference/launchchecklist/policies": {
    --    "title": "",
    --    "resources": [
    --      "https://support.google.com/googleplay/android-developer/answer/4430948",
    --      "https://support.google.com/googleplay/android-developer/topic/2364761",
    --      "https://support.google.com/googleplay/android-developer"
    --    ]
    --  },
    --  "distribute/toolsreference/launchchecklist/quality": {
    --    "title": "",
    --    "resources": [
    --      "distribute/essentials/quality/core.html",
    --      "distribute/essentials/quality/tablets.html",
    --      "https://developers.google.com/edu/guidelines"
    --    ]
    --  },
    --  "distribute/toolsreference/launchchecklist/rating": {
    --    "title": "",
    --    "resources": [
    --      "https://support.google.com/googleplay/android-developer/answer/188189",
    --    ]
    --  },
    --  "distribute/toolsreference/launchchecklist/country": {
    --    "title": "",
    --    "resources": [
    --      "https://support.google.com/googleplay/android-developer/answer/138294"
    --    ]
    --  },
    --  "distribute/toolsreference/launchchecklist/size": {
    --    "title": "",
    --    "resources": [
    --      "google/play/expansion-files.html",
    --      "tools/help/proguard.html"
    --    ]
    --  },
    --  "distribute/toolsreference/launchchecklist/platform": {
    --    "title": "",
    --    "resources": [
    --      "guide/practices/screens_support.html",
    --      "about/dashboards/index.html",
    --      "guide/topics/manifest/uses-sdk-element.html"
    --    ]
    --  },
    --  "distribute/toolsreference/launchchecklist/price": {
    --    "title": "",
    --    "resources": [
    --      "https://support.google.com/googleplay/android-developer/table/3541286",
    --    ]
    --  },
    --  "distribute/toolsreference/launchchecklist/purchasemethod": {
    --    "title": "",
    --    "resources": [
    --      "google/play/billing/index.html",
    --      "google/play/billing/billing_subscriptions.html"
    --    ]
    --  },
    --  "distribute/toolsreference/launchchecklist/setprice": {
    --    "title": "",
    --    "resources": [
    --      "https://support.google.com/googleplay/android-developer/answer/1169947",
    --      "https://support.google.com/googleplay/android-developer/answer/138412",
    --      "https://support.google.com/googleplay/android-developer/answer/112622",
    --      "https://support.google.com/googleplay/android-developer/answer/138000"
    --    ]
    --  },
    --  "distribute/toolsreference/launchchecklist/localization": {
    --    "title": "",
    --    "resources": [
    --      "distribute/tools/localization-checklist.html",
    --      "https://support.google.com/l10n/answer/6359997"
    --    ]
    --  },
    --  "distribute/toolsreference/launchchecklist/graphics": {
    --    "title": "",
    --    "resources": [
    --      "https://support.google.com/googleplay/android-developer/answer/1078870",
    --      "https://android-developers.blogspot.com/2011/10/android-market-featured-image.html"
    --    ]
    --  },
    --  "distribute/toolsreference/launchchecklist/productdetails": {
    --    "title": "",
    --    "resources": [
    --      "https://support.google.com/googleplay/android-developer/answer/113475",
    --      "https://support.google.com/googleplay/android-developer/answer/1078870"
    --    ]
    --  },
    --  "distribute/toolsreference/launchchecklist/badges": {
    --    "title": "",
    --    "resources": [
    --      "https://play.google.com/intl/en_us/badges/",
    --      "distribute/tools/promote/linking.html"
    --    ]
    --  },
    --  "distribute/toolsreference/launchchecklist/finalchecks": {
    --    "title": "",
    --    "resources": [
    --      "https://play.google.com/about/developer-content-policy.html",
    --      "https://support.google.com/googleplay/android-developer/answer/113476",
    --      "support.html"
    --    ]
    --  },
    --  "distribute/toolsreference/launchchecklist/afterlaunch": {
    --    "title": "",
    --    "resources": [
    --      "https://support.google.com/googleplay/android-developer/answer/113477",
    --      "https://support.google.com/googleplay/android-developer/answer/1153479",
    --      "https://support.google.com/payments/answer/2741495",
    --      "distribute/essentials/optimizing-your-app.html"
    --    ]
    --  },
    --  "distribute/toolsreference/launchchecklist/understanding/zhcn": {
    --    "title": "",
    --    "resources": [
    --      "intl/zh-cn/tools/publishing/publishing_overview.html",
    --      "intl/zh-cn/tools/publishing/preparing.html"
    --    ]
    --  },
    --  "distribute/toolsreference/launchchecklist/policies/zhcn": {
    --    "title": "",
    --    "resources": [
    --      "https://support.google.com/googleplay/android-developer/answer/4430948?hl=zh-Hans",
    --      "https://support.google.com/googleplay/android-developer/topic/2364761?hl=zh-Hans",
    --      "https://support.google.com/googleplay/android-developer?hl=zh-Hans"
    --    ]
    --  },
    --  "distribute/toolsreference/launchchecklist/quality/zhcn": {
    --    "title": "",
    --    "resources": [
    --      "intl/zh-cn/distribute/essentials/quality/core.html",
    --      "intl/zh-cn/distribute/essentials/quality/tablets.html",
    --      "https://developers.google.com/edu/guidelines?hl=zh-Hans"
    --    ]
    --  },
    --
    --  "distribute/toolsreference/launchchecklist/rating/zhcn": {
    --    "title": "",
    --    "resources": [
    --      "https://support.google.com/googleplay/android-developer/answer/188189?hl=zh-Hans",
    --    ]
    --  },
    --  "distribute/toolsreference/launchchecklist/country/zhcn": {
    --    "title": "",
    --    "resources": [
    --      "https://support.google.com/googleplay/android-developer/answer/138294?hl=zh-Hans"
    --    ]
    --  },
    --  "distribute/toolsreference/launchchecklist/size/zhcn": {
    --    "title": "",
    --    "resources": [
    --      "google/play/expansion-files.html",
    --      "intl/zh-cn/tools/help/proguard.html"
    --    ]
    --  },
    --  "distribute/toolsreference/launchchecklist/price/zhcn": {
    --    "title": "",
    --    "resources": [
    --      "https://support.google.com/googleplay/android-developer/table/3541286?hl=zh-Hans",
    --    ]
    --  },
    --  "distribute/toolsreference/launchchecklist/purchasemethod/zhcn": {
    --    "title": "",
    --    "resources": [
    --      "intl/zh-cn/google/play/billing/index.html",
    --      "google/play/billing/billing_subscriptions.html"
    --    ]
    --  },
    --  "distribute/toolsreference/launchchecklist/setprice/zhcn": {
    --    "title": "",
    --    "resources": [
    --      "https://support.google.com/googleplay/android-developer/answer/1169947?hl=zh-Hans",
    --      "https://support.google.com/googleplay/android-developer/answer/138412?hl=zh-Hans",
    --      "https://support.google.com/googleplay/android-developer/answer/112622?hl=zh-Hans",
    --      "https://support.google.com/googleplay/android-developer/answer/138000?hl=zh-Hans"
    --    ]
    --  },
    --  "distribute/stories/localization": {
    --    "title": "",
    --    "resources": [
    --      "distribute/stories/games/rvappstudios-zombie.html",
    --      "distribute/stories/games/g4a-indian-rummy.html",
    --      "distribute/stories/apps/sayhi.html"
    --    ]
    --  },
    --  "distribute/toolsreference/launchchecklist/localization/zhcn": {
    --    "title": "",
    --    "resources": [
    --      "intl/zh-cn/distribute/tools/localization-checklist.html",
    --    ]
    --  },
    --  "distribute/toolsreference/launchchecklist/graphics/zhcn": {
    --    "title": "",
    --    "resources": [
    --      "https://support.google.com/googleplay/android-developer/answer/1078870?hl=zh-Hans",
    --      "https://android-developers.blogspot.com/2011/10/android-market-featured-image.html"
    --    ]
    --  },
    --  "distribute/toolsreference/launchchecklist/productdetails/zhcn": {
    --    "title": "",
    --    "resources": [
    --      "https://support.google.com/googleplay/android-developer/answer/113475?hl=zh-Hans",
    --      "https://support.google.com/googleplay/android-developer/answer/1078870?hl=zh-Hans"
    --    ]
    --  },
    --  "distribute/toolsreference/launchchecklist/badges/zhcn": {
    --    "title": "",
    --    "resources": [
    --      "https://play.google.com/intl/en_us/badges/",
    --      "intl/zh-cn/distribute/tools/promote/linking.html"
    --    ]
    --  },
    --  "distribute/toolsreference/launchchecklist/finalchecks/zhcn": {
    --    "title": "",
    --    "resources": [
    --      "https://play.google.com/about/developer-content-policy.html",
    --      "https://support.google.com/googleplay/android-developer/answer/113476?hl=zh-Hans",
    --      "support.html"
    --    ]
    --  },
    --  "distribute/toolsreference/launchchecklist/afterlaunch/zhcn": {
    --    "title": "",
    --    "resources": [
    --      "https://support.google.com/googleplay/android-developer/answer/113477?hl=zh-Hans",
    --      "https://support.google.com/googleplay/android-developer/answer/1153479?hl=zh-Hans",
    --      "https://support.google.com/payments/answer/2741495?hl=zh-Hans",
    --      "distribute/essentials/optimizing-your-app.html"
    --    ]
    --  },
    --  "distribute/monetize/premium": {
    --    "title": "",
    --    "resources": [
    --      "google/play/billing/index.html",
    --      "https://support.google.com/googleplay/android-developer/answer/4407611"
    --    ]
    --  },
    --  "distribute/monetize/freemium": {
    --    "title": "",
    --    "resources": [
    --      "google/play/billing/index.html",
    --      "https://support.google.com/googleplay/android-developer/answer/4407611"
    --    ]
    --  },
    --  "distribute/monetize/subscriptions": {
    --    "title": "",
    --    "resources": [
    --      "google/play/billing/billing_subscriptions.html",
    --      "https://support.google.com/googleplay/android-developer/answer/4407611"
    --    ]
    --  },
    --  "distribute/monetize/ecommerce": {
    --    "title": "",
    --    "resources": [
    --      "https://developers.google.com/wallet/instant-buy/",
    --      "https://support.google.com/googleplay/android-developer/answer/4407611"
    --    ]
    --  },
    --  "distribute/monetize/advertising": {
    --    "title": "",
    --    "resources": [
    --      "https://www.google.com/ads/admob/#subid=us-en-et-dac",
    --      "https://www.google.com/doubleclick/publishers/small-business/index.html",
    --      "https://support.google.com/googleplay/android-developer/topic/2985714",
    --      "training/monetization/ads-and-ux.html"
    --    ]
    --  },
    --  "distribute/monetize/admob": {
    --    "title": "",
    --    "resources": [
    --      "https://support.google.com/admob/topic/2784623",
    --      "https://admob.blogspot.com/",
    --      "https://analyticsacademy.withgoogle.com/mobile-app",
    --      "https://www.udacity.com/courses/ud876-3"
    --    ]
    --  },
    --  "distribute/monetize/paymentmethods": {
    --    "title": "",
    --    "resources": [
    --      "https://play.google.com/about/giftcards/",
    --      "https://support.google.com/googleplay/answer/2651410"
    --    ]
    --  },
    --  "distribute/monetize/conversions": {
    --    "title": "",
    --    "resources": [
    --      "https://support.google.com/adwords/answer/2471188",
    --      "https://developers.google.com/app-conversion-tracking/",
    --      "https://support.google.com/analytics/answer/2611404",
    --      "https://support.google.com/adwords/answer/1704341"
    --    ]
    --  },
    --  "autolanding": {
    --    "title": "",
    --    "resources": [
    --      "auto/index.html",
    --      "design/auto/index.html",
    --      "training/auto/index.html"
    --    ]
    --  },
    --  "tvlanding": {
    --    "title": "",
    --    "resources": [
    --      "tv/index.html",
    --      "design/tv/index.html",
    --      "training/tv/index.html"
    --    ]
    --  },
    --  "wearlanding": {
    --    "title": "",
    --    "resources": [
    --      "design/wear/index.html",
    --      "training/building-wearables.html",
    --      "training/wearables/ui/index.html"
    --    ]
    --  },
    --  "design/auto/auto_ui_guidelines": {
    --    "title": "",
    --    "resources": [
    --      "shareables/auto/AndroidAuto-audio-apps.pdf",
    --      "shareables/auto/AndroidAuto-messaging-apps.pdf",
    --      "shareables/auto/AndroidAuto-custom-colors.pdf"
    --    ]
    --  },
    --  "training/auto/overview": {
    --    "title": "",
    --    "resources": [
    --      "training/auto/start/index.html",
    --      "design/auto/index.html",
    --      "shareables/auto/AndroidAuto-custom-colors.pdf"
    --    ]
    --  },
    --  "training/auto/messaging": {
    --    "title": "",
    --    "resources": [
    --      "training/auto/messaging/index.html",
    --      "shareables/auto/AndroidAuto-messaging-apps.pdf",
    --      "samples/MessagingService/index.html"
    --    ]
    --  },
    --  "training/auto/media": {
    --    "title": "",
    --    "resources": [
    --      "training/auto/audio/index.html",
    --      "shareables/auto/AndroidAuto-audio-apps.pdf",
    --      "samples/MediaBrowserService/index.html"
    --    ]
    --  },
    --  "training/auto/distribute": {
    --    "title": "",
    --    "resources": [
    --      "distribute/essentials/quality/auto.html",
    --      "distribute/googleplay/auto.html"
    --    ]
    --  },
    --  "training/testing/overview": {
    --    "title": "",
    --    "resources": [
    --      "training/testing/start/index.html",
    --      "tools/testing/testing_android.html",
    --      "https://www.youtube.com/watch?v=vdasFFfXKOY"
    --    ]
    --  },
    --  "training/testing/tools": {
    --    "title": "",
    --    "resources": [
    --      "tools/testing-support-library/index.html",
    --      "tools/help/monkey.html",
    --      "tools/help/monkeyrunner_concepts.html",
    --      "tools/testing/testing_otheride.html",
    --      "https://source.android.com/devices/tech/debug/dumpsys.html"
    --    ]
    --  },
    --  "training/testing/techniques": {
    --    "title": "",
    --    "resources": [
    --      "training/testing/ui-testing/index.html",
    --      "training/testing/unit-testing/index.html",
    --      "training/testing/performance.html"
    --    ]
    --  },
    --  "training/testing/resources": {
    --    "title": "",
    --    "resources": [
    --      "https://github.com/googlesamples/android-testing",
    --      "https://www.youtube.com/watch?v=2I6fuD20qlY",
    --      "https://codelabs.developers.google.com/codelabs/android-testing/index.html",
    --      "https://github.com/googlesamples/android-testing-templates",
    --      "https://google.github.io/android-testing-support-library"
    --    ]
    --  },
    --  "distribute/stories/games": {
    --    "title": "",
    --    "resources": [
    --      "https://storage.googleapis.com/androiddevelopers/shareables/stories/Glu_Deerhunter2014_gpgs.pdf",
    --      "https://storage.googleapis.com/androiddevelopers/shareables/stories/ConcreteSoftware_PBABowling_gpgs.pdf",
    --      "https://storage.googleapis.com/androiddevelopers/shareables/stories/Dragonplay_DragonplaySlots_gpgs.pdf",
    --      "https://storage.googleapis.com/androiddevelopers/shareables/stories/Gameloft_Asphalt8_gpgs.pdf",
    --      "https://storage.googleapis.com/androiddevelopers/shareables/stories/Glu_EternityWarriors3_gpgs.pdf",
    --      "https://storage.googleapis.com/androiddevelopers/shareables/stories/HotheadGames_RivalsatWar_gpgs.pdf",
    --      "https://storage.googleapis.com/androiddevelopers/shareables/stories/TMSOFT_Compulsive_gpgs.pdf",
    --      "https://storage.googleapis.com/androiddevelopers/shareables/stories/Noodlecake_SuperStickmanGolf2_gpgs.pdf",
    --      "https://storage.googleapis.com/androiddevelopers/shareables/stories/TinyRebel_DoctorWhoLegacy_gpgs.pdf",
    --      "https://storage.googleapis.com/androiddevelopers/shareables/stories/Senri_LeosFortune_gpgs.pdf"
    --    ]
    --  },
    --  "overview/zhcn/1": {
    --    "title": "",
    --    "resources": [
    --      "intl/zh-cn/distribute/essentials/quality/core.html",
    --      "intl/zh-cn/distribute/essentials/quality/tablets.html",
    --      "intl/zh-cn/distribute/tools/launch-checklist.html",
    --      "intl/zh-cn/tools/publishing/publishing_overview.html",
    --      "intl/zh-cn/distribute/tools/localization-checklist.html"
    --    ]
    --  },
    --    "overview/zhcn/2": {
    --    "title": "",
    --    "resources": [
    --      "intl/zh-cn/google/play/billing/index.html",
    --      "intl/zh-cn/google/play/billing/api.html",
    --      "intl/zh-cn/google/play/billing/billing_admin.html",
    --      "intl/zh-cn/google/play/billing/billing_testing.html",
    --      "intl/zh-cn/google/play/billing/billing_best_practices.html"
    --    ]
    --  },
    --  "overview/zhcn/3": {
    --    "title": "",
    --    "resources": [
    --      "https://play.google.com/intl/en_us/badges/",
    --
    --      "intl/zh-cn/distribute/tools/promote/device-art.html",
    --      "intl/zh-cn/distribute/tools/promote/linking.html",
    --      "intl/zh-cn/distribute/tools/promote/brand.html",
    --      "intl/zh-cn/tools/help/proguard.html"
    --    ]
    --  },
    --  "overview/zhcn/4": {
    --    "title": "",
    --    "resources": [
    --      "intl/zh-cn/design/style/writing.html",
    --      "intl/zh-cn/training/basics/fragments/fragment-ui.html",
    --      "intl/zh-cn/training/multiscreen/index.html",
    --      "intl/zh-cn/training/monitoring-device-state/index.html"
    --    ]
    --  },
    --  "overview/carousel/zhcn": {
    --    "title": "",
    --    "resources": [
    --      "https://www.youtube.com/watch?v=vGV7FHGzpFU",
    --      "https://www.youtube.com/watch?v=aqc3ZOTzpdk",
    --      "https://www.youtube.com/watch?v=jaNrJ8uyLSc"
    --    ]
    --  },
    --  "overview/1": {
    --    "title": "",
    --    "resources": [
    --      "distribute/essentials/quality/core.html",
    --      "distribute/essentials/quality/tablets.html",
    --      "distribute/tools/launch-checklist.html",
    --      "tools/publishing/publishing_overview.html",
    --      "distribute/tools/localization-checklist.html"
    --    ]
    --  },
    --    "overview/2": {
    --    "title": "",
    --    "resources": [
    --      "google/play/billing/index.html",
    --      "google/play/billing/api.html",
    --      "google/play/billing/billing_admin.html",
    --      "google/play/billing/billing_testing.html",
    --      "google/play/billing/billing_best_practices.html"
    --    ]
    --  },
    --  "overview/3": {
    --    "title": "",
    --    "resources": [
    --      "https://play.google.com/intl/en_us/badges/",
    --      "distribute/tools/promote/device-art.html",
    --      "distribute/tools/promote/linking.html",
    --      "distribute/tools/promote/brand.html",
    --      "tools/help/proguard.html"
    --    ]
    --  },
    --  "overview/4": {
    --    "title": "",
    --    "resources": [
    --      "design/style/writing.html",
    --      "training/basics/fragments/fragment-ui.html",
    --      "training/multiscreen/index.html",
    --      "training/monitoring-device-state/index.html"
    --    ]
    --  },
    --"tools/help/log": {
    --    "title": "",
    --    "resources": [
    --       "tools/help/am-logcat.html"
    --    ]
    --  },
    --"tools/help/monitor": {
    --    "title": "",
    --    "resources": [
    --       "tools/help/am-memory.html",
    --       "tools/help/am-cpu.html",
    --       "tools/help/am-gpu.html",
    --       "tools/help/am-network.html"
    --    ]
    --  },
    -- "tools/help/data": {
    --    "title": "",
    --    "resources": [
    --       "tools/help/am-hprof.html",
    --       "tools/help/am-allocation.html",
    --       "tools/help/am-methodtrace.html",
    --       "tools/help/am-sysinfo.html"
    --    ]
    --  },
    --  "tools/help/shot": {
    --    "title": "",
    --    "resources": [
    --       "tools/help/am-screenshot.html",
    --       "tools/help/am-video.html"
    --    ]
    --  },
    --  "tools/performance/rendering": {
    --    "title": "",
    --    "resources": [
    --       "tools/performance/debug-gpu-overdraw/index.html",
    --       "tools/performance/profile-gpu-rendering/index.html",
    --       "tools/performance/hierarchy-viewer/setup.html",
    --       "tools/performance/hierarchy-viewer/index.html",
    --       "tools/performance/hierarchy-viewer/profiling.html"
    --    ]
    --  },
    --  "tools/performance/memory": {
    --    "title": "",
    --    "resources": [
    --       "tools/performance/memory-monitor/index.html",
    --       "tools/performance/heap-viewer/index.html",
    --       "tools/performance/allocation-tracker/index.html",
    --       "tools/performance/comparison.html"
    --    ]
    --  },
    --  "tools/performance/cpu": {
    --    "title": "",
    --    "resources": [
    --       "tools/performance/traceview/index.html",
    --       "tools/performance/systrace/index.html"
    --    ]
    --  },
    --  "tools/performance/battery": {
    --    "title": "",
    --    "resources": [
    --       "tools/performance/batterystats-battery-historian/index.html",
    --       "tools/performance/batterystats-battery-historian/charts.html"
    --    ]
    --  },
    --  "marshmallow/landing/resources": {
    --    "title": "",
    --    "resources": [
    --       "about/versions/marshmallow/android-6.0-changes.html",
    --       "about/versions/marshmallow/android-6.0.html",
    --       "about/versions/marshmallow/samples.html"
    --    ]
    --  },
    --  "marshmallow/landing/videos": {
    --    "title": "",
    --    "resources": [
    --       "https://youtu.be/U9tw5ypqEN0",
    --       "https://youtu.be/N72ksDKrX6c",
    --       "https://youtu.be/iZqDdvhTZj0",
    --       "https://www.youtube.com/watch?v=vcSj8ln-BlE",
    --       "https://youtu.be/LQoohRwojmw",
    --       "https://www.youtube.com/watch?v=VOn7VrTRlA4",
    --       "https://youtu.be/5sCQjeGoE7M",
    --       "https://www.youtube.com/watch?v=C8lUdPVSzDk",
    --       "https://www.youtube.com/watch?v=HXacyy0HSW0",
    --       "https://www.youtube.com/watch?v=OW1A4XFRuyc",
    --       "https://www.youtube.com/watch?v=j3QC6hcpy90",
    --       "https://www.youtube.com/watch?v=f17qe9vZ8RM",
    --       "https://www.youtube.com/watch?v=ndBdf1_oOGA"
    --    ]
    --  },
    --  "marshmallow/landing/more": {
    --    "title": "",
    --    "resources": [
    --      "training/permissions/requesting.html",
    --      "training/backup/autosyncapi.html",
    --      "training/monitoring-device-state/doze-standby.html",
    --      "training/app-links/index.html",
    --      "training/articles/assistant.html",
    --      "training/testing/performance.html",
    --      "https://developers.google.com/android/nexus/images"
    --    ]
    --  },
    --  "tools/landing/resources": {
    --    "title": "",
    --    "resources": [
    --    "tools/studio/index.html",
    --    "tools/studio/studio-features.html",
    --    "studio/intro/index.html",
    --    ]
    --  },
    --  "tools/landing/latest": {
    --    "title": "",
    --    "resources": [
    --    "https://medium.com/google-developers/how-often-should-you-update-android-studio-db25785c488e#.8blbql35x",
    --    "http://android-developers.blogspot.com/2016/04/android-studio-2-0.html",
    --    "https://medium.com/google-developers/writing-more-code-by-writing-less-code-with-android-studio-live-templates-244f648d17c7#.hczcm02du",
    --    ]
    --  },
    --  "work/landing/primary": {
    --    "title": "",
    --    "resources": [
    --      "work/overview.html",
    --      "work/guide.html",
    --      "https://www.google.com/work/android/developers/applyDevHub/",
    --      "work/managed-configurations.html",
    --      "work/cosu.html",
    --      "work/managed-profiles.html"
    --    ]
    --  },
    --  "work/landing/resources": {
    --    "title": "",
    --    "resources": [
    --      "https://developers.google.com/android/work/",
    --      "https://www.google.com/work/android/",
    --      "https://developers.google.com/android/work/build-dpc",
    --      "https://www.youtube.com/watch?v=jQWB_-o1kz4&list=PLOU2XLYxmsIKAK2Bhv19H2THwF-22O5WX",
    --      "https://www.youtube.com/watch?v=Za0OQo8DRM4",
    --      "https://www.youtube.com/watch?v=dH41OutAMNM&list=PLOU2XLYxmsIKAK2Bhv19H2THwF-22O5WX"
    --    ]
    --  },
    --  "work/apps": {
    --    "title": "",
    --    "resources": [
    --      "work/managed-profiles.html",
    --      "work/managed-configurations.html",
    --      "work/cosu.html",
    --      "https://www.youtube.com/watch?v=39NkpWkaH8M&index=2&list=PLOU2XLYxmsIKAK2Bhv19H2THwF-22O5WX",
    --      "samples/AppRestrictionSchema/index.html",
    --      "samples/AppRestrictionEnforcer/index.html"
    --    ]
    --  },
    --  "work/admin": {
    --    "title": "",
    --    "resources": [
    --      "https://developers.google.com/android/work/build-dpc",
    --      "samples/BasicManagedProfile/index.html",
    --      "https://www.youtube.com/watch?v=j3QC6hcpy90"
    --    ]
    --  }
    --};
    -diff --git a/docs/html/jd_extras.js b/docs/html/jd_extras.js
    -deleted file mode 100644
    -index 44ccafa..0000000
    ---- a/docs/html/jd_extras.js
    -+++ /dev/null
    -@@ -1,4120 +0,0 @@
    --/*
    -- * THIS FILE IS DEPRECATED.
    -- *
    -- * Please add and edit resource collections in jd_extras_<lang>.js
    -- * where lang matches the language code appropriate for the resource.
    -- * Last sync'd with jd_extras_<lang>.js on 29 Apr 2016.
    -- *
    -- */
    --DISTRIBUTE_RESOURCES = DISTRIBUTE_RESOURCES.concat([
    -- /* TODO Remove standard resources from here, such as below
    -- */
    --  {
    --    "title":"Writing More Code by Writing Less Code with Android Studio Live Templates",
    --    "titleFriendly":"",
    --    "summary":"Unless you’re getting paid by the keystroke, no one wants to write repetitive boilerplate code.",
    --    "url":"https://medium.com/google-developers/writing-more-code-by-writing-less-code-with-android-studio-live-templates-244f648d17c7#.hczcm02du",
    --    "group":"",
    --    "keywords": [],
    --    "tags": ['studio'],
    --    "image":"https://cdn-images-1.medium.com/max/800/1*JkrYXGs1AxZAbK0sCLrJAQ.gif",
    --    "type":"medium"
    --  },
    --  {
    --    "title":"How Often Should You Update Android Studio?",
    --    "titleFriendly":"",
    --    "summary":"One of the beauties of Android Studio is how quickly is evolves and improves.",
    --    "url":"https://medium.com/google-developers/how-often-should-you-update-android-studio-db25785c488e#.8blbql35x",
    --    "group":"",
    --    "keywords": [],
    --    "tags": ['studio'],
    --    "image":"https://cdn-images-1.medium.com/max/2000/1*chMiA9mGa_FBUOoesHHk3Q.png",
    --    "type":"medium"
    --  },
    --  {
    --    "title":"SmallerAPK, Part 6: Image optimization, Zopfli & WebP",
    --    "category":"",
    --    "summary":"Series of posts on minimizing your APK size.",
    --    "url":"https://medium.com/@wkalicinski/smallerapk-part-6-image-optimization-zopfli-webp-4c462955647d#.23hlddo3x",
    --    "group":"",
    --    "keywords": [],
    --    "tags": [],
    --    "image":"https://cdn-images-1.medium.com/max/2000/1*chMiA9mGa_FBUOoesHHk3Q.png",
    --    "type":"medium"
    --  },
    --  {
    --    "title":"Measure your app’s user acquisition channels",
    --    "titleFriendly":"",
    --    "summary":"Get details on how to use the Developer Console User Acquisitions reports to discover where your users come from.",
    --    "url":"https://support.google.com/googleplay/android-developer/answer/6263332",
    --    "group":"",
    --    "keywords": [],
    --    "tags": [],
    --    "image":"images/play_dev.jpg",
    --    "type":"google"
    --  },
    --  {
    --    "title":"Set up native app install banners in Chrome",
    --    "titleFriendly":"",
    --    "summary":"Get the details you need to add your native app or game to your site’s web app manifest file.",
    --    "url":"https://developers.google.com/web/updates/2015/03/increasing-engagement-with-app-install-banners-in-chrome-for-android#native",
    --    "group":"",
    --    "keywords": [],
    --    "tags": [],
    --    "image":"images/play_dev.jpg",
    --    "type":"google"
    --  },
    --  {
    --    "title":"Optimize your store listing pages with experiments",
    --    "titleFriendly":"",
    --    "summary":"You can run experiments to find the most effective graphics and localized text for your app.",
    --    "url":"https://support.google.com/googleplay/android-developer/answer/6227309",
    --    "group":"",
    --    "keywords": [],
    --    "tags": [],
    --    "image":"images/play_dev.jpg",
    --    "type":"google"
    --  },
    --  {
    --    "title":"Content Experiments for Mobile Apps",
    --    "titleFriendly":"",
    --    "summary":"Google Analytics Content Experiments allows you to test multiple variations of a given web page.",
    --    "url":"https://support.google.com/tagmanager/answer/6003007",
    --    "group":"",
    --    "keywords": [],
    --    "tags": [],
    --    "image":"images/play_dev.jpg",
    --    "type":"google"
    --  },
    --  {
    --    "title":"Store Listing Experiments for Google Play",
    --    "titleFriendly":"",
    --    "summary":"Learn how to use Google Play’s new store listing optimization feature to get more installs of your app.",
    --    "url":"https://www.youtube.com/watch?v=B6ydLpkhq04",
    --    "group":"",
    --    "keywords": [],
    --    "tags": [],
    --    "image":"https://i1.ytimg.com/vi/B6ydLpkhq04/maxresdefault.jpg",
    --    "type":"video"
    --  },
    --  {
    --    "title":"Use alpha/beta testing & staged rollouts",
    --    "titleFriendly":"",
    --    "summary":"Using the Google Play Developer Console, you can choose groups of users to test different versions of your app.",
    --    "url":"https://support.google.com/googleplay/android-developer/answer/3131213",
    --    "group":"",
    --    "keywords": [],
    --    "tags": [],
    --    "image":"images/play_dev.jpg",
    --    "type":"google"
    --  },
    --  {
    --    "title":"Quizlet Developer Story",
    --    "titleFriendly":"",
    --    "summary":"Quizlet is an extremely popular online learning tool for students. See how they optimized for the classroom with Android and the power of Google Play for Education.",
    --    "url":"https://www.youtube.com/watch?v=Idu7VcTTXfk",
    --    "group":"",
    --    "keywords": [],
    --    "tags": [
    --      "#gpfe",
    --      "#googleplay"
    --    ],
    --    "image":"https://i1.ytimg.com/vi/Idu7VcTTXfk/maxresdefault.jpg",
    --    "type":"video"
    --  },
    --  {
    --    "title":"What's New in GPFE",
    --    "titleFriendly":"",
    --    "summary":"Learn about the vision and philosophy behind Google Play for Education",
    --    "url":"https://www.youtube.com/watch?v=IKhU180eJMo",
    --    "group":"",
    --    "keywords": [],
    --    "tags": [
    --      "#gpfe",
    --      "#googleplay"
    --    ],
    --    "image":"https://i1.ytimg.com/vi/IKhU180eJMo/maxresdefault.jpg",
    --    "type":"video"
    --  },
    --  {
    --    "title":"Get started with Google Cast",
    --    "titleFriendly":"",
    --    "summary":"Build multi-screen experiences, let the user send video and audio content to TVs and speakers.",
    --    "url":"https://developers.google.com/cast/docs/ux_guidelines",
    --    "group":"",
    --    "keywords": ["cast", "chromecast", "video", "audio"],
    --    "tags": [],
    --    "image":"images/cards/card-cast_2x.jpg",
    --    "type":"Guide"
    --  },
    --  {
    --    "title":"Android Sender Applications",
    --    "titleFriendly":"",
    --    "summary":"Get an overview of how your Android app can act as a Google Cast sender app.",
    --    "url":"https://developers.google.com/cast/docs/android_sender",
    --    "group":"",
    --    "keywords": ["cast", "sender"],
    --    "tags": [],
    --    "image":"images/cards/card-cast_2x.jpg",
    --    "type":"Guide"
    --  },
    --  {
    --    "title":"Cast sample apps",
    --    "titleFriendly":"",
    --    "summary":"Get example Google Cast applications for both senders and receivers.",
    --    "url":"https://www.github.com/googlecast",
    --    "group":"",
    --    "keywords": ["cast", "samples"],
    --    "tags": [],
    --    "image":"images/cards/card-cast_2x.jpg",
    --    "type":"Samples"
    --  },
    --  {
    --    "title":"Get Cardboard",
    --    "titleFriendly":"",
    --    "summary":"Get your own Cardboard, today. Buy one from a manufacturer or build your own, and start developing.",
    --    "url":"https://www.google.com/get/cardboard/get-cardboard/",
    --    "group":"",
    --    "keywords": ["carboard","vr"],
    --    "tags": [],
    --    "image":"images/cards/card-cardboard_2x.png",
    --    "type":"Guide"
    --  },
    --    {
    --    "title":"Download the Cardboard SDK",
    --    "titleFriendly":"",
    --    "summary":"Grab the Cardboard libraries from GitHub and start creating VR apps in your favorite development environment.",
    --    "url":"https://developers.google.com/cardboard/android/download",
    --    "group":"",
    --    "keywords": ["carboard","vr"],
    --    "tags": [],
    --    "image":"images/cards/card-cardboard_2x.png",
    --    "type":"Guide"
    --  },
    --  {
    --    "title":"Cardboard design guidelines",
    --    "titleFriendly":"",
    --    "summary":"Focus on overall usability and avoiding common VR pitfalls while creating an immersive experience of your own.",
    --    "url":"https://www.google.com/design/spec-vr",
    --    "group":"",
    --    "keywords": ["carboard","vr"],
    --    "tags": [],
    --    "image":"images/cards/card-cardboard_2x.png",
    --    "type":"Design"
    --  },
    --  {
    --    "title":"Maps",
    --    "titleFriendly":"",
    --    "summary":"Give users the map that more than a billion people use every month.",
    --    "url":"https://developers.google.com/maps/documentation/android/",
    --    "group":"",
    --    "keywords": ["maps"],
    --    "tags": [],
    --    "image":"images/google/gps-maps.png",
    --    "type":"Guide"
    --  },
    --    {
    --    "title":"Places API",
    --    "titleFriendly":"",
    --    "summary":"give your users contextual information about where they are, when they’re there.",
    --    "url":"https://developers.google.com/places/android/",
    --    "group":"",
    --    "keywords": ["places","location", "context"],
    --    "tags": [],
    --    "image":"images/cards/card-places_2x.png",
    --    "type":"Guide"
    --  },
    --  {
    --    "title":"GCM Client for Android",
    --    "titleFriendly":"",
    --    "summary":"Send push notifications and pubsub from your server to Android devices around the world.",
    --    "url":"https://developers.google.com/cloud-messaging/android/client",
    --    "group":"",
    --    "keywords": ["push","gcm"],
    --    "tags": [],
    --    "image":"images/cards/card-google-cloud-messaging_16-9_2x.png",
    --    "type":"Guide"
    --  },
    --  {
    --    "title":"Google Cloud Messaging",
    --    "titleFriendly":"",
    --    "summary":"Learn about GCM and the kinds of services you can offer to users through push notifications",
    --    "url":"https://developers.google.com/cloud-messaging/gcm",
    --    "group":"",
    --    "keywords": ["push","gcm"],
    --    "tags": [],
    --    "image":"images/cards/card-google-cloud-messaging_16-9_2x.png",
    --    "type":"Guide"
    --  },
    --  {
    --    "title":"ClassDojo Developer Story",
    --    "titleFriendly":"",
    --    "summary":"ClassDojo is a classroom tool that helps teachers improve behavior in their classrooms quickly and easily. See how they optimized for the classroom with Android and the power of Google Play for Education.",
    --    "url":"https://www.youtube.com/watch?v=iokH4SAIfRw",
    --    "group":"",
    --    "keywords": [],
    --    "tags": [
    --      "#gpfe",
    --      "#googleplay"
    --    ],
    --    "image":"https://i1.ytimg.com/vi/iokH4SAIfRw/maxresdefault.jpg",
    --    "type":"video"
    --  },
    --  {
    --    "title":"Plan for Success",
    --    "titleFriendly":"",
    --    "summary":"5 tips from developers on creating great EDU apps.",
    --    "url":"https://www.youtube.com/watch?v=Eh2adsAyTKc",
    --    "group":"",
    --    "keywords": [],
    --    "tags": [
    --      "#gpfe",
    --      "#googleplay"
    --    ],
    --    "image":"https://i1.ytimg.com/vi/Eh2adsAyTKc/maxresdefault.jpg",
    --    "type":"video"
    --  },
    --  {
    --    "title":"Optimizing Apps for Education",
    --    "titleFriendly":"",
    --    "summary":"Learn how to optimize your app for teachers and students.",
    --    "url":"https://www.youtube.com/watch?v=_AZ6UcPz-_g",
    --    "group":"",
    --    "keywords": [],
    --    "tags": [
    --      "#gpfe",
    --      "#googleplay"
    --    ],
    --    "image":"https://i1.ytimg.com/vi/_AZ6UcPz-_g/maxresdefault.jpg",
    --    "type":"video"
    --  },
    --  {
    --    "title":"Ideas and Tools for Building Innovative Education Apps",
    --    "titleFriendly":"",
    --    "summary":"Are you hungry to build an awesome app for education but don't quite know where to start? Come hear about apps that teachers want, and the APIs you're going to need to build them! In particular, we'll talk about app ideas that combine APIs for Google Drive, Google Login, Android Single Task Mode and more to build transformative Educational apps that will delight educators and kids in and out of the classroom.",
    --    "url":"https://www.youtube.com/watch?v=iulXz8QTD1g",
    --    "group":"",
    --    "keywords": [],
    --    "tags": [
    --      "#gpfe",
    --      "#googleplay"
    --    ],
    --    "image":"https://i1.ytimg.com/vi/iulXz8QTD1g/maxresdefault.jpg",
    --    "type":"video"
    --  },
    --  {
    --    "title":"DesignBytes: Intro To Material Design",
    --    "titleFriendly":"",
    --    "summary":"These days, UI designers need to be thinking about phones, tablets, laptops, TVs, smartwatches, and beyond. In this DesignByte we talk about how Google designers have been working on making cross-platform and multi-screen design easier. We wanted to build a design system that felt at home on every screen, from the smallest watch to the largest TV.",
    --    "url":"https://www.youtube.com/watch?v=p4gmvHyuZzw",
    --    "group":"",
    --    "keywords": [],
    --    "tags": [
    --    ],
    --    "image":"https://i1.ytimg.com/vi/p4gmvHyuZzw/maxresdefault.jpg",
    --    "type":"video"
    --  },
    --  {
    --    "title":"DesignBytes: Paper and Ink: The Materials that Matter",
    --    "titleFriendly":"",
    --    "summary":"Join Rich Fulcher to learn about the materials of material design. See how virtual paper and ink form the foundation of your tactile user interface and master the rules that govern their behaviour.",
    --    "url":"https://www.youtube.com/watch?v=YaG_ljfzeUw",
    --    "group":"",
    --    "keywords": [],
    --    "tags": [
    --    ],
    --    "image":"https://i1.ytimg.com/vi/YaG_ljfzeUw/maxresdefault.jpg",
    --    "type":"video"
    --  },
    --  {
    --    "title":"DesignBytes: Material Design in the Google I/O App",
    --    "titleFriendly":"",
    --    "summary":"Roman Nurik shares details on the design process for the Google I/O 2014 app. To check out the app's source code, visit github.com/google/iosched.",
    --    "url":"https://www.youtube.com/watch?v=XOcCOBe8PTc",
    --    "group":"",
    --    "keywords": [],
    --    "tags": [
    --    ],
    --    "image":"https://i1.ytimg.com/vi/XOcCOBe8PTc/maxresdefault.jpg",
    --    "type":"video"
    --  },
    --  {
    --    "title":"Toolbars for a flexible Action Bar & more",
    --    "titleFriendly":"",
    --    "summary":"Toolbars are a flexible View you can add to your Android app which provides many of the same APIs as the system provided Action Bar, but can also do so much more such as reacting to scrolling or being integrated directly into your layouts.",
    --    "url":"https://www.youtube.com/watch?v=kmUGLURRPkI",
    --    "group":"",
    --    "keywords": [],
    --    "tags": [
    --    ],
    --    "image":"https://i1.ytimg.com/vi/kmUGLURRPkI/maxresdefault.jpg",
    --    "type":"video"
    --  },
    --  {
    --    "title":"Protecting Implicit Intents with Runtime Checks",
    --    "titleFriendly":"",
    --    "summary":"Make sure you protect your implicit intents with a simple runtime check.",
    --    "url":"https://www.youtube.com/watch?v=HGElAW224dE",
    --    "group":"",
    --    "keywords": [],
    --    "tags": [
    --    ],
    --    "image":"https://i1.ytimg.com/vi/HGElAW224dE/maxresdefault.jpg",
    --    "type":"video"
    --  },
    --  {
    --    "title":"Tabs and ViewPager",
    --    "titleFriendly":"",
    --    "summary":"Showing multiple screens or pages of content is easy with the help of ViewPager and a PagerAdapter. Combining that with tabs make for an effective top level navigation strategy for your app or for moving between content at the same level of hierarchy within your app.",
    --    "url":"https://www.youtube.com/watch?v=zQekzaAgIlQ",
    --    "group":"",
    --    "keywords": [],
    --    "tags": [
    --    ],
    --    "image":"https://i1.ytimg.com/vi/zQekzaAgIlQ/maxresdefault.jpg",
    --    "type":"video"
    --  },
    --  {
    --    "title":"Battery Drain and Networking",
    --    "titleFriendly":"",
    --    "summary":"Let’s take a moment to make something insanely clear: As far as battery is concerned, NETWORKING is the biggest, baddest, dirtiest offender there is. And optimizing performance here isn’t easy. Since the chip isn’t always awake and draining power, means you can optimize how it wakes up, sends traffic, and saves battery.",
    --    "url":"https://www.youtube.com/watch?v=fEEulSk1kNY",
    --    "group":"",
    --    "keywords": [],
    --    "tags": [
    --    ],
    --    "image":"https://i1.ytimg.com/vi/fEEulSk1kNY/maxresdefault.jpg",
    --    "type":"video"
    --  },
    --  {
    --    "title":"Batching Background Work Until Later",
    --    "titleFriendly":"",
    --    "summary":"Yes, your app is special. But when it comes to battery use, sometimes it’s better to be part of the crowd. Why not spread the battery blame around a bit? Ian Ni-Lewis shows you how ridiculously easy it is to go from battery hog to team player in this video.",
    --    "url":"https://www.youtube.com/watch?v=-3ry8PxcJJA",
    --    "group":"",
    --    "keywords": [],
    --    "tags": [
    --    ],
    --    "image":"https://i1.ytimg.com/vi/-3ry8PxcJJA/maxresdefault.jpg",
    --    "type":"video"
    --  },
    --  {
    --    "title":"The Performance Lifecycle",
    --    "titleFriendly":"",
    --    "summary":"Performance problems surface in your application at the least-wanted times (like right before you’re about to ship your first build). But don’t freak out: There’s a simple process that you can follow to help get your performance back under control.",
    --    "url":"https://www.youtube.com/watch?v=_kKTGK-Cb_4",
    --    "group":"",
    --    "keywords": [],
    --    "tags": [
    --    ],
    --    "image":"https://i1.ytimg.com/vi/_kKTGK-Cb_4/maxresdefault.jpg",
    --    "type":"video"
    --  },
    --  {
    --    "title":"Introduction to Android Studio",
    --    "titleFriendly":"",
    --    "summary":"Learn why you should migrate your projects to Android Studio now and how it can help you be more productive as a developer. Rich layout editor, handy suggestions and fixes, new Android project view - these are just some of the things you can expect from the IDE, which is built on the successful IntelliJ IDEA.",
    --    "url":"https://www.youtube.com/watch?v=K2dodTXARqc&list=PLWz5rJ2EKKc8I9gHTMh5yKkwRRGE8BjbQ",
    --    "group":"",
    --    "keywords": ["studio", "tools"],
    --    "tags": [
    --    ],
    --    "image":"https://i1.ytimg.com/vi/K2dodTXARqc/maxresdefault.jpg",
    --    "type":"video"
    --  },
    --
    --  {
    --    "title":"Google Play Services 7.5",
    --    "titleFriendly":"",
    --    "summary":"This update brings App Invites, topics to GCM, GCMNetworkManager, Cast Remote Display API, Smart Lock for Passwords, Maps API for Android Wear, Google Fit extensions and more.",
    --    "url":"https://www.youtube.com/watch?v=M3Udfu6qidk&list=PLWz5rJ2EKKc9Qk1_iCZNbBp6adYnJf9Vf",
    --    "group":"",
    --    "keywords": ["google play services"],
    --    "tags": [
    --    ],
    --    "image":"https://i1.ytimg.com/vi/M3Udfu6qidk/maxresdefault.jpg",
    --    "type":"video"
    --  },
    --  {
    --    "title":"Google Play Services 7.3",
    --    "titleFriendly":"",
    --    "summary":"This update brings the ability to connect multiple wearables simultaneously to a single phone. There are also some great new updates to Google Fit, including nutrition types, and to Location.",
    --    "url":"https://www.youtube.com/watch?v=FOn64iqlphk&list=PLWz5rJ2EKKc9Qk1_iCZNbBp6adYnJf9Vf",
    --    "group":"",
    --    "keywords": ["google play services"],
    --    "tags": [
    --    ],
    --    "image":"https://i1.ytimg.com/vi/FOn64iqlphk/maxresdefault.jpg",
    --    "type":"video"
    --  },
    --  {
    --    "title":"Google Play Services 6.5",
    --    "titleFriendly":"",
    --    "summary":"Google Play services 6.5 includes new features in Google Maps, Google Drive and Google Wallet as well as the recently launched Google Fit API. ",
    --    "url":"https://www.youtube.com/watch?v=fvtMtfCuEpw&list=PLWz5rJ2EKKc9Qk1_iCZNbBp6adYnJf9Vf",
    --    "group":"",
    --    "keywords": ["google play services"],
    --    "tags": [
    --    ],
    --    "image":"https://i1.ytimg.com/vi/fvtMtfCuEpw/maxresdefault.jpg",
    --    "type":"video"
    --  },
    --    {
    --    "title":"Google Play Services 7.0",
    --    "titleFriendly":"",
    --    "summary":"Google Play services 7.0 is here! we've added the Places API, made enhancements to Location and Google Fit, and you can also remote control your Android TV through the new Nearby Connections API.",
    --    "url":"https://www.youtube.com/watch?v=F0Kh_RnSM0w&list=PLWz5rJ2EKKc9Qk1_iCZNbBp6adYnJf9Vf",
    --    "group":"",
    --    "keywords": ["google play services"],
    --    "tags": [
    --    ],
    --    "image":"https://i1.ytimg.com/vi/F0Kh_RnSM0w/maxresdefault.jpg",
    --    "type":"video"
    --  },
    --  {
    --    "title":"Running a Successful Games Business with Google",
    --    "titleFriendly":"",
    --    "summary":"Sure, we all want to make the next great gaming masterpiece. But we also want to feed our families and/or dogs. Join Bob Meese from the Google Play team as he gives you some key pointers on how to make sure you're best taking advantage of Google Play and running a successful games business.",
    --    "url":"https://www.youtube.com/watch?v=tDmnGNkTtlE",
    --    "group":"",
    --    "keywords": [],
    --    "tags": [
    --    ],
    --    "image":"https://i1.ytimg.com/vi/tDmnGNkTtlE/maxresdefault.jpg",
    --    "type":"video"
    --  },
    --  {
    --    "title":"Introduction to Android TV",
    --    "titleFriendly":"",
    --    "summary":"Android TV brings the Android platform to the living room with rich content and entertaining app experiences. In this video, Timothy introduces the design philosophy and developer components that make building TV experiences easier than ever before.",
    --    "url":"https://www.youtube.com/watch?v=6K_jxccHv5M&index=1&list=PLOU2XLYxmsILFBfx66ens76VMLMEPJAB0",
    --    "group":"",
    --    "keywords": ["tv"],
    --    "tags": [
    --    ],
    --    "image":"https://i1.ytimg.com/vi/6K_jxccHv5M/maxresdefault.jpg",
    --    "type":"video"
    --  },
    --  {
    --    "title":"Introduction to Android Auto",
    --    "titleFriendly":"",
    --    "summary":"Android Auto brings the Android platform to the car in a way that's optimized for the driving experience. It's the same platform you already use for phones, tablets, televisions, wearables, and more. ",
    --    "url":"https://www.youtube.com/watch?v=ctiaVxgclsg&list=PLWz5rJ2EKKc9BdE_PSLNIGjXXr3h_orXM",
    --    "group":"",
    --    "keywords": ["auto"],
    --    "tags": [
    --    ],
    --    "image":"https://i1.ytimg.com/vi/ctiaVxgclsg/maxresdefault.jpg",
    --    "type":"video"
    --  },
    --  {
    --    "title":"Debugging and testing in Android Studio",
    --    "titleFriendly":"",
    --    "summary":"This video introduces the state of unit testing support in Studio and Google’s new Android Testing Support Library for functional UI testing and running instrumented tests on a device.",
    --    "url":"https://www.youtube.com/watch?v=2I6fuD20qlY",
    --    "group":"",
    --    "keywords": ["testing"],
    --    "tags": [
    --    ],
    --    "image":"https://i1.ytimg.com/vi/2I6fuD20qlY/maxresdefault.jpg",
    --    "type":"video"
    --  },
    --  {
    --    "title":"Android Testing (Android Dev Summit 2015)",
    --    "titleFriendly":"",
    --    "summary":"Overview of the testing tools and frameworks provided by Google and how they can help you to iterate more quickly and maintain a more healthy codebase.",
    --    "url":"https://www.youtube.com/watch?v=vdasFFfXKOY",
    --    "group":"",
    --    "keywords": ["testing"],
    --    "tags": [
    --    ],
    --    "image":"https://i1.ytimg.com/vi/vdasFFfXKOY/maxresdefault.jpg",
    --    "type":"video"
    --  },
    --  {
    --    "title":"dumpsys",
    --    "titleFriendly":"",
    --    "summary":"A tool that runs on the device and provides information about the status of system services.",
    --    "url":"https://source.android.com/devices/tech/debug/dumpsys.html",
    --    "group":"",
    --    "keywords": ["testing"],
    --    "tags": [
    --    ],
    --    "image":"",
    --    "type":"google"
    --  },
    --  {
    --    "title":"Android Testing Samples",
    --    "titleFriendly":"",
    --    "summary":"A collection of samples demonstrating different frameworks and techniques for automated testing.",
    --    "url":"https://github.com/googlesamples/android-testing",
    --    "group":"",
    --    "keywords": ["testing"],
    --    "tags": [
    --    ],
    --    "image":"images/testing/testing-icon.png",
    --    "type":"Samples"
    --  },
    --  {
    --    "title":"Android Testing Templates",
    --    "titleFriendly":"",
    --    "summary":"A collection of Google's Android testing tools and frameworks, all integrated in a single application project.",
    --    "url":"https://github.com/googlesamples/android-testing-templates",
    --    "group":"",
    --    "keywords": ["testing"],
    --    "tags": [
    --    ],
    --    "image":"images/testing/testing-icon.png",
    --    "type":"Samples"
    --  },
    --   {
    --    "title":"Android Testing Support Library (GitHub)",
    --    "titleFriendly":"",
    --    "summary":"A resource page on GitHub for the Android Testing Support Library.",
    --    "url":"https://google.github.io/android-testing-support-library",
    --    "group":"",
    --    "keywords": ["testing"],
    --    "tags": [
    --    ],
    --    "image":"images/testing/testing-icon.png",
    --    "type":"Samples"
    --  },
    --  {
    --    "title":"Android Testing Codelab",
    --    "titleFriendly":"",
    --    "summary":"This codelab shows how to build an Android app from the ground up in Android Studio, using a Model View Presenter architecture, Unit Tests and Instrumentation Tests.",
    --    "url":"https://codelabs.developers.google.com/codelabs/android-testing/index.html",
    --    "group":"",
    --    "keywords": ["testing"],
    --    "tags": [
    --    ],
    --    "image":"images/testing/testing-icon.png",
    --    "type":"google"
    --  },
    --  {
    --    "title":"Developer Registration",
    --    "titleFriendly":"",
    --    "summary":"Additional information about the registration process.",
    --    "url":"https://support.google.com/googleplay/android-developer/answer/113468",
    --    "group":"",
    --    "keywords": [],
    --    "tags": [],
    --    "image":"images/play_dev.jpg",
    --    "type":"google"
    --  },
    --  {
    --    "title": "Google Play Distribution and Seller Countries",
    --    "titleFriendly":"",
    --    "summary": "List of countries and territories where you can distribute your apps in Google Play.",
    --    "url":"https://support.google.com/googleplay/android-developer/answer/138294",
    --    "group":"",
    --    "keywords": [],
    --    "tags": [],
    --    "image":"images/play_dev.jpg",
    --    "type":"google"
    --  },
    --  {
    --    "title": "支持向Google Play用户发布应用的地区",
    --    "lang": "zh-cn",
    --    "titleFriendly":"",
    --    "summary": "支持向Google Play用户发布应用的国家/地区。",
    --    "url":"https://support.google.com/googleplay/android-developer/answer/138294?hl=zh-Hans",
    --    "group":"",
    --    "keywords": [],
    --    "tags": [],
    --    "image":"images/play_dev.jpg",
    --    "type":"google"
    --  },
    --  {
    --    "title":"Google Play Content Policies",
    --    "titleFriendly":"",
    --    "summary":"Details on policies relating to your developer account and app distribution is governed.",
    --    "url":"https://support.google.com/googleplay/android-developer/topic/3453577",
    --    "group":"",
    --    "keywords": [],
    --    "tags": ["#developersupport"],
    --    "image":"images/play_dev.jpg",
    --    "type":"google"
    --  },
    --  {
    --    "title":"Google Play Badge Generator",
    --    "titleFriendly":"",
    --    "summary":"Build badges for your app in just a few clicks, or download hi-res badge assets localized for a variety of languages.",
    --    "url":"https://play.google.com/intl/en_us/badges/",
    --    "group":"",
    --    "keywords": [],
    --    "tags": ["#developersupport"],
    --    "image":"images/gp-badges-set.png",
    --    "type":"google"
    --  },
    --  {
    --    "lang": "en",
    --    "group": "",
    --    "tags": ["#developersupport #termsandpolicies"],
    --    "url": "https://support.google.com/googleplay/android-developer/answer/4407611",
    --    "timestamp": 1194884220000,
    --    "image": 'images/play_dev.jpg',
    --    "title": "Google Play Terms and Policies",
    --    "summary": "Developer terms and policies that apply when you distribute apps in Google Play.",
    --    "keywords": [],
    --    "type": "distribute",
    --    "titleFriendly": ""
    --  },
    --  {
    --    "title":"Google Play Policy Center",
    --    "titleFriendly":"",
    --    "summary":"A central resource for you to learn about Google Play policies and guidelines.",
    --    "url":"https://support.google.com/googleplay/android-developer/answer/4430948",
    --    "group":"",
    --    "keywords": [],
    --    "tags": [],
    --    "image":"https://storage.googleapis.com/support-kms-prod/SNP_712EA2784949DDF085C46E3BE7B1DC618A09_4389397_en_v0",
    --    "type":"google"
    --  },
    --  {
    --    "title":"Google Play应用政策中心",
    --    "titleFriendly":"",
    --    "summary":"一个方便你了解Google Play政策和指南的中心资源。",
    --    "url":"https://support.google.com/googleplay/android-developer/answer/4430948?hl=zh-Hans",
    --    "group":"",
    --    "keywords": [],
    --    "tags": [],
    --    "image":"https://storage.googleapis.com/support-kms-prod/SNP_712EA2784949DDF085C46E3BE7B1DC618A09_4389397_en_v0",
    --    "type":"google"
    --  },
    --  {
    --    "title":"Developer Help Center",
    --    "titleFriendly":"",
    --    "summary":"Complete details on getting started, publishing, troubleshooting, and more.",
    --    "url":"https://support.google.com/googleplay/android-developer",
    --    "group":"",
    --    "keywords": [],
    --    "tags": [],
    --    "image":"images/cards/google-play_2x.png",
    --    "type":"google"
    --  },
    --  {
    --    "title":"开发者帮助中心",
    --    "titleFriendly":"",
    --    "summary":"完整资料帮助开发者新手入手,发布,故障排除,等等",
    --    "url":"https://support.google.com/googleplay/android-developer?hl=zh-Hans",
    --    "group":"",
    --    "keywords": [],
    --    "tags": [],
    --    "image":"images/play_dev.jpg",
    --    "type":"google"
    --  },
    --  {
    --    "title":"Google for Education",
    --    "titleFriendly":"",
    --    "summary":"Find out more about how Google can support your work with apps and tablets.",
    --    "url":"https://www.google.com/edu/tablets/",
    --    "group":"",
    --    "keywords": [],
    --    "tags": [],
    --    "image":"distribute/images/gp-edu-apps-image.jpg",
    --    "type":"google"
    --  },
    --  {
    --    "title":"Keeping Your App Responsive",
    --    "titleFriendly":"",
    --    "summary":"This document describes how the Android system determines whether an application is not responding and provides guidelines for ensuring that your application stays responsive.",
    --    "url":"training/articles/perf-anr.html",
    --    "group":"",
    --    "keywords": [],
    --    "tags": [],
    --    "image":"",
    --    "type":"google"
    --  },
    --  {
    --    "title":"Google Play Game Services",
    --    "titleFriendly":"",
    --    "summary":"Make your games social with Google Play game services. Add achievements, leaderboards, real-time multiplayer, and other popular features using the Google Play game services SDK.",
    --    "url":"https://developers.google.com/games/services/",
    --    "group":"",
    --    "keywords": ["games","play games"],
    --    "tags": [],
    --    "image":"images/google/gps-play_games_logo.png",
    --    "type":"google"
    --  },
    --  {
    --    "title":"Get Started with Analytics",
    --    "titleFriendly":"",
    --    "summary":"Get advanced insight into how players discover and play your games.",
    --    "url":"distribute/analyze/start.html",
    --    "group":"",
    --    "keywords": ["analytics"],
    --    "tags": [],
    --    "image": "images/cards/analytics-mobile_2x.jpg",
    --    "type": "distribute"
    --  },
    --  {
    --    "title":"Build VR with Google Cardboard",
    --    "titleFriendly":"",
    --    "summary":"Turn any phone into a virtual reality headset with a Cardboard viewer and experiment with adding virtual reality to your games with the Cardboard SDK.",
    --    "url":"distribute/googleplay/cardboard.html",
    --    "group":"",
    --    "keywords": ["cardboard"],
    --    "tags": [],
    --    "image":"images/cards/card-cardboard_2x.png",
    --    "type": "distribute"
    --  },
    --  {
    --    "title":"Monetize your apps intelligently",
    --    "titleFriendly":"",
    --    "summary":"Generate revenue from your free games with ads tailored to match your game's look and feel.",
    --    "url":"https://www.google.com/admob/",
    --    "group":"",
    --    "keywords": ["AdMob"],
    --    "tags": [],
    --    "image":"images/cards/admob-analytics_2x.png",
    --    "type": "distribute"
    --  },
    --  {
    --    "lang": "en",
    --    "group": "",
    --    "tags": [
    --      "versions", "blog", "googleplay"
    --    ],
    --    "url": "https://android-developers.blogspot.com/",
    --    "timestamp": 1004884220000,
    --    "image": "images/blog.jpg",
    --    "title": "Android Developers Blog",
    --    "summary": "Follow the latest news on Android design, development, and distribution.",
    --    "keywords": [],
    --    "type": "blog",
    --    "titleFriendly": ""
    --  },
    --  {
    --    "lang": "en",
    --    "group": "",
    --    "tags": [],
    --    "url": "https://android-developers.blogspot.com/2011/11/making-android-games-that-play-nice.html",
    --    "timestamp": 1194884220000,
    --    "image": null,
    --    "title": "Making Android Apps that Play Nice",
    --    "summary": "Audio lifecycle and expected audio behaviors for Android apps.",
    --    "keywords": [],
    --    "type": "blog",
    --    "titleFriendly": ""
    --  },
    --  {
    --    "lang": "en",
    --    "group": "",
    --    "tags": [],
    --    "url": "https://android-developers.blogspot.com/2010/07/multithreading-for-performance.html",
    --    "timestamp": 1194884220000,
    --    "image": null,
    --    "title": "Multithreading for Performance",
    --    "summary": "Ways to improve performance through multi-threading.",
    --    "keywords": [],
    --    "type": "blog",
    --    "titleFriendly": ""
    --  },
    --  {
    --    "lang": "en",
    --    "group": "",
    --    "tags": [],
    --    "url": "https://play.google.com/about/developer-content-policy.html",
    --    "timestamp": 1194884220000,
    --    "image": "images/play_dev.jpg",
    --    "title": "Developer Program Policies",
    --    "summary": "Guidelines acceptable content in Google Play. Please read and understand the policies before publishing.",
    --    "keywords": [],
    --    "type": "google",
    --    "titleFriendly": ""
    --  },
    --  {
    --    "lang": "en",
    --    "group": "",
    --    "tags": [],
    --    "url": "https://support.google.com/googleplay/android-developer/answer/188189",
    --    "timestamp": 1194884220000,
    --    "image": "images/play_dev.jpg",
    --    "title": "Rating your application content for Google Play",
    --    "summary": "How to choose the appropriate content ratings level for your apps.",
    --    "keywords": [],
    --    "type": "support",
    --    "titleFriendly": ""
    --  },
    --  {
    --    "lang": "en",
    --    "group": "",
    --    "tags": ["devices", "nexus", "testing"],
    --    "url": "https://developers.google.com/android/nexus/images",
    --    "timestamp": 1194884220000,
    --    "image": "images/cards/card-download_16-9_2x.png",
    --    "title": "Factory Images for Nexus Devices",
    --    "summary": "System image files for Android 6.0 and other Android releases.",
    --    "keywords": ["nexus, downloads"],
    --    "type": "support",
    --    "titleFriendly": ""
    --  },
    --  {
    --    "lang": "zh-cn",
    --    "group": "",
    --    "tags": [],
    --    "url": "https://support.google.com/googleplay/android-developer/answer/188189?hl=zh-Hans",
    --    "timestamp": 1194884220000,
    --    "image": "images/play_dev.jpg",
    --    "title": "针对Google Play为你的应用内容分级",
    --    "summary": "如何为你的应用内容分级。",
    --    "keywords": [],
    --    "type": "support",
    --    "titleFriendly": ""
    --  },
    --  {
    --    "lang": "en",
    --    "group": "",
    --    "tags": [],
    --    "url": "https://android-developers.blogspot.com/2011/10/android-market-featured-image.html",
    --    "timestamp": 1194884220000,
    --    "image": "images/play_dev.jpg",
    --    "title": "Google Play Featured Image Guidelines",
    --    "summary": "How to create attractive, effective Featured Images for your apps.",
    --    "keywords": [],
    --    "type": "support",
    --    "titleFriendly": ""
    --  },
    --{
    --    "lang": "en",
    --    "group": "",
    --    "tags": [],
    --    "url": "https://support.google.com/googleplay/android-developer/answer/113477",
    --    "timestamp": 1194884220000,
    --    "image": "images/play_dev.jpg",
    --    "title": "Supporting your users",
    --    "summary": "Options for supporting users.",
    --    "keywords": [],
    --    "type": "support",
    --    "titleFriendly": ""
    --  },
    --{
    --    "lang": "zh-cn",
    --    "group": "",
    --    "tags": [],
    --    "url": "https://support.google.com/googleplay/android-developer/answer/113477?hl=zh-Hans",
    --    "timestamp": 1194884220000,
    --    "image": "images/play_dev.jpg",
    --    "title": "为用户提供支持",
    --    "summary": "为用户提供支持的各种选择。",
    --    "keywords": [],
    --    "type": "support",
    --    "titleFriendly": ""
    --  },
    --  {
    --    "lang": "en",
    --    "group": "",
    --    "tags": [],
    --    "url": "guide/practices/screens_support.html#ConfigurationExamples",
    --    "timestamp": 1194884220000,
    --    "image": null,
    --    "title": "Configuration examples",
    --    "summary": "How to declare layouts and other resources for specific screen sizes.",
    --    "keywords": [],
    --    "type": "design",
    --    "titleFriendly": ""
    --  },
    --  {
    --    "lang": "en",
    --    "group": "",
    --    "tags": [],
    --    "url": "training/design-navigation/multiple-sizes.html",
    --    "timestamp": 1194884220000,
    --    "image": null,
    --    "title": "Planning for Multiple Touchscreen Sizes",
    --    "summary": "",
    --    "keywords": [],
    --    "type": "design",
    --    "titleFriendly": ""
    --  },
    --  {
    --    "lang": "en",
    --    "group": "",
    --    "tags": [],
    --    "url": "training/multiscreen/index.html",
    --    "timestamp": 1194884220000,
    --    "image": null,
    --    "title": "Designing for Multiple Screens",
    --    "summary": "Designing an intuitive, effective navigation for tablets and other devices.",
    --    "keywords": [],
    --    "type": "design",
    --    "titleFriendly": ""
    --  },
    --  {
    --    "lang": "en",
    --    "group": "",
    --    "tags": [],
    --    "url": "guide/topics/resources/providing-resources.html",
    --    "timestamp": 1194884220000,
    --    "image": null,
    --    "title": "Providing Resources",
    --    "summary": "Layouts and drawable resources for specific ranges of device screens.",
    --    "keywords": [],
    --    "type": "design",
    --    "titleFriendly": ""
    --  },
    --  {
    --    "lang": "en",
    --    "group": "",
    --    "tags": [],
    --    "url": "training/basics/supporting-devices/screens.html",
    --    "timestamp": 1194884220000,
    --    "image": null,
    --    "title": "Supporting Different Screens",
    --    "summary": "Optimizing the user experience for different screen sizes and densities.",
    --    "keywords": [],
    --    "type": "design",
    --    "titleFriendly": ""
    --  },
    --  {
    --    "lang": "en",
    --    "group": "",
    --    "tags": [],
    --    "url": "guide/topics/appwidgets/index.html#MetaData",
    --    "timestamp": 1194884220000,
    --    "image": null,
    --    "title": "Adding the AppWidgetProviderInfo Metadata",
    --    "summary": "How to set the height and width dimensions of a widget.",
    --    "keywords": [],
    --    "type": "design",
    --    "titleFriendly": ""
    --  },
    --  {
    --    "lang": "en",
    --    "group": "",
    --    "tags": [],
    --    "url": "guide/topics/manifest/uses-sdk-element.html#ApiLevels",
    --    "timestamp": 1194884220000,
    --    "image": null,
    --    "title": "Android API Levels",
    --    "summary": "Introduction to API levels and how they relate to compatibility.",
    --    "keywords": [],
    --    "type": "guide",
    --    "titleFriendly": ""
    --  },
    --  {
    --    "lang": "en",
    --    "group": "",
    --    "tags": [],
    --    "url": "guide/practices/screens_support.html#DeclaringScreenSizeSupport",
    --    "timestamp": 1194884220000,
    --    "image": null,
    --    "title": "Declaring screen size support",
    --    "summary": "How to declare support for screen sizes in your app\'s manifest.",
    --    "keywords": [],
    --    "type": "guide",
    --    "titleFriendly": ""
    --  },
    --  {
    --    "lang": "en",
    --    "group": "",
    --    "tags": [],
    --    "url": "training/material/animations.html#Touch",
    --    "timestamp": 1194884220000,
    --    "image": null,
    --    "title": "Customize Touch Feedback",
    --    "summary": "Provide visual confirmation when users interact with your UI.",
    --    "keywords": [],
    --    "type": "develop",
    --    "category": "guide"
    --  },
    --  {
    --    "lang": "en",
    --    "group": "",
    --    "tags": [],
    --    "url": "guide/topics/manifest/uses-feature-element.html#testing",
    --    "timestamp": 1194884220000,
    --    "image": null,
    --    "title": "Checking for hardware feature requirements",
    --    "summary": "Determining an app’s hardware and software requirements.",
    --    "keywords": [],
    --    "type": "guide",
    --    "titleFriendly": ""
    --  },
    --  {
    --    "lang": "en",
    --    "group": "",
    --    "tags": [],
    --    "url": "https://play.google.com/apps/publish/",
    --    "timestamp": 1194884220000,
    --    "image": null,
    --    "title": "Google Play Developer Console",
    --    "summary": "The tools console for publishing your app.",
    --    "keywords": [],
    --    "type": "guide",
    --    "titleFriendly": ""
    --  },
    --  {
    --    "lang": "zh-cn",
    --    "group": "",
    --    "tags": [],
    --    "url": "https://play.google.com/apps/publish/?hl=zh-Hans",
    --    "timestamp": 1194884220000,
    --    "image": null,
    --    "title": "Google Play 开发者控制台",
    --    "summary": "发布应用的开发者控制台",
    --    "keywords": [],
    --    "type": "guide",
    --    "titleFriendly": ""
    --  },
    --  {
    --    "lang": "en",
    --    "group": "",
    --    "tags": [],
    --    "url": "https://youtu.be/SkHHPf3EdzE",
    --    "timestamp": 1194884220000,
    --    "image": "https://i1.ytimg.com/vi/SkHHPf3EdzE/maxresdefault.jpg",
    --    "title": "Level Up Your Android Game",
    --    "summary": "Learn how to take your game to the next level on Google Play.",
    --    "keywords": [],
    --    "type": "guide",
    --    "titleFriendly": ""
    --  },
    --  {
    --    "lang": "en",
    --    "group": "",
    --    "tags": [],
    --    "url": "https://developers.google.com/+/mobile/android/share/interactive-post",
    --    "timestamp": 1194884220000,
    --    "image": 'images/google/gps-googleplus.png',
    --    "title": "Sharing interactive posts to Google+ from your Android app",
    --    "summary": "Interactive posts provide an easy and prominent way to allow users to share your site or app with their friends and invite them to take a specific action.",
    --    "keywords": ["Interactive", "Google+"],
    --    "type": "guide",
    --    "titleFriendly": ""
    --  },
    --  {
    --    "lang": "en",
    --    "group": "",
    --    "tags": [],
    --    "url": "https://play.google.com/about/developer-distribution-agreement.html",
    --    "timestamp": 1194884220000,
    --    "image": "images/play_dev.jpg",
    --    "title": "Developer Distribution Agreement",
    --    "summary": "Terms for distributing and selling apps and in-app products in Google Play.",
    --    "keywords": [],
    --    "type": "guide",
    --    "titleFriendly": ""
    --  },
    --  {
    --    "lang": "en",
    --    "group": "",
    --    "tags": [],
    --    "url": "https://support.google.com/googleplay/android-developer/answer/113417",
    --    "timestamp": 1194884220000,
    --    "image": null,
    --    "title": "Inappropriate content in comments and applications",
    --    "summary": "More details on what content is appropriate.",
    --    "keywords": [],
    --    "type": "guide",
    --    "titleFriendly": ""
    --  },
    --  {
    --    "lang": "en",
    --    "group": "",
    --    "tags": [],
    --    "url": "https://support.google.com/legal/troubleshooter/1114905",
    --    "timestamp": 1194884220000,
    --    "image": null,
    --    "title": "Removing content from Google",
    --    "summary": "Find how how to request the removal of content that infringes on your trademark.",
    --    "keywords": [],
    --    "type": "guide",
    --    "titleFriendly": ""
    --  },
    --  {
    --    "lang": "en",
    --    "group": "",
    --    "tags": [],
    --    "url": "https://play.google.com/about/developer-distribution-agreement-addendum.html",
    --    "timestamp": 1194884220000,
    --    "image": "images/play_dev.jpg",
    --    "title": "Google Play for Education Addendum",
    --    "summary": "Review the education-specific requirements.",
    --    "keywords": [],
    --    "type": "guide",
    --    "titleFriendly": ""
    --  },
    --  {
    --    "lang": "en",
    --    "group": "",
    --    "tags": [],
    --    "url": "https://android-developers.blogspot.com/2013/03/native-rtl-support-in-android-42.html",
    --    "timestamp": null,
    --    "image": null,
    --    "title": "Native RTL Support in Android 4.2",
    --    "summary": "Blog post that explains how to support RTL in your UI.",
    --    "keywords": [],
    --    "type": "guide",
    --    "titleFriendly": ""
    --  },
    --  {
    --    "lang": "en",
    --    "group": "",
    --    "tags": [],
    --    "url": "guide/topics/resources/string-resource.html#Plurals",
    --    "timestamp": 1194884220000,
    --    "image": null,
    --    "title": "Quantity Strings (Plurals)",
    --    "summary": "How to work with string plurals according to rules of grammar in a given locale.",
    --    "keywords": [],
    --    "type": "guide",
    --    "titleFriendly": ""
    --  },
    --  {
    --    "lang": "en",
    --    "group": "",
    --    "tags": [],
    --    "url": "reference/java/util/Locale.html",
    --    "timestamp": 1194884220000,
    --    "image": null,
    --    "title": "Locale",
    --    "summary": "Determine what CLDR data or version of the Unicode spec a particular Android platform version uses.",
    --    "keywords": [],
    --    "type": "guide",
    --    "titleFriendly": ""
    --  },
    --    {
    --    "lang": "en",
    --    "group": "",
    --    "tags": [],
    --    "url": "guide/topics/resources/string-resource.html",
    --    "timestamp": 1194884220000,
    --    "image": null,
    --    "title": "String Resources",
    --    "summary": "Explains how to use string resources in your UI.",
    --    "keywords": [],
    --    "type": "guide",
    --    "titleFriendly": ""
    --  },
    --  {
    --    "lang": "en",
    --    "group": "",
    --    "tags": [],
    --    "url": "distribute/tools/localization-checklist.html#strings",
    --    "timestamp": 1194884220000,
    --    "image": null,
    --    "title": "Manage strings for localization",
    --    "summary": "Guidance on having your strings translation ready.",
    --    "keywords": [],
    --    "type": "guide",
    --    "titleFriendly": ""
    --  },
    --  {
    --    "lang": "en",
    --    "group": "",
    --    "tags": [],
    --    "url": "tools/publishing/publishing_overview.html",
    --    "timestamp": 1194884220000,
    --    "image": null,
    --    "title": "General Publishing Overview",
    --    "summary": "Start here for an overview of publishing options for Android apps.",
    --    "keywords": [],
    --    "type": "guide",
    --    "titleFriendly": ""
    --  },
    --  {
    --    "lang": "en",
    --    "group": "",
    --    "tags": [],
    --    "url": "tools/publishing/preparing.html",
    --    "timestamp": 1194884220000,
    --    "image": null,
    --    "title": "Preparing for Release",
    --    "summary": "Developer documentation on how to build the signed, release-ready APK. This process is the same for all Android apps.",
    --    "keywords": [],
    --    "type": "guide",
    --    "titleFriendly": ""
    --  },
    --  {
    --    "lang": "en",
    --    "group": "",
    --    "tags": [],
    --    "url": "distribute/googleplay/policies/index.html",
    --    "timestamp": 1194884220000,
    --    "image": "images/play_dev.jpg",
    --    "title": "Google Play Policies and Guidelines",
    --    "summary": "An overview of Google Play policies for spam, intellectual property, and ads, with examples of common problems.",
    --    "keywords": [],
    --    "type": "guide",
    --    "titleFriendly": ""
    --  },
    --  {
    --    "lang": "en",
    --    "group": "",
    --    "tags": [],
    --    "url": "https://support.google.com/googleplay/android-developer/topic/2364761",
    --    "timestamp": 1194884220000,
    --    "image": "images/play_dev.jpg",
    --    "title": "Policy and Best Practices",
    --    "summary": "Help Center document describing various content policies and processes.",
    --    "keywords": [],
    --    "type": "distribute",
    --    "titleFriendly": ""
    --  },
    --  {
    --    "lang": "zh-cn",
    --    "group": "",
    --    "tags": [],
    --    "url": "https://support.google.com/googleplay/android-developer/topic/2364761?hl=zh-Hans",
    --    "timestamp": 1194884220000,
    --    "image": "images/play_dev.jpg",
    --    "title": "政策和最佳做法",
    --    "summary": "内容政策和流程",
    --    "keywords": [],
    --    "type": "distribute",
    --    "titleFriendly": ""
    --  },
    --  {
    --    "lang": "en",
    --    "group": "",
    --    "tags": [],
    --    "url": "google/play/expansion-files.html",
    --    "timestamp": 1194884220000,
    --    "image": null,
    --    "title": "APK Expansion Files",
    --    "summary": "Developer documentation describing APK Expansion Files and how to support them in your app.",
    --    "keywords": [],
    --    "type": "guide",
    --    "titleFriendly": ""
    --  },
    --  {
    --    "lang": "en",
    --    "group": "",
    --    "tags": [],
    --    "url": "tools/help/proguard.html",
    --    "timestamp": 1194884220000,
    --    "image": null,
    --    "title": "ProGuard",
    --    "summary": "Developer documentation describing how to use ProGuard to shrink, optimize, and obfuscate your code prior to release.",
    --    "keywords": [],
    --    "type": "guide",
    --    "titleFriendly": ""
    --  },
    --  {
    --    "title":"Dashboards",
    --    "titleFriendly":"",
    --    "summary":"This page provides information about the relative number of devices that share a certain characteristic, such as Android version or screen size. This information may help you prioritize efforts for supporting different devices by revealing which devices…",
    --    "url":"about/dashboards/index.html",
    --    "group":"",
    --    "keywords": ["android","dashboard","platforms","versions"],
    --    "tags": ["#ecosystem","#versions","#whatsnew"],
    --    "image":"https://chart.googleapis.com/chart?chl=GL%201.1%20only%7CGL%202.0%7CGL%203.0&chf=bg%2Cs%2C00000000&chd=t%3A0.1%2C93.5%2C6.4&chco=c4df9b%2C6fad0c&chs=400x250&cht=p",
    --    "lang":"en",
    --    "type":"about"
    --  },
    --  {
    --    "lang": "en",
    --    "group": "",
    --    "tags": [],
    --    "url": "https://developers.google.com/wallet/instant-buy/",
    --    "timestamp": 1194884220000,
    --    "image": "",
    --    "title": "Android Pay APIs",
    --    "summary": "Developer documentation describing Instant Buy and how to support it in your apps.",
    --    "keywords": [],
    --    "type": "guide",
    --    "titleFriendly": ""
    --  },
    --  {
    --    "lang": "en",
    --    "group": "",
    --    "tags": [],
    --    "url": "https://support.google.com/googleplay/android-developer/answer/1169947",
    --    "timestamp": 1194884220000,
    --    "image": "images/play_dev.jpg",
    --    "title": "Selling Apps in Multiple Currencies",
    --    "summary": "Help Center document describing how pricing works in Google Play.",
    --    "keywords": [],
    --    "type": "guide",
    --    "titleFriendly": ""
    --  },
    --  {
    --    "lang": "en",
    --    "group": "",
    --    "tags": [],
    --    "url": "https://support.google.com/googleplay/android-developer/answer/1169947?hl=zh-Hans",
    --    "timestamp": 1194884220000,
    --    "image": "images/play_dev.jpg",
    --    "title": "以多种货币销售应用",
    --    "summary": "如何在Google Play为应用定价",
    --    "keywords": [],
    --    "type": "guide",
    --    "titleFriendly": ""
    --  },
    --  {
    --    "lang": "en",
    --    "group": "",
    --    "tags": [],
    --    "url": "https://support.google.com/googleplay/android-developer/answer/138412",
    --    "timestamp": 1194884220000,
    --    "image": "images/play_dev.jpg",
    --    "title": "Prices and supported currencies",
    --    "summary": "Help Center document listing supported currencies for pricing your apps.",
    --    "keywords": [],
    --    "type": "guide",
    --    "titleFriendly": ""
    --  },
    --    {
    --    "lang": "zh-cn",
    --    "group": "",
    --    "tags": [],
    --    "url": "https://support.google.com/googleplay/android-developer/answer/138412?hl=zh-Hans",
    --    "timestamp": 1194884220000,
    --    "image": "images/play_dev.jpg",
    --    "title": "各国家/地区获许定价范围和货币",
    --    "summary": "各国家/地区获许定价范围和货币列表",
    --    "keywords": [],
    --    "type": "guide",
    --    "titleFriendly": ""
    --  },
    --  {
    --    "lang": "en",
    --    "group": "",
    --    "tags": [],
    --    "url": "https://support.google.com/googleplay/android-developer/answer/112622",
    --    "timestamp": 1194884220000,
    --    "image": "images/play_dev.jpg",
    --    "title": "Transaction Fees",
    --    "summary": "Help Center document describing transaction fees for priced apps and in-app products.",
    --    "keywords": [],
    --    "type": "guide",
    --    "titleFriendly": ""
    --  },
    --  {
    --    "lang": "zh-cn",
    --    "group": "",
    --    "tags": [],
    --    "url": "https://support.google.com/googleplay/android-developer/answer/112622?hl=zh-Hans",
    --    "timestamp": 1194884220000,
    --    "image": "images/play_dev.jpg",
    --    "title": "交易费用",
    --    "summary": "销售的应用和应用内产品的交易费。",
    --    "keywords": [],
    --    "type": "guide",
    --    "titleFriendly": ""
    --  },
    --  {
    --    "lang": "en",
    --    "group": "",
    --    "tags": [],
    --    "url": "https://support.google.com/googleplay/android-developer/answer/138000",
    --    "timestamp": 1194884220000,
    --    "image": "images/play_dev.jpg",
    --    "title": "Specifying tax rates",
    --    "summary": "Help Center document describing how to set tax rates for different countries.",
    --    "keywords": [],
    --    "type": "guide",
    --    "titleFriendly": ""
    --  },
    --  {
    --    "lang": "zh-cn",
    --    "group": "",
    --    "tags": [],
    --    "url": "https://support.google.com/googleplay/android-developer/answer/138000?hl=zh-Hans",
    --    "timestamp": 1194884220000,
    --    "image": "images/play_dev.jpg",
    --    "title": "税率",
    --    "summary": "如何设置不同国家/地区的税率",
    --    "keywords": [],
    --    "type": "guide",
    --    "titleFriendly": ""
    --  },
    --  {
    --    "lang": "en",
    --    "group": "",
    --    "tags": [],
    --    "url": "guide/topics/resources/localization.html",
    --    "timestamp": 1194884220000,
    --    "image": "images/play_dev.jpg",
    --    "title": "Localizing with Resources",
    --    "summary": "Developer guide to localizing resources in your app.",
    --    "keywords": [],
    --    "type": "guide",
    --    "titleFriendly": ""
    --  },
    --  {
    --    "lang": "en",
    --    "group": "",
    --    "tags": [],
    --    "url": "https://support.google.com/googleplay/android-developer/answer/113475",
    --    "timestamp": 1194884220000,
    --    "image": "images/play_dev.jpg",
    --    "title": "Category types",
    --    "summary": "Help Center document listing available categories for apps.",
    --    "keywords": [],
    --    "type": "guide",
    --    "titleFriendly": ""
    --  },
    --  {
    --    "lang": "zh-cn",
    --    "group": "",
    --    "tags": [],
    --    "url": "https://support.google.com/googleplay/android-developer/answer/113475?hl=zh-Hans",
    --    "timestamp": 1194884220000,
    --    "image": "images/play_dev.jpg",
    --    "title": "类别",
    --    "summary": "应用的类别列表。",
    --    "keywords": [],
    --    "type": "guide",
    --    "titleFriendly": ""
    --  },
    --  {
    --    "lang": "en",
    --    "group": "",
    --    "tags": [],
    --    "url": "https://support.google.com/googleplay/android-developer/answer/113476",
    --    "timestamp": 1194884220000,
    --    "image": "images/play_dev.jpg",
    --    "title": "Updates",
    --    "summary": "Requirements for app updates in Google Play.",
    --    "keywords": [],
    --    "type": "guide",
    --    "titleFriendly": ""
    --  },
    --  {
    --    "lang": "zh-cn",
    --    "group": "",
    --    "tags": [],
    --    "url": "https://support.google.com/googleplay/android-developer/answer/113476?hl=zh-Hans",
    --    "timestamp": 1194884220000,
    --    "image": "images/play_dev.jpg",
    --    "title": "更新应用",
    --    "summary": "更新Google Play应用的要求。",
    --    "keywords": [],
    --    "type": "guide",
    --    "titleFriendly": ""
    --  },
    --  {
    --    "lang": "en",
    --    "group": "",
    --    "tags": [],
    --    "url": "https://support.google.com/googleplay/android-developer/answer/1153479",
    --    "timestamp": 1194884220000,
    --    "image": null,
    --    "title": "In-app Billing",
    --    "summary": "Help Center document describing how to correctly set up In-app Billing.",
    --    "keywords": [],
    --    "type": "guide",
    --    "titleFriendly": ""
    --  },
    --  {
    --    "lang": "zh-cn",
    --    "group": "",
    --    "tags": [],
    --    "url": "https://support.google.com/googleplay/android-developer/answer/1153479?hl=zh-Hans",
    --    "timestamp": 1194884220000,
    --    "image": null,
    --    "title": "应用内结算",
    --    "summary": "如何正确设置应用内商品和订阅结算。",
    --    "keywords": [],
    --    "type": "guide",
    --    "titleFriendly": ""
    --  },
    --  {
    --    "lang": "en",
    --    "group": "",
    --    "tags": [
    --      "#gpfe",
    --      "#googleplay"
    --    ],
    --    "url": "https://youtu.be/vzvpcEffvaE",
    --    "timestamp": 1383243492000,
    --    "image": "https://i1.ytimg.com/vi/vzvpcEffvaE/maxresdefault.jpg",
    --    "title": "Introducing Tablets with Google Play for Education",
    --    "summary": "Schools in Hillsborough, New Jersey were among the first to try out Nexus 7 tablets with Google Play for Education. See the difference it made for students, teachers, and administrators.",
    --    "keywords": [],
    --    "type": "video",
    --    "titleFriendly": ""
    --  },
    --  {
    --    "lang": "en",
    --    "group": "",
    --    "tags": [
    --      "#engagement",
    --    ],
    --    "url": "https://www.youtube.com/yt/dev/",
    --    "timestamp": 1383243492000,
    --    "image": "https://www.youtube.com/yt/dev/media/images/yt-dev-home-hero.jpg",
    --    "title": "YouTube for Developers",
    --    "summary": "The YouTube APIs and Tools enable you to integrate YouTube's video content and functionality into your website, app, or device.",
    --    "keywords": [],
    --    "type": "youtube",
    --    "titleFriendly": ""
    --  },
    --  {
    --    "lang": "en",
    --    "group": "",
    --    "tags": [
    --      "#engagement",
    --    ],
    --    "url": "https://www.google.com/analytics/mobile/",
    --    "timestamp": 1383243492000,
    --    "image": "images/cards/analytics-mobile_2x.jpg",
    --    "title": "Mobile App Analytics",
    --    "summary": "Mobile App Analytics measures what matters most at all key stages: from first discovery and download to in-app purchases. ",
    --    "keywords": ["analytics,user behavior"],
    --    "type": "Guide",
    --    "titleFriendly": ""
    --  },
    --
    --
    --  {
    --    "lang": "en",
    --    "group": "",
    --    "tags": [
    --      "#gcm",
    --    ],
    --    "url": "https://www.youtube.com/watch?v=y76rjidm8cU",
    --    "timestamp": 1383243492000,
    --    "image": "https://1.bp.blogspot.com/-IF-1-1kA0sg/UYwTidxdi3I/AAAAAAAAAEU/ellLeQ-E1vs/s800/google-io-lockup-2.png",
    --    "title": "Google Cloud Messaging at I/O 2013",
    --    "summary": "Google Cloud Messaging allows your services to efficiently send data to applications on Android devices. See what's new, and learn how to use GCM to make your apps more efficient.",
    --    "keywords": ["gcm"],
    --    "type": "youtube",
    --    "titleFriendly": ""
    --  },
    --  {
    --    "lang": "en",
    --    "group": "",
    --    "tags": [
    --      "#gcm",
    --    ],
    --    "url": "https://developer.chrome.com/apps/cloudMessagingV2",
    --    "timestamp": 1383243492000,
    --    "image": "images/kk-chromium-icon.png",
    --    "title": "Google Cloud Messaging for Chrome",
    --    "summary": "Google Cloud Messaging for Chrome (GCM) is a service for signed-in Chrome users that helps developers send message data from servers to their Chrome apps and extensions.",
    --    "keywords": ["gcm"],
    --    "type": "guide",
    --    "titleFriendly": ""
    --  },
    --
    --  {
    --    "lang": "en",
    --    "group": "",
    --    "tags": [
    --      "#sdkupdates"
    --    ],
    --    "url": "https://android-developers.blogspot.com/2013/07/making-beautiful-android-app-icons.html",
    --    "timestamp": 1194884220000,
    --    "image": null,
    --    "title": "Make Beautiful Android App Icons",
    --    "summary": "Follow these in-depth launcher icon tips on the Android Developers blog.",
    --    "keywords": [],
    --    "type": "blog",
    --    "titleFriendly": ""
    --  },
    --     {
    --    "lang": "en",
    --    "group": "",
    --    "tags": [
    --      "#sdkupdates"
    --    ],
    --    "url": "https://android-developers.blogspot.com/2012/12/localize-your-promotional-graphics-on.html",
    --    "timestamp": 1194884220000,
    --    "image": null,
    --    "title": "Localize Your Promotional Graphics",
    --    "summary": "Learn how to capitalise on international audiences.",
    --    "keywords": [],
    --    "type": "blog",
    --    "titleFriendly": ""
    --  },
    --   {
    --    "lang": "en",
    --    "group": "",
    --    "tags": [
    --      "#sdkupdates"
    --    ],
    --    "url": "https://android-developers.blogspot.com/2013/10/making-your-app-content-more-accessible.html",
    --    "timestamp": 1194884220000,
    --    "image": null,
    --    "title": "Make your App Content more Accessible with App Linking",
    --    "summary": "About using search and deep linking to get more users.",
    --    "keywords": [],
    --    "type": "blog",
    --    "titleFriendly": ""
    --  },
    --  {
    --    "lang": "en",
    --    "group": "",
    --    "tags": [],
    --    "url": "https://developers.google.com/+/mobile/android/share/interactive-post",
    --    "timestamp": 1194884220000,
    --    "image": 'images/google/gps-googleplus.png',
    --    "title": "Sharing interactive posts to Google+ from your Android app",
    --    "summary": "Interactive posts provide an easy and prominent way to allow users to share your site or app with their friends and invite them to take a specific action.",
    --    "keywords": ["Interactive", "Google+"],
    --    "type": "guide",
    --    "titleFriendly": ""
    --  },
    --  {
    --    "lang": "en",
    --    "group": "",
    --    "tags": [],
    --    "url": "https://developers.google.com/+/mobile/android/",
    --    "timestamp": 1194884220000,
    --    "image": 'images/google/gps-googleplus.png',
    --    "title": "Google+ Platform",
    --    "summary": "Find out about features such as interactive posts, Hangouts, accessing basic user details and their social graphs to make your app more personal.",
    --    "keywords": ["Google+"],
    --    "type": "guide",
    --    "titleFriendly": ""
    --  },
    --  {
    --    "lang": "en",
    --    "group": "",
    --    "tags": [],
    --    "url": "https://support.google.com/googleplay/android-developer/answer/2528691",
    --    "timestamp": 1194884220000,
    --    "image": "images/play_dev.jpg",
    --    "title": "How to add multiple user accounts to your Developer Console for testing and more.",
    --    "summary": "",
    --    "keywords": [],
    --    "type": "guide",
    --    "titleFriendly": ""
    --  },
    --  {
    --    "lang": "en",
    --    "group": "",
    --    "tags": [],
    --    "url": "https://developers.google.com/+/mobile/android/share/deep-link",
    --    "timestamp": 1194884220000,
    --    "image": null,
    --    "title": "Adding deep linking to Google+ posts shared from your Android app",
    --    "summary": "",
    --    "keywords": [],
    --    "type": "guide",
    --    "titleFriendly": ""
    --  },
    --  {
    --    "lang": "en",
    --    "group": "",
    --    "tags": [],
    --    "url": "google/play/licensing/index.html",
    --    "timestamp": 1194884220000,
    --    "image": null,
    --    "title": "Application Licensing",
    --    "summary": "Information on the features of Google Play to protect your apps’ licences.",
    --    "keywords": [],
    --    "type": "guide",
    --    "titleFriendly": ""
    --  },
    --  {
    --    "lang": "en",
    --    "group": "",
    --    "tags": [],
    --    "url": "design/style/writing.html",
    --    "timestamp": 1194884220000,
    --    "image": null,
    --    "title": "Writing Style",
    --    "summary": "Android Design guidelines for voice and style in your UI.",
    --    "keywords": [],
    --    "type": "guide",
    --    "titleFriendly": ""
    --  },
    --  {
    --    "lang": "en",
    --    "group": "",
    --    "tags": [],
    --    "url": "https://en.wikipedia.org/wiki/XLIFF",
    --    "timestamp": 1194884220000,
    --    "image": null,
    --    "title": "XML Localisation Interchange File Format (XLIFF)",
    --    "summary": "Background information on XLIFF.",
    --    "keywords": [],
    --    "type": "guide",
    --    "titleFriendly": ""
    --  },
    --  {
    --    "lang": "en",
    --    "group": "",
    --    "tags": [],
    --    "url": "https://support.google.com/googleplay/android-developer/answer/1078870",
    --    "timestamp": 1194884220000,
    --    "image": "images/play_dev.jpg",
    --    "title": "Graphic Assets for your Application",
    --    "summary": "Details about the graphics you can add to your product listing.",
    --    "keywords": [],
    --    "type": "guide",
    --    "titleFriendly": ""
    --  },
    --  {
    --    "lang": "zh-cn",
    --    "group": "",
    --    "tags": [],
    --    "url": "https://support.google.com/googleplay/android-developer/answer/1078870?hl=zh-Hans",
    --    "timestamp": 1194884220000,
    --    "image": "images/play_dev.jpg",
    --    "title": "为你的应用的图片资源",
    --    "summary": "如何在你的应用的商品详情页面上添加图片资源。",
    --    "keywords": [],
    --    "type": "guide",
    --    "titleFriendly": ""
    --  },
    --  {
    --    "lang": "en",
    --    "group": "",
    --    "tags": [],
    --    "url": "https://support.google.com/payments/answer/2741495",
    --    "timestamp": null,
    --    "image": null,
    --    "title": "Issuing Refunds",
    --    "summary": "Help Center document describing how to issue refunds.",
    --    "keywords": [],
    --    "type": "guide",
    --    "titleFriendly": ""
    --  },
    --  {
    --    "lang": "zh-cn",
    --    "group": "",
    --    "tags": [],
    --    "url": "https://support.google.com/payments/answer/2741495?hl=zh-Hans",
    --    "timestamp": null,
    --    "image": null,
    --    "title": "退回訂單款項",
    --    "summary": "如何退还已收取的订单款项。",
    --    "keywords": [],
    --    "type": "guide",
    --    "titleFriendly": ""
    --  },
    --  {
    --    "lang": "en",
    --    "group": "",
    --    "tags": [],
    --    "url": "https://android-developers.blogspot.com/2013/11/bring-your-apps-into-classroom-with.html",
    --    "timestamp": null,
    --    "image": "distribute/images/gp-edu-apps-image.jpg",
    --    "title": "Google play for education",
    --    "summary": " ",
    --    "keywords": [],
    --    "type": "distribute",
    --    "titleFriendly": ""
    --  },
    --  {
    --    "lang": "en",
    --    "group": "",
    --    "tags": ["localization", "pricing", "developer support"],
    --    "url": "https://support.google.com/googleplay/android-developer/table/3541286",
    --    "timestamp": null,
    --    "image": "images/play_dev.jpg",
    --    "title": "Supported locations for distributing your apps in Google Play",
    --    "summary": "Countries and regions where you can distribute your app in Google Play.",
    --    "keywords": [],
    --    "type": "distribute",
    --    "titleFriendly": ""
    --  },
    --  {
    --    "lang": "zh-cn",
    --    "group": "",
    --    "tags": ["localization", "pricing", "developer support"],
    --    "url": "https://support.google.com/googleplay/android-developer/table/3541286?hl=zh-Hans",
    --    "timestamp": null,
    --    "image": "images/play_dev.jpg",
    --    "title": "支持向Google Play用户发布应用的地区",
    --    "summary": "支持向Google Play用户发布应用的国家/地区。",
    --    "keywords": [],
    --    "type": "distribute",
    --    "titleFriendly": ""
    --  },
    --  {
    --    "lang": "en",
    --    "group": "",
    --    "tags": ["games", "localization", "quality"],
    --    "url": "https://www.youtube.com/watch?v=SkHHPf3EdzE",
    --    "timestamp": null,
    --    "image": "https://developers.google.com/apps/images/io_2013/google-io-logo.png",
    --    "title": "Level Up Your Android Game",
    --    "summary": "Learn how to take your game to the next level in this Google I/O session.",
    --    "keywords": [],
    --    "type": "distribute",
    --    "titleFriendly": ""
    --  },
    --  {
    --    "lang": "en",
    --    "group": "",
    --    "tags": ["support"],
    --    "url": "https://support.google.com/groups/answer/46601",
    --    "timestamp": null,
    --    "image": null,
    --    "title": "Google Groups",
    --    "summary": "Create a group for your community.",
    --    "keywords": [],
    --    "type": "distribute",
    --    "titleFriendly": ""
    --  },
    --  {
    --    "lang": "en",
    --    "group": "",
    --    "tags": ["support"],
    --    "url": "https://support.google.com/plus/topic/2888488",
    --    "timestamp": null,
    --    "image": null,
    --    "title": "Google+ Communities",
    --    "summary": "Host a Google+ community for testers or users.",
    --    "keywords": [],
    --    "type": "distribute",
    --    "titleFriendly": ""
    --  },
    --  {
    --    "lang": "en",
    --    "group": "",
    --    "tags": ["monetize", "ads"],
    --    "url": "https://www.google.com/doubleclick/publishers/small-business/index.html",
    --    "timestamp": null,
    --    "image": "https://www.google.com/doubleclick/publishers/small-business/images/define_ad.png",
    --    "title": "DoubleClick for Publishers",
    --    "summary": "A free ad management solution that helps growing publishers sell, schedule, deliver, and measure all of their digital ad inventory.",
    --    "keywords": ["ads"],
    --    "type": "distribute",
    --    "titleFriendly": ""
    --  },
    --  {
    --    "lang": "en",
    --    "group": "",
    --    "tags": ["monetize", "ads"],
    --    "url": "https://support.google.com/googleplay/android-developer/topic/2985714",
    --    "timestamp": null,
    --    "image":"images/play_dev.jpg",
    --    "title": "Policy Center: Ads",
    --    "summary": "Introduction to ads and system interference policies in Google Play.",
    --    "keywords": ["ads"],
    --    "type": "distribute",
    --    "titleFriendly": ""
    --  },
    --  {
    --    "lang": "en",
    --    "group": "",
    --    "tags": [],
    --    "url": "https://support.google.com/analytics/answer/2611404",
    --    "timestamp": null,
    --    "image": "images/cards/analytics-mobile_2x.jpg",
    --    "title": "Create Audience lists in Google Analytics",
    --    "summary": "Find out how to use your analytics data to discover high value users and create remarketing audiences to use in AdMob.",
    --    "keywords": ["ads, analytics, monetize"],
    --    "type": "distribute",
    --    "titleFriendly": ""
    --  },
    --  {
    --    "lang": "en",
    --    "group": "",
    --    "tags": [],
    --    "url": "https://admob.blogspot.com/",
    --    "timestamp": null,
    --    "image": "images/cards/analytics-mobile_2x.jpg",
    --    "title": "Inside Admob",
    --    "summary": "Google’s official blog for news, tips, and information on the AdMob developer platform.",
    --    "keywords": ["ads, analytics, monetize"],
    --    "type": "distribute",
    --    "titleFriendly": ""
    --  },
    --  {
    --    "lang": "en",
    --    "group": "",
    --    "tags": [],
    --    "url": "https://support.google.com/admob/answer/3111064",
    --    "timestamp": null,
    --    "image": "distribute/images/advertising.jpg",
    --    "title": "AdMob in-app conversion tracking",
    --    "summary": "Use in-app conversion tracking to attribute revenue back to your IAP promotion campaigns and determine which ones earn you the most.",
    --    "keywords": ["ads, analytics, conversions"],
    --    "type": "distribute",
    --    "titleFriendly": ""
    --  },
    --  {
    --    "lang": "en",
    --    "group": "",
    --    "tags": ["monetize", "giftcards"],
    --    "url": "https://play.google.com/about/giftcards/",
    --    "timestamp": null,
    --    "image": "images/gp-balance.png",
    --    "title": "Google Play Gift Cards",
    --    "summary": "Buy Google Play gift cards online or at a variety of retail stores.",
    --    "keywords": ["gift card"],
    --    "type": "distribute",
    --    "titleFriendly": ""
    --  },
    --  {
    --    "lang": "en",
    --    "group": "",
    --    "tags": ["monetize", "paymentmethods"],
    --    "url": "https://support.google.com/googleplay/answer/2651410",
    --    "timestamp": null,
    --    "image": "images/play_dev.jpg",
    --    "title": "Google Play accepted payment methods",
    --    "summary": "Support details on the payment methods supported in Google Play.",
    --    "keywords": ["gift card"],
    --    "type": "distribute",
    --    "titleFriendly": ""
    --  },
    --  {
    --    "lang": "en",
    --    "group": "",
    --    "tags": [],
    --    "url": "https://support.google.com/adwords/answer/2471188",
    --    "timestamp": null,
    --    "image": "images/play_dev.jpg",
    --    "title": "AdWords Conversion Optimizer",
    --    "summary": "Learn how Conversion Optimizer works to find the users who are most likely to convert and to serve them your conversion ads.",
    --    "keywords": [],
    --    "type": "distribute",
    --    "titleFriendly": ""
    --  },
    --  {
    --    "lang": "en",
    --    "group": "",
    --    "tags": [],
    --    "url": "https://developers.google.com/app-conversion-tracking/",
    --    "timestamp": null,
    --    "image": "images/play_dev.jpg",
    --    "title": "Track conversions with the AdWords SDK or server API",
    --    "summary": "Use the lightweight AdWords app SDK or server-to-server API to track remarketing conversions.",
    --    "keywords": [],
    --    "type": "distribute",
    --    "titleFriendly": ""
    --  },
    --  {
    --    "lang": "en",
    --    "group": "",
    --    "tags": [],
    --    "url": "https://support.google.com/analytics/answer/2611404",
    --    "timestamp": null,
    --    "image": "images/play_dev.jpg",
    --    "title": "Create Remarketing Audiences in Google Analytics",
    --    "summary": "Learn how to use preconfigured audiences created by the Analytics team or create your own to use in your conversion campaigns.",
    --    "keywords": [],
    --    "type": "distribute",
    --    "titleFriendly": ""
    --  },
    --  {
    --    "lang": "en",
    --    "group": "",
    --    "tags": [],
    --    "url": "https://support.google.com/adwords/answer/1704341",
    --    "timestamp": null,
    --    "image": "images/play_dev.jpg",
    --    "title": "Link your Google Analytics and AdWords accounts",
    --    "summary": "Gain greater insight into how AdWords is driving app engagement and conversions, and use this insight to improve your ads and app.",
    --    "keywords": [],
    --    "type": "distribute",
    --    "titleFriendly": ""
    --  },
    --
    --  {
    --    "lang": "en",
    --    "group": "",
    --    "tags": ["plus", "social"],
    --    "url": "https://plus.google.com/+AndroidDevelopers/",
    --    "timestamp": null,
    --    "image": "images/plus.jpg",
    --    "title": "+Android Developers",
    --    "summary": "Sharing news, ideas, and techniques for success.",
    --    "keywords": ["+AndroidDevelopers"],
    --    "type": "Google+",
    --    "titleFriendly": ""
    --  },
    --  {
    --    "lang": "en",
    --    "group": "",
    --    "tags": ["plus", "social"],
    --    "url": "https://plus.google.com/+GooglePlay",
    --    "timestamp": null,
    --    "image": "https://lh4.googleusercontent.com/-IKezweZlcXI/AAAAAAAAAAI/AAAAAAABOvg/uK8Z0jekVE4/s120-c/photo.jpg",
    --    "title": "+Google Play",
    --    "summary": "News and discussion about Google Play, apps, and other content in Google+.",
    --    "keywords": ["+GooglePlay"],
    --    "type": "Google+",
    --    "titleFriendly": ""
    --  },
    --  {
    --    "lang": "en",
    --    "group": "",
    --    "tags": ["support", "android"],
    --    "url": "support.html",
    --    "timestamp": null,
    --    "image": null,
    --    "title": "Developer Support",
    --    "summary": "Links to community and support resources for Android developers.",
    --    "keywords": ["support"],
    --    "type": "Google+",
    --    "titleFriendly": ""
    --  },
    --  {
    --    "lang": "en",
    --    "group": "",
    --    "tags": [],
    --    "url": "https://developers.google.com/analytics/devguides/collection/android/",
    --    "timestamp": null,
    --    "image": "images/cards/analytics-mobile_2x.jpg",
    --    "title": "Mobile App Analytics SDK",
    --    "summary": "Measure everything about your app. Get started with the Google Analytics SDK for Android.",
    --    "keywords": ["analytics, user behavior"],
    --    "type": "sdk",
    --    "titleFriendly": ""
    --  },
    --  {
    --    "lang": "en",
    --    "group": "",
    --    "tags": [],
    --    "url": "https://developers.google.com/edu/guidelines",
    --    "timestamp": null,
    --    "image": "https://developer.android.com/distribute/images/edu-guidelines.jpg",
    --    "title": "Education Guidelines",
    --    "summary": "These guidelines and requirements help you develop great apps for students, which offer compelling content and an intuitive user experience on Android tablets.",
    --    "keywords": [],
    --    "type": "",
    --    "titleFriendly": ""
    --  },
    --  {
    --    "lang": "zh-cn",
    --    "group": "",
    --    "tags": [],
    --    "url": "https://developers.google.com/edu/guidelines?hl=zh-Hans",
    --    "timestamp": null,
    --    "image": "https://developer.android.com/distribute/images/edu-guidelines.jpg",
    --    "title": "Education Guidelines",
    --    "summary": "These guidelines and requirements help you develop great apps for students, which offer compelling content and an intuitive user experience on Android tablets.",
    --    "keywords": [],
    --    "type": "",
    --    "titleFriendly": ""
    --  },
    --  {
    --    "lang": "en",
    --    "group": "",
    --    "tags": [],
    --    "url": "https://developers.google.com/edu/faq",
    --    "timestamp": null,
    --    "image": "https://developer.android.com/distribute/images/gpfe-faq.jpg",
    --    "title": "Education FAQ",
    --    "summary": "Answers to common questions you might have about Google Play for Education.",
    --    "keywords": [],
    --    "type": "",
    --    "titleFriendly": ""
    --  },
    --  {
    --    "lang": "en",
    --    "group": "",
    --    "tags": [],
    --    "url": "https://developers.google.com/edu/",
    --    "timestamp": null,
    --    "image": "https://developers.google.com/edu/images/home-android.png",
    --    "title": "Chrome Apps in Google Play for Education",
    --    "summary": "Find out more about Chrome apps in Google Play for Education.",
    --    "keywords": [],
    --    "type": "",
    --    "titleFriendly": ""
    --  },
    --  {
    --    "lang": "en",
    --    "group": "",
    --    "tags": [],
    --    "url": "https://www.google.com/edu/tablets/#tablets-family",
    --    "timestamp": null,
    --    "image": "https://www.google.com/edu/images/tablets/big-tablet.png",
    --    "title": "Google Play for Education Tablets",
    --    "summary": "Google Play for Education leverages a diverse set up tablets approved for the classroom which may help inform you how to build educational apps.",
    --    "keywords": [],
    --    "type": "",
    --    "titleFriendly": ""
    --  },
    --  {
    --    "lang": "en",
    --    "group": "",
    --    "tags": [],
    --    "url": "https://storage.googleapis.com/androiddevelopers/shareables/stories/Glu_Deerhunter2014_gpgs.pdf",
    --    "timestamp": null,
    --    "image": "https://storage.googleapis.com/androiddevelopers/shareables/stories/Glu_Deerhunter2014_gpgs.png",
    --    "title": "Deer Hunter 2014 by Glu &mdash; Sign-in",
    --    "summary": "Glu finds that Google Play Game Services helps improve the user experience which leads to increased player happiness. They also find that Play Games Services signed in users tend to play longer and have a higher lifetime value.",
    --    "keywords": ["stories"],
    --    "type": "Case Study Deck",
    --    "titleFriendly": ""
    --  },
    --  {
    --    "lang": "en",
    --    "group": "",
    --    "tags": [],
    --    "url": "https://storage.googleapis.com/androiddevelopers/shareables/stories/ConcreteSoftware_PBABowling_gpgs.pdf",
    --    "timestamp": null,
    --    "image": "https://storage.googleapis.com/androiddevelopers/shareables/stories/ConcreteSoftware_PBABowling_gpgs.png",
    --    "title": "PBA® Bowling Challenge by Concrete Software &mdash; Quests",
    --    "summary": "Concrete Software finds that Google Play Game Services' quests are a great way to create new content for users that leads to higher engagement.",
    --    "keywords": ["stories"],
    --    "type": "Case Study Deck",
    --    "titleFriendly": ""
    --  },
    --  {
    --    "lang": "en",
    --    "group": "",
    --    "tags": [],
    --    "url": "https://storage.googleapis.com/androiddevelopers/shareables/stories/Dragonplay_DragonplaySlots_gpgs.pdf",
    --    "timestamp": null,
    --    "image": "https://storage.googleapis.com/androiddevelopers/shareables/stories/Dragonplay_DragonplaySlots_gpgs.png",
    --    "title": "Dragonplay Slots by Dragonplay &mdash; Sign-in",
    --    "summary": "Dragonplay finds that players who sign in with Google Play Games services tend to be high quality users who were highly engaged. They also tend to be easier to convert to paying users.",
    --    "keywords": ["stories"],
    --    "type": "Case Study Deck",
    --    "titleFriendly": ""
    --  },
    --  {
    --    "lang": "en",
    --    "group": "",
    --    "tags": [],
    --    "url": "https://storage.googleapis.com/androiddevelopers/shareables/stories/Gameloft_Asphalt8_gpgs.pdf",
    --    "timestamp": null,
    --    "image": "https://storage.googleapis.com/androiddevelopers/shareables/stories/Gameloft_Asphalt8_gpgs.png",
    --    "title": "Asphalt 8 by Gameloft &mdash; Friends invitations",
    --    "summary": "Gameloft finds that Google Play Game Services users are more engaged than the average Android user and more likely to convert to paying players.",
    --    "keywords": ["stories"],
    --    "type": "Case Study Deck",
    --    "titleFriendly": ""
    --  },
    --  {
    --    "lang": "en",
    --    "group": "",
    --    "tags": [],
    --    "url": "https://storage.googleapis.com/androiddevelopers/shareables/stories/Glu_EternityWarriors3_gpgs.pdf",
    --    "timestamp": null,
    --    "image": "https://storage.googleapis.com/androiddevelopers/shareables/stories/Glu_EternityWarriors3_gpgs.png",
    --    "title": "Eternity Warriors 3 by Glu &mdash; Gifting",
    --    "summary": "Glu finds that Google Play Game Services gifting outperforms other implementations (including those with incentives) because of its seamless flow and consistent performance.",
    --    "keywords": ["stories"],
    --    "type": "Case Study Deck",
    --    "titleFriendly": ""
    --  },
    --  {
    --    "lang": "en",
    --    "group": "",
    --    "tags": [],
    --    "url": "https://storage.googleapis.com/androiddevelopers/shareables/stories/HotheadGames_RivalsatWar_gpgs.pdf",
    --    "timestamp": null,
    --    "image": "https://storage.googleapis.com/androiddevelopers/shareables/stories/HotheadGames_RivalsatWar_gpgs.jpg",
    --    "title": "Rivals at War: Firefight by Hothead Games &mdash; Leaderboards",
    --    "summary": "Hothead Games is planning to include Google Play Game Services features in all their games going forwards after seeing that players that signed in with Play Games Services tend to show higher retention and a higher average revenue.",
    --    "keywords": ["stories"],
    --    "type": "Case Study Deck",
    --    "titleFriendly": ""
    --  },
    --  {
    --    "lang": "en",
    --    "group": "",
    --    "tags": [],
    --    "url": "https://storage.googleapis.com/androiddevelopers/shareables/stories/TMSOFT_Compulsive_gpgs.pdf",
    --    "timestamp": null,
    --    "image": "https://storage.googleapis.com/androiddevelopers/shareables/stories/TMSOFT_Compulsive_gpgs.png",
    --    "title": "Compulsive by TMSOFT &mdash; Cross-platform",
    --    "summary": "TMSOFT finds that users who authenticate with Play Games Services on Android and iOS play Compulsive twice as much and purchase in-app products over four times as much.",
    --    "keywords": ["stories"],
    --    "type": "Case Study Deck",
    --    "titleFriendly": ""
    --  },
    --  {
    --    "lang": "en",
    --    "group": "",
    --    "tags": [],
    --    "url": "https://storage.googleapis.com/androiddevelopers/shareables/stories/Noodlecake_SuperStickmanGolf2_gpgs.pdf",
    --    "timestamp": null,
    --    "image": "https://storage.googleapis.com/androiddevelopers/shareables/stories/Noodlecake_SuperStickmanGolf2_gpgs.png",
    --    "title": "Super Stickman Golf 2 by Noodlecake Studios &mdash; Multiplayer",
    --    "summary": "Noodlecake Studios finds that Google Play Game Services’ multiplayer feature helps reduce attrition.",
    --    "keywords": ["stories"],
    --    "type": "Case Study Deck",
    --    "titleFriendly": ""
    --  },
    --  {
    --    "lang": "en",
    --    "group": "",
    --    "tags": [],
    --    "url": "https://storage.googleapis.com/androiddevelopers/shareables/stories/TinyRebel_DoctorWhoLegacy_gpgs.pdf",
    --    "timestamp": null,
    --    "image": "https://storage.googleapis.com/androiddevelopers/shareables/stories/TinyRebelGames_DrWhoLegacy_pgps.png",
    --    "title": "Dr. Doctor Who: Legacy by Tiny Rebel Games &mdash; Achievements",
    --    "summary": "After integrating achievements and cloud services from Google Play Game Services, Tiny Rebel Games saw a dramatic increase in daily revenues as a result of an increase in daily installs and an increase in the average revenue per install.",
    --    "keywords": ["stories"],
    --    "type": "Case Study Deck",
    --    "titleFriendly": ""
    --  },
    --  {
    --    "lang": "en",
    --    "group": "",
    --    "tags": [],
    --    "url": "https://storage.googleapis.com/androiddevelopers/shareables/stories/Senri_LeosFortune_gpgs.pdf",
    --    "timestamp": null,
    --    "image": "https://storage.googleapis.com/androiddevelopers/shareables/stories/Senri_LeosFortune_gpgs.png",
    --    "title": "Leo’s Fortune by 1337 &amp; Senri &mdash; Saved games",
    --    "summary": "1337 + Senri finds that Google Play Game Services is easy to integrate and provides essential game functions like cloud saved games, achievements and leaderboards which have a very large adoption rate amongst players.",
    --    "keywords": ["stories"],
    --    "type": "Case Study Deck",
    --    "titleFriendly": ""
    --  },
    --  {
    --    "lang": "en",
    --    "group": "",
    --    "tags": ["play,protips"],
    --    "url": "shareables/distribute/secrets_play/v2/web/secrets_to_app_success_v2_en.pdf",
    --    "timestamp": 1447437450,
    --    "image": "images/distribute/secrets_v2_banner.jpg",
    --    "title": "The Secrets to App Success on Google Play",
    --    "summary": "Get the updated guide full of useful features, tips, and best practices that will help you grow a successful app or game business on Google Play.",
    --    "keywords": ["secrets, success, play, google"],
    --    "type": "Book",
    --    "category": "distribute"
    --  },
    --  {
    --    "lang": "en",
    --    "group": "",
    --    "tags": [],
    --    "url": "shareables/auto/AndroidAuto-audio-apps.pdf",
    --    "timestamp": null,
    --    "image": "auto/images/assets/icons/media_app_playback.png",
    --    "title": "Android Auto Audio Apps UI Guidelines",
    --    "summary": "Guidelines for designing audio apps that work with Auto. ",
    --    "keywords": ["design", "Auto", "Automotive"],
    --    "type": "Design",
    --    "titleFriendly": ""
    --  },
    --  {
    --    "lang": "en",
    --    "group": "",
    --    "tags": [],
    --    "url": "shareables/auto/AndroidAuto-messaging-apps.pdf",
    --    "timestamp": null,
    --    "image": "auto/images/assets/icons/messaging_app_notifications.png",
    --    "title": "Android Auto Messaging Apps UI Guidelines",
    --    "summary": "Guidelines for designing messaging apps that work with Auto. ",
    --    "keywords": ["design", "Auto", "Automotive"],
    --    "type": "Design",
    --    "titleFriendly": ""
    --  },
    --  {
    --    "lang": "en",
    --    "group": "",
    --    "tags": [],
    --    "url": "shareables/auto/AndroidAuto-custom-colors.pdf",
    --    "timestamp": null,
    --    "image": "auto/images/ui/gearhead_generic_UI.png",
    --    "title": "Android Auto Color Customization UI Guidelines",
    --    "summary": "Guidelines for color-customizing apps that work with Auto. ",
    --    "keywords": ["design", "Auto", "Automotive"],
    --    "type": "Design",
    --    "titleFriendly": ""
    --  },
    --  {
    --    "lang": "en",
    --    "group": "",
    --    "tags": [],
    --    "url": "http://www.youtube.com/watch?v=RRelFvc6Czo",
    --    "timestamp": null,
    --    "image": "https://i1.ytimg.com/vi/RRelFvc6Czo/maxresdefault.jpg",
    --    "title": "Android Developer Story: Smule",
    --    "summary": "The creators of AutoRap, Magic Piano, and Songify talk about their experiences launching on Android and the explosive global growth they've seen on Google Play.",
    --    "keywords": ["success", "users"],
    --    "type": "video",
    --    "titleFriendly": ""
    --  },
    --  {
    --    "lang": "en",
    --    "group": "",
    --    "tags": [],
    --    "url": "https://developers.google.com/analytics/solutions/mobile-implementation-guide",
    --    "timestamp": null,
    --    "image": "images/cards/analytics-mobile_2x.jpg",
    --    "title": "Mobile Analytics Implementation Guide",
    --    "summary": "Learn how you can implement additional Google Analytics features to better understand your users and their behavior.",
    --    "keywords": ["analytics", "Play", "users"],
    --    "type": "guide",
    --    "titleFriendly": ""
    --  },
    --  {
    --    "lang": "en",
    --    "group": "",
    --    "tags": [],
    --    "url": "https://www.google.com/tagmanager/",
    --    "timestamp": null,
    --    "image": "https://www.google.com/tagmanager/images/gtm-hero-illustration-small.png",
    --    "title": "Google Tag Manager",
    --    "summary": "Google Tag Manager enables you to change configuration values in your mobile apps using the Google Tag Manager interface, without having to rebuild and resubmit application binaries to app marketplaces.",
    --    "keywords": ["analytics", "tagmanager"],
    --    "type": "guide",
    --    "titleFriendly": ""
    --  },
    --  {
    --    "lang": "en",
    --    "group": "",
    --    "tags": [],
    --    "url": "https://analyticsacademy.withgoogle.com/course04",
    --    "timestamp": null,
    --    "image": "images/cards/analytics-mobile_2x.jpg",
    --    "title": "Mobile App Analytics Fundamentals",
    --    "summary": "This self-paced online course on mobile app measurement shows you how Google Analytics data can help you make your app more discoverable and profitable.",
    --    "keywords": ["analytics"],
    --    "type": "Open Source Project",
    --    "titleFriendly": ""
    --  },
    --  {
    --    "lang": "en",
    --    "group": "",
    --    "tags": [],
    --    "url": "https://github.com/googleanalytics/google-analytics-plugin-for-unity",
    --    "timestamp": null,
    --    "image": "images/cards/analytics-mobile_2x.jpg",
    --    "title": "Analytics Plugin for Unity",
    --    "summary": "If you're building games with Unity, you can now implement Analytics once and ship it on multiple platforms automatically.",
    --    "keywords": ["analytics", "unity"],
    --    "type": "Open Source Project",
    --    "titleFriendly": ""
    --  },
    --  {
    --    "lang": "en",
    --    "group": "",
    --    "tags": [],
    --    "url": "https://developers.google.com/analytics/devguides/collection/android/v4/enhanced-ecommerce",
    --    "timestamp": null,
    --    "image": "images/cards/analytics-mobile_2x.jpg",
    --    "title": "In-App Purchases & Ecommerce",
    --    "summary": "If your app sells virtual or real goods, ecommerce tracking can help you understand what behaviors lead to purchases.",
    --    "keywords": ["analytics, ecommerce"],
    --    "type": "Guide",
    --    "titleFriendly": ""
    --  },
    --  {
    --    "lang": "en",
    --    "group": "",
    --    "tags": [],
    --    "url": "https://support.google.com/analytics/answer/1032415",
    --    "timestamp": null,
    --    "image": "images/cards/analytics-mobile_2x.jpg",
    --    "title": "Goals",
    --    "summary": "Track important actions in your app as goals and measure performance against your objectives.",
    --    "keywords": ["analytics"],
    --    "type": "Guide",
    --    "titleFriendly": ""
    --  },
    --  {
    --    "lang": "en",
    --    "group": "",
    --    "tags": [],
    --    "url": "https://support.google.com/analytics/answer/2568874?ref_topic=6012392",
    --    "timestamp": null,
    --    "image": "images/cards/analytics-mobile_2x.jpg",
    --    "title": "Active Users",
    --    "summary": "The active user report displays your 1-day, 7-day, 14-day and 30-day trailing active users next to each other, to help you analyze performance over time.",
    --    "keywords": ["analytics"],
    --    "type": "Guide",
    --    "titleFriendly": ""
    --  },
    --  {
    --    "lang": "en",
    --    "group": "",
    --    "tags": [],
    --    "url": "https://developers.google.com/analytics/devguides/collection/android/v4/events",
    --    "timestamp": null,
    --    "image": "images/cards/analytics-mobile_2x.jpg",
    --    "title": "Events",
    --    "summary": "Events let you measure granular in-app activities and understand user journeys.",
    --    "keywords": ["analytics"],
    --    "type": "Guide",
    --    "titleFriendly": ""
    --  },
    --  {
    --    "lang": "en",
    --    "group": "",
    --    "tags": [],
    --    "url": "https://developers.google.com/analytics/devguides/collection/android/v4/customdimsmets",
    --    "timestamp": null,
    --    "image": "images/cards/analytics-mobile_2x.jpg",
    --    "title": "Custom Dimensions",
    --    "summary": "Custom dimensions enable the association of metadata with hits, users, and sessions in Google Analytics.",
    --    "keywords": ["analytics"],
    --    "type": "Guide",
    --    "titleFriendly": ""
    --  },
    --  {
    --    "lang": "en",
    --    "group": "",
    --    "tags": [],
    --    "url": "https://developers.google.com/analytics/devguides/collection/android/v4/user-id",
    --    "timestamp": null,
    --    "image": "images/cards/analytics-mobile_2x.jpg",
    --    "title": "User ID",
    --    "summary": "The User ID feature enables Google Analytics to measure user activities that span across devices.",
    --    "keywords": ["analytics"],
    --    "type": "Guide",
    --    "titleFriendly": ""
    --  },
    --  {
    --    "lang": "en",
    --    "group": "",
    --    "tags": [],
    --    "url": "https://developers.google.com/analytics/devguides/collection/android/v4/display-features",
    --    "timestamp": null,
    --    "image": "images/cards/analytics-mobile_2x.jpg",
    --    "title": "Demographic Reporting",
    --    "summary": "By enabling display features, you can see just how different user segments engage and monetize.",
    --    "keywords": ["analytics"],
    --    "type": "Guide",
    --    "titleFriendly": ""
    --  },
    --  {
    --    "lang": "en",
    --    "group": "",
    --    "tags": [],
    --    "url": "https://support.google.com/analytics/answer/3123906",
    --    "timestamp": null,
    --    "image": "images/cards/analytics-mobile_2x.jpg",
    --    "title": "User Segmentation",
    --    "summary": "Segments let you compare metrics for different subsets of users to identify trends and opportunities for your apps.",
    --    "keywords": ["analytics"],
    --    "type": "Guide",
    --    "titleFriendly": ""
    --  },
    --  {
    --    "lang": "en",
    --    "group": "",
    --    "tags": [],
    --    "url": "https://developers.google.com/analytics/devguides/collection/android/v4/campaigns",
    --    "timestamp": null,
    --    "image": "images/cards/analytics-mobile_2x.jpg",
    --    "title": "Campaign Tracking",
    --    "summary": "Measuring campaigns in Google Analytics enables the attribution of campaigns and traffic sources to user activity within your app.",
    --    "keywords": ["analytics"],
    --    "type": "Guide",
    --    "titleFriendly": ""
    --  },
    --  {
    --    "lang": "en",
    --    "group": "",
    --    "tags": [],
    --    "url": "https://support.google.com/analytics/answer/2956981",
    --    "timestamp": null,
    --    "image": "images/play_dev.jpg",
    --    "title": "Google Play Integration",
    --    "summary": "By linking Analytics and the Play Developer Console, you can gain additional insights into the acquisition flow.",
    --    "keywords": ["play, analytics"],
    --    "type": "Guide",
    --    "titleFriendly": ""
    --  },
    --  {
    --    "lang": "en",
    --    "group": "",
    --    "tags": [],
    --    "url": "https://support.google.com/analytics/answer/1033961",
    --    "timestamp": null,
    --    "image": "images/cards/analytics-mobile_2x.jpg",
    --    "title": "AdWords Integration",
    --    "summary": "Link Analytics and AdWords to see the entire picture of customer behavior, from ad click or impression through your site to conversion. ",
    --    "keywords": ["adwords, analytics"],
    --    "type": "Guide",
    --    "titleFriendly": ""
    --  },
    --  {
    --    "lang": "en",
    --    "group": "",
    --    "tags": [],
    --    "url": "https://developers.google.com/analytics/devguides/collection/android/v4/campaigns#google-play-url-builder",
    --    "timestamp": null,
    --    "image": "images/cards/analytics-mobile_2x.jpg",
    --    "title": "Campaign URL builder for Google Play",
    --    "summary": "Easily create your URLs to track install campaigns.",
    --    "keywords": ["play, analytics"],
    --    "type": "Guide",
    --    "titleFriendly": ""
    --  },
    --  {
    --    "lang": "en",
    --    "group": "",
    --    "tags": [],
    --    "url": "https://support.google.com/tagmanager/answer/6003007",
    --    "timestamp": null,
    --    "image": "https://www.google.com/tagmanager/images/gtm-hero-illustration-small.png",
    --    "title": "In-App A/B Testing",
    --    "summary": "With content experiments in Google Tag Manager you can test multiple variations of your app to find which works best.",
    --    "keywords": ["tagmanager"],
    --    "type": "Guide",
    --    "titleFriendly": ""
    --  },
    --  {
    --    "lang": "en",
    --    "group": "",
    --    "tags": [],
    --    "url": "https://support.google.com/analytics/answer/2785577",
    --    "timestamp": null,
    --    "image": "images/cards/analytics-mobile_2x.jpg",
    --    "title": "Behavior Flow",
    --    "summary": "The Behavior Flow report visualizes the path users traveled from one Screen or Event to the next. This report can help you discover what content keeps users engaged with your app.",
    --    "keywords": ["analytics"],
    --    "type": "Guide",
    --    "titleFriendly": ""
    --  },
    --  {
    --    "lang": "en",
    --    "group": "",
    --    "tags": [],
    --    "url": "https://support.google.com/analytics/answer/1151300",
    --    "timestamp": null,
    --    "image": "images/cards/analytics-mobile_2x.jpg",
    --    "title": "Custom Reports",
    --    "summary": "Custom Reports let you create your own reports in your Google Analytics account.",
    --    "keywords": ["analytics"],
    --    "type": "Guide",
    --    "titleFriendly": ""
    --  },
    --  {
    --    "lang": "en",
    --    "group": "",
    --    "tags": [],
    --    "url": "https://support.google.com/analytics/answer/2611268",
    --    "timestamp": null,
    --    "image": "images/cards/analytics-mobile_2x.jpg",
    --    "title": "Audience Lists &amp; Remarketing",
    --    "summary": "Remarketing with Google Analytics lets you deliver targeted ads to users who've already been to your site or app. You can even base those ads on the behavior those users displayed during their sessions.",
    --    "keywords": ["analytics"],
    --    "type": "Guide",
    --    "titleFriendly": ""
    --  },
    --  {
    --    "lang": "en",
    --    "group": "",
    --    "tags": [],
    --    "url": "https://support.google.com/admob/answer/3508177",
    --    "timestamp": null,
    --    "image": "images/cards/analytics-mobile_2x.jpg",
    --    "title": "AdMob Integration",
    --    "summary": "With Google Analytics in AdMob, you can view Google Analytics data for your linked apps from within your AdMob account.",
    --    "keywords": ["analytics"],
    --    "type": "Guide",
    --    "titleFriendly": ""
    --  },
    --  {
    --    "lang": "en",
    --    "group": "",
    --    "tags": [],
    --    "url": "https://developers.google.com/analytics/solutions/mobile-campaign-deep-link",
    --    "timestamp": null,
    --    "image": "images/cards/analytics-mobile_2x.jpg",
    --    "title": "Deep-Linking",
    --    "summary": "Google Analytics gives you a full view of how returning users are interacting with your app, for a holistic view beyond the install.",
    --    "keywords": ["analytics"],
    --    "type": "Guide",
    --    "titleFriendly": ""
    --  },
    --  {
    --    "lang": "en",
    --    "group": "",
    --    "tags": [],
    --    "url": "https://support.google.com/admob/answer/3508177",
    --    "timestamp": null,
    --    "image": "images/cards/analytics-mobile_2x.jpg",
    --    "title": "AdMob Integration",
    --    "summary": "With Google Analytics in AdMob, you can view Google Analytics data for your linked apps from within your AdMob account.",
    --    "keywords": ["analytics"],
    --    "type": "Guide",
    --    "titleFriendly": ""
    --  },
    --  {
    --    "lang": "en",
    --    "group": "",
    --    "tags": [],
    --    "url": "https://support.google.com/analytics/answer/2568874",
    --    "timestamp": null,
    --    "image": "images/cards/analytics-mobile_2x.jpg",
    --    "title": "Active User Report",
    --    "summary": "Active user report displays your 1-day, 7-day, 14-day and 30-day trailing active users next to each other, to help you run benchmark analyses of their performance over time.",
    --    "keywords": ["analytics"],
    --    "type": "Guide",
    --    "titleFriendly": ""
    --  },
    --  {
    --    "lang": "en",
    --    "group": "",
    --    "tags": [],
    --    "url": "https://www.google.com/design/spec/animation/",
    --    "timestamp": null,
    --    "image": "images/cards/material-animation_2x.png",
    --    "title": "Animation",
    --    "summary": "",
    --    "keywords": [],
    --    "type": "material design",
    --    "titleFriendly": ""
    --  },
    --  {
    --    "lang": "en",
    --    "group": "",
    --    "tags": [],
    --    "url": "https://www.google.com/design/spec/style/",
    --    "timestamp": null,
    --    "image": "images/cards/material-style_2x.jpg",
    --    "title": "Style",
    --    "summary": "",
    --    "keywords": [],
    --    "type": "material design",
    --    "titleFriendly": ""
    --  },
    --  {
    --    "lang": "en",
    --    "group": "",
    --    "tags": [],
    --    "url": "https://www.google.com/design/spec/layout/",
    --    "timestamp": null,
    --    "image": "images/cards/material-layout_2x.png",
    --    "title": "Layout",
    --    "summary": "",
    --    "keywords": [],
    --    "type": "material design",
    --    "titleFriendly": ""
    --  },
    --  {
    --    "lang": "en",
    --    "group": "",
    --    "tags": [],
    --    "url": "https://www.google.com/design/spec/components/",
    --    "timestamp": null,
    --    "image": "images/cards/material-components_2x.jpg",
    --    "title": "Components",
    --    "summary": "",
    --    "keywords": [],
    --    "type": "material design",
    --    "titleFriendly": ""
    --  },
    --  {
    --    "lang": "en",
    --    "group": "",
    --    "tags": [],
    --    "url": "https://www.google.com/design/spec/patterns/",
    --    "timestamp": null,
    --    "image": "images/cards/material-patterns_2x.png",
    --    "title": "Patterns",
    --    "summary": "",
    --    "keywords": [],
    --    "type": "material design",
    --    "titleFriendly": ""
    --  },
    --  {
    --    "lang": "en",
    --    "group": "",
    --    "tags": [],
    --    "url": "https://www.google.com/design/spec/usability/",
    --    "timestamp": null,
    --    "image": "images/cards/material-usability_2x.png",
    --    "title": "Usability",
    --    "summary": "",
    --    "keywords": [],
    --    "type": "material design",
    --    "titleFriendly": ""
    --  },
    --  {
    --    "lang": "en",
    --    "group": "",
    --    "tags": [],
    --    "url": "https://www.google.com/design/spec/resources/color-palettes.html",
    --    "timestamp": null,
    --    "image": "images/cards/material-color-palette_2x.jpg",
    --    "title": "Color Palettes",
    --    "summary": "",
    --    "keywords": [],
    --    "type": "material design",
    --    "titleFriendly": ""
    --  },
    --  {
    --    "lang": "en",
    --    "group": "",
    --    "tags": [],
    --    "url": "https://www.google.com/design/spec/resources/layout-templates.html",
    --    "timestamp": null,
    --    "image": "images/cards/material-layout-template_2x.jpg",
    --    "title": "Layout Templates",
    --    "summary": "",
    --    "keywords": [],
    --    "type": "material design",
    --    "titleFriendly": ""
    --  },
    --  {
    --    "lang": "en",
    --    "group": "",
    --    "tags": [],
    --    "url": "https://www.google.com/design/spec/resources/sticker-sheets-icons.html",
    --    "timestamp": null,
    --    "image": "images/cards/material-sticker-sheet_2x.jpg",
    --    "title": "Sticker Sheets & Icons",
    --    "summary": "",
    --    "keywords": [],
    --    "type": "material design",
    --    "titleFriendly": ""
    --  },
    --  {
    --    "lang": "en",
    --    "group": "",
    --    "tags": [],
    --    "url": "https://www.google.com/design/spec/resources/roboto-noto-fonts.html",
    --    "timestamp": null,
    --    "image": "images/cards/material-typography_2x.jpg",
    --    "title": "Typography: Roboto and Noto Sans fonts",
    --    "summary": "",
    --    "keywords": [],
    --    "type": "materialdesign",
    --    "titleFriendly": ""
    --  },
    --  {
    --    "lang": "en",
    --    "group": "",
    --    "tags": [
    --      "icons",
    --      "material",
    --      "iconography"
    --    ],
    --    "url": "https://www.google.com/design/icons/index.html",
    --    "timestamp": null,
    --    "image": "images/cards/card-material-icons-16x9_2x.jpg",
    --    "title": "Material icon collection",
    --    "summary": "",
    --    "keywords": ["icons"],
    --    "type": "material design",
    --    "titleFriendly": ""
    --  },
    --  {
    --    "lang": "en",
    --    "group": "",
    --    "tags": [],
    --    "url": "https://support.google.com/adwords/answer/6032059",
    --    "timestamp": null,
    --    "image": "distribute/images/advertising.jpg",
    --    "title": "Setting up Mobile App Install Ads",
    --    "summary": "With Mobile app installs campaigns on the Search and Display Networks, and TrueView for mobile app promotion on YouTube, you can create custom app install ads that run exclusively on phones and tablets.",
    --    "keywords": ["marketing", "admob"],
    --    "type": "distribute",
    --    "titleFriendly": ""
    --  },
    --  {
    --    "lang": "en",
    --    "group": "",
    --    "tags": [],
    --    "url": "https://developers.google.com/nearby/",
    --    "timestamp": null,
    --    "image": "images/play_dev.jpg",
    --    "title": "Create features based on proximity",
    --    "summary": "Build simple interactions between nearby devices and people.",
    --    "keywords": ["nearby", "engage"],
    --    "type": "distribute",
    --    "titleFriendly": ""
    --  },
    --  {
    --    "lang": "en",
    --    "group": "",
    --    "tags": [],
    --    "url": "https://www.youtube.com/watch?v=hultDpBS22s",
    --    "timestamp": null,
    --    "image": "images/play_dev.jpg",
    --    "title": "Use Nearby Messages to collaborate",
    --    "summary": "Nearby Messages is perfect for setting up ad-hoc groups, collaborative sessions, or sharing resources with people in a co-located space.",
    --    "keywords": ["nearby", "engage"],
    --    "type": "distribute",
    --    "titleFriendly": ""
    --  },
    --  {
    --    "lang": "en",
    --    "group": "",
    --    "tags": [],
    --    "url": "https://developers.google.com/beacons",
    --    "timestamp": null,
    --    "image": "images/play_dev.jpg",
    --    "title": "Mark up the world using beacons",
    --    "summary": "Give your users better location and proximity experiences by providing a strong context signal for their devices in the form of Bluetooth low energy (BLE) beacons with Eddystone.",
    --    "keywords": ["nearby", "engage"],
    --    "type": "distribute",
    --    "titleFriendly": ""
    --  },
    --  {
    --    "lang": "en",
    --    "group": "",
    --    "tags": [],
    --    "url": "https://support.google.com/adwords/answer/6167164",
    --    "timestamp": null,
    --    "image": "distribute/images/advertising.jpg",
    --    "title": "Best practices for Mobile App Engagement",
    --    "summary": "Learn how to market to your user base to drive re-engagement with your app. ",
    --    "keywords": ["marketing", "admob"],
    --    "type": "distribute",
    --    "titleFriendly": ""
    --  },
    --  {
    --    "lang": "en",
    --    "group": "",
    --    "tags": [
    --      "marketing",
    --      "engagement",
    --      "adwords1"
    --    ],
    --    "url": "https://support.google.com/adwords/answer/6032073",
    --    "timestamp": null,
    --    "image": "https://www.gstatic.com/images/icons/material/product/2x/adwords_64dp.png",
    --    "title": "Setting up Mobile App Engagement Ads",
    --    "summary": "Mobile app engagement campaigns are a great choice for advertisers focused on connecting with people who already have their app.",
    --    "keywords": [
    --      "marketing",
    --      "engagement",
    --      "adwords"
    --    ],
    --    "type": "distribute",
    --    "titleFriendly": ""
    --  },
    --  {
    --    "lang": "en",
    --    "group": "",
    --    "tags": [
    --      "marketing",
    --      "engagement",
    --      "translate"
    --    ],
    --    "url": "https://support.google.com/l10n/answer/6359997",
    --    "timestamp": null,
    --    "image": "images/play_dev.jpg",
    --    "title": "Use the App Translation Service",
    --    "summary": "The App Translation Service is a human translation service. It makes it easy to order translations for app UI strings, Play Store text, in-app purchase products, and universal app campaign ads.",
    --    "keywords": [
    --      "marketing",
    --      "engagement",
    --      "translate"
    --    ],
    --    "type": "distribute",
    --    "titleFriendly": ""
    --  },
    --  {
    --    "lang": "en",
    --    "group": "",
    --    "tags": [
    --      "marketing",
    --      "engagement"
    --    ],
    --    "url": "https://support.google.com/adwords/answer/6167162",
    --    "timestamp": null,
    --    "image": "https://www.gstatic.com/images/icons/material/product/2x/adwords_64dp.png",
    --    "title": "Best Practices for Mobile App Installs",
    --    "summary": "Getting your mobile app discovered can be challenging. Learn how to drive downloads of your app and grow a valuable user base.",
    --    "keywords": ["marketing", "adwords"],
    --    "type": "distribute",
    --    "titleFriendly": ""
    --  },
    --  {
    --    "lang": "en",
    --    "group": "",
    --    "tags": [],
    --    "url": "https://support.google.com/admob/topic/2784623",
    --    "timestamp": null,
    --    "image": "distribute/images/advertising.jpg",
    --    "title": "Set up your AdMob account",
    --    "summary": "Setting up your AdMob account in the right way will help you get the most value, check out the Setup and Basics guide.",
    --    "keywords": ["marketing", "admob"],
    --    "type": "distribute",
    --    "titleFriendly": ""
    --    },
    --    {
    --    "lang": "en",
    --    "group": "",
    --    "tags": [],
    --    "url": "https://analyticsacademy.withgoogle.com/mobile-app",
    --    "timestamp": null,
    --    "image": "distribute/images/advertising.jpg",
    --    "title": "Analytics Academy for Mobile Apps",
    --    "summary": "Learn how to use Google Analytics to make your app more discoverable and profitable.",
    --    "keywords": ["marketing", "analytics"],
    --    "type": "distribute",
    --    "titleFriendly": ""
    --  },
    --  {
    --    "lang": "en",
    --    "group": "",
    --    "tags": [],
    --    "url": "https://www.udacity.com/courses/ud876-3",
    --    "timestamp": null,
    --    "image": "distribute/images/advertising.jpg",
    --    "title": "Learn how to show ads in your Android app",
    --    "summary": "Take this online course to learn how to use AdMob to display ads in your Android app.",
    --    "keywords": ["marketing", "analytics"],
    --    "type": "distribute",
    --    "titleFriendly": ""
    --  },
    --  {
    --    "lang": "en",
    --    "group": "",
    --    "tags": [],
    --    "url": "https://developers.google.com/mobile-ads-sdk/download",
    --    "timestamp": null,
    --    "image": "distribute/images/advertising.jpg",
    --    "title": "Admob Ads",
    --    "summary": "Use the Mobile Ads SDK to start showing AdMob ads in your apps.",
    --    "keywords": ["marketing", "adwords"],
    --    "type": "Guide",
    --    "titleFriendly": ""
    --  },
    --  {
    --    "lang": "en",
    --    "group": "",
    --    "tags": [],
    --    "url": "https://support.google.com/admob/",
    --    "timestamp": null,
    --    "image": "distribute/images/advertising.jpg",
    --    "title": "AdMob Help Center",
    --    "summary": "For setup assistance, general info, and fixes for specific problems check out the AdMob Help Center.",
    --    "keywords": ["admob"],
    --    "type": "distribute",
    --    "titleFriendly": ""
    --  },
    --  {
    --    "lang": "en",
    --    "group": "",
    --    "tags": [],
    --    "url": "https://support.google.com/admob/answer/2753860",
    --    "timestamp": null,
    --    "image": "distribute/images/advertising.jpg",
    --    "title": "AdMob Policy Guidelines",
    --    "summary": "Learn about best practices for displaying AdMob ads in your apps to maximize revenue.",
    --    "keywords": ["admob"],
    --    "type": "distribute",
    --    "titleFriendly": ""
    --  },
    --  {
    --    "lang": "en",
    --    "group": "",
    --    "tags": [],
    --    "url": "https://developers.google.com/app-invites/",
    --    "timestamp": 1383243492000,
    --    "image": "images/cards/google-search_2x.png",
    --    "title": "Set up App Invites",
    --    "summary": "Bring new users to your apps with personal recommendations, incentives, and offers.",
    --    "keywords": ["invites", "appinvites", "engagement", "getusers"],
    --    "type": "guide",
    --    "titleFriendly": ""
    --  },
    --
    --  {
    --    "lang": "en",
    --    "group": "",
    --    "tags": [],
    --    "url": "https://developers.google.com/app-indexing/",
    --    "timestamp": 1383243492000,
    --    "image": "images/cards/google-search_2x.png",
    --    "title": "Set Up App Indexing",
    --    "summary": "Surface your app content in Google seaerch. Deep link direct to your apps.",
    --    "keywords": ["search", "appindexing", "engagement", "getusers"],
    --    "type": "guide",
    --    "titleFriendly": ""
    --  },
    --  {
    --    "lang": "en",
    --    "group": "",
    --    "tags": [],
    --    "url": "https://developers.google.com/app-indexing/webmasters/details",
    --    "timestamp": null,
    --    "image": "images/cards/google-search_2x.png",
    --    "title": "Index your app",
    --    "summary": "Index your app today by adding deep links and verifying its official web site to ensure it starts appearing in Google Search results. ",
    --    "keywords": ["appindexing","search","getusers"],
    --    "type": "distribute",
    --    "titleFriendly": ""
    --  },
    --  {
    --    "lang": "en",
    --    "group": "",
    --    "tags": [],
    --    "url": "https://developers.google.com/identity/sign-in/android/people",
    --    "timestamp": 1383243492000,
    --    "image": "images/cards/google-sign-in_2x.png",
    --    "title": "Get user profile details",
    --    "summary": "After users sign-in with Google, you can access their age range, language, and public profile information.",
    --    "keywords": ["signin", "identity", "google"],
    --    "type": "guide",
    --    "titleFriendly": ""
    --  },
    --
    --
    --  {
    --    "lang": "en",
    --    "group": "",
    --    "tags": [],
    --    "url": "https://developers.google.com/identity/sign-in/android/",
    --    "timestamp": "",
    --    "image": "images/cards/google-sign-in_2x.png",
    --    "title": "Google Sign-In",
    --    "summary": "Discover how you can enhance user experiences on your website or in your app using information provided by their Google identity.",
    --    "keywords": ["signin", "identity", "google"],
    --    "type": "guide",
    --    "titleFriendly": ""
    --  },
    --  {
    --    "lang": "en",
    --    "group": "",
    --    "tags": [],
    --    "url": "https://developers.google.com/+/features/play-installs",
    --    "timestamp": 1383243492000,
    --    "image": "images/cards/google-sign-in_2x.png",
    --    "title": "Over-the-air installs",
    --    "summary": "Follow this step-by-step guide to quickly add Google Sign-in and over-the-air app installs to your website.",
    --    "keywords": ["signin", "google", "installs"],
    --    "type": "guide",
    --    "titleFriendly": ""
    --  },
    --  {
    --    "lang": "en",
    --    "group": "",
    --    "tags": [],
    --    "url": "https://developers.google.com/+/features/analytics",
    --    "timestamp": 1383243492000,
    --    "image": 'images/google/gps-googleplus.png',
    --    "title": "Google+ Insights",
    --    "summary": "Measure impressions of the over-the-air install prompt, resulting installs, and success rate by day, week, and month.",
    --    "keywords": ["signin", "identity"],
    --    "type": "guide",
    --    "titleFriendly": ""
    --  },
    --
    -- // Online courses
    --
    -- {
    --    "title":"UX Design for Mobile Developers",
    --    "titleFriendly":"",
    --    "summary":"Learn how to design a 5-star app.",
    --    "url":"https://www.udacity.com/course/ud849",
    --    "group":"",
    --    "keywords": ["mobile","ux","design"],
    --    "tags": ["courses, start"],
    --    "image":"images/cards/courses/mobile_ux_course.jpg",
    --    "lang":"en",
    --    "type":"online course"
    --  },
    --  {
    --    "title":"Developing Android Apps",
    --    "titleFriendly":"",
    --    "summary":"Learn Android and build an app!",
    --    "url":"https://www.udacity.com/course/ud853",
    --    "group":"",
    --    "keywords": ["android", "start","firstapp","sdk"],
    --    "tags": ["courses, start"],
    --    "image":"images/cards/courses/android_fundamentals_course.jpg",
    --    "lang":"en",
    --    "type":"online course"
    --  },
    --  {
    --    "title":"Android Performance",
    --    "titleFriendly":"",
    --    "summary":"Optimize your apps for speed and usability.",
    --    "url":"https://www.udacity.com/course/ud825",
    --    "group":"",
    --    "keywords": ["android, performance","battery"],
    --    "tags": ["courses, performance"],
    --    "image":"images/cards/courses/android_performance_course.jpg",
    --    "lang":"en",
    --    "type":"online course"
    --  },
    --  {
    --    "title":"Enroll in the Android Nanodegree",
    --    "titleFriendly":"",
    --    "summary":"Enroll in the Android Nanodegree to build the skills to work as an Android developer.",
    --    "url":"https://www.udacity.com/android",
    --    "group":"",
    --    "keywords": ["android, nanodegree"],
    --    "tags": ["courses"],
    --    "image":"images/cards/courses/android_nanodegree.png",
    --    "lang":"en",
    --    "type":"online course"
    --  },
    --  {
    --    "title":"Advanced Android App Development",
    --    "titleFriendly":"",
    --    "summary":"Productionize and publish your apps.",
    --    "url":"https://www.udacity.com/course/ud855",
    --    "group":"",
    --    "keywords": ["android, experts"],
    --    "tags": ["courses, expert"],
    --    "image":"images/cards/courses/advanced_android_course.jpg",
    --    "lang":"en",
    --    "type":"online course"
    --  },
    --  {
    --    "title":"Material Design for Android Developers",
    --    "titleFriendly":"",
    --    "summary":"Learn how to make your apps material.",
    --    "url":"https://www.udacity.com/course/ud862",
    --    "group":"",
    --    "keywords": ["android, design, pure, material"],
    --    "tags": ["courses, start, material"],
    --    "image":"images/cards/courses/android_design_course.jpg",
    --    "lang":"en",
    --    "type":"online course"
    --  },
    --  {
    --    "title":"Android for Beginners",
    --    "titleFriendly":"",
    --    "summary":"Make your first Android app, even if you don't write code.",
    --    "url":"https://www.udacity.com/course/ud837",
    --    "group":"",
    --    "keywords": ["android, sdk, firstapp"],
    --    "tags": ["courses, start"],
    --    "image":"images/cards/courses/beginning_android_course.jpg",
    --    "lang":"en",
    --    "type":"online course"
    --  },
    --  {
    --    "title":"Gradle for Android and Java",
    --    "titleFriendly":"",
    --    "summary":"Build better apps through automation",
    --    "url":"https://www.udacity.com/course/ud867",
    --    "group":"",
    --    "keywords": ["gradle","studio", "sdk"],
    --    "tags": ["courses, gradle, sdk"],
    --    "image":"images/cards/courses/gradle_course.jpg",
    --    "lang":"en",
    --    "type":"online course"
    --  },
    --  {
    --    "title":"Add Location and Context to your app",
    --    "titleFriendly":"",
    --    "summary":"Make Your Android App Location Aware.",
    --    "url":"https://www.udacity.com/course/ud876-1",
    --    "group":"",
    --    "keywords": ["google services, context, location"],
    --    "tags": ["courses, google, location, context"],
    --    "image":"images/cards/courses/android_location_course.png",
    --    "lang":"en",
    --    "type":"online course"
    --  },
    --  {
    --    "title":"Analytics and Tag Manager for Android",
    --    "titleFriendly":"",
    --    "summary":"Use Analytics and Tag Manager in Your Apps.",
    --    "url":"https://www.udacity.com/course/ud876-2",
    --    "group":"",
    --    "keywords": ["google services, analytics, tag manager"],
    --    "tags": ["courses, google, analytics"],
    --    "image":"images/cards/courses/android_analytics_course.png",
    --    "lang":"en",
    --    "type":"online course"
    --  },
    --  {
    --    "title":"AdMob for Android",
    --    "titleFriendly":"",
    --    "summary":"Monetize Your App by Displaying Ads.",
    --    "url":"https://www.udacity.com/course/ud876-3",
    --    "group":"",
    --    "keywords": ["monetize, google services, ads, admob"],
    --    "tags": ["courses, google, ads, admob"],
    --    "image":"images/cards/courses/admob_course.png",
    --    "lang":"en",
    --    "type":"online course"
    --  },
    --  {
    --    "title":"Add Maps to your Android app",
    --    "titleFriendly":"",
    --    "summary":"Use maps, cameras, markers and more in your app.",
    --    "url":"https://www.udacity.com/course/ud876-4",
    --    "group":"",
    --    "keywords": ["google, maps, marker, camera"],
    --    "tags": ["courses, google, maps"],
    --    "image":"images/cards/courses/android_maps_course.png",
    --    "lang":"en",
    --    "type":"online course"
    --  },
    --  {
    --    "title":"Add Sign-in to your Android app",
    --    "titleFriendly":"",
    --    "summary":"Build a Seamless Sign-In Experience.",
    --    "url":"https://www.udacity.com/course/ud876-5",
    --    "group":"",
    --    "keywords": ["google services, signin, authorization"],
    --    "tags": ["courses, google, auth"],
    --    "image":"images/cards/courses/android_identity_course.png",
    --    "lang":"en",
    --    "type":"online course"
    --  },
    --  {
    --    "title":"Android Wear Development",
    --    "titleFriendly":"",
    --    "summary":"Extend your Apps to Android Smartwatches.",
    --    "url":"https://www.udacity.com/course/ud875A",
    --    "group":"",
    --    "keywords": ["wear, wearables, smartwatch"],
    --    "tags": ["courses, wear, wearable"],
    --    "image":"images/cards/courses/android_wear_course.jpg",
    --    "lang":"en",
    --    "type":"online course"
    --  },
    --  {
    --    "title":"Android TV and Google Cast Development",
    --    "titleFriendly":"",
    --    "summary":"Extend your Apps to the Big Screen.",
    --    "url":"https://www.udacity.com/course/ud875B",
    --    "group":"",
    --    "keywords": ["cast, living room"],
    --    "tags": ["courses, cast, tv"],
    --    "image":"images/cards/courses/android_tv_cast_course.jpg",
    --    "lang":"en",
    --    "type":"online course"
    --  },
    --  {
    --    "title":"Android Auto Development",
    --    "titleFriendly":"",
    --    "summary":"Put your apps in the driver's seat.",
    --    "url":"https://www.udacity.com/course/ud875C",
    --    "group":"",
    --    "keywords": ["auto"],
    --    "tags": ["courses, auto"],
    --    "image":"images/cards/courses/android_auto_course.jpg",
    --    "lang":"en",
    --    "type":"online course"
    --  },
    --
    --
    -- // TODO remove this?
    --  {
    --    "title":"Android Wear Materials",
    --    "titleFriendly":"",
    --    "summary":"Drag and drop your way to beautifully designed Android Wear apps.",
    --    "url":"design/downloads/index.html#Wear",
    --    "group":"",
    --    "keywords": ["icons","stencils","color swatches"],
    --    "tags": ["icons","stencils","colorswatches"],
    --    "image":"images/cards/android-wear-materials_2x.jpg",
    --    "lang":"en",
    --    "type":"design"
    --  },
    --  {
    --    "title":"Watch Faces for Android Wear",
    --    "titleFriendly":"",
    --    "summary":"Watch faces let you customize the most prominent UI feature of Android wearables. The API is simple enough for rapid development and flexible enough to build something awesome.",
    --    "url":"https://www.youtube.com/watch?v=AK38PJZmIW8&list=PLWz5rJ2EKKc-kIrPiq098QH9dOle-fLef",
    --    "group":"",
    --    "keywords": ["wear", "wearable", "watch face"],
    --    "tags": [],
    --    "image":"https://i1.ytimg.com/vi/AK38PJZmIW8/maxresdefault.jpg",
    --    "lang":"en",
    --    "type":"video"
    --  },
    --  {
    --    "title":"Android Support Library",
    --    "titleFriendly":"",
    --    "summary":"These essential components help you build a great app that works on the huge variety of Android devices, faster.",
    --    "url":"https://www.youtube.com/watch?v=3PIc-DuEU2s&list=PLWz5rJ2EKKc9e0d55YHgJFHXNZbGHEXJX",
    --    "group":"",
    --    "keywords": ["support", "compatibility"],
    --    "tags": [],
    --    "image":"https://i1.ytimg.com/vi/3PIc-DuEU2s/maxresdefault.jpg",
    --    "lang":"en",
    --    "type":"Video"
    --  },
    --  {
    --    "title":"Consistent Design with the AppCompat Support Library",
    --    "titleFriendly":"",
    --    "summary":"Getting a great looking app doesn't have to be hard: AppCompat, part of the Android Support Library, gives you a consistent design baseline that works on all Android 2.1 or higher devices.",
    --    "url":"https://www.youtube.com/watch?v=5Be2mJzP-Uw&list=PLWz5rJ2EKKc9e0d55YHgJFHXNZbGHEXJX",
    --    "group":"",
    --    "keywords": ["support", "compatibility","design-code"],
    --    "tags": [],
    --    "image":"https://i1.ytimg.com/vi/5Be2mJzP-Uw/maxresdefault.jpg",
    --    "lang":"en",
    --    "type":"Video"
    --  },
    --  {
    --    "title":"Introducing Gradle",
    --    "titleFriendly":"",
    --    "summary":"Android Studio uses an entirely new and flexible Gradle-based build system. You will be able to create multiple build variants for a single project, manage library dependencies and always be sure that your application builds correctly across different environments.",
    --    "url":"https://www.youtube.com/watch?v=cD7NPxuuXYY&list=PLWz5rJ2EKKc8I9gHTMh5yKkwRRGE8BjbQ",
    --    "group":"",
    --    "keywords": ["tools", "studio","gradle"],
    --    "tags": [],
    --    "image":"https://i1.ytimg.com/vi/cD7NPxuuXYY/maxresdefault.jpg",
    --    "lang":"en",
    --    "type":"Video"
    --  },
    --  {
    --    "title":"Android Studio Layout Editor",
    --    "titleFriendly":"",
    --    "summary":"Android Studio includes a rich, visual layout editor that helps developers create better user interfaces. It eliminates the need to deploy the APK on a real device with each change, making iterations faster and helping eliminate common errors earlier in the development process.",
    --    "url":"https://www.youtube.com/watch?v=JLLnhwtDoHw&list=PLWz5rJ2EKKc8I9gHTMh5yKkwRRGE8BjbQ",
    --    "group":"",
    --    "keywords": ["tools", "studio","layout"],
    --    "tags": [],
    --    "image":"https://i1.ytimg.com/vi/JLLnhwtDoHw/maxresdefault.jpg",
    --    "lang":"en",
    --    "type":"Video"
    --  },
    --  {
    --    "title":"Debugging and testing in Android Studio",
    --    "titleFriendly":"",
    --    "summary":"Learn about new debugger features in Android Studio 1.2: value inlining, quick access to referring objects and a Java .class decompiler, just to name a few. See some new tools and views that let you monitor the CPU and memory performance of your app from within the IDE. ",
    --    "url":"https://www.youtube.com/watch?v=2I6fuD20qlY&list=PLWz5rJ2EKKc8I9gHTMh5yKkwRRGE8BjbQ",
    --    "group":"",
    --    "keywords": ["tools", "studio","debugging","profiling","performance"],
    --    "tags": [],
    --    "image":"https://i1.ytimg.com/vi/2I6fuD20qlY/maxresdefault.jpg",
    --    "lang":"en",
    --    "type":"Video"
    --  },
    --  {
    --    "title":"Scale with Google Cloud Platform",
    --    "titleFriendly":"",
    --    "summary":"Build, test, and deploy applications on Google's highly-scalable and reliable infrastructure for your web, mobile and backend solutions.",
    --    "url":"https://cloud.google.com/docs/",
    --    "group":"",
    --    "keywords": [],
    --    "tags": [],
    --    "image":"images/cards/cloud-platform_2x.png",
    --    "lang":"en",
    --    "type":"distribute"
    --  },
    --  {
    --    "title":"Opportunities & Programs",
    --    "titleFriendly":"",
    --    "summary":"Take advantage of the many ways you can distribute your app to consumers, students, and businesses through Google Play.",
    --    "url":"distribute/googleplay/index.html#opportunities",
    --    "group":"",
    --    "keywords": [],
    --    "tags": [],
    --    "image":"images/cards/program-edu_2x.jpg",
    --    "lang":"en",
    --    "type":"distribute"
    --  },
    --  {
    --    "title":"Join the Android for Work DevHub",
    --    "titleFriendly":"",
    --    "summary":"The Android for Work DevHub is a place to help developers keep up with Android in the workplace.",
    --    "url":"https://www.google.com/work/android/developers/applyDevHub/",
    --    "group":"",
    --    "keywords": ["work", "enterprise", "isv", "devhub"],
    --    "tags": [],
    --    "image":"images/work/cards/work-devhub_600px.png",
    --    "lang":"en",
    --    "type":"Community"
    --  },
    --  {
    --    "title":"Enterprise Mobility Managers",
    --    "titleFriendly":"",
    --    "summary":"Integrate Android for Work into your enterprise mobility management (EMM) solution.",
    --    "url":"https://developers.google.com/android/work/",
    --    "group":"",
    --    "keywords": ["work", "enterprise", "emm"],
    --    "tags": [],
    --    "image":"images/work/cards/work-cloud_600px.png",
    --    "lang":"en",
    --    "type":"guide"
    --  },
    --  {
    --    "title":"Learn More About Android for Work",
    --    "titleFriendly":"",
    --    "summary":"Android for Work makes your favorite phones and tablets the perfect business tools.",
    --    "url":"https://www.google.com/work/android/",
    --    "group":"",
    --    "keywords": ["work", "enterprise", "emm"],
    --    "tags": [],
    --    "image":"images/work/cards/work-profile_600px.png",
    --    "lang":"en",
    --    "type":"about"
    --  },
    --  {
    --    "title":"Build a Device Policy Controller",
    --    "titleFriendly":"",
    --    "summary":"Create and administer a managed profile on an employee's device.",
    --    "url":"https://developers.google.com/android/work/build-dpc",
    --    "group":"",
    --    "keywords": ["work", "enterprise", "emm"],
    --    "tags": [],
    --    "image":"images/work/cards/work-folder_600px.png",
    --    "lang":"en",
    --    "type":"guide"
    --  },
    --  {
    --    "title":"Android for Work for Developers",
    --    "titleFriendly":"",
    --    "summary":"Watch the videos in this playlist to understand more about Android for Work and get tips on developing enterprise apps.",
    --    "url":"https://www.youtube.com/watch?v=jQWB_-o1kz4&list=PLOU2XLYxmsIKAK2Bhv19H2THwF-22O5WX",
    --    "group":"",
    --    "keywords": ["work", "enterprise", "emm"],
    --    "tags": [],
    --    "image":"https://i1.ytimg.com/vi/jQWB_-o1kz4/maxresdefault.jpg",
    --    "lang":"en",
    --    "type":"youtube"
    --  },
    --  {
    --    "title":"App Configurations, Testing and Launchers",
    --    "titleFriendly":"",
    --    "summary":"With Android for Work you can make your apps remotely configurable. We also cover how to test your app in a managed environment.",
    --    "url":"https://www.youtube.com/watch?v=39NkpWkaH8M&index=2&list=PLOU2XLYxmsIKAK2Bhv19H2THwF-22O5WX",
    --    "group":"",
    --    "keywords": ["work", "enterprise", "emm"],
    --    "tags": [],
    --    "image":"https://i1.ytimg.com/vi/39NkpWkaH8M/maxresdefault.jpg",
    --    "lang":"en",
    --    "type":"youtube"
    --  },
    --  {
    --    "title":"Building an Enterprise Ready App",
    --    "titleFriendly":"",
    --    "summary":"A holistic view of Android for Work for developers.",
    --    "url":"https://www.youtube.com/watch?v=dH41OutAMNM&list=PLOU2XLYxmsIKAK2Bhv19H2THwF-22O5WX",
    --    "group":"",
    --    "keywords": ["work", "enterprise", "emm"],
    --    "tags": [],
    --    "image":"https://i1.ytimg.com/vi/dH41OutAMNM/maxresdefault.jpg",
    --    "lang":"en",
    --    "type":"youtube"
    --  },
    --  {
    --    "title":"Android for Work: Single Use Devices",
    --    "titleFriendly":"",
    --    "summary":"Single-purpose computers are everywhere, and Android can meet that need.",
    --    "url":"https://www.youtube.com/watch?v=j3QC6hcpy90",
    --    "group":"",
    --    "keywords": ["work", "enterprise", "emm"],
    --    "tags": [],
    --    "image":"https://i1.ytimg.com/vi/j3QC6hcpy90/maxresdefault.jpg",
    --    "lang":"en",
    --    "type":"youtube"
    --  },
    --  {
    --    "title":"Your Apps at Work",
    --    "titleFriendly":"",
    --    "summary":"In this Google I/O 2016 session we’ll give you details for making your app more attractive to businesses.",
    --    "url":"https://www.youtube.com/watch?v=Za0OQo8DRM4",
    --    "group":"",
    --    "keywords": ["work", "enterprise", "emm"],
    --    "tags": [],
    --    "image":"https://i1.ytimg.com/vi/Za0OQo8DRM4/maxresdefault.jpg",
    --    "lang":"en",
    --    "type":"youtube"
    --  },
    --  {
    --    "title":"Discover YouTube cards",
    --    "titleFriendly":"",
    --    "summary":"Find out more about YouTube cards, the options available, and how to use them to get the most from your YouTube content.",
    --    "url":"https://support.google.com/youtube/answer/6140493",
    --    "group":"",
    --    "keywords": ["youtube", "video", "users", "installs"],
    --    "tags": [],
    --    "image":"images/cards/card-youtube_2x.png",
    --    "lang":"en",
    --    "type":"distribute"
    --  },
    --    {
    --    "title":"What is YouTube account good standing?",
    --    "titleFriendly":"",
    --    "summary":"Learn what it means for an account to be in good standing from the YouTube Help Center.",
    --    "url":"https://support.google.com/youtube/answer/2797387",
    --    "group":"",
    --    "keywords": ["youtube", "video", "users", "installs"],
    --    "tags": [],
    --    "image":"images/cards/card-youtube_2x.png",
    --    "lang":"en",
    --    "type":"distribute"
    --  },
    --  {
    --    "title":"What’s New in Android N Developer Preview",
    --    "titleFriendly":"",
    --    "summary":"Learn all about the new features in the Android N Preview.",
    --    "url":"https://www.youtube.com/watch?v=CsulIu3UaUM",
    --    "group":"",
    --    "keywords": ["n preview"],
    --    "tags": [],
    --    "image":"https://i1.ytimg.com/vi/CsulIu3UaUM/maxresdefault.jpg",
    --    "lang":"en",
    --    "type":"Video"
    --  },
    --  {
    --    "title":"Developing for Android 6.0 (Marshmallow)",
    --    "titleFriendly":"",
    --    "summary":"This video covers how to get started with the preview, important APIs to test and how to provide feedback on the preview.",
    --    "url":"https://www.youtube.com/watch?v=yYU4DHLwoRk",
    --    "group":"",
    --    "keywords": ["Marshmallow"],
    --    "tags": [],
    --    "image":"https://i1.ytimg.com/vi/yYU4DHLwoRk/maxresdefault.jpg",
    --    "lang":"en",
    --    "type":"Video"
    --  },
    --  {
    --    "title":"Google I/O 2015 - What's new in Android",
    --    "titleFriendly":"",
    --    "summary":"This session will highlight the most exciting new developer features of the Android platform.",
    --    "url":"https://www.youtube.com/watch?v=ndBdf1_oOGA",
    --    "group":"",
    --    "keywords": ["Marshmallow"],
    --    "tags": [],
    --    "image":"https://i1.ytimg.com/vi/ndBdf1_oOGA/maxresdefault.jpg",
    --    "lang":"en",
    --    "type":"Video"
    --  },
    --  {
    --    "title":"Fingerprint and payments APIs",
    --    "titleFriendly":"",
    --    "summary":"New fingerprint and payments APIs are introduced in M, to enable enhanced UX and security for online purchasing, banking, and retail payments.",
    --    "url":"https://www.youtube.com/watch?v=VOn7VrTRlA4",
    --    "group":"",
    --    "keywords": ["Marshmallow"],
    --    "tags": [],
    --    "image":"https://i1.ytimg.com/vi/VOn7VrTRlA4/maxresdefault.jpg",
    --    "lang":"en",
    --    "type":"Video"
    --  },
    --  {
    --    "title":"Introduction to Voice Interaction API",
    --    "titleFriendly":"",
    --    "summary":"This video covers how to use the Voice Interaction API to support system or custom voice actions.",
    --    "url":"https://www.youtube.com/watch?v=OW1A4XFRuyc",
    --    "group":"",
    --    "keywords": ["Marshmallow"],
    --    "tags": [],
    --    "image":"https://i1.ytimg.com/vi/OW1A4XFRuyc/maxresdefault.jpg",
    --    "lang":"en",
    --    "type":"Video"
    --  },
    --  {
    --    "title":"Android Auto Backup for Apps",
    --    "titleFriendly":"",
    --    "summary":"Android Backup is the automatic, cloud-based backup and restore of users’ apps when they set up a new device.",
    --    "url":"https://www.youtube.com/watch?v=HXacyy0HSW0",
    --    "group":"",
    --    "keywords": ["Marshmallow"],
    --    "tags": [],
    --    "image":"https://i1.ytimg.com/vi/HXacyy0HSW0/maxresdefault.jpg",
    --    "lang":"en",
    --    "type":"Video"
    --  },
    --  {
    --    "title":"New APIs in M for Android for Work",
    --    "titleFriendly":"",
    --    "summary":"Android M extends Android for Work functionality with a new set of APIs for Enterprise Mobility Management providers to offer new features and policy controls to IT Departments.",
    --    "url":"https://www.youtube.com/watch?v=vcSj8ln-BlE",
    --    "group":"",
    --    "keywords": ["Marshmallow"],
    --    "tags": [],
    --    "image":"https://i1.ytimg.com/vi/vcSj8ln-BlE/maxresdefault.jpg",
    --    "lang":"en",
    --    "type":"Video"
    --  },
    --  {
    --    "title":"Runtime Permissions in Android 6.0 Marshmallow",
    --    "titleFriendly":"",
    --    "summary":"Learn how to integrate runtime permissions into your Android app.",
    --    "url":"https://www.youtube.com/watch?v=C8lUdPVSzDk",
    --    "group":"",
    --    "keywords": ["Marshmallow"],
    --    "tags": [],
    --    "image":"https://i1.ytimg.com/vi/C8lUdPVSzDk/maxresdefault.jpg",
    --    "lang":"en",
    --    "type":"Video"
    --  },
    --  {
    --    "title":"Introduction to Doze",
    --    "titleFriendly":"",
    --    "summary":"An overview of Doze and how to make sure that your app behaves as expected both in and out of Doze mode. ",
    --    "url":"https://youtu.be/N72ksDKrX6c",
    --    "group":"",
    --    "keywords": ["Marshmallow"],
    --    "tags": [],
    --    "image":"https://i1.ytimg.com/vi/N72ksDKrX6c/maxresdefault.jpg",
    --    "lang":"en",
    --    "type":"Video"
    --  },
    --  {
    --    "title":"The Nexus 5X, Nexus 6P and Android Marshmallow",
    --    "titleFriendly":"",
    --    "summary":"The new Nexus 5X and Nexus 6P along with some of the most significant developer features in the latest Android release,.",
    --    "url":"https://youtu.be/U9tw5ypqEN0",
    --    "group":"",
    --    "keywords": ["Marshmallow"],
    --    "tags": [],
    --    "image":"https://i1.ytimg.com/vi/U9tw5ypqEN0/maxresdefault.jpg",
    --    "lang":"en",
    --    "type":"Video"
    --  },
    --  {
    --    "title":"Asking For Permission Fine",
    --    "titleFriendly":"",
    --    "summary":"Picking the right way and time to ask for a permission is critical to it being granted. ",
    --    "url":"https://youtu.be/iZqDdvhTZj0",
    --    "group":"",
    --    "keywords": ["Marshmallow"],
    --    "tags": [],
    --    "image":"https://i1.ytimg.com/vi/iZqDdvhTZj0/maxresdefault.jpg",
    --    "lang":"en",
    --    "type":"Video"
    --  },
    --  {
    --    "title":"Data Binding Library",
    --    "titleFriendly":"",
    --    "summary":"Data Binding Library is a way to write declarative layouts and minimize the glue code necessary to bind your application logic and layouts. ",
    --    "url":"https://youtu.be/5sCQjeGoE7M",
    --    "group":"",
    --    "keywords": ["Marshmallow"],
    --    "tags": [],
    --    "image":"https://i1.ytimg.com/vi/5sCQjeGoE7M/maxresdefault.jpg",
    --    "lang":"en",
    --    "type":"Video"
    --  },
    --  {
    --    "title":"App Links",
    --    "titleFriendly":"",
    --    "summary":"App Links is a new feature of Android Marshmallow that brings a faster way of opening website links for domains that you own.",
    --    "url":"https://youtu.be/LQoohRwojmw",
    --    "group":"",
    --    "keywords": ["Marshmallow"],
    --    "tags": [],
    --    "image":"https://i1.ytimg.com/vi/LQoohRwojmw/maxresdefault.jpg",
    --    "lang":"en",
    --    "type":"Video"
    --  },
    --  {
    --    "title":"Android M Permissions",
    --    "titleFriendly":"",
    --    "summary":"An introduction to Android M runtime permissions in Android M from Google I/O 2015. ",
    --    "url":"https://www.youtube.com/watch?v=f17qe9vZ8RM",
    --    "group":"",
    --    "keywords": ["Marshmallow"],
    --    "tags": [],
    --    "image":"https://i1.ytimg.com/vi/f17qe9vZ8RM/maxresdefault.jpg",
    --    "lang":"en",
    --    "type":"Video"
    --  },
    --  {
    --    "lang": "ja",
    --    "title": "Gaming Everywhere",
    --    "titleFriendly": "",
    --    "summary": "東京ゲームショウ 2014 の基調講演より。",
    --    "url": "https://www.youtube.com/watch?v=xelYnWcYkuE",
    --    "group": "",
    --    "keywords": [],
    --    "tags": [],
    --    "image": "https://img.youtube.com/vi/xelYnWcYkuE/hqdefault.jpg",
    --    "type": "youtube"
    --  },
    --  {
    --    "lang": "ja",
    --    "title": "Playtime Tokyo",
    --    "titleFriendly": "",
    --    "summary": "アプリビジネスのノウハウを各担当者が講演しました。",
    --    "url": "https://www.youtube.com/playlist?list=PLCOC_kP3nqGIHEgwm9mybvA04Vn4Cg9nn",
    --    "group": "",
    --    "keywords": [],
    --    "tags": [],
    --    "image": "https://img.youtube.com/vi/lJdjY3z6-LY/hqdefault.jpg",
    --    "type": "youtube"
    --  },
    --  {
    --    "lang": "ja",
    --    "title": "Android Wear 関連の動画に日本語字幕が付きました",
    --    "titleFriendly": "",
    --    "summary": "",
    --    "url": "https://googledevjp.blogspot.jp/2014/12/android-wear.html",
    --    "group": "",
    --    "keywords": [],
    --    "tags": [],
    --    "image": "https://i1.ytimg.com/vi/4JcDYkgqksY/maxresdefault.jpg",
    --    "type": "blog"
    --  },
    --  {
    --    "lang": "ja",
    --    "title": "Android Studio 1.0 をリリースしました",
    --    "titleFriendly": "",
    --    "summary": "",
    --    "url": "https://googledevjp.blogspot.jp/2014/12/android-studio-10.html",
    --    "group": "",
    --    "keywords": [],
    --    "tags": [],
    --    "image": "https://3.bp.blogspot.com/-1hV3sD1At74/VIaQSWBasUI/AAAAAAAABAU/9vYLJMsmMuQ/s1600/studio-logo.png",
    --    "type": "blog"
    --  },
    --  {
    --    "lang": "ja",
    --    "title": "Google Play 開発者サービス 6.5 のご紹介",
    --    "titleFriendly": "",
    --    "summary": "",
    --    "url": "https://googledevjp.blogspot.jp/2014/12/google-play-65.html",
    --    "group": "",
    --    "keywords": [],
    --    "tags": [],
    --    "image": "https://1.bp.blogspot.com/-4BNREC0Jojo/VGo7ahW35wI/AAAAAAAABAc/9thZl94F6fY/s1600/GMS%2B-%2BRelease%2BBlog%2BNacho%2B-%2BMap%2BToolbar.png",
    --    "type": "blog"
    --  },
    --  {
    --    "lang": "ja",
    --    "title": "Alpha and Beta Testing",
    --    "titleFriendly": "",
    --    "summary": "アプリのローンチにまつわるリスクを最小限にするために必須のツールです。[英語コンテンツ]",
    --    "url": "intl/ja/distribute/googleplay/developer-console.html#alpha-beta",
    --    "group": "",
    --    "keywords": [],
    --    "tags": [],
    --    "image": "images/gp-dc-ab.png",
    --    "type": "distribute"
    --  },
    --  {
    --    "lang": "ja",
    --    "title": "Finding Success on Google Play",
    --    "titleFriendly": "",
    --    "summary": "Google Play での成功の秘訣がこの一冊に。[英語コンテンツ]",
    --    "url": "intl/ja/distribute/googleplay/guide.html",
    --    "group": "",
    --    "keywords": [],
    --    "tags": [],
    --    "image": "distribute/images/play_dev_guide_b.jpg",
    --    "type": "distribute"
    --  },
    --  {
    --    "lang": "ja",
    --    "title": "Core App Quality",
    --    "titleFriendly": "",
    --    "summary": "",
    --    "url": "intl/ja/distribute/essentials/quality/core.html",
    --    "group": "",
    --    "keywords": [],
    --    "tags": [],
    --    "image": "images/gp-core-quality.png",
    --    "type": "distribute"
    --  },
    --  {
    --    "lang": "ja",
    --    "title": "Google Play アプリ ポリシー センター",
    --    "titleFriendly": "",
    --    "summary": "",
    --    "url": "https://support.google.com/googleplay/android-developer/answer/4430948?hl=ja",
    --    "group": "",
    --    "keywords": [],
    --    "tags": [],
    --    "image": "https://storage.googleapis.com/support-kms-prod/SNP_712EA2784949DDF085C46E3BE7B1DC618A09_4389356_en_v0",
    --    "type": "distribute"
    --  },
    --  {
    --    "lang": "ja",
    --    "title": "Developer Support",
    --    "titleFriendly": "",
    --    "summary": "",
    --    "url": "intl/ja/support.html",
    --    "group": "",
    --    "keywords": [],
    --    "tags": [],
    --    "image": "",
    --    "type": "distribute"
    --  },
    --  {
    --    "lang": "ja",
    --    "title": "Wear App Quality",
    --    "titleFriendly": "",
    --    "summary": "いよいよウェアラブルの時代が到来。[英語コンテンツ]",
    --    "url": "intl/ja/distribute/essentials/quality/wear.html",
    --    "group": "",
    --    "keywords": [],
    --    "tags": [],
    --    "image": "distribute/images/gp-wear-quality.png",
    --    "type": "distribute"
    --  },
    --  {
    --    "lang": "ja",
    --    "title": "Google Cloud Platform が支える、新感覚リアルタイム RPG ユニゾンリーグ - 株式会社エイチームの GCP 導入事例",
    --    "titleFriendly": "",
    --    "summary": "スケーラブルなバックエンドを実現する Google Cloud Platform の最新導入事例。",
    --    "url": "https://googleforwork-japan.blogspot.jp/2014/12/gcp-google-cloud-platform-rpg-gcp.html",
    --    "group": "",
    --    "keywords": [],
    --    "tags": [],
    --    "image": "https://3.bp.blogspot.com/-xp7KoPkbne4/VI_PfoFil3I/AAAAAAAAA3U/-k1UZ0zjCBc/s1600/unison-league.jpeg",
    --    "type": "distribute"
    --  },
    --  {
    --    "lang": "ja",
    --    "title": "Monetize with Ads",
    --    "titleFriendly": "",
    --    "summary": "アプリ内広告成功のコツがここに。[英語コンテンツ]",
    --    "url": "intl/ja/distribute/monetize/ads.html",
    --    "group": "",
    --    "keywords": [],
    --    "tags": [],
    --    "image": "distribute/images/advertising.jpg",
    --    "type": "distribute"
    --  },
    --  {
    --    "lang": "ko",
    --    "title": "구글 플레이 2015년 비전",
    --    "titleFriendly": "",
    --    "summary": "G-Star 구글 컨퍼런스",
    --    "url": "https://www.youtube.com/watch?v=7X9Ue0Nfdh4&index=2&list=PL_WJkTbDHdBksDBRoqfeyLchEQqBAOlNl",
    --    "group": "",
    --    "keywords": [],
    --    "tags": [],
    --    "image": "https://img.youtube.com/vi/7X9Ue0Nfdh4/hqdefault.jpg",
    --    "type": "youtube"
    --  },
    --  {
    --    "lang": "ko",
    --    "title": "구글 플레이 게임",
    --    "titleFriendly": "",
    --    "summary": "게임 프로필, 퀘스트, 세이브드 게임 등의 신기능 소개",
    --    "url": "https://www.youtube.com/watch?v=83FpwuschCQ",
    --    "group": "",
    --    "keywords": [],
    --    "tags": [],
    --    "image": "https://img.youtube.com/vi/83FpwuschCQ/hqdefault.jpg",
    --    "type": "youtube"
    --  },
    --  {
    --    "lang": "ko",
    --    "title": "안드로이드 5.0 롤리팝을 맞이하는 개발자를 위한 안내서",
    --    "titleFriendly": "",
    --    "summary": "",
    --    "url": "https://googledevkr.blogspot.com/2014/11/android50guidefordevelopers.html",
    --    "group": "",
    --    "keywords": [],
    --    "tags": [],
    --    "image": "https://lh5.googleusercontent.com/0Gx4Ob_WvIgNOMv3hVMuUm4O7KuSWyxCEFIvy39_6fgXh2q2azqjZf3bpZoEk-LMW-K8GwYMfyYfMUAwp38hhPQ6WFNnddhN2E2_GF3-XBQI_qjhISviz10h_mGgDWsZKA",
    --    "type": "blog"
    --  },
    --  {
    --    "lang": "ko",
    --    "title": "안드로이드 앱을 위한 머티리얼 디자인 체크 리스트",
    --    "titleFriendly": "",
    --    "summary": "",
    --    "url": "https://googledevkr.blogspot.com/2014/10/material-design-on-android-checklist.html",
    --    "group": "",
    --    "keywords": [],
    --    "tags": [],
    --    "image": "https://lh4.googleusercontent.com/JKoxeDdmsj6gYHV8rmp96U1jHj7FKeMzGBaaFu35kXp5EpJR9Ei9MQFAYghjwJoycdgydw-FZTuFNY8pDx63MWhy37rKC96ajoDXEMzvo9W0sj5yC2-uSYJdhpazVOP2cA",
    --    "type": "blog"
    --  },
    --  {
    --    "lang": "ko",
    --    "title": "App Compat 라이브러리",
    --    "titleFriendly": "",
    --    "summary": "",
    --    "url": "https://googledevkr.blogspot.com/2014/10/appcompat-v21-material-design-for-pre.html",
    --    "group": "",
    --    "keywords": [],
    --    "tags": [],
    --    "image": "https://2.bp.blogspot.com/-7fF9ayZ6PgI/U9iFpk5FNEI/AAAAAAAAAs0/4P4SCvdB_4M/s640/image00.png",
    --    "type": "blog"
    --  },
    --  {
    --    "lang": "ko",
    --    "title": "Alpha and Beta Testing",
    --    "titleFriendly": "",
    --    "summary": "출시 전에 완벽한 사전 테스트 [영문]",
    --    "url": "intl/ko/distribute/googleplay/developer-console.html#alpha-beta",
    --    "group": "",
    --    "keywords": [],
    --    "tags": [],
    --    "image": "images/gp-dc-ab.png",
    --    "type": "distribute"
    --  },
    --  {
    --    "lang": "ko",
    --    "title": "Finding Success on Google Play",
    --    "titleFriendly": "",
    --    "summary": "구글 플레이에서 성공하는 비결 [영문]",
    --    "url": "intl/ko/distribute/googleplay/guide.html",
    --    "group": "",
    --    "keywords": [],
    --    "tags": [],
    --    "image": "distribute/images/play_dev_guide_b.jpg",
    --    "type": "distribute"
    --  },
    --  {
    --    "lang": "ko",
    --    "title": "Core App Quality",
    --    "titleFriendly": "",
    --    "summary": "고품질 안드로이드 앱 개발 가이드 [영문]",
    --    "url": "intl/ko/distribute/essentials/quality/core.html",
    --    "group": "",
    --    "keywords": [],
    --    "tags": [],
    --    "image": "images/gp-core-quality.png",
    --    "type": "distribute"
    --  },
    --  {
    --    "lang": "ko",
    --    "title": "Policy Guidelines and Practices",
    --    "titleFriendly": "",
    --    "summary": "숙지해야할 중요한 정책 [영문]",
    --    "url": "https://support.google.com/googleplay/android-developer/answer/4430948?hl=ko",
    --    "group": "",
    --    "keywords": [],
    --    "tags": [],
    --    "image": "https://storage.googleapis.com/support-kms-prod/SNP_712EA2784949DDF085C46E3BE7B1DC618A09_4389356_en_v0",
    --    "type": "distribute"
    --  },
    --  {
    --    "lang": "ko",
    --    "title": "Developer Support",
    --    "titleFriendly": "",
    --    "summary": "개발자 지원 센터 활용 [영문]",
    --    "url": "intl/ko/support.html",
    --    "group": "",
    --    "keywords": [],
    --    "tags": [],
    --    "image": "https://lh3.googleusercontent.com/-mGTYed3Uh-E/AAAAAAAAAAI/AAAAAAAAF58/qNYbk4mMhI0/s120-c/photo.jpg",
    --    "type": "distribute"
    --  },
    --  {
    --    "lang": "ko",
    --    "title": "Wear App Quality",
    --    "titleFriendly": "",
    --    "summary": "웨어러블 앱 개발 가이드 [영문]",
    --    "url": "intl/ko/distribute/essentials/quality/wear.html",
    --    "group": "",
    --    "keywords": [],
    --    "tags": [],
    --    "image": "distribute/images/gp-wear-quality.png",
    --    "type": "distribute"
    --  },
    --  {
    --    "lang": "ko",
    --    "title": "Android TV 어플리케이션 개발",
    --    "titleFriendly": "",
    --    "summary": "앱과 게임을 거실에서 가족과 함께 [영문]",
    --    "url": "intl/ko/tv/index.html",
    --    "group": "",
    --    "keywords": [],
    --    "tags": [],
    --    "image": "design/tv/images/atv-home.jpg",
    --    "type": "distribute"
    --  },
    --  {
    --    "lang": "ko",
    --    "title": "구글 플레이 게임 서비스",
    --    "titleFriendly": "",
    --    "summary": "다양한 구글 플레이 게임 서비스 기능 알아보기 [영문]",
    --    "url": "intl/ko/google/play-services/games.html",
    --    "group": "",
    --    "keywords": [],
    --    "tags": [],
    --    "image": "https://developers.google.com/games/services/images/gamescreen3.jpg",
    --    "type": "distribute"
    --  },
    --  {
    --    "lang": "ko",
    --    "title": "Monetize with Ads",
    --    "titleFriendly": "",
    --    "summary": "광고로 수익 창출하기 [영문]",
    --    "url": "intl/ko/distribute/monetize/ads.html",
    --    "group": "",
    --    "keywords": [],
    --    "tags": [],
    --    "image": "distribute/images/advertising.jpg",
    --    "type": "distribute"
    --  },
    --  {
    --    "url":"https://www.youtube.com/watch?v=QDM52bblwlg",
    --    "image": "images/distribute/hero-family-discovery.jpg",
    --    "title": "Introducing the new family discovery experience on Google Play",
    --    "summary": "Help families create little moments on Google Play. Opt-in your apps now.",
    --    "tags":["families","googleplay"],
    --    "type":"youtube"
    --  },
    --  {
    --    "url":"https://www.youtube.com/watch?v=wcjqBSei3a0&list=PLOU2XLYxmsIKLNUPiFCWVtcO7mZRZ9MmS",
    --    "image": "https://i1.ytimg.com/vi/wcjqBSei3a0/maxresdefault.jpg",
    --    "title": "Developers connecting the world through Google Play",
    --    "summary": "The mobile ecosystem is empowering developers to make good on the dream of connecting the world through technology to improve people's lives.",
    --    "tags":["io15","googleplay"],
    --    "keywords":["Google I/O 2015","io"],
    --    "type":"youtube"
    --  },
    --  {
    --    "url":"https://www.youtube.com/watch?v=B6ydLpkhq04&list=PLOU2XLYxmsIKLNUPiFCWVtcO7mZRZ9MmS",
    --    "image": "https://i1.ytimg.com/vi/B6ydLpkhq04/maxresdefault.jpg",
    --    "title": "Store Listing Experiments for Google Play",
    --    "summary": "Learn how to use Google Play’s new store listing optimization feature to get more installs of your app, and how to test different graphics and text to find out which options perform the best. ",
    --    "tags":["io15","googleplay","store listing"],
    --    "tags":["google i/o","google play","store listing"],
    --    "type":"youtube"
    --  },
    --  {
    --    "url":"https://www.youtube.com/watch?v=jyO3-rF4Mu0&list=PLOU2XLYxmsIKLNUPiFCWVtcO7mZRZ9MmS",
    --    "image": "https://i1.ytimg.com/vi/jyO3-rF4Mu0/maxresdefault.jpg",
    --    "title": "Growing games with Google",
    --    "summary": "The games industry has never been more promising and full of opportunities. This talk covers how Google is helping developers across a broad range of existing and emerging platforms.",
    --    "tags":["io15","android", "googleplay","games"],
    --    "keywords":["Google I/O","google play","games"],
    --    "type":"youtube"
    --  },
    --  {
    --    "url":"https://www.youtube.com/watch?v=yJisuP94lHU",
    --    "image": "images/distribute/hero-playtime-opener.jpg",
    --    "title": "Playtime 2015: Innovation happens everywhere",
    --    "type":"Video",
    --    "tags":["googleplay"],
    --    "summary": "Watch the opening video from Google Play's annual event series, Playtime, which celebrates inspirational developers who are changing the world around them.",
    --  },
    --{
    --    "url":"https://www.youtube.com/watch?v=JrR6o5tYMWQ",
    --    "image": "images/distribute/hero-acquisition-devbyte.jpg",
    --    "title": "User acquisition and tracking on Google Play",
    --    "type" : "Video",
    --    "tags" : "users,googleplay,googleio",
    --    "summary": "Learn how to get new users, using Universal app campaigns directly within the Google Play Developer Console to increase your installs from ads, and find out how your acquisition channels perform.",
    --  },
    --]);
    --
    --var CAROUSEL_OVERRIDE = {
    --  "distribute/googleplay/guide.html": {
    --    "image": "images/distribute/hero-secrets-to-app-success.jpg",
    --    "title": "The Secrets to App Success on Google Play",
    --    "summary": "Get the updated guide full of useful features, tips, and best practices that will help you grow a successful app or game business on Google Play.",
    --  },
    --  "about/versions/lollipop.html": {
    --    "image": "images/home/hero-lollipop_2x.png",
    --    "heroColor": "#263238",
    --    "heroInvert": true,
    --    "title": "Android 5.0 Lollipop",
    --    "summary": "The Android 5.0 update adds a variety of new features for your apps, such as notifications on the lock screen, an all-new camera API, OpenGL ES 3.1, the new naterial design interface, and much more.",
    --  },
    --  "http://www.youtube.com/watch?v=Pms0pcyPbAM": {
    --    "url":"https://www.youtube.com/watch?v=Pms0pcyPbAM&list=PLWz5rJ2EKKc9ofd2f-_-xmUi07wIGZa1c]",
    --    "image": "images/distribute/hero-carousel-giftedmom.jpg",
    --    "title": "Gifted Mom reaches more mothers across Africa with Android",
    --    "type":"youtube",
    --    "summary": "Gifted Mom is an app developed in Cameroon which provides users with critical information about pregnancy, breastfeeding and child vaccinations. Hear the creators explain how they built their business on Google Play.",
    --  },
    --  "http://www.youtube.com/watch?v=9m6MoBM-sFI": {
    --    "url":"https://www.youtube.com/watch?v=9m6MoBM-sFI&list=PLWz5rJ2EKKc9ofd2f-_-xmUi07wIGZa1c&index=3",
    --    "image": "images/distribute/hero-carousel-sgn.jpg",
    --    "title": "SGN increases installs with Store Listing Experiments",
    --    "type" : "youtube",
    --    "summary": "Watch mobile game developer SGN talk about how using Store Listing Experiments to test multiple variants across their portfolio of games helped improve their ROI, conversion rates and gamer retention.",
    --  },
    --  "http://www.youtube.com/watch?v=e7t3svG9PTk": {
    --    "url":"https://www.youtube.com/watch?v=e7t3svG9PTk&index=2&list=PLWz5rJ2EKKc9ofd2f-_-xmUi07wIGZa1c",
    --    "image": "images/distribute/hero-carousel-djit.jpg",
    --    "title": "DJiT builds higher quality experiences on Android",
    --    "type" : "youtube",
    --    "summary": "Learn how Music app developer DJiT create higher quality apps with improved latency on Android Marshmallow, as well as other Android and Google Play features.",
    --  },
    --  "http://www.youtube.com/watch?v=J3IvOfvH1ys": {
    --    "url":"https://www.youtube.com/watch?v=J3IvOfvH1ys&list=PLWz5rJ2EKKc9ofd2f-_-xmUi07wIGZa1c&index=1",
    --    "image": "images/distribute/hero-carousel-wego.jpg",
    --    "title": "Wego increases user retention with material design",
    --    "type" : "youtube",
    --    "summary": "Hear how online travel marketplace Wego, increased monthly user retention by 300% and reduced uninstall rates by up to 25% with material design.",
    --  },
    --  "https://www.youtube.com/watch?v=QDM52bblwlg": {
    --    "url":"distribute/googleplay/families/about.html",
    --    "image": "images/distribute/hero-family-discovery.jpg",
    --    "title": "Designed for families",
    --    "summary": "Introducing the new family discovery experience in Google Play. Your apps can benefit from enhanced discoverability and maintain their existing categories, rankings, and reviews elsewhere in the store. Opt-in your apps today.",
    --    "type":"distribute",
    --  },
    --  "https://www.youtube.com/watch?v=wcjqBSei3a0&list=PLOU2XLYxmsIKLNUPiFCWVtcO7mZRZ9MmS": {
    --    "url":"https://www.youtube.com/watch?v=wcjqBSei3a0&list=PLOU2XLYxmsIKLNUPiFCWVtcO7mZRZ9MmS",
    --    "image": "images/distribute/hero-IO15-google-play.jpg",
    --    "title": "Connecting the world through Google Play",
    --    "tags":["io15"],
    --    "summary": "In this this Google I/O talk, hear how the mobile ecosystem is empowering developers to connect the world through technology and improve people's lives.",
    --  },
    --  "https://www.youtube.com/watch?v=B6ydLpkhq04&list=PLOU2XLYxmsIKLNUPiFCWVtcO7mZRZ9MmS": {
    --    "image": "images/distribute/hero-store-listing-experience.jpg",
    --    "title": "Using Google Play store listing experiments",
    --    "tags":["io15"],
    --    "summary": "Learn how to use Google Play store listing experiments to get more installs in this Google I/O talk. Test different graphics and text to find out which options perform the best. ",
    --  },
    --  "https://www.youtube.com/watch?v=jyO3-rF4Mu0&list=PLOU2XLYxmsIKLNUPiFCWVtcO7mZRZ9MmS": {
    --    "image": "images/distribute/hero-IO15-growing-games.jpg",
    --    "title": "Growing games with Google",
    --    "tags":["io15"],
    --    "summary": "The games industry has never been more promising and full of opportunities. This talk from Google I/O 2015 covers how Google is helping developers across a broad range of existing and emerging platforms.",
    --  }
    --};
    -diff --git a/docs/html/jd_extras_en.js b/docs/html/jd_extras_en.js
    -index dfc30c3..1a97db4 100644
    ---- a/docs/html/jd_extras_en.js
    -+++ b/docs/html/jd_extras_en.js
    -@@ -156,6 +156,16 @@ METADATA['en'].extras = METADATA['en'].extras.concat([
    -     "lang":"en"
    -   },
    -   {
    -+    "title":"GPU Debugger",
    -+    "summary":"Use the GPU Debugger to analyze and debug your OpenGL ES apps. Inspect the GPU state and understand what caused a specific rendering outcome.",
    -+    "url":"studio/debug/am-gpu-debugger.html",
    -+    "image":"images/tools/thumbnails/am-gpu-debugger_2-2_2x.png",
    -+    "type":"tools",
    -+    "keywords": ["android","performance","profiling","tools","monitor","debug"],
    -+    "tags": ["android","performance","profiling","tools","monitor","debug"],
    -+    "lang":"en"
    -+  },
    -+  {
    -     "title":"HPROF Viewer and Analyzer",
    -     "summary":"Use the Memory Monitor to dump the Java heap to an HPROF file. The HPROF Viewer displays classes, instances of each class, and a reference tree to help you track memory usage and find memory leaks.",
    -     "url":"studio/profile/am-hprof.html",
    -@@ -1022,6 +1032,17 @@ METADATA['en'].extras = METADATA['en'].extras.concat([
    -     "type":"distribute"
    -   },
    -   {
    -+    "title": "Play Games Quality",
    -+    "category": "google",
    -+    "summary": "Meet the basic expectations of game players through compelling features and an intuitive, well-designed UI.",
    -+    "url": "https://developers.google.com/games/services/checklist",
    -+    "group": "",
    -+    "keywords": ["games", "play games", "quality"],
    -+    "tags": [],
    -+    "image": "images/cards/distribute/engage/card-game-services.png",
    -+    "type": "distribute"
    -+  },
    -+  {
    -     "title":"Get Started with Analytics",
    -     "category":"google",
    -     "summary":"Get advanced insight into how players discover and play your games.",
    -@@ -2960,7 +2981,6 @@ METADATA['en'].extras = METADATA['en'].extras.concat([
    -     "type": "distribute",
    -     "category": "google"
    -   },
    --
    -   {
    -     "lang": "en",
    -     "group": "",
    -@@ -2969,7 +2989,7 @@ METADATA['en'].extras = METADATA['en'].extras.concat([
    -     "timestamp": 1383243492000,
    -     "image": "images/cards/google-search_2x.png",
    -     "title": "Set Up App Indexing",
    --    "summary": "Surface your app content in Google seaerch. Deep link direct to your apps.",
    -+    "summary": "Surface your app content in Google search. Deep link direct to your apps.",
    -     "keywords": ["search", "appindexing", "engagement", "getusers"],
    -     "type": "distribute",
    -     "category": "google"
    -@@ -4117,8 +4137,8 @@ METADATA['en'].collections = {
    -   "develop/landing/tools": {
    -     "title": "",
    -     "resources": [
    --      "https://www.youtube.com/watch?v=ZOz_yr8Yxq8&list=PLWz5rJ2EKKc_w6fodMGrA1_tsI3pqPbqa",
    --      "https://www.youtube.com/watch?v=eOV2owswDkE&list=PLWz5rJ2EKKc_w6fodMGrA1_tsI3pqPbqa",
    -+      "https://www.youtube.com/watch?v=NbHsi3-uR8E&list=PLWz5rJ2EKKc_w6fodMGrA1_tsI3pqPbqa",
    -+      "https://www.youtube.com/watch?v=-SY5nkNVUn0&list=PLWz5rJ2EKKc_w6fodMGrA1_tsI3pqPbqa",
    -       "https://www.youtube.com/watch?v=StqAZ1OQbqA&list=PLWz5rJ2EKKc_w6fodMGrA1_tsI3pqPbqa",
    -       "https://www.youtube.com/watch?v=-SY5nkNVUn0&list=PLWz5rJ2EKKc_w6fodMGrA1_tsI3pqPbqa",
    -       "https://www.youtube.com/watch?v=4rI4tTd7-J8&list=PLWz5rJ2EKKc_w6fodMGrA1_tsI3pqPbqa",
    -@@ -4366,6 +4386,7 @@ METADATA['en'].collections = {
    -       "distribute/essentials/quality/wear.html",
    -       "distribute/essentials/quality/tv.html",
    -       "distribute/essentials/quality/auto.html",
    -+      "https://developers.google.com/games/services/checklist",
    -       "distribute/essentials/quality/billions.html",
    -       "https://developers.google.com/edu/guidelines"
    -     ]
    -@@ -5354,6 +5375,47 @@ METADATA['en'].collections = {
    -       "https://storage.googleapis.com/androiddevelopers/shareables/stories/Senri_LeosFortune_gpgs.pdf"
    -     ]
    -   },
    -+  "distribute/stories/games/docs": {
    -+    "title": "",
    -+    "resources": [
    -+      "distribute/stories/games/animoca-star-girl.html",
    -+      "distribute/stories/games/happy-labs-experiment.html",
    -+      "distribute/stories/games/playlab-puzzles.html",
    -+      "distribute/stories/games/upbeat-games.html",
    -+      "distribute/stories/games/tapps.html",
    -+      "distribute/stories/games/noodlecake-super-stickman.html",
    -+      "distribute/stories/games/glu-tap-baseball.html",
    -+      "distribute/stories/games/doctor-who-legacy.html",
    -+      "distribute/stories/games/glu-dh.html",
    -+      "distribute/stories/games/dots.html",
    -+      "distribute/stories/games/kongregate-adv-cap.html",
    -+      "distribute/stories/games/kongregate-global-assault.html",
    -+      "distribute/stories/games/leos-fortune.html",
    -+      "distribute/stories/games/tiny-co.html",
    -+      "distribute/stories/games/g4a-indian-rummy.html",
    -+      "distribute/stories/games/rvappstudios-zombie.html",
    -+      "distribute/stories/games/glu-eternity-warriors.html",
    -+      "distribute/stories/games/hotheadgames-firefight.html",
    -+      "distribute/stories/games/concrete-bowling.html",
    -+      "distribute/stories/games/gameloft-asphalt8.html"
    -+    ]
    -+  },
    -+  "distribute/stories/apps/docs": {
    -+    "title": "",
    -+    "resources": [
    -+      "distribute/stories/apps/condenast-shopping.html",
    -+      "distribute/stories/apps/economist-espresso.html",
    -+      "distribute/stories/apps/expressen-sports.html",
    -+      "distribute/stories/apps/drupe-communications.html",
    -+      "distribute/stories/apps/noom-health.html",
    -+      "distribute/stories/apps/aftenposten.html",
    -+      "distribute/stories/apps/el-mundo.html",
    -+      "distribute/stories/apps/segundamano.html",
    -+      "distribute/stories/apps/remember-the-milk.html",
    -+      "distribute/stories/apps/intuit-mint.html",
    -+      "distribute/stories/apps/sayhi.html",
    -+    ]
    -+  },
    -   "training/testing/overview": {
    -     "title": "",
    -     "resources": [
    -@@ -5453,6 +5515,12 @@ METADATA['en'].collections = {
    -        "studio/profile/am-sysinfo.html"
    -     ]
    -   },
    -+"tools/help/gpu": {
    -+    "title": "",
    -+    "resources": [
    -+       "studio/debug/am-gpu-debugger.html"
    -+    ]
    -+  },
    -   "tools/help/shot": {
    -     "title": "",
    -     "resources": [
    -@@ -5552,7 +5620,7 @@ METADATA['en'].collections = {
    -     "title": "",
    -     "resources": [
    -     "https://medium.com/google-developers/how-often-should-you-update-android-studio-db25785c488e#.8blbql35x",
    --    "http://android-developers.blogspot.com/2016/04/android-studio-2-0.html",
    -+    "https://android-developers.blogspot.com/2016/09/android-studio-2-2.html",
    -     "https://medium.com/google-developers/writing-more-code-by-writing-less-code-with-android-studio-live-templates-244f648d17c7#.hczcm02du",
    -     ]
    -   },
    -diff --git a/docs/html/jd_extras_zh-cn.js b/docs/html/jd_extras_zh-cn.js
    -index cb1ccb7..866a87e 100644
    ---- a/docs/html/jd_extras_zh-cn.js
    -+++ b/docs/html/jd_extras_zh-cn.js
    -@@ -244,40 +244,40 @@ METADATA['zh-cn'].collections = {
    -   "overview/zhcn/1": {
    -     "title": "",
    -     "resources": [
    --      "intl/zh-cn/distribute/essentials/quality/core.html",
    --      "intl/zh-cn/distribute/essentials/quality/tablets.html",
    --      "intl/zh-cn/distribute/tools/launch-checklist.html",
    --      "intl/zh-cn/tools/publishing/publishing_overview.html",
    --      "intl/zh-cn/distribute/tools/localization-checklist.html"
    -+      "distribute/essentials/quality/core.html",
    -+      "distribute/essentials/quality/tablets.html",
    -+      "distribute/tools/launch-checklist.html",
    -+      "tools/publishing/publishing_overview.html",
    -+      "distribute/tools/localization-checklist.html"
    -     ]
    -   },
    -   "overview/zhcn/2": {
    -     "title": "",
    -     "resources": [
    --      "intl/zh-cn/google/play/billing/index.html",
    --      "intl/zh-cn/google/play/billing/api.html",
    --      "intl/zh-cn/google/play/billing/billing_admin.html",
    --      "intl/zh-cn/google/play/billing/billing_testing.html",
    --      "intl/zh-cn/google/play/billing/billing_best_practices.html"
    -+      "google/play/billing/index.html",
    -+      "google/play/billing/api.html",
    -+      "google/play/billing/billing_admin.html",
    -+      "google/play/billing/billing_testing.html",
    -+      "google/play/billing/billing_best_practices.html"
    -     ]
    -   },
    -   "overview/zhcn/3": {
    -     "title": "",
    -     "resources": [
    -       "https://play.google.com/intl/en_us/badges/",
    --      "intl/zh-cn/distribute/tools/promote/device-art.html",
    --      "intl/zh-cn/distribute/tools/promote/linking.html",
    --      "intl/zh-cn/distribute/tools/promote/brand.html",
    --      "intl/zh-cn/tools/help/proguard.html"
    -+      "distribute/tools/promote/device-art.html",
    -+      "distribute/tools/promote/linking.html",
    -+      "distribute/tools/promote/brand.html",
    -+      "tools/help/proguard.html"
    -     ]
    -   },
    -   "overview/zhcn/4": {
    -     "title": "",
    -     "resources": [
    --      "intl/zh-cn/design/style/writing.html",
    --      "intl/zh-cn/training/basics/fragments/fragment-ui.html",
    --      "intl/zh-cn/training/multiscreen/index.html",
    --      "intl/zh-cn/training/monitoring-device-state/index.html"
    -+      "design/style/writing.html",
    -+      "training/basics/fragments/fragment-ui.html",
    -+      "training/multiscreen/index.html",
    -+      "training/monitoring-device-state/index.html"
    -     ]
    -   },
    -   "overview/carousel/zhcn": {
    -diff --git a/docs/html/samples/new/index.jd b/docs/html/samples/new/index.jd
    -index a7ffa8c..4d6262e 100644
    ---- a/docs/html/samples/new/index.jd
    -+++ b/docs/html/samples/new/index.jd
    -@@ -5,7 +5,7 @@ page.image=images/cards/samples-new_2x.png
    - 
    - <p>The following code samples were recently published. You can
    - download them in the Android SDK Manager under the <b>Samples for SDK</b>
    --component for Android 6.0 (API 23).</p>
    -+component for Android 7.1 (API 25).</p>
    - 
    - <p class="note">
    -   <strong>Note:</strong> The downloadable projects are designed
    -@@ -14,115 +14,67 @@ component for Android 6.0 (API 23).</p>
    - 
    - <!-- NOTE TO EDITORS: add most recent samples first -->
    - 
    --<h3 id="ActiveNotification">
    --  <a href="{@docRoot}samples/ActiveNotifications/index.html">Active
    --  Notification</a>
    --</h3>
    - 
    --<p>
    --  This sample demonstrates how to use the {@link
    --  android.app.NotificationManager} to tell you how many notifications your app
    --  is currently showing.
    --</p>
    --
    --<h3 id="AutomaticBackup">
    --  <a href="{@docRoot}samples/AutoBackupForApps/index.html">Auto Backup for
    --  Apps</a>
    --</h3>
    --
    --<p>
    --  Android 6.0 (API level 23) introduces automatic backup for app settings. This
    --  sample demonstrates how to add filtering rules to an app to manage settings
    --  backup.
    --</p>
    -+<h3 id="app-shortcuts">App shortcuts sample</h3>
    - 
    --<h3 id="Camera2Raw">
    --  <a href="{@docRoot}samples/Camera2Raw/index.html">Camera 2 Raw</a>
    --</h3>
    -+<!-- TBA
    -+<img src="sample-img.png" style="float: left; padding-right: 0.5em"
    -+ width="xxx"/>
    -+-->
    - 
    - <p>
    --  This sample demonstrates how to use the
    --  <a href="{@docRoot}reference/android/hardware/camera2/package-summary.html">
    --  <code>Camera2</code></a> API to capture RAW camera buffers and save them as
    --  DNG files.
    --</p>
    --
    --<h3 id="ConfirmCredential">
    --  <a href="{@docRoot}samples/ConfirmCredential/index.html">Confirm
    --  Credential</a>
    --</h3>
    --
    --<p>
    -- This sample demonstrates how to use device credentials as an authentication method in your app.
    -+  This sample demonstrates how to use the <a href=
    -+  "/preview/app-shortcuts.html">app shortcuts API</a> introduced in Android 7.1
    -+  (API level 25). This API allows an application to define a set of intents
    -+  which are displayed when a user long-presses on the app's launcher icon.
    -+  Examples are given for registering links both statically in XML, as well as
    -+  dynamically at runtime.
    - </p>
    - 
    --<h3 id="DeviceOwner">
    --  <a href="{@docRoot}samples/DeviceOwner/index.html">Device Owner</a>
    --</h3>
    --
    - <p>
    --  This sample demonstrates how to use the device owner features to manage and
    --  configure a device.
    -+  <a href="/samples/AppShortcuts/index.html">App shortcuts sample</a>
    - </p>
    - 
    --<h3 id="DirectShare">
    --  <a href="{@docRoot}samples/DirectShare/index.html">Direct Share</a>
    --</h3>
    --
    --<p>
    --  This sample demonstrates how to provide the
    --  <a href="{@docRoot}about/versions/marshmallow/android-6.0.html#direct-share">Direct
    --  Share</a> feature. The app shows some options directly in the list of share
    --  intent candidates.
    --</p>
    -+<h3 id="img-kbd-app">Image keyboard app sample</h3>
    - 
    --<h3 id="FingerprintDialog">
    --  <a href="{@docRoot}samples/FingerprintDialog/index.html">Fingerprint
    --  Dialog</a>
    --</h3>
    -+<!-- TBA
    -+<img src="sample-img.png" style="float: left; padding-right: 0.5em"
    -+ width="xxx"/>
    -+-->
    - 
    - <p>
    --  This sample demonstrates how to recognize registered fingerprints to
    --  authenticate your app's user.
    -+  This sample demonstrates how to implement the <a href=
    -+  "/reference/android/view/inputmethod/InputConnection.html#commitContent(android.view.inputmethod.InputContentInfo,%20int,%20android.os.Bundle)">
    -+  Commit Content API</a>, using the <a href=
    -+  "/topic/libraries/support-library/index.html">Android Support Library</a>.
    -+  This API provides a universal way for IMEs to send images and other rich
    -+  content directly to a text editor in an app, allowing users to compose
    -+  content using custom emojis, stickers, or other rich content provided by
    -+  other applications.
    - </p>
    - 
    --<h3 id="MidiScope">
    --  <a href="{@docRoot}samples/MidiScope/index.html">MidiScope</a>
    --</h3>
    --
    - <p>
    --  This sample demonstrates how to use the <a href=
    --  "{@docRoot}reference/android/media/midi/package-summary.html">MIDI API</a> to
    --  receive and process MIDI signals coming from an attached input device.
    -+  <a href="/samples/CommitContentSampleApp/index.html">Image keyboard app sample</a>
    - </p>
    - 
    --<h3 id="MidiSynth">
    --  <a href="{@docRoot}samples/MidiSynth/index.html">MidiSynth</a>
    --</h3>
    -+<h3 id="img-kbd-ime">Image keyboard IME sample</h3>
    - 
    --<p>
    --  This sample demonstrates how to use the <a href=
    --  "{@docRoot}reference/android/media/midi/package-summary.html">MIDI API</a> to
    --  receive and play MIDI messages coming from an attached input device.
    --</p>
    --
    --<h3 id="NfcProvisioning">
    --  <a href="{@docRoot}samples/NfcProvisioning/index.html">NFC Provisioning</a>
    --</h3>
    -+<!-- TBA
    -+<img src="sample-img.png" style="float: left; padding-right: 0.5em"
    -+ width="xxx"/>
    -+-->
    - 
    - <p>
    --  This sample demonstrates how to use NFC to provision other devices with a
    --  specific device owner.
    -+  This sample demonstrates how to write a <a href=
    -+  "/preview/image-keyboard.html">custom image keyboard</a> using the <a href=
    -+  "/reference/android/view/inputmethod/InputConnection.html#commitContent(android.view.inputmethod.InputContentInfo,%20int,%20android.os.Bundle)">
    -+  Commit Content API</a> and the <a href=
    -+  "/topic/libraries/support-library/index.html">Android Support Library</a>.
    -+  This keyboard will be displayed inside compatible apps (also using the Commit
    -+  Content API), allowing users to insert emojis, stickers, or other rich
    -+  content into text editors.
    - </p>
    - 
    --<h3 id="RuntimePermissions">
    --  <a href=
    --  "{@docRoot}samples/RuntimePermissions/index.html">RuntimePermissions</a>
    --</h3>
    --
    - <p>
    --  This sample shows runtime permissions available in Android 6.0 (API level 23)
    --  and higher. Display the log on screen to follow the execution. If executed on
    --  an Android 6.0 device, the app displays an additional option to access
    --  contacts using an 6.0-only optional permission.
    -+  <a href="/samples/CommitContentSampleIME/index.html">Image keyboard IME sample</a>
    - </p>
    -diff --git a/docs/html/sdk/1.0_r1/installing.jd b/docs/html/sdk/1.0_r1/installing.jd
    -index 38c2a1a..eb02742 100644
    ---- a/docs/html/sdk/1.0_r1/installing.jd
    -+++ b/docs/html/sdk/1.0_r1/installing.jd
    -@@ -1,3 +1,4 @@
    -+excludeFromSuggestions=true
    - @jd:body
    - 
    - <script type="text/javascript">
    -diff --git a/docs/html/sdk/1.0_r1/requirements.jd b/docs/html/sdk/1.0_r1/requirements.jd
    -index 96fdcb2..41774f0 100644
    ---- a/docs/html/sdk/1.0_r1/requirements.jd
    -+++ b/docs/html/sdk/1.0_r1/requirements.jd
    -@@ -1,3 +1,4 @@
    -+excludeFromSuggestions=true
    - @jd:body
    - 
    - <script type="text/javascript">
    -diff --git a/docs/html/sdk/1.0_r2/installing.jd b/docs/html/sdk/1.0_r2/installing.jd
    -index 38c2a1a..eb02742 100644
    ---- a/docs/html/sdk/1.0_r2/installing.jd
    -+++ b/docs/html/sdk/1.0_r2/installing.jd
    -@@ -1,3 +1,4 @@
    -+excludeFromSuggestions=true
    - @jd:body
    - 
    - <script type="text/javascript">
    -diff --git a/docs/html/sdk/1.0_r2/requirements.jd b/docs/html/sdk/1.0_r2/requirements.jd
    -index 96fdcb2..41774f0 100644
    ---- a/docs/html/sdk/1.0_r2/requirements.jd
    -+++ b/docs/html/sdk/1.0_r2/requirements.jd
    -@@ -1,3 +1,4 @@
    -+excludeFromSuggestions=true
    - @jd:body
    - 
    - <script type="text/javascript">
    -diff --git a/docs/html/sdk/1.1_r1/installing.jd b/docs/html/sdk/1.1_r1/installing.jd
    -index 38c2a1a..eb02742 100644
    ---- a/docs/html/sdk/1.1_r1/installing.jd
    -+++ b/docs/html/sdk/1.1_r1/installing.jd
    -@@ -1,3 +1,4 @@
    -+excludeFromSuggestions=true
    - @jd:body
    - 
    - <script type="text/javascript">
    -diff --git a/docs/html/sdk/1.1_r1/requirements.jd b/docs/html/sdk/1.1_r1/requirements.jd
    -index 96fdcb2..41774f0 100644
    ---- a/docs/html/sdk/1.1_r1/requirements.jd
    -+++ b/docs/html/sdk/1.1_r1/requirements.jd
    -@@ -1,3 +1,4 @@
    -+excludeFromSuggestions=true
    - @jd:body
    - 
    - <script type="text/javascript">
    -diff --git a/docs/html/sdk/1.5_r1/installing.jd b/docs/html/sdk/1.5_r1/installing.jd
    -index 38c2a1a..eb02742 100644
    ---- a/docs/html/sdk/1.5_r1/installing.jd
    -+++ b/docs/html/sdk/1.5_r1/installing.jd
    -@@ -1,3 +1,4 @@
    -+excludeFromSuggestions=true
    - @jd:body
    - 
    - <script type="text/javascript">
    -diff --git a/docs/html/sdk/1.5_r1/requirements.jd b/docs/html/sdk/1.5_r1/requirements.jd
    -index 96fdcb2..41774f0 100644
    ---- a/docs/html/sdk/1.5_r1/requirements.jd
    -+++ b/docs/html/sdk/1.5_r1/requirements.jd
    -@@ -1,3 +1,4 @@
    -+excludeFromSuggestions=true
    - @jd:body
    - 
    - <script type="text/javascript">
    -diff --git a/docs/html/sdk/1.5_r2/installing.jd b/docs/html/sdk/1.5_r2/installing.jd
    -index 38c2a1a..eb02742 100644
    ---- a/docs/html/sdk/1.5_r2/installing.jd
    -+++ b/docs/html/sdk/1.5_r2/installing.jd
    -@@ -1,3 +1,4 @@
    -+excludeFromSuggestions=true
    - @jd:body
    - 
    - <script type="text/javascript">
    -diff --git a/docs/html/sdk/1.5_r2/requirements.jd b/docs/html/sdk/1.5_r2/requirements.jd
    -index 96fdcb2..41774f0 100644
    ---- a/docs/html/sdk/1.5_r2/requirements.jd
    -+++ b/docs/html/sdk/1.5_r2/requirements.jd
    -@@ -1,3 +1,4 @@
    -+excludeFromSuggestions=true
    - @jd:body
    - 
    - <script type="text/javascript">
    -diff --git a/docs/html/sdk/1.5_r3/installing.jd b/docs/html/sdk/1.5_r3/installing.jd
    -index 38c2a1a..eb02742 100644
    ---- a/docs/html/sdk/1.5_r3/installing.jd
    -+++ b/docs/html/sdk/1.5_r3/installing.jd
    -@@ -1,3 +1,4 @@
    -+excludeFromSuggestions=true
    - @jd:body
    - 
    - <script type="text/javascript">
    -diff --git a/docs/html/sdk/1.5_r3/requirements.jd b/docs/html/sdk/1.5_r3/requirements.jd
    -index 96fdcb2..41774f0 100644
    ---- a/docs/html/sdk/1.5_r3/requirements.jd
    -+++ b/docs/html/sdk/1.5_r3/requirements.jd
    -@@ -1,3 +1,4 @@
    -+excludeFromSuggestions=true
    - @jd:body
    - 
    - <script type="text/javascript">
    -diff --git a/docs/html/sdk/1.6_r1/installing.jd b/docs/html/sdk/1.6_r1/installing.jd
    -index 38c2a1a..eb02742 100644
    ---- a/docs/html/sdk/1.6_r1/installing.jd
    -+++ b/docs/html/sdk/1.6_r1/installing.jd
    -@@ -1,3 +1,4 @@
    -+excludeFromSuggestions=true
    - @jd:body
    - 
    - <script type="text/javascript">
    -diff --git a/docs/html/sdk/1.6_r1/requirements.jd b/docs/html/sdk/1.6_r1/requirements.jd
    -index 96fdcb2..41774f0 100644
    ---- a/docs/html/sdk/1.6_r1/requirements.jd
    -+++ b/docs/html/sdk/1.6_r1/requirements.jd
    -@@ -1,3 +1,4 @@
    -+excludeFromSuggestions=true
    - @jd:body
    - 
    - <script type="text/javascript">
    -diff --git a/docs/html/sdk/support_api_diff/22.2.0/changes/alldiffs_index_additions.html b/docs/html/sdk/support_api_diff/22.2.0/changes/alldiffs_index_additions.html
    -index 9786c92..fcff8ea 100644
    ---- a/docs/html/sdk/support_api_diff/22.2.0/changes/alldiffs_index_additions.html
    -+++ b/docs/html/sdk/support_api_diff/22.2.0/changes/alldiffs_index_additions.html
    -@@ -332,7 +332,7 @@ Listed as: <span style="color:#069"><strong>Added</strong></span>,  <span style=
    - <!-- Method zBy -->
    - <nobr><A HREF="android.support.v4.view.ViewPropertyAnimatorCompat.html#android.support.v4.view.ViewPropertyAnimatorCompat.zBy_added(float)" class="hiddenlink" target="rightframe"><b>zBy</b>
    - (<code>float</code>)</A></nobr><br>
    --<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    - </script>
    - <script type="text/javascript">
    -   try {
    -diff --git a/docs/html/sdk/support_api_diff/22.2.0/changes/alldiffs_index_all.html b/docs/html/sdk/support_api_diff/22.2.0/changes/alldiffs_index_all.html
    -index 7055d15..4e923e6 100644
    ---- a/docs/html/sdk/support_api_diff/22.2.0/changes/alldiffs_index_all.html
    -+++ b/docs/html/sdk/support_api_diff/22.2.0/changes/alldiffs_index_all.html
    -@@ -425,7 +425,7 @@ Listed as: <span style="color:#069"><strong>Added</strong></span>,  <span style=
    - <!-- Method zBy -->
    - <nobr><A HREF="android.support.v4.view.ViewPropertyAnimatorCompat.html#android.support.v4.view.ViewPropertyAnimatorCompat.zBy_added(float)" class="hiddenlink" target="rightframe"><b>zBy</b>
    - (<code>float</code>)</A></nobr><br>
    --<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    - </script>
    - <script type="text/javascript">
    -   try {
    -diff --git a/docs/html/sdk/support_api_diff/22.2.0/changes/alldiffs_index_changes.html b/docs/html/sdk/support_api_diff/22.2.0/changes/alldiffs_index_changes.html
    -index c40c9f5..4002f63 100644
    ---- a/docs/html/sdk/support_api_diff/22.2.0/changes/alldiffs_index_changes.html
    -+++ b/docs/html/sdk/support_api_diff/22.2.0/changes/alldiffs_index_changes.html
    -@@ -114,7 +114,7 @@ Listed as: <span style="color:#069"><strong>Added</strong></span>,  <span style=
    - <A HREF="android.support.v4.view.ViewParentCompat.html" class="hiddenlink" target="rightframe">ViewParentCompat</A><br>
    - <!-- Class ViewPropertyAnimatorCompat -->
    - <A HREF="android.support.v4.view.ViewPropertyAnimatorCompat.html" class="hiddenlink" target="rightframe">ViewPropertyAnimatorCompat</A><br>
    --<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    - </script>
    - <script type="text/javascript">
    -   try {
    -diff --git a/docs/html/sdk/support_api_diff/22.2.0/changes/alldiffs_index_removals.html b/docs/html/sdk/support_api_diff/22.2.0/changes/alldiffs_index_removals.html
    -index 68d2c20..c6ec566 100644
    ---- a/docs/html/sdk/support_api_diff/22.2.0/changes/alldiffs_index_removals.html
    -+++ b/docs/html/sdk/support_api_diff/22.2.0/changes/alldiffs_index_removals.html
    -@@ -47,7 +47,7 @@ body{overflow:auto;}
    - <div id="indexTableCaption" style="background-color:#eee;padding:0 4px 0 4px;font-size:11px;margin-bottom:1em;">
    - Listed as: <span style="color:#069"><strong>Added</strong></span>,  <span style="color:#069"><strike>Removed</strike></span>,  <span style="color:#069">Changed</span></font>
    - </div>
    --<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    - </script>
    - <script type="text/javascript">
    -   try {
    -diff --git a/docs/html/sdk/support_api_diff/22.2.0/changes/android.support.v4.media.session.PlaybackStateCompat.Builder.html b/docs/html/sdk/support_api_diff/22.2.0/changes/android.support.v4.media.session.PlaybackStateCompat.Builder.html
    -index ae6415e..42084ee 100644
    ---- a/docs/html/sdk/support_api_diff/22.2.0/changes/android.support.v4.media.session.PlaybackStateCompat.Builder.html
    -+++ b/docs/html/sdk/support_api_diff/22.2.0/changes/android.support.v4.media.session.PlaybackStateCompat.Builder.html
    -@@ -129,7 +129,7 @@ Class android.support.v4.media.session.<A HREF="../../../../reference/android/su
    -     </div> <!-- end footer -->
    -     </div><!-- end doc-content -->
    -     </div> <!-- end body-content --> 
    --<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    - </script>
    - <script type="text/javascript">
    -   try {
    -diff --git a/docs/html/sdk/support_api_diff/22.2.0/changes/android.support.v4.media.session.PlaybackStateCompat.CustomAction.html b/docs/html/sdk/support_api_diff/22.2.0/changes/android.support.v4.media.session.PlaybackStateCompat.CustomAction.html
    -index 4e476b3..deab0af 100644
    ---- a/docs/html/sdk/support_api_diff/22.2.0/changes/android.support.v4.media.session.PlaybackStateCompat.CustomAction.html
    -+++ b/docs/html/sdk/support_api_diff/22.2.0/changes/android.support.v4.media.session.PlaybackStateCompat.CustomAction.html
    -@@ -115,7 +115,7 @@ Class android.support.v4.media.session.<A HREF="../../../../reference/android/su
    -     </div> <!-- end footer -->
    -     </div><!-- end doc-content -->
    -     </div> <!-- end body-content --> 
    --<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    - </script>
    - <script type="text/javascript">
    -   try {
    -diff --git a/docs/html/sdk/support_api_diff/22.2.0/changes/android.support.v4.media.session.PlaybackStateCompat.html b/docs/html/sdk/support_api_diff/22.2.0/changes/android.support.v4.media.session.PlaybackStateCompat.html
    -index bd3e5dd..16b5462 100644
    ---- a/docs/html/sdk/support_api_diff/22.2.0/changes/android.support.v4.media.session.PlaybackStateCompat.html
    -+++ b/docs/html/sdk/support_api_diff/22.2.0/changes/android.support.v4.media.session.PlaybackStateCompat.html
    -@@ -144,7 +144,7 @@ Class android.support.v4.media.session.<A HREF="../../../../reference/android/su
    -     </div> <!-- end footer -->
    -     </div><!-- end doc-content -->
    -     </div> <!-- end body-content --> 
    --<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    - </script>
    - <script type="text/javascript">
    -   try {
    -diff --git a/docs/html/sdk/support_api_diff/22.2.0/changes/android.support.v4.view.ViewCompat.html b/docs/html/sdk/support_api_diff/22.2.0/changes/android.support.v4.view.ViewCompat.html
    -index 1574050..d48ce71 100644
    ---- a/docs/html/sdk/support_api_diff/22.2.0/changes/android.support.v4.view.ViewCompat.html
    -+++ b/docs/html/sdk/support_api_diff/22.2.0/changes/android.support.v4.view.ViewCompat.html
    -@@ -122,7 +122,7 @@ Class android.support.v4.view.<A HREF="../../../../reference/android/support/v4/
    -     </div> <!-- end footer -->
    -     </div><!-- end doc-content -->
    -     </div> <!-- end body-content --> 
    --<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    - </script>
    - <script type="text/javascript">
    -   try {
    -diff --git a/docs/html/sdk/support_api_diff/22.2.0/changes/android.support.v4.view.ViewPager.html b/docs/html/sdk/support_api_diff/22.2.0/changes/android.support.v4.view.ViewPager.html
    -index f03c403..bed9612 100644
    ---- a/docs/html/sdk/support_api_diff/22.2.0/changes/android.support.v4.view.ViewPager.html
    -+++ b/docs/html/sdk/support_api_diff/22.2.0/changes/android.support.v4.view.ViewPager.html
    -@@ -140,7 +140,7 @@ Class android.support.v4.view.<A HREF="../../../../reference/android/support/v4/
    -     </div> <!-- end footer -->
    -     </div><!-- end doc-content -->
    -     </div> <!-- end body-content --> 
    --<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    - </script>
    - <script type="text/javascript">
    -   try {
    -diff --git a/docs/html/sdk/support_api_diff/22.2.0/changes/android.support.v4.view.ViewParentCompat.html b/docs/html/sdk/support_api_diff/22.2.0/changes/android.support.v4.view.ViewParentCompat.html
    -index 6cdd299..08d2ab2 100644
    ---- a/docs/html/sdk/support_api_diff/22.2.0/changes/android.support.v4.view.ViewParentCompat.html
    -+++ b/docs/html/sdk/support_api_diff/22.2.0/changes/android.support.v4.view.ViewParentCompat.html
    -@@ -108,7 +108,7 @@ Class android.support.v4.view.<A HREF="../../../../reference/android/support/v4/
    -     </div> <!-- end footer -->
    -     </div><!-- end doc-content -->
    -     </div> <!-- end body-content --> 
    --<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    - </script>
    - <script type="text/javascript">
    -   try {
    -diff --git a/docs/html/sdk/support_api_diff/22.2.0/changes/android.support.v4.view.ViewPropertyAnimatorCompat.html b/docs/html/sdk/support_api_diff/22.2.0/changes/android.support.v4.view.ViewPropertyAnimatorCompat.html
    -index 5706997..1bfa2b3 100644
    ---- a/docs/html/sdk/support_api_diff/22.2.0/changes/android.support.v4.view.ViewPropertyAnimatorCompat.html
    -+++ b/docs/html/sdk/support_api_diff/22.2.0/changes/android.support.v4.view.ViewPropertyAnimatorCompat.html
    -@@ -129,7 +129,7 @@ Class android.support.v4.view.<A HREF="../../../../reference/android/support/v4/
    -     </div> <!-- end footer -->
    -     </div><!-- end doc-content -->
    -     </div> <!-- end body-content --> 
    --<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    - </script>
    - <script type="text/javascript">
    -   try {
    -diff --git a/docs/html/sdk/support_api_diff/22.2.0/changes/android.support.v4.view.accessibility.AccessibilityEventCompat.html b/docs/html/sdk/support_api_diff/22.2.0/changes/android.support.v4.view.accessibility.AccessibilityEventCompat.html
    -index e746f08..09b19c2 100644
    ---- a/docs/html/sdk/support_api_diff/22.2.0/changes/android.support.v4.view.accessibility.AccessibilityEventCompat.html
    -+++ b/docs/html/sdk/support_api_diff/22.2.0/changes/android.support.v4.view.accessibility.AccessibilityEventCompat.html
    -@@ -151,7 +151,7 @@ Class android.support.v4.view.accessibility.<A HREF="../../../../reference/andro
    -     </div> <!-- end footer -->
    -     </div><!-- end doc-content -->
    -     </div> <!-- end body-content --> 
    --<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    - </script>
    - <script type="text/javascript">
    -   try {
    -diff --git a/docs/html/sdk/support_api_diff/22.2.0/changes/android.support.v7.app.AppCompatActivity.html b/docs/html/sdk/support_api_diff/22.2.0/changes/android.support.v7.app.AppCompatActivity.html
    -index ccce9c5..7b2f8bb 100644
    ---- a/docs/html/sdk/support_api_diff/22.2.0/changes/android.support.v7.app.AppCompatActivity.html
    -+++ b/docs/html/sdk/support_api_diff/22.2.0/changes/android.support.v7.app.AppCompatActivity.html
    -@@ -108,7 +108,7 @@ Class android.support.v7.app.<A HREF="../../../../reference/android/support/v7/a
    -     </div> <!-- end footer -->
    -     </div><!-- end doc-content -->
    -     </div> <!-- end body-content --> 
    --<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    - </script>
    - <script type="text/javascript">
    -   try {
    -diff --git a/docs/html/sdk/support_api_diff/22.2.0/changes/android.support.v7.app.AppCompatCallback.html b/docs/html/sdk/support_api_diff/22.2.0/changes/android.support.v7.app.AppCompatCallback.html
    -index f53a519..fd75b74 100644
    ---- a/docs/html/sdk/support_api_diff/22.2.0/changes/android.support.v7.app.AppCompatCallback.html
    -+++ b/docs/html/sdk/support_api_diff/22.2.0/changes/android.support.v7.app.AppCompatCallback.html
    -@@ -108,7 +108,7 @@ Interface android.support.v7.app.<A HREF="../../../../reference/android/support/
    -     </div> <!-- end footer -->
    -     </div><!-- end doc-content -->
    -     </div> <!-- end body-content --> 
    --<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    - </script>
    - <script type="text/javascript">
    -   try {
    -diff --git a/docs/html/sdk/support_api_diff/22.2.0/changes/android.support.v7.app.AppCompatDelegate.html b/docs/html/sdk/support_api_diff/22.2.0/changes/android.support.v7.app.AppCompatDelegate.html
    -index 88490d4..5df87b9 100644
    ---- a/docs/html/sdk/support_api_diff/22.2.0/changes/android.support.v7.app.AppCompatDelegate.html
    -+++ b/docs/html/sdk/support_api_diff/22.2.0/changes/android.support.v7.app.AppCompatDelegate.html
    -@@ -115,7 +115,7 @@ Class android.support.v7.app.<A HREF="../../../../reference/android/support/v7/a
    -     </div> <!-- end footer -->
    -     </div><!-- end doc-content -->
    -     </div> <!-- end body-content --> 
    --<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    - </script>
    - <script type="text/javascript">
    -   try {
    -diff --git a/docs/html/sdk/support_api_diff/22.2.0/changes/android.support.v7.app.AppCompatDialog.html b/docs/html/sdk/support_api_diff/22.2.0/changes/android.support.v7.app.AppCompatDialog.html
    -index 42d29a8..6d992ad 100644
    ---- a/docs/html/sdk/support_api_diff/22.2.0/changes/android.support.v7.app.AppCompatDialog.html
    -+++ b/docs/html/sdk/support_api_diff/22.2.0/changes/android.support.v7.app.AppCompatDialog.html
    -@@ -108,7 +108,7 @@ Class android.support.v7.app.<A HREF="../../../../reference/android/support/v7/a
    -     </div> <!-- end footer -->
    -     </div><!-- end doc-content -->
    -     </div> <!-- end body-content --> 
    --<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    - </script>
    - <script type="text/javascript">
    -   try {
    -diff --git a/docs/html/sdk/support_api_diff/22.2.0/changes/android.support.v7.util.SortedList.html b/docs/html/sdk/support_api_diff/22.2.0/changes/android.support.v7.util.SortedList.html
    -index 0364519..edfb8bd 100644
    ---- a/docs/html/sdk/support_api_diff/22.2.0/changes/android.support.v7.util.SortedList.html
    -+++ b/docs/html/sdk/support_api_diff/22.2.0/changes/android.support.v7.util.SortedList.html
    -@@ -108,7 +108,7 @@ Class android.support.v7.util.<A HREF="../../../../reference/android/support/v7/
    -     </div> <!-- end footer -->
    -     </div><!-- end doc-content -->
    -     </div> <!-- end body-content --> 
    --<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    - </script>
    - <script type="text/javascript">
    -   try {
    -diff --git a/docs/html/sdk/support_api_diff/22.2.0/changes/changes-summary.html b/docs/html/sdk/support_api_diff/22.2.0/changes/changes-summary.html
    -index c6736cd..72ddc5a 100644
    ---- a/docs/html/sdk/support_api_diff/22.2.0/changes/changes-summary.html
    -+++ b/docs/html/sdk/support_api_diff/22.2.0/changes/changes-summary.html
    -@@ -233,7 +233,7 @@ see the <a href="http://developer.android.com/index.html" target="_top">Android
    -     </div> <!-- end footer -->
    -     </div><!-- end doc-content -->
    -     </div> <!-- end body-content --> 
    --<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    - </script>
    - <script type="text/javascript">
    -   try {
    -diff --git a/docs/html/sdk/support_api_diff/22.2.0/changes/classes_index_additions.html b/docs/html/sdk/support_api_diff/22.2.0/changes/classes_index_additions.html
    -index ccd5b66..4537739 100644
    ---- a/docs/html/sdk/support_api_diff/22.2.0/changes/classes_index_additions.html
    -+++ b/docs/html/sdk/support_api_diff/22.2.0/changes/classes_index_additions.html
    -@@ -47,7 +47,7 @@ body{overflow:auto;}
    - <div id="indexTableCaption" style="background-color:#eee;padding:0 4px 0 4px;font-size:11px;margin-bottom:1em;">
    - Listed as: <span style="color:#069"><strong>Added</strong></span>,  <span style="color:#069"><strike>Removed</strike></span>,  <span style="color:#069">Changed</span></font>
    - </div>
    --<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    - </script>
    - <script type="text/javascript">
    -   try {
    -diff --git a/docs/html/sdk/support_api_diff/22.2.0/changes/classes_index_all.html b/docs/html/sdk/support_api_diff/22.2.0/changes/classes_index_all.html
    -index 728e37d..50a77aa 100644
    ---- a/docs/html/sdk/support_api_diff/22.2.0/changes/classes_index_all.html
    -+++ b/docs/html/sdk/support_api_diff/22.2.0/changes/classes_index_all.html
    -@@ -88,7 +88,7 @@ Listed as: <span style="color:#069"><strong>Added</strong></span>,  <span style=
    - <A HREF="android.support.v4.view.ViewPager.html" class="hiddenlink" target="rightframe">ViewPager</A><br>
    - <A HREF="android.support.v4.view.ViewParentCompat.html" class="hiddenlink" target="rightframe">ViewParentCompat</A><br>
    - <A HREF="android.support.v4.view.ViewPropertyAnimatorCompat.html" class="hiddenlink" target="rightframe">ViewPropertyAnimatorCompat</A><br>
    --<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    - </script>
    - <script type="text/javascript">
    -   try {
    -diff --git a/docs/html/sdk/support_api_diff/22.2.0/changes/classes_index_changes.html b/docs/html/sdk/support_api_diff/22.2.0/changes/classes_index_changes.html
    -index 64e7f44..04fc9bc 100644
    ---- a/docs/html/sdk/support_api_diff/22.2.0/changes/classes_index_changes.html
    -+++ b/docs/html/sdk/support_api_diff/22.2.0/changes/classes_index_changes.html
    -@@ -88,7 +88,7 @@ Listed as: <span style="color:#069"><strong>Added</strong></span>,  <span style=
    - <A HREF="android.support.v4.view.ViewPager.html" class="hiddenlink" target="rightframe">ViewPager</A><br>
    - <A HREF="android.support.v4.view.ViewParentCompat.html" class="hiddenlink" target="rightframe">ViewParentCompat</A><br>
    - <A HREF="android.support.v4.view.ViewPropertyAnimatorCompat.html" class="hiddenlink" target="rightframe">ViewPropertyAnimatorCompat</A><br>
    --<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    - </script>
    - <script type="text/javascript">
    -   try {
    -diff --git a/docs/html/sdk/support_api_diff/22.2.0/changes/classes_index_removals.html b/docs/html/sdk/support_api_diff/22.2.0/changes/classes_index_removals.html
    -index 792fc4e..8881d7d 100644
    ---- a/docs/html/sdk/support_api_diff/22.2.0/changes/classes_index_removals.html
    -+++ b/docs/html/sdk/support_api_diff/22.2.0/changes/classes_index_removals.html
    -@@ -47,7 +47,7 @@ body{overflow:auto;}
    - <div id="indexTableCaption" style="background-color:#eee;padding:0 4px 0 4px;font-size:11px;margin-bottom:1em;">
    - Listed as: <span style="color:#069"><strong>Added</strong></span>,  <span style="color:#069"><strike>Removed</strike></span>,  <span style="color:#069">Changed</span></font>
    - </div>
    --<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    - </script>
    - <script type="text/javascript">
    -   try {
    -diff --git a/docs/html/sdk/support_api_diff/22.2.0/changes/constructors_index_additions.html b/docs/html/sdk/support_api_diff/22.2.0/changes/constructors_index_additions.html
    -index 3237ba3..603d376 100644
    ---- a/docs/html/sdk/support_api_diff/22.2.0/changes/constructors_index_additions.html
    -+++ b/docs/html/sdk/support_api_diff/22.2.0/changes/constructors_index_additions.html
    -@@ -47,7 +47,7 @@ body{overflow:auto;}
    - <div id="indexTableCaption" style="background-color:#eee;padding:0 4px 0 4px;font-size:11px;margin-bottom:1em;">
    - Listed as: <span style="color:#069"><strong>Added</strong></span>,  <span style="color:#069"><strike>Removed</strike></span>,  <span style="color:#069">Changed</span></font>
    - </div>
    --<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    - </script>
    - <script type="text/javascript">
    -   try {
    -diff --git a/docs/html/sdk/support_api_diff/22.2.0/changes/constructors_index_all.html b/docs/html/sdk/support_api_diff/22.2.0/changes/constructors_index_all.html
    -index 637582e..a29ef64 100644
    ---- a/docs/html/sdk/support_api_diff/22.2.0/changes/constructors_index_all.html
    -+++ b/docs/html/sdk/support_api_diff/22.2.0/changes/constructors_index_all.html
    -@@ -47,7 +47,7 @@ body{overflow:auto;}
    - <div id="indexTableCaption" style="background-color:#eee;padding:0 4px 0 4px;font-size:11px;margin-bottom:1em;">
    - Listed as: <span style="color:#069"><strong>Added</strong></span>,  <span style="color:#069"><strike>Removed</strike></span>,  <span style="color:#069">Changed</span></font>
    - </div>
    --<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    - </script>
    - <script type="text/javascript">
    -   try {
    -diff --git a/docs/html/sdk/support_api_diff/22.2.0/changes/constructors_index_changes.html b/docs/html/sdk/support_api_diff/22.2.0/changes/constructors_index_changes.html
    -index 728fa2d..182ad3c 100644
    ---- a/docs/html/sdk/support_api_diff/22.2.0/changes/constructors_index_changes.html
    -+++ b/docs/html/sdk/support_api_diff/22.2.0/changes/constructors_index_changes.html
    -@@ -47,7 +47,7 @@ body{overflow:auto;}
    - <div id="indexTableCaption" style="background-color:#eee;padding:0 4px 0 4px;font-size:11px;margin-bottom:1em;">
    - Listed as: <span style="color:#069"><strong>Added</strong></span>,  <span style="color:#069"><strike>Removed</strike></span>,  <span style="color:#069">Changed</span></font>
    - </div>
    --<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    - </script>
    - <script type="text/javascript">
    -   try {
    -diff --git a/docs/html/sdk/support_api_diff/22.2.0/changes/constructors_index_removals.html b/docs/html/sdk/support_api_diff/22.2.0/changes/constructors_index_removals.html
    -index 1b95544..9f9bb43 100644
    ---- a/docs/html/sdk/support_api_diff/22.2.0/changes/constructors_index_removals.html
    -+++ b/docs/html/sdk/support_api_diff/22.2.0/changes/constructors_index_removals.html
    -@@ -47,7 +47,7 @@ body{overflow:auto;}
    - <div id="indexTableCaption" style="background-color:#eee;padding:0 4px 0 4px;font-size:11px;margin-bottom:1em;">
    - Listed as: <span style="color:#069"><strong>Added</strong></span>,  <span style="color:#069"><strike>Removed</strike></span>,  <span style="color:#069">Changed</span></font>
    - </div>
    --<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    - </script>
    - <script type="text/javascript">
    -   try {
    -diff --git a/docs/html/sdk/support_api_diff/22.2.0/changes/fields_index_additions.html b/docs/html/sdk/support_api_diff/22.2.0/changes/fields_index_additions.html
    -index 48de992..6b0d997 100644
    ---- a/docs/html/sdk/support_api_diff/22.2.0/changes/fields_index_additions.html
    -+++ b/docs/html/sdk/support_api_diff/22.2.0/changes/fields_index_additions.html
    -@@ -69,7 +69,7 @@ Listed as: <span style="color:#069"><strong>Added</strong></span>,  <span style=
    - </nobr><br>
    - <nobr><A HREF="android.support.v4.media.session.PlaybackStateCompat.html#android.support.v4.media.session.PlaybackStateCompat.STATE_SKIPPING_TO_QUEUE_ITEM" class="hiddenlink" target="rightframe">STATE_SKIPPING_TO_QUEUE_ITEM</A>
    - </nobr><br>
    --<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    - </script>
    - <script type="text/javascript">
    -   try {
    -diff --git a/docs/html/sdk/support_api_diff/22.2.0/changes/fields_index_all.html b/docs/html/sdk/support_api_diff/22.2.0/changes/fields_index_all.html
    -index 02f6dc0..726deb6 100644
    ---- a/docs/html/sdk/support_api_diff/22.2.0/changes/fields_index_all.html
    -+++ b/docs/html/sdk/support_api_diff/22.2.0/changes/fields_index_all.html
    -@@ -69,7 +69,7 @@ Listed as: <span style="color:#069"><strong>Added</strong></span>,  <span style=
    - </nobr><br>
    - <nobr><A HREF="android.support.v4.media.session.PlaybackStateCompat.html#android.support.v4.media.session.PlaybackStateCompat.STATE_SKIPPING_TO_QUEUE_ITEM" class="hiddenlink" target="rightframe">STATE_SKIPPING_TO_QUEUE_ITEM</A>
    - </nobr><br>
    --<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    - </script>
    - <script type="text/javascript">
    -   try {
    -diff --git a/docs/html/sdk/support_api_diff/22.2.0/changes/fields_index_changes.html b/docs/html/sdk/support_api_diff/22.2.0/changes/fields_index_changes.html
    -index 4ebfa31..e4376a5 100644
    ---- a/docs/html/sdk/support_api_diff/22.2.0/changes/fields_index_changes.html
    -+++ b/docs/html/sdk/support_api_diff/22.2.0/changes/fields_index_changes.html
    -@@ -47,7 +47,7 @@ body{overflow:auto;}
    - <div id="indexTableCaption" style="background-color:#eee;padding:0 4px 0 4px;font-size:11px;margin-bottom:1em;">
    - Listed as: <span style="color:#069"><strong>Added</strong></span>,  <span style="color:#069"><strike>Removed</strike></span>,  <span style="color:#069">Changed</span></font>
    - </div>
    --<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    - </script>
    - <script type="text/javascript">
    -   try {
    -diff --git a/docs/html/sdk/support_api_diff/22.2.0/changes/fields_index_removals.html b/docs/html/sdk/support_api_diff/22.2.0/changes/fields_index_removals.html
    -index 09b0726..db6d007 100644
    ---- a/docs/html/sdk/support_api_diff/22.2.0/changes/fields_index_removals.html
    -+++ b/docs/html/sdk/support_api_diff/22.2.0/changes/fields_index_removals.html
    -@@ -47,7 +47,7 @@ body{overflow:auto;}
    - <div id="indexTableCaption" style="background-color:#eee;padding:0 4px 0 4px;font-size:11px;margin-bottom:1em;">
    - Listed as: <span style="color:#069"><strong>Added</strong></span>,  <span style="color:#069"><strike>Removed</strike></span>,  <span style="color:#069">Changed</span></font>
    - </div>
    --<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    - </script>
    - <script type="text/javascript">
    -   try {
    -diff --git a/docs/html/sdk/support_api_diff/22.2.0/changes/jdiff_help.html b/docs/html/sdk/support_api_diff/22.2.0/changes/jdiff_help.html
    -index 8bfbd1d..e978be0 100644
    ---- a/docs/html/sdk/support_api_diff/22.2.0/changes/jdiff_help.html
    -+++ b/docs/html/sdk/support_api_diff/22.2.0/changes/jdiff_help.html
    -@@ -120,7 +120,7 @@ These links show and hide the HTML frames. All pages are available with or witho
    - There are some complex changes which can occur between versions, for example, when two or more methods with the same name change simultaneously, or when a method or field is moved into or from a superclass. 
    - In these cases, the change will be seen as a removal and an addition, rather than as a change. Unexpected removals or additions are often part of one of these type of changes. 
    - </BLOCKQUOTE>
    --<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    - </script>
    - <script type="text/javascript">
    -   try {
    -diff --git a/docs/html/sdk/support_api_diff/22.2.0/changes/jdiff_statistics.html b/docs/html/sdk/support_api_diff/22.2.0/changes/jdiff_statistics.html
    -index 229819b..6a96e39 100644
    ---- a/docs/html/sdk/support_api_diff/22.2.0/changes/jdiff_statistics.html
    -+++ b/docs/html/sdk/support_api_diff/22.2.0/changes/jdiff_statistics.html
    -@@ -265,7 +265,7 @@ added, the change will be 100%.</p>
    -     </div> <!-- end footer -->
    -     </div><!-- end doc-content -->
    -     </div> <!-- end body-content --> 
    --<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    - </script>
    - <script type="text/javascript">
    -   try {
    -diff --git a/docs/html/sdk/support_api_diff/22.2.0/changes/jdiff_topleftframe.html b/docs/html/sdk/support_api_diff/22.2.0/changes/jdiff_topleftframe.html
    -index 36f9836..6a2e76e 100644
    ---- a/docs/html/sdk/support_api_diff/22.2.0/changes/jdiff_topleftframe.html
    -+++ b/docs/html/sdk/support_api_diff/22.2.0/changes/jdiff_topleftframe.html
    -@@ -49,7 +49,7 @@ body{overflow:auto;}
    -   <TD NOWRAP><FONT CLASS="indexText" size="-2"><A HREF="fields_index_all.html" TARGET="bottomleftframe">By Field</A></FONT><br></TD>
    - </TR>
    - </TABLE>
    --<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    - </script>
    - <script type="text/javascript">
    -   try {
    -diff --git a/docs/html/sdk/support_api_diff/22.2.0/changes/methods_index_additions.html b/docs/html/sdk/support_api_diff/22.2.0/changes/methods_index_additions.html
    -index f7c8488..b7b94ac 100644
    ---- a/docs/html/sdk/support_api_diff/22.2.0/changes/methods_index_additions.html
    -+++ b/docs/html/sdk/support_api_diff/22.2.0/changes/methods_index_additions.html
    -@@ -264,7 +264,7 @@ Listed as: <span style="color:#069"><strong>Added</strong></span>,  <span style=
    - (<code>float</code>)</A></nobr><br>
    - <nobr><A HREF="android.support.v4.view.ViewPropertyAnimatorCompat.html#android.support.v4.view.ViewPropertyAnimatorCompat.zBy_added(float)" class="hiddenlink" target="rightframe"><b>zBy</b>
    - (<code>float</code>)</A></nobr><br>
    --<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    - </script>
    - <script type="text/javascript">
    -   try {
    -diff --git a/docs/html/sdk/support_api_diff/22.2.0/changes/methods_index_all.html b/docs/html/sdk/support_api_diff/22.2.0/changes/methods_index_all.html
    -index 63a2848..04d3884 100644
    ---- a/docs/html/sdk/support_api_diff/22.2.0/changes/methods_index_all.html
    -+++ b/docs/html/sdk/support_api_diff/22.2.0/changes/methods_index_all.html
    -@@ -266,7 +266,7 @@ Listed as: <span style="color:#069"><strong>Added</strong></span>,  <span style=
    - (<code>float</code>)</A></nobr><br>
    - <nobr><A HREF="android.support.v4.view.ViewPropertyAnimatorCompat.html#android.support.v4.view.ViewPropertyAnimatorCompat.zBy_added(float)" class="hiddenlink" target="rightframe"><b>zBy</b>
    - (<code>float</code>)</A></nobr><br>
    --<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    - </script>
    - <script type="text/javascript">
    -   try {
    -diff --git a/docs/html/sdk/support_api_diff/22.2.0/changes/methods_index_changes.html b/docs/html/sdk/support_api_diff/22.2.0/changes/methods_index_changes.html
    -index 3e43f87..3bfd471 100644
    ---- a/docs/html/sdk/support_api_diff/22.2.0/changes/methods_index_changes.html
    -+++ b/docs/html/sdk/support_api_diff/22.2.0/changes/methods_index_changes.html
    -@@ -53,7 +53,7 @@ Listed as: <span style="color:#069"><strong>Added</strong></span>,  <span style=
    - <p><div style="line-height:1.5em;color:black">
    - <nobr><A HREF="android.support.v4.view.ViewPager.html#android.support.v4.view.ViewPager.setOnPageChangeListener_changed(android.support.v4.view.ViewPager.OnPageChangeListener)" class="hiddenlink" target="rightframe">setOnPageChangeListener
    - (<code>OnPageChangeListener</code>)</A></nobr><br>
    --<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    - </script>
    - <script type="text/javascript">
    -   try {
    -diff --git a/docs/html/sdk/support_api_diff/22.2.0/changes/methods_index_removals.html b/docs/html/sdk/support_api_diff/22.2.0/changes/methods_index_removals.html
    -index b5aea4f..e85e6fc 100644
    ---- a/docs/html/sdk/support_api_diff/22.2.0/changes/methods_index_removals.html
    -+++ b/docs/html/sdk/support_api_diff/22.2.0/changes/methods_index_removals.html
    -@@ -47,7 +47,7 @@ body{overflow:auto;}
    - <div id="indexTableCaption" style="background-color:#eee;padding:0 4px 0 4px;font-size:11px;margin-bottom:1em;">
    - Listed as: <span style="color:#069"><strong>Added</strong></span>,  <span style="color:#069"><strike>Removed</strike></span>,  <span style="color:#069">Changed</span></font>
    - </div>
    --<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    - </script>
    - <script type="text/javascript">
    -   try {
    -diff --git a/docs/html/sdk/support_api_diff/22.2.0/changes/packages_index_additions.html b/docs/html/sdk/support_api_diff/22.2.0/changes/packages_index_additions.html
    -index 7d92a82..183d500 100644
    ---- a/docs/html/sdk/support_api_diff/22.2.0/changes/packages_index_additions.html
    -+++ b/docs/html/sdk/support_api_diff/22.2.0/changes/packages_index_additions.html
    -@@ -61,7 +61,7 @@ Listed as: <span style="color:#069"><strong>Added</strong></span>,  <span style=
    - <A HREF="changes-summary.html#android.support.v7.appcompat" class="hiddenlink" target="rightframe"><b>android.support.v7.appcompat</b></A><br>
    - <A HREF="changes-summary.html#android.support.v7.recyclerview" class="hiddenlink" target="rightframe"><b>android.support.v7.recyclerview</b></A><br>
    - <A HREF="changes-summary.html#android.support.v7.widget.helper" class="hiddenlink" target="rightframe"><b>android.support.v7.widget.helper</b></A><br>
    --<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    - </script>
    - <script type="text/javascript">
    -   try {
    -diff --git a/docs/html/sdk/support_api_diff/22.2.0/changes/packages_index_all.html b/docs/html/sdk/support_api_diff/22.2.0/changes/packages_index_all.html
    -index 2735fe9..0fb83cf 100644
    ---- a/docs/html/sdk/support_api_diff/22.2.0/changes/packages_index_all.html
    -+++ b/docs/html/sdk/support_api_diff/22.2.0/changes/packages_index_all.html
    -@@ -66,7 +66,7 @@ Listed as: <span style="color:#069"><strong>Added</strong></span>,  <span style=
    - <A HREF="changes-summary.html#android.support.v7.recyclerview" class="hiddenlink" target="rightframe"><b>android.support.v7.recyclerview</b></A><br>
    - <A HREF="pkg_android.support.v7.util.html" class="hiddenlink" target="rightframe">android.support.v7.util</A><br>
    - <A HREF="changes-summary.html#android.support.v7.widget.helper" class="hiddenlink" target="rightframe"><b>android.support.v7.widget.helper</b></A><br>
    --<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    - </script>
    - <script type="text/javascript">
    -   try {
    -diff --git a/docs/html/sdk/support_api_diff/22.2.0/changes/packages_index_changes.html b/docs/html/sdk/support_api_diff/22.2.0/changes/packages_index_changes.html
    -index 3e40878..917e060 100644
    ---- a/docs/html/sdk/support_api_diff/22.2.0/changes/packages_index_changes.html
    -+++ b/docs/html/sdk/support_api_diff/22.2.0/changes/packages_index_changes.html
    -@@ -55,7 +55,7 @@ Listed as: <span style="color:#069"><strong>Added</strong></span>,  <span style=
    - <A HREF="pkg_android.support.v4.view.accessibility.html" class="hiddenlink" target="rightframe">android.support.v4.view.accessibility</A><br>
    - <A HREF="pkg_android.support.v7.app.html" class="hiddenlink" target="rightframe">android.support.v7.app</A><br>
    - <A HREF="pkg_android.support.v7.util.html" class="hiddenlink" target="rightframe">android.support.v7.util</A><br>
    --<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    - </script>
    - <script type="text/javascript">
    -   try {
    -diff --git a/docs/html/sdk/support_api_diff/22.2.0/changes/packages_index_removals.html b/docs/html/sdk/support_api_diff/22.2.0/changes/packages_index_removals.html
    -index d0ffabc..d5a825d 100644
    ---- a/docs/html/sdk/support_api_diff/22.2.0/changes/packages_index_removals.html
    -+++ b/docs/html/sdk/support_api_diff/22.2.0/changes/packages_index_removals.html
    -@@ -49,7 +49,7 @@ Listed as: <span style="color:#069"><strong>Added</strong></span>,  <span style=
    - </div>
    - <br>
    - <div id="indexTableEntries">
    --<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    - </script>
    - <script type="text/javascript">
    -   try {
    -diff --git a/docs/html/sdk/support_api_diff/22.2.0/changes/pkg_android.support.v4.media.session.html b/docs/html/sdk/support_api_diff/22.2.0/changes/pkg_android.support.v4.media.session.html
    -index 4dfd7de..992f05d 100644
    ---- a/docs/html/sdk/support_api_diff/22.2.0/changes/pkg_android.support.v4.media.session.html
    -+++ b/docs/html/sdk/support_api_diff/22.2.0/changes/pkg_android.support.v4.media.session.html
    -@@ -119,7 +119,7 @@ Package <A HREF="../../../../reference/android/support/v4/media/session/package-
    -     </div> <!-- end footer -->
    -     </div><!-- end doc-content -->
    -     </div> <!-- end body-content --> 
    --<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    - </script>
    - <script type="text/javascript">
    -   try {
    -diff --git a/docs/html/sdk/support_api_diff/22.2.0/changes/pkg_android.support.v4.view.accessibility.html b/docs/html/sdk/support_api_diff/22.2.0/changes/pkg_android.support.v4.view.accessibility.html
    -index f52efcb..86dc841 100644
    ---- a/docs/html/sdk/support_api_diff/22.2.0/changes/pkg_android.support.v4.view.accessibility.html
    -+++ b/docs/html/sdk/support_api_diff/22.2.0/changes/pkg_android.support.v4.view.accessibility.html
    -@@ -105,7 +105,7 @@ Package <A HREF="../../../../reference/android/support/v4/view/accessibility/pac
    -     </div> <!-- end footer -->
    -     </div><!-- end doc-content -->
    -     </div> <!-- end body-content --> 
    --<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    - </script>
    - <script type="text/javascript">
    -   try {
    -diff --git a/docs/html/sdk/support_api_diff/22.2.0/changes/pkg_android.support.v4.view.html b/docs/html/sdk/support_api_diff/22.2.0/changes/pkg_android.support.v4.view.html
    -index f05d812..ad51e62 100644
    ---- a/docs/html/sdk/support_api_diff/22.2.0/changes/pkg_android.support.v4.view.html
    -+++ b/docs/html/sdk/support_api_diff/22.2.0/changes/pkg_android.support.v4.view.html
    -@@ -126,7 +126,7 @@ Package <A HREF="../../../../reference/android/support/v4/view/package-summary.h
    -     </div> <!-- end footer -->
    -     </div><!-- end doc-content -->
    -     </div> <!-- end body-content --> 
    --<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    - </script>
    - <script type="text/javascript">
    -   try {
    -diff --git a/docs/html/sdk/support_api_diff/22.2.0/changes/pkg_android.support.v7.app.html b/docs/html/sdk/support_api_diff/22.2.0/changes/pkg_android.support.v7.app.html
    -index 44bf61d..508323f 100644
    ---- a/docs/html/sdk/support_api_diff/22.2.0/changes/pkg_android.support.v7.app.html
    -+++ b/docs/html/sdk/support_api_diff/22.2.0/changes/pkg_android.support.v7.app.html
    -@@ -126,7 +126,7 @@ Package <A HREF="../../../../reference/android/support/v7/app/package-summary.ht
    -     </div> <!-- end footer -->
    -     </div><!-- end doc-content -->
    -     </div> <!-- end body-content --> 
    --<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    - </script>
    - <script type="text/javascript">
    -   try {
    -diff --git a/docs/html/sdk/support_api_diff/22.2.0/changes/pkg_android.support.v7.util.html b/docs/html/sdk/support_api_diff/22.2.0/changes/pkg_android.support.v7.util.html
    -index d08d9af..8f74fb7 100644
    ---- a/docs/html/sdk/support_api_diff/22.2.0/changes/pkg_android.support.v7.util.html
    -+++ b/docs/html/sdk/support_api_diff/22.2.0/changes/pkg_android.support.v7.util.html
    -@@ -105,7 +105,7 @@ Package <A HREF="../../../../reference/android/support/v7/util/package-summary.h
    -     </div> <!-- end footer -->
    -     </div><!-- end doc-content -->
    -     </div> <!-- end body-content --> 
    --<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    - </script>
    - <script type="text/javascript">
    -   try {
    -diff --git a/docs/html/sdk/support_api_diff/22.2.1/changes/alldiffs_index_additions.html b/docs/html/sdk/support_api_diff/22.2.1/changes/alldiffs_index_additions.html
    -index 3374ffd..a1055f1 100644
    ---- a/docs/html/sdk/support_api_diff/22.2.1/changes/alldiffs_index_additions.html
    -+++ b/docs/html/sdk/support_api_diff/22.2.1/changes/alldiffs_index_additions.html
    -@@ -660,7 +660,7 @@ Listed as: <span style="color:#069"><strong>Added</strong></span>,  <span style=
    - <!-- Method useStaticShadow -->
    - <nobr><A HREF="android.support.v17.leanback.widget.ShadowOverlayContainer.html#android.support.v17.leanback.widget.ShadowOverlayContainer.useStaticShadow_added()" class="hiddenlink" target="rightframe"><b>useStaticShadow</b>
    - ()</A></nobr><br>
    --<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    - </script>
    - <script type="text/javascript">
    -   try {
    -diff --git a/docs/html/sdk/support_api_diff/22.2.1/changes/alldiffs_index_all.html b/docs/html/sdk/support_api_diff/22.2.1/changes/alldiffs_index_all.html
    -index bb24c29..48f43d2 100644
    ---- a/docs/html/sdk/support_api_diff/22.2.1/changes/alldiffs_index_all.html
    -+++ b/docs/html/sdk/support_api_diff/22.2.1/changes/alldiffs_index_all.html
    -@@ -913,7 +913,7 @@ Listed as: <span style="color:#069"><strong>Added</strong></span>,  <span style=
    -  <a href="#topheader"><font size="-2">TOP</font></a>
    - <p><div style="line-height:1.5em;color:black">
    - <A HREF="android.support.v17.leanback.widget.VerticalGridPresenter.html" class="hiddenlink" target="rightframe">VerticalGridPresenter</A><br>
    --<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    - </script>
    - <script type="text/javascript">
    -   try {
    -diff --git a/docs/html/sdk/support_api_diff/22.2.1/changes/alldiffs_index_changes.html b/docs/html/sdk/support_api_diff/22.2.1/changes/alldiffs_index_changes.html
    -index 8340749..d5b60c9 100644
    ---- a/docs/html/sdk/support_api_diff/22.2.1/changes/alldiffs_index_changes.html
    -+++ b/docs/html/sdk/support_api_diff/22.2.1/changes/alldiffs_index_changes.html
    -@@ -389,7 +389,7 @@ Listed as: <span style="color:#069"><strong>Added</strong></span>,  <span style=
    -  <a href="#topheader"><font size="-2">TOP</font></a>
    - <p><div style="line-height:1.5em;color:black">
    - <A HREF="android.support.v17.leanback.widget.VerticalGridPresenter.html" class="hiddenlink" target="rightframe">VerticalGridPresenter</A><br>
    --<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    - </script>
    - <script type="text/javascript">
    -   try {
    -diff --git a/docs/html/sdk/support_api_diff/22.2.1/changes/alldiffs_index_removals.html b/docs/html/sdk/support_api_diff/22.2.1/changes/alldiffs_index_removals.html
    -index 0d670c0..f2a8797 100644
    ---- a/docs/html/sdk/support_api_diff/22.2.1/changes/alldiffs_index_removals.html
    -+++ b/docs/html/sdk/support_api_diff/22.2.1/changes/alldiffs_index_removals.html
    -@@ -83,7 +83,7 @@ Listed as: <span style="color:#069"><strong>Added</strong></span>,  <span style=
    - <!-- Field Platform_V12_AppCompat_Light -->
    - <nobr><A HREF="android.support.v7.appcompat.R.style.html#android.support.v7.appcompat.R.style.Platform_V12_AppCompat_Light" class="hiddenlink" target="rightframe"><strike>Platform_V12_AppCompat_Light</strike></A>
    - </nobr><br>
    --<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    - </script>
    - <script type="text/javascript">
    -   try {
    -diff --git a/docs/html/sdk/support_api_diff/22.2.1/changes/android.support.design.widget.CoordinatorLayout.Behavior.html b/docs/html/sdk/support_api_diff/22.2.1/changes/android.support.design.widget.CoordinatorLayout.Behavior.html
    -index 78392f4..c45efa2 100644
    ---- a/docs/html/sdk/support_api_diff/22.2.1/changes/android.support.design.widget.CoordinatorLayout.Behavior.html
    -+++ b/docs/html/sdk/support_api_diff/22.2.1/changes/android.support.design.widget.CoordinatorLayout.Behavior.html
    -@@ -108,7 +108,7 @@ Class android.support.design.widget.<A HREF="../../../../reference/android/suppo
    -     </div> <!-- end footer -->
    -     </div><!-- end doc-content -->
    -     </div> <!-- end body-content --> 
    --<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    - </script>
    - <script type="text/javascript">
    -   try {
    -diff --git a/docs/html/sdk/support_api_diff/22.2.1/changes/android.support.design.widget.FloatingActionButton.Behavior.html b/docs/html/sdk/support_api_diff/22.2.1/changes/android.support.design.widget.FloatingActionButton.Behavior.html
    -index 6d68976..a23105a 100644
    ---- a/docs/html/sdk/support_api_diff/22.2.1/changes/android.support.design.widget.FloatingActionButton.Behavior.html
    -+++ b/docs/html/sdk/support_api_diff/22.2.1/changes/android.support.design.widget.FloatingActionButton.Behavior.html
    -@@ -115,7 +115,7 @@ Class android.support.design.widget.<A HREF="../../../../reference/android/suppo
    -     </div> <!-- end footer -->
    -     </div><!-- end doc-content -->
    -     </div> <!-- end body-content --> 
    --<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    - </script>
    - <script type="text/javascript">
    -   try {
    -diff --git a/docs/html/sdk/support_api_diff/22.2.1/changes/android.support.design.widget.FloatingActionButton.html b/docs/html/sdk/support_api_diff/22.2.1/changes/android.support.design.widget.FloatingActionButton.html
    -index 21b55c0..91a6d77 100644
    ---- a/docs/html/sdk/support_api_diff/22.2.1/changes/android.support.design.widget.FloatingActionButton.html
    -+++ b/docs/html/sdk/support_api_diff/22.2.1/changes/android.support.design.widget.FloatingActionButton.html
    -@@ -115,7 +115,7 @@ Class android.support.design.widget.<A HREF="../../../../reference/android/suppo
    -     </div> <!-- end footer -->
    -     </div><!-- end doc-content -->
    -     </div> <!-- end body-content --> 
    --<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    - </script>
    - <script type="text/javascript">
    -   try {
    -diff --git a/docs/html/sdk/support_api_diff/22.2.1/changes/android.support.design.widget.Snackbar.html b/docs/html/sdk/support_api_diff/22.2.1/changes/android.support.design.widget.Snackbar.html
    -index 028df73..24fdf70 100644
    ---- a/docs/html/sdk/support_api_diff/22.2.1/changes/android.support.design.widget.Snackbar.html
    -+++ b/docs/html/sdk/support_api_diff/22.2.1/changes/android.support.design.widget.Snackbar.html
    -@@ -130,7 +130,7 @@ Class android.support.design.widget.<A HREF="../../../../reference/android/suppo
    -     </div> <!-- end footer -->
    -     </div><!-- end doc-content -->
    -     </div> <!-- end body-content --> 
    --<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    - </script>
    - <script type="text/javascript">
    -   try {
    -diff --git a/docs/html/sdk/support_api_diff/22.2.1/changes/android.support.design.widget.TabLayout.Tab.html b/docs/html/sdk/support_api_diff/22.2.1/changes/android.support.design.widget.TabLayout.Tab.html
    -index 2acf995..74a296d 100644
    ---- a/docs/html/sdk/support_api_diff/22.2.1/changes/android.support.design.widget.TabLayout.Tab.html
    -+++ b/docs/html/sdk/support_api_diff/22.2.1/changes/android.support.design.widget.TabLayout.Tab.html
    -@@ -108,7 +108,7 @@ Class android.support.design.widget.<A HREF="../../../../reference/android/suppo
    -     </div> <!-- end footer -->
    -     </div><!-- end doc-content -->
    -     </div> <!-- end body-content --> 
    --<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    - </script>
    - <script type="text/javascript">
    -   try {
    -diff --git a/docs/html/sdk/support_api_diff/22.2.1/changes/android.support.design.widget.TabLayout.html b/docs/html/sdk/support_api_diff/22.2.1/changes/android.support.design.widget.TabLayout.html
    -index 22a5ff5..3a8d151 100644
    ---- a/docs/html/sdk/support_api_diff/22.2.1/changes/android.support.design.widget.TabLayout.html
    -+++ b/docs/html/sdk/support_api_diff/22.2.1/changes/android.support.design.widget.TabLayout.html
    -@@ -108,7 +108,7 @@ Class android.support.design.widget.<A HREF="../../../../reference/android/suppo
    -     </div> <!-- end footer -->
    -     </div><!-- end doc-content -->
    -     </div> <!-- end body-content --> 
    --<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    - </script>
    - <script type="text/javascript">
    -   try {
    -diff --git a/docs/html/sdk/support_api_diff/22.2.1/changes/android.support.v17.leanback.app.DetailsFragment.html b/docs/html/sdk/support_api_diff/22.2.1/changes/android.support.v17.leanback.app.DetailsFragment.html
    -index 16e5798..7ae6ce1 100644
    ---- a/docs/html/sdk/support_api_diff/22.2.1/changes/android.support.v17.leanback.app.DetailsFragment.html
    -+++ b/docs/html/sdk/support_api_diff/22.2.1/changes/android.support.v17.leanback.app.DetailsFragment.html
    -@@ -136,7 +136,7 @@ Class android.support.v17.leanback.app.<A HREF="../../../../reference/android/su
    -     </div> <!-- end footer -->
    -     </div><!-- end doc-content -->
    -     </div> <!-- end body-content --> 
    --<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    - </script>
    - <script type="text/javascript">
    -   try {
    -diff --git a/docs/html/sdk/support_api_diff/22.2.1/changes/android.support.v17.leanback.app.DetailsSupportFragment.html b/docs/html/sdk/support_api_diff/22.2.1/changes/android.support.v17.leanback.app.DetailsSupportFragment.html
    -index 7825292..d1733ac 100644
    ---- a/docs/html/sdk/support_api_diff/22.2.1/changes/android.support.v17.leanback.app.DetailsSupportFragment.html
    -+++ b/docs/html/sdk/support_api_diff/22.2.1/changes/android.support.v17.leanback.app.DetailsSupportFragment.html
    -@@ -136,7 +136,7 @@ Class android.support.v17.leanback.app.<A HREF="../../../../reference/android/su
    -     </div> <!-- end footer -->
    -     </div><!-- end doc-content -->
    -     </div> <!-- end body-content --> 
    --<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    - </script>
    - <script type="text/javascript">
    -   try {
    -diff --git a/docs/html/sdk/support_api_diff/22.2.1/changes/android.support.v17.leanback.widget.DetailsOverviewRowPresenter.html b/docs/html/sdk/support_api_diff/22.2.1/changes/android.support.v17.leanback.widget.DetailsOverviewRowPresenter.html
    -index ba8e6af..799db3d 100644
    ---- a/docs/html/sdk/support_api_diff/22.2.1/changes/android.support.v17.leanback.widget.DetailsOverviewRowPresenter.html
    -+++ b/docs/html/sdk/support_api_diff/22.2.1/changes/android.support.v17.leanback.widget.DetailsOverviewRowPresenter.html
    -@@ -94,7 +94,7 @@ Class android.support.v17.leanback.widget.<A HREF="../../../../reference/android
    -     </div> <!-- end footer -->
    -     </div><!-- end doc-content -->
    -     </div> <!-- end body-content --> 
    --<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    - </script>
    - <script type="text/javascript">
    -   try {
    -diff --git a/docs/html/sdk/support_api_diff/22.2.1/changes/android.support.v17.leanback.widget.ItemBridgeAdapter.ViewHolder.html b/docs/html/sdk/support_api_diff/22.2.1/changes/android.support.v17.leanback.widget.ItemBridgeAdapter.ViewHolder.html
    -index 25f1b48..f8c0cbf 100644
    ---- a/docs/html/sdk/support_api_diff/22.2.1/changes/android.support.v17.leanback.widget.ItemBridgeAdapter.ViewHolder.html
    -+++ b/docs/html/sdk/support_api_diff/22.2.1/changes/android.support.v17.leanback.widget.ItemBridgeAdapter.ViewHolder.html
    -@@ -109,7 +109,7 @@ Class android.support.v17.leanback.widget.<A HREF="../../../../reference/android
    -     </div> <!-- end footer -->
    -     </div><!-- end doc-content -->
    -     </div> <!-- end body-content --> 
    --<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    - </script>
    - <script type="text/javascript">
    -   try {
    -diff --git a/docs/html/sdk/support_api_diff/22.2.1/changes/android.support.v17.leanback.widget.ItemBridgeAdapter.html b/docs/html/sdk/support_api_diff/22.2.1/changes/android.support.v17.leanback.widget.ItemBridgeAdapter.html
    -index a88f694..b98c33e 100644
    ---- a/docs/html/sdk/support_api_diff/22.2.1/changes/android.support.v17.leanback.widget.ItemBridgeAdapter.html
    -+++ b/docs/html/sdk/support_api_diff/22.2.1/changes/android.support.v17.leanback.widget.ItemBridgeAdapter.html
    -@@ -109,7 +109,7 @@ Class android.support.v17.leanback.widget.<A HREF="../../../../reference/android
    -     </div> <!-- end footer -->
    -     </div><!-- end doc-content -->
    -     </div> <!-- end body-content --> 
    --<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    - </script>
    - <script type="text/javascript">
    -   try {
    -diff --git a/docs/html/sdk/support_api_diff/22.2.1/changes/android.support.v17.leanback.widget.ListRowPresenter.html b/docs/html/sdk/support_api_diff/22.2.1/changes/android.support.v17.leanback.widget.ListRowPresenter.html
    -index 5d71011..f9ad877 100644
    ---- a/docs/html/sdk/support_api_diff/22.2.1/changes/android.support.v17.leanback.widget.ListRowPresenter.html
    -+++ b/docs/html/sdk/support_api_diff/22.2.1/changes/android.support.v17.leanback.widget.ListRowPresenter.html
    -@@ -111,7 +111,7 @@ Change in signature from <code>void</code> to <code>Context</code>.<br>
    -     </div> <!-- end footer -->
    -     </div><!-- end doc-content -->
    -     </div> <!-- end body-content --> 
    --<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    - </script>
    - <script type="text/javascript">
    -   try {
    -diff --git a/docs/html/sdk/support_api_diff/22.2.1/changes/android.support.v17.leanback.widget.OnChildSelectedListener.html b/docs/html/sdk/support_api_diff/22.2.1/changes/android.support.v17.leanback.widget.OnChildSelectedListener.html
    -index eb8a563..f13b147 100644
    ---- a/docs/html/sdk/support_api_diff/22.2.1/changes/android.support.v17.leanback.widget.OnChildSelectedListener.html
    -+++ b/docs/html/sdk/support_api_diff/22.2.1/changes/android.support.v17.leanback.widget.OnChildSelectedListener.html
    -@@ -94,7 +94,7 @@ Interface android.support.v17.leanback.widget.<A HREF="../../../../reference/and
    -     </div> <!-- end footer -->
    -     </div><!-- end doc-content -->
    -     </div> <!-- end body-content --> 
    --<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    - </script>
    - <script type="text/javascript">
    -   try {
    -diff --git a/docs/html/sdk/support_api_diff/22.2.1/changes/android.support.v17.leanback.widget.Presenter.ViewHolder.html b/docs/html/sdk/support_api_diff/22.2.1/changes/android.support.v17.leanback.widget.Presenter.ViewHolder.html
    -index a94d9f5..55f3575 100644
    ---- a/docs/html/sdk/support_api_diff/22.2.1/changes/android.support.v17.leanback.widget.Presenter.ViewHolder.html
    -+++ b/docs/html/sdk/support_api_diff/22.2.1/changes/android.support.v17.leanback.widget.Presenter.ViewHolder.html
    -@@ -116,7 +116,7 @@ Class android.support.v17.leanback.widget.<A HREF="../../../../reference/android
    -     </div> <!-- end footer -->
    -     </div><!-- end doc-content -->
    -     </div> <!-- end body-content --> 
    --<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    - </script>
    - <script type="text/javascript">
    -   try {
    -diff --git a/docs/html/sdk/support_api_diff/22.2.1/changes/android.support.v17.leanback.widget.Presenter.html b/docs/html/sdk/support_api_diff/22.2.1/changes/android.support.v17.leanback.widget.Presenter.html
    -index fde5e4b..417bf86 100644
    ---- a/docs/html/sdk/support_api_diff/22.2.1/changes/android.support.v17.leanback.widget.Presenter.html
    -+++ b/docs/html/sdk/support_api_diff/22.2.1/changes/android.support.v17.leanback.widget.Presenter.html
    -@@ -116,7 +116,7 @@ Class android.support.v17.leanback.widget.<A HREF="../../../../reference/android
    -     </div> <!-- end footer -->
    -     </div><!-- end doc-content -->
    -     </div> <!-- end body-content --> 
    --<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    - </script>
    - <script type="text/javascript">
    -   try {
    -diff --git a/docs/html/sdk/support_api_diff/22.2.1/changes/android.support.v17.leanback.widget.PresenterSelector.html b/docs/html/sdk/support_api_diff/22.2.1/changes/android.support.v17.leanback.widget.PresenterSelector.html
    -index 06a0a79..827b2cf 100644
    ---- a/docs/html/sdk/support_api_diff/22.2.1/changes/android.support.v17.leanback.widget.PresenterSelector.html
    -+++ b/docs/html/sdk/support_api_diff/22.2.1/changes/android.support.v17.leanback.widget.PresenterSelector.html
    -@@ -108,7 +108,7 @@ Class android.support.v17.leanback.widget.<A HREF="../../../../reference/android
    -     </div> <!-- end footer -->
    -     </div><!-- end doc-content -->
    -     </div> <!-- end body-content --> 
    --<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    - </script>
    - <script type="text/javascript">
    -   try {
    -diff --git a/docs/html/sdk/support_api_diff/22.2.1/changes/android.support.v17.leanback.widget.RowPresenter.html b/docs/html/sdk/support_api_diff/22.2.1/changes/android.support.v17.leanback.widget.RowPresenter.html
    -index 6da5f9b..24b7683 100644
    ---- a/docs/html/sdk/support_api_diff/22.2.1/changes/android.support.v17.leanback.widget.RowPresenter.html
    -+++ b/docs/html/sdk/support_api_diff/22.2.1/changes/android.support.v17.leanback.widget.RowPresenter.html
    -@@ -108,7 +108,7 @@ Class android.support.v17.leanback.widget.<A HREF="../../../../reference/android
    -     </div> <!-- end footer -->
    -     </div><!-- end doc-content -->
    -     </div> <!-- end body-content --> 
    --<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    - </script>
    - <script type="text/javascript">
    -   try {
    -diff --git a/docs/html/sdk/support_api_diff/22.2.1/changes/android.support.v17.leanback.widget.ShadowOverlayContainer.html b/docs/html/sdk/support_api_diff/22.2.1/changes/android.support.v17.leanback.widget.ShadowOverlayContainer.html
    -index ac3ac3a..9814065 100644
    ---- a/docs/html/sdk/support_api_diff/22.2.1/changes/android.support.v17.leanback.widget.ShadowOverlayContainer.html
    -+++ b/docs/html/sdk/support_api_diff/22.2.1/changes/android.support.v17.leanback.widget.ShadowOverlayContainer.html
    -@@ -172,7 +172,7 @@ Class android.support.v17.leanback.widget.<A HREF="../../../../reference/android
    -     </div> <!-- end footer -->
    -     </div><!-- end doc-content -->
    -     </div> <!-- end body-content --> 
    --<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    - </script>
    - <script type="text/javascript">
    -   try {
    -diff --git a/docs/html/sdk/support_api_diff/22.2.1/changes/android.support.v17.leanback.widget.VerticalGridPresenter.html b/docs/html/sdk/support_api_diff/22.2.1/changes/android.support.v17.leanback.widget.VerticalGridPresenter.html
    -index ab9ce07..c18075e 100644
    ---- a/docs/html/sdk/support_api_diff/22.2.1/changes/android.support.v17.leanback.widget.VerticalGridPresenter.html
    -+++ b/docs/html/sdk/support_api_diff/22.2.1/changes/android.support.v17.leanback.widget.VerticalGridPresenter.html
    -@@ -111,7 +111,7 @@ Change in signature from <code>void</code> to <code>Context</code>.<br>
    -     </div> <!-- end footer -->
    -     </div><!-- end doc-content -->
    -     </div> <!-- end body-content --> 
    --<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    - </script>
    - <script type="text/javascript">
    -   try {
    -diff --git a/docs/html/sdk/support_api_diff/22.2.1/changes/android.support.v4.app.NotificationCompat.Action.html b/docs/html/sdk/support_api_diff/22.2.1/changes/android.support.v4.app.NotificationCompat.Action.html
    -index 8519610..d96b874 100644
    ---- a/docs/html/sdk/support_api_diff/22.2.1/changes/android.support.v4.app.NotificationCompat.Action.html
    -+++ b/docs/html/sdk/support_api_diff/22.2.1/changes/android.support.v4.app.NotificationCompat.Action.html
    -@@ -131,7 +131,7 @@ Change of visibility from protected to public.<br>
    -     </div> <!-- end footer -->
    -     </div><!-- end doc-content -->
    -     </div> <!-- end body-content --> 
    --<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    - </script>
    - <script type="text/javascript">
    -   try {
    -diff --git a/docs/html/sdk/support_api_diff/22.2.1/changes/android.support.v4.app.NotificationCompatBase.Action.html b/docs/html/sdk/support_api_diff/22.2.1/changes/android.support.v4.app.NotificationCompatBase.Action.html
    -index 498374e..09ae7fc 100644
    ---- a/docs/html/sdk/support_api_diff/22.2.1/changes/android.support.v4.app.NotificationCompatBase.Action.html
    -+++ b/docs/html/sdk/support_api_diff/22.2.1/changes/android.support.v4.app.NotificationCompatBase.Action.html
    -@@ -151,7 +151,7 @@ Change of visibility from protected to public.<br>
    -     </div> <!-- end footer -->
    -     </div><!-- end doc-content -->
    -     </div> <!-- end body-content --> 
    --<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    - </script>
    - <script type="text/javascript">
    -   try {
    -diff --git a/docs/html/sdk/support_api_diff/22.2.1/changes/android.support.v4.app.NotificationCompatBase.html b/docs/html/sdk/support_api_diff/22.2.1/changes/android.support.v4.app.NotificationCompatBase.html
    -index 309d7b6..9824574 100644
    ---- a/docs/html/sdk/support_api_diff/22.2.1/changes/android.support.v4.app.NotificationCompatBase.html
    -+++ b/docs/html/sdk/support_api_diff/22.2.1/changes/android.support.v4.app.NotificationCompatBase.html
    -@@ -109,7 +109,7 @@ Class android.support.v4.app.<A HREF="../../../../reference/android/support/v4/a
    -     </div> <!-- end footer -->
    -     </div><!-- end doc-content -->
    -     </div> <!-- end body-content --> 
    --<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    - </script>
    - <script type="text/javascript">
    -   try {
    -diff --git a/docs/html/sdk/support_api_diff/22.2.1/changes/android.support.v7.appcompat.R.attr.html b/docs/html/sdk/support_api_diff/22.2.1/changes/android.support.v7.appcompat.R.attr.html
    -index 229289c..541f134 100644
    ---- a/docs/html/sdk/support_api_diff/22.2.1/changes/android.support.v7.appcompat.R.attr.html
    -+++ b/docs/html/sdk/support_api_diff/22.2.1/changes/android.support.v7.appcompat.R.attr.html
    -@@ -108,7 +108,7 @@ Class android.support.v7.appcompat.<A HREF="../../../../reference/android/suppor
    -     </div> <!-- end footer -->
    -     </div><!-- end doc-content -->
    -     </div> <!-- end body-content --> 
    --<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    - </script>
    - <script type="text/javascript">
    -   try {
    -diff --git a/docs/html/sdk/support_api_diff/22.2.1/changes/android.support.v7.appcompat.R.dimen.html b/docs/html/sdk/support_api_diff/22.2.1/changes/android.support.v7.appcompat.R.dimen.html
    -index a253e59..584073e 100644
    ---- a/docs/html/sdk/support_api_diff/22.2.1/changes/android.support.v7.appcompat.R.dimen.html
    -+++ b/docs/html/sdk/support_api_diff/22.2.1/changes/android.support.v7.appcompat.R.dimen.html
    -@@ -122,7 +122,7 @@ Class android.support.v7.appcompat.<A HREF="../../../../reference/android/suppor
    -     </div> <!-- end footer -->
    -     </div><!-- end doc-content -->
    -     </div> <!-- end body-content --> 
    --<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    - </script>
    - <script type="text/javascript">
    -   try {
    -diff --git a/docs/html/sdk/support_api_diff/22.2.1/changes/android.support.v7.appcompat.R.drawable.html b/docs/html/sdk/support_api_diff/22.2.1/changes/android.support.v7.appcompat.R.drawable.html
    -index 4f87127..45a1dc7 100644
    ---- a/docs/html/sdk/support_api_diff/22.2.1/changes/android.support.v7.appcompat.R.drawable.html
    -+++ b/docs/html/sdk/support_api_diff/22.2.1/changes/android.support.v7.appcompat.R.drawable.html
    -@@ -108,7 +108,7 @@ Class android.support.v7.appcompat.<A HREF="../../../../reference/android/suppor
    -     </div> <!-- end footer -->
    -     </div><!-- end doc-content -->
    -     </div> <!-- end body-content --> 
    --<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    - </script>
    - <script type="text/javascript">
    -   try {
    -diff --git a/docs/html/sdk/support_api_diff/22.2.1/changes/android.support.v7.appcompat.R.id.html b/docs/html/sdk/support_api_diff/22.2.1/changes/android.support.v7.appcompat.R.id.html
    -index e856c8b..cecd912 100644
    ---- a/docs/html/sdk/support_api_diff/22.2.1/changes/android.support.v7.appcompat.R.id.html
    -+++ b/docs/html/sdk/support_api_diff/22.2.1/changes/android.support.v7.appcompat.R.id.html
    -@@ -192,7 +192,7 @@ Class android.support.v7.appcompat.<A HREF="../../../../reference/android/suppor
    -     </div> <!-- end footer -->
    -     </div><!-- end doc-content -->
    -     </div> <!-- end body-content --> 
    --<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    - </script>
    - <script type="text/javascript">
    -   try {
    -diff --git a/docs/html/sdk/support_api_diff/22.2.1/changes/android.support.v7.appcompat.R.integer.html b/docs/html/sdk/support_api_diff/22.2.1/changes/android.support.v7.appcompat.R.integer.html
    -index 70585a7..4b90739 100644
    ---- a/docs/html/sdk/support_api_diff/22.2.1/changes/android.support.v7.appcompat.R.integer.html
    -+++ b/docs/html/sdk/support_api_diff/22.2.1/changes/android.support.v7.appcompat.R.integer.html
    -@@ -115,7 +115,7 @@ Class android.support.v7.appcompat.<A HREF="../../../../reference/android/suppor
    -     </div> <!-- end footer -->
    -     </div><!-- end doc-content -->
    -     </div> <!-- end body-content --> 
    --<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    - </script>
    - <script type="text/javascript">
    -   try {
    -diff --git a/docs/html/sdk/support_api_diff/22.2.1/changes/android.support.v7.appcompat.R.layout.html b/docs/html/sdk/support_api_diff/22.2.1/changes/android.support.v7.appcompat.R.layout.html
    -index 8130707..c0a1304 100644
    ---- a/docs/html/sdk/support_api_diff/22.2.1/changes/android.support.v7.appcompat.R.layout.html
    -+++ b/docs/html/sdk/support_api_diff/22.2.1/changes/android.support.v7.appcompat.R.layout.html
    -@@ -157,7 +157,7 @@ Class android.support.v7.appcompat.<A HREF="../../../../reference/android/suppor
    -     </div> <!-- end footer -->
    -     </div><!-- end doc-content -->
    -     </div> <!-- end body-content --> 
    --<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    - </script>
    - <script type="text/javascript">
    -   try {
    -diff --git a/docs/html/sdk/support_api_diff/22.2.1/changes/android.support.v7.appcompat.R.string.html b/docs/html/sdk/support_api_diff/22.2.1/changes/android.support.v7.appcompat.R.string.html
    -index 6a01b20..39be2b2 100644
    ---- a/docs/html/sdk/support_api_diff/22.2.1/changes/android.support.v7.appcompat.R.string.html
    -+++ b/docs/html/sdk/support_api_diff/22.2.1/changes/android.support.v7.appcompat.R.string.html
    -@@ -108,7 +108,7 @@ Class android.support.v7.appcompat.<A HREF="../../../../reference/android/suppor
    -     </div> <!-- end footer -->
    -     </div><!-- end doc-content -->
    -     </div> <!-- end body-content --> 
    --<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    - </script>
    - <script type="text/javascript">
    -   try {
    -diff --git a/docs/html/sdk/support_api_diff/22.2.1/changes/android.support.v7.appcompat.R.style.html b/docs/html/sdk/support_api_diff/22.2.1/changes/android.support.v7.appcompat.R.style.html
    -index 886f2ce..ffc3690 100644
    ---- a/docs/html/sdk/support_api_diff/22.2.1/changes/android.support.v7.appcompat.R.style.html
    -+++ b/docs/html/sdk/support_api_diff/22.2.1/changes/android.support.v7.appcompat.R.style.html
    -@@ -186,7 +186,7 @@ Class android.support.v7.appcompat.<A HREF="../../../../reference/android/suppor
    -     </div> <!-- end footer -->
    -     </div><!-- end doc-content -->
    -     </div> <!-- end body-content --> 
    --<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    - </script>
    - <script type="text/javascript">
    -   try {
    -diff --git a/docs/html/sdk/support_api_diff/22.2.1/changes/android.support.v7.appcompat.R.styleable.html b/docs/html/sdk/support_api_diff/22.2.1/changes/android.support.v7.appcompat.R.styleable.html
    -index cd9cd60..713526b 100644
    ---- a/docs/html/sdk/support_api_diff/22.2.1/changes/android.support.v7.appcompat.R.styleable.html
    -+++ b/docs/html/sdk/support_api_diff/22.2.1/changes/android.support.v7.appcompat.R.styleable.html
    -@@ -108,7 +108,7 @@ Class android.support.v7.appcompat.<A HREF="../../../../reference/android/suppor
    -     </div> <!-- end footer -->
    -     </div><!-- end doc-content -->
    -     </div> <!-- end body-content --> 
    --<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    - </script>
    - <script type="text/javascript">
    -   try {
    -diff --git a/docs/html/sdk/support_api_diff/22.2.1/changes/android.support.v7.util.SortedList.html b/docs/html/sdk/support_api_diff/22.2.1/changes/android.support.v7.util.SortedList.html
    -index b38c632..181a0fc 100644
    ---- a/docs/html/sdk/support_api_diff/22.2.1/changes/android.support.v7.util.SortedList.html
    -+++ b/docs/html/sdk/support_api_diff/22.2.1/changes/android.support.v7.util.SortedList.html
    -@@ -122,7 +122,7 @@ Class android.support.v7.util.<A HREF="../../../../reference/android/support/v7/
    -     </div> <!-- end footer -->
    -     </div><!-- end doc-content -->
    -     </div> <!-- end body-content --> 
    --<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    - </script>
    - <script type="text/javascript">
    -   try {
    -diff --git a/docs/html/sdk/support_api_diff/22.2.1/changes/changes-summary.html b/docs/html/sdk/support_api_diff/22.2.1/changes/changes-summary.html
    -index e05b67d..b500246 100644
    ---- a/docs/html/sdk/support_api_diff/22.2.1/changes/changes-summary.html
    -+++ b/docs/html/sdk/support_api_diff/22.2.1/changes/changes-summary.html
    -@@ -177,7 +177,7 @@ see the <a href="http://developer.android.com/index.html" target="_top">Android
    -     </div> <!-- end footer -->
    -     </div><!-- end doc-content -->
    -     </div> <!-- end body-content --> 
    --<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    - </script>
    - <script type="text/javascript">
    -   try {
    -diff --git a/docs/html/sdk/support_api_diff/22.2.1/changes/classes_index_additions.html b/docs/html/sdk/support_api_diff/22.2.1/changes/classes_index_additions.html
    -index 52b4ab7..f2fe6ec 100644
    ---- a/docs/html/sdk/support_api_diff/22.2.1/changes/classes_index_additions.html
    -+++ b/docs/html/sdk/support_api_diff/22.2.1/changes/classes_index_additions.html
    -@@ -103,7 +103,7 @@ Listed as: <span style="color:#069"><strong>Added</strong></span>,  <span style=
    -  <a href="#topheader"><font size="-2">TOP</font></a>
    - <p><div style="line-height:1.5em;color:black">
    - <A HREF="pkg_android.support.v17.leanback.widget.html#OnChildViewHolderSelectedListener" class="hiddenlink" target="rightframe"><b>OnChildViewHolderSelectedListener</b></A><br>
    --<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    - </script>
    - <script type="text/javascript">
    -   try {
    -diff --git a/docs/html/sdk/support_api_diff/22.2.1/changes/classes_index_all.html b/docs/html/sdk/support_api_diff/22.2.1/changes/classes_index_all.html
    -index 1edab7a..16ebdfa 100644
    ---- a/docs/html/sdk/support_api_diff/22.2.1/changes/classes_index_all.html
    -+++ b/docs/html/sdk/support_api_diff/22.2.1/changes/classes_index_all.html
    -@@ -339,7 +339,7 @@ Listed as: <span style="color:#069"><strong>Added</strong></span>,  <span style=
    -  <a href="#topheader"><font size="-2">TOP</font></a>
    - <p><div style="line-height:1.5em;color:black">
    - <A HREF="android.support.v17.leanback.widget.VerticalGridPresenter.html" class="hiddenlink" target="rightframe">VerticalGridPresenter</A><br>
    --<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    - </script>
    - <script type="text/javascript">
    -   try {
    -diff --git a/docs/html/sdk/support_api_diff/22.2.1/changes/classes_index_changes.html b/docs/html/sdk/support_api_diff/22.2.1/changes/classes_index_changes.html
    -index f46bc67..8072f0f 100644
    ---- a/docs/html/sdk/support_api_diff/22.2.1/changes/classes_index_changes.html
    -+++ b/docs/html/sdk/support_api_diff/22.2.1/changes/classes_index_changes.html
    -@@ -259,7 +259,7 @@ Listed as: <span style="color:#069"><strong>Added</strong></span>,  <span style=
    -  <a href="#topheader"><font size="-2">TOP</font></a>
    - <p><div style="line-height:1.5em;color:black">
    - <A HREF="android.support.v17.leanback.widget.VerticalGridPresenter.html" class="hiddenlink" target="rightframe">VerticalGridPresenter</A><br>
    --<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    - </script>
    - <script type="text/javascript">
    -   try {
    -diff --git a/docs/html/sdk/support_api_diff/22.2.1/changes/classes_index_removals.html b/docs/html/sdk/support_api_diff/22.2.1/changes/classes_index_removals.html
    -index 09c0d19..757f5bb 100644
    ---- a/docs/html/sdk/support_api_diff/22.2.1/changes/classes_index_removals.html
    -+++ b/docs/html/sdk/support_api_diff/22.2.1/changes/classes_index_removals.html
    -@@ -63,7 +63,7 @@ Listed as: <span style="color:#069"><strong>Added</strong></span>,  <span style=
    -  <a href="#topheader"><font size="-2">TOP</font></a>
    - <p><div style="line-height:1.5em;color:black">
    - <A HREF="pkg_android.support.v17.leanback.widget.html#GridLayoutManager" class="hiddenlink" target="rightframe"><strike>GridLayoutManager</strike></A><br>
    --<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    - </script>
    - <script type="text/javascript">
    -   try {
    -diff --git a/docs/html/sdk/support_api_diff/22.2.1/changes/constructors_index_additions.html b/docs/html/sdk/support_api_diff/22.2.1/changes/constructors_index_additions.html
    -index e694216..3bced29 100644
    ---- a/docs/html/sdk/support_api_diff/22.2.1/changes/constructors_index_additions.html
    -+++ b/docs/html/sdk/support_api_diff/22.2.1/changes/constructors_index_additions.html
    -@@ -53,7 +53,7 @@ Listed as: <span style="color:#069"><strong>Added</strong></span>,  <span style=
    - <p><div style="line-height:1.5em;color:black">
    - <nobr><A HREF="android.support.v4.app.NotificationCompatBase.html#android.support.v4.app.NotificationCompatBase.ctor_added()" class="hiddenlink" target="rightframe"><b>NotificationCompatBase</b>
    - ()</A></nobr>&nbsp;constructor<br>
    --<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    - </script>
    - <script type="text/javascript">
    -   try {
    -diff --git a/docs/html/sdk/support_api_diff/22.2.1/changes/constructors_index_all.html b/docs/html/sdk/support_api_diff/22.2.1/changes/constructors_index_all.html
    -index 27d7557..7769d75 100644
    ---- a/docs/html/sdk/support_api_diff/22.2.1/changes/constructors_index_all.html
    -+++ b/docs/html/sdk/support_api_diff/22.2.1/changes/constructors_index_all.html
    -@@ -53,7 +53,7 @@ Listed as: <span style="color:#069"><strong>Added</strong></span>,  <span style=
    - <p><div style="line-height:1.5em;color:black">
    - <nobr><A HREF="android.support.v4.app.NotificationCompatBase.html#android.support.v4.app.NotificationCompatBase.ctor_added()" class="hiddenlink" target="rightframe"><b>NotificationCompatBase</b>
    - ()</A></nobr>&nbsp;constructor<br>
    --<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    - </script>
    - <script type="text/javascript">
    -   try {
    -diff --git a/docs/html/sdk/support_api_diff/22.2.1/changes/constructors_index_changes.html b/docs/html/sdk/support_api_diff/22.2.1/changes/constructors_index_changes.html
    -index a5ca2ef..122cdce 100644
    ---- a/docs/html/sdk/support_api_diff/22.2.1/changes/constructors_index_changes.html
    -+++ b/docs/html/sdk/support_api_diff/22.2.1/changes/constructors_index_changes.html
    -@@ -47,7 +47,7 @@ body{overflow:auto;}
    - <div id="indexTableCaption" style="background-color:#eee;padding:0 4px 0 4px;font-size:11px;margin-bottom:1em;">
    - Listed as: <span style="color:#069"><strong>Added</strong></span>,  <span style="color:#069"><strike>Removed</strike></span>,  <span style="color:#069">Changed</span></font>
    - </div>
    --<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    - </script>
    - <script type="text/javascript">
    -   try {
    -diff --git a/docs/html/sdk/support_api_diff/22.2.1/changes/constructors_index_removals.html b/docs/html/sdk/support_api_diff/22.2.1/changes/constructors_index_removals.html
    -index 74a09ba..dadd1cd 100644
    ---- a/docs/html/sdk/support_api_diff/22.2.1/changes/constructors_index_removals.html
    -+++ b/docs/html/sdk/support_api_diff/22.2.1/changes/constructors_index_removals.html
    -@@ -47,7 +47,7 @@ body{overflow:auto;}
    - <div id="indexTableCaption" style="background-color:#eee;padding:0 4px 0 4px;font-size:11px;margin-bottom:1em;">
    - Listed as: <span style="color:#069"><strong>Added</strong></span>,  <span style="color:#069"><strike>Removed</strike></span>,  <span style="color:#069">Changed</span></font>
    - </div>
    --<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    - </script>
    - <script type="text/javascript">
    -   try {
    -diff --git a/docs/html/sdk/support_api_diff/22.2.1/changes/fields_index_additions.html b/docs/html/sdk/support_api_diff/22.2.1/changes/fields_index_additions.html
    -index 2ae5237..5d6411a 100644
    ---- a/docs/html/sdk/support_api_diff/22.2.1/changes/fields_index_additions.html
    -+++ b/docs/html/sdk/support_api_diff/22.2.1/changes/fields_index_additions.html
    -@@ -263,7 +263,7 @@ Listed as: <span style="color:#069"><strong>Added</strong></span>,  <span style=
    - </nobr><br>
    - <nobr><A HREF="android.support.v7.appcompat.R.id.html#android.support.v7.appcompat.R.id.time" class="hiddenlink" target="rightframe">time</A>
    - </nobr><br>
    --<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    - </script>
    - <script type="text/javascript">
    -   try {
    -diff --git a/docs/html/sdk/support_api_diff/22.2.1/changes/fields_index_all.html b/docs/html/sdk/support_api_diff/22.2.1/changes/fields_index_all.html
    -index 4a9194d..85420c3 100644
    ---- a/docs/html/sdk/support_api_diff/22.2.1/changes/fields_index_all.html
    -+++ b/docs/html/sdk/support_api_diff/22.2.1/changes/fields_index_all.html
    -@@ -291,7 +291,7 @@ Listed as: <span style="color:#069"><strong>Added</strong></span>,  <span style=
    - </nobr><br>
    - <nobr><A HREF="android.support.v7.appcompat.R.id.html#android.support.v7.appcompat.R.id.time" class="hiddenlink" target="rightframe">time</A>
    - </nobr><br>
    --<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    - </script>
    - <script type="text/javascript">
    -   try {
    -diff --git a/docs/html/sdk/support_api_diff/22.2.1/changes/fields_index_changes.html b/docs/html/sdk/support_api_diff/22.2.1/changes/fields_index_changes.html
    -index 0e2ccff..301881a 100644
    ---- a/docs/html/sdk/support_api_diff/22.2.1/changes/fields_index_changes.html
    -+++ b/docs/html/sdk/support_api_diff/22.2.1/changes/fields_index_changes.html
    -@@ -47,7 +47,7 @@ body{overflow:auto;}
    - <div id="indexTableCaption" style="background-color:#eee;padding:0 4px 0 4px;font-size:11px;margin-bottom:1em;">
    - Listed as: <span style="color:#069"><strong>Added</strong></span>,  <span style="color:#069"><strike>Removed</strike></span>,  <span style="color:#069">Changed</span></font>
    - </div>
    --<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    - </script>
    - <script type="text/javascript">
    -   try {
    -diff --git a/docs/html/sdk/support_api_diff/22.2.1/changes/fields_index_removals.html b/docs/html/sdk/support_api_diff/22.2.1/changes/fields_index_removals.html
    -index 6245b05..b1bf691 100644
    ---- a/docs/html/sdk/support_api_diff/22.2.1/changes/fields_index_removals.html
    -+++ b/docs/html/sdk/support_api_diff/22.2.1/changes/fields_index_removals.html
    -@@ -55,7 +55,7 @@ Listed as: <span style="color:#069"><strong>Added</strong></span>,  <span style=
    - </nobr><br>
    - <nobr><A HREF="android.support.v7.appcompat.R.style.html#android.support.v7.appcompat.R.style.Platform_V12_AppCompat_Light" class="hiddenlink" target="rightframe"><strike>Platform_V12_AppCompat_Light</strike></A>
    - </nobr><br>
    --<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    - </script>
    - <script type="text/javascript">
    -   try {
    -diff --git a/docs/html/sdk/support_api_diff/22.2.1/changes/jdiff_help.html b/docs/html/sdk/support_api_diff/22.2.1/changes/jdiff_help.html
    -index 25acfbe..f9c1f08 100644
    ---- a/docs/html/sdk/support_api_diff/22.2.1/changes/jdiff_help.html
    -+++ b/docs/html/sdk/support_api_diff/22.2.1/changes/jdiff_help.html
    -@@ -120,7 +120,7 @@ These links show and hide the HTML frames. All pages are available with or witho
    - There are some complex changes which can occur between versions, for example, when two or more methods with the same name change simultaneously, or when a method or field is moved into or from a superclass. 
    - In these cases, the change will be seen as a removal and an addition, rather than as a change. Unexpected removals or additions are often part of one of these type of changes. 
    - </BLOCKQUOTE>
    --<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    - </script>
    - <script type="text/javascript">
    -   try {
    -diff --git a/docs/html/sdk/support_api_diff/22.2.1/changes/jdiff_statistics.html b/docs/html/sdk/support_api_diff/22.2.1/changes/jdiff_statistics.html
    -index 0f4805f..322ad44 100644
    ---- a/docs/html/sdk/support_api_diff/22.2.1/changes/jdiff_statistics.html
    -+++ b/docs/html/sdk/support_api_diff/22.2.1/changes/jdiff_statistics.html
    -@@ -368,7 +368,7 @@ added, the change will be 100%.</p>
    -     </div> <!-- end footer -->
    -     </div><!-- end doc-content -->
    -     </div> <!-- end body-content --> 
    --<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    - </script>
    - <script type="text/javascript">
    -   try {
    -diff --git a/docs/html/sdk/support_api_diff/22.2.1/changes/jdiff_topleftframe.html b/docs/html/sdk/support_api_diff/22.2.1/changes/jdiff_topleftframe.html
    -index 36f9836..6a2e76e 100644
    ---- a/docs/html/sdk/support_api_diff/22.2.1/changes/jdiff_topleftframe.html
    -+++ b/docs/html/sdk/support_api_diff/22.2.1/changes/jdiff_topleftframe.html
    -@@ -49,7 +49,7 @@ body{overflow:auto;}
    -   <TD NOWRAP><FONT CLASS="indexText" size="-2"><A HREF="fields_index_all.html" TARGET="bottomleftframe">By Field</A></FONT><br></TD>
    - </TR>
    - </TABLE>
    --<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    - </script>
    - <script type="text/javascript">
    -   try {
    -diff --git a/docs/html/sdk/support_api_diff/22.2.1/changes/methods_index_additions.html b/docs/html/sdk/support_api_diff/22.2.1/changes/methods_index_additions.html
    -index 33a155f..5a237de 100644
    ---- a/docs/html/sdk/support_api_diff/22.2.1/changes/methods_index_additions.html
    -+++ b/docs/html/sdk/support_api_diff/22.2.1/changes/methods_index_additions.html
    -@@ -224,7 +224,7 @@ Listed as: <span style="color:#069"><strong>Added</strong></span>,  <span style=
    - </A></nobr><br>
    - <nobr><A HREF="android.support.v17.leanback.widget.ShadowOverlayContainer.html#android.support.v17.leanback.widget.ShadowOverlayContainer.useStaticShadow_added()" class="hiddenlink" target="rightframe"><b>useStaticShadow</b>
    - ()</A></nobr><br>
    --<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    - </script>
    - <script type="text/javascript">
    -   try {
    -diff --git a/docs/html/sdk/support_api_diff/22.2.1/changes/methods_index_all.html b/docs/html/sdk/support_api_diff/22.2.1/changes/methods_index_all.html
    -index b9cf858..014ef9a 100644
    ---- a/docs/html/sdk/support_api_diff/22.2.1/changes/methods_index_all.html
    -+++ b/docs/html/sdk/support_api_diff/22.2.1/changes/methods_index_all.html
    -@@ -256,7 +256,7 @@ Listed as: <span style="color:#069"><strong>Added</strong></span>,  <span style=
    - </A></nobr><br>
    - <nobr><A HREF="android.support.v17.leanback.widget.ShadowOverlayContainer.html#android.support.v17.leanback.widget.ShadowOverlayContainer.useStaticShadow_added()" class="hiddenlink" target="rightframe"><b>useStaticShadow</b>
    - ()</A></nobr><br>
    --<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    - </script>
    - <script type="text/javascript">
    -   try {
    -diff --git a/docs/html/sdk/support_api_diff/22.2.1/changes/methods_index_changes.html b/docs/html/sdk/support_api_diff/22.2.1/changes/methods_index_changes.html
    -index 4e2d329..6b02e2a 100644
    ---- a/docs/html/sdk/support_api_diff/22.2.1/changes/methods_index_changes.html
    -+++ b/docs/html/sdk/support_api_diff/22.2.1/changes/methods_index_changes.html
    -@@ -89,7 +89,7 @@ Listed as: <span style="color:#069"><strong>Added</strong></span>,  <span style=
    - &nbsp;&nbsp;<nobr><A HREF="android.support.v17.leanback.widget.VerticalGridPresenter.html#android.support.v17.leanback.widget.VerticalGridPresenter.isUsingZOrder_changed(android.content.Context)" class="hiddenlink" target="rightframe">type&nbsp;
    - (<code>Context</code>)&nbsp;in&nbsp;android.support.v17.leanback.widget.VerticalGridPresenter
    - </A></nobr><br>
    --<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    - </script>
    - <script type="text/javascript">
    -   try {
    -diff --git a/docs/html/sdk/support_api_diff/22.2.1/changes/methods_index_removals.html b/docs/html/sdk/support_api_diff/22.2.1/changes/methods_index_removals.html
    -index b5aea4f..e85e6fc 100644
    ---- a/docs/html/sdk/support_api_diff/22.2.1/changes/methods_index_removals.html
    -+++ b/docs/html/sdk/support_api_diff/22.2.1/changes/methods_index_removals.html
    -@@ -47,7 +47,7 @@ body{overflow:auto;}
    - <div id="indexTableCaption" style="background-color:#eee;padding:0 4px 0 4px;font-size:11px;margin-bottom:1em;">
    - Listed as: <span style="color:#069"><strong>Added</strong></span>,  <span style="color:#069"><strike>Removed</strike></span>,  <span style="color:#069">Changed</span></font>
    - </div>
    --<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    - </script>
    - <script type="text/javascript">
    -   try {
    -diff --git a/docs/html/sdk/support_api_diff/22.2.1/changes/packages_index_additions.html b/docs/html/sdk/support_api_diff/22.2.1/changes/packages_index_additions.html
    -index 6311752..d08c85c 100644
    ---- a/docs/html/sdk/support_api_diff/22.2.1/changes/packages_index_additions.html
    -+++ b/docs/html/sdk/support_api_diff/22.2.1/changes/packages_index_additions.html
    -@@ -51,7 +51,7 @@ Listed as: <span style="color:#069"><strong>Added</strong></span>,  <span style=
    - <div id="indexTableEntries">
    - <A NAME="A"></A>
    - <A HREF="changes-summary.html#android.support.v17.leanback.system" class="hiddenlink" target="rightframe"><b>android.support.v17.leanback.system</b></A><br>
    --<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    - </script>
    - <script type="text/javascript">
    -   try {
    -diff --git a/docs/html/sdk/support_api_diff/22.2.1/changes/packages_index_all.html b/docs/html/sdk/support_api_diff/22.2.1/changes/packages_index_all.html
    -index 3f5ee13..712eac9 100644
    ---- a/docs/html/sdk/support_api_diff/22.2.1/changes/packages_index_all.html
    -+++ b/docs/html/sdk/support_api_diff/22.2.1/changes/packages_index_all.html
    -@@ -58,7 +58,7 @@ Listed as: <span style="color:#069"><strong>Added</strong></span>,  <span style=
    - <A HREF="pkg_android.support.v7.app.html" class="hiddenlink" target="rightframe">android.support.v7.app</A><br>
    - <A HREF="pkg_android.support.v7.appcompat.html" class="hiddenlink" target="rightframe">android.support.v7.appcompat</A><br>
    - <A HREF="pkg_android.support.v7.util.html" class="hiddenlink" target="rightframe">android.support.v7.util</A><br>
    --<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    - </script>
    - <script type="text/javascript">
    -   try {
    -diff --git a/docs/html/sdk/support_api_diff/22.2.1/changes/packages_index_changes.html b/docs/html/sdk/support_api_diff/22.2.1/changes/packages_index_changes.html
    -index a4637a7..e53ee87 100644
    ---- a/docs/html/sdk/support_api_diff/22.2.1/changes/packages_index_changes.html
    -+++ b/docs/html/sdk/support_api_diff/22.2.1/changes/packages_index_changes.html
    -@@ -57,7 +57,7 @@ Listed as: <span style="color:#069"><strong>Added</strong></span>,  <span style=
    - <A HREF="pkg_android.support.v7.app.html" class="hiddenlink" target="rightframe">android.support.v7.app</A><br>
    - <A HREF="pkg_android.support.v7.appcompat.html" class="hiddenlink" target="rightframe">android.support.v7.appcompat</A><br>
    - <A HREF="pkg_android.support.v7.util.html" class="hiddenlink" target="rightframe">android.support.v7.util</A><br>
    --<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    - </script>
    - <script type="text/javascript">
    -   try {
    -diff --git a/docs/html/sdk/support_api_diff/22.2.1/changes/packages_index_removals.html b/docs/html/sdk/support_api_diff/22.2.1/changes/packages_index_removals.html
    -index d0ffabc..d5a825d 100644
    ---- a/docs/html/sdk/support_api_diff/22.2.1/changes/packages_index_removals.html
    -+++ b/docs/html/sdk/support_api_diff/22.2.1/changes/packages_index_removals.html
    -@@ -49,7 +49,7 @@ Listed as: <span style="color:#069"><strong>Added</strong></span>,  <span style=
    - </div>
    - <br>
    - <div id="indexTableEntries">
    --<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    - </script>
    - <script type="text/javascript">
    -   try {
    -diff --git a/docs/html/sdk/support_api_diff/22.2.1/changes/pkg_android.support.design.widget.html b/docs/html/sdk/support_api_diff/22.2.1/changes/pkg_android.support.design.widget.html
    -index 345f33b..25070ce 100644
    ---- a/docs/html/sdk/support_api_diff/22.2.1/changes/pkg_android.support.design.widget.html
    -+++ b/docs/html/sdk/support_api_diff/22.2.1/changes/pkg_android.support.design.widget.html
    -@@ -140,7 +140,7 @@ Package <A HREF="../../../../reference/android/support/design/widget/package-sum
    -     </div> <!-- end footer -->
    -     </div><!-- end doc-content -->
    -     </div> <!-- end body-content --> 
    --<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    - </script>
    - <script type="text/javascript">
    -   try {
    -diff --git a/docs/html/sdk/support_api_diff/22.2.1/changes/pkg_android.support.v17.leanback.app.html b/docs/html/sdk/support_api_diff/22.2.1/changes/pkg_android.support.v17.leanback.app.html
    -index 873bc6b..48f868b 100644
    ---- a/docs/html/sdk/support_api_diff/22.2.1/changes/pkg_android.support.v17.leanback.app.html
    -+++ b/docs/html/sdk/support_api_diff/22.2.1/changes/pkg_android.support.v17.leanback.app.html
    -@@ -112,7 +112,7 @@ Package <A HREF="../../../../reference/android/support/v17/leanback/app/package-
    -     </div> <!-- end footer -->
    -     </div><!-- end doc-content -->
    -     </div> <!-- end body-content --> 
    --<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    - </script>
    - <script type="text/javascript">
    -   try {
    -diff --git a/docs/html/sdk/support_api_diff/22.2.1/changes/pkg_android.support.v17.leanback.widget.html b/docs/html/sdk/support_api_diff/22.2.1/changes/pkg_android.support.v17.leanback.widget.html
    -index 7197d3a..ac3d843 100644
    ---- a/docs/html/sdk/support_api_diff/22.2.1/changes/pkg_android.support.v17.leanback.widget.html
    -+++ b/docs/html/sdk/support_api_diff/22.2.1/changes/pkg_android.support.v17.leanback.widget.html
    -@@ -324,7 +324,7 @@ Package <A HREF="../../../../reference/android/support/v17/leanback/widget/packa
    -     </div> <!-- end footer -->
    -     </div><!-- end doc-content -->
    -     </div> <!-- end body-content --> 
    --<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    - </script>
    - <script type="text/javascript">
    -   try {
    -diff --git a/docs/html/sdk/support_api_diff/22.2.1/changes/pkg_android.support.v4.app.html b/docs/html/sdk/support_api_diff/22.2.1/changes/pkg_android.support.v4.app.html
    -index 1d15399..3122461 100644
    ---- a/docs/html/sdk/support_api_diff/22.2.1/changes/pkg_android.support.v4.app.html
    -+++ b/docs/html/sdk/support_api_diff/22.2.1/changes/pkg_android.support.v4.app.html
    -@@ -119,7 +119,7 @@ Package <A HREF="../../../../reference/android/support/v4/app/package-summary.ht
    -     </div> <!-- end footer -->
    -     </div><!-- end doc-content -->
    -     </div> <!-- end body-content --> 
    --<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    - </script>
    - <script type="text/javascript">
    -   try {
    -diff --git a/docs/html/sdk/support_api_diff/22.2.1/changes/pkg_android.support.v7.app.html b/docs/html/sdk/support_api_diff/22.2.1/changes/pkg_android.support.v7.app.html
    -index 47c0894..5f69310 100644
    ---- a/docs/html/sdk/support_api_diff/22.2.1/changes/pkg_android.support.v7.app.html
    -+++ b/docs/html/sdk/support_api_diff/22.2.1/changes/pkg_android.support.v7.app.html
    -@@ -119,7 +119,7 @@ Package <A HREF="../../../../reference/android/support/v7/app/package-summary.ht
    -     </div> <!-- end footer -->
    -     </div><!-- end doc-content -->
    -     </div> <!-- end body-content --> 
    --<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    - </script>
    - <script type="text/javascript">
    -   try {
    -diff --git a/docs/html/sdk/support_api_diff/22.2.1/changes/pkg_android.support.v7.appcompat.html b/docs/html/sdk/support_api_diff/22.2.1/changes/pkg_android.support.v7.appcompat.html
    -index 4c562ae..00bcf19 100644
    ---- a/docs/html/sdk/support_api_diff/22.2.1/changes/pkg_android.support.v7.appcompat.html
    -+++ b/docs/html/sdk/support_api_diff/22.2.1/changes/pkg_android.support.v7.appcompat.html
    -@@ -161,7 +161,7 @@ Package <A HREF="../../../../reference/android/support/v7/appcompat/package-summ
    -     </div> <!-- end footer -->
    -     </div><!-- end doc-content -->
    -     </div> <!-- end body-content --> 
    --<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    - </script>
    - <script type="text/javascript">
    -   try {
    -diff --git a/docs/html/sdk/support_api_diff/22.2.1/changes/pkg_android.support.v7.util.html b/docs/html/sdk/support_api_diff/22.2.1/changes/pkg_android.support.v7.util.html
    -index bac0313..e0f4bcd 100644
    ---- a/docs/html/sdk/support_api_diff/22.2.1/changes/pkg_android.support.v7.util.html
    -+++ b/docs/html/sdk/support_api_diff/22.2.1/changes/pkg_android.support.v7.util.html
    -@@ -105,7 +105,7 @@ Package <A HREF="../../../../reference/android/support/v7/util/package-summary.h
    -     </div> <!-- end footer -->
    -     </div><!-- end doc-content -->
    -     </div> <!-- end body-content --> 
    --<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    - </script>
    - <script type="text/javascript">
    -   try {
    -diff --git a/docs/html/sdk/support_api_diff/23.1.0/changes/alldiffs_index_additions.html b/docs/html/sdk/support_api_diff/23.1.0/changes/alldiffs_index_additions.html
    -index 5495f89..1717f7d 100644
    ---- a/docs/html/sdk/support_api_diff/23.1.0/changes/alldiffs_index_additions.html
    -+++ b/docs/html/sdk/support_api_diff/23.1.0/changes/alldiffs_index_additions.html
    -@@ -1104,7 +1104,7 @@ Listed as: <span style="color:#069"><strong>Added</strong></span>,  <span style=
    - <!-- Field Widget_AppCompat_SeekBar -->
    - <nobr><A HREF="android.support.v7.appcompat.R.style.html#android.support.v7.appcompat.R.style.Widget_AppCompat_SeekBar" class="hiddenlink" target="rightframe">Widget_AppCompat_SeekBar</A>
    - </nobr><br>
    --<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    - </script>
    - <script type="text/javascript">
    -   try {
    -diff --git a/docs/html/sdk/support_api_diff/23.1.0/changes/alldiffs_index_all.html b/docs/html/sdk/support_api_diff/23.1.0/changes/alldiffs_index_all.html
    -index 575ee95..d4c30e3 100644
    ---- a/docs/html/sdk/support_api_diff/23.1.0/changes/alldiffs_index_all.html
    -+++ b/docs/html/sdk/support_api_diff/23.1.0/changes/alldiffs_index_all.html
    -@@ -1511,7 +1511,7 @@ Listed as: <span style="color:#069"><strong>Added</strong></span>,  <span style=
    - <!-- Field Widget_AppCompat_SeekBar -->
    - <nobr><A HREF="android.support.v7.appcompat.R.style.html#android.support.v7.appcompat.R.style.Widget_AppCompat_SeekBar" class="hiddenlink" target="rightframe">Widget_AppCompat_SeekBar</A>
    - </nobr><br>
    --<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    - </script>
    - <script type="text/javascript">
    -   try {
    -diff --git a/docs/html/sdk/support_api_diff/23.1.0/changes/alldiffs_index_changes.html b/docs/html/sdk/support_api_diff/23.1.0/changes/alldiffs_index_changes.html
    -index d7ebd36..6562fa8 100644
    ---- a/docs/html/sdk/support_api_diff/23.1.0/changes/alldiffs_index_changes.html
    -+++ b/docs/html/sdk/support_api_diff/23.1.0/changes/alldiffs_index_changes.html
    -@@ -548,7 +548,7 @@ Listed as: <span style="color:#069"><strong>Added</strong></span>,  <span style=
    - <A HREF="android.support.v17.leanback.app.VerticalGridSupportFragment.html" class="hiddenlink" target="rightframe">VerticalGridSupportFragment</A><br>
    - <!-- Class ViewCompat -->
    - <A HREF="android.support.v4.view.ViewCompat.html" class="hiddenlink" target="rightframe">ViewCompat</A><br>
    --<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    - </script>
    - <script type="text/javascript">
    -   try {
    -diff --git a/docs/html/sdk/support_api_diff/23.1.0/changes/alldiffs_index_removals.html b/docs/html/sdk/support_api_diff/23.1.0/changes/alldiffs_index_removals.html
    -index 0d7da0f..9b21b1d 100644
    ---- a/docs/html/sdk/support_api_diff/23.1.0/changes/alldiffs_index_removals.html
    -+++ b/docs/html/sdk/support_api_diff/23.1.0/changes/alldiffs_index_removals.html
    -@@ -270,7 +270,7 @@ Listed as: <span style="color:#069"><strong>Added</strong></span>,  <span style=
    - <p><div style="line-height:1.5em;color:black">
    - <nobr><A HREF="android.support.v17.leanback.app.GuidedStepFragment.html#android.support.v17.leanback.app.GuidedStepFragment.setEntryTransitionEnabled_removed(boolean)" class="hiddenlink" target="rightframe"><strike>setEntryTransitionEnabled</strike>
    - (<code>boolean</code>)</A></nobr><br>
    --<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    - </script>
    - <script type="text/javascript">
    -   try {
    -diff --git a/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.customtabs.CustomTabsCallback.html b/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.customtabs.CustomTabsCallback.html
    -index 0466d5d..6ba5f83 100644
    ---- a/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.customtabs.CustomTabsCallback.html
    -+++ b/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.customtabs.CustomTabsCallback.html
    -@@ -115,7 +115,7 @@ Class android.support.customtabs.<A HREF="../../../../reference/android/support/
    -     </div> <!-- end footer -->
    -     </div><!-- end doc-content -->
    -     </div> <!-- end body-content --> 
    --<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    - </script>
    - <script type="text/javascript">
    -   try {
    -diff --git a/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.customtabs.CustomTabsIntent.Builder.html b/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.customtabs.CustomTabsIntent.Builder.html
    -index e3aefb5..c53722b 100644
    ---- a/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.customtabs.CustomTabsIntent.Builder.html
    -+++ b/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.customtabs.CustomTabsIntent.Builder.html
    -@@ -115,7 +115,7 @@ Class android.support.customtabs.<A HREF="../../../../reference/android/support/
    -     </div> <!-- end footer -->
    -     </div><!-- end doc-content -->
    -     </div> <!-- end body-content --> 
    --<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    - </script>
    - <script type="text/javascript">
    -   try {
    -diff --git a/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.customtabs.CustomTabsIntent.html b/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.customtabs.CustomTabsIntent.html
    -index 9312755..db59258 100644
    ---- a/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.customtabs.CustomTabsIntent.html
    -+++ b/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.customtabs.CustomTabsIntent.html
    -@@ -115,7 +115,7 @@ Class android.support.customtabs.<A HREF="../../../../reference/android/support/
    -     </div> <!-- end footer -->
    -     </div><!-- end doc-content -->
    -     </div> <!-- end body-content --> 
    --<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    - </script>
    - <script type="text/javascript">
    -   try {
    -diff --git a/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.customtabs.CustomTabsService.html b/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.customtabs.CustomTabsService.html
    -index 2a0fd18..fd5a12b 100644
    ---- a/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.customtabs.CustomTabsService.html
    -+++ b/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.customtabs.CustomTabsService.html
    -@@ -108,7 +108,7 @@ Class android.support.customtabs.<A HREF="../../../../reference/android/support/
    -     </div> <!-- end footer -->
    -     </div><!-- end doc-content -->
    -     </div> <!-- end body-content --> 
    --<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    - </script>
    - <script type="text/javascript">
    -   try {
    -diff --git a/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.customtabs.CustomTabsSession.html b/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.customtabs.CustomTabsSession.html
    -index 6b70224..6910bab 100644
    ---- a/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.customtabs.CustomTabsSession.html
    -+++ b/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.customtabs.CustomTabsSession.html
    -@@ -108,7 +108,7 @@ Class android.support.customtabs.<A HREF="../../../../reference/android/support/
    -     </div> <!-- end footer -->
    -     </div><!-- end doc-content -->
    -     </div> <!-- end body-content --> 
    --<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    - </script>
    - <script type="text/javascript">
    -   try {
    -diff --git a/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.customtabs.CustomTabsSessionToken.html b/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.customtabs.CustomTabsSessionToken.html
    -index 2bdb42e..0282d49 100644
    ---- a/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.customtabs.CustomTabsSessionToken.html
    -+++ b/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.customtabs.CustomTabsSessionToken.html
    -@@ -108,7 +108,7 @@ Class android.support.customtabs.<A HREF="../../../../reference/android/support/
    -     </div> <!-- end footer -->
    -     </div><!-- end doc-content -->
    -     </div> <!-- end body-content --> 
    --<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    - </script>
    - <script type="text/javascript">
    -   try {
    -diff --git a/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.design.widget.AppBarLayout.Behavior.SavedState.html b/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.design.widget.AppBarLayout.Behavior.SavedState.html
    -index bb89bbd..cea16c0 100644
    ---- a/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.design.widget.AppBarLayout.Behavior.SavedState.html
    -+++ b/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.design.widget.AppBarLayout.Behavior.SavedState.html
    -@@ -123,7 +123,7 @@ Class android.support.design.widget.<A HREF="../../../../reference/android/suppo
    -     </div> <!-- end footer -->
    -     </div><!-- end doc-content -->
    -     </div> <!-- end body-content --> 
    --<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    - </script>
    - <script type="text/javascript">
    -   try {
    -diff --git a/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.design.widget.AppBarLayout.Behavior.html b/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.design.widget.AppBarLayout.Behavior.html
    -index b538999a..672951d 100644
    ---- a/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.design.widget.AppBarLayout.Behavior.html
    -+++ b/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.design.widget.AppBarLayout.Behavior.html
    -@@ -131,7 +131,7 @@ Class android.support.design.widget.<A HREF="../../../../reference/android/suppo
    -     </div> <!-- end footer -->
    -     </div><!-- end doc-content -->
    -     </div> <!-- end body-content --> 
    --<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    - </script>
    - <script type="text/javascript">
    -   try {
    -diff --git a/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.design.widget.AppBarLayout.LayoutParams.html b/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.design.widget.AppBarLayout.LayoutParams.html
    -index 6d19d36..0218c30 100644
    ---- a/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.design.widget.AppBarLayout.LayoutParams.html
    -+++ b/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.design.widget.AppBarLayout.LayoutParams.html
    -@@ -108,7 +108,7 @@ Class android.support.design.widget.<A HREF="../../../../reference/android/suppo
    -     </div> <!-- end footer -->
    -     </div><!-- end doc-content -->
    -     </div> <!-- end body-content --> 
    --<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    - </script>
    - <script type="text/javascript">
    -   try {
    -diff --git a/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.design.widget.AppBarLayout.ScrollingViewBehavior.html b/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.design.widget.AppBarLayout.ScrollingViewBehavior.html
    -index c089db3..424a618 100644
    ---- a/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.design.widget.AppBarLayout.ScrollingViewBehavior.html
    -+++ b/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.design.widget.AppBarLayout.ScrollingViewBehavior.html
    -@@ -124,7 +124,7 @@ Class android.support.design.widget.<A HREF="../../../../reference/android/suppo
    -     </div> <!-- end footer -->
    -     </div><!-- end doc-content -->
    -     </div> <!-- end body-content --> 
    --<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    - </script>
    - <script type="text/javascript">
    -   try {
    -diff --git a/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.design.widget.CollapsingToolbarLayout.html b/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.design.widget.CollapsingToolbarLayout.html
    -index 49d92737..8e708c0 100644
    ---- a/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.design.widget.CollapsingToolbarLayout.html
    -+++ b/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.design.widget.CollapsingToolbarLayout.html
    -@@ -143,7 +143,7 @@ Class android.support.design.widget.<A HREF="../../../../reference/android/suppo
    -     </div> <!-- end footer -->
    -     </div><!-- end doc-content -->
    -     </div> <!-- end body-content --> 
    --<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    - </script>
    - <script type="text/javascript">
    -   try {
    -diff --git a/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.design.widget.CoordinatorLayout.SavedState.html b/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.design.widget.CoordinatorLayout.SavedState.html
    -index f92babd..496a460 100644
    ---- a/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.design.widget.CoordinatorLayout.SavedState.html
    -+++ b/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.design.widget.CoordinatorLayout.SavedState.html
    -@@ -123,7 +123,7 @@ Class android.support.design.widget.<A HREF="../../../../reference/android/suppo
    -     </div> <!-- end footer -->
    -     </div><!-- end doc-content -->
    -     </div> <!-- end body-content --> 
    --<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    - </script>
    - <script type="text/javascript">
    -   try {
    -diff --git a/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.design.widget.FloatingActionButton.Behavior.html b/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.design.widget.FloatingActionButton.Behavior.html
    -index 07fdda1..eba4247 100644
    ---- a/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.design.widget.FloatingActionButton.Behavior.html
    -+++ b/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.design.widget.FloatingActionButton.Behavior.html
    -@@ -108,7 +108,7 @@ Class android.support.design.widget.<A HREF="../../../../reference/android/suppo
    -     </div> <!-- end footer -->
    -     </div><!-- end doc-content -->
    -     </div> <!-- end body-content --> 
    --<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    - </script>
    - <script type="text/javascript">
    -   try {
    -diff --git a/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.design.widget.FloatingActionButton.html b/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.design.widget.FloatingActionButton.html
    -index 90553fa..520fdcf 100644
    ---- a/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.design.widget.FloatingActionButton.html
    -+++ b/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.design.widget.FloatingActionButton.html
    -@@ -116,7 +116,7 @@ Class android.support.design.widget.<A HREF="../../../../reference/android/suppo
    -     </div> <!-- end footer -->
    -     </div><!-- end doc-content -->
    -     </div> <!-- end body-content --> 
    --<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    - </script>
    - <script type="text/javascript">
    -   try {
    -diff --git a/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.design.widget.NavigationView.SavedState.html b/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.design.widget.NavigationView.SavedState.html
    -index 8a9ae80..61428ca 100644
    ---- a/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.design.widget.NavigationView.SavedState.html
    -+++ b/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.design.widget.NavigationView.SavedState.html
    -@@ -123,7 +123,7 @@ Class android.support.design.widget.<A HREF="../../../../reference/android/suppo
    -     </div> <!-- end footer -->
    -     </div><!-- end doc-content -->
    -     </div> <!-- end body-content --> 
    --<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    - </script>
    - <script type="text/javascript">
    -   try {
    -diff --git a/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.design.widget.Snackbar.html b/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.design.widget.Snackbar.html
    -index d741863..f33e47a 100644
    ---- a/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.design.widget.Snackbar.html
    -+++ b/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.design.widget.Snackbar.html
    -@@ -108,7 +108,7 @@ Class android.support.design.widget.<A HREF="../../../../reference/android/suppo
    -     </div> <!-- end footer -->
    -     </div><!-- end doc-content -->
    -     </div> <!-- end body-content --> 
    --<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    - </script>
    - <script type="text/javascript">
    -   try {
    -diff --git a/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.design.widget.TextInputLayout.html b/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.design.widget.TextInputLayout.html
    -index 30d0dd6..609e864 100644
    ---- a/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.design.widget.TextInputLayout.html
    -+++ b/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.design.widget.TextInputLayout.html
    -@@ -129,7 +129,7 @@ Class android.support.design.widget.<A HREF="../../../../reference/android/suppo
    -     </div> <!-- end footer -->
    -     </div><!-- end doc-content -->
    -     </div> <!-- end body-content --> 
    --<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    - </script>
    - <script type="text/javascript">
    -   try {
    -diff --git a/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.percent.PercentLayoutHelper.PercentLayoutInfo.html b/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.percent.PercentLayoutHelper.PercentLayoutInfo.html
    -index b6f2e48..967542f 100644
    ---- a/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.percent.PercentLayoutHelper.PercentLayoutInfo.html
    -+++ b/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.percent.PercentLayoutHelper.PercentLayoutInfo.html
    -@@ -108,7 +108,7 @@ Class android.support.percent.<A HREF="../../../../reference/android/support/per
    -     </div> <!-- end footer -->
    -     </div><!-- end doc-content -->
    -     </div> <!-- end body-content --> 
    --<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    - </script>
    - <script type="text/javascript">
    -   try {
    -diff --git a/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v14.preference.EditTextPreferenceDialogFragment.html b/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v14.preference.EditTextPreferenceDialogFragment.html
    -index 30f22a8..6b6151b 100644
    ---- a/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v14.preference.EditTextPreferenceDialogFragment.html
    -+++ b/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v14.preference.EditTextPreferenceDialogFragment.html
    -@@ -108,7 +108,7 @@ Class android.support.v14.preference.<A HREF="../../../../reference/android/supp
    -     </div> <!-- end footer -->
    -     </div><!-- end doc-content -->
    -     </div> <!-- end body-content --> 
    --<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    - </script>
    - <script type="text/javascript">
    -   try {
    -diff --git a/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v17.leanback.app.BrowseFragment.html b/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v17.leanback.app.BrowseFragment.html
    -index f4d77bf..14f6fdf 100644
    ---- a/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v17.leanback.app.BrowseFragment.html
    -+++ b/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v17.leanback.app.BrowseFragment.html
    -@@ -150,7 +150,7 @@ Class android.support.v17.leanback.app.<A HREF="../../../../reference/android/su
    -     </div> <!-- end footer -->
    -     </div><!-- end doc-content -->
    -     </div> <!-- end body-content --> 
    --<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    - </script>
    - <script type="text/javascript">
    -   try {
    -diff --git a/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v17.leanback.app.BrowseSupportFragment.html b/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v17.leanback.app.BrowseSupportFragment.html
    -index a48ea3b..7adcbe8 100644
    ---- a/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v17.leanback.app.BrowseSupportFragment.html
    -+++ b/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v17.leanback.app.BrowseSupportFragment.html
    -@@ -150,7 +150,7 @@ Class android.support.v17.leanback.app.<A HREF="../../../../reference/android/su
    -     </div> <!-- end footer -->
    -     </div><!-- end doc-content -->
    -     </div> <!-- end body-content --> 
    --<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    - </script>
    - <script type="text/javascript">
    -   try {
    -diff --git a/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v17.leanback.app.DetailsFragment.html b/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v17.leanback.app.DetailsFragment.html
    -index d38127c..2240f4e 100644
    ---- a/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v17.leanback.app.DetailsFragment.html
    -+++ b/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v17.leanback.app.DetailsFragment.html
    -@@ -143,7 +143,7 @@ Class android.support.v17.leanback.app.<A HREF="../../../../reference/android/su
    -     </div> <!-- end footer -->
    -     </div><!-- end doc-content -->
    -     </div> <!-- end body-content --> 
    --<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    - </script>
    - <script type="text/javascript">
    -   try {
    -diff --git a/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v17.leanback.app.DetailsSupportFragment.html b/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v17.leanback.app.DetailsSupportFragment.html
    -index a02b8f3..23ca151 100644
    ---- a/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v17.leanback.app.DetailsSupportFragment.html
    -+++ b/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v17.leanback.app.DetailsSupportFragment.html
    -@@ -143,7 +143,7 @@ Class android.support.v17.leanback.app.<A HREF="../../../../reference/android/su
    -     </div> <!-- end footer -->
    -     </div><!-- end doc-content -->
    -     </div> <!-- end body-content --> 
    --<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    - </script>
    - <script type="text/javascript">
    -   try {
    -diff --git a/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v17.leanback.app.GuidedStepFragment.html b/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v17.leanback.app.GuidedStepFragment.html
    -index 725281a..4c78b30 100644
    ---- a/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v17.leanback.app.GuidedStepFragment.html
    -+++ b/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v17.leanback.app.GuidedStepFragment.html
    -@@ -215,7 +215,7 @@ Class android.support.v17.leanback.app.<A HREF="../../../../reference/android/su
    -     </div> <!-- end footer -->
    -     </div><!-- end doc-content -->
    -     </div> <!-- end body-content --> 
    --<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    - </script>
    - <script type="text/javascript">
    -   try {
    -diff --git a/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v17.leanback.app.PlaybackOverlayFragment.html b/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v17.leanback.app.PlaybackOverlayFragment.html
    -index 71e230b..ecb35be 100644
    ---- a/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v17.leanback.app.PlaybackOverlayFragment.html
    -+++ b/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v17.leanback.app.PlaybackOverlayFragment.html
    -@@ -115,7 +115,7 @@ Class android.support.v17.leanback.app.<A HREF="../../../../reference/android/su
    -     </div> <!-- end footer -->
    -     </div><!-- end doc-content -->
    -     </div> <!-- end body-content --> 
    --<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    - </script>
    - <script type="text/javascript">
    -   try {
    -diff --git a/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v17.leanback.app.PlaybackOverlaySupportFragment.html b/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v17.leanback.app.PlaybackOverlaySupportFragment.html
    -index a794f14..1809374 100644
    ---- a/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v17.leanback.app.PlaybackOverlaySupportFragment.html
    -+++ b/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v17.leanback.app.PlaybackOverlaySupportFragment.html
    -@@ -115,7 +115,7 @@ Class android.support.v17.leanback.app.<A HREF="../../../../reference/android/su
    -     </div> <!-- end footer -->
    -     </div><!-- end doc-content -->
    -     </div> <!-- end body-content --> 
    --<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    - </script>
    - <script type="text/javascript">
    -   try {
    -diff --git a/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v17.leanback.app.SearchFragment.html b/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v17.leanback.app.SearchFragment.html
    -index 827f46b..2c444ae 100644
    ---- a/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v17.leanback.app.SearchFragment.html
    -+++ b/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v17.leanback.app.SearchFragment.html
    -@@ -108,7 +108,7 @@ Class android.support.v17.leanback.app.<A HREF="../../../../reference/android/su
    -     </div> <!-- end footer -->
    -     </div><!-- end doc-content -->
    -     </div> <!-- end body-content --> 
    --<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    - </script>
    - <script type="text/javascript">
    -   try {
    -diff --git a/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v17.leanback.app.SearchSupportFragment.html b/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v17.leanback.app.SearchSupportFragment.html
    -index f1e2826..7ff0204 100644
    ---- a/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v17.leanback.app.SearchSupportFragment.html
    -+++ b/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v17.leanback.app.SearchSupportFragment.html
    -@@ -108,7 +108,7 @@ Class android.support.v17.leanback.app.<A HREF="../../../../reference/android/su
    -     </div> <!-- end footer -->
    -     </div><!-- end doc-content -->
    -     </div> <!-- end body-content --> 
    --<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    - </script>
    - <script type="text/javascript">
    -   try {
    -diff --git a/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v17.leanback.app.VerticalGridFragment.html b/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v17.leanback.app.VerticalGridFragment.html
    -index 01bb4de..5516bda 100644
    ---- a/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v17.leanback.app.VerticalGridFragment.html
    -+++ b/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v17.leanback.app.VerticalGridFragment.html
    -@@ -137,7 +137,7 @@ Class android.support.v17.leanback.app.<A HREF="../../../../reference/android/su
    -     </div> <!-- end footer -->
    -     </div><!-- end doc-content -->
    -     </div> <!-- end body-content --> 
    --<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    - </script>
    - <script type="text/javascript">
    -   try {
    -diff --git a/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v17.leanback.app.VerticalGridSupportFragment.html b/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v17.leanback.app.VerticalGridSupportFragment.html
    -index a818a79..0f09ec0 100644
    ---- a/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v17.leanback.app.VerticalGridSupportFragment.html
    -+++ b/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v17.leanback.app.VerticalGridSupportFragment.html
    -@@ -154,7 +154,7 @@ Method was inherited from <code>android.support.v4.app.Fragment</code>, but is n
    -     </div> <!-- end footer -->
    -     </div><!-- end doc-content -->
    -     </div> <!-- end body-content --> 
    --<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    - </script>
    - <script type="text/javascript">
    -   try {
    -diff --git a/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v17.leanback.widget.FragmentAnimationProvider.html b/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v17.leanback.widget.FragmentAnimationProvider.html
    -index 1cf004d..e457402 100644
    ---- a/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v17.leanback.widget.FragmentAnimationProvider.html
    -+++ b/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v17.leanback.widget.FragmentAnimationProvider.html
    -@@ -165,7 +165,7 @@ Interface android.support.v17.leanback.widget.<A HREF="../../../../reference/and
    -     </div> <!-- end footer -->
    -     </div><!-- end doc-content -->
    -     </div> <!-- end body-content --> 
    --<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    - </script>
    - <script type="text/javascript">
    -   try {
    -diff --git a/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v17.leanback.widget.GuidanceStylist.html b/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v17.leanback.widget.GuidanceStylist.html
    -index e0b94bc..9794929 100644
    ---- a/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v17.leanback.widget.GuidanceStylist.html
    -+++ b/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v17.leanback.widget.GuidanceStylist.html
    -@@ -165,7 +165,7 @@ Class android.support.v17.leanback.widget.<A HREF="../../../../reference/android
    -     </div> <!-- end footer -->
    -     </div><!-- end doc-content -->
    -     </div> <!-- end body-content --> 
    --<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    - </script>
    - <script type="text/javascript">
    -   try {
    -diff --git a/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v17.leanback.widget.GuidedAction.Builder.html b/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v17.leanback.widget.GuidedAction.Builder.html
    -index 96d30a4..3408bd9 100644
    ---- a/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v17.leanback.widget.GuidedAction.Builder.html
    -+++ b/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v17.leanback.widget.GuidedAction.Builder.html
    -@@ -115,7 +115,7 @@ Class android.support.v17.leanback.widget.<A HREF="../../../../reference/android
    -     </div> <!-- end footer -->
    -     </div><!-- end doc-content -->
    -     </div> <!-- end body-content --> 
    --<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    - </script>
    - <script type="text/javascript">
    -   try {
    -diff --git a/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v17.leanback.widget.GuidedAction.html b/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v17.leanback.widget.GuidedAction.html
    -index 84b93bf..857b7d8 100644
    ---- a/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v17.leanback.widget.GuidedAction.html
    -+++ b/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v17.leanback.widget.GuidedAction.html
    -@@ -143,7 +143,7 @@ Class android.support.v17.leanback.widget.<A HREF="../../../../reference/android
    -     </div> <!-- end footer -->
    -     </div><!-- end doc-content -->
    -     </div> <!-- end body-content --> 
    --<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    - </script>
    - <script type="text/javascript">
    -   try {
    -diff --git a/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v17.leanback.widget.GuidedActionsStylist.ViewHolder.html b/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v17.leanback.widget.GuidedActionsStylist.ViewHolder.html
    -index 38e83b4..497e985 100644
    ---- a/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v17.leanback.widget.GuidedActionsStylist.ViewHolder.html
    -+++ b/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v17.leanback.widget.GuidedActionsStylist.ViewHolder.html
    -@@ -108,7 +108,7 @@ Class android.support.v17.leanback.widget.<A HREF="../../../../reference/android
    -     </div> <!-- end footer -->
    -     </div><!-- end doc-content -->
    -     </div> <!-- end body-content --> 
    --<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    - </script>
    - <script type="text/javascript">
    -   try {
    -diff --git a/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v17.leanback.widget.GuidedActionsStylist.html b/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v17.leanback.widget.GuidedActionsStylist.html
    -index 104f325..cd45d6d 100644
    ---- a/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v17.leanback.widget.GuidedActionsStylist.html
    -+++ b/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v17.leanback.widget.GuidedActionsStylist.html
    -@@ -165,7 +165,7 @@ Class android.support.v17.leanback.widget.<A HREF="../../../../reference/android
    -     </div> <!-- end footer -->
    -     </div><!-- end doc-content -->
    -     </div> <!-- end body-content --> 
    --<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    - </script>
    - <script type="text/javascript">
    -   try {
    -diff --git a/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v17.leanback.widget.ImageCardView.html b/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v17.leanback.widget.ImageCardView.html
    -index 1535ca0..a5aa07e 100644
    ---- a/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v17.leanback.widget.ImageCardView.html
    -+++ b/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v17.leanback.widget.ImageCardView.html
    -@@ -151,7 +151,7 @@ Class android.support.v17.leanback.widget.<A HREF="../../../../reference/android
    -     </div> <!-- end footer -->
    -     </div><!-- end doc-content -->
    -     </div> <!-- end body-content --> 
    --<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    - </script>
    - <script type="text/javascript">
    -   try {
    -diff --git a/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v17.leanback.widget.ListRowPresenter.html b/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v17.leanback.widget.ListRowPresenter.html
    -index f536d92..11b95c4 100644
    ---- a/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v17.leanback.widget.ListRowPresenter.html
    -+++ b/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v17.leanback.widget.ListRowPresenter.html
    -@@ -122,7 +122,7 @@ Class android.support.v17.leanback.widget.<A HREF="../../../../reference/android
    -     </div> <!-- end footer -->
    -     </div><!-- end doc-content -->
    -     </div> <!-- end body-content --> 
    --<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    - </script>
    - <script type="text/javascript">
    -   try {
    -diff --git a/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v17.leanback.widget.RowPresenter.html b/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v17.leanback.widget.RowPresenter.html
    -index 3f10b29..0f254d7 100644
    ---- a/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v17.leanback.widget.RowPresenter.html
    -+++ b/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v17.leanback.widget.RowPresenter.html
    -@@ -108,7 +108,7 @@ Class android.support.v17.leanback.widget.<A HREF="../../../../reference/android
    -     </div> <!-- end footer -->
    -     </div><!-- end doc-content -->
    -     </div> <!-- end body-content --> 
    --<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    - </script>
    - <script type="text/javascript">
    -   try {
    -diff --git a/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v17.leanback.widget.SearchBar.html b/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v17.leanback.widget.SearchBar.html
    -index 2965c15..6e4b41c 100644
    ---- a/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v17.leanback.widget.SearchBar.html
    -+++ b/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v17.leanback.widget.SearchBar.html
    -@@ -108,7 +108,7 @@ Class android.support.v17.leanback.widget.<A HREF="../../../../reference/android
    -     </div> <!-- end footer -->
    -     </div><!-- end doc-content -->
    -     </div> <!-- end body-content --> 
    --<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    - </script>
    - <script type="text/javascript">
    -   try {
    -diff --git a/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v17.leanback.widget.ShadowOverlayContainer.html b/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v17.leanback.widget.ShadowOverlayContainer.html
    -index 761fd92..553bbb1 100644
    ---- a/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v17.leanback.widget.ShadowOverlayContainer.html
    -+++ b/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v17.leanback.widget.ShadowOverlayContainer.html
    -@@ -127,7 +127,7 @@ Class android.support.v17.leanback.widget.<A HREF="../../../../reference/android
    -     </div> <!-- end footer -->
    -     </div><!-- end doc-content -->
    -     </div> <!-- end body-content --> 
    --<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    - </script>
    - <script type="text/javascript">
    -   try {
    -diff --git a/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v17.leanback.widget.VerticalGridPresenter.html b/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v17.leanback.widget.VerticalGridPresenter.html
    -index e999838..f1d6fb6 100644
    ---- a/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v17.leanback.widget.VerticalGridPresenter.html
    -+++ b/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v17.leanback.widget.VerticalGridPresenter.html
    -@@ -129,7 +129,7 @@ Class android.support.v17.leanback.widget.<A HREF="../../../../reference/android
    -     </div> <!-- end footer -->
    -     </div><!-- end doc-content -->
    -     </div> <!-- end body-content --> 
    --<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    - </script>
    - <script type="text/javascript">
    -   try {
    -diff --git a/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v4.app.FragmentActivity.html b/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v4.app.FragmentActivity.html
    -index c68356c..dd88aca 100644
    ---- a/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v4.app.FragmentActivity.html
    -+++ b/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v4.app.FragmentActivity.html
    -@@ -115,7 +115,7 @@ Class android.support.v4.app.<A HREF="../../../../reference/android/support/v4/a
    -     </div> <!-- end footer -->
    -     </div><!-- end doc-content -->
    -     </div> <!-- end body-content --> 
    --<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    - </script>
    - <script type="text/javascript">
    -   try {
    -diff --git a/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v4.content.res.ResourcesCompat.html b/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v4.content.res.ResourcesCompat.html
    -index 9bdd4f7..bb339da 100644
    ---- a/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v4.content.res.ResourcesCompat.html
    -+++ b/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v4.content.res.ResourcesCompat.html
    -@@ -115,7 +115,7 @@ Class android.support.v4.content.res.<A HREF="../../../../reference/android/supp
    -     </div> <!-- end footer -->
    -     </div><!-- end doc-content -->
    -     </div> <!-- end body-content --> 
    --<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    - </script>
    - <script type="text/javascript">
    -   try {
    -diff --git a/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v4.media.session.MediaSessionCompat.html b/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v4.media.session.MediaSessionCompat.html
    -index 5b5f1e3..278f42d 100644
    ---- a/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v4.media.session.MediaSessionCompat.html
    -+++ b/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v4.media.session.MediaSessionCompat.html
    -@@ -108,7 +108,7 @@ Class android.support.v4.media.session.<A HREF="../../../../reference/android/su
    -     </div> <!-- end footer -->
    -     </div><!-- end doc-content -->
    -     </div> <!-- end body-content --> 
    --<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    - </script>
    - <script type="text/javascript">
    -   try {
    -diff --git a/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v4.view.ViewCompat.html b/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v4.view.ViewCompat.html
    -index 2e39745..03dda58 100644
    ---- a/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v4.view.ViewCompat.html
    -+++ b/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v4.view.ViewCompat.html
    -@@ -179,7 +179,7 @@ Class android.support.v4.view.<A HREF="../../../../reference/android/support/v4/
    -     </div> <!-- end footer -->
    -     </div><!-- end doc-content -->
    -     </div> <!-- end body-content --> 
    --<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    - </script>
    - <script type="text/javascript">
    -   try {
    -diff --git a/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v4.widget.NestedScrollView.html b/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v4.widget.NestedScrollView.html
    -index 8d4cbaa..cdb3d13 100644
    ---- a/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v4.widget.NestedScrollView.html
    -+++ b/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v4.widget.NestedScrollView.html
    -@@ -109,7 +109,7 @@ Class android.support.v4.widget.<A HREF="../../../../reference/android/support/v
    -     </div> <!-- end footer -->
    -     </div><!-- end doc-content -->
    -     </div> <!-- end body-content --> 
    --<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    - </script>
    - <script type="text/javascript">
    -   try {
    -diff --git a/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v4.widget.ScrollerCompat.html b/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v4.widget.ScrollerCompat.html
    -index 7f47eae..9ef847e 100644
    ---- a/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v4.widget.ScrollerCompat.html
    -+++ b/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v4.widget.ScrollerCompat.html
    -@@ -108,7 +108,7 @@ Class android.support.v4.widget.<A HREF="../../../../reference/android/support/v
    -     </div> <!-- end footer -->
    -     </div><!-- end doc-content -->
    -     </div> <!-- end body-content --> 
    --<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    - </script>
    - <script type="text/javascript">
    -   try {
    -diff --git a/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v4.widget.TextViewCompat.html b/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v4.widget.TextViewCompat.html
    -index 3641625..87b1da2 100644
    ---- a/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v4.widget.TextViewCompat.html
    -+++ b/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v4.widget.TextViewCompat.html
    -@@ -115,7 +115,7 @@ Class android.support.v4.widget.<A HREF="../../../../reference/android/support/v
    -     </div> <!-- end footer -->
    -     </div><!-- end doc-content -->
    -     </div> <!-- end body-content --> 
    --<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    - </script>
    - <script type="text/javascript">
    -   try {
    -diff --git a/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v7.appcompat.R.attr.html b/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v7.appcompat.R.attr.html
    -index dc6fce2..ef31519 100644
    ---- a/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v7.appcompat.R.attr.html
    -+++ b/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v7.appcompat.R.attr.html
    -@@ -122,7 +122,7 @@ Class android.support.v7.appcompat.<A HREF="../../../../reference/android/suppor
    -     </div> <!-- end footer -->
    -     </div><!-- end doc-content -->
    -     </div> <!-- end body-content --> 
    --<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    - </script>
    - <script type="text/javascript">
    -   try {
    -diff --git a/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v7.appcompat.R.bool.html b/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v7.appcompat.R.bool.html
    -index 973cf83..c26367a 100644
    ---- a/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v7.appcompat.R.bool.html
    -+++ b/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v7.appcompat.R.bool.html
    -@@ -108,7 +108,7 @@ Class android.support.v7.appcompat.<A HREF="../../../../reference/android/suppor
    -     </div> <!-- end footer -->
    -     </div><!-- end doc-content -->
    -     </div> <!-- end body-content --> 
    --<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    - </script>
    - <script type="text/javascript">
    -   try {
    -diff --git a/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v7.appcompat.R.dimen.html b/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v7.appcompat.R.dimen.html
    -index ca5fec2..bd324cb 100644
    ---- a/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v7.appcompat.R.dimen.html
    -+++ b/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v7.appcompat.R.dimen.html
    -@@ -186,7 +186,7 @@ Class android.support.v7.appcompat.<A HREF="../../../../reference/android/suppor
    -     </div> <!-- end footer -->
    -     </div><!-- end doc-content -->
    -     </div> <!-- end body-content --> 
    --<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    - </script>
    - <script type="text/javascript">
    -   try {
    -diff --git a/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v7.appcompat.R.drawable.html b/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v7.appcompat.R.drawable.html
    -index 3cfba65..c9264d6 100644
    ---- a/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v7.appcompat.R.drawable.html
    -+++ b/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v7.appcompat.R.drawable.html
    -@@ -157,7 +157,7 @@ Class android.support.v7.appcompat.<A HREF="../../../../reference/android/suppor
    -     </div> <!-- end footer -->
    -     </div><!-- end doc-content -->
    -     </div> <!-- end body-content --> 
    --<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    - </script>
    - <script type="text/javascript">
    -   try {
    -diff --git a/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v7.appcompat.R.id.html b/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v7.appcompat.R.id.html
    -index a25139d..e7f9f95 100644
    ---- a/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v7.appcompat.R.id.html
    -+++ b/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v7.appcompat.R.id.html
    -@@ -122,7 +122,7 @@ Class android.support.v7.appcompat.<A HREF="../../../../reference/android/suppor
    -     </div> <!-- end footer -->
    -     </div><!-- end doc-content -->
    -     </div> <!-- end body-content --> 
    --<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    - </script>
    - <script type="text/javascript">
    -   try {
    -diff --git a/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v7.appcompat.R.layout.html b/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v7.appcompat.R.layout.html
    -index 0b485ea..c04d4f7 100644
    ---- a/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v7.appcompat.R.layout.html
    -+++ b/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v7.appcompat.R.layout.html
    -@@ -108,7 +108,7 @@ Class android.support.v7.appcompat.<A HREF="../../../../reference/android/suppor
    -     </div> <!-- end footer -->
    -     </div><!-- end doc-content -->
    -     </div> <!-- end body-content --> 
    --<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    - </script>
    - <script type="text/javascript">
    -   try {
    -diff --git a/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v7.appcompat.R.string.html b/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v7.appcompat.R.string.html
    -index b5b32c7..9dc84ab 100644
    ---- a/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v7.appcompat.R.string.html
    -+++ b/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v7.appcompat.R.string.html
    -@@ -115,7 +115,7 @@ Class android.support.v7.appcompat.<A HREF="../../../../reference/android/suppor
    -     </div> <!-- end footer -->
    -     </div><!-- end doc-content -->
    -     </div> <!-- end body-content --> 
    --<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    - </script>
    - <script type="text/javascript">
    -   try {
    -diff --git a/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v7.appcompat.R.style.html b/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v7.appcompat.R.style.html
    -index a7b4e2d..58f9025 100644
    ---- a/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v7.appcompat.R.style.html
    -+++ b/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v7.appcompat.R.style.html
    -@@ -158,7 +158,7 @@ Class android.support.v7.appcompat.<A HREF="../../../../reference/android/suppor
    -     </div> <!-- end footer -->
    -     </div><!-- end doc-content -->
    -     </div> <!-- end body-content --> 
    --<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    - </script>
    - <script type="text/javascript">
    -   try {
    -diff --git a/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v7.appcompat.R.styleable.html b/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v7.appcompat.R.styleable.html
    -index 3f6d157..49adae8 100644
    ---- a/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v7.appcompat.R.styleable.html
    -+++ b/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v7.appcompat.R.styleable.html
    -@@ -150,7 +150,7 @@ Class android.support.v7.appcompat.<A HREF="../../../../reference/android/suppor
    -     </div> <!-- end footer -->
    -     </div><!-- end doc-content -->
    -     </div> <!-- end body-content --> 
    --<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    - </script>
    - <script type="text/javascript">
    -   try {
    -diff --git a/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v7.graphics.Palette.Builder.html b/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v7.graphics.Palette.Builder.html
    -index 03171fb..22ee483 100644
    ---- a/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v7.graphics.Palette.Builder.html
    -+++ b/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v7.graphics.Palette.Builder.html
    -@@ -115,7 +115,7 @@ Class android.support.v7.graphics.<A HREF="../../../../reference/android/support
    -     </div> <!-- end footer -->
    -     </div><!-- end doc-content -->
    -     </div> <!-- end body-content --> 
    --<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    - </script>
    - <script type="text/javascript">
    -   try {
    -diff --git a/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v7.graphics.drawable.DrawerArrowDrawable.html b/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v7.graphics.drawable.DrawerArrowDrawable.html
    -index ec3cb15..77232ba 100644
    ---- a/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v7.graphics.drawable.DrawerArrowDrawable.html
    -+++ b/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v7.graphics.drawable.DrawerArrowDrawable.html
    -@@ -108,7 +108,7 @@ Class android.support.v7.graphics.drawable.<A HREF="../../../../reference/androi
    -     </div> <!-- end footer -->
    -     </div><!-- end doc-content -->
    -     </div> <!-- end body-content --> 
    --<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    - </script>
    - <script type="text/javascript">
    -   try {
    -diff --git a/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v7.media.MediaRouteDescriptor.Builder.html b/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v7.media.MediaRouteDescriptor.Builder.html
    -index aec06c0..5cac372 100644
    ---- a/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v7.media.MediaRouteDescriptor.Builder.html
    -+++ b/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v7.media.MediaRouteDescriptor.Builder.html
    -@@ -154,7 +154,7 @@ Class android.support.v7.media.<A HREF="../../../../reference/android/support/v7
    -     </div> <!-- end footer -->
    -     </div><!-- end doc-content -->
    -     </div> <!-- end body-content --> 
    --<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    - </script>
    - <script type="text/javascript">
    -   try {
    -diff --git a/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v7.media.MediaRouteDescriptor.html b/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v7.media.MediaRouteDescriptor.html
    -index 381eb20..437c56d 100644
    ---- a/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v7.media.MediaRouteDescriptor.html
    -+++ b/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v7.media.MediaRouteDescriptor.html
    -@@ -147,7 +147,7 @@ Class android.support.v7.media.<A HREF="../../../../reference/android/support/v7
    -     </div> <!-- end footer -->
    -     </div><!-- end doc-content -->
    -     </div> <!-- end body-content --> 
    --<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    - </script>
    - <script type="text/javascript">
    -   try {
    -diff --git a/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v7.media.MediaRouter.RouteInfo.html b/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v7.media.MediaRouter.RouteInfo.html
    -index 239341d..51afa4f 100644
    ---- a/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v7.media.MediaRouter.RouteInfo.html
    -+++ b/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v7.media.MediaRouter.RouteInfo.html
    -@@ -166,7 +166,7 @@ Class android.support.v7.media.<A HREF="../../../../reference/android/support/v7
    -     </div> <!-- end footer -->
    -     </div><!-- end doc-content -->
    -     </div> <!-- end body-content --> 
    --<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    - </script>
    - <script type="text/javascript">
    -   try {
    -diff --git a/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v7.preference.EditTextPreferenceDialogFragmentCompat.html b/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v7.preference.EditTextPreferenceDialogFragmentCompat.html
    -index 05b65ff..ac63d53 100644
    ---- a/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v7.preference.EditTextPreferenceDialogFragmentCompat.html
    -+++ b/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v7.preference.EditTextPreferenceDialogFragmentCompat.html
    -@@ -108,7 +108,7 @@ Class android.support.v7.preference.<A HREF="../../../../reference/android/suppo
    -     </div> <!-- end footer -->
    -     </div><!-- end doc-content -->
    -     </div> <!-- end body-content --> 
    --<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    - </script>
    - <script type="text/javascript">
    -   try {
    -diff --git a/docs/html/sdk/support_api_diff/23.1.0/changes/changes-summary.html b/docs/html/sdk/support_api_diff/23.1.0/changes/changes-summary.html
    -index 728ade1..d9658ba 100644
    ---- a/docs/html/sdk/support_api_diff/23.1.0/changes/changes-summary.html
    -+++ b/docs/html/sdk/support_api_diff/23.1.0/changes/changes-summary.html
    -@@ -232,7 +232,7 @@ see the <a href="http://developer.android.com/index.html" target="_top">Android
    -     </div> <!-- end footer -->
    -     </div><!-- end doc-content -->
    -     </div> <!-- end body-content --> 
    --<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    - </script>
    - <script type="text/javascript">
    -   try {
    -diff --git a/docs/html/sdk/support_api_diff/23.1.0/changes/classes_index_additions.html b/docs/html/sdk/support_api_diff/23.1.0/changes/classes_index_additions.html
    -index c0022c9..1a97c98 100644
    ---- a/docs/html/sdk/support_api_diff/23.1.0/changes/classes_index_additions.html
    -+++ b/docs/html/sdk/support_api_diff/23.1.0/changes/classes_index_additions.html
    -@@ -197,7 +197,7 @@ Listed as: <span style="color:#069"><strong>Added</strong></span>,  <span style=
    - <A HREF="pkg_android.support.v17.leanback.widget.html#ShadowOverlayHelper" class="hiddenlink" target="rightframe"><b>ShadowOverlayHelper</b></A><br>
    - <A HREF="pkg_android.support.v17.leanback.widget.html#ShadowOverlayHelper.Builder" class="hiddenlink" target="rightframe"><b>ShadowOverlayHelper.Builder</b></A><br>
    - <A HREF="pkg_android.support.v17.leanback.widget.html#ShadowOverlayHelper.Options" class="hiddenlink" target="rightframe"><b>ShadowOverlayHelper.Options</b></A><br>
    --<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    - </script>
    - <script type="text/javascript">
    -   try {
    -diff --git a/docs/html/sdk/support_api_diff/23.1.0/changes/classes_index_all.html b/docs/html/sdk/support_api_diff/23.1.0/changes/classes_index_all.html
    -index 05f83b8..c8f86f4 100644
    ---- a/docs/html/sdk/support_api_diff/23.1.0/changes/classes_index_all.html
    -+++ b/docs/html/sdk/support_api_diff/23.1.0/changes/classes_index_all.html
    -@@ -471,7 +471,7 @@ Listed as: <span style="color:#069"><strong>Added</strong></span>,  <span style=
    - <A HREF="android.support.v17.leanback.widget.VerticalGridPresenter.html" class="hiddenlink" target="rightframe">VerticalGridPresenter</A><br>
    - <A HREF="android.support.v17.leanback.app.VerticalGridSupportFragment.html" class="hiddenlink" target="rightframe">VerticalGridSupportFragment</A><br>
    - <A HREF="android.support.v4.view.ViewCompat.html" class="hiddenlink" target="rightframe">ViewCompat</A><br>
    --<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    - </script>
    - <script type="text/javascript">
    -   try {
    -diff --git a/docs/html/sdk/support_api_diff/23.1.0/changes/classes_index_changes.html b/docs/html/sdk/support_api_diff/23.1.0/changes/classes_index_changes.html
    -index b1ee972..f280906 100644
    ---- a/docs/html/sdk/support_api_diff/23.1.0/changes/classes_index_changes.html
    -+++ b/docs/html/sdk/support_api_diff/23.1.0/changes/classes_index_changes.html
    -@@ -415,7 +415,7 @@ Listed as: <span style="color:#069"><strong>Added</strong></span>,  <span style=
    - <A HREF="android.support.v17.leanback.widget.VerticalGridPresenter.html" class="hiddenlink" target="rightframe">VerticalGridPresenter</A><br>
    - <A HREF="android.support.v17.leanback.app.VerticalGridSupportFragment.html" class="hiddenlink" target="rightframe">VerticalGridSupportFragment</A><br>
    - <A HREF="android.support.v4.view.ViewCompat.html" class="hiddenlink" target="rightframe">ViewCompat</A><br>
    --<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    - </script>
    - <script type="text/javascript">
    -   try {
    -diff --git a/docs/html/sdk/support_api_diff/23.1.0/changes/classes_index_removals.html b/docs/html/sdk/support_api_diff/23.1.0/changes/classes_index_removals.html
    -index e6da73f..c466298 100644
    ---- a/docs/html/sdk/support_api_diff/23.1.0/changes/classes_index_removals.html
    -+++ b/docs/html/sdk/support_api_diff/23.1.0/changes/classes_index_removals.html
    -@@ -47,7 +47,7 @@ body{overflow:auto;}
    - <div id="indexTableCaption" style="background-color:#eee;padding:0 4px 0 4px;font-size:11px;margin-bottom:1em;">
    - Listed as: <span style="color:#069"><strong>Added</strong></span>,  <span style="color:#069"><strike>Removed</strike></span>,  <span style="color:#069">Changed</span></font>
    - </div>
    --<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    - </script>
    - <script type="text/javascript">
    -   try {
    -diff --git a/docs/html/sdk/support_api_diff/23.1.0/changes/constructors_index_additions.html b/docs/html/sdk/support_api_diff/23.1.0/changes/constructors_index_additions.html
    -index 3bf8178..45f72f1 100644
    ---- a/docs/html/sdk/support_api_diff/23.1.0/changes/constructors_index_additions.html
    -+++ b/docs/html/sdk/support_api_diff/23.1.0/changes/constructors_index_additions.html
    -@@ -97,7 +97,7 @@ Listed as: <span style="color:#069"><strong>Added</strong></span>,  <span style=
    - <p><div style="line-height:1.5em;color:black">
    - <nobr><A HREF="android.support.design.widget.NavigationView.SavedState.html#android.support.design.widget.NavigationView.SavedState.ctor_added(android.os.Parcel, java.lang.ClassLoader)" class="hiddenlink" target="rightframe"><b>NavigationView.SavedState</b>
    - (<code>Parcel, ClassLoader</code>)</A></nobr>&nbsp;constructor<br>
    --<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    - </script>
    - <script type="text/javascript">
    -   try {
    -diff --git a/docs/html/sdk/support_api_diff/23.1.0/changes/constructors_index_all.html b/docs/html/sdk/support_api_diff/23.1.0/changes/constructors_index_all.html
    -index 546eae8..8dda68f 100644
    ---- a/docs/html/sdk/support_api_diff/23.1.0/changes/constructors_index_all.html
    -+++ b/docs/html/sdk/support_api_diff/23.1.0/changes/constructors_index_all.html
    -@@ -106,7 +106,7 @@ Listed as: <span style="color:#069"><strong>Added</strong></span>,  <span style=
    - (<code>Parcel</code>)</A></nobr>&nbsp;constructor<br>
    - &nbsp;&nbsp;<nobr><A HREF="android.support.design.widget.NavigationView.SavedState.html#android.support.design.widget.NavigationView.SavedState.ctor_added(android.os.Parcel, java.lang.ClassLoader)" class="hiddenlink" target="rightframe"><b>NavigationView.SavedState</b>
    - (<code>Parcel, ClassLoader</code>)</A></nobr>&nbsp;constructor<br>
    --<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    - </script>
    - <script type="text/javascript">
    -   try {
    -diff --git a/docs/html/sdk/support_api_diff/23.1.0/changes/constructors_index_changes.html b/docs/html/sdk/support_api_diff/23.1.0/changes/constructors_index_changes.html
    -index 52c8b49..d6584d1 100644
    ---- a/docs/html/sdk/support_api_diff/23.1.0/changes/constructors_index_changes.html
    -+++ b/docs/html/sdk/support_api_diff/23.1.0/changes/constructors_index_changes.html
    -@@ -47,7 +47,7 @@ body{overflow:auto;}
    - <div id="indexTableCaption" style="background-color:#eee;padding:0 4px 0 4px;font-size:11px;margin-bottom:1em;">
    - Listed as: <span style="color:#069"><strong>Added</strong></span>,  <span style="color:#069"><strike>Removed</strike></span>,  <span style="color:#069">Changed</span></font>
    - </div>
    --<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    - </script>
    - <script type="text/javascript">
    -   try {
    -diff --git a/docs/html/sdk/support_api_diff/23.1.0/changes/constructors_index_removals.html b/docs/html/sdk/support_api_diff/23.1.0/changes/constructors_index_removals.html
    -index 337274d..49ee23c 100644
    ---- a/docs/html/sdk/support_api_diff/23.1.0/changes/constructors_index_removals.html
    -+++ b/docs/html/sdk/support_api_diff/23.1.0/changes/constructors_index_removals.html
    -@@ -71,7 +71,7 @@ Listed as: <span style="color:#069"><strong>Added</strong></span>,  <span style=
    - <p><div style="line-height:1.5em;color:black">
    - <nobr><A HREF="android.support.design.widget.NavigationView.SavedState.html#android.support.design.widget.NavigationView.SavedState.ctor_removed(android.os.Parcel)" class="hiddenlink" target="rightframe"><strike>NavigationView.SavedState</strike>
    - (<code>Parcel</code>)</A></nobr>&nbsp;constructor<br>
    --<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    - </script>
    - <script type="text/javascript">
    -   try {
    -diff --git a/docs/html/sdk/support_api_diff/23.1.0/changes/fields_index_additions.html b/docs/html/sdk/support_api_diff/23.1.0/changes/fields_index_additions.html
    -index d1ef3ac..0c43320 100644
    ---- a/docs/html/sdk/support_api_diff/23.1.0/changes/fields_index_additions.html
    -+++ b/docs/html/sdk/support_api_diff/23.1.0/changes/fields_index_additions.html
    -@@ -329,7 +329,7 @@ Listed as: <span style="color:#069"><strong>Added</strong></span>,  <span style=
    - </nobr><br>
    - <nobr><A HREF="android.support.v7.appcompat.R.style.html#android.support.v7.appcompat.R.style.Widget_AppCompat_SeekBar" class="hiddenlink" target="rightframe">Widget_AppCompat_SeekBar</A>
    - </nobr><br>
    --<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    - </script>
    - <script type="text/javascript">
    -   try {
    -diff --git a/docs/html/sdk/support_api_diff/23.1.0/changes/fields_index_all.html b/docs/html/sdk/support_api_diff/23.1.0/changes/fields_index_all.html
    -index 697f16a..71d9b71 100644
    ---- a/docs/html/sdk/support_api_diff/23.1.0/changes/fields_index_all.html
    -+++ b/docs/html/sdk/support_api_diff/23.1.0/changes/fields_index_all.html
    -@@ -339,7 +339,7 @@ Listed as: <span style="color:#069"><strong>Added</strong></span>,  <span style=
    - </nobr><br>
    - <nobr><A HREF="android.support.v7.appcompat.R.style.html#android.support.v7.appcompat.R.style.Widget_AppCompat_SeekBar" class="hiddenlink" target="rightframe">Widget_AppCompat_SeekBar</A>
    - </nobr><br>
    --<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    - </script>
    - <script type="text/javascript">
    -   try {
    -diff --git a/docs/html/sdk/support_api_diff/23.1.0/changes/fields_index_changes.html b/docs/html/sdk/support_api_diff/23.1.0/changes/fields_index_changes.html
    -index 0e2ccff..301881a 100644
    ---- a/docs/html/sdk/support_api_diff/23.1.0/changes/fields_index_changes.html
    -+++ b/docs/html/sdk/support_api_diff/23.1.0/changes/fields_index_changes.html
    -@@ -47,7 +47,7 @@ body{overflow:auto;}
    - <div id="indexTableCaption" style="background-color:#eee;padding:0 4px 0 4px;font-size:11px;margin-bottom:1em;">
    - Listed as: <span style="color:#069"><strong>Added</strong></span>,  <span style="color:#069"><strike>Removed</strike></span>,  <span style="color:#069">Changed</span></font>
    - </div>
    --<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    - </script>
    - <script type="text/javascript">
    -   try {
    -diff --git a/docs/html/sdk/support_api_diff/23.1.0/changes/fields_index_removals.html b/docs/html/sdk/support_api_diff/23.1.0/changes/fields_index_removals.html
    -index 93bcdc3..f520de6 100644
    ---- a/docs/html/sdk/support_api_diff/23.1.0/changes/fields_index_removals.html
    -+++ b/docs/html/sdk/support_api_diff/23.1.0/changes/fields_index_removals.html
    -@@ -67,7 +67,7 @@ Listed as: <span style="color:#069"><strong>Added</strong></span>,  <span style=
    - <p><div style="line-height:1.5em;color:black">
    - <nobr><A HREF="android.support.v7.appcompat.R.style.html#android.support.v7.appcompat.R.style.RtlOverlay_Widget_AppCompat_ActionButton_Overflow" class="hiddenlink" target="rightframe"><strike>RtlOverlay_Widget_AppCompat_ActionButton_Overflow</strike></A>
    - </nobr><br>
    --<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    - </script>
    - <script type="text/javascript">
    -   try {
    -diff --git a/docs/html/sdk/support_api_diff/23.1.0/changes/jdiff_help.html b/docs/html/sdk/support_api_diff/23.1.0/changes/jdiff_help.html
    -index b03b763..0ba76e7 100644
    ---- a/docs/html/sdk/support_api_diff/23.1.0/changes/jdiff_help.html
    -+++ b/docs/html/sdk/support_api_diff/23.1.0/changes/jdiff_help.html
    -@@ -120,7 +120,7 @@ These links show and hide the HTML frames. All pages are available with or witho
    - There are some complex changes which can occur between versions, for example, when two or more methods with the same name change simultaneously, or when a method or field is moved into or from a superclass. 
    - In these cases, the change will be seen as a removal and an addition, rather than as a change. Unexpected removals or additions are often part of one of these type of changes. 
    - </BLOCKQUOTE>
    --<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    - </script>
    - <script type="text/javascript">
    -   try {
    -diff --git a/docs/html/sdk/support_api_diff/23.1.0/changes/jdiff_statistics.html b/docs/html/sdk/support_api_diff/23.1.0/changes/jdiff_statistics.html
    -index bdda25f..ac4d43e 100644
    ---- a/docs/html/sdk/support_api_diff/23.1.0/changes/jdiff_statistics.html
    -+++ b/docs/html/sdk/support_api_diff/23.1.0/changes/jdiff_statistics.html
    -@@ -568,7 +568,7 @@ added, the change will be 100%.</p>
    -     </div> <!-- end footer -->
    -     </div><!-- end doc-content -->
    -     </div> <!-- end body-content --> 
    --<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    - </script>
    - <script type="text/javascript">
    -   try {
    -diff --git a/docs/html/sdk/support_api_diff/23.1.0/changes/jdiff_topleftframe.html b/docs/html/sdk/support_api_diff/23.1.0/changes/jdiff_topleftframe.html
    -index 36f9836..6a2e76e 100644
    ---- a/docs/html/sdk/support_api_diff/23.1.0/changes/jdiff_topleftframe.html
    -+++ b/docs/html/sdk/support_api_diff/23.1.0/changes/jdiff_topleftframe.html
    -@@ -49,7 +49,7 @@ body{overflow:auto;}
    -   <TD NOWRAP><FONT CLASS="indexText" size="-2"><A HREF="fields_index_all.html" TARGET="bottomleftframe">By Field</A></FONT><br></TD>
    - </TR>
    - </TABLE>
    --<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    - </script>
    - <script type="text/javascript">
    -   try {
    -diff --git a/docs/html/sdk/support_api_diff/23.1.0/changes/methods_index_additions.html b/docs/html/sdk/support_api_diff/23.1.0/changes/methods_index_additions.html
    -index 9b4eab3..fee36df 100644
    ---- a/docs/html/sdk/support_api_diff/23.1.0/changes/methods_index_additions.html
    -+++ b/docs/html/sdk/support_api_diff/23.1.0/changes/methods_index_additions.html
    -@@ -516,7 +516,7 @@ Listed as: <span style="color:#069"><strong>Added</strong></span>,  <span style=
    - <p><div style="line-height:1.5em;color:black">
    - <nobr><A HREF="android.support.customtabs.CustomTabsService.html#android.support.customtabs.CustomTabsService.updateVisuals_added(android.support.customtabs.CustomTabsSessionToken, android.os.Bundle)" class="hiddenlink" target="rightframe"><b>updateVisuals</b>
    - (<code>CustomTabsSessionToken, Bundle</code>)</A></nobr><br>
    --<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    - </script>
    - <script type="text/javascript">
    -   try {
    -diff --git a/docs/html/sdk/support_api_diff/23.1.0/changes/methods_index_all.html b/docs/html/sdk/support_api_diff/23.1.0/changes/methods_index_all.html
    -index d63656c..7a2fe5c 100644
    ---- a/docs/html/sdk/support_api_diff/23.1.0/changes/methods_index_all.html
    -+++ b/docs/html/sdk/support_api_diff/23.1.0/changes/methods_index_all.html
    -@@ -616,7 +616,7 @@ Listed as: <span style="color:#069"><strong>Added</strong></span>,  <span style=
    - <p><div style="line-height:1.5em;color:black">
    - <nobr><A HREF="android.support.customtabs.CustomTabsService.html#android.support.customtabs.CustomTabsService.updateVisuals_added(android.support.customtabs.CustomTabsSessionToken, android.os.Bundle)" class="hiddenlink" target="rightframe"><b>updateVisuals</b>
    - (<code>CustomTabsSessionToken, Bundle</code>)</A></nobr><br>
    --<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    - </script>
    - <script type="text/javascript">
    -   try {
    -diff --git a/docs/html/sdk/support_api_diff/23.1.0/changes/methods_index_changes.html b/docs/html/sdk/support_api_diff/23.1.0/changes/methods_index_changes.html
    -index 8271b35..254a721 100644
    ---- a/docs/html/sdk/support_api_diff/23.1.0/changes/methods_index_changes.html
    -+++ b/docs/html/sdk/support_api_diff/23.1.0/changes/methods_index_changes.html
    -@@ -77,7 +77,7 @@ Listed as: <span style="color:#069"><strong>Added</strong></span>,  <span style=
    - <p><div style="line-height:1.5em;color:black">
    - <nobr><A HREF="android.support.v7.media.MediaRouteDescriptor.Builder.html#android.support.v7.media.MediaRouteDescriptor.Builder.setConnecting_changed(boolean)" class="hiddenlink" target="rightframe">setConnecting
    - (<code>boolean</code>)</A></nobr><br>
    --<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    - </script>
    - <script type="text/javascript">
    -   try {
    -diff --git a/docs/html/sdk/support_api_diff/23.1.0/changes/methods_index_removals.html b/docs/html/sdk/support_api_diff/23.1.0/changes/methods_index_removals.html
    -index 7250505..0b6f2b4 100644
    ---- a/docs/html/sdk/support_api_diff/23.1.0/changes/methods_index_removals.html
    -+++ b/docs/html/sdk/support_api_diff/23.1.0/changes/methods_index_removals.html
    -@@ -158,7 +158,7 @@ Listed as: <span style="color:#069"><strong>Added</strong></span>,  <span style=
    - <p><div style="line-height:1.5em;color:black">
    - <nobr><A HREF="android.support.v17.leanback.app.GuidedStepFragment.html#android.support.v17.leanback.app.GuidedStepFragment.setEntryTransitionEnabled_removed(boolean)" class="hiddenlink" target="rightframe"><strike>setEntryTransitionEnabled</strike>
    - (<code>boolean</code>)</A></nobr><br>
    --<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    - </script>
    - <script type="text/javascript">
    -   try {
    -diff --git a/docs/html/sdk/support_api_diff/23.1.0/changes/packages_index_additions.html b/docs/html/sdk/support_api_diff/23.1.0/changes/packages_index_additions.html
    -index 1776064..e7ed63e 100644
    ---- a/docs/html/sdk/support_api_diff/23.1.0/changes/packages_index_additions.html
    -+++ b/docs/html/sdk/support_api_diff/23.1.0/changes/packages_index_additions.html
    -@@ -49,7 +49,7 @@ Listed as: <span style="color:#069"><strong>Added</strong></span>,  <span style=
    - </div>
    - <br>
    - <div id="indexTableEntries">
    --<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    - </script>
    - <script type="text/javascript">
    -   try {
    -diff --git a/docs/html/sdk/support_api_diff/23.1.0/changes/packages_index_all.html b/docs/html/sdk/support_api_diff/23.1.0/changes/packages_index_all.html
    -index 2bf0974..4236847 100644
    ---- a/docs/html/sdk/support_api_diff/23.1.0/changes/packages_index_all.html
    -+++ b/docs/html/sdk/support_api_diff/23.1.0/changes/packages_index_all.html
    -@@ -67,7 +67,7 @@ Listed as: <span style="color:#069"><strong>Added</strong></span>,  <span style=
    - <A HREF="pkg_android.support.v7.graphics.drawable.html" class="hiddenlink" target="rightframe">android.support.v7.graphics.drawable</A><br>
    - <A HREF="pkg_android.support.v7.media.html" class="hiddenlink" target="rightframe">android.support.v7.media</A><br>
    - <A HREF="pkg_android.support.v7.preference.html" class="hiddenlink" target="rightframe">android.support.v7.preference</A><br>
    --<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    - </script>
    - <script type="text/javascript">
    -   try {
    -diff --git a/docs/html/sdk/support_api_diff/23.1.0/changes/packages_index_changes.html b/docs/html/sdk/support_api_diff/23.1.0/changes/packages_index_changes.html
    -index 519e9aa..8d51ea2 100644
    ---- a/docs/html/sdk/support_api_diff/23.1.0/changes/packages_index_changes.html
    -+++ b/docs/html/sdk/support_api_diff/23.1.0/changes/packages_index_changes.html
    -@@ -67,7 +67,7 @@ Listed as: <span style="color:#069"><strong>Added</strong></span>,  <span style=
    - <A HREF="pkg_android.support.v7.graphics.drawable.html" class="hiddenlink" target="rightframe">android.support.v7.graphics.drawable</A><br>
    - <A HREF="pkg_android.support.v7.media.html" class="hiddenlink" target="rightframe">android.support.v7.media</A><br>
    - <A HREF="pkg_android.support.v7.preference.html" class="hiddenlink" target="rightframe">android.support.v7.preference</A><br>
    --<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    - </script>
    - <script type="text/javascript">
    -   try {
    -diff --git a/docs/html/sdk/support_api_diff/23.1.0/changes/packages_index_removals.html b/docs/html/sdk/support_api_diff/23.1.0/changes/packages_index_removals.html
    -index 9fd0f7e..ae935f4 100644
    ---- a/docs/html/sdk/support_api_diff/23.1.0/changes/packages_index_removals.html
    -+++ b/docs/html/sdk/support_api_diff/23.1.0/changes/packages_index_removals.html
    -@@ -49,7 +49,7 @@ Listed as: <span style="color:#069"><strong>Added</strong></span>,  <span style=
    - </div>
    - <br>
    - <div id="indexTableEntries">
    --<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    - </script>
    - <script type="text/javascript">
    -   try {
    -diff --git a/docs/html/sdk/support_api_diff/23.1.0/changes/pkg_android.support.customtabs.html b/docs/html/sdk/support_api_diff/23.1.0/changes/pkg_android.support.customtabs.html
    -index d85f3f8..ea62004 100644
    ---- a/docs/html/sdk/support_api_diff/23.1.0/changes/pkg_android.support.customtabs.html
    -+++ b/docs/html/sdk/support_api_diff/23.1.0/changes/pkg_android.support.customtabs.html
    -@@ -140,7 +140,7 @@ Package <A HREF="../../../../reference/android/support/customtabs/package-summar
    -     </div> <!-- end footer -->
    -     </div><!-- end doc-content -->
    -     </div> <!-- end body-content --> 
    --<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    - </script>
    - <script type="text/javascript">
    -   try {
    -diff --git a/docs/html/sdk/support_api_diff/23.1.0/changes/pkg_android.support.design.widget.html b/docs/html/sdk/support_api_diff/23.1.0/changes/pkg_android.support.design.widget.html
    -index 449afa6..45625b9 100644
    ---- a/docs/html/sdk/support_api_diff/23.1.0/changes/pkg_android.support.design.widget.html
    -+++ b/docs/html/sdk/support_api_diff/23.1.0/changes/pkg_android.support.design.widget.html
    -@@ -211,7 +211,7 @@ Package <A HREF="../../../../reference/android/support/design/widget/package-sum
    -     </div> <!-- end footer -->
    -     </div><!-- end doc-content -->
    -     </div> <!-- end body-content --> 
    --<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    - </script>
    - <script type="text/javascript">
    -   try {
    -diff --git a/docs/html/sdk/support_api_diff/23.1.0/changes/pkg_android.support.percent.html b/docs/html/sdk/support_api_diff/23.1.0/changes/pkg_android.support.percent.html
    -index 53b92a9..13b9732 100644
    ---- a/docs/html/sdk/support_api_diff/23.1.0/changes/pkg_android.support.percent.html
    -+++ b/docs/html/sdk/support_api_diff/23.1.0/changes/pkg_android.support.percent.html
    -@@ -105,7 +105,7 @@ Package <A HREF="../../../../reference/android/support/percent/package-summary.h
    -     </div> <!-- end footer -->
    -     </div><!-- end doc-content -->
    -     </div> <!-- end body-content --> 
    --<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    - </script>
    - <script type="text/javascript">
    -   try {
    -diff --git a/docs/html/sdk/support_api_diff/23.1.0/changes/pkg_android.support.v14.preference.html b/docs/html/sdk/support_api_diff/23.1.0/changes/pkg_android.support.v14.preference.html
    -index 3ef0a0f..7364b7c 100644
    ---- a/docs/html/sdk/support_api_diff/23.1.0/changes/pkg_android.support.v14.preference.html
    -+++ b/docs/html/sdk/support_api_diff/23.1.0/changes/pkg_android.support.v14.preference.html
    -@@ -105,7 +105,7 @@ Package <A HREF="../../../../reference/android/support/v14/preference/package-su
    -     </div> <!-- end footer -->
    -     </div><!-- end doc-content -->
    -     </div> <!-- end body-content --> 
    --<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    - </script>
    - <script type="text/javascript">
    -   try {
    -diff --git a/docs/html/sdk/support_api_diff/23.1.0/changes/pkg_android.support.v17.leanback.app.html b/docs/html/sdk/support_api_diff/23.1.0/changes/pkg_android.support.v17.leanback.app.html
    -index 49ee52f..21763fb 100644
    ---- a/docs/html/sdk/support_api_diff/23.1.0/changes/pkg_android.support.v17.leanback.app.html
    -+++ b/docs/html/sdk/support_api_diff/23.1.0/changes/pkg_android.support.v17.leanback.app.html
    -@@ -211,7 +211,7 @@ Package <A HREF="../../../../reference/android/support/v17/leanback/app/package-
    -     </div> <!-- end footer -->
    -     </div><!-- end doc-content -->
    -     </div> <!-- end body-content --> 
    --<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    - </script>
    - <script type="text/javascript">
    -   try {
    -diff --git a/docs/html/sdk/support_api_diff/23.1.0/changes/pkg_android.support.v17.leanback.widget.html b/docs/html/sdk/support_api_diff/23.1.0/changes/pkg_android.support.v17.leanback.widget.html
    -index 73d5050..ff00794 100644
    ---- a/docs/html/sdk/support_api_diff/23.1.0/changes/pkg_android.support.v17.leanback.widget.html
    -+++ b/docs/html/sdk/support_api_diff/23.1.0/changes/pkg_android.support.v17.leanback.widget.html
    -@@ -239,7 +239,7 @@ Package <A HREF="../../../../reference/android/support/v17/leanback/widget/packa
    -     </div> <!-- end footer -->
    -     </div><!-- end doc-content -->
    -     </div> <!-- end body-content --> 
    --<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    - </script>
    - <script type="text/javascript">
    -   try {
    -diff --git a/docs/html/sdk/support_api_diff/23.1.0/changes/pkg_android.support.v4.app.html b/docs/html/sdk/support_api_diff/23.1.0/changes/pkg_android.support.v4.app.html
    -index b1645a6..ccdb5fe 100644
    ---- a/docs/html/sdk/support_api_diff/23.1.0/changes/pkg_android.support.v4.app.html
    -+++ b/docs/html/sdk/support_api_diff/23.1.0/changes/pkg_android.support.v4.app.html
    -@@ -120,7 +120,7 @@ Package <A HREF="../../../../reference/android/support/v4/app/package-summary.ht
    -     </div> <!-- end footer -->
    -     </div><!-- end doc-content -->
    -     </div> <!-- end body-content --> 
    --<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    - </script>
    - <script type="text/javascript">
    -   try {
    -diff --git a/docs/html/sdk/support_api_diff/23.1.0/changes/pkg_android.support.v4.content.html b/docs/html/sdk/support_api_diff/23.1.0/changes/pkg_android.support.v4.content.html
    -index efc62c9..b1b6ffc 100644
    ---- a/docs/html/sdk/support_api_diff/23.1.0/changes/pkg_android.support.v4.content.html
    -+++ b/docs/html/sdk/support_api_diff/23.1.0/changes/pkg_android.support.v4.content.html
    -@@ -105,7 +105,7 @@ Package <A HREF="../../../../reference/android/support/v4/content/package-summar
    -     </div> <!-- end footer -->
    -     </div><!-- end doc-content -->
    -     </div> <!-- end body-content --> 
    --<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    - </script>
    - <script type="text/javascript">
    -   try {
    -diff --git a/docs/html/sdk/support_api_diff/23.1.0/changes/pkg_android.support.v4.content.res.html b/docs/html/sdk/support_api_diff/23.1.0/changes/pkg_android.support.v4.content.res.html
    -index fd9c9f8..f6a1367 100644
    ---- a/docs/html/sdk/support_api_diff/23.1.0/changes/pkg_android.support.v4.content.res.html
    -+++ b/docs/html/sdk/support_api_diff/23.1.0/changes/pkg_android.support.v4.content.res.html
    -@@ -105,7 +105,7 @@ Package <A HREF="../../../../reference/android/support/v4/content/res/package-su
    -     </div> <!-- end footer -->
    -     </div><!-- end doc-content -->
    -     </div> <!-- end body-content --> 
    --<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    - </script>
    - <script type="text/javascript">
    -   try {
    -diff --git a/docs/html/sdk/support_api_diff/23.1.0/changes/pkg_android.support.v4.media.session.html b/docs/html/sdk/support_api_diff/23.1.0/changes/pkg_android.support.v4.media.session.html
    -index afd23b1..1182648 100644
    ---- a/docs/html/sdk/support_api_diff/23.1.0/changes/pkg_android.support.v4.media.session.html
    -+++ b/docs/html/sdk/support_api_diff/23.1.0/changes/pkg_android.support.v4.media.session.html
    -@@ -120,7 +120,7 @@ Package <A HREF="../../../../reference/android/support/v4/media/session/package-
    -     </div> <!-- end footer -->
    -     </div><!-- end doc-content -->
    -     </div> <!-- end body-content --> 
    --<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    - </script>
    - <script type="text/javascript">
    -   try {
    -diff --git a/docs/html/sdk/support_api_diff/23.1.0/changes/pkg_android.support.v4.view.html b/docs/html/sdk/support_api_diff/23.1.0/changes/pkg_android.support.v4.view.html
    -index 7d74c82..b4fe9b2 100644
    ---- a/docs/html/sdk/support_api_diff/23.1.0/changes/pkg_android.support.v4.view.html
    -+++ b/docs/html/sdk/support_api_diff/23.1.0/changes/pkg_android.support.v4.view.html
    -@@ -105,7 +105,7 @@ Package <A HREF="../../../../reference/android/support/v4/view/package-summary.h
    -     </div> <!-- end footer -->
    -     </div><!-- end doc-content -->
    -     </div> <!-- end body-content --> 
    --<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    - </script>
    - <script type="text/javascript">
    -   try {
    -diff --git a/docs/html/sdk/support_api_diff/23.1.0/changes/pkg_android.support.v4.widget.html b/docs/html/sdk/support_api_diff/23.1.0/changes/pkg_android.support.v4.widget.html
    -index 4ca7874..e32ebc8 100644
    ---- a/docs/html/sdk/support_api_diff/23.1.0/changes/pkg_android.support.v4.widget.html
    -+++ b/docs/html/sdk/support_api_diff/23.1.0/changes/pkg_android.support.v4.widget.html
    -@@ -134,7 +134,7 @@ Package <A HREF="../../../../reference/android/support/v4/widget/package-summary
    -     </div> <!-- end footer -->
    -     </div><!-- end doc-content -->
    -     </div> <!-- end body-content --> 
    --<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    - </script>
    - <script type="text/javascript">
    -   try {
    -diff --git a/docs/html/sdk/support_api_diff/23.1.0/changes/pkg_android.support.v7.appcompat.html b/docs/html/sdk/support_api_diff/23.1.0/changes/pkg_android.support.v7.appcompat.html
    -index 553bdf2..b516a35 100644
    ---- a/docs/html/sdk/support_api_diff/23.1.0/changes/pkg_android.support.v7.appcompat.html
    -+++ b/docs/html/sdk/support_api_diff/23.1.0/changes/pkg_android.support.v7.appcompat.html
    -@@ -161,7 +161,7 @@ Package <A HREF="../../../../reference/android/support/v7/appcompat/package-summ
    -     </div> <!-- end footer -->
    -     </div><!-- end doc-content -->
    -     </div> <!-- end body-content --> 
    --<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    - </script>
    - <script type="text/javascript">
    -   try {
    -diff --git a/docs/html/sdk/support_api_diff/23.1.0/changes/pkg_android.support.v7.graphics.drawable.html b/docs/html/sdk/support_api_diff/23.1.0/changes/pkg_android.support.v7.graphics.drawable.html
    -index e9d5cd9..69c91d5 100644
    ---- a/docs/html/sdk/support_api_diff/23.1.0/changes/pkg_android.support.v7.graphics.drawable.html
    -+++ b/docs/html/sdk/support_api_diff/23.1.0/changes/pkg_android.support.v7.graphics.drawable.html
    -@@ -105,7 +105,7 @@ Package <A HREF="../../../../reference/android/support/v7/graphics/drawable/pack
    -     </div> <!-- end footer -->
    -     </div><!-- end doc-content -->
    -     </div> <!-- end body-content --> 
    --<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    - </script>
    - <script type="text/javascript">
    -   try {
    -diff --git a/docs/html/sdk/support_api_diff/23.1.0/changes/pkg_android.support.v7.graphics.html b/docs/html/sdk/support_api_diff/23.1.0/changes/pkg_android.support.v7.graphics.html
    -index ba9a092..13d6ef9 100644
    ---- a/docs/html/sdk/support_api_diff/23.1.0/changes/pkg_android.support.v7.graphics.html
    -+++ b/docs/html/sdk/support_api_diff/23.1.0/changes/pkg_android.support.v7.graphics.html
    -@@ -105,7 +105,7 @@ Package <A HREF="../../../../reference/android/support/v7/graphics/package-summa
    -     </div> <!-- end footer -->
    -     </div><!-- end doc-content -->
    -     </div> <!-- end body-content --> 
    --<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    - </script>
    - <script type="text/javascript">
    -   try {
    -diff --git a/docs/html/sdk/support_api_diff/23.1.0/changes/pkg_android.support.v7.media.html b/docs/html/sdk/support_api_diff/23.1.0/changes/pkg_android.support.v7.media.html
    -index 7892bf9..4c2094c 100644
    ---- a/docs/html/sdk/support_api_diff/23.1.0/changes/pkg_android.support.v7.media.html
    -+++ b/docs/html/sdk/support_api_diff/23.1.0/changes/pkg_android.support.v7.media.html
    -@@ -134,7 +134,7 @@ Package <A HREF="../../../../reference/android/support/v7/media/package-summary.
    -     </div> <!-- end footer -->
    -     </div><!-- end doc-content -->
    -     </div> <!-- end body-content --> 
    --<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    - </script>
    - <script type="text/javascript">
    -   try {
    -diff --git a/docs/html/sdk/support_api_diff/23.1.0/changes/pkg_android.support.v7.preference.html b/docs/html/sdk/support_api_diff/23.1.0/changes/pkg_android.support.v7.preference.html
    -index ced3a90..ed590bb 100644
    ---- a/docs/html/sdk/support_api_diff/23.1.0/changes/pkg_android.support.v7.preference.html
    -+++ b/docs/html/sdk/support_api_diff/23.1.0/changes/pkg_android.support.v7.preference.html
    -@@ -105,7 +105,7 @@ Package <A HREF="../../../../reference/android/support/v7/preference/package-sum
    -     </div> <!-- end footer -->
    -     </div><!-- end doc-content -->
    -     </div> <!-- end body-content --> 
    --<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    - </script>
    - <script type="text/javascript">
    -   try {
    -diff --git a/docs/html/sdk/support_api_diff/23.2.0/changes/alldiffs_index_additions.html b/docs/html/sdk/support_api_diff/23.2.0/changes/alldiffs_index_additions.html
    -index 09ec1eb..3b43f27 100644
    ---- a/docs/html/sdk/support_api_diff/23.2.0/changes/alldiffs_index_additions.html
    -+++ b/docs/html/sdk/support_api_diff/23.2.0/changes/alldiffs_index_additions.html
    -@@ -1955,7 +1955,7 @@ Listed as: <span style="color:#069"><strong>Added</strong></span>,  <span style=
    - <!-- Method XYZToLAB -->
    - <nobr><A HREF="android.support.v4.graphics.ColorUtils.html#android.support.v4.graphics.ColorUtils.XYZToLAB_added(double, double, double, double[])" class="hiddenlink" target="rightframe"><b>XYZToLAB</b>
    - (<code>double, double, double, double[]</code>)</A></nobr><br>
    --<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    - </script>
    - <script type="text/javascript">
    -   try {
    -diff --git a/docs/html/sdk/support_api_diff/23.2.0/changes/alldiffs_index_all.html b/docs/html/sdk/support_api_diff/23.2.0/changes/alldiffs_index_all.html
    -index 770d615..6264757 100644
    ---- a/docs/html/sdk/support_api_diff/23.2.0/changes/alldiffs_index_all.html
    -+++ b/docs/html/sdk/support_api_diff/23.2.0/changes/alldiffs_index_all.html
    -@@ -2914,7 +2914,7 @@ Listed as: <span style="color:#069"><strong>Added</strong></span>,  <span style=
    - <!-- Method XYZToLAB -->
    - <nobr><A HREF="android.support.v4.graphics.ColorUtils.html#android.support.v4.graphics.ColorUtils.XYZToLAB_added(double, double, double, double[])" class="hiddenlink" target="rightframe"><b>XYZToLAB</b>
    - (<code>double, double, double, double[]</code>)</A></nobr><br>
    --<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    - </script>
    - <script type="text/javascript">
    -   try {
    -diff --git a/docs/html/sdk/support_api_diff/23.2.0/changes/alldiffs_index_changes.html b/docs/html/sdk/support_api_diff/23.2.0/changes/alldiffs_index_changes.html
    -index 134580d..6113a9e 100644
    ---- a/docs/html/sdk/support_api_diff/23.2.0/changes/alldiffs_index_changes.html
    -+++ b/docs/html/sdk/support_api_diff/23.2.0/changes/alldiffs_index_changes.html
    -@@ -939,7 +939,7 @@ Listed as: <span style="color:#069"><strong>Added</strong></span>,  <span style=
    -  <a href="#topheader"><font size="-2">TOP</font></a>
    - <p><div style="line-height:1.5em;color:black">
    - <A HREF="android.support.v4.view.WindowCompat.html" class="hiddenlink" target="rightframe">WindowCompat</A><br>
    --<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    - </script>
    - <script type="text/javascript">
    -   try {
    -diff --git a/docs/html/sdk/support_api_diff/23.2.0/changes/alldiffs_index_removals.html b/docs/html/sdk/support_api_diff/23.2.0/changes/alldiffs_index_removals.html
    -index a60b244..2df39dc 100644
    ---- a/docs/html/sdk/support_api_diff/23.2.0/changes/alldiffs_index_removals.html
    -+++ b/docs/html/sdk/support_api_diff/23.2.0/changes/alldiffs_index_removals.html
    -@@ -956,7 +956,7 @@ Listed as: <span style="color:#069"><strong>Added</strong></span>,  <span style=
    - <p><div style="line-height:1.5em;color:black">
    - <nobr><A HREF="android.support.v4.view.WindowCompat.html#android.support.v4.view.WindowCompat.ctor_removed()" class="hiddenlink" target="rightframe"><strike>WindowCompat</strike>
    - ()</A></nobr>&nbsp;constructor<br>
    --<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    - </script>
    - <script type="text/javascript">
    -   try {
    -diff --git a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.customtabs.CustomTabsIntent.Builder.html b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.customtabs.CustomTabsIntent.Builder.html
    -index 46a0548..3e97afd 100644
    ---- a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.customtabs.CustomTabsIntent.Builder.html
    -+++ b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.customtabs.CustomTabsIntent.Builder.html
    -@@ -122,7 +122,7 @@ Class android.support.customtabs.<A HREF="../../../../reference/android/support/
    -     </div> <!-- end footer -->
    -     </div><!-- end doc-content -->
    -     </div> <!-- end body-content --> 
    --<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    - </script>
    - <script type="text/javascript">
    -   try {
    -diff --git a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.customtabs.CustomTabsIntent.html b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.customtabs.CustomTabsIntent.html
    -index 7987724..d7745e6 100644
    ---- a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.customtabs.CustomTabsIntent.html
    -+++ b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.customtabs.CustomTabsIntent.html
    -@@ -151,7 +151,7 @@ Class android.support.customtabs.<A HREF="../../../../reference/android/support/
    -     </div> <!-- end footer -->
    -     </div><!-- end doc-content -->
    -     </div> <!-- end body-content --> 
    --<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    - </script>
    - <script type="text/javascript">
    -   try {
    -diff --git a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.customtabs.CustomTabsSession.html b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.customtabs.CustomTabsSession.html
    -index 1296d4c..9b48018 100644
    ---- a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.customtabs.CustomTabsSession.html
    -+++ b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.customtabs.CustomTabsSession.html
    -@@ -108,7 +108,7 @@ Class android.support.customtabs.<A HREF="../../../../reference/android/support/
    -     </div> <!-- end footer -->
    -     </div><!-- end doc-content -->
    -     </div> <!-- end body-content --> 
    --<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    - </script>
    - <script type="text/javascript">
    -   try {
    -diff --git a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.design.widget.AppBarLayout.ScrollingViewBehavior.html b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.design.widget.AppBarLayout.ScrollingViewBehavior.html
    -index d539481..80c8e11 100644
    ---- a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.design.widget.AppBarLayout.ScrollingViewBehavior.html
    -+++ b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.design.widget.AppBarLayout.ScrollingViewBehavior.html
    -@@ -136,7 +136,7 @@ Method was locally defined, but is now inherited from <a href="../../../../refer
    -     </div> <!-- end footer -->
    -     </div><!-- end doc-content -->
    -     </div> <!-- end body-content --> 
    --<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    - </script>
    - <script type="text/javascript">
    -   try {
    -diff --git a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.design.widget.CollapsingToolbarLayout.html b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.design.widget.CollapsingToolbarLayout.html
    -index e47f317..e1ae295 100644
    ---- a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.design.widget.CollapsingToolbarLayout.html
    -+++ b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.design.widget.CollapsingToolbarLayout.html
    -@@ -164,7 +164,7 @@ Class android.support.design.widget.<A HREF="../../../../reference/android/suppo
    -     </div> <!-- end footer -->
    -     </div><!-- end doc-content -->
    -     </div> <!-- end body-content --> 
    --<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    - </script>
    - <script type="text/javascript">
    -   try {
    -diff --git a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.design.widget.CoordinatorLayout.Behavior.html b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.design.widget.CoordinatorLayout.Behavior.html
    -index 04efe89..ee87ca6 100644
    ---- a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.design.widget.CoordinatorLayout.Behavior.html
    -+++ b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.design.widget.CoordinatorLayout.Behavior.html
    -@@ -121,7 +121,7 @@ Change from final to non-final.<br>
    -     </div> <!-- end footer -->
    -     </div><!-- end doc-content -->
    -     </div> <!-- end body-content --> 
    --<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    - </script>
    - <script type="text/javascript">
    -   try {
    -diff --git a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.design.widget.FloatingActionButton.html b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.design.widget.FloatingActionButton.html
    -index 985adba..33d67e2 100644
    ---- a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.design.widget.FloatingActionButton.html
    -+++ b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.design.widget.FloatingActionButton.html
    -@@ -144,7 +144,7 @@ Class android.support.design.widget.<A HREF="../../../../reference/android/suppo
    -     </div> <!-- end footer -->
    -     </div><!-- end doc-content -->
    -     </div> <!-- end body-content --> 
    --<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    - </script>
    - <script type="text/javascript">
    -   try {
    -diff --git a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.design.widget.HeaderScrollingViewBehavior.html b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.design.widget.HeaderScrollingViewBehavior.html
    -index 7021ba2..0e24356 100644
    ---- a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.design.widget.HeaderScrollingViewBehavior.html
    -+++ b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.design.widget.HeaderScrollingViewBehavior.html
    -@@ -122,7 +122,7 @@ Class android.support.design.widget.<A HREF="../../../../reference/android/suppo
    -     </div> <!-- end footer -->
    -     </div><!-- end doc-content -->
    -     </div> <!-- end body-content --> 
    --<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    - </script>
    - <script type="text/javascript">
    -   try {
    -diff --git a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.design.widget.TabLayout.html b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.design.widget.TabLayout.html
    -index 9224ddb..3d0eb9f 100644
    ---- a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.design.widget.TabLayout.html
    -+++ b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.design.widget.TabLayout.html
    -@@ -111,7 +111,7 @@ Class android.support.design.widget.<A HREF="../../../../reference/android/suppo
    -     </div> <!-- end footer -->
    -     </div><!-- end doc-content -->
    -     </div> <!-- end body-content --> 
    --<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    - </script>
    - <script type="text/javascript">
    -   try {
    -diff --git a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.design.widget.TextInputLayout.html b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.design.widget.TextInputLayout.html
    -index b0f5d63..d72b373 100644
    ---- a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.design.widget.TextInputLayout.html
    -+++ b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.design.widget.TextInputLayout.html
    -@@ -129,7 +129,7 @@ Class android.support.design.widget.<A HREF="../../../../reference/android/suppo
    -     </div> <!-- end footer -->
    -     </div><!-- end doc-content -->
    -     </div> <!-- end body-content --> 
    --<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    - </script>
    - <script type="text/javascript">
    -   try {
    -diff --git a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.design.widget.ViewOffsetBehavior.html b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.design.widget.ViewOffsetBehavior.html
    -index 1b4625f..9faa826 100644
    ---- a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.design.widget.ViewOffsetBehavior.html
    -+++ b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.design.widget.ViewOffsetBehavior.html
    -@@ -108,7 +108,7 @@ Class android.support.design.widget.<A HREF="../../../../reference/android/suppo
    -     </div> <!-- end footer -->
    -     </div><!-- end doc-content -->
    -     </div> <!-- end body-content --> 
    --<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    - </script>
    - <script type="text/javascript">
    -   try {
    -diff --git a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.percent.PercentLayoutHelper.PercentLayoutInfo.html b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.percent.PercentLayoutHelper.PercentLayoutInfo.html
    -index c13de02..13c0b4e 100644
    ---- a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.percent.PercentLayoutHelper.PercentLayoutInfo.html
    -+++ b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.percent.PercentLayoutHelper.PercentLayoutInfo.html
    -@@ -130,7 +130,7 @@ Class android.support.percent.<A HREF="../../../../reference/android/support/per
    -     </div> <!-- end footer -->
    -     </div><!-- end doc-content -->
    -     </div> <!-- end body-content --> 
    --<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    - </script>
    - <script type="text/javascript">
    -   try {
    -diff --git a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v14.preference.PreferenceFragment.html b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v14.preference.PreferenceFragment.html
    -index 3a910d0..7ead465 100644
    ---- a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v14.preference.PreferenceFragment.html
    -+++ b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v14.preference.PreferenceFragment.html
    -@@ -115,7 +115,7 @@ Class android.support.v14.preference.<A HREF="../../../../reference/android/supp
    -     </div> <!-- end footer -->
    -     </div><!-- end doc-content -->
    -     </div> <!-- end body-content --> 
    --<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    - </script>
    - <script type="text/javascript">
    -   try {
    -diff --git a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v17.leanback.app.BaseRowFragment.html b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v17.leanback.app.BaseRowFragment.html
    -index 003f04b..9bd2bd7 100644
    ---- a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v17.leanback.app.BaseRowFragment.html
    -+++ b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v17.leanback.app.BaseRowFragment.html
    -@@ -108,7 +108,7 @@ Class android.support.v17.leanback.app.<A HREF="../../../../reference/android/su
    -     </div> <!-- end footer -->
    -     </div><!-- end doc-content -->
    -     </div> <!-- end body-content --> 
    --<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    - </script>
    - <script type="text/javascript">
    -   try {
    -diff --git a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v17.leanback.app.BaseRowSupportFragment.html b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v17.leanback.app.BaseRowSupportFragment.html
    -index 6a30cc3..cf9900c 100644
    ---- a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v17.leanback.app.BaseRowSupportFragment.html
    -+++ b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v17.leanback.app.BaseRowSupportFragment.html
    -@@ -108,7 +108,7 @@ Class android.support.v17.leanback.app.<A HREF="../../../../reference/android/su
    -     </div> <!-- end footer -->
    -     </div><!-- end doc-content -->
    -     </div> <!-- end body-content --> 
    --<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    - </script>
    - <script type="text/javascript">
    -   try {
    -diff --git a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v17.leanback.app.BrowseFragment.html b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v17.leanback.app.BrowseFragment.html
    -index 74cb151..d7d0e76 100644
    ---- a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v17.leanback.app.BrowseFragment.html
    -+++ b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v17.leanback.app.BrowseFragment.html
    -@@ -129,7 +129,7 @@ Class android.support.v17.leanback.app.<A HREF="../../../../reference/android/su
    -     </div> <!-- end footer -->
    -     </div><!-- end doc-content -->
    -     </div> <!-- end body-content --> 
    --<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    - </script>
    - <script type="text/javascript">
    -   try {
    -diff --git a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v17.leanback.app.BrowseSupportFragment.html b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v17.leanback.app.BrowseSupportFragment.html
    -index a46a8ed..d7bb8c9 100644
    ---- a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v17.leanback.app.BrowseSupportFragment.html
    -+++ b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v17.leanback.app.BrowseSupportFragment.html
    -@@ -129,7 +129,7 @@ Class android.support.v17.leanback.app.<A HREF="../../../../reference/android/su
    -     </div> <!-- end footer -->
    -     </div><!-- end doc-content -->
    -     </div> <!-- end body-content --> 
    --<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    - </script>
    - <script type="text/javascript">
    -   try {
    -diff --git a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v17.leanback.app.DetailsFragment.html b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v17.leanback.app.DetailsFragment.html
    -index 34875c3..852b28a 100644
    ---- a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v17.leanback.app.DetailsFragment.html
    -+++ b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v17.leanback.app.DetailsFragment.html
    -@@ -108,7 +108,7 @@ Class android.support.v17.leanback.app.<A HREF="../../../../reference/android/su
    -     </div> <!-- end footer -->
    -     </div><!-- end doc-content -->
    -     </div> <!-- end body-content --> 
    --<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    - </script>
    - <script type="text/javascript">
    -   try {
    -diff --git a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v17.leanback.app.DetailsSupportFragment.html b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v17.leanback.app.DetailsSupportFragment.html
    -index 4cd41ed..444a537 100644
    ---- a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v17.leanback.app.DetailsSupportFragment.html
    -+++ b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v17.leanback.app.DetailsSupportFragment.html
    -@@ -108,7 +108,7 @@ Class android.support.v17.leanback.app.<A HREF="../../../../reference/android/su
    -     </div> <!-- end footer -->
    -     </div><!-- end doc-content -->
    -     </div> <!-- end body-content --> 
    --<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    - </script>
    - <script type="text/javascript">
    -   try {
    -diff --git a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v17.leanback.app.GuidedStepFragment.html b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v17.leanback.app.GuidedStepFragment.html
    -index 0962be7..1cfc19e 100644
    ---- a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v17.leanback.app.GuidedStepFragment.html
    -+++ b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v17.leanback.app.GuidedStepFragment.html
    -@@ -330,7 +330,7 @@ Class android.support.v17.leanback.app.<A HREF="../../../../reference/android/su
    -     </div> <!-- end footer -->
    -     </div><!-- end doc-content -->
    -     </div> <!-- end body-content --> 
    --<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    - </script>
    - <script type="text/javascript">
    -   try {
    -diff --git a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v17.leanback.app.GuidedStepSupportFragment.html b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v17.leanback.app.GuidedStepSupportFragment.html
    -index b464afa..c5f0d5a 100644
    ---- a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v17.leanback.app.GuidedStepSupportFragment.html
    -+++ b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v17.leanback.app.GuidedStepSupportFragment.html
    -@@ -330,7 +330,7 @@ Class android.support.v17.leanback.app.<A HREF="../../../../reference/android/su
    -     </div> <!-- end footer -->
    -     </div><!-- end doc-content -->
    -     </div> <!-- end body-content --> 
    --<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    - </script>
    - <script type="text/javascript">
    -   try {
    -diff --git a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v17.leanback.app.HeadersFragment.OnHeaderClickedListener.html b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v17.leanback.app.HeadersFragment.OnHeaderClickedListener.html
    -index 0df02c4..800f32b 100644
    ---- a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v17.leanback.app.HeadersFragment.OnHeaderClickedListener.html
    -+++ b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v17.leanback.app.HeadersFragment.OnHeaderClickedListener.html
    -@@ -112,7 +112,7 @@ Change in signature from <code>void</code> to (<code>ViewHolder, Row</code>).<br
    -     </div> <!-- end footer -->
    -     </div><!-- end doc-content -->
    -     </div> <!-- end body-content --> 
    --<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    - </script>
    - <script type="text/javascript">
    -   try {
    -diff --git a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v17.leanback.app.HeadersFragment.OnHeaderViewSelectedListener.html b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v17.leanback.app.HeadersFragment.OnHeaderViewSelectedListener.html
    -index cc2eeda..70ec556 100644
    ---- a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v17.leanback.app.HeadersFragment.OnHeaderViewSelectedListener.html
    -+++ b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v17.leanback.app.HeadersFragment.OnHeaderViewSelectedListener.html
    -@@ -94,7 +94,7 @@ Interface android.support.v17.leanback.app.<A HREF="../../../../reference/androi
    -     </div> <!-- end footer -->
    -     </div><!-- end doc-content -->
    -     </div> <!-- end body-content --> 
    --<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    - </script>
    - <script type="text/javascript">
    -   try {
    -diff --git a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v17.leanback.app.HeadersSupportFragment.OnHeaderClickedListener.html b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v17.leanback.app.HeadersSupportFragment.OnHeaderClickedListener.html
    -index 0c59abd..ee37373 100644
    ---- a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v17.leanback.app.HeadersSupportFragment.OnHeaderClickedListener.html
    -+++ b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v17.leanback.app.HeadersSupportFragment.OnHeaderClickedListener.html
    -@@ -112,7 +112,7 @@ Change in signature from <code>void</code> to (<code>ViewHolder, Row</code>).<br
    -     </div> <!-- end footer -->
    -     </div><!-- end doc-content -->
    -     </div> <!-- end body-content --> 
    --<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    - </script>
    - <script type="text/javascript">
    -   try {
    -diff --git a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v17.leanback.app.HeadersSupportFragment.OnHeaderViewSelectedListener.html b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v17.leanback.app.HeadersSupportFragment.OnHeaderViewSelectedListener.html
    -index ee27726..99e380d 100644
    ---- a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v17.leanback.app.HeadersSupportFragment.OnHeaderViewSelectedListener.html
    -+++ b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v17.leanback.app.HeadersSupportFragment.OnHeaderViewSelectedListener.html
    -@@ -94,7 +94,7 @@ Interface android.support.v17.leanback.app.<A HREF="../../../../reference/androi
    -     </div> <!-- end footer -->
    -     </div><!-- end doc-content -->
    -     </div> <!-- end body-content --> 
    --<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    - </script>
    - <script type="text/javascript">
    -   try {
    -diff --git a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v17.leanback.app.RowsFragment.html b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v17.leanback.app.RowsFragment.html
    -index 612c05a..7c78322 100644
    ---- a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v17.leanback.app.RowsFragment.html
    -+++ b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v17.leanback.app.RowsFragment.html
    -@@ -115,7 +115,7 @@ Class android.support.v17.leanback.app.<A HREF="../../../../reference/android/su
    -     </div> <!-- end footer -->
    -     </div><!-- end doc-content -->
    -     </div> <!-- end body-content --> 
    --<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    - </script>
    - <script type="text/javascript">
    -   try {
    -diff --git a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v17.leanback.app.RowsSupportFragment.html b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v17.leanback.app.RowsSupportFragment.html
    -index 7cbdf0c..a112b19 100644
    ---- a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v17.leanback.app.RowsSupportFragment.html
    -+++ b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v17.leanback.app.RowsSupportFragment.html
    -@@ -115,7 +115,7 @@ Class android.support.v17.leanback.app.<A HREF="../../../../reference/android/su
    -     </div> <!-- end footer -->
    -     </div><!-- end doc-content -->
    -     </div> <!-- end body-content --> 
    --<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    - </script>
    - <script type="text/javascript">
    -   try {
    -diff --git a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v17.leanback.widget.DetailsOverviewLogoPresenter.ViewHolder.html b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v17.leanback.widget.DetailsOverviewLogoPresenter.ViewHolder.html
    -index 674231e..ef74a40 100644
    ---- a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v17.leanback.widget.DetailsOverviewLogoPresenter.ViewHolder.html
    -+++ b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v17.leanback.widget.DetailsOverviewLogoPresenter.ViewHolder.html
    -@@ -129,7 +129,7 @@ Class android.support.v17.leanback.widget.<A HREF="../../../../reference/android
    -     </div> <!-- end footer -->
    -     </div><!-- end doc-content -->
    -     </div> <!-- end body-content --> 
    --<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    - </script>
    - <script type="text/javascript">
    -   try {
    -diff --git a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v17.leanback.widget.DetailsOverviewLogoPresenter.html b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v17.leanback.widget.DetailsOverviewLogoPresenter.html
    -index 74e170c..05a2205 100644
    ---- a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v17.leanback.widget.DetailsOverviewLogoPresenter.html
    -+++ b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v17.leanback.widget.DetailsOverviewLogoPresenter.html
    -@@ -108,7 +108,7 @@ Class android.support.v17.leanback.widget.<A HREF="../../../../reference/android
    -     </div> <!-- end footer -->
    -     </div><!-- end doc-content -->
    -     </div> <!-- end body-content --> 
    --<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    - </script>
    - <script type="text/javascript">
    -   try {
    -diff --git a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v17.leanback.widget.GuidanceStylist.html b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v17.leanback.widget.GuidanceStylist.html
    -index 0a20eb4..f67942e 100644
    ---- a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v17.leanback.widget.GuidanceStylist.html
    -+++ b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v17.leanback.widget.GuidanceStylist.html
    -@@ -108,7 +108,7 @@ Class android.support.v17.leanback.widget.<A HREF="../../../../reference/android
    -     </div> <!-- end footer -->
    -     </div><!-- end doc-content -->
    -     </div> <!-- end body-content --> 
    --<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    - </script>
    - <script type="text/javascript">
    -   try {
    -diff --git a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v17.leanback.widget.GuidedAction.Builder.html b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v17.leanback.widget.GuidedAction.Builder.html
    -index b77684b..4d1d86b 100644
    ---- a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v17.leanback.widget.GuidedAction.Builder.html
    -+++ b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v17.leanback.widget.GuidedAction.Builder.html
    -@@ -281,7 +281,7 @@ Change in return type from <code>Builder</code> to <code>B</code>.<br>
    -     </div> <!-- end footer -->
    -     </div><!-- end doc-content -->
    -     </div> <!-- end body-content --> 
    --<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    - </script>
    - <script type="text/javascript">
    -   try {
    -diff --git a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v17.leanback.widget.GuidedAction.html b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v17.leanback.widget.GuidedAction.html
    -index 20165c7..2ce2773 100644
    ---- a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v17.leanback.widget.GuidedAction.html
    -+++ b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v17.leanback.widget.GuidedAction.html
    -@@ -307,7 +307,7 @@ Class android.support.v17.leanback.widget.<A HREF="../../../../reference/android
    -     </div> <!-- end footer -->
    -     </div><!-- end doc-content -->
    -     </div> <!-- end body-content --> 
    --<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    - </script>
    - <script type="text/javascript">
    -   try {
    -diff --git a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v17.leanback.widget.GuidedActionsStylist.ViewHolder.html b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v17.leanback.widget.GuidedActionsStylist.ViewHolder.html
    -index 0849383..b9b78cb 100644
    ---- a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v17.leanback.widget.GuidedActionsStylist.ViewHolder.html
    -+++ b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v17.leanback.widget.GuidedActionsStylist.ViewHolder.html
    -@@ -195,7 +195,7 @@ Class android.support.v17.leanback.widget.<A HREF="../../../../reference/android
    -     </div> <!-- end footer -->
    -     </div><!-- end doc-content -->
    -     </div> <!-- end body-content --> 
    --<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    - </script>
    - <script type="text/javascript">
    -   try {
    -diff --git a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v17.leanback.widget.GuidedActionsStylist.html b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v17.leanback.widget.GuidedActionsStylist.html
    -index a8dff6f..fbe6bb4 100644
    ---- a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v17.leanback.widget.GuidedActionsStylist.html
    -+++ b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v17.leanback.widget.GuidedActionsStylist.html
    -@@ -306,7 +306,7 @@ Class android.support.v17.leanback.widget.<A HREF="../../../../reference/android
    -     </div> <!-- end footer -->
    -     </div><!-- end doc-content -->
    -     </div> <!-- end body-content --> 
    --<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    - </script>
    - <script type="text/javascript">
    -   try {
    -diff --git a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v17.leanback.widget.ImageCardView.html b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v17.leanback.widget.ImageCardView.html
    -index f110a16..dde52dd 100644
    ---- a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v17.leanback.widget.ImageCardView.html
    -+++ b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v17.leanback.widget.ImageCardView.html
    -@@ -111,7 +111,7 @@ Class android.support.v17.leanback.widget.<A HREF="../../../../reference/android
    -     </div> <!-- end footer -->
    -     </div><!-- end doc-content -->
    -     </div> <!-- end body-content --> 
    --<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    - </script>
    - <script type="text/javascript">
    -   try {
    -diff --git a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v17.leanback.widget.ListRowPresenter.ViewHolder.html b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v17.leanback.widget.ListRowPresenter.ViewHolder.html
    -index 2207a6d..9aadb33 100644
    ---- a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v17.leanback.widget.ListRowPresenter.ViewHolder.html
    -+++ b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v17.leanback.widget.ListRowPresenter.ViewHolder.html
    -@@ -115,7 +115,7 @@ Class android.support.v17.leanback.widget.<A HREF="../../../../reference/android
    -     </div> <!-- end footer -->
    -     </div><!-- end doc-content -->
    -     </div> <!-- end body-content --> 
    --<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    - </script>
    - <script type="text/javascript">
    -   try {
    -diff --git a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.accessibilityservice.AccessibilityServiceInfoCompat.html b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.accessibilityservice.AccessibilityServiceInfoCompat.html
    -index 2479a86..4545dc6 100644
    ---- a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.accessibilityservice.AccessibilityServiceInfoCompat.html
    -+++ b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.accessibilityservice.AccessibilityServiceInfoCompat.html
    -@@ -94,7 +94,7 @@ Class android.support.v4.accessibilityservice.<A HREF="../../../../reference/and
    -     </div> <!-- end footer -->
    -     </div><!-- end doc-content -->
    -     </div> <!-- end body-content --> 
    --<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    - </script>
    - <script type="text/javascript">
    -   try {
    -diff --git a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.app.AppOpsManagerCompat.html b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.app.AppOpsManagerCompat.html
    -index 15ddb44..8d4b281 100644
    ---- a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.app.AppOpsManagerCompat.html
    -+++ b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.app.AppOpsManagerCompat.html
    -@@ -109,7 +109,7 @@ Class android.support.v4.app.<A HREF="../../../../reference/android/support/v4/a
    -     </div> <!-- end footer -->
    -     </div><!-- end doc-content -->
    -     </div> <!-- end body-content --> 
    --<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    - </script>
    - <script type="text/javascript">
    -   try {
    -diff --git a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.app.BundleCompat.html b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.app.BundleCompat.html
    -index 63ecf79..65cb6ce 100644
    ---- a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.app.BundleCompat.html
    -+++ b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.app.BundleCompat.html
    -@@ -109,7 +109,7 @@ Class android.support.v4.app.<A HREF="../../../../reference/android/support/v4/a
    -     </div> <!-- end footer -->
    -     </div><!-- end doc-content -->
    -     </div> <!-- end body-content --> 
    --<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    - </script>
    - <script type="text/javascript">
    -   try {
    -diff --git a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.app.Fragment.html b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.app.Fragment.html
    -index d6c9e88..adb8e8a 100644
    ---- a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.app.Fragment.html
    -+++ b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.app.Fragment.html
    -@@ -115,7 +115,7 @@ Class android.support.v4.app.<A HREF="../../../../reference/android/support/v4/a
    -     </div> <!-- end footer -->
    -     </div><!-- end doc-content -->
    -     </div> <!-- end body-content --> 
    --<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    - </script>
    - <script type="text/javascript">
    -   try {
    -diff --git a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.app.FragmentActivity.html b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.app.FragmentActivity.html
    -index 72bd4de..843cf68 100644
    ---- a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.app.FragmentActivity.html
    -+++ b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.app.FragmentActivity.html
    -@@ -108,7 +108,7 @@ Class android.support.v4.app.<A HREF="../../../../reference/android/support/v4/a
    -     </div> <!-- end footer -->
    -     </div><!-- end doc-content -->
    -     </div> <!-- end body-content --> 
    --<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    - </script>
    - <script type="text/javascript">
    -   try {
    -diff --git a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.app.FragmentHostCallback.html b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.app.FragmentHostCallback.html
    -index fcb311f..ca9cab8 100644
    ---- a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.app.FragmentHostCallback.html
    -+++ b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.app.FragmentHostCallback.html
    -@@ -108,7 +108,7 @@ Class android.support.v4.app.<A HREF="../../../../reference/android/support/v4/a
    -     </div> <!-- end footer -->
    -     </div><!-- end doc-content -->
    -     </div> <!-- end body-content --> 
    --<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    - </script>
    - <script type="text/javascript">
    -   try {
    -diff --git a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.app.NavUtils.html b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.app.NavUtils.html
    -index e4fb7fa..7267e50 100644
    ---- a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.app.NavUtils.html
    -+++ b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.app.NavUtils.html
    -@@ -94,7 +94,7 @@ Class android.support.v4.app.<A HREF="../../../../reference/android/support/v4/a
    -     </div> <!-- end footer -->
    -     </div><!-- end doc-content -->
    -     </div> <!-- end body-content --> 
    --<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    - </script>
    - <script type="text/javascript">
    -   try {
    -diff --git a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.app.NotificationManagerCompat.html b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.app.NotificationManagerCompat.html
    -index be48aac..06346b2 100644
    ---- a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.app.NotificationManagerCompat.html
    -+++ b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.app.NotificationManagerCompat.html
    -@@ -94,7 +94,7 @@ Class android.support.v4.app.<A HREF="../../../../reference/android/support/v4/a
    -     </div> <!-- end footer -->
    -     </div><!-- end doc-content -->
    -     </div> <!-- end body-content --> 
    --<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    - </script>
    - <script type="text/javascript">
    -   try {
    -diff --git a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.app.RemoteInput.html b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.app.RemoteInput.html
    -index a6a2a2d..006eeee 100644
    ---- a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.app.RemoteInput.html
    -+++ b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.app.RemoteInput.html
    -@@ -94,7 +94,7 @@ Class android.support.v4.app.<A HREF="../../../../reference/android/support/v4/a
    -     </div> <!-- end footer -->
    -     </div><!-- end doc-content -->
    -     </div> <!-- end body-content --> 
    --<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    - </script>
    - <script type="text/javascript">
    -   try {
    -diff --git a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.app.ServiceCompat.html b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.app.ServiceCompat.html
    -index c038e52..613affe 100644
    ---- a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.app.ServiceCompat.html
    -+++ b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.app.ServiceCompat.html
    -@@ -94,7 +94,7 @@ Class android.support.v4.app.<A HREF="../../../../reference/android/support/v4/a
    -     </div> <!-- end footer -->
    -     </div><!-- end doc-content -->
    -     </div> <!-- end body-content --> 
    --<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    - </script>
    - <script type="text/javascript">
    -   try {
    -diff --git a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.app.ShareCompat.html b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.app.ShareCompat.html
    -index 8e9c945..90c0630 100644
    ---- a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.app.ShareCompat.html
    -+++ b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.app.ShareCompat.html
    -@@ -109,7 +109,7 @@ Class android.support.v4.app.<A HREF="../../../../reference/android/support/v4/a
    -     </div> <!-- end footer -->
    -     </div><!-- end doc-content -->
    -     </div> <!-- end body-content --> 
    --<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    - </script>
    - <script type="text/javascript">
    -   try {
    -diff --git a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.app.TaskStackBuilder.html b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.app.TaskStackBuilder.html
    -index 8a8a3c7..12d44de 100644
    ---- a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.app.TaskStackBuilder.html
    -+++ b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.app.TaskStackBuilder.html
    -@@ -94,7 +94,7 @@ Class android.support.v4.app.<A HREF="../../../../reference/android/support/v4/a
    -     </div> <!-- end footer -->
    -     </div><!-- end doc-content -->
    -     </div> <!-- end body-content --> 
    --<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    - </script>
    - <script type="text/javascript">
    -   try {
    -diff --git a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.content.ContentResolverCompat.html b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.content.ContentResolverCompat.html
    -index 6abd31a..37ab80d 100644
    ---- a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.content.ContentResolverCompat.html
    -+++ b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.content.ContentResolverCompat.html
    -@@ -94,7 +94,7 @@ Class android.support.v4.content.<A HREF="../../../../reference/android/support/
    -     </div> <!-- end footer -->
    -     </div><!-- end doc-content -->
    -     </div> <!-- end body-content --> 
    --<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    - </script>
    - <script type="text/javascript">
    -   try {
    -diff --git a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.content.ContextCompat.html b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.content.ContextCompat.html
    -index c0abad2..92f9469 100644
    ---- a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.content.ContextCompat.html
    -+++ b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.content.ContextCompat.html
    -@@ -111,7 +111,7 @@ Change from non-static to static.<br> Change from final to non-final.<br>
    -     </div> <!-- end footer -->
    -     </div><!-- end doc-content -->
    -     </div> <!-- end body-content --> 
    --<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    - </script>
    - <script type="text/javascript">
    -   try {
    -diff --git a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.content.IntentCompat.html b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.content.IntentCompat.html
    -index 707b2de..37a8b42 100644
    ---- a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.content.IntentCompat.html
    -+++ b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.content.IntentCompat.html
    -@@ -94,7 +94,7 @@ Class android.support.v4.content.<A HREF="../../../../reference/android/support/
    -     </div> <!-- end footer -->
    -     </div><!-- end doc-content -->
    -     </div> <!-- end body-content --> 
    --<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    - </script>
    - <script type="text/javascript">
    -   try {
    -diff --git a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.content.LocalBroadcastManager.html b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.content.LocalBroadcastManager.html
    -index fb0f8eb..a3d8f89 100644
    ---- a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.content.LocalBroadcastManager.html
    -+++ b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.content.LocalBroadcastManager.html
    -@@ -94,7 +94,7 @@ Class android.support.v4.content.<A HREF="../../../../reference/android/support/
    -     </div> <!-- end footer -->
    -     </div><!-- end doc-content -->
    -     </div> <!-- end body-content --> 
    --<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    - </script>
    - <script type="text/javascript">
    -   try {
    -diff --git a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.content.ParallelExecutorCompat.html b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.content.ParallelExecutorCompat.html
    -index 135c65a..3dd3598 100644
    ---- a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.content.ParallelExecutorCompat.html
    -+++ b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.content.ParallelExecutorCompat.html
    -@@ -109,7 +109,7 @@ Class android.support.v4.content.<A HREF="../../../../reference/android/support/
    -     </div> <!-- end footer -->
    -     </div><!-- end doc-content -->
    -     </div> <!-- end body-content --> 
    --<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    - </script>
    - <script type="text/javascript">
    -   try {
    -diff --git a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.content.SharedPreferencesCompat.EditorCompat.html b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.content.SharedPreferencesCompat.EditorCompat.html
    -index 2a46cc8..5159fec 100644
    ---- a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.content.SharedPreferencesCompat.EditorCompat.html
    -+++ b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.content.SharedPreferencesCompat.EditorCompat.html
    -@@ -94,7 +94,7 @@ Class android.support.v4.content.<A HREF="../../../../reference/android/support/
    -     </div> <!-- end footer -->
    -     </div><!-- end doc-content -->
    -     </div> <!-- end body-content --> 
    --<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    - </script>
    - <script type="text/javascript">
    -   try {
    -diff --git a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.content.SharedPreferencesCompat.html b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.content.SharedPreferencesCompat.html
    -index 99e7e84..3c4513a 100644
    ---- a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.content.SharedPreferencesCompat.html
    -+++ b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.content.SharedPreferencesCompat.html
    -@@ -109,7 +109,7 @@ Class android.support.v4.content.<A HREF="../../../../reference/android/support/
    -     </div> <!-- end footer -->
    -     </div><!-- end doc-content -->
    -     </div> <!-- end body-content --> 
    --<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    - </script>
    - <script type="text/javascript">
    -   try {
    -diff --git a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.content.pm.ActivityInfoCompat.html b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.content.pm.ActivityInfoCompat.html
    -index 201f6e2..1fa3936 100644
    ---- a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.content.pm.ActivityInfoCompat.html
    -+++ b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.content.pm.ActivityInfoCompat.html
    -@@ -94,7 +94,7 @@ Class android.support.v4.content.pm.<A HREF="../../../../reference/android/suppo
    -     </div> <!-- end footer -->
    -     </div><!-- end doc-content -->
    -     </div> <!-- end body-content --> 
    --<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    - </script>
    - <script type="text/javascript">
    -   try {
    -diff --git a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.content.res.ResourcesCompat.html b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.content.res.ResourcesCompat.html
    -index 497d73b..77e6d43 100644
    ---- a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.content.res.ResourcesCompat.html
    -+++ b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.content.res.ResourcesCompat.html
    -@@ -137,7 +137,7 @@ Change from non-static to static.<br>
    -     </div> <!-- end footer -->
    -     </div><!-- end doc-content -->
    -     </div> <!-- end body-content --> 
    --<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    - </script>
    - <script type="text/javascript">
    -   try {
    -diff --git a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.database.DatabaseUtilsCompat.html b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.database.DatabaseUtilsCompat.html
    -index 0feb04b..90a5d72 100644
    ---- a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.database.DatabaseUtilsCompat.html
    -+++ b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.database.DatabaseUtilsCompat.html
    -@@ -94,7 +94,7 @@ Class android.support.v4.database.<A HREF="../../../../reference/android/support
    -     </div> <!-- end footer -->
    -     </div><!-- end doc-content -->
    -     </div> <!-- end body-content --> 
    --<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    - </script>
    - <script type="text/javascript">
    -   try {
    -diff --git a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.graphics.BitmapCompat.html b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.graphics.BitmapCompat.html
    -index 3b50f8e..912d5ee 100644
    ---- a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.graphics.BitmapCompat.html
    -+++ b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.graphics.BitmapCompat.html
    -@@ -109,7 +109,7 @@ Class android.support.v4.graphics.<A HREF="../../../../reference/android/support
    -     </div> <!-- end footer -->
    -     </div><!-- end doc-content -->
    -     </div> <!-- end body-content --> 
    --<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    - </script>
    - <script type="text/javascript">
    -   try {
    -diff --git a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.graphics.ColorUtils.html b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.graphics.ColorUtils.html
    -index 68c2dce..1dfcdc5 100644
    ---- a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.graphics.ColorUtils.html
    -+++ b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.graphics.ColorUtils.html
    -@@ -186,7 +186,7 @@ Class android.support.v4.graphics.<A HREF="../../../../reference/android/support
    -     </div> <!-- end footer -->
    -     </div><!-- end doc-content -->
    -     </div> <!-- end body-content --> 
    --<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    - </script>
    - <script type="text/javascript">
    -   try {
    -diff --git a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.graphics.drawable.DrawableCompat.html b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.graphics.drawable.DrawableCompat.html
    -index 735909e..041cbfd 100644
    ---- a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.graphics.drawable.DrawableCompat.html
    -+++ b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.graphics.drawable.DrawableCompat.html
    -@@ -152,7 +152,7 @@ Class android.support.v4.graphics.drawable.<A HREF="../../../../reference/androi
    -     </div> <!-- end footer -->
    -     </div><!-- end doc-content -->
    -     </div> <!-- end body-content --> 
    --<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    - </script>
    - <script type="text/javascript">
    -   try {
    -diff --git a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.graphics.drawable.RoundedBitmapDrawableFactory.html b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.graphics.drawable.RoundedBitmapDrawableFactory.html
    -index f0e4cbf..2323bf0 100644
    ---- a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.graphics.drawable.RoundedBitmapDrawableFactory.html
    -+++ b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.graphics.drawable.RoundedBitmapDrawableFactory.html
    -@@ -109,7 +109,7 @@ Class android.support.v4.graphics.drawable.<A HREF="../../../../reference/androi
    -     </div> <!-- end footer -->
    -     </div><!-- end doc-content -->
    -     </div> <!-- end body-content --> 
    --<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    - </script>
    - <script type="text/javascript">
    -   try {
    -diff --git a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.hardware.fingerprint.FingerprintManagerCompat.html b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.hardware.fingerprint.FingerprintManagerCompat.html
    -index 3c5e74d..8a49a32 100644
    ---- a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.hardware.fingerprint.FingerprintManagerCompat.html
    -+++ b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.hardware.fingerprint.FingerprintManagerCompat.html
    -@@ -94,7 +94,7 @@ Class android.support.v4.hardware.fingerprint.<A HREF="../../../../reference/and
    -     </div> <!-- end footer -->
    -     </div><!-- end doc-content -->
    -     </div> <!-- end body-content --> 
    --<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    - </script>
    - <script type="text/javascript">
    -   try {
    -diff --git a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.net.ConnectivityManagerCompat.html b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.net.ConnectivityManagerCompat.html
    -index 585fbe1..45e77fa 100644
    ---- a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.net.ConnectivityManagerCompat.html
    -+++ b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.net.ConnectivityManagerCompat.html
    -@@ -109,7 +109,7 @@ Class android.support.v4.net.<A HREF="../../../../reference/android/support/v4/n
    -     </div> <!-- end footer -->
    -     </div><!-- end doc-content -->
    -     </div> <!-- end body-content --> 
    --<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    - </script>
    - <script type="text/javascript">
    -   try {
    -diff --git a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.net.TrafficStatsCompat.html b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.net.TrafficStatsCompat.html
    -index d8d8d74..89403e7 100644
    ---- a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.net.TrafficStatsCompat.html
    -+++ b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.net.TrafficStatsCompat.html
    -@@ -109,7 +109,7 @@ Class android.support.v4.net.<A HREF="../../../../reference/android/support/v4/n
    -     </div> <!-- end footer -->
    -     </div><!-- end doc-content -->
    -     </div> <!-- end body-content --> 
    --<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    - </script>
    - <script type="text/javascript">
    -   try {
    -diff --git a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.os.AsyncTaskCompat.html b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.os.AsyncTaskCompat.html
    -index 0ea4b47..fcde361 100644
    ---- a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.os.AsyncTaskCompat.html
    -+++ b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.os.AsyncTaskCompat.html
    -@@ -109,7 +109,7 @@ Class android.support.v4.os.<A HREF="../../../../reference/android/support/v4/os
    -     </div> <!-- end footer -->
    -     </div><!-- end doc-content -->
    -     </div> <!-- end body-content --> 
    --<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    - </script>
    - <script type="text/javascript">
    -   try {
    -diff --git a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.os.EnvironmentCompat.html b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.os.EnvironmentCompat.html
    -index 4d625b1..914f3f0 100644
    ---- a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.os.EnvironmentCompat.html
    -+++ b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.os.EnvironmentCompat.html
    -@@ -109,7 +109,7 @@ Class android.support.v4.os.<A HREF="../../../../reference/android/support/v4/os
    -     </div> <!-- end footer -->
    -     </div><!-- end doc-content -->
    -     </div> <!-- end body-content --> 
    --<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    - </script>
    - <script type="text/javascript">
    -   try {
    -diff --git a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.os.ParcelableCompat.html b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.os.ParcelableCompat.html
    -index 0192ed6..8933edd 100644
    ---- a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.os.ParcelableCompat.html
    -+++ b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.os.ParcelableCompat.html
    -@@ -109,7 +109,7 @@ Class android.support.v4.os.<A HREF="../../../../reference/android/support/v4/os
    -     </div> <!-- end footer -->
    -     </div><!-- end doc-content -->
    -     </div> <!-- end body-content --> 
    --<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    - </script>
    - <script type="text/javascript">
    -   try {
    -diff --git a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.os.TraceCompat.html b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.os.TraceCompat.html
    -index 3f490ba..8778c2e4 100644
    ---- a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.os.TraceCompat.html
    -+++ b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.os.TraceCompat.html
    -@@ -109,7 +109,7 @@ Class android.support.v4.os.<A HREF="../../../../reference/android/support/v4/os
    -     </div> <!-- end footer -->
    -     </div><!-- end doc-content -->
    -     </div> <!-- end body-content --> 
    --<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    - </script>
    - <script type="text/javascript">
    -   try {
    -diff --git a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.text.ICUCompat.html b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.text.ICUCompat.html
    -index 2b97440..c4ea966 100644
    ---- a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.text.ICUCompat.html
    -+++ b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.text.ICUCompat.html
    -@@ -109,7 +109,7 @@ Class android.support.v4.text.<A HREF="../../../../reference/android/support/v4/
    -     </div> <!-- end footer -->
    -     </div><!-- end doc-content -->
    -     </div> <!-- end body-content --> 
    --<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    - </script>
    - <script type="text/javascript">
    -   try {
    -diff --git a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.text.TextDirectionHeuristicsCompat.html b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.text.TextDirectionHeuristicsCompat.html
    -index 45557e1..351a162 100644
    ---- a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.text.TextDirectionHeuristicsCompat.html
    -+++ b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.text.TextDirectionHeuristicsCompat.html
    -@@ -109,7 +109,7 @@ Class android.support.v4.text.<A HREF="../../../../reference/android/support/v4/
    -     </div> <!-- end footer -->
    -     </div><!-- end doc-content -->
    -     </div> <!-- end body-content --> 
    --<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    - </script>
    - <script type="text/javascript">
    -   try {
    -diff --git a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.text.TextUtilsCompat.html b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.text.TextUtilsCompat.html
    -index 16d0835..d3ab7ce 100644
    ---- a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.text.TextUtilsCompat.html
    -+++ b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.text.TextUtilsCompat.html
    -@@ -109,7 +109,7 @@ Class android.support.v4.text.<A HREF="../../../../reference/android/support/v4/
    -     </div> <!-- end footer -->
    -     </div><!-- end doc-content -->
    -     </div> <!-- end body-content --> 
    --<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    - </script>
    - <script type="text/javascript">
    -   try {
    -diff --git a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.view.GestureDetectorCompat.html b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.view.GestureDetectorCompat.html
    -index 5c0463d..e66c261 100644
    ---- a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.view.GestureDetectorCompat.html
    -+++ b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.view.GestureDetectorCompat.html
    -@@ -94,7 +94,7 @@ Class android.support.v4.view.<A HREF="../../../../reference/android/support/v4/
    -     </div> <!-- end footer -->
    -     </div><!-- end doc-content -->
    -     </div> <!-- end body-content --> 
    --<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    - </script>
    - <script type="text/javascript">
    -   try {
    -diff --git a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.view.GravityCompat.html b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.view.GravityCompat.html
    -index 9ee14c5..95c665e 100644
    ---- a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.view.GravityCompat.html
    -+++ b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.view.GravityCompat.html
    -@@ -109,7 +109,7 @@ Class android.support.v4.view.<A HREF="../../../../reference/android/support/v4/
    -     </div> <!-- end footer -->
    -     </div><!-- end doc-content -->
    -     </div> <!-- end body-content --> 
    --<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    - </script>
    - <script type="text/javascript">
    -   try {
    -diff --git a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.view.InputDeviceCompat.html b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.view.InputDeviceCompat.html
    -index 4a7f385..38a1cd8 100644
    ---- a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.view.InputDeviceCompat.html
    -+++ b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.view.InputDeviceCompat.html
    -@@ -109,7 +109,7 @@ Class android.support.v4.view.<A HREF="../../../../reference/android/support/v4/
    -     </div> <!-- end footer -->
    -     </div><!-- end doc-content -->
    -     </div> <!-- end body-content --> 
    --<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    - </script>
    - <script type="text/javascript">
    -   try {
    -diff --git a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.view.KeyEventCompat.html b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.view.KeyEventCompat.html
    -index 49526ab..58692a9 100644
    ---- a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.view.KeyEventCompat.html
    -+++ b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.view.KeyEventCompat.html
    -@@ -109,7 +109,7 @@ Class android.support.v4.view.<A HREF="../../../../reference/android/support/v4/
    -     </div> <!-- end footer -->
    -     </div><!-- end doc-content -->
    -     </div> <!-- end body-content --> 
    --<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    - </script>
    - <script type="text/javascript">
    -   try {
    -diff --git a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.view.LayoutInflaterCompat.html b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.view.LayoutInflaterCompat.html
    -index 7329ff7..b62e876 100644
    ---- a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.view.LayoutInflaterCompat.html
    -+++ b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.view.LayoutInflaterCompat.html
    -@@ -109,7 +109,7 @@ Class android.support.v4.view.<A HREF="../../../../reference/android/support/v4/
    -     </div> <!-- end footer -->
    -     </div><!-- end doc-content -->
    -     </div> <!-- end body-content --> 
    --<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    - </script>
    - <script type="text/javascript">
    -   try {
    -diff --git a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.view.MarginLayoutParamsCompat.html b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.view.MarginLayoutParamsCompat.html
    -index 86a7b57..444980d 100644
    ---- a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.view.MarginLayoutParamsCompat.html
    -+++ b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.view.MarginLayoutParamsCompat.html
    -@@ -109,7 +109,7 @@ Class android.support.v4.view.<A HREF="../../../../reference/android/support/v4/
    -     </div> <!-- end footer -->
    -     </div><!-- end doc-content -->
    -     </div> <!-- end body-content --> 
    --<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    - </script>
    - <script type="text/javascript">
    -   try {
    -diff --git a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.view.MenuCompat.html b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.view.MenuCompat.html
    -index 22ead5e..17b8b7d 100644
    ---- a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.view.MenuCompat.html
    -+++ b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.view.MenuCompat.html
    -@@ -109,7 +109,7 @@ Class android.support.v4.view.<A HREF="../../../../reference/android/support/v4/
    -     </div> <!-- end footer -->
    -     </div><!-- end doc-content -->
    -     </div> <!-- end body-content --> 
    --<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    - </script>
    - <script type="text/javascript">
    -   try {
    -diff --git a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.view.MenuItemCompat.html b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.view.MenuItemCompat.html
    -index a321ac3..415dae2 100644
    ---- a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.view.MenuItemCompat.html
    -+++ b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.view.MenuItemCompat.html
    -@@ -109,7 +109,7 @@ Class android.support.v4.view.<A HREF="../../../../reference/android/support/v4/
    -     </div> <!-- end footer -->
    -     </div><!-- end doc-content -->
    -     </div> <!-- end body-content --> 
    --<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    - </script>
    - <script type="text/javascript">
    -   try {
    -diff --git a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.view.MotionEventCompat.html b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.view.MotionEventCompat.html
    -index cb8895d..c1f81ba 100644
    ---- a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.view.MotionEventCompat.html
    -+++ b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.view.MotionEventCompat.html
    -@@ -109,7 +109,7 @@ Class android.support.v4.view.<A HREF="../../../../reference/android/support/v4/
    -     </div> <!-- end footer -->
    -     </div><!-- end doc-content -->
    -     </div> <!-- end body-content --> 
    --<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    - </script>
    - <script type="text/javascript">
    -   try {
    -diff --git a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.view.ScaleGestureDetectorCompat.html b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.view.ScaleGestureDetectorCompat.html
    -index 23f8718..8733e6b 100644
    ---- a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.view.ScaleGestureDetectorCompat.html
    -+++ b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.view.ScaleGestureDetectorCompat.html
    -@@ -94,7 +94,7 @@ Class android.support.v4.view.<A HREF="../../../../reference/android/support/v4/
    -     </div> <!-- end footer -->
    -     </div><!-- end doc-content -->
    -     </div> <!-- end body-content --> 
    --<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    - </script>
    - <script type="text/javascript">
    -   try {
    -diff --git a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.view.VelocityTrackerCompat.html b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.view.VelocityTrackerCompat.html
    -index 31a2b66..078bb96 100644
    ---- a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.view.VelocityTrackerCompat.html
    -+++ b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.view.VelocityTrackerCompat.html
    -@@ -109,7 +109,7 @@ Class android.support.v4.view.<A HREF="../../../../reference/android/support/v4/
    -     </div> <!-- end footer -->
    -     </div><!-- end doc-content -->
    -     </div> <!-- end body-content --> 
    --<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    - </script>
    - <script type="text/javascript">
    -   try {
    -diff --git a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.view.ViewCompat.html b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.view.ViewCompat.html
    -index bbfebc1..0647acb 100644
    ---- a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.view.ViewCompat.html
    -+++ b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.view.ViewCompat.html
    -@@ -109,7 +109,7 @@ Class android.support.v4.view.<A HREF="../../../../reference/android/support/v4/
    -     </div> <!-- end footer -->
    -     </div><!-- end doc-content -->
    -     </div> <!-- end body-content --> 
    --<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    - </script>
    - <script type="text/javascript">
    -   try {
    -diff --git a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.view.ViewConfigurationCompat.html b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.view.ViewConfigurationCompat.html
    -index 3deb282..0721e0c 100644
    ---- a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.view.ViewConfigurationCompat.html
    -+++ b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.view.ViewConfigurationCompat.html
    -@@ -109,7 +109,7 @@ Class android.support.v4.view.<A HREF="../../../../reference/android/support/v4/
    -     </div> <!-- end footer -->
    -     </div><!-- end doc-content -->
    -     </div> <!-- end body-content --> 
    --<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    - </script>
    - <script type="text/javascript">
    -   try {
    -diff --git a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.view.ViewGroupCompat.html b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.view.ViewGroupCompat.html
    -index 973f25d..7c3f280 100644
    ---- a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.view.ViewGroupCompat.html
    -+++ b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.view.ViewGroupCompat.html
    -@@ -94,7 +94,7 @@ Class android.support.v4.view.<A HREF="../../../../reference/android/support/v4/
    -     </div> <!-- end footer -->
    -     </div><!-- end doc-content -->
    -     </div> <!-- end body-content --> 
    --<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    - </script>
    - <script type="text/javascript">
    -   try {
    -diff --git a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.view.ViewParentCompat.html b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.view.ViewParentCompat.html
    -index 0ff6977..186cdce 100644
    ---- a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.view.ViewParentCompat.html
    -+++ b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.view.ViewParentCompat.html
    -@@ -94,7 +94,7 @@ Class android.support.v4.view.<A HREF="../../../../reference/android/support/v4/
    -     </div> <!-- end footer -->
    -     </div><!-- end doc-content -->
    -     </div> <!-- end body-content --> 
    --<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    - </script>
    - <script type="text/javascript">
    -   try {
    -diff --git a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.view.ViewPropertyAnimatorCompat.html b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.view.ViewPropertyAnimatorCompat.html
    -index dcb75fc..7611f00 100644
    ---- a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.view.ViewPropertyAnimatorCompat.html
    -+++ b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.view.ViewPropertyAnimatorCompat.html
    -@@ -94,7 +94,7 @@ Class android.support.v4.view.<A HREF="../../../../reference/android/support/v4/
    -     </div> <!-- end footer -->
    -     </div><!-- end doc-content -->
    -     </div> <!-- end body-content --> 
    --<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    - </script>
    - <script type="text/javascript">
    -   try {
    -diff --git a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.view.WindowCompat.html b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.view.WindowCompat.html
    -index a9711fa..bf16942a 100644
    ---- a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.view.WindowCompat.html
    -+++ b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.view.WindowCompat.html
    -@@ -109,7 +109,7 @@ Class android.support.v4.view.<A HREF="../../../../reference/android/support/v4/
    -     </div> <!-- end footer -->
    -     </div><!-- end doc-content -->
    -     </div> <!-- end body-content --> 
    --<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    - </script>
    - <script type="text/javascript">
    -   try {
    -diff --git a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.view.accessibility.AccessibilityEventCompat.html b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.view.accessibility.AccessibilityEventCompat.html
    -index e2045d7..b9b15c8 100644
    ---- a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.view.accessibility.AccessibilityEventCompat.html
    -+++ b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.view.accessibility.AccessibilityEventCompat.html
    -@@ -94,7 +94,7 @@ Class android.support.v4.view.accessibility.<A HREF="../../../../reference/andro
    -     </div> <!-- end footer -->
    -     </div><!-- end doc-content -->
    -     </div> <!-- end body-content --> 
    --<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    - </script>
    - <script type="text/javascript">
    -   try {
    -diff --git a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.view.accessibility.AccessibilityManagerCompat.html b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.view.accessibility.AccessibilityManagerCompat.html
    -index d74f936..5180523 100644
    ---- a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.view.accessibility.AccessibilityManagerCompat.html
    -+++ b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.view.accessibility.AccessibilityManagerCompat.html
    -@@ -109,7 +109,7 @@ Class android.support.v4.view.accessibility.<A HREF="../../../../reference/andro
    -     </div> <!-- end footer -->
    -     </div><!-- end doc-content -->
    -     </div> <!-- end body-content --> 
    --<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    - </script>
    - <script type="text/javascript">
    -   try {
    -diff --git a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.view.animation.PathInterpolatorCompat.html b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.view.animation.PathInterpolatorCompat.html
    -index 6701f77..715f73f 100644
    ---- a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.view.animation.PathInterpolatorCompat.html
    -+++ b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.view.animation.PathInterpolatorCompat.html
    -@@ -94,7 +94,7 @@ Class android.support.v4.view.animation.<A HREF="../../../../reference/android/s
    -     </div> <!-- end footer -->
    -     </div><!-- end doc-content -->
    -     </div> <!-- end body-content --> 
    --<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    - </script>
    - <script type="text/javascript">
    -   try {
    -diff --git a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.widget.DrawerLayout.html b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.widget.DrawerLayout.html
    -index c2e7c83..f859501 100644
    ---- a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.widget.DrawerLayout.html
    -+++ b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.widget.DrawerLayout.html
    -@@ -148,7 +148,7 @@ Class android.support.v4.widget.<A HREF="../../../../reference/android/support/v
    -     </div> <!-- end footer -->
    -     </div><!-- end doc-content -->
    -     </div> <!-- end body-content --> 
    --<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    - </script>
    - <script type="text/javascript">
    -   try {
    -diff --git a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.widget.EdgeEffectCompat.html b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.widget.EdgeEffectCompat.html
    -index 6993bec..a476dfb 100644
    ---- a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.widget.EdgeEffectCompat.html
    -+++ b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.widget.EdgeEffectCompat.html
    -@@ -94,7 +94,7 @@ Class android.support.v4.widget.<A HREF="../../../../reference/android/support/v
    -     </div> <!-- end footer -->
    -     </div><!-- end doc-content -->
    -     </div> <!-- end body-content --> 
    --<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    - </script>
    - <script type="text/javascript">
    -   try {
    -diff --git a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.widget.ListPopupWindowCompat.html b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.widget.ListPopupWindowCompat.html
    -index fc5ed8d..243f6d2 100644
    ---- a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.widget.ListPopupWindowCompat.html
    -+++ b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.widget.ListPopupWindowCompat.html
    -@@ -94,7 +94,7 @@ Class android.support.v4.widget.<A HREF="../../../../reference/android/support/v
    -     </div> <!-- end footer -->
    -     </div><!-- end doc-content -->
    -     </div> <!-- end body-content --> 
    --<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    - </script>
    - <script type="text/javascript">
    -   try {
    -diff --git a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.widget.PopupMenuCompat.html b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.widget.PopupMenuCompat.html
    -index 1d55628..c3cca70 100644
    ---- a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.widget.PopupMenuCompat.html
    -+++ b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.widget.PopupMenuCompat.html
    -@@ -94,7 +94,7 @@ Class android.support.v4.widget.<A HREF="../../../../reference/android/support/v
    -     </div> <!-- end footer -->
    -     </div><!-- end doc-content -->
    -     </div> <!-- end body-content --> 
    --<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    - </script>
    - <script type="text/javascript">
    -   try {
    -diff --git a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.widget.PopupWindowCompat.html b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.widget.PopupWindowCompat.html
    -index 215118c..0523e9f 100644
    ---- a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.widget.PopupWindowCompat.html
    -+++ b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.widget.PopupWindowCompat.html
    -@@ -94,7 +94,7 @@ Class android.support.v4.widget.<A HREF="../../../../reference/android/support/v
    -     </div> <!-- end footer -->
    -     </div><!-- end doc-content -->
    -     </div> <!-- end body-content --> 
    --<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    - </script>
    - <script type="text/javascript">
    -   try {
    -diff --git a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.widget.ScrollerCompat.html b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.widget.ScrollerCompat.html
    -index ea76c92..f13086d 100644
    ---- a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.widget.ScrollerCompat.html
    -+++ b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.widget.ScrollerCompat.html
    -@@ -94,7 +94,7 @@ Class android.support.v4.widget.<A HREF="../../../../reference/android/support/v
    -     </div> <!-- end footer -->
    -     </div><!-- end doc-content -->
    -     </div> <!-- end body-content --> 
    --<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    - </script>
    - <script type="text/javascript">
    -   try {
    -diff --git a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.widget.SearchViewCompat.html b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.widget.SearchViewCompat.html
    -index ce5abd3..e3de11d 100644
    ---- a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.widget.SearchViewCompat.html
    -+++ b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.widget.SearchViewCompat.html
    -@@ -94,7 +94,7 @@ Class android.support.v4.widget.<A HREF="../../../../reference/android/support/v
    -     </div> <!-- end footer -->
    -     </div><!-- end doc-content -->
    -     </div> <!-- end body-content --> 
    --<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    - </script>
    - <script type="text/javascript">
    -   try {
    -diff --git a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.widget.TextViewCompat.html b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.widget.TextViewCompat.html
    -index e2078f4..e3a0f9a 100644
    ---- a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.widget.TextViewCompat.html
    -+++ b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.widget.TextViewCompat.html
    -@@ -109,7 +109,7 @@ Class android.support.v4.widget.<A HREF="../../../../reference/android/support/v
    -     </div> <!-- end footer -->
    -     </div><!-- end doc-content -->
    -     </div> <!-- end body-content --> 
    --<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    - </script>
    - <script type="text/javascript">
    -   try {
    -diff --git a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v7.app.AppCompatDelegate.html b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v7.app.AppCompatDelegate.html
    -index 6fd286c..2dbee43 100644
    ---- a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v7.app.AppCompatDelegate.html
    -+++ b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v7.app.AppCompatDelegate.html
    -@@ -172,7 +172,7 @@ Class android.support.v7.app.<A HREF="../../../../reference/android/support/v7/a
    -     </div> <!-- end footer -->
    -     </div><!-- end doc-content -->
    -     </div> <!-- end body-content --> 
    --<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    - </script>
    - <script type="text/javascript">
    -   try {
    -diff --git a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v7.appcompat.R.attr.html b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v7.appcompat.R.attr.html
    -index c399a8a..2a2364a 100644
    ---- a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v7.appcompat.R.attr.html
    -+++ b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v7.appcompat.R.attr.html
    -@@ -122,7 +122,7 @@ Class android.support.v7.appcompat.<A HREF="../../../../reference/android/suppor
    -     </div> <!-- end footer -->
    -     </div><!-- end doc-content -->
    -     </div> <!-- end body-content --> 
    --<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    - </script>
    - <script type="text/javascript">
    -   try {
    -diff --git a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v7.appcompat.R.drawable.html b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v7.appcompat.R.drawable.html
    -index ec1ee38..a2e1dc3 100644
    ---- a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v7.appcompat.R.drawable.html
    -+++ b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v7.appcompat.R.drawable.html
    -@@ -347,7 +347,7 @@ Class android.support.v7.appcompat.<A HREF="../../../../reference/android/suppor
    -     </div> <!-- end footer -->
    -     </div><!-- end doc-content -->
    -     </div> <!-- end body-content --> 
    --<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    - </script>
    - <script type="text/javascript">
    -   try {
    -diff --git a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v7.appcompat.R.style.html b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v7.appcompat.R.style.html
    -index 478d333..32befe4 100644
    ---- a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v7.appcompat.R.style.html
    -+++ b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v7.appcompat.R.style.html
    -@@ -178,7 +178,7 @@ Class android.support.v7.appcompat.<A HREF="../../../../reference/android/suppor
    -     </div> <!-- end footer -->
    -     </div><!-- end doc-content -->
    -     </div> <!-- end body-content --> 
    --<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    - </script>
    - <script type="text/javascript">
    -   try {
    -diff --git a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v7.appcompat.R.styleable.html b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v7.appcompat.R.styleable.html
    -index 498ec51..6433bc2 100644
    ---- a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v7.appcompat.R.styleable.html
    -+++ b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v7.appcompat.R.styleable.html
    -@@ -1705,7 +1705,7 @@ Class android.support.v7.appcompat.<A HREF="../../../../reference/android/suppor
    -     </div> <!-- end footer -->
    -     </div><!-- end doc-content -->
    -     </div> <!-- end body-content --> 
    --<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    - </script>
    - <script type="text/javascript">
    -   try {
    -diff --git a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v7.graphics.Palette.Builder.html b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v7.graphics.Palette.Builder.html
    -index 83f441b..2758189 100644
    ---- a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v7.graphics.Palette.Builder.html
    -+++ b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v7.graphics.Palette.Builder.html
    -@@ -140,7 +140,7 @@ Class android.support.v7.graphics.<A HREF="../../../../reference/android/support
    -     </div> <!-- end footer -->
    -     </div><!-- end doc-content -->
    -     </div> <!-- end body-content --> 
    --<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    - </script>
    - <script type="text/javascript">
    -   try {
    -diff --git a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v7.graphics.Palette.html b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v7.graphics.Palette.html
    -index be157a7..d7752f5 100644
    ---- a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v7.graphics.Palette.html
    -+++ b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v7.graphics.Palette.html
    -@@ -122,7 +122,7 @@ Class android.support.v7.graphics.<A HREF="../../../../reference/android/support
    -     </div> <!-- end footer -->
    -     </div><!-- end doc-content -->
    -     </div> <!-- end body-content --> 
    --<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    - </script>
    - <script type="text/javascript">
    -   try {
    -diff --git a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v7.media.MediaRouteDescriptor.Builder.html b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v7.media.MediaRouteDescriptor.Builder.html
    -index 7db6666..9181648 100644
    ---- a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v7.media.MediaRouteDescriptor.Builder.html
    -+++ b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v7.media.MediaRouteDescriptor.Builder.html
    -@@ -115,7 +115,7 @@ Class android.support.v7.media.<A HREF="../../../../reference/android/support/v7
    -     </div> <!-- end footer -->
    -     </div><!-- end doc-content -->
    -     </div> <!-- end body-content --> 
    --<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    - </script>
    - <script type="text/javascript">
    -   try {
    -diff --git a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v7.media.MediaRouteDescriptor.html b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v7.media.MediaRouteDescriptor.html
    -index 315ba3d..0cb71cf 100644
    ---- a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v7.media.MediaRouteDescriptor.html
    -+++ b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v7.media.MediaRouteDescriptor.html
    -@@ -108,7 +108,7 @@ Class android.support.v7.media.<A HREF="../../../../reference/android/support/v7
    -     </div> <!-- end footer -->
    -     </div><!-- end doc-content -->
    -     </div> <!-- end body-content --> 
    --<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    - </script>
    - <script type="text/javascript">
    -   try {
    -diff --git a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v7.media.MediaRouter.Callback.html b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v7.media.MediaRouter.Callback.html
    -index 66be68d..5d68006 100644
    ---- a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v7.media.MediaRouter.Callback.html
    -+++ b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v7.media.MediaRouter.Callback.html
    -@@ -108,7 +108,7 @@ Class android.support.v7.media.<A HREF="../../../../reference/android/support/v7
    -     </div> <!-- end footer -->
    -     </div><!-- end doc-content -->
    -     </div> <!-- end body-content --> 
    --<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    - </script>
    - <script type="text/javascript">
    -   try {
    -diff --git a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v7.preference.PreferenceFragmentCompat.html b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v7.preference.PreferenceFragmentCompat.html
    -index 68aa733..980ff0d 100644
    ---- a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v7.preference.PreferenceFragmentCompat.html
    -+++ b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v7.preference.PreferenceFragmentCompat.html
    -@@ -115,7 +115,7 @@ Class android.support.v7.preference.<A HREF="../../../../reference/android/suppo
    -     </div> <!-- end footer -->
    -     </div><!-- end doc-content -->
    -     </div> <!-- end body-content --> 
    --<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    - </script>
    - <script type="text/javascript">
    -   try {
    -diff --git a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v7.preference.PreferenceScreen.html b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v7.preference.PreferenceScreen.html
    -index 12de78c..de14ee0 100644
    ---- a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v7.preference.PreferenceScreen.html
    -+++ b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v7.preference.PreferenceScreen.html
    -@@ -115,7 +115,7 @@ Class android.support.v7.preference.<A HREF="../../../../reference/android/suppo
    -     </div> <!-- end footer -->
    -     </div><!-- end doc-content -->
    -     </div> <!-- end body-content --> 
    --<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    - </script>
    - <script type="text/javascript">
    -   try {
    -diff --git a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v7.preference.PreferenceViewHolder.html b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v7.preference.PreferenceViewHolder.html
    -index b27e66c..0597c2a 100644
    ---- a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v7.preference.PreferenceViewHolder.html
    -+++ b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v7.preference.PreferenceViewHolder.html
    -@@ -129,7 +129,7 @@ Class android.support.v7.preference.<A HREF="../../../../reference/android/suppo
    -     </div> <!-- end footer -->
    -     </div><!-- end doc-content -->
    -     </div> <!-- end body-content --> 
    --<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    - </script>
    - <script type="text/javascript">
    -   try {
    -diff --git a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v7.recyclerview.R.dimen.html b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v7.recyclerview.R.dimen.html
    -index b38c6dc..a56e112 100644
    ---- a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v7.recyclerview.R.dimen.html
    -+++ b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v7.recyclerview.R.dimen.html
    -@@ -115,7 +115,7 @@ Class android.support.v7.recyclerview.<A HREF="../../../../reference/android/sup
    -     </div> <!-- end footer -->
    -     </div><!-- end doc-content -->
    -     </div> <!-- end body-content --> 
    --<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    - </script>
    - <script type="text/javascript">
    -   try {
    -diff --git a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v7.widget.OrientationHelper.html b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v7.widget.OrientationHelper.html
    -index 6a2a9b3..9111877 100644
    ---- a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v7.widget.OrientationHelper.html
    -+++ b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v7.widget.OrientationHelper.html
    -@@ -115,7 +115,7 @@ Class android.support.v7.widget.<A HREF="../../../../reference/android/support/v
    -     </div> <!-- end footer -->
    -     </div><!-- end doc-content -->
    -     </div> <!-- end body-content --> 
    --<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    - </script>
    - <script type="text/javascript">
    -   try {
    -diff --git a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v7.widget.RecyclerView.ItemAnimator.html b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v7.widget.RecyclerView.ItemAnimator.html
    -index 95e642e..a641975 100644
    ---- a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v7.widget.RecyclerView.ItemAnimator.html
    -+++ b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v7.widget.RecyclerView.ItemAnimator.html
    -@@ -108,7 +108,7 @@ Class android.support.v7.widget.<A HREF="../../../../reference/android/support/v
    -     </div> <!-- end footer -->
    -     </div><!-- end doc-content -->
    -     </div> <!-- end body-content --> 
    --<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    - </script>
    - <script type="text/javascript">
    -   try {
    -diff --git a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v7.widget.RecyclerView.LayoutManager.html b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v7.widget.RecyclerView.LayoutManager.html
    -index 30b0a78..173d636 100644
    ---- a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v7.widget.RecyclerView.LayoutManager.html
    -+++ b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v7.widget.RecyclerView.LayoutManager.html
    -@@ -193,7 +193,7 @@ Class android.support.v7.widget.<A HREF="../../../../reference/android/support/v
    -     </div> <!-- end footer -->
    -     </div><!-- end doc-content -->
    -     </div> <!-- end body-content --> 
    --<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    - </script>
    - <script type="text/javascript">
    -   try {
    -diff --git a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v7.widget.RecyclerView.State.html b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v7.widget.RecyclerView.State.html
    -index 2b3ac61..86d91dc 100644
    ---- a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v7.widget.RecyclerView.State.html
    -+++ b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v7.widget.RecyclerView.State.html
    -@@ -108,7 +108,7 @@ Class android.support.v7.widget.<A HREF="../../../../reference/android/support/v
    -     </div> <!-- end footer -->
    -     </div><!-- end doc-content -->
    -     </div> <!-- end body-content --> 
    --<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    - </script>
    - <script type="text/javascript">
    -   try {
    -diff --git a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v7.widget.RecyclerView.html b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v7.widget.RecyclerView.html
    -index 5cdc7a0..a53430b 100644
    ---- a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v7.widget.RecyclerView.html
    -+++ b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v7.widget.RecyclerView.html
    -@@ -115,7 +115,7 @@ Class android.support.v7.widget.<A HREF="../../../../reference/android/support/v
    -     </div> <!-- end footer -->
    -     </div><!-- end doc-content -->
    -     </div> <!-- end body-content --> 
    --<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    - </script>
    - <script type="text/javascript">
    -   try {
    -diff --git a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v7.widget.helper.ItemTouchHelper.Callback.html b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v7.widget.helper.ItemTouchHelper.Callback.html
    -index 1237408..b241e6e 100644
    ---- a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v7.widget.helper.ItemTouchHelper.Callback.html
    -+++ b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v7.widget.helper.ItemTouchHelper.Callback.html
    -@@ -115,7 +115,7 @@ Class android.support.v7.widget.helper.<A HREF="../../../../reference/android/su
    -     </div> <!-- end footer -->
    -     </div><!-- end doc-content -->
    -     </div> <!-- end body-content --> 
    --<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    - </script>
    - <script type="text/javascript">
    -   try {
    -diff --git a/docs/html/sdk/support_api_diff/23.2.0/changes/changes-summary.html b/docs/html/sdk/support_api_diff/23.2.0/changes/changes-summary.html
    -index d41ec1f..431b2ae 100644
    ---- a/docs/html/sdk/support_api_diff/23.2.0/changes/changes-summary.html
    -+++ b/docs/html/sdk/support_api_diff/23.2.0/changes/changes-summary.html
    -@@ -352,7 +352,7 @@ see the <a href="http://developer.android.com/index.html" target="_top">Android
    -     </div> <!-- end footer -->
    -     </div><!-- end doc-content -->
    -     </div> <!-- end body-content --> 
    --<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    - </script>
    - <script type="text/javascript">
    -   try {
    -diff --git a/docs/html/sdk/support_api_diff/23.2.0/changes/classes_index_additions.html b/docs/html/sdk/support_api_diff/23.2.0/changes/classes_index_additions.html
    -index a2e1d44..eb0457c 100644
    ---- a/docs/html/sdk/support_api_diff/23.2.0/changes/classes_index_additions.html
    -+++ b/docs/html/sdk/support_api_diff/23.2.0/changes/classes_index_additions.html
    -@@ -143,7 +143,7 @@ Listed as: <span style="color:#069"><strong>Added</strong></span>,  <span style=
    - <p><div style="line-height:1.5em;color:black">
    - <A HREF="pkg_android.support.v17.leanback.widget.html#ViewHolderTask" class="hiddenlink" target="rightframe"><b><i>ViewHolderTask</i></b></A><br>
    - <A HREF="pkg_android.support.design.widget.html#VisibilityAwareImageButton" class="hiddenlink" target="rightframe"><b>VisibilityAwareImageButton</b></A><br>
    --<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    - </script>
    - <script type="text/javascript">
    -   try {
    -diff --git a/docs/html/sdk/support_api_diff/23/changes/alldiffs_index_additions.html b/docs/html/sdk/support_api_diff/23/changes/alldiffs_index_additions.html
    -index 78c94e1..c526b45 100644
    ---- a/docs/html/sdk/support_api_diff/23/changes/alldiffs_index_additions.html
    -+++ b/docs/html/sdk/support_api_diff/23/changes/alldiffs_index_additions.html
    -@@ -1128,7 +1128,7 @@ Listed as: <span style="color:#069"><strong>Added</strong></span>,  <span style=
    - <p><div style="line-height:1.5em;color:black">
    - <nobr><A HREF="android.support.v7.appcompat.R.style.html#android.support.v7.appcompat.R.style.Widget_AppCompat_Button_Colored" class="hiddenlink" target="rightframe">Widget_AppCompat_Button_Colored</A>
    - </nobr><br>
    --<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    - </script>
    - <script type="text/javascript">
    -   try {
    -diff --git a/docs/html/sdk/support_api_diff/23/changes/alldiffs_index_all.html b/docs/html/sdk/support_api_diff/23/changes/alldiffs_index_all.html
    -index f39d82e..61459ad 100644
    ---- a/docs/html/sdk/support_api_diff/23/changes/alldiffs_index_all.html
    -+++ b/docs/html/sdk/support_api_diff/23/changes/alldiffs_index_all.html
    -@@ -1457,7 +1457,7 @@ Listed as: <span style="color:#069"><strong>Added</strong></span>,  <span style=
    - <p><div style="line-height:1.5em;color:black">
    - <nobr><A HREF="android.support.v7.appcompat.R.style.html#android.support.v7.appcompat.R.style.Widget_AppCompat_Button_Colored" class="hiddenlink" target="rightframe">Widget_AppCompat_Button_Colored</A>
    - </nobr><br>
    --<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    - </script>
    - <script type="text/javascript">
    -   try {
    -diff --git a/docs/html/sdk/support_api_diff/23/changes/alldiffs_index_changes.html b/docs/html/sdk/support_api_diff/23/changes/alldiffs_index_changes.html
    -index debbb14..0a63a58 100644
    ---- a/docs/html/sdk/support_api_diff/23/changes/alldiffs_index_changes.html
    -+++ b/docs/html/sdk/support_api_diff/23/changes/alldiffs_index_changes.html
    -@@ -485,7 +485,7 @@ Listed as: <span style="color:#069"><strong>Added</strong></span>,  <span style=
    -  <a href="#topheader"><font size="-2">TOP</font></a>
    - <p><div style="line-height:1.5em;color:black">
    - <A HREF="android.support.v4.view.ViewCompat.html" class="hiddenlink" target="rightframe">ViewCompat</A><br>
    --<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    - </script>
    - <script type="text/javascript">
    -   try {
    -diff --git a/docs/html/sdk/support_api_diff/23/changes/alldiffs_index_removals.html b/docs/html/sdk/support_api_diff/23/changes/alldiffs_index_removals.html
    -index a6cdb59..9f13a01 100644
    ---- a/docs/html/sdk/support_api_diff/23/changes/alldiffs_index_removals.html
    -+++ b/docs/html/sdk/support_api_diff/23/changes/alldiffs_index_removals.html
    -@@ -332,7 +332,7 @@ Listed as: <span style="color:#069"><strong>Added</strong></span>,  <span style=
    - <!-- Field View_backgroundTintMode -->
    - <nobr><A HREF="android.support.v7.appcompat.R.styleable.html#android.support.v7.appcompat.R.styleable.View_backgroundTintMode" class="hiddenlink" target="rightframe"><strike>View_backgroundTintMode</strike></A>
    - </nobr><br>
    --<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    - </script>
    - <script type="text/javascript">
    -   try {
    -diff --git a/docs/html/sdk/support_api_diff/23/changes/android.support.design.widget.AppBarLayout.Behavior.html b/docs/html/sdk/support_api_diff/23/changes/android.support.design.widget.AppBarLayout.Behavior.html
    -index a6bbf2d..352dcfd 100644
    ---- a/docs/html/sdk/support_api_diff/23/changes/android.support.design.widget.AppBarLayout.Behavior.html
    -+++ b/docs/html/sdk/support_api_diff/23/changes/android.support.design.widget.AppBarLayout.Behavior.html
    -@@ -115,7 +115,7 @@ Class android.support.design.widget.<A HREF="../../../../reference/android/suppo
    -     </div> <!-- end footer -->
    -     </div><!-- end doc-content -->
    -     </div> <!-- end body-content --> 
    --<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    - </script>
    - <script type="text/javascript">
    -   try {
    -diff --git a/docs/html/sdk/support_api_diff/23/changes/android.support.design.widget.AppBarLayout.html b/docs/html/sdk/support_api_diff/23/changes/android.support.design.widget.AppBarLayout.html
    -index 71e3167..cd2a11f 100644
    ---- a/docs/html/sdk/support_api_diff/23/changes/android.support.design.widget.AppBarLayout.html
    -+++ b/docs/html/sdk/support_api_diff/23/changes/android.support.design.widget.AppBarLayout.html
    -@@ -115,7 +115,7 @@ Class android.support.design.widget.<A HREF="../../../../reference/android/suppo
    -     </div> <!-- end footer -->
    -     </div><!-- end doc-content -->
    -     </div> <!-- end body-content --> 
    --<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    - </script>
    - <script type="text/javascript">
    -   try {
    -diff --git a/docs/html/sdk/support_api_diff/23/changes/android.support.design.widget.CollapsingToolbarLayout.html b/docs/html/sdk/support_api_diff/23/changes/android.support.design.widget.CollapsingToolbarLayout.html
    -index 7244be9..d80f7ee 100644
    ---- a/docs/html/sdk/support_api_diff/23/changes/android.support.design.widget.CollapsingToolbarLayout.html
    -+++ b/docs/html/sdk/support_api_diff/23/changes/android.support.design.widget.CollapsingToolbarLayout.html
    -@@ -150,7 +150,7 @@ Class android.support.design.widget.<A HREF="../../../../reference/android/suppo
    -     </div> <!-- end footer -->
    -     </div><!-- end doc-content -->
    -     </div> <!-- end body-content --> 
    --<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    - </script>
    - <script type="text/javascript">
    -   try {
    -diff --git a/docs/html/sdk/support_api_diff/23/changes/android.support.design.widget.NavigationView.html b/docs/html/sdk/support_api_diff/23/changes/android.support.design.widget.NavigationView.html
    -index a38990a..5dd3104 100644
    ---- a/docs/html/sdk/support_api_diff/23/changes/android.support.design.widget.NavigationView.html
    -+++ b/docs/html/sdk/support_api_diff/23/changes/android.support.design.widget.NavigationView.html
    -@@ -115,7 +115,7 @@ Class android.support.design.widget.<A HREF="../../../../reference/android/suppo
    -     </div> <!-- end footer -->
    -     </div><!-- end doc-content -->
    -     </div> <!-- end body-content --> 
    --<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    - </script>
    - <script type="text/javascript">
    -   try {
    -diff --git a/docs/html/sdk/support_api_diff/23/changes/android.support.design.widget.Snackbar.html b/docs/html/sdk/support_api_diff/23/changes/android.support.design.widget.Snackbar.html
    -index 9a53448..2247297 100644
    ---- a/docs/html/sdk/support_api_diff/23/changes/android.support.design.widget.Snackbar.html
    -+++ b/docs/html/sdk/support_api_diff/23/changes/android.support.design.widget.Snackbar.html
    -@@ -116,7 +116,7 @@ Class android.support.design.widget.<A HREF="../../../../reference/android/suppo
    -     </div> <!-- end footer -->
    -     </div><!-- end doc-content -->
    -     </div> <!-- end body-content --> 
    --<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    - </script>
    - <script type="text/javascript">
    -   try {
    -diff --git a/docs/html/sdk/support_api_diff/23/changes/android.support.design.widget.TabLayout.Tab.html b/docs/html/sdk/support_api_diff/23/changes/android.support.design.widget.TabLayout.Tab.html
    -index b7a01f5..a0ea052 100644
    ---- a/docs/html/sdk/support_api_diff/23/changes/android.support.design.widget.TabLayout.Tab.html
    -+++ b/docs/html/sdk/support_api_diff/23/changes/android.support.design.widget.TabLayout.Tab.html
    -@@ -108,7 +108,7 @@ Class android.support.design.widget.<A HREF="../../../../reference/android/suppo
    -     </div> <!-- end footer -->
    -     </div><!-- end doc-content -->
    -     </div> <!-- end body-content --> 
    --<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    - </script>
    - <script type="text/javascript">
    -   try {
    -diff --git a/docs/html/sdk/support_api_diff/23/changes/android.support.design.widget.TabLayout.html b/docs/html/sdk/support_api_diff/23/changes/android.support.design.widget.TabLayout.html
    -index df626ac..bd3c8e6 100644
    ---- a/docs/html/sdk/support_api_diff/23/changes/android.support.design.widget.TabLayout.html
    -+++ b/docs/html/sdk/support_api_diff/23/changes/android.support.design.widget.TabLayout.html
    -@@ -115,7 +115,7 @@ Class android.support.design.widget.<A HREF="../../../../reference/android/suppo
    -     </div> <!-- end footer -->
    -     </div><!-- end doc-content -->
    -     </div> <!-- end body-content --> 
    --<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    - </script>
    - <script type="text/javascript">
    -   try {
    -diff --git a/docs/html/sdk/support_api_diff/23/changes/android.support.design.widget.TextInputLayout.html b/docs/html/sdk/support_api_diff/23/changes/android.support.design.widget.TextInputLayout.html
    -index 471e267..a9a7b49 100644
    ---- a/docs/html/sdk/support_api_diff/23/changes/android.support.design.widget.TextInputLayout.html
    -+++ b/docs/html/sdk/support_api_diff/23/changes/android.support.design.widget.TextInputLayout.html
    -@@ -165,7 +165,7 @@ Class android.support.design.widget.<A HREF="../../../../reference/android/suppo
    -     </div> <!-- end footer -->
    -     </div><!-- end doc-content -->
    -     </div> <!-- end body-content --> 
    --<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    - </script>
    - <script type="text/javascript">
    -   try {
    -diff --git a/docs/html/sdk/support_api_diff/23/changes/android.support.v13.app.FragmentCompat.html b/docs/html/sdk/support_api_diff/23/changes/android.support.v13.app.FragmentCompat.html
    -index 9eb5b24..b61fb5a 100644
    ---- a/docs/html/sdk/support_api_diff/23/changes/android.support.v13.app.FragmentCompat.html
    -+++ b/docs/html/sdk/support_api_diff/23/changes/android.support.v13.app.FragmentCompat.html
    -@@ -115,7 +115,7 @@ Class android.support.v13.app.<A HREF="../../../../reference/android/support/v13
    -     </div> <!-- end footer -->
    -     </div><!-- end doc-content -->
    -     </div> <!-- end body-content --> 
    --<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    - </script>
    - <script type="text/javascript">
    -   try {
    -diff --git a/docs/html/sdk/support_api_diff/23/changes/android.support.v17.leanback.widget.FullWidthDetailsOverviewRowPresenter.ViewHolder.html b/docs/html/sdk/support_api_diff/23/changes/android.support.v17.leanback.widget.FullWidthDetailsOverviewRowPresenter.ViewHolder.html
    -index 3c6165f..f189083 100644
    ---- a/docs/html/sdk/support_api_diff/23/changes/android.support.v17.leanback.widget.FullWidthDetailsOverviewRowPresenter.ViewHolder.html
    -+++ b/docs/html/sdk/support_api_diff/23/changes/android.support.v17.leanback.widget.FullWidthDetailsOverviewRowPresenter.ViewHolder.html
    -@@ -108,7 +108,7 @@ Class android.support.v17.leanback.widget.<A HREF="../../../../reference/android
    -     </div> <!-- end footer -->
    -     </div><!-- end doc-content -->
    -     </div> <!-- end body-content --> 
    --<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    - </script>
    - <script type="text/javascript">
    -   try {
    -diff --git a/docs/html/sdk/support_api_diff/23/changes/android.support.v17.leanback.widget.FullWidthDetailsOverviewRowPresenter.html b/docs/html/sdk/support_api_diff/23/changes/android.support.v17.leanback.widget.FullWidthDetailsOverviewRowPresenter.html
    -index b6d8863..cb2156a 100644
    ---- a/docs/html/sdk/support_api_diff/23/changes/android.support.v17.leanback.widget.FullWidthDetailsOverviewRowPresenter.html
    -+++ b/docs/html/sdk/support_api_diff/23/changes/android.support.v17.leanback.widget.FullWidthDetailsOverviewRowPresenter.html
    -@@ -179,7 +179,7 @@ Change from non-final to final.<br>
    -     </div> <!-- end footer -->
    -     </div><!-- end doc-content -->
    -     </div> <!-- end body-content --> 
    --<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    - </script>
    - <script type="text/javascript">
    -   try {
    -diff --git a/docs/html/sdk/support_api_diff/23/changes/android.support.v4.animation.AnimatorCompatHelper.html b/docs/html/sdk/support_api_diff/23/changes/android.support.v4.animation.AnimatorCompatHelper.html
    -index 092a6c3..5d5a9fc 100644
    ---- a/docs/html/sdk/support_api_diff/23/changes/android.support.v4.animation.AnimatorCompatHelper.html
    -+++ b/docs/html/sdk/support_api_diff/23/changes/android.support.v4.animation.AnimatorCompatHelper.html
    -@@ -108,7 +108,7 @@ Class android.support.v4.animation.<A HREF="../../../../reference/android/suppor
    -     </div> <!-- end footer -->
    -     </div><!-- end doc-content -->
    -     </div> <!-- end body-content --> 
    --<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    - </script>
    - <script type="text/javascript">
    -   try {
    -diff --git a/docs/html/sdk/support_api_diff/23/changes/android.support.v4.app.ActivityCompat.html b/docs/html/sdk/support_api_diff/23/changes/android.support.v4.app.ActivityCompat.html
    -index 76e8ce9..c318b70 100644
    ---- a/docs/html/sdk/support_api_diff/23/changes/android.support.v4.app.ActivityCompat.html
    -+++ b/docs/html/sdk/support_api_diff/23/changes/android.support.v4.app.ActivityCompat.html
    -@@ -122,7 +122,7 @@ Class android.support.v4.app.<A HREF="../../../../reference/android/support/v4/a
    -     </div> <!-- end footer -->
    -     </div><!-- end doc-content -->
    -     </div> <!-- end body-content --> 
    --<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    - </script>
    - <script type="text/javascript">
    -   try {
    -diff --git a/docs/html/sdk/support_api_diff/23/changes/android.support.v4.app.Fragment.html b/docs/html/sdk/support_api_diff/23/changes/android.support.v4.app.Fragment.html
    -index 53a8bd5..2f56f59 100644
    ---- a/docs/html/sdk/support_api_diff/23/changes/android.support.v4.app.Fragment.html
    -+++ b/docs/html/sdk/support_api_diff/23/changes/android.support.v4.app.Fragment.html
    -@@ -190,7 +190,7 @@ Class android.support.v4.app.<A HREF="../../../../reference/android/support/v4/a
    -     </div> <!-- end footer -->
    -     </div><!-- end doc-content -->
    -     </div> <!-- end body-content --> 
    --<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    - </script>
    - <script type="text/javascript">
    -   try {
    -diff --git a/docs/html/sdk/support_api_diff/23/changes/android.support.v4.app.FragmentActivity.html b/docs/html/sdk/support_api_diff/23/changes/android.support.v4.app.FragmentActivity.html
    -index 8d2321f..0338069 100644
    ---- a/docs/html/sdk/support_api_diff/23/changes/android.support.v4.app.FragmentActivity.html
    -+++ b/docs/html/sdk/support_api_diff/23/changes/android.support.v4.app.FragmentActivity.html
    -@@ -109,7 +109,7 @@ Class android.support.v4.app.<A HREF="../../../../reference/android/support/v4/a
    -     </div> <!-- end footer -->
    -     </div><!-- end doc-content -->
    -     </div> <!-- end body-content --> 
    --<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    - </script>
    - <script type="text/javascript">
    -   try {
    -diff --git a/docs/html/sdk/support_api_diff/23/changes/android.support.v4.content.AsyncTaskLoader.html b/docs/html/sdk/support_api_diff/23/changes/android.support.v4.content.AsyncTaskLoader.html
    -index 19be27c..5dfbe6c 100644
    ---- a/docs/html/sdk/support_api_diff/23/changes/android.support.v4.content.AsyncTaskLoader.html
    -+++ b/docs/html/sdk/support_api_diff/23/changes/android.support.v4.content.AsyncTaskLoader.html
    -@@ -133,7 +133,7 @@ Method was locally defined, but is now inherited from <a href="../../../../refer
    -     </div> <!-- end footer -->
    -     </div><!-- end doc-content -->
    -     </div> <!-- end body-content --> 
    --<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    - </script>
    - <script type="text/javascript">
    -   try {
    -diff --git a/docs/html/sdk/support_api_diff/23/changes/android.support.v4.content.ContextCompat.html b/docs/html/sdk/support_api_diff/23/changes/android.support.v4.content.ContextCompat.html
    -index 6ed5b3e..64d09ac 100644
    ---- a/docs/html/sdk/support_api_diff/23/changes/android.support.v4.content.ContextCompat.html
    -+++ b/docs/html/sdk/support_api_diff/23/changes/android.support.v4.content.ContextCompat.html
    -@@ -122,7 +122,7 @@ Class android.support.v4.content.<A HREF="../../../../reference/android/support/
    -     </div> <!-- end footer -->
    -     </div><!-- end doc-content -->
    -     </div> <!-- end body-content --> 
    --<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    - </script>
    - <script type="text/javascript">
    -   try {
    -diff --git a/docs/html/sdk/support_api_diff/23/changes/android.support.v4.content.Loader.html b/docs/html/sdk/support_api_diff/23/changes/android.support.v4.content.Loader.html
    -index d4c3bb0..f97def1 100644
    ---- a/docs/html/sdk/support_api_diff/23/changes/android.support.v4.content.Loader.html
    -+++ b/docs/html/sdk/support_api_diff/23/changes/android.support.v4.content.Loader.html
    -@@ -136,7 +136,7 @@ Class android.support.v4.content.<A HREF="../../../../reference/android/support/
    -     </div> <!-- end footer -->
    -     </div><!-- end doc-content -->
    -     </div> <!-- end body-content --> 
    --<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    - </script>
    - <script type="text/javascript">
    -   try {
    -diff --git a/docs/html/sdk/support_api_diff/23/changes/android.support.v4.graphics.drawable.DrawableCompat.html b/docs/html/sdk/support_api_diff/23/changes/android.support.v4.graphics.drawable.DrawableCompat.html
    -index 87fefee..ca42f3d 100644
    ---- a/docs/html/sdk/support_api_diff/23/changes/android.support.v4.graphics.drawable.DrawableCompat.html
    -+++ b/docs/html/sdk/support_api_diff/23/changes/android.support.v4.graphics.drawable.DrawableCompat.html
    -@@ -115,7 +115,7 @@ Class android.support.v4.graphics.drawable.<A HREF="../../../../reference/androi
    -     </div> <!-- end footer -->
    -     </div><!-- end doc-content -->
    -     </div> <!-- end body-content --> 
    --<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    - </script>
    - <script type="text/javascript">
    -   try {
    -diff --git a/docs/html/sdk/support_api_diff/23/changes/android.support.v4.graphics.drawable.RoundedBitmapDrawable.html b/docs/html/sdk/support_api_diff/23/changes/android.support.v4.graphics.drawable.RoundedBitmapDrawable.html
    -index 7c72cf4..793bd8b 100644
    ---- a/docs/html/sdk/support_api_diff/23/changes/android.support.v4.graphics.drawable.RoundedBitmapDrawable.html
    -+++ b/docs/html/sdk/support_api_diff/23/changes/android.support.v4.graphics.drawable.RoundedBitmapDrawable.html
    -@@ -115,7 +115,7 @@ Class android.support.v4.graphics.drawable.<A HREF="../../../../reference/androi
    -     </div> <!-- end footer -->
    -     </div><!-- end doc-content -->
    -     </div> <!-- end body-content --> 
    --<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    - </script>
    - <script type="text/javascript">
    -   try {
    -diff --git a/docs/html/sdk/support_api_diff/23/changes/android.support.v4.media.MediaDescriptionCompat.Builder.html b/docs/html/sdk/support_api_diff/23/changes/android.support.v4.media.MediaDescriptionCompat.Builder.html
    -index c429c39..6ae7186 100644
    ---- a/docs/html/sdk/support_api_diff/23/changes/android.support.v4.media.MediaDescriptionCompat.Builder.html
    -+++ b/docs/html/sdk/support_api_diff/23/changes/android.support.v4.media.MediaDescriptionCompat.Builder.html
    -@@ -108,7 +108,7 @@ Class android.support.v4.media.<A HREF="../../../../reference/android/support/v4
    -     </div> <!-- end footer -->
    -     </div><!-- end doc-content -->
    -     </div> <!-- end body-content --> 
    --<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    - </script>
    - <script type="text/javascript">
    -   try {
    -diff --git a/docs/html/sdk/support_api_diff/23/changes/android.support.v4.media.MediaDescriptionCompat.html b/docs/html/sdk/support_api_diff/23/changes/android.support.v4.media.MediaDescriptionCompat.html
    -index 4053435..dde12a5 100644
    ---- a/docs/html/sdk/support_api_diff/23/changes/android.support.v4.media.MediaDescriptionCompat.html
    -+++ b/docs/html/sdk/support_api_diff/23/changes/android.support.v4.media.MediaDescriptionCompat.html
    -@@ -108,7 +108,7 @@ Class android.support.v4.media.<A HREF="../../../../reference/android/support/v4
    -     </div> <!-- end footer -->
    -     </div><!-- end doc-content -->
    -     </div> <!-- end body-content --> 
    --<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    - </script>
    - <script type="text/javascript">
    -   try {
    -diff --git a/docs/html/sdk/support_api_diff/23/changes/android.support.v4.media.session.MediaControllerCompat.TransportControls.html b/docs/html/sdk/support_api_diff/23/changes/android.support.v4.media.session.MediaControllerCompat.TransportControls.html
    -index 4d10769..12743cd 100644
    ---- a/docs/html/sdk/support_api_diff/23/changes/android.support.v4.media.session.MediaControllerCompat.TransportControls.html
    -+++ b/docs/html/sdk/support_api_diff/23/changes/android.support.v4.media.session.MediaControllerCompat.TransportControls.html
    -@@ -108,7 +108,7 @@ Class android.support.v4.media.session.<A HREF="../../../../reference/android/su
    -     </div> <!-- end footer -->
    -     </div><!-- end doc-content -->
    -     </div> <!-- end body-content --> 
    --<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    - </script>
    - <script type="text/javascript">
    -   try {
    -diff --git a/docs/html/sdk/support_api_diff/23/changes/android.support.v4.media.session.MediaSessionCompat.Callback.html b/docs/html/sdk/support_api_diff/23/changes/android.support.v4.media.session.MediaSessionCompat.Callback.html
    -index a0bbbf6..4acf244 100644
    ---- a/docs/html/sdk/support_api_diff/23/changes/android.support.v4.media.session.MediaSessionCompat.Callback.html
    -+++ b/docs/html/sdk/support_api_diff/23/changes/android.support.v4.media.session.MediaSessionCompat.Callback.html
    -@@ -108,7 +108,7 @@ Class android.support.v4.media.session.<A HREF="../../../../reference/android/su
    -     </div> <!-- end footer -->
    -     </div><!-- end doc-content -->
    -     </div> <!-- end body-content --> 
    --<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    - </script>
    - <script type="text/javascript">
    -   try {
    -diff --git a/docs/html/sdk/support_api_diff/23/changes/android.support.v4.media.session.PlaybackStateCompat.html b/docs/html/sdk/support_api_diff/23/changes/android.support.v4.media.session.PlaybackStateCompat.html
    -index 29e5f0b..0f568c4 100644
    ---- a/docs/html/sdk/support_api_diff/23/changes/android.support.v4.media.session.PlaybackStateCompat.html
    -+++ b/docs/html/sdk/support_api_diff/23/changes/android.support.v4.media.session.PlaybackStateCompat.html
    -@@ -108,7 +108,7 @@ Class android.support.v4.media.session.<A HREF="../../../../reference/android/su
    -     </div> <!-- end footer -->
    -     </div><!-- end doc-content -->
    -     </div> <!-- end body-content --> 
    --<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    - </script>
    - <script type="text/javascript">
    -   try {
    -diff --git a/docs/html/sdk/support_api_diff/23/changes/android.support.v4.text.ICUCompat.html b/docs/html/sdk/support_api_diff/23/changes/android.support.v4.text.ICUCompat.html
    -index 5f9f31e..e357c50 100644
    ---- a/docs/html/sdk/support_api_diff/23/changes/android.support.v4.text.ICUCompat.html
    -+++ b/docs/html/sdk/support_api_diff/23/changes/android.support.v4.text.ICUCompat.html
    -@@ -130,7 +130,7 @@ Class android.support.v4.text.<A HREF="../../../../reference/android/support/v4/
    -     </div> <!-- end footer -->
    -     </div><!-- end doc-content -->
    -     </div> <!-- end body-content --> 
    --<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    - </script>
    - <script type="text/javascript">
    -   try {
    -diff --git a/docs/html/sdk/support_api_diff/23/changes/android.support.v4.view.ViewCompat.html b/docs/html/sdk/support_api_diff/23/changes/android.support.v4.view.ViewCompat.html
    -index 548502c..caaf19a 100644
    ---- a/docs/html/sdk/support_api_diff/23/changes/android.support.v4.view.ViewCompat.html
    -+++ b/docs/html/sdk/support_api_diff/23/changes/android.support.v4.view.ViewCompat.html
    -@@ -122,7 +122,7 @@ Class android.support.v4.view.<A HREF="../../../../reference/android/support/v4/
    -     </div> <!-- end footer -->
    -     </div><!-- end doc-content -->
    -     </div> <!-- end body-content --> 
    --<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    - </script>
    - <script type="text/javascript">
    -   try {
    -diff --git a/docs/html/sdk/support_api_diff/23/changes/android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat.html b/docs/html/sdk/support_api_diff/23/changes/android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat.html
    -index ce98f64..c60e7e1 100644
    ---- a/docs/html/sdk/support_api_diff/23/changes/android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat.html
    -+++ b/docs/html/sdk/support_api_diff/23/changes/android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat.html
    -@@ -255,7 +255,7 @@ Class android.support.v4.view.accessibility.<A HREF="../../../../reference/andro
    -     </div> <!-- end footer -->
    -     </div><!-- end doc-content -->
    -     </div> <!-- end body-content --> 
    --<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    - </script>
    - <script type="text/javascript">
    -   try {
    -diff --git a/docs/html/sdk/support_api_diff/23/changes/android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.html b/docs/html/sdk/support_api_diff/23/changes/android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.html
    -index f3ef666..6f2e809 100644
    ---- a/docs/html/sdk/support_api_diff/23/changes/android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.html
    -+++ b/docs/html/sdk/support_api_diff/23/changes/android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.html
    -@@ -361,7 +361,7 @@ Class android.support.v4.view.accessibility.<A HREF="../../../../reference/andro
    -     </div> <!-- end footer -->
    -     </div><!-- end doc-content -->
    -     </div> <!-- end body-content --> 
    --<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    - </script>
    - <script type="text/javascript">
    -   try {
    -diff --git a/docs/html/sdk/support_api_diff/23/changes/android.support.v4.widget.DrawerLayout.html b/docs/html/sdk/support_api_diff/23/changes/android.support.v4.widget.DrawerLayout.html
    -index 3297157..c18ae6c 100644
    ---- a/docs/html/sdk/support_api_diff/23/changes/android.support.v4.widget.DrawerLayout.html
    -+++ b/docs/html/sdk/support_api_diff/23/changes/android.support.v4.widget.DrawerLayout.html
    -@@ -115,7 +115,7 @@ Class android.support.v4.widget.<A HREF="../../../../reference/android/support/v
    -     </div> <!-- end footer -->
    -     </div><!-- end doc-content -->
    -     </div> <!-- end body-content --> 
    --<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    - </script>
    - <script type="text/javascript">
    -   try {
    -diff --git a/docs/html/sdk/support_api_diff/23/changes/android.support.v4.widget.ExploreByTouchHelper.html b/docs/html/sdk/support_api_diff/23/changes/android.support.v4.widget.ExploreByTouchHelper.html
    -index 4026cd2..be8512f 100644
    ---- a/docs/html/sdk/support_api_diff/23/changes/android.support.v4.widget.ExploreByTouchHelper.html
    -+++ b/docs/html/sdk/support_api_diff/23/changes/android.support.v4.widget.ExploreByTouchHelper.html
    -@@ -123,7 +123,7 @@ Class android.support.v4.widget.<A HREF="../../../../reference/android/support/v
    -     </div> <!-- end footer -->
    -     </div><!-- end doc-content -->
    -     </div> <!-- end body-content --> 
    --<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    - </script>
    - <script type="text/javascript">
    -   try {
    -diff --git a/docs/html/sdk/support_api_diff/23/changes/android.support.v4.widget.PopupWindowCompat.html b/docs/html/sdk/support_api_diff/23/changes/android.support.v4.widget.PopupWindowCompat.html
    -index 8a9b9c6..284dab4 100644
    ---- a/docs/html/sdk/support_api_diff/23/changes/android.support.v4.widget.PopupWindowCompat.html
    -+++ b/docs/html/sdk/support_api_diff/23/changes/android.support.v4.widget.PopupWindowCompat.html
    -@@ -129,7 +129,7 @@ Class android.support.v4.widget.<A HREF="../../../../reference/android/support/v
    -     </div> <!-- end footer -->
    -     </div><!-- end doc-content -->
    -     </div> <!-- end body-content --> 
    --<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    - </script>
    - <script type="text/javascript">
    -   try {
    -diff --git a/docs/html/sdk/support_api_diff/23/changes/android.support.v4.widget.SwipeRefreshLayout.html b/docs/html/sdk/support_api_diff/23/changes/android.support.v4.widget.SwipeRefreshLayout.html
    -index 91a99cb..1fb912f 100644
    ---- a/docs/html/sdk/support_api_diff/23/changes/android.support.v4.widget.SwipeRefreshLayout.html
    -+++ b/docs/html/sdk/support_api_diff/23/changes/android.support.v4.widget.SwipeRefreshLayout.html
    -@@ -94,7 +94,7 @@ Class android.support.v4.widget.<A HREF="../../../../reference/android/support/v
    -     </div> <!-- end footer -->
    -     </div><!-- end doc-content -->
    -     </div> <!-- end body-content --> 
    --<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    - </script>
    - <script type="text/javascript">
    -   try {
    -diff --git a/docs/html/sdk/support_api_diff/23/changes/android.support.v7.app.AppCompatDelegate.html b/docs/html/sdk/support_api_diff/23/changes/android.support.v7.app.AppCompatDelegate.html
    -index 42ef289..9f768b9 100644
    ---- a/docs/html/sdk/support_api_diff/23/changes/android.support.v7.app.AppCompatDelegate.html
    -+++ b/docs/html/sdk/support_api_diff/23/changes/android.support.v7.app.AppCompatDelegate.html
    -@@ -137,7 +137,7 @@ Class android.support.v7.app.<A HREF="../../../../reference/android/support/v7/a
    -     </div> <!-- end footer -->
    -     </div><!-- end doc-content -->
    -     </div> <!-- end body-content --> 
    --<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    - </script>
    - <script type="text/javascript">
    -   try {
    -diff --git a/docs/html/sdk/support_api_diff/23/changes/android.support.v7.appcompat.R.attr.html b/docs/html/sdk/support_api_diff/23/changes/android.support.v7.appcompat.R.attr.html
    -index cc28516..98d2c2c 100644
    ---- a/docs/html/sdk/support_api_diff/23/changes/android.support.v7.appcompat.R.attr.html
    -+++ b/docs/html/sdk/support_api_diff/23/changes/android.support.v7.appcompat.R.attr.html
    -@@ -221,7 +221,7 @@ Class android.support.v7.appcompat.<A HREF="../../../../reference/android/suppor
    -     </div> <!-- end footer -->
    -     </div><!-- end doc-content -->
    -     </div> <!-- end body-content --> 
    --<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    - </script>
    - <script type="text/javascript">
    -   try {
    -diff --git a/docs/html/sdk/support_api_diff/23/changes/android.support.v7.appcompat.R.color.html b/docs/html/sdk/support_api_diff/23/changes/android.support.v7.appcompat.R.color.html
    -index 5f1a3f6..852d595 100644
    ---- a/docs/html/sdk/support_api_diff/23/changes/android.support.v7.appcompat.R.color.html
    -+++ b/docs/html/sdk/support_api_diff/23/changes/android.support.v7.appcompat.R.color.html
    -@@ -193,7 +193,7 @@ Class android.support.v7.appcompat.<A HREF="../../../../reference/android/suppor
    -     </div> <!-- end footer -->
    -     </div><!-- end doc-content -->
    -     </div> <!-- end body-content --> 
    --<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    - </script>
    - <script type="text/javascript">
    -   try {
    -diff --git a/docs/html/sdk/support_api_diff/23/changes/android.support.v7.appcompat.R.dimen.html b/docs/html/sdk/support_api_diff/23/changes/android.support.v7.appcompat.R.dimen.html
    -index c4fba92..893ea25 100644
    ---- a/docs/html/sdk/support_api_diff/23/changes/android.support.v7.appcompat.R.dimen.html
    -+++ b/docs/html/sdk/support_api_diff/23/changes/android.support.v7.appcompat.R.dimen.html
    -@@ -158,7 +158,7 @@ Class android.support.v7.appcompat.<A HREF="../../../../reference/android/suppor
    -     </div> <!-- end footer -->
    -     </div><!-- end doc-content -->
    -     </div> <!-- end body-content --> 
    --<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    - </script>
    - <script type="text/javascript">
    -   try {
    -diff --git a/docs/html/sdk/support_api_diff/23/changes/android.support.v7.appcompat.R.drawable.html b/docs/html/sdk/support_api_diff/23/changes/android.support.v7.appcompat.R.drawable.html
    -index 0bf5ce1..482e9ff 100644
    ---- a/docs/html/sdk/support_api_diff/23/changes/android.support.v7.appcompat.R.drawable.html
    -+++ b/docs/html/sdk/support_api_diff/23/changes/android.support.v7.appcompat.R.drawable.html
    -@@ -144,7 +144,7 @@ Class android.support.v7.appcompat.<A HREF="../../../../reference/android/suppor
    -     </div> <!-- end footer -->
    -     </div><!-- end doc-content -->
    -     </div> <!-- end body-content --> 
    --<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    - </script>
    - <script type="text/javascript">
    -   try {
    -diff --git a/docs/html/sdk/support_api_diff/23/changes/android.support.v7.appcompat.R.id.html b/docs/html/sdk/support_api_diff/23/changes/android.support.v7.appcompat.R.id.html
    -index 2b34b3a..818a5b0 100644
    ---- a/docs/html/sdk/support_api_diff/23/changes/android.support.v7.appcompat.R.id.html
    -+++ b/docs/html/sdk/support_api_diff/23/changes/android.support.v7.appcompat.R.id.html
    -@@ -115,7 +115,7 @@ Class android.support.v7.appcompat.<A HREF="../../../../reference/android/suppor
    -     </div> <!-- end footer -->
    -     </div><!-- end doc-content -->
    -     </div> <!-- end body-content --> 
    --<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    - </script>
    - <script type="text/javascript">
    -   try {
    -diff --git a/docs/html/sdk/support_api_diff/23/changes/android.support.v7.appcompat.R.layout.html b/docs/html/sdk/support_api_diff/23/changes/android.support.v7.appcompat.R.layout.html
    -index 9d24903..a0a33fb 100644
    ---- a/docs/html/sdk/support_api_diff/23/changes/android.support.v7.appcompat.R.layout.html
    -+++ b/docs/html/sdk/support_api_diff/23/changes/android.support.v7.appcompat.R.layout.html
    -@@ -108,7 +108,7 @@ Class android.support.v7.appcompat.<A HREF="../../../../reference/android/suppor
    -     </div> <!-- end footer -->
    -     </div><!-- end doc-content -->
    -     </div> <!-- end body-content --> 
    --<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    - </script>
    - <script type="text/javascript">
    -   try {
    -diff --git a/docs/html/sdk/support_api_diff/23/changes/android.support.v7.appcompat.R.style.html b/docs/html/sdk/support_api_diff/23/changes/android.support.v7.appcompat.R.style.html
    -index 8b16f1c..d084de0 100644
    ---- a/docs/html/sdk/support_api_diff/23/changes/android.support.v7.appcompat.R.style.html
    -+++ b/docs/html/sdk/support_api_diff/23/changes/android.support.v7.appcompat.R.style.html
    -@@ -207,7 +207,7 @@ Class android.support.v7.appcompat.<A HREF="../../../../reference/android/suppor
    -     </div> <!-- end footer -->
    -     </div><!-- end doc-content -->
    -     </div> <!-- end body-content --> 
    --<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    - </script>
    - <script type="text/javascript">
    -   try {
    -diff --git a/docs/html/sdk/support_api_diff/23/changes/android.support.v7.appcompat.R.styleable.html b/docs/html/sdk/support_api_diff/23/changes/android.support.v7.appcompat.R.styleable.html
    -index 5365376..c021cbe 100644
    ---- a/docs/html/sdk/support_api_diff/23/changes/android.support.v7.appcompat.R.styleable.html
    -+++ b/docs/html/sdk/support_api_diff/23/changes/android.support.v7.appcompat.R.styleable.html
    -@@ -333,7 +333,7 @@ Class android.support.v7.appcompat.<A HREF="../../../../reference/android/suppor
    -     </div> <!-- end footer -->
    -     </div><!-- end doc-content -->
    -     </div> <!-- end body-content --> 
    --<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    - </script>
    - <script type="text/javascript">
    -   try {
    -diff --git a/docs/html/sdk/support_api_diff/23/changes/android.support.v7.graphics.Palette.Builder.html b/docs/html/sdk/support_api_diff/23/changes/android.support.v7.graphics.Palette.Builder.html
    -index 3893441..e707730 100644
    ---- a/docs/html/sdk/support_api_diff/23/changes/android.support.v7.graphics.Palette.Builder.html
    -+++ b/docs/html/sdk/support_api_diff/23/changes/android.support.v7.graphics.Palette.Builder.html
    -@@ -115,7 +115,7 @@ Class android.support.v7.graphics.<A HREF="../../../../reference/android/support
    -     </div> <!-- end footer -->
    -     </div><!-- end doc-content -->
    -     </div> <!-- end body-content --> 
    --<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    - </script>
    - <script type="text/javascript">
    -   try {
    -diff --git a/docs/html/sdk/support_api_diff/23/changes/changes-summary.html b/docs/html/sdk/support_api_diff/23/changes/changes-summary.html
    -index 3deee46..75c1eb3 100644
    ---- a/docs/html/sdk/support_api_diff/23/changes/changes-summary.html
    -+++ b/docs/html/sdk/support_api_diff/23/changes/changes-summary.html
    -@@ -310,7 +310,7 @@ see the <a href="http://developer.android.com/index.html" target="_top">Android
    -     </div> <!-- end footer -->
    -     </div><!-- end doc-content -->
    -     </div> <!-- end body-content --> 
    --<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    - </script>
    - <script type="text/javascript">
    -   try {
    -diff --git a/docs/html/sdk/support_api_diff/23/changes/classes_index_additions.html b/docs/html/sdk/support_api_diff/23/changes/classes_index_additions.html
    -index 094fff5..bc69616 100644
    ---- a/docs/html/sdk/support_api_diff/23/changes/classes_index_additions.html
    -+++ b/docs/html/sdk/support_api_diff/23/changes/classes_index_additions.html
    -@@ -160,7 +160,7 @@ Listed as: <span style="color:#069"><strong>Added</strong></span>,  <span style=
    - <A HREF="pkg_android.support.v4.content.html#SharedPreferencesCompat" class="hiddenlink" target="rightframe"><b>SharedPreferencesCompat</b></A><br>
    - <A HREF="pkg_android.support.v4.content.html#SharedPreferencesCompat.EditorCompat" class="hiddenlink" target="rightframe"><b>SharedPreferencesCompat.EditorCompat</b></A><br>
    - <A HREF="pkg_android.support.design.widget.html#Snackbar.Callback" class="hiddenlink" target="rightframe"><b>Snackbar.Callback</b></A><br>
    --<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    - </script>
    - <script type="text/javascript">
    -   try {
    -diff --git a/docs/html/sdk/support_api_diff/23/changes/classes_index_all.html b/docs/html/sdk/support_api_diff/23/changes/classes_index_all.html
    -index cb1ed5f..33a23bf 100644
    ---- a/docs/html/sdk/support_api_diff/23/changes/classes_index_all.html
    -+++ b/docs/html/sdk/support_api_diff/23/changes/classes_index_all.html
    -@@ -419,7 +419,7 @@ Listed as: <span style="color:#069"><strong>Added</strong></span>,  <span style=
    -  <a href="#topheader"><font size="-2">TOP</font></a>
    - <p><div style="line-height:1.5em;color:black">
    - <A HREF="android.support.v4.view.ViewCompat.html" class="hiddenlink" target="rightframe">ViewCompat</A><br>
    --<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    - </script>
    - <script type="text/javascript">
    -   try {
    -diff --git a/docs/html/sdk/support_api_diff/23/changes/classes_index_changes.html b/docs/html/sdk/support_api_diff/23/changes/classes_index_changes.html
    -index b674f27..9588a73 100644
    ---- a/docs/html/sdk/support_api_diff/23/changes/classes_index_changes.html
    -+++ b/docs/html/sdk/support_api_diff/23/changes/classes_index_changes.html
    -@@ -328,7 +328,7 @@ Listed as: <span style="color:#069"><strong>Added</strong></span>,  <span style=
    -  <a href="#topheader"><font size="-2">TOP</font></a>
    - <p><div style="line-height:1.5em;color:black">
    - <A HREF="android.support.v4.view.ViewCompat.html" class="hiddenlink" target="rightframe">ViewCompat</A><br>
    --<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    - </script>
    - <script type="text/javascript">
    -   try {
    -diff --git a/docs/html/sdk/support_api_diff/23/changes/classes_index_removals.html b/docs/html/sdk/support_api_diff/23/changes/classes_index_removals.html
    -index e6da73f..c466298 100644
    ---- a/docs/html/sdk/support_api_diff/23/changes/classes_index_removals.html
    -+++ b/docs/html/sdk/support_api_diff/23/changes/classes_index_removals.html
    -@@ -47,7 +47,7 @@ body{overflow:auto;}
    - <div id="indexTableCaption" style="background-color:#eee;padding:0 4px 0 4px;font-size:11px;margin-bottom:1em;">
    - Listed as: <span style="color:#069"><strong>Added</strong></span>,  <span style="color:#069"><strike>Removed</strike></span>,  <span style="color:#069">Changed</span></font>
    - </div>
    --<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    - </script>
    - <script type="text/javascript">
    -   try {
    -diff --git a/docs/html/sdk/support_api_diff/23/changes/constructors_index_additions.html b/docs/html/sdk/support_api_diff/23/changes/constructors_index_additions.html
    -index d1e5215..ae8c0d3 100644
    ---- a/docs/html/sdk/support_api_diff/23/changes/constructors_index_additions.html
    -+++ b/docs/html/sdk/support_api_diff/23/changes/constructors_index_additions.html
    -@@ -53,7 +53,7 @@ Listed as: <span style="color:#069"><strong>Added</strong></span>,  <span style=
    - <p><div style="line-height:1.5em;color:black">
    - <nobr><A HREF="android.support.design.widget.TextInputLayout.html#android.support.design.widget.TextInputLayout.ctor_added(android.content.Context, android.util.AttributeSet, int)" class="hiddenlink" target="rightframe"><b>TextInputLayout</b>
    - (<code>Context, AttributeSet, int</code>)</A></nobr>&nbsp;constructor<br>
    --<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    - </script>
    - <script type="text/javascript">
    -   try {
    -diff --git a/docs/html/sdk/support_api_diff/23/changes/constructors_index_all.html b/docs/html/sdk/support_api_diff/23/changes/constructors_index_all.html
    -index 4618d88..401df57 100644
    ---- a/docs/html/sdk/support_api_diff/23/changes/constructors_index_all.html
    -+++ b/docs/html/sdk/support_api_diff/23/changes/constructors_index_all.html
    -@@ -53,7 +53,7 @@ Listed as: <span style="color:#069"><strong>Added</strong></span>,  <span style=
    - <p><div style="line-height:1.5em;color:black">
    - <nobr><A HREF="android.support.design.widget.TextInputLayout.html#android.support.design.widget.TextInputLayout.ctor_added(android.content.Context, android.util.AttributeSet, int)" class="hiddenlink" target="rightframe"><b>TextInputLayout</b>
    - (<code>Context, AttributeSet, int</code>)</A></nobr>&nbsp;constructor<br>
    --<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    - </script>
    - <script type="text/javascript">
    -   try {
    -diff --git a/docs/html/sdk/support_api_diff/23/changes/constructors_index_changes.html b/docs/html/sdk/support_api_diff/23/changes/constructors_index_changes.html
    -index a5ca2ef..122cdce 100644
    ---- a/docs/html/sdk/support_api_diff/23/changes/constructors_index_changes.html
    -+++ b/docs/html/sdk/support_api_diff/23/changes/constructors_index_changes.html
    -@@ -47,7 +47,7 @@ body{overflow:auto;}
    - <div id="indexTableCaption" style="background-color:#eee;padding:0 4px 0 4px;font-size:11px;margin-bottom:1em;">
    - Listed as: <span style="color:#069"><strong>Added</strong></span>,  <span style="color:#069"><strike>Removed</strike></span>,  <span style="color:#069">Changed</span></font>
    - </div>
    --<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    - </script>
    - <script type="text/javascript">
    -   try {
    -diff --git a/docs/html/sdk/support_api_diff/23/changes/constructors_index_removals.html b/docs/html/sdk/support_api_diff/23/changes/constructors_index_removals.html
    -index 74a09ba..dadd1cd 100644
    ---- a/docs/html/sdk/support_api_diff/23/changes/constructors_index_removals.html
    -+++ b/docs/html/sdk/support_api_diff/23/changes/constructors_index_removals.html
    -@@ -47,7 +47,7 @@ body{overflow:auto;}
    - <div id="indexTableCaption" style="background-color:#eee;padding:0 4px 0 4px;font-size:11px;margin-bottom:1em;">
    - Listed as: <span style="color:#069"><strong>Added</strong></span>,  <span style="color:#069"><strike>Removed</strike></span>,  <span style="color:#069">Changed</span></font>
    - </div>
    --<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    - </script>
    - <script type="text/javascript">
    -   try {
    -diff --git a/docs/html/sdk/support_api_diff/23/changes/fields_index_additions.html b/docs/html/sdk/support_api_diff/23/changes/fields_index_additions.html
    -index 2f6ac9c..f9137b8 100644
    ---- a/docs/html/sdk/support_api_diff/23/changes/fields_index_additions.html
    -+++ b/docs/html/sdk/support_api_diff/23/changes/fields_index_additions.html
    -@@ -444,7 +444,7 @@ Listed as: <span style="color:#069"><strong>Added</strong></span>,  <span style=
    - <p><div style="line-height:1.5em;color:black">
    - <nobr><A HREF="android.support.v7.appcompat.R.style.html#android.support.v7.appcompat.R.style.Widget_AppCompat_Button_Colored" class="hiddenlink" target="rightframe">Widget_AppCompat_Button_Colored</A>
    - </nobr><br>
    --<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    - </script>
    - <script type="text/javascript">
    -   try {
    -diff --git a/docs/html/sdk/support_api_diff/23/changes/fields_index_all.html b/docs/html/sdk/support_api_diff/23/changes/fields_index_all.html
    -index a7f5e18..909dbcc 100644
    ---- a/docs/html/sdk/support_api_diff/23/changes/fields_index_all.html
    -+++ b/docs/html/sdk/support_api_diff/23/changes/fields_index_all.html
    -@@ -538,7 +538,7 @@ Listed as: <span style="color:#069"><strong>Added</strong></span>,  <span style=
    - <p><div style="line-height:1.5em;color:black">
    - <nobr><A HREF="android.support.v7.appcompat.R.style.html#android.support.v7.appcompat.R.style.Widget_AppCompat_Button_Colored" class="hiddenlink" target="rightframe">Widget_AppCompat_Button_Colored</A>
    - </nobr><br>
    --<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    - </script>
    - <script type="text/javascript">
    -   try {
    -diff --git a/docs/html/sdk/support_api_diff/23/changes/fields_index_changes.html b/docs/html/sdk/support_api_diff/23/changes/fields_index_changes.html
    -index 0e2ccff..301881a 100644
    ---- a/docs/html/sdk/support_api_diff/23/changes/fields_index_changes.html
    -+++ b/docs/html/sdk/support_api_diff/23/changes/fields_index_changes.html
    -@@ -47,7 +47,7 @@ body{overflow:auto;}
    - <div id="indexTableCaption" style="background-color:#eee;padding:0 4px 0 4px;font-size:11px;margin-bottom:1em;">
    - Listed as: <span style="color:#069"><strong>Added</strong></span>,  <span style="color:#069"><strike>Removed</strike></span>,  <span style="color:#069">Changed</span></font>
    - </div>
    --<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    - </script>
    - <script type="text/javascript">
    -   try {
    -diff --git a/docs/html/sdk/support_api_diff/23/changes/fields_index_removals.html b/docs/html/sdk/support_api_diff/23/changes/fields_index_removals.html
    -index 5027374..174a576 100644
    ---- a/docs/html/sdk/support_api_diff/23/changes/fields_index_removals.html
    -+++ b/docs/html/sdk/support_api_diff/23/changes/fields_index_removals.html
    -@@ -241,7 +241,7 @@ Listed as: <span style="color:#069"><strong>Added</strong></span>,  <span style=
    - </nobr><br>
    - <nobr><A HREF="android.support.v7.appcompat.R.styleable.html#android.support.v7.appcompat.R.styleable.View_backgroundTintMode" class="hiddenlink" target="rightframe"><strike>View_backgroundTintMode</strike></A>
    - </nobr><br>
    --<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    - </script>
    - <script type="text/javascript">
    -   try {
    -diff --git a/docs/html/sdk/support_api_diff/23/changes/jdiff_help.html b/docs/html/sdk/support_api_diff/23/changes/jdiff_help.html
    -index acb8508..125d4e8 100644
    ---- a/docs/html/sdk/support_api_diff/23/changes/jdiff_help.html
    -+++ b/docs/html/sdk/support_api_diff/23/changes/jdiff_help.html
    -@@ -120,7 +120,7 @@ These links show and hide the HTML frames. All pages are available with or witho
    - There are some complex changes which can occur between versions, for example, when two or more methods with the same name change simultaneously, or when a method or field is moved into or from a superclass. 
    - In these cases, the change will be seen as a removal and an addition, rather than as a change. Unexpected removals or additions are often part of one of these type of changes. 
    - </BLOCKQUOTE>
    --<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    - </script>
    - <script type="text/javascript">
    -   try {
    -diff --git a/docs/html/sdk/support_api_diff/23/changes/jdiff_statistics.html b/docs/html/sdk/support_api_diff/23/changes/jdiff_statistics.html
    -index 4480788..1e865b7 100644
    ---- a/docs/html/sdk/support_api_diff/23/changes/jdiff_statistics.html
    -+++ b/docs/html/sdk/support_api_diff/23/changes/jdiff_statistics.html
    -@@ -467,7 +467,7 @@ added, the change will be 100%.</p>
    -     </div> <!-- end footer -->
    -     </div><!-- end doc-content -->
    -     </div> <!-- end body-content --> 
    --<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    - </script>
    - <script type="text/javascript">
    -   try {
    -diff --git a/docs/html/sdk/support_api_diff/23/changes/jdiff_topleftframe.html b/docs/html/sdk/support_api_diff/23/changes/jdiff_topleftframe.html
    -index 36f9836..6a2e76e 100644
    ---- a/docs/html/sdk/support_api_diff/23/changes/jdiff_topleftframe.html
    -+++ b/docs/html/sdk/support_api_diff/23/changes/jdiff_topleftframe.html
    -@@ -49,7 +49,7 @@ body{overflow:auto;}
    -   <TD NOWRAP><FONT CLASS="indexText" size="-2"><A HREF="fields_index_all.html" TARGET="bottomleftframe">By Field</A></FONT><br></TD>
    - </TR>
    - </TABLE>
    --<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    - </script>
    - <script type="text/javascript">
    -   try {
    -diff --git a/docs/html/sdk/support_api_diff/23/changes/methods_index_additions.html b/docs/html/sdk/support_api_diff/23/changes/methods_index_additions.html
    -index 3cec9a3..c3e4176 100644
    ---- a/docs/html/sdk/support_api_diff/23/changes/methods_index_additions.html
    -+++ b/docs/html/sdk/support_api_diff/23/changes/methods_index_additions.html
    -@@ -529,7 +529,7 @@ Listed as: <span style="color:#069"><strong>Added</strong></span>,  <span style=
    - <p><div style="line-height:1.5em;color:black">
    - <nobr><A HREF="android.support.v4.app.FragmentActivity.html#android.support.v4.app.FragmentActivity.validateRequestPermissionsRequestCode_added(int)" class="hiddenlink" target="rightframe"><b>validateRequestPermissionsRequestCode</b>
    - (<code>int</code>)</A></nobr><br>
    --<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    - </script>
    - <script type="text/javascript">
    -   try {
    -diff --git a/docs/html/sdk/support_api_diff/23/changes/methods_index_all.html b/docs/html/sdk/support_api_diff/23/changes/methods_index_all.html
    -index 072b2ff..7b2f1d4 100644
    ---- a/docs/html/sdk/support_api_diff/23/changes/methods_index_all.html
    -+++ b/docs/html/sdk/support_api_diff/23/changes/methods_index_all.html
    -@@ -550,7 +550,7 @@ Listed as: <span style="color:#069"><strong>Added</strong></span>,  <span style=
    - <p><div style="line-height:1.5em;color:black">
    - <nobr><A HREF="android.support.v4.app.FragmentActivity.html#android.support.v4.app.FragmentActivity.validateRequestPermissionsRequestCode_added(int)" class="hiddenlink" target="rightframe"><b>validateRequestPermissionsRequestCode</b>
    - (<code>int</code>)</A></nobr><br>
    --<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    - </script>
    - <script type="text/javascript">
    -   try {
    -diff --git a/docs/html/sdk/support_api_diff/23/changes/methods_index_changes.html b/docs/html/sdk/support_api_diff/23/changes/methods_index_changes.html
    -index d190580..90a0a23 100644
    ---- a/docs/html/sdk/support_api_diff/23/changes/methods_index_changes.html
    -+++ b/docs/html/sdk/support_api_diff/23/changes/methods_index_changes.html
    -@@ -83,7 +83,7 @@ Listed as: <span style="color:#069"><strong>Added</strong></span>,  <span style=
    - <p><div style="line-height:1.5em;color:black">
    - <nobr><A HREF="android.support.v17.leanback.widget.FullWidthDetailsOverviewRowPresenter.html#android.support.v17.leanback.widget.FullWidthDetailsOverviewRowPresenter.setBackgroundColor_changed(int)" class="hiddenlink" target="rightframe">setBackgroundColor
    - (<code>int</code>)</A></nobr><br>
    --<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    - </script>
    - <script type="text/javascript">
    -   try {
    -diff --git a/docs/html/sdk/support_api_diff/23/changes/methods_index_removals.html b/docs/html/sdk/support_api_diff/23/changes/methods_index_removals.html
    -index 2517575..ce89d27 100644
    ---- a/docs/html/sdk/support_api_diff/23/changes/methods_index_removals.html
    -+++ b/docs/html/sdk/support_api_diff/23/changes/methods_index_removals.html
    -@@ -71,7 +71,7 @@ Listed as: <span style="color:#069"><strong>Added</strong></span>,  <span style=
    - <p><div style="line-height:1.5em;color:black">
    - <nobr><A HREF="android.support.v4.app.Fragment.html#android.support.v4.app.Fragment.onAttach_removed(android.app.Activity)" class="hiddenlink" target="rightframe"><strike>onAttach</strike>
    - (<code>Activity</code>)</A></nobr><br>
    --<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    - </script>
    - <script type="text/javascript">
    -   try {
    -diff --git a/docs/html/sdk/support_api_diff/23/changes/packages_index_additions.html b/docs/html/sdk/support_api_diff/23/changes/packages_index_additions.html
    -index 446ee58..fc6d24d 100644
    ---- a/docs/html/sdk/support_api_diff/23/changes/packages_index_additions.html
    -+++ b/docs/html/sdk/support_api_diff/23/changes/packages_index_additions.html
    -@@ -59,7 +59,7 @@ Listed as: <span style="color:#069"><strong>Added</strong></span>,  <span style=
    - <A HREF="changes-summary.html#android.support.v7.graphics.drawable" class="hiddenlink" target="rightframe"><b>android.support.v7.graphics.drawable</b></A><br>
    - <A HREF="changes-summary.html#android.support.v7.preference" class="hiddenlink" target="rightframe"><b>android.support.v7.preference</b></A><br>
    - <A HREF="changes-summary.html#android.support.v8.renderscript" class="hiddenlink" target="rightframe"><b>android.support.v8.renderscript</b></A><br>
    --<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    - </script>
    - <script type="text/javascript">
    -   try {
    -diff --git a/docs/html/sdk/support_api_diff/23/changes/packages_index_all.html b/docs/html/sdk/support_api_diff/23/changes/packages_index_all.html
    -index d1dbbe1..c770167 100644
    ---- a/docs/html/sdk/support_api_diff/23/changes/packages_index_all.html
    -+++ b/docs/html/sdk/support_api_diff/23/changes/packages_index_all.html
    -@@ -77,7 +77,7 @@ Listed as: <span style="color:#069"><strong>Added</strong></span>,  <span style=
    - <A HREF="changes-summary.html#android.support.v7.preference" class="hiddenlink" target="rightframe"><b>android.support.v7.preference</b></A><br>
    - <A HREF="pkg_android.support.v7.util.html" class="hiddenlink" target="rightframe">android.support.v7.util</A><br>
    - <A HREF="changes-summary.html#android.support.v8.renderscript" class="hiddenlink" target="rightframe"><b>android.support.v8.renderscript</b></A><br>
    --<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    - </script>
    - <script type="text/javascript">
    -   try {
    -diff --git a/docs/html/sdk/support_api_diff/23/changes/packages_index_changes.html b/docs/html/sdk/support_api_diff/23/changes/packages_index_changes.html
    -index 730633e..2140313 100644
    ---- a/docs/html/sdk/support_api_diff/23/changes/packages_index_changes.html
    -+++ b/docs/html/sdk/support_api_diff/23/changes/packages_index_changes.html
    -@@ -68,7 +68,7 @@ Listed as: <span style="color:#069"><strong>Added</strong></span>,  <span style=
    - <A HREF="pkg_android.support.v7.appcompat.html" class="hiddenlink" target="rightframe">android.support.v7.appcompat</A><br>
    - <A HREF="pkg_android.support.v7.graphics.html" class="hiddenlink" target="rightframe">android.support.v7.graphics</A><br>
    - <A HREF="pkg_android.support.v7.util.html" class="hiddenlink" target="rightframe">android.support.v7.util</A><br>
    --<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    - </script>
    - <script type="text/javascript">
    -   try {
    -diff --git a/docs/html/sdk/support_api_diff/23/changes/packages_index_removals.html b/docs/html/sdk/support_api_diff/23/changes/packages_index_removals.html
    -index d0ffabc..d5a825d 100644
    ---- a/docs/html/sdk/support_api_diff/23/changes/packages_index_removals.html
    -+++ b/docs/html/sdk/support_api_diff/23/changes/packages_index_removals.html
    -@@ -49,7 +49,7 @@ Listed as: <span style="color:#069"><strong>Added</strong></span>,  <span style=
    - </div>
    - <br>
    - <div id="indexTableEntries">
    --<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    - </script>
    - <script type="text/javascript">
    -   try {
    -diff --git a/docs/html/sdk/support_api_diff/23/changes/pkg_android.support.design.widget.html b/docs/html/sdk/support_api_diff/23/changes/pkg_android.support.design.widget.html
    -index a8630f7..6ebc3a7 100644
    ---- a/docs/html/sdk/support_api_diff/23/changes/pkg_android.support.design.widget.html
    -+++ b/docs/html/sdk/support_api_diff/23/changes/pkg_android.support.design.widget.html
    -@@ -169,7 +169,7 @@ Package <A HREF="../../../../reference/android/support/design/widget/package-sum
    -     </div> <!-- end footer -->
    -     </div><!-- end doc-content -->
    -     </div> <!-- end body-content --> 
    --<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    - </script>
    - <script type="text/javascript">
    -   try {
    -diff --git a/docs/html/sdk/support_api_diff/23/changes/pkg_android.support.v13.app.html b/docs/html/sdk/support_api_diff/23/changes/pkg_android.support.v13.app.html
    -index c56e8a4..877fd6c 100644
    ---- a/docs/html/sdk/support_api_diff/23/changes/pkg_android.support.v13.app.html
    -+++ b/docs/html/sdk/support_api_diff/23/changes/pkg_android.support.v13.app.html
    -@@ -120,7 +120,7 @@ Package <A HREF="../../../../reference/android/support/v13/app/package-summary.h
    -     </div> <!-- end footer -->
    -     </div><!-- end doc-content -->
    -     </div> <!-- end body-content --> 
    --<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    - </script>
    - <script type="text/javascript">
    -   try {
    -diff --git a/docs/html/sdk/support_api_diff/23/changes/pkg_android.support.v17.leanback.widget.html b/docs/html/sdk/support_api_diff/23/changes/pkg_android.support.v17.leanback.widget.html
    -index 3d7f780..ea3848e 100644
    ---- a/docs/html/sdk/support_api_diff/23/changes/pkg_android.support.v17.leanback.widget.html
    -+++ b/docs/html/sdk/support_api_diff/23/changes/pkg_android.support.v17.leanback.widget.html
    -@@ -112,7 +112,7 @@ Package <A HREF="../../../../reference/android/support/v17/leanback/widget/packa
    -     </div> <!-- end footer -->
    -     </div><!-- end doc-content -->
    -     </div> <!-- end body-content --> 
    --<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    - </script>
    - <script type="text/javascript">
    -   try {
    -diff --git a/docs/html/sdk/support_api_diff/23/changes/pkg_android.support.v4.animation.html b/docs/html/sdk/support_api_diff/23/changes/pkg_android.support.v4.animation.html
    -index 36965dd..4a51cf8 100644
    ---- a/docs/html/sdk/support_api_diff/23/changes/pkg_android.support.v4.animation.html
    -+++ b/docs/html/sdk/support_api_diff/23/changes/pkg_android.support.v4.animation.html
    -@@ -105,7 +105,7 @@ Package <A HREF="../../../../reference/android/support/v4/animation/package-summ
    -     </div> <!-- end footer -->
    -     </div><!-- end doc-content -->
    -     </div> <!-- end body-content --> 
    --<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    - </script>
    - <script type="text/javascript">
    -   try {
    -diff --git a/docs/html/sdk/support_api_diff/23/changes/pkg_android.support.v4.app.html b/docs/html/sdk/support_api_diff/23/changes/pkg_android.support.v4.app.html
    -index 692e7ef..9fbee40 100644
    ---- a/docs/html/sdk/support_api_diff/23/changes/pkg_android.support.v4.app.html
    -+++ b/docs/html/sdk/support_api_diff/23/changes/pkg_android.support.v4.app.html
    -@@ -176,7 +176,7 @@ Package <A HREF="../../../../reference/android/support/v4/app/package-summary.ht
    -     </div> <!-- end footer -->
    -     </div><!-- end doc-content -->
    -     </div> <!-- end body-content --> 
    --<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    - </script>
    - <script type="text/javascript">
    -   try {
    -diff --git a/docs/html/sdk/support_api_diff/23/changes/pkg_android.support.v4.content.html b/docs/html/sdk/support_api_diff/23/changes/pkg_android.support.v4.content.html
    -index 44e9f81..9e654a6 100644
    ---- a/docs/html/sdk/support_api_diff/23/changes/pkg_android.support.v4.content.html
    -+++ b/docs/html/sdk/support_api_diff/23/changes/pkg_android.support.v4.content.html
    -@@ -169,7 +169,7 @@ Package <A HREF="../../../../reference/android/support/v4/content/package-summar
    -     </div> <!-- end footer -->
    -     </div><!-- end doc-content -->
    -     </div> <!-- end body-content --> 
    --<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    - </script>
    - <script type="text/javascript">
    -   try {
    -diff --git a/docs/html/sdk/support_api_diff/23/changes/pkg_android.support.v4.graphics.drawable.html b/docs/html/sdk/support_api_diff/23/changes/pkg_android.support.v4.graphics.drawable.html
    -index 6139c8e..de77561 100644
    ---- a/docs/html/sdk/support_api_diff/23/changes/pkg_android.support.v4.graphics.drawable.html
    -+++ b/docs/html/sdk/support_api_diff/23/changes/pkg_android.support.v4.graphics.drawable.html
    -@@ -112,7 +112,7 @@ Package <A HREF="../../../../reference/android/support/v4/graphics/drawable/pack
    -     </div> <!-- end footer -->
    -     </div><!-- end doc-content -->
    -     </div> <!-- end body-content --> 
    --<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    - </script>
    - <script type="text/javascript">
    -   try {
    -diff --git a/docs/html/sdk/support_api_diff/23/changes/pkg_android.support.v4.media.html b/docs/html/sdk/support_api_diff/23/changes/pkg_android.support.v4.media.html
    -index e6fe510..761e746 100644
    ---- a/docs/html/sdk/support_api_diff/23/changes/pkg_android.support.v4.media.html
    -+++ b/docs/html/sdk/support_api_diff/23/changes/pkg_android.support.v4.media.html
    -@@ -112,7 +112,7 @@ Package <A HREF="../../../../reference/android/support/v4/media/package-summary.
    -     </div> <!-- end footer -->
    -     </div><!-- end doc-content -->
    -     </div> <!-- end body-content --> 
    --<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    - </script>
    - <script type="text/javascript">
    -   try {
    -diff --git a/docs/html/sdk/support_api_diff/23/changes/pkg_android.support.v4.media.session.html b/docs/html/sdk/support_api_diff/23/changes/pkg_android.support.v4.media.session.html
    -index 9b0e472..18893f4 100644
    ---- a/docs/html/sdk/support_api_diff/23/changes/pkg_android.support.v4.media.session.html
    -+++ b/docs/html/sdk/support_api_diff/23/changes/pkg_android.support.v4.media.session.html
    -@@ -119,7 +119,7 @@ Package <A HREF="../../../../reference/android/support/v4/media/session/package-
    -     </div> <!-- end footer -->
    -     </div><!-- end doc-content -->
    -     </div> <!-- end body-content --> 
    --<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    - </script>
    - <script type="text/javascript">
    -   try {
    -diff --git a/docs/html/sdk/support_api_diff/23/changes/pkg_android.support.v4.os.html b/docs/html/sdk/support_api_diff/23/changes/pkg_android.support.v4.os.html
    -index 9a76a7b..2ed8d04 100644
    ---- a/docs/html/sdk/support_api_diff/23/changes/pkg_android.support.v4.os.html
    -+++ b/docs/html/sdk/support_api_diff/23/changes/pkg_android.support.v4.os.html
    -@@ -119,7 +119,7 @@ Package <A HREF="../../../../reference/android/support/v4/os/package-summary.htm
    -     </div> <!-- end footer -->
    -     </div><!-- end doc-content -->
    -     </div> <!-- end body-content --> 
    --<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    - </script>
    - <script type="text/javascript">
    -   try {
    -diff --git a/docs/html/sdk/support_api_diff/23/changes/pkg_android.support.v4.text.html b/docs/html/sdk/support_api_diff/23/changes/pkg_android.support.v4.text.html
    -index b2a178a..c995ed8 100644
    ---- a/docs/html/sdk/support_api_diff/23/changes/pkg_android.support.v4.text.html
    -+++ b/docs/html/sdk/support_api_diff/23/changes/pkg_android.support.v4.text.html
    -@@ -105,7 +105,7 @@ Package <A HREF="../../../../reference/android/support/v4/text/package-summary.h
    -     </div> <!-- end footer -->
    -     </div><!-- end doc-content -->
    -     </div> <!-- end body-content --> 
    --<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    - </script>
    - <script type="text/javascript">
    -   try {
    -diff --git a/docs/html/sdk/support_api_diff/23/changes/pkg_android.support.v4.view.accessibility.html b/docs/html/sdk/support_api_diff/23/changes/pkg_android.support.v4.view.accessibility.html
    -index dcdbc56..ec69556 100644
    ---- a/docs/html/sdk/support_api_diff/23/changes/pkg_android.support.v4.view.accessibility.html
    -+++ b/docs/html/sdk/support_api_diff/23/changes/pkg_android.support.v4.view.accessibility.html
    -@@ -127,7 +127,7 @@ Package <A HREF="../../../../reference/android/support/v4/view/accessibility/pac
    -     </div> <!-- end footer -->
    -     </div><!-- end doc-content -->
    -     </div> <!-- end body-content --> 
    --<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    - </script>
    - <script type="text/javascript">
    -   try {
    -diff --git a/docs/html/sdk/support_api_diff/23/changes/pkg_android.support.v4.view.html b/docs/html/sdk/support_api_diff/23/changes/pkg_android.support.v4.view.html
    -index 2a955d3..2361c0f 100644
    ---- a/docs/html/sdk/support_api_diff/23/changes/pkg_android.support.v4.view.html
    -+++ b/docs/html/sdk/support_api_diff/23/changes/pkg_android.support.v4.view.html
    -@@ -105,7 +105,7 @@ Package <A HREF="../../../../reference/android/support/v4/view/package-summary.h
    -     </div> <!-- end footer -->
    -     </div><!-- end doc-content -->
    -     </div> <!-- end body-content --> 
    --<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    - </script>
    - <script type="text/javascript">
    -   try {
    -diff --git a/docs/html/sdk/support_api_diff/23/changes/pkg_android.support.v4.widget.html b/docs/html/sdk/support_api_diff/23/changes/pkg_android.support.v4.widget.html
    -index 482bf1f..c6b5e0c 100644
    ---- a/docs/html/sdk/support_api_diff/23/changes/pkg_android.support.v4.widget.html
    -+++ b/docs/html/sdk/support_api_diff/23/changes/pkg_android.support.v4.widget.html
    -@@ -141,7 +141,7 @@ Package <A HREF="../../../../reference/android/support/v4/widget/package-summary
    -     </div> <!-- end footer -->
    -     </div><!-- end doc-content -->
    -     </div> <!-- end body-content --> 
    --<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    - </script>
    - <script type="text/javascript">
    -   try {
    -diff --git a/docs/html/sdk/support_api_diff/23/changes/pkg_android.support.v7.app.html b/docs/html/sdk/support_api_diff/23/changes/pkg_android.support.v7.app.html
    -index 1dd5425..a99b641 100644
    ---- a/docs/html/sdk/support_api_diff/23/changes/pkg_android.support.v7.app.html
    -+++ b/docs/html/sdk/support_api_diff/23/changes/pkg_android.support.v7.app.html
    -@@ -120,7 +120,7 @@ Package <A HREF="../../../../reference/android/support/v7/app/package-summary.ht
    -     </div> <!-- end footer -->
    -     </div><!-- end doc-content -->
    -     </div> <!-- end body-content --> 
    --<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    - </script>
    - <script type="text/javascript">
    -   try {
    -diff --git a/docs/html/sdk/support_api_diff/23/changes/pkg_android.support.v7.appcompat.html b/docs/html/sdk/support_api_diff/23/changes/pkg_android.support.v7.appcompat.html
    -index e014278..eb5ed08 100644
    ---- a/docs/html/sdk/support_api_diff/23/changes/pkg_android.support.v7.appcompat.html
    -+++ b/docs/html/sdk/support_api_diff/23/changes/pkg_android.support.v7.appcompat.html
    -@@ -154,7 +154,7 @@ Package <A HREF="../../../../reference/android/support/v7/appcompat/package-summ
    -     </div> <!-- end footer -->
    -     </div><!-- end doc-content -->
    -     </div> <!-- end body-content --> 
    --<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    - </script>
    - <script type="text/javascript">
    -   try {
    -diff --git a/docs/html/sdk/support_api_diff/23/changes/pkg_android.support.v7.graphics.html b/docs/html/sdk/support_api_diff/23/changes/pkg_android.support.v7.graphics.html
    -index cb6c97b..9f88138 100644
    ---- a/docs/html/sdk/support_api_diff/23/changes/pkg_android.support.v7.graphics.html
    -+++ b/docs/html/sdk/support_api_diff/23/changes/pkg_android.support.v7.graphics.html
    -@@ -120,7 +120,7 @@ Package <A HREF="../../../../reference/android/support/v7/graphics/package-summa
    -     </div> <!-- end footer -->
    -     </div><!-- end doc-content -->
    -     </div> <!-- end body-content --> 
    --<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    - </script>
    - <script type="text/javascript">
    -   try {
    -diff --git a/docs/html/sdk/support_api_diff/23/changes/pkg_android.support.v7.util.html b/docs/html/sdk/support_api_diff/23/changes/pkg_android.support.v7.util.html
    -index cc0065d..e4da229 100644
    ---- a/docs/html/sdk/support_api_diff/23/changes/pkg_android.support.v7.util.html
    -+++ b/docs/html/sdk/support_api_diff/23/changes/pkg_android.support.v7.util.html
    -@@ -119,7 +119,7 @@ Package <A HREF="../../../../reference/android/support/v7/util/package-summary.h
    -     </div> <!-- end footer -->
    -     </div><!-- end doc-content -->
    -     </div> <!-- end body-content --> 
    --<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    - </script>
    - <script type="text/javascript">
    -   try {
    -diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes.html b/docs/html/sdk/support_api_diff/24.2.0/changes.html
    -new file mode 100644
    -index 0000000..cdf8f36
    ---- /dev/null
    -+++ b/docs/html/sdk/support_api_diff/24.2.0/changes.html
    -@@ -0,0 +1,45 @@
    -+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
    -+<HTML style="overflow:auto;">
    -+<HEAD>
    -+<meta name="generator" content="JDiff v1.1.0">
    -+<!-- Generated by the JDiff Javadoc doclet -->
    -+<!-- (http://www.jdiff.org) -->
    -+<!-- on Tue Aug 16 14:03:10 EDT 2016 -->
    -+<meta name="description" content="JDiff is a Javadoc doclet which generates an HTML report of all the packages, classes, constructors, methods, and fields which have been removed, added or changed in any way, including their documentation, when two APIs are compared.">
    -+<meta name="keywords" content="diff, jdiff, javadiff, java diff, java difference, API difference, difference between two APIs, API diff, Javadoc, doclet">
    -+<TITLE>
    -+Support&nbsp;Library&nbsp;API&nbsp;Differences&nbsp;Report
    -+</TITLE>
    -+<link href="../../../assets/android-developer-docs.css" rel="stylesheet" type="text/css" />
    -+<link href="stylesheet-jdiff.css" rel="stylesheet" type="text/css" />
    -+<noscript>
    -+<style type="text/css">
    -+body{overflow:auto;}
    -+#body-content{position:relative; top:0;}
    -+#doc-content{overflow:visible;border-left:3px solid #666;}
    -+#side-nav{padding:0;}
    -+#side-nav .toggle-list ul {display:block;}
    -+#resize-packages-nav{border-bottom:3px solid #666;}
    -+</style>
    -+</noscript>
    -+<style type="text/css">
    -+</style>
    -+</head>
    -+<frameset cols="242,**" framespacing="1" frameborder="yes" border="1" bordercolor="#e9e9e9"> 
    -+<frameset rows="174,**" framespacing="1" frameborder="yes"  border="1" bordercolor="#e9e9e9">
    -+    <frame src="changes/jdiff_topleftframe.html" scrolling="no" name="topleftframe" frameborder="1">
    -+    <frame src="changes/alldiffs_index_all.html" scrolling="auto" name="bottomleftframe" frameborder="1">
    -+  </frameset>
    -+  <frame src="changes/changes-summary.html" scrolling="auto" name="rightframe" frameborder="1">
    -+</frameset>
    -+<noframes>
    -+<h2>
    -+Frame Alert
    -+</h2>
    -+
    -+<p>
    -+This document is designed to be viewed using the frames feature. If you see this message, you are using a non-frame-capable web client.
    -+<br>
    -+Link to <a href="changes/changes-summary.html" target="_top">Non-frame version.</A>
    -+</noframes>
    -+</html>
    -diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/alldiffs_index_additions.html b/docs/html/sdk/support_api_diff/24.2.0/changes/alldiffs_index_additions.html
    -new file mode 100644
    -index 0000000..f73d864
    ---- /dev/null
    -+++ b/docs/html/sdk/support_api_diff/24.2.0/changes/alldiffs_index_additions.html
    -@@ -0,0 +1,947 @@
    -+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
    -+<HTML style="overflow:auto;">
    -+<HEAD>
    -+<meta name="generator" content="JDiff v1.1.0">
    -+<!-- Generated by the JDiff Javadoc doclet -->
    -+<!-- (http://www.jdiff.org) -->
    -+<meta name="description" content="JDiff is a Javadoc doclet which generates an HTML report of all the packages, classes, constructors, methods, and fields which have been removed, added or changed in any way, including their documentation, when two APIs are compared.">
    -+<meta name="keywords" content="diff, jdiff, javadiff, java diff, java difference, API difference, difference between two APIs, API diff, Javadoc, doclet">
    -+<TITLE>
    -+All Additions Index
    -+</TITLE>
    -+<link href="../../../../assets/android-developer-docs.css" rel="stylesheet" type="text/css" />
    -+<link href="../stylesheet-jdiff.css" rel="stylesheet" type="text/css" />
    -+<noscript>
    -+<style type="text/css">
    -+body{overflow:auto;}
    -+#body-content{position:relative; top:0;}
    -+#doc-content{overflow:visible;border-left:3px solid #666;}
    -+#side-nav{padding:0;}
    -+#side-nav .toggle-list ul {display:block;}
    -+#resize-packages-nav{border-bottom:3px solid #666;}
    -+</style>
    -+</noscript>
    -+<style type="text/css">
    -+</style>
    -+</HEAD>
    -+<BODY class="gc-documentation" style="padding:12px;">
    -+<a NAME="topheader"></a>
    -+<table summary="Index for All Differences" width="100%" class="jdiffIndex" border="0" cellspacing="0" cellpadding="0" style="padding-bottom:0;margin-bottom:0;">
    -+  <tr>
    -+  <th class="indexHeader">
    -+    Filter the Index:
    -+  </th>
    -+  </tr>
    -+  <tr>
    -+  <td class="indexText" style="line-height:1.3em;padding-left:2em;">
    -+<a href="alldiffs_index_all.html" xclass="hiddenlink">All Differences</a>
    -+  <br>
    -+<A HREF="alldiffs_index_removals.html" xclass="hiddenlink">Removals</A>
    -+  <br>
    -+<b>Additions</b>
    -+  <br>
    -+<A HREF="alldiffs_index_changes.html"xclass="hiddenlink">Changes</A>
    -+  </td>
    -+  </tr>
    -+</table>
    -+<div id="indexTableCaption" style="background-color:#eee;padding:0 4px 0 4px;font-size:11px;margin-bottom:1em;">
    -+Listed as: <span style="color:#069"><strong>Added</strong></span>,  <span style="color:#069"><strike>Removed</strike></span>,  <span style="color:#069">Changed</span></font>
    -+</div>
    -+<!-- Class AccessibilityManagerCompat.AccessibilityStateChangeListener -->
    -+<A NAME="A"></A>
    -+<br><font size="+2">A</font>&nbsp;
    -+<a href="#B"><font size="-2">B</font></a> 
    -+<a href="#C"><font size="-2">C</font></a> 
    -+<a href="#D"><font size="-2">D</font></a> 
    -+<a href="#E"><font size="-2">E</font></a> 
    -+<a href="#F"><font size="-2">F</font></a> 
    -+<a href="#G"><font size="-2">G</font></a> 
    -+<a href="#H"><font size="-2">H</font></a> 
    -+<a href="#I"><font size="-2">I</font></a> 
    -+<a href="#L"><font size="-2">L</font></a> 
    -+<a href="#M"><font size="-2">M</font></a> 
    -+<a href="#N"><font size="-2">N</font></a> 
    -+<a href="#O"><font size="-2">O</font></a> 
    -+<a href="#P"><font size="-2">P</font></a> 
    -+<a href="#R"><font size="-2">R</font></a> 
    -+<a href="#S"><font size="-2">S</font></a> 
    -+<a href="#T"><font size="-2">T</font></a> 
    -+<a href="#W"><font size="-2">W</font></a> 
    -+ <a href="#topheader"><font size="-2">TOP</font></a>
    -+<p><div style="line-height:1.5em;color:black">
    -+<A HREF="pkg_android.support.v4.view.accessibility.html#AccessibilityManagerCompat.AccessibilityStateChangeListener" class="hiddenlink" target="rightframe"><b><i>AccessibilityManagerCompat.AccessibilityStateChangeListener</i></b></A><br>
    -+<!-- Class AccessibilityManagerCompat.TouchExplorationStateChangeListener -->
    -+<A HREF="pkg_android.support.v4.view.accessibility.html#AccessibilityManagerCompat.TouchExplorationStateChangeListener" class="hiddenlink" target="rightframe"><b><i>AccessibilityManagerCompat.TouchExplorationStateChangeListener</i></b></A><br>
    -+<!-- Field ACTION_ARGUMENT_COLUMN_INT -->
    -+<nobr><A HREF="android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.html#android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.ACTION_ARGUMENT_COLUMN_INT" class="hiddenlink" target="rightframe">ACTION_ARGUMENT_COLUMN_INT</A>
    -+</nobr><br>
    -+<!-- Field ACTION_ARGUMENT_PROGRESS_VALUE -->
    -+<nobr><A HREF="android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.html#android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.ACTION_ARGUMENT_PROGRESS_VALUE" class="hiddenlink" target="rightframe">ACTION_ARGUMENT_PROGRESS_VALUE</A>
    -+</nobr><br>
    -+<!-- Field ACTION_ARGUMENT_ROW_INT -->
    -+<nobr><A HREF="android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.html#android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.ACTION_ARGUMENT_ROW_INT" class="hiddenlink" target="rightframe">ACTION_ARGUMENT_ROW_INT</A>
    -+</nobr><br>
    -+<!-- Field ACTION_CONTEXT_CLICK -->
    -+<nobr><A HREF="android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat.html#android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat.ACTION_CONTEXT_CLICK" class="hiddenlink" target="rightframe">ACTION_CONTEXT_CLICK</A>
    -+</nobr><br>
    -+<!-- Field ACTION_SCROLL_DOWN -->
    -+<nobr><A HREF="android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat.html#android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat.ACTION_SCROLL_DOWN" class="hiddenlink" target="rightframe">ACTION_SCROLL_DOWN</A>
    -+</nobr><br>
    -+<!-- Field ACTION_SCROLL_LEFT -->
    -+<nobr><A HREF="android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat.html#android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat.ACTION_SCROLL_LEFT" class="hiddenlink" target="rightframe">ACTION_SCROLL_LEFT</A>
    -+</nobr><br>
    -+<!-- Field ACTION_SCROLL_RIGHT -->
    -+<nobr><A HREF="android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat.html#android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat.ACTION_SCROLL_RIGHT" class="hiddenlink" target="rightframe">ACTION_SCROLL_RIGHT</A>
    -+</nobr><br>
    -+<!-- Field ACTION_SCROLL_TO_POSITION -->
    -+<nobr><A HREF="android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat.html#android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat.ACTION_SCROLL_TO_POSITION" class="hiddenlink" target="rightframe">ACTION_SCROLL_TO_POSITION</A>
    -+</nobr><br>
    -+<!-- Field ACTION_SCROLL_UP -->
    -+<nobr><A HREF="android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat.html#android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat.ACTION_SCROLL_UP" class="hiddenlink" target="rightframe">ACTION_SCROLL_UP</A>
    -+</nobr><br>
    -+<!-- Field ACTION_SET_PROGRESS -->
    -+<nobr><A HREF="android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat.html#android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat.ACTION_SET_PROGRESS" class="hiddenlink" target="rightframe">ACTION_SET_PROGRESS</A>
    -+</nobr><br>
    -+<!-- Field ACTION_SHOW_ON_SCREEN -->
    -+<nobr><A HREF="android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat.html#android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat.ACTION_SHOW_ON_SCREEN" class="hiddenlink" target="rightframe">ACTION_SHOW_ON_SCREEN</A>
    -+</nobr><br>
    -+<!-- Class ActionBarActivity -->
    -+<A HREF="pkg_android.support.v7.app.html#ActionBarActivity" class="hiddenlink" target="rightframe"><b>ActionBarActivity</b></A><br>
    -+<!-- Class ActionMenuView -->
    -+<A HREF="pkg_android.support.v7.widget.html#ActionMenuView" class="hiddenlink" target="rightframe"><b>ActionMenuView</b></A><br>
    -+<!-- Class ActionMenuView.LayoutParams -->
    -+<A HREF="pkg_android.support.v7.widget.html#ActionMenuView.LayoutParams" class="hiddenlink" target="rightframe"><b>ActionMenuView.LayoutParams</b></A><br>
    -+<!-- Class ActionMenuView.OnMenuItemClickListener -->
    -+<A HREF="pkg_android.support.v7.widget.html#ActionMenuView.OnMenuItemClickListener" class="hiddenlink" target="rightframe"><b><i>ActionMenuView.OnMenuItemClickListener</i></b></A><br>
    -+<!-- Method addTouchExplorationStateChangeListener -->
    -+<nobr><A HREF="android.support.v4.view.accessibility.AccessibilityManagerCompat.html#android.support.v4.view.accessibility.AccessibilityManagerCompat.addTouchExplorationStateChangeListener_added(android.view.accessibility.AccessibilityManager, android.support.v4.view.accessibility.AccessibilityManagerCompat.TouchExplorationStateChangeListener)" class="hiddenlink" target="rightframe"><b>addTouchExplorationStateChangeListener</b>
    -+(<code>AccessibilityManager, TouchExplorationStateChangeListener</code>)</A></nobr><br>
    -+<!-- Package android.support.transition -->
    -+<A HREF="changes-summary.html#android.support.transition" class="hiddenlink" target="rightframe"><b>android.support.transition</b></A><br>
    -+<!-- Package android.support.v4.text.util -->
    -+<A HREF="changes-summary.html#android.support.v4.text.util" class="hiddenlink" target="rightframe"><b>android.support.v4.text.util</b></A><br>
    -+<!-- Class AppCompatActivity -->
    -+<A HREF="pkg_android.support.v7.app.html#AppCompatActivity" class="hiddenlink" target="rightframe"><b>AppCompatActivity</b></A><br>
    -+<!-- Class AppCompatAutoCompleteTextView -->
    -+<A HREF="pkg_android.support.v7.widget.html#AppCompatAutoCompleteTextView" class="hiddenlink" target="rightframe"><b>AppCompatAutoCompleteTextView</b></A><br>
    -+<!-- Class AppCompatButton -->
    -+<A HREF="pkg_android.support.v7.widget.html#AppCompatButton" class="hiddenlink" target="rightframe"><b>AppCompatButton</b></A><br>
    -+<!-- Class AppCompatCheckBox -->
    -+<A HREF="pkg_android.support.v7.widget.html#AppCompatCheckBox" class="hiddenlink" target="rightframe"><b>AppCompatCheckBox</b></A><br>
    -+<!-- Class AppCompatCheckedTextView -->
    -+<A HREF="pkg_android.support.v7.widget.html#AppCompatCheckedTextView" class="hiddenlink" target="rightframe"><b>AppCompatCheckedTextView</b></A><br>
    -+<!-- Class AppCompatDialogFragment -->
    -+<A HREF="pkg_android.support.v7.app.html#AppCompatDialogFragment" class="hiddenlink" target="rightframe"><b>AppCompatDialogFragment</b></A><br>
    -+<!-- Class AppCompatEditText -->
    -+<A HREF="pkg_android.support.v7.widget.html#AppCompatEditText" class="hiddenlink" target="rightframe"><b>AppCompatEditText</b></A><br>
    -+<!-- Class AppCompatImageButton -->
    -+<A HREF="pkg_android.support.v7.widget.html#AppCompatImageButton" class="hiddenlink" target="rightframe"><b>AppCompatImageButton</b></A><br>
    -+<!-- Class AppCompatImageView -->
    -+<A HREF="pkg_android.support.v7.widget.html#AppCompatImageView" class="hiddenlink" target="rightframe"><b>AppCompatImageView</b></A><br>
    -+<!-- Class AppCompatMultiAutoCompleteTextView -->
    -+<A HREF="pkg_android.support.v7.widget.html#AppCompatMultiAutoCompleteTextView" class="hiddenlink" target="rightframe"><b>AppCompatMultiAutoCompleteTextView</b></A><br>
    -+<!-- Class AppCompatRadioButton -->
    -+<A HREF="pkg_android.support.v7.widget.html#AppCompatRadioButton" class="hiddenlink" target="rightframe"><b>AppCompatRadioButton</b></A><br>
    -+<!-- Class AppCompatRatingBar -->
    -+<A HREF="pkg_android.support.v7.widget.html#AppCompatRatingBar" class="hiddenlink" target="rightframe"><b>AppCompatRatingBar</b></A><br>
    -+<!-- Class AppCompatSeekBar -->
    -+<A HREF="pkg_android.support.v7.widget.html#AppCompatSeekBar" class="hiddenlink" target="rightframe"><b>AppCompatSeekBar</b></A><br>
    -+<!-- Class AppCompatSpinner -->
    -+<A HREF="pkg_android.support.v7.widget.html#AppCompatSpinner" class="hiddenlink" target="rightframe"><b>AppCompatSpinner</b></A><br>
    -+<!-- Class AppCompatTextView -->
    -+<A HREF="pkg_android.support.v7.widget.html#AppCompatTextView" class="hiddenlink" target="rightframe"><b>AppCompatTextView</b></A><br>
    -+<!-- Class BatchingListUpdateCallback -->
    -+<A NAME="B"></A>
    -+<br><font size="+2">B</font>&nbsp;
    -+<a href="#A"><font size="-2">A</font></a> 
    -+<a href="#C"><font size="-2">C</font></a> 
    -+<a href="#D"><font size="-2">D</font></a> 
    -+<a href="#E"><font size="-2">E</font></a> 
    -+<a href="#F"><font size="-2">F</font></a> 
    -+<a href="#G"><font size="-2">G</font></a> 
    -+<a href="#H"><font size="-2">H</font></a> 
    -+<a href="#I"><font size="-2">I</font></a> 
    -+<a href="#L"><font size="-2">L</font></a> 
    -+<a href="#M"><font size="-2">M</font></a> 
    -+<a href="#N"><font size="-2">N</font></a> 
    -+<a href="#O"><font size="-2">O</font></a> 
    -+<a href="#P"><font size="-2">P</font></a> 
    -+<a href="#R"><font size="-2">R</font></a> 
    -+<a href="#S"><font size="-2">S</font></a> 
    -+<a href="#T"><font size="-2">T</font></a> 
    -+<a href="#W"><font size="-2">W</font></a> 
    -+ <a href="#topheader"><font size="-2">TOP</font></a>
    -+<p><div style="line-height:1.5em;color:black">
    -+<A HREF="pkg_android.support.v7.util.html#BatchingListUpdateCallback" class="hiddenlink" target="rightframe"><b>BatchingListUpdateCallback</b></A><br>
    -+<!-- Field BT_FOLDER_TYPE_ALBUMS -->
    -+<nobr><A HREF="android.support.v4.media.MediaDescriptionCompat.html#android.support.v4.media.MediaDescriptionCompat.BT_FOLDER_TYPE_ALBUMS" class="hiddenlink" target="rightframe">BT_FOLDER_TYPE_ALBUMS</A>
    -+</nobr><br>
    -+<!-- Field BT_FOLDER_TYPE_ARTISTS -->
    -+<nobr><A HREF="android.support.v4.media.MediaDescriptionCompat.html#android.support.v4.media.MediaDescriptionCompat.BT_FOLDER_TYPE_ARTISTS" class="hiddenlink" target="rightframe">BT_FOLDER_TYPE_ARTISTS</A>
    -+</nobr><br>
    -+<!-- Field BT_FOLDER_TYPE_GENRES -->
    -+<nobr><A HREF="android.support.v4.media.MediaDescriptionCompat.html#android.support.v4.media.MediaDescriptionCompat.BT_FOLDER_TYPE_GENRES" class="hiddenlink" target="rightframe">BT_FOLDER_TYPE_GENRES</A>
    -+</nobr><br>
    -+<!-- Field BT_FOLDER_TYPE_MIXED -->
    -+<nobr><A HREF="android.support.v4.media.MediaDescriptionCompat.html#android.support.v4.media.MediaDescriptionCompat.BT_FOLDER_TYPE_MIXED" class="hiddenlink" target="rightframe">BT_FOLDER_TYPE_MIXED</A>
    -+</nobr><br>
    -+<!-- Field BT_FOLDER_TYPE_PLAYLISTS -->
    -+<nobr><A HREF="android.support.v4.media.MediaDescriptionCompat.html#android.support.v4.media.MediaDescriptionCompat.BT_FOLDER_TYPE_PLAYLISTS" class="hiddenlink" target="rightframe">BT_FOLDER_TYPE_PLAYLISTS</A>
    -+</nobr><br>
    -+<!-- Field BT_FOLDER_TYPE_TITLES -->
    -+<nobr><A HREF="android.support.v4.media.MediaDescriptionCompat.html#android.support.v4.media.MediaDescriptionCompat.BT_FOLDER_TYPE_TITLES" class="hiddenlink" target="rightframe">BT_FOLDER_TYPE_TITLES</A>
    -+</nobr><br>
    -+<!-- Field BT_FOLDER_TYPE_YEARS -->
    -+<nobr><A HREF="android.support.v4.media.MediaDescriptionCompat.html#android.support.v4.media.MediaDescriptionCompat.BT_FOLDER_TYPE_YEARS" class="hiddenlink" target="rightframe">BT_FOLDER_TYPE_YEARS</A>
    -+</nobr><br>
    -+<!-- Method buildMediaButtonPendingIntent -->
    -+<i>buildMediaButtonPendingIntent</i><br>
    -+&nbsp;&nbsp;<nobr><A HREF="android.support.v4.media.session.MediaButtonReceiver.html#android.support.v4.media.session.MediaButtonReceiver.buildMediaButtonPendingIntent_added(android.content.Context, android.content.ComponentName, long)" class="hiddenlink" target="rightframe">type&nbsp;<b>
    -+(<code>Context, ComponentName, long</code>)</b>&nbsp;in&nbsp;android.support.v4.media.session.MediaButtonReceiver
    -+</A></nobr><br>
    -+<!-- Method buildMediaButtonPendingIntent -->
    -+&nbsp;&nbsp;<nobr><A HREF="android.support.v4.media.session.MediaButtonReceiver.html#android.support.v4.media.session.MediaButtonReceiver.buildMediaButtonPendingIntent_added(android.content.Context, long)" class="hiddenlink" target="rightframe">type&nbsp;<b>
    -+(<code>Context, long</code>)</b>&nbsp;in&nbsp;android.support.v4.media.session.MediaButtonReceiver
    -+</A></nobr><br>
    -+<!-- Class CardView -->
    -+<A NAME="C"></A>
    -+<br><font size="+2">C</font>&nbsp;
    -+<a href="#A"><font size="-2">A</font></a> 
    -+<a href="#B"><font size="-2">B</font></a> 
    -+<a href="#D"><font size="-2">D</font></a> 
    -+<a href="#E"><font size="-2">E</font></a> 
    -+<a href="#F"><font size="-2">F</font></a> 
    -+<a href="#G"><font size="-2">G</font></a> 
    -+<a href="#H"><font size="-2">H</font></a> 
    -+<a href="#I"><font size="-2">I</font></a> 
    -+<a href="#L"><font size="-2">L</font></a> 
    -+<a href="#M"><font size="-2">M</font></a> 
    -+<a href="#N"><font size="-2">N</font></a> 
    -+<a href="#O"><font size="-2">O</font></a> 
    -+<a href="#P"><font size="-2">P</font></a> 
    -+<a href="#R"><font size="-2">R</font></a> 
    -+<a href="#S"><font size="-2">S</font></a> 
    -+<a href="#T"><font size="-2">T</font></a> 
    -+<a href="#W"><font size="-2">W</font></a> 
    -+ <a href="#topheader"><font size="-2">TOP</font></a>
    -+<p><div style="line-height:1.5em;color:black">
    -+<A HREF="pkg_android.support.v7.widget.html#CardView" class="hiddenlink" target="rightframe"><b>CardView</b></A><br>
    -+<!-- Method clearColorFilter -->
    -+<nobr><A HREF="android.support.v4.graphics.drawable.DrawableCompat.html#android.support.v4.graphics.drawable.DrawableCompat.clearColorFilter_added(android.graphics.drawable.Drawable)" class="hiddenlink" target="rightframe"><b>clearColorFilter</b>
    -+(<code>Drawable</code>)</A></nobr><br>
    -+<!-- Method clearOnTabSelectedListeners -->
    -+<nobr><A HREF="android.support.design.widget.TabLayout.html#android.support.design.widget.TabLayout.clearOnTabSelectedListeners_added()" class="hiddenlink" target="rightframe"><b>clearOnTabSelectedListeners</b>
    -+()</A></nobr><br>
    -+<!-- Method computeScrollVectorForPosition -->
    -+<nobr><A HREF="android.support.v7.widget.StaggeredGridLayoutManager.html#android.support.v7.widget.StaggeredGridLayoutManager.computeScrollVectorForPosition_added(int)" class="hiddenlink" target="rightframe"><b>computeScrollVectorForPosition</b>
    -+(<code>int</code>)</A></nobr><br>
    -+<!-- Class DiffUtil -->
    -+<A NAME="D"></A>
    -+<br><font size="+2">D</font>&nbsp;
    -+<a href="#A"><font size="-2">A</font></a> 
    -+<a href="#B"><font size="-2">B</font></a> 
    -+<a href="#C"><font size="-2">C</font></a> 
    -+<a href="#E"><font size="-2">E</font></a> 
    -+<a href="#F"><font size="-2">F</font></a> 
    -+<a href="#G"><font size="-2">G</font></a> 
    -+<a href="#H"><font size="-2">H</font></a> 
    -+<a href="#I"><font size="-2">I</font></a> 
    -+<a href="#L"><font size="-2">L</font></a> 
    -+<a href="#M"><font size="-2">M</font></a> 
    -+<a href="#N"><font size="-2">N</font></a> 
    -+<a href="#O"><font size="-2">O</font></a> 
    -+<a href="#P"><font size="-2">P</font></a> 
    -+<a href="#R"><font size="-2">R</font></a> 
    -+<a href="#S"><font size="-2">S</font></a> 
    -+<a href="#T"><font size="-2">T</font></a> 
    -+<a href="#W"><font size="-2">W</font></a> 
    -+ <a href="#topheader"><font size="-2">TOP</font></a>
    -+<p><div style="line-height:1.5em;color:black">
    -+<A HREF="pkg_android.support.v7.util.html#DiffUtil" class="hiddenlink" target="rightframe"><b>DiffUtil</b></A><br>
    -+<!-- Class DiffUtil.Callback -->
    -+<A HREF="pkg_android.support.v7.util.html#DiffUtil.Callback" class="hiddenlink" target="rightframe"><b>DiffUtil.Callback</b></A><br>
    -+<!-- Class DiffUtil.DiffResult -->
    -+<A HREF="pkg_android.support.v7.util.html#DiffUtil.DiffResult" class="hiddenlink" target="rightframe"><b>DiffUtil.DiffResult</b></A><br>
    -+<!-- Field dodgeInsetEdges -->
    -+<nobr><A HREF="android.support.design.widget.CoordinatorLayout.LayoutParams.html#android.support.design.widget.CoordinatorLayout.LayoutParams.dodgeInsetEdges" class="hiddenlink" target="rightframe">dodgeInsetEdges</A>
    -+</nobr><br>
    -+<!-- Field EXTRA_BT_FOLDER_TYPE -->
    -+<A NAME="E"></A>
    -+<br><font size="+2">E</font>&nbsp;
    -+<a href="#A"><font size="-2">A</font></a> 
    -+<a href="#B"><font size="-2">B</font></a> 
    -+<a href="#C"><font size="-2">C</font></a> 
    -+<a href="#D"><font size="-2">D</font></a> 
    -+<a href="#F"><font size="-2">F</font></a> 
    -+<a href="#G"><font size="-2">G</font></a> 
    -+<a href="#H"><font size="-2">H</font></a> 
    -+<a href="#I"><font size="-2">I</font></a> 
    -+<a href="#L"><font size="-2">L</font></a> 
    -+<a href="#M"><font size="-2">M</font></a> 
    -+<a href="#N"><font size="-2">N</font></a> 
    -+<a href="#O"><font size="-2">O</font></a> 
    -+<a href="#P"><font size="-2">P</font></a> 
    -+<a href="#R"><font size="-2">R</font></a> 
    -+<a href="#S"><font size="-2">S</font></a> 
    -+<a href="#T"><font size="-2">T</font></a> 
    -+<a href="#W"><font size="-2">W</font></a> 
    -+ <a href="#topheader"><font size="-2">TOP</font></a>
    -+<p><div style="line-height:1.5em;color:black">
    -+<nobr><A HREF="android.support.v4.media.MediaDescriptionCompat.html#android.support.v4.media.MediaDescriptionCompat.EXTRA_BT_FOLDER_TYPE" class="hiddenlink" target="rightframe">EXTRA_BT_FOLDER_TYPE</A>
    -+</nobr><br>
    -+<!-- Field EXTRA_ENABLE_INSTANT_APPS -->
    -+<nobr><A HREF="android.support.customtabs.CustomTabsIntent.html#android.support.customtabs.CustomTabsIntent.EXTRA_ENABLE_INSTANT_APPS" class="hiddenlink" target="rightframe">EXTRA_ENABLE_INSTANT_APPS</A>
    -+</nobr><br>
    -+<!-- Field EXTRA_SUGGESTION_KEYWORDS -->
    -+<nobr><A HREF="android.support.v4.media.MediaBrowserServiceCompat.BrowserRoot.html#android.support.v4.media.MediaBrowserServiceCompat.BrowserRoot.EXTRA_SUGGESTION_KEYWORDS" class="hiddenlink" target="rightframe">EXTRA_SUGGESTION_KEYWORDS</A>
    -+</nobr><br>
    -+<!-- Field EXTRA_USAGE_TIME_REPORT -->
    -+<nobr><A HREF="android.support.v4.app.ActivityOptionsCompat.html#android.support.v4.app.ActivityOptionsCompat.EXTRA_USAGE_TIME_REPORT" class="hiddenlink" target="rightframe">EXTRA_USAGE_TIME_REPORT</A>
    -+</nobr><br>
    -+<!-- Field EXTRA_USAGE_TIME_REPORT_PACKAGES -->
    -+<nobr><A HREF="android.support.v4.app.ActivityOptionsCompat.html#android.support.v4.app.ActivityOptionsCompat.EXTRA_USAGE_TIME_REPORT_PACKAGES" class="hiddenlink" target="rightframe">EXTRA_USAGE_TIME_REPORT_PACKAGES</A>
    -+</nobr><br>
    -+<!-- Method findFragmentByWho -->
    -+<A NAME="F"></A>
    -+<br><font size="+2">F</font>&nbsp;
    -+<a href="#A"><font size="-2">A</font></a> 
    -+<a href="#B"><font size="-2">B</font></a> 
    -+<a href="#C"><font size="-2">C</font></a> 
    -+<a href="#D"><font size="-2">D</font></a> 
    -+<a href="#E"><font size="-2">E</font></a> 
    -+<a href="#G"><font size="-2">G</font></a> 
    -+<a href="#H"><font size="-2">H</font></a> 
    -+<a href="#I"><font size="-2">I</font></a> 
    -+<a href="#L"><font size="-2">L</font></a> 
    -+<a href="#M"><font size="-2">M</font></a> 
    -+<a href="#N"><font size="-2">N</font></a> 
    -+<a href="#O"><font size="-2">O</font></a> 
    -+<a href="#P"><font size="-2">P</font></a> 
    -+<a href="#R"><font size="-2">R</font></a> 
    -+<a href="#S"><font size="-2">S</font></a> 
    -+<a href="#T"><font size="-2">T</font></a> 
    -+<a href="#W"><font size="-2">W</font></a> 
    -+ <a href="#topheader"><font size="-2">TOP</font></a>
    -+<p><div style="line-height:1.5em;color:black">
    -+<nobr><A HREF="android.support.v4.app.FragmentController.html#android.support.v4.app.FragmentController.findFragmentByWho_added(java.lang.String)" class="hiddenlink" target="rightframe"><b>findFragmentByWho</b>
    -+(<code>String</code>)</A></nobr><br>
    -+<!-- Method fromMediaItem -->
    -+<nobr><A HREF="android.support.v4.media.MediaBrowserCompat.MediaItem.html#android.support.v4.media.MediaBrowserCompat.MediaItem.fromMediaItem_added(java.lang.Object)" class="hiddenlink" target="rightframe"><b>fromMediaItem</b>
    -+(<code>Object</code>)</A></nobr><br>
    -+<!-- Method fromMediaItemList -->
    -+<nobr><A HREF="android.support.v4.media.MediaBrowserCompat.MediaItem.html#android.support.v4.media.MediaBrowserCompat.MediaItem.fromMediaItemList_added(java.util.List<?>)" class="hiddenlink" target="rightframe"><b>fromMediaItemList</b>
    -+(<code>List&lt;?&gt;</code>)</A></nobr><br>
    -+<!-- Method fromMediaSession -->
    -+<nobr><A HREF="android.support.v4.media.session.MediaSessionCompat.html#android.support.v4.media.session.MediaSessionCompat.fromMediaSession_added(android.content.Context, java.lang.Object)" class="hiddenlink" target="rightframe"><b>fromMediaSession</b>
    -+(<code>Context, Object</code>)</A></nobr><br>
    -+<!-- Method fromQueueItem -->
    -+<nobr><A HREF="android.support.v4.media.session.MediaSessionCompat.QueueItem.html#android.support.v4.media.session.MediaSessionCompat.QueueItem.fromQueueItem_added(java.lang.Object)" class="hiddenlink" target="rightframe"><b>fromQueueItem</b>
    -+(<code>Object</code>)</A></nobr><br>
    -+<!-- Method fromQueueItemList -->
    -+<nobr><A HREF="android.support.v4.media.session.MediaSessionCompat.QueueItem.html#android.support.v4.media.session.MediaSessionCompat.QueueItem.fromQueueItemList_added(java.util.List<?>)" class="hiddenlink" target="rightframe"><b>fromQueueItemList</b>
    -+(<code>List&lt;?&gt;</code>)</A></nobr><br>
    -+<!-- Method getAction -->
    -+<A NAME="G"></A>
    -+<br><font size="+2">G</font>&nbsp;
    -+<a href="#A"><font size="-2">A</font></a> 
    -+<a href="#B"><font size="-2">B</font></a> 
    -+<a href="#C"><font size="-2">C</font></a> 
    -+<a href="#D"><font size="-2">D</font></a> 
    -+<a href="#E"><font size="-2">E</font></a> 
    -+<a href="#F"><font size="-2">F</font></a> 
    -+<a href="#H"><font size="-2">H</font></a> 
    -+<a href="#I"><font size="-2">I</font></a> 
    -+<a href="#L"><font size="-2">L</font></a> 
    -+<a href="#M"><font size="-2">M</font></a> 
    -+<a href="#N"><font size="-2">N</font></a> 
    -+<a href="#O"><font size="-2">O</font></a> 
    -+<a href="#P"><font size="-2">P</font></a> 
    -+<a href="#R"><font size="-2">R</font></a> 
    -+<a href="#S"><font size="-2">S</font></a> 
    -+<a href="#T"><font size="-2">T</font></a> 
    -+<a href="#W"><font size="-2">W</font></a> 
    -+ <a href="#topheader"><font size="-2">TOP</font></a>
    -+<p><div style="line-height:1.5em;color:black">
    -+<nobr><A HREF="android.support.v4.view.accessibility.AccessibilityEventCompat.html#android.support.v4.view.accessibility.AccessibilityEventCompat.getAction_added(android.view.accessibility.AccessibilityEvent)" class="hiddenlink" target="rightframe"><b>getAction</b>
    -+(<code>AccessibilityEvent</code>)</A></nobr><br>
    -+<!-- Method getCompoundDrawablesRelative -->
    -+<nobr><A HREF="android.support.v4.widget.TextViewCompat.html#android.support.v4.widget.TextViewCompat.getCompoundDrawablesRelative_added(android.widget.TextView)" class="hiddenlink" target="rightframe"><b>getCompoundDrawablesRelative</b>
    -+(<code>TextView</code>)</A></nobr><br>
    -+<!-- Method getDependents -->
    -+<nobr><A HREF="android.support.design.widget.CoordinatorLayout.html#android.support.design.widget.CoordinatorLayout.getDependents_added(android.view.View)" class="hiddenlink" target="rightframe"><b>getDependents</b>
    -+(<code>View</code>)</A></nobr><br>
    -+<!-- Method getDominantColor -->
    -+<nobr><A HREF="android.support.v7.graphics.Palette.html#android.support.v7.graphics.Palette.getDominantColor_added(int)" class="hiddenlink" target="rightframe"><b>getDominantColor</b>
    -+(<code>int</code>)</A></nobr><br>
    -+<!-- Method getDominantSwatch -->
    -+<nobr><A HREF="android.support.v7.graphics.Palette.html#android.support.v7.graphics.Palette.getDominantSwatch_added()" class="hiddenlink" target="rightframe"><b>getDominantSwatch</b>
    -+()</A></nobr><br>
    -+<!-- Method getDrawable -->
    -+<nobr><A HREF="android.support.v7.content.res.AppCompatResources.html#android.support.v7.content.res.AppCompatResources.getDrawable_added(android.content.Context, int)" class="hiddenlink" target="rightframe"><b>getDrawable</b>
    -+(<code>Context, int</code>)</A></nobr><br>
    -+<!-- Method getDrawerArrowDrawable -->
    -+<nobr><A HREF="android.support.v7.app.ActionBarDrawerToggle.html#android.support.v7.app.ActionBarDrawerToggle.getDrawerArrowDrawable_added()" class="hiddenlink" target="rightframe"><b>getDrawerArrowDrawable</b>
    -+()</A></nobr><br>
    -+<!-- Method getInsetDodgeRect -->
    -+<i>getInsetDodgeRect</i><br>
    -+&nbsp;&nbsp;<nobr><A HREF="android.support.design.widget.CoordinatorLayout.Behavior.html#android.support.design.widget.CoordinatorLayout.Behavior.getInsetDodgeRect_added(android.support.design.widget.CoordinatorLayout, V, android.graphics.Rect)" class="hiddenlink" target="rightframe">type&nbsp;<b>
    -+(<code>CoordinatorLayout, V, Rect</code>)</b>&nbsp;in&nbsp;android.support.design.widget.CoordinatorLayout.Behavior
    -+</A></nobr><br>
    -+<!-- Method getInsetDodgeRect -->
    -+&nbsp;&nbsp;<nobr><A HREF="android.support.design.widget.FloatingActionButton.Behavior.html#android.support.design.widget.FloatingActionButton.Behavior.getInsetDodgeRect_added(android.support.design.widget.CoordinatorLayout, android.support.design.widget.FloatingActionButton, android.graphics.Rect)" class="hiddenlink" target="rightframe">type&nbsp;<b>
    -+(<code>CoordinatorLayout, FloatingActionButton, Rect</code>)</b>&nbsp;in&nbsp;android.support.design.widget.FloatingActionButton.Behavior
    -+</A></nobr><br>
    -+<!-- Method getLaunchBounds -->
    -+<nobr><A HREF="android.support.v4.app.ActivityOptionsCompat.html#android.support.v4.app.ActivityOptionsCompat.getLaunchBounds_added()" class="hiddenlink" target="rightframe"><b>getLaunchBounds</b>
    -+()</A></nobr><br>
    -+<!-- Method getMediaItemNumberViewFlipper -->
    -+<nobr><A HREF="android.support.v17.leanback.widget.AbstractMediaItemPresenter.ViewHolder.html#android.support.v17.leanback.widget.AbstractMediaItemPresenter.ViewHolder.getMediaItemNumberViewFlipper_added()" class="hiddenlink" target="rightframe"><b>getMediaItemNumberViewFlipper</b>
    -+()</A></nobr><br>
    -+<!-- Method getMediaItemPausedView -->
    -+<nobr><A HREF="android.support.v17.leanback.widget.AbstractMediaItemPresenter.ViewHolder.html#android.support.v17.leanback.widget.AbstractMediaItemPresenter.ViewHolder.getMediaItemPausedView_added()" class="hiddenlink" target="rightframe"><b>getMediaItemPausedView</b>
    -+()</A></nobr><br>
    -+<!-- Method getMediaItemPlayingView -->
    -+<nobr><A HREF="android.support.v17.leanback.widget.AbstractMediaItemPresenter.ViewHolder.html#android.support.v17.leanback.widget.AbstractMediaItemPresenter.ViewHolder.getMediaItemPlayingView_added()" class="hiddenlink" target="rightframe"><b>getMediaItemPlayingView</b>
    -+()</A></nobr><br>
    -+<!-- Method getMediaPlayState -->
    -+<nobr><A HREF="android.support.v17.leanback.widget.AbstractMediaItemPresenter.html#android.support.v17.leanback.widget.AbstractMediaItemPresenter.getMediaPlayState_added(java.lang.Object)" class="hiddenlink" target="rightframe"><b>getMediaPlayState</b>
    -+(<code>Object</code>)</A></nobr><br>
    -+<!-- Method getMovementGranularity -->
    -+<nobr><A HREF="android.support.v4.view.accessibility.AccessibilityEventCompat.html#android.support.v4.view.accessibility.AccessibilityEventCompat.getMovementGranularity_added(android.view.accessibility.AccessibilityEvent)" class="hiddenlink" target="rightframe"><b>getMovementGranularity</b>
    -+(<code>AccessibilityEvent</code>)</A></nobr><br>
    -+<!-- Method getOnFlingListener -->
    -+<nobr><A HREF="android.support.v7.widget.RecyclerView.html#android.support.v7.widget.RecyclerView.getOnFlingListener_added()" class="hiddenlink" target="rightframe"><b>getOnFlingListener</b>
    -+()</A></nobr><br>
    -+<!-- Method getPasswordVisibilityToggleContentDescription -->
    -+<nobr><A HREF="android.support.design.widget.TextInputLayout.html#android.support.design.widget.TextInputLayout.getPasswordVisibilityToggleContentDescription_added()" class="hiddenlink" target="rightframe"><b>getPasswordVisibilityToggleContentDescription</b>
    -+()</A></nobr><br>
    -+<!-- Method getPasswordVisibilityToggleDrawable -->
    -+<nobr><A HREF="android.support.design.widget.TextInputLayout.html#android.support.design.widget.TextInputLayout.getPasswordVisibilityToggleDrawable_added()" class="hiddenlink" target="rightframe"><b>getPasswordVisibilityToggleDrawable</b>
    -+()</A></nobr><br>
    -+<!-- Method getSelectionMode -->
    -+<nobr><A HREF="android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.CollectionInfoCompat.html#android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.CollectionInfoCompat.getSelectionMode_added()" class="hiddenlink" target="rightframe"><b>getSelectionMode</b>
    -+()</A></nobr><br>
    -+<!-- Class GridLayout -->
    -+<A HREF="pkg_android.support.v7.widget.html#GridLayout" class="hiddenlink" target="rightframe"><b>GridLayout</b></A><br>
    -+<!-- Class GridLayout.Alignment -->
    -+<A HREF="pkg_android.support.v7.widget.html#GridLayout.Alignment" class="hiddenlink" target="rightframe"><b>GridLayout.Alignment</b></A><br>
    -+<!-- Class GridLayout.LayoutParams -->
    -+<A HREF="pkg_android.support.v7.widget.html#GridLayout.LayoutParams" class="hiddenlink" target="rightframe"><b>GridLayout.LayoutParams</b></A><br>
    -+<!-- Class GridLayout.Spec -->
    -+<A HREF="pkg_android.support.v7.widget.html#GridLayout.Spec" class="hiddenlink" target="rightframe"><b>GridLayout.Spec</b></A><br>
    -+<!-- Field HOST_VIEW_ID -->
    -+<A NAME="H"></A>
    -+<br><font size="+2">H</font>&nbsp;
    -+<a href="#A"><font size="-2">A</font></a> 
    -+<a href="#B"><font size="-2">B</font></a> 
    -+<a href="#C"><font size="-2">C</font></a> 
    -+<a href="#D"><font size="-2">D</font></a> 
    -+<a href="#E"><font size="-2">E</font></a> 
    -+<a href="#F"><font size="-2">F</font></a> 
    -+<a href="#G"><font size="-2">G</font></a> 
    -+<a href="#I"><font size="-2">I</font></a> 
    -+<a href="#L"><font size="-2">L</font></a> 
    -+<a href="#M"><font size="-2">M</font></a> 
    -+<a href="#N"><font size="-2">N</font></a> 
    -+<a href="#O"><font size="-2">O</font></a> 
    -+<a href="#P"><font size="-2">P</font></a> 
    -+<a href="#R"><font size="-2">R</font></a> 
    -+<a href="#S"><font size="-2">S</font></a> 
    -+<a href="#T"><font size="-2">T</font></a> 
    -+<a href="#W"><font size="-2">W</font></a> 
    -+ <a href="#topheader"><font size="-2">TOP</font></a>
    -+<p><div style="line-height:1.5em;color:black">
    -+<nobr><A HREF="android.support.v4.view.accessibility.AccessibilityNodeProviderCompat.html#android.support.v4.view.accessibility.AccessibilityNodeProviderCompat.HOST_VIEW_ID" class="hiddenlink" target="rightframe">HOST_VIEW_ID</A>
    -+</nobr><br>
    -+<!-- Field insetEdge -->
    -+<A NAME="I"></A>
    -+<br><font size="+2">I</font>&nbsp;
    -+<a href="#A"><font size="-2">A</font></a> 
    -+<a href="#B"><font size="-2">B</font></a> 
    -+<a href="#C"><font size="-2">C</font></a> 
    -+<a href="#D"><font size="-2">D</font></a> 
    -+<a href="#E"><font size="-2">E</font></a> 
    -+<a href="#F"><font size="-2">F</font></a> 
    -+<a href="#G"><font size="-2">G</font></a> 
    -+<a href="#H"><font size="-2">H</font></a> 
    -+<a href="#L"><font size="-2">L</font></a> 
    -+<a href="#M"><font size="-2">M</font></a> 
    -+<a href="#N"><font size="-2">N</font></a> 
    -+<a href="#O"><font size="-2">O</font></a> 
    -+<a href="#P"><font size="-2">P</font></a> 
    -+<a href="#R"><font size="-2">R</font></a> 
    -+<a href="#S"><font size="-2">S</font></a> 
    -+<a href="#T"><font size="-2">T</font></a> 
    -+<a href="#W"><font size="-2">W</font></a> 
    -+ <a href="#topheader"><font size="-2">TOP</font></a>
    -+<p><div style="line-height:1.5em;color:black">
    -+<nobr><A HREF="android.support.design.widget.CoordinatorLayout.LayoutParams.html#android.support.design.widget.CoordinatorLayout.LayoutParams.insetEdge" class="hiddenlink" target="rightframe">insetEdge</A>
    -+</nobr><br>
    -+<!-- Method isAtLeastNMR1 -->
    -+<nobr><A HREF="android.support.v4.os.BuildCompat.html#android.support.v4.os.BuildCompat.isAtLeastNMR1_added()" class="hiddenlink" target="rightframe"><b>isAtLeastNMR1</b>
    -+()</A></nobr><br>
    -+<!-- Method isAutoHideEnabled -->
    -+<nobr><A HREF="android.support.design.widget.FloatingActionButton.Behavior.html#android.support.design.widget.FloatingActionButton.Behavior.isAutoHideEnabled_added()" class="hiddenlink" target="rightframe"><b>isAutoHideEnabled</b>
    -+()</A></nobr><br>
    -+<!-- Method isContextClickable -->
    -+<nobr><A HREF="android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.html#android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.isContextClickable_added()" class="hiddenlink" target="rightframe"><b>isContextClickable</b>
    -+()</A></nobr><br>
    -+<!-- Method isImmediateNotifySupported -->
    -+<nobr><A HREF="android.support.v17.leanback.widget.ObjectAdapter.html#android.support.v17.leanback.widget.ObjectAdapter.isImmediateNotifySupported_added()" class="hiddenlink" target="rightframe"><b>isImmediateNotifySupported</b>
    -+()</A></nobr><br>
    -+<!-- Method isImportantForAccessibility -->
    -+<nobr><A HREF="android.support.v4.view.ViewCompat.html#android.support.v4.view.ViewCompat.isImportantForAccessibility_added(android.view.View)" class="hiddenlink" target="rightframe"><b>isImportantForAccessibility</b>
    -+(<code>View</code>)</A></nobr><br>
    -+<!-- Method isPasswordVisibilityToggleEnabled -->
    -+<nobr><A HREF="android.support.design.widget.TextInputLayout.html#android.support.design.widget.TextInputLayout.isPasswordVisibilityToggleEnabled_added()" class="hiddenlink" target="rightframe"><b>isPasswordVisibilityToggleEnabled</b>
    -+()</A></nobr><br>
    -+<!-- Class LinearLayoutCompat -->
    -+<A NAME="L"></A>
    -+<br><font size="+2">L</font>&nbsp;
    -+<a href="#A"><font size="-2">A</font></a> 
    -+<a href="#B"><font size="-2">B</font></a> 
    -+<a href="#C"><font size="-2">C</font></a> 
    -+<a href="#D"><font size="-2">D</font></a> 
    -+<a href="#E"><font size="-2">E</font></a> 
    -+<a href="#F"><font size="-2">F</font></a> 
    -+<a href="#G"><font size="-2">G</font></a> 
    -+<a href="#H"><font size="-2">H</font></a> 
    -+<a href="#I"><font size="-2">I</font></a> 
    -+<a href="#M"><font size="-2">M</font></a> 
    -+<a href="#N"><font size="-2">N</font></a> 
    -+<a href="#O"><font size="-2">O</font></a> 
    -+<a href="#P"><font size="-2">P</font></a> 
    -+<a href="#R"><font size="-2">R</font></a> 
    -+<a href="#S"><font size="-2">S</font></a> 
    -+<a href="#T"><font size="-2">T</font></a> 
    -+<a href="#W"><font size="-2">W</font></a> 
    -+ <a href="#topheader"><font size="-2">TOP</font></a>
    -+<p><div style="line-height:1.5em;color:black">
    -+<A HREF="pkg_android.support.v7.widget.html#LinearLayoutCompat" class="hiddenlink" target="rightframe"><b>LinearLayoutCompat</b></A><br>
    -+<!-- Class LinearLayoutCompat.LayoutParams -->
    -+<A HREF="pkg_android.support.v7.widget.html#LinearLayoutCompat.LayoutParams" class="hiddenlink" target="rightframe"><b>LinearLayoutCompat.LayoutParams</b></A><br>
    -+<!-- Class LinearSnapHelper -->
    -+<A HREF="pkg_android.support.v7.widget.html#LinearSnapHelper" class="hiddenlink" target="rightframe"><b>LinearSnapHelper</b></A><br>
    -+<!-- Class ListPopupWindow -->
    -+<A HREF="pkg_android.support.v7.widget.html#ListPopupWindow" class="hiddenlink" target="rightframe"><b>ListPopupWindow</b></A><br>
    -+<!-- Class ListUpdateCallback -->
    -+<A HREF="pkg_android.support.v7.util.html#ListUpdateCallback" class="hiddenlink" target="rightframe"><b><i>ListUpdateCallback</i></b></A><br>
    -+<!-- Method loadDescription -->
    -+<nobr><A HREF="android.support.v4.accessibilityservice.AccessibilityServiceInfoCompat.html#android.support.v4.accessibilityservice.AccessibilityServiceInfoCompat.loadDescription_added(android.accessibilityservice.AccessibilityServiceInfo, android.content.pm.PackageManager)" class="hiddenlink" target="rightframe"><b>loadDescription</b>
    -+(<code>AccessibilityServiceInfo, PackageManager</code>)</A></nobr><br>
    -+<!-- Method makeBasic -->
    -+<A NAME="M"></A>
    -+<br><font size="+2">M</font>&nbsp;
    -+<a href="#A"><font size="-2">A</font></a> 
    -+<a href="#B"><font size="-2">B</font></a> 
    -+<a href="#C"><font size="-2">C</font></a> 
    -+<a href="#D"><font size="-2">D</font></a> 
    -+<a href="#E"><font size="-2">E</font></a> 
    -+<a href="#F"><font size="-2">F</font></a> 
    -+<a href="#G"><font size="-2">G</font></a> 
    -+<a href="#H"><font size="-2">H</font></a> 
    -+<a href="#I"><font size="-2">I</font></a> 
    -+<a href="#L"><font size="-2">L</font></a> 
    -+<a href="#N"><font size="-2">N</font></a> 
    -+<a href="#O"><font size="-2">O</font></a> 
    -+<a href="#P"><font size="-2">P</font></a> 
    -+<a href="#R"><font size="-2">R</font></a> 
    -+<a href="#S"><font size="-2">S</font></a> 
    -+<a href="#T"><font size="-2">T</font></a> 
    -+<a href="#W"><font size="-2">W</font></a> 
    -+ <a href="#topheader"><font size="-2">TOP</font></a>
    -+<p><div style="line-height:1.5em;color:black">
    -+<nobr><A HREF="android.support.v4.app.ActivityOptionsCompat.html#android.support.v4.app.ActivityOptionsCompat.makeBasic_added()" class="hiddenlink" target="rightframe"><b>makeBasic</b>
    -+()</A></nobr><br>
    -+<!-- Method makeClipRevealAnimation -->
    -+<nobr><A HREF="android.support.v4.app.ActivityOptionsCompat.html#android.support.v4.app.ActivityOptionsCompat.makeClipRevealAnimation_added(android.view.View, int, int, int, int)" class="hiddenlink" target="rightframe"><b>makeClipRevealAnimation</b>
    -+(<code>View, int, int, int, int</code>)</A></nobr><br>
    -+<!-- Method makeTaskLaunchBehind -->
    -+<nobr><A HREF="android.support.v4.app.ActivityOptionsCompat.html#android.support.v4.app.ActivityOptionsCompat.makeTaskLaunchBehind_added()" class="hiddenlink" target="rightframe"><b>makeTaskLaunchBehind</b>
    -+()</A></nobr><br>
    -+<!-- Field METADATA_KEY_BT_FOLDER_TYPE -->
    -+<nobr><A HREF="android.support.v4.media.MediaMetadataCompat.html#android.support.v4.media.MediaMetadataCompat.METADATA_KEY_BT_FOLDER_TYPE" class="hiddenlink" target="rightframe">METADATA_KEY_BT_FOLDER_TYPE</A>
    -+</nobr><br>
    -+<!-- Field METADATA_KEY_MEDIA_URI -->
    -+<nobr><A HREF="android.support.v4.media.MediaMetadataCompat.html#android.support.v4.media.MediaMetadataCompat.METADATA_KEY_MEDIA_URI" class="hiddenlink" target="rightframe">METADATA_KEY_MEDIA_URI</A>
    -+</nobr><br>
    -+<!-- Class MultiSelectListPreferenceDialogFragmentCompat -->
    -+<A HREF="pkg_android.support.v7.preference.html#MultiSelectListPreferenceDialogFragmentCompat" class="hiddenlink" target="rightframe"><b>MultiSelectListPreferenceDialogFragmentCompat</b></A><br>
    -+<!-- Class NotificationCompat -->
    -+<A NAME="N"></A>
    -+<br><font size="+2">N</font>&nbsp;
    -+<a href="#A"><font size="-2">A</font></a> 
    -+<a href="#B"><font size="-2">B</font></a> 
    -+<a href="#C"><font size="-2">C</font></a> 
    -+<a href="#D"><font size="-2">D</font></a> 
    -+<a href="#E"><font size="-2">E</font></a> 
    -+<a href="#F"><font size="-2">F</font></a> 
    -+<a href="#G"><font size="-2">G</font></a> 
    -+<a href="#H"><font size="-2">H</font></a> 
    -+<a href="#I"><font size="-2">I</font></a> 
    -+<a href="#L"><font size="-2">L</font></a> 
    -+<a href="#M"><font size="-2">M</font></a> 
    -+<a href="#O"><font size="-2">O</font></a> 
    -+<a href="#P"><font size="-2">P</font></a> 
    -+<a href="#R"><font size="-2">R</font></a> 
    -+<a href="#S"><font size="-2">S</font></a> 
    -+<a href="#T"><font size="-2">T</font></a> 
    -+<a href="#W"><font size="-2">W</font></a> 
    -+ <a href="#topheader"><font size="-2">TOP</font></a>
    -+<p><div style="line-height:1.5em;color:black">
    -+<A HREF="pkg_android.support.v7.app.html#NotificationCompat" class="hiddenlink" target="rightframe"><b>NotificationCompat</b></A><br>
    -+<!-- Class NotificationCompat.Builder -->
    -+<A HREF="pkg_android.support.v7.app.html#NotificationCompat.Builder" class="hiddenlink" target="rightframe"><b>NotificationCompat.Builder</b></A><br>
    -+<!-- Class NotificationCompat.MediaStyle -->
    -+<A HREF="pkg_android.support.v7.app.html#NotificationCompat.MediaStyle" class="hiddenlink" target="rightframe"><b>NotificationCompat.MediaStyle</b></A><br>
    -+<!-- Method notifyPlayStateChanged -->
    -+<nobr><A HREF="android.support.v17.leanback.widget.AbstractMediaItemPresenter.ViewHolder.html#android.support.v17.leanback.widget.AbstractMediaItemPresenter.ViewHolder.notifyPlayStateChanged_added()" class="hiddenlink" target="rightframe"><b>notifyPlayStateChanged</b>
    -+()</A></nobr><br>
    -+<!-- Method obtain -->
    -+<A NAME="O"></A>
    -+<br><font size="+2">O</font>&nbsp;
    -+<a href="#A"><font size="-2">A</font></a> 
    -+<a href="#B"><font size="-2">B</font></a> 
    -+<a href="#C"><font size="-2">C</font></a> 
    -+<a href="#D"><font size="-2">D</font></a> 
    -+<a href="#E"><font size="-2">E</font></a> 
    -+<a href="#F"><font size="-2">F</font></a> 
    -+<a href="#G"><font size="-2">G</font></a> 
    -+<a href="#H"><font size="-2">H</font></a> 
    -+<a href="#I"><font size="-2">I</font></a> 
    -+<a href="#L"><font size="-2">L</font></a> 
    -+<a href="#M"><font size="-2">M</font></a> 
    -+<a href="#N"><font size="-2">N</font></a> 
    -+<a href="#P"><font size="-2">P</font></a> 
    -+<a href="#R"><font size="-2">R</font></a> 
    -+<a href="#S"><font size="-2">S</font></a> 
    -+<a href="#T"><font size="-2">T</font></a> 
    -+<a href="#W"><font size="-2">W</font></a> 
    -+ <a href="#topheader"><font size="-2">TOP</font></a>
    -+<p><div style="line-height:1.5em;color:black">
    -+<i>obtain</i><br>
    -+&nbsp;&nbsp;<nobr><A HREF="android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.CollectionInfoCompat.html#android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.CollectionInfoCompat.obtain_added(int, int, boolean)" class="hiddenlink" target="rightframe">type&nbsp;<b>
    -+(<code>int, int, boolean</code>)</b>&nbsp;in&nbsp;android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.CollectionInfoCompat
    -+</A></nobr><br>
    -+<!-- Method obtain -->
    -+&nbsp;&nbsp;<nobr><A HREF="android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.CollectionItemInfoCompat.html#android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.CollectionItemInfoCompat.obtain_added(int, int, int, int, boolean)" class="hiddenlink" target="rightframe">type&nbsp;<b>
    -+(<code>int, int, int, int, boolean</code>)</b>&nbsp;in&nbsp;android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.CollectionItemInfoCompat
    -+</A></nobr><br>
    -+<!-- Method obtain -->
    -+&nbsp;&nbsp;<nobr><A HREF="android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.RangeInfoCompat.html#android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.RangeInfoCompat.obtain_added(int, float, float, float)" class="hiddenlink" target="rightframe">type&nbsp;<b>
    -+(<code>int, float, float, float</code>)</b>&nbsp;in&nbsp;android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.RangeInfoCompat
    -+</A></nobr><br>
    -+<!-- Method onAttachedToLayoutParams -->
    -+<nobr><A HREF="android.support.design.widget.CoordinatorLayout.Behavior.html#android.support.design.widget.CoordinatorLayout.Behavior.onAttachedToLayoutParams_added(android.support.design.widget.CoordinatorLayout.LayoutParams)" class="hiddenlink" target="rightframe"><b>onAttachedToLayoutParams</b>
    -+(<code>LayoutParams</code>)</A></nobr><br>
    -+<!-- Method onBindMediaPlayState -->
    -+<nobr><A HREF="android.support.v17.leanback.widget.AbstractMediaItemPresenter.html#android.support.v17.leanback.widget.AbstractMediaItemPresenter.onBindMediaPlayState_added(android.support.v17.leanback.widget.AbstractMediaItemPresenter.ViewHolder)" class="hiddenlink" target="rightframe"><b>onBindMediaPlayState</b>
    -+(<code>ViewHolder</code>)</A></nobr><br>
    -+<!-- Method onChanged -->
    -+<nobr><A HREF="android.support.v7.util.SortedList.Callback.html#android.support.v7.util.SortedList.Callback.onChanged_added(int, int, java.lang.Object)" class="hiddenlink" target="rightframe"><b>onChanged</b>
    -+(<code>int, int, Object</code>)</A></nobr><br>
    -+<!-- Method onDetachedFromLayoutParams -->
    -+<nobr><A HREF="android.support.design.widget.CoordinatorLayout.Behavior.html#android.support.design.widget.CoordinatorLayout.Behavior.onDetachedFromLayoutParams_added()" class="hiddenlink" target="rightframe"><b>onDetachedFromLayoutParams</b>
    -+()</A></nobr><br>
    -+<!-- Method onRequestChildRectangleOnScreen -->
    -+<i>onRequestChildRectangleOnScreen</i><br>
    -+&nbsp;&nbsp;<nobr><A HREF="android.support.design.widget.AppBarLayout.ScrollingViewBehavior.html#android.support.design.widget.AppBarLayout.ScrollingViewBehavior.onRequestChildRectangleOnScreen_added(android.support.design.widget.CoordinatorLayout, android.view.View, android.graphics.Rect, boolean)" class="hiddenlink" target="rightframe">type&nbsp;<b>
    -+(<code>CoordinatorLayout, View, Rect, boolean</code>)</b>&nbsp;in&nbsp;android.support.design.widget.AppBarLayout.ScrollingViewBehavior
    -+</A></nobr><br>
    -+<!-- Method onRequestChildRectangleOnScreen -->
    -+&nbsp;&nbsp;<nobr><A HREF="android.support.design.widget.CoordinatorLayout.Behavior.html#android.support.design.widget.CoordinatorLayout.Behavior.onRequestChildRectangleOnScreen_added(android.support.design.widget.CoordinatorLayout, V, android.graphics.Rect, boolean)" class="hiddenlink" target="rightframe">type&nbsp;<b>
    -+(<code>CoordinatorLayout, V, Rect, boolean</code>)</b>&nbsp;in&nbsp;android.support.design.widget.CoordinatorLayout.Behavior
    -+</A></nobr><br>
    -+<!-- Method onSharedElementsArrived -->
    -+<nobr><A HREF="android.support.v4.app.SharedElementCallback.html#android.support.v4.app.SharedElementCallback.onSharedElementsArrived_added(java.util.List<java.lang.String>, java.util.List<android.view.View>, android.support.v4.app.SharedElementCallback.OnSharedElementsReadyListener)" class="hiddenlink" target="rightframe"><b>onSharedElementsArrived</b>
    -+(<code>List&lt;String&gt;, List&lt;View&gt;, OnSharedElementsReadyListener</code>)</A></nobr><br>
    -+<!-- Method onStart -->
    -+<nobr><A HREF="android.support.v7.app.AppCompatDelegate.html#android.support.v7.app.AppCompatDelegate.onStart_added()" class="hiddenlink" target="rightframe"><b>onStart</b>
    -+()</A></nobr><br>
    -+<!-- Method onUnbindMediaPlayState -->
    -+<nobr><A HREF="android.support.v17.leanback.widget.AbstractMediaItemPresenter.html#android.support.v17.leanback.widget.AbstractMediaItemPresenter.onUnbindMediaPlayState_added(android.support.v17.leanback.widget.AbstractMediaItemPresenter.ViewHolder)" class="hiddenlink" target="rightframe"><b>onUnbindMediaPlayState</b>
    -+(<code>ViewHolder</code>)</A></nobr><br>
    -+<!-- Class PatternsCompat -->
    -+<A NAME="P"></A>
    -+<br><font size="+2">P</font>&nbsp;
    -+<a href="#A"><font size="-2">A</font></a> 
    -+<a href="#B"><font size="-2">B</font></a> 
    -+<a href="#C"><font size="-2">C</font></a> 
    -+<a href="#D"><font size="-2">D</font></a> 
    -+<a href="#E"><font size="-2">E</font></a> 
    -+<a href="#F"><font size="-2">F</font></a> 
    -+<a href="#G"><font size="-2">G</font></a> 
    -+<a href="#H"><font size="-2">H</font></a> 
    -+<a href="#I"><font size="-2">I</font></a> 
    -+<a href="#L"><font size="-2">L</font></a> 
    -+<a href="#M"><font size="-2">M</font></a> 
    -+<a href="#N"><font size="-2">N</font></a> 
    -+<a href="#O"><font size="-2">O</font></a> 
    -+<a href="#R"><font size="-2">R</font></a> 
    -+<a href="#S"><font size="-2">S</font></a> 
    -+<a href="#T"><font size="-2">T</font></a> 
    -+<a href="#W"><font size="-2">W</font></a> 
    -+ <a href="#topheader"><font size="-2">TOP</font></a>
    -+<p><div style="line-height:1.5em;color:black">
    -+<A HREF="pkg_android.support.v4.util.html#PatternsCompat" class="hiddenlink" target="rightframe"><b>PatternsCompat</b></A><br>
    -+<!-- Field PEEK_HEIGHT_AUTO -->
    -+<nobr><A HREF="android.support.design.widget.BottomSheetBehavior.html#android.support.design.widget.BottomSheetBehavior.PEEK_HEIGHT_AUTO" class="hiddenlink" target="rightframe">PEEK_HEIGHT_AUTO</A>
    -+</nobr><br>
    -+<!-- Field PLAY_STATE_INITIAL -->
    -+<nobr><A HREF="android.support.v17.leanback.widget.AbstractMediaItemPresenter.html#android.support.v17.leanback.widget.AbstractMediaItemPresenter.PLAY_STATE_INITIAL" class="hiddenlink" target="rightframe">PLAY_STATE_INITIAL</A>
    -+</nobr><br>
    -+<!-- Field PLAY_STATE_PAUSED -->
    -+<nobr><A HREF="android.support.v17.leanback.widget.AbstractMediaItemPresenter.html#android.support.v17.leanback.widget.AbstractMediaItemPresenter.PLAY_STATE_PAUSED" class="hiddenlink" target="rightframe">PLAY_STATE_PAUSED</A>
    -+</nobr><br>
    -+<!-- Field PLAY_STATE_PLAYING -->
    -+<nobr><A HREF="android.support.v17.leanback.widget.AbstractMediaItemPresenter.html#android.support.v17.leanback.widget.AbstractMediaItemPresenter.PLAY_STATE_PLAYING" class="hiddenlink" target="rightframe">PLAY_STATE_PLAYING</A>
    -+</nobr><br>
    -+<!-- Class PopupMenu -->
    -+<A HREF="pkg_android.support.v7.widget.html#PopupMenu" class="hiddenlink" target="rightframe"><b>PopupMenu</b></A><br>
    -+<!-- Class PopupMenu.OnDismissListener -->
    -+<A HREF="pkg_android.support.v7.widget.html#PopupMenu.OnDismissListener" class="hiddenlink" target="rightframe"><b><i>PopupMenu.OnDismissListener</i></b></A><br>
    -+<!-- Class PopupMenu.OnMenuItemClickListener -->
    -+<A HREF="pkg_android.support.v7.widget.html#PopupMenu.OnMenuItemClickListener" class="hiddenlink" target="rightframe"><b><i>PopupMenu.OnMenuItemClickListener</i></b></A><br>
    -+<!-- Class RecyclerView.OnFlingListener -->
    -+<A NAME="R"></A>
    -+<br><font size="+2">R</font>&nbsp;
    -+<a href="#A"><font size="-2">A</font></a> 
    -+<a href="#B"><font size="-2">B</font></a> 
    -+<a href="#C"><font size="-2">C</font></a> 
    -+<a href="#D"><font size="-2">D</font></a> 
    -+<a href="#E"><font size="-2">E</font></a> 
    -+<a href="#F"><font size="-2">F</font></a> 
    -+<a href="#G"><font size="-2">G</font></a> 
    -+<a href="#H"><font size="-2">H</font></a> 
    -+<a href="#I"><font size="-2">I</font></a> 
    -+<a href="#L"><font size="-2">L</font></a> 
    -+<a href="#M"><font size="-2">M</font></a> 
    -+<a href="#N"><font size="-2">N</font></a> 
    -+<a href="#O"><font size="-2">O</font></a> 
    -+<a href="#P"><font size="-2">P</font></a> 
    -+<a href="#S"><font size="-2">S</font></a> 
    -+<a href="#T"><font size="-2">T</font></a> 
    -+<a href="#W"><font size="-2">W</font></a> 
    -+ <a href="#topheader"><font size="-2">TOP</font></a>
    -+<p><div style="line-height:1.5em;color:black">
    -+<A HREF="pkg_android.support.v7.widget.html#RecyclerView.OnFlingListener" class="hiddenlink" target="rightframe"><b>RecyclerView.OnFlingListener</b></A><br>
    -+<!-- Class RecyclerView.SmoothScroller.ScrollVectorProvider -->
    -+<A HREF="pkg_android.support.v7.widget.html#RecyclerView.SmoothScroller.ScrollVectorProvider" class="hiddenlink" target="rightframe"><b><i>RecyclerView.SmoothScroller.ScrollVectorProvider</i></b></A><br>
    -+<!-- Method removeTouchExplorationStateChangeListener -->
    -+<nobr><A HREF="android.support.v4.view.accessibility.AccessibilityManagerCompat.html#android.support.v4.view.accessibility.AccessibilityManagerCompat.removeTouchExplorationStateChangeListener_added(android.view.accessibility.AccessibilityManager, android.support.v4.view.accessibility.AccessibilityManagerCompat.TouchExplorationStateChangeListener)" class="hiddenlink" target="rightframe"><b>removeTouchExplorationStateChangeListener</b>
    -+(<code>AccessibilityManager, TouchExplorationStateChangeListener</code>)</A></nobr><br>
    -+<!-- Method requestUsageTimeReport -->
    -+<nobr><A HREF="android.support.v4.app.ActivityOptionsCompat.html#android.support.v4.app.ActivityOptionsCompat.requestUsageTimeReport_added(android.app.PendingIntent)" class="hiddenlink" target="rightframe"><b>requestUsageTimeReport</b>
    -+(<code>PendingIntent</code>)</A></nobr><br>
    -+<!-- Class SearchView -->
    -+<A NAME="S"></A>
    -+<br><font size="+2">S</font>&nbsp;
    -+<a href="#A"><font size="-2">A</font></a> 
    -+<a href="#B"><font size="-2">B</font></a> 
    -+<a href="#C"><font size="-2">C</font></a> 
    -+<a href="#D"><font size="-2">D</font></a> 
    -+<a href="#E"><font size="-2">E</font></a> 
    -+<a href="#F"><font size="-2">F</font></a> 
    -+<a href="#G"><font size="-2">G</font></a> 
    -+<a href="#H"><font size="-2">H</font></a> 
    -+<a href="#I"><font size="-2">I</font></a> 
    -+<a href="#L"><font size="-2">L</font></a> 
    -+<a href="#M"><font size="-2">M</font></a> 
    -+<a href="#N"><font size="-2">N</font></a> 
    -+<a href="#O"><font size="-2">O</font></a> 
    -+<a href="#P"><font size="-2">P</font></a> 
    -+<a href="#R"><font size="-2">R</font></a> 
    -+<a href="#T"><font size="-2">T</font></a> 
    -+<a href="#W"><font size="-2">W</font></a> 
    -+ <a href="#topheader"><font size="-2">TOP</font></a>
    -+<p><div style="line-height:1.5em;color:black">
    -+<A HREF="pkg_android.support.v7.widget.html#SearchView" class="hiddenlink" target="rightframe"><b>SearchView</b></A><br>
    -+<!-- Class SearchView.OnCloseListener -->
    -+<A HREF="pkg_android.support.v7.widget.html#SearchView.OnCloseListener" class="hiddenlink" target="rightframe"><b><i>SearchView.OnCloseListener</i></b></A><br>
    -+<!-- Class SearchView.OnQueryTextListener -->
    -+<A HREF="pkg_android.support.v7.widget.html#SearchView.OnQueryTextListener" class="hiddenlink" target="rightframe"><b><i>SearchView.OnQueryTextListener</i></b></A><br>
    -+<!-- Class SearchView.OnSuggestionListener -->
    -+<A HREF="pkg_android.support.v7.widget.html#SearchView.OnSuggestionListener" class="hiddenlink" target="rightframe"><b><i>SearchView.OnSuggestionListener</i></b></A><br>
    -+<!-- Class SearchViewCompat.OnCloseListener -->
    -+<A HREF="pkg_android.support.v4.widget.html#SearchViewCompat.OnCloseListener" class="hiddenlink" target="rightframe"><b><i>SearchViewCompat.OnCloseListener</i></b></A><br>
    -+<!-- Class SearchViewCompat.OnQueryTextListener -->
    -+<A HREF="pkg_android.support.v4.widget.html#SearchViewCompat.OnQueryTextListener" class="hiddenlink" target="rightframe"><b><i>SearchViewCompat.OnQueryTextListener</i></b></A><br>
    -+<!-- Method setAction -->
    -+<nobr><A HREF="android.support.v4.view.accessibility.AccessibilityEventCompat.html#android.support.v4.view.accessibility.AccessibilityEventCompat.setAction_added(android.view.accessibility.AccessibilityEvent, int)" class="hiddenlink" target="rightframe"><b>setAction</b>
    -+(<code>AccessibilityEvent, int</code>)</A></nobr><br>
    -+<!-- Method setAlwaysUseBrowserUI -->
    -+<nobr><A HREF="android.support.customtabs.CustomTabsIntent.html#android.support.customtabs.CustomTabsIntent.setAlwaysUseBrowserUI_added(android.content.Intent)" class="hiddenlink" target="rightframe"><b>setAlwaysUseBrowserUI</b>
    -+(<code>Intent</code>)</A></nobr><br>
    -+<!-- Method setAutoHideEnabled -->
    -+<nobr><A HREF="android.support.design.widget.FloatingActionButton.Behavior.html#android.support.design.widget.FloatingActionButton.Behavior.setAutoHideEnabled_added(boolean)" class="hiddenlink" target="rightframe"><b>setAutoHideEnabled</b>
    -+(<code>boolean</code>)</A></nobr><br>
    -+<!-- Method setCollapsedTitleTextColor -->
    -+<nobr><A HREF="android.support.design.widget.CollapsingToolbarLayout.html#android.support.design.widget.CollapsingToolbarLayout.setCollapsedTitleTextColor_added(android.content.res.ColorStateList)" class="hiddenlink" target="rightframe"><b>setCollapsedTitleTextColor</b>
    -+(<code>ColorStateList</code>)</A></nobr><br>
    -+<!-- Method setContextClickable -->
    -+<nobr><A HREF="android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.html#android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.setContextClickable_added(boolean)" class="hiddenlink" target="rightframe"><b>setContextClickable</b>
    -+(<code>boolean</code>)</A></nobr><br>
    -+<!-- Method setDrawerArrowDrawable -->
    -+<nobr><A HREF="android.support.v7.app.ActionBarDrawerToggle.html#android.support.v7.app.ActionBarDrawerToggle.setDrawerArrowDrawable_added(android.support.v7.graphics.drawable.DrawerArrowDrawable)" class="hiddenlink" target="rightframe"><b>setDrawerArrowDrawable</b>
    -+(<code>DrawerArrowDrawable</code>)</A></nobr><br>
    -+<!-- Method setExpandedTitleTextColor -->
    -+<nobr><A HREF="android.support.design.widget.CollapsingToolbarLayout.html#android.support.design.widget.CollapsingToolbarLayout.setExpandedTitleTextColor_added(android.content.res.ColorStateList)" class="hiddenlink" target="rightframe"><b>setExpandedTitleTextColor</b>
    -+(<code>ColorStateList</code>)</A></nobr><br>
    -+<!-- Method setInstantAppsEnabled -->
    -+<nobr><A HREF="android.support.customtabs.CustomTabsIntent.Builder.html#android.support.customtabs.CustomTabsIntent.Builder.setInstantAppsEnabled_added(boolean)" class="hiddenlink" target="rightframe"><b>setInstantAppsEnabled</b>
    -+(<code>boolean</code>)</A></nobr><br>
    -+<!-- Method setLaunchBounds -->
    -+<nobr><A HREF="android.support.v4.app.ActivityOptionsCompat.html#android.support.v4.app.ActivityOptionsCompat.setLaunchBounds_added(android.graphics.Rect)" class="hiddenlink" target="rightframe"><b>setLaunchBounds</b>
    -+(<code>Rect</code>)</A></nobr><br>
    -+<!-- Method setMovementGranularity -->
    -+<nobr><A HREF="android.support.v4.view.accessibility.AccessibilityEventCompat.html#android.support.v4.view.accessibility.AccessibilityEventCompat.setMovementGranularity_added(android.view.accessibility.AccessibilityEvent, int)" class="hiddenlink" target="rightframe"><b>setMovementGranularity</b>
    -+(<code>AccessibilityEvent, int</code>)</A></nobr><br>
    -+<!-- Method setOnChildScrollUpCallback -->
    -+<nobr><A HREF="android.support.v4.widget.SwipeRefreshLayout.html#android.support.v4.widget.SwipeRefreshLayout.setOnChildScrollUpCallback_added(android.support.v4.widget.SwipeRefreshLayout.OnChildScrollUpCallback)" class="hiddenlink" target="rightframe"><b>setOnChildScrollUpCallback</b>
    -+(<code>OnChildScrollUpCallback</code>)</A></nobr><br>
    -+<!-- Method setOnFlingListener -->
    -+<nobr><A HREF="android.support.v7.widget.RecyclerView.html#android.support.v7.widget.RecyclerView.setOnFlingListener_added(android.support.v7.widget.RecyclerView.OnFlingListener)" class="hiddenlink" target="rightframe"><b>setOnFlingListener</b>
    -+(<code>OnFlingListener</code>)</A></nobr><br>
    -+<!-- Method setPasswordVisibilityToggleContentDescription -->
    -+<i>setPasswordVisibilityToggleContentDescription</i><br>
    -+&nbsp;&nbsp;<nobr><A HREF="android.support.design.widget.TextInputLayout.html#android.support.design.widget.TextInputLayout.setPasswordVisibilityToggleContentDescription_added(int)" class="hiddenlink" target="rightframe">type&nbsp;<b>
    -+(<code>int</code>)</b>&nbsp;in&nbsp;android.support.design.widget.TextInputLayout
    -+</A></nobr><br>
    -+<!-- Method setPasswordVisibilityToggleContentDescription -->
    -+&nbsp;&nbsp;<nobr><A HREF="android.support.design.widget.TextInputLayout.html#android.support.design.widget.TextInputLayout.setPasswordVisibilityToggleContentDescription_added(java.lang.CharSequence)" class="hiddenlink" target="rightframe">type&nbsp;<b>
    -+(<code>CharSequence</code>)</b>&nbsp;in&nbsp;android.support.design.widget.TextInputLayout
    -+</A></nobr><br>
    -+<!-- Method setPasswordVisibilityToggleDrawable -->
    -+<i>setPasswordVisibilityToggleDrawable</i><br>
    -+&nbsp;&nbsp;<nobr><A HREF="android.support.design.widget.TextInputLayout.html#android.support.design.widget.TextInputLayout.setPasswordVisibilityToggleDrawable_added(android.graphics.drawable.Drawable)" class="hiddenlink" target="rightframe">type&nbsp;<b>
    -+(<code>Drawable</code>)</b>&nbsp;in&nbsp;android.support.design.widget.TextInputLayout
    -+</A></nobr><br>
    -+<!-- Method setPasswordVisibilityToggleDrawable -->
    -+&nbsp;&nbsp;<nobr><A HREF="android.support.design.widget.TextInputLayout.html#android.support.design.widget.TextInputLayout.setPasswordVisibilityToggleDrawable_added(int)" class="hiddenlink" target="rightframe">type&nbsp;<b>
    -+(<code>int</code>)</b>&nbsp;in&nbsp;android.support.design.widget.TextInputLayout
    -+</A></nobr><br>
    -+<!-- Method setPasswordVisibilityToggleEnabled -->
    -+<nobr><A HREF="android.support.design.widget.TextInputLayout.html#android.support.design.widget.TextInputLayout.setPasswordVisibilityToggleEnabled_added(boolean)" class="hiddenlink" target="rightframe"><b>setPasswordVisibilityToggleEnabled</b>
    -+(<code>boolean</code>)</A></nobr><br>
    -+<!-- Method setPasswordVisibilityToggleTintList -->
    -+<nobr><A HREF="android.support.design.widget.TextInputLayout.html#android.support.design.widget.TextInputLayout.setPasswordVisibilityToggleTintList_added(android.content.res.ColorStateList)" class="hiddenlink" target="rightframe"><b>setPasswordVisibilityToggleTintList</b>
    -+(<code>ColorStateList</code>)</A></nobr><br>
    -+<!-- Method setPasswordVisibilityToggleTintMode -->
    -+<nobr><A HREF="android.support.design.widget.TextInputLayout.html#android.support.design.widget.TextInputLayout.setPasswordVisibilityToggleTintMode_added(android.graphics.PorterDuff.Mode)" class="hiddenlink" target="rightframe"><b>setPasswordVisibilityToggleTintMode</b>
    -+(<code>Mode</code>)</A></nobr><br>
    -+<!-- Method setSecondaryToolbarViews -->
    -+<nobr><A HREF="android.support.customtabs.CustomTabsSession.html#android.support.customtabs.CustomTabsSession.setSecondaryToolbarViews_added(android.widget.RemoteViews, int[], android.app.PendingIntent)" class="hiddenlink" target="rightframe"><b>setSecondaryToolbarViews</b>
    -+(<code>RemoteViews, int[], PendingIntent</code>)</A></nobr><br>
    -+<!-- Method setSelectedMediaItemNumberView -->
    -+<nobr><A HREF="android.support.v17.leanback.widget.AbstractMediaItemPresenter.ViewHolder.html#android.support.v17.leanback.widget.AbstractMediaItemPresenter.ViewHolder.setSelectedMediaItemNumberView_added(int)" class="hiddenlink" target="rightframe"><b>setSelectedMediaItemNumberView</b>
    -+(<code>int</code>)</A></nobr><br>
    -+<!-- Class ShareActionProvider -->
    -+<A HREF="pkg_android.support.v7.widget.html#ShareActionProvider" class="hiddenlink" target="rightframe"><b>ShareActionProvider</b></A><br>
    -+<!-- Class ShareActionProvider.OnShareTargetSelectedListener -->
    -+<A HREF="pkg_android.support.v7.widget.html#ShareActionProvider.OnShareTargetSelectedListener" class="hiddenlink" target="rightframe"><b><i>ShareActionProvider.OnShareTargetSelectedListener</i></b></A><br>
    -+<!-- Class SharedElementCallback.OnSharedElementsReadyListener -->
    -+<A HREF="pkg_android.support.v4.app.html#SharedElementCallback.OnSharedElementsReadyListener" class="hiddenlink" target="rightframe"><b><i>SharedElementCallback.OnSharedElementsReadyListener</i></b></A><br>
    -+<!-- Method shouldAlwaysUseBrowserUI -->
    -+<nobr><A HREF="android.support.customtabs.CustomTabsIntent.html#android.support.customtabs.CustomTabsIntent.shouldAlwaysUseBrowserUI_added(android.content.Intent)" class="hiddenlink" target="rightframe"><b>shouldAlwaysUseBrowserUI</b>
    -+(<code>Intent</code>)</A></nobr><br>
    -+<!-- Class SnapHelper -->
    -+<A HREF="pkg_android.support.v7.widget.html#SnapHelper" class="hiddenlink" target="rightframe"><b>SnapHelper</b></A><br>
    -+<!-- Class Space -->
    -+<A HREF="pkg_android.support.v7.widget.html#Space" class="hiddenlink" target="rightframe"><b>Space</b></A><br>
    -+<!-- Field STOP_FOREGROUND_DETACH -->
    -+<nobr><A HREF="android.support.v4.app.ServiceCompat.html#android.support.v4.app.ServiceCompat.STOP_FOREGROUND_DETACH" class="hiddenlink" target="rightframe">STOP_FOREGROUND_DETACH</A>
    -+</nobr><br>
    -+<!-- Field STOP_FOREGROUND_REMOVE -->
    -+<nobr><A HREF="android.support.v4.app.ServiceCompat.html#android.support.v4.app.ServiceCompat.STOP_FOREGROUND_REMOVE" class="hiddenlink" target="rightframe">STOP_FOREGROUND_REMOVE</A>
    -+</nobr><br>
    -+<!-- Method stopForeground -->
    -+<nobr><A HREF="android.support.v4.app.ServiceCompat.html#android.support.v4.app.ServiceCompat.stopForeground_added(android.app.Service, int)" class="hiddenlink" target="rightframe"><b>stopForeground</b>
    -+(<code>Service, int</code>)</A></nobr><br>
    -+<!-- Class SwipeRefreshLayout.OnChildScrollUpCallback -->
    -+<A HREF="pkg_android.support.v4.widget.html#SwipeRefreshLayout.OnChildScrollUpCallback" class="hiddenlink" target="rightframe"><b><i>SwipeRefreshLayout.OnChildScrollUpCallback</i></b></A><br>
    -+<!-- Class SwitchCompat -->
    -+<A HREF="pkg_android.support.v7.widget.html#SwitchCompat" class="hiddenlink" target="rightframe"><b>SwitchCompat</b></A><br>
    -+<!-- Class ThemedSpinnerAdapter -->
    -+<A NAME="T"></A>
    -+<br><font size="+2">T</font>&nbsp;
    -+<a href="#A"><font size="-2">A</font></a> 
    -+<a href="#B"><font size="-2">B</font></a> 
    -+<a href="#C"><font size="-2">C</font></a> 
    -+<a href="#D"><font size="-2">D</font></a> 
    -+<a href="#E"><font size="-2">E</font></a> 
    -+<a href="#F"><font size="-2">F</font></a> 
    -+<a href="#G"><font size="-2">G</font></a> 
    -+<a href="#H"><font size="-2">H</font></a> 
    -+<a href="#I"><font size="-2">I</font></a> 
    -+<a href="#L"><font size="-2">L</font></a> 
    -+<a href="#M"><font size="-2">M</font></a> 
    -+<a href="#N"><font size="-2">N</font></a> 
    -+<a href="#O"><font size="-2">O</font></a> 
    -+<a href="#P"><font size="-2">P</font></a> 
    -+<a href="#R"><font size="-2">R</font></a> 
    -+<a href="#S"><font size="-2">S</font></a> 
    -+<a href="#W"><font size="-2">W</font></a> 
    -+ <a href="#topheader"><font size="-2">TOP</font></a>
    -+<p><div style="line-height:1.5em;color:black">
    -+<A HREF="pkg_android.support.v7.widget.html#ThemedSpinnerAdapter" class="hiddenlink" target="rightframe"><b><i>ThemedSpinnerAdapter</i></b></A><br>
    -+<!-- Class ThemedSpinnerAdapter.Helper -->
    -+<A HREF="pkg_android.support.v7.widget.html#ThemedSpinnerAdapter.Helper" class="hiddenlink" target="rightframe"><b>ThemedSpinnerAdapter.Helper</b></A><br>
    -+<!-- Method toKeyCode -->
    -+<nobr><A HREF="android.support.v4.media.session.PlaybackStateCompat.html#android.support.v4.media.session.PlaybackStateCompat.toKeyCode_added(long)" class="hiddenlink" target="rightframe"><b>toKeyCode</b>
    -+(<code>long</code>)</A></nobr><br>
    -+<!-- Class Toolbar -->
    -+<A HREF="pkg_android.support.v7.widget.html#Toolbar" class="hiddenlink" target="rightframe"><b>Toolbar</b></A><br>
    -+<!-- Class Toolbar.LayoutParams -->
    -+<A HREF="pkg_android.support.v7.widget.html#Toolbar.LayoutParams" class="hiddenlink" target="rightframe"><b>Toolbar.LayoutParams</b></A><br>
    -+<!-- Class Toolbar.OnMenuItemClickListener -->
    -+<A HREF="pkg_android.support.v7.widget.html#Toolbar.OnMenuItemClickListener" class="hiddenlink" target="rightframe"><b><i>Toolbar.OnMenuItemClickListener</i></b></A><br>
    -+<!-- Class Toolbar.SavedState -->
    -+<A HREF="pkg_android.support.v7.widget.html#Toolbar.SavedState" class="hiddenlink" target="rightframe"><b>Toolbar.SavedState</b></A><br>
    -+<!-- Field TYPE_ASSIST_READING_CONTEXT -->
    -+<nobr><A HREF="android.support.v4.view.accessibility.AccessibilityEventCompat.html#android.support.v4.view.accessibility.AccessibilityEventCompat.TYPE_ASSIST_READING_CONTEXT" class="hiddenlink" target="rightframe">TYPE_ASSIST_READING_CONTEXT</A>
    -+</nobr><br>
    -+<!-- Field TYPE_SPLIT_SCREEN_DIVIDER -->
    -+<nobr><A HREF="android.support.v4.view.accessibility.AccessibilityWindowInfoCompat.html#android.support.v4.view.accessibility.AccessibilityWindowInfoCompat.TYPE_SPLIT_SCREEN_DIVIDER" class="hiddenlink" target="rightframe">TYPE_SPLIT_SCREEN_DIVIDER</A>
    -+</nobr><br>
    -+<!-- Field TYPE_VIEW_CONTEXT_CLICKED -->
    -+<nobr><A HREF="android.support.v4.view.accessibility.AccessibilityEventCompat.html#android.support.v4.view.accessibility.AccessibilityEventCompat.TYPE_VIEW_CONTEXT_CLICKED" class="hiddenlink" target="rightframe">TYPE_VIEW_CONTEXT_CLICKED</A>
    -+</nobr><br>
    -+<!-- Field TYPE_WINDOWS_CHANGED -->
    -+<nobr><A HREF="android.support.v4.view.accessibility.AccessibilityEventCompat.html#android.support.v4.view.accessibility.AccessibilityEventCompat.TYPE_WINDOWS_CHANGED" class="hiddenlink" target="rightframe">TYPE_WINDOWS_CHANGED</A>
    -+</nobr><br>
    -+<!-- Constructor WindowInsetsCompat -->
    -+<A NAME="W"></A>
    -+<br><font size="+2">W</font>&nbsp;
    -+<a href="#A"><font size="-2">A</font></a> 
    -+<a href="#B"><font size="-2">B</font></a> 
    -+<a href="#C"><font size="-2">C</font></a> 
    -+<a href="#D"><font size="-2">D</font></a> 
    -+<a href="#E"><font size="-2">E</font></a> 
    -+<a href="#F"><font size="-2">F</font></a> 
    -+<a href="#G"><font size="-2">G</font></a> 
    -+<a href="#H"><font size="-2">H</font></a> 
    -+<a href="#I"><font size="-2">I</font></a> 
    -+<a href="#L"><font size="-2">L</font></a> 
    -+<a href="#M"><font size="-2">M</font></a> 
    -+<a href="#N"><font size="-2">N</font></a> 
    -+<a href="#O"><font size="-2">O</font></a> 
    -+<a href="#P"><font size="-2">P</font></a> 
    -+<a href="#R"><font size="-2">R</font></a> 
    -+<a href="#S"><font size="-2">S</font></a> 
    -+<a href="#T"><font size="-2">T</font></a> 
    -+ <a href="#topheader"><font size="-2">TOP</font></a>
    -+<p><div style="line-height:1.5em;color:black">
    -+<nobr><A HREF="android.support.v4.view.WindowInsetsCompat.html#android.support.v4.view.WindowInsetsCompat.ctor_added(android.support.v4.view.WindowInsetsCompat)" class="hiddenlink" target="rightframe"><b>WindowInsetsCompat</b>
    -+(<code>WindowInsetsCompat</code>)</A></nobr>&nbsp;constructor<br>
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    -+</script>
    -+<script type="text/javascript">
    -+  try {
    -+    var pageTracker = _gat._getTracker("UA-5831155-1");
    -+    pageTracker._setAllowAnchor(true);
    -+    pageTracker._initData();
    -+    pageTracker._trackPageview();
    -+  } catch(e) {}
    -+</script>
    -+</BODY>
    -+</HTML>
    -diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/alldiffs_index_all.html b/docs/html/sdk/support_api_diff/24.2.0/changes/alldiffs_index_all.html
    -new file mode 100644
    -index 0000000..fb553f8
    ---- /dev/null
    -+++ b/docs/html/sdk/support_api_diff/24.2.0/changes/alldiffs_index_all.html
    -@@ -0,0 +1,1327 @@
    -+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
    -+<HTML style="overflow:auto;">
    -+<HEAD>
    -+<meta name="generator" content="JDiff v1.1.0">
    -+<!-- Generated by the JDiff Javadoc doclet -->
    -+<!-- (http://www.jdiff.org) -->
    -+<meta name="description" content="JDiff is a Javadoc doclet which generates an HTML report of all the packages, classes, constructors, methods, and fields which have been removed, added or changed in any way, including their documentation, when two APIs are compared.">
    -+<meta name="keywords" content="diff, jdiff, javadiff, java diff, java difference, API difference, difference between two APIs, API diff, Javadoc, doclet">
    -+<TITLE>
    -+All Differences Index
    -+</TITLE>
    -+<link href="../../../../assets/android-developer-docs.css" rel="stylesheet" type="text/css" />
    -+<link href="../stylesheet-jdiff.css" rel="stylesheet" type="text/css" />
    -+<noscript>
    -+<style type="text/css">
    -+body{overflow:auto;}
    -+#body-content{position:relative; top:0;}
    -+#doc-content{overflow:visible;border-left:3px solid #666;}
    -+#side-nav{padding:0;}
    -+#side-nav .toggle-list ul {display:block;}
    -+#resize-packages-nav{border-bottom:3px solid #666;}
    -+</style>
    -+</noscript>
    -+<style type="text/css">
    -+</style>
    -+</HEAD>
    -+<BODY class="gc-documentation" style="padding:12px;">
    -+<a NAME="topheader"></a>
    -+<table summary="Index for All Differences" width="100%" class="jdiffIndex" border="0" cellspacing="0" cellpadding="0" style="padding-bottom:0;margin-bottom:0;">
    -+  <tr>
    -+  <th class="indexHeader">
    -+    Filter the Index:
    -+  </th>
    -+  </tr>
    -+  <tr>
    -+  <td class="indexText" style="line-height:1.3em;padding-left:2em;">
    -+<b>All Differences</b>
    -+  <br>
    -+<A HREF="alldiffs_index_removals.html" xclass="hiddenlink">Removals</A>
    -+  <br>
    -+<A HREF="alldiffs_index_additions.html"xclass="hiddenlink">Additions</A>
    -+  <br>
    -+<A HREF="alldiffs_index_changes.html"xclass="hiddenlink">Changes</A>
    -+  </td>
    -+  </tr>
    -+</table>
    -+<div id="indexTableCaption" style="background-color:#eee;padding:0 4px 0 4px;font-size:11px;margin-bottom:1em;">
    -+Listed as: <span style="color:#069"><strong>Added</strong></span>,  <span style="color:#069"><strike>Removed</strike></span>,  <span style="color:#069">Changed</span></font>
    -+</div>
    -+<!-- Class AbstractMediaItemPresenter -->
    -+<A NAME="A"></A>
    -+<br><font size="+2">A</font>&nbsp;
    -+<a href="#B"><font size="-2">B</font></a> 
    -+<a href="#C"><font size="-2">C</font></a> 
    -+<a href="#D"><font size="-2">D</font></a> 
    -+<a href="#E"><font size="-2">E</font></a> 
    -+<a href="#F"><font size="-2">F</font></a> 
    -+<a href="#G"><font size="-2">G</font></a> 
    -+<a href="#H"><font size="-2">H</font></a> 
    -+<a href="#I"><font size="-2">I</font></a> 
    -+<a href="#K"><font size="-2">K</font></a> 
    -+<a href="#L"><font size="-2">L</font></a> 
    -+<a href="#M"><font size="-2">M</font></a> 
    -+<a href="#N"><font size="-2">N</font></a> 
    -+<a href="#O"><font size="-2">O</font></a> 
    -+<a href="#P"><font size="-2">P</font></a> 
    -+<a href="#R"><font size="-2">R</font></a> 
    -+<a href="#S"><font size="-2">S</font></a> 
    -+<a href="#T"><font size="-2">T</font></a> 
    -+<a href="#V"><font size="-2">V</font></a> 
    -+<a href="#W"><font size="-2">W</font></a> 
    -+ <a href="#topheader"><font size="-2">TOP</font></a>
    -+<p><div style="line-height:1.5em;color:black">
    -+<A HREF="android.support.v17.leanback.widget.AbstractMediaItemPresenter.html" class="hiddenlink" target="rightframe">AbstractMediaItemPresenter</A><br>
    -+<!-- Class AbstractMediaItemPresenter.ViewHolder -->
    -+<A HREF="android.support.v17.leanback.widget.AbstractMediaItemPresenter.ViewHolder.html" class="hiddenlink" target="rightframe">AbstractMediaItemPresenter.ViewHolder</A><br>
    -+<!-- Class AccessibilityEventCompat -->
    -+<A HREF="android.support.v4.view.accessibility.AccessibilityEventCompat.html" class="hiddenlink" target="rightframe">AccessibilityEventCompat</A><br>
    -+<!-- Class AccessibilityManagerCompat -->
    -+<A HREF="android.support.v4.view.accessibility.AccessibilityManagerCompat.html" class="hiddenlink" target="rightframe">AccessibilityManagerCompat</A><br>
    -+<!-- Class AccessibilityManagerCompat.AccessibilityStateChangeListener -->
    -+<A HREF="pkg_android.support.v4.view.accessibility.html#AccessibilityManagerCompat.AccessibilityStateChangeListener" class="hiddenlink" target="rightframe"><b><i>AccessibilityManagerCompat.AccessibilityStateChangeListener</i></b></A><br>
    -+<!-- Class AccessibilityManagerCompat.AccessibilityStateChangeListenerCompat -->
    -+<A HREF="android.support.v4.view.accessibility.AccessibilityManagerCompat.AccessibilityStateChangeListenerCompat.html" class="hiddenlink" target="rightframe">AccessibilityManagerCompat.AccessibilityStateChangeListenerCompat</A><br>
    -+<!-- Class AccessibilityManagerCompat.TouchExplorationStateChangeListener -->
    -+<A HREF="pkg_android.support.v4.view.accessibility.html#AccessibilityManagerCompat.TouchExplorationStateChangeListener" class="hiddenlink" target="rightframe"><b><i>AccessibilityManagerCompat.TouchExplorationStateChangeListener</i></b></A><br>
    -+<!-- Class AccessibilityNodeInfoCompat -->
    -+<A HREF="android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.html" class="hiddenlink" target="rightframe">AccessibilityNodeInfoCompat</A><br>
    -+<!-- Class AccessibilityNodeInfoCompat.AccessibilityActionCompat -->
    -+<A HREF="android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat.html" class="hiddenlink" target="rightframe">AccessibilityNodeInfoCompat.AccessibilityActionCompat</A><br>
    -+<!-- Class AccessibilityNodeInfoCompat.CollectionInfoCompat -->
    -+<A HREF="android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.CollectionInfoCompat.html" class="hiddenlink" target="rightframe">AccessibilityNodeInfoCompat.CollectionInfoCompat</A><br>
    -+<!-- Class AccessibilityNodeInfoCompat.CollectionItemInfoCompat -->
    -+<A HREF="android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.CollectionItemInfoCompat.html" class="hiddenlink" target="rightframe">AccessibilityNodeInfoCompat.CollectionItemInfoCompat</A><br>
    -+<!-- Class AccessibilityNodeInfoCompat.RangeInfoCompat -->
    -+<A HREF="android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.RangeInfoCompat.html" class="hiddenlink" target="rightframe">AccessibilityNodeInfoCompat.RangeInfoCompat</A><br>
    -+<!-- Class AccessibilityNodeProviderCompat -->
    -+<A HREF="android.support.v4.view.accessibility.AccessibilityNodeProviderCompat.html" class="hiddenlink" target="rightframe">AccessibilityNodeProviderCompat</A><br>
    -+<!-- Class AccessibilityServiceInfoCompat -->
    -+<A HREF="android.support.v4.accessibilityservice.AccessibilityServiceInfoCompat.html" class="hiddenlink" target="rightframe">AccessibilityServiceInfoCompat</A><br>
    -+<!-- Class AccessibilityWindowInfoCompat -->
    -+<A HREF="android.support.v4.view.accessibility.AccessibilityWindowInfoCompat.html" class="hiddenlink" target="rightframe">AccessibilityWindowInfoCompat</A><br>
    -+<!-- Field ACTION_ARGUMENT_COLUMN_INT -->
    -+<nobr><A HREF="android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.html#android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.ACTION_ARGUMENT_COLUMN_INT" class="hiddenlink" target="rightframe">ACTION_ARGUMENT_COLUMN_INT</A>
    -+</nobr><br>
    -+<!-- Field ACTION_ARGUMENT_PROGRESS_VALUE -->
    -+<nobr><A HREF="android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.html#android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.ACTION_ARGUMENT_PROGRESS_VALUE" class="hiddenlink" target="rightframe">ACTION_ARGUMENT_PROGRESS_VALUE</A>
    -+</nobr><br>
    -+<!-- Field ACTION_ARGUMENT_ROW_INT -->
    -+<nobr><A HREF="android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.html#android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.ACTION_ARGUMENT_ROW_INT" class="hiddenlink" target="rightframe">ACTION_ARGUMENT_ROW_INT</A>
    -+</nobr><br>
    -+<!-- Field ACTION_CONTEXT_CLICK -->
    -+<nobr><A HREF="android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat.html#android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat.ACTION_CONTEXT_CLICK" class="hiddenlink" target="rightframe">ACTION_CONTEXT_CLICK</A>
    -+</nobr><br>
    -+<!-- Field ACTION_SCROLL_DOWN -->
    -+<nobr><A HREF="android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat.html#android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat.ACTION_SCROLL_DOWN" class="hiddenlink" target="rightframe">ACTION_SCROLL_DOWN</A>
    -+</nobr><br>
    -+<!-- Field ACTION_SCROLL_LEFT -->
    -+<nobr><A HREF="android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat.html#android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat.ACTION_SCROLL_LEFT" class="hiddenlink" target="rightframe">ACTION_SCROLL_LEFT</A>
    -+</nobr><br>
    -+<!-- Field ACTION_SCROLL_RIGHT -->
    -+<nobr><A HREF="android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat.html#android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat.ACTION_SCROLL_RIGHT" class="hiddenlink" target="rightframe">ACTION_SCROLL_RIGHT</A>
    -+</nobr><br>
    -+<!-- Field ACTION_SCROLL_TO_POSITION -->
    -+<nobr><A HREF="android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat.html#android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat.ACTION_SCROLL_TO_POSITION" class="hiddenlink" target="rightframe">ACTION_SCROLL_TO_POSITION</A>
    -+</nobr><br>
    -+<!-- Field ACTION_SCROLL_UP -->
    -+<nobr><A HREF="android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat.html#android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat.ACTION_SCROLL_UP" class="hiddenlink" target="rightframe">ACTION_SCROLL_UP</A>
    -+</nobr><br>
    -+<!-- Field ACTION_SET_PROGRESS -->
    -+<nobr><A HREF="android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat.html#android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat.ACTION_SET_PROGRESS" class="hiddenlink" target="rightframe">ACTION_SET_PROGRESS</A>
    -+</nobr><br>
    -+<!-- Field ACTION_SHOW_ON_SCREEN -->
    -+<nobr><A HREF="android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat.html#android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat.ACTION_SHOW_ON_SCREEN" class="hiddenlink" target="rightframe">ACTION_SHOW_ON_SCREEN</A>
    -+</nobr><br>
    -+<!-- Class ActionBarActivity -->
    -+<A HREF="pkg_android.support.v7.app.html#ActionBarActivity" class="hiddenlink" target="rightframe"><b>ActionBarActivity</b></A><br>
    -+<!-- Class ActionBarDrawerToggle -->
    -+<A HREF="android.support.v7.app.ActionBarDrawerToggle.html" class="hiddenlink" target="rightframe">ActionBarDrawerToggle</A><br>
    -+<!-- Class ActionMenuView -->
    -+<A HREF="pkg_android.support.v7.widget.html#ActionMenuView" class="hiddenlink" target="rightframe"><b>ActionMenuView</b></A><br>
    -+<!-- Class ActionMenuView.LayoutParams -->
    -+<A HREF="pkg_android.support.v7.widget.html#ActionMenuView.LayoutParams" class="hiddenlink" target="rightframe"><b>ActionMenuView.LayoutParams</b></A><br>
    -+<!-- Class ActionMenuView.OnMenuItemClickListener -->
    -+<A HREF="pkg_android.support.v7.widget.html#ActionMenuView.OnMenuItemClickListener" class="hiddenlink" target="rightframe"><b><i>ActionMenuView.OnMenuItemClickListener</i></b></A><br>
    -+<!-- Class ActivityCompat -->
    -+<i>ActivityCompat</i><br>
    -+&nbsp;&nbsp;<A HREF="android.support.v4.app.ActivityCompat.html" class="hiddenlink" target="rightframe">android.support.v4.app</A><br>
    -+<!-- Constructor ActivityCompat -->
    -+&nbsp;&nbsp;<nobr><A HREF="android.support.v4.app.ActivityCompat.html#android.support.v4.app.ActivityCompat.ctor_changed()" class="hiddenlink" target="rightframe">ActivityCompat
    -+()</A></nobr>&nbsp;constructor<br>
    -+<!-- Class ActivityOptionsCompat -->
    -+<A HREF="android.support.v4.app.ActivityOptionsCompat.html" class="hiddenlink" target="rightframe">ActivityOptionsCompat</A><br>
    -+<!-- Method addAccessibilityStateChangeListener -->
    -+<nobr><A HREF="android.support.v4.view.accessibility.AccessibilityManagerCompat.html#android.support.v4.view.accessibility.AccessibilityManagerCompat.addAccessibilityStateChangeListener_changed(android.view.accessibility.AccessibilityManager, android.support.v4.view.accessibility.AccessibilityManagerCompat.AccessibilityStateChangeListener)" class="hiddenlink" target="rightframe">addAccessibilityStateChangeListener
    -+(<code>AccessibilityManager, AccessibilityStateChangeListener</code>)</A></nobr><br>
    -+<!-- Method addTouchExplorationStateChangeListener -->
    -+<nobr><A HREF="android.support.v4.view.accessibility.AccessibilityManagerCompat.html#android.support.v4.view.accessibility.AccessibilityManagerCompat.addTouchExplorationStateChangeListener_added(android.view.accessibility.AccessibilityManager, android.support.v4.view.accessibility.AccessibilityManagerCompat.TouchExplorationStateChangeListener)" class="hiddenlink" target="rightframe"><b>addTouchExplorationStateChangeListener</b>
    -+(<code>AccessibilityManager, TouchExplorationStateChangeListener</code>)</A></nobr><br>
    -+<!-- Package android.support.customtabs -->
    -+<A HREF="pkg_android.support.customtabs.html" class="hiddenlink" target="rightframe">android.support.customtabs</A><br>
    -+<!-- Package android.support.design.widget -->
    -+<A HREF="pkg_android.support.design.widget.html" class="hiddenlink" target="rightframe">android.support.design.widget</A><br>
    -+<!-- Package android.support.transition -->
    -+<A HREF="changes-summary.html#android.support.transition" class="hiddenlink" target="rightframe"><b>android.support.transition</b></A><br>
    -+<!-- Package android.support.v14.preference -->
    -+<A HREF="pkg_android.support.v14.preference.html" class="hiddenlink" target="rightframe">android.support.v14.preference</A><br>
    -+<!-- Package android.support.v17.leanback.widget -->
    -+<A HREF="pkg_android.support.v17.leanback.widget.html" class="hiddenlink" target="rightframe">android.support.v17.leanback.widget</A><br>
    -+<!-- Package android.support.v17.preference -->
    -+<A HREF="pkg_android.support.v17.preference.html" class="hiddenlink" target="rightframe">android.support.v17.preference</A><br>
    -+<!-- Package android.support.v4.accessibilityservice -->
    -+<A HREF="pkg_android.support.v4.accessibilityservice.html" class="hiddenlink" target="rightframe">android.support.v4.accessibilityservice</A><br>
    -+<!-- Package android.support.v4.app -->
    -+<A HREF="pkg_android.support.v4.app.html" class="hiddenlink" target="rightframe">android.support.v4.app</A><br>
    -+<!-- Package android.support.v4.content -->
    -+<A HREF="pkg_android.support.v4.content.html" class="hiddenlink" target="rightframe">android.support.v4.content</A><br>
    -+<!-- Package android.support.v4.graphics.drawable -->
    -+<A HREF="pkg_android.support.v4.graphics.drawable.html" class="hiddenlink" target="rightframe">android.support.v4.graphics.drawable</A><br>
    -+<!-- Package android.support.v4.media -->
    -+<A HREF="pkg_android.support.v4.media.html" class="hiddenlink" target="rightframe">android.support.v4.media</A><br>
    -+<!-- Package android.support.v4.media.session -->
    -+<A HREF="pkg_android.support.v4.media.session.html" class="hiddenlink" target="rightframe">android.support.v4.media.session</A><br>
    -+<!-- Package android.support.v4.os -->
    -+<A HREF="pkg_android.support.v4.os.html" class="hiddenlink" target="rightframe">android.support.v4.os</A><br>
    -+<!-- Package android.support.v4.text.util -->
    -+<A HREF="changes-summary.html#android.support.v4.text.util" class="hiddenlink" target="rightframe"><b>android.support.v4.text.util</b></A><br>
    -+<!-- Package android.support.v4.util -->
    -+<A HREF="pkg_android.support.v4.util.html" class="hiddenlink" target="rightframe">android.support.v4.util</A><br>
    -+<!-- Package android.support.v4.view -->
    -+<A HREF="pkg_android.support.v4.view.html" class="hiddenlink" target="rightframe">android.support.v4.view</A><br>
    -+<!-- Package android.support.v4.view.accessibility -->
    -+<A HREF="pkg_android.support.v4.view.accessibility.html" class="hiddenlink" target="rightframe">android.support.v4.view.accessibility</A><br>
    -+<!-- Package android.support.v4.widget -->
    -+<A HREF="pkg_android.support.v4.widget.html" class="hiddenlink" target="rightframe">android.support.v4.widget</A><br>
    -+<!-- Package android.support.v7.app -->
    -+<A HREF="pkg_android.support.v7.app.html" class="hiddenlink" target="rightframe">android.support.v7.app</A><br>
    -+<!-- Package android.support.v7.appcompat -->
    -+<A HREF="changes-summary.html#android.support.v7.appcompat" class="hiddenlink" target="rightframe"><strike>android.support.v7.appcompat</strike></A><br>
    -+<!-- Package android.support.v7.content.res -->
    -+<A HREF="pkg_android.support.v7.content.res.html" class="hiddenlink" target="rightframe">android.support.v7.content.res</A><br>
    -+<!-- Package android.support.v7.graphics -->
    -+<A HREF="pkg_android.support.v7.graphics.html" class="hiddenlink" target="rightframe">android.support.v7.graphics</A><br>
    -+<!-- Package android.support.v7.preference -->
    -+<A HREF="pkg_android.support.v7.preference.html" class="hiddenlink" target="rightframe">android.support.v7.preference</A><br>
    -+<!-- Package android.support.v7.recyclerview -->
    -+<A HREF="changes-summary.html#android.support.v7.recyclerview" class="hiddenlink" target="rightframe"><strike>android.support.v7.recyclerview</strike></A><br>
    -+<!-- Package android.support.v7.util -->
    -+<A HREF="pkg_android.support.v7.util.html" class="hiddenlink" target="rightframe">android.support.v7.util</A><br>
    -+<!-- Package android.support.v7.widget -->
    -+<A HREF="pkg_android.support.v7.widget.html" class="hiddenlink" target="rightframe">android.support.v7.widget</A><br>
    -+<!-- Package android.support.v8.renderscript -->
    -+<A HREF="changes-summary.html#android.support.v8.renderscript" class="hiddenlink" target="rightframe"><strike>android.support.v8.renderscript</strike></A><br>
    -+<!-- Class AppBarLayout.ScrollingViewBehavior -->
    -+<A HREF="android.support.design.widget.AppBarLayout.ScrollingViewBehavior.html" class="hiddenlink" target="rightframe">AppBarLayout.ScrollingViewBehavior</A><br>
    -+<!-- Class AppCompatActivity -->
    -+<A HREF="pkg_android.support.v7.app.html#AppCompatActivity" class="hiddenlink" target="rightframe"><b>AppCompatActivity</b></A><br>
    -+<!-- Class AppCompatAutoCompleteTextView -->
    -+<A HREF="pkg_android.support.v7.widget.html#AppCompatAutoCompleteTextView" class="hiddenlink" target="rightframe"><b>AppCompatAutoCompleteTextView</b></A><br>
    -+<!-- Class AppCompatButton -->
    -+<A HREF="pkg_android.support.v7.widget.html#AppCompatButton" class="hiddenlink" target="rightframe"><b>AppCompatButton</b></A><br>
    -+<!-- Class AppCompatCheckBox -->
    -+<A HREF="pkg_android.support.v7.widget.html#AppCompatCheckBox" class="hiddenlink" target="rightframe"><b>AppCompatCheckBox</b></A><br>
    -+<!-- Class AppCompatCheckedTextView -->
    -+<A HREF="pkg_android.support.v7.widget.html#AppCompatCheckedTextView" class="hiddenlink" target="rightframe"><b>AppCompatCheckedTextView</b></A><br>
    -+<!-- Class AppCompatDelegate -->
    -+<A HREF="android.support.v7.app.AppCompatDelegate.html" class="hiddenlink" target="rightframe">AppCompatDelegate</A><br>
    -+<!-- Class AppCompatDialogFragment -->
    -+<A HREF="pkg_android.support.v7.app.html#AppCompatDialogFragment" class="hiddenlink" target="rightframe"><b>AppCompatDialogFragment</b></A><br>
    -+<!-- Class AppCompatEditText -->
    -+<A HREF="pkg_android.support.v7.widget.html#AppCompatEditText" class="hiddenlink" target="rightframe"><b>AppCompatEditText</b></A><br>
    -+<!-- Class AppCompatImageButton -->
    -+<A HREF="pkg_android.support.v7.widget.html#AppCompatImageButton" class="hiddenlink" target="rightframe"><b>AppCompatImageButton</b></A><br>
    -+<!-- Class AppCompatImageView -->
    -+<A HREF="pkg_android.support.v7.widget.html#AppCompatImageView" class="hiddenlink" target="rightframe"><b>AppCompatImageView</b></A><br>
    -+<!-- Class AppCompatMultiAutoCompleteTextView -->
    -+<A HREF="pkg_android.support.v7.widget.html#AppCompatMultiAutoCompleteTextView" class="hiddenlink" target="rightframe"><b>AppCompatMultiAutoCompleteTextView</b></A><br>
    -+<!-- Class AppCompatRadioButton -->
    -+<A HREF="pkg_android.support.v7.widget.html#AppCompatRadioButton" class="hiddenlink" target="rightframe"><b>AppCompatRadioButton</b></A><br>
    -+<!-- Class AppCompatRatingBar -->
    -+<A HREF="pkg_android.support.v7.widget.html#AppCompatRatingBar" class="hiddenlink" target="rightframe"><b>AppCompatRatingBar</b></A><br>
    -+<!-- Class AppCompatResources -->
    -+<A HREF="android.support.v7.content.res.AppCompatResources.html" class="hiddenlink" target="rightframe">AppCompatResources</A><br>
    -+<!-- Class AppCompatSeekBar -->
    -+<A HREF="pkg_android.support.v7.widget.html#AppCompatSeekBar" class="hiddenlink" target="rightframe"><b>AppCompatSeekBar</b></A><br>
    -+<!-- Class AppCompatSpinner -->
    -+<A HREF="pkg_android.support.v7.widget.html#AppCompatSpinner" class="hiddenlink" target="rightframe"><b>AppCompatSpinner</b></A><br>
    -+<!-- Class AppCompatTextView -->
    -+<A HREF="pkg_android.support.v7.widget.html#AppCompatTextView" class="hiddenlink" target="rightframe"><b>AppCompatTextView</b></A><br>
    -+<!-- Class BatchingListUpdateCallback -->
    -+<A NAME="B"></A>
    -+<br><font size="+2">B</font>&nbsp;
    -+<a href="#A"><font size="-2">A</font></a> 
    -+<a href="#C"><font size="-2">C</font></a> 
    -+<a href="#D"><font size="-2">D</font></a> 
    -+<a href="#E"><font size="-2">E</font></a> 
    -+<a href="#F"><font size="-2">F</font></a> 
    -+<a href="#G"><font size="-2">G</font></a> 
    -+<a href="#H"><font size="-2">H</font></a> 
    -+<a href="#I"><font size="-2">I</font></a> 
    -+<a href="#K"><font size="-2">K</font></a> 
    -+<a href="#L"><font size="-2">L</font></a> 
    -+<a href="#M"><font size="-2">M</font></a> 
    -+<a href="#N"><font size="-2">N</font></a> 
    -+<a href="#O"><font size="-2">O</font></a> 
    -+<a href="#P"><font size="-2">P</font></a> 
    -+<a href="#R"><font size="-2">R</font></a> 
    -+<a href="#S"><font size="-2">S</font></a> 
    -+<a href="#T"><font size="-2">T</font></a> 
    -+<a href="#V"><font size="-2">V</font></a> 
    -+<a href="#W"><font size="-2">W</font></a> 
    -+ <a href="#topheader"><font size="-2">TOP</font></a>
    -+<p><div style="line-height:1.5em;color:black">
    -+<A HREF="pkg_android.support.v7.util.html#BatchingListUpdateCallback" class="hiddenlink" target="rightframe"><b>BatchingListUpdateCallback</b></A><br>
    -+<!-- Class BottomSheetBehavior -->
    -+<A HREF="android.support.design.widget.BottomSheetBehavior.html" class="hiddenlink" target="rightframe">BottomSheetBehavior</A><br>
    -+<!-- Field BT_FOLDER_TYPE_ALBUMS -->
    -+<nobr><A HREF="android.support.v4.media.MediaDescriptionCompat.html#android.support.v4.media.MediaDescriptionCompat.BT_FOLDER_TYPE_ALBUMS" class="hiddenlink" target="rightframe">BT_FOLDER_TYPE_ALBUMS</A>
    -+</nobr><br>
    -+<!-- Field BT_FOLDER_TYPE_ARTISTS -->
    -+<nobr><A HREF="android.support.v4.media.MediaDescriptionCompat.html#android.support.v4.media.MediaDescriptionCompat.BT_FOLDER_TYPE_ARTISTS" class="hiddenlink" target="rightframe">BT_FOLDER_TYPE_ARTISTS</A>
    -+</nobr><br>
    -+<!-- Field BT_FOLDER_TYPE_GENRES -->
    -+<nobr><A HREF="android.support.v4.media.MediaDescriptionCompat.html#android.support.v4.media.MediaDescriptionCompat.BT_FOLDER_TYPE_GENRES" class="hiddenlink" target="rightframe">BT_FOLDER_TYPE_GENRES</A>
    -+</nobr><br>
    -+<!-- Field BT_FOLDER_TYPE_MIXED -->
    -+<nobr><A HREF="android.support.v4.media.MediaDescriptionCompat.html#android.support.v4.media.MediaDescriptionCompat.BT_FOLDER_TYPE_MIXED" class="hiddenlink" target="rightframe">BT_FOLDER_TYPE_MIXED</A>
    -+</nobr><br>
    -+<!-- Field BT_FOLDER_TYPE_PLAYLISTS -->
    -+<nobr><A HREF="android.support.v4.media.MediaDescriptionCompat.html#android.support.v4.media.MediaDescriptionCompat.BT_FOLDER_TYPE_PLAYLISTS" class="hiddenlink" target="rightframe">BT_FOLDER_TYPE_PLAYLISTS</A>
    -+</nobr><br>
    -+<!-- Field BT_FOLDER_TYPE_TITLES -->
    -+<nobr><A HREF="android.support.v4.media.MediaDescriptionCompat.html#android.support.v4.media.MediaDescriptionCompat.BT_FOLDER_TYPE_TITLES" class="hiddenlink" target="rightframe">BT_FOLDER_TYPE_TITLES</A>
    -+</nobr><br>
    -+<!-- Field BT_FOLDER_TYPE_YEARS -->
    -+<nobr><A HREF="android.support.v4.media.MediaDescriptionCompat.html#android.support.v4.media.MediaDescriptionCompat.BT_FOLDER_TYPE_YEARS" class="hiddenlink" target="rightframe">BT_FOLDER_TYPE_YEARS</A>
    -+</nobr><br>
    -+<!-- Class BuildCompat -->
    -+<A HREF="android.support.v4.os.BuildCompat.html" class="hiddenlink" target="rightframe">BuildCompat</A><br>
    -+<!-- Method buildMediaButtonPendingIntent -->
    -+<i>buildMediaButtonPendingIntent</i><br>
    -+&nbsp;&nbsp;<nobr><A HREF="android.support.v4.media.session.MediaButtonReceiver.html#android.support.v4.media.session.MediaButtonReceiver.buildMediaButtonPendingIntent_added(android.content.Context, android.content.ComponentName, long)" class="hiddenlink" target="rightframe">type&nbsp;<b>
    -+(<code>Context, ComponentName, long</code>)</b>&nbsp;in&nbsp;android.support.v4.media.session.MediaButtonReceiver
    -+</A></nobr><br>
    -+<!-- Method buildMediaButtonPendingIntent -->
    -+&nbsp;&nbsp;<nobr><A HREF="android.support.v4.media.session.MediaButtonReceiver.html#android.support.v4.media.session.MediaButtonReceiver.buildMediaButtonPendingIntent_added(android.content.Context, long)" class="hiddenlink" target="rightframe">type&nbsp;<b>
    -+(<code>Context, long</code>)</b>&nbsp;in&nbsp;android.support.v4.media.session.MediaButtonReceiver
    -+</A></nobr><br>
    -+<!-- Class CardView -->
    -+<A NAME="C"></A>
    -+<br><font size="+2">C</font>&nbsp;
    -+<a href="#A"><font size="-2">A</font></a> 
    -+<a href="#B"><font size="-2">B</font></a> 
    -+<a href="#D"><font size="-2">D</font></a> 
    -+<a href="#E"><font size="-2">E</font></a> 
    -+<a href="#F"><font size="-2">F</font></a> 
    -+<a href="#G"><font size="-2">G</font></a> 
    -+<a href="#H"><font size="-2">H</font></a> 
    -+<a href="#I"><font size="-2">I</font></a> 
    -+<a href="#K"><font size="-2">K</font></a> 
    -+<a href="#L"><font size="-2">L</font></a> 
    -+<a href="#M"><font size="-2">M</font></a> 
    -+<a href="#N"><font size="-2">N</font></a> 
    -+<a href="#O"><font size="-2">O</font></a> 
    -+<a href="#P"><font size="-2">P</font></a> 
    -+<a href="#R"><font size="-2">R</font></a> 
    -+<a href="#S"><font size="-2">S</font></a> 
    -+<a href="#T"><font size="-2">T</font></a> 
    -+<a href="#V"><font size="-2">V</font></a> 
    -+<a href="#W"><font size="-2">W</font></a> 
    -+ <a href="#topheader"><font size="-2">TOP</font></a>
    -+<p><div style="line-height:1.5em;color:black">
    -+<A HREF="pkg_android.support.v7.widget.html#CardView" class="hiddenlink" target="rightframe"><b>CardView</b></A><br>
    -+<!-- Method clearColorFilter -->
    -+<nobr><A HREF="android.support.v4.graphics.drawable.DrawableCompat.html#android.support.v4.graphics.drawable.DrawableCompat.clearColorFilter_added(android.graphics.drawable.Drawable)" class="hiddenlink" target="rightframe"><b>clearColorFilter</b>
    -+(<code>Drawable</code>)</A></nobr><br>
    -+<!-- Method clearOnTabSelectedListeners -->
    -+<nobr><A HREF="android.support.design.widget.TabLayout.html#android.support.design.widget.TabLayout.clearOnTabSelectedListeners_added()" class="hiddenlink" target="rightframe"><b>clearOnTabSelectedListeners</b>
    -+()</A></nobr><br>
    -+<!-- Class CollapsingToolbarLayout -->
    -+<A HREF="android.support.design.widget.CollapsingToolbarLayout.html" class="hiddenlink" target="rightframe">CollapsingToolbarLayout</A><br>
    -+<!-- Method computeScrollVectorForPosition -->
    -+<i>computeScrollVectorForPosition</i><br>
    -+&nbsp;&nbsp;<nobr><A HREF="android.support.v7.widget.LinearSmoothScroller.html#android.support.v7.widget.LinearSmoothScroller.computeScrollVectorForPosition_changed(int)" class="hiddenlink" target="rightframe">type&nbsp;
    -+(<code>int</code>)&nbsp;in&nbsp;android.support.v7.widget.LinearSmoothScroller
    -+</A></nobr><br>
    -+<!-- Method computeScrollVectorForPosition -->
    -+&nbsp;&nbsp;<nobr><A HREF="android.support.v7.widget.StaggeredGridLayoutManager.html#android.support.v7.widget.StaggeredGridLayoutManager.computeScrollVectorForPosition_added(int)" class="hiddenlink" target="rightframe">type&nbsp;<b>
    -+(<code>int</code>)</b>&nbsp;in&nbsp;android.support.v7.widget.StaggeredGridLayoutManager
    -+</A></nobr><br>
    -+<!-- Class ContextCompat -->
    -+<i>ContextCompat</i><br>
    -+&nbsp;&nbsp;<A HREF="android.support.v4.content.ContextCompat.html" class="hiddenlink" target="rightframe">android.support.v4.content</A><br>
    -+<!-- Constructor ContextCompat -->
    -+&nbsp;&nbsp;<nobr><A HREF="android.support.v4.content.ContextCompat.html#android.support.v4.content.ContextCompat.ctor_changed()" class="hiddenlink" target="rightframe">ContextCompat
    -+()</A></nobr>&nbsp;constructor<br>
    -+<!-- Class CoordinatorLayout -->
    -+<A HREF="android.support.design.widget.CoordinatorLayout.html" class="hiddenlink" target="rightframe">CoordinatorLayout</A><br>
    -+<!-- Class CoordinatorLayout.Behavior -->
    -+<A HREF="android.support.design.widget.CoordinatorLayout.Behavior.html" class="hiddenlink" target="rightframe">CoordinatorLayout.Behavior</A><br>
    -+<!-- Class CoordinatorLayout.LayoutParams -->
    -+<A HREF="android.support.design.widget.CoordinatorLayout.LayoutParams.html" class="hiddenlink" target="rightframe">CoordinatorLayout.LayoutParams</A><br>
    -+<!-- Class CustomTabsIntent -->
    -+<A HREF="android.support.customtabs.CustomTabsIntent.html" class="hiddenlink" target="rightframe">CustomTabsIntent</A><br>
    -+<!-- Class CustomTabsIntent.Builder -->
    -+<A HREF="android.support.customtabs.CustomTabsIntent.Builder.html" class="hiddenlink" target="rightframe">CustomTabsIntent.Builder</A><br>
    -+<!-- Class CustomTabsSession -->
    -+<A HREF="android.support.customtabs.CustomTabsSession.html" class="hiddenlink" target="rightframe">CustomTabsSession</A><br>
    -+<!-- Class DiffUtil -->
    -+<A NAME="D"></A>
    -+<br><font size="+2">D</font>&nbsp;
    -+<a href="#A"><font size="-2">A</font></a> 
    -+<a href="#B"><font size="-2">B</font></a> 
    -+<a href="#C"><font size="-2">C</font></a> 
    -+<a href="#E"><font size="-2">E</font></a> 
    -+<a href="#F"><font size="-2">F</font></a> 
    -+<a href="#G"><font size="-2">G</font></a> 
    -+<a href="#H"><font size="-2">H</font></a> 
    -+<a href="#I"><font size="-2">I</font></a> 
    -+<a href="#K"><font size="-2">K</font></a> 
    -+<a href="#L"><font size="-2">L</font></a> 
    -+<a href="#M"><font size="-2">M</font></a> 
    -+<a href="#N"><font size="-2">N</font></a> 
    -+<a href="#O"><font size="-2">O</font></a> 
    -+<a href="#P"><font size="-2">P</font></a> 
    -+<a href="#R"><font size="-2">R</font></a> 
    -+<a href="#S"><font size="-2">S</font></a> 
    -+<a href="#T"><font size="-2">T</font></a> 
    -+<a href="#V"><font size="-2">V</font></a> 
    -+<a href="#W"><font size="-2">W</font></a> 
    -+ <a href="#topheader"><font size="-2">TOP</font></a>
    -+<p><div style="line-height:1.5em;color:black">
    -+<A HREF="pkg_android.support.v7.util.html#DiffUtil" class="hiddenlink" target="rightframe"><b>DiffUtil</b></A><br>
    -+<!-- Class DiffUtil.Callback -->
    -+<A HREF="pkg_android.support.v7.util.html#DiffUtil.Callback" class="hiddenlink" target="rightframe"><b>DiffUtil.Callback</b></A><br>
    -+<!-- Class DiffUtil.DiffResult -->
    -+<A HREF="pkg_android.support.v7.util.html#DiffUtil.DiffResult" class="hiddenlink" target="rightframe"><b>DiffUtil.DiffResult</b></A><br>
    -+<!-- Method dispatch -->
    -+<nobr><A HREF="android.support.v4.view.KeyEventCompat.html#android.support.v4.view.KeyEventCompat.dispatch_changed(android.view.KeyEvent, android.view.KeyEvent.Callback, java.lang.Object, java.lang.Object)" class="hiddenlink" target="rightframe">dispatch
    -+(<code>KeyEvent, Callback, Object, Object</code>)</A></nobr><br>
    -+<!-- Field dodgeInsetEdges -->
    -+<nobr><A HREF="android.support.design.widget.CoordinatorLayout.LayoutParams.html#android.support.design.widget.CoordinatorLayout.LayoutParams.dodgeInsetEdges" class="hiddenlink" target="rightframe">dodgeInsetEdges</A>
    -+</nobr><br>
    -+<!-- Class DrawableCompat -->
    -+<A HREF="android.support.v4.graphics.drawable.DrawableCompat.html" class="hiddenlink" target="rightframe">DrawableCompat</A><br>
    -+<!-- Field EXTRA_BT_FOLDER_TYPE -->
    -+<A NAME="E"></A>
    -+<br><font size="+2">E</font>&nbsp;
    -+<a href="#A"><font size="-2">A</font></a> 
    -+<a href="#B"><font size="-2">B</font></a> 
    -+<a href="#C"><font size="-2">C</font></a> 
    -+<a href="#D"><font size="-2">D</font></a> 
    -+<a href="#F"><font size="-2">F</font></a> 
    -+<a href="#G"><font size="-2">G</font></a> 
    -+<a href="#H"><font size="-2">H</font></a> 
    -+<a href="#I"><font size="-2">I</font></a> 
    -+<a href="#K"><font size="-2">K</font></a> 
    -+<a href="#L"><font size="-2">L</font></a> 
    -+<a href="#M"><font size="-2">M</font></a> 
    -+<a href="#N"><font size="-2">N</font></a> 
    -+<a href="#O"><font size="-2">O</font></a> 
    -+<a href="#P"><font size="-2">P</font></a> 
    -+<a href="#R"><font size="-2">R</font></a> 
    -+<a href="#S"><font size="-2">S</font></a> 
    -+<a href="#T"><font size="-2">T</font></a> 
    -+<a href="#V"><font size="-2">V</font></a> 
    -+<a href="#W"><font size="-2">W</font></a> 
    -+ <a href="#topheader"><font size="-2">TOP</font></a>
    -+<p><div style="line-height:1.5em;color:black">
    -+<nobr><A HREF="android.support.v4.media.MediaDescriptionCompat.html#android.support.v4.media.MediaDescriptionCompat.EXTRA_BT_FOLDER_TYPE" class="hiddenlink" target="rightframe">EXTRA_BT_FOLDER_TYPE</A>
    -+</nobr><br>
    -+<!-- Field EXTRA_ENABLE_INSTANT_APPS -->
    -+<nobr><A HREF="android.support.customtabs.CustomTabsIntent.html#android.support.customtabs.CustomTabsIntent.EXTRA_ENABLE_INSTANT_APPS" class="hiddenlink" target="rightframe">EXTRA_ENABLE_INSTANT_APPS</A>
    -+</nobr><br>
    -+<!-- Field EXTRA_SUGGESTION_KEYWORDS -->
    -+<nobr><A HREF="android.support.v4.media.MediaBrowserServiceCompat.BrowserRoot.html#android.support.v4.media.MediaBrowserServiceCompat.BrowserRoot.EXTRA_SUGGESTION_KEYWORDS" class="hiddenlink" target="rightframe">EXTRA_SUGGESTION_KEYWORDS</A>
    -+</nobr><br>
    -+<!-- Field EXTRA_USAGE_TIME_REPORT -->
    -+<nobr><A HREF="android.support.v4.app.ActivityOptionsCompat.html#android.support.v4.app.ActivityOptionsCompat.EXTRA_USAGE_TIME_REPORT" class="hiddenlink" target="rightframe">EXTRA_USAGE_TIME_REPORT</A>
    -+</nobr><br>
    -+<!-- Field EXTRA_USAGE_TIME_REPORT_PACKAGES -->
    -+<nobr><A HREF="android.support.v4.app.ActivityOptionsCompat.html#android.support.v4.app.ActivityOptionsCompat.EXTRA_USAGE_TIME_REPORT_PACKAGES" class="hiddenlink" target="rightframe">EXTRA_USAGE_TIME_REPORT_PACKAGES</A>
    -+</nobr><br>
    -+<!-- Method findFragmentByWho -->
    -+<A NAME="F"></A>
    -+<br><font size="+2">F</font>&nbsp;
    -+<a href="#A"><font size="-2">A</font></a> 
    -+<a href="#B"><font size="-2">B</font></a> 
    -+<a href="#C"><font size="-2">C</font></a> 
    -+<a href="#D"><font size="-2">D</font></a> 
    -+<a href="#E"><font size="-2">E</font></a> 
    -+<a href="#G"><font size="-2">G</font></a> 
    -+<a href="#H"><font size="-2">H</font></a> 
    -+<a href="#I"><font size="-2">I</font></a> 
    -+<a href="#K"><font size="-2">K</font></a> 
    -+<a href="#L"><font size="-2">L</font></a> 
    -+<a href="#M"><font size="-2">M</font></a> 
    -+<a href="#N"><font size="-2">N</font></a> 
    -+<a href="#O"><font size="-2">O</font></a> 
    -+<a href="#P"><font size="-2">P</font></a> 
    -+<a href="#R"><font size="-2">R</font></a> 
    -+<a href="#S"><font size="-2">S</font></a> 
    -+<a href="#T"><font size="-2">T</font></a> 
    -+<a href="#V"><font size="-2">V</font></a> 
    -+<a href="#W"><font size="-2">W</font></a> 
    -+ <a href="#topheader"><font size="-2">TOP</font></a>
    -+<p><div style="line-height:1.5em;color:black">
    -+<nobr><A HREF="android.support.v4.app.FragmentController.html#android.support.v4.app.FragmentController.findFragmentByWho_added(java.lang.String)" class="hiddenlink" target="rightframe"><b>findFragmentByWho</b>
    -+(<code>String</code>)</A></nobr><br>
    -+<!-- Method findPointerIndex -->
    -+<nobr><A HREF="android.support.v4.view.MotionEventCompat.html#android.support.v4.view.MotionEventCompat.findPointerIndex_changed(android.view.MotionEvent, int)" class="hiddenlink" target="rightframe">findPointerIndex
    -+(<code>MotionEvent, int</code>)</A></nobr><br>
    -+<!-- Class FloatingActionButton.Behavior -->
    -+<A HREF="android.support.design.widget.FloatingActionButton.Behavior.html" class="hiddenlink" target="rightframe">FloatingActionButton.Behavior</A><br>
    -+<!-- Class FragmentController -->
    -+<A HREF="android.support.v4.app.FragmentController.html" class="hiddenlink" target="rightframe">FragmentController</A><br>
    -+<!-- Method fromMediaItem -->
    -+<nobr><A HREF="android.support.v4.media.MediaBrowserCompat.MediaItem.html#android.support.v4.media.MediaBrowserCompat.MediaItem.fromMediaItem_added(java.lang.Object)" class="hiddenlink" target="rightframe"><b>fromMediaItem</b>
    -+(<code>Object</code>)</A></nobr><br>
    -+<!-- Method fromMediaItemList -->
    -+<nobr><A HREF="android.support.v4.media.MediaBrowserCompat.MediaItem.html#android.support.v4.media.MediaBrowserCompat.MediaItem.fromMediaItemList_added(java.util.List<?>)" class="hiddenlink" target="rightframe"><b>fromMediaItemList</b>
    -+(<code>List&lt;?&gt;</code>)</A></nobr><br>
    -+<!-- Method fromMediaSession -->
    -+<nobr><A HREF="android.support.v4.media.session.MediaSessionCompat.html#android.support.v4.media.session.MediaSessionCompat.fromMediaSession_added(android.content.Context, java.lang.Object)" class="hiddenlink" target="rightframe"><b>fromMediaSession</b>
    -+(<code>Context, Object</code>)</A></nobr><br>
    -+<!-- Method fromQueueItem -->
    -+<nobr><A HREF="android.support.v4.media.session.MediaSessionCompat.QueueItem.html#android.support.v4.media.session.MediaSessionCompat.QueueItem.fromQueueItem_added(java.lang.Object)" class="hiddenlink" target="rightframe"><b>fromQueueItem</b>
    -+(<code>Object</code>)</A></nobr><br>
    -+<!-- Method fromQueueItemList -->
    -+<nobr><A HREF="android.support.v4.media.session.MediaSessionCompat.QueueItem.html#android.support.v4.media.session.MediaSessionCompat.QueueItem.fromQueueItemList_added(java.util.List<?>)" class="hiddenlink" target="rightframe"><b>fromQueueItemList</b>
    -+(<code>List&lt;?&gt;</code>)</A></nobr><br>
    -+<!-- Method getAction -->
    -+<A NAME="G"></A>
    -+<br><font size="+2">G</font>&nbsp;
    -+<a href="#A"><font size="-2">A</font></a> 
    -+<a href="#B"><font size="-2">B</font></a> 
    -+<a href="#C"><font size="-2">C</font></a> 
    -+<a href="#D"><font size="-2">D</font></a> 
    -+<a href="#E"><font size="-2">E</font></a> 
    -+<a href="#F"><font size="-2">F</font></a> 
    -+<a href="#H"><font size="-2">H</font></a> 
    -+<a href="#I"><font size="-2">I</font></a> 
    -+<a href="#K"><font size="-2">K</font></a> 
    -+<a href="#L"><font size="-2">L</font></a> 
    -+<a href="#M"><font size="-2">M</font></a> 
    -+<a href="#N"><font size="-2">N</font></a> 
    -+<a href="#O"><font size="-2">O</font></a> 
    -+<a href="#P"><font size="-2">P</font></a> 
    -+<a href="#R"><font size="-2">R</font></a> 
    -+<a href="#S"><font size="-2">S</font></a> 
    -+<a href="#T"><font size="-2">T</font></a> 
    -+<a href="#V"><font size="-2">V</font></a> 
    -+<a href="#W"><font size="-2">W</font></a> 
    -+ <a href="#topheader"><font size="-2">TOP</font></a>
    -+<p><div style="line-height:1.5em;color:black">
    -+<nobr><A HREF="android.support.v4.view.accessibility.AccessibilityEventCompat.html#android.support.v4.view.accessibility.AccessibilityEventCompat.getAction_added(android.view.accessibility.AccessibilityEvent)" class="hiddenlink" target="rightframe"><b>getAction</b>
    -+(<code>AccessibilityEvent</code>)</A></nobr><br>
    -+<!-- Method getCompoundDrawablesRelative -->
    -+<nobr><A HREF="android.support.v4.widget.TextViewCompat.html#android.support.v4.widget.TextViewCompat.getCompoundDrawablesRelative_added(android.widget.TextView)" class="hiddenlink" target="rightframe"><b>getCompoundDrawablesRelative</b>
    -+(<code>TextView</code>)</A></nobr><br>
    -+<!-- Method getDependents -->
    -+<nobr><A HREF="android.support.design.widget.CoordinatorLayout.html#android.support.design.widget.CoordinatorLayout.getDependents_added(android.view.View)" class="hiddenlink" target="rightframe"><b>getDependents</b>
    -+(<code>View</code>)</A></nobr><br>
    -+<!-- Method getDescription -->
    -+<nobr><A HREF="android.support.v4.accessibilityservice.AccessibilityServiceInfoCompat.html#android.support.v4.accessibilityservice.AccessibilityServiceInfoCompat.getDescription_changed(android.accessibilityservice.AccessibilityServiceInfo)" class="hiddenlink" target="rightframe">getDescription
    -+(<code>AccessibilityServiceInfo</code>)</A></nobr><br>
    -+<!-- Method getDominantColor -->
    -+<nobr><A HREF="android.support.v7.graphics.Palette.html#android.support.v7.graphics.Palette.getDominantColor_added(int)" class="hiddenlink" target="rightframe"><b>getDominantColor</b>
    -+(<code>int</code>)</A></nobr><br>
    -+<!-- Method getDominantSwatch -->
    -+<nobr><A HREF="android.support.v7.graphics.Palette.html#android.support.v7.graphics.Palette.getDominantSwatch_added()" class="hiddenlink" target="rightframe"><b>getDominantSwatch</b>
    -+()</A></nobr><br>
    -+<!-- Method getDrawable -->
    -+<nobr><A HREF="android.support.v7.content.res.AppCompatResources.html#android.support.v7.content.res.AppCompatResources.getDrawable_added(android.content.Context, int)" class="hiddenlink" target="rightframe"><b>getDrawable</b>
    -+(<code>Context, int</code>)</A></nobr><br>
    -+<!-- Method getDrawerArrowDrawable -->
    -+<nobr><A HREF="android.support.v7.app.ActionBarDrawerToggle.html#android.support.v7.app.ActionBarDrawerToggle.getDrawerArrowDrawable_added()" class="hiddenlink" target="rightframe"><b>getDrawerArrowDrawable</b>
    -+()</A></nobr><br>
    -+<!-- Method getInsetDodgeRect -->
    -+<i>getInsetDodgeRect</i><br>
    -+&nbsp;&nbsp;<nobr><A HREF="android.support.design.widget.CoordinatorLayout.Behavior.html#android.support.design.widget.CoordinatorLayout.Behavior.getInsetDodgeRect_added(android.support.design.widget.CoordinatorLayout, V, android.graphics.Rect)" class="hiddenlink" target="rightframe">type&nbsp;<b>
    -+(<code>CoordinatorLayout, V, Rect</code>)</b>&nbsp;in&nbsp;android.support.design.widget.CoordinatorLayout.Behavior
    -+</A></nobr><br>
    -+<!-- Method getInsetDodgeRect -->
    -+&nbsp;&nbsp;<nobr><A HREF="android.support.design.widget.FloatingActionButton.Behavior.html#android.support.design.widget.FloatingActionButton.Behavior.getInsetDodgeRect_added(android.support.design.widget.CoordinatorLayout, android.support.design.widget.FloatingActionButton, android.graphics.Rect)" class="hiddenlink" target="rightframe">type&nbsp;<b>
    -+(<code>CoordinatorLayout, FloatingActionButton, Rect</code>)</b>&nbsp;in&nbsp;android.support.design.widget.FloatingActionButton.Behavior
    -+</A></nobr><br>
    -+<!-- Method getKeyDispatcherState -->
    -+<nobr><A HREF="android.support.v4.view.KeyEventCompat.html#android.support.v4.view.KeyEventCompat.getKeyDispatcherState_changed(android.view.View)" class="hiddenlink" target="rightframe">getKeyDispatcherState
    -+(<code>View</code>)</A></nobr><br>
    -+<!-- Method getLaunchBounds -->
    -+<nobr><A HREF="android.support.v4.app.ActivityOptionsCompat.html#android.support.v4.app.ActivityOptionsCompat.getLaunchBounds_added()" class="hiddenlink" target="rightframe"><b>getLaunchBounds</b>
    -+()</A></nobr><br>
    -+<!-- Method getMediaItemNumberViewFlipper -->
    -+<nobr><A HREF="android.support.v17.leanback.widget.AbstractMediaItemPresenter.ViewHolder.html#android.support.v17.leanback.widget.AbstractMediaItemPresenter.ViewHolder.getMediaItemNumberViewFlipper_added()" class="hiddenlink" target="rightframe"><b>getMediaItemNumberViewFlipper</b>
    -+()</A></nobr><br>
    -+<!-- Method getMediaItemPausedView -->
    -+<nobr><A HREF="android.support.v17.leanback.widget.AbstractMediaItemPresenter.ViewHolder.html#android.support.v17.leanback.widget.AbstractMediaItemPresenter.ViewHolder.getMediaItemPausedView_added()" class="hiddenlink" target="rightframe"><b>getMediaItemPausedView</b>
    -+()</A></nobr><br>
    -+<!-- Method getMediaItemPlayingView -->
    -+<nobr><A HREF="android.support.v17.leanback.widget.AbstractMediaItemPresenter.ViewHolder.html#android.support.v17.leanback.widget.AbstractMediaItemPresenter.ViewHolder.getMediaItemPlayingView_added()" class="hiddenlink" target="rightframe"><b>getMediaItemPlayingView</b>
    -+()</A></nobr><br>
    -+<!-- Method getMediaPlayState -->
    -+<nobr><A HREF="android.support.v17.leanback.widget.AbstractMediaItemPresenter.html#android.support.v17.leanback.widget.AbstractMediaItemPresenter.getMediaPlayState_added(java.lang.Object)" class="hiddenlink" target="rightframe"><b>getMediaPlayState</b>
    -+(<code>Object</code>)</A></nobr><br>
    -+<!-- Method getMovementGranularity -->
    -+<nobr><A HREF="android.support.v4.view.accessibility.AccessibilityEventCompat.html#android.support.v4.view.accessibility.AccessibilityEventCompat.getMovementGranularity_added(android.view.accessibility.AccessibilityEvent)" class="hiddenlink" target="rightframe"><b>getMovementGranularity</b>
    -+(<code>AccessibilityEvent</code>)</A></nobr><br>
    -+<!-- Method getOnFlingListener -->
    -+<nobr><A HREF="android.support.v7.widget.RecyclerView.html#android.support.v7.widget.RecyclerView.getOnFlingListener_added()" class="hiddenlink" target="rightframe"><b>getOnFlingListener</b>
    -+()</A></nobr><br>
    -+<!-- Method getOverScrollMode -->
    -+<nobr><A HREF="android.support.v4.view.ViewCompat.html#android.support.v4.view.ViewCompat.getOverScrollMode_changed(android.view.View)" class="hiddenlink" target="rightframe">getOverScrollMode
    -+(<code>View</code>)</A></nobr><br>
    -+<!-- Method getPasswordVisibilityToggleContentDescription -->
    -+<nobr><A HREF="android.support.design.widget.TextInputLayout.html#android.support.design.widget.TextInputLayout.getPasswordVisibilityToggleContentDescription_added()" class="hiddenlink" target="rightframe"><b>getPasswordVisibilityToggleContentDescription</b>
    -+()</A></nobr><br>
    -+<!-- Method getPasswordVisibilityToggleDrawable -->
    -+<nobr><A HREF="android.support.design.widget.TextInputLayout.html#android.support.design.widget.TextInputLayout.getPasswordVisibilityToggleDrawable_added()" class="hiddenlink" target="rightframe"><b>getPasswordVisibilityToggleDrawable</b>
    -+()</A></nobr><br>
    -+<!-- Method getPointerCount -->
    -+<nobr><A HREF="android.support.v4.view.MotionEventCompat.html#android.support.v4.view.MotionEventCompat.getPointerCount_changed(android.view.MotionEvent)" class="hiddenlink" target="rightframe">getPointerCount
    -+(<code>MotionEvent</code>)</A></nobr><br>
    -+<!-- Method getPointerId -->
    -+<nobr><A HREF="android.support.v4.view.MotionEventCompat.html#android.support.v4.view.MotionEventCompat.getPointerId_changed(android.view.MotionEvent, int)" class="hiddenlink" target="rightframe">getPointerId
    -+(<code>MotionEvent, int</code>)</A></nobr><br>
    -+<!-- Method getReferrer -->
    -+<nobr><A HREF="android.support.v4.app.ActivityCompat.html#android.support.v4.app.ActivityCompat.getReferrer_changed(android.app.Activity)" class="hiddenlink" target="rightframe">getReferrer
    -+(<code>Activity</code>)</A></nobr><br>
    -+<!-- Method getScaledPagingTouchSlop -->
    -+<nobr><A HREF="android.support.v4.view.ViewConfigurationCompat.html#android.support.v4.view.ViewConfigurationCompat.getScaledPagingTouchSlop_changed(android.view.ViewConfiguration)" class="hiddenlink" target="rightframe">getScaledPagingTouchSlop
    -+(<code>ViewConfiguration</code>)</A></nobr><br>
    -+<!-- Method getSelectionMode -->
    -+<nobr><A HREF="android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.CollectionInfoCompat.html#android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.CollectionInfoCompat.getSelectionMode_added()" class="hiddenlink" target="rightframe"><b>getSelectionMode</b>
    -+()</A></nobr><br>
    -+<!-- Method getSource -->
    -+<nobr><A HREF="android.support.v4.view.MotionEventCompat.html#android.support.v4.view.MotionEventCompat.getSource_changed(android.view.MotionEvent)" class="hiddenlink" target="rightframe">getSource
    -+(<code>MotionEvent</code>)</A></nobr><br>
    -+<!-- Method getX -->
    -+<nobr><A HREF="android.support.v4.view.MotionEventCompat.html#android.support.v4.view.MotionEventCompat.getX_changed(android.view.MotionEvent, int)" class="hiddenlink" target="rightframe">getX
    -+(<code>MotionEvent, int</code>)</A></nobr><br>
    -+<!-- Method getY -->
    -+<nobr><A HREF="android.support.v4.view.MotionEventCompat.html#android.support.v4.view.MotionEventCompat.getY_changed(android.view.MotionEvent, int)" class="hiddenlink" target="rightframe">getY
    -+(<code>MotionEvent, int</code>)</A></nobr><br>
    -+<!-- Class GridLayout -->
    -+<A HREF="pkg_android.support.v7.widget.html#GridLayout" class="hiddenlink" target="rightframe"><b>GridLayout</b></A><br>
    -+<!-- Class GridLayout.Alignment -->
    -+<A HREF="pkg_android.support.v7.widget.html#GridLayout.Alignment" class="hiddenlink" target="rightframe"><b>GridLayout.Alignment</b></A><br>
    -+<!-- Class GridLayout.LayoutParams -->
    -+<A HREF="pkg_android.support.v7.widget.html#GridLayout.LayoutParams" class="hiddenlink" target="rightframe"><b>GridLayout.LayoutParams</b></A><br>
    -+<!-- Class GridLayout.Spec -->
    -+<A HREF="pkg_android.support.v7.widget.html#GridLayout.Spec" class="hiddenlink" target="rightframe"><b>GridLayout.Spec</b></A><br>
    -+<!-- Field HOST_VIEW_ID -->
    -+<A NAME="H"></A>
    -+<br><font size="+2">H</font>&nbsp;
    -+<a href="#A"><font size="-2">A</font></a> 
    -+<a href="#B"><font size="-2">B</font></a> 
    -+<a href="#C"><font size="-2">C</font></a> 
    -+<a href="#D"><font size="-2">D</font></a> 
    -+<a href="#E"><font size="-2">E</font></a> 
    -+<a href="#F"><font size="-2">F</font></a> 
    -+<a href="#G"><font size="-2">G</font></a> 
    -+<a href="#I"><font size="-2">I</font></a> 
    -+<a href="#K"><font size="-2">K</font></a> 
    -+<a href="#L"><font size="-2">L</font></a> 
    -+<a href="#M"><font size="-2">M</font></a> 
    -+<a href="#N"><font size="-2">N</font></a> 
    -+<a href="#O"><font size="-2">O</font></a> 
    -+<a href="#P"><font size="-2">P</font></a> 
    -+<a href="#R"><font size="-2">R</font></a> 
    -+<a href="#S"><font size="-2">S</font></a> 
    -+<a href="#T"><font size="-2">T</font></a> 
    -+<a href="#V"><font size="-2">V</font></a> 
    -+<a href="#W"><font size="-2">W</font></a> 
    -+ <a href="#topheader"><font size="-2">TOP</font></a>
    -+<p><div style="line-height:1.5em;color:black">
    -+<nobr><A HREF="android.support.v4.view.accessibility.AccessibilityNodeProviderCompat.html#android.support.v4.view.accessibility.AccessibilityNodeProviderCompat.HOST_VIEW_ID" class="hiddenlink" target="rightframe">HOST_VIEW_ID</A>
    -+</nobr><br>
    -+<!-- Field insetEdge -->
    -+<A NAME="I"></A>
    -+<br><font size="+2">I</font>&nbsp;
    -+<a href="#A"><font size="-2">A</font></a> 
    -+<a href="#B"><font size="-2">B</font></a> 
    -+<a href="#C"><font size="-2">C</font></a> 
    -+<a href="#D"><font size="-2">D</font></a> 
    -+<a href="#E"><font size="-2">E</font></a> 
    -+<a href="#F"><font size="-2">F</font></a> 
    -+<a href="#G"><font size="-2">G</font></a> 
    -+<a href="#H"><font size="-2">H</font></a> 
    -+<a href="#K"><font size="-2">K</font></a> 
    -+<a href="#L"><font size="-2">L</font></a> 
    -+<a href="#M"><font size="-2">M</font></a> 
    -+<a href="#N"><font size="-2">N</font></a> 
    -+<a href="#O"><font size="-2">O</font></a> 
    -+<a href="#P"><font size="-2">P</font></a> 
    -+<a href="#R"><font size="-2">R</font></a> 
    -+<a href="#S"><font size="-2">S</font></a> 
    -+<a href="#T"><font size="-2">T</font></a> 
    -+<a href="#V"><font size="-2">V</font></a> 
    -+<a href="#W"><font size="-2">W</font></a> 
    -+ <a href="#topheader"><font size="-2">TOP</font></a>
    -+<p><div style="line-height:1.5em;color:black">
    -+<nobr><A HREF="android.support.design.widget.CoordinatorLayout.LayoutParams.html#android.support.design.widget.CoordinatorLayout.LayoutParams.insetEdge" class="hiddenlink" target="rightframe">insetEdge</A>
    -+</nobr><br>
    -+<!-- Method isAtLeastNMR1 -->
    -+<nobr><A HREF="android.support.v4.os.BuildCompat.html#android.support.v4.os.BuildCompat.isAtLeastNMR1_added()" class="hiddenlink" target="rightframe"><b>isAtLeastNMR1</b>
    -+()</A></nobr><br>
    -+<!-- Method isAutoHideEnabled -->
    -+<nobr><A HREF="android.support.design.widget.FloatingActionButton.Behavior.html#android.support.design.widget.FloatingActionButton.Behavior.isAutoHideEnabled_added()" class="hiddenlink" target="rightframe"><b>isAutoHideEnabled</b>
    -+()</A></nobr><br>
    -+<!-- Method isContextClickable -->
    -+<nobr><A HREF="android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.html#android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.isContextClickable_added()" class="hiddenlink" target="rightframe"><b>isContextClickable</b>
    -+()</A></nobr><br>
    -+<!-- Method isDirty -->
    -+<nobr><A HREF="android.support.design.widget.CoordinatorLayout.Behavior.html#android.support.design.widget.CoordinatorLayout.Behavior.isDirty_changed(android.support.design.widget.CoordinatorLayout, V)" class="hiddenlink" target="rightframe">isDirty
    -+(<code>CoordinatorLayout, V</code>)</A></nobr><br>
    -+<!-- Method isImmediateNotifySupported -->
    -+<nobr><A HREF="android.support.v17.leanback.widget.ObjectAdapter.html#android.support.v17.leanback.widget.ObjectAdapter.isImmediateNotifySupported_added()" class="hiddenlink" target="rightframe"><b>isImmediateNotifySupported</b>
    -+()</A></nobr><br>
    -+<!-- Method isImportantForAccessibility -->
    -+<nobr><A HREF="android.support.v4.view.ViewCompat.html#android.support.v4.view.ViewCompat.isImportantForAccessibility_added(android.view.View)" class="hiddenlink" target="rightframe"><b>isImportantForAccessibility</b>
    -+(<code>View</code>)</A></nobr><br>
    -+<!-- Method isOpaque -->
    -+<nobr><A HREF="android.support.v4.view.ViewCompat.html#android.support.v4.view.ViewCompat.isOpaque_changed(android.view.View)" class="hiddenlink" target="rightframe">isOpaque
    -+(<code>View</code>)</A></nobr><br>
    -+<!-- Method isPasswordVisibilityToggleEnabled -->
    -+<nobr><A HREF="android.support.design.widget.TextInputLayout.html#android.support.design.widget.TextInputLayout.isPasswordVisibilityToggleEnabled_added()" class="hiddenlink" target="rightframe"><b>isPasswordVisibilityToggleEnabled</b>
    -+()</A></nobr><br>
    -+<!-- Method isTracking -->
    -+<nobr><A HREF="android.support.v4.view.KeyEventCompat.html#android.support.v4.view.KeyEventCompat.isTracking_changed(android.view.KeyEvent)" class="hiddenlink" target="rightframe">isTracking
    -+(<code>KeyEvent</code>)</A></nobr><br>
    -+<!-- Class KeyEventCompat -->
    -+<A NAME="K"></A>
    -+<br><font size="+2">K</font>&nbsp;
    -+<a href="#A"><font size="-2">A</font></a> 
    -+<a href="#B"><font size="-2">B</font></a> 
    -+<a href="#C"><font size="-2">C</font></a> 
    -+<a href="#D"><font size="-2">D</font></a> 
    -+<a href="#E"><font size="-2">E</font></a> 
    -+<a href="#F"><font size="-2">F</font></a> 
    -+<a href="#G"><font size="-2">G</font></a> 
    -+<a href="#H"><font size="-2">H</font></a> 
    -+<a href="#I"><font size="-2">I</font></a> 
    -+<a href="#L"><font size="-2">L</font></a> 
    -+<a href="#M"><font size="-2">M</font></a> 
    -+<a href="#N"><font size="-2">N</font></a> 
    -+<a href="#O"><font size="-2">O</font></a> 
    -+<a href="#P"><font size="-2">P</font></a> 
    -+<a href="#R"><font size="-2">R</font></a> 
    -+<a href="#S"><font size="-2">S</font></a> 
    -+<a href="#T"><font size="-2">T</font></a> 
    -+<a href="#V"><font size="-2">V</font></a> 
    -+<a href="#W"><font size="-2">W</font></a> 
    -+ <a href="#topheader"><font size="-2">TOP</font></a>
    -+<p><div style="line-height:1.5em;color:black">
    -+<A HREF="android.support.v4.view.KeyEventCompat.html" class="hiddenlink" target="rightframe">KeyEventCompat</A><br>
    -+<!-- Method layoutDependsOn -->
    -+<A NAME="L"></A>
    -+<br><font size="+2">L</font>&nbsp;
    -+<a href="#A"><font size="-2">A</font></a> 
    -+<a href="#B"><font size="-2">B</font></a> 
    -+<a href="#C"><font size="-2">C</font></a> 
    -+<a href="#D"><font size="-2">D</font></a> 
    -+<a href="#E"><font size="-2">E</font></a> 
    -+<a href="#F"><font size="-2">F</font></a> 
    -+<a href="#G"><font size="-2">G</font></a> 
    -+<a href="#H"><font size="-2">H</font></a> 
    -+<a href="#I"><font size="-2">I</font></a> 
    -+<a href="#K"><font size="-2">K</font></a> 
    -+<a href="#M"><font size="-2">M</font></a> 
    -+<a href="#N"><font size="-2">N</font></a> 
    -+<a href="#O"><font size="-2">O</font></a> 
    -+<a href="#P"><font size="-2">P</font></a> 
    -+<a href="#R"><font size="-2">R</font></a> 
    -+<a href="#S"><font size="-2">S</font></a> 
    -+<a href="#T"><font size="-2">T</font></a> 
    -+<a href="#V"><font size="-2">V</font></a> 
    -+<a href="#W"><font size="-2">W</font></a> 
    -+ <a href="#topheader"><font size="-2">TOP</font></a>
    -+<p><div style="line-height:1.5em;color:black">
    -+<nobr><A HREF="android.support.design.widget.FloatingActionButton.Behavior.html#android.support.design.widget.FloatingActionButton.Behavior.layoutDependsOn_removed(android.support.design.widget.CoordinatorLayout, android.support.design.widget.FloatingActionButton, android.view.View)" class="hiddenlink" target="rightframe"><strike>layoutDependsOn</strike>
    -+(<code>CoordinatorLayout, FloatingActionButton, View</code>)</A></nobr><br>
    -+<!-- Class LeanbackSettingsFragment -->
    -+<A HREF="android.support.v17.preference.LeanbackSettingsFragment.html" class="hiddenlink" target="rightframe">LeanbackSettingsFragment</A><br>
    -+<!-- Class LinearLayoutCompat -->
    -+<A HREF="pkg_android.support.v7.widget.html#LinearLayoutCompat" class="hiddenlink" target="rightframe"><b>LinearLayoutCompat</b></A><br>
    -+<!-- Class LinearLayoutCompat.LayoutParams -->
    -+<A HREF="pkg_android.support.v7.widget.html#LinearLayoutCompat.LayoutParams" class="hiddenlink" target="rightframe"><b>LinearLayoutCompat.LayoutParams</b></A><br>
    -+<!-- Class LinearLayoutManager -->
    -+<A HREF="android.support.v7.widget.LinearLayoutManager.html" class="hiddenlink" target="rightframe">LinearLayoutManager</A><br>
    -+<!-- Class LinearSmoothScroller -->
    -+<A HREF="android.support.v7.widget.LinearSmoothScroller.html" class="hiddenlink" target="rightframe">LinearSmoothScroller</A><br>
    -+<!-- Class LinearSnapHelper -->
    -+<A HREF="pkg_android.support.v7.widget.html#LinearSnapHelper" class="hiddenlink" target="rightframe"><b>LinearSnapHelper</b></A><br>
    -+<!-- Class ListPopupWindow -->
    -+<A HREF="pkg_android.support.v7.widget.html#ListPopupWindow" class="hiddenlink" target="rightframe"><b>ListPopupWindow</b></A><br>
    -+<!-- Class ListUpdateCallback -->
    -+<A HREF="pkg_android.support.v7.util.html#ListUpdateCallback" class="hiddenlink" target="rightframe"><b><i>ListUpdateCallback</i></b></A><br>
    -+<!-- Method loadDescription -->
    -+<nobr><A HREF="android.support.v4.accessibilityservice.AccessibilityServiceInfoCompat.html#android.support.v4.accessibilityservice.AccessibilityServiceInfoCompat.loadDescription_added(android.accessibilityservice.AccessibilityServiceInfo, android.content.pm.PackageManager)" class="hiddenlink" target="rightframe"><b>loadDescription</b>
    -+(<code>AccessibilityServiceInfo, PackageManager</code>)</A></nobr><br>
    -+<!-- Method makeBasic -->
    -+<A NAME="M"></A>
    -+<br><font size="+2">M</font>&nbsp;
    -+<a href="#A"><font size="-2">A</font></a> 
    -+<a href="#B"><font size="-2">B</font></a> 
    -+<a href="#C"><font size="-2">C</font></a> 
    -+<a href="#D"><font size="-2">D</font></a> 
    -+<a href="#E"><font size="-2">E</font></a> 
    -+<a href="#F"><font size="-2">F</font></a> 
    -+<a href="#G"><font size="-2">G</font></a> 
    -+<a href="#H"><font size="-2">H</font></a> 
    -+<a href="#I"><font size="-2">I</font></a> 
    -+<a href="#K"><font size="-2">K</font></a> 
    -+<a href="#L"><font size="-2">L</font></a> 
    -+<a href="#N"><font size="-2">N</font></a> 
    -+<a href="#O"><font size="-2">O</font></a> 
    -+<a href="#P"><font size="-2">P</font></a> 
    -+<a href="#R"><font size="-2">R</font></a> 
    -+<a href="#S"><font size="-2">S</font></a> 
    -+<a href="#T"><font size="-2">T</font></a> 
    -+<a href="#V"><font size="-2">V</font></a> 
    -+<a href="#W"><font size="-2">W</font></a> 
    -+ <a href="#topheader"><font size="-2">TOP</font></a>
    -+<p><div style="line-height:1.5em;color:black">
    -+<nobr><A HREF="android.support.v4.app.ActivityOptionsCompat.html#android.support.v4.app.ActivityOptionsCompat.makeBasic_added()" class="hiddenlink" target="rightframe"><b>makeBasic</b>
    -+()</A></nobr><br>
    -+<!-- Method makeClipRevealAnimation -->
    -+<nobr><A HREF="android.support.v4.app.ActivityOptionsCompat.html#android.support.v4.app.ActivityOptionsCompat.makeClipRevealAnimation_added(android.view.View, int, int, int, int)" class="hiddenlink" target="rightframe"><b>makeClipRevealAnimation</b>
    -+(<code>View, int, int, int, int</code>)</A></nobr><br>
    -+<!-- Method makeTaskLaunchBehind -->
    -+<nobr><A HREF="android.support.v4.app.ActivityOptionsCompat.html#android.support.v4.app.ActivityOptionsCompat.makeTaskLaunchBehind_added()" class="hiddenlink" target="rightframe"><b>makeTaskLaunchBehind</b>
    -+()</A></nobr><br>
    -+<!-- Class MediaBrowserCompat.MediaItem -->
    -+<A HREF="android.support.v4.media.MediaBrowserCompat.MediaItem.html" class="hiddenlink" target="rightframe">MediaBrowserCompat.MediaItem</A><br>
    -+<!-- Class MediaBrowserServiceCompat.BrowserRoot -->
    -+<A HREF="android.support.v4.media.MediaBrowserServiceCompat.BrowserRoot.html" class="hiddenlink" target="rightframe">MediaBrowserServiceCompat.BrowserRoot</A><br>
    -+<!-- Class MediaButtonReceiver -->
    -+<A HREF="android.support.v4.media.session.MediaButtonReceiver.html" class="hiddenlink" target="rightframe">MediaButtonReceiver</A><br>
    -+<!-- Class MediaDescriptionCompat -->
    -+<A HREF="android.support.v4.media.MediaDescriptionCompat.html" class="hiddenlink" target="rightframe">MediaDescriptionCompat</A><br>
    -+<!-- Class MediaMetadataCompat -->
    -+<A HREF="android.support.v4.media.MediaMetadataCompat.html" class="hiddenlink" target="rightframe">MediaMetadataCompat</A><br>
    -+<!-- Class MediaSessionCompat -->
    -+<A HREF="android.support.v4.media.session.MediaSessionCompat.html" class="hiddenlink" target="rightframe">MediaSessionCompat</A><br>
    -+<!-- Class MediaSessionCompat.QueueItem -->
    -+<A HREF="android.support.v4.media.session.MediaSessionCompat.QueueItem.html" class="hiddenlink" target="rightframe">MediaSessionCompat.QueueItem</A><br>
    -+<!-- Field METADATA_KEY_BT_FOLDER_TYPE -->
    -+<nobr><A HREF="android.support.v4.media.MediaMetadataCompat.html#android.support.v4.media.MediaMetadataCompat.METADATA_KEY_BT_FOLDER_TYPE" class="hiddenlink" target="rightframe">METADATA_KEY_BT_FOLDER_TYPE</A>
    -+</nobr><br>
    -+<!-- Field METADATA_KEY_MEDIA_URI -->
    -+<nobr><A HREF="android.support.v4.media.MediaMetadataCompat.html#android.support.v4.media.MediaMetadataCompat.METADATA_KEY_MEDIA_URI" class="hiddenlink" target="rightframe">METADATA_KEY_MEDIA_URI</A>
    -+</nobr><br>
    -+<!-- Class MotionEventCompat -->
    -+<A HREF="android.support.v4.view.MotionEventCompat.html" class="hiddenlink" target="rightframe">MotionEventCompat</A><br>
    -+<!-- Class MultiSelectListPreferenceDialogFragmentCompat -->
    -+<A HREF="pkg_android.support.v7.preference.html#MultiSelectListPreferenceDialogFragmentCompat" class="hiddenlink" target="rightframe"><b>MultiSelectListPreferenceDialogFragmentCompat</b></A><br>
    -+<!-- Class NotificationCompat -->
    -+<A NAME="N"></A>
    -+<br><font size="+2">N</font>&nbsp;
    -+<a href="#A"><font size="-2">A</font></a> 
    -+<a href="#B"><font size="-2">B</font></a> 
    -+<a href="#C"><font size="-2">C</font></a> 
    -+<a href="#D"><font size="-2">D</font></a> 
    -+<a href="#E"><font size="-2">E</font></a> 
    -+<a href="#F"><font size="-2">F</font></a> 
    -+<a href="#G"><font size="-2">G</font></a> 
    -+<a href="#H"><font size="-2">H</font></a> 
    -+<a href="#I"><font size="-2">I</font></a> 
    -+<a href="#K"><font size="-2">K</font></a> 
    -+<a href="#L"><font size="-2">L</font></a> 
    -+<a href="#M"><font size="-2">M</font></a> 
    -+<a href="#O"><font size="-2">O</font></a> 
    -+<a href="#P"><font size="-2">P</font></a> 
    -+<a href="#R"><font size="-2">R</font></a> 
    -+<a href="#S"><font size="-2">S</font></a> 
    -+<a href="#T"><font size="-2">T</font></a> 
    -+<a href="#V"><font size="-2">V</font></a> 
    -+<a href="#W"><font size="-2">W</font></a> 
    -+ <a href="#topheader"><font size="-2">TOP</font></a>
    -+<p><div style="line-height:1.5em;color:black">
    -+<A HREF="pkg_android.support.v7.app.html#NotificationCompat" class="hiddenlink" target="rightframe"><b>NotificationCompat</b></A><br>
    -+<!-- Class NotificationCompat.Builder -->
    -+<A HREF="pkg_android.support.v7.app.html#NotificationCompat.Builder" class="hiddenlink" target="rightframe"><b>NotificationCompat.Builder</b></A><br>
    -+<!-- Class NotificationCompat.MediaStyle -->
    -+<A HREF="pkg_android.support.v7.app.html#NotificationCompat.MediaStyle" class="hiddenlink" target="rightframe"><b>NotificationCompat.MediaStyle</b></A><br>
    -+<!-- Method notifyPlayStateChanged -->
    -+<nobr><A HREF="android.support.v17.leanback.widget.AbstractMediaItemPresenter.ViewHolder.html#android.support.v17.leanback.widget.AbstractMediaItemPresenter.ViewHolder.notifyPlayStateChanged_added()" class="hiddenlink" target="rightframe"><b>notifyPlayStateChanged</b>
    -+()</A></nobr><br>
    -+<!-- Class ObjectAdapter -->
    -+<A NAME="O"></A>
    -+<br><font size="+2">O</font>&nbsp;
    -+<a href="#A"><font size="-2">A</font></a> 
    -+<a href="#B"><font size="-2">B</font></a> 
    -+<a href="#C"><font size="-2">C</font></a> 
    -+<a href="#D"><font size="-2">D</font></a> 
    -+<a href="#E"><font size="-2">E</font></a> 
    -+<a href="#F"><font size="-2">F</font></a> 
    -+<a href="#G"><font size="-2">G</font></a> 
    -+<a href="#H"><font size="-2">H</font></a> 
    -+<a href="#I"><font size="-2">I</font></a> 
    -+<a href="#K"><font size="-2">K</font></a> 
    -+<a href="#L"><font size="-2">L</font></a> 
    -+<a href="#M"><font size="-2">M</font></a> 
    -+<a href="#N"><font size="-2">N</font></a> 
    -+<a href="#P"><font size="-2">P</font></a> 
    -+<a href="#R"><font size="-2">R</font></a> 
    -+<a href="#S"><font size="-2">S</font></a> 
    -+<a href="#T"><font size="-2">T</font></a> 
    -+<a href="#V"><font size="-2">V</font></a> 
    -+<a href="#W"><font size="-2">W</font></a> 
    -+ <a href="#topheader"><font size="-2">TOP</font></a>
    -+<p><div style="line-height:1.5em;color:black">
    -+<A HREF="android.support.v17.leanback.widget.ObjectAdapter.html" class="hiddenlink" target="rightframe">ObjectAdapter</A><br>
    -+<!-- Method obtain -->
    -+<i>obtain</i><br>
    -+&nbsp;&nbsp;<nobr><A HREF="android.support.v4.media.session.MediaSessionCompat.html#android.support.v4.media.session.MediaSessionCompat.obtain_changed(android.content.Context, java.lang.Object)" class="hiddenlink" target="rightframe">type&nbsp;
    -+(<code>Context, Object</code>)&nbsp;in&nbsp;android.support.v4.media.session.MediaSessionCompat
    -+</A></nobr><br>
    -+<!-- Method obtain -->
    -+&nbsp;&nbsp;<nobr><A HREF="android.support.v4.media.session.MediaSessionCompat.QueueItem.html#android.support.v4.media.session.MediaSessionCompat.QueueItem.obtain_changed(java.lang.Object)" class="hiddenlink" target="rightframe">type&nbsp;
    -+(<code>Object</code>)&nbsp;in&nbsp;android.support.v4.media.session.MediaSessionCompat.QueueItem
    -+</A></nobr><br>
    -+<!-- Method obtain -->
    -+&nbsp;&nbsp;<nobr><A HREF="android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.CollectionInfoCompat.html#android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.CollectionInfoCompat.obtain_added(int, int, boolean)" class="hiddenlink" target="rightframe">type&nbsp;<b>
    -+(<code>int, int, boolean</code>)</b>&nbsp;in&nbsp;android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.CollectionInfoCompat
    -+</A></nobr><br>
    -+<!-- Method obtain -->
    -+&nbsp;&nbsp;<nobr><A HREF="android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.CollectionItemInfoCompat.html#android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.CollectionItemInfoCompat.obtain_added(int, int, int, int, boolean)" class="hiddenlink" target="rightframe">type&nbsp;<b>
    -+(<code>int, int, int, int, boolean</code>)</b>&nbsp;in&nbsp;android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.CollectionItemInfoCompat
    -+</A></nobr><br>
    -+<!-- Method obtain -->
    -+&nbsp;&nbsp;<nobr><A HREF="android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.RangeInfoCompat.html#android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.RangeInfoCompat.obtain_added(int, float, float, float)" class="hiddenlink" target="rightframe">type&nbsp;<b>
    -+(<code>int, float, float, float</code>)</b>&nbsp;in&nbsp;android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.RangeInfoCompat
    -+</A></nobr><br>
    -+<!-- Method onAccessibilityStateChanged -->
    -+<nobr><A HREF="android.support.v4.view.accessibility.AccessibilityManagerCompat.AccessibilityStateChangeListenerCompat.html#android.support.v4.view.accessibility.AccessibilityManagerCompat.AccessibilityStateChangeListenerCompat.onAccessibilityStateChanged_removed(boolean)" class="hiddenlink" target="rightframe"><strike>onAccessibilityStateChanged</strike>
    -+(<code>boolean</code>)</A></nobr><br>
    -+<!-- Method onAttachedToLayoutParams -->
    -+<nobr><A HREF="android.support.design.widget.CoordinatorLayout.Behavior.html#android.support.design.widget.CoordinatorLayout.Behavior.onAttachedToLayoutParams_added(android.support.design.widget.CoordinatorLayout.LayoutParams)" class="hiddenlink" target="rightframe"><b>onAttachedToLayoutParams</b>
    -+(<code>LayoutParams</code>)</A></nobr><br>
    -+<!-- Method onBindMediaPlayState -->
    -+<nobr><A HREF="android.support.v17.leanback.widget.AbstractMediaItemPresenter.html#android.support.v17.leanback.widget.AbstractMediaItemPresenter.onBindMediaPlayState_added(android.support.v17.leanback.widget.AbstractMediaItemPresenter.ViewHolder)" class="hiddenlink" target="rightframe"><b>onBindMediaPlayState</b>
    -+(<code>ViewHolder</code>)</A></nobr><br>
    -+<!-- Method onChanged -->
    -+<nobr><A HREF="android.support.v7.util.SortedList.Callback.html#android.support.v7.util.SortedList.Callback.onChanged_added(int, int, java.lang.Object)" class="hiddenlink" target="rightframe"><b>onChanged</b>
    -+(<code>int, int, Object</code>)</A></nobr><br>
    -+<!-- Method onDependentViewRemoved -->
    -+<nobr><A HREF="android.support.design.widget.FloatingActionButton.Behavior.html#android.support.design.widget.FloatingActionButton.Behavior.onDependentViewRemoved_removed(android.support.design.widget.CoordinatorLayout, android.support.design.widget.FloatingActionButton, android.view.View)" class="hiddenlink" target="rightframe"><strike>onDependentViewRemoved</strike>
    -+(<code>CoordinatorLayout, FloatingActionButton, View</code>)</A></nobr><br>
    -+<!-- Method onDetachedFromLayoutParams -->
    -+<nobr><A HREF="android.support.design.widget.CoordinatorLayout.Behavior.html#android.support.design.widget.CoordinatorLayout.Behavior.onDetachedFromLayoutParams_added()" class="hiddenlink" target="rightframe"><b>onDetachedFromLayoutParams</b>
    -+()</A></nobr><br>
    -+<!-- Method onInserted -->
    -+<nobr><A HREF="android.support.v7.util.SortedList.Callback.html#android.support.v7.util.SortedList.Callback.onInserted_removed(int, int)" class="hiddenlink" target="rightframe"><strike>onInserted</strike>
    -+(<code>int, int</code>)</A></nobr><br>
    -+<!-- Method onMoved -->
    -+<nobr><A HREF="android.support.v7.util.SortedList.Callback.html#android.support.v7.util.SortedList.Callback.onMoved_removed(int, int)" class="hiddenlink" target="rightframe"><strike>onMoved</strike>
    -+(<code>int, int</code>)</A></nobr><br>
    -+<!-- Method onRemoved -->
    -+<nobr><A HREF="android.support.v7.util.SortedList.Callback.html#android.support.v7.util.SortedList.Callback.onRemoved_removed(int, int)" class="hiddenlink" target="rightframe"><strike>onRemoved</strike>
    -+(<code>int, int</code>)</A></nobr><br>
    -+<!-- Method onRequestChildRectangleOnScreen -->
    -+<i>onRequestChildRectangleOnScreen</i><br>
    -+&nbsp;&nbsp;<nobr><A HREF="android.support.design.widget.AppBarLayout.ScrollingViewBehavior.html#android.support.design.widget.AppBarLayout.ScrollingViewBehavior.onRequestChildRectangleOnScreen_added(android.support.design.widget.CoordinatorLayout, android.view.View, android.graphics.Rect, boolean)" class="hiddenlink" target="rightframe">type&nbsp;<b>
    -+(<code>CoordinatorLayout, View, Rect, boolean</code>)</b>&nbsp;in&nbsp;android.support.design.widget.AppBarLayout.ScrollingViewBehavior
    -+</A></nobr><br>
    -+<!-- Method onRequestChildRectangleOnScreen -->
    -+&nbsp;&nbsp;<nobr><A HREF="android.support.design.widget.CoordinatorLayout.Behavior.html#android.support.design.widget.CoordinatorLayout.Behavior.onRequestChildRectangleOnScreen_added(android.support.design.widget.CoordinatorLayout, V, android.graphics.Rect, boolean)" class="hiddenlink" target="rightframe">type&nbsp;<b>
    -+(<code>CoordinatorLayout, V, Rect, boolean</code>)</b>&nbsp;in&nbsp;android.support.design.widget.CoordinatorLayout.Behavior
    -+</A></nobr><br>
    -+<!-- Method onSharedElementsArrived -->
    -+<nobr><A HREF="android.support.v4.app.SharedElementCallback.html#android.support.v4.app.SharedElementCallback.onSharedElementsArrived_added(java.util.List<java.lang.String>, java.util.List<android.view.View>, android.support.v4.app.SharedElementCallback.OnSharedElementsReadyListener)" class="hiddenlink" target="rightframe"><b>onSharedElementsArrived</b>
    -+(<code>List&lt;String&gt;, List&lt;View&gt;, OnSharedElementsReadyListener</code>)</A></nobr><br>
    -+<!-- Method onStart -->
    -+<nobr><A HREF="android.support.v7.app.AppCompatDelegate.html#android.support.v7.app.AppCompatDelegate.onStart_added()" class="hiddenlink" target="rightframe"><b>onStart</b>
    -+()</A></nobr><br>
    -+<!-- Method onUnbindMediaPlayState -->
    -+<nobr><A HREF="android.support.v17.leanback.widget.AbstractMediaItemPresenter.html#android.support.v17.leanback.widget.AbstractMediaItemPresenter.onUnbindMediaPlayState_added(android.support.v17.leanback.widget.AbstractMediaItemPresenter.ViewHolder)" class="hiddenlink" target="rightframe"><b>onUnbindMediaPlayState</b>
    -+(<code>ViewHolder</code>)</A></nobr><br>
    -+<!-- Field OVER_SCROLL_ALWAYS -->
    -+<nobr><A HREF="android.support.v4.view.ViewCompat.html#android.support.v4.view.ViewCompat.OVER_SCROLL_ALWAYS" class="hiddenlink" target="rightframe">OVER_SCROLL_ALWAYS</A>
    -+</nobr><br>
    -+<!-- Field OVER_SCROLL_IF_CONTENT_SCROLLS -->
    -+<nobr><A HREF="android.support.v4.view.ViewCompat.html#android.support.v4.view.ViewCompat.OVER_SCROLL_IF_CONTENT_SCROLLS" class="hiddenlink" target="rightframe">OVER_SCROLL_IF_CONTENT_SCROLLS</A>
    -+</nobr><br>
    -+<!-- Field OVER_SCROLL_NEVER -->
    -+<nobr><A HREF="android.support.v4.view.ViewCompat.html#android.support.v4.view.ViewCompat.OVER_SCROLL_NEVER" class="hiddenlink" target="rightframe">OVER_SCROLL_NEVER</A>
    -+</nobr><br>
    -+<!-- Class Palette -->
    -+<A NAME="P"></A>
    -+<br><font size="+2">P</font>&nbsp;
    -+<a href="#A"><font size="-2">A</font></a> 
    -+<a href="#B"><font size="-2">B</font></a> 
    -+<a href="#C"><font size="-2">C</font></a> 
    -+<a href="#D"><font size="-2">D</font></a> 
    -+<a href="#E"><font size="-2">E</font></a> 
    -+<a href="#F"><font size="-2">F</font></a> 
    -+<a href="#G"><font size="-2">G</font></a> 
    -+<a href="#H"><font size="-2">H</font></a> 
    -+<a href="#I"><font size="-2">I</font></a> 
    -+<a href="#K"><font size="-2">K</font></a> 
    -+<a href="#L"><font size="-2">L</font></a> 
    -+<a href="#M"><font size="-2">M</font></a> 
    -+<a href="#N"><font size="-2">N</font></a> 
    -+<a href="#O"><font size="-2">O</font></a> 
    -+<a href="#R"><font size="-2">R</font></a> 
    -+<a href="#S"><font size="-2">S</font></a> 
    -+<a href="#T"><font size="-2">T</font></a> 
    -+<a href="#V"><font size="-2">V</font></a> 
    -+<a href="#W"><font size="-2">W</font></a> 
    -+ <a href="#topheader"><font size="-2">TOP</font></a>
    -+<p><div style="line-height:1.5em;color:black">
    -+<A HREF="android.support.v7.graphics.Palette.html" class="hiddenlink" target="rightframe">Palette</A><br>
    -+<!-- Class PatternsCompat -->
    -+<A HREF="pkg_android.support.v4.util.html#PatternsCompat" class="hiddenlink" target="rightframe"><b>PatternsCompat</b></A><br>
    -+<!-- Field PEEK_HEIGHT_AUTO -->
    -+<nobr><A HREF="android.support.design.widget.BottomSheetBehavior.html#android.support.design.widget.BottomSheetBehavior.PEEK_HEIGHT_AUTO" class="hiddenlink" target="rightframe">PEEK_HEIGHT_AUTO</A>
    -+</nobr><br>
    -+<!-- Field PLAY_STATE_INITIAL -->
    -+<nobr><A HREF="android.support.v17.leanback.widget.AbstractMediaItemPresenter.html#android.support.v17.leanback.widget.AbstractMediaItemPresenter.PLAY_STATE_INITIAL" class="hiddenlink" target="rightframe">PLAY_STATE_INITIAL</A>
    -+</nobr><br>
    -+<!-- Field PLAY_STATE_PAUSED -->
    -+<nobr><A HREF="android.support.v17.leanback.widget.AbstractMediaItemPresenter.html#android.support.v17.leanback.widget.AbstractMediaItemPresenter.PLAY_STATE_PAUSED" class="hiddenlink" target="rightframe">PLAY_STATE_PAUSED</A>
    -+</nobr><br>
    -+<!-- Field PLAY_STATE_PLAYING -->
    -+<nobr><A HREF="android.support.v17.leanback.widget.AbstractMediaItemPresenter.html#android.support.v17.leanback.widget.AbstractMediaItemPresenter.PLAY_STATE_PLAYING" class="hiddenlink" target="rightframe">PLAY_STATE_PLAYING</A>
    -+</nobr><br>
    -+<!-- Class PlaybackStateCompat -->
    -+<A HREF="android.support.v4.media.session.PlaybackStateCompat.html" class="hiddenlink" target="rightframe">PlaybackStateCompat</A><br>
    -+<!-- Class PopupMenu -->
    -+<A HREF="pkg_android.support.v7.widget.html#PopupMenu" class="hiddenlink" target="rightframe"><b>PopupMenu</b></A><br>
    -+<!-- Class PopupMenu.OnDismissListener -->
    -+<A HREF="pkg_android.support.v7.widget.html#PopupMenu.OnDismissListener" class="hiddenlink" target="rightframe"><b><i>PopupMenu.OnDismissListener</i></b></A><br>
    -+<!-- Class PopupMenu.OnMenuItemClickListener -->
    -+<A HREF="pkg_android.support.v7.widget.html#PopupMenu.OnMenuItemClickListener" class="hiddenlink" target="rightframe"><b><i>PopupMenu.OnMenuItemClickListener</i></b></A><br>
    -+<!-- Class PreferenceFragment -->
    -+<A HREF="android.support.v14.preference.PreferenceFragment.html" class="hiddenlink" target="rightframe">PreferenceFragment</A><br>
    -+<!-- Method prepareForDrop -->
    -+<nobr><A HREF="android.support.v7.widget.LinearLayoutManager.html#android.support.v7.widget.LinearLayoutManager.prepareForDrop_removed(android.view.View, android.view.View, int, int)" class="hiddenlink" target="rightframe"><strike>prepareForDrop</strike>
    -+(<code>View, View, int, int</code>)</A></nobr><br>
    -+<!-- Class RecyclerView -->
    -+<A NAME="R"></A>
    -+<br><font size="+2">R</font>&nbsp;
    -+<a href="#A"><font size="-2">A</font></a> 
    -+<a href="#B"><font size="-2">B</font></a> 
    -+<a href="#C"><font size="-2">C</font></a> 
    -+<a href="#D"><font size="-2">D</font></a> 
    -+<a href="#E"><font size="-2">E</font></a> 
    -+<a href="#F"><font size="-2">F</font></a> 
    -+<a href="#G"><font size="-2">G</font></a> 
    -+<a href="#H"><font size="-2">H</font></a> 
    -+<a href="#I"><font size="-2">I</font></a> 
    -+<a href="#K"><font size="-2">K</font></a> 
    -+<a href="#L"><font size="-2">L</font></a> 
    -+<a href="#M"><font size="-2">M</font></a> 
    -+<a href="#N"><font size="-2">N</font></a> 
    -+<a href="#O"><font size="-2">O</font></a> 
    -+<a href="#P"><font size="-2">P</font></a> 
    -+<a href="#S"><font size="-2">S</font></a> 
    -+<a href="#T"><font size="-2">T</font></a> 
    -+<a href="#V"><font size="-2">V</font></a> 
    -+<a href="#W"><font size="-2">W</font></a> 
    -+ <a href="#topheader"><font size="-2">TOP</font></a>
    -+<p><div style="line-height:1.5em;color:black">
    -+<A HREF="android.support.v7.widget.RecyclerView.html" class="hiddenlink" target="rightframe">RecyclerView</A><br>
    -+<!-- Class RecyclerView.OnFlingListener -->
    -+<A HREF="pkg_android.support.v7.widget.html#RecyclerView.OnFlingListener" class="hiddenlink" target="rightframe"><b>RecyclerView.OnFlingListener</b></A><br>
    -+<!-- Class RecyclerView.SmoothScroller.ScrollVectorProvider -->
    -+<A HREF="pkg_android.support.v7.widget.html#RecyclerView.SmoothScroller.ScrollVectorProvider" class="hiddenlink" target="rightframe"><b><i>RecyclerView.SmoothScroller.ScrollVectorProvider</i></b></A><br>
    -+<!-- Method removeAccessibilityStateChangeListener -->
    -+<nobr><A HREF="android.support.v4.view.accessibility.AccessibilityManagerCompat.html#android.support.v4.view.accessibility.AccessibilityManagerCompat.removeAccessibilityStateChangeListener_changed(android.view.accessibility.AccessibilityManager, android.support.v4.view.accessibility.AccessibilityManagerCompat.AccessibilityStateChangeListener)" class="hiddenlink" target="rightframe">removeAccessibilityStateChangeListener
    -+(<code>AccessibilityManager, AccessibilityStateChangeListener</code>)</A></nobr><br>
    -+<!-- Method removeTouchExplorationStateChangeListener -->
    -+<nobr><A HREF="android.support.v4.view.accessibility.AccessibilityManagerCompat.html#android.support.v4.view.accessibility.AccessibilityManagerCompat.removeTouchExplorationStateChangeListener_added(android.view.accessibility.AccessibilityManager, android.support.v4.view.accessibility.AccessibilityManagerCompat.TouchExplorationStateChangeListener)" class="hiddenlink" target="rightframe"><b>removeTouchExplorationStateChangeListener</b>
    -+(<code>AccessibilityManager, TouchExplorationStateChangeListener</code>)</A></nobr><br>
    -+<!-- Method requestUsageTimeReport -->
    -+<nobr><A HREF="android.support.v4.app.ActivityOptionsCompat.html#android.support.v4.app.ActivityOptionsCompat.requestUsageTimeReport_added(android.app.PendingIntent)" class="hiddenlink" target="rightframe"><b>requestUsageTimeReport</b>
    -+(<code>PendingIntent</code>)</A></nobr><br>
    -+<!-- Class SearchView -->
    -+<A NAME="S"></A>
    -+<br><font size="+2">S</font>&nbsp;
    -+<a href="#A"><font size="-2">A</font></a> 
    -+<a href="#B"><font size="-2">B</font></a> 
    -+<a href="#C"><font size="-2">C</font></a> 
    -+<a href="#D"><font size="-2">D</font></a> 
    -+<a href="#E"><font size="-2">E</font></a> 
    -+<a href="#F"><font size="-2">F</font></a> 
    -+<a href="#G"><font size="-2">G</font></a> 
    -+<a href="#H"><font size="-2">H</font></a> 
    -+<a href="#I"><font size="-2">I</font></a> 
    -+<a href="#K"><font size="-2">K</font></a> 
    -+<a href="#L"><font size="-2">L</font></a> 
    -+<a href="#M"><font size="-2">M</font></a> 
    -+<a href="#N"><font size="-2">N</font></a> 
    -+<a href="#O"><font size="-2">O</font></a> 
    -+<a href="#P"><font size="-2">P</font></a> 
    -+<a href="#R"><font size="-2">R</font></a> 
    -+<a href="#T"><font size="-2">T</font></a> 
    -+<a href="#V"><font size="-2">V</font></a> 
    -+<a href="#W"><font size="-2">W</font></a> 
    -+ <a href="#topheader"><font size="-2">TOP</font></a>
    -+<p><div style="line-height:1.5em;color:black">
    -+<A HREF="pkg_android.support.v7.widget.html#SearchView" class="hiddenlink" target="rightframe"><b>SearchView</b></A><br>
    -+<!-- Class SearchView.OnCloseListener -->
    -+<A HREF="pkg_android.support.v7.widget.html#SearchView.OnCloseListener" class="hiddenlink" target="rightframe"><b><i>SearchView.OnCloseListener</i></b></A><br>
    -+<!-- Class SearchView.OnQueryTextListener -->
    -+<A HREF="pkg_android.support.v7.widget.html#SearchView.OnQueryTextListener" class="hiddenlink" target="rightframe"><b><i>SearchView.OnQueryTextListener</i></b></A><br>
    -+<!-- Class SearchView.OnSuggestionListener -->
    -+<A HREF="pkg_android.support.v7.widget.html#SearchView.OnSuggestionListener" class="hiddenlink" target="rightframe"><b><i>SearchView.OnSuggestionListener</i></b></A><br>
    -+<!-- Class SearchViewCompat -->
    -+<A HREF="android.support.v4.widget.SearchViewCompat.html" class="hiddenlink" target="rightframe">SearchViewCompat</A><br>
    -+<!-- Class SearchViewCompat.OnCloseListener -->
    -+<A HREF="pkg_android.support.v4.widget.html#SearchViewCompat.OnCloseListener" class="hiddenlink" target="rightframe"><b><i>SearchViewCompat.OnCloseListener</i></b></A><br>
    -+<!-- Class SearchViewCompat.OnCloseListenerCompat -->
    -+<A HREF="android.support.v4.widget.SearchViewCompat.OnCloseListenerCompat.html" class="hiddenlink" target="rightframe">SearchViewCompat.OnCloseListenerCompat</A><br>
    -+<!-- Class SearchViewCompat.OnQueryTextListener -->
    -+<A HREF="pkg_android.support.v4.widget.html#SearchViewCompat.OnQueryTextListener" class="hiddenlink" target="rightframe"><b><i>SearchViewCompat.OnQueryTextListener</i></b></A><br>
    -+<!-- Class SearchViewCompat.OnQueryTextListenerCompat -->
    -+<A HREF="android.support.v4.widget.SearchViewCompat.OnQueryTextListenerCompat.html" class="hiddenlink" target="rightframe">SearchViewCompat.OnQueryTextListenerCompat</A><br>
    -+<!-- Class ServiceCompat -->
    -+<A HREF="android.support.v4.app.ServiceCompat.html" class="hiddenlink" target="rightframe">ServiceCompat</A><br>
    -+<!-- Method setAction -->
    -+<nobr><A HREF="android.support.v4.view.accessibility.AccessibilityEventCompat.html#android.support.v4.view.accessibility.AccessibilityEventCompat.setAction_added(android.view.accessibility.AccessibilityEvent, int)" class="hiddenlink" target="rightframe"><b>setAction</b>
    -+(<code>AccessibilityEvent, int</code>)</A></nobr><br>
    -+<!-- Method setAlwaysUseBrowserUI -->
    -+<nobr><A HREF="android.support.customtabs.CustomTabsIntent.html#android.support.customtabs.CustomTabsIntent.setAlwaysUseBrowserUI_added(android.content.Intent)" class="hiddenlink" target="rightframe"><b>setAlwaysUseBrowserUI</b>
    -+(<code>Intent</code>)</A></nobr><br>
    -+<!-- Method setAutoHideEnabled -->
    -+<nobr><A HREF="android.support.design.widget.FloatingActionButton.Behavior.html#android.support.design.widget.FloatingActionButton.Behavior.setAutoHideEnabled_added(boolean)" class="hiddenlink" target="rightframe"><b>setAutoHideEnabled</b>
    -+(<code>boolean</code>)</A></nobr><br>
    -+<!-- Method setCollapsedTitleTextColor -->
    -+<nobr><A HREF="android.support.design.widget.CollapsingToolbarLayout.html#android.support.design.widget.CollapsingToolbarLayout.setCollapsedTitleTextColor_added(android.content.res.ColorStateList)" class="hiddenlink" target="rightframe"><b>setCollapsedTitleTextColor</b>
    -+(<code>ColorStateList</code>)</A></nobr><br>
    -+<!-- Method setContextClickable -->
    -+<nobr><A HREF="android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.html#android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.setContextClickable_added(boolean)" class="hiddenlink" target="rightframe"><b>setContextClickable</b>
    -+(<code>boolean</code>)</A></nobr><br>
    -+<!-- Method setDrawerArrowDrawable -->
    -+<nobr><A HREF="android.support.v7.app.ActionBarDrawerToggle.html#android.support.v7.app.ActionBarDrawerToggle.setDrawerArrowDrawable_added(android.support.v7.graphics.drawable.DrawerArrowDrawable)" class="hiddenlink" target="rightframe"><b>setDrawerArrowDrawable</b>
    -+(<code>DrawerArrowDrawable</code>)</A></nobr><br>
    -+<!-- Method setExpandedTitleTextColor -->
    -+<nobr><A HREF="android.support.design.widget.CollapsingToolbarLayout.html#android.support.design.widget.CollapsingToolbarLayout.setExpandedTitleTextColor_added(android.content.res.ColorStateList)" class="hiddenlink" target="rightframe"><b>setExpandedTitleTextColor</b>
    -+(<code>ColorStateList</code>)</A></nobr><br>
    -+<!-- Method setInstantAppsEnabled -->
    -+<nobr><A HREF="android.support.customtabs.CustomTabsIntent.Builder.html#android.support.customtabs.CustomTabsIntent.Builder.setInstantAppsEnabled_added(boolean)" class="hiddenlink" target="rightframe"><b>setInstantAppsEnabled</b>
    -+(<code>boolean</code>)</A></nobr><br>
    -+<!-- Method setLaunchBounds -->
    -+<nobr><A HREF="android.support.v4.app.ActivityOptionsCompat.html#android.support.v4.app.ActivityOptionsCompat.setLaunchBounds_added(android.graphics.Rect)" class="hiddenlink" target="rightframe"><b>setLaunchBounds</b>
    -+(<code>Rect</code>)</A></nobr><br>
    -+<!-- Method setMovementGranularity -->
    -+<nobr><A HREF="android.support.v4.view.accessibility.AccessibilityEventCompat.html#android.support.v4.view.accessibility.AccessibilityEventCompat.setMovementGranularity_added(android.view.accessibility.AccessibilityEvent, int)" class="hiddenlink" target="rightframe"><b>setMovementGranularity</b>
    -+(<code>AccessibilityEvent, int</code>)</A></nobr><br>
    -+<!-- Method setOnChildScrollUpCallback -->
    -+<nobr><A HREF="android.support.v4.widget.SwipeRefreshLayout.html#android.support.v4.widget.SwipeRefreshLayout.setOnChildScrollUpCallback_added(android.support.v4.widget.SwipeRefreshLayout.OnChildScrollUpCallback)" class="hiddenlink" target="rightframe"><b>setOnChildScrollUpCallback</b>
    -+(<code>OnChildScrollUpCallback</code>)</A></nobr><br>
    -+<!-- Method setOnCloseListener -->
    -+<nobr><A HREF="android.support.v4.widget.SearchViewCompat.html#android.support.v4.widget.SearchViewCompat.setOnCloseListener_changed(android.view.View, android.support.v4.widget.SearchViewCompat.OnCloseListener)" class="hiddenlink" target="rightframe">setOnCloseListener
    -+(<code>View, OnCloseListener</code>)</A></nobr><br>
    -+<!-- Method setOnFlingListener -->
    -+<nobr><A HREF="android.support.v7.widget.RecyclerView.html#android.support.v7.widget.RecyclerView.setOnFlingListener_added(android.support.v7.widget.RecyclerView.OnFlingListener)" class="hiddenlink" target="rightframe"><b>setOnFlingListener</b>
    -+(<code>OnFlingListener</code>)</A></nobr><br>
    -+<!-- Method setOnQueryTextListener -->
    -+<nobr><A HREF="android.support.v4.widget.SearchViewCompat.html#android.support.v4.widget.SearchViewCompat.setOnQueryTextListener_changed(android.view.View, android.support.v4.widget.SearchViewCompat.OnQueryTextListener)" class="hiddenlink" target="rightframe">setOnQueryTextListener
    -+(<code>View, OnQueryTextListener</code>)</A></nobr><br>
    -+<!-- Method setOverScrollMode -->
    -+<nobr><A HREF="android.support.v4.view.ViewCompat.html#android.support.v4.view.ViewCompat.setOverScrollMode_changed(android.view.View, int)" class="hiddenlink" target="rightframe">setOverScrollMode
    -+(<code>View, int</code>)</A></nobr><br>
    -+<!-- Method setPasswordVisibilityToggleContentDescription -->
    -+<i>setPasswordVisibilityToggleContentDescription</i><br>
    -+&nbsp;&nbsp;<nobr><A HREF="android.support.design.widget.TextInputLayout.html#android.support.design.widget.TextInputLayout.setPasswordVisibilityToggleContentDescription_added(int)" class="hiddenlink" target="rightframe">type&nbsp;<b>
    -+(<code>int</code>)</b>&nbsp;in&nbsp;android.support.design.widget.TextInputLayout
    -+</A></nobr><br>
    -+<!-- Method setPasswordVisibilityToggleContentDescription -->
    -+&nbsp;&nbsp;<nobr><A HREF="android.support.design.widget.TextInputLayout.html#android.support.design.widget.TextInputLayout.setPasswordVisibilityToggleContentDescription_added(java.lang.CharSequence)" class="hiddenlink" target="rightframe">type&nbsp;<b>
    -+(<code>CharSequence</code>)</b>&nbsp;in&nbsp;android.support.design.widget.TextInputLayout
    -+</A></nobr><br>
    -+<!-- Method setPasswordVisibilityToggleDrawable -->
    -+<i>setPasswordVisibilityToggleDrawable</i><br>
    -+&nbsp;&nbsp;<nobr><A HREF="android.support.design.widget.TextInputLayout.html#android.support.design.widget.TextInputLayout.setPasswordVisibilityToggleDrawable_added(android.graphics.drawable.Drawable)" class="hiddenlink" target="rightframe">type&nbsp;<b>
    -+(<code>Drawable</code>)</b>&nbsp;in&nbsp;android.support.design.widget.TextInputLayout
    -+</A></nobr><br>
    -+<!-- Method setPasswordVisibilityToggleDrawable -->
    -+&nbsp;&nbsp;<nobr><A HREF="android.support.design.widget.TextInputLayout.html#android.support.design.widget.TextInputLayout.setPasswordVisibilityToggleDrawable_added(int)" class="hiddenlink" target="rightframe">type&nbsp;<b>
    -+(<code>int</code>)</b>&nbsp;in&nbsp;android.support.design.widget.TextInputLayout
    -+</A></nobr><br>
    -+<!-- Method setPasswordVisibilityToggleEnabled -->
    -+<nobr><A HREF="android.support.design.widget.TextInputLayout.html#android.support.design.widget.TextInputLayout.setPasswordVisibilityToggleEnabled_added(boolean)" class="hiddenlink" target="rightframe"><b>setPasswordVisibilityToggleEnabled</b>
    -+(<code>boolean</code>)</A></nobr><br>
    -+<!-- Method setPasswordVisibilityToggleTintList -->
    -+<nobr><A HREF="android.support.design.widget.TextInputLayout.html#android.support.design.widget.TextInputLayout.setPasswordVisibilityToggleTintList_added(android.content.res.ColorStateList)" class="hiddenlink" target="rightframe"><b>setPasswordVisibilityToggleTintList</b>
    -+(<code>ColorStateList</code>)</A></nobr><br>
    -+<!-- Method setPasswordVisibilityToggleTintMode -->
    -+<nobr><A HREF="android.support.design.widget.TextInputLayout.html#android.support.design.widget.TextInputLayout.setPasswordVisibilityToggleTintMode_added(android.graphics.PorterDuff.Mode)" class="hiddenlink" target="rightframe"><b>setPasswordVisibilityToggleTintMode</b>
    -+(<code>Mode</code>)</A></nobr><br>
    -+<!-- Method setSecondaryToolbarViews -->
    -+<nobr><A HREF="android.support.customtabs.CustomTabsSession.html#android.support.customtabs.CustomTabsSession.setSecondaryToolbarViews_added(android.widget.RemoteViews, int[], android.app.PendingIntent)" class="hiddenlink" target="rightframe"><b>setSecondaryToolbarViews</b>
    -+(<code>RemoteViews, int[], PendingIntent</code>)</A></nobr><br>
    -+<!-- Method setSelectedMediaItemNumberView -->
    -+<nobr><A HREF="android.support.v17.leanback.widget.AbstractMediaItemPresenter.ViewHolder.html#android.support.v17.leanback.widget.AbstractMediaItemPresenter.ViewHolder.setSelectedMediaItemNumberView_added(int)" class="hiddenlink" target="rightframe"><b>setSelectedMediaItemNumberView</b>
    -+(<code>int</code>)</A></nobr><br>
    -+<!-- Method setToolbarItem -->
    -+<nobr><A HREF="android.support.customtabs.CustomTabsSession.html#android.support.customtabs.CustomTabsSession.setToolbarItem_changed(int, android.graphics.Bitmap, java.lang.String)" class="hiddenlink" target="rightframe">setToolbarItem
    -+(<code>int, Bitmap, String</code>)</A></nobr><br>
    -+<!-- Class ShareActionProvider -->
    -+<A HREF="pkg_android.support.v7.widget.html#ShareActionProvider" class="hiddenlink" target="rightframe"><b>ShareActionProvider</b></A><br>
    -+<!-- Class ShareActionProvider.OnShareTargetSelectedListener -->
    -+<A HREF="pkg_android.support.v7.widget.html#ShareActionProvider.OnShareTargetSelectedListener" class="hiddenlink" target="rightframe"><b><i>ShareActionProvider.OnShareTargetSelectedListener</i></b></A><br>
    -+<!-- Class SharedElementCallback -->
    -+<A HREF="android.support.v4.app.SharedElementCallback.html" class="hiddenlink" target="rightframe">SharedElementCallback</A><br>
    -+<!-- Class SharedElementCallback.OnSharedElementsReadyListener -->
    -+<A HREF="pkg_android.support.v4.app.html#SharedElementCallback.OnSharedElementsReadyListener" class="hiddenlink" target="rightframe"><b><i>SharedElementCallback.OnSharedElementsReadyListener</i></b></A><br>
    -+<!-- Method shouldAlwaysUseBrowserUI -->
    -+<nobr><A HREF="android.support.customtabs.CustomTabsIntent.html#android.support.customtabs.CustomTabsIntent.shouldAlwaysUseBrowserUI_added(android.content.Intent)" class="hiddenlink" target="rightframe"><b>shouldAlwaysUseBrowserUI</b>
    -+(<code>Intent</code>)</A></nobr><br>
    -+<!-- Class SnapHelper -->
    -+<A HREF="pkg_android.support.v7.widget.html#SnapHelper" class="hiddenlink" target="rightframe"><b>SnapHelper</b></A><br>
    -+<!-- Class SortedList.Callback -->
    -+<A HREF="android.support.v7.util.SortedList.Callback.html" class="hiddenlink" target="rightframe">SortedList.Callback</A><br>
    -+<!-- Class Space -->
    -+<A HREF="pkg_android.support.v7.widget.html#Space" class="hiddenlink" target="rightframe"><b>Space</b></A><br>
    -+<!-- Class StaggeredGridLayoutManager -->
    -+<A HREF="android.support.v7.widget.StaggeredGridLayoutManager.html" class="hiddenlink" target="rightframe">StaggeredGridLayoutManager</A><br>
    -+<!-- Method startTracking -->
    -+<nobr><A HREF="android.support.v4.view.KeyEventCompat.html#android.support.v4.view.KeyEventCompat.startTracking_changed(android.view.KeyEvent)" class="hiddenlink" target="rightframe">startTracking
    -+(<code>KeyEvent</code>)</A></nobr><br>
    -+<!-- Field STOP_FOREGROUND_DETACH -->
    -+<nobr><A HREF="android.support.v4.app.ServiceCompat.html#android.support.v4.app.ServiceCompat.STOP_FOREGROUND_DETACH" class="hiddenlink" target="rightframe">STOP_FOREGROUND_DETACH</A>
    -+</nobr><br>
    -+<!-- Field STOP_FOREGROUND_REMOVE -->
    -+<nobr><A HREF="android.support.v4.app.ServiceCompat.html#android.support.v4.app.ServiceCompat.STOP_FOREGROUND_REMOVE" class="hiddenlink" target="rightframe">STOP_FOREGROUND_REMOVE</A>
    -+</nobr><br>
    -+<!-- Method stopForeground -->
    -+<nobr><A HREF="android.support.v4.app.ServiceCompat.html#android.support.v4.app.ServiceCompat.stopForeground_added(android.app.Service, int)" class="hiddenlink" target="rightframe"><b>stopForeground</b>
    -+(<code>Service, int</code>)</A></nobr><br>
    -+<!-- Class SwipeRefreshLayout -->
    -+<A HREF="android.support.v4.widget.SwipeRefreshLayout.html" class="hiddenlink" target="rightframe">SwipeRefreshLayout</A><br>
    -+<!-- Class SwipeRefreshLayout.OnChildScrollUpCallback -->
    -+<A HREF="pkg_android.support.v4.widget.html#SwipeRefreshLayout.OnChildScrollUpCallback" class="hiddenlink" target="rightframe"><b><i>SwipeRefreshLayout.OnChildScrollUpCallback</i></b></A><br>
    -+<!-- Class SwitchCompat -->
    -+<A HREF="pkg_android.support.v7.widget.html#SwitchCompat" class="hiddenlink" target="rightframe"><b>SwitchCompat</b></A><br>
    -+<!-- Class TabLayout -->
    -+<A NAME="T"></A>
    -+<br><font size="+2">T</font>&nbsp;
    -+<a href="#A"><font size="-2">A</font></a> 
    -+<a href="#B"><font size="-2">B</font></a> 
    -+<a href="#C"><font size="-2">C</font></a> 
    -+<a href="#D"><font size="-2">D</font></a> 
    -+<a href="#E"><font size="-2">E</font></a> 
    -+<a href="#F"><font size="-2">F</font></a> 
    -+<a href="#G"><font size="-2">G</font></a> 
    -+<a href="#H"><font size="-2">H</font></a> 
    -+<a href="#I"><font size="-2">I</font></a> 
    -+<a href="#K"><font size="-2">K</font></a> 
    -+<a href="#L"><font size="-2">L</font></a> 
    -+<a href="#M"><font size="-2">M</font></a> 
    -+<a href="#N"><font size="-2">N</font></a> 
    -+<a href="#O"><font size="-2">O</font></a> 
    -+<a href="#P"><font size="-2">P</font></a> 
    -+<a href="#R"><font size="-2">R</font></a> 
    -+<a href="#S"><font size="-2">S</font></a> 
    -+<a href="#V"><font size="-2">V</font></a> 
    -+<a href="#W"><font size="-2">W</font></a> 
    -+ <a href="#topheader"><font size="-2">TOP</font></a>
    -+<p><div style="line-height:1.5em;color:black">
    -+<A HREF="android.support.design.widget.TabLayout.html" class="hiddenlink" target="rightframe">TabLayout</A><br>
    -+<!-- Field TAG -->
    -+<nobr><A HREF="android.support.v7.widget.StaggeredGridLayoutManager.html#android.support.v7.widget.StaggeredGridLayoutManager.TAG" class="hiddenlink" target="rightframe"><strike>TAG</strike></A>
    -+</nobr><br>
    -+<!-- Class TextInputLayout -->
    -+<A HREF="android.support.design.widget.TextInputLayout.html" class="hiddenlink" target="rightframe">TextInputLayout</A><br>
    -+<!-- Class TextViewCompat -->
    -+<A HREF="android.support.v4.widget.TextViewCompat.html" class="hiddenlink" target="rightframe">TextViewCompat</A><br>
    -+<!-- Class ThemedSpinnerAdapter -->
    -+<A HREF="pkg_android.support.v7.widget.html#ThemedSpinnerAdapter" class="hiddenlink" target="rightframe"><b><i>ThemedSpinnerAdapter</i></b></A><br>
    -+<!-- Class ThemedSpinnerAdapter.Helper -->
    -+<A HREF="pkg_android.support.v7.widget.html#ThemedSpinnerAdapter.Helper" class="hiddenlink" target="rightframe"><b>ThemedSpinnerAdapter.Helper</b></A><br>
    -+<!-- Method toKeyCode -->
    -+<nobr><A HREF="android.support.v4.media.session.PlaybackStateCompat.html#android.support.v4.media.session.PlaybackStateCompat.toKeyCode_added(long)" class="hiddenlink" target="rightframe"><b>toKeyCode</b>
    -+(<code>long</code>)</A></nobr><br>
    -+<!-- Class Toolbar -->
    -+<A HREF="pkg_android.support.v7.widget.html#Toolbar" class="hiddenlink" target="rightframe"><b>Toolbar</b></A><br>
    -+<!-- Class Toolbar.LayoutParams -->
    -+<A HREF="pkg_android.support.v7.widget.html#Toolbar.LayoutParams" class="hiddenlink" target="rightframe"><b>Toolbar.LayoutParams</b></A><br>
    -+<!-- Class Toolbar.OnMenuItemClickListener -->
    -+<A HREF="pkg_android.support.v7.widget.html#Toolbar.OnMenuItemClickListener" class="hiddenlink" target="rightframe"><b><i>Toolbar.OnMenuItemClickListener</i></b></A><br>
    -+<!-- Class Toolbar.SavedState -->
    -+<A HREF="pkg_android.support.v7.widget.html#Toolbar.SavedState" class="hiddenlink" target="rightframe"><b>Toolbar.SavedState</b></A><br>
    -+<!-- Field TYPE_ASSIST_READING_CONTEXT -->
    -+<nobr><A HREF="android.support.v4.view.accessibility.AccessibilityEventCompat.html#android.support.v4.view.accessibility.AccessibilityEventCompat.TYPE_ASSIST_READING_CONTEXT" class="hiddenlink" target="rightframe">TYPE_ASSIST_READING_CONTEXT</A>
    -+</nobr><br>
    -+<!-- Field TYPE_SPLIT_SCREEN_DIVIDER -->
    -+<nobr><A HREF="android.support.v4.view.accessibility.AccessibilityWindowInfoCompat.html#android.support.v4.view.accessibility.AccessibilityWindowInfoCompat.TYPE_SPLIT_SCREEN_DIVIDER" class="hiddenlink" target="rightframe">TYPE_SPLIT_SCREEN_DIVIDER</A>
    -+</nobr><br>
    -+<!-- Field TYPE_VIEW_CONTEXT_CLICKED -->
    -+<nobr><A HREF="android.support.v4.view.accessibility.AccessibilityEventCompat.html#android.support.v4.view.accessibility.AccessibilityEventCompat.TYPE_VIEW_CONTEXT_CLICKED" class="hiddenlink" target="rightframe">TYPE_VIEW_CONTEXT_CLICKED</A>
    -+</nobr><br>
    -+<!-- Field TYPE_WINDOWS_CHANGED -->
    -+<nobr><A HREF="android.support.v4.view.accessibility.AccessibilityEventCompat.html#android.support.v4.view.accessibility.AccessibilityEventCompat.TYPE_WINDOWS_CHANGED" class="hiddenlink" target="rightframe">TYPE_WINDOWS_CHANGED</A>
    -+</nobr><br>
    -+<!-- Class ViewCompat -->
    -+<A NAME="V"></A>
    -+<br><font size="+2">V</font>&nbsp;
    -+<a href="#A"><font size="-2">A</font></a> 
    -+<a href="#B"><font size="-2">B</font></a> 
    -+<a href="#C"><font size="-2">C</font></a> 
    -+<a href="#D"><font size="-2">D</font></a> 
    -+<a href="#E"><font size="-2">E</font></a> 
    -+<a href="#F"><font size="-2">F</font></a> 
    -+<a href="#G"><font size="-2">G</font></a> 
    -+<a href="#H"><font size="-2">H</font></a> 
    -+<a href="#I"><font size="-2">I</font></a> 
    -+<a href="#K"><font size="-2">K</font></a> 
    -+<a href="#L"><font size="-2">L</font></a> 
    -+<a href="#M"><font size="-2">M</font></a> 
    -+<a href="#N"><font size="-2">N</font></a> 
    -+<a href="#O"><font size="-2">O</font></a> 
    -+<a href="#P"><font size="-2">P</font></a> 
    -+<a href="#R"><font size="-2">R</font></a> 
    -+<a href="#S"><font size="-2">S</font></a> 
    -+<a href="#T"><font size="-2">T</font></a> 
    -+<a href="#W"><font size="-2">W</font></a> 
    -+ <a href="#topheader"><font size="-2">TOP</font></a>
    -+<p><div style="line-height:1.5em;color:black">
    -+<A HREF="android.support.v4.view.ViewCompat.html" class="hiddenlink" target="rightframe">ViewCompat</A><br>
    -+<!-- Class ViewConfigurationCompat -->
    -+<A HREF="android.support.v4.view.ViewConfigurationCompat.html" class="hiddenlink" target="rightframe">ViewConfigurationCompat</A><br>
    -+<!-- Class WindowInsetsCompat -->
    -+<A NAME="W"></A>
    -+<br><font size="+2">W</font>&nbsp;
    -+<a href="#A"><font size="-2">A</font></a> 
    -+<a href="#B"><font size="-2">B</font></a> 
    -+<a href="#C"><font size="-2">C</font></a> 
    -+<a href="#D"><font size="-2">D</font></a> 
    -+<a href="#E"><font size="-2">E</font></a> 
    -+<a href="#F"><font size="-2">F</font></a> 
    -+<a href="#G"><font size="-2">G</font></a> 
    -+<a href="#H"><font size="-2">H</font></a> 
    -+<a href="#I"><font size="-2">I</font></a> 
    -+<a href="#K"><font size="-2">K</font></a> 
    -+<a href="#L"><font size="-2">L</font></a> 
    -+<a href="#M"><font size="-2">M</font></a> 
    -+<a href="#N"><font size="-2">N</font></a> 
    -+<a href="#O"><font size="-2">O</font></a> 
    -+<a href="#P"><font size="-2">P</font></a> 
    -+<a href="#R"><font size="-2">R</font></a> 
    -+<a href="#S"><font size="-2">S</font></a> 
    -+<a href="#T"><font size="-2">T</font></a> 
    -+<a href="#V"><font size="-2">V</font></a> 
    -+ <a href="#topheader"><font size="-2">TOP</font></a>
    -+<p><div style="line-height:1.5em;color:black">
    -+<i>WindowInsetsCompat</i><br>
    -+&nbsp;&nbsp;<A HREF="android.support.v4.view.WindowInsetsCompat.html" class="hiddenlink" target="rightframe">android.support.v4.view</A><br>
    -+<!-- Constructor WindowInsetsCompat -->
    -+&nbsp;&nbsp;<nobr><A HREF="android.support.v4.view.WindowInsetsCompat.html#android.support.v4.view.WindowInsetsCompat.ctor_added(android.support.v4.view.WindowInsetsCompat)" class="hiddenlink" target="rightframe"><b>WindowInsetsCompat</b>
    -+(<code>WindowInsetsCompat</code>)</A></nobr>&nbsp;constructor<br>
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    -+</script>
    -+<script type="text/javascript">
    -+  try {
    -+    var pageTracker = _gat._getTracker("UA-5831155-1");
    -+    pageTracker._setAllowAnchor(true);
    -+    pageTracker._initData();
    -+    pageTracker._trackPageview();
    -+  } catch(e) {}
    -+</script>
    -+</BODY>
    -+</HTML>
    -diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/alldiffs_index_changes.html b/docs/html/sdk/support_api_diff/24.2.0/changes/alldiffs_index_changes.html
    -new file mode 100644
    -index 0000000..4718b46
    ---- /dev/null
    -+++ b/docs/html/sdk/support_api_diff/24.2.0/changes/alldiffs_index_changes.html
    -@@ -0,0 +1,666 @@
    -+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
    -+<HTML style="overflow:auto;">
    -+<HEAD>
    -+<meta name="generator" content="JDiff v1.1.0">
    -+<!-- Generated by the JDiff Javadoc doclet -->
    -+<!-- (http://www.jdiff.org) -->
    -+<meta name="description" content="JDiff is a Javadoc doclet which generates an HTML report of all the packages, classes, constructors, methods, and fields which have been removed, added or changed in any way, including their documentation, when two APIs are compared.">
    -+<meta name="keywords" content="diff, jdiff, javadiff, java diff, java difference, API difference, difference between two APIs, API diff, Javadoc, doclet">
    -+<TITLE>
    -+All Changes Index
    -+</TITLE>
    -+<link href="../../../../assets/android-developer-docs.css" rel="stylesheet" type="text/css" />
    -+<link href="../stylesheet-jdiff.css" rel="stylesheet" type="text/css" />
    -+<noscript>
    -+<style type="text/css">
    -+body{overflow:auto;}
    -+#body-content{position:relative; top:0;}
    -+#doc-content{overflow:visible;border-left:3px solid #666;}
    -+#side-nav{padding:0;}
    -+#side-nav .toggle-list ul {display:block;}
    -+#resize-packages-nav{border-bottom:3px solid #666;}
    -+</style>
    -+</noscript>
    -+<style type="text/css">
    -+</style>
    -+</HEAD>
    -+<BODY class="gc-documentation" style="padding:12px;">
    -+<a NAME="topheader"></a>
    -+<table summary="Index for All Differences" width="100%" class="jdiffIndex" border="0" cellspacing="0" cellpadding="0" style="padding-bottom:0;margin-bottom:0;">
    -+  <tr>
    -+  <th class="indexHeader">
    -+    Filter the Index:
    -+  </th>
    -+  </tr>
    -+  <tr>
    -+  <td class="indexText" style="line-height:1.3em;padding-left:2em;">
    -+<a href="alldiffs_index_all.html" xclass="hiddenlink">All Differences</a>
    -+  <br>
    -+<A HREF="alldiffs_index_removals.html" xclass="hiddenlink">Removals</A>
    -+  <br>
    -+<A HREF="alldiffs_index_additions.html"xclass="hiddenlink">Additions</A>
    -+  <br>
    -+<b>Changes</b>
    -+  </td>
    -+  </tr>
    -+</table>
    -+<div id="indexTableCaption" style="background-color:#eee;padding:0 4px 0 4px;font-size:11px;margin-bottom:1em;">
    -+Listed as: <span style="color:#069"><strong>Added</strong></span>,  <span style="color:#069"><strike>Removed</strike></span>,  <span style="color:#069">Changed</span></font>
    -+</div>
    -+<!-- Class AbstractMediaItemPresenter -->
    -+<A NAME="A"></A>
    -+<br><font size="+2">A</font>&nbsp;
    -+<a href="#B"><font size="-2">B</font></a> 
    -+<a href="#C"><font size="-2">C</font></a> 
    -+<a href="#D"><font size="-2">D</font></a> 
    -+<a href="#F"><font size="-2">F</font></a> 
    -+<a href="#G"><font size="-2">G</font></a> 
    -+<a href="#I"><font size="-2">I</font></a> 
    -+<a href="#K"><font size="-2">K</font></a> 
    -+<a href="#L"><font size="-2">L</font></a> 
    -+<a href="#M"><font size="-2">M</font></a> 
    -+<a href="#O"><font size="-2">O</font></a> 
    -+<a href="#P"><font size="-2">P</font></a> 
    -+<a href="#R"><font size="-2">R</font></a> 
    -+<a href="#S"><font size="-2">S</font></a> 
    -+<a href="#T"><font size="-2">T</font></a> 
    -+<a href="#V"><font size="-2">V</font></a> 
    -+<a href="#W"><font size="-2">W</font></a> 
    -+ <a href="#topheader"><font size="-2">TOP</font></a>
    -+<p><div style="line-height:1.5em;color:black">
    -+<A HREF="android.support.v17.leanback.widget.AbstractMediaItemPresenter.html" class="hiddenlink" target="rightframe">AbstractMediaItemPresenter</A><br>
    -+<!-- Class AbstractMediaItemPresenter.ViewHolder -->
    -+<A HREF="android.support.v17.leanback.widget.AbstractMediaItemPresenter.ViewHolder.html" class="hiddenlink" target="rightframe">AbstractMediaItemPresenter.ViewHolder</A><br>
    -+<!-- Class AccessibilityEventCompat -->
    -+<A HREF="android.support.v4.view.accessibility.AccessibilityEventCompat.html" class="hiddenlink" target="rightframe">AccessibilityEventCompat</A><br>
    -+<!-- Class AccessibilityManagerCompat -->
    -+<A HREF="android.support.v4.view.accessibility.AccessibilityManagerCompat.html" class="hiddenlink" target="rightframe">AccessibilityManagerCompat</A><br>
    -+<!-- Class AccessibilityManagerCompat.AccessibilityStateChangeListenerCompat -->
    -+<A HREF="android.support.v4.view.accessibility.AccessibilityManagerCompat.AccessibilityStateChangeListenerCompat.html" class="hiddenlink" target="rightframe">AccessibilityManagerCompat.AccessibilityStateChangeListenerCompat</A><br>
    -+<!-- Class AccessibilityNodeInfoCompat -->
    -+<A HREF="android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.html" class="hiddenlink" target="rightframe">AccessibilityNodeInfoCompat</A><br>
    -+<!-- Class AccessibilityNodeInfoCompat.AccessibilityActionCompat -->
    -+<A HREF="android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat.html" class="hiddenlink" target="rightframe">AccessibilityNodeInfoCompat.AccessibilityActionCompat</A><br>
    -+<!-- Class AccessibilityNodeInfoCompat.CollectionInfoCompat -->
    -+<A HREF="android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.CollectionInfoCompat.html" class="hiddenlink" target="rightframe">AccessibilityNodeInfoCompat.CollectionInfoCompat</A><br>
    -+<!-- Class AccessibilityNodeInfoCompat.CollectionItemInfoCompat -->
    -+<A HREF="android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.CollectionItemInfoCompat.html" class="hiddenlink" target="rightframe">AccessibilityNodeInfoCompat.CollectionItemInfoCompat</A><br>
    -+<!-- Class AccessibilityNodeInfoCompat.RangeInfoCompat -->
    -+<A HREF="android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.RangeInfoCompat.html" class="hiddenlink" target="rightframe">AccessibilityNodeInfoCompat.RangeInfoCompat</A><br>
    -+<!-- Class AccessibilityNodeProviderCompat -->
    -+<A HREF="android.support.v4.view.accessibility.AccessibilityNodeProviderCompat.html" class="hiddenlink" target="rightframe">AccessibilityNodeProviderCompat</A><br>
    -+<!-- Class AccessibilityServiceInfoCompat -->
    -+<A HREF="android.support.v4.accessibilityservice.AccessibilityServiceInfoCompat.html" class="hiddenlink" target="rightframe">AccessibilityServiceInfoCompat</A><br>
    -+<!-- Class AccessibilityWindowInfoCompat -->
    -+<A HREF="android.support.v4.view.accessibility.AccessibilityWindowInfoCompat.html" class="hiddenlink" target="rightframe">AccessibilityWindowInfoCompat</A><br>
    -+<!-- Class ActionBarDrawerToggle -->
    -+<A HREF="android.support.v7.app.ActionBarDrawerToggle.html" class="hiddenlink" target="rightframe">ActionBarDrawerToggle</A><br>
    -+<!-- Class ActivityCompat -->
    -+<i>ActivityCompat</i><br>
    -+&nbsp;&nbsp;<A HREF="android.support.v4.app.ActivityCompat.html" class="hiddenlink" target="rightframe">android.support.v4.app</A><br>
    -+<!-- Constructor ActivityCompat -->
    -+&nbsp;&nbsp;<nobr><A HREF="android.support.v4.app.ActivityCompat.html#android.support.v4.app.ActivityCompat.ctor_changed()" class="hiddenlink" target="rightframe">ActivityCompat
    -+()</A></nobr>&nbsp;constructor<br>
    -+<!-- Class ActivityOptionsCompat -->
    -+<A HREF="android.support.v4.app.ActivityOptionsCompat.html" class="hiddenlink" target="rightframe">ActivityOptionsCompat</A><br>
    -+<!-- Method addAccessibilityStateChangeListener -->
    -+<nobr><A HREF="android.support.v4.view.accessibility.AccessibilityManagerCompat.html#android.support.v4.view.accessibility.AccessibilityManagerCompat.addAccessibilityStateChangeListener_changed(android.view.accessibility.AccessibilityManager, android.support.v4.view.accessibility.AccessibilityManagerCompat.AccessibilityStateChangeListener)" class="hiddenlink" target="rightframe">addAccessibilityStateChangeListener
    -+(<code>AccessibilityManager, AccessibilityStateChangeListener</code>)</A></nobr><br>
    -+<!-- Package android.support.customtabs -->
    -+<A HREF="pkg_android.support.customtabs.html" class="hiddenlink" target="rightframe">android.support.customtabs</A><br>
    -+<!-- Package android.support.design.widget -->
    -+<A HREF="pkg_android.support.design.widget.html" class="hiddenlink" target="rightframe">android.support.design.widget</A><br>
    -+<!-- Package android.support.v14.preference -->
    -+<A HREF="pkg_android.support.v14.preference.html" class="hiddenlink" target="rightframe">android.support.v14.preference</A><br>
    -+<!-- Package android.support.v17.leanback.widget -->
    -+<A HREF="pkg_android.support.v17.leanback.widget.html" class="hiddenlink" target="rightframe">android.support.v17.leanback.widget</A><br>
    -+<!-- Package android.support.v17.preference -->
    -+<A HREF="pkg_android.support.v17.preference.html" class="hiddenlink" target="rightframe">android.support.v17.preference</A><br>
    -+<!-- Package android.support.v4.accessibilityservice -->
    -+<A HREF="pkg_android.support.v4.accessibilityservice.html" class="hiddenlink" target="rightframe">android.support.v4.accessibilityservice</A><br>
    -+<!-- Package android.support.v4.app -->
    -+<A HREF="pkg_android.support.v4.app.html" class="hiddenlink" target="rightframe">android.support.v4.app</A><br>
    -+<!-- Package android.support.v4.content -->
    -+<A HREF="pkg_android.support.v4.content.html" class="hiddenlink" target="rightframe">android.support.v4.content</A><br>
    -+<!-- Package android.support.v4.graphics.drawable -->
    -+<A HREF="pkg_android.support.v4.graphics.drawable.html" class="hiddenlink" target="rightframe">android.support.v4.graphics.drawable</A><br>
    -+<!-- Package android.support.v4.media -->
    -+<A HREF="pkg_android.support.v4.media.html" class="hiddenlink" target="rightframe">android.support.v4.media</A><br>
    -+<!-- Package android.support.v4.media.session -->
    -+<A HREF="pkg_android.support.v4.media.session.html" class="hiddenlink" target="rightframe">android.support.v4.media.session</A><br>
    -+<!-- Package android.support.v4.os -->
    -+<A HREF="pkg_android.support.v4.os.html" class="hiddenlink" target="rightframe">android.support.v4.os</A><br>
    -+<!-- Package android.support.v4.util -->
    -+<A HREF="pkg_android.support.v4.util.html" class="hiddenlink" target="rightframe">android.support.v4.util</A><br>
    -+<!-- Package android.support.v4.view -->
    -+<A HREF="pkg_android.support.v4.view.html" class="hiddenlink" target="rightframe">android.support.v4.view</A><br>
    -+<!-- Package android.support.v4.view.accessibility -->
    -+<A HREF="pkg_android.support.v4.view.accessibility.html" class="hiddenlink" target="rightframe">android.support.v4.view.accessibility</A><br>
    -+<!-- Package android.support.v4.widget -->
    -+<A HREF="pkg_android.support.v4.widget.html" class="hiddenlink" target="rightframe">android.support.v4.widget</A><br>
    -+<!-- Package android.support.v7.app -->
    -+<A HREF="pkg_android.support.v7.app.html" class="hiddenlink" target="rightframe">android.support.v7.app</A><br>
    -+<!-- Package android.support.v7.content.res -->
    -+<A HREF="pkg_android.support.v7.content.res.html" class="hiddenlink" target="rightframe">android.support.v7.content.res</A><br>
    -+<!-- Package android.support.v7.graphics -->
    -+<A HREF="pkg_android.support.v7.graphics.html" class="hiddenlink" target="rightframe">android.support.v7.graphics</A><br>
    -+<!-- Package android.support.v7.preference -->
    -+<A HREF="pkg_android.support.v7.preference.html" class="hiddenlink" target="rightframe">android.support.v7.preference</A><br>
    -+<!-- Package android.support.v7.util -->
    -+<A HREF="pkg_android.support.v7.util.html" class="hiddenlink" target="rightframe">android.support.v7.util</A><br>
    -+<!-- Package android.support.v7.widget -->
    -+<A HREF="pkg_android.support.v7.widget.html" class="hiddenlink" target="rightframe">android.support.v7.widget</A><br>
    -+<!-- Class AppBarLayout.ScrollingViewBehavior -->
    -+<A HREF="android.support.design.widget.AppBarLayout.ScrollingViewBehavior.html" class="hiddenlink" target="rightframe">AppBarLayout.ScrollingViewBehavior</A><br>
    -+<!-- Class AppCompatDelegate -->
    -+<A HREF="android.support.v7.app.AppCompatDelegate.html" class="hiddenlink" target="rightframe">AppCompatDelegate</A><br>
    -+<!-- Class AppCompatResources -->
    -+<A HREF="android.support.v7.content.res.AppCompatResources.html" class="hiddenlink" target="rightframe">AppCompatResources</A><br>
    -+<!-- Class BottomSheetBehavior -->
    -+<A NAME="B"></A>
    -+<br><font size="+2">B</font>&nbsp;
    -+<a href="#A"><font size="-2">A</font></a> 
    -+<a href="#C"><font size="-2">C</font></a> 
    -+<a href="#D"><font size="-2">D</font></a> 
    -+<a href="#F"><font size="-2">F</font></a> 
    -+<a href="#G"><font size="-2">G</font></a> 
    -+<a href="#I"><font size="-2">I</font></a> 
    -+<a href="#K"><font size="-2">K</font></a> 
    -+<a href="#L"><font size="-2">L</font></a> 
    -+<a href="#M"><font size="-2">M</font></a> 
    -+<a href="#O"><font size="-2">O</font></a> 
    -+<a href="#P"><font size="-2">P</font></a> 
    -+<a href="#R"><font size="-2">R</font></a> 
    -+<a href="#S"><font size="-2">S</font></a> 
    -+<a href="#T"><font size="-2">T</font></a> 
    -+<a href="#V"><font size="-2">V</font></a> 
    -+<a href="#W"><font size="-2">W</font></a> 
    -+ <a href="#topheader"><font size="-2">TOP</font></a>
    -+<p><div style="line-height:1.5em;color:black">
    -+<A HREF="android.support.design.widget.BottomSheetBehavior.html" class="hiddenlink" target="rightframe">BottomSheetBehavior</A><br>
    -+<!-- Class BuildCompat -->
    -+<A HREF="android.support.v4.os.BuildCompat.html" class="hiddenlink" target="rightframe">BuildCompat</A><br>
    -+<!-- Class CollapsingToolbarLayout -->
    -+<A NAME="C"></A>
    -+<br><font size="+2">C</font>&nbsp;
    -+<a href="#A"><font size="-2">A</font></a> 
    -+<a href="#B"><font size="-2">B</font></a> 
    -+<a href="#D"><font size="-2">D</font></a> 
    -+<a href="#F"><font size="-2">F</font></a> 
    -+<a href="#G"><font size="-2">G</font></a> 
    -+<a href="#I"><font size="-2">I</font></a> 
    -+<a href="#K"><font size="-2">K</font></a> 
    -+<a href="#L"><font size="-2">L</font></a> 
    -+<a href="#M"><font size="-2">M</font></a> 
    -+<a href="#O"><font size="-2">O</font></a> 
    -+<a href="#P"><font size="-2">P</font></a> 
    -+<a href="#R"><font size="-2">R</font></a> 
    -+<a href="#S"><font size="-2">S</font></a> 
    -+<a href="#T"><font size="-2">T</font></a> 
    -+<a href="#V"><font size="-2">V</font></a> 
    -+<a href="#W"><font size="-2">W</font></a> 
    -+ <a href="#topheader"><font size="-2">TOP</font></a>
    -+<p><div style="line-height:1.5em;color:black">
    -+<A HREF="android.support.design.widget.CollapsingToolbarLayout.html" class="hiddenlink" target="rightframe">CollapsingToolbarLayout</A><br>
    -+<!-- Method computeScrollVectorForPosition -->
    -+<nobr><A HREF="android.support.v7.widget.LinearSmoothScroller.html#android.support.v7.widget.LinearSmoothScroller.computeScrollVectorForPosition_changed(int)" class="hiddenlink" target="rightframe">computeScrollVectorForPosition
    -+(<code>int</code>)</A></nobr><br>
    -+<!-- Class ContextCompat -->
    -+<i>ContextCompat</i><br>
    -+&nbsp;&nbsp;<A HREF="android.support.v4.content.ContextCompat.html" class="hiddenlink" target="rightframe">android.support.v4.content</A><br>
    -+<!-- Constructor ContextCompat -->
    -+&nbsp;&nbsp;<nobr><A HREF="android.support.v4.content.ContextCompat.html#android.support.v4.content.ContextCompat.ctor_changed()" class="hiddenlink" target="rightframe">ContextCompat
    -+()</A></nobr>&nbsp;constructor<br>
    -+<!-- Class CoordinatorLayout -->
    -+<A HREF="android.support.design.widget.CoordinatorLayout.html" class="hiddenlink" target="rightframe">CoordinatorLayout</A><br>
    -+<!-- Class CoordinatorLayout.Behavior -->
    -+<A HREF="android.support.design.widget.CoordinatorLayout.Behavior.html" class="hiddenlink" target="rightframe">CoordinatorLayout.Behavior</A><br>
    -+<!-- Class CoordinatorLayout.LayoutParams -->
    -+<A HREF="android.support.design.widget.CoordinatorLayout.LayoutParams.html" class="hiddenlink" target="rightframe">CoordinatorLayout.LayoutParams</A><br>
    -+<!-- Class CustomTabsIntent -->
    -+<A HREF="android.support.customtabs.CustomTabsIntent.html" class="hiddenlink" target="rightframe">CustomTabsIntent</A><br>
    -+<!-- Class CustomTabsIntent.Builder -->
    -+<A HREF="android.support.customtabs.CustomTabsIntent.Builder.html" class="hiddenlink" target="rightframe">CustomTabsIntent.Builder</A><br>
    -+<!-- Class CustomTabsSession -->
    -+<A HREF="android.support.customtabs.CustomTabsSession.html" class="hiddenlink" target="rightframe">CustomTabsSession</A><br>
    -+<!-- Method dispatch -->
    -+<A NAME="D"></A>
    -+<br><font size="+2">D</font>&nbsp;
    -+<a href="#A"><font size="-2">A</font></a> 
    -+<a href="#B"><font size="-2">B</font></a> 
    -+<a href="#C"><font size="-2">C</font></a> 
    -+<a href="#F"><font size="-2">F</font></a> 
    -+<a href="#G"><font size="-2">G</font></a> 
    -+<a href="#I"><font size="-2">I</font></a> 
    -+<a href="#K"><font size="-2">K</font></a> 
    -+<a href="#L"><font size="-2">L</font></a> 
    -+<a href="#M"><font size="-2">M</font></a> 
    -+<a href="#O"><font size="-2">O</font></a> 
    -+<a href="#P"><font size="-2">P</font></a> 
    -+<a href="#R"><font size="-2">R</font></a> 
    -+<a href="#S"><font size="-2">S</font></a> 
    -+<a href="#T"><font size="-2">T</font></a> 
    -+<a href="#V"><font size="-2">V</font></a> 
    -+<a href="#W"><font size="-2">W</font></a> 
    -+ <a href="#topheader"><font size="-2">TOP</font></a>
    -+<p><div style="line-height:1.5em;color:black">
    -+<nobr><A HREF="android.support.v4.view.KeyEventCompat.html#android.support.v4.view.KeyEventCompat.dispatch_changed(android.view.KeyEvent, android.view.KeyEvent.Callback, java.lang.Object, java.lang.Object)" class="hiddenlink" target="rightframe">dispatch
    -+(<code>KeyEvent, Callback, Object, Object</code>)</A></nobr><br>
    -+<!-- Class DrawableCompat -->
    -+<A HREF="android.support.v4.graphics.drawable.DrawableCompat.html" class="hiddenlink" target="rightframe">DrawableCompat</A><br>
    -+<!-- Method findPointerIndex -->
    -+<A NAME="F"></A>
    -+<br><font size="+2">F</font>&nbsp;
    -+<a href="#A"><font size="-2">A</font></a> 
    -+<a href="#B"><font size="-2">B</font></a> 
    -+<a href="#C"><font size="-2">C</font></a> 
    -+<a href="#D"><font size="-2">D</font></a> 
    -+<a href="#G"><font size="-2">G</font></a> 
    -+<a href="#I"><font size="-2">I</font></a> 
    -+<a href="#K"><font size="-2">K</font></a> 
    -+<a href="#L"><font size="-2">L</font></a> 
    -+<a href="#M"><font size="-2">M</font></a> 
    -+<a href="#O"><font size="-2">O</font></a> 
    -+<a href="#P"><font size="-2">P</font></a> 
    -+<a href="#R"><font size="-2">R</font></a> 
    -+<a href="#S"><font size="-2">S</font></a> 
    -+<a href="#T"><font size="-2">T</font></a> 
    -+<a href="#V"><font size="-2">V</font></a> 
    -+<a href="#W"><font size="-2">W</font></a> 
    -+ <a href="#topheader"><font size="-2">TOP</font></a>
    -+<p><div style="line-height:1.5em;color:black">
    -+<nobr><A HREF="android.support.v4.view.MotionEventCompat.html#android.support.v4.view.MotionEventCompat.findPointerIndex_changed(android.view.MotionEvent, int)" class="hiddenlink" target="rightframe">findPointerIndex
    -+(<code>MotionEvent, int</code>)</A></nobr><br>
    -+<!-- Class FloatingActionButton.Behavior -->
    -+<A HREF="android.support.design.widget.FloatingActionButton.Behavior.html" class="hiddenlink" target="rightframe">FloatingActionButton.Behavior</A><br>
    -+<!-- Class FragmentController -->
    -+<A HREF="android.support.v4.app.FragmentController.html" class="hiddenlink" target="rightframe">FragmentController</A><br>
    -+<!-- Method getDescription -->
    -+<A NAME="G"></A>
    -+<br><font size="+2">G</font>&nbsp;
    -+<a href="#A"><font size="-2">A</font></a> 
    -+<a href="#B"><font size="-2">B</font></a> 
    -+<a href="#C"><font size="-2">C</font></a> 
    -+<a href="#D"><font size="-2">D</font></a> 
    -+<a href="#F"><font size="-2">F</font></a> 
    -+<a href="#I"><font size="-2">I</font></a> 
    -+<a href="#K"><font size="-2">K</font></a> 
    -+<a href="#L"><font size="-2">L</font></a> 
    -+<a href="#M"><font size="-2">M</font></a> 
    -+<a href="#O"><font size="-2">O</font></a> 
    -+<a href="#P"><font size="-2">P</font></a> 
    -+<a href="#R"><font size="-2">R</font></a> 
    -+<a href="#S"><font size="-2">S</font></a> 
    -+<a href="#T"><font size="-2">T</font></a> 
    -+<a href="#V"><font size="-2">V</font></a> 
    -+<a href="#W"><font size="-2">W</font></a> 
    -+ <a href="#topheader"><font size="-2">TOP</font></a>
    -+<p><div style="line-height:1.5em;color:black">
    -+<nobr><A HREF="android.support.v4.accessibilityservice.AccessibilityServiceInfoCompat.html#android.support.v4.accessibilityservice.AccessibilityServiceInfoCompat.getDescription_changed(android.accessibilityservice.AccessibilityServiceInfo)" class="hiddenlink" target="rightframe">getDescription
    -+(<code>AccessibilityServiceInfo</code>)</A></nobr><br>
    -+<!-- Method getKeyDispatcherState -->
    -+<nobr><A HREF="android.support.v4.view.KeyEventCompat.html#android.support.v4.view.KeyEventCompat.getKeyDispatcherState_changed(android.view.View)" class="hiddenlink" target="rightframe">getKeyDispatcherState
    -+(<code>View</code>)</A></nobr><br>
    -+<!-- Method getOverScrollMode -->
    -+<nobr><A HREF="android.support.v4.view.ViewCompat.html#android.support.v4.view.ViewCompat.getOverScrollMode_changed(android.view.View)" class="hiddenlink" target="rightframe">getOverScrollMode
    -+(<code>View</code>)</A></nobr><br>
    -+<!-- Method getPointerCount -->
    -+<nobr><A HREF="android.support.v4.view.MotionEventCompat.html#android.support.v4.view.MotionEventCompat.getPointerCount_changed(android.view.MotionEvent)" class="hiddenlink" target="rightframe">getPointerCount
    -+(<code>MotionEvent</code>)</A></nobr><br>
    -+<!-- Method getPointerId -->
    -+<nobr><A HREF="android.support.v4.view.MotionEventCompat.html#android.support.v4.view.MotionEventCompat.getPointerId_changed(android.view.MotionEvent, int)" class="hiddenlink" target="rightframe">getPointerId
    -+(<code>MotionEvent, int</code>)</A></nobr><br>
    -+<!-- Method getReferrer -->
    -+<nobr><A HREF="android.support.v4.app.ActivityCompat.html#android.support.v4.app.ActivityCompat.getReferrer_changed(android.app.Activity)" class="hiddenlink" target="rightframe">getReferrer
    -+(<code>Activity</code>)</A></nobr><br>
    -+<!-- Method getScaledPagingTouchSlop -->
    -+<nobr><A HREF="android.support.v4.view.ViewConfigurationCompat.html#android.support.v4.view.ViewConfigurationCompat.getScaledPagingTouchSlop_changed(android.view.ViewConfiguration)" class="hiddenlink" target="rightframe">getScaledPagingTouchSlop
    -+(<code>ViewConfiguration</code>)</A></nobr><br>
    -+<!-- Method getSource -->
    -+<nobr><A HREF="android.support.v4.view.MotionEventCompat.html#android.support.v4.view.MotionEventCompat.getSource_changed(android.view.MotionEvent)" class="hiddenlink" target="rightframe">getSource
    -+(<code>MotionEvent</code>)</A></nobr><br>
    -+<!-- Method getX -->
    -+<nobr><A HREF="android.support.v4.view.MotionEventCompat.html#android.support.v4.view.MotionEventCompat.getX_changed(android.view.MotionEvent, int)" class="hiddenlink" target="rightframe">getX
    -+(<code>MotionEvent, int</code>)</A></nobr><br>
    -+<!-- Method getY -->
    -+<nobr><A HREF="android.support.v4.view.MotionEventCompat.html#android.support.v4.view.MotionEventCompat.getY_changed(android.view.MotionEvent, int)" class="hiddenlink" target="rightframe">getY
    -+(<code>MotionEvent, int</code>)</A></nobr><br>
    -+<!-- Method isDirty -->
    -+<A NAME="I"></A>
    -+<br><font size="+2">I</font>&nbsp;
    -+<a href="#A"><font size="-2">A</font></a> 
    -+<a href="#B"><font size="-2">B</font></a> 
    -+<a href="#C"><font size="-2">C</font></a> 
    -+<a href="#D"><font size="-2">D</font></a> 
    -+<a href="#F"><font size="-2">F</font></a> 
    -+<a href="#G"><font size="-2">G</font></a> 
    -+<a href="#K"><font size="-2">K</font></a> 
    -+<a href="#L"><font size="-2">L</font></a> 
    -+<a href="#M"><font size="-2">M</font></a> 
    -+<a href="#O"><font size="-2">O</font></a> 
    -+<a href="#P"><font size="-2">P</font></a> 
    -+<a href="#R"><font size="-2">R</font></a> 
    -+<a href="#S"><font size="-2">S</font></a> 
    -+<a href="#T"><font size="-2">T</font></a> 
    -+<a href="#V"><font size="-2">V</font></a> 
    -+<a href="#W"><font size="-2">W</font></a> 
    -+ <a href="#topheader"><font size="-2">TOP</font></a>
    -+<p><div style="line-height:1.5em;color:black">
    -+<nobr><A HREF="android.support.design.widget.CoordinatorLayout.Behavior.html#android.support.design.widget.CoordinatorLayout.Behavior.isDirty_changed(android.support.design.widget.CoordinatorLayout, V)" class="hiddenlink" target="rightframe">isDirty
    -+(<code>CoordinatorLayout, V</code>)</A></nobr><br>
    -+<!-- Method isOpaque -->
    -+<nobr><A HREF="android.support.v4.view.ViewCompat.html#android.support.v4.view.ViewCompat.isOpaque_changed(android.view.View)" class="hiddenlink" target="rightframe">isOpaque
    -+(<code>View</code>)</A></nobr><br>
    -+<!-- Method isTracking -->
    -+<nobr><A HREF="android.support.v4.view.KeyEventCompat.html#android.support.v4.view.KeyEventCompat.isTracking_changed(android.view.KeyEvent)" class="hiddenlink" target="rightframe">isTracking
    -+(<code>KeyEvent</code>)</A></nobr><br>
    -+<!-- Class KeyEventCompat -->
    -+<A NAME="K"></A>
    -+<br><font size="+2">K</font>&nbsp;
    -+<a href="#A"><font size="-2">A</font></a> 
    -+<a href="#B"><font size="-2">B</font></a> 
    -+<a href="#C"><font size="-2">C</font></a> 
    -+<a href="#D"><font size="-2">D</font></a> 
    -+<a href="#F"><font size="-2">F</font></a> 
    -+<a href="#G"><font size="-2">G</font></a> 
    -+<a href="#I"><font size="-2">I</font></a> 
    -+<a href="#L"><font size="-2">L</font></a> 
    -+<a href="#M"><font size="-2">M</font></a> 
    -+<a href="#O"><font size="-2">O</font></a> 
    -+<a href="#P"><font size="-2">P</font></a> 
    -+<a href="#R"><font size="-2">R</font></a> 
    -+<a href="#S"><font size="-2">S</font></a> 
    -+<a href="#T"><font size="-2">T</font></a> 
    -+<a href="#V"><font size="-2">V</font></a> 
    -+<a href="#W"><font size="-2">W</font></a> 
    -+ <a href="#topheader"><font size="-2">TOP</font></a>
    -+<p><div style="line-height:1.5em;color:black">
    -+<A HREF="android.support.v4.view.KeyEventCompat.html" class="hiddenlink" target="rightframe">KeyEventCompat</A><br>
    -+<!-- Class LeanbackSettingsFragment -->
    -+<A NAME="L"></A>
    -+<br><font size="+2">L</font>&nbsp;
    -+<a href="#A"><font size="-2">A</font></a> 
    -+<a href="#B"><font size="-2">B</font></a> 
    -+<a href="#C"><font size="-2">C</font></a> 
    -+<a href="#D"><font size="-2">D</font></a> 
    -+<a href="#F"><font size="-2">F</font></a> 
    -+<a href="#G"><font size="-2">G</font></a> 
    -+<a href="#I"><font size="-2">I</font></a> 
    -+<a href="#K"><font size="-2">K</font></a> 
    -+<a href="#M"><font size="-2">M</font></a> 
    -+<a href="#O"><font size="-2">O</font></a> 
    -+<a href="#P"><font size="-2">P</font></a> 
    -+<a href="#R"><font size="-2">R</font></a> 
    -+<a href="#S"><font size="-2">S</font></a> 
    -+<a href="#T"><font size="-2">T</font></a> 
    -+<a href="#V"><font size="-2">V</font></a> 
    -+<a href="#W"><font size="-2">W</font></a> 
    -+ <a href="#topheader"><font size="-2">TOP</font></a>
    -+<p><div style="line-height:1.5em;color:black">
    -+<A HREF="android.support.v17.preference.LeanbackSettingsFragment.html" class="hiddenlink" target="rightframe">LeanbackSettingsFragment</A><br>
    -+<!-- Class LinearLayoutManager -->
    -+<A HREF="android.support.v7.widget.LinearLayoutManager.html" class="hiddenlink" target="rightframe">LinearLayoutManager</A><br>
    -+<!-- Class LinearSmoothScroller -->
    -+<A HREF="android.support.v7.widget.LinearSmoothScroller.html" class="hiddenlink" target="rightframe">LinearSmoothScroller</A><br>
    -+<!-- Class MediaBrowserCompat.MediaItem -->
    -+<A NAME="M"></A>
    -+<br><font size="+2">M</font>&nbsp;
    -+<a href="#A"><font size="-2">A</font></a> 
    -+<a href="#B"><font size="-2">B</font></a> 
    -+<a href="#C"><font size="-2">C</font></a> 
    -+<a href="#D"><font size="-2">D</font></a> 
    -+<a href="#F"><font size="-2">F</font></a> 
    -+<a href="#G"><font size="-2">G</font></a> 
    -+<a href="#I"><font size="-2">I</font></a> 
    -+<a href="#K"><font size="-2">K</font></a> 
    -+<a href="#L"><font size="-2">L</font></a> 
    -+<a href="#O"><font size="-2">O</font></a> 
    -+<a href="#P"><font size="-2">P</font></a> 
    -+<a href="#R"><font size="-2">R</font></a> 
    -+<a href="#S"><font size="-2">S</font></a> 
    -+<a href="#T"><font size="-2">T</font></a> 
    -+<a href="#V"><font size="-2">V</font></a> 
    -+<a href="#W"><font size="-2">W</font></a> 
    -+ <a href="#topheader"><font size="-2">TOP</font></a>
    -+<p><div style="line-height:1.5em;color:black">
    -+<A HREF="android.support.v4.media.MediaBrowserCompat.MediaItem.html" class="hiddenlink" target="rightframe">MediaBrowserCompat.MediaItem</A><br>
    -+<!-- Class MediaBrowserServiceCompat.BrowserRoot -->
    -+<A HREF="android.support.v4.media.MediaBrowserServiceCompat.BrowserRoot.html" class="hiddenlink" target="rightframe">MediaBrowserServiceCompat.BrowserRoot</A><br>
    -+<!-- Class MediaButtonReceiver -->
    -+<A HREF="android.support.v4.media.session.MediaButtonReceiver.html" class="hiddenlink" target="rightframe">MediaButtonReceiver</A><br>
    -+<!-- Class MediaDescriptionCompat -->
    -+<A HREF="android.support.v4.media.MediaDescriptionCompat.html" class="hiddenlink" target="rightframe">MediaDescriptionCompat</A><br>
    -+<!-- Class MediaMetadataCompat -->
    -+<A HREF="android.support.v4.media.MediaMetadataCompat.html" class="hiddenlink" target="rightframe">MediaMetadataCompat</A><br>
    -+<!-- Class MediaSessionCompat -->
    -+<A HREF="android.support.v4.media.session.MediaSessionCompat.html" class="hiddenlink" target="rightframe">MediaSessionCompat</A><br>
    -+<!-- Class MediaSessionCompat.QueueItem -->
    -+<A HREF="android.support.v4.media.session.MediaSessionCompat.QueueItem.html" class="hiddenlink" target="rightframe">MediaSessionCompat.QueueItem</A><br>
    -+<!-- Class MotionEventCompat -->
    -+<A HREF="android.support.v4.view.MotionEventCompat.html" class="hiddenlink" target="rightframe">MotionEventCompat</A><br>
    -+<!-- Class ObjectAdapter -->
    -+<A NAME="O"></A>
    -+<br><font size="+2">O</font>&nbsp;
    -+<a href="#A"><font size="-2">A</font></a> 
    -+<a href="#B"><font size="-2">B</font></a> 
    -+<a href="#C"><font size="-2">C</font></a> 
    -+<a href="#D"><font size="-2">D</font></a> 
    -+<a href="#F"><font size="-2">F</font></a> 
    -+<a href="#G"><font size="-2">G</font></a> 
    -+<a href="#I"><font size="-2">I</font></a> 
    -+<a href="#K"><font size="-2">K</font></a> 
    -+<a href="#L"><font size="-2">L</font></a> 
    -+<a href="#M"><font size="-2">M</font></a> 
    -+<a href="#P"><font size="-2">P</font></a> 
    -+<a href="#R"><font size="-2">R</font></a> 
    -+<a href="#S"><font size="-2">S</font></a> 
    -+<a href="#T"><font size="-2">T</font></a> 
    -+<a href="#V"><font size="-2">V</font></a> 
    -+<a href="#W"><font size="-2">W</font></a> 
    -+ <a href="#topheader"><font size="-2">TOP</font></a>
    -+<p><div style="line-height:1.5em;color:black">
    -+<A HREF="android.support.v17.leanback.widget.ObjectAdapter.html" class="hiddenlink" target="rightframe">ObjectAdapter</A><br>
    -+<!-- Method obtain -->
    -+<i>obtain</i><br>
    -+&nbsp;&nbsp;<nobr><A HREF="android.support.v4.media.session.MediaSessionCompat.html#android.support.v4.media.session.MediaSessionCompat.obtain_changed(android.content.Context, java.lang.Object)" class="hiddenlink" target="rightframe">type&nbsp;
    -+(<code>Context, Object</code>)&nbsp;in&nbsp;android.support.v4.media.session.MediaSessionCompat
    -+</A></nobr><br>
    -+<!-- Method obtain -->
    -+&nbsp;&nbsp;<nobr><A HREF="android.support.v4.media.session.MediaSessionCompat.QueueItem.html#android.support.v4.media.session.MediaSessionCompat.QueueItem.obtain_changed(java.lang.Object)" class="hiddenlink" target="rightframe">type&nbsp;
    -+(<code>Object</code>)&nbsp;in&nbsp;android.support.v4.media.session.MediaSessionCompat.QueueItem
    -+</A></nobr><br>
    -+<!-- Field OVER_SCROLL_ALWAYS -->
    -+<nobr><A HREF="android.support.v4.view.ViewCompat.html#android.support.v4.view.ViewCompat.OVER_SCROLL_ALWAYS" class="hiddenlink" target="rightframe">OVER_SCROLL_ALWAYS</A>
    -+</nobr><br>
    -+<!-- Field OVER_SCROLL_IF_CONTENT_SCROLLS -->
    -+<nobr><A HREF="android.support.v4.view.ViewCompat.html#android.support.v4.view.ViewCompat.OVER_SCROLL_IF_CONTENT_SCROLLS" class="hiddenlink" target="rightframe">OVER_SCROLL_IF_CONTENT_SCROLLS</A>
    -+</nobr><br>
    -+<!-- Field OVER_SCROLL_NEVER -->
    -+<nobr><A HREF="android.support.v4.view.ViewCompat.html#android.support.v4.view.ViewCompat.OVER_SCROLL_NEVER" class="hiddenlink" target="rightframe">OVER_SCROLL_NEVER</A>
    -+</nobr><br>
    -+<!-- Class Palette -->
    -+<A NAME="P"></A>
    -+<br><font size="+2">P</font>&nbsp;
    -+<a href="#A"><font size="-2">A</font></a> 
    -+<a href="#B"><font size="-2">B</font></a> 
    -+<a href="#C"><font size="-2">C</font></a> 
    -+<a href="#D"><font size="-2">D</font></a> 
    -+<a href="#F"><font size="-2">F</font></a> 
    -+<a href="#G"><font size="-2">G</font></a> 
    -+<a href="#I"><font size="-2">I</font></a> 
    -+<a href="#K"><font size="-2">K</font></a> 
    -+<a href="#L"><font size="-2">L</font></a> 
    -+<a href="#M"><font size="-2">M</font></a> 
    -+<a href="#O"><font size="-2">O</font></a> 
    -+<a href="#R"><font size="-2">R</font></a> 
    -+<a href="#S"><font size="-2">S</font></a> 
    -+<a href="#T"><font size="-2">T</font></a> 
    -+<a href="#V"><font size="-2">V</font></a> 
    -+<a href="#W"><font size="-2">W</font></a> 
    -+ <a href="#topheader"><font size="-2">TOP</font></a>
    -+<p><div style="line-height:1.5em;color:black">
    -+<A HREF="android.support.v7.graphics.Palette.html" class="hiddenlink" target="rightframe">Palette</A><br>
    -+<!-- Class PlaybackStateCompat -->
    -+<A HREF="android.support.v4.media.session.PlaybackStateCompat.html" class="hiddenlink" target="rightframe">PlaybackStateCompat</A><br>
    -+<!-- Class PreferenceFragment -->
    -+<A HREF="android.support.v14.preference.PreferenceFragment.html" class="hiddenlink" target="rightframe">PreferenceFragment</A><br>
    -+<!-- Class RecyclerView -->
    -+<A NAME="R"></A>
    -+<br><font size="+2">R</font>&nbsp;
    -+<a href="#A"><font size="-2">A</font></a> 
    -+<a href="#B"><font size="-2">B</font></a> 
    -+<a href="#C"><font size="-2">C</font></a> 
    -+<a href="#D"><font size="-2">D</font></a> 
    -+<a href="#F"><font size="-2">F</font></a> 
    -+<a href="#G"><font size="-2">G</font></a> 
    -+<a href="#I"><font size="-2">I</font></a> 
    -+<a href="#K"><font size="-2">K</font></a> 
    -+<a href="#L"><font size="-2">L</font></a> 
    -+<a href="#M"><font size="-2">M</font></a> 
    -+<a href="#O"><font size="-2">O</font></a> 
    -+<a href="#P"><font size="-2">P</font></a> 
    -+<a href="#S"><font size="-2">S</font></a> 
    -+<a href="#T"><font size="-2">T</font></a> 
    -+<a href="#V"><font size="-2">V</font></a> 
    -+<a href="#W"><font size="-2">W</font></a> 
    -+ <a href="#topheader"><font size="-2">TOP</font></a>
    -+<p><div style="line-height:1.5em;color:black">
    -+<A HREF="android.support.v7.widget.RecyclerView.html" class="hiddenlink" target="rightframe">RecyclerView</A><br>
    -+<!-- Method removeAccessibilityStateChangeListener -->
    -+<nobr><A HREF="android.support.v4.view.accessibility.AccessibilityManagerCompat.html#android.support.v4.view.accessibility.AccessibilityManagerCompat.removeAccessibilityStateChangeListener_changed(android.view.accessibility.AccessibilityManager, android.support.v4.view.accessibility.AccessibilityManagerCompat.AccessibilityStateChangeListener)" class="hiddenlink" target="rightframe">removeAccessibilityStateChangeListener
    -+(<code>AccessibilityManager, AccessibilityStateChangeListener</code>)</A></nobr><br>
    -+<!-- Class SearchViewCompat -->
    -+<A NAME="S"></A>
    -+<br><font size="+2">S</font>&nbsp;
    -+<a href="#A"><font size="-2">A</font></a> 
    -+<a href="#B"><font size="-2">B</font></a> 
    -+<a href="#C"><font size="-2">C</font></a> 
    -+<a href="#D"><font size="-2">D</font></a> 
    -+<a href="#F"><font size="-2">F</font></a> 
    -+<a href="#G"><font size="-2">G</font></a> 
    -+<a href="#I"><font size="-2">I</font></a> 
    -+<a href="#K"><font size="-2">K</font></a> 
    -+<a href="#L"><font size="-2">L</font></a> 
    -+<a href="#M"><font size="-2">M</font></a> 
    -+<a href="#O"><font size="-2">O</font></a> 
    -+<a href="#P"><font size="-2">P</font></a> 
    -+<a href="#R"><font size="-2">R</font></a> 
    -+<a href="#T"><font size="-2">T</font></a> 
    -+<a href="#V"><font size="-2">V</font></a> 
    -+<a href="#W"><font size="-2">W</font></a> 
    -+ <a href="#topheader"><font size="-2">TOP</font></a>
    -+<p><div style="line-height:1.5em;color:black">
    -+<A HREF="android.support.v4.widget.SearchViewCompat.html" class="hiddenlink" target="rightframe">SearchViewCompat</A><br>
    -+<!-- Class SearchViewCompat.OnCloseListenerCompat -->
    -+<A HREF="android.support.v4.widget.SearchViewCompat.OnCloseListenerCompat.html" class="hiddenlink" target="rightframe">SearchViewCompat.OnCloseListenerCompat</A><br>
    -+<!-- Class SearchViewCompat.OnQueryTextListenerCompat -->
    -+<A HREF="android.support.v4.widget.SearchViewCompat.OnQueryTextListenerCompat.html" class="hiddenlink" target="rightframe">SearchViewCompat.OnQueryTextListenerCompat</A><br>
    -+<!-- Class ServiceCompat -->
    -+<A HREF="android.support.v4.app.ServiceCompat.html" class="hiddenlink" target="rightframe">ServiceCompat</A><br>
    -+<!-- Method setOnCloseListener -->
    -+<nobr><A HREF="android.support.v4.widget.SearchViewCompat.html#android.support.v4.widget.SearchViewCompat.setOnCloseListener_changed(android.view.View, android.support.v4.widget.SearchViewCompat.OnCloseListener)" class="hiddenlink" target="rightframe">setOnCloseListener
    -+(<code>View, OnCloseListener</code>)</A></nobr><br>
    -+<!-- Method setOnQueryTextListener -->
    -+<nobr><A HREF="android.support.v4.widget.SearchViewCompat.html#android.support.v4.widget.SearchViewCompat.setOnQueryTextListener_changed(android.view.View, android.support.v4.widget.SearchViewCompat.OnQueryTextListener)" class="hiddenlink" target="rightframe">setOnQueryTextListener
    -+(<code>View, OnQueryTextListener</code>)</A></nobr><br>
    -+<!-- Method setOverScrollMode -->
    -+<nobr><A HREF="android.support.v4.view.ViewCompat.html#android.support.v4.view.ViewCompat.setOverScrollMode_changed(android.view.View, int)" class="hiddenlink" target="rightframe">setOverScrollMode
    -+(<code>View, int</code>)</A></nobr><br>
    -+<!-- Method setToolbarItem -->
    -+<nobr><A HREF="android.support.customtabs.CustomTabsSession.html#android.support.customtabs.CustomTabsSession.setToolbarItem_changed(int, android.graphics.Bitmap, java.lang.String)" class="hiddenlink" target="rightframe">setToolbarItem
    -+(<code>int, Bitmap, String</code>)</A></nobr><br>
    -+<!-- Class SharedElementCallback -->
    -+<A HREF="android.support.v4.app.SharedElementCallback.html" class="hiddenlink" target="rightframe">SharedElementCallback</A><br>
    -+<!-- Class SortedList.Callback -->
    -+<A HREF="android.support.v7.util.SortedList.Callback.html" class="hiddenlink" target="rightframe">SortedList.Callback</A><br>
    -+<!-- Class StaggeredGridLayoutManager -->
    -+<A HREF="android.support.v7.widget.StaggeredGridLayoutManager.html" class="hiddenlink" target="rightframe">StaggeredGridLayoutManager</A><br>
    -+<!-- Method startTracking -->
    -+<nobr><A HREF="android.support.v4.view.KeyEventCompat.html#android.support.v4.view.KeyEventCompat.startTracking_changed(android.view.KeyEvent)" class="hiddenlink" target="rightframe">startTracking
    -+(<code>KeyEvent</code>)</A></nobr><br>
    -+<!-- Class SwipeRefreshLayout -->
    -+<A HREF="android.support.v4.widget.SwipeRefreshLayout.html" class="hiddenlink" target="rightframe">SwipeRefreshLayout</A><br>
    -+<!-- Class TabLayout -->
    -+<A NAME="T"></A>
    -+<br><font size="+2">T</font>&nbsp;
    -+<a href="#A"><font size="-2">A</font></a> 
    -+<a href="#B"><font size="-2">B</font></a> 
    -+<a href="#C"><font size="-2">C</font></a> 
    -+<a href="#D"><font size="-2">D</font></a> 
    -+<a href="#F"><font size="-2">F</font></a> 
    -+<a href="#G"><font size="-2">G</font></a> 
    -+<a href="#I"><font size="-2">I</font></a> 
    -+<a href="#K"><font size="-2">K</font></a> 
    -+<a href="#L"><font size="-2">L</font></a> 
    -+<a href="#M"><font size="-2">M</font></a> 
    -+<a href="#O"><font size="-2">O</font></a> 
    -+<a href="#P"><font size="-2">P</font></a> 
    -+<a href="#R"><font size="-2">R</font></a> 
    -+<a href="#S"><font size="-2">S</font></a> 
    -+<a href="#V"><font size="-2">V</font></a> 
    -+<a href="#W"><font size="-2">W</font></a> 
    -+ <a href="#topheader"><font size="-2">TOP</font></a>
    -+<p><div style="line-height:1.5em;color:black">
    -+<A HREF="android.support.design.widget.TabLayout.html" class="hiddenlink" target="rightframe">TabLayout</A><br>
    -+<!-- Class TextInputLayout -->
    -+<A HREF="android.support.design.widget.TextInputLayout.html" class="hiddenlink" target="rightframe">TextInputLayout</A><br>
    -+<!-- Class TextViewCompat -->
    -+<A HREF="android.support.v4.widget.TextViewCompat.html" class="hiddenlink" target="rightframe">TextViewCompat</A><br>
    -+<!-- Class ViewCompat -->
    -+<A NAME="V"></A>
    -+<br><font size="+2">V</font>&nbsp;
    -+<a href="#A"><font size="-2">A</font></a> 
    -+<a href="#B"><font size="-2">B</font></a> 
    -+<a href="#C"><font size="-2">C</font></a> 
    -+<a href="#D"><font size="-2">D</font></a> 
    -+<a href="#F"><font size="-2">F</font></a> 
    -+<a href="#G"><font size="-2">G</font></a> 
    -+<a href="#I"><font size="-2">I</font></a> 
    -+<a href="#K"><font size="-2">K</font></a> 
    -+<a href="#L"><font size="-2">L</font></a> 
    -+<a href="#M"><font size="-2">M</font></a> 
    -+<a href="#O"><font size="-2">O</font></a> 
    -+<a href="#P"><font size="-2">P</font></a> 
    -+<a href="#R"><font size="-2">R</font></a> 
    -+<a href="#S"><font size="-2">S</font></a> 
    -+<a href="#T"><font size="-2">T</font></a> 
    -+<a href="#W"><font size="-2">W</font></a> 
    -+ <a href="#topheader"><font size="-2">TOP</font></a>
    -+<p><div style="line-height:1.5em;color:black">
    -+<A HREF="android.support.v4.view.ViewCompat.html" class="hiddenlink" target="rightframe">ViewCompat</A><br>
    -+<!-- Class ViewConfigurationCompat -->
    -+<A HREF="android.support.v4.view.ViewConfigurationCompat.html" class="hiddenlink" target="rightframe">ViewConfigurationCompat</A><br>
    -+<!-- Class WindowInsetsCompat -->
    -+<A NAME="W"></A>
    -+<br><font size="+2">W</font>&nbsp;
    -+<a href="#A"><font size="-2">A</font></a> 
    -+<a href="#B"><font size="-2">B</font></a> 
    -+<a href="#C"><font size="-2">C</font></a> 
    -+<a href="#D"><font size="-2">D</font></a> 
    -+<a href="#F"><font size="-2">F</font></a> 
    -+<a href="#G"><font size="-2">G</font></a> 
    -+<a href="#I"><font size="-2">I</font></a> 
    -+<a href="#K"><font size="-2">K</font></a> 
    -+<a href="#L"><font size="-2">L</font></a> 
    -+<a href="#M"><font size="-2">M</font></a> 
    -+<a href="#O"><font size="-2">O</font></a> 
    -+<a href="#P"><font size="-2">P</font></a> 
    -+<a href="#R"><font size="-2">R</font></a> 
    -+<a href="#S"><font size="-2">S</font></a> 
    -+<a href="#T"><font size="-2">T</font></a> 
    -+<a href="#V"><font size="-2">V</font></a> 
    -+ <a href="#topheader"><font size="-2">TOP</font></a>
    -+<p><div style="line-height:1.5em;color:black">
    -+<A HREF="android.support.v4.view.WindowInsetsCompat.html" class="hiddenlink" target="rightframe">WindowInsetsCompat</A><br>
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    -+</script>
    -+<script type="text/javascript">
    -+  try {
    -+    var pageTracker = _gat._getTracker("UA-5831155-1");
    -+    pageTracker._setAllowAnchor(true);
    -+    pageTracker._initData();
    -+    pageTracker._trackPageview();
    -+  } catch(e) {}
    -+</script>
    -+</BODY>
    -+</HTML>
    -diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/alldiffs_index_removals.html b/docs/html/sdk/support_api_diff/24.2.0/changes/alldiffs_index_removals.html
    -new file mode 100644
    -index 0000000..179472a
    ---- /dev/null
    -+++ b/docs/html/sdk/support_api_diff/24.2.0/changes/alldiffs_index_removals.html
    -@@ -0,0 +1,124 @@
    -+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
    -+<HTML style="overflow:auto;">
    -+<HEAD>
    -+<meta name="generator" content="JDiff v1.1.0">
    -+<!-- Generated by the JDiff Javadoc doclet -->
    -+<!-- (http://www.jdiff.org) -->
    -+<meta name="description" content="JDiff is a Javadoc doclet which generates an HTML report of all the packages, classes, constructors, methods, and fields which have been removed, added or changed in any way, including their documentation, when two APIs are compared.">
    -+<meta name="keywords" content="diff, jdiff, javadiff, java diff, java difference, API difference, difference between two APIs, API diff, Javadoc, doclet">
    -+<TITLE>
    -+All Removals Index
    -+</TITLE>
    -+<link href="../../../../assets/android-developer-docs.css" rel="stylesheet" type="text/css" />
    -+<link href="../stylesheet-jdiff.css" rel="stylesheet" type="text/css" />
    -+<noscript>
    -+<style type="text/css">
    -+body{overflow:auto;}
    -+#body-content{position:relative; top:0;}
    -+#doc-content{overflow:visible;border-left:3px solid #666;}
    -+#side-nav{padding:0;}
    -+#side-nav .toggle-list ul {display:block;}
    -+#resize-packages-nav{border-bottom:3px solid #666;}
    -+</style>
    -+</noscript>
    -+<style type="text/css">
    -+</style>
    -+</HEAD>
    -+<BODY class="gc-documentation" style="padding:12px;">
    -+<a NAME="topheader"></a>
    -+<table summary="Index for All Differences" width="100%" class="jdiffIndex" border="0" cellspacing="0" cellpadding="0" style="padding-bottom:0;margin-bottom:0;">
    -+  <tr>
    -+  <th class="indexHeader">
    -+    Filter the Index:
    -+  </th>
    -+  </tr>
    -+  <tr>
    -+  <td class="indexText" style="line-height:1.3em;padding-left:2em;">
    -+<a href="alldiffs_index_all.html" xclass="hiddenlink">All Differences</a>
    -+  <br>
    -+<b>Removals</b>
    -+  <br>
    -+<A HREF="alldiffs_index_additions.html"xclass="hiddenlink">Additions</A>
    -+  <br>
    -+<A HREF="alldiffs_index_changes.html"xclass="hiddenlink">Changes</A>
    -+  </td>
    -+  </tr>
    -+</table>
    -+<div id="indexTableCaption" style="background-color:#eee;padding:0 4px 0 4px;font-size:11px;margin-bottom:1em;">
    -+Listed as: <span style="color:#069"><strong>Added</strong></span>,  <span style="color:#069"><strike>Removed</strike></span>,  <span style="color:#069">Changed</span></font>
    -+</div>
    -+<!-- Package android.support.v7.appcompat -->
    -+<A NAME="A"></A>
    -+<A HREF="changes-summary.html#android.support.v7.appcompat" class="hiddenlink" target="rightframe"><strike>android.support.v7.appcompat</strike></A><br>
    -+<!-- Package android.support.v7.recyclerview -->
    -+<A HREF="changes-summary.html#android.support.v7.recyclerview" class="hiddenlink" target="rightframe"><strike>android.support.v7.recyclerview</strike></A><br>
    -+<!-- Package android.support.v8.renderscript -->
    -+<A HREF="changes-summary.html#android.support.v8.renderscript" class="hiddenlink" target="rightframe"><strike>android.support.v8.renderscript</strike></A><br>
    -+<!-- Method layoutDependsOn -->
    -+<A NAME="L"></A>
    -+<br><font size="+2">L</font>&nbsp;
    -+<a href="#A"><font size="-2">A</font></a> 
    -+<a href="#O"><font size="-2">O</font></a> 
    -+<a href="#P"><font size="-2">P</font></a> 
    -+<a href="#T"><font size="-2">T</font></a> 
    -+ <a href="#topheader"><font size="-2">TOP</font></a>
    -+<p><div style="line-height:1.5em;color:black">
    -+<nobr><A HREF="android.support.design.widget.FloatingActionButton.Behavior.html#android.support.design.widget.FloatingActionButton.Behavior.layoutDependsOn_removed(android.support.design.widget.CoordinatorLayout, android.support.design.widget.FloatingActionButton, android.view.View)" class="hiddenlink" target="rightframe"><strike>layoutDependsOn</strike>
    -+(<code>CoordinatorLayout, FloatingActionButton, View</code>)</A></nobr><br>
    -+<!-- Method onAccessibilityStateChanged -->
    -+<A NAME="O"></A>
    -+<br><font size="+2">O</font>&nbsp;
    -+<a href="#A"><font size="-2">A</font></a> 
    -+<a href="#L"><font size="-2">L</font></a> 
    -+<a href="#P"><font size="-2">P</font></a> 
    -+<a href="#T"><font size="-2">T</font></a> 
    -+ <a href="#topheader"><font size="-2">TOP</font></a>
    -+<p><div style="line-height:1.5em;color:black">
    -+<nobr><A HREF="android.support.v4.view.accessibility.AccessibilityManagerCompat.AccessibilityStateChangeListenerCompat.html#android.support.v4.view.accessibility.AccessibilityManagerCompat.AccessibilityStateChangeListenerCompat.onAccessibilityStateChanged_removed(boolean)" class="hiddenlink" target="rightframe"><strike>onAccessibilityStateChanged</strike>
    -+(<code>boolean</code>)</A></nobr><br>
    -+<!-- Method onDependentViewRemoved -->
    -+<nobr><A HREF="android.support.design.widget.FloatingActionButton.Behavior.html#android.support.design.widget.FloatingActionButton.Behavior.onDependentViewRemoved_removed(android.support.design.widget.CoordinatorLayout, android.support.design.widget.FloatingActionButton, android.view.View)" class="hiddenlink" target="rightframe"><strike>onDependentViewRemoved</strike>
    -+(<code>CoordinatorLayout, FloatingActionButton, View</code>)</A></nobr><br>
    -+<!-- Method onInserted -->
    -+<nobr><A HREF="android.support.v7.util.SortedList.Callback.html#android.support.v7.util.SortedList.Callback.onInserted_removed(int, int)" class="hiddenlink" target="rightframe"><strike>onInserted</strike>
    -+(<code>int, int</code>)</A></nobr><br>
    -+<!-- Method onMoved -->
    -+<nobr><A HREF="android.support.v7.util.SortedList.Callback.html#android.support.v7.util.SortedList.Callback.onMoved_removed(int, int)" class="hiddenlink" target="rightframe"><strike>onMoved</strike>
    -+(<code>int, int</code>)</A></nobr><br>
    -+<!-- Method onRemoved -->
    -+<nobr><A HREF="android.support.v7.util.SortedList.Callback.html#android.support.v7.util.SortedList.Callback.onRemoved_removed(int, int)" class="hiddenlink" target="rightframe"><strike>onRemoved</strike>
    -+(<code>int, int</code>)</A></nobr><br>
    -+<!-- Method prepareForDrop -->
    -+<A NAME="P"></A>
    -+<br><font size="+2">P</font>&nbsp;
    -+<a href="#A"><font size="-2">A</font></a> 
    -+<a href="#L"><font size="-2">L</font></a> 
    -+<a href="#O"><font size="-2">O</font></a> 
    -+<a href="#T"><font size="-2">T</font></a> 
    -+ <a href="#topheader"><font size="-2">TOP</font></a>
    -+<p><div style="line-height:1.5em;color:black">
    -+<nobr><A HREF="android.support.v7.widget.LinearLayoutManager.html#android.support.v7.widget.LinearLayoutManager.prepareForDrop_removed(android.view.View, android.view.View, int, int)" class="hiddenlink" target="rightframe"><strike>prepareForDrop</strike>
    -+(<code>View, View, int, int</code>)</A></nobr><br>
    -+<!-- Field TAG -->
    -+<A NAME="T"></A>
    -+<br><font size="+2">T</font>&nbsp;
    -+<a href="#A"><font size="-2">A</font></a> 
    -+<a href="#L"><font size="-2">L</font></a> 
    -+<a href="#O"><font size="-2">O</font></a> 
    -+<a href="#P"><font size="-2">P</font></a> 
    -+ <a href="#topheader"><font size="-2">TOP</font></a>
    -+<p><div style="line-height:1.5em;color:black">
    -+<nobr><A HREF="android.support.v7.widget.StaggeredGridLayoutManager.html#android.support.v7.widget.StaggeredGridLayoutManager.TAG" class="hiddenlink" target="rightframe"><strike>TAG</strike></A>
    -+</nobr><br>
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    -+</script>
    -+<script type="text/javascript">
    -+  try {
    -+    var pageTracker = _gat._getTracker("UA-5831155-1");
    -+    pageTracker._setAllowAnchor(true);
    -+    pageTracker._initData();
    -+    pageTracker._trackPageview();
    -+  } catch(e) {}
    -+</script>
    -+</BODY>
    -+</HTML>
    -diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.customtabs.CustomTabsIntent.Builder.html b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.customtabs.CustomTabsIntent.Builder.html
    -new file mode 100644
    -index 0000000..41ac368
    ---- /dev/null
    -+++ b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.customtabs.CustomTabsIntent.Builder.html
    -@@ -0,0 +1,122 @@
    -+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
    -+<HTML style="overflow:auto;">
    -+<HEAD>
    -+<meta name="generator" content="JDiff v1.1.0">
    -+<!-- Generated by the JDiff Javadoc doclet -->
    -+<!-- (http://www.jdiff.org) -->
    -+<meta name="description" content="JDiff is a Javadoc doclet which generates an HTML report of all the packages, classes, constructors, methods, and fields which have been removed, added or changed in any way, including their documentation, when two APIs are compared.">
    -+<meta name="keywords" content="diff, jdiff, javadiff, java diff, java difference, API difference, difference between two APIs, API diff, Javadoc, doclet">
    -+<TITLE>
    -+android.support.customtabs.CustomTabsIntent.Builder
    -+</TITLE>
    -+<link href="../../../../assets/android-developer-docs.css" rel="stylesheet" type="text/css" />
    -+<link href="../stylesheet-jdiff.css" rel="stylesheet" type="text/css" />
    -+<noscript>
    -+<style type="text/css">
    -+body{overflow:auto;}
    -+#body-content{position:relative; top:0;}
    -+#doc-content{overflow:visible;border-left:3px solid #666;}
    -+#side-nav{padding:0;}
    -+#side-nav .toggle-list ul {display:block;}
    -+#resize-packages-nav{border-bottom:3px solid #666;}
    -+</style>
    -+</noscript>
    -+<style type="text/css">
    -+</style>
    -+</HEAD>
    -+<BODY>
    -+<!-- Start of nav bar -->
    -+<a name="top"></a>
    -+<div id="header" style="margin-bottom:0;padding-bottom:0;">
    -+<div id="headerLeft">
    -+<a href="../../../../index.html" tabindex="-1" target="_top"><img src="../../../../assets/images/bg_logo.png" alt="Android Developers" /></a>
    -+</div>
    -+  <div id="headerRight">
    -+  <div id="headerLinks">
    -+<!-- <img src="/assets/images/icon_world.jpg" alt="" /> -->
    -+<span class="text">
    -+<!-- &nbsp;<a href="#">English</a> | -->
    -+<nobr><a href="http://developer.android.com" target="_top">Android Developers</a> | <a href="http://www.android.com" target="_top">Android.com</a></nobr>
    -+</span>
    -+</div>
    -+  <div class="and-diff-id" style="margin-top:6px;margin-right:8px;">
    -+    <table class="diffspectable">
    -+      <tr>
    -+        <td colspan="2" class="diffspechead">API Diff Specification</td>
    -+      </tr>
    -+      <tr>
    -+        <td class="diffspec" style="padding-top:.25em">To Level:</td>
    -+        <td class="diffvaluenew" style="padding-top:.25em">24.2.0</td>
    -+      </tr>
    -+      <tr>
    -+        <td class="diffspec">From Level:</td>
    -+        <td class="diffvalueold">24.1.0</td>
    -+      </tr>
    -+      <tr>
    -+        <td class="diffspec">Generated</td>
    -+        <td class="diffvalue">2016.08.16 14:03</td>
    -+      </tr>
    -+    </table>
    -+    </div><!-- End and-diff-id -->
    -+  <div class="and-diff-id" style="margin-right:8px;">
    -+    <table class="diffspectable">
    -+      <tr>
    -+        <td class="diffspec" colspan="2"><a href="jdiff_statistics.html">Statistics</a>
    -+      </tr>
    -+    </table>
    -+  </div> <!-- End and-diff-id -->
    -+  </div> <!-- End headerRight -->
    -+  </div> <!-- End header -->
    -+<div id="body-content" xstyle="padding:12px;padding-right:18px;">
    -+<div id="doc-content" style="position:relative;">
    -+<div id="mainBodyFluid">
    -+<H2>
    -+Class android.support.customtabs.<A HREF="../../../../reference/android/support/customtabs/CustomTabsIntent.Builder.html" target="_top"><font size="+2"><code>CustomTabsIntent.Builder</code></font></A>
    -+</H2>
    -+<a NAME="constructors"></a>
    -+<a NAME="methods"></a>
    -+<p>
    -+<a NAME="Added"></a>
    -+<TABLE summary="Added Methods" WIDTH="100%">
    -+<TR>
    -+  <TH VALIGN="TOP" COLSPAN=2>Added Methods</FONT></TD>
    -+</TH>
    -+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    -+  <TD VALIGN="TOP" WIDTH="25%">
    -+  <A NAME="android.support.customtabs.CustomTabsIntent.Builder.setInstantAppsEnabled_added(boolean)"></A>
    -+  <nobr><code>Builder</code>&nbsp;<A HREF="../../../../reference/android/support/customtabs/CustomTabsIntent.Builder.html#setInstantAppsEnabled(boolean)" target="_top"><code>setInstantAppsEnabled</code></A>(<code>boolean</code>)</nobr>
    -+  </TD>
    -+  <TD>&nbsp;</TD>
    -+</TR>
    -+</TABLE>
    -+&nbsp;
    -+<a NAME="fields"></a>
    -+      </div>	
    -+      <div id="footer">
    -+        <div id="copyright">
    -+        Except as noted, this content is licensed under 
    -+        <a href="http://creativecommons.org/licenses/by/2.5/"> Creative Commons Attribution 2.5</a>.
    -+        For details and restrictions, see the <a href="/license.html">Content License</a>.
    -+        </div>
    -+      <div id="footerlinks">
    -+      <p>
    -+        <a href="http://www.android.com/terms.html">Site Terms of Service</a> -
    -+        <a href="http://www.android.com/privacy.html">Privacy Policy</a> -
    -+        <a href="http://www.android.com/branding.html">Brand Guidelines</a>
    -+      </p>
    -+    </div>
    -+    </div> <!-- end footer -->
    -+    </div><!-- end doc-content -->
    -+    </div> <!-- end body-content --> 
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    -+</script>
    -+<script type="text/javascript">
    -+  try {
    -+    var pageTracker = _gat._getTracker("UA-5831155-1");
    -+    pageTracker._setAllowAnchor(true);
    -+    pageTracker._initData();
    -+    pageTracker._trackPageview();
    -+  } catch(e) {}
    -+</script>
    -+</BODY>
    -+</HTML>
    -diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.customtabs.CustomTabsIntent.html b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.customtabs.CustomTabsIntent.html
    -new file mode 100644
    -index 0000000..c4f0bfb
    ---- /dev/null
    -+++ b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.customtabs.CustomTabsIntent.html
    -@@ -0,0 +1,144 @@
    -+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
    -+<HTML style="overflow:auto;">
    -+<HEAD>
    -+<meta name="generator" content="JDiff v1.1.0">
    -+<!-- Generated by the JDiff Javadoc doclet -->
    -+<!-- (http://www.jdiff.org) -->
    -+<meta name="description" content="JDiff is a Javadoc doclet which generates an HTML report of all the packages, classes, constructors, methods, and fields which have been removed, added or changed in any way, including their documentation, when two APIs are compared.">
    -+<meta name="keywords" content="diff, jdiff, javadiff, java diff, java difference, API difference, difference between two APIs, API diff, Javadoc, doclet">
    -+<TITLE>
    -+android.support.customtabs.CustomTabsIntent
    -+</TITLE>
    -+<link href="../../../../assets/android-developer-docs.css" rel="stylesheet" type="text/css" />
    -+<link href="../stylesheet-jdiff.css" rel="stylesheet" type="text/css" />
    -+<noscript>
    -+<style type="text/css">
    -+body{overflow:auto;}
    -+#body-content{position:relative; top:0;}
    -+#doc-content{overflow:visible;border-left:3px solid #666;}
    -+#side-nav{padding:0;}
    -+#side-nav .toggle-list ul {display:block;}
    -+#resize-packages-nav{border-bottom:3px solid #666;}
    -+</style>
    -+</noscript>
    -+<style type="text/css">
    -+</style>
    -+</HEAD>
    -+<BODY>
    -+<!-- Start of nav bar -->
    -+<a name="top"></a>
    -+<div id="header" style="margin-bottom:0;padding-bottom:0;">
    -+<div id="headerLeft">
    -+<a href="../../../../index.html" tabindex="-1" target="_top"><img src="../../../../assets/images/bg_logo.png" alt="Android Developers" /></a>
    -+</div>
    -+  <div id="headerRight">
    -+  <div id="headerLinks">
    -+<!-- <img src="/assets/images/icon_world.jpg" alt="" /> -->
    -+<span class="text">
    -+<!-- &nbsp;<a href="#">English</a> | -->
    -+<nobr><a href="http://developer.android.com" target="_top">Android Developers</a> | <a href="http://www.android.com" target="_top">Android.com</a></nobr>
    -+</span>
    -+</div>
    -+  <div class="and-diff-id" style="margin-top:6px;margin-right:8px;">
    -+    <table class="diffspectable">
    -+      <tr>
    -+        <td colspan="2" class="diffspechead">API Diff Specification</td>
    -+      </tr>
    -+      <tr>
    -+        <td class="diffspec" style="padding-top:.25em">To Level:</td>
    -+        <td class="diffvaluenew" style="padding-top:.25em">24.2.0</td>
    -+      </tr>
    -+      <tr>
    -+        <td class="diffspec">From Level:</td>
    -+        <td class="diffvalueold">24.1.0</td>
    -+      </tr>
    -+      <tr>
    -+        <td class="diffspec">Generated</td>
    -+        <td class="diffvalue">2016.08.16 14:03</td>
    -+      </tr>
    -+    </table>
    -+    </div><!-- End and-diff-id -->
    -+  <div class="and-diff-id" style="margin-right:8px;">
    -+    <table class="diffspectable">
    -+      <tr>
    -+        <td class="diffspec" colspan="2"><a href="jdiff_statistics.html">Statistics</a>
    -+      </tr>
    -+    </table>
    -+  </div> <!-- End and-diff-id -->
    -+  </div> <!-- End headerRight -->
    -+  </div> <!-- End header -->
    -+<div id="body-content" xstyle="padding:12px;padding-right:18px;">
    -+<div id="doc-content" style="position:relative;">
    -+<div id="mainBodyFluid">
    -+<H2>
    -+Class android.support.customtabs.<A HREF="../../../../reference/android/support/customtabs/CustomTabsIntent.html" target="_top"><font size="+2"><code>CustomTabsIntent</code></font></A>
    -+</H2>
    -+<a NAME="constructors"></a>
    -+<a NAME="methods"></a>
    -+<p>
    -+<a NAME="Added"></a>
    -+<TABLE summary="Added Methods" WIDTH="100%">
    -+<TR>
    -+  <TH VALIGN="TOP" COLSPAN=2>Added Methods</FONT></TD>
    -+</TH>
    -+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    -+  <TD VALIGN="TOP" WIDTH="25%">
    -+  <A NAME="android.support.customtabs.CustomTabsIntent.setAlwaysUseBrowserUI_added(android.content.Intent)"></A>
    -+  <nobr><code>Intent</code>&nbsp;<A HREF="../../../../reference/android/support/customtabs/CustomTabsIntent.html#setAlwaysUseBrowserUI(android.content.Intent)" target="_top"><code>setAlwaysUseBrowserUI</code></A>(<code>Intent</code>)</nobr>
    -+  </TD>
    -+  <TD>&nbsp;</TD>
    -+</TR>
    -+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    -+  <TD VALIGN="TOP" WIDTH="25%">
    -+  <A NAME="android.support.customtabs.CustomTabsIntent.shouldAlwaysUseBrowserUI_added(android.content.Intent)"></A>
    -+  <nobr><code>boolean</code>&nbsp;<A HREF="../../../../reference/android/support/customtabs/CustomTabsIntent.html#shouldAlwaysUseBrowserUI(android.content.Intent)" target="_top"><code>shouldAlwaysUseBrowserUI</code></A>(<code>Intent</code>)</nobr>
    -+  </TD>
    -+  <TD>&nbsp;</TD>
    -+</TR>
    -+</TABLE>
    -+&nbsp;
    -+<a NAME="fields"></a>
    -+<p>
    -+<a NAME="Added"></a>
    -+<TABLE summary="Added Fields" WIDTH="100%">
    -+<TR>
    -+  <TH VALIGN="TOP" COLSPAN=2>Added Fields</FONT></TD>
    -+</TH>
    -+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    -+  <TD VALIGN="TOP" WIDTH="25%">
    -+  <A NAME="android.support.customtabs.CustomTabsIntent.EXTRA_ENABLE_INSTANT_APPS"></A>
    -+  <nobr><code>String</code>&nbsp;<A HREF="../../../../reference/android/support/customtabs/CustomTabsIntent.html#EXTRA_ENABLE_INSTANT_APPS" target="_top"><code>EXTRA_ENABLE_INSTANT_APPS</code></A></nobr>
    -+  </TD>
    -+  <TD>&nbsp;</TD>
    -+</TR>
    -+</TABLE>
    -+&nbsp;
    -+      </div>	
    -+      <div id="footer">
    -+        <div id="copyright">
    -+        Except as noted, this content is licensed under 
    -+        <a href="http://creativecommons.org/licenses/by/2.5/"> Creative Commons Attribution 2.5</a>.
    -+        For details and restrictions, see the <a href="/license.html">Content License</a>.
    -+        </div>
    -+      <div id="footerlinks">
    -+      <p>
    -+        <a href="http://www.android.com/terms.html">Site Terms of Service</a> -
    -+        <a href="http://www.android.com/privacy.html">Privacy Policy</a> -
    -+        <a href="http://www.android.com/branding.html">Brand Guidelines</a>
    -+      </p>
    -+    </div>
    -+    </div> <!-- end footer -->
    -+    </div><!-- end doc-content -->
    -+    </div> <!-- end body-content --> 
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    -+</script>
    -+<script type="text/javascript">
    -+  try {
    -+    var pageTracker = _gat._getTracker("UA-5831155-1");
    -+    pageTracker._setAllowAnchor(true);
    -+    pageTracker._initData();
    -+    pageTracker._trackPageview();
    -+  } catch(e) {}
    -+</script>
    -+</BODY>
    -+</HTML>
    -diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.customtabs.CustomTabsSession.html b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.customtabs.CustomTabsSession.html
    -new file mode 100644
    -index 0000000..1ccaab3
    ---- /dev/null
    -+++ b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.customtabs.CustomTabsSession.html
    -@@ -0,0 +1,140 @@
    -+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
    -+<HTML style="overflow:auto;">
    -+<HEAD>
    -+<meta name="generator" content="JDiff v1.1.0">
    -+<!-- Generated by the JDiff Javadoc doclet -->
    -+<!-- (http://www.jdiff.org) -->
    -+<meta name="description" content="JDiff is a Javadoc doclet which generates an HTML report of all the packages, classes, constructors, methods, and fields which have been removed, added or changed in any way, including their documentation, when two APIs are compared.">
    -+<meta name="keywords" content="diff, jdiff, javadiff, java diff, java difference, API difference, difference between two APIs, API diff, Javadoc, doclet">
    -+<TITLE>
    -+android.support.customtabs.CustomTabsSession
    -+</TITLE>
    -+<link href="../../../../assets/android-developer-docs.css" rel="stylesheet" type="text/css" />
    -+<link href="../stylesheet-jdiff.css" rel="stylesheet" type="text/css" />
    -+<noscript>
    -+<style type="text/css">
    -+body{overflow:auto;}
    -+#body-content{position:relative; top:0;}
    -+#doc-content{overflow:visible;border-left:3px solid #666;}
    -+#side-nav{padding:0;}
    -+#side-nav .toggle-list ul {display:block;}
    -+#resize-packages-nav{border-bottom:3px solid #666;}
    -+</style>
    -+</noscript>
    -+<style type="text/css">
    -+</style>
    -+</HEAD>
    -+<BODY>
    -+<!-- Start of nav bar -->
    -+<a name="top"></a>
    -+<div id="header" style="margin-bottom:0;padding-bottom:0;">
    -+<div id="headerLeft">
    -+<a href="../../../../index.html" tabindex="-1" target="_top"><img src="../../../../assets/images/bg_logo.png" alt="Android Developers" /></a>
    -+</div>
    -+  <div id="headerRight">
    -+  <div id="headerLinks">
    -+<!-- <img src="/assets/images/icon_world.jpg" alt="" /> -->
    -+<span class="text">
    -+<!-- &nbsp;<a href="#">English</a> | -->
    -+<nobr><a href="http://developer.android.com" target="_top">Android Developers</a> | <a href="http://www.android.com" target="_top">Android.com</a></nobr>
    -+</span>
    -+</div>
    -+  <div class="and-diff-id" style="margin-top:6px;margin-right:8px;">
    -+    <table class="diffspectable">
    -+      <tr>
    -+        <td colspan="2" class="diffspechead">API Diff Specification</td>
    -+      </tr>
    -+      <tr>
    -+        <td class="diffspec" style="padding-top:.25em">To Level:</td>
    -+        <td class="diffvaluenew" style="padding-top:.25em">24.2.0</td>
    -+      </tr>
    -+      <tr>
    -+        <td class="diffspec">From Level:</td>
    -+        <td class="diffvalueold">24.1.0</td>
    -+      </tr>
    -+      <tr>
    -+        <td class="diffspec">Generated</td>
    -+        <td class="diffvalue">2016.08.16 14:03</td>
    -+      </tr>
    -+    </table>
    -+    </div><!-- End and-diff-id -->
    -+  <div class="and-diff-id" style="margin-right:8px;">
    -+    <table class="diffspectable">
    -+      <tr>
    -+        <td class="diffspec" colspan="2"><a href="jdiff_statistics.html">Statistics</a>
    -+      </tr>
    -+    </table>
    -+  </div> <!-- End and-diff-id -->
    -+  </div> <!-- End headerRight -->
    -+  </div> <!-- End header -->
    -+<div id="body-content" xstyle="padding:12px;padding-right:18px;">
    -+<div id="doc-content" style="position:relative;">
    -+<div id="mainBodyFluid">
    -+<H2>
    -+Class android.support.customtabs.<A HREF="../../../../reference/android/support/customtabs/CustomTabsSession.html" target="_top"><font size="+2"><code>CustomTabsSession</code></font></A>
    -+</H2>
    -+<a NAME="constructors"></a>
    -+<a NAME="methods"></a>
    -+<p>
    -+<a NAME="Added"></a>
    -+<TABLE summary="Added Methods" WIDTH="100%">
    -+<TR>
    -+  <TH VALIGN="TOP" COLSPAN=2>Added Methods</FONT></TD>
    -+</TH>
    -+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    -+  <TD VALIGN="TOP" WIDTH="25%">
    -+  <A NAME="android.support.customtabs.CustomTabsSession.setSecondaryToolbarViews_added(android.widget.RemoteViews, int[], android.app.PendingIntent)"></A>
    -+  <nobr><code>boolean</code>&nbsp;<A HREF="../../../../reference/android/support/customtabs/CustomTabsSession.html#setSecondaryToolbarViews(android.widget.RemoteViews, int[], android.app.PendingIntent)" target="_top"><code>setSecondaryToolbarViews</code></A>(<code>RemoteViews,</nobr> int[]<nobr>,</nobr> PendingIntent<nobr><nobr></code>)</nobr>
    -+  </TD>
    -+  <TD>&nbsp;</TD>
    -+</TR>
    -+</TABLE>
    -+&nbsp;
    -+<p>
    -+<a NAME="Changed"></a>
    -+<TABLE summary="Changed Methods" WIDTH="100%">
    -+<TR>
    -+  <TH VALIGN="TOP" COLSPAN=3>Changed Methods</FONT></TD>
    -+</TH>
    -+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    -+  <TD VALIGN="TOP" WIDTH="25%">
    -+  <A NAME="android.support.customtabs.CustomTabsSession.setToolbarItem_changed(int, android.graphics.Bitmap, java.lang.String)"></A>
    -+  <nobr><code>boolean</code>&nbsp;<A HREF="../../../../reference/android/support/customtabs/CustomTabsSession.html#setToolbarItem(int, android.graphics.Bitmap, java.lang.String)" target="_top"><code>setToolbarItem</code></A>(<code>int,</nobr> Bitmap<nobr>,</nobr> String<nobr><nobr></code>)  </nobr>
    -+  </TD>
    -+  <TD VALIGN="TOP" WIDTH="30%">
    -+<b>Now deprecated</b>.<br>
    -+  </TD>
    -+  <TD>&nbsp;</TD>
    -+</TR>
    -+</TABLE>
    -+&nbsp;
    -+<a NAME="fields"></a>
    -+      </div>	
    -+      <div id="footer">
    -+        <div id="copyright">
    -+        Except as noted, this content is licensed under 
    -+        <a href="http://creativecommons.org/licenses/by/2.5/"> Creative Commons Attribution 2.5</a>.
    -+        For details and restrictions, see the <a href="/license.html">Content License</a>.
    -+        </div>
    -+      <div id="footerlinks">
    -+      <p>
    -+        <a href="http://www.android.com/terms.html">Site Terms of Service</a> -
    -+        <a href="http://www.android.com/privacy.html">Privacy Policy</a> -
    -+        <a href="http://www.android.com/branding.html">Brand Guidelines</a>
    -+      </p>
    -+    </div>
    -+    </div> <!-- end footer -->
    -+    </div><!-- end doc-content -->
    -+    </div> <!-- end body-content --> 
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    -+</script>
    -+<script type="text/javascript">
    -+  try {
    -+    var pageTracker = _gat._getTracker("UA-5831155-1");
    -+    pageTracker._setAllowAnchor(true);
    -+    pageTracker._initData();
    -+    pageTracker._trackPageview();
    -+  } catch(e) {}
    -+</script>
    -+</BODY>
    -+</HTML>
    -diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.design.widget.AppBarLayout.ScrollingViewBehavior.html b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.design.widget.AppBarLayout.ScrollingViewBehavior.html
    -new file mode 100644
    -index 0000000..ad3dfd8
    ---- /dev/null
    -+++ b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.design.widget.AppBarLayout.ScrollingViewBehavior.html
    -@@ -0,0 +1,122 @@
    -+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
    -+<HTML style="overflow:auto;">
    -+<HEAD>
    -+<meta name="generator" content="JDiff v1.1.0">
    -+<!-- Generated by the JDiff Javadoc doclet -->
    -+<!-- (http://www.jdiff.org) -->
    -+<meta name="description" content="JDiff is a Javadoc doclet which generates an HTML report of all the packages, classes, constructors, methods, and fields which have been removed, added or changed in any way, including their documentation, when two APIs are compared.">
    -+<meta name="keywords" content="diff, jdiff, javadiff, java diff, java difference, API difference, difference between two APIs, API diff, Javadoc, doclet">
    -+<TITLE>
    -+android.support.design.widget.AppBarLayout.ScrollingViewBehavior
    -+</TITLE>
    -+<link href="../../../../assets/android-developer-docs.css" rel="stylesheet" type="text/css" />
    -+<link href="../stylesheet-jdiff.css" rel="stylesheet" type="text/css" />
    -+<noscript>
    -+<style type="text/css">
    -+body{overflow:auto;}
    -+#body-content{position:relative; top:0;}
    -+#doc-content{overflow:visible;border-left:3px solid #666;}
    -+#side-nav{padding:0;}
    -+#side-nav .toggle-list ul {display:block;}
    -+#resize-packages-nav{border-bottom:3px solid #666;}
    -+</style>
    -+</noscript>
    -+<style type="text/css">
    -+</style>
    -+</HEAD>
    -+<BODY>
    -+<!-- Start of nav bar -->
    -+<a name="top"></a>
    -+<div id="header" style="margin-bottom:0;padding-bottom:0;">
    -+<div id="headerLeft">
    -+<a href="../../../../index.html" tabindex="-1" target="_top"><img src="../../../../assets/images/bg_logo.png" alt="Android Developers" /></a>
    -+</div>
    -+  <div id="headerRight">
    -+  <div id="headerLinks">
    -+<!-- <img src="/assets/images/icon_world.jpg" alt="" /> -->
    -+<span class="text">
    -+<!-- &nbsp;<a href="#">English</a> | -->
    -+<nobr><a href="http://developer.android.com" target="_top">Android Developers</a> | <a href="http://www.android.com" target="_top">Android.com</a></nobr>
    -+</span>
    -+</div>
    -+  <div class="and-diff-id" style="margin-top:6px;margin-right:8px;">
    -+    <table class="diffspectable">
    -+      <tr>
    -+        <td colspan="2" class="diffspechead">API Diff Specification</td>
    -+      </tr>
    -+      <tr>
    -+        <td class="diffspec" style="padding-top:.25em">To Level:</td>
    -+        <td class="diffvaluenew" style="padding-top:.25em">24.2.0</td>
    -+      </tr>
    -+      <tr>
    -+        <td class="diffspec">From Level:</td>
    -+        <td class="diffvalueold">24.1.0</td>
    -+      </tr>
    -+      <tr>
    -+        <td class="diffspec">Generated</td>
    -+        <td class="diffvalue">2016.08.16 14:03</td>
    -+      </tr>
    -+    </table>
    -+    </div><!-- End and-diff-id -->
    -+  <div class="and-diff-id" style="margin-right:8px;">
    -+    <table class="diffspectable">
    -+      <tr>
    -+        <td class="diffspec" colspan="2"><a href="jdiff_statistics.html">Statistics</a>
    -+      </tr>
    -+    </table>
    -+  </div> <!-- End and-diff-id -->
    -+  </div> <!-- End headerRight -->
    -+  </div> <!-- End header -->
    -+<div id="body-content" xstyle="padding:12px;padding-right:18px;">
    -+<div id="doc-content" style="position:relative;">
    -+<div id="mainBodyFluid">
    -+<H2>
    -+Class android.support.design.widget.<A HREF="../../../../reference/android/support/design/widget/AppBarLayout.ScrollingViewBehavior.html" target="_top"><font size="+2"><code>AppBarLayout.ScrollingViewBehavior</code></font></A>
    -+</H2>
    -+<a NAME="constructors"></a>
    -+<a NAME="methods"></a>
    -+<p>
    -+<a NAME="Added"></a>
    -+<TABLE summary="Added Methods" WIDTH="100%">
    -+<TR>
    -+  <TH VALIGN="TOP" COLSPAN=2>Added Methods</FONT></TD>
    -+</TH>
    -+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    -+  <TD VALIGN="TOP" WIDTH="25%">
    -+  <A NAME="android.support.design.widget.AppBarLayout.ScrollingViewBehavior.onRequestChildRectangleOnScreen_added(android.support.design.widget.CoordinatorLayout, android.view.View, android.graphics.Rect, boolean)"></A>
    -+  <nobr><code>boolean</code>&nbsp;<A HREF="../../../../reference/android/support/design/widget/AppBarLayout.ScrollingViewBehavior.html#onRequestChildRectangleOnScreen(android.support.design.widget.CoordinatorLayout, android.view.View, android.graphics.Rect, boolean)" target="_top"><code>onRequestChildRectangleOnScreen</code></A>(<code>CoordinatorLayout,</nobr> View<nobr>,</nobr> Rect<nobr>,</nobr> boolean<nobr><nobr></code>)</nobr>
    -+  </TD>
    -+  <TD>&nbsp;</TD>
    -+</TR>
    -+</TABLE>
    -+&nbsp;
    -+<a NAME="fields"></a>
    -+      </div>	
    -+      <div id="footer">
    -+        <div id="copyright">
    -+        Except as noted, this content is licensed under 
    -+        <a href="http://creativecommons.org/licenses/by/2.5/"> Creative Commons Attribution 2.5</a>.
    -+        For details and restrictions, see the <a href="/license.html">Content License</a>.
    -+        </div>
    -+      <div id="footerlinks">
    -+      <p>
    -+        <a href="http://www.android.com/terms.html">Site Terms of Service</a> -
    -+        <a href="http://www.android.com/privacy.html">Privacy Policy</a> -
    -+        <a href="http://www.android.com/branding.html">Brand Guidelines</a>
    -+      </p>
    -+    </div>
    -+    </div> <!-- end footer -->
    -+    </div><!-- end doc-content -->
    -+    </div> <!-- end body-content --> 
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    -+</script>
    -+<script type="text/javascript">
    -+  try {
    -+    var pageTracker = _gat._getTracker("UA-5831155-1");
    -+    pageTracker._setAllowAnchor(true);
    -+    pageTracker._initData();
    -+    pageTracker._trackPageview();
    -+  } catch(e) {}
    -+</script>
    -+</BODY>
    -+</HTML>
    -diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.design.widget.BottomSheetBehavior.html b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.design.widget.BottomSheetBehavior.html
    -new file mode 100644
    -index 0000000..22984b8
    ---- /dev/null
    -+++ b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.design.widget.BottomSheetBehavior.html
    -@@ -0,0 +1,122 @@
    -+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
    -+<HTML style="overflow:auto;">
    -+<HEAD>
    -+<meta name="generator" content="JDiff v1.1.0">
    -+<!-- Generated by the JDiff Javadoc doclet -->
    -+<!-- (http://www.jdiff.org) -->
    -+<meta name="description" content="JDiff is a Javadoc doclet which generates an HTML report of all the packages, classes, constructors, methods, and fields which have been removed, added or changed in any way, including their documentation, when two APIs are compared.">
    -+<meta name="keywords" content="diff, jdiff, javadiff, java diff, java difference, API difference, difference between two APIs, API diff, Javadoc, doclet">
    -+<TITLE>
    -+android.support.design.widget.BottomSheetBehavior
    -+</TITLE>
    -+<link href="../../../../assets/android-developer-docs.css" rel="stylesheet" type="text/css" />
    -+<link href="../stylesheet-jdiff.css" rel="stylesheet" type="text/css" />
    -+<noscript>
    -+<style type="text/css">
    -+body{overflow:auto;}
    -+#body-content{position:relative; top:0;}
    -+#doc-content{overflow:visible;border-left:3px solid #666;}
    -+#side-nav{padding:0;}
    -+#side-nav .toggle-list ul {display:block;}
    -+#resize-packages-nav{border-bottom:3px solid #666;}
    -+</style>
    -+</noscript>
    -+<style type="text/css">
    -+</style>
    -+</HEAD>
    -+<BODY>
    -+<!-- Start of nav bar -->
    -+<a name="top"></a>
    -+<div id="header" style="margin-bottom:0;padding-bottom:0;">
    -+<div id="headerLeft">
    -+<a href="../../../../index.html" tabindex="-1" target="_top"><img src="../../../../assets/images/bg_logo.png" alt="Android Developers" /></a>
    -+</div>
    -+  <div id="headerRight">
    -+  <div id="headerLinks">
    -+<!-- <img src="/assets/images/icon_world.jpg" alt="" /> -->
    -+<span class="text">
    -+<!-- &nbsp;<a href="#">English</a> | -->
    -+<nobr><a href="http://developer.android.com" target="_top">Android Developers</a> | <a href="http://www.android.com" target="_top">Android.com</a></nobr>
    -+</span>
    -+</div>
    -+  <div class="and-diff-id" style="margin-top:6px;margin-right:8px;">
    -+    <table class="diffspectable">
    -+      <tr>
    -+        <td colspan="2" class="diffspechead">API Diff Specification</td>
    -+      </tr>
    -+      <tr>
    -+        <td class="diffspec" style="padding-top:.25em">To Level:</td>
    -+        <td class="diffvaluenew" style="padding-top:.25em">24.2.0</td>
    -+      </tr>
    -+      <tr>
    -+        <td class="diffspec">From Level:</td>
    -+        <td class="diffvalueold">24.1.0</td>
    -+      </tr>
    -+      <tr>
    -+        <td class="diffspec">Generated</td>
    -+        <td class="diffvalue">2016.08.16 14:03</td>
    -+      </tr>
    -+    </table>
    -+    </div><!-- End and-diff-id -->
    -+  <div class="and-diff-id" style="margin-right:8px;">
    -+    <table class="diffspectable">
    -+      <tr>
    -+        <td class="diffspec" colspan="2"><a href="jdiff_statistics.html">Statistics</a>
    -+      </tr>
    -+    </table>
    -+  </div> <!-- End and-diff-id -->
    -+  </div> <!-- End headerRight -->
    -+  </div> <!-- End header -->
    -+<div id="body-content" xstyle="padding:12px;padding-right:18px;">
    -+<div id="doc-content" style="position:relative;">
    -+<div id="mainBodyFluid">
    -+<H2>
    -+Class android.support.design.widget.<A HREF="../../../../reference/android/support/design/widget/BottomSheetBehavior.html" target="_top"><font size="+2"><code>BottomSheetBehavior</code></font></A>
    -+</H2>
    -+<a NAME="constructors"></a>
    -+<a NAME="methods"></a>
    -+<a NAME="fields"></a>
    -+<p>
    -+<a NAME="Added"></a>
    -+<TABLE summary="Added Fields" WIDTH="100%">
    -+<TR>
    -+  <TH VALIGN="TOP" COLSPAN=2>Added Fields</FONT></TD>
    -+</TH>
    -+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    -+  <TD VALIGN="TOP" WIDTH="25%">
    -+  <A NAME="android.support.design.widget.BottomSheetBehavior.PEEK_HEIGHT_AUTO"></A>
    -+  <nobr><code>int</code>&nbsp;<A HREF="../../../../reference/android/support/design/widget/BottomSheetBehavior.html#PEEK_HEIGHT_AUTO" target="_top"><code>PEEK_HEIGHT_AUTO</code></A></nobr>
    -+  </TD>
    -+  <TD>&nbsp;</TD>
    -+</TR>
    -+</TABLE>
    -+&nbsp;
    -+      </div>	
    -+      <div id="footer">
    -+        <div id="copyright">
    -+        Except as noted, this content is licensed under 
    -+        <a href="http://creativecommons.org/licenses/by/2.5/"> Creative Commons Attribution 2.5</a>.
    -+        For details and restrictions, see the <a href="/license.html">Content License</a>.
    -+        </div>
    -+      <div id="footerlinks">
    -+      <p>
    -+        <a href="http://www.android.com/terms.html">Site Terms of Service</a> -
    -+        <a href="http://www.android.com/privacy.html">Privacy Policy</a> -
    -+        <a href="http://www.android.com/branding.html">Brand Guidelines</a>
    -+      </p>
    -+    </div>
    -+    </div> <!-- end footer -->
    -+    </div><!-- end doc-content -->
    -+    </div> <!-- end body-content --> 
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    -+</script>
    -+<script type="text/javascript">
    -+  try {
    -+    var pageTracker = _gat._getTracker("UA-5831155-1");
    -+    pageTracker._setAllowAnchor(true);
    -+    pageTracker._initData();
    -+    pageTracker._trackPageview();
    -+  } catch(e) {}
    -+</script>
    -+</BODY>
    -+</HTML>
    -diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.design.widget.CollapsingToolbarLayout.html b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.design.widget.CollapsingToolbarLayout.html
    -new file mode 100644
    -index 0000000..a20a1ed
    ---- /dev/null
    -+++ b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.design.widget.CollapsingToolbarLayout.html
    -@@ -0,0 +1,129 @@
    -+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
    -+<HTML style="overflow:auto;">
    -+<HEAD>
    -+<meta name="generator" content="JDiff v1.1.0">
    -+<!-- Generated by the JDiff Javadoc doclet -->
    -+<!-- (http://www.jdiff.org) -->
    -+<meta name="description" content="JDiff is a Javadoc doclet which generates an HTML report of all the packages, classes, constructors, methods, and fields which have been removed, added or changed in any way, including their documentation, when two APIs are compared.">
    -+<meta name="keywords" content="diff, jdiff, javadiff, java diff, java difference, API difference, difference between two APIs, API diff, Javadoc, doclet">
    -+<TITLE>
    -+android.support.design.widget.CollapsingToolbarLayout
    -+</TITLE>
    -+<link href="../../../../assets/android-developer-docs.css" rel="stylesheet" type="text/css" />
    -+<link href="../stylesheet-jdiff.css" rel="stylesheet" type="text/css" />
    -+<noscript>
    -+<style type="text/css">
    -+body{overflow:auto;}
    -+#body-content{position:relative; top:0;}
    -+#doc-content{overflow:visible;border-left:3px solid #666;}
    -+#side-nav{padding:0;}
    -+#side-nav .toggle-list ul {display:block;}
    -+#resize-packages-nav{border-bottom:3px solid #666;}
    -+</style>
    -+</noscript>
    -+<style type="text/css">
    -+</style>
    -+</HEAD>
    -+<BODY>
    -+<!-- Start of nav bar -->
    -+<a name="top"></a>
    -+<div id="header" style="margin-bottom:0;padding-bottom:0;">
    -+<div id="headerLeft">
    -+<a href="../../../../index.html" tabindex="-1" target="_top"><img src="../../../../assets/images/bg_logo.png" alt="Android Developers" /></a>
    -+</div>
    -+  <div id="headerRight">
    -+  <div id="headerLinks">
    -+<!-- <img src="/assets/images/icon_world.jpg" alt="" /> -->
    -+<span class="text">
    -+<!-- &nbsp;<a href="#">English</a> | -->
    -+<nobr><a href="http://developer.android.com" target="_top">Android Developers</a> | <a href="http://www.android.com" target="_top">Android.com</a></nobr>
    -+</span>
    -+</div>
    -+  <div class="and-diff-id" style="margin-top:6px;margin-right:8px;">
    -+    <table class="diffspectable">
    -+      <tr>
    -+        <td colspan="2" class="diffspechead">API Diff Specification</td>
    -+      </tr>
    -+      <tr>
    -+        <td class="diffspec" style="padding-top:.25em">To Level:</td>
    -+        <td class="diffvaluenew" style="padding-top:.25em">24.2.0</td>
    -+      </tr>
    -+      <tr>
    -+        <td class="diffspec">From Level:</td>
    -+        <td class="diffvalueold">24.1.0</td>
    -+      </tr>
    -+      <tr>
    -+        <td class="diffspec">Generated</td>
    -+        <td class="diffvalue">2016.08.16 14:03</td>
    -+      </tr>
    -+    </table>
    -+    </div><!-- End and-diff-id -->
    -+  <div class="and-diff-id" style="margin-right:8px;">
    -+    <table class="diffspectable">
    -+      <tr>
    -+        <td class="diffspec" colspan="2"><a href="jdiff_statistics.html">Statistics</a>
    -+      </tr>
    -+    </table>
    -+  </div> <!-- End and-diff-id -->
    -+  </div> <!-- End headerRight -->
    -+  </div> <!-- End header -->
    -+<div id="body-content" xstyle="padding:12px;padding-right:18px;">
    -+<div id="doc-content" style="position:relative;">
    -+<div id="mainBodyFluid">
    -+<H2>
    -+Class android.support.design.widget.<A HREF="../../../../reference/android/support/design/widget/CollapsingToolbarLayout.html" target="_top"><font size="+2"><code>CollapsingToolbarLayout</code></font></A>
    -+</H2>
    -+<a NAME="constructors"></a>
    -+<a NAME="methods"></a>
    -+<p>
    -+<a NAME="Added"></a>
    -+<TABLE summary="Added Methods" WIDTH="100%">
    -+<TR>
    -+  <TH VALIGN="TOP" COLSPAN=2>Added Methods</FONT></TD>
    -+</TH>
    -+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    -+  <TD VALIGN="TOP" WIDTH="25%">
    -+  <A NAME="android.support.design.widget.CollapsingToolbarLayout.setCollapsedTitleTextColor_added(android.content.res.ColorStateList)"></A>
    -+  <nobr><code>void</code>&nbsp;<A HREF="../../../../reference/android/support/design/widget/CollapsingToolbarLayout.html#setCollapsedTitleTextColor(android.content.res.ColorStateList)" target="_top"><code>setCollapsedTitleTextColor</code></A>(<code>ColorStateList</code>)</nobr>
    -+  </TD>
    -+  <TD>&nbsp;</TD>
    -+</TR>
    -+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    -+  <TD VALIGN="TOP" WIDTH="25%">
    -+  <A NAME="android.support.design.widget.CollapsingToolbarLayout.setExpandedTitleTextColor_added(android.content.res.ColorStateList)"></A>
    -+  <nobr><code>void</code>&nbsp;<A HREF="../../../../reference/android/support/design/widget/CollapsingToolbarLayout.html#setExpandedTitleTextColor(android.content.res.ColorStateList)" target="_top"><code>setExpandedTitleTextColor</code></A>(<code>ColorStateList</code>)</nobr>
    -+  </TD>
    -+  <TD>&nbsp;</TD>
    -+</TR>
    -+</TABLE>
    -+&nbsp;
    -+<a NAME="fields"></a>
    -+      </div>	
    -+      <div id="footer">
    -+        <div id="copyright">
    -+        Except as noted, this content is licensed under 
    -+        <a href="http://creativecommons.org/licenses/by/2.5/"> Creative Commons Attribution 2.5</a>.
    -+        For details and restrictions, see the <a href="/license.html">Content License</a>.
    -+        </div>
    -+      <div id="footerlinks">
    -+      <p>
    -+        <a href="http://www.android.com/terms.html">Site Terms of Service</a> -
    -+        <a href="http://www.android.com/privacy.html">Privacy Policy</a> -
    -+        <a href="http://www.android.com/branding.html">Brand Guidelines</a>
    -+      </p>
    -+    </div>
    -+    </div> <!-- end footer -->
    -+    </div><!-- end doc-content -->
    -+    </div> <!-- end body-content --> 
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    -+</script>
    -+<script type="text/javascript">
    -+  try {
    -+    var pageTracker = _gat._getTracker("UA-5831155-1");
    -+    pageTracker._setAllowAnchor(true);
    -+    pageTracker._initData();
    -+    pageTracker._trackPageview();
    -+  } catch(e) {}
    -+</script>
    -+</BODY>
    -+</HTML>
    -diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.design.widget.CoordinatorLayout.Behavior.html b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.design.widget.CoordinatorLayout.Behavior.html
    -new file mode 100644
    -index 0000000..edc96ed
    ---- /dev/null
    -+++ b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.design.widget.CoordinatorLayout.Behavior.html
    -@@ -0,0 +1,161 @@
    -+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
    -+<HTML style="overflow:auto;">
    -+<HEAD>
    -+<meta name="generator" content="JDiff v1.1.0">
    -+<!-- Generated by the JDiff Javadoc doclet -->
    -+<!-- (http://www.jdiff.org) -->
    -+<meta name="description" content="JDiff is a Javadoc doclet which generates an HTML report of all the packages, classes, constructors, methods, and fields which have been removed, added or changed in any way, including their documentation, when two APIs are compared.">
    -+<meta name="keywords" content="diff, jdiff, javadiff, java diff, java difference, API difference, difference between two APIs, API diff, Javadoc, doclet">
    -+<TITLE>
    -+android.support.design.widget.CoordinatorLayout.Behavior
    -+</TITLE>
    -+<link href="../../../../assets/android-developer-docs.css" rel="stylesheet" type="text/css" />
    -+<link href="../stylesheet-jdiff.css" rel="stylesheet" type="text/css" />
    -+<noscript>
    -+<style type="text/css">
    -+body{overflow:auto;}
    -+#body-content{position:relative; top:0;}
    -+#doc-content{overflow:visible;border-left:3px solid #666;}
    -+#side-nav{padding:0;}
    -+#side-nav .toggle-list ul {display:block;}
    -+#resize-packages-nav{border-bottom:3px solid #666;}
    -+</style>
    -+</noscript>
    -+<style type="text/css">
    -+</style>
    -+</HEAD>
    -+<BODY>
    -+<!-- Start of nav bar -->
    -+<a name="top"></a>
    -+<div id="header" style="margin-bottom:0;padding-bottom:0;">
    -+<div id="headerLeft">
    -+<a href="../../../../index.html" tabindex="-1" target="_top"><img src="../../../../assets/images/bg_logo.png" alt="Android Developers" /></a>
    -+</div>
    -+  <div id="headerRight">
    -+  <div id="headerLinks">
    -+<!-- <img src="/assets/images/icon_world.jpg" alt="" /> -->
    -+<span class="text">
    -+<!-- &nbsp;<a href="#">English</a> | -->
    -+<nobr><a href="http://developer.android.com" target="_top">Android Developers</a> | <a href="http://www.android.com" target="_top">Android.com</a></nobr>
    -+</span>
    -+</div>
    -+  <div class="and-diff-id" style="margin-top:6px;margin-right:8px;">
    -+    <table class="diffspectable">
    -+      <tr>
    -+        <td colspan="2" class="diffspechead">API Diff Specification</td>
    -+      </tr>
    -+      <tr>
    -+        <td class="diffspec" style="padding-top:.25em">To Level:</td>
    -+        <td class="diffvaluenew" style="padding-top:.25em">24.2.0</td>
    -+      </tr>
    -+      <tr>
    -+        <td class="diffspec">From Level:</td>
    -+        <td class="diffvalueold">24.1.0</td>
    -+      </tr>
    -+      <tr>
    -+        <td class="diffspec">Generated</td>
    -+        <td class="diffvalue">2016.08.16 14:03</td>
    -+      </tr>
    -+    </table>
    -+    </div><!-- End and-diff-id -->
    -+  <div class="and-diff-id" style="margin-right:8px;">
    -+    <table class="diffspectable">
    -+      <tr>
    -+        <td class="diffspec" colspan="2"><a href="jdiff_statistics.html">Statistics</a>
    -+      </tr>
    -+    </table>
    -+  </div> <!-- End and-diff-id -->
    -+  </div> <!-- End headerRight -->
    -+  </div> <!-- End header -->
    -+<div id="body-content" xstyle="padding:12px;padding-right:18px;">
    -+<div id="doc-content" style="position:relative;">
    -+<div id="mainBodyFluid">
    -+<H2>
    -+Class android.support.design.widget.<A HREF="../../../../reference/android/support/design/widget/CoordinatorLayout.Behavior.html" target="_top"><font size="+2"><code>CoordinatorLayout.Behavior</code></font></A>
    -+</H2>
    -+<a NAME="constructors"></a>
    -+<a NAME="methods"></a>
    -+<p>
    -+<a NAME="Added"></a>
    -+<TABLE summary="Added Methods" WIDTH="100%">
    -+<TR>
    -+  <TH VALIGN="TOP" COLSPAN=2>Added Methods</FONT></TD>
    -+</TH>
    -+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    -+  <TD VALIGN="TOP" WIDTH="25%">
    -+  <A NAME="android.support.design.widget.CoordinatorLayout.Behavior.getInsetDodgeRect_added(android.support.design.widget.CoordinatorLayout, V, android.graphics.Rect)"></A>
    -+  <nobr><code>boolean</code>&nbsp;<A HREF="../../../../reference/android/support/design/widget/CoordinatorLayout.Behavior.html#getInsetDodgeRect(android.support.design.widget.CoordinatorLayout, V, android.graphics.Rect)" target="_top"><code>getInsetDodgeRect</code></A>(<code>CoordinatorLayout,</nobr> V<nobr>,</nobr> Rect<nobr><nobr></code>)</nobr>
    -+  </TD>
    -+  <TD>&nbsp;</TD>
    -+</TR>
    -+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    -+  <TD VALIGN="TOP" WIDTH="25%">
    -+  <A NAME="android.support.design.widget.CoordinatorLayout.Behavior.onAttachedToLayoutParams_added(android.support.design.widget.CoordinatorLayout.LayoutParams)"></A>
    -+  <nobr><code>void</code>&nbsp;<A HREF="../../../../reference/android/support/design/widget/CoordinatorLayout.Behavior.html#onAttachedToLayoutParams(android.support.design.widget.CoordinatorLayout.LayoutParams)" target="_top"><code>onAttachedToLayoutParams</code></A>(<code>LayoutParams</code>)</nobr>
    -+  </TD>
    -+  <TD>&nbsp;</TD>
    -+</TR>
    -+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    -+  <TD VALIGN="TOP" WIDTH="25%">
    -+  <A NAME="android.support.design.widget.CoordinatorLayout.Behavior.onDetachedFromLayoutParams_added()"></A>
    -+  <nobr><code>void</code>&nbsp;<A HREF="../../../../reference/android/support/design/widget/CoordinatorLayout.Behavior.html#onDetachedFromLayoutParams()" target="_top"><code>onDetachedFromLayoutParams</code></A>()</nobr>
    -+  </TD>
    -+  <TD>&nbsp;</TD>
    -+</TR>
    -+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    -+  <TD VALIGN="TOP" WIDTH="25%">
    -+  <A NAME="android.support.design.widget.CoordinatorLayout.Behavior.onRequestChildRectangleOnScreen_added(android.support.design.widget.CoordinatorLayout, V, android.graphics.Rect, boolean)"></A>
    -+  <nobr><code>boolean</code>&nbsp;<A HREF="../../../../reference/android/support/design/widget/CoordinatorLayout.Behavior.html#onRequestChildRectangleOnScreen(android.support.design.widget.CoordinatorLayout, V, android.graphics.Rect, boolean)" target="_top"><code>onRequestChildRectangleOnScreen</code></A>(<code>CoordinatorLayout,</nobr> V<nobr>,</nobr> Rect<nobr>,</nobr> boolean<nobr><nobr></code>)</nobr>
    -+  </TD>
    -+  <TD>&nbsp;</TD>
    -+</TR>
    -+</TABLE>
    -+&nbsp;
    -+<p>
    -+<a NAME="Changed"></a>
    -+<TABLE summary="Changed Methods" WIDTH="100%">
    -+<TR>
    -+  <TH VALIGN="TOP" COLSPAN=3>Changed Methods</FONT></TD>
    -+</TH>
    -+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    -+  <TD VALIGN="TOP" WIDTH="25%">
    -+  <A NAME="android.support.design.widget.CoordinatorLayout.Behavior.isDirty_changed(android.support.design.widget.CoordinatorLayout, V)"></A>
    -+  <nobr><code>boolean</code>&nbsp;<A HREF="../../../../reference/android/support/design/widget/CoordinatorLayout.Behavior.html#isDirty(android.support.design.widget.CoordinatorLayout, V)" target="_top"><code>isDirty</code></A>(<code>CoordinatorLayout,</nobr> V<nobr><nobr></code>)  </nobr>
    -+  </TD>
    -+  <TD VALIGN="TOP" WIDTH="30%">
    -+<b>Now deprecated</b>.<br>
    -+  </TD>
    -+  <TD>&nbsp;</TD>
    -+</TR>
    -+</TABLE>
    -+&nbsp;
    -+<a NAME="fields"></a>
    -+      </div>	
    -+      <div id="footer">
    -+        <div id="copyright">
    -+        Except as noted, this content is licensed under 
    -+        <a href="http://creativecommons.org/licenses/by/2.5/"> Creative Commons Attribution 2.5</a>.
    -+        For details and restrictions, see the <a href="/license.html">Content License</a>.
    -+        </div>
    -+      <div id="footerlinks">
    -+      <p>
    -+        <a href="http://www.android.com/terms.html">Site Terms of Service</a> -
    -+        <a href="http://www.android.com/privacy.html">Privacy Policy</a> -
    -+        <a href="http://www.android.com/branding.html">Brand Guidelines</a>
    -+      </p>
    -+    </div>
    -+    </div> <!-- end footer -->
    -+    </div><!-- end doc-content -->
    -+    </div> <!-- end body-content --> 
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    -+</script>
    -+<script type="text/javascript">
    -+  try {
    -+    var pageTracker = _gat._getTracker("UA-5831155-1");
    -+    pageTracker._setAllowAnchor(true);
    -+    pageTracker._initData();
    -+    pageTracker._trackPageview();
    -+  } catch(e) {}
    -+</script>
    -+</BODY>
    -+</HTML>
    -diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.design.widget.CoordinatorLayout.LayoutParams.html b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.design.widget.CoordinatorLayout.LayoutParams.html
    -new file mode 100644
    -index 0000000..445da88
    ---- /dev/null
    -+++ b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.design.widget.CoordinatorLayout.LayoutParams.html
    -@@ -0,0 +1,129 @@
    -+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
    -+<HTML style="overflow:auto;">
    -+<HEAD>
    -+<meta name="generator" content="JDiff v1.1.0">
    -+<!-- Generated by the JDiff Javadoc doclet -->
    -+<!-- (http://www.jdiff.org) -->
    -+<meta name="description" content="JDiff is a Javadoc doclet which generates an HTML report of all the packages, classes, constructors, methods, and fields which have been removed, added or changed in any way, including their documentation, when two APIs are compared.">
    -+<meta name="keywords" content="diff, jdiff, javadiff, java diff, java difference, API difference, difference between two APIs, API diff, Javadoc, doclet">
    -+<TITLE>
    -+android.support.design.widget.CoordinatorLayout.LayoutParams
    -+</TITLE>
    -+<link href="../../../../assets/android-developer-docs.css" rel="stylesheet" type="text/css" />
    -+<link href="../stylesheet-jdiff.css" rel="stylesheet" type="text/css" />
    -+<noscript>
    -+<style type="text/css">
    -+body{overflow:auto;}
    -+#body-content{position:relative; top:0;}
    -+#doc-content{overflow:visible;border-left:3px solid #666;}
    -+#side-nav{padding:0;}
    -+#side-nav .toggle-list ul {display:block;}
    -+#resize-packages-nav{border-bottom:3px solid #666;}
    -+</style>
    -+</noscript>
    -+<style type="text/css">
    -+</style>
    -+</HEAD>
    -+<BODY>
    -+<!-- Start of nav bar -->
    -+<a name="top"></a>
    -+<div id="header" style="margin-bottom:0;padding-bottom:0;">
    -+<div id="headerLeft">
    -+<a href="../../../../index.html" tabindex="-1" target="_top"><img src="../../../../assets/images/bg_logo.png" alt="Android Developers" /></a>
    -+</div>
    -+  <div id="headerRight">
    -+  <div id="headerLinks">
    -+<!-- <img src="/assets/images/icon_world.jpg" alt="" /> -->
    -+<span class="text">
    -+<!-- &nbsp;<a href="#">English</a> | -->
    -+<nobr><a href="http://developer.android.com" target="_top">Android Developers</a> | <a href="http://www.android.com" target="_top">Android.com</a></nobr>
    -+</span>
    -+</div>
    -+  <div class="and-diff-id" style="margin-top:6px;margin-right:8px;">
    -+    <table class="diffspectable">
    -+      <tr>
    -+        <td colspan="2" class="diffspechead">API Diff Specification</td>
    -+      </tr>
    -+      <tr>
    -+        <td class="diffspec" style="padding-top:.25em">To Level:</td>
    -+        <td class="diffvaluenew" style="padding-top:.25em">24.2.0</td>
    -+      </tr>
    -+      <tr>
    -+        <td class="diffspec">From Level:</td>
    -+        <td class="diffvalueold">24.1.0</td>
    -+      </tr>
    -+      <tr>
    -+        <td class="diffspec">Generated</td>
    -+        <td class="diffvalue">2016.08.16 14:03</td>
    -+      </tr>
    -+    </table>
    -+    </div><!-- End and-diff-id -->
    -+  <div class="and-diff-id" style="margin-right:8px;">
    -+    <table class="diffspectable">
    -+      <tr>
    -+        <td class="diffspec" colspan="2"><a href="jdiff_statistics.html">Statistics</a>
    -+      </tr>
    -+    </table>
    -+  </div> <!-- End and-diff-id -->
    -+  </div> <!-- End headerRight -->
    -+  </div> <!-- End header -->
    -+<div id="body-content" xstyle="padding:12px;padding-right:18px;">
    -+<div id="doc-content" style="position:relative;">
    -+<div id="mainBodyFluid">
    -+<H2>
    -+Class android.support.design.widget.<A HREF="../../../../reference/android/support/design/widget/CoordinatorLayout.LayoutParams.html" target="_top"><font size="+2"><code>CoordinatorLayout.LayoutParams</code></font></A>
    -+</H2>
    -+<a NAME="constructors"></a>
    -+<a NAME="methods"></a>
    -+<a NAME="fields"></a>
    -+<p>
    -+<a NAME="Added"></a>
    -+<TABLE summary="Added Fields" WIDTH="100%">
    -+<TR>
    -+  <TH VALIGN="TOP" COLSPAN=2>Added Fields</FONT></TD>
    -+</TH>
    -+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    -+  <TD VALIGN="TOP" WIDTH="25%">
    -+  <A NAME="android.support.design.widget.CoordinatorLayout.LayoutParams.dodgeInsetEdges"></A>
    -+  <nobr><code>int</code>&nbsp;<A HREF="../../../../reference/android/support/design/widget/CoordinatorLayout.LayoutParams.html#dodgeInsetEdges" target="_top"><code>dodgeInsetEdges</code></A></nobr>
    -+  </TD>
    -+  <TD>&nbsp;</TD>
    -+</TR>
    -+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    -+  <TD VALIGN="TOP" WIDTH="25%">
    -+  <A NAME="android.support.design.widget.CoordinatorLayout.LayoutParams.insetEdge"></A>
    -+  <nobr><code>int</code>&nbsp;<A HREF="../../../../reference/android/support/design/widget/CoordinatorLayout.LayoutParams.html#insetEdge" target="_top"><code>insetEdge</code></A></nobr>
    -+  </TD>
    -+  <TD>&nbsp;</TD>
    -+</TR>
    -+</TABLE>
    -+&nbsp;
    -+      </div>	
    -+      <div id="footer">
    -+        <div id="copyright">
    -+        Except as noted, this content is licensed under 
    -+        <a href="http://creativecommons.org/licenses/by/2.5/"> Creative Commons Attribution 2.5</a>.
    -+        For details and restrictions, see the <a href="/license.html">Content License</a>.
    -+        </div>
    -+      <div id="footerlinks">
    -+      <p>
    -+        <a href="http://www.android.com/terms.html">Site Terms of Service</a> -
    -+        <a href="http://www.android.com/privacy.html">Privacy Policy</a> -
    -+        <a href="http://www.android.com/branding.html">Brand Guidelines</a>
    -+      </p>
    -+    </div>
    -+    </div> <!-- end footer -->
    -+    </div><!-- end doc-content -->
    -+    </div> <!-- end body-content --> 
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    -+</script>
    -+<script type="text/javascript">
    -+  try {
    -+    var pageTracker = _gat._getTracker("UA-5831155-1");
    -+    pageTracker._setAllowAnchor(true);
    -+    pageTracker._initData();
    -+    pageTracker._trackPageview();
    -+  } catch(e) {}
    -+</script>
    -+</BODY>
    -+</HTML>
    -diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.design.widget.CoordinatorLayout.html b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.design.widget.CoordinatorLayout.html
    -new file mode 100644
    -index 0000000..3ba5c1e
    ---- /dev/null
    -+++ b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.design.widget.CoordinatorLayout.html
    -@@ -0,0 +1,123 @@
    -+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
    -+<HTML style="overflow:auto;">
    -+<HEAD>
    -+<meta name="generator" content="JDiff v1.1.0">
    -+<!-- Generated by the JDiff Javadoc doclet -->
    -+<!-- (http://www.jdiff.org) -->
    -+<meta name="description" content="JDiff is a Javadoc doclet which generates an HTML report of all the packages, classes, constructors, methods, and fields which have been removed, added or changed in any way, including their documentation, when two APIs are compared.">
    -+<meta name="keywords" content="diff, jdiff, javadiff, java diff, java difference, API difference, difference between two APIs, API diff, Javadoc, doclet">
    -+<TITLE>
    -+android.support.design.widget.CoordinatorLayout
    -+</TITLE>
    -+<link href="../../../../assets/android-developer-docs.css" rel="stylesheet" type="text/css" />
    -+<link href="../stylesheet-jdiff.css" rel="stylesheet" type="text/css" />
    -+<noscript>
    -+<style type="text/css">
    -+body{overflow:auto;}
    -+#body-content{position:relative; top:0;}
    -+#doc-content{overflow:visible;border-left:3px solid #666;}
    -+#side-nav{padding:0;}
    -+#side-nav .toggle-list ul {display:block;}
    -+#resize-packages-nav{border-bottom:3px solid #666;}
    -+</style>
    -+</noscript>
    -+<style type="text/css">
    -+</style>
    -+</HEAD>
    -+<BODY>
    -+<!-- Start of nav bar -->
    -+<a name="top"></a>
    -+<div id="header" style="margin-bottom:0;padding-bottom:0;">
    -+<div id="headerLeft">
    -+<a href="../../../../index.html" tabindex="-1" target="_top"><img src="../../../../assets/images/bg_logo.png" alt="Android Developers" /></a>
    -+</div>
    -+  <div id="headerRight">
    -+  <div id="headerLinks">
    -+<!-- <img src="/assets/images/icon_world.jpg" alt="" /> -->
    -+<span class="text">
    -+<!-- &nbsp;<a href="#">English</a> | -->
    -+<nobr><a href="http://developer.android.com" target="_top">Android Developers</a> | <a href="http://www.android.com" target="_top">Android.com</a></nobr>
    -+</span>
    -+</div>
    -+  <div class="and-diff-id" style="margin-top:6px;margin-right:8px;">
    -+    <table class="diffspectable">
    -+      <tr>
    -+        <td colspan="2" class="diffspechead">API Diff Specification</td>
    -+      </tr>
    -+      <tr>
    -+        <td class="diffspec" style="padding-top:.25em">To Level:</td>
    -+        <td class="diffvaluenew" style="padding-top:.25em">24.2.0</td>
    -+      </tr>
    -+      <tr>
    -+        <td class="diffspec">From Level:</td>
    -+        <td class="diffvalueold">24.1.0</td>
    -+      </tr>
    -+      <tr>
    -+        <td class="diffspec">Generated</td>
    -+        <td class="diffvalue">2016.08.16 14:03</td>
    -+      </tr>
    -+    </table>
    -+    </div><!-- End and-diff-id -->
    -+  <div class="and-diff-id" style="margin-right:8px;">
    -+    <table class="diffspectable">
    -+      <tr>
    -+        <td class="diffspec" colspan="2"><a href="jdiff_statistics.html">Statistics</a>
    -+      </tr>
    -+    </table>
    -+  </div> <!-- End and-diff-id -->
    -+  </div> <!-- End headerRight -->
    -+  </div> <!-- End header -->
    -+<div id="body-content" xstyle="padding:12px;padding-right:18px;">
    -+<div id="doc-content" style="position:relative;">
    -+<div id="mainBodyFluid">
    -+<H2>
    -+Class android.support.design.widget.<A HREF="../../../../reference/android/support/design/widget/CoordinatorLayout.html" target="_top"><font size="+2"><code>CoordinatorLayout</code></font></A>
    -+</H2>
    -+<p><font xsize="+1">Added interface <code>android.support.v4.view.NestedScrollingParent</code>.<br></font>
    -+<a NAME="constructors"></a>
    -+<a NAME="methods"></a>
    -+<p>
    -+<a NAME="Added"></a>
    -+<TABLE summary="Added Methods" WIDTH="100%">
    -+<TR>
    -+  <TH VALIGN="TOP" COLSPAN=2>Added Methods</FONT></TD>
    -+</TH>
    -+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    -+  <TD VALIGN="TOP" WIDTH="25%">
    -+  <A NAME="android.support.design.widget.CoordinatorLayout.getDependents_added(android.view.View)"></A>
    -+  <nobr><code>List&lt;View&gt;</code>&nbsp;<A HREF="../../../../reference/android/support/design/widget/CoordinatorLayout.html#getDependents(android.view.View)" target="_top"><code>getDependents</code></A>(<code>View</code>)</nobr>
    -+  </TD>
    -+  <TD>&nbsp;</TD>
    -+</TR>
    -+</TABLE>
    -+&nbsp;
    -+<a NAME="fields"></a>
    -+      </div>	
    -+      <div id="footer">
    -+        <div id="copyright">
    -+        Except as noted, this content is licensed under 
    -+        <a href="http://creativecommons.org/licenses/by/2.5/"> Creative Commons Attribution 2.5</a>.
    -+        For details and restrictions, see the <a href="/license.html">Content License</a>.
    -+        </div>
    -+      <div id="footerlinks">
    -+      <p>
    -+        <a href="http://www.android.com/terms.html">Site Terms of Service</a> -
    -+        <a href="http://www.android.com/privacy.html">Privacy Policy</a> -
    -+        <a href="http://www.android.com/branding.html">Brand Guidelines</a>
    -+      </p>
    -+    </div>
    -+    </div> <!-- end footer -->
    -+    </div><!-- end doc-content -->
    -+    </div> <!-- end body-content --> 
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    -+</script>
    -+<script type="text/javascript">
    -+  try {
    -+    var pageTracker = _gat._getTracker("UA-5831155-1");
    -+    pageTracker._setAllowAnchor(true);
    -+    pageTracker._initData();
    -+    pageTracker._trackPageview();
    -+  } catch(e) {}
    -+</script>
    -+</BODY>
    -+</HTML>
    -diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.design.widget.FloatingActionButton.Behavior.html b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.design.widget.FloatingActionButton.Behavior.html
    -new file mode 100644
    -index 0000000..07099d6
    ---- /dev/null
    -+++ b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.design.widget.FloatingActionButton.Behavior.html
    -@@ -0,0 +1,158 @@
    -+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
    -+<HTML style="overflow:auto;">
    -+<HEAD>
    -+<meta name="generator" content="JDiff v1.1.0">
    -+<!-- Generated by the JDiff Javadoc doclet -->
    -+<!-- (http://www.jdiff.org) -->
    -+<meta name="description" content="JDiff is a Javadoc doclet which generates an HTML report of all the packages, classes, constructors, methods, and fields which have been removed, added or changed in any way, including their documentation, when two APIs are compared.">
    -+<meta name="keywords" content="diff, jdiff, javadiff, java diff, java difference, API difference, difference between two APIs, API diff, Javadoc, doclet">
    -+<TITLE>
    -+android.support.design.widget.FloatingActionButton.Behavior
    -+</TITLE>
    -+<link href="../../../../assets/android-developer-docs.css" rel="stylesheet" type="text/css" />
    -+<link href="../stylesheet-jdiff.css" rel="stylesheet" type="text/css" />
    -+<noscript>
    -+<style type="text/css">
    -+body{overflow:auto;}
    -+#body-content{position:relative; top:0;}
    -+#doc-content{overflow:visible;border-left:3px solid #666;}
    -+#side-nav{padding:0;}
    -+#side-nav .toggle-list ul {display:block;}
    -+#resize-packages-nav{border-bottom:3px solid #666;}
    -+</style>
    -+</noscript>
    -+<style type="text/css">
    -+</style>
    -+</HEAD>
    -+<BODY>
    -+<!-- Start of nav bar -->
    -+<a name="top"></a>
    -+<div id="header" style="margin-bottom:0;padding-bottom:0;">
    -+<div id="headerLeft">
    -+<a href="../../../../index.html" tabindex="-1" target="_top"><img src="../../../../assets/images/bg_logo.png" alt="Android Developers" /></a>
    -+</div>
    -+  <div id="headerRight">
    -+  <div id="headerLinks">
    -+<!-- <img src="/assets/images/icon_world.jpg" alt="" /> -->
    -+<span class="text">
    -+<!-- &nbsp;<a href="#">English</a> | -->
    -+<nobr><a href="http://developer.android.com" target="_top">Android Developers</a> | <a href="http://www.android.com" target="_top">Android.com</a></nobr>
    -+</span>
    -+</div>
    -+  <div class="and-diff-id" style="margin-top:6px;margin-right:8px;">
    -+    <table class="diffspectable">
    -+      <tr>
    -+        <td colspan="2" class="diffspechead">API Diff Specification</td>
    -+      </tr>
    -+      <tr>
    -+        <td class="diffspec" style="padding-top:.25em">To Level:</td>
    -+        <td class="diffvaluenew" style="padding-top:.25em">24.2.0</td>
    -+      </tr>
    -+      <tr>
    -+        <td class="diffspec">From Level:</td>
    -+        <td class="diffvalueold">24.1.0</td>
    -+      </tr>
    -+      <tr>
    -+        <td class="diffspec">Generated</td>
    -+        <td class="diffvalue">2016.08.16 14:03</td>
    -+      </tr>
    -+    </table>
    -+    </div><!-- End and-diff-id -->
    -+  <div class="and-diff-id" style="margin-right:8px;">
    -+    <table class="diffspectable">
    -+      <tr>
    -+        <td class="diffspec" colspan="2"><a href="jdiff_statistics.html">Statistics</a>
    -+      </tr>
    -+    </table>
    -+  </div> <!-- End and-diff-id -->
    -+  </div> <!-- End headerRight -->
    -+  </div> <!-- End header -->
    -+<div id="body-content" xstyle="padding:12px;padding-right:18px;">
    -+<div id="doc-content" style="position:relative;">
    -+<div id="mainBodyFluid">
    -+<H2>
    -+Class android.support.design.widget.<A HREF="../../../../reference/android/support/design/widget/FloatingActionButton.Behavior.html" target="_top"><font size="+2"><code>FloatingActionButton.Behavior</code></font></A>
    -+</H2>
    -+<a NAME="constructors"></a>
    -+<a NAME="methods"></a>
    -+<p>
    -+<a NAME="Removed"></a>
    -+<TABLE summary="Removed Methods" WIDTH="100%">
    -+<TR>
    -+  <TH VALIGN="TOP" COLSPAN=2>Removed Methods</FONT></TD>
    -+</TH>
    -+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    -+  <TD VALIGN="TOP" WIDTH="25%">
    -+  <A NAME="android.support.design.widget.FloatingActionButton.Behavior.layoutDependsOn_removed(android.support.design.widget.CoordinatorLayout, android.support.design.widget.FloatingActionButton, android.view.View)"></A>
    -+  <nobr><code>boolean</code>&nbsp;layoutDependsOn(<code>CoordinatorLayout,</nobr> FloatingActionButton<nobr>,</nobr> View<nobr><nobr></code>)</nobr>
    -+  </TD>
    -+  <TD>&nbsp;</TD>
    -+</TR>
    -+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    -+  <TD VALIGN="TOP" WIDTH="25%">
    -+  <A NAME="android.support.design.widget.FloatingActionButton.Behavior.onDependentViewRemoved_removed(android.support.design.widget.CoordinatorLayout, android.support.design.widget.FloatingActionButton, android.view.View)"></A>
    -+  <nobr><code>void</code>&nbsp;onDependentViewRemoved(<code>CoordinatorLayout,</nobr> FloatingActionButton<nobr>,</nobr> View<nobr><nobr></code>)</nobr>
    -+  </TD>
    -+  <TD>&nbsp;</TD>
    -+</TR>
    -+</TABLE>
    -+&nbsp;
    -+<p>
    -+<a NAME="Added"></a>
    -+<TABLE summary="Added Methods" WIDTH="100%">
    -+<TR>
    -+  <TH VALIGN="TOP" COLSPAN=2>Added Methods</FONT></TD>
    -+</TH>
    -+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    -+  <TD VALIGN="TOP" WIDTH="25%">
    -+  <A NAME="android.support.design.widget.FloatingActionButton.Behavior.getInsetDodgeRect_added(android.support.design.widget.CoordinatorLayout, android.support.design.widget.FloatingActionButton, android.graphics.Rect)"></A>
    -+  <nobr><code>boolean</code>&nbsp;<A HREF="../../../../reference/android/support/design/widget/FloatingActionButton.Behavior.html#getInsetDodgeRect(android.support.design.widget.CoordinatorLayout, android.support.design.widget.FloatingActionButton, android.graphics.Rect)" target="_top"><code>getInsetDodgeRect</code></A>(<code>CoordinatorLayout,</nobr> FloatingActionButton<nobr>,</nobr> Rect<nobr><nobr></code>)</nobr>
    -+  </TD>
    -+  <TD>&nbsp;</TD>
    -+</TR>
    -+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    -+  <TD VALIGN="TOP" WIDTH="25%">
    -+  <A NAME="android.support.design.widget.FloatingActionButton.Behavior.isAutoHideEnabled_added()"></A>
    -+  <nobr><code>boolean</code>&nbsp;<A HREF="../../../../reference/android/support/design/widget/FloatingActionButton.Behavior.html#isAutoHideEnabled()" target="_top"><code>isAutoHideEnabled</code></A>()</nobr>
    -+  </TD>
    -+  <TD>&nbsp;</TD>
    -+</TR>
    -+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    -+  <TD VALIGN="TOP" WIDTH="25%">
    -+  <A NAME="android.support.design.widget.FloatingActionButton.Behavior.setAutoHideEnabled_added(boolean)"></A>
    -+  <nobr><code>void</code>&nbsp;<A HREF="../../../../reference/android/support/design/widget/FloatingActionButton.Behavior.html#setAutoHideEnabled(boolean)" target="_top"><code>setAutoHideEnabled</code></A>(<code>boolean</code>)</nobr>
    -+  </TD>
    -+  <TD>&nbsp;</TD>
    -+</TR>
    -+</TABLE>
    -+&nbsp;
    -+<a NAME="fields"></a>
    -+      </div>	
    -+      <div id="footer">
    -+        <div id="copyright">
    -+        Except as noted, this content is licensed under 
    -+        <a href="http://creativecommons.org/licenses/by/2.5/"> Creative Commons Attribution 2.5</a>.
    -+        For details and restrictions, see the <a href="/license.html">Content License</a>.
    -+        </div>
    -+      <div id="footerlinks">
    -+      <p>
    -+        <a href="http://www.android.com/terms.html">Site Terms of Service</a> -
    -+        <a href="http://www.android.com/privacy.html">Privacy Policy</a> -
    -+        <a href="http://www.android.com/branding.html">Brand Guidelines</a>
    -+      </p>
    -+    </div>
    -+    </div> <!-- end footer -->
    -+    </div><!-- end doc-content -->
    -+    </div> <!-- end body-content --> 
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    -+</script>
    -+<script type="text/javascript">
    -+  try {
    -+    var pageTracker = _gat._getTracker("UA-5831155-1");
    -+    pageTracker._setAllowAnchor(true);
    -+    pageTracker._initData();
    -+    pageTracker._trackPageview();
    -+  } catch(e) {}
    -+</script>
    -+</BODY>
    -+</HTML>
    -diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.design.widget.TabLayout.html b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.design.widget.TabLayout.html
    -new file mode 100644
    -index 0000000..a09656a
    ---- /dev/null
    -+++ b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.design.widget.TabLayout.html
    -@@ -0,0 +1,122 @@
    -+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
    -+<HTML style="overflow:auto;">
    -+<HEAD>
    -+<meta name="generator" content="JDiff v1.1.0">
    -+<!-- Generated by the JDiff Javadoc doclet -->
    -+<!-- (http://www.jdiff.org) -->
    -+<meta name="description" content="JDiff is a Javadoc doclet which generates an HTML report of all the packages, classes, constructors, methods, and fields which have been removed, added or changed in any way, including their documentation, when two APIs are compared.">
    -+<meta name="keywords" content="diff, jdiff, javadiff, java diff, java difference, API difference, difference between two APIs, API diff, Javadoc, doclet">
    -+<TITLE>
    -+android.support.design.widget.TabLayout
    -+</TITLE>
    -+<link href="../../../../assets/android-developer-docs.css" rel="stylesheet" type="text/css" />
    -+<link href="../stylesheet-jdiff.css" rel="stylesheet" type="text/css" />
    -+<noscript>
    -+<style type="text/css">
    -+body{overflow:auto;}
    -+#body-content{position:relative; top:0;}
    -+#doc-content{overflow:visible;border-left:3px solid #666;}
    -+#side-nav{padding:0;}
    -+#side-nav .toggle-list ul {display:block;}
    -+#resize-packages-nav{border-bottom:3px solid #666;}
    -+</style>
    -+</noscript>
    -+<style type="text/css">
    -+</style>
    -+</HEAD>
    -+<BODY>
    -+<!-- Start of nav bar -->
    -+<a name="top"></a>
    -+<div id="header" style="margin-bottom:0;padding-bottom:0;">
    -+<div id="headerLeft">
    -+<a href="../../../../index.html" tabindex="-1" target="_top"><img src="../../../../assets/images/bg_logo.png" alt="Android Developers" /></a>
    -+</div>
    -+  <div id="headerRight">
    -+  <div id="headerLinks">
    -+<!-- <img src="/assets/images/icon_world.jpg" alt="" /> -->
    -+<span class="text">
    -+<!-- &nbsp;<a href="#">English</a> | -->
    -+<nobr><a href="http://developer.android.com" target="_top">Android Developers</a> | <a href="http://www.android.com" target="_top">Android.com</a></nobr>
    -+</span>
    -+</div>
    -+  <div class="and-diff-id" style="margin-top:6px;margin-right:8px;">
    -+    <table class="diffspectable">
    -+      <tr>
    -+        <td colspan="2" class="diffspechead">API Diff Specification</td>
    -+      </tr>
    -+      <tr>
    -+        <td class="diffspec" style="padding-top:.25em">To Level:</td>
    -+        <td class="diffvaluenew" style="padding-top:.25em">24.2.0</td>
    -+      </tr>
    -+      <tr>
    -+        <td class="diffspec">From Level:</td>
    -+        <td class="diffvalueold">24.1.0</td>
    -+      </tr>
    -+      <tr>
    -+        <td class="diffspec">Generated</td>
    -+        <td class="diffvalue">2016.08.16 14:03</td>
    -+      </tr>
    -+    </table>
    -+    </div><!-- End and-diff-id -->
    -+  <div class="and-diff-id" style="margin-right:8px;">
    -+    <table class="diffspectable">
    -+      <tr>
    -+        <td class="diffspec" colspan="2"><a href="jdiff_statistics.html">Statistics</a>
    -+      </tr>
    -+    </table>
    -+  </div> <!-- End and-diff-id -->
    -+  </div> <!-- End headerRight -->
    -+  </div> <!-- End header -->
    -+<div id="body-content" xstyle="padding:12px;padding-right:18px;">
    -+<div id="doc-content" style="position:relative;">
    -+<div id="mainBodyFluid">
    -+<H2>
    -+Class android.support.design.widget.<A HREF="../../../../reference/android/support/design/widget/TabLayout.html" target="_top"><font size="+2"><code>TabLayout</code></font></A>
    -+</H2>
    -+<a NAME="constructors"></a>
    -+<a NAME="methods"></a>
    -+<p>
    -+<a NAME="Added"></a>
    -+<TABLE summary="Added Methods" WIDTH="100%">
    -+<TR>
    -+  <TH VALIGN="TOP" COLSPAN=2>Added Methods</FONT></TD>
    -+</TH>
    -+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    -+  <TD VALIGN="TOP" WIDTH="25%">
    -+  <A NAME="android.support.design.widget.TabLayout.clearOnTabSelectedListeners_added()"></A>
    -+  <nobr><code>void</code>&nbsp;<A HREF="../../../../reference/android/support/design/widget/TabLayout.html#clearOnTabSelectedListeners()" target="_top"><code>clearOnTabSelectedListeners</code></A>()</nobr>
    -+  </TD>
    -+  <TD>&nbsp;</TD>
    -+</TR>
    -+</TABLE>
    -+&nbsp;
    -+<a NAME="fields"></a>
    -+      </div>	
    -+      <div id="footer">
    -+        <div id="copyright">
    -+        Except as noted, this content is licensed under 
    -+        <a href="http://creativecommons.org/licenses/by/2.5/"> Creative Commons Attribution 2.5</a>.
    -+        For details and restrictions, see the <a href="/license.html">Content License</a>.
    -+        </div>
    -+      <div id="footerlinks">
    -+      <p>
    -+        <a href="http://www.android.com/terms.html">Site Terms of Service</a> -
    -+        <a href="http://www.android.com/privacy.html">Privacy Policy</a> -
    -+        <a href="http://www.android.com/branding.html">Brand Guidelines</a>
    -+      </p>
    -+    </div>
    -+    </div> <!-- end footer -->
    -+    </div><!-- end doc-content -->
    -+    </div> <!-- end body-content --> 
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    -+</script>
    -+<script type="text/javascript">
    -+  try {
    -+    var pageTracker = _gat._getTracker("UA-5831155-1");
    -+    pageTracker._setAllowAnchor(true);
    -+    pageTracker._initData();
    -+    pageTracker._trackPageview();
    -+  } catch(e) {}
    -+</script>
    -+</BODY>
    -+</HTML>
    -diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.design.widget.TextInputLayout.html b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.design.widget.TextInputLayout.html
    -new file mode 100644
    -index 0000000..9ad13eb
    ---- /dev/null
    -+++ b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.design.widget.TextInputLayout.html
    -@@ -0,0 +1,185 @@
    -+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
    -+<HTML style="overflow:auto;">
    -+<HEAD>
    -+<meta name="generator" content="JDiff v1.1.0">
    -+<!-- Generated by the JDiff Javadoc doclet -->
    -+<!-- (http://www.jdiff.org) -->
    -+<meta name="description" content="JDiff is a Javadoc doclet which generates an HTML report of all the packages, classes, constructors, methods, and fields which have been removed, added or changed in any way, including their documentation, when two APIs are compared.">
    -+<meta name="keywords" content="diff, jdiff, javadiff, java diff, java difference, API difference, difference between two APIs, API diff, Javadoc, doclet">
    -+<TITLE>
    -+android.support.design.widget.TextInputLayout
    -+</TITLE>
    -+<link href="../../../../assets/android-developer-docs.css" rel="stylesheet" type="text/css" />
    -+<link href="../stylesheet-jdiff.css" rel="stylesheet" type="text/css" />
    -+<noscript>
    -+<style type="text/css">
    -+body{overflow:auto;}
    -+#body-content{position:relative; top:0;}
    -+#doc-content{overflow:visible;border-left:3px solid #666;}
    -+#side-nav{padding:0;}
    -+#side-nav .toggle-list ul {display:block;}
    -+#resize-packages-nav{border-bottom:3px solid #666;}
    -+</style>
    -+</noscript>
    -+<style type="text/css">
    -+</style>
    -+</HEAD>
    -+<BODY>
    -+<!-- Start of nav bar -->
    -+<a name="top"></a>
    -+<div id="header" style="margin-bottom:0;padding-bottom:0;">
    -+<div id="headerLeft">
    -+<a href="../../../../index.html" tabindex="-1" target="_top"><img src="../../../../assets/images/bg_logo.png" alt="Android Developers" /></a>
    -+</div>
    -+  <div id="headerRight">
    -+  <div id="headerLinks">
    -+<!-- <img src="/assets/images/icon_world.jpg" alt="" /> -->
    -+<span class="text">
    -+<!-- &nbsp;<a href="#">English</a> | -->
    -+<nobr><a href="http://developer.android.com" target="_top">Android Developers</a> | <a href="http://www.android.com" target="_top">Android.com</a></nobr>
    -+</span>
    -+</div>
    -+  <div class="and-diff-id" style="margin-top:6px;margin-right:8px;">
    -+    <table class="diffspectable">
    -+      <tr>
    -+        <td colspan="2" class="diffspechead">API Diff Specification</td>
    -+      </tr>
    -+      <tr>
    -+        <td class="diffspec" style="padding-top:.25em">To Level:</td>
    -+        <td class="diffvaluenew" style="padding-top:.25em">24.2.0</td>
    -+      </tr>
    -+      <tr>
    -+        <td class="diffspec">From Level:</td>
    -+        <td class="diffvalueold">24.1.0</td>
    -+      </tr>
    -+      <tr>
    -+        <td class="diffspec">Generated</td>
    -+        <td class="diffvalue">2016.08.16 14:03</td>
    -+      </tr>
    -+    </table>
    -+    </div><!-- End and-diff-id -->
    -+  <div class="and-diff-id" style="margin-right:8px;">
    -+    <table class="diffspectable">
    -+      <tr>
    -+        <td class="diffspec" colspan="2"><a href="jdiff_statistics.html">Statistics</a>
    -+      </tr>
    -+    </table>
    -+  </div> <!-- End and-diff-id -->
    -+  </div> <!-- End headerRight -->
    -+  </div> <!-- End header -->
    -+<div id="body-content" xstyle="padding:12px;padding-right:18px;">
    -+<div id="doc-content" style="position:relative;">
    -+<div id="mainBodyFluid">
    -+<H2>
    -+Class android.support.design.widget.<A HREF="../../../../reference/android/support/design/widget/TextInputLayout.html" target="_top"><font size="+2"><code>TextInputLayout</code></font></A>
    -+</H2>
    -+<a NAME="constructors"></a>
    -+<a NAME="methods"></a>
    -+<p>
    -+<a NAME="Added"></a>
    -+<TABLE summary="Added Methods" WIDTH="100%">
    -+<TR>
    -+  <TH VALIGN="TOP" COLSPAN=2>Added Methods</FONT></TD>
    -+</TH>
    -+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    -+  <TD VALIGN="TOP" WIDTH="25%">
    -+  <A NAME="android.support.design.widget.TextInputLayout.getPasswordVisibilityToggleContentDescription_added()"></A>
    -+  <nobr><code>CharSequence</code>&nbsp;<A HREF="../../../../reference/android/support/design/widget/TextInputLayout.html#getPasswordVisibilityToggleContentDescription()" target="_top"><code>getPasswordVisibilityToggleContentDescription</code></A>()</nobr>
    -+  </TD>
    -+  <TD>&nbsp;</TD>
    -+</TR>
    -+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    -+  <TD VALIGN="TOP" WIDTH="25%">
    -+  <A NAME="android.support.design.widget.TextInputLayout.getPasswordVisibilityToggleDrawable_added()"></A>
    -+  <nobr><code>Drawable</code>&nbsp;<A HREF="../../../../reference/android/support/design/widget/TextInputLayout.html#getPasswordVisibilityToggleDrawable()" target="_top"><code>getPasswordVisibilityToggleDrawable</code></A>()</nobr>
    -+  </TD>
    -+  <TD>&nbsp;</TD>
    -+</TR>
    -+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    -+  <TD VALIGN="TOP" WIDTH="25%">
    -+  <A NAME="android.support.design.widget.TextInputLayout.isPasswordVisibilityToggleEnabled_added()"></A>
    -+  <nobr><code>boolean</code>&nbsp;<A HREF="../../../../reference/android/support/design/widget/TextInputLayout.html#isPasswordVisibilityToggleEnabled()" target="_top"><code>isPasswordVisibilityToggleEnabled</code></A>()</nobr>
    -+  </TD>
    -+  <TD>&nbsp;</TD>
    -+</TR>
    -+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    -+  <TD VALIGN="TOP" WIDTH="25%">
    -+  <A NAME="android.support.design.widget.TextInputLayout.setPasswordVisibilityToggleContentDescription_added(int)"></A>
    -+  <nobr><code>void</code>&nbsp;<A HREF="../../../../reference/android/support/design/widget/TextInputLayout.html#setPasswordVisibilityToggleContentDescription(int)" target="_top"><code>setPasswordVisibilityToggleContentDescription</code></A>(<code>int</code>)</nobr>
    -+  </TD>
    -+  <TD>&nbsp;</TD>
    -+</TR>
    -+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    -+  <TD VALIGN="TOP" WIDTH="25%">
    -+  <A NAME="android.support.design.widget.TextInputLayout.setPasswordVisibilityToggleContentDescription_added(java.lang.CharSequence)"></A>
    -+  <nobr><code>void</code>&nbsp;<A HREF="../../../../reference/android/support/design/widget/TextInputLayout.html#setPasswordVisibilityToggleContentDescription(java.lang.CharSequence)" target="_top"><code>setPasswordVisibilityToggleContentDescription</code></A>(<code>CharSequence</code>)</nobr>
    -+  </TD>
    -+  <TD>&nbsp;</TD>
    -+</TR>
    -+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    -+  <TD VALIGN="TOP" WIDTH="25%">
    -+  <A NAME="android.support.design.widget.TextInputLayout.setPasswordVisibilityToggleDrawable_added(android.graphics.drawable.Drawable)"></A>
    -+  <nobr><code>void</code>&nbsp;<A HREF="../../../../reference/android/support/design/widget/TextInputLayout.html#setPasswordVisibilityToggleDrawable(android.graphics.drawable.Drawable)" target="_top"><code>setPasswordVisibilityToggleDrawable</code></A>(<code>Drawable</code>)</nobr>
    -+  </TD>
    -+  <TD>&nbsp;</TD>
    -+</TR>
    -+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    -+  <TD VALIGN="TOP" WIDTH="25%">
    -+  <A NAME="android.support.design.widget.TextInputLayout.setPasswordVisibilityToggleDrawable_added(int)"></A>
    -+  <nobr><code>void</code>&nbsp;<A HREF="../../../../reference/android/support/design/widget/TextInputLayout.html#setPasswordVisibilityToggleDrawable(int)" target="_top"><code>setPasswordVisibilityToggleDrawable</code></A>(<code>int</code>)</nobr>
    -+  </TD>
    -+  <TD>&nbsp;</TD>
    -+</TR>
    -+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    -+  <TD VALIGN="TOP" WIDTH="25%">
    -+  <A NAME="android.support.design.widget.TextInputLayout.setPasswordVisibilityToggleEnabled_added(boolean)"></A>
    -+  <nobr><code>void</code>&nbsp;<A HREF="../../../../reference/android/support/design/widget/TextInputLayout.html#setPasswordVisibilityToggleEnabled(boolean)" target="_top"><code>setPasswordVisibilityToggleEnabled</code></A>(<code>boolean</code>)</nobr>
    -+  </TD>
    -+  <TD>&nbsp;</TD>
    -+</TR>
    -+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    -+  <TD VALIGN="TOP" WIDTH="25%">
    -+  <A NAME="android.support.design.widget.TextInputLayout.setPasswordVisibilityToggleTintList_added(android.content.res.ColorStateList)"></A>
    -+  <nobr><code>void</code>&nbsp;<A HREF="../../../../reference/android/support/design/widget/TextInputLayout.html#setPasswordVisibilityToggleTintList(android.content.res.ColorStateList)" target="_top"><code>setPasswordVisibilityToggleTintList</code></A>(<code>ColorStateList</code>)</nobr>
    -+  </TD>
    -+  <TD>&nbsp;</TD>
    -+</TR>
    -+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    -+  <TD VALIGN="TOP" WIDTH="25%">
    -+  <A NAME="android.support.design.widget.TextInputLayout.setPasswordVisibilityToggleTintMode_added(android.graphics.PorterDuff.Mode)"></A>
    -+  <nobr><code>void</code>&nbsp;<A HREF="../../../../reference/android/support/design/widget/TextInputLayout.html#setPasswordVisibilityToggleTintMode(android.graphics.PorterDuff.Mode)" target="_top"><code>setPasswordVisibilityToggleTintMode</code></A>(<code>Mode</code>)</nobr>
    -+  </TD>
    -+  <TD>&nbsp;</TD>
    -+</TR>
    -+</TABLE>
    -+&nbsp;
    -+<a NAME="fields"></a>
    -+      </div>	
    -+      <div id="footer">
    -+        <div id="copyright">
    -+        Except as noted, this content is licensed under 
    -+        <a href="http://creativecommons.org/licenses/by/2.5/"> Creative Commons Attribution 2.5</a>.
    -+        For details and restrictions, see the <a href="/license.html">Content License</a>.
    -+        </div>
    -+      <div id="footerlinks">
    -+      <p>
    -+        <a href="http://www.android.com/terms.html">Site Terms of Service</a> -
    -+        <a href="http://www.android.com/privacy.html">Privacy Policy</a> -
    -+        <a href="http://www.android.com/branding.html">Brand Guidelines</a>
    -+      </p>
    -+    </div>
    -+    </div> <!-- end footer -->
    -+    </div><!-- end doc-content -->
    -+    </div> <!-- end body-content --> 
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    -+</script>
    -+<script type="text/javascript">
    -+  try {
    -+    var pageTracker = _gat._getTracker("UA-5831155-1");
    -+    pageTracker._setAllowAnchor(true);
    -+    pageTracker._initData();
    -+    pageTracker._trackPageview();
    -+  } catch(e) {}
    -+</script>
    -+</BODY>
    -+</HTML>
    -diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v14.preference.PreferenceFragment.html b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v14.preference.PreferenceFragment.html
    -new file mode 100644
    -index 0000000..6b23c17
    ---- /dev/null
    -+++ b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v14.preference.PreferenceFragment.html
    -@@ -0,0 +1,108 @@
    -+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
    -+<HTML style="overflow:auto;">
    -+<HEAD>
    -+<meta name="generator" content="JDiff v1.1.0">
    -+<!-- Generated by the JDiff Javadoc doclet -->
    -+<!-- (http://www.jdiff.org) -->
    -+<meta name="description" content="JDiff is a Javadoc doclet which generates an HTML report of all the packages, classes, constructors, methods, and fields which have been removed, added or changed in any way, including their documentation, when two APIs are compared.">
    -+<meta name="keywords" content="diff, jdiff, javadiff, java diff, java difference, API difference, difference between two APIs, API diff, Javadoc, doclet">
    -+<TITLE>
    -+android.support.v14.preference.PreferenceFragment
    -+</TITLE>
    -+<link href="../../../../assets/android-developer-docs.css" rel="stylesheet" type="text/css" />
    -+<link href="../stylesheet-jdiff.css" rel="stylesheet" type="text/css" />
    -+<noscript>
    -+<style type="text/css">
    -+body{overflow:auto;}
    -+#body-content{position:relative; top:0;}
    -+#doc-content{overflow:visible;border-left:3px solid #666;}
    -+#side-nav{padding:0;}
    -+#side-nav .toggle-list ul {display:block;}
    -+#resize-packages-nav{border-bottom:3px solid #666;}
    -+</style>
    -+</noscript>
    -+<style type="text/css">
    -+</style>
    -+</HEAD>
    -+<BODY>
    -+<!-- Start of nav bar -->
    -+<a name="top"></a>
    -+<div id="header" style="margin-bottom:0;padding-bottom:0;">
    -+<div id="headerLeft">
    -+<a href="../../../../index.html" tabindex="-1" target="_top"><img src="../../../../assets/images/bg_logo.png" alt="Android Developers" /></a>
    -+</div>
    -+  <div id="headerRight">
    -+  <div id="headerLinks">
    -+<!-- <img src="/assets/images/icon_world.jpg" alt="" /> -->
    -+<span class="text">
    -+<!-- &nbsp;<a href="#">English</a> | -->
    -+<nobr><a href="http://developer.android.com" target="_top">Android Developers</a> | <a href="http://www.android.com" target="_top">Android.com</a></nobr>
    -+</span>
    -+</div>
    -+  <div class="and-diff-id" style="margin-top:6px;margin-right:8px;">
    -+    <table class="diffspectable">
    -+      <tr>
    -+        <td colspan="2" class="diffspechead">API Diff Specification</td>
    -+      </tr>
    -+      <tr>
    -+        <td class="diffspec" style="padding-top:.25em">To Level:</td>
    -+        <td class="diffvaluenew" style="padding-top:.25em">24.2.0</td>
    -+      </tr>
    -+      <tr>
    -+        <td class="diffspec">From Level:</td>
    -+        <td class="diffvalueold">24.1.0</td>
    -+      </tr>
    -+      <tr>
    -+        <td class="diffspec">Generated</td>
    -+        <td class="diffvalue">2016.08.16 14:03</td>
    -+      </tr>
    -+    </table>
    -+    </div><!-- End and-diff-id -->
    -+  <div class="and-diff-id" style="margin-right:8px;">
    -+    <table class="diffspectable">
    -+      <tr>
    -+        <td class="diffspec" colspan="2"><a href="jdiff_statistics.html">Statistics</a>
    -+      </tr>
    -+    </table>
    -+  </div> <!-- End and-diff-id -->
    -+  </div> <!-- End headerRight -->
    -+  </div> <!-- End header -->
    -+<div id="body-content" xstyle="padding:12px;padding-right:18px;">
    -+<div id="doc-content" style="position:relative;">
    -+<div id="mainBodyFluid">
    -+<H2>
    -+Class android.support.v14.preference.<A HREF="../../../../reference/android/support/v14/preference/PreferenceFragment.html" target="_top"><font size="+2"><code>PreferenceFragment</code></font></A>
    -+</H2>
    -+<p><font xsize="+1">Added interface <code>android.support.v7.preference.DialogPreference.TargetFragment</code>.<br></font>
    -+<a NAME="constructors"></a>
    -+<a NAME="methods"></a>
    -+<a NAME="fields"></a>
    -+      </div>	
    -+      <div id="footer">
    -+        <div id="copyright">
    -+        Except as noted, this content is licensed under 
    -+        <a href="http://creativecommons.org/licenses/by/2.5/"> Creative Commons Attribution 2.5</a>.
    -+        For details and restrictions, see the <a href="/license.html">Content License</a>.
    -+        </div>
    -+      <div id="footerlinks">
    -+      <p>
    -+        <a href="http://www.android.com/terms.html">Site Terms of Service</a> -
    -+        <a href="http://www.android.com/privacy.html">Privacy Policy</a> -
    -+        <a href="http://www.android.com/branding.html">Brand Guidelines</a>
    -+      </p>
    -+    </div>
    -+    </div> <!-- end footer -->
    -+    </div><!-- end doc-content -->
    -+    </div> <!-- end body-content --> 
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    -+</script>
    -+<script type="text/javascript">
    -+  try {
    -+    var pageTracker = _gat._getTracker("UA-5831155-1");
    -+    pageTracker._setAllowAnchor(true);
    -+    pageTracker._initData();
    -+    pageTracker._trackPageview();
    -+  } catch(e) {}
    -+</script>
    -+</BODY>
    -+</HTML>
    -diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v17.leanback.widget.AbstractMediaItemPresenter.ViewHolder.html b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v17.leanback.widget.AbstractMediaItemPresenter.ViewHolder.html
    -new file mode 100644
    -index 0000000..9f1f00c
    ---- /dev/null
    -+++ b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v17.leanback.widget.AbstractMediaItemPresenter.ViewHolder.html
    -@@ -0,0 +1,150 @@
    -+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
    -+<HTML style="overflow:auto;">
    -+<HEAD>
    -+<meta name="generator" content="JDiff v1.1.0">
    -+<!-- Generated by the JDiff Javadoc doclet -->
    -+<!-- (http://www.jdiff.org) -->
    -+<meta name="description" content="JDiff is a Javadoc doclet which generates an HTML report of all the packages, classes, constructors, methods, and fields which have been removed, added or changed in any way, including their documentation, when two APIs are compared.">
    -+<meta name="keywords" content="diff, jdiff, javadiff, java diff, java difference, API difference, difference between two APIs, API diff, Javadoc, doclet">
    -+<TITLE>
    -+android.support.v17.leanback.widget.AbstractMediaItemPresenter.ViewHolder
    -+</TITLE>
    -+<link href="../../../../assets/android-developer-docs.css" rel="stylesheet" type="text/css" />
    -+<link href="../stylesheet-jdiff.css" rel="stylesheet" type="text/css" />
    -+<noscript>
    -+<style type="text/css">
    -+body{overflow:auto;}
    -+#body-content{position:relative; top:0;}
    -+#doc-content{overflow:visible;border-left:3px solid #666;}
    -+#side-nav{padding:0;}
    -+#side-nav .toggle-list ul {display:block;}
    -+#resize-packages-nav{border-bottom:3px solid #666;}
    -+</style>
    -+</noscript>
    -+<style type="text/css">
    -+</style>
    -+</HEAD>
    -+<BODY>
    -+<!-- Start of nav bar -->
    -+<a name="top"></a>
    -+<div id="header" style="margin-bottom:0;padding-bottom:0;">
    -+<div id="headerLeft">
    -+<a href="../../../../index.html" tabindex="-1" target="_top"><img src="../../../../assets/images/bg_logo.png" alt="Android Developers" /></a>
    -+</div>
    -+  <div id="headerRight">
    -+  <div id="headerLinks">
    -+<!-- <img src="/assets/images/icon_world.jpg" alt="" /> -->
    -+<span class="text">
    -+<!-- &nbsp;<a href="#">English</a> | -->
    -+<nobr><a href="http://developer.android.com" target="_top">Android Developers</a> | <a href="http://www.android.com" target="_top">Android.com</a></nobr>
    -+</span>
    -+</div>
    -+  <div class="and-diff-id" style="margin-top:6px;margin-right:8px;">
    -+    <table class="diffspectable">
    -+      <tr>
    -+        <td colspan="2" class="diffspechead">API Diff Specification</td>
    -+      </tr>
    -+      <tr>
    -+        <td class="diffspec" style="padding-top:.25em">To Level:</td>
    -+        <td class="diffvaluenew" style="padding-top:.25em">24.2.0</td>
    -+      </tr>
    -+      <tr>
    -+        <td class="diffspec">From Level:</td>
    -+        <td class="diffvalueold">24.1.0</td>
    -+      </tr>
    -+      <tr>
    -+        <td class="diffspec">Generated</td>
    -+        <td class="diffvalue">2016.08.16 14:03</td>
    -+      </tr>
    -+    </table>
    -+    </div><!-- End and-diff-id -->
    -+  <div class="and-diff-id" style="margin-right:8px;">
    -+    <table class="diffspectable">
    -+      <tr>
    -+        <td class="diffspec" colspan="2"><a href="jdiff_statistics.html">Statistics</a>
    -+      </tr>
    -+    </table>
    -+  </div> <!-- End and-diff-id -->
    -+  </div> <!-- End headerRight -->
    -+  </div> <!-- End header -->
    -+<div id="body-content" xstyle="padding:12px;padding-right:18px;">
    -+<div id="doc-content" style="position:relative;">
    -+<div id="mainBodyFluid">
    -+<H2>
    -+Class android.support.v17.leanback.widget.<A HREF="../../../../reference/android/support/v17/leanback/widget/AbstractMediaItemPresenter.ViewHolder.html" target="_top"><font size="+2"><code>AbstractMediaItemPresenter.ViewHolder</code></font></A>
    -+</H2>
    -+<a NAME="constructors"></a>
    -+<a NAME="methods"></a>
    -+<p>
    -+<a NAME="Added"></a>
    -+<TABLE summary="Added Methods" WIDTH="100%">
    -+<TR>
    -+  <TH VALIGN="TOP" COLSPAN=2>Added Methods</FONT></TD>
    -+</TH>
    -+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    -+  <TD VALIGN="TOP" WIDTH="25%">
    -+  <A NAME="android.support.v17.leanback.widget.AbstractMediaItemPresenter.ViewHolder.getMediaItemNumberViewFlipper_added()"></A>
    -+  <nobr><code>ViewFlipper</code>&nbsp;<A HREF="../../../../reference/android/support/v17/leanback/widget/AbstractMediaItemPresenter.ViewHolder.html#getMediaItemNumberViewFlipper()" target="_top"><code>getMediaItemNumberViewFlipper</code></A>()</nobr>
    -+  </TD>
    -+  <TD>&nbsp;</TD>
    -+</TR>
    -+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    -+  <TD VALIGN="TOP" WIDTH="25%">
    -+  <A NAME="android.support.v17.leanback.widget.AbstractMediaItemPresenter.ViewHolder.getMediaItemPausedView_added()"></A>
    -+  <nobr><code>View</code>&nbsp;<A HREF="../../../../reference/android/support/v17/leanback/widget/AbstractMediaItemPresenter.ViewHolder.html#getMediaItemPausedView()" target="_top"><code>getMediaItemPausedView</code></A>()</nobr>
    -+  </TD>
    -+  <TD>&nbsp;</TD>
    -+</TR>
    -+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    -+  <TD VALIGN="TOP" WIDTH="25%">
    -+  <A NAME="android.support.v17.leanback.widget.AbstractMediaItemPresenter.ViewHolder.getMediaItemPlayingView_added()"></A>
    -+  <nobr><code>View</code>&nbsp;<A HREF="../../../../reference/android/support/v17/leanback/widget/AbstractMediaItemPresenter.ViewHolder.html#getMediaItemPlayingView()" target="_top"><code>getMediaItemPlayingView</code></A>()</nobr>
    -+  </TD>
    -+  <TD>&nbsp;</TD>
    -+</TR>
    -+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    -+  <TD VALIGN="TOP" WIDTH="25%">
    -+  <A NAME="android.support.v17.leanback.widget.AbstractMediaItemPresenter.ViewHolder.notifyPlayStateChanged_added()"></A>
    -+  <nobr><code>void</code>&nbsp;<A HREF="../../../../reference/android/support/v17/leanback/widget/AbstractMediaItemPresenter.ViewHolder.html#notifyPlayStateChanged()" target="_top"><code>notifyPlayStateChanged</code></A>()</nobr>
    -+  </TD>
    -+  <TD>&nbsp;</TD>
    -+</TR>
    -+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    -+  <TD VALIGN="TOP" WIDTH="25%">
    -+  <A NAME="android.support.v17.leanback.widget.AbstractMediaItemPresenter.ViewHolder.setSelectedMediaItemNumberView_added(int)"></A>
    -+  <nobr><code>void</code>&nbsp;<A HREF="../../../../reference/android/support/v17/leanback/widget/AbstractMediaItemPresenter.ViewHolder.html#setSelectedMediaItemNumberView(int)" target="_top"><code>setSelectedMediaItemNumberView</code></A>(<code>int</code>)</nobr>
    -+  </TD>
    -+  <TD>&nbsp;</TD>
    -+</TR>
    -+</TABLE>
    -+&nbsp;
    -+<a NAME="fields"></a>
    -+      </div>	
    -+      <div id="footer">
    -+        <div id="copyright">
    -+        Except as noted, this content is licensed under 
    -+        <a href="http://creativecommons.org/licenses/by/2.5/"> Creative Commons Attribution 2.5</a>.
    -+        For details and restrictions, see the <a href="/license.html">Content License</a>.
    -+        </div>
    -+      <div id="footerlinks">
    -+      <p>
    -+        <a href="http://www.android.com/terms.html">Site Terms of Service</a> -
    -+        <a href="http://www.android.com/privacy.html">Privacy Policy</a> -
    -+        <a href="http://www.android.com/branding.html">Brand Guidelines</a>
    -+      </p>
    -+    </div>
    -+    </div> <!-- end footer -->
    -+    </div><!-- end doc-content -->
    -+    </div> <!-- end body-content --> 
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    -+</script>
    -+<script type="text/javascript">
    -+  try {
    -+    var pageTracker = _gat._getTracker("UA-5831155-1");
    -+    pageTracker._setAllowAnchor(true);
    -+    pageTracker._initData();
    -+    pageTracker._trackPageview();
    -+  } catch(e) {}
    -+</script>
    -+</BODY>
    -+</HTML>
    -diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v17.leanback.widget.AbstractMediaItemPresenter.html b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v17.leanback.widget.AbstractMediaItemPresenter.html
    -new file mode 100644
    -index 0000000..a0b0aa9
    ---- /dev/null
    -+++ b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v17.leanback.widget.AbstractMediaItemPresenter.html
    -@@ -0,0 +1,165 @@
    -+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
    -+<HTML style="overflow:auto;">
    -+<HEAD>
    -+<meta name="generator" content="JDiff v1.1.0">
    -+<!-- Generated by the JDiff Javadoc doclet -->
    -+<!-- (http://www.jdiff.org) -->
    -+<meta name="description" content="JDiff is a Javadoc doclet which generates an HTML report of all the packages, classes, constructors, methods, and fields which have been removed, added or changed in any way, including their documentation, when two APIs are compared.">
    -+<meta name="keywords" content="diff, jdiff, javadiff, java diff, java difference, API difference, difference between two APIs, API diff, Javadoc, doclet">
    -+<TITLE>
    -+android.support.v17.leanback.widget.AbstractMediaItemPresenter
    -+</TITLE>
    -+<link href="../../../../assets/android-developer-docs.css" rel="stylesheet" type="text/css" />
    -+<link href="../stylesheet-jdiff.css" rel="stylesheet" type="text/css" />
    -+<noscript>
    -+<style type="text/css">
    -+body{overflow:auto;}
    -+#body-content{position:relative; top:0;}
    -+#doc-content{overflow:visible;border-left:3px solid #666;}
    -+#side-nav{padding:0;}
    -+#side-nav .toggle-list ul {display:block;}
    -+#resize-packages-nav{border-bottom:3px solid #666;}
    -+</style>
    -+</noscript>
    -+<style type="text/css">
    -+</style>
    -+</HEAD>
    -+<BODY>
    -+<!-- Start of nav bar -->
    -+<a name="top"></a>
    -+<div id="header" style="margin-bottom:0;padding-bottom:0;">
    -+<div id="headerLeft">
    -+<a href="../../../../index.html" tabindex="-1" target="_top"><img src="../../../../assets/images/bg_logo.png" alt="Android Developers" /></a>
    -+</div>
    -+  <div id="headerRight">
    -+  <div id="headerLinks">
    -+<!-- <img src="/assets/images/icon_world.jpg" alt="" /> -->
    -+<span class="text">
    -+<!-- &nbsp;<a href="#">English</a> | -->
    -+<nobr><a href="http://developer.android.com" target="_top">Android Developers</a> | <a href="http://www.android.com" target="_top">Android.com</a></nobr>
    -+</span>
    -+</div>
    -+  <div class="and-diff-id" style="margin-top:6px;margin-right:8px;">
    -+    <table class="diffspectable">
    -+      <tr>
    -+        <td colspan="2" class="diffspechead">API Diff Specification</td>
    -+      </tr>
    -+      <tr>
    -+        <td class="diffspec" style="padding-top:.25em">To Level:</td>
    -+        <td class="diffvaluenew" style="padding-top:.25em">24.2.0</td>
    -+      </tr>
    -+      <tr>
    -+        <td class="diffspec">From Level:</td>
    -+        <td class="diffvalueold">24.1.0</td>
    -+      </tr>
    -+      <tr>
    -+        <td class="diffspec">Generated</td>
    -+        <td class="diffvalue">2016.08.16 14:03</td>
    -+      </tr>
    -+    </table>
    -+    </div><!-- End and-diff-id -->
    -+  <div class="and-diff-id" style="margin-right:8px;">
    -+    <table class="diffspectable">
    -+      <tr>
    -+        <td class="diffspec" colspan="2"><a href="jdiff_statistics.html">Statistics</a>
    -+      </tr>
    -+    </table>
    -+  </div> <!-- End and-diff-id -->
    -+  </div> <!-- End headerRight -->
    -+  </div> <!-- End header -->
    -+<div id="body-content" xstyle="padding:12px;padding-right:18px;">
    -+<div id="doc-content" style="position:relative;">
    -+<div id="mainBodyFluid">
    -+<H2>
    -+Class android.support.v17.leanback.widget.<A HREF="../../../../reference/android/support/v17/leanback/widget/AbstractMediaItemPresenter.html" target="_top"><font size="+2"><code>AbstractMediaItemPresenter</code></font></A>
    -+</H2>
    -+<a NAME="constructors"></a>
    -+<a NAME="methods"></a>
    -+<p>
    -+<a NAME="Added"></a>
    -+<TABLE summary="Added Methods" WIDTH="100%">
    -+<TR>
    -+  <TH VALIGN="TOP" COLSPAN=2>Added Methods</FONT></TD>
    -+</TH>
    -+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    -+  <TD VALIGN="TOP" WIDTH="25%">
    -+  <A NAME="android.support.v17.leanback.widget.AbstractMediaItemPresenter.getMediaPlayState_added(java.lang.Object)"></A>
    -+  <nobr><code>int</code>&nbsp;<A HREF="../../../../reference/android/support/v17/leanback/widget/AbstractMediaItemPresenter.html#getMediaPlayState(java.lang.Object)" target="_top"><code>getMediaPlayState</code></A>(<code>Object</code>)</nobr>
    -+  </TD>
    -+  <TD>&nbsp;</TD>
    -+</TR>
    -+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    -+  <TD VALIGN="TOP" WIDTH="25%">
    -+  <A NAME="android.support.v17.leanback.widget.AbstractMediaItemPresenter.onBindMediaPlayState_added(android.support.v17.leanback.widget.AbstractMediaItemPresenter.ViewHolder)"></A>
    -+  <nobr><code>void</code>&nbsp;<A HREF="../../../../reference/android/support/v17/leanback/widget/AbstractMediaItemPresenter.html#onBindMediaPlayState(android.support.v17.leanback.widget.AbstractMediaItemPresenter.ViewHolder)" target="_top"><code>onBindMediaPlayState</code></A>(<code>ViewHolder</code>)</nobr>
    -+  </TD>
    -+  <TD>&nbsp;</TD>
    -+</TR>
    -+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    -+  <TD VALIGN="TOP" WIDTH="25%">
    -+  <A NAME="android.support.v17.leanback.widget.AbstractMediaItemPresenter.onUnbindMediaPlayState_added(android.support.v17.leanback.widget.AbstractMediaItemPresenter.ViewHolder)"></A>
    -+  <nobr><code>void</code>&nbsp;<A HREF="../../../../reference/android/support/v17/leanback/widget/AbstractMediaItemPresenter.html#onUnbindMediaPlayState(android.support.v17.leanback.widget.AbstractMediaItemPresenter.ViewHolder)" target="_top"><code>onUnbindMediaPlayState</code></A>(<code>ViewHolder</code>)</nobr>
    -+  </TD>
    -+  <TD>&nbsp;</TD>
    -+</TR>
    -+</TABLE>
    -+&nbsp;
    -+<a NAME="fields"></a>
    -+<p>
    -+<a NAME="Added"></a>
    -+<TABLE summary="Added Fields" WIDTH="100%">
    -+<TR>
    -+  <TH VALIGN="TOP" COLSPAN=2>Added Fields</FONT></TD>
    -+</TH>
    -+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    -+  <TD VALIGN="TOP" WIDTH="25%">
    -+  <A NAME="android.support.v17.leanback.widget.AbstractMediaItemPresenter.PLAY_STATE_INITIAL"></A>
    -+  <nobr><code>int</code>&nbsp;<A HREF="../../../../reference/android/support/v17/leanback/widget/AbstractMediaItemPresenter.html#PLAY_STATE_INITIAL" target="_top"><code>PLAY_STATE_INITIAL</code></A></nobr>
    -+  </TD>
    -+  <TD>&nbsp;</TD>
    -+</TR>
    -+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    -+  <TD VALIGN="TOP" WIDTH="25%">
    -+  <A NAME="android.support.v17.leanback.widget.AbstractMediaItemPresenter.PLAY_STATE_PAUSED"></A>
    -+  <nobr><code>int</code>&nbsp;<A HREF="../../../../reference/android/support/v17/leanback/widget/AbstractMediaItemPresenter.html#PLAY_STATE_PAUSED" target="_top"><code>PLAY_STATE_PAUSED</code></A></nobr>
    -+  </TD>
    -+  <TD>&nbsp;</TD>
    -+</TR>
    -+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    -+  <TD VALIGN="TOP" WIDTH="25%">
    -+  <A NAME="android.support.v17.leanback.widget.AbstractMediaItemPresenter.PLAY_STATE_PLAYING"></A>
    -+  <nobr><code>int</code>&nbsp;<A HREF="../../../../reference/android/support/v17/leanback/widget/AbstractMediaItemPresenter.html#PLAY_STATE_PLAYING" target="_top"><code>PLAY_STATE_PLAYING</code></A></nobr>
    -+  </TD>
    -+  <TD>&nbsp;</TD>
    -+</TR>
    -+</TABLE>
    -+&nbsp;
    -+      </div>	
    -+      <div id="footer">
    -+        <div id="copyright">
    -+        Except as noted, this content is licensed under 
    -+        <a href="http://creativecommons.org/licenses/by/2.5/"> Creative Commons Attribution 2.5</a>.
    -+        For details and restrictions, see the <a href="/license.html">Content License</a>.
    -+        </div>
    -+      <div id="footerlinks">
    -+      <p>
    -+        <a href="http://www.android.com/terms.html">Site Terms of Service</a> -
    -+        <a href="http://www.android.com/privacy.html">Privacy Policy</a> -
    -+        <a href="http://www.android.com/branding.html">Brand Guidelines</a>
    -+      </p>
    -+    </div>
    -+    </div> <!-- end footer -->
    -+    </div><!-- end doc-content -->
    -+    </div> <!-- end body-content --> 
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    -+</script>
    -+<script type="text/javascript">
    -+  try {
    -+    var pageTracker = _gat._getTracker("UA-5831155-1");
    -+    pageTracker._setAllowAnchor(true);
    -+    pageTracker._initData();
    -+    pageTracker._trackPageview();
    -+  } catch(e) {}
    -+</script>
    -+</BODY>
    -+</HTML>
    -diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v17.leanback.widget.ObjectAdapter.html b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v17.leanback.widget.ObjectAdapter.html
    -new file mode 100644
    -index 0000000..3dad1a2
    ---- /dev/null
    -+++ b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v17.leanback.widget.ObjectAdapter.html
    -@@ -0,0 +1,122 @@
    -+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
    -+<HTML style="overflow:auto;">
    -+<HEAD>
    -+<meta name="generator" content="JDiff v1.1.0">
    -+<!-- Generated by the JDiff Javadoc doclet -->
    -+<!-- (http://www.jdiff.org) -->
    -+<meta name="description" content="JDiff is a Javadoc doclet which generates an HTML report of all the packages, classes, constructors, methods, and fields which have been removed, added or changed in any way, including their documentation, when two APIs are compared.">
    -+<meta name="keywords" content="diff, jdiff, javadiff, java diff, java difference, API difference, difference between two APIs, API diff, Javadoc, doclet">
    -+<TITLE>
    -+android.support.v17.leanback.widget.ObjectAdapter
    -+</TITLE>
    -+<link href="../../../../assets/android-developer-docs.css" rel="stylesheet" type="text/css" />
    -+<link href="../stylesheet-jdiff.css" rel="stylesheet" type="text/css" />
    -+<noscript>
    -+<style type="text/css">
    -+body{overflow:auto;}
    -+#body-content{position:relative; top:0;}
    -+#doc-content{overflow:visible;border-left:3px solid #666;}
    -+#side-nav{padding:0;}
    -+#side-nav .toggle-list ul {display:block;}
    -+#resize-packages-nav{border-bottom:3px solid #666;}
    -+</style>
    -+</noscript>
    -+<style type="text/css">
    -+</style>
    -+</HEAD>
    -+<BODY>
    -+<!-- Start of nav bar -->
    -+<a name="top"></a>
    -+<div id="header" style="margin-bottom:0;padding-bottom:0;">
    -+<div id="headerLeft">
    -+<a href="../../../../index.html" tabindex="-1" target="_top"><img src="../../../../assets/images/bg_logo.png" alt="Android Developers" /></a>
    -+</div>
    -+  <div id="headerRight">
    -+  <div id="headerLinks">
    -+<!-- <img src="/assets/images/icon_world.jpg" alt="" /> -->
    -+<span class="text">
    -+<!-- &nbsp;<a href="#">English</a> | -->
    -+<nobr><a href="http://developer.android.com" target="_top">Android Developers</a> | <a href="http://www.android.com" target="_top">Android.com</a></nobr>
    -+</span>
    -+</div>
    -+  <div class="and-diff-id" style="margin-top:6px;margin-right:8px;">
    -+    <table class="diffspectable">
    -+      <tr>
    -+        <td colspan="2" class="diffspechead">API Diff Specification</td>
    -+      </tr>
    -+      <tr>
    -+        <td class="diffspec" style="padding-top:.25em">To Level:</td>
    -+        <td class="diffvaluenew" style="padding-top:.25em">24.2.0</td>
    -+      </tr>
    -+      <tr>
    -+        <td class="diffspec">From Level:</td>
    -+        <td class="diffvalueold">24.1.0</td>
    -+      </tr>
    -+      <tr>
    -+        <td class="diffspec">Generated</td>
    -+        <td class="diffvalue">2016.08.16 14:03</td>
    -+      </tr>
    -+    </table>
    -+    </div><!-- End and-diff-id -->
    -+  <div class="and-diff-id" style="margin-right:8px;">
    -+    <table class="diffspectable">
    -+      <tr>
    -+        <td class="diffspec" colspan="2"><a href="jdiff_statistics.html">Statistics</a>
    -+      </tr>
    -+    </table>
    -+  </div> <!-- End and-diff-id -->
    -+  </div> <!-- End headerRight -->
    -+  </div> <!-- End header -->
    -+<div id="body-content" xstyle="padding:12px;padding-right:18px;">
    -+<div id="doc-content" style="position:relative;">
    -+<div id="mainBodyFluid">
    -+<H2>
    -+Class android.support.v17.leanback.widget.<A HREF="../../../../reference/android/support/v17/leanback/widget/ObjectAdapter.html" target="_top"><font size="+2"><code>ObjectAdapter</code></font></A>
    -+</H2>
    -+<a NAME="constructors"></a>
    -+<a NAME="methods"></a>
    -+<p>
    -+<a NAME="Added"></a>
    -+<TABLE summary="Added Methods" WIDTH="100%">
    -+<TR>
    -+  <TH VALIGN="TOP" COLSPAN=2>Added Methods</FONT></TD>
    -+</TH>
    -+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    -+  <TD VALIGN="TOP" WIDTH="25%">
    -+  <A NAME="android.support.v17.leanback.widget.ObjectAdapter.isImmediateNotifySupported_added()"></A>
    -+  <nobr><code>boolean</code>&nbsp;<A HREF="../../../../reference/android/support/v17/leanback/widget/ObjectAdapter.html#isImmediateNotifySupported()" target="_top"><code>isImmediateNotifySupported</code></A>()</nobr>
    -+  </TD>
    -+  <TD>&nbsp;</TD>
    -+</TR>
    -+</TABLE>
    -+&nbsp;
    -+<a NAME="fields"></a>
    -+      </div>	
    -+      <div id="footer">
    -+        <div id="copyright">
    -+        Except as noted, this content is licensed under 
    -+        <a href="http://creativecommons.org/licenses/by/2.5/"> Creative Commons Attribution 2.5</a>.
    -+        For details and restrictions, see the <a href="/license.html">Content License</a>.
    -+        </div>
    -+      <div id="footerlinks">
    -+      <p>
    -+        <a href="http://www.android.com/terms.html">Site Terms of Service</a> -
    -+        <a href="http://www.android.com/privacy.html">Privacy Policy</a> -
    -+        <a href="http://www.android.com/branding.html">Brand Guidelines</a>
    -+      </p>
    -+    </div>
    -+    </div> <!-- end footer -->
    -+    </div><!-- end doc-content -->
    -+    </div> <!-- end body-content --> 
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    -+</script>
    -+<script type="text/javascript">
    -+  try {
    -+    var pageTracker = _gat._getTracker("UA-5831155-1");
    -+    pageTracker._setAllowAnchor(true);
    -+    pageTracker._initData();
    -+    pageTracker._trackPageview();
    -+  } catch(e) {}
    -+</script>
    -+</BODY>
    -+</HTML>
    -diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v17.preference.LeanbackSettingsFragment.html b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v17.preference.LeanbackSettingsFragment.html
    -new file mode 100644
    -index 0000000..690328a
    ---- /dev/null
    -+++ b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v17.preference.LeanbackSettingsFragment.html
    -@@ -0,0 +1,108 @@
    -+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
    -+<HTML style="overflow:auto;">
    -+<HEAD>
    -+<meta name="generator" content="JDiff v1.1.0">
    -+<!-- Generated by the JDiff Javadoc doclet -->
    -+<!-- (http://www.jdiff.org) -->
    -+<meta name="description" content="JDiff is a Javadoc doclet which generates an HTML report of all the packages, classes, constructors, methods, and fields which have been removed, added or changed in any way, including their documentation, when two APIs are compared.">
    -+<meta name="keywords" content="diff, jdiff, javadiff, java diff, java difference, API difference, difference between two APIs, API diff, Javadoc, doclet">
    -+<TITLE>
    -+android.support.v17.preference.LeanbackSettingsFragment
    -+</TITLE>
    -+<link href="../../../../assets/android-developer-docs.css" rel="stylesheet" type="text/css" />
    -+<link href="../stylesheet-jdiff.css" rel="stylesheet" type="text/css" />
    -+<noscript>
    -+<style type="text/css">
    -+body{overflow:auto;}
    -+#body-content{position:relative; top:0;}
    -+#doc-content{overflow:visible;border-left:3px solid #666;}
    -+#side-nav{padding:0;}
    -+#side-nav .toggle-list ul {display:block;}
    -+#resize-packages-nav{border-bottom:3px solid #666;}
    -+</style>
    -+</noscript>
    -+<style type="text/css">
    -+</style>
    -+</HEAD>
    -+<BODY>
    -+<!-- Start of nav bar -->
    -+<a name="top"></a>
    -+<div id="header" style="margin-bottom:0;padding-bottom:0;">
    -+<div id="headerLeft">
    -+<a href="../../../../index.html" tabindex="-1" target="_top"><img src="../../../../assets/images/bg_logo.png" alt="Android Developers" /></a>
    -+</div>
    -+  <div id="headerRight">
    -+  <div id="headerLinks">
    -+<!-- <img src="/assets/images/icon_world.jpg" alt="" /> -->
    -+<span class="text">
    -+<!-- &nbsp;<a href="#">English</a> | -->
    -+<nobr><a href="http://developer.android.com" target="_top">Android Developers</a> | <a href="http://www.android.com" target="_top">Android.com</a></nobr>
    -+</span>
    -+</div>
    -+  <div class="and-diff-id" style="margin-top:6px;margin-right:8px;">
    -+    <table class="diffspectable">
    -+      <tr>
    -+        <td colspan="2" class="diffspechead">API Diff Specification</td>
    -+      </tr>
    -+      <tr>
    -+        <td class="diffspec" style="padding-top:.25em">To Level:</td>
    -+        <td class="diffvaluenew" style="padding-top:.25em">24.2.0</td>
    -+      </tr>
    -+      <tr>
    -+        <td class="diffspec">From Level:</td>
    -+        <td class="diffvalueold">24.1.0</td>
    -+      </tr>
    -+      <tr>
    -+        <td class="diffspec">Generated</td>
    -+        <td class="diffvalue">2016.08.16 14:03</td>
    -+      </tr>
    -+    </table>
    -+    </div><!-- End and-diff-id -->
    -+  <div class="and-diff-id" style="margin-right:8px;">
    -+    <table class="diffspectable">
    -+      <tr>
    -+        <td class="diffspec" colspan="2"><a href="jdiff_statistics.html">Statistics</a>
    -+      </tr>
    -+    </table>
    -+  </div> <!-- End and-diff-id -->
    -+  </div> <!-- End headerRight -->
    -+  </div> <!-- End header -->
    -+<div id="body-content" xstyle="padding:12px;padding-right:18px;">
    -+<div id="doc-content" style="position:relative;">
    -+<div id="mainBodyFluid">
    -+<H2>
    -+Class android.support.v17.preference.<A HREF="../../../../reference/android/support/v17/preference/LeanbackSettingsFragment.html" target="_top"><font size="+2"><code>LeanbackSettingsFragment</code></font></A>
    -+</H2>
    -+<p><font xsize="+1">Added interfaces <code>android.support.v14.preference.PreferenceFragment.OnPreferenceDisplayDialogCallback, android.support.v14.preference.PreferenceFragment.OnPreferenceStartFragmentCallback, android.support.v14.preference.PreferenceFragment.OnPreferenceStartScreenCallback</code>.<br></font>
    -+<a NAME="constructors"></a>
    -+<a NAME="methods"></a>
    -+<a NAME="fields"></a>
    -+      </div>	
    -+      <div id="footer">
    -+        <div id="copyright">
    -+        Except as noted, this content is licensed under 
    -+        <a href="http://creativecommons.org/licenses/by/2.5/"> Creative Commons Attribution 2.5</a>.
    -+        For details and restrictions, see the <a href="/license.html">Content License</a>.
    -+        </div>
    -+      <div id="footerlinks">
    -+      <p>
    -+        <a href="http://www.android.com/terms.html">Site Terms of Service</a> -
    -+        <a href="http://www.android.com/privacy.html">Privacy Policy</a> -
    -+        <a href="http://www.android.com/branding.html">Brand Guidelines</a>
    -+      </p>
    -+    </div>
    -+    </div> <!-- end footer -->
    -+    </div><!-- end doc-content -->
    -+    </div> <!-- end body-content --> 
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    -+</script>
    -+<script type="text/javascript">
    -+  try {
    -+    var pageTracker = _gat._getTracker("UA-5831155-1");
    -+    pageTracker._setAllowAnchor(true);
    -+    pageTracker._initData();
    -+    pageTracker._trackPageview();
    -+  } catch(e) {}
    -+</script>
    -+</BODY>
    -+</HTML>
    -diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.accessibilityservice.AccessibilityServiceInfoCompat.html b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.accessibilityservice.AccessibilityServiceInfoCompat.html
    -new file mode 100644
    -index 0000000..a353745
    ---- /dev/null
    -+++ b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.accessibilityservice.AccessibilityServiceInfoCompat.html
    -@@ -0,0 +1,140 @@
    -+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
    -+<HTML style="overflow:auto;">
    -+<HEAD>
    -+<meta name="generator" content="JDiff v1.1.0">
    -+<!-- Generated by the JDiff Javadoc doclet -->
    -+<!-- (http://www.jdiff.org) -->
    -+<meta name="description" content="JDiff is a Javadoc doclet which generates an HTML report of all the packages, classes, constructors, methods, and fields which have been removed, added or changed in any way, including their documentation, when two APIs are compared.">
    -+<meta name="keywords" content="diff, jdiff, javadiff, java diff, java difference, API difference, difference between two APIs, API diff, Javadoc, doclet">
    -+<TITLE>
    -+android.support.v4.accessibilityservice.AccessibilityServiceInfoCompat
    -+</TITLE>
    -+<link href="../../../../assets/android-developer-docs.css" rel="stylesheet" type="text/css" />
    -+<link href="../stylesheet-jdiff.css" rel="stylesheet" type="text/css" />
    -+<noscript>
    -+<style type="text/css">
    -+body{overflow:auto;}
    -+#body-content{position:relative; top:0;}
    -+#doc-content{overflow:visible;border-left:3px solid #666;}
    -+#side-nav{padding:0;}
    -+#side-nav .toggle-list ul {display:block;}
    -+#resize-packages-nav{border-bottom:3px solid #666;}
    -+</style>
    -+</noscript>
    -+<style type="text/css">
    -+</style>
    -+</HEAD>
    -+<BODY>
    -+<!-- Start of nav bar -->
    -+<a name="top"></a>
    -+<div id="header" style="margin-bottom:0;padding-bottom:0;">
    -+<div id="headerLeft">
    -+<a href="../../../../index.html" tabindex="-1" target="_top"><img src="../../../../assets/images/bg_logo.png" alt="Android Developers" /></a>
    -+</div>
    -+  <div id="headerRight">
    -+  <div id="headerLinks">
    -+<!-- <img src="/assets/images/icon_world.jpg" alt="" /> -->
    -+<span class="text">
    -+<!-- &nbsp;<a href="#">English</a> | -->
    -+<nobr><a href="http://developer.android.com" target="_top">Android Developers</a> | <a href="http://www.android.com" target="_top">Android.com</a></nobr>
    -+</span>
    -+</div>
    -+  <div class="and-diff-id" style="margin-top:6px;margin-right:8px;">
    -+    <table class="diffspectable">
    -+      <tr>
    -+        <td colspan="2" class="diffspechead">API Diff Specification</td>
    -+      </tr>
    -+      <tr>
    -+        <td class="diffspec" style="padding-top:.25em">To Level:</td>
    -+        <td class="diffvaluenew" style="padding-top:.25em">24.2.0</td>
    -+      </tr>
    -+      <tr>
    -+        <td class="diffspec">From Level:</td>
    -+        <td class="diffvalueold">24.1.0</td>
    -+      </tr>
    -+      <tr>
    -+        <td class="diffspec">Generated</td>
    -+        <td class="diffvalue">2016.08.16 14:03</td>
    -+      </tr>
    -+    </table>
    -+    </div><!-- End and-diff-id -->
    -+  <div class="and-diff-id" style="margin-right:8px;">
    -+    <table class="diffspectable">
    -+      <tr>
    -+        <td class="diffspec" colspan="2"><a href="jdiff_statistics.html">Statistics</a>
    -+      </tr>
    -+    </table>
    -+  </div> <!-- End and-diff-id -->
    -+  </div> <!-- End headerRight -->
    -+  </div> <!-- End header -->
    -+<div id="body-content" xstyle="padding:12px;padding-right:18px;">
    -+<div id="doc-content" style="position:relative;">
    -+<div id="mainBodyFluid">
    -+<H2>
    -+Class android.support.v4.accessibilityservice.<A HREF="../../../../reference/android/support/v4/accessibilityservice/AccessibilityServiceInfoCompat.html" target="_top"><font size="+2"><code>AccessibilityServiceInfoCompat</code></font></A>
    -+</H2>
    -+<a NAME="constructors"></a>
    -+<a NAME="methods"></a>
    -+<p>
    -+<a NAME="Added"></a>
    -+<TABLE summary="Added Methods" WIDTH="100%">
    -+<TR>
    -+  <TH VALIGN="TOP" COLSPAN=2>Added Methods</FONT></TD>
    -+</TH>
    -+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    -+  <TD VALIGN="TOP" WIDTH="25%">
    -+  <A NAME="android.support.v4.accessibilityservice.AccessibilityServiceInfoCompat.loadDescription_added(android.accessibilityservice.AccessibilityServiceInfo, android.content.pm.PackageManager)"></A>
    -+  <nobr><code>String</code>&nbsp;<A HREF="../../../../reference/android/support/v4/accessibilityservice/AccessibilityServiceInfoCompat.html#loadDescription(android.accessibilityservice.AccessibilityServiceInfo, android.content.pm.PackageManager)" target="_top"><code>loadDescription</code></A>(<code>AccessibilityServiceInfo,</nobr> PackageManager<nobr><nobr></code>)</nobr>
    -+  </TD>
    -+  <TD>&nbsp;</TD>
    -+</TR>
    -+</TABLE>
    -+&nbsp;
    -+<p>
    -+<a NAME="Changed"></a>
    -+<TABLE summary="Changed Methods" WIDTH="100%">
    -+<TR>
    -+  <TH VALIGN="TOP" COLSPAN=3>Changed Methods</FONT></TD>
    -+</TH>
    -+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    -+  <TD VALIGN="TOP" WIDTH="25%">
    -+  <A NAME="android.support.v4.accessibilityservice.AccessibilityServiceInfoCompat.getDescription_changed(android.accessibilityservice.AccessibilityServiceInfo)"></A>
    -+  <nobr><code>String</code>&nbsp;<A HREF="../../../../reference/android/support/v4/accessibilityservice/AccessibilityServiceInfoCompat.html#getDescription(android.accessibilityservice.AccessibilityServiceInfo)" target="_top"><code>getDescription</code></A>(<code>AccessibilityServiceInfo</code>)  </nobr>
    -+  </TD>
    -+  <TD VALIGN="TOP" WIDTH="30%">
    -+<b>Now deprecated</b>.<br>
    -+  </TD>
    -+  <TD>&nbsp;</TD>
    -+</TR>
    -+</TABLE>
    -+&nbsp;
    -+<a NAME="fields"></a>
    -+      </div>	
    -+      <div id="footer">
    -+        <div id="copyright">
    -+        Except as noted, this content is licensed under 
    -+        <a href="http://creativecommons.org/licenses/by/2.5/"> Creative Commons Attribution 2.5</a>.
    -+        For details and restrictions, see the <a href="/license.html">Content License</a>.
    -+        </div>
    -+      <div id="footerlinks">
    -+      <p>
    -+        <a href="http://www.android.com/terms.html">Site Terms of Service</a> -
    -+        <a href="http://www.android.com/privacy.html">Privacy Policy</a> -
    -+        <a href="http://www.android.com/branding.html">Brand Guidelines</a>
    -+      </p>
    -+    </div>
    -+    </div> <!-- end footer -->
    -+    </div><!-- end doc-content -->
    -+    </div> <!-- end body-content --> 
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    -+</script>
    -+<script type="text/javascript">
    -+  try {
    -+    var pageTracker = _gat._getTracker("UA-5831155-1");
    -+    pageTracker._setAllowAnchor(true);
    -+    pageTracker._initData();
    -+    pageTracker._trackPageview();
    -+  } catch(e) {}
    -+</script>
    -+</BODY>
    -+</HTML>
    -diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.app.ActivityCompat.html b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.app.ActivityCompat.html
    -new file mode 100644
    -index 0000000..95b4fc6
    ---- /dev/null
    -+++ b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.app.ActivityCompat.html
    -@@ -0,0 +1,143 @@
    -+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
    -+<HTML style="overflow:auto;">
    -+<HEAD>
    -+<meta name="generator" content="JDiff v1.1.0">
    -+<!-- Generated by the JDiff Javadoc doclet -->
    -+<!-- (http://www.jdiff.org) -->
    -+<meta name="description" content="JDiff is a Javadoc doclet which generates an HTML report of all the packages, classes, constructors, methods, and fields which have been removed, added or changed in any way, including their documentation, when two APIs are compared.">
    -+<meta name="keywords" content="diff, jdiff, javadiff, java diff, java difference, API difference, difference between two APIs, API diff, Javadoc, doclet">
    -+<TITLE>
    -+android.support.v4.app.ActivityCompat
    -+</TITLE>
    -+<link href="../../../../assets/android-developer-docs.css" rel="stylesheet" type="text/css" />
    -+<link href="../stylesheet-jdiff.css" rel="stylesheet" type="text/css" />
    -+<noscript>
    -+<style type="text/css">
    -+body{overflow:auto;}
    -+#body-content{position:relative; top:0;}
    -+#doc-content{overflow:visible;border-left:3px solid #666;}
    -+#side-nav{padding:0;}
    -+#side-nav .toggle-list ul {display:block;}
    -+#resize-packages-nav{border-bottom:3px solid #666;}
    -+</style>
    -+</noscript>
    -+<style type="text/css">
    -+</style>
    -+</HEAD>
    -+<BODY>
    -+<!-- Start of nav bar -->
    -+<a name="top"></a>
    -+<div id="header" style="margin-bottom:0;padding-bottom:0;">
    -+<div id="headerLeft">
    -+<a href="../../../../index.html" tabindex="-1" target="_top"><img src="../../../../assets/images/bg_logo.png" alt="Android Developers" /></a>
    -+</div>
    -+  <div id="headerRight">
    -+  <div id="headerLinks">
    -+<!-- <img src="/assets/images/icon_world.jpg" alt="" /> -->
    -+<span class="text">
    -+<!-- &nbsp;<a href="#">English</a> | -->
    -+<nobr><a href="http://developer.android.com" target="_top">Android Developers</a> | <a href="http://www.android.com" target="_top">Android.com</a></nobr>
    -+</span>
    -+</div>
    -+  <div class="and-diff-id" style="margin-top:6px;margin-right:8px;">
    -+    <table class="diffspectable">
    -+      <tr>
    -+        <td colspan="2" class="diffspechead">API Diff Specification</td>
    -+      </tr>
    -+      <tr>
    -+        <td class="diffspec" style="padding-top:.25em">To Level:</td>
    -+        <td class="diffvaluenew" style="padding-top:.25em">24.2.0</td>
    -+      </tr>
    -+      <tr>
    -+        <td class="diffspec">From Level:</td>
    -+        <td class="diffvalueold">24.1.0</td>
    -+      </tr>
    -+      <tr>
    -+        <td class="diffspec">Generated</td>
    -+        <td class="diffvalue">2016.08.16 14:03</td>
    -+      </tr>
    -+    </table>
    -+    </div><!-- End and-diff-id -->
    -+  <div class="and-diff-id" style="margin-right:8px;">
    -+    <table class="diffspectable">
    -+      <tr>
    -+        <td class="diffspec" colspan="2"><a href="jdiff_statistics.html">Statistics</a>
    -+      </tr>
    -+    </table>
    -+  </div> <!-- End and-diff-id -->
    -+  </div> <!-- End headerRight -->
    -+  </div> <!-- End header -->
    -+<div id="body-content" xstyle="padding:12px;padding-right:18px;">
    -+<div id="doc-content" style="position:relative;">
    -+<div id="mainBodyFluid">
    -+<H2>
    -+Class android.support.v4.app.<A HREF="../../../../reference/android/support/v4/app/ActivityCompat.html" target="_top"><font size="+2"><code>ActivityCompat</code></font></A>
    -+</H2>
    -+<a NAME="constructors"></a>
    -+<p>
    -+<a NAME="Changed"></a>
    -+<TABLE summary="Changed Constructors" WIDTH="100%">
    -+<TR>
    -+  <TH VALIGN="TOP" COLSPAN=3>Changed Constructors</FONT></TD>
    -+</TH>
    -+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    -+  <TD VALIGN="TOP" WIDTH="25%">
    -+  <A NAME="android.support.v4.app.ActivityCompat.ctor_changed()"></A>
    -+  <nobr><A HREF="../../../../reference/android/support/v4/app/ActivityCompat.html#ActivityCompat()" target="_top"><code>ActivityCompat</code></A>()  </nobr>
    -+  </TD>
    -+  <TD VALIGN="TOP" WIDTH="30%">
    -+<b>Now deprecated</b>.<br>
    -+  </TD>
    -+  <TD>&nbsp;</TD>
    -+</TR>
    -+</TABLE>
    -+&nbsp;
    -+<a NAME="methods"></a>
    -+<p>
    -+<a NAME="Changed"></a>
    -+<TABLE summary="Changed Methods" WIDTH="100%">
    -+<TR>
    -+  <TH VALIGN="TOP" COLSPAN=3>Changed Methods</FONT></TD>
    -+</TH>
    -+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    -+  <TD VALIGN="TOP" WIDTH="25%">
    -+  <A NAME="android.support.v4.app.ActivityCompat.getReferrer_changed(android.app.Activity)"></A>
    -+  <nobr><code>Uri</code>&nbsp;<A HREF="../../../../reference/android/support/v4/app/ActivityCompat.html#getReferrer(android.app.Activity)" target="_top"><code>getReferrer</code></A>(<code>Activity</code>)  </nobr>
    -+  </TD>
    -+  <TD VALIGN="TOP" WIDTH="30%">
    -+<b>Now deprecated</b>.<br>
    -+  </TD>
    -+  <TD>&nbsp;</TD>
    -+</TR>
    -+</TABLE>
    -+&nbsp;
    -+<a NAME="fields"></a>
    -+      </div>	
    -+      <div id="footer">
    -+        <div id="copyright">
    -+        Except as noted, this content is licensed under 
    -+        <a href="http://creativecommons.org/licenses/by/2.5/"> Creative Commons Attribution 2.5</a>.
    -+        For details and restrictions, see the <a href="/license.html">Content License</a>.
    -+        </div>
    -+      <div id="footerlinks">
    -+      <p>
    -+        <a href="http://www.android.com/terms.html">Site Terms of Service</a> -
    -+        <a href="http://www.android.com/privacy.html">Privacy Policy</a> -
    -+        <a href="http://www.android.com/branding.html">Brand Guidelines</a>
    -+      </p>
    -+    </div>
    -+    </div> <!-- end footer -->
    -+    </div><!-- end doc-content -->
    -+    </div> <!-- end body-content --> 
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    -+</script>
    -+<script type="text/javascript">
    -+  try {
    -+    var pageTracker = _gat._getTracker("UA-5831155-1");
    -+    pageTracker._setAllowAnchor(true);
    -+    pageTracker._initData();
    -+    pageTracker._trackPageview();
    -+  } catch(e) {}
    -+</script>
    -+</BODY>
    -+</HTML>
    -diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.app.ActivityOptionsCompat.html b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.app.ActivityOptionsCompat.html
    -new file mode 100644
    -index 0000000..e675b7f
    ---- /dev/null
    -+++ b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.app.ActivityOptionsCompat.html
    -@@ -0,0 +1,179 @@
    -+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
    -+<HTML style="overflow:auto;">
    -+<HEAD>
    -+<meta name="generator" content="JDiff v1.1.0">
    -+<!-- Generated by the JDiff Javadoc doclet -->
    -+<!-- (http://www.jdiff.org) -->
    -+<meta name="description" content="JDiff is a Javadoc doclet which generates an HTML report of all the packages, classes, constructors, methods, and fields which have been removed, added or changed in any way, including their documentation, when two APIs are compared.">
    -+<meta name="keywords" content="diff, jdiff, javadiff, java diff, java difference, API difference, difference between two APIs, API diff, Javadoc, doclet">
    -+<TITLE>
    -+android.support.v4.app.ActivityOptionsCompat
    -+</TITLE>
    -+<link href="../../../../assets/android-developer-docs.css" rel="stylesheet" type="text/css" />
    -+<link href="../stylesheet-jdiff.css" rel="stylesheet" type="text/css" />
    -+<noscript>
    -+<style type="text/css">
    -+body{overflow:auto;}
    -+#body-content{position:relative; top:0;}
    -+#doc-content{overflow:visible;border-left:3px solid #666;}
    -+#side-nav{padding:0;}
    -+#side-nav .toggle-list ul {display:block;}
    -+#resize-packages-nav{border-bottom:3px solid #666;}
    -+</style>
    -+</noscript>
    -+<style type="text/css">
    -+</style>
    -+</HEAD>
    -+<BODY>
    -+<!-- Start of nav bar -->
    -+<a name="top"></a>
    -+<div id="header" style="margin-bottom:0;padding-bottom:0;">
    -+<div id="headerLeft">
    -+<a href="../../../../index.html" tabindex="-1" target="_top"><img src="../../../../assets/images/bg_logo.png" alt="Android Developers" /></a>
    -+</div>
    -+  <div id="headerRight">
    -+  <div id="headerLinks">
    -+<!-- <img src="/assets/images/icon_world.jpg" alt="" /> -->
    -+<span class="text">
    -+<!-- &nbsp;<a href="#">English</a> | -->
    -+<nobr><a href="http://developer.android.com" target="_top">Android Developers</a> | <a href="http://www.android.com" target="_top">Android.com</a></nobr>
    -+</span>
    -+</div>
    -+  <div class="and-diff-id" style="margin-top:6px;margin-right:8px;">
    -+    <table class="diffspectable">
    -+      <tr>
    -+        <td colspan="2" class="diffspechead">API Diff Specification</td>
    -+      </tr>
    -+      <tr>
    -+        <td class="diffspec" style="padding-top:.25em">To Level:</td>
    -+        <td class="diffvaluenew" style="padding-top:.25em">24.2.0</td>
    -+      </tr>
    -+      <tr>
    -+        <td class="diffspec">From Level:</td>
    -+        <td class="diffvalueold">24.1.0</td>
    -+      </tr>
    -+      <tr>
    -+        <td class="diffspec">Generated</td>
    -+        <td class="diffvalue">2016.08.16 14:03</td>
    -+      </tr>
    -+    </table>
    -+    </div><!-- End and-diff-id -->
    -+  <div class="and-diff-id" style="margin-right:8px;">
    -+    <table class="diffspectable">
    -+      <tr>
    -+        <td class="diffspec" colspan="2"><a href="jdiff_statistics.html">Statistics</a>
    -+      </tr>
    -+    </table>
    -+  </div> <!-- End and-diff-id -->
    -+  </div> <!-- End headerRight -->
    -+  </div> <!-- End header -->
    -+<div id="body-content" xstyle="padding:12px;padding-right:18px;">
    -+<div id="doc-content" style="position:relative;">
    -+<div id="mainBodyFluid">
    -+<H2>
    -+Class android.support.v4.app.<A HREF="../../../../reference/android/support/v4/app/ActivityOptionsCompat.html" target="_top"><font size="+2"><code>ActivityOptionsCompat</code></font></A>
    -+</H2>
    -+<a NAME="constructors"></a>
    -+<a NAME="methods"></a>
    -+<p>
    -+<a NAME="Added"></a>
    -+<TABLE summary="Added Methods" WIDTH="100%">
    -+<TR>
    -+  <TH VALIGN="TOP" COLSPAN=2>Added Methods</FONT></TD>
    -+</TH>
    -+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    -+  <TD VALIGN="TOP" WIDTH="25%">
    -+  <A NAME="android.support.v4.app.ActivityOptionsCompat.getLaunchBounds_added()"></A>
    -+  <nobr><code>Rect</code>&nbsp;<A HREF="../../../../reference/android/support/v4/app/ActivityOptionsCompat.html#getLaunchBounds()" target="_top"><code>getLaunchBounds</code></A>()</nobr>
    -+  </TD>
    -+  <TD>&nbsp;</TD>
    -+</TR>
    -+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    -+  <TD VALIGN="TOP" WIDTH="25%">
    -+  <A NAME="android.support.v4.app.ActivityOptionsCompat.makeBasic_added()"></A>
    -+  <nobr><code>ActivityOptionsCompat</code>&nbsp;<A HREF="../../../../reference/android/support/v4/app/ActivityOptionsCompat.html#makeBasic()" target="_top"><code>makeBasic</code></A>()</nobr>
    -+  </TD>
    -+  <TD>&nbsp;</TD>
    -+</TR>
    -+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    -+  <TD VALIGN="TOP" WIDTH="25%">
    -+  <A NAME="android.support.v4.app.ActivityOptionsCompat.makeClipRevealAnimation_added(android.view.View, int, int, int, int)"></A>
    -+  <nobr><code>ActivityOptionsCompat</code>&nbsp;<A HREF="../../../../reference/android/support/v4/app/ActivityOptionsCompat.html#makeClipRevealAnimation(android.view.View, int, int, int, int)" target="_top"><code>makeClipRevealAnimation</code></A>(<code>View,</nobr> int<nobr>,</nobr> int<nobr>,</nobr> int<nobr>,</nobr> int<nobr><nobr></code>)</nobr>
    -+  </TD>
    -+  <TD>&nbsp;</TD>
    -+</TR>
    -+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    -+  <TD VALIGN="TOP" WIDTH="25%">
    -+  <A NAME="android.support.v4.app.ActivityOptionsCompat.makeTaskLaunchBehind_added()"></A>
    -+  <nobr><code>ActivityOptionsCompat</code>&nbsp;<A HREF="../../../../reference/android/support/v4/app/ActivityOptionsCompat.html#makeTaskLaunchBehind()" target="_top"><code>makeTaskLaunchBehind</code></A>()</nobr>
    -+  </TD>
    -+  <TD>&nbsp;</TD>
    -+</TR>
    -+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    -+  <TD VALIGN="TOP" WIDTH="25%">
    -+  <A NAME="android.support.v4.app.ActivityOptionsCompat.requestUsageTimeReport_added(android.app.PendingIntent)"></A>
    -+  <nobr><code>void</code>&nbsp;<A HREF="../../../../reference/android/support/v4/app/ActivityOptionsCompat.html#requestUsageTimeReport(android.app.PendingIntent)" target="_top"><code>requestUsageTimeReport</code></A>(<code>PendingIntent</code>)</nobr>
    -+  </TD>
    -+  <TD>&nbsp;</TD>
    -+</TR>
    -+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    -+  <TD VALIGN="TOP" WIDTH="25%">
    -+  <A NAME="android.support.v4.app.ActivityOptionsCompat.setLaunchBounds_added(android.graphics.Rect)"></A>
    -+  <nobr><code>ActivityOptionsCompat</code>&nbsp;<A HREF="../../../../reference/android/support/v4/app/ActivityOptionsCompat.html#setLaunchBounds(android.graphics.Rect)" target="_top"><code>setLaunchBounds</code></A>(<code>Rect</code>)</nobr>
    -+  </TD>
    -+  <TD>&nbsp;</TD>
    -+</TR>
    -+</TABLE>
    -+&nbsp;
    -+<a NAME="fields"></a>
    -+<p>
    -+<a NAME="Added"></a>
    -+<TABLE summary="Added Fields" WIDTH="100%">
    -+<TR>
    -+  <TH VALIGN="TOP" COLSPAN=2>Added Fields</FONT></TD>
    -+</TH>
    -+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    -+  <TD VALIGN="TOP" WIDTH="25%">
    -+  <A NAME="android.support.v4.app.ActivityOptionsCompat.EXTRA_USAGE_TIME_REPORT"></A>
    -+  <nobr><code>String</code>&nbsp;<A HREF="../../../../reference/android/support/v4/app/ActivityOptionsCompat.html#EXTRA_USAGE_TIME_REPORT" target="_top"><code>EXTRA_USAGE_TIME_REPORT</code></A></nobr>
    -+  </TD>
    -+  <TD>&nbsp;</TD>
    -+</TR>
    -+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    -+  <TD VALIGN="TOP" WIDTH="25%">
    -+  <A NAME="android.support.v4.app.ActivityOptionsCompat.EXTRA_USAGE_TIME_REPORT_PACKAGES"></A>
    -+  <nobr><code>String</code>&nbsp;<A HREF="../../../../reference/android/support/v4/app/ActivityOptionsCompat.html#EXTRA_USAGE_TIME_REPORT_PACKAGES" target="_top"><code>EXTRA_USAGE_TIME_REPORT_PACKAGES</code></A></nobr>
    -+  </TD>
    -+  <TD>&nbsp;</TD>
    -+</TR>
    -+</TABLE>
    -+&nbsp;
    -+      </div>	
    -+      <div id="footer">
    -+        <div id="copyright">
    -+        Except as noted, this content is licensed under 
    -+        <a href="http://creativecommons.org/licenses/by/2.5/"> Creative Commons Attribution 2.5</a>.
    -+        For details and restrictions, see the <a href="/license.html">Content License</a>.
    -+        </div>
    -+      <div id="footerlinks">
    -+      <p>
    -+        <a href="http://www.android.com/terms.html">Site Terms of Service</a> -
    -+        <a href="http://www.android.com/privacy.html">Privacy Policy</a> -
    -+        <a href="http://www.android.com/branding.html">Brand Guidelines</a>
    -+      </p>
    -+    </div>
    -+    </div> <!-- end footer -->
    -+    </div><!-- end doc-content -->
    -+    </div> <!-- end body-content --> 
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    -+</script>
    -+<script type="text/javascript">
    -+  try {
    -+    var pageTracker = _gat._getTracker("UA-5831155-1");
    -+    pageTracker._setAllowAnchor(true);
    -+    pageTracker._initData();
    -+    pageTracker._trackPageview();
    -+  } catch(e) {}
    -+</script>
    -+</BODY>
    -+</HTML>
    -diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.app.FragmentController.html b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.app.FragmentController.html
    -new file mode 100644
    -index 0000000..dfc1a60
    ---- /dev/null
    -+++ b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.app.FragmentController.html
    -@@ -0,0 +1,122 @@
    -+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
    -+<HTML style="overflow:auto;">
    -+<HEAD>
    -+<meta name="generator" content="JDiff v1.1.0">
    -+<!-- Generated by the JDiff Javadoc doclet -->
    -+<!-- (http://www.jdiff.org) -->
    -+<meta name="description" content="JDiff is a Javadoc doclet which generates an HTML report of all the packages, classes, constructors, methods, and fields which have been removed, added or changed in any way, including their documentation, when two APIs are compared.">
    -+<meta name="keywords" content="diff, jdiff, javadiff, java diff, java difference, API difference, difference between two APIs, API diff, Javadoc, doclet">
    -+<TITLE>
    -+android.support.v4.app.FragmentController
    -+</TITLE>
    -+<link href="../../../../assets/android-developer-docs.css" rel="stylesheet" type="text/css" />
    -+<link href="../stylesheet-jdiff.css" rel="stylesheet" type="text/css" />
    -+<noscript>
    -+<style type="text/css">
    -+body{overflow:auto;}
    -+#body-content{position:relative; top:0;}
    -+#doc-content{overflow:visible;border-left:3px solid #666;}
    -+#side-nav{padding:0;}
    -+#side-nav .toggle-list ul {display:block;}
    -+#resize-packages-nav{border-bottom:3px solid #666;}
    -+</style>
    -+</noscript>
    -+<style type="text/css">
    -+</style>
    -+</HEAD>
    -+<BODY>
    -+<!-- Start of nav bar -->
    -+<a name="top"></a>
    -+<div id="header" style="margin-bottom:0;padding-bottom:0;">
    -+<div id="headerLeft">
    -+<a href="../../../../index.html" tabindex="-1" target="_top"><img src="../../../../assets/images/bg_logo.png" alt="Android Developers" /></a>
    -+</div>
    -+  <div id="headerRight">
    -+  <div id="headerLinks">
    -+<!-- <img src="/assets/images/icon_world.jpg" alt="" /> -->
    -+<span class="text">
    -+<!-- &nbsp;<a href="#">English</a> | -->
    -+<nobr><a href="http://developer.android.com" target="_top">Android Developers</a> | <a href="http://www.android.com" target="_top">Android.com</a></nobr>
    -+</span>
    -+</div>
    -+  <div class="and-diff-id" style="margin-top:6px;margin-right:8px;">
    -+    <table class="diffspectable">
    -+      <tr>
    -+        <td colspan="2" class="diffspechead">API Diff Specification</td>
    -+      </tr>
    -+      <tr>
    -+        <td class="diffspec" style="padding-top:.25em">To Level:</td>
    -+        <td class="diffvaluenew" style="padding-top:.25em">24.2.0</td>
    -+      </tr>
    -+      <tr>
    -+        <td class="diffspec">From Level:</td>
    -+        <td class="diffvalueold">24.1.0</td>
    -+      </tr>
    -+      <tr>
    -+        <td class="diffspec">Generated</td>
    -+        <td class="diffvalue">2016.08.16 14:03</td>
    -+      </tr>
    -+    </table>
    -+    </div><!-- End and-diff-id -->
    -+  <div class="and-diff-id" style="margin-right:8px;">
    -+    <table class="diffspectable">
    -+      <tr>
    -+        <td class="diffspec" colspan="2"><a href="jdiff_statistics.html">Statistics</a>
    -+      </tr>
    -+    </table>
    -+  </div> <!-- End and-diff-id -->
    -+  </div> <!-- End headerRight -->
    -+  </div> <!-- End header -->
    -+<div id="body-content" xstyle="padding:12px;padding-right:18px;">
    -+<div id="doc-content" style="position:relative;">
    -+<div id="mainBodyFluid">
    -+<H2>
    -+Class android.support.v4.app.<A HREF="../../../../reference/android/support/v4/app/FragmentController.html" target="_top"><font size="+2"><code>FragmentController</code></font></A>
    -+</H2>
    -+<a NAME="constructors"></a>
    -+<a NAME="methods"></a>
    -+<p>
    -+<a NAME="Added"></a>
    -+<TABLE summary="Added Methods" WIDTH="100%">
    -+<TR>
    -+  <TH VALIGN="TOP" COLSPAN=2>Added Methods</FONT></TD>
    -+</TH>
    -+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    -+  <TD VALIGN="TOP" WIDTH="25%">
    -+  <A NAME="android.support.v4.app.FragmentController.findFragmentByWho_added(java.lang.String)"></A>
    -+  <nobr><code>Fragment</code>&nbsp;<A HREF="../../../../reference/android/support/v4/app/FragmentController.html#findFragmentByWho(java.lang.String)" target="_top"><code>findFragmentByWho</code></A>(<code>String</code>)</nobr>
    -+  </TD>
    -+  <TD>&nbsp;</TD>
    -+</TR>
    -+</TABLE>
    -+&nbsp;
    -+<a NAME="fields"></a>
    -+      </div>	
    -+      <div id="footer">
    -+        <div id="copyright">
    -+        Except as noted, this content is licensed under 
    -+        <a href="http://creativecommons.org/licenses/by/2.5/"> Creative Commons Attribution 2.5</a>.
    -+        For details and restrictions, see the <a href="/license.html">Content License</a>.
    -+        </div>
    -+      <div id="footerlinks">
    -+      <p>
    -+        <a href="http://www.android.com/terms.html">Site Terms of Service</a> -
    -+        <a href="http://www.android.com/privacy.html">Privacy Policy</a> -
    -+        <a href="http://www.android.com/branding.html">Brand Guidelines</a>
    -+      </p>
    -+    </div>
    -+    </div> <!-- end footer -->
    -+    </div><!-- end doc-content -->
    -+    </div> <!-- end body-content --> 
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    -+</script>
    -+<script type="text/javascript">
    -+  try {
    -+    var pageTracker = _gat._getTracker("UA-5831155-1");
    -+    pageTracker._setAllowAnchor(true);
    -+    pageTracker._initData();
    -+    pageTracker._trackPageview();
    -+  } catch(e) {}
    -+</script>
    -+</BODY>
    -+</HTML>
    -diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.app.ServiceCompat.html b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.app.ServiceCompat.html
    -new file mode 100644
    -index 0000000..211a88f
    ---- /dev/null
    -+++ b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.app.ServiceCompat.html
    -@@ -0,0 +1,144 @@
    -+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
    -+<HTML style="overflow:auto;">
    -+<HEAD>
    -+<meta name="generator" content="JDiff v1.1.0">
    -+<!-- Generated by the JDiff Javadoc doclet -->
    -+<!-- (http://www.jdiff.org) -->
    -+<meta name="description" content="JDiff is a Javadoc doclet which generates an HTML report of all the packages, classes, constructors, methods, and fields which have been removed, added or changed in any way, including their documentation, when two APIs are compared.">
    -+<meta name="keywords" content="diff, jdiff, javadiff, java diff, java difference, API difference, difference between two APIs, API diff, Javadoc, doclet">
    -+<TITLE>
    -+android.support.v4.app.ServiceCompat
    -+</TITLE>
    -+<link href="../../../../assets/android-developer-docs.css" rel="stylesheet" type="text/css" />
    -+<link href="../stylesheet-jdiff.css" rel="stylesheet" type="text/css" />
    -+<noscript>
    -+<style type="text/css">
    -+body{overflow:auto;}
    -+#body-content{position:relative; top:0;}
    -+#doc-content{overflow:visible;border-left:3px solid #666;}
    -+#side-nav{padding:0;}
    -+#side-nav .toggle-list ul {display:block;}
    -+#resize-packages-nav{border-bottom:3px solid #666;}
    -+</style>
    -+</noscript>
    -+<style type="text/css">
    -+</style>
    -+</HEAD>
    -+<BODY>
    -+<!-- Start of nav bar -->
    -+<a name="top"></a>
    -+<div id="header" style="margin-bottom:0;padding-bottom:0;">
    -+<div id="headerLeft">
    -+<a href="../../../../index.html" tabindex="-1" target="_top"><img src="../../../../assets/images/bg_logo.png" alt="Android Developers" /></a>
    -+</div>
    -+  <div id="headerRight">
    -+  <div id="headerLinks">
    -+<!-- <img src="/assets/images/icon_world.jpg" alt="" /> -->
    -+<span class="text">
    -+<!-- &nbsp;<a href="#">English</a> | -->
    -+<nobr><a href="http://developer.android.com" target="_top">Android Developers</a> | <a href="http://www.android.com" target="_top">Android.com</a></nobr>
    -+</span>
    -+</div>
    -+  <div class="and-diff-id" style="margin-top:6px;margin-right:8px;">
    -+    <table class="diffspectable">
    -+      <tr>
    -+        <td colspan="2" class="diffspechead">API Diff Specification</td>
    -+      </tr>
    -+      <tr>
    -+        <td class="diffspec" style="padding-top:.25em">To Level:</td>
    -+        <td class="diffvaluenew" style="padding-top:.25em">24.2.0</td>
    -+      </tr>
    -+      <tr>
    -+        <td class="diffspec">From Level:</td>
    -+        <td class="diffvalueold">24.1.0</td>
    -+      </tr>
    -+      <tr>
    -+        <td class="diffspec">Generated</td>
    -+        <td class="diffvalue">2016.08.16 14:03</td>
    -+      </tr>
    -+    </table>
    -+    </div><!-- End and-diff-id -->
    -+  <div class="and-diff-id" style="margin-right:8px;">
    -+    <table class="diffspectable">
    -+      <tr>
    -+        <td class="diffspec" colspan="2"><a href="jdiff_statistics.html">Statistics</a>
    -+      </tr>
    -+    </table>
    -+  </div> <!-- End and-diff-id -->
    -+  </div> <!-- End headerRight -->
    -+  </div> <!-- End header -->
    -+<div id="body-content" xstyle="padding:12px;padding-right:18px;">
    -+<div id="doc-content" style="position:relative;">
    -+<div id="mainBodyFluid">
    -+<H2>
    -+Class android.support.v4.app.<A HREF="../../../../reference/android/support/v4/app/ServiceCompat.html" target="_top"><font size="+2"><code>ServiceCompat</code></font></A>
    -+</H2>
    -+<a NAME="constructors"></a>
    -+<a NAME="methods"></a>
    -+<p>
    -+<a NAME="Added"></a>
    -+<TABLE summary="Added Methods" WIDTH="100%">
    -+<TR>
    -+  <TH VALIGN="TOP" COLSPAN=2>Added Methods</FONT></TD>
    -+</TH>
    -+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    -+  <TD VALIGN="TOP" WIDTH="25%">
    -+  <A NAME="android.support.v4.app.ServiceCompat.stopForeground_added(android.app.Service, int)"></A>
    -+  <nobr><code>void</code>&nbsp;<A HREF="../../../../reference/android/support/v4/app/ServiceCompat.html#stopForeground(android.app.Service, int)" target="_top"><code>stopForeground</code></A>(<code>Service,</nobr> int<nobr><nobr></code>)</nobr>
    -+  </TD>
    -+  <TD>&nbsp;</TD>
    -+</TR>
    -+</TABLE>
    -+&nbsp;
    -+<a NAME="fields"></a>
    -+<p>
    -+<a NAME="Added"></a>
    -+<TABLE summary="Added Fields" WIDTH="100%">
    -+<TR>
    -+  <TH VALIGN="TOP" COLSPAN=2>Added Fields</FONT></TD>
    -+</TH>
    -+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    -+  <TD VALIGN="TOP" WIDTH="25%">
    -+  <A NAME="android.support.v4.app.ServiceCompat.STOP_FOREGROUND_DETACH"></A>
    -+  <nobr><code>int</code>&nbsp;<A HREF="../../../../reference/android/support/v4/app/ServiceCompat.html#STOP_FOREGROUND_DETACH" target="_top"><code>STOP_FOREGROUND_DETACH</code></A></nobr>
    -+  </TD>
    -+  <TD>&nbsp;</TD>
    -+</TR>
    -+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    -+  <TD VALIGN="TOP" WIDTH="25%">
    -+  <A NAME="android.support.v4.app.ServiceCompat.STOP_FOREGROUND_REMOVE"></A>
    -+  <nobr><code>int</code>&nbsp;<A HREF="../../../../reference/android/support/v4/app/ServiceCompat.html#STOP_FOREGROUND_REMOVE" target="_top"><code>STOP_FOREGROUND_REMOVE</code></A></nobr>
    -+  </TD>
    -+  <TD>&nbsp;</TD>
    -+</TR>
    -+</TABLE>
    -+&nbsp;
    -+      </div>	
    -+      <div id="footer">
    -+        <div id="copyright">
    -+        Except as noted, this content is licensed under 
    -+        <a href="http://creativecommons.org/licenses/by/2.5/"> Creative Commons Attribution 2.5</a>.
    -+        For details and restrictions, see the <a href="/license.html">Content License</a>.
    -+        </div>
    -+      <div id="footerlinks">
    -+      <p>
    -+        <a href="http://www.android.com/terms.html">Site Terms of Service</a> -
    -+        <a href="http://www.android.com/privacy.html">Privacy Policy</a> -
    -+        <a href="http://www.android.com/branding.html">Brand Guidelines</a>
    -+      </p>
    -+    </div>
    -+    </div> <!-- end footer -->
    -+    </div><!-- end doc-content -->
    -+    </div> <!-- end body-content --> 
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    -+</script>
    -+<script type="text/javascript">
    -+  try {
    -+    var pageTracker = _gat._getTracker("UA-5831155-1");
    -+    pageTracker._setAllowAnchor(true);
    -+    pageTracker._initData();
    -+    pageTracker._trackPageview();
    -+  } catch(e) {}
    -+</script>
    -+</BODY>
    -+</HTML>
    -diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.app.SharedElementCallback.html b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.app.SharedElementCallback.html
    -new file mode 100644
    -index 0000000..7394059
    ---- /dev/null
    -+++ b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.app.SharedElementCallback.html
    -@@ -0,0 +1,122 @@
    -+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
    -+<HTML style="overflow:auto;">
    -+<HEAD>
    -+<meta name="generator" content="JDiff v1.1.0">
    -+<!-- Generated by the JDiff Javadoc doclet -->
    -+<!-- (http://www.jdiff.org) -->
    -+<meta name="description" content="JDiff is a Javadoc doclet which generates an HTML report of all the packages, classes, constructors, methods, and fields which have been removed, added or changed in any way, including their documentation, when two APIs are compared.">
    -+<meta name="keywords" content="diff, jdiff, javadiff, java diff, java difference, API difference, difference between two APIs, API diff, Javadoc, doclet">
    -+<TITLE>
    -+android.support.v4.app.SharedElementCallback
    -+</TITLE>
    -+<link href="../../../../assets/android-developer-docs.css" rel="stylesheet" type="text/css" />
    -+<link href="../stylesheet-jdiff.css" rel="stylesheet" type="text/css" />
    -+<noscript>
    -+<style type="text/css">
    -+body{overflow:auto;}
    -+#body-content{position:relative; top:0;}
    -+#doc-content{overflow:visible;border-left:3px solid #666;}
    -+#side-nav{padding:0;}
    -+#side-nav .toggle-list ul {display:block;}
    -+#resize-packages-nav{border-bottom:3px solid #666;}
    -+</style>
    -+</noscript>
    -+<style type="text/css">
    -+</style>
    -+</HEAD>
    -+<BODY>
    -+<!-- Start of nav bar -->
    -+<a name="top"></a>
    -+<div id="header" style="margin-bottom:0;padding-bottom:0;">
    -+<div id="headerLeft">
    -+<a href="../../../../index.html" tabindex="-1" target="_top"><img src="../../../../assets/images/bg_logo.png" alt="Android Developers" /></a>
    -+</div>
    -+  <div id="headerRight">
    -+  <div id="headerLinks">
    -+<!-- <img src="/assets/images/icon_world.jpg" alt="" /> -->
    -+<span class="text">
    -+<!-- &nbsp;<a href="#">English</a> | -->
    -+<nobr><a href="http://developer.android.com" target="_top">Android Developers</a> | <a href="http://www.android.com" target="_top">Android.com</a></nobr>
    -+</span>
    -+</div>
    -+  <div class="and-diff-id" style="margin-top:6px;margin-right:8px;">
    -+    <table class="diffspectable">
    -+      <tr>
    -+        <td colspan="2" class="diffspechead">API Diff Specification</td>
    -+      </tr>
    -+      <tr>
    -+        <td class="diffspec" style="padding-top:.25em">To Level:</td>
    -+        <td class="diffvaluenew" style="padding-top:.25em">24.2.0</td>
    -+      </tr>
    -+      <tr>
    -+        <td class="diffspec">From Level:</td>
    -+        <td class="diffvalueold">24.1.0</td>
    -+      </tr>
    -+      <tr>
    -+        <td class="diffspec">Generated</td>
    -+        <td class="diffvalue">2016.08.16 14:03</td>
    -+      </tr>
    -+    </table>
    -+    </div><!-- End and-diff-id -->
    -+  <div class="and-diff-id" style="margin-right:8px;">
    -+    <table class="diffspectable">
    -+      <tr>
    -+        <td class="diffspec" colspan="2"><a href="jdiff_statistics.html">Statistics</a>
    -+      </tr>
    -+    </table>
    -+  </div> <!-- End and-diff-id -->
    -+  </div> <!-- End headerRight -->
    -+  </div> <!-- End header -->
    -+<div id="body-content" xstyle="padding:12px;padding-right:18px;">
    -+<div id="doc-content" style="position:relative;">
    -+<div id="mainBodyFluid">
    -+<H2>
    -+Class android.support.v4.app.<A HREF="../../../../reference/android/support/v4/app/SharedElementCallback.html" target="_top"><font size="+2"><code>SharedElementCallback</code></font></A>
    -+</H2>
    -+<a NAME="constructors"></a>
    -+<a NAME="methods"></a>
    -+<p>
    -+<a NAME="Added"></a>
    -+<TABLE summary="Added Methods" WIDTH="100%">
    -+<TR>
    -+  <TH VALIGN="TOP" COLSPAN=2>Added Methods</FONT></TD>
    -+</TH>
    -+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    -+  <TD VALIGN="TOP" WIDTH="25%">
    -+  <A NAME="android.support.v4.app.SharedElementCallback.onSharedElementsArrived_added(java.util.List<java.lang.String>, java.util.List<android.view.View>, android.support.v4.app.SharedElementCallback.OnSharedElementsReadyListener)"></A>
    -+  <nobr><code>void</code>&nbsp;<A HREF="../../../../reference/android/support/v4/app/SharedElementCallback.html#onSharedElementsArrived(java.util.List<java.lang.String>, java.util.List<android.view.View>, android.support.v4.app.SharedElementCallback.OnSharedElementsReadyListener)" target="_top"><code>onSharedElementsArrived</code></A>(<code>List&lt;String&gt;,</nobr> List&lt;View&gt;<nobr>,</nobr> OnSharedElementsReadyListener<nobr><nobr></code>)</nobr>
    -+  </TD>
    -+  <TD>&nbsp;</TD>
    -+</TR>
    -+</TABLE>
    -+&nbsp;
    -+<a NAME="fields"></a>
    -+      </div>	
    -+      <div id="footer">
    -+        <div id="copyright">
    -+        Except as noted, this content is licensed under 
    -+        <a href="http://creativecommons.org/licenses/by/2.5/"> Creative Commons Attribution 2.5</a>.
    -+        For details and restrictions, see the <a href="/license.html">Content License</a>.
    -+        </div>
    -+      <div id="footerlinks">
    -+      <p>
    -+        <a href="http://www.android.com/terms.html">Site Terms of Service</a> -
    -+        <a href="http://www.android.com/privacy.html">Privacy Policy</a> -
    -+        <a href="http://www.android.com/branding.html">Brand Guidelines</a>
    -+      </p>
    -+    </div>
    -+    </div> <!-- end footer -->
    -+    </div><!-- end doc-content -->
    -+    </div> <!-- end body-content --> 
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    -+</script>
    -+<script type="text/javascript">
    -+  try {
    -+    var pageTracker = _gat._getTracker("UA-5831155-1");
    -+    pageTracker._setAllowAnchor(true);
    -+    pageTracker._initData();
    -+    pageTracker._trackPageview();
    -+  } catch(e) {}
    -+</script>
    -+</BODY>
    -+</HTML>
    -diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.content.ContextCompat.html b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.content.ContextCompat.html
    -new file mode 100644
    -index 0000000..b6157a2
    ---- /dev/null
    -+++ b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.content.ContextCompat.html
    -@@ -0,0 +1,125 @@
    -+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
    -+<HTML style="overflow:auto;">
    -+<HEAD>
    -+<meta name="generator" content="JDiff v1.1.0">
    -+<!-- Generated by the JDiff Javadoc doclet -->
    -+<!-- (http://www.jdiff.org) -->
    -+<meta name="description" content="JDiff is a Javadoc doclet which generates an HTML report of all the packages, classes, constructors, methods, and fields which have been removed, added or changed in any way, including their documentation, when two APIs are compared.">
    -+<meta name="keywords" content="diff, jdiff, javadiff, java diff, java difference, API difference, difference between two APIs, API diff, Javadoc, doclet">
    -+<TITLE>
    -+android.support.v4.content.ContextCompat
    -+</TITLE>
    -+<link href="../../../../assets/android-developer-docs.css" rel="stylesheet" type="text/css" />
    -+<link href="../stylesheet-jdiff.css" rel="stylesheet" type="text/css" />
    -+<noscript>
    -+<style type="text/css">
    -+body{overflow:auto;}
    -+#body-content{position:relative; top:0;}
    -+#doc-content{overflow:visible;border-left:3px solid #666;}
    -+#side-nav{padding:0;}
    -+#side-nav .toggle-list ul {display:block;}
    -+#resize-packages-nav{border-bottom:3px solid #666;}
    -+</style>
    -+</noscript>
    -+<style type="text/css">
    -+</style>
    -+</HEAD>
    -+<BODY>
    -+<!-- Start of nav bar -->
    -+<a name="top"></a>
    -+<div id="header" style="margin-bottom:0;padding-bottom:0;">
    -+<div id="headerLeft">
    -+<a href="../../../../index.html" tabindex="-1" target="_top"><img src="../../../../assets/images/bg_logo.png" alt="Android Developers" /></a>
    -+</div>
    -+  <div id="headerRight">
    -+  <div id="headerLinks">
    -+<!-- <img src="/assets/images/icon_world.jpg" alt="" /> -->
    -+<span class="text">
    -+<!-- &nbsp;<a href="#">English</a> | -->
    -+<nobr><a href="http://developer.android.com" target="_top">Android Developers</a> | <a href="http://www.android.com" target="_top">Android.com</a></nobr>
    -+</span>
    -+</div>
    -+  <div class="and-diff-id" style="margin-top:6px;margin-right:8px;">
    -+    <table class="diffspectable">
    -+      <tr>
    -+        <td colspan="2" class="diffspechead">API Diff Specification</td>
    -+      </tr>
    -+      <tr>
    -+        <td class="diffspec" style="padding-top:.25em">To Level:</td>
    -+        <td class="diffvaluenew" style="padding-top:.25em">24.2.0</td>
    -+      </tr>
    -+      <tr>
    -+        <td class="diffspec">From Level:</td>
    -+        <td class="diffvalueold">24.1.0</td>
    -+      </tr>
    -+      <tr>
    -+        <td class="diffspec">Generated</td>
    -+        <td class="diffvalue">2016.08.16 14:03</td>
    -+      </tr>
    -+    </table>
    -+    </div><!-- End and-diff-id -->
    -+  <div class="and-diff-id" style="margin-right:8px;">
    -+    <table class="diffspectable">
    -+      <tr>
    -+        <td class="diffspec" colspan="2"><a href="jdiff_statistics.html">Statistics</a>
    -+      </tr>
    -+    </table>
    -+  </div> <!-- End and-diff-id -->
    -+  </div> <!-- End headerRight -->
    -+  </div> <!-- End header -->
    -+<div id="body-content" xstyle="padding:12px;padding-right:18px;">
    -+<div id="doc-content" style="position:relative;">
    -+<div id="mainBodyFluid">
    -+<H2>
    -+Class android.support.v4.content.<A HREF="../../../../reference/android/support/v4/content/ContextCompat.html" target="_top"><font size="+2"><code>ContextCompat</code></font></A>
    -+</H2>
    -+<a NAME="constructors"></a>
    -+<p>
    -+<a NAME="Changed"></a>
    -+<TABLE summary="Changed Constructors" WIDTH="100%">
    -+<TR>
    -+  <TH VALIGN="TOP" COLSPAN=3>Changed Constructors</FONT></TD>
    -+</TH>
    -+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    -+  <TD VALIGN="TOP" WIDTH="25%">
    -+  <A NAME="android.support.v4.content.ContextCompat.ctor_changed()"></A>
    -+  <nobr><A HREF="../../../../reference/android/support/v4/content/ContextCompat.html#ContextCompat()" target="_top"><code>ContextCompat</code></A>()  </nobr>
    -+  </TD>
    -+  <TD VALIGN="TOP" WIDTH="30%">
    -+<b>Now deprecated</b>.<br>
    -+  </TD>
    -+  <TD>&nbsp;</TD>
    -+</TR>
    -+</TABLE>
    -+&nbsp;
    -+<a NAME="methods"></a>
    -+<a NAME="fields"></a>
    -+      </div>	
    -+      <div id="footer">
    -+        <div id="copyright">
    -+        Except as noted, this content is licensed under 
    -+        <a href="http://creativecommons.org/licenses/by/2.5/"> Creative Commons Attribution 2.5</a>.
    -+        For details and restrictions, see the <a href="/license.html">Content License</a>.
    -+        </div>
    -+      <div id="footerlinks">
    -+      <p>
    -+        <a href="http://www.android.com/terms.html">Site Terms of Service</a> -
    -+        <a href="http://www.android.com/privacy.html">Privacy Policy</a> -
    -+        <a href="http://www.android.com/branding.html">Brand Guidelines</a>
    -+      </p>
    -+    </div>
    -+    </div> <!-- end footer -->
    -+    </div><!-- end doc-content -->
    -+    </div> <!-- end body-content --> 
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    -+</script>
    -+<script type="text/javascript">
    -+  try {
    -+    var pageTracker = _gat._getTracker("UA-5831155-1");
    -+    pageTracker._setAllowAnchor(true);
    -+    pageTracker._initData();
    -+    pageTracker._trackPageview();
    -+  } catch(e) {}
    -+</script>
    -+</BODY>
    -+</HTML>
    -diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.graphics.drawable.DrawableCompat.html b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.graphics.drawable.DrawableCompat.html
    -new file mode 100644
    -index 0000000..92f1ba4
    ---- /dev/null
    -+++ b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.graphics.drawable.DrawableCompat.html
    -@@ -0,0 +1,122 @@
    -+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
    -+<HTML style="overflow:auto;">
    -+<HEAD>
    -+<meta name="generator" content="JDiff v1.1.0">
    -+<!-- Generated by the JDiff Javadoc doclet -->
    -+<!-- (http://www.jdiff.org) -->
    -+<meta name="description" content="JDiff is a Javadoc doclet which generates an HTML report of all the packages, classes, constructors, methods, and fields which have been removed, added or changed in any way, including their documentation, when two APIs are compared.">
    -+<meta name="keywords" content="diff, jdiff, javadiff, java diff, java difference, API difference, difference between two APIs, API diff, Javadoc, doclet">
    -+<TITLE>
    -+android.support.v4.graphics.drawable.DrawableCompat
    -+</TITLE>
    -+<link href="../../../../assets/android-developer-docs.css" rel="stylesheet" type="text/css" />
    -+<link href="../stylesheet-jdiff.css" rel="stylesheet" type="text/css" />
    -+<noscript>
    -+<style type="text/css">
    -+body{overflow:auto;}
    -+#body-content{position:relative; top:0;}
    -+#doc-content{overflow:visible;border-left:3px solid #666;}
    -+#side-nav{padding:0;}
    -+#side-nav .toggle-list ul {display:block;}
    -+#resize-packages-nav{border-bottom:3px solid #666;}
    -+</style>
    -+</noscript>
    -+<style type="text/css">
    -+</style>
    -+</HEAD>
    -+<BODY>
    -+<!-- Start of nav bar -->
    -+<a name="top"></a>
    -+<div id="header" style="margin-bottom:0;padding-bottom:0;">
    -+<div id="headerLeft">
    -+<a href="../../../../index.html" tabindex="-1" target="_top"><img src="../../../../assets/images/bg_logo.png" alt="Android Developers" /></a>
    -+</div>
    -+  <div id="headerRight">
    -+  <div id="headerLinks">
    -+<!-- <img src="/assets/images/icon_world.jpg" alt="" /> -->
    -+<span class="text">
    -+<!-- &nbsp;<a href="#">English</a> | -->
    -+<nobr><a href="http://developer.android.com" target="_top">Android Developers</a> | <a href="http://www.android.com" target="_top">Android.com</a></nobr>
    -+</span>
    -+</div>
    -+  <div class="and-diff-id" style="margin-top:6px;margin-right:8px;">
    -+    <table class="diffspectable">
    -+      <tr>
    -+        <td colspan="2" class="diffspechead">API Diff Specification</td>
    -+      </tr>
    -+      <tr>
    -+        <td class="diffspec" style="padding-top:.25em">To Level:</td>
    -+        <td class="diffvaluenew" style="padding-top:.25em">24.2.0</td>
    -+      </tr>
    -+      <tr>
    -+        <td class="diffspec">From Level:</td>
    -+        <td class="diffvalueold">24.1.0</td>
    -+      </tr>
    -+      <tr>
    -+        <td class="diffspec">Generated</td>
    -+        <td class="diffvalue">2016.08.16 14:03</td>
    -+      </tr>
    -+    </table>
    -+    </div><!-- End and-diff-id -->
    -+  <div class="and-diff-id" style="margin-right:8px;">
    -+    <table class="diffspectable">
    -+      <tr>
    -+        <td class="diffspec" colspan="2"><a href="jdiff_statistics.html">Statistics</a>
    -+      </tr>
    -+    </table>
    -+  </div> <!-- End and-diff-id -->
    -+  </div> <!-- End headerRight -->
    -+  </div> <!-- End header -->
    -+<div id="body-content" xstyle="padding:12px;padding-right:18px;">
    -+<div id="doc-content" style="position:relative;">
    -+<div id="mainBodyFluid">
    -+<H2>
    -+Class android.support.v4.graphics.drawable.<A HREF="../../../../reference/android/support/v4/graphics/drawable/DrawableCompat.html" target="_top"><font size="+2"><code>DrawableCompat</code></font></A>
    -+</H2>
    -+<a NAME="constructors"></a>
    -+<a NAME="methods"></a>
    -+<p>
    -+<a NAME="Added"></a>
    -+<TABLE summary="Added Methods" WIDTH="100%">
    -+<TR>
    -+  <TH VALIGN="TOP" COLSPAN=2>Added Methods</FONT></TD>
    -+</TH>
    -+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    -+  <TD VALIGN="TOP" WIDTH="25%">
    -+  <A NAME="android.support.v4.graphics.drawable.DrawableCompat.clearColorFilter_added(android.graphics.drawable.Drawable)"></A>
    -+  <nobr><code>void</code>&nbsp;<A HREF="../../../../reference/android/support/v4/graphics/drawable/DrawableCompat.html#clearColorFilter(android.graphics.drawable.Drawable)" target="_top"><code>clearColorFilter</code></A>(<code>Drawable</code>)</nobr>
    -+  </TD>
    -+  <TD>&nbsp;</TD>
    -+</TR>
    -+</TABLE>
    -+&nbsp;
    -+<a NAME="fields"></a>
    -+      </div>	
    -+      <div id="footer">
    -+        <div id="copyright">
    -+        Except as noted, this content is licensed under 
    -+        <a href="http://creativecommons.org/licenses/by/2.5/"> Creative Commons Attribution 2.5</a>.
    -+        For details and restrictions, see the <a href="/license.html">Content License</a>.
    -+        </div>
    -+      <div id="footerlinks">
    -+      <p>
    -+        <a href="http://www.android.com/terms.html">Site Terms of Service</a> -
    -+        <a href="http://www.android.com/privacy.html">Privacy Policy</a> -
    -+        <a href="http://www.android.com/branding.html">Brand Guidelines</a>
    -+      </p>
    -+    </div>
    -+    </div> <!-- end footer -->
    -+    </div><!-- end doc-content -->
    -+    </div> <!-- end body-content --> 
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    -+</script>
    -+<script type="text/javascript">
    -+  try {
    -+    var pageTracker = _gat._getTracker("UA-5831155-1");
    -+    pageTracker._setAllowAnchor(true);
    -+    pageTracker._initData();
    -+    pageTracker._trackPageview();
    -+  } catch(e) {}
    -+</script>
    -+</BODY>
    -+</HTML>
    -diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.media.MediaBrowserCompat.MediaItem.html b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.media.MediaBrowserCompat.MediaItem.html
    -new file mode 100644
    -index 0000000..52da3d4
    ---- /dev/null
    -+++ b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.media.MediaBrowserCompat.MediaItem.html
    -@@ -0,0 +1,129 @@
    -+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
    -+<HTML style="overflow:auto;">
    -+<HEAD>
    -+<meta name="generator" content="JDiff v1.1.0">
    -+<!-- Generated by the JDiff Javadoc doclet -->
    -+<!-- (http://www.jdiff.org) -->
    -+<meta name="description" content="JDiff is a Javadoc doclet which generates an HTML report of all the packages, classes, constructors, methods, and fields which have been removed, added or changed in any way, including their documentation, when two APIs are compared.">
    -+<meta name="keywords" content="diff, jdiff, javadiff, java diff, java difference, API difference, difference between two APIs, API diff, Javadoc, doclet">
    -+<TITLE>
    -+android.support.v4.media.MediaBrowserCompat.MediaItem
    -+</TITLE>
    -+<link href="../../../../assets/android-developer-docs.css" rel="stylesheet" type="text/css" />
    -+<link href="../stylesheet-jdiff.css" rel="stylesheet" type="text/css" />
    -+<noscript>
    -+<style type="text/css">
    -+body{overflow:auto;}
    -+#body-content{position:relative; top:0;}
    -+#doc-content{overflow:visible;border-left:3px solid #666;}
    -+#side-nav{padding:0;}
    -+#side-nav .toggle-list ul {display:block;}
    -+#resize-packages-nav{border-bottom:3px solid #666;}
    -+</style>
    -+</noscript>
    -+<style type="text/css">
    -+</style>
    -+</HEAD>
    -+<BODY>
    -+<!-- Start of nav bar -->
    -+<a name="top"></a>
    -+<div id="header" style="margin-bottom:0;padding-bottom:0;">
    -+<div id="headerLeft">
    -+<a href="../../../../index.html" tabindex="-1" target="_top"><img src="../../../../assets/images/bg_logo.png" alt="Android Developers" /></a>
    -+</div>
    -+  <div id="headerRight">
    -+  <div id="headerLinks">
    -+<!-- <img src="/assets/images/icon_world.jpg" alt="" /> -->
    -+<span class="text">
    -+<!-- &nbsp;<a href="#">English</a> | -->
    -+<nobr><a href="http://developer.android.com" target="_top">Android Developers</a> | <a href="http://www.android.com" target="_top">Android.com</a></nobr>
    -+</span>
    -+</div>
    -+  <div class="and-diff-id" style="margin-top:6px;margin-right:8px;">
    -+    <table class="diffspectable">
    -+      <tr>
    -+        <td colspan="2" class="diffspechead">API Diff Specification</td>
    -+      </tr>
    -+      <tr>
    -+        <td class="diffspec" style="padding-top:.25em">To Level:</td>
    -+        <td class="diffvaluenew" style="padding-top:.25em">24.2.0</td>
    -+      </tr>
    -+      <tr>
    -+        <td class="diffspec">From Level:</td>
    -+        <td class="diffvalueold">24.1.0</td>
    -+      </tr>
    -+      <tr>
    -+        <td class="diffspec">Generated</td>
    -+        <td class="diffvalue">2016.08.16 14:03</td>
    -+      </tr>
    -+    </table>
    -+    </div><!-- End and-diff-id -->
    -+  <div class="and-diff-id" style="margin-right:8px;">
    -+    <table class="diffspectable">
    -+      <tr>
    -+        <td class="diffspec" colspan="2"><a href="jdiff_statistics.html">Statistics</a>
    -+      </tr>
    -+    </table>
    -+  </div> <!-- End and-diff-id -->
    -+  </div> <!-- End headerRight -->
    -+  </div> <!-- End header -->
    -+<div id="body-content" xstyle="padding:12px;padding-right:18px;">
    -+<div id="doc-content" style="position:relative;">
    -+<div id="mainBodyFluid">
    -+<H2>
    -+Class android.support.v4.media.<A HREF="../../../../reference/android/support/v4/media/MediaBrowserCompat.MediaItem.html" target="_top"><font size="+2"><code>MediaBrowserCompat.MediaItem</code></font></A>
    -+</H2>
    -+<a NAME="constructors"></a>
    -+<a NAME="methods"></a>
    -+<p>
    -+<a NAME="Added"></a>
    -+<TABLE summary="Added Methods" WIDTH="100%">
    -+<TR>
    -+  <TH VALIGN="TOP" COLSPAN=2>Added Methods</FONT></TD>
    -+</TH>
    -+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    -+  <TD VALIGN="TOP" WIDTH="25%">
    -+  <A NAME="android.support.v4.media.MediaBrowserCompat.MediaItem.fromMediaItem_added(java.lang.Object)"></A>
    -+  <nobr><code>MediaItem</code>&nbsp;<A HREF="../../../../reference/android/support/v4/media/MediaBrowserCompat.MediaItem.html#fromMediaItem(java.lang.Object)" target="_top"><code>fromMediaItem</code></A>(<code>Object</code>)</nobr>
    -+  </TD>
    -+  <TD>&nbsp;</TD>
    -+</TR>
    -+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    -+  <TD VALIGN="TOP" WIDTH="25%">
    -+  <A NAME="android.support.v4.media.MediaBrowserCompat.MediaItem.fromMediaItemList_added(java.util.List<?>)"></A>
    -+  <nobr><code>List&lt;MediaItem&gt;</code>&nbsp;<A HREF="../../../../reference/android/support/v4/media/MediaBrowserCompat.MediaItem.html#fromMediaItemList(java.util.List<?>)" target="_top"><code>fromMediaItemList</code></A>(<code>List&lt;?&gt;</code>)</nobr>
    -+  </TD>
    -+  <TD>&nbsp;</TD>
    -+</TR>
    -+</TABLE>
    -+&nbsp;
    -+<a NAME="fields"></a>
    -+      </div>	
    -+      <div id="footer">
    -+        <div id="copyright">
    -+        Except as noted, this content is licensed under 
    -+        <a href="http://creativecommons.org/licenses/by/2.5/"> Creative Commons Attribution 2.5</a>.
    -+        For details and restrictions, see the <a href="/license.html">Content License</a>.
    -+        </div>
    -+      <div id="footerlinks">
    -+      <p>
    -+        <a href="http://www.android.com/terms.html">Site Terms of Service</a> -
    -+        <a href="http://www.android.com/privacy.html">Privacy Policy</a> -
    -+        <a href="http://www.android.com/branding.html">Brand Guidelines</a>
    -+      </p>
    -+    </div>
    -+    </div> <!-- end footer -->
    -+    </div><!-- end doc-content -->
    -+    </div> <!-- end body-content --> 
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    -+</script>
    -+<script type="text/javascript">
    -+  try {
    -+    var pageTracker = _gat._getTracker("UA-5831155-1");
    -+    pageTracker._setAllowAnchor(true);
    -+    pageTracker._initData();
    -+    pageTracker._trackPageview();
    -+  } catch(e) {}
    -+</script>
    -+</BODY>
    -+</HTML>
    -diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.media.MediaBrowserServiceCompat.BrowserRoot.html b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.media.MediaBrowserServiceCompat.BrowserRoot.html
    -new file mode 100644
    -index 0000000..7ea97f3
    ---- /dev/null
    -+++ b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.media.MediaBrowserServiceCompat.BrowserRoot.html
    -@@ -0,0 +1,122 @@
    -+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
    -+<HTML style="overflow:auto;">
    -+<HEAD>
    -+<meta name="generator" content="JDiff v1.1.0">
    -+<!-- Generated by the JDiff Javadoc doclet -->
    -+<!-- (http://www.jdiff.org) -->
    -+<meta name="description" content="JDiff is a Javadoc doclet which generates an HTML report of all the packages, classes, constructors, methods, and fields which have been removed, added or changed in any way, including their documentation, when two APIs are compared.">
    -+<meta name="keywords" content="diff, jdiff, javadiff, java diff, java difference, API difference, difference between two APIs, API diff, Javadoc, doclet">
    -+<TITLE>
    -+android.support.v4.media.MediaBrowserServiceCompat.BrowserRoot
    -+</TITLE>
    -+<link href="../../../../assets/android-developer-docs.css" rel="stylesheet" type="text/css" />
    -+<link href="../stylesheet-jdiff.css" rel="stylesheet" type="text/css" />
    -+<noscript>
    -+<style type="text/css">
    -+body{overflow:auto;}
    -+#body-content{position:relative; top:0;}
    -+#doc-content{overflow:visible;border-left:3px solid #666;}
    -+#side-nav{padding:0;}
    -+#side-nav .toggle-list ul {display:block;}
    -+#resize-packages-nav{border-bottom:3px solid #666;}
    -+</style>
    -+</noscript>
    -+<style type="text/css">
    -+</style>
    -+</HEAD>
    -+<BODY>
    -+<!-- Start of nav bar -->
    -+<a name="top"></a>
    -+<div id="header" style="margin-bottom:0;padding-bottom:0;">
    -+<div id="headerLeft">
    -+<a href="../../../../index.html" tabindex="-1" target="_top"><img src="../../../../assets/images/bg_logo.png" alt="Android Developers" /></a>
    -+</div>
    -+  <div id="headerRight">
    -+  <div id="headerLinks">
    -+<!-- <img src="/assets/images/icon_world.jpg" alt="" /> -->
    -+<span class="text">
    -+<!-- &nbsp;<a href="#">English</a> | -->
    -+<nobr><a href="http://developer.android.com" target="_top">Android Developers</a> | <a href="http://www.android.com" target="_top">Android.com</a></nobr>
    -+</span>
    -+</div>
    -+  <div class="and-diff-id" style="margin-top:6px;margin-right:8px;">
    -+    <table class="diffspectable">
    -+      <tr>
    -+        <td colspan="2" class="diffspechead">API Diff Specification</td>
    -+      </tr>
    -+      <tr>
    -+        <td class="diffspec" style="padding-top:.25em">To Level:</td>
    -+        <td class="diffvaluenew" style="padding-top:.25em">24.2.0</td>
    -+      </tr>
    -+      <tr>
    -+        <td class="diffspec">From Level:</td>
    -+        <td class="diffvalueold">24.1.0</td>
    -+      </tr>
    -+      <tr>
    -+        <td class="diffspec">Generated</td>
    -+        <td class="diffvalue">2016.08.16 14:03</td>
    -+      </tr>
    -+    </table>
    -+    </div><!-- End and-diff-id -->
    -+  <div class="and-diff-id" style="margin-right:8px;">
    -+    <table class="diffspectable">
    -+      <tr>
    -+        <td class="diffspec" colspan="2"><a href="jdiff_statistics.html">Statistics</a>
    -+      </tr>
    -+    </table>
    -+  </div> <!-- End and-diff-id -->
    -+  </div> <!-- End headerRight -->
    -+  </div> <!-- End header -->
    -+<div id="body-content" xstyle="padding:12px;padding-right:18px;">
    -+<div id="doc-content" style="position:relative;">
    -+<div id="mainBodyFluid">
    -+<H2>
    -+Class android.support.v4.media.<A HREF="../../../../reference/android/support/v4/media/MediaBrowserServiceCompat.BrowserRoot.html" target="_top"><font size="+2"><code>MediaBrowserServiceCompat.BrowserRoot</code></font></A>
    -+</H2>
    -+<a NAME="constructors"></a>
    -+<a NAME="methods"></a>
    -+<a NAME="fields"></a>
    -+<p>
    -+<a NAME="Added"></a>
    -+<TABLE summary="Added Fields" WIDTH="100%">
    -+<TR>
    -+  <TH VALIGN="TOP" COLSPAN=2>Added Fields</FONT></TD>
    -+</TH>
    -+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    -+  <TD VALIGN="TOP" WIDTH="25%">
    -+  <A NAME="android.support.v4.media.MediaBrowserServiceCompat.BrowserRoot.EXTRA_SUGGESTION_KEYWORDS"></A>
    -+  <nobr><code>String</code>&nbsp;<A HREF="../../../../reference/android/support/v4/media/MediaBrowserServiceCompat.BrowserRoot.html#EXTRA_SUGGESTION_KEYWORDS" target="_top"><code>EXTRA_SUGGESTION_KEYWORDS</code></A></nobr>
    -+  </TD>
    -+  <TD>&nbsp;</TD>
    -+</TR>
    -+</TABLE>
    -+&nbsp;
    -+      </div>	
    -+      <div id="footer">
    -+        <div id="copyright">
    -+        Except as noted, this content is licensed under 
    -+        <a href="http://creativecommons.org/licenses/by/2.5/"> Creative Commons Attribution 2.5</a>.
    -+        For details and restrictions, see the <a href="/license.html">Content License</a>.
    -+        </div>
    -+      <div id="footerlinks">
    -+      <p>
    -+        <a href="http://www.android.com/terms.html">Site Terms of Service</a> -
    -+        <a href="http://www.android.com/privacy.html">Privacy Policy</a> -
    -+        <a href="http://www.android.com/branding.html">Brand Guidelines</a>
    -+      </p>
    -+    </div>
    -+    </div> <!-- end footer -->
    -+    </div><!-- end doc-content -->
    -+    </div> <!-- end body-content --> 
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    -+</script>
    -+<script type="text/javascript">
    -+  try {
    -+    var pageTracker = _gat._getTracker("UA-5831155-1");
    -+    pageTracker._setAllowAnchor(true);
    -+    pageTracker._initData();
    -+    pageTracker._trackPageview();
    -+  } catch(e) {}
    -+</script>
    -+</BODY>
    -+</HTML>
    -diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.media.MediaDescriptionCompat.html b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.media.MediaDescriptionCompat.html
    -new file mode 100644
    -index 0000000..fa1d610
    ---- /dev/null
    -+++ b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.media.MediaDescriptionCompat.html
    -@@ -0,0 +1,171 @@
    -+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
    -+<HTML style="overflow:auto;">
    -+<HEAD>
    -+<meta name="generator" content="JDiff v1.1.0">
    -+<!-- Generated by the JDiff Javadoc doclet -->
    -+<!-- (http://www.jdiff.org) -->
    -+<meta name="description" content="JDiff is a Javadoc doclet which generates an HTML report of all the packages, classes, constructors, methods, and fields which have been removed, added or changed in any way, including their documentation, when two APIs are compared.">
    -+<meta name="keywords" content="diff, jdiff, javadiff, java diff, java difference, API difference, difference between two APIs, API diff, Javadoc, doclet">
    -+<TITLE>
    -+android.support.v4.media.MediaDescriptionCompat
    -+</TITLE>
    -+<link href="../../../../assets/android-developer-docs.css" rel="stylesheet" type="text/css" />
    -+<link href="../stylesheet-jdiff.css" rel="stylesheet" type="text/css" />
    -+<noscript>
    -+<style type="text/css">
    -+body{overflow:auto;}
    -+#body-content{position:relative; top:0;}
    -+#doc-content{overflow:visible;border-left:3px solid #666;}
    -+#side-nav{padding:0;}
    -+#side-nav .toggle-list ul {display:block;}
    -+#resize-packages-nav{border-bottom:3px solid #666;}
    -+</style>
    -+</noscript>
    -+<style type="text/css">
    -+</style>
    -+</HEAD>
    -+<BODY>
    -+<!-- Start of nav bar -->
    -+<a name="top"></a>
    -+<div id="header" style="margin-bottom:0;padding-bottom:0;">
    -+<div id="headerLeft">
    -+<a href="../../../../index.html" tabindex="-1" target="_top"><img src="../../../../assets/images/bg_logo.png" alt="Android Developers" /></a>
    -+</div>
    -+  <div id="headerRight">
    -+  <div id="headerLinks">
    -+<!-- <img src="/assets/images/icon_world.jpg" alt="" /> -->
    -+<span class="text">
    -+<!-- &nbsp;<a href="#">English</a> | -->
    -+<nobr><a href="http://developer.android.com" target="_top">Android Developers</a> | <a href="http://www.android.com" target="_top">Android.com</a></nobr>
    -+</span>
    -+</div>
    -+  <div class="and-diff-id" style="margin-top:6px;margin-right:8px;">
    -+    <table class="diffspectable">
    -+      <tr>
    -+        <td colspan="2" class="diffspechead">API Diff Specification</td>
    -+      </tr>
    -+      <tr>
    -+        <td class="diffspec" style="padding-top:.25em">To Level:</td>
    -+        <td class="diffvaluenew" style="padding-top:.25em">24.2.0</td>
    -+      </tr>
    -+      <tr>
    -+        <td class="diffspec">From Level:</td>
    -+        <td class="diffvalueold">24.1.0</td>
    -+      </tr>
    -+      <tr>
    -+        <td class="diffspec">Generated</td>
    -+        <td class="diffvalue">2016.08.16 14:03</td>
    -+      </tr>
    -+    </table>
    -+    </div><!-- End and-diff-id -->
    -+  <div class="and-diff-id" style="margin-right:8px;">
    -+    <table class="diffspectable">
    -+      <tr>
    -+        <td class="diffspec" colspan="2"><a href="jdiff_statistics.html">Statistics</a>
    -+      </tr>
    -+    </table>
    -+  </div> <!-- End and-diff-id -->
    -+  </div> <!-- End headerRight -->
    -+  </div> <!-- End header -->
    -+<div id="body-content" xstyle="padding:12px;padding-right:18px;">
    -+<div id="doc-content" style="position:relative;">
    -+<div id="mainBodyFluid">
    -+<H2>
    -+Class android.support.v4.media.<A HREF="../../../../reference/android/support/v4/media/MediaDescriptionCompat.html" target="_top"><font size="+2"><code>MediaDescriptionCompat</code></font></A>
    -+</H2>
    -+<a NAME="constructors"></a>
    -+<a NAME="methods"></a>
    -+<a NAME="fields"></a>
    -+<p>
    -+<a NAME="Added"></a>
    -+<TABLE summary="Added Fields" WIDTH="100%">
    -+<TR>
    -+  <TH VALIGN="TOP" COLSPAN=2>Added Fields</FONT></TD>
    -+</TH>
    -+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    -+  <TD VALIGN="TOP" WIDTH="25%">
    -+  <A NAME="android.support.v4.media.MediaDescriptionCompat.BT_FOLDER_TYPE_ALBUMS"></A>
    -+  <nobr><code>long</code>&nbsp;<A HREF="../../../../reference/android/support/v4/media/MediaDescriptionCompat.html#BT_FOLDER_TYPE_ALBUMS" target="_top"><code>BT_FOLDER_TYPE_ALBUMS</code></A></nobr>
    -+  </TD>
    -+  <TD>&nbsp;</TD>
    -+</TR>
    -+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    -+  <TD VALIGN="TOP" WIDTH="25%">
    -+  <A NAME="android.support.v4.media.MediaDescriptionCompat.BT_FOLDER_TYPE_ARTISTS"></A>
    -+  <nobr><code>long</code>&nbsp;<A HREF="../../../../reference/android/support/v4/media/MediaDescriptionCompat.html#BT_FOLDER_TYPE_ARTISTS" target="_top"><code>BT_FOLDER_TYPE_ARTISTS</code></A></nobr>
    -+  </TD>
    -+  <TD>&nbsp;</TD>
    -+</TR>
    -+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    -+  <TD VALIGN="TOP" WIDTH="25%">
    -+  <A NAME="android.support.v4.media.MediaDescriptionCompat.BT_FOLDER_TYPE_GENRES"></A>
    -+  <nobr><code>long</code>&nbsp;<A HREF="../../../../reference/android/support/v4/media/MediaDescriptionCompat.html#BT_FOLDER_TYPE_GENRES" target="_top"><code>BT_FOLDER_TYPE_GENRES</code></A></nobr>
    -+  </TD>
    -+  <TD>&nbsp;</TD>
    -+</TR>
    -+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    -+  <TD VALIGN="TOP" WIDTH="25%">
    -+  <A NAME="android.support.v4.media.MediaDescriptionCompat.BT_FOLDER_TYPE_MIXED"></A>
    -+  <nobr><code>long</code>&nbsp;<A HREF="../../../../reference/android/support/v4/media/MediaDescriptionCompat.html#BT_FOLDER_TYPE_MIXED" target="_top"><code>BT_FOLDER_TYPE_MIXED</code></A></nobr>
    -+  </TD>
    -+  <TD>&nbsp;</TD>
    -+</TR>
    -+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    -+  <TD VALIGN="TOP" WIDTH="25%">
    -+  <A NAME="android.support.v4.media.MediaDescriptionCompat.BT_FOLDER_TYPE_PLAYLISTS"></A>
    -+  <nobr><code>long</code>&nbsp;<A HREF="../../../../reference/android/support/v4/media/MediaDescriptionCompat.html#BT_FOLDER_TYPE_PLAYLISTS" target="_top"><code>BT_FOLDER_TYPE_PLAYLISTS</code></A></nobr>
    -+  </TD>
    -+  <TD>&nbsp;</TD>
    -+</TR>
    -+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    -+  <TD VALIGN="TOP" WIDTH="25%">
    -+  <A NAME="android.support.v4.media.MediaDescriptionCompat.BT_FOLDER_TYPE_TITLES"></A>
    -+  <nobr><code>long</code>&nbsp;<A HREF="../../../../reference/android/support/v4/media/MediaDescriptionCompat.html#BT_FOLDER_TYPE_TITLES" target="_top"><code>BT_FOLDER_TYPE_TITLES</code></A></nobr>
    -+  </TD>
    -+  <TD>&nbsp;</TD>
    -+</TR>
    -+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    -+  <TD VALIGN="TOP" WIDTH="25%">
    -+  <A NAME="android.support.v4.media.MediaDescriptionCompat.BT_FOLDER_TYPE_YEARS"></A>
    -+  <nobr><code>long</code>&nbsp;<A HREF="../../../../reference/android/support/v4/media/MediaDescriptionCompat.html#BT_FOLDER_TYPE_YEARS" target="_top"><code>BT_FOLDER_TYPE_YEARS</code></A></nobr>
    -+  </TD>
    -+  <TD>&nbsp;</TD>
    -+</TR>
    -+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    -+  <TD VALIGN="TOP" WIDTH="25%">
    -+  <A NAME="android.support.v4.media.MediaDescriptionCompat.EXTRA_BT_FOLDER_TYPE"></A>
    -+  <nobr><code>String</code>&nbsp;<A HREF="../../../../reference/android/support/v4/media/MediaDescriptionCompat.html#EXTRA_BT_FOLDER_TYPE" target="_top"><code>EXTRA_BT_FOLDER_TYPE</code></A></nobr>
    -+  </TD>
    -+  <TD>&nbsp;</TD>
    -+</TR>
    -+</TABLE>
    -+&nbsp;
    -+      </div>	
    -+      <div id="footer">
    -+        <div id="copyright">
    -+        Except as noted, this content is licensed under 
    -+        <a href="http://creativecommons.org/licenses/by/2.5/"> Creative Commons Attribution 2.5</a>.
    -+        For details and restrictions, see the <a href="/license.html">Content License</a>.
    -+        </div>
    -+      <div id="footerlinks">
    -+      <p>
    -+        <a href="http://www.android.com/terms.html">Site Terms of Service</a> -
    -+        <a href="http://www.android.com/privacy.html">Privacy Policy</a> -
    -+        <a href="http://www.android.com/branding.html">Brand Guidelines</a>
    -+      </p>
    -+    </div>
    -+    </div> <!-- end footer -->
    -+    </div><!-- end doc-content -->
    -+    </div> <!-- end body-content --> 
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    -+</script>
    -+<script type="text/javascript">
    -+  try {
    -+    var pageTracker = _gat._getTracker("UA-5831155-1");
    -+    pageTracker._setAllowAnchor(true);
    -+    pageTracker._initData();
    -+    pageTracker._trackPageview();
    -+  } catch(e) {}
    -+</script>
    -+</BODY>
    -+</HTML>
    -diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.media.MediaMetadataCompat.html b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.media.MediaMetadataCompat.html
    -new file mode 100644
    -index 0000000..7e0f137
    ---- /dev/null
    -+++ b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.media.MediaMetadataCompat.html
    -@@ -0,0 +1,129 @@
    -+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
    -+<HTML style="overflow:auto;">
    -+<HEAD>
    -+<meta name="generator" content="JDiff v1.1.0">
    -+<!-- Generated by the JDiff Javadoc doclet -->
    -+<!-- (http://www.jdiff.org) -->
    -+<meta name="description" content="JDiff is a Javadoc doclet which generates an HTML report of all the packages, classes, constructors, methods, and fields which have been removed, added or changed in any way, including their documentation, when two APIs are compared.">
    -+<meta name="keywords" content="diff, jdiff, javadiff, java diff, java difference, API difference, difference between two APIs, API diff, Javadoc, doclet">
    -+<TITLE>
    -+android.support.v4.media.MediaMetadataCompat
    -+</TITLE>
    -+<link href="../../../../assets/android-developer-docs.css" rel="stylesheet" type="text/css" />
    -+<link href="../stylesheet-jdiff.css" rel="stylesheet" type="text/css" />
    -+<noscript>
    -+<style type="text/css">
    -+body{overflow:auto;}
    -+#body-content{position:relative; top:0;}
    -+#doc-content{overflow:visible;border-left:3px solid #666;}
    -+#side-nav{padding:0;}
    -+#side-nav .toggle-list ul {display:block;}
    -+#resize-packages-nav{border-bottom:3px solid #666;}
    -+</style>
    -+</noscript>
    -+<style type="text/css">
    -+</style>
    -+</HEAD>
    -+<BODY>
    -+<!-- Start of nav bar -->
    -+<a name="top"></a>
    -+<div id="header" style="margin-bottom:0;padding-bottom:0;">
    -+<div id="headerLeft">
    -+<a href="../../../../index.html" tabindex="-1" target="_top"><img src="../../../../assets/images/bg_logo.png" alt="Android Developers" /></a>
    -+</div>
    -+  <div id="headerRight">
    -+  <div id="headerLinks">
    -+<!-- <img src="/assets/images/icon_world.jpg" alt="" /> -->
    -+<span class="text">
    -+<!-- &nbsp;<a href="#">English</a> | -->
    -+<nobr><a href="http://developer.android.com" target="_top">Android Developers</a> | <a href="http://www.android.com" target="_top">Android.com</a></nobr>
    -+</span>
    -+</div>
    -+  <div class="and-diff-id" style="margin-top:6px;margin-right:8px;">
    -+    <table class="diffspectable">
    -+      <tr>
    -+        <td colspan="2" class="diffspechead">API Diff Specification</td>
    -+      </tr>
    -+      <tr>
    -+        <td class="diffspec" style="padding-top:.25em">To Level:</td>
    -+        <td class="diffvaluenew" style="padding-top:.25em">24.2.0</td>
    -+      </tr>
    -+      <tr>
    -+        <td class="diffspec">From Level:</td>
    -+        <td class="diffvalueold">24.1.0</td>
    -+      </tr>
    -+      <tr>
    -+        <td class="diffspec">Generated</td>
    -+        <td class="diffvalue">2016.08.16 14:03</td>
    -+      </tr>
    -+    </table>
    -+    </div><!-- End and-diff-id -->
    -+  <div class="and-diff-id" style="margin-right:8px;">
    -+    <table class="diffspectable">
    -+      <tr>
    -+        <td class="diffspec" colspan="2"><a href="jdiff_statistics.html">Statistics</a>
    -+      </tr>
    -+    </table>
    -+  </div> <!-- End and-diff-id -->
    -+  </div> <!-- End headerRight -->
    -+  </div> <!-- End header -->
    -+<div id="body-content" xstyle="padding:12px;padding-right:18px;">
    -+<div id="doc-content" style="position:relative;">
    -+<div id="mainBodyFluid">
    -+<H2>
    -+Class android.support.v4.media.<A HREF="../../../../reference/android/support/v4/media/MediaMetadataCompat.html" target="_top"><font size="+2"><code>MediaMetadataCompat</code></font></A>
    -+</H2>
    -+<a NAME="constructors"></a>
    -+<a NAME="methods"></a>
    -+<a NAME="fields"></a>
    -+<p>
    -+<a NAME="Added"></a>
    -+<TABLE summary="Added Fields" WIDTH="100%">
    -+<TR>
    -+  <TH VALIGN="TOP" COLSPAN=2>Added Fields</FONT></TD>
    -+</TH>
    -+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    -+  <TD VALIGN="TOP" WIDTH="25%">
    -+  <A NAME="android.support.v4.media.MediaMetadataCompat.METADATA_KEY_BT_FOLDER_TYPE"></A>
    -+  <nobr><code>String</code>&nbsp;<A HREF="../../../../reference/android/support/v4/media/MediaMetadataCompat.html#METADATA_KEY_BT_FOLDER_TYPE" target="_top"><code>METADATA_KEY_BT_FOLDER_TYPE</code></A></nobr>
    -+  </TD>
    -+  <TD>&nbsp;</TD>
    -+</TR>
    -+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    -+  <TD VALIGN="TOP" WIDTH="25%">
    -+  <A NAME="android.support.v4.media.MediaMetadataCompat.METADATA_KEY_MEDIA_URI"></A>
    -+  <nobr><code>String</code>&nbsp;<A HREF="../../../../reference/android/support/v4/media/MediaMetadataCompat.html#METADATA_KEY_MEDIA_URI" target="_top"><code>METADATA_KEY_MEDIA_URI</code></A></nobr>
    -+  </TD>
    -+  <TD>&nbsp;</TD>
    -+</TR>
    -+</TABLE>
    -+&nbsp;
    -+      </div>	
    -+      <div id="footer">
    -+        <div id="copyright">
    -+        Except as noted, this content is licensed under 
    -+        <a href="http://creativecommons.org/licenses/by/2.5/"> Creative Commons Attribution 2.5</a>.
    -+        For details and restrictions, see the <a href="/license.html">Content License</a>.
    -+        </div>
    -+      <div id="footerlinks">
    -+      <p>
    -+        <a href="http://www.android.com/terms.html">Site Terms of Service</a> -
    -+        <a href="http://www.android.com/privacy.html">Privacy Policy</a> -
    -+        <a href="http://www.android.com/branding.html">Brand Guidelines</a>
    -+      </p>
    -+    </div>
    -+    </div> <!-- end footer -->
    -+    </div><!-- end doc-content -->
    -+    </div> <!-- end body-content --> 
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    -+</script>
    -+<script type="text/javascript">
    -+  try {
    -+    var pageTracker = _gat._getTracker("UA-5831155-1");
    -+    pageTracker._setAllowAnchor(true);
    -+    pageTracker._initData();
    -+    pageTracker._trackPageview();
    -+  } catch(e) {}
    -+</script>
    -+</BODY>
    -+</HTML>
    -diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.media.session.MediaButtonReceiver.html b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.media.session.MediaButtonReceiver.html
    -new file mode 100644
    -index 0000000..65467b8
    ---- /dev/null
    -+++ b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.media.session.MediaButtonReceiver.html
    -@@ -0,0 +1,129 @@
    -+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
    -+<HTML style="overflow:auto;">
    -+<HEAD>
    -+<meta name="generator" content="JDiff v1.1.0">
    -+<!-- Generated by the JDiff Javadoc doclet -->
    -+<!-- (http://www.jdiff.org) -->
    -+<meta name="description" content="JDiff is a Javadoc doclet which generates an HTML report of all the packages, classes, constructors, methods, and fields which have been removed, added or changed in any way, including their documentation, when two APIs are compared.">
    -+<meta name="keywords" content="diff, jdiff, javadiff, java diff, java difference, API difference, difference between two APIs, API diff, Javadoc, doclet">
    -+<TITLE>
    -+android.support.v4.media.session.MediaButtonReceiver
    -+</TITLE>
    -+<link href="../../../../assets/android-developer-docs.css" rel="stylesheet" type="text/css" />
    -+<link href="../stylesheet-jdiff.css" rel="stylesheet" type="text/css" />
    -+<noscript>
    -+<style type="text/css">
    -+body{overflow:auto;}
    -+#body-content{position:relative; top:0;}
    -+#doc-content{overflow:visible;border-left:3px solid #666;}
    -+#side-nav{padding:0;}
    -+#side-nav .toggle-list ul {display:block;}
    -+#resize-packages-nav{border-bottom:3px solid #666;}
    -+</style>
    -+</noscript>
    -+<style type="text/css">
    -+</style>
    -+</HEAD>
    -+<BODY>
    -+<!-- Start of nav bar -->
    -+<a name="top"></a>
    -+<div id="header" style="margin-bottom:0;padding-bottom:0;">
    -+<div id="headerLeft">
    -+<a href="../../../../index.html" tabindex="-1" target="_top"><img src="../../../../assets/images/bg_logo.png" alt="Android Developers" /></a>
    -+</div>
    -+  <div id="headerRight">
    -+  <div id="headerLinks">
    -+<!-- <img src="/assets/images/icon_world.jpg" alt="" /> -->
    -+<span class="text">
    -+<!-- &nbsp;<a href="#">English</a> | -->
    -+<nobr><a href="http://developer.android.com" target="_top">Android Developers</a> | <a href="http://www.android.com" target="_top">Android.com</a></nobr>
    -+</span>
    -+</div>
    -+  <div class="and-diff-id" style="margin-top:6px;margin-right:8px;">
    -+    <table class="diffspectable">
    -+      <tr>
    -+        <td colspan="2" class="diffspechead">API Diff Specification</td>
    -+      </tr>
    -+      <tr>
    -+        <td class="diffspec" style="padding-top:.25em">To Level:</td>
    -+        <td class="diffvaluenew" style="padding-top:.25em">24.2.0</td>
    -+      </tr>
    -+      <tr>
    -+        <td class="diffspec">From Level:</td>
    -+        <td class="diffvalueold">24.1.0</td>
    -+      </tr>
    -+      <tr>
    -+        <td class="diffspec">Generated</td>
    -+        <td class="diffvalue">2016.08.16 14:03</td>
    -+      </tr>
    -+    </table>
    -+    </div><!-- End and-diff-id -->
    -+  <div class="and-diff-id" style="margin-right:8px;">
    -+    <table class="diffspectable">
    -+      <tr>
    -+        <td class="diffspec" colspan="2"><a href="jdiff_statistics.html">Statistics</a>
    -+      </tr>
    -+    </table>
    -+  </div> <!-- End and-diff-id -->
    -+  </div> <!-- End headerRight -->
    -+  </div> <!-- End header -->
    -+<div id="body-content" xstyle="padding:12px;padding-right:18px;">
    -+<div id="doc-content" style="position:relative;">
    -+<div id="mainBodyFluid">
    -+<H2>
    -+Class android.support.v4.media.session.<A HREF="../../../../reference/android/support/v4/media/session/MediaButtonReceiver.html" target="_top"><font size="+2"><code>MediaButtonReceiver</code></font></A>
    -+</H2>
    -+<a NAME="constructors"></a>
    -+<a NAME="methods"></a>
    -+<p>
    -+<a NAME="Added"></a>
    -+<TABLE summary="Added Methods" WIDTH="100%">
    -+<TR>
    -+  <TH VALIGN="TOP" COLSPAN=2>Added Methods</FONT></TD>
    -+</TH>
    -+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    -+  <TD VALIGN="TOP" WIDTH="25%">
    -+  <A NAME="android.support.v4.media.session.MediaButtonReceiver.buildMediaButtonPendingIntent_added(android.content.Context, android.content.ComponentName, long)"></A>
    -+  <nobr><code>PendingIntent</code>&nbsp;<A HREF="../../../../reference/android/support/v4/media/session/MediaButtonReceiver.html#buildMediaButtonPendingIntent(android.content.Context, android.content.ComponentName, long)" target="_top"><code>buildMediaButtonPendingIntent</code></A>(<code>Context,</nobr> ComponentName<nobr>,</nobr> long<nobr><nobr></code>)</nobr>
    -+  </TD>
    -+  <TD>&nbsp;</TD>
    -+</TR>
    -+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    -+  <TD VALIGN="TOP" WIDTH="25%">
    -+  <A NAME="android.support.v4.media.session.MediaButtonReceiver.buildMediaButtonPendingIntent_added(android.content.Context, long)"></A>
    -+  <nobr><code>PendingIntent</code>&nbsp;<A HREF="../../../../reference/android/support/v4/media/session/MediaButtonReceiver.html#buildMediaButtonPendingIntent(android.content.Context, long)" target="_top"><code>buildMediaButtonPendingIntent</code></A>(<code>Context,</nobr> long<nobr><nobr></code>)</nobr>
    -+  </TD>
    -+  <TD>&nbsp;</TD>
    -+</TR>
    -+</TABLE>
    -+&nbsp;
    -+<a NAME="fields"></a>
    -+      </div>	
    -+      <div id="footer">
    -+        <div id="copyright">
    -+        Except as noted, this content is licensed under 
    -+        <a href="http://creativecommons.org/licenses/by/2.5/"> Creative Commons Attribution 2.5</a>.
    -+        For details and restrictions, see the <a href="/license.html">Content License</a>.
    -+        </div>
    -+      <div id="footerlinks">
    -+      <p>
    -+        <a href="http://www.android.com/terms.html">Site Terms of Service</a> -
    -+        <a href="http://www.android.com/privacy.html">Privacy Policy</a> -
    -+        <a href="http://www.android.com/branding.html">Brand Guidelines</a>
    -+      </p>
    -+    </div>
    -+    </div> <!-- end footer -->
    -+    </div><!-- end doc-content -->
    -+    </div> <!-- end body-content --> 
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    -+</script>
    -+<script type="text/javascript">
    -+  try {
    -+    var pageTracker = _gat._getTracker("UA-5831155-1");
    -+    pageTracker._setAllowAnchor(true);
    -+    pageTracker._initData();
    -+    pageTracker._trackPageview();
    -+  } catch(e) {}
    -+</script>
    -+</BODY>
    -+</HTML>
    -diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.media.session.MediaSessionCompat.QueueItem.html b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.media.session.MediaSessionCompat.QueueItem.html
    -new file mode 100644
    -index 0000000..e3b0184
    ---- /dev/null
    -+++ b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.media.session.MediaSessionCompat.QueueItem.html
    -@@ -0,0 +1,147 @@
    -+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
    -+<HTML style="overflow:auto;">
    -+<HEAD>
    -+<meta name="generator" content="JDiff v1.1.0">
    -+<!-- Generated by the JDiff Javadoc doclet -->
    -+<!-- (http://www.jdiff.org) -->
    -+<meta name="description" content="JDiff is a Javadoc doclet which generates an HTML report of all the packages, classes, constructors, methods, and fields which have been removed, added or changed in any way, including their documentation, when two APIs are compared.">
    -+<meta name="keywords" content="diff, jdiff, javadiff, java diff, java difference, API difference, difference between two APIs, API diff, Javadoc, doclet">
    -+<TITLE>
    -+android.support.v4.media.session.MediaSessionCompat.QueueItem
    -+</TITLE>
    -+<link href="../../../../assets/android-developer-docs.css" rel="stylesheet" type="text/css" />
    -+<link href="../stylesheet-jdiff.css" rel="stylesheet" type="text/css" />
    -+<noscript>
    -+<style type="text/css">
    -+body{overflow:auto;}
    -+#body-content{position:relative; top:0;}
    -+#doc-content{overflow:visible;border-left:3px solid #666;}
    -+#side-nav{padding:0;}
    -+#side-nav .toggle-list ul {display:block;}
    -+#resize-packages-nav{border-bottom:3px solid #666;}
    -+</style>
    -+</noscript>
    -+<style type="text/css">
    -+</style>
    -+</HEAD>
    -+<BODY>
    -+<!-- Start of nav bar -->
    -+<a name="top"></a>
    -+<div id="header" style="margin-bottom:0;padding-bottom:0;">
    -+<div id="headerLeft">
    -+<a href="../../../../index.html" tabindex="-1" target="_top"><img src="../../../../assets/images/bg_logo.png" alt="Android Developers" /></a>
    -+</div>
    -+  <div id="headerRight">
    -+  <div id="headerLinks">
    -+<!-- <img src="/assets/images/icon_world.jpg" alt="" /> -->
    -+<span class="text">
    -+<!-- &nbsp;<a href="#">English</a> | -->
    -+<nobr><a href="http://developer.android.com" target="_top">Android Developers</a> | <a href="http://www.android.com" target="_top">Android.com</a></nobr>
    -+</span>
    -+</div>
    -+  <div class="and-diff-id" style="margin-top:6px;margin-right:8px;">
    -+    <table class="diffspectable">
    -+      <tr>
    -+        <td colspan="2" class="diffspechead">API Diff Specification</td>
    -+      </tr>
    -+      <tr>
    -+        <td class="diffspec" style="padding-top:.25em">To Level:</td>
    -+        <td class="diffvaluenew" style="padding-top:.25em">24.2.0</td>
    -+      </tr>
    -+      <tr>
    -+        <td class="diffspec">From Level:</td>
    -+        <td class="diffvalueold">24.1.0</td>
    -+      </tr>
    -+      <tr>
    -+        <td class="diffspec">Generated</td>
    -+        <td class="diffvalue">2016.08.16 14:03</td>
    -+      </tr>
    -+    </table>
    -+    </div><!-- End and-diff-id -->
    -+  <div class="and-diff-id" style="margin-right:8px;">
    -+    <table class="diffspectable">
    -+      <tr>
    -+        <td class="diffspec" colspan="2"><a href="jdiff_statistics.html">Statistics</a>
    -+      </tr>
    -+    </table>
    -+  </div> <!-- End and-diff-id -->
    -+  </div> <!-- End headerRight -->
    -+  </div> <!-- End header -->
    -+<div id="body-content" xstyle="padding:12px;padding-right:18px;">
    -+<div id="doc-content" style="position:relative;">
    -+<div id="mainBodyFluid">
    -+<H2>
    -+Class android.support.v4.media.session.<A HREF="../../../../reference/android/support/v4/media/session/MediaSessionCompat.QueueItem.html" target="_top"><font size="+2"><code>MediaSessionCompat.QueueItem</code></font></A>
    -+</H2>
    -+<a NAME="constructors"></a>
    -+<a NAME="methods"></a>
    -+<p>
    -+<a NAME="Added"></a>
    -+<TABLE summary="Added Methods" WIDTH="100%">
    -+<TR>
    -+  <TH VALIGN="TOP" COLSPAN=2>Added Methods</FONT></TD>
    -+</TH>
    -+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    -+  <TD VALIGN="TOP" WIDTH="25%">
    -+  <A NAME="android.support.v4.media.session.MediaSessionCompat.QueueItem.fromQueueItem_added(java.lang.Object)"></A>
    -+  <nobr><code>QueueItem</code>&nbsp;<A HREF="../../../../reference/android/support/v4/media/session/MediaSessionCompat.QueueItem.html#fromQueueItem(java.lang.Object)" target="_top"><code>fromQueueItem</code></A>(<code>Object</code>)</nobr>
    -+  </TD>
    -+  <TD>&nbsp;</TD>
    -+</TR>
    -+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    -+  <TD VALIGN="TOP" WIDTH="25%">
    -+  <A NAME="android.support.v4.media.session.MediaSessionCompat.QueueItem.fromQueueItemList_added(java.util.List<?>)"></A>
    -+  <nobr><code>List&lt;QueueItem&gt;</code>&nbsp;<A HREF="../../../../reference/android/support/v4/media/session/MediaSessionCompat.QueueItem.html#fromQueueItemList(java.util.List<?>)" target="_top"><code>fromQueueItemList</code></A>(<code>List&lt;?&gt;</code>)</nobr>
    -+  </TD>
    -+  <TD>&nbsp;</TD>
    -+</TR>
    -+</TABLE>
    -+&nbsp;
    -+<p>
    -+<a NAME="Changed"></a>
    -+<TABLE summary="Changed Methods" WIDTH="100%">
    -+<TR>
    -+  <TH VALIGN="TOP" COLSPAN=3>Changed Methods</FONT></TD>
    -+</TH>
    -+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    -+  <TD VALIGN="TOP" WIDTH="25%">
    -+  <A NAME="android.support.v4.media.session.MediaSessionCompat.QueueItem.obtain_changed(java.lang.Object)"></A>
    -+  <nobr><code>QueueItem</code>&nbsp;<A HREF="../../../../reference/android/support/v4/media/session/MediaSessionCompat.QueueItem.html#obtain(java.lang.Object)" target="_top"><code>obtain</code></A>(<code>Object</code>)  </nobr>
    -+  </TD>
    -+  <TD VALIGN="TOP" WIDTH="30%">
    -+<b>Now deprecated</b>.<br>
    -+  </TD>
    -+  <TD>&nbsp;</TD>
    -+</TR>
    -+</TABLE>
    -+&nbsp;
    -+<a NAME="fields"></a>
    -+      </div>	
    -+      <div id="footer">
    -+        <div id="copyright">
    -+        Except as noted, this content is licensed under 
    -+        <a href="http://creativecommons.org/licenses/by/2.5/"> Creative Commons Attribution 2.5</a>.
    -+        For details and restrictions, see the <a href="/license.html">Content License</a>.
    -+        </div>
    -+      <div id="footerlinks">
    -+      <p>
    -+        <a href="http://www.android.com/terms.html">Site Terms of Service</a> -
    -+        <a href="http://www.android.com/privacy.html">Privacy Policy</a> -
    -+        <a href="http://www.android.com/branding.html">Brand Guidelines</a>
    -+      </p>
    -+    </div>
    -+    </div> <!-- end footer -->
    -+    </div><!-- end doc-content -->
    -+    </div> <!-- end body-content --> 
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    -+</script>
    -+<script type="text/javascript">
    -+  try {
    -+    var pageTracker = _gat._getTracker("UA-5831155-1");
    -+    pageTracker._setAllowAnchor(true);
    -+    pageTracker._initData();
    -+    pageTracker._trackPageview();
    -+  } catch(e) {}
    -+</script>
    -+</BODY>
    -+</HTML>
    -diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.media.session.MediaSessionCompat.html b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.media.session.MediaSessionCompat.html
    -new file mode 100644
    -index 0000000..90bd5eb
    ---- /dev/null
    -+++ b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.media.session.MediaSessionCompat.html
    -@@ -0,0 +1,140 @@
    -+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
    -+<HTML style="overflow:auto;">
    -+<HEAD>
    -+<meta name="generator" content="JDiff v1.1.0">
    -+<!-- Generated by the JDiff Javadoc doclet -->
    -+<!-- (http://www.jdiff.org) -->
    -+<meta name="description" content="JDiff is a Javadoc doclet which generates an HTML report of all the packages, classes, constructors, methods, and fields which have been removed, added or changed in any way, including their documentation, when two APIs are compared.">
    -+<meta name="keywords" content="diff, jdiff, javadiff, java diff, java difference, API difference, difference between two APIs, API diff, Javadoc, doclet">
    -+<TITLE>
    -+android.support.v4.media.session.MediaSessionCompat
    -+</TITLE>
    -+<link href="../../../../assets/android-developer-docs.css" rel="stylesheet" type="text/css" />
    -+<link href="../stylesheet-jdiff.css" rel="stylesheet" type="text/css" />
    -+<noscript>
    -+<style type="text/css">
    -+body{overflow:auto;}
    -+#body-content{position:relative; top:0;}
    -+#doc-content{overflow:visible;border-left:3px solid #666;}
    -+#side-nav{padding:0;}
    -+#side-nav .toggle-list ul {display:block;}
    -+#resize-packages-nav{border-bottom:3px solid #666;}
    -+</style>
    -+</noscript>
    -+<style type="text/css">
    -+</style>
    -+</HEAD>
    -+<BODY>
    -+<!-- Start of nav bar -->
    -+<a name="top"></a>
    -+<div id="header" style="margin-bottom:0;padding-bottom:0;">
    -+<div id="headerLeft">
    -+<a href="../../../../index.html" tabindex="-1" target="_top"><img src="../../../../assets/images/bg_logo.png" alt="Android Developers" /></a>
    -+</div>
    -+  <div id="headerRight">
    -+  <div id="headerLinks">
    -+<!-- <img src="/assets/images/icon_world.jpg" alt="" /> -->
    -+<span class="text">
    -+<!-- &nbsp;<a href="#">English</a> | -->
    -+<nobr><a href="http://developer.android.com" target="_top">Android Developers</a> | <a href="http://www.android.com" target="_top">Android.com</a></nobr>
    -+</span>
    -+</div>
    -+  <div class="and-diff-id" style="margin-top:6px;margin-right:8px;">
    -+    <table class="diffspectable">
    -+      <tr>
    -+        <td colspan="2" class="diffspechead">API Diff Specification</td>
    -+      </tr>
    -+      <tr>
    -+        <td class="diffspec" style="padding-top:.25em">To Level:</td>
    -+        <td class="diffvaluenew" style="padding-top:.25em">24.2.0</td>
    -+      </tr>
    -+      <tr>
    -+        <td class="diffspec">From Level:</td>
    -+        <td class="diffvalueold">24.1.0</td>
    -+      </tr>
    -+      <tr>
    -+        <td class="diffspec">Generated</td>
    -+        <td class="diffvalue">2016.08.16 14:03</td>
    -+      </tr>
    -+    </table>
    -+    </div><!-- End and-diff-id -->
    -+  <div class="and-diff-id" style="margin-right:8px;">
    -+    <table class="diffspectable">
    -+      <tr>
    -+        <td class="diffspec" colspan="2"><a href="jdiff_statistics.html">Statistics</a>
    -+      </tr>
    -+    </table>
    -+  </div> <!-- End and-diff-id -->
    -+  </div> <!-- End headerRight -->
    -+  </div> <!-- End header -->
    -+<div id="body-content" xstyle="padding:12px;padding-right:18px;">
    -+<div id="doc-content" style="position:relative;">
    -+<div id="mainBodyFluid">
    -+<H2>
    -+Class android.support.v4.media.session.<A HREF="../../../../reference/android/support/v4/media/session/MediaSessionCompat.html" target="_top"><font size="+2"><code>MediaSessionCompat</code></font></A>
    -+</H2>
    -+<a NAME="constructors"></a>
    -+<a NAME="methods"></a>
    -+<p>
    -+<a NAME="Added"></a>
    -+<TABLE summary="Added Methods" WIDTH="100%">
    -+<TR>
    -+  <TH VALIGN="TOP" COLSPAN=2>Added Methods</FONT></TD>
    -+</TH>
    -+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    -+  <TD VALIGN="TOP" WIDTH="25%">
    -+  <A NAME="android.support.v4.media.session.MediaSessionCompat.fromMediaSession_added(android.content.Context, java.lang.Object)"></A>
    -+  <nobr><code>MediaSessionCompat</code>&nbsp;<A HREF="../../../../reference/android/support/v4/media/session/MediaSessionCompat.html#fromMediaSession(android.content.Context, java.lang.Object)" target="_top"><code>fromMediaSession</code></A>(<code>Context,</nobr> Object<nobr><nobr></code>)</nobr>
    -+  </TD>
    -+  <TD>&nbsp;</TD>
    -+</TR>
    -+</TABLE>
    -+&nbsp;
    -+<p>
    -+<a NAME="Changed"></a>
    -+<TABLE summary="Changed Methods" WIDTH="100%">
    -+<TR>
    -+  <TH VALIGN="TOP" COLSPAN=3>Changed Methods</FONT></TD>
    -+</TH>
    -+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    -+  <TD VALIGN="TOP" WIDTH="25%">
    -+  <A NAME="android.support.v4.media.session.MediaSessionCompat.obtain_changed(android.content.Context, java.lang.Object)"></A>
    -+  <nobr><code>MediaSessionCompat</code>&nbsp;<A HREF="../../../../reference/android/support/v4/media/session/MediaSessionCompat.html#obtain(android.content.Context, java.lang.Object)" target="_top"><code>obtain</code></A>(<code>Context,</nobr> Object<nobr><nobr></code>)  </nobr>
    -+  </TD>
    -+  <TD VALIGN="TOP" WIDTH="30%">
    -+<b>Now deprecated</b>.<br>
    -+  </TD>
    -+  <TD>&nbsp;</TD>
    -+</TR>
    -+</TABLE>
    -+&nbsp;
    -+<a NAME="fields"></a>
    -+      </div>	
    -+      <div id="footer">
    -+        <div id="copyright">
    -+        Except as noted, this content is licensed under 
    -+        <a href="http://creativecommons.org/licenses/by/2.5/"> Creative Commons Attribution 2.5</a>.
    -+        For details and restrictions, see the <a href="/license.html">Content License</a>.
    -+        </div>
    -+      <div id="footerlinks">
    -+      <p>
    -+        <a href="http://www.android.com/terms.html">Site Terms of Service</a> -
    -+        <a href="http://www.android.com/privacy.html">Privacy Policy</a> -
    -+        <a href="http://www.android.com/branding.html">Brand Guidelines</a>
    -+      </p>
    -+    </div>
    -+    </div> <!-- end footer -->
    -+    </div><!-- end doc-content -->
    -+    </div> <!-- end body-content --> 
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    -+</script>
    -+<script type="text/javascript">
    -+  try {
    -+    var pageTracker = _gat._getTracker("UA-5831155-1");
    -+    pageTracker._setAllowAnchor(true);
    -+    pageTracker._initData();
    -+    pageTracker._trackPageview();
    -+  } catch(e) {}
    -+</script>
    -+</BODY>
    -+</HTML>
    -diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.media.session.PlaybackStateCompat.html b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.media.session.PlaybackStateCompat.html
    -new file mode 100644
    -index 0000000..07e2449
    ---- /dev/null
    -+++ b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.media.session.PlaybackStateCompat.html
    -@@ -0,0 +1,122 @@
    -+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
    -+<HTML style="overflow:auto;">
    -+<HEAD>
    -+<meta name="generator" content="JDiff v1.1.0">
    -+<!-- Generated by the JDiff Javadoc doclet -->
    -+<!-- (http://www.jdiff.org) -->
    -+<meta name="description" content="JDiff is a Javadoc doclet which generates an HTML report of all the packages, classes, constructors, methods, and fields which have been removed, added or changed in any way, including their documentation, when two APIs are compared.">
    -+<meta name="keywords" content="diff, jdiff, javadiff, java diff, java difference, API difference, difference between two APIs, API diff, Javadoc, doclet">
    -+<TITLE>
    -+android.support.v4.media.session.PlaybackStateCompat
    -+</TITLE>
    -+<link href="../../../../assets/android-developer-docs.css" rel="stylesheet" type="text/css" />
    -+<link href="../stylesheet-jdiff.css" rel="stylesheet" type="text/css" />
    -+<noscript>
    -+<style type="text/css">
    -+body{overflow:auto;}
    -+#body-content{position:relative; top:0;}
    -+#doc-content{overflow:visible;border-left:3px solid #666;}
    -+#side-nav{padding:0;}
    -+#side-nav .toggle-list ul {display:block;}
    -+#resize-packages-nav{border-bottom:3px solid #666;}
    -+</style>
    -+</noscript>
    -+<style type="text/css">
    -+</style>
    -+</HEAD>
    -+<BODY>
    -+<!-- Start of nav bar -->
    -+<a name="top"></a>
    -+<div id="header" style="margin-bottom:0;padding-bottom:0;">
    -+<div id="headerLeft">
    -+<a href="../../../../index.html" tabindex="-1" target="_top"><img src="../../../../assets/images/bg_logo.png" alt="Android Developers" /></a>
    -+</div>
    -+  <div id="headerRight">
    -+  <div id="headerLinks">
    -+<!-- <img src="/assets/images/icon_world.jpg" alt="" /> -->
    -+<span class="text">
    -+<!-- &nbsp;<a href="#">English</a> | -->
    -+<nobr><a href="http://developer.android.com" target="_top">Android Developers</a> | <a href="http://www.android.com" target="_top">Android.com</a></nobr>
    -+</span>
    -+</div>
    -+  <div class="and-diff-id" style="margin-top:6px;margin-right:8px;">
    -+    <table class="diffspectable">
    -+      <tr>
    -+        <td colspan="2" class="diffspechead">API Diff Specification</td>
    -+      </tr>
    -+      <tr>
    -+        <td class="diffspec" style="padding-top:.25em">To Level:</td>
    -+        <td class="diffvaluenew" style="padding-top:.25em">24.2.0</td>
    -+      </tr>
    -+      <tr>
    -+        <td class="diffspec">From Level:</td>
    -+        <td class="diffvalueold">24.1.0</td>
    -+      </tr>
    -+      <tr>
    -+        <td class="diffspec">Generated</td>
    -+        <td class="diffvalue">2016.08.16 14:03</td>
    -+      </tr>
    -+    </table>
    -+    </div><!-- End and-diff-id -->
    -+  <div class="and-diff-id" style="margin-right:8px;">
    -+    <table class="diffspectable">
    -+      <tr>
    -+        <td class="diffspec" colspan="2"><a href="jdiff_statistics.html">Statistics</a>
    -+      </tr>
    -+    </table>
    -+  </div> <!-- End and-diff-id -->
    -+  </div> <!-- End headerRight -->
    -+  </div> <!-- End header -->
    -+<div id="body-content" xstyle="padding:12px;padding-right:18px;">
    -+<div id="doc-content" style="position:relative;">
    -+<div id="mainBodyFluid">
    -+<H2>
    -+Class android.support.v4.media.session.<A HREF="../../../../reference/android/support/v4/media/session/PlaybackStateCompat.html" target="_top"><font size="+2"><code>PlaybackStateCompat</code></font></A>
    -+</H2>
    -+<a NAME="constructors"></a>
    -+<a NAME="methods"></a>
    -+<p>
    -+<a NAME="Added"></a>
    -+<TABLE summary="Added Methods" WIDTH="100%">
    -+<TR>
    -+  <TH VALIGN="TOP" COLSPAN=2>Added Methods</FONT></TD>
    -+</TH>
    -+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    -+  <TD VALIGN="TOP" WIDTH="25%">
    -+  <A NAME="android.support.v4.media.session.PlaybackStateCompat.toKeyCode_added(long)"></A>
    -+  <nobr><code>int</code>&nbsp;<A HREF="../../../../reference/android/support/v4/media/session/PlaybackStateCompat.html#toKeyCode(long)" target="_top"><code>toKeyCode</code></A>(<code>long</code>)</nobr>
    -+  </TD>
    -+  <TD>&nbsp;</TD>
    -+</TR>
    -+</TABLE>
    -+&nbsp;
    -+<a NAME="fields"></a>
    -+      </div>	
    -+      <div id="footer">
    -+        <div id="copyright">
    -+        Except as noted, this content is licensed under 
    -+        <a href="http://creativecommons.org/licenses/by/2.5/"> Creative Commons Attribution 2.5</a>.
    -+        For details and restrictions, see the <a href="/license.html">Content License</a>.
    -+        </div>
    -+      <div id="footerlinks">
    -+      <p>
    -+        <a href="http://www.android.com/terms.html">Site Terms of Service</a> -
    -+        <a href="http://www.android.com/privacy.html">Privacy Policy</a> -
    -+        <a href="http://www.android.com/branding.html">Brand Guidelines</a>
    -+      </p>
    -+    </div>
    -+    </div> <!-- end footer -->
    -+    </div><!-- end doc-content -->
    -+    </div> <!-- end body-content --> 
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    -+</script>
    -+<script type="text/javascript">
    -+  try {
    -+    var pageTracker = _gat._getTracker("UA-5831155-1");
    -+    pageTracker._setAllowAnchor(true);
    -+    pageTracker._initData();
    -+    pageTracker._trackPageview();
    -+  } catch(e) {}
    -+</script>
    -+</BODY>
    -+</HTML>
    -diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.os.BuildCompat.html b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.os.BuildCompat.html
    -new file mode 100644
    -index 0000000..372415a
    ---- /dev/null
    -+++ b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.os.BuildCompat.html
    -@@ -0,0 +1,122 @@
    -+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
    -+<HTML style="overflow:auto;">
    -+<HEAD>
    -+<meta name="generator" content="JDiff v1.1.0">
    -+<!-- Generated by the JDiff Javadoc doclet -->
    -+<!-- (http://www.jdiff.org) -->
    -+<meta name="description" content="JDiff is a Javadoc doclet which generates an HTML report of all the packages, classes, constructors, methods, and fields which have been removed, added or changed in any way, including their documentation, when two APIs are compared.">
    -+<meta name="keywords" content="diff, jdiff, javadiff, java diff, java difference, API difference, difference between two APIs, API diff, Javadoc, doclet">
    -+<TITLE>
    -+android.support.v4.os.BuildCompat
    -+</TITLE>
    -+<link href="../../../../assets/android-developer-docs.css" rel="stylesheet" type="text/css" />
    -+<link href="../stylesheet-jdiff.css" rel="stylesheet" type="text/css" />
    -+<noscript>
    -+<style type="text/css">
    -+body{overflow:auto;}
    -+#body-content{position:relative; top:0;}
    -+#doc-content{overflow:visible;border-left:3px solid #666;}
    -+#side-nav{padding:0;}
    -+#side-nav .toggle-list ul {display:block;}
    -+#resize-packages-nav{border-bottom:3px solid #666;}
    -+</style>
    -+</noscript>
    -+<style type="text/css">
    -+</style>
    -+</HEAD>
    -+<BODY>
    -+<!-- Start of nav bar -->
    -+<a name="top"></a>
    -+<div id="header" style="margin-bottom:0;padding-bottom:0;">
    -+<div id="headerLeft">
    -+<a href="../../../../index.html" tabindex="-1" target="_top"><img src="../../../../assets/images/bg_logo.png" alt="Android Developers" /></a>
    -+</div>
    -+  <div id="headerRight">
    -+  <div id="headerLinks">
    -+<!-- <img src="/assets/images/icon_world.jpg" alt="" /> -->
    -+<span class="text">
    -+<!-- &nbsp;<a href="#">English</a> | -->
    -+<nobr><a href="http://developer.android.com" target="_top">Android Developers</a> | <a href="http://www.android.com" target="_top">Android.com</a></nobr>
    -+</span>
    -+</div>
    -+  <div class="and-diff-id" style="margin-top:6px;margin-right:8px;">
    -+    <table class="diffspectable">
    -+      <tr>
    -+        <td colspan="2" class="diffspechead">API Diff Specification</td>
    -+      </tr>
    -+      <tr>
    -+        <td class="diffspec" style="padding-top:.25em">To Level:</td>
    -+        <td class="diffvaluenew" style="padding-top:.25em">24.2.0</td>
    -+      </tr>
    -+      <tr>
    -+        <td class="diffspec">From Level:</td>
    -+        <td class="diffvalueold">24.1.0</td>
    -+      </tr>
    -+      <tr>
    -+        <td class="diffspec">Generated</td>
    -+        <td class="diffvalue">2016.08.16 14:03</td>
    -+      </tr>
    -+    </table>
    -+    </div><!-- End and-diff-id -->
    -+  <div class="and-diff-id" style="margin-right:8px;">
    -+    <table class="diffspectable">
    -+      <tr>
    -+        <td class="diffspec" colspan="2"><a href="jdiff_statistics.html">Statistics</a>
    -+      </tr>
    -+    </table>
    -+  </div> <!-- End and-diff-id -->
    -+  </div> <!-- End headerRight -->
    -+  </div> <!-- End header -->
    -+<div id="body-content" xstyle="padding:12px;padding-right:18px;">
    -+<div id="doc-content" style="position:relative;">
    -+<div id="mainBodyFluid">
    -+<H2>
    -+Class android.support.v4.os.<A HREF="../../../../reference/android/support/v4/os/BuildCompat.html" target="_top"><font size="+2"><code>BuildCompat</code></font></A>
    -+</H2>
    -+<a NAME="constructors"></a>
    -+<a NAME="methods"></a>
    -+<p>
    -+<a NAME="Added"></a>
    -+<TABLE summary="Added Methods" WIDTH="100%">
    -+<TR>
    -+  <TH VALIGN="TOP" COLSPAN=2>Added Methods</FONT></TD>
    -+</TH>
    -+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    -+  <TD VALIGN="TOP" WIDTH="25%">
    -+  <A NAME="android.support.v4.os.BuildCompat.isAtLeastNMR1_added()"></A>
    -+  <nobr><code>boolean</code>&nbsp;<A HREF="../../../../reference/android/support/v4/os/BuildCompat.html#isAtLeastNMR1()" target="_top"><code>isAtLeastNMR1</code></A>()</nobr>
    -+  </TD>
    -+  <TD>&nbsp;</TD>
    -+</TR>
    -+</TABLE>
    -+&nbsp;
    -+<a NAME="fields"></a>
    -+      </div>	
    -+      <div id="footer">
    -+        <div id="copyright">
    -+        Except as noted, this content is licensed under 
    -+        <a href="http://creativecommons.org/licenses/by/2.5/"> Creative Commons Attribution 2.5</a>.
    -+        For details and restrictions, see the <a href="/license.html">Content License</a>.
    -+        </div>
    -+      <div id="footerlinks">
    -+      <p>
    -+        <a href="http://www.android.com/terms.html">Site Terms of Service</a> -
    -+        <a href="http://www.android.com/privacy.html">Privacy Policy</a> -
    -+        <a href="http://www.android.com/branding.html">Brand Guidelines</a>
    -+      </p>
    -+    </div>
    -+    </div> <!-- end footer -->
    -+    </div><!-- end doc-content -->
    -+    </div> <!-- end body-content --> 
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    -+</script>
    -+<script type="text/javascript">
    -+  try {
    -+    var pageTracker = _gat._getTracker("UA-5831155-1");
    -+    pageTracker._setAllowAnchor(true);
    -+    pageTracker._initData();
    -+    pageTracker._trackPageview();
    -+  } catch(e) {}
    -+</script>
    -+</BODY>
    -+</HTML>
    -diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.view.KeyEventCompat.html b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.view.KeyEventCompat.html
    -new file mode 100644
    -index 0000000..d62437e
    ---- /dev/null
    -+++ b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.view.KeyEventCompat.html
    -@@ -0,0 +1,155 @@
    -+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
    -+<HTML style="overflow:auto;">
    -+<HEAD>
    -+<meta name="generator" content="JDiff v1.1.0">
    -+<!-- Generated by the JDiff Javadoc doclet -->
    -+<!-- (http://www.jdiff.org) -->
    -+<meta name="description" content="JDiff is a Javadoc doclet which generates an HTML report of all the packages, classes, constructors, methods, and fields which have been removed, added or changed in any way, including their documentation, when two APIs are compared.">
    -+<meta name="keywords" content="diff, jdiff, javadiff, java diff, java difference, API difference, difference between two APIs, API diff, Javadoc, doclet">
    -+<TITLE>
    -+android.support.v4.view.KeyEventCompat
    -+</TITLE>
    -+<link href="../../../../assets/android-developer-docs.css" rel="stylesheet" type="text/css" />
    -+<link href="../stylesheet-jdiff.css" rel="stylesheet" type="text/css" />
    -+<noscript>
    -+<style type="text/css">
    -+body{overflow:auto;}
    -+#body-content{position:relative; top:0;}
    -+#doc-content{overflow:visible;border-left:3px solid #666;}
    -+#side-nav{padding:0;}
    -+#side-nav .toggle-list ul {display:block;}
    -+#resize-packages-nav{border-bottom:3px solid #666;}
    -+</style>
    -+</noscript>
    -+<style type="text/css">
    -+</style>
    -+</HEAD>
    -+<BODY>
    -+<!-- Start of nav bar -->
    -+<a name="top"></a>
    -+<div id="header" style="margin-bottom:0;padding-bottom:0;">
    -+<div id="headerLeft">
    -+<a href="../../../../index.html" tabindex="-1" target="_top"><img src="../../../../assets/images/bg_logo.png" alt="Android Developers" /></a>
    -+</div>
    -+  <div id="headerRight">
    -+  <div id="headerLinks">
    -+<!-- <img src="/assets/images/icon_world.jpg" alt="" /> -->
    -+<span class="text">
    -+<!-- &nbsp;<a href="#">English</a> | -->
    -+<nobr><a href="http://developer.android.com" target="_top">Android Developers</a> | <a href="http://www.android.com" target="_top">Android.com</a></nobr>
    -+</span>
    -+</div>
    -+  <div class="and-diff-id" style="margin-top:6px;margin-right:8px;">
    -+    <table class="diffspectable">
    -+      <tr>
    -+        <td colspan="2" class="diffspechead">API Diff Specification</td>
    -+      </tr>
    -+      <tr>
    -+        <td class="diffspec" style="padding-top:.25em">To Level:</td>
    -+        <td class="diffvaluenew" style="padding-top:.25em">24.2.0</td>
    -+      </tr>
    -+      <tr>
    -+        <td class="diffspec">From Level:</td>
    -+        <td class="diffvalueold">24.1.0</td>
    -+      </tr>
    -+      <tr>
    -+        <td class="diffspec">Generated</td>
    -+        <td class="diffvalue">2016.08.16 14:03</td>
    -+      </tr>
    -+    </table>
    -+    </div><!-- End and-diff-id -->
    -+  <div class="and-diff-id" style="margin-right:8px;">
    -+    <table class="diffspectable">
    -+      <tr>
    -+        <td class="diffspec" colspan="2"><a href="jdiff_statistics.html">Statistics</a>
    -+      </tr>
    -+    </table>
    -+  </div> <!-- End and-diff-id -->
    -+  </div> <!-- End headerRight -->
    -+  </div> <!-- End header -->
    -+<div id="body-content" xstyle="padding:12px;padding-right:18px;">
    -+<div id="doc-content" style="position:relative;">
    -+<div id="mainBodyFluid">
    -+<H2>
    -+Class android.support.v4.view.<A HREF="../../../../reference/android/support/v4/view/KeyEventCompat.html" target="_top"><font size="+2"><code>KeyEventCompat</code></font></A>
    -+</H2>
    -+<a NAME="constructors"></a>
    -+<a NAME="methods"></a>
    -+<p>
    -+<a NAME="Changed"></a>
    -+<TABLE summary="Changed Methods" WIDTH="100%">
    -+<TR>
    -+  <TH VALIGN="TOP" COLSPAN=3>Changed Methods</FONT></TD>
    -+</TH>
    -+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    -+  <TD VALIGN="TOP" WIDTH="25%">
    -+  <A NAME="android.support.v4.view.KeyEventCompat.dispatch_changed(android.view.KeyEvent, android.view.KeyEvent.Callback, java.lang.Object, java.lang.Object)"></A>
    -+  <nobr><code>boolean</code>&nbsp;<A HREF="../../../../reference/android/support/v4/view/KeyEventCompat.html#dispatch(android.view.KeyEvent, android.view.KeyEvent.Callback, java.lang.Object, java.lang.Object)" target="_top"><code>dispatch</code></A>(<code>KeyEvent,</nobr> Callback<nobr>,</nobr> Object<nobr>,</nobr> Object<nobr><nobr></code>)  </nobr>
    -+  </TD>
    -+  <TD VALIGN="TOP" WIDTH="30%">
    -+<b>Now deprecated</b>.<br>
    -+  </TD>
    -+  <TD>&nbsp;</TD>
    -+</TR>
    -+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    -+  <TD VALIGN="TOP" WIDTH="25%">
    -+  <A NAME="android.support.v4.view.KeyEventCompat.getKeyDispatcherState_changed(android.view.View)"></A>
    -+  <nobr><code>Object</code>&nbsp;<A HREF="../../../../reference/android/support/v4/view/KeyEventCompat.html#getKeyDispatcherState(android.view.View)" target="_top"><code>getKeyDispatcherState</code></A>(<code>View</code>)  </nobr>
    -+  </TD>
    -+  <TD VALIGN="TOP" WIDTH="30%">
    -+<b>Now deprecated</b>.<br>
    -+  </TD>
    -+  <TD>&nbsp;</TD>
    -+</TR>
    -+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    -+  <TD VALIGN="TOP" WIDTH="25%">
    -+  <A NAME="android.support.v4.view.KeyEventCompat.isTracking_changed(android.view.KeyEvent)"></A>
    -+  <nobr><code>boolean</code>&nbsp;<A HREF="../../../../reference/android/support/v4/view/KeyEventCompat.html#isTracking(android.view.KeyEvent)" target="_top"><code>isTracking</code></A>(<code>KeyEvent</code>)  </nobr>
    -+  </TD>
    -+  <TD VALIGN="TOP" WIDTH="30%">
    -+<b>Now deprecated</b>.<br>
    -+  </TD>
    -+  <TD>&nbsp;</TD>
    -+</TR>
    -+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    -+  <TD VALIGN="TOP" WIDTH="25%">
    -+  <A NAME="android.support.v4.view.KeyEventCompat.startTracking_changed(android.view.KeyEvent)"></A>
    -+  <nobr><code>void</code>&nbsp;<A HREF="../../../../reference/android/support/v4/view/KeyEventCompat.html#startTracking(android.view.KeyEvent)" target="_top"><code>startTracking</code></A>(<code>KeyEvent</code>)  </nobr>
    -+  </TD>
    -+  <TD VALIGN="TOP" WIDTH="30%">
    -+<b>Now deprecated</b>.<br>
    -+  </TD>
    -+  <TD>&nbsp;</TD>
    -+</TR>
    -+</TABLE>
    -+&nbsp;
    -+<a NAME="fields"></a>
    -+      </div>	
    -+      <div id="footer">
    -+        <div id="copyright">
    -+        Except as noted, this content is licensed under 
    -+        <a href="http://creativecommons.org/licenses/by/2.5/"> Creative Commons Attribution 2.5</a>.
    -+        For details and restrictions, see the <a href="/license.html">Content License</a>.
    -+        </div>
    -+      <div id="footerlinks">
    -+      <p>
    -+        <a href="http://www.android.com/terms.html">Site Terms of Service</a> -
    -+        <a href="http://www.android.com/privacy.html">Privacy Policy</a> -
    -+        <a href="http://www.android.com/branding.html">Brand Guidelines</a>
    -+      </p>
    -+    </div>
    -+    </div> <!-- end footer -->
    -+    </div><!-- end doc-content -->
    -+    </div> <!-- end body-content --> 
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    -+</script>
    -+<script type="text/javascript">
    -+  try {
    -+    var pageTracker = _gat._getTracker("UA-5831155-1");
    -+    pageTracker._setAllowAnchor(true);
    -+    pageTracker._initData();
    -+    pageTracker._trackPageview();
    -+  } catch(e) {}
    -+</script>
    -+</BODY>
    -+</HTML>
    -diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.view.MotionEventCompat.html b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.view.MotionEventCompat.html
    -new file mode 100644
    -index 0000000..8f58037
    ---- /dev/null
    -+++ b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.view.MotionEventCompat.html
    -@@ -0,0 +1,175 @@
    -+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
    -+<HTML style="overflow:auto;">
    -+<HEAD>
    -+<meta name="generator" content="JDiff v1.1.0">
    -+<!-- Generated by the JDiff Javadoc doclet -->
    -+<!-- (http://www.jdiff.org) -->
    -+<meta name="description" content="JDiff is a Javadoc doclet which generates an HTML report of all the packages, classes, constructors, methods, and fields which have been removed, added or changed in any way, including their documentation, when two APIs are compared.">
    -+<meta name="keywords" content="diff, jdiff, javadiff, java diff, java difference, API difference, difference between two APIs, API diff, Javadoc, doclet">
    -+<TITLE>
    -+android.support.v4.view.MotionEventCompat
    -+</TITLE>
    -+<link href="../../../../assets/android-developer-docs.css" rel="stylesheet" type="text/css" />
    -+<link href="../stylesheet-jdiff.css" rel="stylesheet" type="text/css" />
    -+<noscript>
    -+<style type="text/css">
    -+body{overflow:auto;}
    -+#body-content{position:relative; top:0;}
    -+#doc-content{overflow:visible;border-left:3px solid #666;}
    -+#side-nav{padding:0;}
    -+#side-nav .toggle-list ul {display:block;}
    -+#resize-packages-nav{border-bottom:3px solid #666;}
    -+</style>
    -+</noscript>
    -+<style type="text/css">
    -+</style>
    -+</HEAD>
    -+<BODY>
    -+<!-- Start of nav bar -->
    -+<a name="top"></a>
    -+<div id="header" style="margin-bottom:0;padding-bottom:0;">
    -+<div id="headerLeft">
    -+<a href="../../../../index.html" tabindex="-1" target="_top"><img src="../../../../assets/images/bg_logo.png" alt="Android Developers" /></a>
    -+</div>
    -+  <div id="headerRight">
    -+  <div id="headerLinks">
    -+<!-- <img src="/assets/images/icon_world.jpg" alt="" /> -->
    -+<span class="text">
    -+<!-- &nbsp;<a href="#">English</a> | -->
    -+<nobr><a href="http://developer.android.com" target="_top">Android Developers</a> | <a href="http://www.android.com" target="_top">Android.com</a></nobr>
    -+</span>
    -+</div>
    -+  <div class="and-diff-id" style="margin-top:6px;margin-right:8px;">
    -+    <table class="diffspectable">
    -+      <tr>
    -+        <td colspan="2" class="diffspechead">API Diff Specification</td>
    -+      </tr>
    -+      <tr>
    -+        <td class="diffspec" style="padding-top:.25em">To Level:</td>
    -+        <td class="diffvaluenew" style="padding-top:.25em">24.2.0</td>
    -+      </tr>
    -+      <tr>
    -+        <td class="diffspec">From Level:</td>
    -+        <td class="diffvalueold">24.1.0</td>
    -+      </tr>
    -+      <tr>
    -+        <td class="diffspec">Generated</td>
    -+        <td class="diffvalue">2016.08.16 14:03</td>
    -+      </tr>
    -+    </table>
    -+    </div><!-- End and-diff-id -->
    -+  <div class="and-diff-id" style="margin-right:8px;">
    -+    <table class="diffspectable">
    -+      <tr>
    -+        <td class="diffspec" colspan="2"><a href="jdiff_statistics.html">Statistics</a>
    -+      </tr>
    -+    </table>
    -+  </div> <!-- End and-diff-id -->
    -+  </div> <!-- End headerRight -->
    -+  </div> <!-- End header -->
    -+<div id="body-content" xstyle="padding:12px;padding-right:18px;">
    -+<div id="doc-content" style="position:relative;">
    -+<div id="mainBodyFluid">
    -+<H2>
    -+Class android.support.v4.view.<A HREF="../../../../reference/android/support/v4/view/MotionEventCompat.html" target="_top"><font size="+2"><code>MotionEventCompat</code></font></A>
    -+</H2>
    -+<a NAME="constructors"></a>
    -+<a NAME="methods"></a>
    -+<p>
    -+<a NAME="Changed"></a>
    -+<TABLE summary="Changed Methods" WIDTH="100%">
    -+<TR>
    -+  <TH VALIGN="TOP" COLSPAN=3>Changed Methods</FONT></TD>
    -+</TH>
    -+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    -+  <TD VALIGN="TOP" WIDTH="25%">
    -+  <A NAME="android.support.v4.view.MotionEventCompat.findPointerIndex_changed(android.view.MotionEvent, int)"></A>
    -+  <nobr><code>int</code>&nbsp;<A HREF="../../../../reference/android/support/v4/view/MotionEventCompat.html#findPointerIndex(android.view.MotionEvent, int)" target="_top"><code>findPointerIndex</code></A>(<code>MotionEvent,</nobr> int<nobr><nobr></code>)  </nobr>
    -+  </TD>
    -+  <TD VALIGN="TOP" WIDTH="30%">
    -+<b>Now deprecated</b>.<br>
    -+  </TD>
    -+  <TD>&nbsp;</TD>
    -+</TR>
    -+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    -+  <TD VALIGN="TOP" WIDTH="25%">
    -+  <A NAME="android.support.v4.view.MotionEventCompat.getPointerCount_changed(android.view.MotionEvent)"></A>
    -+  <nobr><code>int</code>&nbsp;<A HREF="../../../../reference/android/support/v4/view/MotionEventCompat.html#getPointerCount(android.view.MotionEvent)" target="_top"><code>getPointerCount</code></A>(<code>MotionEvent</code>)  </nobr>
    -+  </TD>
    -+  <TD VALIGN="TOP" WIDTH="30%">
    -+<b>Now deprecated</b>.<br>
    -+  </TD>
    -+  <TD>&nbsp;</TD>
    -+</TR>
    -+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    -+  <TD VALIGN="TOP" WIDTH="25%">
    -+  <A NAME="android.support.v4.view.MotionEventCompat.getPointerId_changed(android.view.MotionEvent, int)"></A>
    -+  <nobr><code>int</code>&nbsp;<A HREF="../../../../reference/android/support/v4/view/MotionEventCompat.html#getPointerId(android.view.MotionEvent, int)" target="_top"><code>getPointerId</code></A>(<code>MotionEvent,</nobr> int<nobr><nobr></code>)  </nobr>
    -+  </TD>
    -+  <TD VALIGN="TOP" WIDTH="30%">
    -+<b>Now deprecated</b>.<br>
    -+  </TD>
    -+  <TD>&nbsp;</TD>
    -+</TR>
    -+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    -+  <TD VALIGN="TOP" WIDTH="25%">
    -+  <A NAME="android.support.v4.view.MotionEventCompat.getSource_changed(android.view.MotionEvent)"></A>
    -+  <nobr><code>int</code>&nbsp;<A HREF="../../../../reference/android/support/v4/view/MotionEventCompat.html#getSource(android.view.MotionEvent)" target="_top"><code>getSource</code></A>(<code>MotionEvent</code>)  </nobr>
    -+  </TD>
    -+  <TD VALIGN="TOP" WIDTH="30%">
    -+<b>Now deprecated</b>.<br>
    -+  </TD>
    -+  <TD>&nbsp;</TD>
    -+</TR>
    -+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    -+  <TD VALIGN="TOP" WIDTH="25%">
    -+  <A NAME="android.support.v4.view.MotionEventCompat.getX_changed(android.view.MotionEvent, int)"></A>
    -+  <nobr><code>float</code>&nbsp;<A HREF="../../../../reference/android/support/v4/view/MotionEventCompat.html#getX(android.view.MotionEvent, int)" target="_top"><code>getX</code></A>(<code>MotionEvent,</nobr> int<nobr><nobr></code>)  </nobr>
    -+  </TD>
    -+  <TD VALIGN="TOP" WIDTH="30%">
    -+<b>Now deprecated</b>.<br>
    -+  </TD>
    -+  <TD>&nbsp;</TD>
    -+</TR>
    -+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    -+  <TD VALIGN="TOP" WIDTH="25%">
    -+  <A NAME="android.support.v4.view.MotionEventCompat.getY_changed(android.view.MotionEvent, int)"></A>
    -+  <nobr><code>float</code>&nbsp;<A HREF="../../../../reference/android/support/v4/view/MotionEventCompat.html#getY(android.view.MotionEvent, int)" target="_top"><code>getY</code></A>(<code>MotionEvent,</nobr> int<nobr><nobr></code>)  </nobr>
    -+  </TD>
    -+  <TD VALIGN="TOP" WIDTH="30%">
    -+<b>Now deprecated</b>.<br>
    -+  </TD>
    -+  <TD>&nbsp;</TD>
    -+</TR>
    -+</TABLE>
    -+&nbsp;
    -+<a NAME="fields"></a>
    -+      </div>	
    -+      <div id="footer">
    -+        <div id="copyright">
    -+        Except as noted, this content is licensed under 
    -+        <a href="http://creativecommons.org/licenses/by/2.5/"> Creative Commons Attribution 2.5</a>.
    -+        For details and restrictions, see the <a href="/license.html">Content License</a>.
    -+        </div>
    -+      <div id="footerlinks">
    -+      <p>
    -+        <a href="http://www.android.com/terms.html">Site Terms of Service</a> -
    -+        <a href="http://www.android.com/privacy.html">Privacy Policy</a> -
    -+        <a href="http://www.android.com/branding.html">Brand Guidelines</a>
    -+      </p>
    -+    </div>
    -+    </div> <!-- end footer -->
    -+    </div><!-- end doc-content -->
    -+    </div> <!-- end body-content --> 
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    -+</script>
    -+<script type="text/javascript">
    -+  try {
    -+    var pageTracker = _gat._getTracker("UA-5831155-1");
    -+    pageTracker._setAllowAnchor(true);
    -+    pageTracker._initData();
    -+    pageTracker._trackPageview();
    -+  } catch(e) {}
    -+</script>
    -+</BODY>
    -+</HTML>
    -diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.view.ViewCompat.html b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.view.ViewCompat.html
    -new file mode 100644
    -index 0000000..0974230
    ---- /dev/null
    -+++ b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.view.ViewCompat.html
    -@@ -0,0 +1,195 @@
    -+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
    -+<HTML style="overflow:auto;">
    -+<HEAD>
    -+<meta name="generator" content="JDiff v1.1.0">
    -+<!-- Generated by the JDiff Javadoc doclet -->
    -+<!-- (http://www.jdiff.org) -->
    -+<meta name="description" content="JDiff is a Javadoc doclet which generates an HTML report of all the packages, classes, constructors, methods, and fields which have been removed, added or changed in any way, including their documentation, when two APIs are compared.">
    -+<meta name="keywords" content="diff, jdiff, javadiff, java diff, java difference, API difference, difference between two APIs, API diff, Javadoc, doclet">
    -+<TITLE>
    -+android.support.v4.view.ViewCompat
    -+</TITLE>
    -+<link href="../../../../assets/android-developer-docs.css" rel="stylesheet" type="text/css" />
    -+<link href="../stylesheet-jdiff.css" rel="stylesheet" type="text/css" />
    -+<noscript>
    -+<style type="text/css">
    -+body{overflow:auto;}
    -+#body-content{position:relative; top:0;}
    -+#doc-content{overflow:visible;border-left:3px solid #666;}
    -+#side-nav{padding:0;}
    -+#side-nav .toggle-list ul {display:block;}
    -+#resize-packages-nav{border-bottom:3px solid #666;}
    -+</style>
    -+</noscript>
    -+<style type="text/css">
    -+</style>
    -+</HEAD>
    -+<BODY>
    -+<!-- Start of nav bar -->
    -+<a name="top"></a>
    -+<div id="header" style="margin-bottom:0;padding-bottom:0;">
    -+<div id="headerLeft">
    -+<a href="../../../../index.html" tabindex="-1" target="_top"><img src="../../../../assets/images/bg_logo.png" alt="Android Developers" /></a>
    -+</div>
    -+  <div id="headerRight">
    -+  <div id="headerLinks">
    -+<!-- <img src="/assets/images/icon_world.jpg" alt="" /> -->
    -+<span class="text">
    -+<!-- &nbsp;<a href="#">English</a> | -->
    -+<nobr><a href="http://developer.android.com" target="_top">Android Developers</a> | <a href="http://www.android.com" target="_top">Android.com</a></nobr>
    -+</span>
    -+</div>
    -+  <div class="and-diff-id" style="margin-top:6px;margin-right:8px;">
    -+    <table class="diffspectable">
    -+      <tr>
    -+        <td colspan="2" class="diffspechead">API Diff Specification</td>
    -+      </tr>
    -+      <tr>
    -+        <td class="diffspec" style="padding-top:.25em">To Level:</td>
    -+        <td class="diffvaluenew" style="padding-top:.25em">24.2.0</td>
    -+      </tr>
    -+      <tr>
    -+        <td class="diffspec">From Level:</td>
    -+        <td class="diffvalueold">24.1.0</td>
    -+      </tr>
    -+      <tr>
    -+        <td class="diffspec">Generated</td>
    -+        <td class="diffvalue">2016.08.16 14:03</td>
    -+      </tr>
    -+    </table>
    -+    </div><!-- End and-diff-id -->
    -+  <div class="and-diff-id" style="margin-right:8px;">
    -+    <table class="diffspectable">
    -+      <tr>
    -+        <td class="diffspec" colspan="2"><a href="jdiff_statistics.html">Statistics</a>
    -+      </tr>
    -+    </table>
    -+  </div> <!-- End and-diff-id -->
    -+  </div> <!-- End headerRight -->
    -+  </div> <!-- End header -->
    -+<div id="body-content" xstyle="padding:12px;padding-right:18px;">
    -+<div id="doc-content" style="position:relative;">
    -+<div id="mainBodyFluid">
    -+<H2>
    -+Class android.support.v4.view.<A HREF="../../../../reference/android/support/v4/view/ViewCompat.html" target="_top"><font size="+2"><code>ViewCompat</code></font></A>
    -+</H2>
    -+<a NAME="constructors"></a>
    -+<a NAME="methods"></a>
    -+<p>
    -+<a NAME="Added"></a>
    -+<TABLE summary="Added Methods" WIDTH="100%">
    -+<TR>
    -+  <TH VALIGN="TOP" COLSPAN=2>Added Methods</FONT></TD>
    -+</TH>
    -+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    -+  <TD VALIGN="TOP" WIDTH="25%">
    -+  <A NAME="android.support.v4.view.ViewCompat.isImportantForAccessibility_added(android.view.View)"></A>
    -+  <nobr><code>boolean</code>&nbsp;<A HREF="../../../../reference/android/support/v4/view/ViewCompat.html#isImportantForAccessibility(android.view.View)" target="_top"><code>isImportantForAccessibility</code></A>(<code>View</code>)</nobr>
    -+  </TD>
    -+  <TD>&nbsp;</TD>
    -+</TR>
    -+</TABLE>
    -+&nbsp;
    -+<p>
    -+<a NAME="Changed"></a>
    -+<TABLE summary="Changed Methods" WIDTH="100%">
    -+<TR>
    -+  <TH VALIGN="TOP" COLSPAN=3>Changed Methods</FONT></TD>
    -+</TH>
    -+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    -+  <TD VALIGN="TOP" WIDTH="25%">
    -+  <A NAME="android.support.v4.view.ViewCompat.getOverScrollMode_changed(android.view.View)"></A>
    -+  <nobr><code>int</code>&nbsp;<A HREF="../../../../reference/android/support/v4/view/ViewCompat.html#getOverScrollMode(android.view.View)" target="_top"><code>getOverScrollMode</code></A>(<code>View</code>)  </nobr>
    -+  </TD>
    -+  <TD VALIGN="TOP" WIDTH="30%">
    -+<b>Now deprecated</b>.<br>
    -+  </TD>
    -+  <TD>&nbsp;</TD>
    -+</TR>
    -+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    -+  <TD VALIGN="TOP" WIDTH="25%">
    -+  <A NAME="android.support.v4.view.ViewCompat.isOpaque_changed(android.view.View)"></A>
    -+  <nobr><code>boolean</code>&nbsp;<A HREF="../../../../reference/android/support/v4/view/ViewCompat.html#isOpaque(android.view.View)" target="_top"><code>isOpaque</code></A>(<code>View</code>)  </nobr>
    -+  </TD>
    -+  <TD VALIGN="TOP" WIDTH="30%">
    -+<b>Now deprecated</b>.<br>
    -+  </TD>
    -+  <TD>&nbsp;</TD>
    -+</TR>
    -+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    -+  <TD VALIGN="TOP" WIDTH="25%">
    -+  <A NAME="android.support.v4.view.ViewCompat.setOverScrollMode_changed(android.view.View, int)"></A>
    -+  <nobr><code>void</code>&nbsp;<A HREF="../../../../reference/android/support/v4/view/ViewCompat.html#setOverScrollMode(android.view.View, int)" target="_top"><code>setOverScrollMode</code></A>(<code>View,</nobr> int<nobr><nobr></code>)  </nobr>
    -+  </TD>
    -+  <TD VALIGN="TOP" WIDTH="30%">
    -+<b>Now deprecated</b>.<br>
    -+  </TD>
    -+  <TD>&nbsp;</TD>
    -+</TR>
    -+</TABLE>
    -+&nbsp;
    -+<a NAME="fields"></a>
    -+<p>
    -+<a NAME="Changed"></a>
    -+<TABLE summary="Changed Fields" WIDTH="100%">
    -+<TR>
    -+  <TH VALIGN="TOP" COLSPAN=3>Changed Fields</FONT></TD>
    -+</TH>
    -+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    -+  <TD VALIGN="TOP" WIDTH="25%">
    -+  <A NAME="android.support.v4.view.ViewCompat.OVER_SCROLL_ALWAYS"></A>
    -+  <nobr><code>int</code>&nbsp;<A HREF="../../../../reference/android/support/v4/view/ViewCompat.html#OVER_SCROLL_ALWAYS" target="_top"><code>OVER_SCROLL_ALWAYS</code></font></A></nobr>  </TD>
    -+  <TD VALIGN="TOP" WIDTH="30%">
    -+<b>Now deprecated</b>.<br>
    -+  </TD>
    -+  <TD>&nbsp;</TD>
    -+</TR>
    -+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    -+  <TD VALIGN="TOP" WIDTH="25%">
    -+  <A NAME="android.support.v4.view.ViewCompat.OVER_SCROLL_IF_CONTENT_SCROLLS"></A>
    -+  <nobr><code>int</code>&nbsp;<A HREF="../../../../reference/android/support/v4/view/ViewCompat.html#OVER_SCROLL_IF_CONTENT_SCROLLS" target="_top"><code>OVER_SCROLL_IF_CONTENT_SCROLLS</code></font></A></nobr>  </TD>
    -+  <TD VALIGN="TOP" WIDTH="30%">
    -+<b>Now deprecated</b>.<br>
    -+  </TD>
    -+  <TD>&nbsp;</TD>
    -+</TR>
    -+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    -+  <TD VALIGN="TOP" WIDTH="25%">
    -+  <A NAME="android.support.v4.view.ViewCompat.OVER_SCROLL_NEVER"></A>
    -+  <nobr><code>int</code>&nbsp;<A HREF="../../../../reference/android/support/v4/view/ViewCompat.html#OVER_SCROLL_NEVER" target="_top"><code>OVER_SCROLL_NEVER</code></font></A></nobr>  </TD>
    -+  <TD VALIGN="TOP" WIDTH="30%">
    -+<b>Now deprecated</b>.<br>
    -+  </TD>
    -+  <TD>&nbsp;</TD>
    -+</TR>
    -+</TABLE>
    -+&nbsp;
    -+      </div>	
    -+      <div id="footer">
    -+        <div id="copyright">
    -+        Except as noted, this content is licensed under 
    -+        <a href="http://creativecommons.org/licenses/by/2.5/"> Creative Commons Attribution 2.5</a>.
    -+        For details and restrictions, see the <a href="/license.html">Content License</a>.
    -+        </div>
    -+      <div id="footerlinks">
    -+      <p>
    -+        <a href="http://www.android.com/terms.html">Site Terms of Service</a> -
    -+        <a href="http://www.android.com/privacy.html">Privacy Policy</a> -
    -+        <a href="http://www.android.com/branding.html">Brand Guidelines</a>
    -+      </p>
    -+    </div>
    -+    </div> <!-- end footer -->
    -+    </div><!-- end doc-content -->
    -+    </div> <!-- end body-content --> 
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    -+</script>
    -+<script type="text/javascript">
    -+  try {
    -+    var pageTracker = _gat._getTracker("UA-5831155-1");
    -+    pageTracker._setAllowAnchor(true);
    -+    pageTracker._initData();
    -+    pageTracker._trackPageview();
    -+  } catch(e) {}
    -+</script>
    -+</BODY>
    -+</HTML>
    -diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.view.ViewConfigurationCompat.html b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.view.ViewConfigurationCompat.html
    -new file mode 100644
    -index 0000000..3eec7fa
    ---- /dev/null
    -+++ b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.view.ViewConfigurationCompat.html
    -@@ -0,0 +1,125 @@
    -+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
    -+<HTML style="overflow:auto;">
    -+<HEAD>
    -+<meta name="generator" content="JDiff v1.1.0">
    -+<!-- Generated by the JDiff Javadoc doclet -->
    -+<!-- (http://www.jdiff.org) -->
    -+<meta name="description" content="JDiff is a Javadoc doclet which generates an HTML report of all the packages, classes, constructors, methods, and fields which have been removed, added or changed in any way, including their documentation, when two APIs are compared.">
    -+<meta name="keywords" content="diff, jdiff, javadiff, java diff, java difference, API difference, difference between two APIs, API diff, Javadoc, doclet">
    -+<TITLE>
    -+android.support.v4.view.ViewConfigurationCompat
    -+</TITLE>
    -+<link href="../../../../assets/android-developer-docs.css" rel="stylesheet" type="text/css" />
    -+<link href="../stylesheet-jdiff.css" rel="stylesheet" type="text/css" />
    -+<noscript>
    -+<style type="text/css">
    -+body{overflow:auto;}
    -+#body-content{position:relative; top:0;}
    -+#doc-content{overflow:visible;border-left:3px solid #666;}
    -+#side-nav{padding:0;}
    -+#side-nav .toggle-list ul {display:block;}
    -+#resize-packages-nav{border-bottom:3px solid #666;}
    -+</style>
    -+</noscript>
    -+<style type="text/css">
    -+</style>
    -+</HEAD>
    -+<BODY>
    -+<!-- Start of nav bar -->
    -+<a name="top"></a>
    -+<div id="header" style="margin-bottom:0;padding-bottom:0;">
    -+<div id="headerLeft">
    -+<a href="../../../../index.html" tabindex="-1" target="_top"><img src="../../../../assets/images/bg_logo.png" alt="Android Developers" /></a>
    -+</div>
    -+  <div id="headerRight">
    -+  <div id="headerLinks">
    -+<!-- <img src="/assets/images/icon_world.jpg" alt="" /> -->
    -+<span class="text">
    -+<!-- &nbsp;<a href="#">English</a> | -->
    -+<nobr><a href="http://developer.android.com" target="_top">Android Developers</a> | <a href="http://www.android.com" target="_top">Android.com</a></nobr>
    -+</span>
    -+</div>
    -+  <div class="and-diff-id" style="margin-top:6px;margin-right:8px;">
    -+    <table class="diffspectable">
    -+      <tr>
    -+        <td colspan="2" class="diffspechead">API Diff Specification</td>
    -+      </tr>
    -+      <tr>
    -+        <td class="diffspec" style="padding-top:.25em">To Level:</td>
    -+        <td class="diffvaluenew" style="padding-top:.25em">24.2.0</td>
    -+      </tr>
    -+      <tr>
    -+        <td class="diffspec">From Level:</td>
    -+        <td class="diffvalueold">24.1.0</td>
    -+      </tr>
    -+      <tr>
    -+        <td class="diffspec">Generated</td>
    -+        <td class="diffvalue">2016.08.16 14:03</td>
    -+      </tr>
    -+    </table>
    -+    </div><!-- End and-diff-id -->
    -+  <div class="and-diff-id" style="margin-right:8px;">
    -+    <table class="diffspectable">
    -+      <tr>
    -+        <td class="diffspec" colspan="2"><a href="jdiff_statistics.html">Statistics</a>
    -+      </tr>
    -+    </table>
    -+  </div> <!-- End and-diff-id -->
    -+  </div> <!-- End headerRight -->
    -+  </div> <!-- End header -->
    -+<div id="body-content" xstyle="padding:12px;padding-right:18px;">
    -+<div id="doc-content" style="position:relative;">
    -+<div id="mainBodyFluid">
    -+<H2>
    -+Class android.support.v4.view.<A HREF="../../../../reference/android/support/v4/view/ViewConfigurationCompat.html" target="_top"><font size="+2"><code>ViewConfigurationCompat</code></font></A>
    -+</H2>
    -+<a NAME="constructors"></a>
    -+<a NAME="methods"></a>
    -+<p>
    -+<a NAME="Changed"></a>
    -+<TABLE summary="Changed Methods" WIDTH="100%">
    -+<TR>
    -+  <TH VALIGN="TOP" COLSPAN=3>Changed Methods</FONT></TD>
    -+</TH>
    -+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    -+  <TD VALIGN="TOP" WIDTH="25%">
    -+  <A NAME="android.support.v4.view.ViewConfigurationCompat.getScaledPagingTouchSlop_changed(android.view.ViewConfiguration)"></A>
    -+  <nobr><code>int</code>&nbsp;<A HREF="../../../../reference/android/support/v4/view/ViewConfigurationCompat.html#getScaledPagingTouchSlop(android.view.ViewConfiguration)" target="_top"><code>getScaledPagingTouchSlop</code></A>(<code>ViewConfiguration</code>)  </nobr>
    -+  </TD>
    -+  <TD VALIGN="TOP" WIDTH="30%">
    -+<b>Now deprecated</b>.<br>
    -+  </TD>
    -+  <TD>&nbsp;</TD>
    -+</TR>
    -+</TABLE>
    -+&nbsp;
    -+<a NAME="fields"></a>
    -+      </div>	
    -+      <div id="footer">
    -+        <div id="copyright">
    -+        Except as noted, this content is licensed under 
    -+        <a href="http://creativecommons.org/licenses/by/2.5/"> Creative Commons Attribution 2.5</a>.
    -+        For details and restrictions, see the <a href="/license.html">Content License</a>.
    -+        </div>
    -+      <div id="footerlinks">
    -+      <p>
    -+        <a href="http://www.android.com/terms.html">Site Terms of Service</a> -
    -+        <a href="http://www.android.com/privacy.html">Privacy Policy</a> -
    -+        <a href="http://www.android.com/branding.html">Brand Guidelines</a>
    -+      </p>
    -+    </div>
    -+    </div> <!-- end footer -->
    -+    </div><!-- end doc-content -->
    -+    </div> <!-- end body-content --> 
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    -+</script>
    -+<script type="text/javascript">
    -+  try {
    -+    var pageTracker = _gat._getTracker("UA-5831155-1");
    -+    pageTracker._setAllowAnchor(true);
    -+    pageTracker._initData();
    -+    pageTracker._trackPageview();
    -+  } catch(e) {}
    -+</script>
    -+</BODY>
    -+</HTML>
    -diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.view.WindowInsetsCompat.html b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.view.WindowInsetsCompat.html
    -new file mode 100644
    -index 0000000..c5c1d22
    ---- /dev/null
    -+++ b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.view.WindowInsetsCompat.html
    -@@ -0,0 +1,122 @@
    -+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
    -+<HTML style="overflow:auto;">
    -+<HEAD>
    -+<meta name="generator" content="JDiff v1.1.0">
    -+<!-- Generated by the JDiff Javadoc doclet -->
    -+<!-- (http://www.jdiff.org) -->
    -+<meta name="description" content="JDiff is a Javadoc doclet which generates an HTML report of all the packages, classes, constructors, methods, and fields which have been removed, added or changed in any way, including their documentation, when two APIs are compared.">
    -+<meta name="keywords" content="diff, jdiff, javadiff, java diff, java difference, API difference, difference between two APIs, API diff, Javadoc, doclet">
    -+<TITLE>
    -+android.support.v4.view.WindowInsetsCompat
    -+</TITLE>
    -+<link href="../../../../assets/android-developer-docs.css" rel="stylesheet" type="text/css" />
    -+<link href="../stylesheet-jdiff.css" rel="stylesheet" type="text/css" />
    -+<noscript>
    -+<style type="text/css">
    -+body{overflow:auto;}
    -+#body-content{position:relative; top:0;}
    -+#doc-content{overflow:visible;border-left:3px solid #666;}
    -+#side-nav{padding:0;}
    -+#side-nav .toggle-list ul {display:block;}
    -+#resize-packages-nav{border-bottom:3px solid #666;}
    -+</style>
    -+</noscript>
    -+<style type="text/css">
    -+</style>
    -+</HEAD>
    -+<BODY>
    -+<!-- Start of nav bar -->
    -+<a name="top"></a>
    -+<div id="header" style="margin-bottom:0;padding-bottom:0;">
    -+<div id="headerLeft">
    -+<a href="../../../../index.html" tabindex="-1" target="_top"><img src="../../../../assets/images/bg_logo.png" alt="Android Developers" /></a>
    -+</div>
    -+  <div id="headerRight">
    -+  <div id="headerLinks">
    -+<!-- <img src="/assets/images/icon_world.jpg" alt="" /> -->
    -+<span class="text">
    -+<!-- &nbsp;<a href="#">English</a> | -->
    -+<nobr><a href="http://developer.android.com" target="_top">Android Developers</a> | <a href="http://www.android.com" target="_top">Android.com</a></nobr>
    -+</span>
    -+</div>
    -+  <div class="and-diff-id" style="margin-top:6px;margin-right:8px;">
    -+    <table class="diffspectable">
    -+      <tr>
    -+        <td colspan="2" class="diffspechead">API Diff Specification</td>
    -+      </tr>
    -+      <tr>
    -+        <td class="diffspec" style="padding-top:.25em">To Level:</td>
    -+        <td class="diffvaluenew" style="padding-top:.25em">24.2.0</td>
    -+      </tr>
    -+      <tr>
    -+        <td class="diffspec">From Level:</td>
    -+        <td class="diffvalueold">24.1.0</td>
    -+      </tr>
    -+      <tr>
    -+        <td class="diffspec">Generated</td>
    -+        <td class="diffvalue">2016.08.16 14:03</td>
    -+      </tr>
    -+    </table>
    -+    </div><!-- End and-diff-id -->
    -+  <div class="and-diff-id" style="margin-right:8px;">
    -+    <table class="diffspectable">
    -+      <tr>
    -+        <td class="diffspec" colspan="2"><a href="jdiff_statistics.html">Statistics</a>
    -+      </tr>
    -+    </table>
    -+  </div> <!-- End and-diff-id -->
    -+  </div> <!-- End headerRight -->
    -+  </div> <!-- End header -->
    -+<div id="body-content" xstyle="padding:12px;padding-right:18px;">
    -+<div id="doc-content" style="position:relative;">
    -+<div id="mainBodyFluid">
    -+<H2>
    -+Class android.support.v4.view.<A HREF="../../../../reference/android/support/v4/view/WindowInsetsCompat.html" target="_top"><font size="+2"><code>WindowInsetsCompat</code></font></A>
    -+</H2>
    -+<a NAME="constructors"></a>
    -+<p>
    -+<a NAME="Added"></a>
    -+<TABLE summary="Added Constructors" WIDTH="100%">
    -+<TR>
    -+  <TH VALIGN="TOP" COLSPAN=2>Added Constructors</FONT></TD>
    -+</TH>
    -+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    -+  <TD VALIGN="TOP" WIDTH="25%">
    -+  <A NAME="android.support.v4.view.WindowInsetsCompat.ctor_added(android.support.v4.view.WindowInsetsCompat)"></A>
    -+  <nobr><A HREF="../../../../reference/android/support/v4/view/WindowInsetsCompat.html#WindowInsetsCompat(android.support.v4.view.WindowInsetsCompat)" target="_top"><code>WindowInsetsCompat</code></A>(<code>WindowInsetsCompat</code>)</nobr>
    -+  </TD>
    -+  <TD>&nbsp;</TD>
    -+</TR>
    -+</TABLE>
    -+&nbsp;
    -+<a NAME="methods"></a>
    -+<a NAME="fields"></a>
    -+      </div>	
    -+      <div id="footer">
    -+        <div id="copyright">
    -+        Except as noted, this content is licensed under 
    -+        <a href="http://creativecommons.org/licenses/by/2.5/"> Creative Commons Attribution 2.5</a>.
    -+        For details and restrictions, see the <a href="/license.html">Content License</a>.
    -+        </div>
    -+      <div id="footerlinks">
    -+      <p>
    -+        <a href="http://www.android.com/terms.html">Site Terms of Service</a> -
    -+        <a href="http://www.android.com/privacy.html">Privacy Policy</a> -
    -+        <a href="http://www.android.com/branding.html">Brand Guidelines</a>
    -+      </p>
    -+    </div>
    -+    </div> <!-- end footer -->
    -+    </div><!-- end doc-content -->
    -+    </div> <!-- end body-content --> 
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    -+</script>
    -+<script type="text/javascript">
    -+  try {
    -+    var pageTracker = _gat._getTracker("UA-5831155-1");
    -+    pageTracker._setAllowAnchor(true);
    -+    pageTracker._initData();
    -+    pageTracker._trackPageview();
    -+  } catch(e) {}
    -+</script>
    -+</BODY>
    -+</HTML>
    -diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.view.accessibility.AccessibilityEventCompat.html b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.view.accessibility.AccessibilityEventCompat.html
    -new file mode 100644
    -index 0000000..1f9801f
    ---- /dev/null
    -+++ b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.view.accessibility.AccessibilityEventCompat.html
    -@@ -0,0 +1,172 @@
    -+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
    -+<HTML style="overflow:auto;">
    -+<HEAD>
    -+<meta name="generator" content="JDiff v1.1.0">
    -+<!-- Generated by the JDiff Javadoc doclet -->
    -+<!-- (http://www.jdiff.org) -->
    -+<meta name="description" content="JDiff is a Javadoc doclet which generates an HTML report of all the packages, classes, constructors, methods, and fields which have been removed, added or changed in any way, including their documentation, when two APIs are compared.">
    -+<meta name="keywords" content="diff, jdiff, javadiff, java diff, java difference, API difference, difference between two APIs, API diff, Javadoc, doclet">
    -+<TITLE>
    -+android.support.v4.view.accessibility.AccessibilityEventCompat
    -+</TITLE>
    -+<link href="../../../../assets/android-developer-docs.css" rel="stylesheet" type="text/css" />
    -+<link href="../stylesheet-jdiff.css" rel="stylesheet" type="text/css" />
    -+<noscript>
    -+<style type="text/css">
    -+body{overflow:auto;}
    -+#body-content{position:relative; top:0;}
    -+#doc-content{overflow:visible;border-left:3px solid #666;}
    -+#side-nav{padding:0;}
    -+#side-nav .toggle-list ul {display:block;}
    -+#resize-packages-nav{border-bottom:3px solid #666;}
    -+</style>
    -+</noscript>
    -+<style type="text/css">
    -+</style>
    -+</HEAD>
    -+<BODY>
    -+<!-- Start of nav bar -->
    -+<a name="top"></a>
    -+<div id="header" style="margin-bottom:0;padding-bottom:0;">
    -+<div id="headerLeft">
    -+<a href="../../../../index.html" tabindex="-1" target="_top"><img src="../../../../assets/images/bg_logo.png" alt="Android Developers" /></a>
    -+</div>
    -+  <div id="headerRight">
    -+  <div id="headerLinks">
    -+<!-- <img src="/assets/images/icon_world.jpg" alt="" /> -->
    -+<span class="text">
    -+<!-- &nbsp;<a href="#">English</a> | -->
    -+<nobr><a href="http://developer.android.com" target="_top">Android Developers</a> | <a href="http://www.android.com" target="_top">Android.com</a></nobr>
    -+</span>
    -+</div>
    -+  <div class="and-diff-id" style="margin-top:6px;margin-right:8px;">
    -+    <table class="diffspectable">
    -+      <tr>
    -+        <td colspan="2" class="diffspechead">API Diff Specification</td>
    -+      </tr>
    -+      <tr>
    -+        <td class="diffspec" style="padding-top:.25em">To Level:</td>
    -+        <td class="diffvaluenew" style="padding-top:.25em">24.2.0</td>
    -+      </tr>
    -+      <tr>
    -+        <td class="diffspec">From Level:</td>
    -+        <td class="diffvalueold">24.1.0</td>
    -+      </tr>
    -+      <tr>
    -+        <td class="diffspec">Generated</td>
    -+        <td class="diffvalue">2016.08.16 14:03</td>
    -+      </tr>
    -+    </table>
    -+    </div><!-- End and-diff-id -->
    -+  <div class="and-diff-id" style="margin-right:8px;">
    -+    <table class="diffspectable">
    -+      <tr>
    -+        <td class="diffspec" colspan="2"><a href="jdiff_statistics.html">Statistics</a>
    -+      </tr>
    -+    </table>
    -+  </div> <!-- End and-diff-id -->
    -+  </div> <!-- End headerRight -->
    -+  </div> <!-- End header -->
    -+<div id="body-content" xstyle="padding:12px;padding-right:18px;">
    -+<div id="doc-content" style="position:relative;">
    -+<div id="mainBodyFluid">
    -+<H2>
    -+Class android.support.v4.view.accessibility.<A HREF="../../../../reference/android/support/v4/view/accessibility/AccessibilityEventCompat.html" target="_top"><font size="+2"><code>AccessibilityEventCompat</code></font></A>
    -+</H2>
    -+<a NAME="constructors"></a>
    -+<a NAME="methods"></a>
    -+<p>
    -+<a NAME="Added"></a>
    -+<TABLE summary="Added Methods" WIDTH="100%">
    -+<TR>
    -+  <TH VALIGN="TOP" COLSPAN=2>Added Methods</FONT></TD>
    -+</TH>
    -+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    -+  <TD VALIGN="TOP" WIDTH="25%">
    -+  <A NAME="android.support.v4.view.accessibility.AccessibilityEventCompat.getAction_added(android.view.accessibility.AccessibilityEvent)"></A>
    -+  <nobr><code>int</code>&nbsp;<A HREF="../../../../reference/android/support/v4/view/accessibility/AccessibilityEventCompat.html#getAction(android.view.accessibility.AccessibilityEvent)" target="_top"><code>getAction</code></A>(<code>AccessibilityEvent</code>)</nobr>
    -+  </TD>
    -+  <TD>&nbsp;</TD>
    -+</TR>
    -+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    -+  <TD VALIGN="TOP" WIDTH="25%">
    -+  <A NAME="android.support.v4.view.accessibility.AccessibilityEventCompat.getMovementGranularity_added(android.view.accessibility.AccessibilityEvent)"></A>
    -+  <nobr><code>int</code>&nbsp;<A HREF="../../../../reference/android/support/v4/view/accessibility/AccessibilityEventCompat.html#getMovementGranularity(android.view.accessibility.AccessibilityEvent)" target="_top"><code>getMovementGranularity</code></A>(<code>AccessibilityEvent</code>)</nobr>
    -+  </TD>
    -+  <TD>&nbsp;</TD>
    -+</TR>
    -+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    -+  <TD VALIGN="TOP" WIDTH="25%">
    -+  <A NAME="android.support.v4.view.accessibility.AccessibilityEventCompat.setAction_added(android.view.accessibility.AccessibilityEvent, int)"></A>
    -+  <nobr><code>void</code>&nbsp;<A HREF="../../../../reference/android/support/v4/view/accessibility/AccessibilityEventCompat.html#setAction(android.view.accessibility.AccessibilityEvent, int)" target="_top"><code>setAction</code></A>(<code>AccessibilityEvent,</nobr> int<nobr><nobr></code>)</nobr>
    -+  </TD>
    -+  <TD>&nbsp;</TD>
    -+</TR>
    -+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    -+  <TD VALIGN="TOP" WIDTH="25%">
    -+  <A NAME="android.support.v4.view.accessibility.AccessibilityEventCompat.setMovementGranularity_added(android.view.accessibility.AccessibilityEvent, int)"></A>
    -+  <nobr><code>void</code>&nbsp;<A HREF="../../../../reference/android/support/v4/view/accessibility/AccessibilityEventCompat.html#setMovementGranularity(android.view.accessibility.AccessibilityEvent, int)" target="_top"><code>setMovementGranularity</code></A>(<code>AccessibilityEvent,</nobr> int<nobr><nobr></code>)</nobr>
    -+  </TD>
    -+  <TD>&nbsp;</TD>
    -+</TR>
    -+</TABLE>
    -+&nbsp;
    -+<a NAME="fields"></a>
    -+<p>
    -+<a NAME="Added"></a>
    -+<TABLE summary="Added Fields" WIDTH="100%">
    -+<TR>
    -+  <TH VALIGN="TOP" COLSPAN=2>Added Fields</FONT></TD>
    -+</TH>
    -+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    -+  <TD VALIGN="TOP" WIDTH="25%">
    -+  <A NAME="android.support.v4.view.accessibility.AccessibilityEventCompat.TYPE_ASSIST_READING_CONTEXT"></A>
    -+  <nobr><code>int</code>&nbsp;<A HREF="../../../../reference/android/support/v4/view/accessibility/AccessibilityEventCompat.html#TYPE_ASSIST_READING_CONTEXT" target="_top"><code>TYPE_ASSIST_READING_CONTEXT</code></A></nobr>
    -+  </TD>
    -+  <TD>&nbsp;</TD>
    -+</TR>
    -+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    -+  <TD VALIGN="TOP" WIDTH="25%">
    -+  <A NAME="android.support.v4.view.accessibility.AccessibilityEventCompat.TYPE_VIEW_CONTEXT_CLICKED"></A>
    -+  <nobr><code>int</code>&nbsp;<A HREF="../../../../reference/android/support/v4/view/accessibility/AccessibilityEventCompat.html#TYPE_VIEW_CONTEXT_CLICKED" target="_top"><code>TYPE_VIEW_CONTEXT_CLICKED</code></A></nobr>
    -+  </TD>
    -+  <TD>&nbsp;</TD>
    -+</TR>
    -+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    -+  <TD VALIGN="TOP" WIDTH="25%">
    -+  <A NAME="android.support.v4.view.accessibility.AccessibilityEventCompat.TYPE_WINDOWS_CHANGED"></A>
    -+  <nobr><code>int</code>&nbsp;<A HREF="../../../../reference/android/support/v4/view/accessibility/AccessibilityEventCompat.html#TYPE_WINDOWS_CHANGED" target="_top"><code>TYPE_WINDOWS_CHANGED</code></A></nobr>
    -+  </TD>
    -+  <TD>&nbsp;</TD>
    -+</TR>
    -+</TABLE>
    -+&nbsp;
    -+      </div>	
    -+      <div id="footer">
    -+        <div id="copyright">
    -+        Except as noted, this content is licensed under 
    -+        <a href="http://creativecommons.org/licenses/by/2.5/"> Creative Commons Attribution 2.5</a>.
    -+        For details and restrictions, see the <a href="/license.html">Content License</a>.
    -+        </div>
    -+      <div id="footerlinks">
    -+      <p>
    -+        <a href="http://www.android.com/terms.html">Site Terms of Service</a> -
    -+        <a href="http://www.android.com/privacy.html">Privacy Policy</a> -
    -+        <a href="http://www.android.com/branding.html">Brand Guidelines</a>
    -+      </p>
    -+    </div>
    -+    </div> <!-- end footer -->
    -+    </div><!-- end doc-content -->
    -+    </div> <!-- end body-content --> 
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    -+</script>
    -+<script type="text/javascript">
    -+  try {
    -+    var pageTracker = _gat._getTracker("UA-5831155-1");
    -+    pageTracker._setAllowAnchor(true);
    -+    pageTracker._initData();
    -+    pageTracker._trackPageview();
    -+  } catch(e) {}
    -+</script>
    -+</BODY>
    -+</HTML>
    -diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.view.accessibility.AccessibilityManagerCompat.AccessibilityStateChangeListenerCompat.html b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.view.accessibility.AccessibilityManagerCompat.AccessibilityStateChangeListenerCompat.html
    -new file mode 100644
    -index 0000000..923ec80
    ---- /dev/null
    -+++ b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.view.accessibility.AccessibilityManagerCompat.AccessibilityStateChangeListenerCompat.html
    -@@ -0,0 +1,124 @@
    -+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
    -+<HTML style="overflow:auto;">
    -+<HEAD>
    -+<meta name="generator" content="JDiff v1.1.0">
    -+<!-- Generated by the JDiff Javadoc doclet -->
    -+<!-- (http://www.jdiff.org) -->
    -+<meta name="description" content="JDiff is a Javadoc doclet which generates an HTML report of all the packages, classes, constructors, methods, and fields which have been removed, added or changed in any way, including their documentation, when two APIs are compared.">
    -+<meta name="keywords" content="diff, jdiff, javadiff, java diff, java difference, API difference, difference between two APIs, API diff, Javadoc, doclet">
    -+<TITLE>
    -+android.support.v4.view.accessibility.AccessibilityManagerCompat.AccessibilityStateChangeListenerCompat
    -+</TITLE>
    -+<link href="../../../../assets/android-developer-docs.css" rel="stylesheet" type="text/css" />
    -+<link href="../stylesheet-jdiff.css" rel="stylesheet" type="text/css" />
    -+<noscript>
    -+<style type="text/css">
    -+body{overflow:auto;}
    -+#body-content{position:relative; top:0;}
    -+#doc-content{overflow:visible;border-left:3px solid #666;}
    -+#side-nav{padding:0;}
    -+#side-nav .toggle-list ul {display:block;}
    -+#resize-packages-nav{border-bottom:3px solid #666;}
    -+</style>
    -+</noscript>
    -+<style type="text/css">
    -+</style>
    -+</HEAD>
    -+<BODY>
    -+<!-- Start of nav bar -->
    -+<a name="top"></a>
    -+<div id="header" style="margin-bottom:0;padding-bottom:0;">
    -+<div id="headerLeft">
    -+<a href="../../../../index.html" tabindex="-1" target="_top"><img src="../../../../assets/images/bg_logo.png" alt="Android Developers" /></a>
    -+</div>
    -+  <div id="headerRight">
    -+  <div id="headerLinks">
    -+<!-- <img src="/assets/images/icon_world.jpg" alt="" /> -->
    -+<span class="text">
    -+<!-- &nbsp;<a href="#">English</a> | -->
    -+<nobr><a href="http://developer.android.com" target="_top">Android Developers</a> | <a href="http://www.android.com" target="_top">Android.com</a></nobr>
    -+</span>
    -+</div>
    -+  <div class="and-diff-id" style="margin-top:6px;margin-right:8px;">
    -+    <table class="diffspectable">
    -+      <tr>
    -+        <td colspan="2" class="diffspechead">API Diff Specification</td>
    -+      </tr>
    -+      <tr>
    -+        <td class="diffspec" style="padding-top:.25em">To Level:</td>
    -+        <td class="diffvaluenew" style="padding-top:.25em">24.2.0</td>
    -+      </tr>
    -+      <tr>
    -+        <td class="diffspec">From Level:</td>
    -+        <td class="diffvalueold">24.1.0</td>
    -+      </tr>
    -+      <tr>
    -+        <td class="diffspec">Generated</td>
    -+        <td class="diffvalue">2016.08.16 14:03</td>
    -+      </tr>
    -+    </table>
    -+    </div><!-- End and-diff-id -->
    -+  <div class="and-diff-id" style="margin-right:8px;">
    -+    <table class="diffspectable">
    -+      <tr>
    -+        <td class="diffspec" colspan="2"><a href="jdiff_statistics.html">Statistics</a>
    -+      </tr>
    -+    </table>
    -+  </div> <!-- End and-diff-id -->
    -+  </div> <!-- End headerRight -->
    -+  </div> <!-- End header -->
    -+<div id="body-content" xstyle="padding:12px;padding-right:18px;">
    -+<div id="doc-content" style="position:relative;">
    -+<div id="mainBodyFluid">
    -+<H2>
    -+Class android.support.v4.view.accessibility.<A HREF="../../../../reference/android/support/v4/view/accessibility/AccessibilityManagerCompat.AccessibilityStateChangeListenerCompat.html" target="_top"><font size="+2"><code>AccessibilityManagerCompat.AccessibilityStateChangeListenerCompat</code></font></A>
    -+</H2>
    -+<p><font xsize="+1">Added interface <code>android.support.v4.view.accessibility.AccessibilityManagerCompat.AccessibilityStateChangeListener</code>.<br></font>
    -+<p><b>Now deprecated</b>.<br>
    -+<a NAME="constructors"></a>
    -+<a NAME="methods"></a>
    -+<p>
    -+<a NAME="Removed"></a>
    -+<TABLE summary="Removed Methods" WIDTH="100%">
    -+<TR>
    -+  <TH VALIGN="TOP" COLSPAN=2>Removed Methods</FONT></TD>
    -+</TH>
    -+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    -+  <TD VALIGN="TOP" WIDTH="25%">
    -+  <A NAME="android.support.v4.view.accessibility.AccessibilityManagerCompat.AccessibilityStateChangeListenerCompat.onAccessibilityStateChanged_removed(boolean)"></A>
    -+  <nobr><code>void</code>&nbsp;onAccessibilityStateChanged(<code>boolean</code>)</nobr>
    -+  </TD>
    -+  <TD>&nbsp;</TD>
    -+</TR>
    -+</TABLE>
    -+&nbsp;
    -+<a NAME="fields"></a>
    -+      </div>	
    -+      <div id="footer">
    -+        <div id="copyright">
    -+        Except as noted, this content is licensed under 
    -+        <a href="http://creativecommons.org/licenses/by/2.5/"> Creative Commons Attribution 2.5</a>.
    -+        For details and restrictions, see the <a href="/license.html">Content License</a>.
    -+        </div>
    -+      <div id="footerlinks">
    -+      <p>
    -+        <a href="http://www.android.com/terms.html">Site Terms of Service</a> -
    -+        <a href="http://www.android.com/privacy.html">Privacy Policy</a> -
    -+        <a href="http://www.android.com/branding.html">Brand Guidelines</a>
    -+      </p>
    -+    </div>
    -+    </div> <!-- end footer -->
    -+    </div><!-- end doc-content -->
    -+    </div> <!-- end body-content --> 
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    -+</script>
    -+<script type="text/javascript">
    -+  try {
    -+    var pageTracker = _gat._getTracker("UA-5831155-1");
    -+    pageTracker._setAllowAnchor(true);
    -+    pageTracker._initData();
    -+    pageTracker._trackPageview();
    -+  } catch(e) {}
    -+</script>
    -+</BODY>
    -+</HTML>
    -diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.view.accessibility.AccessibilityManagerCompat.html b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.view.accessibility.AccessibilityManagerCompat.html
    -new file mode 100644
    -index 0000000..defa406
    ---- /dev/null
    -+++ b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.view.accessibility.AccessibilityManagerCompat.html
    -@@ -0,0 +1,157 @@
    -+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
    -+<HTML style="overflow:auto;">
    -+<HEAD>
    -+<meta name="generator" content="JDiff v1.1.0">
    -+<!-- Generated by the JDiff Javadoc doclet -->
    -+<!-- (http://www.jdiff.org) -->
    -+<meta name="description" content="JDiff is a Javadoc doclet which generates an HTML report of all the packages, classes, constructors, methods, and fields which have been removed, added or changed in any way, including their documentation, when two APIs are compared.">
    -+<meta name="keywords" content="diff, jdiff, javadiff, java diff, java difference, API difference, difference between two APIs, API diff, Javadoc, doclet">
    -+<TITLE>
    -+android.support.v4.view.accessibility.AccessibilityManagerCompat
    -+</TITLE>
    -+<link href="../../../../assets/android-developer-docs.css" rel="stylesheet" type="text/css" />
    -+<link href="../stylesheet-jdiff.css" rel="stylesheet" type="text/css" />
    -+<noscript>
    -+<style type="text/css">
    -+body{overflow:auto;}
    -+#body-content{position:relative; top:0;}
    -+#doc-content{overflow:visible;border-left:3px solid #666;}
    -+#side-nav{padding:0;}
    -+#side-nav .toggle-list ul {display:block;}
    -+#resize-packages-nav{border-bottom:3px solid #666;}
    -+</style>
    -+</noscript>
    -+<style type="text/css">
    -+</style>
    -+</HEAD>
    -+<BODY>
    -+<!-- Start of nav bar -->
    -+<a name="top"></a>
    -+<div id="header" style="margin-bottom:0;padding-bottom:0;">
    -+<div id="headerLeft">
    -+<a href="../../../../index.html" tabindex="-1" target="_top"><img src="../../../../assets/images/bg_logo.png" alt="Android Developers" /></a>
    -+</div>
    -+  <div id="headerRight">
    -+  <div id="headerLinks">
    -+<!-- <img src="/assets/images/icon_world.jpg" alt="" /> -->
    -+<span class="text">
    -+<!-- &nbsp;<a href="#">English</a> | -->
    -+<nobr><a href="http://developer.android.com" target="_top">Android Developers</a> | <a href="http://www.android.com" target="_top">Android.com</a></nobr>
    -+</span>
    -+</div>
    -+  <div class="and-diff-id" style="margin-top:6px;margin-right:8px;">
    -+    <table class="diffspectable">
    -+      <tr>
    -+        <td colspan="2" class="diffspechead">API Diff Specification</td>
    -+      </tr>
    -+      <tr>
    -+        <td class="diffspec" style="padding-top:.25em">To Level:</td>
    -+        <td class="diffvaluenew" style="padding-top:.25em">24.2.0</td>
    -+      </tr>
    -+      <tr>
    -+        <td class="diffspec">From Level:</td>
    -+        <td class="diffvalueold">24.1.0</td>
    -+      </tr>
    -+      <tr>
    -+        <td class="diffspec">Generated</td>
    -+        <td class="diffvalue">2016.08.16 14:03</td>
    -+      </tr>
    -+    </table>
    -+    </div><!-- End and-diff-id -->
    -+  <div class="and-diff-id" style="margin-right:8px;">
    -+    <table class="diffspectable">
    -+      <tr>
    -+        <td class="diffspec" colspan="2"><a href="jdiff_statistics.html">Statistics</a>
    -+      </tr>
    -+    </table>
    -+  </div> <!-- End and-diff-id -->
    -+  </div> <!-- End headerRight -->
    -+  </div> <!-- End header -->
    -+<div id="body-content" xstyle="padding:12px;padding-right:18px;">
    -+<div id="doc-content" style="position:relative;">
    -+<div id="mainBodyFluid">
    -+<H2>
    -+Class android.support.v4.view.accessibility.<A HREF="../../../../reference/android/support/v4/view/accessibility/AccessibilityManagerCompat.html" target="_top"><font size="+2"><code>AccessibilityManagerCompat</code></font></A>
    -+</H2>
    -+<a NAME="constructors"></a>
    -+<a NAME="methods"></a>
    -+<p>
    -+<a NAME="Added"></a>
    -+<TABLE summary="Added Methods" WIDTH="100%">
    -+<TR>
    -+  <TH VALIGN="TOP" COLSPAN=2>Added Methods</FONT></TD>
    -+</TH>
    -+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    -+  <TD VALIGN="TOP" WIDTH="25%">
    -+  <A NAME="android.support.v4.view.accessibility.AccessibilityManagerCompat.addTouchExplorationStateChangeListener_added(android.view.accessibility.AccessibilityManager, android.support.v4.view.accessibility.AccessibilityManagerCompat.TouchExplorationStateChangeListener)"></A>
    -+  <nobr><code>boolean</code>&nbsp;<A HREF="../../../../reference/android/support/v4/view/accessibility/AccessibilityManagerCompat.html#addTouchExplorationStateChangeListener(android.view.accessibility.AccessibilityManager, android.support.v4.view.accessibility.AccessibilityManagerCompat.TouchExplorationStateChangeListener)" target="_top"><code>addTouchExplorationStateChangeListener</code></A>(<code>AccessibilityManager,</nobr> TouchExplorationStateChangeListener<nobr><nobr></code>)</nobr>
    -+  </TD>
    -+  <TD>&nbsp;</TD>
    -+</TR>
    -+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    -+  <TD VALIGN="TOP" WIDTH="25%">
    -+  <A NAME="android.support.v4.view.accessibility.AccessibilityManagerCompat.removeTouchExplorationStateChangeListener_added(android.view.accessibility.AccessibilityManager, android.support.v4.view.accessibility.AccessibilityManagerCompat.TouchExplorationStateChangeListener)"></A>
    -+  <nobr><code>boolean</code>&nbsp;<A HREF="../../../../reference/android/support/v4/view/accessibility/AccessibilityManagerCompat.html#removeTouchExplorationStateChangeListener(android.view.accessibility.AccessibilityManager, android.support.v4.view.accessibility.AccessibilityManagerCompat.TouchExplorationStateChangeListener)" target="_top"><code>removeTouchExplorationStateChangeListener</code></A>(<code>AccessibilityManager,</nobr> TouchExplorationStateChangeListener<nobr><nobr></code>)</nobr>
    -+  </TD>
    -+  <TD>&nbsp;</TD>
    -+</TR>
    -+</TABLE>
    -+&nbsp;
    -+<p>
    -+<a NAME="Changed"></a>
    -+<TABLE summary="Changed Methods" WIDTH="100%">
    -+<TR>
    -+  <TH VALIGN="TOP" COLSPAN=3>Changed Methods</FONT></TD>
    -+</TH>
    -+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    -+  <TD VALIGN="TOP" WIDTH="25%">
    -+  <A NAME="android.support.v4.view.accessibility.AccessibilityManagerCompat.addAccessibilityStateChangeListener_changed(android.view.accessibility.AccessibilityManager, android.support.v4.view.accessibility.AccessibilityManagerCompat.AccessibilityStateChangeListener)"></A>
    -+  <nobr><code>boolean</code>&nbsp;<A HREF="../../../../reference/android/support/v4/view/accessibility/AccessibilityManagerCompat.html#addAccessibilityStateChangeListener(android.view.accessibility.AccessibilityManager, android.support.v4.view.accessibility.AccessibilityManagerCompat.AccessibilityStateChangeListener)" target="_top"><code>addAccessibilityStateChangeListener</code></A>(<code>AccessibilityManager,</nobr> AccessibilityStateChangeListener<nobr><nobr></code>)  </nobr>
    -+  </TD>
    -+  <TD VALIGN="TOP" WIDTH="30%">
    -+Change in signature from (<code>AccessibilityManager, AccessibilityStateChangeListenerCompat</code>) to (<code>AccessibilityManager, AccessibilityStateChangeListener</code>).<br>
    -+  </TD>
    -+  <TD>&nbsp;</TD>
    -+</TR>
    -+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    -+  <TD VALIGN="TOP" WIDTH="25%">
    -+  <A NAME="android.support.v4.view.accessibility.AccessibilityManagerCompat.removeAccessibilityStateChangeListener_changed(android.view.accessibility.AccessibilityManager, android.support.v4.view.accessibility.AccessibilityManagerCompat.AccessibilityStateChangeListener)"></A>
    -+  <nobr><code>boolean</code>&nbsp;<A HREF="../../../../reference/android/support/v4/view/accessibility/AccessibilityManagerCompat.html#removeAccessibilityStateChangeListener(android.view.accessibility.AccessibilityManager, android.support.v4.view.accessibility.AccessibilityManagerCompat.AccessibilityStateChangeListener)" target="_top"><code>removeAccessibilityStateChangeListener</code></A>(<code>AccessibilityManager,</nobr> AccessibilityStateChangeListener<nobr><nobr></code>)  </nobr>
    -+  </TD>
    -+  <TD VALIGN="TOP" WIDTH="30%">
    -+Change in signature from (<code>AccessibilityManager, AccessibilityStateChangeListenerCompat</code>) to (<code>AccessibilityManager, AccessibilityStateChangeListener</code>).<br>
    -+  </TD>
    -+  <TD>&nbsp;</TD>
    -+</TR>
    -+</TABLE>
    -+&nbsp;
    -+<a NAME="fields"></a>
    -+      </div>	
    -+      <div id="footer">
    -+        <div id="copyright">
    -+        Except as noted, this content is licensed under 
    -+        <a href="http://creativecommons.org/licenses/by/2.5/"> Creative Commons Attribution 2.5</a>.
    -+        For details and restrictions, see the <a href="/license.html">Content License</a>.
    -+        </div>
    -+      <div id="footerlinks">
    -+      <p>
    -+        <a href="http://www.android.com/terms.html">Site Terms of Service</a> -
    -+        <a href="http://www.android.com/privacy.html">Privacy Policy</a> -
    -+        <a href="http://www.android.com/branding.html">Brand Guidelines</a>
    -+      </p>
    -+    </div>
    -+    </div> <!-- end footer -->
    -+    </div><!-- end doc-content -->
    -+    </div> <!-- end body-content --> 
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    -+</script>
    -+<script type="text/javascript">
    -+  try {
    -+    var pageTracker = _gat._getTracker("UA-5831155-1");
    -+    pageTracker._setAllowAnchor(true);
    -+    pageTracker._initData();
    -+    pageTracker._trackPageview();
    -+  } catch(e) {}
    -+</script>
    -+</BODY>
    -+</HTML>
    -diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat.html b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat.html
    -new file mode 100644
    -index 0000000..d6f719e
    ---- /dev/null
    -+++ b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat.html
    -@@ -0,0 +1,171 @@
    -+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
    -+<HTML style="overflow:auto;">
    -+<HEAD>
    -+<meta name="generator" content="JDiff v1.1.0">
    -+<!-- Generated by the JDiff Javadoc doclet -->
    -+<!-- (http://www.jdiff.org) -->
    -+<meta name="description" content="JDiff is a Javadoc doclet which generates an HTML report of all the packages, classes, constructors, methods, and fields which have been removed, added or changed in any way, including their documentation, when two APIs are compared.">
    -+<meta name="keywords" content="diff, jdiff, javadiff, java diff, java difference, API difference, difference between two APIs, API diff, Javadoc, doclet">
    -+<TITLE>
    -+android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat
    -+</TITLE>
    -+<link href="../../../../assets/android-developer-docs.css" rel="stylesheet" type="text/css" />
    -+<link href="../stylesheet-jdiff.css" rel="stylesheet" type="text/css" />
    -+<noscript>
    -+<style type="text/css">
    -+body{overflow:auto;}
    -+#body-content{position:relative; top:0;}
    -+#doc-content{overflow:visible;border-left:3px solid #666;}
    -+#side-nav{padding:0;}
    -+#side-nav .toggle-list ul {display:block;}
    -+#resize-packages-nav{border-bottom:3px solid #666;}
    -+</style>
    -+</noscript>
    -+<style type="text/css">
    -+</style>
    -+</HEAD>
    -+<BODY>
    -+<!-- Start of nav bar -->
    -+<a name="top"></a>
    -+<div id="header" style="margin-bottom:0;padding-bottom:0;">
    -+<div id="headerLeft">
    -+<a href="../../../../index.html" tabindex="-1" target="_top"><img src="../../../../assets/images/bg_logo.png" alt="Android Developers" /></a>
    -+</div>
    -+  <div id="headerRight">
    -+  <div id="headerLinks">
    -+<!-- <img src="/assets/images/icon_world.jpg" alt="" /> -->
    -+<span class="text">
    -+<!-- &nbsp;<a href="#">English</a> | -->
    -+<nobr><a href="http://developer.android.com" target="_top">Android Developers</a> | <a href="http://www.android.com" target="_top">Android.com</a></nobr>
    -+</span>
    -+</div>
    -+  <div class="and-diff-id" style="margin-top:6px;margin-right:8px;">
    -+    <table class="diffspectable">
    -+      <tr>
    -+        <td colspan="2" class="diffspechead">API Diff Specification</td>
    -+      </tr>
    -+      <tr>
    -+        <td class="diffspec" style="padding-top:.25em">To Level:</td>
    -+        <td class="diffvaluenew" style="padding-top:.25em">24.2.0</td>
    -+      </tr>
    -+      <tr>
    -+        <td class="diffspec">From Level:</td>
    -+        <td class="diffvalueold">24.1.0</td>
    -+      </tr>
    -+      <tr>
    -+        <td class="diffspec">Generated</td>
    -+        <td class="diffvalue">2016.08.16 14:03</td>
    -+      </tr>
    -+    </table>
    -+    </div><!-- End and-diff-id -->
    -+  <div class="and-diff-id" style="margin-right:8px;">
    -+    <table class="diffspectable">
    -+      <tr>
    -+        <td class="diffspec" colspan="2"><a href="jdiff_statistics.html">Statistics</a>
    -+      </tr>
    -+    </table>
    -+  </div> <!-- End and-diff-id -->
    -+  </div> <!-- End headerRight -->
    -+  </div> <!-- End header -->
    -+<div id="body-content" xstyle="padding:12px;padding-right:18px;">
    -+<div id="doc-content" style="position:relative;">
    -+<div id="mainBodyFluid">
    -+<H2>
    -+Class android.support.v4.view.accessibility.<A HREF="../../../../reference/android/support/v4/view/accessibility/AccessibilityNodeInfoCompat.AccessibilityActionCompat.html" target="_top"><font size="+2"><code>AccessibilityNodeInfoCompat.AccessibilityActionCompat</code></font></A>
    -+</H2>
    -+<a NAME="constructors"></a>
    -+<a NAME="methods"></a>
    -+<a NAME="fields"></a>
    -+<p>
    -+<a NAME="Added"></a>
    -+<TABLE summary="Added Fields" WIDTH="100%">
    -+<TR>
    -+  <TH VALIGN="TOP" COLSPAN=2>Added Fields</FONT></TD>
    -+</TH>
    -+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    -+  <TD VALIGN="TOP" WIDTH="25%">
    -+  <A NAME="android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat.ACTION_CONTEXT_CLICK"></A>
    -+  <nobr><code>AccessibilityActionCompat</code>&nbsp;<A HREF="../../../../reference/android/support/v4/view/accessibility/AccessibilityNodeInfoCompat.AccessibilityActionCompat.html#ACTION_CONTEXT_CLICK" target="_top"><code>ACTION_CONTEXT_CLICK</code></A></nobr>
    -+  </TD>
    -+  <TD>&nbsp;</TD>
    -+</TR>
    -+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    -+  <TD VALIGN="TOP" WIDTH="25%">
    -+  <A NAME="android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat.ACTION_SCROLL_DOWN"></A>
    -+  <nobr><code>AccessibilityActionCompat</code>&nbsp;<A HREF="../../../../reference/android/support/v4/view/accessibility/AccessibilityNodeInfoCompat.AccessibilityActionCompat.html#ACTION_SCROLL_DOWN" target="_top"><code>ACTION_SCROLL_DOWN</code></A></nobr>
    -+  </TD>
    -+  <TD>&nbsp;</TD>
    -+</TR>
    -+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    -+  <TD VALIGN="TOP" WIDTH="25%">
    -+  <A NAME="android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat.ACTION_SCROLL_LEFT"></A>
    -+  <nobr><code>AccessibilityActionCompat</code>&nbsp;<A HREF="../../../../reference/android/support/v4/view/accessibility/AccessibilityNodeInfoCompat.AccessibilityActionCompat.html#ACTION_SCROLL_LEFT" target="_top"><code>ACTION_SCROLL_LEFT</code></A></nobr>
    -+  </TD>
    -+  <TD>&nbsp;</TD>
    -+</TR>
    -+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    -+  <TD VALIGN="TOP" WIDTH="25%">
    -+  <A NAME="android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat.ACTION_SCROLL_RIGHT"></A>
    -+  <nobr><code>AccessibilityActionCompat</code>&nbsp;<A HREF="../../../../reference/android/support/v4/view/accessibility/AccessibilityNodeInfoCompat.AccessibilityActionCompat.html#ACTION_SCROLL_RIGHT" target="_top"><code>ACTION_SCROLL_RIGHT</code></A></nobr>
    -+  </TD>
    -+  <TD>&nbsp;</TD>
    -+</TR>
    -+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    -+  <TD VALIGN="TOP" WIDTH="25%">
    -+  <A NAME="android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat.ACTION_SCROLL_TO_POSITION"></A>
    -+  <nobr><code>AccessibilityActionCompat</code>&nbsp;<A HREF="../../../../reference/android/support/v4/view/accessibility/AccessibilityNodeInfoCompat.AccessibilityActionCompat.html#ACTION_SCROLL_TO_POSITION" target="_top"><code>ACTION_SCROLL_TO_POSITION</code></A></nobr>
    -+  </TD>
    -+  <TD>&nbsp;</TD>
    -+</TR>
    -+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    -+  <TD VALIGN="TOP" WIDTH="25%">
    -+  <A NAME="android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat.ACTION_SCROLL_UP"></A>
    -+  <nobr><code>AccessibilityActionCompat</code>&nbsp;<A HREF="../../../../reference/android/support/v4/view/accessibility/AccessibilityNodeInfoCompat.AccessibilityActionCompat.html#ACTION_SCROLL_UP" target="_top"><code>ACTION_SCROLL_UP</code></A></nobr>
    -+  </TD>
    -+  <TD>&nbsp;</TD>
    -+</TR>
    -+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    -+  <TD VALIGN="TOP" WIDTH="25%">
    -+  <A NAME="android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat.ACTION_SET_PROGRESS"></A>
    -+  <nobr><code>AccessibilityActionCompat</code>&nbsp;<A HREF="../../../../reference/android/support/v4/view/accessibility/AccessibilityNodeInfoCompat.AccessibilityActionCompat.html#ACTION_SET_PROGRESS" target="_top"><code>ACTION_SET_PROGRESS</code></A></nobr>
    -+  </TD>
    -+  <TD>&nbsp;</TD>
    -+</TR>
    -+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    -+  <TD VALIGN="TOP" WIDTH="25%">
    -+  <A NAME="android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat.ACTION_SHOW_ON_SCREEN"></A>
    -+  <nobr><code>AccessibilityActionCompat</code>&nbsp;<A HREF="../../../../reference/android/support/v4/view/accessibility/AccessibilityNodeInfoCompat.AccessibilityActionCompat.html#ACTION_SHOW_ON_SCREEN" target="_top"><code>ACTION_SHOW_ON_SCREEN</code></A></nobr>
    -+  </TD>
    -+  <TD>&nbsp;</TD>
    -+</TR>
    -+</TABLE>
    -+&nbsp;
    -+      </div>	
    -+      <div id="footer">
    -+        <div id="copyright">
    -+        Except as noted, this content is licensed under 
    -+        <a href="http://creativecommons.org/licenses/by/2.5/"> Creative Commons Attribution 2.5</a>.
    -+        For details and restrictions, see the <a href="/license.html">Content License</a>.
    -+        </div>
    -+      <div id="footerlinks">
    -+      <p>
    -+        <a href="http://www.android.com/terms.html">Site Terms of Service</a> -
    -+        <a href="http://www.android.com/privacy.html">Privacy Policy</a> -
    -+        <a href="http://www.android.com/branding.html">Brand Guidelines</a>
    -+      </p>
    -+    </div>
    -+    </div> <!-- end footer -->
    -+    </div><!-- end doc-content -->
    -+    </div> <!-- end body-content --> 
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    -+</script>
    -+<script type="text/javascript">
    -+  try {
    -+    var pageTracker = _gat._getTracker("UA-5831155-1");
    -+    pageTracker._setAllowAnchor(true);
    -+    pageTracker._initData();
    -+    pageTracker._trackPageview();
    -+  } catch(e) {}
    -+</script>
    -+</BODY>
    -+</HTML>
    -diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.CollectionInfoCompat.html b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.CollectionInfoCompat.html
    -new file mode 100644
    -index 0000000..d087e4a
    ---- /dev/null
    -+++ b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.CollectionInfoCompat.html
    -@@ -0,0 +1,129 @@
    -+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
    -+<HTML style="overflow:auto;">
    -+<HEAD>
    -+<meta name="generator" content="JDiff v1.1.0">
    -+<!-- Generated by the JDiff Javadoc doclet -->
    -+<!-- (http://www.jdiff.org) -->
    -+<meta name="description" content="JDiff is a Javadoc doclet which generates an HTML report of all the packages, classes, constructors, methods, and fields which have been removed, added or changed in any way, including their documentation, when two APIs are compared.">
    -+<meta name="keywords" content="diff, jdiff, javadiff, java diff, java difference, API difference, difference between two APIs, API diff, Javadoc, doclet">
    -+<TITLE>
    -+android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.CollectionInfoCompat
    -+</TITLE>
    -+<link href="../../../../assets/android-developer-docs.css" rel="stylesheet" type="text/css" />
    -+<link href="../stylesheet-jdiff.css" rel="stylesheet" type="text/css" />
    -+<noscript>
    -+<style type="text/css">
    -+body{overflow:auto;}
    -+#body-content{position:relative; top:0;}
    -+#doc-content{overflow:visible;border-left:3px solid #666;}
    -+#side-nav{padding:0;}
    -+#side-nav .toggle-list ul {display:block;}
    -+#resize-packages-nav{border-bottom:3px solid #666;}
    -+</style>
    -+</noscript>
    -+<style type="text/css">
    -+</style>
    -+</HEAD>
    -+<BODY>
    -+<!-- Start of nav bar -->
    -+<a name="top"></a>
    -+<div id="header" style="margin-bottom:0;padding-bottom:0;">
    -+<div id="headerLeft">
    -+<a href="../../../../index.html" tabindex="-1" target="_top"><img src="../../../../assets/images/bg_logo.png" alt="Android Developers" /></a>
    -+</div>
    -+  <div id="headerRight">
    -+  <div id="headerLinks">
    -+<!-- <img src="/assets/images/icon_world.jpg" alt="" /> -->
    -+<span class="text">
    -+<!-- &nbsp;<a href="#">English</a> | -->
    -+<nobr><a href="http://developer.android.com" target="_top">Android Developers</a> | <a href="http://www.android.com" target="_top">Android.com</a></nobr>
    -+</span>
    -+</div>
    -+  <div class="and-diff-id" style="margin-top:6px;margin-right:8px;">
    -+    <table class="diffspectable">
    -+      <tr>
    -+        <td colspan="2" class="diffspechead">API Diff Specification</td>
    -+      </tr>
    -+      <tr>
    -+        <td class="diffspec" style="padding-top:.25em">To Level:</td>
    -+        <td class="diffvaluenew" style="padding-top:.25em">24.2.0</td>
    -+      </tr>
    -+      <tr>
    -+        <td class="diffspec">From Level:</td>
    -+        <td class="diffvalueold">24.1.0</td>
    -+      </tr>
    -+      <tr>
    -+        <td class="diffspec">Generated</td>
    -+        <td class="diffvalue">2016.08.16 14:03</td>
    -+      </tr>
    -+    </table>
    -+    </div><!-- End and-diff-id -->
    -+  <div class="and-diff-id" style="margin-right:8px;">
    -+    <table class="diffspectable">
    -+      <tr>
    -+        <td class="diffspec" colspan="2"><a href="jdiff_statistics.html">Statistics</a>
    -+      </tr>
    -+    </table>
    -+  </div> <!-- End and-diff-id -->
    -+  </div> <!-- End headerRight -->
    -+  </div> <!-- End header -->
    -+<div id="body-content" xstyle="padding:12px;padding-right:18px;">
    -+<div id="doc-content" style="position:relative;">
    -+<div id="mainBodyFluid">
    -+<H2>
    -+Class android.support.v4.view.accessibility.<A HREF="../../../../reference/android/support/v4/view/accessibility/AccessibilityNodeInfoCompat.CollectionInfoCompat.html" target="_top"><font size="+2"><code>AccessibilityNodeInfoCompat.CollectionInfoCompat</code></font></A>
    -+</H2>
    -+<a NAME="constructors"></a>
    -+<a NAME="methods"></a>
    -+<p>
    -+<a NAME="Added"></a>
    -+<TABLE summary="Added Methods" WIDTH="100%">
    -+<TR>
    -+  <TH VALIGN="TOP" COLSPAN=2>Added Methods</FONT></TD>
    -+</TH>
    -+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    -+  <TD VALIGN="TOP" WIDTH="25%">
    -+  <A NAME="android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.CollectionInfoCompat.getSelectionMode_added()"></A>
    -+  <nobr><code>int</code>&nbsp;<A HREF="../../../../reference/android/support/v4/view/accessibility/AccessibilityNodeInfoCompat.CollectionInfoCompat.html#getSelectionMode()" target="_top"><code>getSelectionMode</code></A>()</nobr>
    -+  </TD>
    -+  <TD>&nbsp;</TD>
    -+</TR>
    -+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    -+  <TD VALIGN="TOP" WIDTH="25%">
    -+  <A NAME="android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.CollectionInfoCompat.obtain_added(int, int, boolean)"></A>
    -+  <nobr><code>CollectionInfoCompat</code>&nbsp;<A HREF="../../../../reference/android/support/v4/view/accessibility/AccessibilityNodeInfoCompat.CollectionInfoCompat.html#obtain(int, int, boolean)" target="_top"><code>obtain</code></A>(<code>int,</nobr> int<nobr>,</nobr> boolean<nobr><nobr></code>)</nobr>
    -+  </TD>
    -+  <TD>&nbsp;</TD>
    -+</TR>
    -+</TABLE>
    -+&nbsp;
    -+<a NAME="fields"></a>
    -+      </div>	
    -+      <div id="footer">
    -+        <div id="copyright">
    -+        Except as noted, this content is licensed under 
    -+        <a href="http://creativecommons.org/licenses/by/2.5/"> Creative Commons Attribution 2.5</a>.
    -+        For details and restrictions, see the <a href="/license.html">Content License</a>.
    -+        </div>
    -+      <div id="footerlinks">
    -+      <p>
    -+        <a href="http://www.android.com/terms.html">Site Terms of Service</a> -
    -+        <a href="http://www.android.com/privacy.html">Privacy Policy</a> -
    -+        <a href="http://www.android.com/branding.html">Brand Guidelines</a>
    -+      </p>
    -+    </div>
    -+    </div> <!-- end footer -->
    -+    </div><!-- end doc-content -->
    -+    </div> <!-- end body-content --> 
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    -+</script>
    -+<script type="text/javascript">
    -+  try {
    -+    var pageTracker = _gat._getTracker("UA-5831155-1");
    -+    pageTracker._setAllowAnchor(true);
    -+    pageTracker._initData();
    -+    pageTracker._trackPageview();
    -+  } catch(e) {}
    -+</script>
    -+</BODY>
    -+</HTML>
    -diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.CollectionItemInfoCompat.html b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.CollectionItemInfoCompat.html
    -new file mode 100644
    -index 0000000..84fc73b
    ---- /dev/null
    -+++ b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.CollectionItemInfoCompat.html
    -@@ -0,0 +1,122 @@
    -+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
    -+<HTML style="overflow:auto;">
    -+<HEAD>
    -+<meta name="generator" content="JDiff v1.1.0">
    -+<!-- Generated by the JDiff Javadoc doclet -->
    -+<!-- (http://www.jdiff.org) -->
    -+<meta name="description" content="JDiff is a Javadoc doclet which generates an HTML report of all the packages, classes, constructors, methods, and fields which have been removed, added or changed in any way, including their documentation, when two APIs are compared.">
    -+<meta name="keywords" content="diff, jdiff, javadiff, java diff, java difference, API difference, difference between two APIs, API diff, Javadoc, doclet">
    -+<TITLE>
    -+android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.CollectionItemInfoCompat
    -+</TITLE>
    -+<link href="../../../../assets/android-developer-docs.css" rel="stylesheet" type="text/css" />
    -+<link href="../stylesheet-jdiff.css" rel="stylesheet" type="text/css" />
    -+<noscript>
    -+<style type="text/css">
    -+body{overflow:auto;}
    -+#body-content{position:relative; top:0;}
    -+#doc-content{overflow:visible;border-left:3px solid #666;}
    -+#side-nav{padding:0;}
    -+#side-nav .toggle-list ul {display:block;}
    -+#resize-packages-nav{border-bottom:3px solid #666;}
    -+</style>
    -+</noscript>
    -+<style type="text/css">
    -+</style>
    -+</HEAD>
    -+<BODY>
    -+<!-- Start of nav bar -->
    -+<a name="top"></a>
    -+<div id="header" style="margin-bottom:0;padding-bottom:0;">
    -+<div id="headerLeft">
    -+<a href="../../../../index.html" tabindex="-1" target="_top"><img src="../../../../assets/images/bg_logo.png" alt="Android Developers" /></a>
    -+</div>
    -+  <div id="headerRight">
    -+  <div id="headerLinks">
    -+<!-- <img src="/assets/images/icon_world.jpg" alt="" /> -->
    -+<span class="text">
    -+<!-- &nbsp;<a href="#">English</a> | -->
    -+<nobr><a href="http://developer.android.com" target="_top">Android Developers</a> | <a href="http://www.android.com" target="_top">Android.com</a></nobr>
    -+</span>
    -+</div>
    -+  <div class="and-diff-id" style="margin-top:6px;margin-right:8px;">
    -+    <table class="diffspectable">
    -+      <tr>
    -+        <td colspan="2" class="diffspechead">API Diff Specification</td>
    -+      </tr>
    -+      <tr>
    -+        <td class="diffspec" style="padding-top:.25em">To Level:</td>
    -+        <td class="diffvaluenew" style="padding-top:.25em">24.2.0</td>
    -+      </tr>
    -+      <tr>
    -+        <td class="diffspec">From Level:</td>
    -+        <td class="diffvalueold">24.1.0</td>
    -+      </tr>
    -+      <tr>
    -+        <td class="diffspec">Generated</td>
    -+        <td class="diffvalue">2016.08.16 14:03</td>
    -+      </tr>
    -+    </table>
    -+    </div><!-- End and-diff-id -->
    -+  <div class="and-diff-id" style="margin-right:8px;">
    -+    <table class="diffspectable">
    -+      <tr>
    -+        <td class="diffspec" colspan="2"><a href="jdiff_statistics.html">Statistics</a>
    -+      </tr>
    -+    </table>
    -+  </div> <!-- End and-diff-id -->
    -+  </div> <!-- End headerRight -->
    -+  </div> <!-- End header -->
    -+<div id="body-content" xstyle="padding:12px;padding-right:18px;">
    -+<div id="doc-content" style="position:relative;">
    -+<div id="mainBodyFluid">
    -+<H2>
    -+Class android.support.v4.view.accessibility.<A HREF="../../../../reference/android/support/v4/view/accessibility/AccessibilityNodeInfoCompat.CollectionItemInfoCompat.html" target="_top"><font size="+2"><code>AccessibilityNodeInfoCompat.CollectionItemInfoCompat</code></font></A>
    -+</H2>
    -+<a NAME="constructors"></a>
    -+<a NAME="methods"></a>
    -+<p>
    -+<a NAME="Added"></a>
    -+<TABLE summary="Added Methods" WIDTH="100%">
    -+<TR>
    -+  <TH VALIGN="TOP" COLSPAN=2>Added Methods</FONT></TD>
    -+</TH>
    -+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    -+  <TD VALIGN="TOP" WIDTH="25%">
    -+  <A NAME="android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.CollectionItemInfoCompat.obtain_added(int, int, int, int, boolean)"></A>
    -+  <nobr><code>CollectionItemInfoCompat</code>&nbsp;<A HREF="../../../../reference/android/support/v4/view/accessibility/AccessibilityNodeInfoCompat.CollectionItemInfoCompat.html#obtain(int, int, int, int, boolean)" target="_top"><code>obtain</code></A>(<code>int,</nobr> int<nobr>,</nobr> int<nobr>,</nobr> int<nobr>,</nobr> boolean<nobr><nobr></code>)</nobr>
    -+  </TD>
    -+  <TD>&nbsp;</TD>
    -+</TR>
    -+</TABLE>
    -+&nbsp;
    -+<a NAME="fields"></a>
    -+      </div>	
    -+      <div id="footer">
    -+        <div id="copyright">
    -+        Except as noted, this content is licensed under 
    -+        <a href="http://creativecommons.org/licenses/by/2.5/"> Creative Commons Attribution 2.5</a>.
    -+        For details and restrictions, see the <a href="/license.html">Content License</a>.
    -+        </div>
    -+      <div id="footerlinks">
    -+      <p>
    -+        <a href="http://www.android.com/terms.html">Site Terms of Service</a> -
    -+        <a href="http://www.android.com/privacy.html">Privacy Policy</a> -
    -+        <a href="http://www.android.com/branding.html">Brand Guidelines</a>
    -+      </p>
    -+    </div>
    -+    </div> <!-- end footer -->
    -+    </div><!-- end doc-content -->
    -+    </div> <!-- end body-content --> 
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    -+</script>
    -+<script type="text/javascript">
    -+  try {
    -+    var pageTracker = _gat._getTracker("UA-5831155-1");
    -+    pageTracker._setAllowAnchor(true);
    -+    pageTracker._initData();
    -+    pageTracker._trackPageview();
    -+  } catch(e) {}
    -+</script>
    -+</BODY>
    -+</HTML>
    -diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.RangeInfoCompat.html b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.RangeInfoCompat.html
    -new file mode 100644
    -index 0000000..41abf7e
    ---- /dev/null
    -+++ b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.RangeInfoCompat.html
    -@@ -0,0 +1,122 @@
    -+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
    -+<HTML style="overflow:auto;">
    -+<HEAD>
    -+<meta name="generator" content="JDiff v1.1.0">
    -+<!-- Generated by the JDiff Javadoc doclet -->
    -+<!-- (http://www.jdiff.org) -->
    -+<meta name="description" content="JDiff is a Javadoc doclet which generates an HTML report of all the packages, classes, constructors, methods, and fields which have been removed, added or changed in any way, including their documentation, when two APIs are compared.">
    -+<meta name="keywords" content="diff, jdiff, javadiff, java diff, java difference, API difference, difference between two APIs, API diff, Javadoc, doclet">
    -+<TITLE>
    -+android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.RangeInfoCompat
    -+</TITLE>
    -+<link href="../../../../assets/android-developer-docs.css" rel="stylesheet" type="text/css" />
    -+<link href="../stylesheet-jdiff.css" rel="stylesheet" type="text/css" />
    -+<noscript>
    -+<style type="text/css">
    -+body{overflow:auto;}
    -+#body-content{position:relative; top:0;}
    -+#doc-content{overflow:visible;border-left:3px solid #666;}
    -+#side-nav{padding:0;}
    -+#side-nav .toggle-list ul {display:block;}
    -+#resize-packages-nav{border-bottom:3px solid #666;}
    -+</style>
    -+</noscript>
    -+<style type="text/css">
    -+</style>
    -+</HEAD>
    -+<BODY>
    -+<!-- Start of nav bar -->
    -+<a name="top"></a>
    -+<div id="header" style="margin-bottom:0;padding-bottom:0;">
    -+<div id="headerLeft">
    -+<a href="../../../../index.html" tabindex="-1" target="_top"><img src="../../../../assets/images/bg_logo.png" alt="Android Developers" /></a>
    -+</div>
    -+  <div id="headerRight">
    -+  <div id="headerLinks">
    -+<!-- <img src="/assets/images/icon_world.jpg" alt="" /> -->
    -+<span class="text">
    -+<!-- &nbsp;<a href="#">English</a> | -->
    -+<nobr><a href="http://developer.android.com" target="_top">Android Developers</a> | <a href="http://www.android.com" target="_top">Android.com</a></nobr>
    -+</span>
    -+</div>
    -+  <div class="and-diff-id" style="margin-top:6px;margin-right:8px;">
    -+    <table class="diffspectable">
    -+      <tr>
    -+        <td colspan="2" class="diffspechead">API Diff Specification</td>
    -+      </tr>
    -+      <tr>
    -+        <td class="diffspec" style="padding-top:.25em">To Level:</td>
    -+        <td class="diffvaluenew" style="padding-top:.25em">24.2.0</td>
    -+      </tr>
    -+      <tr>
    -+        <td class="diffspec">From Level:</td>
    -+        <td class="diffvalueold">24.1.0</td>
    -+      </tr>
    -+      <tr>
    -+        <td class="diffspec">Generated</td>
    -+        <td class="diffvalue">2016.08.16 14:03</td>
    -+      </tr>
    -+    </table>
    -+    </div><!-- End and-diff-id -->
    -+  <div class="and-diff-id" style="margin-right:8px;">
    -+    <table class="diffspectable">
    -+      <tr>
    -+        <td class="diffspec" colspan="2"><a href="jdiff_statistics.html">Statistics</a>
    -+      </tr>
    -+    </table>
    -+  </div> <!-- End and-diff-id -->
    -+  </div> <!-- End headerRight -->
    -+  </div> <!-- End header -->
    -+<div id="body-content" xstyle="padding:12px;padding-right:18px;">
    -+<div id="doc-content" style="position:relative;">
    -+<div id="mainBodyFluid">
    -+<H2>
    -+Class android.support.v4.view.accessibility.<A HREF="../../../../reference/android/support/v4/view/accessibility/AccessibilityNodeInfoCompat.RangeInfoCompat.html" target="_top"><font size="+2"><code>AccessibilityNodeInfoCompat.RangeInfoCompat</code></font></A>
    -+</H2>
    -+<a NAME="constructors"></a>
    -+<a NAME="methods"></a>
    -+<p>
    -+<a NAME="Added"></a>
    -+<TABLE summary="Added Methods" WIDTH="100%">
    -+<TR>
    -+  <TH VALIGN="TOP" COLSPAN=2>Added Methods</FONT></TD>
    -+</TH>
    -+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    -+  <TD VALIGN="TOP" WIDTH="25%">
    -+  <A NAME="android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.RangeInfoCompat.obtain_added(int, float, float, float)"></A>
    -+  <nobr><code>RangeInfoCompat</code>&nbsp;<A HREF="../../../../reference/android/support/v4/view/accessibility/AccessibilityNodeInfoCompat.RangeInfoCompat.html#obtain(int, float, float, float)" target="_top"><code>obtain</code></A>(<code>int,</nobr> float<nobr>,</nobr> float<nobr>,</nobr> float<nobr><nobr></code>)</nobr>
    -+  </TD>
    -+  <TD>&nbsp;</TD>
    -+</TR>
    -+</TABLE>
    -+&nbsp;
    -+<a NAME="fields"></a>
    -+      </div>	
    -+      <div id="footer">
    -+        <div id="copyright">
    -+        Except as noted, this content is licensed under 
    -+        <a href="http://creativecommons.org/licenses/by/2.5/"> Creative Commons Attribution 2.5</a>.
    -+        For details and restrictions, see the <a href="/license.html">Content License</a>.
    -+        </div>
    -+      <div id="footerlinks">
    -+      <p>
    -+        <a href="http://www.android.com/terms.html">Site Terms of Service</a> -
    -+        <a href="http://www.android.com/privacy.html">Privacy Policy</a> -
    -+        <a href="http://www.android.com/branding.html">Brand Guidelines</a>
    -+      </p>
    -+    </div>
    -+    </div> <!-- end footer -->
    -+    </div><!-- end doc-content -->
    -+    </div> <!-- end body-content --> 
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    -+</script>
    -+<script type="text/javascript">
    -+  try {
    -+    var pageTracker = _gat._getTracker("UA-5831155-1");
    -+    pageTracker._setAllowAnchor(true);
    -+    pageTracker._initData();
    -+    pageTracker._trackPageview();
    -+  } catch(e) {}
    -+</script>
    -+</BODY>
    -+</HTML>
    -diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.html b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.html
    -new file mode 100644
    -index 0000000..005616a
    ---- /dev/null
    -+++ b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.html
    -@@ -0,0 +1,158 @@
    -+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
    -+<HTML style="overflow:auto;">
    -+<HEAD>
    -+<meta name="generator" content="JDiff v1.1.0">
    -+<!-- Generated by the JDiff Javadoc doclet -->
    -+<!-- (http://www.jdiff.org) -->
    -+<meta name="description" content="JDiff is a Javadoc doclet which generates an HTML report of all the packages, classes, constructors, methods, and fields which have been removed, added or changed in any way, including their documentation, when two APIs are compared.">
    -+<meta name="keywords" content="diff, jdiff, javadiff, java diff, java difference, API difference, difference between two APIs, API diff, Javadoc, doclet">
    -+<TITLE>
    -+android.support.v4.view.accessibility.AccessibilityNodeInfoCompat
    -+</TITLE>
    -+<link href="../../../../assets/android-developer-docs.css" rel="stylesheet" type="text/css" />
    -+<link href="../stylesheet-jdiff.css" rel="stylesheet" type="text/css" />
    -+<noscript>
    -+<style type="text/css">
    -+body{overflow:auto;}
    -+#body-content{position:relative; top:0;}
    -+#doc-content{overflow:visible;border-left:3px solid #666;}
    -+#side-nav{padding:0;}
    -+#side-nav .toggle-list ul {display:block;}
    -+#resize-packages-nav{border-bottom:3px solid #666;}
    -+</style>
    -+</noscript>
    -+<style type="text/css">
    -+</style>
    -+</HEAD>
    -+<BODY>
    -+<!-- Start of nav bar -->
    -+<a name="top"></a>
    -+<div id="header" style="margin-bottom:0;padding-bottom:0;">
    -+<div id="headerLeft">
    -+<a href="../../../../index.html" tabindex="-1" target="_top"><img src="../../../../assets/images/bg_logo.png" alt="Android Developers" /></a>
    -+</div>
    -+  <div id="headerRight">
    -+  <div id="headerLinks">
    -+<!-- <img src="/assets/images/icon_world.jpg" alt="" /> -->
    -+<span class="text">
    -+<!-- &nbsp;<a href="#">English</a> | -->
    -+<nobr><a href="http://developer.android.com" target="_top">Android Developers</a> | <a href="http://www.android.com" target="_top">Android.com</a></nobr>
    -+</span>
    -+</div>
    -+  <div class="and-diff-id" style="margin-top:6px;margin-right:8px;">
    -+    <table class="diffspectable">
    -+      <tr>
    -+        <td colspan="2" class="diffspechead">API Diff Specification</td>
    -+      </tr>
    -+      <tr>
    -+        <td class="diffspec" style="padding-top:.25em">To Level:</td>
    -+        <td class="diffvaluenew" style="padding-top:.25em">24.2.0</td>
    -+      </tr>
    -+      <tr>
    -+        <td class="diffspec">From Level:</td>
    -+        <td class="diffvalueold">24.1.0</td>
    -+      </tr>
    -+      <tr>
    -+        <td class="diffspec">Generated</td>
    -+        <td class="diffvalue">2016.08.16 14:03</td>
    -+      </tr>
    -+    </table>
    -+    </div><!-- End and-diff-id -->
    -+  <div class="and-diff-id" style="margin-right:8px;">
    -+    <table class="diffspectable">
    -+      <tr>
    -+        <td class="diffspec" colspan="2"><a href="jdiff_statistics.html">Statistics</a>
    -+      </tr>
    -+    </table>
    -+  </div> <!-- End and-diff-id -->
    -+  </div> <!-- End headerRight -->
    -+  </div> <!-- End header -->
    -+<div id="body-content" xstyle="padding:12px;padding-right:18px;">
    -+<div id="doc-content" style="position:relative;">
    -+<div id="mainBodyFluid">
    -+<H2>
    -+Class android.support.v4.view.accessibility.<A HREF="../../../../reference/android/support/v4/view/accessibility/AccessibilityNodeInfoCompat.html" target="_top"><font size="+2"><code>AccessibilityNodeInfoCompat</code></font></A>
    -+</H2>
    -+<a NAME="constructors"></a>
    -+<a NAME="methods"></a>
    -+<p>
    -+<a NAME="Added"></a>
    -+<TABLE summary="Added Methods" WIDTH="100%">
    -+<TR>
    -+  <TH VALIGN="TOP" COLSPAN=2>Added Methods</FONT></TD>
    -+</TH>
    -+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    -+  <TD VALIGN="TOP" WIDTH="25%">
    -+  <A NAME="android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.isContextClickable_added()"></A>
    -+  <nobr><code>boolean</code>&nbsp;<A HREF="../../../../reference/android/support/v4/view/accessibility/AccessibilityNodeInfoCompat.html#isContextClickable()" target="_top"><code>isContextClickable</code></A>()</nobr>
    -+  </TD>
    -+  <TD>&nbsp;</TD>
    -+</TR>
    -+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    -+  <TD VALIGN="TOP" WIDTH="25%">
    -+  <A NAME="android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.setContextClickable_added(boolean)"></A>
    -+  <nobr><code>void</code>&nbsp;<A HREF="../../../../reference/android/support/v4/view/accessibility/AccessibilityNodeInfoCompat.html#setContextClickable(boolean)" target="_top"><code>setContextClickable</code></A>(<code>boolean</code>)</nobr>
    -+  </TD>
    -+  <TD>&nbsp;</TD>
    -+</TR>
    -+</TABLE>
    -+&nbsp;
    -+<a NAME="fields"></a>
    -+<p>
    -+<a NAME="Added"></a>
    -+<TABLE summary="Added Fields" WIDTH="100%">
    -+<TR>
    -+  <TH VALIGN="TOP" COLSPAN=2>Added Fields</FONT></TD>
    -+</TH>
    -+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    -+  <TD VALIGN="TOP" WIDTH="25%">
    -+  <A NAME="android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.ACTION_ARGUMENT_COLUMN_INT"></A>
    -+  <nobr><code>String</code>&nbsp;<A HREF="../../../../reference/android/support/v4/view/accessibility/AccessibilityNodeInfoCompat.html#ACTION_ARGUMENT_COLUMN_INT" target="_top"><code>ACTION_ARGUMENT_COLUMN_INT</code></A></nobr>
    -+  </TD>
    -+  <TD>&nbsp;</TD>
    -+</TR>
    -+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    -+  <TD VALIGN="TOP" WIDTH="25%">
    -+  <A NAME="android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.ACTION_ARGUMENT_PROGRESS_VALUE"></A>
    -+  <nobr><code>String</code>&nbsp;<A HREF="../../../../reference/android/support/v4/view/accessibility/AccessibilityNodeInfoCompat.html#ACTION_ARGUMENT_PROGRESS_VALUE" target="_top"><code>ACTION_ARGUMENT_PROGRESS_VALUE</code></A></nobr>
    -+  </TD>
    -+  <TD>&nbsp;</TD>
    -+</TR>
    -+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    -+  <TD VALIGN="TOP" WIDTH="25%">
    -+  <A NAME="android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.ACTION_ARGUMENT_ROW_INT"></A>
    -+  <nobr><code>String</code>&nbsp;<A HREF="../../../../reference/android/support/v4/view/accessibility/AccessibilityNodeInfoCompat.html#ACTION_ARGUMENT_ROW_INT" target="_top"><code>ACTION_ARGUMENT_ROW_INT</code></A></nobr>
    -+  </TD>
    -+  <TD>&nbsp;</TD>
    -+</TR>
    -+</TABLE>
    -+&nbsp;
    -+      </div>	
    -+      <div id="footer">
    -+        <div id="copyright">
    -+        Except as noted, this content is licensed under 
    -+        <a href="http://creativecommons.org/licenses/by/2.5/"> Creative Commons Attribution 2.5</a>.
    -+        For details and restrictions, see the <a href="/license.html">Content License</a>.
    -+        </div>
    -+      <div id="footerlinks">
    -+      <p>
    -+        <a href="http://www.android.com/terms.html">Site Terms of Service</a> -
    -+        <a href="http://www.android.com/privacy.html">Privacy Policy</a> -
    -+        <a href="http://www.android.com/branding.html">Brand Guidelines</a>
    -+      </p>
    -+    </div>
    -+    </div> <!-- end footer -->
    -+    </div><!-- end doc-content -->
    -+    </div> <!-- end body-content --> 
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    -+</script>
    -+<script type="text/javascript">
    -+  try {
    -+    var pageTracker = _gat._getTracker("UA-5831155-1");
    -+    pageTracker._setAllowAnchor(true);
    -+    pageTracker._initData();
    -+    pageTracker._trackPageview();
    -+  } catch(e) {}
    -+</script>
    -+</BODY>
    -+</HTML>
    -diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.view.accessibility.AccessibilityNodeProviderCompat.html b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.view.accessibility.AccessibilityNodeProviderCompat.html
    -new file mode 100644
    -index 0000000..bd6b7f8
    ---- /dev/null
    -+++ b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.view.accessibility.AccessibilityNodeProviderCompat.html
    -@@ -0,0 +1,122 @@
    -+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
    -+<HTML style="overflow:auto;">
    -+<HEAD>
    -+<meta name="generator" content="JDiff v1.1.0">
    -+<!-- Generated by the JDiff Javadoc doclet -->
    -+<!-- (http://www.jdiff.org) -->
    -+<meta name="description" content="JDiff is a Javadoc doclet which generates an HTML report of all the packages, classes, constructors, methods, and fields which have been removed, added or changed in any way, including their documentation, when two APIs are compared.">
    -+<meta name="keywords" content="diff, jdiff, javadiff, java diff, java difference, API difference, difference between two APIs, API diff, Javadoc, doclet">
    -+<TITLE>
    -+android.support.v4.view.accessibility.AccessibilityNodeProviderCompat
    -+</TITLE>
    -+<link href="../../../../assets/android-developer-docs.css" rel="stylesheet" type="text/css" />
    -+<link href="../stylesheet-jdiff.css" rel="stylesheet" type="text/css" />
    -+<noscript>
    -+<style type="text/css">
    -+body{overflow:auto;}
    -+#body-content{position:relative; top:0;}
    -+#doc-content{overflow:visible;border-left:3px solid #666;}
    -+#side-nav{padding:0;}
    -+#side-nav .toggle-list ul {display:block;}
    -+#resize-packages-nav{border-bottom:3px solid #666;}
    -+</style>
    -+</noscript>
    -+<style type="text/css">
    -+</style>
    -+</HEAD>
    -+<BODY>
    -+<!-- Start of nav bar -->
    -+<a name="top"></a>
    -+<div id="header" style="margin-bottom:0;padding-bottom:0;">
    -+<div id="headerLeft">
    -+<a href="../../../../index.html" tabindex="-1" target="_top"><img src="../../../../assets/images/bg_logo.png" alt="Android Developers" /></a>
    -+</div>
    -+  <div id="headerRight">
    -+  <div id="headerLinks">
    -+<!-- <img src="/assets/images/icon_world.jpg" alt="" /> -->
    -+<span class="text">
    -+<!-- &nbsp;<a href="#">English</a> | -->
    -+<nobr><a href="http://developer.android.com" target="_top">Android Developers</a> | <a href="http://www.android.com" target="_top">Android.com</a></nobr>
    -+</span>
    -+</div>
    -+  <div class="and-diff-id" style="margin-top:6px;margin-right:8px;">
    -+    <table class="diffspectable">
    -+      <tr>
    -+        <td colspan="2" class="diffspechead">API Diff Specification</td>
    -+      </tr>
    -+      <tr>
    -+        <td class="diffspec" style="padding-top:.25em">To Level:</td>
    -+        <td class="diffvaluenew" style="padding-top:.25em">24.2.0</td>
    -+      </tr>
    -+      <tr>
    -+        <td class="diffspec">From Level:</td>
    -+        <td class="diffvalueold">24.1.0</td>
    -+      </tr>
    -+      <tr>
    -+        <td class="diffspec">Generated</td>
    -+        <td class="diffvalue">2016.08.16 14:03</td>
    -+      </tr>
    -+    </table>
    -+    </div><!-- End and-diff-id -->
    -+  <div class="and-diff-id" style="margin-right:8px;">
    -+    <table class="diffspectable">
    -+      <tr>
    -+        <td class="diffspec" colspan="2"><a href="jdiff_statistics.html">Statistics</a>
    -+      </tr>
    -+    </table>
    -+  </div> <!-- End and-diff-id -->
    -+  </div> <!-- End headerRight -->
    -+  </div> <!-- End header -->
    -+<div id="body-content" xstyle="padding:12px;padding-right:18px;">
    -+<div id="doc-content" style="position:relative;">
    -+<div id="mainBodyFluid">
    -+<H2>
    -+Class android.support.v4.view.accessibility.<A HREF="../../../../reference/android/support/v4/view/accessibility/AccessibilityNodeProviderCompat.html" target="_top"><font size="+2"><code>AccessibilityNodeProviderCompat</code></font></A>
    -+</H2>
    -+<a NAME="constructors"></a>
    -+<a NAME="methods"></a>
    -+<a NAME="fields"></a>
    -+<p>
    -+<a NAME="Added"></a>
    -+<TABLE summary="Added Fields" WIDTH="100%">
    -+<TR>
    -+  <TH VALIGN="TOP" COLSPAN=2>Added Fields</FONT></TD>
    -+</TH>
    -+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    -+  <TD VALIGN="TOP" WIDTH="25%">
    -+  <A NAME="android.support.v4.view.accessibility.AccessibilityNodeProviderCompat.HOST_VIEW_ID"></A>
    -+  <nobr><code>int</code>&nbsp;<A HREF="../../../../reference/android/support/v4/view/accessibility/AccessibilityNodeProviderCompat.html#HOST_VIEW_ID" target="_top"><code>HOST_VIEW_ID</code></A></nobr>
    -+  </TD>
    -+  <TD>&nbsp;</TD>
    -+</TR>
    -+</TABLE>
    -+&nbsp;
    -+      </div>	
    -+      <div id="footer">
    -+        <div id="copyright">
    -+        Except as noted, this content is licensed under 
    -+        <a href="http://creativecommons.org/licenses/by/2.5/"> Creative Commons Attribution 2.5</a>.
    -+        For details and restrictions, see the <a href="/license.html">Content License</a>.
    -+        </div>
    -+      <div id="footerlinks">
    -+      <p>
    -+        <a href="http://www.android.com/terms.html">Site Terms of Service</a> -
    -+        <a href="http://www.android.com/privacy.html">Privacy Policy</a> -
    -+        <a href="http://www.android.com/branding.html">Brand Guidelines</a>
    -+      </p>
    -+    </div>
    -+    </div> <!-- end footer -->
    -+    </div><!-- end doc-content -->
    -+    </div> <!-- end body-content --> 
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    -+</script>
    -+<script type="text/javascript">
    -+  try {
    -+    var pageTracker = _gat._getTracker("UA-5831155-1");
    -+    pageTracker._setAllowAnchor(true);
    -+    pageTracker._initData();
    -+    pageTracker._trackPageview();
    -+  } catch(e) {}
    -+</script>
    -+</BODY>
    -+</HTML>
    -diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.view.accessibility.AccessibilityWindowInfoCompat.html b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.view.accessibility.AccessibilityWindowInfoCompat.html
    -new file mode 100644
    -index 0000000..40f3ca2
    ---- /dev/null
    -+++ b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.view.accessibility.AccessibilityWindowInfoCompat.html
    -@@ -0,0 +1,122 @@
    -+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
    -+<HTML style="overflow:auto;">
    -+<HEAD>
    -+<meta name="generator" content="JDiff v1.1.0">
    -+<!-- Generated by the JDiff Javadoc doclet -->
    -+<!-- (http://www.jdiff.org) -->
    -+<meta name="description" content="JDiff is a Javadoc doclet which generates an HTML report of all the packages, classes, constructors, methods, and fields which have been removed, added or changed in any way, including their documentation, when two APIs are compared.">
    -+<meta name="keywords" content="diff, jdiff, javadiff, java diff, java difference, API difference, difference between two APIs, API diff, Javadoc, doclet">
    -+<TITLE>
    -+android.support.v4.view.accessibility.AccessibilityWindowInfoCompat
    -+</TITLE>
    -+<link href="../../../../assets/android-developer-docs.css" rel="stylesheet" type="text/css" />
    -+<link href="../stylesheet-jdiff.css" rel="stylesheet" type="text/css" />
    -+<noscript>
    -+<style type="text/css">
    -+body{overflow:auto;}
    -+#body-content{position:relative; top:0;}
    -+#doc-content{overflow:visible;border-left:3px solid #666;}
    -+#side-nav{padding:0;}
    -+#side-nav .toggle-list ul {display:block;}
    -+#resize-packages-nav{border-bottom:3px solid #666;}
    -+</style>
    -+</noscript>
    -+<style type="text/css">
    -+</style>
    -+</HEAD>
    -+<BODY>
    -+<!-- Start of nav bar -->
    -+<a name="top"></a>
    -+<div id="header" style="margin-bottom:0;padding-bottom:0;">
    -+<div id="headerLeft">
    -+<a href="../../../../index.html" tabindex="-1" target="_top"><img src="../../../../assets/images/bg_logo.png" alt="Android Developers" /></a>
    -+</div>
    -+  <div id="headerRight">
    -+  <div id="headerLinks">
    -+<!-- <img src="/assets/images/icon_world.jpg" alt="" /> -->
    -+<span class="text">
    -+<!-- &nbsp;<a href="#">English</a> | -->
    -+<nobr><a href="http://developer.android.com" target="_top">Android Developers</a> | <a href="http://www.android.com" target="_top">Android.com</a></nobr>
    -+</span>
    -+</div>
    -+  <div class="and-diff-id" style="margin-top:6px;margin-right:8px;">
    -+    <table class="diffspectable">
    -+      <tr>
    -+        <td colspan="2" class="diffspechead">API Diff Specification</td>
    -+      </tr>
    -+      <tr>
    -+        <td class="diffspec" style="padding-top:.25em">To Level:</td>
    -+        <td class="diffvaluenew" style="padding-top:.25em">24.2.0</td>
    -+      </tr>
    -+      <tr>
    -+        <td class="diffspec">From Level:</td>
    -+        <td class="diffvalueold">24.1.0</td>
    -+      </tr>
    -+      <tr>
    -+        <td class="diffspec">Generated</td>
    -+        <td class="diffvalue">2016.08.16 14:03</td>
    -+      </tr>
    -+    </table>
    -+    </div><!-- End and-diff-id -->
    -+  <div class="and-diff-id" style="margin-right:8px;">
    -+    <table class="diffspectable">
    -+      <tr>
    -+        <td class="diffspec" colspan="2"><a href="jdiff_statistics.html">Statistics</a>
    -+      </tr>
    -+    </table>
    -+  </div> <!-- End and-diff-id -->
    -+  </div> <!-- End headerRight -->
    -+  </div> <!-- End header -->
    -+<div id="body-content" xstyle="padding:12px;padding-right:18px;">
    -+<div id="doc-content" style="position:relative;">
    -+<div id="mainBodyFluid">
    -+<H2>
    -+Class android.support.v4.view.accessibility.<A HREF="../../../../reference/android/support/v4/view/accessibility/AccessibilityWindowInfoCompat.html" target="_top"><font size="+2"><code>AccessibilityWindowInfoCompat</code></font></A>
    -+</H2>
    -+<a NAME="constructors"></a>
    -+<a NAME="methods"></a>
    -+<a NAME="fields"></a>
    -+<p>
    -+<a NAME="Added"></a>
    -+<TABLE summary="Added Fields" WIDTH="100%">
    -+<TR>
    -+  <TH VALIGN="TOP" COLSPAN=2>Added Fields</FONT></TD>
    -+</TH>
    -+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    -+  <TD VALIGN="TOP" WIDTH="25%">
    -+  <A NAME="android.support.v4.view.accessibility.AccessibilityWindowInfoCompat.TYPE_SPLIT_SCREEN_DIVIDER"></A>
    -+  <nobr><code>int</code>&nbsp;<A HREF="../../../../reference/android/support/v4/view/accessibility/AccessibilityWindowInfoCompat.html#TYPE_SPLIT_SCREEN_DIVIDER" target="_top"><code>TYPE_SPLIT_SCREEN_DIVIDER</code></A></nobr>
    -+  </TD>
    -+  <TD>&nbsp;</TD>
    -+</TR>
    -+</TABLE>
    -+&nbsp;
    -+      </div>	
    -+      <div id="footer">
    -+        <div id="copyright">
    -+        Except as noted, this content is licensed under 
    -+        <a href="http://creativecommons.org/licenses/by/2.5/"> Creative Commons Attribution 2.5</a>.
    -+        For details and restrictions, see the <a href="/license.html">Content License</a>.
    -+        </div>
    -+      <div id="footerlinks">
    -+      <p>
    -+        <a href="http://www.android.com/terms.html">Site Terms of Service</a> -
    -+        <a href="http://www.android.com/privacy.html">Privacy Policy</a> -
    -+        <a href="http://www.android.com/branding.html">Brand Guidelines</a>
    -+      </p>
    -+    </div>
    -+    </div> <!-- end footer -->
    -+    </div><!-- end doc-content -->
    -+    </div> <!-- end body-content --> 
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    -+</script>
    -+<script type="text/javascript">
    -+  try {
    -+    var pageTracker = _gat._getTracker("UA-5831155-1");
    -+    pageTracker._setAllowAnchor(true);
    -+    pageTracker._initData();
    -+    pageTracker._trackPageview();
    -+  } catch(e) {}
    -+</script>
    -+</BODY>
    -+</HTML>
    -diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.widget.SearchViewCompat.OnCloseListenerCompat.html b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.widget.SearchViewCompat.OnCloseListenerCompat.html
    -new file mode 100644
    -index 0000000..3d9f2ea
    ---- /dev/null
    -+++ b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.widget.SearchViewCompat.OnCloseListenerCompat.html
    -@@ -0,0 +1,109 @@
    -+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
    -+<HTML style="overflow:auto;">
    -+<HEAD>
    -+<meta name="generator" content="JDiff v1.1.0">
    -+<!-- Generated by the JDiff Javadoc doclet -->
    -+<!-- (http://www.jdiff.org) -->
    -+<meta name="description" content="JDiff is a Javadoc doclet which generates an HTML report of all the packages, classes, constructors, methods, and fields which have been removed, added or changed in any way, including their documentation, when two APIs are compared.">
    -+<meta name="keywords" content="diff, jdiff, javadiff, java diff, java difference, API difference, difference between two APIs, API diff, Javadoc, doclet">
    -+<TITLE>
    -+android.support.v4.widget.SearchViewCompat.OnCloseListenerCompat
    -+</TITLE>
    -+<link href="../../../../assets/android-developer-docs.css" rel="stylesheet" type="text/css" />
    -+<link href="../stylesheet-jdiff.css" rel="stylesheet" type="text/css" />
    -+<noscript>
    -+<style type="text/css">
    -+body{overflow:auto;}
    -+#body-content{position:relative; top:0;}
    -+#doc-content{overflow:visible;border-left:3px solid #666;}
    -+#side-nav{padding:0;}
    -+#side-nav .toggle-list ul {display:block;}
    -+#resize-packages-nav{border-bottom:3px solid #666;}
    -+</style>
    -+</noscript>
    -+<style type="text/css">
    -+</style>
    -+</HEAD>
    -+<BODY>
    -+<!-- Start of nav bar -->
    -+<a name="top"></a>
    -+<div id="header" style="margin-bottom:0;padding-bottom:0;">
    -+<div id="headerLeft">
    -+<a href="../../../../index.html" tabindex="-1" target="_top"><img src="../../../../assets/images/bg_logo.png" alt="Android Developers" /></a>
    -+</div>
    -+  <div id="headerRight">
    -+  <div id="headerLinks">
    -+<!-- <img src="/assets/images/icon_world.jpg" alt="" /> -->
    -+<span class="text">
    -+<!-- &nbsp;<a href="#">English</a> | -->
    -+<nobr><a href="http://developer.android.com" target="_top">Android Developers</a> | <a href="http://www.android.com" target="_top">Android.com</a></nobr>
    -+</span>
    -+</div>
    -+  <div class="and-diff-id" style="margin-top:6px;margin-right:8px;">
    -+    <table class="diffspectable">
    -+      <tr>
    -+        <td colspan="2" class="diffspechead">API Diff Specification</td>
    -+      </tr>
    -+      <tr>
    -+        <td class="diffspec" style="padding-top:.25em">To Level:</td>
    -+        <td class="diffvaluenew" style="padding-top:.25em">24.2.0</td>
    -+      </tr>
    -+      <tr>
    -+        <td class="diffspec">From Level:</td>
    -+        <td class="diffvalueold">24.1.0</td>
    -+      </tr>
    -+      <tr>
    -+        <td class="diffspec">Generated</td>
    -+        <td class="diffvalue">2016.08.16 14:03</td>
    -+      </tr>
    -+    </table>
    -+    </div><!-- End and-diff-id -->
    -+  <div class="and-diff-id" style="margin-right:8px;">
    -+    <table class="diffspectable">
    -+      <tr>
    -+        <td class="diffspec" colspan="2"><a href="jdiff_statistics.html">Statistics</a>
    -+      </tr>
    -+    </table>
    -+  </div> <!-- End and-diff-id -->
    -+  </div> <!-- End headerRight -->
    -+  </div> <!-- End header -->
    -+<div id="body-content" xstyle="padding:12px;padding-right:18px;">
    -+<div id="doc-content" style="position:relative;">
    -+<div id="mainBodyFluid">
    -+<H2>
    -+Class android.support.v4.widget.<A HREF="../../../../reference/android/support/v4/widget/SearchViewCompat.OnCloseListenerCompat.html" target="_top"><font size="+2"><code>SearchViewCompat.OnCloseListenerCompat</code></font></A>
    -+</H2>
    -+<p><font xsize="+1">Added interface <code>android.support.v4.widget.SearchViewCompat.OnCloseListener</code>.<br></font>
    -+<p><b>Now deprecated</b>.<br>
    -+<a NAME="constructors"></a>
    -+<a NAME="methods"></a>
    -+<a NAME="fields"></a>
    -+      </div>	
    -+      <div id="footer">
    -+        <div id="copyright">
    -+        Except as noted, this content is licensed under 
    -+        <a href="http://creativecommons.org/licenses/by/2.5/"> Creative Commons Attribution 2.5</a>.
    -+        For details and restrictions, see the <a href="/license.html">Content License</a>.
    -+        </div>
    -+      <div id="footerlinks">
    -+      <p>
    -+        <a href="http://www.android.com/terms.html">Site Terms of Service</a> -
    -+        <a href="http://www.android.com/privacy.html">Privacy Policy</a> -
    -+        <a href="http://www.android.com/branding.html">Brand Guidelines</a>
    -+      </p>
    -+    </div>
    -+    </div> <!-- end footer -->
    -+    </div><!-- end doc-content -->
    -+    </div> <!-- end body-content --> 
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    -+</script>
    -+<script type="text/javascript">
    -+  try {
    -+    var pageTracker = _gat._getTracker("UA-5831155-1");
    -+    pageTracker._setAllowAnchor(true);
    -+    pageTracker._initData();
    -+    pageTracker._trackPageview();
    -+  } catch(e) {}
    -+</script>
    -+</BODY>
    -+</HTML>
    -diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.widget.SearchViewCompat.OnQueryTextListenerCompat.html b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.widget.SearchViewCompat.OnQueryTextListenerCompat.html
    -new file mode 100644
    -index 0000000..df0f3e1
    ---- /dev/null
    -+++ b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.widget.SearchViewCompat.OnQueryTextListenerCompat.html
    -@@ -0,0 +1,109 @@
    -+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
    -+<HTML style="overflow:auto;">
    -+<HEAD>
    -+<meta name="generator" content="JDiff v1.1.0">
    -+<!-- Generated by the JDiff Javadoc doclet -->
    -+<!-- (http://www.jdiff.org) -->
    -+<meta name="description" content="JDiff is a Javadoc doclet which generates an HTML report of all the packages, classes, constructors, methods, and fields which have been removed, added or changed in any way, including their documentation, when two APIs are compared.">
    -+<meta name="keywords" content="diff, jdiff, javadiff, java diff, java difference, API difference, difference between two APIs, API diff, Javadoc, doclet">
    -+<TITLE>
    -+android.support.v4.widget.SearchViewCompat.OnQueryTextListenerCompat
    -+</TITLE>
    -+<link href="../../../../assets/android-developer-docs.css" rel="stylesheet" type="text/css" />
    -+<link href="../stylesheet-jdiff.css" rel="stylesheet" type="text/css" />
    -+<noscript>
    -+<style type="text/css">
    -+body{overflow:auto;}
    -+#body-content{position:relative; top:0;}
    -+#doc-content{overflow:visible;border-left:3px solid #666;}
    -+#side-nav{padding:0;}
    -+#side-nav .toggle-list ul {display:block;}
    -+#resize-packages-nav{border-bottom:3px solid #666;}
    -+</style>
    -+</noscript>
    -+<style type="text/css">
    -+</style>
    -+</HEAD>
    -+<BODY>
    -+<!-- Start of nav bar -->
    -+<a name="top"></a>
    -+<div id="header" style="margin-bottom:0;padding-bottom:0;">
    -+<div id="headerLeft">
    -+<a href="../../../../index.html" tabindex="-1" target="_top"><img src="../../../../assets/images/bg_logo.png" alt="Android Developers" /></a>
    -+</div>
    -+  <div id="headerRight">
    -+  <div id="headerLinks">
    -+<!-- <img src="/assets/images/icon_world.jpg" alt="" /> -->
    -+<span class="text">
    -+<!-- &nbsp;<a href="#">English</a> | -->
    -+<nobr><a href="http://developer.android.com" target="_top">Android Developers</a> | <a href="http://www.android.com" target="_top">Android.com</a></nobr>
    -+</span>
    -+</div>
    -+  <div class="and-diff-id" style="margin-top:6px;margin-right:8px;">
    -+    <table class="diffspectable">
    -+      <tr>
    -+        <td colspan="2" class="diffspechead">API Diff Specification</td>
    -+      </tr>
    -+      <tr>
    -+        <td class="diffspec" style="padding-top:.25em">To Level:</td>
    -+        <td class="diffvaluenew" style="padding-top:.25em">24.2.0</td>
    -+      </tr>
    -+      <tr>
    -+        <td class="diffspec">From Level:</td>
    -+        <td class="diffvalueold">24.1.0</td>
    -+      </tr>
    -+      <tr>
    -+        <td class="diffspec">Generated</td>
    -+        <td class="diffvalue">2016.08.16 14:03</td>
    -+      </tr>
    -+    </table>
    -+    </div><!-- End and-diff-id -->
    -+  <div class="and-diff-id" style="margin-right:8px;">
    -+    <table class="diffspectable">
    -+      <tr>
    -+        <td class="diffspec" colspan="2"><a href="jdiff_statistics.html">Statistics</a>
    -+      </tr>
    -+    </table>
    -+  </div> <!-- End and-diff-id -->
    -+  </div> <!-- End headerRight -->
    -+  </div> <!-- End header -->
    -+<div id="body-content" xstyle="padding:12px;padding-right:18px;">
    -+<div id="doc-content" style="position:relative;">
    -+<div id="mainBodyFluid">
    -+<H2>
    -+Class android.support.v4.widget.<A HREF="../../../../reference/android/support/v4/widget/SearchViewCompat.OnQueryTextListenerCompat.html" target="_top"><font size="+2"><code>SearchViewCompat.OnQueryTextListenerCompat</code></font></A>
    -+</H2>
    -+<p><font xsize="+1">Added interface <code>android.support.v4.widget.SearchViewCompat.OnQueryTextListener</code>.<br></font>
    -+<p><b>Now deprecated</b>.<br>
    -+<a NAME="constructors"></a>
    -+<a NAME="methods"></a>
    -+<a NAME="fields"></a>
    -+      </div>	
    -+      <div id="footer">
    -+        <div id="copyright">
    -+        Except as noted, this content is licensed under 
    -+        <a href="http://creativecommons.org/licenses/by/2.5/"> Creative Commons Attribution 2.5</a>.
    -+        For details and restrictions, see the <a href="/license.html">Content License</a>.
    -+        </div>
    -+      <div id="footerlinks">
    -+      <p>
    -+        <a href="http://www.android.com/terms.html">Site Terms of Service</a> -
    -+        <a href="http://www.android.com/privacy.html">Privacy Policy</a> -
    -+        <a href="http://www.android.com/branding.html">Brand Guidelines</a>
    -+      </p>
    -+    </div>
    -+    </div> <!-- end footer -->
    -+    </div><!-- end doc-content -->
    -+    </div> <!-- end body-content --> 
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    -+</script>
    -+<script type="text/javascript">
    -+  try {
    -+    var pageTracker = _gat._getTracker("UA-5831155-1");
    -+    pageTracker._setAllowAnchor(true);
    -+    pageTracker._initData();
    -+    pageTracker._trackPageview();
    -+  } catch(e) {}
    -+</script>
    -+</BODY>
    -+</HTML>
    -diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.widget.SearchViewCompat.html b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.widget.SearchViewCompat.html
    -new file mode 100644
    -index 0000000..4af1e46
    ---- /dev/null
    -+++ b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.widget.SearchViewCompat.html
    -@@ -0,0 +1,135 @@
    -+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
    -+<HTML style="overflow:auto;">
    -+<HEAD>
    -+<meta name="generator" content="JDiff v1.1.0">
    -+<!-- Generated by the JDiff Javadoc doclet -->
    -+<!-- (http://www.jdiff.org) -->
    -+<meta name="description" content="JDiff is a Javadoc doclet which generates an HTML report of all the packages, classes, constructors, methods, and fields which have been removed, added or changed in any way, including their documentation, when two APIs are compared.">
    -+<meta name="keywords" content="diff, jdiff, javadiff, java diff, java difference, API difference, difference between two APIs, API diff, Javadoc, doclet">
    -+<TITLE>
    -+android.support.v4.widget.SearchViewCompat
    -+</TITLE>
    -+<link href="../../../../assets/android-developer-docs.css" rel="stylesheet" type="text/css" />
    -+<link href="../stylesheet-jdiff.css" rel="stylesheet" type="text/css" />
    -+<noscript>
    -+<style type="text/css">
    -+body{overflow:auto;}
    -+#body-content{position:relative; top:0;}
    -+#doc-content{overflow:visible;border-left:3px solid #666;}
    -+#side-nav{padding:0;}
    -+#side-nav .toggle-list ul {display:block;}
    -+#resize-packages-nav{border-bottom:3px solid #666;}
    -+</style>
    -+</noscript>
    -+<style type="text/css">
    -+</style>
    -+</HEAD>
    -+<BODY>
    -+<!-- Start of nav bar -->
    -+<a name="top"></a>
    -+<div id="header" style="margin-bottom:0;padding-bottom:0;">
    -+<div id="headerLeft">
    -+<a href="../../../../index.html" tabindex="-1" target="_top"><img src="../../../../assets/images/bg_logo.png" alt="Android Developers" /></a>
    -+</div>
    -+  <div id="headerRight">
    -+  <div id="headerLinks">
    -+<!-- <img src="/assets/images/icon_world.jpg" alt="" /> -->
    -+<span class="text">
    -+<!-- &nbsp;<a href="#">English</a> | -->
    -+<nobr><a href="http://developer.android.com" target="_top">Android Developers</a> | <a href="http://www.android.com" target="_top">Android.com</a></nobr>
    -+</span>
    -+</div>
    -+  <div class="and-diff-id" style="margin-top:6px;margin-right:8px;">
    -+    <table class="diffspectable">
    -+      <tr>
    -+        <td colspan="2" class="diffspechead">API Diff Specification</td>
    -+      </tr>
    -+      <tr>
    -+        <td class="diffspec" style="padding-top:.25em">To Level:</td>
    -+        <td class="diffvaluenew" style="padding-top:.25em">24.2.0</td>
    -+      </tr>
    -+      <tr>
    -+        <td class="diffspec">From Level:</td>
    -+        <td class="diffvalueold">24.1.0</td>
    -+      </tr>
    -+      <tr>
    -+        <td class="diffspec">Generated</td>
    -+        <td class="diffvalue">2016.08.16 14:03</td>
    -+      </tr>
    -+    </table>
    -+    </div><!-- End and-diff-id -->
    -+  <div class="and-diff-id" style="margin-right:8px;">
    -+    <table class="diffspectable">
    -+      <tr>
    -+        <td class="diffspec" colspan="2"><a href="jdiff_statistics.html">Statistics</a>
    -+      </tr>
    -+    </table>
    -+  </div> <!-- End and-diff-id -->
    -+  </div> <!-- End headerRight -->
    -+  </div> <!-- End header -->
    -+<div id="body-content" xstyle="padding:12px;padding-right:18px;">
    -+<div id="doc-content" style="position:relative;">
    -+<div id="mainBodyFluid">
    -+<H2>
    -+Class android.support.v4.widget.<A HREF="../../../../reference/android/support/v4/widget/SearchViewCompat.html" target="_top"><font size="+2"><code>SearchViewCompat</code></font></A>
    -+</H2>
    -+<a NAME="constructors"></a>
    -+<a NAME="methods"></a>
    -+<p>
    -+<a NAME="Changed"></a>
    -+<TABLE summary="Changed Methods" WIDTH="100%">
    -+<TR>
    -+  <TH VALIGN="TOP" COLSPAN=3>Changed Methods</FONT></TD>
    -+</TH>
    -+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    -+  <TD VALIGN="TOP" WIDTH="25%">
    -+  <A NAME="android.support.v4.widget.SearchViewCompat.setOnCloseListener_changed(android.view.View, android.support.v4.widget.SearchViewCompat.OnCloseListener)"></A>
    -+  <nobr><code>void</code>&nbsp;<A HREF="../../../../reference/android/support/v4/widget/SearchViewCompat.html#setOnCloseListener(android.view.View, android.support.v4.widget.SearchViewCompat.OnCloseListener)" target="_top"><code>setOnCloseListener</code></A>(<code>View,</nobr> OnCloseListener<nobr><nobr></code>)  </nobr>
    -+  </TD>
    -+  <TD VALIGN="TOP" WIDTH="30%">
    -+Change in signature from (<code>View, OnCloseListenerCompat</code>) to (<code>View, OnCloseListener</code>).<br>
    -+  </TD>
    -+  <TD>&nbsp;</TD>
    -+</TR>
    -+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    -+  <TD VALIGN="TOP" WIDTH="25%">
    -+  <A NAME="android.support.v4.widget.SearchViewCompat.setOnQueryTextListener_changed(android.view.View, android.support.v4.widget.SearchViewCompat.OnQueryTextListener)"></A>
    -+  <nobr><code>void</code>&nbsp;<A HREF="../../../../reference/android/support/v4/widget/SearchViewCompat.html#setOnQueryTextListener(android.view.View, android.support.v4.widget.SearchViewCompat.OnQueryTextListener)" target="_top"><code>setOnQueryTextListener</code></A>(<code>View,</nobr> OnQueryTextListener<nobr><nobr></code>)  </nobr>
    -+  </TD>
    -+  <TD VALIGN="TOP" WIDTH="30%">
    -+Change in signature from (<code>View, OnQueryTextListenerCompat</code>) to (<code>View, OnQueryTextListener</code>).<br>
    -+  </TD>
    -+  <TD>&nbsp;</TD>
    -+</TR>
    -+</TABLE>
    -+&nbsp;
    -+<a NAME="fields"></a>
    -+      </div>	
    -+      <div id="footer">
    -+        <div id="copyright">
    -+        Except as noted, this content is licensed under 
    -+        <a href="http://creativecommons.org/licenses/by/2.5/"> Creative Commons Attribution 2.5</a>.
    -+        For details and restrictions, see the <a href="/license.html">Content License</a>.
    -+        </div>
    -+      <div id="footerlinks">
    -+      <p>
    -+        <a href="http://www.android.com/terms.html">Site Terms of Service</a> -
    -+        <a href="http://www.android.com/privacy.html">Privacy Policy</a> -
    -+        <a href="http://www.android.com/branding.html">Brand Guidelines</a>
    -+      </p>
    -+    </div>
    -+    </div> <!-- end footer -->
    -+    </div><!-- end doc-content -->
    -+    </div> <!-- end body-content --> 
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    -+</script>
    -+<script type="text/javascript">
    -+  try {
    -+    var pageTracker = _gat._getTracker("UA-5831155-1");
    -+    pageTracker._setAllowAnchor(true);
    -+    pageTracker._initData();
    -+    pageTracker._trackPageview();
    -+  } catch(e) {}
    -+</script>
    -+</BODY>
    -+</HTML>
    -diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.widget.SwipeRefreshLayout.html b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.widget.SwipeRefreshLayout.html
    -new file mode 100644
    -index 0000000..5848782
    ---- /dev/null
    -+++ b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.widget.SwipeRefreshLayout.html
    -@@ -0,0 +1,122 @@
    -+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
    -+<HTML style="overflow:auto;">
    -+<HEAD>
    -+<meta name="generator" content="JDiff v1.1.0">
    -+<!-- Generated by the JDiff Javadoc doclet -->
    -+<!-- (http://www.jdiff.org) -->
    -+<meta name="description" content="JDiff is a Javadoc doclet which generates an HTML report of all the packages, classes, constructors, methods, and fields which have been removed, added or changed in any way, including their documentation, when two APIs are compared.">
    -+<meta name="keywords" content="diff, jdiff, javadiff, java diff, java difference, API difference, difference between two APIs, API diff, Javadoc, doclet">
    -+<TITLE>
    -+android.support.v4.widget.SwipeRefreshLayout
    -+</TITLE>
    -+<link href="../../../../assets/android-developer-docs.css" rel="stylesheet" type="text/css" />
    -+<link href="../stylesheet-jdiff.css" rel="stylesheet" type="text/css" />
    -+<noscript>
    -+<style type="text/css">
    -+body{overflow:auto;}
    -+#body-content{position:relative; top:0;}
    -+#doc-content{overflow:visible;border-left:3px solid #666;}
    -+#side-nav{padding:0;}
    -+#side-nav .toggle-list ul {display:block;}
    -+#resize-packages-nav{border-bottom:3px solid #666;}
    -+</style>
    -+</noscript>
    -+<style type="text/css">
    -+</style>
    -+</HEAD>
    -+<BODY>
    -+<!-- Start of nav bar -->
    -+<a name="top"></a>
    -+<div id="header" style="margin-bottom:0;padding-bottom:0;">
    -+<div id="headerLeft">
    -+<a href="../../../../index.html" tabindex="-1" target="_top"><img src="../../../../assets/images/bg_logo.png" alt="Android Developers" /></a>
    -+</div>
    -+  <div id="headerRight">
    -+  <div id="headerLinks">
    -+<!-- <img src="/assets/images/icon_world.jpg" alt="" /> -->
    -+<span class="text">
    -+<!-- &nbsp;<a href="#">English</a> | -->
    -+<nobr><a href="http://developer.android.com" target="_top">Android Developers</a> | <a href="http://www.android.com" target="_top">Android.com</a></nobr>
    -+</span>
    -+</div>
    -+  <div class="and-diff-id" style="margin-top:6px;margin-right:8px;">
    -+    <table class="diffspectable">
    -+      <tr>
    -+        <td colspan="2" class="diffspechead">API Diff Specification</td>
    -+      </tr>
    -+      <tr>
    -+        <td class="diffspec" style="padding-top:.25em">To Level:</td>
    -+        <td class="diffvaluenew" style="padding-top:.25em">24.2.0</td>
    -+      </tr>
    -+      <tr>
    -+        <td class="diffspec">From Level:</td>
    -+        <td class="diffvalueold">24.1.0</td>
    -+      </tr>
    -+      <tr>
    -+        <td class="diffspec">Generated</td>
    -+        <td class="diffvalue">2016.08.16 14:03</td>
    -+      </tr>
    -+    </table>
    -+    </div><!-- End and-diff-id -->
    -+  <div class="and-diff-id" style="margin-right:8px;">
    -+    <table class="diffspectable">
    -+      <tr>
    -+        <td class="diffspec" colspan="2"><a href="jdiff_statistics.html">Statistics</a>
    -+      </tr>
    -+    </table>
    -+  </div> <!-- End and-diff-id -->
    -+  </div> <!-- End headerRight -->
    -+  </div> <!-- End header -->
    -+<div id="body-content" xstyle="padding:12px;padding-right:18px;">
    -+<div id="doc-content" style="position:relative;">
    -+<div id="mainBodyFluid">
    -+<H2>
    -+Class android.support.v4.widget.<A HREF="../../../../reference/android/support/v4/widget/SwipeRefreshLayout.html" target="_top"><font size="+2"><code>SwipeRefreshLayout</code></font></A>
    -+</H2>
    -+<a NAME="constructors"></a>
    -+<a NAME="methods"></a>
    -+<p>
    -+<a NAME="Added"></a>
    -+<TABLE summary="Added Methods" WIDTH="100%">
    -+<TR>
    -+  <TH VALIGN="TOP" COLSPAN=2>Added Methods</FONT></TD>
    -+</TH>
    -+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    -+  <TD VALIGN="TOP" WIDTH="25%">
    -+  <A NAME="android.support.v4.widget.SwipeRefreshLayout.setOnChildScrollUpCallback_added(android.support.v4.widget.SwipeRefreshLayout.OnChildScrollUpCallback)"></A>
    -+  <nobr><code>void</code>&nbsp;<A HREF="../../../../reference/android/support/v4/widget/SwipeRefreshLayout.html#setOnChildScrollUpCallback(android.support.v4.widget.SwipeRefreshLayout.OnChildScrollUpCallback)" target="_top"><code>setOnChildScrollUpCallback</code></A>(<code>OnChildScrollUpCallback</code>)</nobr>
    -+  </TD>
    -+  <TD>&nbsp;</TD>
    -+</TR>
    -+</TABLE>
    -+&nbsp;
    -+<a NAME="fields"></a>
    -+      </div>	
    -+      <div id="footer">
    -+        <div id="copyright">
    -+        Except as noted, this content is licensed under 
    -+        <a href="http://creativecommons.org/licenses/by/2.5/"> Creative Commons Attribution 2.5</a>.
    -+        For details and restrictions, see the <a href="/license.html">Content License</a>.
    -+        </div>
    -+      <div id="footerlinks">
    -+      <p>
    -+        <a href="http://www.android.com/terms.html">Site Terms of Service</a> -
    -+        <a href="http://www.android.com/privacy.html">Privacy Policy</a> -
    -+        <a href="http://www.android.com/branding.html">Brand Guidelines</a>
    -+      </p>
    -+    </div>
    -+    </div> <!-- end footer -->
    -+    </div><!-- end doc-content -->
    -+    </div> <!-- end body-content --> 
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    -+</script>
    -+<script type="text/javascript">
    -+  try {
    -+    var pageTracker = _gat._getTracker("UA-5831155-1");
    -+    pageTracker._setAllowAnchor(true);
    -+    pageTracker._initData();
    -+    pageTracker._trackPageview();
    -+  } catch(e) {}
    -+</script>
    -+</BODY>
    -+</HTML>
    -diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.widget.TextViewCompat.html b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.widget.TextViewCompat.html
    -new file mode 100644
    -index 0000000..87b9e69
    ---- /dev/null
    -+++ b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.widget.TextViewCompat.html
    -@@ -0,0 +1,122 @@
    -+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
    -+<HTML style="overflow:auto;">
    -+<HEAD>
    -+<meta name="generator" content="JDiff v1.1.0">
    -+<!-- Generated by the JDiff Javadoc doclet -->
    -+<!-- (http://www.jdiff.org) -->
    -+<meta name="description" content="JDiff is a Javadoc doclet which generates an HTML report of all the packages, classes, constructors, methods, and fields which have been removed, added or changed in any way, including their documentation, when two APIs are compared.">
    -+<meta name="keywords" content="diff, jdiff, javadiff, java diff, java difference, API difference, difference between two APIs, API diff, Javadoc, doclet">
    -+<TITLE>
    -+android.support.v4.widget.TextViewCompat
    -+</TITLE>
    -+<link href="../../../../assets/android-developer-docs.css" rel="stylesheet" type="text/css" />
    -+<link href="../stylesheet-jdiff.css" rel="stylesheet" type="text/css" />
    -+<noscript>
    -+<style type="text/css">
    -+body{overflow:auto;}
    -+#body-content{position:relative; top:0;}
    -+#doc-content{overflow:visible;border-left:3px solid #666;}
    -+#side-nav{padding:0;}
    -+#side-nav .toggle-list ul {display:block;}
    -+#resize-packages-nav{border-bottom:3px solid #666;}
    -+</style>
    -+</noscript>
    -+<style type="text/css">
    -+</style>
    -+</HEAD>
    -+<BODY>
    -+<!-- Start of nav bar -->
    -+<a name="top"></a>
    -+<div id="header" style="margin-bottom:0;padding-bottom:0;">
    -+<div id="headerLeft">
    -+<a href="../../../../index.html" tabindex="-1" target="_top"><img src="../../../../assets/images/bg_logo.png" alt="Android Developers" /></a>
    -+</div>
    -+  <div id="headerRight">
    -+  <div id="headerLinks">
    -+<!-- <img src="/assets/images/icon_world.jpg" alt="" /> -->
    -+<span class="text">
    -+<!-- &nbsp;<a href="#">English</a> | -->
    -+<nobr><a href="http://developer.android.com" target="_top">Android Developers</a> | <a href="http://www.android.com" target="_top">Android.com</a></nobr>
    -+</span>
    -+</div>
    -+  <div class="and-diff-id" style="margin-top:6px;margin-right:8px;">
    -+    <table class="diffspectable">
    -+      <tr>
    -+        <td colspan="2" class="diffspechead">API Diff Specification</td>
    -+      </tr>
    -+      <tr>
    -+        <td class="diffspec" style="padding-top:.25em">To Level:</td>
    -+        <td class="diffvaluenew" style="padding-top:.25em">24.2.0</td>
    -+      </tr>
    -+      <tr>
    -+        <td class="diffspec">From Level:</td>
    -+        <td class="diffvalueold">24.1.0</td>
    -+      </tr>
    -+      <tr>
    -+        <td class="diffspec">Generated</td>
    -+        <td class="diffvalue">2016.08.16 14:03</td>
    -+      </tr>
    -+    </table>
    -+    </div><!-- End and-diff-id -->
    -+  <div class="and-diff-id" style="margin-right:8px;">
    -+    <table class="diffspectable">
    -+      <tr>
    -+        <td class="diffspec" colspan="2"><a href="jdiff_statistics.html">Statistics</a>
    -+      </tr>
    -+    </table>
    -+  </div> <!-- End and-diff-id -->
    -+  </div> <!-- End headerRight -->
    -+  </div> <!-- End header -->
    -+<div id="body-content" xstyle="padding:12px;padding-right:18px;">
    -+<div id="doc-content" style="position:relative;">
    -+<div id="mainBodyFluid">
    -+<H2>
    -+Class android.support.v4.widget.<A HREF="../../../../reference/android/support/v4/widget/TextViewCompat.html" target="_top"><font size="+2"><code>TextViewCompat</code></font></A>
    -+</H2>
    -+<a NAME="constructors"></a>
    -+<a NAME="methods"></a>
    -+<p>
    -+<a NAME="Added"></a>
    -+<TABLE summary="Added Methods" WIDTH="100%">
    -+<TR>
    -+  <TH VALIGN="TOP" COLSPAN=2>Added Methods</FONT></TD>
    -+</TH>
    -+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    -+  <TD VALIGN="TOP" WIDTH="25%">
    -+  <A NAME="android.support.v4.widget.TextViewCompat.getCompoundDrawablesRelative_added(android.widget.TextView)"></A>
    -+  <nobr><code>Drawable[]</code>&nbsp;<A HREF="../../../../reference/android/support/v4/widget/TextViewCompat.html#getCompoundDrawablesRelative(android.widget.TextView)" target="_top"><code>getCompoundDrawablesRelative</code></A>(<code>TextView</code>)</nobr>
    -+  </TD>
    -+  <TD>&nbsp;</TD>
    -+</TR>
    -+</TABLE>
    -+&nbsp;
    -+<a NAME="fields"></a>
    -+      </div>	
    -+      <div id="footer">
    -+        <div id="copyright">
    -+        Except as noted, this content is licensed under 
    -+        <a href="http://creativecommons.org/licenses/by/2.5/"> Creative Commons Attribution 2.5</a>.
    -+        For details and restrictions, see the <a href="/license.html">Content License</a>.
    -+        </div>
    -+      <div id="footerlinks">
    -+      <p>
    -+        <a href="http://www.android.com/terms.html">Site Terms of Service</a> -
    -+        <a href="http://www.android.com/privacy.html">Privacy Policy</a> -
    -+        <a href="http://www.android.com/branding.html">Brand Guidelines</a>
    -+      </p>
    -+    </div>
    -+    </div> <!-- end footer -->
    -+    </div><!-- end doc-content -->
    -+    </div> <!-- end body-content --> 
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    -+</script>
    -+<script type="text/javascript">
    -+  try {
    -+    var pageTracker = _gat._getTracker("UA-5831155-1");
    -+    pageTracker._setAllowAnchor(true);
    -+    pageTracker._initData();
    -+    pageTracker._trackPageview();
    -+  } catch(e) {}
    -+</script>
    -+</BODY>
    -+</HTML>
    -diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v7.app.ActionBarDrawerToggle.html b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v7.app.ActionBarDrawerToggle.html
    -new file mode 100644
    -index 0000000..bc8abd6
    ---- /dev/null
    -+++ b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v7.app.ActionBarDrawerToggle.html
    -@@ -0,0 +1,129 @@
    -+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
    -+<HTML style="overflow:auto;">
    -+<HEAD>
    -+<meta name="generator" content="JDiff v1.1.0">
    -+<!-- Generated by the JDiff Javadoc doclet -->
    -+<!-- (http://www.jdiff.org) -->
    -+<meta name="description" content="JDiff is a Javadoc doclet which generates an HTML report of all the packages, classes, constructors, methods, and fields which have been removed, added or changed in any way, including their documentation, when two APIs are compared.">
    -+<meta name="keywords" content="diff, jdiff, javadiff, java diff, java difference, API difference, difference between two APIs, API diff, Javadoc, doclet">
    -+<TITLE>
    -+android.support.v7.app.ActionBarDrawerToggle
    -+</TITLE>
    -+<link href="../../../../assets/android-developer-docs.css" rel="stylesheet" type="text/css" />
    -+<link href="../stylesheet-jdiff.css" rel="stylesheet" type="text/css" />
    -+<noscript>
    -+<style type="text/css">
    -+body{overflow:auto;}
    -+#body-content{position:relative; top:0;}
    -+#doc-content{overflow:visible;border-left:3px solid #666;}
    -+#side-nav{padding:0;}
    -+#side-nav .toggle-list ul {display:block;}
    -+#resize-packages-nav{border-bottom:3px solid #666;}
    -+</style>
    -+</noscript>
    -+<style type="text/css">
    -+</style>
    -+</HEAD>
    -+<BODY>
    -+<!-- Start of nav bar -->
    -+<a name="top"></a>
    -+<div id="header" style="margin-bottom:0;padding-bottom:0;">
    -+<div id="headerLeft">
    -+<a href="../../../../index.html" tabindex="-1" target="_top"><img src="../../../../assets/images/bg_logo.png" alt="Android Developers" /></a>
    -+</div>
    -+  <div id="headerRight">
    -+  <div id="headerLinks">
    -+<!-- <img src="/assets/images/icon_world.jpg" alt="" /> -->
    -+<span class="text">
    -+<!-- &nbsp;<a href="#">English</a> | -->
    -+<nobr><a href="http://developer.android.com" target="_top">Android Developers</a> | <a href="http://www.android.com" target="_top">Android.com</a></nobr>
    -+</span>
    -+</div>
    -+  <div class="and-diff-id" style="margin-top:6px;margin-right:8px;">
    -+    <table class="diffspectable">
    -+      <tr>
    -+        <td colspan="2" class="diffspechead">API Diff Specification</td>
    -+      </tr>
    -+      <tr>
    -+        <td class="diffspec" style="padding-top:.25em">To Level:</td>
    -+        <td class="diffvaluenew" style="padding-top:.25em">24.2.0</td>
    -+      </tr>
    -+      <tr>
    -+        <td class="diffspec">From Level:</td>
    -+        <td class="diffvalueold">24.1.0</td>
    -+      </tr>
    -+      <tr>
    -+        <td class="diffspec">Generated</td>
    -+        <td class="diffvalue">2016.08.16 14:03</td>
    -+      </tr>
    -+    </table>
    -+    </div><!-- End and-diff-id -->
    -+  <div class="and-diff-id" style="margin-right:8px;">
    -+    <table class="diffspectable">
    -+      <tr>
    -+        <td class="diffspec" colspan="2"><a href="jdiff_statistics.html">Statistics</a>
    -+      </tr>
    -+    </table>
    -+  </div> <!-- End and-diff-id -->
    -+  </div> <!-- End headerRight -->
    -+  </div> <!-- End header -->
    -+<div id="body-content" xstyle="padding:12px;padding-right:18px;">
    -+<div id="doc-content" style="position:relative;">
    -+<div id="mainBodyFluid">
    -+<H2>
    -+Class android.support.v7.app.<A HREF="../../../../reference/android/support/v7/app/ActionBarDrawerToggle.html" target="_top"><font size="+2"><code>ActionBarDrawerToggle</code></font></A>
    -+</H2>
    -+<a NAME="constructors"></a>
    -+<a NAME="methods"></a>
    -+<p>
    -+<a NAME="Added"></a>
    -+<TABLE summary="Added Methods" WIDTH="100%">
    -+<TR>
    -+  <TH VALIGN="TOP" COLSPAN=2>Added Methods</FONT></TD>
    -+</TH>
    -+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    -+  <TD VALIGN="TOP" WIDTH="25%">
    -+  <A NAME="android.support.v7.app.ActionBarDrawerToggle.getDrawerArrowDrawable_added()"></A>
    -+  <nobr><code>DrawerArrowDrawable</code>&nbsp;<A HREF="../../../../reference/android/support/v7/app/ActionBarDrawerToggle.html#getDrawerArrowDrawable()" target="_top"><code>getDrawerArrowDrawable</code></A>()</nobr>
    -+  </TD>
    -+  <TD>&nbsp;</TD>
    -+</TR>
    -+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    -+  <TD VALIGN="TOP" WIDTH="25%">
    -+  <A NAME="android.support.v7.app.ActionBarDrawerToggle.setDrawerArrowDrawable_added(android.support.v7.graphics.drawable.DrawerArrowDrawable)"></A>
    -+  <nobr><code>void</code>&nbsp;<A HREF="../../../../reference/android/support/v7/app/ActionBarDrawerToggle.html#setDrawerArrowDrawable(android.support.v7.graphics.drawable.DrawerArrowDrawable)" target="_top"><code>setDrawerArrowDrawable</code></A>(<code>DrawerArrowDrawable</code>)</nobr>
    -+  </TD>
    -+  <TD>&nbsp;</TD>
    -+</TR>
    -+</TABLE>
    -+&nbsp;
    -+<a NAME="fields"></a>
    -+      </div>	
    -+      <div id="footer">
    -+        <div id="copyright">
    -+        Except as noted, this content is licensed under 
    -+        <a href="http://creativecommons.org/licenses/by/2.5/"> Creative Commons Attribution 2.5</a>.
    -+        For details and restrictions, see the <a href="/license.html">Content License</a>.
    -+        </div>
    -+      <div id="footerlinks">
    -+      <p>
    -+        <a href="http://www.android.com/terms.html">Site Terms of Service</a> -
    -+        <a href="http://www.android.com/privacy.html">Privacy Policy</a> -
    -+        <a href="http://www.android.com/branding.html">Brand Guidelines</a>
    -+      </p>
    -+    </div>
    -+    </div> <!-- end footer -->
    -+    </div><!-- end doc-content -->
    -+    </div> <!-- end body-content --> 
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    -+</script>
    -+<script type="text/javascript">
    -+  try {
    -+    var pageTracker = _gat._getTracker("UA-5831155-1");
    -+    pageTracker._setAllowAnchor(true);
    -+    pageTracker._initData();
    -+    pageTracker._trackPageview();
    -+  } catch(e) {}
    -+</script>
    -+</BODY>
    -+</HTML>
    -diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v7.app.AppCompatDelegate.html b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v7.app.AppCompatDelegate.html
    -new file mode 100644
    -index 0000000..7b131e6
    ---- /dev/null
    -+++ b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v7.app.AppCompatDelegate.html
    -@@ -0,0 +1,122 @@
    -+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
    -+<HTML style="overflow:auto;">
    -+<HEAD>
    -+<meta name="generator" content="JDiff v1.1.0">
    -+<!-- Generated by the JDiff Javadoc doclet -->
    -+<!-- (http://www.jdiff.org) -->
    -+<meta name="description" content="JDiff is a Javadoc doclet which generates an HTML report of all the packages, classes, constructors, methods, and fields which have been removed, added or changed in any way, including their documentation, when two APIs are compared.">
    -+<meta name="keywords" content="diff, jdiff, javadiff, java diff, java difference, API difference, difference between two APIs, API diff, Javadoc, doclet">
    -+<TITLE>
    -+android.support.v7.app.AppCompatDelegate
    -+</TITLE>
    -+<link href="../../../../assets/android-developer-docs.css" rel="stylesheet" type="text/css" />
    -+<link href="../stylesheet-jdiff.css" rel="stylesheet" type="text/css" />
    -+<noscript>
    -+<style type="text/css">
    -+body{overflow:auto;}
    -+#body-content{position:relative; top:0;}
    -+#doc-content{overflow:visible;border-left:3px solid #666;}
    -+#side-nav{padding:0;}
    -+#side-nav .toggle-list ul {display:block;}
    -+#resize-packages-nav{border-bottom:3px solid #666;}
    -+</style>
    -+</noscript>
    -+<style type="text/css">
    -+</style>
    -+</HEAD>
    -+<BODY>
    -+<!-- Start of nav bar -->
    -+<a name="top"></a>
    -+<div id="header" style="margin-bottom:0;padding-bottom:0;">
    -+<div id="headerLeft">
    -+<a href="../../../../index.html" tabindex="-1" target="_top"><img src="../../../../assets/images/bg_logo.png" alt="Android Developers" /></a>
    -+</div>
    -+  <div id="headerRight">
    -+  <div id="headerLinks">
    -+<!-- <img src="/assets/images/icon_world.jpg" alt="" /> -->
    -+<span class="text">
    -+<!-- &nbsp;<a href="#">English</a> | -->
    -+<nobr><a href="http://developer.android.com" target="_top">Android Developers</a> | <a href="http://www.android.com" target="_top">Android.com</a></nobr>
    -+</span>
    -+</div>
    -+  <div class="and-diff-id" style="margin-top:6px;margin-right:8px;">
    -+    <table class="diffspectable">
    -+      <tr>
    -+        <td colspan="2" class="diffspechead">API Diff Specification</td>
    -+      </tr>
    -+      <tr>
    -+        <td class="diffspec" style="padding-top:.25em">To Level:</td>
    -+        <td class="diffvaluenew" style="padding-top:.25em">24.2.0</td>
    -+      </tr>
    -+      <tr>
    -+        <td class="diffspec">From Level:</td>
    -+        <td class="diffvalueold">24.1.0</td>
    -+      </tr>
    -+      <tr>
    -+        <td class="diffspec">Generated</td>
    -+        <td class="diffvalue">2016.08.16 14:03</td>
    -+      </tr>
    -+    </table>
    -+    </div><!-- End and-diff-id -->
    -+  <div class="and-diff-id" style="margin-right:8px;">
    -+    <table class="diffspectable">
    -+      <tr>
    -+        <td class="diffspec" colspan="2"><a href="jdiff_statistics.html">Statistics</a>
    -+      </tr>
    -+    </table>
    -+  </div> <!-- End and-diff-id -->
    -+  </div> <!-- End headerRight -->
    -+  </div> <!-- End header -->
    -+<div id="body-content" xstyle="padding:12px;padding-right:18px;">
    -+<div id="doc-content" style="position:relative;">
    -+<div id="mainBodyFluid">
    -+<H2>
    -+Class android.support.v7.app.<A HREF="../../../../reference/android/support/v7/app/AppCompatDelegate.html" target="_top"><font size="+2"><code>AppCompatDelegate</code></font></A>
    -+</H2>
    -+<a NAME="constructors"></a>
    -+<a NAME="methods"></a>
    -+<p>
    -+<a NAME="Added"></a>
    -+<TABLE summary="Added Methods" WIDTH="100%">
    -+<TR>
    -+  <TH VALIGN="TOP" COLSPAN=2>Added Methods</FONT></TD>
    -+</TH>
    -+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    -+  <TD VALIGN="TOP" WIDTH="25%">
    -+  <A NAME="android.support.v7.app.AppCompatDelegate.onStart_added()"></A>
    -+  <nobr><code>void</code>&nbsp;<A HREF="../../../../reference/android/support/v7/app/AppCompatDelegate.html#onStart()" target="_top"><code>onStart</code></A>()</nobr>
    -+  </TD>
    -+  <TD>&nbsp;</TD>
    -+</TR>
    -+</TABLE>
    -+&nbsp;
    -+<a NAME="fields"></a>
    -+      </div>	
    -+      <div id="footer">
    -+        <div id="copyright">
    -+        Except as noted, this content is licensed under 
    -+        <a href="http://creativecommons.org/licenses/by/2.5/"> Creative Commons Attribution 2.5</a>.
    -+        For details and restrictions, see the <a href="/license.html">Content License</a>.
    -+        </div>
    -+      <div id="footerlinks">
    -+      <p>
    -+        <a href="http://www.android.com/terms.html">Site Terms of Service</a> -
    -+        <a href="http://www.android.com/privacy.html">Privacy Policy</a> -
    -+        <a href="http://www.android.com/branding.html">Brand Guidelines</a>
    -+      </p>
    -+    </div>
    -+    </div> <!-- end footer -->
    -+    </div><!-- end doc-content -->
    -+    </div> <!-- end body-content --> 
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    -+</script>
    -+<script type="text/javascript">
    -+  try {
    -+    var pageTracker = _gat._getTracker("UA-5831155-1");
    -+    pageTracker._setAllowAnchor(true);
    -+    pageTracker._initData();
    -+    pageTracker._trackPageview();
    -+  } catch(e) {}
    -+</script>
    -+</BODY>
    -+</HTML>
    -diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v7.content.res.AppCompatResources.html b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v7.content.res.AppCompatResources.html
    -new file mode 100644
    -index 0000000..02f43fd
    ---- /dev/null
    -+++ b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v7.content.res.AppCompatResources.html
    -@@ -0,0 +1,122 @@
    -+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
    -+<HTML style="overflow:auto;">
    -+<HEAD>
    -+<meta name="generator" content="JDiff v1.1.0">
    -+<!-- Generated by the JDiff Javadoc doclet -->
    -+<!-- (http://www.jdiff.org) -->
    -+<meta name="description" content="JDiff is a Javadoc doclet which generates an HTML report of all the packages, classes, constructors, methods, and fields which have been removed, added or changed in any way, including their documentation, when two APIs are compared.">
    -+<meta name="keywords" content="diff, jdiff, javadiff, java diff, java difference, API difference, difference between two APIs, API diff, Javadoc, doclet">
    -+<TITLE>
    -+android.support.v7.content.res.AppCompatResources
    -+</TITLE>
    -+<link href="../../../../assets/android-developer-docs.css" rel="stylesheet" type="text/css" />
    -+<link href="../stylesheet-jdiff.css" rel="stylesheet" type="text/css" />
    -+<noscript>
    -+<style type="text/css">
    -+body{overflow:auto;}
    -+#body-content{position:relative; top:0;}
    -+#doc-content{overflow:visible;border-left:3px solid #666;}
    -+#side-nav{padding:0;}
    -+#side-nav .toggle-list ul {display:block;}
    -+#resize-packages-nav{border-bottom:3px solid #666;}
    -+</style>
    -+</noscript>
    -+<style type="text/css">
    -+</style>
    -+</HEAD>
    -+<BODY>
    -+<!-- Start of nav bar -->
    -+<a name="top"></a>
    -+<div id="header" style="margin-bottom:0;padding-bottom:0;">
    -+<div id="headerLeft">
    -+<a href="../../../../index.html" tabindex="-1" target="_top"><img src="../../../../assets/images/bg_logo.png" alt="Android Developers" /></a>
    -+</div>
    -+  <div id="headerRight">
    -+  <div id="headerLinks">
    -+<!-- <img src="/assets/images/icon_world.jpg" alt="" /> -->
    -+<span class="text">
    -+<!-- &nbsp;<a href="#">English</a> | -->
    -+<nobr><a href="http://developer.android.com" target="_top">Android Developers</a> | <a href="http://www.android.com" target="_top">Android.com</a></nobr>
    -+</span>
    -+</div>
    -+  <div class="and-diff-id" style="margin-top:6px;margin-right:8px;">
    -+    <table class="diffspectable">
    -+      <tr>
    -+        <td colspan="2" class="diffspechead">API Diff Specification</td>
    -+      </tr>
    -+      <tr>
    -+        <td class="diffspec" style="padding-top:.25em">To Level:</td>
    -+        <td class="diffvaluenew" style="padding-top:.25em">24.2.0</td>
    -+      </tr>
    -+      <tr>
    -+        <td class="diffspec">From Level:</td>
    -+        <td class="diffvalueold">24.1.0</td>
    -+      </tr>
    -+      <tr>
    -+        <td class="diffspec">Generated</td>
    -+        <td class="diffvalue">2016.08.16 14:03</td>
    -+      </tr>
    -+    </table>
    -+    </div><!-- End and-diff-id -->
    -+  <div class="and-diff-id" style="margin-right:8px;">
    -+    <table class="diffspectable">
    -+      <tr>
    -+        <td class="diffspec" colspan="2"><a href="jdiff_statistics.html">Statistics</a>
    -+      </tr>
    -+    </table>
    -+  </div> <!-- End and-diff-id -->
    -+  </div> <!-- End headerRight -->
    -+  </div> <!-- End header -->
    -+<div id="body-content" xstyle="padding:12px;padding-right:18px;">
    -+<div id="doc-content" style="position:relative;">
    -+<div id="mainBodyFluid">
    -+<H2>
    -+Class android.support.v7.content.res.<A HREF="../../../../reference/android/support/v7/content/res/AppCompatResources.html" target="_top"><font size="+2"><code>AppCompatResources</code></font></A>
    -+</H2>
    -+<a NAME="constructors"></a>
    -+<a NAME="methods"></a>
    -+<p>
    -+<a NAME="Added"></a>
    -+<TABLE summary="Added Methods" WIDTH="100%">
    -+<TR>
    -+  <TH VALIGN="TOP" COLSPAN=2>Added Methods</FONT></TD>
    -+</TH>
    -+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    -+  <TD VALIGN="TOP" WIDTH="25%">
    -+  <A NAME="android.support.v7.content.res.AppCompatResources.getDrawable_added(android.content.Context, int)"></A>
    -+  <nobr><code>Drawable</code>&nbsp;<A HREF="../../../../reference/android/support/v7/content/res/AppCompatResources.html#getDrawable(android.content.Context, int)" target="_top"><code>getDrawable</code></A>(<code>Context,</nobr> int<nobr><nobr></code>)</nobr>
    -+  </TD>
    -+  <TD>&nbsp;</TD>
    -+</TR>
    -+</TABLE>
    -+&nbsp;
    -+<a NAME="fields"></a>
    -+      </div>	
    -+      <div id="footer">
    -+        <div id="copyright">
    -+        Except as noted, this content is licensed under 
    -+        <a href="http://creativecommons.org/licenses/by/2.5/"> Creative Commons Attribution 2.5</a>.
    -+        For details and restrictions, see the <a href="/license.html">Content License</a>.
    -+        </div>
    -+      <div id="footerlinks">
    -+      <p>
    -+        <a href="http://www.android.com/terms.html">Site Terms of Service</a> -
    -+        <a href="http://www.android.com/privacy.html">Privacy Policy</a> -
    -+        <a href="http://www.android.com/branding.html">Brand Guidelines</a>
    -+      </p>
    -+    </div>
    -+    </div> <!-- end footer -->
    -+    </div><!-- end doc-content -->
    -+    </div> <!-- end body-content --> 
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    -+</script>
    -+<script type="text/javascript">
    -+  try {
    -+    var pageTracker = _gat._getTracker("UA-5831155-1");
    -+    pageTracker._setAllowAnchor(true);
    -+    pageTracker._initData();
    -+    pageTracker._trackPageview();
    -+  } catch(e) {}
    -+</script>
    -+</BODY>
    -+</HTML>
    -diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v7.graphics.Palette.html b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v7.graphics.Palette.html
    -new file mode 100644
    -index 0000000..1999a48
    ---- /dev/null
    -+++ b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v7.graphics.Palette.html
    -@@ -0,0 +1,129 @@
    -+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
    -+<HTML style="overflow:auto;">
    -+<HEAD>
    -+<meta name="generator" content="JDiff v1.1.0">
    -+<!-- Generated by the JDiff Javadoc doclet -->
    -+<!-- (http://www.jdiff.org) -->
    -+<meta name="description" content="JDiff is a Javadoc doclet which generates an HTML report of all the packages, classes, constructors, methods, and fields which have been removed, added or changed in any way, including their documentation, when two APIs are compared.">
    -+<meta name="keywords" content="diff, jdiff, javadiff, java diff, java difference, API difference, difference between two APIs, API diff, Javadoc, doclet">
    -+<TITLE>
    -+android.support.v7.graphics.Palette
    -+</TITLE>
    -+<link href="../../../../assets/android-developer-docs.css" rel="stylesheet" type="text/css" />
    -+<link href="../stylesheet-jdiff.css" rel="stylesheet" type="text/css" />
    -+<noscript>
    -+<style type="text/css">
    -+body{overflow:auto;}
    -+#body-content{position:relative; top:0;}
    -+#doc-content{overflow:visible;border-left:3px solid #666;}
    -+#side-nav{padding:0;}
    -+#side-nav .toggle-list ul {display:block;}
    -+#resize-packages-nav{border-bottom:3px solid #666;}
    -+</style>
    -+</noscript>
    -+<style type="text/css">
    -+</style>
    -+</HEAD>
    -+<BODY>
    -+<!-- Start of nav bar -->
    -+<a name="top"></a>
    -+<div id="header" style="margin-bottom:0;padding-bottom:0;">
    -+<div id="headerLeft">
    -+<a href="../../../../index.html" tabindex="-1" target="_top"><img src="../../../../assets/images/bg_logo.png" alt="Android Developers" /></a>
    -+</div>
    -+  <div id="headerRight">
    -+  <div id="headerLinks">
    -+<!-- <img src="/assets/images/icon_world.jpg" alt="" /> -->
    -+<span class="text">
    -+<!-- &nbsp;<a href="#">English</a> | -->
    -+<nobr><a href="http://developer.android.com" target="_top">Android Developers</a> | <a href="http://www.android.com" target="_top">Android.com</a></nobr>
    -+</span>
    -+</div>
    -+  <div class="and-diff-id" style="margin-top:6px;margin-right:8px;">
    -+    <table class="diffspectable">
    -+      <tr>
    -+        <td colspan="2" class="diffspechead">API Diff Specification</td>
    -+      </tr>
    -+      <tr>
    -+        <td class="diffspec" style="padding-top:.25em">To Level:</td>
    -+        <td class="diffvaluenew" style="padding-top:.25em">24.2.0</td>
    -+      </tr>
    -+      <tr>
    -+        <td class="diffspec">From Level:</td>
    -+        <td class="diffvalueold">24.1.0</td>
    -+      </tr>
    -+      <tr>
    -+        <td class="diffspec">Generated</td>
    -+        <td class="diffvalue">2016.08.16 14:03</td>
    -+      </tr>
    -+    </table>
    -+    </div><!-- End and-diff-id -->
    -+  <div class="and-diff-id" style="margin-right:8px;">
    -+    <table class="diffspectable">
    -+      <tr>
    -+        <td class="diffspec" colspan="2"><a href="jdiff_statistics.html">Statistics</a>
    -+      </tr>
    -+    </table>
    -+  </div> <!-- End and-diff-id -->
    -+  </div> <!-- End headerRight -->
    -+  </div> <!-- End header -->
    -+<div id="body-content" xstyle="padding:12px;padding-right:18px;">
    -+<div id="doc-content" style="position:relative;">
    -+<div id="mainBodyFluid">
    -+<H2>
    -+Class android.support.v7.graphics.<A HREF="../../../../reference/android/support/v7/graphics/Palette.html" target="_top"><font size="+2"><code>Palette</code></font></A>
    -+</H2>
    -+<a NAME="constructors"></a>
    -+<a NAME="methods"></a>
    -+<p>
    -+<a NAME="Added"></a>
    -+<TABLE summary="Added Methods" WIDTH="100%">
    -+<TR>
    -+  <TH VALIGN="TOP" COLSPAN=2>Added Methods</FONT></TD>
    -+</TH>
    -+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    -+  <TD VALIGN="TOP" WIDTH="25%">
    -+  <A NAME="android.support.v7.graphics.Palette.getDominantColor_added(int)"></A>
    -+  <nobr><code>int</code>&nbsp;<A HREF="../../../../reference/android/support/v7/graphics/Palette.html#getDominantColor(int)" target="_top"><code>getDominantColor</code></A>(<code>int</code>)</nobr>
    -+  </TD>
    -+  <TD>&nbsp;</TD>
    -+</TR>
    -+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    -+  <TD VALIGN="TOP" WIDTH="25%">
    -+  <A NAME="android.support.v7.graphics.Palette.getDominantSwatch_added()"></A>
    -+  <nobr><code>Swatch</code>&nbsp;<A HREF="../../../../reference/android/support/v7/graphics/Palette.html#getDominantSwatch()" target="_top"><code>getDominantSwatch</code></A>()</nobr>
    -+  </TD>
    -+  <TD>&nbsp;</TD>
    -+</TR>
    -+</TABLE>
    -+&nbsp;
    -+<a NAME="fields"></a>
    -+      </div>	
    -+      <div id="footer">
    -+        <div id="copyright">
    -+        Except as noted, this content is licensed under 
    -+        <a href="http://creativecommons.org/licenses/by/2.5/"> Creative Commons Attribution 2.5</a>.
    -+        For details and restrictions, see the <a href="/license.html">Content License</a>.
    -+        </div>
    -+      <div id="footerlinks">
    -+      <p>
    -+        <a href="http://www.android.com/terms.html">Site Terms of Service</a> -
    -+        <a href="http://www.android.com/privacy.html">Privacy Policy</a> -
    -+        <a href="http://www.android.com/branding.html">Brand Guidelines</a>
    -+      </p>
    -+    </div>
    -+    </div> <!-- end footer -->
    -+    </div><!-- end doc-content -->
    -+    </div> <!-- end body-content --> 
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    -+</script>
    -+<script type="text/javascript">
    -+  try {
    -+    var pageTracker = _gat._getTracker("UA-5831155-1");
    -+    pageTracker._setAllowAnchor(true);
    -+    pageTracker._initData();
    -+    pageTracker._trackPageview();
    -+  } catch(e) {}
    -+</script>
    -+</BODY>
    -+</HTML>
    -diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v7.util.SortedList.Callback.html b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v7.util.SortedList.Callback.html
    -new file mode 100644
    -index 0000000..95be79c
    ---- /dev/null
    -+++ b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v7.util.SortedList.Callback.html
    -@@ -0,0 +1,152 @@
    -+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
    -+<HTML style="overflow:auto;">
    -+<HEAD>
    -+<meta name="generator" content="JDiff v1.1.0">
    -+<!-- Generated by the JDiff Javadoc doclet -->
    -+<!-- (http://www.jdiff.org) -->
    -+<meta name="description" content="JDiff is a Javadoc doclet which generates an HTML report of all the packages, classes, constructors, methods, and fields which have been removed, added or changed in any way, including their documentation, when two APIs are compared.">
    -+<meta name="keywords" content="diff, jdiff, javadiff, java diff, java difference, API difference, difference between two APIs, API diff, Javadoc, doclet">
    -+<TITLE>
    -+android.support.v7.util.SortedList.Callback
    -+</TITLE>
    -+<link href="../../../../assets/android-developer-docs.css" rel="stylesheet" type="text/css" />
    -+<link href="../stylesheet-jdiff.css" rel="stylesheet" type="text/css" />
    -+<noscript>
    -+<style type="text/css">
    -+body{overflow:auto;}
    -+#body-content{position:relative; top:0;}
    -+#doc-content{overflow:visible;border-left:3px solid #666;}
    -+#side-nav{padding:0;}
    -+#side-nav .toggle-list ul {display:block;}
    -+#resize-packages-nav{border-bottom:3px solid #666;}
    -+</style>
    -+</noscript>
    -+<style type="text/css">
    -+</style>
    -+</HEAD>
    -+<BODY>
    -+<!-- Start of nav bar -->
    -+<a name="top"></a>
    -+<div id="header" style="margin-bottom:0;padding-bottom:0;">
    -+<div id="headerLeft">
    -+<a href="../../../../index.html" tabindex="-1" target="_top"><img src="../../../../assets/images/bg_logo.png" alt="Android Developers" /></a>
    -+</div>
    -+  <div id="headerRight">
    -+  <div id="headerLinks">
    -+<!-- <img src="/assets/images/icon_world.jpg" alt="" /> -->
    -+<span class="text">
    -+<!-- &nbsp;<a href="#">English</a> | -->
    -+<nobr><a href="http://developer.android.com" target="_top">Android Developers</a> | <a href="http://www.android.com" target="_top">Android.com</a></nobr>
    -+</span>
    -+</div>
    -+  <div class="and-diff-id" style="margin-top:6px;margin-right:8px;">
    -+    <table class="diffspectable">
    -+      <tr>
    -+        <td colspan="2" class="diffspechead">API Diff Specification</td>
    -+      </tr>
    -+      <tr>
    -+        <td class="diffspec" style="padding-top:.25em">To Level:</td>
    -+        <td class="diffvaluenew" style="padding-top:.25em">24.2.0</td>
    -+      </tr>
    -+      <tr>
    -+        <td class="diffspec">From Level:</td>
    -+        <td class="diffvalueold">24.1.0</td>
    -+      </tr>
    -+      <tr>
    -+        <td class="diffspec">Generated</td>
    -+        <td class="diffvalue">2016.08.16 14:03</td>
    -+      </tr>
    -+    </table>
    -+    </div><!-- End and-diff-id -->
    -+  <div class="and-diff-id" style="margin-right:8px;">
    -+    <table class="diffspectable">
    -+      <tr>
    -+        <td class="diffspec" colspan="2"><a href="jdiff_statistics.html">Statistics</a>
    -+      </tr>
    -+    </table>
    -+  </div> <!-- End and-diff-id -->
    -+  </div> <!-- End headerRight -->
    -+  </div> <!-- End header -->
    -+<div id="body-content" xstyle="padding:12px;padding-right:18px;">
    -+<div id="doc-content" style="position:relative;">
    -+<div id="mainBodyFluid">
    -+<H2>
    -+Class android.support.v7.util.<A HREF="../../../../reference/android/support/v7/util/SortedList.Callback.html" target="_top"><font size="+2"><code>SortedList.Callback</code></font></A>
    -+</H2>
    -+<p><font xsize="+1">Added interface <code>android.support.v7.util.ListUpdateCallback</code>.<br></font>
    -+<a NAME="constructors"></a>
    -+<a NAME="methods"></a>
    -+<p>
    -+<a NAME="Removed"></a>
    -+<TABLE summary="Removed Methods" WIDTH="100%">
    -+<TR>
    -+  <TH VALIGN="TOP" COLSPAN=2>Removed Methods</FONT></TD>
    -+</TH>
    -+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    -+  <TD VALIGN="TOP" WIDTH="25%">
    -+  <A NAME="android.support.v7.util.SortedList.Callback.onInserted_removed(int, int)"></A>
    -+  <nobr><code>void</code>&nbsp;onInserted(<code>int,</nobr> int<nobr><nobr></code>)</nobr>
    -+  </TD>
    -+  <TD>&nbsp;</TD>
    -+</TR>
    -+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    -+  <TD VALIGN="TOP" WIDTH="25%">
    -+  <A NAME="android.support.v7.util.SortedList.Callback.onMoved_removed(int, int)"></A>
    -+  <nobr><code>void</code>&nbsp;onMoved(<code>int,</nobr> int<nobr><nobr></code>)</nobr>
    -+  </TD>
    -+  <TD>&nbsp;</TD>
    -+</TR>
    -+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    -+  <TD VALIGN="TOP" WIDTH="25%">
    -+  <A NAME="android.support.v7.util.SortedList.Callback.onRemoved_removed(int, int)"></A>
    -+  <nobr><code>void</code>&nbsp;onRemoved(<code>int,</nobr> int<nobr><nobr></code>)</nobr>
    -+  </TD>
    -+  <TD>&nbsp;</TD>
    -+</TR>
    -+</TABLE>
    -+&nbsp;
    -+<p>
    -+<a NAME="Added"></a>
    -+<TABLE summary="Added Methods" WIDTH="100%">
    -+<TR>
    -+  <TH VALIGN="TOP" COLSPAN=2>Added Methods</FONT></TD>
    -+</TH>
    -+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    -+  <TD VALIGN="TOP" WIDTH="25%">
    -+  <A NAME="android.support.v7.util.SortedList.Callback.onChanged_added(int, int, java.lang.Object)"></A>
    -+  <nobr><code>void</code>&nbsp;<A HREF="../../../../reference/android/support/v7/util/SortedList.Callback.html#onChanged(int, int, java.lang.Object)" target="_top"><code>onChanged</code></A>(<code>int,</nobr> int<nobr>,</nobr> Object<nobr><nobr></code>)</nobr>
    -+  </TD>
    -+  <TD>&nbsp;</TD>
    -+</TR>
    -+</TABLE>
    -+&nbsp;
    -+<a NAME="fields"></a>
    -+      </div>	
    -+      <div id="footer">
    -+        <div id="copyright">
    -+        Except as noted, this content is licensed under 
    -+        <a href="http://creativecommons.org/licenses/by/2.5/"> Creative Commons Attribution 2.5</a>.
    -+        For details and restrictions, see the <a href="/license.html">Content License</a>.
    -+        </div>
    -+      <div id="footerlinks">
    -+      <p>
    -+        <a href="http://www.android.com/terms.html">Site Terms of Service</a> -
    -+        <a href="http://www.android.com/privacy.html">Privacy Policy</a> -
    -+        <a href="http://www.android.com/branding.html">Brand Guidelines</a>
    -+      </p>
    -+    </div>
    -+    </div> <!-- end footer -->
    -+    </div><!-- end doc-content -->
    -+    </div> <!-- end body-content --> 
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    -+</script>
    -+<script type="text/javascript">
    -+  try {
    -+    var pageTracker = _gat._getTracker("UA-5831155-1");
    -+    pageTracker._setAllowAnchor(true);
    -+    pageTracker._initData();
    -+    pageTracker._trackPageview();
    -+  } catch(e) {}
    -+</script>
    -+</BODY>
    -+</HTML>
    -diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v7.widget.LinearLayoutManager.html b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v7.widget.LinearLayoutManager.html
    -new file mode 100644
    -index 0000000..2fdfb0e
    ---- /dev/null
    -+++ b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v7.widget.LinearLayoutManager.html
    -@@ -0,0 +1,123 @@
    -+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
    -+<HTML style="overflow:auto;">
    -+<HEAD>
    -+<meta name="generator" content="JDiff v1.1.0">
    -+<!-- Generated by the JDiff Javadoc doclet -->
    -+<!-- (http://www.jdiff.org) -->
    -+<meta name="description" content="JDiff is a Javadoc doclet which generates an HTML report of all the packages, classes, constructors, methods, and fields which have been removed, added or changed in any way, including their documentation, when two APIs are compared.">
    -+<meta name="keywords" content="diff, jdiff, javadiff, java diff, java difference, API difference, difference between two APIs, API diff, Javadoc, doclet">
    -+<TITLE>
    -+android.support.v7.widget.LinearLayoutManager
    -+</TITLE>
    -+<link href="../../../../assets/android-developer-docs.css" rel="stylesheet" type="text/css" />
    -+<link href="../stylesheet-jdiff.css" rel="stylesheet" type="text/css" />
    -+<noscript>
    -+<style type="text/css">
    -+body{overflow:auto;}
    -+#body-content{position:relative; top:0;}
    -+#doc-content{overflow:visible;border-left:3px solid #666;}
    -+#side-nav{padding:0;}
    -+#side-nav .toggle-list ul {display:block;}
    -+#resize-packages-nav{border-bottom:3px solid #666;}
    -+</style>
    -+</noscript>
    -+<style type="text/css">
    -+</style>
    -+</HEAD>
    -+<BODY>
    -+<!-- Start of nav bar -->
    -+<a name="top"></a>
    -+<div id="header" style="margin-bottom:0;padding-bottom:0;">
    -+<div id="headerLeft">
    -+<a href="../../../../index.html" tabindex="-1" target="_top"><img src="../../../../assets/images/bg_logo.png" alt="Android Developers" /></a>
    -+</div>
    -+  <div id="headerRight">
    -+  <div id="headerLinks">
    -+<!-- <img src="/assets/images/icon_world.jpg" alt="" /> -->
    -+<span class="text">
    -+<!-- &nbsp;<a href="#">English</a> | -->
    -+<nobr><a href="http://developer.android.com" target="_top">Android Developers</a> | <a href="http://www.android.com" target="_top">Android.com</a></nobr>
    -+</span>
    -+</div>
    -+  <div class="and-diff-id" style="margin-top:6px;margin-right:8px;">
    -+    <table class="diffspectable">
    -+      <tr>
    -+        <td colspan="2" class="diffspechead">API Diff Specification</td>
    -+      </tr>
    -+      <tr>
    -+        <td class="diffspec" style="padding-top:.25em">To Level:</td>
    -+        <td class="diffvaluenew" style="padding-top:.25em">24.2.0</td>
    -+      </tr>
    -+      <tr>
    -+        <td class="diffspec">From Level:</td>
    -+        <td class="diffvalueold">24.1.0</td>
    -+      </tr>
    -+      <tr>
    -+        <td class="diffspec">Generated</td>
    -+        <td class="diffvalue">2016.08.16 14:03</td>
    -+      </tr>
    -+    </table>
    -+    </div><!-- End and-diff-id -->
    -+  <div class="and-diff-id" style="margin-right:8px;">
    -+    <table class="diffspectable">
    -+      <tr>
    -+        <td class="diffspec" colspan="2"><a href="jdiff_statistics.html">Statistics</a>
    -+      </tr>
    -+    </table>
    -+  </div> <!-- End and-diff-id -->
    -+  </div> <!-- End headerRight -->
    -+  </div> <!-- End header -->
    -+<div id="body-content" xstyle="padding:12px;padding-right:18px;">
    -+<div id="doc-content" style="position:relative;">
    -+<div id="mainBodyFluid">
    -+<H2>
    -+Class android.support.v7.widget.<A HREF="../../../../reference/android/support/v7/widget/LinearLayoutManager.html" target="_top"><font size="+2"><code>LinearLayoutManager</code></font></A>
    -+</H2>
    -+<p><font xsize="+1">Added interface <code>android.support.v7.widget.RecyclerView.SmoothScroller.ScrollVectorProvider</code>.<br></font>
    -+<a NAME="constructors"></a>
    -+<a NAME="methods"></a>
    -+<p>
    -+<a NAME="Removed"></a>
    -+<TABLE summary="Removed Methods" WIDTH="100%">
    -+<TR>
    -+  <TH VALIGN="TOP" COLSPAN=2>Removed Methods</FONT></TD>
    -+</TH>
    -+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    -+  <TD VALIGN="TOP" WIDTH="25%">
    -+  <A NAME="android.support.v7.widget.LinearLayoutManager.prepareForDrop_removed(android.view.View, android.view.View, int, int)"></A>
    -+  <nobr><code>void</code>&nbsp;prepareForDrop(<code>View,</nobr> View<nobr>,</nobr> int<nobr>,</nobr> int<nobr><nobr></code>)</nobr>
    -+  </TD>
    -+  <TD>&nbsp;</TD>
    -+</TR>
    -+</TABLE>
    -+&nbsp;
    -+<a NAME="fields"></a>
    -+      </div>	
    -+      <div id="footer">
    -+        <div id="copyright">
    -+        Except as noted, this content is licensed under 
    -+        <a href="http://creativecommons.org/licenses/by/2.5/"> Creative Commons Attribution 2.5</a>.
    -+        For details and restrictions, see the <a href="/license.html">Content License</a>.
    -+        </div>
    -+      <div id="footerlinks">
    -+      <p>
    -+        <a href="http://www.android.com/terms.html">Site Terms of Service</a> -
    -+        <a href="http://www.android.com/privacy.html">Privacy Policy</a> -
    -+        <a href="http://www.android.com/branding.html">Brand Guidelines</a>
    -+      </p>
    -+    </div>
    -+    </div> <!-- end footer -->
    -+    </div><!-- end doc-content -->
    -+    </div> <!-- end body-content --> 
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    -+</script>
    -+<script type="text/javascript">
    -+  try {
    -+    var pageTracker = _gat._getTracker("UA-5831155-1");
    -+    pageTracker._setAllowAnchor(true);
    -+    pageTracker._initData();
    -+    pageTracker._trackPageview();
    -+  } catch(e) {}
    -+</script>
    -+</BODY>
    -+</HTML>
    -diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v7.widget.LinearSmoothScroller.html b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v7.widget.LinearSmoothScroller.html
    -new file mode 100644
    -index 0000000..5cf79ee
    ---- /dev/null
    -+++ b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v7.widget.LinearSmoothScroller.html
    -@@ -0,0 +1,126 @@
    -+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
    -+<HTML style="overflow:auto;">
    -+<HEAD>
    -+<meta name="generator" content="JDiff v1.1.0">
    -+<!-- Generated by the JDiff Javadoc doclet -->
    -+<!-- (http://www.jdiff.org) -->
    -+<meta name="description" content="JDiff is a Javadoc doclet which generates an HTML report of all the packages, classes, constructors, methods, and fields which have been removed, added or changed in any way, including their documentation, when two APIs are compared.">
    -+<meta name="keywords" content="diff, jdiff, javadiff, java diff, java difference, API difference, difference between two APIs, API diff, Javadoc, doclet">
    -+<TITLE>
    -+android.support.v7.widget.LinearSmoothScroller
    -+</TITLE>
    -+<link href="../../../../assets/android-developer-docs.css" rel="stylesheet" type="text/css" />
    -+<link href="../stylesheet-jdiff.css" rel="stylesheet" type="text/css" />
    -+<noscript>
    -+<style type="text/css">
    -+body{overflow:auto;}
    -+#body-content{position:relative; top:0;}
    -+#doc-content{overflow:visible;border-left:3px solid #666;}
    -+#side-nav{padding:0;}
    -+#side-nav .toggle-list ul {display:block;}
    -+#resize-packages-nav{border-bottom:3px solid #666;}
    -+</style>
    -+</noscript>
    -+<style type="text/css">
    -+</style>
    -+</HEAD>
    -+<BODY>
    -+<!-- Start of nav bar -->
    -+<a name="top"></a>
    -+<div id="header" style="margin-bottom:0;padding-bottom:0;">
    -+<div id="headerLeft">
    -+<a href="../../../../index.html" tabindex="-1" target="_top"><img src="../../../../assets/images/bg_logo.png" alt="Android Developers" /></a>
    -+</div>
    -+  <div id="headerRight">
    -+  <div id="headerLinks">
    -+<!-- <img src="/assets/images/icon_world.jpg" alt="" /> -->
    -+<span class="text">
    -+<!-- &nbsp;<a href="#">English</a> | -->
    -+<nobr><a href="http://developer.android.com" target="_top">Android Developers</a> | <a href="http://www.android.com" target="_top">Android.com</a></nobr>
    -+</span>
    -+</div>
    -+  <div class="and-diff-id" style="margin-top:6px;margin-right:8px;">
    -+    <table class="diffspectable">
    -+      <tr>
    -+        <td colspan="2" class="diffspechead">API Diff Specification</td>
    -+      </tr>
    -+      <tr>
    -+        <td class="diffspec" style="padding-top:.25em">To Level:</td>
    -+        <td class="diffvaluenew" style="padding-top:.25em">24.2.0</td>
    -+      </tr>
    -+      <tr>
    -+        <td class="diffspec">From Level:</td>
    -+        <td class="diffvalueold">24.1.0</td>
    -+      </tr>
    -+      <tr>
    -+        <td class="diffspec">Generated</td>
    -+        <td class="diffvalue">2016.08.16 14:03</td>
    -+      </tr>
    -+    </table>
    -+    </div><!-- End and-diff-id -->
    -+  <div class="and-diff-id" style="margin-right:8px;">
    -+    <table class="diffspectable">
    -+      <tr>
    -+        <td class="diffspec" colspan="2"><a href="jdiff_statistics.html">Statistics</a>
    -+      </tr>
    -+    </table>
    -+  </div> <!-- End and-diff-id -->
    -+  </div> <!-- End headerRight -->
    -+  </div> <!-- End header -->
    -+<div id="body-content" xstyle="padding:12px;padding-right:18px;">
    -+<div id="doc-content" style="position:relative;">
    -+<div id="mainBodyFluid">
    -+<H2>
    -+Class android.support.v7.widget.<A HREF="../../../../reference/android/support/v7/widget/LinearSmoothScroller.html" target="_top"><font size="+2"><code>LinearSmoothScroller</code></font></A>
    -+</H2>
    -+<p>Changed from abstract to non-abstract.
    -+<a NAME="constructors"></a>
    -+<a NAME="methods"></a>
    -+<p>
    -+<a NAME="Changed"></a>
    -+<TABLE summary="Changed Methods" WIDTH="100%">
    -+<TR>
    -+  <TH VALIGN="TOP" COLSPAN=3>Changed Methods</FONT></TD>
    -+</TH>
    -+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    -+  <TD VALIGN="TOP" WIDTH="25%">
    -+  <A NAME="android.support.v7.widget.LinearSmoothScroller.computeScrollVectorForPosition_changed(int)"></A>
    -+  <nobr><code>PointF</code>&nbsp;<A HREF="../../../../reference/android/support/v7/widget/LinearSmoothScroller.html#computeScrollVectorForPosition(int)" target="_top"><code>computeScrollVectorForPosition</code></A>(<code>int</code>)  </nobr>
    -+  </TD>
    -+  <TD VALIGN="TOP" WIDTH="30%">
    -+Changed from abstract to non-abstract.
    -+  </TD>
    -+  <TD>&nbsp;</TD>
    -+</TR>
    -+</TABLE>
    -+&nbsp;
    -+<a NAME="fields"></a>
    -+      </div>	
    -+      <div id="footer">
    -+        <div id="copyright">
    -+        Except as noted, this content is licensed under 
    -+        <a href="http://creativecommons.org/licenses/by/2.5/"> Creative Commons Attribution 2.5</a>.
    -+        For details and restrictions, see the <a href="/license.html">Content License</a>.
    -+        </div>
    -+      <div id="footerlinks">
    -+      <p>
    -+        <a href="http://www.android.com/terms.html">Site Terms of Service</a> -
    -+        <a href="http://www.android.com/privacy.html">Privacy Policy</a> -
    -+        <a href="http://www.android.com/branding.html">Brand Guidelines</a>
    -+      </p>
    -+    </div>
    -+    </div> <!-- end footer -->
    -+    </div><!-- end doc-content -->
    -+    </div> <!-- end body-content --> 
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    -+</script>
    -+<script type="text/javascript">
    -+  try {
    -+    var pageTracker = _gat._getTracker("UA-5831155-1");
    -+    pageTracker._setAllowAnchor(true);
    -+    pageTracker._initData();
    -+    pageTracker._trackPageview();
    -+  } catch(e) {}
    -+</script>
    -+</BODY>
    -+</HTML>
    -diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v7.widget.RecyclerView.html b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v7.widget.RecyclerView.html
    -new file mode 100644
    -index 0000000..5411a1f
    ---- /dev/null
    -+++ b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v7.widget.RecyclerView.html
    -@@ -0,0 +1,130 @@
    -+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
    -+<HTML style="overflow:auto;">
    -+<HEAD>
    -+<meta name="generator" content="JDiff v1.1.0">
    -+<!-- Generated by the JDiff Javadoc doclet -->
    -+<!-- (http://www.jdiff.org) -->
    -+<meta name="description" content="JDiff is a Javadoc doclet which generates an HTML report of all the packages, classes, constructors, methods, and fields which have been removed, added or changed in any way, including their documentation, when two APIs are compared.">
    -+<meta name="keywords" content="diff, jdiff, javadiff, java diff, java difference, API difference, difference between two APIs, API diff, Javadoc, doclet">
    -+<TITLE>
    -+android.support.v7.widget.RecyclerView
    -+</TITLE>
    -+<link href="../../../../assets/android-developer-docs.css" rel="stylesheet" type="text/css" />
    -+<link href="../stylesheet-jdiff.css" rel="stylesheet" type="text/css" />
    -+<noscript>
    -+<style type="text/css">
    -+body{overflow:auto;}
    -+#body-content{position:relative; top:0;}
    -+#doc-content{overflow:visible;border-left:3px solid #666;}
    -+#side-nav{padding:0;}
    -+#side-nav .toggle-list ul {display:block;}
    -+#resize-packages-nav{border-bottom:3px solid #666;}
    -+</style>
    -+</noscript>
    -+<style type="text/css">
    -+</style>
    -+</HEAD>
    -+<BODY>
    -+<!-- Start of nav bar -->
    -+<a name="top"></a>
    -+<div id="header" style="margin-bottom:0;padding-bottom:0;">
    -+<div id="headerLeft">
    -+<a href="../../../../index.html" tabindex="-1" target="_top"><img src="../../../../assets/images/bg_logo.png" alt="Android Developers" /></a>
    -+</div>
    -+  <div id="headerRight">
    -+  <div id="headerLinks">
    -+<!-- <img src="/assets/images/icon_world.jpg" alt="" /> -->
    -+<span class="text">
    -+<!-- &nbsp;<a href="#">English</a> | -->
    -+<nobr><a href="http://developer.android.com" target="_top">Android Developers</a> | <a href="http://www.android.com" target="_top">Android.com</a></nobr>
    -+</span>
    -+</div>
    -+  <div class="and-diff-id" style="margin-top:6px;margin-right:8px;">
    -+    <table class="diffspectable">
    -+      <tr>
    -+        <td colspan="2" class="diffspechead">API Diff Specification</td>
    -+      </tr>
    -+      <tr>
    -+        <td class="diffspec" style="padding-top:.25em">To Level:</td>
    -+        <td class="diffvaluenew" style="padding-top:.25em">24.2.0</td>
    -+      </tr>
    -+      <tr>
    -+        <td class="diffspec">From Level:</td>
    -+        <td class="diffvalueold">24.1.0</td>
    -+      </tr>
    -+      <tr>
    -+        <td class="diffspec">Generated</td>
    -+        <td class="diffvalue">2016.08.16 14:03</td>
    -+      </tr>
    -+    </table>
    -+    </div><!-- End and-diff-id -->
    -+  <div class="and-diff-id" style="margin-right:8px;">
    -+    <table class="diffspectable">
    -+      <tr>
    -+        <td class="diffspec" colspan="2"><a href="jdiff_statistics.html">Statistics</a>
    -+      </tr>
    -+    </table>
    -+  </div> <!-- End and-diff-id -->
    -+  </div> <!-- End headerRight -->
    -+  </div> <!-- End header -->
    -+<div id="body-content" xstyle="padding:12px;padding-right:18px;">
    -+<div id="doc-content" style="position:relative;">
    -+<div id="mainBodyFluid">
    -+<H2>
    -+Class android.support.v7.widget.<A HREF="../../../../reference/android/support/v7/widget/RecyclerView.html" target="_top"><font size="+2"><code>RecyclerView</code></font></A>
    -+</H2>
    -+<p><font xsize="+1">Added interfaces <code>android.support.v4.view.NestedScrollingChild, android.support.v4.view.ScrollingView</code>.<br></font>
    -+<a NAME="constructors"></a>
    -+<a NAME="methods"></a>
    -+<p>
    -+<a NAME="Added"></a>
    -+<TABLE summary="Added Methods" WIDTH="100%">
    -+<TR>
    -+  <TH VALIGN="TOP" COLSPAN=2>Added Methods</FONT></TD>
    -+</TH>
    -+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    -+  <TD VALIGN="TOP" WIDTH="25%">
    -+  <A NAME="android.support.v7.widget.RecyclerView.getOnFlingListener_added()"></A>
    -+  <nobr><code>OnFlingListener</code>&nbsp;<A HREF="../../../../reference/android/support/v7/widget/RecyclerView.html#getOnFlingListener()" target="_top"><code>getOnFlingListener</code></A>()</nobr>
    -+  </TD>
    -+  <TD>&nbsp;</TD>
    -+</TR>
    -+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    -+  <TD VALIGN="TOP" WIDTH="25%">
    -+  <A NAME="android.support.v7.widget.RecyclerView.setOnFlingListener_added(android.support.v7.widget.RecyclerView.OnFlingListener)"></A>
    -+  <nobr><code>void</code>&nbsp;<A HREF="../../../../reference/android/support/v7/widget/RecyclerView.html#setOnFlingListener(android.support.v7.widget.RecyclerView.OnFlingListener)" target="_top"><code>setOnFlingListener</code></A>(<code>OnFlingListener</code>)</nobr>
    -+  </TD>
    -+  <TD>&nbsp;</TD>
    -+</TR>
    -+</TABLE>
    -+&nbsp;
    -+<a NAME="fields"></a>
    -+      </div>	
    -+      <div id="footer">
    -+        <div id="copyright">
    -+        Except as noted, this content is licensed under 
    -+        <a href="http://creativecommons.org/licenses/by/2.5/"> Creative Commons Attribution 2.5</a>.
    -+        For details and restrictions, see the <a href="/license.html">Content License</a>.
    -+        </div>
    -+      <div id="footerlinks">
    -+      <p>
    -+        <a href="http://www.android.com/terms.html">Site Terms of Service</a> -
    -+        <a href="http://www.android.com/privacy.html">Privacy Policy</a> -
    -+        <a href="http://www.android.com/branding.html">Brand Guidelines</a>
    -+      </p>
    -+    </div>
    -+    </div> <!-- end footer -->
    -+    </div><!-- end doc-content -->
    -+    </div> <!-- end body-content --> 
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    -+</script>
    -+<script type="text/javascript">
    -+  try {
    -+    var pageTracker = _gat._getTracker("UA-5831155-1");
    -+    pageTracker._setAllowAnchor(true);
    -+    pageTracker._initData();
    -+    pageTracker._trackPageview();
    -+  } catch(e) {}
    -+</script>
    -+</BODY>
    -+</HTML>
    -diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v7.widget.StaggeredGridLayoutManager.html b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v7.widget.StaggeredGridLayoutManager.html
    -new file mode 100644
    -index 0000000..9d0ab87
    ---- /dev/null
    -+++ b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v7.widget.StaggeredGridLayoutManager.html
    -@@ -0,0 +1,138 @@
    -+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
    -+<HTML style="overflow:auto;">
    -+<HEAD>
    -+<meta name="generator" content="JDiff v1.1.0">
    -+<!-- Generated by the JDiff Javadoc doclet -->
    -+<!-- (http://www.jdiff.org) -->
    -+<meta name="description" content="JDiff is a Javadoc doclet which generates an HTML report of all the packages, classes, constructors, methods, and fields which have been removed, added or changed in any way, including their documentation, when two APIs are compared.">
    -+<meta name="keywords" content="diff, jdiff, javadiff, java diff, java difference, API difference, difference between two APIs, API diff, Javadoc, doclet">
    -+<TITLE>
    -+android.support.v7.widget.StaggeredGridLayoutManager
    -+</TITLE>
    -+<link href="../../../../assets/android-developer-docs.css" rel="stylesheet" type="text/css" />
    -+<link href="../stylesheet-jdiff.css" rel="stylesheet" type="text/css" />
    -+<noscript>
    -+<style type="text/css">
    -+body{overflow:auto;}
    -+#body-content{position:relative; top:0;}
    -+#doc-content{overflow:visible;border-left:3px solid #666;}
    -+#side-nav{padding:0;}
    -+#side-nav .toggle-list ul {display:block;}
    -+#resize-packages-nav{border-bottom:3px solid #666;}
    -+</style>
    -+</noscript>
    -+<style type="text/css">
    -+</style>
    -+</HEAD>
    -+<BODY>
    -+<!-- Start of nav bar -->
    -+<a name="top"></a>
    -+<div id="header" style="margin-bottom:0;padding-bottom:0;">
    -+<div id="headerLeft">
    -+<a href="../../../../index.html" tabindex="-1" target="_top"><img src="../../../../assets/images/bg_logo.png" alt="Android Developers" /></a>
    -+</div>
    -+  <div id="headerRight">
    -+  <div id="headerLinks">
    -+<!-- <img src="/assets/images/icon_world.jpg" alt="" /> -->
    -+<span class="text">
    -+<!-- &nbsp;<a href="#">English</a> | -->
    -+<nobr><a href="http://developer.android.com" target="_top">Android Developers</a> | <a href="http://www.android.com" target="_top">Android.com</a></nobr>
    -+</span>
    -+</div>
    -+  <div class="and-diff-id" style="margin-top:6px;margin-right:8px;">
    -+    <table class="diffspectable">
    -+      <tr>
    -+        <td colspan="2" class="diffspechead">API Diff Specification</td>
    -+      </tr>
    -+      <tr>
    -+        <td class="diffspec" style="padding-top:.25em">To Level:</td>
    -+        <td class="diffvaluenew" style="padding-top:.25em">24.2.0</td>
    -+      </tr>
    -+      <tr>
    -+        <td class="diffspec">From Level:</td>
    -+        <td class="diffvalueold">24.1.0</td>
    -+      </tr>
    -+      <tr>
    -+        <td class="diffspec">Generated</td>
    -+        <td class="diffvalue">2016.08.16 14:03</td>
    -+      </tr>
    -+    </table>
    -+    </div><!-- End and-diff-id -->
    -+  <div class="and-diff-id" style="margin-right:8px;">
    -+    <table class="diffspectable">
    -+      <tr>
    -+        <td class="diffspec" colspan="2"><a href="jdiff_statistics.html">Statistics</a>
    -+      </tr>
    -+    </table>
    -+  </div> <!-- End and-diff-id -->
    -+  </div> <!-- End headerRight -->
    -+  </div> <!-- End header -->
    -+<div id="body-content" xstyle="padding:12px;padding-right:18px;">
    -+<div id="doc-content" style="position:relative;">
    -+<div id="mainBodyFluid">
    -+<H2>
    -+Class android.support.v7.widget.<A HREF="../../../../reference/android/support/v7/widget/StaggeredGridLayoutManager.html" target="_top"><font size="+2"><code>StaggeredGridLayoutManager</code></font></A>
    -+</H2>
    -+<p><font xsize="+1">Added interface <code>android.support.v7.widget.RecyclerView.SmoothScroller.ScrollVectorProvider</code>.<br></font>
    -+<a NAME="constructors"></a>
    -+<a NAME="methods"></a>
    -+<p>
    -+<a NAME="Added"></a>
    -+<TABLE summary="Added Methods" WIDTH="100%">
    -+<TR>
    -+  <TH VALIGN="TOP" COLSPAN=2>Added Methods</FONT></TD>
    -+</TH>
    -+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    -+  <TD VALIGN="TOP" WIDTH="25%">
    -+  <A NAME="android.support.v7.widget.StaggeredGridLayoutManager.computeScrollVectorForPosition_added(int)"></A>
    -+  <nobr><code>PointF</code>&nbsp;<A HREF="../../../../reference/android/support/v7/widget/StaggeredGridLayoutManager.html#computeScrollVectorForPosition(int)" target="_top"><code>computeScrollVectorForPosition</code></A>(<code>int</code>)</nobr>
    -+  </TD>
    -+  <TD>&nbsp;</TD>
    -+</TR>
    -+</TABLE>
    -+&nbsp;
    -+<a NAME="fields"></a>
    -+<p>
    -+<a NAME="Removed"></a>
    -+<TABLE summary="Removed Fields" WIDTH="100%">
    -+<TR>
    -+  <TH VALIGN="TOP" COLSPAN=2>Removed Fields</FONT></TD>
    -+</TH>
    -+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    -+  <TD VALIGN="TOP" WIDTH="25%">
    -+  <A NAME="android.support.v7.widget.StaggeredGridLayoutManager.TAG"></A>
    -+  <code>String</code>&nbsp;TAG
    -+  </TD>
    -+  <TD>&nbsp;</TD>
    -+</TR>
    -+</TABLE>
    -+&nbsp;
    -+      </div>	
    -+      <div id="footer">
    -+        <div id="copyright">
    -+        Except as noted, this content is licensed under 
    -+        <a href="http://creativecommons.org/licenses/by/2.5/"> Creative Commons Attribution 2.5</a>.
    -+        For details and restrictions, see the <a href="/license.html">Content License</a>.
    -+        </div>
    -+      <div id="footerlinks">
    -+      <p>
    -+        <a href="http://www.android.com/terms.html">Site Terms of Service</a> -
    -+        <a href="http://www.android.com/privacy.html">Privacy Policy</a> -
    -+        <a href="http://www.android.com/branding.html">Brand Guidelines</a>
    -+      </p>
    -+    </div>
    -+    </div> <!-- end footer -->
    -+    </div><!-- end doc-content -->
    -+    </div> <!-- end body-content --> 
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    -+</script>
    -+<script type="text/javascript">
    -+  try {
    -+    var pageTracker = _gat._getTracker("UA-5831155-1");
    -+    pageTracker._setAllowAnchor(true);
    -+    pageTracker._initData();
    -+    pageTracker._trackPageview();
    -+  } catch(e) {}
    -+</script>
    -+</BODY>
    -+</HTML>
    -diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/changes-summary.html b/docs/html/sdk/support_api_diff/24.2.0/changes/changes-summary.html
    -new file mode 100644
    -index 0000000..4456c22
    ---- /dev/null
    -+++ b/docs/html/sdk/support_api_diff/24.2.0/changes/changes-summary.html
    -@@ -0,0 +1,329 @@
    -+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
    -+<HTML style="overflow:auto;">
    -+<HEAD>
    -+<meta name="generator" content="JDiff v1.1.0">
    -+<!-- Generated by the JDiff Javadoc doclet -->
    -+<!-- (http://www.jdiff.org) -->
    -+<meta name="description" content="JDiff is a Javadoc doclet which generates an HTML report of all the packages, classes, constructors, methods, and fields which have been removed, added or changed in any way, including their documentation, when two APIs are compared.">
    -+<meta name="keywords" content="diff, jdiff, javadiff, java diff, java difference, API difference, difference between two APIs, API diff, Javadoc, doclet">
    -+<TITLE>
    -+Support&nbsp;Library&nbsp;API&nbsp;Differences&nbsp;Report
    -+</TITLE>
    -+<link href="../../../../assets/android-developer-docs.css" rel="stylesheet" type="text/css" />
    -+<link href="../stylesheet-jdiff.css" rel="stylesheet" type="text/css" />
    -+<noscript>
    -+<style type="text/css">
    -+body{overflow:auto;}
    -+#body-content{position:relative; top:0;}
    -+#doc-content{overflow:visible;border-left:3px solid #666;}
    -+#side-nav{padding:0;}
    -+#side-nav .toggle-list ul {display:block;}
    -+#resize-packages-nav{border-bottom:3px solid #666;}
    -+</style>
    -+</noscript>
    -+<style type="text/css">
    -+</style>
    -+</HEAD>
    -+<body class="gc-documentation">
    -+<!-- Start of nav bar -->
    -+<a name="top"></a>
    -+<div id="header" style="margin-bottom:0;padding-bottom:0;">
    -+<div id="headerLeft">
    -+<a href="../../../../index.html" tabindex="-1" target="_top"><img src="../../../../assets/images/bg_logo.png" alt="Android Developers" /></a>
    -+</div>
    -+  <div id="headerRight">
    -+  <div id="headerLinks">
    -+<!-- <img src="/assets/images/icon_world.jpg" alt="" /> -->
    -+<span class="text">
    -+<!-- &nbsp;<a href="#">English</a> | -->
    -+<nobr><a href="http://developer.android.com" target="_top">Android Developers</a> | <a href="http://www.android.com" target="_top">Android.com</a></nobr>
    -+</span>
    -+</div>
    -+  <div class="and-diff-id" style="margin-top:6px;margin-right:8px;">
    -+    <table class="diffspectable">
    -+      <tr>
    -+        <td colspan="2" class="diffspechead">API Diff Specification</td>
    -+      </tr>
    -+      <tr>
    -+        <td class="diffspec" style="padding-top:.25em">To Level:</td>
    -+        <td class="diffvaluenew" style="padding-top:.25em">24.2.0</td>
    -+      </tr>
    -+      <tr>
    -+        <td class="diffspec">From Level:</td>
    -+        <td class="diffvalueold">24.1.0</td>
    -+      </tr>
    -+      <tr>
    -+        <td class="diffspec">Generated</td>
    -+        <td class="diffvalue">2016.08.16 14:03</td>
    -+      </tr>
    -+    </table>
    -+    </div><!-- End and-diff-id -->
    -+  <div class="and-diff-id" style="margin-right:8px;">
    -+    <table class="diffspectable">
    -+      <tr>
    -+        <td class="diffspec" colspan="2"><a href="jdiff_statistics.html">Statistics</a>
    -+      </tr>
    -+    </table>
    -+  </div> <!-- End and-diff-id -->
    -+  </div> <!-- End headerRight -->
    -+  </div> <!-- End header -->
    -+<div id="body-content" xstyle="padding:12px;padding-right:18px;">
    -+<div id="doc-content" style="position:relative;">
    -+<div id="mainBodyFluid">
    -+    <div id="docTitleContainer">
    -+    <h1>Support&nbsp;Library&nbsp;API&nbsp;Differences&nbsp;Report</h1>
    -+<p>This report details the changes in the Android Support Library API between two versions. 
    -+It shows additions, modifications, and removals for packages, classes, methods, and fields. 
    -+The report also includes general statistics that characterize the extent and type of the differences.</p>
    -+<p>This report is based a comparison of the Support Library API specifications 
    -+whose version level identifiers are given in the upper-right corner of this page. It compares a 
    -+newer "to" version's API to an older "from" version's API, noting all changes relative to the 
    -+older API. So, for example, API elements marked as removed are no longer present in the "to" 
    -+API specification.</p>
    -+<p>To navigate the report, use the "Select a Diffs Index" and "Filter the Index" 
    -+controls on the left. The report uses text formatting to indicate <em>interface names</em>, 
    -+<a href= ><code>links to reference documentation</code></a>, and <a href= >links to change 
    -+description</a>. The statistics are accessible from the "Statistics" link in the upper-right corner.</p>
    -+<p>For more information about the Android API and SDK, 
    -+see the <a href="http://developer.android.com/index.html" target="_top">Android Developers site</a>.</p>
    -+<p>
    -+<a NAME="Removed"></a>
    -+<TABLE summary="Removed Packages" WIDTH="100%">
    -+<TR>
    -+  <TH VALIGN="TOP" COLSPAN=2>Removed Packages</FONT></TD>
    -+</TH>
    -+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    -+  <TD VALIGN="TOP" WIDTH="25%">
    -+  <A NAME="android.support.v7.appcompat"></A>
    -+  android.support.v7.appcompat  </TD>
    -+  <TD>&nbsp;</TD>
    -+</TR>
    -+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    -+  <TD VALIGN="TOP" WIDTH="25%">
    -+  <A NAME="android.support.v7.recyclerview"></A>
    -+  android.support.v7.recyclerview  </TD>
    -+  <TD>&nbsp;</TD>
    -+</TR>
    -+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    -+  <TD VALIGN="TOP" WIDTH="25%">
    -+  <A NAME="android.support.v8.renderscript"></A>
    -+  android.support.v8.renderscript  </TD>
    -+  <TD>&nbsp;</TD>
    -+</TR>
    -+</TABLE>
    -+&nbsp;
    -+<p>
    -+<a NAME="Added"></a>
    -+<TABLE summary="Added Packages" WIDTH="100%">
    -+<TR>
    -+  <TH VALIGN="TOP" COLSPAN=2>Added Packages</FONT></TD>
    -+</TH>
    -+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    -+  <TD VALIGN="TOP" WIDTH="25%">
    -+  <A NAME="android.support.transition"></A>
    -+  <nobr><A HREF="../../../../reference/android/support/transition/package-summary.html" target="_top"><code>android.support.transition</code></A></nobr>
    -+  </TD>
    -+  <TD>&nbsp;</TD>
    -+</TR>
    -+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    -+  <TD VALIGN="TOP" WIDTH="25%">
    -+  <A NAME="android.support.v4.text.util"></A>
    -+  <nobr><A HREF="../../../../reference/android/support/v4/text/util/package-summary.html" target="_top"><code>android.support.v4.text.util</code></A></nobr>
    -+  </TD>
    -+  <TD>&nbsp;</TD>
    -+</TR>
    -+</TABLE>
    -+&nbsp;
    -+<p>
    -+<a NAME="Changed"></a>
    -+<TABLE summary="Changed Packages" WIDTH="100%">
    -+<TR>
    -+  <TH VALIGN="TOP" COLSPAN=3>Changed Packages</FONT></TD>
    -+</TH>
    -+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    -+  <TD VALIGN="TOP" WIDTH="25%">
    -+  <A NAME="android.support.customtabs"></A>
    -+  <nobr><A HREF="pkg_android.support.customtabs.html">android.support.customtabs</A></nobr>
    -+  </TD>
    -+  <TD>&nbsp;</TD>
    -+</TR>
    -+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    -+  <TD VALIGN="TOP" WIDTH="25%">
    -+  <A NAME="android.support.design.widget"></A>
    -+  <nobr><A HREF="pkg_android.support.design.widget.html">android.support.design.widget</A></nobr>
    -+  </TD>
    -+  <TD>&nbsp;</TD>
    -+</TR>
    -+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    -+  <TD VALIGN="TOP" WIDTH="25%">
    -+  <A NAME="android.support.v14.preference"></A>
    -+  <nobr><A HREF="pkg_android.support.v14.preference.html">android.support.v14.preference</A></nobr>
    -+  </TD>
    -+  <TD>&nbsp;</TD>
    -+</TR>
    -+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    -+  <TD VALIGN="TOP" WIDTH="25%">
    -+  <A NAME="android.support.v17.leanback.widget"></A>
    -+  <nobr><A HREF="pkg_android.support.v17.leanback.widget.html">android.support.v17.leanback.widget</A></nobr>
    -+  </TD>
    -+  <TD>&nbsp;</TD>
    -+</TR>
    -+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    -+  <TD VALIGN="TOP" WIDTH="25%">
    -+  <A NAME="android.support.v17.preference"></A>
    -+  <nobr><A HREF="pkg_android.support.v17.preference.html">android.support.v17.preference</A></nobr>
    -+  </TD>
    -+  <TD>&nbsp;</TD>
    -+</TR>
    -+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    -+  <TD VALIGN="TOP" WIDTH="25%">
    -+  <A NAME="android.support.v4.accessibilityservice"></A>
    -+  <nobr><A HREF="pkg_android.support.v4.accessibilityservice.html">android.support.v4.accessibilityservice</A></nobr>
    -+  </TD>
    -+  <TD>&nbsp;</TD>
    -+</TR>
    -+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    -+  <TD VALIGN="TOP" WIDTH="25%">
    -+  <A NAME="android.support.v4.app"></A>
    -+  <nobr><A HREF="pkg_android.support.v4.app.html">android.support.v4.app</A></nobr>
    -+  </TD>
    -+  <TD>&nbsp;</TD>
    -+</TR>
    -+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    -+  <TD VALIGN="TOP" WIDTH="25%">
    -+  <A NAME="android.support.v4.content"></A>
    -+  <nobr><A HREF="pkg_android.support.v4.content.html">android.support.v4.content</A></nobr>
    -+  </TD>
    -+  <TD>&nbsp;</TD>
    -+</TR>
    -+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    -+  <TD VALIGN="TOP" WIDTH="25%">
    -+  <A NAME="android.support.v4.graphics.drawable"></A>
    -+  <nobr><A HREF="pkg_android.support.v4.graphics.drawable.html">android.support.v4.graphics.drawable</A></nobr>
    -+  </TD>
    -+  <TD>&nbsp;</TD>
    -+</TR>
    -+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    -+  <TD VALIGN="TOP" WIDTH="25%">
    -+  <A NAME="android.support.v4.media"></A>
    -+  <nobr><A HREF="pkg_android.support.v4.media.html">android.support.v4.media</A></nobr>
    -+  </TD>
    -+  <TD>&nbsp;</TD>
    -+</TR>
    -+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    -+  <TD VALIGN="TOP" WIDTH="25%">
    -+  <A NAME="android.support.v4.media.session"></A>
    -+  <nobr><A HREF="pkg_android.support.v4.media.session.html">android.support.v4.media.session</A></nobr>
    -+  </TD>
    -+  <TD>&nbsp;</TD>
    -+</TR>
    -+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    -+  <TD VALIGN="TOP" WIDTH="25%">
    -+  <A NAME="android.support.v4.os"></A>
    -+  <nobr><A HREF="pkg_android.support.v4.os.html">android.support.v4.os</A></nobr>
    -+  </TD>
    -+  <TD>&nbsp;</TD>
    -+</TR>
    -+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    -+  <TD VALIGN="TOP" WIDTH="25%">
    -+  <A NAME="android.support.v4.util"></A>
    -+  <nobr><A HREF="pkg_android.support.v4.util.html">android.support.v4.util</A></nobr>
    -+  </TD>
    -+  <TD>&nbsp;</TD>
    -+</TR>
    -+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    -+  <TD VALIGN="TOP" WIDTH="25%">
    -+  <A NAME="android.support.v4.view"></A>
    -+  <nobr><A HREF="pkg_android.support.v4.view.html">android.support.v4.view</A></nobr>
    -+  </TD>
    -+  <TD>&nbsp;</TD>
    -+</TR>
    -+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    -+  <TD VALIGN="TOP" WIDTH="25%">
    -+  <A NAME="android.support.v4.view.accessibility"></A>
    -+  <nobr><A HREF="pkg_android.support.v4.view.accessibility.html">android.support.v4.view.accessibility</A></nobr>
    -+  </TD>
    -+  <TD>&nbsp;</TD>
    -+</TR>
    -+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    -+  <TD VALIGN="TOP" WIDTH="25%">
    -+  <A NAME="android.support.v4.widget"></A>
    -+  <nobr><A HREF="pkg_android.support.v4.widget.html">android.support.v4.widget</A></nobr>
    -+  </TD>
    -+  <TD>&nbsp;</TD>
    -+</TR>
    -+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    -+  <TD VALIGN="TOP" WIDTH="25%">
    -+  <A NAME="android.support.v7.app"></A>
    -+  <nobr><A HREF="pkg_android.support.v7.app.html">android.support.v7.app</A></nobr>
    -+  </TD>
    -+  <TD>&nbsp;</TD>
    -+</TR>
    -+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    -+  <TD VALIGN="TOP" WIDTH="25%">
    -+  <A NAME="android.support.v7.content.res"></A>
    -+  <nobr><A HREF="pkg_android.support.v7.content.res.html">android.support.v7.content.res</A></nobr>
    -+  </TD>
    -+  <TD>&nbsp;</TD>
    -+</TR>
    -+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    -+  <TD VALIGN="TOP" WIDTH="25%">
    -+  <A NAME="android.support.v7.graphics"></A>
    -+  <nobr><A HREF="pkg_android.support.v7.graphics.html">android.support.v7.graphics</A></nobr>
    -+  </TD>
    -+  <TD>&nbsp;</TD>
    -+</TR>
    -+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    -+  <TD VALIGN="TOP" WIDTH="25%">
    -+  <A NAME="android.support.v7.preference"></A>
    -+  <nobr><A HREF="pkg_android.support.v7.preference.html">android.support.v7.preference</A></nobr>
    -+  </TD>
    -+  <TD>&nbsp;</TD>
    -+</TR>
    -+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    -+  <TD VALIGN="TOP" WIDTH="25%">
    -+  <A NAME="android.support.v7.util"></A>
    -+  <nobr><A HREF="pkg_android.support.v7.util.html">android.support.v7.util</A></nobr>
    -+  </TD>
    -+  <TD>&nbsp;</TD>
    -+</TR>
    -+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    -+  <TD VALIGN="TOP" WIDTH="25%">
    -+  <A NAME="android.support.v7.widget"></A>
    -+  <nobr><A HREF="pkg_android.support.v7.widget.html">android.support.v7.widget</A></nobr>
    -+  </TD>
    -+  <TD>&nbsp;</TD>
    -+</TR>
    -+</TABLE>
    -+&nbsp;
    -+<!-- End of API section -->
    -+<!-- Start of packages section -->
    -+      </div>	
    -+      <div id="footer">
    -+        <div id="copyright">
    -+        Except as noted, this content is licensed under 
    -+        <a href="http://creativecommons.org/licenses/by/2.5/"> Creative Commons Attribution 2.5</a>.
    -+        For details and restrictions, see the <a href="/license.html">Content License</a>.
    -+        </div>
    -+      <div id="footerlinks">
    -+      <p>
    -+        <a href="http://www.android.com/terms.html">Site Terms of Service</a> -
    -+        <a href="http://www.android.com/privacy.html">Privacy Policy</a> -
    -+        <a href="http://www.android.com/branding.html">Brand Guidelines</a>
    -+      </p>
    -+    </div>
    -+    </div> <!-- end footer -->
    -+    </div><!-- end doc-content -->
    -+    </div> <!-- end body-content --> 
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    -+</script>
    -+<script type="text/javascript">
    -+  try {
    -+    var pageTracker = _gat._getTracker("UA-5831155-1");
    -+    pageTracker._setAllowAnchor(true);
    -+    pageTracker._initData();
    -+    pageTracker._trackPageview();
    -+  } catch(e) {}
    -+</script>
    -+</BODY>
    -+</HTML>
    -diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/classes_index_additions.html b/docs/html/sdk/support_api_diff/24.2.0/changes/classes_index_additions.html
    -new file mode 100644
    -index 0000000..acb8115
    ---- /dev/null
    -+++ b/docs/html/sdk/support_api_diff/24.2.0/changes/classes_index_additions.html
    -@@ -0,0 +1,305 @@
    -+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
    -+<HTML style="overflow:auto;">
    -+<HEAD>
    -+<meta name="generator" content="JDiff v1.1.0">
    -+<!-- Generated by the JDiff Javadoc doclet -->
    -+<!-- (http://www.jdiff.org) -->
    -+<meta name="description" content="JDiff is a Javadoc doclet which generates an HTML report of all the packages, classes, constructors, methods, and fields which have been removed, added or changed in any way, including their documentation, when two APIs are compared.">
    -+<meta name="keywords" content="diff, jdiff, javadiff, java diff, java difference, API difference, difference between two APIs, API diff, Javadoc, doclet">
    -+<TITLE>
    -+Class Additions Index
    -+</TITLE>
    -+<link href="../../../../assets/android-developer-docs.css" rel="stylesheet" type="text/css" />
    -+<link href="../stylesheet-jdiff.css" rel="stylesheet" type="text/css" />
    -+<noscript>
    -+<style type="text/css">
    -+body{overflow:auto;}
    -+#body-content{position:relative; top:0;}
    -+#doc-content{overflow:visible;border-left:3px solid #666;}
    -+#side-nav{padding:0;}
    -+#side-nav .toggle-list ul {display:block;}
    -+#resize-packages-nav{border-bottom:3px solid #666;}
    -+</style>
    -+</noscript>
    -+<style type="text/css">
    -+</style>
    -+</HEAD>
    -+<BODY class="gc-documentation" style="padding:12px;">
    -+<a NAME="topheader"></a>
    -+<table summary="Index for Classes" width="100%" class="jdiffIndex" border="0" cellspacing="0" cellpadding="0" style="padding-bottom:0;margin-bottom:0;">
    -+  <tr>
    -+  <th class="indexHeader">
    -+    Filter the Index:
    -+  </th>
    -+  </tr>
    -+  <tr>
    -+  <td class="indexText" style="line-height:1.3em;padding-left:2em;">
    -+<a href="classes_index_all.html" class="staysblack">All Classes</a>
    -+  <br>
    -+<font color="#999999">Removals</font>
    -+  <br>
    -+<b>Additions</b>
    -+  <br>
    -+<A HREF="classes_index_changes.html"xclass="hiddenlink">Changes</A>
    -+  </td>
    -+  </tr>
    -+</table>
    -+<div id="indexTableCaption" style="background-color:#eee;padding:0 4px 0 4px;font-size:11px;margin-bottom:1em;">
    -+Listed as: <span style="color:#069"><strong>Added</strong></span>,  <span style="color:#069"><strike>Removed</strike></span>,  <span style="color:#069">Changed</span></font>
    -+</div>
    -+<A NAME="A"></A>
    -+<br><font size="+2">A</font>&nbsp;
    -+<a href="#B"><font size="-2">B</font></a> 
    -+<a href="#C"><font size="-2">C</font></a> 
    -+<a href="#D"><font size="-2">D</font></a> 
    -+<a href="#G"><font size="-2">G</font></a> 
    -+<a href="#L"><font size="-2">L</font></a> 
    -+<a href="#M"><font size="-2">M</font></a> 
    -+<a href="#N"><font size="-2">N</font></a> 
    -+<a href="#P"><font size="-2">P</font></a> 
    -+<a href="#R"><font size="-2">R</font></a> 
    -+<a href="#S"><font size="-2">S</font></a> 
    -+<a href="#T"><font size="-2">T</font></a> 
    -+ <a href="#topheader"><font size="-2">TOP</font></a>
    -+<p><div style="line-height:1.5em;color:black">
    -+<A HREF="pkg_android.support.v4.view.accessibility.html#AccessibilityManagerCompat.AccessibilityStateChangeListener" class="hiddenlink" target="rightframe"><b><i>AccessibilityManagerCompat.AccessibilityStateChangeListener</i></b></A><br>
    -+<A HREF="pkg_android.support.v4.view.accessibility.html#AccessibilityManagerCompat.TouchExplorationStateChangeListener" class="hiddenlink" target="rightframe"><b><i>AccessibilityManagerCompat.TouchExplorationStateChangeListener</i></b></A><br>
    -+<A HREF="pkg_android.support.v7.app.html#ActionBarActivity" class="hiddenlink" target="rightframe"><b>ActionBarActivity</b></A><br>
    -+<A HREF="pkg_android.support.v7.widget.html#ActionMenuView" class="hiddenlink" target="rightframe"><b>ActionMenuView</b></A><br>
    -+<A HREF="pkg_android.support.v7.widget.html#ActionMenuView.LayoutParams" class="hiddenlink" target="rightframe"><b>ActionMenuView.LayoutParams</b></A><br>
    -+<A HREF="pkg_android.support.v7.widget.html#ActionMenuView.OnMenuItemClickListener" class="hiddenlink" target="rightframe"><b><i>ActionMenuView.OnMenuItemClickListener</i></b></A><br>
    -+<A HREF="pkg_android.support.v7.app.html#AppCompatActivity" class="hiddenlink" target="rightframe"><b>AppCompatActivity</b></A><br>
    -+<A HREF="pkg_android.support.v7.widget.html#AppCompatAutoCompleteTextView" class="hiddenlink" target="rightframe"><b>AppCompatAutoCompleteTextView</b></A><br>
    -+<A HREF="pkg_android.support.v7.widget.html#AppCompatButton" class="hiddenlink" target="rightframe"><b>AppCompatButton</b></A><br>
    -+<A HREF="pkg_android.support.v7.widget.html#AppCompatCheckBox" class="hiddenlink" target="rightframe"><b>AppCompatCheckBox</b></A><br>
    -+<A HREF="pkg_android.support.v7.widget.html#AppCompatCheckedTextView" class="hiddenlink" target="rightframe"><b>AppCompatCheckedTextView</b></A><br>
    -+<A HREF="pkg_android.support.v7.app.html#AppCompatDialogFragment" class="hiddenlink" target="rightframe"><b>AppCompatDialogFragment</b></A><br>
    -+<A HREF="pkg_android.support.v7.widget.html#AppCompatEditText" class="hiddenlink" target="rightframe"><b>AppCompatEditText</b></A><br>
    -+<A HREF="pkg_android.support.v7.widget.html#AppCompatImageButton" class="hiddenlink" target="rightframe"><b>AppCompatImageButton</b></A><br>
    -+<A HREF="pkg_android.support.v7.widget.html#AppCompatImageView" class="hiddenlink" target="rightframe"><b>AppCompatImageView</b></A><br>
    -+<A HREF="pkg_android.support.v7.widget.html#AppCompatMultiAutoCompleteTextView" class="hiddenlink" target="rightframe"><b>AppCompatMultiAutoCompleteTextView</b></A><br>
    -+<A HREF="pkg_android.support.v7.widget.html#AppCompatRadioButton" class="hiddenlink" target="rightframe"><b>AppCompatRadioButton</b></A><br>
    -+<A HREF="pkg_android.support.v7.widget.html#AppCompatRatingBar" class="hiddenlink" target="rightframe"><b>AppCompatRatingBar</b></A><br>
    -+<A HREF="pkg_android.support.v7.widget.html#AppCompatSeekBar" class="hiddenlink" target="rightframe"><b>AppCompatSeekBar</b></A><br>
    -+<A HREF="pkg_android.support.v7.widget.html#AppCompatSpinner" class="hiddenlink" target="rightframe"><b>AppCompatSpinner</b></A><br>
    -+<A HREF="pkg_android.support.v7.widget.html#AppCompatTextView" class="hiddenlink" target="rightframe"><b>AppCompatTextView</b></A><br>
    -+<A NAME="B"></A>
    -+<br><font size="+2">B</font>&nbsp;
    -+<a href="#A"><font size="-2">A</font></a> 
    -+<a href="#C"><font size="-2">C</font></a> 
    -+<a href="#D"><font size="-2">D</font></a> 
    -+<a href="#G"><font size="-2">G</font></a> 
    -+<a href="#L"><font size="-2">L</font></a> 
    -+<a href="#M"><font size="-2">M</font></a> 
    -+<a href="#N"><font size="-2">N</font></a> 
    -+<a href="#P"><font size="-2">P</font></a> 
    -+<a href="#R"><font size="-2">R</font></a> 
    -+<a href="#S"><font size="-2">S</font></a> 
    -+<a href="#T"><font size="-2">T</font></a> 
    -+ <a href="#topheader"><font size="-2">TOP</font></a>
    -+<p><div style="line-height:1.5em;color:black">
    -+<A HREF="pkg_android.support.v7.util.html#BatchingListUpdateCallback" class="hiddenlink" target="rightframe"><b>BatchingListUpdateCallback</b></A><br>
    -+<A NAME="C"></A>
    -+<br><font size="+2">C</font>&nbsp;
    -+<a href="#A"><font size="-2">A</font></a> 
    -+<a href="#B"><font size="-2">B</font></a> 
    -+<a href="#D"><font size="-2">D</font></a> 
    -+<a href="#G"><font size="-2">G</font></a> 
    -+<a href="#L"><font size="-2">L</font></a> 
    -+<a href="#M"><font size="-2">M</font></a> 
    -+<a href="#N"><font size="-2">N</font></a> 
    -+<a href="#P"><font size="-2">P</font></a> 
    -+<a href="#R"><font size="-2">R</font></a> 
    -+<a href="#S"><font size="-2">S</font></a> 
    -+<a href="#T"><font size="-2">T</font></a> 
    -+ <a href="#topheader"><font size="-2">TOP</font></a>
    -+<p><div style="line-height:1.5em;color:black">
    -+<A HREF="pkg_android.support.v7.widget.html#CardView" class="hiddenlink" target="rightframe"><b>CardView</b></A><br>
    -+<A NAME="D"></A>
    -+<br><font size="+2">D</font>&nbsp;
    -+<a href="#A"><font size="-2">A</font></a> 
    -+<a href="#B"><font size="-2">B</font></a> 
    -+<a href="#C"><font size="-2">C</font></a> 
    -+<a href="#G"><font size="-2">G</font></a> 
    -+<a href="#L"><font size="-2">L</font></a> 
    -+<a href="#M"><font size="-2">M</font></a> 
    -+<a href="#N"><font size="-2">N</font></a> 
    -+<a href="#P"><font size="-2">P</font></a> 
    -+<a href="#R"><font size="-2">R</font></a> 
    -+<a href="#S"><font size="-2">S</font></a> 
    -+<a href="#T"><font size="-2">T</font></a> 
    -+ <a href="#topheader"><font size="-2">TOP</font></a>
    -+<p><div style="line-height:1.5em;color:black">
    -+<A HREF="pkg_android.support.v7.util.html#DiffUtil" class="hiddenlink" target="rightframe"><b>DiffUtil</b></A><br>
    -+<A HREF="pkg_android.support.v7.util.html#DiffUtil.Callback" class="hiddenlink" target="rightframe"><b>DiffUtil.Callback</b></A><br>
    -+<A HREF="pkg_android.support.v7.util.html#DiffUtil.DiffResult" class="hiddenlink" target="rightframe"><b>DiffUtil.DiffResult</b></A><br>
    -+<A NAME="G"></A>
    -+<br><font size="+2">G</font>&nbsp;
    -+<a href="#A"><font size="-2">A</font></a> 
    -+<a href="#B"><font size="-2">B</font></a> 
    -+<a href="#C"><font size="-2">C</font></a> 
    -+<a href="#D"><font size="-2">D</font></a> 
    -+<a href="#L"><font size="-2">L</font></a> 
    -+<a href="#M"><font size="-2">M</font></a> 
    -+<a href="#N"><font size="-2">N</font></a> 
    -+<a href="#P"><font size="-2">P</font></a> 
    -+<a href="#R"><font size="-2">R</font></a> 
    -+<a href="#S"><font size="-2">S</font></a> 
    -+<a href="#T"><font size="-2">T</font></a> 
    -+ <a href="#topheader"><font size="-2">TOP</font></a>
    -+<p><div style="line-height:1.5em;color:black">
    -+<A HREF="pkg_android.support.v7.widget.html#GridLayout" class="hiddenlink" target="rightframe"><b>GridLayout</b></A><br>
    -+<A HREF="pkg_android.support.v7.widget.html#GridLayout.Alignment" class="hiddenlink" target="rightframe"><b>GridLayout.Alignment</b></A><br>
    -+<A HREF="pkg_android.support.v7.widget.html#GridLayout.LayoutParams" class="hiddenlink" target="rightframe"><b>GridLayout.LayoutParams</b></A><br>
    -+<A HREF="pkg_android.support.v7.widget.html#GridLayout.Spec" class="hiddenlink" target="rightframe"><b>GridLayout.Spec</b></A><br>
    -+<A NAME="L"></A>
    -+<br><font size="+2">L</font>&nbsp;
    -+<a href="#A"><font size="-2">A</font></a> 
    -+<a href="#B"><font size="-2">B</font></a> 
    -+<a href="#C"><font size="-2">C</font></a> 
    -+<a href="#D"><font size="-2">D</font></a> 
    -+<a href="#G"><font size="-2">G</font></a> 
    -+<a href="#M"><font size="-2">M</font></a> 
    -+<a href="#N"><font size="-2">N</font></a> 
    -+<a href="#P"><font size="-2">P</font></a> 
    -+<a href="#R"><font size="-2">R</font></a> 
    -+<a href="#S"><font size="-2">S</font></a> 
    -+<a href="#T"><font size="-2">T</font></a> 
    -+ <a href="#topheader"><font size="-2">TOP</font></a>
    -+<p><div style="line-height:1.5em;color:black">
    -+<A HREF="pkg_android.support.v7.widget.html#LinearLayoutCompat" class="hiddenlink" target="rightframe"><b>LinearLayoutCompat</b></A><br>
    -+<A HREF="pkg_android.support.v7.widget.html#LinearLayoutCompat.LayoutParams" class="hiddenlink" target="rightframe"><b>LinearLayoutCompat.LayoutParams</b></A><br>
    -+<A HREF="pkg_android.support.v7.widget.html#LinearSnapHelper" class="hiddenlink" target="rightframe"><b>LinearSnapHelper</b></A><br>
    -+<A HREF="pkg_android.support.v7.widget.html#ListPopupWindow" class="hiddenlink" target="rightframe"><b>ListPopupWindow</b></A><br>
    -+<A HREF="pkg_android.support.v7.util.html#ListUpdateCallback" class="hiddenlink" target="rightframe"><b><i>ListUpdateCallback</i></b></A><br>
    -+<A NAME="M"></A>
    -+<br><font size="+2">M</font>&nbsp;
    -+<a href="#A"><font size="-2">A</font></a> 
    -+<a href="#B"><font size="-2">B</font></a> 
    -+<a href="#C"><font size="-2">C</font></a> 
    -+<a href="#D"><font size="-2">D</font></a> 
    -+<a href="#G"><font size="-2">G</font></a> 
    -+<a href="#L"><font size="-2">L</font></a> 
    -+<a href="#N"><font size="-2">N</font></a> 
    -+<a href="#P"><font size="-2">P</font></a> 
    -+<a href="#R"><font size="-2">R</font></a> 
    -+<a href="#S"><font size="-2">S</font></a> 
    -+<a href="#T"><font size="-2">T</font></a> 
    -+ <a href="#topheader"><font size="-2">TOP</font></a>
    -+<p><div style="line-height:1.5em;color:black">
    -+<A HREF="pkg_android.support.v7.preference.html#MultiSelectListPreferenceDialogFragmentCompat" class="hiddenlink" target="rightframe"><b>MultiSelectListPreferenceDialogFragmentCompat</b></A><br>
    -+<A NAME="N"></A>
    -+<br><font size="+2">N</font>&nbsp;
    -+<a href="#A"><font size="-2">A</font></a> 
    -+<a href="#B"><font size="-2">B</font></a> 
    -+<a href="#C"><font size="-2">C</font></a> 
    -+<a href="#D"><font size="-2">D</font></a> 
    -+<a href="#G"><font size="-2">G</font></a> 
    -+<a href="#L"><font size="-2">L</font></a> 
    -+<a href="#M"><font size="-2">M</font></a> 
    -+<a href="#P"><font size="-2">P</font></a> 
    -+<a href="#R"><font size="-2">R</font></a> 
    -+<a href="#S"><font size="-2">S</font></a> 
    -+<a href="#T"><font size="-2">T</font></a> 
    -+ <a href="#topheader"><font size="-2">TOP</font></a>
    -+<p><div style="line-height:1.5em;color:black">
    -+<A HREF="pkg_android.support.v7.app.html#NotificationCompat" class="hiddenlink" target="rightframe"><b>NotificationCompat</b></A><br>
    -+<A HREF="pkg_android.support.v7.app.html#NotificationCompat.Builder" class="hiddenlink" target="rightframe"><b>NotificationCompat.Builder</b></A><br>
    -+<A HREF="pkg_android.support.v7.app.html#NotificationCompat.MediaStyle" class="hiddenlink" target="rightframe"><b>NotificationCompat.MediaStyle</b></A><br>
    -+<A NAME="P"></A>
    -+<br><font size="+2">P</font>&nbsp;
    -+<a href="#A"><font size="-2">A</font></a> 
    -+<a href="#B"><font size="-2">B</font></a> 
    -+<a href="#C"><font size="-2">C</font></a> 
    -+<a href="#D"><font size="-2">D</font></a> 
    -+<a href="#G"><font size="-2">G</font></a> 
    -+<a href="#L"><font size="-2">L</font></a> 
    -+<a href="#M"><font size="-2">M</font></a> 
    -+<a href="#N"><font size="-2">N</font></a> 
    -+<a href="#R"><font size="-2">R</font></a> 
    -+<a href="#S"><font size="-2">S</font></a> 
    -+<a href="#T"><font size="-2">T</font></a> 
    -+ <a href="#topheader"><font size="-2">TOP</font></a>
    -+<p><div style="line-height:1.5em;color:black">
    -+<A HREF="pkg_android.support.v4.util.html#PatternsCompat" class="hiddenlink" target="rightframe"><b>PatternsCompat</b></A><br>
    -+<A HREF="pkg_android.support.v7.widget.html#PopupMenu" class="hiddenlink" target="rightframe"><b>PopupMenu</b></A><br>
    -+<A HREF="pkg_android.support.v7.widget.html#PopupMenu.OnDismissListener" class="hiddenlink" target="rightframe"><b><i>PopupMenu.OnDismissListener</i></b></A><br>
    -+<A HREF="pkg_android.support.v7.widget.html#PopupMenu.OnMenuItemClickListener" class="hiddenlink" target="rightframe"><b><i>PopupMenu.OnMenuItemClickListener</i></b></A><br>
    -+<A NAME="R"></A>
    -+<br><font size="+2">R</font>&nbsp;
    -+<a href="#A"><font size="-2">A</font></a> 
    -+<a href="#B"><font size="-2">B</font></a> 
    -+<a href="#C"><font size="-2">C</font></a> 
    -+<a href="#D"><font size="-2">D</font></a> 
    -+<a href="#G"><font size="-2">G</font></a> 
    -+<a href="#L"><font size="-2">L</font></a> 
    -+<a href="#M"><font size="-2">M</font></a> 
    -+<a href="#N"><font size="-2">N</font></a> 
    -+<a href="#P"><font size="-2">P</font></a> 
    -+<a href="#S"><font size="-2">S</font></a> 
    -+<a href="#T"><font size="-2">T</font></a> 
    -+ <a href="#topheader"><font size="-2">TOP</font></a>
    -+<p><div style="line-height:1.5em;color:black">
    -+<A HREF="pkg_android.support.v7.widget.html#RecyclerView.OnFlingListener" class="hiddenlink" target="rightframe"><b>RecyclerView.OnFlingListener</b></A><br>
    -+<A HREF="pkg_android.support.v7.widget.html#RecyclerView.SmoothScroller.ScrollVectorProvider" class="hiddenlink" target="rightframe"><b><i>RecyclerView.SmoothScroller.ScrollVectorProvider</i></b></A><br>
    -+<A NAME="S"></A>
    -+<br><font size="+2">S</font>&nbsp;
    -+<a href="#A"><font size="-2">A</font></a> 
    -+<a href="#B"><font size="-2">B</font></a> 
    -+<a href="#C"><font size="-2">C</font></a> 
    -+<a href="#D"><font size="-2">D</font></a> 
    -+<a href="#G"><font size="-2">G</font></a> 
    -+<a href="#L"><font size="-2">L</font></a> 
    -+<a href="#M"><font size="-2">M</font></a> 
    -+<a href="#N"><font size="-2">N</font></a> 
    -+<a href="#P"><font size="-2">P</font></a> 
    -+<a href="#R"><font size="-2">R</font></a> 
    -+<a href="#T"><font size="-2">T</font></a> 
    -+ <a href="#topheader"><font size="-2">TOP</font></a>
    -+<p><div style="line-height:1.5em;color:black">
    -+<A HREF="pkg_android.support.v7.widget.html#SearchView" class="hiddenlink" target="rightframe"><b>SearchView</b></A><br>
    -+<A HREF="pkg_android.support.v7.widget.html#SearchView.OnCloseListener" class="hiddenlink" target="rightframe"><b><i>SearchView.OnCloseListener</i></b></A><br>
    -+<A HREF="pkg_android.support.v7.widget.html#SearchView.OnQueryTextListener" class="hiddenlink" target="rightframe"><b><i>SearchView.OnQueryTextListener</i></b></A><br>
    -+<A HREF="pkg_android.support.v7.widget.html#SearchView.OnSuggestionListener" class="hiddenlink" target="rightframe"><b><i>SearchView.OnSuggestionListener</i></b></A><br>
    -+<A HREF="pkg_android.support.v4.widget.html#SearchViewCompat.OnCloseListener" class="hiddenlink" target="rightframe"><b><i>SearchViewCompat.OnCloseListener</i></b></A><br>
    -+<A HREF="pkg_android.support.v4.widget.html#SearchViewCompat.OnQueryTextListener" class="hiddenlink" target="rightframe"><b><i>SearchViewCompat.OnQueryTextListener</i></b></A><br>
    -+<A HREF="pkg_android.support.v7.widget.html#ShareActionProvider" class="hiddenlink" target="rightframe"><b>ShareActionProvider</b></A><br>
    -+<A HREF="pkg_android.support.v7.widget.html#ShareActionProvider.OnShareTargetSelectedListener" class="hiddenlink" target="rightframe"><b><i>ShareActionProvider.OnShareTargetSelectedListener</i></b></A><br>
    -+<A HREF="pkg_android.support.v4.app.html#SharedElementCallback.OnSharedElementsReadyListener" class="hiddenlink" target="rightframe"><b><i>SharedElementCallback.OnSharedElementsReadyListener</i></b></A><br>
    -+<A HREF="pkg_android.support.v7.widget.html#SnapHelper" class="hiddenlink" target="rightframe"><b>SnapHelper</b></A><br>
    -+<A HREF="pkg_android.support.v7.widget.html#Space" class="hiddenlink" target="rightframe"><b>Space</b></A><br>
    -+<A HREF="pkg_android.support.v4.widget.html#SwipeRefreshLayout.OnChildScrollUpCallback" class="hiddenlink" target="rightframe"><b><i>SwipeRefreshLayout.OnChildScrollUpCallback</i></b></A><br>
    -+<A HREF="pkg_android.support.v7.widget.html#SwitchCompat" class="hiddenlink" target="rightframe"><b>SwitchCompat</b></A><br>
    -+<A NAME="T"></A>
    -+<br><font size="+2">T</font>&nbsp;
    -+<a href="#A"><font size="-2">A</font></a> 
    -+<a href="#B"><font size="-2">B</font></a> 
    -+<a href="#C"><font size="-2">C</font></a> 
    -+<a href="#D"><font size="-2">D</font></a> 
    -+<a href="#G"><font size="-2">G</font></a> 
    -+<a href="#L"><font size="-2">L</font></a> 
    -+<a href="#M"><font size="-2">M</font></a> 
    -+<a href="#N"><font size="-2">N</font></a> 
    -+<a href="#P"><font size="-2">P</font></a> 
    -+<a href="#R"><font size="-2">R</font></a> 
    -+<a href="#S"><font size="-2">S</font></a> 
    -+ <a href="#topheader"><font size="-2">TOP</font></a>
    -+<p><div style="line-height:1.5em;color:black">
    -+<A HREF="pkg_android.support.v7.widget.html#ThemedSpinnerAdapter" class="hiddenlink" target="rightframe"><b><i>ThemedSpinnerAdapter</i></b></A><br>
    -+<A HREF="pkg_android.support.v7.widget.html#ThemedSpinnerAdapter.Helper" class="hiddenlink" target="rightframe"><b>ThemedSpinnerAdapter.Helper</b></A><br>
    -+<A HREF="pkg_android.support.v7.widget.html#Toolbar" class="hiddenlink" target="rightframe"><b>Toolbar</b></A><br>
    -+<A HREF="pkg_android.support.v7.widget.html#Toolbar.LayoutParams" class="hiddenlink" target="rightframe"><b>Toolbar.LayoutParams</b></A><br>
    -+<A HREF="pkg_android.support.v7.widget.html#Toolbar.OnMenuItemClickListener" class="hiddenlink" target="rightframe"><b><i>Toolbar.OnMenuItemClickListener</i></b></A><br>
    -+<A HREF="pkg_android.support.v7.widget.html#Toolbar.SavedState" class="hiddenlink" target="rightframe"><b>Toolbar.SavedState</b></A><br>
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    -+</script>
    -+<script type="text/javascript">
    -+  try {
    -+    var pageTracker = _gat._getTracker("UA-5831155-1");
    -+    pageTracker._setAllowAnchor(true);
    -+    pageTracker._initData();
    -+    pageTracker._trackPageview();
    -+  } catch(e) {}
    -+</script>
    -+</BODY>
    -+</HTML>
    -diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/classes_index_all.html b/docs/html/sdk/support_api_diff/24.2.0/changes/classes_index_all.html
    -new file mode 100644
    -index 0000000..3e77bf2
    ---- /dev/null
    -+++ b/docs/html/sdk/support_api_diff/24.2.0/changes/classes_index_all.html
    -@@ -0,0 +1,528 @@
    -+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
    -+<HTML style="overflow:auto;">
    -+<HEAD>
    -+<meta name="generator" content="JDiff v1.1.0">
    -+<!-- Generated by the JDiff Javadoc doclet -->
    -+<!-- (http://www.jdiff.org) -->
    -+<meta name="description" content="JDiff is a Javadoc doclet which generates an HTML report of all the packages, classes, constructors, methods, and fields which have been removed, added or changed in any way, including their documentation, when two APIs are compared.">
    -+<meta name="keywords" content="diff, jdiff, javadiff, java diff, java difference, API difference, difference between two APIs, API diff, Javadoc, doclet">
    -+<TITLE>
    -+Class Differences Index
    -+</TITLE>
    -+<link href="../../../../assets/android-developer-docs.css" rel="stylesheet" type="text/css" />
    -+<link href="../stylesheet-jdiff.css" rel="stylesheet" type="text/css" />
    -+<noscript>
    -+<style type="text/css">
    -+body{overflow:auto;}
    -+#body-content{position:relative; top:0;}
    -+#doc-content{overflow:visible;border-left:3px solid #666;}
    -+#side-nav{padding:0;}
    -+#side-nav .toggle-list ul {display:block;}
    -+#resize-packages-nav{border-bottom:3px solid #666;}
    -+</style>
    -+</noscript>
    -+<style type="text/css">
    -+</style>
    -+</HEAD>
    -+<BODY class="gc-documentation" style="padding:12px;">
    -+<a NAME="topheader"></a>
    -+<table summary="Index for Classes" width="100%" class="jdiffIndex" border="0" cellspacing="0" cellpadding="0" style="padding-bottom:0;margin-bottom:0;">
    -+  <tr>
    -+  <th class="indexHeader">
    -+    Filter the Index:
    -+  </th>
    -+  </tr>
    -+  <tr>
    -+  <td class="indexText" style="line-height:1.3em;padding-left:2em;">
    -+<b>Classes</b>
    -+  <br>
    -+<font color="#999999">Removals</font>
    -+  <br>
    -+<A HREF="classes_index_additions.html"xclass="hiddenlink">Additions</A>
    -+  <br>
    -+<A HREF="classes_index_changes.html"xclass="hiddenlink">Changes</A>
    -+  </td>
    -+  </tr>
    -+</table>
    -+<div id="indexTableCaption" style="background-color:#eee;padding:0 4px 0 4px;font-size:11px;margin-bottom:1em;">
    -+Listed as: <span style="color:#069"><strong>Added</strong></span>,  <span style="color:#069"><strike>Removed</strike></span>,  <span style="color:#069">Changed</span></font>
    -+</div>
    -+<A NAME="A"></A>
    -+<br><font size="+2">A</font>&nbsp;
    -+<a href="#B"><font size="-2">B</font></a> 
    -+<a href="#C"><font size="-2">C</font></a> 
    -+<a href="#D"><font size="-2">D</font></a> 
    -+<a href="#F"><font size="-2">F</font></a> 
    -+<a href="#G"><font size="-2">G</font></a> 
    -+<a href="#K"><font size="-2">K</font></a> 
    -+<a href="#L"><font size="-2">L</font></a> 
    -+<a href="#M"><font size="-2">M</font></a> 
    -+<a href="#N"><font size="-2">N</font></a> 
    -+<a href="#O"><font size="-2">O</font></a> 
    -+<a href="#P"><font size="-2">P</font></a> 
    -+<a href="#R"><font size="-2">R</font></a> 
    -+<a href="#S"><font size="-2">S</font></a> 
    -+<a href="#T"><font size="-2">T</font></a> 
    -+<a href="#V"><font size="-2">V</font></a> 
    -+<a href="#W"><font size="-2">W</font></a> 
    -+ <a href="#topheader"><font size="-2">TOP</font></a>
    -+<p><div style="line-height:1.5em;color:black">
    -+<A HREF="android.support.v17.leanback.widget.AbstractMediaItemPresenter.html" class="hiddenlink" target="rightframe">AbstractMediaItemPresenter</A><br>
    -+<A HREF="android.support.v17.leanback.widget.AbstractMediaItemPresenter.ViewHolder.html" class="hiddenlink" target="rightframe">AbstractMediaItemPresenter.ViewHolder</A><br>
    -+<A HREF="android.support.v4.view.accessibility.AccessibilityEventCompat.html" class="hiddenlink" target="rightframe">AccessibilityEventCompat</A><br>
    -+<A HREF="android.support.v4.view.accessibility.AccessibilityManagerCompat.html" class="hiddenlink" target="rightframe">AccessibilityManagerCompat</A><br>
    -+<A HREF="pkg_android.support.v4.view.accessibility.html#AccessibilityManagerCompat.AccessibilityStateChangeListener" class="hiddenlink" target="rightframe"><b><i>AccessibilityManagerCompat.AccessibilityStateChangeListener</i></b></A><br>
    -+<A HREF="android.support.v4.view.accessibility.AccessibilityManagerCompat.AccessibilityStateChangeListenerCompat.html" class="hiddenlink" target="rightframe">AccessibilityManagerCompat.AccessibilityStateChangeListenerCompat</A><br>
    -+<A HREF="pkg_android.support.v4.view.accessibility.html#AccessibilityManagerCompat.TouchExplorationStateChangeListener" class="hiddenlink" target="rightframe"><b><i>AccessibilityManagerCompat.TouchExplorationStateChangeListener</i></b></A><br>
    -+<A HREF="android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.html" class="hiddenlink" target="rightframe">AccessibilityNodeInfoCompat</A><br>
    -+<A HREF="android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat.html" class="hiddenlink" target="rightframe">AccessibilityNodeInfoCompat.AccessibilityActionCompat</A><br>
    -+<A HREF="android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.CollectionInfoCompat.html" class="hiddenlink" target="rightframe">AccessibilityNodeInfoCompat.CollectionInfoCompat</A><br>
    -+<A HREF="android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.CollectionItemInfoCompat.html" class="hiddenlink" target="rightframe">AccessibilityNodeInfoCompat.CollectionItemInfoCompat</A><br>
    -+<A HREF="android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.RangeInfoCompat.html" class="hiddenlink" target="rightframe">AccessibilityNodeInfoCompat.RangeInfoCompat</A><br>
    -+<A HREF="android.support.v4.view.accessibility.AccessibilityNodeProviderCompat.html" class="hiddenlink" target="rightframe">AccessibilityNodeProviderCompat</A><br>
    -+<A HREF="android.support.v4.accessibilityservice.AccessibilityServiceInfoCompat.html" class="hiddenlink" target="rightframe">AccessibilityServiceInfoCompat</A><br>
    -+<A HREF="android.support.v4.view.accessibility.AccessibilityWindowInfoCompat.html" class="hiddenlink" target="rightframe">AccessibilityWindowInfoCompat</A><br>
    -+<A HREF="pkg_android.support.v7.app.html#ActionBarActivity" class="hiddenlink" target="rightframe"><b>ActionBarActivity</b></A><br>
    -+<A HREF="android.support.v7.app.ActionBarDrawerToggle.html" class="hiddenlink" target="rightframe">ActionBarDrawerToggle</A><br>
    -+<A HREF="pkg_android.support.v7.widget.html#ActionMenuView" class="hiddenlink" target="rightframe"><b>ActionMenuView</b></A><br>
    -+<A HREF="pkg_android.support.v7.widget.html#ActionMenuView.LayoutParams" class="hiddenlink" target="rightframe"><b>ActionMenuView.LayoutParams</b></A><br>
    -+<A HREF="pkg_android.support.v7.widget.html#ActionMenuView.OnMenuItemClickListener" class="hiddenlink" target="rightframe"><b><i>ActionMenuView.OnMenuItemClickListener</i></b></A><br>
    -+<A HREF="android.support.v4.app.ActivityCompat.html" class="hiddenlink" target="rightframe">ActivityCompat</A><br>
    -+<A HREF="android.support.v4.app.ActivityOptionsCompat.html" class="hiddenlink" target="rightframe">ActivityOptionsCompat</A><br>
    -+<A HREF="android.support.design.widget.AppBarLayout.ScrollingViewBehavior.html" class="hiddenlink" target="rightframe">AppBarLayout.ScrollingViewBehavior</A><br>
    -+<A HREF="pkg_android.support.v7.app.html#AppCompatActivity" class="hiddenlink" target="rightframe"><b>AppCompatActivity</b></A><br>
    -+<A HREF="pkg_android.support.v7.widget.html#AppCompatAutoCompleteTextView" class="hiddenlink" target="rightframe"><b>AppCompatAutoCompleteTextView</b></A><br>
    -+<A HREF="pkg_android.support.v7.widget.html#AppCompatButton" class="hiddenlink" target="rightframe"><b>AppCompatButton</b></A><br>
    -+<A HREF="pkg_android.support.v7.widget.html#AppCompatCheckBox" class="hiddenlink" target="rightframe"><b>AppCompatCheckBox</b></A><br>
    -+<A HREF="pkg_android.support.v7.widget.html#AppCompatCheckedTextView" class="hiddenlink" target="rightframe"><b>AppCompatCheckedTextView</b></A><br>
    -+<A HREF="android.support.v7.app.AppCompatDelegate.html" class="hiddenlink" target="rightframe">AppCompatDelegate</A><br>
    -+<A HREF="pkg_android.support.v7.app.html#AppCompatDialogFragment" class="hiddenlink" target="rightframe"><b>AppCompatDialogFragment</b></A><br>
    -+<A HREF="pkg_android.support.v7.widget.html#AppCompatEditText" class="hiddenlink" target="rightframe"><b>AppCompatEditText</b></A><br>
    -+<A HREF="pkg_android.support.v7.widget.html#AppCompatImageButton" class="hiddenlink" target="rightframe"><b>AppCompatImageButton</b></A><br>
    -+<A HREF="pkg_android.support.v7.widget.html#AppCompatImageView" class="hiddenlink" target="rightframe"><b>AppCompatImageView</b></A><br>
    -+<A HREF="pkg_android.support.v7.widget.html#AppCompatMultiAutoCompleteTextView" class="hiddenlink" target="rightframe"><b>AppCompatMultiAutoCompleteTextView</b></A><br>
    -+<A HREF="pkg_android.support.v7.widget.html#AppCompatRadioButton" class="hiddenlink" target="rightframe"><b>AppCompatRadioButton</b></A><br>
    -+<A HREF="pkg_android.support.v7.widget.html#AppCompatRatingBar" class="hiddenlink" target="rightframe"><b>AppCompatRatingBar</b></A><br>
    -+<A HREF="android.support.v7.content.res.AppCompatResources.html" class="hiddenlink" target="rightframe">AppCompatResources</A><br>
    -+<A HREF="pkg_android.support.v7.widget.html#AppCompatSeekBar" class="hiddenlink" target="rightframe"><b>AppCompatSeekBar</b></A><br>
    -+<A HREF="pkg_android.support.v7.widget.html#AppCompatSpinner" class="hiddenlink" target="rightframe"><b>AppCompatSpinner</b></A><br>
    -+<A HREF="pkg_android.support.v7.widget.html#AppCompatTextView" class="hiddenlink" target="rightframe"><b>AppCompatTextView</b></A><br>
    -+<A NAME="B"></A>
    -+<br><font size="+2">B</font>&nbsp;
    -+<a href="#A"><font size="-2">A</font></a> 
    -+<a href="#C"><font size="-2">C</font></a> 
    -+<a href="#D"><font size="-2">D</font></a> 
    -+<a href="#F"><font size="-2">F</font></a> 
    -+<a href="#G"><font size="-2">G</font></a> 
    -+<a href="#K"><font size="-2">K</font></a> 
    -+<a href="#L"><font size="-2">L</font></a> 
    -+<a href="#M"><font size="-2">M</font></a> 
    -+<a href="#N"><font size="-2">N</font></a> 
    -+<a href="#O"><font size="-2">O</font></a> 
    -+<a href="#P"><font size="-2">P</font></a> 
    -+<a href="#R"><font size="-2">R</font></a> 
    -+<a href="#S"><font size="-2">S</font></a> 
    -+<a href="#T"><font size="-2">T</font></a> 
    -+<a href="#V"><font size="-2">V</font></a> 
    -+<a href="#W"><font size="-2">W</font></a> 
    -+ <a href="#topheader"><font size="-2">TOP</font></a>
    -+<p><div style="line-height:1.5em;color:black">
    -+<A HREF="pkg_android.support.v7.util.html#BatchingListUpdateCallback" class="hiddenlink" target="rightframe"><b>BatchingListUpdateCallback</b></A><br>
    -+<A HREF="android.support.design.widget.BottomSheetBehavior.html" class="hiddenlink" target="rightframe">BottomSheetBehavior</A><br>
    -+<A HREF="android.support.v4.os.BuildCompat.html" class="hiddenlink" target="rightframe">BuildCompat</A><br>
    -+<A NAME="C"></A>
    -+<br><font size="+2">C</font>&nbsp;
    -+<a href="#A"><font size="-2">A</font></a> 
    -+<a href="#B"><font size="-2">B</font></a> 
    -+<a href="#D"><font size="-2">D</font></a> 
    -+<a href="#F"><font size="-2">F</font></a> 
    -+<a href="#G"><font size="-2">G</font></a> 
    -+<a href="#K"><font size="-2">K</font></a> 
    -+<a href="#L"><font size="-2">L</font></a> 
    -+<a href="#M"><font size="-2">M</font></a> 
    -+<a href="#N"><font size="-2">N</font></a> 
    -+<a href="#O"><font size="-2">O</font></a> 
    -+<a href="#P"><font size="-2">P</font></a> 
    -+<a href="#R"><font size="-2">R</font></a> 
    -+<a href="#S"><font size="-2">S</font></a> 
    -+<a href="#T"><font size="-2">T</font></a> 
    -+<a href="#V"><font size="-2">V</font></a> 
    -+<a href="#W"><font size="-2">W</font></a> 
    -+ <a href="#topheader"><font size="-2">TOP</font></a>
    -+<p><div style="line-height:1.5em;color:black">
    -+<A HREF="pkg_android.support.v7.widget.html#CardView" class="hiddenlink" target="rightframe"><b>CardView</b></A><br>
    -+<A HREF="android.support.design.widget.CollapsingToolbarLayout.html" class="hiddenlink" target="rightframe">CollapsingToolbarLayout</A><br>
    -+<A HREF="android.support.v4.content.ContextCompat.html" class="hiddenlink" target="rightframe">ContextCompat</A><br>
    -+<A HREF="android.support.design.widget.CoordinatorLayout.html" class="hiddenlink" target="rightframe">CoordinatorLayout</A><br>
    -+<A HREF="android.support.design.widget.CoordinatorLayout.Behavior.html" class="hiddenlink" target="rightframe">CoordinatorLayout.Behavior</A><br>
    -+<A HREF="android.support.design.widget.CoordinatorLayout.LayoutParams.html" class="hiddenlink" target="rightframe">CoordinatorLayout.LayoutParams</A><br>
    -+<A HREF="android.support.customtabs.CustomTabsIntent.html" class="hiddenlink" target="rightframe">CustomTabsIntent</A><br>
    -+<A HREF="android.support.customtabs.CustomTabsIntent.Builder.html" class="hiddenlink" target="rightframe">CustomTabsIntent.Builder</A><br>
    -+<A HREF="android.support.customtabs.CustomTabsSession.html" class="hiddenlink" target="rightframe">CustomTabsSession</A><br>
    -+<A NAME="D"></A>
    -+<br><font size="+2">D</font>&nbsp;
    -+<a href="#A"><font size="-2">A</font></a> 
    -+<a href="#B"><font size="-2">B</font></a> 
    -+<a href="#C"><font size="-2">C</font></a> 
    -+<a href="#F"><font size="-2">F</font></a> 
    -+<a href="#G"><font size="-2">G</font></a> 
    -+<a href="#K"><font size="-2">K</font></a> 
    -+<a href="#L"><font size="-2">L</font></a> 
    -+<a href="#M"><font size="-2">M</font></a> 
    -+<a href="#N"><font size="-2">N</font></a> 
    -+<a href="#O"><font size="-2">O</font></a> 
    -+<a href="#P"><font size="-2">P</font></a> 
    -+<a href="#R"><font size="-2">R</font></a> 
    -+<a href="#S"><font size="-2">S</font></a> 
    -+<a href="#T"><font size="-2">T</font></a> 
    -+<a href="#V"><font size="-2">V</font></a> 
    -+<a href="#W"><font size="-2">W</font></a> 
    -+ <a href="#topheader"><font size="-2">TOP</font></a>
    -+<p><div style="line-height:1.5em;color:black">
    -+<A HREF="pkg_android.support.v7.util.html#DiffUtil" class="hiddenlink" target="rightframe"><b>DiffUtil</b></A><br>
    -+<A HREF="pkg_android.support.v7.util.html#DiffUtil.Callback" class="hiddenlink" target="rightframe"><b>DiffUtil.Callback</b></A><br>
    -+<A HREF="pkg_android.support.v7.util.html#DiffUtil.DiffResult" class="hiddenlink" target="rightframe"><b>DiffUtil.DiffResult</b></A><br>
    -+<A HREF="android.support.v4.graphics.drawable.DrawableCompat.html" class="hiddenlink" target="rightframe">DrawableCompat</A><br>
    -+<A NAME="F"></A>
    -+<br><font size="+2">F</font>&nbsp;
    -+<a href="#A"><font size="-2">A</font></a> 
    -+<a href="#B"><font size="-2">B</font></a> 
    -+<a href="#C"><font size="-2">C</font></a> 
    -+<a href="#D"><font size="-2">D</font></a> 
    -+<a href="#G"><font size="-2">G</font></a> 
    -+<a href="#K"><font size="-2">K</font></a> 
    -+<a href="#L"><font size="-2">L</font></a> 
    -+<a href="#M"><font size="-2">M</font></a> 
    -+<a href="#N"><font size="-2">N</font></a> 
    -+<a href="#O"><font size="-2">O</font></a> 
    -+<a href="#P"><font size="-2">P</font></a> 
    -+<a href="#R"><font size="-2">R</font></a> 
    -+<a href="#S"><font size="-2">S</font></a> 
    -+<a href="#T"><font size="-2">T</font></a> 
    -+<a href="#V"><font size="-2">V</font></a> 
    -+<a href="#W"><font size="-2">W</font></a> 
    -+ <a href="#topheader"><font size="-2">TOP</font></a>
    -+<p><div style="line-height:1.5em;color:black">
    -+<A HREF="android.support.design.widget.FloatingActionButton.Behavior.html" class="hiddenlink" target="rightframe">FloatingActionButton.Behavior</A><br>
    -+<A HREF="android.support.v4.app.FragmentController.html" class="hiddenlink" target="rightframe">FragmentController</A><br>
    -+<A NAME="G"></A>
    -+<br><font size="+2">G</font>&nbsp;
    -+<a href="#A"><font size="-2">A</font></a> 
    -+<a href="#B"><font size="-2">B</font></a> 
    -+<a href="#C"><font size="-2">C</font></a> 
    -+<a href="#D"><font size="-2">D</font></a> 
    -+<a href="#F"><font size="-2">F</font></a> 
    -+<a href="#K"><font size="-2">K</font></a> 
    -+<a href="#L"><font size="-2">L</font></a> 
    -+<a href="#M"><font size="-2">M</font></a> 
    -+<a href="#N"><font size="-2">N</font></a> 
    -+<a href="#O"><font size="-2">O</font></a> 
    -+<a href="#P"><font size="-2">P</font></a> 
    -+<a href="#R"><font size="-2">R</font></a> 
    -+<a href="#S"><font size="-2">S</font></a> 
    -+<a href="#T"><font size="-2">T</font></a> 
    -+<a href="#V"><font size="-2">V</font></a> 
    -+<a href="#W"><font size="-2">W</font></a> 
    -+ <a href="#topheader"><font size="-2">TOP</font></a>
    -+<p><div style="line-height:1.5em;color:black">
    -+<A HREF="pkg_android.support.v7.widget.html#GridLayout" class="hiddenlink" target="rightframe"><b>GridLayout</b></A><br>
    -+<A HREF="pkg_android.support.v7.widget.html#GridLayout.Alignment" class="hiddenlink" target="rightframe"><b>GridLayout.Alignment</b></A><br>
    -+<A HREF="pkg_android.support.v7.widget.html#GridLayout.LayoutParams" class="hiddenlink" target="rightframe"><b>GridLayout.LayoutParams</b></A><br>
    -+<A HREF="pkg_android.support.v7.widget.html#GridLayout.Spec" class="hiddenlink" target="rightframe"><b>GridLayout.Spec</b></A><br>
    -+<A NAME="K"></A>
    -+<br><font size="+2">K</font>&nbsp;
    -+<a href="#A"><font size="-2">A</font></a> 
    -+<a href="#B"><font size="-2">B</font></a> 
    -+<a href="#C"><font size="-2">C</font></a> 
    -+<a href="#D"><font size="-2">D</font></a> 
    -+<a href="#F"><font size="-2">F</font></a> 
    -+<a href="#G"><font size="-2">G</font></a> 
    -+<a href="#L"><font size="-2">L</font></a> 
    -+<a href="#M"><font size="-2">M</font></a> 
    -+<a href="#N"><font size="-2">N</font></a> 
    -+<a href="#O"><font size="-2">O</font></a> 
    -+<a href="#P"><font size="-2">P</font></a> 
    -+<a href="#R"><font size="-2">R</font></a> 
    -+<a href="#S"><font size="-2">S</font></a> 
    -+<a href="#T"><font size="-2">T</font></a> 
    -+<a href="#V"><font size="-2">V</font></a> 
    -+<a href="#W"><font size="-2">W</font></a> 
    -+ <a href="#topheader"><font size="-2">TOP</font></a>
    -+<p><div style="line-height:1.5em;color:black">
    -+<A HREF="android.support.v4.view.KeyEventCompat.html" class="hiddenlink" target="rightframe">KeyEventCompat</A><br>
    -+<A NAME="L"></A>
    -+<br><font size="+2">L</font>&nbsp;
    -+<a href="#A"><font size="-2">A</font></a> 
    -+<a href="#B"><font size="-2">B</font></a> 
    -+<a href="#C"><font size="-2">C</font></a> 
    -+<a href="#D"><font size="-2">D</font></a> 
    -+<a href="#F"><font size="-2">F</font></a> 
    -+<a href="#G"><font size="-2">G</font></a> 
    -+<a href="#K"><font size="-2">K</font></a> 
    -+<a href="#M"><font size="-2">M</font></a> 
    -+<a href="#N"><font size="-2">N</font></a> 
    -+<a href="#O"><font size="-2">O</font></a> 
    -+<a href="#P"><font size="-2">P</font></a> 
    -+<a href="#R"><font size="-2">R</font></a> 
    -+<a href="#S"><font size="-2">S</font></a> 
    -+<a href="#T"><font size="-2">T</font></a> 
    -+<a href="#V"><font size="-2">V</font></a> 
    -+<a href="#W"><font size="-2">W</font></a> 
    -+ <a href="#topheader"><font size="-2">TOP</font></a>
    -+<p><div style="line-height:1.5em;color:black">
    -+<A HREF="android.support.v17.preference.LeanbackSettingsFragment.html" class="hiddenlink" target="rightframe">LeanbackSettingsFragment</A><br>
    -+<A HREF="pkg_android.support.v7.widget.html#LinearLayoutCompat" class="hiddenlink" target="rightframe"><b>LinearLayoutCompat</b></A><br>
    -+<A HREF="pkg_android.support.v7.widget.html#LinearLayoutCompat.LayoutParams" class="hiddenlink" target="rightframe"><b>LinearLayoutCompat.LayoutParams</b></A><br>
    -+<A HREF="android.support.v7.widget.LinearLayoutManager.html" class="hiddenlink" target="rightframe">LinearLayoutManager</A><br>
    -+<A HREF="android.support.v7.widget.LinearSmoothScroller.html" class="hiddenlink" target="rightframe">LinearSmoothScroller</A><br>
    -+<A HREF="pkg_android.support.v7.widget.html#LinearSnapHelper" class="hiddenlink" target="rightframe"><b>LinearSnapHelper</b></A><br>
    -+<A HREF="pkg_android.support.v7.widget.html#ListPopupWindow" class="hiddenlink" target="rightframe"><b>ListPopupWindow</b></A><br>
    -+<A HREF="pkg_android.support.v7.util.html#ListUpdateCallback" class="hiddenlink" target="rightframe"><b><i>ListUpdateCallback</i></b></A><br>
    -+<A NAME="M"></A>
    -+<br><font size="+2">M</font>&nbsp;
    -+<a href="#A"><font size="-2">A</font></a> 
    -+<a href="#B"><font size="-2">B</font></a> 
    -+<a href="#C"><font size="-2">C</font></a> 
    -+<a href="#D"><font size="-2">D</font></a> 
    -+<a href="#F"><font size="-2">F</font></a> 
    -+<a href="#G"><font size="-2">G</font></a> 
    -+<a href="#K"><font size="-2">K</font></a> 
    -+<a href="#L"><font size="-2">L</font></a> 
    -+<a href="#N"><font size="-2">N</font></a> 
    -+<a href="#O"><font size="-2">O</font></a> 
    -+<a href="#P"><font size="-2">P</font></a> 
    -+<a href="#R"><font size="-2">R</font></a> 
    -+<a href="#S"><font size="-2">S</font></a> 
    -+<a href="#T"><font size="-2">T</font></a> 
    -+<a href="#V"><font size="-2">V</font></a> 
    -+<a href="#W"><font size="-2">W</font></a> 
    -+ <a href="#topheader"><font size="-2">TOP</font></a>
    -+<p><div style="line-height:1.5em;color:black">
    -+<A HREF="android.support.v4.media.MediaBrowserCompat.MediaItem.html" class="hiddenlink" target="rightframe">MediaBrowserCompat.MediaItem</A><br>
    -+<A HREF="android.support.v4.media.MediaBrowserServiceCompat.BrowserRoot.html" class="hiddenlink" target="rightframe">MediaBrowserServiceCompat.BrowserRoot</A><br>
    -+<A HREF="android.support.v4.media.session.MediaButtonReceiver.html" class="hiddenlink" target="rightframe">MediaButtonReceiver</A><br>
    -+<A HREF="android.support.v4.media.MediaDescriptionCompat.html" class="hiddenlink" target="rightframe">MediaDescriptionCompat</A><br>
    -+<A HREF="android.support.v4.media.MediaMetadataCompat.html" class="hiddenlink" target="rightframe">MediaMetadataCompat</A><br>
    -+<A HREF="android.support.v4.media.session.MediaSessionCompat.html" class="hiddenlink" target="rightframe">MediaSessionCompat</A><br>
    -+<A HREF="android.support.v4.media.session.MediaSessionCompat.QueueItem.html" class="hiddenlink" target="rightframe">MediaSessionCompat.QueueItem</A><br>
    -+<A HREF="android.support.v4.view.MotionEventCompat.html" class="hiddenlink" target="rightframe">MotionEventCompat</A><br>
    -+<A HREF="pkg_android.support.v7.preference.html#MultiSelectListPreferenceDialogFragmentCompat" class="hiddenlink" target="rightframe"><b>MultiSelectListPreferenceDialogFragmentCompat</b></A><br>
    -+<A NAME="N"></A>
    -+<br><font size="+2">N</font>&nbsp;
    -+<a href="#A"><font size="-2">A</font></a> 
    -+<a href="#B"><font size="-2">B</font></a> 
    -+<a href="#C"><font size="-2">C</font></a> 
    -+<a href="#D"><font size="-2">D</font></a> 
    -+<a href="#F"><font size="-2">F</font></a> 
    -+<a href="#G"><font size="-2">G</font></a> 
    -+<a href="#K"><font size="-2">K</font></a> 
    -+<a href="#L"><font size="-2">L</font></a> 
    -+<a href="#M"><font size="-2">M</font></a> 
    -+<a href="#O"><font size="-2">O</font></a> 
    -+<a href="#P"><font size="-2">P</font></a> 
    -+<a href="#R"><font size="-2">R</font></a> 
    -+<a href="#S"><font size="-2">S</font></a> 
    -+<a href="#T"><font size="-2">T</font></a> 
    -+<a href="#V"><font size="-2">V</font></a> 
    -+<a href="#W"><font size="-2">W</font></a> 
    -+ <a href="#topheader"><font size="-2">TOP</font></a>
    -+<p><div style="line-height:1.5em;color:black">
    -+<A HREF="pkg_android.support.v7.app.html#NotificationCompat" class="hiddenlink" target="rightframe"><b>NotificationCompat</b></A><br>
    -+<A HREF="pkg_android.support.v7.app.html#NotificationCompat.Builder" class="hiddenlink" target="rightframe"><b>NotificationCompat.Builder</b></A><br>
    -+<A HREF="pkg_android.support.v7.app.html#NotificationCompat.MediaStyle" class="hiddenlink" target="rightframe"><b>NotificationCompat.MediaStyle</b></A><br>
    -+<A NAME="O"></A>
    -+<br><font size="+2">O</font>&nbsp;
    -+<a href="#A"><font size="-2">A</font></a> 
    -+<a href="#B"><font size="-2">B</font></a> 
    -+<a href="#C"><font size="-2">C</font></a> 
    -+<a href="#D"><font size="-2">D</font></a> 
    -+<a href="#F"><font size="-2">F</font></a> 
    -+<a href="#G"><font size="-2">G</font></a> 
    -+<a href="#K"><font size="-2">K</font></a> 
    -+<a href="#L"><font size="-2">L</font></a> 
    -+<a href="#M"><font size="-2">M</font></a> 
    -+<a href="#N"><font size="-2">N</font></a> 
    -+<a href="#P"><font size="-2">P</font></a> 
    -+<a href="#R"><font size="-2">R</font></a> 
    -+<a href="#S"><font size="-2">S</font></a> 
    -+<a href="#T"><font size="-2">T</font></a> 
    -+<a href="#V"><font size="-2">V</font></a> 
    -+<a href="#W"><font size="-2">W</font></a> 
    -+ <a href="#topheader"><font size="-2">TOP</font></a>
    -+<p><div style="line-height:1.5em;color:black">
    -+<A HREF="android.support.v17.leanback.widget.ObjectAdapter.html" class="hiddenlink" target="rightframe">ObjectAdapter</A><br>
    -+<A NAME="P"></A>
    -+<br><font size="+2">P</font>&nbsp;
    -+<a href="#A"><font size="-2">A</font></a> 
    -+<a href="#B"><font size="-2">B</font></a> 
    -+<a href="#C"><font size="-2">C</font></a> 
    -+<a href="#D"><font size="-2">D</font></a> 
    -+<a href="#F"><font size="-2">F</font></a> 
    -+<a href="#G"><font size="-2">G</font></a> 
    -+<a href="#K"><font size="-2">K</font></a> 
    -+<a href="#L"><font size="-2">L</font></a> 
    -+<a href="#M"><font size="-2">M</font></a> 
    -+<a href="#N"><font size="-2">N</font></a> 
    -+<a href="#O"><font size="-2">O</font></a> 
    -+<a href="#R"><font size="-2">R</font></a> 
    -+<a href="#S"><font size="-2">S</font></a> 
    -+<a href="#T"><font size="-2">T</font></a> 
    -+<a href="#V"><font size="-2">V</font></a> 
    -+<a href="#W"><font size="-2">W</font></a> 
    -+ <a href="#topheader"><font size="-2">TOP</font></a>
    -+<p><div style="line-height:1.5em;color:black">
    -+<A HREF="android.support.v7.graphics.Palette.html" class="hiddenlink" target="rightframe">Palette</A><br>
    -+<A HREF="pkg_android.support.v4.util.html#PatternsCompat" class="hiddenlink" target="rightframe"><b>PatternsCompat</b></A><br>
    -+<A HREF="android.support.v4.media.session.PlaybackStateCompat.html" class="hiddenlink" target="rightframe">PlaybackStateCompat</A><br>
    -+<A HREF="pkg_android.support.v7.widget.html#PopupMenu" class="hiddenlink" target="rightframe"><b>PopupMenu</b></A><br>
    -+<A HREF="pkg_android.support.v7.widget.html#PopupMenu.OnDismissListener" class="hiddenlink" target="rightframe"><b><i>PopupMenu.OnDismissListener</i></b></A><br>
    -+<A HREF="pkg_android.support.v7.widget.html#PopupMenu.OnMenuItemClickListener" class="hiddenlink" target="rightframe"><b><i>PopupMenu.OnMenuItemClickListener</i></b></A><br>
    -+<A HREF="android.support.v14.preference.PreferenceFragment.html" class="hiddenlink" target="rightframe">PreferenceFragment</A><br>
    -+<A NAME="R"></A>
    -+<br><font size="+2">R</font>&nbsp;
    -+<a href="#A"><font size="-2">A</font></a> 
    -+<a href="#B"><font size="-2">B</font></a> 
    -+<a href="#C"><font size="-2">C</font></a> 
    -+<a href="#D"><font size="-2">D</font></a> 
    -+<a href="#F"><font size="-2">F</font></a> 
    -+<a href="#G"><font size="-2">G</font></a> 
    -+<a href="#K"><font size="-2">K</font></a> 
    -+<a href="#L"><font size="-2">L</font></a> 
    -+<a href="#M"><font size="-2">M</font></a> 
    -+<a href="#N"><font size="-2">N</font></a> 
    -+<a href="#O"><font size="-2">O</font></a> 
    -+<a href="#P"><font size="-2">P</font></a> 
    -+<a href="#S"><font size="-2">S</font></a> 
    -+<a href="#T"><font size="-2">T</font></a> 
    -+<a href="#V"><font size="-2">V</font></a> 
    -+<a href="#W"><font size="-2">W</font></a> 
    -+ <a href="#topheader"><font size="-2">TOP</font></a>
    -+<p><div style="line-height:1.5em;color:black">
    -+<A HREF="android.support.v7.widget.RecyclerView.html" class="hiddenlink" target="rightframe">RecyclerView</A><br>
    -+<A HREF="pkg_android.support.v7.widget.html#RecyclerView.OnFlingListener" class="hiddenlink" target="rightframe"><b>RecyclerView.OnFlingListener</b></A><br>
    -+<A HREF="pkg_android.support.v7.widget.html#RecyclerView.SmoothScroller.ScrollVectorProvider" class="hiddenlink" target="rightframe"><b><i>RecyclerView.SmoothScroller.ScrollVectorProvider</i></b></A><br>
    -+<A NAME="S"></A>
    -+<br><font size="+2">S</font>&nbsp;
    -+<a href="#A"><font size="-2">A</font></a> 
    -+<a href="#B"><font size="-2">B</font></a> 
    -+<a href="#C"><font size="-2">C</font></a> 
    -+<a href="#D"><font size="-2">D</font></a> 
    -+<a href="#F"><font size="-2">F</font></a> 
    -+<a href="#G"><font size="-2">G</font></a> 
    -+<a href="#K"><font size="-2">K</font></a> 
    -+<a href="#L"><font size="-2">L</font></a> 
    -+<a href="#M"><font size="-2">M</font></a> 
    -+<a href="#N"><font size="-2">N</font></a> 
    -+<a href="#O"><font size="-2">O</font></a> 
    -+<a href="#P"><font size="-2">P</font></a> 
    -+<a href="#R"><font size="-2">R</font></a> 
    -+<a href="#T"><font size="-2">T</font></a> 
    -+<a href="#V"><font size="-2">V</font></a> 
    -+<a href="#W"><font size="-2">W</font></a> 
    -+ <a href="#topheader"><font size="-2">TOP</font></a>
    -+<p><div style="line-height:1.5em;color:black">
    -+<A HREF="pkg_android.support.v7.widget.html#SearchView" class="hiddenlink" target="rightframe"><b>SearchView</b></A><br>
    -+<A HREF="pkg_android.support.v7.widget.html#SearchView.OnCloseListener" class="hiddenlink" target="rightframe"><b><i>SearchView.OnCloseListener</i></b></A><br>
    -+<A HREF="pkg_android.support.v7.widget.html#SearchView.OnQueryTextListener" class="hiddenlink" target="rightframe"><b><i>SearchView.OnQueryTextListener</i></b></A><br>
    -+<A HREF="pkg_android.support.v7.widget.html#SearchView.OnSuggestionListener" class="hiddenlink" target="rightframe"><b><i>SearchView.OnSuggestionListener</i></b></A><br>
    -+<A HREF="android.support.v4.widget.SearchViewCompat.html" class="hiddenlink" target="rightframe">SearchViewCompat</A><br>
    -+<A HREF="pkg_android.support.v4.widget.html#SearchViewCompat.OnCloseListener" class="hiddenlink" target="rightframe"><b><i>SearchViewCompat.OnCloseListener</i></b></A><br>
    -+<A HREF="android.support.v4.widget.SearchViewCompat.OnCloseListenerCompat.html" class="hiddenlink" target="rightframe">SearchViewCompat.OnCloseListenerCompat</A><br>
    -+<A HREF="pkg_android.support.v4.widget.html#SearchViewCompat.OnQueryTextListener" class="hiddenlink" target="rightframe"><b><i>SearchViewCompat.OnQueryTextListener</i></b></A><br>
    -+<A HREF="android.support.v4.widget.SearchViewCompat.OnQueryTextListenerCompat.html" class="hiddenlink" target="rightframe">SearchViewCompat.OnQueryTextListenerCompat</A><br>
    -+<A HREF="android.support.v4.app.ServiceCompat.html" class="hiddenlink" target="rightframe">ServiceCompat</A><br>
    -+<A HREF="pkg_android.support.v7.widget.html#ShareActionProvider" class="hiddenlink" target="rightframe"><b>ShareActionProvider</b></A><br>
    -+<A HREF="pkg_android.support.v7.widget.html#ShareActionProvider.OnShareTargetSelectedListener" class="hiddenlink" target="rightframe"><b><i>ShareActionProvider.OnShareTargetSelectedListener</i></b></A><br>
    -+<A HREF="android.support.v4.app.SharedElementCallback.html" class="hiddenlink" target="rightframe">SharedElementCallback</A><br>
    -+<A HREF="pkg_android.support.v4.app.html#SharedElementCallback.OnSharedElementsReadyListener" class="hiddenlink" target="rightframe"><b><i>SharedElementCallback.OnSharedElementsReadyListener</i></b></A><br>
    -+<A HREF="pkg_android.support.v7.widget.html#SnapHelper" class="hiddenlink" target="rightframe"><b>SnapHelper</b></A><br>
    -+<A HREF="android.support.v7.util.SortedList.Callback.html" class="hiddenlink" target="rightframe">SortedList.Callback</A><br>
    -+<A HREF="pkg_android.support.v7.widget.html#Space" class="hiddenlink" target="rightframe"><b>Space</b></A><br>
    -+<A HREF="android.support.v7.widget.StaggeredGridLayoutManager.html" class="hiddenlink" target="rightframe">StaggeredGridLayoutManager</A><br>
    -+<A HREF="android.support.v4.widget.SwipeRefreshLayout.html" class="hiddenlink" target="rightframe">SwipeRefreshLayout</A><br>
    -+<A HREF="pkg_android.support.v4.widget.html#SwipeRefreshLayout.OnChildScrollUpCallback" class="hiddenlink" target="rightframe"><b><i>SwipeRefreshLayout.OnChildScrollUpCallback</i></b></A><br>
    -+<A HREF="pkg_android.support.v7.widget.html#SwitchCompat" class="hiddenlink" target="rightframe"><b>SwitchCompat</b></A><br>
    -+<A NAME="T"></A>
    -+<br><font size="+2">T</font>&nbsp;
    -+<a href="#A"><font size="-2">A</font></a> 
    -+<a href="#B"><font size="-2">B</font></a> 
    -+<a href="#C"><font size="-2">C</font></a> 
    -+<a href="#D"><font size="-2">D</font></a> 
    -+<a href="#F"><font size="-2">F</font></a> 
    -+<a href="#G"><font size="-2">G</font></a> 
    -+<a href="#K"><font size="-2">K</font></a> 
    -+<a href="#L"><font size="-2">L</font></a> 
    -+<a href="#M"><font size="-2">M</font></a> 
    -+<a href="#N"><font size="-2">N</font></a> 
    -+<a href="#O"><font size="-2">O</font></a> 
    -+<a href="#P"><font size="-2">P</font></a> 
    -+<a href="#R"><font size="-2">R</font></a> 
    -+<a href="#S"><font size="-2">S</font></a> 
    -+<a href="#V"><font size="-2">V</font></a> 
    -+<a href="#W"><font size="-2">W</font></a> 
    -+ <a href="#topheader"><font size="-2">TOP</font></a>
    -+<p><div style="line-height:1.5em;color:black">
    -+<A HREF="android.support.design.widget.TabLayout.html" class="hiddenlink" target="rightframe">TabLayout</A><br>
    -+<A HREF="android.support.design.widget.TextInputLayout.html" class="hiddenlink" target="rightframe">TextInputLayout</A><br>
    -+<A HREF="android.support.v4.widget.TextViewCompat.html" class="hiddenlink" target="rightframe">TextViewCompat</A><br>
    -+<A HREF="pkg_android.support.v7.widget.html#ThemedSpinnerAdapter" class="hiddenlink" target="rightframe"><b><i>ThemedSpinnerAdapter</i></b></A><br>
    -+<A HREF="pkg_android.support.v7.widget.html#ThemedSpinnerAdapter.Helper" class="hiddenlink" target="rightframe"><b>ThemedSpinnerAdapter.Helper</b></A><br>
    -+<A HREF="pkg_android.support.v7.widget.html#Toolbar" class="hiddenlink" target="rightframe"><b>Toolbar</b></A><br>
    -+<A HREF="pkg_android.support.v7.widget.html#Toolbar.LayoutParams" class="hiddenlink" target="rightframe"><b>Toolbar.LayoutParams</b></A><br>
    -+<A HREF="pkg_android.support.v7.widget.html#Toolbar.OnMenuItemClickListener" class="hiddenlink" target="rightframe"><b><i>Toolbar.OnMenuItemClickListener</i></b></A><br>
    -+<A HREF="pkg_android.support.v7.widget.html#Toolbar.SavedState" class="hiddenlink" target="rightframe"><b>Toolbar.SavedState</b></A><br>
    -+<A NAME="V"></A>
    -+<br><font size="+2">V</font>&nbsp;
    -+<a href="#A"><font size="-2">A</font></a> 
    -+<a href="#B"><font size="-2">B</font></a> 
    -+<a href="#C"><font size="-2">C</font></a> 
    -+<a href="#D"><font size="-2">D</font></a> 
    -+<a href="#F"><font size="-2">F</font></a> 
    -+<a href="#G"><font size="-2">G</font></a> 
    -+<a href="#K"><font size="-2">K</font></a> 
    -+<a href="#L"><font size="-2">L</font></a> 
    -+<a href="#M"><font size="-2">M</font></a> 
    -+<a href="#N"><font size="-2">N</font></a> 
    -+<a href="#O"><font size="-2">O</font></a> 
    -+<a href="#P"><font size="-2">P</font></a> 
    -+<a href="#R"><font size="-2">R</font></a> 
    -+<a href="#S"><font size="-2">S</font></a> 
    -+<a href="#T"><font size="-2">T</font></a> 
    -+<a href="#W"><font size="-2">W</font></a> 
    -+ <a href="#topheader"><font size="-2">TOP</font></a>
    -+<p><div style="line-height:1.5em;color:black">
    -+<A HREF="android.support.v4.view.ViewCompat.html" class="hiddenlink" target="rightframe">ViewCompat</A><br>
    -+<A HREF="android.support.v4.view.ViewConfigurationCompat.html" class="hiddenlink" target="rightframe">ViewConfigurationCompat</A><br>
    -+<A NAME="W"></A>
    -+<br><font size="+2">W</font>&nbsp;
    -+<a href="#A"><font size="-2">A</font></a> 
    -+<a href="#B"><font size="-2">B</font></a> 
    -+<a href="#C"><font size="-2">C</font></a> 
    -+<a href="#D"><font size="-2">D</font></a> 
    -+<a href="#F"><font size="-2">F</font></a> 
    -+<a href="#G"><font size="-2">G</font></a> 
    -+<a href="#K"><font size="-2">K</font></a> 
    -+<a href="#L"><font size="-2">L</font></a> 
    -+<a href="#M"><font size="-2">M</font></a> 
    -+<a href="#N"><font size="-2">N</font></a> 
    -+<a href="#O"><font size="-2">O</font></a> 
    -+<a href="#P"><font size="-2">P</font></a> 
    -+<a href="#R"><font size="-2">R</font></a> 
    -+<a href="#S"><font size="-2">S</font></a> 
    -+<a href="#T"><font size="-2">T</font></a> 
    -+<a href="#V"><font size="-2">V</font></a> 
    -+ <a href="#topheader"><font size="-2">TOP</font></a>
    -+<p><div style="line-height:1.5em;color:black">
    -+<A HREF="android.support.v4.view.WindowInsetsCompat.html" class="hiddenlink" target="rightframe">WindowInsetsCompat</A><br>
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    -+</script>
    -+<script type="text/javascript">
    -+  try {
    -+    var pageTracker = _gat._getTracker("UA-5831155-1");
    -+    pageTracker._setAllowAnchor(true);
    -+    pageTracker._initData();
    -+    pageTracker._trackPageview();
    -+  } catch(e) {}
    -+</script>
    -+</BODY>
    -+</HTML>
    -diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/classes_index_changes.html b/docs/html/sdk/support_api_diff/24.2.0/changes/classes_index_changes.html
    -new file mode 100644
    -index 0000000..58fe615
    ---- /dev/null
    -+++ b/docs/html/sdk/support_api_diff/24.2.0/changes/classes_index_changes.html
    -@@ -0,0 +1,394 @@
    -+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
    -+<HTML style="overflow:auto;">
    -+<HEAD>
    -+<meta name="generator" content="JDiff v1.1.0">
    -+<!-- Generated by the JDiff Javadoc doclet -->
    -+<!-- (http://www.jdiff.org) -->
    -+<meta name="description" content="JDiff is a Javadoc doclet which generates an HTML report of all the packages, classes, constructors, methods, and fields which have been removed, added or changed in any way, including their documentation, when two APIs are compared.">
    -+<meta name="keywords" content="diff, jdiff, javadiff, java diff, java difference, API difference, difference between two APIs, API diff, Javadoc, doclet">
    -+<TITLE>
    -+Class Changes Index
    -+</TITLE>
    -+<link href="../../../../assets/android-developer-docs.css" rel="stylesheet" type="text/css" />
    -+<link href="../stylesheet-jdiff.css" rel="stylesheet" type="text/css" />
    -+<noscript>
    -+<style type="text/css">
    -+body{overflow:auto;}
    -+#body-content{position:relative; top:0;}
    -+#doc-content{overflow:visible;border-left:3px solid #666;}
    -+#side-nav{padding:0;}
    -+#side-nav .toggle-list ul {display:block;}
    -+#resize-packages-nav{border-bottom:3px solid #666;}
    -+</style>
    -+</noscript>
    -+<style type="text/css">
    -+</style>
    -+</HEAD>
    -+<BODY class="gc-documentation" style="padding:12px;">
    -+<a NAME="topheader"></a>
    -+<table summary="Index for Classes" width="100%" class="jdiffIndex" border="0" cellspacing="0" cellpadding="0" style="padding-bottom:0;margin-bottom:0;">
    -+  <tr>
    -+  <th class="indexHeader">
    -+    Filter the Index:
    -+  </th>
    -+  </tr>
    -+  <tr>
    -+  <td class="indexText" style="line-height:1.3em;padding-left:2em;">
    -+<a href="classes_index_all.html" class="staysblack">All Classes</a>
    -+  <br>
    -+<font color="#999999">Removals</font>
    -+  <br>
    -+<A HREF="classes_index_additions.html"xclass="hiddenlink">Additions</A>
    -+  <br>
    -+<b>Changes</b>
    -+  </td>
    -+  </tr>
    -+</table>
    -+<div id="indexTableCaption" style="background-color:#eee;padding:0 4px 0 4px;font-size:11px;margin-bottom:1em;">
    -+Listed as: <span style="color:#069"><strong>Added</strong></span>,  <span style="color:#069"><strike>Removed</strike></span>,  <span style="color:#069">Changed</span></font>
    -+</div>
    -+<A NAME="A"></A>
    -+<br><font size="+2">A</font>&nbsp;
    -+<a href="#B"><font size="-2">B</font></a> 
    -+<a href="#C"><font size="-2">C</font></a> 
    -+<a href="#D"><font size="-2">D</font></a> 
    -+<a href="#F"><font size="-2">F</font></a> 
    -+<a href="#K"><font size="-2">K</font></a> 
    -+<a href="#L"><font size="-2">L</font></a> 
    -+<a href="#M"><font size="-2">M</font></a> 
    -+<a href="#O"><font size="-2">O</font></a> 
    -+<a href="#P"><font size="-2">P</font></a> 
    -+<a href="#R"><font size="-2">R</font></a> 
    -+<a href="#S"><font size="-2">S</font></a> 
    -+<a href="#T"><font size="-2">T</font></a> 
    -+<a href="#V"><font size="-2">V</font></a> 
    -+<a href="#W"><font size="-2">W</font></a> 
    -+ <a href="#topheader"><font size="-2">TOP</font></a>
    -+<p><div style="line-height:1.5em;color:black">
    -+<A HREF="android.support.v17.leanback.widget.AbstractMediaItemPresenter.html" class="hiddenlink" target="rightframe">AbstractMediaItemPresenter</A><br>
    -+<A HREF="android.support.v17.leanback.widget.AbstractMediaItemPresenter.ViewHolder.html" class="hiddenlink" target="rightframe">AbstractMediaItemPresenter.ViewHolder</A><br>
    -+<A HREF="android.support.v4.view.accessibility.AccessibilityEventCompat.html" class="hiddenlink" target="rightframe">AccessibilityEventCompat</A><br>
    -+<A HREF="android.support.v4.view.accessibility.AccessibilityManagerCompat.html" class="hiddenlink" target="rightframe">AccessibilityManagerCompat</A><br>
    -+<A HREF="android.support.v4.view.accessibility.AccessibilityManagerCompat.AccessibilityStateChangeListenerCompat.html" class="hiddenlink" target="rightframe">AccessibilityManagerCompat.AccessibilityStateChangeListenerCompat</A><br>
    -+<A HREF="android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.html" class="hiddenlink" target="rightframe">AccessibilityNodeInfoCompat</A><br>
    -+<A HREF="android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat.html" class="hiddenlink" target="rightframe">AccessibilityNodeInfoCompat.AccessibilityActionCompat</A><br>
    -+<A HREF="android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.CollectionInfoCompat.html" class="hiddenlink" target="rightframe">AccessibilityNodeInfoCompat.CollectionInfoCompat</A><br>
    -+<A HREF="android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.CollectionItemInfoCompat.html" class="hiddenlink" target="rightframe">AccessibilityNodeInfoCompat.CollectionItemInfoCompat</A><br>
    -+<A HREF="android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.RangeInfoCompat.html" class="hiddenlink" target="rightframe">AccessibilityNodeInfoCompat.RangeInfoCompat</A><br>
    -+<A HREF="android.support.v4.view.accessibility.AccessibilityNodeProviderCompat.html" class="hiddenlink" target="rightframe">AccessibilityNodeProviderCompat</A><br>
    -+<A HREF="android.support.v4.accessibilityservice.AccessibilityServiceInfoCompat.html" class="hiddenlink" target="rightframe">AccessibilityServiceInfoCompat</A><br>
    -+<A HREF="android.support.v4.view.accessibility.AccessibilityWindowInfoCompat.html" class="hiddenlink" target="rightframe">AccessibilityWindowInfoCompat</A><br>
    -+<A HREF="android.support.v7.app.ActionBarDrawerToggle.html" class="hiddenlink" target="rightframe">ActionBarDrawerToggle</A><br>
    -+<A HREF="android.support.v4.app.ActivityCompat.html" class="hiddenlink" target="rightframe">ActivityCompat</A><br>
    -+<A HREF="android.support.v4.app.ActivityOptionsCompat.html" class="hiddenlink" target="rightframe">ActivityOptionsCompat</A><br>
    -+<A HREF="android.support.design.widget.AppBarLayout.ScrollingViewBehavior.html" class="hiddenlink" target="rightframe">AppBarLayout.ScrollingViewBehavior</A><br>
    -+<A HREF="android.support.v7.app.AppCompatDelegate.html" class="hiddenlink" target="rightframe">AppCompatDelegate</A><br>
    -+<A HREF="android.support.v7.content.res.AppCompatResources.html" class="hiddenlink" target="rightframe">AppCompatResources</A><br>
    -+<A NAME="B"></A>
    -+<br><font size="+2">B</font>&nbsp;
    -+<a href="#A"><font size="-2">A</font></a> 
    -+<a href="#C"><font size="-2">C</font></a> 
    -+<a href="#D"><font size="-2">D</font></a> 
    -+<a href="#F"><font size="-2">F</font></a> 
    -+<a href="#K"><font size="-2">K</font></a> 
    -+<a href="#L"><font size="-2">L</font></a> 
    -+<a href="#M"><font size="-2">M</font></a> 
    -+<a href="#O"><font size="-2">O</font></a> 
    -+<a href="#P"><font size="-2">P</font></a> 
    -+<a href="#R"><font size="-2">R</font></a> 
    -+<a href="#S"><font size="-2">S</font></a> 
    -+<a href="#T"><font size="-2">T</font></a> 
    -+<a href="#V"><font size="-2">V</font></a> 
    -+<a href="#W"><font size="-2">W</font></a> 
    -+ <a href="#topheader"><font size="-2">TOP</font></a>
    -+<p><div style="line-height:1.5em;color:black">
    -+<A HREF="android.support.design.widget.BottomSheetBehavior.html" class="hiddenlink" target="rightframe">BottomSheetBehavior</A><br>
    -+<A HREF="android.support.v4.os.BuildCompat.html" class="hiddenlink" target="rightframe">BuildCompat</A><br>
    -+<A NAME="C"></A>
    -+<br><font size="+2">C</font>&nbsp;
    -+<a href="#A"><font size="-2">A</font></a> 
    -+<a href="#B"><font size="-2">B</font></a> 
    -+<a href="#D"><font size="-2">D</font></a> 
    -+<a href="#F"><font size="-2">F</font></a> 
    -+<a href="#K"><font size="-2">K</font></a> 
    -+<a href="#L"><font size="-2">L</font></a> 
    -+<a href="#M"><font size="-2">M</font></a> 
    -+<a href="#O"><font size="-2">O</font></a> 
    -+<a href="#P"><font size="-2">P</font></a> 
    -+<a href="#R"><font size="-2">R</font></a> 
    -+<a href="#S"><font size="-2">S</font></a> 
    -+<a href="#T"><font size="-2">T</font></a> 
    -+<a href="#V"><font size="-2">V</font></a> 
    -+<a href="#W"><font size="-2">W</font></a> 
    -+ <a href="#topheader"><font size="-2">TOP</font></a>
    -+<p><div style="line-height:1.5em;color:black">
    -+<A HREF="android.support.design.widget.CollapsingToolbarLayout.html" class="hiddenlink" target="rightframe">CollapsingToolbarLayout</A><br>
    -+<A HREF="android.support.v4.content.ContextCompat.html" class="hiddenlink" target="rightframe">ContextCompat</A><br>
    -+<A HREF="android.support.design.widget.CoordinatorLayout.html" class="hiddenlink" target="rightframe">CoordinatorLayout</A><br>
    -+<A HREF="android.support.design.widget.CoordinatorLayout.Behavior.html" class="hiddenlink" target="rightframe">CoordinatorLayout.Behavior</A><br>
    -+<A HREF="android.support.design.widget.CoordinatorLayout.LayoutParams.html" class="hiddenlink" target="rightframe">CoordinatorLayout.LayoutParams</A><br>
    -+<A HREF="android.support.customtabs.CustomTabsIntent.html" class="hiddenlink" target="rightframe">CustomTabsIntent</A><br>
    -+<A HREF="android.support.customtabs.CustomTabsIntent.Builder.html" class="hiddenlink" target="rightframe">CustomTabsIntent.Builder</A><br>
    -+<A HREF="android.support.customtabs.CustomTabsSession.html" class="hiddenlink" target="rightframe">CustomTabsSession</A><br>
    -+<A NAME="D"></A>
    -+<br><font size="+2">D</font>&nbsp;
    -+<a href="#A"><font size="-2">A</font></a> 
    -+<a href="#B"><font size="-2">B</font></a> 
    -+<a href="#C"><font size="-2">C</font></a> 
    -+<a href="#F"><font size="-2">F</font></a> 
    -+<a href="#K"><font size="-2">K</font></a> 
    -+<a href="#L"><font size="-2">L</font></a> 
    -+<a href="#M"><font size="-2">M</font></a> 
    -+<a href="#O"><font size="-2">O</font></a> 
    -+<a href="#P"><font size="-2">P</font></a> 
    -+<a href="#R"><font size="-2">R</font></a> 
    -+<a href="#S"><font size="-2">S</font></a> 
    -+<a href="#T"><font size="-2">T</font></a> 
    -+<a href="#V"><font size="-2">V</font></a> 
    -+<a href="#W"><font size="-2">W</font></a> 
    -+ <a href="#topheader"><font size="-2">TOP</font></a>
    -+<p><div style="line-height:1.5em;color:black">
    -+<A HREF="android.support.v4.graphics.drawable.DrawableCompat.html" class="hiddenlink" target="rightframe">DrawableCompat</A><br>
    -+<A NAME="F"></A>
    -+<br><font size="+2">F</font>&nbsp;
    -+<a href="#A"><font size="-2">A</font></a> 
    -+<a href="#B"><font size="-2">B</font></a> 
    -+<a href="#C"><font size="-2">C</font></a> 
    -+<a href="#D"><font size="-2">D</font></a> 
    -+<a href="#K"><font size="-2">K</font></a> 
    -+<a href="#L"><font size="-2">L</font></a> 
    -+<a href="#M"><font size="-2">M</font></a> 
    -+<a href="#O"><font size="-2">O</font></a> 
    -+<a href="#P"><font size="-2">P</font></a> 
    -+<a href="#R"><font size="-2">R</font></a> 
    -+<a href="#S"><font size="-2">S</font></a> 
    -+<a href="#T"><font size="-2">T</font></a> 
    -+<a href="#V"><font size="-2">V</font></a> 
    -+<a href="#W"><font size="-2">W</font></a> 
    -+ <a href="#topheader"><font size="-2">TOP</font></a>
    -+<p><div style="line-height:1.5em;color:black">
    -+<A HREF="android.support.design.widget.FloatingActionButton.Behavior.html" class="hiddenlink" target="rightframe">FloatingActionButton.Behavior</A><br>
    -+<A HREF="android.support.v4.app.FragmentController.html" class="hiddenlink" target="rightframe">FragmentController</A><br>
    -+<A NAME="K"></A>
    -+<br><font size="+2">K</font>&nbsp;
    -+<a href="#A"><font size="-2">A</font></a> 
    -+<a href="#B"><font size="-2">B</font></a> 
    -+<a href="#C"><font size="-2">C</font></a> 
    -+<a href="#D"><font size="-2">D</font></a> 
    -+<a href="#F"><font size="-2">F</font></a> 
    -+<a href="#L"><font size="-2">L</font></a> 
    -+<a href="#M"><font size="-2">M</font></a> 
    -+<a href="#O"><font size="-2">O</font></a> 
    -+<a href="#P"><font size="-2">P</font></a> 
    -+<a href="#R"><font size="-2">R</font></a> 
    -+<a href="#S"><font size="-2">S</font></a> 
    -+<a href="#T"><font size="-2">T</font></a> 
    -+<a href="#V"><font size="-2">V</font></a> 
    -+<a href="#W"><font size="-2">W</font></a> 
    -+ <a href="#topheader"><font size="-2">TOP</font></a>
    -+<p><div style="line-height:1.5em;color:black">
    -+<A HREF="android.support.v4.view.KeyEventCompat.html" class="hiddenlink" target="rightframe">KeyEventCompat</A><br>
    -+<A NAME="L"></A>
    -+<br><font size="+2">L</font>&nbsp;
    -+<a href="#A"><font size="-2">A</font></a> 
    -+<a href="#B"><font size="-2">B</font></a> 
    -+<a href="#C"><font size="-2">C</font></a> 
    -+<a href="#D"><font size="-2">D</font></a> 
    -+<a href="#F"><font size="-2">F</font></a> 
    -+<a href="#K"><font size="-2">K</font></a> 
    -+<a href="#M"><font size="-2">M</font></a> 
    -+<a href="#O"><font size="-2">O</font></a> 
    -+<a href="#P"><font size="-2">P</font></a> 
    -+<a href="#R"><font size="-2">R</font></a> 
    -+<a href="#S"><font size="-2">S</font></a> 
    -+<a href="#T"><font size="-2">T</font></a> 
    -+<a href="#V"><font size="-2">V</font></a> 
    -+<a href="#W"><font size="-2">W</font></a> 
    -+ <a href="#topheader"><font size="-2">TOP</font></a>
    -+<p><div style="line-height:1.5em;color:black">
    -+<A HREF="android.support.v17.preference.LeanbackSettingsFragment.html" class="hiddenlink" target="rightframe">LeanbackSettingsFragment</A><br>
    -+<A HREF="android.support.v7.widget.LinearLayoutManager.html" class="hiddenlink" target="rightframe">LinearLayoutManager</A><br>
    -+<A HREF="android.support.v7.widget.LinearSmoothScroller.html" class="hiddenlink" target="rightframe">LinearSmoothScroller</A><br>
    -+<A NAME="M"></A>
    -+<br><font size="+2">M</font>&nbsp;
    -+<a href="#A"><font size="-2">A</font></a> 
    -+<a href="#B"><font size="-2">B</font></a> 
    -+<a href="#C"><font size="-2">C</font></a> 
    -+<a href="#D"><font size="-2">D</font></a> 
    -+<a href="#F"><font size="-2">F</font></a> 
    -+<a href="#K"><font size="-2">K</font></a> 
    -+<a href="#L"><font size="-2">L</font></a> 
    -+<a href="#O"><font size="-2">O</font></a> 
    -+<a href="#P"><font size="-2">P</font></a> 
    -+<a href="#R"><font size="-2">R</font></a> 
    -+<a href="#S"><font size="-2">S</font></a> 
    -+<a href="#T"><font size="-2">T</font></a> 
    -+<a href="#V"><font size="-2">V</font></a> 
    -+<a href="#W"><font size="-2">W</font></a> 
    -+ <a href="#topheader"><font size="-2">TOP</font></a>
    -+<p><div style="line-height:1.5em;color:black">
    -+<A HREF="android.support.v4.media.MediaBrowserCompat.MediaItem.html" class="hiddenlink" target="rightframe">MediaBrowserCompat.MediaItem</A><br>
    -+<A HREF="android.support.v4.media.MediaBrowserServiceCompat.BrowserRoot.html" class="hiddenlink" target="rightframe">MediaBrowserServiceCompat.BrowserRoot</A><br>
    -+<A HREF="android.support.v4.media.session.MediaButtonReceiver.html" class="hiddenlink" target="rightframe">MediaButtonReceiver</A><br>
    -+<A HREF="android.support.v4.media.MediaDescriptionCompat.html" class="hiddenlink" target="rightframe">MediaDescriptionCompat</A><br>
    -+<A HREF="android.support.v4.media.MediaMetadataCompat.html" class="hiddenlink" target="rightframe">MediaMetadataCompat</A><br>
    -+<A HREF="android.support.v4.media.session.MediaSessionCompat.html" class="hiddenlink" target="rightframe">MediaSessionCompat</A><br>
    -+<A HREF="android.support.v4.media.session.MediaSessionCompat.QueueItem.html" class="hiddenlink" target="rightframe">MediaSessionCompat.QueueItem</A><br>
    -+<A HREF="android.support.v4.view.MotionEventCompat.html" class="hiddenlink" target="rightframe">MotionEventCompat</A><br>
    -+<A NAME="O"></A>
    -+<br><font size="+2">O</font>&nbsp;
    -+<a href="#A"><font size="-2">A</font></a> 
    -+<a href="#B"><font size="-2">B</font></a> 
    -+<a href="#C"><font size="-2">C</font></a> 
    -+<a href="#D"><font size="-2">D</font></a> 
    -+<a href="#F"><font size="-2">F</font></a> 
    -+<a href="#K"><font size="-2">K</font></a> 
    -+<a href="#L"><font size="-2">L</font></a> 
    -+<a href="#M"><font size="-2">M</font></a> 
    -+<a href="#P"><font size="-2">P</font></a> 
    -+<a href="#R"><font size="-2">R</font></a> 
    -+<a href="#S"><font size="-2">S</font></a> 
    -+<a href="#T"><font size="-2">T</font></a> 
    -+<a href="#V"><font size="-2">V</font></a> 
    -+<a href="#W"><font size="-2">W</font></a> 
    -+ <a href="#topheader"><font size="-2">TOP</font></a>
    -+<p><div style="line-height:1.5em;color:black">
    -+<A HREF="android.support.v17.leanback.widget.ObjectAdapter.html" class="hiddenlink" target="rightframe">ObjectAdapter</A><br>
    -+<A NAME="P"></A>
    -+<br><font size="+2">P</font>&nbsp;
    -+<a href="#A"><font size="-2">A</font></a> 
    -+<a href="#B"><font size="-2">B</font></a> 
    -+<a href="#C"><font size="-2">C</font></a> 
    -+<a href="#D"><font size="-2">D</font></a> 
    -+<a href="#F"><font size="-2">F</font></a> 
    -+<a href="#K"><font size="-2">K</font></a> 
    -+<a href="#L"><font size="-2">L</font></a> 
    -+<a href="#M"><font size="-2">M</font></a> 
    -+<a href="#O"><font size="-2">O</font></a> 
    -+<a href="#R"><font size="-2">R</font></a> 
    -+<a href="#S"><font size="-2">S</font></a> 
    -+<a href="#T"><font size="-2">T</font></a> 
    -+<a href="#V"><font size="-2">V</font></a> 
    -+<a href="#W"><font size="-2">W</font></a> 
    -+ <a href="#topheader"><font size="-2">TOP</font></a>
    -+<p><div style="line-height:1.5em;color:black">
    -+<A HREF="android.support.v7.graphics.Palette.html" class="hiddenlink" target="rightframe">Palette</A><br>
    -+<A HREF="android.support.v4.media.session.PlaybackStateCompat.html" class="hiddenlink" target="rightframe">PlaybackStateCompat</A><br>
    -+<A HREF="android.support.v14.preference.PreferenceFragment.html" class="hiddenlink" target="rightframe">PreferenceFragment</A><br>
    -+<A NAME="R"></A>
    -+<br><font size="+2">R</font>&nbsp;
    -+<a href="#A"><font size="-2">A</font></a> 
    -+<a href="#B"><font size="-2">B</font></a> 
    -+<a href="#C"><font size="-2">C</font></a> 
    -+<a href="#D"><font size="-2">D</font></a> 
    -+<a href="#F"><font size="-2">F</font></a> 
    -+<a href="#K"><font size="-2">K</font></a> 
    -+<a href="#L"><font size="-2">L</font></a> 
    -+<a href="#M"><font size="-2">M</font></a> 
    -+<a href="#O"><font size="-2">O</font></a> 
    -+<a href="#P"><font size="-2">P</font></a> 
    -+<a href="#S"><font size="-2">S</font></a> 
    -+<a href="#T"><font size="-2">T</font></a> 
    -+<a href="#V"><font size="-2">V</font></a> 
    -+<a href="#W"><font size="-2">W</font></a> 
    -+ <a href="#topheader"><font size="-2">TOP</font></a>
    -+<p><div style="line-height:1.5em;color:black">
    -+<A HREF="android.support.v7.widget.RecyclerView.html" class="hiddenlink" target="rightframe">RecyclerView</A><br>
    -+<A NAME="S"></A>
    -+<br><font size="+2">S</font>&nbsp;
    -+<a href="#A"><font size="-2">A</font></a> 
    -+<a href="#B"><font size="-2">B</font></a> 
    -+<a href="#C"><font size="-2">C</font></a> 
    -+<a href="#D"><font size="-2">D</font></a> 
    -+<a href="#F"><font size="-2">F</font></a> 
    -+<a href="#K"><font size="-2">K</font></a> 
    -+<a href="#L"><font size="-2">L</font></a> 
    -+<a href="#M"><font size="-2">M</font></a> 
    -+<a href="#O"><font size="-2">O</font></a> 
    -+<a href="#P"><font size="-2">P</font></a> 
    -+<a href="#R"><font size="-2">R</font></a> 
    -+<a href="#T"><font size="-2">T</font></a> 
    -+<a href="#V"><font size="-2">V</font></a> 
    -+<a href="#W"><font size="-2">W</font></a> 
    -+ <a href="#topheader"><font size="-2">TOP</font></a>
    -+<p><div style="line-height:1.5em;color:black">
    -+<A HREF="android.support.v4.widget.SearchViewCompat.html" class="hiddenlink" target="rightframe">SearchViewCompat</A><br>
    -+<A HREF="android.support.v4.widget.SearchViewCompat.OnCloseListenerCompat.html" class="hiddenlink" target="rightframe">SearchViewCompat.OnCloseListenerCompat</A><br>
    -+<A HREF="android.support.v4.widget.SearchViewCompat.OnQueryTextListenerCompat.html" class="hiddenlink" target="rightframe">SearchViewCompat.OnQueryTextListenerCompat</A><br>
    -+<A HREF="android.support.v4.app.ServiceCompat.html" class="hiddenlink" target="rightframe">ServiceCompat</A><br>
    -+<A HREF="android.support.v4.app.SharedElementCallback.html" class="hiddenlink" target="rightframe">SharedElementCallback</A><br>
    -+<A HREF="android.support.v7.util.SortedList.Callback.html" class="hiddenlink" target="rightframe">SortedList.Callback</A><br>
    -+<A HREF="android.support.v7.widget.StaggeredGridLayoutManager.html" class="hiddenlink" target="rightframe">StaggeredGridLayoutManager</A><br>
    -+<A HREF="android.support.v4.widget.SwipeRefreshLayout.html" class="hiddenlink" target="rightframe">SwipeRefreshLayout</A><br>
    -+<A NAME="T"></A>
    -+<br><font size="+2">T</font>&nbsp;
    -+<a href="#A"><font size="-2">A</font></a> 
    -+<a href="#B"><font size="-2">B</font></a> 
    -+<a href="#C"><font size="-2">C</font></a> 
    -+<a href="#D"><font size="-2">D</font></a> 
    -+<a href="#F"><font size="-2">F</font></a> 
    -+<a href="#K"><font size="-2">K</font></a> 
    -+<a href="#L"><font size="-2">L</font></a> 
    -+<a href="#M"><font size="-2">M</font></a> 
    -+<a href="#O"><font size="-2">O</font></a> 
    -+<a href="#P"><font size="-2">P</font></a> 
    -+<a href="#R"><font size="-2">R</font></a> 
    -+<a href="#S"><font size="-2">S</font></a> 
    -+<a href="#V"><font size="-2">V</font></a> 
    -+<a href="#W"><font size="-2">W</font></a> 
    -+ <a href="#topheader"><font size="-2">TOP</font></a>
    -+<p><div style="line-height:1.5em;color:black">
    -+<A HREF="android.support.design.widget.TabLayout.html" class="hiddenlink" target="rightframe">TabLayout</A><br>
    -+<A HREF="android.support.design.widget.TextInputLayout.html" class="hiddenlink" target="rightframe">TextInputLayout</A><br>
    -+<A HREF="android.support.v4.widget.TextViewCompat.html" class="hiddenlink" target="rightframe">TextViewCompat</A><br>
    -+<A NAME="V"></A>
    -+<br><font size="+2">V</font>&nbsp;
    -+<a href="#A"><font size="-2">A</font></a> 
    -+<a href="#B"><font size="-2">B</font></a> 
    -+<a href="#C"><font size="-2">C</font></a> 
    -+<a href="#D"><font size="-2">D</font></a> 
    -+<a href="#F"><font size="-2">F</font></a> 
    -+<a href="#K"><font size="-2">K</font></a> 
    -+<a href="#L"><font size="-2">L</font></a> 
    -+<a href="#M"><font size="-2">M</font></a> 
    -+<a href="#O"><font size="-2">O</font></a> 
    -+<a href="#P"><font size="-2">P</font></a> 
    -+<a href="#R"><font size="-2">R</font></a> 
    -+<a href="#S"><font size="-2">S</font></a> 
    -+<a href="#T"><font size="-2">T</font></a> 
    -+<a href="#W"><font size="-2">W</font></a> 
    -+ <a href="#topheader"><font size="-2">TOP</font></a>
    -+<p><div style="line-height:1.5em;color:black">
    -+<A HREF="android.support.v4.view.ViewCompat.html" class="hiddenlink" target="rightframe">ViewCompat</A><br>
    -+<A HREF="android.support.v4.view.ViewConfigurationCompat.html" class="hiddenlink" target="rightframe">ViewConfigurationCompat</A><br>
    -+<A NAME="W"></A>
    -+<br><font size="+2">W</font>&nbsp;
    -+<a href="#A"><font size="-2">A</font></a> 
    -+<a href="#B"><font size="-2">B</font></a> 
    -+<a href="#C"><font size="-2">C</font></a> 
    -+<a href="#D"><font size="-2">D</font></a> 
    -+<a href="#F"><font size="-2">F</font></a> 
    -+<a href="#K"><font size="-2">K</font></a> 
    -+<a href="#L"><font size="-2">L</font></a> 
    -+<a href="#M"><font size="-2">M</font></a> 
    -+<a href="#O"><font size="-2">O</font></a> 
    -+<a href="#P"><font size="-2">P</font></a> 
    -+<a href="#R"><font size="-2">R</font></a> 
    -+<a href="#S"><font size="-2">S</font></a> 
    -+<a href="#T"><font size="-2">T</font></a> 
    -+<a href="#V"><font size="-2">V</font></a> 
    -+ <a href="#topheader"><font size="-2">TOP</font></a>
    -+<p><div style="line-height:1.5em;color:black">
    -+<A HREF="android.support.v4.view.WindowInsetsCompat.html" class="hiddenlink" target="rightframe">WindowInsetsCompat</A><br>
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    -+</script>
    -+<script type="text/javascript">
    -+  try {
    -+    var pageTracker = _gat._getTracker("UA-5831155-1");
    -+    pageTracker._setAllowAnchor(true);
    -+    pageTracker._initData();
    -+    pageTracker._trackPageview();
    -+  } catch(e) {}
    -+</script>
    -+</BODY>
    -+</HTML>
    -diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/classes_index_removals.html b/docs/html/sdk/support_api_diff/24.2.0/changes/classes_index_removals.html
    -new file mode 100644
    -index 0000000..c466298
    ---- /dev/null
    -+++ b/docs/html/sdk/support_api_diff/24.2.0/changes/classes_index_removals.html
    -@@ -0,0 +1,61 @@
    -+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
    -+<HTML style="overflow:auto;">
    -+<HEAD>
    -+<meta name="generator" content="JDiff v1.1.0">
    -+<!-- Generated by the JDiff Javadoc doclet -->
    -+<!-- (http://www.jdiff.org) -->
    -+<meta name="description" content="JDiff is a Javadoc doclet which generates an HTML report of all the packages, classes, constructors, methods, and fields which have been removed, added or changed in any way, including their documentation, when two APIs are compared.">
    -+<meta name="keywords" content="diff, jdiff, javadiff, java diff, java difference, API difference, difference between two APIs, API diff, Javadoc, doclet">
    -+<TITLE>
    -+Class Removals Index
    -+</TITLE>
    -+<link href="../../../../assets/android-developer-docs.css" rel="stylesheet" type="text/css" />
    -+<link href="../stylesheet-jdiff.css" rel="stylesheet" type="text/css" />
    -+<noscript>
    -+<style type="text/css">
    -+body{overflow:auto;}
    -+#body-content{position:relative; top:0;}
    -+#doc-content{overflow:visible;border-left:3px solid #666;}
    -+#side-nav{padding:0;}
    -+#side-nav .toggle-list ul {display:block;}
    -+#resize-packages-nav{border-bottom:3px solid #666;}
    -+</style>
    -+</noscript>
    -+<style type="text/css">
    -+</style>
    -+</HEAD>
    -+<BODY class="gc-documentation" style="padding:12px;">
    -+<a NAME="topheader"></a>
    -+<table summary="Index for Classes" width="100%" class="jdiffIndex" border="0" cellspacing="0" cellpadding="0" style="padding-bottom:0;margin-bottom:0;">
    -+  <tr>
    -+  <th class="indexHeader">
    -+    Filter the Index:
    -+  </th>
    -+  </tr>
    -+  <tr>
    -+  <td class="indexText" style="line-height:1.3em;padding-left:2em;">
    -+<a href="classes_index_all.html" class="staysblack">All Classes</a>
    -+  <br>
    -+<font color="#999999">Removals</font>
    -+  <br>
    -+<A HREF="classes_index_additions.html"xclass="hiddenlink">Additions</A>
    -+  <br>
    -+<A HREF="classes_index_changes.html"xclass="hiddenlink">Changes</A>
    -+  </td>
    -+  </tr>
    -+</table>
    -+<div id="indexTableCaption" style="background-color:#eee;padding:0 4px 0 4px;font-size:11px;margin-bottom:1em;">
    -+Listed as: <span style="color:#069"><strong>Added</strong></span>,  <span style="color:#069"><strike>Removed</strike></span>,  <span style="color:#069">Changed</span></font>
    -+</div>
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    -+</script>
    -+<script type="text/javascript">
    -+  try {
    -+    var pageTracker = _gat._getTracker("UA-5831155-1");
    -+    pageTracker._setAllowAnchor(true);
    -+    pageTracker._initData();
    -+    pageTracker._trackPageview();
    -+  } catch(e) {}
    -+</script>
    -+</BODY>
    -+</HTML>
    -diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/constructors_index_additions.html b/docs/html/sdk/support_api_diff/24.2.0/changes/constructors_index_additions.html
    -new file mode 100644
    -index 0000000..312effc
    ---- /dev/null
    -+++ b/docs/html/sdk/support_api_diff/24.2.0/changes/constructors_index_additions.html
    -@@ -0,0 +1,67 @@
    -+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
    -+<HTML style="overflow:auto;">
    -+<HEAD>
    -+<meta name="generator" content="JDiff v1.1.0">
    -+<!-- Generated by the JDiff Javadoc doclet -->
    -+<!-- (http://www.jdiff.org) -->
    -+<meta name="description" content="JDiff is a Javadoc doclet which generates an HTML report of all the packages, classes, constructors, methods, and fields which have been removed, added or changed in any way, including their documentation, when two APIs are compared.">
    -+<meta name="keywords" content="diff, jdiff, javadiff, java diff, java difference, API difference, difference between two APIs, API diff, Javadoc, doclet">
    -+<TITLE>
    -+Constructor Additions Index
    -+</TITLE>
    -+<link href="../../../../assets/android-developer-docs.css" rel="stylesheet" type="text/css" />
    -+<link href="../stylesheet-jdiff.css" rel="stylesheet" type="text/css" />
    -+<noscript>
    -+<style type="text/css">
    -+body{overflow:auto;}
    -+#body-content{position:relative; top:0;}
    -+#doc-content{overflow:visible;border-left:3px solid #666;}
    -+#side-nav{padding:0;}
    -+#side-nav .toggle-list ul {display:block;}
    -+#resize-packages-nav{border-bottom:3px solid #666;}
    -+</style>
    -+</noscript>
    -+<style type="text/css">
    -+</style>
    -+</HEAD>
    -+<BODY class="gc-documentation" style="padding:12px;">
    -+<a NAME="topheader"></a>
    -+<table summary="Index for Constructors" width="100%" class="jdiffIndex" border="0" cellspacing="0" cellpadding="0" style="padding-bottom:0;margin-bottom:0;">
    -+  <tr>
    -+  <th class="indexHeader">
    -+    Filter the Index:
    -+  </th>
    -+  </tr>
    -+  <tr>
    -+  <td class="indexText" style="line-height:1.3em;padding-left:2em;">
    -+<a href="constructors_index_all.html" class="staysblack">All Constructors</a>
    -+  <br>
    -+<font color="#999999">Removals</font>
    -+  <br>
    -+<b>Additions</b>
    -+  <br>
    -+<A HREF="constructors_index_changes.html"xclass="hiddenlink">Changes</A>
    -+  </td>
    -+  </tr>
    -+</table>
    -+<div id="indexTableCaption" style="background-color:#eee;padding:0 4px 0 4px;font-size:11px;margin-bottom:1em;">
    -+Listed as: <span style="color:#069"><strong>Added</strong></span>,  <span style="color:#069"><strike>Removed</strike></span>,  <span style="color:#069">Changed</span></font>
    -+</div>
    -+<A NAME="W"></A>
    -+<br><font size="+2">W</font>&nbsp;
    -+ <a href="#topheader"><font size="-2">TOP</font></a>
    -+<p><div style="line-height:1.5em;color:black">
    -+<nobr><A HREF="android.support.v4.view.WindowInsetsCompat.html#android.support.v4.view.WindowInsetsCompat.ctor_added(android.support.v4.view.WindowInsetsCompat)" class="hiddenlink" target="rightframe"><b>WindowInsetsCompat</b>
    -+(<code>WindowInsetsCompat</code>)</A></nobr>&nbsp;constructor<br>
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    -+</script>
    -+<script type="text/javascript">
    -+  try {
    -+    var pageTracker = _gat._getTracker("UA-5831155-1");
    -+    pageTracker._setAllowAnchor(true);
    -+    pageTracker._initData();
    -+    pageTracker._trackPageview();
    -+  } catch(e) {}
    -+</script>
    -+</BODY>
    -+</HTML>
    -diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/constructors_index_all.html b/docs/html/sdk/support_api_diff/24.2.0/changes/constructors_index_all.html
    -new file mode 100644
    -index 0000000..24310b7
    ---- /dev/null
    -+++ b/docs/html/sdk/support_api_diff/24.2.0/changes/constructors_index_all.html
    -@@ -0,0 +1,85 @@
    -+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
    -+<HTML style="overflow:auto;">
    -+<HEAD>
    -+<meta name="generator" content="JDiff v1.1.0">
    -+<!-- Generated by the JDiff Javadoc doclet -->
    -+<!-- (http://www.jdiff.org) -->
    -+<meta name="description" content="JDiff is a Javadoc doclet which generates an HTML report of all the packages, classes, constructors, methods, and fields which have been removed, added or changed in any way, including their documentation, when two APIs are compared.">
    -+<meta name="keywords" content="diff, jdiff, javadiff, java diff, java difference, API difference, difference between two APIs, API diff, Javadoc, doclet">
    -+<TITLE>
    -+Constructor Differences Index
    -+</TITLE>
    -+<link href="../../../../assets/android-developer-docs.css" rel="stylesheet" type="text/css" />
    -+<link href="../stylesheet-jdiff.css" rel="stylesheet" type="text/css" />
    -+<noscript>
    -+<style type="text/css">
    -+body{overflow:auto;}
    -+#body-content{position:relative; top:0;}
    -+#doc-content{overflow:visible;border-left:3px solid #666;}
    -+#side-nav{padding:0;}
    -+#side-nav .toggle-list ul {display:block;}
    -+#resize-packages-nav{border-bottom:3px solid #666;}
    -+</style>
    -+</noscript>
    -+<style type="text/css">
    -+</style>
    -+</HEAD>
    -+<BODY class="gc-documentation" style="padding:12px;">
    -+<a NAME="topheader"></a>
    -+<table summary="Index for Constructors" width="100%" class="jdiffIndex" border="0" cellspacing="0" cellpadding="0" style="padding-bottom:0;margin-bottom:0;">
    -+  <tr>
    -+  <th class="indexHeader">
    -+    Filter the Index:
    -+  </th>
    -+  </tr>
    -+  <tr>
    -+  <td class="indexText" style="line-height:1.3em;padding-left:2em;">
    -+<b>Constructors</b>
    -+  <br>
    -+<font color="#999999">Removals</font>
    -+  <br>
    -+<A HREF="constructors_index_additions.html"xclass="hiddenlink">Additions</A>
    -+  <br>
    -+<A HREF="constructors_index_changes.html"xclass="hiddenlink">Changes</A>
    -+  </td>
    -+  </tr>
    -+</table>
    -+<div id="indexTableCaption" style="background-color:#eee;padding:0 4px 0 4px;font-size:11px;margin-bottom:1em;">
    -+Listed as: <span style="color:#069"><strong>Added</strong></span>,  <span style="color:#069"><strike>Removed</strike></span>,  <span style="color:#069">Changed</span></font>
    -+</div>
    -+<A NAME="A"></A>
    -+<br><font size="+2">A</font>&nbsp;
    -+<a href="#C"><font size="-2">C</font></a> 
    -+<a href="#W"><font size="-2">W</font></a> 
    -+ <a href="#topheader"><font size="-2">TOP</font></a>
    -+<p><div style="line-height:1.5em;color:black">
    -+<nobr><A HREF="android.support.v4.app.ActivityCompat.html#android.support.v4.app.ActivityCompat.ctor_changed()" class="hiddenlink" target="rightframe">ActivityCompat
    -+()</A></nobr>&nbsp;constructor<br>
    -+<A NAME="C"></A>
    -+<br><font size="+2">C</font>&nbsp;
    -+<a href="#A"><font size="-2">A</font></a> 
    -+<a href="#W"><font size="-2">W</font></a> 
    -+ <a href="#topheader"><font size="-2">TOP</font></a>
    -+<p><div style="line-height:1.5em;color:black">
    -+<nobr><A HREF="android.support.v4.content.ContextCompat.html#android.support.v4.content.ContextCompat.ctor_changed()" class="hiddenlink" target="rightframe">ContextCompat
    -+()</A></nobr>&nbsp;constructor<br>
    -+<A NAME="W"></A>
    -+<br><font size="+2">W</font>&nbsp;
    -+<a href="#A"><font size="-2">A</font></a> 
    -+<a href="#C"><font size="-2">C</font></a> 
    -+ <a href="#topheader"><font size="-2">TOP</font></a>
    -+<p><div style="line-height:1.5em;color:black">
    -+<nobr><A HREF="android.support.v4.view.WindowInsetsCompat.html#android.support.v4.view.WindowInsetsCompat.ctor_added(android.support.v4.view.WindowInsetsCompat)" class="hiddenlink" target="rightframe"><b>WindowInsetsCompat</b>
    -+(<code>WindowInsetsCompat</code>)</A></nobr>&nbsp;constructor<br>
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    -+</script>
    -+<script type="text/javascript">
    -+  try {
    -+    var pageTracker = _gat._getTracker("UA-5831155-1");
    -+    pageTracker._setAllowAnchor(true);
    -+    pageTracker._initData();
    -+    pageTracker._trackPageview();
    -+  } catch(e) {}
    -+</script>
    -+</BODY>
    -+</HTML>
    -diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/constructors_index_changes.html b/docs/html/sdk/support_api_diff/24.2.0/changes/constructors_index_changes.html
    -new file mode 100644
    -index 0000000..62a75f8
    ---- /dev/null
    -+++ b/docs/html/sdk/support_api_diff/24.2.0/changes/constructors_index_changes.html
    -@@ -0,0 +1,75 @@
    -+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
    -+<HTML style="overflow:auto;">
    -+<HEAD>
    -+<meta name="generator" content="JDiff v1.1.0">
    -+<!-- Generated by the JDiff Javadoc doclet -->
    -+<!-- (http://www.jdiff.org) -->
    -+<meta name="description" content="JDiff is a Javadoc doclet which generates an HTML report of all the packages, classes, constructors, methods, and fields which have been removed, added or changed in any way, including their documentation, when two APIs are compared.">
    -+<meta name="keywords" content="diff, jdiff, javadiff, java diff, java difference, API difference, difference between two APIs, API diff, Javadoc, doclet">
    -+<TITLE>
    -+Constructor Changes Index
    -+</TITLE>
    -+<link href="../../../../assets/android-developer-docs.css" rel="stylesheet" type="text/css" />
    -+<link href="../stylesheet-jdiff.css" rel="stylesheet" type="text/css" />
    -+<noscript>
    -+<style type="text/css">
    -+body{overflow:auto;}
    -+#body-content{position:relative; top:0;}
    -+#doc-content{overflow:visible;border-left:3px solid #666;}
    -+#side-nav{padding:0;}
    -+#side-nav .toggle-list ul {display:block;}
    -+#resize-packages-nav{border-bottom:3px solid #666;}
    -+</style>
    -+</noscript>
    -+<style type="text/css">
    -+</style>
    -+</HEAD>
    -+<BODY class="gc-documentation" style="padding:12px;">
    -+<a NAME="topheader"></a>
    -+<table summary="Index for Constructors" width="100%" class="jdiffIndex" border="0" cellspacing="0" cellpadding="0" style="padding-bottom:0;margin-bottom:0;">
    -+  <tr>
    -+  <th class="indexHeader">
    -+    Filter the Index:
    -+  </th>
    -+  </tr>
    -+  <tr>
    -+  <td class="indexText" style="line-height:1.3em;padding-left:2em;">
    -+<a href="constructors_index_all.html" class="staysblack">All Constructors</a>
    -+  <br>
    -+<font color="#999999">Removals</font>
    -+  <br>
    -+<A HREF="constructors_index_additions.html"xclass="hiddenlink">Additions</A>
    -+  <br>
    -+<b>Changes</b>
    -+  </td>
    -+  </tr>
    -+</table>
    -+<div id="indexTableCaption" style="background-color:#eee;padding:0 4px 0 4px;font-size:11px;margin-bottom:1em;">
    -+Listed as: <span style="color:#069"><strong>Added</strong></span>,  <span style="color:#069"><strike>Removed</strike></span>,  <span style="color:#069">Changed</span></font>
    -+</div>
    -+<A NAME="A"></A>
    -+<br><font size="+2">A</font>&nbsp;
    -+<a href="#C"><font size="-2">C</font></a> 
    -+ <a href="#topheader"><font size="-2">TOP</font></a>
    -+<p><div style="line-height:1.5em;color:black">
    -+<nobr><A HREF="android.support.v4.app.ActivityCompat.html#android.support.v4.app.ActivityCompat.ctor_changed()" class="hiddenlink" target="rightframe">ActivityCompat
    -+()</A></nobr>&nbsp;constructor<br>
    -+<A NAME="C"></A>
    -+<br><font size="+2">C</font>&nbsp;
    -+<a href="#A"><font size="-2">A</font></a> 
    -+ <a href="#topheader"><font size="-2">TOP</font></a>
    -+<p><div style="line-height:1.5em;color:black">
    -+<nobr><A HREF="android.support.v4.content.ContextCompat.html#android.support.v4.content.ContextCompat.ctor_changed()" class="hiddenlink" target="rightframe">ContextCompat
    -+()</A></nobr>&nbsp;constructor<br>
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    -+</script>
    -+<script type="text/javascript">
    -+  try {
    -+    var pageTracker = _gat._getTracker("UA-5831155-1");
    -+    pageTracker._setAllowAnchor(true);
    -+    pageTracker._initData();
    -+    pageTracker._trackPageview();
    -+  } catch(e) {}
    -+</script>
    -+</BODY>
    -+</HTML>
    -diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/constructors_index_removals.html b/docs/html/sdk/support_api_diff/24.2.0/changes/constructors_index_removals.html
    -new file mode 100644
    -index 0000000..2fbd2e1
    ---- /dev/null
    -+++ b/docs/html/sdk/support_api_diff/24.2.0/changes/constructors_index_removals.html
    -@@ -0,0 +1,61 @@
    -+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
    -+<HTML style="overflow:auto;">
    -+<HEAD>
    -+<meta name="generator" content="JDiff v1.1.0">
    -+<!-- Generated by the JDiff Javadoc doclet -->
    -+<!-- (http://www.jdiff.org) -->
    -+<meta name="description" content="JDiff is a Javadoc doclet which generates an HTML report of all the packages, classes, constructors, methods, and fields which have been removed, added or changed in any way, including their documentation, when two APIs are compared.">
    -+<meta name="keywords" content="diff, jdiff, javadiff, java diff, java difference, API difference, difference between two APIs, API diff, Javadoc, doclet">
    -+<TITLE>
    -+Constructor Removals Index
    -+</TITLE>
    -+<link href="../../../../assets/android-developer-docs.css" rel="stylesheet" type="text/css" />
    -+<link href="../stylesheet-jdiff.css" rel="stylesheet" type="text/css" />
    -+<noscript>
    -+<style type="text/css">
    -+body{overflow:auto;}
    -+#body-content{position:relative; top:0;}
    -+#doc-content{overflow:visible;border-left:3px solid #666;}
    -+#side-nav{padding:0;}
    -+#side-nav .toggle-list ul {display:block;}
    -+#resize-packages-nav{border-bottom:3px solid #666;}
    -+</style>
    -+</noscript>
    -+<style type="text/css">
    -+</style>
    -+</HEAD>
    -+<BODY class="gc-documentation" style="padding:12px;">
    -+<a NAME="topheader"></a>
    -+<table summary="Index for Constructors" width="100%" class="jdiffIndex" border="0" cellspacing="0" cellpadding="0" style="padding-bottom:0;margin-bottom:0;">
    -+  <tr>
    -+  <th class="indexHeader">
    -+    Filter the Index:
    -+  </th>
    -+  </tr>
    -+  <tr>
    -+  <td class="indexText" style="line-height:1.3em;padding-left:2em;">
    -+<a href="constructors_index_all.html" class="staysblack">All Constructors</a>
    -+  <br>
    -+<font color="#999999">Removals</font>
    -+  <br>
    -+<A HREF="constructors_index_additions.html"xclass="hiddenlink">Additions</A>
    -+  <br>
    -+<A HREF="constructors_index_changes.html"xclass="hiddenlink">Changes</A>
    -+  </td>
    -+  </tr>
    -+</table>
    -+<div id="indexTableCaption" style="background-color:#eee;padding:0 4px 0 4px;font-size:11px;margin-bottom:1em;">
    -+Listed as: <span style="color:#069"><strong>Added</strong></span>,  <span style="color:#069"><strike>Removed</strike></span>,  <span style="color:#069">Changed</span></font>
    -+</div>
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    -+</script>
    -+<script type="text/javascript">
    -+  try {
    -+    var pageTracker = _gat._getTracker("UA-5831155-1");
    -+    pageTracker._setAllowAnchor(true);
    -+    pageTracker._initData();
    -+    pageTracker._trackPageview();
    -+  } catch(e) {}
    -+</script>
    -+</BODY>
    -+</HTML>
    -diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/fields_index_additions.html b/docs/html/sdk/support_api_diff/24.2.0/changes/fields_index_additions.html
    -new file mode 100644
    -index 0000000..cdb8ee8
    ---- /dev/null
    -+++ b/docs/html/sdk/support_api_diff/24.2.0/changes/fields_index_additions.html
    -@@ -0,0 +1,267 @@
    -+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
    -+<HTML style="overflow:auto;">
    -+<HEAD>
    -+<meta name="generator" content="JDiff v1.1.0">
    -+<!-- Generated by the JDiff Javadoc doclet -->
    -+<!-- (http://www.jdiff.org) -->
    -+<meta name="description" content="JDiff is a Javadoc doclet which generates an HTML report of all the packages, classes, constructors, methods, and fields which have been removed, added or changed in any way, including their documentation, when two APIs are compared.">
    -+<meta name="keywords" content="diff, jdiff, javadiff, java diff, java difference, API difference, difference between two APIs, API diff, Javadoc, doclet">
    -+<TITLE>
    -+Field Additions Index
    -+</TITLE>
    -+<link href="../../../../assets/android-developer-docs.css" rel="stylesheet" type="text/css" />
    -+<link href="../stylesheet-jdiff.css" rel="stylesheet" type="text/css" />
    -+<noscript>
    -+<style type="text/css">
    -+body{overflow:auto;}
    -+#body-content{position:relative; top:0;}
    -+#doc-content{overflow:visible;border-left:3px solid #666;}
    -+#side-nav{padding:0;}
    -+#side-nav .toggle-list ul {display:block;}
    -+#resize-packages-nav{border-bottom:3px solid #666;}
    -+</style>
    -+</noscript>
    -+<style type="text/css">
    -+</style>
    -+</HEAD>
    -+<BODY class="gc-documentation" style="padding:12px;">
    -+<a NAME="topheader"></a>
    -+<table summary="Index for Fields" width="100%" class="jdiffIndex" border="0" cellspacing="0" cellpadding="0" style="padding-bottom:0;margin-bottom:0;">
    -+  <tr>
    -+  <th class="indexHeader">
    -+    Filter the Index:
    -+  </th>
    -+  </tr>
    -+  <tr>
    -+  <td class="indexText" style="line-height:1.3em;padding-left:2em;">
    -+<a href="fields_index_all.html" class="staysblack">All Fields</a>
    -+  <br>
    -+<A HREF="fields_index_removals.html" xclass="hiddenlink">Removals</A>
    -+  <br>
    -+<b>Additions</b>
    -+  <br>
    -+<A HREF="fields_index_changes.html"xclass="hiddenlink">Changes</A>
    -+  </td>
    -+  </tr>
    -+</table>
    -+<div id="indexTableCaption" style="background-color:#eee;padding:0 4px 0 4px;font-size:11px;margin-bottom:1em;">
    -+Listed as: <span style="color:#069"><strong>Added</strong></span>,  <span style="color:#069"><strike>Removed</strike></span>,  <span style="color:#069">Changed</span></font>
    -+</div>
    -+<A NAME="A"></A>
    -+<br><font size="+2">A</font>&nbsp;
    -+<a href="#B"><font size="-2">B</font></a> 
    -+<a href="#D"><font size="-2">D</font></a> 
    -+<a href="#E"><font size="-2">E</font></a> 
    -+<a href="#H"><font size="-2">H</font></a> 
    -+<a href="#I"><font size="-2">I</font></a> 
    -+<a href="#M"><font size="-2">M</font></a> 
    -+<a href="#P"><font size="-2">P</font></a> 
    -+<a href="#S"><font size="-2">S</font></a> 
    -+<a href="#T"><font size="-2">T</font></a> 
    -+ <a href="#topheader"><font size="-2">TOP</font></a>
    -+<p><div style="line-height:1.5em;color:black">
    -+<nobr><A HREF="android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.html#android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.ACTION_ARGUMENT_COLUMN_INT" class="hiddenlink" target="rightframe">ACTION_ARGUMENT_COLUMN_INT</A>
    -+</nobr><br>
    -+<nobr><A HREF="android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.html#android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.ACTION_ARGUMENT_PROGRESS_VALUE" class="hiddenlink" target="rightframe">ACTION_ARGUMENT_PROGRESS_VALUE</A>
    -+</nobr><br>
    -+<nobr><A HREF="android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.html#android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.ACTION_ARGUMENT_ROW_INT" class="hiddenlink" target="rightframe">ACTION_ARGUMENT_ROW_INT</A>
    -+</nobr><br>
    -+<nobr><A HREF="android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat.html#android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat.ACTION_CONTEXT_CLICK" class="hiddenlink" target="rightframe">ACTION_CONTEXT_CLICK</A>
    -+</nobr><br>
    -+<nobr><A HREF="android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat.html#android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat.ACTION_SCROLL_DOWN" class="hiddenlink" target="rightframe">ACTION_SCROLL_DOWN</A>
    -+</nobr><br>
    -+<nobr><A HREF="android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat.html#android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat.ACTION_SCROLL_LEFT" class="hiddenlink" target="rightframe">ACTION_SCROLL_LEFT</A>
    -+</nobr><br>
    -+<nobr><A HREF="android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat.html#android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat.ACTION_SCROLL_RIGHT" class="hiddenlink" target="rightframe">ACTION_SCROLL_RIGHT</A>
    -+</nobr><br>
    -+<nobr><A HREF="android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat.html#android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat.ACTION_SCROLL_TO_POSITION" class="hiddenlink" target="rightframe">ACTION_SCROLL_TO_POSITION</A>
    -+</nobr><br>
    -+<nobr><A HREF="android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat.html#android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat.ACTION_SCROLL_UP" class="hiddenlink" target="rightframe">ACTION_SCROLL_UP</A>
    -+</nobr><br>
    -+<nobr><A HREF="android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat.html#android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat.ACTION_SET_PROGRESS" class="hiddenlink" target="rightframe">ACTION_SET_PROGRESS</A>
    -+</nobr><br>
    -+<nobr><A HREF="android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat.html#android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat.ACTION_SHOW_ON_SCREEN" class="hiddenlink" target="rightframe">ACTION_SHOW_ON_SCREEN</A>
    -+</nobr><br>
    -+<A NAME="B"></A>
    -+<br><font size="+2">B</font>&nbsp;
    -+<a href="#A"><font size="-2">A</font></a> 
    -+<a href="#D"><font size="-2">D</font></a> 
    -+<a href="#E"><font size="-2">E</font></a> 
    -+<a href="#H"><font size="-2">H</font></a> 
    -+<a href="#I"><font size="-2">I</font></a> 
    -+<a href="#M"><font size="-2">M</font></a> 
    -+<a href="#P"><font size="-2">P</font></a> 
    -+<a href="#S"><font size="-2">S</font></a> 
    -+<a href="#T"><font size="-2">T</font></a> 
    -+ <a href="#topheader"><font size="-2">TOP</font></a>
    -+<p><div style="line-height:1.5em;color:black">
    -+<nobr><A HREF="android.support.v4.media.MediaDescriptionCompat.html#android.support.v4.media.MediaDescriptionCompat.BT_FOLDER_TYPE_ALBUMS" class="hiddenlink" target="rightframe">BT_FOLDER_TYPE_ALBUMS</A>
    -+</nobr><br>
    -+<nobr><A HREF="android.support.v4.media.MediaDescriptionCompat.html#android.support.v4.media.MediaDescriptionCompat.BT_FOLDER_TYPE_ARTISTS" class="hiddenlink" target="rightframe">BT_FOLDER_TYPE_ARTISTS</A>
    -+</nobr><br>
    -+<nobr><A HREF="android.support.v4.media.MediaDescriptionCompat.html#android.support.v4.media.MediaDescriptionCompat.BT_FOLDER_TYPE_GENRES" class="hiddenlink" target="rightframe">BT_FOLDER_TYPE_GENRES</A>
    -+</nobr><br>
    -+<nobr><A HREF="android.support.v4.media.MediaDescriptionCompat.html#android.support.v4.media.MediaDescriptionCompat.BT_FOLDER_TYPE_MIXED" class="hiddenlink" target="rightframe">BT_FOLDER_TYPE_MIXED</A>
    -+</nobr><br>
    -+<nobr><A HREF="android.support.v4.media.MediaDescriptionCompat.html#android.support.v4.media.MediaDescriptionCompat.BT_FOLDER_TYPE_PLAYLISTS" class="hiddenlink" target="rightframe">BT_FOLDER_TYPE_PLAYLISTS</A>
    -+</nobr><br>
    -+<nobr><A HREF="android.support.v4.media.MediaDescriptionCompat.html#android.support.v4.media.MediaDescriptionCompat.BT_FOLDER_TYPE_TITLES" class="hiddenlink" target="rightframe">BT_FOLDER_TYPE_TITLES</A>
    -+</nobr><br>
    -+<nobr><A HREF="android.support.v4.media.MediaDescriptionCompat.html#android.support.v4.media.MediaDescriptionCompat.BT_FOLDER_TYPE_YEARS" class="hiddenlink" target="rightframe">BT_FOLDER_TYPE_YEARS</A>
    -+</nobr><br>
    -+<A NAME="D"></A>
    -+<br><font size="+2">D</font>&nbsp;
    -+<a href="#A"><font size="-2">A</font></a> 
    -+<a href="#B"><font size="-2">B</font></a> 
    -+<a href="#E"><font size="-2">E</font></a> 
    -+<a href="#H"><font size="-2">H</font></a> 
    -+<a href="#I"><font size="-2">I</font></a> 
    -+<a href="#M"><font size="-2">M</font></a> 
    -+<a href="#P"><font size="-2">P</font></a> 
    -+<a href="#S"><font size="-2">S</font></a> 
    -+<a href="#T"><font size="-2">T</font></a> 
    -+ <a href="#topheader"><font size="-2">TOP</font></a>
    -+<p><div style="line-height:1.5em;color:black">
    -+<nobr><A HREF="android.support.design.widget.CoordinatorLayout.LayoutParams.html#android.support.design.widget.CoordinatorLayout.LayoutParams.dodgeInsetEdges" class="hiddenlink" target="rightframe">dodgeInsetEdges</A>
    -+</nobr><br>
    -+<A NAME="E"></A>
    -+<br><font size="+2">E</font>&nbsp;
    -+<a href="#A"><font size="-2">A</font></a> 
    -+<a href="#B"><font size="-2">B</font></a> 
    -+<a href="#D"><font size="-2">D</font></a> 
    -+<a href="#H"><font size="-2">H</font></a> 
    -+<a href="#I"><font size="-2">I</font></a> 
    -+<a href="#M"><font size="-2">M</font></a> 
    -+<a href="#P"><font size="-2">P</font></a> 
    -+<a href="#S"><font size="-2">S</font></a> 
    -+<a href="#T"><font size="-2">T</font></a> 
    -+ <a href="#topheader"><font size="-2">TOP</font></a>
    -+<p><div style="line-height:1.5em;color:black">
    -+<nobr><A HREF="android.support.v4.media.MediaDescriptionCompat.html#android.support.v4.media.MediaDescriptionCompat.EXTRA_BT_FOLDER_TYPE" class="hiddenlink" target="rightframe">EXTRA_BT_FOLDER_TYPE</A>
    -+</nobr><br>
    -+<nobr><A HREF="android.support.customtabs.CustomTabsIntent.html#android.support.customtabs.CustomTabsIntent.EXTRA_ENABLE_INSTANT_APPS" class="hiddenlink" target="rightframe">EXTRA_ENABLE_INSTANT_APPS</A>
    -+</nobr><br>
    -+<nobr><A HREF="android.support.v4.media.MediaBrowserServiceCompat.BrowserRoot.html#android.support.v4.media.MediaBrowserServiceCompat.BrowserRoot.EXTRA_SUGGESTION_KEYWORDS" class="hiddenlink" target="rightframe">EXTRA_SUGGESTION_KEYWORDS</A>
    -+</nobr><br>
    -+<nobr><A HREF="android.support.v4.app.ActivityOptionsCompat.html#android.support.v4.app.ActivityOptionsCompat.EXTRA_USAGE_TIME_REPORT" class="hiddenlink" target="rightframe">EXTRA_USAGE_TIME_REPORT</A>
    -+</nobr><br>
    -+<nobr><A HREF="android.support.v4.app.ActivityOptionsCompat.html#android.support.v4.app.ActivityOptionsCompat.EXTRA_USAGE_TIME_REPORT_PACKAGES" class="hiddenlink" target="rightframe">EXTRA_USAGE_TIME_REPORT_PACKAGES</A>
    -+</nobr><br>
    -+<A NAME="H"></A>
    -+<br><font size="+2">H</font>&nbsp;
    -+<a href="#A"><font size="-2">A</font></a> 
    -+<a href="#B"><font size="-2">B</font></a> 
    -+<a href="#D"><font size="-2">D</font></a> 
    -+<a href="#E"><font size="-2">E</font></a> 
    -+<a href="#I"><font size="-2">I</font></a> 
    -+<a href="#M"><font size="-2">M</font></a> 
    -+<a href="#P"><font size="-2">P</font></a> 
    -+<a href="#S"><font size="-2">S</font></a> 
    -+<a href="#T"><font size="-2">T</font></a> 
    -+ <a href="#topheader"><font size="-2">TOP</font></a>
    -+<p><div style="line-height:1.5em;color:black">
    -+<nobr><A HREF="android.support.v4.view.accessibility.AccessibilityNodeProviderCompat.html#android.support.v4.view.accessibility.AccessibilityNodeProviderCompat.HOST_VIEW_ID" class="hiddenlink" target="rightframe">HOST_VIEW_ID</A>
    -+</nobr><br>
    -+<A NAME="I"></A>
    -+<br><font size="+2">I</font>&nbsp;
    -+<a href="#A"><font size="-2">A</font></a> 
    -+<a href="#B"><font size="-2">B</font></a> 
    -+<a href="#D"><font size="-2">D</font></a> 
    -+<a href="#E"><font size="-2">E</font></a> 
    -+<a href="#H"><font size="-2">H</font></a> 
    -+<a href="#M"><font size="-2">M</font></a> 
    -+<a href="#P"><font size="-2">P</font></a> 
    -+<a href="#S"><font size="-2">S</font></a> 
    -+<a href="#T"><font size="-2">T</font></a> 
    -+ <a href="#topheader"><font size="-2">TOP</font></a>
    -+<p><div style="line-height:1.5em;color:black">
    -+<nobr><A HREF="android.support.design.widget.CoordinatorLayout.LayoutParams.html#android.support.design.widget.CoordinatorLayout.LayoutParams.insetEdge" class="hiddenlink" target="rightframe">insetEdge</A>
    -+</nobr><br>
    -+<A NAME="M"></A>
    -+<br><font size="+2">M</font>&nbsp;
    -+<a href="#A"><font size="-2">A</font></a> 
    -+<a href="#B"><font size="-2">B</font></a> 
    -+<a href="#D"><font size="-2">D</font></a> 
    -+<a href="#E"><font size="-2">E</font></a> 
    -+<a href="#H"><font size="-2">H</font></a> 
    -+<a href="#I"><font size="-2">I</font></a> 
    -+<a href="#P"><font size="-2">P</font></a> 
    -+<a href="#S"><font size="-2">S</font></a> 
    -+<a href="#T"><font size="-2">T</font></a> 
    -+ <a href="#topheader"><font size="-2">TOP</font></a>
    -+<p><div style="line-height:1.5em;color:black">
    -+<nobr><A HREF="android.support.v4.media.MediaMetadataCompat.html#android.support.v4.media.MediaMetadataCompat.METADATA_KEY_BT_FOLDER_TYPE" class="hiddenlink" target="rightframe">METADATA_KEY_BT_FOLDER_TYPE</A>
    -+</nobr><br>
    -+<nobr><A HREF="android.support.v4.media.MediaMetadataCompat.html#android.support.v4.media.MediaMetadataCompat.METADATA_KEY_MEDIA_URI" class="hiddenlink" target="rightframe">METADATA_KEY_MEDIA_URI</A>
    -+</nobr><br>
    -+<A NAME="P"></A>
    -+<br><font size="+2">P</font>&nbsp;
    -+<a href="#A"><font size="-2">A</font></a> 
    -+<a href="#B"><font size="-2">B</font></a> 
    -+<a href="#D"><font size="-2">D</font></a> 
    -+<a href="#E"><font size="-2">E</font></a> 
    -+<a href="#H"><font size="-2">H</font></a> 
    -+<a href="#I"><font size="-2">I</font></a> 
    -+<a href="#M"><font size="-2">M</font></a> 
    -+<a href="#S"><font size="-2">S</font></a> 
    -+<a href="#T"><font size="-2">T</font></a> 
    -+ <a href="#topheader"><font size="-2">TOP</font></a>
    -+<p><div style="line-height:1.5em;color:black">
    -+<nobr><A HREF="android.support.design.widget.BottomSheetBehavior.html#android.support.design.widget.BottomSheetBehavior.PEEK_HEIGHT_AUTO" class="hiddenlink" target="rightframe">PEEK_HEIGHT_AUTO</A>
    -+</nobr><br>
    -+<nobr><A HREF="android.support.v17.leanback.widget.AbstractMediaItemPresenter.html#android.support.v17.leanback.widget.AbstractMediaItemPresenter.PLAY_STATE_INITIAL" class="hiddenlink" target="rightframe">PLAY_STATE_INITIAL</A>
    -+</nobr><br>
    -+<nobr><A HREF="android.support.v17.leanback.widget.AbstractMediaItemPresenter.html#android.support.v17.leanback.widget.AbstractMediaItemPresenter.PLAY_STATE_PAUSED" class="hiddenlink" target="rightframe">PLAY_STATE_PAUSED</A>
    -+</nobr><br>
    -+<nobr><A HREF="android.support.v17.leanback.widget.AbstractMediaItemPresenter.html#android.support.v17.leanback.widget.AbstractMediaItemPresenter.PLAY_STATE_PLAYING" class="hiddenlink" target="rightframe">PLAY_STATE_PLAYING</A>
    -+</nobr><br>
    -+<A NAME="S"></A>
    -+<br><font size="+2">S</font>&nbsp;
    -+<a href="#A"><font size="-2">A</font></a> 
    -+<a href="#B"><font size="-2">B</font></a> 
    -+<a href="#D"><font size="-2">D</font></a> 
    -+<a href="#E"><font size="-2">E</font></a> 
    -+<a href="#H"><font size="-2">H</font></a> 
    -+<a href="#I"><font size="-2">I</font></a> 
    -+<a href="#M"><font size="-2">M</font></a> 
    -+<a href="#P"><font size="-2">P</font></a> 
    -+<a href="#T"><font size="-2">T</font></a> 
    -+ <a href="#topheader"><font size="-2">TOP</font></a>
    -+<p><div style="line-height:1.5em;color:black">
    -+<nobr><A HREF="android.support.v4.app.ServiceCompat.html#android.support.v4.app.ServiceCompat.STOP_FOREGROUND_DETACH" class="hiddenlink" target="rightframe">STOP_FOREGROUND_DETACH</A>
    -+</nobr><br>
    -+<nobr><A HREF="android.support.v4.app.ServiceCompat.html#android.support.v4.app.ServiceCompat.STOP_FOREGROUND_REMOVE" class="hiddenlink" target="rightframe">STOP_FOREGROUND_REMOVE</A>
    -+</nobr><br>
    -+<A NAME="T"></A>
    -+<br><font size="+2">T</font>&nbsp;
    -+<a href="#A"><font size="-2">A</font></a> 
    -+<a href="#B"><font size="-2">B</font></a> 
    -+<a href="#D"><font size="-2">D</font></a> 
    -+<a href="#E"><font size="-2">E</font></a> 
    -+<a href="#H"><font size="-2">H</font></a> 
    -+<a href="#I"><font size="-2">I</font></a> 
    -+<a href="#M"><font size="-2">M</font></a> 
    -+<a href="#P"><font size="-2">P</font></a> 
    -+<a href="#S"><font size="-2">S</font></a> 
    -+ <a href="#topheader"><font size="-2">TOP</font></a>
    -+<p><div style="line-height:1.5em;color:black">
    -+<nobr><A HREF="android.support.v4.view.accessibility.AccessibilityEventCompat.html#android.support.v4.view.accessibility.AccessibilityEventCompat.TYPE_ASSIST_READING_CONTEXT" class="hiddenlink" target="rightframe">TYPE_ASSIST_READING_CONTEXT</A>
    -+</nobr><br>
    -+<nobr><A HREF="android.support.v4.view.accessibility.AccessibilityWindowInfoCompat.html#android.support.v4.view.accessibility.AccessibilityWindowInfoCompat.TYPE_SPLIT_SCREEN_DIVIDER" class="hiddenlink" target="rightframe">TYPE_SPLIT_SCREEN_DIVIDER</A>
    -+</nobr><br>
    -+<nobr><A HREF="android.support.v4.view.accessibility.AccessibilityEventCompat.html#android.support.v4.view.accessibility.AccessibilityEventCompat.TYPE_VIEW_CONTEXT_CLICKED" class="hiddenlink" target="rightframe">TYPE_VIEW_CONTEXT_CLICKED</A>
    -+</nobr><br>
    -+<nobr><A HREF="android.support.v4.view.accessibility.AccessibilityEventCompat.html#android.support.v4.view.accessibility.AccessibilityEventCompat.TYPE_WINDOWS_CHANGED" class="hiddenlink" target="rightframe">TYPE_WINDOWS_CHANGED</A>
    -+</nobr><br>
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    -+</script>
    -+<script type="text/javascript">
    -+  try {
    -+    var pageTracker = _gat._getTracker("UA-5831155-1");
    -+    pageTracker._setAllowAnchor(true);
    -+    pageTracker._initData();
    -+    pageTracker._trackPageview();
    -+  } catch(e) {}
    -+</script>
    -+</BODY>
    -+</HTML>
    -diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/fields_index_all.html b/docs/html/sdk/support_api_diff/24.2.0/changes/fields_index_all.html
    -new file mode 100644
    -index 0000000..14b3e97
    ---- /dev/null
    -+++ b/docs/html/sdk/support_api_diff/24.2.0/changes/fields_index_all.html
    -@@ -0,0 +1,299 @@
    -+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
    -+<HTML style="overflow:auto;">
    -+<HEAD>
    -+<meta name="generator" content="JDiff v1.1.0">
    -+<!-- Generated by the JDiff Javadoc doclet -->
    -+<!-- (http://www.jdiff.org) -->
    -+<meta name="description" content="JDiff is a Javadoc doclet which generates an HTML report of all the packages, classes, constructors, methods, and fields which have been removed, added or changed in any way, including their documentation, when two APIs are compared.">
    -+<meta name="keywords" content="diff, jdiff, javadiff, java diff, java difference, API difference, difference between two APIs, API diff, Javadoc, doclet">
    -+<TITLE>
    -+Field Differences Index
    -+</TITLE>
    -+<link href="../../../../assets/android-developer-docs.css" rel="stylesheet" type="text/css" />
    -+<link href="../stylesheet-jdiff.css" rel="stylesheet" type="text/css" />
    -+<noscript>
    -+<style type="text/css">
    -+body{overflow:auto;}
    -+#body-content{position:relative; top:0;}
    -+#doc-content{overflow:visible;border-left:3px solid #666;}
    -+#side-nav{padding:0;}
    -+#side-nav .toggle-list ul {display:block;}
    -+#resize-packages-nav{border-bottom:3px solid #666;}
    -+</style>
    -+</noscript>
    -+<style type="text/css">
    -+</style>
    -+</HEAD>
    -+<BODY class="gc-documentation" style="padding:12px;">
    -+<a NAME="topheader"></a>
    -+<table summary="Index for Fields" width="100%" class="jdiffIndex" border="0" cellspacing="0" cellpadding="0" style="padding-bottom:0;margin-bottom:0;">
    -+  <tr>
    -+  <th class="indexHeader">
    -+    Filter the Index:
    -+  </th>
    -+  </tr>
    -+  <tr>
    -+  <td class="indexText" style="line-height:1.3em;padding-left:2em;">
    -+<b>Fields</b>
    -+  <br>
    -+<A HREF="fields_index_removals.html" xclass="hiddenlink">Removals</A>
    -+  <br>
    -+<A HREF="fields_index_additions.html"xclass="hiddenlink">Additions</A>
    -+  <br>
    -+<A HREF="fields_index_changes.html"xclass="hiddenlink">Changes</A>
    -+  </td>
    -+  </tr>
    -+</table>
    -+<div id="indexTableCaption" style="background-color:#eee;padding:0 4px 0 4px;font-size:11px;margin-bottom:1em;">
    -+Listed as: <span style="color:#069"><strong>Added</strong></span>,  <span style="color:#069"><strike>Removed</strike></span>,  <span style="color:#069">Changed</span></font>
    -+</div>
    -+<A NAME="A"></A>
    -+<br><font size="+2">A</font>&nbsp;
    -+<a href="#B"><font size="-2">B</font></a> 
    -+<a href="#D"><font size="-2">D</font></a> 
    -+<a href="#E"><font size="-2">E</font></a> 
    -+<a href="#H"><font size="-2">H</font></a> 
    -+<a href="#I"><font size="-2">I</font></a> 
    -+<a href="#M"><font size="-2">M</font></a> 
    -+<a href="#O"><font size="-2">O</font></a> 
    -+<a href="#P"><font size="-2">P</font></a> 
    -+<a href="#S"><font size="-2">S</font></a> 
    -+<a href="#T"><font size="-2">T</font></a> 
    -+ <a href="#topheader"><font size="-2">TOP</font></a>
    -+<p><div style="line-height:1.5em;color:black">
    -+<nobr><A HREF="android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.html#android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.ACTION_ARGUMENT_COLUMN_INT" class="hiddenlink" target="rightframe">ACTION_ARGUMENT_COLUMN_INT</A>
    -+</nobr><br>
    -+<nobr><A HREF="android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.html#android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.ACTION_ARGUMENT_PROGRESS_VALUE" class="hiddenlink" target="rightframe">ACTION_ARGUMENT_PROGRESS_VALUE</A>
    -+</nobr><br>
    -+<nobr><A HREF="android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.html#android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.ACTION_ARGUMENT_ROW_INT" class="hiddenlink" target="rightframe">ACTION_ARGUMENT_ROW_INT</A>
    -+</nobr><br>
    -+<nobr><A HREF="android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat.html#android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat.ACTION_CONTEXT_CLICK" class="hiddenlink" target="rightframe">ACTION_CONTEXT_CLICK</A>
    -+</nobr><br>
    -+<nobr><A HREF="android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat.html#android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat.ACTION_SCROLL_DOWN" class="hiddenlink" target="rightframe">ACTION_SCROLL_DOWN</A>
    -+</nobr><br>
    -+<nobr><A HREF="android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat.html#android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat.ACTION_SCROLL_LEFT" class="hiddenlink" target="rightframe">ACTION_SCROLL_LEFT</A>
    -+</nobr><br>
    -+<nobr><A HREF="android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat.html#android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat.ACTION_SCROLL_RIGHT" class="hiddenlink" target="rightframe">ACTION_SCROLL_RIGHT</A>
    -+</nobr><br>
    -+<nobr><A HREF="android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat.html#android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat.ACTION_SCROLL_TO_POSITION" class="hiddenlink" target="rightframe">ACTION_SCROLL_TO_POSITION</A>
    -+</nobr><br>
    -+<nobr><A HREF="android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat.html#android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat.ACTION_SCROLL_UP" class="hiddenlink" target="rightframe">ACTION_SCROLL_UP</A>
    -+</nobr><br>
    -+<nobr><A HREF="android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat.html#android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat.ACTION_SET_PROGRESS" class="hiddenlink" target="rightframe">ACTION_SET_PROGRESS</A>
    -+</nobr><br>
    -+<nobr><A HREF="android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat.html#android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat.ACTION_SHOW_ON_SCREEN" class="hiddenlink" target="rightframe">ACTION_SHOW_ON_SCREEN</A>
    -+</nobr><br>
    -+<A NAME="B"></A>
    -+<br><font size="+2">B</font>&nbsp;
    -+<a href="#A"><font size="-2">A</font></a> 
    -+<a href="#D"><font size="-2">D</font></a> 
    -+<a href="#E"><font size="-2">E</font></a> 
    -+<a href="#H"><font size="-2">H</font></a> 
    -+<a href="#I"><font size="-2">I</font></a> 
    -+<a href="#M"><font size="-2">M</font></a> 
    -+<a href="#O"><font size="-2">O</font></a> 
    -+<a href="#P"><font size="-2">P</font></a> 
    -+<a href="#S"><font size="-2">S</font></a> 
    -+<a href="#T"><font size="-2">T</font></a> 
    -+ <a href="#topheader"><font size="-2">TOP</font></a>
    -+<p><div style="line-height:1.5em;color:black">
    -+<nobr><A HREF="android.support.v4.media.MediaDescriptionCompat.html#android.support.v4.media.MediaDescriptionCompat.BT_FOLDER_TYPE_ALBUMS" class="hiddenlink" target="rightframe">BT_FOLDER_TYPE_ALBUMS</A>
    -+</nobr><br>
    -+<nobr><A HREF="android.support.v4.media.MediaDescriptionCompat.html#android.support.v4.media.MediaDescriptionCompat.BT_FOLDER_TYPE_ARTISTS" class="hiddenlink" target="rightframe">BT_FOLDER_TYPE_ARTISTS</A>
    -+</nobr><br>
    -+<nobr><A HREF="android.support.v4.media.MediaDescriptionCompat.html#android.support.v4.media.MediaDescriptionCompat.BT_FOLDER_TYPE_GENRES" class="hiddenlink" target="rightframe">BT_FOLDER_TYPE_GENRES</A>
    -+</nobr><br>
    -+<nobr><A HREF="android.support.v4.media.MediaDescriptionCompat.html#android.support.v4.media.MediaDescriptionCompat.BT_FOLDER_TYPE_MIXED" class="hiddenlink" target="rightframe">BT_FOLDER_TYPE_MIXED</A>
    -+</nobr><br>
    -+<nobr><A HREF="android.support.v4.media.MediaDescriptionCompat.html#android.support.v4.media.MediaDescriptionCompat.BT_FOLDER_TYPE_PLAYLISTS" class="hiddenlink" target="rightframe">BT_FOLDER_TYPE_PLAYLISTS</A>
    -+</nobr><br>
    -+<nobr><A HREF="android.support.v4.media.MediaDescriptionCompat.html#android.support.v4.media.MediaDescriptionCompat.BT_FOLDER_TYPE_TITLES" class="hiddenlink" target="rightframe">BT_FOLDER_TYPE_TITLES</A>
    -+</nobr><br>
    -+<nobr><A HREF="android.support.v4.media.MediaDescriptionCompat.html#android.support.v4.media.MediaDescriptionCompat.BT_FOLDER_TYPE_YEARS" class="hiddenlink" target="rightframe">BT_FOLDER_TYPE_YEARS</A>
    -+</nobr><br>
    -+<A NAME="D"></A>
    -+<br><font size="+2">D</font>&nbsp;
    -+<a href="#A"><font size="-2">A</font></a> 
    -+<a href="#B"><font size="-2">B</font></a> 
    -+<a href="#E"><font size="-2">E</font></a> 
    -+<a href="#H"><font size="-2">H</font></a> 
    -+<a href="#I"><font size="-2">I</font></a> 
    -+<a href="#M"><font size="-2">M</font></a> 
    -+<a href="#O"><font size="-2">O</font></a> 
    -+<a href="#P"><font size="-2">P</font></a> 
    -+<a href="#S"><font size="-2">S</font></a> 
    -+<a href="#T"><font size="-2">T</font></a> 
    -+ <a href="#topheader"><font size="-2">TOP</font></a>
    -+<p><div style="line-height:1.5em;color:black">
    -+<nobr><A HREF="android.support.design.widget.CoordinatorLayout.LayoutParams.html#android.support.design.widget.CoordinatorLayout.LayoutParams.dodgeInsetEdges" class="hiddenlink" target="rightframe">dodgeInsetEdges</A>
    -+</nobr><br>
    -+<A NAME="E"></A>
    -+<br><font size="+2">E</font>&nbsp;
    -+<a href="#A"><font size="-2">A</font></a> 
    -+<a href="#B"><font size="-2">B</font></a> 
    -+<a href="#D"><font size="-2">D</font></a> 
    -+<a href="#H"><font size="-2">H</font></a> 
    -+<a href="#I"><font size="-2">I</font></a> 
    -+<a href="#M"><font size="-2">M</font></a> 
    -+<a href="#O"><font size="-2">O</font></a> 
    -+<a href="#P"><font size="-2">P</font></a> 
    -+<a href="#S"><font size="-2">S</font></a> 
    -+<a href="#T"><font size="-2">T</font></a> 
    -+ <a href="#topheader"><font size="-2">TOP</font></a>
    -+<p><div style="line-height:1.5em;color:black">
    -+<nobr><A HREF="android.support.v4.media.MediaDescriptionCompat.html#android.support.v4.media.MediaDescriptionCompat.EXTRA_BT_FOLDER_TYPE" class="hiddenlink" target="rightframe">EXTRA_BT_FOLDER_TYPE</A>
    -+</nobr><br>
    -+<nobr><A HREF="android.support.customtabs.CustomTabsIntent.html#android.support.customtabs.CustomTabsIntent.EXTRA_ENABLE_INSTANT_APPS" class="hiddenlink" target="rightframe">EXTRA_ENABLE_INSTANT_APPS</A>
    -+</nobr><br>
    -+<nobr><A HREF="android.support.v4.media.MediaBrowserServiceCompat.BrowserRoot.html#android.support.v4.media.MediaBrowserServiceCompat.BrowserRoot.EXTRA_SUGGESTION_KEYWORDS" class="hiddenlink" target="rightframe">EXTRA_SUGGESTION_KEYWORDS</A>
    -+</nobr><br>
    -+<nobr><A HREF="android.support.v4.app.ActivityOptionsCompat.html#android.support.v4.app.ActivityOptionsCompat.EXTRA_USAGE_TIME_REPORT" class="hiddenlink" target="rightframe">EXTRA_USAGE_TIME_REPORT</A>
    -+</nobr><br>
    -+<nobr><A HREF="android.support.v4.app.ActivityOptionsCompat.html#android.support.v4.app.ActivityOptionsCompat.EXTRA_USAGE_TIME_REPORT_PACKAGES" class="hiddenlink" target="rightframe">EXTRA_USAGE_TIME_REPORT_PACKAGES</A>
    -+</nobr><br>
    -+<A NAME="H"></A>
    -+<br><font size="+2">H</font>&nbsp;
    -+<a href="#A"><font size="-2">A</font></a> 
    -+<a href="#B"><font size="-2">B</font></a> 
    -+<a href="#D"><font size="-2">D</font></a> 
    -+<a href="#E"><font size="-2">E</font></a> 
    -+<a href="#I"><font size="-2">I</font></a> 
    -+<a href="#M"><font size="-2">M</font></a> 
    -+<a href="#O"><font size="-2">O</font></a> 
    -+<a href="#P"><font size="-2">P</font></a> 
    -+<a href="#S"><font size="-2">S</font></a> 
    -+<a href="#T"><font size="-2">T</font></a> 
    -+ <a href="#topheader"><font size="-2">TOP</font></a>
    -+<p><div style="line-height:1.5em;color:black">
    -+<nobr><A HREF="android.support.v4.view.accessibility.AccessibilityNodeProviderCompat.html#android.support.v4.view.accessibility.AccessibilityNodeProviderCompat.HOST_VIEW_ID" class="hiddenlink" target="rightframe">HOST_VIEW_ID</A>
    -+</nobr><br>
    -+<A NAME="I"></A>
    -+<br><font size="+2">I</font>&nbsp;
    -+<a href="#A"><font size="-2">A</font></a> 
    -+<a href="#B"><font size="-2">B</font></a> 
    -+<a href="#D"><font size="-2">D</font></a> 
    -+<a href="#E"><font size="-2">E</font></a> 
    -+<a href="#H"><font size="-2">H</font></a> 
    -+<a href="#M"><font size="-2">M</font></a> 
    -+<a href="#O"><font size="-2">O</font></a> 
    -+<a href="#P"><font size="-2">P</font></a> 
    -+<a href="#S"><font size="-2">S</font></a> 
    -+<a href="#T"><font size="-2">T</font></a> 
    -+ <a href="#topheader"><font size="-2">TOP</font></a>
    -+<p><div style="line-height:1.5em;color:black">
    -+<nobr><A HREF="android.support.design.widget.CoordinatorLayout.LayoutParams.html#android.support.design.widget.CoordinatorLayout.LayoutParams.insetEdge" class="hiddenlink" target="rightframe">insetEdge</A>
    -+</nobr><br>
    -+<A NAME="M"></A>
    -+<br><font size="+2">M</font>&nbsp;
    -+<a href="#A"><font size="-2">A</font></a> 
    -+<a href="#B"><font size="-2">B</font></a> 
    -+<a href="#D"><font size="-2">D</font></a> 
    -+<a href="#E"><font size="-2">E</font></a> 
    -+<a href="#H"><font size="-2">H</font></a> 
    -+<a href="#I"><font size="-2">I</font></a> 
    -+<a href="#O"><font size="-2">O</font></a> 
    -+<a href="#P"><font size="-2">P</font></a> 
    -+<a href="#S"><font size="-2">S</font></a> 
    -+<a href="#T"><font size="-2">T</font></a> 
    -+ <a href="#topheader"><font size="-2">TOP</font></a>
    -+<p><div style="line-height:1.5em;color:black">
    -+<nobr><A HREF="android.support.v4.media.MediaMetadataCompat.html#android.support.v4.media.MediaMetadataCompat.METADATA_KEY_BT_FOLDER_TYPE" class="hiddenlink" target="rightframe">METADATA_KEY_BT_FOLDER_TYPE</A>
    -+</nobr><br>
    -+<nobr><A HREF="android.support.v4.media.MediaMetadataCompat.html#android.support.v4.media.MediaMetadataCompat.METADATA_KEY_MEDIA_URI" class="hiddenlink" target="rightframe">METADATA_KEY_MEDIA_URI</A>
    -+</nobr><br>
    -+<A NAME="O"></A>
    -+<br><font size="+2">O</font>&nbsp;
    -+<a href="#A"><font size="-2">A</font></a> 
    -+<a href="#B"><font size="-2">B</font></a> 
    -+<a href="#D"><font size="-2">D</font></a> 
    -+<a href="#E"><font size="-2">E</font></a> 
    -+<a href="#H"><font size="-2">H</font></a> 
    -+<a href="#I"><font size="-2">I</font></a> 
    -+<a href="#M"><font size="-2">M</font></a> 
    -+<a href="#P"><font size="-2">P</font></a> 
    -+<a href="#S"><font size="-2">S</font></a> 
    -+<a href="#T"><font size="-2">T</font></a> 
    -+ <a href="#topheader"><font size="-2">TOP</font></a>
    -+<p><div style="line-height:1.5em;color:black">
    -+<nobr><A HREF="android.support.v4.view.ViewCompat.html#android.support.v4.view.ViewCompat.OVER_SCROLL_ALWAYS" class="hiddenlink" target="rightframe">OVER_SCROLL_ALWAYS</A>
    -+</nobr><br>
    -+<nobr><A HREF="android.support.v4.view.ViewCompat.html#android.support.v4.view.ViewCompat.OVER_SCROLL_IF_CONTENT_SCROLLS" class="hiddenlink" target="rightframe">OVER_SCROLL_IF_CONTENT_SCROLLS</A>
    -+</nobr><br>
    -+<nobr><A HREF="android.support.v4.view.ViewCompat.html#android.support.v4.view.ViewCompat.OVER_SCROLL_NEVER" class="hiddenlink" target="rightframe">OVER_SCROLL_NEVER</A>
    -+</nobr><br>
    -+<A NAME="P"></A>
    -+<br><font size="+2">P</font>&nbsp;
    -+<a href="#A"><font size="-2">A</font></a> 
    -+<a href="#B"><font size="-2">B</font></a> 
    -+<a href="#D"><font size="-2">D</font></a> 
    -+<a href="#E"><font size="-2">E</font></a> 
    -+<a href="#H"><font size="-2">H</font></a> 
    -+<a href="#I"><font size="-2">I</font></a> 
    -+<a href="#M"><font size="-2">M</font></a> 
    -+<a href="#O"><font size="-2">O</font></a> 
    -+<a href="#S"><font size="-2">S</font></a> 
    -+<a href="#T"><font size="-2">T</font></a> 
    -+ <a href="#topheader"><font size="-2">TOP</font></a>
    -+<p><div style="line-height:1.5em;color:black">
    -+<nobr><A HREF="android.support.design.widget.BottomSheetBehavior.html#android.support.design.widget.BottomSheetBehavior.PEEK_HEIGHT_AUTO" class="hiddenlink" target="rightframe">PEEK_HEIGHT_AUTO</A>
    -+</nobr><br>
    -+<nobr><A HREF="android.support.v17.leanback.widget.AbstractMediaItemPresenter.html#android.support.v17.leanback.widget.AbstractMediaItemPresenter.PLAY_STATE_INITIAL" class="hiddenlink" target="rightframe">PLAY_STATE_INITIAL</A>
    -+</nobr><br>
    -+<nobr><A HREF="android.support.v17.leanback.widget.AbstractMediaItemPresenter.html#android.support.v17.leanback.widget.AbstractMediaItemPresenter.PLAY_STATE_PAUSED" class="hiddenlink" target="rightframe">PLAY_STATE_PAUSED</A>
    -+</nobr><br>
    -+<nobr><A HREF="android.support.v17.leanback.widget.AbstractMediaItemPresenter.html#android.support.v17.leanback.widget.AbstractMediaItemPresenter.PLAY_STATE_PLAYING" class="hiddenlink" target="rightframe">PLAY_STATE_PLAYING</A>
    -+</nobr><br>
    -+<A NAME="S"></A>
    -+<br><font size="+2">S</font>&nbsp;
    -+<a href="#A"><font size="-2">A</font></a> 
    -+<a href="#B"><font size="-2">B</font></a> 
    -+<a href="#D"><font size="-2">D</font></a> 
    -+<a href="#E"><font size="-2">E</font></a> 
    -+<a href="#H"><font size="-2">H</font></a> 
    -+<a href="#I"><font size="-2">I</font></a> 
    -+<a href="#M"><font size="-2">M</font></a> 
    -+<a href="#O"><font size="-2">O</font></a> 
    -+<a href="#P"><font size="-2">P</font></a> 
    -+<a href="#T"><font size="-2">T</font></a> 
    -+ <a href="#topheader"><font size="-2">TOP</font></a>
    -+<p><div style="line-height:1.5em;color:black">
    -+<nobr><A HREF="android.support.v4.app.ServiceCompat.html#android.support.v4.app.ServiceCompat.STOP_FOREGROUND_DETACH" class="hiddenlink" target="rightframe">STOP_FOREGROUND_DETACH</A>
    -+</nobr><br>
    -+<nobr><A HREF="android.support.v4.app.ServiceCompat.html#android.support.v4.app.ServiceCompat.STOP_FOREGROUND_REMOVE" class="hiddenlink" target="rightframe">STOP_FOREGROUND_REMOVE</A>
    -+</nobr><br>
    -+<A NAME="T"></A>
    -+<br><font size="+2">T</font>&nbsp;
    -+<a href="#A"><font size="-2">A</font></a> 
    -+<a href="#B"><font size="-2">B</font></a> 
    -+<a href="#D"><font size="-2">D</font></a> 
    -+<a href="#E"><font size="-2">E</font></a> 
    -+<a href="#H"><font size="-2">H</font></a> 
    -+<a href="#I"><font size="-2">I</font></a> 
    -+<a href="#M"><font size="-2">M</font></a> 
    -+<a href="#O"><font size="-2">O</font></a> 
    -+<a href="#P"><font size="-2">P</font></a> 
    -+<a href="#S"><font size="-2">S</font></a> 
    -+ <a href="#topheader"><font size="-2">TOP</font></a>
    -+<p><div style="line-height:1.5em;color:black">
    -+<nobr><A HREF="android.support.v7.widget.StaggeredGridLayoutManager.html#android.support.v7.widget.StaggeredGridLayoutManager.TAG" class="hiddenlink" target="rightframe"><strike>TAG</strike></A>
    -+</nobr><br>
    -+<nobr><A HREF="android.support.v4.view.accessibility.AccessibilityEventCompat.html#android.support.v4.view.accessibility.AccessibilityEventCompat.TYPE_ASSIST_READING_CONTEXT" class="hiddenlink" target="rightframe">TYPE_ASSIST_READING_CONTEXT</A>
    -+</nobr><br>
    -+<nobr><A HREF="android.support.v4.view.accessibility.AccessibilityWindowInfoCompat.html#android.support.v4.view.accessibility.AccessibilityWindowInfoCompat.TYPE_SPLIT_SCREEN_DIVIDER" class="hiddenlink" target="rightframe">TYPE_SPLIT_SCREEN_DIVIDER</A>
    -+</nobr><br>
    -+<nobr><A HREF="android.support.v4.view.accessibility.AccessibilityEventCompat.html#android.support.v4.view.accessibility.AccessibilityEventCompat.TYPE_VIEW_CONTEXT_CLICKED" class="hiddenlink" target="rightframe">TYPE_VIEW_CONTEXT_CLICKED</A>
    -+</nobr><br>
    -+<nobr><A HREF="android.support.v4.view.accessibility.AccessibilityEventCompat.html#android.support.v4.view.accessibility.AccessibilityEventCompat.TYPE_WINDOWS_CHANGED" class="hiddenlink" target="rightframe">TYPE_WINDOWS_CHANGED</A>
    -+</nobr><br>
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    -+</script>
    -+<script type="text/javascript">
    -+  try {
    -+    var pageTracker = _gat._getTracker("UA-5831155-1");
    -+    pageTracker._setAllowAnchor(true);
    -+    pageTracker._initData();
    -+    pageTracker._trackPageview();
    -+  } catch(e) {}
    -+</script>
    -+</BODY>
    -+</HTML>
    -diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/fields_index_changes.html b/docs/html/sdk/support_api_diff/24.2.0/changes/fields_index_changes.html
    -new file mode 100644
    -index 0000000..c72b2de
    ---- /dev/null
    -+++ b/docs/html/sdk/support_api_diff/24.2.0/changes/fields_index_changes.html
    -@@ -0,0 +1,71 @@
    -+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
    -+<HTML style="overflow:auto;">
    -+<HEAD>
    -+<meta name="generator" content="JDiff v1.1.0">
    -+<!-- Generated by the JDiff Javadoc doclet -->
    -+<!-- (http://www.jdiff.org) -->
    -+<meta name="description" content="JDiff is a Javadoc doclet which generates an HTML report of all the packages, classes, constructors, methods, and fields which have been removed, added or changed in any way, including their documentation, when two APIs are compared.">
    -+<meta name="keywords" content="diff, jdiff, javadiff, java diff, java difference, API difference, difference between two APIs, API diff, Javadoc, doclet">
    -+<TITLE>
    -+Field Changes Index
    -+</TITLE>
    -+<link href="../../../../assets/android-developer-docs.css" rel="stylesheet" type="text/css" />
    -+<link href="../stylesheet-jdiff.css" rel="stylesheet" type="text/css" />
    -+<noscript>
    -+<style type="text/css">
    -+body{overflow:auto;}
    -+#body-content{position:relative; top:0;}
    -+#doc-content{overflow:visible;border-left:3px solid #666;}
    -+#side-nav{padding:0;}
    -+#side-nav .toggle-list ul {display:block;}
    -+#resize-packages-nav{border-bottom:3px solid #666;}
    -+</style>
    -+</noscript>
    -+<style type="text/css">
    -+</style>
    -+</HEAD>
    -+<BODY class="gc-documentation" style="padding:12px;">
    -+<a NAME="topheader"></a>
    -+<table summary="Index for Fields" width="100%" class="jdiffIndex" border="0" cellspacing="0" cellpadding="0" style="padding-bottom:0;margin-bottom:0;">
    -+  <tr>
    -+  <th class="indexHeader">
    -+    Filter the Index:
    -+  </th>
    -+  </tr>
    -+  <tr>
    -+  <td class="indexText" style="line-height:1.3em;padding-left:2em;">
    -+<a href="fields_index_all.html" class="staysblack">All Fields</a>
    -+  <br>
    -+<A HREF="fields_index_removals.html" xclass="hiddenlink">Removals</A>
    -+  <br>
    -+<A HREF="fields_index_additions.html"xclass="hiddenlink">Additions</A>
    -+  <br>
    -+<b>Changes</b>
    -+  </td>
    -+  </tr>
    -+</table>
    -+<div id="indexTableCaption" style="background-color:#eee;padding:0 4px 0 4px;font-size:11px;margin-bottom:1em;">
    -+Listed as: <span style="color:#069"><strong>Added</strong></span>,  <span style="color:#069"><strike>Removed</strike></span>,  <span style="color:#069">Changed</span></font>
    -+</div>
    -+<A NAME="O"></A>
    -+<br><font size="+2">O</font>&nbsp;
    -+ <a href="#topheader"><font size="-2">TOP</font></a>
    -+<p><div style="line-height:1.5em;color:black">
    -+<nobr><A HREF="android.support.v4.view.ViewCompat.html#android.support.v4.view.ViewCompat.OVER_SCROLL_ALWAYS" class="hiddenlink" target="rightframe">OVER_SCROLL_ALWAYS</A>
    -+</nobr><br>
    -+<nobr><A HREF="android.support.v4.view.ViewCompat.html#android.support.v4.view.ViewCompat.OVER_SCROLL_IF_CONTENT_SCROLLS" class="hiddenlink" target="rightframe">OVER_SCROLL_IF_CONTENT_SCROLLS</A>
    -+</nobr><br>
    -+<nobr><A HREF="android.support.v4.view.ViewCompat.html#android.support.v4.view.ViewCompat.OVER_SCROLL_NEVER" class="hiddenlink" target="rightframe">OVER_SCROLL_NEVER</A>
    -+</nobr><br>
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    -+</script>
    -+<script type="text/javascript">
    -+  try {
    -+    var pageTracker = _gat._getTracker("UA-5831155-1");
    -+    pageTracker._setAllowAnchor(true);
    -+    pageTracker._initData();
    -+    pageTracker._trackPageview();
    -+  } catch(e) {}
    -+</script>
    -+</BODY>
    -+</HTML>
    -diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/fields_index_removals.html b/docs/html/sdk/support_api_diff/24.2.0/changes/fields_index_removals.html
    -new file mode 100644
    -index 0000000..61820d1
    ---- /dev/null
    -+++ b/docs/html/sdk/support_api_diff/24.2.0/changes/fields_index_removals.html
    -@@ -0,0 +1,67 @@
    -+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
    -+<HTML style="overflow:auto;">
    -+<HEAD>
    -+<meta name="generator" content="JDiff v1.1.0">
    -+<!-- Generated by the JDiff Javadoc doclet -->
    -+<!-- (http://www.jdiff.org) -->
    -+<meta name="description" content="JDiff is a Javadoc doclet which generates an HTML report of all the packages, classes, constructors, methods, and fields which have been removed, added or changed in any way, including their documentation, when two APIs are compared.">
    -+<meta name="keywords" content="diff, jdiff, javadiff, java diff, java difference, API difference, difference between two APIs, API diff, Javadoc, doclet">
    -+<TITLE>
    -+Field Removals Index
    -+</TITLE>
    -+<link href="../../../../assets/android-developer-docs.css" rel="stylesheet" type="text/css" />
    -+<link href="../stylesheet-jdiff.css" rel="stylesheet" type="text/css" />
    -+<noscript>
    -+<style type="text/css">
    -+body{overflow:auto;}
    -+#body-content{position:relative; top:0;}
    -+#doc-content{overflow:visible;border-left:3px solid #666;}
    -+#side-nav{padding:0;}
    -+#side-nav .toggle-list ul {display:block;}
    -+#resize-packages-nav{border-bottom:3px solid #666;}
    -+</style>
    -+</noscript>
    -+<style type="text/css">
    -+</style>
    -+</HEAD>
    -+<BODY class="gc-documentation" style="padding:12px;">
    -+<a NAME="topheader"></a>
    -+<table summary="Index for Fields" width="100%" class="jdiffIndex" border="0" cellspacing="0" cellpadding="0" style="padding-bottom:0;margin-bottom:0;">
    -+  <tr>
    -+  <th class="indexHeader">
    -+    Filter the Index:
    -+  </th>
    -+  </tr>
    -+  <tr>
    -+  <td class="indexText" style="line-height:1.3em;padding-left:2em;">
    -+<a href="fields_index_all.html" class="staysblack">All Fields</a>
    -+  <br>
    -+<b>Removals</b>
    -+  <br>
    -+<A HREF="fields_index_additions.html"xclass="hiddenlink">Additions</A>
    -+  <br>
    -+<A HREF="fields_index_changes.html"xclass="hiddenlink">Changes</A>
    -+  </td>
    -+  </tr>
    -+</table>
    -+<div id="indexTableCaption" style="background-color:#eee;padding:0 4px 0 4px;font-size:11px;margin-bottom:1em;">
    -+Listed as: <span style="color:#069"><strong>Added</strong></span>,  <span style="color:#069"><strike>Removed</strike></span>,  <span style="color:#069">Changed</span></font>
    -+</div>
    -+<A NAME="T"></A>
    -+<br><font size="+2">T</font>&nbsp;
    -+ <a href="#topheader"><font size="-2">TOP</font></a>
    -+<p><div style="line-height:1.5em;color:black">
    -+<nobr><A HREF="android.support.v7.widget.StaggeredGridLayoutManager.html#android.support.v7.widget.StaggeredGridLayoutManager.TAG" class="hiddenlink" target="rightframe"><strike>TAG</strike></A>
    -+</nobr><br>
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    -+</script>
    -+<script type="text/javascript">
    -+  try {
    -+    var pageTracker = _gat._getTracker("UA-5831155-1");
    -+    pageTracker._setAllowAnchor(true);
    -+    pageTracker._initData();
    -+    pageTracker._trackPageview();
    -+  } catch(e) {}
    -+</script>
    -+</BODY>
    -+</HTML>
    -diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/jdiff_help.html b/docs/html/sdk/support_api_diff/24.2.0/changes/jdiff_help.html
    -new file mode 100644
    -index 0000000..966dda8
    ---- /dev/null
    -+++ b/docs/html/sdk/support_api_diff/24.2.0/changes/jdiff_help.html
    -@@ -0,0 +1,134 @@
    -+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
    -+<HTML style="overflow:auto;">
    -+<HEAD>
    -+<meta name="generator" content="JDiff v1.1.0">
    -+<!-- Generated by the JDiff Javadoc doclet -->
    -+<!-- (http://www.jdiff.org) -->
    -+<meta name="description" content="JDiff is a Javadoc doclet which generates an HTML report of all the packages, classes, constructors, methods, and fields which have been removed, added or changed in any way, including their documentation, when two APIs are compared.">
    -+<meta name="keywords" content="diff, jdiff, javadiff, java diff, java difference, API difference, difference between two APIs, API diff, Javadoc, doclet">
    -+<TITLE>
    -+JDiff Help
    -+</TITLE>
    -+<link href="../../../../assets/android-developer-docs.css" rel="stylesheet" type="text/css" />
    -+<link href="../stylesheet-jdiff.css" rel="stylesheet" type="text/css" />
    -+<noscript>
    -+<style type="text/css">
    -+body{overflow:auto;}
    -+#body-content{position:relative; top:0;}
    -+#doc-content{overflow:visible;border-left:3px solid #666;}
    -+#side-nav{padding:0;}
    -+#side-nav .toggle-list ul {display:block;}
    -+#resize-packages-nav{border-bottom:3px solid #666;}
    -+</style>
    -+</noscript>
    -+<style type="text/css">
    -+</style>
    -+</HEAD>
    -+<BODY>
    -+<!-- Start of nav bar -->
    -+<TABLE summary="Navigation bar" BORDER="0" WIDTH="100%" CELLPADDING="1" CELLSPACING="0">
    -+<TR>
    -+<TD COLSPAN=2 BGCOLOR="#EEEEFF" CLASS="NavBarCell1">
    -+  <TABLE summary="Navigation bar" BORDER="0" CELLPADDING="0" CELLSPACING="3">
    -+    <TR ALIGN="center" VALIGN="top">
    -+      <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../../reference/index.html" target="_top"><FONT CLASS="NavBarFont1"><B><code>24.2.0</code></B></FONT></A>&nbsp;</TD>
    -+      <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="changes-summary.html"><FONT CLASS="NavBarFont1"><B>Overview</B></FONT></A>&nbsp;</TD>
    -+      <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> &nbsp;<FONT CLASS="NavBarFont1">Package</FONT>&nbsp;</TD>
    -+      <TD BGCOLOR="#FFFFFF" CLASS="NavBarCell1"> &nbsp;<FONT CLASS="NavBarFont1">Class</FONT>&nbsp;</TD>
    -+      <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="jdiff_statistics.html"><FONT CLASS="NavBarFont1"><B>Statistics</B></FONT></A>&nbsp;</TD>
    -+      <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1Rev"> &nbsp;<FONT CLASS="NavBarFont1Rev"><B>Help</B></FONT>&nbsp;</TD>
    -+    </TR>
    -+  </TABLE>
    -+</TD>
    -+<TD ALIGN="right" VALIGN="top" ROWSPAN=3><EM><b>Generated by<br><a href="http://www.jdiff.org" class="staysblack" target="_top">JDiff</a></b></EM></TD>
    -+</TR>
    -+<TR>
    -+  <TD BGCOLOR="#FFFFFF" CLASS="NavBarCell2"><FONT SIZE="-2"></FONT>
    -+</TD>
    -+  <TD BGCOLOR="#FFFFFF" CLASS="NavBarCell2"><FONT SIZE="-2">
    -+  <A HREF="../changes.html" TARGET="_top"><B>FRAMES</B></A>  &nbsp;
    -+  &nbsp;<A HREF="jdiff_help.html" TARGET="_top"><B>NO FRAMES</B></A></FONT></TD>
    -+</TR>
    -+</TABLE>
    -+<HR>
    -+<!-- End of nav bar -->
    -+<center>
    -+<H1>JDiff Documentation</H1>
    -+</center>
    -+<BLOCKQUOTE>
    -+JDiff is a <a href="http://java.sun.com/j2se/javadoc/" target="_top">Javadoc</a> doclet which generates a report of the API differences between two versions of a product. It does not report changes in Javadoc comments, or changes in what a class or method does. 
    -+This help page describes the different parts of the output from JDiff.
    -+</BLOCKQUOTE>
    -+<BLOCKQUOTE>
    -+ See the reference page in the <a href="http://www.jdiff.org">source for JDiff</a> for information about how to generate a report like this one.
    -+</BLOCKQUOTE>
    -+<BLOCKQUOTE>
    -+The indexes shown in the top-left frame help show each type of change in more detail. The index "All Differences" contains all the differences between the APIs, in alphabetical order. 
    -+These indexes all use the same format:
    -+<ul>
    -+<li>Removed packages, classes, constructors, methods and fields are <strike>struck through</strike>.</li>
    -+<li>Added packages, classes, constructors, methods and fields appear in <b>bold</b>.</li>
    -+<li>Changed packages, classes, constructors, methods and fields appear in normal text.</li>
    -+</ul>
    -+</BLOCKQUOTE>
    -+<BLOCKQUOTE>
    -+You can always tell when you are reading a JDiff page, rather than a Javadoc page, by the color of the index bar and the color of the background. 
    -+Links which take you to a Javadoc page are always in a <code>typewriter</code> font. 
    -+Just like Javadoc, all interface names are in <i>italic</i>, and class names are not italicized. Where there are multiple entries in an index with the same name, the heading for them is also in italics, but is not a link.
    -+</BLOCKQUOTE>
    -+<BLOCKQUOTE>
    -+<H3><b><code>Javadoc</code></b></H3>
    -+This is a link to the <a href="../../../../reference/index.html" target="_top">top-level</a> Javadoc page for the new version of the product.
    -+</BLOCKQUOTE>
    -+<BLOCKQUOTE>
    -+<H3>Overview</H3>
    -+The <a href="changes-summary.html">overview</a> is the top-level summary of what was removed, added and changed between versions.
    -+</BLOCKQUOTE>
    -+<BLOCKQUOTE>
    -+<H3>Package</H3>
    -+This is a link to the package containing the current changed class or interface.
    -+</BLOCKQUOTE>
    -+<BLOCKQUOTE>
    -+<H3>Class</H3>
    -+This is highlighted when you are looking at the changed class or interface.
    -+</BLOCKQUOTE>
    -+<BLOCKQUOTE>
    -+<H3>Text Changes</H3>
    -+This is a link to the top-level index of all documentation changes for the current package or class. 
    -+If it is not present, then there are no documentation changes for the current package or class. 
    -+This link can be removed entirely by not using the <code>-docchanges</code> option.
    -+</BLOCKQUOTE>
    -+<BLOCKQUOTE>
    -+<H3>Statistics</H3>
    -+This is a link to a page which shows statistics about the changes between the two APIs.
    -+This link can be removed entirely by not using the <code>-stats</code> option.
    -+</BLOCKQUOTE>
    -+<BLOCKQUOTE>
    -+<H3>Help</H3>
    -+A link to this Help page for JDiff.
    -+</BLOCKQUOTE>
    -+<BLOCKQUOTE>
    -+<H3>Prev/Next</H3>
    -+These links take you to the previous  and next changed package or class.
    -+</BLOCKQUOTE>
    -+<BLOCKQUOTE>
    -+<H3>Frames/No Frames</H3>
    -+These links show and hide the HTML frames. All pages are available with or without frames.
    -+</BLOCKQUOTE>
    -+<BLOCKQUOTE>
    -+<H2>Complex Changes</H2>
    -+There are some complex changes which can occur between versions, for example, when two or more methods with the same name change simultaneously, or when a method or field is moved into or from a superclass. 
    -+In these cases, the change will be seen as a removal and an addition, rather than as a change. Unexpected removals or additions are often part of one of these type of changes. 
    -+</BLOCKQUOTE>
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    -+</script>
    -+<script type="text/javascript">
    -+  try {
    -+    var pageTracker = _gat._getTracker("UA-5831155-1");
    -+    pageTracker._setAllowAnchor(true);
    -+    pageTracker._initData();
    -+    pageTracker._trackPageview();
    -+  } catch(e) {}
    -+</script>
    -+</BODY>
    -+</HTML>
    -diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/jdiff_statistics.html b/docs/html/sdk/support_api_diff/24.2.0/changes/jdiff_statistics.html
    -new file mode 100644
    -index 0000000..7010da6
    ---- /dev/null
    -+++ b/docs/html/sdk/support_api_diff/24.2.0/changes/jdiff_statistics.html
    -@@ -0,0 +1,596 @@
    -+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
    -+<HTML style="overflow:auto;">
    -+<HEAD>
    -+<meta name="generator" content="JDiff v1.1.0">
    -+<!-- Generated by the JDiff Javadoc doclet -->
    -+<!-- (http://www.jdiff.org) -->
    -+<meta name="description" content="JDiff is a Javadoc doclet which generates an HTML report of all the packages, classes, constructors, methods, and fields which have been removed, added or changed in any way, including their documentation, when two APIs are compared.">
    -+<meta name="keywords" content="diff, jdiff, javadiff, java diff, java difference, API difference, difference between two APIs, API diff, Javadoc, doclet">
    -+<TITLE>
    -+API Change Statistics
    -+</TITLE>
    -+<link href="../../../../assets/android-developer-docs.css" rel="stylesheet" type="text/css" />
    -+<link href="../stylesheet-jdiff.css" rel="stylesheet" type="text/css" />
    -+<noscript>
    -+<style type="text/css">
    -+body{overflow:auto;}
    -+#body-content{position:relative; top:0;}
    -+#doc-content{overflow:visible;border-left:3px solid #666;}
    -+#side-nav{padding:0;}
    -+#side-nav .toggle-list ul {display:block;}
    -+#resize-packages-nav{border-bottom:3px solid #666;}
    -+</style>
    -+</noscript>
    -+<style type="text/css">
    -+</style>
    -+</HEAD>
    -+<body class="gc-documentation">
    -+<!-- Start of nav bar -->
    -+<a name="top"></a>
    -+<div id="header" style="margin-bottom:0;xborder-bottom:none;">
    -+<div id="headerLeft">
    -+<a href="../../../../index.html" tabindex="-1" target="_top"><img src="../../../../assets/images/bg_logo.png" alt="Android Developers" /></a>
    -+</div>
    -+  <div id="headerRight">
    -+  <div id="headerLinks">
    -+<!-- <img src="/assets/images/icon_world.jpg" alt="" /> -->
    -+<span class="text">
    -+<!-- &nbsp;<a href="#">English</a> | -->
    -+<nobr><a href="http://developer.android.com" target="_top">Android Developers</a> | <a href="http://www.android.com" target="_top">Android.com</a></nobr>
    -+</span>
    -+</div>
    -+  <div class="and-diff-id" style="margin-top:6px;margin-right:8px;">
    -+    <table class="diffspectable">
    -+      <tr>
    -+        <td colspan="2" class="diffspechead">API Diff Specification</td>
    -+      </tr>
    -+      <tr>
    -+        <td class="diffspec" style="padding-top:.25em">To Level:</td>
    -+        <td class="diffvaluenew" style="padding-top:.25em">24.2.0</td>
    -+      </tr>
    -+      <tr>
    -+        <td class="diffspec">From Level:</td>
    -+        <td class="diffvalueold">24.1.0</td>
    -+      </tr>
    -+      <tr>
    -+        <td class="diffspec">Generated</td>
    -+        <td class="diffvalue">2016.08.16 14:03</td>
    -+      </tr>
    -+    </table>
    -+    </div><!-- End and-diff-id -->
    -+  <div class="and-diff-id" style="margin-right:8px;">
    -+    <table class="diffspectable">
    -+      <tr>
    -+        <td class="diffspec" colspan="2"><a href="../changes.html" target="_top">Top of Report</a>
    -+      </tr>
    -+    </table>
    -+  </div> <!-- End and-diff-id -->
    -+  </div> <!-- End headerRight -->
    -+  </div> <!-- End header -->
    -+<div id="body-content">
    -+<div id="doc-content" style="position:relative;">
    -+<div id="mainBodyFluid">
    -+<h1>API&nbsp;Change&nbsp;Statistics</h1>
    -+<p>The overall difference between API Levels 24.1.0 and 24.2.0 is approximately <span style="color:222;font-weight:bold;">8.39%</span>.
    -+</p>
    -+<br>
    -+<a name="numbers"></a>
    -+<h2>Total of Differences, by Number and Type</h2>
    -+<p>
    -+The table below lists the numbers of program elements (packages, classes, constructors, methods, and fields) that were added, changed, or removed. The table includes only the highest-level program elements &mdash; that is, if a class with two methods was added, the number of methods added does not include those two methods, but the number of classes added does include that class.
    -+</p>
    -+<TABLE summary="Number of differences" WIDTH="100%">
    -+<TR>
    -+  <th>Type</th>
    -+  <TH ALIGN="center"><b>Additions</b></TH>
    -+  <TH ALIGN="center"><b>Changes</b></TH>
    -+  <TH ALIGN="center">Removals</TH>
    -+  <TH ALIGN="center"><b>Total</b></TH>
    -+</TR>
    -+<TR>
    -+  <TD>Packages</TD>
    -+  <TD ALIGN="right">2</TD>
    -+  <TD ALIGN="right">22</TD>
    -+  <TD ALIGN="right">3</TD>
    -+  <TD ALIGN="right">27</TD>
    -+</TR>
    -+<TR>
    -+  <TD>Classes and <i>Interfaces</i></TD>
    -+  <TD ALIGN="right">64</TD>
    -+  <TD ALIGN="right">63</TD>
    -+  <TD ALIGN="right">0</TD>
    -+  <TD ALIGN="right">127</TD>
    -+</TR>
    -+<TR>
    -+  <TD>Constructors</TD>
    -+  <TD ALIGN="right">1</TD>
    -+  <TD ALIGN="right">2</TD>
    -+  <TD ALIGN="right">0</TD>
    -+  <TD ALIGN="right">3</TD>
    -+</TR>
    -+<TR>
    -+  <TD>Methods</TD>
    -+  <TD ALIGN="right">80</TD>
    -+  <TD ALIGN="right">25</TD>
    -+  <TD ALIGN="right">7</TD>
    -+  <TD ALIGN="right">112</TD>
    -+</TR>
    -+<TR>
    -+  <TD>Fields</TD>
    -+  <TD ALIGN="right">38</TD>
    -+  <TD ALIGN="right">3</TD>
    -+  <TD ALIGN="right">1</TD>
    -+  <TD ALIGN="right">42</TD>
    -+</TR>
    -+<TR>
    -+  <TD style="background-color:#FAFAFA"><b>Total</b></TD>
    -+  <TD  style="background-color:#FAFAFA" ALIGN="right"><strong>185</strong></TD>
    -+  <TD  style="background-color:#FAFAFA" ALIGN="right"><strong>115</strong></TD>
    -+  <TD  style="background-color:#FAFAFA" ALIGN="right"><strong>11</strong></TD>
    -+  <TD  style="background-color:#FAFAFA" ALIGN="right"><strong>311</strong></TD>
    -+</TR>
    -+</TABLE>
    -+<br>
    -+<a name="packages"></a>
    -+<h2>Changed Packages, Sorted by Percentage Difference</h2>
    -+<TABLE summary="Packages sorted by percentage difference" WIDTH="100%">
    -+<TR>
    -+  <TH  WIDTH="10%">Percentage Difference*</TH>
    -+  <TH>Package</TH>
    -+</TR>
    -+<TR>
    -+  <TD ALIGN="center">37</TD>
    -+  <TD><A HREF="pkg_android.support.v7.widget.html">android.support.v7.widget</A></TD>
    -+</TR>
    -+<TR>
    -+  <TD ALIGN="center">33</TD>
    -+  <TD><A HREF="pkg_android.support.v7.content.res.html">android.support.v7.content.res</A></TD>
    -+</TR>
    -+<TR>
    -+  <TD ALIGN="center">32</TD>
    -+  <TD><A HREF="pkg_android.support.v7.util.html">android.support.v7.util</A></TD>
    -+</TR>
    -+<TR>
    -+  <TD ALIGN="center">19</TD>
    -+  <TD><A HREF="pkg_android.support.v4.view.accessibility.html">android.support.v4.view.accessibility</A></TD>
    -+</TR>
    -+<TR>
    -+  <TD ALIGN="center">12</TD>
    -+  <TD><A HREF="pkg_android.support.v7.app.html">android.support.v7.app</A></TD>
    -+</TR>
    -+<TR>
    -+  <TD ALIGN="center">5</TD>
    -+  <TD><A HREF="pkg_android.support.v4.widget.html">android.support.v4.widget</A></TD>
    -+</TR>
    -+<TR>
    -+  <TD ALIGN="center">4</TD>
    -+  <TD><A HREF="pkg_android.support.v4.accessibilityservice.html">android.support.v4.accessibilityservice</A></TD>
    -+</TR>
    -+<TR>
    -+  <TD ALIGN="center">4</TD>
    -+  <TD><A HREF="pkg_android.support.customtabs.html">android.support.customtabs</A></TD>
    -+</TR>
    -+<TR>
    -+  <TD ALIGN="center">3</TD>
    -+  <TD><A HREF="pkg_android.support.v4.util.html">android.support.v4.util</A></TD>
    -+</TR>
    -+<TR>
    -+  <TD ALIGN="center">3</TD>
    -+  <TD><A HREF="pkg_android.support.v4.os.html">android.support.v4.os</A></TD>
    -+</TR>
    -+<TR>
    -+  <TD ALIGN="center">2</TD>
    -+  <TD><A HREF="pkg_android.support.v4.media.session.html">android.support.v4.media.session</A></TD>
    -+</TR>
    -+<TR>
    -+  <TD ALIGN="center">2</TD>
    -+  <TD><A HREF="pkg_android.support.v4.app.html">android.support.v4.app</A></TD>
    -+</TR>
    -+<TR>
    -+  <TD ALIGN="center">2</TD>
    -+  <TD><A HREF="pkg_android.support.design.widget.html">android.support.design.widget</A></TD>
    -+</TR>
    -+<TR>
    -+  <TD ALIGN="center">2</TD>
    -+  <TD><A HREF="pkg_android.support.v4.media.html">android.support.v4.media</A></TD>
    -+</TR>
    -+<TR>
    -+  <TD ALIGN="center">1</TD>
    -+  <TD><A HREF="pkg_android.support.v7.preference.html">android.support.v7.preference</A></TD>
    -+</TR>
    -+<TR>
    -+  <TD ALIGN="center">1</TD>
    -+  <TD><A HREF="pkg_android.support.v4.view.html">android.support.v4.view</A></TD>
    -+</TR>
    -+<TR>
    -+  <TD ALIGN="center">1</TD>
    -+  <TD><A HREF="pkg_android.support.v17.preference.html">android.support.v17.preference</A></TD>
    -+</TR>
    -+<TR>
    -+  <TD ALIGN="center">&lt;1</TD>
    -+  <TD><A HREF="pkg_android.support.v4.graphics.drawable.html">android.support.v4.graphics.drawable</A></TD>
    -+</TR>
    -+<TR>
    -+  <TD ALIGN="center">&lt;1</TD>
    -+  <TD><A HREF="pkg_android.support.v7.graphics.html">android.support.v7.graphics</A></TD>
    -+</TR>
    -+<TR>
    -+  <TD ALIGN="center">&lt;1</TD>
    -+  <TD><A HREF="pkg_android.support.v17.leanback.widget.html">android.support.v17.leanback.widget</A></TD>
    -+</TR>
    -+<TR>
    -+  <TD ALIGN="center">&lt;1</TD>
    -+  <TD><A HREF="pkg_android.support.v14.preference.html">android.support.v14.preference</A></TD>
    -+</TR>
    -+<TR>
    -+  <TD ALIGN="center">&lt;1</TD>
    -+  <TD><A HREF="pkg_android.support.v4.content.html">android.support.v4.content</A></TD>
    -+</TR>
    -+</TABLE>
    -+<p style="font-size:10px">* See <a href="#calculation">Calculation of Change Percentages</a>, below.</p>
    -+<br>
    -+<a name="classes"></a>
    -+<h2>Changed Classes and <i>Interfaces</i>, Sorted by Percentage Difference</h2>
    -+<TABLE summary="Classes sorted by percentage difference" WIDTH="100%">
    -+<TR WIDTH="20%">
    -+  <TH WIDTH="10%">Percentage<br>Difference*</TH>
    -+  <TH><b>Class or <i>Interface</i></b></TH>
    -+</TR>
    -+<TR>
    -+  <TD ALIGN="center">60</TD>
    -+  <TD><A HREF="android.support.v4.app.ServiceCompat.html">
    -+android.support.v4.app.ServiceCompat</A></TD>
    -+</TR>
    -+<TR>
    -+  <TD ALIGN="center">38</TD>
    -+  <TD><A HREF="android.support.design.widget.FloatingActionButton.Behavior.html">
    -+android.support.design.widget.FloatingActionButton.Behavior</A></TD>
    -+</TR>
    -+<TR>
    -+  <TD ALIGN="center">33</TD>
    -+  <TD><A HREF="android.support.v4.app.ActivityOptionsCompat.html">
    -+android.support.v4.app.ActivityOptionsCompat</A></TD>
    -+</TR>
    -+<TR>
    -+  <TD ALIGN="center">33</TD>
    -+  <TD><A HREF="android.support.v4.os.BuildCompat.html">
    -+android.support.v4.os.BuildCompat</A></TD>
    -+</TR>
    -+<TR>
    -+  <TD ALIGN="center">33</TD>
    -+  <TD><A HREF="android.support.v4.view.accessibility.AccessibilityManagerCompat.html">
    -+android.support.v4.view.accessibility.AccessibilityManagerCompat</A></TD>
    -+</TR>
    -+<TR>
    -+  <TD ALIGN="center">33</TD>
    -+  <TD><A HREF="android.support.v4.view.accessibility.AccessibilityManagerCompat.AccessibilityStateChangeListenerCompat.html">
    -+android.support.v4.view.accessibility.AccessibilityManagerCompat.AccessibilityStateChangeListenerCompat</A></TD>
    -+</TR>
    -+<TR>
    -+  <TD ALIGN="center">33</TD>
    -+  <TD><A HREF="android.support.v7.content.res.AppCompatResources.html">
    -+android.support.v7.content.res.AppCompatResources</A></TD>
    -+</TR>
    -+<TR>
    -+  <TD ALIGN="center">28</TD>
    -+  <TD><A HREF="android.support.customtabs.CustomTabsSession.html">
    -+android.support.customtabs.CustomTabsSession</A></TD>
    -+</TR>
    -+<TR>
    -+  <TD ALIGN="center">28</TD>
    -+  <TD><A HREF="android.support.v7.util.SortedList.Callback.html">
    -+android.support.v7.util.SortedList.Callback</A></TD>
    -+</TR>
    -+<TR>
    -+  <TD ALIGN="center">25</TD>
    -+  <TD><A HREF="android.support.v4.media.session.MediaButtonReceiver.html">
    -+android.support.v4.media.session.MediaButtonReceiver</A></TD>
    -+</TR>
    -+<TR>
    -+  <TD ALIGN="center">25</TD>
    -+  <TD><A HREF="android.support.v4.view.ViewConfigurationCompat.html">
    -+android.support.v4.view.ViewConfigurationCompat</A></TD>
    -+</TR>
    -+<TR>
    -+  <TD ALIGN="center">25</TD>
    -+  <TD><A HREF="android.support.v4.widget.SearchViewCompat.OnCloseListenerCompat.html">
    -+android.support.v4.widget.SearchViewCompat.OnCloseListenerCompat</A></TD>
    -+</TR>
    -+<TR>
    -+  <TD ALIGN="center">23</TD>
    -+  <TD><A HREF="android.support.v4.media.MediaDescriptionCompat.html">
    -+android.support.v4.media.MediaDescriptionCompat</A></TD>
    -+</TR>
    -+<TR>
    -+  <TD ALIGN="center">20</TD>
    -+  <TD><A HREF="android.support.v4.view.KeyEventCompat.html">
    -+android.support.v4.view.KeyEventCompat</A></TD>
    -+</TR>
    -+<TR>
    -+  <TD ALIGN="center">18</TD>
    -+  <TD><A HREF="android.support.v17.leanback.widget.AbstractMediaItemPresenter.html">
    -+android.support.v17.leanback.widget.AbstractMediaItemPresenter</A></TD>
    -+</TR>
    -+<TR>
    -+  <TD ALIGN="center">18</TD>
    -+  <TD><A HREF="android.support.design.widget.TextInputLayout.html">
    -+android.support.design.widget.TextInputLayout</A></TD>
    -+</TR>
    -+<TR>
    -+  <TD ALIGN="center">17</TD>
    -+  <TD><A HREF="android.support.v17.leanback.widget.AbstractMediaItemPresenter.ViewHolder.html">
    -+android.support.v17.leanback.widget.AbstractMediaItemPresenter.ViewHolder</A></TD>
    -+</TR>
    -+<TR>
    -+  <TD ALIGN="center">16</TD>
    -+  <TD><A HREF="android.support.v4.widget.SearchViewCompat.OnQueryTextListenerCompat.html">
    -+android.support.v4.widget.SearchViewCompat.OnQueryTextListenerCompat</A></TD>
    -+</TR>
    -+<TR>
    -+  <TD ALIGN="center">15</TD>
    -+  <TD><A HREF="android.support.v4.media.session.MediaSessionCompat.QueueItem.html">
    -+android.support.v4.media.session.MediaSessionCompat.QueueItem</A></TD>
    -+</TR>
    -+<TR>
    -+  <TD ALIGN="center">13</TD>
    -+  <TD><A HREF="android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat.html">
    -+android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat</A></TD>
    -+</TR>
    -+<TR>
    -+  <TD ALIGN="center">12</TD>
    -+  <TD><A HREF="android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.CollectionInfoCompat.html">
    -+android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.CollectionInfoCompat</A></TD>
    -+</TR>
    -+<TR>
    -+  <TD ALIGN="center">11</TD>
    -+  <TD><A HREF="android.support.v4.view.accessibility.AccessibilityEventCompat.html">
    -+android.support.v4.view.accessibility.AccessibilityEventCompat</A></TD>
    -+</TR>
    -+<TR>
    -+  <TD ALIGN="center">11</TD>
    -+  <TD><A HREF="android.support.design.widget.AppBarLayout.ScrollingViewBehavior.html">
    -+android.support.design.widget.AppBarLayout.ScrollingViewBehavior</A></TD>
    -+</TR>
    -+<TR>
    -+  <TD ALIGN="center">10</TD>
    -+  <TD><A HREF="android.support.v17.preference.LeanbackSettingsFragment.html">
    -+android.support.v17.preference.LeanbackSettingsFragment</A></TD>
    -+</TR>
    -+<TR>
    -+  <TD ALIGN="center">9</TD>
    -+  <TD><A HREF="android.support.design.widget.CoordinatorLayout.Behavior.html">
    -+android.support.design.widget.CoordinatorLayout.Behavior</A></TD>
    -+</TR>
    -+<TR>
    -+  <TD ALIGN="center">8</TD>
    -+  <TD><A HREF="android.support.design.widget.CoordinatorLayout.LayoutParams.html">
    -+android.support.design.widget.CoordinatorLayout.LayoutParams</A></TD>
    -+</TR>
    -+<TR>
    -+  <TD ALIGN="center">8</TD>
    -+  <TD><A HREF="android.support.v4.media.MediaBrowserCompat.MediaItem.html">
    -+android.support.v4.media.MediaBrowserCompat.MediaItem</A></TD>
    -+</TR>
    -+<TR>
    -+  <TD ALIGN="center">7</TD>
    -+  <TD><A HREF="android.support.v4.media.MediaBrowserServiceCompat.BrowserRoot.html">
    -+android.support.v4.media.MediaBrowserServiceCompat.BrowserRoot</A></TD>
    -+</TR>
    -+<TR>
    -+  <TD ALIGN="center">7</TD>
    -+  <TD><A HREF="android.support.v4.widget.TextViewCompat.html">
    -+android.support.v4.widget.TextViewCompat</A></TD>
    -+</TR>
    -+<TR>
    -+  <TD ALIGN="center">7</TD>
    -+  <TD><A HREF="android.support.v4.app.ActivityCompat.html">
    -+android.support.v4.app.ActivityCompat</A></TD>
    -+</TR>
    -+<TR>
    -+  <TD ALIGN="center">6</TD>
    -+  <TD><A HREF="android.support.v4.app.SharedElementCallback.html">
    -+android.support.v4.app.SharedElementCallback</A></TD>
    -+</TR>
    -+<TR>
    -+  <TD ALIGN="center">6</TD>
    -+  <TD><A HREF="android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.CollectionItemInfoCompat.html">
    -+android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.CollectionItemInfoCompat</A></TD>
    -+</TR>
    -+<TR>
    -+  <TD ALIGN="center">6</TD>
    -+  <TD><A HREF="android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.RangeInfoCompat.html">
    -+android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.RangeInfoCompat</A></TD>
    -+</TR>
    -+<TR>
    -+  <TD ALIGN="center">6</TD>
    -+  <TD><A HREF="android.support.v4.view.accessibility.AccessibilityNodeProviderCompat.html">
    -+android.support.v4.view.accessibility.AccessibilityNodeProviderCompat</A></TD>
    -+</TR>
    -+<TR>
    -+  <TD ALIGN="center">6</TD>
    -+  <TD><A HREF="android.support.v4.widget.SearchViewCompat.html">
    -+android.support.v4.widget.SearchViewCompat</A></TD>
    -+</TR>
    -+<TR>
    -+  <TD ALIGN="center">6</TD>
    -+  <TD><A HREF="android.support.v7.app.ActionBarDrawerToggle.html">
    -+android.support.v7.app.ActionBarDrawerToggle</A></TD>
    -+</TR>
    -+<TR>
    -+  <TD ALIGN="center">5</TD>
    -+  <TD><A HREF="android.support.customtabs.CustomTabsIntent.html">
    -+android.support.customtabs.CustomTabsIntent</A></TD>
    -+</TR>
    -+<TR>
    -+  <TD ALIGN="center">4</TD>
    -+  <TD><A HREF="android.support.v4.accessibilityservice.AccessibilityServiceInfoCompat.html">
    -+android.support.v4.accessibilityservice.AccessibilityServiceInfoCompat</A></TD>
    -+</TR>
    -+<TR>
    -+  <TD ALIGN="center">4</TD>
    -+  <TD><A HREF="android.support.v4.view.MotionEventCompat.html">
    -+android.support.v4.view.MotionEventCompat</A></TD>
    -+</TR>
    -+<TR>
    -+  <TD ALIGN="center">4</TD>
    -+  <TD><A HREF="android.support.v7.graphics.Palette.html">
    -+android.support.v7.graphics.Palette</A></TD>
    -+</TR>
    -+<TR>
    -+  <TD ALIGN="center">4</TD>
    -+  <TD><A HREF="android.support.v7.widget.StaggeredGridLayoutManager.html">
    -+android.support.v7.widget.StaggeredGridLayoutManager</A></TD>
    -+</TR>
    -+<TR>
    -+  <TD ALIGN="center">3</TD>
    -+  <TD><A HREF="android.support.v4.media.session.MediaSessionCompat.html">
    -+android.support.v4.media.session.MediaSessionCompat</A></TD>
    -+</TR>
    -+<TR>
    -+  <TD ALIGN="center">3</TD>
    -+  <TD><A HREF="android.support.v4.content.ContextCompat.html">
    -+android.support.v4.content.ContextCompat</A></TD>
    -+</TR>
    -+<TR>
    -+  <TD ALIGN="center">3</TD>
    -+  <TD><A HREF="android.support.customtabs.CustomTabsIntent.Builder.html">
    -+android.support.customtabs.CustomTabsIntent.Builder</A></TD>
    -+</TR>
    -+<TR>
    -+  <TD ALIGN="center">2</TD>
    -+  <TD><A HREF="android.support.design.widget.BottomSheetBehavior.html">
    -+android.support.design.widget.BottomSheetBehavior</A></TD>
    -+</TR>
    -+<TR>
    -+  <TD ALIGN="center">2</TD>
    -+  <TD><A HREF="android.support.design.widget.CoordinatorLayout.html">
    -+android.support.design.widget.CoordinatorLayout</A></TD>
    -+</TR>
    -+<TR>
    -+  <TD ALIGN="center">2</TD>
    -+  <TD><A HREF="android.support.v4.graphics.drawable.DrawableCompat.html">
    -+android.support.v4.graphics.drawable.DrawableCompat</A></TD>
    -+</TR>
    -+<TR>
    -+  <TD ALIGN="center">2</TD>
    -+  <TD><A HREF="android.support.v4.view.WindowInsetsCompat.html">
    -+android.support.v4.view.WindowInsetsCompat</A></TD>
    -+</TR>
    -+<TR>
    -+  <TD ALIGN="center">2</TD>
    -+  <TD><A HREF="android.support.v14.preference.PreferenceFragment.html">
    -+android.support.v14.preference.PreferenceFragment</A></TD>
    -+</TR>
    -+<TR>
    -+  <TD ALIGN="center">2</TD>
    -+  <TD><A HREF="android.support.v4.view.accessibility.AccessibilityWindowInfoCompat.html">
    -+android.support.v4.view.accessibility.AccessibilityWindowInfoCompat</A></TD>
    -+</TR>
    -+<TR>
    -+  <TD ALIGN="center">2</TD>
    -+  <TD><A HREF="android.support.v4.view.ViewCompat.html">
    -+android.support.v4.view.ViewCompat</A></TD>
    -+</TR>
    -+<TR>
    -+  <TD ALIGN="center">2</TD>
    -+  <TD><A HREF="android.support.design.widget.CollapsingToolbarLayout.html">
    -+android.support.design.widget.CollapsingToolbarLayout</A></TD>
    -+</TR>
    -+<TR>
    -+  <TD ALIGN="center">2</TD>
    -+  <TD><A HREF="android.support.v17.leanback.widget.ObjectAdapter.html">
    -+android.support.v17.leanback.widget.ObjectAdapter</A></TD>
    -+</TR>
    -+<TR>
    -+  <TD ALIGN="center">2</TD>
    -+  <TD><A HREF="android.support.v4.media.MediaMetadataCompat.html">
    -+android.support.v4.media.MediaMetadataCompat</A></TD>
    -+</TR>
    -+<TR>
    -+  <TD ALIGN="center">2</TD>
    -+  <TD><A HREF="android.support.v7.widget.LinearSmoothScroller.html">
    -+android.support.v7.widget.LinearSmoothScroller</A></TD>
    -+</TR>
    -+<TR>
    -+  <TD ALIGN="center">2</TD>
    -+  <TD><A HREF="android.support.v4.widget.SwipeRefreshLayout.html">
    -+android.support.v4.widget.SwipeRefreshLayout</A></TD>
    -+</TR>
    -+<TR>
    -+  <TD ALIGN="center">1</TD>
    -+  <TD><A HREF="android.support.v7.widget.LinearLayoutManager.html">
    -+android.support.v7.widget.LinearLayoutManager</A></TD>
    -+</TR>
    -+<TR>
    -+  <TD ALIGN="center">1</TD>
    -+  <TD><A HREF="android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.html">
    -+android.support.v4.view.accessibility.AccessibilityNodeInfoCompat</A></TD>
    -+</TR>
    -+<TR>
    -+  <TD ALIGN="center">1</TD>
    -+  <TD><A HREF="android.support.design.widget.TabLayout.html">
    -+android.support.design.widget.TabLayout</A></TD>
    -+</TR>
    -+<TR>
    -+  <TD ALIGN="center">1</TD>
    -+  <TD><A HREF="android.support.v4.app.FragmentController.html">
    -+android.support.v4.app.FragmentController</A></TD>
    -+</TR>
    -+<TR>
    -+  <TD ALIGN="center">1</TD>
    -+  <TD><A HREF="android.support.v7.app.AppCompatDelegate.html">
    -+android.support.v7.app.AppCompatDelegate</A></TD>
    -+</TR>
    -+<TR>
    -+  <TD ALIGN="center">1</TD>
    -+  <TD><A HREF="android.support.v7.widget.RecyclerView.html">
    -+android.support.v7.widget.RecyclerView</A></TD>
    -+</TR>
    -+<TR>
    -+  <TD ALIGN="center">1</TD>
    -+  <TD><A HREF="android.support.v4.media.session.PlaybackStateCompat.html">
    -+android.support.v4.media.session.PlaybackStateCompat</A></TD>
    -+</TR>
    -+</TABLE>
    -+<p style="font-size:10px">* See <a href="#calculation">Calculation of Change Percentages</a>, below.</p>
    -+<br>
    -+<h2 id="calculation">Calculation of Change Percentages</h2>
    -+<p>
    -+The percent change statistic reported for all elements in the &quot;to&quot; API Level specification is defined recursively as follows:</p>
    -+<pre>
    -+Percentage difference = 100 * (added + removed + 2*changed)
    -+                        -----------------------------------
    -+                        sum of public elements in BOTH APIs
    -+</pre>
    -+<p>where <code>added</code> is the number of packages added, <code>removed</code> is the number of packages removed, and <code>changed</code> is the number of packages changed.
    -+This definition is applied recursively for the classes and their program elements, so the value for a changed package will be less than 1, unless every class in that package has changed.
    -+The definition ensures that if all packages are removed and all new packages are
    -+added, the change will be 100%.</p>
    -+      </div>	
    -+      <div id="footer">
    -+        <div id="copyright">
    -+        Except as noted, this content is licensed under 
    -+        <a href="http://creativecommons.org/licenses/by/2.5/"> Creative Commons Attribution 2.5</a>.
    -+        For details and restrictions, see the <a href="/license.html">Content License</a>.
    -+        </div>
    -+      <div id="footerlinks">
    -+      <p>
    -+        <a href="http://www.android.com/terms.html">Site Terms of Service</a> -
    -+        <a href="http://www.android.com/privacy.html">Privacy Policy</a> -
    -+        <a href="http://www.android.com/branding.html">Brand Guidelines</a>
    -+      </p>
    -+    </div>
    -+    </div> <!-- end footer -->
    -+    </div><!-- end doc-content -->
    -+    </div> <!-- end body-content --> 
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    -+</script>
    -+<script type="text/javascript">
    -+  try {
    -+    var pageTracker = _gat._getTracker("UA-5831155-1");
    -+    pageTracker._setAllowAnchor(true);
    -+    pageTracker._initData();
    -+    pageTracker._trackPageview();
    -+  } catch(e) {}
    -+</script>
    -+</BODY></HTML>
    -diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/jdiff_topleftframe.html b/docs/html/sdk/support_api_diff/24.2.0/changes/jdiff_topleftframe.html
    -new file mode 100644
    -index 0000000..6a2e76e
    ---- /dev/null
    -+++ b/docs/html/sdk/support_api_diff/24.2.0/changes/jdiff_topleftframe.html
    -@@ -0,0 +1,63 @@
    -+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
    -+<HTML style="overflow:auto;">
    -+<HEAD>
    -+<meta name="generator" content="JDiff v1.1.0">
    -+<!-- Generated by the JDiff Javadoc doclet -->
    -+<!-- (http://www.jdiff.org) -->
    -+<meta name="description" content="JDiff is a Javadoc doclet which generates an HTML report of all the packages, classes, constructors, methods, and fields which have been removed, added or changed in any way, including their documentation, when two APIs are compared.">
    -+<meta name="keywords" content="diff, jdiff, javadiff, java diff, java difference, API difference, difference between two APIs, API diff, Javadoc, doclet">
    -+<TITLE>
    -+Android API Version Differences
    -+</TITLE>
    -+<link href="../../../../assets/android-developer-docs.css" rel="stylesheet" type="text/css" />
    -+<link href="../stylesheet-jdiff.css" rel="stylesheet" type="text/css" />
    -+<noscript>
    -+<style type="text/css">
    -+body{overflow:auto;}
    -+#body-content{position:relative; top:0;}
    -+#doc-content{overflow:visible;border-left:3px solid #666;}
    -+#side-nav{padding:0;}
    -+#side-nav .toggle-list ul {display:block;}
    -+#resize-packages-nav{border-bottom:3px solid #666;}
    -+</style>
    -+</noscript>
    -+<style type="text/css">
    -+</style>
    -+</HEAD>
    -+<BODY class="gc-documentation" style="padding:12px;">
    -+<table class="jdiffIndex" summary="Links to diff index files" BORDER="0" WIDTH="100%" cellspacing="0" cellpadding="0" style="margin:0">
    -+<TR>
    -+  <th class="indexHeader" nowrap>
    -+  Select a Diffs Index:</th>
    -+</TR>
    -+<TR>
    -+  <TD><FONT CLASS="indexText" size="-2"><A HREF="alldiffs_index_all.html" TARGET="bottomleftframe">All Differences</A></FONT><br></TD>
    -+</TR>
    -+<TR>
    -+  <TD NOWRAP><FONT CLASS="indexText" size="-2"><A HREF="packages_index_all.html" TARGET="bottomleftframe">By Package</A></FONT><br></TD>
    -+</TR>
    -+<TR>
    -+  <TD NOWRAP><FONT CLASS="indexText" size="-2"><A HREF="classes_index_all.html" TARGET="bottomleftframe">By Class</A></FONT><br></TD>
    -+</TR>
    -+<TR>
    -+  <TD NOWRAP><FONT CLASS="indexText" size="-2"><A HREF="constructors_index_all.html" TARGET="bottomleftframe">By Constructor</A></FONT><br></TD>
    -+</TR>
    -+<TR>
    -+  <TD NOWRAP><FONT CLASS="indexText" size="-2"><A HREF="methods_index_all.html" TARGET="bottomleftframe">By Method</A></FONT><br></TD>
    -+</TR>
    -+<TR>
    -+  <TD NOWRAP><FONT CLASS="indexText" size="-2"><A HREF="fields_index_all.html" TARGET="bottomleftframe">By Field</A></FONT><br></TD>
    -+</TR>
    -+</TABLE>
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    -+</script>
    -+<script type="text/javascript">
    -+  try {
    -+    var pageTracker = _gat._getTracker("UA-5831155-1");
    -+    pageTracker._setAllowAnchor(true);
    -+    pageTracker._initData();
    -+    pageTracker._trackPageview();
    -+  } catch(e) {}
    -+</script>
    -+</BODY>
    -+</HTML>
    -diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/methods_index_additions.html b/docs/html/sdk/support_api_diff/24.2.0/changes/methods_index_additions.html
    -new file mode 100644
    -index 0000000..419a607
    ---- /dev/null
    -+++ b/docs/html/sdk/support_api_diff/24.2.0/changes/methods_index_additions.html
    -@@ -0,0 +1,448 @@
    -+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
    -+<HTML style="overflow:auto;">
    -+<HEAD>
    -+<meta name="generator" content="JDiff v1.1.0">
    -+<!-- Generated by the JDiff Javadoc doclet -->
    -+<!-- (http://www.jdiff.org) -->
    -+<meta name="description" content="JDiff is a Javadoc doclet which generates an HTML report of all the packages, classes, constructors, methods, and fields which have been removed, added or changed in any way, including their documentation, when two APIs are compared.">
    -+<meta name="keywords" content="diff, jdiff, javadiff, java diff, java difference, API difference, difference between two APIs, API diff, Javadoc, doclet">
    -+<TITLE>
    -+Method Additions Index
    -+</TITLE>
    -+<link href="../../../../assets/android-developer-docs.css" rel="stylesheet" type="text/css" />
    -+<link href="../stylesheet-jdiff.css" rel="stylesheet" type="text/css" />
    -+<noscript>
    -+<style type="text/css">
    -+body{overflow:auto;}
    -+#body-content{position:relative; top:0;}
    -+#doc-content{overflow:visible;border-left:3px solid #666;}
    -+#side-nav{padding:0;}
    -+#side-nav .toggle-list ul {display:block;}
    -+#resize-packages-nav{border-bottom:3px solid #666;}
    -+</style>
    -+</noscript>
    -+<style type="text/css">
    -+</style>
    -+</HEAD>
    -+<BODY class="gc-documentation" style="padding:12px;">
    -+<a NAME="topheader"></a>
    -+<table summary="Index for Methods" width="100%" class="jdiffIndex" border="0" cellspacing="0" cellpadding="0" style="padding-bottom:0;margin-bottom:0;">
    -+  <tr>
    -+  <th class="indexHeader">
    -+    Filter the Index:
    -+  </th>
    -+  </tr>
    -+  <tr>
    -+  <td class="indexText" style="line-height:1.3em;padding-left:2em;">
    -+<a href="methods_index_all.html" class="staysblack">All Methods</a>
    -+  <br>
    -+<A HREF="methods_index_removals.html" xclass="hiddenlink">Removals</A>
    -+  <br>
    -+<b>Additions</b>
    -+  <br>
    -+<A HREF="methods_index_changes.html"xclass="hiddenlink">Changes</A>
    -+  </td>
    -+  </tr>
    -+</table>
    -+<div id="indexTableCaption" style="background-color:#eee;padding:0 4px 0 4px;font-size:11px;margin-bottom:1em;">
    -+Listed as: <span style="color:#069"><strong>Added</strong></span>,  <span style="color:#069"><strike>Removed</strike></span>,  <span style="color:#069">Changed</span></font>
    -+</div>
    -+<A NAME="A"></A>
    -+<br><font size="+2">A</font>&nbsp;
    -+<a href="#B"><font size="-2">B</font></a> 
    -+<a href="#C"><font size="-2">C</font></a> 
    -+<a href="#F"><font size="-2">F</font></a> 
    -+<a href="#G"><font size="-2">G</font></a> 
    -+<a href="#I"><font size="-2">I</font></a> 
    -+<a href="#L"><font size="-2">L</font></a> 
    -+<a href="#M"><font size="-2">M</font></a> 
    -+<a href="#N"><font size="-2">N</font></a> 
    -+<a href="#O"><font size="-2">O</font></a> 
    -+<a href="#R"><font size="-2">R</font></a> 
    -+<a href="#S"><font size="-2">S</font></a> 
    -+<a href="#T"><font size="-2">T</font></a> 
    -+ <a href="#topheader"><font size="-2">TOP</font></a>
    -+<p><div style="line-height:1.5em;color:black">
    -+<nobr><A HREF="android.support.v4.view.accessibility.AccessibilityManagerCompat.html#android.support.v4.view.accessibility.AccessibilityManagerCompat.addTouchExplorationStateChangeListener_added(android.view.accessibility.AccessibilityManager, android.support.v4.view.accessibility.AccessibilityManagerCompat.TouchExplorationStateChangeListener)" class="hiddenlink" target="rightframe"><b>addTouchExplorationStateChangeListener</b>
    -+(<code>AccessibilityManager, TouchExplorationStateChangeListener</code>)</A></nobr><br>
    -+<A NAME="B"></A>
    -+<br><font size="+2">B</font>&nbsp;
    -+<a href="#A"><font size="-2">A</font></a> 
    -+<a href="#C"><font size="-2">C</font></a> 
    -+<a href="#F"><font size="-2">F</font></a> 
    -+<a href="#G"><font size="-2">G</font></a> 
    -+<a href="#I"><font size="-2">I</font></a> 
    -+<a href="#L"><font size="-2">L</font></a> 
    -+<a href="#M"><font size="-2">M</font></a> 
    -+<a href="#N"><font size="-2">N</font></a> 
    -+<a href="#O"><font size="-2">O</font></a> 
    -+<a href="#R"><font size="-2">R</font></a> 
    -+<a href="#S"><font size="-2">S</font></a> 
    -+<a href="#T"><font size="-2">T</font></a> 
    -+ <a href="#topheader"><font size="-2">TOP</font></a>
    -+<p><div style="line-height:1.5em;color:black">
    -+<i>buildMediaButtonPendingIntent</i><br>
    -+&nbsp;&nbsp;<nobr><A HREF="android.support.v4.media.session.MediaButtonReceiver.html#android.support.v4.media.session.MediaButtonReceiver.buildMediaButtonPendingIntent_added(android.content.Context, android.content.ComponentName, long)" class="hiddenlink" target="rightframe">type&nbsp;<b>
    -+(<code>Context, ComponentName, long</code>)</b>&nbsp;in&nbsp;android.support.v4.media.session.MediaButtonReceiver
    -+</A></nobr><br>
    -+&nbsp;&nbsp;<nobr><A HREF="android.support.v4.media.session.MediaButtonReceiver.html#android.support.v4.media.session.MediaButtonReceiver.buildMediaButtonPendingIntent_added(android.content.Context, long)" class="hiddenlink" target="rightframe">type&nbsp;<b>
    -+(<code>Context, long</code>)</b>&nbsp;in&nbsp;android.support.v4.media.session.MediaButtonReceiver
    -+</A></nobr><br>
    -+<A NAME="C"></A>
    -+<br><font size="+2">C</font>&nbsp;
    -+<a href="#A"><font size="-2">A</font></a> 
    -+<a href="#B"><font size="-2">B</font></a> 
    -+<a href="#F"><font size="-2">F</font></a> 
    -+<a href="#G"><font size="-2">G</font></a> 
    -+<a href="#I"><font size="-2">I</font></a> 
    -+<a href="#L"><font size="-2">L</font></a> 
    -+<a href="#M"><font size="-2">M</font></a> 
    -+<a href="#N"><font size="-2">N</font></a> 
    -+<a href="#O"><font size="-2">O</font></a> 
    -+<a href="#R"><font size="-2">R</font></a> 
    -+<a href="#S"><font size="-2">S</font></a> 
    -+<a href="#T"><font size="-2">T</font></a> 
    -+ <a href="#topheader"><font size="-2">TOP</font></a>
    -+<p><div style="line-height:1.5em;color:black">
    -+<nobr><A HREF="android.support.v4.graphics.drawable.DrawableCompat.html#android.support.v4.graphics.drawable.DrawableCompat.clearColorFilter_added(android.graphics.drawable.Drawable)" class="hiddenlink" target="rightframe"><b>clearColorFilter</b>
    -+(<code>Drawable</code>)</A></nobr><br>
    -+<nobr><A HREF="android.support.design.widget.TabLayout.html#android.support.design.widget.TabLayout.clearOnTabSelectedListeners_added()" class="hiddenlink" target="rightframe"><b>clearOnTabSelectedListeners</b>
    -+()</A></nobr><br>
    -+<nobr><A HREF="android.support.v7.widget.StaggeredGridLayoutManager.html#android.support.v7.widget.StaggeredGridLayoutManager.computeScrollVectorForPosition_added(int)" class="hiddenlink" target="rightframe"><b>computeScrollVectorForPosition</b>
    -+(<code>int</code>)</A></nobr><br>
    -+<A NAME="F"></A>
    -+<br><font size="+2">F</font>&nbsp;
    -+<a href="#A"><font size="-2">A</font></a> 
    -+<a href="#B"><font size="-2">B</font></a> 
    -+<a href="#C"><font size="-2">C</font></a> 
    -+<a href="#G"><font size="-2">G</font></a> 
    -+<a href="#I"><font size="-2">I</font></a> 
    -+<a href="#L"><font size="-2">L</font></a> 
    -+<a href="#M"><font size="-2">M</font></a> 
    -+<a href="#N"><font size="-2">N</font></a> 
    -+<a href="#O"><font size="-2">O</font></a> 
    -+<a href="#R"><font size="-2">R</font></a> 
    -+<a href="#S"><font size="-2">S</font></a> 
    -+<a href="#T"><font size="-2">T</font></a> 
    -+ <a href="#topheader"><font size="-2">TOP</font></a>
    -+<p><div style="line-height:1.5em;color:black">
    -+<nobr><A HREF="android.support.v4.app.FragmentController.html#android.support.v4.app.FragmentController.findFragmentByWho_added(java.lang.String)" class="hiddenlink" target="rightframe"><b>findFragmentByWho</b>
    -+(<code>String</code>)</A></nobr><br>
    -+<nobr><A HREF="android.support.v4.media.MediaBrowserCompat.MediaItem.html#android.support.v4.media.MediaBrowserCompat.MediaItem.fromMediaItem_added(java.lang.Object)" class="hiddenlink" target="rightframe"><b>fromMediaItem</b>
    -+(<code>Object</code>)</A></nobr><br>
    -+<nobr><A HREF="android.support.v4.media.MediaBrowserCompat.MediaItem.html#android.support.v4.media.MediaBrowserCompat.MediaItem.fromMediaItemList_added(java.util.List<?>)" class="hiddenlink" target="rightframe"><b>fromMediaItemList</b>
    -+(<code>List&lt;?&gt;</code>)</A></nobr><br>
    -+<nobr><A HREF="android.support.v4.media.session.MediaSessionCompat.html#android.support.v4.media.session.MediaSessionCompat.fromMediaSession_added(android.content.Context, java.lang.Object)" class="hiddenlink" target="rightframe"><b>fromMediaSession</b>
    -+(<code>Context, Object</code>)</A></nobr><br>
    -+<nobr><A HREF="android.support.v4.media.session.MediaSessionCompat.QueueItem.html#android.support.v4.media.session.MediaSessionCompat.QueueItem.fromQueueItem_added(java.lang.Object)" class="hiddenlink" target="rightframe"><b>fromQueueItem</b>
    -+(<code>Object</code>)</A></nobr><br>
    -+<nobr><A HREF="android.support.v4.media.session.MediaSessionCompat.QueueItem.html#android.support.v4.media.session.MediaSessionCompat.QueueItem.fromQueueItemList_added(java.util.List<?>)" class="hiddenlink" target="rightframe"><b>fromQueueItemList</b>
    -+(<code>List&lt;?&gt;</code>)</A></nobr><br>
    -+<A NAME="G"></A>
    -+<br><font size="+2">G</font>&nbsp;
    -+<a href="#A"><font size="-2">A</font></a> 
    -+<a href="#B"><font size="-2">B</font></a> 
    -+<a href="#C"><font size="-2">C</font></a> 
    -+<a href="#F"><font size="-2">F</font></a> 
    -+<a href="#I"><font size="-2">I</font></a> 
    -+<a href="#L"><font size="-2">L</font></a> 
    -+<a href="#M"><font size="-2">M</font></a> 
    -+<a href="#N"><font size="-2">N</font></a> 
    -+<a href="#O"><font size="-2">O</font></a> 
    -+<a href="#R"><font size="-2">R</font></a> 
    -+<a href="#S"><font size="-2">S</font></a> 
    -+<a href="#T"><font size="-2">T</font></a> 
    -+ <a href="#topheader"><font size="-2">TOP</font></a>
    -+<p><div style="line-height:1.5em;color:black">
    -+<nobr><A HREF="android.support.v4.view.accessibility.AccessibilityEventCompat.html#android.support.v4.view.accessibility.AccessibilityEventCompat.getAction_added(android.view.accessibility.AccessibilityEvent)" class="hiddenlink" target="rightframe"><b>getAction</b>
    -+(<code>AccessibilityEvent</code>)</A></nobr><br>
    -+<nobr><A HREF="android.support.v4.widget.TextViewCompat.html#android.support.v4.widget.TextViewCompat.getCompoundDrawablesRelative_added(android.widget.TextView)" class="hiddenlink" target="rightframe"><b>getCompoundDrawablesRelative</b>
    -+(<code>TextView</code>)</A></nobr><br>
    -+<nobr><A HREF="android.support.design.widget.CoordinatorLayout.html#android.support.design.widget.CoordinatorLayout.getDependents_added(android.view.View)" class="hiddenlink" target="rightframe"><b>getDependents</b>
    -+(<code>View</code>)</A></nobr><br>
    -+<nobr><A HREF="android.support.v7.graphics.Palette.html#android.support.v7.graphics.Palette.getDominantColor_added(int)" class="hiddenlink" target="rightframe"><b>getDominantColor</b>
    -+(<code>int</code>)</A></nobr><br>
    -+<nobr><A HREF="android.support.v7.graphics.Palette.html#android.support.v7.graphics.Palette.getDominantSwatch_added()" class="hiddenlink" target="rightframe"><b>getDominantSwatch</b>
    -+()</A></nobr><br>
    -+<nobr><A HREF="android.support.v7.content.res.AppCompatResources.html#android.support.v7.content.res.AppCompatResources.getDrawable_added(android.content.Context, int)" class="hiddenlink" target="rightframe"><b>getDrawable</b>
    -+(<code>Context, int</code>)</A></nobr><br>
    -+<nobr><A HREF="android.support.v7.app.ActionBarDrawerToggle.html#android.support.v7.app.ActionBarDrawerToggle.getDrawerArrowDrawable_added()" class="hiddenlink" target="rightframe"><b>getDrawerArrowDrawable</b>
    -+()</A></nobr><br>
    -+<i>getInsetDodgeRect</i><br>
    -+&nbsp;&nbsp;<nobr><A HREF="android.support.design.widget.CoordinatorLayout.Behavior.html#android.support.design.widget.CoordinatorLayout.Behavior.getInsetDodgeRect_added(android.support.design.widget.CoordinatorLayout, V, android.graphics.Rect)" class="hiddenlink" target="rightframe">type&nbsp;<b>
    -+(<code>CoordinatorLayout, V, Rect</code>)</b>&nbsp;in&nbsp;android.support.design.widget.CoordinatorLayout.Behavior
    -+</A></nobr><br>
    -+&nbsp;&nbsp;<nobr><A HREF="android.support.design.widget.FloatingActionButton.Behavior.html#android.support.design.widget.FloatingActionButton.Behavior.getInsetDodgeRect_added(android.support.design.widget.CoordinatorLayout, android.support.design.widget.FloatingActionButton, android.graphics.Rect)" class="hiddenlink" target="rightframe">type&nbsp;<b>
    -+(<code>CoordinatorLayout, FloatingActionButton, Rect</code>)</b>&nbsp;in&nbsp;android.support.design.widget.FloatingActionButton.Behavior
    -+</A></nobr><br>
    -+<nobr><A HREF="android.support.v4.app.ActivityOptionsCompat.html#android.support.v4.app.ActivityOptionsCompat.getLaunchBounds_added()" class="hiddenlink" target="rightframe"><b>getLaunchBounds</b>
    -+()</A></nobr><br>
    -+<nobr><A HREF="android.support.v17.leanback.widget.AbstractMediaItemPresenter.ViewHolder.html#android.support.v17.leanback.widget.AbstractMediaItemPresenter.ViewHolder.getMediaItemNumberViewFlipper_added()" class="hiddenlink" target="rightframe"><b>getMediaItemNumberViewFlipper</b>
    -+()</A></nobr><br>
    -+<nobr><A HREF="android.support.v17.leanback.widget.AbstractMediaItemPresenter.ViewHolder.html#android.support.v17.leanback.widget.AbstractMediaItemPresenter.ViewHolder.getMediaItemPausedView_added()" class="hiddenlink" target="rightframe"><b>getMediaItemPausedView</b>
    -+()</A></nobr><br>
    -+<nobr><A HREF="android.support.v17.leanback.widget.AbstractMediaItemPresenter.ViewHolder.html#android.support.v17.leanback.widget.AbstractMediaItemPresenter.ViewHolder.getMediaItemPlayingView_added()" class="hiddenlink" target="rightframe"><b>getMediaItemPlayingView</b>
    -+()</A></nobr><br>
    -+<nobr><A HREF="android.support.v17.leanback.widget.AbstractMediaItemPresenter.html#android.support.v17.leanback.widget.AbstractMediaItemPresenter.getMediaPlayState_added(java.lang.Object)" class="hiddenlink" target="rightframe"><b>getMediaPlayState</b>
    -+(<code>Object</code>)</A></nobr><br>
    -+<nobr><A HREF="android.support.v4.view.accessibility.AccessibilityEventCompat.html#android.support.v4.view.accessibility.AccessibilityEventCompat.getMovementGranularity_added(android.view.accessibility.AccessibilityEvent)" class="hiddenlink" target="rightframe"><b>getMovementGranularity</b>
    -+(<code>AccessibilityEvent</code>)</A></nobr><br>
    -+<nobr><A HREF="android.support.v7.widget.RecyclerView.html#android.support.v7.widget.RecyclerView.getOnFlingListener_added()" class="hiddenlink" target="rightframe"><b>getOnFlingListener</b>
    -+()</A></nobr><br>
    -+<nobr><A HREF="android.support.design.widget.TextInputLayout.html#android.support.design.widget.TextInputLayout.getPasswordVisibilityToggleContentDescription_added()" class="hiddenlink" target="rightframe"><b>getPasswordVisibilityToggleContentDescription</b>
    -+()</A></nobr><br>
    -+<nobr><A HREF="android.support.design.widget.TextInputLayout.html#android.support.design.widget.TextInputLayout.getPasswordVisibilityToggleDrawable_added()" class="hiddenlink" target="rightframe"><b>getPasswordVisibilityToggleDrawable</b>
    -+()</A></nobr><br>
    -+<nobr><A HREF="android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.CollectionInfoCompat.html#android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.CollectionInfoCompat.getSelectionMode_added()" class="hiddenlink" target="rightframe"><b>getSelectionMode</b>
    -+()</A></nobr><br>
    -+<A NAME="I"></A>
    -+<br><font size="+2">I</font>&nbsp;
    -+<a href="#A"><font size="-2">A</font></a> 
    -+<a href="#B"><font size="-2">B</font></a> 
    -+<a href="#C"><font size="-2">C</font></a> 
    -+<a href="#F"><font size="-2">F</font></a> 
    -+<a href="#G"><font size="-2">G</font></a> 
    -+<a href="#L"><font size="-2">L</font></a> 
    -+<a href="#M"><font size="-2">M</font></a> 
    -+<a href="#N"><font size="-2">N</font></a> 
    -+<a href="#O"><font size="-2">O</font></a> 
    -+<a href="#R"><font size="-2">R</font></a> 
    -+<a href="#S"><font size="-2">S</font></a> 
    -+<a href="#T"><font size="-2">T</font></a> 
    -+ <a href="#topheader"><font size="-2">TOP</font></a>
    -+<p><div style="line-height:1.5em;color:black">
    -+<nobr><A HREF="android.support.v4.os.BuildCompat.html#android.support.v4.os.BuildCompat.isAtLeastNMR1_added()" class="hiddenlink" target="rightframe"><b>isAtLeastNMR1</b>
    -+()</A></nobr><br>
    -+<nobr><A HREF="android.support.design.widget.FloatingActionButton.Behavior.html#android.support.design.widget.FloatingActionButton.Behavior.isAutoHideEnabled_added()" class="hiddenlink" target="rightframe"><b>isAutoHideEnabled</b>
    -+()</A></nobr><br>
    -+<nobr><A HREF="android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.html#android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.isContextClickable_added()" class="hiddenlink" target="rightframe"><b>isContextClickable</b>
    -+()</A></nobr><br>
    -+<nobr><A HREF="android.support.v17.leanback.widget.ObjectAdapter.html#android.support.v17.leanback.widget.ObjectAdapter.isImmediateNotifySupported_added()" class="hiddenlink" target="rightframe"><b>isImmediateNotifySupported</b>
    -+()</A></nobr><br>
    -+<nobr><A HREF="android.support.v4.view.ViewCompat.html#android.support.v4.view.ViewCompat.isImportantForAccessibility_added(android.view.View)" class="hiddenlink" target="rightframe"><b>isImportantForAccessibility</b>
    -+(<code>View</code>)</A></nobr><br>
    -+<nobr><A HREF="android.support.design.widget.TextInputLayout.html#android.support.design.widget.TextInputLayout.isPasswordVisibilityToggleEnabled_added()" class="hiddenlink" target="rightframe"><b>isPasswordVisibilityToggleEnabled</b>
    -+()</A></nobr><br>
    -+<A NAME="L"></A>
    -+<br><font size="+2">L</font>&nbsp;
    -+<a href="#A"><font size="-2">A</font></a> 
    -+<a href="#B"><font size="-2">B</font></a> 
    -+<a href="#C"><font size="-2">C</font></a> 
    -+<a href="#F"><font size="-2">F</font></a> 
    -+<a href="#G"><font size="-2">G</font></a> 
    -+<a href="#I"><font size="-2">I</font></a> 
    -+<a href="#M"><font size="-2">M</font></a> 
    -+<a href="#N"><font size="-2">N</font></a> 
    -+<a href="#O"><font size="-2">O</font></a> 
    -+<a href="#R"><font size="-2">R</font></a> 
    -+<a href="#S"><font size="-2">S</font></a> 
    -+<a href="#T"><font size="-2">T</font></a> 
    -+ <a href="#topheader"><font size="-2">TOP</font></a>
    -+<p><div style="line-height:1.5em;color:black">
    -+<nobr><A HREF="android.support.v4.accessibilityservice.AccessibilityServiceInfoCompat.html#android.support.v4.accessibilityservice.AccessibilityServiceInfoCompat.loadDescription_added(android.accessibilityservice.AccessibilityServiceInfo, android.content.pm.PackageManager)" class="hiddenlink" target="rightframe"><b>loadDescription</b>
    -+(<code>AccessibilityServiceInfo, PackageManager</code>)</A></nobr><br>
    -+<A NAME="M"></A>
    -+<br><font size="+2">M</font>&nbsp;
    -+<a href="#A"><font size="-2">A</font></a> 
    -+<a href="#B"><font size="-2">B</font></a> 
    -+<a href="#C"><font size="-2">C</font></a> 
    -+<a href="#F"><font size="-2">F</font></a> 
    -+<a href="#G"><font size="-2">G</font></a> 
    -+<a href="#I"><font size="-2">I</font></a> 
    -+<a href="#L"><font size="-2">L</font></a> 
    -+<a href="#N"><font size="-2">N</font></a> 
    -+<a href="#O"><font size="-2">O</font></a> 
    -+<a href="#R"><font size="-2">R</font></a> 
    -+<a href="#S"><font size="-2">S</font></a> 
    -+<a href="#T"><font size="-2">T</font></a> 
    -+ <a href="#topheader"><font size="-2">TOP</font></a>
    -+<p><div style="line-height:1.5em;color:black">
    -+<nobr><A HREF="android.support.v4.app.ActivityOptionsCompat.html#android.support.v4.app.ActivityOptionsCompat.makeBasic_added()" class="hiddenlink" target="rightframe"><b>makeBasic</b>
    -+()</A></nobr><br>
    -+<nobr><A HREF="android.support.v4.app.ActivityOptionsCompat.html#android.support.v4.app.ActivityOptionsCompat.makeClipRevealAnimation_added(android.view.View, int, int, int, int)" class="hiddenlink" target="rightframe"><b>makeClipRevealAnimation</b>
    -+(<code>View, int, int, int, int</code>)</A></nobr><br>
    -+<nobr><A HREF="android.support.v4.app.ActivityOptionsCompat.html#android.support.v4.app.ActivityOptionsCompat.makeTaskLaunchBehind_added()" class="hiddenlink" target="rightframe"><b>makeTaskLaunchBehind</b>
    -+()</A></nobr><br>
    -+<A NAME="N"></A>
    -+<br><font size="+2">N</font>&nbsp;
    -+<a href="#A"><font size="-2">A</font></a> 
    -+<a href="#B"><font size="-2">B</font></a> 
    -+<a href="#C"><font size="-2">C</font></a> 
    -+<a href="#F"><font size="-2">F</font></a> 
    -+<a href="#G"><font size="-2">G</font></a> 
    -+<a href="#I"><font size="-2">I</font></a> 
    -+<a href="#L"><font size="-2">L</font></a> 
    -+<a href="#M"><font size="-2">M</font></a> 
    -+<a href="#O"><font size="-2">O</font></a> 
    -+<a href="#R"><font size="-2">R</font></a> 
    -+<a href="#S"><font size="-2">S</font></a> 
    -+<a href="#T"><font size="-2">T</font></a> 
    -+ <a href="#topheader"><font size="-2">TOP</font></a>
    -+<p><div style="line-height:1.5em;color:black">
    -+<nobr><A HREF="android.support.v17.leanback.widget.AbstractMediaItemPresenter.ViewHolder.html#android.support.v17.leanback.widget.AbstractMediaItemPresenter.ViewHolder.notifyPlayStateChanged_added()" class="hiddenlink" target="rightframe"><b>notifyPlayStateChanged</b>
    -+()</A></nobr><br>
    -+<A NAME="O"></A>
    -+<br><font size="+2">O</font>&nbsp;
    -+<a href="#A"><font size="-2">A</font></a> 
    -+<a href="#B"><font size="-2">B</font></a> 
    -+<a href="#C"><font size="-2">C</font></a> 
    -+<a href="#F"><font size="-2">F</font></a> 
    -+<a href="#G"><font size="-2">G</font></a> 
    -+<a href="#I"><font size="-2">I</font></a> 
    -+<a href="#L"><font size="-2">L</font></a> 
    -+<a href="#M"><font size="-2">M</font></a> 
    -+<a href="#N"><font size="-2">N</font></a> 
    -+<a href="#R"><font size="-2">R</font></a> 
    -+<a href="#S"><font size="-2">S</font></a> 
    -+<a href="#T"><font size="-2">T</font></a> 
    -+ <a href="#topheader"><font size="-2">TOP</font></a>
    -+<p><div style="line-height:1.5em;color:black">
    -+<i>obtain</i><br>
    -+&nbsp;&nbsp;<nobr><A HREF="android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.CollectionInfoCompat.html#android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.CollectionInfoCompat.obtain_added(int, int, boolean)" class="hiddenlink" target="rightframe">type&nbsp;<b>
    -+(<code>int, int, boolean</code>)</b>&nbsp;in&nbsp;android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.CollectionInfoCompat
    -+</A></nobr><br>
    -+&nbsp;&nbsp;<nobr><A HREF="android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.CollectionItemInfoCompat.html#android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.CollectionItemInfoCompat.obtain_added(int, int, int, int, boolean)" class="hiddenlink" target="rightframe">type&nbsp;<b>
    -+(<code>int, int, int, int, boolean</code>)</b>&nbsp;in&nbsp;android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.CollectionItemInfoCompat
    -+</A></nobr><br>
    -+&nbsp;&nbsp;<nobr><A HREF="android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.RangeInfoCompat.html#android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.RangeInfoCompat.obtain_added(int, float, float, float)" class="hiddenlink" target="rightframe">type&nbsp;<b>
    -+(<code>int, float, float, float</code>)</b>&nbsp;in&nbsp;android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.RangeInfoCompat
    -+</A></nobr><br>
    -+<nobr><A HREF="android.support.design.widget.CoordinatorLayout.Behavior.html#android.support.design.widget.CoordinatorLayout.Behavior.onAttachedToLayoutParams_added(android.support.design.widget.CoordinatorLayout.LayoutParams)" class="hiddenlink" target="rightframe"><b>onAttachedToLayoutParams</b>
    -+(<code>LayoutParams</code>)</A></nobr><br>
    -+<nobr><A HREF="android.support.v17.leanback.widget.AbstractMediaItemPresenter.html#android.support.v17.leanback.widget.AbstractMediaItemPresenter.onBindMediaPlayState_added(android.support.v17.leanback.widget.AbstractMediaItemPresenter.ViewHolder)" class="hiddenlink" target="rightframe"><b>onBindMediaPlayState</b>
    -+(<code>ViewHolder</code>)</A></nobr><br>
    -+<nobr><A HREF="android.support.v7.util.SortedList.Callback.html#android.support.v7.util.SortedList.Callback.onChanged_added(int, int, java.lang.Object)" class="hiddenlink" target="rightframe"><b>onChanged</b>
    -+(<code>int, int, Object</code>)</A></nobr><br>
    -+<nobr><A HREF="android.support.design.widget.CoordinatorLayout.Behavior.html#android.support.design.widget.CoordinatorLayout.Behavior.onDetachedFromLayoutParams_added()" class="hiddenlink" target="rightframe"><b>onDetachedFromLayoutParams</b>
    -+()</A></nobr><br>
    -+<i>onRequestChildRectangleOnScreen</i><br>
    -+&nbsp;&nbsp;<nobr><A HREF="android.support.design.widget.AppBarLayout.ScrollingViewBehavior.html#android.support.design.widget.AppBarLayout.ScrollingViewBehavior.onRequestChildRectangleOnScreen_added(android.support.design.widget.CoordinatorLayout, android.view.View, android.graphics.Rect, boolean)" class="hiddenlink" target="rightframe">type&nbsp;<b>
    -+(<code>CoordinatorLayout, View, Rect, boolean</code>)</b>&nbsp;in&nbsp;android.support.design.widget.AppBarLayout.ScrollingViewBehavior
    -+</A></nobr><br>
    -+&nbsp;&nbsp;<nobr><A HREF="android.support.design.widget.CoordinatorLayout.Behavior.html#android.support.design.widget.CoordinatorLayout.Behavior.onRequestChildRectangleOnScreen_added(android.support.design.widget.CoordinatorLayout, V, android.graphics.Rect, boolean)" class="hiddenlink" target="rightframe">type&nbsp;<b>
    -+(<code>CoordinatorLayout, V, Rect, boolean</code>)</b>&nbsp;in&nbsp;android.support.design.widget.CoordinatorLayout.Behavior
    -+</A></nobr><br>
    -+<nobr><A HREF="android.support.v4.app.SharedElementCallback.html#android.support.v4.app.SharedElementCallback.onSharedElementsArrived_added(java.util.List<java.lang.String>, java.util.List<android.view.View>, android.support.v4.app.SharedElementCallback.OnSharedElementsReadyListener)" class="hiddenlink" target="rightframe"><b>onSharedElementsArrived</b>
    -+(<code>List&lt;String&gt;, List&lt;View&gt;, OnSharedElementsReadyListener</code>)</A></nobr><br>
    -+<nobr><A HREF="android.support.v7.app.AppCompatDelegate.html#android.support.v7.app.AppCompatDelegate.onStart_added()" class="hiddenlink" target="rightframe"><b>onStart</b>
    -+()</A></nobr><br>
    -+<nobr><A HREF="android.support.v17.leanback.widget.AbstractMediaItemPresenter.html#android.support.v17.leanback.widget.AbstractMediaItemPresenter.onUnbindMediaPlayState_added(android.support.v17.leanback.widget.AbstractMediaItemPresenter.ViewHolder)" class="hiddenlink" target="rightframe"><b>onUnbindMediaPlayState</b>
    -+(<code>ViewHolder</code>)</A></nobr><br>
    -+<A NAME="R"></A>
    -+<br><font size="+2">R</font>&nbsp;
    -+<a href="#A"><font size="-2">A</font></a> 
    -+<a href="#B"><font size="-2">B</font></a> 
    -+<a href="#C"><font size="-2">C</font></a> 
    -+<a href="#F"><font size="-2">F</font></a> 
    -+<a href="#G"><font size="-2">G</font></a> 
    -+<a href="#I"><font size="-2">I</font></a> 
    -+<a href="#L"><font size="-2">L</font></a> 
    -+<a href="#M"><font size="-2">M</font></a> 
    -+<a href="#N"><font size="-2">N</font></a> 
    -+<a href="#O"><font size="-2">O</font></a> 
    -+<a href="#S"><font size="-2">S</font></a> 
    -+<a href="#T"><font size="-2">T</font></a> 
    -+ <a href="#topheader"><font size="-2">TOP</font></a>
    -+<p><div style="line-height:1.5em;color:black">
    -+<nobr><A HREF="android.support.v4.view.accessibility.AccessibilityManagerCompat.html#android.support.v4.view.accessibility.AccessibilityManagerCompat.removeTouchExplorationStateChangeListener_added(android.view.accessibility.AccessibilityManager, android.support.v4.view.accessibility.AccessibilityManagerCompat.TouchExplorationStateChangeListener)" class="hiddenlink" target="rightframe"><b>removeTouchExplorationStateChangeListener</b>
    -+(<code>AccessibilityManager, TouchExplorationStateChangeListener</code>)</A></nobr><br>
    -+<nobr><A HREF="android.support.v4.app.ActivityOptionsCompat.html#android.support.v4.app.ActivityOptionsCompat.requestUsageTimeReport_added(android.app.PendingIntent)" class="hiddenlink" target="rightframe"><b>requestUsageTimeReport</b>
    -+(<code>PendingIntent</code>)</A></nobr><br>
    -+<A NAME="S"></A>
    -+<br><font size="+2">S</font>&nbsp;
    -+<a href="#A"><font size="-2">A</font></a> 
    -+<a href="#B"><font size="-2">B</font></a> 
    -+<a href="#C"><font size="-2">C</font></a> 
    -+<a href="#F"><font size="-2">F</font></a> 
    -+<a href="#G"><font size="-2">G</font></a> 
    -+<a href="#I"><font size="-2">I</font></a> 
    -+<a href="#L"><font size="-2">L</font></a> 
    -+<a href="#M"><font size="-2">M</font></a> 
    -+<a href="#N"><font size="-2">N</font></a> 
    -+<a href="#O"><font size="-2">O</font></a> 
    -+<a href="#R"><font size="-2">R</font></a> 
    -+<a href="#T"><font size="-2">T</font></a> 
    -+ <a href="#topheader"><font size="-2">TOP</font></a>
    -+<p><div style="line-height:1.5em;color:black">
    -+<nobr><A HREF="android.support.v4.view.accessibility.AccessibilityEventCompat.html#android.support.v4.view.accessibility.AccessibilityEventCompat.setAction_added(android.view.accessibility.AccessibilityEvent, int)" class="hiddenlink" target="rightframe"><b>setAction</b>
    -+(<code>AccessibilityEvent, int</code>)</A></nobr><br>
    -+<nobr><A HREF="android.support.customtabs.CustomTabsIntent.html#android.support.customtabs.CustomTabsIntent.setAlwaysUseBrowserUI_added(android.content.Intent)" class="hiddenlink" target="rightframe"><b>setAlwaysUseBrowserUI</b>
    -+(<code>Intent</code>)</A></nobr><br>
    -+<nobr><A HREF="android.support.design.widget.FloatingActionButton.Behavior.html#android.support.design.widget.FloatingActionButton.Behavior.setAutoHideEnabled_added(boolean)" class="hiddenlink" target="rightframe"><b>setAutoHideEnabled</b>
    -+(<code>boolean</code>)</A></nobr><br>
    -+<nobr><A HREF="android.support.design.widget.CollapsingToolbarLayout.html#android.support.design.widget.CollapsingToolbarLayout.setCollapsedTitleTextColor_added(android.content.res.ColorStateList)" class="hiddenlink" target="rightframe"><b>setCollapsedTitleTextColor</b>
    -+(<code>ColorStateList</code>)</A></nobr><br>
    -+<nobr><A HREF="android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.html#android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.setContextClickable_added(boolean)" class="hiddenlink" target="rightframe"><b>setContextClickable</b>
    -+(<code>boolean</code>)</A></nobr><br>
    -+<nobr><A HREF="android.support.v7.app.ActionBarDrawerToggle.html#android.support.v7.app.ActionBarDrawerToggle.setDrawerArrowDrawable_added(android.support.v7.graphics.drawable.DrawerArrowDrawable)" class="hiddenlink" target="rightframe"><b>setDrawerArrowDrawable</b>
    -+(<code>DrawerArrowDrawable</code>)</A></nobr><br>
    -+<nobr><A HREF="android.support.design.widget.CollapsingToolbarLayout.html#android.support.design.widget.CollapsingToolbarLayout.setExpandedTitleTextColor_added(android.content.res.ColorStateList)" class="hiddenlink" target="rightframe"><b>setExpandedTitleTextColor</b>
    -+(<code>ColorStateList</code>)</A></nobr><br>
    -+<nobr><A HREF="android.support.customtabs.CustomTabsIntent.Builder.html#android.support.customtabs.CustomTabsIntent.Builder.setInstantAppsEnabled_added(boolean)" class="hiddenlink" target="rightframe"><b>setInstantAppsEnabled</b>
    -+(<code>boolean</code>)</A></nobr><br>
    -+<nobr><A HREF="android.support.v4.app.ActivityOptionsCompat.html#android.support.v4.app.ActivityOptionsCompat.setLaunchBounds_added(android.graphics.Rect)" class="hiddenlink" target="rightframe"><b>setLaunchBounds</b>
    -+(<code>Rect</code>)</A></nobr><br>
    -+<nobr><A HREF="android.support.v4.view.accessibility.AccessibilityEventCompat.html#android.support.v4.view.accessibility.AccessibilityEventCompat.setMovementGranularity_added(android.view.accessibility.AccessibilityEvent, int)" class="hiddenlink" target="rightframe"><b>setMovementGranularity</b>
    -+(<code>AccessibilityEvent, int</code>)</A></nobr><br>
    -+<nobr><A HREF="android.support.v4.widget.SwipeRefreshLayout.html#android.support.v4.widget.SwipeRefreshLayout.setOnChildScrollUpCallback_added(android.support.v4.widget.SwipeRefreshLayout.OnChildScrollUpCallback)" class="hiddenlink" target="rightframe"><b>setOnChildScrollUpCallback</b>
    -+(<code>OnChildScrollUpCallback</code>)</A></nobr><br>
    -+<nobr><A HREF="android.support.v7.widget.RecyclerView.html#android.support.v7.widget.RecyclerView.setOnFlingListener_added(android.support.v7.widget.RecyclerView.OnFlingListener)" class="hiddenlink" target="rightframe"><b>setOnFlingListener</b>
    -+(<code>OnFlingListener</code>)</A></nobr><br>
    -+<i>setPasswordVisibilityToggleContentDescription</i><br>
    -+&nbsp;&nbsp;<nobr><A HREF="android.support.design.widget.TextInputLayout.html#android.support.design.widget.TextInputLayout.setPasswordVisibilityToggleContentDescription_added(int)" class="hiddenlink" target="rightframe">type&nbsp;<b>
    -+(<code>int</code>)</b>&nbsp;in&nbsp;android.support.design.widget.TextInputLayout
    -+</A></nobr><br>
    -+&nbsp;&nbsp;<nobr><A HREF="android.support.design.widget.TextInputLayout.html#android.support.design.widget.TextInputLayout.setPasswordVisibilityToggleContentDescription_added(java.lang.CharSequence)" class="hiddenlink" target="rightframe">type&nbsp;<b>
    -+(<code>CharSequence</code>)</b>&nbsp;in&nbsp;android.support.design.widget.TextInputLayout
    -+</A></nobr><br>
    -+<i>setPasswordVisibilityToggleDrawable</i><br>
    -+&nbsp;&nbsp;<nobr><A HREF="android.support.design.widget.TextInputLayout.html#android.support.design.widget.TextInputLayout.setPasswordVisibilityToggleDrawable_added(android.graphics.drawable.Drawable)" class="hiddenlink" target="rightframe">type&nbsp;<b>
    -+(<code>Drawable</code>)</b>&nbsp;in&nbsp;android.support.design.widget.TextInputLayout
    -+</A></nobr><br>
    -+&nbsp;&nbsp;<nobr><A HREF="android.support.design.widget.TextInputLayout.html#android.support.design.widget.TextInputLayout.setPasswordVisibilityToggleDrawable_added(int)" class="hiddenlink" target="rightframe">type&nbsp;<b>
    -+(<code>int</code>)</b>&nbsp;in&nbsp;android.support.design.widget.TextInputLayout
    -+</A></nobr><br>
    -+<nobr><A HREF="android.support.design.widget.TextInputLayout.html#android.support.design.widget.TextInputLayout.setPasswordVisibilityToggleEnabled_added(boolean)" class="hiddenlink" target="rightframe"><b>setPasswordVisibilityToggleEnabled</b>
    -+(<code>boolean</code>)</A></nobr><br>
    -+<nobr><A HREF="android.support.design.widget.TextInputLayout.html#android.support.design.widget.TextInputLayout.setPasswordVisibilityToggleTintList_added(android.content.res.ColorStateList)" class="hiddenlink" target="rightframe"><b>setPasswordVisibilityToggleTintList</b>
    -+(<code>ColorStateList</code>)</A></nobr><br>
    -+<nobr><A HREF="android.support.design.widget.TextInputLayout.html#android.support.design.widget.TextInputLayout.setPasswordVisibilityToggleTintMode_added(android.graphics.PorterDuff.Mode)" class="hiddenlink" target="rightframe"><b>setPasswordVisibilityToggleTintMode</b>
    -+(<code>Mode</code>)</A></nobr><br>
    -+<nobr><A HREF="android.support.customtabs.CustomTabsSession.html#android.support.customtabs.CustomTabsSession.setSecondaryToolbarViews_added(android.widget.RemoteViews, int[], android.app.PendingIntent)" class="hiddenlink" target="rightframe"><b>setSecondaryToolbarViews</b>
    -+(<code>RemoteViews, int[], PendingIntent</code>)</A></nobr><br>
    -+<nobr><A HREF="android.support.v17.leanback.widget.AbstractMediaItemPresenter.ViewHolder.html#android.support.v17.leanback.widget.AbstractMediaItemPresenter.ViewHolder.setSelectedMediaItemNumberView_added(int)" class="hiddenlink" target="rightframe"><b>setSelectedMediaItemNumberView</b>
    -+(<code>int</code>)</A></nobr><br>
    -+<nobr><A HREF="android.support.customtabs.CustomTabsIntent.html#android.support.customtabs.CustomTabsIntent.shouldAlwaysUseBrowserUI_added(android.content.Intent)" class="hiddenlink" target="rightframe"><b>shouldAlwaysUseBrowserUI</b>
    -+(<code>Intent</code>)</A></nobr><br>
    -+<nobr><A HREF="android.support.v4.app.ServiceCompat.html#android.support.v4.app.ServiceCompat.stopForeground_added(android.app.Service, int)" class="hiddenlink" target="rightframe"><b>stopForeground</b>
    -+(<code>Service, int</code>)</A></nobr><br>
    -+<A NAME="T"></A>
    -+<br><font size="+2">T</font>&nbsp;
    -+<a href="#A"><font size="-2">A</font></a> 
    -+<a href="#B"><font size="-2">B</font></a> 
    -+<a href="#C"><font size="-2">C</font></a> 
    -+<a href="#F"><font size="-2">F</font></a> 
    -+<a href="#G"><font size="-2">G</font></a> 
    -+<a href="#I"><font size="-2">I</font></a> 
    -+<a href="#L"><font size="-2">L</font></a> 
    -+<a href="#M"><font size="-2">M</font></a> 
    -+<a href="#N"><font size="-2">N</font></a> 
    -+<a href="#O"><font size="-2">O</font></a> 
    -+<a href="#R"><font size="-2">R</font></a> 
    -+<a href="#S"><font size="-2">S</font></a> 
    -+ <a href="#topheader"><font size="-2">TOP</font></a>
    -+<p><div style="line-height:1.5em;color:black">
    -+<nobr><A HREF="android.support.v4.media.session.PlaybackStateCompat.html#android.support.v4.media.session.PlaybackStateCompat.toKeyCode_added(long)" class="hiddenlink" target="rightframe"><b>toKeyCode</b>
    -+(<code>long</code>)</A></nobr><br>
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    -+</script>
    -+<script type="text/javascript">
    -+  try {
    -+    var pageTracker = _gat._getTracker("UA-5831155-1");
    -+    pageTracker._setAllowAnchor(true);
    -+    pageTracker._initData();
    -+    pageTracker._trackPageview();
    -+  } catch(e) {}
    -+</script>
    -+</BODY>
    -+</HTML>
    -diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/methods_index_all.html b/docs/html/sdk/support_api_diff/24.2.0/changes/methods_index_all.html
    -new file mode 100644
    -index 0000000..d33bfc0
    ---- /dev/null
    -+++ b/docs/html/sdk/support_api_diff/24.2.0/changes/methods_index_all.html
    -@@ -0,0 +1,579 @@
    -+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
    -+<HTML style="overflow:auto;">
    -+<HEAD>
    -+<meta name="generator" content="JDiff v1.1.0">
    -+<!-- Generated by the JDiff Javadoc doclet -->
    -+<!-- (http://www.jdiff.org) -->
    -+<meta name="description" content="JDiff is a Javadoc doclet which generates an HTML report of all the packages, classes, constructors, methods, and fields which have been removed, added or changed in any way, including their documentation, when two APIs are compared.">
    -+<meta name="keywords" content="diff, jdiff, javadiff, java diff, java difference, API difference, difference between two APIs, API diff, Javadoc, doclet">
    -+<TITLE>
    -+Method Differences Index
    -+</TITLE>
    -+<link href="../../../../assets/android-developer-docs.css" rel="stylesheet" type="text/css" />
    -+<link href="../stylesheet-jdiff.css" rel="stylesheet" type="text/css" />
    -+<noscript>
    -+<style type="text/css">
    -+body{overflow:auto;}
    -+#body-content{position:relative; top:0;}
    -+#doc-content{overflow:visible;border-left:3px solid #666;}
    -+#side-nav{padding:0;}
    -+#side-nav .toggle-list ul {display:block;}
    -+#resize-packages-nav{border-bottom:3px solid #666;}
    -+</style>
    -+</noscript>
    -+<style type="text/css">
    -+</style>
    -+</HEAD>
    -+<BODY class="gc-documentation" style="padding:12px;">
    -+<a NAME="topheader"></a>
    -+<table summary="Index for Methods" width="100%" class="jdiffIndex" border="0" cellspacing="0" cellpadding="0" style="padding-bottom:0;margin-bottom:0;">
    -+  <tr>
    -+  <th class="indexHeader">
    -+    Filter the Index:
    -+  </th>
    -+  </tr>
    -+  <tr>
    -+  <td class="indexText" style="line-height:1.3em;padding-left:2em;">
    -+<b>Methods</b>
    -+  <br>
    -+<A HREF="methods_index_removals.html" xclass="hiddenlink">Removals</A>
    -+  <br>
    -+<A HREF="methods_index_additions.html"xclass="hiddenlink">Additions</A>
    -+  <br>
    -+<A HREF="methods_index_changes.html"xclass="hiddenlink">Changes</A>
    -+  </td>
    -+  </tr>
    -+</table>
    -+<div id="indexTableCaption" style="background-color:#eee;padding:0 4px 0 4px;font-size:11px;margin-bottom:1em;">
    -+Listed as: <span style="color:#069"><strong>Added</strong></span>,  <span style="color:#069"><strike>Removed</strike></span>,  <span style="color:#069">Changed</span></font>
    -+</div>
    -+<A NAME="A"></A>
    -+<br><font size="+2">A</font>&nbsp;
    -+<a href="#B"><font size="-2">B</font></a> 
    -+<a href="#C"><font size="-2">C</font></a> 
    -+<a href="#D"><font size="-2">D</font></a> 
    -+<a href="#F"><font size="-2">F</font></a> 
    -+<a href="#G"><font size="-2">G</font></a> 
    -+<a href="#I"><font size="-2">I</font></a> 
    -+<a href="#L"><font size="-2">L</font></a> 
    -+<a href="#M"><font size="-2">M</font></a> 
    -+<a href="#N"><font size="-2">N</font></a> 
    -+<a href="#O"><font size="-2">O</font></a> 
    -+<a href="#P"><font size="-2">P</font></a> 
    -+<a href="#R"><font size="-2">R</font></a> 
    -+<a href="#S"><font size="-2">S</font></a> 
    -+<a href="#T"><font size="-2">T</font></a> 
    -+ <a href="#topheader"><font size="-2">TOP</font></a>
    -+<p><div style="line-height:1.5em;color:black">
    -+<nobr><A HREF="android.support.v4.view.accessibility.AccessibilityManagerCompat.html#android.support.v4.view.accessibility.AccessibilityManagerCompat.addAccessibilityStateChangeListener_changed(android.view.accessibility.AccessibilityManager, android.support.v4.view.accessibility.AccessibilityManagerCompat.AccessibilityStateChangeListener)" class="hiddenlink" target="rightframe">addAccessibilityStateChangeListener
    -+(<code>AccessibilityManager, AccessibilityStateChangeListener</code>)</A></nobr><br>
    -+<nobr><A HREF="android.support.v4.view.accessibility.AccessibilityManagerCompat.html#android.support.v4.view.accessibility.AccessibilityManagerCompat.addTouchExplorationStateChangeListener_added(android.view.accessibility.AccessibilityManager, android.support.v4.view.accessibility.AccessibilityManagerCompat.TouchExplorationStateChangeListener)" class="hiddenlink" target="rightframe"><b>addTouchExplorationStateChangeListener</b>
    -+(<code>AccessibilityManager, TouchExplorationStateChangeListener</code>)</A></nobr><br>
    -+<A NAME="B"></A>
    -+<br><font size="+2">B</font>&nbsp;
    -+<a href="#A"><font size="-2">A</font></a> 
    -+<a href="#C"><font size="-2">C</font></a> 
    -+<a href="#D"><font size="-2">D</font></a> 
    -+<a href="#F"><font size="-2">F</font></a> 
    -+<a href="#G"><font size="-2">G</font></a> 
    -+<a href="#I"><font size="-2">I</font></a> 
    -+<a href="#L"><font size="-2">L</font></a> 
    -+<a href="#M"><font size="-2">M</font></a> 
    -+<a href="#N"><font size="-2">N</font></a> 
    -+<a href="#O"><font size="-2">O</font></a> 
    -+<a href="#P"><font size="-2">P</font></a> 
    -+<a href="#R"><font size="-2">R</font></a> 
    -+<a href="#S"><font size="-2">S</font></a> 
    -+<a href="#T"><font size="-2">T</font></a> 
    -+ <a href="#topheader"><font size="-2">TOP</font></a>
    -+<p><div style="line-height:1.5em;color:black">
    -+<i>buildMediaButtonPendingIntent</i><br>
    -+&nbsp;&nbsp;<nobr><A HREF="android.support.v4.media.session.MediaButtonReceiver.html#android.support.v4.media.session.MediaButtonReceiver.buildMediaButtonPendingIntent_added(android.content.Context, android.content.ComponentName, long)" class="hiddenlink" target="rightframe">type&nbsp;<b>
    -+(<code>Context, ComponentName, long</code>)</b>&nbsp;in&nbsp;android.support.v4.media.session.MediaButtonReceiver
    -+</A></nobr><br>
    -+&nbsp;&nbsp;<nobr><A HREF="android.support.v4.media.session.MediaButtonReceiver.html#android.support.v4.media.session.MediaButtonReceiver.buildMediaButtonPendingIntent_added(android.content.Context, long)" class="hiddenlink" target="rightframe">type&nbsp;<b>
    -+(<code>Context, long</code>)</b>&nbsp;in&nbsp;android.support.v4.media.session.MediaButtonReceiver
    -+</A></nobr><br>
    -+<A NAME="C"></A>
    -+<br><font size="+2">C</font>&nbsp;
    -+<a href="#A"><font size="-2">A</font></a> 
    -+<a href="#B"><font size="-2">B</font></a> 
    -+<a href="#D"><font size="-2">D</font></a> 
    -+<a href="#F"><font size="-2">F</font></a> 
    -+<a href="#G"><font size="-2">G</font></a> 
    -+<a href="#I"><font size="-2">I</font></a> 
    -+<a href="#L"><font size="-2">L</font></a> 
    -+<a href="#M"><font size="-2">M</font></a> 
    -+<a href="#N"><font size="-2">N</font></a> 
    -+<a href="#O"><font size="-2">O</font></a> 
    -+<a href="#P"><font size="-2">P</font></a> 
    -+<a href="#R"><font size="-2">R</font></a> 
    -+<a href="#S"><font size="-2">S</font></a> 
    -+<a href="#T"><font size="-2">T</font></a> 
    -+ <a href="#topheader"><font size="-2">TOP</font></a>
    -+<p><div style="line-height:1.5em;color:black">
    -+<nobr><A HREF="android.support.v4.graphics.drawable.DrawableCompat.html#android.support.v4.graphics.drawable.DrawableCompat.clearColorFilter_added(android.graphics.drawable.Drawable)" class="hiddenlink" target="rightframe"><b>clearColorFilter</b>
    -+(<code>Drawable</code>)</A></nobr><br>
    -+<nobr><A HREF="android.support.design.widget.TabLayout.html#android.support.design.widget.TabLayout.clearOnTabSelectedListeners_added()" class="hiddenlink" target="rightframe"><b>clearOnTabSelectedListeners</b>
    -+()</A></nobr><br>
    -+<i>computeScrollVectorForPosition</i><br>
    -+&nbsp;&nbsp;<nobr><A HREF="android.support.v7.widget.LinearSmoothScroller.html#android.support.v7.widget.LinearSmoothScroller.computeScrollVectorForPosition_changed(int)" class="hiddenlink" target="rightframe">type&nbsp;
    -+(<code>int</code>)&nbsp;in&nbsp;android.support.v7.widget.LinearSmoothScroller
    -+</A></nobr><br>
    -+&nbsp;&nbsp;<nobr><A HREF="android.support.v7.widget.StaggeredGridLayoutManager.html#android.support.v7.widget.StaggeredGridLayoutManager.computeScrollVectorForPosition_added(int)" class="hiddenlink" target="rightframe">type&nbsp;<b>
    -+(<code>int</code>)</b>&nbsp;in&nbsp;android.support.v7.widget.StaggeredGridLayoutManager
    -+</A></nobr><br>
    -+<A NAME="D"></A>
    -+<br><font size="+2">D</font>&nbsp;
    -+<a href="#A"><font size="-2">A</font></a> 
    -+<a href="#B"><font size="-2">B</font></a> 
    -+<a href="#C"><font size="-2">C</font></a> 
    -+<a href="#F"><font size="-2">F</font></a> 
    -+<a href="#G"><font size="-2">G</font></a> 
    -+<a href="#I"><font size="-2">I</font></a> 
    -+<a href="#L"><font size="-2">L</font></a> 
    -+<a href="#M"><font size="-2">M</font></a> 
    -+<a href="#N"><font size="-2">N</font></a> 
    -+<a href="#O"><font size="-2">O</font></a> 
    -+<a href="#P"><font size="-2">P</font></a> 
    -+<a href="#R"><font size="-2">R</font></a> 
    -+<a href="#S"><font size="-2">S</font></a> 
    -+<a href="#T"><font size="-2">T</font></a> 
    -+ <a href="#topheader"><font size="-2">TOP</font></a>
    -+<p><div style="line-height:1.5em;color:black">
    -+<nobr><A HREF="android.support.v4.view.KeyEventCompat.html#android.support.v4.view.KeyEventCompat.dispatch_changed(android.view.KeyEvent, android.view.KeyEvent.Callback, java.lang.Object, java.lang.Object)" class="hiddenlink" target="rightframe">dispatch
    -+(<code>KeyEvent, Callback, Object, Object</code>)</A></nobr><br>
    -+<A NAME="F"></A>
    -+<br><font size="+2">F</font>&nbsp;
    -+<a href="#A"><font size="-2">A</font></a> 
    -+<a href="#B"><font size="-2">B</font></a> 
    -+<a href="#C"><font size="-2">C</font></a> 
    -+<a href="#D"><font size="-2">D</font></a> 
    -+<a href="#G"><font size="-2">G</font></a> 
    -+<a href="#I"><font size="-2">I</font></a> 
    -+<a href="#L"><font size="-2">L</font></a> 
    -+<a href="#M"><font size="-2">M</font></a> 
    -+<a href="#N"><font size="-2">N</font></a> 
    -+<a href="#O"><font size="-2">O</font></a> 
    -+<a href="#P"><font size="-2">P</font></a> 
    -+<a href="#R"><font size="-2">R</font></a> 
    -+<a href="#S"><font size="-2">S</font></a> 
    -+<a href="#T"><font size="-2">T</font></a> 
    -+ <a href="#topheader"><font size="-2">TOP</font></a>
    -+<p><div style="line-height:1.5em;color:black">
    -+<nobr><A HREF="android.support.v4.app.FragmentController.html#android.support.v4.app.FragmentController.findFragmentByWho_added(java.lang.String)" class="hiddenlink" target="rightframe"><b>findFragmentByWho</b>
    -+(<code>String</code>)</A></nobr><br>
    -+<nobr><A HREF="android.support.v4.view.MotionEventCompat.html#android.support.v4.view.MotionEventCompat.findPointerIndex_changed(android.view.MotionEvent, int)" class="hiddenlink" target="rightframe">findPointerIndex
    -+(<code>MotionEvent, int</code>)</A></nobr><br>
    -+<nobr><A HREF="android.support.v4.media.MediaBrowserCompat.MediaItem.html#android.support.v4.media.MediaBrowserCompat.MediaItem.fromMediaItem_added(java.lang.Object)" class="hiddenlink" target="rightframe"><b>fromMediaItem</b>
    -+(<code>Object</code>)</A></nobr><br>
    -+<nobr><A HREF="android.support.v4.media.MediaBrowserCompat.MediaItem.html#android.support.v4.media.MediaBrowserCompat.MediaItem.fromMediaItemList_added(java.util.List<?>)" class="hiddenlink" target="rightframe"><b>fromMediaItemList</b>
    -+(<code>List&lt;?&gt;</code>)</A></nobr><br>
    -+<nobr><A HREF="android.support.v4.media.session.MediaSessionCompat.html#android.support.v4.media.session.MediaSessionCompat.fromMediaSession_added(android.content.Context, java.lang.Object)" class="hiddenlink" target="rightframe"><b>fromMediaSession</b>
    -+(<code>Context, Object</code>)</A></nobr><br>
    -+<nobr><A HREF="android.support.v4.media.session.MediaSessionCompat.QueueItem.html#android.support.v4.media.session.MediaSessionCompat.QueueItem.fromQueueItem_added(java.lang.Object)" class="hiddenlink" target="rightframe"><b>fromQueueItem</b>
    -+(<code>Object</code>)</A></nobr><br>
    -+<nobr><A HREF="android.support.v4.media.session.MediaSessionCompat.QueueItem.html#android.support.v4.media.session.MediaSessionCompat.QueueItem.fromQueueItemList_added(java.util.List<?>)" class="hiddenlink" target="rightframe"><b>fromQueueItemList</b>
    -+(<code>List&lt;?&gt;</code>)</A></nobr><br>
    -+<A NAME="G"></A>
    -+<br><font size="+2">G</font>&nbsp;
    -+<a href="#A"><font size="-2">A</font></a> 
    -+<a href="#B"><font size="-2">B</font></a> 
    -+<a href="#C"><font size="-2">C</font></a> 
    -+<a href="#D"><font size="-2">D</font></a> 
    -+<a href="#F"><font size="-2">F</font></a> 
    -+<a href="#I"><font size="-2">I</font></a> 
    -+<a href="#L"><font size="-2">L</font></a> 
    -+<a href="#M"><font size="-2">M</font></a> 
    -+<a href="#N"><font size="-2">N</font></a> 
    -+<a href="#O"><font size="-2">O</font></a> 
    -+<a href="#P"><font size="-2">P</font></a> 
    -+<a href="#R"><font size="-2">R</font></a> 
    -+<a href="#S"><font size="-2">S</font></a> 
    -+<a href="#T"><font size="-2">T</font></a> 
    -+ <a href="#topheader"><font size="-2">TOP</font></a>
    -+<p><div style="line-height:1.5em;color:black">
    -+<nobr><A HREF="android.support.v4.view.accessibility.AccessibilityEventCompat.html#android.support.v4.view.accessibility.AccessibilityEventCompat.getAction_added(android.view.accessibility.AccessibilityEvent)" class="hiddenlink" target="rightframe"><b>getAction</b>
    -+(<code>AccessibilityEvent</code>)</A></nobr><br>
    -+<nobr><A HREF="android.support.v4.widget.TextViewCompat.html#android.support.v4.widget.TextViewCompat.getCompoundDrawablesRelative_added(android.widget.TextView)" class="hiddenlink" target="rightframe"><b>getCompoundDrawablesRelative</b>
    -+(<code>TextView</code>)</A></nobr><br>
    -+<nobr><A HREF="android.support.design.widget.CoordinatorLayout.html#android.support.design.widget.CoordinatorLayout.getDependents_added(android.view.View)" class="hiddenlink" target="rightframe"><b>getDependents</b>
    -+(<code>View</code>)</A></nobr><br>
    -+<nobr><A HREF="android.support.v4.accessibilityservice.AccessibilityServiceInfoCompat.html#android.support.v4.accessibilityservice.AccessibilityServiceInfoCompat.getDescription_changed(android.accessibilityservice.AccessibilityServiceInfo)" class="hiddenlink" target="rightframe">getDescription
    -+(<code>AccessibilityServiceInfo</code>)</A></nobr><br>
    -+<nobr><A HREF="android.support.v7.graphics.Palette.html#android.support.v7.graphics.Palette.getDominantColor_added(int)" class="hiddenlink" target="rightframe"><b>getDominantColor</b>
    -+(<code>int</code>)</A></nobr><br>
    -+<nobr><A HREF="android.support.v7.graphics.Palette.html#android.support.v7.graphics.Palette.getDominantSwatch_added()" class="hiddenlink" target="rightframe"><b>getDominantSwatch</b>
    -+()</A></nobr><br>
    -+<nobr><A HREF="android.support.v7.content.res.AppCompatResources.html#android.support.v7.content.res.AppCompatResources.getDrawable_added(android.content.Context, int)" class="hiddenlink" target="rightframe"><b>getDrawable</b>
    -+(<code>Context, int</code>)</A></nobr><br>
    -+<nobr><A HREF="android.support.v7.app.ActionBarDrawerToggle.html#android.support.v7.app.ActionBarDrawerToggle.getDrawerArrowDrawable_added()" class="hiddenlink" target="rightframe"><b>getDrawerArrowDrawable</b>
    -+()</A></nobr><br>
    -+<i>getInsetDodgeRect</i><br>
    -+&nbsp;&nbsp;<nobr><A HREF="android.support.design.widget.CoordinatorLayout.Behavior.html#android.support.design.widget.CoordinatorLayout.Behavior.getInsetDodgeRect_added(android.support.design.widget.CoordinatorLayout, V, android.graphics.Rect)" class="hiddenlink" target="rightframe">type&nbsp;<b>
    -+(<code>CoordinatorLayout, V, Rect</code>)</b>&nbsp;in&nbsp;android.support.design.widget.CoordinatorLayout.Behavior
    -+</A></nobr><br>
    -+&nbsp;&nbsp;<nobr><A HREF="android.support.design.widget.FloatingActionButton.Behavior.html#android.support.design.widget.FloatingActionButton.Behavior.getInsetDodgeRect_added(android.support.design.widget.CoordinatorLayout, android.support.design.widget.FloatingActionButton, android.graphics.Rect)" class="hiddenlink" target="rightframe">type&nbsp;<b>
    -+(<code>CoordinatorLayout, FloatingActionButton, Rect</code>)</b>&nbsp;in&nbsp;android.support.design.widget.FloatingActionButton.Behavior
    -+</A></nobr><br>
    -+<nobr><A HREF="android.support.v4.view.KeyEventCompat.html#android.support.v4.view.KeyEventCompat.getKeyDispatcherState_changed(android.view.View)" class="hiddenlink" target="rightframe">getKeyDispatcherState
    -+(<code>View</code>)</A></nobr><br>
    -+<nobr><A HREF="android.support.v4.app.ActivityOptionsCompat.html#android.support.v4.app.ActivityOptionsCompat.getLaunchBounds_added()" class="hiddenlink" target="rightframe"><b>getLaunchBounds</b>
    -+()</A></nobr><br>
    -+<nobr><A HREF="android.support.v17.leanback.widget.AbstractMediaItemPresenter.ViewHolder.html#android.support.v17.leanback.widget.AbstractMediaItemPresenter.ViewHolder.getMediaItemNumberViewFlipper_added()" class="hiddenlink" target="rightframe"><b>getMediaItemNumberViewFlipper</b>
    -+()</A></nobr><br>
    -+<nobr><A HREF="android.support.v17.leanback.widget.AbstractMediaItemPresenter.ViewHolder.html#android.support.v17.leanback.widget.AbstractMediaItemPresenter.ViewHolder.getMediaItemPausedView_added()" class="hiddenlink" target="rightframe"><b>getMediaItemPausedView</b>
    -+()</A></nobr><br>
    -+<nobr><A HREF="android.support.v17.leanback.widget.AbstractMediaItemPresenter.ViewHolder.html#android.support.v17.leanback.widget.AbstractMediaItemPresenter.ViewHolder.getMediaItemPlayingView_added()" class="hiddenlink" target="rightframe"><b>getMediaItemPlayingView</b>
    -+()</A></nobr><br>
    -+<nobr><A HREF="android.support.v17.leanback.widget.AbstractMediaItemPresenter.html#android.support.v17.leanback.widget.AbstractMediaItemPresenter.getMediaPlayState_added(java.lang.Object)" class="hiddenlink" target="rightframe"><b>getMediaPlayState</b>
    -+(<code>Object</code>)</A></nobr><br>
    -+<nobr><A HREF="android.support.v4.view.accessibility.AccessibilityEventCompat.html#android.support.v4.view.accessibility.AccessibilityEventCompat.getMovementGranularity_added(android.view.accessibility.AccessibilityEvent)" class="hiddenlink" target="rightframe"><b>getMovementGranularity</b>
    -+(<code>AccessibilityEvent</code>)</A></nobr><br>
    -+<nobr><A HREF="android.support.v7.widget.RecyclerView.html#android.support.v7.widget.RecyclerView.getOnFlingListener_added()" class="hiddenlink" target="rightframe"><b>getOnFlingListener</b>
    -+()</A></nobr><br>
    -+<nobr><A HREF="android.support.v4.view.ViewCompat.html#android.support.v4.view.ViewCompat.getOverScrollMode_changed(android.view.View)" class="hiddenlink" target="rightframe">getOverScrollMode
    -+(<code>View</code>)</A></nobr><br>
    -+<nobr><A HREF="android.support.design.widget.TextInputLayout.html#android.support.design.widget.TextInputLayout.getPasswordVisibilityToggleContentDescription_added()" class="hiddenlink" target="rightframe"><b>getPasswordVisibilityToggleContentDescription</b>
    -+()</A></nobr><br>
    -+<nobr><A HREF="android.support.design.widget.TextInputLayout.html#android.support.design.widget.TextInputLayout.getPasswordVisibilityToggleDrawable_added()" class="hiddenlink" target="rightframe"><b>getPasswordVisibilityToggleDrawable</b>
    -+()</A></nobr><br>
    -+<nobr><A HREF="android.support.v4.view.MotionEventCompat.html#android.support.v4.view.MotionEventCompat.getPointerCount_changed(android.view.MotionEvent)" class="hiddenlink" target="rightframe">getPointerCount
    -+(<code>MotionEvent</code>)</A></nobr><br>
    -+<nobr><A HREF="android.support.v4.view.MotionEventCompat.html#android.support.v4.view.MotionEventCompat.getPointerId_changed(android.view.MotionEvent, int)" class="hiddenlink" target="rightframe">getPointerId
    -+(<code>MotionEvent, int</code>)</A></nobr><br>
    -+<nobr><A HREF="android.support.v4.app.ActivityCompat.html#android.support.v4.app.ActivityCompat.getReferrer_changed(android.app.Activity)" class="hiddenlink" target="rightframe">getReferrer
    -+(<code>Activity</code>)</A></nobr><br>
    -+<nobr><A HREF="android.support.v4.view.ViewConfigurationCompat.html#android.support.v4.view.ViewConfigurationCompat.getScaledPagingTouchSlop_changed(android.view.ViewConfiguration)" class="hiddenlink" target="rightframe">getScaledPagingTouchSlop
    -+(<code>ViewConfiguration</code>)</A></nobr><br>
    -+<nobr><A HREF="android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.CollectionInfoCompat.html#android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.CollectionInfoCompat.getSelectionMode_added()" class="hiddenlink" target="rightframe"><b>getSelectionMode</b>
    -+()</A></nobr><br>
    -+<nobr><A HREF="android.support.v4.view.MotionEventCompat.html#android.support.v4.view.MotionEventCompat.getSource_changed(android.view.MotionEvent)" class="hiddenlink" target="rightframe">getSource
    -+(<code>MotionEvent</code>)</A></nobr><br>
    -+<nobr><A HREF="android.support.v4.view.MotionEventCompat.html#android.support.v4.view.MotionEventCompat.getX_changed(android.view.MotionEvent, int)" class="hiddenlink" target="rightframe">getX
    -+(<code>MotionEvent, int</code>)</A></nobr><br>
    -+<nobr><A HREF="android.support.v4.view.MotionEventCompat.html#android.support.v4.view.MotionEventCompat.getY_changed(android.view.MotionEvent, int)" class="hiddenlink" target="rightframe">getY
    -+(<code>MotionEvent, int</code>)</A></nobr><br>
    -+<A NAME="I"></A>
    -+<br><font size="+2">I</font>&nbsp;
    -+<a href="#A"><font size="-2">A</font></a> 
    -+<a href="#B"><font size="-2">B</font></a> 
    -+<a href="#C"><font size="-2">C</font></a> 
    -+<a href="#D"><font size="-2">D</font></a> 
    -+<a href="#F"><font size="-2">F</font></a> 
    -+<a href="#G"><font size="-2">G</font></a> 
    -+<a href="#L"><font size="-2">L</font></a> 
    -+<a href="#M"><font size="-2">M</font></a> 
    -+<a href="#N"><font size="-2">N</font></a> 
    -+<a href="#O"><font size="-2">O</font></a> 
    -+<a href="#P"><font size="-2">P</font></a> 
    -+<a href="#R"><font size="-2">R</font></a> 
    -+<a href="#S"><font size="-2">S</font></a> 
    -+<a href="#T"><font size="-2">T</font></a> 
    -+ <a href="#topheader"><font size="-2">TOP</font></a>
    -+<p><div style="line-height:1.5em;color:black">
    -+<nobr><A HREF="android.support.v4.os.BuildCompat.html#android.support.v4.os.BuildCompat.isAtLeastNMR1_added()" class="hiddenlink" target="rightframe"><b>isAtLeastNMR1</b>
    -+()</A></nobr><br>
    -+<nobr><A HREF="android.support.design.widget.FloatingActionButton.Behavior.html#android.support.design.widget.FloatingActionButton.Behavior.isAutoHideEnabled_added()" class="hiddenlink" target="rightframe"><b>isAutoHideEnabled</b>
    -+()</A></nobr><br>
    -+<nobr><A HREF="android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.html#android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.isContextClickable_added()" class="hiddenlink" target="rightframe"><b>isContextClickable</b>
    -+()</A></nobr><br>
    -+<nobr><A HREF="android.support.design.widget.CoordinatorLayout.Behavior.html#android.support.design.widget.CoordinatorLayout.Behavior.isDirty_changed(android.support.design.widget.CoordinatorLayout, V)" class="hiddenlink" target="rightframe">isDirty
    -+(<code>CoordinatorLayout, V</code>)</A></nobr><br>
    -+<nobr><A HREF="android.support.v17.leanback.widget.ObjectAdapter.html#android.support.v17.leanback.widget.ObjectAdapter.isImmediateNotifySupported_added()" class="hiddenlink" target="rightframe"><b>isImmediateNotifySupported</b>
    -+()</A></nobr><br>
    -+<nobr><A HREF="android.support.v4.view.ViewCompat.html#android.support.v4.view.ViewCompat.isImportantForAccessibility_added(android.view.View)" class="hiddenlink" target="rightframe"><b>isImportantForAccessibility</b>
    -+(<code>View</code>)</A></nobr><br>
    -+<nobr><A HREF="android.support.v4.view.ViewCompat.html#android.support.v4.view.ViewCompat.isOpaque_changed(android.view.View)" class="hiddenlink" target="rightframe">isOpaque
    -+(<code>View</code>)</A></nobr><br>
    -+<nobr><A HREF="android.support.design.widget.TextInputLayout.html#android.support.design.widget.TextInputLayout.isPasswordVisibilityToggleEnabled_added()" class="hiddenlink" target="rightframe"><b>isPasswordVisibilityToggleEnabled</b>
    -+()</A></nobr><br>
    -+<nobr><A HREF="android.support.v4.view.KeyEventCompat.html#android.support.v4.view.KeyEventCompat.isTracking_changed(android.view.KeyEvent)" class="hiddenlink" target="rightframe">isTracking
    -+(<code>KeyEvent</code>)</A></nobr><br>
    -+<A NAME="L"></A>
    -+<br><font size="+2">L</font>&nbsp;
    -+<a href="#A"><font size="-2">A</font></a> 
    -+<a href="#B"><font size="-2">B</font></a> 
    -+<a href="#C"><font size="-2">C</font></a> 
    -+<a href="#D"><font size="-2">D</font></a> 
    -+<a href="#F"><font size="-2">F</font></a> 
    -+<a href="#G"><font size="-2">G</font></a> 
    -+<a href="#I"><font size="-2">I</font></a> 
    -+<a href="#M"><font size="-2">M</font></a> 
    -+<a href="#N"><font size="-2">N</font></a> 
    -+<a href="#O"><font size="-2">O</font></a> 
    -+<a href="#P"><font size="-2">P</font></a> 
    -+<a href="#R"><font size="-2">R</font></a> 
    -+<a href="#S"><font size="-2">S</font></a> 
    -+<a href="#T"><font size="-2">T</font></a> 
    -+ <a href="#topheader"><font size="-2">TOP</font></a>
    -+<p><div style="line-height:1.5em;color:black">
    -+<nobr><A HREF="android.support.design.widget.FloatingActionButton.Behavior.html#android.support.design.widget.FloatingActionButton.Behavior.layoutDependsOn_removed(android.support.design.widget.CoordinatorLayout, android.support.design.widget.FloatingActionButton, android.view.View)" class="hiddenlink" target="rightframe"><strike>layoutDependsOn</strike>
    -+(<code>CoordinatorLayout, FloatingActionButton, View</code>)</A></nobr><br>
    -+<nobr><A HREF="android.support.v4.accessibilityservice.AccessibilityServiceInfoCompat.html#android.support.v4.accessibilityservice.AccessibilityServiceInfoCompat.loadDescription_added(android.accessibilityservice.AccessibilityServiceInfo, android.content.pm.PackageManager)" class="hiddenlink" target="rightframe"><b>loadDescription</b>
    -+(<code>AccessibilityServiceInfo, PackageManager</code>)</A></nobr><br>
    -+<A NAME="M"></A>
    -+<br><font size="+2">M</font>&nbsp;
    -+<a href="#A"><font size="-2">A</font></a> 
    -+<a href="#B"><font size="-2">B</font></a> 
    -+<a href="#C"><font size="-2">C</font></a> 
    -+<a href="#D"><font size="-2">D</font></a> 
    -+<a href="#F"><font size="-2">F</font></a> 
    -+<a href="#G"><font size="-2">G</font></a> 
    -+<a href="#I"><font size="-2">I</font></a> 
    -+<a href="#L"><font size="-2">L</font></a> 
    -+<a href="#N"><font size="-2">N</font></a> 
    -+<a href="#O"><font size="-2">O</font></a> 
    -+<a href="#P"><font size="-2">P</font></a> 
    -+<a href="#R"><font size="-2">R</font></a> 
    -+<a href="#S"><font size="-2">S</font></a> 
    -+<a href="#T"><font size="-2">T</font></a> 
    -+ <a href="#topheader"><font size="-2">TOP</font></a>
    -+<p><div style="line-height:1.5em;color:black">
    -+<nobr><A HREF="android.support.v4.app.ActivityOptionsCompat.html#android.support.v4.app.ActivityOptionsCompat.makeBasic_added()" class="hiddenlink" target="rightframe"><b>makeBasic</b>
    -+()</A></nobr><br>
    -+<nobr><A HREF="android.support.v4.app.ActivityOptionsCompat.html#android.support.v4.app.ActivityOptionsCompat.makeClipRevealAnimation_added(android.view.View, int, int, int, int)" class="hiddenlink" target="rightframe"><b>makeClipRevealAnimation</b>
    -+(<code>View, int, int, int, int</code>)</A></nobr><br>
    -+<nobr><A HREF="android.support.v4.app.ActivityOptionsCompat.html#android.support.v4.app.ActivityOptionsCompat.makeTaskLaunchBehind_added()" class="hiddenlink" target="rightframe"><b>makeTaskLaunchBehind</b>
    -+()</A></nobr><br>
    -+<A NAME="N"></A>
    -+<br><font size="+2">N</font>&nbsp;
    -+<a href="#A"><font size="-2">A</font></a> 
    -+<a href="#B"><font size="-2">B</font></a> 
    -+<a href="#C"><font size="-2">C</font></a> 
    -+<a href="#D"><font size="-2">D</font></a> 
    -+<a href="#F"><font size="-2">F</font></a> 
    -+<a href="#G"><font size="-2">G</font></a> 
    -+<a href="#I"><font size="-2">I</font></a> 
    -+<a href="#L"><font size="-2">L</font></a> 
    -+<a href="#M"><font size="-2">M</font></a> 
    -+<a href="#O"><font size="-2">O</font></a> 
    -+<a href="#P"><font size="-2">P</font></a> 
    -+<a href="#R"><font size="-2">R</font></a> 
    -+<a href="#S"><font size="-2">S</font></a> 
    -+<a href="#T"><font size="-2">T</font></a> 
    -+ <a href="#topheader"><font size="-2">TOP</font></a>
    -+<p><div style="line-height:1.5em;color:black">
    -+<nobr><A HREF="android.support.v17.leanback.widget.AbstractMediaItemPresenter.ViewHolder.html#android.support.v17.leanback.widget.AbstractMediaItemPresenter.ViewHolder.notifyPlayStateChanged_added()" class="hiddenlink" target="rightframe"><b>notifyPlayStateChanged</b>
    -+()</A></nobr><br>
    -+<A NAME="O"></A>
    -+<br><font size="+2">O</font>&nbsp;
    -+<a href="#A"><font size="-2">A</font></a> 
    -+<a href="#B"><font size="-2">B</font></a> 
    -+<a href="#C"><font size="-2">C</font></a> 
    -+<a href="#D"><font size="-2">D</font></a> 
    -+<a href="#F"><font size="-2">F</font></a> 
    -+<a href="#G"><font size="-2">G</font></a> 
    -+<a href="#I"><font size="-2">I</font></a> 
    -+<a href="#L"><font size="-2">L</font></a> 
    -+<a href="#M"><font size="-2">M</font></a> 
    -+<a href="#N"><font size="-2">N</font></a> 
    -+<a href="#P"><font size="-2">P</font></a> 
    -+<a href="#R"><font size="-2">R</font></a> 
    -+<a href="#S"><font size="-2">S</font></a> 
    -+<a href="#T"><font size="-2">T</font></a> 
    -+ <a href="#topheader"><font size="-2">TOP</font></a>
    -+<p><div style="line-height:1.5em;color:black">
    -+<i>obtain</i><br>
    -+&nbsp;&nbsp;<nobr><A HREF="android.support.v4.media.session.MediaSessionCompat.html#android.support.v4.media.session.MediaSessionCompat.obtain_changed(android.content.Context, java.lang.Object)" class="hiddenlink" target="rightframe">type&nbsp;
    -+(<code>Context, Object</code>)&nbsp;in&nbsp;android.support.v4.media.session.MediaSessionCompat
    -+</A></nobr><br>
    -+&nbsp;&nbsp;<nobr><A HREF="android.support.v4.media.session.MediaSessionCompat.QueueItem.html#android.support.v4.media.session.MediaSessionCompat.QueueItem.obtain_changed(java.lang.Object)" class="hiddenlink" target="rightframe">type&nbsp;
    -+(<code>Object</code>)&nbsp;in&nbsp;android.support.v4.media.session.MediaSessionCompat.QueueItem
    -+</A></nobr><br>
    -+&nbsp;&nbsp;<nobr><A HREF="android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.CollectionInfoCompat.html#android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.CollectionInfoCompat.obtain_added(int, int, boolean)" class="hiddenlink" target="rightframe">type&nbsp;<b>
    -+(<code>int, int, boolean</code>)</b>&nbsp;in&nbsp;android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.CollectionInfoCompat
    -+</A></nobr><br>
    -+&nbsp;&nbsp;<nobr><A HREF="android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.CollectionItemInfoCompat.html#android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.CollectionItemInfoCompat.obtain_added(int, int, int, int, boolean)" class="hiddenlink" target="rightframe">type&nbsp;<b>
    -+(<code>int, int, int, int, boolean</code>)</b>&nbsp;in&nbsp;android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.CollectionItemInfoCompat
    -+</A></nobr><br>
    -+&nbsp;&nbsp;<nobr><A HREF="android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.RangeInfoCompat.html#android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.RangeInfoCompat.obtain_added(int, float, float, float)" class="hiddenlink" target="rightframe">type&nbsp;<b>
    -+(<code>int, float, float, float</code>)</b>&nbsp;in&nbsp;android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.RangeInfoCompat
    -+</A></nobr><br>
    -+<nobr><A HREF="android.support.v4.view.accessibility.AccessibilityManagerCompat.AccessibilityStateChangeListenerCompat.html#android.support.v4.view.accessibility.AccessibilityManagerCompat.AccessibilityStateChangeListenerCompat.onAccessibilityStateChanged_removed(boolean)" class="hiddenlink" target="rightframe"><strike>onAccessibilityStateChanged</strike>
    -+(<code>boolean</code>)</A></nobr><br>
    -+<nobr><A HREF="android.support.design.widget.CoordinatorLayout.Behavior.html#android.support.design.widget.CoordinatorLayout.Behavior.onAttachedToLayoutParams_added(android.support.design.widget.CoordinatorLayout.LayoutParams)" class="hiddenlink" target="rightframe"><b>onAttachedToLayoutParams</b>
    -+(<code>LayoutParams</code>)</A></nobr><br>
    -+<nobr><A HREF="android.support.v17.leanback.widget.AbstractMediaItemPresenter.html#android.support.v17.leanback.widget.AbstractMediaItemPresenter.onBindMediaPlayState_added(android.support.v17.leanback.widget.AbstractMediaItemPresenter.ViewHolder)" class="hiddenlink" target="rightframe"><b>onBindMediaPlayState</b>
    -+(<code>ViewHolder</code>)</A></nobr><br>
    -+<nobr><A HREF="android.support.v7.util.SortedList.Callback.html#android.support.v7.util.SortedList.Callback.onChanged_added(int, int, java.lang.Object)" class="hiddenlink" target="rightframe"><b>onChanged</b>
    -+(<code>int, int, Object</code>)</A></nobr><br>
    -+<nobr><A HREF="android.support.design.widget.FloatingActionButton.Behavior.html#android.support.design.widget.FloatingActionButton.Behavior.onDependentViewRemoved_removed(android.support.design.widget.CoordinatorLayout, android.support.design.widget.FloatingActionButton, android.view.View)" class="hiddenlink" target="rightframe"><strike>onDependentViewRemoved</strike>
    -+(<code>CoordinatorLayout, FloatingActionButton, View</code>)</A></nobr><br>
    -+<nobr><A HREF="android.support.design.widget.CoordinatorLayout.Behavior.html#android.support.design.widget.CoordinatorLayout.Behavior.onDetachedFromLayoutParams_added()" class="hiddenlink" target="rightframe"><b>onDetachedFromLayoutParams</b>
    -+()</A></nobr><br>
    -+<nobr><A HREF="android.support.v7.util.SortedList.Callback.html#android.support.v7.util.SortedList.Callback.onInserted_removed(int, int)" class="hiddenlink" target="rightframe"><strike>onInserted</strike>
    -+(<code>int, int</code>)</A></nobr><br>
    -+<nobr><A HREF="android.support.v7.util.SortedList.Callback.html#android.support.v7.util.SortedList.Callback.onMoved_removed(int, int)" class="hiddenlink" target="rightframe"><strike>onMoved</strike>
    -+(<code>int, int</code>)</A></nobr><br>
    -+<nobr><A HREF="android.support.v7.util.SortedList.Callback.html#android.support.v7.util.SortedList.Callback.onRemoved_removed(int, int)" class="hiddenlink" target="rightframe"><strike>onRemoved</strike>
    -+(<code>int, int</code>)</A></nobr><br>
    -+<i>onRequestChildRectangleOnScreen</i><br>
    -+&nbsp;&nbsp;<nobr><A HREF="android.support.design.widget.AppBarLayout.ScrollingViewBehavior.html#android.support.design.widget.AppBarLayout.ScrollingViewBehavior.onRequestChildRectangleOnScreen_added(android.support.design.widget.CoordinatorLayout, android.view.View, android.graphics.Rect, boolean)" class="hiddenlink" target="rightframe">type&nbsp;<b>
    -+(<code>CoordinatorLayout, View, Rect, boolean</code>)</b>&nbsp;in&nbsp;android.support.design.widget.AppBarLayout.ScrollingViewBehavior
    -+</A></nobr><br>
    -+&nbsp;&nbsp;<nobr><A HREF="android.support.design.widget.CoordinatorLayout.Behavior.html#android.support.design.widget.CoordinatorLayout.Behavior.onRequestChildRectangleOnScreen_added(android.support.design.widget.CoordinatorLayout, V, android.graphics.Rect, boolean)" class="hiddenlink" target="rightframe">type&nbsp;<b>
    -+(<code>CoordinatorLayout, V, Rect, boolean</code>)</b>&nbsp;in&nbsp;android.support.design.widget.CoordinatorLayout.Behavior
    -+</A></nobr><br>
    -+<nobr><A HREF="android.support.v4.app.SharedElementCallback.html#android.support.v4.app.SharedElementCallback.onSharedElementsArrived_added(java.util.List<java.lang.String>, java.util.List<android.view.View>, android.support.v4.app.SharedElementCallback.OnSharedElementsReadyListener)" class="hiddenlink" target="rightframe"><b>onSharedElementsArrived</b>
    -+(<code>List&lt;String&gt;, List&lt;View&gt;, OnSharedElementsReadyListener</code>)</A></nobr><br>
    -+<nobr><A HREF="android.support.v7.app.AppCompatDelegate.html#android.support.v7.app.AppCompatDelegate.onStart_added()" class="hiddenlink" target="rightframe"><b>onStart</b>
    -+()</A></nobr><br>
    -+<nobr><A HREF="android.support.v17.leanback.widget.AbstractMediaItemPresenter.html#android.support.v17.leanback.widget.AbstractMediaItemPresenter.onUnbindMediaPlayState_added(android.support.v17.leanback.widget.AbstractMediaItemPresenter.ViewHolder)" class="hiddenlink" target="rightframe"><b>onUnbindMediaPlayState</b>
    -+(<code>ViewHolder</code>)</A></nobr><br>
    -+<A NAME="P"></A>
    -+<br><font size="+2">P</font>&nbsp;
    -+<a href="#A"><font size="-2">A</font></a> 
    -+<a href="#B"><font size="-2">B</font></a> 
    -+<a href="#C"><font size="-2">C</font></a> 
    -+<a href="#D"><font size="-2">D</font></a> 
    -+<a href="#F"><font size="-2">F</font></a> 
    -+<a href="#G"><font size="-2">G</font></a> 
    -+<a href="#I"><font size="-2">I</font></a> 
    -+<a href="#L"><font size="-2">L</font></a> 
    -+<a href="#M"><font size="-2">M</font></a> 
    -+<a href="#N"><font size="-2">N</font></a> 
    -+<a href="#O"><font size="-2">O</font></a> 
    -+<a href="#R"><font size="-2">R</font></a> 
    -+<a href="#S"><font size="-2">S</font></a> 
    -+<a href="#T"><font size="-2">T</font></a> 
    -+ <a href="#topheader"><font size="-2">TOP</font></a>
    -+<p><div style="line-height:1.5em;color:black">
    -+<nobr><A HREF="android.support.v7.widget.LinearLayoutManager.html#android.support.v7.widget.LinearLayoutManager.prepareForDrop_removed(android.view.View, android.view.View, int, int)" class="hiddenlink" target="rightframe"><strike>prepareForDrop</strike>
    -+(<code>View, View, int, int</code>)</A></nobr><br>
    -+<A NAME="R"></A>
    -+<br><font size="+2">R</font>&nbsp;
    -+<a href="#A"><font size="-2">A</font></a> 
    -+<a href="#B"><font size="-2">B</font></a> 
    -+<a href="#C"><font size="-2">C</font></a> 
    -+<a href="#D"><font size="-2">D</font></a> 
    -+<a href="#F"><font size="-2">F</font></a> 
    -+<a href="#G"><font size="-2">G</font></a> 
    -+<a href="#I"><font size="-2">I</font></a> 
    -+<a href="#L"><font size="-2">L</font></a> 
    -+<a href="#M"><font size="-2">M</font></a> 
    -+<a href="#N"><font size="-2">N</font></a> 
    -+<a href="#O"><font size="-2">O</font></a> 
    -+<a href="#P"><font size="-2">P</font></a> 
    -+<a href="#S"><font size="-2">S</font></a> 
    -+<a href="#T"><font size="-2">T</font></a> 
    -+ <a href="#topheader"><font size="-2">TOP</font></a>
    -+<p><div style="line-height:1.5em;color:black">
    -+<nobr><A HREF="android.support.v4.view.accessibility.AccessibilityManagerCompat.html#android.support.v4.view.accessibility.AccessibilityManagerCompat.removeAccessibilityStateChangeListener_changed(android.view.accessibility.AccessibilityManager, android.support.v4.view.accessibility.AccessibilityManagerCompat.AccessibilityStateChangeListener)" class="hiddenlink" target="rightframe">removeAccessibilityStateChangeListener
    -+(<code>AccessibilityManager, AccessibilityStateChangeListener</code>)</A></nobr><br>
    -+<nobr><A HREF="android.support.v4.view.accessibility.AccessibilityManagerCompat.html#android.support.v4.view.accessibility.AccessibilityManagerCompat.removeTouchExplorationStateChangeListener_added(android.view.accessibility.AccessibilityManager, android.support.v4.view.accessibility.AccessibilityManagerCompat.TouchExplorationStateChangeListener)" class="hiddenlink" target="rightframe"><b>removeTouchExplorationStateChangeListener</b>
    -+(<code>AccessibilityManager, TouchExplorationStateChangeListener</code>)</A></nobr><br>
    -+<nobr><A HREF="android.support.v4.app.ActivityOptionsCompat.html#android.support.v4.app.ActivityOptionsCompat.requestUsageTimeReport_added(android.app.PendingIntent)" class="hiddenlink" target="rightframe"><b>requestUsageTimeReport</b>
    -+(<code>PendingIntent</code>)</A></nobr><br>
    -+<A NAME="S"></A>
    -+<br><font size="+2">S</font>&nbsp;
    -+<a href="#A"><font size="-2">A</font></a> 
    -+<a href="#B"><font size="-2">B</font></a> 
    -+<a href="#C"><font size="-2">C</font></a> 
    -+<a href="#D"><font size="-2">D</font></a> 
    -+<a href="#F"><font size="-2">F</font></a> 
    -+<a href="#G"><font size="-2">G</font></a> 
    -+<a href="#I"><font size="-2">I</font></a> 
    -+<a href="#L"><font size="-2">L</font></a> 
    -+<a href="#M"><font size="-2">M</font></a> 
    -+<a href="#N"><font size="-2">N</font></a> 
    -+<a href="#O"><font size="-2">O</font></a> 
    -+<a href="#P"><font size="-2">P</font></a> 
    -+<a href="#R"><font size="-2">R</font></a> 
    -+<a href="#T"><font size="-2">T</font></a> 
    -+ <a href="#topheader"><font size="-2">TOP</font></a>
    -+<p><div style="line-height:1.5em;color:black">
    -+<nobr><A HREF="android.support.v4.view.accessibility.AccessibilityEventCompat.html#android.support.v4.view.accessibility.AccessibilityEventCompat.setAction_added(android.view.accessibility.AccessibilityEvent, int)" class="hiddenlink" target="rightframe"><b>setAction</b>
    -+(<code>AccessibilityEvent, int</code>)</A></nobr><br>
    -+<nobr><A HREF="android.support.customtabs.CustomTabsIntent.html#android.support.customtabs.CustomTabsIntent.setAlwaysUseBrowserUI_added(android.content.Intent)" class="hiddenlink" target="rightframe"><b>setAlwaysUseBrowserUI</b>
    -+(<code>Intent</code>)</A></nobr><br>
    -+<nobr><A HREF="android.support.design.widget.FloatingActionButton.Behavior.html#android.support.design.widget.FloatingActionButton.Behavior.setAutoHideEnabled_added(boolean)" class="hiddenlink" target="rightframe"><b>setAutoHideEnabled</b>
    -+(<code>boolean</code>)</A></nobr><br>
    -+<nobr><A HREF="android.support.design.widget.CollapsingToolbarLayout.html#android.support.design.widget.CollapsingToolbarLayout.setCollapsedTitleTextColor_added(android.content.res.ColorStateList)" class="hiddenlink" target="rightframe"><b>setCollapsedTitleTextColor</b>
    -+(<code>ColorStateList</code>)</A></nobr><br>
    -+<nobr><A HREF="android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.html#android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.setContextClickable_added(boolean)" class="hiddenlink" target="rightframe"><b>setContextClickable</b>
    -+(<code>boolean</code>)</A></nobr><br>
    -+<nobr><A HREF="android.support.v7.app.ActionBarDrawerToggle.html#android.support.v7.app.ActionBarDrawerToggle.setDrawerArrowDrawable_added(android.support.v7.graphics.drawable.DrawerArrowDrawable)" class="hiddenlink" target="rightframe"><b>setDrawerArrowDrawable</b>
    -+(<code>DrawerArrowDrawable</code>)</A></nobr><br>
    -+<nobr><A HREF="android.support.design.widget.CollapsingToolbarLayout.html#android.support.design.widget.CollapsingToolbarLayout.setExpandedTitleTextColor_added(android.content.res.ColorStateList)" class="hiddenlink" target="rightframe"><b>setExpandedTitleTextColor</b>
    -+(<code>ColorStateList</code>)</A></nobr><br>
    -+<nobr><A HREF="android.support.customtabs.CustomTabsIntent.Builder.html#android.support.customtabs.CustomTabsIntent.Builder.setInstantAppsEnabled_added(boolean)" class="hiddenlink" target="rightframe"><b>setInstantAppsEnabled</b>
    -+(<code>boolean</code>)</A></nobr><br>
    -+<nobr><A HREF="android.support.v4.app.ActivityOptionsCompat.html#android.support.v4.app.ActivityOptionsCompat.setLaunchBounds_added(android.graphics.Rect)" class="hiddenlink" target="rightframe"><b>setLaunchBounds</b>
    -+(<code>Rect</code>)</A></nobr><br>
    -+<nobr><A HREF="android.support.v4.view.accessibility.AccessibilityEventCompat.html#android.support.v4.view.accessibility.AccessibilityEventCompat.setMovementGranularity_added(android.view.accessibility.AccessibilityEvent, int)" class="hiddenlink" target="rightframe"><b>setMovementGranularity</b>
    -+(<code>AccessibilityEvent, int</code>)</A></nobr><br>
    -+<nobr><A HREF="android.support.v4.widget.SwipeRefreshLayout.html#android.support.v4.widget.SwipeRefreshLayout.setOnChildScrollUpCallback_added(android.support.v4.widget.SwipeRefreshLayout.OnChildScrollUpCallback)" class="hiddenlink" target="rightframe"><b>setOnChildScrollUpCallback</b>
    -+(<code>OnChildScrollUpCallback</code>)</A></nobr><br>
    -+<nobr><A HREF="android.support.v4.widget.SearchViewCompat.html#android.support.v4.widget.SearchViewCompat.setOnCloseListener_changed(android.view.View, android.support.v4.widget.SearchViewCompat.OnCloseListener)" class="hiddenlink" target="rightframe">setOnCloseListener
    -+(<code>View, OnCloseListener</code>)</A></nobr><br>
    -+<nobr><A HREF="android.support.v7.widget.RecyclerView.html#android.support.v7.widget.RecyclerView.setOnFlingListener_added(android.support.v7.widget.RecyclerView.OnFlingListener)" class="hiddenlink" target="rightframe"><b>setOnFlingListener</b>
    -+(<code>OnFlingListener</code>)</A></nobr><br>
    -+<nobr><A HREF="android.support.v4.widget.SearchViewCompat.html#android.support.v4.widget.SearchViewCompat.setOnQueryTextListener_changed(android.view.View, android.support.v4.widget.SearchViewCompat.OnQueryTextListener)" class="hiddenlink" target="rightframe">setOnQueryTextListener
    -+(<code>View, OnQueryTextListener</code>)</A></nobr><br>
    -+<nobr><A HREF="android.support.v4.view.ViewCompat.html#android.support.v4.view.ViewCompat.setOverScrollMode_changed(android.view.View, int)" class="hiddenlink" target="rightframe">setOverScrollMode
    -+(<code>View, int</code>)</A></nobr><br>
    -+<i>setPasswordVisibilityToggleContentDescription</i><br>
    -+&nbsp;&nbsp;<nobr><A HREF="android.support.design.widget.TextInputLayout.html#android.support.design.widget.TextInputLayout.setPasswordVisibilityToggleContentDescription_added(int)" class="hiddenlink" target="rightframe">type&nbsp;<b>
    -+(<code>int</code>)</b>&nbsp;in&nbsp;android.support.design.widget.TextInputLayout
    -+</A></nobr><br>
    -+&nbsp;&nbsp;<nobr><A HREF="android.support.design.widget.TextInputLayout.html#android.support.design.widget.TextInputLayout.setPasswordVisibilityToggleContentDescription_added(java.lang.CharSequence)" class="hiddenlink" target="rightframe">type&nbsp;<b>
    -+(<code>CharSequence</code>)</b>&nbsp;in&nbsp;android.support.design.widget.TextInputLayout
    -+</A></nobr><br>
    -+<i>setPasswordVisibilityToggleDrawable</i><br>
    -+&nbsp;&nbsp;<nobr><A HREF="android.support.design.widget.TextInputLayout.html#android.support.design.widget.TextInputLayout.setPasswordVisibilityToggleDrawable_added(android.graphics.drawable.Drawable)" class="hiddenlink" target="rightframe">type&nbsp;<b>
    -+(<code>Drawable</code>)</b>&nbsp;in&nbsp;android.support.design.widget.TextInputLayout
    -+</A></nobr><br>
    -+&nbsp;&nbsp;<nobr><A HREF="android.support.design.widget.TextInputLayout.html#android.support.design.widget.TextInputLayout.setPasswordVisibilityToggleDrawable_added(int)" class="hiddenlink" target="rightframe">type&nbsp;<b>
    -+(<code>int</code>)</b>&nbsp;in&nbsp;android.support.design.widget.TextInputLayout
    -+</A></nobr><br>
    -+<nobr><A HREF="android.support.design.widget.TextInputLayout.html#android.support.design.widget.TextInputLayout.setPasswordVisibilityToggleEnabled_added(boolean)" class="hiddenlink" target="rightframe"><b>setPasswordVisibilityToggleEnabled</b>
    -+(<code>boolean</code>)</A></nobr><br>
    -+<nobr><A HREF="android.support.design.widget.TextInputLayout.html#android.support.design.widget.TextInputLayout.setPasswordVisibilityToggleTintList_added(android.content.res.ColorStateList)" class="hiddenlink" target="rightframe"><b>setPasswordVisibilityToggleTintList</b>
    -+(<code>ColorStateList</code>)</A></nobr><br>
    -+<nobr><A HREF="android.support.design.widget.TextInputLayout.html#android.support.design.widget.TextInputLayout.setPasswordVisibilityToggleTintMode_added(android.graphics.PorterDuff.Mode)" class="hiddenlink" target="rightframe"><b>setPasswordVisibilityToggleTintMode</b>
    -+(<code>Mode</code>)</A></nobr><br>
    -+<nobr><A HREF="android.support.customtabs.CustomTabsSession.html#android.support.customtabs.CustomTabsSession.setSecondaryToolbarViews_added(android.widget.RemoteViews, int[], android.app.PendingIntent)" class="hiddenlink" target="rightframe"><b>setSecondaryToolbarViews</b>
    -+(<code>RemoteViews, int[], PendingIntent</code>)</A></nobr><br>
    -+<nobr><A HREF="android.support.v17.leanback.widget.AbstractMediaItemPresenter.ViewHolder.html#android.support.v17.leanback.widget.AbstractMediaItemPresenter.ViewHolder.setSelectedMediaItemNumberView_added(int)" class="hiddenlink" target="rightframe"><b>setSelectedMediaItemNumberView</b>
    -+(<code>int</code>)</A></nobr><br>
    -+<nobr><A HREF="android.support.customtabs.CustomTabsSession.html#android.support.customtabs.CustomTabsSession.setToolbarItem_changed(int, android.graphics.Bitmap, java.lang.String)" class="hiddenlink" target="rightframe">setToolbarItem
    -+(<code>int, Bitmap, String</code>)</A></nobr><br>
    -+<nobr><A HREF="android.support.customtabs.CustomTabsIntent.html#android.support.customtabs.CustomTabsIntent.shouldAlwaysUseBrowserUI_added(android.content.Intent)" class="hiddenlink" target="rightframe"><b>shouldAlwaysUseBrowserUI</b>
    -+(<code>Intent</code>)</A></nobr><br>
    -+<nobr><A HREF="android.support.v4.view.KeyEventCompat.html#android.support.v4.view.KeyEventCompat.startTracking_changed(android.view.KeyEvent)" class="hiddenlink" target="rightframe">startTracking
    -+(<code>KeyEvent</code>)</A></nobr><br>
    -+<nobr><A HREF="android.support.v4.app.ServiceCompat.html#android.support.v4.app.ServiceCompat.stopForeground_added(android.app.Service, int)" class="hiddenlink" target="rightframe"><b>stopForeground</b>
    -+(<code>Service, int</code>)</A></nobr><br>
    -+<A NAME="T"></A>
    -+<br><font size="+2">T</font>&nbsp;
    -+<a href="#A"><font size="-2">A</font></a> 
    -+<a href="#B"><font size="-2">B</font></a> 
    -+<a href="#C"><font size="-2">C</font></a> 
    -+<a href="#D"><font size="-2">D</font></a> 
    -+<a href="#F"><font size="-2">F</font></a> 
    -+<a href="#G"><font size="-2">G</font></a> 
    -+<a href="#I"><font size="-2">I</font></a> 
    -+<a href="#L"><font size="-2">L</font></a> 
    -+<a href="#M"><font size="-2">M</font></a> 
    -+<a href="#N"><font size="-2">N</font></a> 
    -+<a href="#O"><font size="-2">O</font></a> 
    -+<a href="#P"><font size="-2">P</font></a> 
    -+<a href="#R"><font size="-2">R</font></a> 
    -+<a href="#S"><font size="-2">S</font></a> 
    -+ <a href="#topheader"><font size="-2">TOP</font></a>
    -+<p><div style="line-height:1.5em;color:black">
    -+<nobr><A HREF="android.support.v4.media.session.PlaybackStateCompat.html#android.support.v4.media.session.PlaybackStateCompat.toKeyCode_added(long)" class="hiddenlink" target="rightframe"><b>toKeyCode</b>
    -+(<code>long</code>)</A></nobr><br>
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    -+</script>
    -+<script type="text/javascript">
    -+  try {
    -+    var pageTracker = _gat._getTracker("UA-5831155-1");
    -+    pageTracker._setAllowAnchor(true);
    -+    pageTracker._initData();
    -+    pageTracker._trackPageview();
    -+  } catch(e) {}
    -+</script>
    -+</BODY>
    -+</HTML>
    -diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/methods_index_changes.html b/docs/html/sdk/support_api_diff/24.2.0/changes/methods_index_changes.html
    -new file mode 100644
    -index 0000000..ef008cb
    ---- /dev/null
    -+++ b/docs/html/sdk/support_api_diff/24.2.0/changes/methods_index_changes.html
    -@@ -0,0 +1,222 @@
    -+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
    -+<HTML style="overflow:auto;">
    -+<HEAD>
    -+<meta name="generator" content="JDiff v1.1.0">
    -+<!-- Generated by the JDiff Javadoc doclet -->
    -+<!-- (http://www.jdiff.org) -->
    -+<meta name="description" content="JDiff is a Javadoc doclet which generates an HTML report of all the packages, classes, constructors, methods, and fields which have been removed, added or changed in any way, including their documentation, when two APIs are compared.">
    -+<meta name="keywords" content="diff, jdiff, javadiff, java diff, java difference, API difference, difference between two APIs, API diff, Javadoc, doclet">
    -+<TITLE>
    -+Method Changes Index
    -+</TITLE>
    -+<link href="../../../../assets/android-developer-docs.css" rel="stylesheet" type="text/css" />
    -+<link href="../stylesheet-jdiff.css" rel="stylesheet" type="text/css" />
    -+<noscript>
    -+<style type="text/css">
    -+body{overflow:auto;}
    -+#body-content{position:relative; top:0;}
    -+#doc-content{overflow:visible;border-left:3px solid #666;}
    -+#side-nav{padding:0;}
    -+#side-nav .toggle-list ul {display:block;}
    -+#resize-packages-nav{border-bottom:3px solid #666;}
    -+</style>
    -+</noscript>
    -+<style type="text/css">
    -+</style>
    -+</HEAD>
    -+<BODY class="gc-documentation" style="padding:12px;">
    -+<a NAME="topheader"></a>
    -+<table summary="Index for Methods" width="100%" class="jdiffIndex" border="0" cellspacing="0" cellpadding="0" style="padding-bottom:0;margin-bottom:0;">
    -+  <tr>
    -+  <th class="indexHeader">
    -+    Filter the Index:
    -+  </th>
    -+  </tr>
    -+  <tr>
    -+  <td class="indexText" style="line-height:1.3em;padding-left:2em;">
    -+<a href="methods_index_all.html" class="staysblack">All Methods</a>
    -+  <br>
    -+<A HREF="methods_index_removals.html" xclass="hiddenlink">Removals</A>
    -+  <br>
    -+<A HREF="methods_index_additions.html"xclass="hiddenlink">Additions</A>
    -+  <br>
    -+<b>Changes</b>
    -+  </td>
    -+  </tr>
    -+</table>
    -+<div id="indexTableCaption" style="background-color:#eee;padding:0 4px 0 4px;font-size:11px;margin-bottom:1em;">
    -+Listed as: <span style="color:#069"><strong>Added</strong></span>,  <span style="color:#069"><strike>Removed</strike></span>,  <span style="color:#069">Changed</span></font>
    -+</div>
    -+<A NAME="A"></A>
    -+<br><font size="+2">A</font>&nbsp;
    -+<a href="#C"><font size="-2">C</font></a> 
    -+<a href="#D"><font size="-2">D</font></a> 
    -+<a href="#F"><font size="-2">F</font></a> 
    -+<a href="#G"><font size="-2">G</font></a> 
    -+<a href="#I"><font size="-2">I</font></a> 
    -+<a href="#O"><font size="-2">O</font></a> 
    -+<a href="#R"><font size="-2">R</font></a> 
    -+<a href="#S"><font size="-2">S</font></a> 
    -+ <a href="#topheader"><font size="-2">TOP</font></a>
    -+<p><div style="line-height:1.5em;color:black">
    -+<nobr><A HREF="android.support.v4.view.accessibility.AccessibilityManagerCompat.html#android.support.v4.view.accessibility.AccessibilityManagerCompat.addAccessibilityStateChangeListener_changed(android.view.accessibility.AccessibilityManager, android.support.v4.view.accessibility.AccessibilityManagerCompat.AccessibilityStateChangeListener)" class="hiddenlink" target="rightframe">addAccessibilityStateChangeListener
    -+(<code>AccessibilityManager, AccessibilityStateChangeListener</code>)</A></nobr><br>
    -+<A NAME="C"></A>
    -+<br><font size="+2">C</font>&nbsp;
    -+<a href="#A"><font size="-2">A</font></a> 
    -+<a href="#D"><font size="-2">D</font></a> 
    -+<a href="#F"><font size="-2">F</font></a> 
    -+<a href="#G"><font size="-2">G</font></a> 
    -+<a href="#I"><font size="-2">I</font></a> 
    -+<a href="#O"><font size="-2">O</font></a> 
    -+<a href="#R"><font size="-2">R</font></a> 
    -+<a href="#S"><font size="-2">S</font></a> 
    -+ <a href="#topheader"><font size="-2">TOP</font></a>
    -+<p><div style="line-height:1.5em;color:black">
    -+<nobr><A HREF="android.support.v7.widget.LinearSmoothScroller.html#android.support.v7.widget.LinearSmoothScroller.computeScrollVectorForPosition_changed(int)" class="hiddenlink" target="rightframe">computeScrollVectorForPosition
    -+(<code>int</code>)</A></nobr><br>
    -+<A NAME="D"></A>
    -+<br><font size="+2">D</font>&nbsp;
    -+<a href="#A"><font size="-2">A</font></a> 
    -+<a href="#C"><font size="-2">C</font></a> 
    -+<a href="#F"><font size="-2">F</font></a> 
    -+<a href="#G"><font size="-2">G</font></a> 
    -+<a href="#I"><font size="-2">I</font></a> 
    -+<a href="#O"><font size="-2">O</font></a> 
    -+<a href="#R"><font size="-2">R</font></a> 
    -+<a href="#S"><font size="-2">S</font></a> 
    -+ <a href="#topheader"><font size="-2">TOP</font></a>
    -+<p><div style="line-height:1.5em;color:black">
    -+<nobr><A HREF="android.support.v4.view.KeyEventCompat.html#android.support.v4.view.KeyEventCompat.dispatch_changed(android.view.KeyEvent, android.view.KeyEvent.Callback, java.lang.Object, java.lang.Object)" class="hiddenlink" target="rightframe">dispatch
    -+(<code>KeyEvent, Callback, Object, Object</code>)</A></nobr><br>
    -+<A NAME="F"></A>
    -+<br><font size="+2">F</font>&nbsp;
    -+<a href="#A"><font size="-2">A</font></a> 
    -+<a href="#C"><font size="-2">C</font></a> 
    -+<a href="#D"><font size="-2">D</font></a> 
    -+<a href="#G"><font size="-2">G</font></a> 
    -+<a href="#I"><font size="-2">I</font></a> 
    -+<a href="#O"><font size="-2">O</font></a> 
    -+<a href="#R"><font size="-2">R</font></a> 
    -+<a href="#S"><font size="-2">S</font></a> 
    -+ <a href="#topheader"><font size="-2">TOP</font></a>
    -+<p><div style="line-height:1.5em;color:black">
    -+<nobr><A HREF="android.support.v4.view.MotionEventCompat.html#android.support.v4.view.MotionEventCompat.findPointerIndex_changed(android.view.MotionEvent, int)" class="hiddenlink" target="rightframe">findPointerIndex
    -+(<code>MotionEvent, int</code>)</A></nobr><br>
    -+<A NAME="G"></A>
    -+<br><font size="+2">G</font>&nbsp;
    -+<a href="#A"><font size="-2">A</font></a> 
    -+<a href="#C"><font size="-2">C</font></a> 
    -+<a href="#D"><font size="-2">D</font></a> 
    -+<a href="#F"><font size="-2">F</font></a> 
    -+<a href="#I"><font size="-2">I</font></a> 
    -+<a href="#O"><font size="-2">O</font></a> 
    -+<a href="#R"><font size="-2">R</font></a> 
    -+<a href="#S"><font size="-2">S</font></a> 
    -+ <a href="#topheader"><font size="-2">TOP</font></a>
    -+<p><div style="line-height:1.5em;color:black">
    -+<nobr><A HREF="android.support.v4.accessibilityservice.AccessibilityServiceInfoCompat.html#android.support.v4.accessibilityservice.AccessibilityServiceInfoCompat.getDescription_changed(android.accessibilityservice.AccessibilityServiceInfo)" class="hiddenlink" target="rightframe">getDescription
    -+(<code>AccessibilityServiceInfo</code>)</A></nobr><br>
    -+<nobr><A HREF="android.support.v4.view.KeyEventCompat.html#android.support.v4.view.KeyEventCompat.getKeyDispatcherState_changed(android.view.View)" class="hiddenlink" target="rightframe">getKeyDispatcherState
    -+(<code>View</code>)</A></nobr><br>
    -+<nobr><A HREF="android.support.v4.view.ViewCompat.html#android.support.v4.view.ViewCompat.getOverScrollMode_changed(android.view.View)" class="hiddenlink" target="rightframe">getOverScrollMode
    -+(<code>View</code>)</A></nobr><br>
    -+<nobr><A HREF="android.support.v4.view.MotionEventCompat.html#android.support.v4.view.MotionEventCompat.getPointerCount_changed(android.view.MotionEvent)" class="hiddenlink" target="rightframe">getPointerCount
    -+(<code>MotionEvent</code>)</A></nobr><br>
    -+<nobr><A HREF="android.support.v4.view.MotionEventCompat.html#android.support.v4.view.MotionEventCompat.getPointerId_changed(android.view.MotionEvent, int)" class="hiddenlink" target="rightframe">getPointerId
    -+(<code>MotionEvent, int</code>)</A></nobr><br>
    -+<nobr><A HREF="android.support.v4.app.ActivityCompat.html#android.support.v4.app.ActivityCompat.getReferrer_changed(android.app.Activity)" class="hiddenlink" target="rightframe">getReferrer
    -+(<code>Activity</code>)</A></nobr><br>
    -+<nobr><A HREF="android.support.v4.view.ViewConfigurationCompat.html#android.support.v4.view.ViewConfigurationCompat.getScaledPagingTouchSlop_changed(android.view.ViewConfiguration)" class="hiddenlink" target="rightframe">getScaledPagingTouchSlop
    -+(<code>ViewConfiguration</code>)</A></nobr><br>
    -+<nobr><A HREF="android.support.v4.view.MotionEventCompat.html#android.support.v4.view.MotionEventCompat.getSource_changed(android.view.MotionEvent)" class="hiddenlink" target="rightframe">getSource
    -+(<code>MotionEvent</code>)</A></nobr><br>
    -+<nobr><A HREF="android.support.v4.view.MotionEventCompat.html#android.support.v4.view.MotionEventCompat.getX_changed(android.view.MotionEvent, int)" class="hiddenlink" target="rightframe">getX
    -+(<code>MotionEvent, int</code>)</A></nobr><br>
    -+<nobr><A HREF="android.support.v4.view.MotionEventCompat.html#android.support.v4.view.MotionEventCompat.getY_changed(android.view.MotionEvent, int)" class="hiddenlink" target="rightframe">getY
    -+(<code>MotionEvent, int</code>)</A></nobr><br>
    -+<A NAME="I"></A>
    -+<br><font size="+2">I</font>&nbsp;
    -+<a href="#A"><font size="-2">A</font></a> 
    -+<a href="#C"><font size="-2">C</font></a> 
    -+<a href="#D"><font size="-2">D</font></a> 
    -+<a href="#F"><font size="-2">F</font></a> 
    -+<a href="#G"><font size="-2">G</font></a> 
    -+<a href="#O"><font size="-2">O</font></a> 
    -+<a href="#R"><font size="-2">R</font></a> 
    -+<a href="#S"><font size="-2">S</font></a> 
    -+ <a href="#topheader"><font size="-2">TOP</font></a>
    -+<p><div style="line-height:1.5em;color:black">
    -+<nobr><A HREF="android.support.design.widget.CoordinatorLayout.Behavior.html#android.support.design.widget.CoordinatorLayout.Behavior.isDirty_changed(android.support.design.widget.CoordinatorLayout, V)" class="hiddenlink" target="rightframe">isDirty
    -+(<code>CoordinatorLayout, V</code>)</A></nobr><br>
    -+<nobr><A HREF="android.support.v4.view.ViewCompat.html#android.support.v4.view.ViewCompat.isOpaque_changed(android.view.View)" class="hiddenlink" target="rightframe">isOpaque
    -+(<code>View</code>)</A></nobr><br>
    -+<nobr><A HREF="android.support.v4.view.KeyEventCompat.html#android.support.v4.view.KeyEventCompat.isTracking_changed(android.view.KeyEvent)" class="hiddenlink" target="rightframe">isTracking
    -+(<code>KeyEvent</code>)</A></nobr><br>
    -+<A NAME="O"></A>
    -+<br><font size="+2">O</font>&nbsp;
    -+<a href="#A"><font size="-2">A</font></a> 
    -+<a href="#C"><font size="-2">C</font></a> 
    -+<a href="#D"><font size="-2">D</font></a> 
    -+<a href="#F"><font size="-2">F</font></a> 
    -+<a href="#G"><font size="-2">G</font></a> 
    -+<a href="#I"><font size="-2">I</font></a> 
    -+<a href="#R"><font size="-2">R</font></a> 
    -+<a href="#S"><font size="-2">S</font></a> 
    -+ <a href="#topheader"><font size="-2">TOP</font></a>
    -+<p><div style="line-height:1.5em;color:black">
    -+<i>obtain</i><br>
    -+&nbsp;&nbsp;<nobr><A HREF="android.support.v4.media.session.MediaSessionCompat.html#android.support.v4.media.session.MediaSessionCompat.obtain_changed(android.content.Context, java.lang.Object)" class="hiddenlink" target="rightframe">type&nbsp;
    -+(<code>Context, Object</code>)&nbsp;in&nbsp;android.support.v4.media.session.MediaSessionCompat
    -+</A></nobr><br>
    -+&nbsp;&nbsp;<nobr><A HREF="android.support.v4.media.session.MediaSessionCompat.QueueItem.html#android.support.v4.media.session.MediaSessionCompat.QueueItem.obtain_changed(java.lang.Object)" class="hiddenlink" target="rightframe">type&nbsp;
    -+(<code>Object</code>)&nbsp;in&nbsp;android.support.v4.media.session.MediaSessionCompat.QueueItem
    -+</A></nobr><br>
    -+<A NAME="R"></A>
    -+<br><font size="+2">R</font>&nbsp;
    -+<a href="#A"><font size="-2">A</font></a> 
    -+<a href="#C"><font size="-2">C</font></a> 
    -+<a href="#D"><font size="-2">D</font></a> 
    -+<a href="#F"><font size="-2">F</font></a> 
    -+<a href="#G"><font size="-2">G</font></a> 
    -+<a href="#I"><font size="-2">I</font></a> 
    -+<a href="#O"><font size="-2">O</font></a> 
    -+<a href="#S"><font size="-2">S</font></a> 
    -+ <a href="#topheader"><font size="-2">TOP</font></a>
    -+<p><div style="line-height:1.5em;color:black">
    -+<nobr><A HREF="android.support.v4.view.accessibility.AccessibilityManagerCompat.html#android.support.v4.view.accessibility.AccessibilityManagerCompat.removeAccessibilityStateChangeListener_changed(android.view.accessibility.AccessibilityManager, android.support.v4.view.accessibility.AccessibilityManagerCompat.AccessibilityStateChangeListener)" class="hiddenlink" target="rightframe">removeAccessibilityStateChangeListener
    -+(<code>AccessibilityManager, AccessibilityStateChangeListener</code>)</A></nobr><br>
    -+<A NAME="S"></A>
    -+<br><font size="+2">S</font>&nbsp;
    -+<a href="#A"><font size="-2">A</font></a> 
    -+<a href="#C"><font size="-2">C</font></a> 
    -+<a href="#D"><font size="-2">D</font></a> 
    -+<a href="#F"><font size="-2">F</font></a> 
    -+<a href="#G"><font size="-2">G</font></a> 
    -+<a href="#I"><font size="-2">I</font></a> 
    -+<a href="#O"><font size="-2">O</font></a> 
    -+<a href="#R"><font size="-2">R</font></a> 
    -+ <a href="#topheader"><font size="-2">TOP</font></a>
    -+<p><div style="line-height:1.5em;color:black">
    -+<nobr><A HREF="android.support.v4.widget.SearchViewCompat.html#android.support.v4.widget.SearchViewCompat.setOnCloseListener_changed(android.view.View, android.support.v4.widget.SearchViewCompat.OnCloseListener)" class="hiddenlink" target="rightframe">setOnCloseListener
    -+(<code>View, OnCloseListener</code>)</A></nobr><br>
    -+<nobr><A HREF="android.support.v4.widget.SearchViewCompat.html#android.support.v4.widget.SearchViewCompat.setOnQueryTextListener_changed(android.view.View, android.support.v4.widget.SearchViewCompat.OnQueryTextListener)" class="hiddenlink" target="rightframe">setOnQueryTextListener
    -+(<code>View, OnQueryTextListener</code>)</A></nobr><br>
    -+<nobr><A HREF="android.support.v4.view.ViewCompat.html#android.support.v4.view.ViewCompat.setOverScrollMode_changed(android.view.View, int)" class="hiddenlink" target="rightframe">setOverScrollMode
    -+(<code>View, int</code>)</A></nobr><br>
    -+<nobr><A HREF="android.support.customtabs.CustomTabsSession.html#android.support.customtabs.CustomTabsSession.setToolbarItem_changed(int, android.graphics.Bitmap, java.lang.String)" class="hiddenlink" target="rightframe">setToolbarItem
    -+(<code>int, Bitmap, String</code>)</A></nobr><br>
    -+<nobr><A HREF="android.support.v4.view.KeyEventCompat.html#android.support.v4.view.KeyEventCompat.startTracking_changed(android.view.KeyEvent)" class="hiddenlink" target="rightframe">startTracking
    -+(<code>KeyEvent</code>)</A></nobr><br>
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    -+</script>
    -+<script type="text/javascript">
    -+  try {
    -+    var pageTracker = _gat._getTracker("UA-5831155-1");
    -+    pageTracker._setAllowAnchor(true);
    -+    pageTracker._initData();
    -+    pageTracker._trackPageview();
    -+  } catch(e) {}
    -+</script>
    -+</BODY>
    -+</HTML>
    -diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/methods_index_removals.html b/docs/html/sdk/support_api_diff/24.2.0/changes/methods_index_removals.html
    -new file mode 100644
    -index 0000000..1c0c6be
    ---- /dev/null
    -+++ b/docs/html/sdk/support_api_diff/24.2.0/changes/methods_index_removals.html
    -@@ -0,0 +1,93 @@
    -+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
    -+<HTML style="overflow:auto;">
    -+<HEAD>
    -+<meta name="generator" content="JDiff v1.1.0">
    -+<!-- Generated by the JDiff Javadoc doclet -->
    -+<!-- (http://www.jdiff.org) -->
    -+<meta name="description" content="JDiff is a Javadoc doclet which generates an HTML report of all the packages, classes, constructors, methods, and fields which have been removed, added or changed in any way, including their documentation, when two APIs are compared.">
    -+<meta name="keywords" content="diff, jdiff, javadiff, java diff, java difference, API difference, difference between two APIs, API diff, Javadoc, doclet">
    -+<TITLE>
    -+Method Removals Index
    -+</TITLE>
    -+<link href="../../../../assets/android-developer-docs.css" rel="stylesheet" type="text/css" />
    -+<link href="../stylesheet-jdiff.css" rel="stylesheet" type="text/css" />
    -+<noscript>
    -+<style type="text/css">
    -+body{overflow:auto;}
    -+#body-content{position:relative; top:0;}
    -+#doc-content{overflow:visible;border-left:3px solid #666;}
    -+#side-nav{padding:0;}
    -+#side-nav .toggle-list ul {display:block;}
    -+#resize-packages-nav{border-bottom:3px solid #666;}
    -+</style>
    -+</noscript>
    -+<style type="text/css">
    -+</style>
    -+</HEAD>
    -+<BODY class="gc-documentation" style="padding:12px;">
    -+<a NAME="topheader"></a>
    -+<table summary="Index for Methods" width="100%" class="jdiffIndex" border="0" cellspacing="0" cellpadding="0" style="padding-bottom:0;margin-bottom:0;">
    -+  <tr>
    -+  <th class="indexHeader">
    -+    Filter the Index:
    -+  </th>
    -+  </tr>
    -+  <tr>
    -+  <td class="indexText" style="line-height:1.3em;padding-left:2em;">
    -+<a href="methods_index_all.html" class="staysblack">All Methods</a>
    -+  <br>
    -+<b>Removals</b>
    -+  <br>
    -+<A HREF="methods_index_additions.html"xclass="hiddenlink">Additions</A>
    -+  <br>
    -+<A HREF="methods_index_changes.html"xclass="hiddenlink">Changes</A>
    -+  </td>
    -+  </tr>
    -+</table>
    -+<div id="indexTableCaption" style="background-color:#eee;padding:0 4px 0 4px;font-size:11px;margin-bottom:1em;">
    -+Listed as: <span style="color:#069"><strong>Added</strong></span>,  <span style="color:#069"><strike>Removed</strike></span>,  <span style="color:#069">Changed</span></font>
    -+</div>
    -+<A NAME="L"></A>
    -+<br><font size="+2">L</font>&nbsp;
    -+<a href="#O"><font size="-2">O</font></a> 
    -+<a href="#P"><font size="-2">P</font></a> 
    -+ <a href="#topheader"><font size="-2">TOP</font></a>
    -+<p><div style="line-height:1.5em;color:black">
    -+<nobr><A HREF="android.support.design.widget.FloatingActionButton.Behavior.html#android.support.design.widget.FloatingActionButton.Behavior.layoutDependsOn_removed(android.support.design.widget.CoordinatorLayout, android.support.design.widget.FloatingActionButton, android.view.View)" class="hiddenlink" target="rightframe"><strike>layoutDependsOn</strike>
    -+(<code>CoordinatorLayout, FloatingActionButton, View</code>)</A></nobr><br>
    -+<A NAME="O"></A>
    -+<br><font size="+2">O</font>&nbsp;
    -+<a href="#L"><font size="-2">L</font></a> 
    -+<a href="#P"><font size="-2">P</font></a> 
    -+ <a href="#topheader"><font size="-2">TOP</font></a>
    -+<p><div style="line-height:1.5em;color:black">
    -+<nobr><A HREF="android.support.v4.view.accessibility.AccessibilityManagerCompat.AccessibilityStateChangeListenerCompat.html#android.support.v4.view.accessibility.AccessibilityManagerCompat.AccessibilityStateChangeListenerCompat.onAccessibilityStateChanged_removed(boolean)" class="hiddenlink" target="rightframe"><strike>onAccessibilityStateChanged</strike>
    -+(<code>boolean</code>)</A></nobr><br>
    -+<nobr><A HREF="android.support.design.widget.FloatingActionButton.Behavior.html#android.support.design.widget.FloatingActionButton.Behavior.onDependentViewRemoved_removed(android.support.design.widget.CoordinatorLayout, android.support.design.widget.FloatingActionButton, android.view.View)" class="hiddenlink" target="rightframe"><strike>onDependentViewRemoved</strike>
    -+(<code>CoordinatorLayout, FloatingActionButton, View</code>)</A></nobr><br>
    -+<nobr><A HREF="android.support.v7.util.SortedList.Callback.html#android.support.v7.util.SortedList.Callback.onInserted_removed(int, int)" class="hiddenlink" target="rightframe"><strike>onInserted</strike>
    -+(<code>int, int</code>)</A></nobr><br>
    -+<nobr><A HREF="android.support.v7.util.SortedList.Callback.html#android.support.v7.util.SortedList.Callback.onMoved_removed(int, int)" class="hiddenlink" target="rightframe"><strike>onMoved</strike>
    -+(<code>int, int</code>)</A></nobr><br>
    -+<nobr><A HREF="android.support.v7.util.SortedList.Callback.html#android.support.v7.util.SortedList.Callback.onRemoved_removed(int, int)" class="hiddenlink" target="rightframe"><strike>onRemoved</strike>
    -+(<code>int, int</code>)</A></nobr><br>
    -+<A NAME="P"></A>
    -+<br><font size="+2">P</font>&nbsp;
    -+<a href="#L"><font size="-2">L</font></a> 
    -+<a href="#O"><font size="-2">O</font></a> 
    -+ <a href="#topheader"><font size="-2">TOP</font></a>
    -+<p><div style="line-height:1.5em;color:black">
    -+<nobr><A HREF="android.support.v7.widget.LinearLayoutManager.html#android.support.v7.widget.LinearLayoutManager.prepareForDrop_removed(android.view.View, android.view.View, int, int)" class="hiddenlink" target="rightframe"><strike>prepareForDrop</strike>
    -+(<code>View, View, int, int</code>)</A></nobr><br>
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    -+</script>
    -+<script type="text/javascript">
    -+  try {
    -+    var pageTracker = _gat._getTracker("UA-5831155-1");
    -+    pageTracker._setAllowAnchor(true);
    -+    pageTracker._initData();
    -+    pageTracker._trackPageview();
    -+  } catch(e) {}
    -+</script>
    -+</BODY>
    -+</HTML>
    -diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/packages_index_additions.html b/docs/html/sdk/support_api_diff/24.2.0/changes/packages_index_additions.html
    -new file mode 100644
    -index 0000000..bb88d9f
    ---- /dev/null
    -+++ b/docs/html/sdk/support_api_diff/24.2.0/changes/packages_index_additions.html
    -@@ -0,0 +1,66 @@
    -+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
    -+<HTML style="overflow:auto;">
    -+<HEAD>
    -+<meta name="generator" content="JDiff v1.1.0">
    -+<!-- Generated by the JDiff Javadoc doclet -->
    -+<!-- (http://www.jdiff.org) -->
    -+<meta name="description" content="JDiff is a Javadoc doclet which generates an HTML report of all the packages, classes, constructors, methods, and fields which have been removed, added or changed in any way, including their documentation, when two APIs are compared.">
    -+<meta name="keywords" content="diff, jdiff, javadiff, java diff, java difference, API difference, difference between two APIs, API diff, Javadoc, doclet">
    -+<TITLE>
    -+Package Additions Index
    -+</TITLE>
    -+<link href="../../../../assets/android-developer-docs.css" rel="stylesheet" type="text/css" />
    -+<link href="../stylesheet-jdiff.css" rel="stylesheet" type="text/css" />
    -+<noscript>
    -+<style type="text/css">
    -+body{overflow:auto;}
    -+#body-content{position:relative; top:0;}
    -+#doc-content{overflow:visible;border-left:3px solid #666;}
    -+#side-nav{padding:0;}
    -+#side-nav .toggle-list ul {display:block;}
    -+#resize-packages-nav{border-bottom:3px solid #666;}
    -+</style>
    -+</noscript>
    -+<style type="text/css">
    -+</style>
    -+</HEAD>
    -+<BODY class="gc-documentation" style="padding:12px;">
    -+<a NAME="topheader"></a>
    -+<table summary="Index for Packages" width="100%" class="jdiffIndex" border="0" cellspacing="0" cellpadding="0" style="padding-bottom:0;margin-bottom:0;">
    -+  <tr>
    -+  <th class="indexHeader">
    -+    Filter the Index:
    -+  </th>
    -+  </tr>
    -+  <tr>
    -+  <td class="indexText" style="line-height:1.3em;padding-left:2em;">
    -+<a href="packages_index_all.html" class="staysblack">All Packages</a>
    -+  <br>
    -+<A HREF="packages_index_removals.html" xclass="hiddenlink">Removals</A>
    -+  <br>
    -+<b>Additions</b>
    -+  <br>
    -+<A HREF="packages_index_changes.html"xclass="hiddenlink">Changes</A>
    -+  </td>
    -+  </tr>
    -+</table>
    -+<div id="indexTableCaption" style="background-color:#eee;padding:0 4px 0 4px;font-size:11px;margin-bottom:1em;">
    -+Listed as: <span style="color:#069"><strong>Added</strong></span>,  <span style="color:#069"><strike>Removed</strike></span>,  <span style="color:#069">Changed</span></font>
    -+</div>
    -+<br>
    -+<div id="indexTableEntries">
    -+<A NAME="A"></A>
    -+<A HREF="changes-summary.html#android.support.transition" class="hiddenlink" target="rightframe"><b>android.support.transition</b></A><br>
    -+<A HREF="changes-summary.html#android.support.v4.text.util" class="hiddenlink" target="rightframe"><b>android.support.v4.text.util</b></A><br>
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    -+</script>
    -+<script type="text/javascript">
    -+  try {
    -+    var pageTracker = _gat._getTracker("UA-5831155-1");
    -+    pageTracker._setAllowAnchor(true);
    -+    pageTracker._initData();
    -+    pageTracker._trackPageview();
    -+  } catch(e) {}
    -+</script>
    -+</BODY>
    -+</HTML>
    -diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/packages_index_all.html b/docs/html/sdk/support_api_diff/24.2.0/changes/packages_index_all.html
    -new file mode 100644
    -index 0000000..78805db
    ---- /dev/null
    -+++ b/docs/html/sdk/support_api_diff/24.2.0/changes/packages_index_all.html
    -@@ -0,0 +1,91 @@
    -+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
    -+<HTML style="overflow:auto;">
    -+<HEAD>
    -+<meta name="generator" content="JDiff v1.1.0">
    -+<!-- Generated by the JDiff Javadoc doclet -->
    -+<!-- (http://www.jdiff.org) -->
    -+<meta name="description" content="JDiff is a Javadoc doclet which generates an HTML report of all the packages, classes, constructors, methods, and fields which have been removed, added or changed in any way, including their documentation, when two APIs are compared.">
    -+<meta name="keywords" content="diff, jdiff, javadiff, java diff, java difference, API difference, difference between two APIs, API diff, Javadoc, doclet">
    -+<TITLE>
    -+Package Differences Index
    -+</TITLE>
    -+<link href="../../../../assets/android-developer-docs.css" rel="stylesheet" type="text/css" />
    -+<link href="../stylesheet-jdiff.css" rel="stylesheet" type="text/css" />
    -+<noscript>
    -+<style type="text/css">
    -+body{overflow:auto;}
    -+#body-content{position:relative; top:0;}
    -+#doc-content{overflow:visible;border-left:3px solid #666;}
    -+#side-nav{padding:0;}
    -+#side-nav .toggle-list ul {display:block;}
    -+#resize-packages-nav{border-bottom:3px solid #666;}
    -+</style>
    -+</noscript>
    -+<style type="text/css">
    -+</style>
    -+</HEAD>
    -+<BODY class="gc-documentation" style="padding:12px;">
    -+<a NAME="topheader"></a>
    -+<table summary="Index for Packages" width="100%" class="jdiffIndex" border="0" cellspacing="0" cellpadding="0" style="padding-bottom:0;margin-bottom:0;">
    -+  <tr>
    -+  <th class="indexHeader">
    -+    Filter the Index:
    -+  </th>
    -+  </tr>
    -+  <tr>
    -+  <td class="indexText" style="line-height:1.3em;padding-left:2em;">
    -+<b>Packages</b>
    -+  <br>
    -+<A HREF="packages_index_removals.html" xclass="hiddenlink">Removals</A>
    -+  <br>
    -+<A HREF="packages_index_additions.html"xclass="hiddenlink">Additions</A>
    -+  <br>
    -+<A HREF="packages_index_changes.html"xclass="hiddenlink">Changes</A>
    -+  </td>
    -+  </tr>
    -+</table>
    -+<div id="indexTableCaption" style="background-color:#eee;padding:0 4px 0 4px;font-size:11px;margin-bottom:1em;">
    -+Listed as: <span style="color:#069"><strong>Added</strong></span>,  <span style="color:#069"><strike>Removed</strike></span>,  <span style="color:#069">Changed</span></font>
    -+</div>
    -+<br>
    -+<div id="indexTableEntries">
    -+<A NAME="A"></A>
    -+<A HREF="pkg_android.support.customtabs.html" class="hiddenlink" target="rightframe">android.support.customtabs</A><br>
    -+<A HREF="pkg_android.support.design.widget.html" class="hiddenlink" target="rightframe">android.support.design.widget</A><br>
    -+<A HREF="changes-summary.html#android.support.transition" class="hiddenlink" target="rightframe"><b>android.support.transition</b></A><br>
    -+<A HREF="pkg_android.support.v14.preference.html" class="hiddenlink" target="rightframe">android.support.v14.preference</A><br>
    -+<A HREF="pkg_android.support.v17.leanback.widget.html" class="hiddenlink" target="rightframe">android.support.v17.leanback.widget</A><br>
    -+<A HREF="pkg_android.support.v17.preference.html" class="hiddenlink" target="rightframe">android.support.v17.preference</A><br>
    -+<A HREF="pkg_android.support.v4.accessibilityservice.html" class="hiddenlink" target="rightframe">android.support.v4.accessibilityservice</A><br>
    -+<A HREF="pkg_android.support.v4.app.html" class="hiddenlink" target="rightframe">android.support.v4.app</A><br>
    -+<A HREF="pkg_android.support.v4.content.html" class="hiddenlink" target="rightframe">android.support.v4.content</A><br>
    -+<A HREF="pkg_android.support.v4.graphics.drawable.html" class="hiddenlink" target="rightframe">android.support.v4.graphics.drawable</A><br>
    -+<A HREF="pkg_android.support.v4.media.html" class="hiddenlink" target="rightframe">android.support.v4.media</A><br>
    -+<A HREF="pkg_android.support.v4.media.session.html" class="hiddenlink" target="rightframe">android.support.v4.media.session</A><br>
    -+<A HREF="pkg_android.support.v4.os.html" class="hiddenlink" target="rightframe">android.support.v4.os</A><br>
    -+<A HREF="changes-summary.html#android.support.v4.text.util" class="hiddenlink" target="rightframe"><b>android.support.v4.text.util</b></A><br>
    -+<A HREF="pkg_android.support.v4.util.html" class="hiddenlink" target="rightframe">android.support.v4.util</A><br>
    -+<A HREF="pkg_android.support.v4.view.html" class="hiddenlink" target="rightframe">android.support.v4.view</A><br>
    -+<A HREF="pkg_android.support.v4.view.accessibility.html" class="hiddenlink" target="rightframe">android.support.v4.view.accessibility</A><br>
    -+<A HREF="pkg_android.support.v4.widget.html" class="hiddenlink" target="rightframe">android.support.v4.widget</A><br>
    -+<A HREF="pkg_android.support.v7.app.html" class="hiddenlink" target="rightframe">android.support.v7.app</A><br>
    -+<A HREF="changes-summary.html#android.support.v7.appcompat" class="hiddenlink" target="rightframe"><strike>android.support.v7.appcompat</strike></A><br>
    -+<A HREF="pkg_android.support.v7.content.res.html" class="hiddenlink" target="rightframe">android.support.v7.content.res</A><br>
    -+<A HREF="pkg_android.support.v7.graphics.html" class="hiddenlink" target="rightframe">android.support.v7.graphics</A><br>
    -+<A HREF="pkg_android.support.v7.preference.html" class="hiddenlink" target="rightframe">android.support.v7.preference</A><br>
    -+<A HREF="changes-summary.html#android.support.v7.recyclerview" class="hiddenlink" target="rightframe"><strike>android.support.v7.recyclerview</strike></A><br>
    -+<A HREF="pkg_android.support.v7.util.html" class="hiddenlink" target="rightframe">android.support.v7.util</A><br>
    -+<A HREF="pkg_android.support.v7.widget.html" class="hiddenlink" target="rightframe">android.support.v7.widget</A><br>
    -+<A HREF="changes-summary.html#android.support.v8.renderscript" class="hiddenlink" target="rightframe"><strike>android.support.v8.renderscript</strike></A><br>
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    -+</script>
    -+<script type="text/javascript">
    -+  try {
    -+    var pageTracker = _gat._getTracker("UA-5831155-1");
    -+    pageTracker._setAllowAnchor(true);
    -+    pageTracker._initData();
    -+    pageTracker._trackPageview();
    -+  } catch(e) {}
    -+</script>
    -+</BODY>
    -+</HTML>
    -diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/packages_index_changes.html b/docs/html/sdk/support_api_diff/24.2.0/changes/packages_index_changes.html
    -new file mode 100644
    -index 0000000..f5f6425
    ---- /dev/null
    -+++ b/docs/html/sdk/support_api_diff/24.2.0/changes/packages_index_changes.html
    -@@ -0,0 +1,86 @@
    -+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
    -+<HTML style="overflow:auto;">
    -+<HEAD>
    -+<meta name="generator" content="JDiff v1.1.0">
    -+<!-- Generated by the JDiff Javadoc doclet -->
    -+<!-- (http://www.jdiff.org) -->
    -+<meta name="description" content="JDiff is a Javadoc doclet which generates an HTML report of all the packages, classes, constructors, methods, and fields which have been removed, added or changed in any way, including their documentation, when two APIs are compared.">
    -+<meta name="keywords" content="diff, jdiff, javadiff, java diff, java difference, API difference, difference between two APIs, API diff, Javadoc, doclet">
    -+<TITLE>
    -+Package Changes Index
    -+</TITLE>
    -+<link href="../../../../assets/android-developer-docs.css" rel="stylesheet" type="text/css" />
    -+<link href="../stylesheet-jdiff.css" rel="stylesheet" type="text/css" />
    -+<noscript>
    -+<style type="text/css">
    -+body{overflow:auto;}
    -+#body-content{position:relative; top:0;}
    -+#doc-content{overflow:visible;border-left:3px solid #666;}
    -+#side-nav{padding:0;}
    -+#side-nav .toggle-list ul {display:block;}
    -+#resize-packages-nav{border-bottom:3px solid #666;}
    -+</style>
    -+</noscript>
    -+<style type="text/css">
    -+</style>
    -+</HEAD>
    -+<BODY class="gc-documentation" style="padding:12px;">
    -+<a NAME="topheader"></a>
    -+<table summary="Index for Packages" width="100%" class="jdiffIndex" border="0" cellspacing="0" cellpadding="0" style="padding-bottom:0;margin-bottom:0;">
    -+  <tr>
    -+  <th class="indexHeader">
    -+    Filter the Index:
    -+  </th>
    -+  </tr>
    -+  <tr>
    -+  <td class="indexText" style="line-height:1.3em;padding-left:2em;">
    -+<a href="packages_index_all.html" class="staysblack">All Packages</a>
    -+  <br>
    -+<A HREF="packages_index_removals.html" xclass="hiddenlink">Removals</A>
    -+  <br>
    -+<A HREF="packages_index_additions.html"xclass="hiddenlink">Additions</A>
    -+  <br>
    -+<b>Changes</b>
    -+  </td>
    -+  </tr>
    -+</table>
    -+<div id="indexTableCaption" style="background-color:#eee;padding:0 4px 0 4px;font-size:11px;margin-bottom:1em;">
    -+Listed as: <span style="color:#069"><strong>Added</strong></span>,  <span style="color:#069"><strike>Removed</strike></span>,  <span style="color:#069">Changed</span></font>
    -+</div>
    -+<br>
    -+<div id="indexTableEntries">
    -+<A NAME="A"></A>
    -+<A HREF="pkg_android.support.customtabs.html" class="hiddenlink" target="rightframe">android.support.customtabs</A><br>
    -+<A HREF="pkg_android.support.design.widget.html" class="hiddenlink" target="rightframe">android.support.design.widget</A><br>
    -+<A HREF="pkg_android.support.v14.preference.html" class="hiddenlink" target="rightframe">android.support.v14.preference</A><br>
    -+<A HREF="pkg_android.support.v17.leanback.widget.html" class="hiddenlink" target="rightframe">android.support.v17.leanback.widget</A><br>
    -+<A HREF="pkg_android.support.v17.preference.html" class="hiddenlink" target="rightframe">android.support.v17.preference</A><br>
    -+<A HREF="pkg_android.support.v4.accessibilityservice.html" class="hiddenlink" target="rightframe">android.support.v4.accessibilityservice</A><br>
    -+<A HREF="pkg_android.support.v4.app.html" class="hiddenlink" target="rightframe">android.support.v4.app</A><br>
    -+<A HREF="pkg_android.support.v4.content.html" class="hiddenlink" target="rightframe">android.support.v4.content</A><br>
    -+<A HREF="pkg_android.support.v4.graphics.drawable.html" class="hiddenlink" target="rightframe">android.support.v4.graphics.drawable</A><br>
    -+<A HREF="pkg_android.support.v4.media.html" class="hiddenlink" target="rightframe">android.support.v4.media</A><br>
    -+<A HREF="pkg_android.support.v4.media.session.html" class="hiddenlink" target="rightframe">android.support.v4.media.session</A><br>
    -+<A HREF="pkg_android.support.v4.os.html" class="hiddenlink" target="rightframe">android.support.v4.os</A><br>
    -+<A HREF="pkg_android.support.v4.util.html" class="hiddenlink" target="rightframe">android.support.v4.util</A><br>
    -+<A HREF="pkg_android.support.v4.view.html" class="hiddenlink" target="rightframe">android.support.v4.view</A><br>
    -+<A HREF="pkg_android.support.v4.view.accessibility.html" class="hiddenlink" target="rightframe">android.support.v4.view.accessibility</A><br>
    -+<A HREF="pkg_android.support.v4.widget.html" class="hiddenlink" target="rightframe">android.support.v4.widget</A><br>
    -+<A HREF="pkg_android.support.v7.app.html" class="hiddenlink" target="rightframe">android.support.v7.app</A><br>
    -+<A HREF="pkg_android.support.v7.content.res.html" class="hiddenlink" target="rightframe">android.support.v7.content.res</A><br>
    -+<A HREF="pkg_android.support.v7.graphics.html" class="hiddenlink" target="rightframe">android.support.v7.graphics</A><br>
    -+<A HREF="pkg_android.support.v7.preference.html" class="hiddenlink" target="rightframe">android.support.v7.preference</A><br>
    -+<A HREF="pkg_android.support.v7.util.html" class="hiddenlink" target="rightframe">android.support.v7.util</A><br>
    -+<A HREF="pkg_android.support.v7.widget.html" class="hiddenlink" target="rightframe">android.support.v7.widget</A><br>
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    -+</script>
    -+<script type="text/javascript">
    -+  try {
    -+    var pageTracker = _gat._getTracker("UA-5831155-1");
    -+    pageTracker._setAllowAnchor(true);
    -+    pageTracker._initData();
    -+    pageTracker._trackPageview();
    -+  } catch(e) {}
    -+</script>
    -+</BODY>
    -+</HTML>
    -diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/packages_index_removals.html b/docs/html/sdk/support_api_diff/24.2.0/changes/packages_index_removals.html
    -new file mode 100644
    -index 0000000..ce5ca58
    ---- /dev/null
    -+++ b/docs/html/sdk/support_api_diff/24.2.0/changes/packages_index_removals.html
    -@@ -0,0 +1,67 @@
    -+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
    -+<HTML style="overflow:auto;">
    -+<HEAD>
    -+<meta name="generator" content="JDiff v1.1.0">
    -+<!-- Generated by the JDiff Javadoc doclet -->
    -+<!-- (http://www.jdiff.org) -->
    -+<meta name="description" content="JDiff is a Javadoc doclet which generates an HTML report of all the packages, classes, constructors, methods, and fields which have been removed, added or changed in any way, including their documentation, when two APIs are compared.">
    -+<meta name="keywords" content="diff, jdiff, javadiff, java diff, java difference, API difference, difference between two APIs, API diff, Javadoc, doclet">
    -+<TITLE>
    -+Package Removals Index
    -+</TITLE>
    -+<link href="../../../../assets/android-developer-docs.css" rel="stylesheet" type="text/css" />
    -+<link href="../stylesheet-jdiff.css" rel="stylesheet" type="text/css" />
    -+<noscript>
    -+<style type="text/css">
    -+body{overflow:auto;}
    -+#body-content{position:relative; top:0;}
    -+#doc-content{overflow:visible;border-left:3px solid #666;}
    -+#side-nav{padding:0;}
    -+#side-nav .toggle-list ul {display:block;}
    -+#resize-packages-nav{border-bottom:3px solid #666;}
    -+</style>
    -+</noscript>
    -+<style type="text/css">
    -+</style>
    -+</HEAD>
    -+<BODY class="gc-documentation" style="padding:12px;">
    -+<a NAME="topheader"></a>
    -+<table summary="Index for Packages" width="100%" class="jdiffIndex" border="0" cellspacing="0" cellpadding="0" style="padding-bottom:0;margin-bottom:0;">
    -+  <tr>
    -+  <th class="indexHeader">
    -+    Filter the Index:
    -+  </th>
    -+  </tr>
    -+  <tr>
    -+  <td class="indexText" style="line-height:1.3em;padding-left:2em;">
    -+<a href="packages_index_all.html" class="staysblack">All Packages</a>
    -+  <br>
    -+<b>Removals</b>
    -+  <br>
    -+<A HREF="packages_index_additions.html"xclass="hiddenlink">Additions</A>
    -+  <br>
    -+<A HREF="packages_index_changes.html"xclass="hiddenlink">Changes</A>
    -+  </td>
    -+  </tr>
    -+</table>
    -+<div id="indexTableCaption" style="background-color:#eee;padding:0 4px 0 4px;font-size:11px;margin-bottom:1em;">
    -+Listed as: <span style="color:#069"><strong>Added</strong></span>,  <span style="color:#069"><strike>Removed</strike></span>,  <span style="color:#069">Changed</span></font>
    -+</div>
    -+<br>
    -+<div id="indexTableEntries">
    -+<A NAME="A"></A>
    -+<A HREF="changes-summary.html#android.support.v7.appcompat" class="hiddenlink" target="rightframe"><strike>android.support.v7.appcompat</strike></A><br>
    -+<A HREF="changes-summary.html#android.support.v7.recyclerview" class="hiddenlink" target="rightframe"><strike>android.support.v7.recyclerview</strike></A><br>
    -+<A HREF="changes-summary.html#android.support.v8.renderscript" class="hiddenlink" target="rightframe"><strike>android.support.v8.renderscript</strike></A><br>
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    -+</script>
    -+<script type="text/javascript">
    -+  try {
    -+    var pageTracker = _gat._getTracker("UA-5831155-1");
    -+    pageTracker._setAllowAnchor(true);
    -+    pageTracker._initData();
    -+    pageTracker._trackPageview();
    -+  } catch(e) {}
    -+</script>
    -+</BODY>
    -+</HTML>
    -diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/pkg_android.support.customtabs.html b/docs/html/sdk/support_api_diff/24.2.0/changes/pkg_android.support.customtabs.html
    -new file mode 100644
    -index 0000000..45a31ff
    ---- /dev/null
    -+++ b/docs/html/sdk/support_api_diff/24.2.0/changes/pkg_android.support.customtabs.html
    -@@ -0,0 +1,133 @@
    -+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
    -+<HTML style="overflow:auto;">
    -+<HEAD>
    -+<meta name="generator" content="JDiff v1.1.0">
    -+<!-- Generated by the JDiff Javadoc doclet -->
    -+<!-- (http://www.jdiff.org) -->
    -+<meta name="description" content="JDiff is a Javadoc doclet which generates an HTML report of all the packages, classes, constructors, methods, and fields which have been removed, added or changed in any way, including their documentation, when two APIs are compared.">
    -+<meta name="keywords" content="diff, jdiff, javadiff, java diff, java difference, API difference, difference between two APIs, API diff, Javadoc, doclet">
    -+<TITLE>
    -+android.support.customtabs
    -+</TITLE>
    -+<link href="../../../../assets/android-developer-docs.css" rel="stylesheet" type="text/css" />
    -+<link href="../stylesheet-jdiff.css" rel="stylesheet" type="text/css" />
    -+<noscript>
    -+<style type="text/css">
    -+body{overflow:auto;}
    -+#body-content{position:relative; top:0;}
    -+#doc-content{overflow:visible;border-left:3px solid #666;}
    -+#side-nav{padding:0;}
    -+#side-nav .toggle-list ul {display:block;}
    -+#resize-packages-nav{border-bottom:3px solid #666;}
    -+</style>
    -+</noscript>
    -+<style type="text/css">
    -+</style>
    -+</HEAD>
    -+<BODY>
    -+<!-- Start of nav bar -->
    -+<a name="top"></a>
    -+<div id="header" style="margin-bottom:0;padding-bottom:0;">
    -+<div id="headerLeft">
    -+<a href="../../../../index.html" tabindex="-1" target="_top"><img src="../../../../assets/images/bg_logo.png" alt="Android Developers" /></a>
    -+</div>
    -+  <div id="headerRight">
    -+  <div id="headerLinks">
    -+<!-- <img src="/assets/images/icon_world.jpg" alt="" /> -->
    -+<span class="text">
    -+<!-- &nbsp;<a href="#">English</a> | -->
    -+<nobr><a href="http://developer.android.com" target="_top">Android Developers</a> | <a href="http://www.android.com" target="_top">Android.com</a></nobr>
    -+</span>
    -+</div>
    -+  <div class="and-diff-id" style="margin-top:6px;margin-right:8px;">
    -+    <table class="diffspectable">
    -+      <tr>
    -+        <td colspan="2" class="diffspechead">API Diff Specification</td>
    -+      </tr>
    -+      <tr>
    -+        <td class="diffspec" style="padding-top:.25em">To Level:</td>
    -+        <td class="diffvaluenew" style="padding-top:.25em">24.2.0</td>
    -+      </tr>
    -+      <tr>
    -+        <td class="diffspec">From Level:</td>
    -+        <td class="diffvalueold">24.1.0</td>
    -+      </tr>
    -+      <tr>
    -+        <td class="diffspec">Generated</td>
    -+        <td class="diffvalue">2016.08.16 14:03</td>
    -+      </tr>
    -+    </table>
    -+    </div><!-- End and-diff-id -->
    -+  <div class="and-diff-id" style="margin-right:8px;">
    -+    <table class="diffspectable">
    -+      <tr>
    -+        <td class="diffspec" colspan="2"><a href="jdiff_statistics.html">Statistics</a>
    -+      </tr>
    -+    </table>
    -+  </div> <!-- End and-diff-id -->
    -+  </div> <!-- End headerRight -->
    -+  </div> <!-- End header -->
    -+<div id="body-content" xstyle="padding:12px;padding-right:18px;">
    -+<div id="doc-content" style="position:relative;">
    -+<div id="mainBodyFluid">
    -+<H2>
    -+Package <A HREF="../../../../reference/android/support/customtabs/package-summary.html" target="_top"><font size="+1"><code>android.support.customtabs</code></font></A>
    -+</H2>
    -+<p>
    -+<a NAME="Changed"></a>
    -+<TABLE summary="Changed Classes" WIDTH="100%">
    -+<TR>
    -+  <TH VALIGN="TOP" COLSPAN=2>Changed Classes</FONT></TD>
    -+</TH>
    -+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    -+  <TD VALIGN="TOP" WIDTH="25%">
    -+  <A NAME="CustomTabsIntent"></A>
    -+  <nobr><A HREF="android.support.customtabs.CustomTabsIntent.html">CustomTabsIntent</A></nobr>
    -+  </TD>
    -+  <TD>&nbsp;</TD>
    -+</TR>
    -+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    -+  <TD VALIGN="TOP" WIDTH="25%">
    -+  <A NAME="CustomTabsIntent.Builder"></A>
    -+  <nobr><A HREF="android.support.customtabs.CustomTabsIntent.Builder.html">CustomTabsIntent.Builder</A></nobr>
    -+  </TD>
    -+  <TD>&nbsp;</TD>
    -+</TR>
    -+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    -+  <TD VALIGN="TOP" WIDTH="25%">
    -+  <A NAME="CustomTabsSession"></A>
    -+  <nobr><A HREF="android.support.customtabs.CustomTabsSession.html">CustomTabsSession</A></nobr>
    -+  </TD>
    -+  <TD>&nbsp;</TD>
    -+</TR>
    -+</TABLE>
    -+&nbsp;
    -+      </div>	
    -+      <div id="footer">
    -+        <div id="copyright">
    -+        Except as noted, this content is licensed under 
    -+        <a href="http://creativecommons.org/licenses/by/2.5/"> Creative Commons Attribution 2.5</a>.
    -+        For details and restrictions, see the <a href="/license.html">Content License</a>.
    -+        </div>
    -+      <div id="footerlinks">
    -+      <p>
    -+        <a href="http://www.android.com/terms.html">Site Terms of Service</a> -
    -+        <a href="http://www.android.com/privacy.html">Privacy Policy</a> -
    -+        <a href="http://www.android.com/branding.html">Brand Guidelines</a>
    -+      </p>
    -+    </div>
    -+    </div> <!-- end footer -->
    -+    </div><!-- end doc-content -->
    -+    </div> <!-- end body-content --> 
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    -+</script>
    -+<script type="text/javascript">
    -+  try {
    -+    var pageTracker = _gat._getTracker("UA-5831155-1");
    -+    pageTracker._setAllowAnchor(true);
    -+    pageTracker._initData();
    -+    pageTracker._trackPageview();
    -+  } catch(e) {}
    -+</script>
    -+</BODY>
    -+</HTML>
    -diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/pkg_android.support.design.widget.html b/docs/html/sdk/support_api_diff/24.2.0/changes/pkg_android.support.design.widget.html
    -new file mode 100644
    -index 0000000..a311b48
    ---- /dev/null
    -+++ b/docs/html/sdk/support_api_diff/24.2.0/changes/pkg_android.support.design.widget.html
    -@@ -0,0 +1,175 @@
    -+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
    -+<HTML style="overflow:auto;">
    -+<HEAD>
    -+<meta name="generator" content="JDiff v1.1.0">
    -+<!-- Generated by the JDiff Javadoc doclet -->
    -+<!-- (http://www.jdiff.org) -->
    -+<meta name="description" content="JDiff is a Javadoc doclet which generates an HTML report of all the packages, classes, constructors, methods, and fields which have been removed, added or changed in any way, including their documentation, when two APIs are compared.">
    -+<meta name="keywords" content="diff, jdiff, javadiff, java diff, java difference, API difference, difference between two APIs, API diff, Javadoc, doclet">
    -+<TITLE>
    -+android.support.design.widget
    -+</TITLE>
    -+<link href="../../../../assets/android-developer-docs.css" rel="stylesheet" type="text/css" />
    -+<link href="../stylesheet-jdiff.css" rel="stylesheet" type="text/css" />
    -+<noscript>
    -+<style type="text/css">
    -+body{overflow:auto;}
    -+#body-content{position:relative; top:0;}
    -+#doc-content{overflow:visible;border-left:3px solid #666;}
    -+#side-nav{padding:0;}
    -+#side-nav .toggle-list ul {display:block;}
    -+#resize-packages-nav{border-bottom:3px solid #666;}
    -+</style>
    -+</noscript>
    -+<style type="text/css">
    -+</style>
    -+</HEAD>
    -+<BODY>
    -+<!-- Start of nav bar -->
    -+<a name="top"></a>
    -+<div id="header" style="margin-bottom:0;padding-bottom:0;">
    -+<div id="headerLeft">
    -+<a href="../../../../index.html" tabindex="-1" target="_top"><img src="../../../../assets/images/bg_logo.png" alt="Android Developers" /></a>
    -+</div>
    -+  <div id="headerRight">
    -+  <div id="headerLinks">
    -+<!-- <img src="/assets/images/icon_world.jpg" alt="" /> -->
    -+<span class="text">
    -+<!-- &nbsp;<a href="#">English</a> | -->
    -+<nobr><a href="http://developer.android.com" target="_top">Android Developers</a> | <a href="http://www.android.com" target="_top">Android.com</a></nobr>
    -+</span>
    -+</div>
    -+  <div class="and-diff-id" style="margin-top:6px;margin-right:8px;">
    -+    <table class="diffspectable">
    -+      <tr>
    -+        <td colspan="2" class="diffspechead">API Diff Specification</td>
    -+      </tr>
    -+      <tr>
    -+        <td class="diffspec" style="padding-top:.25em">To Level:</td>
    -+        <td class="diffvaluenew" style="padding-top:.25em">24.2.0</td>
    -+      </tr>
    -+      <tr>
    -+        <td class="diffspec">From Level:</td>
    -+        <td class="diffvalueold">24.1.0</td>
    -+      </tr>
    -+      <tr>
    -+        <td class="diffspec">Generated</td>
    -+        <td class="diffvalue">2016.08.16 14:03</td>
    -+      </tr>
    -+    </table>
    -+    </div><!-- End and-diff-id -->
    -+  <div class="and-diff-id" style="margin-right:8px;">
    -+    <table class="diffspectable">
    -+      <tr>
    -+        <td class="diffspec" colspan="2"><a href="jdiff_statistics.html">Statistics</a>
    -+      </tr>
    -+    </table>
    -+  </div> <!-- End and-diff-id -->
    -+  </div> <!-- End headerRight -->
    -+  </div> <!-- End header -->
    -+<div id="body-content" xstyle="padding:12px;padding-right:18px;">
    -+<div id="doc-content" style="position:relative;">
    -+<div id="mainBodyFluid">
    -+<H2>
    -+Package <A HREF="../../../../reference/android/support/design/widget/package-summary.html" target="_top"><font size="+1"><code>android.support.design.widget</code></font></A>
    -+</H2>
    -+<p>
    -+<a NAME="Changed"></a>
    -+<TABLE summary="Changed Classes" WIDTH="100%">
    -+<TR>
    -+  <TH VALIGN="TOP" COLSPAN=2>Changed Classes</FONT></TD>
    -+</TH>
    -+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    -+  <TD VALIGN="TOP" WIDTH="25%">
    -+  <A NAME="AppBarLayout.ScrollingViewBehavior"></A>
    -+  <nobr><A HREF="android.support.design.widget.AppBarLayout.ScrollingViewBehavior.html">AppBarLayout.ScrollingViewBehavior</A></nobr>
    -+  </TD>
    -+  <TD>&nbsp;</TD>
    -+</TR>
    -+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    -+  <TD VALIGN="TOP" WIDTH="25%">
    -+  <A NAME="BottomSheetBehavior"></A>
    -+  <nobr><A HREF="android.support.design.widget.BottomSheetBehavior.html">BottomSheetBehavior</A></nobr>
    -+  </TD>
    -+  <TD>&nbsp;</TD>
    -+</TR>
    -+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    -+  <TD VALIGN="TOP" WIDTH="25%">
    -+  <A NAME="CollapsingToolbarLayout"></A>
    -+  <nobr><A HREF="android.support.design.widget.CollapsingToolbarLayout.html">CollapsingToolbarLayout</A></nobr>
    -+  </TD>
    -+  <TD>&nbsp;</TD>
    -+</TR>
    -+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    -+  <TD VALIGN="TOP" WIDTH="25%">
    -+  <A NAME="CoordinatorLayout"></A>
    -+  <nobr><A HREF="android.support.design.widget.CoordinatorLayout.html">CoordinatorLayout</A></nobr>
    -+  </TD>
    -+  <TD>&nbsp;</TD>
    -+</TR>
    -+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    -+  <TD VALIGN="TOP" WIDTH="25%">
    -+  <A NAME="CoordinatorLayout.Behavior"></A>
    -+  <nobr><A HREF="android.support.design.widget.CoordinatorLayout.Behavior.html">CoordinatorLayout.Behavior</A></nobr>
    -+  </TD>
    -+  <TD>&nbsp;</TD>
    -+</TR>
    -+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    -+  <TD VALIGN="TOP" WIDTH="25%">
    -+  <A NAME="CoordinatorLayout.LayoutParams"></A>
    -+  <nobr><A HREF="android.support.design.widget.CoordinatorLayout.LayoutParams.html">CoordinatorLayout.LayoutParams</A></nobr>
    -+  </TD>
    -+  <TD>&nbsp;</TD>
    -+</TR>
    -+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    -+  <TD VALIGN="TOP" WIDTH="25%">
    -+  <A NAME="FloatingActionButton.Behavior"></A>
    -+  <nobr><A HREF="android.support.design.widget.FloatingActionButton.Behavior.html">FloatingActionButton.Behavior</A></nobr>
    -+  </TD>
    -+  <TD>&nbsp;</TD>
    -+</TR>
    -+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    -+  <TD VALIGN="TOP" WIDTH="25%">
    -+  <A NAME="TabLayout"></A>
    -+  <nobr><A HREF="android.support.design.widget.TabLayout.html">TabLayout</A></nobr>
    -+  </TD>
    -+  <TD>&nbsp;</TD>
    -+</TR>
    -+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    -+  <TD VALIGN="TOP" WIDTH="25%">
    -+  <A NAME="TextInputLayout"></A>
    -+  <nobr><A HREF="android.support.design.widget.TextInputLayout.html">TextInputLayout</A></nobr>
    -+  </TD>
    -+  <TD>&nbsp;</TD>
    -+</TR>
    -+</TABLE>
    -+&nbsp;
    -+      </div>	
    -+      <div id="footer">
    -+        <div id="copyright">
    -+        Except as noted, this content is licensed under 
    -+        <a href="http://creativecommons.org/licenses/by/2.5/"> Creative Commons Attribution 2.5</a>.
    -+        For details and restrictions, see the <a href="/license.html">Content License</a>.
    -+        </div>
    -+      <div id="footerlinks">
    -+      <p>
    -+        <a href="http://www.android.com/terms.html">Site Terms of Service</a> -
    -+        <a href="http://www.android.com/privacy.html">Privacy Policy</a> -
    -+        <a href="http://www.android.com/branding.html">Brand Guidelines</a>
    -+      </p>
    -+    </div>
    -+    </div> <!-- end footer -->
    -+    </div><!-- end doc-content -->
    -+    </div> <!-- end body-content --> 
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    -+</script>
    -+<script type="text/javascript">
    -+  try {
    -+    var pageTracker = _gat._getTracker("UA-5831155-1");
    -+    pageTracker._setAllowAnchor(true);
    -+    pageTracker._initData();
    -+    pageTracker._trackPageview();
    -+  } catch(e) {}
    -+</script>
    -+</BODY>
    -+</HTML>
    -diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/pkg_android.support.v14.preference.html b/docs/html/sdk/support_api_diff/24.2.0/changes/pkg_android.support.v14.preference.html
    -new file mode 100644
    -index 0000000..f24be00
    ---- /dev/null
    -+++ b/docs/html/sdk/support_api_diff/24.2.0/changes/pkg_android.support.v14.preference.html
    -@@ -0,0 +1,119 @@
    -+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
    -+<HTML style="overflow:auto;">
    -+<HEAD>
    -+<meta name="generator" content="JDiff v1.1.0">
    -+<!-- Generated by the JDiff Javadoc doclet -->
    -+<!-- (http://www.jdiff.org) -->
    -+<meta name="description" content="JDiff is a Javadoc doclet which generates an HTML report of all the packages, classes, constructors, methods, and fields which have been removed, added or changed in any way, including their documentation, when two APIs are compared.">
    -+<meta name="keywords" content="diff, jdiff, javadiff, java diff, java difference, API difference, difference between two APIs, API diff, Javadoc, doclet">
    -+<TITLE>
    -+android.support.v14.preference
    -+</TITLE>
    -+<link href="../../../../assets/android-developer-docs.css" rel="stylesheet" type="text/css" />
    -+<link href="../stylesheet-jdiff.css" rel="stylesheet" type="text/css" />
    -+<noscript>
    -+<style type="text/css">
    -+body{overflow:auto;}
    -+#body-content{position:relative; top:0;}
    -+#doc-content{overflow:visible;border-left:3px solid #666;}
    -+#side-nav{padding:0;}
    -+#side-nav .toggle-list ul {display:block;}
    -+#resize-packages-nav{border-bottom:3px solid #666;}
    -+</style>
    -+</noscript>
    -+<style type="text/css">
    -+</style>
    -+</HEAD>
    -+<BODY>
    -+<!-- Start of nav bar -->
    -+<a name="top"></a>
    -+<div id="header" style="margin-bottom:0;padding-bottom:0;">
    -+<div id="headerLeft">
    -+<a href="../../../../index.html" tabindex="-1" target="_top"><img src="../../../../assets/images/bg_logo.png" alt="Android Developers" /></a>
    -+</div>
    -+  <div id="headerRight">
    -+  <div id="headerLinks">
    -+<!-- <img src="/assets/images/icon_world.jpg" alt="" /> -->
    -+<span class="text">
    -+<!-- &nbsp;<a href="#">English</a> | -->
    -+<nobr><a href="http://developer.android.com" target="_top">Android Developers</a> | <a href="http://www.android.com" target="_top">Android.com</a></nobr>
    -+</span>
    -+</div>
    -+  <div class="and-diff-id" style="margin-top:6px;margin-right:8px;">
    -+    <table class="diffspectable">
    -+      <tr>
    -+        <td colspan="2" class="diffspechead">API Diff Specification</td>
    -+      </tr>
    -+      <tr>
    -+        <td class="diffspec" style="padding-top:.25em">To Level:</td>
    -+        <td class="diffvaluenew" style="padding-top:.25em">24.2.0</td>
    -+      </tr>
    -+      <tr>
    -+        <td class="diffspec">From Level:</td>
    -+        <td class="diffvalueold">24.1.0</td>
    -+      </tr>
    -+      <tr>
    -+        <td class="diffspec">Generated</td>
    -+        <td class="diffvalue">2016.08.16 14:03</td>
    -+      </tr>
    -+    </table>
    -+    </div><!-- End and-diff-id -->
    -+  <div class="and-diff-id" style="margin-right:8px;">
    -+    <table class="diffspectable">
    -+      <tr>
    -+        <td class="diffspec" colspan="2"><a href="jdiff_statistics.html">Statistics</a>
    -+      </tr>
    -+    </table>
    -+  </div> <!-- End and-diff-id -->
    -+  </div> <!-- End headerRight -->
    -+  </div> <!-- End header -->
    -+<div id="body-content" xstyle="padding:12px;padding-right:18px;">
    -+<div id="doc-content" style="position:relative;">
    -+<div id="mainBodyFluid">
    -+<H2>
    -+Package <A HREF="../../../../reference/android/support/v14/preference/package-summary.html" target="_top"><font size="+1"><code>android.support.v14.preference</code></font></A>
    -+</H2>
    -+<p>
    -+<a NAME="Changed"></a>
    -+<TABLE summary="Changed Classes" WIDTH="100%">
    -+<TR>
    -+  <TH VALIGN="TOP" COLSPAN=2>Changed Classes</FONT></TD>
    -+</TH>
    -+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    -+  <TD VALIGN="TOP" WIDTH="25%">
    -+  <A NAME="PreferenceFragment"></A>
    -+  <nobr><A HREF="android.support.v14.preference.PreferenceFragment.html">PreferenceFragment</A></nobr>
    -+  </TD>
    -+  <TD>&nbsp;</TD>
    -+</TR>
    -+</TABLE>
    -+&nbsp;
    -+      </div>	
    -+      <div id="footer">
    -+        <div id="copyright">
    -+        Except as noted, this content is licensed under 
    -+        <a href="http://creativecommons.org/licenses/by/2.5/"> Creative Commons Attribution 2.5</a>.
    -+        For details and restrictions, see the <a href="/license.html">Content License</a>.
    -+        </div>
    -+      <div id="footerlinks">
    -+      <p>
    -+        <a href="http://www.android.com/terms.html">Site Terms of Service</a> -
    -+        <a href="http://www.android.com/privacy.html">Privacy Policy</a> -
    -+        <a href="http://www.android.com/branding.html">Brand Guidelines</a>
    -+      </p>
    -+    </div>
    -+    </div> <!-- end footer -->
    -+    </div><!-- end doc-content -->
    -+    </div> <!-- end body-content --> 
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    -+</script>
    -+<script type="text/javascript">
    -+  try {
    -+    var pageTracker = _gat._getTracker("UA-5831155-1");
    -+    pageTracker._setAllowAnchor(true);
    -+    pageTracker._initData();
    -+    pageTracker._trackPageview();
    -+  } catch(e) {}
    -+</script>
    -+</BODY>
    -+</HTML>
    -diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/pkg_android.support.v17.leanback.widget.html b/docs/html/sdk/support_api_diff/24.2.0/changes/pkg_android.support.v17.leanback.widget.html
    -new file mode 100644
    -index 0000000..c07a487
    ---- /dev/null
    -+++ b/docs/html/sdk/support_api_diff/24.2.0/changes/pkg_android.support.v17.leanback.widget.html
    -@@ -0,0 +1,133 @@
    -+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
    -+<HTML style="overflow:auto;">
    -+<HEAD>
    -+<meta name="generator" content="JDiff v1.1.0">
    -+<!-- Generated by the JDiff Javadoc doclet -->
    -+<!-- (http://www.jdiff.org) -->
    -+<meta name="description" content="JDiff is a Javadoc doclet which generates an HTML report of all the packages, classes, constructors, methods, and fields which have been removed, added or changed in any way, including their documentation, when two APIs are compared.">
    -+<meta name="keywords" content="diff, jdiff, javadiff, java diff, java difference, API difference, difference between two APIs, API diff, Javadoc, doclet">
    -+<TITLE>
    -+android.support.v17.leanback.widget
    -+</TITLE>
    -+<link href="../../../../assets/android-developer-docs.css" rel="stylesheet" type="text/css" />
    -+<link href="../stylesheet-jdiff.css" rel="stylesheet" type="text/css" />
    -+<noscript>
    -+<style type="text/css">
    -+body{overflow:auto;}
    -+#body-content{position:relative; top:0;}
    -+#doc-content{overflow:visible;border-left:3px solid #666;}
    -+#side-nav{padding:0;}
    -+#side-nav .toggle-list ul {display:block;}
    -+#resize-packages-nav{border-bottom:3px solid #666;}
    -+</style>
    -+</noscript>
    -+<style type="text/css">
    -+</style>
    -+</HEAD>
    -+<BODY>
    -+<!-- Start of nav bar -->
    -+<a name="top"></a>
    -+<div id="header" style="margin-bottom:0;padding-bottom:0;">
    -+<div id="headerLeft">
    -+<a href="../../../../index.html" tabindex="-1" target="_top"><img src="../../../../assets/images/bg_logo.png" alt="Android Developers" /></a>
    -+</div>
    -+  <div id="headerRight">
    -+  <div id="headerLinks">
    -+<!-- <img src="/assets/images/icon_world.jpg" alt="" /> -->
    -+<span class="text">
    -+<!-- &nbsp;<a href="#">English</a> | -->
    -+<nobr><a href="http://developer.android.com" target="_top">Android Developers</a> | <a href="http://www.android.com" target="_top">Android.com</a></nobr>
    -+</span>
    -+</div>
    -+  <div class="and-diff-id" style="margin-top:6px;margin-right:8px;">
    -+    <table class="diffspectable">
    -+      <tr>
    -+        <td colspan="2" class="diffspechead">API Diff Specification</td>
    -+      </tr>
    -+      <tr>
    -+        <td class="diffspec" style="padding-top:.25em">To Level:</td>
    -+        <td class="diffvaluenew" style="padding-top:.25em">24.2.0</td>
    -+      </tr>
    -+      <tr>
    -+        <td class="diffspec">From Level:</td>
    -+        <td class="diffvalueold">24.1.0</td>
    -+      </tr>
    -+      <tr>
    -+        <td class="diffspec">Generated</td>
    -+        <td class="diffvalue">2016.08.16 14:03</td>
    -+      </tr>
    -+    </table>
    -+    </div><!-- End and-diff-id -->
    -+  <div class="and-diff-id" style="margin-right:8px;">
    -+    <table class="diffspectable">
    -+      <tr>
    -+        <td class="diffspec" colspan="2"><a href="jdiff_statistics.html">Statistics</a>
    -+      </tr>
    -+    </table>
    -+  </div> <!-- End and-diff-id -->
    -+  </div> <!-- End headerRight -->
    -+  </div> <!-- End header -->
    -+<div id="body-content" xstyle="padding:12px;padding-right:18px;">
    -+<div id="doc-content" style="position:relative;">
    -+<div id="mainBodyFluid">
    -+<H2>
    -+Package <A HREF="../../../../reference/android/support/v17/leanback/widget/package-summary.html" target="_top"><font size="+1"><code>android.support.v17.leanback.widget</code></font></A>
    -+</H2>
    -+<p>
    -+<a NAME="Changed"></a>
    -+<TABLE summary="Changed Classes" WIDTH="100%">
    -+<TR>
    -+  <TH VALIGN="TOP" COLSPAN=2>Changed Classes</FONT></TD>
    -+</TH>
    -+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    -+  <TD VALIGN="TOP" WIDTH="25%">
    -+  <A NAME="AbstractMediaItemPresenter"></A>
    -+  <nobr><A HREF="android.support.v17.leanback.widget.AbstractMediaItemPresenter.html">AbstractMediaItemPresenter</A></nobr>
    -+  </TD>
    -+  <TD>&nbsp;</TD>
    -+</TR>
    -+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    -+  <TD VALIGN="TOP" WIDTH="25%">
    -+  <A NAME="AbstractMediaItemPresenter.ViewHolder"></A>
    -+  <nobr><A HREF="android.support.v17.leanback.widget.AbstractMediaItemPresenter.ViewHolder.html">AbstractMediaItemPresenter.<br>ViewHolder</A></nobr>
    -+  </TD>
    -+  <TD>&nbsp;</TD>
    -+</TR>
    -+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    -+  <TD VALIGN="TOP" WIDTH="25%">
    -+  <A NAME="ObjectAdapter"></A>
    -+  <nobr><A HREF="android.support.v17.leanback.widget.ObjectAdapter.html">ObjectAdapter</A></nobr>
    -+  </TD>
    -+  <TD>&nbsp;</TD>
    -+</TR>
    -+</TABLE>
    -+&nbsp;
    -+      </div>	
    -+      <div id="footer">
    -+        <div id="copyright">
    -+        Except as noted, this content is licensed under 
    -+        <a href="http://creativecommons.org/licenses/by/2.5/"> Creative Commons Attribution 2.5</a>.
    -+        For details and restrictions, see the <a href="/license.html">Content License</a>.
    -+        </div>
    -+      <div id="footerlinks">
    -+      <p>
    -+        <a href="http://www.android.com/terms.html">Site Terms of Service</a> -
    -+        <a href="http://www.android.com/privacy.html">Privacy Policy</a> -
    -+        <a href="http://www.android.com/branding.html">Brand Guidelines</a>
    -+      </p>
    -+    </div>
    -+    </div> <!-- end footer -->
    -+    </div><!-- end doc-content -->
    -+    </div> <!-- end body-content --> 
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    -+</script>
    -+<script type="text/javascript">
    -+  try {
    -+    var pageTracker = _gat._getTracker("UA-5831155-1");
    -+    pageTracker._setAllowAnchor(true);
    -+    pageTracker._initData();
    -+    pageTracker._trackPageview();
    -+  } catch(e) {}
    -+</script>
    -+</BODY>
    -+</HTML>
    -diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/pkg_android.support.v17.preference.html b/docs/html/sdk/support_api_diff/24.2.0/changes/pkg_android.support.v17.preference.html
    -new file mode 100644
    -index 0000000..c61d79d
    ---- /dev/null
    -+++ b/docs/html/sdk/support_api_diff/24.2.0/changes/pkg_android.support.v17.preference.html
    -@@ -0,0 +1,119 @@
    -+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
    -+<HTML style="overflow:auto;">
    -+<HEAD>
    -+<meta name="generator" content="JDiff v1.1.0">
    -+<!-- Generated by the JDiff Javadoc doclet -->
    -+<!-- (http://www.jdiff.org) -->
    -+<meta name="description" content="JDiff is a Javadoc doclet which generates an HTML report of all the packages, classes, constructors, methods, and fields which have been removed, added or changed in any way, including their documentation, when two APIs are compared.">
    -+<meta name="keywords" content="diff, jdiff, javadiff, java diff, java difference, API difference, difference between two APIs, API diff, Javadoc, doclet">
    -+<TITLE>
    -+android.support.v17.preference
    -+</TITLE>
    -+<link href="../../../../assets/android-developer-docs.css" rel="stylesheet" type="text/css" />
    -+<link href="../stylesheet-jdiff.css" rel="stylesheet" type="text/css" />
    -+<noscript>
    -+<style type="text/css">
    -+body{overflow:auto;}
    -+#body-content{position:relative; top:0;}
    -+#doc-content{overflow:visible;border-left:3px solid #666;}
    -+#side-nav{padding:0;}
    -+#side-nav .toggle-list ul {display:block;}
    -+#resize-packages-nav{border-bottom:3px solid #666;}
    -+</style>
    -+</noscript>
    -+<style type="text/css">
    -+</style>
    -+</HEAD>
    -+<BODY>
    -+<!-- Start of nav bar -->
    -+<a name="top"></a>
    -+<div id="header" style="margin-bottom:0;padding-bottom:0;">
    -+<div id="headerLeft">
    -+<a href="../../../../index.html" tabindex="-1" target="_top"><img src="../../../../assets/images/bg_logo.png" alt="Android Developers" /></a>
    -+</div>
    -+  <div id="headerRight">
    -+  <div id="headerLinks">
    -+<!-- <img src="/assets/images/icon_world.jpg" alt="" /> -->
    -+<span class="text">
    -+<!-- &nbsp;<a href="#">English</a> | -->
    -+<nobr><a href="http://developer.android.com" target="_top">Android Developers</a> | <a href="http://www.android.com" target="_top">Android.com</a></nobr>
    -+</span>
    -+</div>
    -+  <div class="and-diff-id" style="margin-top:6px;margin-right:8px;">
    -+    <table class="diffspectable">
    -+      <tr>
    -+        <td colspan="2" class="diffspechead">API Diff Specification</td>
    -+      </tr>
    -+      <tr>
    -+        <td class="diffspec" style="padding-top:.25em">To Level:</td>
    -+        <td class="diffvaluenew" style="padding-top:.25em">24.2.0</td>
    -+      </tr>
    -+      <tr>
    -+        <td class="diffspec">From Level:</td>
    -+        <td class="diffvalueold">24.1.0</td>
    -+      </tr>
    -+      <tr>
    -+        <td class="diffspec">Generated</td>
    -+        <td class="diffvalue">2016.08.16 14:03</td>
    -+      </tr>
    -+    </table>
    -+    </div><!-- End and-diff-id -->
    -+  <div class="and-diff-id" style="margin-right:8px;">
    -+    <table class="diffspectable">
    -+      <tr>
    -+        <td class="diffspec" colspan="2"><a href="jdiff_statistics.html">Statistics</a>
    -+      </tr>
    -+    </table>
    -+  </div> <!-- End and-diff-id -->
    -+  </div> <!-- End headerRight -->
    -+  </div> <!-- End header -->
    -+<div id="body-content" xstyle="padding:12px;padding-right:18px;">
    -+<div id="doc-content" style="position:relative;">
    -+<div id="mainBodyFluid">
    -+<H2>
    -+Package <A HREF="../../../../reference/android/support/v17/preference/package-summary.html" target="_top"><font size="+1"><code>android.support.v17.preference</code></font></A>
    -+</H2>
    -+<p>
    -+<a NAME="Changed"></a>
    -+<TABLE summary="Changed Classes" WIDTH="100%">
    -+<TR>
    -+  <TH VALIGN="TOP" COLSPAN=2>Changed Classes</FONT></TD>
    -+</TH>
    -+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    -+  <TD VALIGN="TOP" WIDTH="25%">
    -+  <A NAME="LeanbackSettingsFragment"></A>
    -+  <nobr><A HREF="android.support.v17.preference.LeanbackSettingsFragment.html">LeanbackSettingsFragment</A></nobr>
    -+  </TD>
    -+  <TD>&nbsp;</TD>
    -+</TR>
    -+</TABLE>
    -+&nbsp;
    -+      </div>	
    -+      <div id="footer">
    -+        <div id="copyright">
    -+        Except as noted, this content is licensed under 
    -+        <a href="http://creativecommons.org/licenses/by/2.5/"> Creative Commons Attribution 2.5</a>.
    -+        For details and restrictions, see the <a href="/license.html">Content License</a>.
    -+        </div>
    -+      <div id="footerlinks">
    -+      <p>
    -+        <a href="http://www.android.com/terms.html">Site Terms of Service</a> -
    -+        <a href="http://www.android.com/privacy.html">Privacy Policy</a> -
    -+        <a href="http://www.android.com/branding.html">Brand Guidelines</a>
    -+      </p>
    -+    </div>
    -+    </div> <!-- end footer -->
    -+    </div><!-- end doc-content -->
    -+    </div> <!-- end body-content --> 
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    -+</script>
    -+<script type="text/javascript">
    -+  try {
    -+    var pageTracker = _gat._getTracker("UA-5831155-1");
    -+    pageTracker._setAllowAnchor(true);
    -+    pageTracker._initData();
    -+    pageTracker._trackPageview();
    -+  } catch(e) {}
    -+</script>
    -+</BODY>
    -+</HTML>
    -diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/pkg_android.support.v4.accessibilityservice.html b/docs/html/sdk/support_api_diff/24.2.0/changes/pkg_android.support.v4.accessibilityservice.html
    -new file mode 100644
    -index 0000000..2c0f684
    ---- /dev/null
    -+++ b/docs/html/sdk/support_api_diff/24.2.0/changes/pkg_android.support.v4.accessibilityservice.html
    -@@ -0,0 +1,119 @@
    -+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
    -+<HTML style="overflow:auto;">
    -+<HEAD>
    -+<meta name="generator" content="JDiff v1.1.0">
    -+<!-- Generated by the JDiff Javadoc doclet -->
    -+<!-- (http://www.jdiff.org) -->
    -+<meta name="description" content="JDiff is a Javadoc doclet which generates an HTML report of all the packages, classes, constructors, methods, and fields which have been removed, added or changed in any way, including their documentation, when two APIs are compared.">
    -+<meta name="keywords" content="diff, jdiff, javadiff, java diff, java difference, API difference, difference between two APIs, API diff, Javadoc, doclet">
    -+<TITLE>
    -+android.support.v4.accessibilityservice
    -+</TITLE>
    -+<link href="../../../../assets/android-developer-docs.css" rel="stylesheet" type="text/css" />
    -+<link href="../stylesheet-jdiff.css" rel="stylesheet" type="text/css" />
    -+<noscript>
    -+<style type="text/css">
    -+body{overflow:auto;}
    -+#body-content{position:relative; top:0;}
    -+#doc-content{overflow:visible;border-left:3px solid #666;}
    -+#side-nav{padding:0;}
    -+#side-nav .toggle-list ul {display:block;}
    -+#resize-packages-nav{border-bottom:3px solid #666;}
    -+</style>
    -+</noscript>
    -+<style type="text/css">
    -+</style>
    -+</HEAD>
    -+<BODY>
    -+<!-- Start of nav bar -->
    -+<a name="top"></a>
    -+<div id="header" style="margin-bottom:0;padding-bottom:0;">
    -+<div id="headerLeft">
    -+<a href="../../../../index.html" tabindex="-1" target="_top"><img src="../../../../assets/images/bg_logo.png" alt="Android Developers" /></a>
    -+</div>
    -+  <div id="headerRight">
    -+  <div id="headerLinks">
    -+<!-- <img src="/assets/images/icon_world.jpg" alt="" /> -->
    -+<span class="text">
    -+<!-- &nbsp;<a href="#">English</a> | -->
    -+<nobr><a href="http://developer.android.com" target="_top">Android Developers</a> | <a href="http://www.android.com" target="_top">Android.com</a></nobr>
    -+</span>
    -+</div>
    -+  <div class="and-diff-id" style="margin-top:6px;margin-right:8px;">
    -+    <table class="diffspectable">
    -+      <tr>
    -+        <td colspan="2" class="diffspechead">API Diff Specification</td>
    -+      </tr>
    -+      <tr>
    -+        <td class="diffspec" style="padding-top:.25em">To Level:</td>
    -+        <td class="diffvaluenew" style="padding-top:.25em">24.2.0</td>
    -+      </tr>
    -+      <tr>
    -+        <td class="diffspec">From Level:</td>
    -+        <td class="diffvalueold">24.1.0</td>
    -+      </tr>
    -+      <tr>
    -+        <td class="diffspec">Generated</td>
    -+        <td class="diffvalue">2016.08.16 14:03</td>
    -+      </tr>
    -+    </table>
    -+    </div><!-- End and-diff-id -->
    -+  <div class="and-diff-id" style="margin-right:8px;">
    -+    <table class="diffspectable">
    -+      <tr>
    -+        <td class="diffspec" colspan="2"><a href="jdiff_statistics.html">Statistics</a>
    -+      </tr>
    -+    </table>
    -+  </div> <!-- End and-diff-id -->
    -+  </div> <!-- End headerRight -->
    -+  </div> <!-- End header -->
    -+<div id="body-content" xstyle="padding:12px;padding-right:18px;">
    -+<div id="doc-content" style="position:relative;">
    -+<div id="mainBodyFluid">
    -+<H2>
    -+Package <A HREF="../../../../reference/android/support/v4/accessibilityservice/package-summary.html" target="_top"><font size="+1"><code>android.support.v4.accessibilityservice</code></font></A>
    -+</H2>
    -+<p>
    -+<a NAME="Changed"></a>
    -+<TABLE summary="Changed Classes" WIDTH="100%">
    -+<TR>
    -+  <TH VALIGN="TOP" COLSPAN=2>Changed Classes</FONT></TD>
    -+</TH>
    -+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    -+  <TD VALIGN="TOP" WIDTH="25%">
    -+  <A NAME="AccessibilityServiceInfoCompat"></A>
    -+  <nobr><A HREF="android.support.v4.accessibilityservice.AccessibilityServiceInfoCompat.html">AccessibilityServiceInfoCompat</A></nobr>
    -+  </TD>
    -+  <TD>&nbsp;</TD>
    -+</TR>
    -+</TABLE>
    -+&nbsp;
    -+      </div>	
    -+      <div id="footer">
    -+        <div id="copyright">
    -+        Except as noted, this content is licensed under 
    -+        <a href="http://creativecommons.org/licenses/by/2.5/"> Creative Commons Attribution 2.5</a>.
    -+        For details and restrictions, see the <a href="/license.html">Content License</a>.
    -+        </div>
    -+      <div id="footerlinks">
    -+      <p>
    -+        <a href="http://www.android.com/terms.html">Site Terms of Service</a> -
    -+        <a href="http://www.android.com/privacy.html">Privacy Policy</a> -
    -+        <a href="http://www.android.com/branding.html">Brand Guidelines</a>
    -+      </p>
    -+    </div>
    -+    </div> <!-- end footer -->
    -+    </div><!-- end doc-content -->
    -+    </div> <!-- end body-content --> 
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    -+</script>
    -+<script type="text/javascript">
    -+  try {
    -+    var pageTracker = _gat._getTracker("UA-5831155-1");
    -+    pageTracker._setAllowAnchor(true);
    -+    pageTracker._initData();
    -+    pageTracker._trackPageview();
    -+  } catch(e) {}
    -+</script>
    -+</BODY>
    -+</HTML>
    -diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/pkg_android.support.v4.app.html b/docs/html/sdk/support_api_diff/24.2.0/changes/pkg_android.support.v4.app.html
    -new file mode 100644
    -index 0000000..58ed06f
    ---- /dev/null
    -+++ b/docs/html/sdk/support_api_diff/24.2.0/changes/pkg_android.support.v4.app.html
    -@@ -0,0 +1,162 @@
    -+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
    -+<HTML style="overflow:auto;">
    -+<HEAD>
    -+<meta name="generator" content="JDiff v1.1.0">
    -+<!-- Generated by the JDiff Javadoc doclet -->
    -+<!-- (http://www.jdiff.org) -->
    -+<meta name="description" content="JDiff is a Javadoc doclet which generates an HTML report of all the packages, classes, constructors, methods, and fields which have been removed, added or changed in any way, including their documentation, when two APIs are compared.">
    -+<meta name="keywords" content="diff, jdiff, javadiff, java diff, java difference, API difference, difference between two APIs, API diff, Javadoc, doclet">
    -+<TITLE>
    -+android.support.v4.app
    -+</TITLE>
    -+<link href="../../../../assets/android-developer-docs.css" rel="stylesheet" type="text/css" />
    -+<link href="../stylesheet-jdiff.css" rel="stylesheet" type="text/css" />
    -+<noscript>
    -+<style type="text/css">
    -+body{overflow:auto;}
    -+#body-content{position:relative; top:0;}
    -+#doc-content{overflow:visible;border-left:3px solid #666;}
    -+#side-nav{padding:0;}
    -+#side-nav .toggle-list ul {display:block;}
    -+#resize-packages-nav{border-bottom:3px solid #666;}
    -+</style>
    -+</noscript>
    -+<style type="text/css">
    -+</style>
    -+</HEAD>
    -+<BODY>
    -+<!-- Start of nav bar -->
    -+<a name="top"></a>
    -+<div id="header" style="margin-bottom:0;padding-bottom:0;">
    -+<div id="headerLeft">
    -+<a href="../../../../index.html" tabindex="-1" target="_top"><img src="../../../../assets/images/bg_logo.png" alt="Android Developers" /></a>
    -+</div>
    -+  <div id="headerRight">
    -+  <div id="headerLinks">
    -+<!-- <img src="/assets/images/icon_world.jpg" alt="" /> -->
    -+<span class="text">
    -+<!-- &nbsp;<a href="#">English</a> | -->
    -+<nobr><a href="http://developer.android.com" target="_top">Android Developers</a> | <a href="http://www.android.com" target="_top">Android.com</a></nobr>
    -+</span>
    -+</div>
    -+  <div class="and-diff-id" style="margin-top:6px;margin-right:8px;">
    -+    <table class="diffspectable">
    -+      <tr>
    -+        <td colspan="2" class="diffspechead">API Diff Specification</td>
    -+      </tr>
    -+      <tr>
    -+        <td class="diffspec" style="padding-top:.25em">To Level:</td>
    -+        <td class="diffvaluenew" style="padding-top:.25em">24.2.0</td>
    -+      </tr>
    -+      <tr>
    -+        <td class="diffspec">From Level:</td>
    -+        <td class="diffvalueold">24.1.0</td>
    -+      </tr>
    -+      <tr>
    -+        <td class="diffspec">Generated</td>
    -+        <td class="diffvalue">2016.08.16 14:03</td>
    -+      </tr>
    -+    </table>
    -+    </div><!-- End and-diff-id -->
    -+  <div class="and-diff-id" style="margin-right:8px;">
    -+    <table class="diffspectable">
    -+      <tr>
    -+        <td class="diffspec" colspan="2"><a href="jdiff_statistics.html">Statistics</a>
    -+      </tr>
    -+    </table>
    -+  </div> <!-- End and-diff-id -->
    -+  </div> <!-- End headerRight -->
    -+  </div> <!-- End header -->
    -+<div id="body-content" xstyle="padding:12px;padding-right:18px;">
    -+<div id="doc-content" style="position:relative;">
    -+<div id="mainBodyFluid">
    -+<H2>
    -+Package <A HREF="../../../../reference/android/support/v4/app/package-summary.html" target="_top"><font size="+1"><code>android.support.v4.app</code></font></A>
    -+</H2>
    -+<p>
    -+<a NAME="Added"></a>
    -+<TABLE summary="Added Interfaces" WIDTH="100%">
    -+<TR>
    -+  <TH VALIGN="TOP" COLSPAN=2>Added Interfaces</FONT></TD>
    -+</TH>
    -+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    -+  <TD VALIGN="TOP" WIDTH="25%">
    -+  <A NAME="SharedElementCallback.OnSharedElementsReadyListener"></A>
    -+  <nobr><A HREF="../../../../reference/android/support/v4/app/SharedElementCallback.OnSharedElementsReadyListener.html" target="_top"><code><I>SharedElementCallback.<br>OnSharedElementsReadyListener</I></code></A></nobr>
    -+  </TD>
    -+  <TD>&nbsp;</TD>
    -+</TR>
    -+</TABLE>
    -+&nbsp;
    -+<p>
    -+<a NAME="Changed"></a>
    -+<TABLE summary="Changed Classes" WIDTH="100%">
    -+<TR>
    -+  <TH VALIGN="TOP" COLSPAN=2>Changed Classes</FONT></TD>
    -+</TH>
    -+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    -+  <TD VALIGN="TOP" WIDTH="25%">
    -+  <A NAME="ActivityCompat"></A>
    -+  <nobr><A HREF="android.support.v4.app.ActivityCompat.html">ActivityCompat</A></nobr>
    -+  </TD>
    -+  <TD>&nbsp;</TD>
    -+</TR>
    -+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    -+  <TD VALIGN="TOP" WIDTH="25%">
    -+  <A NAME="ActivityOptionsCompat"></A>
    -+  <nobr><A HREF="android.support.v4.app.ActivityOptionsCompat.html">ActivityOptionsCompat</A></nobr>
    -+  </TD>
    -+  <TD>&nbsp;</TD>
    -+</TR>
    -+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    -+  <TD VALIGN="TOP" WIDTH="25%">
    -+  <A NAME="FragmentController"></A>
    -+  <nobr><A HREF="android.support.v4.app.FragmentController.html">FragmentController</A></nobr>
    -+  </TD>
    -+  <TD>&nbsp;</TD>
    -+</TR>
    -+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    -+  <TD VALIGN="TOP" WIDTH="25%">
    -+  <A NAME="ServiceCompat"></A>
    -+  <nobr><A HREF="android.support.v4.app.ServiceCompat.html">ServiceCompat</A></nobr>
    -+  </TD>
    -+  <TD>&nbsp;</TD>
    -+</TR>
    -+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    -+  <TD VALIGN="TOP" WIDTH="25%">
    -+  <A NAME="SharedElementCallback"></A>
    -+  <nobr><A HREF="android.support.v4.app.SharedElementCallback.html">SharedElementCallback</A></nobr>
    -+  </TD>
    -+  <TD>&nbsp;</TD>
    -+</TR>
    -+</TABLE>
    -+&nbsp;
    -+      </div>	
    -+      <div id="footer">
    -+        <div id="copyright">
    -+        Except as noted, this content is licensed under 
    -+        <a href="http://creativecommons.org/licenses/by/2.5/"> Creative Commons Attribution 2.5</a>.
    -+        For details and restrictions, see the <a href="/license.html">Content License</a>.
    -+        </div>
    -+      <div id="footerlinks">
    -+      <p>
    -+        <a href="http://www.android.com/terms.html">Site Terms of Service</a> -
    -+        <a href="http://www.android.com/privacy.html">Privacy Policy</a> -
    -+        <a href="http://www.android.com/branding.html">Brand Guidelines</a>
    -+      </p>
    -+    </div>
    -+    </div> <!-- end footer -->
    -+    </div><!-- end doc-content -->
    -+    </div> <!-- end body-content --> 
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    -+</script>
    -+<script type="text/javascript">
    -+  try {
    -+    var pageTracker = _gat._getTracker("UA-5831155-1");
    -+    pageTracker._setAllowAnchor(true);
    -+    pageTracker._initData();
    -+    pageTracker._trackPageview();
    -+  } catch(e) {}
    -+</script>
    -+</BODY>
    -+</HTML>
    -diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/pkg_android.support.v4.content.html b/docs/html/sdk/support_api_diff/24.2.0/changes/pkg_android.support.v4.content.html
    -new file mode 100644
    -index 0000000..65dd616
    ---- /dev/null
    -+++ b/docs/html/sdk/support_api_diff/24.2.0/changes/pkg_android.support.v4.content.html
    -@@ -0,0 +1,119 @@
    -+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
    -+<HTML style="overflow:auto;">
    -+<HEAD>
    -+<meta name="generator" content="JDiff v1.1.0">
    -+<!-- Generated by the JDiff Javadoc doclet -->
    -+<!-- (http://www.jdiff.org) -->
    -+<meta name="description" content="JDiff is a Javadoc doclet which generates an HTML report of all the packages, classes, constructors, methods, and fields which have been removed, added or changed in any way, including their documentation, when two APIs are compared.">
    -+<meta name="keywords" content="diff, jdiff, javadiff, java diff, java difference, API difference, difference between two APIs, API diff, Javadoc, doclet">
    -+<TITLE>
    -+android.support.v4.content
    -+</TITLE>
    -+<link href="../../../../assets/android-developer-docs.css" rel="stylesheet" type="text/css" />
    -+<link href="../stylesheet-jdiff.css" rel="stylesheet" type="text/css" />
    -+<noscript>
    -+<style type="text/css">
    -+body{overflow:auto;}
    -+#body-content{position:relative; top:0;}
    -+#doc-content{overflow:visible;border-left:3px solid #666;}
    -+#side-nav{padding:0;}
    -+#side-nav .toggle-list ul {display:block;}
    -+#resize-packages-nav{border-bottom:3px solid #666;}
    -+</style>
    -+</noscript>
    -+<style type="text/css">
    -+</style>
    -+</HEAD>
    -+<BODY>
    -+<!-- Start of nav bar -->
    -+<a name="top"></a>
    -+<div id="header" style="margin-bottom:0;padding-bottom:0;">
    -+<div id="headerLeft">
    -+<a href="../../../../index.html" tabindex="-1" target="_top"><img src="../../../../assets/images/bg_logo.png" alt="Android Developers" /></a>
    -+</div>
    -+  <div id="headerRight">
    -+  <div id="headerLinks">
    -+<!-- <img src="/assets/images/icon_world.jpg" alt="" /> -->
    -+<span class="text">
    -+<!-- &nbsp;<a href="#">English</a> | -->
    -+<nobr><a href="http://developer.android.com" target="_top">Android Developers</a> | <a href="http://www.android.com" target="_top">Android.com</a></nobr>
    -+</span>
    -+</div>
    -+  <div class="and-diff-id" style="margin-top:6px;margin-right:8px;">
    -+    <table class="diffspectable">
    -+      <tr>
    -+        <td colspan="2" class="diffspechead">API Diff Specification</td>
    -+      </tr>
    -+      <tr>
    -+        <td class="diffspec" style="padding-top:.25em">To Level:</td>
    -+        <td class="diffvaluenew" style="padding-top:.25em">24.2.0</td>
    -+      </tr>
    -+      <tr>
    -+        <td class="diffspec">From Level:</td>
    -+        <td class="diffvalueold">24.1.0</td>
    -+      </tr>
    -+      <tr>
    -+        <td class="diffspec">Generated</td>
    -+        <td class="diffvalue">2016.08.16 14:03</td>
    -+      </tr>
    -+    </table>
    -+    </div><!-- End and-diff-id -->
    -+  <div class="and-diff-id" style="margin-right:8px;">
    -+    <table class="diffspectable">
    -+      <tr>
    -+        <td class="diffspec" colspan="2"><a href="jdiff_statistics.html">Statistics</a>
    -+      </tr>
    -+    </table>
    -+  </div> <!-- End and-diff-id -->
    -+  </div> <!-- End headerRight -->
    -+  </div> <!-- End header -->
    -+<div id="body-content" xstyle="padding:12px;padding-right:18px;">
    -+<div id="doc-content" style="position:relative;">
    -+<div id="mainBodyFluid">
    -+<H2>
    -+Package <A HREF="../../../../reference/android/support/v4/content/package-summary.html" target="_top"><font size="+1"><code>android.support.v4.content</code></font></A>
    -+</H2>
    -+<p>
    -+<a NAME="Changed"></a>
    -+<TABLE summary="Changed Classes" WIDTH="100%">
    -+<TR>
    -+  <TH VALIGN="TOP" COLSPAN=2>Changed Classes</FONT></TD>
    -+</TH>
    -+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    -+  <TD VALIGN="TOP" WIDTH="25%">
    -+  <A NAME="ContextCompat"></A>
    -+  <nobr><A HREF="android.support.v4.content.ContextCompat.html">ContextCompat</A></nobr>
    -+  </TD>
    -+  <TD>&nbsp;</TD>
    -+</TR>
    -+</TABLE>
    -+&nbsp;
    -+      </div>	
    -+      <div id="footer">
    -+        <div id="copyright">
    -+        Except as noted, this content is licensed under 
    -+        <a href="http://creativecommons.org/licenses/by/2.5/"> Creative Commons Attribution 2.5</a>.
    -+        For details and restrictions, see the <a href="/license.html">Content License</a>.
    -+        </div>
    -+      <div id="footerlinks">
    -+      <p>
    -+        <a href="http://www.android.com/terms.html">Site Terms of Service</a> -
    -+        <a href="http://www.android.com/privacy.html">Privacy Policy</a> -
    -+        <a href="http://www.android.com/branding.html">Brand Guidelines</a>
    -+      </p>
    -+    </div>
    -+    </div> <!-- end footer -->
    -+    </div><!-- end doc-content -->
    -+    </div> <!-- end body-content --> 
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    -+</script>
    -+<script type="text/javascript">
    -+  try {
    -+    var pageTracker = _gat._getTracker("UA-5831155-1");
    -+    pageTracker._setAllowAnchor(true);
    -+    pageTracker._initData();
    -+    pageTracker._trackPageview();
    -+  } catch(e) {}
    -+</script>
    -+</BODY>
    -+</HTML>
    -diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/pkg_android.support.v4.graphics.drawable.html b/docs/html/sdk/support_api_diff/24.2.0/changes/pkg_android.support.v4.graphics.drawable.html
    -new file mode 100644
    -index 0000000..f8b31a5
    ---- /dev/null
    -+++ b/docs/html/sdk/support_api_diff/24.2.0/changes/pkg_android.support.v4.graphics.drawable.html
    -@@ -0,0 +1,119 @@
    -+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
    -+<HTML style="overflow:auto;">
    -+<HEAD>
    -+<meta name="generator" content="JDiff v1.1.0">
    -+<!-- Generated by the JDiff Javadoc doclet -->
    -+<!-- (http://www.jdiff.org) -->
    -+<meta name="description" content="JDiff is a Javadoc doclet which generates an HTML report of all the packages, classes, constructors, methods, and fields which have been removed, added or changed in any way, including their documentation, when two APIs are compared.">
    -+<meta name="keywords" content="diff, jdiff, javadiff, java diff, java difference, API difference, difference between two APIs, API diff, Javadoc, doclet">
    -+<TITLE>
    -+android.support.v4.graphics.drawable
    -+</TITLE>
    -+<link href="../../../../assets/android-developer-docs.css" rel="stylesheet" type="text/css" />
    -+<link href="../stylesheet-jdiff.css" rel="stylesheet" type="text/css" />
    -+<noscript>
    -+<style type="text/css">
    -+body{overflow:auto;}
    -+#body-content{position:relative; top:0;}
    -+#doc-content{overflow:visible;border-left:3px solid #666;}
    -+#side-nav{padding:0;}
    -+#side-nav .toggle-list ul {display:block;}
    -+#resize-packages-nav{border-bottom:3px solid #666;}
    -+</style>
    -+</noscript>
    -+<style type="text/css">
    -+</style>
    -+</HEAD>
    -+<BODY>
    -+<!-- Start of nav bar -->
    -+<a name="top"></a>
    -+<div id="header" style="margin-bottom:0;padding-bottom:0;">
    -+<div id="headerLeft">
    -+<a href="../../../../index.html" tabindex="-1" target="_top"><img src="../../../../assets/images/bg_logo.png" alt="Android Developers" /></a>
    -+</div>
    -+  <div id="headerRight">
    -+  <div id="headerLinks">
    -+<!-- <img src="/assets/images/icon_world.jpg" alt="" /> -->
    -+<span class="text">
    -+<!-- &nbsp;<a href="#">English</a> | -->
    -+<nobr><a href="http://developer.android.com" target="_top">Android Developers</a> | <a href="http://www.android.com" target="_top">Android.com</a></nobr>
    -+</span>
    -+</div>
    -+  <div class="and-diff-id" style="margin-top:6px;margin-right:8px;">
    -+    <table class="diffspectable">
    -+      <tr>
    -+        <td colspan="2" class="diffspechead">API Diff Specification</td>
    -+      </tr>
    -+      <tr>
    -+        <td class="diffspec" style="padding-top:.25em">To Level:</td>
    -+        <td class="diffvaluenew" style="padding-top:.25em">24.2.0</td>
    -+      </tr>
    -+      <tr>
    -+        <td class="diffspec">From Level:</td>
    -+        <td class="diffvalueold">24.1.0</td>
    -+      </tr>
    -+      <tr>
    -+        <td class="diffspec">Generated</td>
    -+        <td class="diffvalue">2016.08.16 14:03</td>
    -+      </tr>
    -+    </table>
    -+    </div><!-- End and-diff-id -->
    -+  <div class="and-diff-id" style="margin-right:8px;">
    -+    <table class="diffspectable">
    -+      <tr>
    -+        <td class="diffspec" colspan="2"><a href="jdiff_statistics.html">Statistics</a>
    -+      </tr>
    -+    </table>
    -+  </div> <!-- End and-diff-id -->
    -+  </div> <!-- End headerRight -->
    -+  </div> <!-- End header -->
    -+<div id="body-content" xstyle="padding:12px;padding-right:18px;">
    -+<div id="doc-content" style="position:relative;">
    -+<div id="mainBodyFluid">
    -+<H2>
    -+Package <A HREF="../../../../reference/android/support/v4/graphics/drawable/package-summary.html" target="_top"><font size="+1"><code>android.support.v4.graphics.drawable</code></font></A>
    -+</H2>
    -+<p>
    -+<a NAME="Changed"></a>
    -+<TABLE summary="Changed Classes" WIDTH="100%">
    -+<TR>
    -+  <TH VALIGN="TOP" COLSPAN=2>Changed Classes</FONT></TD>
    -+</TH>
    -+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    -+  <TD VALIGN="TOP" WIDTH="25%">
    -+  <A NAME="DrawableCompat"></A>
    -+  <nobr><A HREF="android.support.v4.graphics.drawable.DrawableCompat.html">DrawableCompat</A></nobr>
    -+  </TD>
    -+  <TD>&nbsp;</TD>
    -+</TR>
    -+</TABLE>
    -+&nbsp;
    -+      </div>	
    -+      <div id="footer">
    -+        <div id="copyright">
    -+        Except as noted, this content is licensed under 
    -+        <a href="http://creativecommons.org/licenses/by/2.5/"> Creative Commons Attribution 2.5</a>.
    -+        For details and restrictions, see the <a href="/license.html">Content License</a>.
    -+        </div>
    -+      <div id="footerlinks">
    -+      <p>
    -+        <a href="http://www.android.com/terms.html">Site Terms of Service</a> -
    -+        <a href="http://www.android.com/privacy.html">Privacy Policy</a> -
    -+        <a href="http://www.android.com/branding.html">Brand Guidelines</a>
    -+      </p>
    -+    </div>
    -+    </div> <!-- end footer -->
    -+    </div><!-- end doc-content -->
    -+    </div> <!-- end body-content --> 
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    -+</script>
    -+<script type="text/javascript">
    -+  try {
    -+    var pageTracker = _gat._getTracker("UA-5831155-1");
    -+    pageTracker._setAllowAnchor(true);
    -+    pageTracker._initData();
    -+    pageTracker._trackPageview();
    -+  } catch(e) {}
    -+</script>
    -+</BODY>
    -+</HTML>
    -diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/pkg_android.support.v4.media.html b/docs/html/sdk/support_api_diff/24.2.0/changes/pkg_android.support.v4.media.html
    -new file mode 100644
    -index 0000000..5300c86
    ---- /dev/null
    -+++ b/docs/html/sdk/support_api_diff/24.2.0/changes/pkg_android.support.v4.media.html
    -@@ -0,0 +1,140 @@
    -+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
    -+<HTML style="overflow:auto;">
    -+<HEAD>
    -+<meta name="generator" content="JDiff v1.1.0">
    -+<!-- Generated by the JDiff Javadoc doclet -->
    -+<!-- (http://www.jdiff.org) -->
    -+<meta name="description" content="JDiff is a Javadoc doclet which generates an HTML report of all the packages, classes, constructors, methods, and fields which have been removed, added or changed in any way, including their documentation, when two APIs are compared.">
    -+<meta name="keywords" content="diff, jdiff, javadiff, java diff, java difference, API difference, difference between two APIs, API diff, Javadoc, doclet">
    -+<TITLE>
    -+android.support.v4.media
    -+</TITLE>
    -+<link href="../../../../assets/android-developer-docs.css" rel="stylesheet" type="text/css" />
    -+<link href="../stylesheet-jdiff.css" rel="stylesheet" type="text/css" />
    -+<noscript>
    -+<style type="text/css">
    -+body{overflow:auto;}
    -+#body-content{position:relative; top:0;}
    -+#doc-content{overflow:visible;border-left:3px solid #666;}
    -+#side-nav{padding:0;}
    -+#side-nav .toggle-list ul {display:block;}
    -+#resize-packages-nav{border-bottom:3px solid #666;}
    -+</style>
    -+</noscript>
    -+<style type="text/css">
    -+</style>
    -+</HEAD>
    -+<BODY>
    -+<!-- Start of nav bar -->
    -+<a name="top"></a>
    -+<div id="header" style="margin-bottom:0;padding-bottom:0;">
    -+<div id="headerLeft">
    -+<a href="../../../../index.html" tabindex="-1" target="_top"><img src="../../../../assets/images/bg_logo.png" alt="Android Developers" /></a>
    -+</div>
    -+  <div id="headerRight">
    -+  <div id="headerLinks">
    -+<!-- <img src="/assets/images/icon_world.jpg" alt="" /> -->
    -+<span class="text">
    -+<!-- &nbsp;<a href="#">English</a> | -->
    -+<nobr><a href="http://developer.android.com" target="_top">Android Developers</a> | <a href="http://www.android.com" target="_top">Android.com</a></nobr>
    -+</span>
    -+</div>
    -+  <div class="and-diff-id" style="margin-top:6px;margin-right:8px;">
    -+    <table class="diffspectable">
    -+      <tr>
    -+        <td colspan="2" class="diffspechead">API Diff Specification</td>
    -+      </tr>
    -+      <tr>
    -+        <td class="diffspec" style="padding-top:.25em">To Level:</td>
    -+        <td class="diffvaluenew" style="padding-top:.25em">24.2.0</td>
    -+      </tr>
    -+      <tr>
    -+        <td class="diffspec">From Level:</td>
    -+        <td class="diffvalueold">24.1.0</td>
    -+      </tr>
    -+      <tr>
    -+        <td class="diffspec">Generated</td>
    -+        <td class="diffvalue">2016.08.16 14:03</td>
    -+      </tr>
    -+    </table>
    -+    </div><!-- End and-diff-id -->
    -+  <div class="and-diff-id" style="margin-right:8px;">
    -+    <table class="diffspectable">
    -+      <tr>
    -+        <td class="diffspec" colspan="2"><a href="jdiff_statistics.html">Statistics</a>
    -+      </tr>
    -+    </table>
    -+  </div> <!-- End and-diff-id -->
    -+  </div> <!-- End headerRight -->
    -+  </div> <!-- End header -->
    -+<div id="body-content" xstyle="padding:12px;padding-right:18px;">
    -+<div id="doc-content" style="position:relative;">
    -+<div id="mainBodyFluid">
    -+<H2>
    -+Package <A HREF="../../../../reference/android/support/v4/media/package-summary.html" target="_top"><font size="+1"><code>android.support.v4.media</code></font></A>
    -+</H2>
    -+<p>
    -+<a NAME="Changed"></a>
    -+<TABLE summary="Changed Classes" WIDTH="100%">
    -+<TR>
    -+  <TH VALIGN="TOP" COLSPAN=2>Changed Classes</FONT></TD>
    -+</TH>
    -+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    -+  <TD VALIGN="TOP" WIDTH="25%">
    -+  <A NAME="MediaBrowserCompat.MediaItem"></A>
    -+  <nobr><A HREF="android.support.v4.media.MediaBrowserCompat.MediaItem.html">MediaBrowserCompat.MediaItem</A></nobr>
    -+  </TD>
    -+  <TD>&nbsp;</TD>
    -+</TR>
    -+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    -+  <TD VALIGN="TOP" WIDTH="25%">
    -+  <A NAME="MediaBrowserServiceCompat.BrowserRoot"></A>
    -+  <nobr><A HREF="android.support.v4.media.MediaBrowserServiceCompat.BrowserRoot.html">MediaBrowserServiceCompat.<br>BrowserRoot</A></nobr>
    -+  </TD>
    -+  <TD>&nbsp;</TD>
    -+</TR>
    -+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    -+  <TD VALIGN="TOP" WIDTH="25%">
    -+  <A NAME="MediaDescriptionCompat"></A>
    -+  <nobr><A HREF="android.support.v4.media.MediaDescriptionCompat.html">MediaDescriptionCompat</A></nobr>
    -+  </TD>
    -+  <TD>&nbsp;</TD>
    -+</TR>
    -+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    -+  <TD VALIGN="TOP" WIDTH="25%">
    -+  <A NAME="MediaMetadataCompat"></A>
    -+  <nobr><A HREF="android.support.v4.media.MediaMetadataCompat.html">MediaMetadataCompat</A></nobr>
    -+  </TD>
    -+  <TD>&nbsp;</TD>
    -+</TR>
    -+</TABLE>
    -+&nbsp;
    -+      </div>	
    -+      <div id="footer">
    -+        <div id="copyright">
    -+        Except as noted, this content is licensed under 
    -+        <a href="http://creativecommons.org/licenses/by/2.5/"> Creative Commons Attribution 2.5</a>.
    -+        For details and restrictions, see the <a href="/license.html">Content License</a>.
    -+        </div>
    -+      <div id="footerlinks">
    -+      <p>
    -+        <a href="http://www.android.com/terms.html">Site Terms of Service</a> -
    -+        <a href="http://www.android.com/privacy.html">Privacy Policy</a> -
    -+        <a href="http://www.android.com/branding.html">Brand Guidelines</a>
    -+      </p>
    -+    </div>
    -+    </div> <!-- end footer -->
    -+    </div><!-- end doc-content -->
    -+    </div> <!-- end body-content --> 
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    -+</script>
    -+<script type="text/javascript">
    -+  try {
    -+    var pageTracker = _gat._getTracker("UA-5831155-1");
    -+    pageTracker._setAllowAnchor(true);
    -+    pageTracker._initData();
    -+    pageTracker._trackPageview();
    -+  } catch(e) {}
    -+</script>
    -+</BODY>
    -+</HTML>
    -diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/pkg_android.support.v4.media.session.html b/docs/html/sdk/support_api_diff/24.2.0/changes/pkg_android.support.v4.media.session.html
    -new file mode 100644
    -index 0000000..459d0c3
    ---- /dev/null
    -+++ b/docs/html/sdk/support_api_diff/24.2.0/changes/pkg_android.support.v4.media.session.html
    -@@ -0,0 +1,140 @@
    -+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
    -+<HTML style="overflow:auto;">
    -+<HEAD>
    -+<meta name="generator" content="JDiff v1.1.0">
    -+<!-- Generated by the JDiff Javadoc doclet -->
    -+<!-- (http://www.jdiff.org) -->
    -+<meta name="description" content="JDiff is a Javadoc doclet which generates an HTML report of all the packages, classes, constructors, methods, and fields which have been removed, added or changed in any way, including their documentation, when two APIs are compared.">
    -+<meta name="keywords" content="diff, jdiff, javadiff, java diff, java difference, API difference, difference between two APIs, API diff, Javadoc, doclet">
    -+<TITLE>
    -+android.support.v4.media.session
    -+</TITLE>
    -+<link href="../../../../assets/android-developer-docs.css" rel="stylesheet" type="text/css" />
    -+<link href="../stylesheet-jdiff.css" rel="stylesheet" type="text/css" />
    -+<noscript>
    -+<style type="text/css">
    -+body{overflow:auto;}
    -+#body-content{position:relative; top:0;}
    -+#doc-content{overflow:visible;border-left:3px solid #666;}
    -+#side-nav{padding:0;}
    -+#side-nav .toggle-list ul {display:block;}
    -+#resize-packages-nav{border-bottom:3px solid #666;}
    -+</style>
    -+</noscript>
    -+<style type="text/css">
    -+</style>
    -+</HEAD>
    -+<BODY>
    -+<!-- Start of nav bar -->
    -+<a name="top"></a>
    -+<div id="header" style="margin-bottom:0;padding-bottom:0;">
    -+<div id="headerLeft">
    -+<a href="../../../../index.html" tabindex="-1" target="_top"><img src="../../../../assets/images/bg_logo.png" alt="Android Developers" /></a>
    -+</div>
    -+  <div id="headerRight">
    -+  <div id="headerLinks">
    -+<!-- <img src="/assets/images/icon_world.jpg" alt="" /> -->
    -+<span class="text">
    -+<!-- &nbsp;<a href="#">English</a> | -->
    -+<nobr><a href="http://developer.android.com" target="_top">Android Developers</a> | <a href="http://www.android.com" target="_top">Android.com</a></nobr>
    -+</span>
    -+</div>
    -+  <div class="and-diff-id" style="margin-top:6px;margin-right:8px;">
    -+    <table class="diffspectable">
    -+      <tr>
    -+        <td colspan="2" class="diffspechead">API Diff Specification</td>
    -+      </tr>
    -+      <tr>
    -+        <td class="diffspec" style="padding-top:.25em">To Level:</td>
    -+        <td class="diffvaluenew" style="padding-top:.25em">24.2.0</td>
    -+      </tr>
    -+      <tr>
    -+        <td class="diffspec">From Level:</td>
    -+        <td class="diffvalueold">24.1.0</td>
    -+      </tr>
    -+      <tr>
    -+        <td class="diffspec">Generated</td>
    -+        <td class="diffvalue">2016.08.16 14:03</td>
    -+      </tr>
    -+    </table>
    -+    </div><!-- End and-diff-id -->
    -+  <div class="and-diff-id" style="margin-right:8px;">
    -+    <table class="diffspectable">
    -+      <tr>
    -+        <td class="diffspec" colspan="2"><a href="jdiff_statistics.html">Statistics</a>
    -+      </tr>
    -+    </table>
    -+  </div> <!-- End and-diff-id -->
    -+  </div> <!-- End headerRight -->
    -+  </div> <!-- End header -->
    -+<div id="body-content" xstyle="padding:12px;padding-right:18px;">
    -+<div id="doc-content" style="position:relative;">
    -+<div id="mainBodyFluid">
    -+<H2>
    -+Package <A HREF="../../../../reference/android/support/v4/media/session/package-summary.html" target="_top"><font size="+1"><code>android.support.v4.media.session</code></font></A>
    -+</H2>
    -+<p>
    -+<a NAME="Changed"></a>
    -+<TABLE summary="Changed Classes" WIDTH="100%">
    -+<TR>
    -+  <TH VALIGN="TOP" COLSPAN=2>Changed Classes</FONT></TD>
    -+</TH>
    -+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    -+  <TD VALIGN="TOP" WIDTH="25%">
    -+  <A NAME="MediaButtonReceiver"></A>
    -+  <nobr><A HREF="android.support.v4.media.session.MediaButtonReceiver.html">MediaButtonReceiver</A></nobr>
    -+  </TD>
    -+  <TD>&nbsp;</TD>
    -+</TR>
    -+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    -+  <TD VALIGN="TOP" WIDTH="25%">
    -+  <A NAME="MediaSessionCompat"></A>
    -+  <nobr><A HREF="android.support.v4.media.session.MediaSessionCompat.html">MediaSessionCompat</A></nobr>
    -+  </TD>
    -+  <TD>&nbsp;</TD>
    -+</TR>
    -+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    -+  <TD VALIGN="TOP" WIDTH="25%">
    -+  <A NAME="MediaSessionCompat.QueueItem"></A>
    -+  <nobr><A HREF="android.support.v4.media.session.MediaSessionCompat.QueueItem.html">MediaSessionCompat.QueueItem</A></nobr>
    -+  </TD>
    -+  <TD>&nbsp;</TD>
    -+</TR>
    -+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    -+  <TD VALIGN="TOP" WIDTH="25%">
    -+  <A NAME="PlaybackStateCompat"></A>
    -+  <nobr><A HREF="android.support.v4.media.session.PlaybackStateCompat.html">PlaybackStateCompat</A></nobr>
    -+  </TD>
    -+  <TD>&nbsp;</TD>
    -+</TR>
    -+</TABLE>
    -+&nbsp;
    -+      </div>	
    -+      <div id="footer">
    -+        <div id="copyright">
    -+        Except as noted, this content is licensed under 
    -+        <a href="http://creativecommons.org/licenses/by/2.5/"> Creative Commons Attribution 2.5</a>.
    -+        For details and restrictions, see the <a href="/license.html">Content License</a>.
    -+        </div>
    -+      <div id="footerlinks">
    -+      <p>
    -+        <a href="http://www.android.com/terms.html">Site Terms of Service</a> -
    -+        <a href="http://www.android.com/privacy.html">Privacy Policy</a> -
    -+        <a href="http://www.android.com/branding.html">Brand Guidelines</a>
    -+      </p>
    -+    </div>
    -+    </div> <!-- end footer -->
    -+    </div><!-- end doc-content -->
    -+    </div> <!-- end body-content --> 
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    -+</script>
    -+<script type="text/javascript">
    -+  try {
    -+    var pageTracker = _gat._getTracker("UA-5831155-1");
    -+    pageTracker._setAllowAnchor(true);
    -+    pageTracker._initData();
    -+    pageTracker._trackPageview();
    -+  } catch(e) {}
    -+</script>
    -+</BODY>
    -+</HTML>
    -diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/pkg_android.support.v4.os.html b/docs/html/sdk/support_api_diff/24.2.0/changes/pkg_android.support.v4.os.html
    -new file mode 100644
    -index 0000000..6d7f399
    ---- /dev/null
    -+++ b/docs/html/sdk/support_api_diff/24.2.0/changes/pkg_android.support.v4.os.html
    -@@ -0,0 +1,119 @@
    -+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
    -+<HTML style="overflow:auto;">
    -+<HEAD>
    -+<meta name="generator" content="JDiff v1.1.0">
    -+<!-- Generated by the JDiff Javadoc doclet -->
    -+<!-- (http://www.jdiff.org) -->
    -+<meta name="description" content="JDiff is a Javadoc doclet which generates an HTML report of all the packages, classes, constructors, methods, and fields which have been removed, added or changed in any way, including their documentation, when two APIs are compared.">
    -+<meta name="keywords" content="diff, jdiff, javadiff, java diff, java difference, API difference, difference between two APIs, API diff, Javadoc, doclet">
    -+<TITLE>
    -+android.support.v4.os
    -+</TITLE>
    -+<link href="../../../../assets/android-developer-docs.css" rel="stylesheet" type="text/css" />
    -+<link href="../stylesheet-jdiff.css" rel="stylesheet" type="text/css" />
    -+<noscript>
    -+<style type="text/css">
    -+body{overflow:auto;}
    -+#body-content{position:relative; top:0;}
    -+#doc-content{overflow:visible;border-left:3px solid #666;}
    -+#side-nav{padding:0;}
    -+#side-nav .toggle-list ul {display:block;}
    -+#resize-packages-nav{border-bottom:3px solid #666;}
    -+</style>
    -+</noscript>
    -+<style type="text/css">
    -+</style>
    -+</HEAD>
    -+<BODY>
    -+<!-- Start of nav bar -->
    -+<a name="top"></a>
    -+<div id="header" style="margin-bottom:0;padding-bottom:0;">
    -+<div id="headerLeft">
    -+<a href="../../../../index.html" tabindex="-1" target="_top"><img src="../../../../assets/images/bg_logo.png" alt="Android Developers" /></a>
    -+</div>
    -+  <div id="headerRight">
    -+  <div id="headerLinks">
    -+<!-- <img src="/assets/images/icon_world.jpg" alt="" /> -->
    -+<span class="text">
    -+<!-- &nbsp;<a href="#">English</a> | -->
    -+<nobr><a href="http://developer.android.com" target="_top">Android Developers</a> | <a href="http://www.android.com" target="_top">Android.com</a></nobr>
    -+</span>
    -+</div>
    -+  <div class="and-diff-id" style="margin-top:6px;margin-right:8px;">
    -+    <table class="diffspectable">
    -+      <tr>
    -+        <td colspan="2" class="diffspechead">API Diff Specification</td>
    -+      </tr>
    -+      <tr>
    -+        <td class="diffspec" style="padding-top:.25em">To Level:</td>
    -+        <td class="diffvaluenew" style="padding-top:.25em">24.2.0</td>
    -+      </tr>
    -+      <tr>
    -+        <td class="diffspec">From Level:</td>
    -+        <td class="diffvalueold">24.1.0</td>
    -+      </tr>
    -+      <tr>
    -+        <td class="diffspec">Generated</td>
    -+        <td class="diffvalue">2016.08.16 14:03</td>
    -+      </tr>
    -+    </table>
    -+    </div><!-- End and-diff-id -->
    -+  <div class="and-diff-id" style="margin-right:8px;">
    -+    <table class="diffspectable">
    -+      <tr>
    -+        <td class="diffspec" colspan="2"><a href="jdiff_statistics.html">Statistics</a>
    -+      </tr>
    -+    </table>
    -+  </div> <!-- End and-diff-id -->
    -+  </div> <!-- End headerRight -->
    -+  </div> <!-- End header -->
    -+<div id="body-content" xstyle="padding:12px;padding-right:18px;">
    -+<div id="doc-content" style="position:relative;">
    -+<div id="mainBodyFluid">
    -+<H2>
    -+Package <A HREF="../../../../reference/android/support/v4/os/package-summary.html" target="_top"><font size="+1"><code>android.support.v4.os</code></font></A>
    -+</H2>
    -+<p>
    -+<a NAME="Changed"></a>
    -+<TABLE summary="Changed Classes" WIDTH="100%">
    -+<TR>
    -+  <TH VALIGN="TOP" COLSPAN=2>Changed Classes</FONT></TD>
    -+</TH>
    -+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    -+  <TD VALIGN="TOP" WIDTH="25%">
    -+  <A NAME="BuildCompat"></A>
    -+  <nobr><A HREF="android.support.v4.os.BuildCompat.html">BuildCompat</A></nobr>
    -+  </TD>
    -+  <TD>&nbsp;</TD>
    -+</TR>
    -+</TABLE>
    -+&nbsp;
    -+      </div>	
    -+      <div id="footer">
    -+        <div id="copyright">
    -+        Except as noted, this content is licensed under 
    -+        <a href="http://creativecommons.org/licenses/by/2.5/"> Creative Commons Attribution 2.5</a>.
    -+        For details and restrictions, see the <a href="/license.html">Content License</a>.
    -+        </div>
    -+      <div id="footerlinks">
    -+      <p>
    -+        <a href="http://www.android.com/terms.html">Site Terms of Service</a> -
    -+        <a href="http://www.android.com/privacy.html">Privacy Policy</a> -
    -+        <a href="http://www.android.com/branding.html">Brand Guidelines</a>
    -+      </p>
    -+    </div>
    -+    </div> <!-- end footer -->
    -+    </div><!-- end doc-content -->
    -+    </div> <!-- end body-content --> 
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    -+</script>
    -+<script type="text/javascript">
    -+  try {
    -+    var pageTracker = _gat._getTracker("UA-5831155-1");
    -+    pageTracker._setAllowAnchor(true);
    -+    pageTracker._initData();
    -+    pageTracker._trackPageview();
    -+  } catch(e) {}
    -+</script>
    -+</BODY>
    -+</HTML>
    -diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/pkg_android.support.v4.util.html b/docs/html/sdk/support_api_diff/24.2.0/changes/pkg_android.support.v4.util.html
    -new file mode 100644
    -index 0000000..6f0e777
    ---- /dev/null
    -+++ b/docs/html/sdk/support_api_diff/24.2.0/changes/pkg_android.support.v4.util.html
    -@@ -0,0 +1,119 @@
    -+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
    -+<HTML style="overflow:auto;">
    -+<HEAD>
    -+<meta name="generator" content="JDiff v1.1.0">
    -+<!-- Generated by the JDiff Javadoc doclet -->
    -+<!-- (http://www.jdiff.org) -->
    -+<meta name="description" content="JDiff is a Javadoc doclet which generates an HTML report of all the packages, classes, constructors, methods, and fields which have been removed, added or changed in any way, including their documentation, when two APIs are compared.">
    -+<meta name="keywords" content="diff, jdiff, javadiff, java diff, java difference, API difference, difference between two APIs, API diff, Javadoc, doclet">
    -+<TITLE>
    -+android.support.v4.util
    -+</TITLE>
    -+<link href="../../../../assets/android-developer-docs.css" rel="stylesheet" type="text/css" />
    -+<link href="../stylesheet-jdiff.css" rel="stylesheet" type="text/css" />
    -+<noscript>
    -+<style type="text/css">
    -+body{overflow:auto;}
    -+#body-content{position:relative; top:0;}
    -+#doc-content{overflow:visible;border-left:3px solid #666;}
    -+#side-nav{padding:0;}
    -+#side-nav .toggle-list ul {display:block;}
    -+#resize-packages-nav{border-bottom:3px solid #666;}
    -+</style>
    -+</noscript>
    -+<style type="text/css">
    -+</style>
    -+</HEAD>
    -+<BODY>
    -+<!-- Start of nav bar -->
    -+<a name="top"></a>
    -+<div id="header" style="margin-bottom:0;padding-bottom:0;">
    -+<div id="headerLeft">
    -+<a href="../../../../index.html" tabindex="-1" target="_top"><img src="../../../../assets/images/bg_logo.png" alt="Android Developers" /></a>
    -+</div>
    -+  <div id="headerRight">
    -+  <div id="headerLinks">
    -+<!-- <img src="/assets/images/icon_world.jpg" alt="" /> -->
    -+<span class="text">
    -+<!-- &nbsp;<a href="#">English</a> | -->
    -+<nobr><a href="http://developer.android.com" target="_top">Android Developers</a> | <a href="http://www.android.com" target="_top">Android.com</a></nobr>
    -+</span>
    -+</div>
    -+  <div class="and-diff-id" style="margin-top:6px;margin-right:8px;">
    -+    <table class="diffspectable">
    -+      <tr>
    -+        <td colspan="2" class="diffspechead">API Diff Specification</td>
    -+      </tr>
    -+      <tr>
    -+        <td class="diffspec" style="padding-top:.25em">To Level:</td>
    -+        <td class="diffvaluenew" style="padding-top:.25em">24.2.0</td>
    -+      </tr>
    -+      <tr>
    -+        <td class="diffspec">From Level:</td>
    -+        <td class="diffvalueold">24.1.0</td>
    -+      </tr>
    -+      <tr>
    -+        <td class="diffspec">Generated</td>
    -+        <td class="diffvalue">2016.08.16 14:03</td>
    -+      </tr>
    -+    </table>
    -+    </div><!-- End and-diff-id -->
    -+  <div class="and-diff-id" style="margin-right:8px;">
    -+    <table class="diffspectable">
    -+      <tr>
    -+        <td class="diffspec" colspan="2"><a href="jdiff_statistics.html">Statistics</a>
    -+      </tr>
    -+    </table>
    -+  </div> <!-- End and-diff-id -->
    -+  </div> <!-- End headerRight -->
    -+  </div> <!-- End header -->
    -+<div id="body-content" xstyle="padding:12px;padding-right:18px;">
    -+<div id="doc-content" style="position:relative;">
    -+<div id="mainBodyFluid">
    -+<H2>
    -+Package <A HREF="../../../../reference/android/support/v4/util/package-summary.html" target="_top"><font size="+1"><code>android.support.v4.util</code></font></A>
    -+</H2>
    -+<p>
    -+<a NAME="Added"></a>
    -+<TABLE summary="Added Classes" WIDTH="100%">
    -+<TR>
    -+  <TH VALIGN="TOP" COLSPAN=2>Added Classes</FONT></TD>
    -+</TH>
    -+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    -+  <TD VALIGN="TOP" WIDTH="25%">
    -+  <A NAME="PatternsCompat"></A>
    -+  <nobr><A HREF="../../../../reference/android/support/v4/util/PatternsCompat.html" target="_top"><code>PatternsCompat</code></A></nobr>
    -+  </TD>
    -+  <TD>&nbsp;</TD>
    -+</TR>
    -+</TABLE>
    -+&nbsp;
    -+      </div>	
    -+      <div id="footer">
    -+        <div id="copyright">
    -+        Except as noted, this content is licensed under 
    -+        <a href="http://creativecommons.org/licenses/by/2.5/"> Creative Commons Attribution 2.5</a>.
    -+        For details and restrictions, see the <a href="/license.html">Content License</a>.
    -+        </div>
    -+      <div id="footerlinks">
    -+      <p>
    -+        <a href="http://www.android.com/terms.html">Site Terms of Service</a> -
    -+        <a href="http://www.android.com/privacy.html">Privacy Policy</a> -
    -+        <a href="http://www.android.com/branding.html">Brand Guidelines</a>
    -+      </p>
    -+    </div>
    -+    </div> <!-- end footer -->
    -+    </div><!-- end doc-content -->
    -+    </div> <!-- end body-content --> 
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    -+</script>
    -+<script type="text/javascript">
    -+  try {
    -+    var pageTracker = _gat._getTracker("UA-5831155-1");
    -+    pageTracker._setAllowAnchor(true);
    -+    pageTracker._initData();
    -+    pageTracker._trackPageview();
    -+  } catch(e) {}
    -+</script>
    -+</BODY>
    -+</HTML>
    -diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/pkg_android.support.v4.view.accessibility.html b/docs/html/sdk/support_api_diff/24.2.0/changes/pkg_android.support.v4.view.accessibility.html
    -new file mode 100644
    -index 0000000..d5d126c
    ---- /dev/null
    -+++ b/docs/html/sdk/support_api_diff/24.2.0/changes/pkg_android.support.v4.view.accessibility.html
    -@@ -0,0 +1,204 @@
    -+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
    -+<HTML style="overflow:auto;">
    -+<HEAD>
    -+<meta name="generator" content="JDiff v1.1.0">
    -+<!-- Generated by the JDiff Javadoc doclet -->
    -+<!-- (http://www.jdiff.org) -->
    -+<meta name="description" content="JDiff is a Javadoc doclet which generates an HTML report of all the packages, classes, constructors, methods, and fields which have been removed, added or changed in any way, including their documentation, when two APIs are compared.">
    -+<meta name="keywords" content="diff, jdiff, javadiff, java diff, java difference, API difference, difference between two APIs, API diff, Javadoc, doclet">
    -+<TITLE>
    -+android.support.v4.view.accessibility
    -+</TITLE>
    -+<link href="../../../../assets/android-developer-docs.css" rel="stylesheet" type="text/css" />
    -+<link href="../stylesheet-jdiff.css" rel="stylesheet" type="text/css" />
    -+<noscript>
    -+<style type="text/css">
    -+body{overflow:auto;}
    -+#body-content{position:relative; top:0;}
    -+#doc-content{overflow:visible;border-left:3px solid #666;}
    -+#side-nav{padding:0;}
    -+#side-nav .toggle-list ul {display:block;}
    -+#resize-packages-nav{border-bottom:3px solid #666;}
    -+</style>
    -+</noscript>
    -+<style type="text/css">
    -+</style>
    -+</HEAD>
    -+<BODY>
    -+<!-- Start of nav bar -->
    -+<a name="top"></a>
    -+<div id="header" style="margin-bottom:0;padding-bottom:0;">
    -+<div id="headerLeft">
    -+<a href="../../../../index.html" tabindex="-1" target="_top"><img src="../../../../assets/images/bg_logo.png" alt="Android Developers" /></a>
    -+</div>
    -+  <div id="headerRight">
    -+  <div id="headerLinks">
    -+<!-- <img src="/assets/images/icon_world.jpg" alt="" /> -->
    -+<span class="text">
    -+<!-- &nbsp;<a href="#">English</a> | -->
    -+<nobr><a href="http://developer.android.com" target="_top">Android Developers</a> | <a href="http://www.android.com" target="_top">Android.com</a></nobr>
    -+</span>
    -+</div>
    -+  <div class="and-diff-id" style="margin-top:6px;margin-right:8px;">
    -+    <table class="diffspectable">
    -+      <tr>
    -+        <td colspan="2" class="diffspechead">API Diff Specification</td>
    -+      </tr>
    -+      <tr>
    -+        <td class="diffspec" style="padding-top:.25em">To Level:</td>
    -+        <td class="diffvaluenew" style="padding-top:.25em">24.2.0</td>
    -+      </tr>
    -+      <tr>
    -+        <td class="diffspec">From Level:</td>
    -+        <td class="diffvalueold">24.1.0</td>
    -+      </tr>
    -+      <tr>
    -+        <td class="diffspec">Generated</td>
    -+        <td class="diffvalue">2016.08.16 14:03</td>
    -+      </tr>
    -+    </table>
    -+    </div><!-- End and-diff-id -->
    -+  <div class="and-diff-id" style="margin-right:8px;">
    -+    <table class="diffspectable">
    -+      <tr>
    -+        <td class="diffspec" colspan="2"><a href="jdiff_statistics.html">Statistics</a>
    -+      </tr>
    -+    </table>
    -+  </div> <!-- End and-diff-id -->
    -+  </div> <!-- End headerRight -->
    -+  </div> <!-- End header -->
    -+<div id="body-content" xstyle="padding:12px;padding-right:18px;">
    -+<div id="doc-content" style="position:relative;">
    -+<div id="mainBodyFluid">
    -+<H2>
    -+Package <A HREF="../../../../reference/android/support/v4/view/accessibility/package-summary.html" target="_top"><font size="+1"><code>android.support.v4.view.accessibility</code></font></A>
    -+</H2>
    -+<p>
    -+<a NAME="Added"></a>
    -+<TABLE summary="Added Interfaces" WIDTH="100%">
    -+<TR>
    -+  <TH VALIGN="TOP" COLSPAN=2>Added Interfaces</FONT></TD>
    -+</TH>
    -+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    -+  <TD VALIGN="TOP" WIDTH="25%">
    -+  <A NAME="AccessibilityManagerCompat.AccessibilityStateChangeListener"></A>
    -+  <nobr><A HREF="../../../../reference/android/support/v4/view/accessibility/AccessibilityManagerCompat.AccessibilityStateChangeListener.html" target="_top"><code><I>AccessibilityManagerCompat.<br>AccessibilityStateChangeListener</I></code></A></nobr>
    -+  </TD>
    -+  <TD>&nbsp;</TD>
    -+</TR>
    -+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    -+  <TD VALIGN="TOP" WIDTH="25%">
    -+  <A NAME="AccessibilityManagerCompat.TouchExplorationStateChangeListener"></A>
    -+  <nobr><A HREF="../../../../reference/android/support/v4/view/accessibility/AccessibilityManagerCompat.TouchExplorationStateChangeListener.html" target="_top"><code><I>AccessibilityManagerCompat.<br>TouchExplorationStateChangeListener</I></code></A></nobr>
    -+  </TD>
    -+  <TD>&nbsp;</TD>
    -+</TR>
    -+</TABLE>
    -+&nbsp;
    -+<p>
    -+<a NAME="Changed"></a>
    -+<TABLE summary="Changed Classes" WIDTH="100%">
    -+<TR>
    -+  <TH VALIGN="TOP" COLSPAN=2>Changed Classes</FONT></TD>
    -+</TH>
    -+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    -+  <TD VALIGN="TOP" WIDTH="25%">
    -+  <A NAME="AccessibilityEventCompat"></A>
    -+  <nobr><A HREF="android.support.v4.view.accessibility.AccessibilityEventCompat.html">AccessibilityEventCompat</A></nobr>
    -+  </TD>
    -+  <TD>&nbsp;</TD>
    -+</TR>
    -+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    -+  <TD VALIGN="TOP" WIDTH="25%">
    -+  <A NAME="AccessibilityManagerCompat"></A>
    -+  <nobr><A HREF="android.support.v4.view.accessibility.AccessibilityManagerCompat.html">AccessibilityManagerCompat</A></nobr>
    -+  </TD>
    -+  <TD>&nbsp;</TD>
    -+</TR>
    -+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    -+  <TD VALIGN="TOP" WIDTH="25%">
    -+  <A NAME="AccessibilityManagerCompat.AccessibilityStateChangeListenerCompat"></A>
    -+  <nobr><A HREF="android.support.v4.view.accessibility.AccessibilityManagerCompat.AccessibilityStateChangeListenerCompat.html">AccessibilityManagerCompat.<br>AccessibilityStateChangeListenerCompat</A></nobr>
    -+  </TD>
    -+  <TD>&nbsp;</TD>
    -+</TR>
    -+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    -+  <TD VALIGN="TOP" WIDTH="25%">
    -+  <A NAME="AccessibilityNodeInfoCompat"></A>
    -+  <nobr><A HREF="android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.html">AccessibilityNodeInfoCompat</A></nobr>
    -+  </TD>
    -+  <TD>&nbsp;</TD>
    -+</TR>
    -+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    -+  <TD VALIGN="TOP" WIDTH="25%">
    -+  <A NAME="AccessibilityNodeInfoCompat.AccessibilityActionCompat"></A>
    -+  <nobr><A HREF="android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat.html">AccessibilityNodeInfoCompat.<br>AccessibilityActionCompat</A></nobr>
    -+  </TD>
    -+  <TD>&nbsp;</TD>
    -+</TR>
    -+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    -+  <TD VALIGN="TOP" WIDTH="25%">
    -+  <A NAME="AccessibilityNodeInfoCompat.CollectionInfoCompat"></A>
    -+  <nobr><A HREF="android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.CollectionInfoCompat.html">AccessibilityNodeInfoCompat.<br>CollectionInfoCompat</A></nobr>
    -+  </TD>
    -+  <TD>&nbsp;</TD>
    -+</TR>
    -+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    -+  <TD VALIGN="TOP" WIDTH="25%">
    -+  <A NAME="AccessibilityNodeInfoCompat.CollectionItemInfoCompat"></A>
    -+  <nobr><A HREF="android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.CollectionItemInfoCompat.html">AccessibilityNodeInfoCompat.<br>CollectionItemInfoCompat</A></nobr>
    -+  </TD>
    -+  <TD>&nbsp;</TD>
    -+</TR>
    -+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    -+  <TD VALIGN="TOP" WIDTH="25%">
    -+  <A NAME="AccessibilityNodeInfoCompat.RangeInfoCompat"></A>
    -+  <nobr><A HREF="android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.RangeInfoCompat.html">AccessibilityNodeInfoCompat.<br>RangeInfoCompat</A></nobr>
    -+  </TD>
    -+  <TD>&nbsp;</TD>
    -+</TR>
    -+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    -+  <TD VALIGN="TOP" WIDTH="25%">
    -+  <A NAME="AccessibilityNodeProviderCompat"></A>
    -+  <nobr><A HREF="android.support.v4.view.accessibility.AccessibilityNodeProviderCompat.html">AccessibilityNodeProviderCompat</A></nobr>
    -+  </TD>
    -+  <TD>&nbsp;</TD>
    -+</TR>
    -+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    -+  <TD VALIGN="TOP" WIDTH="25%">
    -+  <A NAME="AccessibilityWindowInfoCompat"></A>
    -+  <nobr><A HREF="android.support.v4.view.accessibility.AccessibilityWindowInfoCompat.html">AccessibilityWindowInfoCompat</A></nobr>
    -+  </TD>
    -+  <TD>&nbsp;</TD>
    -+</TR>
    -+</TABLE>
    -+&nbsp;
    -+      </div>	
    -+      <div id="footer">
    -+        <div id="copyright">
    -+        Except as noted, this content is licensed under 
    -+        <a href="http://creativecommons.org/licenses/by/2.5/"> Creative Commons Attribution 2.5</a>.
    -+        For details and restrictions, see the <a href="/license.html">Content License</a>.
    -+        </div>
    -+      <div id="footerlinks">
    -+      <p>
    -+        <a href="http://www.android.com/terms.html">Site Terms of Service</a> -
    -+        <a href="http://www.android.com/privacy.html">Privacy Policy</a> -
    -+        <a href="http://www.android.com/branding.html">Brand Guidelines</a>
    -+      </p>
    -+    </div>
    -+    </div> <!-- end footer -->
    -+    </div><!-- end doc-content -->
    -+    </div> <!-- end body-content --> 
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    -+</script>
    -+<script type="text/javascript">
    -+  try {
    -+    var pageTracker = _gat._getTracker("UA-5831155-1");
    -+    pageTracker._setAllowAnchor(true);
    -+    pageTracker._initData();
    -+    pageTracker._trackPageview();
    -+  } catch(e) {}
    -+</script>
    -+</BODY>
    -+</HTML>
    -diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/pkg_android.support.v4.view.html b/docs/html/sdk/support_api_diff/24.2.0/changes/pkg_android.support.v4.view.html
    -new file mode 100644
    -index 0000000..d720d41
    ---- /dev/null
    -+++ b/docs/html/sdk/support_api_diff/24.2.0/changes/pkg_android.support.v4.view.html
    -@@ -0,0 +1,147 @@
    -+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
    -+<HTML style="overflow:auto;">
    -+<HEAD>
    -+<meta name="generator" content="JDiff v1.1.0">
    -+<!-- Generated by the JDiff Javadoc doclet -->
    -+<!-- (http://www.jdiff.org) -->
    -+<meta name="description" content="JDiff is a Javadoc doclet which generates an HTML report of all the packages, classes, constructors, methods, and fields which have been removed, added or changed in any way, including their documentation, when two APIs are compared.">
    -+<meta name="keywords" content="diff, jdiff, javadiff, java diff, java difference, API difference, difference between two APIs, API diff, Javadoc, doclet">
    -+<TITLE>
    -+android.support.v4.view
    -+</TITLE>
    -+<link href="../../../../assets/android-developer-docs.css" rel="stylesheet" type="text/css" />
    -+<link href="../stylesheet-jdiff.css" rel="stylesheet" type="text/css" />
    -+<noscript>
    -+<style type="text/css">
    -+body{overflow:auto;}
    -+#body-content{position:relative; top:0;}
    -+#doc-content{overflow:visible;border-left:3px solid #666;}
    -+#side-nav{padding:0;}
    -+#side-nav .toggle-list ul {display:block;}
    -+#resize-packages-nav{border-bottom:3px solid #666;}
    -+</style>
    -+</noscript>
    -+<style type="text/css">
    -+</style>
    -+</HEAD>
    -+<BODY>
    -+<!-- Start of nav bar -->
    -+<a name="top"></a>
    -+<div id="header" style="margin-bottom:0;padding-bottom:0;">
    -+<div id="headerLeft">
    -+<a href="../../../../index.html" tabindex="-1" target="_top"><img src="../../../../assets/images/bg_logo.png" alt="Android Developers" /></a>
    -+</div>
    -+  <div id="headerRight">
    -+  <div id="headerLinks">
    -+<!-- <img src="/assets/images/icon_world.jpg" alt="" /> -->
    -+<span class="text">
    -+<!-- &nbsp;<a href="#">English</a> | -->
    -+<nobr><a href="http://developer.android.com" target="_top">Android Developers</a> | <a href="http://www.android.com" target="_top">Android.com</a></nobr>
    -+</span>
    -+</div>
    -+  <div class="and-diff-id" style="margin-top:6px;margin-right:8px;">
    -+    <table class="diffspectable">
    -+      <tr>
    -+        <td colspan="2" class="diffspechead">API Diff Specification</td>
    -+      </tr>
    -+      <tr>
    -+        <td class="diffspec" style="padding-top:.25em">To Level:</td>
    -+        <td class="diffvaluenew" style="padding-top:.25em">24.2.0</td>
    -+      </tr>
    -+      <tr>
    -+        <td class="diffspec">From Level:</td>
    -+        <td class="diffvalueold">24.1.0</td>
    -+      </tr>
    -+      <tr>
    -+        <td class="diffspec">Generated</td>
    -+        <td class="diffvalue">2016.08.16 14:03</td>
    -+      </tr>
    -+    </table>
    -+    </div><!-- End and-diff-id -->
    -+  <div class="and-diff-id" style="margin-right:8px;">
    -+    <table class="diffspectable">
    -+      <tr>
    -+        <td class="diffspec" colspan="2"><a href="jdiff_statistics.html">Statistics</a>
    -+      </tr>
    -+    </table>
    -+  </div> <!-- End and-diff-id -->
    -+  </div> <!-- End headerRight -->
    -+  </div> <!-- End header -->
    -+<div id="body-content" xstyle="padding:12px;padding-right:18px;">
    -+<div id="doc-content" style="position:relative;">
    -+<div id="mainBodyFluid">
    -+<H2>
    -+Package <A HREF="../../../../reference/android/support/v4/view/package-summary.html" target="_top"><font size="+1"><code>android.support.v4.view</code></font></A>
    -+</H2>
    -+<p>
    -+<a NAME="Changed"></a>
    -+<TABLE summary="Changed Classes" WIDTH="100%">
    -+<TR>
    -+  <TH VALIGN="TOP" COLSPAN=2>Changed Classes</FONT></TD>
    -+</TH>
    -+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    -+  <TD VALIGN="TOP" WIDTH="25%">
    -+  <A NAME="KeyEventCompat"></A>
    -+  <nobr><A HREF="android.support.v4.view.KeyEventCompat.html">KeyEventCompat</A></nobr>
    -+  </TD>
    -+  <TD>&nbsp;</TD>
    -+</TR>
    -+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    -+  <TD VALIGN="TOP" WIDTH="25%">
    -+  <A NAME="MotionEventCompat"></A>
    -+  <nobr><A HREF="android.support.v4.view.MotionEventCompat.html">MotionEventCompat</A></nobr>
    -+  </TD>
    -+  <TD>&nbsp;</TD>
    -+</TR>
    -+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    -+  <TD VALIGN="TOP" WIDTH="25%">
    -+  <A NAME="ViewCompat"></A>
    -+  <nobr><A HREF="android.support.v4.view.ViewCompat.html">ViewCompat</A></nobr>
    -+  </TD>
    -+  <TD>&nbsp;</TD>
    -+</TR>
    -+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    -+  <TD VALIGN="TOP" WIDTH="25%">
    -+  <A NAME="ViewConfigurationCompat"></A>
    -+  <nobr><A HREF="android.support.v4.view.ViewConfigurationCompat.html">ViewConfigurationCompat</A></nobr>
    -+  </TD>
    -+  <TD>&nbsp;</TD>
    -+</TR>
    -+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    -+  <TD VALIGN="TOP" WIDTH="25%">
    -+  <A NAME="WindowInsetsCompat"></A>
    -+  <nobr><A HREF="android.support.v4.view.WindowInsetsCompat.html">WindowInsetsCompat</A></nobr>
    -+  </TD>
    -+  <TD>&nbsp;</TD>
    -+</TR>
    -+</TABLE>
    -+&nbsp;
    -+      </div>	
    -+      <div id="footer">
    -+        <div id="copyright">
    -+        Except as noted, this content is licensed under 
    -+        <a href="http://creativecommons.org/licenses/by/2.5/"> Creative Commons Attribution 2.5</a>.
    -+        For details and restrictions, see the <a href="/license.html">Content License</a>.
    -+        </div>
    -+      <div id="footerlinks">
    -+      <p>
    -+        <a href="http://www.android.com/terms.html">Site Terms of Service</a> -
    -+        <a href="http://www.android.com/privacy.html">Privacy Policy</a> -
    -+        <a href="http://www.android.com/branding.html">Brand Guidelines</a>
    -+      </p>
    -+    </div>
    -+    </div> <!-- end footer -->
    -+    </div><!-- end doc-content -->
    -+    </div> <!-- end body-content --> 
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    -+</script>
    -+<script type="text/javascript">
    -+  try {
    -+    var pageTracker = _gat._getTracker("UA-5831155-1");
    -+    pageTracker._setAllowAnchor(true);
    -+    pageTracker._initData();
    -+    pageTracker._trackPageview();
    -+  } catch(e) {}
    -+</script>
    -+</BODY>
    -+</HTML>
    -diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/pkg_android.support.v4.widget.html b/docs/html/sdk/support_api_diff/24.2.0/changes/pkg_android.support.v4.widget.html
    -new file mode 100644
    -index 0000000..2efef45
    ---- /dev/null
    -+++ b/docs/html/sdk/support_api_diff/24.2.0/changes/pkg_android.support.v4.widget.html
    -@@ -0,0 +1,176 @@
    -+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
    -+<HTML style="overflow:auto;">
    -+<HEAD>
    -+<meta name="generator" content="JDiff v1.1.0">
    -+<!-- Generated by the JDiff Javadoc doclet -->
    -+<!-- (http://www.jdiff.org) -->
    -+<meta name="description" content="JDiff is a Javadoc doclet which generates an HTML report of all the packages, classes, constructors, methods, and fields which have been removed, added or changed in any way, including their documentation, when two APIs are compared.">
    -+<meta name="keywords" content="diff, jdiff, javadiff, java diff, java difference, API difference, difference between two APIs, API diff, Javadoc, doclet">
    -+<TITLE>
    -+android.support.v4.widget
    -+</TITLE>
    -+<link href="../../../../assets/android-developer-docs.css" rel="stylesheet" type="text/css" />
    -+<link href="../stylesheet-jdiff.css" rel="stylesheet" type="text/css" />
    -+<noscript>
    -+<style type="text/css">
    -+body{overflow:auto;}
    -+#body-content{position:relative; top:0;}
    -+#doc-content{overflow:visible;border-left:3px solid #666;}
    -+#side-nav{padding:0;}
    -+#side-nav .toggle-list ul {display:block;}
    -+#resize-packages-nav{border-bottom:3px solid #666;}
    -+</style>
    -+</noscript>
    -+<style type="text/css">
    -+</style>
    -+</HEAD>
    -+<BODY>
    -+<!-- Start of nav bar -->
    -+<a name="top"></a>
    -+<div id="header" style="margin-bottom:0;padding-bottom:0;">
    -+<div id="headerLeft">
    -+<a href="../../../../index.html" tabindex="-1" target="_top"><img src="../../../../assets/images/bg_logo.png" alt="Android Developers" /></a>
    -+</div>
    -+  <div id="headerRight">
    -+  <div id="headerLinks">
    -+<!-- <img src="/assets/images/icon_world.jpg" alt="" /> -->
    -+<span class="text">
    -+<!-- &nbsp;<a href="#">English</a> | -->
    -+<nobr><a href="http://developer.android.com" target="_top">Android Developers</a> | <a href="http://www.android.com" target="_top">Android.com</a></nobr>
    -+</span>
    -+</div>
    -+  <div class="and-diff-id" style="margin-top:6px;margin-right:8px;">
    -+    <table class="diffspectable">
    -+      <tr>
    -+        <td colspan="2" class="diffspechead">API Diff Specification</td>
    -+      </tr>
    -+      <tr>
    -+        <td class="diffspec" style="padding-top:.25em">To Level:</td>
    -+        <td class="diffvaluenew" style="padding-top:.25em">24.2.0</td>
    -+      </tr>
    -+      <tr>
    -+        <td class="diffspec">From Level:</td>
    -+        <td class="diffvalueold">24.1.0</td>
    -+      </tr>
    -+      <tr>
    -+        <td class="diffspec">Generated</td>
    -+        <td class="diffvalue">2016.08.16 14:03</td>
    -+      </tr>
    -+    </table>
    -+    </div><!-- End and-diff-id -->
    -+  <div class="and-diff-id" style="margin-right:8px;">
    -+    <table class="diffspectable">
    -+      <tr>
    -+        <td class="diffspec" colspan="2"><a href="jdiff_statistics.html">Statistics</a>
    -+      </tr>
    -+    </table>
    -+  </div> <!-- End and-diff-id -->
    -+  </div> <!-- End headerRight -->
    -+  </div> <!-- End header -->
    -+<div id="body-content" xstyle="padding:12px;padding-right:18px;">
    -+<div id="doc-content" style="position:relative;">
    -+<div id="mainBodyFluid">
    -+<H2>
    -+Package <A HREF="../../../../reference/android/support/v4/widget/package-summary.html" target="_top"><font size="+1"><code>android.support.v4.widget</code></font></A>
    -+</H2>
    -+<p>
    -+<a NAME="Added"></a>
    -+<TABLE summary="Added Interfaces" WIDTH="100%">
    -+<TR>
    -+  <TH VALIGN="TOP" COLSPAN=2>Added Interfaces</FONT></TD>
    -+</TH>
    -+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    -+  <TD VALIGN="TOP" WIDTH="25%">
    -+  <A NAME="SearchViewCompat.OnCloseListener"></A>
    -+  <nobr><A HREF="../../../../reference/android/support/v4/widget/SearchViewCompat.OnCloseListener.html" target="_top"><code><I>SearchViewCompat.OnCloseListener</I></code></A></nobr>
    -+  </TD>
    -+  <TD>&nbsp;</TD>
    -+</TR>
    -+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    -+  <TD VALIGN="TOP" WIDTH="25%">
    -+  <A NAME="SearchViewCompat.OnQueryTextListener"></A>
    -+  <nobr><A HREF="../../../../reference/android/support/v4/widget/SearchViewCompat.OnQueryTextListener.html" target="_top"><code><I>SearchViewCompat.OnQueryTextListener</I></code></A></nobr>
    -+  </TD>
    -+  <TD>&nbsp;</TD>
    -+</TR>
    -+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    -+  <TD VALIGN="TOP" WIDTH="25%">
    -+  <A NAME="SwipeRefreshLayout.OnChildScrollUpCallback"></A>
    -+  <nobr><A HREF="../../../../reference/android/support/v4/widget/SwipeRefreshLayout.OnChildScrollUpCallback.html" target="_top"><code><I>SwipeRefreshLayout.OnChildScrollUpCallback</I></code></A></nobr>
    -+  </TD>
    -+  <TD>&nbsp;</TD>
    -+</TR>
    -+</TABLE>
    -+&nbsp;
    -+<p>
    -+<a NAME="Changed"></a>
    -+<TABLE summary="Changed Classes" WIDTH="100%">
    -+<TR>
    -+  <TH VALIGN="TOP" COLSPAN=2>Changed Classes</FONT></TD>
    -+</TH>
    -+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    -+  <TD VALIGN="TOP" WIDTH="25%">
    -+  <A NAME="SearchViewCompat"></A>
    -+  <nobr><A HREF="android.support.v4.widget.SearchViewCompat.html">SearchViewCompat</A></nobr>
    -+  </TD>
    -+  <TD>&nbsp;</TD>
    -+</TR>
    -+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    -+  <TD VALIGN="TOP" WIDTH="25%">
    -+  <A NAME="SearchViewCompat.OnCloseListenerCompat"></A>
    -+  <nobr><A HREF="android.support.v4.widget.SearchViewCompat.OnCloseListenerCompat.html">SearchViewCompat.OnCloseListenerCompat</A></nobr>
    -+  </TD>
    -+  <TD>&nbsp;</TD>
    -+</TR>
    -+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    -+  <TD VALIGN="TOP" WIDTH="25%">
    -+  <A NAME="SearchViewCompat.OnQueryTextListenerCompat"></A>
    -+  <nobr><A HREF="android.support.v4.widget.SearchViewCompat.OnQueryTextListenerCompat.html">SearchViewCompat.OnQueryTextListenerCompat</A></nobr>
    -+  </TD>
    -+  <TD>&nbsp;</TD>
    -+</TR>
    -+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    -+  <TD VALIGN="TOP" WIDTH="25%">
    -+  <A NAME="SwipeRefreshLayout"></A>
    -+  <nobr><A HREF="android.support.v4.widget.SwipeRefreshLayout.html">SwipeRefreshLayout</A></nobr>
    -+  </TD>
    -+  <TD>&nbsp;</TD>
    -+</TR>
    -+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    -+  <TD VALIGN="TOP" WIDTH="25%">
    -+  <A NAME="TextViewCompat"></A>
    -+  <nobr><A HREF="android.support.v4.widget.TextViewCompat.html">TextViewCompat</A></nobr>
    -+  </TD>
    -+  <TD>&nbsp;</TD>
    -+</TR>
    -+</TABLE>
    -+&nbsp;
    -+      </div>	
    -+      <div id="footer">
    -+        <div id="copyright">
    -+        Except as noted, this content is licensed under 
    -+        <a href="http://creativecommons.org/licenses/by/2.5/"> Creative Commons Attribution 2.5</a>.
    -+        For details and restrictions, see the <a href="/license.html">Content License</a>.
    -+        </div>
    -+      <div id="footerlinks">
    -+      <p>
    -+        <a href="http://www.android.com/terms.html">Site Terms of Service</a> -
    -+        <a href="http://www.android.com/privacy.html">Privacy Policy</a> -
    -+        <a href="http://www.android.com/branding.html">Brand Guidelines</a>
    -+      </p>
    -+    </div>
    -+    </div> <!-- end footer -->
    -+    </div><!-- end doc-content -->
    -+    </div> <!-- end body-content --> 
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    -+</script>
    -+<script type="text/javascript">
    -+  try {
    -+    var pageTracker = _gat._getTracker("UA-5831155-1");
    -+    pageTracker._setAllowAnchor(true);
    -+    pageTracker._initData();
    -+    pageTracker._trackPageview();
    -+  } catch(e) {}
    -+</script>
    -+</BODY>
    -+</HTML>
    -diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/pkg_android.support.v7.app.html b/docs/html/sdk/support_api_diff/24.2.0/changes/pkg_android.support.v7.app.html
    -new file mode 100644
    -index 0000000..f36cba5
    ---- /dev/null
    -+++ b/docs/html/sdk/support_api_diff/24.2.0/changes/pkg_android.support.v7.app.html
    -@@ -0,0 +1,176 @@
    -+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
    -+<HTML style="overflow:auto;">
    -+<HEAD>
    -+<meta name="generator" content="JDiff v1.1.0">
    -+<!-- Generated by the JDiff Javadoc doclet -->
    -+<!-- (http://www.jdiff.org) -->
    -+<meta name="description" content="JDiff is a Javadoc doclet which generates an HTML report of all the packages, classes, constructors, methods, and fields which have been removed, added or changed in any way, including their documentation, when two APIs are compared.">
    -+<meta name="keywords" content="diff, jdiff, javadiff, java diff, java difference, API difference, difference between two APIs, API diff, Javadoc, doclet">
    -+<TITLE>
    -+android.support.v7.app
    -+</TITLE>
    -+<link href="../../../../assets/android-developer-docs.css" rel="stylesheet" type="text/css" />
    -+<link href="../stylesheet-jdiff.css" rel="stylesheet" type="text/css" />
    -+<noscript>
    -+<style type="text/css">
    -+body{overflow:auto;}
    -+#body-content{position:relative; top:0;}
    -+#doc-content{overflow:visible;border-left:3px solid #666;}
    -+#side-nav{padding:0;}
    -+#side-nav .toggle-list ul {display:block;}
    -+#resize-packages-nav{border-bottom:3px solid #666;}
    -+</style>
    -+</noscript>
    -+<style type="text/css">
    -+</style>
    -+</HEAD>
    -+<BODY>
    -+<!-- Start of nav bar -->
    -+<a name="top"></a>
    -+<div id="header" style="margin-bottom:0;padding-bottom:0;">
    -+<div id="headerLeft">
    -+<a href="../../../../index.html" tabindex="-1" target="_top"><img src="../../../../assets/images/bg_logo.png" alt="Android Developers" /></a>
    -+</div>
    -+  <div id="headerRight">
    -+  <div id="headerLinks">
    -+<!-- <img src="/assets/images/icon_world.jpg" alt="" /> -->
    -+<span class="text">
    -+<!-- &nbsp;<a href="#">English</a> | -->
    -+<nobr><a href="http://developer.android.com" target="_top">Android Developers</a> | <a href="http://www.android.com" target="_top">Android.com</a></nobr>
    -+</span>
    -+</div>
    -+  <div class="and-diff-id" style="margin-top:6px;margin-right:8px;">
    -+    <table class="diffspectable">
    -+      <tr>
    -+        <td colspan="2" class="diffspechead">API Diff Specification</td>
    -+      </tr>
    -+      <tr>
    -+        <td class="diffspec" style="padding-top:.25em">To Level:</td>
    -+        <td class="diffvaluenew" style="padding-top:.25em">24.2.0</td>
    -+      </tr>
    -+      <tr>
    -+        <td class="diffspec">From Level:</td>
    -+        <td class="diffvalueold">24.1.0</td>
    -+      </tr>
    -+      <tr>
    -+        <td class="diffspec">Generated</td>
    -+        <td class="diffvalue">2016.08.16 14:03</td>
    -+      </tr>
    -+    </table>
    -+    </div><!-- End and-diff-id -->
    -+  <div class="and-diff-id" style="margin-right:8px;">
    -+    <table class="diffspectable">
    -+      <tr>
    -+        <td class="diffspec" colspan="2"><a href="jdiff_statistics.html">Statistics</a>
    -+      </tr>
    -+    </table>
    -+  </div> <!-- End and-diff-id -->
    -+  </div> <!-- End headerRight -->
    -+  </div> <!-- End header -->
    -+<div id="body-content" xstyle="padding:12px;padding-right:18px;">
    -+<div id="doc-content" style="position:relative;">
    -+<div id="mainBodyFluid">
    -+<H2>
    -+Package <A HREF="../../../../reference/android/support/v7/app/package-summary.html" target="_top"><font size="+1"><code>android.support.v7.app</code></font></A>
    -+</H2>
    -+<p>
    -+<a NAME="Added"></a>
    -+<TABLE summary="Added Classes" WIDTH="100%">
    -+<TR>
    -+  <TH VALIGN="TOP" COLSPAN=2>Added Classes</FONT></TD>
    -+</TH>
    -+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    -+  <TD VALIGN="TOP" WIDTH="25%">
    -+  <A NAME="ActionBarActivity"></A>
    -+  <nobr><A HREF="../../../../reference/android/support/v7/app/ActionBarActivity.html" target="_top"><code>ActionBarActivity</code></A></nobr>
    -+  </TD>
    -+  <TD>&nbsp;</TD>
    -+</TR>
    -+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    -+  <TD VALIGN="TOP" WIDTH="25%">
    -+  <A NAME="AppCompatActivity"></A>
    -+  <nobr><A HREF="../../../../reference/android/support/v7/app/AppCompatActivity.html" target="_top"><code>AppCompatActivity</code></A></nobr>
    -+  </TD>
    -+  <TD>&nbsp;</TD>
    -+</TR>
    -+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    -+  <TD VALIGN="TOP" WIDTH="25%">
    -+  <A NAME="AppCompatDialogFragment"></A>
    -+  <nobr><A HREF="../../../../reference/android/support/v7/app/AppCompatDialogFragment.html" target="_top"><code>AppCompatDialogFragment</code></A></nobr>
    -+  </TD>
    -+  <TD>&nbsp;</TD>
    -+</TR>
    -+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    -+  <TD VALIGN="TOP" WIDTH="25%">
    -+  <A NAME="NotificationCompat"></A>
    -+  <nobr><A HREF="../../../../reference/android/support/v7/app/NotificationCompat.html" target="_top"><code>NotificationCompat</code></A></nobr>
    -+  </TD>
    -+  <TD>&nbsp;</TD>
    -+</TR>
    -+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    -+  <TD VALIGN="TOP" WIDTH="25%">
    -+  <A NAME="NotificationCompat.Builder"></A>
    -+  <nobr><A HREF="../../../../reference/android/support/v7/app/NotificationCompat.Builder.html" target="_top"><code>NotificationCompat.Builder</code></A></nobr>
    -+  </TD>
    -+  <TD>&nbsp;</TD>
    -+</TR>
    -+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    -+  <TD VALIGN="TOP" WIDTH="25%">
    -+  <A NAME="NotificationCompat.MediaStyle"></A>
    -+  <nobr><A HREF="../../../../reference/android/support/v7/app/NotificationCompat.MediaStyle.html" target="_top"><code>NotificationCompat.MediaStyle</code></A></nobr>
    -+  </TD>
    -+  <TD>&nbsp;</TD>
    -+</TR>
    -+</TABLE>
    -+&nbsp;
    -+<p>
    -+<a NAME="Changed"></a>
    -+<TABLE summary="Changed Classes" WIDTH="100%">
    -+<TR>
    -+  <TH VALIGN="TOP" COLSPAN=2>Changed Classes</FONT></TD>
    -+</TH>
    -+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    -+  <TD VALIGN="TOP" WIDTH="25%">
    -+  <A NAME="ActionBarDrawerToggle"></A>
    -+  <nobr><A HREF="android.support.v7.app.ActionBarDrawerToggle.html">ActionBarDrawerToggle</A></nobr>
    -+  </TD>
    -+  <TD>&nbsp;</TD>
    -+</TR>
    -+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    -+  <TD VALIGN="TOP" WIDTH="25%">
    -+  <A NAME="AppCompatDelegate"></A>
    -+  <nobr><A HREF="android.support.v7.app.AppCompatDelegate.html">AppCompatDelegate</A></nobr>
    -+  </TD>
    -+  <TD>&nbsp;</TD>
    -+</TR>
    -+</TABLE>
    -+&nbsp;
    -+      </div>	
    -+      <div id="footer">
    -+        <div id="copyright">
    -+        Except as noted, this content is licensed under 
    -+        <a href="http://creativecommons.org/licenses/by/2.5/"> Creative Commons Attribution 2.5</a>.
    -+        For details and restrictions, see the <a href="/license.html">Content License</a>.
    -+        </div>
    -+      <div id="footerlinks">
    -+      <p>
    -+        <a href="http://www.android.com/terms.html">Site Terms of Service</a> -
    -+        <a href="http://www.android.com/privacy.html">Privacy Policy</a> -
    -+        <a href="http://www.android.com/branding.html">Brand Guidelines</a>
    -+      </p>
    -+    </div>
    -+    </div> <!-- end footer -->
    -+    </div><!-- end doc-content -->
    -+    </div> <!-- end body-content --> 
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    -+</script>
    -+<script type="text/javascript">
    -+  try {
    -+    var pageTracker = _gat._getTracker("UA-5831155-1");
    -+    pageTracker._setAllowAnchor(true);
    -+    pageTracker._initData();
    -+    pageTracker._trackPageview();
    -+  } catch(e) {}
    -+</script>
    -+</BODY>
    -+</HTML>
    -diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/pkg_android.support.v7.content.res.html b/docs/html/sdk/support_api_diff/24.2.0/changes/pkg_android.support.v7.content.res.html
    -new file mode 100644
    -index 0000000..2e4b703
    ---- /dev/null
    -+++ b/docs/html/sdk/support_api_diff/24.2.0/changes/pkg_android.support.v7.content.res.html
    -@@ -0,0 +1,119 @@
    -+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
    -+<HTML style="overflow:auto;">
    -+<HEAD>
    -+<meta name="generator" content="JDiff v1.1.0">
    -+<!-- Generated by the JDiff Javadoc doclet -->
    -+<!-- (http://www.jdiff.org) -->
    -+<meta name="description" content="JDiff is a Javadoc doclet which generates an HTML report of all the packages, classes, constructors, methods, and fields which have been removed, added or changed in any way, including their documentation, when two APIs are compared.">
    -+<meta name="keywords" content="diff, jdiff, javadiff, java diff, java difference, API difference, difference between two APIs, API diff, Javadoc, doclet">
    -+<TITLE>
    -+android.support.v7.content.res
    -+</TITLE>
    -+<link href="../../../../assets/android-developer-docs.css" rel="stylesheet" type="text/css" />
    -+<link href="../stylesheet-jdiff.css" rel="stylesheet" type="text/css" />
    -+<noscript>
    -+<style type="text/css">
    -+body{overflow:auto;}
    -+#body-content{position:relative; top:0;}
    -+#doc-content{overflow:visible;border-left:3px solid #666;}
    -+#side-nav{padding:0;}
    -+#side-nav .toggle-list ul {display:block;}
    -+#resize-packages-nav{border-bottom:3px solid #666;}
    -+</style>
    -+</noscript>
    -+<style type="text/css">
    -+</style>
    -+</HEAD>
    -+<BODY>
    -+<!-- Start of nav bar -->
    -+<a name="top"></a>
    -+<div id="header" style="margin-bottom:0;padding-bottom:0;">
    -+<div id="headerLeft">
    -+<a href="../../../../index.html" tabindex="-1" target="_top"><img src="../../../../assets/images/bg_logo.png" alt="Android Developers" /></a>
    -+</div>
    -+  <div id="headerRight">
    -+  <div id="headerLinks">
    -+<!-- <img src="/assets/images/icon_world.jpg" alt="" /> -->
    -+<span class="text">
    -+<!-- &nbsp;<a href="#">English</a> | -->
    -+<nobr><a href="http://developer.android.com" target="_top">Android Developers</a> | <a href="http://www.android.com" target="_top">Android.com</a></nobr>
    -+</span>
    -+</div>
    -+  <div class="and-diff-id" style="margin-top:6px;margin-right:8px;">
    -+    <table class="diffspectable">
    -+      <tr>
    -+        <td colspan="2" class="diffspechead">API Diff Specification</td>
    -+      </tr>
    -+      <tr>
    -+        <td class="diffspec" style="padding-top:.25em">To Level:</td>
    -+        <td class="diffvaluenew" style="padding-top:.25em">24.2.0</td>
    -+      </tr>
    -+      <tr>
    -+        <td class="diffspec">From Level:</td>
    -+        <td class="diffvalueold">24.1.0</td>
    -+      </tr>
    -+      <tr>
    -+        <td class="diffspec">Generated</td>
    -+        <td class="diffvalue">2016.08.16 14:03</td>
    -+      </tr>
    -+    </table>
    -+    </div><!-- End and-diff-id -->
    -+  <div class="and-diff-id" style="margin-right:8px;">
    -+    <table class="diffspectable">
    -+      <tr>
    -+        <td class="diffspec" colspan="2"><a href="jdiff_statistics.html">Statistics</a>
    -+      </tr>
    -+    </table>
    -+  </div> <!-- End and-diff-id -->
    -+  </div> <!-- End headerRight -->
    -+  </div> <!-- End header -->
    -+<div id="body-content" xstyle="padding:12px;padding-right:18px;">
    -+<div id="doc-content" style="position:relative;">
    -+<div id="mainBodyFluid">
    -+<H2>
    -+Package <A HREF="../../../../reference/android/support/v7/content/res/package-summary.html" target="_top"><font size="+1"><code>android.support.v7.content.res</code></font></A>
    -+</H2>
    -+<p>
    -+<a NAME="Changed"></a>
    -+<TABLE summary="Changed Classes" WIDTH="100%">
    -+<TR>
    -+  <TH VALIGN="TOP" COLSPAN=2>Changed Classes</FONT></TD>
    -+</TH>
    -+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    -+  <TD VALIGN="TOP" WIDTH="25%">
    -+  <A NAME="AppCompatResources"></A>
    -+  <nobr><A HREF="android.support.v7.content.res.AppCompatResources.html">AppCompatResources</A></nobr>
    -+  </TD>
    -+  <TD>&nbsp;</TD>
    -+</TR>
    -+</TABLE>
    -+&nbsp;
    -+      </div>	
    -+      <div id="footer">
    -+        <div id="copyright">
    -+        Except as noted, this content is licensed under 
    -+        <a href="http://creativecommons.org/licenses/by/2.5/"> Creative Commons Attribution 2.5</a>.
    -+        For details and restrictions, see the <a href="/license.html">Content License</a>.
    -+        </div>
    -+      <div id="footerlinks">
    -+      <p>
    -+        <a href="http://www.android.com/terms.html">Site Terms of Service</a> -
    -+        <a href="http://www.android.com/privacy.html">Privacy Policy</a> -
    -+        <a href="http://www.android.com/branding.html">Brand Guidelines</a>
    -+      </p>
    -+    </div>
    -+    </div> <!-- end footer -->
    -+    </div><!-- end doc-content -->
    -+    </div> <!-- end body-content --> 
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    -+</script>
    -+<script type="text/javascript">
    -+  try {
    -+    var pageTracker = _gat._getTracker("UA-5831155-1");
    -+    pageTracker._setAllowAnchor(true);
    -+    pageTracker._initData();
    -+    pageTracker._trackPageview();
    -+  } catch(e) {}
    -+</script>
    -+</BODY>
    -+</HTML>
    -diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/pkg_android.support.v7.graphics.html b/docs/html/sdk/support_api_diff/24.2.0/changes/pkg_android.support.v7.graphics.html
    -new file mode 100644
    -index 0000000..439c8d3
    ---- /dev/null
    -+++ b/docs/html/sdk/support_api_diff/24.2.0/changes/pkg_android.support.v7.graphics.html
    -@@ -0,0 +1,119 @@
    -+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
    -+<HTML style="overflow:auto;">
    -+<HEAD>
    -+<meta name="generator" content="JDiff v1.1.0">
    -+<!-- Generated by the JDiff Javadoc doclet -->
    -+<!-- (http://www.jdiff.org) -->
    -+<meta name="description" content="JDiff is a Javadoc doclet which generates an HTML report of all the packages, classes, constructors, methods, and fields which have been removed, added or changed in any way, including their documentation, when two APIs are compared.">
    -+<meta name="keywords" content="diff, jdiff, javadiff, java diff, java difference, API difference, difference between two APIs, API diff, Javadoc, doclet">
    -+<TITLE>
    -+android.support.v7.graphics
    -+</TITLE>
    -+<link href="../../../../assets/android-developer-docs.css" rel="stylesheet" type="text/css" />
    -+<link href="../stylesheet-jdiff.css" rel="stylesheet" type="text/css" />
    -+<noscript>
    -+<style type="text/css">
    -+body{overflow:auto;}
    -+#body-content{position:relative; top:0;}
    -+#doc-content{overflow:visible;border-left:3px solid #666;}
    -+#side-nav{padding:0;}
    -+#side-nav .toggle-list ul {display:block;}
    -+#resize-packages-nav{border-bottom:3px solid #666;}
    -+</style>
    -+</noscript>
    -+<style type="text/css">
    -+</style>
    -+</HEAD>
    -+<BODY>
    -+<!-- Start of nav bar -->
    -+<a name="top"></a>
    -+<div id="header" style="margin-bottom:0;padding-bottom:0;">
    -+<div id="headerLeft">
    -+<a href="../../../../index.html" tabindex="-1" target="_top"><img src="../../../../assets/images/bg_logo.png" alt="Android Developers" /></a>
    -+</div>
    -+  <div id="headerRight">
    -+  <div id="headerLinks">
    -+<!-- <img src="/assets/images/icon_world.jpg" alt="" /> -->
    -+<span class="text">
    -+<!-- &nbsp;<a href="#">English</a> | -->
    -+<nobr><a href="http://developer.android.com" target="_top">Android Developers</a> | <a href="http://www.android.com" target="_top">Android.com</a></nobr>
    -+</span>
    -+</div>
    -+  <div class="and-diff-id" style="margin-top:6px;margin-right:8px;">
    -+    <table class="diffspectable">
    -+      <tr>
    -+        <td colspan="2" class="diffspechead">API Diff Specification</td>
    -+      </tr>
    -+      <tr>
    -+        <td class="diffspec" style="padding-top:.25em">To Level:</td>
    -+        <td class="diffvaluenew" style="padding-top:.25em">24.2.0</td>
    -+      </tr>
    -+      <tr>
    -+        <td class="diffspec">From Level:</td>
    -+        <td class="diffvalueold">24.1.0</td>
    -+      </tr>
    -+      <tr>
    -+        <td class="diffspec">Generated</td>
    -+        <td class="diffvalue">2016.08.16 14:03</td>
    -+      </tr>
    -+    </table>
    -+    </div><!-- End and-diff-id -->
    -+  <div class="and-diff-id" style="margin-right:8px;">
    -+    <table class="diffspectable">
    -+      <tr>
    -+        <td class="diffspec" colspan="2"><a href="jdiff_statistics.html">Statistics</a>
    -+      </tr>
    -+    </table>
    -+  </div> <!-- End and-diff-id -->
    -+  </div> <!-- End headerRight -->
    -+  </div> <!-- End header -->
    -+<div id="body-content" xstyle="padding:12px;padding-right:18px;">
    -+<div id="doc-content" style="position:relative;">
    -+<div id="mainBodyFluid">
    -+<H2>
    -+Package <A HREF="../../../../reference/android/support/v7/graphics/package-summary.html" target="_top"><font size="+1"><code>android.support.v7.graphics</code></font></A>
    -+</H2>
    -+<p>
    -+<a NAME="Changed"></a>
    -+<TABLE summary="Changed Classes" WIDTH="100%">
    -+<TR>
    -+  <TH VALIGN="TOP" COLSPAN=2>Changed Classes</FONT></TD>
    -+</TH>
    -+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    -+  <TD VALIGN="TOP" WIDTH="25%">
    -+  <A NAME="Palette"></A>
    -+  <nobr><A HREF="android.support.v7.graphics.Palette.html">Palette</A></nobr>
    -+  </TD>
    -+  <TD>&nbsp;</TD>
    -+</TR>
    -+</TABLE>
    -+&nbsp;
    -+      </div>	
    -+      <div id="footer">
    -+        <div id="copyright">
    -+        Except as noted, this content is licensed under 
    -+        <a href="http://creativecommons.org/licenses/by/2.5/"> Creative Commons Attribution 2.5</a>.
    -+        For details and restrictions, see the <a href="/license.html">Content License</a>.
    -+        </div>
    -+      <div id="footerlinks">
    -+      <p>
    -+        <a href="http://www.android.com/terms.html">Site Terms of Service</a> -
    -+        <a href="http://www.android.com/privacy.html">Privacy Policy</a> -
    -+        <a href="http://www.android.com/branding.html">Brand Guidelines</a>
    -+      </p>
    -+    </div>
    -+    </div> <!-- end footer -->
    -+    </div><!-- end doc-content -->
    -+    </div> <!-- end body-content --> 
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    -+</script>
    -+<script type="text/javascript">
    -+  try {
    -+    var pageTracker = _gat._getTracker("UA-5831155-1");
    -+    pageTracker._setAllowAnchor(true);
    -+    pageTracker._initData();
    -+    pageTracker._trackPageview();
    -+  } catch(e) {}
    -+</script>
    -+</BODY>
    -+</HTML>
    -diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/pkg_android.support.v7.preference.html b/docs/html/sdk/support_api_diff/24.2.0/changes/pkg_android.support.v7.preference.html
    -new file mode 100644
    -index 0000000..b2b781b
    ---- /dev/null
    -+++ b/docs/html/sdk/support_api_diff/24.2.0/changes/pkg_android.support.v7.preference.html
    -@@ -0,0 +1,119 @@
    -+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
    -+<HTML style="overflow:auto;">
    -+<HEAD>
    -+<meta name="generator" content="JDiff v1.1.0">
    -+<!-- Generated by the JDiff Javadoc doclet -->
    -+<!-- (http://www.jdiff.org) -->
    -+<meta name="description" content="JDiff is a Javadoc doclet which generates an HTML report of all the packages, classes, constructors, methods, and fields which have been removed, added or changed in any way, including their documentation, when two APIs are compared.">
    -+<meta name="keywords" content="diff, jdiff, javadiff, java diff, java difference, API difference, difference between two APIs, API diff, Javadoc, doclet">
    -+<TITLE>
    -+android.support.v7.preference
    -+</TITLE>
    -+<link href="../../../../assets/android-developer-docs.css" rel="stylesheet" type="text/css" />
    -+<link href="../stylesheet-jdiff.css" rel="stylesheet" type="text/css" />
    -+<noscript>
    -+<style type="text/css">
    -+body{overflow:auto;}
    -+#body-content{position:relative; top:0;}
    -+#doc-content{overflow:visible;border-left:3px solid #666;}
    -+#side-nav{padding:0;}
    -+#side-nav .toggle-list ul {display:block;}
    -+#resize-packages-nav{border-bottom:3px solid #666;}
    -+</style>
    -+</noscript>
    -+<style type="text/css">
    -+</style>
    -+</HEAD>
    -+<BODY>
    -+<!-- Start of nav bar -->
    -+<a name="top"></a>
    -+<div id="header" style="margin-bottom:0;padding-bottom:0;">
    -+<div id="headerLeft">
    -+<a href="../../../../index.html" tabindex="-1" target="_top"><img src="../../../../assets/images/bg_logo.png" alt="Android Developers" /></a>
    -+</div>
    -+  <div id="headerRight">
    -+  <div id="headerLinks">
    -+<!-- <img src="/assets/images/icon_world.jpg" alt="" /> -->
    -+<span class="text">
    -+<!-- &nbsp;<a href="#">English</a> | -->
    -+<nobr><a href="http://developer.android.com" target="_top">Android Developers</a> | <a href="http://www.android.com" target="_top">Android.com</a></nobr>
    -+</span>
    -+</div>
    -+  <div class="and-diff-id" style="margin-top:6px;margin-right:8px;">
    -+    <table class="diffspectable">
    -+      <tr>
    -+        <td colspan="2" class="diffspechead">API Diff Specification</td>
    -+      </tr>
    -+      <tr>
    -+        <td class="diffspec" style="padding-top:.25em">To Level:</td>
    -+        <td class="diffvaluenew" style="padding-top:.25em">24.2.0</td>
    -+      </tr>
    -+      <tr>
    -+        <td class="diffspec">From Level:</td>
    -+        <td class="diffvalueold">24.1.0</td>
    -+      </tr>
    -+      <tr>
    -+        <td class="diffspec">Generated</td>
    -+        <td class="diffvalue">2016.08.16 14:03</td>
    -+      </tr>
    -+    </table>
    -+    </div><!-- End and-diff-id -->
    -+  <div class="and-diff-id" style="margin-right:8px;">
    -+    <table class="diffspectable">
    -+      <tr>
    -+        <td class="diffspec" colspan="2"><a href="jdiff_statistics.html">Statistics</a>
    -+      </tr>
    -+    </table>
    -+  </div> <!-- End and-diff-id -->
    -+  </div> <!-- End headerRight -->
    -+  </div> <!-- End header -->
    -+<div id="body-content" xstyle="padding:12px;padding-right:18px;">
    -+<div id="doc-content" style="position:relative;">
    -+<div id="mainBodyFluid">
    -+<H2>
    -+Package <A HREF="../../../../reference/android/support/v7/preference/package-summary.html" target="_top"><font size="+1"><code>android.support.v7.preference</code></font></A>
    -+</H2>
    -+<p>
    -+<a NAME="Added"></a>
    -+<TABLE summary="Added Classes" WIDTH="100%">
    -+<TR>
    -+  <TH VALIGN="TOP" COLSPAN=2>Added Classes</FONT></TD>
    -+</TH>
    -+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    -+  <TD VALIGN="TOP" WIDTH="25%">
    -+  <A NAME="MultiSelectListPreferenceDialogFragmentCompat"></A>
    -+  <nobr><A HREF="../../../../reference/android/support/v7/preference/MultiSelectListPreferenceDialogFragmentCompat.html" target="_top"><code>MultiSelectListPreferenceDialogFragmentCompat</code></A></nobr>
    -+  </TD>
    -+  <TD>&nbsp;</TD>
    -+</TR>
    -+</TABLE>
    -+&nbsp;
    -+      </div>	
    -+      <div id="footer">
    -+        <div id="copyright">
    -+        Except as noted, this content is licensed under 
    -+        <a href="http://creativecommons.org/licenses/by/2.5/"> Creative Commons Attribution 2.5</a>.
    -+        For details and restrictions, see the <a href="/license.html">Content License</a>.
    -+        </div>
    -+      <div id="footerlinks">
    -+      <p>
    -+        <a href="http://www.android.com/terms.html">Site Terms of Service</a> -
    -+        <a href="http://www.android.com/privacy.html">Privacy Policy</a> -
    -+        <a href="http://www.android.com/branding.html">Brand Guidelines</a>
    -+      </p>
    -+    </div>
    -+    </div> <!-- end footer -->
    -+    </div><!-- end doc-content -->
    -+    </div> <!-- end body-content --> 
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    -+</script>
    -+<script type="text/javascript">
    -+  try {
    -+    var pageTracker = _gat._getTracker("UA-5831155-1");
    -+    pageTracker._setAllowAnchor(true);
    -+    pageTracker._initData();
    -+    pageTracker._trackPageview();
    -+  } catch(e) {}
    -+</script>
    -+</BODY>
    -+</HTML>
    -diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/pkg_android.support.v7.util.html b/docs/html/sdk/support_api_diff/24.2.0/changes/pkg_android.support.v7.util.html
    -new file mode 100644
    -index 0000000..c35fb8c
    ---- /dev/null
    -+++ b/docs/html/sdk/support_api_diff/24.2.0/changes/pkg_android.support.v7.util.html
    -@@ -0,0 +1,162 @@
    -+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
    -+<HTML style="overflow:auto;">
    -+<HEAD>
    -+<meta name="generator" content="JDiff v1.1.0">
    -+<!-- Generated by the JDiff Javadoc doclet -->
    -+<!-- (http://www.jdiff.org) -->
    -+<meta name="description" content="JDiff is a Javadoc doclet which generates an HTML report of all the packages, classes, constructors, methods, and fields which have been removed, added or changed in any way, including their documentation, when two APIs are compared.">
    -+<meta name="keywords" content="diff, jdiff, javadiff, java diff, java difference, API difference, difference between two APIs, API diff, Javadoc, doclet">
    -+<TITLE>
    -+android.support.v7.util
    -+</TITLE>
    -+<link href="../../../../assets/android-developer-docs.css" rel="stylesheet" type="text/css" />
    -+<link href="../stylesheet-jdiff.css" rel="stylesheet" type="text/css" />
    -+<noscript>
    -+<style type="text/css">
    -+body{overflow:auto;}
    -+#body-content{position:relative; top:0;}
    -+#doc-content{overflow:visible;border-left:3px solid #666;}
    -+#side-nav{padding:0;}
    -+#side-nav .toggle-list ul {display:block;}
    -+#resize-packages-nav{border-bottom:3px solid #666;}
    -+</style>
    -+</noscript>
    -+<style type="text/css">
    -+</style>
    -+</HEAD>
    -+<BODY>
    -+<!-- Start of nav bar -->
    -+<a name="top"></a>
    -+<div id="header" style="margin-bottom:0;padding-bottom:0;">
    -+<div id="headerLeft">
    -+<a href="../../../../index.html" tabindex="-1" target="_top"><img src="../../../../assets/images/bg_logo.png" alt="Android Developers" /></a>
    -+</div>
    -+  <div id="headerRight">
    -+  <div id="headerLinks">
    -+<!-- <img src="/assets/images/icon_world.jpg" alt="" /> -->
    -+<span class="text">
    -+<!-- &nbsp;<a href="#">English</a> | -->
    -+<nobr><a href="http://developer.android.com" target="_top">Android Developers</a> | <a href="http://www.android.com" target="_top">Android.com</a></nobr>
    -+</span>
    -+</div>
    -+  <div class="and-diff-id" style="margin-top:6px;margin-right:8px;">
    -+    <table class="diffspectable">
    -+      <tr>
    -+        <td colspan="2" class="diffspechead">API Diff Specification</td>
    -+      </tr>
    -+      <tr>
    -+        <td class="diffspec" style="padding-top:.25em">To Level:</td>
    -+        <td class="diffvaluenew" style="padding-top:.25em">24.2.0</td>
    -+      </tr>
    -+      <tr>
    -+        <td class="diffspec">From Level:</td>
    -+        <td class="diffvalueold">24.1.0</td>
    -+      </tr>
    -+      <tr>
    -+        <td class="diffspec">Generated</td>
    -+        <td class="diffvalue">2016.08.16 14:03</td>
    -+      </tr>
    -+    </table>
    -+    </div><!-- End and-diff-id -->
    -+  <div class="and-diff-id" style="margin-right:8px;">
    -+    <table class="diffspectable">
    -+      <tr>
    -+        <td class="diffspec" colspan="2"><a href="jdiff_statistics.html">Statistics</a>
    -+      </tr>
    -+    </table>
    -+  </div> <!-- End and-diff-id -->
    -+  </div> <!-- End headerRight -->
    -+  </div> <!-- End header -->
    -+<div id="body-content" xstyle="padding:12px;padding-right:18px;">
    -+<div id="doc-content" style="position:relative;">
    -+<div id="mainBodyFluid">
    -+<H2>
    -+Package <A HREF="../../../../reference/android/support/v7/util/package-summary.html" target="_top"><font size="+1"><code>android.support.v7.util</code></font></A>
    -+</H2>
    -+<p>
    -+<a NAME="Added"></a>
    -+<TABLE summary="Added Classes and Interfaces" WIDTH="100%">
    -+<TR>
    -+  <TH VALIGN="TOP" COLSPAN=2>Added Classes and Interfaces</FONT></TD>
    -+</TH>
    -+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    -+  <TD VALIGN="TOP" WIDTH="25%">
    -+  <A NAME="BatchingListUpdateCallback"></A>
    -+  <nobr><A HREF="../../../../reference/android/support/v7/util/BatchingListUpdateCallback.html" target="_top"><code>BatchingListUpdateCallback</code></A></nobr>
    -+  </TD>
    -+  <TD>&nbsp;</TD>
    -+</TR>
    -+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    -+  <TD VALIGN="TOP" WIDTH="25%">
    -+  <A NAME="DiffUtil"></A>
    -+  <nobr><A HREF="../../../../reference/android/support/v7/util/DiffUtil.html" target="_top"><code>DiffUtil</code></A></nobr>
    -+  </TD>
    -+  <TD>&nbsp;</TD>
    -+</TR>
    -+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    -+  <TD VALIGN="TOP" WIDTH="25%">
    -+  <A NAME="DiffUtil.Callback"></A>
    -+  <nobr><A HREF="../../../../reference/android/support/v7/util/DiffUtil.Callback.html" target="_top"><code>DiffUtil.Callback</code></A></nobr>
    -+  </TD>
    -+  <TD>&nbsp;</TD>
    -+</TR>
    -+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    -+  <TD VALIGN="TOP" WIDTH="25%">
    -+  <A NAME="DiffUtil.DiffResult"></A>
    -+  <nobr><A HREF="../../../../reference/android/support/v7/util/DiffUtil.DiffResult.html" target="_top"><code>DiffUtil.DiffResult</code></A></nobr>
    -+  </TD>
    -+  <TD>&nbsp;</TD>
    -+</TR>
    -+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    -+  <TD VALIGN="TOP" WIDTH="25%">
    -+  <A NAME="ListUpdateCallback"></A>
    -+  <nobr><A HREF="../../../../reference/android/support/v7/util/ListUpdateCallback.html" target="_top"><code><I>ListUpdateCallback</I></code></A></nobr>
    -+  </TD>
    -+  <TD>&nbsp;</TD>
    -+</TR>
    -+</TABLE>
    -+&nbsp;
    -+<p>
    -+<a NAME="Changed"></a>
    -+<TABLE summary="Changed Classes" WIDTH="100%">
    -+<TR>
    -+  <TH VALIGN="TOP" COLSPAN=2>Changed Classes</FONT></TD>
    -+</TH>
    -+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    -+  <TD VALIGN="TOP" WIDTH="25%">
    -+  <A NAME="SortedList.Callback"></A>
    -+  <nobr><A HREF="android.support.v7.util.SortedList.Callback.html">SortedList.Callback</A></nobr>
    -+  </TD>
    -+  <TD>&nbsp;</TD>
    -+</TR>
    -+</TABLE>
    -+&nbsp;
    -+      </div>	
    -+      <div id="footer">
    -+        <div id="copyright">
    -+        Except as noted, this content is licensed under 
    -+        <a href="http://creativecommons.org/licenses/by/2.5/"> Creative Commons Attribution 2.5</a>.
    -+        For details and restrictions, see the <a href="/license.html">Content License</a>.
    -+        </div>
    -+      <div id="footerlinks">
    -+      <p>
    -+        <a href="http://www.android.com/terms.html">Site Terms of Service</a> -
    -+        <a href="http://www.android.com/privacy.html">Privacy Policy</a> -
    -+        <a href="http://www.android.com/branding.html">Brand Guidelines</a>
    -+      </p>
    -+    </div>
    -+    </div> <!-- end footer -->
    -+    </div><!-- end doc-content -->
    -+    </div> <!-- end body-content --> 
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    -+</script>
    -+<script type="text/javascript">
    -+  try {
    -+    var pageTracker = _gat._getTracker("UA-5831155-1");
    -+    pageTracker._setAllowAnchor(true);
    -+    pageTracker._initData();
    -+    pageTracker._trackPageview();
    -+  } catch(e) {}
    -+</script>
    -+</BODY>
    -+</HTML>
    -diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/pkg_android.support.v7.widget.html b/docs/html/sdk/support_api_diff/24.2.0/changes/pkg_android.support.v7.widget.html
    -new file mode 100644
    -index 0000000..72e5497
    ---- /dev/null
    -+++ b/docs/html/sdk/support_api_diff/24.2.0/changes/pkg_android.support.v7.widget.html
    -@@ -0,0 +1,463 @@
    -+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
    -+<HTML style="overflow:auto;">
    -+<HEAD>
    -+<meta name="generator" content="JDiff v1.1.0">
    -+<!-- Generated by the JDiff Javadoc doclet -->
    -+<!-- (http://www.jdiff.org) -->
    -+<meta name="description" content="JDiff is a Javadoc doclet which generates an HTML report of all the packages, classes, constructors, methods, and fields which have been removed, added or changed in any way, including their documentation, when two APIs are compared.">
    -+<meta name="keywords" content="diff, jdiff, javadiff, java diff, java difference, API difference, difference between two APIs, API diff, Javadoc, doclet">
    -+<TITLE>
    -+android.support.v7.widget
    -+</TITLE>
    -+<link href="../../../../assets/android-developer-docs.css" rel="stylesheet" type="text/css" />
    -+<link href="../stylesheet-jdiff.css" rel="stylesheet" type="text/css" />
    -+<noscript>
    -+<style type="text/css">
    -+body{overflow:auto;}
    -+#body-content{position:relative; top:0;}
    -+#doc-content{overflow:visible;border-left:3px solid #666;}
    -+#side-nav{padding:0;}
    -+#side-nav .toggle-list ul {display:block;}
    -+#resize-packages-nav{border-bottom:3px solid #666;}
    -+</style>
    -+</noscript>
    -+<style type="text/css">
    -+</style>
    -+</HEAD>
    -+<BODY>
    -+<!-- Start of nav bar -->
    -+<a name="top"></a>
    -+<div id="header" style="margin-bottom:0;padding-bottom:0;">
    -+<div id="headerLeft">
    -+<a href="../../../../index.html" tabindex="-1" target="_top"><img src="../../../../assets/images/bg_logo.png" alt="Android Developers" /></a>
    -+</div>
    -+  <div id="headerRight">
    -+  <div id="headerLinks">
    -+<!-- <img src="/assets/images/icon_world.jpg" alt="" /> -->
    -+<span class="text">
    -+<!-- &nbsp;<a href="#">English</a> | -->
    -+<nobr><a href="http://developer.android.com" target="_top">Android Developers</a> | <a href="http://www.android.com" target="_top">Android.com</a></nobr>
    -+</span>
    -+</div>
    -+  <div class="and-diff-id" style="margin-top:6px;margin-right:8px;">
    -+    <table class="diffspectable">
    -+      <tr>
    -+        <td colspan="2" class="diffspechead">API Diff Specification</td>
    -+      </tr>
    -+      <tr>
    -+        <td class="diffspec" style="padding-top:.25em">To Level:</td>
    -+        <td class="diffvaluenew" style="padding-top:.25em">24.2.0</td>
    -+      </tr>
    -+      <tr>
    -+        <td class="diffspec">From Level:</td>
    -+        <td class="diffvalueold">24.1.0</td>
    -+      </tr>
    -+      <tr>
    -+        <td class="diffspec">Generated</td>
    -+        <td class="diffvalue">2016.08.16 14:03</td>
    -+      </tr>
    -+    </table>
    -+    </div><!-- End and-diff-id -->
    -+  <div class="and-diff-id" style="margin-right:8px;">
    -+    <table class="diffspectable">
    -+      <tr>
    -+        <td class="diffspec" colspan="2"><a href="jdiff_statistics.html">Statistics</a>
    -+      </tr>
    -+    </table>
    -+  </div> <!-- End and-diff-id -->
    -+  </div> <!-- End headerRight -->
    -+  </div> <!-- End header -->
    -+<div id="body-content" xstyle="padding:12px;padding-right:18px;">
    -+<div id="doc-content" style="position:relative;">
    -+<div id="mainBodyFluid">
    -+<H2>
    -+Package <A HREF="../../../../reference/android/support/v7/widget/package-summary.html" target="_top"><font size="+1"><code>android.support.v7.widget</code></font></A>
    -+</H2>
    -+<p>
    -+<a NAME="Added"></a>
    -+<TABLE summary="Added Classes and Interfaces" WIDTH="100%">
    -+<TR>
    -+  <TH VALIGN="TOP" COLSPAN=2>Added Classes and Interfaces</FONT></TD>
    -+</TH>
    -+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    -+  <TD VALIGN="TOP" WIDTH="25%">
    -+  <A NAME="ActionMenuView"></A>
    -+  <nobr><A HREF="../../../../reference/android/support/v7/widget/ActionMenuView.html" target="_top"><code>ActionMenuView</code></A></nobr>
    -+  </TD>
    -+  <TD>&nbsp;</TD>
    -+</TR>
    -+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    -+  <TD VALIGN="TOP" WIDTH="25%">
    -+  <A NAME="ActionMenuView.LayoutParams"></A>
    -+  <nobr><A HREF="../../../../reference/android/support/v7/widget/ActionMenuView.LayoutParams.html" target="_top"><code>ActionMenuView.LayoutParams</code></A></nobr>
    -+  </TD>
    -+  <TD>&nbsp;</TD>
    -+</TR>
    -+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    -+  <TD VALIGN="TOP" WIDTH="25%">
    -+  <A NAME="ActionMenuView.OnMenuItemClickListener"></A>
    -+  <nobr><A HREF="../../../../reference/android/support/v7/widget/ActionMenuView.OnMenuItemClickListener.html" target="_top"><code><I>ActionMenuView.OnMenuItemClickListener</I></code></A></nobr>
    -+  </TD>
    -+  <TD>&nbsp;</TD>
    -+</TR>
    -+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    -+  <TD VALIGN="TOP" WIDTH="25%">
    -+  <A NAME="AppCompatAutoCompleteTextView"></A>
    -+  <nobr><A HREF="../../../../reference/android/support/v7/widget/AppCompatAutoCompleteTextView.html" target="_top"><code>AppCompatAutoCompleteTextView</code></A></nobr>
    -+  </TD>
    -+  <TD>&nbsp;</TD>
    -+</TR>
    -+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    -+  <TD VALIGN="TOP" WIDTH="25%">
    -+  <A NAME="AppCompatButton"></A>
    -+  <nobr><A HREF="../../../../reference/android/support/v7/widget/AppCompatButton.html" target="_top"><code>AppCompatButton</code></A></nobr>
    -+  </TD>
    -+  <TD>&nbsp;</TD>
    -+</TR>
    -+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    -+  <TD VALIGN="TOP" WIDTH="25%">
    -+  <A NAME="AppCompatCheckBox"></A>
    -+  <nobr><A HREF="../../../../reference/android/support/v7/widget/AppCompatCheckBox.html" target="_top"><code>AppCompatCheckBox</code></A></nobr>
    -+  </TD>
    -+  <TD>&nbsp;</TD>
    -+</TR>
    -+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    -+  <TD VALIGN="TOP" WIDTH="25%">
    -+  <A NAME="AppCompatCheckedTextView"></A>
    -+  <nobr><A HREF="../../../../reference/android/support/v7/widget/AppCompatCheckedTextView.html" target="_top"><code>AppCompatCheckedTextView</code></A></nobr>
    -+  </TD>
    -+  <TD>&nbsp;</TD>
    -+</TR>
    -+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    -+  <TD VALIGN="TOP" WIDTH="25%">
    -+  <A NAME="AppCompatEditText"></A>
    -+  <nobr><A HREF="../../../../reference/android/support/v7/widget/AppCompatEditText.html" target="_top"><code>AppCompatEditText</code></A></nobr>
    -+  </TD>
    -+  <TD>&nbsp;</TD>
    -+</TR>
    -+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    -+  <TD VALIGN="TOP" WIDTH="25%">
    -+  <A NAME="AppCompatImageButton"></A>
    -+  <nobr><A HREF="../../../../reference/android/support/v7/widget/AppCompatImageButton.html" target="_top"><code>AppCompatImageButton</code></A></nobr>
    -+  </TD>
    -+  <TD>&nbsp;</TD>
    -+</TR>
    -+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    -+  <TD VALIGN="TOP" WIDTH="25%">
    -+  <A NAME="AppCompatImageView"></A>
    -+  <nobr><A HREF="../../../../reference/android/support/v7/widget/AppCompatImageView.html" target="_top"><code>AppCompatImageView</code></A></nobr>
    -+  </TD>
    -+  <TD>&nbsp;</TD>
    -+</TR>
    -+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    -+  <TD VALIGN="TOP" WIDTH="25%">
    -+  <A NAME="AppCompatMultiAutoCompleteTextView"></A>
    -+  <nobr><A HREF="../../../../reference/android/support/v7/widget/AppCompatMultiAutoCompleteTextView.html" target="_top"><code>AppCompatMultiAutoCompleteTextView</code></A></nobr>
    -+  </TD>
    -+  <TD>&nbsp;</TD>
    -+</TR>
    -+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    -+  <TD VALIGN="TOP" WIDTH="25%">
    -+  <A NAME="AppCompatRadioButton"></A>
    -+  <nobr><A HREF="../../../../reference/android/support/v7/widget/AppCompatRadioButton.html" target="_top"><code>AppCompatRadioButton</code></A></nobr>
    -+  </TD>
    -+  <TD>&nbsp;</TD>
    -+</TR>
    -+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    -+  <TD VALIGN="TOP" WIDTH="25%">
    -+  <A NAME="AppCompatRatingBar"></A>
    -+  <nobr><A HREF="../../../../reference/android/support/v7/widget/AppCompatRatingBar.html" target="_top"><code>AppCompatRatingBar</code></A></nobr>
    -+  </TD>
    -+  <TD>&nbsp;</TD>
    -+</TR>
    -+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    -+  <TD VALIGN="TOP" WIDTH="25%">
    -+  <A NAME="AppCompatSeekBar"></A>
    -+  <nobr><A HREF="../../../../reference/android/support/v7/widget/AppCompatSeekBar.html" target="_top"><code>AppCompatSeekBar</code></A></nobr>
    -+  </TD>
    -+  <TD>&nbsp;</TD>
    -+</TR>
    -+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    -+  <TD VALIGN="TOP" WIDTH="25%">
    -+  <A NAME="AppCompatSpinner"></A>
    -+  <nobr><A HREF="../../../../reference/android/support/v7/widget/AppCompatSpinner.html" target="_top"><code>AppCompatSpinner</code></A></nobr>
    -+  </TD>
    -+  <TD>&nbsp;</TD>
    -+</TR>
    -+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    -+  <TD VALIGN="TOP" WIDTH="25%">
    -+  <A NAME="AppCompatTextView"></A>
    -+  <nobr><A HREF="../../../../reference/android/support/v7/widget/AppCompatTextView.html" target="_top"><code>AppCompatTextView</code></A></nobr>
    -+  </TD>
    -+  <TD>&nbsp;</TD>
    -+</TR>
    -+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    -+  <TD VALIGN="TOP" WIDTH="25%">
    -+  <A NAME="CardView"></A>
    -+  <nobr><A HREF="../../../../reference/android/support/v7/widget/CardView.html" target="_top"><code>CardView</code></A></nobr>
    -+  </TD>
    -+  <TD>&nbsp;</TD>
    -+</TR>
    -+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    -+  <TD VALIGN="TOP" WIDTH="25%">
    -+  <A NAME="GridLayout"></A>
    -+  <nobr><A HREF="../../../../reference/android/support/v7/widget/GridLayout.html" target="_top"><code>GridLayout</code></A></nobr>
    -+  </TD>
    -+  <TD>&nbsp;</TD>
    -+</TR>
    -+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    -+  <TD VALIGN="TOP" WIDTH="25%">
    -+  <A NAME="GridLayout.Alignment"></A>
    -+  <nobr><A HREF="../../../../reference/android/support/v7/widget/GridLayout.Alignment.html" target="_top"><code>GridLayout.Alignment</code></A></nobr>
    -+  </TD>
    -+  <TD>&nbsp;</TD>
    -+</TR>
    -+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    -+  <TD VALIGN="TOP" WIDTH="25%">
    -+  <A NAME="GridLayout.LayoutParams"></A>
    -+  <nobr><A HREF="../../../../reference/android/support/v7/widget/GridLayout.LayoutParams.html" target="_top"><code>GridLayout.LayoutParams</code></A></nobr>
    -+  </TD>
    -+  <TD>&nbsp;</TD>
    -+</TR>
    -+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    -+  <TD VALIGN="TOP" WIDTH="25%">
    -+  <A NAME="GridLayout.Spec"></A>
    -+  <nobr><A HREF="../../../../reference/android/support/v7/widget/GridLayout.Spec.html" target="_top"><code>GridLayout.Spec</code></A></nobr>
    -+  </TD>
    -+  <TD>&nbsp;</TD>
    -+</TR>
    -+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    -+  <TD VALIGN="TOP" WIDTH="25%">
    -+  <A NAME="LinearLayoutCompat"></A>
    -+  <nobr><A HREF="../../../../reference/android/support/v7/widget/LinearLayoutCompat.html" target="_top"><code>LinearLayoutCompat</code></A></nobr>
    -+  </TD>
    -+  <TD>&nbsp;</TD>
    -+</TR>
    -+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    -+  <TD VALIGN="TOP" WIDTH="25%">
    -+  <A NAME="LinearLayoutCompat.LayoutParams"></A>
    -+  <nobr><A HREF="../../../../reference/android/support/v7/widget/LinearLayoutCompat.LayoutParams.html" target="_top"><code>LinearLayoutCompat.LayoutParams</code></A></nobr>
    -+  </TD>
    -+  <TD>&nbsp;</TD>
    -+</TR>
    -+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    -+  <TD VALIGN="TOP" WIDTH="25%">
    -+  <A NAME="LinearSnapHelper"></A>
    -+  <nobr><A HREF="../../../../reference/android/support/v7/widget/LinearSnapHelper.html" target="_top"><code>LinearSnapHelper</code></A></nobr>
    -+  </TD>
    -+  <TD>&nbsp;</TD>
    -+</TR>
    -+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    -+  <TD VALIGN="TOP" WIDTH="25%">
    -+  <A NAME="ListPopupWindow"></A>
    -+  <nobr><A HREF="../../../../reference/android/support/v7/widget/ListPopupWindow.html" target="_top"><code>ListPopupWindow</code></A></nobr>
    -+  </TD>
    -+  <TD>&nbsp;</TD>
    -+</TR>
    -+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    -+  <TD VALIGN="TOP" WIDTH="25%">
    -+  <A NAME="PopupMenu"></A>
    -+  <nobr><A HREF="../../../../reference/android/support/v7/widget/PopupMenu.html" target="_top"><code>PopupMenu</code></A></nobr>
    -+  </TD>
    -+  <TD>&nbsp;</TD>
    -+</TR>
    -+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    -+  <TD VALIGN="TOP" WIDTH="25%">
    -+  <A NAME="PopupMenu.OnDismissListener"></A>
    -+  <nobr><A HREF="../../../../reference/android/support/v7/widget/PopupMenu.OnDismissListener.html" target="_top"><code><I>PopupMenu.OnDismissListener</I></code></A></nobr>
    -+  </TD>
    -+  <TD>&nbsp;</TD>
    -+</TR>
    -+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    -+  <TD VALIGN="TOP" WIDTH="25%">
    -+  <A NAME="PopupMenu.OnMenuItemClickListener"></A>
    -+  <nobr><A HREF="../../../../reference/android/support/v7/widget/PopupMenu.OnMenuItemClickListener.html" target="_top"><code><I>PopupMenu.OnMenuItemClickListener</I></code></A></nobr>
    -+  </TD>
    -+  <TD>&nbsp;</TD>
    -+</TR>
    -+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    -+  <TD VALIGN="TOP" WIDTH="25%">
    -+  <A NAME="RecyclerView.OnFlingListener"></A>
    -+  <nobr><A HREF="../../../../reference/android/support/v7/widget/RecyclerView.OnFlingListener.html" target="_top"><code>RecyclerView.OnFlingListener</code></A></nobr>
    -+  </TD>
    -+  <TD>&nbsp;</TD>
    -+</TR>
    -+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    -+  <TD VALIGN="TOP" WIDTH="25%">
    -+  <A NAME="RecyclerView.SmoothScroller.ScrollVectorProvider"></A>
    -+  <nobr><A HREF="../../../../reference/android/support/v7/widget/RecyclerView.SmoothScroller.ScrollVectorProvider.html" target="_top"><code><I>RecyclerView.SmoothScroller.<br>ScrollVectorProvider</I></code></A></nobr>
    -+  </TD>
    -+  <TD>&nbsp;</TD>
    -+</TR>
    -+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    -+  <TD VALIGN="TOP" WIDTH="25%">
    -+  <A NAME="SearchView"></A>
    -+  <nobr><A HREF="../../../../reference/android/support/v7/widget/SearchView.html" target="_top"><code>SearchView</code></A></nobr>
    -+  </TD>
    -+  <TD>&nbsp;</TD>
    -+</TR>
    -+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    -+  <TD VALIGN="TOP" WIDTH="25%">
    -+  <A NAME="SearchView.OnCloseListener"></A>
    -+  <nobr><A HREF="../../../../reference/android/support/v7/widget/SearchView.OnCloseListener.html" target="_top"><code><I>SearchView.OnCloseListener</I></code></A></nobr>
    -+  </TD>
    -+  <TD>&nbsp;</TD>
    -+</TR>
    -+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    -+  <TD VALIGN="TOP" WIDTH="25%">
    -+  <A NAME="SearchView.OnQueryTextListener"></A>
    -+  <nobr><A HREF="../../../../reference/android/support/v7/widget/SearchView.OnQueryTextListener.html" target="_top"><code><I>SearchView.OnQueryTextListener</I></code></A></nobr>
    -+  </TD>
    -+  <TD>&nbsp;</TD>
    -+</TR>
    -+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    -+  <TD VALIGN="TOP" WIDTH="25%">
    -+  <A NAME="SearchView.OnSuggestionListener"></A>
    -+  <nobr><A HREF="../../../../reference/android/support/v7/widget/SearchView.OnSuggestionListener.html" target="_top"><code><I>SearchView.OnSuggestionListener</I></code></A></nobr>
    -+  </TD>
    -+  <TD>&nbsp;</TD>
    -+</TR>
    -+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    -+  <TD VALIGN="TOP" WIDTH="25%">
    -+  <A NAME="ShareActionProvider"></A>
    -+  <nobr><A HREF="../../../../reference/android/support/v7/widget/ShareActionProvider.html" target="_top"><code>ShareActionProvider</code></A></nobr>
    -+  </TD>
    -+  <TD>&nbsp;</TD>
    -+</TR>
    -+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    -+  <TD VALIGN="TOP" WIDTH="25%">
    -+  <A NAME="ShareActionProvider.OnShareTargetSelectedListener"></A>
    -+  <nobr><A HREF="../../../../reference/android/support/v7/widget/ShareActionProvider.OnShareTargetSelectedListener.html" target="_top"><code><I>ShareActionProvider.OnShareTargetSelectedListener</I></code></A></nobr>
    -+  </TD>
    -+  <TD>&nbsp;</TD>
    -+</TR>
    -+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    -+  <TD VALIGN="TOP" WIDTH="25%">
    -+  <A NAME="SnapHelper"></A>
    -+  <nobr><A HREF="../../../../reference/android/support/v7/widget/SnapHelper.html" target="_top"><code>SnapHelper</code></A></nobr>
    -+  </TD>
    -+  <TD>&nbsp;</TD>
    -+</TR>
    -+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    -+  <TD VALIGN="TOP" WIDTH="25%">
    -+  <A NAME="Space"></A>
    -+  <nobr><A HREF="../../../../reference/android/support/v7/widget/Space.html" target="_top"><code>Space</code></A></nobr>
    -+  </TD>
    -+  <TD>&nbsp;</TD>
    -+</TR>
    -+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    -+  <TD VALIGN="TOP" WIDTH="25%">
    -+  <A NAME="SwitchCompat"></A>
    -+  <nobr><A HREF="../../../../reference/android/support/v7/widget/SwitchCompat.html" target="_top"><code>SwitchCompat</code></A></nobr>
    -+  </TD>
    -+  <TD>&nbsp;</TD>
    -+</TR>
    -+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    -+  <TD VALIGN="TOP" WIDTH="25%">
    -+  <A NAME="ThemedSpinnerAdapter"></A>
    -+  <nobr><A HREF="../../../../reference/android/support/v7/widget/ThemedSpinnerAdapter.html" target="_top"><code><I>ThemedSpinnerAdapter</I></code></A></nobr>
    -+  </TD>
    -+  <TD>&nbsp;</TD>
    -+</TR>
    -+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    -+  <TD VALIGN="TOP" WIDTH="25%">
    -+  <A NAME="ThemedSpinnerAdapter.Helper"></A>
    -+  <nobr><A HREF="../../../../reference/android/support/v7/widget/ThemedSpinnerAdapter.Helper.html" target="_top"><code>ThemedSpinnerAdapter.Helper</code></A></nobr>
    -+  </TD>
    -+  <TD>&nbsp;</TD>
    -+</TR>
    -+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    -+  <TD VALIGN="TOP" WIDTH="25%">
    -+  <A NAME="Toolbar"></A>
    -+  <nobr><A HREF="../../../../reference/android/support/v7/widget/Toolbar.html" target="_top"><code>Toolbar</code></A></nobr>
    -+  </TD>
    -+  <TD>&nbsp;</TD>
    -+</TR>
    -+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    -+  <TD VALIGN="TOP" WIDTH="25%">
    -+  <A NAME="Toolbar.LayoutParams"></A>
    -+  <nobr><A HREF="../../../../reference/android/support/v7/widget/Toolbar.LayoutParams.html" target="_top"><code>Toolbar.LayoutParams</code></A></nobr>
    -+  </TD>
    -+  <TD>&nbsp;</TD>
    -+</TR>
    -+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    -+  <TD VALIGN="TOP" WIDTH="25%">
    -+  <A NAME="Toolbar.OnMenuItemClickListener"></A>
    -+  <nobr><A HREF="../../../../reference/android/support/v7/widget/Toolbar.OnMenuItemClickListener.html" target="_top"><code><I>Toolbar.OnMenuItemClickListener</I></code></A></nobr>
    -+  </TD>
    -+  <TD>&nbsp;</TD>
    -+</TR>
    -+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    -+  <TD VALIGN="TOP" WIDTH="25%">
    -+  <A NAME="Toolbar.SavedState"></A>
    -+  <nobr><A HREF="../../../../reference/android/support/v7/widget/Toolbar.SavedState.html" target="_top"><code>Toolbar.SavedState</code></A></nobr>
    -+  </TD>
    -+  <TD>&nbsp;</TD>
    -+</TR>
    -+</TABLE>
    -+&nbsp;
    -+<p>
    -+<a NAME="Changed"></a>
    -+<TABLE summary="Changed Classes" WIDTH="100%">
    -+<TR>
    -+  <TH VALIGN="TOP" COLSPAN=2>Changed Classes</FONT></TD>
    -+</TH>
    -+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    -+  <TD VALIGN="TOP" WIDTH="25%">
    -+  <A NAME="LinearLayoutManager"></A>
    -+  <nobr><A HREF="android.support.v7.widget.LinearLayoutManager.html">LinearLayoutManager</A></nobr>
    -+  </TD>
    -+  <TD>&nbsp;</TD>
    -+</TR>
    -+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    -+  <TD VALIGN="TOP" WIDTH="25%">
    -+  <A NAME="LinearSmoothScroller"></A>
    -+  <nobr><A HREF="android.support.v7.widget.LinearSmoothScroller.html">LinearSmoothScroller</A></nobr>
    -+  </TD>
    -+  <TD>&nbsp;</TD>
    -+</TR>
    -+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    -+  <TD VALIGN="TOP" WIDTH="25%">
    -+  <A NAME="RecyclerView"></A>
    -+  <nobr><A HREF="android.support.v7.widget.RecyclerView.html">RecyclerView</A></nobr>
    -+  </TD>
    -+  <TD>&nbsp;</TD>
    -+</TR>
    -+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
    -+  <TD VALIGN="TOP" WIDTH="25%">
    -+  <A NAME="StaggeredGridLayoutManager"></A>
    -+  <nobr><A HREF="android.support.v7.widget.StaggeredGridLayoutManager.html">StaggeredGridLayoutManager</A></nobr>
    -+  </TD>
    -+  <TD>&nbsp;</TD>
    -+</TR>
    -+</TABLE>
    -+&nbsp;
    -+      </div>	
    -+      <div id="footer">
    -+        <div id="copyright">
    -+        Except as noted, this content is licensed under 
    -+        <a href="http://creativecommons.org/licenses/by/2.5/"> Creative Commons Attribution 2.5</a>.
    -+        For details and restrictions, see the <a href="/license.html">Content License</a>.
    -+        </div>
    -+      <div id="footerlinks">
    -+      <p>
    -+        <a href="http://www.android.com/terms.html">Site Terms of Service</a> -
    -+        <a href="http://www.android.com/privacy.html">Privacy Policy</a> -
    -+        <a href="http://www.android.com/branding.html">Brand Guidelines</a>
    -+      </p>
    -+    </div>
    -+    </div> <!-- end footer -->
    -+    </div><!-- end doc-content -->
    -+    </div> <!-- end body-content --> 
    -+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
    -+</script>
    -+<script type="text/javascript">
    -+  try {
    -+    var pageTracker = _gat._getTracker("UA-5831155-1");
    -+    pageTracker._setAllowAnchor(true);
    -+    pageTracker._initData();
    -+    pageTracker._trackPageview();
    -+  } catch(e) {}
    -+</script>
    -+</BODY>
    -+</HTML>
    -diff --git a/docs/html/sdk/support_api_diff/24.2.0/missingSinces.txt b/docs/html/sdk/support_api_diff/24.2.0/missingSinces.txt
    -new file mode 100644
    -index 0000000..9514985
    ---- /dev/null
    -+++ b/docs/html/sdk/support_api_diff/24.2.0/missingSinces.txt
    -@@ -0,0 +1,183 @@
    -+NO DOC BLOCK: android.support.v4.view.accessibility.AccessibilityManagerCompat.AccessibilityStateChangeListener Interface
    -+NO DOC BLOCK: android.support.v4.view.accessibility.AccessibilityManagerCompat.TouchExplorationStateChangeListener Interface
    -+NO DOC BLOCK: android.support.v7.app.ActionBarActivity Class
    -+NO DOC BLOCK: android.support.v7.widget.ActionMenuView Class
    -+NO DOC BLOCK: android.support.v7.widget.ActionMenuView.LayoutParams Class
    -+NO DOC BLOCK: android.support.v7.widget.ActionMenuView.OnMenuItemClickListener Interface
    -+NO DOC BLOCK: android.support.v7.app.AppCompatActivity Class
    -+NO DOC BLOCK: android.support.v7.widget.AppCompatAutoCompleteTextView Class
    -+NO DOC BLOCK: android.support.v7.widget.AppCompatButton Class
    -+NO DOC BLOCK: android.support.v7.widget.AppCompatCheckBox Class
    -+NO DOC BLOCK: android.support.v7.widget.AppCompatCheckedTextView Class
    -+NO DOC BLOCK: android.support.v7.app.AppCompatDialogFragment Class
    -+NO DOC BLOCK: android.support.v7.widget.AppCompatEditText Class
    -+NO DOC BLOCK: android.support.v7.widget.AppCompatImageButton Class
    -+NO DOC BLOCK: android.support.v7.widget.AppCompatImageView Class
    -+NO DOC BLOCK: android.support.v7.widget.AppCompatMultiAutoCompleteTextView Class
    -+NO DOC BLOCK: android.support.v7.widget.AppCompatRadioButton Class
    -+NO DOC BLOCK: android.support.v7.widget.AppCompatRatingBar Class
    -+NO DOC BLOCK: android.support.v7.widget.AppCompatSeekBar Class
    -+NO DOC BLOCK: android.support.v7.widget.AppCompatSpinner Class
    -+NO DOC BLOCK: android.support.v7.widget.AppCompatTextView Class
    -+NO DOC BLOCK: android.support.v7.util.BatchingListUpdateCallback Class
    -+NO DOC BLOCK: android.support.v7.widget.CardView Class
    -+NO DOC BLOCK: android.support.v7.util.DiffUtil Class
    -+NO DOC BLOCK: android.support.v7.util.DiffUtil.Callback Class
    -+NO DOC BLOCK: android.support.v7.util.DiffUtil.DiffResult Class
    -+NO DOC BLOCK: android.support.v7.widget.GridLayout Class
    -+NO DOC BLOCK: android.support.v7.widget.GridLayout.Alignment Class
    -+NO DOC BLOCK: android.support.v7.widget.GridLayout.LayoutParams Class
    -+NO DOC BLOCK: android.support.v7.widget.GridLayout.Spec Class
    -+NO DOC BLOCK: android.support.v7.widget.LinearLayoutCompat Class
    -+NO DOC BLOCK: android.support.v7.widget.LinearLayoutCompat.LayoutParams Class
    -+NO DOC BLOCK: android.support.v7.widget.LinearSnapHelper Class
    -+NO DOC BLOCK: android.support.v7.widget.ListPopupWindow Class
    -+NO DOC BLOCK: android.support.v7.util.ListUpdateCallback Interface
    -+NO DOC BLOCK: android.support.v7.preference.MultiSelectListPreferenceDialogFragmentCompat Class
    -+NO DOC BLOCK: android.support.v7.app.NotificationCompat Class
    -+NO DOC BLOCK: android.support.v7.app.NotificationCompat.Builder Class
    -+NO DOC BLOCK: android.support.v7.app.NotificationCompat.MediaStyle Class
    -+NO DOC BLOCK: android.support.v4.util.PatternsCompat Class
    -+NO DOC BLOCK: android.support.v7.widget.PopupMenu Class
    -+NO DOC BLOCK: android.support.v7.widget.PopupMenu.OnDismissListener Interface
    -+NO DOC BLOCK: android.support.v7.widget.PopupMenu.OnMenuItemClickListener Interface
    -+NO DOC BLOCK: android.support.v7.widget.RecyclerView.OnFlingListener Class
    -+NO DOC BLOCK: android.support.v7.widget.RecyclerView.SmoothScroller.ScrollVectorProvider Interface
    -+NO DOC BLOCK: android.support.v7.widget.SearchView Class
    -+NO DOC BLOCK: android.support.v7.widget.SearchView.OnCloseListener Interface
    -+NO DOC BLOCK: android.support.v7.widget.SearchView.OnQueryTextListener Interface
    -+NO DOC BLOCK: android.support.v7.widget.SearchView.OnSuggestionListener Interface
    -+NO DOC BLOCK: android.support.v4.widget.SearchViewCompat.OnCloseListener Interface
    -+NO DOC BLOCK: android.support.v4.widget.SearchViewCompat.OnQueryTextListener Interface
    -+NO DOC BLOCK: android.support.v7.widget.ShareActionProvider Class
    -+NO DOC BLOCK: android.support.v7.widget.ShareActionProvider.OnShareTargetSelectedListener Interface
    -+NO DOC BLOCK: android.support.v4.app.SharedElementCallback.OnSharedElementsReadyListener Interface
    -+NO DOC BLOCK: android.support.v7.widget.SnapHelper Class
    -+NO DOC BLOCK: android.support.v7.widget.Space Class
    -+NO DOC BLOCK: android.support.v4.widget.SwipeRefreshLayout.OnChildScrollUpCallback Interface
    -+NO DOC BLOCK: android.support.v7.widget.SwitchCompat Class
    -+NO DOC BLOCK: android.support.v7.widget.ThemedSpinnerAdapter Interface
    -+NO DOC BLOCK: android.support.v7.widget.ThemedSpinnerAdapter.Helper Class
    -+NO DOC BLOCK: android.support.v7.widget.Toolbar Class
    -+NO DOC BLOCK: android.support.v7.widget.Toolbar.LayoutParams Class
    -+NO DOC BLOCK: android.support.v7.widget.Toolbar.OnMenuItemClickListener Interface
    -+NO DOC BLOCK: android.support.v7.widget.Toolbar.SavedState Class
    -+NO DOC BLOCK: android.support.v4.view.WindowInsetsCompat Constructor (android.support.v4.view.WindowInsetsCompat)
    -+NO DOC BLOCK: android.support.v4.view.accessibility.AccessibilityManagerCompat Method addTouchExplorationStateChangeListener(android.view.accessibility.AccessibilityManager, android.support.v4.view.accessibility.AccessibilityManagerCompat.TouchExplorationStateChangeListener)
    -+NO DOC BLOCK: android.support.v4.media.session.MediaButtonReceiver Method buildMediaButtonPendingIntent(android.content.Context, android.content.ComponentName, long)
    -+NO DOC BLOCK: android.support.v4.media.session.MediaButtonReceiver Method buildMediaButtonPendingIntent(android.content.Context, long)
    -+NO DOC BLOCK: android.support.v4.graphics.drawable.DrawableCompat Method clearColorFilter(android.graphics.drawable.Drawable)
    -+NO DOC BLOCK: android.support.design.widget.TabLayout Method clearOnTabSelectedListeners()
    -+NO DOC BLOCK: android.support.v7.widget.StaggeredGridLayoutManager Method computeScrollVectorForPosition(int)
    -+NO DOC BLOCK: android.support.v4.app.FragmentController Method findFragmentByWho(java.lang.String)
    -+NO DOC BLOCK: android.support.v4.media.MediaBrowserCompat.MediaItem Method fromMediaItem(java.lang.Object)
    -+NO DOC BLOCK: android.support.v4.media.MediaBrowserCompat.MediaItem Method fromMediaItemList(java.util.List<?>)
    -+NO DOC BLOCK: android.support.v4.media.session.MediaSessionCompat Method fromMediaSession(android.content.Context, java.lang.Object)
    -+NO DOC BLOCK: android.support.v4.media.session.MediaSessionCompat.QueueItem Method fromQueueItem(java.lang.Object)
    -+NO DOC BLOCK: android.support.v4.media.session.MediaSessionCompat.QueueItem Method fromQueueItemList(java.util.List<?>)
    -+NO DOC BLOCK: android.support.v4.view.accessibility.AccessibilityEventCompat Method getAction(android.view.accessibility.AccessibilityEvent)
    -+NO DOC BLOCK: android.support.v4.widget.TextViewCompat Method getCompoundDrawablesRelative(android.widget.TextView)
    -+NO DOC BLOCK: android.support.design.widget.CoordinatorLayout Method getDependents(android.view.View)
    -+NO DOC BLOCK: android.support.v7.graphics.Palette Method getDominantColor(int)
    -+NO DOC BLOCK: android.support.v7.graphics.Palette Method getDominantSwatch()
    -+NO DOC BLOCK: android.support.v7.content.res.AppCompatResources Method getDrawable(android.content.Context, int)
    -+NO DOC BLOCK: android.support.v7.app.ActionBarDrawerToggle Method getDrawerArrowDrawable()
    -+NO DOC BLOCK: android.support.design.widget.CoordinatorLayout.Behavior Method getInsetDodgeRect(android.support.design.widget.CoordinatorLayout, V, android.graphics.Rect)
    -+NO DOC BLOCK: android.support.design.widget.FloatingActionButton.Behavior Method getInsetDodgeRect(android.support.design.widget.CoordinatorLayout, android.support.design.widget.FloatingActionButton, android.graphics.Rect)
    -+NO DOC BLOCK: android.support.v4.app.ActivityOptionsCompat Method getLaunchBounds()
    -+NO DOC BLOCK: android.support.v17.leanback.widget.AbstractMediaItemPresenter.ViewHolder Method getMediaItemNumberViewFlipper()
    -+NO DOC BLOCK: android.support.v17.leanback.widget.AbstractMediaItemPresenter.ViewHolder Method getMediaItemPausedView()
    -+NO DOC BLOCK: android.support.v17.leanback.widget.AbstractMediaItemPresenter.ViewHolder Method getMediaItemPlayingView()
    -+NO DOC BLOCK: android.support.v17.leanback.widget.AbstractMediaItemPresenter Method getMediaPlayState(java.lang.Object)
    -+NO DOC BLOCK: android.support.v4.view.accessibility.AccessibilityEventCompat Method getMovementGranularity(android.view.accessibility.AccessibilityEvent)
    -+NO DOC BLOCK: android.support.v7.widget.RecyclerView Method getOnFlingListener()
    -+NO DOC BLOCK: android.support.design.widget.TextInputLayout Method getPasswordVisibilityToggleContentDescription()
    -+NO DOC BLOCK: android.support.design.widget.TextInputLayout Method getPasswordVisibilityToggleDrawable()
    -+NO DOC BLOCK: android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.CollectionInfoCompat Method getSelectionMode()
    -+NO DOC BLOCK: android.support.v4.os.BuildCompat Method isAtLeastNMR1()
    -+NO DOC BLOCK: android.support.design.widget.FloatingActionButton.Behavior Method isAutoHideEnabled()
    -+NO DOC BLOCK: android.support.v4.view.accessibility.AccessibilityNodeInfoCompat Method isContextClickable()
    -+NO DOC BLOCK: android.support.v17.leanback.widget.ObjectAdapter Method isImmediateNotifySupported()
    -+NO DOC BLOCK: android.support.v4.view.ViewCompat Method isImportantForAccessibility(android.view.View)
    -+NO DOC BLOCK: android.support.design.widget.TextInputLayout Method isPasswordVisibilityToggleEnabled()
    -+NO DOC BLOCK: android.support.v4.accessibilityservice.AccessibilityServiceInfoCompat Method loadDescription(android.accessibilityservice.AccessibilityServiceInfo, android.content.pm.PackageManager)
    -+NO DOC BLOCK: android.support.v4.app.ActivityOptionsCompat Method makeBasic()
    -+NO DOC BLOCK: android.support.v4.app.ActivityOptionsCompat Method makeClipRevealAnimation(android.view.View, int, int, int, int)
    -+NO DOC BLOCK: android.support.v4.app.ActivityOptionsCompat Method makeTaskLaunchBehind()
    -+NO DOC BLOCK: android.support.v17.leanback.widget.AbstractMediaItemPresenter.ViewHolder Method notifyPlayStateChanged()
    -+NO DOC BLOCK: android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.CollectionInfoCompat Method obtain(int, int, boolean)
    -+NO DOC BLOCK: android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.CollectionItemInfoCompat Method obtain(int, int, int, int, boolean)
    -+NO DOC BLOCK: android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.RangeInfoCompat Method obtain(int, float, float, float)
    -+NO DOC BLOCK: android.support.design.widget.CoordinatorLayout.Behavior Method onAttachedToLayoutParams(android.support.design.widget.CoordinatorLayout.LayoutParams)
    -+NO DOC BLOCK: android.support.v17.leanback.widget.AbstractMediaItemPresenter Method onBindMediaPlayState(android.support.v17.leanback.widget.AbstractMediaItemPresenter.ViewHolder)
    -+NO DOC BLOCK: android.support.v7.util.SortedList.Callback Method onChanged(int, int, java.lang.Object)
    -+NO DOC BLOCK: android.support.design.widget.CoordinatorLayout.Behavior Method onDetachedFromLayoutParams()
    -+NO DOC BLOCK: android.support.design.widget.AppBarLayout.ScrollingViewBehavior Method onRequestChildRectangleOnScreen(android.support.design.widget.CoordinatorLayout, android.view.View, android.graphics.Rect, boolean)
    -+NO DOC BLOCK: android.support.design.widget.CoordinatorLayout.Behavior Method onRequestChildRectangleOnScreen(android.support.design.widget.CoordinatorLayout, V, android.graphics.Rect, boolean)
    -+NO DOC BLOCK: android.support.v4.app.SharedElementCallback Method onSharedElementsArrived(java.util.List<java.lang.String>, java.util.List<android.view.View>, android.support.v4.app.SharedElementCallback.OnSharedElementsReadyListener)
    -+NO DOC BLOCK: android.support.v7.app.AppCompatDelegate Method onStart()
    -+NO DOC BLOCK: android.support.v17.leanback.widget.AbstractMediaItemPresenter Method onUnbindMediaPlayState(android.support.v17.leanback.widget.AbstractMediaItemPresenter.ViewHolder)
    -+NO DOC BLOCK: android.support.v4.view.accessibility.AccessibilityManagerCompat Method removeTouchExplorationStateChangeListener(android.view.accessibility.AccessibilityManager, android.support.v4.view.accessibility.AccessibilityManagerCompat.TouchExplorationStateChangeListener)
    -+NO DOC BLOCK: android.support.v4.app.ActivityOptionsCompat Method requestUsageTimeReport(android.app.PendingIntent)
    -+NO DOC BLOCK: android.support.v4.view.accessibility.AccessibilityEventCompat Method setAction(android.view.accessibility.AccessibilityEvent, int)
    -+NO DOC BLOCK: android.support.customtabs.CustomTabsIntent Method setAlwaysUseBrowserUI(android.content.Intent)
    -+NO DOC BLOCK: android.support.design.widget.FloatingActionButton.Behavior Method setAutoHideEnabled(boolean)
    -+NO DOC BLOCK: android.support.design.widget.CollapsingToolbarLayout Method setCollapsedTitleTextColor(android.content.res.ColorStateList)
    -+NO DOC BLOCK: android.support.v4.view.accessibility.AccessibilityNodeInfoCompat Method setContextClickable(boolean)
    -+NO DOC BLOCK: android.support.v7.app.ActionBarDrawerToggle Method setDrawerArrowDrawable(android.support.v7.graphics.drawable.DrawerArrowDrawable)
    -+NO DOC BLOCK: android.support.design.widget.CollapsingToolbarLayout Method setExpandedTitleTextColor(android.content.res.ColorStateList)
    -+NO DOC BLOCK: android.support.customtabs.CustomTabsIntent.Builder Method setInstantAppsEnabled(boolean)
    -+NO DOC BLOCK: android.support.v4.app.ActivityOptionsCompat Method setLaunchBounds(android.graphics.Rect)
    -+NO DOC BLOCK: android.support.v4.view.accessibility.AccessibilityEventCompat Method setMovementGranularity(android.view.accessibility.AccessibilityEvent, int)
    -+NO DOC BLOCK: android.support.v4.widget.SwipeRefreshLayout Method setOnChildScrollUpCallback(android.support.v4.widget.SwipeRefreshLayout.OnChildScrollUpCallback)
    -+NO DOC BLOCK: android.support.v7.widget.RecyclerView Method setOnFlingListener(android.support.v7.widget.RecyclerView.OnFlingListener)
    -+NO DOC BLOCK: android.support.design.widget.TextInputLayout Method setPasswordVisibilityToggleContentDescription(int)
    -+NO DOC BLOCK: android.support.design.widget.TextInputLayout Method setPasswordVisibilityToggleContentDescription(java.lang.CharSequence)
    -+NO DOC BLOCK: android.support.design.widget.TextInputLayout Method setPasswordVisibilityToggleDrawable(android.graphics.drawable.Drawable)
    -+NO DOC BLOCK: android.support.design.widget.TextInputLayout Method setPasswordVisibilityToggleDrawable(int)
    -+NO DOC BLOCK: android.support.design.widget.TextInputLayout Method setPasswordVisibilityToggleEnabled(boolean)
    -+NO DOC BLOCK: android.support.design.widget.TextInputLayout Method setPasswordVisibilityToggleTintList(android.content.res.ColorStateList)
    -+NO DOC BLOCK: android.support.design.widget.TextInputLayout Method setPasswordVisibilityToggleTintMode(android.graphics.PorterDuff.Mode)
    -+NO DOC BLOCK: android.support.customtabs.CustomTabsSession Method setSecondaryToolbarViews(android.widget.RemoteViews, int[], android.app.PendingIntent)
    -+NO DOC BLOCK: android.support.v17.leanback.widget.AbstractMediaItemPresenter.ViewHolder Method setSelectedMediaItemNumberView(int)
    -+NO DOC BLOCK: android.support.customtabs.CustomTabsIntent Method shouldAlwaysUseBrowserUI(android.content.Intent)
    -+NO DOC BLOCK: android.support.v4.app.ServiceCompat Method stopForeground(android.app.Service, int)
    -+NO DOC BLOCK: android.support.v4.media.session.PlaybackStateCompat Method toKeyCode(long)
    -+NO DOC BLOCK: android.support.v4.view.accessibility.AccessibilityNodeInfoCompat Field ACTION_ARGUMENT_COLUMN_INT
    -+NO DOC BLOCK: android.support.v4.view.accessibility.AccessibilityNodeInfoCompat Field ACTION_ARGUMENT_PROGRESS_VALUE
    -+NO DOC BLOCK: android.support.v4.view.accessibility.AccessibilityNodeInfoCompat Field ACTION_ARGUMENT_ROW_INT
    -+NO DOC BLOCK: android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat Field ACTION_CONTEXT_CLICK
    -+NO DOC BLOCK: android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat Field ACTION_SCROLL_DOWN
    -+NO DOC BLOCK: android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat Field ACTION_SCROLL_LEFT
    -+NO DOC BLOCK: android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat Field ACTION_SCROLL_RIGHT
    -+NO DOC BLOCK: android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat Field ACTION_SCROLL_TO_POSITION
    -+NO DOC BLOCK: android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat Field ACTION_SCROLL_UP
    -+NO DOC BLOCK: android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat Field ACTION_SET_PROGRESS
    -+NO DOC BLOCK: android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat Field ACTION_SHOW_ON_SCREEN
    -+NO DOC BLOCK: android.support.v4.media.MediaDescriptionCompat Field BT_FOLDER_TYPE_ALBUMS
    -+NO DOC BLOCK: android.support.v4.media.MediaDescriptionCompat Field BT_FOLDER_TYPE_ARTISTS
    -+NO DOC BLOCK: android.support.v4.media.MediaDescriptionCompat Field BT_FOLDER_TYPE_GENRES
    -+NO DOC BLOCK: android.support.v4.media.MediaDescriptionCompat Field BT_FOLDER_TYPE_MIXED
    -+NO DOC BLOCK: android.support.v4.media.MediaDescriptionCompat Field BT_FOLDER_TYPE_PLAYLISTS
    -+NO DOC BLOCK: android.support.v4.media.MediaDescriptionCompat Field BT_FOLDER_TYPE_TITLES
    -+NO DOC BLOCK: android.support.v4.media.MediaDescriptionCompat Field BT_FOLDER_TYPE_YEARS
    -+NO DOC BLOCK: android.support.design.widget.CoordinatorLayout.LayoutParams Field dodgeInsetEdges
    -+NO DOC BLOCK: android.support.v4.media.MediaDescriptionCompat Field EXTRA_BT_FOLDER_TYPE
    -+NO DOC BLOCK: android.support.customtabs.CustomTabsIntent Field EXTRA_ENABLE_INSTANT_APPS
    -+NO DOC BLOCK: android.support.v4.media.MediaBrowserServiceCompat.BrowserRoot Field EXTRA_SUGGESTION_KEYWORDS
    -+NO DOC BLOCK: android.support.v4.app.ActivityOptionsCompat Field EXTRA_USAGE_TIME_REPORT
    -+NO DOC BLOCK: android.support.v4.app.ActivityOptionsCompat Field EXTRA_USAGE_TIME_REPORT_PACKAGES
    -+NO DOC BLOCK: android.support.v4.view.accessibility.AccessibilityNodeProviderCompat Field HOST_VIEW_ID
    -+NO DOC BLOCK: android.support.design.widget.CoordinatorLayout.LayoutParams Field insetEdge
    -+NO DOC BLOCK: android.support.v4.media.MediaMetadataCompat Field METADATA_KEY_BT_FOLDER_TYPE
    -+NO DOC BLOCK: android.support.v4.media.MediaMetadataCompat Field METADATA_KEY_MEDIA_URI
    -+NO DOC BLOCK: android.support.design.widget.BottomSheetBehavior Field PEEK_HEIGHT_AUTO
    -+NO DOC BLOCK: android.support.v17.leanback.widget.AbstractMediaItemPresenter Field PLAY_STATE_INITIAL
    -+NO DOC BLOCK: android.support.v17.leanback.widget.AbstractMediaItemPresenter Field PLAY_STATE_PAUSED
    -+NO DOC BLOCK: android.support.v17.leanback.widget.AbstractMediaItemPresenter Field PLAY_STATE_PLAYING
    -+NO DOC BLOCK: android.support.v4.app.ServiceCompat Field STOP_FOREGROUND_DETACH
    -+NO DOC BLOCK: android.support.v4.app.ServiceCompat Field STOP_FOREGROUND_REMOVE
    -+NO DOC BLOCK: android.support.v4.view.accessibility.AccessibilityEventCompat Field TYPE_ASSIST_READING_CONTEXT
    -+NO DOC BLOCK: android.support.v4.view.accessibility.AccessibilityWindowInfoCompat Field TYPE_SPLIT_SCREEN_DIVIDER
    -+NO DOC BLOCK: android.support.v4.view.accessibility.AccessibilityEventCompat Field TYPE_VIEW_CONTEXT_CLICKED
    -+NO DOC BLOCK: android.support.v4.view.accessibility.AccessibilityEventCompat Field TYPE_WINDOWS_CHANGED
    -diff --git a/docs/html/sdk/support_api_diff/24.2.0/stylesheet-jdiff.css b/docs/html/sdk/support_api_diff/24.2.0/stylesheet-jdiff.css
    -new file mode 100644
    -index 0000000..edafaa3
    ---- /dev/null
    -+++ b/docs/html/sdk/support_api_diff/24.2.0/stylesheet-jdiff.css
    -@@ -0,0 +1,44 @@
    -+
    -+/* (http://www.jdiff.org) */
    -+
    -+div.and-diff-id {border: 1px solid #eee;position:relative;float:right;clear:both;padding:0px;}
    -+table.diffspectable {border:1px;padding:0px;margin:0px;}
    -+.diffspechead {background-color:#eee;}
    -+.diffspectable tr {border:0px;padding:0px;}
    -+.diffspectable td  {background-color:eee;border:0px;font-size:90%;font-weight:normal;padding:0px;padding-left:1px;padding-right:1px;text-align:center;color:777;}
    -+td.diffvalueold {color:orange;background-color:white;border:0px;font-size:80%;font-style:normal;text-align:left;padding:0px;padding-left:1px;padding-right:1px;line-height:.95em;}
    -+td.diffvaluenew {color:green;background-color:white;border:0px;font-size:80%;font-weight:normal;text-align:left;padding:0px;padding-left:1px;padding-right:1px;line-height:.95em;}
    -+td.diffvalue {color:444;background-color:white;border:0px;font-size:80%;font-weight:normal;text-align:left;padding:0px;padding-left:1px;padding-right:1px;line-height:.95em;}
    -+td.diffspec {background-color:white;border:0px;font-size:80%;font-weight:normal;padding:1px;color:444;text-align:right;padding-right:.5em;line-height:.95em;}
    -+tt {font-size:11pt;font-family:monospace;}
    -+.indexHeader {
    -+  font-size:96%;
    -+  line-height:.8em;}
    -+.jdiffIndex td {
    -+  font-size:96%;
    -+  xline-height:.8em;
    -+  padding:2px;
    -+  padding-left:1em;}
    -+.indexText {
    -+  font-size:100%;
    -+  padding-left:1em;}
    -+#indexTableCaption {
    -+  font-size:96%;
    -+  margin-top:.25em;
    -+  margin-bottom:0;
    -+  }
    -+.hiddenlink {
    -+  font-size:96%;
    -+  line-height:.8em;
    -+  text-decoration:none;}
    -+a {
    -+  text-decoration:none;}
    -+a:hover {
    -+  text-decoration:underline;}
    -+.indexBox {
    -+  border: 1px solid red;
    -+  margin:1em 0 0 0;}
    -+.letterIndexHead {
    -+  font-size: 1.5em;font-weight:9;
    -+  margin:0 0 0em 0;
    -+  border: 1px solid red;}
    -diff --git a/docs/html/sdk/support_api_diff/24.2.0/user_comments_for_24.1.0_to_24.2.0.xml b/docs/html/sdk/support_api_diff/24.2.0/user_comments_for_24.1.0_to_24.2.0.xml
    -new file mode 100644
    -index 0000000..5a1bfc6
    ---- /dev/null
    -+++ b/docs/html/sdk/support_api_diff/24.2.0/user_comments_for_24.1.0_to_24.2.0.xml
    -@@ -0,0 +1,1897 @@
    -+<?xml version="1.0" encoding="iso-8859-1" standalone="no"?>
    -+<comments
    -+  xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance'
    -+  xsi:noNamespaceSchemaLocation='comments.xsd'
    -+  name="24.1.0_to_24.2.0"
    -+  jdversion="1.1.0">
    -+
    -+<!-- Use this file to enter an API change description. For example, when you remove a class, 
    -+     you can enter a comment for that class that points developers to the replacement class. 
    -+     You can also provide a change summary for modified API, to give an overview of the changes 
    -+     why they were made, workarounds, etc.  -->
    -+
    -+<!-- When the API diffs report is generated, the comments in this file get added to the tables of 
    -+     removed, added, and modified packages, classes, methods, and fields. This file does not ship 
    -+     with the final report. -->
    -+
    -+<!-- The id attribute in an identifier element identifies the change as noted in the report. 
    -+     An id has the form package[.class[.[ctor|method|field].signature]], where [] indicates optional 
    -+     text. A comment element can have multiple identifier elements, which will will cause the same 
    -+     text to appear at each place in the report, but will be converted to separate comments when the 
    -+     comments file is used. -->
    -+
    -+<!-- HTML tags in the text field will appear in the report. You also need to close p HTML elements, 
    -+     used for paragraphs - see the top-level documentation. -->
    -+
    -+<!-- You can include standard javadoc links in your change descriptions. You can use the @first command  
    -+     to cause jdiff to include the first line of the API documentation. You also need to close p HTML 
    -+     elements, used for paragraphs - see the top-level documentation. -->
    -+
    -+<comment>
    -+  <identifier id="android.support.customtabs"/>
    -+  <text>
    -+    InsertCommentsHere
    -+  </text>
    -+</comment>
    -+<comment>
    -+  <identifier id="android.support.customtabs.CustomTabsIntent"/>
    -+  <text>
    -+    InsertCommentsHere
    -+  </text>
    -+</comment>
    -+<comment>
    -+  <identifier id="android.support.customtabs.CustomTabsIntent.Builder"/>
    -+  <text>
    -+    InsertCommentsHere
    -+  </text>
    -+</comment>
    -+<comment>
    -+  <identifier id="android.support.customtabs.CustomTabsIntent.Builder.setInstantAppsEnabled_added(boolean)"/>
    -+  <text>
    -+    InsertCommentsHere
    -+  </text>
    -+</comment>
    -+<comment>
    -+  <identifier id="android.support.customtabs.CustomTabsIntent.EXTRA_ENABLE_INSTANT_APPS"/>
    -+  <text>
    -+    InsertCommentsHere
    -+  </text>
    -+</comment>
    -+<comment>
    -+  <identifier id="android.support.customtabs.CustomTabsIntent.setAlwaysUseBrowserUI_added(android.content.Intent)"/>
    -+  <text>
    -+    InsertCommentsHere
    -+  </text>
    -+</comment>
    -+<comment>
    -+  <identifier id="android.support.customtabs.CustomTabsIntent.shouldAlwaysUseBrowserUI_added(android.content.Intent)"/>
    -+  <text>
    -+    InsertCommentsHere
    -+  </text>
    -+</comment>
    -+<comment>
    -+  <identifier id="android.support.customtabs.CustomTabsSession"/>
    -+  <text>
    -+    InsertCommentsHere
    -+  </text>
    -+</comment>
    -+<comment>
    -+  <identifier id="android.support.customtabs.CustomTabsSession.setSecondaryToolbarViews_added(android.widget.RemoteViews, int[], android.app.PendingIntent)"/>
    -+  <text>
    -+    InsertCommentsHere
    -+  </text>
    -+</comment>
    -+<comment>
    -+  <identifier id="android.support.customtabs.CustomTabsSession.setToolbarItem_changed(int, android.graphics.Bitmap, java.lang.String)"/>
    -+  <text>
    -+    InsertCommentsHere
    -+  </text>
    -+</comment>
    -+<comment>
    -+  <identifier id="android.support.design.widget"/>
    -+  <text>
    -+    InsertCommentsHere
    -+  </text>
    -+</comment>
    -+<comment>
    -+  <identifier id="android.support.design.widget.AppBarLayout.ScrollingViewBehavior"/>
    -+  <text>
    -+    InsertCommentsHere
    -+  </text>
    -+</comment>
    -+<comment>
    -+  <identifier id="android.support.design.widget.AppBarLayout.ScrollingViewBehavior.onRequestChildRectangleOnScreen_added(android.support.design.widget.CoordinatorLayout, android.view.View, android.graphics.Rect, boolean)"/>
    -+  <text>
    -+    InsertCommentsHere
    -+  </text>
    -+</comment>
    -+<comment>
    -+  <identifier id="android.support.design.widget.BottomSheetBehavior"/>
    -+  <text>
    -+    InsertCommentsHere
    -+  </text>
    -+</comment>
    -+<comment>
    -+  <identifier id="android.support.design.widget.BottomSheetBehavior.PEEK_HEIGHT_AUTO"/>
    -+  <text>
    -+    InsertCommentsHere
    -+  </text>
    -+</comment>
    -+<comment>
    -+  <identifier id="android.support.design.widget.CollapsingToolbarLayout"/>
    -+  <text>
    -+    InsertCommentsHere
    -+  </text>
    -+</comment>
    -+<comment>
    -+  <identifier id="android.support.design.widget.CollapsingToolbarLayout.setCollapsedTitleTextColor_added(android.content.res.ColorStateList)"/>
    -+  <text>
    -+    InsertCommentsHere
    -+  </text>
    -+</comment>
    -+<comment>
    -+  <identifier id="android.support.design.widget.CollapsingToolbarLayout.setExpandedTitleTextColor_added(android.content.res.ColorStateList)"/>
    -+  <text>
    -+    InsertCommentsHere
    -+  </text>
    -+</comment>
    -+<comment>
    -+  <identifier id="android.support.design.widget.CoordinatorLayout"/>
    -+  <text>
    -+    InsertCommentsHere
    -+  </text>
    -+</comment>
    -+<comment>
    -+  <identifier id="android.support.design.widget.CoordinatorLayout.Behavior"/>
    -+  <text>
    -+    InsertCommentsHere
    -+  </text>
    -+</comment>
    -+<comment>
    -+  <identifier id="android.support.design.widget.CoordinatorLayout.Behavior.getInsetDodgeRect_added(android.support.design.widget.CoordinatorLayout, V, android.graphics.Rect)"/>
    -+  <text>
    -+    InsertCommentsHere
    -+  </text>
    -+</comment>
    -+<comment>
    -+  <identifier id="android.support.design.widget.CoordinatorLayout.Behavior.isDirty_changed(android.support.design.widget.CoordinatorLayout, V)"/>
    -+  <text>
    -+    InsertCommentsHere
    -+  </text>
    -+</comment>
    -+<comment>
    -+  <identifier id="android.support.design.widget.CoordinatorLayout.Behavior.onAttachedToLayoutParams_added(android.support.design.widget.CoordinatorLayout.LayoutParams)"/>
    -+  <text>
    -+    InsertCommentsHere
    -+  </text>
    -+</comment>
    -+<comment>
    -+  <identifier id="android.support.design.widget.CoordinatorLayout.Behavior.onDetachedFromLayoutParams_added()"/>
    -+  <text>
    -+    InsertCommentsHere
    -+  </text>
    -+</comment>
    -+<comment>
    -+  <identifier id="android.support.design.widget.CoordinatorLayout.Behavior.onRequestChildRectangleOnScreen_added(android.support.design.widget.CoordinatorLayout, V, android.graphics.Rect, boolean)"/>
    -+  <text>
    -+    InsertCommentsHere
    -+  </text>
    -+</comment>
    -+<comment>
    -+  <identifier id="android.support.design.widget.CoordinatorLayout.LayoutParams"/>
    -+  <text>
    -+    InsertCommentsHere
    -+  </text>
    -+</comment>
    -+<comment>
    -+  <identifier id="android.support.design.widget.CoordinatorLayout.LayoutParams.dodgeInsetEdges"/>
    -+  <text>
    -+    InsertCommentsHere
    -+  </text>
    -+</comment>
    -+<comment>
    -+  <identifier id="android.support.design.widget.CoordinatorLayout.LayoutParams.insetEdge"/>
    -+  <text>
    -+    InsertCommentsHere
    -+  </text>
    -+</comment>
    -+<comment>
    -+  <identifier id="android.support.design.widget.CoordinatorLayout.getDependents_added(android.view.View)"/>
    -+  <text>
    -+    InsertCommentsHere
    -+  </text>
    -+</comment>
    -+<comment>
    -+  <identifier id="android.support.design.widget.FloatingActionButton.Behavior"/>
    -+  <text>
    -+    InsertCommentsHere
    -+  </text>
    -+</comment>
    -+<comment>
    -+  <identifier id="android.support.design.widget.FloatingActionButton.Behavior.getInsetDodgeRect_added(android.support.design.widget.CoordinatorLayout, android.support.design.widget.FloatingActionButton, android.graphics.Rect)"/>
    -+  <text>
    -+    InsertCommentsHere
    -+  </text>
    -+</comment>
    -+<comment>
    -+  <identifier id="android.support.design.widget.FloatingActionButton.Behavior.isAutoHideEnabled_added()"/>
    -+  <text>
    -+    InsertCommentsHere
    -+  </text>
    -+</comment>
    -+<comment>
    -+  <identifier id="android.support.design.widget.FloatingActionButton.Behavior.layoutDependsOn_removed(android.support.design.widget.CoordinatorLayout, android.support.design.widget.FloatingActionButton, android.view.View)"/>
    -+  <text>
    -+    InsertCommentsHere
    -+  </text>
    -+</comment>
    -+<comment>
    -+  <identifier id="android.support.design.widget.FloatingActionButton.Behavior.onDependentViewRemoved_removed(android.support.design.widget.CoordinatorLayout, android.support.design.widget.FloatingActionButton, android.view.View)"/>
    -+  <text>
    -+    InsertCommentsHere
    -+  </text>
    -+</comment>
    -+<comment>
    -+  <identifier id="android.support.design.widget.FloatingActionButton.Behavior.setAutoHideEnabled_added(boolean)"/>
    -+  <text>
    -+    InsertCommentsHere
    -+  </text>
    -+</comment>
    -+<comment>
    -+  <identifier id="android.support.design.widget.TabLayout"/>
    -+  <text>
    -+    InsertCommentsHere
    -+  </text>
    -+</comment>
    -+<comment>
    -+  <identifier id="android.support.design.widget.TabLayout.clearOnTabSelectedListeners_added()"/>
    -+  <text>
    -+    InsertCommentsHere
    -+  </text>
    -+</comment>
    -+<comment>
    -+  <identifier id="android.support.design.widget.TextInputLayout"/>
    -+  <text>
    -+    InsertCommentsHere
    -+  </text>
    -+</comment>
    -+<comment>
    -+  <identifier id="android.support.design.widget.TextInputLayout.getPasswordVisibilityToggleContentDescription_added()"/>
    -+  <text>
    -+    InsertCommentsHere
    -+  </text>
    -+</comment>
    -+<comment>
    -+  <identifier id="android.support.design.widget.TextInputLayout.getPasswordVisibilityToggleDrawable_added()"/>
    -+  <text>
    -+    InsertCommentsHere
    -+  </text>
    -+</comment>
    -+<comment>
    -+  <identifier id="android.support.design.widget.TextInputLayout.isPasswordVisibilityToggleEnabled_added()"/>
    -+  <text>
    -+    InsertCommentsHere
    -+  </text>
    -+</comment>
    -+<comment>
    -+  <identifier id="android.support.design.widget.TextInputLayout.setPasswordVisibilityToggleContentDescription_added(int)"/>
    -+  <text>
    -+    InsertCommentsHere
    -+  </text>
    -+</comment>
    -+<comment>
    -+  <identifier id="android.support.design.widget.TextInputLayout.setPasswordVisibilityToggleContentDescription_added(java.lang.CharSequence)"/>
    -+  <text>
    -+    InsertCommentsHere
    -+  </text>
    -+</comment>
    -+<comment>
    -+  <identifier id="android.support.design.widget.TextInputLayout.setPasswordVisibilityToggleDrawable_added(android.graphics.drawable.Drawable)"/>
    -+  <text>
    -+    InsertCommentsHere
    -+  </text>
    -+</comment>
    -+<comment>
    -+  <identifier id="android.support.design.widget.TextInputLayout.setPasswordVisibilityToggleDrawable_added(int)"/>
    -+  <text>
    -+    InsertCommentsHere
    -+  </text>
    -+</comment>
    -+<comment>
    -+  <identifier id="android.support.design.widget.TextInputLayout.setPasswordVisibilityToggleEnabled_added(boolean)"/>
    -+  <text>
    -+    InsertCommentsHere
    -+  </text>
    -+</comment>
    -+<comment>
    -+  <identifier id="android.support.design.widget.TextInputLayout.setPasswordVisibilityToggleTintList_added(android.content.res.ColorStateList)"/>
    -+  <text>
    -+    InsertCommentsHere
    -+  </text>
    -+</comment>
    -+<comment>
    -+  <identifier id="android.support.design.widget.TextInputLayout.setPasswordVisibilityToggleTintMode_added(android.graphics.PorterDuff.Mode)"/>
    -+  <text>
    -+    InsertCommentsHere
    -+  </text>
    -+</comment>
    -+<comment>
    -+  <identifier id="android.support.transition"/>
    -+  <text>
    -+    InsertCommentsHere
    -+  </text>
    -+</comment>
    -+<comment>
    -+  <identifier id="android.support.v14.preference"/>
    -+  <text>
    -+    InsertCommentsHere
    -+  </text>
    -+</comment>
    -+<comment>
    -+  <identifier id="android.support.v14.preference.PreferenceFragment"/>
    -+  <text>
    -+    InsertCommentsHere
    -+  </text>
    -+</comment>
    -+<comment>
    -+  <identifier id="android.support.v17.leanback.widget"/>
    -+  <text>
    -+    InsertCommentsHere
    -+  </text>
    -+</comment>
    -+<comment>
    -+  <identifier id="android.support.v17.leanback.widget.AbstractMediaItemPresenter"/>
    -+  <text>
    -+    InsertCommentsHere
    -+  </text>
    -+</comment>
    -+<comment>
    -+  <identifier id="android.support.v17.leanback.widget.AbstractMediaItemPresenter.PLAY_STATE_INITIAL"/>
    -+  <text>
    -+    InsertCommentsHere
    -+  </text>
    -+</comment>
    -+<comment>
    -+  <identifier id="android.support.v17.leanback.widget.AbstractMediaItemPresenter.PLAY_STATE_PAUSED"/>
    -+  <text>
    -+    InsertCommentsHere
    -+  </text>
    -+</comment>
    -+<comment>
    -+  <identifier id="android.support.v17.leanback.widget.AbstractMediaItemPresenter.PLAY_STATE_PLAYING"/>
    -+  <text>
    -+    InsertCommentsHere
    -+  </text>
    -+</comment>
    -+<comment>
    -+  <identifier id="android.support.v17.leanback.widget.AbstractMediaItemPresenter.ViewHolder"/>
    -+  <text>
    -+    InsertCommentsHere
    -+  </text>
    -+</comment>
    -+<comment>
    -+  <identifier id="android.support.v17.leanback.widget.AbstractMediaItemPresenter.ViewHolder.getMediaItemNumberViewFlipper_added()"/>
    -+  <text>
    -+    InsertCommentsHere
    -+  </text>
    -+</comment>
    -+<comment>
    -+  <identifier id="android.support.v17.leanback.widget.AbstractMediaItemPresenter.ViewHolder.getMediaItemPausedView_added()"/>
    -+  <text>
    -+    InsertCommentsHere
    -+  </text>
    -+</comment>
    -+<comment>
    -+  <identifier id="android.support.v17.leanback.widget.AbstractMediaItemPresenter.ViewHolder.getMediaItemPlayingView_added()"/>
    -+  <text>
    -+    InsertCommentsHere
    -+  </text>
    -+</comment>
    -+<comment>
    -+  <identifier id="android.support.v17.leanback.widget.AbstractMediaItemPresenter.ViewHolder.notifyPlayStateChanged_added()"/>
    -+  <text>
    -+    InsertCommentsHere
    -+  </text>
    -+</comment>
    -+<comment>
    -+  <identifier id="android.support.v17.leanback.widget.AbstractMediaItemPresenter.ViewHolder.setSelectedMediaItemNumberView_added(int)"/>
    -+  <text>
    -+    InsertCommentsHere
    -+  </text>
    -+</comment>
    -+<comment>
    -+  <identifier id="android.support.v17.leanback.widget.AbstractMediaItemPresenter.getMediaPlayState_added(java.lang.Object)"/>
    -+  <text>
    -+    InsertCommentsHere
    -+  </text>
    -+</comment>
    -+<comment>
    -+  <identifier id="android.support.v17.leanback.widget.AbstractMediaItemPresenter.onBindMediaPlayState_added(android.support.v17.leanback.widget.AbstractMediaItemPresenter.ViewHolder)"/>
    -+  <text>
    -+    InsertCommentsHere
    -+  </text>
    -+</comment>
    -+<comment>
    -+  <identifier id="android.support.v17.leanback.widget.AbstractMediaItemPresenter.onUnbindMediaPlayState_added(android.support.v17.leanback.widget.AbstractMediaItemPresenter.ViewHolder)"/>
    -+  <text>
    -+    InsertCommentsHere
    -+  </text>
    -+</comment>
    -+<comment>
    -+  <identifier id="android.support.v17.leanback.widget.ObjectAdapter"/>
    -+  <text>
    -+    InsertCommentsHere
    -+  </text>
    -+</comment>
    -+<comment>
    -+  <identifier id="android.support.v17.leanback.widget.ObjectAdapter.isImmediateNotifySupported_added()"/>
    -+  <text>
    -+    InsertCommentsHere
    -+  </text>
    -+</comment>
    -+<comment>
    -+  <identifier id="android.support.v17.preference"/>
    -+  <text>
    -+    InsertCommentsHere
    -+  </text>
    -+</comment>
    -+<comment>
    -+  <identifier id="android.support.v17.preference.LeanbackSettingsFragment"/>
    -+  <text>
    -+    InsertCommentsHere
    -+  </text>
    -+</comment>
    -+<comment>
    -+  <identifier id="android.support.v4.accessibilityservice"/>
    -+  <text>
    -+    InsertCommentsHere
    -+  </text>
    -+</comment>
    -+<comment>
    -+  <identifier id="android.support.v4.accessibilityservice.AccessibilityServiceInfoCompat"/>
    -+  <text>
    -+    InsertCommentsHere
    -+  </text>
    -+</comment>
    -+<comment>
    -+  <identifier id="android.support.v4.accessibilityservice.AccessibilityServiceInfoCompat.getDescription_changed(android.accessibilityservice.AccessibilityServiceInfo)"/>
    -+  <text>
    -+    InsertCommentsHere
    -+  </text>
    -+</comment>
    -+<comment>
    -+  <identifier id="android.support.v4.accessibilityservice.AccessibilityServiceInfoCompat.loadDescription_added(android.accessibilityservice.AccessibilityServiceInfo, android.content.pm.PackageManager)"/>
    -+  <text>
    -+    InsertCommentsHere
    -+  </text>
    -+</comment>
    -+<comment>
    -+  <identifier id="android.support.v4.app"/>
    -+  <text>
    -+    InsertCommentsHere
    -+  </text>
    -+</comment>
    -+<comment>
    -+  <identifier id="android.support.v4.app.ActivityCompat"/>
    -+  <text>
    -+    InsertCommentsHere
    -+  </text>
    -+</comment>
    -+<comment>
    -+  <identifier id="android.support.v4.app.ActivityCompat.ctor_changed()"/>
    -+  <text>
    -+    InsertCommentsHere
    -+  </text>
    -+</comment>
    -+<comment>
    -+  <identifier id="android.support.v4.app.ActivityCompat.getReferrer_changed(android.app.Activity)"/>
    -+  <text>
    -+    InsertCommentsHere
    -+  </text>
    -+</comment>
    -+<comment>
    -+  <identifier id="android.support.v4.app.ActivityOptionsCompat"/>
    -+  <text>
    -+    InsertCommentsHere
    -+  </text>
    -+</comment>
    -+<comment>
    -+  <identifier id="android.support.v4.app.ActivityOptionsCompat.EXTRA_USAGE_TIME_REPORT"/>
    -+  <text>
    -+    InsertCommentsHere
    -+  </text>
    -+</comment>
    -+<comment>
    -+  <identifier id="android.support.v4.app.ActivityOptionsCompat.EXTRA_USAGE_TIME_REPORT_PACKAGES"/>
    -+  <text>
    -+    InsertCommentsHere
    -+  </text>
    -+</comment>
    -+<comment>
    -+  <identifier id="android.support.v4.app.ActivityOptionsCompat.getLaunchBounds_added()"/>
    -+  <text>
    -+    InsertCommentsHere
    -+  </text>
    -+</comment>
    -+<comment>
    -+  <identifier id="android.support.v4.app.ActivityOptionsCompat.makeBasic_added()"/>
    -+  <text>
    -+    InsertCommentsHere
    -+  </text>
    -+</comment>
    -+<comment>
    -+  <identifier id="android.support.v4.app.ActivityOptionsCompat.makeClipRevealAnimation_added(android.view.View, int, int, int, int)"/>
    -+  <text>
    -+    InsertCommentsHere
    -+  </text>
    -+</comment>
    -+<comment>
    -+  <identifier id="android.support.v4.app.ActivityOptionsCompat.makeTaskLaunchBehind_added()"/>
    -+  <text>
    -+    InsertCommentsHere
    -+  </text>
    -+</comment>
    -+<comment>
    -+  <identifier id="android.support.v4.app.ActivityOptionsCompat.requestUsageTimeReport_added(android.app.PendingIntent)"/>
    -+  <text>
    -+    InsertCommentsHere
    -+  </text>
    -+</comment>
    -+<comment>
    -+  <identifier id="android.support.v4.app.ActivityOptionsCompat.setLaunchBounds_added(android.graphics.Rect)"/>
    -+  <text>
    -+    InsertCommentsHere
    -+  </text>
    -+</comment>
    -+<comment>
    -+  <identifier id="android.support.v4.app.FragmentController"/>
    -+  <text>
    -+    InsertCommentsHere
    -+  </text>
    -+</comment>
    -+<comment>
    -+  <identifier id="android.support.v4.app.FragmentController.findFragmentByWho_added(java.lang.String)"/>
    -+  <text>
    -+    InsertCommentsHere
    -+  </text>
    -+</comment>
    -+<comment>
    -+  <identifier id="android.support.v4.app.ServiceCompat"/>
    -+  <text>
    -+    InsertCommentsHere
    -+  </text>
    -+</comment>
    -+<comment>
    -+  <identifier id="android.support.v4.app.ServiceCompat.STOP_FOREGROUND_DETACH"/>
    -+  <text>
    -+    InsertCommentsHere
    -+  </text>
    -+</comment>
    -+<comment>
    -+  <identifier id="android.support.v4.app.ServiceCompat.STOP_FOREGROUND_REMOVE"/>
    -+  <text>
    -+    InsertCommentsHere
    -+  </text>
    -+</comment>
    -+<comment>
    -+  <identifier id="android.support.v4.app.ServiceCompat.stopForeground_added(android.app.Service, int)"/>
    -+  <text>
    -+    InsertCommentsHere
    -+  </text>
    -+</comment>
    -+<comment>
    -+  <identifier id="android.support.v4.app.SharedElementCallback"/>
    -+  <text>
    -+    InsertCommentsHere
    -+  </text>
    -+</comment>
    -+<comment>
    -+  <identifier id="android.support.v4.app.SharedElementCallback.OnSharedElementsReadyListener"/>
    -+  <text>
    -+    InsertCommentsHere
    -+  </text>
    -+</comment>
    -+<comment>
    -+  <identifier id="android.support.v4.app.SharedElementCallback.onSharedElementsArrived_added(java.util.List&lt;java.lang.String&gt;, java.util.List&lt;android.view.View&gt;, android.support.v4.app.SharedElementCallback.OnSharedElementsReadyListener)"/>
    -+  <text>
    -+    InsertCommentsHere
    -+  </text>
    -+</comment>
    -+<comment>
    -+  <identifier id="android.support.v4.content"/>
    -+  <text>
    -+    InsertCommentsHere
    -+  </text>
    -+</comment>
    -+<comment>
    -+  <identifier id="android.support.v4.content.ContextCompat"/>
    -+  <text>
    -+    InsertCommentsHere
    -+  </text>
    -+</comment>
    -+<comment>
    -+  <identifier id="android.support.v4.content.ContextCompat.ctor_changed()"/>
    -+  <text>
    -+    InsertCommentsHere
    -+  </text>
    -+</comment>
    -+<comment>
    -+  <identifier id="android.support.v4.graphics.drawable"/>
    -+  <text>
    -+    InsertCommentsHere
    -+  </text>
    -+</comment>
    -+<comment>
    -+  <identifier id="android.support.v4.graphics.drawable.DrawableCompat"/>
    -+  <text>
    -+    InsertCommentsHere
    -+  </text>
    -+</comment>
    -+<comment>
    -+  <identifier id="android.support.v4.graphics.drawable.DrawableCompat.clearColorFilter_added(android.graphics.drawable.Drawable)"/>
    -+  <text>
    -+    InsertCommentsHere
    -+  </text>
    -+</comment>
    -+<comment>
    -+  <identifier id="android.support.v4.media"/>
    -+  <text>
    -+    InsertCommentsHere
    -+  </text>
    -+</comment>
    -+<comment>
    -+  <identifier id="android.support.v4.media.MediaBrowserCompat.MediaItem"/>
    -+  <text>
    -+    InsertCommentsHere
    -+  </text>
    -+</comment>
    -+<comment>
    -+  <identifier id="android.support.v4.media.MediaBrowserCompat.MediaItem.fromMediaItemList_added(java.util.List&lt;?&gt;)"/>
    -+  <text>
    -+    InsertCommentsHere
    -+  </text>
    -+</comment>
    -+<comment>
    -+  <identifier id="android.support.v4.media.MediaBrowserCompat.MediaItem.fromMediaItem_added(java.lang.Object)"/>
    -+  <text>
    -+    InsertCommentsHere
    -+  </text>
    -+</comment>
    -+<comment>
    -+  <identifier id="android.support.v4.media.MediaBrowserServiceCompat.BrowserRoot"/>
    -+  <text>
    -+    InsertCommentsHere
    -+  </text>
    -+</comment>
    -+<comment>
    -+  <identifier id="android.support.v4.media.MediaBrowserServiceCompat.BrowserRoot.EXTRA_SUGGESTION_KEYWORDS"/>
    -+  <text>
    -+    InsertCommentsHere
    -+  </text>
    -+</comment>
    -+<comment>
    -+  <identifier id="android.support.v4.media.MediaDescriptionCompat"/>
    -+  <text>
    -+    InsertCommentsHere
    -+  </text>
    -+</comment>
    -+<comment>
    -+  <identifier id="android.support.v4.media.MediaDescriptionCompat.BT_FOLDER_TYPE_ALBUMS"/>
    -+  <text>
    -+    InsertCommentsHere
    -+  </text>
    -+</comment>
    -+<comment>
    -+  <identifier id="android.support.v4.media.MediaDescriptionCompat.BT_FOLDER_TYPE_ARTISTS"/>
    -+  <text>
    -+    InsertCommentsHere
    -+  </text>
    -+</comment>
    -+<comment>
    -+  <identifier id="android.support.v4.media.MediaDescriptionCompat.BT_FOLDER_TYPE_GENRES"/>
    -+  <text>
    -+    InsertCommentsHere
    -+  </text>
    -+</comment>
    -+<comment>
    -+  <identifier id="android.support.v4.media.MediaDescriptionCompat.BT_FOLDER_TYPE_MIXED"/>
    -+  <text>
    -+    InsertCommentsHere
    -+  </text>
    -+</comment>
    -+<comment>
    -+  <identifier id="android.support.v4.media.MediaDescriptionCompat.BT_FOLDER_TYPE_PLAYLISTS"/>
    -+  <text>
    -+    InsertCommentsHere
    -+  </text>
    -+</comment>
    -+<comment>
    -+  <identifier id="android.support.v4.media.MediaDescriptionCompat.BT_FOLDER_TYPE_TITLES"/>
    -+  <text>
    -+    InsertCommentsHere
    -+  </text>
    -+</comment>
    -+<comment>
    -+  <identifier id="android.support.v4.media.MediaDescriptionCompat.BT_FOLDER_TYPE_YEARS"/>
    -+  <text>
    -+    InsertCommentsHere
    -+  </text>
    -+</comment>
    -+<comment>
    -+  <identifier id="android.support.v4.media.MediaDescriptionCompat.EXTRA_BT_FOLDER_TYPE"/>
    -+  <text>
    -+    InsertCommentsHere
    -+  </text>
    -+</comment>
    -+<comment>
    -+  <identifier id="android.support.v4.media.MediaMetadataCompat"/>
    -+  <text>
    -+    InsertCommentsHere
    -+  </text>
    -+</comment>
    -+<comment>
    -+  <identifier id="android.support.v4.media.MediaMetadataCompat.METADATA_KEY_BT_FOLDER_TYPE"/>
    -+  <text>
    -+    InsertCommentsHere
    -+  </text>
    -+</comment>
    -+<comment>
    -+  <identifier id="android.support.v4.media.MediaMetadataCompat.METADATA_KEY_MEDIA_URI"/>
    -+  <text>
    -+    InsertCommentsHere
    -+  </text>
    -+</comment>
    -+<comment>
    -+  <identifier id="android.support.v4.media.session"/>
    -+  <text>
    -+    InsertCommentsHere
    -+  </text>
    -+</comment>
    -+<comment>
    -+  <identifier id="android.support.v4.media.session.MediaButtonReceiver"/>
    -+  <text>
    -+    InsertCommentsHere
    -+  </text>
    -+</comment>
    -+<comment>
    -+  <identifier id="android.support.v4.media.session.MediaButtonReceiver.buildMediaButtonPendingIntent_added(android.content.Context, android.content.ComponentName, long)"/>
    -+  <text>
    -+    InsertCommentsHere
    -+  </text>
    -+</comment>
    -+<comment>
    -+  <identifier id="android.support.v4.media.session.MediaButtonReceiver.buildMediaButtonPendingIntent_added(android.content.Context, long)"/>
    -+  <text>
    -+    InsertCommentsHere
    -+  </text>
    -+</comment>
    -+<comment>
    -+  <identifier id="android.support.v4.media.session.MediaSessionCompat"/>
    -+  <text>
    -+    InsertCommentsHere
    -+  </text>
    -+</comment>
    -+<comment>
    -+  <identifier id="android.support.v4.media.session.MediaSessionCompat.QueueItem"/>
    -+  <text>
    -+    InsertCommentsHere
    -+  </text>
    -+</comment>
    -+<comment>
    -+  <identifier id="android.support.v4.media.session.MediaSessionCompat.QueueItem.fromQueueItemList_added(java.util.List&lt;?&gt;)"/>
    -+  <text>
    -+    InsertCommentsHere
    -+  </text>
    -+</comment>
    -+<comment>
    -+  <identifier id="android.support.v4.media.session.MediaSessionCompat.QueueItem.fromQueueItem_added(java.lang.Object)"/>
    -+  <text>
    -+    InsertCommentsHere
    -+  </text>
    -+</comment>
    -+<comment>
    -+  <identifier id="android.support.v4.media.session.MediaSessionCompat.QueueItem.obtain_changed(java.lang.Object)"/>
    -+  <text>
    -+    InsertCommentsHere
    -+  </text>
    -+</comment>
    -+<comment>
    -+  <identifier id="android.support.v4.media.session.MediaSessionCompat.fromMediaSession_added(android.content.Context, java.lang.Object)"/>
    -+  <text>
    -+    InsertCommentsHere
    -+  </text>
    -+</comment>
    -+<comment>
    -+  <identifier id="android.support.v4.media.session.MediaSessionCompat.obtain_changed(android.content.Context, java.lang.Object)"/>
    -+  <text>
    -+    InsertCommentsHere
    -+  </text>
    -+</comment>
    -+<comment>
    -+  <identifier id="android.support.v4.media.session.PlaybackStateCompat"/>
    -+  <text>
    -+    InsertCommentsHere
    -+  </text>
    -+</comment>
    -+<comment>
    -+  <identifier id="android.support.v4.media.session.PlaybackStateCompat.toKeyCode_added(long)"/>
    -+  <text>
    -+    InsertCommentsHere
    -+  </text>
    -+</comment>
    -+<comment>
    -+  <identifier id="android.support.v4.os"/>
    -+  <text>
    -+    InsertCommentsHere
    -+  </text>
    -+</comment>
    -+<comment>
    -+  <identifier id="android.support.v4.os.BuildCompat"/>
    -+  <text>
    -+    InsertCommentsHere
    -+  </text>
    -+</comment>
    -+<comment>
    -+  <identifier id="android.support.v4.os.BuildCompat.isAtLeastNMR1_added()"/>
    -+  <text>
    -+    InsertCommentsHere
    -+  </text>
    -+</comment>
    -+<comment>
    -+  <identifier id="android.support.v4.text.util"/>
    -+  <text>
    -+    InsertCommentsHere
    -+  </text>
    -+</comment>
    -+<comment>
    -+  <identifier id="android.support.v4.util"/>
    -+  <text>
    -+    InsertCommentsHere
    -+  </text>
    -+</comment>
    -+<comment>
    -+  <identifier id="android.support.v4.util.PatternsCompat"/>
    -+  <text>
    -+    InsertCommentsHere
    -+  </text>
    -+</comment>
    -+<comment>
    -+  <identifier id="android.support.v4.view"/>
    -+  <text>
    -+    InsertCommentsHere
    -+  </text>
    -+</comment>
    -+<comment>
    -+  <identifier id="android.support.v4.view.KeyEventCompat"/>
    -+  <text>
    -+    InsertCommentsHere
    -+  </text>
    -+</comment>
    -+<comment>
    -+  <identifier id="android.support.v4.view.KeyEventCompat.dispatch_changed(android.view.KeyEvent, android.view.KeyEvent.Callback, java.lang.Object, java.lang.Object)"/>
    -+  <text>
    -+    InsertCommentsHere
    -+  </text>
    -+</comment>
    -+<comment>
    -+  <identifier id="android.support.v4.view.KeyEventCompat.getKeyDispatcherState_changed(android.view.View)"/>
    -+  <text>
    -+    InsertCommentsHere
    -+  </text>
    -+</comment>
    -+<comment>
    -+  <identifier id="android.support.v4.view.KeyEventCompat.isTracking_changed(android.view.KeyEvent)"/>
    -+  <text>
    -+    InsertCommentsHere
    -+  </text>
    -+</comment>
    -+<comment>
    -+  <identifier id="android.support.v4.view.KeyEventCompat.startTracking_changed(android.view.KeyEvent)"/>
    -+  <text>
    -+    InsertCommentsHere
    -+  </text>
    -+</comment>
    -+<comment>
    -+  <identifier id="android.support.v4.view.MotionEventCompat"/>
    -+  <text>
    -+    InsertCommentsHere
    -+  </text>
    -+</comment>
    -+<comment>
    -+  <identifier id="android.support.v4.view.MotionEventCompat.findPointerIndex_changed(android.view.MotionEvent, int)"/>
    -+  <text>
    -+    InsertCommentsHere
    -+  </text>
    -+</comment>
    -+<comment>
    -+  <identifier id="android.support.v4.view.MotionEventCompat.getPointerCount_changed(android.view.MotionEvent)"/>
    -+  <text>
    -+    InsertCommentsHere
    -+  </text>
    -+</comment>
    -+<comment>
    -+  <identifier id="android.support.v4.view.MotionEventCompat.getPointerId_changed(android.view.MotionEvent, int)"/>
    -+  <text>
    -+    InsertCommentsHere
    -+  </text>
    -+</comment>
    -+<comment>
    -+  <identifier id="android.support.v4.view.MotionEventCompat.getSource_changed(android.view.MotionEvent)"/>
    -+  <text>
    -+    InsertCommentsHere
    -+  </text>
    -+</comment>
    -+<comment>
    -+  <identifier id="android.support.v4.view.MotionEventCompat.getX_changed(android.view.MotionEvent, int)"/>
    -+  <text>
    -+    InsertCommentsHere
    -+  </text>
    -+</comment>
    -+<comment>
    -+  <identifier id="android.support.v4.view.MotionEventCompat.getY_changed(android.view.MotionEvent, int)"/>
    -+  <text>
    -+    InsertCommentsHere
    -+  </text>
    -+</comment>
    -+<comment>
    -+  <identifier id="android.support.v4.view.ViewCompat"/>
    -+  <text>
    -+    InsertCommentsHere
    -+  </text>
    -+</comment>
    -+<comment>
    -+  <identifier id="android.support.v4.view.ViewCompat.OVER_SCROLL_ALWAYS"/>
    -+  <text>
    -+    InsertCommentsHere
    -+  </text>
    -+</comment>
    -+<comment>
    -+  <identifier id="android.support.v4.view.ViewCompat.OVER_SCROLL_IF_CONTENT_SCROLLS"/>
    -+  <text>
    -+    InsertCommentsHere
    -+  </text>
    -+</comment>
    -+<comment>
    -+  <identifier id="android.support.v4.view.ViewCompat.OVER_SCROLL_NEVER"/>
    -+  <text>
    -+    InsertCommentsHere
    -+  </text>
    -+</comment>
    -+<comment>
    -+  <identifier id="android.support.v4.view.ViewCompat.getOverScrollMode_changed(android.view.View)"/>
    -+  <text>
    -+    InsertCommentsHere
    -+  </text>
    -+</comment>
    -+<comment>
    -+  <identifier id="android.support.v4.view.ViewCompat.isImportantForAccessibility_added(android.view.View)"/>
    -+  <text>
    -+    InsertCommentsHere
    -+  </text>
    -+</comment>
    -+<comment>
    -+  <identifier id="android.support.v4.view.ViewCompat.isOpaque_changed(android.view.View)"/>
    -+  <text>
    -+    InsertCommentsHere
    -+  </text>
    -+</comment>
    -+<comment>
    -+  <identifier id="android.support.v4.view.ViewCompat.setOverScrollMode_changed(android.view.View, int)"/>
    -+  <text>
    -+    InsertCommentsHere
    -+  </text>
    -+</comment>
    -+<comment>
    -+  <identifier id="android.support.v4.view.ViewConfigurationCompat"/>
    -+  <text>
    -+    InsertCommentsHere
    -+  </text>
    -+</comment>
    -+<comment>
    -+  <identifier id="android.support.v4.view.ViewConfigurationCompat.getScaledPagingTouchSlop_changed(android.view.ViewConfiguration)"/>
    -+  <text>
    -+    InsertCommentsHere
    -+  </text>
    -+</comment>
    -+<comment>
    -+  <identifier id="android.support.v4.view.WindowInsetsCompat"/>
    -+  <text>
    -+    InsertCommentsHere
    -+  </text>
    -+</comment>
    -+<comment>
    -+  <identifier id="android.support.v4.view.WindowInsetsCompat.ctor_added(android.support.v4.view.WindowInsetsCompat)"/>
    -+  <text>
    -+    InsertCommentsHere
    -+  </text>
    -+</comment>
    -+<comment>
    -+  <identifier id="android.support.v4.view.accessibility"/>
    -+  <text>
    -+    InsertCommentsHere
    -+  </text>
    -+</comment>
    -+<comment>
    -+  <identifier id="android.support.v4.view.accessibility.AccessibilityEventCompat"/>
    -+  <text>
    -+    InsertCommentsHere
    -+  </text>
    -+</comment>
    -+<comment>
    -+  <identifier id="android.support.v4.view.accessibility.AccessibilityEventCompat.TYPE_ASSIST_READING_CONTEXT"/>
    -+  <text>
    -+    InsertCommentsHere
    -+  </text>
    -+</comment>
    -+<comment>
    -+  <identifier id="android.support.v4.view.accessibility.AccessibilityEventCompat.TYPE_VIEW_CONTEXT_CLICKED"/>
    -+  <text>
    -+    InsertCommentsHere
    -+  </text>
    -+</comment>
    -+<comment>
    -+  <identifier id="android.support.v4.view.accessibility.AccessibilityEventCompat.TYPE_WINDOWS_CHANGED"/>
    -+  <text>
    -+    InsertCommentsHere
    -+  </text>
    -+</comment>
    -+<comment>
    -+  <identifier id="android.support.v4.view.accessibility.AccessibilityEventCompat.getAction_added(android.view.accessibility.AccessibilityEvent)"/>
    -+  <text>
    -+    InsertCommentsHere
    -+  </text>
    -+</comment>
    -+<comment>
    -+  <identifier id="android.support.v4.view.accessibility.AccessibilityEventCompat.getMovementGranularity_added(android.view.accessibility.AccessibilityEvent)"/>
    -+  <text>
    -+    InsertCommentsHere
    -+  </text>
    -+</comment>
    -+<comment>
    -+  <identifier id="android.support.v4.view.accessibility.AccessibilityEventCompat.setAction_added(android.view.accessibility.AccessibilityEvent, int)"/>
    -+  <text>
    -+    InsertCommentsHere
    -+  </text>
    -+</comment>
    -+<comment>
    -+  <identifier id="android.support.v4.view.accessibility.AccessibilityEventCompat.setMovementGranularity_added(android.view.accessibility.AccessibilityEvent, int)"/>
    -+  <text>
    -+    InsertCommentsHere
    -+  </text>
    -+</comment>
    -+<comment>
    -+  <identifier id="android.support.v4.view.accessibility.AccessibilityManagerCompat"/>
    -+  <text>
    -+    InsertCommentsHere
    -+  </text>
    -+</comment>
    -+<comment>
    -+  <identifier id="android.support.v4.view.accessibility.AccessibilityManagerCompat.AccessibilityStateChangeListener"/>
    -+  <text>
    -+    InsertCommentsHere
    -+  </text>
    -+</comment>
    -+<comment>
    -+  <identifier id="android.support.v4.view.accessibility.AccessibilityManagerCompat.AccessibilityStateChangeListenerCompat"/>
    -+  <text>
    -+    InsertCommentsHere
    -+  </text>
    -+</comment>
    -+<comment>
    -+  <identifier id="android.support.v4.view.accessibility.AccessibilityManagerCompat.AccessibilityStateChangeListenerCompat.onAccessibilityStateChanged_removed(boolean)"/>
    -+  <text>
    -+    InsertCommentsHere
    -+  </text>
    -+</comment>
    -+<comment>
    -+  <identifier id="android.support.v4.view.accessibility.AccessibilityManagerCompat.TouchExplorationStateChangeListener"/>
    -+  <text>
    -+    InsertCommentsHere
    -+  </text>
    -+</comment>
    -+<comment>
    -+  <identifier id="android.support.v4.view.accessibility.AccessibilityManagerCompat.addAccessibilityStateChangeListener_changed(android.view.accessibility.AccessibilityManager, android.support.v4.view.accessibility.AccessibilityManagerCompat.AccessibilityStateChangeListener)"/>
    -+  <text>
    -+    InsertCommentsHere
    -+  </text>
    -+</comment>
    -+<comment>
    -+  <identifier id="android.support.v4.view.accessibility.AccessibilityManagerCompat.addTouchExplorationStateChangeListener_added(android.view.accessibility.AccessibilityManager, android.support.v4.view.accessibility.AccessibilityManagerCompat.TouchExplorationStateChangeListener)"/>
    -+  <text>
    -+    InsertCommentsHere
    -+  </text>
    -+</comment>
    -+<comment>
    -+  <identifier id="android.support.v4.view.accessibility.AccessibilityManagerCompat.removeAccessibilityStateChangeListener_changed(android.view.accessibility.AccessibilityManager, android.support.v4.view.accessibility.AccessibilityManagerCompat.AccessibilityStateChangeListener)"/>
    -+  <text>
    -+    InsertCommentsHere
    -+  </text>
    -+</comment>
    -+<comment>
    -+  <identifier id="android.support.v4.view.accessibility.AccessibilityManagerCompat.removeTouchExplorationStateChangeListener_added(android.view.accessibility.AccessibilityManager, android.support.v4.view.accessibility.AccessibilityManagerCompat.TouchExplorationStateChangeListener)"/>
    -+  <text>
    -+    InsertCommentsHere
    -+  </text>
    -+</comment>
    -+<comment>
    -+  <identifier id="android.support.v4.view.accessibility.AccessibilityNodeInfoCompat"/>
    -+  <text>
    -+    InsertCommentsHere
    -+  </text>
    -+</comment>
    -+<comment>
    -+  <identifier id="android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.ACTION_ARGUMENT_COLUMN_INT"/>
    -+  <text>
    -+    InsertCommentsHere
    -+  </text>
    -+</comment>
    -+<comment>
    -+  <identifier id="android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.ACTION_ARGUMENT_PROGRESS_VALUE"/>
    -+  <text>
    -+    InsertCommentsHere
    -+  </text>
    -+</comment>
    -+<comment>
    -+  <identifier id="android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.ACTION_ARGUMENT_ROW_INT"/>
    -+  <text>
    -+    InsertCommentsHere
    -+  </text>
    -+</comment>
    -+<comment>
    -+  <identifier id="android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat"/>
    -+  <text>
    -+    InsertCommentsHere
    -+  </text>
    -+</comment>
    -+<comment>
    -+  <identifier id="android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat.ACTION_CONTEXT_CLICK"/>
    -+  <text>
    -+    InsertCommentsHere
    -+  </text>
    -+</comment>
    -+<comment>
    -+  <identifier id="android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat.ACTION_SCROLL_DOWN"/>
    -+  <text>
    -+    InsertCommentsHere
    -+  </text>
    -+</comment>
    -+<comment>
    -+  <identifier id="android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat.ACTION_SCROLL_LEFT"/>
    -+  <text>
    -+    InsertCommentsHere
    -+  </text>
    -+</comment>
    -+<comment>
    -+  <identifier id="android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat.ACTION_SCROLL_RIGHT"/>
    -+  <text>
    -+    InsertCommentsHere
    -+  </text>
    -+</comment>
    -+<comment>
    -+  <identifier id="android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat.ACTION_SCROLL_TO_POSITION"/>
    -+  <text>
    -+    InsertCommentsHere
    -+  </text>
    -+</comment>
    -+<comment>
    -+  <identifier id="android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat.ACTION_SCROLL_UP"/>
    -+  <text>
    -+    InsertCommentsHere
    -+  </text>
    -+</comment>
    -+<comment>
    -+  <identifier id="android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat.ACTION_SET_PROGRESS"/>
    -+  <text>
    -+    InsertCommentsHere
    -+  </text>
    -+</comment>
    -+<comment>
    -+  <identifier id="android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat.ACTION_SHOW_ON_SCREEN"/>
    -+  <text>
    -+    InsertCommentsHere
    -+  </text>
    -+</comment>
    -+<comment>
    -+  <identifier id="android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.CollectionInfoCompat"/>
    -+  <text>
    -+    InsertCommentsHere
    -+  </text>
    -+</comment>
    -+<comment>
    -+  <identifier id="android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.CollectionInfoCompat.getSelectionMode_added()"/>
    -+  <text>
    -+    InsertCommentsHere
    -+  </text>
    -+</comment>
    -+<comment>
    -+  <identifier id="android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.CollectionInfoCompat.obtain_added(int, int, boolean)"/>
    -+  <text>
    -+    InsertCommentsHere
    -+  </text>
    -+</comment>
    -+<comment>
    -+  <identifier id="android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.CollectionItemInfoCompat"/>
    -+  <text>
    -+    InsertCommentsHere
    -+  </text>
    -+</comment>
    -+<comment>
    -+  <identifier id="android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.CollectionItemInfoCompat.obtain_added(int, int, int, int, boolean)"/>
    -+  <text>
    -+    InsertCommentsHere
    -+  </text>
    -+</comment>
    -+<comment>
    -+  <identifier id="android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.RangeInfoCompat"/>
    -+  <text>
    -+    InsertCommentsHere
    -+  </text>
    -+</comment>
    -+<comment>
    -+  <identifier id="android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.RangeInfoCompat.obtain_added(int, float, float, float)"/>
    -+  <text>
    -+    InsertCommentsHere
    -+  </text>
    -+</comment>
    -+<comment>
    -+  <identifier id="android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.isContextClickable_added()"/>
    -+  <text>
    -+    InsertCommentsHere
    -+  </text>
    -+</comment>
    -+<comment>
    -+  <identifier id="android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.setContextClickable_added(boolean)"/>
    -+  <text>
    -+    InsertCommentsHere
    -+  </text>
    -+</comment>
    -+<comment>
    -+  <identifier id="android.support.v4.view.accessibility.AccessibilityNodeProviderCompat"/>
    -+  <text>
    -+    InsertCommentsHere
    -+  </text>
    -+</comment>
    -+<comment>
    -+  <identifier id="android.support.v4.view.accessibility.AccessibilityNodeProviderCompat.HOST_VIEW_ID"/>
    -+  <text>
    -+    InsertCommentsHere
    -+  </text>
    -+</comment>
    -+<comment>
    -+  <identifier id="android.support.v4.view.accessibility.AccessibilityWindowInfoCompat"/>
    -+  <text>
    -+    InsertCommentsHere
    -+  </text>
    -+</comment>
    -+<comment>
    -+  <identifier id="android.support.v4.view.accessibility.AccessibilityWindowInfoCompat.TYPE_SPLIT_SCREEN_DIVIDER"/>
    -+  <text>
    -+    InsertCommentsHere
    -+  </text>
    -+</comment>
    -+<comment>
    -+  <identifier id="android.support.v4.widget"/>
    -+  <text>
    -+    InsertCommentsHere
    -+  </text>
    -+</comment>
    -+<comment>
    -+  <identifier id="android.support.v4.widget.SearchViewCompat"/>
    -+  <text>
    -+    InsertCommentsHere
    -+  </text>
    -+</comment>
    -+<comment>
    -+  <identifier id="android.support.v4.widget.SearchViewCompat.OnCloseListener"/>
    -+  <text>
    -+    InsertCommentsHere
    -+  </text>
    -+</comment>
    -+<comment>
    -+  <identifier id="android.support.v4.widget.SearchViewCompat.OnCloseListenerCompat"/>
    -+  <text>
    -+    InsertCommentsHere
    -+  </text>
    -+</comment>
    -+<comment>
    -+  <identifier id="android.support.v4.widget.SearchViewCompat.OnQueryTextListener"/>
    -+  <text>
    -+    InsertCommentsHere
    -+  </text>
    -+</comment>
    -+<comment>
    -+  <identifier id="android.support.v4.widget.SearchViewCompat.OnQueryTextListenerCompat"/>
    -+  <text>
    -+    InsertCommentsHere
    -+  </text>
    -+</comment>
    -+<comment>
    -+  <identifier id="android.support.v4.widget.SearchViewCompat.setOnCloseListener_changed(android.view.View, android.support.v4.widget.SearchViewCompat.OnCloseListener)"/>
    -+  <text>
    -+    InsertCommentsHere
    -+  </text>
    -+</comment>
    -+<comment>
    -+  <identifier id="android.support.v4.widget.SearchViewCompat.setOnQueryTextListener_changed(android.view.View, android.support.v4.widget.SearchViewCompat.OnQueryTextListener)"/>
    -+  <text>
    -+    InsertCommentsHere
    -+  </text>
    -+</comment>
    -+<comment>
    -+  <identifier id="android.support.v4.widget.SwipeRefreshLayout"/>
    -+  <text>
    -+    InsertCommentsHere
    -+  </text>
    -+</comment>
    -+<comment>
    -+  <identifier id="android.support.v4.widget.SwipeRefreshLayout.OnChildScrollUpCallback"/>
    -+  <text>
    -+    InsertCommentsHere
    -+  </text>
    -+</comment>
    -+<comment>
    -+  <identifier id="android.support.v4.widget.SwipeRefreshLayout.setOnChildScrollUpCallback_added(android.support.v4.widget.SwipeRefreshLayout.OnChildScrollUpCallback)"/>
    -+  <text>
    -+    InsertCommentsHere
    -+  </text>
    -+</comment>
    -+<comment>
    -+  <identifier id="android.support.v4.widget.TextViewCompat"/>
    -+  <text>
    -+    InsertCommentsHere
    -+  </text>
    -+</comment>
    -+<comment>
    -+  <identifier id="android.support.v4.widget.TextViewCompat.getCompoundDrawablesRelative_added(android.widget.TextView)"/>
    -+  <text>
    -+    InsertCommentsHere
    -+  </text>
    -+</comment>
    -+<comment>
    -+  <identifier id="android.support.v7.app"/>
    -+  <text>
    -+    InsertCommentsHere
    -+  </text>
    -+</comment>
    -+<comment>
    -+  <identifier id="android.support.v7.app.ActionBarActivity"/>
    -+  <text>
    -+    InsertCommentsHere
    -+  </text>
    -+</comment>
    -+<comment>
    -+  <identifier id="android.support.v7.app.ActionBarDrawerToggle"/>
    -+  <text>
    -+    InsertCommentsHere
    -+  </text>
    -+</comment>
    -+<comment>
    -+  <identifier id="android.support.v7.app.ActionBarDrawerToggle.getDrawerArrowDrawable_added()"/>
    -+  <text>
    -+    InsertCommentsHere
    -+  </text>
    -+</comment>
    -+<comment>
    -+  <identifier id="android.support.v7.app.ActionBarDrawerToggle.setDrawerArrowDrawable_added(android.support.v7.graphics.drawable.DrawerArrowDrawable)"/>
    -+  <text>
    -+    InsertCommentsHere
    -+  </text>
    -+</comment>
    -+<comment>
    -+  <identifier id="android.support.v7.app.AppCompatActivity"/>
    -+  <text>
    -+    InsertCommentsHere
    -+  </text>
    -+</comment>
    -+<comment>
    -+  <identifier id="android.support.v7.app.AppCompatDelegate"/>
    -+  <text>
    -+    InsertCommentsHere
    -+  </text>
    -+</comment>
    -+<comment>
    -+  <identifier id="android.support.v7.app.AppCompatDelegate.onStart_added()"/>
    -+  <text>
    -+    InsertCommentsHere
    -+  </text>
    -+</comment>
    -+<comment>
    -+  <identifier id="android.support.v7.app.AppCompatDialogFragment"/>
    -+  <text>
    -+    InsertCommentsHere
    -+  </text>
    -+</comment>
    -+<comment>
    -+  <identifier id="android.support.v7.app.NotificationCompat"/>
    -+  <text>
    -+    InsertCommentsHere
    -+  </text>
    -+</comment>
    -+<comment>
    -+  <identifier id="android.support.v7.app.NotificationCompat.Builder"/>
    -+  <text>
    -+    InsertCommentsHere
    -+  </text>
    -+</comment>
    -+<comment>
    -+  <identifier id="android.support.v7.app.NotificationCompat.MediaStyle"/>
    -+  <text>
    -+    InsertCommentsHere
    -+  </text>
    -+</comment>
    -+<comment>
    -+  <identifier id="android.support.v7.appcompat"/>
    -+  <text>
    -+    InsertCommentsHere
    -+  </text>
    -+</comment>
    -+<comment>
    -+  <identifier id="android.support.v7.content.res"/>
    -+  <text>
    -+    InsertCommentsHere
    -+  </text>
    -+</comment>
    -+<comment>
    -+  <identifier id="android.support.v7.content.res.AppCompatResources"/>
    -+  <text>
    -+    InsertCommentsHere
    -+  </text>
    -+</comment>
    -+<comment>
    -+  <identifier id="android.support.v7.content.res.AppCompatResources.getDrawable_added(android.content.Context, int)"/>
    -+  <text>
    -+    InsertCommentsHere
    -+  </text>
    -+</comment>
    -+<comment>
    -+  <identifier id="android.support.v7.graphics"/>
    -+  <text>
    -+    InsertCommentsHere
    -+  </text>
    -+</comment>
    -+<comment>
    -+  <identifier id="android.support.v7.graphics.Palette"/>
    -+  <text>
    -+    InsertCommentsHere
    -+  </text>
    -+</comment>
    -+<comment>
    -+  <identifier id="android.support.v7.graphics.Palette.getDominantColor_added(int)"/>
    -+  <text>
    -+    InsertCommentsHere
    -+  </text>
    -+</comment>
    -+<comment>
    -+  <identifier id="android.support.v7.graphics.Palette.getDominantSwatch_added()"/>
    -+  <text>
    -+    InsertCommentsHere
    -+  </text>
    -+</comment>
    -+<comment>
    -+  <identifier id="android.support.v7.preference"/>
    -+  <text>
    -+    InsertCommentsHere
    -+  </text>
    -+</comment>
    -+<comment>
    -+  <identifier id="android.support.v7.preference.MultiSelectListPreferenceDialogFragmentCompat"/>
    -+  <text>
    -+    InsertCommentsHere
    -+  </text>
    -+</comment>
    -+<comment>
    -+  <identifier id="android.support.v7.recyclerview"/>
    -+  <text>
    -+    InsertCommentsHere
    -+  </text>
    -+</comment>
    -+<comment>
    -+  <identifier id="android.support.v7.util"/>
    -+  <text>
    -+    InsertCommentsHere
    -+  </text>
    -+</comment>
    -+<comment>
    -+  <identifier id="android.support.v7.util.BatchingListUpdateCallback"/>
    -+  <text>
    -+    InsertCommentsHere
    -+  </text>
    -+</comment>
    -+<comment>
    -+  <identifier id="android.support.v7.util.DiffUtil"/>
    -+  <text>
    -+    InsertCommentsHere
    -+  </text>
    -+</comment>
    -+<comment>
    -+  <identifier id="android.support.v7.util.DiffUtil.Callback"/>
    -+  <text>
    -+    InsertCommentsHere
    -+  </text>
    -+</comment>
    -+<comment>
    -+  <identifier id="android.support.v7.util.DiffUtil.DiffResult"/>
    -+  <text>
    -+    InsertCommentsHere
    -+  </text>
    -+</comment>
    -+<comment>
    -+  <identifier id="android.support.v7.util.ListUpdateCallback"/>
    -+  <text>
    -+    InsertCommentsHere
    -+  </text>
    -+</comment>
    -+<comment>
    -+  <identifier id="android.support.v7.util.SortedList.Callback"/>
    -+  <text>
    -+    InsertCommentsHere
    -+  </text>
    -+</comment>
    -+<comment>
    -+  <identifier id="android.support.v7.util.SortedList.Callback.onChanged_added(int, int, java.lang.Object)"/>
    -+  <text>
    -+    InsertCommentsHere
    -+  </text>
    -+</comment>
    -+<comment>
    -+  <identifier id="android.support.v7.util.SortedList.Callback.onInserted_removed(int, int)"/>
    -+  <text>
    -+    InsertCommentsHere
    -+  </text>
    -+</comment>
    -+<comment>
    -+  <identifier id="android.support.v7.util.SortedList.Callback.onMoved_removed(int, int)"/>
    -+  <text>
    -+    InsertCommentsHere
    -+  </text>
    -+</comment>
    -+<comment>
    -+  <identifier id="android.support.v7.util.SortedList.Callback.onRemoved_removed(int, int)"/>
    -+  <text>
    -+    InsertCommentsHere
    -+  </text>
    -+</comment>
    -+<comment>
    -+  <identifier id="android.support.v7.widget"/>
    -+  <text>
    -+    InsertCommentsHere
    -+  </text>
    -+</comment>
    -+<comment>
    -+  <identifier id="android.support.v7.widget.ActionMenuView"/>
    -+  <text>
    -+    InsertCommentsHere
    -+  </text>
    -+</comment>
    -+<comment>
    -+  <identifier id="android.support.v7.widget.ActionMenuView.LayoutParams"/>
    -+  <text>
    -+    InsertCommentsHere
    -+  </text>
    -+</comment>
    -+<comment>
    -+  <identifier id="android.support.v7.widget.ActionMenuView.OnMenuItemClickListener"/>
    -+  <text>
    -+    InsertCommentsHere
    -+  </text>
    -+</comment>
    -+<comment>
    -+  <identifier id="android.support.v7.widget.AppCompatAutoCompleteTextView"/>
    -+  <text>
    -+    InsertCommentsHere
    -+  </text>
    -+</comment>
    -+<comment>
    -+  <identifier id="android.support.v7.widget.AppCompatButton"/>
    -+  <text>
    -+    InsertCommentsHere
    -+  </text>
    -+</comment>
    -+<comment>
    -+  <identifier id="android.support.v7.widget.AppCompatCheckBox"/>
    -+  <text>
    -+    InsertCommentsHere
    -+  </text>
    -+</comment>
    -+<comment>
    -+  <identifier id="android.support.v7.widget.AppCompatCheckedTextView"/>
    -+  <text>
    -+    InsertCommentsHere
    -+  </text>
    -+</comment>
    -+<comment>
    -+  <identifier id="android.support.v7.widget.AppCompatEditText"/>
    -+  <text>
    -+    InsertCommentsHere
    -+  </text>
    -+</comment>
    -+<comment>
    -+  <identifier id="android.support.v7.widget.AppCompatImageButton"/>
    -+  <text>
    -+    InsertCommentsHere
    -+  </text>
    -+</comment>
    -+<comment>
    -+  <identifier id="android.support.v7.widget.AppCompatImageView"/>
    -+  <text>
    -+    InsertCommentsHere
    -+  </text>
    -+</comment>
    -+<comment>
    -+  <identifier id="android.support.v7.widget.AppCompatMultiAutoCompleteTextView"/>
    -+  <text>
    -+    InsertCommentsHere
    -+  </text>
    -+</comment>
    -+<comment>
    -+  <identifier id="android.support.v7.widget.AppCompatRadioButton"/>
    -+  <text>
    -+    InsertCommentsHere
    -+  </text>
    -+</comment>
    -+<comment>
    -+  <identifier id="android.support.v7.widget.AppCompatRatingBar"/>
    -+  <text>
    -+    InsertCommentsHere
    -+  </text>
    -+</comment>
    -+<comment>
    -+  <identifier id="android.support.v7.widget.AppCompatSeekBar"/>
    -+  <text>
    -+    InsertCommentsHere
    -+  </text>
    -+</comment>
    -+<comment>
    -+  <identifier id="android.support.v7.widget.AppCompatSpinner"/>
    -+  <text>
    -+    InsertCommentsHere
    -+  </text>
    -+</comment>
    -+<comment>
    -+  <identifier id="android.support.v7.widget.AppCompatTextView"/>
    -+  <text>
    -+    InsertCommentsHere
    -+  </text>
    -+</comment>
    -+<comment>
    -+  <identifier id="android.support.v7.widget.CardView"/>
    -+  <text>
    -+    InsertCommentsHere
    -+  </text>
    -+</comment>
    -+<comment>
    -+  <identifier id="android.support.v7.widget.GridLayout"/>
    -+  <text>
    -+    InsertCommentsHere
    -+  </text>
    -+</comment>
    -+<comment>
    -+  <identifier id="android.support.v7.widget.GridLayout.Alignment"/>
    -+  <text>
    -+    InsertCommentsHere
    -+  </text>
    -+</comment>
    -+<comment>
    -+  <identifier id="android.support.v7.widget.GridLayout.LayoutParams"/>
    -+  <text>
    -+    InsertCommentsHere
    -+  </text>
    -+</comment>
    -+<comment>
    -+  <identifier id="android.support.v7.widget.GridLayout.Spec"/>
    -+  <text>
    -+    InsertCommentsHere
    -+  </text>
    -+</comment>
    -+<comment>
    -+  <identifier id="android.support.v7.widget.LinearLayoutCompat"/>
    -+  <text>
    -+    InsertCommentsHere
    -+  </text>
    -+</comment>
    -+<comment>
    -+  <identifier id="android.support.v7.widget.LinearLayoutCompat.LayoutParams"/>
    -+  <text>
    -+    InsertCommentsHere
    -+  </text>
    -+</comment>
    -+<comment>
    -+  <identifier id="android.support.v7.widget.LinearLayoutManager"/>
    -+  <text>
    -+    InsertCommentsHere
    -+  </text>
    -+</comment>
    -+<comment>
    -+  <identifier id="android.support.v7.widget.LinearLayoutManager.prepareForDrop_removed(android.view.View, android.view.View, int, int)"/>
    -+  <text>
    -+    InsertCommentsHere
    -+  </text>
    -+</comment>
    -+<comment>
    -+  <identifier id="android.support.v7.widget.LinearSmoothScroller"/>
    -+  <text>
    -+    InsertCommentsHere
    -+  </text>
    -+</comment>
    -+<comment>
    -+  <identifier id="android.support.v7.widget.LinearSmoothScroller.computeScrollVectorForPosition_changed(int)"/>
    -+  <text>
    -+    InsertCommentsHere
    -+  </text>
    -+</comment>
    -+<comment>
    -+  <identifier id="android.support.v7.widget.LinearSnapHelper"/>
    -+  <text>
    -+    InsertCommentsHere
    -+  </text>
    -+</comment>
    -+<comment>
    -+  <identifier id="android.support.v7.widget.ListPopupWindow"/>
    -+  <text>
    -+    InsertCommentsHere
    -+  </text>
    -+</comment>
    -+<comment>
    -+  <identifier id="android.support.v7.widget.PopupMenu"/>
    -+  <text>
    -+    InsertCommentsHere
    -+  </text>
    -+</comment>
    -+<comment>
    -+  <identifier id="android.support.v7.widget.PopupMenu.OnDismissListener"/>
    -+  <text>
    -+    InsertCommentsHere
    -+  </text>
    -+</comment>
    -+<comment>
    -+  <identifier id="android.support.v7.widget.PopupMenu.OnMenuItemClickListener"/>
    -+  <text>
    -+    InsertCommentsHere
    -+  </text>
    -+</comment>
    -+<comment>
    -+  <identifier id="android.support.v7.widget.RecyclerView"/>
    -+  <text>
    -+    InsertCommentsHere
    -+  </text>
    -+</comment>
    -+<comment>
    -+  <identifier id="android.support.v7.widget.RecyclerView.OnFlingListener"/>
    -+  <text>
    -+    InsertCommentsHere
    -+  </text>
    -+</comment>
    -+<comment>
    -+  <identifier id="android.support.v7.widget.RecyclerView.SmoothScroller.ScrollVectorProvider"/>
    -+  <text>
    -+    InsertCommentsHere
    -+  </text>
    -+</comment>
    -+<comment>
    -+  <identifier id="android.support.v7.widget.RecyclerView.getOnFlingListener_added()"/>
    -+  <text>
    -+    InsertCommentsHere
    -+  </text>
    -+</comment>
    -+<comment>
    -+  <identifier id="android.support.v7.widget.RecyclerView.setOnFlingListener_added(android.support.v7.widget.RecyclerView.OnFlingListener)"/>
    -+  <text>
    -+    InsertCommentsHere
    -+  </text>
    -+</comment>
    -+<comment>
    -+  <identifier id="android.support.v7.widget.SearchView"/>
    -+  <text>
    -+    InsertCommentsHere
    -+  </text>
    -+</comment>
    -+<comment>
    -+  <identifier id="android.support.v7.widget.SearchView.OnCloseListener"/>
    -+  <text>
    -+    InsertCommentsHere
    -+  </text>
    -+</comment>
    -+<comment>
    -+  <identifier id="android.support.v7.widget.SearchView.OnQueryTextListener"/>
    -+  <text>
    -+    InsertCommentsHere
    -+  </text>
    -+</comment>
    -+<comment>
    -+  <identifier id="android.support.v7.widget.SearchView.OnSuggestionListener"/>
    -+  <text>
    -+    InsertCommentsHere
    -+  </text>
    -+</comment>
    -+<comment>
    -+  <identifier id="android.support.v7.widget.ShareActionProvider"/>
    -+  <text>
    -+    InsertCommentsHere
    -+  </text>
    -+</comment>
    -+<comment>
    -+  <identifier id="android.support.v7.widget.ShareActionProvider.OnShareTargetSelectedListener"/>
    -+  <text>
    -+    InsertCommentsHere
    -+  </text>
    -+</comment>
    -+<comment>
    -+  <identifier id="android.support.v7.widget.SnapHelper"/>
    -+  <text>
    -+    InsertCommentsHere
    -+  </text>
    -+</comment>
    -+<comment>
    -+  <identifier id="android.support.v7.widget.Space"/>
    -+  <text>
    -+    InsertCommentsHere
    -+  </text>
    -+</comment>
    -+<comment>
    -+  <identifier id="android.support.v7.widget.StaggeredGridLayoutManager"/>
    -+  <text>
    -+    InsertCommentsHere
    -+  </text>
    -+</comment>
    -+<comment>
    -+  <identifier id="android.support.v7.widget.StaggeredGridLayoutManager.TAG"/>
    -+  <text>
    -+    InsertCommentsHere
    -+  </text>
    -+</comment>
    -+<comment>
    -+  <identifier id="android.support.v7.widget.StaggeredGridLayoutManager.computeScrollVectorForPosition_added(int)"/>
    -+  <text>
    -+    InsertCommentsHere
    -+  </text>
    -+</comment>
    -+<comment>
    -+  <identifier id="android.support.v7.widget.SwitchCompat"/>
    -+  <text>
    -+    InsertCommentsHere
    -+  </text>
    -+</comment>
    -+<comment>
    -+  <identifier id="android.support.v7.widget.ThemedSpinnerAdapter"/>
    -+  <text>
    -+    InsertCommentsHere
    -+  </text>
    -+</comment>
    -+<comment>
    -+  <identifier id="android.support.v7.widget.ThemedSpinnerAdapter.Helper"/>
    -+  <text>
    -+    InsertCommentsHere
    -+  </text>
    -+</comment>
    -+<comment>
    -+  <identifier id="android.support.v7.widget.Toolbar"/>
    -+  <text>
    -+    InsertCommentsHere
    -+  </text>
    -+</comment>
    -+<comment>
    -+  <identifier id="android.support.v7.widget.Toolbar.LayoutParams"/>
    -+  <text>
    -+    InsertCommentsHere
    -+  </text>
    -+</comment>
    -+<comment>
    -+  <identifier id="android.support.v7.widget.Toolbar.OnMenuItemClickListener"/>
    -+  <text>
    -+    InsertCommentsHere
    -+  </text>
    -+</comment>
    -+<comment>
    -+  <identifier id="android.support.v7.widget.Toolbar.SavedState"/>
    -+  <text>
    -+    InsertCommentsHere
    -+  </text>
    -+</comment>
    -+<comment>
    -+  <identifier id="android.support.v8.renderscript"/>
    -+  <text>
    -+    InsertCommentsHere
    -+  </text>
    -+</comment>
    -+
    -+</comments>
    -diff --git a/docs/html/topic/arc/index.jd b/docs/html/topic/arc/index.jd
    -index d46fbc8..a025459 100644
    ---- a/docs/html/topic/arc/index.jd
    -+++ b/docs/html/topic/arc/index.jd
    -@@ -51,7 +51,7 @@ review your mouse and keyboard interactions.
    -     &lt;!-- Some Chromebooks don't support touch. Although not essential,
    -          it's a good idea to explicitly include this declaration. --&gt;
    -     &lt;uses-feature android:name="android.hardware.touchscreen"
    --                  required="false" /&gt;
    -+                  android:required="false" /&gt;
    - &lt;/manifest&gt;
    - </pre>
    - 
    -diff --git a/docs/html/topic/libraries/data-binding/index.jd b/docs/html/topic/libraries/data-binding/index.jd
    -index ddcc9f2..0faa1db 100644
    ---- a/docs/html/topic/libraries/data-binding/index.jd
    -+++ b/docs/html/topic/libraries/data-binding/index.jd
    -@@ -162,7 +162,9 @@ page.tags="databinding", "layouts"
    - 
    - <p>
    -   To use data binding, Android Plugin for Gradle <strong>1.5.0-alpha1</strong>
    --  or higher is required.
    -+  or higher is required. See how to <a
    -+href="/studio/releases/gradle-plugin.html#updating-plugin">update the Android
    -+Plugin for Gradle</a>.
    - </p>
    - 
    - <h2 id="build_environment">
    -diff --git a/docs/html/topic/libraries/support-library/features.jd b/docs/html/topic/libraries/support-library/features.jd
    -index 614392e..b5f189a 100755
    ---- a/docs/html/topic/libraries/support-library/features.jd
    -+++ b/docs/html/topic/libraries/support-library/features.jd
    -@@ -108,7 +108,7 @@ page.title=Support Library Features
    - <p>The Gradle build script dependency identifier for this library is as follows:</p>
    - 
    - <pre>
    --com.android.support:support-compat:24.2.0
    -+com.android.support:support-compat:24.2.1
    - </pre>
    - 
    - <h3 id="v4-core-utils">v4 core-utils library</h3>
    -@@ -124,7 +124,7 @@ com.android.support:support-compat:24.2.0
    - </p>
    - 
    - <pre>
    --com.android.support:support-core-utils:24.2.0
    -+com.android.support:support-core-utils:24.2.1
    - </pre>
    - 
    - <h3 id="v4-core-ui">v4 core-ui library</h3>
    -@@ -141,7 +141,7 @@ com.android.support:support-core-utils:24.2.0
    - </p>
    - 
    - <pre>
    --com.android.support:support-core-ui:24.2.0
    -+com.android.support:support-core-ui:24.2.1
    - </pre>
    - 
    - <h3 id="v4-media-compat">v4 media-compat library</h3>
    -@@ -158,7 +158,7 @@ com.android.support:support-core-ui:24.2.0
    - </p>
    - 
    - <pre>
    --com.android.support:support-media-compat:24.2.0
    -+com.android.support:support-media-compat:24.2.1
    - </pre>
    - 
    - <h3 id="v4-fragment">v4 fragment library</h3>
    -@@ -178,7 +178,7 @@ com.android.support:support-media-compat:24.2.0
    - </p>
    - 
    - <pre>
    --com.android.support:support-fragment:24.2.0
    -+com.android.support:support-fragment:24.2.1
    - </pre>
    - 
    - <h2 id="multidex">Multidex Support Library</h2>
    -@@ -245,7 +245,7 @@ com.android.support:multidex:1.0.0
    - <p>The Gradle build script dependency identifier for this library is as follows:</p>
    - 
    - <pre>
    --com.android.support:appcompat-v7:24.2.0
    -+com.android.support:appcompat-v7:24.2.1
    - </pre>
    - 
    - 
    -@@ -260,7 +260,7 @@ implementations, and are used extensively in layouts for TV apps.</p>
    - <p>The Gradle build script dependency identifier for this library is as follows:</p>
    - 
    - <pre>
    --com.android.support:cardview-v7:24.2.0
    -+com.android.support:cardview-v7:24.2.1
    - </pre>
    - 
    - 
    -@@ -276,7 +276,7 @@ For detailed information about the v7 gridlayout library APIs, see the
    - <p>The Gradle build script dependency identifier for this library is as follows:</p>
    - 
    - <pre>
    --com.android.support:gridlayout-v7:24.2.0
    -+com.android.support:gridlayout-v7:24.2.1
    - </pre>
    - 
    - 
    -@@ -299,7 +299,7 @@ reference.</p>
    - <p>The Gradle build script dependency identifier for this library is as follows:</p>
    - 
    - <pre>
    --com.android.support:mediarouter-v7:24.2.0
    -+com.android.support:mediarouter-v7:24.2.1
    - </pre>
    - 
    - <p class="caution">The v7 mediarouter library APIs introduced in Support Library
    -@@ -319,7 +319,7 @@ title card.</p>
    - <p>The Gradle build script dependency identifier for this library is as follows:</p>
    - 
    - <pre>
    --com.android.support:palette-v7:24.2.0
    -+com.android.support:palette-v7:24.2.1
    - </pre>
    - 
    - 
    -@@ -335,7 +335,7 @@ limited window of data items.</p>
    - <p>The Gradle build script dependency identifier for this library is as follows:</p>
    - 
    - <pre>
    --com.android.support:recyclerview-v7:24.2.0
    -+com.android.support:recyclerview-v7:24.2.1
    - </pre>
    - 
    - 
    -@@ -358,7 +358,7 @@ such as {@link android.support.v7.preference.CheckBoxPreference} and
    - <p>The Gradle build script dependency identifier for this library is as follows:</p>
    - 
    - <pre>
    --com.android.support:preference-v7:24.2.0
    -+com.android.support:preference-v7:24.2.1
    - </pre>
    - 
    - <h2 id="v8">v8 Support Library</h2>
    -@@ -409,7 +409,7 @@ defaultConfig {
    - <p>The Gradle build script dependency identifier for this library is as follows:</p>
    - 
    - <pre>
    --com.android.support:support-v13:24.2.0
    -+com.android.support:support-v13:24.2.1
    - </pre>
    - 
    - 
    -@@ -435,7 +435,7 @@ for preference interfaces such as
    - <p>The Gradle build script dependency identifier for this library is as follows:</p>
    - 
    - <pre>
    --com.android.support:preference-v14:24.2.0
    -+com.android.support:preference-v14:24.2.1
    - </pre>
    - 
    - 
    -@@ -458,7 +458,7 @@ interface and classes, such as
    - <p>The Gradle build script dependency identifier for this library is as follows:</p>
    - 
    - <pre>
    --com.android.support:preference-leanback-v17:24.2.0
    -+com.android.support:preference-leanback-v17:24.2.1
    - </pre>
    - 
    - 
    -@@ -494,7 +494,7 @@ com.android.support:preference-leanback-v17:24.2.0
    - <p>The Gradle build script dependency identifier for this library is as follows:</p>
    - 
    - <pre>
    --com.android.support:leanback-v17:24.2.0
    -+com.android.support:leanback-v17:24.2.1
    - </pre>
    - 
    - 
    -@@ -509,7 +509,7 @@ package provides APIs to support adding annotation metadata to your apps. </p>
    - <p>The Gradle build script dependency identifier for this library is as follows:</p>
    - 
    - <pre>
    --com.android.support:support-annotations:24.2.0
    -+com.android.support:support-annotations:24.2.1
    - </pre>
    - 
    - 
    -@@ -527,7 +527,7 @@ snackbars, and <a href="{@docRoot}design/building-blocks/tabs.html">tabs</a>.  <
    - <p>The Gradle build script dependency identifier for this library is as follows:</p>
    - 
    - <pre>
    --com.android.support:design:24.2.0
    -+com.android.support:design:24.2.1
    - </pre>
    - 
    - 
    -@@ -548,7 +548,7 @@ Callback</a>.  </p>
    - <p>The Gradle build script dependency identifier for this library is as follows:</p>
    - 
    - <pre>
    --com.android.support:customtabs:24.2.0
    -+com.android.support:customtabs:24.2.1
    - </pre>
    - 
    - 
    -@@ -572,7 +572,7 @@ PercentRelativeLayout</a>.  </p>
    - <p>The Gradle build script dependency identifier for this library is as follows:</p>
    - 
    - <pre>
    --com.android.support:percent:24.2.0
    -+com.android.support:percent:24.2.1
    - </pre>
    - 
    - 
    -@@ -595,5 +595,5 @@ RecommendationExtender</a>.  </p>
    - <p>The Gradle build script dependency identifier for this library is as follows:</p>
    - 
    - <pre>
    --com.android.support:recommendation:24.2.0
    -+com.android.support:recommendation:24.2.1
    - </pre>
    -diff --git a/docs/html/topic/libraries/support-library/revisions.jd b/docs/html/topic/libraries/support-library/revisions.jd
    -index 4e14c70..9a24d15 100644
    ---- a/docs/html/topic/libraries/support-library/revisions.jd
    -+++ b/docs/html/topic/libraries/support-library/revisions.jd
    -@@ -6,9 +6,71 @@ page.metaDescription=This page provides details about the Support Library packag
    - <p>This page provides details about the Support Library package releases.</p>
    - 
    - <div class="toggle-content opened">
    --  <p id="rev24-2-0">
    -+  <p id="rev24-2-1">
    -     <a href="#" onclick="return toggleContent(this)"><img src=
    -     "{@docRoot}assets/images/styles/disclosure_up.png" class=
    -+    "toggle-content-img" alt="">Android Support Library, revision 24.2.1</a>
    -+    <em>(September 2016)</em>
    -+  </p>
    -+
    -+  <div class="toggle-content-toggleme">
    -+
    -+    <p>Fixed issues:</p>
    -+
    -+<ul>
    -+  <li>{@link android.support.design.widget.FloatingActionButton} can no longer
    -+  be anchored to indirect children of {@link
    -+  android.support.design.widget.CoordinatorLayout}. (AOSP issue <a href=
    -+  "https://code.google.com/p/android/issues/detail?id=220250">220250</a>)
    -+  </li>
    -+
    -+  <li>Image inside {@link
    -+  android.support.design.widget.CollapsingToolbarLayout} doesn’t scale properly
    -+  with <code>fitsSystemWindows=true</code>. (AOSP issue <a href=
    -+  "https://code.google.com/p/android/issues/detail?id=220389">220389</a>)
    -+  </li>
    -+
    -+  <li>{@link android.support.design.widget.CoordinatorLayout} throws {@link
    -+  java.lang.IndexOutOfBoundsException} when {@link
    -+  android.support.design.widget.Snackbar} is shown and dismissed. (AOSP issue
    -+  <a href="https://code.google.com/p/android/issues/detail?id=220762"
    -+  >220762</a>)
    -+  </li>
    -+
    -+  <li>{@link android.support.design.widget.TextInputLayout} fails to resolve
    -+  error text color. (AOSP issue <a href=
    -+  "https://code.google.com/p/android/issues/detail?id=220305">220305</a>)
    -+  </li>
    -+
    -+  <li>{@link android.support.v7.util.SortedList.BatchedCallback#onMoved
    -+  BatchedCallback.onMoved()} calls {@link
    -+  android.support.v7.util.SortedList.BatchedCallback#onInserted
    -+  BatchedCallback.onInserted()}. (AOSP issue <a href=
    -+  "https://code.google.com/p/android/issues/detail?id=220309">220309</a>)
    -+  </li>
    -+
    -+  <li>{@link android.support.design.widget.TextInputLayout} overrides right
    -+  compound drawable. (AOSP issue <a href=
    -+  "https://code.google.com/p/android/issues/detail?id=220728">220728</a>)
    -+  </li>
    -+</ul>
    -+
    -+<p>
    -+  A complete list of public bug fixes is available on the <a href=
    -+  "https://code.google.com/p/android/issues/list?can=1&q=label%3ATarget-Support-24.2.1">
    -+  AOSP Issue Tracker</a>.
    -+</p>
    -+
    -+
    -+  </div>
    -+</div>
    -+
    -+<!-- end of collapsible section: 24.2.1 -->
    -+
    -+<div class="toggle-content closed">
    -+  <p id="rev24-2-0">
    -+    <a href="#" onclick="return toggleContent(this)"><img src=
    -+    "{@docRoot}assets/images/styles/disclosure_down.png" class=
    -     "toggle-content-img" alt="">Android Support Library, revision 24.2.0</a>
    -     <em>(August 2016)</em>
    -   </p>
    -@@ -174,6 +236,14 @@ APK size, we recommend that you just list the specific modules your app needs.
    -     behavior similar to {@link android.support.v4.view.ViewPager}.
    -   </li>
    - 
    -+  <li>The Custom Tabs library now allows clients to request the standard
    -+  browser UI, rather than custom tabs UI, by calling <a href=
    -+  "/reference/android/support/customtabs/CustomTabsIntent.html#setAlwaysUseBrowserUI(android.content.Intent)">
    -+    <code>CustomTabsIntent.setAlwaysUseBrowserUI()</code></a>. This behavior is
    -+    useful in cases where the browser defaults to custom tabs UI but the user
    -+    has expressed a preference for the standard browser UI.
    -+  </li>
    -+
    - </ul>
    - 
    - <h3 id="24-2-0-behavior">Behavior changes</h3>
    -@@ -189,8 +259,17 @@ APK size, we recommend that you just list the specific modules your app needs.
    -   <li>{@link android.support.design.widget.Snackbar} now draws behind the
    -   navigation bar if the status bar is translucent.
    -   </li>
    -+
    - </ul>
    - 
    -+<h4>MediaRouter library</h4>
    -+
    -+<p>
    -+  Bluetooth devices are no longer listed as media routes. Routing audio to
    -+  Bluetooth devices is now solely controlled at the Android system level.
    -+</p>
    -+
    -+
    - <h3 id="24-2-0-deprecations">Deprecations</h3>
    - 
    - <p>Deprecated classes and methods are subject to removal in a future release. You should migrate away from these APIs as soon as possible.</p>
    -@@ -2895,8 +2974,6 @@ if (animator instanceof SimpleItemAnimator) {
    -         <ul>
    -           <li>Added {@link android.support.v7.widget.GridLayout} to provide support for the
    -             {@link android.widget.GridLayout} layout object.</li>
    --          <li>Added {@link android.support.v7.widget.Space} which can be used to create blank areas
    --            within a {@link android.support.v7.widget.GridLayout} layout object.</li>
    -         </ul>
    -     </dl>
    -   </div>
    -diff --git a/docs/html/topic/performance/_book.yaml b/docs/html/topic/performance/_book.yaml
    -index e053a2c..4021e85 100644
    ---- a/docs/html/topic/performance/_book.yaml
    -+++ b/docs/html/topic/performance/_book.yaml
    -@@ -1,34 +1,61 @@
    - toc:
    --- title: Reducing Network Battery Drain
    --  path: /topic/performance/power/network/index.html
    -+- title: Optimizing for Battery Life
    -+  path: /topic/performance/power/index.html
    -   path_attributes:
    -   - name: description
    --    value: Access the network while going easy on battery life.
    -+    value: Learn to make your app more battery-friendly.
    -   section:
    --  - title: Collecting Network Traffic Data
    --    path: /topic/performance/power/network/gather-data.html
    --  - title: Analyzing Network Traffic Data
    --    path: /topic/performance/power/network/analyze-data.html
    --  - title: Optimizing User-Initiated Network Use
    --    path: /topic/performance/power/network/action-user-traffic.html
    --  - title: Optimizing Server-Initiated Network Use
    --    path: /topic/performance/power/network/action-server-traffic.html
    --  - title: Optimizing General Network Use
    --    path: /topic/performance/power/network/action-any-traffic.html
    --- title: Implementing Doze
    --  path: /training/monitoring-device-state/doze-standby.html
    -+  - title: Network Use and Battery Consumption
    -+    path: /topic/performance/power/network/index.html
    -+    section:
    -+    - title: Collecting Network Traffic Data
    -+      path: /topic/performance/power/network/gather-data.html
    -+    - title: Analyzing Data Traffic
    -+      path: /topic/performance/power/network/analyze-data.html
    -+    - title: Optimizing User-Initiated Network Use
    -+      path: /topic/performance/power/network/action-user-traffic.html
    -+    - title: Optimizing App-Initiated Network Use
    -+      path: topic/performance/power/network/action-app-traffic.html
    -+    - title: Optimizing Server-Initiated Network Use
    -+      path: /topic/performance/power/network/action-server-traffic.html
    -+    - title: Optimizing General Network Use
    -+      path: /topic/performance/power/network/action-any-traffic.html
    -+  - title: Doze and App Standby
    -+    path: /training/monitoring-device-state/doze-standby.html
    -+    path_attributes:
    -+    - name: description
    -+      value: Help ensure the device isn't depleting the battery when not in use.
    -+  - title: Battery Historian
    -+    path: /topic/performance/power/battery-historian.html
    -+- title: Rendering
    -+  path: /topic/performance/rendering/index.html
    -   path_attributes:
    -   - name: description
    --    value: Help ensure the device isn't depleting the battery when not in use.
    --- title: Launch-Time Performance
    --  path: /topic/performance/launch-time.html
    --- title: Better Performance through Threading
    --  path: /topic/performance/threads.html
    --- title: Optimizing View Hierarchies
    --  path: /topic/performance/optimizing-view-hierarchies.html
    --- title: Background Optimization
    --  path: /topic/performance/background-optimization.html
    -+    value: Speed up your app's rendering
    -+  section:
    -+  - title: Reducing Overdraw
    -+    path: /topic/performance/rendering/overdraw.html
    -+  - title: Performance and View Hierarchies
    -+    path: /topic/performance/rendering/optimizing-view-hierarchies.html
    -+  - title: Analyzing with Profile GPU Rendering
    -+    path: /topic/performance/rendering/profile-gpu.html
    - - title: Intelligent Job-Scheduling
    -   path: /topic/performance/scheduling.html
    -+- title: Background Optimization
    -+  path: /topic/performance/background-optimization.html
    - - title: Reducing APK Size
    -   path: /topic/performance/reduce-apk-size.html
    -+- title: Reducing Image Download Sizes
    -+  path: /topic/performance/network-xfer.html
    -+- title: Launch-Time Performance
    -+  path: /topic/performance/launch-time.html
    -+- title: Better Performance through Threading
    -+  path: /topic/performance/threads.html
    -+- title: Manage Your App's Memory
    -+  path: /topic/performance/memory.html
    -+- title: Overview of Memory Managemement
    -+  path: /topic/performance/memory-overview.html
    -+  path_attributes:
    -+  - name: description
    -+    value: How to keep your app's memory footprint small in order to improve performance on a variety of mobile devices.
    -+
    -diff --git a/docs/html/topic/performance/background-optimization.jd b/docs/html/topic/performance/background-optimization.jd
    -index 3e4c041..0a1a6f5 100644
    ---- a/docs/html/topic/performance/background-optimization.jd
    -+++ b/docs/html/topic/performance/background-optimization.jd
    -@@ -14,29 +14,31 @@ page.image=images/cards/card-nyc_2x.jpg
    -     <ol>
    -       <li>
    -         <a href="#connectivity-action">Restrictions on CONNECTIVITY_ACTION</a>
    --      </li>
    --
    --      <li>
    --        <a href="#sched-jobs">Scheduling Network Jobs on Unmetered
    --        Connections</a>
    --      </li>
    --
    --      <li>
    --        <a href="#monitor-conn">Monitoring Network Connectivity While the App
    --        is Running</a>
    -+        <ul>
    -+          <li>
    -+            <a href="#sched-jobs">Scheduling Network Jobs on Unmetered
    -+            Connections</a>
    -+          </li>
    -+
    -+          <li>
    -+            <a href="#monitor-conn">Monitoring Network Connectivity While the
    -+            App is Running</a>
    -+          </li>
    -+        </ul>
    -       </li>
    - 
    -       <li>
    -         <a href="#media-broadcasts">Restrictions on NEW_PICTURE and
    -         NEW_VIDEO</a>
    --      </li>
    --
    --      <li>
    --        <a href="#new-jobinfo">New JobInfo methods</a>
    --      </li>
    --
    --      <li>
    --        <a href="#new-jobparam">New JobParameter Methods</a>
    -+        <ul>
    -+          <li>
    -+            <a href="#new-jobinfo">New JobInfo methods</a>
    -+          </li>
    -+
    -+          <li>
    -+            <a href="#new-jobparam">New JobParameter Methods</a>
    -+          </li>
    -+        </ul>
    -       </li>
    - 
    -       <li>
    -@@ -54,12 +56,12 @@ page.image=images/cards/card-nyc_2x.jpg
    - </p>
    - 
    - <p>
    --  To alleviate this issue, Android N applies the following
    -+  To alleviate this issue, Android 7.0 (API level 24) applies the following
    -   restrictions:
    - </p>
    - 
    - <ul>
    --  <li>Apps targeting the Preview do not receive {@link
    -+  <li>Apps targeting Android 7.0 (API level 24) do not receive {@link
    -   android.net.ConnectivityManager#CONNECTIVITY_ACTION} broadcasts if they
    -   register to receive them in their manifest. Apps that are running can still
    -   listen for {@code CONNECTIVITY_CHANGE} on their main thread by registering a
    -@@ -70,16 +72,16 @@ page.image=images/cards/card-nyc_2x.jpg
    -   <li>Apps cannot send or receive {@link
    -   android.hardware.Camera#ACTION_NEW_PICTURE} or {@link
    -   android.hardware.Camera#ACTION_NEW_VIDEO} broadcasts. This optimization
    --  affects all apps, not only those targeting the Preview.
    -+  affects all apps, not only those targeting Android 7.0 (API level 24).
    -   </li>
    - </ul>
    - 
    - <p>
    --  If your app uses any of these intents, you should remove dependencies on
    --  them as soon as possible so that you can target Android N devices properly.
    --  The Android framework provides several solutions to mitigate the need for
    --  these implicit broadcasts. For example, {@link android.app.job.JobScheduler}
    --  and <a href=
    -+  If your app uses any of these intents, you should remove dependencies on them
    -+  as soon as possible so that you can target devices running Android 7.0
    -+  properly. The Android framework provides several solutions to mitigate the
    -+  need for these implicit broadcasts. For example, {@link
    -+  android.app.job.JobScheduler} and <a href=
    -   "https://developers.google.com/android/reference/com/google/android/gms/gcm/GcmNetworkManager">
    -   {@code GcmNetworkManager}</a> provide robust mechanisms to schedule network
    -   operations when specified conditions, such as a connection to an unmetered
    -@@ -101,7 +103,7 @@ page.image=images/cards/card-nyc_2x.jpg
    - </h2>
    - 
    - <p>
    --  Apps targeting the Android N do not receive {@link
    -+  Apps targeting Android 7.0 (API level 24) do not receive {@link
    -   android.net.ConnectivityManager#CONNECTIVITY_ACTION} broadcasts if they
    -   register to receive them in their manifest, and processes that depend on this
    -   broadcast will not start. This could pose a problem for apps that want
    -@@ -198,11 +200,11 @@ public static void scheduleJob(Context context) {
    - </h2>
    - 
    - <p>
    --  In the Android N, apps are not able to send or receive {@link
    -+  In Android 7.0 (API level 24), apps are not able to send or receive {@link
    -   android.hardware.Camera#ACTION_NEW_PICTURE} or {@link
    -   android.hardware.Camera#ACTION_NEW_VIDEO} broadcasts. This restriction helps
    -   alleviate the performance and user experience impacts when several apps must
    --  wake up in order to process a new image or video. Android N
    -+  wake up in order to process a new image or video. Android 7.0 (API level 24)
    -   extends {@link android.app.job.JobInfo} and {@link
    -   android.app.job.JobParameters} to provide an alternative solution.
    - </p>
    -@@ -212,7 +214,7 @@ public static void scheduleJob(Context context) {
    - </h3>
    - 
    - <p>
    --  To trigger jobs on content URI changes, Android N extends
    -+  To trigger jobs on content URI changes, Android 7.0 (API level 24) extends
    -   the {@link android.app.job.JobInfo} API with the following methods:
    - </p>
    - 
    -@@ -287,7 +289,7 @@ public static void scheduleJob(Context context) {
    - </h3>
    - 
    - <p>
    --  Android N also extends {@link android.app.job.JobParameters} to
    -+  Android 7.0 (API level 24) also extends {@link android.app.job.JobParameters} to
    -   allow your app to receive useful information about what content authorities
    -   and URIs triggered the job:
    - </p>
    -@@ -361,13 +363,13 @@ public boolean onStartJob(JobParameters params) {
    -   conditions, can improve performance and user experience. Removing
    -   dependencies on background services and statically-registered implicit
    -   broadcast receivers can help your app run better on such devices. Although
    --  Android N takes steps to reduce some of these issues, it is
    -+  Android 7.0 (API level 24) takes steps to reduce some of these issues, it is
    -   recommended that you optimize your app to run without the use of these
    -   background processes entirely.
    - </p>
    - 
    - <p>
    --  Android N introduces some additional <a href=
    -+  Android 7.0 (API level 24) introduces some additional <a href=
    -   "{@docRoot}tools/help/adb.html">Android Debug Bridge (ADB)</a> commands that
    -   you can use to test app behavior with those background processes disabled:
    - </p>
    -@@ -379,7 +381,7 @@ public boolean onStartJob(JobParameters params) {
    - 
    -   <li style="list-style: none; display: inline">
    - <pre class="no-pretty-print">
    --{@code $ adb shell cmd appops set &lt;package_name&gt; RUN_IN_BACKGROUND ignore}
    -+{@code $ adb shell cmd appops set <package_name> RUN_IN_BACKGROUND ignore}
    - </pre>
    -   </li>
    - 
    -@@ -389,7 +391,7 @@ public boolean onStartJob(JobParameters params) {
    - 
    -   <li style="list-style: none; display: inline">
    - <pre class="no-pretty-print">
    --{@code $ adb shell cmd appops set &lt;package_name&gt; RUN_IN_BACKGROUND allow}
    -+{@code $ adb shell cmd appops set <package_name> RUN_IN_BACKGROUND allow}
    - </pre>
    -   </li>
    - </ul>
    -diff --git a/docs/html/topic/performance/images/app-rankings.png b/docs/html/topic/performance/images/app-rankings.png
    -new file mode 100644
    -index 0000000..9dd60e5
    -Binary files /dev/null and b/docs/html/topic/performance/images/app-rankings.png differ
    -diff --git a/docs/html/topic/performance/images/bars.png b/docs/html/topic/performance/images/bars.png
    -new file mode 100644
    -index 0000000..3afea46
    -Binary files /dev/null and b/docs/html/topic/performance/images/bars.png differ
    -diff --git a/docs/html/topic/performance/images/beforeafterindexed.png b/docs/html/topic/performance/images/beforeafterindexed.png
    -new file mode 100644
    -index 0000000..dc7762e
    -Binary files /dev/null and b/docs/html/topic/performance/images/beforeafterindexed.png differ
    -diff --git a/docs/html/topic/performance/images/comparison.png b/docs/html/topic/performance/images/comparison.png
    -new file mode 100644
    -index 0000000..18f204c
    -Binary files /dev/null and b/docs/html/topic/performance/images/comparison.png differ
    -diff --git a/docs/html/topic/performance/images/decisions.png b/docs/html/topic/performance/images/decisions.png
    -new file mode 100644
    -index 0000000..d4f21f8
    -Binary files /dev/null and b/docs/html/topic/performance/images/decisions.png differ
    -diff --git a/docs/html/topic/performance/images/dropdown.png b/docs/html/topic/performance/images/dropdown.png
    -new file mode 100644
    -index 0000000..59ec6110
    -Binary files /dev/null and b/docs/html/topic/performance/images/dropdown.png differ
    -diff --git a/docs/html/topic/performance/images/generic-timeline.png b/docs/html/topic/performance/images/generic-timeline.png
    -new file mode 100644
    -index 0000000..04388b6
    -Binary files /dev/null and b/docs/html/topic/performance/images/generic-timeline.png differ
    -diff --git a/docs/html/topic/performance/images/moarparrots.png b/docs/html/topic/performance/images/moarparrots.png
    -new file mode 100644
    -index 0000000..ee10ec1
    -Binary files /dev/null and b/docs/html/topic/performance/images/moarparrots.png differ
    -diff --git a/docs/html/topic/performance/images/palette.png b/docs/html/topic/performance/images/palette.png
    -new file mode 100644
    -index 0000000..eb6be6b
    -Binary files /dev/null and b/docs/html/topic/performance/images/palette.png differ
    -diff --git a/docs/html/topic/performance/images/parrot.png b/docs/html/topic/performance/images/parrot.png
    -new file mode 100644
    -index 0000000..7a8b86a
    -Binary files /dev/null and b/docs/html/topic/performance/images/parrot.png differ
    -diff --git a/docs/html/topic/performance/images/pug-visualization.png b/docs/html/topic/performance/images/pug-visualization.png
    -new file mode 100644
    -index 0000000..8270d0e
    -Binary files /dev/null and b/docs/html/topic/performance/images/pug-visualization.png differ
    -diff --git a/docs/html/topic/performance/images/pugspecificdata.png b/docs/html/topic/performance/images/pugspecificdata.png
    -new file mode 100644
    -index 0000000..1c2be83
    -Binary files /dev/null and b/docs/html/topic/performance/images/pugspecificdata.png differ
    -diff --git a/docs/html/topic/performance/images/s-generic-closeup.png b/docs/html/topic/performance/images/s-generic-closeup.png
    -new file mode 100644
    -index 0000000..6685d51
    -Binary files /dev/null and b/docs/html/topic/performance/images/s-generic-closeup.png differ
    -diff --git a/docs/html/topic/performance/images/s-profiler-legend.png b/docs/html/topic/performance/images/s-profiler-legend.png
    -new file mode 100644
    -index 0000000..968fd38
    -Binary files /dev/null and b/docs/html/topic/performance/images/s-profiler-legend.png differ
    -diff --git a/docs/html/topic/performance/images/vq.gif b/docs/html/topic/performance/images/vq.gif
    -new file mode 100644
    -index 0000000..cbf6a35
    -Binary files /dev/null and b/docs/html/topic/performance/images/vq.gif differ
    -diff --git a/docs/html/topic/performance/index.jd b/docs/html/topic/performance/index.jd
    -index e08db15..2b6b197 100644
    ---- a/docs/html/topic/performance/index.jd
    -+++ b/docs/html/topic/performance/index.jd
    -@@ -1,4 +1,4 @@
    --page.title=Performance
    -+page.title=Performance and Power
    - page.article=true
    - page.metaDescription=Improve your app's performance by learning how to optimize power consumption, launch times, and other important areas of performance.
    - 
    -diff --git a/docs/html/topic/performance/memory-overview.jd b/docs/html/topic/performance/memory-overview.jd
    -new file mode 100644
    -index 0000000..58067d2
    ---- /dev/null
    -+++ b/docs/html/topic/performance/memory-overview.jd
    -@@ -0,0 +1,288 @@
    -+page.title=Overview of Android Memory Management
    -+page.tags=ram,memory,paging,mmap
    -+
    -+@jd:body
    -+
    -+<div id="qv-wrapper">
    -+<div id="qv">
    -+
    -+<h2>In this document</h2>
    -+<ol class="nolist">
    -+  <li><a href="#gc">Garbage collection</a></li>
    -+  <li><a href="#SharingRAM">Sharing Memory</a></li>
    -+  <li><a href="#AllocatingRAM">Allocating and Reclaiming App Memory</a></li>
    -+  <li><a href="#RestrictingMemory">Restricting App Memory</a></li>
    -+  <li><a href="#SwitchingApps">Switching Apps</a></li>
    -+</ol>
    -+<h2>See Also</h2>
    -+<ul>
    -+  <li><a href="{@docRoot}training/articles/memory.html">Manage Your App's Memory</a>
    -+  </li>
    -+  <li><a href="{@docRoot}studio/profile/investigate-ram.html">Investigating Your RAM Usage</a>
    -+  </li>
    -+</ul>
    -+
    -+</div>
    -+</div>
    -+
    -+<p>
    -+  The Android Runtime (ART) and Dalvik virtual machine use
    -+  <a href="http://en.wikipedia.org/wiki/Paging" class="external-link">paging</a>
    -+  and <a href="http://en.wikipedia.org/wiki/Memory-mapped_files" class="external-link">memory-mapping</a>
    -+  (mmapping) to manage memory. This means that any memory an app
    -+  modifies&mdash;whether by allocating
    -+  new objects or touching mmapped pages&mdash;remains resident in RAM and
    -+  cannot be paged out. The only way to release memory from an app is to release
    -+  object references that the app holds, making the memory available to the
    -+  garbage collector.
    -+  That is with one exception: any files
    -+  mmapped in without modification, such as code,
    -+  can be paged out of RAM if the system wants to use that memory elsewhere.
    -+</p>
    -+
    -+<p>
    -+  This page explains how Android manages app processes and memory
    -+  allocation. For more information about how to manage memory more efficiently
    -+  in your app, see
    -+  <a href="{@docRoot}training/articles/memory.html">Manage Your App's Memory</a>.
    -+</p>
    -+
    -+<!-- Section 1 #################################################### -->
    -+
    -+<h2 id="gc">Garbage collection</h2>
    -+
    -+<p>
    -+  A managed memory environment, like the ART or Dalvik virtual machine,
    -+  keeps track of each memory allocation. Once it determines
    -+  that a piece of memory is no longer being used by the program,
    -+  it frees it back to the heap, without any intervention from the programmer.
    -+  The mechanism for reclaiming unused memory
    -+  within a managed memory environment
    -+  is known as <i>garbage collection</i>. Garbage collection has two goals:
    -+  find data objects in a program that cannot be accessed in the future; and
    -+  reclaim the resources used by those objects.
    -+</p>
    -+
    -+<p>
    -+  Android’s memory heap is a generational one, meaning that there are
    -+  different buckets of allocations that it tracks,
    -+  based on the expected life and size of an object being allocated.
    -+  For example, recently allocated objects belong in the <i>Young generation</i>.
    -+  When an object stays active long enough, it can be promoted
    -+  to an older generation, followed by a permanent generation.
    -+</p>
    -+
    -+<p>
    -+  Each heap generation has its own dedicated upper limit on the amount
    -+  of memory that objects there can occupy. Any time a generation starts
    -+  to fill up, the system executes a garbage collection
    -+  event in an attempt to free up memory. The duration of the garbage collection
    -+  depends on which generation of objects it's collecting
    -+  and how many active objects are in each generation.
    -+</p>
    -+
    -+<p>
    -+  Even though garbage collection can be quite fast, it can still
    -+  affect your app's performance. You don’t generally control
    -+  when a garbage collection event occurs from within your code.
    -+  The system has a running set of criteria for determining when to perform
    -+  garbage collection. When the criteria are satisfied,
    -+  the system stops executing the process and begins garbage collection. If
    -+  garbage collection occurs in the middle of an intensive processing loop
    -+  like an animation or during music playback, it can increase processing time.
    -+  This increase can potentially push code execution in your app past the
    -+  recommended 16ms threshold for efficient and smooth frame rendering.
    -+</p>
    -+
    -+<p>
    -+  Additionally, your code flow may perform kinds of work that
    -+  force garbage collection events to occur
    -+  more often or make them last longer-than-normal.
    -+  For example, if you allocate multiple objects in the
    -+  innermost part of a for-loop during each frame of an alpha
    -+  blending animation, you might pollute your memory heap with a
    -+  lot of objects.
    -+  In that circumstance, the garbage collector executes multiple garbage
    -+  collection events and can degrade the performance of your app.
    -+</p>
    -+
    -+<p>
    -+  For more general information about garbage collection, see
    -+  <a href="https://en.wikipedia.org/wiki/Garbage_collection_(computer_science)"
    -+  class="external-link">Garbage collection</a>.
    -+</p>
    -+
    -+<!-- Section 2 #################################################### -->
    -+
    -+<h2 id="SharingRAM">Sharing Memory</h2>
    -+
    -+<p>
    -+  In order to fit everything it needs in RAM,
    -+  Android tries to share RAM pages across processes. It
    -+  can do so in the following ways:
    -+</p>
    -+
    -+<ul>
    -+  <li>
    -+    Each app process is forked from an existing process called Zygote.
    -+    The Zygote process starts when the system boots and loads common
    -+    framework code and resources
    -+    (such as activity themes). To start a new app process,
    -+    the system forks the Zygote process then
    -+    loads and runs the app's code in the new process.
    -+    This approach allows most of the RAM pages allocated for
    -+    framework code and resources to be shared across all app processes.
    -+  </li>
    -+
    -+  <li>
    -+    Most static data is mmapped into a process.
    -+    This technique allows data to be shared
    -+    between processes, and also allows it to be paged
    -+    out when needed. Example static data include:
    -+    Dalvik code (by placing it in a pre-linked <code>.odex</code>
    -+    file for direct mmapping), app resources
    -+    (by designing the resource table to be a structure
    -+    that can be mmapped and by aligning the zip
    -+    entries of the APK), and traditional project
    -+    elements like native code in <code>.so</code> files.
    -+  </li>
    -+
    -+  <li>
    -+    In many places, Android shares the same dynamic
    -+    RAM across processes using explicitly allocated
    -+    shared memory regions (either with ashmem or gralloc).
    -+    For example, window surfaces use shared
    -+    memory between the app and screen compositor, and
    -+    cursor buffers use shared memory between the
    -+    content provider and client.
    -+  </li>
    -+</ul>
    -+
    -+<p>
    -+  Due to the extensive use of shared memory, determining
    -+  how much memory your app is using requires
    -+  care. Techniques to properly determine your app's
    -+  memory use are discussed in
    -+  <a href="{@docRoot}studio/profile/investigate-ram.html">Investigating Your RAM Usage</a>.
    -+</p>
    -+
    -+<!-- Section 3 #################################################### -->
    -+
    -+<h2 id="AllocatingRAM">Allocating and Reclaiming App Memory</h2>
    -+
    -+<p>
    -+  The Dalvik heap is constrained to a
    -+  single virtual memory range for each app process. This defines
    -+  the logical heap size, which can grow as it needs to
    -+  but only up to a limit that the system defines
    -+  for each app.
    -+</p>
    -+
    -+<p>
    -+  The logical size of the heap is not the same as
    -+  the amount of physical memory used by the heap.
    -+  When inspecting your app's heap, Android computes
    -+  a value called the Proportional Set Size (PSS),
    -+  which accounts for both dirty and clean pages
    -+  that are shared with other processes—but only in an
    -+  amount that's proportional to how many apps share
    -+  that RAM. This (PSS) total is what the system
    -+  considers to be your physical memory footprint.
    -+  For more information about PSS, see the
    -+  <a href="{@docRoot}studio/profile/investigate-ram.html">Investigating Your RAM Usage</a>
    -+  guide.
    -+</p>
    -+
    -+<p>
    -+  The Dalvik heap does not compact the logical
    -+  size of the heap, meaning that Android does not
    -+  defragment the heap to close up space. Android
    -+  can only shrink the logical heap size when there
    -+  is unused space at the end of the heap. However,
    -+  the system can still reduce physical memory used by the heap.
    -+  After garbage collection, Dalvik
    -+  walks the heap and finds unused pages, then returns
    -+  those pages to the kernel using madvise. So, paired
    -+  allocations and deallocations of large
    -+  chunks should result in reclaiming all (or nearly all)
    -+  the physical memory used. However,
    -+  reclaiming memory from small allocations can be much
    -+  less efficient because the page used
    -+  for a small allocation may still be shared with
    -+  something else that has not yet been freed.
    -+
    -+</p>
    -+
    -+<!-- Section 4 #################################################### -->
    -+
    -+<h2 id="RestrictingMemory">Restricting App Memory</h2>
    -+
    -+<p>
    -+  To maintain a functional multi-tasking environment,
    -+  Android sets a hard limit on the heap size
    -+  for each app. The exact heap size limit varies
    -+  between devices based on how much RAM the device
    -+  has available overall. If your app has reached the
    -+  heap capacity and tries to allocate more
    -+  memory, it can receive an {@link java.lang.OutOfMemoryError}.
    -+</p>
    -+
    -+<p>
    -+  In some cases, you might want to query the
    -+  system to determine exactly how much heap space you
    -+  have available on the current device—for example, to
    -+  determine how much data is safe to keep in a
    -+  cache. You can query the system for this figure by calling
    -+  {@link android.app.ActivityManager#getMemoryClass() }.
    -+  This method returns an integer indicating the number of
    -+  megabytes available for your app's heap.
    -+</p>
    -+
    -+<!-- Section 5 #################################################### -->
    -+
    -+<h2 id="SwitchingApps">Switching apps</h2>
    -+
    -+<p>
    -+  When users switch between apps,
    -+  Android keeps apps that
    -+  are not foreground&mdash;that is, not visible to the user or running a
    -+  foreground service like music playback&mdash;
    -+  in a least-recently used (LRU) cache.
    -+  For example, when a user first launches an app,
    -+  a process is created for it; but when the user
    -+  leaves the app, that process does <em>not</em> quit.
    -+  The system keeps the process cached. If
    -+  the user later returns to the app, the system reuses the process, thereby
    -+  making the app switching faster.
    -+</p>
    -+
    -+<p>
    -+  If your app has a cached process and it retains memory
    -+  that it currently does not need,
    -+  then your app&mdash;even while the user is not using it&mdash;
    -+  affects the system's
    -+  overall performance. As the system runs low on memory,
    -+  it kills processes in the LRU cache
    -+  beginning with the process least recently used. The system also
    -+  accounts for processes that hold onto the most memory
    -+  and can terminate them to free up RAM.
    -+</p>
    -+
    -+<p class="note">
    -+  <strong>Note:</strong> When the system begins killing processes in the
    -+  LRU cache, it primarily works bottom-up. The system also considers which
    -+  processes consume more memory and thus provide the system
    -+  more memory gain if killed.
    -+  The less memory you consume while in the LRU list overall,
    -+  the better your chances are
    -+  to remain in the list and be able to quickly resume.
    -+</p>
    -+
    -+<p>
    -+  For more information about how processes are cached while
    -+  not running in the foreground and how
    -+  Android decides which ones
    -+  can be killed, see the
    -+  <a href="{@docRoot}guide/components/processes-and-threads.html">Processes and Threads</a>
    -+  guide.
    -+</p>
    -diff --git a/docs/html/topic/performance/memory.jd b/docs/html/topic/performance/memory.jd
    -new file mode 100644
    -index 0000000..ef1c4ae
    ---- /dev/null
    -+++ b/docs/html/topic/performance/memory.jd
    -@@ -0,0 +1,593 @@
    -+page.title=Manage Your App's Memory
    -+page.tags=ram,low memory,OutOfMemoryError,onTrimMemory
    -+
    -+@jd:body
    -+
    -+<div id="qv-wrapper">
    -+<div id="qv">
    -+
    -+<h2>In this document</h2>
    -+<ol>
    -+  <li><a href="#monitor">Monitor Available Memory and Memory Usage</a>
    -+    <ul>
    -+      <li><a href="#AnalyzeRam">Tools for analyzing RAM usage</a></li>
    -+      <li><a href="#release">Release memory in response to events</a></li>
    -+      <li><a href="#CheckHowMuchMemory">Check how much memory you should use</a></li>
    -+    </ul>
    -+  </li>
    -+  <li><a href="#code">Use More Efficient Code Constructs</a>
    -+    <ul>
    -+      <li><a href="#Services">Use services sparingly</a></li>
    -+      <li><a href="#DataContainers">Use optimized data containers</a></li>
    -+      <li><a href="#Abstractions">Be careful with code abstractions</a></li>
    -+      <li><a href="#NanoProto">Use nano protobufs for serialized data</a></li>
    -+      <li><a href="#churn">Avoid memory churn</a></li>
    -+    </ul>
    -+  </li>
    -+  <li><a href="#remove">Remove Memory-Intensive Resources and Libraries</a>
    -+    <ul>
    -+      <li><a href="#reduce">Reduce overall APK size</a></li>
    -+      <li><a href="#DependencyInjection">Avoid dependency injection frameworks</a></li>
    -+      <li><a href="#ExternalLibs">Be careful about using external libraries</a></li>
    -+    </ul>
    -+  </li>
    -+</ol>
    -+<h2>See Also</h2>
    -+<ul>
    -+  <li><a href="{@docRoot}training/articles/memory-overview.html">Overview of Android Memory Management</a>
    -+  </li>
    -+  <li><a href="{@docRoot}studio/profile/investigate-ram.html">Investigating Your RAM Usage</a>
    -+  </li>
    -+  <li><a href="{@docRoot}topic/performance/reduce-apk-size.html">Reduce APK Size</a></li>
    -+</ul>
    -+
    -+</div>
    -+</div>
    -+
    -+<!-- INTRO #################################################### -->
    -+
    -+<p>
    -+  Random-access memory (RAM) is a valuable
    -+  resource in any software development environment, but
    -+  it's even more valuable on a mobile operating system
    -+  where physical memory is often constrained.
    -+  Although both the Android Runtime (ART) and Dalvik virtual machine perform
    -+  routine garbage collection, this does not mean you can ignore
    -+  when and where your app allocates and releases memory.
    -+  You still need to avoid
    -+  introducing memory leaks, usually caused by holding onto
    -+  object references in static member variables, and
    -+  release any {@link java.lang.ref.Reference} objects at the appropriate
    -+  time as defined by
    -+  lifecycle callbacks.
    -+</p>
    -+
    -+<p>
    -+  This page explains how you can
    -+  proactively reduce memory usage within your app.
    -+  For more information about general
    -+  practices to clean up your resources when programming in Java,
    -+  refer to other books or online
    -+  documentation about managing resource references.
    -+  If you’re looking for information about how to
    -+  analyze memory in a running app, read
    -+  <a href="#AnalyzeRam">Tools for analyzing RAM usage</a>.
    -+  For more detailed information about how the Android Runtime and Dalvik
    -+  virtual machine manage memory, see the
    -+  <a href="{@docRoot}training/articles/memory-overview.html">Overview of Android Memory Management</a>.
    -+</p>
    -+
    -+<!-- Section 1 #################################################### -->
    -+
    -+<h2 id="monitor">Monitor Available Memory and Memory Usage</h2>
    -+
    -+<p>
    -+  The Android framework, Android Studio, and Android SDK
    -+  can help you analyze and adjust your app's memory usage.
    -+  The Android framework
    -+  exposes several APIs that allow your app to reduce its memory usage
    -+  dynamically during runtime. Android Studio and the Android SDK
    -+  contain several tools  that allow you to investigate how your
    -+  app uses memory.
    -+</p>
    -+
    -+<!-- Section 1.1 #################################################### -->
    -+
    -+<h3 id="AnalyzeRam">Tools for analyzing RAM usage</h3>
    -+
    -+<p>
    -+  Before you can fix the memory usage problems in your app, you first need
    -+  to find them. Android Studio and the Android SDK include several tools
    -+  for analyzing memory usage in your app:
    -+</p>
    -+
    -+<ol>
    -+  <li>
    -+    The Device Monitor has a Dalvik Debug Monitor Server (DDMS) tool that allows
    -+    you to inspect memory allocation within your app process.
    -+    You can use this information to understand how your
    -+    app uses memory overall. For example, you can force a garbage collection
    -+    event and then view the types of objects that remain in memory. You can
    -+    use this information to identify operations or actions within your app
    -+    that allocate or leave excessive amounts of objects in memory.
    -+
    -+    <p>For more information about how to use the DDMS tool, see
    -+      <a href="/studio/profile/ddms.html">Using DDMS</a>.
    -+    </p>
    -+  </li>
    -+
    -+  <li>
    -+    The Memory Monitor in Android Studio shows you how your app allocates
    -+    memory over the course of a single session.
    -+    The tool shows a graph of available
    -+    and allocated Java memory over time, including garbage collection events.
    -+    You can also initiate garbage collection events and take a snapshot of
    -+    the Java heap while your app runs. The output from the Memory Monitor tool
    -+    can help you identify points when your app experiences excessive garbage
    -+    collection events, leading to app slowness.
    -+    <p>
    -+      For more information about how to use Memory Monitor tool, see
    -+      <a href="{@docRoot}tools/debugging/debugging-memory.html#ViewHeap">Viewing Heap Updates</a>.
    -+    </p>
    -+  </li>
    -+
    -+  <li>
    -+    Garbage collection events also show up in the Traceview viewer. Traceview
    -+    allows you to view trace log files as both a timeline and as a profile
    -+    of what happened within a method. You can use this tool to determine
    -+    what code was executing when a garbage collection event occurred.
    -+    <p>
    -+      For more information about how to use the Traceview viewer, see
    -+      <a href="https://developer.android.com/studio/profile/traceview.html">Profiling with Traceview and dmtracedump</a>.
    -+    </p>
    -+  </li>
    -+
    -+  <li>
    -+    The Allocation Tracker tool in Android Studio gives you a detailed look
    -+    at how your app allocates memory.
    -+    The Allocation Tracker records an app's memory allocations and lists
    -+    all allocated objects within the profiling snapshot. You can use this
    -+    tool to track down parts of your code that allocate too many objects.
    -+
    -+    <p>
    -+      For more information about how to use the Allocation Tracker tool, see
    -+      <a href="{docRoot}studio/profile/allocation-tracker-walkthru.html">Allocation Tracker Walkthrough</a>.
    -+    </p>
    -+  </li>
    -+
    -+</ol>
    -+
    -+<!-- Section 1.2 #################################################### -->
    -+
    -+<h3 id="release">Release memory in response to events</h3>
    -+
    -+<p>
    -+  An Android device can run with varying amounts of free memory
    -+  depending on the physical amount of RAM on the device and how the user
    -+  operates it. The system broadcasts signals to indicate when it is under
    -+  memory pressure, and apps should listen for these signals and adjust
    -+  their memory usage as appropriate.
    -+</p>
    -+
    -+</p>
    -+  You can use the {@link android.content.ComponentCallbacks2} API
    -+  to listen for these signals and then adjust your memory
    -+  usage in response to app lifecycle
    -+  or device events. The
    -+  {@link android.content.ComponentCallbacks2#onTrimMemory onTrimMemory()}
    -+  method allows your app to listen for memory related events when the app runs
    -+  in the foreground (is visible) and when it runs in the background.
    -+</p>
    -+
    -+<p>
    -+  To listen for these events, implement the {@link
    -+  android.content.ComponentCallbacks2#onTrimMemory onTrimMemory()}
    -+  callback in your {@link android.app.Activity}
    -+  classes, as shown in the following code snippet.
    -+</p>
    -+
    -+<pre class="prettyprint">
    -+import android.content.ComponentCallbacks2;
    -+// Other import statements ...
    -+
    -+public class MainActivity extends AppCompatActivity
    -+    implements ComponentCallbacks2 {
    -+
    -+    // Other activity code ...
    -+
    -+    /**
    -+     * Release memory when the UI becomes hidden or when system resources become low.
    -+     * @param level the memory-related event that was raised.
    -+     */
    -+    public void onTrimMemory(int level) {
    -+
    -+        // Determine which lifecycle or system event was raised.
    -+        switch (level) {
    -+
    -+            case ComponentCallbacks2.TRIM_MEMORY_UI_HIDDEN:
    -+
    -+                /*
    -+                   Release any UI objects that currently hold memory.
    -+
    -+                   The user interface has moved to the background.
    -+                */
    -+
    -+                break;
    -+
    -+            case ComponentCallbacks2.TRIM_MEMORY_RUNNING_MODERATE:
    -+            case ComponentCallbacks2.TRIM_MEMORY_RUNNING_LOW:
    -+            case ComponentCallbacks2.TRIM_MEMORY_RUNNING_CRITICAL:
    -+
    -+                /*
    -+                   Release any memory that your app doesn't need to run.
    -+
    -+                   The device is running low on memory while the app is running.
    -+                   The event raised indicates the severity of the memory-related event.
    -+                   If the event is TRIM_MEMORY_RUNNING_CRITICAL, then the system will
    -+                   begin killing background processes.
    -+                */
    -+
    -+                break;
    -+
    -+            case ComponentCallbacks2.TRIM_MEMORY_BACKGROUND:
    -+            case ComponentCallbacks2.TRIM_MEMORY_MODERATE:
    -+            case ComponentCallbacks2.TRIM_MEMORY_COMPLETE:
    -+
    -+                /*
    -+                   Release as much memory as the process can.
    -+
    -+                   The app is on the LRU list and the system is running low on memory.
    -+                   The event raised indicates where the app sits within the LRU list.
    -+                   If the event is TRIM_MEMORY_COMPLETE, the process will be one of
    -+                   the first to be terminated.
    -+                */
    -+
    -+                break;
    -+
    -+            default:
    -+                /*
    -+                  Release any non-critical data structures.
    -+
    -+                  The app received an unrecognized memory level value
    -+                  from the system. Treat this as a generic low-memory message.
    -+                */
    -+                break;
    -+        }
    -+    }
    -+}
    -+</pre>
    -+
    -+<p>
    -+  The
    -+  {@link android.content.ComponentCallbacks2#onTrimMemory onTrimMemory()}
    -+  callback was added in Android 4.0 (API level 14). For earlier versions,
    -+  you can use the
    -+  {@link android.content.ComponentCallbacks#onLowMemory()}
    -+  callback as a fallback for older versions, which is roughly equivalent to the
    -+  {@link android.content.ComponentCallbacks2#TRIM_MEMORY_COMPLETE} event.
    -+</p>
    -+
    -+<!-- Section 1.3 #################################################### -->
    -+
    -+<h3 id="CheckHowMuchMemory">Check how much memory you should use</h3>
    -+
    -+<p>
    -+  To allow multiple running processes, Android sets a hard limit
    -+  on the heap size alloted for each app. The exact heap size limit varies
    -+  between devices based on how much RAM the device
    -+  has available overall. If your app has reached the heap capacity and
    -+  tries to allocate more
    -+  memory, the system throws an {@link java.lang.OutOfMemoryError}.
    -+</p>
    -+
    -+<p>
    -+  To avoid running out of memory, you can to query the system to determine
    -+  how much heap space you have available on the current device.
    -+  You can query the system for this figure by calling
    -+  {@link android.app.ActivityManager#getMemoryInfo(android.app.ActivityManager.MemoryInfo) getMemoryInfo()}.
    -+  This returns an
    -+  {@link android.app.ActivityManager.MemoryInfo } object that provides
    -+  information about the device's
    -+  current memory status, including available memory, total memory, and
    -+  the memory threshold&mdash;the memory level below which the system begins
    -+  to kill processes. The
    -+  {@link android.app.ActivityManager.MemoryInfo } class also exposes a simple
    -+  boolean field,
    -+  {@link android.app.ActivityManager.MemoryInfo#lowMemory }
    -+  that tells you whether the device is running low on memory.
    -+</p>
    -+
    -+<p>
    -+  The following code snippet shows an example of how you can use the
    -+  {@link android.app.ActivityManager#getMemoryInfo(android.app.ActivityManager.MemoryInfo) getMemoryInfo()}.
    -+  method in your application.
    -+</p>
    -+
    -+<pre class="prettyprint">
    -+public void doSomethingMemoryIntensive() {
    -+
    -+    // Before doing something that requires a lot of memory,
    -+    // check to see whether the device is in a low memory state.
    -+    ActivityManager.MemoryInfo memoryInfo = getAvailableMemory();
    -+
    -+    if (!memoryInfo.lowMemory) {
    -+        // Do memory intensive work ...
    -+    }
    -+}
    -+
    -+// Get a MemoryInfo object for the device's current memory status.
    -+private ActivityManager.MemoryInfo getAvailableMemory() {
    -+    ActivityManager activityManager = (ActivityManager) this.getSystemService(ACTIVITY_SERVICE);
    -+    ActivityManager.MemoryInfo memoryInfo = new ActivityManager.MemoryInfo();
    -+    activityManager.getMemoryInfo(memoryInfo);
    -+    return memoryInfo;
    -+}
    -+</pre>
    -+
    -+<!-- Section 2 #################################################### -->
    -+
    -+<h2 id="code">Use More Memory-Efficient Code Constructs</h2>
    -+
    -+<p>
    -+  Some Android features, Java classes, and code constructs tend to
    -+  use more memory than others. You can minimize how
    -+  much memory your app uses by choosing more efficient alternatives in
    -+  your code.
    -+</p>
    -+
    -+<!-- Section 2.1 #################################################### -->
    -+
    -+<h3 id="Services">Use services sparingly</h3>
    -+
    -+<p>
    -+  Leaving a service running when it’s not needed is
    -+  <strong>one of the worst memory-management
    -+  mistakes</strong> an Android app can make. If your app needs a
    -+  <a href="{@docRoot}guide/components/services.html">service</a>
    -+  to perform work in the background, do not keep it running unless
    -+  it needs to run a job. Remember to stop your service when it has completed
    -+  its task. Otherwise, you can inadvertently cause a memory leak.
    -+</p>
    -+
    -+<p>
    -+  When you start a service, the system prefers to always keep the process
    -+  for that service running. This behavior
    -+  makes services processes very expensive
    -+  because the RAM used by a service remains unavailable to other processes.
    -+  This reduces the number of cached processes that the system can keep in
    -+  the LRU cache, making app switching less efficient. It can even lead to
    -+  thrashing in the system when memory is tight and the system can’t
    -+  maintain enough processes to host all the services currently running.
    -+</p>
    -+
    -+<p>
    -+  You should generally avoid use of persistent services because of
    -+  the on-going demands they place on available memory. Instead, we
    -+  recommend that you use an alternative implementation
    -+  such as {@link android.app.job.JobScheduler}. For more information about
    -+  how to use {@link android.app.job.JobScheduler} to schedule background
    -+  processes, see
    -+  <a href="/topic/performance/background-optimization.html">Background Optimizations</a>.
    -+<p>
    -+  If you must use a service, the
    -+  best way to limit the lifespan of your service is to use an {@link
    -+  android.app.IntentService}, which finishes
    -+  itself as soon as it's done handling the intent that started it.
    -+  For more information, read
    -+  <a href="{@docRoot}training/run-background-service/index.html">Running in a Background Service</a>.
    -+</p>
    -+
    -+<!-- Section 2.2 #################################################### -->
    -+
    -+<h3 id="DataContainers">Use optimized data containers</h3>
    -+
    -+<p>
    -+  Some of the classes provided by the programming language are not optimized for
    -+  use on mobile devices. For example, the generic
    -+  {@link java.util.HashMap} implementation can be quite memory
    -+  inefficient because it needs a separate entry object for every mapping.
    -+</p>
    -+
    -+<p>
    -+  The Android framework includes several optimized data containers, including
    -+  {@link android.util.SparseArray}, {@link android.util.SparseBooleanArray},
    -+  and {@link android.support.v4.util.LongSparseArray}.
    -+  For example, the {@link android.util.SparseArray} classes are more
    -+  efficient because they avoid the system's need to
    -+  <acronym title="Automatic conversion from primitive types to object classes (such as int to Integer)">autobox</acronym>
    -+  the key and sometimes value (which creates yet another object or
    -+  two per entry).
    -+</p>
    -+
    -+<p>
    -+  If necessary, you can always switch to raw arrays for a really lean data
    -+  structure.
    -+</p>
    -+
    -+<!-- Section 2.3 #################################################### -->
    -+
    -+<h3 id="Abstractions">Be careful with code abstractions</h3>
    -+
    -+<p>
    -+  Developers often use abstractions simply as a good programming practice,
    -+  because abstractions can improve code flexibility and maintenance.
    -+  However, abstractions come at a significant cost:
    -+  generally they require a fair amount more code that
    -+  needs to be executed, requiring more time and
    -+  more RAM for that code to be mapped into memory.
    -+  So if your abstractions aren't supplying a
    -+  significant benefit, you should avoid them.
    -+</p>
    -+
    -+<p>
    -+  For example, enums often require more than twice as much memory as static
    -+  constants. You should strictly avoid using enums on Android.
    -+</p>
    -+
    -+<!-- Section 2.4 #################################################### -->
    -+
    -+<h3 id="NanoProto">Use nano protobufs for serialized data</h3>
    -+
    -+<p>
    -+  <a href="https://developers.google.com/protocol-buffers/docs/overview">Protocol buffers</a>
    -+  are a language-neutral, platform-neutral, extensible mechanism
    -+  designed by Google for serializing structured data&mdash;similar to XML, but
    -+  smaller, faster, and simpler. If you decide to use
    -+  protobufs for your data, you should always use nano protobufs in your
    -+  client-side code. Regular protobufs generate extremely verbose code, which
    -+  can cause many kinds of problems in your app such as
    -+  increased RAM use, significant APK size increase, and slower execution.
    -+</p>
    -+
    -+<p>
    -+  For more information, see the "Nano version" section in the
    -+  <a href="https://android.googlesource.com/platform/external/protobuf/+/master/java/README.txt"
    -+class="external-link">protobuf readme</a>.
    -+</p>
    -+
    -+<!-- Section 2.5 #################################################### -->
    -+
    -+<h3 id="churn">Avoid memory churn</h3>
    -+
    -+<p>
    -+  As mentioned previously, garbage collections events don't normally affect
    -+  your app's performance. However, many garbage collection events that occur
    -+  over a short period of time can quickly eat up your frame time. The more time
    -+  that the system spends on garbage collection, the less time it has to do
    -+  other stuff like rendering or streaming audio.
    -+</p>
    -+
    -+<p>
    -+  Often, <em>memory churn</em> can cause a large number of
    -+  garbage collection events to occur. In practice, memory churn describes the
    -+  number of allocated temporary objects that occur in a given amount of time.
    -+</p>
    -+
    -+<p>
    -+  For example, you might allocate multiple temporary objects within a
    -+  <code>for</code> loop. Or you might create new
    -+  {@link android.graphics.Paint} or {@link android.graphics.Bitmap}
    -+  objects inside the
    -+  {@link android.view.View#onDraw(android.graphics.Canvas) onDraw()}
    -+  function of a view.
    -+  In both cases, the app creates a lot of objects quickly at high volume.
    -+  These can quickly consume all the available memory in the young generation,
    -+  forcing a garbage collection event to occur.
    -+</p>
    -+
    -+<p>
    -+  Of course, you need to find the places in your code where
    -+  the memory churn is high before you can fix them. Use the tools discussed in
    -+  <a href="#AnalyzeRam">Analyze your RAM usage</a>
    -+</p>
    -+
    -+<p>
    -+  Once you identify the problem areas in your code, try to reduce the number of
    -+  allocations within performance critical areas. Consider moving things out of
    -+  inner loops or perhaps moving them into a
    -+  <a href="https://en.wikipedia.org/wiki/Factory_method_pattern" class="external-link">Factory</a>
    -+  based allocation structure.
    -+</p>
    -+
    -+<!-- Section 3 #################################################### -->
    -+
    -+<h2 id="remove">Remove Memory-Intensive Resources and Libraries</h2>
    -+
    -+<p>
    -+  Some resources and libraries within your code can gobble up memory without
    -+  you knowing it. Overall size of your APK, including third-party libraries
    -+  or embedded resources, can affect how much memory your app consumes. You can
    -+  improve your app's memory consumption by removing any redundant, unnecessary,
    -+  or bloated components, resources, or libraries from your code.
    -+</p>
    -+
    -+<!-- Section 3.1 #################################################### -->
    -+
    -+<h3 id="reduce">Reduce overall APK size</h3>
    -+
    -+<p>
    -+  You can significantly reduce your app's memory usage by reducing the overall
    -+  size of your app. Bitmap size, resources, animation frames, and third-party
    -+  libraries can all contribute to the size of your APK.
    -+  Android Studio and the Android SDK provide multiple tools
    -+  to help you reduce the size of your resources and external dependencies.
    -+</p>
    -+
    -+<p>
    -+  For more information about how to reduce your overall APK size, see
    -+  <a href="{@docRoot}topic/performance/reduce-apk-size.html">Reduce APK Size</a>.
    -+</p>
    -+
    -+<!-- Section 3.2 #################################################### -->
    -+
    -+<h3 id="DependencyInjection">Use caution with dependency injection frameworks</h3>
    -+
    -+<p>
    -+  Dependency injection framework such as
    -+  <a href="https://code.google.com/p/google-guice/" class="external-link">Guice</a>
    -+  or
    -+  <a href="https://github.com/roboguice/roboguice" class="external-link">RoboGuice</a>
    -+  can simplify the code you write and provide an adaptive environment
    -+  that's useful for testing and other configuration changes. However, dependency
    -+  frameworks aren't always optimized for mobile devices.
    -+</p>
    -+
    -+<p>
    -+  For example, these frameworks tend to initialize processes by
    -+  scanning your code for annotations. This which can require significant
    -+  amounts of your code to be mapped into RAM unnecessarily. The system
    -+  allocates these mapped pages into clean memory so Android can drop them; yet
    -+  that can't happen until the pages have remained in memory for a long period
    -+  of time.
    -+ </p>
    -+
    -+<p>
    -+  If you need to use a dependency injection framework in your app, consider
    -+  using
    -+  <a class="external-link" href="http://google.github.io/dagger/">Dagger</a>
    -+  instead. For example, Dagger does not use reflection to scan your app's code.
    -+  Dagger's strict implementation means that it can be used in Android apps
    -+  without needlessly increasing memory usage.
    -+</p>
    -+
    -+<!-- Section 3.3 #################################################### -->
    -+
    -+<h3 id="ExternalLibs">Be careful about using external libraries</h3>
    -+
    -+<p>
    -+  External library code is often not written for mobile environments and
    -+  can be inefficient when used
    -+  for work on a mobile client. When you decide to use an
    -+  external library, you may need to optimize that library for mobile devices.
    -+  Plan for that work up-front and analyze the library in terms of code size and
    -+  RAM footprint before deciding to use it at all.
    -+</p>
    -+
    -+<p>
    -+  Even some mobile-optimized libraries can cause problems due to differing
    -+  implementations. For example, one library may use nano protobufs
    -+  while another uses micro protobufs, resulting in two different protobuf
    -+  implementations in your app. This can happen with different
    -+  implementations of logging, analytics, image loading frameworks,
    -+  caching, and many other things you don't expect.
    -+</p>
    -+
    -+<p>
    -+  Although <a href="{@docRoot}tools/help/proguard.html">ProGuard</a> can
    -+  help to remove APIs and resources with the right flags, it can't remove a
    -+  library's large internal dependencies. The features that you want in these
    -+  libraries may require lower-level dependencies. This becomes especially
    -+  problematic when you use an {@link android.app.Activity } subclass from a
    -+  library (which will tend to have wide swaths of dependencies),
    -+  when libraries use reflection (which is common and means you need to spend a
    -+  lot of time manually tweaking ProGuard to get it to work), and so on.
    -+</p>
    -+
    -+<p>
    -+  Also avoid using a shared library for just one or two features out of dozens.
    -+  You don't want to pull in a large amount of code and overhead that
    -+  you don't even use. When you consider whether to use a library, look for
    -+  an implementation that strongly matches what you need. Otherwise, you might
    -+  decide to create your own implementation.
    -+</p>
    -+
    -diff --git a/docs/html/topic/performance/network-xfer.jd b/docs/html/topic/performance/network-xfer.jd
    -new file mode 100644
    -index 0000000..7fe5594
    ---- /dev/null
    -+++ b/docs/html/topic/performance/network-xfer.jd
    -@@ -0,0 +1,374 @@
    -+page.title=Reducing Image Download Sizes
    -+page.metaDescription=Improve network performance by optimizing image size.
    -+
    -+meta.tags="performance"
    -+page.tags="performance"
    -+
    -+@jd:body
    -+
    -+<div id="qv-wrapper">
    -+<div id="qv">
    -+
    -+<h2>In this document</h2>
    -+    <ol>
    -+
    -+      <li>
    -+        <a href="#uif">Understanding Image Formats</a>
    -+        <ul>
    -+           <li><a href="#png">PNG</a></li>
    -+           <li><a href="#jpg">JPG</a></li>
    -+           <li><a href="#webp">WebP</a></li>
    -+        </ul>
    -+      </li>
    -+      <li>
    -+        <a href="#sf">Selecting a Format</a></li>
    -+      <li><a href="#doqv">Determining Optimal Quality Values</a>
    -+        <ul>
    -+           <li><a href="#sv">Scalar Values (JPG, WebP only)</a></li>
    -+           <li><a href="#butter">Butteraugli</a></li>
    -+        </ul>
    -+      </li>
    -+      <li><a href="#sizes">Serving Sizes</a></li>
    -+    </ol>
    -+  </div>
    -+</div>
    -+
    -+<p>
    -+Most download traffic consists of images. As a result, the smaller you can make
    -+your downloadable images, the better a network experience your app can provide
    -+for users. This page provides guidance on making image files smaller and more
    -+network-friendly.
    -+</p>
    -+
    -+<h2 id="uif">Understanding Image Formats</h2>
    -+
    -+<p>Android apps typically use images that are in one or more of the following file
    -+formats: PNG, JPG, and WebP. For each of these formats, there are steps you can
    -+take to reduce image sizes.
    -+</p>
    -+
    -+<h3 id="png">PNG</h3>
    -+
    -+<p>
    -+A key to making your PNG files smaller is reducing the number of unique
    -+colors used in each row of pixels that comprises the image. By using fewer
    -+colors, you improve the compression potential at all of the other stages of
    -+the pipeline.
    -+</p>
    -+
    -+<p>
    -+Reducing the number of unique colors makes a significant difference because PNG
    -+compression effectiveness is partly a function of the degree to which
    -+horizontally adjacent pixel colors vary. Thus, reducing the number of unique
    -+colors in each row of your PNG images can help in reducing their file sizes.
    -+</p>
    -+
    -+<p>
    -+When deciding whether to pursue this strategy, you should keep in mind that
    -+reducing the number of unique colors effectively amounts to applying a lossy
    -+encoding stage to the image. However, an encoding tool may not be a good
    -+judge of how bad a seemingly small error looks to the human eye. Therefore,
    -+you should perform this work manually in order to help ensure
    -+the right balance between efficient compression and acceptable image quality.
    -+</p>
    -+
    -+<p>
    -+There are two particularly useful approaches you can take: striving for indexed
    -+formats, and applying vector quantization.
    -+</p>
    -+
    -+
    -+<h4 id="strive">Strive for indexed formats</h4>
    -+
    -+<p>
    -+Any attempt at color reduction should start with trying to optimize your colors
    -+so that you can use the INDEXED format when exporting the image as a PNG. The
    -+INDEXED color mode works by choosing the best 256 colors to use, and replacing
    -+all pixel values with indices into that color palette. The result is a
    -+reduction from 16 million (potential) colors to only 256 colors: from 3 (without
    -+transparency) or 4 (with transparency) bytes per pixel to 1 byte per pixel.
    -+This change is a significant first-step file size reduction.
    -+</p>
    -+
    -+<p>
    -+Figure 1 shows shows an image and its indexed variant.
    -+</p>
    -+
    -+  <img src="{@docRoot}topic/performance/images/beforeafterindexed.png">
    -+  <p class="img-caption">
    -+Figure 1. An image before and after conversion to the INDEXED format.
    -+  </p>
    -+
    -+
    -+<p>
    -+Figure 2 shows the color palette for the image in Figure 1:
    -+</p>
    -+
    -+  <img src="{@docRoot}topic/performance/images/palette.png">
    -+  <p class="img-caption">
    -+Figure 2. The color palette for the image in Figure 1.
    -+  </p>
    -+
    -+<p>
    -+Representing your image as a paletted image goes a long way toward
    -+significantly improving the file size, so it's worth investigating if the
    -+majority of your images can be converted.
    -+</p>
    -+
    -+<p>
    -+Of course, not every image can be accurately represented with only 256 colors.
    -+Some images, for example, might need 257, 310, 512, or 912 colors to
    -+look correct. In such cases, vector quantization can also be helpful.
    -+</p>
    -+
    -+<h4 id="vq">Vector quantization</h4>
    -+
    -+<p>
    -+The process of creating an indexed image may be better described as vector
    -+quantization (VQ). VQ serves as a rounding process for multidimensional
    -+numbers.  In this process, all the colors in your image get grouped based upon
    -+their similarity. For a given group, all colors in that group are replaced by a
    -+single <em>center point</em> value, which minimizes error for colors in that
    -+cell (or "site" if you're using the Voronoi terminology). In Figure 3,
    -+the green dots represent input colors, and the red dots are the center points
    -+that replace the input colors. Each cell is bounded by blue lines.
    -+</p>
    -+
    -+  <img src="{@docRoot}topic/performance/images/vq.gif">
    -+  <p class="img-caption">
    -+Figure 3. Applying vector quantization to the colors in an image.
    -+</p>
    -+
    -+<p>
    -+The result of applying VQ to an image reduces the number of unique colors,
    -+replacing each group of colors with a single color that's "pretty close"
    -+in visual quality.
    -+</p>
    -+
    -+<p>
    -+This technique also allows you to define the maximum number of unique colors in
    -+your image. For example, Figure 4 shows the a parrot head in 16.7 million colors
    -+(24 bits per pixel, or bpp) alongside a version that only allows only
    -+16 (3 bpp) unique colors to be used.
    -+</p>
    -+
    -+  <img src="{@docRoot}topic/performance/images/parrot.png">
    -+  <p class="img-caption">
    -+Figure 4. Image before and after application of vector quantification.
    -+  </p>
    -+
    -+<p>
    -+Immediately, you can see that there's a loss of quality; most of the gradient
    -+colors have been replaced, imparting a banding effect to the image. This image
    -+needs more than 16 unique colors.
    -+</p>
    -+
    -+<p>
    -+Setting up a VQ step in your pipeline can help you get a better sense of the
    -+true number of unique colors that your image uses, and can help you reduce them
    -+significantly. There are a number of readily available tools that you can use
    -+to help you implement this technique.
    -+</p>
    -+
    -+<h3 id="jpg">JPG</h3>
    -+
    -+<p>
    -+If you are using JPG images, there are several small changes you can make that
    -+potentially provide significant file-size savings. These include:
    -+</p>
    -+
    -+<ul>
    -+   <li>
    -+Producing a smaller file size through different encoding methods (without
    -+impacting quality).
    -+   </li>
    -+
    -+   <li>
    -+Adjusting quality slightly in order to yield better compression.
    -+   </li>
    -+</ul>
    -+
    -+<p>Pursuing these strategies can often net you file-size reductions of up to
    -+25%.
    -+</p>
    -+
    -+<p>
    -+When choosing tools, remember that photo exporting tools can
    -+insert unnecessary metadata, such as GPS information, into your images. At
    -+a minimum, try to leverage existing tools to help strip out this information
    -+from your files.
    -+</p>
    -+
    -+<h3 id="webp">WebP</h3>
    -+
    -+<p>
    -+WebP is a newer image format supported from Android 4.2.1 (API level 17). This
    -+format provides superior lossless and lossy compression for images on the web.
    -+Using WebP, developers can create smaller, richer images. WebP lossless image
    -+files are, on average,
    -+<a href="https://developers.google.com/speed/webp/docs/webp_lossless_alpha_study#conclusions">
    -+26% smaller</a> than PNGs. These image files also support
    -+transparency (also known as alpha channel) at a cost of just
    -+<a href="https://developers.google.com/speed/webp/docs/webp_lossless_alpha_study#results">
    -+22% more</a> bytes.
    -+</p>
    -+
    -+<p>
    -+WebP lossy images are
    -+<a href="https://developers.google.com/speed/webp/docs/webp_study#experiment_1_webp_vs_jpeg_at_equal_ssim_index">
    -+25-34% smaller</a> than comparable JPG images at equivalent
    -+<a href="https://en.wikipedia.org/wiki/Structural_similarity">SSIM</a>
    -+quality indices. For cases when lossy RGB compression is acceptable, lossy
    -+WebP also supports transparency, typically producing file sizes 3 times smaller
    -+than PNG.
    -+</p>
    -+
    -+<p>
    -+For more information about WebP, visit the
    -+<a href="https://developers.google.com/speed/webp/">WebP site</a>.
    -+</p>
    -+
    -+<h2 id="sf">Selecting a Format</h2>
    -+
    -+<p>
    -+Different image formats are suitable for different types of images. JPG and PNG
    -+have very different compression processes, and they produce quite different
    -+results.
    -+</p>
    -+
    -+<p>
    -+The decision between PNG and JPG often comes down to the complexity of the
    -+image itself. Figure 5 shows two images that come out quite differently
    -+depending on which compression scheme the developer applies. The image on the
    -+left has many small details, and thus compresses more efficiently with JPG. The
    -+image on the right, with runs of the same color, compresses more efficiently
    -+with PNG.
    -+</p>
    -+
    -+  <img src="{@docRoot}topic/performance/images/comparison.png">
    -+  <p class="img-caption">
    -+Figure 5. Suitable cases for JPG vs. PNG
    -+  </p>
    -+
    -+
    -+<p>
    -+WebP as a format can support both lossy and lossless modes, making it an ideal
    -+replacement for both PNG and JPG. The only thing to keep in mind is that it
    -+only has native support on devices running Android 4.2.1 (API level 17) and
    -+higher. Fortunately, the large
    -+<a
    -+href="https://developer.android.com/about/dashboards/index.html#Platform">
    -+majority of devices</a> satisfy that requirement.
    -+</p>
    -+
    -+<p>
    -+Figure 6 provides a simple visualization to help you decide which compression
    -+scheme to use.
    -+</p>
    -+
    -+  <img src="{@docRoot}topic/performance/images/decisions.png">
    -+  <p class="img-caption">
    -+Figure 6. Deciding on a compression scheme
    -+  </p>
    -+
    -+<h2 id="doqv">Determining Optimal Quality Values</h2>
    -+
    -+<p>
    -+There are several techniques you can use to achieve the right balance between
    -+compression and image quality. One technique uses scalar values and therefore
    -+only works for JPG and WebP. The other technique takes advantage of the
    -+Butteraugli library, and is usable for all image formats.
    -+</p>
    -+
    -+<h3 id="sv">Scalar values (JPG and WebP only)</h3>
    -+
    -+<p>
    -+The power of JPG and WebP comes from the fact that you can use a scalar value
    -+to balance quality against file size. The trick is finding out what the correct
    -+quality value is for your image. Too low a quality level produces a small file
    -+at the cost of image quality. Too high a quality level increases file size
    -+without providing a noticeable benefit to the user.
    -+</p>
    -+
    -+<p>
    -+The most straightforward solution is to pick some non-maximum value, and use
    -+that value. However, be aware that the quality value affects every image
    -+differently. While a quality of 75%, for example, may look fine on most images,
    -+there may be some cases do not fare as well. You should make sure to test your
    -+chosen maximum value against a representative sample of images. Also, make
    -+sure to perform all of your tests against the original images, and not on
    -+compressed versions.
    -+</p>
    -+
    -+<p>
    -+For large media applications that upload and re-send millions of JPGs a day,
    -+hand-tuning for each asset is impractical. You might address this challenge by
    -+specifying several different quality levels, according to image category. For
    -+example, you might set 35% as the quality setting for thumbnails, since a
    -+smaller image hides more compression artifacts.
    -+</p>
    -+
    -+<h3 id="butter">Butteraugli</h4>
    -+
    -+<p>
    -+The Butteraugli project is a library to test an image's Psychovisual Error
    -+Threshold: the point at which a viewer starts to notice image degradation. In
    -+other words, this project attempts to quantify how distorted your compressed
    -+image is.
    -+</p>
    -+
    -+<p>
    -+Butteraugli allows you to define a goal for visual quality, and then run PNG,
    -+JPG, WebP lossy, and WebP lossless compressions. You can then choose the image
    -+that is the best balance of file size and Butteraugli level. Figure 7 shows an
    -+example of how Butteraugli was used to find the minimal JPG quality level
    -+before the visual distortion was high enough for a user could perceive a
    -+problem; the result is a roughly 65% reduction in file size.
    -+</p>
    -+
    -+  <img src="{@docRoot}topic/performance/images/moarparrots.png">
    -+  <p class="img-caption">
    -+Figure 7. An image before and after application of Butteraugli technology.
    -+  </p>
    -+
    -+<p>
    -+Butteraugli allows you to proceed based on either output or input. That is, you
    -+can look for the lowest quality setting before a user perceives noticeable
    -+distortion in the resulting image, or you can iteratively set image-distortion
    -+levels to learn their associated quality levels.
    -+</p>
    -+
    -+<h2 id="sizes">Serving Sizes</h2>
    -+
    -+<p>
    -+It is tempting to keep only a single resolution of an image on a server. When a
    -+device accesses the image, the server serves it at that one resolution and
    -+leaves downscaling to the device.
    -+</p>
    -+
    -+<p>
    -+This solution is convenient for the developer, but potentially painful for the
    -+user, because the solution forces the user to download much more data than they
    -+need.
    -+
    -+You should instead store multiple sizes of images, and serve the size that is
    -+most appropriate for a particular use case. For example, for a thumbnail,
    -+serving an actual thumbnail image instead of serving and downscaling a
    -+full-size version consumes much less network bandwidth
    -+</p>
    -+
    -+</p>
    -+This approach is good for download speed, and is less costly for users who may
    -+be using limited or metered data plans. Proceeding like this also results in
    -+the image's taking less space on the device and in main memory. In the
    -+case of large images, such as 4K ones, this approach also saves the device
    -+from having to resize images before loading them.
    -+</p>
    -+
    -+<p>
    -+Implementing this approach requires that you have a backend image service to
    -+provide images at various resolutions with proper caching. There are existing
    -+services that can provide help with this task. For example,
    -+<a href="https://cloud.google.com/appengine/">App Engine</a> comes
    -+with image resizing functionality already installed.
    -+</p>
    -diff --git a/docs/html/topic/performance/optimizing-view-hierarchies.jd b/docs/html/topic/performance/optimizing-view-hierarchies.jd
    -deleted file mode 100644
    -index 27d3d16..0000000
    ---- a/docs/html/topic/performance/optimizing-view-hierarchies.jd
    -+++ /dev/null
    -@@ -1,388 +0,0 @@
    --page.title=Performance and View Hierarchies
    --@jd:body
    --
    --<div id="qv-wrapper">
    --<div id="qv">
    --
    --<h2>In this document</h2>
    --<ol>
    --<li><a href="#lmp">Layout-and-Measure Performance</a>
    --  <ol>
    --    <li><a href="#managing">Managing complexity: layouts matter</a></li>
    --    <li><a href="#double">Double taxation</a></li>
    --  </ol>
    --</li>
    --<li><a href="#dx">Diagnosing View Hierarchy Issues</a>
    --  <ol>
    --    <li><a href="#systrace">Systrace</a></li>
    --    <li><a href="#profile">Profile GPU rendering</a></li>
    --    <li><a href="#lint">Lint</a></li>
    --    <li><a href="#hv">Hierarchy Viewer</a></li>
    --  </ol>
    --</li>
    --<li><a href="#solving">Solving View Hierarchy Issues</a>
    --   <ol>
    --      <li><a href="#removing">Removing redundant nested layouts</a></li>
    --      <li><a href="#cheaper">Adopting a cheaper layout</a></li>
    --   </ol>
    --      </li>
    --</ol>
    --</div>
    --</div>
    --
    --
    --<p>
    --The way you manage the hierarchy of your {@link android.view.View} objects can
    --have a substantial impact on your app’s performance. This page describes how to
    --assess whether your view hierarchy is slowing your app down, and offers some
    --strategies for addressing issues that may arise.
    --</p>
    --
    --<h2 id="lmp">Layout and Measure Performance</h2>
    --<p>
    --The rendering pipeline includes a <em>layout-and-measure</em>
    --stage, during which the system appropriately positions the relevant items in
    --your view hierarchy. The measure part of this stage determines the sizes and
    --boundaries of {@link android.view.View} objects. The layout part determines where on the screen to
    --position the {@link android.view.View} objects.
    --</p>
    --
    --<p>
    --Both of these pipeline stages incur some small cost per view or layout that they
    --process. Most of the time, this cost is minimal and doesn’t noticeably affect
    --performance. However, it can be greater when an app adds or removes View
    --objects, such as when a {@link android.support.v7.widget.RecyclerView}
    --object recycles them or reuses them. The
    --cost can also be higher if a {@link android.view.View} object needs to consider
    --resizing to main its constraints: For example, if your app calls
    --{@link android.widget.TextView#setText(char[], int, int) SetText()} on a
    --{@link android.view.View} object that wraps text, the
    --{@link android.view.View} may need to resize.
    --</p>
    --
    --<p>
    --If cases like these take too long, they can prevent a frame from rendering
    --within the allowed 16ms, so that frames are dropped, and animation becomes
    --janky.
    --</p>
    --
    --<p>
    --Because you cannot move these operations to a worker thread&mdash;your app must
    --process them on the main thread&mdash;your best bet is to optimize them so that
    --they can take as little time as possible.
    --</p>
    --
    --<h3 id="managing">Managing complexity: layouts matter</h3>
    --
    --<p>
    --Android <a
    --href="{@docRoot}guide/topics/ui/declaring-layout.html">Layouts</a>
    --allow you to nest UI objects in the view hierarchy. This nesting can also impose
    --a layout cost. When your app processes an object for layout, the app performs
    --the same process on all children of the layout as well. For a complicated
    --layout, sometimes a cost only arises the first time the system computes the
    --layout. For instance, when your app recycles a complex list item in a
    --{@link android.support.v7.widget.RecyclerView} object, the
    --system needs to lay out all of the objects. In another example, trivial changes
    --can propagate up the chain toward the parent
    --until they reach an object that doesn’t affect the size of the parent.
    --</p>
    --
    --<p>
    --The most common case in which layout takes an especially long time is when
    --hierarchies of {@link android.view.View} objects are nested within one another. Each nested layout
    --object adds cost to the layout stage. The flatter your hierarchy, the less
    --time that it takes for the layout stage to complete.
    --</p>
    --
    --<p>
    --If you are using the {@link android.widget.RelativeLayout} class, you may be able to achieve the same
    --effect, at lower cost, by using nested, unweighted
    --{@link android.widget.LinearLayout} views instead. Additionally, if your app
    --targets Android N (API level 24), it is likely that
    --you can use a special layout editor to create a <a
    --href="http://tools.android.com/tech-docs/layout-editor">{@code ConstraintLayout}</a>
    --object instead of {@link android.widget.RelativeLayout}. Doing so allows you
    --to avoid many of the issues this section
    --describes. The <a
    --href="http://tools.android.com/tech-docs/layout-editor">{@code ConstraintLayout}</a>
    --class offers similar layout control, but
    --with much-improved performance. This class uses its own constraint-solving
    --system to resolve relationships between views in a very different way from
    --standard layouts.
    --</p>
    --
    --<h3 id="double">Double Taxation</h3>
    --
    --<p>
    --Typically, the framework executes the <a
    --href="{@docRoot}guide/topics/ui/declaring-layout.html">layout</a>
    --or measure stage in a single pass and quite quickly. However, with some more
    --complicated layout cases, the framework may have to iterate multiple times on
    --the layout or measure stage before ultimately positioning the elements. Having
    --to perform more than one layout-and-measure iteration is referred to as
    --<em>double taxation.</em>
    --</p>
    --
    --<p>
    --For example, when you use the {@link android.widget.RelativeLayout} container, which allows you to
    --position {@link android.view.View} objects with respect to the positions of other {@link android.view.View} objects, the
    --framework performs the following actions:
    --</p>
    --
    --<ol style="1">
    --   <li>Executes a layout-and-measure pass, during which the framework calculates
    --each child object’s position and size, based on each child’s request.
    --   <li>Uses this data, also taking object weights into account, to figure out the
    --proper position of correlated views.
    --   <li>Performs a second layout pass to finalize the objects’ positions.
    --   <li>Goes on to the next stage of the rendering process.</li></ol>
    --
    --<p>
    --The more levels your view hierarchy has, the greater the potential performance
    --penalty.
    --</p>
    --
    --<p>
    --Containers other than {@link android.widget.RelativeLayout} may also give rise to double taxation. For
    --example:
    --</p>
    --
    --<ul>
    --   <li>A {@link android.widget.LinearLayout} view
    --could result in a double layout-and-measure pass if you make it horizontal.
    --A double layout-and-measure pass may also occur in a vertical orientation if you
    --add <a
    --href="{@docRoot}reference/android/widget/LinearLayout.html#attr_android:measureWithLargestChild">measureWithLargestChild</a>,
    --in which case the framework may need to do a second pass to resolve the proper
    --sizes of objects.
    --   <li>The {@link android.widget.GridLayout}
    --has a similar issue. While this container also allows relative positioning, it
    --normally avoids double taxation by pre-processing the positional relationships
    --among child views. However, if the layout uses weights or fill with the
    --{@link android.view.Gravity} class, the
    --benefit of that preprocessing is lost, and the framework may have to perform
    --multiple passes if it the container were a {@link android.widget.RelativeLayout}.</li>
    --</ul>
    --<p>
    --Multiple layout-and-measure passes are not, in themselves, a performance burden.
    --But they can become so if they’re in the wrong spot. You should be wary of
    --situations where one of the following conditions applies to your container:
    --</p>
    --
    --<ul>
    --   <li>It is a root element in your view hierarchy.
    --   <li>It has a deep view hierarchy beneath it.
    --   <li>It is nested.
    --   <li>There are many instances of it populating the screen, similar to children
    --   in a {@link android.widget.ListView} object.</li>
    --</ul>
    --
    --<h2 id="dx">Diagnosing View Hierarchy Issues</h2>
    --
    --<p>
    --Layout performance is a complex problem with many facets. There are a couple of
    --tools that can give you solid indications about where performance bottlenecks
    --are occurring. A few other tools provide less definitive information, but can
    --also provide helpful hints.
    --</p>
    --
    --<p>
    --<h3 id="systrace">Systrace</h3>
    --</p>
    --
    --<p>
    --One tool that provides excellent data about performance is <a
    --href="{@docRoot}studio/profile/systrace.html">Systrace</a>,
    --which is built into Android Studio. The Systrace tool allows you to collect and
    --inspect timing information across an entire Android device, allowing you to see
    --specifically where performance bottlenecks arise. For more information about
    --Systrace, see <a href=”{docRoot}<a href="{@docRoot}studio/profile/systrace.html">
    --Analyze UI Performance with Systrace</a>.
    --</p>
    --
    --<h3 id="profile">Profile GPU rendering</h3>
    --
    --<p>
    --The other tool most likely to provide you with concrete information about
    --performance bottlenecks is the on-device <a
    --href="{@docRoot}studio/profile/dev-options-rendering.html">
    --Profile GPU rendering</a> tool, available on devices powered by Android 6.0 (API
    --level 23) and later.  This tool allows you to see how long the layout-and-measurestage is
    -- taking for <a href="https://youtu.be/erGJw8WDV74">each frame
    --of rendering</a>. This data can help you diagnose runtime performance issues,
    --and help you determine what, if any layout-and-measure issues you need to
    --address.
    --</p>
    --
    --<p>
    --In its graphical representation of the data it captures, <a
    --href="{@docRoot}studio/profile/dev-options-rendering.html">Profile
    --GPU rendering</a> uses the color blue to represent layout time. For more
    --information about how to use this tool, see <a
    --href="{@docRoot}studio/profile/dev-options-rendering.html">Profile
    --GPU Rendering Walkthrough.</a>
    --</p>
    --
    --<h3 id="lint">Lint</h3>
    --
    --<p>
    --Android Studio’s <a
    --href="{@docRoot}studio/write/lint.html">Lint</a> tool can
    --help you gain a sense of inefficiencies in the view hierarchy. To use this tool,
    --select <strong>Analyze > Inspect Code</strong>, as shown in Figure 1.
    --</p>
    --
    --  <img src="{@docRoot}topic/performance/images/lint-inspect-code.png">
    --  <p class="img-caption">
    --    <strong>Figure 1.</strong> Locating <strong>Inspect Code</strong> in the
    --Android Studio.
    --  </p>
    --
    --<p>
    --Information about various layout items appears under
    --<em>Android > Lint > Performance</em>. To see more detail,
    --you can click on each item to expand it, and see more
    --information in the pane on the right side of the screen.
    --Figure 2 shows an example of such a display.
    --</p>
    --
    --  <img src="{@docRoot}topic/performance/images/lint-display.png">
    --  <p class="img-caption">
    --    <strong>Figure 2.</strong> Viewing information about specific
    --issues that the lint tool has identified.
    --  </p>
    --
    --
    --<p>
    --Clicking on one of these items reveals, in the pane to the right, the problem
    --associated with that item.
    --</p>
    --
    --<p>
    --To understand more about specific topics and issues in this area, see the <a
    --href="{@docRoot}studio/write/lint.html">Lint
    --</a>documentation.
    --</p>
    --
    --<h3 id="hv">Hierarchy Viewer</h3>
    --
    --<p>
    --Android Studio’s <a
    --href="{@docRoot}studio/profile/hierarchy-viewer.html">Hierarchy
    --Viewer</a> tool provides a visual representation of your app’s view hierarchy.
    --It is a good way to navigate the hierarchy of your app, providing a clear visual
    --representation of a particular view’s parent chain, and allowing you to inspect
    --the layouts that your app constructs.
    --</p>
    --
    --<p>
    --The views that Hierarchy Viewer presents can also help identify performance
    --problems arising from double taxation. It can also provide an easy way for you
    --to identify deep chains of nested layouts, or layout areas with a large amount
    --of nested children, another potential source of performance costs. In these
    --scenarios, the layout-and-measure stages can be particularly costly,
    --resulting in performance issues.
    --</p>
    --
    --<p>
    --You can also can get a sense of relative time taken by layout-and-measure
    --operations by clicking the “profile node” button.
    --</p>
    --
    --<p>
    --For more information about Hierarchy Viewer, see <a
    --href="{@docRoot}studio/profile/optimize-ui.html#HierarchyViewer">Optimizing
    --Your UI</a>.
    --</p>
    --
    --<h2 id="solving">Solving View Hierarchy Issues</h2>
    --
    --<p>
    --The fundamental concept behind solving performance problems that arise from view
    --hierarchies is simple in concept, but more difficult in practice. Preventing
    --view hierarchies from imposing performance penalties encompasses the dual goals
    --of flattening your view hierarchy and reducing double taxation. This section
    --discusses some strategies for pursuing these goals.
    --</p>
    --
    --<h3 id="removing">Removing redundant nested layouts</h3>
    --
    --<p>
    --Developers often use more nested layouts than necessary. For example, a
    --{@link android.widget.RelativeLayout} container might contain a single child that is also a
    --{@link android.widget.RelativeLayout} container. This nesting amounts to redundancy, and adds
    --unnecessary cost to the view hierarchy.
    --</p>
    --
    --<p>
    --Lint can often flag this problem for you, reducing debugging time.
    --</p>
    --
    --<h3>Adopting Merge/Include </h3>
    --<p>
    --One frequent cause of redundant nested layouts is the <a
    --href="{@docRoot}training/improving-layouts/reusing-layouts.html">
    --&lt;include&gt;
    --tag</a>. For example, you may define a re-usable layout as follows:
    --</p>
    --
    --<pre class="prettyprint">
    --&lt;LinearLayout&gt;
    --    &lt;!-- some stuff here --&gt;
    --&lt;/LinearLayout&gt;
    --&lt;/pre&gt;
    --</pre>
    --
    --<p>
    --And then an include tag to add this item to the parent container:
    --</p>
    --
    --<pre class="prettyprint">
    --&lt;LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    --    android:orientation="vertical"
    --    android:layout_width="match_parent"
    --    android:layout_height="match_parent"
    --    android:background="@color/app_bg"
    --    android:gravity="center_horizontal"&gt;
    --
    --    &lt;include layout="@layout/titlebar"/&gt;
    --
    --    &lt;TextView android:layout_width="match_parent"
    --              android:layout_height="wrap_content"
    --              android:text="@string/hello"
    --              android:padding="10dp" /&gt;
    --
    --    ...
    --
    --&lt;/LinearLayout&gt;
    --</pre>
    --
    --<p>
    --The include unnecessarily nests the first layout within the second layout.
    --</p>
    --
    --<p>
    --The <a
    --href="{@docRoot}training/improving-layouts/reusing-layouts.html#Merge">merge
    --</a>tag can help prevent this issue. For information about this tag, see <a
    --href="{@docRoot}training/improving-layouts/reusing-layouts.html#Merge">Re-using
    --Layouts with &lt;include&gt;</a>.
    --</p>
    --
    --<h3 id="cheaper">Adopting a cheaper layout</h3>
    --
    --<p>
    --You may not be able to adjust your existing layout scheme so that it doesn’t
    --contain redundant layouts. In certain cases, the only solution may be to flatten
    --your hierarchy by switching over to an entirely different layout type.
    --</p>
    --
    --<p>
    --For example, you may find that a {@link android.widget.TableLayout}
    --provides the same functionality as a more complex layout with many
    --positional dependencies. In the N release of Android, the
    --<a
    --href="http://tools.android.com/tech-docs/layout-editor">{@code ConstraintLayout}</a> class provides similar functionality to
    --{@link android.widget.RelativeLayout}, but at a significantly lower cost.
    --</p>
    -diff --git a/docs/html/topic/performance/power/battery-historian.jd b/docs/html/topic/performance/power/battery-historian.jd
    -new file mode 100644
    -index 0000000..79ea59d
    ---- /dev/null
    -+++ b/docs/html/topic/performance/power/battery-historian.jd
    -@@ -0,0 +1,247 @@
    -+page.title=Analyzing Power Use with Battery Historian
    -+page.metaDescription=Improve network performance by optimizing image size.
    -+
    -+meta.tags="power"
    -+page.tags="power"
    -+
    -+@jd:body
    -+
    -+<div id="qv-wrapper">
    -+<div id="qv">
    -+
    -+<h2>In this document</h2>
    -+    <ol>
    -+      <li>
    -+        <a href="#sv">System-wide View</a>
    -+      </li>
    -+      <li>
    -+        <a href="#asd">App-Specific Data</a>
    -+      </li>
    -+      <li>
    -+        <a href="#usecases">Other Cases Where Battery Historian Can Help</a>
    -+      </li>
    -+    </ol>
    -+<h2>See also</h2>
    -+   <ol>
    -+      <li>
    -+      <a href="https://github.com/google/battery-historian">Battery Historian
    -+      on GitHub</a>
    -+      </li>
    -+
    -+      <li>
    -+      <a href="https://developer.android.com/studio/profile/battery-historian.html">
    -+      Batterystats and Battery Historian Walkthrough
    -+      </li>
    -+
    -+      <li>
    -+      <a href="https://youtu.be/VC2Hlb22mZM?list=PLOU2XLYxmsILe6_eGvDN3GyiodoV3qNSC&t=2063"
    -+      target="_blank">
    -+      Battery Historian talk at Google I/O 2016</a>
    -+      </li>
    -+    </ol>
    -+  </div>
    -+</div>
    -+
    -+<p>
    -+The Battery Historian tool provides insight into a device’s battery consumption
    -+over time. At a system-wide level, the tool visualizes power-related events from
    -+the system logs in an HTML representation. At an app-specific level, the tool
    -+provides a variety of data that can help you identify battery-draining app
    -+behavior.
    -+</p>
    -+
    -+<p>
    -+This document describes some of the ways you can use Battery Historian
    -+to learn about battery-consumption patterns. The document begins by explaining
    -+how to read the system-wide data that Battery Historian reports. Then,
    -+it presents ways in which you can use Battery Historian to diagnose
    -+and troubleshoot your own app's behavior related to battery consumption.
    -+Last, it offers several tips on scenarios in which Battery Historian may be
    -+particularly useful.
    -+</p>
    -+
    -+<h2 id="sv">System-wide View</h2>
    -+
    -+<p>
    -+The Battery Historian tool provides a system-wide visualization of various
    -+app and system behaviors, along with their correlation against battery
    -+consumption over time. This view, shown in Figure 1, can help you
    -+diagnose and identify power use issues with your app.
    -+</p>
    -+
    -+  <img src="{@docRoot}topic/performance/images/generic-timeline.png">
    -+  <p class="img-caption">
    -+<strong>Figure 1.</strong>
    -+Battery Historian’s display of system-wide events affecting power
    -+consumption.
    -+  </p>
    -+
    -+<p>
    -+Of particular interest in this figure is the black, horizontal, downward trend
    -+line representing Battery Level, measured on the y-axis. For example, at the
    -+very beginning of the Battery Level line, at approximately 6:50 AM, the
    -+visualization shows a relatively steep drop in battery level.
    -+</p>
    -+
    -+<p>
    -+Figure 2 provides a close-up of that part of the display.
    -+</p>
    -+
    -+  <img src="{@docRoot}topic/performance/images/s-generic-closeup.png">
    -+  <p class="img-caption">
    -+<strong>Figure 2.</strong>
    -+A close-up of the Battery Historian timeline from roughly 6:50 AM to 7:20 AM.
    -+  </p>
    -+
    -+<p>
    -+At the very beginning of the Battery Level line, as battery decline steeply,
    -+the display shows three things happening: The CPU is running, an app has
    -+acquired a wakelock, and the screen is on. In this way, Battery Historian helps
    -+you understand what events are happening when battery consumption is high. You
    -+can then target these behaviors in your app and investigate whether there are
    -+related optimizations you can make.
    -+</p>
    -+
    -+<p>
    -+The system-wide visualization can provide other clues, as well. For instance, if
    -+it shows that the mobile radio is frequently being turned off and on, there may
    -+be an opportunity to optimize this behavior through <a href=”intelligent
    -+scheduling page”>intelligent scheduling APIs</a> such as JobScheduler or
    -+Firebase Job Dispatcher.
    -+</p>
    -+
    -+<p>
    -+The next section explains how to investigate behavior and events specific to
    -+your own app.
    -+</p>
    -+
    -+<p>
    -+<h2 id="asd">App-Specific Data</h2>
    -+</p>
    -+
    -+<p>
    -+In addition to the macro-level data provided by the system-wide view, Battery
    -+Historian also provides tables and some visualization of data specific to each
    -+app running on your device. The tabular data includes:
    -+</p>
    -+
    -+<ul>
    -+   <li>The app’s estimated power use on the device.</li>
    -+   <li>Network information.</li>
    -+   <li>Wakelocks.</li>
    -+   <li>Services.</li>
    -+   <li>Process info.</li>
    -+</ul>
    -+
    -+<p>
    -+The tables provide two dimensions of data about your app. First, you can look
    -+up where your app’s power usage ranks compared to other apps. To do so, click
    -+<em>Device Power Estimates</em> table under <em>Tables</em>. This example
    -+examines a fictional app called Pug Power.
    -+</p>
    -+
    -+  <img src="{@docRoot}topic/performance/images/app-rankings.png">
    -+  <p class="img-caption">
    -+<strong>Figure 3.</strong> Investigating which apps consume the most power.
    -+  </p>
    -+
    -+<p>
    -+The table in Figure 3 reveals that Pug Power is the ninth biggest consumer of
    -+battery power on this device, and the third biggest app that is not part of the
    -+OS. This data suggests that this app bears deeper investigation.
    -+</p>
    -+
    -+<p>
    -+To look up the data for a specific app, enter its package name into the lower
    -+of the two dropdown menus under <em>App Selection</em>, located under the left
    -+side of the visualization.
    -+</p>
    -+
    -+  <img src="{@docRoot}topic/performance/images/dropdown.png">
    -+  <p class="img-caption">
    -+<strong>Figure 4.</strong> Entering a specific app whose data to view.
    -+  </p>
    -+
    -+<p>
    -+When you select a specific app, the following data visualization categories
    -+change to display app-specific data instead of system-wide data:
    -+</p>
    -+
    -+<ul>
    -+   <li>SyncManager.</li>
    -+   <li>Foreground process.</li>
    -+   <li>Userspace Wakelock.</li>
    -+   <li>Top app.</li>
    -+   <li>JobScheduler.</li>
    -+   <li>Activity Manager Proc.</li>
    -+</ul>
    -+
    -+The SyncManager and JobScheduler visualizations immediately make it obvious if
    -+your app performs syncs and executes jobs more frequently than necessary. In
    -+doing so, they can quickly reveal an opportunity to optimize your app’s
    -+behavior for improved battery performance.
    -+
    -+<p>
    -+You can also obtain one more piece of app-specific visualization data,
    -+<em>Userspace Wakelock</em>. To include this information in the bug report,
    -+enter the following command in your terminal window:
    -+</p>
    -+
    -+<pre>
    -+$ adb shell dumpsys batterystats --enable full-wake-history
    -+</pre>
    -+
    -+<p class="note">
    -+<strong>Note:</strong> From Android 6.0 (API level 23), the platform includes
    -+Doze functionality, which imposes certain optimizations on apps. For example,
    -+Doze batches jobs to take place during brief maintenance windows, regardless of
    -+how JobScheduler has scheduled them.
    -+</p>
    -+
    -+<p>
    -+Figures 5 and 6 show data for Pug Power: Figure 5
    -+shows the visualization of
    -+the app-specific data, and Figure 6 shows the corresponding tabular data.
    -+</p>
    -+
    -+  <img src="{@docRoot}topic/performance/images/pug-visualization.png">
    -+  <p class="img-caption">
    -+<strong>Figure 5.</strong> Visualization of data for fictional app Pug Power.
    -+  </p>
    -+
    -+  <img src="{@docRoot}topic/performance/images/pugspecificdata.png">
    -+  <p class="img-caption">
    -+<strong>Figure 6.</strong> Tabular data for the fictional Pug Power app.
    -+  </p>
    -+
    -+<p>
    -+A look at the visualization does not show anything immediately obvious.
    -+The JobScheduler line shows that the app has no jobs scheduled. The SyncManager
    -+line shows that the app has not performed any syncs.
    -+</p>
    -+
    -+<p>
    -+However, examination of the <em>Wakelocks</em> segment of the tabular data
    -+reveals that Pug Power acquires wakelocks totaling over an hour. This unusual
    -+and costly behavior can account for the app’s high level of power consumption.
    -+This piece of information helps the developer target an area where optimization
    -+is likely to greatly help. In this case, why does the app acquire so much
    -+wakelock time, and how can the developer ameliorate this behavior?
    -+</p>
    -+
    -+<h2 id="usecases">Other Cases Where Battery Historian Can Help</h2>
    -+
    -+<p>
    -+There are many other cases in which Battery Historian can help you diagnose
    -+opportunities for improving battery behavior. For example, Battery Historian
    -+can tell you if your app is:
    -+</p>
    -+
    -+<ul>
    -+   <li>Firing wakeup alarms overly frequently (every 10 seconds or less).</li>
    -+   <li>Continuously holding a GPS lock.</li>
    -+   <li>Scheduling jobs every 30 seconds or less.</li>
    -+   <li>Scheduling syncs every 30 seconds or less.</li>
    -+   <li>Using the cellular radio more frequently than you expect.</li>
    -+</ul>
    -+
    -diff --git a/docs/html/topic/performance/power/index.jd b/docs/html/topic/performance/power/index.jd
    -new file mode 100644
    -index 0000000..88addce
    ---- /dev/null
    -+++ b/docs/html/topic/performance/power/index.jd
    -@@ -0,0 +1,125 @@
    -+page.title=Optimizing for Battery Life
    -+page.metaDescription=Learn how to help your app go easier on the battery.
    -+
    -+meta.tags="performance"
    -+page.tags="performance"
    -+
    -+@jd:body
    -+
    -+<div id="qv-wrapper">
    -+  <div id="qv">
    -+    <h2>
    -+      In this document
    -+    </h2>
    -+    <ol>
    -+      <li>
    -+        <a href="#lazy">Lazy First</a>
    -+      </li>
    -+      <li>
    -+        <a href="#features">Platform Features</a>
    -+      </li>
    -+      <li>
    -+        <a href="#toolery">Tooling</a>
    -+      </li>
    -+    </ol>
    -+  </div>
    -+</div>
    -+
    -+<p>Battery life is the single most important aspect of the mobile user
    -+experience. A device without power offers no functionality at all.
    -+For this reason, it is critically important that apps be as respectful of
    -+battery life as possible.</p>
    -+
    -+<p>There are three important things to keep in mind in keeping your app
    -+power-thrifty:</p>
    -+<ul>
    -+<li>Make your apps <em>Lazy First</em>.</li>
    -+<li>Take advantage of platform features that can help manage your app's battery
    -+consumption.</li>
    -+<li>Use tools that can help you identify battery-draining culprits.</li>
    -+</ul>
    -+
    -+<h2 id="lazy">Lazy First</h2>
    -+
    -+<p>Making your app Lazy First means looking for ways to reduce and optimize
    -+operations that are particularly battery-intensive. The core questions
    -+underpinning Lazy First design are:
    -+
    -+<ul>
    -+
    -+   <li><strong>Reduce:</strong> Are there redundant operations your app can cut
    -+out? For example, can it cache downloaded data instead of repeatedly waking
    -+   up the radio to re-download the data?</li>
    -+
    -+   <li><strong>Defer:</strong> Does an app need to perform an action right
    -+   away? For example,
    -+    can it wait until the device is charging before it backs data up to the
    -+    cloud?</li>
    -+
    -+   <li><strong>Coalesce:</strong> Can work be batched, instead of putting the
    -+   device
    -+   into an active state many times? For example, is it really necessary for
    -+   several dozen apps to each turn on the radio at separate times to send
    -+   their messages? Can the messages instead be transmitted during a
    -+   single awakening of the radio?</li>
    -+</ul>
    -+
    -+<p>
    -+You should ask these questions when it comes to using the CPU,
    -+the radio, and the screen. Lazy First design is often a good way
    -+to tame these battery killers.
    -+</p>
    -+
    -+<p>
    -+To help you achieve these and other efficiencies, the Android platform
    -+provides a number of features to help maximize battery life.
    -+</p>
    -+
    -+<h2 id="features">Platform Features</h2>
    -+
    -+<p>
    -+Broadly speaking, the Android platform provides two categories of help
    -+for you to optimize your app's battery use. First, it provides several
    -+APIs that you can implement in your app. You can learn more about these APIs in
    -+<a href="/topic/performance/scheduling.html">Intelligent Job Scheduling</a>
    -+and <a href="/performance/power/network/index.html">
    -+Network Use and Battery Consumption</a>.
    -+</p>
    -+
    -+<p>
    -+There are also internal mechanisms in the platform to help conserve
    -+battery life. While they are not APIs that you implement programmatically,
    -+you should still be aware of them so that your app can leverage them
    -+successfully. For more information, see
    -+<a href="/training/monitoring-device-state/doze-standby.html">Doze and
    -+App Standby</a>.</p>
    -+
    -+<p>
    -+You can get even more benefit out of these features by using the tools
    -+available for the platform to discover the parts of your app that consume
    -+the most power. Finding what to target is a big step toward
    -+successful optimization.
    -+</p>
    -+
    -+<h2 id ="toolery">Tooling</h2>
    -+
    -+<p>There are tools for Android, including
    -+<a href="/studio/profile/dev-options-rendering.html">Profile GPU Rendering</a>
    -+and <a class="external-link"
    -+href="https://github.com/google/battery-historian">Battery Historian</a>
    -+to help you identify areas that you can optimize for better battery life.
    -+Take advantage of these tools to target areas where you can apply the
    -+principles of Lazy First.
    -+</p>
    -+
    -+<section class="dac-section dac-small" id="latest-games"><div class="wrap">
    -+  <h2 class="norule" style="margin:0 0">More resources</h2>
    -+  <div class="resource-widget resource-flow-layout col-16"
    -+       data-query="collection:develop/performance/landing"
    -+       data-sortOrder="random"
    -+       data-cardSizes="6x6"
    -+       data-maxResults="24"
    -+       data-items-per-page="24"
    -+       data-initial-results="3"></div>
    -+  </div>
    -+</section>
    -diff --git a/docs/html/topic/performance/rendering/index.jd b/docs/html/topic/performance/rendering/index.jd
    -new file mode 100644
    -index 0000000..1b16df0
    ---- /dev/null
    -+++ b/docs/html/topic/performance/rendering/index.jd
    -@@ -0,0 +1,60 @@
    -+page.title=Rendering
    -+page.article=true
    -+
    -+page.tags=battery
    -+page.metaDescription=Learn how to optimize your app's rendering performance.
    -+
    -+@jd:body
    -+
    -+
    -+<iframe width="448" height="252"
    -+    src="//www.youtube.com/embed/wIy8g8yNhNk?autohide=1&amp;showinfo=0"
    -+    frameborder="0" allowfullscreen=""
    -+    style="float: right; margin: 0 0 20px 20px;"></iframe>
    -+
    -+<p>
    -+  A key aspect of your app that influences your users' perception of quality is
    -+  the smoothness with which it renders images and text to the screen. It is
    -+  important to avoid jank and sluggish responsiveness when your app is drawing
    -+  to the screen.
    -+</p>
    -+
    -+<p>
    -+  This section helps you learn several ways to optimize your app's rendering
    -+  performance: reducing overdraw, optimizing view hierarchies, and taking
    -+  advantage of the Profile GPU tool.
    -+</p>
    -+
    -+<h2>Rendering Actions</h2>
    -+
    -+<dl>
    -+  <dt>
    -+    <strong><a href="overdraw.html">
    -+        Reducing Overdraw</a></strong>
    -+  </dt>
    -+  <dd>
    -+    Minimize the number of times you app redraws the same pixel in a single
    -+    frame.
    -+  </dd>
    -+
    -+  <dt>
    -+    <strong><a href="optimizing-view-hierarchies.html">
    -+        Performance and View Hierarchies</a></strong>
    -+  </dt>
    -+  <dd>
    -+    Make sure your layout and measurement are executing efficiently, and
    -+    avoid double taxation.
    -+  </dd>
    -+
    -+
    -+  <dt>
    -+    <strong><a href="profile-gpu.html">
    -+        Analyzing with Profile GPU Rendering</a></strong>
    -+  </dt>
    -+  <dd>
    -+    Take advantage of this on-device tool to identify bottlenecks that
    -+    may be slowing your app's rendering down.
    -+  </dd>
    -+
    -+
    -+</dl>
    -diff --git a/docs/html/topic/performance/rendering/optimizing-view-hierarchies.jd b/docs/html/topic/performance/rendering/optimizing-view-hierarchies.jd
    -new file mode 100644
    -index 0000000..27d3d16
    ---- /dev/null
    -+++ b/docs/html/topic/performance/rendering/optimizing-view-hierarchies.jd
    -@@ -0,0 +1,388 @@
    -+page.title=Performance and View Hierarchies
    -+@jd:body
    -+
    -+<div id="qv-wrapper">
    -+<div id="qv">
    -+
    -+<h2>In this document</h2>
    -+<ol>
    -+<li><a href="#lmp">Layout-and-Measure Performance</a>
    -+  <ol>
    -+    <li><a href="#managing">Managing complexity: layouts matter</a></li>
    -+    <li><a href="#double">Double taxation</a></li>
    -+  </ol>
    -+</li>
    -+<li><a href="#dx">Diagnosing View Hierarchy Issues</a>
    -+  <ol>
    -+    <li><a href="#systrace">Systrace</a></li>
    -+    <li><a href="#profile">Profile GPU rendering</a></li>
    -+    <li><a href="#lint">Lint</a></li>
    -+    <li><a href="#hv">Hierarchy Viewer</a></li>
    -+  </ol>
    -+</li>
    -+<li><a href="#solving">Solving View Hierarchy Issues</a>
    -+   <ol>
    -+      <li><a href="#removing">Removing redundant nested layouts</a></li>
    -+      <li><a href="#cheaper">Adopting a cheaper layout</a></li>
    -+   </ol>
    -+      </li>
    -+</ol>
    -+</div>
    -+</div>
    -+
    -+
    -+<p>
    -+The way you manage the hierarchy of your {@link android.view.View} objects can
    -+have a substantial impact on your app’s performance. This page describes how to
    -+assess whether your view hierarchy is slowing your app down, and offers some
    -+strategies for addressing issues that may arise.
    -+</p>
    -+
    -+<h2 id="lmp">Layout and Measure Performance</h2>
    -+<p>
    -+The rendering pipeline includes a <em>layout-and-measure</em>
    -+stage, during which the system appropriately positions the relevant items in
    -+your view hierarchy. The measure part of this stage determines the sizes and
    -+boundaries of {@link android.view.View} objects. The layout part determines where on the screen to
    -+position the {@link android.view.View} objects.
    -+</p>
    -+
    -+<p>
    -+Both of these pipeline stages incur some small cost per view or layout that they
    -+process. Most of the time, this cost is minimal and doesn’t noticeably affect
    -+performance. However, it can be greater when an app adds or removes View
    -+objects, such as when a {@link android.support.v7.widget.RecyclerView}
    -+object recycles them or reuses them. The
    -+cost can also be higher if a {@link android.view.View} object needs to consider
    -+resizing to main its constraints: For example, if your app calls
    -+{@link android.widget.TextView#setText(char[], int, int) SetText()} on a
    -+{@link android.view.View} object that wraps text, the
    -+{@link android.view.View} may need to resize.
    -+</p>
    -+
    -+<p>
    -+If cases like these take too long, they can prevent a frame from rendering
    -+within the allowed 16ms, so that frames are dropped, and animation becomes
    -+janky.
    -+</p>
    -+
    -+<p>
    -+Because you cannot move these operations to a worker thread&mdash;your app must
    -+process them on the main thread&mdash;your best bet is to optimize them so that
    -+they can take as little time as possible.
    -+</p>
    -+
    -+<h3 id="managing">Managing complexity: layouts matter</h3>
    -+
    -+<p>
    -+Android <a
    -+href="{@docRoot}guide/topics/ui/declaring-layout.html">Layouts</a>
    -+allow you to nest UI objects in the view hierarchy. This nesting can also impose
    -+a layout cost. When your app processes an object for layout, the app performs
    -+the same process on all children of the layout as well. For a complicated
    -+layout, sometimes a cost only arises the first time the system computes the
    -+layout. For instance, when your app recycles a complex list item in a
    -+{@link android.support.v7.widget.RecyclerView} object, the
    -+system needs to lay out all of the objects. In another example, trivial changes
    -+can propagate up the chain toward the parent
    -+until they reach an object that doesn’t affect the size of the parent.
    -+</p>
    -+
    -+<p>
    -+The most common case in which layout takes an especially long time is when
    -+hierarchies of {@link android.view.View} objects are nested within one another. Each nested layout
    -+object adds cost to the layout stage. The flatter your hierarchy, the less
    -+time that it takes for the layout stage to complete.
    -+</p>
    -+
    -+<p>
    -+If you are using the {@link android.widget.RelativeLayout} class, you may be able to achieve the same
    -+effect, at lower cost, by using nested, unweighted
    -+{@link android.widget.LinearLayout} views instead. Additionally, if your app
    -+targets Android N (API level 24), it is likely that
    -+you can use a special layout editor to create a <a
    -+href="http://tools.android.com/tech-docs/layout-editor">{@code ConstraintLayout}</a>
    -+object instead of {@link android.widget.RelativeLayout}. Doing so allows you
    -+to avoid many of the issues this section
    -+describes. The <a
    -+href="http://tools.android.com/tech-docs/layout-editor">{@code ConstraintLayout}</a>
    -+class offers similar layout control, but
    -+with much-improved performance. This class uses its own constraint-solving
    -+system to resolve relationships between views in a very different way from
    -+standard layouts.
    -+</p>
    -+
    -+<h3 id="double">Double Taxation</h3>
    -+
    -+<p>
    -+Typically, the framework executes the <a
    -+href="{@docRoot}guide/topics/ui/declaring-layout.html">layout</a>
    -+or measure stage in a single pass and quite quickly. However, with some more
    -+complicated layout cases, the framework may have to iterate multiple times on
    -+the layout or measure stage before ultimately positioning the elements. Having
    -+to perform more than one layout-and-measure iteration is referred to as
    -+<em>double taxation.</em>
    -+</p>
    -+
    -+<p>
    -+For example, when you use the {@link android.widget.RelativeLayout} container, which allows you to
    -+position {@link android.view.View} objects with respect to the positions of other {@link android.view.View} objects, the
    -+framework performs the following actions:
    -+</p>
    -+
    -+<ol style="1">
    -+   <li>Executes a layout-and-measure pass, during which the framework calculates
    -+each child object’s position and size, based on each child’s request.
    -+   <li>Uses this data, also taking object weights into account, to figure out the
    -+proper position of correlated views.
    -+   <li>Performs a second layout pass to finalize the objects’ positions.
    -+   <li>Goes on to the next stage of the rendering process.</li></ol>
    -+
    -+<p>
    -+The more levels your view hierarchy has, the greater the potential performance
    -+penalty.
    -+</p>
    -+
    -+<p>
    -+Containers other than {@link android.widget.RelativeLayout} may also give rise to double taxation. For
    -+example:
    -+</p>
    -+
    -+<ul>
    -+   <li>A {@link android.widget.LinearLayout} view
    -+could result in a double layout-and-measure pass if you make it horizontal.
    -+A double layout-and-measure pass may also occur in a vertical orientation if you
    -+add <a
    -+href="{@docRoot}reference/android/widget/LinearLayout.html#attr_android:measureWithLargestChild">measureWithLargestChild</a>,
    -+in which case the framework may need to do a second pass to resolve the proper
    -+sizes of objects.
    -+   <li>The {@link android.widget.GridLayout}
    -+has a similar issue. While this container also allows relative positioning, it
    -+normally avoids double taxation by pre-processing the positional relationships
    -+among child views. However, if the layout uses weights or fill with the
    -+{@link android.view.Gravity} class, the
    -+benefit of that preprocessing is lost, and the framework may have to perform
    -+multiple passes if it the container were a {@link android.widget.RelativeLayout}.</li>
    -+</ul>
    -+<p>
    -+Multiple layout-and-measure passes are not, in themselves, a performance burden.
    -+But they can become so if they’re in the wrong spot. You should be wary of
    -+situations where one of the following conditions applies to your container:
    -+</p>
    -+
    -+<ul>
    -+   <li>It is a root element in your view hierarchy.
    -+   <li>It has a deep view hierarchy beneath it.
    -+   <li>It is nested.
    -+   <li>There are many instances of it populating the screen, similar to children
    -+   in a {@link android.widget.ListView} object.</li>
    -+</ul>
    -+
    -+<h2 id="dx">Diagnosing View Hierarchy Issues</h2>
    -+
    -+<p>
    -+Layout performance is a complex problem with many facets. There are a couple of
    -+tools that can give you solid indications about where performance bottlenecks
    -+are occurring. A few other tools provide less definitive information, but can
    -+also provide helpful hints.
    -+</p>
    -+
    -+<p>
    -+<h3 id="systrace">Systrace</h3>
    -+</p>
    -+
    -+<p>
    -+One tool that provides excellent data about performance is <a
    -+href="{@docRoot}studio/profile/systrace.html">Systrace</a>,
    -+which is built into Android Studio. The Systrace tool allows you to collect and
    -+inspect timing information across an entire Android device, allowing you to see
    -+specifically where performance bottlenecks arise. For more information about
    -+Systrace, see <a href=”{docRoot}<a href="{@docRoot}studio/profile/systrace.html">
    -+Analyze UI Performance with Systrace</a>.
    -+</p>
    -+
    -+<h3 id="profile">Profile GPU rendering</h3>
    -+
    -+<p>
    -+The other tool most likely to provide you with concrete information about
    -+performance bottlenecks is the on-device <a
    -+href="{@docRoot}studio/profile/dev-options-rendering.html">
    -+Profile GPU rendering</a> tool, available on devices powered by Android 6.0 (API
    -+level 23) and later.  This tool allows you to see how long the layout-and-measurestage is
    -+ taking for <a href="https://youtu.be/erGJw8WDV74">each frame
    -+of rendering</a>. This data can help you diagnose runtime performance issues,
    -+and help you determine what, if any layout-and-measure issues you need to
    -+address.
    -+</p>
    -+
    -+<p>
    -+In its graphical representation of the data it captures, <a
    -+href="{@docRoot}studio/profile/dev-options-rendering.html">Profile
    -+GPU rendering</a> uses the color blue to represent layout time. For more
    -+information about how to use this tool, see <a
    -+href="{@docRoot}studio/profile/dev-options-rendering.html">Profile
    -+GPU Rendering Walkthrough.</a>
    -+</p>
    -+
    -+<h3 id="lint">Lint</h3>
    -+
    -+<p>
    -+Android Studio’s <a
    -+href="{@docRoot}studio/write/lint.html">Lint</a> tool can
    -+help you gain a sense of inefficiencies in the view hierarchy. To use this tool,
    -+select <strong>Analyze > Inspect Code</strong>, as shown in Figure 1.
    -+</p>
    -+
    -+  <img src="{@docRoot}topic/performance/images/lint-inspect-code.png">
    -+  <p class="img-caption">
    -+    <strong>Figure 1.</strong> Locating <strong>Inspect Code</strong> in the
    -+Android Studio.
    -+  </p>
    -+
    -+<p>
    -+Information about various layout items appears under
    -+<em>Android > Lint > Performance</em>. To see more detail,
    -+you can click on each item to expand it, and see more
    -+information in the pane on the right side of the screen.
    -+Figure 2 shows an example of such a display.
    -+</p>
    -+
    -+  <img src="{@docRoot}topic/performance/images/lint-display.png">
    -+  <p class="img-caption">
    -+    <strong>Figure 2.</strong> Viewing information about specific
    -+issues that the lint tool has identified.
    -+  </p>
    -+
    -+
    -+<p>
    -+Clicking on one of these items reveals, in the pane to the right, the problem
    -+associated with that item.
    -+</p>
    -+
    -+<p>
    -+To understand more about specific topics and issues in this area, see the <a
    -+href="{@docRoot}studio/write/lint.html">Lint
    -+</a>documentation.
    -+</p>
    -+
    -+<h3 id="hv">Hierarchy Viewer</h3>
    -+
    -+<p>
    -+Android Studio’s <a
    -+href="{@docRoot}studio/profile/hierarchy-viewer.html">Hierarchy
    -+Viewer</a> tool provides a visual representation of your app’s view hierarchy.
    -+It is a good way to navigate the hierarchy of your app, providing a clear visual
    -+representation of a particular view’s parent chain, and allowing you to inspect
    -+the layouts that your app constructs.
    -+</p>
    -+
    -+<p>
    -+The views that Hierarchy Viewer presents can also help identify performance
    -+problems arising from double taxation. It can also provide an easy way for you
    -+to identify deep chains of nested layouts, or layout areas with a large amount
    -+of nested children, another potential source of performance costs. In these
    -+scenarios, the layout-and-measure stages can be particularly costly,
    -+resulting in performance issues.
    -+</p>
    -+
    -+<p>
    -+You can also can get a sense of relative time taken by layout-and-measure
    -+operations by clicking the “profile node” button.
    -+</p>
    -+
    -+<p>
    -+For more information about Hierarchy Viewer, see <a
    -+href="{@docRoot}studio/profile/optimize-ui.html#HierarchyViewer">Optimizing
    -+Your UI</a>.
    -+</p>
    -+
    -+<h2 id="solving">Solving View Hierarchy Issues</h2>
    -+
    -+<p>
    -+The fundamental concept behind solving performance problems that arise from view
    -+hierarchies is simple in concept, but more difficult in practice. Preventing
    -+view hierarchies from imposing performance penalties encompasses the dual goals
    -+of flattening your view hierarchy and reducing double taxation. This section
    -+discusses some strategies for pursuing these goals.
    -+</p>
    -+
    -+<h3 id="removing">Removing redundant nested layouts</h3>
    -+
    -+<p>
    -+Developers often use more nested layouts than necessary. For example, a
    -+{@link android.widget.RelativeLayout} container might contain a single child that is also a
    -+{@link android.widget.RelativeLayout} container. This nesting amounts to redundancy, and adds
    -+unnecessary cost to the view hierarchy.
    -+</p>
    -+
    -+<p>
    -+Lint can often flag this problem for you, reducing debugging time.
    -+</p>
    -+
    -+<h3>Adopting Merge/Include </h3>
    -+<p>
    -+One frequent cause of redundant nested layouts is the <a
    -+href="{@docRoot}training/improving-layouts/reusing-layouts.html">
    -+&lt;include&gt;
    -+tag</a>. For example, you may define a re-usable layout as follows:
    -+</p>
    -+
    -+<pre class="prettyprint">
    -+&lt;LinearLayout&gt;
    -+    &lt;!-- some stuff here --&gt;
    -+&lt;/LinearLayout&gt;
    -+&lt;/pre&gt;
    -+</pre>
    -+
    -+<p>
    -+And then an include tag to add this item to the parent container:
    -+</p>
    -+
    -+<pre class="prettyprint">
    -+&lt;LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    -+    android:orientation="vertical"
    -+    android:layout_width="match_parent"
    -+    android:layout_height="match_parent"
    -+    android:background="@color/app_bg"
    -+    android:gravity="center_horizontal"&gt;
    -+
    -+    &lt;include layout="@layout/titlebar"/&gt;
    -+
    -+    &lt;TextView android:layout_width="match_parent"
    -+              android:layout_height="wrap_content"
    -+              android:text="@string/hello"
    -+              android:padding="10dp" /&gt;
    -+
    -+    ...
    -+
    -+&lt;/LinearLayout&gt;
    -+</pre>
    -+
    -+<p>
    -+The include unnecessarily nests the first layout within the second layout.
    -+</p>
    -+
    -+<p>
    -+The <a
    -+href="{@docRoot}training/improving-layouts/reusing-layouts.html#Merge">merge
    -+</a>tag can help prevent this issue. For information about this tag, see <a
    -+href="{@docRoot}training/improving-layouts/reusing-layouts.html#Merge">Re-using
    -+Layouts with &lt;include&gt;</a>.
    -+</p>
    -+
    -+<h3 id="cheaper">Adopting a cheaper layout</h3>
    -+
    -+<p>
    -+You may not be able to adjust your existing layout scheme so that it doesn’t
    -+contain redundant layouts. In certain cases, the only solution may be to flatten
    -+your hierarchy by switching over to an entirely different layout type.
    -+</p>
    -+
    -+<p>
    -+For example, you may find that a {@link android.widget.TableLayout}
    -+provides the same functionality as a more complex layout with many
    -+positional dependencies. In the N release of Android, the
    -+<a
    -+href="http://tools.android.com/tech-docs/layout-editor">{@code ConstraintLayout}</a> class provides similar functionality to
    -+{@link android.widget.RelativeLayout}, but at a significantly lower cost.
    -+</p>
    -diff --git a/docs/html/topic/performance/rendering/overdraw.jd b/docs/html/topic/performance/rendering/overdraw.jd
    -new file mode 100644
    -index 0000000..c1feff5
    ---- /dev/null
    -+++ b/docs/html/topic/performance/rendering/overdraw.jd
    -@@ -0,0 +1,197 @@
    -+page.title=Reducing Overdraw
    -+page.metaDescription=Improve performance by reducing unnecessary rendering.
    -+
    -+meta.tags="performance"
    -+page.tags="performance"
    -+
    -+@jd:body
    -+
    -+<div id="qv-wrapper">
    -+<div id="qv">
    -+
    -+<h2>In this document</h2>
    -+    <ol>
    -+
    -+      <li>
    -+        <a href="#understanding">Understanding Overdraw</a>
    -+      </li>
    -+      <li>
    -+        <a href="#finding">Finding Overdraw Problems</a>
    -+      </li>
    -+      <li>
    -+        <a href="#fixing">Fixing Overdraw</a>
    -+      </li>
    -+    </ol>
    -+  </div>
    -+</div>
    -+
    -+<p>
    -+An app may draw the same pixel more than once within a single frame, an event
    -+called <em>overdraw</em>. Overdraw is usually unnecessary, and best
    -+eliminated. It manifests itself as a performance problem by wasting GPU time to
    -+render pixels that don't contribute to what the user sees on the screen.
    -+</p>
    -+
    -+<p>
    -+This document explains overdraw: what it is, how to diagnose it, and actions you
    -+can take to eliminate or mitigate it.
    -+</p>
    -+
    -+<h2 name="understanding">Understanding Overdraw</h2>
    -+
    -+<p>
    -+Overdraw refers to the system's drawing a pixel on the screen multiple times
    -+in a single frame of rendering. For example, if we have a bunch of stacked UI
    -+cards, each card hides a portion of the one below it.
    -+</p>
    -+
    -+<p>
    -+However, the system still needs to draw even the hidden portions of the cards
    -+in the stack. This is because stacked cards are rendered according to the
    -+<a class="external-link"
    -+href="https://en.wikipedia.org/wiki/Painter%27s_algorithm">painter's
    -+algorithm</a>: that is, in back-to-front order.
    -+This sequence of rendering allows the system to apply proper alpha blending to
    -+translucent objects such as shadows.
    -+</p>
    -+
    -+<h2 name="finding">Finding Overdraw Problems</h2>
    -+
    -+<p>
    -+The platform offers several tools to help you determine if overdraw is
    -+affecting your app's performance. These tools are available right on the device,
    -+and accessible by turning on <strong>Developer Settings</strong></a> under
    -+<em>Settings</em>. For more information about device developer settings, see
    -+<a href="/studio/run/device.html#developer-device-options">Run Apps on a
    -+Hardware Device</a>.
    -+</p>
    -+
    -+<h3 id="dgot">Debug GPU overdraw tool</h3>
    -+
    -+<p>
    -+The Debug GPU Overdraw tool uses color-coding to show the number of times your
    -+app draws each pixel on the screen. The higher this count, the
    -+more likely it is that overdraw affects your app's performance.
    -+</p>
    -+
    -+<p>
    -+For more information on how to use the tool, refer to the related
    -+<a href="/studio/profile/dev-options-overdraw.html">walkthrough</a>
    -+and
    -+<a href="https://io2015codelabs.appspot.com/codelabs/android-performance-debug-gpu-overdraw#1">
    -+codelab</a>.
    -+</p>
    -+
    -+<h3 id="pgrt">Profile GPU rendering tool</h3>
    -+
    -+<p>
    -+The Profile GPU Rendering tool displays, as a scrolling histogram, the time
    -+each stage of the rendering pipeline takes to display a single frame. The
    -+<em>Process</em> part of each bar, indicated in orange, shows when the system
    -+is swapping buffers; this metric provides important clues about overdraw.
    -+</p>
    -+
    -+<p>
    -+On less performant GPUs, available fill-rate (the speed at which the GPU can
    -+fill the frame buffer) can be quite low. As the number of
    -+pixels required to draw a frame increases, the GPU may take longer to process
    -+new commands, and ask the rest of the system to wait until it can catch up.
    -+The <em>Process</em> bar shows that this spike happens as the GPU gets
    -+overwhelmed trying to draw pixels as fast as possible. Issues other than
    -+raw numbers of pixels may also cause this metric to spike. For example,
    -+if the Debug GPU Overdraw tool shows heavy overdraw and <em>Process</em> spikes,
    -+there's likely an issue with overdraw.
    -+</p>
    -+
    -+<p class="note"><strong>Note: </strong>The
    -+<a href="https://developer.android.com/studio/profile/dev-options-rendering.html">
    -+Profile GPU Rendering</a> tool does not
    -+work with apps that use the NDK. This is because the system pushes framework
    -+messages to the background whenever OpenGL takes a full-screen context. In
    -+such cases, you may find a profiling tool provided by the GPU manufacturer
    -+helpful.</p>
    -+
    -+<h2 name="fixing">Fixing Overdraw</h2>
    -+
    -+<p>
    -+There are several strategies you can pursue to reduce or eliminate overdraw:
    -+</p>
    -+
    -+<ul>
    -+   <li>Removing unneeded backgrounds in layouts.</li>
    -+   <li>Flattening the view hierarchy.</li>
    -+   <li>Reducing transparency.</li>
    -+</ul>
    -+
    -+<p>
    -+This section provides information about each of these approaches.
    -+</p>
    -+
    -+<h3 id="rubil">Removing unneeded backgrounds in layouts</h3>
    -+
    -+<p>
    -+By default, a layout does not have a background, which means it does not render
    -+anything directly by itself. When layouts do have backgrounds, however, they may
    -+contribute to overdraw.
    -+</p>
    -+
    -+<p>
    -+Removing unnecessary backgrounds is a quick way of improving rendering
    -+performance. An unnecessary background may never be visible because it's
    -+completely covered by everything else the app is drawing on top of that
    -+view. For example, the system may entirely cover up a parent's
    -+background when it draws child views on top of it.
    -+</p>
    -+
    -+<p>
    -+To find out why you're overdrawing, walk through the hierarchy in
    -+the <a href="/studio/profile/hierarchy-viewer.html">Hierarchy Viewer</a> tool.
    -+As you do so, look out for any backgrounds you can eliminate because
    -+they are not visible to the user. Cases where many containers share a
    -+common background color offer another opportunity to eliminate unneeded
    -+backgrounds: You can set the window background to the main background color
    -+of your app, and leave all of the containers above it with no background values
    -+defined.
    -+</p>
    -+
    -+<h3 id="fvh">Flattening view hierarchy</h3>
    -+
    -+<p>
    -+Modern layouts make it easy to stack and layer views to produce beautiful
    -+design. However, doing so can degrade performance by resulting in overdraw,
    -+especially in scenarios where each stacked view object is opaque, requiring the
    -+drawing of both seen and unseen pixels to the screen.
    -+</p>
    -+
    -+<p>
    -+If you encounter this sort of issue, you may be able to improve performance by
    -+optimizing your view hierarchy to reduce the number of overlapping UI objects.
    -+For more information about how to accomplish this, see
    -+<a href="/topic/performance/optimizing-view-hierarchies.html">Optimizing View
    -+Hierarchies</a>.
    -+</p>
    -+
    -+<h3 id="rt">Reducing transparency</h3>
    -+
    -+<p>
    -+Rendering of transparent pixels on screen, known as alpha rendering, is a key
    -+contributor to overdraw. Unlike standard overdraw,
    -+in which the system completely hides existing drawn pixels by drawing
    -+opaque pixels on top of them, transparent
    -+objects require existing pixels to be drawn first, so that the right blending
    -+equation can occur.  Visual effects like transparent animations, fade-outs, and
    -+drop shadows all involve some sort of transparency, and can therefore contribute
    -+significantly to overdraw. You can improve overdraw in these situations by
    -+reducing the number of transparent objects you render. For example, you can get
    -+gray text by drawing black text in a {@link android.widget.TextView} with a
    -+translucent alpha value set on it. But you can get the same effect with far
    -+better performance by simply drawing the text in gray.
    -+</p>
    -+
    -+<p>
    -+To learn more about performance costs that transparency imposes throughout the
    -+entire drawing pipeline, watch the video
    -+<a href="https://www.youtube.com/watch?v=wIy8g8yNhNk&index=46&list=PLWz5rJ2EKKc9CBxr3BVjPTPoDPLdPIFCE">
    -+Hidden Costs of Transparency</a>.
    -+</p>
    -+
    -diff --git a/docs/html/topic/performance/rendering/profile-gpu.jd b/docs/html/topic/performance/rendering/profile-gpu.jd
    -new file mode 100644
    -index 0000000..fc98777
    ---- /dev/null
    -+++ b/docs/html/topic/performance/rendering/profile-gpu.jd
    -@@ -0,0 +1,406 @@
    -+page.title=Analyzing with Profile GPU Rendering
    -+page.metaDescription=Use the Profile GPU tool to help you optimize your app's rendering performance.
    -+
    -+meta.tags="power"
    -+page.tags="power"
    -+
    -+@jd:body
    -+
    -+<div id="qv-wrapper">
    -+<div id="qv">
    -+
    -+<h2>In this document</h2>
    -+    <ol>
    -+      <li>
    -+        <a href="#visrep">Visual Representation</a></li>
    -+      </li>
    -+
    -+      <li>
    -+       <a href="#sam">Stages and Their Meanings</a>
    -+      
    -+      <ul>
    -+         <li>
    -+           <a href="#sv">Input Handling</a>
    -+         </li>
    -+         <li>
    -+           <a href="#asd">Animation</a>
    -+         </li>
    -+         <li>
    -+           <a href="#asd">Measurement/Layout</a>
    -+         </li>
    -+         <li>
    -+           <a href="#asd">Drawing</a>
    -+         </li>
    -+         </li>
    -+         <li>
    -+           <a href="#asd">Sync/Upload</a>
    -+         </li>
    -+         <li>
    -+           <a href="#asd">Issuing Commands</a>
    -+         </li>
    -+         <li>
    -+           <a href="#asd">Processing/Swapping Buffer</a>
    -+         </li>
    -+         <li>
    -+           <a href="#asd">Miscellaneous</a>
    -+         </li>
    -+      </ul>
    -+      </li>     
    -+     </ol>
    -+  </div>
    -+</div>
    -+
    -+<p>
    -+The <a href="/studio/profile/dev-options-rendering.html">
    -+Profile GPU Rendering</a> tool indicates the relative time that each stage of
    -+the rendering pipeline takes to render the previous frame. This knowledge
    -+can help you identify bottlenecks in the pipeline, so that you
    -+can know what to optimize to improve your app's rendering performance.
    -+</p>
    -+
    -+<p>
    -+This page briefly explains what happens during each pipeline stage, and
    -+discusses issues that can cause bottlenecks there. Before reading
    -+this page, you should be familiar with the information presented in the
    -+<a href="/studio/profile/dev-options-rendering.html">Profile GPU
    -+Rendering Walkthrough</a>. In addition, to understand how all of the
    -+stages fit together, it may be helpful to review
    -+<a href="https://www.youtube.com/watch?v=we6poP0kw6E&index=64&list=PLWz5rJ2EKKc9CBxr3BVjPTPoDPLdPIFCE">
    -+how the rendering pipeline works.</a>
    -+</p>
    -+
    -+<h2 id="#visrep">Visual Representation</h2>
    -+
    -+<p>
    -+The Profile GPU Rendering tool displays stages and their relative times in the
    -+form of a graph: a color-coded histogram. Figure 1 shows an example of
    -+such a display.
    -+</p>
    -+
    -+  <img src="{@docRoot}topic/performance/images/bars.png">
    -+  <p class="img-caption">
    -+<strong>Figure 1.</strong> Profile GPU Rendering Graph
    -+  </p>
    -+
    -+</p>
    -+
    -+<p>
    -+Each segment of each vertical bar displayed in the Profile GPU Rendering
    -+graph represents a stage of the pipeline and is highlighted using a specific
    -+color in
    -+the bar graph. Figure 2 shows a key to the meaning of each displayed color.
    -+</p>
    -+
    -+  <img src="{@docRoot}topic/performance/images/s-profiler-legend.png">
    -+  <p class="img-caption">
    -+<strong>Figure 2.</strong> Profile GPU Rendering Graph Legend
    -+  </p>
    -+
    -+<p>
    -+Once you understand what each color signfiies,
    -+you can target specific aspects of your
    -+app to try to optimize its rendering performance.
    -+</p>
    -+
    -+<h2 id="sam">Stages and Their Meanings</a></h2>
    -+
    -+<p>
    -+This section explains what happens during each stage corresponding
    -+to a color in Figure 2, as well as bottleneck causes to look out for.
    -+</p>
    -+
    -+
    -+<h3 id="ih">Input Handling</h3>
    -+
    -+<p>
    -+The input handling stage of the pipeline measures how long the app
    -+spent handling input events. This metric indicates how long the app
    -+spent executing code called as a result of input event callbacks.
    -+</p>
    -+
    -+<h4>When this segment is large</h4>
    -+
    -+<p>
    -+High values in this area are typically a result of too much work, or
    -+too-complex work, occurring inside the input-handler event callbacks.
    -+Since these callbacks always occur on the main thread, solutions to this
    -+problem focus on optimizing the work directly, or offloading the work to a
    -+different thread.
    -+</p>
    -+
    -+<p>
    -+It’s also worth noting that {@link android.support.v7.widget.RecyclerView}
    -+scrolling can appear in this phase.
    -+{@link android.support.v7.widget.RecyclerView} scrolls immediately when it
    -+consumes the touch event. As a result,
    -+it can inflate or populate new item views. For this reason, it’s important to
    -+make this operation as fast as possible. Profiling tools like Traceview or
    -+Systrace can help you investigate further.
    -+</p>
    -+
    -+<h3 id="at">Animation</h3>
    -+
    -+<p>
    -+The Animations phase shows you just how long it took to evaluate all the
    -+animators that were running in that frame. The most common animators are
    -+{@link android.animation.ObjectAnimator},
    -+{@link android.view.ViewPropertyAnimator}, and
    -+<a href="/training/transitions/overview.html">Transitions</a>.
    -+</p>
    -+
    -+<h4>When this segment is large</h4>
    -+
    -+<p>
    -+High values in this area are typically a result of work that’s executing due
    -+to some property change of the animation. For example, a fling animation,
    -+which scrolls your {@link android.widget.ListView} or
    -+{@link android.support.v7.widget.RecyclerView}, causes large amounts of view
    -+inflation and population.
    -+</p>
    -+
    -+<h3 id="ml">Measurement/Layout</h3>
    -+
    -+<p>
    -+In order for Android to draw your view items on the screen, it executes
    -+two specific operations across layouts and views in your view hierarchy.
    -+</p>
    -+
    -+<p>
    -+First, the system measures the view items. Every view and layout has
    -+specific data that describes the size of the object on the screen. Some views
    -+can have a specific size; others have a size that adapts to the size
    -+of the parent layout container
    -+</p>
    -+
    -+<p>
    -+Second, the system lays out the view items. Once the system calculates
    -+the sizes of children views, the system can proceed with layout, sizing
    -+and positioning the views on the screen.
    -+</p>
    -+
    -+<p>
    -+The system performs measurement and layout not only for the views to be drawn,
    -+but also for the parent hierarchies of those views, all the way up to the root
    -+view.
    -+</p>
    -+
    -+<h4>When this segment is large</h4>
    -+
    -+<p>
    -+If your app spends a lot of time per frame in this area, it is
    -+usually either because of the sheer volume of views that need to be
    -+laid out, or problems such as
    -+<a href="/topic/performance/optimizing-view-hierarchies.html#double">
    -+double taxation</a> at the wrong spot in your
    -+hierarchy. In either of these cases, addressing performance involves
    -+<a href="/topic/performance/optimizing-view-hierarchies.html">improving
    -+the performance of your view hierarchies</a>.
    -+</p>
    -+
    -+<p>
    -+Code that you’ve added to
    -+{@link android.view.View#onLayout(boolean, int, int, int, int)} or
    -+{@link android.view.View#onMeasure(int, int)}
    -+can also cause performance
    -+issues. <a href="/studio/profile/traceview.html">Traceview</a> and
    -+<a href="/studio/profile/systrace.html">Systrace</a> can help you examine
    -+the callstacks to identify problems your code may have.
    -+</p>
    -+
    -+<h3 id="draw">Drawing</h3>
    -+
    -+<p>
    -+The draw stage translates a view’s rendering operations, such as drawing
    -+a background or drawing text, into a sequence of native drawing commands.
    -+The system captures these commands into a display list.
    -+</p>
    -+
    -+<p>
    -+The Draw bar records how much time it takes to complete capturing the commands
    -+into the display list, for all the views that needed to be updated on the screen
    -+this frame. The measured time applies to any code that you have added to the UI
    -+objects in your app. Examples of such code may be the
    -+{@link android.view.View#onDraw(android.graphics.Canvas) onDraw()},
    -+{@link android.view.View#dispatchDraw(android.graphics.Canvas) dispatchDraw()},
    -+and the various <code>draw ()methods</code> belonging to the subclasses of the
    -+{@link android.graphics.drawable.Drawable} class.
    -+</p>
    -+
    -+<h4>When this segment is large</h4>
    -+
    -+<p>
    -+In simplified terms, you can understand this metric as showing how long it took
    -+to run all of the calls to
    -+{@link android.view.View#onDraw(android.graphics.Canvas) onDraw()}
    -+for each invalidated view. This
    -+measurement includes any time spent dispatching draw commands to children and
    -+drawables that may be present. For this reason, when you see this bar spike, the
    -+cause could be that a bunch of views suddenly became invalidated. Invalidation
    -+makes it necessary to regenerate views' display lists. Alternatively, a
    -+lengthy time may be the result of a few custom views that have some extremely
    -+complex logic in their
    -+{@link android.view.View#onDraw(android.graphics.Canvas) onDraw()} methods.
    -+</p>
    -+
    -+<h3 id="su">Sync/Upload</h3>
    -+
    -+<p>
    -+The Sync & Upload metric represents the time it takes to transfer
    -+bitmap objects from CPU memory to GPU memory during the current frame.
    -+</p>
    -+
    -+<p>
    -+As different processors, the CPU and the GPU have different RAM areas
    -+dedicated to processing. When you draw a bitmap on Android, the system
    -+transfers the bitmap to GPU memory before the GPU can render it to the
    -+screen. Then, the GPU caches the bitmap so that the system doesn’t need to
    -+transfer the data again unless the texture gets evicted from the GPU texture
    -+cache.
    -+</p>
    -+
    -+<p class="note"><strong>Note:</strong> On Lollipop devices, this stage is
    -+purple.
    -+</p>
    -+
    -+<h4>When this segment is large</h4>
    -+
    -+<p>
    -+All resources for a frame need to reside in GPU memory before they can be
    -+used to draw a frame. This means that a high value for this metric could mean
    -+either a large number of small resource loads or a small number of very large
    -+resources. A common case is when an app displays a single bitmap that’s
    -+close to the size of the screen. Another case is when an app displays a
    -+large number of thumbnails.
    -+</p>
    -+
    -+<p>
    -+To shrink this bar, you can employ techniques such as:
    -+</p>
    -+
    -+<ul>
    -+   <li>
    -+Ensuring your bitmap resolutions are not much larger than the size at which they
    -+will be displayed. For example, your app should avoid displaying a 1024x1024
    -+image as a 48x48 image.
    -+   </li>
    -+
    -+   <li>
    -+Taking advantage of {@link android.graphics.Bitmap#prepareToDraw()}
    -+to asynchronously pre-upload a bitmap before the next sync phase.
    -+   </li>
    -+</ul>
    -+
    -+<h3 id="ic">Issuing Commands</h3>
    -+
    -+<p>
    -+The <em>Issue Commands</em> segment represents the time it takes to issue all
    -+of the commands necessary for drawing display lists to the screen.
    -+</p>
    -+
    -+<p>
    -+For the system to draw display lists to the screen, it sends the
    -+necessary commands to the GPU. Typically, it performs this action through the
    -+<a href="/guide/topics/graphics/opengl.html">OpenGL ES</a> API.
    -+</p>
    -+
    -+<p>
    -+This process takes some time, as the system performs final transformation
    -+and clipping for each command before sending the command to the GPU. Additional
    -+overhead then arises on the GPU side, which computes the final commands. These
    -+commands include final transformations, and additional clipping.
    -+</p>
    -+
    -+<h4>When this segment is large</h4>
    -+
    -+<p>
    -+The time spent in this stage is a direct measure of the complexity and
    -+quantity of display lists that the system renders in a given
    -+frame. For example, having many draw operations, especially in cases where
    -+there's a small inherent cost to each draw primitive, could inflate this time.
    -+For example:
    -+</p>
    -+
    -+<pre>
    -+for (int i = 0; i < 1000; i++)
    -+canvas.drawPoint()
    -+</pre>
    -+
    -+<p>
    -+is a lot more expensive to issue than:
    -+</p>
    -+
    -+<pre>
    -+canvas.drawPoints(mThousandPointArray);
    -+</pre>
    -+
    -+<p>
    -+There isn’t always a 1:1 correlation between issuing commands and
    -+actually drawing display lists. Unlike <em>Issue Commands</em>,
    -+which captures the time it takes to send drawing commands to the GPU,
    -+the <em>Draw</em> metric represents the time that it took to capture the issued
    -+commands into the display list.
    -+</p>
    -+
    -+<p>
    -+This difference arises because the display lists are cached by
    -+the system wherever possible. As a result, there are situations where a
    -+scroll, transform, or animation requires the system to re-send a display
    -+list, but not have to actually rebuild it&mdash;recapture the drawing
    -+commands&mdash;from scratch. As a result, you can see a high “Issue
    -+commands” bar without seeing a high <em>Draw commands</em> bar.
    -+</p>
    -+
    -+<h3 id="psb">Processing/Swapping Buffers</h3>
    -+
    -+<p>
    -+Once Android finishes submitting all its display list to the GPU,
    -+the system issues one final command to tell the graphics driver that it's
    -+done with the current frame. At this point, the driver can finally present
    -+the updated image to the screen.
    -+</p>
    -+
    -+<h4>When this segment is large</h4>
    -+
    -+<p>
    -+It’s important to understand that the GPU executes work in parallel with the
    -+CPU. The Android system issues draw commands to the GPU, and then moves on to
    -+the next task. The GPU reads those draw commands from a queue and processes
    -+them.
    -+</p>
    -+
    -+<p>
    -+In situations where the CPU issues commands faster than the GPU
    -+consumes them, the communications queue between the processors can become
    -+full. When this occurs, the CPU blocks, and waits until there is space in the
    -+queue to place the next command. This full-queue state arises often during the
    -+<em>Swap Buffers</em> stage, because at that point, a whole frame’s worth of
    -+commands have been submitted.
    -+</p>
    -+
    -+</p>
    -+The key to mitigating this problem is to reduce the complexity of work occurring
    -+on the GPU, in similar fashion to what you would do for the “Issue Commands”
    -+phase.
    -+</p>
    -+
    -+
    -+<h3 id="mt">Miscellaneous</h3>
    -+
    -+<p>
    -+In addition to the time it takes the rendering system to perform its work,
    -+there’s an additional set of work that occurs on the main thread and has
    -+nothing to do with rendering. Time that this work consumes is reported as
    -+<em>misc time</em>. Misc time generally represents work that might be occurring
    -+on the UI thread between two consecutive frames of rendering.
    -+</p>
    -+
    -+<h4>When this segment is large</h4>
    -+
    -+<p>
    -+If this value is high, it is likely that your app has callbacks, intents, or
    -+other work that should be happening on another thread. Tools such as
    -+<a href="/studio/profile/traceview.html">Method
    -+Tracing</a> or <a href="/studio/profile/systrace.html">Systrace</a> can provide
    -+visibility into the tasks that are running on
    -+the main thread. This information can help you target performance improvements.
    -+</p>
    -diff --git a/docs/html/training/_book.yaml b/docs/html/training/_book.yaml
    -index 891574f..47862e2 100644
    ---- a/docs/html/training/_book.yaml
    -+++ b/docs/html/training/_book.yaml
    -@@ -438,16 +438,6 @@ toc:
    -       path: /training/efficient-downloads/redundant_redundant.html
    -     - title: Modifying Patterns Based on the Connectivity Type
    -       path: /training/efficient-downloads/connectivity_patterns.html
    --  - title: Backing up App Data to the Cloud
    --    path: /training/backup/index.html
    --    path_attributes:
    --    - name: description
    --      value: How to sync and back up app and user data to remote web services in the cloud and how to restore the data back to multiple devices.
    --    section:
    --    - title: Configuring Auto Backup
    --      path: /training/backup/autosyncapi.html
    --    - title: Using the Backup API
    --      path: /training/backup/backupapi.html
    -   - title: Resolving Cloud Save Conflicts
    -     path: /training/cloudsave/conflict-res.html
    -     path_attributes:
    -@@ -695,6 +685,8 @@ toc:
    -         value: 再生中カードを表示する
    -     - title: Adding a Guided Step
    -       path: /training/tv/playback/guided-step.html
    -+    - title: Introducing First-time Users to Your App
    -+      path: /training/tv/playback/onboarding.html
    -     - title: Enabling Background Playback
    -       path: /training/tv/playback/options.html
    -     - title: Adding Picture-in-picture
    -@@ -898,6 +890,11 @@ toc:
    -         value: 順応性のある UI フローの実装
    -       - name: zh-cn-lang
    -         value: 实施自适应用户界面流程
    -+  - title: Build a Responsive UI with ConstraintLayout
    -+    path: /training/constraint-layout/index.html
    -+    path_attributes:
    -+    - name: description
    -+      value: How to build a layout using ConstraintLayout and the Android Studio Layout Editor.
    -   - title: Adding the App Bar
    -     path: /training/appbar/index.html
    -     path_attributes:
    -@@ -1149,6 +1146,8 @@ toc:
    -         value: 维护兼容性
    -       - name: zh-tw-lang
    -         value: 維持相容性
    -+    - title: Selecting Colors with the Palette API
    -+      path: /training/material/palette-colors.html
    - 
    - - title: Best Practices for User Input
    -   path: /training/best-user-input.html
    -@@ -1233,15 +1232,9 @@ toc:
    -       path: /training/scheduling/wakelock.html
    -     - title: Scheduling Repeating Alarms
    -       path: /training/scheduling/alarms.html
    --
    - - title: Best Practices for Performance
    -   path: /training/best-performance.html
    -   section:
    --  - title: Managing Your App's Memory
    --    path: /training/articles/memory.html
    --    path_attributes:
    --    - name: description
    --      value: How to keep your app's memory footprint small in order to improve performance on a variety of mobile devices.
    -   - title: Performance Tips
    -     path: /training/articles/perf-tips.html
    -     path_attributes:
    -@@ -1273,23 +1266,6 @@ toc:
    -     - name: description
    -       value: How to minimize the amount of power your app requires by adapting to current power conditions and performing power-hungry tasks at proper intervals.
    -     section:
    --    - title: Reducing Network Battery Drain
    --      path: /training/performance/battery/network/index.html
    --      section:
    --      - title: Collecting Network Traffic Data
    --        path: /training/performance/battery/network/gather-data.html
    --      - title: Analyzing Network Traffic Data
    --        path: /training/performance/battery/network/analyze-data.html
    --      - title: Optimizing User-Initiated Network Use
    --        path: /training/performance/battery/network/action-user-traffic.html
    --      - title: Optimizing App-Initiated Network Use
    --        path: /training/performance/battery/network/action-app-traffic.html
    --      - title: Optimizing Server-Initiated Network Use
    --        path: /training/performance/battery/network/action-server-traffic.html
    --      - title: Optimizing General Network Use
    --        path: /training/performance/battery/network/action-any-traffic.html
    --    - title: Optimizing for Doze and App Standby
    --      path: /training/monitoring-device-state/doze-standby.html
    -     - title: Monitoring the Battery Level and Charging State
    -       path: /training/monitoring-device-state/battery-monitoring.html
    -       path_attributes:
    -diff --git a/docs/html/training/accessibility/service.jd b/docs/html/training/accessibility/service.jd
    -index de00db7..c034145 100755
    ---- a/docs/html/training/accessibility/service.jd
    -+++ b/docs/html/training/accessibility/service.jd
    -@@ -17,7 +17,7 @@ previous.link=accessible-app.html
    -   <li><a href="#create">Create Your Accessibility Service</a></li>
    -   <li><a href="#configure">Configure Your Accessibility Service</a></li>
    -   <li><a href="#events">Respond to AccessibilityEvents</a></li>
    --  <li><a href="#query">Query the View Heirarchy for More Context</a></li>
    -+  <li><a href="#query">Query the View Hierarchy for More Context</a></li>
    - </ol>
    - 
    - <h2>You should also read</h2>
    -@@ -174,7 +174,7 @@ android.accessibilityservice.AccessibilityService#onAccessibilityEvent} method.
    - In that method, use {@link
    - android.view.accessibility.AccessibilityEvent#getEventType} to determine the
    - type of event, and {@link
    --android.view.accessibility.AccessibilityRecord#getContentDescription} to extract
    -+android.view.accessibility.AccessibilityEvent#getContentDescription} to extract
    - any label text associated with the view that fired the event.</pre>
    - 
    - <pre>
    -@@ -200,7 +200,7 @@ public void onAccessibilityEvent(AccessibilityEvent event) {
    - }
    - </pre>
    - 
    --<h2 id="query">Query the View Heirarchy for More Context</h2>
    -+<h2 id="query">Query the View Hierarchy for More Context</h2>
    - <p>This step is optional, but highly useful. The Android platform provides the ability for an
    - {@link android.accessibilityservice.AccessibilityService} to query the view
    - hierarchy, collecting information about the UI component that generated an event, and
    -@@ -211,7 +211,7 @@ android:canRetrieveWindowContent="true"
    - </pre>
    - <p>Once that's done, get an {@link
    - android.view.accessibility.AccessibilityNodeInfo} object using {@link
    --android.view.accessibility.AccessibilityRecord#getSource}.  This call only
    -+android.view.accessibility.AccessibilityEvent#getSource}.  This call only
    - returns an object if the window where the event originated is still the active
    - window.  If not, it will return null, so <em>behave accordingly</em>.  The
    - following example is a snippet of code that, when it receives an event, does
    -diff --git a/docs/html/training/articles/memory.jd b/docs/html/training/articles/memory.jd
    -deleted file mode 100644
    -index de7af58..0000000
    ---- a/docs/html/training/articles/memory.jd
    -+++ /dev/null
    -@@ -1,740 +0,0 @@
    --page.title=Managing Your App's Memory
    --page.tags=ram,low memory,OutOfMemoryError,onTrimMemory
    --page.article=true
    --@jd:body
    --
    --
    --<div id="tb-wrapper">
    --<div id="tb">
    --
    --<h2>In this document</h2>
    --<ol class="nolist">
    --  <li><a href="#Android">How Android Manages Memory</a>
    --    <ol>
    --      <li><a href="#SharingRAM">Sharing Memory</a></li>
    --      <li><a href="#AllocatingRAM">Allocating and Reclaiming App Memory</a></li>
    --      <li><a href="#RestrictingMemory">Restricting App Memory</a></li>
    --      <li><a href="#SwitchingApps">Switching Apps</a></li>
    --    </ol>
    --  </li>
    --  <li><a href="#YourApp">How Your App Should Manage Memory</a>
    --    <ol>
    --      <li><a href="#Services">Use services sparingly</a></li>
    --      <li><a href="#ReleaseMemoryAsUiGone">Release memory when your user interface becomes hidden</a></li>
    --      <li><a href="#ReleaseMemoryAsTight">Release memory as memory becomes tight</a></li>
    --      <li><a href="#CheckHowMuchMemory">Check how much memory you should use</a></li>
    --      <li><a href="#Bitmaps">Avoid wasting memory with bitmaps</a></li>
    --      <li><a href="#DataContainers">Use optimized data containers</a></li>
    --      <li><a href="#Overhead">Be aware of memory overhead</a></li>
    --      <li><a href="#Abstractions">Be careful with code abstractions</a></li>
    --      <li><a href="#NanoProto">Use nano protobufs for serialized data</a></li>
    --      <li><a href="#DependencyInjection">Avoid dependency injection frameworks</a></li>
    --      <li><a href="#ExternalLibs">Be careful about using external libraries</a></li>
    --      <li><a href="#OverallPerf">Optimize overall performance</a></li>
    --      <li><a href="#Proguard">Use ProGuard to strip out any unneeded code</a></li>
    --      <li><a href="#Zipalign">Use zipalign on your final APK</a></li>
    --      <li><a href="#AnalyzeRam">Analyze your RAM usage</a></li>
    --      <li><a href="#MultipleProcesses">Use multiple processes</a></li>
    --    </ol>
    --  </li>
    --</ol>
    --<h2>See Also</h2>
    --<ul>
    --  <li><a href="{@docRoot}tools/debugging/debugging-memory.html">Investigating Your RAM Usage</a>
    --  </li>
    --</ul>
    --
    --</div>
    --</div>
    --
    --
    --<p>Random-access memory (RAM) is a valuable resource in any software development environment, but
    --it's even more valuable on a mobile operating system where physical memory is often constrained.
    --Although Android's Dalvik virtual machine performs routine garbage collection, this doesn't allow
    --you to ignore when and where your app allocates and releases memory.</p>
    --
    --<p>In order for the garbage collector to reclaim memory from your app, you need to avoid
    --introducing memory leaks (usually caused by holding onto object references in global members) and
    --release any {@link java.lang.ref.Reference} objects at the appropriate time (as defined by
    --lifecycle callbacks discussed further below). For most apps, the Dalvik garbage collector takes
    --care of the rest: the system reclaims your memory allocations when the corresponding objects leave
    --the scope of your app's active threads.</p>
    --
    --<p>This document explains how Android manages app processes and memory allocation, and how you can
    --proactively reduce memory usage while developing for Android. For more information about general
    --practices to clean up your resources when programming in Java, refer to other books or online
    --documentation about managing resource references. If you’re looking for information about how to
    --analyze your app’s memory once you’ve already built it, read <a
    --href="{@docRoot}tools/debugging/debugging-memory.html">Investigating Your RAM Usage</a>.</p>
    --
    --
    --
    --
    --<h2 id="Android">How Android Manages Memory</h2>
    --
    --<p>Android does not offer swap space for memory, but it does use <a href=
    --"http://en.wikipedia.org/wiki/Paging" class="external-link">paging</a> and <a href=
    --"http://en.wikipedia.org/wiki/Memory-mapped_files" class="external-link">memory-mapping</a>
    --(mmapping) to manage memory. This means that any memory you modify&mdash;whether by allocating
    --new objects or touching mmapped pages&mdash;remains resident in RAM and cannot be paged out.
    --So the only way to completely release memory from your app is to release object references you may
    --be holding, making the memory available to the garbage collector. That is with one exception:
    --any files mmapped in without modification, such as code, can be paged out of RAM if the system
    --wants to use that memory elsewhere.</p>
    --
    --
    --<h3 id="SharingRAM">Sharing Memory</h3>
    --
    --<p>In order to fit everything it needs in RAM, Android tries to share RAM pages across processes. It
    --can do so in the following ways:</p>
    --<ul>
    --<li>Each app process is forked from an existing process called Zygote.
    --The Zygote process starts when the system boots and loads common framework code and resources
    --(such as activity themes). To start a new app process, the system forks the Zygote process then
    --loads and runs the app's code in the new process. This allows most of the RAM pages allocated for
    --framework code and resources to be shared across all app processes.</li>
    --
    --<li>Most static data is mmapped into a process. This not only allows that same data to be shared
    --between processes but also allows it to be paged out when needed. Example static data include:
    --Dalvik code (by placing it in a pre-linked {@code .odex} file for direct mmapping), app resources
    --(by designing the resource table to be a structure that can be mmapped and by aligning the zip
    --entries of the APK), and traditional project elements like native code in {@code .so} files.</li>
    --
    --<li>In many places, Android shares the same dynamic RAM across processes using explicitly allocated
    --shared memory regions (either with ashmem or gralloc). For example, window surfaces use shared
    --memory between the app and screen compositor, and cursor buffers use shared memory between the
    --content provider and client.</li>
    --</ul>
    --
    --<p>Due to the extensive use of shared memory, determining how much memory your app is using requires
    --care. Techniques to properly determine your app's memory use are discussed in <a
    --href="{@docRoot}tools/debugging/debugging-memory.html">Investigating Your RAM Usage</a>.</p>
    --
    --
    --<h3 id="AllocatingRAM">Allocating and Reclaiming App Memory</h3>
    --
    --<p>Here are some facts about how Android allocates then reclaims memory from your app:</p>
    --
    --<ul>
    --<li>The Dalvik heap for each process is constrained to a single virtual memory range. This defines
    --the logical heap size, which can grow as it needs to (but only up to a limit that the system defines
    --for each app).</li>
    --
    --<li>The logical size of the heap is not the same as the amount of physical memory used by the heap.
    --When inspecting your app's heap, Android computes a value called the Proportional Set Size (PSS),
    --which accounts for both dirty and clean pages that are shared with other processes&mdash;but only in an
    --amount that's proportional to how many apps share that RAM. This (PSS) total is what the system
    --considers to be your physical memory footprint. For more information about PSS, see the <a
    --href="{@docRoot}tools/debugging/debugging-memory.html#ViewingAllocations">Investigating Your
    --RAM Usage</a> guide.</li>
    --
    --<li>The Dalvik heap does not compact the logical size of the heap, meaning that Android does not
    --defragment the heap to close up space. Android can only shrink the logical heap size when there
    --is unused space at the end of the heap. But this doesn't mean the physical memory used by the heap
    --can't shrink. After garbage collection, Dalvik walks the heap and finds unused pages, then returns
    --those pages to the kernel using madvise. So, paired allocations and deallocations of large
    --chunks should result in reclaiming all (or nearly all) the physical memory used. However,
    --reclaiming memory from small allocations can be much less efficient because the page used
    --for a small allocation may still be shared with something else that has not yet been freed.</li>
    --</ul>
    --
    --
    --<h3 id="RestrictingMemory">Restricting App Memory</h3>
    --
    --<p>To maintain a functional multi-tasking environment, Android sets a hard limit on the heap size
    --for each app. The exact heap size limit varies between devices based on how much RAM the device
    --has available overall. If your app has reached the heap capacity and tries to allocate more
    --memory, it will receive an {@link java.lang.OutOfMemoryError}.</p>
    --
    --<p>In some cases, you might want to query the system to determine exactly how much heap space you
    --have available on the current device&mdash;for example, to determine how much data is safe to keep in a
    --cache. You can query the system for this figure by calling {@link
    --android.app.ActivityManager#getMemoryClass()}. This returns an integer indicating the number of
    --megabytes available for your app's heap. This is discussed further below, under
    --<a href="#CheckHowMuchMemory">Check how much memory you should use</a>.</p>
    --
    --
    --<h3 id="SwitchingApps">Switching Apps</h3>
    --
    --<p>Instead of using swap space when the user switches between apps, Android keeps processes that
    --are not hosting a foreground ("user visible") app component in a least-recently used (LRU) cache.
    --For example, when the user first launches an app, a process is created for it, but when the user
    --leaves the app, that process does <em>not</em> quit. The system keeps the process cached, so if
    --the user later returns to the app, the process is reused for faster app switching.</p>
    --
    --<p>If your app has a cached process and it retains memory that it currently does not need,
    --then your app&mdash;even while the user is not using it&mdash;is constraining the system's
    --overall performance. So, as the system runs low on memory, it may kill processes in the LRU cache
    --beginning with the process least recently used, but also giving some consideration toward
    --which processes are most memory intensive. To keep your process cached as long as possible, follow
    --the advice in the following sections about when to release your references.</p>
    --
    --<p>More information about how processes are cached while not running in the foreground and how
    --Android decides which ones
    --can be killed is available in the <a href="{@docRoot}guide/components/processes-and-threads.html"
    -->Processes and Threads</a> guide.</p>
    --
    --
    --
    --
    --<h2 id="YourApp">How Your App Should Manage Memory</h2>
    --
    --<p>You should consider RAM constraints throughout all phases of development, including during app
    --design (before you begin development). There are many
    --ways you can design and write code that lead to more efficient results, through aggregation of the
    --same techniques applied over and over.</p>
    --
    --<p>You should apply the following techniques while designing and implementing your app to make it
    --more memory efficient.</p>
    --
    --
    --<h3 id="Services">Use services sparingly</h3>
    --
    --<p>If your app needs a <a href="{@docRoot}guide/components/services.html">service</a>
    --to perform work in the background, do not keep it running unless
    --it's actively performing a job. Also be careful to never leak your service by failing to stop it
    --when its work is done.</p>
    --
    --<p>When you start a service, the system prefers to always keep the process for that service
    --running. This makes the process very expensive because the RAM used by the service can’t be used by
    --anything else or paged out. This reduces the number of cached processes that the system can keep in
    --the LRU cache, making app switching less efficient. It can even lead to thrashing in the system
    --when memory is tight and the system can’t maintain enough processes to host all the services
    --currently running.</p>
    --
    --<p>The best way to limit the lifespan of your service is to use an {@link
    --android.app.IntentService}, which finishes
    --itself as soon as it's done handling the intent that started it. For more information, read
    --<a href="{@docRoot}training/run-background-service/index.html">Running in a Background Service</a>
    --.</p>
    --
    --<p>Leaving a service running when it’s not needed is <strong>one of the worst memory-management
    --mistakes</strong> an Android app can make. So don’t be greedy by keeping a service for your app
    --running. Not only will it increase the risk of your app performing poorly due to RAM constraints,
    --but users will discover such misbehaving apps and uninstall them.</p>
    --
    --
    --<h3 id="ReleaseMemoryAsUiGone">Release memory when your user interface becomes hidden</h3>
    --
    --<p>When the user navigates to a different app and your UI is no longer visible, you should
    --release any resources that are used by only your UI. Releasing UI resources at this time can
    --significantly increase the system's capacity for cached processes, which has a direct impact on the
    --quality of the user experience.</p>
    --
    --<p>To be notified when the user exits your UI, implement the {@link
    --android.content.ComponentCallbacks2#onTrimMemory onTrimMemory()} callback in your {@link
    --android.app.Activity} classes. You should use this
    --method to listen for the {@link android.content.ComponentCallbacks2#TRIM_MEMORY_UI_HIDDEN} level,
    --which indicates your UI is now hidden from view and you should free resources that only your UI
    --uses.</p>
    --
    --
    --<p>Notice that your app receives the {@link android.content.ComponentCallbacks2#onTrimMemory
    --onTrimMemory()} callback with {@link android.content.ComponentCallbacks2#TRIM_MEMORY_UI_HIDDEN}
    --only when <em>all the UI components</em> of your app process become hidden from the user.
    --This is distinct
    --from the {@link android.app.Activity#onStop onStop()} callback, which is called when an {@link
    --android.app.Activity} instance becomes hidden, which occurs even when the user moves to
    --another activity in your app. So although you should implement {@link android.app.Activity#onStop
    --onStop()} to release activity resources such as a network connection or to unregister broadcast
    --receivers, you usually should not release your UI resources until you receive {@link
    --android.content.ComponentCallbacks2#onTrimMemory onTrimMemory(TRIM_MEMORY_UI_HIDDEN)}. This ensures
    --that if the user navigates <em>back</em> from another activity in your app, your UI resources are
    --still available to resume the activity quickly.</p>
    --
    --
    --
    --<h3 id="ReleaseMemoryAsTight">Release memory as memory becomes tight</h3>
    --
    --<p>During any stage of your app's lifecycle, the {@link
    --android.content.ComponentCallbacks2#onTrimMemory onTrimMemory()} callback also tells you when
    --the overall device memory is getting low. You should respond by further releasing resources based
    --on the following memory levels delivered by {@link android.content.ComponentCallbacks2#onTrimMemory
    --onTrimMemory()}:</p>
    --
    --<ul>
    --<li>{@link android.content.ComponentCallbacks2#TRIM_MEMORY_RUNNING_MODERATE}
    --<p>Your app is running and not considered killable, but the device is running low on memory and the
    --system is actively killing processes in the LRU cache.</p>
    --</li>
    --
    --<li>{@link android.content.ComponentCallbacks2#TRIM_MEMORY_RUNNING_LOW}
    --<p>Your app is running and not considered killable, but the device is running much lower on
    --memory so you should release unused resources to improve system performance (which directly
    --impacts your app's performance).</p>
    --</li>
    --
    --<li>{@link android.content.ComponentCallbacks2#TRIM_MEMORY_RUNNING_CRITICAL}
    --<p>Your app is still running, but the system has already killed most of the processes in the
    --LRU cache, so you should release all non-critical resources now. If the system cannot reclaim
    --sufficient amounts of RAM, it will clear all of the LRU cache and begin killing processes that
    --the system prefers to keep alive, such as those hosting a running service.</p>
    --</li>
    --</ul>
    --
    --<p>Also, when your app process is currently cached, you may receive one of the following
    --levels from {@link android.content.ComponentCallbacks2#onTrimMemory onTrimMemory()}:</p>
    --<ul>
    --<li>{@link android.content.ComponentCallbacks2#TRIM_MEMORY_BACKGROUND}
    --<p>The system is running low on memory and your process is near the beginning of the LRU list.
    --Although your app process is not at a high risk of being killed, the system may already be killing
    --processes in the LRU cache. You should release resources that are easy to recover so your process
    --will remain in the list and resume quickly when the user returns to your app.</p>
    --</li>
    --
    --<li>{@link android.content.ComponentCallbacks2#TRIM_MEMORY_MODERATE}
    --<p>The system is running low on memory and your process is near the middle of the LRU list. If the
    --system becomes further constrained for memory, there's a chance your process will be killed.</p>
    --</li>
    --
    --<li>{@link android.content.ComponentCallbacks2#TRIM_MEMORY_COMPLETE}
    --<p>The system is running low on memory and your process is one of the first to be killed if the
    --system does not recover memory now. You should release everything that's not critical to
    --resuming your app state.</p>
    --
    --</li>
    --</ul>
    --
    --<p>Because the {@link android.content.ComponentCallbacks2#onTrimMemory onTrimMemory()} callback was
    --added in API level 14, you can use the {@link android.content.ComponentCallbacks#onLowMemory()}
    --callback as a fallback for older versions, which is roughly equivalent to the {@link
    --android.content.ComponentCallbacks2#TRIM_MEMORY_COMPLETE} event.</p>
    --
    --<p class="note"><strong>Note:</strong> When the system begins killing processes in the LRU cache,
    --although it primarily works bottom-up, it does give some consideration to which processes are
    --consuming more memory and will thus provide the system more memory gain if killed.
    --So the less memory you consume while in the LRU list overall, the better your chances are
    --to remain in the list and be able to quickly resume.</p>
    --
    --
    --
    --<h3 id="CheckHowMuchMemory">Check how much memory you should use</h3>
    --
    --<p>As mentioned earlier, each Android-powered device has a different amount of RAM available to the
    --system and thus provides a different heap limit for each app. You can call {@link
    --android.app.ActivityManager#getMemoryClass()} to get an estimate of your app's available heap in
    --megabytes. If your app tries to allocate more memory than is available here, it will receive an
    --{@link java.lang.OutOfMemoryError}.</p>
    --
    --<p>In very special situations, you can request a larger heap size by setting the <a
    --href="{@docRoot}guide/topics/manifest/application-element.html#largeHeap">{@code largeHeap}</a>
    --attribute to "true" in the manifest <a
    --href="{@docRoot}guide/topics/manifest/application-element.html">{@code <application>}</a>
    --tag. If you do so, you can call {@link
    --android.app.ActivityManager#getLargeMemoryClass()} to get an estimate of the large heap size.</p>
    --
    --<p>However, the ability to request a large heap is intended only for a small set of apps that can
    --justify the need to consume more RAM (such as a large photo editing app). <strong>Never request a
    --large heap simply because you've run out of memory</strong> and you need a quick fix&mdash;you
    --should use it only when you know exactly where all your memory is being allocated and why it must
    --be retained. Yet, even when you're confident your app can justify the large heap, you should avoid
    --requesting it to whatever extent possible. Using the extra memory will increasingly be to the
    --detriment of the overall user experience because garbage collection will take longer and system
    --performance may be slower when task switching or performing other common operations.</p>
    --
    --<p>Additionally, the large heap size is not the same on all devices and, when running on
    --devices that have limited RAM, the large heap size may be exactly the same as the regular heap
    --size. So even if you do request the large heap size, you should call {@link
    --android.app.ActivityManager#getMemoryClass()} to check the regular heap size and strive to always
    --stay below that limit.</p>
    --
    --
    --<h3 id="Bitmaps">Avoid wasting memory with bitmaps</h3>
    --
    --<p>When you load a bitmap, keep it in RAM only at the resolution you need for the current device's
    --screen, scaling it down if the original bitmap is a higher resolution. Keep in mind that an
    --increase in bitmap resolution results in a corresponding (increase<sup>2</sup>) in memory needed,
    --because both the X and Y dimensions increase.</p>
    --
    --<p class="note"><strong>Note:</strong> On Android 2.3.x (API level 10) and below, bitmap objects
    --always appear as the same size in your app heap regardless of the image resolution (the actual
    --pixel data is stored separately in native memory). This makes it more difficult to debug the bitmap
    --memory allocation because most heap analysis tools do not see the native allocation. However,
    --beginning in Android 3.0 (API level 11), the bitmap pixel data is allocated in your app's Dalvik
    --heap, improving garbage collection and debuggability. So if your app uses bitmaps and you're having
    --trouble discovering why your app is using some memory on an older device, switch to a device
    --running Android 3.0 or higher to debug it.</p>
    --
    --<p>For more tips about working with bitmaps, read <a
    --href="{@docRoot}training/displaying-bitmaps/manage-memory.html">Managing Bitmap Memory</a>.</p>
    --
    --
    --<h3 id="DataContainers">Use optimized data containers</h3>
    --
    --<p>Take advantage of optimized containers in the Android framework, such as {@link
    --android.util.SparseArray}, {@link android.util.SparseBooleanArray}, and {@link
    --android.support.v4.util.LongSparseArray}. The generic {@link java.util.HashMap}
    --implementation can be quite memory
    --inefficient because it needs a separate entry object for every mapping. Additionally, the {@link
    --android.util.SparseArray} classes are more efficient because they avoid the system's need
    --to <acronym title=
    --"Automatic conversion from primitive types to object classes (such as int to Integer)"
    -->autobox</acronym>
    --the key and sometimes value (which creates yet another object or two per entry). And don't be
    --afraid of dropping down to raw arrays when that makes sense.</p>
    --
    --
    --
    --<h3 id="Overhead">Be aware of memory overhead</h3>
    --
    --<p>Be knowledgeable about the cost and overhead of the language and libraries you are using, and
    --keep this information in mind when you design your app, from start to finish. Often, things on the
    --surface that look innocuous may in fact have a large amount of overhead. Examples include:</p>
    --<ul>
    --<li>Enums often require more than twice as much memory as static constants. You should strictly
    --avoid using enums on Android.</li>
    --
    --<li>Every class in Java (including anonymous inner classes) uses about 500 bytes of code.</li>
    --
    --<li>Every class instance has 12-16 bytes of RAM overhead.</li>
    --
    --<li>Putting a single entry into a {@link java.util.HashMap} requires the allocation of an
    --additional entry object that takes 32 bytes (see the previous section about <a
    --href="#DataContainers">optimized data containers</a>).</li>
    --</ul>
    --
    --<p>A few bytes here and there quickly add up—app designs that are class- or object-heavy will suffer
    --from this overhead. That can leave you in the difficult position of looking at a heap analysis and
    --realizing your problem is a lot of small objects using up your RAM.</p>
    --
    --
    --<h3 id="Abstractions">Be careful with code abstractions</h3>
    --
    --<p>Often, developers use abstractions simply as a "good programming practice," because abstractions
    --can improve code flexibility and maintenance. However, abstractions come at a significant cost:
    --generally they require a fair amount more code that needs to be executed, requiring more time and
    --more RAM for that code to be mapped into memory. So if your abstractions aren't supplying a
    --significant benefit, you should avoid them.</p>
    --
    --
    --<h3 id="NanoProto">Use nano protobufs for serialized data</h3>
    --
    --<p><a href="https://developers.google.com/protocol-buffers/docs/overview">Protocol
    --buffers</a> are a language-neutral, platform-neutral, extensible mechanism designed by Google for
    --serializing structured data&mdash;think XML, but smaller, faster, and simpler. If you decide to use
    --protobufs for your data, you should always use nano protobufs in your client-side code. Regular
    --protobufs generate extremely verbose code, which will cause many kinds of problems in your app:
    --increased RAM use, significant APK size increase, slower execution, and quickly hitting the DEX
    --symbol limit.</p>
    --
    --<p>For more information, see the "Nano version" section in the <a
    --href="https://android.googlesource.com/platform/external/protobuf/+/master/java/README.txt"
    --class="external-link">protobuf readme</a>.</p>
    --
    --
    --
    --<h3 id="DependencyInjection">Avoid dependency injection frameworks</h3>
    --
    --<p>Using a dependency injection framework such as <a
    --href="https://code.google.com/p/google-guice/" class="external-link">Guice</a> or
    --<a href="https://github.com/roboguice/roboguice" class="external-link">RoboGuice</a> may be
    --attractive because they can simplify the code you write and provide an adaptive environment
    --that's useful for testing and other configuration changes. However, these frameworks tend to perform
    --a lot of process initialization by scanning your code for annotations, which can require significant
    --amounts of your code to be mapped into RAM even though you don't need it. These mapped pages are
    --allocated into clean memory so Android can drop them, but that won't happen until the pages have
    --been left in memory for a long period of time.</p>
    --
    --
    --<h3 id="ExternalLibs">Be careful about using external libraries</h3>
    --
    --<p>External library code is often not written for mobile environments and can be inefficient when used
    --for work on a mobile client. At the very least, when you decide to use an external library, you
    --should assume you are taking on a significant porting and maintenance burden to optimize the
    --library for mobile. Plan for that work up-front and analyze the library in terms of code size and
    --RAM footprint before deciding to use it at all.</p>
    --
    --<p>Even libraries supposedly designed for use on Android are potentially dangerous because each
    --library may do things differently. For example, one library may use nano protobufs while another
    --uses micro protobufs. Now you have two different protobuf implementations in your app. This can and
    --will also happen with different implementations of logging, analytics, image loading frameworks,
    --caching, and all kinds of other things you don't expect. <a
    --href="{@docRoot}tools/help/proguard.html">ProGuard</a> won't save you here because these
    --will all be lower-level dependencies that are required by the features for which you want the
    --library. This becomes especially problematic when you use an {@link android.app.Activity}
    --subclass from a library (which
    --will tend to have wide swaths of dependencies), when libraries use reflection (which is common and
    --means you need to spend a lot of time manually tweaking ProGuard to get it to work), and so on.</p>
    --
    --<p>Also be careful not to fall into the trap of using a shared library for one or two features out of
    --dozens of other things it does; you don't want to pull in a large amount of code and overhead that
    --you don't even use. At the end of the day, if there isn't an existing implementation that is a
    --strong match for what you need to do, it may be best if you create your own implementation.</p>
    --
    --
    --<h3 id="OverallPerf">Optimize overall performance</h3>
    --
    --<p>A variety of information about optimizing your app's overall performance is available
    --in other documents listed in <a href="{@docRoot}training/best-performance.html">Best Practices
    --for Performance</a>. Many of these documents include optimizations tips for CPU performance, but
    --many of these tips also help optimize your app's memory use, such as by reducing the number of
    --layout objects required by your UI.</p>
    --
    --<p>You should also read about <a href="{@docRoot}tools/debugging/debugging-ui.html">optimizing
    --your UI</a> with the layout debugging tools and take advantage of
    --the optimization suggestions provided by the <a
    --href="{@docRoot}tools/debugging/improving-w-lint.html">lint tool</a>.</p>
    --
    --
    --<h3 id="Proguard">Use ProGuard to strip out any unneeded code</h3>
    --
    --<p>The <a href="{@docRoot}tools/help/proguard.html">ProGuard</a> tool shrinks,
    --optimizes, and obfuscates your code by removing unused code and renaming classes, fields, and
    --methods with semantically obscure names. Using ProGuard can make your code more compact, requiring
    --fewer RAM pages to be mapped.</p>
    --
    --
    --<h3 id="Zipalign">Use zipalign on your final APK</h3>
    --
    --<p>If you do any post-processing of an APK generated by a build system (including signing it
    --with your final production certificate), then you must run <a
    --href="{@docRoot}tools/help/zipalign.html">zipalign</a> on it to have it re-aligned.
    --Failing to do so can cause your app to require significantly more RAM, because things like
    --resources can no longer be mmapped from the APK.</p>
    --
    --<p class="note"><strong>Note:</strong> Google Play Store does not accept APK files that
    --are not zipaligned.</p>
    --
    --
    --<h3 id="AnalyzeRam">Analyze your RAM usage</h3>
    --
    --<p>Once you achieve a relatively stable build, begin analyzing how much RAM your app is using
    --throughout all stages of its lifecycle. For information about how to analyze your app, read <a
    --href="{@docRoot}tools/debugging/debugging-memory.html">Investigating Your RAM Usage</a>.</p>
    --
    --
    --
    --
    --<h3 id="MultipleProcesses">Use multiple processes</h3>
    --
    --<p>If it's appropriate for your app, an advanced technique that may help you manage your app's
    --memory is dividing components of your app into multiple processes. This technique must always be
    --used carefully and <strong>most apps should not run multiple processes</strong>, as it can easily
    --increase&mdash;rather than decrease&mdash;your RAM footprint if done incorrectly. It is primarily
    --useful to apps that may run significant work in the background as well as the foreground and can
    --manage those operations separately.</p>
    --
    --
    --<p>An example of when multiple processes may be appropriate is when building a music player that
    --plays music from a service for long period of time. If
    --the entire app runs in one process, then many of the allocations performed for its activity UI must
    --be kept around as long as it is playing music, even if the user is currently in another app and the
    --service is controlling the playback. An app like this may be split into two process: one for its
    --UI, and the other for the work that continues running in the background service.</p>
    --
    --<p>You can specify a separate process for each app component by declaring the <a href=
    --"{@docRoot}guide/topics/manifest/service-element.html#proc">{@code android:process}</a> attribute
    --for each component in the manifest file. For example, you can specify that your service should run
    --in a process separate from your app's main process by declaring a new process named "background"
    --(but you can name the process anything you like):</p>
    --
    --<pre>
    --&lt;service android:name=".PlaybackService"
    --         android:process=":background" />
    --</pre>
    --
    --<p>Your process name should begin with a colon (':') to ensure that the process remains private to
    --your app.</p>
    --
    --<p>Before you decide to create a new process, you need to understand the memory implications.
    --To illustrate the consequences of each process, consider that an empty process doing basically
    --nothing has an extra memory footprint of about 1.4MB, as shown by the memory information
    --dump below.</p>
    --
    --<pre class="no-pretty-print">
    --adb shell dumpsys meminfo com.example.android.apis:empty
    --
    --** MEMINFO in pid 10172 [com.example.android.apis:empty] **
    --                Pss     Pss  Shared Private  Shared Private    Heap    Heap    Heap
    --              Total   Clean   Dirty   Dirty   Clean   Clean    Size   Alloc    Free
    --             ------  ------  ------  ------  ------  ------  ------  ------  ------
    --  Native Heap     0       0       0       0       0       0    1864    1800      63
    --  Dalvik Heap   764       0    5228     316       0       0    5584    5499      85
    -- Dalvik Other   619       0    3784     448       0       0
    --        Stack    28       0       8      28       0       0
    --    Other dev     4       0      12       0       0       4
    --     .so mmap   287       0    2840     212     972       0
    --    .apk mmap    54       0       0       0     136       0
    --    .dex mmap   250     148       0       0    3704     148
    --   Other mmap     8       0       8       8      20       0
    --      Unknown   403       0     600     380       0       0
    --        TOTAL  2417     148   12480    1392    4832     152    7448    7299     148
    --</pre>
    --
    --<p class="note"><strong>Note:</strong> More information about how to read this output is provided
    --in <a href="{@docRoot}tools/debugging/debugging-memory.html#ViewingAllocations">Investigating
    --Your RAM Usage</a>. The key data here is the <em>Private Dirty</em> and <em>Private
    --Clean</em> memory, which shows that this process is using almost 1.4MB of non-pageable RAM
    --(distributed across the Dalvik heap, native allocations, book-keeping, and library-loading),
    --and another 150K of RAM for code that has been mapped in to execute.</p>
    --
    --<p>This memory footprint for an empty process is fairly significant and it can quickly
    --grow as you start doing work in that process. For
    --example, here is the memory use of a process that is created only to show an activity with some
    --text in it:</p>
    --
    --<pre class="no-pretty-print">
    --** MEMINFO in pid 10226 [com.example.android.helloactivity] **
    --                Pss     Pss  Shared Private  Shared Private    Heap    Heap    Heap
    --              Total   Clean   Dirty   Dirty   Clean   Clean    Size   Alloc    Free
    --             ------  ------  ------  ------  ------  ------  ------  ------  ------
    --  Native Heap     0       0       0       0       0       0    3000    2951      48
    --  Dalvik Heap  1074       0    4928     776       0       0    5744    5658      86
    -- Dalvik Other   802       0    3612     664       0       0
    --        Stack    28       0       8      28       0       0
    --       Ashmem     6       0      16       0       0       0
    --    Other dev   108       0      24     104       0       4
    --     .so mmap  2166       0    2824    1828    3756       0
    --    .apk mmap    48       0       0       0     632       0
    --    .ttf mmap     3       0       0       0      24       0
    --    .dex mmap   292       4       0       0    5672       4
    --   Other mmap    10       0       8       8      68       0
    --      Unknown   632       0     412     624       0       0
    --        TOTAL  5169       4   11832    4032   10152       8    8744    8609     134
    --</pre>
    --
    --<p>The process has now almost tripled in size, to 4MB, simply by showing some text in the UI. This
    --leads to an important conclusion: If you are going to split your app into multiple processes, only
    --one process should be responsible for UI. Other processes should avoid any UI, as this will quickly
    --increase the RAM required by the process (especially once you start loading bitmap assets and other
    --resources). It may then be hard or impossible to reduce the memory usage once the UI is drawn.</p>
    --
    --<p>Additionally, when running more than one process, it's more important than ever that you keep your
    --code as lean as possible, because any unnecessary RAM overhead for common implementations are now
    --replicated in each process. For example, if you are using enums (though <a
    --href="#Overhead">you should not use enums</a>), all of
    --the RAM needed to create and initialize those constants is duplicated in each process, and any
    --abstractions you have with adapters and temporaries or other overhead will likewise be replicated.</p>
    --
    --<p>Another concern with multiple processes is the dependencies that exist between them. For example,
    --if your app has a content provider that you have running in the default process which also hosts
    --your UI, then code in a background process that uses that content provider will also require that
    --your UI process remain in RAM. If your goal is to have a background process that can run
    --independently of a heavy-weight UI process, it can't have dependencies on content providers or
    --services that execute in the UI process.</p>
    --
    --
    --
    --
    --
    --
    --
    --
    --
    --
    --<!-- THE FOLLOWING IS OVERWHELMING AND NOT NECESSARY FOR MOST APPS, LEAVING OUT FOR NOW
    --
    --
    --<p>You can examine the dependencies between your processes with the command:</p>
    --
    --<pre class="no-pretty-print">
    --adb shell dumpsys activity
    --</pre>
    --
    --<p>This dumps various information about the Activity Manager's state, ending with a list of all
    --processes in their memory management order, including the reason each process is at its given
    --level. For example, below is a dump with the Music app in the foreground.</p>
    --
    --<pre class="no-pretty-print">
    --ACTIVITY MANAGER RUNNING PROCESSES (dumpsys activity processes)
    --  Process LRU list (sorted by oom_adj):
    --    PERS # 4: adj=sys  /F  trm= 0 20674:system/1000 (fixed)
    --    PERS #39: adj=pers /F  trm= 0 20964:com.android.nfc/1027 (fixed)
    --    PERS # 2: adj=pers /F  trm= 0 20959:com.android.phone/1001 (fixed)
    --    PERS # 1: adj=pers /F  trm= 0 20779:com.android.systemui/u0a10057 (fixed)
    --    Proc #11: adj=fore /FA trm= 0 8663:com.google.android.music:ui/u0a10043 (top-activity)
    --    Proc #10: adj=fore /F  trm= 0 30881:com.google.android.music:main/u0a10043 (provider)
    --        com.google.android.music/.store.MusicContentProvider<=Proc{8663:com.google.android.music:ui/u0a10043}
    --    Proc # 6: adj=fore /F  trm= 0 21014:com.google.process.gapps/u0a10023 (provider)
    --        com.google.android.gsf/.settings.GoogleSettingsProvider<=Proc{20935:com.google.process.location/u0a10023}
    --    Proc #38: adj=vis  /F  trm= 0 21028:com.android.nfc:handover/1027 (service)
    --        com.android.nfc/.handover.HandoverService<=Proc{20964:com.android.nfc/1027}
    --    Proc # 7: adj=vis  /B  trm= 0 20935:com.google.process.location/u0a10023 (service)
    --        com.google.android.location/.GeocodeService<=Proc{20674:system/1000}
    --    Proc # 3: adj=vis  /F  trm= 0 21225:com.android.bluetooth/1002 (service)
    --        com.android.bluetooth/.hfp.HeadsetService<=Proc{20674:system/1000}
    --    Proc # 0: adj=vis  /F  trm= 0 20908:com.google.android.inputmethod.latin/u0a10035 (service)
    --        com.google.android.inputmethod.latin/com.android.inputmethod.latin.LatinIME<=Proc{20674:system/1000}
    --    Proc #34: adj=svc  /B  trm= 0 16765:com.google.android.apps.currents/u0a10012 (started-services)
    --    Proc #14: adj=svc  /B  trm= 0 21148:com.google.android.gms/u0a10023 (started-services)
    --    Proc #12: adj=home /B  trm= 0 20989:com.android.launcher/u0a10036 (home)
    --    Proc #37: adj=svcb /B  trm= 0 15194:com.google.android.apps.googlevoice/u0a10089 (started-services)
    --    Proc #17: adj=svcb /B  trm= 0 24537:android.process.media/u0a10016 (started-services)
    --    Proc #35: adj=bak  /B  trm= 0 16087:com.android.defcontainer/u0a10013 (service)
    --        com.android.defcontainer/.DefaultContainerService<=Proc{16050:com.android.settings/1000}
    --    Proc #16: adj=bak  /B  trm= 0 7334:com.google.android.gm/u0a10022 (bg-act)
    --    Proc #15: adj=bak  /B  trm= 0 22499:com.google.android.googlequicksearchbox/u0a10060 (bg-act)
    --    Proc # 9: adj=bak  /B  trm= 0 20856:com.google.android.gsf.login/u0a10023 (bg-empty)
    --    Proc #26: adj=bak+1/B  trm= 0 9923:com.android.mms/u0a10042 (bg-act)
    --    Proc #23: adj=bak+1/B  trm= 0 16721:com.android.chrome/u0a10010 (bg-act)
    --    Proc #22: adj=bak+1/B  trm= 0 17596:com.android.chrome:sandboxed_process0/u0a10010i33 (service)
    --        com.android.chrome/org.chromium.content.app.SandboxedProcessService0<=Proc{16721:com.android.chrome/u0a10010}
    --    Proc #19: adj=bak+1/B  trm= 0 17442:com.google.android.youtube/u0a10067 (bg-services)
    --    Proc #18: adj=bak+2/B  trm= 0 16740:com.google.android.apps.plus/u0a10052 (bg-empty)
    --    Proc #13: adj=bak+2/B  trm= 0 7707:com.android.musicfx/u0a10044 (bg-empty)
    --    Proc #36: adj=bak+3/B  trm= 0 16050:com.android.settings/1000 (bg-act)
    --    Proc #33: adj=bak+3/B  trm= 0 16863:com.android.dialer/u0a10015 (bg-act)
    --</pre>
    --
    --
    --<p class="note"><strong>Note:</strong> The exact details of what is shown here will vary across
    --platform versions as process management policies are tweaked and improved.</p>
    --
    --
    --<p>Details on the highlighted sections are:</p>
    --
    --<ol>
    --<li>Foreground app: This is the current app running in the foreground -- it is in the "fore" memory
    --class because it is the top activity on the activity stack.</li>
    --
    --<li>Persistent processes: These are processes that are part of the core system that must always be
    --running.</li>
    --
    --<li>Dependent process: This shows how the Music app is using two processes. Its UI process has a
    --dependency on the "main" process (through a content provider). So while the UI process is in use,
    --the main process must also be kept around. This means the app's memory footprint is actually the
    --sum of both processes. You will have this kind of connection on a content provider any time you
    --have active calls into it or have unclosed cursors or file streams that came from it.</li>
    --
    --<li>Visible processes: These are processes that count in some way as "visible" to the user. This
    --generally means that it is either something the user can literally see (such as a process hosting a
    --paused but visible activity that is behind a non-full-screen dialog) or is something the user might
    --notice if the process disappeared (such as a foreground service playing music). You should be
    --certain that any process you have running at the "visible" level is indeed critical to the user,
    --because they are very expensive to the overall RAM load.</li>
    --
    --<li>Service processes: These are processes running long-term jobs in a service. This level of the
    --list is the start of less-critical processes, which the system has some freedom to kill if RAM is
    --needed elsewhere. These services are still quite expensive because they can be killed only
    --temporarily and the system tries to keep them running whenever possible.</li>
    --
    --<li>Home process: A special slot for the process that hosts the current Home activity, to try to
    --prevent it from being killed as much as possible. Killing this process is much more damaging to the
    --user experience than killing other cached processes, because so much user interaction goes through
    --home.</li>
    --
    --<li>Secondary service processes: These are services that have been running for a relatively long time
    --and so should be killed more aggressively when RAM is needed elsewhere.</li>
    --
    --<li>Cached processes: These are cached processes held in the LRU cache, which allow for fast app
    --switching and component launching. These processes are not required and the system will kill them
    --as needed to reclaim memory. You will often see a process hosting a running service here—this is
    --part of a platform policy of allowing very long-running services to drop down into the LRU list and
    --eventually be killed. If the service should continue running (as defined by the {@link
    --android.app.Service#onStartCommand onStartCommand()} return value, such as {@link
    --android.app.Service#START_STICKY}), the the system eventually restarts it. This avoids issues with
    --such services having memory leaks that over time reduce the number of regular cached processes that
    --can be kept.</li>
    --
    --</ol>
    --
    --<p>This numbered list of processes is essentially the LRU list of processes that the framework
    --provides to the kernel to help it determine which processes it should kill as it needs more RAM.
    --The kernel's out of memory killer will generally begin from the bottom of this list, killing the
    --last process and working its way up. It may not do it in exactly this order, as it can also take
    --into consideration other factors such as the relative RAM footprint of processes to some degree.</p>
    --
    --<p>There are many other options you can use with the activity command to analyze further details of
    --your app's state&mdash;use <code>adb shell dumpsys activity -h</code> for help on its use.</p>
    --
    ---->
    -diff --git a/docs/html/training/articles/perf-anr.jd b/docs/html/training/articles/perf-anr.jd
    -index 8848354..58db3e2 100644
    ---- a/docs/html/training/articles/perf-anr.jd
    -+++ b/docs/html/training/articles/perf-anr.jd
    -@@ -14,6 +14,14 @@ page.article=true
    -   <li><a href="#Reinforcing">Reinforcing Responsiveness</a></li>
    - </ol>
    - 
    -+<h2>You should also read</h2>
    -+<ul>
    -+  <li><a href="/topic/performance/background-optimization.html">Background Optimizations</a>
    -+  <li><a href="/topic/performance/scheduling.html">Intelligent Job-Scheduling</a>
    -+  <li><a href="/training/monitoring-device-state/manifest-receivers.html">Manipulating Broadcast Receivers On Demand</a>
    -+  <li><a href="/guide/components/intents-filters.html">Intents and Intent Filters</a>
    -+</ul>
    -+
    - </div>
    - </div>
    - 
    -@@ -146,7 +154,7 @@ as the UI thread by default.</p>
    - 
    - <p>If you implement {@link java.lang.Thread} or {@link android.os.HandlerThread},
    - be sure that your UI thread does not block while waiting for the worker thread to
    --complete&mdash;do not call {@link java.lang.Object#wait Thread.wait()} or
    -+complete&mdash;do not call {@link java.lang.Thread#wait Thread.wait()} or
    - {@link java.lang.Thread#sleep Thread.sleep()}. Instead of blocking while waiting for a worker
    - thread to complete, your main thread should provide a {@link
    - android.os.Handler} for the other threads to post back to upon completion.
    -@@ -165,6 +173,16 @@ application should start an {@link android.app.IntentService} if a
    - potentially long running action needs to be taken in response to an intent
    - broadcast.</p>
    - 
    -+<p>
    -+  Another common issue with {@link android.content.BroadcastReceiver} objects
    -+  occurs when they execute too frequently. Frequent background execution can
    -+  reduce the amount of memory available to other apps.
    -+  For more information about how to enable and disable
    -+  {@link android.content.BroadcastReceiver} objects efficiently, see
    -+  <a href="/training/monitoring-device-state/manifest-receivers.html">Manipulating
    -+    Broadcast Receivers on Demand</a>.
    -+</p>
    -+
    - <p class="note"><strong>Tip:</strong>
    - You can use {@link android.os.StrictMode} to help find potentially
    - long running operations such as network or database operations that
    -diff --git a/docs/html/training/articles/perf-tips.jd b/docs/html/training/articles/perf-tips.jd
    -index 82de69a..30cab14 100644
    ---- a/docs/html/training/articles/perf-tips.jd
    -+++ b/docs/html/training/articles/perf-tips.jd
    -@@ -28,7 +28,8 @@ when combined, but it's unlikely that these changes will result in dramatic
    - performance effects. Choosing the right algorithms and data structures should always be your
    - priority, but is outside the scope of this document. You should use the tips in this document
    - as general coding practices that you can incorporate into your habits for general code
    --efficiency.</p>
    -+efficiency.
    -+</p>
    - 
    - <p>There are two basic rules for writing efficient code:</p>
    - <ul>
    -@@ -49,8 +50,7 @@ code for a device with a JIT is not always the best code for a device
    - without.</p>
    - 
    - <p>To ensure your app performs well across a wide variety of devices, ensure
    --your code is efficient at all levels and agressively optimize your performance.</p>
    --
    -+your code is efficient at all levels and aggressively optimize your performance.</p>
    - 
    - <h2 id="ObjectCreation">Avoid Creating Unnecessary Objects</h2>
    - 
    -diff --git a/docs/html/training/articles/security-tips.jd b/docs/html/training/articles/security-tips.jd
    -index abf6711..9796d9a 100644
    ---- a/docs/html/training/articles/security-tips.jd
    -+++ b/docs/html/training/articles/security-tips.jd
    -@@ -6,34 +6,32 @@ page.article=true
    - <div id="tb">
    - <h2>In this document</h2>
    - <ol class="nolist">
    --  <li><a href="#StoringData">Storing Data</a></li>
    --  <li><a href="#Permissions">Using Permissions</a></li>
    --  <li><a href="#Networking">Using Networking</a></li>
    --  <li><a href="#InputValidation">Performing Input Validation</a></li>
    --  <li><a href="#UserData">Handling User Data</a></li>
    -+  <li><a href="#StoringData">Storing data</a></li>
    -+  <li><a href="#Permissions">Using permissions</a></li>
    -+  <li><a href="#Networking">Using networking</a></li>
    -+  <li><a href="#InputValidation">Performing input validation</a></li>
    -+  <li><a href="#UserData">Handling user data</a></li>
    -   <li><a href="#WebView">Using WebView</a></li>
    --  <li><a href="#Crypto">Using Cryptography</a></li>
    --  <li><a href="#IPC">Using Interprocess Communication</a></li>
    --  <li><a href="#DynamicCode">Dynamically Loading Code</a></li>
    --  <li><a href="#Dalvik">Security in a Virtual Machine</a></li>
    --  <li><a href="#Native">Security in Native Code</a></li>
    -+  <li><a href="#Crypto">Using cryptography</a></li>
    -+  <li><a href="#IPC">Using interprocess communication</a></li>
    -+  <li><a href="#DynamicCode">Dynamically loading code</a></li>
    -+  <li><a href="#Dalvik">Security in a virtual machine</a></li>
    -+  <li><a href="#Native">Security in native code</a></li>
    - </ol>
    - <h2>See also</h2>
    - <ul>
    - <li><a href="http://source.android.com/tech/security/index.html">Android
    --Security Overview</a></li>
    -+  Security Overview</a></li>
    - <li><a href="{@docRoot}guide/topics/security/permissions.html">Permissions</a></li>
    - </ul>
    - </div></div>
    - 
    - 
    --<p>Android has security features built
    --into the operating system that significantly reduce the frequency and impact of
    --application security issues. The system is designed so you can typically build your apps with
    --default system and file permissions and avoid difficult decisions about security.</p>
    -+<p>Android has built-in security features that significantly reduce the frequency and impact of
    -+application security issues. The system is designed so that you can typically build your apps with
    -+the default system and file permissions and avoid difficult decisions about security.</p>
    - 
    --<p>Some of the core security features that help you build secure apps
    --include:
    -+<p>The following core security features help you build secure apps:
    - <ul>
    - <li>The Android Application Sandbox, which isolates your app data and code execution
    - from other apps.</li>
    -@@ -43,47 +41,54 @@ security functionality such as cryptography, permissions, and secure
    - <li>Technologies like ASLR, NX, ProPolice, safe_iop, OpenBSD dlmalloc, OpenBSD
    - calloc, and Linux mmap_min_addr to mitigate risks associated with common memory
    - management errors.</li>
    --<li>An encrypted filesystem that can be enabled to protect data on lost or
    -+<li>An encrypted file system that can be enabled to protect data on lost or
    - stolen devices.</li>
    - <li>User-granted permissions to restrict access to system features and user data.</li>
    - <li>Application-defined permissions to control application data on a per-app basis.</li>
    - </ul>
    - 
    --<p>Nevertheless, it is important that you be familiar with the Android
    -+<p>It is important that you be familiar with the Android
    - security best practices in this document. Following these practices as general coding habits
    --will reduce the likelihood of inadvertently introducing security issues that
    -+ reduces the likelihood of inadvertently introducing security issues that
    - adversely affect your users.</p>
    - 
    - 
    - 
    --<h2 id="StoringData">Storing Data</h2>
    -+<h2 id="StoringData">Storing data</h2>
    - 
    - <p>The most common security concern for an application on Android is whether the data
    - that you save on the device is accessible to other apps. There are three fundamental
    - ways to save data on the device:</p>
    - 
    -+<ul>
    -+<li>Internal storage.</li>
    -+<li>External storage.</li>
    -+<li>Content providers.</li>
    -+</ul>
    -+
    -+The following paragraphs describe the security issues associated with each approach.
    -+
    - <h3 id="InternalStorage">Using internal storage</h3>
    - 
    - <p>By default, files that you create on <a
    - href="{@docRoot}guide/topics/data/data-storage.html#filesInternal">internal
    --storage</a> are accessible only to your app. This
    --protection is implemented by Android and is sufficient for most
    --applications.</p>
    -+storage</a> are accessible only to your app.
    -+ Android implements this protection, and it's sufficient for most applications.</p>
    - 
    --<p>You should generally avoid using the {@link android.content.Context#MODE_WORLD_WRITEABLE} or
    -+<p>Generally, avoid the {@link android.content.Context#MODE_WORLD_WRITEABLE} or
    - {@link android.content.Context#MODE_WORLD_READABLE} modes for
    - <acronym title="Interprocess Communication">IPC</acronym> files because they do not provide
    - the ability to limit data access to particular applications, nor do they
    --provide any control on data format. If you want to share your data with other
    --app processes, you might instead consider using a
    -+provide any control of data format. If you want to share your data with other
    -+app processes, instead consider using a
    - <a href="{@docRoot}guide/topics/providers/content-providers.html">content provider</a>, which
    - offers read and write permissions to other apps and can make
    - dynamic permission grants on a case-by-case basis.</p>
    - 
    --<p>To provide additional protection for sensitive data, you might
    --choose to encrypt local files using a key that is not directly accessible to the
    --application. For example, a key can be placed in a {@link java.security.KeyStore}
    --and protected with a user password that is not stored on the device.  While this
    -+<p>To provide additional protection for sensitive data, you can
    -+ encrypt local files using a key that is not directly accessible to the
    -+application. For example, you can place a key in a {@link java.security.KeyStore}
    -+and protect it with a user password that is not stored on the device.  While this
    - does not protect data from a root compromise that can monitor the user
    - inputting the password,  it can provide protection for a lost device without <a
    - href="http://source.android.com/tech/encryption/index.html">file system
    -@@ -94,14 +99,14 @@ encryption</a>.</p>
    - 
    - <p>Files created on <a
    - href="{@docRoot}guide/topics/data/data-storage.html#filesExternal">external
    --storage</a>, such as SD Cards, are globally readable and writable.  Because
    -+storage</a>, such as SD cards, are globally readable and writable. Because
    - external storage can be removed by the user and also modified by any
    --application,  you should not store sensitive information using
    -+application, don't store sensitive information using
    - external storage.</p>
    - 
    --<p>As with data from any untrusted source, you should <a href="#InputValidation">perform input
    --validation</a> when handling data from external storage.
    --We strongly recommend that you not store executables or
    -+<p>You should <a href="#InputValidation">Perform input validation</a> when handling
    -+data from external storage as you would with data from any untrusted source.
    -+You should not store executables or
    - class files on external storage prior to dynamic loading.  If your app
    - does retrieve executable files from external storage, the files should be signed and
    - cryptographically verified prior to dynamic loading.</p>
    -@@ -117,22 +122,22 @@ applications with access to your {@link android.content.ContentProvider}, mark t
    - href="{@docRoot}guide/topics/manifest/provider-element.html#exported">
    - android:exported=false</a></code> in the application manifest. Otherwise, set the <code><a
    - href="{@docRoot}guide/topics/manifest/provider-element.html#exported">android:exported</a></code>
    --attribute {@code "true"} to allow other apps to access the stored data.
    -+attribute to {@code true} to allow other apps to access the stored data.
    - </p>
    - 
    - <p>When creating a {@link android.content.ContentProvider}
    --that will be exported for use by other applications, you can specify a single
    -+that is exported for use by other applications, you can specify a single
    - <a href="{@docRoot}guide/topics/manifest/provider-element.html#prmsn">permission
    --</a> for reading and writing, or distinct permissions for reading and writing
    --within the manifest. We recommend that you limit your permissions to those
    -+</a> for reading and writing, or you can specify distinct permissions for reading and writing.
    -+You should limit your permissions to those
    - required to accomplish the task at hand. Keep in mind that it’s usually
    - easier to add permissions later to expose new functionality than it is to take
    --them away and break existing users.</p>
    -+them away and impact existing users.</p>
    - 
    - <p>If you are using a content provider
    - for sharing data between only your own apps, it is preferable to use the
    - <a href="{@docRoot}guide/topics/manifest/permission-element.html#plevel">{@code
    --android:protectionLevel}</a> attribute set to {@code "signature"} protection.
    -+android:protectionLevel}</a> attribute set to {@code signature} protection.
    - Signature permissions do not require user confirmation,
    - so they provide a better user experience and more controlled access to the
    - content provider data when the apps accessing the data are
    -@@ -148,7 +153,7 @@ android.content.Intent#FLAG_GRANT_WRITE_URI_PERMISSION} flags in the
    - that activates the component.  The scope of these permissions can be further
    - limited by the <code><a
    - href="{@docRoot}guide/topics/manifest/grant-uri-permission-element.html">
    --&lt;grant-uri-permission element&gt;</a></code>.</p>
    -+&lt;grant-uri-permission&gt;</a></code> element.</p>
    - 
    - <p>When accessing a content provider, use parameterized query methods such as
    - {@link android.content.ContentProvider#query(Uri,String[],String,String[],String) query()},
    -@@ -158,11 +163,11 @@ potential SQL injection from untrusted sources. Note that using parameterized me
    - sufficient if the <code>selection</code> argument is built by concatenating user data
    - prior to submitting it to the method.</p>
    - 
    --<p>Do not have a false sense of security about the write permission.  Consider
    --that the write permission allows SQL statements which make it possible for some
    -+<p>Don't have a false sense of security about the write permission.
    -+ The write permission allows SQL statements that make it possible for some
    - data to be confirmed using creative <code>WHERE</code> clauses and parsing the
    --results. For example, an attacker might probe for presence of a specific phone
    --number in a call-log by modifying a row only if that phone number already
    -+results. For example, an attacker might probe for the presence of a specific phone
    -+number in a call log by modifying a row only if that phone number already
    - exists. If the content provider data has predictable structure, the write
    - permission may be equivalent to providing both reading and writing.</p>
    - 
    -@@ -172,7 +177,7 @@ permission may be equivalent to providing both reading and writing.</p>
    - 
    - 
    - 
    --<h2 id="Permissions">Using Permissions</h2>
    -+<h2 id="Permissions">Using permissions</h2>
    - 
    - <p>Because Android sandboxes applications from each other, applications must explicitly
    - share resources and data. They do this by declaring the permissions they need for additional
    -@@ -180,25 +185,25 @@ capabilities not provided by the basic sandbox, including access to device featu
    - the camera.</p>
    - 
    - 
    --<h3 id="RequestingPermissions">Requesting Permissions</h3>
    -+<h3 id="RequestingPermissions">Requesting permissions</h3>
    - 
    --<p>We recommend minimizing the number of permissions that your app requests.
    --Not having access to sensitive permissions reduces the risk of
    --inadvertently misusing those permissions, can improve user adoption, and makes
    -+<p>You should minimize the number of permissions that your app requests.
    -+Restricting access to sensitive permissions reduces the risk of
    -+inadvertently misusing those permissions, improves user adoption, and makes
    - your app less vulnerable for attackers. Generally,
    --if a permission is not required for your app to function, do not request it.</p>
    -+if a permission is not required for your app to function, don't request it.</p>
    - 
    - <p>If it's possible to design your application in a way that does not require
    - any permissions, that is preferable.  For example, rather than requesting access
    - to device information to create a unique identifier, create a <a
    - href="{@docRoot}reference/java/util/UUID.html">GUID</a> for your application
    --(see the section about <a href="#UserData">Handling User Data</a>). Or, rather than
    -+(see the section about <a href="#UserData">Handling user data</a>). Or, rather than
    - using external storage (which requires permission), store data
    - on the internal storage.</p>
    - 
    - <p>In addition to requesting permissions, your application can use the <a
    --href="{@docRoot}guide/topics/manifest/permission-element.html">{@code <permissions>}</a>
    --to protect IPC that is security sensitive and will be exposed to other
    -+href="{@docRoot}guide/topics/manifest/permission-element.html">{@code &lt;permission&gt;}</a>
    -+ element to protect IPC that is security sensitive and is exposed to other
    - applications, such as a {@link android.content.ContentProvider}.
    - In general, we recommend using access controls
    - other than user confirmed permissions where possible because permissions can
    -@@ -211,13 +216,14 @@ provided by a single developer.</p>
    - data over IPC that is available only because your app has permission to access
    - that data. The clients of your app's IPC interface may not have that same
    - data-access permission. More details on the frequency and potential effects
    --of this issue appear in <a class="external-link"
    --href="https://www.usenix.org/legacy/event/sec11/tech/full_papers/Felt.pdf"> this
    --research paper</a>, published at USENIX.
    -+of this issue appear in the research paper <a
    -+href="https://www.usenix.org/legacy/event/sec11/tech/full_papers/Felt.pdf" class="external-link">
    -+Permission Re-Delegation: Attacks and Defenses
    -+</a>, published at USENIX.
    - 
    - 
    - 
    --<h3 id="CreatingPermissions">Creating Permissions</h3>
    -+<h3 id="CreatingPermissions">Creating permissions</h3>
    - 
    - <p>Generally, you should strive to define as few permissions as possible while
    - satisfying your security requirements.  Creating a new permission is relatively
    -@@ -228,18 +234,18 @@ perform access checks using existing permissions.</p>
    - 
    - <p>If you must create a new permission, consider whether you can accomplish
    - your task with a <a
    --href="{@docRoot}guide/topics/manifest/permission-element.html#plevel">"signature"
    -+href="{@docRoot}guide/topics/manifest/permission-element.html#plevel">signature
    - protection level</a>.  Signature permissions are transparent
    --to the user and only allow access by applications signed by the same developer
    --as application performing the permission check.</p>
    -+to the user and allow access only by applications signed by the same developer
    -+as the application performing the permission check.</p>
    - 
    - <p>If you create a permission with the <a
    --href="{@docRoot}guide/topics/manifest/permission-element.html#plevel">"dangerous"
    -+href="{@docRoot}guide/topics/manifest/permission-element.html#plevel">dangerous
    - protection level</a>, there are a number of complexities
    - that you need to consider:
    - <ul>
    - <li>The permission must have a string that concisely expresses to a user the
    --security decision they will be required to make.</li>
    -+security decision they are required to make.</li>
    - <li>The permission string must be localized to many different languages.</li>
    - <li>Users may choose not to install an application because a permission is
    - confusing or perceived as risky.</li>
    -@@ -247,28 +253,28 @@ confusing or perceived as risky.</li>
    - has not been installed.</li>
    - </ul>
    - 
    --<p>Each of these poses a significant non-technical challenge for you as the developer
    -+<p>Each of these poses a significant nontechnical challenge for you as the developer
    - while also confusing your users,
    --which is why we discourage the use of the "dangerous" permission level.</p>
    -+which is why we discourages the use of the <em>dangerous</em> permission level.</p>
    - 
    - 
    - 
    - 
    - 
    --<h2 id="Networking">Using Networking</h2>
    -+<h2 id="Networking">Using networking</h2>
    - 
    --<p>Network transactions are inherently risky for security, because it involves transmitting
    -+<p>Network transactions are inherently risky for security, because they involve transmitting
    - data that is potentially private to the user. People are increasingly aware of the privacy
    - concerns of a mobile device, especially when the device performs network transactions,
    - so it's very important that your app implement all best practices toward keeping the user's
    - data secure at all times.</p>
    - 
    --<h3 id="IPNetworking">Using IP Networking</h3>
    -+<h3 id="IPNetworking">Using IP networking</h3>
    - 
    - <p>Networking on Android is not significantly different from other Linux
    - environments.  The key consideration is making sure that appropriate protocols
    - are used for sensitive data, such as {@link javax.net.ssl.HttpsURLConnection} for
    --secure web traffic.   We prefer use of HTTPS over HTTP anywhere that HTTPS is
    -+secure web traffic. You should use HTTPS over HTTP anywhere that HTTPS is
    - supported on the server, because mobile devices frequently connect on networks
    - that are not secured, such as public Wi-Fi hotspots.</p>
    - 
    -@@ -278,32 +284,32 @@ class.  Given the frequency with which Android devices connect to unsecured
    - wireless networks using Wi-Fi, the use of secure networking is strongly
    - encouraged for all applications that communicate over the network.</p>
    - 
    --<p>We have seen some applications use <a
    --href="http://en.wikipedia.org/wiki/Localhost">localhost</a> network ports for
    --handling sensitive IPC.  We discourage this approach since these interfaces are
    --accessible by other applications on the device.  Instead, you should use an Android IPC
    --mechanism where authentication is possible such as with a {@link android.app.Service}.  (Even
    --worse than using loopback is to bind to INADDR_ANY since then your application
    --may receive requests from anywhere.)</p>
    -+<p>Some applications use <a
    -+href="http://en.wikipedia.org/wiki/Localhost" class="external-link">localhost</a> network ports for
    -+handling sensitive IPC.  You should not use this approach because these interfaces are
    -+accessible by other applications on the device. Instead, use an Android IPC
    -+mechanism where authentication is possible, such as with a {@link android.app.Service}.
    -+Binding to INADDR_ANY is worse than using loopback because then your application
    -+may receive requests from anywhere.</p>
    - 
    --<p>Also, one common issue that warrants repeating is to make sure that you do
    --not trust data downloaded from HTTP or other insecure protocols.  This includes
    -+<p>Make sure that you don't
    -+ trust data downloaded from HTTP or other insecure protocols.  This includes
    - validation of input in {@link android.webkit.WebView} and
    - any responses to intents issued against HTTP.</p>
    - 
    - 
    --<h3>Using Telephony Networking</h3>
    -+<h3>Using telephony networking</h3>
    - 
    - <p>The <acronym title="Short Message Service">SMS</acronym> protocol was primarily designed for
    - user-to-user communication and is not well-suited for apps that want to transfer data.
    --Due to the limitations of SMS, we strongly recommend the use of <a
    -+Due to the limitations of SMS, you should use <a
    - href="{@docRoot}google/gcm/index.html">Google Cloud Messaging</a> (GCM)
    - and IP networking for sending data messages from a web server to your app on a user device.</p>
    - 
    - <p>Beware that SMS is neither encrypted nor strongly
    --authenticated on either the network or the device.  In particular, any SMS receiver
    --should expect that a malicious user may have sent the SMS to your application&mdash;Do
    --not rely on unauthenticated SMS data to perform sensitive commands.
    -+authenticated on either the network or the device. In particular, any SMS receiver
    -+should expect that a malicious user may have sent the SMS to your application. Don't
    -+ rely on unauthenticated SMS data to perform sensitive commands.
    - Also, you should be aware that SMS may be subject to spoofing and/or
    - interception on the network.  On the Android-powered device itself, SMS
    - messages are transmitted as broadcast intents, so they may be read or captured
    -@@ -314,32 +320,32 @@ permission.</p>
    - 
    - 
    - 
    --<h2 id="InputValidation">Performing Input Validation</h2>
    -+<h2 id="InputValidation">Performing input validation</h2>
    - 
    - <p>Insufficient input validation is one of the most common security problems
    --affecting applications, regardless of what platform they run on. Android does
    --have platform-level countermeasures that reduce the exposure of applications to
    --input validation issues and you should use those features where possible. Also
    --note that selection of type-safe languages tends to reduce the likelihood of
    -+affecting applications, regardless of what platform they run on. Android
    -+has platform-level countermeasures that reduce the exposure of applications to
    -+input validation issues, and you should use those features where possible. Also
    -+note that the selection of type-safe languages tends to reduce the likelihood of
    - input validation issues.</p>
    - 
    --<p>If you are using native code, then any data read from files, received over
    -+<p>If you are using native code, any data read from files, received over
    - the network, or received from an IPC has the potential to introduce a security
    - issue.  The most common problems are <a
    --href="http://en.wikipedia.org/wiki/Buffer_overflow">buffer overflows</a>, <a
    --href="http://en.wikipedia.org/wiki/Double_free#Use_after_free">use after
    -+href="http://en.wikipedia.org/wiki/Buffer_overflow" class="external-link">buffer overflows</a>, <a
    -+href="http://en.wikipedia.org/wiki/Double_free#Use_after_free" class="external-link">use after
    - free</a>, and <a
    --href="http://en.wikipedia.org/wiki/Off-by-one_error">off-by-one errors</a>.
    -+href="http://en.wikipedia.org/wiki/Off-by-one_error" class="external-link">off-by-one errors</a>.
    - Android provides a number of technologies like <acronym
    - title="Address Space Layout Randomization">ASLR</acronym> and <acronym
    - title="Data Execution Prevention">DEP</acronym> that reduce the
    --exploitability of these errors, but they do not solve the underlying problem.
    --You can prevent these vulneratbilities by careful handling pointers and managing
    -+exploitability of these errors, but they don't solve the underlying problem.
    -+You can prevent these vulnerabilities by carefully handling pointers and managing
    - buffers.</p>
    - 
    --<p>Dynamic, string based languages such as JavaScript and SQL are also subject
    -+<p>Dynamic, string-based languages such as JavaScript and SQL are also subject
    - to input validation problems due to escape characters and <a
    --href="http://en.wikipedia.org/wiki/Code_injection">script injection</a>.</p>
    -+href="http://en.wikipedia.org/wiki/Code_injection" class="external-link">script injection</a>.</p>
    - 
    - <p>If you are using data within queries that are submitted to an SQL database or a
    - content provider, SQL injection may be an issue.  The best defense is to use
    -@@ -348,60 +354,59 @@ href="#ContentProviders">content providers</a>.
    - Limiting permissions to read-only or write-only can also reduce the potential
    - for harm related to SQL injection.</p>
    - 
    --<p>If you cannot use the security features above, we strongly recommend the use
    --of well-structured data formats and verifying that the data conforms to the
    -+<p>If you can't use the security features above, you should make sure to use
    -+well-structured data formats and verify that the data conforms to the
    - expected format. While blacklisting of characters or character-replacement can
    --be an effective strategy, these techniques are error-prone in practice and
    -+be an effective strategy, these techniques are error prone in practice and
    - should be avoided when possible.</p>
    - 
    - 
    - 
    - 
    - 
    --<h2 id="UserData">Handling User Data</h2>
    -+<h2 id="UserData">Handling user data</h2>
    - 
    - <p>In general, the best approach for user data security is to minimize the use of APIs that access
    - sensitive or personal user data. If you have access to user data and can avoid
    --storing or transmitting the information, do not store or transmit the data.
    --Finally, consider if there is a way that your application logic can be
    -+storing or transmitting it, don't store or transmit the data.
    -+Consider if there is a way that your application logic can be
    - implemented using a hash or non-reversible form of the data.  For example, your
    --application might use the hash of an an email address as a primary key, to
    -+application might use the hash of an email address as a primary key to
    - avoid transmitting or storing the email address.  This reduces the chances of
    - inadvertently exposing data, and it also reduces the chance of attackers
    - attempting to exploit your application.</p>
    - 
    - <p>If your application accesses personal information such as passwords or
    --usernames, keep in mind that some jurisdictions may require you to provide a
    --privacy policy explaining your use and storage of that data.  So following the
    -+user names, keep in mind that some jurisdictions may require you to provide a
    -+privacy policy explaining your use and storage of that data. Following the
    - security best practice of minimizing access to user data may also simplify
    - compliance.</p>
    - 
    - <p>You should also consider whether your application might be inadvertently
    - exposing personal information to other parties such as third-party components
    - for advertising or third-party services used by your application. If you don't
    --know why a component or service requires a personal information, don’t
    -+know why a component or service requires personal information, don’t
    - provide it.  In general, reducing the access to personal information by your
    --application will reduce the potential for problems in this area.</p>
    --
    --<p>If access to sensitive data is required, evaluate whether that information
    --must be transmitted to a server, or whether the operation can be performed on
    --the client.  Consider running any code using sensitive data on the client to
    --avoid transmitting user data.</p>
    --
    --<p>Also, make sure that you do not inadvertently expose user data to other
    --application on the device through overly permissive IPC, world writable files,
    --or network sockets. This is a special case of leaking permission-protected data,
    -+application reduces the potential for problems in this area.</p>
    -+
    -+<p>If your app requires access to sensitive data, evaluate whether you need to
    -+ transmit it to a server or you can run the operation on
    -+the client. Consider running any code using sensitive data on the client to
    -+avoid transmitting user data. Also, make sure that you do not inadvertently expose user
    -+ data to other
    -+applications on the device through overly permissive IPC, world-writable files,
    -+or network sockets. Overly permissive IPC is a special case of leaking permission-protected data,
    - discussed in the <a href="#RequestingPermissions">Requesting Permissions</a> section.</p>
    - 
    - <p>If a <acronym title="Globally Unique Identifier">GUID</acronym>
    --is required, create a large, unique number and store it.  Do not
    --use phone identifiers such as the phone number or IMEI which may be associated
    -+is required, create a large, unique number and store it.  Don't
    -+use phone identifiers such as the phone number or IMEI, which may be associated
    - with personal information.  This topic is discussed in more detail in the <a
    --href="http://android-developers.blogspot.com/2011/03/identifying-app-installations.html">Android
    --Developer Blog</a>.</p>
    -+href="http://android-developers.blogspot.com/2011/03/identifying-app-installations.html"
    -+>Android Developer Blog</a>.</p>
    - 
    - <p>Be careful when writing to on-device logs.
    --In Android, logs are a shared resource, and are available
    -+In Android, logs are a shared resource and are available
    - to an application with the {@link android.Manifest.permission#READ_LOGS} permission.
    - Even though the phone log data
    - is temporary and erased on reboot, inappropriate logging of user information
    -@@ -414,19 +419,23 @@ could inadvertently leak user data to other applications.</p>
    - 
    - <h2 id="WebView">Using WebView</h2>
    - 
    --<p>Because {@link android.webkit.WebView} consumes web content that can include HTML and JavaScript,
    -+<p>Because {@link android.webkit.WebView} consumes web content that can include HTML
    -+ and JavaScript,
    - improper use can introduce common web security issues such as <a
    --href="http://en.wikipedia.org/wiki/Cross_site_scripting">cross-site-scripting</a>
    -+href="http://en.wikipedia.org/wiki/Cross_site_scripting" class="external-link">
    -+cross-site-scripting</a>
    - (JavaScript injection).  Android includes a number of mechanisms to reduce
    --the scope of these potential issues by limiting the capability of {@link android.webkit.WebView} to
    -+the scope of these potential issues by limiting the capability of
    -+ {@link android.webkit.WebView} to
    - the minimum functionality required by your application.</p>
    - 
    --<p>If your application does not directly use JavaScript within a {@link android.webkit.WebView}, do
    --<em>not</em> call {@link android.webkit.WebSettings#setJavaScriptEnabled setJavaScriptEnabled()}.
    -+<p>If your application doesn't directly use JavaScript within a {@link android.webkit.WebView},
    -+ <em>do not</em> call
    -+ {@link android.webkit.WebSettings#setJavaScriptEnabled setJavaScriptEnabled()}.
    - Some sample code uses this method, which you might repurpose in production
    - application, so remove that method call if it's not required. By default,
    - {@link android.webkit.WebView} does
    --not execute JavaScript so cross-site-scripting is not possible.</p>
    -+not execute JavaScript, so cross-site-scripting is not possible.</p>
    - 
    - <p>Use {@link android.webkit.WebView#addJavascriptInterface
    - addJavaScriptInterface()} with
    -@@ -441,55 +450,55 @@ addJavaScriptInterface()} only to JavaScript that is contained within your appli
    - <p>If your application accesses sensitive data with a
    - {@link android.webkit.WebView}, you may want to use the
    - {@link android.webkit.WebView#clearCache clearCache()} method to delete any files stored
    --locally. Server-side
    --headers like <code>no-cache</code> can also be used to indicate that an application should
    -+locally. You can also use server-side
    -+headers such as <code>no-cache</code> to indicate that an application should
    - not cache particular content.</p>
    - 
    - <p>Devices running platforms older than Android 4.4 (API level 19)
    - use a version of {@link android.webkit webkit} that has a number of security issues.
    - As a workaround, if your app is running on these devices, it
    --should confirm that {@link android.webkit.WebView} objects display only trusted
    --content. You should also use the updatable security {@link
    --java.security.Provider Provider} object to make sure your app isn’t exposed to
    --potential vulnerabilities in SSL, as described in <a
    -+must confirm that {@link android.webkit.WebView} objects display only trusted
    -+content. To make sure your app isn’t exposed to
    -+potential vulnerabilities in SSL, use the updatable security {@link
    -+java.security.Provider Provider} object as described in <a
    - href="{@docRoot}training/articles/security-gms-provider.html">Updating Your
    - Security Provider to Protect Against SSL Exploits</a>. If your application must
    - render content from the open web, consider providing your own renderer so
    - you can keep it up to date with the latest security patches.</p>
    - 
    - 
    --<h3 id="Credentials">Handling Credentials</h3>
    -+<h3 id="Credentials">Handling credentials</h3>
    - 
    --<p>In general, we recommend minimizing the frequency of asking for user
    --credentials&mdash;to make phishing attacks more conspicuous, and less likely to be
    --successful.  Instead use an authorization token and refresh it.</p>
    -+<p>To make phishing attacks more conspicuous and less likely to be
    -+successful, minimize the frequency of asking for user
    -+credentials. Instead use an authorization token and refresh it.</p>
    - 
    --<p>Where possible, username and password should not be stored on the device.
    --Instead, perform initial authentication using the username and password
    --supplied by the user, and then use a short-lived, service-specific
    -+<p>Where possible, don't store user names and passwords on the device.
    -+Instead, perform initial authentication using the user name and password
    -+ supplied by the user, and then use a short-lived, service-specific
    - authorization token.</p>
    - 
    --<p>Services that will be accessible to multiple applications should be accessed
    -+<p>Services that are accessible to multiple applications should be accessed
    - using {@link android.accounts.AccountManager}. If possible, use the
    --{@link android.accounts.AccountManager} class to invoke a cloud-based service and do not store
    -+{@link android.accounts.AccountManager} class to invoke a cloud-based service and don't store
    - passwords on the device.</p>
    - 
    - <p>After using {@link android.accounts.AccountManager} to retrieve an
    --{@link android.accounts.Account}, {@link android.accounts.Account#CREATOR}
    --before passing in any credentials, so that you do not inadvertently pass
    -+{@link android.accounts.Account}, use {@link android.accounts.Account#CREATOR}
    -+before passing in any credentials so that you do not inadvertently pass
    - credentials to the wrong application.</p>
    - 
    --<p>If credentials are to be used only by applications that you create, then you
    --can verify the application which accesses the {@link android.accounts.AccountManager} using
    -+<p>If credentials are used only by applications that you create, you
    -+can verify the application that accesses the {@link android.accounts.AccountManager} using
    - {@link android.content.pm.PackageManager#checkSignatures checkSignature()}.
    --Alternatively, if only one application will use the credential, you might use a
    -+Alternatively, if only one application uses the credential, you might use a
    - {@link java.security.KeyStore} for storage.</p>
    - 
    - 
    - 
    - 
    - 
    --<h2 id="Crypto">Using Cryptography</h2>
    -+<h2 id="Crypto">Using cryptography</h2>
    - 
    - <p>In addition to providing data isolation, supporting full-filesystem
    - encryption, and providing secure communications channels, Android provides a
    -@@ -500,21 +509,21 @@ implementation that can  support your use case.  If you need to securely
    - retrieve a file from a known location, a simple HTTPS URI may be adequate and
    - requires no knowledge of cryptography.  If you need a secure
    - tunnel, consider using {@link javax.net.ssl.HttpsURLConnection} or
    --{@link javax.net.ssl.SSLSocket}, rather than writing your own protocol.</p>
    -+{@link javax.net.ssl.SSLSocket} rather than writing your own protocol.</p>
    - 
    --<p>If you do find yourself needing to implement your own protocol, we strongly
    --recommend that you <em>not</em> implement your own cryptographic algorithms. Use
    -+<p>If you do need to implement your own protocol, you should <em>not</em>
    -+implement your own cryptographic algorithms. Use
    - existing cryptographic algorithms such as those in the implementation of AES or
    - RSA provided in the {@link javax.crypto.Cipher} class.</p>
    - 
    - <p>Use a secure random number generator, {@link java.security.SecureRandom},
    --to initialize any cryptographic keys, {@link javax.crypto.KeyGenerator}.
    -+to initialize any cryptographic keys generated by {@link javax.crypto.KeyGenerator}.
    - Use of a key that is not generated with a secure random
    --number generator significantly weakens the strength of the algorithm, and may
    -+number generator significantly weakens the strength of the algorithm and may
    - allow offline attacks.</p>
    - 
    --<p>If you need to store a key for repeated use, use a mechanism like
    --  {@link java.security.KeyStore} that
    -+<p>If you need to store a key for repeated use, use a mechanism, such as
    -+  {@link java.security.KeyStore}, that
    - provides a mechanism for long term storage and retrieval of cryptographic
    - keys.</p>
    - 
    -@@ -522,10 +531,10 @@ keys.</p>
    - 
    - 
    - 
    --<h2 id="IPC">Using Interprocess Communication</h2>
    -+<h2 id="IPC">Using interprocess communication</h2>
    - 
    - <p>Some apps attempt to implement IPC using traditional Linux
    --techniques such as network sockets and shared files.  We strongly encourage you to instead
    -+techniques such as network sockets and shared files. However, you should instead
    - use Android system functionality for IPC such as {@link android.content.Intent},
    - {@link android.os.Binder} or {@link android.os.Messenger} with a {@link
    - android.app.Service}, and {@link android.content.BroadcastReceiver}.
    -@@ -535,19 +544,19 @@ mechanism.</p>
    - 
    - <p>Many of the security elements are shared across IPC mechanisms.
    - If your IPC mechanism is not intended for use by other applications, set the
    --{@code android:exported} attribute to {@code "false"} in the component's manifest element,
    -+{@code android:exported} attribute to {@code false} in the component's manifest element,
    - such as for the <a
    --href="{@docRoot}guide/topics/manifest/service-element.html#exported">{@code <service>}</a>
    -+href="{@docRoot}guide/topics/manifest/service-element.html#exported">{@code &lt;service&gt;}</a>
    - element.  This is useful for applications that consist of multiple processes
    --within the same UID, or if you decide late in development that you do not
    --actually want to expose functionality as IPC but you don’t want to rewrite
    -+within the same UID or if you decide late in development that you don't
    -+actually want to expose functionality as IPC, but you don’t want to rewrite
    - the code.</p>
    - 
    --<p>If your IPC is intended to be accessible to other applications, you can
    -+<p>If your IPC is accessible to other applications, you can
    - apply a security policy by using the <a
    --href="{@docRoot}guide/topics/manifest/permission-element.html">{@code <permission>}</a>
    -+href="{@docRoot}guide/topics/manifest/permission-element.html">{@code &lt;permission>}</a>
    - element. If IPC is between your own separate apps that are signed with the same key,
    --it is preferable to use {@code "signature"} level permission in the <a
    -+it is preferable to use {@code signature} level permission in the <a
    - href="{@docRoot}guide/topics/manifest/permission-element.html#plevel">{@code
    - android:protectionLevel}</a>.</p>
    - 
    -@@ -556,31 +565,42 @@ android:protectionLevel}</a>.</p>
    - 
    - <h3>Using intents</h3>
    - 
    --<p>Intents are the preferred mechanism for asynchronous IPC in Android.
    -+<p>For activities and broadcast receivers, intents are the preferred mechanism for
    -+ asynchronous IPC in Android.
    - Depending on your application requirements, you might use {@link
    - android.content.Context#sendBroadcast sendBroadcast()}, {@link
    - android.content.Context#sendOrderedBroadcast sendOrderedBroadcast()},
    - or an explicit intent to a specific application component.</p>
    - 
    --<p>Note that ordered broadcasts can be “consumed” by a recipient, so they
    -+<p class="caution"><strong>Caution:</strong> If you use an intent to bind to a
    -+ {@link android.app.Service}, ensure that your app is secure by using an
    -+ <a href="{@docRoot}guide/components/intents-filters.html#Types">explicit</a>
    -+intent. Using an implicit intent to start a service is a
    -+security hazard because you can't be certain what service will respond to the intent,
    -+and the user can't see which service starts. Beginning with Android 5.0 (API level 21),
    -+ the system
    -+throws an exception if you call {@link android.content.Context#bindService bindService()}
    -+with an implicit intent.</p>
    -+
    -+<p>Note that ordered broadcasts can be <em>consumed</em> by a recipient, so they
    - may not be delivered to all applications.  If you are sending an intent that must be delivered
    --to a specific receiver, then you must use an explicit intent that declares the receiver
    --by nameintent.</p>
    -+to a specific receiver, you must use an explicit intent that declares the receiver
    -+by name.</p>
    - 
    --<p>Senders of an intent can verify that the recipient has a permission
    --specifying a non-Null permission with the method call.  Only applications with that
    --permission will receive the intent.  If data within a broadcast intent may be
    -+<p>Senders of an intent can verify that the recipient has permission
    -+ by specifying a non-null permission with the method call.  Only applications with that
    -+permission receive the intent. If data within a broadcast intent may be
    - sensitive, you should consider applying a permission to make sure that
    --malicious applications cannot register to receive those messages without
    --appropriate permissions.  In those circumstances, you may also consider
    -+malicious applications can't register to receive those messages without
    -+appropriate permissions. In those circumstances, you may also consider
    - invoking the receiver directly, rather than raising a broadcast.</p>
    - 
    - <p class="note"><strong>Note:</strong> Intent filters should not be considered
    --a security feature&mdash;components
    -+a security feature. Components
    - can be invoked with explicit intents and may not have data that would conform to the intent
    --filter. You should perform input validation within your intent receiver to
    -+filter. To
    - confirm that it is properly formatted for the invoked receiver, service, or
    --activity.</p>
    -+activity, perform input validation within your intent receiver.</p>
    - 
    - 
    - 
    -@@ -589,26 +609,32 @@ activity.</p>
    - 
    - <p>A {@link android.app.Service} is often used to supply functionality for other applications to
    - use. Each service class must have a corresponding <a
    --href="{@docRoot}guide/topics/manifest/service-element.html">{@code <service>}</a> declaration in its
    -+href="{@docRoot}guide/topics/manifest/service-element.html">{@code <service>}</a>
    -+ declaration in its
    - manifest file.</p>
    - 
    - <p>By default, services are not exported and cannot be invoked by any other
    --application. However, if you add any intent filters to the service declaration, then it is exported
    -+application. However, if you add any intent filters to the service declaration, it is exported
    - by default. It's best if you explicitly declare the <a
    - href="{@docRoot}guide/topics/manifest/service-element.html#exported">{@code
    - android:exported}</a> attribute to be sure it behaves as you'd like.
    - Services can also be protected using the <a
    - href="{@docRoot}guide/topics/manifest/service-element.html#prmsn">{@code android:permission}</a>
    --attribute. By doing so, other applications will need to declare
    -+attribute. By doing so, other applications need to declare
    - a corresponding <code><a
    - href="{@docRoot}guide/topics/manifest/uses-permission-element.html">&lt;uses-permission&gt;</a>
    - </code> element in their own manifest to be
    - able to start, stop, or bind to the service.</p>
    - 
    -+<p class="note"><strong>Note:</strong> If your app targets Android 5.0 (API level 21) or later,
    -+ you should use the {@link android.app.job.JobScheduler} to execute background
    -+ services. For more information about {@link android.app.job.JobScheduler}, see its
    -+ {@link android.app.job.JobScheduler API-reference documentation}.</p>
    -+
    - <p>A service can protect individual IPC calls into it with permissions, by
    - calling {@link android.content.Context#checkCallingPermission
    - checkCallingPermission()} before executing
    --the implementation of that call.  We generally recommend using the
    -+the implementation of that call. You should use the
    - declarative permissions in the manifest, since those are less prone to
    - oversight.</p>
    - 
    -@@ -620,24 +646,24 @@ oversight.</p>
    - preferred mechanism for RPC-style IPC in Android. They provide a well-defined
    - interface that enables mutual authentication of the endpoints, if required.</p>
    - 
    --<p>We strongly encourage designing interfaces in a manner that does not require
    --interface specific permission checks. {@link android.os.Binder} and
    -+<p>You should design your app interfaces in a manner that does not require
    -+interface-specific permission checks. {@link android.os.Binder} and
    - {@link android.os.Messenger} objects are not declared within the
    - application manifest, and therefore you cannot apply declarative permissions
    - directly to them.  They generally inherit permissions declared in the
    - application manifest for the {@link android.app.Service} or {@link
    - android.app.Activity} within which they are
    - implemented.  If you are creating an interface that requires authentication
    --and/or access controls, those controls must be
    --explicitly added as code in the {@link android.os.Binder} or {@link android.os.Messenger}
    -+and/or access controls, you must explicitly add those controls
    -+ as code in the {@link android.os.Binder} or {@link android.os.Messenger}
    - interface.</p>
    - 
    --<p>If providing an interface that does require access controls, use {@link
    -+<p>If you are providing an interface that does require access controls, use {@link
    - android.content.Context#checkCallingPermission checkCallingPermission()}
    - to verify whether the
    - caller has a required permission. This is especially important
    - before accessing a service on behalf of the caller, as the identify of your
    --application is passed to other interfaces.  If invoking an interface provided
    -+application is passed to other interfaces.  If you are invoking an interface provided
    - by a {@link android.app.Service}, the {@link
    - android.content.Context#bindService bindService()}
    -  invocation may fail if you do not have permission to access the given service.
    -@@ -660,8 +686,8 @@ application. If your {@link android.content.BroadcastReceiver}
    - is intended for use by other applications, you
    - may want to apply security permissions to receivers using the <code><a
    - href="{@docRoot}guide/topics/manifest/receiver-element.html">
    --&lt;receiver&gt;</a></code> element within the application manifest.  This will
    --prevent applications without appropriate permissions from sending an intent to
    -+&lt;receiver&gt;</a></code> element within the application manifest.  This
    -+prevents applications without appropriate permissions from sending an intent to
    - the {@link android.content.BroadcastReceiver}.</p>
    - 
    - 
    -@@ -671,57 +697,58 @@ the {@link android.content.BroadcastReceiver}.</p>
    - 
    - 
    - 
    --<h2 id="DynamicCode">Dynamically Loading Code</h2>
    -+<h2 id="DynamicCode">Dynamically loading code</h2>
    - 
    - <p>We strongly discourage loading code from outside of your application APK.
    - Doing so significantly increases the likelihood of application compromise due
    --to code injection or code tampering.  It also adds complexity around version
    --management and application testing.  Finally, it can make it impossible to
    -+to code injection or code tampering. It also adds complexity around version
    -+management and application testing. It can also make it impossible to
    - verify the behavior of an application, so it may be prohibited in some
    - environments.</p>
    - 
    - <p>If your application does dynamically load code, the most important thing to
    --keep in mind about dynamically loaded code is that it runs with the same
    --security permissions as the application APK.  The user made a decision to
    --install your application based on your identity, and they are expecting that
    -+keep in mind about dynamically-loaded code is that it runs with the same
    -+security permissions as the application APK.  The user makes a decision to
    -+install your application based on your identity, and the user expects that
    - you provide any code run within the application, including code that is
    - dynamically loaded.</p>
    - 
    - <p>The major security risk associated with dynamically loading code is that the
    - code needs to come from a verifiable source. If the modules are included
    --directly within your APK, then they cannot be modified by other applications.
    -+directly within your APK, they cannot be modified by other applications.
    - This is true whether the code is a native library or a class being loaded using
    --{@link dalvik.system.DexClassLoader}.  We have seen many instances of applications
    --attempting to load code from insecure locations, such as downloaded from the
    --network over unencrypted protocols or from world writable locations such as
    -+{@link dalvik.system.DexClassLoader}.  Many applications
    -+attempt to load code from insecure locations, such as downloaded from the
    -+network over unencrypted protocols or from world-writable locations such as
    - external storage. These locations could allow someone on the network to modify
    --the content in transit, or another application on a users device to modify the
    --content on the device, respectively.</p>
    -+the content in transit or another application on a user's device to modify the
    -+content on the device.</p>
    - 
    - 
    - 
    - 
    - 
    --<h2 id="Dalvik">Security in a Virtual Machine</h2>
    -+<h2 id="Dalvik">Security in a virtual machine</h2>
    - 
    - <p>Dalvik is Android's runtime virtual machine (VM). Dalvik was built specifically for Android,
    - but many of the concerns regarding secure code in other virtual machines also apply to Android.
    - In general, you shouldn't concern yourself with security issues relating to the virtual machine.
    --Your application runs in a secure sandbox environment, so other processes on the system cannnot
    -+Your application runs in a secure sandbox environment, so other processes on the system can't
    - access your code or private data.</p>
    - 
    --<p>If you're interested in diving deeper on the subject of virtual machine security,
    --we recommend that you familiarize yourself with some
    -+<p>If you're interested in learning more about virtual machine security,
    -+ familiarize yourself with some
    - existing literature on the subject. Two of the more popular resources are:
    - <ul>
    --<li><a href="http://www.securingjava.com/toc.html">
    --http://www.securingjava.com/toc.html</a></li>
    -+<li><a href="http://www.securingjava.com/toc.html" class="external-link">
    -+Securing Java</a></li>
    - <li><a
    --href="https://www.owasp.org/index.php/Java_Security_Resources">
    --https://www.owasp.org/index.php/Java_Security_Resources</a></li>
    -+href="https://www.owasp.org/index.php/Category:Java#tab=Related_3rd_Party_Projects"
    -+ class="external-link">
    -+Related 3rd party Projects</a></li>
    - </ul></p>
    - 
    --<p>This document is focused on the areas which are Android specific or
    -+<p>This document focuses on areas that are Android specific or
    - different from other VM environments.  For developers experienced with VM
    - programming in other environments, there are two broad issues that may be
    - different about writing apps for Android:
    -@@ -742,21 +769,19 @@ because that code might be modified to include malicious behavior.</li>
    - 
    - 
    - 
    --<h2 id="Native">Security in Native Code</h2>
    -+<h2 id="Native">Security in native code</h2>
    - 
    --<p>In general, we encourage developers to use the Android SDK for
    -+<p>In general, you should use the Android SDK for
    - application development, rather than using native code with the
    - <a href="{@docRoot}tools/sdk/ndk/index.html">Android NDK</a>.  Applications built
    - with native code are more complex, less portable, and more like to include
    --common memory corruption errors such as buffer overflows.</p>
    -+common memory-corruption errors such as buffer overflows.</p>
    - 
    --<p>Android is built using the Linux kernel and being familiar with Linux
    --development security best practices is especially useful if you are going to
    --use native code. Linux security practices are beyond the scope of this document,
    --but one of the most popular resources is “Secure Programming for
    --Linux and Unix HOWTO”, available at <a
    --href="http://www.dwheeler.com/secure-programs">
    --http://www.dwheeler.com/secure-programs</a>.</p>
    -+<p>Android is built using the Linux kernel, and being familiar with Linux
    -+development security best practices is especially useful if you are
    -+using native code. Linux security practices are beyond the scope of this document,
    -+but one of the most popular resources is <a href="http://www.dwheeler.com/secure-programs"
    -+ class="external-link">Secure Programming HOWTO - Creating Secure Software</a>.</p>
    - 
    - <p>An important difference between Android and most Linux environments is the
    - Application Sandbox.  On Android, all applications run in the Application
    -@@ -765,6 +790,5 @@ good way to think about it for developers familiar with Linux is to know that
    - every application is given a unique <acronym title="User Identifier">UID</acronym>
    - with very limited permissions. This is discussed in more detail in the <a
    - href="http://source.android.com/tech/security/index.html">Android Security
    --Overview</a> and you should be familiar with application permissions even if
    -+Overview</a>, and you should be familiar with application permissions even if
    - you are using native code.</p>
    --
    -diff --git a/docs/html/training/auto/audio/index.jd b/docs/html/training/auto/audio/index.jd
    -index 3a1b1e8..6588367 100644
    ---- a/docs/html/training/auto/audio/index.jd
    -+++ b/docs/html/training/auto/audio/index.jd
    -@@ -596,7 +596,7 @@ href="https://www.youtube.com/watch?v=xc2HZSwPcwM">
    - </a>
    - <h2 id="support_voice">Support Voice Actions</h2>
    - 
    --<p>To reduce driver distractions, you can add voice actions in your audio playback app. With voice
    -+<p>To reduce driver distractions, you must add voice actions in your audio playback app. With voice
    - action support, users can launch your app and play audio by providing voice input on Auto screens.
    - If your audio playback app is already active and the user says
    - <i>“Play a song”</i>, the system starts playing music without requiring the user to look at or touch
    -diff --git a/docs/html/training/backup/autosyncapi.jd b/docs/html/training/backup/autosyncapi.jd
    -deleted file mode 100644
    -index e0df7bb..0000000
    ---- a/docs/html/training/backup/autosyncapi.jd
    -+++ /dev/null
    -@@ -1,370 +0,0 @@
    --page.title=Configuring Auto Backup for Apps
    --page.tags=backup, marshmallow, androidm
    --page.keywords=backup, autobackup
    --page.image=images/cards/card-auto-backup_2x.png
    --
    --@jd:body
    --
    --<div id="tb-wrapper">
    --<div id="tb">
    --<h2>This lesson teaches you to</h2>
    --<ol>
    --        <li><a href="#configuring">Configure Data Backup</a></li>
    --        <li><a href="#previous-androids">Support Lower Versions of Android</a></li>
    --        <li><a href="#testing">Test Backup Configuration</a></li>
    --        <li><a href="#issues">Handle Google Cloud Messaging</a></li>
    --</ol>
    --    <h2>You should also read</h2>
    --    <ul>
    --      <li><a href="{@docRoot}guide/topics/data/backup.html">Data Backup</a></li>
    --      <li><a href="{@docRoot}training/backup/backupapi.html">Using the Backup API</a>
    --      </li>
    --    </ul>
    --
    --</div>
    --</div>
    --
    --<p>
    --  Users frequently invest time and effort to configure apps just the way they like them. Switching
    --  to a new device can cancel out all that careful configuration. For apps whose <a href=
    --  "{@docRoot}guide/topics/manifest/uses-sdk-element.html#target">target SDK version</a>
    --  is Android 6.0 (API level 23) and higher, devices running Android 6.0 and higher automatically
    --  back up app data to the cloud. The system performs this automatic backup
    --  for nearly all app data by default, and does so without your having to write any additional app
    --  code.
    --</p>
    --
    --<p class="note">
    --<strong>Note:</strong> To protect user privacy, the device user must have opted in to Google
    --services for Auto Backup to work. The Google services opt-in dialog appears when the user goes
    --through the Setup Wizard or configures the first Google account on the device.
    --</p>
    --
    --<p>
    --  When a user installs your app on
    --  a new device, or reinstalls your app on one (for example, after a factory reset), the system
    --  automatically restores the app data from the cloud. This lesson provides information about how to
    --  configure the Auto Backup for Apps feature, explaining its default behavior and how to
    --  exclude data that you don't want the system to back up.
    --</p>
    --
    --<p>
    --  The automatic backup feature preserves the data your app creates on a user device by uploading it
    --  to the user’s Google Drive account and encrypting it. There is no charge to you or the user for
    --  data storage, and the saved data does not count towards the user's personal Google Drive quota.
    --  Each app can store up to 25MB. Once its backed-up data reaches 25MB, the app no longer sends
    --  data to the cloud. If the system performs a data restore, it uses the last data snapshot that
    --  the app had sent to the cloud.
    --</p>
    --
    --<p>Automatic backups occur when the following conditions are met:</p>
    --  <ul>
    --     <li>The device is idle.</li>
    --     <li>The device is charging.</li>
    --     <li>The device is connected to a Wi-Fi network.</li>
    --     <li>At least 24 hours have elapsed since the last backup.</li>
    --  </ul>
    --</p>
    --
    --<h2 id="configuring">Configure Data Backup</h2>
    --
    --<p>
    --  On devices running Android 6.0 (API level 23) or higher, the default system behavior is to back up
    --  almost all data that an app creates. The exception is <a href="#auto-exclude">
    --  automatically excluded data files</a>. This section explains how you can use settings in
    --  your app <a href="{@docRoot}guide/topics/manifest/manifest-intro.html">manifest</a> to further
    --  limit and configure what data the system backs up.
    --</p>
    --
    --<h3 id="include-exclude">Including or excluding data</h3>
    --
    --<p>
    --  Depending on what data your app needs and how you save it, you may need to set specific
    --  rules for including or excluding certain files or directories. Auto Backup for Apps
    --  lets you set these backup rules through the app manifest, in which you specify a backup scheme
    --  configuration XML file. For example:
    --</p>
    --
    --<pre>
    --&lt;?xml version="1.0" encoding="utf-8"?&gt;
    --&lt;manifest xmlns:android="http://schemas.android.com/apk/res/android"
    --        xmlns:tools="http://schemas.android.com/tools"
    --        package="com.my.appexample"&gt;
    --    &lt;uses-sdk android:minSdkVersion="23"/&gt;
    --    &lt;uses-sdk android:targetSdkVersion="23"/&gt;
    --    &lt;application ...
    --<strong>        android:fullBackupContent="&#64;xml/mybackupscheme"&gt;</strong>
    --    &lt;/app&gt;
    --    ...
    --&lt;/manifest&gt;
    --</pre>
    --
    --<p>
    --  In this example, the <code>android:fullBackupContent</code> attribute specifies an XML file
    --  called {@code mybackupscheme.xml}, which resides in the <code>res/xml/</code> directory of your
    --  app development project. This configuration file contains rules controlling which files are backed
    --  up. The following example code shows a configuration file that excludes a specific file,
    --  {@code device_info.db}:
    --</p>
    --
    --<pre>
    --&lt;?xml version="1.0" encoding="utf-8"?&gt;
    --&lt;full-backup-content&gt;
    --    &lt;exclude domain="database" path="device_info.db"/&gt;
    --&lt;/full-backup-content&gt;
    --</pre>
    --
    --<h3 id="auto-exclude">Automatically excluded data files</h3>
    --
    --<p>
    --  Most apps do not need to, and in fact should not, back up all data. For example, the system
    --  should not back up temporary files and caches. For this reason, the automatic backup
    --  service excludes certain data files by default:
    --</p>
    --
    --<ul>
    --  <li>Files in the directories to which the
    --  {@link android.content.Context#getCacheDir getCacheDir()} and
    --  {@link android.content.Context#getCodeCacheDir getCodeCacheDir()} methods refer.
    --  </li>
    --
    --  <li>Files located on external storage, unless they reside in the directory to which the
    --    {@link android.content.Context#getExternalFilesDir getExternalFilesDir()} method refers.
    --  </li>
    --
    --  <li>Files located in the directory to which the
    --    {@link android.content.Context#getNoBackupFilesDir getNoBackupFilesDir()} method refers.
    --  </li>
    --</ul>
    --<h3>Backup Configuration Syntax</h3>
    --
    --<p>
    --  The backup service configuration allows you to specify what files to include or exclude from
    --  backup. The syntax for the data backup configuration XML file is as follows:
    --</p>
    --
    --<pre>
    --&lt;full-backup-content&gt;
    --    &lt;include domain=["file" | "database" | "sharedpref" | "external" | "root"]
    --    path="string" /&gt;
    --    &lt;exclude domain=["file" | "database" | "sharedpref" | "external" | "root"]
    --    path="string" /&gt;
    --&lt;/full-backup-content&gt;
    --</pre>
    --
    --<p>
    --  The following elements and attributes allow you to specify the files to include in, and exclude
    --  from, backup:
    --</p>
    --
    --<ul>
    --  <li>
    --  <code>&lt;include&gt;</code>: Specifies a set of resources to
    --  back up, instead of having the system back up all data in your app by default. If you specify
    --  an <code>&lt;include&gt;</code> element, the system backs up <em>only the resources specified</em>
    --  with this element. You can specify multiple sets of resources to back up by using multiple
    --  <code>&lt;include&gt;</code> elements
    --  </li>
    --
    --  <li>
    --  <code>&lt;exclude&gt;</code>: Specifies any data you want the system to exclude
    --  when it does a full backup. If you target the same set of resources with both the
    --  <code>&lt;include&gt;</code> and <code>&lt;exclude&gt;</code> elements,
    --  <code>&lt;exclude&gt;</code> takes precedence.
    --  </li>
    --
    --  <li>
    --  <code>domain</code>: Specifies the type of resource you want to include in,
    --  or exclude from, backup. Valid values for this attribute include:
    --
    --
    --
    --  <ul>
    --    <li>
    --    <code>root</code>: Specifies that the resource is in the app’s root directory.
    --    </li>
    --
    --    <li>
    --    <code>file</code>: Specifies a resource in the directory returned by the
    --    {@link android.content.Context#getFilesDir getFilesDir()} method.
    --    </li>
    --
    --    <li>
    --    <code>database</code>: Specifies a database that the
    --    {@link android.content.Context#getDatabasePath getDatabasePath()} method returns, or that
    --    the app interacts with via the {@link android.database.sqlite.SQLiteOpenHelper} class.
    --    </li>
    --
    --    <li>
    --    <code>sharedpref</code>: Specifies a {@link android.content.SharedPreferences} object
    --    that the {@link android.content.Context#getSharedPreferences getSharedPreferences()}
    --    method returns.
    --    </li>
    --
    --    <li>
    --    <code>external</code>: Specifies that the resource is in external storage, and corresponds
    --    to a file in the directory that the
    --    {@link android.content.Context#getExternalFilesDir getExternalFilesDir()} method returns.
    --    </li>
    --  </ul>
    --  </li>
    --    <li>
    --    <code>path</code>: Specifies the file path to a resource that you want to include in, or
    --    exclude from, backup.
    --    </li>
    --
    --  </li>
    --</ul>
    --
    --
    --<h3 id="disabling">Disabling data backups</h3>
    --
    --<p>
    --  You can choose to prevent automatic backups of any of your app data by setting the
    --  <code>android:allowBackup</code> attribute to <code>false</code> in the {@code app} element of
    --  your manifest. This setting is illustrated in the following example:
    --</p>
    --
    --<pre>
    --&lt;?xml version="1.0" encoding="utf-8"?&gt;
    --&lt;manifest xmlns:android="http://schemas.android.com/apk/res/android"
    --        xmlns:tools="http://schemas.android.com/tools"
    --        package="com.my.appexample"&gt;
    --    &lt;uses-sdk android:minSdkVersion="23"/&gt;
    --    &lt;uses-sdk android:targetSdkVersion="23"/&gt;
    --    &lt;application ...
    --<strong>        android:allowBackup="false"&gt;</strong>
    --    &lt;/application&gt;
    --    ...
    --&lt;/manifest&gt;
    --</pre>
    --
    --<h2 id="previous-androids">Support Lower Versions of Android</h2>
    --
    --<p>There are two scenarios in which you may also need to support versions of Android lower
    --than 6.0 (API level 23): You may be updating your existing app to take advantage of the
    --new auto backup functionality in Android 6.0, while wanting
    --to continue supporting earlier versions of Android. Or you may be releasing a new app, but
    --want to make sure devices running on versions of Android predating 6.0 also have backup
    --functionality.</p>
    --
    --<h3 id="updating">Updating an existing app to support auto backup</h3>
    --
    --<p>Earlier versions of Android supported a key/value-pair-based backup mechanism, in which the app
    --defines a subclass of {@link android.app.backup.BackupAgent} and sets
    --<a href="{@docRoot}guide/topics/manifest/application-element.html#agent">
    --{@code android:backupAgent}</a> in its
    --<a href="{@docRoot}guide/topics/manifest/application-element.html">app manifest</a>. If your app
    --used this legacy approach, you can transition to full-data backups by adding the
    --{@code android:fullBackupOnly="true"} attribute to the
    --<a href="{@docRoot}guide/topics/manifest/application-element.html">{@code <application/>}</a>
    --element in the manifest. When running on a device with Android 5.1
    --(API level 22) or lower, your app ignores this value in the manifest, and continues performing
    --backups in the previous manner.</p>
    --
    --<p>Even if you’re not using key/value backups, you can still use the approach described above to do
    --any custom processing in {@link android.app.Activity#onCreate(android.os.Bundle) onCreate()}
    --or {@link android.app.backup.BackupAgent#onFullBackup onFullBackup()}. You can also use that
    --approach to receive a notification when a restore operation happens in
    --{@link android.app.backup.BackupAgent#onRestoreFinished onRestoreFinished()}. If you want to retain
    --the system's default implementation of
    --<a href="#include-exclude">XML include/exclude rules handling</a>, call
    --{@link android.app.backup.BackupAgent#onFullBackup super.onFullBackup()}.</p>
    --
    --<h3 id="lower-versions">Giving your new app support for lower versions of Android</h3>
    --
    --<p>If you are creating a new app that targets Android 6.0, but you also want to enable cloud backup
    --for devices running on Android 5.1 (API level 22) and lower, you must also
    --<a href="{@docRoot}training/backup/backupapi.html">implement the Backup API</a>.</p>
    --
    --<h2 id="testing">Test Backup Configuration</h2>
    --
    --<p>
    --  Once you have created a backup configuration, you should test it to make sure your app saves data
    --  and can restore it properly.
    --</p>
    --
    --
    --<h3>Enabling Backup Logging</h3>
    --
    --<p>
    --  To help determine how the backup feature is parsing your XML file, enable logging before
    --  performing a test backup:
    --</p>
    --
    --<pre class="no-pretty-print">
    --$ adb shell setprop log.tag.BackupXmlParserLogging VERBOSE
    --</pre>
    --
    --<h3>Testing Backup</h3>
    --
    --<p>To manually run a backup, first initialize the Backup Manager by executing the following
    --  command:
    --</p>
    --
    --<pre class="no-pretty-print">
    --$ adb shell bmgr run
    --</pre>
    --
    --<p>
    --  Next, manually back up your application using the following command. Use the
    --  <code>&lt;PACKAGE&gt;</code> parameter to specify the package name for your app:
    --</p>
    --
    --<pre class="no-pretty-print">
    --$ adb shell bmgr fullbackup &lt;PACKAGE&gt;</pre>
    --
    --
    --<h3>Testing restore</h3>
    --
    --<p>
    --  To manually initiate a restore after the system has backed up your app data, execute the following
    --  command, using the <code>&lt;PACKAGE&gt;</code> parameter to specify the package name for your
    --  app:
    --</p>
    --
    --<pre class="noprettyprint">
    --$ adb shell bmgr restore &lt;PACKAGE&gt;
    --</pre>
    --
    --<p class="warning">
    --  <b>Warning:</b> This action stops your app and wipes its data before performing the restore
    --  operation.
    --</p>
    --
    --<p>
    --  You can test automatic restore for your app by uninstalling and reinstalling your app. The app
    --  data is automatically restored from the cloud once the app installation is complete.
    --</p>
    --
    --
    --<h3>Troubleshooting backups</h3>
    --
    --<p>
    --  If backup fails, you can clear the backup data and associated metadata either by turning backup
    --  off and on in <strong>Settings &gt; Backup</strong>, factory-resetting the device, or
    --  executing this command:
    --</p>
    --
    --<pre>$ adb shell bmgr wipe &lt;TRANSPORT&gt; &lt;PACKAGE&gt;</pre>
    --
    --<p>
    --  You must prepend <code>com.google.android.gms</code> to the {@code <TRANSPORT>} value.
    --  To get the list of <a href="{@docRoot}google/backup/index.html">transports</a>, execute the
    --  following command:
    --</p>
    --
    --<pre>$ adb shell bmgr list transports</pre>
    --
    --<h2 id="gcm">Handle Google Cloud Messaging</h2>
    --
    --  <p>
    --  For apps that use <a href="https://developers.google.com/cloud-messaging/gcm">Google Cloud
    --  Messaging</a> (GCM) for push notifications, backing up the registration
    --  token that Google Cloud Messaging registration returned can cause unexpected behavior in
    --  notifications for the restored app. This is because when a user installs your app on a new device,
    --  the app must <a href="https://developers.google.com/cloud-messaging/android/client#sample-register">
    --  query the GCM API for a new registration token</a>. If the old registration is present, because the
    --  system had backed it up and restored it, the app doesn't seek the new token. To prevent this issue
    --  from arising, exclude the registration token from the set of backed-up files.
    --  </p>
    -diff --git a/docs/html/training/backup/backupapi.jd b/docs/html/training/backup/backupapi.jd
    -deleted file mode 100644
    -index 2f3e939..0000000
    ---- a/docs/html/training/backup/backupapi.jd
    -+++ /dev/null
    -@@ -1,200 +0,0 @@
    --page.title=Using the Backup API
    --parent.title=Backing up App Data to the Cloud
    --parent.link=index.html
    --
    --trainingnavtop=true
    --
    --next.title=Making the Most of Google Cloud Messaging
    --next.link=gcm.html
    --
    --@jd:body
    --
    --<div id="tb-wrapper">
    --  <div id="tb">
    --    <h2>This lesson teaches you to</h2>
    --    <ol>
    --      <li><a href="#register">Register for the Android Backup Service</a></li>
    --      <li><a href="#manifest">Configure Your Manifest</a></li>
    --      <li><a href="#agent">Write Your Backup Agent</a></li>
    --      <li><a href="#backup">Request a Backup</a></li>
    --      <li><a href="#restore">Restore from a Backup</a></li>
    --    </ol>
    --    <h2>You should also read</h2>
    --    <ul>
    --      <li><a href="{@docRoot}guide/topics/data/backup.html">Data Backup</a></li>
    --      <li><a href="{@docRoot}training/backup/autosyncapi.html">Configuring Auto Backup for Apps</a>
    --      (Android 6.0 (API level 23) and higher)</li>
    --    </ul>
    --  </div>
    --</div>
    --
    --<p>When a user purchases a new device or resets their existing one, they might
    --expect that when Google Play restores your app back to their device during the
    --initial setup, the previous data associated with the app restores as well. On versions of Android
    --prior to 6.0 (API level 23), app data is not restored by default, and all the user's accomplishments
    --or settings in your app are lost.</p>
    --<p>For situations where the volume of data is relatively light (less than a
    --megabyte), like the user's preferences, notes, game high scores or other
    --stats, the Backup API provides a lightweight solution.  This lesson walks you
    --through integrating the Backup API into your application, and restoring data to
    --new devices using the Backup API.
    --
    --<p class="note">
    --<strong>Note:</strong> Devices running Android 6.0 and higher
    --<a href="{@docRoot}training/backup/autosyncapi.html">automatically back up</a>
    --nearly all data by default.
    --</p>
    --
    --<h2 id="register">Register for the Android Backup Service</h2>
    --<p>This lesson requires the use of the <a
    --  href="{@docRoot}google/backup/index.html">Android Backup
    --  Service</a>, which requires registration.  Go ahead and <a
    --  href="http://code.google.com/android/backup/signup.html">register here</a>.  Once
    --that's done, the service pre-populates an XML tag for insertion in your Android
    --Manifest, which looks like this:</p>
    --<pre>
    --&lt;meta-data android:name="com.google.android.backup.api_key"
    --android:value="ABcDe1FGHij2KlmN3oPQRs4TUvW5xYZ" /&gt;
    --</pre>
    --<p>Note that each backup key works with a specific package name.  If you have
    --different applications, register separate keys for each one.</p>
    --
    --
    --<h2 id="manifest">Configure Your Manifest</h2>
    --<p>Use of the Android Backup Service requires two additions to your application
    --manifest.  First, declare the name of the class that acts as your backup agent,
    --then add the snippet above as a child element of the Application tag.  Assuming
    --your backup agent is going to be called {@code TheBackupAgent}, here's an example of
    --what the manifest looks like with this tag included:</p>
    --
    --<pre>
    --&lt;application android:label="MyApp"
    --             android:backupAgent="TheBackupAgent"&gt;
    --    ...
    --    &lt;meta-data android:name="com.google.android.backup.api_key"
    --    android:value="ABcDe1FGHij2KlmN3oPQRs4TUvW5xYZ" /&gt;
    --    ...
    --&lt;/application&gt;
    --</pre>
    --<h2 id="agent">Write Your Backup Agent</h2>
    --<p>The easiest way to create your backup agent is by extending the wrapper class
    --{@link android.app.backup.BackupAgentHelper}.  Creating this helper class is
    --actually a very simple process.  Just create a class with the same name as you
    --used in the manifest in the previous step (in this example, {@code
    --TheBackupAgent}),
    --and extend {@code BackupAgentHelper}.  Then override the {@link
    --android.app.backup.BackupAgent#onCreate()}.</p>
    --
    --<p>Inside the {@link android.app.backup.BackupAgent#onCreate()} method, create a {@link
    --android.app.backup.BackupHelper}.  These helpers are
    --specialized classes for backing up certain kinds of data.  The Android framework
    --currently includes two such helpers:  {@link
    --android.app.backup.FileBackupHelper} and {@link
    --android.app.backup.SharedPreferencesBackupHelper}.  After you create the helper
    --and point it at the data you want to back up, just add it to the
    --BackupAgentHelper using the {@link android.app.backup.BackupAgentHelper#addHelper(String, BackupHelper) addHelper()}
    --method, adding a key which is used to
    --retrieve the data later.  In most cases the entire
    --implementation is perhaps 10 lines of code.</p>
    --
    --<p>Here's an example that backs up a high scores file.</p>
    --
    --<pre>
    --import android.app.backup.BackupAgentHelper;
    --import android.app.backup.FileBackupHelper;
    --
    --
    --public class TheBackupAgent extends BackupAgentHelper {
    --  // The name of the SharedPreferences file
    --  static final String HIGH_SCORES_FILENAME = "scores";
    --
    --  // A key to uniquely identify the set of backup data
    --  static final String FILES_BACKUP_KEY = "myfiles";
    --
    --  // Allocate a helper and add it to the backup agent
    --  &#64;Override
    --  void onCreate() {
    --      FileBackupHelper helper = new FileBackupHelper(this, HIGH_SCORES_FILENAME);
    --      addHelper(FILES_BACKUP_KEY, helper);
    --  }
    --}
    --</pre>
    --<p>For added flexibility, {@link android.app.backup.FileBackupHelper}'s
    --constructor can take a variable number of filenames.  You could just as easily
    --have backed up both a high scores file and a game progress file just by adding
    --an extra parameter, like this:</p>
    --<pre>
    --&#64;Override
    --  void onCreate() {
    --      FileBackupHelper helper = new FileBackupHelper(this, HIGH_SCORES_FILENAME, PROGRESS_FILENAME);
    --      addHelper(FILES_BACKUP_KEY, helper);
    --  }
    --</pre>
    --<p>Backing up preferences is similarly easy.  Create a {@link
    --android.app.backup.SharedPreferencesBackupHelper}  the same way you did a {@link
    --android.app.backup.FileBackupHelper}.  In this case, instead of adding filenames
    --to the constructor, add the names of the shared preference groups being used by
    --your application.  Here's an example of how your backup agent helper might look if
    --high scores are implemented as preferences instead of a flat file:</p>
    --
    --<pre>
    --import android.app.backup.BackupAgentHelper;
    --import android.app.backup.SharedPreferencesBackupHelper;
    --
    --public class TheBackupAgent extends BackupAgentHelper {
    --    // The names of the SharedPreferences groups that the application maintains.  These
    --    // are the same strings that are passed to getSharedPreferences(String, int).
    --    static final String PREFS_DISPLAY = "displayprefs";
    --    static final String PREFS_SCORES = "highscores";
    --
    --    // An arbitrary string used within the BackupAgentHelper implementation to
    --    // identify the SharedPreferencesBackupHelper's data.
    --    static final String MY_PREFS_BACKUP_KEY = "myprefs";
    --
    --    // Simply allocate a helper and install it
    --    void onCreate() {
    --       SharedPreferencesBackupHelper helper =
    --                new SharedPreferencesBackupHelper(this, PREFS_DISPLAY, PREFS_SCORES);
    --        addHelper(MY_PREFS_BACKUP_KEY, helper);
    --    }
    --}
    --</pre>
    --
    --<p>You can add as many backup helper instances to your backup agent helper as you
    --like, but remember that you only need one of each type.  One {@link
    --android.app.backup.FileBackupHelper} handles all the files that you need to back up, and one
    --{@link android.app.backup.SharedPreferencesBackupHelper} handles all the shared
    --preferencegroups you need backed up.
    --</p>
    --
    --
    --<h2 id="backup">Request a Backup</h2>
    --<p>In order to request a backup, just create an instance of the {@link
    --android.app.backup.BackupManager}, and call it's {@link
    --android.app.backup.BackupManager#dataChanged()} method.</p>
    --
    --<pre>
    --import android.app.backup.BackupManager;
    --...
    --
    --public void requestBackup() {
    --  BackupManager bm = new BackupManager(this);
    --  bm.dataChanged();
    --}
    --</pre>
    --
    --<p>This call notifies the backup manager that there is data ready to be backed
    --up to the cloud.  At some point in the future, the backup manager then calls
    --your backup agent's {@link
    --android.app.backup.BackupAgent#onBackup(ParcelFileDescriptor, BackupDataOutput,
    --ParcelFileDescriptor) onBackup()} method.  You can make
    --the call whenever your data has changed, without having to worry about causing
    --excessive network activity.  If you request a backup twice before a backup
    --occurs, the backup only occurs once.</p>
    --
    --
    --<h2 id="restore">Restore from a Backup</h2>
    --<p>Typically you shouldn't ever have to manually request a restore, as it
    --happens automatically when your application is installed on a device.  However,
    --if it <em>is</em> necessary to trigger a manual restore, just call the
    --{@link android.app.backup.BackupManager#requestRestore(RestoreObserver) requestRestore()} method.</p>
    -diff --git a/docs/html/training/backup/index.jd b/docs/html/training/backup/index.jd
    -deleted file mode 100644
    -index 4449fde..0000000
    ---- a/docs/html/training/backup/index.jd
    -+++ /dev/null
    -@@ -1,47 +0,0 @@
    --page.title=Backing up App Data to the Cloud
    --page.tags=cloud,sync,backup
    --
    --trainingnavtop=true
    --startpage=true
    --
    --@jd:body
    --
    --<div id="tb-wrapper">
    --<div id="tb">
    --
    --<h2>Dependencies and prerequisites</h2>
    --<ul>
    --  <li>Android 2.2 (API level 8) and higher</li>
    --</ul>
    --</div>
    --</div>
    --
    --<p>Users often invest significant time and effort creating data and setting
    --preferences within apps. Preserving that data for users if they replace a broken
    --device or upgrade to a new one is an important part of ensuring a great user
    --experience.</p>
    --
    --<p>This class covers techniques for backing up data to the cloud so that
    --users can restore their data when recovering from a data loss (such as a factory
    --reset) or installing your application on a new device.</p>
    --
    --<p>It is important to note that the API for cloud backup changed with the
    --release of Android 6.0 (API level 23). For your app to support backup both
    --on devices running Android 6.0, and those running Android 5.1 (API level
    --22) and lower, you must implement both techniques that this class explains.</p>
    --
    --<h2>Lessons</h2>
    --
    --<dl>
    --	<dt><strong><a href="autosyncapi.html">Configuring Auto Backup for Apps</a></strong></dt>
    --	<dd>This lesson applies to Android 6.0 (API level 23) and higher. Learn how to accomplish
    --  seamless app data backup and restore with zero additional lines of application code.</dd>
    --</dl>
    --
    --<dl>
    --  <dt><strong><a href="backupapi.html">Using the Backup API</a></strong></dt>
    --  <dd>This lesson applies to Android 5.1 (API level 22) and lower. Learn how to integrate the Backup
    --  API into your Android app, so all of that  app's user data, such as preferences, notes, and high
    --  scores, updates seamlessly across all devices linked to that Google account.</dd>
    --</dl>
    --
    -diff --git a/docs/html/training/basics/firstapp/building-ui.jd b/docs/html/training/basics/firstapp/building-ui.jd
    -index a680c73..6f321e9 100644
    ---- a/docs/html/training/basics/firstapp/building-ui.jd
    -+++ b/docs/html/training/basics/firstapp/building-ui.jd
    -@@ -71,17 +71,17 @@ android.view.View} objects.</p>
    - <h2 id="LinearLayout">Create a Linear Layout</h2>
    - 
    - <ol>
    --  <li>From the <code>res/layout/</code> directory, open the
    --    <code>activity_main.xml</code> file.
    -+  <li>In Android Studio's <b>Project</b> window, open <b>app > res >
    -+    layout > activity_main.xml</b>.
    -     <p>This XML file defines the layout of your activity. It contains the
    -       default "Hello World" text view.</p>
    -   </li>
    -   <li>When you open a layout file, you’re first shown the design editor in the
    -     <a href="/studio/write/layout-editor.html">Layout Editor</a>. For this lesson,
    --    you work directly with the XML, so click the <b>Text</b> tab to switch to
    --    the text editor.
    -+    you work directly with the XML, so click the <b>Text</b> tab at the bottom
    -+    of the window to switch to the text editor.
    -   </li>
    --  <li>Replace the contents of the file with the following XML:
    -+  <li>Delete everything and insert the following XML:
    -     <pre>&lt;?xml version="1.0" encoding="utf-8"?&gt;
    - &lt;LinearLayout
    -     xmlns:android="http://schemas.android.com/apk/res/android"
    -@@ -138,6 +138,9 @@ href="{@docRoot}guide/topics/ui/declaring-layout.html">Layout</a> guide.</p>
    - &lt;/LinearLayout&gt;
    - </pre>
    - 
    -+<p>Don't worry about the error that appears for
    -+<code>&#64;string/edit_message</code>; you'll fix that soon.</p>
    -+
    - <p>Here is a description of the attributes in the
    -   {@link android.widget.EditText &lt;EditText>} you added:</p>
    - 
    -@@ -157,7 +160,7 @@ XML. It is followed by the resource type ({@code id} in this case), a slash, the
    -   <p>A resource object is a unique integer name that's associated with an app resource,
    - such as a bitmap, layout file, or string.</p>
    -   <p>Every resource has a
    --corresponding resource object defined in your project's {@code gen/R.java} file. You can use the
    -+corresponding resource object defined in your project's {@code R.java} file. You can use the
    - object names in the {@code R} class to refer to your resources, such as when you need to specify a
    - string value for the <a
    - href="{@docRoot}reference/android/widget/TextView.html#attr_android:hint">{@code android:hint}</a>
    -@@ -174,7 +177,7 @@ href="{@docRoot}guide/topics/resources/providing-resources.html">Providing Resou
    - <p>The plus sign (<code>+</code>) before the resource type is needed only when you're defining a
    - resource ID for the first time. When you compile the app,
    - the SDK tools use the ID name to create a new resource ID in
    --your project's {@code gen/R.java} file that refers to the {@link
    -+your project's {@code R.java} file that refers to the {@link
    - android.widget.EditText} element. With the resource ID declared once this way,
    - other references to the ID do not
    - need the plus sign. Using the plus sign is necessary only when specifying a new resource ID and not
    -@@ -211,10 +214,10 @@ the same name does not cause collisions.</p>
    - <h2 id="Strings">Add String Resources</h2>
    - 
    - <p>By default, your Android project includes a string resource file at
    --<code>res/values/strings.xml</code>. Here, you'll add two new strings.</p>
    -+<b>res > values > strings.xml</b>. Here, you'll add two new strings.</p>
    - 
    - <ol>
    --<li>From the <code>res/values/</code> directory, open <code>strings.xml</code>.</li>
    -+<li>From the <b>Project</b> window, open <b>res > values > strings.xml</b>.</li>
    - <li>Add two strings so that your file looks like this:
    - <pre>&lt;?xml version="1.0" encoding="utf-8"?>
    - &lt;resources>
    -@@ -340,15 +343,12 @@ android.widget.LinearLayout}.</p>
    - 
    - <h2>Run Your App</h2>
    - 
    --<p>This layout is applied by the default {@link android.app.Activity} class
    --that the SDK tools generated when you created the project.</p>
    --
    --<p>To run the app and see the results,
    --  click <strong>Run 'app'</strong>
    -+<p>To see how the app now looks on your device or emulator,
    -+  click <strong>Run</strong>
    -     <img src="{@docRoot}images/tools/as-run.png"
    -     style="vertical-align:baseline;margin:0; max-height:1em" /> in the
    -     toolbar.</p>
    - 
    --<p>Continue to the <a href="starting-activity.html">next
    --lesson</a> to learn how to respond to button presses, read content
    --from the text field, start another activity, and more.</p>
    -\ No newline at end of file
    -+<p>To add app behaviors such as responding to a button and starting
    -+another activity, continue to the <a href="starting-activity.html">next
    -+lesson</a>.</p>
    -\ No newline at end of file
    -diff --git a/docs/html/training/basics/firstapp/creating-project.jd b/docs/html/training/basics/firstapp/creating-project.jd
    -index cad32bf..60be5f6 100644
    ---- a/docs/html/training/basics/firstapp/creating-project.jd
    -+++ b/docs/html/training/basics/firstapp/creating-project.jd
    -@@ -31,129 +31,71 @@ next.link=running-app.html
    - <ol>
    -   <li>In Android Studio, create a new project:
    -     <ul>
    --      <li>If you don't have a project opened, in the <strong>Welcome</strong> screen, click <strong>
    --        New Project</strong>.</li>
    --      <li>If you have a project opened, from the <strong>File</strong> menu, select <strong>New
    --        Project</strong>. The <em>Create New Project</em> screen appears.</li>
    -+      <li>If you don't have a project opened, in the <strong>Welcome to Android Studio</strong> window, click <strong>
    -+        Start a new Android Studio project</strong>.</li>
    -+      <li>If you have a project opened, select <strong>File > New Project</strong>.</li>
    -     </ul>
    -   </li>
    --  <li>Fill out the fields on the screen. For <strong>Application Name</strong>
    --    use "My First App". For <strong>Company Domain</strong>, use "example.com".
    --    For the other fields, use the default values and click <strong>Next</strong>
    --    <p>Here's a brief explanation of each field:</p>
    -+  <li>In the <b>New Project</b> screen, enter the following values:</p>
    -     <ul>
    --      <li><strong>Application Name</strong> is the app name that appears to users.</li>
    --      <li><strong>Company domain</strong> provides a qualifier that will be appended to the package
    --        name; Android Studio will remember this qualifier for each new project you create.</li>
    --      <li><strong>Package name</strong> is the fully qualified name for the project (following the
    --        same rules as those for naming packages in the Java programming language). Your package name
    --        must be unique across all packages installed on the Android system. You can <strong>
    --        Edit</strong> this value independently from the application name or the company
    --        domain.</li>
    --      <li><strong>Project location</strong> is the directory on your system that holds the project
    --        files.</li>
    -+      <li><strong>Application Name</strong>: "My First App" </li>
    -+      <li><strong>Company Domain</strong>: "example.com"</li>
    -     </ul>
    -+    <p>Android Studio fills in the package name and project location for you,
    -+    but you can edit these if you'd like.
    -   </li>
    --  <li>Under <strong>Target Android Devices</strong>, accept the default values
    --    and click <strong>Next</strong>.
    --    <p>The Minimum Required SDK is the earliest version of Android that your app supports,
    --      indicated using the <a href="{@docRoot}guide/topics/manifest/uses-sdk-element.html#ApiLevels">
    -+  <li>Click <b>Next</b>.</li>
    -+  <li>In the <b>Target Android Devices</b> screen, keep the default values and
    -+    click <b>Next</b>.
    -+    <p>The <b>Minimum Required SDK</b> is the earliest version of Android that your app supports,
    -+      which is indicated by the <a href="{@docRoot}guide/topics/manifest/uses-sdk-element.html#ApiLevels">
    -       API level</a>. To support as many devices as possible, you should set this to the lowest
    -       version available that allows your app to provide its core feature set. If any feature of your
    --      app is possible only on newer versions of Android and it's not critical to the app's core
    --      feature set, you can enable the feature only when running on the versions that support it (as
    --      discussed in <a href="{@docRoot}training/basics/supporting-devices/platforms.html">
    -+      app is possible only on newer versions of Android and it's not critical to the core
    -+      feature set, enable that feature only when running on the versions that support it (see
    -+      <a href="{@docRoot}training/basics/supporting-devices/platforms.html">
    -       Supporting Different Platform Versions</a>).</p>
    -     </li>
    - 
    --  <li>Under <strong>Add an Activity to Mobile</strong>, select <strong>Empty
    -+  <li>In the <strong>Add an Activity to Mobile</strong> screen, select <strong>Empty
    -     Activity</strong> and click <strong>Next</strong>.
    -   </li>
    - 
    --  <div class="sidebox-wrapper">
    --    <div class="sidebox">
    --      <h3>Activities</h3>
    --      <p>An activity is one of the distinguishing features of the Android framework. Activities
    --        provide the user with access to your app, and there may be many activities. An application
    --        will usually have a main activity for when the user launches the application, another
    --        activity for when she selects some content to view, for example, and other activities for
    --        when she performs other tasks within the app. See <a href="{@docRoot}guide/components/activities.html">
    --        Activities</a> for more information.</p>
    --    </div>
    --  </div>
    --
    --  <li>Under <strong>Customize the Activity</strong>, accept the default values
    -+  <li>In the <strong>Customize the Activity</strong> screen, keep the default values
    -     and click <strong>Finish</strong>.
    - </ol>
    - 
    --<p>Your Android project is now a basic "Hello World" app that contains some default files. Take a
    --moment to review the most important of these:</p>
    -+<p>After some processing, Android Studio opens and displays a "Hello World" app
    -+with default files. You will add functionality to some of
    -+these files in the following lessons.</p>
    -+
    -+<p>Now take a moment to review the most important files. First, be sure that
    -+the <b>Project</b> window is open (select <b>View > Tool Windows > Project</b>)
    -+and the <b>Android</b> view is selected from the drop-down list at the top.
    -+You can then see the following files:</p>
    - 
    - <dl>
    --  <dt><code>app/src/main/java/com.example.myfirstapp/MainActivity.java</code></dt>
    -+  <dt><b>app > java > com.example.myfirstapp > MainActivity.java</b></dt>
    -   <dd>This file appears in Android Studio after the New Project wizard finishes.
    -     It contains the class definition for the activity you created earlier. When you build
    -     and run the app, the {@link android.app.Activity} starts and loads the
    -     layout file that says "Hello World!"</dd>
    - 
    --  <dt><code>app/src/main/res/layout/activity_main.xml</code></dt>
    -+  <dt><b>app > res > layout > activity_main.xml</b></dt>
    -   <dd>This XML file defines the layout of the activity. It contains a {@code TextView}
    -     element with the text "Hello world!".</dd>
    - 
    --  <dt><code>app/src/main/AndroidManifest.xml</code></dt>
    -+  <dt><b>app > manifests > AndroidManifest.xml</b></dt>
    -   <dd>The <a href="{@docRoot}guide/topics/manifest/manifest-intro.html">manifest file</a> describes
    -     the fundamental characteristics of the app and defines each of its components. You'll revisit
    -     this file as you follow these lessons and add more components to your app.</dd>
    --  <dt><code>app/build.gradle</code></dt>
    -+
    -+  <dt><b>Gradle Scripts > build.gradle</b></dt>
    -   <dd>Android Studio uses Gradle to compile and build your app. There is a <code>build.gradle</code>
    -     file for each module of your project, as well as a <code>build.gradle</code> file for the entire
    --    project. Usually, you're only interested in the <code>build.gradle</code> file for the module,
    --    in this case the <code>app</code> or application module. This is where your app's build dependencies
    --    are set, including the <code>defaultConfig</code> settings:
    --    <ul>
    --      <li><code>compiledSdkVersion</code> is the platform version against which you will compile
    --        your app. By default, this is set to the latest version of Android available in your SDK.
    --        By default, this is set to the latest version of Android SDK installed on your
    --        development machine.
    --        You can still build your app to support older versions, but setting this to the latest
    --        version allows you to enable new features and optimize your app for a great user experience
    --        on the latest devices.</li>
    --      <li><code>applicationId</code> is the fully qualified package name for your application that
    --        you specified in the New Project wizard.</li>
    --      <li><code>minSdkVersion</code> is the Minimum SDK version you specified during the New Project
    --        wizard. This is the earliest version of the Android SDK that your app supports.</li>
    --      <li><code>targetSdkVersion</code> indicates the highest version of Android with which you have
    --        tested your application. As new versions of Android become available, you should
    --        test your app on the new version and update this value to match the latest API level and
    --        thereby take advantage of new platform features. For more information, read
    --        <a href="{@docRoot}training/basics/supporting-devices/platforms.html">Supporting Different
    --          Platform Versions</a>.</li>
    --    </ul>
    --    <p>See <a href="{@docRoot}studio/build/index.html">Building Your Project with Gradle</a>
    --    for more information about Gradle.</p></dd>
    --</dl>
    --
    --<p>Note also the <code>/res</code> subdirectories that contain the
    --<a href="{@docRoot}guide/topics/resources/overview.html">resources</a> for your application:</p>
    --<dl>
    --  <dt><code>drawable<em>-&lt;density&gt;</em>/</code></dt>
    --    <dd>Directories for <a href="{@docRoot}guide/topics/resources/drawable-resource.html">
    --    drawable resources</a>, other than launcher icons, designed
    --    for various <a href="{@docRoot}training/multiscreen/screendensities.html">densities</a>.
    --</dd>
    --  <dt><code>layout/</code></dt>
    --    <dd>Directory for files that define your app's user interface like {@code activity_main.xml},
    --      discussed above, which describes a basic layout for the {@code MainActivity}
    --      class.</dd>
    --  <dt><code>menu/</code></dt>
    --    <dd>Directory for files that define your app's menu items.</dd>
    --  <dt><code>mipmap/</code></dt>
    --    <dd>Launcher icons reside in the {@code mipmap/} folder rather than the
    --    {@code drawable/} folders. This folder contains the {@code ic_launcher.png} image
    --    that appears when you run the default app.</dd>
    --  <dt><code>values/</code></dt>
    --    <dd>Directory for other XML files that contain a collection of resources, such as
    --      string and color definitions.</dd>
    -+    project. Usually, you're only interested in the <code>build.gradle</code> file for the module.
    -+    in this case the <code>app</code> or application module. For more information about this file,
    -+    see <a href="{@docRoot}studio/build/index.html">Building Your Project with Gradle</a>.</dd>
    - </dl>
    - 
    - <p>
    -diff --git a/docs/html/training/basics/firstapp/running-app.jd b/docs/html/training/basics/firstapp/running-app.jd
    -index e809871..085849f 100755
    ---- a/docs/html/training/basics/firstapp/running-app.jd
    -+++ b/docs/html/training/basics/firstapp/running-app.jd
    -@@ -3,9 +3,7 @@ parent.title=Building Your First App
    - parent.link=index.html
    - 
    - trainingnavtop=true
    --
    - page.tags=emulator
    --helpoutsWidget=true
    - 
    - @jd:body
    - 
    -@@ -18,7 +16,7 @@ helpoutsWidget=true
    - 
    - <ol>
    -   <li><a href="#RealDevice">Run on a Real Device</a></li>
    --  <li><a href="#Emulator">Run on the Emulator</a></li>
    -+  <li><a href="#Emulator">Run on an Emulator</a></li>
    - </ol>
    - 
    - <h2>You should also read</h2>
    -@@ -34,8 +32,10 @@ helpoutsWidget=true
    - 
    - 
    - <p>In the <a href="creating-project.html">previous lesson</a>, you created an
    --  Android project. The project contains a default app that displays
    --  "Hello World". In this lesson, you will run the app on a device or emulator.</p>
    -+Android project that displays "Hello World." You can now run the app on a real
    -+device or on an emulator. If you don't have a real device available, skip to
    -+<a href="#Emulator">Run on an Emulator</a>.</p>
    -+
    - 
    - <h2 id="RealDevice">Run on a Real Device</h2>
    - 
    -@@ -68,7 +68,7 @@ helpoutsWidget=true
    - <p>Android Studio installs the app on your connected device and starts it.</p>
    - 
    - 
    --<h2 id="Emulator">Run on the Emulator</h2>
    -+<h2 id="Emulator">Run on an Emulator</h2>
    - 
    - <p>Before you run your app on an emulator, you need to create an
    -   <a href="{@docRoot}tools/devices/index.html">Android Virtual Device</a> (AVD)
    -@@ -82,12 +82,14 @@ helpoutsWidget=true
    -     <strong>Tools &gt; Android &gt; AVD Manager</strong>, or by clicking
    -     the AVD Manager icon <img src="{@docRoot}images/tools/avd-manager-studio.png"
    -     style="vertical-align:bottom;margin:0;height:19px"> in the toolbar.</li>
    --  <li>On the AVD Manager main screen, click <strong>Create Virtual Device</strong>.</li>
    --  <li>In the Select Hardware page, select a phone device, such as Nexus 6,
    --    then click <strong>Next</strong>.
    -+  <li>In the <b>Your Virtual Devices</b> screen, click <strong>Create Virtual Device</strong>.</li>
    -+  <li>In the <b>Select Hardware</b> screen, select a phone device, such as Nexus 6,
    -+    and then click <strong>Next</strong>.
    -   </li>
    --  <li>In the Select Image page, choose the desired system image for the AVD and
    -+  <li>In the <b>System Image</b> screen, choose the desired system image for the AVD and
    -     click <strong>Next</strong>.
    -+    <p>If you don't have a particular system image installed,
    -+    you can get it by clicking the <b>download</b> link.</p>
    -   </li>
    -   <li>Verify the configuration settings (for your first AVD, leave all the
    -     settings as they are), and then click <strong>Finish</strong>.
    -diff --git a/docs/html/training/basics/firstapp/starting-activity.jd b/docs/html/training/basics/firstapp/starting-activity.jd
    -index ebf42cb..4385d13 100644
    ---- a/docs/html/training/basics/firstapp/starting-activity.jd
    -+++ b/docs/html/training/basics/firstapp/starting-activity.jd
    -@@ -38,7 +38,7 @@ starts a new activity when the user clicks the Send button.</p>
    - <h2 id="RespondToButton">Respond to the Send Button</h2>
    - 
    - <ol>
    --  <li>In the file <code>res/layout/activity_main.xml</code>, add the
    -+  <li>In the file <b>res > layout > activity_main.xml</b>, add the
    -     <a href="{@docRoot}reference/android/view/View.html#attr_android:onClick">{@code android:onClick}</a>
    -     attribute to the {@link android.widget.Button &lt;Button&gt;} element as
    -     shown below:
    -@@ -52,7 +52,7 @@ starts a new activity when the user clicks the Send button.</p>
    -       method in your activity whenever a user clicks on the button.</p>
    -   </li>
    - 
    --  <li>In the file <code>java/com.example.myfirstapp/MainActivity.java</code>,
    -+  <li>In the file <b>java > com.example.myfirstapp > MainActivity.java</b>,
    -     add the <code>sendMessage()</code> method stub as shown below:
    - 
    -     <pre>public class MainActivity extends AppCompatActivity {
    -@@ -85,7 +85,9 @@ starts a new activity when the user clicks the Send button.</p>
    - <p>Next, you’ll fill in this method to read the contents of the text field and deliver that text to
    - another activity.</p>
    - 
    -+
    - <h2 id="BuildIntent">Build an Intent</h2>
    -+
    - <p>An {@link android.content.Intent} is an object that provides runtime binding
    -   between separate components (such as two activities). The
    -   {@link android.content.Intent} represents an app’s "intent to do something."
    -@@ -113,13 +115,22 @@ another activity.</p>
    -     }
    - }</pre>
    - 
    --<p class="note"><strong>Note: </strong>Android Studio will display
    --  <code>Cannot resolve symbol</code> errors because the code references classes
    --  like {@link android.content.Intent} and {@link android.widget.EditText}
    --  that have not been imported. To import these classes, you can either 1)
    --  use Android Studio's "import class" functionality by pressing Alt + Enter
    --  (Option + Return on Mac) or 2) manually add import statements at the top of
    --  the file.</p>
    -+<p>Android Studio will display <b>Cannot
    -+resolve symbol</b> errors because this code references classes that are not
    -+imported. You can solve some of these with Android Studio's "import class"
    -+functionality by pressing Alt + Enter (or Option + Return on Mac).
    -+Your imports should end up as the following:</p>
    -+<pre>
    -+import android.content.Intent;
    -+import android.support.v7.app.AppCompatActivity;
    -+import android.os.Bundle;
    -+import android.view.View;
    -+import android.widget.EditText;
    -+</pre>
    -+
    -+<p>An error remains for <code>DisplayMessageActivity</code>, but that's okay;
    -+you'll fix that in the next section.
    -+
    - 
    - <p>There’s a lot going on in <code>sendMessage()</code>, so let’s explain
    -   what's going on.</p>
    -@@ -150,6 +161,7 @@ another activity.</p>
    -   method starts an instance of the <code>DisplayMessageActivity</code> specified
    -   by the {@link android.content.Intent}. Now you need to create the class.</p>
    - 
    -+
    - <h2 id="CreateActivity">Create the Second Activity</h2>
    - 
    - <ol>
    -@@ -169,7 +181,8 @@ another activity.</p>
    -   <li>Creates the corresponding layout file <code>activity_display_message.xml</code>
    -     </li>
    -   <li>Adds the required
    --    <a href="{@docRoot}guide/topics/manifest/activity-element.html">&lt;activity&gt;</a>
    -+    <a href="{@docRoot}guide/topics/manifest/activity-element.html"
    -+    ><code>&lt;activity&gt;</code></a>
    -     element in <code>AndroidManifest.xml</code>.
    - </ul>
    - 
    -@@ -199,7 +212,16 @@ protected void onCreate(Bundle savedInstanceState) {
    -    layout.addView(textView);
    - }</pre>
    -   </li>
    --  <li>Press Alt + Enter (option + return on Mac) to import missing classes.</li>
    -+  <li>Press Alt + Enter (or Option + Return on Mac) to import missing classes.
    -+  Your imports should end up as the following:
    -+<pre>
    -+import android.content.Intent;
    -+import android.support.v7.app.AppCompatActivity;
    -+import android.os.Bundle;
    -+import android.view.ViewGroup;
    -+import android.widget.TextView;
    -+</pre>
    -+</li>
    - </ol>
    - 
    - <p>There’s a lot going on here, so let’s explain:</p>
    -diff --git a/docs/html/training/basics/network-ops/data-saver.jd b/docs/html/training/basics/network-ops/data-saver.jd
    -index 75b7264..babf7c6 100644
    ---- a/docs/html/training/basics/network-ops/data-saver.jd
    -+++ b/docs/html/training/basics/network-ops/data-saver.jd
    -@@ -45,7 +45,7 @@ next.link=xml.html
    - </p>
    - 
    - <p>
    --  The N Developer Preview extends the {@link android.net.ConnectivityManager}
    -+  Android 7.0 (API level 24) extends the {@link android.net.ConnectivityManager}
    -   API to provide apps with a way to <a href="#status">retrieve the user’s Data
    -   Saver preferences</a> and <a href="#monitor-changes">monitor preference
    -   changes</a>. It is considered good practice for apps to check whether the
    -@@ -58,7 +58,7 @@ next.link=xml.html
    - </h2>
    - 
    - <p>
    --  In the N Developer Preview, apps can use the {@link
    -+  In Android 7.0 (API level 24), apps can use the {@link
    -   android.net.ConnectivityManager} API to determine what data usage
    -   restrictions are being applied. The {@code getRestrictBackgroundStatus()}
    -   method returns one of the following values:
    -diff --git a/docs/html/training/best-performance.jd b/docs/html/training/best-performance.jd
    -index 8ea6fd5..bb88e99 100644
    ---- a/docs/html/training/best-performance.jd
    -+++ b/docs/html/training/best-performance.jd
    -@@ -5,4 +5,9 @@ page.trainingcourse=true
    - 
    - 
    - <p>These classes and articles help you build an app that's smooth, responsive,
    --and uses as little battery as possible.</p>
    -\ No newline at end of file
    -+and uses as little battery as possible.</p>
    -+
    -+<p>Along with this section, you can find additional information about optimizing
    -+your app in the <a href="/topic/performance/index.html">Performance and
    -+Power</a> section.</p>
    -+
    -diff --git a/docs/html/training/camera/videobasics.jd b/docs/html/training/camera/videobasics.jd
    -index 6da239a..b20cfef 100644
    ---- a/docs/html/training/camera/videobasics.jd
    -+++ b/docs/html/training/camera/videobasics.jd
    -@@ -108,7 +108,7 @@ retrieves this video and displays it in a {@link android.widget.VideoView}.</p>
    - 
    - <pre>
    - &#64;Override
    --protected void onActivityResult(int requestCode, int resultCode, Intent data) {
    -+protected void onActivityResult(int requestCode, int resultCode, Intent intent) {
    -     if (requestCode == REQUEST_VIDEO_CAPTURE && resultCode == RESULT_OK) {
    -         Uri videoUri = intent.getData();
    -         mVideoView.setVideoURI(videoUri);
    -diff --git a/docs/html/training/constraint-layout/images/alignment-constraint-offset_2x.png b/docs/html/training/constraint-layout/images/alignment-constraint-offset_2x.png
    -new file mode 100644
    -index 0000000..1e4867e
    -Binary files /dev/null and b/docs/html/training/constraint-layout/images/alignment-constraint-offset_2x.png differ
    -diff --git a/docs/html/training/constraint-layout/images/alignment-constraint_2x.png b/docs/html/training/constraint-layout/images/alignment-constraint_2x.png
    -new file mode 100644
    -index 0000000..afe7d4a
    -Binary files /dev/null and b/docs/html/training/constraint-layout/images/alignment-constraint_2x.png differ
    -diff --git a/docs/html/training/constraint-layout/images/baseline-constraint_2x.png b/docs/html/training/constraint-layout/images/baseline-constraint_2x.png
    -new file mode 100644
    -index 0000000..dfc3522
    -Binary files /dev/null and b/docs/html/training/constraint-layout/images/baseline-constraint_2x.png differ
    -diff --git a/docs/html/training/constraint-layout/images/constraint-fail-fixed_2x.png b/docs/html/training/constraint-layout/images/constraint-fail-fixed_2x.png
    -new file mode 100644
    -index 0000000..be9d54f
    -Binary files /dev/null and b/docs/html/training/constraint-layout/images/constraint-fail-fixed_2x.png differ
    -diff --git a/docs/html/training/constraint-layout/images/constraint-fail_2x.png b/docs/html/training/constraint-layout/images/constraint-fail_2x.png
    -new file mode 100644
    -index 0000000..3f28ef7
    -Binary files /dev/null and b/docs/html/training/constraint-layout/images/constraint-fail_2x.png differ
    -diff --git a/docs/html/training/constraint-layout/images/layout-editor-convert-to-constraint_2x.png b/docs/html/training/constraint-layout/images/layout-editor-convert-to-constraint_2x.png
    -new file mode 100644
    -index 0000000..ace31a6
    -Binary files /dev/null and b/docs/html/training/constraint-layout/images/layout-editor-convert-to-constraint_2x.png differ
    -diff --git a/docs/html/training/constraint-layout/images/layout-editor-margin-callout_2-2_2x.png b/docs/html/training/constraint-layout/images/layout-editor-margin-callout_2-2_2x.png
    -new file mode 100644
    -index 0000000..0768022
    -Binary files /dev/null and b/docs/html/training/constraint-layout/images/layout-editor-margin-callout_2-2_2x.png differ
    -diff --git a/docs/html/training/constraint-layout/images/layout-editor-properties-callouts_2-2_2x.png b/docs/html/training/constraint-layout/images/layout-editor-properties-callouts_2-2_2x.png
    -new file mode 100644
    -index 0000000..b4ffb2c
    -Binary files /dev/null and b/docs/html/training/constraint-layout/images/layout-editor-properties-callouts_2-2_2x.png differ
    -diff --git a/docs/html/training/constraint-layout/images/layout-editor_2-2_2x.png b/docs/html/training/constraint-layout/images/layout-editor_2-2_2x.png
    -new file mode 100644
    -index 0000000..72a4e40
    -Binary files /dev/null and b/docs/html/training/constraint-layout/images/layout-editor_2-2_2x.png differ
    -diff --git a/docs/html/training/constraint-layout/images/parent-constraint_2x.png b/docs/html/training/constraint-layout/images/parent-constraint_2x.png
    -new file mode 100644
    -index 0000000..0414f1d
    -Binary files /dev/null and b/docs/html/training/constraint-layout/images/parent-constraint_2x.png differ
    -diff --git a/docs/html/training/constraint-layout/images/position-constraint_2x.png b/docs/html/training/constraint-layout/images/position-constraint_2x.png
    -new file mode 100644
    -index 0000000..9f93e72
    -Binary files /dev/null and b/docs/html/training/constraint-layout/images/position-constraint_2x.png differ
    -diff --git a/docs/html/training/constraint-layout/images/thumbnail-add-layout-guideline_2-2.png b/docs/html/training/constraint-layout/images/thumbnail-add-layout-guideline_2-2.png
    -new file mode 100644
    -index 0000000..f863e5f
    -Binary files /dev/null and b/docs/html/training/constraint-layout/images/thumbnail-add-layout-guideline_2-2.png differ
    -diff --git a/docs/html/training/constraint-layout/images/thumbnail-adjust-constraint-bias.png b/docs/html/training/constraint-layout/images/thumbnail-adjust-constraint-bias.png
    -new file mode 100644
    -index 0000000..d61e9b2
    -Binary files /dev/null and b/docs/html/training/constraint-layout/images/thumbnail-adjust-constraint-bias.png differ
    -diff --git a/docs/html/training/constraint-layout/images/thumbnail-studio-constraint-first.png b/docs/html/training/constraint-layout/images/thumbnail-studio-constraint-first.png
    -new file mode 100644
    -index 0000000..9747102
    -Binary files /dev/null and b/docs/html/training/constraint-layout/images/thumbnail-studio-constraint-first.png differ
    -diff --git a/docs/html/training/constraint-layout/images/thumbnail-studio-constraint-second.png b/docs/html/training/constraint-layout/images/thumbnail-studio-constraint-second.png
    -new file mode 100644
    -index 0000000..940b8495
    -Binary files /dev/null and b/docs/html/training/constraint-layout/images/thumbnail-studio-constraint-second.png differ
    -diff --git a/docs/html/training/constraint-layout/index.html b/docs/html/training/constraint-layout/index.html
    -new file mode 100644
    -index 0000000..62eaf15
    ---- /dev/null
    -+++ b/docs/html/training/constraint-layout/index.html
    -@@ -0,0 +1,498 @@
    -+<html devsite>
    -+<head>
    -+  <title>Build a Responsive UI with ConstraintLayout</title>
    -+  <meta name="book_path" value="/training/_book.yaml" />
    -+  <meta name="top_category" value="develop" />
    -+  <meta name="subcategory" value="training" />
    -+</head>
    -+<body>
    -+
    -+<div id="tb-wrapper">
    -+<div id="tb">
    -+  <h2>In this document</h2>
    -+  <ol>
    -+    <li><a href="#constraints-overview">Constraints overview</a></li>
    -+    <li><a href="#add-constraintlayout-to-your-project">Add ConstraintLayout to your project</a></li>
    -+    <li><a href="#add-a-constraint">Add a constraint</a></li>
    -+    <li><a href="#use-autoconnect-and-infer-constraints">Use Autoconnect and Infer Constraints</a></li>
    -+    <li><a href="#adjust-the-view-size">Adjust the view size</a></li>
    -+    <li><a href="#adjust-the-constraint-bias">Adjust the constraint bias</a></li>
    -+    <li><a href="#adjust-the-view-margins">Adjust the view margins</a></li>
    -+  </ol>
    -+</div>
    -+</div>
    -+
    -+
    -+<p><code>ConstraintLayout</code> allows you to create large and complex layouts with a flat view
    -+hierarchy (no nested view groups). It's similar to <code>RelativeLayout</code> in that all views are
    -+layed out according to relationships between sibling views and the parent layout, but it's more
    -+flexible than <code>RelativeLayout</code> and easier to use with Android Studio's Layout Editor.
    -+</p>
    -+
    -+<p>Everything you can do with <code>ConstraintLayout</code> is available directly from the Layout Editor's visual
    -+tools, because the layout API and the Layout Editor were specially built for each other. So you can
    -+build your layout with <code>ConstraintLayout</code> entirely by drag-and-dropping instead of editing the XML.
    -+</p>
    -+
    -+<img src="/training/constraint-layout/images/layout-editor_2-2_2x.png" alt=""
    -+  width="640"/>
    -+<p class="img-caption"><b>Figure 1.</b> A <code>ConstraintLayout</code> in the Layout Editor</p>
    -+
    -+
    -+<p>
    -+<code>ConstraintLayout</code> is available in an API library that's compatible with Android
    -+2.3 (API level 9) and higher, and the new layout editor is available in Android
    -+Studio 2.2 and higher.
    -+</p>
    -+
    -+<p>
    -+This page provides a guide to building a layout with <code>ConstraintLayout</code> in Android
    -+Studio. If you'd like more information about the Layout Editor itself, see the
    -+Android Studio guide to <a href="/studio/write/layout-editor.html">Build a UI with
    -+Layout Editor</a>.
    -+</p>
    -+
    -+
    -+<h2 id="constraints-overview">Constraints overview</h2>
    -+<p>
    -+To define a view's position in <code>ConstraintLayout</code>, you must add two
    -+or more <em>constraints</em> for the view. Each constraint represents a connection or
    -+alignment to another view, the parent layout, or an invisible guideline. Each
    -+constraint defines the view's position along either the
    -+vertical or horizontal axis; so each view must have a minimum of one constraint for each
    -+axis, but often more are necessary.
    -+</p>
    -+
    -+<p>
    -+When you drop a view into the Layout Editor, it stays where you leave it even if
    -+it has no constraints. However, this is only to make editing easier; if a view has
    -+no constraints when you run your layout on a device, it is drawn at
    -+position [0,0] (the top-left corner).</p>
    -+
    -+<p>In figure 2, the layout looks good in the
    -+editor, but there's no vertical constraint on <code>TextView B</code>. When this
    -+layout draws on a device, <code>TextView B</code> horizontally aligns with the left and
    -+right edges of the <code>ImageView</code>, but appears at the top of the screen because
    -+it has no vertical constraint.
    -+</p>
    -+
    -+<div class="cols">
    -+<div class="col-1of2">
    -+<img src="/training/constraint-layout/images/constraint-fail_2x.png" width="100%" alt="" />
    -+<p class="img-caption"><strong>Figure 2.</strong> <code>TextView B</code> is missing a
    -+vertical constraint</p>
    -+</div>
    -+<div class="col-1of2">
    -+<img src="/training/constraint-layout/images/constraint-fail-fixed_2x.png" width="100%" alt="" />
    -+<p class="img-caption"><strong>Figure 3.</strong> <code>TextView B</code> is now vertically
    -+constrained to the <code>ImageView</code></p>
    -+</div>
    -+</div>
    -+
    -+<p>
    -+Although a missing constraint won't cause a compilation error, the Layout Editor
    -+indicates missing constraints as an error in the toolbar. To view the errors and
    -+other warnings, click <strong>Show Warnings and Errors</strong>
    -+<img src="/studio/images/buttons/layout-editor-errors.png" class="inline-icon" alt="" />.
    -+To help you avoid missing constraints, the Layout Editor can automatically add
    -+constraints for you with the <a
    -+href="#use-autoconnect-and-infer-constraints">Autoconnect and infer
    -+constraints</a> features.
    -+</p>
    -+
    -+
    -+<h2 id="add-constraintlayout-to-your-project">Add ConstraintLayout to your project</h2>
    -+<p>
    -+To use <code>ConstraintLayout</code> in your project, proceed as follows:
    -+</p>
    -+
    -+<ol>
    -+<li>Ensure you have the latest Constraint Layout library:
    -+<ol>
    -+ <li>Click <strong>Tools > Android > SDK Manager</strong>.
    -+ <li>Click the <strong>SDK Tools</strong> tab.
    -+ <li>Expand <strong>Support Repository</strong> and then check
    -+<b>ConstraintLayout for Android</b> and <b>Solver for ConstraintLayout</b>.
    -+Check <b>Show Package Details</b> and take note of the version you're downloading
    -+(you'll need this below).</p>
    -+ <li>Click <strong>OK</strong>.
    -+<li>Add the ConstraintLayout library as a dependency in your module-level
    -+  <code>build.gradle</code> file:
    -+<pre>
    -+dependencies {
    -+    compile 'com.android.support.constraint:constraint-layout:1.0.0-alpha8'
    -+}
    -+</pre>
    -+  <p>The library version you download may be higher, so be sure the value you specify
    -+  here matches the version from step 3.</p>
    -+</li>
    -+<li>In the toolbar or sync notification, click <strong>Sync Project with Gradle
    -+Files</strong>.</li>
    -+</ol>
    -+</li>
    -+</ol>
    -+
    -+<p>Now you're ready to build your layout with <code>ConstraintLayout</code>.</p>
    -+
    -+<h3 id="convert">Convert a layout</h3>
    -+
    -+<div class="figure" style="width:415px">
    -+<img src="/training/constraint-layout/images/layout-editor-convert-to-constraint_2x.png"
    -+  width="415" alt="" />
    -+<p class="img-caption">
    -+  <b>Figure 4.</b> The menu to convert a layout to <code>ConstraintLayout</code></p>
    -+</div>
    -+
    -+<p>To convert an existing layout to a constraint layout, follow these steps:</p>
    -+<ol>
    -+<li>Open your layout in Android Studio and click the <strong>Design</strong> tab
    -+at the bottom of the editor window.
    -+<li>In the <strong>Component Tree</strong> window, right-click the layout and
    -+click <strong>Convert <em>layout</em> to ConstraintLayout</strong>.</li>
    -+</ol>
    -+
    -+<h3 id="createNew">Create a new layout</h3>
    -+
    -+<p>To start a new constraint layout file, follow these steps:</p>
    -+<ol>
    -+<li>Click anywhere in the <strong>Project</strong> window and then select
    -+<strong>File > New > XML > Layout XML</strong>.
    -+<li>Enter a name for the layout file and enter
    -+"android.support.constraint.ConstraintLayout" for the <b>Root Tag</b>.
    -+<li>Click <strong>Finish</strong>.</li>
    -+</ol>
    -+
    -+
    -+<h2 id="add-a-constraint">Add a constraint</h2>
    -+
    -+<p>Start by dragging a view from the <b>Palette</b> window into the editor.
    -+When you add a view in a <code>ConstraintLayout</code>, it displays a bounding box with square
    -+resizing handles on each corner and circular constraint handles on each side.
    -+</p>
    -+
    -+
    -+<div class="figure" style="width:460px">
    -+<div class="video-wrapper">
    -+<video controls poster="/training/constraint-layout/images/thumbnail-studio-constraint-first.png"
    -+  onclick="this.play()" width="460">
    -+  <source src="https://storage.googleapis.com/androiddevelopers/videos/studio/studio-constraint-first.mp4" type="video/mp4">
    -+  <img src="/training/constraint-layout/images/thumbnail-studio-constraint-first" alt="" />
    -+</video>
    -+</div>
    -+<p class="img-caption">
    -+<strong>Video 1. </strong>The left side of a view is constrained to the left side of the parent
    -+</p>
    -+</div>
    -+
    -+<p>
    -+Click the view to select it. Then click-and-hold one of the
    -+constraint handles and drag the line to an available anchor point (the edge of
    -+another view, the edge of the layout, or a guideline). When you release, the
    -+constraint is made, with <a href="#adjust-the-view-margins">a default margin</a>
    -+separating the two views.
    -+</p>
    -+
    -+<p>When creating constraints, remember the following rules:</p>
    -+
    -+<ul>
    -+<li>Every view must have at least two constraints: one horizontal and one
    -+vertical.
    -+<li>You can create constraints only between a constraint handle and an anchor
    -+point that share the same plane. So a vertical plane (the left and right sides)
    -+of a view can be constrained only to another vertical plane; and baselines can
    -+constrain only to other baselines.
    -+<li>Each constraint handle can be used for just one constraint, but you can
    -+create multiple constraints (from different views) to the same anchor
    -+point.</li>
    -+</ul>
    -+
    -+
    -+
    -+<div class="figure" style="width:460px">
    -+<div class="video-wrapper">
    -+<video controls poster="/training/constraint-layout/images/thumbnail-studio-constraint-second.png"
    -+  onclick="this.play()" width="460">
    -+  <source src="https://storage.googleapis.com/androiddevelopers/videos/studio/studio-constraint-second.mp4" type="video/mp4">
    -+  <img src="/training/constraint-layout/images/thumbnail-studio-constraint-second.png" alt="" />
    -+</video>
    -+</div>
    -+<p class="img-caption">
    -+<strong>Video 2. </strong>Adding a constraint that opposes an existing one
    -+</p>
    -+</div>
    -+
    -+
    -+
    -+<p>
    -+To remove a constraint, select the view and then click the constraint handle.
    -+</p>
    -+
    -+<p>If you add opposing constraints on a view, the constraint lines become squiggly
    -+like a spring to indicate the opposing forces, as shown in video 2. The effect
    -+is most visible when the view size is set to "fixed" or "wrap content," in which
    -+case the view is centered between the constraints. If you instead
    -+want the view to stretch its size to meet the constraints, <a
    -+href="#adjust-the-view-size">switch the size to "any size"</a>; or if you want
    -+to keep the current size but move the view so that it is not centered, <a
    -+href="#adjust-the-constraint-bias">adjust the constraint bias</a>.
    -+</p>
    -+
    -+
    -+
    -+<p>
    -+There are many ways to constrain a view, but the following constraint types
    -+provide the basic building blocks.
    -+</p>
    -+
    -+
    -+
    -+
    -+<h3>Parent constraint</h3>
    -+<div class="cols">
    -+<div class="col-2of3">
    -+  <p>
    -+  Connect the side of a view to the corresponding edge of the layout.
    -+  <p>
    -+  In figure 5, the left side of a view is connected to the left edge of the
    -+  parent layout.
    -+  <p>
    -+</div>
    -+<div class="col-1of3">
    -+  <img src="/training/constraint-layout/images/parent-constraint_2x.png" width="100%" alt="">
    -+  <p class="img-caption"><strong>Figure 5. </strong>A horizontal constraint to the parent</p>
    -+</div>
    -+</div>
    -+
    -+
    -+<h3>Position constraint</h3>
    -+<div class="cols">
    -+<div class="col-2of3">
    -+<p>Define the order of appearance for two views, either vertically or horizontally.</p>
    -+<p>In figure 6, a <code>Button</code> is constrained below an <code>ImageView</code> with a 24dp
    -+margin.</p>
    -+</div>
    -+<div class="col-1of3">
    -+  <img src="/training/constraint-layout/images/position-constraint_2x.png" width="100%" alt="">
    -+  <p class="img-caption"><strong>Figure 6.</strong> A vertical position constraint</p>
    -+</div>
    -+</div>
    -+
    -+
    -+
    -+<h3>Alignment constraint</h3>
    -+<div class="cols">
    -+<div class="col-1of3">
    -+<p>Align the edge of a view to the same edge of another view.<p>
    -+<p>In figure 7, the left side of a <code>Button</code> is aligned to the left side of an
    -+<code>ImageView</code>.</p>
    -+<p>You can offset the alignment by dragging the view
    -+inward from the constraint. For example, figure 8 shows the same
    -+<code>Button</code> with a 24dp offset alignment.
    -+The offset is defined by the constrained view's margin.</p>
    -+</div>
    -+<div class="col-1of3">
    -+  <img src="/training/constraint-layout/images/alignment-constraint_2x.png" width="100%" alt="">
    -+  <p class="img-caption"><strong>Figure 7.</strong> A horizontal alignment constraint</p>
    -+</div>
    -+<div class="col-1of3">
    -+  <img src="/training/constraint-layout/images/alignment-constraint-offset_2x.png" width="100%"
    -+    alt="">
    -+  <p class="img-caption"><strong>Figure 8.</strong> An offset horizontal alignment constraint</p>
    -+</div>
    -+</div>
    -+
    -+
    -+<h3>Baseline alignment constraint</h3>
    -+<div class="cols">
    -+<div class="col-2of3">
    -+<p>Align the text baseline of a view to the text baseline of another view.</p>
    -+<p>In figure 9, the first line of a <code>TextView</code> is aligned with the text in a
    -+<code>Button</code>.</p>
    -+<p>To create a baseline constraint, hover your mouse over the baseline handle for
    -+two seconds until the handle blinks white. Then click and drag the line to
    -+another baseline.</p>
    -+</div>
    -+<div class="col-1of3">
    -+  <img src="/training/constraint-layout/images/baseline-constraint_2x.png" width="100%" alt="">
    -+  <p class="img-caption"><strong>Figure 9.</strong> A baseline alignment constraint</p>
    -+</div>
    -+</div>
    -+
    -+
    -+
    -+
    -+
    -+<h3 id="constrain-to-a-guideline">Constrain to a guideline</h3>
    -+<div class="cols">
    -+<div class="col-1of2">
    -+
    -+<p>
    -+You can add a vertical or horizontal guideline to which you can attach
    -+constraints. You can position the guideline within the layout based on either dp
    -+units or percent, relative to the layout's edge.
    -+</p>
    -+
    -+<p>
    -+To create a guideline, click <strong>Guidelines</strong>
    -+<img src="/studio/images/buttons/layout-editor-guidelines.png" class="inline-icon" alt="" />
    -+in the toolbar, and then click either <strong>Add Vertical Guideline</strong>
    -+or <strong>Add Horizontal Guideline</strong>.
    -+</p>
    -+
    -+<p>
    -+Click the circle at the edge of the guideline to toggle the measurements used to
    -+position the guideline (either percent or dp units from the layout's edge).
    -+</p>
    -+
    -+<p>
    -+Guidelines are not visible to your users.
    -+</p>
    -+</div>
    -+
    -+<div class="col-1of2">
    -+  <div class="video-wrapper">
    -+  <video controls poster="/training/constraint-layout/images/thumbnail-add-layout-guideline_2-2.png"
    -+    onclick="this.play()" width="100%">
    -+    <source src="https://storage.googleapis.com/androiddevelopers/videos/studio/add-layout-guideline_2-2.mp4" type="video/mp4">
    -+    <img src="/training/constraint-layout/images/thumbnail-add-layout-guideline_2-2.png" alt="" />
    -+  </video>
    -+  </div>
    -+  <p class="img-caption"><strong>Video 3.</strong> Adding a constraint to a guideline</p>
    -+</div>
    -+</div>
    -+
    -+
    -+<h2 id="use-autoconnect-and-infer-constraints">Use Autoconnect and Infer Constraints</h2>
    -+
    -+<div class="figure" style="width:460px">
    -+<div class="video-wrapper">
    -+<video controls poster=""
    -+  onclick="this.play()" width="460">
    -+  <source src="https://storage.googleapis.com/androiddevelopers/videos/studio/constraint-autoconnect_2-2.mp4" type="video/mp4">
    -+</video>
    -+</div>
    -+<p class="img-caption"><b>Video 4.</b> Adding a view with Autoconnect enabled</p>
    -+</div>
    -+
    -+<p>
    -+Autoconnect is a persistent mode that automatically creates two or more
    -+constraints for each view you add to the layout. Autoconnect is disabled by
    -+default. You can enable it by clicking <strong>Turn on Autoconnect</strong>
    -+<img src="/studio/images/buttons/layout-editor-autoconnect-on.png" class="inline-icon" alt="" />
    -+in the Layout Editor toolbar.
    -+</p>
    -+
    -+<p>While enabled, Autoconnect creates constraints for each view as you add them; it does not create
    -+constraints for existing views in the layout. If you drag a view once the constraints are made, the
    -+constraints do not change (though the margins do), so you must delete the constraints if you want to
    -+significantly reposition the view.</p>
    -+
    -+<p>Alternatively, you can click  <strong>Infer Constraints</strong>
    -+<img src="/studio/images/buttons/layout-editor-infer.png" class="inline-icon" alt="" />
    -+to create constraints for all views in the layout.
    -+</p>
    -+
    -+<p>Infer Constraints is a one-time action that scans the entire layout to determine the most
    -+effective set of constraints for all views, so it may create constraints between elements that are
    -+far from each other. Autoconnect, however, creates constraints only for the view you are adding, and
    -+it creates constraints to only the nearest elements. In either case, you can always modify a
    -+constraint by clicking the constraint handle to delete it, and then create a new constraint.</p>
    -+
    -+
    -+<h2 id="adjust-the-view-size">Adjust the view size</h2>
    -+
    -+<p>
    -+You can use the handles on each corner of the view to resize it, but doing so
    -+hard codes the width and height values, which you should avoid for most views
    -+because hard-coded view sizes cannot adapt to different content and screen
    -+sizes. To select from one of the dynamic sizing modes or to define more specific
    -+dimensions, click a view and open the <strong>Properties</strong>
    -+<img src="/studio/images/buttons/window-properties.png" class="inline-icon" alt="" />
    -+window on the right side of the editor. At the top of the window is the view
    -+inspector, as shown in figure 10.
    -+</p>
    -+<div class="figure" style="width:287px" >
    -+<img src="/training/constraint-layout/images/layout-editor-properties-callouts_2-2_2x.png" alt=""
    -+  width="287" />
    -+<p class="img-caption"><strong>Figure 10.</strong> The <b>Properties</b> window includes controls for
    -+<strong>(1)</strong> view size, <strong>(2)</strong> margins, and
    -+<strong>(3)</strong> constraint bias.</p>
    -+</div>
    -+
    -+<p>
    -+The grey square represents the selected view. The symbols inside the square
    -+represent the height and width settings as follows:
    -+</p>
    -+
    -+<ul>
    -+<li>
    -+<img src="/studio/images/buttons/layout-width-wrap.png" class="inline-icon" alt="" />
    -+ <strong>Wrap Content</strong>: The view expands exactly as needed to fit its
    -+contents.
    -+<li>
    -+<img src="/studio/images/buttons/layout-width-match.png" class="inline-icon" alt="" />
    -+ <strong>Any Size</strong>: The view expands exactly as needed to match the
    -+constraints. The actual value is 0dp because the view has no desired dimensions, but
    -+it resizes as needed to meet the constraints. However, if the given dimension
    -+has only one constraint, then the view expands to fit its contents. Another way
    -+to think of it is "match constraints" (instead of <code>match_parent</code>) because it
    -+expands the view as much as possible after accounting for the limits of each
    -+constraint and its margins.
    -+<li>
    -+<img src="/studio/images/buttons/layout-width-fixed.png" class="inline-icon" alt="" />
    -+ <strong>Fixed</strong>: You specify the dimension in the text box below or by
    -+resizing the view in the editor.</li>
    -+</ul>
    -+
    -+<p>To toggle between these settings, click the symbols.</p>
    -+
    -+<p class="note"><strong>Note</strong>: You should not use <code>match_parent</code> for any view
    -+in a <code>ConstraintLayout</code>. Instead use "Any Size" (<code>0dp</code>).
    -+</p>
    -+
    -+
    -+<h2 id="adjust-the-constraint-bias">Adjust the constraint bias</h2>
    -+
    -+<p>When you add a constraint to both sides of a view (and the view size for the same dimension is
    -+either "fixed" or "wrap content"), the view becomes centered between the two anchor points by
    -+default. When a view is centered, the bias is 50%. You can adjust the bias by dragging the bias
    -+slider in the <b>Properties</b> window or by dragging the view, as shown in video 5.</p>
    -+
    -+<div class="video-wrapper" style="max-width:740px">
    -+<video controls poster="/training/constraint-layout/images/thumbnail-adjust-constraint-bias.png"
    -+  onclick="this.play();$(this.parentElement).addClass('playing');">
    -+  <source src="https://storage.googleapis.com/androiddevelopers/videos/studio/adjust-constraint-bias.mp4" type="video/mp4">
    -+  <img src="/training/constraint-layout/images/thumbnail-adjust-constraint-bias.png" alt="" />
    -+</video>
    -+</div>
    -+<p class="img-caption"><b>Video 5.</b> Adjusting the constraint bias</p>
    -+
    -+<p>If you instead want the view to stretch its size to meet the constraints, <a href="#adjust-the-
    -+view-size">switch the size to "any size"</a>.</p>
    -+
    -+
    -+<h2 id="adjust-the-view-margins">Adjust the view margins</h2>
    -+
    -+<p> To ensure that all your views are evenly spaced, click <strong>Margin</strong> <img
    -+src="/studio/images/buttons/layout-editor-margin.png" class="inline-icon" alt="" /> in the toolbar
    -+to select the default margin for each view that you add to the layout. The button changes to show
    -+your current margin selection. Any change you make to the default margin applies only to the views
    -+you add from then on. </p>
    -+
    -+
    -+<img src="/training/constraint-layout/images/layout-editor-margin-callout_2-2_2x.png"
    -+ alt="" width="232"/>
    -+<p class="img-caption"><strong>Figure 11.</strong> The toolbar's <b>Margin</b> button.
    -+Click to adjust the default margin.
    -+</p>
    -+
    -+<p> You can control the margin for each view in the <strong>Properties</strong> window by clicking
    -+the number on the line that represents each constraint (in figure 10, the margins are each set to
    -+16dp). </p>
    -+
    -+<p> All margins offered by the tool are factors of 8dp to help your views align to Material Design's
    -+<a href="https://material.google.com/layout/metrics-keylines.html">8dp square grid
    -+recommendations</a>. </p>
    -+
    -+</body>
    -+</html>
    -diff --git a/docs/html/training/contacts-provider/display-contact-badge.jd b/docs/html/training/contacts-provider/display-contact-badge.jd
    -index d286440..6c9616b 100644
    ---- a/docs/html/training/contacts-provider/display-contact-badge.jd
    -+++ b/docs/html/training/contacts-provider/display-contact-badge.jd
    -@@ -113,10 +113,10 @@ trainingnavtop=true
    - <p>
    -     For Android 3.0 (API level 11) and later, include the following columns in your projection:</p>
    - <ul>
    --    <li>{@link android.provider.BaseColumns#_ID Contacts._ID}</li>
    --    <li>{@link android.provider.ContactsContract.ContactsColumns#LOOKUP_KEY Contacts.LOOKUP_KEY}</li>
    -+    <li>{@link android.provider.ContactsContract.Contacts#_ID Contacts._ID}</li>
    -+    <li>{@link android.provider.ContactsContract.Contacts#LOOKUP_KEY Contacts.LOOKUP_KEY}</li>
    -     <li>
    --        {@link android.provider.ContactsContract.ContactsColumns#PHOTO_THUMBNAIL_URI
    -+        {@link android.provider.ContactsContract.Contacts#PHOTO_THUMBNAIL_URI
    -         Contacts.PHOTO_THUMBNAIL_URI}
    -     </li>
    - </ul>
    -@@ -124,8 +124,8 @@ trainingnavtop=true
    -     For Android 2.3.3 (API level 10) and earlier, use the following columns:
    - </p>
    - <ul>
    --    <li>{@link android.provider.BaseColumns#_ID Contacts._ID}</li>
    --    <li>{@link android.provider.ContactsContract.ContactsColumns#LOOKUP_KEY Contacts.LOOKUP_KEY}</li>
    -+    <li>{@link android.provider.ContactsContract.Contacts#_ID Contacts._ID}</li>
    -+    <li>{@link android.provider.ContactsContract.Contacts#LOOKUP_KEY Contacts.LOOKUP_KEY}</li>
    - </ul>
    - <p>
    -     The remainder of this lesson assumes that you've already loaded a
    -@@ -187,14 +187,14 @@ trainingnavtop=true
    - </p>
    - <p class="note">
    -     <strong>Note:</strong> The
    --    {@link android.provider.ContactsContract.ContactsColumns#PHOTO_THUMBNAIL_URI} column isn't available
    -+    {@link android.provider.ContactsContract.Contacts#PHOTO_THUMBNAIL_URI} column isn't available
    -     in platform versions prior to 3.0. For those versions, you must retrieve the URI
    -     from the {@link android.provider.ContactsContract.Contacts.Photo Contacts.Photo} subtable.
    - </p>
    - <p>
    -     First, set up variables for accessing the {@link android.database.Cursor} containing the
    --    {@link android.provider.BaseColumns#_ID Contacts._ID} and
    --    {@link android.provider.ContactsContract.ContactsColumns#LOOKUP_KEY Contacts.LOOKUP_KEY} columns, as
    -+    {@link android.provider.ContactsContract.Contacts#_ID Contacts._ID} and
    -+    {@link android.provider.ContactsContract.Contacts#LOOKUP_KEY Contacts.LOOKUP_KEY} columns, as
    -     described previously:
    - </p>
    - <pre>
    -diff --git a/docs/html/training/contacts-provider/modify-data.jd b/docs/html/training/contacts-provider/modify-data.jd
    -index e993c56..64853ef 100644
    ---- a/docs/html/training/contacts-provider/modify-data.jd
    -+++ b/docs/html/training/contacts-provider/modify-data.jd
    -@@ -196,8 +196,8 @@ intent.putExtra(Intents.Insert.EMAIL, mEmailAddress.getText())
    -     Contacts.CONTENT_LOOKUP_URI}, call
    -     {@link android.provider.ContactsContract.Contacts#getLookupUri
    -     Contacts.getLookupUri(id, lookupkey)} with the contact's
    --    {@link android.provider.BaseColumns#_ID Contacts._ID} and
    --    {@link android.provider.ContactsContract.ContactsColumns#LOOKUP_KEY Contacts.LOOKUP_KEY} values as
    -+    {@link android.provider.ContactsContract.Contacts#_ID Contacts._ID} and
    -+    {@link android.provider.ContactsContract.Contacts#LOOKUP_KEY Contacts.LOOKUP_KEY} values as
    -     arguments.
    - </p>
    - <p>
    -diff --git a/docs/html/training/contacts-provider/retrieve-details.jd b/docs/html/training/contacts-provider/retrieve-details.jd
    -index a463b75..0de3b67 100644
    ---- a/docs/html/training/contacts-provider/retrieve-details.jd
    -+++ b/docs/html/training/contacts-provider/retrieve-details.jd
    -@@ -55,11 +55,11 @@ trainingnavtop=true
    - <p>
    -     To retrieve all the details for a contact, search the
    -     {@link android.provider.ContactsContract.Data} table for any rows that contain the contact's
    --    {@link android.provider.ContactsContract.ContactsColumns#LOOKUP_KEY}. This column is available in
    -+    {@link android.provider.ContactsContract.Data#LOOKUP_KEY}. This column is available in
    -     the {@link android.provider.ContactsContract.Data} table, because the Contacts
    -     Provider makes an implicit join between the {@link android.provider.ContactsContract.Contacts}
    -     table and the {@link android.provider.ContactsContract.Data} table. The
    --    {@link android.provider.ContactsContract.ContactsColumns#LOOKUP_KEY} column is described
    -+    {@link android.provider.ContactsContract.Contacts#LOOKUP_KEY} column is described
    -     in more detail in the <a href="retrieve-names.html">Retrieving Contact Names</a> lesson.
    - </p>
    - <p class="note">
    -@@ -85,9 +85,9 @@ trainingnavtop=true
    -     the data is in different columns depending on the data type.
    -     To ensure you get all the possible columns for all possible data types, you need to add all the
    -     column names to your projection. Always retrieve
    --    {@link android.provider.BaseColumns#_ID Data._ID} if you're binding the result
    -+    {@link android.provider.ContactsContract.Data#_ID Data._ID} if you're binding the result
    -     {@link android.database.Cursor} to a {@link android.widget.ListView}; otherwise, the binding
    --    won't work. Also retrieve {@link android.provider.ContactsContract.DataColumns#MIMETYPE Data.MIMETYPE}
    -+    won't work. Also retrieve {@link android.provider.ContactsContract.Data#MIMETYPE Data.MIMETYPE}
    -     so you can identify the data type of each row you retrieve. For example:
    - </p>
    - <pre>
    -@@ -128,7 +128,7 @@ trainingnavtop=true
    - <p>
    -     Define a constant for your selection clause, an array to hold selection arguments, and a
    -     variable to hold the selection value. Use
    --    the {@link android.provider.ContactsContract.ContactsColumns#LOOKUP_KEY Contacts.LOOKUP_KEY} column to
    -+    the {@link android.provider.ContactsContract.Contacts#LOOKUP_KEY Contacts.LOOKUP_KEY} column to
    -     find the contact. For example:
    - </p>
    - <pre>
    -@@ -153,7 +153,7 @@ trainingnavtop=true
    - <p>
    -     Define the sort order you want in the resulting {@link android.database.Cursor}. To
    -     keep all rows for a particular data type together, sort by
    --    {@link android.provider.ContactsContract.DataColumns#MIMETYPE Data.MIMETYPE}. This query argument
    -+    {@link android.provider.ContactsContract.Data#MIMETYPE Data.MIMETYPE}. This query argument
    -     groups all email rows together, all phone rows together, and so forth. For example:
    - </p>
    - <pre>
    -@@ -299,7 +299,7 @@ public class DetailsFragment extends Fragment implements
    -     </dt>
    -     <dd>
    -         Modify the selection text to search for the
    --        {@link android.provider.ContactsContract.DataColumns#MIMETYPE MIMETYPE} value that's specific to
    -+        {@link android.provider.ContactsContract.Data#MIMETYPE MIMETYPE} value that's specific to
    -         your data type.
    -     </dd>
    -     <dt>
    -@@ -307,7 +307,7 @@ public class DetailsFragment extends Fragment implements
    -     </dt>
    -     <dd>
    -         Since you're only selecting a single detail type, don't group the returned
    --        {@link android.database.Cursor} by {@link android.provider.ContactsContract.DataColumns#MIMETYPE
    -+        {@link android.database.Cursor} by {@link android.provider.ContactsContract.Data#MIMETYPE
    -         Data.MIMETYPE}.
    -     </dd>
    - </dl>
    -@@ -344,9 +344,9 @@ public class DetailsFragment extends Fragment implements
    - <h3>Define selection criteria</h3>
    - <p>
    -     Define a search text expression that retrieves rows for a specific contact's
    --    {@link android.provider.ContactsContract.ContactsColumns#LOOKUP_KEY} and the
    --    {@link android.provider.ContactsContract.DataColumns#MIMETYPE Data.MIMETYPE} of the details you
    --    want. Enclose the {@link android.provider.ContactsContract.DataColumns#MIMETYPE MIMETYPE} value in
    -+    {@link android.provider.ContactsContract.Data#LOOKUP_KEY} and the
    -+    {@link android.provider.ContactsContract.Data#MIMETYPE Data.MIMETYPE} of the details you
    -+    want. Enclose the {@link android.provider.ContactsContract.Data#MIMETYPE MIMETYPE} value in
    -     single quotes by concatenating a "<code>'</code>" (single-quote) character to the start and end
    -     of the constant; otherwise, the provider interprets the constant as a variable name rather
    -     than as a string value. You don't need to use a placeholder for this value, because you're
    -@@ -368,10 +368,10 @@ public class DetailsFragment extends Fragment implements
    - <h3>Define a sort order</h3>
    - <p>
    -     Define a sort order for the returned {@link android.database.Cursor}. Since you're retrieving a
    --    specific data type, omit the sort on {@link android.provider.ContactsContract.DataColumns#MIMETYPE}.
    -+    specific data type, omit the sort on {@link android.provider.ContactsContract.Data#MIMETYPE}.
    -     Instead, if the type of detail data you're searching includes a subtype, sort on it.
    -     For example, for email data you can sort on
    --    {@link android.provider.ContactsContract.CommonDataKinds.CommonColumns#TYPE Email.TYPE}:
    -+    {@link android.provider.ContactsContract.CommonDataKinds.Email#TYPE Email.TYPE}:
    - </p>
    - <pre>
    -     private static final String SORT_ORDER = Email.TYPE + " ASC ";
    -diff --git a/docs/html/training/contacts-provider/retrieve-names.jd b/docs/html/training/contacts-provider/retrieve-names.jd
    -index 7d70ceb..49d6e95 100755
    ---- a/docs/html/training/contacts-provider/retrieve-names.jd
    -+++ b/docs/html/training/contacts-provider/retrieve-names.jd
    -@@ -227,7 +227,7 @@ public class ContactsFragment extends Fragment implements
    - </pre>
    - <p class="note">
    -     <strong>Note:</strong> Since
    --    {@link android.provider.ContactsContract.ContactNameColumns#DISPLAY_NAME_PRIMARY
    -+    {@link android.provider.ContactsContract.Contacts#DISPLAY_NAME_PRIMARY
    -     Contacts.DISPLAY_NAME_PRIMARY} requires Android 3.0 (API version 11) or later, setting your
    -     app's <code>minSdkVersion</code> to 10 or below generates an Android Lint warning in
    -     Android Studio. To turn off this warning, add the annotation
    -@@ -261,7 +261,7 @@ public class ContactsFragment extends Fragment implements
    -     that displays the contacts, you need to call {@link android.app.Activity#findViewById
    -     Activity.findViewById()} using the parent activity of the
    -     {@link android.support.v4.app.Fragment}. Use the {@link android.content.Context} of the
    --    parent activity when you call {@link android.widget.AdapterView#setAdapter setAdapter()}.
    -+    parent activity when you call {@link android.widget.ListView#setAdapter setAdapter()}.
    -     For example:
    - </p>
    - <pre>
    -@@ -293,7 +293,7 @@ public class ContactsFragment extends Fragment implements
    - </p>
    - <p>
    -     To continue setting up the listener, bind it to the {@link android.widget.ListView} by
    --    calling the method {@link android.widget.AdapterView#setOnItemClickListener
    -+    calling the method {@link android.widget.ListView#setOnItemClickListener
    -     setOnItemClickListener()} in {@link android.support.v4.app.Fragment#onActivityCreated
    -     onActivityCreated()}. For example:
    - </p>
    -@@ -318,15 +318,15 @@ public class ContactsFragment extends Fragment implements
    -     the {@link android.widget.ListView} displays the contact's display name,
    -     which contains the main form of the contact's name. In Android 3.0 (API version 11) and later,
    -     the name of this column is
    --    {@link android.provider.ContactsContract.ContactNameColumns#DISPLAY_NAME_PRIMARY
    -+    {@link android.provider.ContactsContract.Contacts#DISPLAY_NAME_PRIMARY
    -     Contacts.DISPLAY_NAME_PRIMARY}; in versions previous to that, its name is
    --    {@link android.provider.ContactsContract.ContactsColumns#DISPLAY_NAME Contacts.DISPLAY_NAME}.
    -+    {@link android.provider.ContactsContract.Contacts#DISPLAY_NAME Contacts.DISPLAY_NAME}.
    - </p>
    - <p>
    --    The column {@link android.provider.BaseColumns#_ID Contacts._ID} is used by the
    -+    The column {@link android.provider.ContactsContract.Contacts#_ID Contacts._ID} is used by the
    -     {@link android.support.v4.widget.SimpleCursorAdapter} binding process.
    --    {@link android.provider.BaseColumns#_ID Contacts._ID} and
    --    {@link android.provider.ContactsContract.ContactsColumns#LOOKUP_KEY} are used together to
    -+    {@link android.provider.ContactsContract.Contacts#_ID Contacts._ID} and
    -+    {@link android.provider.ContactsContract.Contacts#LOOKUP_KEY} are used together to
    -     construct a content URI for the contact the user selects.
    - </p>
    - <pre>
    -@@ -635,7 +635,7 @@ public class ContactsFragment extends Fragment implements
    -     </li>
    -     <li>
    -         The name of the column that contains the custom MIME type value. This name is always
    --        {@link android.provider.ContactsContract.DataColumns#MIMETYPE Data.MIMETYPE}.
    -+        {@link android.provider.ContactsContract.Data#MIMETYPE Data.MIMETYPE}.
    -     </li>
    -     <li>
    -         The custom MIME type value for the data type. As described previously, this is the constant
    -diff --git a/docs/html/training/graphics/opengl/touch.jd b/docs/html/training/graphics/opengl/touch.jd
    -index 6a961da..089ede7 100644
    ---- a/docs/html/training/graphics/opengl/touch.jd
    -+++ b/docs/html/training/graphics/opengl/touch.jd
    -@@ -36,7 +36,7 @@ class="button">Download the sample</a>
    - getting some attention, but what if you want to have users interact with your OpenGL ES graphics?
    - The key to making your OpenGL ES application touch interactive is expanding your implementation of
    - {@link android.opengl.GLSurfaceView} to override the {@link
    --android.view.View#onTouchEvent onTouchEvent()} to listen for touch events.</p>
    -+android.opengl.GLSurfaceView#onTouchEvent onTouchEvent()} to listen for touch events.</p>
    - 
    - <p>This lesson shows you how to listen for touch events to let users rotate an OpenGL ES object.</p>
    - 
    -@@ -44,7 +44,7 @@ android.view.View#onTouchEvent onTouchEvent()} to listen for touch events.</p>
    - <h2 id="listener">Setup a Touch Listener</h2>
    - 
    - <p>In order to make your OpenGL ES application respond to touch events, you must implement the
    --{@link android.view.View#onTouchEvent onTouchEvent()} method in your
    -+{@link android.opengl.GLSurfaceView#onTouchEvent onTouchEvent()} method in your
    - {@link android.opengl.GLSurfaceView} class. The example implementation below shows how to listen for
    - {@link android.view.MotionEvent#ACTION_MOVE MotionEvent.ACTION_MOVE} events and translate them to
    - an angle of rotation for a shape.</p>
    -diff --git a/docs/html/training/implementing-navigation/nav-drawer.jd b/docs/html/training/implementing-navigation/nav-drawer.jd
    -index abc79b6..8aebd4b 100644
    ---- a/docs/html/training/implementing-navigation/nav-drawer.jd
    -+++ b/docs/html/training/implementing-navigation/nav-drawer.jd
    -@@ -148,7 +148,7 @@ public class MainActivity extends Activity {
    - }
    - </pre>
    - 
    --<p>This code also calls {@link android.widget.AdapterView#setOnItemClickListener
    -+<p>This code also calls {@link android.widget.ListView#setOnItemClickListener
    - setOnItemClickListener()} to receive click events in the navigation drawer's list.
    - The next section shows how to implement this interface
    - and change the content view when the user selects an item.</p>
    -@@ -160,7 +160,7 @@ and change the content view when the user selects an item.</p>
    - <p>When the user selects an item in the drawer's list, the system calls {@link
    - android.widget.AdapterView.OnItemClickListener#onItemClick onItemClick()} on the
    - {@link android.widget.AdapterView.OnItemClickListener OnItemClickListener} given to
    --{@link android.widget.AdapterView#setOnItemClickListener setOnItemClickListener()}.</p>
    -+{@link android.widget.ListView#setOnItemClickListener setOnItemClickListener()}.</p>
    - 
    - <p>What you do in the {@link
    - android.widget.AdapterView.OnItemClickListener#onItemClick onItemClick()} method
    -diff --git a/docs/html/training/location/display-address.jd b/docs/html/training/location/display-address.jd
    -index daa6fd3..088e926 100644
    ---- a/docs/html/training/location/display-address.jd
    -+++ b/docs/html/training/location/display-address.jd
    -@@ -7,11 +7,11 @@ trainingnavtop=true
    - 
    -     <h2>This lesson teaches you how to</h2>
    -     <ol>
    --      <li><a href="#connect">Get a Geographic Location</a></li>
    --      <li><a href="#fetch-address">Define an Intent Service to Fetch the
    --        Address</a></li>
    --      <li><a href="#start-intent">Start the Intent Service</a></li>
    --      <li><a href="#result-receiver">Receive the Geocoding Results</a></li>
    -+      <li><a href="#connect">Get a geographic location</a></li>
    -+      <li><a href="#fetch-address">Define an intent service to fetch the
    -+        address</a></li>
    -+      <li><a href="#start-intent">Start the intent service</a></li>
    -+      <li><a href="#result-receiver">Receive the geocoding results</a></li>
    -     </ol>
    - 
    -     <h2>You should also read</h2>
    -@@ -58,7 +58,7 @@ trainingnavtop=true
    -   convert a geographic location to an address. The method returns an estimated
    -   street address corresponding to a given latitude and longitude.</p>
    - 
    --<h2 id="connect">Get a Geographic Location</h2>
    -+<h2 id="connect">Get a geographic location</h2>
    - 
    - <p>The last known location of the device is a useful starting point for the
    -   address lookup feature. The lesson on
    -@@ -69,12 +69,12 @@ trainingnavtop=true
    -   <a href="{@docRoot}reference/com/google/android/gms/location/FusedLocationProviderApi.html">fused
    -   location provider</a> to find the latest location of the device.</p>
    - 
    --<p>To access the fused location provider, you need to create an instance of the
    -+<p>To access the fused location provider, create an instance of the
    -   Google Play services API client. To learn how to connect your client, see
    -   <a href="{@docRoot}training/location/retrieve-current.html#play-services">Connect
    -   to Google Play Services</a>.</p>
    - 
    --<p>In order for the fused location provider to retrieve a precise street
    -+<p>To enable the fused location provider to retrieve a precise street
    -   address, set the location permission in your app manifest to
    -   {@code ACCESS_FINE_LOCATION}, as shown in the following example:</p>
    - 
    -@@ -86,12 +86,12 @@ trainingnavtop=true
    - &lt;/manifest&gt;
    - </pre>
    - 
    --<h2 id="fetch-address">Define an Intent Service to Fetch the Address</h2>
    -+<h2 id="fetch-address">Define an intent service to fetch the address</h2>
    - 
    - <p>The {@link android.location.Geocoder#getFromLocation getFromLocation()}
    -   method provided by the {@link android.location.Geocoder} class accepts a
    --  latitude and longitude, and returns a list of addresses. The method is
    --  synchronous, and may take a long time to do its work, so you should not call
    -+  latitude and longitude and returns a list of addresses. The method is
    -+  synchronous and may take a long time to do its work, so you should not call
    -   it from the main, user interface (UI) thread of your app.</p>
    - 
    - <p>The {@link android.app.IntentService IntentService} class provides a
    -@@ -100,23 +100,23 @@ trainingnavtop=true
    -   Note that the {@link android.os.AsyncTask AsyncTask} class also allows you to
    -   perform background operations, but it's designed for short operations. An
    -   {@link android.os.AsyncTask AsyncTask} shouldn't keep a reference to the UI if
    --  the activity is recreated, for example when the device is rotated. In
    -+  the activity is re-created, such as when the device is rotated. In
    -   contrast, an {@link android.app.IntentService IntentService} doesn't need to
    -   be cancelled when the activity is rebuilt.</p>
    - 
    - <p>Define a {@code FetchAddressIntentService} class that extends
    -   {@link android.app.IntentService}. This class is your address lookup service.
    --  The intent service handles an intent asynchronously on a worker thread, and
    -+  The intent service handles an intent asynchronously on a worker thread and
    -   stops itself when it runs out of work. The intent extras provide the data
    -   needed by the service, including a {@link android.location.Location} object
    --  for conversion to an address, and a {@link android.os.ResultReceiver} object
    -+  for conversion to an address and a {@link android.os.ResultReceiver} object
    -   to handle the results of the address lookup. The service uses a {@link
    --  android.location.Geocoder} to fetch the address for the location, and sends
    -+  android.location.Geocoder} to fetch the address for the location and sends
    -   the results to the {@link android.os.ResultReceiver}.</p>
    - 
    --<h3>Define the Intent Service in your App Manifest</h3>
    -+<h3>Define the intent service in your app manifest</h3>
    - 
    --<p>Add an entry to your app manifest defining the intent service:</p>
    -+<p>Add an entry to your app manifest that defines the intent service, as shown here:</p>
    - 
    - <pre>
    - &lt;manifest xmlns:android="http://schemas.android.com/apk/res/android"
    -@@ -131,26 +131,26 @@ trainingnavtop=true
    - &lt;/manifest&gt;
    - </pre>
    - 
    --<p class="note"><strong>Note:</strong> The {@code <service>} element in
    --  the manifest doesn't need to include an intent filter, because your main
    -+<p class="note"><strong>Note:</strong> The {@code &lt;service&gt;} element in
    -+  the manifest doesn't need to include an intent filter because your main
    -   activity creates an explicit intent by specifying the name of the class to use
    -   for the intent.</p>
    - 
    --<h3>Create a Geocoder</h3>
    -+<h3>Create a geocoder</h3>
    - 
    - <p>The process of converting a geographic location to an address is called
    --  <em>reverse geocoding</em>. To perform the main work of the intent service,
    --  that is, your reverse geocoding request, implement
    -+  <em>reverse geocoding</em>. To perform the main work of the intent service (your reverse
    -+  geocoding request), implement
    -   {@link android.app.IntentService#onHandleIntent onHandleIntent()} within the
    -   {@code FetchAddressIntentService} class. Create a
    -   {@link android.location.Geocoder} object to handle the reverse geocoding.</p>
    - 
    - <p>A locale represents a specific geographical or linguistic region. Locale
    --  objects are used to adjust the presentation of information, such as numbers or
    --  dates, to suit the conventions in the region represented by the locale. Pass a
    -+  objects adjust the presentation of information, such as numbers or
    -+  dates, to suit the conventions in the region that is represented by the locale. Pass a
    -   <a href="{@docRoot}reference/java/util/Locale.html">{@code Locale}</a> object
    --  to the {@link android.location.Geocoder} object, to ensure that the resulting
    --  address is localized to the user's geographic region.</p>
    -+  to the {@link android.location.Geocoder} object to ensure that the resulting
    -+  address is localized to the user's geographic region. Here is an example:</p>
    - 
    - <pre>
    - &#64;Override
    -@@ -162,7 +162,7 @@ protected void onHandleIntent(Intent intent) {
    - 
    - <h3 id="retrieve-street-address">Retrieve the street address data</h3>
    - 
    --<p>The next step is to retrieve the street address from the geocoder, handle
    -+<p>You can now retrieve the street address from the geocoder, handle
    -   any errors that may occur, and send the results back to the activity that
    -   requested the address. To report the results of the geocoding
    -   process, you need two numeric constants that indicate success or failure.
    -@@ -185,32 +185,34 @@ public final class Constants {
    - 
    - <p>To get a street address corresponding to a geographical location, call
    -   {@link android.location.Geocoder#getFromLocation getFromLocation()},
    --  passing it the latitude and longitude from the location object, and the
    --  maximum number of addresses you want returned. In this case, you want just one
    --  address. The geocoder returns an array of addresses. If no addresses were
    -+  passing it the latitude and longitude from the location object and the
    -+  maximum number of addresses that you want returned. In this case, you want just one
    -+  address. The geocoder returns an array of addresses. If no addresses are
    -   found to match the given location, it returns an empty list. If there is no
    -   backend geocoding service available, the geocoder returns null.</p>
    - 
    --<p>Check for the following errors as shown in the code sample below. If an error
    --  occurs, place the corresponding error message in the {@code errorMessage}
    --  variable, so you can send it back to the requesting activity:</p>
    -+<p>Check for the following errors, as shown in the code sample below:</p>
    - 
    - <ul>
    --  <li><strong>No location data provided</strong> - The intent extras do not
    --    include the {@link android.location.Location} object required for reverse
    -+  <li><strong>No location data provided</strong> &ndash; The intent extras do not
    -+    include the {@link android.location.Location} object that is required for reverse
    -     geocoding.</li>
    --  <li><strong>Invalid latitude or longitude used</strong> - The latitude
    --    and/or longitude values provided in the {@link android.location.Location}
    -+  <li><strong>Invalid latitude or longitude used</strong> &ndash; The latitude
    -+    and/or longitude values that are provided in the {@link android.location.Location}
    -     object are invalid.</li>
    --  <li><strong>No geocoder available</strong> - The background geocoding service
    --    is not available, due to a network error or IO exception.</li>
    --  <li><strong>Sorry, no address found</strong> - The geocoder could not find an
    -+  <li><strong>No geocoder available</strong> &ndash; The background geocoding service
    -+    is not available due to a network error or IO exception.</li>
    -+  <li><strong>Sorry, no address found</strong> &ndash; The geocoder can't find an
    -     address for the given latitude/longitude.</li>
    - </ul>
    - 
    -+<p>If an error
    -+  occurs, place the corresponding error message in the {@code errorMessage}
    -+  variable so that you can send it back to the requesting activity.
    -+
    - <p>To get the individual lines of an address object, use the
    -   {@link android.location.Address#getAddressLine getAddressLine()}
    --  method provided by the {@link android.location.Address} class. Then join the
    -+  method that is provided by the {@link android.location.Address} class. Join the
    -   lines into a list of address fragments ready to return to the activity that
    -   requested the address.</p>
    - 
    -@@ -220,7 +222,7 @@ public final class Constants {
    -   results consist of the previously-mentioned numeric success/failure code and
    -   a string. In the case of a successful reverse geocoding, the string contains
    -   the address. In the case of a failure, the string contains the error message,
    --  as shown in the code sample below:</p>
    -+  as shown in this code sample:</p>
    - 
    - <pre>
    - &#64;Override
    -@@ -280,18 +282,18 @@ protected void onHandleIntent(Intent intent) {
    - 
    - <h3 id="return-address">Return the address to the requestor</h3>
    - 
    --<p>The final thing the intent service must do is send the address back to a
    -+<p>The final action that the intent service must complete is sending the address back to a
    -   {@link android.os.ResultReceiver} in the activity that started the service.
    -   The {@link android.os.ResultReceiver} class allows you to send a
    -   numeric result code as well as a message containing the result data. The
    -   numeric code is useful for reporting the success or failure of the geocoding
    -   request. In the case of a successful reverse geocoding, the message contains
    -   the address. In the case of a failure, the message contains some text
    --  describing the reason for failure.</p>
    -+  describing the reason for the failure.</p>
    - 
    - <p>You have already retrieved the address from the geocoder, trapped any errors
    --  that may occur, and called the {@code deliverResultToReceiver()} method. Now
    --  you need to define the {@code deliverResultToReceiver()} method that sends
    -+  that may occur, and called the {@code deliverResultToReceiver()} method, so now
    -+  you must define the {@code deliverResultToReceiver()} method that sends
    -   a result code and message bundle to the result receiver.</p>
    - 
    - <p>For the result code, use the value that you've passed to the
    -@@ -299,7 +301,7 @@ protected void onHandleIntent(Intent intent) {
    -   To construct the message bundle, concatenate the {@code RESULT_DATA_KEY}
    -   constant from your {@code Constants} class (defined in
    -   <a href="#retrieve-street-address">Retrieve the street address data</a>) and
    --  the value in the {@code message} parameter passed to the
    -+  the value in the {@code message} parameter that is passed to the
    -   {@code deliverResultToReceiver()} method, as shown in the following sample:
    - </p>
    - 
    -@@ -315,26 +317,26 @@ public class FetchAddressIntentService extends IntentService {
    - }
    - </pre>
    - 
    --<h2 id="start-intent">Start the Intent Service</h2>
    -+<h2 id="start-intent">Start the intent service</h2>
    - 
    - <p>The intent service, as defined in the previous section, runs in the
    --  background and is responsible for fetching the address corresponding to a
    -+  background and fetches the address corresponding to a
    -   given geographic location. When you start the service, the Android framework
    --  instantiates and starts the service if it isn't already running, and creates a
    --  process if needed. If the service is already running then it remains running.
    -+  instantiates and starts the service if it isn't already running, and it creates a
    -+  process if needed. If the service is already running, it remains running.
    -   Because the service extends {@link android.app.IntentService IntentService},
    --  it shuts down automatically when all intents have been processed.</p>
    -+  it shuts down automatically after all intents are processed.</p>
    - 
    --<p>Start the service from your app's main activity,
    -+<p>Start the service from your app's main activity
    -   and create an {@link android.content.Intent} to pass data to the service. You
    --  need an <em>explicit</em> intent, because you want only your service
    -+  need an <em>explicit</em> intent because you want only your service
    -   to respond to the intent. For more information, see
    -   <a href="{@docRoot}guide/components/intents-filters.html#Types">Intent
    -   Types</a>.</p>
    - 
    - <p>To create an explicit intent, specify the name of the
    -   class to use for the service: {@code FetchAddressIntentService.class}.
    --  Pass two pieces of information in the intent extras:</p>
    -+  Pass this information in the intent extras:</p>
    - 
    - <ul>
    -   <li>A {@link android.os.ResultReceiver} to handle the results of the address
    -@@ -362,6 +364,12 @@ public class MainActivity extends ActionBarActivity implements
    - }
    - </pre>
    - 
    -+<p class="caution"><strong>Caution</strong>: To ensure that your app is secure, always use an
    -+explicit intent when starting a {@link android.app.Service} and do not declare intent filters for
    -+your services. Using an implicit intent to start a service is a security hazard because you cannot
    -+be certain of the service that will respond to the intent, and the user cannot see which service
    -+starts.</p>
    -+
    - <p>Call the above {@code startIntentService()} method when the
    -   user takes an action that requires a geocoding address lookup. For example,
    -   the user may press a <em>Fetch address</em> button on your app's UI. Before
    -@@ -391,7 +399,7 @@ public void fetchAddressButtonHandler(View view) {
    -   app's UI. The following code snippet shows the call to the
    -   {@code startIntentService()} method in the
    -   <a href="{@docRoot}reference/com/google/android/gms/common/api/GoogleApiClient.ConnectionCallbacks.html#onConnected(android.os.Bundle)">{@code onConnected()}</a>
    --  callback provided by the Google API Client:</p>
    -+  callback that is provided by the Google API Client:</p>
    - 
    - <pre>
    - public class MainActivity extends ActionBarActivity implements
    -@@ -420,9 +428,9 @@ public class MainActivity extends ActionBarActivity implements
    - }
    - </pre>
    - 
    --<h2 id="result-receiver">Receive the Geocoding Results</h2>
    -+<h2 id="result-receiver">Receive the geocoding results</h2>
    - 
    --<p>The intent service has handled the geocoding request, and uses a
    -+<p>After the intent service handles the geocoding request, it uses a
    -   {@link android.os.ResultReceiver} to return the results to the activity that
    -   made the request. In the activity that makes the request, define an
    -   {@code AddressResultReceiver} that extends {@link android.os.ResultReceiver}
    -@@ -430,14 +438,14 @@ public class MainActivity extends ActionBarActivity implements
    - 
    - <p>The result includes a numeric result code (<code>resultCode</code>) as well
    -   as a message containing the result data (<code>resultData</code>). If the
    --  reverse geocoding process was successful, the <code>resultData</code> contains
    -+  reverse geocoding process is successful, the <code>resultData</code> contains
    -   the address. In the case of a failure, the <code>resultData</code> contains
    --  text describing the reason for failure. For details of the possible errors,
    -+  text describing the reason for the failure. For details of the possible errors,
    -   see <a href="#return-address">Return the address to the requestor</a>.</p>
    - 
    - <p>Override the
    -   {@link android.os.ResultReceiver#onReceiveResult onReceiveResult()} method
    --  to handle the results delivered to the result receiver, as shown in the
    -+  to handle the results that are delivered to the result receiver, as shown in the
    -   following code sample:</p>
    - 
    - <pre>
    -diff --git a/docs/html/training/location/geofencing.jd b/docs/html/training/location/geofencing.jd
    -index ce6ad55..046e99e 100644
    ---- a/docs/html/training/location/geofencing.jd
    -+++ b/docs/html/training/location/geofencing.jd
    -@@ -332,22 +332,39 @@ LocationServices.GeofencingApi.removeGeofences(
    - <p>This section outlines recommendations for using geofencing with the location
    - APIs for Android.</p>
    - 
    --<h3>Reduce power consumption</h3>
    -+<h3>
    -+  Reduce power consumption
    -+</h3>
    - 
    --<p>You can use the following techniques to optimize power consumption in your apps that use geofencing:</p>
    -+<p>
    -+  You can use the following techniques to optimize power consumption in your
    -+  apps that use geofencing:
    -+</p>
    - 
    - <ul>
    --<li><p>Set the <a href="{@docRoot}android/reference/com/google/android/gms/location/Geofence.Builder.html#setNotificationResponsiveness(int)">
    --notification responsiveness</a> to a higher value. Doing so improves power consumption by
    --increasing the latency of geofence alerts. For example, if you set a responsiveness value of five
    --minutes your app only checks for an entrance or exit alert once every five minutes.
    --Setting lower values does not necessarily mean that users will be notified within that time period
    --(for example, if you set a value of 5 seconds it may take a bit longer than that to receive the
    --alert).</p></li>
    --<li><p>Use a larger geofence radius for locations where a user spends a significant amount of time,
    --such as home or work. While a larger radius doesn't directly reduce power consumption, it reduces
    --the frequency at which the app checks for entrance or exit, effectively lowering overall power
    --consumption.</p></li>
    -+  <li>
    -+    <p>
    -+      Set the <a href=
    -+      "https://developers.google.com/android/reference/com/google/android/gms/location/Geofence.Builder.html#setNotificationResponsiveness(int)">
    -+      notification responsiveness</a> to a higher value. Doing so improves
    -+      power consumption by increasing the latency of geofence alerts. For
    -+      example, if you set a responsiveness value of five minutes your app only
    -+      checks for an entrance or exit alert once every five minutes. Setting
    -+      lower values does not necessarily mean that users will be notified
    -+      within that time period (for example, if you set a value of 5 seconds it
    -+      may take a bit longer than that to receive the alert).
    -+    </p>
    -+  </li>
    -+
    -+  <li>
    -+    <p>
    -+      Use a larger geofence radius for locations where a user spends a
    -+      significant amount of time, such as home or work. While a larger radius
    -+      doesn't directly reduce power consumption, it reduces the frequency at
    -+      which the app checks for entrance or exit, effectively lowering overall
    -+      power consumption.
    -+    </p>
    -+  </li>
    - </ul>
    - 
    - <h3>Choose the optimal radius for your geofence</h3>
    -diff --git a/docs/html/training/material/images/palette-library-color-profiles_2-1_2x.png b/docs/html/training/material/images/palette-library-color-profiles_2-1_2x.png
    -new file mode 100644
    -index 0000000..d14ec32
    -Binary files /dev/null and b/docs/html/training/material/images/palette-library-color-profiles_2-1_2x.png differ
    -diff --git a/docs/html/training/material/images/palette-library-title-text-color_2-1_2x.png b/docs/html/training/material/images/palette-library-title-text-color_2-1_2x.png
    -new file mode 100644
    -index 0000000..883adba
    -Binary files /dev/null and b/docs/html/training/material/images/palette-library-title-text-color_2-1_2x.png differ
    -diff --git a/docs/html/training/material/index.jd b/docs/html/training/material/index.jd
    -index 4001e6b..8baa065 100644
    ---- a/docs/html/training/material/index.jd
    -+++ b/docs/html/training/material/index.jd
    -@@ -3,7 +3,6 @@ page.type=design
    - page.image=images/cards/material_2x.png
    - page.metaDescription=Learn how to apply material design to your apps.
    - 
    --
    - @jd:body
    - 
    - <div id="tb-wrapper">
    -@@ -58,6 +57,9 @@ specification</a> and use the new components and functionality available in Andr
    - 
    -   <dt><a href="{@docRoot}training/material/compatibility.html">Maintaining Compatibility</a></dt>
    -   <dd>Learn how to maintain compatibility with platform versions earlier than Android 5.0.</dd>
    -+
    -+  <dt><a href="{@docRoot}training/material/palette-colors.html">Selecting Colors with the Palette API</a></dt>
    -+  <dd>Learn how to select colors for your app using the v7 Palette library.</dd>
    - </dl>
    - 
    - <h2>Video Training</h2>
    -diff --git a/docs/html/training/material/palette-colors.html b/docs/html/training/material/palette-colors.html
    -new file mode 100644
    -index 0000000..27485d2
    ---- /dev/null
    -+++ b/docs/html/training/material/palette-colors.html
    -@@ -0,0 +1,310 @@
    -+<html devsite>
    -+<head>
    -+  <title>Selecting Colors with the Palette API</title>
    -+  <meta name="book_path" value="/training/_book.yaml" />
    -+  <meta name="top_category" value="develop" />
    -+  <meta name="subcategory" value="training" />
    -+</head>
    -+<body>
    -+
    -+<div id="tb-wrapper">
    -+  <div id="tb">
    -+    <h2>This lesson teaches you to</h2>
    -+    <ol>
    -+      <li><a href="#set-up-the-library">Set up the library</a></li>
    -+      <li><a href="#create-a-palette">Create a palette</a>
    -+        <ol>
    -+          <li><a href="#generate-a-palette-instance">Generate a Palette instance</a></li>
    -+          <li><a href="#customize-your-palette">Customize your palette</a></li>
    -+        </ol>
    -+      </li>
    -+      <li><a href="#extract-color-profiles">Extract color profiles</a>
    -+        <ol>
    -+          <li><a href="#use-swatches">Use swatches to create color schemes</a></li>
    -+        </ol>
    -+      </li>
    -+    </ol>
    -+    <h2>You should also read</h2>
    -+    <ul>
    -+      <li><a href="http://www.google.com/design/spec">Material design specification</a></li>
    -+      <li><a href="/design/material/index.html">Material design on Android</a></li>
    -+    </ul>
    -+  </div>
    -+</div>
    -+
    -+<p>Good visual design is essential for a successful app, and color schemes are a primary component of design. The palette library is a
    -+<a href="/topic/libraries/support-library/features.html#v7-palette">support library</a>
    -+that extracts prominent colors from images to help you create visually engaging apps.</p>
    -+
    -+<p>You can use the palette library to design layout
    -+<a href="/guide/topics/ui/themes.html">themes</a> and apply custom colors to visual elements in your app.
    -+For example, you can use a palette to create a color-coordinated title 
    -+card for a song based on its album cover or to adjust an app’s toolbar color when its 
    -+background image changes. The <code><a 
    -+href="/reference/android/support/v7/graphics/Palette.html">Palette</a></code> object gives 
    -+you access to the colors in a <code><a
    -+href="/reference/android/graphics/Bitmap.html">Bitmap</a></code> 
    -+image while also providing six main color profiles from the bitmap to help
    -+inform your <a href="http://material.google.com">design choices</a>.</p>
    -+
    -+<h2 id="set-up-the-library">Set up the library</h2>
    -+
    -+<p>To use the palette library, install or update the <a
    -+href="/topic/libraries/support-library/index.html">Android
    -+Support Library</a> to version 24.0.0 or higher and follow the instructions for <a
    -+href="/topic/libraries/support-library/setup.html#add-library">Adding
    -+Support Libraries</a> to add the palette library to your app development project.</p>
    -+
    -+<p>Make sure that the version specified in your dependency identifier matches your
    -+app’s <code>compileSdkVersion</code>, set in the <code>build.gradle</code>
    -+file:</p>
    -+
    -+<pre class="prettyprint">
    -+android {
    -+  compileSdkVersion 24
    -+  ...
    -+}
    -+
    -+dependencies {
    -+  ...
    -+  compile 'com.android.support:palette-v7:24.2.1'
    -+}
    -+</pre>
    -+
    -+<p>For more information about adding the palette dependency, read about the palette
    -+feature in the <a
    -+href="/topic/libraries/support-library/features.html#v7-palette">support
    -+library documentation</a>.</p>
    -+
    -+<h2 id="create-a-palette">Create a palette</h2>
    -+
    -+<p>A <code>Palette</code> object gives you access to the primary colors in an
    -+image, as well as the corresponding colors for overlaid text. Use palettes to design
    -+your app’s style and to dynamically change your app’s color scheme based on a
    -+given source image.</p>
    -+
    -+<p>To create a palette, first instantiate a <code><a
    -+href="https://developer.android.com/reference/android/support/v7/graphics/Palette.Builder.html">Palette.Builder</a></code>
    -+from a <code>Bitmap</code>. You can then use the
    -+<code>Palette.Builder</code> to customize the palette before generating it. This
    -+section will describe palette generation and customization from a bitmap
    -+image.</p>
    -+
    -+<h3 id="generate-a-palette-instance">Generate a Palette instance</h3>
    -+
    -+<p>Generate a <code>Palette</code> instance using <code>Palette</code>’s
    -+<code><a
    -+href="/reference/android/support/v7/graphics/Palette.html#from(android.graphics.Bitmap)">from(Bitmap
    -+bitmap)</a></code> method to first create a <code>Palette.Builder</code>
    -+from a <code>Bitmap</code>. The builder can then generate the palette either
    -+synchronously or asynchronously.</p>
    -+
    -+<p>Use synchronous palette generation if you want to create the palette on
    -+the same thread as the method being called. If you generate the palette
    -+asynchronously on a different thread, use the <code><a
    -+href="/reference/android/support/v7/graphics/Palette.PaletteAsyncListener.html#onGenerated(android.support.v7.graphics.Palette)">onGenerated()</a></code>
    -+method to access the palette immediately after it has been created.</p>
    -+
    -+<p>The following code snippet provides example methods for both types of palette generation:</p>
    -+
    -+<pre class="prettyprint">
    -+// Generate palette synchronously and return it
    -+public Palette createPaletteSync(Bitmap bitmap) {
    -+  Palette p = Palette.from(bitmap).generate();
    -+  return p;
    -+}
    -+
    -+// Generate palette asynchronously and use it on a different
    -+// thread using onGenerated()
    -+public void createPaletteAsync(Bitmap bitmap) {
    -+  Palette.from(bitmap).generate(new PaletteAsyncListener() {
    -+    public void onGenerated(Palette p) {
    -+      // Use generated instance
    -+    }
    -+  });
    -+}
    -+</pre>
    -+
    -+<p>If you need to continuously generate palettes for a sorted list of images
    -+or objects, consider <a
    -+href="/reference/android/util/LruCache.html">caching</a>
    -+the <code>Palette</code> instances to prevent slow UI performance. You also
    -+should not create the palettes on your <a href="/training/articles/perf-anr.html">main thread</a>.</p>
    -+
    -+<h3 id="customize-your-palette">Customize your palette</h3>
    -+
    -+<p>The <code>Palette.Builder</code> allows you to customize your palette by
    -+choosing how many colors are in the resulting palette, what area of your
    -+image the builder uses to generate the palette, and what colors are allowed in the
    -+palette. For example, you can filter out the color black or ensure that the
    -+builder only uses the top half of an image to generate your palette.</p>
    -+
    -+<p>Fine-tune your palette’s size and colors with the following methods from
    -+the <code>Palette.Builder</code> class:</p>
    -+
    -+<dl>
    -+
    -+  <dt><code><a 
    -+  href="/reference/android/support/v7/graphics/Palette.Builder.html#addFilter(android.support.v7.graphics.Palette.Filter)">addFilter()</a></code></dt>
    -+  <dd>This method adds a filter that indicates what colors are allowed in the
    -+  resulting palette. Pass in your own<code> <a
    -+  href="/reference/android/support/v7/graphics/Palette.Filter.html">Palette.Filter</a></code>
    -+  and modify its <code>isAllowed()</code> method to determine which colors are
    -+  filtered from the palette.</dd>
    -+
    -+  <dt><code><a
    -+  href="/reference/android/support/v7/graphics/Palette.Builder.html#maximumColorCount(int)">maximumColorCount()</a></code></dt>
    -+  <dd>This method sets the maximum number of colors in your palette. The
    -+  default value is 16, and the optimal value depends on the source image. 
    -+  For landscapes, optimal values range from 8-16 while pictures with faces 
    -+  usually have values that fall between 24-32. The
    -+  <code>Palette.Builder</code> takes longer to generate palettes with more
    -+  colors.</dd>
    -+
    -+  <dt><code><a 
    -+  href="/reference/android/support/v7/graphics/Palette.Builder.html#setRegion(int,%20int,%20int,%20int)">setRegion()</a></code></dt>
    -+  <dd>This method indicates what area of the bitmap the builder uses when
    -+  creating the palette. You can only use this method when generating the palette from
    -+  a bitmap, and it does not affect the original image.</dd>
    -+
    -+  <dt><code><a
    -+  href="/reference/android/support/v7/graphics/Palette.Builder.html#addTarget(android.support.v7.graphics.Target)">addTarget()</a></code></dt>
    -+  <dd>This method allows you to perform your own color matching by adding a
    -+  <code><a
    -+  href="/reference/android/support/v7/graphics/Target.html">Target</a></code>
    -+  color profile to the builder. If the default <code>Target</code>s are not
    -+  sufficient, advanced developers can create their own <code>Target</code>s
    -+  using a <code><a
    -+  href="/reference/android/support/v7/graphics/Target.Builder.html">Target.Builder</a></code>.</dd>
    -+
    -+</dl>
    -+
    -+<h2 id="extract-color-profiles">Extract color profiles</h2>
    -+
    -+<p>Based on the <a
    -+href="https://material.google.com/style/color.html#">standards
    -+of material design</a>, the palette library extracts commonly used color
    -+profiles from an image. Each profile is defined by a <code><a
    -+href="/reference/android/support/v7/graphics/Target.html">Target</a></code>,
    -+and colors extracted from the bitmap image are scored against each profile
    -+based on saturation, luminance, and population (number of pixels in the bitmap
    -+represented by the color). For each profile, the color with the best score
    -+defines that color profile for the given image.</p>
    -+
    -+<p>By default, a <code>Palette</code> object contains 16 primary colors from
    -+a given image. When generating your palette, you can <a
    -+href="#customize-your-palette">customize</a> its number of colors using the
    -+<code>Palette.Builder</code>. Extracting more colors provides more potential
    -+matches for each color profile but also causes <code>Palette.Builder</code> to
    -+take longer when generating the palette.</p>
    -+
    -+<p>The palette library attempts to extract the following six color
    -+profiles:</p>
    -+
    -+<ul>
    -+  <li>Light Vibrant</li>
    -+  <li>Vibrant</li>
    -+  <li>Dark Vibrant</li>
    -+  <li>Light Muted</li>
    -+  <li>Muted</li>
    -+  <li>Dark Muted</li>
    -+</ul>
    -+
    -+<p>Each of <code>Palette</code>’s <code>get&lt;<em>Profile</em>&gt;Color()</code>
    -+methods returns the color in the palette associated with that particular profile,
    -+where <code>&lt;<em>Profile</em>&gt;</code> is replaced by the name of one of the six
    -+color profiles. For example, the method to get the Dark Vibrant color profile is <code><a
    -+href="/reference/android/support/v7/graphics/Palette.html#getDarkVibrantColor(int)">getDarkVibrantColor()</a></code>.
    -+Since not all images will contain all color profiles, you must also provide
    -+a default color to return.</p>
    -+
    -+<p>Figure 1 displays a photo and its corresponding color
    -+profiles from the <code>get&lt;<em>Profile</em>&gt;Color()</code> methods.</p>
    -+
    -+<img src="/training/material/images/palette-library-color-profiles_2-1_2x.png" alt="" width="624"/>
    -+
    -+<p class="img-caption"><strong>Figure 1.</strong> An example image and its
    -+extracted color profiles given the default maximum color count (16) for the palette.</p>
    -+
    -+<h3 id="use-swatches">Use swatches to create color schemes</h3>
    -+
    -+<p>The <code>Palette</code> class also generates <code><a 
    -+href="/reference/android/support/v7/graphics/Palette.Swatch.html">Palette.Swatch</a></code>
    -+objects for each color profile. <code>Palette.Swatch</code>
    -+objects contain the associated color for that profile, as well as the
    -+color’s population in pixels.</p>
    -+
    -+<p>Swatches have additional methods for accessing more information about the color
    -+profile, such as HSL values and pixel population. You can use swatches to help
    -+create more comprehensive color schemes and app themes using the <code><a
    -+href="/reference/android/support/v7/graphics/Palette.Swatch.html#getBodyTextColor()">getBodyTextColor()</a></code>
    -+and <code><a
    -+href="/reference/android/support/v7/graphics/Palette.Swatch.html#getTitleTextColor()">getTitleTextColor()</a></code>
    -+methods. These methods return colors appropriate for use over the swatch’s
    -+color.</p>
    -+
    -+<p>Each of <code>Palette</code>’s <code>get&lt;<em>Profile</em>&gt;Swatch()</code>
    -+methods returns the swatch associated with that particular profile,
    -+where <code>&lt;<em>Profile</em>&gt;</code> is replaced by the name of one of the six
    -+color profiles. Although the palette’s <code>get&lt;<em>Profile</em>&gt;Swatch()</code> methods
    -+do not require default value parameters, they return <code>null</code> if that
    -+particular profile does not exist in the image. Therefore, you should check that
    -+a swatch is not null before using it. For example, the following method 
    -+returns the Vibrant swatch from a palette if the swatch is not null:</p>
    -+
    -+<pre class="prettyprint">
    -+// Return a palette's vibrant swatch after checking that it exists
    -+private Palette.Swatch checkVibrantSwatch(Palette p) {
    -+  Palette.Swatch vibrant = p.getVibrantSwatch();
    -+  if (vibrant != null) {
    -+    return vibrant;
    -+  }
    -+  // Throw error
    -+}
    -+</pre>
    -+
    -+<p>To access all colors in a palette, the <code><a
    -+href="/reference/android/support/v7/graphics/Palette.html#getSwatches()">getSwatches()</a></code>
    -+method returns a list of all swatches generated from an
    -+image, including the standard six color profiles.</p>
    -+
    -+<p>The following snippet of code uses the methods from the above code snippets to
    -+synchronously generate a palette, get its vibrant swatch, and change the colors of a
    -+toolbar to match the bitmap image. Figure 2 displays the resulting image and toolbar.</p>
    -+
    -+<div class="cols">
    -+
    -+  <div class="col-2of3">
    -+
    -+<pre class="prettyprint">
    -+// Set the background and text colors of a toolbar given a
    -+// bitmap image to match
    -+public void setToolbarColor(Bitmap bitmap) {
    -+  // Generate the palette and get the vibrant swatch
    -+  // See the createPaletteSync() and checkVibrantSwatch() methods
    -+  // from the code snippets above
    -+  Palette p = createPaletteSync(bitmap);
    -+  Palette.Swatch vibrantSwatch = checkVibrantSwatch(p);
    -+  
    -+  // Set the toolbar background and text colors
    -+  Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
    -+  toolbar.setBackgroundColor(vibrantSwatch.getRgb());
    -+  toolbar.setTitleTextColor(vibrantSwatch.getTitleTextColor());
    -+}
    -+</pre>
    -+
    -+  </div>
    -+
    -+  <div class="col-1of3">
    -+
    -+    <img src="/training/material/images/palette-library-title-text-color_2-1_2x.png" alt="" width="400"/>
    -+
    -+    <p class="img-caption"><strong>Figure 2.</strong> An example image with its
    -+    vibrant-colored toolbar and corresponding title text color.</p>
    -+
    -+  </div>
    -+
    -+</div>
    -+
    -+</body>
    -+</html>
    -diff --git a/docs/html/training/monitoring-device-state/battery-monitoring.jd b/docs/html/training/monitoring-device-state/battery-monitoring.jd
    -index db75aaf..bab9c9c 100644
    ---- a/docs/html/training/monitoring-device-state/battery-monitoring.jd
    -+++ b/docs/html/training/monitoring-device-state/battery-monitoring.jd
    -@@ -141,10 +141,11 @@ receiver. The receiver is triggered whenever the device battery becomes low or e
    - condition by listening for {@link android.content.Intent#ACTION_BATTERY_LOW} and {@link
    - android.content.Intent#ACTION_BATTERY_OKAY}.</p>
    - 
    --<pre>&lt;receiver android:name=".BatteryLevelReceiver">
    --&lt;intent-filter>
    --  &lt;action android:name="android.intent.action.ACTION_BATTERY_LOW"/>
    --  &lt;action android:name="android.intent.action.ACTION_BATTERY_OKAY"/>
    -+<pre>
    -+&lt;receiver android:name=".BatteryLevelReceiver">
    -+  &lt;intent-filter>
    -+    &lt;action android:name="android.intent.action.BATTERY_LOW"/>
    -+    &lt;action android:name="android.intent.action.BATTERY_OKAY"/>
    -   &lt;/intent-filter>
    - &lt;/receiver></pre>
    - 
    -diff --git a/docs/html/training/monitoring-device-state/connectivity-monitoring.jd b/docs/html/training/monitoring-device-state/connectivity-monitoring.jd
    -index 2dd904f..c63822b 100644
    ---- a/docs/html/training/monitoring-device-state/connectivity-monitoring.jd
    -+++ b/docs/html/training/monitoring-device-state/connectivity-monitoring.jd
    -@@ -33,7 +33,7 @@ next.link=manifest-receivers.html
    - <p>Some of the most common uses for repeating alarms and background services is to schedule regular
    - updates of application data from Internet resources, cache data, or execute long running downloads.
    - But if you aren't connected to the Internet, or the connection is too slow to complete your
    --download, why both waking the device to schedule the update at all?</p>
    -+download, why bother waking the device to schedule the update at all?</p>
    - 
    - <p>You can use the {@link android.net.ConnectivityManager} to check that you're actually
    - connected to the Internet, and if so, what type of connection is in place.</p>
    -diff --git a/docs/html/training/monitoring-device-state/manifest-receivers.jd b/docs/html/training/monitoring-device-state/manifest-receivers.jd
    -index 3e36dba..5efa2fa 100644
    ---- a/docs/html/training/monitoring-device-state/manifest-receivers.jd
    -+++ b/docs/html/training/monitoring-device-state/manifest-receivers.jd
    -@@ -21,7 +21,10 @@ Efficiency</a></li>
    - 
    - <h2>You should also read</h2>
    - <ul>
    --  <li><a href="{@docRoot}guide/components/intents-filters.html">Intents and Intent Filters</a>
    -+  <li><a href="/topic/performance/background-optimization.html">Background Optimizations</a>
    -+  <li><a href="/topic/performance/scheduling.html">Intelligent Job-Scheduling</a>
    -+  <li><a href="/training/articles/perf-anr.html">Keeping Your App Responsive</a>
    -+  <li><a href="/guide/components/intents-filters.html">Intents and Intent Filters</a>
    - </ul>
    - 
    - </div>
    -@@ -32,13 +35,22 @@ android.content.BroadcastReceiver} for each state you're monitoring and register
    - your application manifest. Then within each of these receivers you simply reschedule your recurring
    - alarms based on the current device state.</p>
    - 
    --<p>A side-effect of this approach is that your app will wake the device each time any of these
    --receivers is triggered&mdash;potentially much more frequently than required.</p>
    --
    - <p>A better approach is to disable or enable the broadcast receivers at runtime. That way you can
    - use the receivers you declared in the manifest as passive alarms that are triggered by system events
    - only when necessary.</p>
    - 
    -+<p class="warning">
    -+    <strong>Warning:</strong> Limit how many broadcast
    -+    receivers you set in your app. Instead of using broadcast receivers,
    -+    consider using other APIs for
    -+    performing background work. For example, in Android 5.0 (API level 21) and
    -+    higher, you can use the {@link android.app.job.JobScheduler} class for
    -+    assigning work to be completed in the background.
    -+    For more information about APIs you can use instead of the
    -+    {@link android.content.BroadcastReceiver} class for scheduling background
    -+    work, see
    -+    <a href="{@docRoot}topic/performance/background-optimization.html">Background Optimizations</a>.
    -+</p>
    - 
    - <h2 id="ToggleReceivers">Toggle and Cascade State Change Receivers to Improve Efficiency </h2>
    - 
    -diff --git a/docs/html/training/notify-user/build-notification.jd b/docs/html/training/notify-user/build-notification.jd
    -index 7df2787..baa1074 100644
    ---- a/docs/html/training/notify-user/build-notification.jd
    -+++ b/docs/html/training/notify-user/build-notification.jd
    -@@ -134,8 +134,8 @@ mBuilder.setContentIntent(resultPendingIntent);</pre>
    - <ul>
    - <li>Get an instance of {@link android.app.NotificationManager}.</li>
    - 
    --<li>Use the {@link android.app.NotificationManager#notify(String, int, Notification)} method to issue the
    --notification. When you call {@link android.app.NotificationManager#notify(String, int, Notification)}, specify a notification ID.
    -+<li>Use the {@link android.app.NotificationManager#notify notify()} method to issue the
    -+notification. When you call {@link android.app.NotificationManager#notify notify()}, specify a notification ID.
    - You can use this ID to update the notification later on. This is described in more detail in
    - <a href="managing.html">Managing Notifications</a>.</li>
    - 
    -diff --git a/docs/html/training/run-background-service/index.jd b/docs/html/training/run-background-service/index.jd
    -index 22f3fc8..c48c681 100644
    ---- a/docs/html/training/run-background-service/index.jd
    -+++ b/docs/html/training/run-background-service/index.jd
    -@@ -35,16 +35,22 @@ startpage=true
    - <!-- ------------------------------------------------------------------------------------------- -->
    - <p>
    -     Unless you specify otherwise, most of the operations you do in an app run in the foreground on
    --    a special thread called the UI thread. This can cause problems, because long-running operations
    --    will interfere with the responsiveness of your user interface. This annoys your users, and can
    -+    a special thread called the UI thread. Long-running foreground operations can cause problems
    -+    and interfere with the responsiveness of your user interface, which annoys your users and can
    -     even cause system errors. To avoid this, the Android framework offers several classes that
    --    help you off-load operations onto a separate thread running in the background. The most useful
    --    of these is {@link android.app.IntentService}.
    -+    help you off-load operations onto a separate thread that runs in the background. The most
    -+    useful of these is {@link android.app.IntentService}.
    - </p>
    - <p>
    -     This class describes how to implement an {@link android.app.IntentService}, send it work
    -     requests, and report its results to other components.
    - </p>
    -+
    -+<p class="note"><strong>Note:</strong> If your app targets Android 5.0 (API level 21),
    -+    you should use {@link android.app.job.JobScheduler} to execute background
    -+    services. For more information about this class,
    -+    see the {@link android.app.job.JobScheduler} reference documentation.</p>
    -+
    - <h2>Lessons</h2>
    - <dl>
    -     <dt>
    -diff --git a/docs/html/training/testing/ui-testing/espresso-testing.jd b/docs/html/training/testing/ui-testing/espresso-testing.jd
    -index d3d31de..3d2bca7 100644
    ---- a/docs/html/training/testing/ui-testing/espresso-testing.jd
    -+++ b/docs/html/training/testing/ui-testing/espresso-testing.jd
    -@@ -24,17 +24,11 @@ trainingnavtop=true
    -         </h2>
    - 
    -         <ol>
    --          <li>
    --            <a href="#setup">Set Up Espresso</a>
    --          </li>
    -+          <li><a href="#setup">Set Up Espresso</a></li>
    - 
    --          <li>
    --            <a href="#build">Create an Espresso Test Class</a>
    --          </li>
    -+          <li><a href="#build">Create an Espresso Test Class</a></li>
    - 
    --          <li>
    --            <a href="#run">Run Espresso Tests on a Device or Emulator</a>
    --          </li>
    -+          <li><a href="#run">Run Espresso Tests on a Device or Emulator</a></li>
    -         </ol>
    - 
    -         <h2>
    -@@ -59,31 +53,40 @@ trainingnavtop=true
    -             class="external-link">Android Testing Codelab</a></li>
    -         </ul>
    -       </div>
    --    </div>
    -+</div>
    - 
    -     <p>
    -       Testing user interactions
    -       within a single app helps to ensure that users do not
    --      encounter unexpected results or have a poor experience when interacting with your app.
    --      You should get into the habit of creating user interface (UI) tests if you need to verify
    -+      encounter unexpected results or have a poor
    -+      experience when interacting with your app.
    -+      You should get into the habit of creating
    -+      user interface (UI) tests if you need to verify
    -       that the UI of your app is functioning correctly.
    -     </p>
    - 
    -     <p>
    -       The Espresso testing framework, provided by the
    -       <a href="{@docRoot}tools/testing-support-library/index.html">Android Testing Support Library</a>,
    --      provides APIs for writing UI tests to simulate user interactions within a
    --      single target app. Espresso tests can run on devices running Android 2.2 (API level 8) and
    --      higher. A key benefit of using Espresso is that it provides automatic synchronization of test
    --      actions with the UI of the app you are testing. Espresso detects when the main thread is idle,
    --      so it is able to run your test commands at the appropriate time, improving the reliability of
    --      your tests. This capability also relieves you from having to adding any timing workarounds,
    --      such as a sleep period, in your test code.
    -+      provides APIs for writing UI tests to simulate
    -+      user interactions within a
    -+      single target app. Espresso tests can run on
    -+      devices running Android 2.3.3 (API level 10) and
    -+      higher. A key benefit of using Espresso is
    -+      that it provides automatic synchronization of test
    -+      actions with the UI of the app you are testing.
    -+      Espresso detects when the main thread is idle,
    -+      so it is able to run your test commands
    -+      at the appropriate time, improving the reliability of
    -+      your tests. This capability also relieves you
    -+      from having to add any timing workarounds,
    -+      such as {@link java.lang.Thread#sleep(long) Thread.sleep()}
    -+      in your test code.
    -     </p>
    - 
    -     <p>
    --      The Espresso testing framework is an instrumentation-based API and works
    --      with the
    -+      The Espresso testing framework is
    -+      an instrumentation-based API and works with the
    -       <a href="{@docRoot}reference/android/support/test/runner/AndroidJUnitRunner.html">{@code
    -       AndroidJUnitRunner}</a> test runner.
    -     </p>
    -@@ -92,105 +95,139 @@ trainingnavtop=true
    -       Set Up Espresso
    -     </h2>
    - 
    --<p>Before building your UI test with Espresso, make sure to configure your test source code
    --location and project dependencies, as described in
    --<a href="{@docRoot}training/testing/start/index.html#config-instrumented-tests">
    --Getting Started with Testing</a>.</p>
    -+<p>
    -+  Before building your UI test with Espresso,
    -+  make sure to configure your test source code
    -+  location and project dependencies, as described in
    -+  <a href="{@docRoot}training/testing/start/index.html#config-instrumented-tests">Getting Started with Testing</a>.
    -+</p>
    - 
    --<p>In the {@code build.gradle} file of your Android app module, you must set a dependency
    --  reference to the Espresso library:</p>
    -+<p>
    -+  In the {@code build.gradle} file of your Android app
    -+  module, you must set a dependency
    -+  reference to the Espresso library:
    -+</p>
    - 
    - <pre>
    - dependencies {
    --    ...
    --    androidTestCompile 'com.android.support.test.espresso:espresso-core:2.2.1'
    -+    // Other dependencies ...
    -+    androidTestCompile 'com.android.support.test.espresso:espresso-core:2.2.2'
    - }
    - </pre>
    - 
    --<p>Turn off animations on your test device &mdash; leaving system animations turned on in the test
    --device might cause unexpected results or may lead your test to fail. Turn off animations from
    --<em>Settings</em> by opening <em>Developing Options</em> and turning all the following options off:
    -+<p>
    -+  Turn off animations on your test device &mdash;
    -+  leaving system animations turned on in the test
    -+  device might cause unexpected results or may
    -+  lead your test to fail. Turn off animations from
    -+  <em>Settings</em> by opening <em>Developer options</em>
    -+  and turning all the following options off:
    - </p>
    --        <ul>
    --          <li>
    --            <strong>Window animation scale</strong>
    --          </li>
    - 
    --          <li>
    --            <strong>Transition animation scale</strong>
    --          </li>
    -+<p>
    -+  <ul>
    -+    <li>
    -+      <strong>Window animation scale</strong>
    -+    </li>
    -+
    -+    <li>
    -+      <strong>Transition animation scale</strong>
    -+    </li>
    -+
    -+    <li>
    -+      <strong>Animator duration scale</strong>
    -+    </li>
    -+  </ul>
    -+</p>
    - 
    --          <li>
    --            <strong>Animator duration scale</strong>
    --          </li>
    --        </ul>
    --      </li>
    --    </ul>
    --<p>If you want to set up your project to use Espresso features other than what the core API
    -+<p>
    -+  If you want to set up your project to use Espresso
    -+  features other than what the core API
    -   provides, see this
    -   <a href="https://google.github.io/android-testing-support-library/docs/espresso/index.html"
    -   class="external-link">resource</a>.</p>
    - 
    --    <h2 id="build">
    --      Create an Espresso Test Class
    --    </h2>
    -+<!-- Section 2 -->
    - 
    --    <p>
    --      To create an Espresso test, create a Java class that follows this programming model:
    --    </p>
    -+<h2 id="build">
    -+  Create an Espresso Test Class
    -+</h2>
    - 
    --    <ol>
    --      <li>Find the UI component you want to test in an {@link android.app.Activity} (for example, a
    --      sign-in button in the app) by calling the
    --      <a href="{@docRoot}reference/android/support/test/espresso/Espresso.html#onView(org.hamcrest.Matcher<android.view.View>)">
    --        {@code onView()}</a> method, or the
    --      <a href="{@docRoot}reference/android/support/test/espresso/Espresso.html#onData(org.hamcrest.Matcher<java.lang.Object>)">
    --      {@code onData()}</a> method for {@link android.widget.AdapterView} controls.
    --      </li>
    --
    --      <li>Simulate a specific user interaction to perform on that UI component, by calling the
    --      <a href="{@docRoot}reference/android/support/test/espresso/ViewInteraction.html#perform(android.support.test.espresso.ViewAction...)">{@code ViewInteraction.perform()}</a>
    --      or
    --      <a href="{@docRoot}reference/android/support/test/espresso/DataInteraction.html#perform(android.support.test.espresso.ViewAction...)">{@code DataInteraction.perform()}</a>
    --      method and passing in the user action (for example, click on the sign-in button). To sequence
    --      multiple actions on the same UI component, chain them using a comma-separated list in your
    --      method argument.
    --      </li>
    --
    --      <li>Repeat the steps above as necessary, to simulate a user flow across multiple
    --      activities in the target app.
    --      </li>
    --
    --      <li>Use the
    -+<p>
    -+  To create an Espresso test, create a Java
    -+  class that follows this programming model:
    -+</p>
    -+
    -+<ol>
    -+  <li>
    -+    Find the UI component you want to test in
    -+    an {@link android.app.Activity} (for example, a
    -+    sign-in button in the app) by calling the
    -+    <a href="{@docRoot}reference/android/support/test/espresso/Espresso.html#onView(org.hamcrest.Matcher<android.view.View>)">
    -+    {@code onView()}</a> method, or the
    -+    <a href="{@docRoot}reference/android/support/test/espresso/Espresso.html#onData(org.hamcrest.Matcher<java.lang.Object>)">
    -+    {@code onData()}</a> method for {@link android.widget.AdapterView} controls.
    -+  </li>
    -+
    -+  <li>
    -+    Simulate a specific user interaction to
    -+    perform on that UI component, by calling the
    -+    <a href="{@docRoot}reference/android/support/test/espresso/ViewInteraction.html#perform(android.support.test.espresso.ViewAction...)">{@code ViewInteraction.perform()}</a>
    -+    or
    -+    <a href="{@docRoot}reference/android/support/test/espresso/DataInteraction.html#perform(android.support.test.espresso.ViewAction...)">{@code DataInteraction.perform()}</a>
    -+    method and passing in the user action
    -+    (for example, click on the sign-in button). To sequence
    -+    multiple actions on the same UI component, chain them using a comma-separated list in your
    -+    method argument.
    -+  </li>
    -+
    -+  <li>
    -+    Repeat the steps above as necessary, to simulate a user flow across multiple
    -+    activities in the target app.
    -+  </li>
    -+
    -+  <li>
    -+    Use the
    -     <a href="{@docRoot}reference/android/support/test/espresso/assertion/ViewAssertions.html">{@code ViewAssertions}</a>
    --        methods to check that the UI reflects the expected
    --      state or behavior, after these user interactions are performed.
    --      </li>
    --    </ol>
    -+    methods to check that the UI reflects the expected
    -+    state or behavior, after these user interactions are performed.
    -+  </li>
    -+</ol>
    - 
    --    <p>
    --      These steps are covered in more detail in the sections below.
    --    </p>
    -+<p>
    -+  These steps are covered in more detail in the sections below.
    -+</p>
    - 
    --    <p>
    --      The following code snippet shows how your test class might invoke this basic workflow:
    --    </p>
    -+<p>
    -+  The following code snippet shows how your test
    -+  class might invoke this basic workflow:
    -+</p>
    - 
    - <pre>
    - onView(withId(R.id.my_view))            // withId(R.id.my_view) is a ViewMatcher
    -         .perform(click())               // click() is a ViewAction
    -         .check(matches(isDisplayed())); // matches(isDisplayed()) is a ViewAssertion
    - </pre>
    --<h3 id="espresso-atr">Using Espresso with ActivityTestRule</h3>
    -+
    -+<!-- Section 2.1 -->
    -+
    -+<h3 id="espresso-atr">
    -+  Using Espresso with ActivityTestRule
    -+</h3>
    -+
    - <p>
    --The following section describes how to create a new Espresso test in the JUnit 4 style and use
    --<a href="{@docRoot}reference/android/support/test/rule/ActivityTestRule.html">
    --{@code ActivityTestRule}</a> to reduce the amount of boilerplate code you need to write. By using
    --<a href="{@docRoot}reference/android/support/test/rule/ActivityTestRule.html">
    --{@code ActivityTestRule}</a>, the testing framework launches the activity under test
    --before each test method annotated with <code>&#64;Test</code> and before any method annotated with
    --<code>&#64;Before</code>. The framework handles shutting down the activity after the test finishes
    --and all methods annotated with <code>&#64;After</code> are run.</p>
    -+  The following section describes how to create a
    -+  new Espresso test in the JUnit 4 style and use
    -+  <a href="{@docRoot}reference/android/support/test/rule/ActivityTestRule.html">{@code ActivityTestRule}</a>
    -+  to reduce the amount of boilerplate code you need to write. By using
    -+  <a href="{@docRoot}reference/android/support/test/rule/ActivityTestRule.html">{@code ActivityTestRule}</a>,
    -+  the testing framework launches the activity under test
    -+  before each test method annotated with
    -+  <code>&#64;Test</code> and before any method annotated with
    -+  <code>&#64;Before</code>. The framework handles
    -+  shutting down the activity after the test finishes
    -+  and all methods annotated with <code>&#64;After</code> are run.
    -+</p>
    - 
    - <pre>
    - package com.example.android.testing.espresso.BasicSample;
    -@@ -234,103 +271,57 @@ public class ChangeTextBehaviorTest {
    - }
    - </pre>
    - 
    --    <h3 id="espresso-aitc2">
    --      Using Espresso with ActivityInstrumentationTestCase2
    --    </h3>
    --<p>The following section describes how to migrate to Espresso if you have existing test classes
    --subclassed from {@link android.test.ActivityInstrumentationTestCase2} and you don't want to rewrite
    --them to use JUnit4.</p>
    --<p class="note"><strong>Note:</strong> For new UI tests, we strongly recommend that you write your
    --test in the JUnit 4 style and use the
    --<a href="{@docRoot}reference/android/support/test/rule/ActivityTestRule.html">
    --{@code ActivityTestRule}</a> class, instead of
    --{@link android.test.ActivityInstrumentationTestCase2}.</p>
    --    <p>
    --      If you are subclassing {@link android.test.ActivityInstrumentationTestCase2}
    --      to create your Espresso test class, you must inject an
    --      {@link android.app.Instrumentation} instance into your test class. This step is required in
    --      order for your Espresso test to run with the
    --      <a href="{@docRoot}reference/android/support/test/runner/AndroidJUnitRunner.html">{@code AndroidJUnitRunner}</a>
    --      test runner.
    --    </p>
    -+<!-- Section 2.2 -->
    - 
    --    <p>
    --      To do this, call the
    --      {@link android.test.InstrumentationTestCase#injectInstrumentation(android.app.Instrumentation) injectInstrumentation()}
    --      method and pass in the result of
    --      <a href="{@docRoot}reference/android/support/test/InstrumentationRegistry.html#getInstrumentation()">
    --      {@code InstrumentationRegistry.getInstrumentation()}</a>, as shown in the following code
    --      example:
    --    </p>
    --
    --<pre>
    --import android.support.test.InstrumentationRegistry;
    -+<h3 id="accessing-ui-components">
    -+  Accessing UI Components
    -+</h3>
    - 
    --public class MyEspressoTest
    --        extends ActivityInstrumentationTestCase2&lt;MyActivity&gt; {
    --
    --    private MyActivity mActivity;
    --
    --    public MyEspressoTest() {
    --        super(MyActivity.class);
    --    }
    --
    --    &#64;Before
    --    public void setUp() throws Exception {
    --        super.setUp();
    --        injectInstrumentation(InstrumentationRegistry.getInstrumentation());
    --        mActivity = getActivity();
    --    }
    --
    --   ...
    --}
    --</pre>
    --
    --<p class="note"><strong>Note:</strong> Previously, {@link android.test.InstrumentationTestRunner}
    --would inject the {@link android.app.Instrumentation} instance, but this test runner is being
    --deprecated.</p>
    --
    --    <h3 id="accessing-ui-components">
    --      Accessing UI Components
    --    </h3>
    --
    --    <p>
    --      Before Espresso can interact with the app under test, you must first specify the UI component
    --      or <em>view</em>. Espresso supports the use of
    --<a href="http://hamcrest.org/" class="external-link">Hamcrest matchers</a>
    --      for specifying views and adapters in your app.
    --    </p>
    -+<p>
    -+  Before Espresso can interact with the app
    -+  under test, you must first specify the UI component
    -+  or <em>view</em>. Espresso supports the use of
    -+  <a href="http://hamcrest.org/" class="external-link">Hamcrest matchers</a>
    -+  for specifying views and adapters in your app.
    -+</p>
    - 
    --    <p>
    --      To find the view, call the <a href="{@docRoot}reference/android/support/test/espresso/Espresso.html#onView(org.hamcrest.Matcher<android.view.View>)">
    --      {@code onView()}</a>
    --      method and pass in a view matcher that specifies the view that you are targeting. This is
    --      described in more detail in <a href="#specifying-view-matcher">Specifying a View Matcher</a>.
    --      The <a href="{@docRoot}reference/android/support/test/espresso/Espresso.html#onView(org.hamcrest.Matcher<android.view.View>)">
    --      {@code onView()}</a> method returns a
    --      <a href="{@docRoot}reference/android/support/test/espresso/ViewInteraction.html">
    --      {@code ViewInteraction}</a>
    --      object that allows your test to interact with the view.
    --      However, calling  the <a href="{@docRoot}reference/android/support/test/espresso/Espresso.html#onView(org.hamcrest.Matcher<android.view.View>)">
    --      {@code onView()}</a> method may not work if you want to locate a view in
    --      an {@link android.widget.AdapterView} layout. In this case, follow the instructions in
    --      <a href="#locating-adpeterview-view">Locating a view in an AdapterView</a> instead.
    --    </p>
    -+<p>
    -+  To find the view, call the
    -+  <a href="{@docRoot}reference/android/support/test/espresso/Espresso.html#onView(org.hamcrest.Matcher<android.view.View>)">{@code onView()}</a>
    -+  method and pass in a view matcher that
    -+  specifies the view that you are targeting. This is
    -+  described in more detail in
    -+  <a href="#specifying-view-matcher">Specifying a View Matcher</a>.
    -+  The <a href="{@docRoot}reference/android/support/test/espresso/Espresso.html#onView(org.hamcrest.Matcher<android.view.View>)">{@code onView()}</a>
    -+  method returns a
    -+  <a href="{@docRoot}reference/android/support/test/espresso/ViewInteraction.html">{@code ViewInteraction}</a>
    -+  object that allows your test to interact with the view.
    -+  However, calling the
    -+  <a href="{@docRoot}reference/android/support/test/espresso/Espresso.html#onView(org.hamcrest.Matcher<android.view.View>)">
    -+  {@code onView()}</a>
    -+  method may not work if you want to locate a view in
    -+  an {@link android.support.v7.widget.RecyclerView} layout.
    -+  In this case, follow the instructions in
    -+  <a href="#locating-adpeterview-view">Locating a view in an AdapterView</a>
    -+  instead.
    -+</p>
    - 
    --    <p class="note">
    --      <strong>Note</strong>: The <a href="{@docRoot}reference/android/support/test/espresso/Espresso.html#onView(org.hamcrest.Matcher<android.view.View>)">
    --      {@code onView()}</a> method does not check if the view you specified is
    --      valid. Instead, Espresso searches only the current view hierarchy, using the matcher provided.
    --      If no match is found, the method throws a
    --      <a href="{@docRoot}reference/android/support/test/espresso/NoMatchingViewException.html">
    --      {@code NoMatchingViewException}</a>.
    --    </p>
    -+<p class="note">
    -+  <strong>Note</strong>:
    -+  The <a href="{@docRoot}reference/android/support/test/espresso/Espresso.html#onView(org.hamcrest.Matcher<android.view.View>)">{@code onView()}</a>
    -+  method does not check if the view you specified is
    -+  valid. Instead, Espresso searches only the
    -+  current view hierarchy, using the matcher provided.
    -+  If no match is found, the method throws a
    -+  <a href="{@docRoot}reference/android/support/test/espresso/NoMatchingViewException.html">{@code NoMatchingViewException}</a>.
    -+</p>
    - 
    --    <p>
    --      The following code snippet shows how you might write a test that accesses an
    --      {@link android.widget.EditText} field, enters a string of text, closes the virtual keyboard,
    --      and then performs a button click.
    --    </p>
    -+<p>
    -+  The following code snippet shows how you might write a test that accesses an
    -+  {@link android.widget.EditText} field,
    -+  enters a string of text, closes the virtual keyboard,
    -+  and then performs a button click.
    -+</p>
    - 
    - <pre>
    - public void testChangeText_sameActivity() {
    -@@ -344,231 +335,464 @@ public void testChangeText_sameActivity() {
    - }
    - </pre>
    - 
    --    <h4 id="specifying-view-matcher">
    --      Specifying a View Matcher
    --    </h4>
    -+<!-- Section 2.2.1 -->
    -+<h4 id="specifying-view-matcher">
    -+  Specifying a View Matcher
    -+</h4>
    - 
    --    <p>
    --      You can specify a view matcher by using these approaches:
    --    </p>
    -+<p>
    -+  You can specify a view matcher by using these approaches:
    -+</p>
    - 
    --    <ul>
    --      <li>Calling methods in the
    --        <a href="{@docRoot}reference/android/support/test/espresso/matcher/ViewMatchers.html">
    --        {@code ViewMatchers}</a> class. For example, to find a view by looking for a text string it
    --        displays, you can call a method like this:
    --        <pre>
    -+<ul>
    -+  <li>Calling methods in the
    -+    <a href="{@docRoot}reference/android/support/test/espresso/matcher/ViewMatchers.html">{@code ViewMatchers}</a>
    -+    class. For example, to find a view by looking for a text string it
    -+    displays, you can call a method like this:
    -+<pre>
    - onView(withText("Sign-in"));
    - </pre>
    - 
    --<p>Similarly you can call
    --<a href="{@docRoot}reference/android/support/test/espresso/matcher/ViewMatchers.html#withId(int)">
    --{@code withId()}</a> and providing the resource ID ({@code R.id}) of the view, as shown in the
    --following example:</p>
    -+    <p>
    -+      Similarly you can call
    -+      <a href="{@docRoot}reference/android/support/test/espresso/matcher/ViewMatchers.html#withId(int)">{@code withId()}</a>
    -+      and providing the resource ID ({@code R.id}) of the view,
    -+      as shown in the
    -+      following example:
    -+    </p>
    - 
    - <pre>
    - onView(withId(R.id.button_signin));
    - </pre>
    - 
    -     <p>
    --      Android resource IDs are not guaranteed to be unique. If your test attempts to match to a
    -+      Android resource IDs are not guaranteed to be unique.
    -+      If your test attempts to match to a
    -       resource ID used by more than one view, Espresso throws an
    --<a href="{@docRoot}reference/android/support/test/espresso/AmbiguousViewMatcherException.html">
    --  {@code AmbiguousViewMatcherException}</a>.
    -+      <a href="{@docRoot}reference/android/support/test/espresso/AmbiguousViewMatcherException.html">{@code AmbiguousViewMatcherException}</a>.
    -     </p>
    --      </li>
    --      <li>Using the Hamcrest
    --      <a href="http://hamcrest.org/JavaHamcrest/javadoc/1.3/org/hamcrest/Matchers.html"
    --         class="external-link">{@code Matchers}</a> class. You can use the
    --      {@code allOf()} methods to combine multiple matchers, such as
    --      {@code containsString()} and {@code instanceOf()}. This approach allows you to
    --      filter the match results more narrowly, as shown in the following example:
    -+  </li>
    -+
    -+  <li>
    -+    Using the Hamcrest
    -+    <a href="http://hamcrest.org/JavaHamcrest/javadoc/1.3/org/hamcrest/Matchers.html"
    -+    class="external-link">{@code Matchers}</a> class. You can use the
    -+    {@code allOf()} methods to combine multiple matchers, such as
    -+    {@code containsString()} and {@code instanceOf()}.
    -+    This approach allows you to
    -+    filter the match results more narrowly, as shown in the following example:
    -+
    - <pre>
    - onView(allOf(withId(R.id.button_signin), withText("Sign-in")));
    - </pre>
    --<p>You can use the {@code not} keyword to filter for views that don't correspond to the matcher, as
    --shown in the following example:</p>
    -+
    -+    <p>
    -+      You can use the {@code not} keyword to filter
    -+      for views that don't correspond to the matcher, as
    -+      shown in the following example:
    -+    </p>
    -+
    - <pre>
    - onView(allOf(withId(R.id.button_signin), not(withText("Sign-out"))));
    - </pre>
    --<p>To use these methods in your test, import the {@code org.hamcrest.Matchers} package. To
    --learn more about Hamcrest matching, see the
    --<a href="http://hamcrest.org/" class="external-link">Hamcrest site</a>.
    --</p>
    --      </li>
    --    </ul>
    - 
    -     <p>
    --      To improve the performance of your Espresso tests, specify the minimum matching information
    --      needed to find your target view. For example, if a view is uniquely identifiable by its
    --      descriptive text, you do not need to specify that it is also assignable from the
    --      {@link android.widget.TextView} instance.
    -+      To use these methods in your test,
    -+      import the {@code org.hamcrest.Matchers} package. To
    -+      learn more about Hamcrest matching, see the
    -+      <a href="http://hamcrest.org/" class="external-link">Hamcrest site</a>.
    -     </p>
    -+  </li>
    -+</ul>
    - 
    --    <h4 id="#locating-adpeterview-view">
    --      Locating a view in an AdapterView
    --    </h4>
    -+<p>
    -+  To improve the performance of your Espresso tests,
    -+  specify the minimum matching information
    -+  needed to find your target view. For example,
    -+  if a view is uniquely identifiable by its
    -+  descriptive text, you do not need to specify
    -+  that it is also assignable from the
    -+  {@link android.widget.TextView} instance.
    -+</p>
    - 
    --    <p>
    --      In an {@link android.widget.AdapterView} widget, the view is dynamically populated with child
    --      views at runtime. If the target view you want to test is inside an
    --      {@link android.widget.AdapterView}
    --      (such as a {@link android.widget.ListView}, {@link android.widget.GridView}, or
    --      {@link android.widget.Spinner}), the
    --<a href="{@docRoot}reference/android/support/test/espresso/Espresso.html#onView(org.hamcrest.Matcher<android.view.View>)">
    --  {@code onView()}</a> method might not work because only a
    --      subset of the views may be loaded in the current view hierarchy.
    --    </p>
    -+<!-- Section 2.2.2 -->
    - 
    --    <p>
    --      Instead, call the <a href="{@docRoot}reference/android/support/test/espresso/Espresso.html#onData(org.hamcrest.Matcher<java.lang.Object>)">{@code onData()}</a>
    --      method to obtain a
    --      <a href="{@docRoot}reference/android/support/test/espresso/DataInteraction.html">
    --      {@code DataInteraction}</a>
    --      object to access the target view element. Espresso handles loading the target view element
    --      into the current view hierarchy. Espresso also takes care of scrolling to the target element,
    --      and putting the element into focus.
    --    </p>
    -+<h4 id="#locating-adpeterview-view">
    -+  Locating a view in an AdapterView
    -+</h4>
    -+
    -+<p>
    -+  In an {@link android.widget.AdapterView} widget,
    -+  the view is dynamically populated with child
    -+  views at runtime. If the target view you want to test is inside an
    -+  {@link android.widget.AdapterView}
    -+  (such as a {@link android.widget.ListView},
    -+  {@link android.widget.GridView}, or
    -+  {@link android.widget.Spinner}), the
    -+  <a href="{@docRoot}reference/android/support/test/espresso/Espresso.html#onView(org.hamcrest.Matcher<android.view.View>)">{@code onView()}</a>
    -+  method might not work because only a
    -+  subset of the views may be loaded in the current view hierarchy.
    -+</p>
    - 
    --    <p class="note">
    --      <strong>Note</strong>: The
    -+<p>
    -+  Instead, call the
    -   <a href="{@docRoot}reference/android/support/test/espresso/Espresso.html#onData(org.hamcrest.Matcher<java.lang.Object>)">{@code onData()}</a>
    --      method does not check if if the item you specified corresponds with a view. Espresso searches
    --      only the current view hierarchy. If no match is found, the method throws a
    --      <a href="{@docRoot}reference/android/support/test/espresso/NoMatchingViewException.html">
    --        {@code NoMatchingViewException}</a>.
    --    </p>
    -+  method to obtain a
    -+  <a href="{@docRoot}reference/android/support/test/espresso/DataInteraction.html">{@code DataInteraction}</a>
    -+  object to access the target view element.
    -+  Espresso handles loading the target view element
    -+  into the current view hierarchy. Espresso
    -+  also takes care of scrolling to the target element,
    -+  and putting the element into focus.
    -+</p>
    - 
    --    <p>
    --      The following code snippet shows how you can use the
    --      <a href="{@docRoot}reference/android/support/test/espresso/Espresso.html#onData(org.hamcrest.Matcher<java.lang.Object>)">{@code onData()}</a>
    --      method together
    --      with Hamcrest matching to search for a specific row in a list that contains a given string.
    --      In this example, the {@code LongListActivity} class contains a list of strings exposed
    --      through a {@link android.widget.SimpleAdapter}.
    --    </p>
    -+<p class="note">
    -+  <strong>Note</strong>: The
    -+  <a href="{@docRoot}reference/android/support/test/espresso/Espresso.html#onData(org.hamcrest.Matcher<java.lang.Object>)">{@code onData()}</a>
    -+  method does not check if the item you
    -+  specified corresponds with a view. Espresso searches
    -+  only the current view hierarchy. If no match is found, the method throws a
    -+  <a href="{@docRoot}reference/android/support/test/espresso/NoMatchingViewException.html">{@code NoMatchingViewException}</a>.
    -+</p>
    -+
    -+<p>
    -+  The following code snippet shows how you can use the
    -+  <a href="{@docRoot}reference/android/support/test/espresso/Espresso.html#onData(org.hamcrest.Matcher<java.lang.Object>)">{@code onData()}</a>
    -+  method together
    -+  with Hamcrest matching to search for a specific
    -+  row in a list that contains a given string.
    -+  In this example, the {@code LongListActivity} class
    -+  contains a list of strings exposed
    -+  through a {@link android.widget.SimpleAdapter}.
    -+</p>
    - 
    - <pre>
    - onData(allOf(is(instanceOf(Map.class)),
    --        hasEntry(equalTo(LongListActivity.ROW_TEXT), is(str))));
    -+        hasEntry(equalTo(LongListActivity.ROW_TEXT), is("test input")));
    - </pre>
    - 
    --    <h3 id="perform-actions">
    --      Performing Actions
    --    </h3>
    -+<!-- Section 2.3 -->
    - 
    --    <p>
    --      Call the <a href="{@docRoot}reference/android/support/test/espresso/ViewInteraction.html#perform(android.support.test.espresso.ViewAction...)">{@code ViewInteraction.perform()}</a>
    --      or
    --      <a href="{@docRoot}reference/android/support/test/espresso/DataInteraction.html#perform(android.support.test.espresso.ViewAction...)">{@code DataInteraction.perform()}</a>
    --      methods to
    --      simulate user interactions on the UI component. You must pass in one or more
    --      <a href="{@docRoot}reference/android/support/test/espresso/ViewAction.html">{@code ViewAction}</a>
    --      objects as arguments. Espresso fires each action in sequence according to
    --      the given order, and executes them in the main thread.
    --    </p>
    -+<h3 id="perform-actions">Performing Actions</h3>
    - 
    --    <p>
    --      The
    --      <a href="{@docRoot}reference/android/support/test/espresso/action/ViewActions.html">{@code ViewActions}</a>
    --      class provides a list of helper methods for specifying common actions.
    --      You can use these methods as convenient shortcuts instead of creating and configuring
    --      individual <a href="{@docRoot}reference/android/support/test/espresso/ViewAction.html">{@code ViewAction}</a>
    --      objects. You can specify such actions as:
    --    </p>
    -+<p>
    -+  Call the
    -+  <a href="{@docRoot}reference/android/support/test/espresso/ViewInteraction.html#perform(android.support.test.espresso.ViewAction...)">{@code ViewInteraction.perform()}</a>
    -+  or
    -+  <a href="{@docRoot}reference/android/support/test/espresso/DataInteraction.html#perform(android.support.test.espresso.ViewAction...)">{@code DataInteraction.perform()}</a>
    -+  methods to
    -+  simulate user interactions on the UI component. You must pass in one or more
    -+  <a href="{@docRoot}reference/android/support/test/espresso/ViewAction.html">{@code ViewAction}</a>
    -+  objects as arguments. Espresso fires each action in sequence according to
    -+  the given order, and executes them in the main thread.
    -+</p>
    - 
    --    <ul>
    --      <li>
    --       <a href="{@docRoot}reference/android/support/test/espresso/action/ViewActions.html#click()">{@code ViewActions.click()}</a>:
    --       Clicks on the view.
    --      </li>
    --
    --      <li>
    --       <a href="{@docRoot}reference/android/support/test/espresso/action/ViewActions.html#typeText(java.lang.String)">{@code ViewActions.typeText()}</a>:
    --       Clicks on a view and enters a specified string.
    --      </li>
    --
    --      <li>
    --       <a href="{@docRoot}reference/android/support/test/espresso/action/ViewActions.html#scrollTo()">{@code ViewActions.scrollTo()}</a>:
    --       Scrolls to the view. The
    --        target view must be subclassed from {@link android.widget.ScrollView}
    --        and the value of its
    --        <a href="http://developer.android.com/reference/android/view/View.html#attr_android:visibility">{@code android:visibility}</a>
    --        property must be {@link android.view.View#VISIBLE}. For views that extend
    --        {@link android.widget.AdapterView} (for example,
    --        {@link android.widget.ListView}),
    --        the
    --        <a href="{@docRoot}reference/android/support/test/espresso/Espresso.html#onData(org.hamcrest.Matcher<java.lang.Object>)">{@code onData()}</a>
    --        method takes care of scrolling for you.
    --      </li>
    --
    --      <li>
    --       <a href="{@docRoot}reference/android/support/test/espresso/action/ViewActions.html#pressKey(int)">{@code ViewActions.pressKey()}</a>:
    --       Performs a key press using a specified keycode.
    --      </li>
    --
    --      <li>
    --      <a href="{@docRoot}reference/android/support/test/espresso/action/ViewActions.html#clearText()">{@code ViewActions.clearText()}</a>:
    --      Clears the text in the target view.
    --      </li>
    --    </ul>
    -+<p>
    -+  The
    -+  <a href="{@docRoot}reference/android/support/test/espresso/action/ViewActions.html">{@code ViewActions}</a>
    -+  class provides a list of helper methods for specifying common actions.
    -+  You can use these methods as convenient shortcuts
    -+  instead of creating and configuring individual
    -+  <a href="{@docRoot}reference/android/support/test/espresso/ViewAction.html">{@code ViewAction}</a>
    -+  objects. You can specify such actions as:
    -+</p>
    - 
    --    <p>
    --      If the target view is inside a {@link android.widget.ScrollView}, perform the
    --      <a href="{@docRoot}reference/android/support/test/espresso/action/ViewActions.html#scrollTo()">{@code ViewActions.scrollTo()}</a>
    --      action first to display the view in the screen before other proceeding
    --      with other actions. The
    --      <a href="{@docRoot}reference/android/support/test/espresso/action/ViewActions.html#scrollTo()">{@code ViewActions.scrollTo()}</a>
    --      action will have no effect if the view is already displayed.
    --    </p>
    -+<ul>
    -+  <li>
    -+   <a href="{@docRoot}reference/android/support/test/espresso/action/ViewActions.html#click()">{@code ViewActions.click()}</a>:
    -+   Clicks on the view.
    -+  </li>
    -+
    -+  <li>
    -+   <a href="{@docRoot}reference/android/support/test/espresso/action/ViewActions.html#typeText(java.lang.String)">{@code ViewActions.typeText()}</a>:
    -+   Clicks on a view and enters a specified string.
    -+  </li>
    -+
    -+  <li>
    -+    <a href="{@docRoot}reference/android/support/test/espresso/action/ViewActions.html#scrollTo()">{@code ViewActions.scrollTo()}</a>:
    -+    Scrolls to the view. The
    -+    target view must be subclassed from {@link android.widget.ScrollView}
    -+    and the value of its
    -+    <a href="http://developer.android.com/reference/android/view/View.html#attr_android:visibility">{@code android:visibility}</a>
    -+    property must be {@link android.view.View#VISIBLE}. For views that extend
    -+    {@link android.widget.AdapterView} (for example,
    -+    {@link android.widget.ListView}), the
    -+    <a href="{@docRoot}reference/android/support/test/espresso/Espresso.html#onData(org.hamcrest.Matcher<java.lang.Object>)">{@code onData()}</a>
    -+    method takes care of scrolling for you.
    -+  </li>
    -+
    -+  <li>
    -+    <a href="{@docRoot}reference/android/support/test/espresso/action/ViewActions.html#pressKey(int)">{@code ViewActions.pressKey()}</a>:
    -+    Performs a key press using a specified keycode.
    -+  </li>
    -+
    -+  <li>
    -+    <a href="{@docRoot}reference/android/support/test/espresso/action/ViewActions.html#clearText()">{@code ViewActions.clearText()}</a>:
    -+  Clears the text in the target view.
    -+  </li>
    -+</ul>
    - 
    --    <h3 id="verify-results">
    --      Verifying Results
    --    </h3>
    -+<p>
    -+  If the target view is inside a {@link android.widget.ScrollView},
    -+  perform the
    -+  <a href="{@docRoot}reference/android/support/test/espresso/action/ViewActions.html#scrollTo()">{@code ViewActions.scrollTo()}</a>
    -+  action first to display the view in the screen before other proceeding
    -+  with other actions. The
    -+  <a href="{@docRoot}reference/android/support/test/espresso/action/ViewActions.html#scrollTo()">{@code ViewActions.scrollTo()}</a>
    -+  action will have no effect if the view is already displayed.
    -+</p>
    - 
    --    <p>
    --      Call the
    --      <a href="{@docRoot}reference/android/support/test/espresso/ViewInteraction.html#check(android.support.test.espresso.ViewAssertion)">{@code ViewInteraction.check()}</a>
    --      or
    --      <a href="{@docRoot}reference/android/support/test/espresso/DataInteraction.html#check(android.support.test.espresso.ViewAssertion)">{@code DataInteraction.check()}</a>
    --      method to assert
    --      that the view in the UI matches some expected state. You must pass in a
    --      <a href="{@docRoot}reference/android/support/test/espresso/ViewAssertion.html">
    --      {@code ViewAssertion}</a> object as the argument. If the assertion fails, Espresso throws
    --      an {@link junit.framework.AssertionFailedError}.
    --    </p>
    -+<!-- Section 2.4 -->
    - 
    --    <p>
    --      The
    -+<h3 id="intents">
    -+  Test your activities in isolation with Espresso Intents
    -+</h3>
    -+
    -+<p>
    -+  <a href="https://google.github.io/android-testing-support-library/docs/espresso/intents/index.html" class="external-link">Espresso Intents</a>
    -+  enables validation and stubbing of intents sent out by an app.
    -+  With Espresso Intents, you can test an app, activity, or service in isolation
    -+  by intercepting outgoing intents, stubbing the result, and sending it back to
    -+  the component under test.
    -+</p>
    -+
    -+<p>
    -+  To begin testing with Espresso Intents, you need
    -+  to add the following line to your app's build.gradle file:
    -+</p>
    -+
    -+<pre>
    -+dependencies {
    -+  // Other dependencies ...
    -+  androidTestCompile 'com.android.support.test.espresso:espresso-intents:2.2.2'
    -+}
    -+</pre>
    -+
    -+<p>
    -+  To test an intent, you need to create an instance of the
    -+  <a href="{@docRoot}reference/android/support/test/espresso/intent/rule/IntentsTestRule.html">IntentsTestRule</a>
    -+  class, which is very similar to the
    -+  <a href="{@docRoot}reference/android/support/test/rule/ActivityTestRule.html">ActivityTestRule</a>
    -+  class.
    -+  The
    -+  <a href="{@docRoot}reference/android/support/test/espresso/intent/rule/IntentsTestRule.html">IntentsTestRule</a>
    -+  class initializes Espresso Intents before each test,
    -+  terminates the host activity,
    -+  and releases Espresso Intents after each test.
    -+</p>
    -+
    -+<p>
    -+  The test class shown in the following codes snippet provides a simple
    -+  test for an explicit intent. It tests the activities and intents created in the
    -+  <a href="{@docRoot}training/basics/firstapp/index.html">Building Your First App</a>
    -+  tutorial.
    -+</p>
    -+
    -+<pre>
    -+&#64;Large
    -+&#64;RunWith(AndroidJUnit4.class)
    -+public class SimpleIntentTest {
    -+
    -+    private static final String MESSAGE = "This is a test";
    -+    private static final String PACKAGE_NAME = "com.example.myfirstapp";
    -+
    -+    /* Instantiate an IntentsTestRule object. */
    -+    &#64;Rule
    -+    public IntentsTestRule&lg;MainActivity&gt; mIntentsRule =
    -+      new IntentsTestRule&lg;&gt;(MainActivity.class);
    -+
    -+    &#64;Test
    -+    public void verifyMessageSentToMessageActivity() {
    -+
    -+        // Types a message into a EditText element.
    -+        onView(withId(R.id.edit_message))
    -+                .perform(typeText(MESSAGE), closeSoftKeyboard());
    -+
    -+        // Clicks a button to send the message to another
    -+        // activity through an explicit intent.
    -+        onView(withId(R.id.send_message)).perform(click());
    -+
    -+        // Verifies that the DisplayMessageActivity received an intent
    -+        // with the correct package name and message.
    -+        intended(allOf(
    -+                hasComponent(hasShortClassName(".DisplayMessageActivity")),
    -+                toPackage(PACKAGE_NAME),
    -+                hasExtra(MainActivity.EXTRA_MESSAGE, MESSAGE)));
    -+
    -+    }
    -+}
    -+</pre>
    -+
    -+<p>
    -+  For more information about Espresso Intents, see the
    -+  <a href="https://google.github.io/android-testing-support-library/docs/espresso/intents/index.html"
    -+  class="external-link">Espresso Intents
    -+  documentation on the Android Testing Support Library site</a>.
    -+  You can also download the
    -+  <a href="https://github.com/googlesamples/android-testing/tree/master/ui/espresso/IntentsBasicSample"
    -+  class="external-link">IntentsBasicSample</a> and
    -+  <a href="https://github.com/googlesamples/android-testing/tree/master/ui/espresso/IntentsAdvancedSample"
    -+  class="external-link">IntentsAdvancedSample</a>
    -+  code samples.
    -+</p>
    -+
    -+<!-- Section 2.5 -->
    -+
    -+<h3 id="webviews">
    -+  Testing WebViews with Espresso Web
    -+</h3>
    -+
    -+<p>
    -+  Espresso Web allows you to test {@link android.webkit.WebView} components
    -+  contained within an activity. It uses the
    -+  <a href="http://docs.seleniumhq.org/docs/03_webdriver.jsp"
    -+  class="external-link">WebDriver API</a> to inspect and control the
    -+  behavior of a {@link android.webkit.WebView}.
    -+</p>
    -+
    -+<p>
    -+  To begin testing with Espresso Web, you need
    -+  to add the following line to your app's build.gradle file:
    -+</p>
    -+
    -+<pre>
    -+dependencies {
    -+  // Other dependencies ...
    -+  androidTestCompile 'com.android.support.test.espresso:espresso-web:2.2.2'
    -+}
    -+</pre>
    -+
    -+<p>
    -+  When creating a test using Espresso Web, you need to enable
    -+  JavaScript on the {@link android.webkit.WebView} when you instantiate the
    -+  <a href="{@docRoot}reference/android/support/test/rule/ActivityTestRule.html">ActivityTestRule</a>
    -+  object to test the activity. In the tests, you can select
    -+  HTML elements displayed in the
    -+  {@link android.webkit.WebView} and simulate user interactions, like
    -+  entering text into a text box and then clicking a button. After the actions
    -+  are completed, you can then verify that the results on the
    -+  Web page match the results that you expect.
    -+</p>
    -+
    -+<p>
    -+  In the following code snippet, the class tests
    -+  a {@link android.webkit.WebView} component with the id value 'webview'
    -+  in the activity being tested.
    -+  The <code>verifyValidInputYieldsSuccesfulSubmission()</code> test selects an
    -+  <code>&lt;input&gt;</code> element on the
    -+  Web page, enters some text, and checks text that appears in
    -+  another element.
    -+</p>
    -+
    -+<pre>
    -+&#64;LargeTest
    -+&#64;RunWith(AndroidJUnit4.class)
    -+public class WebViewActivityTest {
    -+
    -+    private static final String MACCHIATO = "Macchiato";
    -+    private static final String DOPPIO = "Doppio";
    -+
    -+    &#64;Rule
    -+    public ActivityTestRule<WebViewActivity> mActivityRule =
    -+        new ActivityTestRule<WebViewActivity>(WebViewActivity.class,
    -+            false /* Initial touch mode */, false /*  launch activity */) {
    -+
    -+        &#64;Override
    -+        protected void afterActivityLaunched() {
    -+            // Enable JavaScript.
    -+            onWebView().forceJavascriptEnabled();
    -+        }
    -+    }
    -+
    -+    &#64;Test
    -+    public void typeTextInInput_clickButton_SubmitsForm() {
    -+       // Lazily launch the Activity with a custom start Intent per test
    -+       mActivityRule.launchActivity(withWebFormIntent());
    -+
    -+       // Selects the WebView in your layout.
    -+       // If you have multiple WebViews you can also use a
    -+       // matcher to select a given WebView, onWebView(withId(R.id.web_view)).
    -+       onWebView()
    -+           // Find the input element by ID
    -+           .withElement(findElement(Locator.ID, "text_input"))
    -+           // Clear previous input
    -+           .perform(clearElement())
    -+           // Enter text into the input element
    -+           .perform(DriverAtoms.webKeys(MACCHIATO))
    -+           // Find the submit button
    -+           .withElement(findElement(Locator.ID, "submitBtn"))
    -+           // Simulate a click via JavaScript
    -+           .perform(webClick())
    -+           // Find the response element by ID
    -+           .withElement(findElement(Locator.ID, "response"))
    -+           // Verify that the response page contains the entered text
    -+           .check(webMatches(getText(), containsString(MACCHIATO)));
    -+    }
    -+}
    -+</pre>
    -+
    -+<p>
    -+  For more information about Espresso Web, see the
    -+  <a href="https://google.github.io/android-testing-support-library/docs/espresso/web/index.html"
    -+  class="external-link">Espresso
    -+  Web documentation on the Android Testing Support Library site.</a>.
    -+  You can also download this code snippet as part of the
    -+  <a href="https://github.com/googlesamples/android-testing/tree/master/ui/espresso/WebBasicSample"
    -+  class="external-link">Espresso Web code sample</a>.
    -+</p>
    -+
    -+<!-- Section 2.6 -->
    -+
    -+<h3 id="verify-results">
    -+  Verifying Results
    -+</h3>
    -+
    -+<p>
    -+  Call the
    -+  <a href="{@docRoot}reference/android/support/test/espresso/ViewInteraction.html#check(android.support.test.espresso.ViewAssertion)">{@code ViewInteraction.check()}</a>
    -+  or
    -+  <a href="{@docRoot}reference/android/support/test/espresso/DataInteraction.html#check(android.support.test.espresso.ViewAssertion)">{@code DataInteraction.check()}</a>
    -+  method to assert
    -+  that the view in the UI matches some expected state. You must pass in a
    -+  <a href="{@docRoot}reference/android/support/test/espresso/ViewAssertion.html">{@code ViewAssertion}</a>
    -+  object as the argument. If the assertion fails, Espresso throws
    -+  an {@link junit.framework.AssertionFailedError}.
    -+</p>
    -+
    -+<p>
    -+  The
    -   <a href="{@docRoot}reference/android/support/test/espresso/assertion/ViewAssertions.html">{@code ViewAssertions}</a>
    --      class provides a list of helper methods for specifying common
    --      assertions. The assertions you can use include:
    --    </p>
    -+  class provides a list of helper methods for specifying common
    -+  assertions. The assertions you can use include:
    -+</p>
    - 
    --    <ul>
    --      <li>
    --        <a href="{@docRoot}reference/android/support/test/espresso/assertion/ViewAssertions.html#doesNotExist()">{@code doesNotExist}</a>:
    --Asserts that there is no view matching the specified criteria in the current view hierarchy.
    --      </li>
    --
    --      <li>
    --        <a href="{@docRoot}reference/android/support/test/espresso/assertion/ViewAssertions.html#matches(org.hamcrest.Matcher&lt;? super android.view.View&gt;)">{@code matches}</a>:
    --        Asserts that the specified view exists in the current view hierarchy
    --        and its state matches some given Hamcrest matcher.
    --      </li>
    --
    --      <li>
    --       <a href="{@docRoot}reference/android/support/test/espresso/assertion/ViewAssertions.html#selectedDescendantsMatch(org.hamcrest.Matcher&lt;android.view.View&gt;, org.hamcrest.Matcher&lt;android.view.View&gt;)">{@code selectedDescendentsMatch}</a>
    --       : Asserts that the specified children views for a
    --        parent view exist, and their state matches some given Hamcrest matcher.
    --      </li>
    --    </ul>
    -+<ul>
    -+  <li>
    -+    <a href="{@docRoot}reference/android/support/test/espresso/assertion/ViewAssertions.html#doesNotExist()">{@code doesNotExist}</a>:
    -+    Asserts that there is no view matching the specified
    -+    criteria in the current view hierarchy.
    -+  </li>
    -+
    -+  <li>
    -+    <a href="{@docRoot}reference/android/support/test/espresso/assertion/ViewAssertions.html#matches(org.hamcrest.Matcher&lt;? super android.view.View&gt;)">{@code matches}</a>:
    -+    Asserts that the specified view exists in the current view hierarchy
    -+    and its state matches some given Hamcrest matcher.
    -+  </li>
    -+
    -+  <li>
    -+    <a href="{@docRoot}reference/android/support/test/espresso/assertion/ViewAssertions.html#selectedDescendantsMatch(org.hamcrest.Matcher&lt;android.view.View&gt;, org.hamcrest.Matcher&lt;android.view.View&gt;)">{@code selectedDescendentsMatch}</a>:
    -+    Asserts that the specified children views for a
    -+    parent view exist, and their state matches some given Hamcrest matcher.
    -+  </li>
    -+</ul>
    -+
    -+<p>
    -+  The following code snippet shows how you might
    -+  check that the text displayed in the UI has
    -+  the same value as the text previously entered in the
    -+  {@link android.widget.EditText} field.
    -+</p>
    - 
    --    <p>
    --      The following code snippet shows how you might check that the text displayed in the UI has
    --      the same value as the text previously entered in the
    --      {@link android.widget.EditText} field.
    --    </p>
    - <pre>
    - public void testChangeText_sameActivity() {
    -     // Type text and then press the button.
    -@@ -580,14 +804,22 @@ public void testChangeText_sameActivity() {
    - }
    - </pre>
    - 
    --<h2 id="run">Run Espresso Tests on a Device or Emulator</h2>
    -+<!-- Section 3 -->
    -+
    -+<h2 id="run">
    -+  Run Espresso Tests on a Device or Emulator
    -+</h2>
    -+
    - <p>
    --You can run Espresso tests from <a href="{@docRoot}studio/index.html">Android Studio</a> or
    --from the command-line. Make sure to specify
    --<a href="{@docRoot}reference/android/support/test/runner/AndroidJUnitRunner.html">
    --  {@code AndroidJUnitRunner}</a> as the default instrumentation runner in your project.
    -+  You can run Espresso tests from
    -+  <a href="{@docRoot}studio/index.html">Android Studio</a> or
    -+  from the command-line. Make sure to specify
    -+  <a href="{@docRoot}reference/android/support/test/runner/AndroidJUnitRunner.html">{@code AndroidJUnitRunner}</a>
    -+  as the default instrumentation runner in your project.
    - </p>
    -+
    - <p>
    --To run your Espresso test, follow the steps for running instrumented tests
    --described in <a href="{@docRoot}training/testing/start/index.html#run-instrumented-tests">
    --Getting Started with Testing</a>.</p>
    -+  To run your Espresso test, follow the steps for running instrumented tests
    -+  described in
    -+  <a href="{@docRoot}training/testing/start/index.html#run-instrumented-tests">Getting Started with Testing</a>.
    -+</p>
    -diff --git a/docs/html/training/testing/unit-testing/instrumented-unit-tests.jd b/docs/html/training/testing/unit-testing/instrumented-unit-tests.jd
    -index 8fc4dca..dc94bdf 100644
    ---- a/docs/html/training/testing/unit-testing/instrumented-unit-tests.jd
    -+++ b/docs/html/training/testing/unit-testing/instrumented-unit-tests.jd
    -@@ -53,8 +53,9 @@ you choose, to simulate any dependency relationships.</p>
    - 
    - <p>In your Android Studio project, you must store the source files for
    - instrumented tests at
    --<code><var>module-name</var>/src/androidTests/java/</code>. This directory
    --already exists when you create a new project.</p>
    -+<code><var>module-name</var>/src/androidTest/java/</code>. This directory
    -+already exists when you create a new project and contains an example
    -+instrumented test.</p>
    - 
    - <p>Before you begin, you should
    -   <a href="{@docRoot}tools/testing-support-library/index.html#setup">download
    -@@ -292,23 +293,21 @@ from the command line. Test results provide test logs and include the details
    - of any app failures.</p>
    - 
    - <p>
    --  Before you can start using Firebase Test Lab, you need to:
    -+  Before you can start using Firebase Test Lab, you need to do the following
    -+unless you already have a Google account and a Firebase project with the Blaze
    -+billing plan enabled:
    - </p>
    - 
    - <ol>
    --  <li>
    --    <a href="https://console.developers.google.com/freetrial">Create a
    --    Google Cloud Platform account</a> to use with active billing.
    --  </li>
    --
    --  <li>
    --    <a href="https://support.google.com/cloud/answer/6251787">Create a Google
    --    Cloud project</a> for your app.
    --  </li>
    --
    --  <li>
    --    <a href="https://support.google.com/cloud/answer/6288653">Set up an active
    --    billing account</a> and associate it with the project you just created.
    -+  <li><a href="https://accounts.google.com/">Create a Google account</a>,
    -+  if you don't have one already.</li>
    -+  <li>In the <a href="https://console.firebase.google.com/">Firebase
    -+  console</a>, click <b>Create New Project</b>.</li>
    -+  <li>In the Firebase console, click <b>Upgrade</b>, and then click <b>Select
    -+Plan</b> in the <b>Blaze</b> plan column.
    -+    <p class="note"><b>Note</b>: To learn about billing,
    -+see <a href="https://firebase.google.com/docs/test-lab/overview#billing">Test
    -+Lab billing</a>.</p>
    -   </li>
    - </ol>
    - 
    -@@ -318,10 +317,10 @@ Configure a test matrix and run a test
    - </h4>
    - 
    - <p>
    --  Android Studio provides integrated tools that allow you to configure how you
    -- want to deploy your tests to Firebase Test Lab. After you have created a Google
    --  Cloud project with active billing, you can create a test configuration and
    --  run your tests:
    -+Android Studio provides integrated tools that allow you to configure how you
    -+want to deploy your tests to Firebase Test Lab. After you have created a
    -+Firebase project with Blaze plan billing, you can create a test configuration
    -+and run your tests:
    - </p>
    - 
    - <ol>
    -@@ -329,7 +328,8 @@ Configure a test matrix and run a test
    -   the main menu.
    -   </li>
    - 
    --  <li>Click <strong>Add New Configuration (+)</strong> and select
    -+  <li>Click <strong>Add New Configuration</strong> <img
    -+src="/studio/images/buttons/ic_plus.png" alt="" class="inline-icon"/> and select
    -   <strong>Android Tests</strong>.
    -   </li>
    - 
    -@@ -340,7 +340,7 @@ Configure a test matrix and run a test
    -       </li>
    - 
    -       <li>From the <em>Target</em> drop-down menu under <em>Deployment Target
    --      Options</em>, select <strong>Cloud Test Lab Device Matrix</strong>.
    -+      Options</em>, select <strong>Firebase Test Lab Device Matrix</strong>.
    -       </li>
    - 
    -       <li>If you are not logged in, click <strong>Connect to Google Cloud
    -@@ -348,9 +348,9 @@ Configure a test matrix and run a test
    -       </li>
    - 
    -       <li>Next to <em>Cloud Project</em>, click the <img src=
    --      "{@docRoot}images/tools/as-wrench.png" alt="wrench and nut" style=
    --      "vertical-align:bottom;margin:0;"> button and select your Google Cloud
    --      Platform project from the list.
    -+      "{@docRoot}images/tools/as-wrench.png" alt="" class="inline-icon"/>
    -+      button and select your Firebase
    -+      project from the list.
    -       </li>
    -     </ol>
    -   </li>
    -@@ -359,7 +359,7 @@ Configure a test matrix and run a test
    -     <ol type="a">
    -       <li>Next to the <em>Matrix Configuration</em> drop-down list, click <strong>
    -         Open Dialog</strong> <img src="{@docRoot}images/tools/as-launchavdm.png"
    --        alt="ellipses button" style="vertical-align:bottom;margin:0;">.
    -+        alt="" class="inline-icon">.
    -       </li>
    - 
    -       <li>Click <strong>Add New Configuration (+)</strong>.
    -@@ -385,8 +385,7 @@ Configure a test matrix and run a test
    -   </li>
    - 
    -   <li>Run your tests by clicking <strong>Run</strong> <img src=
    --  "{@docRoot}images/tools/as-run.png" alt="" style=
    --  "vertical-align:bottom;margin:0;">.
    -+  "{@docRoot}images/tools/as-run.png" alt="" class="inline-icon"/>.
    -   </li>
    - </ol>
    - 
    -@@ -404,7 +403,7 @@ Configure a test matrix and run a test
    -   When Firebase Test Lab completes running your tests, the <em>Run</em> window
    -   will open to show the results, as shown in figure 2. You may need to click
    -   <strong>Show Passed</strong> <img src="{@docRoot}images/tools/as-ok.png" alt=
    --  "" style="vertical-align:bottom;margin:0;"> to see all your executed tests.
    -+  "" class="inline-icon"/> to see all your executed tests.
    - </p>
    - 
    - <img src="{@docRoot}images/training/ctl-test-results.png" alt="">
    -@@ -416,15 +415,7 @@ Configure a test matrix and run a test
    - 
    - <p>
    -   You can also analyze your tests on the web by following the link displayed at
    --  the beginning of the test execution log in the <em>Run</em> window, as shown
    --  in figure 3.
    --</p>
    --
    --<img src="{@docRoot}images/training/ctl-exec-log.png" alt="">
    --
    --<p class="img-caption">
    --  <strong>Figure 3.</strong> Click the link to view detailed test results on
    --  the web.
    -+  the beginning of the test execution log in the <em>Run</em> window.
    - </p>
    - 
    - <p>
    -diff --git a/docs/html/training/training_toc.cs b/docs/html/training/training_toc.cs
    -index d0dccba..d2bf881 100644
    ---- a/docs/html/training/training_toc.cs
    -+++ b/docs/html/training/training_toc.cs
    -@@ -649,25 +649,7 @@
    -           </li>
    -         </ul>
    -       </li>
    --
    -       <li class="nav-section">
    --        <div class="nav-section-header">
    --          <a href="<?cs var:toroot ?>training/backup/index.html"
    --             description=
    --             "How to sync and back up app and user data to remote web services in the
    --              cloud and how to restore the data back to multiple devices."
    --            >Backing up App Data to the Cloud</a>
    --        </div>
    --        <ul>
    --          <li><a href="<?cs var:toroot ?>training/backup/autosyncapi.html">
    --            Configuring Auto Backup
    --          </a>
    --          </li>
    --          <li><a href="<?cs var:toroot ?>training/backup/backupapi.html">
    --            Using the Backup API
    --          </a>
    --          </li>
    --        </ul>
    -         <li><a href="<?cs var:toroot ?>training/cloudsave/conflict-res.html"
    -            description=
    -            "How to design a robust conflict resolution strategy for apps that save data to the cloud."
    -@@ -1888,6 +1870,12 @@ results."
    -           >Managing Your App's Memory</a>
    -       </li>
    -       <li>
    -+        <a href="<?cs var:toroot ?>training/articles/memory-overview.html"
    -+          description=
    -+          "How Android manages app process and memory allocation."
    -+          >Overview of Android Memory Management</a>
    -+      </li>
    -+      <li>
    -         <a href="<?cs var:toroot ?>training/articles/perf-tips.html"
    -            description=
    -            "How to optimize your app's performance in various ways to improve its
    -diff --git a/docs/html/training/tv/playback/card.jd b/docs/html/training/tv/playback/card.jd
    -index a3a9872..2391185 100644
    ---- a/docs/html/training/tv/playback/card.jd
    -+++ b/docs/html/training/tv/playback/card.jd
    -@@ -43,7 +43,7 @@ Leanback sample app</a> image card view when selected.</p>
    - on demand. In the browse fragment where your app presents its content to the user, you create a
    - {@link android.support.v17.leanback.widget.Presenter} for the content cards and pass it to the adapter
    - that adds the content to the screen. In the following code, the <code>CardPresenter</code> is created
    --in the {@link android.support.v4.app.LoaderManager.LoaderCallbacks#onLoadFinished(android.support.v4.content.Loader, java.lang.Object) onLoadFinished()}
    -+in the {@link android.support.v4.app.LoaderManager.LoaderCallbacks#onLoadFinished onLoadFinished()}
    - callback of the {@link android.support.v4.app.LoaderManager}.</p>
    - 
    - <pre>
    -diff --git a/docs/html/training/tv/playback/index.jd b/docs/html/training/tv/playback/index.jd
    -index d5e4e67..34c6287 100644
    ---- a/docs/html/training/tv/playback/index.jd
    -+++ b/docs/html/training/tv/playback/index.jd
    -@@ -69,6 +69,10 @@ startpage=true
    -     <dd>Learn how to use the Leanback support library to guide a user through a series of
    -     decisions.</dd>
    - 
    -+  <dt><b><a href="onboarding.html">Introducing First-time Users to Your App</a></b></dt>
    -+    <dd>Learn how to use the Leanback support library to show first-time users
    -+    how to get the most out of your app.</dd>
    -+
    -   <dt><b><a href="options.html">Enabling Background Playback</a></b></dt>
    -     <dd>Learn how to continue playback when the user clicks on <strong>Home</strong>.</dd>
    - </dl>
    -diff --git a/docs/html/training/tv/playback/onboarding.jd b/docs/html/training/tv/playback/onboarding.jd
    -new file mode 100644
    -index 0000000..bb41bec
    ---- /dev/null
    -+++ b/docs/html/training/tv/playback/onboarding.jd
    -@@ -0,0 +1,377 @@
    -+page.title=Introducing First-time Users to Your App
    -+page.tags=tv,onboarding,OnboardingFragment
    -+page.keywords=tv,onboarding,OnboardingFragment
    -+helpoutsWidget=true
    -+
    -+trainingnavtop=true
    -+
    -+@jd:body
    -+
    -+<div id="tb-wrapper">
    -+<div id="tb">
    -+  <h2>This lesson teaches you to</h2>
    -+  <ol>
    -+    <li><a href="#addFragment">Add an OnboardingFragment</a></li>
    -+    <li><a href="#pageContent">Add OnboardingFragment Pages</a></li>
    -+    <li><a href="#logoScreen">Add an Initial Logo Screen</a></li>
    -+    <li><a href="#pageAnimations">Customize Page Animations</a></li>
    -+    <li><a href="#themes">Customize Themes</a></li>
    -+  </ol>
    -+  <h2>Try it out</h2>
    -+  <ul>
    -+    <li><a class="external-link" href="https://github.com/googlesamples/androidtv-Leanback">Android
    -+    Leanback sample app</a></li>
    -+  </ul>
    -+</div>
    -+</div>
    -+
    -+<p>
    -+To show a first-time user how to get the most from your app, present
    -+onboarding information at app startup. Here are some examples of onboarding
    -+information:
    -+</p>
    -+
    -+<ul>
    -+<li>Present detailed information on which channels are available when a user
    -+first accesses a channel app.</li>
    -+<li>Call attention to noteworthy features in your app.</li>
    -+<li>Illustrate any required or recommended steps that users should take when
    -+using the app for the first time.</li>
    -+</ul>
    -+
    -+<p>The <a href=
    -+"{@docRoot}tools/support-library/features.html#v17-leanback">v17 Leanback
    -+support library</a> provides the
    -+{@link android.support.v17.leanback.app.OnboardingFragment} class for
    -+presenting first-time user information. This lesson describes how to use the
    -+{@link android.support.v17.leanback.app.OnboardingFragment} class to present
    -+introductory information that is shown when the app launches for the first
    -+time. {@link android.support.v17.leanback.app.OnboardingFragment} uses TV UI
    -+best practices to present the information in a way that matches TV UI styles,
    -+and is easy to navigate on TV devices.</p>
    -+
    -+<img src="{@docRoot}images/training/tv/playback/onboarding-fragment.png"
    -+srcset="{@docRoot}images/training/tv/playback/onboarding-fragment.png 1x,
    -+{@docRoot}images/training/tv/playback/onboarding-fragment_2x.png 2x" />
    -+<p class="img-caption"><strong>Figure 1.</strong> An example
    -+OnboardingFragment.</p>
    -+
    -+<p>Your {@link android.support.v17.leanback.app.OnboardingFragment} should
    -+not contain UI elements that require user input, such as buttons and fields.
    -+Similarly, it should not be used as a UI element for a task the user will do
    -+regularly. If you need to present a multi-page UI that requires
    -+user input, consider using a
    -+{@link android.support.v17.leanback.app.GuidedStepFragment}.</p>
    -+
    -+<h2 id="addFragment">Add an OnboardingFragment</h2>
    -+
    -+<p>To add an {@link android.support.v17.leanback.app.OnboardingFragment}
    -+to your app, implement a class that extends
    -+the {@link android.support.v17.leanback.app.OnboardingFragment} class. Add
    -+this fragment to an activity, either via the activity's layout XML, or
    -+programmatically. Make sure the activity or
    -+fragment is using a theme derived from
    -+{@link android.support.v17.leanback.R.style#Theme_Leanback_Onboarding},
    -+as described in <a href="#themes">Customize Themes</a>.</p>
    -+
    -+<p>In the {@link android.app.Activity#onCreate onCreate()} method of your
    -+app's main activity, call
    -+{@link android.app.Activity#startActivity startActivity()}
    -+with an {@link android.content.Intent} that points to your
    -+{@link android.support.v17.leanback.app.OnboardingFragment OnboardingFragment's}
    -+parent activity. This ensures that your
    -+{@link android.support.v17.leanback.app.OnboardingFragment} appears as
    -+soon as your app starts.<p>
    -+
    -+<p>To ensure that the
    -+{@link android.support.v17.leanback.app.OnboardingFragment} only appears the
    -+first time that the user starts your app, use a
    -+{@link android.content.SharedPreferences} object
    -+to track whether the user has already viewed the
    -+{@link android.support.v17.leanback.app.OnboardingFragment}. Define a boolean
    -+value that changes to true when the user finishes viewing the
    -+{@link android.support.v17.leanback.app.OnboardingFragment}. Check
    -+this value in your main activity’s
    -+{@link android.app.Activity#onCreate onCreate()}, and only start the
    -+{@link android.support.v17.leanback.app.OnboardingFragment} parent activity if
    -+the value is false. The following example shows an override of
    -+{@link android.app.Activity#onCreate onCreate()} that checks for a
    -+{@link android.content.SharedPreferences} value and, if not set to true, calls
    -+{@link android.app.Activity#startActivity startActivity()} to
    -+show the {@link android.support.v17.leanback.app.OnboardingFragment}:</p>
    -+
    -+<pre>
    -+&#64;Override
    -+protected void onCreate(Bundle savedInstanceState) {
    -+    super.onCreate(savedInstanceState);
    -+    setContentView(R.layout.activity_main);
    -+    SharedPreferences sharedPreferences =
    -+            PreferenceManager.getDefaultSharedPreferences(this);
    -+    // Check if we need to display our OnboardingFragment
    -+    if (!sharedPreferences.getBoolean(
    -+            MyOnboardingFragment.COMPLETED_ONBOARDING_PREF_NAME, false)) {
    -+        // The user hasn't seen the OnboardingFragment yet, so show it
    -+        startActivity(new Intent(this, OnboardingActivity.class));
    -+    }
    -+}
    -+</pre>
    -+
    -+<p>After the user views the
    -+{@link android.support.v17.leanback.app.OnboardingFragment}, mark it as viewed
    -+using the {@link android.content.SharedPreferences} object. To do this, in your
    -+{@link android.support.v17.leanback.app.OnboardingFragment}, override
    -+{@link android.support.v17.leanback.app.OnboardingFragment#onFinishFragment
    -+onFinishFragment()} and set your {@link android.content.SharedPreferences} value
    -+to true, as shown in the following example:
    -+
    -+<pre>
    -+&#64;Override
    -+protected void onFinishFragment() {
    -+    super.onFinishFragment();
    -+    // User has seen OnboardingFragment, so mark our SharedPreferences
    -+    // flag as completed so that we don't show our OnboardingFragment
    -+    // the next time the user launches the app.
    -+    SharedPreferences.Editor sharedPreferencesEditor =
    -+            PreferenceManager.getDefaultSharedPreferences(getContext()).edit();
    -+    sharedPreferencesEditor.putBoolean(
    -+            COMPLETED_ONBOARDING_PREF_NAME, true);
    -+    sharedPreferencesEditor.apply();
    -+}
    -+</pre>
    -+
    -+<h2 id="pageContent">Add OnboardingFragment Pages</h2>
    -+
    -+<p>After you add your
    -+{@link android.support.v17.leanback.app.OnboardingFragment}, you need to define
    -+the onboarding pages. An
    -+{@link android.support.v17.leanback.app.OnboardingFragment} displays content
    -+in a series of ordered pages. Each page can have a title, description, and
    -+several sub-views that can contain images or animations.</p>
    -+
    -+<img src="{@docRoot}images/training/tv/playback/onboarding-fragment-diagram.png"
    -+/><p class="img-caption"><strong>Figure 2.</strong> OnboardingFragment
    -+page elements.
    -+</p>
    -+
    -+<p>Figure 2 shows an example page with callouts marking customizable page
    -+elements that your {@link android.support.v17.leanback.app.OnboardingFragment}
    -+can provide. The page elements are:</p>
    -+
    -+<ol>
    -+<li>The page title.</li>
    -+<li>The page description.</li>
    -+<li>The page content view, in this case a simple green checkmark in a grey box.
    -+This view is optional. Use this view to illustrate page details such as a
    -+screenshot that highlights the app feature that the page describes.</li>
    -+<li>The page background view, in this case a simple blue gradient. This view
    -+always renders behind other views on the page. This view is optional.</li>
    -+<li>The page foreground view, in this case a logo. This view always renders
    -+in front of all other views on the page. This view is optional.</li>
    -+</ol>
    -+
    -+<p>Initialize page information when your
    -+{@link android.support.v17.leanback.app.OnboardingFragment} is first created
    -+or attached to the parent activity, as the system requests page
    -+information when it creates the fragment's view. You can initialize page
    -+information in your class constructor or in an override of
    -+{@link android.app.Fragment#onAttach onAttach()}.</p>
    -+
    -+<p>Override each of the following methods that provide page information
    -+to the system:</p>
    -+
    -+<ul>
    -+<li>{@link android.support.v17.leanback.app.OnboardingFragment#getPageCount
    -+getPageCount()} returns the number of pages in your
    -+{@link android.support.v17.leanback.app.OnboardingFragment}.</li>
    -+<li>{@link android.support.v17.leanback.app.OnboardingFragment#getPageTitle
    -+getPageTitle()} returns the title for the requested page number.</li>
    -+<li>{@link android.support.v17.leanback.app.OnboardingFragment#getPageDescription
    -+getPagedescription()} returns the description for the requested page
    -+number.</li>
    -+</ul>
    -+
    -+<p>Override each of the following methods to provide optional sub-views used
    -+to display images or animations:</p>
    -+
    -+<ul>
    -+<li>{@link android.support.v17.leanback.app.OnboardingFragment#onCreateBackgroundView
    -+onCreateBackgroundView()} returns a {@link android.view.View} that you
    -+create to act as the background view, or null if no background view is needed.
    -+<li>{@link android.support.v17.leanback.app.OnboardingFragment#onCreateContentView
    -+onCreateContentView()} returns a {@link android.view.View} that you
    -+create to act as the content view, or null if no content view is needed.
    -+<li>{@link android.support.v17.leanback.app.OnboardingFragment#onCreateForegroundView
    -+onCreateForegroundView()} returns a {@link android.view.View} that you
    -+create to act as the foreground view, or null if no foreground view is needed.
    -+</ul>
    -+
    -+<p>The system adds the {@link android.view.View} that you create to the page
    -+layout. The following example overrides
    -+{@link android.support.v17.leanback.app.OnboardingFragment#onCreateContentView
    -+onCreateContentView()} and returns an {@link android.widget.ImageView}:</p>
    -+
    -+<pre>
    -+private ImageView mContentView;
    -+...
    -+&#64;Override
    -+protected View onCreateContentView(LayoutInflater inflater, ViewGroup container) {
    -+    mContentView = new ImageView(getContext());
    -+    mContentView.setScaleType(ImageView.ScaleType.CENTER_INSIDE);
    -+    mContentView.setImageResource(R.drawable.onboarding_content_view);
    -+    mContentView.setPadding(0, 32, 0, 32);
    -+    return mContentView;
    -+}
    -+</pre>
    -+
    -+<h2 id="logoScreen">Add an Initial Logo Screen</h2>
    -+
    -+<p>Your {@link android.support.v17.leanback.app.OnboardingFragment} can start
    -+with an optional logo screen that introduces your app. If you want to display
    -+a {@link android.graphics.drawable.Drawable} as your logo screen, in your
    -+{@link android.support.v17.leanback.app.OnboardingFragment OnboardingFragment's}
    -+{@link android.app.Fragment#onCreate onCreate()} method, call
    -+{@link android.support.v17.leanback.app.OnboardingFragment#setLogoResourceId
    -+setLogoResourceId()} with the ID of your
    -+{@link android.graphics.drawable.Drawable}. The
    -+system will fade in and briefly display this
    -+{@link android.graphics.drawable.Drawable}, and then fade out the
    -+{@link android.graphics.drawable.Drawable}
    -+before displaying the first page of your
    -+{@link android.support.v17.leanback.app.OnboardingFragment}.</p>
    -+
    -+<p>If you want to provide a custom animation for your logo screen, instead of
    -+calling
    -+{@link android.support.v17.leanback.app.OnboardingFragment#setLogoResourceId
    -+setLogoResourceId()}, override
    -+{@link android.support.v17.leanback.app.OnboardingFragment#onCreateLogoAnimation
    -+onCreateLogoAnimation()} and return an {@link android.animation.Animator}
    -+object that renders your custom animation, as shown in the following example:
    -+</p>
    -+
    -+<pre>
    -+&#64;Override
    -+public Animator onCreateLogoAnimation() {
    -+    return AnimatorInflater.loadAnimator(mContext,
    -+            R.animator.onboarding_logo_screen_animation);
    -+}
    -+</pre>
    -+
    -+<h2 id="pageAnimations">Customize Page Animations</h2>
    -+
    -+<p>The system uses default animations when displaying the first page of your
    -+{@link android.support.v17.leanback.app.OnboardingFragment} and when the user
    -+navigates to a different page. You can customize these animations by
    -+overriding methods in your
    -+{@link android.support.v17.leanback.app.OnboardingFragment}.</p>
    -+
    -+<p>To customize the animation that appears on your first page,
    -+override
    -+{@link android.support.v17.leanback.app.OnboardingFragment#onCreateEnterAnimation
    -+onCreateEnterAnimation()} and return an {@link android.animation.Animator}.
    -+The following example creates an
    -+{@link android.animation.Animator} that scales the content view
    -+horizontally:</p>
    -+
    -+<pre>
    -+&#64;Override
    -+protected Animator onCreateEnterAnimation() {
    -+    Animator startAnimator = ObjectAnimator.ofFloat(mContentView,
    -+            View.SCALE_X, 0.2f, 1.0f).setDuration(ANIMATION_DURATION);
    -+    return startAnimator;
    -+}
    -+</pre>
    -+
    -+<p>To customize the animation used when the user navigates to a different page,
    -+override
    -+{@link android.support.v17.leanback.app.OnboardingFragment#onPageChanged
    -+onPageChanged()}. In your
    -+{@link android.support.v17.leanback.app.OnboardingFragment#onPageChanged
    -+onPageChanged()} method, create {@link android.animation.Animator Animators}
    -+that remove the previous page and display the next page, add these to an
    -+{@link android.animation.AnimatorSet}, and play the set. The following
    -+example uses a fade-out animation to remove the previous page, updates the
    -+content view image, and uses a fade-in animation to display the next page:</p>
    -+
    -+<pre>
    -+&#64;Override
    -+protected void onPageChanged(final int newPage, int previousPage) {
    -+    // Create a fade-out animation used to fade out previousPage and, once
    -+    // done, swaps the contentView image with the next page's image.
    -+    Animator fadeOut = ObjectAnimator.ofFloat(mContentView,
    -+            View.ALPHA, 1.0f, 0.0f).setDuration(ANIMATION_DURATION);
    -+    fadeOut.addListener(new AnimatorListenerAdapter() {
    -+        &#64;Override
    -+        public void onAnimationEnd(Animator animation) {
    -+            mContentView.setImageResource(pageImages[newPage]);
    -+        }
    -+    });
    -+    // Create a fade-in animation used to fade in nextPage
    -+    Animator fadeIn = ObjectAnimator.ofFloat(mContentView,
    -+            View.ALPHA, 0.0f, 1.0f).setDuration(ANIMATION_DURATION);
    -+    // Create AnimatorSet with our fade-out and fade-in animators, and start it
    -+    AnimatorSet set = new AnimatorSet();
    -+    set.playSequentially(fadeOut, fadeIn);
    -+    set.start();
    -+}
    -+</pre>
    -+
    -+<p>For more details about how to create
    -+{@link android.animation.Animator Animators} and
    -+{@link android.animation.AnimatorSet AnimatorSets}, see
    -+<a href="https://developer.android.com/guide/topics/graphics/prop-animation.html">
    -+Property Animations</a>.</p>
    -+
    -+<h2 id="themes">Customize Themes</h2>
    -+
    -+<p>Any {@link android.support.v17.leanback.app.OnboardingFragment}
    -+implementation must use either the
    -+{@link android.support.v17.leanback.R.style#Theme_Leanback_Onboarding} theme
    -+or a theme that inherits from
    -+{@link android.support.v17.leanback.R.style#Theme_Leanback_Onboarding}. Set the
    -+theme for your {@link android.support.v17.leanback.app.OnboardingFragment} by
    -+doing one of the following:</p>
    -+
    -+<ul>
    -+<li>Set the {@link android.support.v17.leanback.app.OnboardingFragment
    -+OnboardingFragment's} parent activity to use the desired theme. The following
    -+example shows how to set an activity to use
    -+{@link android.support.v17.leanback.R.style#Theme_Leanback_Onboarding} in the
    -+app manifest:
    -+<pre>
    -+&lt;activity
    -+   android:name=".OnboardingActivity"
    -+   android:enabled="true"
    -+   android:exported="true"
    -+   android:theme="&#64;style/Theme.Leanback.Onboarding"&gt;
    -+&lt;/activity&gt;
    -+</pre>
    -+</li>
    -+<li>
    -+Set the theme in the parent activity by using the
    -+{@link android.support.v17.leanback.R.styleable#LeanbackOnboardingTheme_onboardingTheme}
    -+attribute in a custom activity theme. Point this attribute to another
    -+custom theme that only the
    -+{@link android.support.v17.leanback.app.OnboardingFragment}
    -+objects in your activity use. Use this approach if your activity already uses
    -+a custom theme and you don't want to apply
    -+{@link android.support.v17.leanback.app.OnboardingFragment} styles to other
    -+views in the activity.
    -+</li>
    -+<li>Override
    -+{@link android.support.v17.leanback.app.OnboardingFragment#onProvideTheme
    -+onProvideTheme()} and return the desired theme. Use this approach if
    -+multiple activities use your
    -+{@link android.support.v17.leanback.app.OnboardingFragment}
    -+or if the parent activity can't use the desired theme.
    -+The following example overrides
    -+{@link android.support.v17.leanback.app.OnboardingFragment#onProvideTheme
    -+onProvideTheme()} and returns
    -+{@link android.support.v17.leanback.R.style#Theme_Leanback_Onboarding}:
    -+<pre>
    -+&#64;Override
    -+public int onProvideTheme() {
    -+   return R.style.Theme_Leanback_Onboarding;
    -+}
    -+</pre>
    -+</li>
    -+</ul>
    -\ No newline at end of file
    -diff --git a/docs/html/training/tv/start/hardware.jd b/docs/html/training/tv/start/hardware.jd
    -index 97cf7ff..0639871 100644
    ---- a/docs/html/training/tv/start/hardware.jd
    -+++ b/docs/html/training/tv/start/hardware.jd
    -@@ -227,13 +227,19 @@ if (uiModeManager.getCurrentModeType() == Configuration.UI_MODE_TYPE_TELEVISION)
    -   </tr>
    -   <tr>
    -     <td>{@link android.Manifest.permission#ACCESS_COARSE_LOCATION}</td>
    --    <td>{@code android.hardware.location} <em>and</em> <br>
    --      {@code android.hardware.location.network}</td>
    -+    <td>
    -+      <p>{@code android.hardware.location}</p>
    -+      <p>{@code android.hardware.location.network} (Target API level 20 or lower
    -+      only.)</p>
    -+    </td>
    -   </tr>
    -   <tr>
    -     <td>{@link android.Manifest.permission#ACCESS_FINE_LOCATION}</td>
    --    <td>{@code android.hardware.location} <em>and</em> <br>
    --      {@code android.hardware.location.gps}</td>
    -+    <td>
    -+      <p>{@code android.hardware.location}</p>
    -+      <p>{@code android.hardware.location.gps} (Target API level 20 or lower
    -+      only.)</p>
    -+    </td>
    -   </tr>
    - </table>
    - 
    -@@ -246,6 +252,13 @@ if (uiModeManager.getCurrentModeType() == Configuration.UI_MODE_TYPE_TELEVISION)
    -   required ({@code android:required="false"}).
    - </p>
    - 
    -+<p class="note">
    -+  <strong>Note:</strong> If your app targets Android 5.0 (API level 21) or
    -+  higher and uses the <code>ACCESS_COARSE_LOCATION</code> or
    -+  <code>ACCESS_FINE_LOCATION</code> permission, users can still install your
    -+  app on a TV device, even if the TV device doesn't have a network card or a GPS
    -+  receiver.
    -+</p>
    - 
    - <h3 id="check-features">Checking for hardware features</h2>
    - 
    -diff --git a/docs/html/training/tv/tif/tvinput.jd b/docs/html/training/tv/tif/tvinput.jd
    -index 1a53398..2153ef8 100644
    ---- a/docs/html/training/tv/tif/tvinput.jd
    -+++ b/docs/html/training/tv/tif/tvinput.jd
    -@@ -10,9 +10,8 @@ trainingnavtop=true
    - <div id="tb">
    -   <h2>This lesson teaches you to</h2>
    -   <ol>
    --    <li><a href="#manifest">Declare Your TV Input Service in the Manifest</a></li>
    --    <li><a href="#tvinput">Define Your TV Input Service</a></li>
    --    <li><a href="#setup">Define Your Setup Activity</a></li>
    -+    <li><a href="#TIFCompanion">Create a TV Input Service Using the TIF Companion Library</a></li>
    -+    <li><a href="#NoTIFCompanion">Create a TV Input Service Using the TIF Framework</a></li>
    -   </ol>
    -   <h2>You should also read</h2>
    -   <ul>
    -@@ -30,14 +29,253 @@ trainingnavtop=true
    - </div>
    - 
    - <p>A TV input service represents a media stream source, and lets you present your media content in a
    --linear, broadcast TV fashion as channels and programs. With the TV input service, you can provide
    -+linear, broadcast TV fashion as channels and programs. With a TV input service, you can provide
    - parental controls, program guide information, and content ratings. The TV input service works
    --with the Android system TV app, developed for the device and immutable by third-party apps, which
    --ultimately controls and presents content on the TV. See
    -+with the Android system TV app. This app ultimately controls and presents channel content
    -+on the TV. The system TV app is developed specifically for the device and immutable
    -+by third-party apps. For more information about the TV Input Framework (TIF)
    -+architecture and its components, see
    - <a class="external-link" href="http://source.android.com/devices/tv/index.html">
    --TV Input Framework</a> for more information about the framework architecture and its components.</p>
    -+TV Input Framework</a>.</p>
    - 
    --<p>To develop a TV input service, you implement the following components:</p>
    -+<h2 id="TIFCompanion">Create a TV Input Service Using the TIF Companion Library</h2>
    -+
    -+<p>
    -+The TIF Companion Library is a framework that provides extensible
    -+implementations of common TV input service features. Use the TIF Companion
    -+Library to quickly and easily create your own TV input service that follows
    -+best practices for Android TV.
    -+</p>
    -+
    -+<h3 id="build">Update your build.gradle file</h3>
    -+
    -+<p>
    -+To get started using the TIF Companion Library, add the following line to your
    -+app's <code>build.gradle</code> file:
    -+</p>
    -+
    -+<pre>
    -+compile 'com.google.android.media.tv.companionlibrary:1.0.0'
    -+</pre>
    -+
    -+<p>The TIF Companion Library is not currently part of the Android
    -+framework. It is distributed as part of the <a class="external-link"
    -+href="https://github.com/googlesamples/androidtv-sample-inputs">
    -+TV Input Service sample app</a>, and not with the Android SDK.
    -+</p>
    -+
    -+<h3 id="manifest">Declare your TV input service in the manifest</h3>
    -+
    -+<p>Your app must provide a {@link android.media.tv.TvInputService}-compatible
    -+service that the system uses to access your app. The TIF
    -+Companion Library provides the <code>BaseTvInputService</code> class, which
    -+provides a default implementation of {@link android.media.tv.TvInputService}
    -+that you can customize. Create a subclass of <code>BaseTvInputService</code>,
    -+and declare the subclass in your manifest as a service.</p>
    -+
    -+<p>Within the manifest declaration, specify the
    -+{@link android.Manifest.permission#BIND_TV_INPUT} permission to allow the
    -+service to connect the TV input to the system. A system service
    -+performs the binding and has the
    -+{@link android.Manifest.permission#BIND_TV_INPUT} permission.
    -+The system TV app sends requests to TV input services
    -+via the {@link android.media.tv.TvInputManager} interface.</p>
    -+
    -+<p>In your service declaration, include an intent filter that specifies
    -+{@link android.media.tv.TvInputService} as the action to perform with the
    -+intent. Also declare the service metadata as a separate XML resource. The
    -+service declaration, intent filter, and service metadata declaration are shown
    -+in the following example:</p>
    -+
    -+<pre>
    -+&lt;service android:name=".rich.RichTvInputService"
    -+    android:label="@string/rich_input_label"
    -+    android:permission="android.permission.BIND_TV_INPUT"&gt;
    -+    &lt;!-- Required filter used by the system to launch our account service. --&gt;
    -+    &lt;intent-filter&gt;
    -+        &lt;action android:name="android.media.tv.TvInputService" /&gt;
    -+    &lt;/intent-filter&gt;
    -+    &lt;!-- An XML file which describes this input. This provides pointers to
    -+    the RichTvInputSetupActivity to the system/TV app. --&gt;
    -+    &lt;meta-data
    -+        android:name="android.media.tv.input"
    -+        android:resource="@xml/richtvinputservice" /&gt;
    -+&lt;/service&gt;
    -+</pre>
    -+
    -+<p>Define the service metadata in a separate XML file. The service
    -+metadata XML file must include a setup interface that describes the TV input's
    -+initial configuration and channel scan. The metadata file should also contain a
    -+flag stating whether or not users are able to record content. For more
    -+information on how to support recording content in your app, see
    -+<a href="{@docRoot}preview/features/tv-recording-api.html">TV Recording</a>.
    -+</p>
    -+
    -+<p>The service metadata file is located in the XML resources directory
    -+for your app and must match the name of the resource you declared in the
    -+manifest. Using the manifest entries from the previous example, you would
    -+create the XML file at <code>res/xml/richtvinputservice.xml</code>, with the
    -+following contents:</p>
    -+
    -+<pre>
    -+&lt;?xml version="1.0" encoding="utf-8"?&gt;
    -+&lt;tv-input xmlns:android="http://schemas.android.com/apk/res/android"
    -+  android:canRecord="true"
    -+  android:setupActivity="com.example.android.sampletvinput.rich.RichTvInputSetupActivity" /&gt;
    -+</pre>
    -+
    -+<h3 id="setup">Define channels and create your setup activity</h3>
    -+
    -+<p>Your TV input service must define at least one channel that users
    -+access via the system TV app. You should register your channels
    -+in the system database, and provide a setup activity that the system
    -+invokes when it cannot find a channel for your app.</p>
    -+
    -+<p>First, enable your app to read from and write to the system Electronic
    -+Programming Guide (EPG), whose data includes channels and programs available
    -+to the user. To enable your app to perform these actions, and sync with the
    -+EPG after device restart, add the following elements to your app manifest:</p>
    -+
    -+<pre>
    -+&lt;uses-permission android:name="com.android.providers.tv.permission.READ_EPG_DATA" /&gt;
    -+&lt;uses-permission android:name="com.android.providers.tv.permission.WRITE_EPG_DATA" /&gt;
    -+&lt;uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED "/&gt;
    -+</pre>
    -+
    -+<p>Add the following element to ensure that your app shows up in the
    -+Google Play Store as an app that provides content channels in Android TV:</p>
    -+
    -+<pre>
    -+&lt;uses-feature
    -+    android:name="android.software.live_tv"
    -+    android:required="true" /&gt;
    -+</pre>
    -+
    -+<p>Next, create a class which extends the <code>EpgSyncJobService</code>
    -+class. This abstract class makes it easy to create a job service that
    -+creates and updates channels in the system database.</p>
    -+
    -+<p>In your subclass, create and return your full list of channels in
    -+<code>getChannels()</code>. If your channels come from an XMLTV file,
    -+use the <code>XmlTvParser</code> class. Otherwise generate
    -+channels programmatically using the <code>Channel.Builder</code> class.
    -+</p>
    -+
    -+<p>For each channel, the system calls <code>getProgramsForChannel()</code>
    -+when it needs a list of programs that can be viewed within a given time window
    -+on the channel. Return a list of <code>Program</code> objects for the
    -+channel. Use the <code>XmlTvParser</code> class to obtain programs from an
    -+XMLTV file, or generate them programmatically using the
    -+<code>Program.Builder</code> class.</p>
    -+
    -+<p>For each <code>Program</code> object, use an
    -+<code>InternalProviderData</code> object to set program information such as the
    -+program's video type. If you only have a limited number of programs that you
    -+want the channel to repeat in a loop, use the
    -+<code>InternalProviderData.setRepeatable()</code> method with a value of
    -+<code>true</code> when setting information about your program.</p>
    -+
    -+<p>After you've implemented the job service, add it to your app manifest:</p>
    -+
    -+<pre>
    -+&lt;service
    -+    android:name=".sync.SampleJobService"
    -+    android:permission="android.permission.BIND_JOB_SERVICE"
    -+    android:exported="true" /&gt;
    -+</pre>
    -+
    -+<p>Finally, create a setup activity. Your setup activity should provide a way
    -+to sync channel and program data. One way to do this is for the user to do it
    -+via the UI in the activity. You might also have the app do it automatically
    -+when the activity starts. When the setup activity needs to sync channel and
    -+program info, the app should start the job service:</p>
    -+
    -+<pre>
    -+String inputId = getActivity().getIntent().getStringExtra(TvInputInfo.EXTRA_INPUT_ID);
    -+EpgSyncJobService.cancelAllSyncRequests(getActivity());
    -+EpgSyncJobService.requestImmediateSync(getActivity(), inputId,
    -+        new ComponentName(getActivity(), SampleJobService.class));
    -+</pre>
    -+
    -+<p>Use the <code>requestImmediateSync()</code> method to sync
    -+the job service. The user must wait for the sync to finish, so you should
    -+keep your request period relatively short.</p>
    -+
    -+<p>Use the <code>setUpPeriodicSync()</code> method to have the job service
    -+periodically sync channel and program data in the background:</p>
    -+
    -+<pre>
    -+EpgSyncJobService.setUpPeriodicSync(context, inputId,
    -+        new ComponentName(context, SampleJobService.class));
    -+</pre>
    -+
    -+<p>The TIF Companion Library provides an additional overloaded method of
    -+<code>requestImmediateSync()</code> that lets you specify the duration of
    -+channel data to sync in milliseconds. The default method syncs one hour's
    -+worth of channel data.
    -+</p>
    -+
    -+<p>The TIF Companion Library also provides an additional overloaded method of
    -+<code>setUpPeriodicSync()</code> that lets you specify the duration of
    -+channel data to sync, and how often the periodic sync should occur. The
    -+default method syncs 48 hours of channel data every 12 hours.
    -+</p>
    -+
    -+<p>For more details about channel data and the EPG, see
    -+<a href="{@docRoot}training/tv/tif/channel.html"> Working with Channel Data</a>.
    -+</p>
    -+
    -+<h3 id="playback">Handle tuning requests and media playback</h3>
    -+
    -+<p>When a user selects a specific channel, the system TV app uses a
    -+<code>Session</code>, created by your app, to tune to the requested channel
    -+and play content. The TIF Companion Library provides several
    -+classes you can extend to handle channel and session calls from the system.</p>
    -+
    -+<p>Your <code>BaseTvInputService</code> subclass creates sessions which handle
    -+tuning requests. Override the
    -+<code>onCreateSession()</code> method, create a session extended from
    -+the <code>BaseTvInputService.Session</code> class, and call
    -+<code>super.sessionCreated()</code> with your new session. In the following
    -+example, <code>onCreateSession()</code> returns a
    -+<code>RichTvInputSessionImpl</code> object that extends
    -+<code>BaseTvInputService.Session</code>:</p>
    -+
    -+<pre>
    -+&#64;Override
    -+public final Session onCreateSession(String inputId) {
    -+    RichTvInputSessionImpl session = new RichTvInputSessionImpl(this, inputId);
    -+    session.setOverlayViewEnabled(true);
    -+    return super.sessionCreated(session);
    -+}
    -+</pre>
    -+
    -+<p>When the user uses the system TV app to start viewing one of your channels,
    -+the system calls your session's <code>onPlayChannel()</code> method. Override
    -+this method if you need to do any special channel initialization before the
    -+program starts playing.</p>
    -+
    -+<p>The system then obtains the currently scheduled program and calls your
    -+session's <code>onPlayProgram()</code> method, specifying the program
    -+information and start time in milliseconds. Use the
    -+<code>TvPlayer</code> interface to start playing the program.</p>
    -+
    -+<p>Your media player code should implement <code>TvPlayer</code> to handle
    -+specific playback events. The <code>TvPlayer</code> class handles features
    -+like time-shifting controls without adding complexity to your
    -+<code>BaseTvInputService</code> implementation.</p>
    -+
    -+<p>In your session's <code>getTvPlayer()</code> method, return
    -+your media player that implements <code>TvPlayer</code>. The
    -+<a class="external-link"
    -+href="https://github.com/googlesamples/androidtv-sample-inputs">
    -+TV Input Service sample app</a> implements a media player that uses
    -+<a href="{@docRoot}guide/topics/media/exoplayer.html">ExoPlayer</a>.</p>
    -+
    -+<h2 id="NoTIFCompanion">Create a TV Input Service Using the TIF Framework</h2>
    -+
    -+<p>If your TV input service can't use the TIF Companion Library, you need
    -+to implement the following components:</p>
    - 
    - <ul>
    -   <li>{@link android.media.tv.TvInputService} provides long-running and background availability for
    -@@ -56,43 +294,18 @@ TV Input Framework</a> for more information about the framework architecture and
    -   the interaction with TV inputs and apps</li>
    - </ul>
    - 
    --<h2 id="manifest">Declare Your TV Input Service in the Manifest</h2>
    --
    --<p>Your app manifest must declare your {@link android.media.tv.TvInputService}. Within that
    --declaration, specify the {@link android.Manifest.permission#BIND_TV_INPUT} permission to allow the
    --service to connect the TV input to the system. A system service (<code>TvInputManagerService</code>)
    --performs the binding and has that permission. The system TV app sends requests to TV input services
    --via the {@link android.media.tv.TvInputManager} interface. The service declaration must also
    --include an intent filter that specifies the {@link android.media.tv.TvInputService}
    --as the action to perform with the intent. Also within the service declaration, declare the service
    --meta data in a separate XML resource. The service declaration, the intent filter and the service
    --meta data are described in the following example.</p>
    --
    --<pre>
    --&lt;service android:name="com.example.sampletvinput.SampleTvInput"
    --    android:label="@string/sample_tv_input_label"
    --    android:permission="android.permission.BIND_TV_INPUT"&gt;
    --    &lt;intent-filter&gt;
    --        &lt;action android:name="android.media.tv.TvInputService" /&gt;
    --    &lt;/intent-filter&gt;
    --    &lt;meta-data android:name="android.media.tv.input"
    --      android:resource="@xml/sample_tv_input" /&gt;
    --&lt;/service&gt;
    --</pre>
    --
    --<p>Define the service meta data in separate XML file, as shown in the following example. The service
    --meta data must include a setup interface that describes the TV input's initial configuration and
    --channel scan. The service meta data file is located in the XML resources directory
    --for your application and must match the name of the resource in the manifest. Using the example
    --manifest entries above, you would create an XML file in the location
    --<code>res/xml/sample_tv_input.xml</code>, with the following contents:</p>
    -+<p>You also need to do the following:</p>
    - 
    --<pre>
    --&lt;tv-input xmlns:android="http://schemas.android.com/apk/res/android"
    --  android:setupActivity="com.example.sampletvinput.SampleTvInputSetupActivity" /&gt;
    --</pre>
    -+<ol>
    -+<li>Declare your TV input service in the manifest, as
    -+described in <a href="#manifest">Declare your TV input service in the
    -+manifest</a>.</li>
    -+<li>Create the service metadata file.</li>
    -+<li>Create and register your channel and program information.</li>
    -+<li>Create your setup activity.</li>
    -+</ol>
    - 
    --<h2 id="tvinput">Define Your TV Input Service</h2>
    -+<h3 id="tvinput">Define your TV input service</h3>
    - 
    - <div class="figure">
    - <img id="tvinputlife" src="{@docRoot}images/tv/tvinput-life.png" alt=""/>
    -@@ -102,7 +315,7 @@ manifest entries above, you would create an XML file in the location
    - <p>For your service, you extend the {@link android.media.tv.TvInputService} class. A
    - {@link android.media.tv.TvInputService} implementation is a
    - <a href="{@docRoot}guide/components/bound-services.html">bound service</a> where the system service
    --(<code>TvInputManagerService</code>) is the client that binds to it. The service life cycle methods
    -+is the client that binds to it. The service life cycle methods
    - you need to implement are illustrated in figure 1.</p>
    - 
    - <p>The {@link android.app.Service#onCreate()} method initializes and starts the
    -@@ -145,7 +358,8 @@ you may want to handle in your TV input service.</p>
    - 
    - <p>The {@link android.media.tv.TvInputService} creates a
    - {@link android.media.tv.TvInputService.Session} that implements {@link android.os.Handler.Callback}
    --to handle player state changes. With {@link android.media.tv.TvInputService.Session#onSetSurface(android.view.Surface) onSetSurface()},
    -+to handle player state changes. With
    -+{@link android.media.tv.TvInputService.Session#onSetSurface(android.view.Surface) onSetSurface()},
    - the {@link android.media.tv.TvInputService.Session} sets the {@link android.view.Surface} with the
    - video content. See <a href="{@docRoot}training/tv/tif/ui.html#surface">Integrate Player with Surface</a>
    - for more information about working with {@link android.view.Surface} to render video.</p>
    -@@ -153,16 +367,16 @@ for more information about working with {@link android.view.Surface} to render v
    - <p>The {@link android.media.tv.TvInputService.Session} handles the
    - {@link android.media.tv.TvInputService.Session#onTune(android.net.Uri) onTune()}
    - event when the user selects a channel, and notifies the system TV app for changes in the content and
    --content meta data. These <code>notify()</code> methods are described in
    -+content metadata. These <code>notify()</code> methods are described in
    - <a href="{@docRoot}training/tv/tif/ui.html#control">
    - Control Content</a> and <a href="{@docRoot}training/tv/tif/ui.html#track">Handle Track Selection</a>
    - further in this training.</p>
    - 
    --<h2 id="setup">Define Your Setup Activity</h2>
    -+<h3 id="setup">Define your setup activity</h3>
    - 
    - <p>The system TV app works with the setup activity you define for your TV input. The
    - setup activity is required and must provide at least one channel record for the system database. The
    --system TV app will invoke the setup activity when it cannot find a channel for the TV input.
    -+system TV app invokes the setup activity when it cannot find a channel for the TV input.
    - <p>The setup activity describes to the system TV app the channels made available through the TV
    - input, as demonstrated in the next lesson, <a href="{@docRoot}training/tv/tif/channel.html">Creating
    --and Updating Channel Data</a>.</p>
    -+and Updating Channel Data</a>.</p>
    -\ No newline at end of file
    -diff --git a/docs/html/training/volley/index.jd b/docs/html/training/volley/index.jd
    -index a8c4b84..d3645d9 100755
    ---- a/docs/html/training/volley/index.jd
    -+++ b/docs/html/training/volley/index.jd
    -@@ -42,7 +42,7 @@ faster. Volley is available through the open
    - <li>Automatic scheduling of network requests.</li>
    - <li>Multiple concurrent network connections.</li>
    - <li>Transparent disk and memory response caching with standard HTTP
    --<a href=http://en.wikipedia.org/wiki/Cache_coherence">cache coherence</a>.</li>
    -+<a href="http://en.wikipedia.org/wiki/Cache_coherence">cache coherence</a>.</li>
    - <li>Support for request prioritization.</li>
    - <li>Cancellation request API. You can cancel a single request, or you can set blocks or
    - scopes of requests to cancel.</li>
    -@@ -66,13 +66,22 @@ alternative like {@link android.app.DownloadManager}.</p>
    - <a href="https://android.googlesource.com/platform/frameworks/volley">AOSP</a>
    - repository at {@code frameworks/volley} and contains the main request dispatch pipeline
    - as well as a set of commonly applicable utilities, available in the Volley "toolbox." The
    --easiest way to add Volley to your project is to clone the Volley repository and set it as
    --a library project:</p>
    -+easiest way to add Volley to your project is to add the following dependency to your app's
    -+build.gradle file:
    -+
    -+<pre class="no-pretty-print">
    -+dependencies {
    -+    ...
    -+    compile 'com.android.volley:volley:1.0.0'
    -+}
    -+</pre>
    -+
    -+You can also clone the Volley repository and set it as a library project:</p>
    - 
    - <ol>
    - <li>Git clone the repository by typing the following at the command line:
    - 
    --<pre>
    -+<pre class="no-pretty-print">
    - git clone https://android.googlesource.com/platform/frameworks/volley
    - </pre>
    - </li>
    -diff --git a/docs/html/training/wearables/data-layer/messages.jd b/docs/html/training/wearables/data-layer/messages.jd
    -index ef9bfb1..8c4b730 100644
    ---- a/docs/html/training/wearables/data-layer/messages.jd
    -+++ b/docs/html/training/wearables/data-layer/messages.jd
    -@@ -10,12 +10,6 @@ page.title=Sending and Receiving Messages
    -   <li><a href="#SendMessage">Send a Message</a></li>
    -   <li><a href="#ReceiveMessage">Receive a Message</a></li>
    - </ol>
    --<h2>Try it out</h2>
    --<ul>
    --  <li>
    --    <a href="https://github.com/googlesamples/android-FindMyPhone/" class="external-link">FindMyPhone</a>
    --  </li>
    --</ul>
    - </div>
    - </div>
    - 
    -@@ -27,6 +21,7 @@ and attach the following items to the message:</p>
    -   <li>An arbitrary payload (optional)</li>
    -   <li>A path that uniquely identifies the message's action</li>
    - </ul>
    -+
    - <p>
    - Unlike with data items, there is no syncing between the handheld and wearable apps.
    - Messages are a one-way communication mechanism that's good for remote procedure calls (RPC),
    -@@ -149,11 +144,9 @@ If you create a service that extends
    - <a href="{@docRoot}reference/com/google/android/gms/wearable/WearableListenerService.html"><code>WearableListenerService</code></a>
    - to detect capability changes, you may want to override the
    - <a href="{@docRoot}reference/com/google/android/gms/wearable/WearableListenerService.html#onConnectedNodes(java.util.List<com.google.android.gms.wearable.Node>)"><code>onConnectedNodes()</code></a>
    --method to listen to finer-grained connectivity details, such as when a wearable device switches
    --from Wi-Fi to a Bluetooth connection to the handset. For an example implementation, see the
    --<code>DisconnectListenerService</code> class in the
    --<a href="https://github.com/googlesamples/android-FindMyPhone/" class="external-link">FindMyPhone</a>
    --sample. For more information on how to listen for important events, see
    -+method to listen to finer-grained connectivity details, such as when a wearable
    -+device switches from Wi-Fi to a Bluetooth connection to the handset.
    -+For more information on how to listen for important events, see
    - <a href="{@docRoot}training/wearables/data-layer/events.html#Listen">Listen for Data Layer Events</a>.
    - </p>
    - 
    -diff --git a/docs/html/training/wearables/notifications/creating.jd b/docs/html/training/wearables/notifications/creating.jd
    -index 35bb2bd..5663b58 100644
    ---- a/docs/html/training/wearables/notifications/creating.jd
    -+++ b/docs/html/training/wearables/notifications/creating.jd
    -@@ -58,7 +58,7 @@ such as action buttons and large icons, while remaining compatible with Android
    - 
    - <p>To create a notification with the support library, you create an instance of
    - {@link android.support.v4.app.NotificationCompat.Builder} and issue the notification by
    --passing it to {@link android.support.v4.app.NotificationManagerCompat#notify(int, android.app.Notification) notify()}. For example:
    -+passing it to {@link android.support.v4.app.NotificationManagerCompat#notify notify()}. For example:
    - </p>
    - 
    - <pre>
    -diff --git a/docs/html/training/wearables/notifications/stacks.jd b/docs/html/training/wearables/notifications/stacks.jd
    -index c3f43a7..8056fc8 100644
    ---- a/docs/html/training/wearables/notifications/stacks.jd
    -+++ b/docs/html/training/wearables/notifications/stacks.jd
    -@@ -37,7 +37,7 @@ possible while allowing you to still provide only one summary notification on th
    - 
    - <p>To create a stack, call {@link android.support.v4.app.NotificationCompat.Builder#setGroup setGroup()}
    - for each notification you want in the stack and specify a
    --group key. Then call {@link android.support.v4.app.NotificationManagerCompat#notify(int, android.app.Notification) notify()}
    -+group key. Then call {@link android.support.v4.app.NotificationManagerCompat#notify notify()}
    - to send it to the wearable.</p>
    - 
    - <pre style="clear:right">
    -@@ -59,7 +59,7 @@ notificationManager.notify(notificationId1, notif);
    - 
    - <p>Later on, when you create another notification, specify
    - the same group key. When you call
    --{@link android.support.v4.app.NotificationManagerCompat#notify(int, android.app.Notification) notify()},
    -+{@link android.support.v4.app.NotificationManagerCompat#notify notify()},
    - this notification appears in the same stack as the previous notification,
    - instead of as a new card:</p>
    - 
    -diff --git a/docs/html/tv/_project.yaml b/docs/html/tv/_project.yaml
    -new file mode 100644
    -index 0000000..d2d41e1
    ---- /dev/null
    -+++ b/docs/html/tv/_project.yaml
    -@@ -0,0 +1,6 @@
    -+name: "TV"
    -+home_url: /tv/
    -+description: "Bring your apps, games, and content to the biggest screen in the house."
    -+content_license: cc3-apache2
    -+buganizer_id: 30209417
    -+parent_project_metadata_path: /about/_project.yaml
    -diff --git a/docs/html/tv/index.jd b/docs/html/tv/index.jd
    -index 7c958c0..6ecc1ea 100644
    ---- a/docs/html/tv/index.jd
    -+++ b/docs/html/tv/index.jd
    -@@ -13,7 +13,7 @@ nonavpage=true
    - 
    - <style>
    - .fullpage>#footer,
    --#jd-content>.content-footer.wrap {
    -+#body-content>.content-footer.wrap {
    -   display:none;
    - }
    - </style>
    -diff --git a/docs/html/wear/_project.yaml b/docs/html/wear/_project.yaml
    -index 2a94274..114cc5b 100644
    ---- a/docs/html/wear/_project.yaml
    -+++ b/docs/html/wear/_project.yaml
    -@@ -3,3 +3,4 @@ home_url: /wear/
    - description: "Small, powerful devices, worn on the body. Useful information when you need it most."
    - content_license: cc3-apache2
    - buganizer_id: 30209417
    -+parent_project_metadata_path: /about/_project.yaml
    -diff --git a/docs/html/wear/images/partners/mkors.png b/docs/html/wear/images/partners/mkors.png
    -new file mode 100644
    -index 0000000..2f1e8ec
    -Binary files /dev/null and b/docs/html/wear/images/partners/mkors.png differ
    -diff --git a/docs/html/wear/images/partners/nixon.png b/docs/html/wear/images/partners/nixon.png
    -new file mode 100644
    -index 0000000..8674da2
    -Binary files /dev/null and b/docs/html/wear/images/partners/nixon.png differ
    -diff --git a/docs/html/wear/images/partners/polar.png b/docs/html/wear/images/partners/polar.png
    -new file mode 100644
    -index 0000000..2faeb06
    -Binary files /dev/null and b/docs/html/wear/images/partners/polar.png differ
    -diff --git a/docs/html/wear/index.jd b/docs/html/wear/index.jd
    -index f5e9e87..1eb08be 100644
    ---- a/docs/html/wear/index.jd
    -+++ b/docs/html/wear/index.jd
    -@@ -9,7 +9,7 @@ nonavpage=true
    - 
    - <style>
    - .fullpage>#footer,
    --#jd-content>.content-footer.wrap {
    -+#body-content>.content-footer.wrap {
    -   display:none;
    - }
    - </style>
    -@@ -267,6 +267,9 @@ nonavpage=true
    -             <div class="col-4">
    -               <img src="/wear/images/partners/mips.png" alt="MIPS">
    -             </div>
    -+            <div class="col-4">
    -+              <img src="/wear/images/partners/mkors.png" alt=Michael Kors">
    -+            </div>
    -              <div class="col-4">
    -               <img src="/wear/images/partners/mobvoi.png" alt="Mobvoi">
    -             </div>
    -@@ -277,6 +280,12 @@ nonavpage=true
    -               <img src="/wear/images/partners/nb.png" alt="New Balance">
    -             </div>
    -             <div class="col-4">
    -+              <img src="/wear/images/partners/nixon.png" alt="Nixon">
    -+            </div>
    -+            <div class="col-4">
    -+              <img src="/wear/images/partners/polar.png" alt="Polar">
    -+            </div>
    -+            <div class="col-4">
    -               <img src="/wear/images/partners/qualcomm.png" alt="Qualcomm">
    -             </div>
    -             <div class="col-4">
    -diff --git a/docs/html/wear/preview/_book.yaml b/docs/html/wear/preview/_book.yaml
    -index a231fb5..54d5442 100644
    ---- a/docs/html/wear/preview/_book.yaml
    -+++ b/docs/html/wear/preview/_book.yaml
    -@@ -8,18 +8,24 @@ toc:
    - - title: API Overview
    -   path: /wear/preview/api-overview.html
    -   section:
    --  - title: Notification Improvements
    --    path: /wear/preview/features/notifications.html
    --  - title: Input Method Framework
    --    path: /wear/preview/features/ime.html
    -   - title: Complications
    -     path: /wear/preview/features/complications.html
    -   - title: Navigation and Actions
    -     path: /wear/preview/features/ui-nav-actions.html
    -+  - title: Curved Layout
    -+    path: /wear/preview/features/wearable-recycler-view.html
    -+  - title: Notification Improvements
    -+    path: /wear/preview/features/notifications.html
    -   - title: Bridging for Notifications
    -     path: /wear/preview/features/bridger.html
    -+  - title: Input Method Framework
    -+    path: /wear/preview/features/ime.html
    -   - title: Wrist Gestures
    -     path: /wear/preview/features/gestures.html
    -+  - title: Standalone apps
    -+    path: /wear/preview/features/standalone-apps.html
    -+  - title: App Distribution
    -+    path: /wear/preview/features/app-distribution.html
    - 
    - - title: Get Started
    -   path: /wear/preview/start.html
    -diff --git a/docs/html/wear/preview/_project.yaml b/docs/html/wear/preview/_project.yaml
    -new file mode 100644
    -index 0000000..4f7083e
    ---- /dev/null
    -+++ b/docs/html/wear/preview/_project.yaml
    -@@ -0,0 +1,6 @@
    -+name: "Wear Preview"
    -+home_url: /wear/preview/
    -+description: "Small, powerful devices, worn on the body. Useful information when you need it most."
    -+content_license: cc3-apache2
    -+buganizer_id: 30209417
    -+parent_project_metadata_path: /wear/_project.yaml
    -diff --git a/docs/html/wear/preview/api-overview.jd b/docs/html/wear/preview/api-overview.jd
    -index 0b3ac6b..f4612a2 100644
    ---- a/docs/html/wear/preview/api-overview.jd
    -+++ b/docs/html/wear/preview/api-overview.jd
    -@@ -13,15 +13,16 @@ page.image=images/cards/card-n-apis_2x.png
    -           <ol>
    -             <li><a href="#complications">Complications</a></li>
    -             <li><a href="#drawers">Navigation and Action Drawers</a></li>
    -+            <li><a href="#wrv">Curved Layout</a></li>
    -           </ol>
    -         </li>
    - 
    -         <li><a href="#notify">Notifications and Input</a>
    -           <ol>
    --            <li><a href="#expanded">Expanded Notification</a></li>
    --            <li><a href="#messaging">Messaging Style Notification</a></li>
    -+            <li><a href="#expanded">Expanded Notifications</a></li>
    -+            <li><a href="#messaging">Messaging Style Notifications</a></li>
    -+            <li><a href="#inline-action">Inline Action</a></li>
    -             <li><a href="#smart-replies">Smart Reply</a></li>
    --            <li><a href="#content-action">Notification Content Action</a>
    -             <li><a href="#remote-input">Remote Input</a></li>
    -             <li><a href="#bridging">Bridging Mode</a></li>
    -             <li><a href="#imf">Input Method Framework</a></li>
    -@@ -40,308 +41,447 @@ page.image=images/cards/card-n-apis_2x.png
    - </div>
    - </div>
    - 
    --
    --
    --<p>
    --  The Android Wear Preview API is still in active development, but you can try
    --  it now as part of the Wear 2.0 Developer Preview. The sections below
    --  highlight some of the new features for Android Wear developers.
    --</p>
    --
    --
    --<h2 id="ui">User Interface Improvements</h2>
    --
    --<p>
    --  The preview introduces powerful additions to the user interface, opening up
    --  exciting possibilities to developers. A complication
    --  is any feature in a watch face that displays more than hours and
    --  minutes. With the Complications API, watch faces can display extra information
    --  and separate apps can expose complication data. The navigation and action
    --  drawers provide users with new ways to interact with apps.
    --</p>
    --
    --
    --<h3 id="complications">Complications</h3>
    --<img src="{@docRoot}wear/preview/images/complications-main-image.png"
    --  height="320" style="float:right;margin:10px 0 0 40px" />
    --
    --<p>
    --  A <a href=
    --  "https://en.wikipedia.org/wiki/Complication_(horology)">complication</a> is a
    --  feature of a watch face that displays more than hours and minutes, such as a
    --  battery indicator or a step counter. The Complications API thus helps watch face
    --  developers create visual features and the data connections they
    --  require.
    --</p>
    --
    --<p>
    --  Watch faces that use this API can display extra information without needing
    --  code for getting the underlying data. Data providers can supply data to any
    --  watch face using the API.
    --</p>
    --
    --<p>For information about this API,
    --see <a href="{@docRoot}wear/preview/features/complications.html">
    -- Watch Face Complications</a>.
    --</p>
    --
    --<h3 id="drawers">Navigation and Action drawers</h3>
    --
    --<p>Wear 2.0 introduces two new widgets, navigation drawer and action drawer. These
    -- widgets give your users new ways to interact with your app. The navigation drawer
    --  appears at the top of the screen and allows users to navigate between app views.
    --   The  action drawer appears at the bottom of the screen and allows users to choose
    --    from a list of actions associated with the current usage context.  These drawers
    --     are accessible to users when they edge swipe from the top or bottom of the
    --     screen; they peek when users scroll in an opposite direction.
    --</p>
    --
    --<div class="cols">
    --  <div class="col-2of6">
    --    <img src="{@docRoot}wear/preview/images/nav_drawer.gif"
    --      height="240" alt="" style="padding:.5em">
    --  </div>
    --  <div class="col-2of6">
    --    <img src="{@docRoot}wear/preview/images/action_drawer.gif"
    --      height="240" alt="" style="padding:.5em;">
    --  </div>
    --</div>
    --
    --<p>
    --  To learn how to add these widgets to your app, see
    --  <a href="{@docRoot}wear/preview/features/ui-nav-actions.html">
    --  Wear Navigation and Actions</a>.
    --</p>
    --
    --
    --<h2 id="notify">Notifications and Input</h2>
    --
    --<p>In Wear 2.0, we’ve redesigned the key experiences on the watch to be even more
    -- intuitive and provide users new ways to respond to messages. Some of the highlights
    --  are below; for a complete list of changes, see
    --  <a href="{@docRoot}wear/preview/features/notifications.html">Notification Changes in Wear 2.0</a>.
    --
    --
    --<img src="{@docRoot}wear/preview/images/expanded_diagram.png" height="340"
    --  style="float:left;margin:10px 20px 0 0" />
    --<h3 id="expanded">Expanded notifications</h3>
    --
    --<p>
    --  When a user taps on a notification that is bridged from the phone to the
    --  watch or that lacks a
    --  <a href="{@docRoot}reference/android/support/v4/app/NotificationCompat.Builder.html#setContentIntent(android.app.PendingIntent)">
    --  {@code contentIntent}</a>, the user will be taken to the expanded view of
    --  that notification. When you <a href=
    --  "{@docRoot}training/wearables/notifications/pages.html">specify additional
    --  content pages</a> and actions for a notification, those are available to the
    --  user within the expanded notification. Each expanded notification follows
    --  <a href="https://google.com/design/spec-wear">Material Design for Android
    --  Wear</a>, so the user gets an app-like experience.
    --</p>
    --
    --
    --<h3 id="messaging">Messaging Style notification</h3>
    --<p> If you have a chat messaging app, your notifications should use
    --{@code Notification.MessagingStyle}, which is new in Android 6.0. Wear 2.0 uses
    --the chat messages included in a
    --<a href="{@docRoot}preview/features/notification-updates.html#style">{@code MessagingStyle}</a>
    -- notification
    --(see {@code addMessage()}) to provide a rich chat app-like experience in the
    --expanded notification.
    --</p>
    --
    --
    --<h3 id="smart-replies">Smart Reply</h3>
    --
    --<p>Android Wear 2.0 introduces support for Smart Reply in
    --<a href="{@docRoot}wear/preview/features/notifications.html#messaging">{@code MessagingStyle}</a>
    -- notifications. Smart Reply provides the user with contextually relevant,
    -- touchable choices in the expanded notification and in
    -- <a href="{@docRoot}reference/android/app/RemoteInput.html">{@code RemoteInput}</a>.
    --</p>
    --
    --<p>By enabling Smart Reply for your {@code MessagingStyle} notifications, you provide
    --users a fast (single tap), discreet (no speaking aloud), and reliable way to respond
    -- to chat messages they receive.
    -- </p>
    --
    --
    --<img src="{@docRoot}wear/preview/images/remoteinput.png" height="350"
    --  style="float:right;margin:10px 0 0 40px" />
    --
    --<h3 id="remote-input">Remote Input</h3>
    --
    --<p>Wear 2.0 users can choose between various input options from
    --<a href="{@docRoot}reference/android/app/RemoteInput.html">Remote Input</a>.
    -- These options include:
    --</p>
    --<ul>
    --<li>Dictation</li>
    --<li>Emoji</li>
    --<li>Canned responses</li>
    --<li>Smart Reply</i>
    --<li>Default IME </i>
    --</ul>
    --
    --<p>
    --For messaging notifications with Smart Reply, the system-generated Smart Reply
    -- appears within <a href="{@docRoot}reference/android/app/RemoteInput.html">{@code RemoteInput}</a>
    --  above the developer-provided list of canned responses.
    --  You can also use the
    --  <a href="{@docRoot}reference/android/app/RemoteInput.Builder.html#setChoices(java.lang.CharSequence[])">setChoices()</a>
    --   method in the {@code RemoteInput} API to enable users to select from a list
    --   of canned responses.
    --</p>
    --
    --<h3 id="bridging"> Bridging Mode </h3>
    --<p>By default, notifications are
    --<a href="{@docRoot}training/wearables/notifications/index.html">
    --bridged</a> (shared) from an app on a companion phone
    --to the watch. Since a phone app and a standalone watch app may be sources of the
    -- same notifications, the Android Wear 2.0 Preview includes a Bridging mode feature.
    --  Developers can begin planning to change the behavior of notifications with the
    --  following:
    --</p>
    --
    --<ul>
    --<li>Specifying in the standalone app's Android manifest file that notifications from
    -- the corresponding phone app should not be bridged to the watch. </li>
    --<li>Setting a dismissal ID so notification dismissals (by users) are synced across
    --devices.</li>
    --</ul>
    --
    --<p>For an example of how to use this feature, see <a href="{@docRoot}wear/preview/features/bridger.html">
    --Bridging Mode for Notifications</a>.</p>
    --
    --<h3 id="imf">Input Method Framework</h3>
    --
    --<p>Wear 2.0 extends the Android input method framework (IMF) to Android Wear.
    --This allows users to enter text on Wear using the system default IME or third party
    -- IMEs.  The Wear IME lets the user enter text via gesture typing as well as tapping
    --  individual keys. The IMF APIs used for Wear devices are the same as other form
    --  factors, though usage is slightly different due to limited screen real estate.
    --</p>
    --
    --<p>Wear provides user settings on the watch that let the user:</p>
    --<ul>
    --<li>Enable multiple IMEs from the list of installed IMEs.</li>
    --<li>Set a single default IME from the list of enabled IMEs.</li>
    --<li>Change languages for various IMEs.</li>
    --</ul>
    --
    --<p>To learn how to create an IME for Wear, see <a href="{@docRoot}wear/preview/features/ime.html">
    --Input Method Framework</a>.
    --</p>
    --
    --<h3 id="wrist-gestures">Wrist Gestures</h3>
    --
    --<p>
    --  Wrist gestures can enable quick, one-handed interactions with your app
    --  when use of a touch screen is inconvenient. The following
    --  <a href="https://support.google.com/androidwear/answer/6312406">wrist gestures</a>
    --  are available for use by apps:
    --</p>
    --
    --<ul>
    --  <li>Flick wrist out</li>
    --  <li>Flick wrist in</li>
    --</ul>
    --
    --<p>For more information, see
    --<a href="{@docRoot}wear/preview/features/gestures.html">
    -- Wrist Gestures</a>.
    --</p>
    --
    --<h2 id="stand-alone">Standalone Devices</h2>
    --
    --<p>Standalone watches will enable Android Wear apps to work independently of phone
    -- apps. This means your app can continue to offer full functionality even if the
    -- paired phone is far away or turned off. </p>
    --
    --<h3 id="wear-apk">Wear-Specific APKs</h3>
    --
    --<p>For delivery to a watch, an Android Wear app is currently embedded in its corresponding
    --phone app. This delivery method can result in an increased download size for users,
    -- regardless of whether they have an Android Wear device.
    --</p>
    --
    --<p>With standalone devices, the
    --<a href ="{@docRoot}google/play/publishing/multiple-apks.html">Multi-APK</a>
    -- delivery method will be used. Developers will have the ability to release Android
    --  Wear apps independently of the corresponding phone apps. Please stay tuned for
    --   more information about this change.
    --</p>
    --
    --<h3 id="network">Network Access</h3>
    --
    --<p>Since Android Wear apps will work independently of phone apps, Android Wear's
    -- network access will no longer require the
    -- <a href="{@docRoot}training/wearables/data-layer/index.html">
    -- Wearable Data Layer API</a>. Android Wear apps will have the ability to make
    -- their own network requests. Additionally, they will be able to directly use
    -- Google Cloud Messaging.
    --</p>
    --
    --<p>No APIs for network access or GCM are specific to Android Wear; refer to the
    --existing documentation about
    --<a href="{@docRoot}training/basics/network-ops/connecting.html">
    --Connecting to the Network</a> and
    --<a href="https://developers.google.com/cloud-messaging/">Cloud Messaging</a>.
    --</p>
    --
    --<p>We recommend using the following libraries:</p>
    --<ul>
    --<li><a href="{@docRoot}reference/android/app/job/JobScheduler.html">
    --JobScheduler</a> for asynchronous jobs, including polling at regular intervals
    --</li>
    --<li>Multi-networking APIs if you need to connect to specific network types; see
    --the <a href="{@docRoot}about/versions/android-5.0.html#Wireless">
    --Multiple Network Connections</a>
    --</li>
    --</ul>
    --
    --<p>You will still be able to use the
    --<a href="{@docRoot}training/wearables/data-layer/index.html">
    -- Wearable Data Layer API</a> to communicate with a phone app.
    -- However, use of this API to connect to a network will be discouraged.
    -- </p>
    --
    --
    --<h3 id="auth">Authentication</h3>
    --
    --<p>Since Android Wear apps will work independently of phone apps, Android Wear's
    -- authentication capabilities will be more powerful; apps will have new ways to
    -- authenticate.</p>
    --
    --<h4>Users can enter a username and password on a watch</h4>
    --
    --<p>Google Keyboard will be standard on Android Wear, allowing for direct text
    --entry. This feature will work as expected with standard
    --<a href="{@docRoot}reference/android/widget/EditText.html">EditText widgets</a>.
    --For passwords, the {@code textPassword} attribute will be used.</p>
    --
    --<h4>Utilizing Account Manager</h4>
    --
    --<p>Android Wear will include the
    --<a href="{@docRoot}reference/android/accounts/AccountManager.html">
    --AccountManager</a>, which will be accessible for syncing and storing account
    --data, as it is on an Android phone.</p>
    --
    --<h4>Authentication tokens can be passed over the Wearable Data Layer</h4>
    --
    --<p>For Android-paired watches (only), a phone securely
    --transfers authentication credentials to a watch app via the
    --<a href="{@docRoot}training/wearables/data-layer/index.html">
    --Wearable Data Layer API</a>. The credentials can be transferred as
    --messages or data items.</p>
    --
    --<p>If your watch app needs to determine if your phone app is installed, you can
    --advertise a capability on the phone app and retrieve the capability on the
    --watch. For more information, see the following sections of
    --<a href="{@docRoot}training/wearables/data-layer/messages.html">
    --Sending and Receiving Messages</a>:</p>
    --
    --<ul>
    --  <li>Advertise Capabilities</li>
    --  <li>Retrieve the Nodes with the Required Capabilities</li>
    --</ul>
    -+    <p>
    -+      Wear 2.0 is still in active development, but you can try it as part of
    -+      the Wear 2.0 Developer Preview. The sections below highlight some of the
    -+      new features for developers.
    -+    </p>
    -+
    -+    <h2 id="ui">
    -+      User Interface Improvements
    -+    </h2>
    -+
    -+    <p>
    -+      The preview introduces powerful additions to the user interface, opening
    -+      up exciting possibilities to developers.
    -+    </p>
    -+
    -+    <h3 id="complications">
    -+      Complications
    -+    </h3>
    -+
    -+    <img src="{@docRoot}wear/preview/images/complications-main-image.png"
    -+    height="320" style="float:right;margin:10px 0 0 40px">
    -+    <p>
    -+      A <a href=
    -+      "https://en.wikipedia.org/wiki/Complication_(horology)">complication</a>
    -+      is a feature of a watch face that displays more than hours and minutes,
    -+      such as a battery indicator or a step counter. The Complications API thus
    -+      helps watch face developers create visual features and the data
    -+      connections they require.
    -+    </p>
    -+
    -+    <p>
    -+      Watch faces that use this API can display extra information without
    -+      needing code for getting the underlying data. Data providers can supply
    -+      data to any watch face using the API.
    -+    </p>
    -+
    -+    <p>
    -+      For information about this API, see <a href=
    -+      "{@docRoot}wear/preview/features/complications.html">Watch Face
    -+      Complications</a>.
    -+    </p>
    -+
    -+    <h3 id="drawers">
    -+      Navigation and Action Drawers
    -+    </h3>
    -+
    -+    <p>
    -+      Wear 2.0 introduces two new widgets, navigation drawer and action drawer.
    -+      These widgets give your users new ways to interact with your app. The
    -+      navigation drawer appears at the top of the screen and allows users to
    -+      navigate between app views. The action drawer appears at the bottom of
    -+      the screen and allows users to choose from a list of actions associated
    -+      with the current usage context. These drawers are accessible to users
    -+      when they edge swipe from the top or bottom of the screen; they peek when
    -+      users scroll in an opposite direction.
    -+    </p>
    -+
    -+    <div class="cols">
    -+      <div class="col-2of6">
    -+        <img src="{@docRoot}wear/preview/images/nav_drawer.gif" height="240"
    -+        alt="" style="padding:.5em">
    -+      </div>
    -+
    -+      <div class="col-2of6">
    -+        <img src="{@docRoot}wear/preview/images/action_drawer.gif" height="240"
    -+        alt="" style="padding:.5em;">
    -+      </div>
    -+    </div>
    -+
    -+    <p>
    -+      To learn how to add these widgets to your app, see <a href=
    -+      "{@docRoot}wear/preview/features/ui-nav-actions.html">Wear Navigation and
    -+      Actions</a>.
    -+    </p>
    -+
    -+    <h3 id="wrv">
    -+      Curved Layout
    -+    </h3>
    -+
    -+    <p>
    -+      Wear 2.0 introduces the <code>WearableRecyclerView</code> class for
    -+      displaying and manipulating a vertical list of items,
    -+      optimized for round displays.
    -+    </p>
    -+
    -+    <p>
    -+      The key features include the following:
    -+    </p>
    -+
    -+    <ul>
    -+      <li>A curved layout on round devices
    -+      </li>
    -+
    -+      <li>A circular scrolling gesture, which can be toggled on and off
    -+      </li>
    -+    </ul>
    -+
    -+    <p>
    -+      To learn how to create a curved layout optimized for round devices, see
    -+      <a href=
    -+      "https://developer.android.com/wear/preview/features/wearable-recycler-view.html">
    -+      Curved Layout</a>.
    -+    </p>
    -+
    -+    <h2 id="notify">
    -+      Notifications and Input
    -+    </h2>
    -+
    -+    <p>
    -+      In Wear 2.0, we’ve redesigned the key experiences on the watch to be even
    -+      more intuitive and provide users new ways to respond to messages. Some of
    -+      the highlights are below; for a complete list of changes, see <a href=
    -+      "{@docRoot}wear/preview/features/notifications.html">Notification Changes
    -+      in Wear 2.0</a>. <img src=
    -+      "{@docRoot}wear/preview/images/expanded_diagram.png" height="340" style=
    -+      "float:left;margin:10px 20px 0 0">
    -+    </p>
    -+
    -+    <h3 id="expanded">
    -+      Expanded Notifications
    -+    </h3>
    -+
    -+    <p>
    -+      When a user taps on a notification that is bridged from the phone to the
    -+      watch or that lacks a <a href=
    -+      "{@docRoot}reference/android/support/v4/app/NotificationCompat.Builder.html#setContentIntent(android.app.PendingIntent)">
    -+      {@code contentIntent}</a>, the user will be taken to the expanded view of
    -+      that notification. When you <a href=
    -+      "{@docRoot}training/wearables/notifications/pages.html">specify
    -+      additional content pages</a> and actions for a notification, those are
    -+      available to the user within the expanded notification. Each expanded
    -+      notification follows <a href=
    -+      "https://google.com/design/spec-wear">Material Design for Android
    -+      Wear</a>, so the user gets an app-like experience.
    -+    </p>
    -+
    -+    <h3 id="messaging">
    -+      Messaging Style Notifications
    -+    </h3>
    -+
    -+    <p>
    -+      If you have a chat messaging app, your notifications should use {@code
    -+      Notification.MessagingStyle}, which is new in Android 6.0. Wear 2.0 uses
    -+      the chat messages included in a <a href=
    -+      "{@docRoot}preview/features/notification-updates.html#style">{@code
    -+      MessagingStyle}</a> notification (see {@code addMessage()}) to provide a
    -+      rich chat, app-like experience in the expanded notification.
    -+    </p>
    -+
    -+    <h3 id="inline-action">
    -+      Inline Action
    -+    </h3>
    -+
    -+    <p>
    -+      Wear 2.0 enables you to add an inline action within the notification
    -+      stream so that users can quickly take an action on a notification.
    -+      Examples of good use cases for an inline action within a notification stream
    -+      include replying to a text message, stopping a fitness activity, or
    -+      archiving an email message.
    -+    </p>
    -+
    -+    <p>
    -+      To learn how to add an inline action to your notification stream, see
    -+      <a href=
    -+      "https://developer.android.com/wear/preview/features/notifications.html#inline">
    -+      Inline Action</a>.
    -+    </p>
    -+
    -+    <h3 id="smart-replies">
    -+      Smart Reply
    -+    </h3>
    -+
    -+    <p>
    -+      Android Wear 2.0 introduces support for Smart Reply in <a href=
    -+      "{@docRoot}wear/preview/features/notifications.html#messaging">{@code
    -+      MessagingStyle}</a> notifications. Smart Reply provides the user with
    -+      contextually relevant, touchable choices in the expanded notification and
    -+      in <a href="{@docRoot}reference/android/app/RemoteInput.html">{@code
    -+      RemoteInput}</a>.
    -+    </p>
    -+
    -+    <p>
    -+      By enabling Smart Reply for your {@code MessagingStyle} notifications,
    -+      you provide users a fast (single tap), discreet (no speaking aloud), and
    -+      reliable way to respond to chat messages they receive.
    -+    </p>
    -+
    -+    <img src="{@docRoot}wear/preview/images/remoteinput.png" height="350"
    -+    style="float:right;margin:10px 0 0 40px">
    -+
    -+    <h3 id="remote-input">
    -+      Remote Input
    -+    </h3>
    -+
    -+    <p>
    -+      Wear 2.0 users can choose between various input options from <a href=
    -+      "{@docRoot}reference/android/app/RemoteInput.html">Remote Input</a>.
    -+      These options include:
    -+    </p>
    -+
    -+    <ul>
    -+      <li>Dictation
    -+      </li>
    -+
    -+      <li>Emoji
    -+      </li>
    -+
    -+      <li>Canned responses
    -+      </li>
    -+
    -+      <li>Smart Reply
    -+      </li>
    -+
    -+      <li>Default IME
    -+      </li>
    -+    </ul>
    -+
    -+    <p>
    -+      For messaging notifications with Smart Reply, the system-generated Smart
    -+      Reply appears within <a href=
    -+      "{@docRoot}reference/android/app/RemoteInput.html">{@code
    -+      RemoteInput}</a> above the developer-provided list of canned responses.
    -+      You can also use the <a href=
    -+      "{@docRoot}reference/android/app/RemoteInput.Builder.html#setChoices(java.lang.CharSequence[])">
    -+      setChoices()</a> method in the {@code RemoteInput} API to enable users to
    -+      select from a list of canned responses.
    -+    </p>
    -+
    -+    <h3 id="bridging">
    -+      Bridging Mode
    -+    </h3>
    -+
    -+    <p>
    -+      By default, notifications are <a href=
    -+      "{@docRoot}training/wearables/notifications/index.html">bridged</a>
    -+      (shared) from an app on a companion phone to the watch. Since a phone app
    -+      and a standalone watch app may be sources of the same notifications, the
    -+      Android Wear 2.0 Preview includes a Bridging mode feature.
    -+    </p>
    -+
    -+    <p>
    -+      For information about this feature, see <a href=
    -+      "{@docRoot}wear/preview/features/bridger.html">Bridging Mode for
    -+      Notifications</a>.
    -+    </p>
    -+
    -+    <h3 id="imf">
    -+      Input Method Framework
    -+    </h3>
    -+
    -+    <p>
    -+      Wear 2.0 extends the Android input method framework (IMF) to Android
    -+      Wear. This allows users to enter text on Wear using the system default
    -+      IME or third party IMEs. The Wear IME lets the user enter text via
    -+      gesture typing as well as tapping individual keys. The IMF APIs used for
    -+      Wear devices are the same as other form factors, though usage is slightly
    -+      different due to limited screen real estate.
    -+    </p>
    -+
    -+    <p>
    -+      Wear provides user settings on the watch that let the user:
    -+    </p>
    -+
    -+    <ul>
    -+      <li>Enable multiple IMEs from the list of installed IMEs.
    -+      </li>
    -+
    -+      <li>Set a single default IME from the list of enabled IMEs.
    -+      </li>
    -+
    -+      <li>Change languages for various IMEs.
    -+      </li>
    -+    </ul>
    -+
    -+    <p>
    -+      To learn how to create an IME for Wear, see <a href=
    -+      "{@docRoot}wear/preview/features/ime.html">Input Method Framework</a>.
    -+    </p>
    -+
    -+    <h3 id="wrist-gestures">
    -+      Wrist Gestures
    -+    </h3>
    -+
    -+    <p>
    -+      Wrist gestures can enable quick, one-handed interactions with your app
    -+      when use of a touch screen is inconvenient. The following <a href=
    -+      "https://support.google.com/androidwear/answer/6312406">wrist
    -+      gestures</a> are available for use by apps:
    -+    </p>
    -+
    -+    <ul>
    -+      <li>Flick wrist out
    -+      </li>
    -+
    -+      <li>Flick wrist in
    -+      </li>
    -+    </ul>
    -+
    -+    <p>
    -+      For more information, see <a href=
    -+      "{@docRoot}wear/preview/features/gestures.html">Wrist Gestures</a>.
    -+    </p>
    -+
    -+    <h2 id="stand-alone">
    -+      Standalone Devices
    -+    </h2>
    -+
    -+    <p>
    -+      Standalone watches enable Android Wear apps to work independently of
    -+      phone apps. This means your app can continue to offer full functionality
    -+      even if the paired phone is far away or turned off.
    -+    </p>
    -+
    -+    <h3 id="wear-apk">
    -+      Wear-Specific APKs
    -+    </h3>
    -+
    -+    <p>
    -+      For delivery to a watch, an Android Wear app is currently embedded in its
    -+      corresponding phone app. This delivery method can result in an increased
    -+      download size for users, regardless of whether they have an Android Wear
    -+      device.
    -+    </p>
    -+
    -+    <p>
    -+      For information about planning and building your standalone app
    -+      for Wear 2.0, see <a href=
    -+      "https://developer.android.com/wear/preview/features/standalone-apps.html">
    -+      Standalone Apps</a>.
    -+    </p>
    -+
    -+    <p>
    -+      For information about distributing your app, see <a href=
    -+      "https://developer.android.com/wear/preview/features/app-distribution.html">
    -+      App Distribution</a>.
    -+    </p>
    -+
    -+    <h3 id="network">
    -+      Network Access
    -+    </h3>
    -+
    -+    <p>
    -+      Since Android Wear apps will work independently of phone apps, Android
    -+      Wear's network access will no longer require the <a href=
    -+      "{@docRoot}training/wearables/data-layer/index.html">Wearable Data Layer
    -+      API</a>. Android Wear apps will have the ability to make their own
    -+      network requests. Additionally, they will be able to directly use Google
    -+      Cloud Messaging. For more information, see
    -+      <a href=
    -+      "https://developer.android.com/wear/preview/features/standalone-apps.html#network_access">
    -+      Network Access and Cloud Messaging</a>.
    -+    </p>
    -+
    -+    <p>
    -+      No APIs for network access or GCM are specific to Android Wear; refer to
    -+      the existing documentation about <a href=
    -+      "{@docRoot}training/basics/network-ops/connecting.html">Connecting to the
    -+      Network</a> and <a href=
    -+      "https://developers.google.com/cloud-messaging/">Cloud Messaging</a>.
    -+    </p>
    -+
    -+    <p>
    -+      We recommend using the following libraries:
    -+    </p>
    -+
    -+    <ul>
    -+      <li>
    -+        <a href=
    -+        "{@docRoot}reference/android/app/job/JobScheduler.html">JobScheduler</a>
    -+        for asynchronous jobs, including polling at regular intervals
    -+      </li>
    -+
    -+      <li>Multi-networking APIs, to connect to specific network
    -+      types; see <a href=
    -+      "{@docRoot}about/versions/android-5.0.html#Wireless">Multiple Network
    -+      Connections</a>
    -+      </li>
    -+    </ul>
    -+
    -+    <p>
    -+      The <a href=
    -+      "{@docRoot}training/wearables/data-layer/index.html">Wearable Data Layer
    -+      API</a> is available to communicate with a phone app.
    -+      However, use of this API to connect to a network will be discouraged.
    -+    </p>
    -+
    -+    <h3 id="auth">
    -+      Authentication
    -+    </h3>
    -+
    -+    <p>
    -+      Since Android Wear apps will work independently of phone apps, Android
    -+      Wear's authentication capabilities will be more powerful; apps will have
    -+      new ways to authenticate.
    -+    </p>
    -+
    -+    <h4>
    -+      Users can enter a username and password on a watch
    -+    </h4>
    -+
    -+    <p>
    -+      Google Keyboard will be standard on Android Wear, allowing for direct
    -+      text entry. This feature will work as expected with standard <a href=
    -+      "{@docRoot}reference/android/widget/EditText.html">EditText widgets</a>.
    -+      For passwords, the {@code textPassword} attribute will be used.
    -+    </p>
    -+
    -+    <h4>
    -+      Utilizing Account Manager
    -+    </h4>
    -+
    -+    <p>
    -+      Android Wear will include the <a href=
    -+      "{@docRoot}reference/android/accounts/AccountManager.html">AccountManager</a>,
    -+      which will be accessible for syncing and storing account data, as it is
    -+      on an Android phone.
    -+    </p>
    -+
    -+    <h4>
    -+      Authentication tokens can be passed over the Wearable Data Layer
    -+    </h4>
    -+
    -+    <p>
    -+      For Android-paired watches (only), a phone securely transfers
    -+      authentication credentials to a watch app via the <a href=
    -+      "{@docRoot}training/wearables/data-layer/index.html">Wearable Data Layer
    -+      API</a>. The credentials can be transferred as messages or data items.
    -+    </p>
    -+
    -+    <p>
    -+      If your watch app needs to determine if your phone app is installed, you
    -+      can advertise a capability on the phone app and retrieve the capability
    -+      on the watch. For more information, see the following sections of
    -+      <a href="{@docRoot}training/wearables/data-layer/messages.html">Sending
    -+      and Receiving Messages</a>:
    -+    </p>
    -+
    -+    <ul>
    -+      <li>Advertise Capabilities
    -+      </li>
    -+
    -+      <li>Retrieve the Nodes with the Required Capabilities
    -+      </li>
    -+    </ul>
    -diff --git a/docs/html/wear/preview/behavior-changes.jd b/docs/html/wear/preview/behavior-changes.jd
    -index 0214622..c93d337 100644
    ---- a/docs/html/wear/preview/behavior-changes.jd
    -+++ b/docs/html/wear/preview/behavior-changes.jd
    -@@ -22,6 +22,8 @@ page.tags="preview", "developer preview"
    - 
    - <ul>
    -   <li><a href="#activity-dismissal">Activity Dismissal</a></li>
    -+  <li><a href="#invalid-fields">Invalid Fields for a Complication Type</a></li>
    -+  <li><a href="#empty">Complication Types for Empty Data</a></li>
    - </ul>
    - 
    - </div>
    -@@ -61,3 +63,44 @@ page.tags="preview", "developer preview"
    -   <a href="{@docRoot}wear/preview/features/ui-nav-actions.html">navigation
    -   drawers</a>.
    - </p>
    -+
    -+<h2 id="invalid-fields">Invalid Fields for a Complication Type</h2>
    -+
    -+<p>
    -+  When a watch face uses the <a href="{@docRoot}wear/preview/features/complications.html">
    -+  Complications API</a>, the watch face requests data from a chosen provider.
    -+  A <code>ComplicationData</code> object, which contains
    -+  complication types, is returned.
    -+</p>
    -+
    -+<p>
    -+  A complication type determines the
    -+  kinds of data that a watch face can render. This section describes
    -+  a behavior change related to the <code>ComplicationData</code> object.
    -+</p>
    -+
    -+<p>
    -+  Starting with
    -+  <a href="https://developer.android.com/wear/preview/support.html#dp3">
    -+  Developer Preview 3</a>, when a watch face requests a field that is invalid
    -+  for a complication type, a default value for the field is returned.
    -+  For example, if a watch face tries to access a <code>Long text</code>
    -+  field in a <code>SHORT_TEXT</code> type, the default value for the
    -+  <code>Long text</code> field is returned.
    -+  In previous releases, such a request for an invalid field
    -+  (for a type) resulted in an exception.
    -+</p>
    -+
    -+<h2 id="empty">Complication Types for Empty Data</h2>
    -+
    -+<p>
    -+  Starting with
    -+  <a href="https://developer.android.com/wear/preview/support.html#dp3">
    -+  Developer Preview 3</a>, the complication types used for "empty" data are
    -+  changed. Apps that use the Complications API
    -+  may need to be updated to use
    -+  <code>TYPE_NO_DATA</code>. See the information
    -+  about <code>TYPE_NO_DATA</code> in the
    -+  <a href="{@docRoot}wear/preview/features/complications.html#types_and_fields">
    -+  Types and fields</a> section.
    -+</p>
    -diff --git a/docs/html/wear/preview/downloads.jd b/docs/html/wear/preview/downloads.jd
    -index 4bc401b..bfa384b 100644
    ---- a/docs/html/wear/preview/downloads.jd
    -+++ b/docs/html/wear/preview/downloads.jd
    -@@ -171,7 +171,9 @@ This is the Android Wear SDK Preview License Agreement (the “License Agreement
    -           <li>
    -             <a href="#set_up_a_watch">Set Up a Watch</a>
    -           </li>
    --
    -+          <li>
    -+            <a href="#set_up_a_phone">Set Up a Phone</a>
    -+          </li>
    -           <li>
    -             <a href="#set_up_an_emulator">Set Up an Emulator</a>
    -           </li>
    -@@ -180,7 +182,7 @@ This is the Android Wear SDK Preview License Agreement (the “License Agreement
    -     </div>
    - 
    -     <p>
    --      You can run and test your app with the Android Wear 2.0 Developer Preview
    -+      You can run and test your app with the Android Wear 2.0 Preview
    -       in either of these ways:
    -     </p>
    - 
    -@@ -237,6 +239,13 @@ This is the Android Wear SDK Preview License Agreement (the “License Agreement
    -       following tables and flash it to the corresponding device.
    -     </p>
    - 
    -+    <p class="caution"><strong>Caution:</strong>
    -+      After you flash an image to a watch, follow the steps for
    -+      <a href="#set_up_a_phone">setting up a phone</a> with the beta version of
    -+      the Android Wear companion app. To use a Wear 2.0 image on a watch,
    -+      you must have the beta companion app on a paired phone.
    -+    </p>
    -+
    -     <p>
    -       To restore your device to its original state during the preview,
    -       you can flash the appropriate retail system image, below, to the device.
    -@@ -266,9 +275,9 @@ This is the Android Wear SDK Preview License Agreement (the “License Agreement
    -         <td>
    -           Preview image for testing
    -         </td>
    --        <td><a href="#top" onclick="onDownload(this)">nemo-nvd83h-factory-48ac950c.tgz</a><br>
    --          MD5: dd351884cce9fb5bf1bdec0a8e5f56e3<br>
    --          SHA-1: 48ac950c48faef96a7770e3c1acb56d23a28d859
    -+        <td><a href="#top" onclick="onDownload(this)">nemo-nve68j-factory-302a33ea.tgz</a><br>
    -+          MD5: ddfccc3e050c7e2db8d657c82f7d6291<br>
    -+          SHA-1: 302a33eac348c401fcb165bad4b9aaa40c7beb2b
    -         </td>
    -       </tr>
    - 
    -@@ -276,9 +285,9 @@ This is the Android Wear SDK Preview License Agreement (the “License Agreement
    -         <td>
    -           Non-preview image (for after testing)
    -         </td>
    --        <td><a href="#top" onclick="onDownload(this)">nemo-mnc40x-factory-fa528bec.tgz</a><br>
    --          MD5: 0b8ba3653d5a93cb854f4d7409d7b6c9<br>
    --          SHA-1: fa528bec8aba3bf6c7d901ba63cd6ea0a08dbeb0
    -+        <td><a href="#top" onclick="onDownload(this)">nemo-mfd18l-factory-3faf6f2d.tgz</a><br>
    -+          MD5: f3a0090c0e99da82ad095b5d2a9acc6d<br>
    -+          SHA-1: 3faf6f2d7f422a17a5f6c54cf5e1d2c5622689b0
    -         </td>
    -       </tr>
    - 
    -@@ -307,18 +316,18 @@ This is the Android Wear SDK Preview License Agreement (the “License Agreement
    -         <td>
    -           Preview image for testing
    -         </td>
    --        <td><a href="#top" onclick="onDownload(this)">sturgeon-nvd83h-factory-cb5a11ab.tgz</a><br>
    --          MD5: 38c1047992b1d28f6833d9f6c8470cdc<br>
    --          SHA-1: cb5a11ab0260ea3ca7da5894e73e41f70357da6b
    -+        <td><a href="#top" onclick="onDownload(this)">sturgeon-nve68j-factory-6607cd31.tgz</a><br>
    -+          MD5: f78ac6ba8bb84038d163cc2d7ca85040<br>
    -+          SHA-1: 6607cd31858af1bfd50b905c68f7cf1f0b6e570e
    -         </td>
    -       </tr>
    -       <tr id="sturgeon-non-preview">
    -         <td>
    -           Non-preview image (for after testing)
    -         </td>
    --        <td><a href="#top" onclick="onDownload(this)">sturgeon-mec23l-factory-48003078.tgz</a><br>
    --          MD5: 417b5cbddb29a2262bce133e283d2732<br>
    --          SHA-1: 4800307843580f818557dd7c43d8ba2161e289b2
    -+        <td><a href="#top" onclick="onDownload(this)">sturgeon-m6e69f-factory-e659286a.tgz</a><br>
    -+          MD5: 12ce6cb0b0e43b67ea46a886eae052ae<br>
    -+          SHA-1: e659286aa9004f4555a476ede4e8b690f56cfefd
    -         </td>
    -       </tr>
    -     </table>
    -@@ -337,7 +346,8 @@ This is the Android Wear SDK Preview License Agreement (the “License Agreement
    -     </p>
    - 
    -     <p class="warning">
    --      <strong>Warning:</strong> Installing a system image on a watch removes all data from the
    -+      <strong>Warning:</strong> Installing a system image on a watch
    -+      removes all data from the
    -       watch, so you should back up your data first.
    -     </p>
    - 
    -@@ -346,8 +356,7 @@ This is the Android Wear SDK Preview License Agreement (the “License Agreement
    -     </h4>
    - 
    -     <p>
    --      From the phone, unpair ("Forget") the watch.
    --      Then on the watch, enable the Developer Options menu and ADB debugging as
    -+      On the watch, enable the Developer Options menu and ADB debugging as
    -       follows:
    -     </p>
    - 
    -@@ -356,14 +365,14 @@ This is the Android Wear SDK Preview License Agreement (the “License Agreement
    -       </li>
    - 
    -       <li>Scroll to the bottom of the menu. If no <strong>Developer
    --      Options</strong> item is provided, tap <strong>About</strong>.
    -+      Options</strong> item is provided, tap <strong>System</strong>
    -+      and then <strong>About</strong>.
    -       </li>
    - 
    -       <li>Tap the build number 7 times.
    -       </li>
    - 
    --      <li>From the Settings menu, tap the <strong>Developer Options</strong>
    --      item.
    -+      <li>From the Settings menu, tap <strong>Developer Options</strong>.
    -       </li>
    - 
    -       <li>Enable ADB debugging.
    -@@ -409,7 +418,9 @@ This is the Android Wear SDK Preview License Agreement (the “License Agreement
    -       </li>
    - 
    -       <li>Use the following <a href="{@docRoot}tools/help/adb.html">adb
    --      command</a> to confirm that the watch is available for flashing:
    -+      command</a> to confirm that the watch is recognized.
    -+      You may need to turn ADB debugging off and then on for the watch to
    -+      be recognized:
    -       <code>adb devices</code>
    -       </li>
    - 
    -@@ -423,11 +434,11 @@ This is the Android Wear SDK Preview License Agreement (the “License Agreement
    -       devices, <code>fastboot oem unlock</code>
    -       </li>
    - 
    --      <li>On the watch, select the <strong>Unlock</strong> option.
    -+      <li>On the watch, select the option to unlock the bootloader.
    -       </li>
    - 
    --      <li>Navigate to the directory where you unzipped the system image in Step
    --      1. At the top level of that directory,
    -+      <li>On your computer, navigate to the directory where you unzipped the
    -+      system image in Step 1. At the top level of that directory,
    -       execute the <code>flash-all</code> script by typing
    -       <code>flash-all.sh</code> or, in the case of Windows,
    -       <code>flash-all.bat</code>. The following may need to
    -@@ -437,18 +448,19 @@ This is the Android Wear SDK Preview License Agreement (the “License Agreement
    - 
    - 
    -     <h4 id="set_up_watch">
    --      Set up the watch and begin testing
    -+      Set up the watch
    -     </h4>
    - 
    --      <p>
    --        After the <code>flash-all</code> script finishes, your watch reboots.
    --        Pair the watch with a phone or tablet. The preview now is available
    --        for testing on the watch. Before installing an app, perform the
    --        following steps on the watch to re-secure the watch's bootloader:
    -+    <p>
    -+      After the <code>flash-all</code> script finishes, the watch reboots.
    -+      Only pair the watch with a phone (so you can begin testing the preview)
    -+      by using the instructions in <a href="#set_up_a_phone">Set Up a Phone</a>.
    -+      Additionally, before installing an app, perform the
    -+      following steps on the watch to re-secure the watch's bootloader:
    -     </p>
    - 
    -     <ol>
    --      <li>Open the Settings menu (on the watch).
    -+      <li>Open the Settings menu by long-pressing the physical button.
    -       </li>
    - 
    -       <li>Scroll to the bottom of the menu and tap <strong>About</strong>.
    -@@ -457,15 +469,16 @@ This is the Android Wear SDK Preview License Agreement (the “License Agreement
    -       <li>Tap the build number 7 times.
    -       </li>
    - 
    --      <li>From the Settings menu, tap the <strong>Developer Options</strong>
    --      item.
    -+      <li>From the Settings menu, tap <strong>Developer Options</strong>.
    -       </li>
    - 
    -       <li>Enable ADB debugging.
    -       </li>
    - 
    -       <li>Connect the watch to your computer and tap <strong>Always allow from
    --      this computer</strong>.
    -+      this computer</strong>. (You may need to turn ADB debugging off
    -+      and then on, to be prompted to always allow ADB debugging from
    -+      the connected computer.)
    -       </li>
    - 
    -       <li>Use the following adb command to start the device in fastboot mode:
    -@@ -477,13 +490,18 @@ This is the Android Wear SDK Preview License Agreement (the “License Agreement
    -       devices, <code>fastboot oem lock</code>
    -       </li>
    - 
    --      <li>On the watch, continue the boot by choosing
    --      <strong>Start</strong> and touching <strong>'0'</strong>.
    -+      <li>On the watch, continue the boot as follows:
    -+      On an LGE Watch Urbane 2nd Edition, choose
    -+      <strong>Start</strong> and touch <strong>'0'</strong>.
    -+      On a Huawei Watch, confirm that <strong>Reboot</strong> is chosen and
    -+      long-press the physical button.
    -       </li>
    -     </ol>
    - 
    -     <p>
    --      Your watch is ready for you to <a href=
    -+      After you follow the instructions in
    -+      <a href="#set_up_a_phone">Set Up a Phone</a>,
    -+      your watch will be ready for you to <a href=
    -       "{@docRoot}training/wearables/apps/creating.html#Install">install and run
    -       your app</a>:
    -     </p>
    -@@ -539,13 +557,116 @@ This is the Android Wear SDK Preview License Agreement (the “License Agreement
    -       device reset and removes all user data on the device.
    -     </p>
    - 
    -+    <h2 id="set_up_a_phone">
    -+      Set Up a Phone
    -+    </h2>
    -+
    -+    <p>
    -+      On a phone, follow the instructions in this section to install the beta
    -+      version of the Android Wear companion app. The beta version cannot be run
    -+      on a phone at the same time as the non-beta version. Additionally, the
    -+      beta version is English-only.
    -+    </p>
    -+
    -+    <p>
    -+      <p class="caution"><strong>Caution:</strong> If you have an existing
    -+      pairing of the phone to a Wear 1.x
    -+      watch, installation of the beta companion app will cause a loss of that
    -+      pairing.
    -+    </p>
    -+
    -+    <h3 id="join-the-wear-2-0-preview-group">
    -+      Join the Wear 2.0 preview group
    -+    </h3>
    -+
    -+    <p>
    -+      To access the beta companion app, you must <a href=
    -+      "https://groups.google.com/forum/#!forum/android-wear-developer-preview">join
    -+      the preview group in Google Groups</a>.
    -+    </p>
    -+
    -+    <h3>
    -+      Opt in for beta testing
    -+    </h3>
    -+
    -+    <p>
    -+      On the <a href=
    -+      "https://play.google.com/apps/testing/com.google.android.wearable.app">Testing
    -+      Opt-in</a> page, select <strong>Become a Tester</strong>.
    -+    </p>
    -+
    -+    <h3 id="download-and-install-the-beta-version-of-the-companion-app">
    -+      Download and install the beta version of the companion app
    -+    </h3>
    -+
    -+    <p>
    -+      On the Play Store on your phone, go to the <a href=
    -+      "https://play.google.com/store/apps/details?id=com.google.android.wearable.app">
    -+      Android Wear app listing</a>. Tap <strong>Update</strong> to download and
    -+      install the beta version of the app. After installation, confirm that
    -+      <strong>Auto-update</strong> is selected for the app (see
    -+      the "Set up automatic updates for specific apps" section of <a href=
    -+      "https://support.google.com/googleplay/answer/113412">Update downloaded
    -+      apps</a>). Tap <strong>Open</strong> to start the app.
    -+    </p>
    -+
    -+    <h3 id="pairing">
    -+      Pair the phone to the watch
    -+    </h3>
    -+
    -+    <p>
    -+      After you install the beta version of the companion app on a phone,
    -+      unpair ("Forget") any obsolete watch pairings, if necessary.
    -+      Then you can pair the phone to a newly-imaged watch:
    -+    </p>
    -+
    -+    <ol>
    -+      <li>On the phone, select your device name from the list of devices.
    -+      A pairing code is displayed on the phone and on the watch.
    -+      Ensure that the codes match.
    -+      </li>
    -+
    -+      <li>Tap <strong>Pair</strong> to
    -+      continue the pairing process. When the watch is connected to
    -+      the phone, a confirmation message is displayed.
    -+      On the phone, a screen is displayed that lists
    -+      the accounts on the phone.
    -+      </li>
    -+
    -+      <li>Choose a Google Account to add and sync to your watch.
    -+      </li>
    -+
    -+      <li>Confirm the screen lock and enter the password to start the copying of
    -+      the account from the phone to the watch.
    -+      </li>
    -+
    -+      <li>Follow the instructions in the wizard to finish the
    -+      pairing process.
    -+      </li>
    -+    </ol>
    -+
    -+    <p>
    -+      You can begin testing your app with the preview.
    -+    </p>
    -+
    -     <h2 id="set_up_an_emulator">
    -       Set Up an Emulator
    -     </h2>
    - 
    -     <p>
    --      To test with the Android Emulator, create a virtual device in Android
    --      Studio as follows:
    -+      To test with the Android Emulator,
    -+      confirm that you have the latest version of the <strong>Android SDK
    -+      Platform-tools</strong> from the <a href=
    -+      "{@docRoot}studio/intro/update.html#sdk-manager">SDK Manager</a>.
    -+    </p>
    -+
    -+    <p>
    -+      After you create a virtual device as described below, follow the steps for
    -+      <a href="#set_up_a_phone">setting up a phone</a> with the beta version of
    -+      the Android Wear companion app.
    -+    </p>
    -+
    -+    <p>Create a new virtual device in Android Studio as follows:
    -     </p>
    - 
    -     <ol>
    -@@ -556,19 +677,19 @@ This is the Android Wear SDK Preview License Agreement (the “License Agreement
    -       <li>Click <strong>Create Virtual Device</strong>.
    -       </li>
    - 
    --      <li>In the <strong>Category</strong> pane, select Wear and
    --       choose a hardware profile.
    -+      <li>In the <strong>Category</strong> pane, select <strong>Wear</strong>
    -+       and choose a hardware profile.
    -        The Android Wear 2.0 Developer Preview
    -        is only optimized for round devices currently, so we recommend not
    -        using the square or chin profiles for now.
    -        Click <strong>Next</strong>.
    -       </li>
    - 
    --      <li>Select an <strong>N</strong> image to download. The images may be on
    -+      <li>Select a <strong>Nougat</strong> image to download. The images may be on
    -       the <strong>x86</strong> tab instead of the <strong>Recommended</strong>
    -       tab, until installed. For example, select the image with the
    --      <strong>Release Name</strong> of N, the <strong>API Level</strong> of N,
    --      and the <strong>Target</strong> of "Android 6.X (with Android Wear)".
    -+      <strong>Release Name</strong> of Nougat, the <strong>API Level</strong> of 24,
    -+      and the <strong>Target</strong> of "Android 7.0 (with Android Wear)".
    -       When the download and installation are complete, click
    -       <strong>Finish</strong> and then click <strong>Next</strong>.
    -       </li>
    -@@ -576,16 +697,68 @@ This is the Android Wear SDK Preview License Agreement (the “License Agreement
    -       <li>Verify the configuration of the Android Virtual Device (AVD) and
    -       click <strong>Finish</strong>.
    -       </li>
    -+
    -+      <li>Start the emulator by selecting the new virtual device, clicking the
    -+      <strong>Play</strong> button, and waiting until
    -+      the emulator initializes and shows the Android Wear home screen.
    -+      </li>
    -     </ol>
    - 
    -     <p>
    --      You can now test an application with a virtual preview device
    -+      Pair the phone with the emulator, and sync a Google Account, as follows:
    -+    </p>
    -+
    -+    <ol>
    -+      <li>Follow the steps for
    -+      <a href="#set_up_a_phone">setting up a phone</a> with the beta version of
    -+      the Android Wear companion app.
    -+      </li>
    -+
    -+      <li>On the phone, enable Developer Options and USB Debugging.
    -+      </li>
    -+
    -+      <li>Connect the phone to your computer through USB.
    -+      </li>
    -+
    -+      <li>Forward the AVD's communication port to the connected handheld device
    -+      (each time the phone is connected):<br>
    -+      <code>adb -d forward tcp:5601 tcp:5601</code>
    -+      </li>
    -+
    -+      <li>On the phone, in the Android Wear app, begin the standard pairing
    -+      process. For example, on the Welcome screen, tap the
    -+      <strong>Set It Up</strong> button.
    -+      Alternatively, if an existing watch already is paired, in the upper-left
    -+      drop-down, tap <strong>Add a New Watch</strong>.
    -+      </li>
    -+
    -+      <li>On the phone, in the Android Wear app, tap the
    -+      Overflow button, and then tap
    -+      <strong>Pair with Emulator</strong>.
    -+      </li>
    -+
    -+      <li>Tap the Settings icon.
    -+      </li>
    -+
    -+      <li>Under Device Settings, tap <strong>Emulator</strong>.
    -+      </li>
    -+
    -+      <li>Tap <strong>Accounts</strong> and select a Google Account,
    -+      and follow the steps in the wizard to
    -+      sync the account with the emulator. If necessary, type the screen-lock
    -+      device password, and Google Account password, to start the account sync.
    -+      </li>
    -+    </ol>
    -+
    -+    <p>
    -+      You can now test an app with a virtual preview device
    -       in the <a href=
    -       "{@docRoot}tools/devices/emulator.html">Android Emulator</a>. For more
    -       information about using virtual devices, see <a href=
    --      "{@docRoot}tools/devices/managing-avds.html">Managing AVDs with the AVD
    --      Manager</a>.
    -+      "{@docRoot}studio/run/managing-avds.html">
    -+      Create and Manage Virtual Devices</a>.
    -     </p>
    -+
    -  </div><!-- landing -->
    - 
    - </div><!-- relative wrapper -->
    -diff --git a/docs/html/wear/preview/features/app-distribution.jd b/docs/html/wear/preview/features/app-distribution.jd
    -new file mode 100644
    -index 0000000..afc9516
    ---- /dev/null
    -+++ b/docs/html/wear/preview/features/app-distribution.jd
    -@@ -0,0 +1,329 @@
    -+page.title=App Distribution
    -+meta.keywords="wear-preview"
    -+page.tags="wear-preview"
    -+page.image=images/cards/card-n-sdk_2x.png
    -+@jd:body
    -+
    -+<div id="qv-wrapper">
    -+<div id="qv">
    -+
    -+<h2>In this document</h2>
    -+
    -+  <ul>
    -+    <li><a href="#publish">Publish Your APKs</a></li>
    -+    <li><a href="#targeting">Setting Up Targeting for a Watch</a></li>
    -+    <li><a href="#console">Using the Play Developer Console</a></li>
    -+  </ul>
    -+
    -+</div>
    -+</div>
    -+
    -+    <p>
    -+      With Android Wear 2.0, a user can visit the Play Store on a watch and
    -+      download a Wear app directly to the watch.
    -+    </p>
    -+
    -+    <p>
    -+      Generally, a Wear 2.0 app in the Play Store needs
    -+      a minimum and target API level of 24 or higher in
    -+      the Android manifest file. The minimum SDK level can be 23
    -+      only if you are using the same APK
    -+      for Wear 1.0 and 2.0 (and thus have an embedded Wear 1.0 APK).
    -+    </p>
    -+
    -+    <h2 id="publish">
    -+      Publish Your APKs
    -+    </h2>
    -+
    -+    <p>
    -+      To make your app appear in the on-watch Play Store, upload
    -+      the watch APK in the Play Developer Console just as you would any other
    -+      APK. If you only have a watch APK and no phone APK, no other steps
    -+      are required.
    -+    </p>
    -+
    -+    <p>
    -+      If you have a phone APK in addition to a watch APK, you must use the
    -+      <a href="https://developer.android.com/google/play/publishing/multiple-apks.html">Multi-APK delivery method</a>.
    -+    </p>
    -+
    -+    <p>
    -+      <a href=
    -+      "https://developer.android.com/training/permissions/requesting.html">Run-time
    -+      permissions</a> are required.
    -+    </p>
    -+
    -+    <p>
    -+      Also see
    -+      <a href="{@docRoot}wear/preview/features/standalone-apps.html">
    -+      Standalone Apps</a>.
    -+    </p>
    -+
    -+    <h3>
    -+      Distribution to Wear 2.0 watches
    -+    </h3>
    -+
    -+    <p>
    -+      If you only want your app to be distributed to Wear 2.0 watches,
    -+      it is unnecessary to embed the watch APK inside the the phone APK.
    -+    </p>
    -+
    -+    <p>
    -+      If you want your app to
    -+      be distributed to Wear 1.0 watches, you need to embed the
    -+      watch APK inside the phone APK, as described directly below.
    -+    </p>
    -+
    -+    <h3>
    -+      Distribution to Wear 1.0 and 2.0 watches
    -+    </h3>
    -+
    -+    <p>
    -+      If you are already distributing your app to Wear 1.0 watches,
    -+      follow these steps:
    -+    </p>
    -+
    -+    <ol>
    -+      <li>Provide a Wear 2.0 (standalone) version of your watch APK that can be made
    -+      available in the Play Store on Wear.
    -+      </li>
    -+
    -+      <li>Continue embedding a Wear 1.0 APK in your phone APK,
    -+      for use by watches that do not have Wear 2.0.
    -+      </li>
    -+    </ol>
    -+
    -+    <h3>
    -+      Specifying a version code
    -+    </h3>
    -+
    -+    <p>
    -+      To ensure that a standalone APK acts as an upgrade to an embedded Wear APK, the
    -+      standalone Wear APK's <a href=
    -+      "https://developer.android.com/google/play/publishing/multiple-apks.html#VersionCodes">
    -+      version code</a> generally should be higher than the embedded Wear APK's version code.
    -+      (A phone APK's version code scheme can be independent from that of a watch
    -+      APK, although they must be unique.) However, the version codes
    -+      of the standalone APK and the embedded Wear APK can be the same if
    -+      the APKs are equivalent. If the APKs are not equivalent,
    -+      but the version code is the same, then when a watch updates from Wear 1.0
    -+      to 2.0, the watch may get the new APK only after waiting for a
    -+      longer-than-expected period of time.
    -+    </p>
    -+
    -+    <p>
    -+      Note that it currently is not possible to create a single APK that works
    -+      on a phone and watch.
    -+    </p>
    -+
    -+    <h3>
    -+      Support in the Gradle file
    -+    </h3>
    -+
    -+    <p>
    -+      If you have a Wear app that is intended for both Wear 1.0 and Wear 2.0,
    -+      consider using <a href=
    -+      "https://developer.android.com/studio/build/build-variants.html#product-flavors">
    -+      product flavors</a>. For example,
    -+      if you want to target both SDK version 23 and version 24,
    -+      update your Wear module's <code>build.gradle</code> file to include
    -+      the following if an existing embedded app has a minimum SDK version of 23:
    -+    </p>
    -+
    -+<pre>
    -+android {
    -+    // Allows you to reference product flavors in your
    -+    // phone module's build.gradle file
    -+    publishNonDefault true
    -+    ...
    -+    defaultConfig
    -+    {
    -+       // This is the minSdkVersion of the Wear 1.0 embedded app
    -+       minSdkVersion 23
    -+       ...
    -+    }
    -+    buildTypes {...}
    -+    productFlavors {
    -+        wear1 {
    -+          // Use the defaultConfig value
    -+        }
    -+        wear2 {
    -+            minSdkVersion 24
    -+        }
    -+    }
    -+}
    -+</pre>
    -+
    -+    <p>
    -+      Then update your phone module’s <code>build.gradle</code> file, replacing
    -+      <code>wearApp</code> as follows:
    -+    </p>
    -+
    -+<pre>
    -+dependencies {
    -+    ...
    -+    wearApp project(path: ':wear', configuration: 'wear1Release')
    -+}
    -+</pre>
    -+
    -+    <p>
    -+      A <a href=
    -+      "https://developer.android.com/studio/build/build-variants.html#product-flavors">
    -+      build variant</a> is a combination of the product flavor and build type.
    -+      In Android Studio, select the appropriate build variant when
    -+      debugging or publishing your app. For example, if <code>wear2</code> is a
    -+      product flavor, select <strong>wear2Release</strong> as the
    -+      release build variant.
    -+    </p>
    -+
    -+    <p>
    -+      For purposes of code that is Wear 2.0-specific or Wear 1.0-specific,
    -+      consider <a href=
    -+      "https://developer.android.com/studio/build/build-variants.html#sourcesets">
    -+      source sets for build variants</a>.
    -+    </p>
    -+
    -+
    -+    <h2 id="targeting">
    -+      Setting Up Targeting for a Watch
    -+    </h2>
    -+
    -+    <p>
    -+      In your Android Manifest file, you must specify the following feature
    -+      restriction: the <code>uses-feature</code> element is set to
    -+      <code>android.hardware.type.watch</code>. Do not set
    -+      the <code>required</code> attribute to <code>false</code>.
    -+      A single APK for Wear and non-Wear devices presently is not supported.
    -+    </p>
    -+
    -+    <p>
    -+      Thus, if an APK has the following setting, Google Play provides the APK
    -+      to watches only:
    -+    </p>
    -+
    -+<pre>
    -+&lt;manifest package=&quot;com.example.standalone&quot;
    -+    xmlns:android=&quot;http://schemas.android.com/apk/res/android&quot;&gt;
    -+    &lt;uses-feature
    -+        android:name=&quot;android.hardware.type.watch&quot;
    -+    ...
    -+&lt;/manifest&gt;
    -+</pre>
    -+
    -+    <p>
    -+      The <code>android.hardware.type.watch</code> setting above can be
    -+      combined with other criteria such as SDK version, screen resolution, and
    -+      CPU architecture. Thus, different Wear APKs can target different hardware
    -+      configurations.
    -+    </p>
    -+
    -+    <h2 id="console">
    -+      Using the Play Developer Console
    -+    </h2>
    -+
    -+    <p>
    -+      Below is an introduction to <a href=
    -+      "https://support.google.com/googleplay/android-developer/answer/113469">uploading</a>
    -+      a standalone Wear APK to an application listing using the Play Developer
    -+      Console.
    -+    </p>
    -+
    -+    <p>
    -+      If your app supports both Wear 1.0 and Wear 2.0, continue embedding the
    -+      Wear 1.0 APK (minimum SDK version of 20, 21, or 22, or 23) in the phone
    -+      APK and upload the phone APK. In addition, upload your standalone Wear
    -+      2.0 APK (which has a minimum SDK version of 24).
    -+    </p>
    -+
    -+    <p>
    -+      Also see <a href=
    -+      "https://developer.android.com/google/play/publishing/multiple-apks.html">
    -+      Multiple APK Support</a> and <a href=
    -+      "https://developer.android.com/distribute/googleplay/developer-console.html#manage">
    -+      Manage Your App</a>.
    -+      Before uploading an APK as described below, the APK
    -+      must be <a href=
    -+      "https://developer.android.com/studio/publish/app-signing.html#release-mode">
    -+      signed</a>.
    -+    </p>
    -+
    -+     <h3  id="uploading-apk">
    -+      Uploading your APK
    -+    </h3>
    -+
    -+    <p>
    -+      Go to the <a href="https://play.google.com/apps/publish">Play Developer
    -+      Console</a>, navigate to your application listing, and select
    -+      <strong>APK</strong> in the left-navigation panel. An APK screen similar to
    -+      the following is displayed:
    -+    </p>
    -+    <img src="../images/apk-tabs.png" width="" alt="alt_text">
    -+
    -+    <p>
    -+      You may need to use advanced mode for uploads, as follows:
    -+    </p>
    -+
    -+    <ul>
    -+      <li>Advanced mode is unnecessary if you only have a Wear 2.0 app and no
    -+      phone app. Instead of advanced mode, use simple mode.</li>
    -+
    -+      <li>Use advanced mode if you support Wear 1.0 or have a phone app.</li>
    -+    </ul>
    -+
    -+    <p>
    -+      Therefore, on the above APK screen, to determine whether to click
    -+      the <strong>Switch to advanced mode</strong>
    -+      button, consider the following:
    -+    </p>
    -+
    -+    <ul>
    -+      <li>If your app does not support Wear 1.0, and only has a watch APK,
    -+      upload it using simple mode.
    -+      </li>
    -+
    -+      <li>If your app does not support Wear 1.0 and has both a watch APK and a
    -+      phone APK, click <strong>Switch to advanced mode</strong>
    -+      to upload the watch and phone APKs.
    -+      </li>
    -+    </ul>
    -+
    -+    <p>
    -+      See <a href=
    -+      "https://developer.android.com/google/play/publishing/multiple-apks.html#SimpleAndAdvanced">
    -+      Simple mode and advanced mode</a> for more information about toggling
    -+      between modes.
    -+    </p>
    -+
    -+    <p>
    -+      Select the appropriate tab (<strong>Production</strong>, <strong>Beta
    -+      Testing</strong>, or <strong>Alpha Testing</strong>) for your upload.
    -+      Then click
    -+      the <strong>Upload New APK</strong> button and select your standalone
    -+      Wear APK for upload.
    -+    </p>
    -+
    -+    <h3>
    -+      Reviewing and publishing
    -+    </h3>
    -+
    -+    <p>
    -+      After you upload your standalone Wear APK and scroll down the resulting
    -+      page, the APK is shown in the <strong>Current APK</strong> table, with a
    -+      version number, in a similar way to the following:
    -+    </p>
    -+    <img src="../images/current-apk.png" width="" alt="alt_text">
    -+
    -+    <p>
    -+      Finally, in the <strong>Current APK</strong> table above, click the line
    -+      with the <strong>Version</strong> to review the APK. The <strong>APK
    -+      Details</strong> panel is displayed. You can verify, for example, that
    -+      the number in the <strong>Supported Android Devices</strong> line is far
    -+      fewer than the number would be for a typical phone APK:
    -+    </p>
    -+    <img src="../images/apk-details.png" width="" alt="alt_text">
    -+
    -+    <p>
    -+      When you are ready, <a href=
    -+      "https://support.google.com/googleplay/android-developer/answer/6334282">publish</a>
    -+      your app.
    -+    </p>
    -diff --git a/docs/html/wear/preview/features/bridger.jd b/docs/html/wear/preview/features/bridger.jd
    -index b7be093..2d879ca 100644
    ---- a/docs/html/wear/preview/features/bridger.jd
    -+++ b/docs/html/wear/preview/features/bridger.jd
    -@@ -6,19 +6,26 @@ page.tags="wear-preview"
    - 
    -     <div id="qv-wrapper">
    -       <div id="qv">
    --        <ol>
    -+        <ul>
    -           <li>
    -             <a href=
    --            "#preventing_bridging_with_the_bridging_mode_feature">Preventing
    --            Bridging with the Bridging Mode Feature</a>
    -+            "#using-an-entry-in-the-manifest-file">Specifying a Bridging Configuration in the Manifest File</a>
    -           </li>
    - 
    -           <li>
    -             <a href=
    --            "#using_a_dismissal_id_to_sync_notification_dismissals">Using a
    --            Dismissal ID to Sync Notification Dismissals</a>
    -+            "#specifying-a-bridging-configuration-at-runtime">Specifying a Bridging Configuration at Runtime</a>
    -           </li>
    --        </ol>
    -+          <li>
    -+            <a href=
    -+            "#existing-method-of-preventing-bridging">Existing Method of Preventing Bridging</a>
    -+          </li>
    -+
    -+          <li>
    -+            <a href=
    -+            "#using_a_dismissal_id_to_sync_notification_dismissals">Using a Dismissal ID to Sync Notification Dismissals</a>
    -+          </li>
    -+        </ul>
    -       </div>
    -     </div>
    - 
    -@@ -27,19 +34,20 @@ page.tags="wear-preview"
    -       "{@docRoot}training/wearables/notifications/index.html">are bridged
    -       (shared)</a> from an app on a companion phone to the watch. If you build
    -       a standalone watch app and have a companion phone app, they may duplicate
    --      notifications. The Android Wear 2.0 Preview includes a Bridging mode
    --      feature to handle this problem of repeated notifications.
    -+      notifications. The Android Wear 2.0 Preview includes
    -+      features to handle this problem of repeated notifications.
    -     </p>
    - 
    -     <p>
    --      With the Android Wear 2.0 Preview, developers can change the
    --      behavior of notifications with the following:
    -+      With the Android Wear 2.0 Preview, developers can change the behavior of
    -+      notifications with one or more of the following:
    -     </p>
    - 
    -     <ul>
    --      <li>Specifying in the standalone app's Android manifest file that
    --      notifications from the corresponding phone app should not be
    --      bridged to the watch
    -+      <li>Specifying a bridging configuration in the manifest file
    -+      </li>
    -+
    -+      <li>Specifying a bridging configuration at runtime
    -       </li>
    - 
    -       <li>Setting a dismissal ID so notification dismissals are synced across
    -@@ -47,43 +55,201 @@ page.tags="wear-preview"
    -       </li>
    -     </ul>
    - 
    --    <h2 id="preventing_bridging_with_the_bridging_mode_feature">
    --      Preventing Bridging with the Bridging Mode Feature
    -+    <h2 id="using-an-entry-in-the-manifest-file">
    -+      Specifying a Bridging Configuration in the Manifest File
    -     </h2>
    - 
    -     <p>
    --      To prevent bridging of notifications from a phone app, you can use an
    -+      An app's Android manifest file can indicate that notifications from the
    -+      corresponding phone app should not be bridged to the watch. Specifically,
    -+      to prevent bridging of notifications from a phone app, you can use a
    -+      <code>&lt;meta-data&gt;</code>
    -       entry in the manifest file of the watch app (e.g. the standalone watch
    -       app), as follows:
    -     </p>
    - 
    --    <pre>
    -+<pre>
    - com.google.android.wearable.notificationBridgeMode
    --    </pre>
    -+</pre>
    - 
    -     <p>
    -       Setting that entry to <code>NO_BRIDGING</code> will prevent bridging:
    -     </p>
    - 
    --    <pre>
    --&lt;meta-data android:name="com.google.android.wearable.notificationBridgeMode"
    --                   android:value="NO_BRIDGING" /&gt;
    -+<pre>
    -+&lt;meta-data android:name=&quot;com.google.android.wearable.notificationBridgeMode&quot;
    -+                   android:value=&quot;NO_BRIDGING&quot; /&gt;
    - </pre>
    -+
    -     <p>
    --      The default bridging behavior occurs if you do not include the entry or
    -+      The default bridging behavior occurs if you do not
    -+      include the <code>&lt;meta-data&gt;</code> entry or
    -       if you specify a value of <code>BRIDGING</code> instead of
    -       <code>NO_BRIDGING</code>.
    -     </p>
    - 
    --    <h3 id="existing_method_of_preventing_bridging">
    --      Existing method of preventing bridging
    -+    <p>
    -+      For an existing app, if you are using
    -+      Google Cloud Messaging (GCM) or Firebase Cloud
    -+      Messaging (FCM) to send notification alerts to devices,
    -+      you may already have disabled bridging in case a phone is not
    -+      connected at the time of receiving an alert.
    -+      In this case, you may still want to dismiss the notification
    -+      across other devices when it is dismissed in a watch app.
    -+    </p>
    -+
    -+    <p>
    -+      The bridging configuration that is set in the manifest takes effect as
    -+      soon as a watch app is installed.
    -+    </p>
    -+
    -+    <h2 id="specifying-a-bridging-configuration-at-runtime">
    -+      Specifying a Bridging Configuration at Runtime
    -+    </h2>
    -+
    -+    <p>
    -+      This section describes how to specify a bridging configuration at runtime
    -+      using the <code>BridgingManager</code> class
    -+      <code>(android.support.wearable.notifications.BridgingManager)</code>.
    -+    </p>
    -+
    -+    <p>
    -+      You can set a bridging mode, and optionally set tags for notifications
    -+      that are exempt from the bridging mode, using a
    -+      <code>BridgingManager</code> object. Specifically, create a
    -+      <code>BridgingConfig</code> object and set it as shown in this section,
    -+      optionally using the <code>setBridgingEnabled</code> method. If you
    -+      specify a bridging configuration at runtime, then if the
    -+      <code>setBridgingEnabled</code> method is not set, bridging is enabled by
    -+      default.
    -+    </p>
    -+
    -+    <p>
    -+      Specifying a bridging configuration at runtime overrides a
    -+      bridging-related setting in the Android manifest file.
    -+    </p>
    -+
    -+    <h3 id="disable-bridging-for-all-notifications">
    -+      Disable bridging for all notifications
    -+    </h3>
    -+
    -+    <p>
    -+      You can use the <code>setBridgingEnabled</code> method, as follows:
    -+    </p>
    -+
    -+<pre>
    -+BridgingManager.setConfig(context,
    -+  new BridgingConfig.Builder(context)
    -+    .setBridgingEnabled(false)
    -+    .build());
    -+</pre>
    -+    <p>
    -+      If the above setter is not called, the bridging mode defaults to true.
    -+      Here is an example of setting tags without using the
    -+      <code>setBridgingEnabled</code> method, excluding notifications with a
    -+      tag of <code>foo</code> or <code>bar</code>:
    -+    </p>
    -+
    -+<pre>
    -+BridgingManager.setConfig(context,
    -+  new BridgingConfig.Builder(context)
    -+    .addExcludedTag("foo")
    -+    .addExcludedTag("bar")
    -+    .build());
    -+</pre>
    -+    <h3 id="exempt-notifications-that-are-tagged">
    -+      Exempt notifications that are tagged
    -     </h3>
    - 
    -     <p>
    -+      You can disable bridging for all notifications except those with certain
    -+      tags.
    -+    </p>
    -+
    -+    <p>
    -+      For example, you can disable bridging, except for notifications tagged as
    -+      <code>foo</code> or <code>bar,</code> with the following:
    -+    </p>
    -+
    -+<pre>
    -+BridgingManager.setConfig(context,
    -+  new BridgingConfig.Builder(context)
    -+    .setBridgingEnabled(false)
    -+    .addExcludedTag("foo")
    -+    .addExcludedTag("bar")
    -+    .build());
    -+</pre>
    -+
    -+    <p>
    -+      As another example, you can disable bridging for all notifications except
    -+      for notifications tagged as <code>foo</code>, <code>bar</code> or
    -+      <code>baz</code>.
    -+    </p>
    -+
    -+    <pre>
    -+BridgingManager.setConfig(context,
    -+  new BridgingConfig.Builder(context)
    -+    .setBridgingEnabled(false)
    -+    .addExcludedTags(Arrays.asList("foo", "bar", "baz"))
    -+    .build());
    -+</pre>
    -+    <h3 id="enable-bridging-except-for-notifications-with-certain-tags">
    -+      Enable bridging except for notifications with certain tags
    -+    </h3>
    -+
    -+    <p>
    -+      You can enable bridging for all notifications except those with certain
    -+      tags.
    -+    </p>
    -+
    -+    <p>
    -+      For example, you can enable bridging for all notifications, except for
    -+      notifications tagged as <code>foo</code> or <code>bar</code>, with the
    -+      following:
    -+    </p>
    -+
    -+<pre>
    -+BridgingManager.setConfig(context,
    -+  new BridgingConfig.Builder(context)
    -+    .setBridgingEnabled(true)
    -+    .addExcludedTag("foo")
    -+    .addExcludedTag("bar")
    -+    .build());
    -+</pre>
    -+
    -+    <h3 id="setting-a-bridge-tag">
    -+      Setting a bridge tag
    -+    </h3>
    -+
    -+    <p>
    -+      A bridge tag can be set on a notification by calling the
    -+      <code>setNotificationBridgeTag</code> method as follows:
    -+    </p>
    -+
    -+<pre>
    -+BridgingManager.setNotificationBridgeTag(&lt;NotificationCompat.Builder&gt;, &lt;String&gt;);
    -+</pre>
    -+
    -+    <p>
    -+      For example:
    -+    </p>
    -+
    -+<pre>
    -+NotificationCompat.Builder builder = new NotificationCompat.Builder(context)
    -+&lt;set other fields&gt;;
    -+BridgingManager.setNotificationBridgeTag(builder, &quot;foo&quot;);
    -+Notification notification =  builder.build();
    -+</pre>
    -+
    -+    <h2 id="existing-method-of-preventing-bridging">
    -+      Existing Method of Preventing Bridging
    -+    </h2>
    -+
    -+    <p>
    -       An existing way to prevent bridging is with the
    -       <code>Notification.Builder</code> class; specify <code>true</code> in the
    -       <a href=
    --      "{@docRoot}reference/android/app/Notification.Builder.html#setLocalOnly(boolean)">
    -+      "http://developer.android.com/reference/android/app/Notification.Builder.html#setLocalOnly(boolean)">
    -       setLocalOnly</a> method.
    -     </p>
    - 
    -@@ -95,12 +261,6 @@ com.google.android.wearable.notificationBridgeMode
    -       the watch app may not be installed on all of them.
    -     </p>
    - 
    --    <p>
    --      Thus, if bridging should be prevented when the watch app
    --      is installed, use the <a href=
    --      "#preventing_bridging_with_the_bridging_mode_feature">Bridging mode
    --      feature</a>.
    --    </p>
    - 
    -     <h2 id="using_a_dismissal_id_to_sync_notification_dismissals">
    -       Using a Dismissal ID to Sync Notification Dismissals
    -@@ -110,7 +270,7 @@ com.google.android.wearable.notificationBridgeMode
    -       If you prevent bridging with the Bridging mode feature, dismissals
    -       (cancellations) of notifications are not synced across a user's devices.
    -       However, the following methods of the <a href=
    --      "{@docRoot}reference/android/support/v4/app/NotificationCompat.WearableExtender.html">
    -+      "http://developer.android.com/reference/android/support/v4/app/NotificationCompat.WearableExtender.html">
    -       NotificationCompat.WearableExtender</a> class enable you to use dismissal
    -       IDs:
    -     </p>
    -@@ -118,7 +278,7 @@ com.google.android.wearable.notificationBridgeMode
    -     <pre>
    - public WearableExtender setDismissalId(String dismissalId)
    - public String getDismissalId()
    --    </pre>
    -+</pre>
    -     <p>
    -       To enable a dismissal to be synced, use the <code>setDismissalId()</code>
    -       method. For each notification, pass a globally unique ID, as a string,
    -@@ -135,12 +295,12 @@ public String getDismissalId()
    - 
    -     <pre>
    - NotificationCompat.WearableExtender wearableExtender =
    --new NotificationCompat.WearableExtender().setDismissalId(“abc123”);
    -+new NotificationCompat.WearableExtender().setDismissalId("abc123");
    - Notification notification = new NotificationCompat.Builder(context)
    - &lt;set other fields&gt;
    - .extend(wearableExtender)
    - .build();
    --    </pre>
    -+</pre>
    -     <p>
    -       Dismissal IDs work if a watch is paired to an Android phone, but not if a
    -       watch is paired to an iPhone.
    -diff --git a/docs/html/wear/preview/features/complications.jd b/docs/html/wear/preview/features/complications.jd
    -index 3334cb7..c866118 100644
    ---- a/docs/html/wear/preview/features/complications.jd
    -+++ b/docs/html/wear/preview/features/complications.jd
    -@@ -13,6 +13,13 @@ page.image=/wear/preview/images/complications-main-image.png
    -             Complications to a Watch Face</a>
    -           </li>
    -           <li>
    -+            <a href="#permissions-for-complication-data">Permissions
    -+            for Complication Data</a>
    -+          </li>
    -+          <li>
    -+            <a href="#default-providers">Default Providers for Watch Faces</a>
    -+          </li>
    -+          <li>
    -             <a href="#exposing_data_to_complications">Exposing Data to
    -             Complications</a>
    -           </li>
    -@@ -27,12 +34,14 @@ page.image=/wear/preview/images/complications-main-image.png
    -             <a href="#api_additions">API Additions</a>
    -           </li>
    -       </ol>
    -+
    -     <h2>See Also</h2>
    -       <ol>
    -         <li><a class="external-link"
    -           href="https://github.com/googlesamples/android-WatchFace">Watch
    -           Face sample app with complications</a></li>
    -       </ol>
    -+
    -       </div>
    -     </div>
    - 
    -@@ -56,9 +65,12 @@ page.image=/wear/preview/images/complications-main-image.png
    -     </p>
    - 
    -     <p>
    --      Along with reviewing this page, download the Android Wear 2.0 Preview
    --      Reference (see the Complications API <a href=
    --      "#api_additions">additions</a>) and review the Javadoc for complications.
    -+      You can review the Javadoc for complications by downloading
    -+      the Android Wear 2.0 Preview
    -+      Reference. Also see the <a href="#api_additions">API additions for
    -+      complications</a> and the
    -+      <a href="https://developer.android.com/wear/preview/behavior-changes.html">
    -+      behavior changes</a> for Wear 2.0.
    -     </p>
    - 
    -     <p>
    -@@ -117,8 +129,8 @@ page.image=/wear/preview/images/complications-main-image.png
    -       <code>WatchFaceService.Engine</code> class, with a list of watch face
    -       complication IDs. A watch face creates these IDs to uniquely identify
    -       slots on the watch face where complications can appear, and passes them
    --      to the <code>createProviderChooserIntent</code> method (of the
    --      <code>ProviderChooserIntent</code> class) to allow the user to decide
    -+      to the <code>createProviderChooserIntent</code> method
    -+      to allow the user to decide
    -       which complication should go in which slot.
    -     </p>
    - 
    -@@ -186,6 +198,406 @@ page.image=/wear/preview/images/complications-main-image.png
    -       where possible.
    -     </p>
    - 
    -+    <h2 id="permissions-for-complication-data">
    -+      Permissions for Complication Data
    -+    </h2>
    -+
    -+    <p>
    -+      A watch face must have the following <a href=
    -+      "https://developer.android.com/training/permissions/requesting.html">permission</a>
    -+      to receive complication data and open the provider chooser:
    -+    </p>
    -+
    -+<pre>
    -+com.google.android.wearable.permission.RECEIVE_COMPLICATION_DATA
    -+</pre>
    -+
    -+    <h3 id="opening-the-provider-chooser">
    -+      Opening the provider chooser
    -+    </h3>
    -+
    -+    <p>
    -+      A watch face that was not granted the above permission will be unable to
    -+      start the provider chooser.
    -+    </p>
    -+
    -+    <p>
    -+      To make it easier to request the permission and start the chooser, the
    -+      <code>ComplicationHelperActivity</code> class is available in the
    -+      wearable support library. This class should be used instead of
    -+      <code>ProviderChooserIntent</code> to start the chooser in almost all
    -+      cases.
    -+    </p>
    -+
    -+    <h4 id="requesting-the-necessary-permission">
    -+      Requesting the necessary permission
    -+    </h4>
    -+
    -+    <p>
    -+      To use <code>ComplicationHelperActivity</code>, add it to the watch face
    -+      in the <a href=
    -+      "https://developer.android.com/guide/topics/manifest/manifest-intro.html">
    -+      manifest file</a>:
    -+    </p>
    -+
    -+<pre>
    -+&lt;activity android:name=&quot;android.support.wearable.complications.ComplicationHelperActivity&quot;/&gt;
    -+</pre>
    -+
    -+    <p>
    -+      To start the provider chooser, call the
    -+      <code>ComplicationHelperActivity.createProviderChooserHelperIntent</code>
    -+      method, to obtain an intent.
    -+    </p>
    -+
    -+    <p>
    -+      The new intent can be used with either <code>startActivity</code> or
    -+      <code>startActivityForResult</code> to launch the chooser.
    -+    </p>
    -+
    -+    <p>
    -+      Here is an example of using the new intent with
    -+      <code>startActivityForResult</code>:
    -+    </p>
    -+
    -+    <pre>
    -+startActivityForResult(
    -+  ComplicationHelperActivity.createProviderChooserHelperIntent(
    -+     getActivity(),
    -+     watchFace,
    -+     complicationId,
    -+     ComplicationData.TYPE_LARGE_IMAGE),
    -+  PROVIDER_CHOOSER_REQUEST_CODE);
    -+</pre>
    -+    <p>
    -+      When the helper activity is started, the helper activity checks if the
    -+      permission was granted. If the permission was not granted, the helper
    -+      activity makes a runtime permission request. If the permission request is
    -+      accepted (or is unneeded), the provider chooser is shown.
    -+    </p>
    -+
    -+    <p>
    -+      If <code>startActivityForResult</code> was used with the intent, the
    -+      result delivered back to the calling Activity will have a result code of
    -+      <code>RESULT_OK</code> if a provider was successfully set, or a result
    -+      code of <code>RESULT_CANCELLED</code> if no provider was set.
    -+    </p>
    -+
    -+    <p>
    -+      In the case where a provider was set,
    -+      <code>ComplicationProviderInfo</code> for the chosen provider will be
    -+      included in the data intent of the result, as an extra with the key
    -+      <code>ProviderChooserIntent#EXTRA_PROVIDER_INFO</code>.
    -+    </p>
    -+
    -+    <h3 id="receiving-complication-data">
    -+      Receiving complication data
    -+    </h3>
    -+
    -+    <p>
    -+      In general, watch faces need the above permission in order to receive
    -+      complication data, but there are some exceptions. Specifically, a watch
    -+      face can only receive data from a provider if one of the following is
    -+      true:
    -+    </p>
    -+
    -+    <ul>
    -+      <li>The provider is a "safe" system provider,
    -+      </li>
    -+
    -+      <li>The provider and watch face are from the same app,
    -+      </li>
    -+
    -+      <li>The provider whitelists the watch face as a "safe" watch face, or
    -+      </li>
    -+
    -+      <li>The watch face has the permission
    -+      </li>
    -+    </ul>
    -+
    -+    <h4 id="lack-of-appropriate-permission">
    -+      Lack of appropriate permission
    -+    </h4>
    -+
    -+    <p>
    -+      If none of the above is true, then when <code>ComplicationData</code>
    -+      normally would be sent by a provider to a watch face, the system instead
    -+      sends data of the type <code>TYPE_NO_PERMISSION</code>. This type
    -+      includes an icon (an exclamation mark) and short text ("--") to allow it
    -+      to be rendered as if it were of the short text type or icon type, for
    -+      convenience.
    -+    </p>
    -+
    -+    <p>
    -+      When a watch face receives data of <code>TYPE_NO_PERMISSION</code>, the
    -+      watch face should render this appropriately, so the user can see that
    -+      action is needed for the complication to work. If possible, a tap on a
    -+      complication in this state should launch a permission request. This can
    -+      be done using
    -+      <code>ComplicationHelperActivity.createPermissionRequestHelperIntent</code>,
    -+      if the helper activity was added to the watch face app.
    -+    </p>
    -+
    -+    <p>
    -+      If a user accepts the permission request created by the helper activity,
    -+      updates are requested for all the active complications on the watch face
    -+      automatically, allowing the <code>TYPE_NO_PERMISSION</code> data to be
    -+      replaced by real data.
    -+    </p>
    -+
    -+    <h4 id="safe-providers">
    -+      Safe providers
    -+    </h4>
    -+
    -+    <p>
    -+      Some system providers are considered "safe", because they only supply
    -+      information that the watch face already could obtain itself.
    -+    </p>
    -+
    -+    <p>
    -+      These providers are listed in the new <code>SystemProviders</code> class
    -+      in the wearable support library. Whether a system provider is safe is
    -+      stated in the Javadoc (in the Android Wear 2.0 Preview Reference). Also
    -+      see <a href="#system-providers">System providers</a> for a list.
    -+    </p>
    -+
    -+    <h4 id="provider-specified-safe-watch-faces">
    -+      Provider-specified safe watch faces
    -+    </h4>
    -+
    -+    <p>
    -+      Providers can specify certain watch faces as "safe" to receive their
    -+      data. This is intended to be used only when the watch face will attempt
    -+      to use the provider as a default (see below),
    -+      and the provider trusts the watch face app.
    -+    </p>
    -+
    -+    <p>
    -+      To declare watch faces as safe, the provider adds metadata with a key of
    -+      <code>android.support.wearable.complications.SAFE_WATCH_FACES</code>. The
    -+      metadata value should be a comma-separated list (whitespace is ignored).
    -+      Entries in the list can be component names (of
    -+      <code>WatchFaceServices</code>, given as if
    -+      <code>ComponentName.flattenToString()</code> had been called), or they
    -+      can be package names (of apps, in which case every watch face within a
    -+      specified app is considered safe).
    -+    </p>
    -+
    -+    <p>
    -+      For example:
    -+    </p>
    -+
    -+<pre>
    -+&lt;meta-data
    -+       android:name=&quot;android.support.wearable.complications.SAFE_WATCH_FACES&quot;
    -+        android:value=&quot;
    -+          com.app.watchface/com.app.watchface.MyWatchFaceService,
    -+          com.anotherapp.anotherwatchface/com.something.WatchFaceService,
    -+          com.something.text
    -+        &quot;/&gt;
    -+</pre>
    -+
    -+  <h2 id="default-providers">
    -+      Default Providers for Watch Faces
    -+  </h2>
    -+
    -+    <p>
    -+      Watch faces can specify default providers that are used until a user
    -+      selects a provider.
    -+    </p>
    -+
    -+    <h3 id="setting-default-providers">
    -+      Setting default providers
    -+    </h3>
    -+
    -+    <p>
    -+      Set default providers using the
    -+      <code>setDefaultComplicationProvider</code> method in
    -+      <code>WatchFaceService.Engine</code>. This method may be called at any
    -+      time, but it does nothing if the user already chose a provider for the
    -+      given complication.
    -+    </p>
    -+
    -+    <h3 id="safe-providers2">
    -+      Safe providers
    -+    </h3>
    -+
    -+    <p>
    -+      For most providers, the <code>RECEIVE_COMPLICATION_DATA</code> permission
    -+      must be granted to a watch face before data can flow to it. However, some
    -+      system providers are considered "safe", and do not require the watch face
    -+      to have the permission for data to be sent (see <a href=
    -+      "#safe-providers">Safe Providers</a> and <a href=
    -+      "#system-providers">System providers</a>). These providers may be
    -+      preferable to use as defaults, as they can supply data immediately.
    -+    </p>
    -+
    -+    <p>
    -+      Alternatively, if a watch face has a partnership with a certain provider
    -+      and wishes to use it as a default, it can request that the provider list
    -+      it as a safe watch face (see <a href=
    -+      "#provider-specified-safe-watch-faces">Provider-specified safe watch
    -+      faces</a>).
    -+    </p>
    -+
    -+    <h3 id="system-providers">
    -+      System providers
    -+    </h3>
    -+
    -+    <p>
    -+      The system includes providers that can be used as defaults. These are
    -+      listed in the <code>SystemProviders</code> class in the wearable support
    -+      library.
    -+    </p>
    -+
    -+    <p>
    -+      The following table has details about providers that are considered safe:
    -+    </p>
    -+
    -+    <table>
    -+      <tr>
    -+        <th>
    -+          Method name in the SystemProviders class
    -+        </th>
    -+        <th>
    -+          Safety
    -+        </th>
    -+        <th>
    -+          Can be the default
    -+        </th>
    -+        <th>
    -+          Notes
    -+        </th>
    -+      </tr>
    -+
    -+      <tr>
    -+        <td>
    -+          <code>dateProvider()</code>
    -+        </td>
    -+        <td>
    -+          Yes
    -+        </td>
    -+        <td>
    -+          Yes
    -+        </td>
    -+        <td>
    -+          The standard system date provider. Tapping opens the standard Agenda
    -+          app.
    -+        </td>
    -+      </tr>
    -+
    -+      <tr>
    -+        <td>
    -+          <code>currentTimeProvider()</code>
    -+        </td>
    -+        <td>
    -+          Yes
    -+        </td>
    -+        <td>
    -+          Yes
    -+        </td>
    -+        <td>
    -+          The standard system "time and date" provider. No tap action.
    -+        </td>
    -+      </tr>
    -+
    -+      <tr>
    -+        <td>
    -+          <code>batteryProvider()</code>
    -+        </td>
    -+        <td>
    -+          Yes
    -+        </td>
    -+        <td>
    -+          Yes
    -+        </td>
    -+        <td>
    -+          The standard system battery provider. No tap action.
    -+        </td>
    -+      </tr>
    -+
    -+      <tr>
    -+        <td>
    -+          <code>stepCountProvider()</code>
    -+        </td>
    -+        <td>
    -+          Yes
    -+        </td>
    -+        <td>
    -+          Yes
    -+        </td>
    -+        <td>
    -+          Shows a daily total of steps, as reported by
    -+          <code>readDailyTotal</code>.
    -+        </td>
    -+      </tr>
    -+
    -+      <tr>
    -+        <td>
    -+          <code>unreadCountProvider()</code>
    -+        </td>
    -+        <td>
    -+          Yes
    -+        </td>
    -+        <td>
    -+          Yes
    -+        </td>
    -+        <td>
    -+          Shows the number of unread notifications in the stream.
    -+        </td>
    -+      </tr>
    -+
    -+      <tr>
    -+        <td>
    -+          <code>worldClockProvider()</code>
    -+        </td>
    -+        <td>
    -+          Yes
    -+        </td>
    -+        <td>
    -+          Yes
    -+        </td>
    -+        <td>
    -+          Will default to London or New York. Can be tapped to change the time
    -+          zone.
    -+        </td>
    -+      </tr>
    -+
    -+      <tr>
    -+        <td>
    -+          <code>appsProvider()</code>
    -+        </td>
    -+        <td>
    -+          Yes
    -+        </td>
    -+        <td>
    -+          Yes
    -+        </td>
    -+        <td>
    -+          Will show an "apps" icon at first, which can be tapped to choose an
    -+          app.
    -+        </td>
    -+      </tr>
    -+
    -+      <tr>
    -+        <td>
    -+          <code>nextEventProvider()</code>
    -+        </td>
    -+        <td>
    -+          No
    -+        </td>
    -+        <td>
    -+          Yes (but not a safe provider)
    -+        </td>
    -+        <td>
    -+          The standard system "next event" provider. Tapping opens
    -+            the standard Agenda app.
    -+          </p>
    -+        </td>
    -+      </tr>
    -+    </table>
    -+
    -+
    -     <h2 id="exposing_data_to_complications">
    -       Exposing Data to Complications
    -     </h2>
    -@@ -203,6 +615,11 @@ page.image=/wear/preview/images/complications-main-image.png
    -       be used to send data back to the system.
    -     </p>
    - 
    -+    <p class="note"><strong>Note:</strong> When you provide data as a
    -+    complication data provider, the watch face receives the raw values
    -+    you send so it can draw them on the watch face.
    -+    </p>
    -+
    -     <p>
    -       In your app's manifest, declare the service and add an intent filter for
    -       the following:
    -@@ -210,7 +627,8 @@ page.image=/wear/preview/images/complications-main-image.png
    - 
    -     <pre>
    - android.support.wearable.complications.ACTION_COMPLICATION_UPDATE_REQUEST
    --</pre>
    -+    </pre>
    -+
    -     <p>
    -       The service's manifest entry should also include an
    -       <code>android:icon</code> attribute. The provided icon should be a
    -@@ -227,6 +645,21 @@ android.support.wearable.complications.ACTION_COMPLICATION_UPDATE_REQUEST
    -       <a href="#api_additions">API Additions</a>).
    -     </p>
    - 
    -+    <p>
    -+      Additionally, a permission for provider services ensures that only the Android Wear system
    -+      can bind to provider services. Only the Android Wear system can have this
    -+      permission.
    -+    </p>
    -+
    -+    <p>
    -+      Provider services should add the following to their service declarations
    -+      in the manifest:
    -+    </p>
    -+
    -+<pre>
    -+android:permission="com.google.android.wearable.permission.BIND_COMPLICATION_PROVIDER"
    -+</pre>
    -+
    -     <h3 id="update_period">
    -       Update period
    -     </h3>
    -@@ -371,6 +804,11 @@ METADATA_KEY_PROVIDER_CONFIG_ACTION
    -     <p>
    -       The following table describes the types and fields of the
    -       <code>ComplicationData</code> object.
    -+      If a watch face requests a field that is invalid for a complication type,
    -+      a default value for the field is returned.
    -+      For example, if a watch face tries to access a <code>Long text</code>
    -+      field in a <code>SHORT_TEXT</code> type, the default value for the
    -+      <code>Long text</code> field is returned.
    -     </p>
    - 
    -     <table>
    -@@ -489,56 +927,80 @@ METADATA_KEY_PROVIDER_CONFIG_ACTION
    -     </table>
    - 
    -     <p>
    --      In addition, the following two types have no fields. These two types may
    --      be sent for any complication slot and do not need to be included in a
    --      list of supported types:
    -+      In addition, the types in the table below are for empty data and
    -+      may be sent for any complication slot. These types have no fields
    -+      and do not need to be included in a
    -+      list of supported types. These types enable watch
    -+      faces to differentiate among the following three cases:
    -+    </p>
    -+
    -+    <ul>
    -+      <li>No provider was chosen
    -+      </li>
    -+
    -+      <li>The user has selected "empty" for a slot
    -+      </li>
    -+
    -+      <li>A provider has no data to send
    -+      </li>
    -+    </ul>
    -+
    -+    <p>
    -+      Providers should not send <code>TYPE_EMPTY</code> in response to
    -+      update requests. Providers should send <code>TYPE_NO_DATA</code> instead.
    -+    </p>
    -+
    -+    <p>
    -+      Details on the complication types for "empty" data are in the
    -+      following table:
    -     </p>
    - 
    -     <table>
    -       <tr>
    --        <th style="width:175px">
    --          Type
    --        </th>
    --        <th style="width:175px">
    --          Required fields
    -+        <th>Complication type
    -         </th>
    --        <th style="width:175px">
    --          Optional fields
    --        </th>
    --        <th>
    --          Notes
    -+        <th>Description
    -         </th>
    -       </tr>
    - 
    -       <tr>
    -         <td>
    --          NOT_CONFIGURED
    --        </td>
    --        <td>
    --          None
    --        </td>
    --        <td>
    --          None
    -+          <code>TYPE_NOT_CONFIGURED</code>
    -         </td>
    -         <td>
    --          Sent when a provider has not yet been chosen for a complication.
    -+          Sent by the system when a complication is activated but the user has
    -+          not selected a provider, and no default was set.
    -+          <p>
    -+            Cannot be sent by providers.
    -+          </p>
    -         </td>
    -       </tr>
    - 
    -       <tr>
    -         <td>
    --          EMPTY
    -+          <code>TYPE_EMPTY</code>
    -         </td>
    -         <td>
    --          None
    -+          Sent by the system when a complication is activated and the user has
    -+          chosen "empty" instead of a provider, or when the watch face has
    -+          chosen no provider, and this type, as the default.
    -+          <p>
    -+            Cannot be sent by providers.
    -+          </p>
    -         </td>
    -+      </tr>
    -+
    -+      <tr>
    -         <td>
    --          None
    -+          <code>TYPE_NO_DATA</code>
    -         </td>
    -         <td>
    --          Sent by a provider when there is no data to display in a
    --          complication, or sent by the system when nothing should be shown in a
    --          complication.
    -+          Sent by the system when a complication (that has a provider) is
    -+          activated, to clear the complication before actual data is received
    -+          from the provider.
    -+          <p>
    -+            Should be sent by providers if they have no actual data to send.
    -+          </p>
    -         </td>
    -       </tr>
    -     </table>
    -@@ -700,8 +1162,8 @@ METADATA_KEY_PROVIDER_CONFIG_ACTION
    -     </h2>
    - 
    -     <p>
    --      The Complications API includes new classes in the Wearable Support
    --      Library. For more information, download the <a href=
    -+      The Complications API includes new classes in the wearable support
    -+      library. For more information, download the <a href=
    -       "{@docRoot}wear/preview/start.html#get_the_preview_reference_documentation">
    -       Android Wear 2.0 Preview Reference</a>.
    -     </p>
    -@@ -722,14 +1184,26 @@ METADATA_KEY_PROVIDER_CONFIG_ACTION
    -       </li>
    - 
    -       <li>
    --        <code>ComplicationText</code>
    -+        <code>ComplicationHelperActivity</code>
    -         <ul>
    --          <li>Used to supply text-based values in a
    --          <code>ComplicationData</code> object
    -+          <li>Used to request the following permission: <br>
    -+<code>com.google.android.wearable.permission.RECEIVE_COMPLICATION_DATA</code>
    -           </li>
    - 
    --          <li>Includes options for time-dependent values, whose text value
    --          depends on the current time
    -+          <li>Used instead of <code>ProviderChooserIntent</code>
    -+          to start the chooser in almost all cases
    -+          </li>
    -+        </ul>
    -+      </li>
    -+
    -+      <li>
    -+        <code>ComplicationManager</code>
    -+        <ul>
    -+          <li>A wrapper for the complication manager service, for use by
    -+          providers
    -+          </li>
    -+
    -+          <li>Allows providers to send complication data to the system
    -           </li>
    -         </ul>
    -       </li>
    -@@ -747,13 +1221,14 @@ METADATA_KEY_PROVIDER_CONFIG_ACTION
    -       </li>
    - 
    -       <li>
    --        <code>ComplicationManager</code>
    -+        <code>ComplicationText</code>
    -         <ul>
    --          <li>A wrapper for the complication manager service, for use by
    --          providers
    -+          <li>Used to supply text-based values in a
    -+          <code>ComplicationData</code> object
    -           </li>
    - 
    --          <li>Allows providers to send complication data to the system
    -+          <li>Includes options for time-dependent values, whose text value
    -+          depends on the current time
    -           </li>
    -         </ul>
    -       </li>
    -@@ -761,11 +1236,8 @@ METADATA_KEY_PROVIDER_CONFIG_ACTION
    -       <li>
    -         <code>ProviderChooserIntent</code>
    -         <ul>
    --          <li>Non-instantiable utility class
    --          </li>
    --
    --          <li>Includes a method that a watch face can call for starting a
    --          provider chooser (to allow a user to configure complications)
    -+          <li>Non-instantiable utility class that is not commonly used; use
    -+          <code>ComplicationHelperActivity</code> instead
    -           </li>
    -         </ul>
    -       </li>
    -@@ -789,6 +1261,16 @@ METADATA_KEY_PROVIDER_CONFIG_ACTION
    -           </li>
    -         </ul>
    -       </li>
    -+
    -+      <li>
    -+        <code>SystemProviders</code>
    -+        <ul>
    -+          <li>Lists system providers that are considered "safe",
    -+          because they only supply information that the watch face
    -+          already could obtain itself
    -+          </li>
    -+        </ul>
    -+      </li>
    -     </ul>
    - 
    -     <p>
    -diff --git a/docs/html/wear/preview/features/notifications.jd b/docs/html/wear/preview/features/notifications.jd
    -index dcc0970..b546978 100644
    ---- a/docs/html/wear/preview/features/notifications.jd
    -+++ b/docs/html/wear/preview/features/notifications.jd
    -@@ -1,6 +1,5 @@
    - page.title=Notification Changes in Android Wear 2.0
    --meta.tags="wear", "wear-preview", "notifications"
    --page.tags="wear"
    -+meta.tags="wear", "wear-preview", "notifications" page.tags="wear"
    - page.image=/wear/preview/images/expanded_diagram.png
    - 
    - 
    -@@ -12,6 +11,7 @@ page.image=/wear/preview/images/expanded_diagram.png
    -     <h2>This document includes</h2>
    -     <ol>
    -       <li><a href="#visual">Visual Updates</a></li>
    -+      <li><a href="#inline">Inline Action</a></li>
    -       <li><a href="#expanded">Expanded Notifications</a></li>
    -       <li><a href="#messaging">MessagingStyle</a></li>
    -     </ol>
    -@@ -67,7 +67,8 @@ material design</a> visual changes.
    -   We recommended that you don't set color for bridged notifications.
    - 
    -   When Wear apps post local notifications, you can work around this by checking
    --  <a href="{@docRoot}training/basics/supporting-devices/platforms.html#version-codes">the API level of the device</a> they're running on and using an appropriate color
    -+  <a href="{@docRoot}training/basics/supporting-devices/platforms.html#version-codes">the API level of the device</a>
    -+   they're running on and using an appropriate color
    -   for Wear 1.x and a different color for Wear 2.0.
    - </li>
    - 
    -@@ -77,6 +78,85 @@ material design</a> visual changes.
    -   you must update the text of your notification.
    - </li>
    - </ul>
    -+
    -+<h2 id="inline">Inline Action</h3>
    -+
    -+<img src="{@docRoot}wear/preview/images/inline_action.png" style="float:right;margin:10px 20px 0 0">
    -+<p>
    -+  Wear 2.0 now supports inline action, which allows users to take actions on a
    -+  notification from within the notification stream card.  On Wear, the inline
    -+  action appears as an additional button displayed at the bottom of the notification.
    -+</p>
    -+<p>
    -+  Inline actions are optional but recommended for cases in which users are likely
    -+  to take an action on a notification after viewing the contents in the
    -+  notification stream card (without going to the
    -+  <a href= "{@docRoot}wear/preview/features/notifications.html#expanded">expanded notification</a>).
    -+  Examples of good use cases for inline action on a notification include: replying to a
    -+  text message, stopping a fitness activity, and archiving an email message.
    -+</p>
    -+
    -+<p>
    -+  A notification can provide only one inline action.
    -+  To display the inline action as an additional button in the notification, set
    -+  the <a href="https://developer.android.com/reference/android/support/v4/app/NotificationCompat.Action.WearableExtender.html#setHintDisplayActionInline(boolean)">{@code setHintDisplayActionInline()}</a>
    -+  method to true. When a user taps the inline action, the system invokes
    -+  the intent that you specified in the notification action.
    -+</p>
    -+
    -+<h3>Adding an inline action</h3>
    -+<p>
    -+  The following code example shows how to create a notification with an inline
    -+  reply action:
    -+</p>
    -+
    -+<ol>
    -+  <li>Create an instance of
    -+    <a href="https://developer.android.com/reference/android/support/v4/app/RemoteInput.Builder.html">{@code RemoteInput.Builder}</a></code>
    -+    that you can add to your notification action. This class's constructor accepts a
    -+    string that the system uses as the key for the text input. Later, your app
    -+    uses that key to retrieve the text of the input.
    -+
    -+<pre>
    -+String[] choices = context.getResources().getStringArray(R.array.notification_reply_choices);
    -+    choices = WearUtil.addEmojisToCannedResponse(choices);
    -+  RemoteInput remoteInput = new RemoteInput.Builder(Intent.EXTRA_TEXT)
    -+        .setLabel(context.getString(R.string.notification_prompt_reply))
    -+        .setChoices(choices)
    -+        .build();
    -+</pre>
    -+
    -+  </li>
    -+
    -+  <li>
    -+    Use the <a href="https://developer.android.com/reference/android/support/v4/app/NotificationCompat.Action.Builder.html#addRemoteInput(android.support.v4.app.RemoteInput)">{@code addRemoteInput()}</a>
    -+    method to attach the <ahref="https://developer.android.com/reference/android/support/v4/app/RemoteInput.html">{@code RemoteInput}</a>
    -+    object to an action.
    -+
    -+<pre>
    -+NotificationCompat.Action.Builder actionBuilder = new NotificationCompat.Action.Builder(
    -+        R.drawable.ic_full_reply, R.string.notification_reply, replyPendingIntent);
    -+    actionBuilder.addRemoteInput(remoteInput);
    -+    actionBuilder.setAllowGeneratedReplies(true);
    -+</pre>
    -+  </li>
    -+
    -+  <li>
    -+    Add a hint to display the reply action inline, and use the
    -+    <a href="https://developer.android.com/reference/android/support/v4/app/NotificationCompat.WearableExtender.html#addAction(android.support.v4.app.NotificationCompat.Action)">{@code addAction}</a>
    -+    method to add this action to the notification.
    -+
    -+<pre>
    -+// Android Wear 2.0 requires a hint to display the reply action inline.
    -+    Action.WearableExtender actionExtender =
    -+        new Action.WearableExtender()
    -+            .setHintLaunchesActivity(true)
    -+            .setHintDisplayActionInline(true);
    -+    wearableExtender.addAction(actionBuilder.extend(actionExtender).build());
    -+</pre>
    -+  </li>
    -+</ol>
    -+
    - <h2 id="expanded">Expanded Notifications</h2>
    - <p>Android Wear 2.0 introduces <i>expanded notifications</i>, which provide
    -   substantial additional content and actions for each notification.
    -@@ -152,51 +232,52 @@ action in the notification unless a different action is specified using
    - </p>
    - <h2 id="messaging">MessagingStyle</h2>
    - 
    --<p>If you have a chat messaging app, your notifications should use
    --<a href="{@docRoot}preview/features/notification-updates.html#style">{@code Notification.MessagingStyle}</a>,
    -- which is new in Android N. Wear 2.0 uses the chat messages included
    --  in a <a href="{@docRoot}preview/features/notification-updates.html#style">{@code MessagingStyle}</a> notification
    --
    --  (see <a href="{@docRoot}preview/features/notification-updates.html#style">{@code addMessage()}</a>) to provide
    --  a rich chat app-like experience in the expanded notification.
    -+<p>
    -+  If you have a chat messaging app, your notifications should use
    -+  <a href="https://developer.android.com/reference/android/support/v4/app/NotificationCompat.MessagingStyle.html">{@code NotificationCompat.MessagingStyle}</a>,
    -+  which is new in Android 7.0. Wear 2.0 uses the chat messages included in a
    -+  {@code MessagingStyle} notification
    -+  (see <a href="https://developer.android.com/reference/android/support/v4/app/NotificationCompat.MessagingStyle.html#addMessage(android.support.v4.app.NotificationCompat.MessagingStyle.Message)">{@code addMessage()}</a>)
    -+  to provide a rich chat app-like experience in the expanded notification.
    - </p>
    - 
    --<p class="note">Note: <a href="{@docRoot}preview/features/notification-updates.html#style">{@code MessagingStyle}</a>
    -+<p class="note">Note: <a href="https://developer.android.com/reference/android/support/v4/app/NotificationCompat.MessagingStyle.html">{@code MessagingStyle}</a>
    - expanded notifications require that you have at least version 1.5.0.2861804 of the
    -   <a href="https://play.google.com/store/apps/details?id=com.google.android.wearable.app">Android Wear app</a>
    --  on your paired Android phone. That version will be available within the next
    --  few weeks in the Play Store.
    -+  on your paired Android phone.
    - </p>
    - 
    - <h3 id="smart-reply">Smart Reply</h3>
    - <img src="{@docRoot}wear/preview/images/messaging_style.png" height="420"
    -   style="float:right;margin:10px 20px 0 0" />
    --<p>Wear 2.0 also introduces <i>Smart Reply</i>
    --for <a href="{@docRoot}preview/features/notification-updates.html#style">{@code MessagingStyle}</a> notifications.
    -+<p>Wear 2.0 also introduces <i>Smart Reply</i> for
    -+  <a href="https://developer.android.com/reference/android/support/v4/app/NotificationCompat.MessagingStyle.html">{@code MessagingStyle}</a> notifications.
    -   Smart Reply provides the user with contextually relevant, touchable choices in
    -   the expanded notification and in {@code RemoteInput}. These augment the fixed
    -   list of choices that the developer provides in
    --   <a href="http://developer.android.com/reference/android/support/v4/app/RemoteInput.html">{@code RemoteInput}</a>
    --    using the
    --    <a href="{@docRoot}reference/android/support/v4/app/RemoteInput.Builder.html#setChoices(java.lang.CharSequence[])">{@code setChoices()}</a> method.
    -+  <a href="http://developer.android.com/reference/android/support/v4/app/RemoteInput.html">{@code RemoteInput}</a>
    -+  using the
    -+  <a href="{@docRoot}reference/android/support/v4/app/RemoteInput.Builder.html#setChoices(java.lang.CharSequence[])">{@code setChoices()}</a> method.
    - </p>
    --<p>By enabling Smart Reply for your MessagingStyle notifications,
    --  you provide users with a fast (single tap), discreet (no speaking aloud), and
    --  reliable way to respond to chat messages.
    -+<p> Smart Reply provides users with a fast (single tap), discreet (no speaking aloud),
    -+  private (messages received by a user never leave the watch), and reliable (no
    -+  internet connection needed) way to respond to chat messages.
    - </p>
    - 
    --<p>Responses generated by Smart Reply are shown in addition to those set using the
    --  <a href="{@docRoot}reference/android/support/v4/app/RemoteInput.Builder.html#setChoices(java.lang.CharSequence[])">{@code setChoices()}</a> method.
    -+<p>
    -+  Smart Reply responses are generated by an entirely on-watch machine learning
    -+  model using the context provided by the MessagingStyle notification. No user
    -+  notification data is sent to Google servers to generate Smart Reply responses.
    - </p>
    -+
    - <p>To enable Smart Reply for your notification action, you need to do the
    - following:
    - </p>
    - <ol>
    --  <li>Use <a href="{@docRoot}preview/features/notification-updates.html#style">{@code Notification.MessagingStyle}</a>.
    -+  <li>Use <a href="https://developer.android.com/reference/android/support/v4/app/NotificationCompat.MessagingStyle.html">{@code NotificationCompat.MessagingStyle}</a>.
    -   </li>
    --  <li>Call the method {@code setAllowGeneratedReplies()} for the notification action.
    --  For more information, see the downloadable
    --  <a href="{@docRoot}preview/setup-sdk.html#docs-dl">API reference</a>.
    -+  <li>Call the method <a href="https://developer.android.com/reference/android/support/v4/app/NotificationCompat.Action.Builder.html#setAllowGeneratedReplies(boolean)">{@code setAllowGeneratedReplies(true)}</a>
    -+   for the notification action.
    -   </li>
    -   <li>Ensure that the notification action has a
    -     <a href="{@docRoot}reference/android/app/RemoteInput.html">{@code RemoteInput}</a>
    -@@ -236,3 +317,29 @@ Notification noti = new NotificationCompat.Builder()
    - // 3) add an action with RemoteInput
    - .extend(new WearableExtender().addAction(action)).build();
    - </pre>
    -+
    -+<h3 id="images">Adding images to a MessagingStyle notification</h3>
    -+<p>
    -+  You can add images to a notification message  by setting the appropriate MIME
    -+  type and placing the URI to the image in {@code NotificationCompat.MessagingStyle.Message.}
    -+  <a href="https://developer.android.com/reference/android/support/v4/app/NotificationCompat.MessagingStyle.Message.html#setData(java.lang.String, android.net.Uri)">{@code setData()}</a> method.
    -+</p>
    -+<p>
    -+  Here is the code snippet to set data of type image in a notification:
    -+</p>
    -+<pre>
    -+NotificationCompat.MessagingStyle.Message message = new Message("sticker", 1, "Jeff")
    -+                      .setData("image/png", stickerUri);
    -+
    -+  NotificationCompat notification = new NotificationCompat.Builder()
    -+             .setStyle(new NotificationComapt.MessagingStyle("Me")
    -+             .addMessage(message)
    -+             .build());
    -+
    -+</pre>
    -+<p>
    -+  In the above code snippet the variable <code>stickerUri </code>is a Uri that
    -+  points to a publicly-accessible location, as described <a
    -+  href="https://developer.android.com/reference/android/support/v4/app/NotificationCompat.MessagingStyle.Message.html">here
    -+  </a>.
    -+</p>
    -\ No newline at end of file
    -diff --git a/docs/html/wear/preview/features/standalone-apps.jd b/docs/html/wear/preview/features/standalone-apps.jd
    -new file mode 100644
    -index 0000000..5c1930d
    ---- /dev/null
    -+++ b/docs/html/wear/preview/features/standalone-apps.jd
    -@@ -0,0 +1,499 @@
    -+page.title=Standalone Apps
    -+meta.keywords="wear-preview"
    -+page.tags="wear-preview"
    -+page.image=images/cards/card-n-sdk_2x.png
    -+
    -+@jd:body
    -+
    -+<div id="qv-wrapper">
    -+<div id="qv">
    -+
    -+<h2>In this document</h2>
    -+
    -+  <ul>
    -+    <li><a href="#planning_apps">Planning Your Phone and Watch Apps</a></li>
    -+    <li><a href="#network_access">Network Access and Cloud Messaging</a></li>
    -+    <li><a href="#background_services">Using Background Services</a></li>
    -+    <li><a href="#fcm">Cloud Notifications Using FCM</a></li>
    -+    <li><a href="#fcm-phone">Notifications from a Companion Phone</a></li>
    -+  </ul>
    -+
    -+</div>
    -+</div>
    -+
    -+    <p>
    -+      In Android Wear 2.0, apps can work independently of a phone. Users can
    -+      complete more tasks on a watch, without access to an Android or iOS
    -+      phone.
    -+    </p>
    -+
    -+    <h2 id="planning_apps">
    -+      Planning Your Phone and Watch Apps
    -+    </h2>
    -+
    -+    <p>
    -+      A watch APK targeting Wear 2.0 should not be embedded in a phone APK.
    -+      For more information, see
    -+      <a href="{@docRoot}wear/preview/features/app-distribution.html">
    -+      App Distribution</a>.
    -+    </p>
    -+
    -+    <p>
    -+      Generally, the minimum and target API level for a standalone app, and
    -+      for Wear 2.0, is level 24. The minimum SDK level can be 23
    -+      only if you are using the same APK
    -+      for Wear 1.0 and 2.0 (and thus have an embedded Wear 1.0 APK).
    -+    </p>
    -+
    -+    <p>
    -+      If you build a standalone Wear 2.0 APK and will continue to have a
    -+      Wear 1.0 APK, please do both of the following:
    -+    </p>
    -+
    -+    <ul>
    -+      <li>Provide a standalone version of the Wear APK, and
    -+      </li>
    -+
    -+      <li>Continue embedding a version of the Wear APK in your phone APK
    -+      </li>
    -+    </ul>
    -+
    -+    <p>
    -+      <strong>Caution</strong>: For the Wear 2.0 Developer Preview, if you
    -+      publish an update to your production phone APK that has removed an embedded
    -+      Wear APK, production users who update the phone APK before installing
    -+      your standalone Wear APK will lose their existing Wear app and its data.
    -+      Therefore, it's important that you continue to embed
    -+      your watch APK into your phone APK.
    -+    </p>
    -+
    -+    <p>
    -+      <a href=
    -+      "https://developer.android.com/training/articles/wear-permissions.html">
    -+      Run-time permissions</a> are required for standalone apps.
    -+    </p>
    -+
    -+    <h3>
    -+      Shared code and data storage
    -+    </h3>
    -+
    -+    <p>
    -+      Code can be shared between a Wear app and a phone app. Optionally, code
    -+      that is specific to a form factor can be in a separate module.
    -+    </p>
    -+
    -+    <p>
    -+      For example, common code for networking can be in a shared library.
    -+    </p>
    -+
    -+    <p>
    -+      You can use standard Android storage APIs to store data locally.
    -+      For example, you can use
    -+      the <a href=
    -+      "https://developer.android.com/reference/android/content/SharedPreferences.html">
    -+      SharedPreferences APIs</a>, SQLite, or internal storage (as you would in
    -+      the case of a phone).
    -+    </p>
    -+
    -+    <h3>
    -+      Detecting your phone app or watch app
    -+    </h3>
    -+
    -+    <p>
    -+      If a user of your watch app needs your phone app, your watch app can
    -+      detect if the phone app is available. Using the <a href=
    -+      "https://developers.google.com/android/reference/com/google/android/gms/wearable/CapabilityApi">
    -+      CapabilityApi</a>, your phone app or watch app can advertise its presence
    -+      to a paired device. It can do so statically and dynamically. When an app
    -+      is on a node in a user's Wear network (i.e., on a phone, paired watch, or
    -+      in the cloud), the <code>CapabilityApi</code> enables another
    -+      app to detect if it is installed. For more information, see <a href=
    -+      "https://developer.android.com/training/wearables/data-layer/messages.html#AdvertiseCapabilities">
    -+      Advertise capabilities</a>.
    -+    </p>
    -+
    -+    <p>
    -+      If your phone app is unavailable, your can check if the Play Store is
    -+      available on the phone, as described below, before directing the user to
    -+      go to the Play Store (to install your phone app).
    -+    </p>
    -+
    -+    <h4>
    -+      Checking for Play Store availability on a phone
    -+    </h4>
    -+
    -+    <p>
    -+      iPhones and some Android phones lack the Play Store. A standalone Wear
    -+      app can check if the paired phone has the Play Store, before directing a
    -+      user to go there to install your phone app. The
    -+      <code>PlayStoreAvailability</code> class contains a
    -+      <code>getPlayStoreAvailabilityOnPhone()</code> method that enables your
    -+      Wear app to check if a companion phone has the Play Store.
    -+    </p>
    -+
    -+    <p>
    -+      More information about the <code>PlayStoreAvailability</code> class is
    -+      available when you <a href=
    -+      "https://developer.android.com/wear/preview/start.html#get_the_preview_reference_documentation">
    -+      download the Android Wear 2.0 Preview Reference</a>. Here is a snippet
    -+      that uses the <code>getPlayStoreAvailabilityOnPhone()</code> method to
    -+      determine if the paired phone has the Play Store:
    -+    </p>
    -+
    -+<pre>
    -+int playStoreAvailabilityOnPhone =
    -+PlayStoreAvailability.getPlayStoreAvailabilityOnPhone(context);
    -+</pre>
    -+
    -+    <p>
    -+      The value returned by the <code>getPlayStoreAvailabilityOnPhone()</code>
    -+      method is one of the following:
    -+    </p>
    -+
    -+    <table>
    -+      <tr>
    -+        <th>
    -+          <strong>Return value</strong>
    -+        </th>
    -+        <th>
    -+          <strong>Description</strong>
    -+        </th>
    -+      </tr>
    -+
    -+      <tr>
    -+        <td>
    -+          <code>PLAY_STORE_ON_PHONE_AVAILABLE</code>
    -+        </td>
    -+        <td>
    -+          The Play Store is available on the companion phone.
    -+        </td>
    -+      </tr>
    -+
    -+      <tr>
    -+        <td>
    -+          <code>PLAY_STORE_ON_PHONE_UNAVAILABLE</code>
    -+        </td>
    -+        <td>
    -+          The Play Store is not available on the companion phone.
    -+        </td>
    -+      </tr>
    -+
    -+      <tr>
    -+        <td>
    -+          <code>PLAY_STORE_ON_PHONE_ERROR_UNKNOWN</code>
    -+        </td>
    -+        <td>
    -+          An error occurred in the check for the Play Store; another check
    -+          should be made later.
    -+        </td>
    -+      </tr>
    -+    </table>
    -+
    -+    <h2 id="network_access">
    -+      Network Access and Cloud Messaging
    -+    </h2>
    -+
    -+    <p>
    -+      Android Wear apps can make their own network requests. When a watch has a
    -+      Bluetooth connection to a phone, the watch's network traffic is proxied
    -+      through the phone. When a phone is unavailable, Wi-Fi and cellular
    -+      networks are used, depending on the hardware. The Wear platform handles
    -+      transitions between networks. A watch's network access thus does not
    -+      require the <a href=
    -+      "https://developer.android.com/training/wearables/data-layer/index.html">
    -+      Wearable Data Layer API</a>.
    -+    </p>
    -+
    -+    <p>
    -+      For sending notifications, apps can directly use Firebase Cloud Messaging
    -+      (FCM), which replaces Google Cloud Messaging, or continue to use GCM.
    -+    </p>
    -+
    -+    <p>
    -+      No APIs for network access or FCM are specific to Android Wear.
    -+      Refer to the existing documentation about <a href=
    -+      "https://developer.android.com/training/basics/network-ops/connecting.html">
    -+      connecting to a network</a> and <a href=
    -+      "https://developers.google.com/cloud-messaging/">cloud messaging</a>.
    -+    </p>
    -+
    -+    <p>
    -+      You can use protocols such as HTTP, TCP, and UDP. However,
    -+      the <a href="https://developer.android.com/reference/android/webkit/package-summary.html">
    -+      android.webkit</a> APIs are not available. Therefore,
    -+      use of cookies is available by reading and writing headers on
    -+      requests and responses, but the <a href=
    -+      "https://developer.androidcom/reference/android/webkit/CookieManager.html">
    -+      CookieManager</a> class is not available.
    -+    </p>
    -+
    -+    <p>
    -+      FCM works well with
    -+      <a href="https://developer.android.com/training/monitoring-device-state/doze-standby.html">
    -+      Doze</a>.
    -+    </p>
    -+
    -+    <p>
    -+      Additionally, we recommend using the following:
    -+    </p>
    -+
    -+    <ul>
    -+      <li>The <a href=
    -+      "https://developer.android.com/reference/android/app/job/JobScheduler.html">
    -+        JobScheduler</a> API for asynchronous jobs, including polling at
    -+        regular intervals (described below)
    -+      </li>
    -+
    -+      <li>Multi-networking APIs if you need to connect to specific network
    -+      types; see <a href=
    -+      "https://developer.android.com/about/versions/android-5.0.html#Wireless">
    -+        Multiple Network Connections</a>
    -+      </li>
    -+    </ul>
    -+
    -+    <p>
    -+      For foreground use cases, we currently recommend that you make a
    -+      request for an unmetered network. Here is an example of using
    -+      the multi-networking APIs to request an unmetered network:
    -+    </p>
    -+
    -+<pre>
    -+ConnectivityManager.NetworkCallback networkCallback =
    -+  new ConnectivityManager.NetworkCallback() {
    -+    &#64;Override
    -+    public void onAvailable(Network network) {
    -+      // access network
    -+      }
    -+    };
    -+ConnectivityManager connectivityManager =
    -+  (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
    -+
    -+connectivityManager.requestNetwork(new NetworkRequest.Builder()
    -+  .addCapability(NET_CAPABILITY_NOT_METERED)
    -+  .build(), networkCallback);
    -+</pre>
    -+
    -+    <p>
    -+      We also recommend setting a timer for frontend scenarios
    -+      to prevent a user from potentially waiting for a long time.
    -+      When the network is no longer needed, or if the timer fires,
    -+      the network callback needs to be unregistered:
    -+    </p>
    -+
    -+<pre>
    -+connectivityManager.unregisterNetworkCallback(networkCallback):
    -+</pre>
    -+
    -+    <p>
    -+      A Wear app can communicate with a phone app using the <a href=
    -+      "https://developer.android.com/training/wearables/data-layer/index.html">Wearable
    -+      Data Layer API</a>, but connecting to a network using that API is
    -+      discouraged.
    -+    </p>
    -+
    -+    <h3 id="necessary_data">
    -+      Obtaining only the necessary data
    -+    </h3>
    -+
    -+    <p>
    -+      When obtaining data from the cloud, get only the necessary data.
    -+      Otherwise, you may introduce unnecessary latency, memory use, and battery
    -+      use.
    -+    </p>
    -+
    -+    <p>
    -+      When a watch is connected over a Bluetooth LE connection, your app may
    -+      have access to a bandwidth of only 10 kilobytes per second. Therefore,
    -+      the following steps are recommended:
    -+    </p>
    -+
    -+    <ul>
    -+      <li>Audit your network requests and responses for extra data that only is
    -+      for a phone app
    -+      </li>
    -+
    -+      <li>Shrink large images before sending them over a network to a watch
    -+      </li>
    -+    </ul>
    -+
    -+    <h2 id="background_services">
    -+      Using Background Services
    -+    </h2>
    -+
    -+    <p>
    -+      To ensure that background tasks are correctly executed, they must account
    -+      for <a href=
    -+      "https://developer.android.com/training/monitoring-device-state/doze-standby.html">
    -+      Doze</a>. In Android 6.0, Doze and App Standby resulted in significant
    -+      improvements to battery life by allowing devices to enter deep sleep when
    -+      idle and stationary.
    -+    </p>
    -+
    -+    <p>
    -+      Doze is <a href=
    -+      "https://developer.android.com/preview/behavior-changes.html#doze">enhanced</a>
    -+      in Android Nougat and Android Wear 2.0. When a screen turns off or enters
    -+      ambient mode for a long enough time, a subset of Doze can occur and
    -+      background tasks may be deferred for certain periods. Later, when a
    -+      device is stationary for an extended time, regular Doze occurs.
    -+    </p>
    -+
    -+    <p>
    -+      You should schedule jobs with the <a href=
    -+      "https://developer.android.com/reference/android/app/job/JobScheduler.html">
    -+      JobScheduler</a> API, which enables your app to register for Doze-safe
    -+      code execution. When scheduling jobs, you can select constraints such as
    -+      periodic execution and the need for connectivity or device charging.
    -+      It is important to configure jobs in a way that does not adversely
    -+      impact battery life. Jobs should use a
    -+      <a href="https://developer.android.com/reference/android/app/job/JobInfo.Builder.html">
    -+      JobInfo.Builder</a> object to provide constraints and metadata, e.g. with
    -+      one or more of the following methods for a task:
    -+    </p>
    -+
    -+    <ul>
    -+      <li>To schedule a task that requires networking, use
    -+      <code>setRequiredNetworkType(int networkType)</code>, specifying
    -+      <code>NETWORK_TYPE_ANY</code> or <code>NETWORK_TYPE_UNMETERED</code>;
    -+      note that <code>NETWORK_TYPE_UNMETERED</code> is for large data transfers
    -+      while <code>NETWORK_TYPE_ANY</code> is for small transfers
    -+      </li>
    -+
    -+      <li>To schedule a task while charging, use
    -+      <code>setRequiresCharging(boolean requiresCharging)</code>
    -+      </li>
    -+
    -+      <li>For specifying that a device is idle for a task, use
    -+      <code>setRequiresDeviceIdle(boolean requiresDeviceIdle)</code>; this
    -+      method can be useful for lower-priority background work or
    -+      synchronization, especially when used with
    -+      <code>setRequiresCharging</code>
    -+      </li>
    -+    </ul>
    -+
    -+    <p>
    -+      Note that some low-bandwidth networks, such as Bluetooth LE, are
    -+      considered metered.
    -+    </p>
    -+
    -+    <h3>
    -+      Scheduling with constraints
    -+    </h3>
    -+
    -+    <p>
    -+      You can schedule a task that requires constraints. In the example below,
    -+      a <code>JobScheduler</code> object activates <code>MyJobService</code>
    -+      when the following constraints are met:
    -+    </p>
    -+
    -+    <ul>
    -+      <li>Unmetered networking
    -+      </li>
    -+
    -+      <li>Device charging
    -+      </li>
    -+    </ul>
    -+
    -+    <p>
    -+      You can use the builder method <code>setExtras</code> to attach a bundle
    -+      of app-specific metadata to the job request. When your job executes, this
    -+      bundle is provided to your job service. Note the <code>MY_JOB_ID</code>
    -+      value passed to the <code>JobInfo.Builder</code> constructor. This
    -+      <code>MY_JOB_ID</code> value is an app-provided identifier. Subsequent
    -+      calls to cancel, and subsequent jobs created with that same value, will
    -+      update the existing job:
    -+    </p>
    -+
    -+<pre>
    -+JobInfo jobInfo = new JobInfo.Builder(MY_JOB_ID,
    -+        new ComponentName(this, MyJobService.class))
    -+        .setRequiredNetworkType(JobInfo.NETWORK_TYPE_UNMETERED)
    -+        .setRequiresCharging(true)
    -+        .setExtras(extras)
    -+        .build();
    -+((JobScheduler) getSystemService(JOB_SCHEDULER_SERVICE))
    -+        .schedule(jobInfo);
    -+</pre>
    -+
    -+    <p>
    -+      Below is an implementation of <a href=
    -+      "https://developer.android.com/reference/android/app/job/JobService.html">
    -+      JobService</a> to handle the job above. When the job executes, a
    -+      <code>JobParameters</code> object is passed into the
    -+      <code>onStartJob</code> method. The <code>JobParameters</code> object
    -+      enables you to get the job ID value along with any extras bundle provided
    -+      when scheduling the job. The <code>onStartJob</code> method is called on
    -+      the main application thread, and therefore any expensive logic should be
    -+      run from a separate thread. In the example, an <code>AsyncTask</code> is
    -+      used to run code in the background. When work is complete, you would call
    -+      the <code>jobFinished</code> method to notify <code>JobScheduler</code>
    -+      that the task is done:
    -+    </p>
    -+
    -+<pre>
    -+public class MyJobService extends JobService {
    -+    &#64;Override public boolean onStartJob(JobParameters params) {
    -+        new JobAsyncTask().execute(params);
    -+        return true;
    -+    }
    -+
    -+    private class JobAsyncTask extends AsyncTask
    -+</pre>
    -+
    -+    <h2 id="fcm">
    -+      Cloud Notifications Using FCM
    -+    </h2>
    -+
    -+    <p>
    -+      FCM is the recommended way to send notifications to a watch.
    -+    </p>
    -+
    -+    <p>
    -+      Provide for messages from FCM by collecting a registration token for a
    -+      device when your Wear app runs. Then include the token as part of the
    -+      destination when your server sends messages to the FCM REST endpoint. FCM
    -+      sends messages to the device identified by the token.
    -+    </p>
    -+
    -+    <p>
    -+      An FCM message is in JSON format and can include one or both of the
    -+      following payloads:
    -+    </p>
    -+
    -+    <ul>
    -+      <li>
    -+        <strong>Notification payload.</strong> When a notification payload is
    -+        received by a watch, the data is displayed to a user directly in the
    -+        notification stream. When the user taps the notification, your app is
    -+        launched.
    -+      </li>
    -+
    -+      <li>
    -+        <strong>Data payload</strong>. The payload has a set of custom
    -+        key/value pairs. The payload and is delivered as data to your Wear app.
    -+      </li>
    -+    </ul>
    -+
    -+    <p>
    -+      For more information and examples of payloads, see <a href=
    -+      "https://firebase.google.com/docs/cloud-messaging/concept-options">About
    -+      FCM Messages</a>.
    -+    </p>
    -+
    -+    <h2 id="fcm-phone">
    -+      Notifications from a Companion Phone
    -+    </h2>
    -+
    -+    <p>
    -+      By default, notifications are bridged (shared) from a phone app to a
    -+      watch. If you have a standalone Wear app and a corresponding phone app,
    -+      duplicate notifications can occur. For example, the same notification
    -+      from FCM, received by both a phone and a watch, could be
    -+      displayed by both devices independently.
    -+    </p>
    -+
    -+    <p>
    -+      For information about preventing duplicate notifications, see <a href=
    -+      "https://developer.android.com/wear/preview/features/bridger.html">Bridging
    -+      Mode for Notifications</a>.
    -+    </p>
    -diff --git a/docs/html/wear/preview/features/wearable-recycler-view.jd b/docs/html/wear/preview/features/wearable-recycler-view.jd
    -new file mode 100644
    -index 0000000..f28a472
    ---- /dev/null
    -+++ b/docs/html/wear/preview/features/wearable-recycler-view.jd
    -@@ -0,0 +1,223 @@
    -+
    -+page.title=Curved Layout
    -+meta.tags="wear", "wear-preview", "RecyclerView"
    -+page.tags="wear"
    -+
    -+@jd:body
    -+
    -+
    -+<div id="qv-wrapper">
    -+<div id="qv">
    -+
    -+    <h2>In this document</h2>
    -+    <ol>
    -+      <li><a href="#creating">Creating a Curved Layout</a></li>
    -+      <li><a href="#adding">Adding a Circular Scrolling Gesture</a></li>
    -+      <li><a href="#aligning">Anchoring Children to the Curve</a></li>
    -+    </ol>
    -+
    -+</div>
    -+</div>
    -+
    -+
    -+<p>
    -+  Wear 2.0 introduces the {@code WearableRecyclerView} class for displaying
    -+  and manipulating a vertical list of items optimized for round displays.
    -+  {@code WearableRecyclerView} extends the existing
    -+  <a href="{@docRoot}reference/android/support/v7/widget/RecyclerView.html">{@code RecyclerView}</a>
    -+  class to provide a curved layout and a circular scrolling gesture in wearable apps.
    -+</p>
    -+<img src="https://android-dot-devsite.googleplex.com/wear/preview/images/wrv_new.png"
    -+      style="float:right;margin:10px 20px 0 0">
    -+
    -+<p>
    -+  You can adapt to this interface in your wearable app by creating a new
    -+  {@code WearableRecyclerView} container.
    -+</p>
    -+
    -+<p>
    -+  You should decide whether to use a {@code WearableRecyclerView}, based on
    -+  the kind of user experience you want to provide. We recommend using the
    -+  {@code WearableRecyclerView} for a simple, long list of items, such as an
    -+  application launcher, or a list contacts. Each item might have a short string
    -+  and an associated icon. Alternatively, each item might have only a string or
    -+  an icon. We do not recommend using a {@code WearableRecyclerView} for short
    -+  or complex lists.
    -+</p>
    -+
    -+<p>
    -+  This document describes how to create a curved layout for your scrollable items
    -+  and properly align them along the curve.
    -+</p>
    -+
    -+
    -+<h2 id="creating">Creating a Curved Layout</h2>
    -+<p>To create a curved layout for scrollable items in your wearable app:
    -+</p>
    -+<ul>
    -+  <li>Use {@code WearableRecyclerView} as your main container in the relevant
    -+      xml layout.
    -+  </li>
    -+
    -+  <li>By default, {@code WearableRecyclerView} uses the {@code
    -+    DefaultOffsettingHelper} class to offset items in a curved layout on round
    -+    devices. If you wish to implement your own offsetting logic, you can extend the
    -+    abstract {@code WearableRecyclerView.OffsettingHelper} class and attach it to
    -+    the {@code WearableRecyclerView} using {@code
    -+    WearableRecyclerView.setOffsettingHelper} method.
    -+
    -+    <pre>
    -+      CircularOffsettingHelper circularHelper = new CircularOffsettingHelper();
    -+      mRecyclerView.setOffsettingHelper(circularHelper);
    -+    </pre>
    -+
    -+    <pre>
    -+      public class CircularOffsettingHelper extends OffsettingHelper {
    -+
    -+        &#64;Override
    -+        public void updateChild(View child, WearableRecyclerView parent) {
    -+          int progress = child.getTop() / parent.getHeight();
    -+          child.setTranslationX(-child.getHeight() * progress);
    -+         }
    -+      }
    -+    </pre>
    -+
    -+  </li>
    -+
    -+</ul>
    -+
    -+<p class="note">
    -+  <strong>Note:</strong> {@code DefaultOffsettingHelper} class
    -+  offsets the child items
    -+  along a predefined UX curve, but the operation can cut off part of the child
    -+  view if it is not scaled down accordingly. This is because the default curve
    -+  attempts to fit 5 items on the screen, regardless of their size.
    -+  If you do not wish to scale your items, you should consider additional padding.
    -+</p>
    -+
    -+<h3>Examples</h3>
    -+<p>
    -+  The following code example demonstrates how to add {@code WearableRecyclerView}
    -+   to a layout:
    -+</p>
    -+<pre>
    -+&lt;android.support.wearable.view.WearableRecyclerView
    -+   xmlns:android="http://schemas.android.com/apk/res/android"
    -+   xmlns:tools="http://schemas.android.com/tools"
    -+   android:id="&#64;+id/recycler_launcher_view"
    -+   android:layout_width="match_parent"
    -+   android:layout_height="match_parent"
    -+   android:scrollbars="vertical" /&gt;
    -+ </pre>
    -+
    -+
    -+<p>
    -+  To customize the appearance of the children while scrolling (for example,
    -+  scale the icons and text while the items scroll away from the center),  extend
    -+  the  {@code DefaultOffsettingHelper} and override the {@code updateChild }
    -+  method. It is important to call the {@code super.updateChild(child, parent)} to
    -+  offset the children along the curve. However, if for any particular child you do
    -+  not wish them to follow a curve, you can chose not to call the super method for
    -+  that particular child.
    -+</p>
    -+
    -+<pre>
    -+
    -+public class MyOffsettingHelper extends DefaultOffsettingHelper {
    -+
    -+   /** How much should we scale the icon at most. */
    -+   private static final float MAX_ICON_PROGRESS = 0.65f;
    -+
    -+   private float mProgressToCenter;
    -+
    -+   public OffsettingHelper() {}
    -+
    -+   &#64;Override
    -+
    -+   public void updateChild(View child,  WearableRecyclerView parent) {
    -+       super.updateChild(child, parent);
    -+
    -+
    -+       // Figure out % progress from top to bottom
    -+       float centerOffset = ((float) child.getHeight() / 2.0f) /  (float) mParentView.getHeight();
    -+       float yRelativeToCenterOffset = (child.getY() / mParentView.getHeight()) + centerOffset;
    -+
    -+       // Normalize for center
    -+       mProgressToCenter = Math.abs(0.5f - yRelativeToCenterOffset);
    -+       // Adjust to the maximum scale
    -+       mProgressToCenter = Math.min(mProgressToCenter, MAX_ICON_PROGRESS);
    -+
    -+       child.setScaleX(1 - mProgressToCenter);
    -+       child.setScaleY(1 - mProgressToCenter);
    -+   }
    -+}
    -+
    -+
    -+</pre>
    -+
    -+
    -+<h2 id="adding">Adding a Circular Scrolling Gesture</h2>
    -+
    -+<p>
    -+  By default, circular scrolling is disabled in the {@code
    -+  WearableRecyclerView}. If you want to enable circular scrolling gesture
    -+  in your child view, use the  {@code WearavleRecyclerView}’s {@code
    -+  setCircularScrollingGestureEnabled()} method.  You can also customize the
    -+  circular scrolling gesture by defining one or both of the following:
    -+</p>
    -+
    -+<ul>
    -+  <li>How many degrees the user has to rotate by to scroll through one screen height.
    -+    This effectively influences the speed of the scolling -
    -+    {@code setScrollDegreesPerScreen} - the default value is set at 180 degrees.
    -+  </li>
    -+
    -+  <li>
    -+    The width of a virtual ‘bezel’ near the the edge of the screen in which the
    -+    gesture will be recognized - {@code setBezelWidth} - the default value is set
    -+    at 1. This is expressed as a fraction of the radius of the view.
    -+</ul>
    -+
    -+
    -+<p>The following code snippet shows how to set these methods:</p>
    -+
    -+<pre>
    -+  setCircularScrollingGestureEnabled(true);
    -+  setBezelWidth(0.5f);
    -+  setScrollDegreesPerScreen(90);
    -+</pre>
    -+
    -+<h2 id="aligning"> Anchoring Children to the Curve </h2>
    -+
    -+<p>
    -+  To ensure that the layout for WearableRecyclerView is adaptable to different
    -+  types of child views, the WearableRecyclerView class, by default, chooses the
    -+  middle left edge (X=0, Y=Half the child height) as the anchor coordinates for
    -+  the child item. Using the default anchor coordinates can result in offsetting
    -+  the child items from the left edge of the watch face. To customize the anchor
    -+  coordinates of your child view along the curve, you can overwrite the
    -+  {@code adjustAnchorOffsetXY()} method. You can calculate the X (horizontal)
    -+  and Y (vertical) offset of the child item, and set it using the
    -+  {@code adjustAnchorOffsetXY()} method to properly align items
    -+  along the curve. The coordinates should be with relation to the child view.
    -+</p>
    -+
    -+<p><img src="{@docRoot}wear/preview/images/alignment.png"/></p>
    -+<p><b>Figure 1</b>. Imaginary UX curve and anchor points on the curve.</p>
    -+
    -+<p>
    -+  The code snippet below, calculates the X offset for a child item in which the
    -+  width of the icon is same as the height of the child item. In this case, the
    -+  anchor coordinates for the child item are at the center of the icon.
    -+
    -+</p>
    -+<img src="{@docRoot}wear/preview/images/center_align.png" style="float:left;margin:10px 20px 0 0"/>
    -+
    -+<pre>
    -+ &#64;Override
    -+  protected void adjustAnchorOffsetXY(View child, float[] anchorOffsetXY) {
    -+    anchorOffsetXY[0] = child.getHeight() / 2.0f;
    -+  }
    -+</pre>
    -+
    -+
    -diff --git a/docs/html/wear/preview/images/alignment.png b/docs/html/wear/preview/images/alignment.png
    -new file mode 100644
    -index 0000000..525b334
    -Binary files /dev/null and b/docs/html/wear/preview/images/alignment.png differ
    -diff --git a/docs/html/wear/preview/images/apk-details.png b/docs/html/wear/preview/images/apk-details.png
    -new file mode 100644
    -index 0000000..eb3b859
    -Binary files /dev/null and b/docs/html/wear/preview/images/apk-details.png differ
    -diff --git a/docs/html/wear/preview/images/apk-tabs.png b/docs/html/wear/preview/images/apk-tabs.png
    -new file mode 100644
    -index 0000000..949b98f
    -Binary files /dev/null and b/docs/html/wear/preview/images/apk-tabs.png differ
    -diff --git a/docs/html/wear/preview/images/center_align.png b/docs/html/wear/preview/images/center_align.png
    -new file mode 100644
    -index 0000000..ca88ad7
    -Binary files /dev/null and b/docs/html/wear/preview/images/center_align.png differ
    -diff --git a/docs/html/wear/preview/images/current-apk.png b/docs/html/wear/preview/images/current-apk.png
    -new file mode 100644
    -index 0000000..2545f92
    -Binary files /dev/null and b/docs/html/wear/preview/images/current-apk.png differ
    -diff --git a/docs/html/wear/preview/images/inline_action.png b/docs/html/wear/preview/images/inline_action.png
    -new file mode 100644
    -index 0000000..7ecaafe
    -Binary files /dev/null and b/docs/html/wear/preview/images/inline_action.png differ
    -diff --git a/docs/html/wear/preview/images/wrv_new.png b/docs/html/wear/preview/images/wrv_new.png
    -new file mode 100644
    -index 0000000..c413c59
    -Binary files /dev/null and b/docs/html/wear/preview/images/wrv_new.png differ
    -diff --git a/docs/html/wear/preview/index.jd b/docs/html/wear/preview/index.jd
    -index 4b3c1f2..6292577 100644
    ---- a/docs/html/wear/preview/index.jd
    -+++ b/docs/html/wear/preview/index.jd
    -@@ -7,16 +7,6 @@ header.hide=1
    - footer.hide=1
    - @jd:body
    - 
    --<script>
    --  $(document).ready(function() {
    --    if (useUpdatedTemplates) {
    --      $("#useUpdatedTemplates").css("display","block");
    --    } else {
    --      $("#useOldTemplates").css("display","block");
    --    }
    --  })
    --</script>
    --
    - <section class="dac-expand dac-hero dac-light" style="background-color:#FFFFFF">
    -   <div class="wrap" style="max-width:1100px;margin-top:0">
    -     <div class="cols dac-hero-content" style="padding-bottom:1em;">
    -@@ -55,7 +45,7 @@ footer.hide=1
    -   </div>
    - </section>
    - 
    --<div id="useUpdatedTemplates" style="display:none" class="dac-section dac-slim dac-gray dac-expand">
    -+<div class="dac-section dac-slim dac-gray dac-expand">
    -   <div class="wrap dac-offset-parent">
    -     <a class="dac-fab dac-scroll-button" data-scroll-button href="#build-apps">
    -       <i class="dac-sprite dac-arrow-down-gray"></i>
    -@@ -77,22 +67,6 @@ footer.hide=1
    -   </div><!-- end .wrap -->
    - </div><!-- end .dac-actions -->
    - 
    --<div id="useOldTemplates" style="display:none;color:black" class="actions-bar dac-expand dac-invert">
    --  <div class="wrap dac-offset-parent">
    --
    --    <div class="actions">
    --      <div><a href="{@docRoot}wear/preview/bug">
    --        <span class="dac-sprite dac-auto-chevron-large"></span>
    --        Report an issue
    --      </a></div>
    --      <div><a href="http://g.co/androidweardev">
    --        <span class="dac-sprite dac-auto-chevron-large"></span>
    --        Join developer community
    --      </a></div>
    --    </div><!-- end .actions -->
    --  </div><!-- end .wrap -->
    --</div>
    --
    - <section class="dac-section dac-light"><div class="wrap">
    -   <h1 class="dac-section-title">Resources</h1>
    -   <div class="dac-section-subtitle">
    -diff --git a/docs/html/wear/preview/program.jd b/docs/html/wear/preview/program.jd
    -index e2bf92f..4f2fb5c 100644
    ---- a/docs/html/wear/preview/program.jd
    -+++ b/docs/html/wear/preview/program.jd
    -@@ -143,8 +143,9 @@ page.image=images/cards/card-n-sdk_2x.png
    -     <p>
    -       At milestone 4, you'll have access to the final Android Wear 2.0
    -       APIs and SDK to develop with, as well as near-final system images to test
    --      system behaviors and features. Android Wear 2.0 will use the Android N
    --      API level at this time. You can begin final compatibility testing of your
    -+      system behaviors and features. Android Wear 2.0 will use the
    -+      Android 7.0 API level at this time.
    -+      You can begin final compatibility testing of your
    -       legacy apps and refine any new code that is using the Android Wear 2.0
    -       APIs or features.
    -     </p>
    -diff --git a/docs/html/wear/preview/start.jd b/docs/html/wear/preview/start.jd
    -index 8fccdc8..c9720dc 100644
    ---- a/docs/html/wear/preview/start.jd
    -+++ b/docs/html/wear/preview/start.jd
    -@@ -29,7 +29,7 @@ page.image=images/cards/card-n-sdk_2x.png
    - 
    -     <p>
    -       If you want an environment for basic compatibility
    --      testing of your app, you can use your current APK and a
    -+      testing, you can use your current APK and a
    -       supported watch or an emulator. You don't necessarily need to update your
    -       full development environment to do basic testing. To simply test your
    -       app's compatibility with a preview system image, see <a href=
    -@@ -48,10 +48,8 @@ page.image=images/cards/card-n-sdk_2x.png
    -     </h2>
    - 
    -     <p>
    --      1. For compatibility with the <a href="{@docRoot}preview/overview.html">N
    --      Developer Preview</a>, follow the <a href=
    --      "{@docRoot}preview/setup-sdk.html">setup instructions</a> for installing
    --      the latest version of Android Studio.
    -+      1. For compatibility with Android 7.0, install the latest version of
    -+      <a href="https://developer.android.com/studio/index.html">Android Studio</a>.
    -     </p>
    - 
    -     <p>
    -@@ -63,7 +61,7 @@ page.image=images/cards/card-n-sdk_2x.png
    -     <ul>
    -       <li>Under the <strong>SDK Platforms tab</strong>:
    -         <ul>
    --          <li>Android N Preview
    -+          <li>Android 7.0 (Nougat)
    -           </li>
    -         </ul>
    -       </li>
    -@@ -107,10 +105,10 @@ page.image=images/cards/card-n-sdk_2x.png
    - 
    -       <tr>
    -         <td>
    --          <a href="http://storage.googleapis.com/androiddevelopers/shareables/wear-preview/wearable-support-preview-2-docs.zip">wearable-support-preview-2-docs.zip</a>
    -+          <a href="http://storage.googleapis.com/androiddevelopers/shareables/wear-preview/wearable-support-preview-3-docs.zip">wearable-support-preview-3-docs.zip</a>
    -         </td>
    --        <td>MD5: afb770c9c5c0431bbcbdde186f1eae06<br>
    --            SHA-1: 81d681e61cee01f222ea82e83297d23c4e55b8f3
    -+        <td>MD5: 22bae00e473e39e320aae8ea09a001a5<br>
    -+            SHA-1: 474502cc7092bcf0bd671441b8654aa8d6c155ed
    -         </td>
    -       </tr>
    -     </table>
    -@@ -163,7 +161,7 @@ page.image=images/cards/card-n-sdk_2x.png
    -       following, which requires that your the Google Repository <a href=
    -       "#install_android_studio_and_the_latest_packages">is the latest
    -       version</a>:
    --      <code>compile 'com.google.android.support:wearable:2.0.0-alpha2'</code>
    -+      <code>compile 'com.google.android.support:wearable:2.0.0-alpha3'</code>
    -         </li>
    -       </ul>
    -       </li>
    -@@ -190,12 +188,12 @@ page.image=images/cards/card-n-sdk_2x.png
    -       </li>
    - 
    -       <li>Optionally, select the <strong>Phone and Tablet</strong> option. If
    --      you plan to use N Preview APIs in a phone app, then the Minimum SDK
    --      option list, select <strong>API N: Android 6.x (N Preview)</strong>.
    -+      you plan to use Android 7.0 APIs in a phone app, then the Minimum SDK
    -+      option list, select <strong>API 24: Android 7.0 (Nougat)</strong>.
    -       </li>
    - 
    -       <li>Select the <strong>Wear</strong> option, and in the Minimum SDK
    --      option list, select the latest available (<strong>N Preview</strong>)
    -+      option list, select the latest available (<strong>API Nougat</strong>)
    -       option. Click <strong>Next</strong> until you exit the Create New Project
    -       wizard.
    -       </li>
    -@@ -215,7 +213,7 @@ page.image=images/cards/card-n-sdk_2x.png
    -       following, which requires that your the Google Repository <a href=
    -       "#install_android_studio_and_the_latest_packages">is the latest
    -       version</a>:
    --      <code>compile 'com.google.android.support:wearable:2.0.0-alpha2'</code>
    -+      <code>compile 'com.google.android.support:wearable:2.0.0-alpha3'</code>
    -         </li>
    -       </ul>
    -       </li>
    -diff --git a/docs/html/wear/preview/support.jd b/docs/html/wear/preview/support.jd
    -index 78b4e4b..6006627 100644
    ---- a/docs/html/wear/preview/support.jd
    -+++ b/docs/html/wear/preview/support.jd
    -@@ -23,7 +23,9 @@ page.tags="preview", "developer preview"
    - 
    - <ul>
    -   <li><a href="#general">General Advisories</a></li>
    -+  <li><a href="#platform-version">Platform API Version</a></li>
    -   <li><a href="#deprecations">Deprecations</a></li>
    -+  <li><a href="#dp3">Developer Preview 3</a></li>
    -   <li><a href="#dp2">Developer Preview 2</a></li>
    -   <li><a href="#dp1">Developer Preview 1</a></li>
    - </ul>
    -@@ -46,10 +48,25 @@ page.tags="preview", "developer preview"
    -     panics and crashes.
    -   </li>
    -   <li>Some apps <strong>may not function as expected</strong> on the new
    --  platform version. This includes Google’s apps and other apps.
    -+  platform version. This includes Google's apps and other apps.
    -   </li>
    - </ul>
    - 
    -+<h2 id="platform-version">
    -+  Platform API Version
    -+</h2>
    -+
    -+<p>
    -+  The Android Platform API version is incremented to 24 to match Android 7.0.
    -+  You can update the following in your Android Wear 2.0 Preview project
    -+  to <strong>24</strong>:
    -+</p>
    -+
    -+<ul>
    -+  <li><code>compileSdkVersion</code></li>
    -+  <li><code>targetSdkVersion</code></li>
    -+</ul>
    -+
    - <h2 id="deprecations">Deprecations</h2>
    - 
    - <p>The following fields are deprecated in the preview:</p>
    -@@ -64,6 +81,291 @@ page.tags="preview", "developer preview"
    -   </li>
    - </ul>
    - 
    -+<h2 id="dp3">Developer Preview 3</h2>
    -+
    -+<div class="wrap">
    -+  <div class="cols">
    -+    <div class="col-6of12">
    -+      <p><em>Date: September 2016<br />
    -+      Builds: Wearable Support 2.0.0-alpha3, NVE68J<br/>
    -+      Emulator support: x86 & ARM (32-bit)<br/>
    -+      </em></p>
    -+    </div>
    -+  </div>
    -+</div>
    -+
    -+<h3 id="new-in-fdp3">
    -+  New in Preview 3
    -+</h3>
    -+
    -+    <p>
    -+      For access to system images and the companion app for Preview 3, see
    -+      <a href="https://developer.android.com/wear/preview/downloads.html">
    -+      Download and Test with a Device</a>.
    -+    </p>
    -+
    -+    <h4>
    -+      Additions for standalone apps and the Play Store on Wear
    -+    </h4>
    -+
    -+    <p>
    -+      For information about planning your Wear 2.0 app, see <a href=
    -+      "https://developer.android.com/wear/preview/features/standalone-apps.html">
    -+      Standalone Apps</a>.
    -+    </p>
    -+
    -+    <p>
    -+      Generally, the minimum and target SDK level for Wear 2.0, and for a
    -+      standalone APK, is level 24. The minimum SDK level can be 23
    -+      only if you are using the same APK
    -+      for Wear 1.0 and 2.0 (and thus have an embedded Wear 1.0 APK).
    -+    </p>
    -+
    -+    <p>
    -+      Run-time permissions are required.
    -+    </p>
    -+
    -+    <p>
    -+      For information about distributing your Wear 2.0 app, see <a href=
    -+      "https://developer.android.com/wear/preview/features/app-distribution.html">
    -+      App Distribution</a>.
    -+    </p>
    -+
    -+    <h4 id="additions-to-the-complications-api">
    -+      Complications API additions
    -+    </h4>
    -+
    -+    <p>
    -+      For Preview 3, additions and changes have been made to the Complications
    -+      API. The <a href=
    -+      "https://developer.android.com/wear/preview/features/complications.html">documentation</a>
    -+      includes information about the following additions and changes:
    -+    </p>
    -+
    -+    <ul>
    -+      <li>To receive complication data and open the provider chooser, a watch
    -+      face must have the <code>RECEIVE_COMPLICATION_DATA</code> permission.
    -+      </li>
    -+
    -+      <li>To ease a request for the new permission and the starting of the
    -+      chooser, the <code>ComplicationHelperActivity</code> class is available
    -+      in the wearable support library. This class should be used instead of
    -+      <code>ProviderChooserIntent</code> to start the chooser in almost all
    -+      cases.
    -+      </li>
    -+
    -+      <li>Watch faces can specify default providers that are used until a user
    -+      selects a provider.
    -+      </li>
    -+
    -+      <li>The complication types used for "empty" data are changed.
    -+      </li>
    -+
    -+      <li>A new permission was added to ensure that only the Android Wear
    -+      system can bind to provider services.
    -+      </li>
    -+    </ul>
    -+
    -+    <p>
    -+      For changes related to the <code>ComplicationData</code> object, see
    -+      <a href=
    -+      "https://developer.android.com/wear/preview/behavior-changes.html">Behavior
    -+      Changes</a>.
    -+    </p>
    -+
    -+    <h4 id="wearable-recycler-view-api">
    -+      Curved Layout
    -+    </h4>
    -+
    -+    <p>
    -+      For information about creating a curved layout using
    -+      the <code>WearableRecyclerView</code> API in your Wear 2.0 app, see
    -+      <a href="https://developer.android.com/wear/preview/features/wearable-recycler-view.html">
    -+      Curved Layout</a>.
    -+    </p>
    -+
    -+    <h4 id="notifications-features-fdp3">
    -+      Notifications features
    -+    </h4>
    -+
    -+    <p>
    -+      To learn about adding an inline action to a notification,
    -+      see <a href="https://developer.android.com/wear/preview/notifications.html#inline">Inline
    -+      Action</a>.
    -+    </p>
    -+
    -+    <p>
    -+      To learn about adding images to a notification, see
    -+      <a href=
    -+      "https://developer.android.com/wear/preview/notifications.html#images">Adding
    -+      images to a notification</a>.
    -+    </p>
    -+
    -+    <p>
    -+      For additions related to the bridging of notifications from a companion
    -+      app to a watch, see <a href=
    -+      "https://developer.android.com/wear/preview/features/bridger.html">Bridging
    -+      Mode for Notifications</a>.
    -+    </p>
    -+
    -+    <h4 id="additions-for-smart-reply">
    -+      Smart Reply additions
    -+    </h4>
    -+
    -+    <p>
    -+      Smart Reply responses are generated by an entirely on-watch,
    -+      machine-learning model using the context provided by <a href=
    -+      "https://developer.android.com/wear/preview/features/notifications.html#messaging">
    -+      MessagingStyle</a> notifications. Use the <a href=
    -+      "https://developer.android.com/reference/android/support/v4/app/NotificationCompat.Action.Builder.html#setAllowGeneratedReplies(boolean)">
    -+      setAllowGeneratedReplies(boolean)</a> method to enable Smart Reply for
    -+      your <code>MessagingStyle</code> notification.
    -+    </p>
    -+
    -+    <h3 id="known-issues-3">
    -+      Known Issues
    -+    </h3>
    -+
    -+    <h4 id="notifications">
    -+      Notifications
    -+    </h4>
    -+
    -+    <ul>
    -+      <li>The <code>MessagingStyle</code> <a href=
    -+      "https://developer.android.com/wear/preview/features/notifications.html#images">
    -+        notifications with images</a> posted by standalone apps don't show
    -+        images in the notification (i.e., bridged notifications show images,
    -+        but standalone notifications don't).
    -+      </li>
    -+
    -+      <li>This preview release does not include support for notification
    -+      groups.
    -+      </li>
    -+
    -+      <li>With Wear 2.0, a watch can receive notifications directly from
    -+      Firebase Cloud Messaging (FCM), which replaces Google Cloud Messaging
    -+      (GCM). However, in Preview 3 of Wear 2.0, FCM does not function with
    -+      iOS-paired watches.
    -+      </li>
    -+
    -+      <li>Smart Reply responses are only shown in <code>RemoteInput</code> when
    -+      <code>RemoteInput</code> is called from a <code>MessagingStyle</code>
    -+      expanded notification. Smart Reply responses are not shown in
    -+      <code>RemoteInput</code> when <code>RemoteInput</code> is called from an
    -+      <a href=
    -+      "https://developer.android.com/wear/preview/features/notifications.html#inline">
    -+        inline action</a> within the stream&#8212;an action set with the <a href=
    -+        "https://developer.android.com/reference/android/support/v4/app/NotificationCompat.Action.WearableExtender.html#setHintDisplayActionInline(boolean)">
    -+        setHintDisplayActionInline(true)</a> method.
    -+      </li>
    -+    </ul>
    -+
    -+    <h4 id="companion-app">
    -+      Companion app
    -+    </h4>
    -+
    -+    <ul>
    -+      <li>The preview companion app is not compatible with Android 4.3
    -+      (Jelly Bean MR2), which has an SDK build version code of:
    -+      <code>JELLY_BEAN_MR2</code></li>
    -+    </ul>
    -+
    -+    <ul>
    -+      <li>In permission screens in the preview companion app:
    -+      If you deny a permission, you cannot
    -+      proceed. Instead of denying a permission, tap <strong>Skip</strong>.
    -+      </li>
    -+    </ul>
    -+
    -+
    -+    <h4 id="developer-console">
    -+      Developer Console
    -+    </h4>
    -+
    -+    <ul>
    -+      <li>If you set a minimum SDK version of 24, the Play Developer Console
    -+      states that there are few supported devices.
    -+      </li>
    -+    </ul>
    -+
    -+    <h4 id="system-user-interface">
    -+      System user interface and apps
    -+    </h4>
    -+
    -+    <ul>
    -+      <li>Dismissing multiple notifications can cause an app to forcibly close.
    -+      </li>
    -+
    -+      <li>The "Ok Google" detection and voice transcription may not work
    -+      reliably.
    -+      </li>
    -+
    -+      <li>Google Fit is not available with Preview 3.
    -+      </li>
    -+
    -+      <li>Syncing for embedded apps is not enabled for the preview. Therefore,
    -+      to test an app on a device, add it to the Play Store or side-load it
    -+      onto a watch. Some existing Wear apps, e.g. Google Maps, are only
    -+      using the embedded apps mechanism currently, and are therefore not
    -+      installable on the preview (and therefore do not appear on the watch).
    -+      </li>
    -+
    -+      <li>In Play Store search results on the watch,
    -+      results other than apps sometimes appear.
    -+      </li>
    -+
    -+      <li>Media controls/notifications are not bridged
    -+      to the watch from an Android KitKat phone.
    -+      </li>
    -+    </ul>
    -+
    -+    <h4 id="account">
    -+      Account sync
    -+    </h4>
    -+
    -+    <ul>
    -+      <li>Account sync initiated from watch settings may not work reliably.
    -+      Instead, add accounts from the setup flow of the Android Wear app, or using
    -+      the Accounts settings for a device from the Android Wear app.
    -+      </li>
    -+
    -+      <li>The list of accounts that can be synced is the same as the list of accounts
    -+      on the phone. So to add a new account, use the Android settings on the phone,
    -+      and then proceed to Android Wear app to sync that account.
    -+      </li>
    -+    </ul>
    -+
    -+    <h4 id="devices">
    -+      Devices
    -+    </h4>
    -+
    -+    <ul>
    -+      <li>In Android Wear emulators, the Play Store app requires that an
    -+      account is synced to the device before the app can be opened.
    -+      </li>
    -+
    -+      <li>On the Huawei Watch, selecting the language, followed by multiple
    -+      acknowledgement dialogues, results in a black screen.
    -+      </li>
    -+
    -+      <li>On the LG Watch Urbane 2nd Edition, when answering a call from the
    -+      watch, the watch does not provide audio from the caller.
    -+      </li>
    -+    </ul>
    -+
    -+    <h4 id="smart-reply">
    -+      Smart Reply
    -+    </h4>
    -+
    -+    <ul>
    -+      <li>Smart Reply is only available if your watch's system language is
    -+      English.
    -+      </li>
    -+
    -+      <li>Smart Reply responses are not generated for all messages.
    -+      </li>
    -+    </ul>
    -+
    - <h2 id="dp2">Developer Preview 2</h2>
    - 
    - <div class="wrap">
    -@@ -78,24 +380,9 @@ page.tags="preview", "developer preview"
    - </div>
    - 
    - <h3 id="new-in-fdp2">
    --  <strong>New in Preview 2</strong>
    -+  New in Preview 2
    - </h3>
    - 
    --<h4 id="platform-version-24">
    --  Platform API Version
    --</h4>
    --
    --<p>
    --  The Android Platform API version is incremented to 24 to match Android Nougat.
    --  You can update the following in your Android Wear 2.0 Preview project
    --  to <strong>24</strong>:
    --</p>
    --
    --<ul>
    --  <li><code>compileSdkVersion</code></li>
    --  <li><code>targetSdkVersion</code></li>
    --</ul>
    --
    - <h4 id="wearable-drawers">
    -   Wearable drawers
    - </h4>
    -@@ -174,7 +461,7 @@ page.tags="preview", "developer preview"
    - </p>
    - 
    - <h3 id="known-issues-2">
    --  <strong>Known Issues</strong>
    -+  Known Issues
    - </h3>
    - 
    - <h4 id="notifications-2">
    -@@ -239,6 +526,10 @@ page.tags="preview", "developer preview"
    - 
    -   <li>Unable to turn off the Wi-Fi on a wearable.
    -   </li>
    -+
    -+  <li>After music is played on a companion phone,
    -+  music card notifications are not mirrored to the watch.
    -+  </li>
    - </ul>
    - 
    - <h4 id="companion-app-2">
    -diff --git a/docs/html/work/managed-configurations.jd b/docs/html/work/managed-configurations.jd
    -index 76ca82f..6de4d8b 100644
    ---- a/docs/html/work/managed-configurations.jd
    -+++ b/docs/html/work/managed-configurations.jd
    -@@ -349,7 +349,7 @@ enterprise administrator to:</p>
    - <p>
    -   To get a {@link android.content.RestrictionsManager} object, get the current
    -   activity with {@link android.app.Fragment#getActivity getActivity()}, then
    --  call that activity's {@link android.app.Activity#getSystemService(java.lang.String)
    -+  call that activity's {@link android.app.Activity#getSystemService
    -   Activity.getSystemService()} method:
    - </p>
    - 
    -@@ -399,9 +399,9 @@ enterprise administrator to:</p>
    -   <code>String</code>, and <code>String[]</code>. Once you have the
    -   managed configurations {@link android.os.Bundle}, you can check the current
    -   configuration settings with the standard {@link android.os.Bundle} methods for
    --  those data types, such as {@link android.os.BaseBundle#getBoolean getBoolean()}
    -+  those data types, such as {@link android.os.Bundle#getBoolean getBoolean()}
    -   or
    --  {@link android.os.BaseBundle#getString getString()}.
    -+  {@link android.os.Bundle#getString getString()}.
    - </p>
    - 
    - <p class="note">
    -diff --git a/docs/image_sources/brand/android_logo_no.graffle/data.plist b/docs/image_sources/brand/android_logo_no.graffle/data.plist
    -new file mode 100644
    -index 0000000..1132a59
    -Binary files /dev/null and b/docs/image_sources/brand/android_logo_no.graffle/data.plist differ
    -diff --git a/docs/image_sources/brand/android_logo_no.graffle/image1.jpg b/docs/image_sources/brand/android_logo_no.graffle/image1.jpg
    -new file mode 100644
    -index 0000000..ff29599
    -Binary files /dev/null and b/docs/image_sources/brand/android_logo_no.graffle/image1.jpg differ
    -diff --git a/docs/image_sources/training/tv/playback/onboarding-fragment-diagram.graffle.zip b/docs/image_sources/training/tv/playback/onboarding-fragment-diagram.graffle.zip
    -new file mode 100644
    -index 0000000..89a799b
    -Binary files /dev/null and b/docs/image_sources/training/tv/playback/onboarding-fragment-diagram.graffle.zip differ
    -diff --git a/docs/source.properties b/docs/source.properties
    -new file mode 100644
    -index 0000000..77a760b
    ---- /dev/null
    -+++ b/docs/source.properties
    -@@ -0,0 +1,3 @@
    -+Pkg.Revision=24.0
    -+Pkg.Desc=Android offline API reference
    -+Pkg.Path=docs
    -\ No newline at end of file
    -diff --git a/graphics/java/android/graphics/SurfaceTexture.java b/graphics/java/android/graphics/SurfaceTexture.java
    -index 5c54324..c386108 100644
    ---- a/graphics/java/android/graphics/SurfaceTexture.java
    -+++ b/graphics/java/android/graphics/SurfaceTexture.java
    -@@ -77,6 +77,8 @@ public class SurfaceTexture {
    -     private long mProducer;
    -     private long mFrameAvailableListener;
    - 
    -+    private boolean mIsSingleBuffered;
    -+
    -     /**
    -      * Callback interface for being notified that a new stream frame is available.
    -      */
    -@@ -130,6 +132,7 @@ public class SurfaceTexture {
    -      */
    -     public SurfaceTexture(int texName, boolean singleBufferMode) {
    -         mCreatorLooper = Looper.myLooper();
    -+        mIsSingleBuffered = singleBufferMode;
    -         nativeInit(false, texName, singleBufferMode, new WeakReference<SurfaceTexture>(this));
    -     }
    - 
    -@@ -157,6 +160,7 @@ public class SurfaceTexture {
    -      */
    -     public SurfaceTexture(boolean singleBufferMode) {
    -         mCreatorLooper = Looper.myLooper();
    -+        mIsSingleBuffered = singleBufferMode;
    -         nativeInit(true, 0, singleBufferMode, new WeakReference<SurfaceTexture>(this));
    -     }
    - 
    -@@ -378,6 +382,14 @@ public class SurfaceTexture {
    -         }
    -     }
    - 
    -+    /**
    -+     * Returns true if the SurfaceTexture is single-buffered
    -+     * @hide
    -+     */
    -+    public boolean isSingleBuffered() {
    -+        return mIsSingleBuffered;
    -+    }
    -+
    -     private native void nativeInit(boolean isDetached, int texName,
    -             boolean singleBufferMode, WeakReference<SurfaceTexture> weakSelf)
    -             throws Surface.OutOfResourcesException;
    -diff --git a/graphics/java/android/graphics/drawable/AnimatedVectorDrawable.java b/graphics/java/android/graphics/drawable/AnimatedVectorDrawable.java
    -index c836204..c24d313 100644
    ---- a/graphics/java/android/graphics/drawable/AnimatedVectorDrawable.java
    -+++ b/graphics/java/android/graphics/drawable/AnimatedVectorDrawable.java
    -@@ -65,19 +65,36 @@ import java.lang.ref.WeakReference;
    - import java.util.ArrayList;
    - 
    - /**
    -- * This class uses {@link android.animation.ObjectAnimator} and
    -- * {@link android.animation.AnimatorSet} to animate the properties of a
    -- * {@link android.graphics.drawable.VectorDrawable} to create an animated drawable.
    -+ * This class animates properties of a {@link android.graphics.drawable.VectorDrawable} with
    -+ * animations defined using {@link android.animation.ObjectAnimator} or
    -+ * {@link android.animation.AnimatorSet}.
    -  * <p>
    -- * AnimatedVectorDrawable are normally defined as 3 separate XML files.
    -+ * Starting from API 25, AnimatedVectorDrawable runs on RenderThread (as opposed to on UI thread for
    -+ * earlier APIs). This means animations in AnimatedVectorDrawable can remain smooth even when there
    -+ * is heavy workload on the UI thread. Note: If the UI thread is unresponsive, RenderThread may
    -+ * continue animating until the UI thread is capable of pushing another frame. Therefore, it is not
    -+ * possible to precisely coordinate a RenderThread-enabled AnimatedVectorDrawable with UI thread
    -+ * animations. Additionally,
    -+ * {@link android.graphics.drawable.Animatable2.AnimationCallback#onAnimationEnd(Drawable)} will be
    -+ * called the frame after the AnimatedVectorDrawable finishes on the RenderThread.
    -  * </p>
    -  * <p>
    -- * First is the XML file for {@link android.graphics.drawable.VectorDrawable}.
    -- * Note that we allow the animation to happen on the group's attributes and path's
    -- * attributes, which requires they are uniquely named in this XML file. Groups
    -- * and paths without animations do not need names.
    -+ * AnimatedVectorDrawable can be defined in either <a href="#ThreeXML">three separate XML files</a>,
    -+ * or <a href="#OneXML">one XML</a>.
    -  * </p>
    -- * <li>Here is a simple VectorDrawable in this vectordrawable.xml file.
    -+ * <a name="ThreeXML"></a>
    -+ * <h3>Define an AnimatedVectorDrawable in three separate XML files</h3>
    -+ * <ul>
    -+ * <a name="VDExample"></a>
    -+ * <li><h4>XML for the VectorDrawable containing properties to be animated</h4>
    -+ * <p>
    -+ * Animations can be performed on both group and path attributes, which requires groups and paths to
    -+ * have unique names in the same VectorDrawable. Groups and paths without animations do not need to
    -+ * be named.
    -+ * </p>
    -+ * Below is an example of a VectorDrawable defined in vectordrawable.xml. This VectorDrawable is
    -+ * referred to by its file name (not including file suffix) in the
    -+ * <a href="AVDExample">AnimatedVectorDrawable XML example</a>.
    -  * <pre>
    -  * &lt;vector xmlns:android=&quot;http://schemas.android.com/apk/res/android&quot;
    -  *     android:height=&quot;64dp&quot;
    -@@ -96,17 +113,20 @@ import java.util.ArrayList;
    -  *     &lt;/group&gt;
    -  * &lt;/vector&gt;
    -  * </pre></li>
    -+ *
    -+ * <a name="AVDExample"></a>
    -+ * <li><h4>XML for AnimatedVectorDrawable</h4>
    -  * <p>
    -- * Second is the AnimatedVectorDrawable's XML file, which defines the target
    -- * VectorDrawable, the target paths and groups to animate, the properties of the
    -- * path and group to animate and the animations defined as the ObjectAnimators
    -- * or AnimatorSets.
    -+ * An AnimatedVectorDrawable element has a VectorDrawable attribute, and one or more target
    -+ * element(s). The target elements can be the path or group to be animated. Each target element
    -+ * contains a name attribute that references a property (of a path or a group) to animate, and an
    -+ * animation attribute that points to an ObjectAnimator or an AnimatorSet.
    -  * </p>
    -- * <li>Here is a simple AnimatedVectorDrawable defined in this avd.xml file.
    -- * Note how we use the names to refer to the groups and paths in the vectordrawable.xml.
    -+ * The following code sample defines an AnimatedVectorDrawable. Note that the names refer to the
    -+ * groups and paths in the <a href="#VDExample">VectorDrawable XML above</a>.
    -  * <pre>
    -  * &lt;animated-vector xmlns:android=&quot;http://schemas.android.com/apk/res/android&quot;
    -- *   android:drawable=&quot;@drawable/vectordrawable&quot; &gt;
    -+ *     android:drawable=&quot;@drawable/vectordrawable&quot; &gt;
    -  *     &lt;target
    -  *         android:name=&quot;rotationGroup&quot;
    -  *         android:animation=&quot;@anim/rotation&quot; /&gt;
    -@@ -114,36 +134,89 @@ import java.util.ArrayList;
    -  *         android:name=&quot;v&quot;
    -  *         android:animation=&quot;@anim/path_morph&quot; /&gt;
    -  * &lt;/animated-vector&gt;
    -- * </pre></li>
    -+ * </pre>
    -+ * </li>
    -+ *
    -+ * <li><h4>XML for Animations defined using ObjectAnimator or AnimatorSet</h4>
    -  * <p>
    -- * Last is the Animator XML file, which is the same as a normal ObjectAnimator
    -- * or AnimatorSet.
    -- * To complete this example, here are the 2 animator files used in avd.xml:
    -- * rotation.xml and path_morph.xml.
    -+ * From the previous <a href="#AVDExample">example of AnimatedVectorDrawable</a>, two animations
    -+ * were used: rotation.xml and path_morph.xml.
    -  * </p>
    -- * <li>Here is the rotation.xml, which will rotate the target group for 360 degrees.
    -+ * rotation.xml rotates the target group from 0 degree to 360 degrees over 6000ms:
    -  * <pre>
    -  * &lt;objectAnimator
    -  *     android:duration=&quot;6000&quot;
    -  *     android:propertyName=&quot;rotation&quot;
    -  *     android:valueFrom=&quot;0&quot;
    -  *     android:valueTo=&quot;360&quot; /&gt;
    -- * </pre></li>
    -- * <li>Here is the path_morph.xml, which will morph the path from one shape to
    -- * the other. Note that the paths must be compatible for morphing.
    -- * In more details, the paths should have exact same length of commands , and
    -- * exact same length of parameters for each commands.
    -- * Note that the path strings are better stored in strings.xml for reusing.
    -+ * </pre>
    -+ *
    -+ * path_morph.xml morphs the path from one shape into the other. Note that the paths must be
    -+ * compatible for morphing. Specifically, the paths must have the same commands, in the same order,
    -+ * and must have the same number of parameters for each command. It is recommended to store path
    -+ * strings as string resources for reuse.
    -  * <pre>
    -  * &lt;set xmlns:android=&quot;http://schemas.android.com/apk/res/android&quot;&gt;
    -  *     &lt;objectAnimator
    -  *         android:duration=&quot;3000&quot;
    -  *         android:propertyName=&quot;pathData&quot;
    -- *         android:valueFrom=&quot;M300,70 l 0,-70 70,70 0,0   -70,70z&quot;
    -+ *         android:valueFrom=&quot;M300,70 l 0,-70 70,70 0,0 -70,70z&quot;
    -  *         android:valueTo=&quot;M300,70 l 0,-70 70,0  0,140 -70,0 z&quot;
    -  *         android:valueType=&quot;pathType&quot;/&gt;
    -  * &lt;/set&gt;
    -- * </pre></li>
    -+ * </pre>
    -+ * </ul>
    -+ * <a name="OneXML"></a>
    -+ * <h3>Define an AnimatedVectorDrawable all in one XML file</h3>
    -+ * <p>
    -+ * Since the AAPT tool supports a new format that bundles several related XML files together, we can
    -+ * merge the XML files from the previous examples into one XML file:
    -+ * </p>
    -+ * <pre>
    -+ * &lt;animated-vector xmlns:android=&quot;http://schemas.android.com/apk/res/android&quot; &gt;
    -+ *     &lt;aapt:attr name="android:drawable"&gt;
    -+ *         &lt;vector
    -+ *             android:height=&quot;64dp&quot;
    -+ *             android:width=&quot;64dp&quot;
    -+ *             android:viewportHeight=&quot;600&quot;
    -+ *             android:viewportWidth=&quot;600&quot; &gt;
    -+ *             &lt;group
    -+ *                 android:name=&quot;rotationGroup&quot;
    -+ *                 android:pivotX=&quot;300.0&quot;
    -+ *                 android:pivotY=&quot;300.0&quot;
    -+ *                 android:rotation=&quot;45.0&quot; &gt;
    -+ *                 &lt;path
    -+ *                     android:name=&quot;v&quot;
    -+ *                     android:fillColor=&quot;#000000&quot;
    -+ *                     android:pathData=&quot;M300,70 l 0,-70 70,70 0,0 -70,70z&quot; /&gt;
    -+ *             &lt;/group&gt;
    -+ *         &lt;/vector&gt;
    -+ *     &lt;/aapt:attr&gt;
    -+ *
    -+ *     &lt;target android:name=&quot;rotationGroup&quot;&gt; *
    -+ *         &lt;aapt:attr name="android:animation"&gt;
    -+ *             &lt;objectAnimator
    -+ *             android:duration=&quot;6000&quot;
    -+ *             android:propertyName=&quot;rotation&quot;
    -+ *             android:valueFrom=&quot;0&quot;
    -+ *             android:valueTo=&quot;360&quot; /&gt;
    -+ *         &lt;/aapt:attr&gt;
    -+ *     &lt;/target&gt;
    -+ *
    -+ *     &lt;target android:name=&quot;v&quot; &gt;
    -+ *         &lt;aapt:attr name="android:animation"&gt;
    -+ *             &lt;set&gt;
    -+ *                 &lt;objectAnimator
    -+ *                     android:duration=&quot;3000&quot;
    -+ *                     android:propertyName=&quot;pathData&quot;
    -+ *                     android:valueFrom=&quot;M300,70 l 0,-70 70,70 0,0 -70,70z&quot;
    -+ *                     android:valueTo=&quot;M300,70 l 0,-70 70,0  0,140 -70,0 z&quot;
    -+ *                     android:valueType=&quot;pathType&quot;/&gt;
    -+ *             &lt;/set&gt;
    -+ *         &lt;/aapt:attr&gt;
    -+ *      &lt;/target&gt;
    -+ * &lt;/animated-vector&gt;
    -+ * </pre>
    -  *
    -  * @attr ref android.R.styleable#AnimatedVectorDrawable_drawable
    -  * @attr ref android.R.styleable#AnimatedVectorDrawableTarget_name
    -@@ -237,6 +310,17 @@ public class AnimatedVectorDrawable extends Drawable implements Animatable2 {
    -         return super.getChangingConfigurations() | mAnimatedVectorState.getChangingConfigurations();
    -     }
    - 
    -+    /**
    -+     * Draws the AnimatedVectorDrawable into the given canvas.
    -+     * <p>
    -+     * <strong>Note:</strong> Calling this method with a software canvas when the
    -+     * AnimatedVectorDrawable is being animated on RenderThread (for API 25 and later) may yield
    -+     * outdated result, as the UI thread is not guaranteed to be in sync with RenderThread on
    -+     * VectorDrawable's property changes during RenderThread animations.
    -+     * </p>
    -+     *
    -+     * @param canvas The canvas to draw into
    -+     */
    -     @Override
    -     public void draw(Canvas canvas) {
    -         if (!canvas.isHardwareAccelerated() && mAnimatorSet instanceof VectorDrawableAnimatorRT) {
    -@@ -272,9 +356,9 @@ public class AnimatedVectorDrawable extends Drawable implements Animatable2 {
    -     }
    - 
    -     /**
    --     * AnimatedVectorDrawable is running on render thread now. Therefore, if the root alpha is being
    --     * animated, then the root alpha value we get from this call could be out of sync with alpha
    --     * value used in the render thread. Otherwise, the root alpha should be always the same value.
    -+     * For API 25 and later, AnimatedVectorDrawable runs on RenderThread. Therefore, when the
    -+     * root alpha is being animated, this getter does not guarantee to return an up-to-date alpha
    -+     * value.
    -      *
    -      * @return the containing vector drawable's root alpha value.
    -      */
    -@@ -371,7 +455,11 @@ public class AnimatedVectorDrawable extends Drawable implements Animatable2 {
    - 
    -         int eventType = parser.getEventType();
    -         float pathErrorScale = 1;
    --        while (eventType != XmlPullParser.END_DOCUMENT) {
    -+        final int innerDepth = parser.getDepth() + 1;
    -+
    -+        // Parse everything until the end of the animated-vector element.
    -+        while (eventType != XmlPullParser.END_DOCUMENT
    -+                && (parser.getDepth() >= innerDepth || eventType != XmlPullParser.END_TAG)) {
    -             if (eventType == XmlPullParser.START_TAG) {
    -                 final String tagName = parser.getName();
    -                 if (ANIMATED_VECTOR.equals(tagName)) {
    -@@ -1446,7 +1534,6 @@ public class AnimatedVectorDrawable extends Drawable implements Animatable2 {
    -             } else {
    -                 addPendingAction(START_ANIMATION);
    -             }
    --
    -         }
    - 
    -         @Override
    -diff --git a/graphics/java/android/graphics/drawable/BitmapDrawable.java b/graphics/java/android/graphics/drawable/BitmapDrawable.java
    -index 9d8ede0..df107f5 100644
    ---- a/graphics/java/android/graphics/drawable/BitmapDrawable.java
    -+++ b/graphics/java/android/graphics/drawable/BitmapDrawable.java
    -@@ -463,31 +463,14 @@ public class BitmapDrawable extends Drawable {
    -         return isAutoMirrored() && getLayoutDirection() == LayoutDirection.RTL;
    -     }
    - 
    --    private void updateMirrorMatrix(float dx) {
    --        if (mMirrorMatrix == null) {
    --            mMirrorMatrix = new Matrix();
    --        }
    --        mMirrorMatrix.setTranslate(dx, 0);
    --        mMirrorMatrix.preScale(-1.0f, 1.0f);
    --    }
    --
    -     @Override
    -     protected void onBoundsChange(Rect bounds) {
    -         mDstRectAndInsetsDirty = true;
    - 
    -+        final Bitmap bitmap = mBitmapState.mBitmap;
    -         final Shader shader = mBitmapState.mPaint.getShader();
    --        if (shader != null) {
    --            if (needMirroring()) {
    --                updateMirrorMatrix(bounds.right - bounds.left);
    --                shader.setLocalMatrix(mMirrorMatrix);
    --                mBitmapState.mPaint.setShader(shader);
    --            } else {
    --                if (mMirrorMatrix != null) {
    --                    mMirrorMatrix = null;
    --                    shader.setLocalMatrix(Matrix.IDENTITY_MATRIX);
    --                    mBitmapState.mPaint.setShader(shader);
    --                }
    --            }
    -+        if (bitmap != null && shader != null) {
    -+            updateShaderMatrix(bitmap, mBitmapState.mPaint, shader, needMirroring());
    -         }
    -     }
    - 
    -@@ -548,19 +531,7 @@ public class BitmapDrawable extends Drawable {
    -                 canvas.restore();
    -             }
    -         } else {
    --            if (needMirroring) {
    --                // Mirror the bitmap
    --                updateMirrorMatrix(mDstRect.right - mDstRect.left);
    --                shader.setLocalMatrix(mMirrorMatrix);
    --                paint.setShader(shader);
    --            } else {
    --                if (mMirrorMatrix != null) {
    --                    mMirrorMatrix = null;
    --                    shader.setLocalMatrix(Matrix.IDENTITY_MATRIX);
    --                    paint.setShader(shader);
    --                }
    --            }
    --
    -+            updateShaderMatrix(bitmap, paint, shader, needMirroring);
    -             canvas.drawRect(mDstRect, paint);
    -         }
    - 
    -@@ -573,6 +544,51 @@ public class BitmapDrawable extends Drawable {
    -         }
    -     }
    - 
    -+    /**
    -+     * Updates the {@code paint}'s shader matrix to be consistent with the
    -+     * destination size and layout direction.
    -+     *
    -+     * @param bitmap the bitmap to be drawn
    -+     * @param paint the paint used to draw the bitmap
    -+     * @param shader the shader to set on the paint
    -+     * @param needMirroring whether the bitmap should be mirrored
    -+     */
    -+    private void updateShaderMatrix(@NonNull Bitmap bitmap, @NonNull Paint paint,
    -+            @NonNull Shader shader, boolean needMirroring) {
    -+        final int sourceDensity = bitmap.getDensity();
    -+        final int targetDensity = mTargetDensity;
    -+        final boolean needScaling = sourceDensity != 0 && sourceDensity != targetDensity;
    -+        if (needScaling || needMirroring) {
    -+            final Matrix matrix = getOrCreateMirrorMatrix();
    -+            matrix.reset();
    -+
    -+            if (needMirroring) {
    -+                final int dx = mDstRect.right - mDstRect.left;
    -+                matrix.setTranslate(dx, 0);
    -+                matrix.setScale(-1, 1);
    -+            }
    -+
    -+            if (needScaling) {
    -+                final float densityScale = targetDensity / (float) sourceDensity;
    -+                matrix.postScale(densityScale, densityScale);
    -+            }
    -+
    -+            shader.setLocalMatrix(matrix);
    -+        } else {
    -+            mMirrorMatrix = null;
    -+            shader.setLocalMatrix(Matrix.IDENTITY_MATRIX);
    -+        }
    -+
    -+        paint.setShader(shader);
    -+    }
    -+
    -+    private Matrix getOrCreateMirrorMatrix() {
    -+        if (mMirrorMatrix == null) {
    -+            mMirrorMatrix = new Matrix();
    -+        }
    -+        return mMirrorMatrix;
    -+    }
    -+
    -     private void updateDstRectAndInsetsIfDirty() {
    -         if (mDstRectAndInsetsDirty) {
    -             if (mBitmapState.mTileModeX == null && mBitmapState.mTileModeY == null) {
    -diff --git a/graphics/java/android/graphics/drawable/Drawable.java b/graphics/java/android/graphics/drawable/Drawable.java
    -index 7f3a437..c2e302e 100644
    ---- a/graphics/java/android/graphics/drawable/Drawable.java
    -+++ b/graphics/java/android/graphics/drawable/Drawable.java
    -@@ -109,6 +109,9 @@ import java.util.Collection;
    -  *     <li> <b>Nine Patch</b>: an extension to the PNG format allows it to
    -  *     specify information about how to stretch it and place things inside of
    -  *     it.
    -+ *     <li><b>Vector</b>: a drawable defined in an XML file as a set of points,
    -+ *     lines, and curves along with its associated color information. This type
    -+ *     of drawable can be scaled without loss of display quality.
    -  *     <li> <b>Shape</b>: contains simple drawing commands instead of a raw
    -  *     bitmap, allowing it to resize better in some cases.
    -  *     <li> <b>Layers</b>: a compound drawable, which draws multiple underlying
    -@@ -1422,9 +1425,10 @@ public abstract class Drawable {
    -     /**
    -      * Obtains styled attributes from the theme, if available, or unstyled
    -      * resources if the theme is null.
    -+     * @hide
    -      */
    --    static @NonNull TypedArray obtainAttributes(@NonNull Resources res, @Nullable Theme theme,
    --            @NonNull AttributeSet set, @NonNull int[] attrs) {
    -+    protected static @NonNull TypedArray obtainAttributes(@NonNull Resources res,
    -+            @Nullable Theme theme, @NonNull AttributeSet set, @NonNull int[] attrs) {
    -         if (theme == null) {
    -             return res.obtainAttributes(set, attrs);
    -         }
    -diff --git a/graphics/java/android/graphics/drawable/DrawableContainer.java b/graphics/java/android/graphics/drawable/DrawableContainer.java
    -index cc7f5c7..c7a3c75 100644
    ---- a/graphics/java/android/graphics/drawable/DrawableContainer.java
    -+++ b/graphics/java/android/graphics/drawable/DrawableContainer.java
    -@@ -27,8 +27,8 @@ import android.graphics.ColorFilter;
    - import android.graphics.Insets;
    - import android.graphics.Outline;
    - import android.graphics.PixelFormat;
    --import android.graphics.Rect;
    - import android.graphics.PorterDuff.Mode;
    -+import android.graphics.Rect;
    - import android.os.SystemClock;
    - import android.util.DisplayMetrics;
    - import android.util.LayoutDirection;
    -@@ -601,8 +601,9 @@ public class DrawableContainer extends Drawable implements Drawable.Callback {
    -      * during inflation.
    -      *
    -      * @param res the resources used to inflate density-dependent values
    -+     * @hide
    -      */
    --    final void updateDensity(Resources res) {
    -+    protected final void updateDensity(Resources res) {
    -         mDrawableContainerState.updateDensity(res);
    -     }
    - 
    -@@ -711,7 +712,10 @@ public class DrawableContainer extends Drawable implements Drawable.Callback {
    -         boolean mHasTintList;
    -         boolean mHasTintMode;
    - 
    --        DrawableContainerState(DrawableContainerState orig, DrawableContainer owner,
    -+        /**
    -+         * @hide
    -+         */
    -+        protected DrawableContainerState(DrawableContainerState orig, DrawableContainer owner,
    -                 Resources res) {
    -             mOwner = owner;
    -             mSourceRes = res != null ? res : (orig != null ? orig.mSourceRes : null);
    -diff --git a/graphics/java/android/graphics/drawable/GradientDrawable.java b/graphics/java/android/graphics/drawable/GradientDrawable.java
    -index 3dbd2a9..8c633b0 100644
    ---- a/graphics/java/android/graphics/drawable/GradientDrawable.java
    -+++ b/graphics/java/android/graphics/drawable/GradientDrawable.java
    -@@ -475,16 +475,17 @@ public class GradientDrawable extends Drawable {
    -     }
    - 
    -     /**
    --     * Sets the center location in pixels of the gradient. The radius is
    --     * honored only when the gradient type is set to {@link #RADIAL_GRADIENT}
    --     * or {@link #SWEEP_GRADIENT}.
    -+     * Sets the position of the center of the gradient as a fraction of the
    -+     * width and height.
    -+     * <p>
    -+     * The default value is (0.5, 0.5).
    -      * <p>
    -      * <strong>Note</strong>: changing this property will affect all instances
    -      * of a drawable loaded from a resource. It is recommended to invoke
    -      * {@link #mutate()} before changing this property.
    -      *
    --     * @param x the x coordinate of the gradient's center in pixels
    --     * @param y the y coordinate of the gradient's center in pixels
    -+     * @param x the X-position of the center of the gradient
    -+     * @param y the Y-position of the center of the gradient
    -      *
    -      * @see #mutate()
    -      * @see #setGradientType(int)
    -@@ -498,9 +499,10 @@ public class GradientDrawable extends Drawable {
    -     }
    - 
    -     /**
    --     * Returns the center X location of this gradient in pixels.
    -+     * Returns the X-position of the center of the gradient as a fraction of
    -+     * the width.
    -      *
    --     * @return the center X location of this gradient in pixels
    -+     * @return the X-position of the center of the gradient
    -      * @see #setGradientCenter(float, float)
    -      */
    -     public float getGradientCenterX() {
    -@@ -508,9 +510,10 @@ public class GradientDrawable extends Drawable {
    -     }
    - 
    -     /**
    --     * Returns the center Y location of this gradient in pixels.
    -+     * Returns the Y-position of the center of this gradient as a fraction of
    -+     * the height.
    -      *
    --     * @return the center Y location of this gradient in pixels
    -+     * @return the Y-position of the center of the gradient
    -      * @see #setGradientCenter(float, float)
    -      */
    -     public float getGradientCenterY() {
    -@@ -554,19 +557,43 @@ public class GradientDrawable extends Drawable {
    -     }
    - 
    -     /**
    --     * Sets whether or not this drawable will honor its {@code level} property.
    -+     * Sets whether this drawable's {@code level} property will be used to
    -+     * scale the gradient. If a gradient is not used, this property has no
    -+     * effect.
    -      * <p>
    --     * <strong>Note</strong>: changing this property will affect all instances
    -+     * Scaling behavior varies based on gradient type:
    -+     * <ul>
    -+     *     <li>{@link #LINEAR_GRADIENT} adjusts the ending position along the
    -+     *         gradient's axis of orientation (see {@link #getOrientation()})
    -+     *     <li>{@link #RADIAL_GRADIENT} adjusts the outer radius
    -+     *     <li>{@link #SWEEP_GRADIENT} adjusts the ending angle
    -+     * <ul>
    -+     * <p>
    -+     * The default value for this property is {@code false}.
    -+     * <p>
    -+     * <strong>Note</strong>: This property corresponds to the
    -+     * {@code android:useLevel} attribute on the inner {@code &lt;gradient&gt;}
    -+     * tag, NOT the {@code android:useLevel} attribute on the outer
    -+     * {@code &lt;shape&gt;} tag. For example,
    -+     * <pre>{@code
    -+     * <shape ...>
    -+     *     <gradient
    -+     *         ...
    -+     *         android:useLevel="true" />
    -+     * </shape>
    -+     * }</pre><p>
    -+     * <strong>Note</strong>: Changing this property will affect all instances
    -      * of a drawable loaded from a resource. It is recommended to invoke
    -      * {@link #mutate()} before changing this property.
    -      *
    --     * @param useLevel {@code true} if this drawable should honor its level,
    --     *                 {@code false} otherwise
    -+     * @param useLevel {@code true} if the gradient should be scaled based on
    -+     *                 level, {@code false} otherwise
    -      *
    -      * @see #mutate()
    -      * @see #setLevel(int)
    -      * @see #getLevel()
    -      * @see #getUseLevel()
    -+     * @attr ref android.R.styleable#GradientDrawableGradient_useLevel
    -      */
    -     public void setUseLevel(boolean useLevel) {
    -         mGradientState.mUseLevel = useLevel;
    -@@ -575,12 +602,13 @@ public class GradientDrawable extends Drawable {
    -     }
    - 
    -     /**
    --     * Returns whether or not this drawable will honor its {@code level}
    --     * property.
    -+     * Returns whether this drawable's {@code level} property will be used to
    -+     * scale the gradient.
    -      *
    --     * @return {@code true} if this drawable should honor its level,
    -+     * @return {@code true} if the gradient should be scaled based on level,
    -      *         {@code false} otherwise
    -      * @see #setUseLevel(boolean)
    -+     * @attr ref android.R.styleable#GradientDrawableGradient_useLevel
    -      */
    -     public boolean getUseLevel() {
    -         return mGradientState.mUseLevel;
    -diff --git a/graphics/java/android/graphics/drawable/LayerDrawable.java b/graphics/java/android/graphics/drawable/LayerDrawable.java
    -index 1864206..c30c4c2 100644
    ---- a/graphics/java/android/graphics/drawable/LayerDrawable.java
    -+++ b/graphics/java/android/graphics/drawable/LayerDrawable.java
    -@@ -269,7 +269,8 @@ public class LayerDrawable extends Drawable implements Drawable.Callback {
    - 
    -             // If the layer doesn't have a drawable or unresolved theme
    -             // attribute for a drawable, attempt to parse one from the child
    --            // element.
    -+            // element. If multiple child elements exist, we'll only use the
    -+            // first one.
    -             if (layer.mDrawable == null && (layer.mThemeAttrs == null ||
    -                     layer.mThemeAttrs[R.styleable.LayerDrawableItem_drawable] == 0)) {
    -                 while ((type = parser.next()) == XmlPullParser.TEXT) {
    -@@ -279,13 +280,12 @@ public class LayerDrawable extends Drawable implements Drawable.Callback {
    -                             + ": <item> tag requires a 'drawable' attribute or "
    -                             + "child tag defining a drawable");
    -                 }
    --                layer.mDrawable = Drawable.createFromXmlInner(r, parser, attrs, theme);
    --            }
    - 
    --            if (layer.mDrawable != null) {
    -+                // We found a child drawable. Take ownership.
    -+                layer.mDrawable = Drawable.createFromXmlInner(r, parser, attrs, theme);
    -+                layer.mDrawable.setCallback(this);
    -                 state.mChildrenChangingConfigurations |=
    -                         layer.mDrawable.getChangingConfigurations();
    --                layer.mDrawable.setCallback(this);
    -             }
    - 
    -             addLayer(layer);
    -@@ -387,7 +387,19 @@ public class LayerDrawable extends Drawable implements Drawable.Callback {
    - 
    -         final Drawable dr = a.getDrawable(R.styleable.LayerDrawableItem_drawable);
    -         if (dr != null) {
    -+            if (layer.mDrawable != null) {
    -+                // It's possible that a drawable was already set, in which case
    -+                // we should clear the callback. We may have also integrated the
    -+                // drawable's changing configurations, but we don't have enough
    -+                // information to revert that change.
    -+                layer.mDrawable.setCallback(null);
    -+            }
    -+
    -+            // Take ownership of the new drawable.
    -             layer.mDrawable = dr;
    -+            layer.mDrawable.setCallback(this);
    -+            state.mChildrenChangingConfigurations |=
    -+                    layer.mDrawable.getChangingConfigurations();
    -         }
    -     }
    - 
    -diff --git a/graphics/java/android/graphics/drawable/VectorDrawable.java b/graphics/java/android/graphics/drawable/VectorDrawable.java
    -index dc1d18f..1ca1552 100644
    ---- a/graphics/java/android/graphics/drawable/VectorDrawable.java
    -+++ b/graphics/java/android/graphics/drawable/VectorDrawable.java
    -@@ -27,9 +27,9 @@ import android.graphics.Canvas;
    - import android.graphics.ColorFilter;
    - import android.graphics.Insets;
    - import android.graphics.PixelFormat;
    -+import android.graphics.PorterDuff.Mode;
    - import android.graphics.PorterDuffColorFilter;
    - import android.graphics.Rect;
    --import android.graphics.PorterDuff.Mode;
    - import android.graphics.Shader;
    - import android.util.ArrayMap;
    - import android.util.AttributeSet;
    -@@ -76,27 +76,36 @@ import dalvik.system.VMRuntime;
    -  * <dl>
    -  * <dt><code>android:name</code></dt>
    -  * <dd>Defines the name of this vector drawable.</dd>
    -+ * <dd>Animatable : No.</dd>
    -  * <dt><code>android:width</code></dt>
    -  * <dd>Used to define the intrinsic width of the drawable.
    -  * This support all the dimension units, normally specified with dp.</dd>
    -+ * <dd>Animatable : No.</dd>
    -  * <dt><code>android:height</code></dt>
    -  * <dd>Used to define the intrinsic height the drawable.
    -  * This support all the dimension units, normally specified with dp.</dd>
    -+ * <dd>Animatable : No.</dd>
    -  * <dt><code>android:viewportWidth</code></dt>
    -  * <dd>Used to define the width of the viewport space. Viewport is basically
    -  * the virtual canvas where the paths are drawn on.</dd>
    -+ * <dd>Animatable : No.</dd>
    -  * <dt><code>android:viewportHeight</code></dt>
    -  * <dd>Used to define the height of the viewport space. Viewport is basically
    -  * the virtual canvas where the paths are drawn on.</dd>
    -+ * <dd>Animatable : No.</dd>
    -  * <dt><code>android:tint</code></dt>
    -  * <dd>The color to apply to the drawable as a tint. By default, no tint is applied.</dd>
    -+ * <dd>Animatable : No.</dd>
    -  * <dt><code>android:tintMode</code></dt>
    -  * <dd>The Porter-Duff blending mode for the tint color. The default value is src_in.</dd>
    -+ * <dd>Animatable : No.</dd>
    -  * <dt><code>android:autoMirrored</code></dt>
    -  * <dd>Indicates if the drawable needs to be mirrored when its layout direction is
    -  * RTL (right-to-left).</dd>
    -+ * <dd>Animatable : No.</dd>
    -  * <dt><code>android:alpha</code></dt>
    -  * <dd>The opacity of this drawable.</dd>
    -+ * <dd>Animatable : Yes.</dd>
    -  * </dl></dd>
    -  * </dl>
    -  *
    -@@ -108,24 +117,32 @@ import dalvik.system.VMRuntime;
    -  * <dl>
    -  * <dt><code>android:name</code></dt>
    -  * <dd>Defines the name of the group.</dd>
    -+ * <dd>Animatable : No.</dd>
    -  * <dt><code>android:rotation</code></dt>
    -  * <dd>The degrees of rotation of the group.</dd>
    -+ * <dd>Animatable : Yes.</dd>
    -  * <dt><code>android:pivotX</code></dt>
    -  * <dd>The X coordinate of the pivot for the scale and rotation of the group.
    -  * This is defined in the viewport space.</dd>
    -+ * <dd>Animatable : Yes.</dd>
    -  * <dt><code>android:pivotY</code></dt>
    -  * <dd>The Y coordinate of the pivot for the scale and rotation of the group.
    -  * This is defined in the viewport space.</dd>
    -+ * <dd>Animatable : Yes.</dd>
    -  * <dt><code>android:scaleX</code></dt>
    -  * <dd>The amount of scale on the X Coordinate.</dd>
    -+ * <dd>Animatable : Yes.</dd>
    -  * <dt><code>android:scaleY</code></dt>
    -  * <dd>The amount of scale on the Y coordinate.</dd>
    -+ * <dd>Animatable : Yes.</dd>
    -  * <dt><code>android:translateX</code></dt>
    -  * <dd>The amount of translation on the X coordinate.
    -  * This is defined in the viewport space.</dd>
    -+ * <dd>Animatable : Yes.</dd>
    -  * <dt><code>android:translateY</code></dt>
    -  * <dd>The amount of translation on the Y coordinate.
    -  * This is defined in the viewport space.</dd>
    -+ * <dd>Animatable : Yes.</dd>
    -  * </dl></dd>
    -  * </dl>
    -  *
    -@@ -135,40 +152,60 @@ import dalvik.system.VMRuntime;
    -  * <dl>
    -  * <dt><code>android:name</code></dt>
    -  * <dd>Defines the name of the path.</dd>
    -+ * <dd>Animatable : No.</dd>
    -  * <dt><code>android:pathData</code></dt>
    -  * <dd>Defines path data using exactly same format as "d" attribute
    -  * in the SVG's path data. This is defined in the viewport space.</dd>
    -+ * <dd>Animatable : Yes.</dd>
    -  * <dt><code>android:fillColor</code></dt>
    -  * <dd>Specifies the color used to fill the path. May be a color or, for SDK 24+, a color state list
    -- * or a gradient color. If this property is animated, any value set by the animation will
    -- * override the original value. No path fill is drawn if this property is not specified.</dd>
    -+ * or a gradient color (See {@link android.R.styleable#GradientColor}
    -+ * and {@link android.R.styleable#GradientColorItem}).
    -+ * If this property is animated, any value set by the animation will override the original value.
    -+ * No path fill is drawn if this property is not specified.</dd>
    -+ * <dd>Animatable : Yes.</dd>
    -  * <dt><code>android:strokeColor</code></dt>
    -  * <dd>Specifies the color used to draw the path outline. May be a color or, for SDK 24+, a color
    -- * state list or a gradient color. If this property is animated, any value set by the animation will
    -- * override the original value. No path outline is drawn if this property is not specified.</dd>
    -+ * state list or a gradient color (See {@link android.R.styleable#GradientColor}
    -+ * and {@link android.R.styleable#GradientColorItem}).
    -+ * If this property is animated, any value set by the animation will override the original value.
    -+ * No path outline is drawn if this property is not specified.</dd>
    -+ * <dd>Animatable : Yes.</dd>
    -  * <dt><code>android:strokeWidth</code></dt>
    -  * <dd>The width a path stroke.</dd>
    -+ * <dd>Animatable : Yes.</dd>
    -  * <dt><code>android:strokeAlpha</code></dt>
    -  * <dd>The opacity of a path stroke.</dd>
    -+ * <dd>Animatable : Yes.</dd>
    -  * <dt><code>android:fillAlpha</code></dt>
    -  * <dd>The opacity to fill the path with.</dd>
    -+ * <dd>Animatable : Yes.</dd>
    -  * <dt><code>android:trimPathStart</code></dt>
    -  * <dd>The fraction of the path to trim from the start, in the range from 0 to 1.</dd>
    -+ * <dd>Animatable : Yes.</dd>
    -  * <dt><code>android:trimPathEnd</code></dt>
    -  * <dd>The fraction of the path to trim from the end, in the range from 0 to 1.</dd>
    -+ * <dd>Animatable : Yes.</dd>
    -  * <dt><code>android:trimPathOffset</code></dt>
    -  * <dd>Shift trim region (allows showed region to include the start and end), in the range
    -  * from 0 to 1.</dd>
    -+ * <dd>Animatable : Yes.</dd>
    -  * <dt><code>android:strokeLineCap</code></dt>
    -  * <dd>Sets the linecap for a stroked path: butt, round, square.</dd>
    -+ * <dd>Animatable : No.</dd>
    -  * <dt><code>android:strokeLineJoin</code></dt>
    -  * <dd>Sets the lineJoin for a stroked path: miter,round,bevel.</dd>
    -+ * <dd>Animatable : No.</dd>
    -  * <dt><code>android:strokeMiterLimit</code></dt>
    -  * <dd>Sets the Miter limit for a stroked path.</dd>
    -+ * <dd>Animatable : No.</dd>
    -  * <dt><code>android:fillType</code></dt>
    -- * <dd>Sets the fillType for a path. It is the same as SVG's "fill-rule" properties.
    -- * For more details, see https://www.w3.org/TR/SVG/painting.html#FillRuleProperty</dd>
    -+ * <dd>Sets the fillType for a path. The types can be either "evenOdd" or "nonZero". They behave the
    -+ * same as SVG's "fill-rule" properties. For more details, see
    -+ * <a href="https://www.w3.org/TR/SVG/painting.html#FillRuleProperty">FillRuleProperty</a></dd>
    -+ * <dd>Animatable : No.</dd>
    -  * </dl></dd>
    -+ *
    -  * </dl>
    -  *
    -  * <dl>
    -@@ -178,9 +215,11 @@ import dalvik.system.VMRuntime;
    -  * <dl>
    -  * <dt><code>android:name</code></dt>
    -  * <dd>Defines the name of the clip path.</dd>
    -+ * <dd>Animatable : No.</dd>
    -  * <dt><code>android:pathData</code></dt>
    -  * <dd>Defines clip path using the same format as "d" attribute
    -  * in the SVG's path data.</dd>
    -+ * <dd>Animatable : Yes.</dd>
    -  * </dl></dd>
    -  * </dl>
    -  * <li>Here is a simple VectorDrawable in this vectordrawable.xml file.
    -@@ -201,7 +240,26 @@ import dalvik.system.VMRuntime;
    -  *             android:pathData=&quot;M300,70 l 0,-70 70,70 0,0 -70,70z&quot; /&gt;
    -  *     &lt;/group&gt;
    -  * &lt;/vector&gt;
    -- * </pre></li>
    -+ * </pre>
    -+ * </li>
    -+ * <li>And here is an example of linear gradient color, which is supported in SDK 24+.
    -+ * See more details in {@link android.R.styleable#GradientColor} and
    -+ * {@link android.R.styleable#GradientColorItem}.
    -+ * <pre>
    -+ * &lt;gradient xmlns:android="http://schemas.android.com/apk/res/android"
    -+ *     android:angle="90"
    -+ *     android:startColor="?android:attr/colorPrimary"
    -+ *     android:endColor="?android:attr/colorControlActivated"
    -+ *     android:centerColor="#f00"
    -+ *     android:startX="0"
    -+ *     android:startY="0"
    -+ *     android:endX="100"
    -+ *     android:endY="100"
    -+ *     android:type="linear"&gt;
    -+ * &lt;/gradient&gt;
    -+ * </pre>
    -+ * </li>
    -+ *
    -  */
    - 
    - public class VectorDrawable extends Drawable {
    -@@ -686,7 +744,11 @@ public class VectorDrawable extends Drawable {
    -         groupStack.push(state.mRootGroup);
    - 
    -         int eventType = parser.getEventType();
    --        while (eventType != XmlPullParser.END_DOCUMENT) {
    -+        final int innerDepth = parser.getDepth() + 1;
    -+
    -+        // Parse everything until the end of the vector element.
    -+        while (eventType != XmlPullParser.END_DOCUMENT
    -+                && (parser.getDepth() >= innerDepth || eventType != XmlPullParser.END_TAG)) {
    -             if (eventType == XmlPullParser.START_TAG) {
    -                 final String tagName = parser.getName();
    -                 final VGroup currentGroup = groupStack.peek();
    -diff --git a/graphics/java/android/graphics/pdf/PdfEditor.java b/graphics/java/android/graphics/pdf/PdfEditor.java
    -index 2b70b6a..cd1f8de 100644
    ---- a/graphics/java/android/graphics/pdf/PdfEditor.java
    -+++ b/graphics/java/android/graphics/pdf/PdfEditor.java
    -@@ -79,8 +79,12 @@ public final class PdfEditor {
    -         }
    - 
    -         mInput = input;
    --        mNativeDocument = nativeOpen(mInput.getFd(), size);
    --        mPageCount = nativeGetPageCount(mNativeDocument);
    -+
    -+        synchronized (PdfRenderer.sPdfiumLock) {
    -+            mNativeDocument = nativeOpen(mInput.getFd(), size);
    -+            mPageCount = nativeGetPageCount(mNativeDocument);
    -+        }
    -+
    -         mCloseGuard.open("close");
    -     }
    - 
    -@@ -102,7 +106,10 @@ public final class PdfEditor {
    -     public void removePage(int pageIndex) {
    -         throwIfClosed();
    -         throwIfPageNotInDocument(pageIndex);
    --        mPageCount = nativeRemovePage(mNativeDocument, pageIndex);
    -+
    -+        synchronized (PdfRenderer.sPdfiumLock) {
    -+            mPageCount = nativeRemovePage(mNativeDocument, pageIndex);
    -+        }
    -     }
    - 
    -     /**
    -@@ -125,11 +132,16 @@ public final class PdfEditor {
    -         if (clip == null) {
    -             Point size = new Point();
    -             getPageSize(pageIndex, size);
    --            nativeSetTransformAndClip(mNativeDocument, pageIndex, transform.native_instance,
    --                    0, 0, size.x, size.y);
    -+
    -+            synchronized (PdfRenderer.sPdfiumLock) {
    -+                nativeSetTransformAndClip(mNativeDocument, pageIndex, transform.native_instance,
    -+                        0, 0, size.x, size.y);
    -+            }
    -         } else {
    --            nativeSetTransformAndClip(mNativeDocument, pageIndex, transform.native_instance,
    --                    clip.left, clip.top, clip.right, clip.bottom);
    -+            synchronized (PdfRenderer.sPdfiumLock) {
    -+                nativeSetTransformAndClip(mNativeDocument, pageIndex, transform.native_instance,
    -+                        clip.left, clip.top, clip.right, clip.bottom);
    -+            }
    -         }
    -     }
    - 
    -@@ -143,7 +155,10 @@ public final class PdfEditor {
    -         throwIfClosed();
    -         throwIfOutSizeNull(outSize);
    -         throwIfPageNotInDocument(pageIndex);
    --        nativeGetPageSize(mNativeDocument, pageIndex, outSize);
    -+
    -+        synchronized (PdfRenderer.sPdfiumLock) {
    -+            nativeGetPageSize(mNativeDocument, pageIndex, outSize);
    -+        }
    -     }
    - 
    -     /**
    -@@ -156,7 +171,10 @@ public final class PdfEditor {
    -         throwIfClosed();
    -         throwIfOutMediaBoxNull(outMediaBox);
    -         throwIfPageNotInDocument(pageIndex);
    --        return nativeGetPageMediaBox(mNativeDocument, pageIndex, outMediaBox);
    -+
    -+        synchronized (PdfRenderer.sPdfiumLock) {
    -+            return nativeGetPageMediaBox(mNativeDocument, pageIndex, outMediaBox);
    -+        }
    -     }
    - 
    -     /**
    -@@ -169,7 +187,10 @@ public final class PdfEditor {
    -         throwIfClosed();
    -         throwIfMediaBoxNull(mediaBox);
    -         throwIfPageNotInDocument(pageIndex);
    --        nativeSetPageMediaBox(mNativeDocument, pageIndex, mediaBox);
    -+
    -+        synchronized (PdfRenderer.sPdfiumLock) {
    -+            nativeSetPageMediaBox(mNativeDocument, pageIndex, mediaBox);
    -+        }
    -     }
    - 
    -     /**
    -@@ -182,7 +203,10 @@ public final class PdfEditor {
    -         throwIfClosed();
    -         throwIfOutCropBoxNull(outCropBox);
    -         throwIfPageNotInDocument(pageIndex);
    --        return nativeGetPageCropBox(mNativeDocument, pageIndex, outCropBox);
    -+
    -+        synchronized (PdfRenderer.sPdfiumLock) {
    -+            return nativeGetPageCropBox(mNativeDocument, pageIndex, outCropBox);
    -+        }
    -     }
    - 
    -     /**
    -@@ -195,7 +219,10 @@ public final class PdfEditor {
    -         throwIfClosed();
    -         throwIfCropBoxNull(cropBox);
    -         throwIfPageNotInDocument(pageIndex);
    --        nativeSetPageCropBox(mNativeDocument, pageIndex, cropBox);
    -+
    -+        synchronized (PdfRenderer.sPdfiumLock) {
    -+            nativeSetPageCropBox(mNativeDocument, pageIndex, cropBox);
    -+        }
    -     }
    - 
    -     /**
    -@@ -205,7 +232,10 @@ public final class PdfEditor {
    -      */
    -     public boolean shouldScaleForPrinting() {
    -         throwIfClosed();
    --        return nativeScaleForPrinting(mNativeDocument);
    -+
    -+        synchronized (PdfRenderer.sPdfiumLock) {
    -+            return nativeScaleForPrinting(mNativeDocument);
    -+        }
    -     }
    - 
    -     /**
    -@@ -219,7 +249,10 @@ public final class PdfEditor {
    -     public void write(ParcelFileDescriptor output) throws IOException {
    -         try {
    -             throwIfClosed();
    --            nativeWrite(mNativeDocument, output.getFd());
    -+
    -+            synchronized (PdfRenderer.sPdfiumLock) {
    -+                nativeWrite(mNativeDocument, output.getFd());
    -+            }
    -         } finally {
    -             IoUtils.closeQuietly(output);
    -         }
    -@@ -247,7 +280,9 @@ public final class PdfEditor {
    -     }
    - 
    -     private void doClose() {
    --        nativeClose(mNativeDocument);
    -+        synchronized (PdfRenderer.sPdfiumLock) {
    -+            nativeClose(mNativeDocument);
    -+        }
    -         IoUtils.closeQuietly(mInput);
    -         mInput = null;
    -         mCloseGuard.close();
    -diff --git a/graphics/java/android/graphics/pdf/PdfRenderer.java b/graphics/java/android/graphics/pdf/PdfRenderer.java
    -index 520ebe5..cfc1309 100644
    ---- a/graphics/java/android/graphics/pdf/PdfRenderer.java
    -+++ b/graphics/java/android/graphics/pdf/PdfRenderer.java
    -@@ -99,6 +99,12 @@ import java.lang.annotation.RetentionPolicy;
    -  * @see #close()
    -  */
    - public final class PdfRenderer implements AutoCloseable {
    -+    /**
    -+     * Any call the native pdfium code has to be single threaded as the library does not support
    -+     * parallel use.
    -+     */
    -+    final static Object sPdfiumLock = new Object();
    -+
    -     private final CloseGuard mCloseGuard = CloseGuard.get();
    - 
    -     private final Point mTempPoint = new Point();
    -@@ -154,8 +160,12 @@ public final class PdfRenderer implements AutoCloseable {
    -         }
    - 
    -         mInput = input;
    --        mNativeDocument = nativeCreate(mInput.getFd(), size);
    --        mPageCount = nativeGetPageCount(mNativeDocument);
    -+
    -+        synchronized (sPdfiumLock) {
    -+            mNativeDocument = nativeCreate(mInput.getFd(), size);
    -+            mPageCount = nativeGetPageCount(mNativeDocument);
    -+        }
    -+
    -         mCloseGuard.open("close");
    -     }
    - 
    -@@ -189,7 +199,10 @@ public final class PdfRenderer implements AutoCloseable {
    -      */
    -     public boolean shouldScaleForPrinting() {
    -         throwIfClosed();
    --        return nativeScaleForPrinting(mNativeDocument);
    -+
    -+        synchronized (sPdfiumLock) {
    -+            return nativeScaleForPrinting(mNativeDocument);
    -+        }
    -     }
    - 
    -     /**
    -@@ -224,7 +237,9 @@ public final class PdfRenderer implements AutoCloseable {
    -         if (mCurrentPage != null) {
    -             mCurrentPage.close();
    -         }
    --        nativeClose(mNativeDocument);
    -+        synchronized (sPdfiumLock) {
    -+            nativeClose(mNativeDocument);
    -+        }
    -         try {
    -             mInput.close();
    -         } catch (IOException ioe) {
    -@@ -277,7 +292,9 @@ public final class PdfRenderer implements AutoCloseable {
    - 
    -         private Page(int index) {
    -             Point size = mTempPoint;
    --            mNativePage = nativeOpenPageAndGetSize(mNativeDocument, index, size);
    -+            synchronized (sPdfiumLock) {
    -+                mNativePage = nativeOpenPageAndGetSize(mNativeDocument, index, size);
    -+            }
    -             mIndex = index;
    -             mWidth = size.x;
    -             mHeight = size.y;
    -@@ -384,8 +401,10 @@ public final class PdfRenderer implements AutoCloseable {
    - 
    -             final long transformPtr = (transform != null) ? transform.native_instance : 0;
    - 
    --            nativeRenderPage(mNativeDocument, mNativePage, destination, contentLeft,
    --                    contentTop, contentRight, contentBottom, transformPtr, renderMode);
    -+            synchronized (sPdfiumLock) {
    -+                nativeRenderPage(mNativeDocument, mNativePage, destination, contentLeft,
    -+                        contentTop, contentRight, contentBottom, transformPtr, renderMode);
    -+            }
    -         }
    - 
    -         /**
    -@@ -412,7 +431,9 @@ public final class PdfRenderer implements AutoCloseable {
    -         }
    - 
    -         private void doClose() {
    --            nativeClosePage(mNativePage);
    -+            synchronized (sPdfiumLock) {
    -+                nativeClosePage(mNativePage);
    -+            }
    -             mNativePage = 0;
    -             mCloseGuard.close();
    -             mCurrentPage = null;
    -diff --git a/include/androidfw/Asset.h b/include/androidfw/Asset.h
    -index ee77e97..52c8637 100644
    ---- a/include/androidfw/Asset.h
    -+++ b/include/androidfw/Asset.h
    -@@ -44,7 +44,7 @@ namespace android {
    -  */
    - class Asset {
    - public:
    --    virtual ~Asset(void);
    -+    virtual ~Asset(void) = default;
    - 
    -     static int32_t getGlobalCount();
    -     static String8 getAssetAllocations();
    -@@ -119,6 +119,19 @@ public:
    -     const char* getAssetSource(void) const { return mAssetSource.string(); }
    - 
    - protected:
    -+    /*
    -+     * Adds this Asset to the global Asset list for debugging and
    -+     * accounting.
    -+     * Concrete subclasses must call this in their constructor.
    -+     */
    -+    static void registerAsset(Asset* asset);
    -+
    -+    /*
    -+     * Removes this Asset from the global Asset list.
    -+     * Concrete subclasses must call this in their destructor.
    -+     */
    -+    static void unregisterAsset(Asset* asset);
    -+
    -     Asset(void);        // constructor; only invoked indirectly
    - 
    -     /* handle common seek() housekeeping */
    -diff --git a/keystore/java/android/security/KeyChain.java b/keystore/java/android/security/KeyChain.java
    -index cce58c2..a96ca39 100644
    ---- a/keystore/java/android/security/KeyChain.java
    -+++ b/keystore/java/android/security/KeyChain.java
    -@@ -20,6 +20,7 @@ import android.annotation.Nullable;
    - import android.annotation.WorkerThread;
    - import android.app.Activity;
    - import android.app.PendingIntent;
    -+import android.app.Service;
    - import android.content.ComponentName;
    - import android.content.Context;
    - import android.content.Intent;
    -@@ -356,6 +357,9 @@ public final class KeyChain {
    -      *
    -      * <p> This method may block while waiting for a connection to another process, and must never
    -      * be called from the main thread.
    -+     * <p> As {@link Activity} and {@link Service} contexts are short-lived and can be destroyed
    -+     * at any time from the main thread, it is safer to rely on a long-lived context such as one
    -+     * returned from {@link Context#getApplicationContext()}.
    -      *
    -      * @param alias The alias of the desired private key, typically returned via
    -      *              {@link KeyChainAliasCallback#alias}.
    -@@ -368,7 +372,7 @@ public final class KeyChain {
    -         if (alias == null) {
    -             throw new NullPointerException("alias == null");
    -         }
    --        KeyChainConnection keyChainConnection = bind(context);
    -+        KeyChainConnection keyChainConnection = bind(context.getApplicationContext());
    -         try {
    -             final IKeyChainService keyChainService = keyChainConnection.getService();
    -             final String keyId = keyChainService.requestPrivateKey(alias);
    -@@ -400,6 +404,9 @@ public final class KeyChain {
    -      *
    -      * <p> This method may block while waiting for a connection to another process, and must never
    -      * be called from the main thread.
    -+     * <p> As {@link Activity} and {@link Service} contexts are short-lived and can be destroyed
    -+     * at any time from the main thread, it is safer to rely on a long-lived context such as one
    -+     * returned from {@link Context#getApplicationContext()}.
    -      *
    -      * @param alias The alias of the desired certificate chain, typically
    -      * returned via {@link KeyChainAliasCallback#alias}.
    -@@ -412,7 +419,7 @@ public final class KeyChain {
    -         if (alias == null) {
    -             throw new NullPointerException("alias == null");
    -         }
    --        KeyChainConnection keyChainConnection = bind(context);
    -+        KeyChainConnection keyChainConnection = bind(context.getApplicationContext());
    -         try {
    -             IKeyChainService keyChainService = keyChainConnection.getService();
    - 
    -diff --git a/keystore/java/android/security/KeyPairGeneratorSpec.java b/keystore/java/android/security/KeyPairGeneratorSpec.java
    -index d849317..d023866 100644
    ---- a/keystore/java/android/security/KeyPairGeneratorSpec.java
    -+++ b/keystore/java/android/security/KeyPairGeneratorSpec.java
    -@@ -251,8 +251,9 @@ public final class KeyPairGeneratorSpec implements AlgorithmParameterSpec {
    -     /**
    -      * Builder class for {@link KeyPairGeneratorSpec} objects.
    -      * <p>
    --     * This will build a parameter spec for use with the <a href="{@docRoot}
    --     * training/articles/keystore.html">Android KeyStore facility</a>.
    -+     * This will build a parameter spec for use with the
    -+     * <a href="{@docRoot}training/articles/keystore.html">Android KeyStore
    -+     * facility</a>.
    -      * <p>
    -      * The required fields must be filled in with the builder.
    -      * <p>
    -diff --git a/libs/androidfw/Asset.cpp b/libs/androidfw/Asset.cpp
    -index 4e14b13..6ae39d5 100644
    ---- a/libs/androidfw/Asset.cpp
    -+++ b/libs/androidfw/Asset.cpp
    -@@ -52,6 +52,47 @@ static int32_t gCount = 0;
    - static Asset* gHead = NULL;
    - static Asset* gTail = NULL;
    - 
    -+void Asset::registerAsset(Asset* asset)
    -+{
    -+    AutoMutex _l(gAssetLock);
    -+    gCount++;
    -+    asset->mNext = asset->mPrev = NULL;
    -+    if (gTail == NULL) {
    -+        gHead = gTail = asset;
    -+    } else {
    -+        asset->mPrev = gTail;
    -+        gTail->mNext = asset;
    -+        gTail = asset;
    -+    }
    -+
    -+    if (kIsDebug) {
    -+        ALOGI("Creating Asset %p #%d\n", asset, gCount);
    -+    }
    -+}
    -+
    -+void Asset::unregisterAsset(Asset* asset)
    -+{
    -+    AutoMutex _l(gAssetLock);
    -+    gCount--;
    -+    if (gHead == asset) {
    -+        gHead = asset->mNext;
    -+    }
    -+    if (gTail == asset) {
    -+        gTail = asset->mPrev;
    -+    }
    -+    if (asset->mNext != NULL) {
    -+        asset->mNext->mPrev = asset->mPrev;
    -+    }
    -+    if (asset->mPrev != NULL) {
    -+        asset->mPrev->mNext = asset->mNext;
    -+    }
    -+    asset->mNext = asset->mPrev = NULL;
    -+
    -+    if (kIsDebug) {
    -+        ALOGI("Destroying Asset in %p #%d\n", asset, gCount);
    -+    }
    -+}
    -+
    - int32_t Asset::getGlobalCount()
    - {
    -     AutoMutex _l(gAssetLock);
    -@@ -79,43 +120,8 @@ String8 Asset::getAssetAllocations()
    - }
    - 
    - Asset::Asset(void)
    --    : mAccessMode(ACCESS_UNKNOWN)
    -+    : mAccessMode(ACCESS_UNKNOWN), mNext(NULL), mPrev(NULL)
    - {
    --    AutoMutex _l(gAssetLock);
    --    gCount++;
    --    mNext = mPrev = NULL;
    --    if (gTail == NULL) {
    --        gHead = gTail = this;
    --    } else {
    --        mPrev = gTail;
    --        gTail->mNext = this;
    --        gTail = this;
    --    }
    --    if (kIsDebug) {
    --        ALOGI("Creating Asset %p #%d\n", this, gCount);
    --    }
    --}
    --
    --Asset::~Asset(void)
    --{
    --    AutoMutex _l(gAssetLock);
    --    gCount--;
    --    if (gHead == this) {
    --        gHead = mNext;
    --    }
    --    if (gTail == this) {
    --        gTail = mPrev;
    --    }
    --    if (mNext != NULL) {
    --        mNext->mPrev = mPrev;
    --    }
    --    if (mPrev != NULL) {
    --        mPrev->mNext = mNext;
    --    }
    --    mNext = mPrev = NULL;
    --    if (kIsDebug) {
    --        ALOGI("Destroying Asset in %p #%d\n", this, gCount);
    --    }
    - }
    - 
    - /*
    -@@ -361,6 +367,9 @@ off64_t Asset::handleSeek(off64_t offset, int whence, off64_t curPosn, off64_t m
    - _FileAsset::_FileAsset(void)
    -     : mStart(0), mLength(0), mOffset(0), mFp(NULL), mFileName(NULL), mMap(NULL), mBuf(NULL)
    - {
    -+    // Register the Asset with the global list here after it is fully constructed and its
    -+    // vtable pointer points to this concrete type. b/31113965
    -+    registerAsset(this);
    - }
    - 
    - /*
    -@@ -369,6 +378,10 @@ _FileAsset::_FileAsset(void)
    - _FileAsset::~_FileAsset(void)
    - {
    -     close();
    -+
    -+    // Unregister the Asset from the global list here before it is destructed and while its vtable
    -+    // pointer still points to this concrete type. b/31113965
    -+    unregisterAsset(this);
    - }
    - 
    - /*
    -@@ -685,6 +698,9 @@ _CompressedAsset::_CompressedAsset(void)
    -     : mStart(0), mCompressedLen(0), mUncompressedLen(0), mOffset(0),
    -       mMap(NULL), mFd(-1), mZipInflater(NULL), mBuf(NULL)
    - {
    -+    // Register the Asset with the global list here after it is fully constructed and its
    -+    // vtable pointer points to this concrete type. b/31113965
    -+    registerAsset(this);
    - }
    - 
    - /*
    -@@ -693,6 +709,10 @@ _CompressedAsset::_CompressedAsset(void)
    - _CompressedAsset::~_CompressedAsset(void)
    - {
    -     close();
    -+
    -+    // Unregister the Asset from the global list here before it is destructed and while its vtable
    -+    // pointer still points to this concrete type. b/31113965
    -+    unregisterAsset(this);
    - }
    - 
    - /*
    -diff --git a/libs/androidfw/AssetManager.cpp b/libs/androidfw/AssetManager.cpp
    -index f50cff4..07044d0 100644
    ---- a/libs/androidfw/AssetManager.cpp
    -+++ b/libs/androidfw/AssetManager.cpp
    -@@ -35,6 +35,9 @@
    - #include <utils/threads.h>
    - #include <utils/Timers.h>
    - #include <utils/Trace.h>
    -+#ifndef _WIN32
    -+#include <sys/file.h>
    -+#endif
    - 
    - #include <assert.h>
    - #include <dirent.h>
    -@@ -767,6 +770,12 @@ void AssetManager::addSystemOverlays(const char* pathOverlaysList,
    -         return;
    -     }
    - 
    -+#ifndef _WIN32
    -+    if (TEMP_FAILURE_RETRY(flock(fileno(fin), LOCK_SH)) != 0) {
    -+        fclose(fin);
    -+        return;
    -+    }
    -+#endif
    -     char buf[1024];
    -     while (fgets(buf, sizeof(buf), fin)) {
    -         // format of each line:
    -@@ -797,6 +806,10 @@ void AssetManager::addSystemOverlays(const char* pathOverlaysList,
    -             const_cast<AssetManager*>(this)->mZipSet.addOverlay(targetPackagePath, oap);
    -         }
    -     }
    -+
    -+#ifndef _WIN32
    -+    TEMP_FAILURE_RETRY(flock(fileno(fin), LOCK_UN));
    -+#endif
    -     fclose(fin);
    - }
    - 
    -@@ -1892,6 +1905,7 @@ ZipFileRO* AssetManager::SharedZip::getZip()
    - 
    - Asset* AssetManager::SharedZip::getResourceTableAsset()
    - {
    -+    AutoMutex _l(gLock);
    -     ALOGV("Getting from SharedZip %p resource asset %p\n", this, mResourceTableAsset);
    -     return mResourceTableAsset;
    - }
    -@@ -1901,10 +1915,10 @@ Asset* AssetManager::SharedZip::setResourceTableAsset(Asset* asset)
    -     {
    -         AutoMutex _l(gLock);
    -         if (mResourceTableAsset == NULL) {
    --            mResourceTableAsset = asset;
    -             // This is not thread safe the first time it is called, so
    -             // do it here with the global lock held.
    -             asset->getBuffer(true);
    -+            mResourceTableAsset = asset;
    -             return asset;
    -         }
    -     }
    -diff --git a/libs/androidfw/tests/Android.mk b/libs/androidfw/tests/Android.mk
    -index 2bc026b..1fe1773 100644
    ---- a/libs/androidfw/tests/Android.mk
    -+++ b/libs/androidfw/tests/Android.mk
    -@@ -22,6 +22,7 @@ LOCAL_PATH:= $(call my-dir)
    - 
    - testFiles := \
    -     AppAsLib_test.cpp \
    -+    Asset_test.cpp \
    -     AttributeFinder_test.cpp \
    -     ByteBucketArray_test.cpp \
    -     Config_test.cpp \
    -diff --git a/libs/androidfw/tests/Asset_test.cpp b/libs/androidfw/tests/Asset_test.cpp
    -new file mode 100644
    -index 0000000..45c8cef
    ---- /dev/null
    -+++ b/libs/androidfw/tests/Asset_test.cpp
    -@@ -0,0 +1,37 @@
    -+/*
    -+ * Copyright (C) 2016 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.
    -+ */
    -+
    -+#include <androidfw/Asset.h>
    -+
    -+#include <gtest/gtest.h>
    -+
    -+using namespace android;
    -+
    -+TEST(AssetTest, FileAssetRegistersItself) {
    -+    const int32_t count = Asset::getGlobalCount();
    -+    Asset* asset = new _FileAsset();
    -+    EXPECT_EQ(count + 1, Asset::getGlobalCount());
    -+    delete asset;
    -+    EXPECT_EQ(count, Asset::getGlobalCount());
    -+}
    -+
    -+TEST(AssetTest, CompressedAssetRegistersItself) {
    -+    const int32_t count = Asset::getGlobalCount();
    -+    Asset* asset = new _CompressedAsset();
    -+    EXPECT_EQ(count + 1, Asset::getGlobalCount());
    -+    delete asset;
    -+    EXPECT_EQ(count, Asset::getGlobalCount());
    -+}
    -diff --git a/libs/hwui/Android.mk b/libs/hwui/Android.mk
    -index 366ef71..0b177b9 100644
    ---- a/libs/hwui/Android.mk
    -+++ b/libs/hwui/Android.mk
    -@@ -3,6 +3,7 @@ include $(CLEAR_VARS)
    - LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
    - 
    - HWUI_NEW_OPS := true
    -+BUGREPORT_FONT_CACHE_USAGE := false
    - 
    - # Enables fine-grained GLES error checking
    - # If set to true, every GLES call is wrapped & error checked
    -@@ -135,13 +136,20 @@ ifeq (true, $(HWUI_NEW_OPS))
    - 
    - endif
    - 
    -+ifeq (true, $(BUGREPORT_FONT_CACHE_USAGE))
    -+    hwui_src_files += \
    -+        font/FontCacheHistoryTracker.cpp
    -+    hwui_cflags += -DBUGREPORT_FONT_CACHE_USAGE
    -+endif
    -+
    -+
    - ifndef HWUI_COMPILE_SYMBOLS
    -     hwui_cflags += -fvisibility=hidden
    - endif
    - 
    - ifdef HWUI_COMPILE_FOR_PERF
    -     # TODO: Non-arm?
    --    hwui_cflags += -fno-omit-frame-pointer -marm -mapcs
    -+    hwui_cflags += -fno-omit-frame-pointer -marm 
    - endif
    - 
    - # This has to be lazy-resolved because it depends on the LOCAL_MODULE_CLASS
    -diff --git a/libs/hwui/Caches.cpp b/libs/hwui/Caches.cpp
    -index 949ad45..a8ced9b 100644
    ---- a/libs/hwui/Caches.cpp
    -+++ b/libs/hwui/Caches.cpp
    -@@ -21,6 +21,9 @@
    - #include "Properties.h"
    - #include "renderstate/RenderState.h"
    - #include "ShadowTessellator.h"
    -+#ifdef BUGREPORT_FONT_CACHE_USAGE
    -+#include "font/FontCacheHistoryTracker.h"
    -+#endif
    - #include "utils/GLUtils.h"
    - 
    - #include <cutils/properties.h>
    -@@ -195,12 +198,7 @@ void Caches::dumpMemoryUsage(String8 &log) {
    -     log.appendFormat("  PatchCache           %8d / %8d\n",
    -             patchCache.getSize(), patchCache.getMaxSize());
    - 
    --    const uint32_t sizeA8 = fontRenderer.getFontRendererSize(GL_ALPHA);
    --    const uint32_t sizeRGBA = fontRenderer.getFontRendererSize(GL_RGBA);
    --    log.appendFormat("  FontRenderer A8    %8d / %8d\n", sizeA8, sizeA8);
    --    log.appendFormat("  FontRenderer RGBA  %8d / %8d\n", sizeRGBA, sizeRGBA);
    --    log.appendFormat("  FontRenderer total %8d / %8d\n", sizeA8 + sizeRGBA,
    --            sizeA8 + sizeRGBA);
    -+    fontRenderer.dumpMemoryUsage(log);
    - 
    -     log.appendFormat("Other:\n");
    -     log.appendFormat("  FboCache             %8d / %8d\n",
    -@@ -213,11 +211,14 @@ void Caches::dumpMemoryUsage(String8 &log) {
    -     total += tessellationCache.getSize();
    -     total += dropShadowCache.getSize();
    -     total += patchCache.getSize();
    --    total += fontRenderer.getFontRendererSize(GL_ALPHA);
    --    total += fontRenderer.getFontRendererSize(GL_RGBA);
    -+    total += fontRenderer.getSize();
    - 
    -     log.appendFormat("Total memory usage:\n");
    -     log.appendFormat("  %d bytes, %.2f MB\n", total, total / 1024.0f / 1024.0f);
    -+
    -+#ifdef BUGREPORT_FONT_CACHE_USAGE
    -+    fontRenderer.getFontRenderer().historyTracker().dump(log);
    -+#endif
    - }
    - 
    - ///////////////////////////////////////////////////////////////////////////////
    -diff --git a/libs/hwui/FontRenderer.cpp b/libs/hwui/FontRenderer.cpp
    -index 276c18d..681cf55 100644
    ---- a/libs/hwui/FontRenderer.cpp
    -+++ b/libs/hwui/FontRenderer.cpp
    -@@ -168,10 +168,17 @@ void FontRenderer::flushAllAndInvalidate() {
    - 
    -     for (uint32_t i = 0; i < mACacheTextures.size(); i++) {
    -         mACacheTextures[i]->init();
    -+
    -+#ifdef BUGREPORT_FONT_CACHE_USAGE
    -+        mHistoryTracker.glyphsCleared(mACacheTextures[i]);
    -+#endif
    -     }
    - 
    -     for (uint32_t i = 0; i < mRGBACacheTextures.size(); i++) {
    -         mRGBACacheTextures[i]->init();
    -+#ifdef BUGREPORT_FONT_CACHE_USAGE
    -+        mHistoryTracker.glyphsCleared(mRGBACacheTextures[i]);
    -+#endif
    -     }
    - 
    -     mDrawn = false;
    -@@ -183,6 +190,9 @@ void FontRenderer::flushLargeCaches(std::vector<CacheTexture*>& cacheTextures) {
    -         CacheTexture* cacheTexture = cacheTextures[i];
    -         if (cacheTexture->getPixelBuffer()) {
    -             cacheTexture->init();
    -+#ifdef BUGREPORT_FONT_CACHE_USAGE
    -+            mHistoryTracker.glyphsCleared(cacheTexture);
    -+#endif
    -             LruCache<Font::FontDescription, Font*>::Iterator it(mActiveFonts);
    -             while (it.next()) {
    -                 it.value()->invalidateTextureCache(cacheTexture);
    -@@ -385,6 +395,10 @@ void FontRenderer::cacheBitmap(const SkGlyph& glyph, CachedGlyphInfo* cachedGlyp
    -     }
    - 
    -     cachedGlyph->mIsValid = true;
    -+
    -+#ifdef BUGREPORT_FONT_CACHE_USAGE
    -+    mHistoryTracker.glyphUploaded(cacheTexture, startX, startY, glyph.fWidth, glyph.fHeight);
    -+#endif
    - }
    - 
    - CacheTexture* FontRenderer::createCacheTexture(int width, int height, GLenum format,
    -@@ -747,19 +761,68 @@ static uint32_t calculateCacheSize(const std::vector<CacheTexture*>& cacheTextur
    -     return size;
    - }
    - 
    --uint32_t FontRenderer::getCacheSize(GLenum format) const {
    -+static uint32_t calculateFreeCacheSize(const std::vector<CacheTexture*>& cacheTextures) {
    -+    uint32_t size = 0;
    -+    for (uint32_t i = 0; i < cacheTextures.size(); i++) {
    -+        CacheTexture* cacheTexture = cacheTextures[i];
    -+        if (cacheTexture && cacheTexture->getPixelBuffer()) {
    -+            size += cacheTexture->calculateFreeMemory();
    -+        }
    -+    }
    -+    return size;
    -+}
    -+
    -+const std::vector<CacheTexture*>& FontRenderer::cacheTexturesForFormat(GLenum format) const {
    -     switch (format) {
    -         case GL_ALPHA: {
    --            return calculateCacheSize(mACacheTextures);
    -+            return mACacheTextures;
    -         }
    -         case GL_RGBA: {
    --            return calculateCacheSize(mRGBACacheTextures);
    -+            return mRGBACacheTextures;
    -         }
    -         default: {
    --            return 0;
    -+            LOG_ALWAYS_FATAL("Unsupported format: %d", format);
    -+            // Impossible to hit this, but the compiler doesn't know that
    -+            return *(new std::vector<CacheTexture*>());
    -         }
    -     }
    - }
    - 
    -+static void dumpTextures(String8& log, const char* tag,
    -+        const std::vector<CacheTexture*>& cacheTextures) {
    -+    for (uint32_t i = 0; i < cacheTextures.size(); i++) {
    -+        CacheTexture* cacheTexture = cacheTextures[i];
    -+        if (cacheTexture && cacheTexture->getPixelBuffer()) {
    -+            uint32_t free = cacheTexture->calculateFreeMemory();
    -+            uint32_t total = cacheTexture->getPixelBuffer()->getSize();
    -+            log.appendFormat("    %-4s texture %d     %8d / %8d\n", tag, i, total - free, total);
    -+        }
    -+    }
    -+}
    -+
    -+void FontRenderer::dumpMemoryUsage(String8& log) const {
    -+    const uint32_t sizeA8 = getCacheSize(GL_ALPHA);
    -+    const uint32_t usedA8 = sizeA8 - getFreeCacheSize(GL_ALPHA);
    -+    const uint32_t sizeRGBA = getCacheSize(GL_RGBA);
    -+    const uint32_t usedRGBA = sizeRGBA - getFreeCacheSize(GL_RGBA);
    -+    log.appendFormat("  FontRenderer A8      %8d / %8d\n", usedA8, sizeA8);
    -+    dumpTextures(log, "A8", cacheTexturesForFormat(GL_ALPHA));
    -+    log.appendFormat("  FontRenderer RGBA    %8d / %8d\n", usedRGBA, sizeRGBA);
    -+    dumpTextures(log, "RGBA", cacheTexturesForFormat(GL_RGBA));
    -+    log.appendFormat("  FontRenderer total   %8d / %8d\n", usedA8 + usedRGBA, sizeA8 + sizeRGBA);
    -+}
    -+
    -+uint32_t FontRenderer::getCacheSize(GLenum format) const {
    -+    return calculateCacheSize(cacheTexturesForFormat(format));
    -+}
    -+
    -+uint32_t FontRenderer::getFreeCacheSize(GLenum format) const {
    -+    return calculateFreeCacheSize(cacheTexturesForFormat(format));
    -+}
    -+
    -+uint32_t FontRenderer::getSize() const {
    -+    return getCacheSize(GL_ALPHA) + getCacheSize(GL_RGBA);
    -+}
    -+
    - }; // namespace uirenderer
    - }; // namespace android
    -diff --git a/libs/hwui/FontRenderer.h b/libs/hwui/FontRenderer.h
    -index e10a81b..504dce8 100644
    ---- a/libs/hwui/FontRenderer.h
    -+++ b/libs/hwui/FontRenderer.h
    -@@ -21,8 +21,12 @@
    - #include "font/CacheTexture.h"
    - #include "font/CachedGlyphInfo.h"
    - #include "font/Font.h"
    -+#ifdef BUGREPORT_FONT_CACHE_USAGE
    -+#include "font/FontCacheHistoryTracker.h"
    -+#endif
    - 
    - #include <utils/LruCache.h>
    -+#include <utils/String8.h>
    - #include <utils/StrongPointer.h>
    - 
    - #include <SkPaint.h>
    -@@ -132,7 +136,12 @@ public:
    -         mLinearFiltering = linearFiltering;
    -     }
    - 
    --    uint32_t getCacheSize(GLenum format) const;
    -+    uint32_t getSize() const;
    -+    void dumpMemoryUsage(String8& log) const;
    -+
    -+#ifdef BUGREPORT_FONT_CACHE_USAGE
    -+    FontCacheHistoryTracker& historyTracker() { return mHistoryTracker; }
    -+#endif
    - 
    - private:
    -     friend class Font;
    -@@ -175,6 +184,10 @@ private:
    -         mUploadTexture = true;
    -     }
    - 
    -+    const std::vector<CacheTexture*>& cacheTexturesForFormat(GLenum format) const;
    -+    uint32_t getCacheSize(GLenum format) const;
    -+    uint32_t getFreeCacheSize(GLenum format) const;
    -+
    -     uint32_t mSmallCacheWidth;
    -     uint32_t mSmallCacheHeight;
    -     uint32_t mLargeCacheWidth;
    -@@ -199,6 +212,10 @@ private:
    - 
    -     bool mLinearFiltering;
    - 
    -+#ifdef BUGREPORT_FONT_CACHE_USAGE
    -+    FontCacheHistoryTracker mHistoryTracker;
    -+#endif
    -+
    - #ifdef ANDROID_ENABLE_RENDERSCRIPT
    -     // RS constructs
    -     RSC::sp<RSC::RS> mRs;
    -diff --git a/libs/hwui/FrameBuilder.cpp b/libs/hwui/FrameBuilder.cpp
    -index 37d9d0e..7524ba0 100644
    ---- a/libs/hwui/FrameBuilder.cpp
    -+++ b/libs/hwui/FrameBuilder.cpp
    -@@ -591,7 +591,7 @@ void FrameBuilder::deferArcOp(const ArcOp& op) {
    - }
    - 
    - static bool hasMergeableClip(const BakedOpState& state) {
    --    return state.computedState.clipState
    -+    return !state.computedState.clipState
    -             || state.computedState.clipState->mode == ClipMode::Rectangle;
    - }
    - 
    -diff --git a/libs/hwui/GammaFontRenderer.h b/libs/hwui/GammaFontRenderer.h
    -index 5813e7f..bd27a1a 100644
    ---- a/libs/hwui/GammaFontRenderer.h
    -+++ b/libs/hwui/GammaFontRenderer.h
    -@@ -22,6 +22,8 @@
    - 
    - #include <SkPaint.h>
    - 
    -+#include <utils/String8.h>
    -+
    - namespace android {
    - namespace uirenderer {
    - 
    -@@ -46,8 +48,16 @@ public:
    -         return *mRenderer;
    -     }
    - 
    --    uint32_t getFontRendererSize(GLenum format) const {
    --        return mRenderer ? mRenderer->getCacheSize(format) : 0;
    -+    void dumpMemoryUsage(String8& log) const {
    -+        if (mRenderer) {
    -+            mRenderer->dumpMemoryUsage(log);
    -+        } else {
    -+            log.appendFormat("FontRenderer doesn't exist.\n");
    -+        }
    -+    }
    -+
    -+    uint32_t getSize() const {
    -+        return mRenderer ? mRenderer->getSize() : 0;
    -     }
    - 
    -     void endPrecaching();
    -diff --git a/libs/hwui/PropertyValuesAnimatorSet.cpp b/libs/hwui/PropertyValuesAnimatorSet.cpp
    -index 38fb70a..e3258e3 100644
    ---- a/libs/hwui/PropertyValuesAnimatorSet.cpp
    -+++ b/libs/hwui/PropertyValuesAnimatorSet.cpp
    -@@ -46,8 +46,17 @@ PropertyValuesAnimatorSet::PropertyValuesAnimatorSet()
    - 
    - void PropertyValuesAnimatorSet::onFinished(BaseRenderNodeAnimator* animator) {
    -     if (mOneShotListener.get()) {
    --        mOneShotListener->onAnimationFinished(animator);
    -+        sp<AnimationListener> listener = std::move(mOneShotListener);
    -+        // Set the listener to nullptr before the onAnimationFinished callback, rather than after,
    -+        // for two reasons:
    -+        // 1) We need to prevent changes to mOneShotListener during the onAnimationFinished
    -+        // callback (specifically in AnimationListenerBridge::onAnimationFinished(...) from
    -+        // triggering dtor of the bridge and potentially unsafely re-entering
    -+        // AnimationListenerBridge::onAnimationFinished(...).
    -+        // 2) It's possible that there are changes to the listener during the callback, therefore
    -+        // we need to reset the listener before the callback rather than afterwards.
    -         mOneShotListener = nullptr;
    -+        listener->onAnimationFinished(animator);
    -     }
    - }
    - 
    -diff --git a/libs/hwui/Readback.cpp b/libs/hwui/Readback.cpp
    -index 55f823d..0ab247d 100644
    ---- a/libs/hwui/Readback.cpp
    -+++ b/libs/hwui/Readback.cpp
    -@@ -136,7 +136,7 @@ CopyResult Readback::copySurfaceInto(renderthread::RenderThread& renderThread,
    -             EGL_NATIVE_BUFFER_ANDROID, clientBuffer, attrs);
    - 
    -     if (sourceImage == EGL_NO_IMAGE_KHR) {
    --        ALOGW("Error creating image (%#x)", eglGetError());
    -+        ALOGW("eglCreateImageKHR failed (%#x)", eglGetError());
    -         return CopyResult::UnknownError;
    -     }
    -     GLuint sourceTexId;
    -@@ -147,7 +147,8 @@ CopyResult Readback::copySurfaceInto(renderthread::RenderThread& renderThread,
    - 
    -     GLenum status = GL_NO_ERROR;
    -     while ((status = glGetError()) != GL_NO_ERROR) {
    --        ALOGW("Error creating image (%#x)", status);
    -+        ALOGW("glEGLImageTargetTexture2DOES failed (%#x)", status);
    -+        eglDestroyImageKHR(display, sourceImage);
    -         return CopyResult::UnknownError;
    -     }
    - 
    -@@ -183,6 +184,13 @@ CopyResult Readback::copySurfaceInto(renderthread::RenderThread& renderThread,
    -     caches.textureState().deleteTexture(texture);
    -     renderState.deleteFramebuffer(fbo);
    - 
    -+    sourceTexture.deleteTexture();
    -+    // All we're flushing & finishing is the deletion of the texture since
    -+    // copyTextureInto already did a major flush & finish as an implicit
    -+    // part of glReadPixels, so this shouldn't pose any major stalls.
    -+    glFinish();
    -+    eglDestroyImageKHR(display, sourceImage);
    -+
    -     GL_CHECKPOINT(MODERATE);
    - 
    -     return CopyResult::Success;
    -diff --git a/libs/hwui/SkiaCanvas.cpp b/libs/hwui/SkiaCanvas.cpp
    -index ce67554..c7289fc 100644
    ---- a/libs/hwui/SkiaCanvas.cpp
    -+++ b/libs/hwui/SkiaCanvas.cpp
    -@@ -329,9 +329,10 @@ void SkiaCanvas::restoreToCount(int restoreCount) {
    - static inline SkCanvas::SaveLayerFlags layerFlags(SaveFlags::Flags flags) {
    -     SkCanvas::SaveLayerFlags layerFlags = 0;
    - 
    --    if (!(flags & SaveFlags::HasAlphaLayer)) {
    --        layerFlags |= SkCanvas::kIsOpaque_SaveLayerFlag;
    --    }
    -+    // We intentionally ignore the SaveFlags::HasAlphaLayer and
    -+    // SkCanvas::kIsOpaque_SaveLayerFlag flags because HWUI ignores it
    -+    // and our Android client may use it incorrectly.
    -+    // In Skia, this flag is purely for performance optimization.
    - 
    -     if (!(flags & SaveFlags::ClipToLayer)) {
    -         layerFlags |= SkCanvas::kDontClipToLayer_Legacy_SaveLayerFlag;
    -diff --git a/libs/hwui/Snapshot.cpp b/libs/hwui/Snapshot.cpp
    -index 2c9c9d9..7c187fb 100644
    ---- a/libs/hwui/Snapshot.cpp
    -+++ b/libs/hwui/Snapshot.cpp
    -@@ -38,6 +38,7 @@ Snapshot::Snapshot()
    -         , mClipArea(&mClipAreaRoot) {
    -     transform = &mTransformRoot;
    -     region = nullptr;
    -+    mRelativeLightCenter.x = mRelativeLightCenter.y = mRelativeLightCenter.z = 0;
    - }
    - 
    - /**
    -diff --git a/libs/hwui/SpotShadow.cpp b/libs/hwui/SpotShadow.cpp
    -index 760d814..cc96a13 100644
    ---- a/libs/hwui/SpotShadow.cpp
    -+++ b/libs/hwui/SpotShadow.cpp
    -@@ -942,9 +942,13 @@ void SpotShadow::generateTriangleStrip(bool isCasterOpaque, float shadowStrength
    -         AlphaVertex::set(&shadowVertices[vertexBufferIndex++], newPenumbra[i].x,
    -                 newPenumbra[i].y, PENUMBRA_ALPHA);
    -     }
    -+    // Since the umbra can be a faked one when the occluder is too high, the umbra should be lighter
    -+    // in this case.
    -+    float scaledUmbraAlpha = UMBRA_ALPHA * shadowStrengthScale;
    -+
    -     for (int i = 0; i < umbraLength; i++) {
    -         AlphaVertex::set(&shadowVertices[vertexBufferIndex++], umbra[i].x, umbra[i].y,
    --                UMBRA_ALPHA);
    -+                scaledUmbraAlpha);
    -     }
    - 
    -     for (int i = 0; i < verticesPairIndex; i++) {
    -@@ -984,14 +988,14 @@ void SpotShadow::generateTriangleStrip(bool isCasterOpaque, float shadowStrength
    -             indexBuffer[indexBufferIndex++] = newPenumbraLength + i;
    -             indexBuffer[indexBufferIndex++] = vertexBufferIndex;
    -             AlphaVertex::set(&shadowVertices[vertexBufferIndex++],
    --                    closerVertex.x, closerVertex.y, UMBRA_ALPHA);
    -+                    closerVertex.x, closerVertex.y, scaledUmbraAlpha);
    -         }
    -     } else {
    -         // If there is no occluded umbra at all, then draw the triangle fan
    -         // starting from the centroid to all umbra vertices.
    -         int lastCentroidIndex = vertexBufferIndex;
    -         AlphaVertex::set(&shadowVertices[vertexBufferIndex++], centroid.x,
    --                centroid.y, UMBRA_ALPHA);
    -+                centroid.y, scaledUmbraAlpha);
    -         for (int i = 0; i < umbraLength; i++) {
    -             indexBuffer[indexBufferIndex++] = newPenumbraLength + i;
    -             indexBuffer[indexBufferIndex++] = lastCentroidIndex;
    -diff --git a/libs/hwui/VectorDrawable.cpp b/libs/hwui/VectorDrawable.cpp
    -index 2b79941..aeee661 100644
    ---- a/libs/hwui/VectorDrawable.cpp
    -+++ b/libs/hwui/VectorDrawable.cpp
    -@@ -202,7 +202,9 @@ void FullPath::drawPath(SkCanvas* outCanvas, SkPath& renderPath, float strokeSca
    -     if (properties.getFillGradient() != nullptr) {
    -         paint.setColor(applyAlpha(SK_ColorBLACK, properties.getFillAlpha()));
    -         SkShader* newShader = properties.getFillGradient()->newWithLocalMatrix(matrix);
    --        paint.setShader(newShader);
    -+        // newWithLocalMatrix(...) creates a new SkShader and returns a bare pointer. We need to
    -+        // remove the extra ref so that the ref count is correctly managed.
    -+        paint.setShader(newShader)->unref();
    -         needsFill = true;
    -     } else if (properties.getFillColor() != SK_ColorTRANSPARENT) {
    -         paint.setColor(applyAlpha(properties.getFillColor(), properties.getFillAlpha()));
    -@@ -222,7 +224,9 @@ void FullPath::drawPath(SkCanvas* outCanvas, SkPath& renderPath, float strokeSca
    -     if (properties.getStrokeGradient() != nullptr) {
    -         paint.setColor(applyAlpha(SK_ColorBLACK, properties.getStrokeAlpha()));
    -         SkShader* newShader = properties.getStrokeGradient()->newWithLocalMatrix(matrix);
    --        paint.setShader(newShader);
    -+        // newWithLocalMatrix(...) creates a new SkShader and returns a bare pointer. We need to
    -+        // remove the extra ref so that the ref count is correctly managed.
    -+        paint.setShader(newShader)->unref();
    -         needsStroke = true;
    -     } else if (properties.getStrokeColor() != SK_ColorTRANSPARENT) {
    -         paint.setColor(applyAlpha(properties.getStrokeColor(), properties.getStrokeAlpha()));
    -diff --git a/libs/hwui/font/CacheTexture.cpp b/libs/hwui/font/CacheTexture.cpp
    -index 8ba4761..4b13814 100644
    ---- a/libs/hwui/font/CacheTexture.cpp
    -+++ b/libs/hwui/font/CacheTexture.cpp
    -@@ -324,5 +324,17 @@ bool CacheTexture::fitBitmap(const SkGlyph& glyph, uint32_t* retOriginX, uint32_
    -     return false;
    - }
    - 
    -+uint32_t CacheTexture::calculateFreeMemory() const {
    -+    CacheBlock* cacheBlock = mCacheBlocks;
    -+    uint32_t free = 0;
    -+    // currently only two formats are supported: GL_ALPHA or GL_RGBA;
    -+    uint32_t bpp = mFormat == GL_RGBA ? 4 : 1;
    -+    while (cacheBlock) {
    -+        free += bpp * cacheBlock->mWidth * cacheBlock->mHeight;
    -+        cacheBlock = cacheBlock->mNext;
    -+    }
    -+    return free;
    -+}
    -+
    - }; // namespace uirenderer
    - }; // namespace android
    -diff --git a/libs/hwui/font/CacheTexture.h b/libs/hwui/font/CacheTexture.h
    -index 4dfb41d..6750a8a 100644
    ---- a/libs/hwui/font/CacheTexture.h
    -+++ b/libs/hwui/font/CacheTexture.h
    -@@ -178,6 +178,8 @@ public:
    -         return mCurrentQuad == mMaxQuadCount;
    -     }
    - 
    -+    uint32_t calculateFreeMemory() const;
    -+
    - private:
    -     void setDirty(bool dirty);
    - 
    -diff --git a/libs/hwui/font/Font.cpp b/libs/hwui/font/Font.cpp
    -index 8e04c87..a95454a 100644
    ---- a/libs/hwui/font/Font.cpp
    -+++ b/libs/hwui/font/Font.cpp
    -@@ -408,9 +408,15 @@ void Font::render(const SkPaint* paint, const glyph_t* glyphs,
    -         if (cachedGlyph->mIsValid && cachedGlyph->mCacheTexture) {
    -             int penX = x + (int) roundf(positions[(glyphsCount << 1)]);
    -             int penY = y + (int) roundf(positions[(glyphsCount << 1) + 1]);
    --
    -+#ifdef BUGREPORT_FONT_CACHE_USAGE
    -+            mState->historyTracker().glyphRendered(cachedGlyph, penX, penY);
    -+#endif
    -             (*this.*render)(cachedGlyph, penX, penY,
    -                     bitmap, bitmapW, bitmapH, bounds, positions);
    -+        } else {
    -+#ifdef BUGREPORT_FONT_CACHE_USAGE
    -+            mState->historyTracker().glyphRendered(cachedGlyph, -1, -1);
    -+#endif
    -         }
    - 
    -         glyphsCount++;
    -diff --git a/libs/hwui/font/FontCacheHistoryTracker.cpp b/libs/hwui/font/FontCacheHistoryTracker.cpp
    -new file mode 100644
    -index 0000000..a2bfb27
    ---- /dev/null
    -+++ b/libs/hwui/font/FontCacheHistoryTracker.cpp
    -@@ -0,0 +1,100 @@
    -+/*
    -+ * Copyright (C) 2016 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.
    -+ */
    -+
    -+#include "FontCacheHistoryTracker.h"
    -+
    -+#include "CachedGlyphInfo.h"
    -+#include "CacheTexture.h"
    -+
    -+namespace android {
    -+namespace uirenderer {
    -+
    -+void FontCacheHistoryTracker::dumpCachedGlyph(String8& log, const CachedGlyph& glyph) {
    -+    log.appendFormat("glyph (texture %p, position: (%d, %d), size: %dx%d, gen: %d)", glyph.texture,
    -+            glyph.startX, glyph.startY, glyph.bitmapW, glyph.bitmapH, glyph.generation);
    -+}
    -+
    -+void FontCacheHistoryTracker::dumpRenderEntry(String8& log, const RenderEntry& entry) {
    -+    if (entry.penX == -1 && entry.penY == -1) {
    -+        log.appendFormat("      glyph skipped in gen: %d\n", entry.glyph.generation);
    -+    } else {
    -+        log.appendFormat("      rendered ");
    -+        dumpCachedGlyph(log, entry.glyph);
    -+        log.appendFormat(" at (%d, %d)\n", entry.penX, entry.penY);
    -+    }
    -+}
    -+
    -+void FontCacheHistoryTracker::dumpUploadEntry(String8& log, const CachedGlyph& glyph) {
    -+    if (glyph.bitmapW == 0 && glyph.bitmapH == 0) {
    -+        log.appendFormat("      cleared cachetexture %p in gen %d\n", glyph.texture,
    -+                glyph.generation);
    -+    } else {
    -+        log.appendFormat("      uploaded ");
    -+        dumpCachedGlyph(log, glyph);
    -+        log.appendFormat("\n");
    -+    }
    -+}
    -+
    -+void FontCacheHistoryTracker::dump(String8& log) const {
    -+    log.appendFormat("FontCacheHistory: \n");
    -+    log.appendFormat("  Upload history: \n");
    -+    for (size_t i = 0; i < mUploadHistory.size(); i++) {
    -+        dumpUploadEntry(log, mUploadHistory[i]);
    -+    }
    -+    log.appendFormat("  Render history: \n");
    -+    for (size_t i = 0; i < mRenderHistory.size(); i++) {
    -+        dumpRenderEntry(log, mRenderHistory[i]);
    -+    }
    -+}
    -+
    -+void FontCacheHistoryTracker::glyphRendered(CachedGlyphInfo* glyphInfo, int penX, int penY) {
    -+    RenderEntry& entry = mRenderHistory.next();
    -+    entry.glyph.generation = generation;
    -+    entry.glyph.texture = glyphInfo->mCacheTexture;
    -+    entry.glyph.startX = glyphInfo->mStartX;
    -+    entry.glyph.startY = glyphInfo->mStartY;
    -+    entry.glyph.bitmapW = glyphInfo->mBitmapWidth;
    -+    entry.glyph.bitmapH = glyphInfo->mBitmapHeight;
    -+    entry.penX = penX;
    -+    entry.penY = penY;
    -+}
    -+
    -+void FontCacheHistoryTracker::glyphUploaded(CacheTexture* texture, uint32_t x, uint32_t y,
    -+        uint16_t glyphW, uint16_t glyphH) {
    -+    CachedGlyph& glyph = mUploadHistory.next();
    -+    glyph.generation = generation;
    -+    glyph.texture = texture;
    -+    glyph.startX = x;
    -+    glyph.startY = y;
    -+    glyph.bitmapW = glyphW;
    -+    glyph.bitmapH = glyphH;
    -+}
    -+
    -+void FontCacheHistoryTracker::glyphsCleared(CacheTexture* texture) {
    -+    CachedGlyph& glyph = mUploadHistory.next();
    -+    glyph.generation = generation;
    -+    glyph.texture = texture;
    -+    glyph.startX = 0;
    -+    glyph.startY = 0;
    -+    glyph.bitmapW = 0;
    -+    glyph.bitmapH = 0;
    -+}
    -+
    -+void FontCacheHistoryTracker::frameCompleted() {
    -+    generation++;
    -+}
    -+}; // namespace uirenderer
    -+}; // namespace android
    -diff --git a/libs/hwui/font/FontCacheHistoryTracker.h b/libs/hwui/font/FontCacheHistoryTracker.h
    -new file mode 100644
    -index 0000000..f1d9b9f
    ---- /dev/null
    -+++ b/libs/hwui/font/FontCacheHistoryTracker.h
    -@@ -0,0 +1,64 @@
    -+/*
    -+ * Copyright (C) 2016 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.
    -+ */
    -+
    -+#pragma once
    -+#include "../utils/RingBuffer.h"
    -+
    -+#include <utils/String8.h>
    -+
    -+namespace android {
    -+namespace uirenderer {
    -+
    -+class CacheTexture;
    -+struct CachedGlyphInfo;
    -+
    -+// Tracks glyph uploads and recent rendered/skipped glyphs, so it can give an idea
    -+// what a missing character is: skipped glyph, wrong coordinates in cache texture etc.
    -+class FontCacheHistoryTracker {
    -+public:
    -+    void glyphRendered(CachedGlyphInfo*, int penX, int penY);
    -+    void glyphUploaded(CacheTexture*, uint32_t x, uint32_t y, uint16_t glyphW, uint16_t glyphH);
    -+    void glyphsCleared(CacheTexture*);
    -+    void frameCompleted();
    -+
    -+    void dump(String8& log) const;
    -+private:
    -+    struct CachedGlyph {
    -+        void* texture;
    -+        uint16_t generation;
    -+        uint16_t startX;
    -+        uint16_t startY;
    -+        uint16_t bitmapW;
    -+        uint16_t bitmapH;
    -+    };
    -+
    -+    struct RenderEntry {
    -+        CachedGlyph glyph;
    -+        int penX;
    -+        int penY;
    -+    };
    -+
    -+    static void dumpCachedGlyph(String8& log, const CachedGlyph& glyph);
    -+    static void dumpRenderEntry(String8& log, const RenderEntry& entry);
    -+    static void dumpUploadEntry(String8& log, const CachedGlyph& glyph);
    -+
    -+    RingBuffer<RenderEntry, 300> mRenderHistory;
    -+    RingBuffer<CachedGlyph, 120> mUploadHistory;
    -+    uint16_t generation = 0;
    -+};
    -+
    -+}; // namespace uirenderer
    -+}; // namespace android
    -\ No newline at end of file
    -diff --git a/libs/hwui/renderthread/CanvasContext.cpp b/libs/hwui/renderthread/CanvasContext.cpp
    -index dcaec42..975ac83 100644
    ---- a/libs/hwui/renderthread/CanvasContext.cpp
    -+++ b/libs/hwui/renderthread/CanvasContext.cpp
    -@@ -608,6 +608,10 @@ void CanvasContext::draw() {
    -     }
    - 
    -     GpuMemoryTracker::onFrameCompleted();
    -+#ifdef BUGREPORT_FONT_CACHE_USAGE
    -+    caches.fontRenderer.getFontRenderer().historyTracker().frameCompleted();
    -+#endif
    -+
    - }
    - 
    - // Called by choreographer to do an RT-driven animation
    -@@ -633,6 +637,9 @@ void CanvasContext::prepareAndDraw(RenderNode* node) {
    -     prepareTree(info, frameInfo, systemTime(CLOCK_MONOTONIC), node);
    -     if (info.out.canDrawThisFrame) {
    -         draw();
    -+    } else {
    -+        // wait on fences so tasks don't overlap next frame
    -+        waitOnFences();
    -     }
    - }
    - 
    -diff --git a/libs/hwui/renderthread/CanvasContext.h b/libs/hwui/renderthread/CanvasContext.h
    -index 3eef29b..e182175 100644
    ---- a/libs/hwui/renderthread/CanvasContext.h
    -+++ b/libs/hwui/renderthread/CanvasContext.h
    -@@ -168,6 +168,8 @@ public:
    - 
    -     ANDROID_API int64_t getFrameNumber();
    - 
    -+    void waitOnFences();
    -+
    - private:
    -     friend class RegisterFrameCallbackTask;
    -     // TODO: Replace with something better for layer & other GL object
    -@@ -178,8 +180,6 @@ private:
    - 
    -     void freePrefetchedLayers(TreeObserver* observer);
    - 
    --    void waitOnFences();
    --
    -     bool isSwapChainStuffed();
    - 
    -     EGLint mLastFrameWidth = 0;
    -diff --git a/libs/hwui/renderthread/DrawFrameTask.cpp b/libs/hwui/renderthread/DrawFrameTask.cpp
    -index c9c07b3..e3b6dc6 100644
    ---- a/libs/hwui/renderthread/DrawFrameTask.cpp
    -+++ b/libs/hwui/renderthread/DrawFrameTask.cpp
    -@@ -104,6 +104,9 @@ void DrawFrameTask::run() {
    - 
    -     if (CC_LIKELY(canDrawThisFrame)) {
    -         context->draw();
    -+    } else {
    -+        // wait on fences so tasks don't overlap next frame
    -+        context->waitOnFences();
    -     }
    - 
    -     if (!canUnblockUiThread) {
    -diff --git a/libs/hwui/tests/unit/FrameBuilderTests.cpp b/libs/hwui/tests/unit/FrameBuilderTests.cpp
    -index 53dbede..e2dc3a0 100644
    ---- a/libs/hwui/tests/unit/FrameBuilderTests.cpp
    -+++ b/libs/hwui/tests/unit/FrameBuilderTests.cpp
    -@@ -477,6 +477,35 @@ RENDERTHREAD_TEST(FrameBuilder, clippedMerging) {
    -     EXPECT_EQ(4, renderer.getIndex());
    - }
    - 
    -+RENDERTHREAD_TEST(FrameBuilder, regionClipStopsMerge) {
    -+    class RegionClipStopsMergeTestRenderer : public TestRendererBase {
    -+    public:
    -+        void onTextOp(const TextOp& op, const BakedOpState& state) override { mIndex++; }
    -+    };
    -+    auto node = TestUtils::createNode(0, 0, 400, 400,
    -+            [](RenderProperties& props, TestCanvas& canvas) {
    -+        SkPath path;
    -+        path.addCircle(200, 200, 200, SkPath::kCW_Direction);
    -+        canvas.save(SaveFlags::MatrixClip);
    -+        canvas.clipPath(&path, SkRegion::kIntersect_Op);
    -+        SkPaint paint;
    -+        paint.setTextEncoding(SkPaint::kGlyphID_TextEncoding);
    -+        paint.setAntiAlias(true);
    -+        paint.setTextSize(50);
    -+        TestUtils::drawUtf8ToCanvas(&canvas, "Test string1", paint, 100, 100);
    -+        TestUtils::drawUtf8ToCanvas(&canvas, "Test string1", paint, 100, 200);
    -+        canvas.restore();
    -+    });
    -+
    -+    FrameBuilder frameBuilder(SkRect::MakeWH(400, 400), 400, 400,
    -+            sLightGeometry, Caches::getInstance());
    -+    frameBuilder.deferRenderNode(*TestUtils::getSyncedNode(node));
    -+
    -+    RegionClipStopsMergeTestRenderer renderer;
    -+    frameBuilder.replayBakedOps<TestDispatcher>(renderer);
    -+    EXPECT_EQ(2, renderer.getIndex());
    -+}
    -+
    - RENDERTHREAD_TEST(FrameBuilder, textMerging) {
    -     class TextMergingTestRenderer : public TestRendererBase {
    -     public:
    -diff --git a/libs/hwui/tests/unit/VectorDrawableTests.cpp b/libs/hwui/tests/unit/VectorDrawableTests.cpp
    -index 83b485f..8e0d3ee 100644
    ---- a/libs/hwui/tests/unit/VectorDrawableTests.cpp
    -+++ b/libs/hwui/tests/unit/VectorDrawableTests.cpp
    -@@ -426,5 +426,49 @@ TEST(VectorDrawable, groupProperties) {
    -     EXPECT_EQ(1.0f, properties->getPivotY());
    - 
    - }
    -+
    -+static SkShader* createShader(bool* isDestroyed) {
    -+    class TestShader : public SkShader {
    -+    public:
    -+        TestShader(bool* isDestroyed) : SkShader(), mDestroyed(isDestroyed) {
    -+        }
    -+        ~TestShader() {
    -+            *mDestroyed = true;
    -+        }
    -+
    -+        Factory getFactory() const override { return nullptr; }
    -+    private:
    -+        bool* mDestroyed;
    -+    };
    -+    return new TestShader(isDestroyed);
    -+}
    -+
    -+TEST(VectorDrawable, drawPathWithoutIncrementingShaderRefCount) {
    -+    VectorDrawable::FullPath path("m1 1", 4);
    -+    SkBitmap bitmap;
    -+    SkImageInfo info = SkImageInfo::Make(5, 5, kN32_SkColorType, kPremul_SkAlphaType);
    -+    bitmap.setInfo(info);
    -+    bitmap.allocPixels(info);
    -+    SkCanvas canvas(bitmap);
    -+
    -+    bool shaderIsDestroyed = false;
    -+
    -+    // Initial ref count is 1
    -+    SkShader* shader = createShader(&shaderIsDestroyed);
    -+
    -+    // Setting the fill gradient increments the ref count of the shader by 1
    -+    path.mutateStagingProperties()->setFillGradient(shader);
    -+    path.draw(&canvas, SkMatrix::I(), 1.0f, 1.0f, true);
    -+    // Resetting the fill gradient decrements the ref count of the shader by 1
    -+    path.mutateStagingProperties()->setFillGradient(nullptr);
    -+
    -+    // Expect ref count to be 1 again, i.e. nothing else to have a ref to the shader now. Unref()
    -+    // again should bring the ref count to zero and consequently trigger detor.
    -+    shader->unref();
    -+
    -+    // Verify that detor is called.
    -+    EXPECT_TRUE(shaderIsDestroyed);
    -+}
    -+
    - }; // namespace uirenderer
    - }; // namespace android
    -diff --git a/libs/input/PointerController.cpp b/libs/input/PointerController.cpp
    -index 27193b7..abef66f 100644
    ---- a/libs/input/PointerController.cpp
    -+++ b/libs/input/PointerController.cpp
    -@@ -36,6 +36,29 @@
    - 
    - namespace android {
    - 
    -+// --- WeakLooperCallback ---
    -+
    -+class WeakLooperCallback: public LooperCallback {
    -+protected:
    -+    virtual ~WeakLooperCallback() { }
    -+
    -+public:
    -+    WeakLooperCallback(const wp<LooperCallback>& callback) :
    -+        mCallback(callback) {
    -+    }
    -+
    -+    virtual int handleEvent(int fd, int events, void* data) {
    -+        sp<LooperCallback> callback = mCallback.promote();
    -+        if (callback != NULL) {
    -+            return callback->handleEvent(fd, events, data);
    -+        }
    -+        return 0; // the client is gone, remove the callback
    -+    }
    -+
    -+private:
    -+    wp<LooperCallback> mCallback;
    -+};
    -+
    - // --- PointerController ---
    - 
    - // Time to wait before starting the fade when the pointer is inactive.
    -@@ -57,10 +80,11 @@ PointerController::PointerController(const sp<PointerControllerPolicyInterface>&
    -         const sp<Looper>& looper, const sp<SpriteController>& spriteController) :
    -         mPolicy(policy), mLooper(looper), mSpriteController(spriteController) {
    -     mHandler = new WeakMessageHandler(this);
    -+    mCallback = new WeakLooperCallback(this);
    - 
    -     if (mDisplayEventReceiver.initCheck() == NO_ERROR) {
    -         mLooper->addFd(mDisplayEventReceiver.getFd(), Looper::POLL_CALLBACK,
    --                       Looper::EVENT_INPUT, this, nullptr);
    -+                       Looper::EVENT_INPUT, mCallback, nullptr);
    -     } else {
    -         ALOGE("Failed to initialize DisplayEventReceiver.");
    -     }
    -diff --git a/libs/input/PointerController.h b/libs/input/PointerController.h
    -index 99292d7..4794f3d 100644
    ---- a/libs/input/PointerController.h
    -+++ b/libs/input/PointerController.h
    -@@ -144,6 +144,7 @@ private:
    -     sp<Looper> mLooper;
    -     sp<SpriteController> mSpriteController;
    -     sp<WeakMessageHandler> mHandler;
    -+    sp<LooperCallback> mCallback;
    - 
    -     DisplayEventReceiver mDisplayEventReceiver;
    - 
    -diff --git a/location/java/android/location/Address.java b/location/java/android/location/Address.java
    -index b152f48..335ad5e 100644
    ---- a/location/java/android/location/Address.java
    -+++ b/location/java/android/location/Address.java
    -@@ -28,7 +28,7 @@ import android.os.Parcelable;
    - /**
    -  * A class representing an Address, i.e, a set of Strings describing a location.
    -  *
    -- * The addres format is a simplified version of xAL (eXtensible Address Language)
    -+ * The address format is a simplified version of xAL (eXtensible Address Language)
    -  * http://www.oasis-open.org/committees/ciq/ciq.html#6
    -  */
    - public class Address implements Parcelable {
    -diff --git a/location/java/android/location/LocationManager.java b/location/java/android/location/LocationManager.java
    -index 2b3ed87..da0e515 100644
    ---- a/location/java/android/location/LocationManager.java
    -+++ b/location/java/android/location/LocationManager.java
    -@@ -1465,7 +1465,7 @@ public class LocationManager {
    -             mGpsNmeaListener = null;
    -             mNmeaBuffer = null;
    -             mOldGnssCallback = null;
    --            mGnssCallback = new GnssStatus.Callback() {
    -+            mGnssCallback = mGpsListener != null ? new GnssStatus.Callback() {
    -                 @Override
    -                 public void onStarted() {
    -                     mGpsListener.onGpsStatusChanged(GpsStatus.GPS_EVENT_STARTED);
    -@@ -1485,7 +1485,7 @@ public class LocationManager {
    -                 public void onSatelliteStatusChanged(GnssStatus status) {
    -                     mGpsListener.onGpsStatusChanged(GpsStatus.GPS_EVENT_SATELLITE_STATUS);
    -                 }
    --            };
    -+            } : null;
    -             mOldGnssNmeaListener = null;
    -             mGnssNmeaListener = null;
    -         }
    -@@ -1502,12 +1502,12 @@ public class LocationManager {
    -             mOldGnssCallback = null;
    -             mGnssCallback = null;
    -             mOldGnssNmeaListener = null;
    --            mGnssNmeaListener = new OnNmeaMessageListener() {
    -+            mGnssNmeaListener = mGpsNmeaListener != null ? new OnNmeaMessageListener() {
    -                 @Override
    -                 public void onNmeaMessage(String nmea, long timestamp) {
    -                     mGpsNmeaListener.onNmeaReceived(timestamp, nmea);
    -                 }
    --            };
    -+            } : null;
    -         }
    - 
    -         GnssStatusListenerTransport(GnssStatusCallback callback) {
    -@@ -1516,7 +1516,7 @@ public class LocationManager {
    - 
    -         GnssStatusListenerTransport(GnssStatusCallback callback, Handler handler) {
    -             mOldGnssCallback = callback;
    --            mGnssCallback = new GnssStatus.Callback() {
    -+            mGnssCallback = mOldGnssCallback != null ? new GnssStatus.Callback() {
    -                 @Override
    -                 public void onStarted() {
    -                     mOldGnssCallback.onStarted();
    -@@ -1536,7 +1536,7 @@ public class LocationManager {
    -                 public void onSatelliteStatusChanged(GnssStatus status) {
    -                     mOldGnssCallback.onSatelliteStatusChanged(status);
    -                 }
    --            };
    -+            } : null;
    -             mGnssHandler = new GnssHandler(handler);
    -             mOldGnssNmeaListener = null;
    -             mGnssNmeaListener = null;
    -@@ -1569,12 +1569,12 @@ public class LocationManager {
    -             mOldGnssCallback = null;
    -             mGnssHandler = new GnssHandler(handler);
    -             mOldGnssNmeaListener = listener;
    --            mGnssNmeaListener = new OnNmeaMessageListener() {
    -+            mGnssNmeaListener = mOldGnssNmeaListener != null ? new OnNmeaMessageListener() {
    -                 @Override
    -                 public void onNmeaMessage(String message, long timestamp) {
    -                     mOldGnssNmeaListener.onNmeaReceived(timestamp, message);
    -                 }
    --            };
    -+            } : null;
    -             mGpsListener = null;
    -             mGpsNmeaListener = null;
    -             mNmeaBuffer = new ArrayList<Nmea>();
    -@@ -1597,7 +1597,7 @@ public class LocationManager {
    - 
    -         @Override
    -         public void onGnssStarted() {
    --            if (mGpsListener != null) {
    -+            if (mGnssCallback != null) {
    -                 Message msg = Message.obtain();
    -                 msg.what = GpsStatus.GPS_EVENT_STARTED;
    -                 mGnssHandler.sendMessage(msg);
    -@@ -1606,7 +1606,7 @@ public class LocationManager {
    - 
    -         @Override
    -         public void onGnssStopped() {
    --            if (mGpsListener != null) {
    -+            if (mGnssCallback != null) {
    -                 Message msg = Message.obtain();
    -                 msg.what = GpsStatus.GPS_EVENT_STOPPED;
    -                 mGnssHandler.sendMessage(msg);
    -@@ -1615,7 +1615,7 @@ public class LocationManager {
    - 
    -         @Override
    -         public void onFirstFix(int ttff) {
    --            if (mGpsListener != null) {
    -+            if (mGnssCallback != null) {
    -                 mTimeToFirstFix = ttff;
    -                 Message msg = Message.obtain();
    -                 msg.what = GpsStatus.GPS_EVENT_FIRST_FIX;
    -diff --git a/media/java/android/media/AudioAttributes.java b/media/java/android/media/AudioAttributes.java
    -index 5286f8f..89709ee 100644
    ---- a/media/java/android/media/AudioAttributes.java
    -+++ b/media/java/android/media/AudioAttributes.java
    -@@ -24,6 +24,7 @@ import android.os.Parcel;
    - import android.os.Parcelable;
    - import android.text.TextUtils;
    - import android.util.Log;
    -+import android.util.SparseIntArray;
    - 
    - import java.lang.annotation.Retention;
    - import java.lang.annotation.RetentionPolicy;
    -@@ -170,6 +171,66 @@ public final class AudioAttributes implements Parcelable {
    -     public final static int USAGE_VIRTUAL_SOURCE = 15;
    - 
    -     /**
    -+     * IMPORTANT: when adding new usage types, add them to SDK_USAGES and update SUPPRESSIBLE_USAGES
    -+     *            if applicable.
    -+     */
    -+
    -+    /**
    -+     * @hide
    -+     * Denotes a usage for notifications that do not expect immediate intervention from the user,
    -+     * will be muted when the Zen mode disables notifications
    -+     * @see #SUPPRESSIBLE_USAGES
    -+     */
    -+    public final static int SUPPRESSIBLE_NOTIFICATION = 1;
    -+    /**
    -+     * @hide
    -+     * Denotes a usage for notifications that do expect immediate intervention from the user,
    -+     * will be muted when the Zen mode disables calls
    -+     * @see #SUPPRESSIBLE_USAGES
    -+     */
    -+    public final static int SUPPRESSIBLE_CALL = 2;
    -+
    -+    /**
    -+     * @hide
    -+     * Array of all usage types for calls and notifications to assign the suppression behavior,
    -+     * used by the Zen mode restrictions.
    -+     * @see com.android.server.notification.ZenModeHelper
    -+     */
    -+    public static final SparseIntArray SUPPRESSIBLE_USAGES;
    -+
    -+    static {
    -+        SUPPRESSIBLE_USAGES = new SparseIntArray();
    -+        SUPPRESSIBLE_USAGES.put(USAGE_NOTIFICATION,                      SUPPRESSIBLE_NOTIFICATION);
    -+        SUPPRESSIBLE_USAGES.put(USAGE_NOTIFICATION_RINGTONE,             SUPPRESSIBLE_CALL);
    -+        SUPPRESSIBLE_USAGES.put(USAGE_NOTIFICATION_COMMUNICATION_REQUEST,SUPPRESSIBLE_CALL);
    -+        SUPPRESSIBLE_USAGES.put(USAGE_NOTIFICATION_COMMUNICATION_INSTANT,SUPPRESSIBLE_NOTIFICATION);
    -+        SUPPRESSIBLE_USAGES.put(USAGE_NOTIFICATION_COMMUNICATION_DELAYED,SUPPRESSIBLE_NOTIFICATION);
    -+        SUPPRESSIBLE_USAGES.put(USAGE_NOTIFICATION_EVENT,                SUPPRESSIBLE_NOTIFICATION);
    -+    }
    -+
    -+    /**
    -+     * @hide
    -+     * Array of all usage types exposed in the SDK that applications can use.
    -+     */
    -+    public final static int[] SDK_USAGES = {
    -+            USAGE_UNKNOWN,
    -+            USAGE_MEDIA,
    -+            USAGE_VOICE_COMMUNICATION,
    -+            USAGE_VOICE_COMMUNICATION_SIGNALLING,
    -+            USAGE_ALARM,
    -+            USAGE_NOTIFICATION,
    -+            USAGE_NOTIFICATION_RINGTONE,
    -+            USAGE_NOTIFICATION_COMMUNICATION_REQUEST,
    -+            USAGE_NOTIFICATION_COMMUNICATION_INSTANT,
    -+            USAGE_NOTIFICATION_COMMUNICATION_DELAYED,
    -+            USAGE_NOTIFICATION_EVENT,
    -+            USAGE_ASSISTANCE_ACCESSIBILITY,
    -+            USAGE_ASSISTANCE_NAVIGATION_GUIDANCE,
    -+            USAGE_ASSISTANCE_SONIFICATION,
    -+            USAGE_GAME
    -+    };
    -+
    -+    /**
    -      * Flag defining a behavior where the audibility of the sound will be ensured by the system.
    -      */
    -     public final static int FLAG_AUDIBILITY_ENFORCED = 0x1 << 0;
    -diff --git a/media/java/android/media/ExifInterface.java b/media/java/android/media/ExifInterface.java
    -index 56af57a..6f24f76 100644
    ---- a/media/java/android/media/ExifInterface.java
    -+++ b/media/java/android/media/ExifInterface.java
    -@@ -1554,14 +1554,16 @@ public class ExifInterface {
    -      * copying all the data from one file to another and deleting the old file and renaming the
    -      * other. It's best to use {@link #setAttribute(String,String)} to set all attributes to write
    -      * and make a single call rather than multiple calls for each attribute.
    -+     * <p>
    -+     * This method is only supported for JPEG files.
    -+     * </p>
    -      */
    -     public void saveAttributes() throws IOException {
    -         if (!mIsSupportedFile || mIsRaw) {
    --            throw new UnsupportedOperationException(
    --                    "ExifInterface only supports saving attributes on JPEG formats.");
    -+            throw new IOException("ExifInterface only supports saving attributes on JPEG formats.");
    -         }
    -         if (mIsInputStream || (mSeekableFileDescriptor == null && mFilename == null)) {
    --            throw new UnsupportedOperationException(
    -+            throw new IOException(
    -                     "ExifInterface does not support saving attributes for the current input.");
    -         }
    - 
    -diff --git a/media/java/android/media/ImageReader.java b/media/java/android/media/ImageReader.java
    -index 2cbeb3a..ed71849 100644
    ---- a/media/java/android/media/ImageReader.java
    -+++ b/media/java/android/media/ImageReader.java
    -@@ -241,6 +241,10 @@ public class ImageReader implements AutoCloseable {
    -      * same {@link Surface} can be reused with a different API once the first source is
    -      * disconnected from the {@link Surface}.</p>
    -      *
    -+     * <p>Please note that holding on to the Surface object returned by this method is not enough
    -+     * to keep its parent ImageReader from being reclaimed. In that sense, a Surface acts like a
    -+     * {@link java.lang.ref.WeakReference weak reference} to the ImageReader that provides it.</p>
    -+     *
    -      * @return A {@link Surface} to use for a drawing target for various APIs.
    -      */
    -     public Surface getSurface() {
    -diff --git a/media/java/android/media/MediaExtractor.java b/media/java/android/media/MediaExtractor.java
    -index 6f5199b..c8aedd0 100644
    ---- a/media/java/android/media/MediaExtractor.java
    -+++ b/media/java/android/media/MediaExtractor.java
    -@@ -496,6 +496,11 @@ final public class MediaExtractor {
    -     /**
    -      * Advance to the next sample. Returns false if no more sample data
    -      * is available (end of stream).
    -+     *
    -+     * When extracting a local file, the behaviors of {@link #advance} and
    -+     * {@link #readSampleData} are undefined in presence of concurrent
    -+     * writes to the same local file; more specifically, end of stream
    -+     * could be signalled earlier than expected.
    -      */
    -     public native boolean advance();
    - 
    -diff --git a/media/java/android/media/MediaPlayer.java b/media/java/android/media/MediaPlayer.java
    -index 31c7a32..e5f7527 100644
    ---- a/media/java/android/media/MediaPlayer.java
    -+++ b/media/java/android/media/MediaPlayer.java
    -@@ -1641,7 +1641,8 @@ public class MediaPlayer extends PlayerBase
    -      * (i.e. reaches the end of the stream).
    -      * The media framework will attempt to transition from this player to
    -      * the next as seamlessly as possible. The next player can be set at
    --     * any time before completion. The next player must be prepared by the
    -+     * any time before completion, but shall be after setDataSource has been
    -+     * called successfully. The next player must be prepared by the
    -      * app, and the application should not call start() on it.
    -      * The next MediaPlayer must be different from 'this'. An exception
    -      * will be thrown if next == this.
    -diff --git a/media/java/android/media/MediaRouter.java b/media/java/android/media/MediaRouter.java
    -index 101facd..79195d6 100644
    ---- a/media/java/android/media/MediaRouter.java
    -+++ b/media/java/android/media/MediaRouter.java
    -@@ -220,8 +220,7 @@ public class MediaRouter {
    - 
    -             if (mBluetoothA2dpRoute != null) {
    -                 final boolean a2dpEnabled = isBluetoothA2dpOn();
    --                if (mainType != AudioRoutesInfo.MAIN_SPEAKER &&
    --                        mSelectedRoute == mBluetoothA2dpRoute && !a2dpEnabled) {
    -+                if (mSelectedRoute == mBluetoothA2dpRoute && !a2dpEnabled) {
    -                     selectRouteStatic(ROUTE_TYPE_LIVE_AUDIO, mDefaultAudioVideo, false);
    -                 } else if ((mSelectedRoute == mDefaultAudioVideo || mSelectedRoute == null) &&
    -                         a2dpEnabled) {
    -diff --git a/media/java/android/media/MediaScanner.java b/media/java/android/media/MediaScanner.java
    -index c8ab5f9..0fafe4b 100644
    ---- a/media/java/android/media/MediaScanner.java
    -+++ b/media/java/android/media/MediaScanner.java
    -@@ -21,12 +21,14 @@ import android.content.ContentResolver;
    - import android.content.ContentUris;
    - import android.content.ContentValues;
    - import android.content.Context;
    -+import android.content.SharedPreferences;
    - import android.database.Cursor;
    - import android.database.SQLException;
    - import android.drm.DrmManagerClient;
    - import android.graphics.BitmapFactory;
    - import android.mtp.MtpConstants;
    - import android.net.Uri;
    -+import android.os.Build;
    - import android.os.Environment;
    - import android.os.RemoteException;
    - import android.os.SystemProperties;
    -@@ -153,6 +155,11 @@ public class MediaScanner implements AutoCloseable {
    -     private static final String MUSIC_DIR = "/music/";
    -     private static final String PODCAST_DIR = "/podcasts/";
    - 
    -+    public static final String SCANNED_BUILD_PREFS_NAME = "MediaScanBuild";
    -+    public static final String LAST_INTERNAL_SCAN_FINGERPRINT = "lastScanFingerprint";
    -+    private static final String SYSTEM_SOUNDS_DIR = "/system/media/audio";
    -+    private static String sLastInternalScanFingerprint;
    -+
    -     private static final String[] ID3_GENRES = {
    -         // ID3v1 Genres
    -         "Blues",
    -@@ -402,6 +409,13 @@ public class MediaScanner implements AutoCloseable {
    -         mMediaProvider = mContext.getContentResolver()
    -                 .acquireContentProviderClient(MediaStore.AUTHORITY);
    - 
    -+        if (sLastInternalScanFingerprint == null) {
    -+            final SharedPreferences scanSettings =
    -+                    mContext.getSharedPreferences(SCANNED_BUILD_PREFS_NAME, Context.MODE_PRIVATE);
    -+            sLastInternalScanFingerprint =
    -+                    scanSettings.getString(LAST_INTERNAL_SCAN_FINGERPRINT, new String());
    -+        }
    -+
    -         mAudioUri = Audio.Media.getContentUri(volumeName);
    -         mVideoUri = Video.Media.getContentUri(volumeName);
    -         mImagesUri = Images.Media.getContentUri(volumeName);
    -@@ -585,16 +599,24 @@ public class MediaScanner implements AutoCloseable {
    -                     entry.mRowId = 0;
    -                 }
    - 
    --                if (entry.mPath != null &&
    --                        ((!mDefaultNotificationSet &&
    -+                if (entry.mPath != null) {
    -+                    if (((!mDefaultNotificationSet &&
    -                                 doesPathHaveFilename(entry.mPath, mDefaultNotificationFilename))
    -                         || (!mDefaultRingtoneSet &&
    -                                 doesPathHaveFilename(entry.mPath, mDefaultRingtoneFilename))
    -                         || (!mDefaultAlarmSet &&
    -                                 doesPathHaveFilename(entry.mPath, mDefaultAlarmAlertFilename)))) {
    --                    Log.w(TAG, "forcing rescan of " + entry.mPath +
    --                            "since ringtone setting didn't finish");
    --                    scanAlways = true;
    -+                        Log.w(TAG, "forcing rescan of " + entry.mPath +
    -+                                "since ringtone setting didn't finish");
    -+                        scanAlways = true;
    -+                    } else if (isSystemSoundWithMetadata(entry.mPath)
    -+                            && !Build.FINGERPRINT.equals(sLastInternalScanFingerprint)) {
    -+                        // file is located on the system partition where the date cannot be trusted:
    -+                        // rescan if the build fingerprint has changed since the last scan.
    -+                        Log.i(TAG, "forcing rescan of " + entry.mPath
    -+                                + " since build fingerprint changed");
    -+                        scanAlways = true;
    -+                    }
    -                 }
    - 
    -                 // rescan for metadata if file was modified since last scan
    -@@ -1128,6 +1150,15 @@ public class MediaScanner implements AutoCloseable {
    - 
    -     }; // end of anonymous MediaScannerClient instance
    - 
    -+    private static boolean isSystemSoundWithMetadata(String path) {
    -+        if (path.startsWith(SYSTEM_SOUNDS_DIR + ALARMS_DIR)
    -+                || path.startsWith(SYSTEM_SOUNDS_DIR + RINGTONES_DIR)
    -+                || path.startsWith(SYSTEM_SOUNDS_DIR + NOTIFICATIONS_DIR)) {
    -+            return true;
    -+        }
    -+        return false;
    -+    }
    -+
    -     private String settingSetIndicatorName(String base) {
    -         return base + "_set";
    -     }
    -@@ -1252,16 +1283,6 @@ public class MediaScanner implements AutoCloseable {
    -         }
    -     }
    - 
    --    private boolean inScanDirectory(String path, String[] directories) {
    --        for (int i = 0; i < directories.length; i++) {
    --            String directory = directories[i];
    --            if (path.startsWith(directory)) {
    --                return true;
    --            }
    --        }
    --        return false;
    --    }
    --
    -     private void pruneDeadThumbnailFiles() {
    -         HashSet<String> existingFiles = new HashSet<String>();
    -         String directory = "/sdcard/DCIM/.thumbnails";
    -diff --git a/media/java/android/media/MediaScannerConnection.java b/media/java/android/media/MediaScannerConnection.java
    -index d714672..471fa2c 100644
    ---- a/media/java/android/media/MediaScannerConnection.java
    -+++ b/media/java/android/media/MediaScannerConnection.java
    -@@ -133,6 +133,10 @@ public class MediaScannerConnection implements ServiceConnection {
    -                 }
    -                 try {
    -                     mContext.unbindService(this);
    -+                    if (mClient instanceof ClientProxy) {
    -+                        mClient = null;
    -+                    }
    -+                    mService = null;
    -                 } catch (IllegalArgumentException ex) {
    -                     if (false) {
    -                         Log.v(TAG, "disconnect failed: " + ex);
    -@@ -205,6 +209,7 @@ public class MediaScannerConnection implements ServiceConnection {
    -         void scanNextPath() {
    -             if (mNextPath >= mPaths.length) {
    -                 mConnection.disconnect();
    -+                mConnection = null;
    -                 return;
    -             }
    -             String mimeType = mMimeTypes != null ? mMimeTypes[mNextPath] : null;
    -diff --git a/media/java/android/media/Ringtone.java b/media/java/android/media/Ringtone.java
    -index c2bcd93..79412d4 100644
    ---- a/media/java/android/media/Ringtone.java
    -+++ b/media/java/android/media/Ringtone.java
    -@@ -469,6 +469,7 @@ public class Ringtone {
    -             synchronized (sActiveRingtones) {
    -                 sActiveRingtones.remove(Ringtone.this);
    -             }
    -+            mp.setOnCompletionListener(null); // Help the Java GC: break the refcount cycle.
    -         }
    -     }
    - }
    -diff --git a/media/java/android/mtp/MtpDevice.java b/media/java/android/mtp/MtpDevice.java
    -index 4082778..e7ea1a5 100644
    ---- a/media/java/android/mtp/MtpDevice.java
    -+++ b/media/java/android/mtp/MtpDevice.java
    -@@ -18,11 +18,13 @@ package android.mtp;
    - 
    - import android.annotation.NonNull;
    - import android.annotation.Nullable;
    -+import android.content.Context;
    - import android.hardware.usb.UsbDevice;
    - import android.hardware.usb.UsbDeviceConnection;
    - import android.os.CancellationSignal;
    - import android.os.ParcelFileDescriptor;
    - 
    -+import android.os.UserManager;
    - import com.android.internal.util.Preconditions;
    - 
    - import java.io.IOException;
    -@@ -62,7 +64,17 @@ public final class MtpDevice {
    -      * @return true if the device was successfully opened.
    -      */
    -     public boolean open(UsbDeviceConnection connection) {
    --        boolean result = native_open(mDevice.getDeviceName(), connection.getFileDescriptor());
    -+        boolean result = false;
    -+
    -+        Context context = connection.getContext();
    -+        if (context != null) {
    -+            UserManager userManager = (UserManager) context.getSystemService(Context.USER_SERVICE);
    -+
    -+            if (!userManager.hasUserRestriction(UserManager.DISALLOW_USB_FILE_TRANSFER)) {
    -+                result = native_open(mDevice.getDeviceName(), connection.getFileDescriptor());
    -+            }
    -+        }
    -+
    -         if (!result) {
    -             connection.close();
    -         }
    -diff --git a/media/jni/audioeffect/android_media_Visualizer.cpp b/media/jni/audioeffect/android_media_Visualizer.cpp
    -index f1a8c6f..aec31f0 100644
    ---- a/media/jni/audioeffect/android_media_Visualizer.cpp
    -+++ b/media/jni/audioeffect/android_media_Visualizer.cpp
    -@@ -435,11 +435,12 @@ setup_failure:
    - 
    - // ----------------------------------------------------------------------------
    - static void android_media_visualizer_native_release(JNIEnv *env,  jobject thiz) {
    --    sp<Visualizer> lpVisualizer = setVisualizer(env, thiz, 0);
    --    if (lpVisualizer == 0) {
    --        return;
    -+    { //limit scope so that lpVisualizer is deleted before JNI storage data.
    -+        sp<Visualizer> lpVisualizer = setVisualizer(env, thiz, 0);
    -+        if (lpVisualizer == 0) {
    -+            return;
    -+        }
    -     }
    --
    -     // delete the JNI data
    -     VisualizerJniStorage* lpJniStorage =
    -         (VisualizerJniStorage *)env->GetLongField(thiz, fields.fidJniData);
    -diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/ExifInterfaceTest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/ExifInterfaceTest.java
    -index db326ba..012041f 100644
    ---- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/ExifInterfaceTest.java
    -+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/ExifInterfaceTest.java
    -@@ -416,7 +416,7 @@ public class ExifInterfaceTest extends AndroidTestCase {
    -             in = getContext().getAssets().open(imageFile.getName());
    -             ExifInterface exifInterface = new ExifInterface(in);
    -             exifInterface.saveAttributes();
    --        } catch (UnsupportedOperationException e) {
    -+        } catch (IOException e) {
    -             // Expected. saveAttributes is not supported with an ExifInterface object which was
    -             // created with InputStream.
    -             return;
    -diff --git a/obex/javax/obex/ClientOperation.java b/obex/javax/obex/ClientOperation.java
    -index 883c8c6..b65598c 100644
    ---- a/obex/javax/obex/ClientOperation.java
    -+++ b/obex/javax/obex/ClientOperation.java
    -@@ -207,7 +207,6 @@ public final class ClientOperation implements Operation, BaseStream {
    -      *         object
    -      */
    -     public synchronized int getResponseCode() throws IOException {
    --        //avoid dup validateConnection
    -         if ((mReplyHeader.responseCode == -1)
    -                 || (mReplyHeader.responseCode == ResponseCodes.OBEX_HTTP_CONTINUE)) {
    -             validateConnection();
    -@@ -423,8 +422,9 @@ public final class ClientOperation implements Operation, BaseStream {
    -     private void validateConnection() throws IOException {
    -         ensureOpen();
    - 
    --        // to sure only one privateInput object exist.
    --        if (mPrivateInput == null) {
    -+        // Make sure that a response has been recieved from remote
    -+        // before continuing
    -+        if (mPrivateInput == null || mReplyHeader.responseCode == -1) {
    -             startProcessing();
    -         }
    -     }
    -diff --git a/packages/CaptivePortalLogin/res/values-bn-rBD/strings.xml b/packages/CaptivePortalLogin/res/values-bn-rBD/strings.xml
    -index 20173b0..24cbfbd 100644
    ---- a/packages/CaptivePortalLogin/res/values-bn-rBD/strings.xml
    -+++ b/packages/CaptivePortalLogin/res/values-bn-rBD/strings.xml
    -@@ -4,7 +4,7 @@
    -     <string name="app_name" msgid="5934709770924185752">"CaptivePortalLogin"</string>
    -     <string name="action_use_network" msgid="6076184727448466030">"যেভাবে আছে সেভাবেই এই নেটওয়ার্ক ব্যবহার করুন"</string>
    -     <string name="action_do_not_use_network" msgid="4577366536956516683">"এই নেটওয়ার্ক ব্যবহার করবেন না"</string>
    --    <string name="action_bar_label" msgid="917235635415966620">"নেটওয়ার্কে প্রবেশ করুন করুন"</string>
    -+    <string name="action_bar_label" msgid="917235635415966620">"নেটওয়ার্কে প্রবেশ করুন"</string>
    -     <string name="ssl_error_warning" msgid="6653188881418638872">"আপনি যে নেটওয়ার্কে যোগ দেওয়ার চেষ্টা করছেন তাতে নিরাপত্তার সমস্যা আছে।"</string>
    -     <string name="ssl_error_example" msgid="647898534624078900">"উদাহরণস্বরূপ, লগইন পৃষ্ঠাটি প্রদর্শিত প্রতিষ্ঠানের অন্তর্গত নাও হতে পারে৷"</string>
    -     <string name="ssl_error_continue" msgid="6492718244923937110">"যাই হোক না কেন ব্রাউজারের মাধ্যমে অবিরত রাখুন"</string>
    -diff --git a/packages/CaptivePortalLogin/src/com/android/captiveportallogin/CaptivePortalLoginActivity.java b/packages/CaptivePortalLogin/src/com/android/captiveportallogin/CaptivePortalLoginActivity.java
    -index b58c87a..bb8eb2c 100644
    ---- a/packages/CaptivePortalLogin/src/com/android/captiveportallogin/CaptivePortalLoginActivity.java
    -+++ b/packages/CaptivePortalLogin/src/com/android/captiveportallogin/CaptivePortalLoginActivity.java
    -@@ -115,6 +115,7 @@ public class CaptivePortalLoginActivity extends Activity {
    -         myWebView.clearCache(true);
    -         WebSettings webSettings = myWebView.getSettings();
    -         webSettings.setJavaScriptEnabled(true);
    -+        webSettings.setMixedContentMode(WebSettings.MIXED_CONTENT_COMPATIBILITY_MODE);
    -         mWebViewClient = new MyWebViewClient();
    -         myWebView.setWebViewClient(mWebViewClient);
    -         myWebView.setWebChromeClient(new MyWebChromeClient());
    -diff --git a/packages/DocumentsUI/src/com/android/documentsui/BaseActivity.java b/packages/DocumentsUI/src/com/android/documentsui/BaseActivity.java
    -index 1922773..46e7fe0 100644
    ---- a/packages/DocumentsUI/src/com/android/documentsui/BaseActivity.java
    -+++ b/packages/DocumentsUI/src/com/android/documentsui/BaseActivity.java
    -@@ -612,23 +612,13 @@ public abstract class BaseActivity extends Activity
    -             return;
    -         }
    - 
    --        if (!mState.hasLocationChanged()) {
    --            super.onBackPressed();
    --            return;
    --        }
    --
    --        if (onBeforePopDir() || popDir()) {
    -+        if (popDir()) {
    -             return;
    -         }
    - 
    -         super.onBackPressed();
    -     }
    - 
    --    boolean onBeforePopDir() {
    --        // Files app overrides this with some fancy logic.
    --        return false;
    --    }
    --
    -     public void onStackPicked(DocumentStack stack) {
    -         try {
    -             // Update the restored stack to ensure we have freshest data
    -diff --git a/packages/DocumentsUI/src/com/android/documentsui/Events.java b/packages/DocumentsUI/src/com/android/documentsui/Events.java
    -index 14d4e2d..02a9127 100644
    ---- a/packages/DocumentsUI/src/com/android/documentsui/Events.java
    -+++ b/packages/DocumentsUI/src/com/android/documentsui/Events.java
    -@@ -53,7 +53,8 @@ public final class Events {
    -      */
    -     public static boolean isTouchType(int toolType) {
    -         return toolType == MotionEvent.TOOL_TYPE_FINGER
    --                || toolType == MotionEvent.TOOL_TYPE_STYLUS;
    -+                || toolType == MotionEvent.TOOL_TYPE_STYLUS
    -+                || toolType == MotionEvent.TOOL_TYPE_UNKNOWN;
    -     }
    - 
    -     /**
    -diff --git a/packages/DocumentsUI/src/com/android/documentsui/FilesActivity.java b/packages/DocumentsUI/src/com/android/documentsui/FilesActivity.java
    -index b82f8dd..3b1ca77 100644
    ---- a/packages/DocumentsUI/src/com/android/documentsui/FilesActivity.java
    -+++ b/packages/DocumentsUI/src/com/android/documentsui/FilesActivity.java
    -@@ -60,12 +60,6 @@ public class FilesActivity extends BaseActivity {
    - 
    -     public static final String TAG = "FilesActivity";
    - 
    --    // See comments where this const is referenced for details.
    --    private static final int DRAWER_NO_FIDDLE_DELAY = 1500;
    --
    --    // Track the time we opened the drawer in response to back being pressed.
    --    // We use the time gap to figure out whether to close app or reopen the drawer.
    --    private long mDrawerLastFiddled;
    -     private DocumentClipper mClipper;
    - 
    -     public FilesActivity() {
    -@@ -341,8 +335,18 @@ public class FilesActivity extends BaseActivity {
    - 
    -         // Fall back to traditional VIEW action...
    -         intent = new Intent(Intent.ACTION_VIEW);
    --        intent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
    --        intent.setData(doc.derivedUri);
    -+        intent.setDataAndType(doc.derivedUri, doc.mimeType);
    -+
    -+        // Downloads has traditionally added the WRITE permission
    -+        // in the TrampolineActivity. Since this behavior is long
    -+        // established, we set the same permission for non-managed files
    -+        // This ensures consistent behavior between the Downloads root
    -+        // and other roots.
    -+        int flags = Intent.FLAG_GRANT_READ_URI_PERMISSION;
    -+        if (doc.isWriteSupported()) {
    -+            flags |= Intent.FLAG_GRANT_WRITE_URI_PERMISSION;
    -+        }
    -+        intent.setFlags(flags);
    - 
    -         if (DEBUG && intent.getClipData() != null) {
    -             Log.d(TAG, "Starting intent w/ clip data: " + intent.getClipData());
    -@@ -385,34 +389,6 @@ public class FilesActivity extends BaseActivity {
    -         }
    -     }
    - 
    --    // Do some "do what a I want" drawer fiddling, but don't
    --    // do it if user already hit back recently and we recently
    --    // did some fiddling.
    --    @Override
    --    boolean onBeforePopDir() {
    --        int size = mState.stack.size();
    --
    --        if (mDrawer.isPresent()
    --                && (System.currentTimeMillis() - mDrawerLastFiddled) > DRAWER_NO_FIDDLE_DELAY) {
    --            // Close drawer if it is open.
    --            if (mDrawer.isOpen()) {
    --                mDrawer.setOpen(false);
    --                mDrawerLastFiddled = System.currentTimeMillis();
    --                return true;
    --            }
    --
    --            // Open the Close drawer if it is closed and we're at the top of a root.
    --            if (size <= 1) {
    --                mDrawer.setOpen(true);
    --                // Remember so we don't just close it again if back is pressed again.
    --                mDrawerLastFiddled = System.currentTimeMillis();
    --                return true;
    --            }
    --        }
    --
    --        return false;
    --    }
    --
    -     // Turns out only DocumentsActivity was ever calling saveStackBlocking.
    -     // There may be a  case where we want to contribute entries from
    -     // Behavior here in FilesActivity, but it isn't yet obvious.
    -diff --git a/packages/DocumentsUI/src/com/android/documentsui/IconUtils.java b/packages/DocumentsUI/src/com/android/documentsui/IconUtils.java
    -index 177ba0d..d87bc11 100644
    ---- a/packages/DocumentsUI/src/com/android/documentsui/IconUtils.java
    -+++ b/packages/DocumentsUI/src/com/android/documentsui/IconUtils.java
    -@@ -42,12 +42,6 @@ public class IconUtils {
    -     public static Drawable loadMimeIcon(
    -             Context context, String mimeType, String authority, String docId, int mode) {
    -         if (Document.MIME_TYPE_DIR.equals(mimeType)) {
    --            // TODO: eventually move these hacky assets into that package
    --            if ("com.android.providers.media.documents".equals(authority)
    --                    && docId.startsWith("album")) {
    --                return context.getDrawable(R.drawable.ic_doc_album);
    --            }
    --
    -             if (mode == State.MODE_GRID) {
    -                 return context.getDrawable(R.drawable.ic_grid_folder);
    -             } else {
    -diff --git a/packages/DocumentsUI/src/com/android/documentsui/LocalPreferences.java b/packages/DocumentsUI/src/com/android/documentsui/LocalPreferences.java
    -index d2e9885..b3db037 100644
    ---- a/packages/DocumentsUI/src/com/android/documentsui/LocalPreferences.java
    -+++ b/packages/DocumentsUI/src/com/android/documentsui/LocalPreferences.java
    -@@ -22,6 +22,7 @@ import android.annotation.IntDef;
    - import android.annotation.Nullable;
    - import android.content.Context;
    - import android.content.SharedPreferences;
    -+import android.content.SharedPreferences.Editor;
    - import android.os.UserHandle;
    - import android.preference.PreferenceManager;
    - 
    -@@ -85,6 +86,15 @@ public class LocalPreferences {
    -     public @interface PermissionStatus {}
    - 
    -     /**
    -+     * Clears all preferences associated with a given package.
    -+     *
    -+     * <p>Typically called when a package is removed or when user asked to clear its data.
    -+     */
    -+    static void clearPackagePreferences(Context context, String packageName) {
    -+        clearScopedAccessPreferences(context, packageName);
    -+    }
    -+
    -+    /**
    -      * Methods below are used to keep track of denied user requests on scoped directory access so
    -      * the dialog is not offered when user checked the 'Do not ask again' box
    -      *
    -@@ -108,6 +118,23 @@ public class LocalPreferences {
    -       getPrefs(context).edit().putInt(key, status).apply();
    -     }
    - 
    -+    private static void clearScopedAccessPreferences(Context context, String packageName) {
    -+        final String keySubstring = "|" + packageName + "|";
    -+        final SharedPreferences prefs = getPrefs(context);
    -+        Editor editor = null;
    -+        for (final String key : prefs.getAll().keySet()) {
    -+            if (key.contains(keySubstring)) {
    -+                if (editor == null) {
    -+                    editor = prefs.edit();
    -+                }
    -+                editor.remove(key);
    -+            }
    -+        }
    -+        if (editor != null) {
    -+            editor.apply();
    -+        }
    -+    }
    -+
    -     private static String getScopedAccessDenialsKey(String packageName, String uuid,
    -             String directory) {
    -         final int userId = UserHandle.myUserId();
    -diff --git a/packages/DocumentsUI/src/com/android/documentsui/PackageReceiver.java b/packages/DocumentsUI/src/com/android/documentsui/PackageReceiver.java
    -index aef63af..fd1183f 100644
    ---- a/packages/DocumentsUI/src/com/android/documentsui/PackageReceiver.java
    -+++ b/packages/DocumentsUI/src/com/android/documentsui/PackageReceiver.java
    -@@ -23,7 +23,7 @@ import android.content.Intent;
    - import android.net.Uri;
    - 
    - /**
    -- * Clean up {@link RecentsProvider} when packages are removed.
    -+ * Cleans up {@link RecentsProvider} and {@link LocalPreferences} when packages are removed.
    -  */
    - public class PackageReceiver extends BroadcastReceiver {
    -     @Override
    -@@ -31,15 +31,19 @@ public class PackageReceiver extends BroadcastReceiver {
    -         final ContentResolver resolver = context.getContentResolver();
    - 
    -         final String action = intent.getAction();
    -+        final Uri data = intent.getData();
    -+        final String packageName = data == null ? null : data.getSchemeSpecificPart();
    -+
    -         if (Intent.ACTION_PACKAGE_FULLY_REMOVED.equals(action)) {
    -             resolver.call(RecentsProvider.buildRecent(), RecentsProvider.METHOD_PURGE, null, null);
    --
    -+            if (packageName != null) {
    -+                LocalPreferences.clearPackagePreferences(context, packageName);
    -+            }
    -         } else if (Intent.ACTION_PACKAGE_DATA_CLEARED.equals(action)) {
    --            final Uri data = intent.getData();
    --            if (data != null) {
    --                final String packageName = data.getSchemeSpecificPart();
    -+            if (packageName != null) {
    -                 resolver.call(RecentsProvider.buildRecent(), RecentsProvider.METHOD_PURGE_PACKAGE,
    -                         packageName, null);
    -+                LocalPreferences.clearPackagePreferences(context, packageName);
    -             }
    -         }
    -     }
    -diff --git a/packages/DocumentsUI/src/com/android/documentsui/RecentsLoader.java b/packages/DocumentsUI/src/com/android/documentsui/RecentsLoader.java
    -index cebc9b0..557a2f6 100644
    ---- a/packages/DocumentsUI/src/com/android/documentsui/RecentsLoader.java
    -+++ b/packages/DocumentsUI/src/com/android/documentsui/RecentsLoader.java
    -@@ -157,6 +157,9 @@ public class RecentsLoader extends AsyncTaskLoader<DirectoryResult> {
    -                     throw new RuntimeException(e);
    -                 } catch (ExecutionException e) {
    -                     // We already logged on other side
    -+                } catch (Exception e) {
    -+                    Log.e(TAG, "Failed to query Recents for authority: " + task.authority
    -+                        + ". Skip this authority in Recents.", e);
    -                 }
    -             } else {
    -                 allDone = false;
    -diff --git a/packages/DocumentsUI/src/com/android/documentsui/dirlist/DirectoryFragment.java b/packages/DocumentsUI/src/com/android/documentsui/dirlist/DirectoryFragment.java
    -index b7c0a9c..8a6723f 100644
    ---- a/packages/DocumentsUI/src/com/android/documentsui/dirlist/DirectoryFragment.java
    -+++ b/packages/DocumentsUI/src/com/android/documentsui/dirlist/DirectoryFragment.java
    -@@ -53,10 +53,13 @@ import android.provider.DocumentsContract.Document;
    - import android.support.annotation.Nullable;
    - import android.support.design.widget.Snackbar;
    - import android.support.v13.view.DragStartHelper;
    -+import android.support.v4.view.accessibility.AccessibilityNodeInfoCompat;
    -+import android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat;
    - import android.support.v7.widget.GridLayoutManager;
    - import android.support.v7.widget.GridLayoutManager.SpanSizeLookup;
    - import android.support.v7.widget.RecyclerView;
    - import android.support.v7.widget.RecyclerView.OnItemTouchListener;
    -+import android.support.v7.widget.RecyclerView.Recycler;
    - import android.support.v7.widget.RecyclerView.RecyclerListener;
    - import android.support.v7.widget.RecyclerView.ViewHolder;
    - import android.text.BidiFormatter;
    -@@ -243,7 +246,40 @@ public class DirectoryFragment extends Fragment
    - 
    -         mRecView.setAdapter(mAdapter);
    - 
    --        mLayout = new GridLayoutManager(getContext(), mColumnCount);
    -+        // Switch Access Accessibility API needs an {@link AccessibilityDelegate} to know the proper
    -+        // route when user selects an UI element. It usually guesses this if the element has an
    -+        // {@link OnClickListener}, but since we do not have one for itemView, we will need to
    -+        // manually route it to the right behavior. RecyclerView has its own AccessibilityDelegate,
    -+        // and routes it to its LayoutManager; so we must override the LayoutManager's accessibility
    -+        // methods to route clicks correctly.
    -+        mLayout = new GridLayoutManager(getContext(), mColumnCount) {
    -+            @Override
    -+            public void onInitializeAccessibilityNodeInfoForItem(
    -+                    RecyclerView.Recycler recycler, RecyclerView.State state,
    -+                    View host, AccessibilityNodeInfoCompat info) {
    -+                super.onInitializeAccessibilityNodeInfoForItem(recycler, state, host, info);
    -+                info.addAction(AccessibilityActionCompat.ACTION_CLICK);
    -+            }
    -+
    -+            @Override
    -+            public boolean performAccessibilityActionForItem(
    -+                    RecyclerView.Recycler recycler, RecyclerView.State state, View view,
    -+                    int action, Bundle args) {
    -+                // We are only handling click events; route all other to default implementation
    -+                if (action == AccessibilityNodeInfoCompat.ACTION_CLICK) {
    -+                    RecyclerView.ViewHolder vh = mRecView.getChildViewHolder(view);
    -+                    if (vh instanceof DocumentHolder) {
    -+                        DocumentHolder dh = (DocumentHolder) vh;
    -+                        if (dh.mEventListener != null) {
    -+                            dh.mEventListener.onActivate(dh);
    -+                            return true;
    -+                        }
    -+                    }
    -+                }
    -+                return super.performAccessibilityActionForItem(recycler, state, view, action,
    -+                        args);
    -+            }
    -+        };
    -         SpanSizeLookup lookup = mAdapter.createSpanSizeLookup();
    -         if (lookup != null) {
    -             mLayout.setSpanSizeLookup(lookup);
    -@@ -717,63 +753,57 @@ public class DirectoryFragment extends Fragment
    -     private void openDocuments(final Selection selected) {
    -         Metrics.logUserAction(getContext(), Metrics.USER_ACTION_OPEN);
    - 
    --        new GetDocumentsTask() {
    --            @Override
    --            void onDocumentsReady(List<DocumentInfo> docs) {
    --                // TODO: Implement support in Files activity for opening multiple docs.
    --                BaseActivity.get(DirectoryFragment.this).onDocumentsPicked(docs);
    --            }
    --        }.execute(selected);
    -+        // Model must be accessed in UI thread, since underlying cursor is not threadsafe.
    -+        List<DocumentInfo> docs = mModel.getDocuments(selected);
    -+        // TODO: Implement support in Files activity for opening multiple docs.
    -+        BaseActivity.get(DirectoryFragment.this).onDocumentsPicked(docs);
    -     }
    - 
    -     private void shareDocuments(final Selection selected) {
    -         Metrics.logUserAction(getContext(), Metrics.USER_ACTION_SHARE);
    - 
    --        new GetDocumentsTask() {
    --            @Override
    --            void onDocumentsReady(List<DocumentInfo> docs) {
    --                Intent intent;
    --
    --                // Filter out directories and virtual files - those can't be shared.
    --                List<DocumentInfo> docsForSend = new ArrayList<>();
    --                for (DocumentInfo doc: docs) {
    --                    if (!doc.isDirectory() && !doc.isVirtualDocument()) {
    --                        docsForSend.add(doc);
    --                    }
    --                }
    -+        // Model must be accessed in UI thread, since underlying cursor is not threadsafe.
    -+        List<DocumentInfo> docs = mModel.getDocuments(selected);
    -+        Intent intent;
    - 
    --                if (docsForSend.size() == 1) {
    --                    final DocumentInfo doc = docsForSend.get(0);
    --
    --                    intent = new Intent(Intent.ACTION_SEND);
    --                    intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
    --                    intent.addCategory(Intent.CATEGORY_DEFAULT);
    --                    intent.setType(doc.mimeType);
    --                    intent.putExtra(Intent.EXTRA_STREAM, doc.derivedUri);
    --
    --                } else if (docsForSend.size() > 1) {
    --                    intent = new Intent(Intent.ACTION_SEND_MULTIPLE);
    --                    intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
    --                    intent.addCategory(Intent.CATEGORY_DEFAULT);
    --
    --                    final ArrayList<String> mimeTypes = new ArrayList<>();
    --                    final ArrayList<Uri> uris = new ArrayList<>();
    --                    for (DocumentInfo doc : docsForSend) {
    --                        mimeTypes.add(doc.mimeType);
    --                        uris.add(doc.derivedUri);
    --                    }
    -+        // Filter out directories and virtual files - those can't be shared.
    -+        List<DocumentInfo> docsForSend = new ArrayList<>();
    -+        for (DocumentInfo doc: docs) {
    -+            if (!doc.isDirectory() && !doc.isVirtualDocument()) {
    -+                docsForSend.add(doc);
    -+            }
    -+        }
    - 
    --                    intent.setType(findCommonMimeType(mimeTypes));
    --                    intent.putParcelableArrayListExtra(Intent.EXTRA_STREAM, uris);
    -+        if (docsForSend.size() == 1) {
    -+            final DocumentInfo doc = docsForSend.get(0);
    - 
    --                } else {
    --                    return;
    --                }
    -+            intent = new Intent(Intent.ACTION_SEND);
    -+            intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
    -+            intent.addCategory(Intent.CATEGORY_DEFAULT);
    -+            intent.setType(doc.mimeType);
    -+            intent.putExtra(Intent.EXTRA_STREAM, doc.derivedUri);
    -+
    -+        } else if (docsForSend.size() > 1) {
    -+            intent = new Intent(Intent.ACTION_SEND_MULTIPLE);
    -+            intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
    -+            intent.addCategory(Intent.CATEGORY_DEFAULT);
    - 
    --                intent = Intent.createChooser(intent, getActivity().getText(R.string.share_via));
    --                startActivity(intent);
    -+            final ArrayList<String> mimeTypes = new ArrayList<>();
    -+            final ArrayList<Uri> uris = new ArrayList<>();
    -+            for (DocumentInfo doc : docsForSend) {
    -+                mimeTypes.add(doc.mimeType);
    -+                uris.add(doc.derivedUri);
    -             }
    --        }.execute(selected);
    -+
    -+            intent.setType(findCommonMimeType(mimeTypes));
    -+            intent.putParcelableArrayListExtra(Intent.EXTRA_STREAM, uris);
    -+
    -+        } else {
    -+            return;
    -+        }
    -+
    -+        intent = Intent.createChooser(intent, getActivity().getText(R.string.share_via));
    -+        startActivity(intent);
    -     }
    - 
    -     private String generateDeleteMessage(final List<DocumentInfo> docs) {
    -@@ -819,52 +849,51 @@ public class DirectoryFragment extends Fragment
    -         assert(!selected.isEmpty());
    - 
    -         final DocumentInfo srcParent = getDisplayState().stack.peek();
    --        new GetDocumentsTask() {
    --            @Override
    --            void onDocumentsReady(final List<DocumentInfo> docs) {
    --
    --                TextView message =
    --                        (TextView) mInflater.inflate(R.layout.dialog_delete_confirmation, null);
    --                message.setText(generateDeleteMessage(docs));
    --
    --                // This "insta-hides" files that are being deleted, because
    --                // the delete operation may be not execute immediately (it
    --                // may be queued up on the FileOperationService.)
    --                // To hide the files locally, we call the hide method on the adapter
    --                // ...which a live object...cannot be parceled.
    --                // For that reason, for now, we implement this dialog NOT
    --                // as a fragment (which can survive rotation and have its own state),
    --                // but as a simple runtime dialog. So rotating a device with an
    --                // active delete dialog...results in that dialog disappearing.
    --                // We can do better, but don't have cycles for it now.
    --                new AlertDialog.Builder(getActivity())
    --                    .setView(message)
    --                    .setPositiveButton(
    --                         android.R.string.yes,
    --                         new DialogInterface.OnClickListener() {
    --                            public void onClick(DialogInterface dialog, int id) {
    --                                // Finish selection mode first which clears selection so we
    --                                // don't end up trying to deselect deleted documents.
    --                                // This is done here, rather in the onActionItemClicked
    --                                // so we can avoid de-selecting items in the case where
    --                                // the user cancels the delete.
    --                                if (mActionMode != null) {
    --                                    mActionMode.finish();
    --                                } else {
    --                                    Log.w(TAG, "Action mode is null before deleting documents.");
    --                                }
    --                                // Hide the files in the UI...since the operation
    --                                // might be queued up on FileOperationService.
    --                                // We're walking a line here.
    --                                mAdapter.hide(selected.getAll());
    --                                FileOperations.delete(
    --                                        getActivity(), docs, srcParent, getDisplayState().stack);
    --                            }
    --                        })
    --                    .setNegativeButton(android.R.string.no, null)
    --                    .show();
    --            }
    --        }.execute(selected);
    -+
    -+        // Model must be accessed in UI thread, since underlying cursor is not threadsafe.
    -+        List<DocumentInfo> docs = mModel.getDocuments(selected);
    -+
    -+        TextView message =
    -+                (TextView) mInflater.inflate(R.layout.dialog_delete_confirmation, null);
    -+        message.setText(generateDeleteMessage(docs));
    -+
    -+        // This "insta-hides" files that are being deleted, because
    -+        // the delete operation may be not execute immediately (it
    -+        // may be queued up on the FileOperationService.)
    -+        // To hide the files locally, we call the hide method on the adapter
    -+        // ...which a live object...cannot be parceled.
    -+        // For that reason, for now, we implement this dialog NOT
    -+        // as a fragment (which can survive rotation and have its own state),
    -+        // but as a simple runtime dialog. So rotating a device with an
    -+        // active delete dialog...results in that dialog disappearing.
    -+        // We can do better, but don't have cycles for it now.
    -+        new AlertDialog.Builder(getActivity())
    -+            .setView(message)
    -+            .setPositiveButton(
    -+                 android.R.string.yes,
    -+                 new DialogInterface.OnClickListener() {
    -+                    @Override
    -+                    public void onClick(DialogInterface dialog, int id) {
    -+                        // Finish selection mode first which clears selection so we
    -+                        // don't end up trying to deselect deleted documents.
    -+                        // This is done here, rather in the onActionItemClicked
    -+                        // so we can avoid de-selecting items in the case where
    -+                        // the user cancels the delete.
    -+                        if (mActionMode != null) {
    -+                            mActionMode.finish();
    -+                        } else {
    -+                            Log.w(TAG, "Action mode is null before deleting documents.");
    -+                        }
    -+                        // Hide the files in the UI...since the operation
    -+                        // might be queued up on FileOperationService.
    -+                        // We're walking a line here.
    -+                        mAdapter.hide(selected.getAll());
    -+                        FileOperations.delete(
    -+                                getActivity(), docs, srcParent, getDisplayState().stack);
    -+                    }
    -+                })
    -+            .setNegativeButton(android.R.string.no, null)
    -+            .show();
    -     }
    - 
    -     private void transferDocuments(final Selection selected, final @OpType int mode) {
    -@@ -898,25 +927,21 @@ public class DirectoryFragment extends Fragment
    -                 ? R.string.menu_move : R.string.menu_copy;
    -         intent.putExtra(DocumentsContract.EXTRA_PROMPT, getResources().getString(drawerTitleId));
    - 
    --        new GetDocumentsTask() {
    --            @Override
    --            void onDocumentsReady(List<DocumentInfo> docs) {
    --                // TODO: Can this move to Fragment bundle state?
    --                getDisplayState().selectedDocumentsForCopy = docs;
    --
    --                // Determine if there is a directory in the set of documents
    --                // to be copied? Why? Directory creation isn't supported by some roots
    --                // (like Downloads). This informs DocumentsActivity (the "picker")
    --                // to restrict available roots to just those with support.
    --                intent.putExtra(Shared.EXTRA_DIRECTORY_COPY, hasDirectory(docs));
    --                intent.putExtra(FileOperationService.EXTRA_OPERATION, mode);
    --
    --                // This just identifies the type of request...we'll check it
    --                // when we reveive a response.
    --                startActivityForResult(intent, REQUEST_COPY_DESTINATION);
    --            }
    -+        // Model must be accessed in UI thread, since underlying cursor is not threadsafe.
    -+        List<DocumentInfo> docs = mModel.getDocuments(selected);
    -+        // TODO: Can this move to Fragment bundle state?
    -+        getDisplayState().selectedDocumentsForCopy = docs;
    -+
    -+        // Determine if there is a directory in the set of documents
    -+        // to be copied? Why? Directory creation isn't supported by some roots
    -+        // (like Downloads). This informs DocumentsActivity (the "picker")
    -+        // to restrict available roots to just those with support.
    -+        intent.putExtra(Shared.EXTRA_DIRECTORY_COPY, hasDirectory(docs));
    -+        intent.putExtra(FileOperationService.EXTRA_OPERATION, mode);
    - 
    --        }.execute(selected);
    -+        // This just identifies the type of request...we'll check it
    -+        // when we reveive a response.
    -+        startActivityForResult(intent, REQUEST_COPY_DESTINATION);
    -     }
    - 
    -     private static boolean hasDirectory(List<DocumentInfo> docs) {
    -@@ -935,12 +960,9 @@ public class DirectoryFragment extends Fragment
    -         // Rename option is only available in menu when 1 document selected
    -         assert(selected.size() == 1);
    - 
    --        new GetDocumentsTask() {
    --            @Override
    --            void onDocumentsReady(List<DocumentInfo> docs) {
    --                RenameDocumentFragment.show(getFragmentManager(), docs.get(0));
    --            }
    --        }.execute(selected);
    -+        // Model must be accessed in UI thread, since underlying cursor is not threadsafe.
    -+        List<DocumentInfo> docs = mModel.getDocuments(selected);
    -+        RenameDocumentFragment.show(getFragmentManager(), docs.get(0));
    -     }
    - 
    -     @Override
    -@@ -1099,19 +1121,17 @@ public class DirectoryFragment extends Fragment
    -         }
    -     }
    - 
    --    void copySelectionToClipboard(Selection selection) {
    --        assert(!selection.isEmpty());
    --        new GetDocumentsTask() {
    --            @Override
    --            void onDocumentsReady(List<DocumentInfo> docs) {
    --                mClipper.clipDocuments(docs);
    --                Activity activity = getActivity();
    --                Snackbars.makeSnackbar(activity,
    --                        activity.getResources().getQuantityString(
    --                                R.plurals.clipboard_files_clipped, docs.size(), docs.size()),
    --                        Snackbar.LENGTH_SHORT).show();
    --            }
    --        }.execute(selection);
    -+    void copySelectionToClipboard(Selection selected) {
    -+        assert(!selected.isEmpty());
    -+
    -+        // Model must be accessed in UI thread, since underlying cursor is not threadsafe.
    -+        List<DocumentInfo> docs = mModel.getDocuments(selected);
    -+        mClipper.clipDocuments(docs);
    -+        Activity activity = getActivity();
    -+        Snackbars.makeSnackbar(activity,
    -+                activity.getResources().getQuantityString(
    -+                        R.plurals.clipboard_files_clipped, docs.size(), docs.size()),
    -+                Snackbar.LENGTH_SHORT).show();
    -     }
    - 
    -     public void pasteFromClipboard() {
    -@@ -1420,25 +1440,6 @@ public class DirectoryFragment extends Fragment
    -             mShadowView.draw(canvas);
    -         }
    -     }
    --    /**
    --     * Abstract task providing support for loading documents *off*
    --     * the main thread. And if it isn't obvious, creating a list
    --     * of documents (especially large lists) can be pretty expensive.
    --     */
    --    private abstract class GetDocumentsTask
    --            extends AsyncTask<Selection, Void, List<DocumentInfo>> {
    --        @Override
    --        protected final List<DocumentInfo> doInBackground(Selection... selected) {
    --            return mModel.getDocuments(selected[0]);
    --        }
    --
    --        @Override
    --        protected final void onPostExecute(List<DocumentInfo> docs) {
    --            onDocumentsReady(docs);
    --        }
    --
    --        abstract void onDocumentsReady(List<DocumentInfo> docs);
    --    }
    - 
    -     @Override
    -     public boolean isSelected(String modelId) {
    -diff --git a/packages/DocumentsUI/src/com/android/documentsui/dirlist/Model.java b/packages/DocumentsUI/src/com/android/documentsui/dirlist/Model.java
    -index 0a2960f..94b8277 100644
    ---- a/packages/DocumentsUI/src/com/android/documentsui/dirlist/Model.java
    -+++ b/packages/DocumentsUI/src/com/android/documentsui/dirlist/Model.java
    -@@ -107,7 +107,13 @@ public class Model {
    -         mSortOrder = result.sortOrder;
    -         doc = result.doc;
    - 
    --        updateModelData();
    -+        try {
    -+            updateModelData();
    -+        } catch (Exception e) {
    -+            Log.e(TAG, "Error while accessing cursors", e);
    -+            notifyUpdateListeners(e);
    -+            return;
    -+        }
    - 
    -         final Bundle extras = mCursor.getExtras();
    -         if (extras != null) {
    -diff --git a/packages/DocumentsUI/src/com/android/documentsui/model/DocumentInfo.java b/packages/DocumentsUI/src/com/android/documentsui/model/DocumentInfo.java
    -index 3a86a51..63f66de 100644
    ---- a/packages/DocumentsUI/src/com/android/documentsui/model/DocumentInfo.java
    -+++ b/packages/DocumentsUI/src/com/android/documentsui/model/DocumentInfo.java
    -@@ -235,6 +235,10 @@ public class DocumentInfo implements Durable, Parcelable {
    -         return (flags & Document.FLAG_DIR_PREFERS_GRID) != 0;
    -     }
    - 
    -+    public boolean isWriteSupported() {
    -+        return (flags & Document.FLAG_SUPPORTS_WRITE) != 0;
    -+    }
    -+
    -     public boolean isDeleteSupported() {
    -         return (flags & Document.FLAG_SUPPORTS_DELETE) != 0;
    -     }
    -diff --git a/packages/DocumentsUI/src/com/android/documentsui/services/MoveJob.java b/packages/DocumentsUI/src/com/android/documentsui/services/MoveJob.java
    -index 1118171..1de3bbc 100644
    ---- a/packages/DocumentsUI/src/com/android/documentsui/services/MoveJob.java
    -+++ b/packages/DocumentsUI/src/com/android/documentsui/services/MoveJob.java
    -@@ -117,7 +117,9 @@ final class MoveJob extends CopyJob {
    -         byteCopyDocument(src, dest);
    - 
    -         // Remove the source document.
    --        deleteDocument(src, srcParent);
    -+        if(!isCanceled()) {
    -+            deleteDocument(src, srcParent);
    -+        }
    -     }
    - 
    -     @Override
    -diff --git a/packages/EasterEgg/src/com/android/egg/neko/NekoService.java b/packages/EasterEgg/src/com/android/egg/neko/NekoService.java
    -index 32e3358..808ec36 100644
    ---- a/packages/EasterEgg/src/com/android/egg/neko/NekoService.java
    -+++ b/packages/EasterEgg/src/com/android/egg/neko/NekoService.java
    -@@ -102,6 +102,14 @@ public class NekoService extends JobService {
    -         return false;
    -     }
    - 
    -+    public static void registerJobIfNeeded(Context context, long intervalMinutes) {
    -+        JobScheduler jss = context.getSystemService(JobScheduler.class);
    -+        JobInfo info = jss.getPendingJob(JOB_ID);
    -+        if (info == null) {
    -+            registerJob(context, intervalMinutes);
    -+        }
    -+    }
    -+
    -     public static void registerJob(Context context, long intervalMinutes) {
    -         JobScheduler jss = context.getSystemService(JobScheduler.class);
    -         jss.cancel(JOB_ID);
    -diff --git a/packages/EasterEgg/src/com/android/egg/neko/NekoTile.java b/packages/EasterEgg/src/com/android/egg/neko/NekoTile.java
    -index 8a3ec8f..159b40a 100644
    ---- a/packages/EasterEgg/src/com/android/egg/neko/NekoTile.java
    -+++ b/packages/EasterEgg/src/com/android/egg/neko/NekoTile.java
    -@@ -68,6 +68,9 @@ public class NekoTile extends TileService implements PrefsListener {
    -         Tile tile = getQsTile();
    -         int foodState = mPrefs.getFoodState();
    -         Food food = new Food(foodState);
    -+        if (foodState != 0) {
    -+            NekoService.registerJobIfNeeded(this, food.getInterval(this));
    -+        }
    -         tile.setIcon(food.getIcon(this));
    -         tile.setLabel(food.getName(this));
    -         tile.setState(foodState != 0 ? Tile.STATE_ACTIVE : Tile.STATE_INACTIVE);
    -diff --git a/packages/EasterEgg/src/com/android/egg/neko/PrefState.java b/packages/EasterEgg/src/com/android/egg/neko/PrefState.java
    -index 5f54180..bf71b19 100644
    ---- a/packages/EasterEgg/src/com/android/egg/neko/PrefState.java
    -+++ b/packages/EasterEgg/src/com/android/egg/neko/PrefState.java
    -@@ -43,13 +43,11 @@ public class PrefState implements OnSharedPreferenceChangeListener {
    -     public void addCat(Cat cat) {
    -         mPrefs.edit()
    -               .putString(CAT_KEY_PREFIX + String.valueOf(cat.getSeed()), cat.getName())
    --              .commit();
    -+              .apply();
    -     }
    - 
    -     public void removeCat(Cat cat) {
    --        mPrefs.edit()
    --                .remove(CAT_KEY_PREFIX + String.valueOf(cat.getSeed()))
    --                .commit();
    -+        mPrefs.edit().remove(CAT_KEY_PREFIX + String.valueOf(cat.getSeed())).apply();
    -     }
    - 
    -     public List<Cat> getCats() {
    -@@ -71,7 +69,7 @@ public class PrefState implements OnSharedPreferenceChangeListener {
    -     }
    - 
    -     public void setFoodState(int foodState) {
    --        mPrefs.edit().putInt(FOOD_STATE, foodState).commit();
    -+        mPrefs.edit().putInt(FOOD_STATE, foodState).apply();
    -     }
    - 
    -     public void setListener(PrefsListener listener) {
    -diff --git a/packages/ExternalStorageProvider/src/com/android/externalstorage/ExternalStorageProvider.java b/packages/ExternalStorageProvider/src/com/android/externalstorage/ExternalStorageProvider.java
    -index 78b9927..3ef9b8e 100644
    ---- a/packages/ExternalStorageProvider/src/com/android/externalstorage/ExternalStorageProvider.java
    -+++ b/packages/ExternalStorageProvider/src/com/android/externalstorage/ExternalStorageProvider.java
    -@@ -466,10 +466,7 @@ public class ExternalStorageProvider extends DocumentsProvider {
    -         displayName = FileUtils.buildValidFatFilename(displayName);
    - 
    -         final File before = getFileForDocId(docId);
    --        final File after = new File(before.getParentFile(), displayName);
    --        if (after.exists()) {
    --            throw new IllegalStateException("Already exists " + after);
    --        }
    -+        final File after = FileUtils.buildUniqueFile(before.getParentFile(), displayName);
    -         if (!before.renameTo(after)) {
    -             throw new IllegalStateException("Failed to rename to " + after);
    -         }
    -@@ -566,6 +563,7 @@ public class ExternalStorageProvider extends DocumentsProvider {
    -             throws FileNotFoundException {
    -         final MatrixCursor result = new MatrixCursor(resolveDocumentProjection(projection));
    - 
    -+        query = query.toLowerCase();
    -         final File parent;
    -         synchronized (mRootsLock) {
    -             parent = mRoots.get(rootId).path;
    -diff --git a/packages/Keyguard/src/com/android/keyguard/EmergencyButton.java b/packages/Keyguard/src/com/android/keyguard/EmergencyButton.java
    -index 8d41145..0474df7 100644
    ---- a/packages/Keyguard/src/com/android/keyguard/EmergencyButton.java
    -+++ b/packages/Keyguard/src/com/android/keyguard/EmergencyButton.java
    -@@ -28,13 +28,16 @@ import android.os.UserHandle;
    - import android.telecom.TelecomManager;
    - import android.util.AttributeSet;
    - import android.util.Slog;
    -+import android.view.MotionEvent;
    - import android.view.View;
    -+import android.view.ViewConfiguration;
    - import android.widget.Button;
    - 
    - import com.android.internal.logging.MetricsLogger;
    - import com.android.internal.logging.MetricsProto.MetricsEvent;
    - import com.android.internal.telephony.IccCardConstants.State;
    - import com.android.internal.widget.LockPatternUtils;
    -+import com.android.internal.policy.EmergencyAffordanceManager;
    - 
    - /**
    -  * This class implements a smart emergency button that updates itself based
    -@@ -51,7 +54,10 @@ public class EmergencyButton extends Button {
    -                     | Intent.FLAG_ACTIVITY_CLEAR_TOP);
    - 
    -     private static final String LOG_TAG = "EmergencyButton";
    -+    private final EmergencyAffordanceManager mEmergencyAffordanceManager;
    - 
    -+    private int mDownX;
    -+    private int mDownY;
    -     KeyguardUpdateMonitorCallback mInfoCallback = new KeyguardUpdateMonitorCallback() {
    - 
    -         @Override
    -@@ -64,6 +70,7 @@ public class EmergencyButton extends Button {
    -             updateEmergencyCallButton();
    -         }
    -     };
    -+    private boolean mLongPressWasDragged;
    - 
    -     public interface EmergencyButtonCallback {
    -         public void onEmergencyButtonClickedWhenInCall();
    -@@ -86,6 +93,7 @@ public class EmergencyButton extends Button {
    -                 com.android.internal.R.bool.config_voice_capable);
    -         mEnableEmergencyCallWhileSimLocked = mContext.getResources().getBoolean(
    -                 com.android.internal.R.bool.config_enable_emergency_call_while_sim_locked);
    -+        mEmergencyAffordanceManager = new EmergencyAffordanceManager(context);
    -     }
    - 
    -     @Override
    -@@ -110,10 +118,45 @@ public class EmergencyButton extends Button {
    -                 takeEmergencyCallAction();
    -             }
    -         });
    -+        setOnLongClickListener(new OnLongClickListener() {
    -+            @Override
    -+            public boolean onLongClick(View v) {
    -+                if (!mLongPressWasDragged
    -+                        && mEmergencyAffordanceManager.needsEmergencyAffordance()) {
    -+                    mEmergencyAffordanceManager.performEmergencyCall();
    -+                    return true;
    -+                }
    -+                return false;
    -+            }
    -+        });
    -         updateEmergencyCallButton();
    -     }
    - 
    -     @Override
    -+    public boolean onTouchEvent(MotionEvent event) {
    -+        final int x = (int) event.getX();
    -+        final int y = (int) event.getY();
    -+        if (event.getActionMasked() == MotionEvent.ACTION_DOWN) {
    -+            mDownX = x;
    -+            mDownY = y;
    -+            mLongPressWasDragged = false;
    -+        } else {
    -+            final int xDiff = Math.abs(x - mDownX);
    -+            final int yDiff = Math.abs(y - mDownY);
    -+            int touchSlop = ViewConfiguration.get(mContext).getScaledTouchSlop();
    -+            if (Math.abs(yDiff) > touchSlop || Math.abs(xDiff) > touchSlop) {
    -+                mLongPressWasDragged = true;
    -+            }
    -+        }
    -+        return super.onTouchEvent(event);
    -+    }
    -+
    -+    @Override
    -+    public boolean performLongClick() {
    -+        return super.performLongClick();
    -+    }
    -+
    -+    @Override
    -     protected void onConfigurationChanged(Configuration newConfig) {
    -         super.onConfigurationChanged(newConfig);
    -         updateEmergencyCallButton();
    -diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardPINView.java b/packages/Keyguard/src/com/android/keyguard/KeyguardPINView.java
    -index 4f5152a..285b1ae 100644
    ---- a/packages/Keyguard/src/com/android/keyguard/KeyguardPINView.java
    -+++ b/packages/Keyguard/src/com/android/keyguard/KeyguardPINView.java
    -@@ -16,12 +16,8 @@
    - 
    - package com.android.keyguard;
    - 
    --import android.animation.Animator;
    --import android.animation.ObjectAnimator;
    - import android.content.Context;
    - import android.util.AttributeSet;
    --import android.view.RenderNode;
    --import android.view.RenderNodeAnimator;
    - import android.view.View;
    - import android.view.ViewGroup;
    - import android.view.animation.AnimationUtils;
    -@@ -144,9 +140,10 @@ public class KeyguardPINView extends KeyguardPinBasedInputView {
    -         setTranslationY(0);
    -         AppearAnimationUtils.startTranslationYAnimation(this, 0 /* delay */, 280 /* duration */,
    -                 mDisappearYTranslation, mDisappearAnimationUtils.getInterpolator());
    --        DisappearAnimationUtils disappearAnimationUtils = mKeyguardUpdateMonitor.isUserUnlocked()
    --                ? mDisappearAnimationUtils
    --                : mDisappearAnimationUtilsLocked;
    -+        DisappearAnimationUtils disappearAnimationUtils = mKeyguardUpdateMonitor
    -+                .needsSlowUnlockTransition()
    -+                        ? mDisappearAnimationUtilsLocked
    -+                        : mDisappearAnimationUtils;
    -         disappearAnimationUtils.startAnimation2d(mViews,
    -                 new Runnable() {
    -                     @Override
    -diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardPatternView.java b/packages/Keyguard/src/com/android/keyguard/KeyguardPatternView.java
    -index 84b90c4..506f77d 100644
    ---- a/packages/Keyguard/src/com/android/keyguard/KeyguardPatternView.java
    -+++ b/packages/Keyguard/src/com/android/keyguard/KeyguardPatternView.java
    -@@ -408,9 +408,9 @@ public class KeyguardPatternView extends LinearLayout implements KeyguardSecurit
    - 
    -     @Override
    -     public boolean startDisappearAnimation(final Runnable finishRunnable) {
    --        float durationMultiplier = mKeyguardUpdateMonitor.isUserUnlocked()
    --                ? 1f
    --                : DISAPPEAR_MULTIPLIER_LOCKED;
    -+        float durationMultiplier = mKeyguardUpdateMonitor.needsSlowUnlockTransition()
    -+                ? DISAPPEAR_MULTIPLIER_LOCKED
    -+                : 1f;
    -         mLockPatternView.clearPattern();
    -         enableClipping(false);
    -         setTranslationY(0);
    -@@ -419,9 +419,10 @@ public class KeyguardPatternView extends LinearLayout implements KeyguardSecurit
    -                 -mDisappearAnimationUtils.getStartTranslation(),
    -                 mDisappearAnimationUtils.getInterpolator());
    - 
    --        DisappearAnimationUtils disappearAnimationUtils = mKeyguardUpdateMonitor.isUserUnlocked()
    --                ? mDisappearAnimationUtils
    --                : mDisappearAnimationUtilsLocked;
    -+        DisappearAnimationUtils disappearAnimationUtils = mKeyguardUpdateMonitor
    -+                .needsSlowUnlockTransition()
    -+                        ? mDisappearAnimationUtilsLocked
    -+                        : mDisappearAnimationUtils;
    -         disappearAnimationUtils.startAnimation2d(mLockPatternView.getCellStates(),
    -                 () -> {
    -                     enableClipping(true);
    -diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitor.java b/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitor.java
    -index 56f3741..a9f6dc9 100644
    ---- a/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitor.java
    -+++ b/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitor.java
    -@@ -16,6 +16,7 @@
    - 
    - package com.android.keyguard;
    - 
    -+import static android.content.Intent.ACTION_USER_UNLOCKED;
    - import static android.os.BatteryManager.BATTERY_HEALTH_UNKNOWN;
    - import static android.os.BatteryManager.BATTERY_STATUS_FULL;
    - import static android.os.BatteryManager.BATTERY_STATUS_UNKNOWN;
    -@@ -34,9 +35,12 @@ import android.app.PendingIntent;
    - import android.app.admin.DevicePolicyManager;
    - import android.app.trust.TrustManager;
    - import android.content.BroadcastReceiver;
    -+import android.content.ComponentName;
    - import android.content.Context;
    - import android.content.Intent;
    - import android.content.IntentFilter;
    -+import android.content.pm.PackageManager;
    -+import android.content.pm.ResolveInfo;
    - import android.database.ContentObserver;
    - import android.graphics.Bitmap;
    - import android.hardware.fingerprint.FingerprintManager;
    -@@ -108,12 +112,6 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener {
    - 
    -     private static final String PERMISSION_SELF = "com.android.systemui.permission.SELF";
    - 
    --    /**
    --     * Milliseconds after unlocking with fingerprint times out, i.e. the user has to use a
    --     * strong auth method like password, PIN or pattern.
    --     */
    --    private static final long FINGERPRINT_UNLOCK_TIMEOUT_MS = 72 * 60 * 60 * 1000;
    --
    -     // Callback messages
    -     private static final int MSG_TIME_UPDATE = 301;
    -     private static final int MSG_BATTERY_UPDATE = 302;
    -@@ -138,6 +136,8 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener {
    -     private static final int MSG_SERVICE_STATE_CHANGE = 330;
    -     private static final int MSG_SCREEN_TURNED_ON = 331;
    -     private static final int MSG_SCREEN_TURNED_OFF = 332;
    -+    private static final int MSG_DREAMING_STATE_CHANGED = 333;
    -+    private static final int MSG_USER_UNLOCKED = 334;
    - 
    -     /** Fingerprint state: Not listening to fingerprint. */
    -     private static final int FINGERPRINT_STATE_STOPPED = 0;
    -@@ -159,6 +159,9 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener {
    - 
    -     private static final int DEFAULT_CHARGING_VOLTAGE_MICRO_VOLT = 5000000;
    - 
    -+    private static final ComponentName FALLBACK_HOME_COMPONENT = new ComponentName(
    -+            "com.android.settings", "com.android.settings.FallbackHome");
    -+
    -     private static KeyguardUpdateMonitor sInstance;
    - 
    -     private final Context mContext;
    -@@ -177,7 +180,7 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener {
    -     private boolean mGoingToSleep;
    -     private boolean mBouncer;
    -     private boolean mBootCompleted;
    --    private boolean mUserUnlocked;
    -+    private boolean mNeedsSlowUnlockTransition;
    -     private boolean mHasLockscreenWallpaper;
    - 
    -     // Device provisioning state
    -@@ -287,6 +290,12 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener {
    -                     handleScreenTurnedOff();
    -                     Trace.endSection();
    -                     break;
    -+                case MSG_DREAMING_STATE_CHANGED:
    -+                    handleDreamingStateChanged(msg.arg1);
    -+                    break;
    -+                case MSG_USER_UNLOCKED:
    -+                    handleUserUnlocked();
    -+                    break;
    -             }
    -         }
    -     };
    -@@ -380,7 +389,7 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener {
    -     }
    - 
    -     /** @return List of SubscriptionInfo records, maybe empty but never null */
    --    List<SubscriptionInfo> getSubscriptionInfo(boolean forceReload) {
    -+    public List<SubscriptionInfo> getSubscriptionInfo(boolean forceReload) {
    -         List<SubscriptionInfo> sil = mSubscriptionInfo;
    -         if (sil == null || forceReload) {
    -             sil = mSubscriptionManager.getActiveSubscriptionInfoList();
    -@@ -572,8 +581,8 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener {
    -                 && !hasFingerprintUnlockTimedOut(sCurrentUser);
    -     }
    - 
    --    public boolean isUserUnlocked() {
    --        return mUserUnlocked;
    -+    public boolean needsSlowUnlockTransition() {
    -+        return mNeedsSlowUnlockTransition;
    -     }
    - 
    -     public StrongAuthTracker getStrongAuthTracker() {
    -@@ -598,7 +607,10 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener {
    -     }
    - 
    -     private void scheduleStrongAuthTimeout() {
    --        long when = SystemClock.elapsedRealtime() + FINGERPRINT_UNLOCK_TIMEOUT_MS;
    -+        final DevicePolicyManager dpm =
    -+                (DevicePolicyManager) mContext.getSystemService(Context.DEVICE_POLICY_SERVICE);
    -+        long when = SystemClock.elapsedRealtime() + dpm.getRequiredStrongAuthTimeout(null,
    -+                sCurrentUser);
    -         Intent intent = new Intent(ACTION_STRONG_AUTH_TIMEOUT);
    -         intent.putExtra(USER_ID, sCurrentUser);
    -         PendingIntent sender = PendingIntent.getBroadcast(mContext,
    -@@ -716,6 +728,8 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener {
    -             } else if (DevicePolicyManager.ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED
    -                     .equals(action)) {
    -                 mHandler.sendEmptyMessage(MSG_DPM_STATE_CHANGED);
    -+            } else if (ACTION_USER_UNLOCKED.equals(action)) {
    -+                mHandler.sendEmptyMessage(MSG_USER_UNLOCKED);
    -             }
    -         }
    -     };
    -@@ -984,6 +998,17 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener {
    -         }
    -     }
    - 
    -+    private void handleDreamingStateChanged(int dreamStart) {
    -+        final int count = mCallbacks.size();
    -+        boolean showingDream = dreamStart == 1;
    -+        for (int i = 0; i < count; i++) {
    -+            KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get();
    -+            if (cb != null) {
    -+                cb.onDreamingStateChanged(showingDream);
    -+            }
    -+        }
    -+    }
    -+
    -     /**
    -      * IMPORTANT: Must be called from UI thread.
    -      */
    -@@ -1007,6 +1032,16 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener {
    -         }
    -     }
    - 
    -+    private void handleUserUnlocked() {
    -+        mNeedsSlowUnlockTransition = resolveNeedsSlowUnlockTransition();
    -+        for (int i = 0; i < mCallbacks.size(); i++) {
    -+            KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get();
    -+            if (cb != null) {
    -+                cb.onUserUnlocked();
    -+            }
    -+        }
    -+    }
    -+
    -     private KeyguardUpdateMonitor(Context context) {
    -         mContext = context;
    -         mSubscriptionManager = SubscriptionManager.from(context);
    -@@ -1047,6 +1082,7 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener {
    -         allUserFilter.addAction(ACTION_FACE_UNLOCK_STARTED);
    -         allUserFilter.addAction(ACTION_FACE_UNLOCK_STOPPED);
    -         allUserFilter.addAction(DevicePolicyManager.ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED);
    -+        allUserFilter.addAction(ACTION_USER_UNLOCKED);
    -         context.registerReceiverAsUser(mBroadcastAllReceiver, UserHandle.ALL, allUserFilter,
    -                 null, null);
    - 
    -@@ -1444,7 +1480,18 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener {
    -     private void handleKeyguardReset() {
    -         if (DEBUG) Log.d(TAG, "handleKeyguardReset");
    -         updateFingerprintListeningState();
    --        mUserUnlocked = mUserManager.isUserUnlocked(getCurrentUser());
    -+        mNeedsSlowUnlockTransition = resolveNeedsSlowUnlockTransition();
    -+    }
    -+
    -+    private boolean resolveNeedsSlowUnlockTransition() {
    -+        if (mUserManager.isUserUnlocked(getCurrentUser())) {
    -+            return false;
    -+        }
    -+        Intent homeIntent = new Intent(Intent.ACTION_MAIN)
    -+                .addCategory(Intent.CATEGORY_HOME);
    -+        ResolveInfo resolveInfo = mContext.getPackageManager().resolveActivity(homeIntent,
    -+                0 /* flags */);
    -+        return FALLBACK_HOME_COMPONENT.equals(resolveInfo.getComponentInfo().getComponentName());
    -     }
    - 
    -     /**
    -@@ -1719,6 +1766,14 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener {
    -         mHandler.sendEmptyMessage(MSG_SCREEN_TURNED_OFF);
    -     }
    - 
    -+    public void dispatchDreamingStarted() {
    -+        mHandler.sendMessage(mHandler.obtainMessage(MSG_DREAMING_STATE_CHANGED, 1, 0));
    -+    }
    -+
    -+    public void dispatchDreamingStopped() {
    -+        mHandler.sendMessage(mHandler.obtainMessage(MSG_DREAMING_STATE_CHANGED, 0, 0));
    -+    }
    -+
    -     public boolean isDeviceInteractive() {
    -         return mDeviceInteractive;
    -     }
    -diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitorCallback.java b/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitorCallback.java
    -index 4a2d356..14d6b59 100644
    ---- a/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitorCallback.java
    -+++ b/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitorCallback.java
    -@@ -128,6 +128,11 @@ public class KeyguardUpdateMonitorCallback {
    -     public void onUserInfoChanged(int userId) { }
    - 
    -     /**
    -+     * Called when a user got unlocked.
    -+     */
    -+    public void onUserUnlocked() { }
    -+
    -+    /**
    -      * Called when boot completed.
    -      *
    -      * Note, this callback will only be received if boot complete occurs after registering with
    -@@ -245,4 +250,10 @@ public class KeyguardUpdateMonitorCallback {
    -      * Called when the state whether we have a lockscreen wallpaper has changed.
    -      */
    -     public void onHasLockscreenWallpaperChanged(boolean hasLockscreenWallpaper) { }
    -+
    -+    /**
    -+     * Called when the dream's window state is changed.
    -+     * @param dreaming true if the dream's window has been created and is visible
    -+     */
    -+    public void onDreamingStateChanged(boolean dreaming) { }
    - }
    -diff --git a/packages/MtpDocumentsProvider/src/com/android/mtp/MtpDatabase.java b/packages/MtpDocumentsProvider/src/com/android/mtp/MtpDatabase.java
    -index cce619e..4950af3 100644
    ---- a/packages/MtpDocumentsProvider/src/com/android/mtp/MtpDatabase.java
    -+++ b/packages/MtpDocumentsProvider/src/com/android/mtp/MtpDatabase.java
    -@@ -873,7 +873,7 @@ class MtpDatabase {
    -     }
    - 
    -     private static int getRootFlags(int[] operationsSupported) {
    --        int rootFlag = Root.FLAG_SUPPORTS_IS_CHILD;
    -+        int rootFlag = Root.FLAG_SUPPORTS_IS_CHILD | Root.FLAG_LOCAL_ONLY;
    -         if (MtpDeviceRecord.isWritingSupported(operationsSupported)) {
    -             rootFlag |= Root.FLAG_SUPPORTS_CREATE;
    -         }
    -diff --git a/packages/MtpDocumentsProvider/src/com/android/mtp/MtpManager.java b/packages/MtpDocumentsProvider/src/com/android/mtp/MtpManager.java
    -index 90dd440..8f254e9 100644
    ---- a/packages/MtpDocumentsProvider/src/com/android/mtp/MtpManager.java
    -+++ b/packages/MtpDocumentsProvider/src/com/android/mtp/MtpManager.java
    -@@ -282,8 +282,8 @@ class MtpManager {
    -             }
    -             final MtpDeviceInfo info = mtpDevice.getDeviceInfo();
    -             if (info != null) {
    --                operationsSupported = mtpDevice.getDeviceInfo().getOperationsSupported();
    --                eventsSupported = mtpDevice.getDeviceInfo().getEventsSupported();
    -+                operationsSupported = info.getOperationsSupported();
    -+                eventsSupported = info.getEventsSupported();
    -             }
    -         } else {
    -             roots = new MtpRoot[0];
    -diff --git a/packages/MtpDocumentsProvider/tests/src/com/android/mtp/MtpDatabaseTest.java b/packages/MtpDocumentsProvider/tests/src/com/android/mtp/MtpDatabaseTest.java
    -index 404047b..8c13c81 100644
    ---- a/packages/MtpDocumentsProvider/tests/src/com/android/mtp/MtpDatabaseTest.java
    -+++ b/packages/MtpDocumentsProvider/tests/src/com/android/mtp/MtpDatabaseTest.java
    -@@ -128,7 +128,7 @@ public class MtpDatabaseTest extends AndroidTestCase {
    -             cursor.moveToNext();
    -             assertEquals(1, getInt(cursor, Root.COLUMN_ROOT_ID));
    -             assertEquals(
    --                    Root.FLAG_SUPPORTS_IS_CHILD | Root.FLAG_SUPPORTS_CREATE,
    -+                    Root.FLAG_SUPPORTS_IS_CHILD | Root.FLAG_SUPPORTS_CREATE | Root.FLAG_LOCAL_ONLY,
    -                     getInt(cursor, Root.COLUMN_FLAGS));
    -             assertEquals(R.drawable.ic_root_mtp, getInt(cursor, Root.COLUMN_ICON));
    -             assertEquals("Device Storage", getString(cursor, Root.COLUMN_TITLE));
    -diff --git a/packages/MtpDocumentsProvider/tests/src/com/android/mtp/MtpDocumentsProviderTest.java b/packages/MtpDocumentsProvider/tests/src/com/android/mtp/MtpDocumentsProviderTest.java
    -index 9ed15c8..d19b460 100644
    ---- a/packages/MtpDocumentsProvider/tests/src/com/android/mtp/MtpDocumentsProviderTest.java
    -+++ b/packages/MtpDocumentsProvider/tests/src/com/android/mtp/MtpDocumentsProviderTest.java
    -@@ -210,7 +210,11 @@ public class MtpDocumentsProviderTest extends AndroidTestCase {
    -             assertEquals(2, cursor.getCount());
    -             cursor.moveToNext();
    -             assertEquals("1", cursor.getString(0));
    --            assertEquals(Root.FLAG_SUPPORTS_IS_CHILD | Root.FLAG_SUPPORTS_CREATE, cursor.getInt(1));
    -+            assertEquals(
    -+                    Root.FLAG_SUPPORTS_IS_CHILD |
    -+                    Root.FLAG_SUPPORTS_CREATE |
    -+                    Root.FLAG_LOCAL_ONLY,
    -+                    cursor.getInt(1));
    -             assertEquals(R.drawable.ic_root_mtp, cursor.getInt(2));
    -             assertEquals("Device A Storage A", cursor.getString(3));
    -             assertEquals("1", cursor.getString(4));
    -@@ -225,7 +229,8 @@ public class MtpDocumentsProviderTest extends AndroidTestCase {
    -             cursor.moveToNext();
    -             cursor.moveToNext();
    -             assertEquals("2", cursor.getString(0));
    --            assertEquals(Root.FLAG_SUPPORTS_IS_CHILD, cursor.getInt(1));
    -+            assertEquals(
    -+                    Root.FLAG_SUPPORTS_IS_CHILD | Root.FLAG_LOCAL_ONLY, cursor.getInt(1));
    -             assertEquals(R.drawable.ic_root_mtp, cursor.getInt(2));
    -             assertEquals("Device B Storage B", cursor.getString(3));
    -             assertEquals("2", cursor.getString(4));
    -@@ -271,7 +276,9 @@ public class MtpDocumentsProviderTest extends AndroidTestCase {
    - 
    -             cursor.moveToNext();
    -             assertEquals("1", cursor.getString(0));
    --            assertEquals(Root.FLAG_SUPPORTS_IS_CHILD | Root.FLAG_SUPPORTS_CREATE, cursor.getInt(1));
    -+            assertEquals(
    -+                    Root.FLAG_SUPPORTS_IS_CHILD | Root.FLAG_SUPPORTS_CREATE | Root.FLAG_LOCAL_ONLY,
    -+                    cursor.getInt(1));
    -             assertEquals(R.drawable.ic_root_mtp, cursor.getInt(2));
    -             assertEquals("Device A", cursor.getString(3));
    -             assertEquals("1", cursor.getString(4));
    -@@ -279,7 +286,9 @@ public class MtpDocumentsProviderTest extends AndroidTestCase {
    - 
    -             cursor.moveToNext();
    -             assertEquals("2", cursor.getString(0));
    --            assertEquals(Root.FLAG_SUPPORTS_IS_CHILD | Root.FLAG_SUPPORTS_CREATE, cursor.getInt(1));
    -+            assertEquals(
    -+                    Root.FLAG_SUPPORTS_IS_CHILD | Root.FLAG_SUPPORTS_CREATE | Root.FLAG_LOCAL_ONLY,
    -+                    cursor.getInt(1));
    -             assertEquals(R.drawable.ic_root_mtp, cursor.getInt(2));
    -             assertEquals("Device B Storage B", cursor.getString(3));
    -             assertEquals("2", cursor.getString(4));
    -diff --git a/packages/PrintSpooler/res/layout/print_activity.xml b/packages/PrintSpooler/res/layout/print_activity.xml
    -index 2db6fb0..31a776c 100644
    ---- a/packages/PrintSpooler/res/layout/print_activity.xml
    -+++ b/packages/PrintSpooler/res/layout/print_activity.xml
    -@@ -16,7 +16,6 @@
    - 
    - <com.android.printspooler.widget.PrintContentView
    -         xmlns:android="http://schemas.android.com/apk/res/android"
    --        xmlns:printspooler="http://schemas.android.com/apk/res/com.android.printspooler"
    -     android:id="@+id/options_content"
    -     android:layout_width="fill_parent"
    -     android:layout_height="fill_parent">
    -@@ -28,12 +27,14 @@
    -         android:layout_width="fill_parent"
    -         android:layout_height="wrap_content"
    -         android:paddingStart="8dip"
    -+        android:layout_marginEnd="16dp"
    -         android:elevation="@dimen/preview_controls_elevation"
    -         android:background="?android:attr/colorPrimary">
    - 
    -         <Spinner
    -             android:id="@+id/destination_spinner"
    --            android:layout_width="@dimen/preview_destination_spinner_width"
    -+            android:layout_width="wrap_content"
    -+            android:minWidth="@dimen/preview_destination_spinner_width"
    -             android:layout_height="wrap_content"
    -             android:layout_marginTop="4dip"
    -             android:dropDownWidth="wrap_content"
    -diff --git a/packages/PrintSpooler/res/layout/printer_dropdown_item.xml b/packages/PrintSpooler/res/layout/printer_dropdown_item.xml
    -index 103c157..0d8a90a 100644
    ---- a/packages/PrintSpooler/res/layout/printer_dropdown_item.xml
    -+++ b/packages/PrintSpooler/res/layout/printer_dropdown_item.xml
    -@@ -16,7 +16,8 @@
    - 
    - <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    -       android:layout_width="fill_parent"
    --      android:layout_height="?android:attr/listPreferredItemHeightSmall"
    -+      android:layout_height="wrap_content"
    -+      android:minHeight="?android:attr/listPreferredItemHeightSmall"
    -       style="?android:attr/spinnerItemStyle"
    -       android:orientation="horizontal"
    -       android:gravity="start|center_vertical">
    -diff --git a/packages/PrintSpooler/res/values-zh-rCN/strings.xml b/packages/PrintSpooler/res/values-zh-rCN/strings.xml
    -index 3debf8e..d4e7963 100644
    ---- a/packages/PrintSpooler/res/values-zh-rCN/strings.xml
    -+++ b/packages/PrintSpooler/res/values-zh-rCN/strings.xml
    -@@ -60,7 +60,7 @@
    -       <item quantity="one">找到 <xliff:g id="COUNT_0">%1$s</xliff:g> 台打印机</item>
    -     </plurals>
    -     <string name="printer_extended_description_template" msgid="1366699227703381874">"<xliff:g id="PRINT_SERVICE_LABEL">%1$s</xliff:g> - <xliff:g id="PRINTER_DESCRIPTION">%2$s</xliff:g>"</string>
    --    <string name="printer_info_desc" msgid="7181988788991581654">"关于此打印机的更多信息"</string>
    -+    <string name="printer_info_desc" msgid="7181988788991581654">"此打印机的详细信息"</string>
    -     <string name="could_not_create_file" msgid="3425025039427448443">"无法创建文件"</string>
    -     <string name="print_services_disabled_toast" msgid="9089060734685174685">"部分打印服务已停用"</string>
    -     <string name="print_searching_for_printers" msgid="6550424555079932867">"正在搜索打印机"</string>
    -diff --git a/packages/SettingsLib/res/values-af/strings.xml b/packages/SettingsLib/res/values-af/strings.xml
    -index c16e08a..66f2f87 100644
    ---- a/packages/SettingsLib/res/values-af/strings.xml
    -+++ b/packages/SettingsLib/res/values-af/strings.xml
    -@@ -28,7 +28,8 @@
    -     <string name="wifi_disabled_wifi_failure" msgid="3081668066612876581">"WiFi-verbinding het misluk"</string>
    -     <string name="wifi_disabled_password_failure" msgid="8659805351763133575">"Stawingsprobleem"</string>
    -     <string name="wifi_not_in_range" msgid="1136191511238508967">"Nie binne ontvangs nie"</string>
    --    <string name="wifi_no_internet" msgid="9151470775868728896">"Geen internettoegang bespeur nie, sal nie outomaties herkoppel nie."</string>
    -+    <string name="wifi_no_internet_no_reconnect" msgid="2211781637653149657">"Geen internettoegang word bespeur nie, sal nie outomaties herkoppel nie."</string>
    -+    <string name="wifi_no_internet" msgid="5011955173375805204">"Geen internettoegang nie."</string>
    -     <string name="saved_network" msgid="4352716707126620811">"Gestoor deur <xliff:g id="NAME">%1$s</xliff:g>"</string>
    -     <string name="connected_via_wfa" msgid="3805736726317410714">"Gekoppel via Wi-Fi-assistent"</string>
    -     <string name="connected_via_passpoint" msgid="2826205693803088747">"Gekoppel via %1$s"</string>
    -@@ -233,8 +234,6 @@
    -     <string name="debug_layout_summary" msgid="2001775315258637682">"Wys snitgrense, kantlyne, ens."</string>
    -     <string name="force_rtl_layout_all_locales" msgid="2259906643093138978">"Dwing RTL-uitlegrigting"</string>
    -     <string name="force_rtl_layout_all_locales_summary" msgid="9192797796616132534">"Dwing skermuitlegrigting na RTL vir alle locales"</string>
    --    <string name="show_cpu_usage" msgid="2389212910758076024">"Wys CPU-verbruik"</string>
    --    <string name="show_cpu_usage_summary" msgid="2113341923988958266">"Skermlaag wys huidige CPU-gebruik"</string>
    -     <string name="force_hw_ui" msgid="6426383462520888732">"Forseer GPU-lewering"</string>
    -     <string name="force_hw_ui_summary" msgid="5535991166074861515">"Dwing gebruik van GPU vir 2D-tekening"</string>
    -     <string name="force_msaa" msgid="7920323238677284387">"Dwing 4x MSAA"</string>
    -@@ -341,4 +340,5 @@
    -     <string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"Grootste"</string>
    -     <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Gepasmaak (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
    -     <string name="help_feedback_label" msgid="6815040660801785649">"Hulp en terugvoer"</string>
    -+    <string name="content_description_menu_button" msgid="8182594799812351266">"Kieslys"</string>
    - </resources>
    -diff --git a/packages/SettingsLib/res/values-am/strings.xml b/packages/SettingsLib/res/values-am/strings.xml
    -index 6e9dcd7..cfda4ab 100644
    ---- a/packages/SettingsLib/res/values-am/strings.xml
    -+++ b/packages/SettingsLib/res/values-am/strings.xml
    -@@ -28,7 +28,8 @@
    -     <string name="wifi_disabled_wifi_failure" msgid="3081668066612876581">"የWiFi ግንኙነት መሰናከል"</string>
    -     <string name="wifi_disabled_password_failure" msgid="8659805351763133575">"የማረጋገጫ ችግር"</string>
    -     <string name="wifi_not_in_range" msgid="1136191511238508967">"በክልል ውስጥ የለም"</string>
    --    <string name="wifi_no_internet" msgid="9151470775868728896">"ምንም የበይነ መረብ መዳረሻ ተፈልጎ አልተገኘም፣ በራስ-ሰር እንደገና እንዲገናኝ አይደረግም።"</string>
    -+    <string name="wifi_no_internet_no_reconnect" msgid="2211781637653149657">"ምንም የበይነ መረብ መዳረሻ አልተገኘም፣ በራስ-ሰር እንደገና እንዲገናኝ አይደረግም።"</string>
    -+    <string name="wifi_no_internet" msgid="5011955173375805204">"ምንም የበይነመረብ መዳረሻ የለም።"</string>
    -     <string name="saved_network" msgid="4352716707126620811">"የተቀመጠው በ<xliff:g id="NAME">%1$s</xliff:g>"</string>
    -     <string name="connected_via_wfa" msgid="3805736726317410714">"በWi‑Fi ረዳት አማካኝነት ተገናኝቷል"</string>
    -     <string name="connected_via_passpoint" msgid="2826205693803088747">"በ%1$s በኩል መገናኘት"</string>
    -@@ -233,8 +234,6 @@
    -     <string name="debug_layout_summary" msgid="2001775315258637682">"የቅንጥብ ገደቦች፣ ጠርዞች፣ ወዘተ አሳይ"</string>
    -     <string name="force_rtl_layout_all_locales" msgid="2259906643093138978">"የቀኝ-ወደ-ግራ አቀማመጥ አቅጣጫ አስገድድ"</string>
    -     <string name="force_rtl_layout_all_locales_summary" msgid="9192797796616132534">"ለሁሉም አካባቢዎች የማያ ገጽ አቀማመጥ ከቀኝ-ወደ-ግራ እንዲሆን አስገድድ"</string>
    --    <string name="show_cpu_usage" msgid="2389212910758076024">"የCPU አጠቃቀም አሳይ"</string>
    --    <string name="show_cpu_usage_summary" msgid="2113341923988958266">"የማያ ተደራቢ የአሁኑን የCPU አጠቃቀም  እያሳየ ነው።"</string>
    -     <string name="force_hw_ui" msgid="6426383462520888732">"GPU ምላሽ መስጠትን አስገድድ"</string>
    -     <string name="force_hw_ui_summary" msgid="5535991166074861515">"ለ2-ልኬት መሳል የGPU ስራ አስገድድ"</string>
    -     <string name="force_msaa" msgid="7920323238677284387">"4x MSAA አስገድድ"</string>
    -@@ -341,4 +340,5 @@
    -     <string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"በጣም ተለቅ ያለ"</string>
    -     <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"ብጁ (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
    -     <string name="help_feedback_label" msgid="6815040660801785649">"እገዛ እና ግብረመልስ"</string>
    -+    <string name="content_description_menu_button" msgid="8182594799812351266">"ምናሌ"</string>
    - </resources>
    -diff --git a/packages/SettingsLib/res/values-ar/strings.xml b/packages/SettingsLib/res/values-ar/strings.xml
    -index ee579dc..e65feff 100644
    ---- a/packages/SettingsLib/res/values-ar/strings.xml
    -+++ b/packages/SettingsLib/res/values-ar/strings.xml
    -@@ -28,7 +28,8 @@
    -     <string name="wifi_disabled_wifi_failure" msgid="3081668066612876581">"‏أخفق اتصال WiFi"</string>
    -     <string name="wifi_disabled_password_failure" msgid="8659805351763133575">"حدثت مشكلة في المصادقة"</string>
    -     <string name="wifi_not_in_range" msgid="1136191511238508967">"ليست في النطاق"</string>
    --    <string name="wifi_no_internet" msgid="9151470775868728896">"لم يتم اكتشاف اتصال بالإنترنت."</string>
    -+    <string name="wifi_no_internet_no_reconnect" msgid="2211781637653149657">"لم يتم اكتشاف اتصال بالإنترنت، ولن تتم إعادة الاتصال تلقائيًا."</string>
    -+    <string name="wifi_no_internet" msgid="5011955173375805204">"لا يتوفر اتصال بالإنترنت."</string>
    -     <string name="saved_network" msgid="4352716707126620811">"تم الحفظ بواسطة <xliff:g id="NAME">%1$s</xliff:g>"</string>
    -     <string name="connected_via_wfa" msgid="3805736726317410714">"‏تم التوصيل عبر مساعد Wi-Fi"</string>
    -     <string name="connected_via_passpoint" msgid="2826205693803088747">"‏تم الاتصال عبر %1$s"</string>
    -@@ -233,8 +234,6 @@
    -     <string name="debug_layout_summary" msgid="2001775315258637682">"عرض حدود وهوامش المقطع وما إلى ذلك."</string>
    -     <string name="force_rtl_layout_all_locales" msgid="2259906643093138978">"فرض اتجاه التنسيق ليكون من اليمين إلى اليسار"</string>
    -     <string name="force_rtl_layout_all_locales_summary" msgid="9192797796616132534">"فرض اتجاه تنسيق الشاشة ليكون من اليمين إلى اليسار لجميع اللغات"</string>
    --    <string name="show_cpu_usage" msgid="2389212910758076024">"‏عرض استخدام CPU"</string>
    --    <string name="show_cpu_usage_summary" msgid="2113341923988958266">"‏عرض تراكب الشاشة لاستخدام CPU الحالي"</string>
    -     <string name="force_hw_ui" msgid="6426383462520888732">"‏فرض عرض رسومات GPU"</string>
    -     <string name="force_hw_ui_summary" msgid="5535991166074861515">"فرض استخدام وحدة معالجة الرسومات للرسم ثنائي الأبعاد"</string>
    -     <string name="force_msaa" msgid="7920323238677284387">"‏فرض 4x MSAA"</string>
    -@@ -329,7 +328,7 @@
    -     <string name="home" msgid="3256884684164448244">"الشاشة الرئيسية للإعدادات"</string>
    -   <string-array name="battery_labels">
    -     <item msgid="8494684293649631252">"٠‏٪"</item>
    --    <item msgid="8934126114226089439">"٪۵۰"</item>
    -+    <item msgid="8934126114226089439">"٥٠٪"</item>
    -     <item msgid="1286113608943010849">"٪۱۰۰"</item>
    -   </string-array>
    -     <string name="charge_length_format" msgid="8978516217024434156">"قبل <xliff:g id="ID_1">%1$s</xliff:g>"</string>
    -@@ -341,4 +340,5 @@
    -     <string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"أكبر مستوى"</string>
    -     <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"مخصص (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
    -     <string name="help_feedback_label" msgid="6815040660801785649">"المساعدة والتعليقات"</string>
    -+    <string name="content_description_menu_button" msgid="8182594799812351266">"القائمة"</string>
    - </resources>
    -diff --git a/packages/SettingsLib/res/values-az-rAZ/strings.xml b/packages/SettingsLib/res/values-az-rAZ/strings.xml
    -index 60d0169..5aac49e 100644
    ---- a/packages/SettingsLib/res/values-az-rAZ/strings.xml
    -+++ b/packages/SettingsLib/res/values-az-rAZ/strings.xml
    -@@ -28,7 +28,8 @@
    -     <string name="wifi_disabled_wifi_failure" msgid="3081668066612876581">"WiFi Bağlantı Uğursuzluğu"</string>
    -     <string name="wifi_disabled_password_failure" msgid="8659805351763133575">"Autentifikasiya problemi"</string>
    -     <string name="wifi_not_in_range" msgid="1136191511238508967">"Diapazonda deyil"</string>
    --    <string name="wifi_no_internet" msgid="9151470775868728896">"İnternet bağlantısı tapılmadı, avtomatik olaraq yenidən qoşulmayacaq."</string>
    -+    <string name="wifi_no_internet_no_reconnect" msgid="2211781637653149657">"İnternet bağlantısı tapılmadı, avtomatik olaraq yenidən qoşulmayacaq."</string>
    -+    <string name="wifi_no_internet" msgid="5011955173375805204">"İnternet girişi yoxdur."</string>
    -     <string name="saved_network" msgid="4352716707126620811">"<xliff:g id="NAME">%1$s</xliff:g> tərəfindən saxlandı"</string>
    -     <string name="connected_via_wfa" msgid="3805736726317410714">"Wi‑Fi köməkçisi vasitəsilə qoşulub"</string>
    -     <string name="connected_via_passpoint" msgid="2826205693803088747">"%1$s vasitəsilə qoşuludur"</string>
    -@@ -233,8 +234,6 @@
    -     <string name="debug_layout_summary" msgid="2001775315258637682">"Klip sərhədləri, boşluqları və s. göstər"</string>
    -     <string name="force_rtl_layout_all_locales" msgid="2259906643093138978">"RTL düzən istiqamətinə məcbur edin"</string>
    -     <string name="force_rtl_layout_all_locales_summary" msgid="9192797796616132534">"Ekran düzən istiqamətini RTL üzərinə bütün yerli variantlar üçün məcbur edin"</string>
    --    <string name="show_cpu_usage" msgid="2389212910758076024">"CPU istifadəsini göstər"</string>
    --    <string name="show_cpu_usage_summary" msgid="2113341923988958266">"Ekran örtüşməsi cari CPU istifadəsini göstərir"</string>
    -     <string name="force_hw_ui" msgid="6426383462520888732">"GPU renderə məcbur edin"</string>
    -     <string name="force_hw_ui_summary" msgid="5535991166074861515">"2d rəsm üçün GPU məcburi istifadə"</string>
    -     <string name="force_msaa" msgid="7920323238677284387">"4x MSAA məcbur edin"</string>
    -@@ -341,4 +340,5 @@
    -     <string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"Ən böyük"</string>
    -     <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Fərdi (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
    -     <string name="help_feedback_label" msgid="6815040660801785649">"Yardım və rəy"</string>
    -+    <string name="content_description_menu_button" msgid="8182594799812351266">"Menyu"</string>
    - </resources>
    -diff --git a/packages/SettingsLib/res/values-b+sr+Latn/strings.xml b/packages/SettingsLib/res/values-b+sr+Latn/strings.xml
    -index 060a5fb..345c0bb 100644
    ---- a/packages/SettingsLib/res/values-b+sr+Latn/strings.xml
    -+++ b/packages/SettingsLib/res/values-b+sr+Latn/strings.xml
    -@@ -28,7 +28,8 @@
    -     <string name="wifi_disabled_wifi_failure" msgid="3081668066612876581">"Wi-Fi veza je otkazala"</string>
    -     <string name="wifi_disabled_password_failure" msgid="8659805351763133575">"Problem sa potvrdom autentičnosti"</string>
    -     <string name="wifi_not_in_range" msgid="1136191511238508967">"Nije u opsegu"</string>
    --    <string name="wifi_no_internet" msgid="9151470775868728896">"Pristup internetu nije otkriven, automatsko povezivanje nije moguće."</string>
    -+    <string name="wifi_no_internet_no_reconnect" msgid="2211781637653149657">"Pristup internetu nije otkriven, automatsko povezivanje nije moguće."</string>
    -+    <string name="wifi_no_internet" msgid="5011955173375805204">"Nema pristupa internetu."</string>
    -     <string name="saved_network" msgid="4352716707126620811">"Sačuvao/la je <xliff:g id="NAME">%1$s</xliff:g>"</string>
    -     <string name="connected_via_wfa" msgid="3805736726317410714">"Povezano preko Wi‑Fi pomoćnika"</string>
    -     <string name="connected_via_passpoint" msgid="2826205693803088747">"Veza je uspostavljena preko pristupne tačke %1$s"</string>
    -@@ -233,8 +234,6 @@
    -     <string name="debug_layout_summary" msgid="2001775315258637682">"Prikaži granice klipa, margine itd."</string>
    -     <string name="force_rtl_layout_all_locales" msgid="2259906643093138978">"Nametni smer rasporeda zdesna nalevo"</string>
    -     <string name="force_rtl_layout_all_locales_summary" msgid="9192797796616132534">"Nametni smer rasporeda ekrana zdesna nalevo za sve lokalitete"</string>
    --    <string name="show_cpu_usage" msgid="2389212910758076024">"Prik. upotrebu procesora"</string>
    --    <string name="show_cpu_usage_summary" msgid="2113341923988958266">"Postav. element sa trenutnom upotrebom procesora"</string>
    -     <string name="force_hw_ui" msgid="6426383462520888732">"Prinudni prikaz pom. GPU"</string>
    -     <string name="force_hw_ui_summary" msgid="5535991166074861515">"Prinudno koristi GPU za 2D crtanje"</string>
    -     <string name="force_msaa" msgid="7920323238677284387">"Nametni 4x MSAA"</string>
    -@@ -282,7 +281,7 @@
    -     <string name="enable_webview_multiprocess_desc" msgid="2485604010404197724">"Pokrećite WebView prikazivače zasebno"</string>
    -     <string name="select_webview_provider_title" msgid="4628592979751918907">"Primena WebView-a"</string>
    -     <string name="select_webview_provider_dialog_title" msgid="4370551378720004872">"Podesite primenu WebView-a"</string>
    --    <string name="select_webview_provider_toast_text" msgid="5466970498308266359">"Ovaj izbor više nije važeći. Pokušajte ponovo."</string>
    -+    <string name="select_webview_provider_toast_text" msgid="5466970498308266359">"Ovaj izbor više nije važeći. Probajte ponovo."</string>
    -     <string name="convert_to_file_encryption" msgid="3060156730651061223">"Konvertuj u šifrovanje datoteka"</string>
    -     <string name="convert_to_file_encryption_enabled" msgid="2861258671151428346">"Konvertuj..."</string>
    -     <string name="convert_to_file_encryption_done" msgid="7859766358000523953">"Već se koristi šifrovanje datoteka"</string>
    -@@ -341,4 +340,5 @@
    -     <string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"Najveći"</string>
    -     <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Prilagođeni (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
    -     <string name="help_feedback_label" msgid="6815040660801785649">"Pomoć i povratne informacije"</string>
    -+    <string name="content_description_menu_button" msgid="8182594799812351266">"Meni"</string>
    - </resources>
    -diff --git a/packages/SettingsLib/res/values-be-rBY/strings.xml b/packages/SettingsLib/res/values-be-rBY/strings.xml
    -index 03de8ba..52077fb 100644
    ---- a/packages/SettingsLib/res/values-be-rBY/strings.xml
    -+++ b/packages/SettingsLib/res/values-be-rBY/strings.xml
    -@@ -28,7 +28,8 @@
    -     <string name="wifi_disabled_wifi_failure" msgid="3081668066612876581">"Збой падлучэння Wi-Fi"</string>
    -     <string name="wifi_disabled_password_failure" msgid="8659805351763133575">"Праблема аўтэнтыфікацыі"</string>
    -     <string name="wifi_not_in_range" msgid="1136191511238508967">"Не ў зоне дасягальнасці"</string>
    --    <string name="wifi_no_internet" msgid="9151470775868728896">"Доступ да інтэрнэту не выяўлены, аўтаматычнае перападлучэнне не адбудзецца."</string>
    -+    <string name="wifi_no_internet_no_reconnect" msgid="2211781637653149657">"Доступ да інтэрнэту не выяўлены, аўтаматычнае перападключэнне не адбудзецца."</string>
    -+    <string name="wifi_no_internet" msgid="5011955173375805204">"Няма доступу да інтэрнэту."</string>
    -     <string name="saved_network" msgid="4352716707126620811">"Хто захаваў: <xliff:g id="NAME">%1$s</xliff:g>"</string>
    -     <string name="connected_via_wfa" msgid="3805736726317410714">"Падлучана праз памочніка Wi‑Fi"</string>
    -     <string name="connected_via_passpoint" msgid="2826205693803088747">"Падлучана праз %1$s"</string>
    -@@ -233,8 +234,6 @@
    -     <string name="debug_layout_summary" msgid="2001775315258637682">"Паказаць межы кліпу, палі і г. д."</string>
    -     <string name="force_rtl_layout_all_locales" msgid="2259906643093138978">"Прымусовая раскладка справа налева"</string>
    -     <string name="force_rtl_layout_all_locales_summary" msgid="9192797796616132534">"Прымусовая раскладка экрана справа налева для ўсіх рэгіянальных налад"</string>
    --    <string name="show_cpu_usage" msgid="2389212910758076024">"Паказаць выкарыстанне ЦП"</string>
    --    <string name="show_cpu_usage_summary" msgid="2113341923988958266">"Наклад на экран з бягучым выкарыстаннем працэсара"</string>
    -     <string name="force_hw_ui" msgid="6426383462520888732">"Прымусовае адлюстраванне GPU"</string>
    -     <string name="force_hw_ui_summary" msgid="5535991166074861515">"Прымусовае выкарыстанне GPU для 2-мерных чарцяжоў"</string>
    -     <string name="force_msaa" msgid="7920323238677284387">"Прымусовае выкананне 4x MSAA"</string>
    -@@ -341,4 +340,5 @@
    -     <string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"Найвялікшы"</string>
    -     <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Карыстальніцкі (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
    -     <string name="help_feedback_label" msgid="6815040660801785649">"Даведка і водгукі"</string>
    -+    <string name="content_description_menu_button" msgid="8182594799812351266">"Меню"</string>
    - </resources>
    -diff --git a/packages/SettingsLib/res/values-bg/strings.xml b/packages/SettingsLib/res/values-bg/strings.xml
    -index f6596dc..eba51b3 100644
    ---- a/packages/SettingsLib/res/values-bg/strings.xml
    -+++ b/packages/SettingsLib/res/values-bg/strings.xml
    -@@ -28,7 +28,8 @@
    -     <string name="wifi_disabled_wifi_failure" msgid="3081668066612876581">"Неуспешна връзка с Wi-Fi"</string>
    -     <string name="wifi_disabled_password_failure" msgid="8659805351763133575">"Проблем при удостоверяването"</string>
    -     <string name="wifi_not_in_range" msgid="1136191511238508967">"Извън обхват"</string>
    --    <string name="wifi_no_internet" msgid="9151470775868728896">"Не е открит достъп до интернет. Няма да се свърже отново автоматично."</string>
    -+    <string name="wifi_no_internet_no_reconnect" msgid="2211781637653149657">"Не е открит достъп до интернет. Връзката няма да се възобнови автоматично."</string>
    -+    <string name="wifi_no_internet" msgid="5011955173375805204">"Няма достъп до интернет."</string>
    -     <string name="saved_network" msgid="4352716707126620811">"Запазено от <xliff:g id="NAME">%1$s</xliff:g>"</string>
    -     <string name="connected_via_wfa" msgid="3805736726317410714">"Установена е връзка чрез помощника за Wi-Fi"</string>
    -     <string name="connected_via_passpoint" msgid="2826205693803088747">"Установена е връзка през „%1$s“"</string>
    -@@ -233,8 +234,6 @@
    -     <string name="debug_layout_summary" msgid="2001775315258637682">"Показв. на границите на изрязване, полетата и др."</string>
    -     <string name="force_rtl_layout_all_locales" msgid="2259906643093138978">"Принуд. оформл. отдясно наляво"</string>
    -     <string name="force_rtl_layout_all_locales_summary" msgid="9192797796616132534">"Принуд. оформл. на екрана отдясно наляво за вс. локали"</string>
    --    <string name="show_cpu_usage" msgid="2389212910758076024">"Употреба на процесора"</string>
    --    <string name="show_cpu_usage_summary" msgid="2113341923988958266">"Наслагване на екрана показва употр. на процесора"</string>
    -     <string name="force_hw_ui" msgid="6426383462520888732">"Принудително изобразяване"</string>
    -     <string name="force_hw_ui_summary" msgid="5535991166074861515">"Принуд. използв. на GPU за двуизмерно начертаване"</string>
    -     <string name="force_msaa" msgid="7920323238677284387">"Задаване на 4x MSAA"</string>
    -@@ -341,4 +340,5 @@
    -     <string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"Най-голямо"</string>
    -     <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Персонализирано (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
    -     <string name="help_feedback_label" msgid="6815040660801785649">"Помощ и отзиви"</string>
    -+    <string name="content_description_menu_button" msgid="8182594799812351266">"Меню"</string>
    - </resources>
    -diff --git a/packages/SettingsLib/res/values-bn-rBD/strings.xml b/packages/SettingsLib/res/values-bn-rBD/strings.xml
    -index 4a11198..4ad361b 100644
    ---- a/packages/SettingsLib/res/values-bn-rBD/strings.xml
    -+++ b/packages/SettingsLib/res/values-bn-rBD/strings.xml
    -@@ -28,7 +28,8 @@
    -     <string name="wifi_disabled_wifi_failure" msgid="3081668066612876581">"WiFi সংযোগের ব্যর্থতা"</string>
    -     <string name="wifi_disabled_password_failure" msgid="8659805351763133575">"প্রমাণীকরণ সমস্যা"</string>
    -     <string name="wifi_not_in_range" msgid="1136191511238508967">"পরিসরের মধ্যে নয়"</string>
    --    <string name="wifi_no_internet" msgid="9151470775868728896">"কোনো ইন্টারনেট অ্যাক্সেস শনাক্ত হয়নি, স্বয়ংক্রিয়ভাবে পুনরায় সংযোগ স্থাপন করবে না৷"</string>
    -+    <string name="wifi_no_internet_no_reconnect" msgid="2211781637653149657">"কোনো ইন্টারনেট অ্যাক্সেস শনাক্ত হয়নি, স্বয়ংক্রিয়ভাবে পুনরায় সংযোগ স্থাপন করবে না৷"</string>
    -+    <string name="wifi_no_internet" msgid="5011955173375805204">"কোনো ইন্টারনেট অ্যাক্সেস নেই৷"</string>
    -     <string name="saved_network" msgid="4352716707126620811">"<xliff:g id="NAME">%1$s</xliff:g> দ্বারা সংরক্ষিত"</string>
    -     <string name="connected_via_wfa" msgid="3805736726317410714">"ওয়াই-ফাই সহায়ক-এর মাধ্যমে সংযুক্ত হয়েছে"</string>
    -     <string name="connected_via_passpoint" msgid="2826205693803088747">"%1$s মাধ্যমে সংযুক্ত হয়েছে"</string>
    -@@ -233,8 +234,6 @@
    -     <string name="debug_layout_summary" msgid="2001775315258637682">"ক্লিপ বাউন্ড, মার্জিন ইত্যাদি দেখান"</string>
    -     <string name="force_rtl_layout_all_locales" msgid="2259906643093138978">"RTL লেআউট দিকনির্দেশ জোর দিন"</string>
    -     <string name="force_rtl_layout_all_locales_summary" msgid="9192797796616132534">"সমস্ত স্থানের জন্য RTL এ স্ক্রীন লেআউট দিকনির্দেশে জোর দেয়"</string>
    --    <string name="show_cpu_usage" msgid="2389212910758076024">"CPU এর ব্যবহার দেখান"</string>
    --    <string name="show_cpu_usage_summary" msgid="2113341923988958266">"স্ক্রীন ওভারলে বর্তমান CPU ব্যবহার দেখাচ্ছে"</string>
    -     <string name="force_hw_ui" msgid="6426383462520888732">"জোর করে GPU রেন্ডারিং করুন"</string>
    -     <string name="force_hw_ui_summary" msgid="5535991166074861515">"2D অঙ্কনের জন্য GPU-এর ব্যবহারে জোর দিন"</string>
    -     <string name="force_msaa" msgid="7920323238677284387">"4x MSAA এ জোর দিন"</string>
    -@@ -341,4 +340,5 @@
    -     <string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"বৃহত্তম"</string>
    -     <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"কাস্টম (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
    -     <string name="help_feedback_label" msgid="6815040660801785649">"সহায়তা ও মতামত"</string>
    -+    <string name="content_description_menu_button" msgid="8182594799812351266">"মেনু"</string>
    - </resources>
    -diff --git a/packages/SettingsLib/res/values-bs-rBA/strings.xml b/packages/SettingsLib/res/values-bs-rBA/strings.xml
    -index 40a3630..8c7c4e0 100644
    ---- a/packages/SettingsLib/res/values-bs-rBA/strings.xml
    -+++ b/packages/SettingsLib/res/values-bs-rBA/strings.xml
    -@@ -28,7 +28,8 @@
    -     <string name="wifi_disabled_wifi_failure" msgid="3081668066612876581">"Greška pri povezivanju na Wi-Fi"</string>
    -     <string name="wifi_disabled_password_failure" msgid="8659805351763133575">"Problem pri provjeri vjerodostojnosti."</string>
    -     <string name="wifi_not_in_range" msgid="1136191511238508967">"Nije u dometu"</string>
    --    <string name="wifi_no_internet" msgid="9151470775868728896">"Pristup internetu nije pronađen. Neće se ponovo povezivati automatski."</string>
    -+    <string name="wifi_no_internet_no_reconnect" msgid="2211781637653149657">"Pristup internetu nije pronađen. Neće se ponovo povezivati automatski."</string>
    -+    <string name="wifi_no_internet" msgid="5011955173375805204">"Nema pristupa internetu."</string>
    -     <string name="saved_network" msgid="4352716707126620811">"Sačuvao <xliff:g id="NAME">%1$s</xliff:g>"</string>
    -     <string name="connected_via_wfa" msgid="3805736726317410714">"Povezani preko Wi-Fi pomoćnika"</string>
    -     <string name="connected_via_passpoint" msgid="2826205693803088747">"Povezani preko %1$s"</string>
    -@@ -233,8 +234,6 @@
    -     <string name="debug_layout_summary" msgid="2001775315258637682">"Prikaži granice isječka, margine itd."</string>
    -     <string name="force_rtl_layout_all_locales" msgid="2259906643093138978">"Prisilno postavi raspored s desna u lijevo"</string>
    -     <string name="force_rtl_layout_all_locales_summary" msgid="9192797796616132534">"Prisilno postavi raspored ekrana s desna u lijevo za sve regije"</string>
    --    <string name="show_cpu_usage" msgid="2389212910758076024">"Prikaži korištenje CPU-a"</string>
    --    <string name="show_cpu_usage_summary" msgid="2113341923988958266">"Trenutno korištenje CPU-a prikazuje se u nadsloju preko ekrana"</string>
    -     <string name="force_hw_ui" msgid="6426383462520888732">"Prisili GPU iscrtavanje"</string>
    -     <string name="force_hw_ui_summary" msgid="5535991166074861515">"Prisilno koristite GPU za 2d crtanje"</string>
    -     <string name="force_msaa" msgid="7920323238677284387">"Prinudno primjeni 4x MSAA"</string>
    -@@ -341,4 +340,5 @@
    -     <string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"Najveće"</string>
    -     <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Prilagodi (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
    -     <string name="help_feedback_label" msgid="6815040660801785649">"Pomoć i povratne informacije"</string>
    -+    <string name="content_description_menu_button" msgid="8182594799812351266">"Meni"</string>
    - </resources>
    -diff --git a/packages/SettingsLib/res/values-ca/strings.xml b/packages/SettingsLib/res/values-ca/strings.xml
    -index 99850a5..20ae6b0 100644
    ---- a/packages/SettingsLib/res/values-ca/strings.xml
    -+++ b/packages/SettingsLib/res/values-ca/strings.xml
    -@@ -28,7 +28,8 @@
    -     <string name="wifi_disabled_wifi_failure" msgid="3081668066612876581">"Error de connexió Wi-Fi"</string>
    -     <string name="wifi_disabled_password_failure" msgid="8659805351763133575">"Problema d\'autenticació"</string>
    -     <string name="wifi_not_in_range" msgid="1136191511238508967">"Fora de l\'abast"</string>
    --    <string name="wifi_no_internet" msgid="9151470775868728896">"No s\'ha detectat accés a Internet, no s\'hi tornarà a connectar automàticament."</string>
    -+    <string name="wifi_no_internet_no_reconnect" msgid="2211781637653149657">"No s\'ha detectat accés a Internet; no s\'hi tornarà a connectar automàticament."</string>
    -+    <string name="wifi_no_internet" msgid="5011955173375805204">"No hi ha accés a Internet."</string>
    -     <string name="saved_network" msgid="4352716707126620811">"Desat per <xliff:g id="NAME">%1$s</xliff:g>"</string>
    -     <string name="connected_via_wfa" msgid="3805736726317410714">"Connectat mitjançant l\'assistent de Wi‑Fi"</string>
    -     <string name="connected_via_passpoint" msgid="2826205693803088747">"Connectada mitjançant %1$s"</string>
    -@@ -233,8 +234,6 @@
    -     <string name="debug_layout_summary" msgid="2001775315258637682">"Mostra els límits de clips, els marges, etc."</string>
    -     <string name="force_rtl_layout_all_locales" msgid="2259906643093138978">"Força direcció dreta-esquerra"</string>
    -     <string name="force_rtl_layout_all_locales_summary" msgid="9192797796616132534">"Força direcció de pantalla dreta-esquerra en totes les llengües"</string>
    --    <string name="show_cpu_usage" msgid="2389212910758076024">"Mostra l\'ús de la CPU"</string>
    --    <string name="show_cpu_usage_summary" msgid="2113341923988958266">"Superposa l\'ús de la CPU a la pantalla"</string>
    -     <string name="force_hw_ui" msgid="6426383462520888732">"Força acceleració GPU"</string>
    -     <string name="force_hw_ui_summary" msgid="5535991166074861515">"Força l\'ús de GPU per a dibuixos en 2D"</string>
    -     <string name="force_msaa" msgid="7920323238677284387">"Força MSAA  4x"</string>
    -@@ -341,4 +340,5 @@
    -     <string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"Màxim"</string>
    -     <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Personalitzat (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
    -     <string name="help_feedback_label" msgid="6815040660801785649">"Ajuda i suggeriments"</string>
    -+    <string name="content_description_menu_button" msgid="8182594799812351266">"Menú"</string>
    - </resources>
    -diff --git a/packages/SettingsLib/res/values-cs/strings.xml b/packages/SettingsLib/res/values-cs/strings.xml
    -index 361ba1f..bbc1266 100644
    ---- a/packages/SettingsLib/res/values-cs/strings.xml
    -+++ b/packages/SettingsLib/res/values-cs/strings.xml
    -@@ -28,7 +28,8 @@
    -     <string name="wifi_disabled_wifi_failure" msgid="3081668066612876581">"Selhání připojení Wi-Fi"</string>
    -     <string name="wifi_disabled_password_failure" msgid="8659805351763133575">"Problém s ověřením"</string>
    -     <string name="wifi_not_in_range" msgid="1136191511238508967">"Mimo dosah"</string>
    --    <string name="wifi_no_internet" msgid="9151470775868728896">"Nebyl zjištěn žádný přístup k internetu, připojení nebude automaticky obnoveno."</string>
    -+    <string name="wifi_no_internet_no_reconnect" msgid="2211781637653149657">"Nebyl zjištěn žádný přístup k internetu, připojení nebude automaticky obnoveno."</string>
    -+    <string name="wifi_no_internet" msgid="5011955173375805204">"Není k dispozici přístup k internetu."</string>
    -     <string name="saved_network" msgid="4352716707126620811">"Uloženo uživatelem <xliff:g id="NAME">%1$s</xliff:g>"</string>
    -     <string name="connected_via_wfa" msgid="3805736726317410714">"Připojeno pomocí asistenta připojení Wi-Fi"</string>
    -     <string name="connected_via_passpoint" msgid="2826205693803088747">"Připojeno prostřednictvím %1$s"</string>
    -@@ -233,8 +234,6 @@
    -     <string name="debug_layout_summary" msgid="2001775315258637682">"Zobrazit u výstřižku ohraničení, okraje atd."</string>
    -     <string name="force_rtl_layout_all_locales" msgid="2259906643093138978">"Vynutit rozvržení zprava doleva"</string>
    -     <string name="force_rtl_layout_all_locales_summary" msgid="9192797796616132534">"Vynutit ve všech jazycích rozvržení obrazovky zprava doleva"</string>
    --    <string name="show_cpu_usage" msgid="2389212910758076024">"Zobrazit využití CPU"</string>
    --    <string name="show_cpu_usage_summary" msgid="2113341923988958266">"Překryvná vrstva s aktuálním využitím procesoru"</string>
    -     <string name="force_hw_ui" msgid="6426383462520888732">"Vykreslování pomocí GPU"</string>
    -     <string name="force_hw_ui_summary" msgid="5535991166074861515">"Vynutit použití GPU pro 2D vykreslování"</string>
    -     <string name="force_msaa" msgid="7920323238677284387">"Vynutit 4x MSAA"</string>
    -@@ -341,4 +340,5 @@
    -     <string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"Největší"</string>
    -     <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Vlastní (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
    -     <string name="help_feedback_label" msgid="6815040660801785649">"Nápověda a zpětná vazba"</string>
    -+    <string name="content_description_menu_button" msgid="8182594799812351266">"Nabídka"</string>
    - </resources>
    -diff --git a/packages/SettingsLib/res/values-da/strings.xml b/packages/SettingsLib/res/values-da/strings.xml
    -index 98f41fc..108d8dc 100644
    ---- a/packages/SettingsLib/res/values-da/strings.xml
    -+++ b/packages/SettingsLib/res/values-da/strings.xml
    -@@ -28,7 +28,8 @@
    -     <string name="wifi_disabled_wifi_failure" msgid="3081668066612876581">"Wi-Fi-forbindelsesfejl"</string>
    -     <string name="wifi_disabled_password_failure" msgid="8659805351763133575">"Problem med godkendelse"</string>
    -     <string name="wifi_not_in_range" msgid="1136191511238508967">"Ikke inden for rækkevidde"</string>
    --    <string name="wifi_no_internet" msgid="9151470775868728896">"Der blev ikke fundet nogen internetadgang. Forbindelsen bliver ikke automatisk genoprettet."</string>
    -+    <string name="wifi_no_internet_no_reconnect" msgid="2211781637653149657">"Der blev ikke fundet nogen internetadgang. Forbindelsen bliver ikke automatisk genoprettet."</string>
    -+    <string name="wifi_no_internet" msgid="5011955173375805204">"Ingen internetadgang."</string>
    -     <string name="saved_network" msgid="4352716707126620811">"Gemt af <xliff:g id="NAME">%1$s</xliff:g>"</string>
    -     <string name="connected_via_wfa" msgid="3805736726317410714">"Forbindelse via Wi-Fi-assistent"</string>
    -     <string name="connected_via_passpoint" msgid="2826205693803088747">"Tilsluttet via %1$s"</string>
    -@@ -151,7 +152,7 @@
    -     <string name="clear_adb_keys" msgid="4038889221503122743">"Tilbagekald tilladelser for USB-fejlfinding"</string>
    -     <string name="bugreport_in_power" msgid="7923901846375587241">"Genvej til fejlrapporting"</string>
    -     <string name="bugreport_in_power_summary" msgid="1778455732762984579">"Vis en knap til oprettelse af fejlrapporter i menu for slukknap"</string>
    --    <string name="keep_screen_on" msgid="1146389631208760344">"Undgå dvale"</string>
    -+    <string name="keep_screen_on" msgid="1146389631208760344">"Lås ikke"</string>
    -     <string name="keep_screen_on_summary" msgid="2173114350754293009">"Skærmen går ikke i dvale under opladning"</string>
    -     <string name="bt_hci_snoop_log" msgid="3340699311158865670">"Aktivér Bluetooth HCI snoop log"</string>
    -     <string name="bt_hci_snoop_log_summary" msgid="730247028210113851">"Gem alle Bluetooth HCI-pakker i en fil"</string>
    -@@ -233,8 +234,6 @@
    -     <string name="debug_layout_summary" msgid="2001775315258637682">"Vis grænser for klip, margener osv."</string>
    -     <string name="force_rtl_layout_all_locales" msgid="2259906643093138978">"Tving læsning mod venstre"</string>
    -     <string name="force_rtl_layout_all_locales_summary" msgid="9192797796616132534">"Tving til højre mod venstre-layout for alle sprog"</string>
    --    <string name="show_cpu_usage" msgid="2389212910758076024">"Vis CPU-forbrug"</string>
    --    <string name="show_cpu_usage_summary" msgid="2113341923988958266">"Skærmoverlejring viser det aktuelle CPU-forbrug"</string>
    -     <string name="force_hw_ui" msgid="6426383462520888732">"Tving gengivelse af GPU"</string>
    -     <string name="force_hw_ui_summary" msgid="5535991166074861515">"Gennemtving brug af GPU til 2D-tegning"</string>
    -     <string name="force_msaa" msgid="7920323238677284387">"Tving 4x MSAA"</string>
    -@@ -341,4 +340,5 @@
    -     <string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"Størst"</string>
    -     <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Tilpasset (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
    -     <string name="help_feedback_label" msgid="6815040660801785649">"Hjælp og feedback"</string>
    -+    <string name="content_description_menu_button" msgid="8182594799812351266">"Menu"</string>
    - </resources>
    -diff --git a/packages/SettingsLib/res/values-de/strings.xml b/packages/SettingsLib/res/values-de/strings.xml
    -index c9da6c9..d93dbac 100644
    ---- a/packages/SettingsLib/res/values-de/strings.xml
    -+++ b/packages/SettingsLib/res/values-de/strings.xml
    -@@ -28,7 +28,8 @@
    -     <string name="wifi_disabled_wifi_failure" msgid="3081668066612876581">"WLAN-Verbindungsfehler"</string>
    -     <string name="wifi_disabled_password_failure" msgid="8659805351763133575">"Authentifizierungsproblem"</string>
    -     <string name="wifi_not_in_range" msgid="1136191511238508967">"Nicht in Reichweite"</string>
    --    <string name="wifi_no_internet" msgid="9151470775868728896">"Keine Internetverbindung erkannt, es kann nicht automatisch eine Verbindung hergestellt werden."</string>
    -+    <string name="wifi_no_internet_no_reconnect" msgid="2211781637653149657">"Keine Internetverbindung erkannt. Es kann nicht automatisch eine Verbindung hergestellt werden."</string>
    -+    <string name="wifi_no_internet" msgid="5011955173375805204">"Kein Internetzugriff."</string>
    -     <string name="saved_network" msgid="4352716707126620811">"Gespeichert von <xliff:g id="NAME">%1$s</xliff:g>"</string>
    -     <string name="connected_via_wfa" msgid="3805736726317410714">"Über WLAN-Assistenten verbunden"</string>
    -     <string name="connected_via_passpoint" msgid="2826205693803088747">"Über %1$s verbunden"</string>
    -@@ -38,7 +39,7 @@
    -     <string name="bluetooth_disconnecting" msgid="8913264760027764974">"Verbindung wird getrennt..."</string>
    -     <string name="bluetooth_connecting" msgid="8555009514614320497">"Verbindung wird hergestellt..."</string>
    -     <string name="bluetooth_connected" msgid="6038755206916626419">"Verbunden"</string>
    --    <string name="bluetooth_pairing" msgid="1426882272690346242">"Pairing läuft…"</string>
    -+    <string name="bluetooth_pairing" msgid="1426882272690346242">"Kopplung läuft…"</string>
    -     <string name="bluetooth_connected_no_headset" msgid="2866994875046035609">"Verbunden (kein Telefon)"</string>
    -     <string name="bluetooth_connected_no_a2dp" msgid="4576188601581440337">"Verbunden (außer Audiomedien)"</string>
    -     <string name="bluetooth_connected_no_map" msgid="6504436917057479986">"Verbunden (ohne Nachrichtenzugriff)"</string>
    -@@ -69,12 +70,12 @@
    -     <string name="bluetooth_headset_profile_summary_use_for" msgid="8705753622443862627">"Für Audiosystem des Telefons verwenden"</string>
    -     <string name="bluetooth_opp_profile_summary_use_for" msgid="1255674547144769756">"Für Dateiübertragung verwenden"</string>
    -     <string name="bluetooth_hid_profile_summary_use_for" msgid="232727040453645139">"Für Eingabe verwenden"</string>
    --    <string name="bluetooth_pairing_accept" msgid="6163520056536604875">"Pairing durchführen"</string>
    --    <string name="bluetooth_pairing_accept_all_caps" msgid="6061699265220789149">"Pairing durchführen"</string>
    -+    <string name="bluetooth_pairing_accept" msgid="6163520056536604875">"Koppeln"</string>
    -+    <string name="bluetooth_pairing_accept_all_caps" msgid="6061699265220789149">"KOPPELN"</string>
    -     <string name="bluetooth_pairing_decline" msgid="4185420413578948140">"Abbrechen"</string>
    --    <string name="bluetooth_pairing_will_share_phonebook" msgid="4982239145676394429">"Über das Pairing kann auf deine Kontakte und auf deinen Anrufverlauf zugegriffen werden, wenn eine Verbindung besteht."</string>
    --    <string name="bluetooth_pairing_error_message" msgid="3748157733635947087">"Pairing mit <xliff:g id="DEVICE_NAME">%1$s</xliff:g> war nicht möglich."</string>
    --    <string name="bluetooth_pairing_pin_error_message" msgid="8337234855188925274">"Pairing mit <xliff:g id="DEVICE_NAME">%1$s</xliff:g> war nicht möglich, weil die eingegebene PIN oder der Zugangscode falsch ist."</string>
    -+    <string name="bluetooth_pairing_will_share_phonebook" msgid="4982239145676394429">"Über die Kopplung kann auf deine Kontakte und auf deinen Anrufverlauf zugegriffen werden, wenn eine Verbindung besteht."</string>
    -+    <string name="bluetooth_pairing_error_message" msgid="3748157733635947087">"Kopplung mit <xliff:g id="DEVICE_NAME">%1$s</xliff:g> war nicht möglich."</string>
    -+    <string name="bluetooth_pairing_pin_error_message" msgid="8337234855188925274">"Kopplung mit <xliff:g id="DEVICE_NAME">%1$s</xliff:g> war nicht möglich, weil die eingegebene PIN oder der Zugangscode falsch ist."</string>
    -     <string name="bluetooth_pairing_device_down_error_message" msgid="7870998403045801381">"Kommunikation mit <xliff:g id="DEVICE_NAME">%1$s</xliff:g> ist nicht möglich."</string>
    -     <string name="bluetooth_pairing_rejected_error_message" msgid="1648157108520832454">"Verbindung wurde von <xliff:g id="DEVICE_NAME">%1$s</xliff:g> abgelehnt."</string>
    -     <string name="accessibility_wifi_off" msgid="1166761729660614716">"WLAN: aus"</string>
    -@@ -233,8 +234,6 @@
    -     <string name="debug_layout_summary" msgid="2001775315258637682">"Clip-Begrenzungen, Ränder usw. anzeigen"</string>
    -     <string name="force_rtl_layout_all_locales" msgid="2259906643093138978">"RTL-Layout erzwingen"</string>
    -     <string name="force_rtl_layout_all_locales_summary" msgid="9192797796616132534">"RTL-Bildschirmlayout für alle Sprachen erzwingen"</string>
    --    <string name="show_cpu_usage" msgid="2389212910758076024">"CPU-Auslastung anzeigen"</string>
    --    <string name="show_cpu_usage_summary" msgid="2113341923988958266">"Bildschirm-Overlay mit aktueller CPU-Auslastung"</string>
    -     <string name="force_hw_ui" msgid="6426383462520888732">"GPU-Rendering erzwingen"</string>
    -     <string name="force_hw_ui_summary" msgid="5535991166074861515">"Einsatz von GPU für 2D-Zeichnung erzwingen"</string>
    -     <string name="force_msaa" msgid="7920323238677284387">"4x MSAA erzwingen"</string>
    -@@ -341,4 +340,5 @@
    -     <string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"Am größten"</string>
    -     <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Benutzerdefiniert (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
    -     <string name="help_feedback_label" msgid="6815040660801785649">"Hilfe &amp; Feedback"</string>
    -+    <string name="content_description_menu_button" msgid="8182594799812351266">"Menü"</string>
    - </resources>
    -diff --git a/packages/SettingsLib/res/values-el/strings.xml b/packages/SettingsLib/res/values-el/strings.xml
    -index 05e4e64..6bbc11c 100644
    ---- a/packages/SettingsLib/res/values-el/strings.xml
    -+++ b/packages/SettingsLib/res/values-el/strings.xml
    -@@ -28,7 +28,8 @@
    -     <string name="wifi_disabled_wifi_failure" msgid="3081668066612876581">"Αποτυχία σύνδεσης Wi-Fi"</string>
    -     <string name="wifi_disabled_password_failure" msgid="8659805351763133575">"Πρόβλημα ελέγχου ταυτότητας"</string>
    -     <string name="wifi_not_in_range" msgid="1136191511238508967">"Εκτός εμβέλειας"</string>
    --    <string name="wifi_no_internet" msgid="9151470775868728896">"Δεν εντοπίστηκε καμία πρόσβαση στο διαδίκτυο, δεν θα γίνει αυτόματη επανασύνδεση."</string>
    -+    <string name="wifi_no_internet_no_reconnect" msgid="2211781637653149657">"Δεν εντοπίστηκε πρόσβαση στο διαδίκτυο. Δεν θα πραγματοποιηθεί αυτόματη επανασύνδεση."</string>
    -+    <string name="wifi_no_internet" msgid="5011955173375805204">"Δεν υπάρχει πρόσβαση στο διαδίκτυο."</string>
    -     <string name="saved_network" msgid="4352716707126620811">"Αποθηκεύτηκε από <xliff:g id="NAME">%1$s</xliff:g>"</string>
    -     <string name="connected_via_wfa" msgid="3805736726317410714">"Σύνδεση μέσω βοηθού Wi‑Fi"</string>
    -     <string name="connected_via_passpoint" msgid="2826205693803088747">"Συνδέθηκε μέσω %1$s"</string>
    -@@ -233,8 +234,6 @@
    -     <string name="debug_layout_summary" msgid="2001775315258637682">"Εμφάνιση ορίων κλιπ, περιθωρίων, κλπ."</string>
    -     <string name="force_rtl_layout_all_locales" msgid="2259906643093138978">"Επιβολή κατ. διάταξης RTL"</string>
    -     <string name="force_rtl_layout_all_locales_summary" msgid="9192797796616132534">"Επιβολή διάταξης οθόν. RTL για όλες τις τοπ. ρυθμ."</string>
    --    <string name="show_cpu_usage" msgid="2389212910758076024">"Προβολή χρήσης CPU"</string>
    --    <string name="show_cpu_usage_summary" msgid="2113341923988958266">"Επικάλυψη οθόνης για προβολή τρέχουσας χρήσης CPU"</string>
    -     <string name="force_hw_ui" msgid="6426383462520888732">"Αναγκαστική απόδοση GPU"</string>
    -     <string name="force_hw_ui_summary" msgid="5535991166074861515">"Αναγκαστική χρήση του GPU για σχέδιο 2D"</string>
    -     <string name="force_msaa" msgid="7920323238677284387">"Αναγκαστικά 4x MSAA"</string>
    -@@ -287,8 +286,8 @@
    -     <string name="convert_to_file_encryption_enabled" msgid="2861258671151428346">"Μετατροπή…"</string>
    -     <string name="convert_to_file_encryption_done" msgid="7859766358000523953">"Με κρυπτογράφηση αρχείου"</string>
    -     <string name="title_convert_fbe" msgid="1263622876196444453">"Μετατροπή σε κρυπτογράφηση βάσει αρχείου…"</string>
    --    <string name="convert_to_fbe_warning" msgid="6139067817148865527">"Μετατροπή τμήματος δεδομένων σε κρυπτογράφηση βάσει αρχείου.\n !!Προσοχή!! Με αυτήν την ενέργεια, θα διαγραφούν όλα τα δεδομένα σας.\n Αυτή η λειτουργία βρίσκεται σε δοκιμαστικό στάδιο alpha και ενδέχεται να μην λειτουργεί σωστά.\n Πατήστε \"Εκκαθάριση και μετατροπή…\" για να συνεχίσετε."</string>
    --    <string name="button_convert_fbe" msgid="5152671181309826405">"Εκκαθάριση και μετατροπή…"</string>
    -+    <string name="convert_to_fbe_warning" msgid="6139067817148865527">"Μετατροπή τμήματος δεδομένων σε κρυπτογράφηση βάσει αρχείου.\n !!Προσοχή!! Με αυτήν την ενέργεια, θα διαγραφούν όλα τα δεδομένα σας.\n Αυτή η λειτουργία βρίσκεται σε δοκιμαστικό στάδιο alpha και ενδέχεται να μην λειτουργεί σωστά.\n Πατήστε \"Διαγραφή και μετατροπή…\" για να συνεχίσετε."</string>
    -+    <string name="button_convert_fbe" msgid="5152671181309826405">"Διαγραφή και μετατροπή…"</string>
    -     <string name="picture_color_mode" msgid="4560755008730283695">"Λειτουργία χρώματος εικόνας"</string>
    -     <string name="picture_color_mode_desc" msgid="1141891467675548590">"Χρήση sRGB"</string>
    -     <string name="daltonizer_mode_disabled" msgid="7482661936053801862">"Απενεργοποιημένο"</string>
    -@@ -341,4 +340,5 @@
    -     <string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"Μεγαλύτερα"</string>
    -     <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Προσαρμοσμένη (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
    -     <string name="help_feedback_label" msgid="6815040660801785649">"Βοήθεια και σχόλια"</string>
    -+    <string name="content_description_menu_button" msgid="8182594799812351266">"Μενού"</string>
    - </resources>
    -diff --git a/packages/SettingsLib/res/values-en-rAU/strings.xml b/packages/SettingsLib/res/values-en-rAU/strings.xml
    -index 799802b..a571aff 100644
    ---- a/packages/SettingsLib/res/values-en-rAU/strings.xml
    -+++ b/packages/SettingsLib/res/values-en-rAU/strings.xml
    -@@ -28,7 +28,8 @@
    -     <string name="wifi_disabled_wifi_failure" msgid="3081668066612876581">"Wi-Fi Connection Failure"</string>
    -     <string name="wifi_disabled_password_failure" msgid="8659805351763133575">"Authentication problem"</string>
    -     <string name="wifi_not_in_range" msgid="1136191511238508967">"Not in range"</string>
    --    <string name="wifi_no_internet" msgid="9151470775868728896">"No Internet Access Detected, won\'t automatically reconnect."</string>
    -+    <string name="wifi_no_internet_no_reconnect" msgid="2211781637653149657">"No Internet access detected, won\'t automatically reconnect."</string>
    -+    <string name="wifi_no_internet" msgid="5011955173375805204">"No Internet Access."</string>
    -     <string name="saved_network" msgid="4352716707126620811">"Saved by <xliff:g id="NAME">%1$s</xliff:g>"</string>
    -     <string name="connected_via_wfa" msgid="3805736726317410714">"Connected via Wi‑Fi assistant"</string>
    -     <string name="connected_via_passpoint" msgid="2826205693803088747">"Connected via %1$s"</string>
    -@@ -233,8 +234,6 @@
    -     <string name="debug_layout_summary" msgid="2001775315258637682">"Show clip bounds, margins, etc."</string>
    -     <string name="force_rtl_layout_all_locales" msgid="2259906643093138978">"Force RTL layout direction"</string>
    -     <string name="force_rtl_layout_all_locales_summary" msgid="9192797796616132534">"Force screen layout direction to RTL for all locales"</string>
    --    <string name="show_cpu_usage" msgid="2389212910758076024">"Show CPU usage"</string>
    --    <string name="show_cpu_usage_summary" msgid="2113341923988958266">"Screen overlay showing current CPU usage"</string>
    -     <string name="force_hw_ui" msgid="6426383462520888732">"Force GPU rendering"</string>
    -     <string name="force_hw_ui_summary" msgid="5535991166074861515">"Force use of GPU for 2D drawing"</string>
    -     <string name="force_msaa" msgid="7920323238677284387">"Force 4x MSAA"</string>
    -@@ -341,4 +340,5 @@
    -     <string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"Largest"</string>
    -     <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Custom (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
    -     <string name="help_feedback_label" msgid="6815040660801785649">"Help &amp; feedback"</string>
    -+    <string name="content_description_menu_button" msgid="8182594799812351266">"Menu"</string>
    - </resources>
    -diff --git a/packages/SettingsLib/res/values-en-rGB/strings.xml b/packages/SettingsLib/res/values-en-rGB/strings.xml
    -index 799802b..a571aff 100644
    ---- a/packages/SettingsLib/res/values-en-rGB/strings.xml
    -+++ b/packages/SettingsLib/res/values-en-rGB/strings.xml
    -@@ -28,7 +28,8 @@
    -     <string name="wifi_disabled_wifi_failure" msgid="3081668066612876581">"Wi-Fi Connection Failure"</string>
    -     <string name="wifi_disabled_password_failure" msgid="8659805351763133575">"Authentication problem"</string>
    -     <string name="wifi_not_in_range" msgid="1136191511238508967">"Not in range"</string>
    --    <string name="wifi_no_internet" msgid="9151470775868728896">"No Internet Access Detected, won\'t automatically reconnect."</string>
    -+    <string name="wifi_no_internet_no_reconnect" msgid="2211781637653149657">"No Internet access detected, won\'t automatically reconnect."</string>
    -+    <string name="wifi_no_internet" msgid="5011955173375805204">"No Internet Access."</string>
    -     <string name="saved_network" msgid="4352716707126620811">"Saved by <xliff:g id="NAME">%1$s</xliff:g>"</string>
    -     <string name="connected_via_wfa" msgid="3805736726317410714">"Connected via Wi‑Fi assistant"</string>
    -     <string name="connected_via_passpoint" msgid="2826205693803088747">"Connected via %1$s"</string>
    -@@ -233,8 +234,6 @@
    -     <string name="debug_layout_summary" msgid="2001775315258637682">"Show clip bounds, margins, etc."</string>
    -     <string name="force_rtl_layout_all_locales" msgid="2259906643093138978">"Force RTL layout direction"</string>
    -     <string name="force_rtl_layout_all_locales_summary" msgid="9192797796616132534">"Force screen layout direction to RTL for all locales"</string>
    --    <string name="show_cpu_usage" msgid="2389212910758076024">"Show CPU usage"</string>
    --    <string name="show_cpu_usage_summary" msgid="2113341923988958266">"Screen overlay showing current CPU usage"</string>
    -     <string name="force_hw_ui" msgid="6426383462520888732">"Force GPU rendering"</string>
    -     <string name="force_hw_ui_summary" msgid="5535991166074861515">"Force use of GPU for 2D drawing"</string>
    -     <string name="force_msaa" msgid="7920323238677284387">"Force 4x MSAA"</string>
    -@@ -341,4 +340,5 @@
    -     <string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"Largest"</string>
    -     <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Custom (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
    -     <string name="help_feedback_label" msgid="6815040660801785649">"Help &amp; feedback"</string>
    -+    <string name="content_description_menu_button" msgid="8182594799812351266">"Menu"</string>
    - </resources>
    -diff --git a/packages/SettingsLib/res/values-en-rIN/strings.xml b/packages/SettingsLib/res/values-en-rIN/strings.xml
    -index 799802b..a571aff 100644
    ---- a/packages/SettingsLib/res/values-en-rIN/strings.xml
    -+++ b/packages/SettingsLib/res/values-en-rIN/strings.xml
    -@@ -28,7 +28,8 @@
    -     <string name="wifi_disabled_wifi_failure" msgid="3081668066612876581">"Wi-Fi Connection Failure"</string>
    -     <string name="wifi_disabled_password_failure" msgid="8659805351763133575">"Authentication problem"</string>
    -     <string name="wifi_not_in_range" msgid="1136191511238508967">"Not in range"</string>
    --    <string name="wifi_no_internet" msgid="9151470775868728896">"No Internet Access Detected, won\'t automatically reconnect."</string>
    -+    <string name="wifi_no_internet_no_reconnect" msgid="2211781637653149657">"No Internet access detected, won\'t automatically reconnect."</string>
    -+    <string name="wifi_no_internet" msgid="5011955173375805204">"No Internet Access."</string>
    -     <string name="saved_network" msgid="4352716707126620811">"Saved by <xliff:g id="NAME">%1$s</xliff:g>"</string>
    -     <string name="connected_via_wfa" msgid="3805736726317410714">"Connected via Wi‑Fi assistant"</string>
    -     <string name="connected_via_passpoint" msgid="2826205693803088747">"Connected via %1$s"</string>
    -@@ -233,8 +234,6 @@
    -     <string name="debug_layout_summary" msgid="2001775315258637682">"Show clip bounds, margins, etc."</string>
    -     <string name="force_rtl_layout_all_locales" msgid="2259906643093138978">"Force RTL layout direction"</string>
    -     <string name="force_rtl_layout_all_locales_summary" msgid="9192797796616132534">"Force screen layout direction to RTL for all locales"</string>
    --    <string name="show_cpu_usage" msgid="2389212910758076024">"Show CPU usage"</string>
    --    <string name="show_cpu_usage_summary" msgid="2113341923988958266">"Screen overlay showing current CPU usage"</string>
    -     <string name="force_hw_ui" msgid="6426383462520888732">"Force GPU rendering"</string>
    -     <string name="force_hw_ui_summary" msgid="5535991166074861515">"Force use of GPU for 2D drawing"</string>
    -     <string name="force_msaa" msgid="7920323238677284387">"Force 4x MSAA"</string>
    -@@ -341,4 +340,5 @@
    -     <string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"Largest"</string>
    -     <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Custom (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
    -     <string name="help_feedback_label" msgid="6815040660801785649">"Help &amp; feedback"</string>
    -+    <string name="content_description_menu_button" msgid="8182594799812351266">"Menu"</string>
    - </resources>
    -diff --git a/packages/SettingsLib/res/values-es-rUS/strings.xml b/packages/SettingsLib/res/values-es-rUS/strings.xml
    -index 08e739a..924c18a 100644
    ---- a/packages/SettingsLib/res/values-es-rUS/strings.xml
    -+++ b/packages/SettingsLib/res/values-es-rUS/strings.xml
    -@@ -28,7 +28,8 @@
    -     <string name="wifi_disabled_wifi_failure" msgid="3081668066612876581">"Error de conexión Wi-Fi"</string>
    -     <string name="wifi_disabled_password_failure" msgid="8659805351763133575">"Problema de autenticación"</string>
    -     <string name="wifi_not_in_range" msgid="1136191511238508967">"Fuera de alcance"</string>
    --    <string name="wifi_no_internet" msgid="9151470775868728896">"No se detectó el acceso a Internet. No se volverá a conectar de forma automática."</string>
    -+    <string name="wifi_no_internet_no_reconnect" msgid="2211781637653149657">"No se detectó el acceso a Internet. No se volverá a conectar de forma automática."</string>
    -+    <string name="wifi_no_internet" msgid="5011955173375805204">"No se detectó el acceso a Internet."</string>
    -     <string name="saved_network" msgid="4352716707126620811">"Guardadas por <xliff:g id="NAME">%1$s</xliff:g>"</string>
    -     <string name="connected_via_wfa" msgid="3805736726317410714">"Conexión por asistente de Wi-Fi"</string>
    -     <string name="connected_via_passpoint" msgid="2826205693803088747">"Conexión a través de %1$s"</string>
    -@@ -233,8 +234,6 @@
    -     <string name="debug_layout_summary" msgid="2001775315258637682">"Mostrar límites de recortes, márgenes, etc."</string>
    -     <string name="force_rtl_layout_all_locales" msgid="2259906643093138978">"Forzar diseño der. a izq."</string>
    -     <string name="force_rtl_layout_all_locales_summary" msgid="9192797796616132534">"Forzar diseño pantalla der.&gt;izq., cualquier idioma"</string>
    --    <string name="show_cpu_usage" msgid="2389212910758076024">"Mostrar el uso de CPU"</string>
    --    <string name="show_cpu_usage_summary" msgid="2113341923988958266">"Mostrar superposición en pantalla con uso actual de la CPU"</string>
    -     <string name="force_hw_ui" msgid="6426383462520888732">"Forzar representación GPU"</string>
    -     <string name="force_hw_ui_summary" msgid="5535991166074861515">"Forzar uso de GPU para dibujar en 2d"</string>
    -     <string name="force_msaa" msgid="7920323238677284387">"Forzar MSAA 4x"</string>
    -@@ -341,4 +340,5 @@
    -     <string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"Máximo"</string>
    -     <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Personalizado (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
    -     <string name="help_feedback_label" msgid="6815040660801785649">"Ayuda y comentarios"</string>
    -+    <string name="content_description_menu_button" msgid="8182594799812351266">"Menú"</string>
    - </resources>
    -diff --git a/packages/SettingsLib/res/values-es/strings.xml b/packages/SettingsLib/res/values-es/strings.xml
    -index 3d2f6c1..7824949 100644
    ---- a/packages/SettingsLib/res/values-es/strings.xml
    -+++ b/packages/SettingsLib/res/values-es/strings.xml
    -@@ -28,7 +28,8 @@
    -     <string name="wifi_disabled_wifi_failure" msgid="3081668066612876581">"Error de conexión Wi-Fi"</string>
    -     <string name="wifi_disabled_password_failure" msgid="8659805351763133575">"Error de autenticación"</string>
    -     <string name="wifi_not_in_range" msgid="1136191511238508967">"Fuera de rango"</string>
    --    <string name="wifi_no_internet" msgid="9151470775868728896">"No se ha detectado acceso a Internet, no se volverá a conectar automáticamente."</string>
    -+    <string name="wifi_no_internet_no_reconnect" msgid="2211781637653149657">"No se ha detectado acceso a Internet, por lo que no se volverá a conectar automáticamente."</string>
    -+    <string name="wifi_no_internet" msgid="5011955173375805204">"No se ha detectado acceso a Internet."</string>
    -     <string name="saved_network" msgid="4352716707126620811">"Guardadas por <xliff:g id="NAME">%1$s</xliff:g>"</string>
    -     <string name="connected_via_wfa" msgid="3805736726317410714">"Conectado a través de asistente Wi‑Fi"</string>
    -     <string name="connected_via_passpoint" msgid="2826205693803088747">"Conectado a través de %1$s"</string>
    -@@ -173,7 +174,7 @@
    -     <string name="wifi_verbose_logging_summary" msgid="6615071616111731958">"Aumentar el nivel de logging de Wi-Fi, mostrar por SSID RSSI en el selector Wi-Fi"</string>
    -     <string name="wifi_aggressive_handover_summary" msgid="6328455667642570371">"Si está habilitada, la conexión Wi‑Fi será más agresiva al transferir la conexión de datos al móvil (si la señal Wi‑Fi no es estable)"</string>
    -     <string name="wifi_allow_scan_with_traffic_summary" msgid="2575101424972686310">"Permitir/No permitir búsquedas de Wi-Fi basadas en la cantidad de tráfico de datos presente en la interfaz"</string>
    --    <string name="select_logd_size_title" msgid="7433137108348553508">"Tamaños del búfer de Logger"</string>
    -+    <string name="select_logd_size_title" msgid="7433137108348553508">"Tamaños de búfer de registrador"</string>
    -     <string name="select_logd_size_dialog_title" msgid="1206769310236476760">"Elige el tamaño del Logger por búfer"</string>
    -     <string name="dev_logpersist_clear_warning_title" msgid="684806692440237967">"¿Borrar almacenamiento continuo del registrador?"</string>
    -     <string name="dev_logpersist_clear_warning_message" msgid="2256582531342994562">"Cuando ya no supervisamos la actividad con el registrador de forma continua, estamos obligados a borrar los datos del registrador almacenados en el dispositivo."</string>
    -@@ -233,8 +234,6 @@
    -     <string name="debug_layout_summary" msgid="2001775315258637682">"Mostrar límites de vídeo, márgenes, etc."</string>
    -     <string name="force_rtl_layout_all_locales" msgid="2259906643093138978">"Forzar dirección diseño RTL"</string>
    -     <string name="force_rtl_layout_all_locales_summary" msgid="9192797796616132534">"Forzar dirección (RTL) para todas configuraciones"</string>
    --    <string name="show_cpu_usage" msgid="2389212910758076024">"Mostrar uso de la CPU"</string>
    --    <string name="show_cpu_usage_summary" msgid="2113341923988958266">"Suporponer el uso de la CPU en la pantalla"</string>
    -     <string name="force_hw_ui" msgid="6426383462520888732">"Forzar aceleración GPU"</string>
    -     <string name="force_hw_ui_summary" msgid="5535991166074861515">"Forzar uso de GPU para dibujos en 2D"</string>
    -     <string name="force_msaa" msgid="7920323238677284387">"Forzar MSAA 4x"</string>
    -@@ -341,4 +340,5 @@
    -     <string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"Lo más grande posible"</string>
    -     <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Personalizado (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
    -     <string name="help_feedback_label" msgid="6815040660801785649">"Ayuda y sugerencias"</string>
    -+    <string name="content_description_menu_button" msgid="8182594799812351266">"Menú"</string>
    - </resources>
    -diff --git a/packages/SettingsLib/res/values-et-rEE/strings.xml b/packages/SettingsLib/res/values-et-rEE/strings.xml
    -index a7b0f64..5f76b9f 100644
    ---- a/packages/SettingsLib/res/values-et-rEE/strings.xml
    -+++ b/packages/SettingsLib/res/values-et-rEE/strings.xml
    -@@ -28,7 +28,8 @@
    -     <string name="wifi_disabled_wifi_failure" msgid="3081668066612876581">"WiFi-ühenduse viga"</string>
    -     <string name="wifi_disabled_password_failure" msgid="8659805351763133575">"Autentimise probleem"</string>
    -     <string name="wifi_not_in_range" msgid="1136191511238508967">"Pole vahemikus"</string>
    --    <string name="wifi_no_internet" msgid="9151470775868728896">"Interneti-ühendust ei tuvastatud, seadet ei ühendata automaatselt."</string>
    -+    <string name="wifi_no_internet_no_reconnect" msgid="2211781637653149657">"Interneti-ühendust ei tuvastatud, seadet ei ühendata automaatselt uuesti."</string>
    -+    <string name="wifi_no_internet" msgid="5011955173375805204">"Interneti-ühendus puudub."</string>
    -     <string name="saved_network" msgid="4352716707126620811">"Salvestas: <xliff:g id="NAME">%1$s</xliff:g>"</string>
    -     <string name="connected_via_wfa" msgid="3805736726317410714">"Ühendatud WiFi-abi kaudu"</string>
    -     <string name="connected_via_passpoint" msgid="2826205693803088747">"Ühendatud üksuse %1$s kaudu"</string>
    -@@ -233,8 +234,6 @@
    -     <string name="debug_layout_summary" msgid="2001775315258637682">"Kuva klipi piirid, veerised jms"</string>
    -     <string name="force_rtl_layout_all_locales" msgid="2259906643093138978">"Paremalt vasakule paig."</string>
    -     <string name="force_rtl_layout_all_locales_summary" msgid="9192797796616132534">"Määra lokaatides ekraanipaig. paremalt vasakule"</string>
    --    <string name="show_cpu_usage" msgid="2389212910758076024">"CPU-kasutuse kuvamine"</string>
    --    <string name="show_cpu_usage_summary" msgid="2113341923988958266">"Praegust CPU-kasutust kuvav ekraani ülekate"</string>
    -     <string name="force_hw_ui" msgid="6426383462520888732">"Jõusta GPU renderdamine"</string>
    -     <string name="force_hw_ui_summary" msgid="5535991166074861515">"Jõusta GPU kasutam. kahemõõtmeliste jooniste puhul"</string>
    -     <string name="force_msaa" msgid="7920323238677284387">"Jõusta 4x MSAA"</string>
    -@@ -341,4 +340,5 @@
    -     <string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"Suurim"</string>
    -     <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Kohandatud (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
    -     <string name="help_feedback_label" msgid="6815040660801785649">"Abi ja tagasiside"</string>
    -+    <string name="content_description_menu_button" msgid="8182594799812351266">"Menüü"</string>
    - </resources>
    -diff --git a/packages/SettingsLib/res/values-eu-rES/strings.xml b/packages/SettingsLib/res/values-eu-rES/strings.xml
    -index f476511..abcf282 100644
    ---- a/packages/SettingsLib/res/values-eu-rES/strings.xml
    -+++ b/packages/SettingsLib/res/values-eu-rES/strings.xml
    -@@ -28,7 +28,8 @@
    -     <string name="wifi_disabled_wifi_failure" msgid="3081668066612876581">"Ezin izan da konektatu Wi-Fi sarera"</string>
    -     <string name="wifi_disabled_password_failure" msgid="8659805351763133575">"Autentifikazio-arazoa"</string>
    -     <string name="wifi_not_in_range" msgid="1136191511238508967">"Urrunegi"</string>
    --    <string name="wifi_no_internet" msgid="9151470775868728896">"Ez da hauteman Interneterako sarbiderik. Ez da automatikoki berriro konektatuko."</string>
    -+    <string name="wifi_no_internet_no_reconnect" msgid="2211781637653149657">"Ez da hauteman Interneterako sarbiderik. Ez da automatikoki berriro konektatuko."</string>
    -+    <string name="wifi_no_internet" msgid="5011955173375805204">"Ezin da konektatu Internetera."</string>
    -     <string name="saved_network" msgid="4352716707126620811">"<xliff:g id="NAME">%1$s</xliff:g> aplikazioak gorde du"</string>
    -     <string name="connected_via_wfa" msgid="3805736726317410714">"Wi‑Fi laguntzailearen bidez konektatuta"</string>
    -     <string name="connected_via_passpoint" msgid="2826205693803088747">"%1$s bidez konektatuta"</string>
    -@@ -233,8 +234,6 @@
    -     <string name="debug_layout_summary" msgid="2001775315258637682">"Erakutsi kliparen mugak, marjinak, etab."</string>
    -     <string name="force_rtl_layout_all_locales" msgid="2259906643093138978">"Behartu eskuin-ezker norabidea."</string>
    -     <string name="force_rtl_layout_all_locales_summary" msgid="9192797796616132534">"Behartu pantaila-diseinuaren norabidea eskuin-ezker izatera eskualdeko ezarpen guztiekin."</string>
    --    <string name="show_cpu_usage" msgid="2389212910758076024">"Erakutsi PUZ erabilera"</string>
    --    <string name="show_cpu_usage_summary" msgid="2113341923988958266">"PUZ erabilera erakusten duen pantaila-gainjartzea"</string>
    -     <string name="force_hw_ui" msgid="6426383462520888732">"Behartu GPU errendatzea"</string>
    -     <string name="force_hw_ui_summary" msgid="5535991166074861515">"Behartu GPUa erabiltzera 2 dimentsioko marrazkietan."</string>
    -     <string name="force_msaa" msgid="7920323238677284387">"Behartu 4x MSAA"</string>
    -@@ -341,4 +340,5 @@
    -     <string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"Handiena"</string>
    -     <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Pertsonalizatua (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
    -     <string name="help_feedback_label" msgid="6815040660801785649">"Laguntza eta iritziak"</string>
    -+    <string name="content_description_menu_button" msgid="8182594799812351266">"Menua"</string>
    - </resources>
    -diff --git a/packages/SettingsLib/res/values-fa/strings.xml b/packages/SettingsLib/res/values-fa/strings.xml
    -index 4491851..c573b68 100644
    ---- a/packages/SettingsLib/res/values-fa/strings.xml
    -+++ b/packages/SettingsLib/res/values-fa/strings.xml
    -@@ -28,7 +28,8 @@
    -     <string name="wifi_disabled_wifi_failure" msgid="3081668066612876581">"‏اتصال Wi-Fi برقرار نشد"</string>
    -     <string name="wifi_disabled_password_failure" msgid="8659805351763133575">"مشکل احراز هویت"</string>
    -     <string name="wifi_not_in_range" msgid="1136191511238508967">"در محدوده نیست"</string>
    --    <string name="wifi_no_internet" msgid="9151470775868728896">"دسترسی به اینترنت شناسایی نشد، به صورت خودکار وصل نمی‌شود."</string>
    -+    <string name="wifi_no_internet_no_reconnect" msgid="2211781637653149657">"دسترسی به اینترنت شناسایی نشد، به‌صورت خودکار وصل نمی‌شود."</string>
    -+    <string name="wifi_no_internet" msgid="5011955173375805204">"دسترسی به اینترنت وجود ندارد."</string>
    -     <string name="saved_network" msgid="4352716707126620811">"ذخیره‌شده توسط <xliff:g id="NAME">%1$s</xliff:g>"</string>
    -     <string name="connected_via_wfa" msgid="3805736726317410714">"‏متصل شده از طریق دستیار Wi-Fi"</string>
    -     <string name="connected_via_passpoint" msgid="2826205693803088747">"‏متصل از طریق %1$s"</string>
    -@@ -183,7 +184,7 @@
    -     <string name="select_usb_configuration_dialog_title" msgid="6385564442851599963">"‏انتخاب پیکربندی USB"</string>
    -     <string name="allow_mock_location" msgid="2787962564578664888">"مکان‌های کاذب مجاز هستند"</string>
    -     <string name="allow_mock_location_summary" msgid="317615105156345626">"مکان‌های کاذب مجاز هستند"</string>
    --    <string name="debug_view_attributes" msgid="6485448367803310384">"فعال کردن بازبینی ویژگی بازدید"</string>
    -+    <string name="debug_view_attributes" msgid="6485448367803310384">"فعال کردن نمایش بازبینی ویژگی"</string>
    -     <string name="mobile_data_always_on_summary" msgid="8149773901431697910">"‏داده سلولی همیشه فعال نگه داشته می‌شود، حتی وقتی Wi-Fi فعال است (برای جابه‌جایی سریع شبکه)."</string>
    -     <string name="adb_warning_title" msgid="6234463310896563253">"‏اشکال‌زدایی USB انجام شود؟"</string>
    -     <string name="adb_warning_message" msgid="7316799925425402244">"‏اشکال‌زدایی USB فقط برای اهداف برنامه‌نویسی در نظر گرفته شده است. از آن برای رونوشت‌برداری داده بین رایانه و دستگاهتان، نصب برنامه‌ها در دستگاهتان بدون اعلان و خواندن داده‌های گزارش استفاده کنید."</string>
    -@@ -233,8 +234,6 @@
    -     <string name="debug_layout_summary" msgid="2001775315258637682">"نمایش مرزها، حاشیه‌ها و ویژگی‌های دیگر کلیپ."</string>
    -     <string name="force_rtl_layout_all_locales" msgid="2259906643093138978">"‏اجباری کردن چیدمان RTL"</string>
    -     <string name="force_rtl_layout_all_locales_summary" msgid="9192797796616132534">"‏اجباری کردن چیدمان RTL صفحه برای همه زبان‌ها"</string>
    --    <string name="show_cpu_usage" msgid="2389212910758076024">"‏نمایش میزان استفاده از CPU"</string>
    --    <string name="show_cpu_usage_summary" msgid="2113341923988958266">"‏هم‌پوشانی صفحه‌نمایش میزان استفاده از CPU فعلی"</string>
    -     <string name="force_hw_ui" msgid="6426383462520888732">"‏پردازش اجباری GPU"</string>
    -     <string name="force_hw_ui_summary" msgid="5535991166074861515">"‏استفاده اجباری از GPU برای طراحی دوم"</string>
    -     <string name="force_msaa" msgid="7920323238677284387">"‏اجبار 4x MSAA"</string>
    -@@ -341,4 +340,5 @@
    -     <string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"بزرگ‌ترین"</string>
    -     <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"سفارشی (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
    -     <string name="help_feedback_label" msgid="6815040660801785649">"راهنما و بازخورد"</string>
    -+    <string name="content_description_menu_button" msgid="8182594799812351266">"منو"</string>
    - </resources>
    -diff --git a/packages/SettingsLib/res/values-fi/strings.xml b/packages/SettingsLib/res/values-fi/strings.xml
    -index cdef968..05f786a 100644
    ---- a/packages/SettingsLib/res/values-fi/strings.xml
    -+++ b/packages/SettingsLib/res/values-fi/strings.xml
    -@@ -28,7 +28,8 @@
    -     <string name="wifi_disabled_wifi_failure" msgid="3081668066612876581">"Wi-Fi-yhteysvirhe"</string>
    -     <string name="wifi_disabled_password_failure" msgid="8659805351763133575">"Todennusvirhe"</string>
    -     <string name="wifi_not_in_range" msgid="1136191511238508967">"Ei kantoalueella"</string>
    --    <string name="wifi_no_internet" msgid="9151470775868728896">"Internetyhteyttä ei havaittu, yhteyttä ei muodosteta automaattisesti uudelleen."</string>
    -+    <string name="wifi_no_internet_no_reconnect" msgid="2211781637653149657">"Internetyhteyttä ei havaittu. Yhteyttä ei muodosteta automaattisesti uudelleen."</string>
    -+    <string name="wifi_no_internet" msgid="5011955173375805204">"Ei internetyhteyttä"</string>
    -     <string name="saved_network" msgid="4352716707126620811">"Tallentaja: <xliff:g id="NAME">%1$s</xliff:g>"</string>
    -     <string name="connected_via_wfa" msgid="3805736726317410714">"Yhteys muodostettu Wi‑Fi-apurin kautta"</string>
    -     <string name="connected_via_passpoint" msgid="2826205693803088747">"Yhdistetty seuraavan kautta: %1$s"</string>
    -@@ -233,8 +234,6 @@
    -     <string name="debug_layout_summary" msgid="2001775315258637682">"Näytä leikkeiden rajat, marginaalit jne."</string>
    -     <string name="force_rtl_layout_all_locales" msgid="2259906643093138978">"Pakota RTL-ulkoasun suunta"</string>
    -     <string name="force_rtl_layout_all_locales_summary" msgid="9192797796616132534">"Pakota kaikkien kielten näytön ulkoasun suunnaksi RTL"</string>
    --    <string name="show_cpu_usage" msgid="2389212910758076024">"Näytä suorittimen käyttö"</string>
    --    <string name="show_cpu_usage_summary" msgid="2113341923988958266">"Näytön peittokuva näyttää nykyisen suoritinkäytön"</string>
    -     <string name="force_hw_ui" msgid="6426383462520888732">"Pakota GPU-hahmonnus"</string>
    -     <string name="force_hw_ui_summary" msgid="5535991166074861515">"Käytä GPU:ta 2d-piirtämiseen"</string>
    -     <string name="force_msaa" msgid="7920323238677284387">"Pakota 4x MSAA"</string>
    -@@ -341,4 +340,5 @@
    -     <string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"Suurin"</string>
    -     <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Muokattu (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
    -     <string name="help_feedback_label" msgid="6815040660801785649">"Ohje ja palaute"</string>
    -+    <string name="content_description_menu_button" msgid="8182594799812351266">"Valikko"</string>
    - </resources>
    -diff --git a/packages/SettingsLib/res/values-fr-rCA/strings.xml b/packages/SettingsLib/res/values-fr-rCA/strings.xml
    -index 958b8fd..2538443 100644
    ---- a/packages/SettingsLib/res/values-fr-rCA/strings.xml
    -+++ b/packages/SettingsLib/res/values-fr-rCA/strings.xml
    -@@ -28,7 +28,8 @@
    -     <string name="wifi_disabled_wifi_failure" msgid="3081668066612876581">"Échec de connexion Wi-Fi"</string>
    -     <string name="wifi_disabled_password_failure" msgid="8659805351763133575">"Problème d\'authentification"</string>
    -     <string name="wifi_not_in_range" msgid="1136191511238508967">"Hors de portée"</string>
    --    <string name="wifi_no_internet" msgid="9151470775868728896">"Aucun accès à Internet détecté, reconnexion automatique impossible"</string>
    -+    <string name="wifi_no_internet_no_reconnect" msgid="2211781637653149657">"Aucun accès à Internet détecté, reconnexion automatique impossible."</string>
    -+    <string name="wifi_no_internet" msgid="5011955173375805204">"Aucun accès à Internet."</string>
    -     <string name="saved_network" msgid="4352716707126620811">"Enregistrés par <xliff:g id="NAME">%1$s</xliff:g>"</string>
    -     <string name="connected_via_wfa" msgid="3805736726317410714">"Connecté à l\'aide de l\'assistant Wi-Fi"</string>
    -     <string name="connected_via_passpoint" msgid="2826205693803088747">"Connecté par %1$s"</string>
    -@@ -233,8 +234,6 @@
    -     <string name="debug_layout_summary" msgid="2001775315258637682">"Afficher les limites, les marges de clip, etc."</string>
    -     <string name="force_rtl_layout_all_locales" msgid="2259906643093138978">"Forcer orient. : g. à d."</string>
    -     <string name="force_rtl_layout_all_locales_summary" msgid="9192797796616132534">"Forcer l\'orientation: g. à droite (toutes langues)"</string>
    --    <string name="show_cpu_usage" msgid="2389212910758076024">"Afficher mém. CPU utilisée"</string>
    --    <string name="show_cpu_usage_summary" msgid="2113341923988958266">"Superposition écran indiquant mémoire CPU utilisée"</string>
    -     <string name="force_hw_ui" msgid="6426383462520888732">"Forcer le rendu GPU"</string>
    -     <string name="force_hw_ui_summary" msgid="5535991166074861515">"Forcer l\'utilisation du GPU pour le dessin 2D"</string>
    -     <string name="force_msaa" msgid="7920323238677284387">"Forcer MSAA 4x"</string>
    -@@ -341,4 +340,5 @@
    -     <string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"La plus grande"</string>
    -     <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Personnalisée (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
    -     <string name="help_feedback_label" msgid="6815040660801785649">"Aide et commentaires"</string>
    -+    <string name="content_description_menu_button" msgid="8182594799812351266">"Menu"</string>
    - </resources>
    -diff --git a/packages/SettingsLib/res/values-fr/strings.xml b/packages/SettingsLib/res/values-fr/strings.xml
    -index cf08f3b..3b5491f 100644
    ---- a/packages/SettingsLib/res/values-fr/strings.xml
    -+++ b/packages/SettingsLib/res/values-fr/strings.xml
    -@@ -28,7 +28,8 @@
    -     <string name="wifi_disabled_wifi_failure" msgid="3081668066612876581">"Échec de la connexion Wi-Fi"</string>
    -     <string name="wifi_disabled_password_failure" msgid="8659805351763133575">"Problème d\'authentification."</string>
    -     <string name="wifi_not_in_range" msgid="1136191511238508967">"Hors de portée"</string>
    --    <string name="wifi_no_internet" msgid="9151470775868728896">"Aucun accès à Internet détecté, reconnexion automatique impossible"</string>
    -+    <string name="wifi_no_internet_no_reconnect" msgid="2211781637653149657">"Aucun accès à Internet détecté. Reconnexion automatique impossible."</string>
    -+    <string name="wifi_no_internet" msgid="5011955173375805204">"Aucun accès à Internet"</string>
    -     <string name="saved_network" msgid="4352716707126620811">"Enregistré par <xliff:g id="NAME">%1$s</xliff:g>"</string>
    -     <string name="connected_via_wfa" msgid="3805736726317410714">"Connecté via l\'assistant Wi‑Fi"</string>
    -     <string name="connected_via_passpoint" msgid="2826205693803088747">"Connecté via %1$s"</string>
    -@@ -233,8 +234,6 @@
    -     <string name="debug_layout_summary" msgid="2001775315258637682">"Afficher les limites de coupe, les marges, etc."</string>
    -     <string name="force_rtl_layout_all_locales" msgid="2259906643093138978">"Forcer droite à gauche"</string>
    -     <string name="force_rtl_layout_all_locales_summary" msgid="9192797796616132534">"Forcer orient. droite à gauche pour toutes langues"</string>
    --    <string name="show_cpu_usage" msgid="2389212910758076024">"Afficher mém. CPU utilisée"</string>
    --    <string name="show_cpu_usage_summary" msgid="2113341923988958266">"Superposition écran indiquant mémoire CPU utilisée"</string>
    -     <string name="force_hw_ui" msgid="6426383462520888732">"Forcer le rendu GPU"</string>
    -     <string name="force_hw_ui_summary" msgid="5535991166074861515">"Forcer l\'utilisation du GPU pour le dessin 2D"</string>
    -     <string name="force_msaa" msgid="7920323238677284387">"Forcer MSAA 4x"</string>
    -@@ -341,4 +340,5 @@
    -     <string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"Le plus grand"</string>
    -     <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Personnalisé (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
    -     <string name="help_feedback_label" msgid="6815040660801785649">"Aide et commentaires"</string>
    -+    <string name="content_description_menu_button" msgid="8182594799812351266">"Menu"</string>
    - </resources>
    -diff --git a/packages/SettingsLib/res/values-gl-rES/strings.xml b/packages/SettingsLib/res/values-gl-rES/strings.xml
    -index cdc4581..dcd45a8 100644
    ---- a/packages/SettingsLib/res/values-gl-rES/strings.xml
    -+++ b/packages/SettingsLib/res/values-gl-rES/strings.xml
    -@@ -28,7 +28,8 @@
    -     <string name="wifi_disabled_wifi_failure" msgid="3081668066612876581">"Erro na conexión wifi"</string>
    -     <string name="wifi_disabled_password_failure" msgid="8659805351763133575">"Problema de autenticación"</string>
    -     <string name="wifi_not_in_range" msgid="1136191511238508967">"Non está dentro da zona de cobertura"</string>
    --    <string name="wifi_no_internet" msgid="9151470775868728896">"Non se detectou acceso a Internet e non se volverá conectar automaticamente."</string>
    -+    <string name="wifi_no_internet_no_reconnect" msgid="2211781637653149657">"Non se detectou acceso a Internet e non se volverá establecer conexión automaticamente."</string>
    -+    <string name="wifi_no_internet" msgid="5011955173375805204">"Non hai acceso a Internet."</string>
    -     <string name="saved_network" msgid="4352716707126620811">"Redes gardadas por <xliff:g id="NAME">%1$s</xliff:g>"</string>
    -     <string name="connected_via_wfa" msgid="3805736726317410714">"Conectado ao asistente de wifi"</string>
    -     <string name="connected_via_passpoint" msgid="2826205693803088747">"Conectado a través de %1$s"</string>
    -@@ -233,8 +234,6 @@
    -     <string name="debug_layout_summary" msgid="2001775315258637682">"Mostra os límites dos clips, as marxes, etc."</string>
    -     <string name="force_rtl_layout_all_locales" msgid="2259906643093138978">"Forzar dirección do deseño RTL"</string>
    -     <string name="force_rtl_layout_all_locales_summary" msgid="9192797796616132534">"Forza a dirección de pantalla a RTL (dereita a esquerda) para todas as configuración rexionais"</string>
    --    <string name="show_cpu_usage" msgid="2389212910758076024">"Mostrar uso da CPU"</string>
    --    <string name="show_cpu_usage_summary" msgid="2113341923988958266">"Superpoñer o uso da CPU na pantalla"</string>
    -     <string name="force_hw_ui" msgid="6426383462520888732">"Forzar procesamento GPU"</string>
    -     <string name="force_hw_ui_summary" msgid="5535991166074861515">"Forzar o uso de GPU para o debuxo en 2D"</string>
    -     <string name="force_msaa" msgid="7920323238677284387">"Forzar MSAA 4x"</string>
    -@@ -341,4 +340,5 @@
    -     <string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"O máis grande"</string>
    -     <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Personalizado (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
    -     <string name="help_feedback_label" msgid="6815040660801785649">"Axuda e suxestións"</string>
    -+    <string name="content_description_menu_button" msgid="8182594799812351266">"Menú"</string>
    - </resources>
    -diff --git a/packages/SettingsLib/res/values-gu-rIN/strings.xml b/packages/SettingsLib/res/values-gu-rIN/strings.xml
    -index 1b40e01..554ca40 100644
    ---- a/packages/SettingsLib/res/values-gu-rIN/strings.xml
    -+++ b/packages/SettingsLib/res/values-gu-rIN/strings.xml
    -@@ -28,7 +28,8 @@
    -     <string name="wifi_disabled_wifi_failure" msgid="3081668066612876581">"WiFi કનેક્શન નિષ્ફળ"</string>
    -     <string name="wifi_disabled_password_failure" msgid="8659805351763133575">"પ્રમાણીકરણ સમસ્યા"</string>
    -     <string name="wifi_not_in_range" msgid="1136191511238508967">"રેન્જમાં નથી"</string>
    --    <string name="wifi_no_internet" msgid="9151470775868728896">"કોઈ ઇન્ટરનેટ અ‍ૅક્સેસ શોધાયું નથી, આપમેળે ફરીથી કનેક્ટ કરશે નહીં."</string>
    -+    <string name="wifi_no_internet_no_reconnect" msgid="2211781637653149657">"કોઈ ઇન્ટરનેટ અ‍ૅક્સેસ મળી નથી, આપમેળે ફરીથી કનેક્ટ કરશે નહીં."</string>
    -+    <string name="wifi_no_internet" msgid="5011955173375805204">"કોઈ ઇન્ટરનેટ ઍક્સેસ નથી."</string>
    -     <string name="saved_network" msgid="4352716707126620811">"<xliff:g id="NAME">%1$s</xliff:g> દ્વારા સચવાયું"</string>
    -     <string name="connected_via_wfa" msgid="3805736726317410714">"Wi-Fi સહાયક દ્વારા કનેક્ટ થયું"</string>
    -     <string name="connected_via_passpoint" msgid="2826205693803088747">"%1$s દ્વારા કનેક્ટ થયેલ"</string>
    -@@ -233,8 +234,6 @@
    -     <string name="debug_layout_summary" msgid="2001775315258637682">"ક્લિપ બાઉન્ડ્સ, હાંસિયાં વગેરે બતાવો."</string>
    -     <string name="force_rtl_layout_all_locales" msgid="2259906643093138978">"RTL લેઆઉટ દિશા નિર્દેશની ફરજ પાડો"</string>
    -     <string name="force_rtl_layout_all_locales_summary" msgid="9192797796616132534">"તમામ લૉકેલ્સ માટે સ્ક્રીન લેઆઉટ દિશા નિર્દેશને RTL ની ફરજ પાડો"</string>
    --    <string name="show_cpu_usage" msgid="2389212910758076024">"CPU સંગ્રહ બતાવો"</string>
    --    <string name="show_cpu_usage_summary" msgid="2113341923988958266">"વર્તમાન CPU વપરાશ દર્શાવતું સ્ક્રીન ઓવરલે"</string>
    -     <string name="force_hw_ui" msgid="6426383462520888732">"GPU રેન્ડરિંગની ફરજ પાડો"</string>
    -     <string name="force_hw_ui_summary" msgid="5535991166074861515">"2જા રેખાંકન માટે GPU ના ઉપયોગની ફરજ પાડો"</string>
    -     <string name="force_msaa" msgid="7920323238677284387">"4x MSAA ને ફરજ પાડો"</string>
    -@@ -341,4 +340,5 @@
    -     <string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"સૌથી મોટું"</string>
    -     <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"કસ્ટમ (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
    -     <string name="help_feedback_label" msgid="6815040660801785649">"સહાય અને પ્રતિસાદ"</string>
    -+    <string name="content_description_menu_button" msgid="8182594799812351266">"મેનુ"</string>
    - </resources>
    -diff --git a/packages/SettingsLib/res/values-hi/strings.xml b/packages/SettingsLib/res/values-hi/strings.xml
    -index 8dfbb4a..fb6f181 100644
    ---- a/packages/SettingsLib/res/values-hi/strings.xml
    -+++ b/packages/SettingsLib/res/values-hi/strings.xml
    -@@ -28,7 +28,8 @@
    -     <string name="wifi_disabled_wifi_failure" msgid="3081668066612876581">"वाईफ़ाई कनेक्‍शन विफलता"</string>
    -     <string name="wifi_disabled_password_failure" msgid="8659805351763133575">"प्रमाणीकरण समस्या"</string>
    -     <string name="wifi_not_in_range" msgid="1136191511238508967">"रेंज में नहीं"</string>
    --    <string name="wifi_no_internet" msgid="9151470775868728896">"किसी इंटरनेट कनेक्‍शन का पता नहीं चला, अपने आप पुन: कनेक्‍ट नहीं हो सकता."</string>
    -+    <string name="wifi_no_internet_no_reconnect" msgid="2211781637653149657">"किसी इंटरनेट कनेक्‍शन का पता नहीं चला, अपने आप फिर से कनेक्‍ट नहीं हो सकता."</string>
    -+    <string name="wifi_no_internet" msgid="5011955173375805204">"कोई इंटरनेट एक्सेस नहीं."</string>
    -     <string name="saved_network" msgid="4352716707126620811">"<xliff:g id="NAME">%1$s</xliff:g> के द्वारा सहेजा गया"</string>
    -     <string name="connected_via_wfa" msgid="3805736726317410714">"वाई-फ़ाई सहायक के द्वारा कनेक्‍ट है"</string>
    -     <string name="connected_via_passpoint" msgid="2826205693803088747">"%1$s के द्वारा उपलब्ध"</string>
    -@@ -233,8 +234,6 @@
    -     <string name="debug_layout_summary" msgid="2001775315258637682">"क्लिप सीमाएं, मार्जिन, आदि दिखाएं."</string>
    -     <string name="force_rtl_layout_all_locales" msgid="2259906643093138978">"RTL लेआउट दिशा लागू करें"</string>
    -     <string name="force_rtl_layout_all_locales_summary" msgid="9192797796616132534">"सभी भाषाओं के लिए स्क्रीन लेआउट दिशा को RTL रखें"</string>
    --    <string name="show_cpu_usage" msgid="2389212910758076024">"CPU उपयोग दिखाएं"</string>
    --    <string name="show_cpu_usage_summary" msgid="2113341923988958266">"स्‍क्रीन ओवरले वर्तमान CPU उपयोग को दिखा रहा है"</string>
    -     <string name="force_hw_ui" msgid="6426383462520888732">"बलपूर्वक GPU रेंडर करें"</string>
    -     <string name="force_hw_ui_summary" msgid="5535991166074861515">"2d ड्रॉइंग के लिए GPU का बलपूर्वक उपयोग करें"</string>
    -     <string name="force_msaa" msgid="7920323238677284387">"4x MSAA को बाध्य करें"</string>
    -@@ -341,4 +340,5 @@
    -     <string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"सबसे बड़ा"</string>
    -     <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"कस्टम (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
    -     <string name="help_feedback_label" msgid="6815040660801785649">"सहायता और फ़ीडबैक"</string>
    -+    <string name="content_description_menu_button" msgid="8182594799812351266">"मेनू"</string>
    - </resources>
    -diff --git a/packages/SettingsLib/res/values-hr/strings.xml b/packages/SettingsLib/res/values-hr/strings.xml
    -index 07e4925..619826d 100644
    ---- a/packages/SettingsLib/res/values-hr/strings.xml
    -+++ b/packages/SettingsLib/res/values-hr/strings.xml
    -@@ -28,7 +28,8 @@
    -     <string name="wifi_disabled_wifi_failure" msgid="3081668066612876581">"Povezivanje s Wi-Fi-jem nije uspjelo"</string>
    -     <string name="wifi_disabled_password_failure" msgid="8659805351763133575">"Problem u autentifikaciji"</string>
    -     <string name="wifi_not_in_range" msgid="1136191511238508967">"Nije u rasponu"</string>
    --    <string name="wifi_no_internet" msgid="9151470775868728896">"Pristup internetu nije otkriven. Nema automatskog ponovnog povezivanja."</string>
    -+    <string name="wifi_no_internet_no_reconnect" msgid="2211781637653149657">"Pristup internetu nije otkriven. Nema automatskog ponovnog povezivanja."</string>
    -+    <string name="wifi_no_internet" msgid="5011955173375805204">"Nema pristupa internetu."</string>
    -     <string name="saved_network" msgid="4352716707126620811">"Spremljeno: <xliff:g id="NAME">%1$s</xliff:g>"</string>
    -     <string name="connected_via_wfa" msgid="3805736726317410714">"Povezani putem pomoćnika za Wi-Fi"</string>
    -     <string name="connected_via_passpoint" msgid="2826205693803088747">"Povezano putem %1$s"</string>
    -@@ -233,8 +234,6 @@
    -     <string name="debug_layout_summary" msgid="2001775315258637682">"Prikazuju se obrubi, margine itd. isječaka."</string>
    -     <string name="force_rtl_layout_all_locales" msgid="2259906643093138978">"Nametni zdesna ulijevo"</string>
    -     <string name="force_rtl_layout_all_locales_summary" msgid="9192797796616132534">"Nametni smjer zdesna ulijevo za sve zemlje/jezike"</string>
    --    <string name="show_cpu_usage" msgid="2389212910758076024">"Prikaži upotrebu procesora"</string>
    --    <string name="show_cpu_usage_summary" msgid="2113341923988958266">"Na zaslonu se prikazuje iskorištenost procesora."</string>
    -     <string name="force_hw_ui" msgid="6426383462520888732">"Nametni GPU renderiranje"</string>
    -     <string name="force_hw_ui_summary" msgid="5535991166074861515">"Nametni upotrebu GPU-a za 2D crteže"</string>
    -     <string name="force_msaa" msgid="7920323238677284387">"Nametni 4x MSAA"</string>
    -@@ -341,4 +340,5 @@
    -     <string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"Najveće"</string>
    -     <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Prilagođeno (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
    -     <string name="help_feedback_label" msgid="6815040660801785649">"Pomoć i povratne informacije"</string>
    -+    <string name="content_description_menu_button" msgid="8182594799812351266">"Izbornik"</string>
    - </resources>
    -diff --git a/packages/SettingsLib/res/values-hu/strings.xml b/packages/SettingsLib/res/values-hu/strings.xml
    -index 0d8ec26..e389c00 100644
    ---- a/packages/SettingsLib/res/values-hu/strings.xml
    -+++ b/packages/SettingsLib/res/values-hu/strings.xml
    -@@ -28,7 +28,8 @@
    -     <string name="wifi_disabled_wifi_failure" msgid="3081668066612876581">"Wi-Fi-kapcsolati hiba"</string>
    -     <string name="wifi_disabled_password_failure" msgid="8659805351763133575">"Azonosítási probléma"</string>
    -     <string name="wifi_not_in_range" msgid="1136191511238508967">"Hatókörön kívül"</string>
    --    <string name="wifi_no_internet" msgid="9151470775868728896">"Nincs érzékelhető internet-hozzáférés, ezért nem kapcsolódik újra automatikusan."</string>
    -+    <string name="wifi_no_internet_no_reconnect" msgid="2211781637653149657">"Nincs érzékelhető internet-hozzáférés, ezért nem kapcsolódik újra automatikusan."</string>
    -+    <string name="wifi_no_internet" msgid="5011955173375805204">"Nincs internet-hozzáférés."</string>
    -     <string name="saved_network" msgid="4352716707126620811">"Mentette: <xliff:g id="NAME">%1$s</xliff:g>"</string>
    -     <string name="connected_via_wfa" msgid="3805736726317410714">"Csatlakozva Wi‑Fi-segéddel"</string>
    -     <string name="connected_via_passpoint" msgid="2826205693803088747">"Csatlakozva a következőn keresztül: %1$s"</string>
    -@@ -233,8 +234,6 @@
    -     <string name="debug_layout_summary" msgid="2001775315258637682">"Kliphatárok, margók stb. megjelenítése."</string>
    -     <string name="force_rtl_layout_all_locales" msgid="2259906643093138978">"Elrendezés jobbról balra"</string>
    -     <string name="force_rtl_layout_all_locales_summary" msgid="9192797796616132534">"Elrendezés jobbról balra minden nyelvnél"</string>
    --    <string name="show_cpu_usage" msgid="2389212910758076024">"CPU-használat mutatása"</string>
    --    <string name="show_cpu_usage_summary" msgid="2113341923988958266">"Képernyőfedvény a jelenlegi CPU-használattal"</string>
    -     <string name="force_hw_ui" msgid="6426383462520888732">"GPU-megjelenítés"</string>
    -     <string name="force_hw_ui_summary" msgid="5535991166074861515">"GPU használatának kényszerítése 2D rajzhoz"</string>
    -     <string name="force_msaa" msgid="7920323238677284387">"4x MSAA kényszerítése"</string>
    -@@ -341,4 +340,5 @@
    -     <string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"Legnagyobb"</string>
    -     <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Egyéni (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
    -     <string name="help_feedback_label" msgid="6815040660801785649">"Súgó és visszajelzés"</string>
    -+    <string name="content_description_menu_button" msgid="8182594799812351266">"Menü"</string>
    - </resources>
    -diff --git a/packages/SettingsLib/res/values-hy-rAM/strings.xml b/packages/SettingsLib/res/values-hy-rAM/strings.xml
    -index cb12fbf..8d2d78e 100644
    ---- a/packages/SettingsLib/res/values-hy-rAM/strings.xml
    -+++ b/packages/SettingsLib/res/values-hy-rAM/strings.xml
    -@@ -28,7 +28,8 @@
    -     <string name="wifi_disabled_wifi_failure" msgid="3081668066612876581">"WiFi կապի ձախողում"</string>
    -     <string name="wifi_disabled_password_failure" msgid="8659805351763133575">"Նույնականացման խնդիր"</string>
    -     <string name="wifi_not_in_range" msgid="1136191511238508967">"Ընդգրկույթից դուրս է"</string>
    --    <string name="wifi_no_internet" msgid="9151470775868728896">"Ինտերնետի հասանելիություն չկա. ավտոմատ կերպով կրկին չի միանա:"</string>
    -+    <string name="wifi_no_internet_no_reconnect" msgid="2211781637653149657">"Ինտերնետ կապ չկա, ինչի պատճառով ավտոմատ վերամիացում չի կատարվի:"</string>
    -+    <string name="wifi_no_internet" msgid="5011955173375805204">"Ինտերնետ կապ չկա:"</string>
    -     <string name="saved_network" msgid="4352716707126620811">"Պահել է հետևյալ օգտվողը՝ <xliff:g id="NAME">%1$s</xliff:g>"</string>
    -     <string name="connected_via_wfa" msgid="3805736726317410714">"Կապակցված է Wi‑Fi Օգնականի միջոցով"</string>
    -     <string name="connected_via_passpoint" msgid="2826205693803088747">"Կապակցված է %1$s-ի միջոցով"</string>
    -@@ -38,7 +39,7 @@
    -     <string name="bluetooth_disconnecting" msgid="8913264760027764974">"Անջատվում է..."</string>
    -     <string name="bluetooth_connecting" msgid="8555009514614320497">"Միանում է..."</string>
    -     <string name="bluetooth_connected" msgid="6038755206916626419">"Միացված է"</string>
    --    <string name="bluetooth_pairing" msgid="1426882272690346242">"Զուգավորում..."</string>
    -+    <string name="bluetooth_pairing" msgid="1426882272690346242">"Զուգակցում..."</string>
    -     <string name="bluetooth_connected_no_headset" msgid="2866994875046035609">"Միացված (առանց հեռախոսի)"</string>
    -     <string name="bluetooth_connected_no_a2dp" msgid="4576188601581440337">"Միացված է (առանց մեդիա)"</string>
    -     <string name="bluetooth_connected_no_map" msgid="6504436917057479986">"Միացված է (հաղորդագրությանը մուտք չկա)"</string>
    -@@ -72,7 +73,7 @@
    -     <string name="bluetooth_pairing_accept" msgid="6163520056536604875">"Զուգավորել"</string>
    -     <string name="bluetooth_pairing_accept_all_caps" msgid="6061699265220789149">"Զուգավորել"</string>
    -     <string name="bluetooth_pairing_decline" msgid="4185420413578948140">"Չեղարկել"</string>
    --    <string name="bluetooth_pairing_will_share_phonebook" msgid="4982239145676394429">"Զուգավորում է մուտքի թույլտվությունը դեպի ձեր կոնտակտները և զանգերի պատմությունը, երբ միացված է:"</string>
    -+    <string name="bluetooth_pairing_will_share_phonebook" msgid="4982239145676394429">"Զուգակցում է մուտքի թույլտվությունը դեպի ձեր կոնտակտները և զանգերի պատմությունը, երբ միացված է:"</string>
    -     <string name="bluetooth_pairing_error_message" msgid="3748157733635947087">"Չհաջողվեց զուգավորել <xliff:g id="DEVICE_NAME">%1$s</xliff:g>-ի հետ:"</string>
    -     <string name="bluetooth_pairing_pin_error_message" msgid="8337234855188925274">"Հնարավոր չեղավ զուգավորվել <xliff:g id="DEVICE_NAME">%1$s</xliff:g>-ի հետ սխալ PIN-ի կամ անցաբառի պատճառով:."</string>
    -     <string name="bluetooth_pairing_device_down_error_message" msgid="7870998403045801381">"Հնարավոր չէ կապ հաստատել  <xliff:g id="DEVICE_NAME">%1$s</xliff:g>-ի հետ:"</string>
    -@@ -233,8 +234,6 @@
    -     <string name="debug_layout_summary" msgid="2001775315258637682">"Ցույց տալ կտրվածքի սահմանները, լուսանցքները և այլն"</string>
    -     <string name="force_rtl_layout_all_locales" msgid="2259906643093138978">"Փոխել RTL-ի դասավորության ուղղությունը"</string>
    -     <string name="force_rtl_layout_all_locales_summary" msgid="9192797796616132534">"Դարձնել էկրանի դասավորության ուղղությունը դեպի RTL բոլոր լեզուների համար"</string>
    --    <string name="show_cpu_usage" msgid="2389212910758076024">"Ցույց տալ CPU-ի աշխատանքը"</string>
    --    <string name="show_cpu_usage_summary" msgid="2113341923988958266">"Էկրանի վերադրումը ցույց է տալիս ընթացիկ CPU օգտագործումը"</string>
    -     <string name="force_hw_ui" msgid="6426383462520888732">"Ստիպել GPU-ին մատուցել"</string>
    -     <string name="force_hw_ui_summary" msgid="5535991166074861515">"Ստիպողաբար GPU-ի օգտագործում 2-րդ պատկերի համար"</string>
    -     <string name="force_msaa" msgid="7920323238677284387">"Ստիպել  4x MSAA"</string>
    -@@ -341,4 +340,5 @@
    -     <string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"Ամենամեծ"</string>
    -     <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Հատուկ (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
    -     <string name="help_feedback_label" msgid="6815040660801785649">"Օգնություն և հետադարձ կապ"</string>
    -+    <string name="content_description_menu_button" msgid="8182594799812351266">"Ընտրացանկ"</string>
    - </resources>
    -diff --git a/packages/SettingsLib/res/values-in/strings.xml b/packages/SettingsLib/res/values-in/strings.xml
    -index ffdb607..0e0d32f 100644
    ---- a/packages/SettingsLib/res/values-in/strings.xml
    -+++ b/packages/SettingsLib/res/values-in/strings.xml
    -@@ -28,7 +28,8 @@
    -     <string name="wifi_disabled_wifi_failure" msgid="3081668066612876581">"Kegagalan Sambungan Wi-Fi"</string>
    -     <string name="wifi_disabled_password_failure" msgid="8659805351763133575">"Masalah autentikasi"</string>
    -     <string name="wifi_not_in_range" msgid="1136191511238508967">"Tidak dalam jangkauan"</string>
    --    <string name="wifi_no_internet" msgid="9151470775868728896">"Akses Internet Tidak Terdeteksi, tidak akan menyambung ulang secara otomatis."</string>
    -+    <string name="wifi_no_internet_no_reconnect" msgid="2211781637653149657">"Akses Internet Tidak Terdeteksi, tidak akan menyambung ulang secara otomatis."</string>
    -+    <string name="wifi_no_internet" msgid="5011955173375805204">"Tidak Ada Akses Internet."</string>
    -     <string name="saved_network" msgid="4352716707126620811">"Disimpan oleh <xliff:g id="NAME">%1$s</xliff:g>"</string>
    -     <string name="connected_via_wfa" msgid="3805736726317410714">"Terhubung melalui Asisten Wi-Fi"</string>
    -     <string name="connected_via_passpoint" msgid="2826205693803088747">"Terhubung melalui %1$s"</string>
    -@@ -233,8 +234,6 @@
    -     <string name="debug_layout_summary" msgid="2001775315258637682">"Tampilkan batas klip, margin, dll."</string>
    -     <string name="force_rtl_layout_all_locales" msgid="2259906643093138978">"Paksa arah tata letak RTL"</string>
    -     <string name="force_rtl_layout_all_locales_summary" msgid="9192797796616132534">"Paksa arah tata letak layar RTL untuk semua lokal"</string>
    --    <string name="show_cpu_usage" msgid="2389212910758076024">"Tampilkan penggunaan CPU"</string>
    --    <string name="show_cpu_usage_summary" msgid="2113341923988958266">"Hamparan layar menampilkan penggunaan CPU saat ini"</string>
    -     <string name="force_hw_ui" msgid="6426383462520888732">"Paksa perenderan GPU"</string>
    -     <string name="force_hw_ui_summary" msgid="5535991166074861515">"Paksa penggunaan GPU untuk gambar 2d"</string>
    -     <string name="force_msaa" msgid="7920323238677284387">"Force 4x MSAA"</string>
    -@@ -341,4 +340,5 @@
    -     <string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"Terbesar"</string>
    -     <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"(<xliff:g id="DENSITYDPI">%d</xliff:g>) khusus"</string>
    -     <string name="help_feedback_label" msgid="6815040660801785649">"Bantuan &amp; masukan"</string>
    -+    <string name="content_description_menu_button" msgid="8182594799812351266">"Menu"</string>
    - </resources>
    -diff --git a/packages/SettingsLib/res/values-is-rIS/strings.xml b/packages/SettingsLib/res/values-is-rIS/strings.xml
    -index 25e13a4..d1c177b 100644
    ---- a/packages/SettingsLib/res/values-is-rIS/strings.xml
    -+++ b/packages/SettingsLib/res/values-is-rIS/strings.xml
    -@@ -28,7 +28,8 @@
    -     <string name="wifi_disabled_wifi_failure" msgid="3081668066612876581">"WiFi-tengingarvilla"</string>
    -     <string name="wifi_disabled_password_failure" msgid="8659805351763133575">"Vandamál við auðkenningu"</string>
    -     <string name="wifi_not_in_range" msgid="1136191511238508967">"Ekkert samband"</string>
    --    <string name="wifi_no_internet" msgid="9151470775868728896">"Enginn netaðgangur fannst; endurtengist ekki sjálfkrafa."</string>
    -+    <string name="wifi_no_internet_no_reconnect" msgid="2211781637653149657">"Enginn netaðgangur fannst, endurtengist ekki sjálfkrafa."</string>
    -+    <string name="wifi_no_internet" msgid="5011955173375805204">"Enginn netaðgangur."</string>
    -     <string name="saved_network" msgid="4352716707126620811">"<xliff:g id="NAME">%1$s</xliff:g> vistaði"</string>
    -     <string name="connected_via_wfa" msgid="3805736726317410714">"Tengt í gegnum Wi-Fi aðstoð"</string>
    -     <string name="connected_via_passpoint" msgid="2826205693803088747">"Tengt í gegnum %1$s"</string>
    -@@ -233,8 +234,6 @@
    -     <string name="debug_layout_summary" msgid="2001775315258637682">"Sýna skurðlínur, spássíur o.s.frv."</string>
    -     <string name="force_rtl_layout_all_locales" msgid="2259906643093138978">"Þvinga umbrot frá hægri til vinstri"</string>
    -     <string name="force_rtl_layout_all_locales_summary" msgid="9192797796616132534">"Þvinga umbrot skjás frá hægri til vinstri fyrir alla tungumálskóða"</string>
    --    <string name="show_cpu_usage" msgid="2389212910758076024">"Sýna örgjörvanotkun"</string>
    --    <string name="show_cpu_usage_summary" msgid="2113341923988958266">"Skjáyfirlögn sem sýnir núverandi örgjörvanotkun"</string>
    -     <string name="force_hw_ui" msgid="6426383462520888732">"Þvinga skjákortsteiknun"</string>
    -     <string name="force_hw_ui_summary" msgid="5535991166074861515">"Þvinga notkun skjákorts fyrir tvívíða teikningu"</string>
    -     <string name="force_msaa" msgid="7920323238677284387">"Þvinga 4x MSAA"</string>
    -@@ -341,4 +340,5 @@
    -     <string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"Stærst"</string>
    -     <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Sérsniðið (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
    -     <string name="help_feedback_label" msgid="6815040660801785649">"Hjálp og ábendingar"</string>
    -+    <string name="content_description_menu_button" msgid="8182594799812351266">"Valmynd"</string>
    - </resources>
    -diff --git a/packages/SettingsLib/res/values-it/strings.xml b/packages/SettingsLib/res/values-it/strings.xml
    -index cb323a2..c566e79 100644
    ---- a/packages/SettingsLib/res/values-it/strings.xml
    -+++ b/packages/SettingsLib/res/values-it/strings.xml
    -@@ -28,7 +28,8 @@
    -     <string name="wifi_disabled_wifi_failure" msgid="3081668066612876581">"Errore connessione Wi-Fi"</string>
    -     <string name="wifi_disabled_password_failure" msgid="8659805351763133575">"Problema di autenticazione"</string>
    -     <string name="wifi_not_in_range" msgid="1136191511238508967">"Fuori portata"</string>
    --    <string name="wifi_no_internet" msgid="9151470775868728896">"Nessun accesso a Internet rilevato, non verrà eseguita la riconnessione automatica."</string>
    -+    <string name="wifi_no_internet_no_reconnect" msgid="2211781637653149657">"Nessun accesso a Internet rilevato. Non verrà eseguita la riconnessione automatica."</string>
    -+    <string name="wifi_no_internet" msgid="5011955173375805204">"Nessun accesso a Internet."</string>
    -     <string name="saved_network" msgid="4352716707126620811">"Salvata da <xliff:g id="NAME">%1$s</xliff:g>"</string>
    -     <string name="connected_via_wfa" msgid="3805736726317410714">"Connesso tramite assistente Wi‑Fi"</string>
    -     <string name="connected_via_passpoint" msgid="2826205693803088747">"Collegato tramite %1$s"</string>
    -@@ -191,7 +192,7 @@
    -     <string name="dev_settings_warning_title" msgid="7244607768088540165">"Consentire impostazioni di sviluppo?"</string>
    -     <string name="dev_settings_warning_message" msgid="2298337781139097964">"Queste impostazioni sono utilizzabili solo a scopo di sviluppo. Possono causare l\'arresto o il comportamento anomalo del dispositivo e delle applicazioni su di esso."</string>
    -     <string name="verify_apps_over_usb_title" msgid="4177086489869041953">"Verifica app tramite USB"</string>
    --    <string name="verify_apps_over_usb_summary" msgid="9164096969924529200">"Controlla che le applicazioni installate tramite ADB/ADT non abbiano un comportamento dannoso."</string>
    -+    <string name="verify_apps_over_usb_summary" msgid="9164096969924529200">"Controlla che le app installate tramite ADB/ADT non abbiano un comportamento dannoso."</string>
    -     <string name="bluetooth_disable_absolute_volume_summary" msgid="6031284410786545957">"Consente di disattivare la funzione del volume assoluto Bluetooth in caso di problemi con il volume dei dispositivi remoti, ad esempio un volume troppo alto o la mancanza di controllo."</string>
    -     <string name="enable_terminal_title" msgid="95572094356054120">"Terminale locale"</string>
    -     <string name="enable_terminal_summary" msgid="67667852659359206">"Abilita l\'app Terminale che offre l\'accesso alla shell locale"</string>
    -@@ -233,8 +234,6 @@
    -     <string name="debug_layout_summary" msgid="2001775315258637682">"Mostra limiti, margini dei clip e così via"</string>
    -     <string name="force_rtl_layout_all_locales" msgid="2259906643093138978">"Forza direzione layout RTL"</string>
    -     <string name="force_rtl_layout_all_locales_summary" msgid="9192797796616132534">"Direzione layout schermo RTL per tutte le lingue"</string>
    --    <string name="show_cpu_usage" msgid="2389212910758076024">"Mostra utilizzo CPU"</string>
    --    <string name="show_cpu_usage_summary" msgid="2113341923988958266">"Overlay schermo che mostra l\'uso corrente della CPU"</string>
    -     <string name="force_hw_ui" msgid="6426383462520888732">"Forza rendering GPU"</string>
    -     <string name="force_hw_ui_summary" msgid="5535991166074861515">"Forza l\'uso della GPU per i disegni 2D"</string>
    -     <string name="force_msaa" msgid="7920323238677284387">"Forza MSAA 4x"</string>
    -@@ -329,8 +328,8 @@
    -     <string name="home" msgid="3256884684164448244">"Home page Impostazioni"</string>
    -   <string-array name="battery_labels">
    -     <item msgid="8494684293649631252">"0%"</item>
    --    <item msgid="8934126114226089439">"50%%"</item>
    --    <item msgid="1286113608943010849">"100%%"</item>
    -+    <item msgid="8934126114226089439">"50%"</item>
    -+    <item msgid="1286113608943010849">"100%"</item>
    -   </string-array>
    -     <string name="charge_length_format" msgid="8978516217024434156">"<xliff:g id="ID_1">%1$s</xliff:g> fa"</string>
    -     <string name="remaining_length_format" msgid="7886337596669190587">"<xliff:g id="ID_1">%1$s</xliff:g> rimanenti"</string>
    -@@ -341,4 +340,5 @@
    -     <string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"Massimo"</string>
    -     <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Personalizzato (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
    -     <string name="help_feedback_label" msgid="6815040660801785649">"Guida e feedback"</string>
    -+    <string name="content_description_menu_button" msgid="8182594799812351266">"Menu"</string>
    - </resources>
    -diff --git a/packages/SettingsLib/res/values-iw/strings.xml b/packages/SettingsLib/res/values-iw/strings.xml
    -index 7c16e42..4523380 100644
    ---- a/packages/SettingsLib/res/values-iw/strings.xml
    -+++ b/packages/SettingsLib/res/values-iw/strings.xml
    -@@ -28,7 +28,8 @@
    -     <string name="wifi_disabled_wifi_failure" msgid="3081668066612876581">"‏כשל בחיבור Wi-Fi"</string>
    -     <string name="wifi_disabled_password_failure" msgid="8659805351763133575">"בעיית אימות"</string>
    -     <string name="wifi_not_in_range" msgid="1136191511238508967">"מחוץ לטווח"</string>
    --    <string name="wifi_no_internet" msgid="9151470775868728896">"אין גישה לאינטרנט. לא יתבצע חיבור מחדש באופן אוטומטי."</string>
    -+    <string name="wifi_no_internet_no_reconnect" msgid="2211781637653149657">"אין גישה לאינטרנט. לא יתבצע חיבור מחדש באופן אוטומטי."</string>
    -+    <string name="wifi_no_internet" msgid="5011955173375805204">"אין גישה לאינטרנט."</string>
    -     <string name="saved_network" msgid="4352716707126620811">"נשמר על ידי <xliff:g id="NAME">%1$s</xliff:g>"</string>
    -     <string name="connected_via_wfa" msgid="3805736726317410714">"‏מחובר באמצעות אסיסטנט ה-Wi-Fi"</string>
    -     <string name="connected_via_passpoint" msgid="2826205693803088747">"‏מחובר דרך %1$s"</string>
    -@@ -233,8 +234,6 @@
    -     <string name="debug_layout_summary" msgid="2001775315258637682">"הצג גבולות קליפ, שוליים וכו\'"</string>
    -     <string name="force_rtl_layout_all_locales" msgid="2259906643093138978">"אלץ כיוון פריסה מימין לשמאל"</string>
    -     <string name="force_rtl_layout_all_locales_summary" msgid="9192797796616132534">"אלץ כיוון פריסת מסך מימין לשמאל עבור כל השפות בכל המקומות"</string>
    --    <string name="show_cpu_usage" msgid="2389212910758076024">"‏הצג את השימוש ב-CPU"</string>
    --    <string name="show_cpu_usage_summary" msgid="2113341923988958266">"‏שכבת-על של מסך שמציגה את השימוש הנוכחי ב-CPU"</string>
    -     <string name="force_hw_ui" msgid="6426383462520888732">"‏אלץ עיבוד ב-GPU"</string>
    -     <string name="force_hw_ui_summary" msgid="5535991166074861515">"‏אכוף שימוש ב-GPU לשרטוט דו-מימדי"</string>
    -     <string name="force_msaa" msgid="7920323238677284387">"‏אלץ הפעלת 4x MSAA"</string>
    -@@ -341,4 +340,5 @@
    -     <string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"הכי גדול"</string>
    -     <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"מותאם אישית (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
    -     <string name="help_feedback_label" msgid="6815040660801785649">"עזרה ומשוב"</string>
    -+    <string name="content_description_menu_button" msgid="8182594799812351266">"תפריט"</string>
    - </resources>
    -diff --git a/packages/SettingsLib/res/values-ja/strings.xml b/packages/SettingsLib/res/values-ja/strings.xml
    -index 25f4152..1761adb 100644
    ---- a/packages/SettingsLib/res/values-ja/strings.xml
    -+++ b/packages/SettingsLib/res/values-ja/strings.xml
    -@@ -28,7 +28,8 @@
    -     <string name="wifi_disabled_wifi_failure" msgid="3081668066612876581">"WiFi接続エラー"</string>
    -     <string name="wifi_disabled_password_failure" msgid="8659805351763133575">"認証に問題"</string>
    -     <string name="wifi_not_in_range" msgid="1136191511238508967">"圏外"</string>
    --    <string name="wifi_no_internet" msgid="9151470775868728896">"インターネットアクセスを検出できないため、自動的に再接続されません。"</string>
    -+    <string name="wifi_no_internet_no_reconnect" msgid="2211781637653149657">"インターネット アクセスを検出できないため、自動的に再接続されません。"</string>
    -+    <string name="wifi_no_internet" msgid="5011955173375805204">"インターネットに接続していません。"</string>
    -     <string name="saved_network" msgid="4352716707126620811">"<xliff:g id="NAME">%1$s</xliff:g>で保存"</string>
    -     <string name="connected_via_wfa" msgid="3805736726317410714">"Wi‑Fiアシスタント経由で接続"</string>
    -     <string name="connected_via_passpoint" msgid="2826205693803088747">"%1$s経由で接続"</string>
    -@@ -233,8 +234,6 @@
    -     <string name="debug_layout_summary" msgid="2001775315258637682">"クリップの境界線、マージンなどを表示"</string>
    -     <string name="force_rtl_layout_all_locales" msgid="2259906643093138978">"RTLレイアウト方向を使用"</string>
    -     <string name="force_rtl_layout_all_locales_summary" msgid="9192797796616132534">"すべての言語/地域で画面レイアウト方向をRTLに設定"</string>
    --    <string name="show_cpu_usage" msgid="2389212910758076024">"CPU使用状況を表示"</string>
    --    <string name="show_cpu_usage_summary" msgid="2113341923988958266">"現在のCPU使用状況をオーバーレイ表示する"</string>
    -     <string name="force_hw_ui" msgid="6426383462520888732">"GPUレンダリングを使用"</string>
    -     <string name="force_hw_ui_summary" msgid="5535991166074861515">"2D描画にGPUを常に使用する"</string>
    -     <string name="force_msaa" msgid="7920323238677284387">"4x MSAAを適用"</string>
    -@@ -343,4 +342,5 @@
    -     <string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"最大"</string>
    -     <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"カスタム(<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
    -     <string name="help_feedback_label" msgid="6815040660801785649">"ヘルプとフィードバック"</string>
    -+    <string name="content_description_menu_button" msgid="8182594799812351266">"メニュー"</string>
    - </resources>
    -diff --git a/packages/SettingsLib/res/values-ka-rGE/strings.xml b/packages/SettingsLib/res/values-ka-rGE/strings.xml
    -index ffe194a..a39d4b2 100644
    ---- a/packages/SettingsLib/res/values-ka-rGE/strings.xml
    -+++ b/packages/SettingsLib/res/values-ka-rGE/strings.xml
    -@@ -28,7 +28,8 @@
    -     <string name="wifi_disabled_wifi_failure" msgid="3081668066612876581">"WiFi კავშირის შეფერხება"</string>
    -     <string name="wifi_disabled_password_failure" msgid="8659805351763133575">"ავთენტიკაციის პრობლემა"</string>
    -     <string name="wifi_not_in_range" msgid="1136191511238508967">"არ არის დიაპაზონში"</string>
    --    <string name="wifi_no_internet" msgid="9151470775868728896">"ინტერნეტთან წვდომის ამოცნობა ვერ მოხერხდა. ავტომატურად ხელახლა დაკავშირება არ განხორციელდება."</string>
    -+    <string name="wifi_no_internet_no_reconnect" msgid="2211781637653149657">"ინტერნეტთან კავშირის ამოცნობა ვერ მოხერხდა. ავტომატურად ხელახლა დაკავშირება არ განხორციელდება."</string>
    -+    <string name="wifi_no_internet" msgid="5011955173375805204">"ინტერნეტთან კავშირი არ არის."</string>
    -     <string name="saved_network" msgid="4352716707126620811">"შენახული <xliff:g id="NAME">%1$s</xliff:g>-ის მიერ"</string>
    -     <string name="connected_via_wfa" msgid="3805736726317410714">"დაკავშირებულია Wi-Fi თანაშემწით"</string>
    -     <string name="connected_via_passpoint" msgid="2826205693803088747">"%1$s-ით დაკავშირებული"</string>
    -@@ -233,8 +234,6 @@
    -     <string name="debug_layout_summary" msgid="2001775315258637682">"კლიპის საზღვრების, მინდვრების ჩვენება და ა.შ."</string>
    -     <string name="force_rtl_layout_all_locales" msgid="2259906643093138978">"მარჯვნიდან მარცხნივ განლაგების მიმართულების იძულება"</string>
    -     <string name="force_rtl_layout_all_locales_summary" msgid="9192797796616132534">"ეკრანის RTL მიმართულებაზე იძულება ყველა ლოკალისათვის"</string>
    --    <string name="show_cpu_usage" msgid="2389212910758076024">"ცენტრალური პროცესორის ჩატვირთვის ჩვენება"</string>
    --    <string name="show_cpu_usage_summary" msgid="2113341923988958266">"ეკრანის გადაფარვა აჩვენებს CPU ამჟამინდელ გამოყენებას"</string>
    -     <string name="force_hw_ui" msgid="6426383462520888732">"GPU-აჩქარება"</string>
    -     <string name="force_hw_ui_summary" msgid="5535991166074861515">"GPU-ის ძალით გამოყენება 2d drawing-თვის"</string>
    -     <string name="force_msaa" msgid="7920323238677284387">"4x MSAA-ს ჩართვა"</string>
    -@@ -341,4 +340,5 @@
    -     <string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"უდიდესი"</string>
    -     <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"მორგებული (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
    -     <string name="help_feedback_label" msgid="6815040660801785649">"დახმარება და გამოხმაურება"</string>
    -+    <string name="content_description_menu_button" msgid="8182594799812351266">"მენიუ"</string>
    - </resources>
    -diff --git a/packages/SettingsLib/res/values-kk-rKZ/strings.xml b/packages/SettingsLib/res/values-kk-rKZ/strings.xml
    -index 3dcc7eb..c636feb 100644
    ---- a/packages/SettingsLib/res/values-kk-rKZ/strings.xml
    -+++ b/packages/SettingsLib/res/values-kk-rKZ/strings.xml
    -@@ -28,7 +28,8 @@
    -     <string name="wifi_disabled_wifi_failure" msgid="3081668066612876581">"Wi-Fi байланысының қатесі"</string>
    -     <string name="wifi_disabled_password_failure" msgid="8659805351763133575">"Растау мәселесі"</string>
    -     <string name="wifi_not_in_range" msgid="1136191511238508967">"Аумақта жоқ"</string>
    --    <string name="wifi_no_internet" msgid="9151470775868728896">"Интернетке қатынас анықталмады, автоматты түрде қайта қосылу орындалмайды."</string>
    -+    <string name="wifi_no_internet_no_reconnect" msgid="2211781637653149657">"Интернетпен байланыс жоқ, автоматты түрде қайта қосылмайды."</string>
    -+    <string name="wifi_no_internet" msgid="5011955173375805204">"Интернетпен байланыс жоқ."</string>
    -     <string name="saved_network" msgid="4352716707126620811">"<xliff:g id="NAME">%1$s</xliff:g> сақтаған"</string>
    -     <string name="connected_via_wfa" msgid="3805736726317410714">"Wi‑Fi көмекшісі арқылы қосылу орындалды"</string>
    -     <string name="connected_via_passpoint" msgid="2826205693803088747">"%1$s арқылы қосылған"</string>
    -@@ -233,8 +234,6 @@
    -     <string name="debug_layout_summary" msgid="2001775315258637682">"Қию шектерін, жиектерін, т.б көрсету."</string>
    -     <string name="force_rtl_layout_all_locales" msgid="2259906643093138978">"Оңнан солға орналасу бағытына реттеу"</string>
    -     <string name="force_rtl_layout_all_locales_summary" msgid="9192797796616132534">"Экранның орналасу бағытын барлық тілдер үшін оңнан солға қарату"</string>
    --    <string name="show_cpu_usage" msgid="2389212910758076024">"CPU (орталық өңдеу бірлігі) қолданысы"</string>
    --    <string name="show_cpu_usage_summary" msgid="2113341923988958266">"Экран бетіне ағымдағы CPU қолданысы көрсетіледі"</string>
    -     <string name="force_hw_ui" msgid="6426383462520888732">"GPU рендерингін жылдамдату"</string>
    -     <string name="force_hw_ui_summary" msgid="5535991166074861515">"Графикалық процессорды 2d сызбаларына қолдану"</string>
    -     <string name="force_msaa" msgid="7920323238677284387">"4x MSAA қолдану"</string>
    -@@ -341,4 +340,5 @@
    -     <string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"Ең үлкен"</string>
    -     <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Арнаулы (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
    -     <string name="help_feedback_label" msgid="6815040660801785649">"Анықтама және пікір"</string>
    -+    <string name="content_description_menu_button" msgid="8182594799812351266">"Mәзір"</string>
    - </resources>
    -diff --git a/packages/SettingsLib/res/values-km-rKH/strings.xml b/packages/SettingsLib/res/values-km-rKH/strings.xml
    -index aa0ce24..94ce5f1 100644
    ---- a/packages/SettingsLib/res/values-km-rKH/strings.xml
    -+++ b/packages/SettingsLib/res/values-km-rKH/strings.xml
    -@@ -28,7 +28,8 @@
    -     <string name="wifi_disabled_wifi_failure" msgid="3081668066612876581">"ការ​ភ្ជាប់​ WiFi បរាជ័យ"</string>
    -     <string name="wifi_disabled_password_failure" msgid="8659805351763133575">"បញ្ហា​ក្នុង​ការ​ផ្ទៀងផ្ទាត់"</string>
    -     <string name="wifi_not_in_range" msgid="1136191511238508967">"នៅ​ក្រៅ​តំបន់"</string>
    --    <string name="wifi_no_internet" msgid="9151470775868728896">"រក​មិន​ឃើញ​ការ​ចូល​ដំណើរការ​អ៊ីនធឺណិត, នឹង​មិន​ភ្ជាប់​ឡើង​វិញ​ដោយ​ស្វ័យ​ប្រវត្តិ​ទេ។"</string>
    -+    <string name="wifi_no_internet_no_reconnect" msgid="2211781637653149657">"រកមិនឃើញការតភ្ជាប់អ៊ីនធឺណិតទេ វានឹងមិនភ្ជាប់ឡើងវិញដោយស្វ័យប្រវត្តិទេ។"</string>
    -+    <string name="wifi_no_internet" msgid="5011955173375805204">"គ្មានការតភ្ជាប់អ៊ីនធឺណិតទេ"</string>
    -     <string name="saved_network" msgid="4352716707126620811">"បានរក្សាទុកដោយ <xliff:g id="NAME">%1$s</xliff:g>"</string>
    -     <string name="connected_via_wfa" msgid="3805736726317410714">"បានភ្ជាប់តាមរយៈជំនួយការ Wi‑Fi"</string>
    -     <string name="connected_via_passpoint" msgid="2826205693803088747">"បានភ្ជាប់តាមរយៈ %1$s"</string>
    -@@ -233,8 +234,6 @@
    -     <string name="debug_layout_summary" msgid="2001775315258637682">"បង្ហាញ​ការ​ភ្ជាប់​អត្ថបទ​សម្រង់ រឹម ។ល។"</string>
    -     <string name="force_rtl_layout_all_locales" msgid="2259906643093138978">"បង្ខំ​ទិស​ប្លង់ RTL"</string>
    -     <string name="force_rtl_layout_all_locales_summary" msgid="9192797796616132534">"បង្ខំ​ទិស​ប្លង់​អេក្រង់​ទៅកាន់ RTL សម្រាប់​មូលដ្ឋាន​ទាំងអស់"</string>
    --    <string name="show_cpu_usage" msgid="2389212910758076024">"បង្ហាញ​​ការ​ប្រើ CPU"</string>
    --    <string name="show_cpu_usage_summary" msgid="2113341923988958266">"អេក្រង់​ត្រួត​គ្នា​បង្ហាញ​​ការ​ប្រើ CPU បច្ចុប្បន្ន"</string>
    -     <string name="force_hw_ui" msgid="6426383462520888732">"បង្ខំ​ឲ្យ​បង្ហាញ GPU"</string>
    -     <string name="force_hw_ui_summary" msgid="5535991166074861515">"បង្ខំ​ប្រើ GPU សម្រាប់​ការ​គូរ​លើក​ទី​ពីរ"</string>
    -     <string name="force_msaa" msgid="7920323238677284387">"បង្ខំ 4x MSAA"</string>
    -@@ -341,4 +340,5 @@
    -     <string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"ធំបំផុត"</string>
    -     <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"ផ្ទាល់ខ្លួន (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
    -     <string name="help_feedback_label" msgid="6815040660801785649">"ជំនួយ និងមតិស្ថាបនា"</string>
    -+    <string name="content_description_menu_button" msgid="8182594799812351266">"ម៉ឺនុយ"</string>
    - </resources>
    -diff --git a/packages/SettingsLib/res/values-kn-rIN/strings.xml b/packages/SettingsLib/res/values-kn-rIN/strings.xml
    -index 643875f..ce10d35 100644
    ---- a/packages/SettingsLib/res/values-kn-rIN/strings.xml
    -+++ b/packages/SettingsLib/res/values-kn-rIN/strings.xml
    -@@ -28,7 +28,8 @@
    -     <string name="wifi_disabled_wifi_failure" msgid="3081668066612876581">"WiFi ಸಂಪರ್ಕ ವಿಫಲತೆ"</string>
    -     <string name="wifi_disabled_password_failure" msgid="8659805351763133575">"ಪ್ರಮಾಣೀಕರಣ ಸಮಸ್ಯೆ"</string>
    -     <string name="wifi_not_in_range" msgid="1136191511238508967">"ವ್ಯಾಪ್ತಿಯಲ್ಲಿಲ್ಲ"</string>
    --    <string name="wifi_no_internet" msgid="9151470775868728896">"ಯಾವುದೇ ಇಂಟರ್ನೆಟ್‌ ಪ್ರವೇಶ ಪತ್ತೆಯಾಗಿಲ್ಲ, ಸ್ವಯಂಚಾಲಿತವಾಗಿ ಮರುಸಂಪರ್ಕಿಸಲು ಸಾಧ್ಯವಿಲ್ಲ."</string>
    -+    <string name="wifi_no_internet_no_reconnect" msgid="2211781637653149657">"ಯಾವುದೇ ಇಂಟರ್ನೆಟ್‌ ಪ್ರವೇಶ ಪತ್ತೆಯಾಗಿಲ್ಲ, ಸ್ವಯಂಚಾಲಿತವಾಗಿ ಮರುಸಂಪರ್ಕಿಸಲು ಸಾಧ್ಯವಿಲ್ಲ."</string>
    -+    <string name="wifi_no_internet" msgid="5011955173375805204">"ಯಾವುದೇ ಇಂಟರ್ನೆಟ್ ಪ್ರವೇಶವಿಲ್ಲ."</string>
    -     <string name="saved_network" msgid="4352716707126620811">"<xliff:g id="NAME">%1$s</xliff:g> ರಿಂದ ಉಳಿಸಲಾಗಿದೆ"</string>
    -     <string name="connected_via_wfa" msgid="3805736726317410714">"Wi‑Fi ಸಹಾಯಕದ ಮೂಲಕ ಸಂಪರ್ಕಿತಗೊಳಿಸಲಾಗಿದೆ"</string>
    -     <string name="connected_via_passpoint" msgid="2826205693803088747">"%1$s ಮೂಲಕ ಸಂಪರ್ಕಗೊಂಡಿದೆ"</string>
    -@@ -93,7 +94,7 @@
    -     <string name="tether_settings_title_all" msgid="8356136101061143841">"ಟೆಥರಿಂಗ್ &amp; ಪೋರ್ಟಬಲ್ ಹಾಟ್‌ಸ್ಪಾಟ್"</string>
    -     <string name="managed_user_title" msgid="8109605045406748842">"ಎಲ್ಲ ಕೆಲಸದ ಅಪ್ಲಿಕೇಶನ್‌ಗಳು"</string>
    -     <string name="user_guest" msgid="8475274842845401871">"ಅತಿಥಿ"</string>
    --    <string name="unknown" msgid="1592123443519355854">"ಅಜ್ಞಾತ"</string>
    -+    <string name="unknown" msgid="1592123443519355854">"ಅಪರಿಚಿತ"</string>
    -     <string name="running_process_item_user_label" msgid="3129887865552025943">"ಬಳಕೆದಾರ: <xliff:g id="USER_NAME">%1$s</xliff:g>"</string>
    -     <string name="launch_defaults_some" msgid="313159469856372621">"ಕೆಲವು ಡೀಫಾಲ್ಟ್‌ಗಳನ್ನು ಹೊಂದಿಸಲಾಗಿದೆ"</string>
    -     <string name="launch_defaults_none" msgid="4241129108140034876">"ಡೀಫಾಲ್ಟ್‌ಗಳನ್ನು ಹೊಂದಿಸಲಾಗಿಲ್ಲ"</string>
    -@@ -233,8 +234,6 @@
    -     <string name="debug_layout_summary" msgid="2001775315258637682">"ಕ್ಲಿಪ್‌ನ ಗಡಿಗಳು, ಅಂಚುಗಳು, ಇತ್ಯಾದಿ ತೋರಿಸು."</string>
    -     <string name="force_rtl_layout_all_locales" msgid="2259906643093138978">"RTL ಲೇಔಟ್‌ ಪರಿಮಿತಿ ಬಲಗೊಳಿಸಿ"</string>
    -     <string name="force_rtl_layout_all_locales_summary" msgid="9192797796616132534">"ಎಲ್ಲ ಸ್ಥಳಗಳಿಗಾಗಿ RTL ಗೆ ಸ್ಕ್ರೀನ್‌ ಲೇಔಟ್‌ ದಿಕ್ಕನ್ನು ಪ್ರಬಲಗೊಳಿಸಿ"</string>
    --    <string name="show_cpu_usage" msgid="2389212910758076024">"CPU ಬಳಕೆಯನ್ನು ತೋರಿಸು"</string>
    --    <string name="show_cpu_usage_summary" msgid="2113341923988958266">"ಪ್ರಸ್ತುತ CPU ಬಳಕೆಯನ್ನು ತೋರಿಸುತ್ತಿರುವ ಪರದೆಯ ಓವರ್‌ಲೇ"</string>
    -     <string name="force_hw_ui" msgid="6426383462520888732">"GPU ನೀಡುವಿಕೆ ಬಲಗೊಳಿಸು"</string>
    -     <string name="force_hw_ui_summary" msgid="5535991166074861515">"2d ಚಿತ್ರಕಲೆಗಾಗಿ GPU ಬಳಕೆ ಬಲಗೊಳಿಸಿ"</string>
    -     <string name="force_msaa" msgid="7920323238677284387">"4x MSAA ಪ್ರಬಲಗೊಳಿಸಿ"</string>
    -@@ -312,7 +311,7 @@
    -     <string name="power_charging_duration_usb_short" msgid="941854728040426399">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g>"</string>
    -     <string name="power_charging_duration_wireless" msgid="1829295708243159464">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> ವೈರ್‌‌ಲೆಸ್‌ನಿಂದ ಪೂರ್ಣವಾಗುವವರೆಗೆ"</string>
    -     <string name="power_charging_duration_wireless_short" msgid="1642664799869599476">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g>"</string>
    --    <string name="battery_info_status_unknown" msgid="196130600938058547">"ಅಜ್ಞಾತ"</string>
    -+    <string name="battery_info_status_unknown" msgid="196130600938058547">"ಅಪರಿಚಿತ"</string>
    -     <string name="battery_info_status_charging" msgid="1705179948350365604">"ಚಾರ್ಜ್ ಆಗುತ್ತಿದೆ"</string>
    -     <string name="battery_info_status_charging_ac" msgid="2909861890674399949">"AC ನಲ್ಲಿ ಚಾರ್ಜ್‌"</string>
    -     <string name="battery_info_status_charging_ac_short" msgid="7431401092096415502">"ಚಾರ್ಜ್ ಆಗುತ್ತಿದೆ"</string>
    -@@ -341,4 +340,5 @@
    -     <string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"ದೊಡ್ಡ"</string>
    -     <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"ಕಸ್ಟಮ್ (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
    -     <string name="help_feedback_label" msgid="6815040660801785649">"ಸಹಾಯ ಮತ್ತು ಪ್ರತಿಕ್ರಿಯೆ"</string>
    -+    <string name="content_description_menu_button" msgid="8182594799812351266">"ಮೆನು"</string>
    - </resources>
    -diff --git a/packages/SettingsLib/res/values-ko/strings.xml b/packages/SettingsLib/res/values-ko/strings.xml
    -index 4617681..6910b37 100644
    ---- a/packages/SettingsLib/res/values-ko/strings.xml
    -+++ b/packages/SettingsLib/res/values-ko/strings.xml
    -@@ -28,7 +28,8 @@
    -     <string name="wifi_disabled_wifi_failure" msgid="3081668066612876581">"Wi-Fi 연결 실패"</string>
    -     <string name="wifi_disabled_password_failure" msgid="8659805351763133575">"인증 문제"</string>
    -     <string name="wifi_not_in_range" msgid="1136191511238508967">"범위 내에 없음"</string>
    --    <string name="wifi_no_internet" msgid="9151470775868728896">"감지된 인터넷 액세스가 없으며 자동으로 다시 연결되지 않습니다."</string>
    -+    <string name="wifi_no_internet_no_reconnect" msgid="2211781637653149657">"감지된 인터넷 액세스가 없으며 자동으로 다시 연결되지 않습니다."</string>
    -+    <string name="wifi_no_internet" msgid="5011955173375805204">"인터넷에 연결되어 있지 않습니다."</string>
    -     <string name="saved_network" msgid="4352716707126620811">"<xliff:g id="NAME">%1$s</xliff:g>(으)로 저장됨"</string>
    -     <string name="connected_via_wfa" msgid="3805736726317410714">"Wi‑Fi 도우미를 통해 연결됨"</string>
    -     <string name="connected_via_passpoint" msgid="2826205693803088747">"%1$s을(를) 통해 연결됨"</string>
    -@@ -233,8 +234,6 @@
    -     <string name="debug_layout_summary" msgid="2001775315258637682">"클립 경계, 여백 등을 표시"</string>
    -     <string name="force_rtl_layout_all_locales" msgid="2259906643093138978">"RTL 레이아웃 방향 강제 적용"</string>
    -     <string name="force_rtl_layout_all_locales_summary" msgid="9192797796616132534">"모든 언어에 대해 화면 레이아웃 방향을 RTL로 강제 적용"</string>
    --    <string name="show_cpu_usage" msgid="2389212910758076024">"CPU 사용량 표시"</string>
    --    <string name="show_cpu_usage_summary" msgid="2113341923988958266">"현재 CPU 사용량 오버레이 표시"</string>
    -     <string name="force_hw_ui" msgid="6426383462520888732">"GPU 렌더링 강제 설정"</string>
    -     <string name="force_hw_ui_summary" msgid="5535991166074861515">"2D 드로잉용으로 GPU 강제 사용"</string>
    -     <string name="force_msaa" msgid="7920323238677284387">"4x MSAA 강제 사용"</string>
    -@@ -341,4 +340,5 @@
    -     <string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"가장 크게"</string>
    -     <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"맞춤(<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
    -     <string name="help_feedback_label" msgid="6815040660801785649">"고객센터"</string>
    -+    <string name="content_description_menu_button" msgid="8182594799812351266">"메뉴"</string>
    - </resources>
    -diff --git a/packages/SettingsLib/res/values-ky-rKG/strings.xml b/packages/SettingsLib/res/values-ky-rKG/strings.xml
    -index 96c1ec0..711551b 100644
    ---- a/packages/SettingsLib/res/values-ky-rKG/strings.xml
    -+++ b/packages/SettingsLib/res/values-ky-rKG/strings.xml
    -@@ -28,7 +28,8 @@
    -     <string name="wifi_disabled_wifi_failure" msgid="3081668066612876581">"WiFi туташуусу бузулду"</string>
    -     <string name="wifi_disabled_password_failure" msgid="8659805351763133575">"Аутентификация маселеси бар"</string>
    -     <string name="wifi_not_in_range" msgid="1136191511238508967">"Тейлөө аймагында эмес"</string>
    --    <string name="wifi_no_internet" msgid="9151470775868728896">"Интернетке кирүү мүмкүнчүлүгү табылган жок, андыктан автоматтык түрдө кайра туташпайт."</string>
    -+    <string name="wifi_no_internet_no_reconnect" msgid="2211781637653149657">"Интернетке кирүү мүмкүнчүлүгү жок, андыктан автоматтык түрдө кайра туташпайт."</string>
    -+    <string name="wifi_no_internet" msgid="5011955173375805204">"Интернетке туташпай турат."</string>
    -     <string name="saved_network" msgid="4352716707126620811">"<xliff:g id="NAME">%1$s</xliff:g> тарабынан сакталды"</string>
    -     <string name="connected_via_wfa" msgid="3805736726317410714">"Wi‑Fi жардамчысы аркылуу туташып турат"</string>
    -     <string name="connected_via_passpoint" msgid="2826205693803088747">"%1$s аркылуу жеткиликтүү"</string>
    -@@ -233,8 +234,6 @@
    -     <string name="debug_layout_summary" msgid="2001775315258637682">"Клиптин чектерин, талааларын ж.б. көргөзүү"</string>
    -     <string name="force_rtl_layout_all_locales" msgid="2259906643093138978">"Солдон оңго багытына мажбурлоо"</string>
    -     <string name="force_rtl_layout_all_locales_summary" msgid="9192797796616132534">"Экрандын жайгашуу багытын бардык тилдер үчүн Оңдон-солго кылуу"</string>
    --    <string name="show_cpu_usage" msgid="2389212910758076024">"CPU колдонулушун көрсөтүү"</string>
    --    <string name="show_cpu_usage_summary" msgid="2113341923988958266">"Учурдагы CPU колдонулушун көрсөтүүчү экран катмары"</string>
    -     <string name="force_hw_ui" msgid="6426383462520888732">"GPU иштетүүсүн мажбурлоо"</string>
    -     <string name="force_hw_ui_summary" msgid="5535991166074861515">"2d тартуу үчүн GPU\'ну колдонууга мажбурлоо"</string>
    -     <string name="force_msaa" msgid="7920323238677284387">"4x MSAA мажбурлоо"</string>
    -@@ -341,4 +340,5 @@
    -     <string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"Эң чоң"</string>
    -     <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Ыңгайлаштырылган (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
    -     <string name="help_feedback_label" msgid="6815040660801785649">"Жардам жана жооп пикир"</string>
    -+    <string name="content_description_menu_button" msgid="8182594799812351266">"Меню"</string>
    - </resources>
    -diff --git a/packages/SettingsLib/res/values-lo-rLA/strings.xml b/packages/SettingsLib/res/values-lo-rLA/strings.xml
    -index 24f0c16..abf36e3 100644
    ---- a/packages/SettingsLib/res/values-lo-rLA/strings.xml
    -+++ b/packages/SettingsLib/res/values-lo-rLA/strings.xml
    -@@ -28,7 +28,8 @@
    -     <string name="wifi_disabled_wifi_failure" msgid="3081668066612876581">"​ການ​ເຊື່ອມ​ຕໍ່ WiFi ລົ້ມ​ເຫຼວ"</string>
    -     <string name="wifi_disabled_password_failure" msgid="8659805351763133575">"ບັນຫາການພິສູດຢືນຢັນ"</string>
    -     <string name="wifi_not_in_range" msgid="1136191511238508967">"ບໍ່ຢູ່ໃນໄລຍະທີ່ເຊື່ອມຕໍ່ໄດ້"</string>
    --    <string name="wifi_no_internet" msgid="9151470775868728896">"​ບໍ່​ພົບ​ການ​ເຊື່ອມ​ຕໍ່​ອິນ​ເຕີ​ເນັດ​, ຈະ​ບໍ່​ຖືກ​ເຊື່ອມ​ຕໍ່​ໃໝ່​ໂດຍ​ອັດ​ຕະ​ໂນ​ມັດ."</string>
    -+    <string name="wifi_no_internet_no_reconnect" msgid="2211781637653149657">"ບໍ່ພົບການເຊື່ອມຕໍ່ອິນເຕີເນັດ, ຈະບໍ່ເຊື່ອມຕໍ່ໃໝ່ໂດຍອັດຕະໂນມັດ."</string>
    -+    <string name="wifi_no_internet" msgid="5011955173375805204">"ບໍ່ມີການເຊື່ອມຕໍ່ອິນເຕີເນັດ."</string>
    -     <string name="saved_network" msgid="4352716707126620811">"ບັນທຶກ​​​ໂດຍ <xliff:g id="NAME">%1$s</xliff:g>"</string>
    -     <string name="connected_via_wfa" msgid="3805736726317410714">"ເຊື່ອມ​ຕໍ່​ຜ່ານ Wi‑Fi ຕົວ​ຊ່ວຍ​ແລ້ວ"</string>
    -     <string name="connected_via_passpoint" msgid="2826205693803088747">"​ເຊື່ອມຕໍ່​ຜ່ານ %1$s ​ແລ້ວ"</string>
    -@@ -233,8 +234,6 @@
    -     <string name="debug_layout_summary" msgid="2001775315258637682">"ສະແດງໜ້າປົກຄລິບ, ຂອບ ແລະອື່ນໆ."</string>
    -     <string name="force_rtl_layout_all_locales" msgid="2259906643093138978">"ບັງ​ຄັບ​ໃຫ້ຮູບຮ່າງຂຽນຈາກຂວາຫາຊ້າຍ"</string>
    -     <string name="force_rtl_layout_all_locales_summary" msgid="9192797796616132534">"ບັງຄັບໃຫ້ຮູບຮ່າງໜ້າຈໍ ຂຽນຈາກຂວາໄປຊ້າຍ ສຳລັບທຸກພາສາ"</string>
    --    <string name="show_cpu_usage" msgid="2389212910758076024">"ສະແດງການນຳໃຊ້ CPU"</string>
    --    <string name="show_cpu_usage_summary" msgid="2113341923988958266">"ການວາງຊ້ອນໜ້າຈໍທີ່ສະແດງການນຳໃຊ້ CPU ໃນປັດຈຸບັນ"</string>
    -     <string name="force_hw_ui" msgid="6426383462520888732">"ບັງຄັບໃຊ້ GPU ປະມວນພາບ"</string>
    -     <string name="force_hw_ui_summary" msgid="5535991166074861515">"ບັງຄັບໃຊ້ GPU ເພື່ອການແຕ້ມພາບ 2 ມິຕິ"</string>
    -     <string name="force_msaa" msgid="7920323238677284387">"ບັງຄັບໃຊ້ 4x MSAA"</string>
    -@@ -341,4 +340,5 @@
    -     <string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"ໃຫຍ່ທີ່ສຸດ"</string>
    -     <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"ປັບແຕ່ງເອງ (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
    -     <string name="help_feedback_label" msgid="6815040660801785649">"ຊ່ວຍເຫຼືອ &amp; ຄຳຕິຊົມ"</string>
    -+    <string name="content_description_menu_button" msgid="8182594799812351266">"ເມນູ"</string>
    - </resources>
    -diff --git a/packages/SettingsLib/res/values-lt/strings.xml b/packages/SettingsLib/res/values-lt/strings.xml
    -index 4b8890d..cab29de 100644
    ---- a/packages/SettingsLib/res/values-lt/strings.xml
    -+++ b/packages/SettingsLib/res/values-lt/strings.xml
    -@@ -28,7 +28,8 @@
    -     <string name="wifi_disabled_wifi_failure" msgid="3081668066612876581">"„Wi-Fi“ ryšio triktis"</string>
    -     <string name="wifi_disabled_password_failure" msgid="8659805351763133575">"Autentifikavimo problema"</string>
    -     <string name="wifi_not_in_range" msgid="1136191511238508967">"Ne diapazone"</string>
    --    <string name="wifi_no_internet" msgid="9151470775868728896">"Neaptikta jokia prieiga prie interneto, nebus automatiškai iš naujo prisijungta."</string>
    -+    <string name="wifi_no_internet_no_reconnect" msgid="2211781637653149657">"Neaptikta jokia prieiga prie interneto, nebus automatiškai iš naujo prisijungta."</string>
    -+    <string name="wifi_no_internet" msgid="5011955173375805204">"Nėra prieigos prie interneto."</string>
    -     <string name="saved_network" msgid="4352716707126620811">"Išsaugojo <xliff:g id="NAME">%1$s</xliff:g>"</string>
    -     <string name="connected_via_wfa" msgid="3805736726317410714">"Prisijungta naudojant „Wi‑Fi“ pagelbiklį"</string>
    -     <string name="connected_via_passpoint" msgid="2826205693803088747">"Prisijungta naudojant „%1$s“"</string>
    -@@ -233,8 +234,6 @@
    -     <string name="debug_layout_summary" msgid="2001775315258637682">"Rodyti iškarpų ribas, kraštines ir t. t."</string>
    -     <string name="force_rtl_layout_all_locales" msgid="2259906643093138978">"Išdėst. iš dešin. į kairę"</string>
    -     <string name="force_rtl_layout_all_locales_summary" msgid="9192797796616132534">"Nust. visų lokalių ekran. išdėst. iš deš. į kairę"</string>
    --    <string name="show_cpu_usage" msgid="2389212910758076024">"Rodyti centr. proc. naud."</string>
    --    <string name="show_cpu_usage_summary" msgid="2113341923988958266">"Ekrano perdanga rodo dabartinį centr. proc. naud."</string>
    -     <string name="force_hw_ui" msgid="6426383462520888732">"Priverst. GPU atvaizd."</string>
    -     <string name="force_hw_ui_summary" msgid="5535991166074861515">"Priverstinai naudoti GPU atvaizduojant 2D formatą"</string>
    -     <string name="force_msaa" msgid="7920323238677284387">"Priverst. vykdyti 4x MSAA"</string>
    -@@ -341,4 +340,5 @@
    -     <string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"Didžiausias"</string>
    -     <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Tinkintas (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
    -     <string name="help_feedback_label" msgid="6815040660801785649">"Pagalba ir atsiliepimai"</string>
    -+    <string name="content_description_menu_button" msgid="8182594799812351266">"Meniu"</string>
    - </resources>
    -diff --git a/packages/SettingsLib/res/values-lv/strings.xml b/packages/SettingsLib/res/values-lv/strings.xml
    -index 4d76adc..90bf867 100644
    ---- a/packages/SettingsLib/res/values-lv/strings.xml
    -+++ b/packages/SettingsLib/res/values-lv/strings.xml
    -@@ -28,7 +28,8 @@
    -     <string name="wifi_disabled_wifi_failure" msgid="3081668066612876581">"Wi-Fi savienojuma kļūme"</string>
    -     <string name="wifi_disabled_password_failure" msgid="8659805351763133575">"Autentificēšanas problēma"</string>
    -     <string name="wifi_not_in_range" msgid="1136191511238508967">"Nav diapazona ietvaros"</string>
    --    <string name="wifi_no_internet" msgid="9151470775868728896">"Nevar noteikt interneta savienojumu. Savienojums netiks izveidots vēlreiz automātiski."</string>
    -+    <string name="wifi_no_internet_no_reconnect" msgid="2211781637653149657">"Nevar noteikt interneta savienojumu. Savienojums netiks izveidots vēlreiz automātiski."</string>
    -+    <string name="wifi_no_internet" msgid="5011955173375805204">"Nav piekļuves internetam."</string>
    -     <string name="saved_network" msgid="4352716707126620811">"Saglabāja: <xliff:g id="NAME">%1$s</xliff:g>"</string>
    -     <string name="connected_via_wfa" msgid="3805736726317410714">"Izveidots savienojums ar Wi‑Fi palīgu"</string>
    -     <string name="connected_via_passpoint" msgid="2826205693803088747">"Savienots, izmantojot %1$s"</string>
    -@@ -233,8 +234,6 @@
    -     <string name="debug_layout_summary" msgid="2001775315258637682">"Rādīt klipu robežas, malas utt."</string>
    -     <string name="force_rtl_layout_all_locales" msgid="2259906643093138978">"Virziens no labās uz kreiso (Obligāts) WL: 295"</string>
    -     <string name="force_rtl_layout_all_locales_summary" msgid="9192797796616132534">"Obl. izkārt. virz. no labās uz kr. pusi visām lok."</string>
    --    <string name="show_cpu_usage" msgid="2389212910758076024">"Rādīt CPU lietojumu"</string>
    --    <string name="show_cpu_usage_summary" msgid="2113341923988958266">"Ekrāna pārklājums ar aktuālo CPU lietojumu"</string>
    -     <string name="force_hw_ui" msgid="6426383462520888732">"Piespiedu GPU render."</string>
    -     <string name="force_hw_ui_summary" msgid="5535991166074861515">"Izmantot GPU atveidi divdimensiju zīmējumiem"</string>
    -     <string name="force_msaa" msgid="7920323238677284387">"4x MSAA piespiedu palaiš."</string>
    -@@ -341,4 +340,5 @@
    -     <string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"Vislielākais"</string>
    -     <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Pielāgots (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
    -     <string name="help_feedback_label" msgid="6815040660801785649">"Palīdzība un atsauksmes"</string>
    -+    <string name="content_description_menu_button" msgid="8182594799812351266">"Izvēlne"</string>
    - </resources>
    -diff --git a/packages/SettingsLib/res/values-mk-rMK/strings.xml b/packages/SettingsLib/res/values-mk-rMK/strings.xml
    -index 953360a..725a39d 100644
    ---- a/packages/SettingsLib/res/values-mk-rMK/strings.xml
    -+++ b/packages/SettingsLib/res/values-mk-rMK/strings.xml
    -@@ -28,7 +28,8 @@
    -     <string name="wifi_disabled_wifi_failure" msgid="3081668066612876581">"Поврзувањето преку Wi-Fi не успеа"</string>
    -     <string name="wifi_disabled_password_failure" msgid="8659805351763133575">"Проблем со автентикација"</string>
    -     <string name="wifi_not_in_range" msgid="1136191511238508967">"Надвор од опсег"</string>
    --    <string name="wifi_no_internet" msgid="9151470775868728896">"Не е откриен пристап до интернет, нема автоматски повторно да се поврзете."</string>
    -+    <string name="wifi_no_internet_no_reconnect" msgid="2211781637653149657">"Не е откриен пристап до Интернет, нема автоматски повторно да се поврзете."</string>
    -+    <string name="wifi_no_internet" msgid="5011955173375805204">"Нема пристап до Интернет."</string>
    -     <string name="saved_network" msgid="4352716707126620811">"Зачувано од <xliff:g id="NAME">%1$s</xliff:g>"</string>
    -     <string name="connected_via_wfa" msgid="3805736726317410714">"Поврзано преку помошник за Wi-Fismile"</string>
    -     <string name="connected_via_passpoint" msgid="2826205693803088747">"Поврзано преку %1$s"</string>
    -@@ -233,8 +234,6 @@
    -     <string name="debug_layout_summary" msgid="2001775315258637682">"Прикажи граници на клип, маргини, итн."</string>
    -     <string name="force_rtl_layout_all_locales" msgid="2259906643093138978">"Сила на RTL за насока на слој"</string>
    -     <string name="force_rtl_layout_all_locales_summary" msgid="9192797796616132534">"Присилно постави насока на распоред на екран во РТЛ за сите локални стандарди"</string>
    --    <string name="show_cpu_usage" msgid="2389212910758076024">"Прикажи употреба на ЦПУ"</string>
    --    <string name="show_cpu_usage_summary" msgid="2113341923988958266">"Прекривка на екран прикаж. употреба на тековен ЦПУ"</string>
    -     <string name="force_hw_ui" msgid="6426383462520888732">"Присили рендерирање на GPU"</string>
    -     <string name="force_hw_ui_summary" msgid="5535991166074861515">"Присилно користење на GPU за цртеж 2D"</string>
    -     <string name="force_msaa" msgid="7920323238677284387">"Сила 4x MSAA"</string>
    -@@ -341,4 +340,5 @@
    -     <string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"Најголем"</string>
    -     <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Приспособен (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
    -     <string name="help_feedback_label" msgid="6815040660801785649">"Помош и повратни информации"</string>
    -+    <string name="content_description_menu_button" msgid="8182594799812351266">"Мени"</string>
    - </resources>
    -diff --git a/packages/SettingsLib/res/values-ml-rIN/strings.xml b/packages/SettingsLib/res/values-ml-rIN/strings.xml
    -index 92c0448..01565ac 100644
    ---- a/packages/SettingsLib/res/values-ml-rIN/strings.xml
    -+++ b/packages/SettingsLib/res/values-ml-rIN/strings.xml
    -@@ -28,7 +28,8 @@
    -     <string name="wifi_disabled_wifi_failure" msgid="3081668066612876581">"WiFi കണക്ഷൻ പരാജയം"</string>
    -     <string name="wifi_disabled_password_failure" msgid="8659805351763133575">"ആധികാരികമാക്കുന്നതിലെ പ്രശ്‌നം"</string>
    -     <string name="wifi_not_in_range" msgid="1136191511238508967">"പരിധിയിലില്ല"</string>
    --    <string name="wifi_no_internet" msgid="9151470775868728896">"ഇന്റർനെറ്റ് ആക്സസ്സൊന്നും കണ്ടെത്താത്തതിനാൽ സ്വയം വീണ്ടും കണക്‌റ്റുചെയ്യില്ല."</string>
    -+    <string name="wifi_no_internet_no_reconnect" msgid="2211781637653149657">"ഇന്റർനെറ്റ് ആക്സസ്സൊന്നും കണ്ടെത്താത്തതിനാൽ സ്വയം വീണ്ടും കണക്‌റ്റുചെയ്യില്ല."</string>
    -+    <string name="wifi_no_internet" msgid="5011955173375805204">"ഇന്റർനെറ്റ് ആക്‌സസ്സ് ഇല്ല."</string>
    -     <string name="saved_network" msgid="4352716707126620811">"<xliff:g id="NAME">%1$s</xliff:g> സംരക്ഷിച്ചത്"</string>
    -     <string name="connected_via_wfa" msgid="3805736726317410714">"വൈഫൈ അസിസ്റ്റന്റ് മുഖേന കണക്‌റ്റുചെയ്തു"</string>
    -     <string name="connected_via_passpoint" msgid="2826205693803088747">"%1$s വഴി ബന്ധിപ്പിച്ചു"</string>
    -@@ -233,8 +234,6 @@
    -     <string name="debug_layout_summary" msgid="2001775315258637682">"ക്ലിപ്പ് ബൗണ്ടുകൾ, മാർജിനുകൾ തുടങ്ങിയവ ദൃശ്യമാക്കുക"</string>
    -     <string name="force_rtl_layout_all_locales" msgid="2259906643093138978">"RTL ലേഔട്ട് ഡയറക്ഷൻ നിർബന്ധമാക്കുക"</string>
    -     <string name="force_rtl_layout_all_locales_summary" msgid="9192797796616132534">"എല്ലാ ഭാഷകൾക്കുമായി സ്‌ക്രീൻ ലേഔട്ട് ഡയറക്ഷൻ RTL-ലേക്ക് നിർബന്ധമാക്കുക"</string>
    --    <string name="show_cpu_usage" msgid="2389212910758076024">"CPU ഉപയോഗം ദൃശ്യമാക്കുക"</string>
    --    <string name="show_cpu_usage_summary" msgid="2113341923988958266">"സ്ക്രീൻ ഓവർലേ നിലവിലെ CPU ഉപയോഗം ദൃശ്യമാക്കുന്നു"</string>
    -     <string name="force_hw_ui" msgid="6426383462520888732">"GPU റെൻഡറിംഗ് ഫോഴ്സ്ചെയ്യുക"</string>
    -     <string name="force_hw_ui_summary" msgid="5535991166074861515">"2d ഡ്രോയിംഗിനായുള്ള നിരബന്ധിത GPU ഉപയോഗം"</string>
    -     <string name="force_msaa" msgid="7920323238677284387">"4x MSAA നിർബന്ധമാക്കുക"</string>
    -@@ -341,4 +340,5 @@
    -     <string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"ഏറ്റവും വലുത്"</string>
    -     <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"ഇഷ്ടാനുസൃതം ( <xliff:g id="DENSITYDPI">%d</xliff:g> )"</string>
    -     <string name="help_feedback_label" msgid="6815040660801785649">"സഹായവും പ്രതികരണവും"</string>
    -+    <string name="content_description_menu_button" msgid="8182594799812351266">"മെനു"</string>
    - </resources>
    -diff --git a/packages/SettingsLib/res/values-mn-rMN/strings.xml b/packages/SettingsLib/res/values-mn-rMN/strings.xml
    -index 4c98c04..5121f44 100644
    ---- a/packages/SettingsLib/res/values-mn-rMN/strings.xml
    -+++ b/packages/SettingsLib/res/values-mn-rMN/strings.xml
    -@@ -28,7 +28,8 @@
    -     <string name="wifi_disabled_wifi_failure" msgid="3081668066612876581">"WiFi холболт амжилтгүй"</string>
    -     <string name="wifi_disabled_password_failure" msgid="8659805351763133575">"Гэрчлэлийн асуудал"</string>
    -     <string name="wifi_not_in_range" msgid="1136191511238508967">"Хүрээнд байхгүй"</string>
    --    <string name="wifi_no_internet" msgid="9151470775868728896">"Интернэт холболт илэрсэнгүй, автоматаар дахин холболт хийгдэхгүй"</string>
    -+    <string name="wifi_no_internet_no_reconnect" msgid="2211781637653149657">"Интернэт хандалт олдсонгүй тул автоматаар дахин холбогдохгүй."</string>
    -+    <string name="wifi_no_internet" msgid="5011955173375805204">"Интернэт хандалт алга"</string>
    -     <string name="saved_network" msgid="4352716707126620811">"<xliff:g id="NAME">%1$s</xliff:g> хадгалсан"</string>
    -     <string name="connected_via_wfa" msgid="3805736726317410714">"Wi-Fi туслагчаар дамжуулан холбогдлоо"</string>
    -     <string name="connected_via_passpoint" msgid="2826205693803088747">"%1$s-р холбогдсон"</string>
    -@@ -233,8 +234,6 @@
    -     <string name="debug_layout_summary" msgid="2001775315258637682">"Клипийн зах, хязгаар зэргийг харуулах"</string>
    -     <string name="force_rtl_layout_all_locales" msgid="2259906643093138978">"RTL байрлалын чиглэлийг хүчээр тогтоох"</string>
    -     <string name="force_rtl_layout_all_locales_summary" msgid="9192797796616132534">"Бүх локалын хувьд дэлгэцийн байрлалын чиглэлийг хүчээр RTL болгох"</string>
    --    <string name="show_cpu_usage" msgid="2389212910758076024">"CPU ашиглалтыг харуулах"</string>
    --    <string name="show_cpu_usage_summary" msgid="2113341923988958266">"Дэлгэцийн давхцалаар одоогийн CPU ашиглалтыг харуулж байна"</string>
    -     <string name="force_hw_ui" msgid="6426383462520888732">"Хүчээр GPU ашиглах"</string>
    -     <string name="force_hw_ui_summary" msgid="5535991166074861515">"GPU-г 2d зурагт хүчээр ашиглах"</string>
    -     <string name="force_msaa" msgid="7920323238677284387">"Хүчээр 4x MSAA ашиглах"</string>
    -@@ -341,4 +340,5 @@
    -     <string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"Хамгийн том"</string>
    -     <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Тогтмол утга (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
    -     <string name="help_feedback_label" msgid="6815040660801785649">"Тусламж, санал хүсэлт"</string>
    -+    <string name="content_description_menu_button" msgid="8182594799812351266">"Цэс"</string>
    - </resources>
    -diff --git a/packages/SettingsLib/res/values-mr-rIN/strings.xml b/packages/SettingsLib/res/values-mr-rIN/strings.xml
    -index e3a7cc4..5ee18d5 100644
    ---- a/packages/SettingsLib/res/values-mr-rIN/strings.xml
    -+++ b/packages/SettingsLib/res/values-mr-rIN/strings.xml
    -@@ -28,7 +28,8 @@
    -     <string name="wifi_disabled_wifi_failure" msgid="3081668066612876581">"WiFi कनेक्शन अयशस्वी"</string>
    -     <string name="wifi_disabled_password_failure" msgid="8659805351763133575">"प्रमाणीकरण समस्या"</string>
    -     <string name="wifi_not_in_range" msgid="1136191511238508967">"परिक्षेत्रामध्ये नाही"</string>
    --    <string name="wifi_no_internet" msgid="9151470775868728896">"कोणताही इंटरनेट प्रवेश आढळला नाही, स्वयंचलितपणे रीकनेक्ट करणार नाही."</string>
    -+    <string name="wifi_no_internet_no_reconnect" msgid="2211781637653149657">"कोणताही इंटरनेट प्रवेश आढळला नाही, स्वयंचलितपणे पुन्हा कनेक्ट करणार नाही."</string>
    -+    <string name="wifi_no_internet" msgid="5011955173375805204">"इंटरनेट प्रवेश नाही."</string>
    -     <string name="saved_network" msgid="4352716707126620811">"<xliff:g id="NAME">%1$s</xliff:g> द्वारे जतन केले"</string>
    -     <string name="connected_via_wfa" msgid="3805736726317410714">"Wi‑Fi सहाय्यक द्वारे कनेक्ट केले"</string>
    -     <string name="connected_via_passpoint" msgid="2826205693803088747">"%1$s द्वारे कनेक्‍ट केले"</string>
    -@@ -233,8 +234,6 @@
    -     <string name="debug_layout_summary" msgid="2001775315258637682">"क्लिप सीमा, समास इत्यादी दर्शवा."</string>
    -     <string name="force_rtl_layout_all_locales" msgid="2259906643093138978">"RTL लेआउट दिशानिर्देशाची सक्ती करा"</string>
    -     <string name="force_rtl_layout_all_locales_summary" msgid="9192797796616132534">"सर्व लोकॅलसाठी RTL स्क्रीन लेआउट दिशानिर्देशाची सक्ती करा"</string>
    --    <string name="show_cpu_usage" msgid="2389212910758076024">"CPU वापर दर्शवा"</string>
    --    <string name="show_cpu_usage_summary" msgid="2113341923988958266">"वर्तमान CPU वापर दर्शविणारे स्क्रीन आच्छादन"</string>
    -     <string name="force_hw_ui" msgid="6426383462520888732">"GPU प्रस्तुतीस सक्ती करा"</string>
    -     <string name="force_hw_ui_summary" msgid="5535991166074861515">"2d रेखांकनासाठी GPU च्या वापराची सक्ती करा"</string>
    -     <string name="force_msaa" msgid="7920323238677284387">"4x MSAA ची सक्ती करा"</string>
    -@@ -341,4 +340,5 @@
    -     <string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"सर्वात मोठा"</string>
    -     <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"सानुकूल करा (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
    -     <string name="help_feedback_label" msgid="6815040660801785649">"मदत आणि अभिप्राय"</string>
    -+    <string name="content_description_menu_button" msgid="8182594799812351266">"मेनू"</string>
    - </resources>
    -diff --git a/packages/SettingsLib/res/values-ms-rMY/strings.xml b/packages/SettingsLib/res/values-ms-rMY/strings.xml
    -index a1caa2a..fabfd63 100644
    ---- a/packages/SettingsLib/res/values-ms-rMY/strings.xml
    -+++ b/packages/SettingsLib/res/values-ms-rMY/strings.xml
    -@@ -28,7 +28,8 @@
    -     <string name="wifi_disabled_wifi_failure" msgid="3081668066612876581">"Kegagalan Sambungan WiFi"</string>
    -     <string name="wifi_disabled_password_failure" msgid="8659805351763133575">"Masalah pengesahan"</string>
    -     <string name="wifi_not_in_range" msgid="1136191511238508967">"Tidak dalam liputan"</string>
    --    <string name="wifi_no_internet" msgid="9151470775868728896">"Tiada Akses Internet Dikesan, tidak akan menyambung secara automatik."</string>
    -+    <string name="wifi_no_internet_no_reconnect" msgid="2211781637653149657">"Tiada Akses Internet Dikesan, tidak akan menyambung secara automatik."</string>
    -+    <string name="wifi_no_internet" msgid="5011955173375805204">"Tiada Akses Internet."</string>
    -     <string name="saved_network" msgid="4352716707126620811">"Diselamatkan oleh <xliff:g id="NAME">%1$s</xliff:g>"</string>
    -     <string name="connected_via_wfa" msgid="3805736726317410714">"Disambungkan melalui Pembantu Wi-Fi"</string>
    -     <string name="connected_via_passpoint" msgid="2826205693803088747">"Disambungkan melalui %1$s"</string>
    -@@ -233,8 +234,6 @@
    -     <string name="debug_layout_summary" msgid="2001775315258637682">"Tunjukkan batas klip, margin dll."</string>
    -     <string name="force_rtl_layout_all_locales" msgid="2259906643093138978">"Paksa arah reka letak RTL"</string>
    -     <string name="force_rtl_layout_all_locales_summary" msgid="9192797796616132534">"Paksa arah reka letak skrin RTL bagi semua tempat peristiwa"</string>
    --    <string name="show_cpu_usage" msgid="2389212910758076024">"Tunjukkan penggunaan CPU"</string>
    --    <string name="show_cpu_usage_summary" msgid="2113341923988958266">"Tindihan skrin menunjukkan penggunaan semasa CPU"</string>
    -     <string name="force_hw_ui" msgid="6426383462520888732">"Paksa pemaparan GPU"</string>
    -     <string name="force_hw_ui_summary" msgid="5535991166074861515">"Paksa penggunaan GPU untuk lukisan 2d"</string>
    -     <string name="force_msaa" msgid="7920323238677284387">"Paksa 4x MSAA"</string>
    -@@ -341,4 +340,5 @@
    -     <string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"Terbesar"</string>
    -     <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Tersuai (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
    -     <string name="help_feedback_label" msgid="6815040660801785649">"Bantuan &amp; maklum balas"</string>
    -+    <string name="content_description_menu_button" msgid="8182594799812351266">"Menu"</string>
    - </resources>
    -diff --git a/packages/SettingsLib/res/values-my-rMM/strings.xml b/packages/SettingsLib/res/values-my-rMM/strings.xml
    -index 6a1c331..571a931 100644
    ---- a/packages/SettingsLib/res/values-my-rMM/strings.xml
    -+++ b/packages/SettingsLib/res/values-my-rMM/strings.xml
    -@@ -28,7 +28,8 @@
    -     <string name="wifi_disabled_wifi_failure" msgid="3081668066612876581">"WiFi ချိတ်ဆက်မှု မအောင်မြင်ပါ"</string>
    -     <string name="wifi_disabled_password_failure" msgid="8659805351763133575">"စစ်မှန်ကြောင်းအတည်ပြုရန်၌ ပြသနာရှိခြင်း"</string>
    -     <string name="wifi_not_in_range" msgid="1136191511238508967">"စက်ကွင်းထဲတွင် မဟုတ်ပါ"</string>
    --    <string name="wifi_no_internet" msgid="9151470775868728896">"မည်သည့် အင်တာနက်မျှမရှိပါ၊ အလိုအလျောက် ပြန်လည်မချိတ်ဆက်ပါ။"</string>
    -+    <string name="wifi_no_internet_no_reconnect" msgid="2211781637653149657">"အင်တာနက်ချိတ်ဆက်မှု ရှာမတွေ့ပါ၊ အလိုအလျောက် ပြန်လည်ချိတ်ဆက်မည် မဟုတ်ပါ။"</string>
    -+    <string name="wifi_no_internet" msgid="5011955173375805204">"အင်တာနက် ချိတ်ဆက်မှု မရှိပါ။"</string>
    -     <string name="saved_network" msgid="4352716707126620811">"<xliff:g id="NAME">%1$s</xliff:g> မှသိမ်းဆည်းခဲ့သည်"</string>
    -     <string name="connected_via_wfa" msgid="3805736726317410714">"ကြိုးမဲ့ကူညီသူမှတဆင့် ချိတ်ဆက်၏"</string>
    -     <string name="connected_via_passpoint" msgid="2826205693803088747">"%1$s မှတစ်ဆင့် ချိတ်ဆက်ထားသည်"</string>
    -@@ -233,8 +234,6 @@
    -     <string name="debug_layout_summary" msgid="2001775315258637682">"ဖြတ်ပိုင်းအနားသတ်များ၊ အနားများ စသဖြင့် ပြပါ။"</string>
    -     <string name="force_rtl_layout_all_locales" msgid="2259906643093138978">"RTL ဖွဲ့စည်းပုံအညွှန်း မဖြစ်မနေလုပ်ပါ"</string>
    -     <string name="force_rtl_layout_all_locales_summary" msgid="9192797796616132534">"လိုကယ်လ်အားလုံးအတွက် မျက်နှာပြင် ဖွဲ့စည်းပုံအညွှန်း မဖြစ်မနေလုပ်ရန်"</string>
    --    <string name="show_cpu_usage" msgid="2389212910758076024">"CPUအသုံးပြုမှုအား ပြသရန်"</string>
    --    <string name="show_cpu_usage_summary" msgid="2113341923988958266">"လက်ရှိCPUအသုံးပြုမှုအားလုံး မျက်နှာပြင်တွင်ပြသမှု"</string>
    -     <string name="force_hw_ui" msgid="6426383462520888732">"GPUအား အတင်းအကျပ်ဖြစ်စေမည်"</string>
    -     <string name="force_hw_ui_summary" msgid="5535991166074861515">"GPUကို ၂ဖက်မြင်ပုံဆွဲခြင်းအတွက် မဖြစ်မနေအသုံးပြုစေရန်"</string>
    -     <string name="force_msaa" msgid="7920323238677284387">"တွန်းအား ၄× MSAA"</string>
    -@@ -341,4 +340,5 @@
    -     <string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"အကြီးဆုံး"</string>
    -     <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"စိတ်ကြိုက် (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
    -     <string name="help_feedback_label" msgid="6815040660801785649">"အကူအညီနှင့် အကြံပြုချက်"</string>
    -+    <string name="content_description_menu_button" msgid="8182594799812351266">"မီနူး"</string>
    - </resources>
    -diff --git a/packages/SettingsLib/res/values-nb/strings.xml b/packages/SettingsLib/res/values-nb/strings.xml
    -index 5d8ae55..834c849 100644
    ---- a/packages/SettingsLib/res/values-nb/strings.xml
    -+++ b/packages/SettingsLib/res/values-nb/strings.xml
    -@@ -28,7 +28,8 @@
    -     <string name="wifi_disabled_wifi_failure" msgid="3081668066612876581">"Wi-Fi-tilkoblingsfeil"</string>
    -     <string name="wifi_disabled_password_failure" msgid="8659805351763133575">"Autentiseringsproblem"</string>
    -     <string name="wifi_not_in_range" msgid="1136191511238508967">"Utenfor område"</string>
    --    <string name="wifi_no_internet" msgid="9151470775868728896">"Ingen Internett-tilgang ble funnet. Kan ikke koble til på nytt automatisk."</string>
    -+    <string name="wifi_no_internet_no_reconnect" msgid="2211781637653149657">"Fant ingen Internett-tilgang. Kan ikke automatisk koble til på nytt."</string>
    -+    <string name="wifi_no_internet" msgid="5011955173375805204">"Ingen Internett-tilgang."</string>
    -     <string name="saved_network" msgid="4352716707126620811">"Lagret av <xliff:g id="NAME">%1$s</xliff:g>"</string>
    -     <string name="connected_via_wfa" msgid="3805736726317410714">"Koblet til via en Wi-Fi-assistent"</string>
    -     <string name="connected_via_passpoint" msgid="2826205693803088747">"Tilkoblet via %1$s"</string>
    -@@ -233,8 +234,6 @@
    -     <string name="debug_layout_summary" msgid="2001775315258637682">"Vis kanter, marger osv."</string>
    -     <string name="force_rtl_layout_all_locales" msgid="2259906643093138978">"Tving layoutretning for RTL"</string>
    -     <string name="force_rtl_layout_all_locales_summary" msgid="9192797796616132534">"Tving RTL-retning på skjermen for alle språk"</string>
    --    <string name="show_cpu_usage" msgid="2389212910758076024">"Vis CPU-bruk"</string>
    --    <string name="show_cpu_usage_summary" msgid="2113341923988958266">"Skjermoverlegg viser gjeldende CPU-bruk"</string>
    -     <string name="force_hw_ui" msgid="6426383462520888732">"Tving GPU-gjengivelse"</string>
    -     <string name="force_hw_ui_summary" msgid="5535991166074861515">"Tving bruk av GPU for 2D-tegning"</string>
    -     <string name="force_msaa" msgid="7920323238677284387">"Tving 4x MSAA"</string>
    -@@ -341,4 +340,5 @@
    -     <string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"Størst"</string>
    -     <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Egendefinert (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
    -     <string name="help_feedback_label" msgid="6815040660801785649">"Hjelp og tilbakemelding"</string>
    -+    <string name="content_description_menu_button" msgid="8182594799812351266">"Meny"</string>
    - </resources>
    -diff --git a/packages/SettingsLib/res/values-ne-rNP/strings.xml b/packages/SettingsLib/res/values-ne-rNP/strings.xml
    -index 15cc8ea..01b39a0 100644
    ---- a/packages/SettingsLib/res/values-ne-rNP/strings.xml
    -+++ b/packages/SettingsLib/res/values-ne-rNP/strings.xml
    -@@ -28,7 +28,8 @@
    -     <string name="wifi_disabled_wifi_failure" msgid="3081668066612876581">"वाईफाई जडान असफल"</string>
    -     <string name="wifi_disabled_password_failure" msgid="8659805351763133575">"प्रमाणीकरण समस्या"</string>
    -     <string name="wifi_not_in_range" msgid="1136191511238508967">"दायराभित्र छैन"</string>
    --    <string name="wifi_no_internet" msgid="9151470775868728896">"कुनै इन्टरनेट पहुँच पाईएन, स्वचालित रूपमा पुन: जडान छैन।"</string>
    -+    <string name="wifi_no_internet_no_reconnect" msgid="2211781637653149657">"इन्टरनेट माथिको पहुँच पत्ता लागेन, स्वतः पुनः जडान हुने छैन।"</string>
    -+    <string name="wifi_no_internet" msgid="5011955173375805204">"इन्टरनेट माथिको पहुँच छैन।"</string>
    -     <string name="saved_network" msgid="4352716707126620811">"<xliff:g id="NAME">%1$s</xliff:g> द्वारा सुरक्षित गरियो"</string>
    -     <string name="connected_via_wfa" msgid="3805736726317410714">"Wi-Fi सहायक द्वारा जोडिएको"</string>
    -     <string name="connected_via_passpoint" msgid="2826205693803088747">"%1$s मार्फत जडित"</string>
    -@@ -233,8 +234,6 @@
    -     <string name="debug_layout_summary" msgid="2001775315258637682">"क्लिप सीमा, मार्जिन, इत्यादि देखाउनुहोस्।"</string>
    -     <string name="force_rtl_layout_all_locales" msgid="2259906643093138978">"RTL लेआउट दिशामा जबर्जस्ती गर्नुहोस्"</string>
    -     <string name="force_rtl_layout_all_locales_summary" msgid="9192797796616132534">"सबै लोकेलहरूको लागि RTLमा स्क्रिन लेआउट दिशामा जबर्जस्ती गर्नुहोस्"</string>
    --    <string name="show_cpu_usage" msgid="2389212910758076024">"CPU उपयोग देखाउनुहोस्"</string>
    --    <string name="show_cpu_usage_summary" msgid="2113341923988958266">"स्क्रिन ओभरले वर्तमान CPU प्रयोग देखाउँदै"</string>
    -     <string name="force_hw_ui" msgid="6426383462520888732">"GPU रेन्डर गर्न जोड गर्नुहोस्"</string>
    -     <string name="force_hw_ui_summary" msgid="5535991166074861515">"2d चित्र कोर्नका लागि GPU को प्रयोगलाई जोड दिनुहोस्"</string>
    -     <string name="force_msaa" msgid="7920323238677284387">"4x MSAA जोड गर्नुहोस्"</string>
    -@@ -341,4 +340,5 @@
    -     <string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"सबैभन्दा ठूलो"</string>
    -     <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"अनुकूलन (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
    -     <string name="help_feedback_label" msgid="6815040660801785649">"मद्दत र प्रतिक्रिया"</string>
    -+    <string name="content_description_menu_button" msgid="8182594799812351266">"मेनु"</string>
    - </resources>
    -diff --git a/packages/SettingsLib/res/values-nl/strings.xml b/packages/SettingsLib/res/values-nl/strings.xml
    -index 12bdb4f..feb78df 100644
    ---- a/packages/SettingsLib/res/values-nl/strings.xml
    -+++ b/packages/SettingsLib/res/values-nl/strings.xml
    -@@ -28,7 +28,8 @@
    -     <string name="wifi_disabled_wifi_failure" msgid="3081668066612876581">"Wifi-verbinding mislukt"</string>
    -     <string name="wifi_disabled_password_failure" msgid="8659805351763133575">"Authenticatieprobleem"</string>
    -     <string name="wifi_not_in_range" msgid="1136191511238508967">"Niet binnen bereik"</string>
    --    <string name="wifi_no_internet" msgid="9151470775868728896">"Geen internettoegang gevonden. Er wordt niet automatisch opnieuw verbinding gemaakt."</string>
    -+    <string name="wifi_no_internet_no_reconnect" msgid="2211781637653149657">"Geen internettoegang gevonden. Er wordt niet automatisch opnieuw verbinding gemaakt."</string>
    -+    <string name="wifi_no_internet" msgid="5011955173375805204">"Geen internettoegang."</string>
    -     <string name="saved_network" msgid="4352716707126620811">"Opgeslagen door <xliff:g id="NAME">%1$s</xliff:g>"</string>
    -     <string name="connected_via_wfa" msgid="3805736726317410714">"Verbonden via wifi-assistent"</string>
    -     <string name="connected_via_passpoint" msgid="2826205693803088747">"Verbonden via %1$s"</string>
    -@@ -233,8 +234,6 @@
    -     <string name="debug_layout_summary" msgid="2001775315258637682">"Clipgrenzen, marges en meer weergeven"</string>
    -     <string name="force_rtl_layout_all_locales" msgid="2259906643093138978">"V.r.n.l.-indelingsrichting afdwingen"</string>
    -     <string name="force_rtl_layout_all_locales_summary" msgid="9192797796616132534">"Schermindelingsrichting geforceerd instellen op v.r.n.l. voor alle talen"</string>
    --    <string name="show_cpu_usage" msgid="2389212910758076024">"CPU-gebruik weergeven"</string>
    --    <string name="show_cpu_usage_summary" msgid="2113341923988958266">"Schermoverlay met huidig CPU-gebruik"</string>
    -     <string name="force_hw_ui" msgid="6426383462520888732">"GPU-rendering afdwingen"</string>
    -     <string name="force_hw_ui_summary" msgid="5535991166074861515">"Gebruik van GPU voor 2D-tekening forceren"</string>
    -     <string name="force_msaa" msgid="7920323238677284387">"4x MSAA forceren"</string>
    -@@ -341,4 +340,5 @@
    -     <string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"Grootst"</string>
    -     <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Aangepast (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
    -     <string name="help_feedback_label" msgid="6815040660801785649">"Help en feedback"</string>
    -+    <string name="content_description_menu_button" msgid="8182594799812351266">"Menu"</string>
    - </resources>
    -diff --git a/packages/SettingsLib/res/values-pa-rIN/strings.xml b/packages/SettingsLib/res/values-pa-rIN/strings.xml
    -index 21d11b0..f21ee6d 100644
    ---- a/packages/SettingsLib/res/values-pa-rIN/strings.xml
    -+++ b/packages/SettingsLib/res/values-pa-rIN/strings.xml
    -@@ -28,7 +28,8 @@
    -     <string name="wifi_disabled_wifi_failure" msgid="3081668066612876581">"WiFi ਕਨੈਕਸ਼ਨ ਅਸਫਲਤਾ"</string>
    -     <string name="wifi_disabled_password_failure" msgid="8659805351763133575">"ਪ੍ਰਮਾਣੀਕਰਨ ਸਮੱਸਿਆ"</string>
    -     <string name="wifi_not_in_range" msgid="1136191511238508967">"ਰੇਂਜ ਵਿੱਚ ਨਹੀਂ ਹੈ"</string>
    --    <string name="wifi_no_internet" msgid="9151470775868728896">"ਕੋਈ ਇੰਟਰਨੈਟ ਪਹੁੰਚ ਨਹੀਂ ਮਿਲੀ, ਆਟੋਮੈਟਿਕਲੀ ਰੀਕਨੈਕਟ ਨਹੀਂ ਕੀਤਾ ਜਾਏਗਾ।"</string>
    -+    <string name="wifi_no_internet_no_reconnect" msgid="2211781637653149657">"ਕੋਈ ਇੰਟਰਨੈੱਟ ਪਹੁੰਚ ਨਹੀਂ ਮਿਲੀ, ਸਵੈਚਲਿਤ ਤੌਰ \'ਤੇ ਮੁੜ-ਕਨੈਕਟ ਨਹੀਂ ਕੀਤਾ ਜਾਵੇਗਾ।"</string>
    -+    <string name="wifi_no_internet" msgid="5011955173375805204">"ਕੋਈ ਇੰਟਰਨੈੱਟ ਪਹੁੰਚ ਨਹੀਂ।"</string>
    -     <string name="saved_network" msgid="4352716707126620811">"<xliff:g id="NAME">%1$s</xliff:g> ਵੱਲੋਂ ਸੁਰੱਖਿਅਤ ਕੀਤਾ"</string>
    -     <string name="connected_via_wfa" msgid="3805736726317410714">"Wi‑Fi ਸਹਾਇਕ ਰਾਹੀਂ ਕਨੈਕਟ ਕੀਤਾ"</string>
    -     <string name="connected_via_passpoint" msgid="2826205693803088747">"%1$s ਰਾਹੀਂ ਕਨੈਕਟ ਕੀਤਾ"</string>
    -@@ -233,8 +234,6 @@
    -     <string name="debug_layout_summary" msgid="2001775315258637682">"ਕਲਿਪ ਬਾਊਂਡਸ, ਮਾਰਜਿਨ ਆਦਿ ਦਿਖਾਓ"</string>
    -     <string name="force_rtl_layout_all_locales" msgid="2259906643093138978">"RTL ਲੇਆਉਟ ਦਿਸ਼ਾ ਤੇ ਜ਼ੋਰ ਪਾਓ"</string>
    -     <string name="force_rtl_layout_all_locales_summary" msgid="9192797796616132534">"ਸਾਰੇ ਸਥਾਨਾਂ ਲਈ RTL ਵੱਲ ਸਕ੍ਰੀਨ ਲੇਆਉਟ ਦਿਸ਼ਾ ਤੇ ਜ਼ੋਰ ਪਾਓ"</string>
    --    <string name="show_cpu_usage" msgid="2389212910758076024">"CPU ਵਰਤੋਂ ਦਿਖਾਓ"</string>
    --    <string name="show_cpu_usage_summary" msgid="2113341923988958266">"ਸਕ੍ਰੀਨ ਓਵਰਲੇ ਵਰਤਮਾਨ CPU ਵਰਤੋਂ ਦਿਖਾ ਰਿਹਾ ਹੈ"</string>
    -     <string name="force_hw_ui" msgid="6426383462520888732">"GPU ਪ੍ਰਗਟਾਅ ਤੇ ਜ਼ੋਰ ਪਾਓ"</string>
    -     <string name="force_hw_ui_summary" msgid="5535991166074861515">"2d ਡ੍ਰਾਇੰਗ ਲਈ GPU ਦੀ ਵਰਤੋਂ ਤੇ ਜ਼ੋਰ ਪਾਓ"</string>
    -     <string name="force_msaa" msgid="7920323238677284387">"4x MSAA ਤੇ ਜ਼ੋਰ ਪਾਓ"</string>
    -@@ -341,4 +340,5 @@
    -     <string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"ਸਭ ਤੋਂ ਵੱਡਾ"</string>
    -     <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"ਵਿਸ਼ੇਸ਼-ਵਿਉਂਤਬੱਧ (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
    -     <string name="help_feedback_label" msgid="6815040660801785649">"ਮਦਦ ਅਤੇ ਪ੍ਰਤੀਕਰਮ"</string>
    -+    <string name="content_description_menu_button" msgid="8182594799812351266">"ਮੀਨੂ"</string>
    - </resources>
    -diff --git a/packages/SettingsLib/res/values-pl/strings.xml b/packages/SettingsLib/res/values-pl/strings.xml
    -index d5116a2..bcdf812 100644
    ---- a/packages/SettingsLib/res/values-pl/strings.xml
    -+++ b/packages/SettingsLib/res/values-pl/strings.xml
    -@@ -28,7 +28,8 @@
    -     <string name="wifi_disabled_wifi_failure" msgid="3081668066612876581">"Błąd połączenia Wi-Fi"</string>
    -     <string name="wifi_disabled_password_failure" msgid="8659805351763133575">"Problem z uwierzytelnianiem"</string>
    -     <string name="wifi_not_in_range" msgid="1136191511238508967">"Poza zasięgiem"</string>
    --    <string name="wifi_no_internet" msgid="9151470775868728896">"Nie wykryto dostępu do internetu. Nie można automatycznie przywrócić połączenia."</string>
    -+    <string name="wifi_no_internet_no_reconnect" msgid="2211781637653149657">"Nie wykryto dostępu do internetu. Nie można automatycznie przywrócić połączenia."</string>
    -+    <string name="wifi_no_internet" msgid="5011955173375805204">"Brak dostępu do internetu."</string>
    -     <string name="saved_network" msgid="4352716707126620811">"Zapisane przez: <xliff:g id="NAME">%1$s</xliff:g>"</string>
    -     <string name="connected_via_wfa" msgid="3805736726317410714">"Połączono przez Asystenta Wi‑Fi"</string>
    -     <string name="connected_via_passpoint" msgid="2826205693803088747">"Połączono przez %1$s"</string>
    -@@ -233,8 +234,6 @@
    -     <string name="debug_layout_summary" msgid="2001775315258637682">"Pokaż granice przycięcia, marginesy itd."</string>
    -     <string name="force_rtl_layout_all_locales" msgid="2259906643093138978">"Układ od prawej do lewej"</string>
    -     <string name="force_rtl_layout_all_locales_summary" msgid="9192797796616132534">"Wymuś wszędzie układ ekranu od prawej do lewej"</string>
    --    <string name="show_cpu_usage" msgid="2389212910758076024">"Pokaż użycie procesora"</string>
    --    <string name="show_cpu_usage_summary" msgid="2113341923988958266">"Nakładka na ekranie pokazująca użycie procesora"</string>
    -     <string name="force_hw_ui" msgid="6426383462520888732">"Renderowanie na GPU"</string>
    -     <string name="force_hw_ui_summary" msgid="5535991166074861515">"Wymuszaj użycie GPU do rysowania 2D"</string>
    -     <string name="force_msaa" msgid="7920323238677284387">"Wymuś 4x MSAA"</string>
    -@@ -341,4 +340,5 @@
    -     <string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"Największy"</string>
    -     <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Niestandardowe (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
    -     <string name="help_feedback_label" msgid="6815040660801785649">"Pomoc i opinie"</string>
    -+    <string name="content_description_menu_button" msgid="8182594799812351266">"Menu"</string>
    - </resources>
    -diff --git a/packages/SettingsLib/res/values-pt-rBR/strings.xml b/packages/SettingsLib/res/values-pt-rBR/strings.xml
    -index f0cfa23..ef4ec77 100644
    ---- a/packages/SettingsLib/res/values-pt-rBR/strings.xml
    -+++ b/packages/SettingsLib/res/values-pt-rBR/strings.xml
    -@@ -28,7 +28,8 @@
    -     <string name="wifi_disabled_wifi_failure" msgid="3081668066612876581">"Falha de conexão Wi-Fi"</string>
    -     <string name="wifi_disabled_password_failure" msgid="8659805351763133575">"Problema de autenticação"</string>
    -     <string name="wifi_not_in_range" msgid="1136191511238508967">"Fora do alcance"</string>
    --    <string name="wifi_no_internet" msgid="9151470775868728896">"Nenhum acesso à Internet detectado. O dispositivo não conectará automaticamente."</string>
    -+    <string name="wifi_no_internet_no_reconnect" msgid="2211781637653149657">"Nenhum acesso à Internet foi detectado. O dispositivo não será reconectado automaticamente."</string>
    -+    <string name="wifi_no_internet" msgid="5011955173375805204">"Sem acesso à Internet."</string>
    -     <string name="saved_network" msgid="4352716707126620811">"Salvas por <xliff:g id="NAME">%1$s</xliff:g>"</string>
    -     <string name="connected_via_wfa" msgid="3805736726317410714">"Conectado via assistente de Wi‑Fi"</string>
    -     <string name="connected_via_passpoint" msgid="2826205693803088747">"Conectado via %1$s"</string>
    -@@ -233,8 +234,6 @@
    -     <string name="debug_layout_summary" msgid="2001775315258637682">"Mostrar limites de corte, margens, etc."</string>
    -     <string name="force_rtl_layout_all_locales" msgid="2259906643093138978">"Forçar dir. layout (RTL)"</string>
    -     <string name="force_rtl_layout_all_locales_summary" msgid="9192797796616132534">"Forçar direção do layout (RTL) p/ todas as local."</string>
    --    <string name="show_cpu_usage" msgid="2389212910758076024">"Mostrar o uso da CPU"</string>
    --    <string name="show_cpu_usage_summary" msgid="2113341923988958266">"Sobreposição de tela que mostra o uso da CPU atual"</string>
    -     <string name="force_hw_ui" msgid="6426383462520888732">"Forçar renderização GPU"</string>
    -     <string name="force_hw_ui_summary" msgid="5535991166074861515">"Forçar uso da GPU para desenho em 2D"</string>
    -     <string name="force_msaa" msgid="7920323238677284387">"Forçar 4x MSAA"</string>
    -@@ -341,4 +340,5 @@
    -     <string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"Maior"</string>
    -     <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Personalizada (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
    -     <string name="help_feedback_label" msgid="6815040660801785649">"Ajuda e feedback"</string>
    -+    <string name="content_description_menu_button" msgid="8182594799812351266">"Menu"</string>
    - </resources>
    -diff --git a/packages/SettingsLib/res/values-pt-rPT/strings.xml b/packages/SettingsLib/res/values-pt-rPT/strings.xml
    -index 40dfc74..b6e9b4f 100644
    ---- a/packages/SettingsLib/res/values-pt-rPT/strings.xml
    -+++ b/packages/SettingsLib/res/values-pt-rPT/strings.xml
    -@@ -28,7 +28,8 @@
    -     <string name="wifi_disabled_wifi_failure" msgid="3081668066612876581">"Falha de ligação Wi-Fi"</string>
    -     <string name="wifi_disabled_password_failure" msgid="8659805351763133575">"Problema de autenticação"</string>
    -     <string name="wifi_not_in_range" msgid="1136191511238508967">"Fora do alcance"</string>
    --    <string name="wifi_no_internet" msgid="9151470775868728896">"Nenhum acesso à Internet detetado; não será efetuada uma nova ligação automaticamente."</string>
    -+    <string name="wifi_no_internet_no_reconnect" msgid="2211781637653149657">"Nenhum acesso à Internet detetado. Não será efetuada uma nova ligação automaticamente."</string>
    -+    <string name="wifi_no_internet" msgid="5011955173375805204">"Sem acesso à Internet."</string>
    -     <string name="saved_network" msgid="4352716707126620811">"Guardada por <xliff:g id="NAME">%1$s</xliff:g>"</string>
    -     <string name="connected_via_wfa" msgid="3805736726317410714">"Ligado através do Assistente de Wi‑Fi"</string>
    -     <string name="connected_via_passpoint" msgid="2826205693803088747">"Ligado através de %1$s"</string>
    -@@ -233,8 +234,6 @@
    -     <string name="debug_layout_summary" msgid="2001775315258637682">"Apresentar limites de clipes, margens, etc."</string>
    -     <string name="force_rtl_layout_all_locales" msgid="2259906643093138978">"Forçar dir. do esq. RTL"</string>
    -     <string name="force_rtl_layout_all_locales_summary" msgid="9192797796616132534">"Forçar dir. do esq. do ecrã p. RTL tds os locais"</string>
    --    <string name="show_cpu_usage" msgid="2389212910758076024">"Mostrar utilização da CPU"</string>
    --    <string name="show_cpu_usage_summary" msgid="2113341923988958266">"Sobrep. de ecrã que mostra a utiliz. atual da CPU"</string>
    -     <string name="force_hw_ui" msgid="6426383462520888732">"Forçar composição GPU"</string>
    -     <string name="force_hw_ui_summary" msgid="5535991166074861515">"Forçar a utilização de GPU para desenho 2D"</string>
    -     <string name="force_msaa" msgid="7920323238677284387">"Forçar 4x MSAA"</string>
    -@@ -341,4 +340,5 @@
    -     <string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"O maior"</string>
    -     <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Personalizado (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
    -     <string name="help_feedback_label" msgid="6815040660801785649">"Ajuda e comentários"</string>
    -+    <string name="content_description_menu_button" msgid="8182594799812351266">"Menu"</string>
    - </resources>
    -diff --git a/packages/SettingsLib/res/values-pt/strings.xml b/packages/SettingsLib/res/values-pt/strings.xml
    -index f0cfa23..ef4ec77 100644
    ---- a/packages/SettingsLib/res/values-pt/strings.xml
    -+++ b/packages/SettingsLib/res/values-pt/strings.xml
    -@@ -28,7 +28,8 @@
    -     <string name="wifi_disabled_wifi_failure" msgid="3081668066612876581">"Falha de conexão Wi-Fi"</string>
    -     <string name="wifi_disabled_password_failure" msgid="8659805351763133575">"Problema de autenticação"</string>
    -     <string name="wifi_not_in_range" msgid="1136191511238508967">"Fora do alcance"</string>
    --    <string name="wifi_no_internet" msgid="9151470775868728896">"Nenhum acesso à Internet detectado. O dispositivo não conectará automaticamente."</string>
    -+    <string name="wifi_no_internet_no_reconnect" msgid="2211781637653149657">"Nenhum acesso à Internet foi detectado. O dispositivo não será reconectado automaticamente."</string>
    -+    <string name="wifi_no_internet" msgid="5011955173375805204">"Sem acesso à Internet."</string>
    -     <string name="saved_network" msgid="4352716707126620811">"Salvas por <xliff:g id="NAME">%1$s</xliff:g>"</string>
    -     <string name="connected_via_wfa" msgid="3805736726317410714">"Conectado via assistente de Wi‑Fi"</string>
    -     <string name="connected_via_passpoint" msgid="2826205693803088747">"Conectado via %1$s"</string>
    -@@ -233,8 +234,6 @@
    -     <string name="debug_layout_summary" msgid="2001775315258637682">"Mostrar limites de corte, margens, etc."</string>
    -     <string name="force_rtl_layout_all_locales" msgid="2259906643093138978">"Forçar dir. layout (RTL)"</string>
    -     <string name="force_rtl_layout_all_locales_summary" msgid="9192797796616132534">"Forçar direção do layout (RTL) p/ todas as local."</string>
    --    <string name="show_cpu_usage" msgid="2389212910758076024">"Mostrar o uso da CPU"</string>
    --    <string name="show_cpu_usage_summary" msgid="2113341923988958266">"Sobreposição de tela que mostra o uso da CPU atual"</string>
    -     <string name="force_hw_ui" msgid="6426383462520888732">"Forçar renderização GPU"</string>
    -     <string name="force_hw_ui_summary" msgid="5535991166074861515">"Forçar uso da GPU para desenho em 2D"</string>
    -     <string name="force_msaa" msgid="7920323238677284387">"Forçar 4x MSAA"</string>
    -@@ -341,4 +340,5 @@
    -     <string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"Maior"</string>
    -     <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Personalizada (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
    -     <string name="help_feedback_label" msgid="6815040660801785649">"Ajuda e feedback"</string>
    -+    <string name="content_description_menu_button" msgid="8182594799812351266">"Menu"</string>
    - </resources>
    -diff --git a/packages/SettingsLib/res/values-ro/strings.xml b/packages/SettingsLib/res/values-ro/strings.xml
    -index 6cc0f87..a5ee78a 100644
    ---- a/packages/SettingsLib/res/values-ro/strings.xml
    -+++ b/packages/SettingsLib/res/values-ro/strings.xml
    -@@ -28,7 +28,8 @@
    -     <string name="wifi_disabled_wifi_failure" msgid="3081668066612876581">"Eroare de conexiune Wi-Fi"</string>
    -     <string name="wifi_disabled_password_failure" msgid="8659805351763133575">"Problemă la autentificare"</string>
    -     <string name="wifi_not_in_range" msgid="1136191511238508967">"În afara ariei de acoperire"</string>
    --    <string name="wifi_no_internet" msgid="9151470775868728896">"Nu s-a detectat acces la internet, nu se va efectua reconectarea automată."</string>
    -+    <string name="wifi_no_internet_no_reconnect" msgid="2211781637653149657">"Nu s-a detectat acces la internet, nu se va reconecta automat."</string>
    -+    <string name="wifi_no_internet" msgid="5011955173375805204">"Nu există acces la internet."</string>
    -     <string name="saved_network" msgid="4352716707126620811">"Salvată de <xliff:g id="NAME">%1$s</xliff:g>"</string>
    -     <string name="connected_via_wfa" msgid="3805736726317410714">"Conexiune realizată printr-un asistent Wi-Fi"</string>
    -     <string name="connected_via_passpoint" msgid="2826205693803088747">"Conectată prin %1$s"</string>
    -@@ -233,8 +234,6 @@
    -     <string name="debug_layout_summary" msgid="2001775315258637682">"Afișați limitele clipului, marginile etc."</string>
    -     <string name="force_rtl_layout_all_locales" msgid="2259906643093138978">"Direcție aspect dreapta - stânga"</string>
    -     <string name="force_rtl_layout_all_locales_summary" msgid="9192797796616132534">"Direcție obligatorie aspect ecran dreapta - stânga"</string>
    --    <string name="show_cpu_usage" msgid="2389212910758076024">"Afișați utiliz. procesor"</string>
    --    <string name="show_cpu_usage_summary" msgid="2113341923988958266">"Suprapunere care indică utilizare curentă procesor"</string>
    -     <string name="force_hw_ui" msgid="6426383462520888732">"Forțați redarea cu GPU"</string>
    -     <string name="force_hw_ui_summary" msgid="5535991166074861515">"Forțați utilizarea GPU pentru desen în 2D"</string>
    -     <string name="force_msaa" msgid="7920323238677284387">"Forțați MSAA 4x"</string>
    -@@ -341,4 +340,5 @@
    -     <string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"Cel mai mare"</string>
    -     <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Personalizat (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
    -     <string name="help_feedback_label" msgid="6815040660801785649">"Ajutor și feedback"</string>
    -+    <string name="content_description_menu_button" msgid="8182594799812351266">"Meniu"</string>
    - </resources>
    -diff --git a/packages/SettingsLib/res/values-ru/strings.xml b/packages/SettingsLib/res/values-ru/strings.xml
    -index ad4db89..b24a705 100644
    ---- a/packages/SettingsLib/res/values-ru/strings.xml
    -+++ b/packages/SettingsLib/res/values-ru/strings.xml
    -@@ -28,13 +28,14 @@
    -     <string name="wifi_disabled_wifi_failure" msgid="3081668066612876581">"Ошибка подключения Wi-Fi"</string>
    -     <string name="wifi_disabled_password_failure" msgid="8659805351763133575">"Ошибка аутентификации"</string>
    -     <string name="wifi_not_in_range" msgid="1136191511238508967">"Недоступна"</string>
    --    <string name="wifi_no_internet" msgid="9151470775868728896">"Подключение к Интернету отсутствует и не будет восстановлено автоматически."</string>
    -+    <string name="wifi_no_internet_no_reconnect" msgid="2211781637653149657">"Отсутствует интернет-соединение. Повторное подключение к сети не будет выполняться автоматически."</string>
    -+    <string name="wifi_no_internet" msgid="5011955173375805204">"Отсутствует подключение к Интернету"</string>
    -     <string name="saved_network" msgid="4352716707126620811">"Кто сохранил: <xliff:g id="NAME">%1$s</xliff:g>"</string>
    -     <string name="connected_via_wfa" msgid="3805736726317410714">"Установлено подключение через Ассистента Wi-Fi"</string>
    -     <string name="connected_via_passpoint" msgid="2826205693803088747">"Подключено к %1$s"</string>
    -     <string name="available_via_passpoint" msgid="1617440946846329613">"Доступно через %1$s"</string>
    -     <string name="wifi_connected_no_internet" msgid="3149853966840874992">"Подключено, без Интернета"</string>
    --    <string name="bluetooth_disconnected" msgid="6557104142667339895">"Отключено"</string>
    -+    <string name="bluetooth_disconnected" msgid="6557104142667339895">"Нет подключения"</string>
    -     <string name="bluetooth_disconnecting" msgid="8913264760027764974">"Отключение..."</string>
    -     <string name="bluetooth_connecting" msgid="8555009514614320497">"Подключение..."</string>
    -     <string name="bluetooth_connected" msgid="6038755206916626419">"Подключено"</string>
    -@@ -233,8 +234,6 @@
    -     <string name="debug_layout_summary" msgid="2001775315258637682">"Показывать границы клипа, поля и т. д."</string>
    -     <string name="force_rtl_layout_all_locales" msgid="2259906643093138978">"Написание справа налево"</string>
    -     <string name="force_rtl_layout_all_locales_summary" msgid="9192797796616132534">"Включить написание справа налево для всех языков"</string>
    --    <string name="show_cpu_usage" msgid="2389212910758076024">"Показывать загрузку ЦП"</string>
    --    <string name="show_cpu_usage_summary" msgid="2113341923988958266">"Экран, показывающий текущую загрузку ЦП"</string>
    -     <string name="force_hw_ui" msgid="6426383462520888732">"GPU-ускорение"</string>
    -     <string name="force_hw_ui_summary" msgid="5535991166074861515">"Всегда использовать GPU для двухмерного рисования"</string>
    -     <string name="force_msaa" msgid="7920323238677284387">"Включить 4x MSAA"</string>
    -@@ -246,7 +245,7 @@
    -     <string name="animator_duration_scale_title" msgid="3406722410819934083">"Длительность анимации"</string>
    -     <string name="overlay_display_devices_title" msgid="5364176287998398539">"Эмуляция доп. экранов"</string>
    -     <string name="debug_applications_category" msgid="4206913653849771549">"Приложения"</string>
    --    <string name="immediately_destroy_activities" msgid="1579659389568133959">"Не сохранять действия"</string>
    -+    <string name="immediately_destroy_activities" msgid="1579659389568133959">"Не сохранять активности"</string>
    -     <string name="immediately_destroy_activities_summary" msgid="3592221124808773368">"Удалять сводку действий после их завершения"</string>
    -     <string name="app_process_limit_title" msgid="4280600650253107163">"Лимит фоновых процессов"</string>
    -     <string name="show_all_anrs" msgid="28462979638729082">"Все ANR"</string>
    -@@ -341,4 +340,5 @@
    -     <string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"Максимальный"</string>
    -     <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Другой (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
    -     <string name="help_feedback_label" msgid="6815040660801785649">"Справка/отзыв"</string>
    -+    <string name="content_description_menu_button" msgid="8182594799812351266">"Меню"</string>
    - </resources>
    -diff --git a/packages/SettingsLib/res/values-si-rLK/strings.xml b/packages/SettingsLib/res/values-si-rLK/strings.xml
    -index 5efb400..e3acfae 100644
    ---- a/packages/SettingsLib/res/values-si-rLK/strings.xml
    -+++ b/packages/SettingsLib/res/values-si-rLK/strings.xml
    -@@ -28,7 +28,8 @@
    -     <string name="wifi_disabled_wifi_failure" msgid="3081668066612876581">"WiFi සම්බන්ධතාව අසාර්ථකයි"</string>
    -     <string name="wifi_disabled_password_failure" msgid="8659805351763133575">"සත්‍යාපනයේ ගැටලුවකි"</string>
    -     <string name="wifi_not_in_range" msgid="1136191511238508967">"පරාසයේ නැත"</string>
    --    <string name="wifi_no_internet" msgid="9151470775868728896">"අන්තර්ජාල ප්‍රවේශය අනාවරණය වුයේ නැත, ස්වයංක්‍රිය නැවත සම්බන්ධ වීම වූ නැත"</string>
    -+    <string name="wifi_no_internet_no_reconnect" msgid="2211781637653149657">"අන්තර්ජාල ප්‍රවේශය නැත, ස්වයංක්‍රිය නැවත සම්බන්ධ නොවනු ඇත."</string>
    -+    <string name="wifi_no_internet" msgid="5011955173375805204">"අන්තර්ජාල ප්‍රවේශය නැත."</string>
    -     <string name="saved_network" msgid="4352716707126620811">"<xliff:g id="NAME">%1$s</xliff:g> විසින් සුරකින ලදී"</string>
    -     <string name="connected_via_wfa" msgid="3805736726317410714">"Wi‑Fi සහායක හරහා සම්බන්ධ කරන ලදි"</string>
    -     <string name="connected_via_passpoint" msgid="2826205693803088747">"%1$s හරහා සම්බන්ධ විය"</string>
    -@@ -233,8 +234,6 @@
    -     <string name="debug_layout_summary" msgid="2001775315258637682">"ක්ලිප් සීමා, මායිම්, ආදිය පෙන්වන්න."</string>
    -     <string name="force_rtl_layout_all_locales" msgid="2259906643093138978">"බල RTL පිරිසැලසුම් දිශාව"</string>
    -     <string name="force_rtl_layout_all_locales_summary" msgid="9192797796616132534">"සියලු පෙදෙසි සඳහා RTL වෙත බල තිර පිරිසැලසුම"</string>
    --    <string name="show_cpu_usage" msgid="2389212910758076024">"CPU භාවිතය පෙන්වන්න"</string>
    --    <string name="show_cpu_usage_summary" msgid="2113341923988958266">"තීර උඩැතිරිය වත්මන් CPU භාවිතය පෙන්නුම් කරයි"</string>
    -     <string name="force_hw_ui" msgid="6426383462520888732">"GPU විදහාපෑම බලකරන්න"</string>
    -     <string name="force_hw_ui_summary" msgid="5535991166074861515">"2d ඇඳීම් සඳහා GPU බලයෙන් භාවිතා කරන්න"</string>
    -     <string name="force_msaa" msgid="7920323238677284387">"4x MSAA බල කරන්න"</string>
    -@@ -341,4 +340,5 @@
    -     <string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"විශාලතම"</string>
    -     <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"අභිරුචි (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
    -     <string name="help_feedback_label" msgid="6815040660801785649">"උදව් සහ ප්‍රතිපෝෂණ"</string>
    -+    <string name="content_description_menu_button" msgid="8182594799812351266">"මෙනුව"</string>
    - </resources>
    -diff --git a/packages/SettingsLib/res/values-sk/strings.xml b/packages/SettingsLib/res/values-sk/strings.xml
    -index 7a7e3d4..74a2b46 100644
    ---- a/packages/SettingsLib/res/values-sk/strings.xml
    -+++ b/packages/SettingsLib/res/values-sk/strings.xml
    -@@ -28,7 +28,8 @@
    -     <string name="wifi_disabled_wifi_failure" msgid="3081668066612876581">"Zlyhanie pripojenia Wi-Fi"</string>
    -     <string name="wifi_disabled_password_failure" msgid="8659805351763133575">"Problém s overením totožnosti"</string>
    -     <string name="wifi_not_in_range" msgid="1136191511238508967">"Mimo dosah"</string>
    --    <string name="wifi_no_internet" msgid="9151470775868728896">"Nenašiel sa žiadny prístup k internetu, preto nedôjde k automatickému opätovnému pripojeniu"</string>
    -+    <string name="wifi_no_internet_no_reconnect" msgid="2211781637653149657">"Nenašiel sa žiadny prístup k internetu, preto nedôjde k automatickému opätovnému pripojeniu."</string>
    -+    <string name="wifi_no_internet" msgid="5011955173375805204">"Žiadny prístup k internetu."</string>
    -     <string name="saved_network" msgid="4352716707126620811">"Uložil(a) <xliff:g id="NAME">%1$s</xliff:g>"</string>
    -     <string name="connected_via_wfa" msgid="3805736726317410714">"Pripojené pomocou Asistenta Wi-Fi"</string>
    -     <string name="connected_via_passpoint" msgid="2826205693803088747">"Pripojené prostredníctvom %1$s"</string>
    -@@ -173,8 +174,8 @@
    -     <string name="wifi_verbose_logging_summary" msgid="6615071616111731958">"Zvýšiť úroveň denníkov Wi-Fi, zobrazovať podľa SSID RSSI pri výbere siete Wi-Fi"</string>
    -     <string name="wifi_aggressive_handover_summary" msgid="6328455667642570371">"Keď túto možnosť zapnete, Wi-Fi bude agresívnejšie odovzdávať dát. pripoj. na mob. sieť vtedy, keď bude slabý signál Wi-Fi"</string>
    -     <string name="wifi_allow_scan_with_traffic_summary" msgid="2575101424972686310">"Povoliť alebo zakázať funkciu Wifi Roam Scans na základe objemu prenosu údajov v rozhraní"</string>
    --    <string name="select_logd_size_title" msgid="7433137108348553508">"Veľkosti vyrovnávacej pamäte denníka"</string>
    --    <string name="select_logd_size_dialog_title" msgid="1206769310236476760">"Veľkosť na vyrovnávaciu pamäť nástroja denníkov"</string>
    -+    <string name="select_logd_size_title" msgid="7433137108348553508">"Vyrovnávacia pamäť nástroja denníkov"</string>
    -+    <string name="select_logd_size_dialog_title" msgid="1206769310236476760">"Veľkosť vyrovnávacej pamäte nástroja denníkov"</string>
    -     <string name="dev_logpersist_clear_warning_title" msgid="684806692440237967">"Vymazať trvalé úložisko zapisovača do denníka?"</string>
    -     <string name="dev_logpersist_clear_warning_message" msgid="2256582531342994562">"Keď prestaneme monitorovať pomocou trvalého zapisovača do denníka, musíme vymazať jeho dáta, ktoré sa nachádzajú vo vašom zariadení."</string>
    -     <string name="select_logpersist_title" msgid="7530031344550073166">"Natrvalo ukladať dáta zapisovača do denníka na zariadení"</string>
    -@@ -186,8 +187,8 @@
    -     <string name="debug_view_attributes" msgid="6485448367803310384">"Kontrola atribútov zobrazenia"</string>
    -     <string name="mobile_data_always_on_summary" msgid="8149773901431697910">"Vždy ponechávať mobilné dáta aktívne, dokonca aj pri aktívnej sieti Wi‑Fi (na rýchle prepínanie sietí)"</string>
    -     <string name="adb_warning_title" msgid="6234463310896563253">"Povoliť ladenie cez USB?"</string>
    --    <string name="adb_warning_message" msgid="7316799925425402244">"Ladenie prostredníctvom USB je určené iba na účely vývoja. Použite ho na kopírovanie dát medzi počítačom a zariadením, inštaláciu aplikácií do zariadenia bez upozornenia a čítanie údajov denníka."</string>
    --    <string name="adb_keys_warning_message" msgid="5659849457135841625">"Chcete odvolať prístup k ladeniu cez USB zo všetkých počítačov, ktoré ste predtým autorizovali?"</string>
    -+    <string name="adb_warning_message" msgid="7316799925425402244">"Ladenie cez USB je určené iba na účely vývoja. Možno ho použiť na kopírovanie dát medzi počítačom a zariadením, inštaláciu aplikácií do zariadenia bez upozornenia a čítanie dát denníka."</string>
    -+    <string name="adb_keys_warning_message" msgid="5659849457135841625">"Chcete všetkým v minulosti autorizovaným počítačom odvolať prístup k ladeniu cez USB?"</string>
    -     <string name="dev_settings_warning_title" msgid="7244607768088540165">"Povoliť nastavenia pre vývojárov?"</string>
    -     <string name="dev_settings_warning_message" msgid="2298337781139097964">"Tieto nastavenia sú určené len pre vývojárov. Môžu spôsobiť poruchu alebo nesprávne fungovanie zariadenia a nainštalovaných aplikácií."</string>
    -     <string name="verify_apps_over_usb_title" msgid="4177086489869041953">"Overovať aplikácie z USB"</string>
    -@@ -233,8 +234,6 @@
    -     <string name="debug_layout_summary" msgid="2001775315258637682">"Zobraziť vo výstrižku ohraničenie, okraje a pod."</string>
    -     <string name="force_rtl_layout_all_locales" msgid="2259906643093138978">"Rozloženia sprava doľava"</string>
    -     <string name="force_rtl_layout_all_locales_summary" msgid="9192797796616132534">"Vynútiť pre všetky jazyky rozloženie obrazovky sprava doľava"</string>
    --    <string name="show_cpu_usage" msgid="2389212910758076024">"Zobraziť využitie CPU"</string>
    --    <string name="show_cpu_usage_summary" msgid="2113341923988958266">"Prekryvná vrstva s aktuálnym využitím procesora"</string>
    -     <string name="force_hw_ui" msgid="6426383462520888732">"Vykresľovat pomocou GPU"</string>
    -     <string name="force_hw_ui_summary" msgid="5535991166074861515">"Používať GPU na dvojrozmerné vykresľovanie"</string>
    -     <string name="force_msaa" msgid="7920323238677284387">"Vynútiť 4x MSAA"</string>
    -@@ -341,4 +340,5 @@
    -     <string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"Najväčšie"</string>
    -     <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Vlastné (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
    -     <string name="help_feedback_label" msgid="6815040660801785649">"Pomocník a spätná väzba"</string>
    -+    <string name="content_description_menu_button" msgid="8182594799812351266">"Ponuka"</string>
    - </resources>
    -diff --git a/packages/SettingsLib/res/values-sl/strings.xml b/packages/SettingsLib/res/values-sl/strings.xml
    -index 10bff6e..788b97c 100644
    ---- a/packages/SettingsLib/res/values-sl/strings.xml
    -+++ b/packages/SettingsLib/res/values-sl/strings.xml
    -@@ -28,7 +28,8 @@
    -     <string name="wifi_disabled_wifi_failure" msgid="3081668066612876581">"Povezava prek Wi-Fi-ja ni uspela"</string>
    -     <string name="wifi_disabled_password_failure" msgid="8659805351763133575">"Težava s preverjanjem pristnosti"</string>
    -     <string name="wifi_not_in_range" msgid="1136191511238508967">"Ni v obsegu"</string>
    --    <string name="wifi_no_internet" msgid="9151470775868728896">"Ni zaznanega dostopa do interneta; samodejna vnovična vzpostavitev povezave se ne bo izvedla."</string>
    -+    <string name="wifi_no_internet_no_reconnect" msgid="2211781637653149657">"Ni zaznanega dostopa do interneta; samodejna vnovična vzpostavitev povezave se ne bo izvedla."</string>
    -+    <string name="wifi_no_internet" msgid="5011955173375805204">"Ni dostopa do interneta."</string>
    -     <string name="saved_network" msgid="4352716707126620811">"Shranil(-a): <xliff:g id="NAME">%1$s</xliff:g>"</string>
    -     <string name="connected_via_wfa" msgid="3805736726317410714">"Povezava vzpostavljena prek pomočnika za Wi-Fi"</string>
    -     <string name="connected_via_passpoint" msgid="2826205693803088747">"Vzpostavljena povezava prek: %1$s"</string>
    -@@ -233,8 +234,6 @@
    -     <string name="debug_layout_summary" msgid="2001775315258637682">"Pokaži meje obrezovanja, obrobe ipd."</string>
    -     <string name="force_rtl_layout_all_locales" msgid="2259906643093138978">"Vsili od desne proti levi"</string>
    -     <string name="force_rtl_layout_all_locales_summary" msgid="9192797796616132534">"Vsili smer postavitve na zaslonu od desne proti levi za vse jezike"</string>
    --    <string name="show_cpu_usage" msgid="2389212910758076024">"Prikaži uporabo CPE-ja"</string>
    --    <string name="show_cpu_usage_summary" msgid="2113341923988958266">"Prekrivanje zaslona prikazuje tren. uporabo CPE-ja"</string>
    -     <string name="force_hw_ui" msgid="6426383462520888732">"Vsili upodabljanje z GPE-jem"</string>
    -     <string name="force_hw_ui_summary" msgid="5535991166074861515">"Za risanje 2D vsili uporabo grafičnega procesorja"</string>
    -     <string name="force_msaa" msgid="7920323238677284387">"Vsili 4x MSAA"</string>
    -@@ -341,4 +340,5 @@
    -     <string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"Največje"</string>
    -     <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Po meri (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
    -     <string name="help_feedback_label" msgid="6815040660801785649">"Pomoč in povratne informacije"</string>
    -+    <string name="content_description_menu_button" msgid="8182594799812351266">"Meni"</string>
    - </resources>
    -diff --git a/packages/SettingsLib/res/values-sq-rAL/strings.xml b/packages/SettingsLib/res/values-sq-rAL/strings.xml
    -index e4f0eaa..d6419dd 100644
    ---- a/packages/SettingsLib/res/values-sq-rAL/strings.xml
    -+++ b/packages/SettingsLib/res/values-sq-rAL/strings.xml
    -@@ -28,7 +28,8 @@
    -     <string name="wifi_disabled_wifi_failure" msgid="3081668066612876581">"Dështim i lidhjes WiFi"</string>
    -     <string name="wifi_disabled_password_failure" msgid="8659805351763133575">"Problem me vërtetimin"</string>
    -     <string name="wifi_not_in_range" msgid="1136191511238508967">"Nuk është brenda rrezes"</string>
    --    <string name="wifi_no_internet" msgid="9151470775868728896">"Nuk u diktua qasje në internet. Lidhja nuk do të realizohet automatikisht."</string>
    -+    <string name="wifi_no_internet_no_reconnect" msgid="2211781637653149657">"Nuk u zbulua qasje në internet. Nuk do të lidhet përsëri automatikisht."</string>
    -+    <string name="wifi_no_internet" msgid="5011955173375805204">"Nuk ka qasje në internet."</string>
    -     <string name="saved_network" msgid="4352716707126620811">"E ruajtur nga <xliff:g id="NAME">%1$s</xliff:g>"</string>
    -     <string name="connected_via_wfa" msgid="3805736726317410714">"I lidhur nëpërmjet ndihmësit të Wi‑Fi"</string>
    -     <string name="connected_via_passpoint" msgid="2826205693803088747">"E lidhur përmes %1$s"</string>
    -@@ -233,8 +234,6 @@
    -     <string name="debug_layout_summary" msgid="2001775315258637682">"Shfaq konturet e klipit, hapësirat etj."</string>
    -     <string name="force_rtl_layout_all_locales" msgid="2259906643093138978">"Detyro drejtimin e shkrimit nga e djathta në të majtë"</string>
    -     <string name="force_rtl_layout_all_locales_summary" msgid="9192797796616132534">"Ndrysho me detyrim drejtimin e planit të ekranit nga e djathta në të majtë për të gjitha vendet"</string>
    --    <string name="show_cpu_usage" msgid="2389212910758076024">"Shfaq përdorimin e CPU-së"</string>
    --    <string name="show_cpu_usage_summary" msgid="2113341923988958266">"Mbivendosja e ekranit tregon përdorimin e CPU-së"</string>
    -     <string name="force_hw_ui" msgid="6426383462520888732">"Detyro interpretimin e GPU-së"</string>
    -     <string name="force_hw_ui_summary" msgid="5535991166074861515">"Detyro përdorimin e GPU-së për vizatimin e dytë"</string>
    -     <string name="force_msaa" msgid="7920323238677284387">"Detyro 4x MSAA"</string>
    -@@ -341,4 +340,5 @@
    -     <string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"Më i madhi"</string>
    -     <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"I personalizuar (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
    -     <string name="help_feedback_label" msgid="6815040660801785649">"Ndihma dhe komentet"</string>
    -+    <string name="content_description_menu_button" msgid="8182594799812351266">"Menyja"</string>
    - </resources>
    -diff --git a/packages/SettingsLib/res/values-sr/strings.xml b/packages/SettingsLib/res/values-sr/strings.xml
    -index fba58c5..f8b3b4b 100644
    ---- a/packages/SettingsLib/res/values-sr/strings.xml
    -+++ b/packages/SettingsLib/res/values-sr/strings.xml
    -@@ -28,7 +28,8 @@
    -     <string name="wifi_disabled_wifi_failure" msgid="3081668066612876581">"Wi-Fi веза је отказала"</string>
    -     <string name="wifi_disabled_password_failure" msgid="8659805351763133575">"Проблем са потврдом аутентичности"</string>
    -     <string name="wifi_not_in_range" msgid="1136191511238508967">"Није у опсегу"</string>
    --    <string name="wifi_no_internet" msgid="9151470775868728896">"Приступ интернету није откривен, аутоматско повезивање није могуће."</string>
    -+    <string name="wifi_no_internet_no_reconnect" msgid="2211781637653149657">"Приступ интернету није откривен, аутоматско повезивање није могуће."</string>
    -+    <string name="wifi_no_internet" msgid="5011955173375805204">"Нема приступа интернету."</string>
    -     <string name="saved_network" msgid="4352716707126620811">"Сачувао/ла је <xliff:g id="NAME">%1$s</xliff:g>"</string>
    -     <string name="connected_via_wfa" msgid="3805736726317410714">"Повезано преко Wi‑Fi помоћника"</string>
    -     <string name="connected_via_passpoint" msgid="2826205693803088747">"Веза је успостављена преко приступне тачке %1$s"</string>
    -@@ -233,8 +234,6 @@
    -     <string name="debug_layout_summary" msgid="2001775315258637682">"Прикажи границе клипа, маргине итд."</string>
    -     <string name="force_rtl_layout_all_locales" msgid="2259906643093138978">"Наметни смер распореда здесна налево"</string>
    -     <string name="force_rtl_layout_all_locales_summary" msgid="9192797796616132534">"Наметни смер распореда екрана здесна налево за све локалитете"</string>
    --    <string name="show_cpu_usage" msgid="2389212910758076024">"Прик. употребу процесора"</string>
    --    <string name="show_cpu_usage_summary" msgid="2113341923988958266">"Постав. елемент са тренутном употребом процесора"</string>
    -     <string name="force_hw_ui" msgid="6426383462520888732">"Принудни приказ пом. GPU"</string>
    -     <string name="force_hw_ui_summary" msgid="5535991166074861515">"Принудно користи GPU за 2D цртање"</string>
    -     <string name="force_msaa" msgid="7920323238677284387">"Наметни 4x MSAA"</string>
    -@@ -282,7 +281,7 @@
    -     <string name="enable_webview_multiprocess_desc" msgid="2485604010404197724">"Покрећите WebView приказиваче засебно"</string>
    -     <string name="select_webview_provider_title" msgid="4628592979751918907">"Примена WebView-а"</string>
    -     <string name="select_webview_provider_dialog_title" msgid="4370551378720004872">"Подесите примену WebView-а"</string>
    --    <string name="select_webview_provider_toast_text" msgid="5466970498308266359">"Овај избор више није важећи. Покушајте поново."</string>
    -+    <string name="select_webview_provider_toast_text" msgid="5466970498308266359">"Овај избор више није важећи. Пробајте поново."</string>
    -     <string name="convert_to_file_encryption" msgid="3060156730651061223">"Конвертуј у шифровање датотека"</string>
    -     <string name="convert_to_file_encryption_enabled" msgid="2861258671151428346">"Конвертуј..."</string>
    -     <string name="convert_to_file_encryption_done" msgid="7859766358000523953">"Већ се користи шифровање датотека"</string>
    -@@ -341,4 +340,5 @@
    -     <string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"Највећи"</string>
    -     <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Прилагођени (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
    -     <string name="help_feedback_label" msgid="6815040660801785649">"Помоћ и повратне информације"</string>
    -+    <string name="content_description_menu_button" msgid="8182594799812351266">"Мени"</string>
    - </resources>
    -diff --git a/packages/SettingsLib/res/values-sv/strings.xml b/packages/SettingsLib/res/values-sv/strings.xml
    -index ecc728a..389e03a 100644
    ---- a/packages/SettingsLib/res/values-sv/strings.xml
    -+++ b/packages/SettingsLib/res/values-sv/strings.xml
    -@@ -28,7 +28,8 @@
    -     <string name="wifi_disabled_wifi_failure" msgid="3081668066612876581">"Wi-Fi-anslutningsfel"</string>
    -     <string name="wifi_disabled_password_failure" msgid="8659805351763133575">"Autentiseringsproblem"</string>
    -     <string name="wifi_not_in_range" msgid="1136191511238508967">"Utom räckhåll"</string>
    --    <string name="wifi_no_internet" msgid="9151470775868728896">"Ingen internetåtkomst hittades. Det går inte att återansluta automatiskt."</string>
    -+    <string name="wifi_no_internet_no_reconnect" msgid="2211781637653149657">"Ingen internetåtkomst hittades. Det går inte att återansluta automatiskt."</string>
    -+    <string name="wifi_no_internet" msgid="5011955173375805204">"Ingen internetåtkomst"</string>
    -     <string name="saved_network" msgid="4352716707126620811">"Sparades av <xliff:g id="NAME">%1$s</xliff:g>"</string>
    -     <string name="connected_via_wfa" msgid="3805736726317410714">"Ansluten via Wi-Fi-assistent"</string>
    -     <string name="connected_via_passpoint" msgid="2826205693803088747">"Anslutet via %1$s"</string>
    -@@ -233,8 +234,6 @@
    -     <string name="debug_layout_summary" msgid="2001775315258637682">"Visa gränser för videoklipp, marginaler m.m."</string>
    -     <string name="force_rtl_layout_all_locales" msgid="2259906643093138978">"Tvinga fram RTL-layout"</string>
    -     <string name="force_rtl_layout_all_locales_summary" msgid="9192797796616132534">"Tvinga fram RTL-skärmlayout (hö–vä) för alla språk"</string>
    --    <string name="show_cpu_usage" msgid="2389212910758076024">"Visa CPU-användning"</string>
    --    <string name="show_cpu_usage_summary" msgid="2113341923988958266">"Överlägg på skärmen med aktuell CPU-användning"</string>
    -     <string name="force_hw_ui" msgid="6426383462520888732">"Framtvinga GPU-rendering"</string>
    -     <string name="force_hw_ui_summary" msgid="5535991166074861515">"Tvingad användning av GPU för 2D-ritning"</string>
    -     <string name="force_msaa" msgid="7920323238677284387">"Force 4x MSAA"</string>
    -@@ -341,4 +340,5 @@
    -     <string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"Störst"</string>
    -     <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Anpassad (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
    -     <string name="help_feedback_label" msgid="6815040660801785649">"Hjälp och feedback"</string>
    -+    <string name="content_description_menu_button" msgid="8182594799812351266">"Meny"</string>
    - </resources>
    -diff --git a/packages/SettingsLib/res/values-sw/strings.xml b/packages/SettingsLib/res/values-sw/strings.xml
    -index 435a1bd..ff6687c 100644
    ---- a/packages/SettingsLib/res/values-sw/strings.xml
    -+++ b/packages/SettingsLib/res/values-sw/strings.xml
    -@@ -28,7 +28,8 @@
    -     <string name="wifi_disabled_wifi_failure" msgid="3081668066612876581">"Haikuweza Kuunganisha kwenye WiFi"</string>
    -     <string name="wifi_disabled_password_failure" msgid="8659805351763133575">"Tatizo la uthibitishaji"</string>
    -     <string name="wifi_not_in_range" msgid="1136191511238508967">"Haiko karibu"</string>
    --    <string name="wifi_no_internet" msgid="9151470775868728896">"Hakuna Ufikiaji kwa Intaneti Uliogunduliwa, haitaweza kuunganisha kiotomatiki."</string>
    -+    <string name="wifi_no_internet_no_reconnect" msgid="2211781637653149657">"Haikupata Muunganisho wa Intaneti. Haitaweza kuunganisha tena kiotomatiki."</string>
    -+    <string name="wifi_no_internet" msgid="5011955173375805204">"Hakuna Muunganisho wa Intaneti."</string>
    -     <string name="saved_network" msgid="4352716707126620811">"Ilihifadhiwa na <xliff:g id="NAME">%1$s</xliff:g>"</string>
    -     <string name="connected_via_wfa" msgid="3805736726317410714">"Imeunganishwa kupitia Kisaidizi cha Wi-Fi"</string>
    -     <string name="connected_via_passpoint" msgid="2826205693803088747">"Imeunganishwa kupitia %1$s"</string>
    -@@ -233,8 +234,6 @@
    -     <string name="debug_layout_summary" msgid="2001775315258637682">"Onyesha mipaka ya picha, kingo, nk."</string>
    -     <string name="force_rtl_layout_all_locales" msgid="2259906643093138978">"Lazimisha uelekezaji wa muundo wa RTL"</string>
    -     <string name="force_rtl_layout_all_locales_summary" msgid="9192797796616132534">"Lazimisha uelekezaji wa muundo wa skrini kwa RTL kwa lugha zote"</string>
    --    <string name="show_cpu_usage" msgid="2389212910758076024">"Onyesha matumizi ya CPU"</string>
    --    <string name="show_cpu_usage_summary" msgid="2113341923988958266">"Kuegeshwa kwa skrini ikionyesha matumizi ya sasa ya CPU"</string>
    -     <string name="force_hw_ui" msgid="6426383462520888732">"Lazimisha kutungiliza  GPU"</string>
    -     <string name="force_hw_ui_summary" msgid="5535991166074861515">"Lazimisha matumizi ya GPU kwa uchoraji wa 2d"</string>
    -     <string name="force_msaa" msgid="7920323238677284387">"Lazimisha 4x MSAA"</string>
    -@@ -341,4 +340,5 @@
    -     <string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"Kubwa zaidi"</string>
    -     <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Kiwango maalum (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
    -     <string name="help_feedback_label" msgid="6815040660801785649">"Usaidizi na maoni"</string>
    -+    <string name="content_description_menu_button" msgid="8182594799812351266">"Menyu"</string>
    - </resources>
    -diff --git a/packages/SettingsLib/res/values-ta-rIN/strings.xml b/packages/SettingsLib/res/values-ta-rIN/strings.xml
    -index 033955c..86f58fc 100644
    ---- a/packages/SettingsLib/res/values-ta-rIN/strings.xml
    -+++ b/packages/SettingsLib/res/values-ta-rIN/strings.xml
    -@@ -28,7 +28,8 @@
    -     <string name="wifi_disabled_wifi_failure" msgid="3081668066612876581">"வைஃபை இணைப்பில் தோல்வி"</string>
    -     <string name="wifi_disabled_password_failure" msgid="8659805351763133575">"அங்கீகரிப்புச் சிக்கல்"</string>
    -     <string name="wifi_not_in_range" msgid="1136191511238508967">"தொடர்பு எல்லையில் இல்லை"</string>
    --    <string name="wifi_no_internet" msgid="9151470775868728896">"இணைய அணுகல் இல்லை, மீண்டும் தானாக இணையாது."</string>
    -+    <string name="wifi_no_internet_no_reconnect" msgid="2211781637653149657">"இணைய அணுகல் இல்லை, மீண்டும் தானாக இணையாது."</string>
    -+    <string name="wifi_no_internet" msgid="5011955173375805204">"இணைய அணுகல் இல்லை."</string>
    -     <string name="saved_network" msgid="4352716707126620811">"<xliff:g id="NAME">%1$s</xliff:g> சேமித்தது"</string>
    -     <string name="connected_via_wfa" msgid="3805736726317410714">"வைஃபை அசிஸ்டண்ட் மூலம் இணைக்கப்பட்டது"</string>
    -     <string name="connected_via_passpoint" msgid="2826205693803088747">"%1$s வழியாக இணைக்கப்பட்டது"</string>
    -@@ -233,8 +234,6 @@
    -     <string name="debug_layout_summary" msgid="2001775315258637682">"கிளிப் எல்லைகள், ஓரங்கள், மேலும் பலவற்றைக் காட்டு"</string>
    -     <string name="force_rtl_layout_all_locales" msgid="2259906643093138978">"RTL தளவமைப்பின் திசையை வலியுறுத்து"</string>
    -     <string name="force_rtl_layout_all_locales_summary" msgid="9192797796616132534">"எல்லா மொழிகளுக்கும் திரையின் தளவமைப்பு திசையை RTL க்கு மாற்று"</string>
    --    <string name="show_cpu_usage" msgid="2389212910758076024">"CPU பயன்பாட்டைக் காட்டு"</string>
    --    <string name="show_cpu_usage_summary" msgid="2113341923988958266">"தற்போதைய CPU பயன்பாட்டைக் காட்டும் திரை மேலடுக்கு"</string>
    -     <string name="force_hw_ui" msgid="6426383462520888732">"GPU காட்சியாக்கத்தை வலியுறுத்து"</string>
    -     <string name="force_hw_ui_summary" msgid="5535991166074861515">"2d வரைபடத்திற்கு GPU பயன்பாட்டை வலியுறுத்து"</string>
    -     <string name="force_msaa" msgid="7920323238677284387">"4x MSAA ஐ வலியுறுத்து"</string>
    -@@ -341,4 +340,5 @@
    -     <string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"மிகப் பெரியது"</string>
    -     <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"தனிப்பயன் (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
    -     <string name="help_feedback_label" msgid="6815040660801785649">"உதவி &amp; கருத்து"</string>
    -+    <string name="content_description_menu_button" msgid="8182594799812351266">"மெனு"</string>
    - </resources>
    -diff --git a/packages/SettingsLib/res/values-te-rIN/strings.xml b/packages/SettingsLib/res/values-te-rIN/strings.xml
    -index 5758176..1326576 100644
    ---- a/packages/SettingsLib/res/values-te-rIN/strings.xml
    -+++ b/packages/SettingsLib/res/values-te-rIN/strings.xml
    -@@ -28,7 +28,8 @@
    -     <string name="wifi_disabled_wifi_failure" msgid="3081668066612876581">"WiFi కనెక్షన్ వైఫల్యం"</string>
    -     <string name="wifi_disabled_password_failure" msgid="8659805351763133575">"ప్రామాణీకరణ సమస్య"</string>
    -     <string name="wifi_not_in_range" msgid="1136191511238508967">"పరిధిలో లేదు"</string>
    --    <string name="wifi_no_internet" msgid="9151470775868728896">"ఇంటర్నెట్ ప్రాప్యత కనుగొనబడలేదు, స్వయంచాలకంగా మళ్లీ కనెక్ట్ చేయబడదు."</string>
    -+    <string name="wifi_no_internet_no_reconnect" msgid="2211781637653149657">"ఇంటర్నెట్ ప్రాప్యత కనుగొనబడలేదు, స్వయంచాలకంగా మళ్లీ కనెక్ట్ చేయబడదు."</string>
    -+    <string name="wifi_no_internet" msgid="5011955173375805204">"ఇంటర్నెట్ ప్రాప్యత లేదు."</string>
    -     <string name="saved_network" msgid="4352716707126620811">"<xliff:g id="NAME">%1$s</xliff:g> ద్వారా సేవ్ చేయబడింది"</string>
    -     <string name="connected_via_wfa" msgid="3805736726317410714">"Wi‑Fi సహాయకం ద్వారా కనెక్ట్ చేయబడింది"</string>
    -     <string name="connected_via_passpoint" msgid="2826205693803088747">"%1$s ద్వారా కనెక్ట్ చేయబడింది"</string>
    -@@ -233,8 +234,6 @@
    -     <string name="debug_layout_summary" msgid="2001775315258637682">"క్లిప్ సరిహద్దులు, అంచులు మొ. చూపు"</string>
    -     <string name="force_rtl_layout_all_locales" msgid="2259906643093138978">"RTL లేఅవుట్ దిశను నిర్భందం చేయండి"</string>
    -     <string name="force_rtl_layout_all_locales_summary" msgid="9192797796616132534">"అన్ని లొకేల్‌ల కోసం RTLకి స్క్రీన్ లేఅవుట్ దిశను నిర్భందించు"</string>
    --    <string name="show_cpu_usage" msgid="2389212910758076024">"CPU వినియోగాన్ని చూపు"</string>
    --    <string name="show_cpu_usage_summary" msgid="2113341923988958266">"ప్రస్తుత CPU వినియోగాన్ని చూపేలా స్క్రీన్ అతివ్యాప్తి చేయబడుతుంది"</string>
    -     <string name="force_hw_ui" msgid="6426383462520888732">"నిర్బంధంగా GPU భాషాంతరీకరణ"</string>
    -     <string name="force_hw_ui_summary" msgid="5535991166074861515">"2d డ్రాయింగ్ కోసం GPU నిర్భంద వినియోగం"</string>
    -     <string name="force_msaa" msgid="7920323238677284387">"నిర్భందం 4x MSAA"</string>
    -@@ -341,4 +340,5 @@
    -     <string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"అతి పెద్దగా"</string>
    -     <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"అనుకూలం (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
    -     <string name="help_feedback_label" msgid="6815040660801785649">"సహాయం &amp; అభిప్రాయం"</string>
    -+    <string name="content_description_menu_button" msgid="8182594799812351266">"మెను"</string>
    - </resources>
    -diff --git a/packages/SettingsLib/res/values-th/strings.xml b/packages/SettingsLib/res/values-th/strings.xml
    -index 4849e19..5d302d0 100644
    ---- a/packages/SettingsLib/res/values-th/strings.xml
    -+++ b/packages/SettingsLib/res/values-th/strings.xml
    -@@ -28,7 +28,8 @@
    -     <string name="wifi_disabled_wifi_failure" msgid="3081668066612876581">"การเชื่อมต่อ Wi-Fi ล้มเหลว"</string>
    -     <string name="wifi_disabled_password_failure" msgid="8659805351763133575">"ปัญหาในการตรวจสอบสิทธิ์"</string>
    -     <string name="wifi_not_in_range" msgid="1136191511238508967">"ไม่อยู่ในพื้นที่ให้บริการ"</string>
    --    <string name="wifi_no_internet" msgid="9151470775868728896">"ไม่พบการเข้าถึงอินเทอร์เน็ต ระบบจะไม่เชื่อมต่อใหม่โดยอัตโนมัติ"</string>
    -+    <string name="wifi_no_internet_no_reconnect" msgid="2211781637653149657">"ไม่พบการเข้าถึงอินเทอร์เน็ต ระบบจะไม่เชื่อมต่อใหม่โดยอัตโนมัติ"</string>
    -+    <string name="wifi_no_internet" msgid="5011955173375805204">"ไม่สามารถเข้าถึงอินเทอร์เน็ต"</string>
    -     <string name="saved_network" msgid="4352716707126620811">"บันทึกโดย <xliff:g id="NAME">%1$s</xliff:g> แล้ว"</string>
    -     <string name="connected_via_wfa" msgid="3805736726317410714">"เชื่อมต่อผ่านตัวช่วย Wi-Fi อยู่"</string>
    -     <string name="connected_via_passpoint" msgid="2826205693803088747">"เชื่อมต่อผ่าน %1$s แล้ว"</string>
    -@@ -233,8 +234,6 @@
    -     <string name="debug_layout_summary" msgid="2001775315258637682">"แสดงหน้าปกคลิป ขอบ ฯลฯ"</string>
    -     <string name="force_rtl_layout_all_locales" msgid="2259906643093138978">"บังคับทิศทางการจัดวาง RTL"</string>
    -     <string name="force_rtl_layout_all_locales_summary" msgid="9192797796616132534">"บังคับทิศทางการจัดวางหน้าจอเป็น RTL สำหรับทุกภาษา"</string>
    --    <string name="show_cpu_usage" msgid="2389212910758076024">"แสดงการใช้ CPU"</string>
    --    <string name="show_cpu_usage_summary" msgid="2113341923988958266">"การวางซ้อนหน้าจอที่แสดงการใช้ CPU ในปัจจุบัน"</string>
    -     <string name="force_hw_ui" msgid="6426383462520888732">"เร่งการแสดงผลของ GPU"</string>
    -     <string name="force_hw_ui_summary" msgid="5535991166074861515">"ต้องใช้ GPU สำหรับการวาดภาพ 2 มิติ"</string>
    -     <string name="force_msaa" msgid="7920323238677284387">"บังคับใช้ 4x MSAA"</string>
    -@@ -341,4 +340,5 @@
    -     <string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"ใหญ่ที่สุด"</string>
    -     <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"กำหนดเอง (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
    -     <string name="help_feedback_label" msgid="6815040660801785649">"ความช่วยเหลือและความคิดเห็น"</string>
    -+    <string name="content_description_menu_button" msgid="8182594799812351266">"เมนู"</string>
    - </resources>
    -diff --git a/packages/SettingsLib/res/values-tl/strings.xml b/packages/SettingsLib/res/values-tl/strings.xml
    -index 24f5499..c2232ee 100644
    ---- a/packages/SettingsLib/res/values-tl/strings.xml
    -+++ b/packages/SettingsLib/res/values-tl/strings.xml
    -@@ -28,7 +28,8 @@
    -     <string name="wifi_disabled_wifi_failure" msgid="3081668066612876581">"Pagkabigo ng Koneksyon sa WiFi"</string>
    -     <string name="wifi_disabled_password_failure" msgid="8659805351763133575">"Problema sa pagpapatotoo"</string>
    -     <string name="wifi_not_in_range" msgid="1136191511238508967">"Wala sa sakop"</string>
    --    <string name="wifi_no_internet" msgid="9151470775868728896">"Walang Natukoy na Access sa Internet, hindi awtomatikong muling kumonekta."</string>
    -+    <string name="wifi_no_internet_no_reconnect" msgid="2211781637653149657">"Walang Na-detect na Access sa Internet, hindi awtomatikong muling kokonekta."</string>
    -+    <string name="wifi_no_internet" msgid="5011955173375805204">"Walang Access sa Internet."</string>
    -     <string name="saved_network" msgid="4352716707126620811">"Na-save ni <xliff:g id="NAME">%1$s</xliff:g>"</string>
    -     <string name="connected_via_wfa" msgid="3805736726317410714">"Nakakonekta sa pamamagitan ng Wi‑Fi assistant"</string>
    -     <string name="connected_via_passpoint" msgid="2826205693803088747">"Nakakonekta sa pamamagitan ng %1$s"</string>
    -@@ -146,7 +147,7 @@
    -     <string name="vpn_settings_not_available" msgid="956841430176985598">"Hindi available ang mga setting ng VPN para sa user na ito"</string>
    -     <string name="tethering_settings_not_available" msgid="6765770438438291012">"Hindi available ang mga setting ng pagte-theter para sa user na ito"</string>
    -     <string name="apn_settings_not_available" msgid="7873729032165324000">"Hindi available ang mga setting ng Access Point Name para sa user na ito"</string>
    --    <string name="enable_adb" msgid="7982306934419797485">"Pagde-debug ng USB"</string>
    -+    <string name="enable_adb" msgid="7982306934419797485">"Pag-debug ng USB"</string>
    -     <string name="enable_adb_summary" msgid="4881186971746056635">"Debug mode kapag nakakonekta ang USB"</string>
    -     <string name="clear_adb_keys" msgid="4038889221503122743">"Bawiin ang mga pahintulot sa pag-debug ng USB"</string>
    -     <string name="bugreport_in_power" msgid="7923901846375587241">"Shortcut ng ulat sa bug"</string>
    -@@ -186,8 +187,8 @@
    -     <string name="debug_view_attributes" msgid="6485448367803310384">"I-enable ang pagsisiyasat sa attribute na view"</string>
    -     <string name="mobile_data_always_on_summary" msgid="8149773901431697910">"Palaging panatilihing aktibo ang mobile data, kahit na aktibo ang Wi‑Fi (para sa mabilis na paglipat ng network)."</string>
    -     <string name="adb_warning_title" msgid="6234463310896563253">"Payagan ang pag-debug ng USB?"</string>
    --    <string name="adb_warning_message" msgid="7316799925425402244">"Ang pag-debug ng USB ay nilalayon para sa mga layuning pagpapabuti lamang. Gamitin ito upang kumopya ng data sa pagitan ng iyong computer at iyong device, mag-install ng apps sa iyong device nang walang notification, at magbasa ng data ng log."</string>
    --    <string name="adb_keys_warning_message" msgid="5659849457135841625">"Bawiin ang access sa pagde-debug ng USB mula sa lahat ng computer na dati mong pinahintulutan?"</string>
    -+    <string name="adb_warning_message" msgid="7316799925425402244">"Ang pag-debug ng USB ay para lang sa mga layuning pag-develop. Gamitin ito upang kumopya ng data sa pagitan ng iyong computer at iyong device, mag-install ng mga app sa iyong device nang walang notification, at magbasa ng data ng log."</string>
    -+    <string name="adb_keys_warning_message" msgid="5659849457135841625">"Bawiin ang access sa pag-debug ng USB mula sa lahat ng computer na dati mong pinahintulutan?"</string>
    -     <string name="dev_settings_warning_title" msgid="7244607768088540165">"Payagan ang mga setting ng pag-develop?"</string>
    -     <string name="dev_settings_warning_message" msgid="2298337781139097964">"Nilalayon ang mga setting na ito para sa paggamit sa pag-develop lamang. Maaaring magsanhi ang mga ito ng pagkasira o hindi paggana nang maayos ng iyong device at mga application na nandito."</string>
    -     <string name="verify_apps_over_usb_title" msgid="4177086489869041953">"I-verify ang mga app sa USB"</string>
    -@@ -233,8 +234,6 @@
    -     <string name="debug_layout_summary" msgid="2001775315258637682">"Ipakita ang mga hangganan ng clip, margin, atbp."</string>
    -     <string name="force_rtl_layout_all_locales" msgid="2259906643093138978">"Force RTL layout dir."</string>
    -     <string name="force_rtl_layout_all_locales_summary" msgid="9192797796616132534">"Force screen layout dir. sa RTL sa lahat ng lokal"</string>
    --    <string name="show_cpu_usage" msgid="2389212910758076024">"Ipakita paggamit ng CPU"</string>
    --    <string name="show_cpu_usage_summary" msgid="2113341923988958266">"Ipinapakita ng screen overlay ang paggamit ng CPU ngayon"</string>
    -     <string name="force_hw_ui" msgid="6426383462520888732">"Ipilit ang pag-render ng GPU"</string>
    -     <string name="force_hw_ui_summary" msgid="5535991166074861515">"Sapilitang paggamit sa GPU para sa 2d na pagguhit"</string>
    -     <string name="force_msaa" msgid="7920323238677284387">"Puwersahin ang 4x MSAA"</string>
    -@@ -341,4 +340,5 @@
    -     <string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"Pinakamalaki"</string>
    -     <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Custom (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
    -     <string name="help_feedback_label" msgid="6815040660801785649">"Tulong at feedback"</string>
    -+    <string name="content_description_menu_button" msgid="8182594799812351266">"Menu"</string>
    - </resources>
    -diff --git a/packages/SettingsLib/res/values-tr/strings.xml b/packages/SettingsLib/res/values-tr/strings.xml
    -index 950e322..2541a3f 100644
    ---- a/packages/SettingsLib/res/values-tr/strings.xml
    -+++ b/packages/SettingsLib/res/values-tr/strings.xml
    -@@ -28,7 +28,8 @@
    -     <string name="wifi_disabled_wifi_failure" msgid="3081668066612876581">"Kablosuz Bağlantı Hatası"</string>
    -     <string name="wifi_disabled_password_failure" msgid="8659805351763133575">"Kimlik doğrulama sorunu"</string>
    -     <string name="wifi_not_in_range" msgid="1136191511238508967">"Kapsama alanı dışında"</string>
    --    <string name="wifi_no_internet" msgid="9151470775868728896">"İnternet Erişimi algılanmadı, otomatik olarak tekrar bağlanmayacak."</string>
    -+    <string name="wifi_no_internet_no_reconnect" msgid="2211781637653149657">"İnternet Erişimi Algılanmadı, otomatik olarak tekrar bağlanmayacak."</string>
    -+    <string name="wifi_no_internet" msgid="5011955173375805204">"İnternet Erişimi Yok."</string>
    -     <string name="saved_network" msgid="4352716707126620811">"<xliff:g id="NAME">%1$s</xliff:g> tarafından kaydedildi"</string>
    -     <string name="connected_via_wfa" msgid="3805736726317410714">"Kablosuz bağlantı yardımcısıyla bağlandı"</string>
    -     <string name="connected_via_passpoint" msgid="2826205693803088747">"%1$s üzerinden bağlı"</string>
    -@@ -233,8 +234,6 @@
    -     <string name="debug_layout_summary" msgid="2001775315258637682">"Klip sınırlarını, kenar boşluklarını vb. göster"</string>
    -     <string name="force_rtl_layout_all_locales" msgid="2259906643093138978">"Sağdan sola düzenini zorla"</string>
    -     <string name="force_rtl_layout_all_locales_summary" msgid="9192797796616132534">"Tüm yerel ayarlar için sağdan sola ekran düzenini zorlar"</string>
    --    <string name="show_cpu_usage" msgid="2389212910758076024">"CPU kullanımını göster"</string>
    --    <string name="show_cpu_usage_summary" msgid="2113341923988958266">"Mevcut CPU kullanımını gösteren yer paylaşımı"</string>
    -     <string name="force_hw_ui" msgid="6426383462520888732">"GPU oluşturmayı zorla"</string>
    -     <string name="force_hw_ui_summary" msgid="5535991166074861515">"2D çizimde GPU kullanımını zorla"</string>
    -     <string name="force_msaa" msgid="7920323238677284387">"4x MSAA\'yı zorla"</string>
    -@@ -341,4 +340,5 @@
    -     <string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"En büyük"</string>
    -     <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Özel (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
    -     <string name="help_feedback_label" msgid="6815040660801785649">"Yardım ve geri bildirim"</string>
    -+    <string name="content_description_menu_button" msgid="8182594799812351266">"Menü"</string>
    - </resources>
    -diff --git a/packages/SettingsLib/res/values-uk/strings.xml b/packages/SettingsLib/res/values-uk/strings.xml
    -index 6b49b14..1829677 100644
    ---- a/packages/SettingsLib/res/values-uk/strings.xml
    -+++ b/packages/SettingsLib/res/values-uk/strings.xml
    -@@ -28,7 +28,8 @@
    -     <string name="wifi_disabled_wifi_failure" msgid="3081668066612876581">"Помилка з’єднання Wi-Fi"</string>
    -     <string name="wifi_disabled_password_failure" msgid="8659805351763133575">"Проблема з автентифікацією"</string>
    -     <string name="wifi_not_in_range" msgid="1136191511238508967">"Не в діапазоні"</string>
    --    <string name="wifi_no_internet" msgid="9151470775868728896">"Немає доступу до Інтернету. Спроба під’єднання не здійснюватиметься автоматично."</string>
    -+    <string name="wifi_no_internet_no_reconnect" msgid="2211781637653149657">"Немає доступу до Інтернету. Спроба під’єднання не здійснюватиметься автоматично."</string>
    -+    <string name="wifi_no_internet" msgid="5011955173375805204">"Немає доступу до Інтернету."</string>
    -     <string name="saved_network" msgid="4352716707126620811">"Збережено додатком <xliff:g id="NAME">%1$s</xliff:g>"</string>
    -     <string name="connected_via_wfa" msgid="3805736726317410714">"Під’єднано через Диспетчер Wi-Fi-з’єднання"</string>
    -     <string name="connected_via_passpoint" msgid="2826205693803088747">"Під’єднано через %1$s"</string>
    -@@ -233,8 +234,6 @@
    -     <string name="debug_layout_summary" msgid="2001775315258637682">"Показувати межі роликів, поля тощо"</string>
    -     <string name="force_rtl_layout_all_locales" msgid="2259906643093138978">"Макет письма справа наліво"</string>
    -     <string name="force_rtl_layout_all_locales_summary" msgid="9192797796616132534">"Застосовувати макет письма справа наліво для всіх мов"</string>
    --    <string name="show_cpu_usage" msgid="2389212910758076024">"Показати використання ЦП"</string>
    --    <string name="show_cpu_usage_summary" msgid="2113341923988958266">"Показувати на екрані поточне використання ЦП"</string>
    -     <string name="force_hw_ui" msgid="6426383462520888732">"Примусова візуалізація GPU"</string>
    -     <string name="force_hw_ui_summary" msgid="5535991166074861515">"Примусово використовувати GPU для 2D-малювання"</string>
    -     <string name="force_msaa" msgid="7920323238677284387">"Примус. запустити 4x MSAA"</string>
    -@@ -341,4 +340,5 @@
    -     <string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"Найбільші елементи"</string>
    -     <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Спеціальний масштаб (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
    -     <string name="help_feedback_label" msgid="6815040660801785649">"Довідка й відгуки"</string>
    -+    <string name="content_description_menu_button" msgid="8182594799812351266">"Меню"</string>
    - </resources>
    -diff --git a/packages/SettingsLib/res/values-ur-rPK/strings.xml b/packages/SettingsLib/res/values-ur-rPK/strings.xml
    -index 2ac8a61..8bcf20b 100644
    ---- a/packages/SettingsLib/res/values-ur-rPK/strings.xml
    -+++ b/packages/SettingsLib/res/values-ur-rPK/strings.xml
    -@@ -28,7 +28,8 @@
    -     <string name="wifi_disabled_wifi_failure" msgid="3081668066612876581">"‏WiFi کنکشن کی ناکامی"</string>
    -     <string name="wifi_disabled_password_failure" msgid="8659805351763133575">"توثیق کا مسئلہ"</string>
    -     <string name="wifi_not_in_range" msgid="1136191511238508967">"رینج میں نہیں ہے"</string>
    --    <string name="wifi_no_internet" msgid="9151470775868728896">"انٹرنیٹ تک کسی رسائی کا پتہ نہیں چلا، خود بخود دوبارہ منسلک نہیں ہوگا۔"</string>
    -+    <string name="wifi_no_internet_no_reconnect" msgid="2211781637653149657">"انٹرنیٹ تک کسی رسائی کا پتہ نہیں چلا، خودکار طور پر دوبارہ منسلک نہیں ہوگا۔"</string>
    -+    <string name="wifi_no_internet" msgid="5011955173375805204">"انٹرنیٹ تک کوئی رسائی نہیں۔"</string>
    -     <string name="saved_network" msgid="4352716707126620811">"<xliff:g id="NAME">%1$s</xliff:g> کی جانب سے محفوظ کردہ"</string>
    -     <string name="connected_via_wfa" msgid="3805736726317410714">"‏Wi‑Fi اسسٹنٹ کے ذریعے منسلک ہے"</string>
    -     <string name="connected_via_passpoint" msgid="2826205693803088747">"‏منسلک بذریعہ ‎%1$s"</string>
    -@@ -233,8 +234,6 @@
    -     <string name="debug_layout_summary" msgid="2001775315258637682">"کلپ باؤنڈز، حاشیے وغیرہ دکھائیں"</string>
    -     <string name="force_rtl_layout_all_locales" msgid="2259906643093138978">"‏RTL لے آؤٹ سمت زبردستی نافذ کریں"</string>
    -     <string name="force_rtl_layout_all_locales_summary" msgid="9192797796616132534">"‏سبھی زبانوں کیلئے اسکرین لے آؤٹ کی سمت کو RTL پر مجبور کریں"</string>
    --    <string name="show_cpu_usage" msgid="2389212910758076024">"‏CPU استعمال دکھائیں"</string>
    --    <string name="show_cpu_usage_summary" msgid="2113341923988958266">"‏موجودہ CPU استعمال دکھانے والا اسکرین اوورلے"</string>
    -     <string name="force_hw_ui" msgid="6426383462520888732">"‏GPU رینڈرنگ زبردستی نافذ کریں"</string>
    -     <string name="force_hw_ui_summary" msgid="5535991166074861515">"‏2D ڈرائنگ کیلئے GPU کا استعمال زبردستی نافذ کریں"</string>
    -     <string name="force_msaa" msgid="7920323238677284387">"‏4x MSAA زبردستی نافذ کریں"</string>
    -@@ -341,4 +340,5 @@
    -     <string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"سب سے بڑا"</string>
    -     <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"حسب ضرورت (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
    -     <string name="help_feedback_label" msgid="6815040660801785649">"مدد اور تاثرات"</string>
    -+    <string name="content_description_menu_button" msgid="8182594799812351266">"مینو"</string>
    - </resources>
    -diff --git a/packages/SettingsLib/res/values-uz-rUZ/strings.xml b/packages/SettingsLib/res/values-uz-rUZ/strings.xml
    -index 9022ad3..a0c72a0 100644
    ---- a/packages/SettingsLib/res/values-uz-rUZ/strings.xml
    -+++ b/packages/SettingsLib/res/values-uz-rUZ/strings.xml
    -@@ -28,7 +28,8 @@
    -     <string name="wifi_disabled_wifi_failure" msgid="3081668066612876581">"Wi-Fi ulanishini o‘rnatib bo‘lmadi"</string>
    -     <string name="wifi_disabled_password_failure" msgid="8659805351763133575">"Tasdiqdan o‘tishda muammo"</string>
    -     <string name="wifi_not_in_range" msgid="1136191511238508967">"Aloqada emas"</string>
    --    <string name="wifi_no_internet" msgid="9151470775868728896">"Internetga ulanish aniqlanmadi, avtomatik ravishda qayta ulana olmaydi."</string>
    -+    <string name="wifi_no_internet_no_reconnect" msgid="2211781637653149657">"Internetga ulanish aniqlanmadi, avtomatik ravishda qayta ulana olmaydi."</string>
    -+    <string name="wifi_no_internet" msgid="5011955173375805204">"Internet aloqasi yo‘q."</string>
    -     <string name="saved_network" msgid="4352716707126620811">"<xliff:g id="NAME">%1$s</xliff:g> tomonidan saqlangan"</string>
    -     <string name="connected_via_wfa" msgid="3805736726317410714">"Wi‑Fi yordamchisi orqali ulangan"</string>
    -     <string name="connected_via_passpoint" msgid="2826205693803088747">"%1$s orqali ulangan"</string>
    -@@ -233,8 +234,6 @@
    -     <string name="debug_layout_summary" msgid="2001775315258637682">"Klip, maydon va h.k. chegaralarini ko‘rsatish"</string>
    -     <string name="force_rtl_layout_all_locales" msgid="2259906643093138978">"O‘ngdan chapga qarab yozish"</string>
    -     <string name="force_rtl_layout_all_locales_summary" msgid="9192797796616132534">"Barcha tillarda o‘ngdan chapga qarab yozish"</string>
    --    <string name="show_cpu_usage" msgid="2389212910758076024">"MP yuklanishini ko‘rsatish"</string>
    --    <string name="show_cpu_usage_summary" msgid="2113341923988958266">"Joriy MP yuklanishini ko‘rsatuvchi ekran"</string>
    -     <string name="force_hw_ui" msgid="6426383462520888732">"GPU yordamida tezlatish"</string>
    -     <string name="force_hw_ui_summary" msgid="5535991166074861515">"Ikki o‘lchamli chizma uchun doim GPU ishlatilsin"</string>
    -     <string name="force_msaa" msgid="7920323238677284387">"4x MSAAni yoqish"</string>
    -@@ -341,4 +340,5 @@
    -     <string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"Eng katta"</string>
    -     <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Moslashtirilgan (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
    -     <string name="help_feedback_label" msgid="6815040660801785649">"Yordam va fikr-mulohaza"</string>
    -+    <string name="content_description_menu_button" msgid="8182594799812351266">"Menyu"</string>
    - </resources>
    -diff --git a/packages/SettingsLib/res/values-vi/strings.xml b/packages/SettingsLib/res/values-vi/strings.xml
    -index c58f849..b991177 100644
    ---- a/packages/SettingsLib/res/values-vi/strings.xml
    -+++ b/packages/SettingsLib/res/values-vi/strings.xml
    -@@ -28,7 +28,8 @@
    -     <string name="wifi_disabled_wifi_failure" msgid="3081668066612876581">"Lỗi kết nối WiFi"</string>
    -     <string name="wifi_disabled_password_failure" msgid="8659805351763133575">"Sự cố xác thực"</string>
    -     <string name="wifi_not_in_range" msgid="1136191511238508967">"Ngoài vùng phủ sóng"</string>
    --    <string name="wifi_no_internet" msgid="9151470775868728896">"Không phát hiện thấy truy cập Internet nào, mạng sẽ không được tự động kết nối lại."</string>
    -+    <string name="wifi_no_internet_no_reconnect" msgid="2211781637653149657">"Không phát hiện thấy kết nối Internet, mạng sẽ không tự động kết nối lại."</string>
    -+    <string name="wifi_no_internet" msgid="5011955173375805204">"Không có kết nối Internet."</string>
    -     <string name="saved_network" msgid="4352716707126620811">"Được lưu bởi <xliff:g id="NAME">%1$s</xliff:g>"</string>
    -     <string name="connected_via_wfa" msgid="3805736726317410714">"Được kết nối qua trình hỗ trợ Wi‑Fi"</string>
    -     <string name="connected_via_passpoint" msgid="2826205693803088747">"Được kết nối qua %1$s"</string>
    -@@ -233,8 +234,6 @@
    -     <string name="debug_layout_summary" msgid="2001775315258637682">"Hiển thị viền đoạn video, lề, v.v.."</string>
    -     <string name="force_rtl_layout_all_locales" msgid="2259906643093138978">"Buộc hướng bố cục RTL"</string>
    -     <string name="force_rtl_layout_all_locales_summary" msgid="9192797796616132534">"Buộc hướng bố cục màn hình RTL cho tất cả ngôn ngữ"</string>
    --    <string name="show_cpu_usage" msgid="2389212910758076024">"Hiển thị mức sử dụng CPU"</string>
    --    <string name="show_cpu_usage_summary" msgid="2113341923988958266">"Lớp phủ màn hình hiển thị mức sử dụng CPU hiện tại"</string>
    -     <string name="force_hw_ui" msgid="6426383462520888732">"Bắt buộc kết xuất GPU"</string>
    -     <string name="force_hw_ui_summary" msgid="5535991166074861515">"Bắt buộc sử dụng GPU cho bản vẽ 2d"</string>
    -     <string name="force_msaa" msgid="7920323238677284387">"Bắt buộc 4x MSAA"</string>
    -@@ -341,4 +340,5 @@
    -     <string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"Lớn nhất"</string>
    -     <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Tùy chỉnh (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
    -     <string name="help_feedback_label" msgid="6815040660801785649">"Trợ giúp và phản hồi"</string>
    -+    <string name="content_description_menu_button" msgid="8182594799812351266">"Menu"</string>
    - </resources>
    -diff --git a/packages/SettingsLib/res/values-zh-rCN/strings.xml b/packages/SettingsLib/res/values-zh-rCN/strings.xml
    -index 18ae80e..29c4c73 100644
    ---- a/packages/SettingsLib/res/values-zh-rCN/strings.xml
    -+++ b/packages/SettingsLib/res/values-zh-rCN/strings.xml
    -@@ -28,7 +28,8 @@
    -     <string name="wifi_disabled_wifi_failure" msgid="3081668066612876581">"WLAN 连接失败"</string>
    -     <string name="wifi_disabled_password_failure" msgid="8659805351763133575">"身份验证出现问题"</string>
    -     <string name="wifi_not_in_range" msgid="1136191511238508967">"不在范围内"</string>
    --    <string name="wifi_no_internet" msgid="9151470775868728896">"未检测到任何互联网连接,因此不会自动重新连接。"</string>
    -+    <string name="wifi_no_internet_no_reconnect" msgid="2211781637653149657">"未检测到任何互联网连接,系统无法自动为您重新连接。"</string>
    -+    <string name="wifi_no_internet" msgid="5011955173375805204">"无法连接到互联网。"</string>
    -     <string name="saved_network" msgid="4352716707126620811">"已通过<xliff:g id="NAME">%1$s</xliff:g>保存"</string>
    -     <string name="connected_via_wfa" msgid="3805736726317410714">"已连接(通过 WLAN 助手)"</string>
    -     <string name="connected_via_passpoint" msgid="2826205693803088747">"已通过%1$s连接"</string>
    -@@ -186,7 +187,7 @@
    -     <string name="debug_view_attributes" msgid="6485448367803310384">"启用视图属性检查功能"</string>
    -     <string name="mobile_data_always_on_summary" msgid="8149773901431697910">"始终开启移动数据网络,即使 WLAN 网络已开启(便于快速切换网络)。"</string>
    -     <string name="adb_warning_title" msgid="6234463310896563253">"是否允许USB调试?"</string>
    --    <string name="adb_warning_message" msgid="7316799925425402244">"USB调试仅适用于开发工作。该功能可用于在您的计算机和设备之间复制数据、在您的设备上安装应用而不发送通知以及读取日志数据。"</string>
    -+    <string name="adb_warning_message" msgid="7316799925425402244">"USB 调试仅用于开发目的。该功能可用于在您的计算机和设备之间复制数据、在您的设备上安装应用(事先不发通知)以及读取日志数据。"</string>
    -     <string name="adb_keys_warning_message" msgid="5659849457135841625">"是否针对您之前授权的所有计算机撤消USB调试的访问权限?"</string>
    -     <string name="dev_settings_warning_title" msgid="7244607768088540165">"允许开发设置?"</string>
    -     <string name="dev_settings_warning_message" msgid="2298337781139097964">"这些设置仅适用于开发工作。一旦启用,会导致您的设备以及设备上的应用崩溃或出现异常。"</string>
    -@@ -233,8 +234,6 @@
    -     <string name="debug_layout_summary" msgid="2001775315258637682">"显示剪辑边界、边距等。"</string>
    -     <string name="force_rtl_layout_all_locales" msgid="2259906643093138978">"强制使用从右到左的布局方向"</string>
    -     <string name="force_rtl_layout_all_locales_summary" msgid="9192797796616132534">"强制将所有语言区域的屏幕布局方向改为从右到左"</string>
    --    <string name="show_cpu_usage" msgid="2389212910758076024">"显示 CPU 使用情况"</string>
    --    <string name="show_cpu_usage_summary" msgid="2113341923988958266">"屏幕叠加层显示当前 CPU 使用情况"</string>
    -     <string name="force_hw_ui" msgid="6426383462520888732">"强制进行 GPU 渲染"</string>
    -     <string name="force_hw_ui_summary" msgid="5535991166074861515">"强制使用 GPU 进行 2D 绘图"</string>
    -     <string name="force_msaa" msgid="7920323238677284387">"强制启用 4x MSAA"</string>
    -@@ -341,4 +340,5 @@
    -     <string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"最大"</string>
    -     <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"自定义 (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
    -     <string name="help_feedback_label" msgid="6815040660801785649">"帮助和反馈"</string>
    -+    <string name="content_description_menu_button" msgid="8182594799812351266">"菜单"</string>
    - </resources>
    -diff --git a/packages/SettingsLib/res/values-zh-rHK/strings.xml b/packages/SettingsLib/res/values-zh-rHK/strings.xml
    -index 660071d..c77b786 100644
    ---- a/packages/SettingsLib/res/values-zh-rHK/strings.xml
    -+++ b/packages/SettingsLib/res/values-zh-rHK/strings.xml
    -@@ -28,7 +28,8 @@
    -     <string name="wifi_disabled_wifi_failure" msgid="3081668066612876581">"WiFi 連線失敗"</string>
    -     <string name="wifi_disabled_password_failure" msgid="8659805351763133575">"驗證問題"</string>
    -     <string name="wifi_not_in_range" msgid="1136191511238508967">"超出可用範圍"</string>
    --    <string name="wifi_no_internet" msgid="9151470775868728896">"未能偵測到互聯網連線,因此不會自動重新連線。"</string>
    -+    <string name="wifi_no_internet_no_reconnect" msgid="2211781637653149657">"無法偵測互聯網連線,未能自動重新連線。"</string>
    -+    <string name="wifi_no_internet" msgid="5011955173375805204">"無法偵測互聯網連線。"</string>
    -     <string name="saved_network" msgid="4352716707126620811">"<xliff:g id="NAME">%1$s</xliff:g> 的儲存"</string>
    -     <string name="connected_via_wfa" msgid="3805736726317410714">"已透過 Wi-Fi 小幫手連線"</string>
    -     <string name="connected_via_passpoint" msgid="2826205693803088747">"已透過 %1$s 連線"</string>
    -@@ -233,8 +234,6 @@
    -     <string name="debug_layout_summary" msgid="2001775315258637682">"顯示剪輯範圍、邊界等"</string>
    -     <string name="force_rtl_layout_all_locales" msgid="2259906643093138978">"強制使用從右至左的版面配置方向"</string>
    -     <string name="force_rtl_layout_all_locales_summary" msgid="9192797796616132534">"強制將所有語言代碼的畫面配置方向改為從右至左"</string>
    --    <string name="show_cpu_usage" msgid="2389212910758076024">"顯示 CPU 使用量"</string>
    --    <string name="show_cpu_usage_summary" msgid="2113341923988958266">"在螢幕上重疊顯示目前的 CPU 使用量"</string>
    -     <string name="force_hw_ui" msgid="6426383462520888732">"強制使用 GPU 轉譯"</string>
    -     <string name="force_hw_ui_summary" msgid="5535991166074861515">"強制使用 GPU 進行 2D 繪圖"</string>
    -     <string name="force_msaa" msgid="7920323238677284387">"強制 4x MSAA"</string>
    -@@ -341,4 +340,5 @@
    -     <string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"最大"</string>
    -     <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"自訂 (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
    -     <string name="help_feedback_label" msgid="6815040660801785649">"說明與意見反映"</string>
    -+    <string name="content_description_menu_button" msgid="8182594799812351266">"選單"</string>
    - </resources>
    -diff --git a/packages/SettingsLib/res/values-zh-rTW/strings.xml b/packages/SettingsLib/res/values-zh-rTW/strings.xml
    -index bce6f24..fb180ff 100644
    ---- a/packages/SettingsLib/res/values-zh-rTW/strings.xml
    -+++ b/packages/SettingsLib/res/values-zh-rTW/strings.xml
    -@@ -28,7 +28,8 @@
    -     <string name="wifi_disabled_wifi_failure" msgid="3081668066612876581">"WiFi 連線失敗"</string>
    -     <string name="wifi_disabled_password_failure" msgid="8659805351763133575">"驗證問題"</string>
    -     <string name="wifi_not_in_range" msgid="1136191511238508967">"不在有效範圍內"</string>
    --    <string name="wifi_no_internet" msgid="9151470775868728896">"未偵測到可用的網際網路連線,系統無法為您自動重新連線。"</string>
    -+    <string name="wifi_no_internet_no_reconnect" msgid="2211781637653149657">"未偵測到可用的網際網路連線,系統無法為你自動重新連線。"</string>
    -+    <string name="wifi_no_internet" msgid="5011955173375805204">"沒有可用的網際網路連線。"</string>
    -     <string name="saved_network" msgid="4352716707126620811">"由<xliff:g id="NAME">%1$s</xliff:g>儲存"</string>
    -     <string name="connected_via_wfa" msgid="3805736726317410714">"已透過 Wi‑Fi 小幫手連線"</string>
    -     <string name="connected_via_passpoint" msgid="2826205693803088747">"已透過 %1$s 連線"</string>
    -@@ -233,8 +234,6 @@
    -     <string name="debug_layout_summary" msgid="2001775315258637682">"顯示剪輯範圍、邊界等。"</string>
    -     <string name="force_rtl_layout_all_locales" msgid="2259906643093138978">"強制使用從右至左版面配置方向"</string>
    -     <string name="force_rtl_layout_all_locales_summary" msgid="9192797796616132534">"強制將所有語言代碼的畫面配置方向改為從右至左"</string>
    --    <string name="show_cpu_usage" msgid="2389212910758076024">"顯示 CPU 使用量"</string>
    --    <string name="show_cpu_usage_summary" msgid="2113341923988958266">"在螢幕上方顯示目前的 CPU 使用量"</string>
    -     <string name="force_hw_ui" msgid="6426383462520888732">"強制使用 GPU 轉譯"</string>
    -     <string name="force_hw_ui_summary" msgid="5535991166074861515">"強制使用 GPU 進行 2D 繪圖"</string>
    -     <string name="force_msaa" msgid="7920323238677284387">"強制 4x MSAA"</string>
    -@@ -341,4 +340,5 @@
    -     <string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"最大"</string>
    -     <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"自訂 (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
    -     <string name="help_feedback_label" msgid="6815040660801785649">"說明與意見回饋"</string>
    -+    <string name="content_description_menu_button" msgid="8182594799812351266">"選單"</string>
    - </resources>
    -diff --git a/packages/SettingsLib/res/values-zu/strings.xml b/packages/SettingsLib/res/values-zu/strings.xml
    -index 07c6fce..2f9d428 100644
    ---- a/packages/SettingsLib/res/values-zu/strings.xml
    -+++ b/packages/SettingsLib/res/values-zu/strings.xml
    -@@ -28,7 +28,8 @@
    -     <string name="wifi_disabled_wifi_failure" msgid="3081668066612876581">"Ukwehlulekla koxhumo le-WiFi"</string>
    -     <string name="wifi_disabled_password_failure" msgid="8659805351763133575">"Inkinga yokufakazela ubuqiniso"</string>
    -     <string name="wifi_not_in_range" msgid="1136191511238508967">"Ayikho ebubanzini"</string>
    --    <string name="wifi_no_internet" msgid="9151470775868728896">"Ukufinyeela okungekhona kwe-inthanethi kutholakele, ngeke kuxhumeke ngokuzenzakalelayo."</string>
    -+    <string name="wifi_no_internet_no_reconnect" msgid="2211781637653149657">"Ukufinyeela okungekhona kwe-inthanethi kutholakele, ngeke kuxhumeke ngokuzenzakalelayo."</string>
    -+    <string name="wifi_no_internet" msgid="5011955173375805204">"Akukho ukufinyelela kwe-intanethi."</string>
    -     <string name="saved_network" msgid="4352716707126620811">"Kulondolozwe ngu-<xliff:g id="NAME">%1$s</xliff:g>"</string>
    -     <string name="connected_via_wfa" msgid="3805736726317410714">"Ixhunywe ngomsizi we-Wi-FI"</string>
    -     <string name="connected_via_passpoint" msgid="2826205693803088747">"Kuxhumeke nge-%1$s"</string>
    -@@ -233,8 +234,6 @@
    -     <string name="debug_layout_summary" msgid="2001775315258637682">"Bonisa imikhawulo, imiphetho, njll, yesiqeshana."</string>
    -     <string name="force_rtl_layout_all_locales" msgid="2259906643093138978">"Phoqelela isikhombisi-ndlela sesakhiwo se-RTL"</string>
    -     <string name="force_rtl_layout_all_locales_summary" msgid="9192797796616132534">"Phoqelela isikhombisi-ndlela sesikrini ku-RTL kuzo zonke izifunda"</string>
    --    <string name="show_cpu_usage" msgid="2389212910758076024">"Bonisa ukusebenzisa i-CPU"</string>
    --    <string name="show_cpu_usage_summary" msgid="2113341923988958266">"Imbondela yesikrini ibonisa ukusetshenziswa kwe-CPU okwamanje"</string>
    -     <string name="force_hw_ui" msgid="6426383462520888732">"Phoqa ukunikeza i-GPU"</string>
    -     <string name="force_hw_ui_summary" msgid="5535991166074861515">"Phoqelela ukusetshenziswa kwe-GPU ngomdwebo we-2d"</string>
    -     <string name="force_msaa" msgid="7920323238677284387">"Phoqelela i-4x MSAA"</string>
    -@@ -341,4 +340,5 @@
    -     <string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"Okukhulu kakhulu"</string>
    -     <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Ngokwezifiso (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
    -     <string name="help_feedback_label" msgid="6815040660801785649">"Usizo nempendulo"</string>
    -+    <string name="content_description_menu_button" msgid="8182594799812351266">"Imenyu"</string>
    - </resources>
    -diff --git a/packages/SettingsLib/res/values/config.xml b/packages/SettingsLib/res/values/config.xml
    -index 0cf4a41..0aa76a0 100755
    ---- a/packages/SettingsLib/res/values/config.xml
    -+++ b/packages/SettingsLib/res/values/config.xml
    -@@ -23,8 +23,8 @@
    -     <!-- Default data warning level in mb -->
    -     <integer name="default_data_warning_level_mb">2048</integer>
    - 
    --    <!-- Whether to send a custom package name with the PSD. translatable="false"-->
    --    <bool name="config_sendPackageName">true</bool>
    -+    <!-- Whether to send a custom package name with the PSD.-->
    -+    <bool name="config_sendPackageName">false</bool>
    - 
    -     <!-- Name for the set of keys associating package names -->
    -     <string name="config_helpPackageNameKey" translatable="false"></string>
    -@@ -37,4 +37,7 @@
    - 
    -     <!-- Intent key for package name values -->
    -     <string name="config_helpIntentNameKey" translatable="false"></string>
    --</resources>
    -+
    -+    <!-- The apps that need to be hided when they are disabled -->
    -+    <string-array name="config_hideWhenDisabled_packageNames"></string-array>
    -+</resources>
    -\ No newline at end of file
    -diff --git a/packages/SettingsLib/res/values/strings.xml b/packages/SettingsLib/res/values/strings.xml
    -index 7d42211..43b7668 100644
    ---- a/packages/SettingsLib/res/values/strings.xml
    -+++ b/packages/SettingsLib/res/values/strings.xml
    -@@ -64,8 +64,10 @@
    -     <string name="wifi_disabled_password_failure">Authentication problem</string>
    -     <!-- Summary for the remembered network but currently not in range. -->
    -     <string name="wifi_not_in_range">Not in range</string>
    -+    <!-- Summary for the network but no internet connection was detected. -->
    -+    <string name="wifi_no_internet_no_reconnect">No Internet Access Detected, won\'t automatically reconnect.</string>
    -     <!-- Summary for the remembered network but no internet connection was detected. -->
    --    <string name="wifi_no_internet">No Internet Access Detected, won\'t automatically reconnect.</string>
    -+    <string name="wifi_no_internet">No Internet Access.</string>
    -     <!-- Summary for saved networks -->
    -     <string name="saved_network">Saved by <xliff:g id="name">%1$s</xliff:g></string>
    - 
    -@@ -580,11 +582,6 @@
    -     <!-- UI debug setting: force right to left layout summary [CHAR LIMIT=100] -->
    -     <string name="force_rtl_layout_all_locales_summary">Force screen layout direction to RTL for all locales</string>
    - 
    --    <!-- UI debug setting: show how CPU is being used? [CHAR LIMIT=25] -->
    --    <string name="show_cpu_usage">Show CPU usage</string>
    --    <!-- UI debug setting: show cpu usage summary [CHAR LIMIT=50] -->
    --    <string name="show_cpu_usage_summary">Screen overlay showing current CPU usage</string>
    --
    -     <!-- UI debug setting: force hardware acceleration to render apps [CHAR LIMIT=25] -->
    -     <string name="force_hw_ui">Force GPU rendering</string>
    -     <!-- UI debug setting: force hardware acceleration summary [CHAR LIMIT=50] -->
    -@@ -863,4 +860,7 @@
    -     <!-- Label for Help and feedback menu item -->
    -     <string name="help_feedback_label">Help &amp; feedback</string>
    - 
    -+    <!-- Content description for drawer menu button [CHAR_LIMIT=30]-->
    -+    <string name="content_description_menu_button">Menu</string>
    -+
    - </resources>
    -diff --git a/packages/SettingsLib/src/com/android/settingslib/HelpUtils.java b/packages/SettingsLib/src/com/android/settingslib/HelpUtils.java
    -index b5295da..381f903 100644
    ---- a/packages/SettingsLib/src/com/android/settingslib/HelpUtils.java
    -+++ b/packages/SettingsLib/src/com/android/settingslib/HelpUtils.java
    -@@ -34,6 +34,8 @@ import android.util.TypedValue;
    - import android.view.Menu;
    - import android.view.MenuItem;
    - import android.view.MenuItem.OnMenuItemClickListener;
    -+import com.android.internal.logging.MetricsLogger;
    -+import com.android.internal.logging.MetricsProto.MetricsEvent;
    - 
    - import java.net.URISyntaxException;
    - import java.util.Locale;
    -@@ -112,6 +114,9 @@ public class HelpUtils {
    -                 helpMenuItem.setOnMenuItemClickListener(new OnMenuItemClickListener() {
    -                     @Override
    -                     public boolean onMenuItemClick(MenuItem item) {
    -+                        MetricsLogger.action(activity,
    -+                            MetricsEvent.ACTION_SETTING_HELP_AND_FEEDBACK,
    -+                            intent.getStringExtra(EXTRA_CONTEXT));
    -                         try {
    -                             activity.startActivityForResult(intent, 0);
    -                         } catch (ActivityNotFoundException exc) {
    -diff --git a/packages/SettingsLib/src/com/android/settingslib/applications/ApplicationsState.java b/packages/SettingsLib/src/com/android/settingslib/applications/ApplicationsState.java
    -index a22a051..f0ec107 100644
    ---- a/packages/SettingsLib/src/com/android/settingslib/applications/ApplicationsState.java
    -+++ b/packages/SettingsLib/src/com/android/settingslib/applications/ApplicationsState.java
    -@@ -47,6 +47,7 @@ import android.util.Log;
    - import android.util.SparseArray;
    - 
    - import com.android.internal.util.ArrayUtils;
    -+import com.android.settingslib.R;
    - 
    - import java.io.File;
    - import java.text.Collator;
    -@@ -621,7 +622,7 @@ public class ApplicationsState {
    -             }
    - 
    -             if (filter != null) {
    --                filter.init();
    -+                filter.init(mContext);
    -             }
    - 
    -             List<AppEntry> apps;
    -@@ -1280,6 +1281,9 @@ public class ApplicationsState {
    - 
    -     public interface AppFilter {
    -         void init();
    -+        default void init(Context context) {
    -+            init();
    -+        }
    -         boolean filterApp(AppEntry info);
    -     }
    - 
    -@@ -1398,6 +1402,33 @@ public class ApplicationsState {
    -         }
    -     };
    - 
    -+    public static final AppFilter FILTER_NOT_HIDE = new AppFilter() {
    -+        private String[] mHidePackageNames;
    -+
    -+        public void init(Context context) {
    -+            mHidePackageNames = context.getResources()
    -+                .getStringArray(R.array.config_hideWhenDisabled_packageNames);
    -+        }
    -+
    -+        @Override
    -+        public void init() {
    -+        }
    -+
    -+        @Override
    -+        public boolean filterApp(AppEntry entry) {
    -+            if (ArrayUtils.contains(mHidePackageNames, entry.info.packageName)) {
    -+                if (!entry.info.enabled) {
    -+                    return false;
    -+                } else if (entry.info.enabledSetting ==
    -+                    PackageManager.COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED) {
    -+                    return false;
    -+                }
    -+            }
    -+
    -+            return true;
    -+        }
    -+    };
    -+
    -     public static class VolumeFilter implements AppFilter {
    -         private final String mVolumeUuid;
    - 
    -@@ -1425,6 +1456,12 @@ public class ApplicationsState {
    -         }
    - 
    -         @Override
    -+        public void init(Context context) {
    -+            mFirstFilter.init(context);
    -+            mSecondFilter.init(context);
    -+        }
    -+
    -+        @Override
    -         public void init() {
    -             mFirstFilter.init();
    -             mSecondFilter.init();
    -diff --git a/packages/SettingsLib/src/com/android/settingslib/deviceinfo/StorageMeasurement.java b/packages/SettingsLib/src/com/android/settingslib/deviceinfo/StorageMeasurement.java
    -index 0e3e0d5..5c577f8 100644
    ---- a/packages/SettingsLib/src/com/android/settingslib/deviceinfo/StorageMeasurement.java
    -+++ b/packages/SettingsLib/src/com/android/settingslib/deviceinfo/StorageMeasurement.java
    -@@ -126,6 +126,13 @@ public class StorageMeasurement {
    -          * internal storage. Key is {@link UserHandle}.
    -          */
    -         public SparseLongArray usersSize = new SparseLongArray();
    -+
    -+        @Override
    -+        public String toString() {
    -+            return "MeasurementDetails: [totalSize: " + totalSize + " availSize: " + availSize
    -+                    + " cacheSize: " + cacheSize + " mediaSize: " + mediaSize
    -+                    + " miscSize: " + miscSize + "usersSize: " + usersSize + "]";
    -+        }
    -     }
    - 
    -     public interface MeasurementReceiver {
    -@@ -435,7 +442,7 @@ public class StorageMeasurement {
    -     private static long getDirectorySize(IMediaContainerService imcs, File path) {
    -         try {
    -             final long size = imcs.calculateDirectorySize(path.toString());
    --            Log.d(TAG, "getDirectorySize(" + path + ") returned " + size);
    -+            if (LOGV) Log.v(TAG, "getDirectorySize(" + path + ") returned " + size);
    -             return size;
    -         } catch (Exception e) {
    -             Log.w(TAG, "Could not read memory from default container service for " + path, e);
    -diff --git a/packages/SettingsLib/src/com/android/settingslib/display/DisplayDensityUtils.java b/packages/SettingsLib/src/com/android/settingslib/display/DisplayDensityUtils.java
    -index a99e668..af8fd4c 100644
    ---- a/packages/SettingsLib/src/com/android/settingslib/display/DisplayDensityUtils.java
    -+++ b/packages/SettingsLib/src/com/android/settingslib/display/DisplayDensityUtils.java
    -@@ -23,6 +23,7 @@ import android.content.res.Resources;
    - import android.hardware.display.DisplayManager;
    - import android.os.AsyncTask;
    - import android.os.RemoteException;
    -+import android.os.UserHandle;
    - import android.util.DisplayMetrics;
    - import android.util.Log;
    - import android.util.MathUtils;
    -@@ -207,39 +208,41 @@ public class DisplayDensityUtils {
    - 
    -     /**
    -      * Asynchronously applies display density changes to the specified display.
    -+     * <p>
    -+     * The change will be applied to the user specified by the value of
    -+     * {@link UserHandle#myUserId()} at the time the method is called.
    -      *
    -      * @param displayId the identifier of the display to modify
    -      */
    -     public static void clearForcedDisplayDensity(final int displayId) {
    --        AsyncTask.execute(new Runnable() {
    --            @Override
    --            public void run() {
    --                try {
    --                    final IWindowManager wm = WindowManagerGlobal.getWindowManagerService();
    --                    wm.clearForcedDisplayDensity(displayId);
    --                } catch (RemoteException exc) {
    --                    Log.w(LOG_TAG, "Unable to clear forced display density setting");
    --                }
    -+        final int userId = UserHandle.myUserId();
    -+        AsyncTask.execute(() -> {
    -+            try {
    -+                final IWindowManager wm = WindowManagerGlobal.getWindowManagerService();
    -+                wm.clearForcedDisplayDensityForUser(displayId, userId);
    -+            } catch (RemoteException exc) {
    -+                Log.w(LOG_TAG, "Unable to clear forced display density setting");
    -             }
    -         });
    -     }
    - 
    -     /**
    -      * Asynchronously applies display density changes to the specified display.
    -+     * <p>
    -+     * The change will be applied to the user specified by the value of
    -+     * {@link UserHandle#myUserId()} at the time the method is called.
    -      *
    -      * @param displayId the identifier of the display to modify
    -      * @param density the density to force for the specified display
    -      */
    -     public static void setForcedDisplayDensity(final int displayId, final int density) {
    --        AsyncTask.execute(new Runnable() {
    --            @Override
    --            public void run() {
    --                try {
    --                    final IWindowManager wm = WindowManagerGlobal.getWindowManagerService();
    --                    wm.setForcedDisplayDensity(displayId, density);
    --                } catch (RemoteException exc) {
    --                    Log.w(LOG_TAG, "Unable to save forced display density setting");
    --                }
    -+        final int userId = UserHandle.myUserId();
    -+        AsyncTask.execute(() -> {
    -+            try {
    -+                final IWindowManager wm = WindowManagerGlobal.getWindowManagerService();
    -+                wm.setForcedDisplayDensityForUser(displayId, density, userId);
    -+            } catch (RemoteException exc) {
    -+                Log.w(LOG_TAG, "Unable to save forced display density setting");
    -             }
    -         });
    -     }
    -diff --git a/packages/SettingsLib/src/com/android/settingslib/drawer/SettingsDrawerActivity.java b/packages/SettingsLib/src/com/android/settingslib/drawer/SettingsDrawerActivity.java
    -index 6658c14..e6e0243 100644
    ---- a/packages/SettingsLib/src/com/android/settingslib/drawer/SettingsDrawerActivity.java
    -+++ b/packages/SettingsLib/src/com/android/settingslib/drawer/SettingsDrawerActivity.java
    -@@ -28,8 +28,11 @@ import android.content.pm.PackageManager;
    - import android.content.res.TypedArray;
    - import android.os.AsyncTask;
    - import android.os.Bundle;
    -+import android.os.UserHandle;
    -+import android.os.UserManager;
    - import android.provider.Settings;
    - import android.support.v4.widget.DrawerLayout;
    -+import android.text.TextUtils;
    - import android.util.ArraySet;
    - import android.util.Log;
    - import android.util.Pair;
    -@@ -56,6 +59,7 @@ public class SettingsDrawerActivity extends Activity {
    - 
    -     protected static final boolean DEBUG_TIMING = false;
    -     private static final String TAG = "SettingsDrawerActivity";
    -+    private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
    - 
    -     public static final String EXTRA_SHOW_MENU = "show_drawer_menu";
    - 
    -@@ -73,6 +77,7 @@ public class SettingsDrawerActivity extends Activity {
    -     private FrameLayout mContentHeaderContainer;
    -     private DrawerLayout mDrawerLayout;
    -     private boolean mShowingMenu;
    -+    private UserManager mUserManager;
    - 
    -     @Override
    -     protected void onCreate(@Nullable Bundle savedInstanceState) {
    -@@ -108,8 +113,10 @@ public class SettingsDrawerActivity extends Activity {
    -             public void onItemClick(android.widget.AdapterView<?> parent, View view, int position,
    -                     long id) {
    -                 onTileClicked(mDrawerAdapter.getTile(position));
    --            };
    -+            }
    -         });
    -+
    -+        mUserManager = UserManager.get(this);
    -         if (DEBUG_TIMING) Log.d(TAG, "onCreate took " + (System.currentTimeMillis() - startTime)
    -                 + " ms");
    -     }
    -@@ -138,8 +145,16 @@ public class SettingsDrawerActivity extends Activity {
    - 
    -             new CategoriesUpdater().execute();
    -         }
    --        if (getIntent() != null && getIntent().getBooleanExtra(EXTRA_SHOW_MENU, false)) {
    --            showMenuIcon();
    -+        final Intent intent = getIntent();
    -+        if (intent != null) {
    -+            if (intent.hasExtra(EXTRA_SHOW_MENU)) {
    -+                if (intent.getBooleanExtra(EXTRA_SHOW_MENU, false)) {
    -+                    // Intent explicitly set to show menu.
    -+                    showMenuIcon();
    -+                }
    -+            } else if (isTopLevelTile(intent)) {
    -+                showMenuIcon();
    -+            }
    -         }
    -     }
    - 
    -@@ -152,6 +167,30 @@ public class SettingsDrawerActivity extends Activity {
    -         super.onPause();
    -     }
    - 
    -+    private boolean isTopLevelTile(Intent intent) {
    -+        final ComponentName componentName = intent.getComponent();
    -+        if (componentName == null) {
    -+            return false;
    -+        }
    -+        // Look for a tile that has the same component as incoming intent
    -+        final List<DashboardCategory> categories = getDashboardCategories();
    -+        for (DashboardCategory category : categories) {
    -+            for (Tile tile : category.tiles) {
    -+                if (TextUtils.equals(tile.intent.getComponent().getClassName(),
    -+                        componentName.getClassName())) {
    -+                    if (DEBUG) {
    -+                        Log.d(TAG, "intent is for top level tile: " + tile.title);
    -+                    }
    -+                    return true;
    -+                }
    -+            }
    -+        }
    -+        if (DEBUG) {
    -+            Log.d(TAG, "Intent is not for top level settings " + intent);
    -+        }
    -+        return false;
    -+    }
    -+
    -     public void addCategoryListener(CategoryListener listener) {
    -         mCategoryListeners.add(listener);
    -     }
    -@@ -226,6 +265,7 @@ public class SettingsDrawerActivity extends Activity {
    -     public void showMenuIcon() {
    -         mShowingMenu = true;
    -         getActionBar().setHomeAsUpIndicator(R.drawable.ic_menu);
    -+        getActionBar().setHomeActionContentDescription(R.string.content_description_menu_button);
    -         getActionBar().setDisplayHomeAsUpEnabled(true);
    -     }
    - 
    -@@ -256,6 +296,7 @@ public class SettingsDrawerActivity extends Activity {
    -             return true;
    -         }
    -         try {
    -+            updateUserHandlesIfNeeded(tile);
    -             int numUserHandles = tile.userHandle.size();
    -             if (numUserHandles > 1) {
    -                 ProfileSelectDialog.show(getFragmentManager(), tile);
    -@@ -277,6 +318,19 @@ public class SettingsDrawerActivity extends Activity {
    -         return true;
    -     }
    - 
    -+    private void updateUserHandlesIfNeeded(Tile tile) {
    -+        List<UserHandle> userHandles = tile.userHandle;
    -+
    -+        for (int i = userHandles.size() - 1; i >= 0; i--) {
    -+            if (mUserManager.getUserInfo(userHandles.get(i).getIdentifier()) == null) {
    -+                if (DEBUG) {
    -+                    Log.d(TAG, "Delete the user: " + userHandles.get(i).getIdentifier());
    -+                }
    -+                userHandles.remove(i);
    -+            }
    -+        }
    -+    }
    -+
    -     protected void onTileClicked(Tile tile) {
    -         if (openTile(tile)) {
    -             finish();
    -diff --git a/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java b/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java
    -index 380fcd4..234ae71 100644
    ---- a/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java
    -+++ b/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java
    -@@ -356,21 +356,26 @@ public class AccessPoint implements Comparable<AccessPoint> {
    -     }
    - 
    -     public DetailedState getDetailedState() {
    --        return mNetworkInfo != null ? mNetworkInfo.getDetailedState() : null;
    -+        if (mNetworkInfo != null) {
    -+            return mNetworkInfo.getDetailedState();
    -+        }
    -+        Log.w(TAG, "NetworkInfo is null, cannot return detailed state");
    -+        return null;
    -     }
    - 
    -     public String getSavedNetworkSummary() {
    --        if (mConfig != null) {
    -+        WifiConfiguration config = mConfig;
    -+        if (config != null) {
    -             PackageManager pm = mContext.getPackageManager();
    -             String systemName = pm.getNameForUid(android.os.Process.SYSTEM_UID);
    --            int userId = UserHandle.getUserId(mConfig.creatorUid);
    -+            int userId = UserHandle.getUserId(config.creatorUid);
    -             ApplicationInfo appInfo = null;
    --            if (mConfig.creatorName != null && mConfig.creatorName.equals(systemName)) {
    -+            if (config.creatorName != null && config.creatorName.equals(systemName)) {
    -                 appInfo = mContext.getApplicationInfo();
    -             } else {
    -                 try {
    -                     IPackageManager ipm = AppGlobals.getPackageManager();
    --                    appInfo = ipm.getApplicationInfo(mConfig.creatorName, 0 /* flags */, userId);
    -+                    appInfo = ipm.getApplicationInfo(config.creatorName, 0 /* flags */, userId);
    -                 } catch (RemoteException rex) {
    -                 }
    -             }
    -@@ -385,29 +390,36 @@ public class AccessPoint implements Comparable<AccessPoint> {
    -     }
    - 
    -     public String getSummary() {
    --        return getSettingsSummary();
    -+        return getSettingsSummary(mConfig);
    -     }
    - 
    -     public String getSettingsSummary() {
    -+        return getSettingsSummary(mConfig);
    -+    }
    -+
    -+    private String getSettingsSummary(WifiConfiguration config) {
    -         // Update to new summary
    -         StringBuilder summary = new StringBuilder();
    - 
    --        if (isActive() && mConfig != null && mConfig.isPasspoint()) {
    -+        if (isActive() && config != null && config.isPasspoint()) {
    -             // This is the active connection on passpoint
    -             summary.append(getSummary(mContext, getDetailedState(),
    --                    false, mConfig.providerFriendlyName));
    -+                    false, config.providerFriendlyName));
    -         } else if (isActive()) {
    -             // This is the active connection on non-passpoint network
    -             summary.append(getSummary(mContext, getDetailedState(),
    -                     mInfo != null && mInfo.isEphemeral()));
    --        } else if (mConfig != null && mConfig.isPasspoint()) {
    -+        } else if (config != null && config.isPasspoint()) {
    -             String format = mContext.getString(R.string.available_via_passpoint);
    --            summary.append(String.format(format, mConfig.providerFriendlyName));
    --        } else if (mConfig != null && mConfig.hasNoInternetAccess()) {
    --            summary.append(mContext.getString(R.string.wifi_no_internet));
    --        } else if (mConfig != null && !mConfig.getNetworkSelectionStatus().isNetworkEnabled()) {
    -+            summary.append(String.format(format, config.providerFriendlyName));
    -+        } else if (config != null && config.hasNoInternetAccess()) {
    -+            int messageID = config.getNetworkSelectionStatus().isNetworkPermanentlyDisabled()
    -+                    ? R.string.wifi_no_internet_no_reconnect
    -+                    : R.string.wifi_no_internet;
    -+            summary.append(mContext.getString(messageID));
    -+        } else if (config != null && !config.getNetworkSelectionStatus().isNetworkEnabled()) {
    -             WifiConfiguration.NetworkSelectionStatus networkStatus =
    --                    mConfig.getNetworkSelectionStatus();
    -+                    config.getNetworkSelectionStatus();
    -             switch (networkStatus.getNetworkSelectionDisableReason()) {
    -                 case WifiConfiguration.NetworkSelectionStatus.DISABLED_AUTHENTICATION_FAILURE:
    -                     summary.append(mContext.getString(R.string.wifi_disabled_password_failure));
    -@@ -423,7 +435,7 @@ public class AccessPoint implements Comparable<AccessPoint> {
    -         } else if (mRssi == Integer.MAX_VALUE) { // Wifi out of range
    -             summary.append(mContext.getString(R.string.wifi_not_in_range));
    -         } else { // In range, not disabled.
    --            if (mConfig != null) { // Is saved network
    -+            if (config != null) { // Is saved network
    -                 summary.append(mContext.getString(R.string.wifi_remembered));
    -             }
    -         }
    -@@ -435,11 +447,11 @@ public class AccessPoint implements Comparable<AccessPoint> {
    -                 summary.append(" f=" + Integer.toString(mInfo.getFrequency()));
    -             }
    -             summary.append(" " + getVisibilityStatus());
    --            if (mConfig != null && !mConfig.getNetworkSelectionStatus().isNetworkEnabled()) {
    --                summary.append(" (" + mConfig.getNetworkSelectionStatus().getNetworkStatusString());
    --                if (mConfig.getNetworkSelectionStatus().getDisableTime() > 0) {
    -+            if (config != null && !config.getNetworkSelectionStatus().isNetworkEnabled()) {
    -+                summary.append(" (" + config.getNetworkSelectionStatus().getNetworkStatusString());
    -+                if (config.getNetworkSelectionStatus().getDisableTime() > 0) {
    -                     long now = System.currentTimeMillis();
    --                    long diff = (now - mConfig.getNetworkSelectionStatus().getDisableTime()) / 1000;
    -+                    long diff = (now - config.getNetworkSelectionStatus().getDisableTime()) / 1000;
    -                     long sec = diff%60; //seconds
    -                     long min = (diff/60)%60; //minutes
    -                     long hour = (min/60)%60; //hours
    -@@ -451,9 +463,9 @@ public class AccessPoint implements Comparable<AccessPoint> {
    -                 summary.append(")");
    -             }
    - 
    --            if (mConfig != null) {
    -+            if (config != null) {
    -                 WifiConfiguration.NetworkSelectionStatus networkStatus =
    --                        mConfig.getNetworkSelectionStatus();
    -+                        config.getNetworkSelectionStatus();
    -                 for (int index = WifiConfiguration.NetworkSelectionStatus.NETWORK_SELECTION_ENABLE;
    -                         index < WifiConfiguration.NetworkSelectionStatus
    -                         .NETWORK_SELECTION_DISABLED_MAX; index++) {
    -@@ -790,7 +802,10 @@ public class AccessPoint implements Comparable<AccessPoint> {
    -                 return context.getString(R.string.wifi_connected_no_internet);
    -             }
    -         }
    --
    -+        if (state == null) {
    -+            Log.w(TAG, "state is null, returning empty summary");
    -+            return "";
    -+        }
    -         String[] formats = context.getResources().getStringArray((ssid == null)
    -                 ? R.array.wifi_status : R.array.wifi_status_with_ssid);
    -         int index = state.ordinal();
    -diff --git a/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPointPreference.java b/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPointPreference.java
    -index 284827b..aae9cf6 100644
    ---- a/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPointPreference.java
    -+++ b/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPointPreference.java
    -@@ -29,7 +29,6 @@ import android.text.TextUtils;
    - import android.util.AttributeSet;
    - import android.util.SparseArray;
    - import android.widget.TextView;
    --
    - import com.android.settingslib.R;
    - 
    - public class AccessPointPreference extends Preference {
    -@@ -44,13 +43,14 @@ public class AccessPointPreference extends Preference {
    -     private final StateListDrawable mWifiSld;
    -     private final int mBadgePadding;
    -     private final UserBadgeCache mBadgeCache;
    --
    -     private TextView mTitleView;
    -+
    -     private boolean mForSavedNetworks = false;
    -     private AccessPoint mAccessPoint;
    -     private Drawable mBadge;
    -     private int mLevel;
    -     private CharSequence mContentDescription;
    -+    private int mDefaultIconResId;
    - 
    -     static final int[] WIFI_CONNECTION_STRENGTH = {
    -             R.string.accessibility_wifi_one_bar,
    -@@ -85,6 +85,24 @@ public class AccessPointPreference extends Preference {
    -         refresh();
    -     }
    - 
    -+    public AccessPointPreference(AccessPoint accessPoint, Context context, UserBadgeCache cache,
    -+            int iconResId, boolean forSavedNetworks) {
    -+        super(context);
    -+        mBadgeCache = cache;
    -+        mAccessPoint = accessPoint;
    -+        mForSavedNetworks = forSavedNetworks;
    -+        mAccessPoint.setTag(this);
    -+        mLevel = -1;
    -+        mDefaultIconResId = iconResId;
    -+
    -+        mWifiSld = (StateListDrawable) context.getTheme()
    -+                .obtainStyledAttributes(wifi_signal_attributes).getDrawable(0);
    -+
    -+        // Distance from the end of the title at which this AP's user badge should sit.
    -+        mBadgePadding = context.getResources()
    -+                .getDimensionPixelSize(R.dimen.wifi_preference_badge_padding);
    -+    }
    -+
    -     public AccessPoint getAccessPoint() {
    -         return mAccessPoint;
    -     }
    -@@ -112,7 +130,7 @@ public class AccessPointPreference extends Preference {
    - 
    -     protected void updateIcon(int level, Context context) {
    -         if (level == -1) {
    --            setIcon(null);
    -+            safeSetDefaultIcon();
    -         } else {
    -             if (getIcon() == null) {
    -                 // To avoid a drawing race condition, we first set the state (SECURE/NONE) and then
    -@@ -124,16 +142,24 @@ public class AccessPointPreference extends Preference {
    -                             ? STATE_SECURED
    -                             : STATE_NONE);
    -                     Drawable drawable = mWifiSld.getCurrent();
    --                    if (!mForSavedNetworks) {
    -+                    if (!mForSavedNetworks && drawable != null) {
    -                         setIcon(drawable);
    --                    } else {
    --                        setIcon(null);
    -+                        return;
    -                     }
    -                 }
    -+                safeSetDefaultIcon();
    -             }
    -         }
    -     }
    - 
    -+    private void safeSetDefaultIcon() {
    -+        if (mDefaultIconResId != 0) {
    -+            setIcon(mDefaultIconResId);
    -+        } else {
    -+            setIcon(null);
    -+        }
    -+    }
    -+
    -     protected void updateBadge(Context context) {
    -         WifiConfiguration config = mAccessPoint.getConfig();
    -         if (config != null) {
    -diff --git a/packages/SettingsProvider/res/values/defaults.xml b/packages/SettingsProvider/res/values/defaults.xml
    -index f7e9541..cd2d6b3 100644
    ---- a/packages/SettingsProvider/res/values/defaults.xml
    -+++ b/packages/SettingsProvider/res/values/defaults.xml
    -@@ -36,7 +36,7 @@
    -     <fraction name="def_window_transition_scale">100%</fraction>
    -     <bool name="def_haptic_feedback">true</bool>
    - 
    --    <bool name="def_bluetooth_on">false</bool>
    -+    <bool name="def_bluetooth_on">true</bool>
    -     <bool name="def_wifi_display_on">false</bool>
    -     <bool name="def_install_non_market_apps">false</bool>
    -     <bool name="def_package_verifier_enable">true</bool>
    -diff --git a/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java b/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java
    -index 7338a9c..c1a1f84 100644
    ---- a/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java
    -+++ b/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java
    -@@ -1483,7 +1483,6 @@ class DatabaseHelper extends SQLiteOpenHelper {
    -                             Settings.Global.CALL_AUTO_RETRY,
    -                             Settings.Global.DEBUG_APP,
    -                             Settings.Global.WAIT_FOR_DEBUGGER,
    --                            Settings.Global.SHOW_PROCESSES,
    -                             Settings.Global.ALWAYS_FINISH_ACTIVITIES,
    -                     };
    -                     String[] secureToGlobal = {
    -diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
    -index 0f7fe6f..d751895 100644
    ---- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
    -+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
    -@@ -114,7 +114,7 @@ import java.util.regex.Pattern;
    - public class SettingsProvider extends ContentProvider {
    -     private static final boolean DEBUG = false;
    - 
    --    private static final boolean DROP_DATABASE_ON_MIGRATION = !Build.IS_DEBUGGABLE;
    -+    private static final boolean DROP_DATABASE_ON_MIGRATION = true;
    - 
    -     private static final String LOG_TAG = "SettingsProvider";
    - 
    -@@ -2102,7 +2102,7 @@ public class SettingsProvider extends ContentProvider {
    -         }
    - 
    -         private final class UpgradeController {
    --            private static final int SETTINGS_VERSION = 130;
    -+            private static final int SETTINGS_VERSION = 131;
    - 
    -             private final int mUserId;
    - 
    -@@ -2142,6 +2142,12 @@ public class SettingsProvider extends ContentProvider {
    - 
    -                     // Now upgrade should work fine.
    -                     onUpgradeLocked(mUserId, oldVersion, newVersion);
    -+
    -+                    // Make a note what happened, so we don't wonder why data was lost
    -+                    String reason = "Settings rebuilt! Current version: "
    -+                            + curVersion + " while expected: " + newVersion;
    -+                    getGlobalSettingsLocked().insertSettingLocked(
    -+                            Settings.Global.DATABASE_DOWNGRADE_REASON, reason, "android");
    -                 }
    - 
    -                 // Set the global settings version if owner.
    -@@ -2410,8 +2416,23 @@ public class SettingsProvider extends ContentProvider {
    -                     currentVersion = 130;
    -                 }
    - 
    -+                if (currentVersion == 130) {
    -+                    // Split Ambient settings
    -+                    final SettingsState secureSettings = getSecureSettingsLocked(userId);
    -+                    boolean dozeExplicitlyDisabled = "0".equals(secureSettings.
    -+                            getSettingLocked(Settings.Secure.DOZE_ENABLED).getValue());
    -+
    -+                    if (dozeExplicitlyDisabled) {
    -+                        secureSettings.insertSettingLocked(Settings.Secure.DOZE_PULSE_ON_PICK_UP,
    -+                                "0", SettingsState.SYSTEM_PACKAGE_NAME);
    -+                        secureSettings.insertSettingLocked(Settings.Secure.DOZE_PULSE_ON_DOUBLE_TAP,
    -+                                "0", SettingsState.SYSTEM_PACKAGE_NAME);
    -+                    }
    -+                    currentVersion = 131;
    -+                }
    -+
    -                 if (currentVersion != newVersion) {
    --                    Slog.w("SettingsProvider", "warning: upgrading settings database to version "
    -+                    Slog.wtf("SettingsProvider", "warning: upgrading settings database to version "
    -                             + newVersion + " left it at "
    -                             + currentVersion + " instead; this is probably a bug", new Throwable());
    -                     if (DEBUG) {
    -diff --git a/packages/Shell/Android.mk b/packages/Shell/Android.mk
    -index 73a0449..81ab2ff 100644
    ---- a/packages/Shell/Android.mk
    -+++ b/packages/Shell/Android.mk
    -@@ -12,6 +12,8 @@ LOCAL_PACKAGE_NAME := Shell
    - LOCAL_CERTIFICATE := platform
    - LOCAL_PRIVILEGED_MODULE := true
    - 
    -+LOCAL_JACK_COVERAGE_INCLUDE_FILTER := com.android.shell.*
    -+
    - include $(BUILD_PACKAGE)
    - 
    - include $(LOCAL_PATH)/tests/Android.mk
    -diff --git a/packages/Shell/AndroidManifest.xml b/packages/Shell/AndroidManifest.xml
    -index f1789ea..227d0e9 100644
    ---- a/packages/Shell/AndroidManifest.xml
    -+++ b/packages/Shell/AndroidManifest.xml
    -@@ -114,6 +114,8 @@
    -     <uses-permission android:name="android.permission.CHANGE_COMPONENT_ENABLED_STATE" />
    -     <!-- Permission needed to rename bugreport notifications (so they're not shown as Shell) -->
    -     <uses-permission android:name="android.permission.SUBSTITUTE_NOTIFICATION_APP_NAME" />
    -+    <!-- Permission needed to hold a wakelock in dumpstate.cpp (drop_root_user()) -->
    -+    <uses-permission android:name="android.permission.WAKE_LOCK" />
    - 
    -     <application android:label="@string/app_label"
    -                  android:defaultToDeviceProtectedStorage="true"
    -diff --git a/packages/Shell/src/com/android/shell/BugreportStorageProvider.java b/packages/Shell/src/com/android/shell/BugreportStorageProvider.java
    -index 8b07599..9fd80d3 100644
    ---- a/packages/Shell/src/com/android/shell/BugreportStorageProvider.java
    -+++ b/packages/Shell/src/com/android/shell/BugreportStorageProvider.java
    -@@ -132,6 +132,7 @@ public class BugreportStorageProvider extends DocumentsProvider {
    -         if (!getFileForDocId(documentId).delete()) {
    -             throw new FileNotFoundException("Failed to delete: " + documentId);
    -         }
    -+        getContext().getContentResolver().notifyChange(getNotificationUri(), null);
    -     }
    - 
    -     // This is used by BugreportProgressService so that the notification uri shared by
    -diff --git a/packages/SystemUI/AndroidManifest.xml b/packages/SystemUI/AndroidManifest.xml
    -index bdb103a..a74fbf8 100644
    ---- a/packages/SystemUI/AndroidManifest.xml
    -+++ b/packages/SystemUI/AndroidManifest.xml
    -@@ -150,9 +150,6 @@
    -     <!-- DevicePolicyManager get user restrictions -->
    -     <uses-permission android:name="android.permission.MANAGE_PROFILE_AND_DEVICE_OWNERS" />
    - 
    --    <!-- Needed for passing extras with intent ACTION_SHOW_ADMIN_SUPPORT_DETAILS -->
    --    <uses-permission android:name="android.permission.MANAGE_DEVICE_ADMINS" />
    --
    -     <!-- TV picture-in-picture -->
    -     <uses-permission android:name="android.permission.RECEIVE_MEDIA_RESOURCE_USAGE" />
    - 
    -@@ -216,19 +213,10 @@
    -             </intent-filter>
    -         </receiver>
    - 
    --        <service android:name=".LoadAverageService"
    --                android:exported="true" />
    --
    -         <service android:name=".ImageWallpaper"
    -                 android:permission="android.permission.BIND_WALLPAPER"
    -                 android:exported="true" />
    - 
    --        <receiver android:name=".BootReceiver" androidprv:systemUserOnly="true">
    --            <intent-filter android:priority="1000">
    --                <action android:name="android.intent.action.BOOT_COMPLETED" />
    --            </intent-filter>
    --        </receiver>
    --
    -         <activity android:name=".tuner.TunerActivity"
    -                   android:enabled="false"
    -                   android:icon="@drawable/tuner"
    -diff --git a/packages/SystemUI/res/drawable-nodpi/play.xml b/packages/SystemUI/res/drawable-nodpi/play.xml
    -index 747e60b..7720230 100644
    ---- a/packages/SystemUI/res/drawable-nodpi/play.xml
    -+++ b/packages/SystemUI/res/drawable-nodpi/play.xml
    -@@ -21,7 +21,4 @@ Copyright (C) 2015 The Android Open Source Project
    -     <path
    -         android:fillColor="#FF000000"
    -         android:pathData="M8.0,5.0l0.0,14.0l11.0,-7.0z"/>
    --    <path
    --        android:pathData="M0 0h24v24H0z"
    --        android:fillColor="#00000000"/>
    - </vector>
    -diff --git a/packages/SystemUI/res/drawable/car_ic_arrow.xml b/packages/SystemUI/res/drawable/car_ic_arrow.xml
    -index 9d292cc..2c5ad27 100644
    ---- a/packages/SystemUI/res/drawable/car_ic_arrow.xml
    -+++ b/packages/SystemUI/res/drawable/car_ic_arrow.xml
    -@@ -21,7 +21,4 @@
    -     <path
    -         android:fillColor="#FFFFFFFF"
    -         android:pathData="M14.0,20.0l10.0,10.0 10.0,-10.0z"/>
    --    <path
    --        android:pathData="M0 0h48v48H0z"
    --        android:fillColor="#00000000"/>
    - </vector>
    -diff --git a/packages/SystemUI/res/drawable/ic_fullscreen_white_24dp.xml b/packages/SystemUI/res/drawable/ic_fullscreen_white_24dp.xml
    -index 7ddb40c..314a25a 100644
    ---- a/packages/SystemUI/res/drawable/ic_fullscreen_white_24dp.xml
    -+++ b/packages/SystemUI/res/drawable/ic_fullscreen_white_24dp.xml
    -@@ -18,9 +18,6 @@ Copyright (C) 2016 The Android Open Source Project
    -     android:height="24dp"
    -     android:viewportWidth="24"
    -     android:viewportHeight="24">
    --
    --    <path
    --        android:pathData="M0 0h24v24H0z" />
    -     <path
    -         android:fillColor="#FFFFFF"
    -         android:pathData="M7 14H5v5h5v-2H7v-3zm-2-4h2V7h3V5H5v5zm12 7h-3v2h5v-5h-2v3zM14 5v2h3v3h2V5h-5z" />
    -diff --git a/packages/SystemUI/res/drawable/ic_ksh_key_backspace.xml b/packages/SystemUI/res/drawable/ic_ksh_key_backspace.xml
    -index 6519673..1183203 100644
    ---- a/packages/SystemUI/res/drawable/ic_ksh_key_backspace.xml
    -+++ b/packages/SystemUI/res/drawable/ic_ksh_key_backspace.xml
    -@@ -19,7 +19,6 @@
    -         android:height="24dp"
    -         android:viewportWidth="24"
    -         android:viewportHeight="24">
    --    <path android:pathData="M0 0h24v24H0z" />
    -     <path android:fillColor="@color/ksh_key_item_color"
    -             android:pathData="M22 3H7c-.69 0-1.23 .35 -1.59 .88 L0 12l5.41 8.11c.36 .53 .9 .89
    - 1.59 .89 h15c1.1 0 2-.9 2-2V5c0-1.1-.9-2-2-2zm-3 12.59L17.59 17 14 13.41 10.41 17 9 15.59
    -diff --git a/packages/SystemUI/res/drawable/ic_ksh_key_enter.xml b/packages/SystemUI/res/drawable/ic_ksh_key_enter.xml
    -index 599f350..66b1307 100644
    ---- a/packages/SystemUI/res/drawable/ic_ksh_key_enter.xml
    -+++ b/packages/SystemUI/res/drawable/ic_ksh_key_enter.xml
    -@@ -19,7 +19,6 @@
    -         android:height="24dp"
    -         android:viewportWidth="24"
    -         android:viewportHeight="24">
    --    <path android:pathData="M0 0h24v24H0z" />
    -    <path android:fillColor="@color/ksh_key_item_color"
    -             android:pathData="M19 7v4H5.83l3.58-3.59L8 6l-6 6 6 6 1.41-1.41L5.83 13H21V7z" />
    - </vector>
    -diff --git a/packages/SystemUI/res/drawable/ic_ksh_key_left.xml b/packages/SystemUI/res/drawable/ic_ksh_key_left.xml
    -index 038187e..57d0423 100644
    ---- a/packages/SystemUI/res/drawable/ic_ksh_key_left.xml
    -+++ b/packages/SystemUI/res/drawable/ic_ksh_key_left.xml
    -@@ -21,5 +21,4 @@
    -         android:viewportHeight="24">
    -     <path android:fillColor="@color/ksh_key_item_color"
    -             android:pathData="M15.41 7.41L14 6l-6 6 6 6 1.41-1.41L10.83 12z" />
    --    <path android:pathData="M0 0h24v24H0z" />
    - </vector>
    -diff --git a/packages/SystemUI/res/drawable/ic_ksh_key_meta.xml b/packages/SystemUI/res/drawable/ic_ksh_key_meta.xml
    -index 1e2195e..be8fe8c 100644
    ---- a/packages/SystemUI/res/drawable/ic_ksh_key_meta.xml
    -+++ b/packages/SystemUI/res/drawable/ic_ksh_key_meta.xml
    -@@ -24,5 +24,4 @@
    - 3 9.5 5.91 16 9.5 16c1.61 0 3.09-.59 4.23-1.57l.27 .28 v.79l5 4.99L20.49
    - 19l-4.99-5zm-6 0C7.01 14 5 11.99 5 9.5S7.01 5 9.5 5 14 7.01 14 9.5 11.99 14 9.5
    - 14z" />
    --    <path android:pathData="M0 0h24v24H0z" />
    - </vector>
    -diff --git a/packages/SystemUI/res/drawable/ic_ksh_key_right.xml b/packages/SystemUI/res/drawable/ic_ksh_key_right.xml
    -index f2d7315..720d4e4 100644
    ---- a/packages/SystemUI/res/drawable/ic_ksh_key_right.xml
    -+++ b/packages/SystemUI/res/drawable/ic_ksh_key_right.xml
    -@@ -21,5 +21,4 @@
    -         android:viewportHeight="24">
    -     <path android:fillColor="@color/ksh_key_item_color"
    -             android:pathData="M10 6L8.59 7.41 13.17 12l-4.58 4.59L10 18l6-6z" />
    --    <path android:pathData="M0 0h24v24H0z" />
    - </vector>
    -diff --git a/packages/SystemUI/res/drawable/ic_ksh_key_up.xml b/packages/SystemUI/res/drawable/ic_ksh_key_up.xml
    -index 36a83b1..350c994 100644
    ---- a/packages/SystemUI/res/drawable/ic_ksh_key_up.xml
    -+++ b/packages/SystemUI/res/drawable/ic_ksh_key_up.xml
    -@@ -21,5 +21,4 @@
    -         android:viewportHeight="24">
    -     <path android:fillColor="@color/ksh_key_item_color"
    -             android:pathData="M7.41 15.41L12 10.83l4.59 4.58L18 14l-6-6-6 6z" />
    --    <path android:pathData="M0 0h24v24H0z" />
    - </vector>
    -diff --git a/packages/SystemUI/res/drawable/ic_pause_white_24dp.xml b/packages/SystemUI/res/drawable/ic_pause_white_24dp.xml
    -index d9a4f7b..5b65f10 100644
    ---- a/packages/SystemUI/res/drawable/ic_pause_white_24dp.xml
    -+++ b/packages/SystemUI/res/drawable/ic_pause_white_24dp.xml
    -@@ -22,6 +22,4 @@ Copyright (C) 2016 The Android Open Source Project
    -     <path
    -         android:fillColor="#FFFFFF"
    -         android:pathData="M6 19h4V5H6v14zm8-14v14h4V5h-4z" />
    --    <path
    --        android:pathData="M0 0h24v24H0z" />
    - </vector>
    -diff --git a/packages/SystemUI/res/drawable/ic_play_arrow_white_24dp.xml b/packages/SystemUI/res/drawable/ic_play_arrow_white_24dp.xml
    -index b8fa99e..ddc9e8d 100644
    ---- a/packages/SystemUI/res/drawable/ic_play_arrow_white_24dp.xml
    -+++ b/packages/SystemUI/res/drawable/ic_play_arrow_white_24dp.xml
    -@@ -22,6 +22,4 @@ Copyright (C) 2016 The Android Open Source Project
    -     <path
    -         android:fillColor="#FFFFFF"
    -         android:pathData="M8 5v14l11-7z" />
    --    <path
    --        android:pathData="M0 0h24v24H0z" />
    - </vector>
    -diff --git a/packages/SystemUI/res/drawable/ic_qs_data_disabled.xml b/packages/SystemUI/res/drawable/ic_qs_data_disabled.xml
    -index b4144a3..d11b6f4 100644
    ---- a/packages/SystemUI/res/drawable/ic_qs_data_disabled.xml
    -+++ b/packages/SystemUI/res/drawable/ic_qs_data_disabled.xml
    -@@ -14,8 +14,9 @@
    -     limitations under the License.
    - -->
    - <vector xmlns:android="http://schemas.android.com/apk/res/android"
    --        android:width="24.0dp"
    --        android:height="24.0dp"
    -+        android:autoMirrored="true"
    -+        android:width="32.0dp"
    -+        android:height="32.0dp"
    -         android:viewportWidth="40.0"
    -         android:viewportHeight="40.0">
    -     <path
    -diff --git a/packages/SystemUI/res/drawable/ic_qs_wifi_disconnected.xml b/packages/SystemUI/res/drawable/ic_qs_wifi_disconnected.xml
    -index 4d2a35e..2dcdb71 100644
    ---- a/packages/SystemUI/res/drawable/ic_qs_wifi_disconnected.xml
    -+++ b/packages/SystemUI/res/drawable/ic_qs_wifi_disconnected.xml
    -@@ -19,9 +19,6 @@
    -         android:viewportWidth="26.0"
    -         android:viewportHeight="24.0">
    -     <path
    --        android:pathData="M0 0h26v24H0z"
    --        android:fillColor="#00000000"/>
    --    <path
    -         android:fillColor="#FFFFFFFF"
    -         android:pathData="M21.0,8.5
    -         c0.85,0.0 1.6,0.23 2.3,0.62l2.24,-2.79
    -diff --git a/packages/SystemUI/res/drawable/ic_send.xml b/packages/SystemUI/res/drawable/ic_send.xml
    -index 6ce3672..7cac2a4 100644
    ---- a/packages/SystemUI/res/drawable/ic_send.xml
    -+++ b/packages/SystemUI/res/drawable/ic_send.xml
    -@@ -22,7 +22,4 @@ Copyright (C) 2014 The Android Open Source Project
    -     <path
    -         android:fillColor="#FF000000"
    -         android:pathData="M4.02,42.0L46.0,24.0 4.02,6.0 4.0,20.0l30.0,4.0 -30.0,4.0z"/>
    --    <path
    --        android:pathData="M0 0h48v48H0z"
    --        android:fillColor="#00000000"/>
    - </vector>
    -diff --git a/packages/SystemUI/res/drawable/stat_sys_data_disabled.xml b/packages/SystemUI/res/drawable/stat_sys_data_disabled.xml
    -index 4e2a024..694019e 100644
    ---- a/packages/SystemUI/res/drawable/stat_sys_data_disabled.xml
    -+++ b/packages/SystemUI/res/drawable/stat_sys_data_disabled.xml
    -@@ -14,9 +14,9 @@
    -     limitations under the License.
    - -->
    - <vector xmlns:android="http://schemas.android.com/apk/res/android"
    --        android:width="17.0dp"
    -+        android:width="8.5dp"
    -         android:height="17.0dp"
    --        android:viewportWidth="40.0"
    -+        android:viewportWidth="20.0"
    -         android:viewportHeight="40.0">
    -     <path
    -         android:fillColor="#FFFFFFFF"
    -diff --git a/packages/SystemUI/res/layout/emergency_cryptkeeper_text.xml b/packages/SystemUI/res/layout/emergency_cryptkeeper_text.xml
    -new file mode 100644
    -index 0000000..0a1730a
    ---- /dev/null
    -+++ b/packages/SystemUI/res/layout/emergency_cryptkeeper_text.xml
    -@@ -0,0 +1,28 @@
    -+<?xml version="1.0" encoding="utf-8"?>
    -+<!--
    -+  ~ Copyright (C) 2016 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
    -+  -->
    -+
    -+<com.android.systemui.statusbar.policy.EmergencyCryptkeeperText
    -+        xmlns:android="http://schemas.android.com/apk/res/android"
    -+        android:id="@+id/emergency_cryptkeeper_text"
    -+        android:layout_width="wrap_content"
    -+        android:layout_height="match_parent"
    -+        android:textAppearance="@style/TextAppearance.StatusBar.Clock"
    -+        android:paddingStart="6dp"
    -+        android:singleLine="true"
    -+        android:ellipsize="marquee"
    -+        android:gravity="center_vertical|start"
    -+        />
    -\ No newline at end of file
    -diff --git a/packages/SystemUI/res/layout/notification_guts.xml b/packages/SystemUI/res/layout/notification_guts.xml
    -index e84ed23..17bade4 100644
    ---- a/packages/SystemUI/res/layout/notification_guts.xml
    -+++ b/packages/SystemUI/res/layout/notification_guts.xml
    -@@ -91,6 +91,16 @@
    -                 style="@style/TextAppearance.NotificationGuts.Radio"
    -                 android:buttonTint="@color/notification_guts_buttons" />
    -     </RadioGroup>
    -+    <!-- When neither blocking or silencing is available -->
    -+    <TextView
    -+        android:id="@+id/cant_silence_or_block"
    -+        android:layout_width="match_parent"
    -+        android:layout_height="48dp"
    -+        android:gravity="center_vertical"
    -+        style="@style/TextAppearance.NotificationGuts.Radio"
    -+        android:text="@string/cant_silence_or_block"
    -+        android:visibility="gone"
    -+        />
    -     <!-- Importance slider -->
    -     <LinearLayout
    -             android:id="@+id/importance_slider"
    -diff --git a/packages/SystemUI/res/layout/recents_task_view.xml b/packages/SystemUI/res/layout/recents_task_view.xml
    -index 1978a93..c8e5b61 100644
    ---- a/packages/SystemUI/res/layout/recents_task_view.xml
    -+++ b/packages/SystemUI/res/layout/recents_task_view.xml
    -@@ -30,8 +30,8 @@
    -         android:id="@+id/lock_to_app_fab"
    -         android:layout_width="@dimen/recents_lock_to_app_size"
    -         android:layout_height="@dimen/recents_lock_to_app_size"
    --        android:layout_gravity="bottom|right"
    --        android:layout_marginRight="15dp"
    -+        android:layout_gravity="bottom|end"
    -+        android:layout_marginEnd="15dp"
    -         android:layout_marginBottom="15dp"
    -         android:translationZ="4dp"
    -         android:contentDescription="@string/recents_lock_to_app_button_label"
    -diff --git a/packages/SystemUI/res/layout/remote_input.xml b/packages/SystemUI/res/layout/remote_input.xml
    -index f0c4e59..73f26e2 100644
    ---- a/packages/SystemUI/res/layout/remote_input.xml
    -+++ b/packages/SystemUI/res/layout/remote_input.xml
    -@@ -42,7 +42,7 @@
    -             android:singleLine="true"
    -             android:ellipsize="start"
    -             android:inputType="textShortMessage|textAutoCorrect|textCapSentences"
    --            android:imeOptions="actionNone|flagNoExtractUi" />
    -+            android:imeOptions="actionNone|flagNoExtractUi|flagNoFullscreen" />
    - 
    -     <FrameLayout
    -             android:layout_width="wrap_content"
    -diff --git a/packages/SystemUI/res/layout/status_bar.xml b/packages/SystemUI/res/layout/status_bar.xml
    -index 39c16d7..63af3e0 100644
    ---- a/packages/SystemUI/res/layout/status_bar.xml
    -+++ b/packages/SystemUI/res/layout/status_bar.xml
    -@@ -77,4 +77,11 @@
    -         </com.android.keyguard.AlphaOptimizedLinearLayout>
    -     </LinearLayout>
    - 
    -+    <ViewStub
    -+        android:id="@+id/emergency_cryptkeeper_text"
    -+        android:layout_width="wrap_content"
    -+        android:layout_height="match_parent"
    -+        android:layout="@layout/emergency_cryptkeeper_text"
    -+    />
    -+
    - </com.android.systemui.statusbar.phone.PhoneStatusBarView>
    -diff --git a/packages/SystemUI/res/values-af/strings.xml b/packages/SystemUI/res/values-af/strings.xml
    -index 546698c..fbd523f 100644
    ---- a/packages/SystemUI/res/values-af/strings.xml
    -+++ b/packages/SystemUI/res/values-af/strings.xml
    -@@ -238,7 +238,7 @@
    -     <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"4G-data is laat wag"</string>
    -     <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"Sellulêre data is onderbreek"</string>
    -     <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"Data is onderbreek"</string>
    --    <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"Omdat die gestelde dataperk bereik is, het die toestel datagebruik vir die res van hierdie siklus onderbreek.\n\nAs dit hervat word, kan dit tot heffings deur jou diensverskaffer lei."</string>
    -+    <string name="data_usage_disabled_dialog" msgid="1841738975235283398">"Jy het die datalimiet wat jy gestel het, bereik. Jy gebruik nie meer sellulêre data nie.\n\nAs jy voortgaan, kan heffings vir datagebruik geld."</string>
    -     <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"Hervat"</string>
    -     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Geen internetverbinding nie"</string>
    -     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi gekoppel"</string>
    -@@ -404,6 +404,7 @@
    -     <string name="device_owned_footer" msgid="3802752663326030053">"Toestel kan gemonitor word"</string>
    -     <string name="profile_owned_footer" msgid="8021888108553696069">"Profiel kan gemonitor word"</string>
    -     <string name="vpn_footer" msgid="2388611096129106812">"Netwerk kan dalk gemonitor word"</string>
    -+    <string name="branded_vpn_footer" msgid="2168111859226496230">"Netwerk kan dalk gemonitor word"</string>
    -     <string name="monitoring_title_device_owned" msgid="7121079311903859610">"Toestelmonitering"</string>
    -     <string name="monitoring_title_profile_owned" msgid="6790109874733501487">"Profielmonitering"</string>
    -     <string name="monitoring_title" msgid="169206259253048106">"Netwerkmonitering"</string>
    -@@ -416,6 +417,7 @@
    -     <string name="legacy_vpn_name" msgid="6604123105765737830">"VPN"</string>
    -     <string name="monitoring_description_app" msgid="6259179342284742878">"Jy is gekoppel aan <xliff:g id="APPLICATION">%1$s</xliff:g>, wat jou netwerkaktiwiteit, insluitend e-posse, programme en webwerwe, kan monitor."</string>
    -     <string name="monitoring_description_app_personal" msgid="484599052118316268">"Jy is gekoppel aan <xliff:g id="APPLICATION">%1$s</xliff:g>, wat jou persoonlike netwerkaktiwiteit, insluitend e-posse, programme en webwerwe, kan monitor."</string>
    -+    <string name="branded_monitoring_description_app_personal" msgid="2669518213949202599">"Jy is gekoppel aan <xliff:g id="APPLICATION">%1$s</xliff:g>, wat jou persoonlike netwerkaktiwiteit, insluitend e-posse, programme en webwerwe, kan monitor."</string>
    -     <string name="monitoring_description_app_work" msgid="1754325860918060897">"Jou werkprofiel word deur <xliff:g id="ORGANIZATION">%1$s</xliff:g> bestuur. Dit is gekoppel aan <xliff:g id="APPLICATION">%2$s</xliff:g>, wat jou werknetwerkaktiwiteit, insluitend e-posse, programme en webwerwe, kan monitor.\n\nKontak jou administrateur vir meer inligting."</string>
    -     <string name="monitoring_description_app_personal_work" msgid="4946600443852045903">"Jou werkprofiel word deur <xliff:g id="ORGANIZATION">%1$s</xliff:g> bestuur. Dit is gekoppel aan <xliff:g id="APPLICATION_WORK">%2$s</xliff:g>, wat jou werknetwerkaktiwiteit, insluitend e-posse, programme en webwerwe, kan monitor.\n\nJy is ook gekoppel aan <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g>, wat jou persoonlike netwerkaktiwiteit kan monitor."</string>
    -     <string name="monitoring_description_vpn_app_device_owned" msgid="4970443827043261703">"Jou toestel word bestuur deur <xliff:g id="ORGANIZATION">%1$s</xliff:g>\n\nJou administrateur kan instelings, korporatiewe toegang, programme, data wat met jou toestel geassosieer word en jou toestel se ligginginligting monitor en bestuur.\n\nJy is gekoppel aan <xliff:g id="APPLICATION">%2$s</xliff:g>, wat jou netwerkaktiwiteit, insluitend e-posse, programme en webwerwe, kan monitor.\n\nVir meer inligting, kontak jou administrateur."</string>
    -@@ -492,8 +494,6 @@
    -     <string name="clock_seconds_desc" msgid="6282693067130470675">"Wys horlosiesekondes op die statusbalk. Sal batterylewe dalk beïnvloed."</string>
    -     <string name="qs_rearrange" msgid="8060918697551068765">"Herrangskik Kitsinstellings"</string>
    -     <string name="show_brightness" msgid="6613930842805942519">"Wys helderheid in Kitsinstellings"</string>
    --    <string name="overview_nav_bar_gesture" msgid="8579814204727917764">"Aktiveer die verdeling van die skerm deur op te swiep"</string>
    --    <string name="overview_nav_bar_gesture_desc" msgid="6329167382305102615">"Aktiveer gebaar om skerm te verdeel deur van die Oorsig-knoppie af op te swiep"</string>
    -     <string name="experimental" msgid="6198182315536726162">"Eksperimenteel"</string>
    -     <string name="enable_bluetooth_title" msgid="5027037706500635269">"Skakel Bluetooth aan?"</string>
    -     <string name="enable_bluetooth_message" msgid="9106595990708985385">"Jy moet Bluetooth aanskakel om jou sleutelbord aan jou tablet te koppel."</string>
    -@@ -651,4 +651,5 @@
    -     <string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"Maak <xliff:g id="ID_1">%s</xliff:g>-instellings oop."</string>
    -     <string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"Wysig volgorde van instellings."</string>
    -     <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"Bladsy <xliff:g id="ID_1">%1$d</xliff:g> van <xliff:g id="ID_2">%2$d</xliff:g>"</string>
    -+    <string name="cant_silence_or_block" msgid="999689262131488625">"Kennisgewings kan nie stilgemaak of geblokkeer word nie"</string>
    - </resources>
    -diff --git a/packages/SystemUI/res/values-am/strings.xml b/packages/SystemUI/res/values-am/strings.xml
    -index bd4afe1..98f09f4 100644
    ---- a/packages/SystemUI/res/values-am/strings.xml
    -+++ b/packages/SystemUI/res/values-am/strings.xml
    -@@ -238,7 +238,7 @@
    -     <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"4ጂ ውሂብ ላፍታ ቆሟል"</string>
    -     <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"የተንቀሳቃሽ ስልክ ውሂብ ላፍታ ቆሟል"</string>
    -     <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"ውሂብ ላፍታ ቆሟል"</string>
    --    <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"የእርስዎ የተዋቀረው የውሂብ ገደብ ላይ ስለተደረሰ፣ የዚህን ዑደት አጠቃቀም ለማስታወስ መሣሪያው ላፍታ ቆሟል።\n\nከቆመበት ማስቀጠሉ ከእርስዎ የአገልግሎት አቅራቢ ክፍያን ሊያስጠይቅዎት ይችላል።"</string>
    -+    <string name="data_usage_disabled_dialog" msgid="1841738975235283398">"እርስዎ ያስቀመጡት የውሂብ ገደብ ላይ ተደርሷል። ከእንግዲህ ተንቀሳቃሽ ውሂብ እየተጠቀሙ አይደለም ያሉት።\n\nከቆመበት ከቀጠሉ የውሂብ አጠቃቀም ክፍያዎች ተፈጻሚ ሊሆኑ ይችላሉ።"</string>
    -     <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"ከቆመበት ቀጥል"</string>
    -     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"ምንም በይነመረብ ተያያዥ የለም።"</string>
    -     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi ተያይዟል"</string>
    -@@ -404,6 +404,7 @@
    -     <string name="device_owned_footer" msgid="3802752663326030053">"መሣሪያው ክትትል የሚደረግበት ሊሆን ይችላል"</string>
    -     <string name="profile_owned_footer" msgid="8021888108553696069">"መገለጫ ክትትል ሊደረግበት ይችላል"</string>
    -     <string name="vpn_footer" msgid="2388611096129106812">"አውታረ መረብ በክትትል እየተደረገበት ሊሆን ይችላል"</string>
    -+    <string name="branded_vpn_footer" msgid="2168111859226496230">"አውታረ መረብ ክትትል የሚደረግበት ሊሆን ይችላል"</string>
    -     <string name="monitoring_title_device_owned" msgid="7121079311903859610">"የመሣሪያ ክትትል"</string>
    -     <string name="monitoring_title_profile_owned" msgid="6790109874733501487">"መገለጫን መከታተል"</string>
    -     <string name="monitoring_title" msgid="169206259253048106">"የአውታረ መረብ ክትትል"</string>
    -@@ -416,6 +417,7 @@
    -     <string name="legacy_vpn_name" msgid="6604123105765737830">"VPN"</string>
    -     <string name="monitoring_description_app" msgid="6259179342284742878">"እርስዎ ኢሜይሎችን፣ መተግበሪያዎችን እና ድር ጣቢያዎችንም ጨምሮ የአውታረ መረብ እንቅስቃሴዎን መከታተል ከሚችለው <xliff:g id="APPLICATION">%1$s</xliff:g> ጋር ተገናኝተዋል።"</string>
    -     <string name="monitoring_description_app_personal" msgid="484599052118316268">"እርስዎ ኢሜይሎችን፣ መተግበሪያዎችን እና ድር ጣቢያዎችንም ጨምሮ የግል የአውታረ መረብ እንቅስቃሴዎን መከታተል ከሚችለው <xliff:g id="APPLICATION">%1$s</xliff:g> ጋር ተገናኝተዋል።"</string>
    -+    <string name="branded_monitoring_description_app_personal" msgid="2669518213949202599">"እርስዎ ኢሜይሎችን፣ መተግበሪያዎችን እና ድር ጣቢያዎችንም ጨምሮ የግል የአውታረ መረብ እንቅስቃሴዎን ከሚከታተለው ከ<xliff:g id="APPLICATION">%1$s</xliff:g> ጋር ተገናኝተዋል።"</string>
    -     <string name="monitoring_description_app_work" msgid="1754325860918060897">"የስራ መገለጫዎ በ<xliff:g id="ORGANIZATION">%1$s</xliff:g> ነው እየተዳደረ ያለው። ኢሜይሎችን፣ መተግበሪያዎችን እና ድር ጣቢያዎችንም ጨምሮ የአውታረ መረብ እንቅስቃሴዎን መከታተል ከሚችለው <xliff:g id="APPLICATION">%2$s</xliff:g> ጋር ተገናኝተዋል።\n\nተጨማሪ መረጃ ለማግኘት አስተዳዳሪዎን ያነጋግሩ።"</string>
    -     <string name="monitoring_description_app_personal_work" msgid="4946600443852045903">"የስራ መገለጫዎ በ<xliff:g id="ORGANIZATION">%1$s</xliff:g> ነው እየተዳደረ ያለው። ኢሜይሎችን፣ መተግበሪያዎችን እና ድር ጣቢያዎችንም ጨምሮ የአውታረ መረብ እንቅስቃሴዎን መከታተል ከሚችለው <xliff:g id="APPLICATION_WORK">%2$s</xliff:g> ጋር ተገናኝተዋል።\n\nእንዲሁም የግል አውታረ መረብ እንቅስቃሴዎን መከታተል ከሚችለው <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g> ጋርም ተገናኝተዋል።"</string>
    -     <string name="monitoring_description_vpn_app_device_owned" msgid="4970443827043261703">"የእርስዎ መሣሪያ በ<xliff:g id="ORGANIZATION">%1$s</xliff:g> ነው የሚተዳደረው።\n\nየእርስዎ አስተዳዳሪ ቅንብሮችን፣ የኮርፖሬት መዳረሻን፣ መተግበሪያዎችን፣ ከመሣሪያዎ ጋር የተጎዳኘ ውሂብን እና የመሣሪያዎ የአካባቢ መረጃን መከታተል እና ማቀናበር ይችላል።\n\nእርስዎ ኢሜይሎችን፣ መተግበሪያዎችን እና ድር ጣቢያዎችን  ጨምሮ የአውታረ መረብ እንቅስቃሴዎን መከታተል ከሚችለው <xliff:g id="APPLICATION">%2$s</xliff:g> ጋር ተገናኝተዋል።\n\nተጨማሪ መረጃ ለማግኘት አስተዳዳሪዎን ያነጋግሩ።"</string>
    -@@ -492,8 +494,6 @@
    -     <string name="clock_seconds_desc" msgid="6282693067130470675">"የሰዓት ሰከንዶችን በሁኔታ አሞሌ ውስጥ አሳይ። በባትሪ ዕድሜ ላይ ተጽዕኖ ሊኖርው ይችል ይሆናል።"</string>
    -     <string name="qs_rearrange" msgid="8060918697551068765">"ፈጣን ቅንብሮችን ዳግም ያደራጁ"</string>
    -     <string name="show_brightness" msgid="6613930842805942519">"በፈጣን ቅንብሮች ውስጥ ብሩህነትን አሳይ"</string>
    --    <string name="overview_nav_bar_gesture" msgid="8579814204727917764">"የተከፈለ ማያ ገጽ ወደ ላይ የማንሸራተት ጣት ምልክትን ያንቁ"</string>
    --    <string name="overview_nav_bar_gesture_desc" msgid="6329167382305102615">"ከአጠቃላይ እይታ አዝራሩ ወደ ላይ በማንሸራተት ወደ የተከፈለ ማያ ገጽ የሚገቡበትን የጣት ምልክት ያንቁ"</string>
    -     <string name="experimental" msgid="6198182315536726162">"የሙከራ"</string>
    -     <string name="enable_bluetooth_title" msgid="5027037706500635269">"ብሉቱዝ ይብራ?"</string>
    -     <string name="enable_bluetooth_message" msgid="9106595990708985385">"የቁልፍ ሰሌዳዎን ከእርስዎ ጡባዊ ጋር ለማገናኘት በመጀመሪያ ብሉቱዝን ማብራት አለብዎት።"</string>
    -@@ -651,4 +651,5 @@
    -     <string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"የ<xliff:g id="ID_1">%s</xliff:g> ቅንብሮችን ክፈት።"</string>
    -     <string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"የቅንብሮድ ቅደም-ተከተል አርትዕ።"</string>
    -     <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"ገጽ <xliff:g id="ID_1">%1$d</xliff:g> ከ <xliff:g id="ID_2">%2$d</xliff:g>"</string>
    -+    <string name="cant_silence_or_block" msgid="999689262131488625">"ማሳወቂያዎች ላይ ድምጸ-ከል ማድረግ ወይም ማገድ አይቻልም"</string>
    - </resources>
    -diff --git a/packages/SystemUI/res/values-ar/strings.xml b/packages/SystemUI/res/values-ar/strings.xml
    -index eca668e..c954e41 100644
    ---- a/packages/SystemUI/res/values-ar/strings.xml
    -+++ b/packages/SystemUI/res/values-ar/strings.xml
    -@@ -242,7 +242,7 @@
    -     <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"تم إيقاف بيانات شبكة الجيل الرابع مؤقتًا"</string>
    -     <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"تم إيقاف بيانات شبكة الجوّال مؤقتًا"</string>
    -     <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"تم إيقاف البيانات مؤقتًا"</string>
    --    <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"نظرًا لأنك بلغت الحد الأقصى المحدد للبيانات، فقد أوقف الجهاز استخدام البيانات مؤقتًا في بقية هذه الدورة.\n\nومن الممكن أن يؤدي الاستئناف إلى تحصيل رسوم من قِبل مشغِّل شبكة الجوّال."</string>
    -+    <string name="data_usage_disabled_dialog" msgid="1841738975235283398">"تم الوصول إلى حد البيانات الذي عيَّنته، ولم يعد بإمكانك استخدام بيانات شبكة الجوّال.\n\nعند الاستئناف، قد يتم تحصيل رسوم مقابل استخدام البيانات."</string>
    -     <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"استئناف"</string>
    -     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"لا يوجد اتصال إنترنت"</string>
    -     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"‏Wi-Fi متصل"</string>
    -@@ -412,6 +412,7 @@
    -     <string name="device_owned_footer" msgid="3802752663326030053">"ربما تتم مراقبة الجهاز"</string>
    -     <string name="profile_owned_footer" msgid="8021888108553696069">"ربما تتم مراقبة الملف الشخصي"</string>
    -     <string name="vpn_footer" msgid="2388611096129106812">"قد تكون الشبكة خاضعة للمراقبة"</string>
    -+    <string name="branded_vpn_footer" msgid="2168111859226496230">"قد تكون الشبكة خاضعة للمراقبة"</string>
    -     <string name="monitoring_title_device_owned" msgid="7121079311903859610">"مراقبة الأجهزة"</string>
    -     <string name="monitoring_title_profile_owned" msgid="6790109874733501487">"مراقبة الملف الشخصي"</string>
    -     <string name="monitoring_title" msgid="169206259253048106">"مراقبة الشبكات"</string>
    -@@ -424,6 +425,7 @@
    -     <string name="legacy_vpn_name" msgid="6604123105765737830">"شبكة ظاهرية خاصة"</string>
    -     <string name="monitoring_description_app" msgid="6259179342284742878">"أنت متصل بـ <xliff:g id="APPLICATION">%1$s</xliff:g>، الذي يمكنه مراقبة أنشطتك على الشبكة، بما في ذلك الرسائل الإلكترونية والتطبيقات ومواقع الويب."</string>
    -     <string name="monitoring_description_app_personal" msgid="484599052118316268">"أنت متصل بـ <xliff:g id="APPLICATION">%1$s</xliff:g>، الذي يمكنه مراقبة أنشطتك الشخصية على الشبكة، بما في ذلك الرسائل الإلكترونية والتطبيقات ومواقع الويب."</string>
    -+    <string name="branded_monitoring_description_app_personal" msgid="2669518213949202599">"أنت متصل بـ <xliff:g id="APPLICATION">%1$s</xliff:g>، الذي يمكنه مراقبة أنشطتك الشخصية على الشبكة، بما في ذلك الرسائل الإلكترونية والتطبيقات ومواقع الويب."</string>
    -     <string name="monitoring_description_app_work" msgid="1754325860918060897">"تتم إدارة ملفك الشخصي للعمل عن طريق <xliff:g id="ORGANIZATION">%1$s</xliff:g>. وهذا الملف الشخصي للعمل متصل بـ <xliff:g id="APPLICATION">%2$s</xliff:g>، الذي يمكنه مراقبة أنشطتك على شبكة العمل، بما في ذلك الرسائل الإلكترونية والتطبيقات ومواقع الويب.\n\nللمزيد من المعلومات، اتصل بالمشرف."</string>
    -     <string name="monitoring_description_app_personal_work" msgid="4946600443852045903">"تتم إدارة ملفك الشخصي للعمل عن طريق <xliff:g id="ORGANIZATION">%1$s</xliff:g>. وهذا الملف الشخصي للعمل متصل بـ <xliff:g id="APPLICATION_WORK">%2$s</xliff:g>، الذي يمكنه مراقبة أنشطتك على شبكة العمل، بما في ذلك الرسائل الإلكترونية والتطبيقات ومواقع الويب.\n\nأنت متصل أيضًا بـ <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g>، الذي يمكنه مراقبة أنشطتك الشخصية على الشبكة."</string>
    -     <string name="monitoring_description_vpn_app_device_owned" msgid="4970443827043261703">"تتم إدارة جهازك عن طريق <xliff:g id="ORGANIZATION">%1$s</xliff:g>.\n\nيمكن للمشرف مراقبة وإدارة كل من الإعدادات والوصول إلى الشركة والتطبيقات والبيانات المرتبطة بجهازك ومعلومات الموقع لجهازك.\n\nأنت متصل بـ <xliff:g id="APPLICATION">%2$s</xliff:g>، الذي يمكنه مراقبة أنشطتك على الشبكة، بما في ذلك الرسائل الإلكترونية والتطبيقات ومواقع الويب.\n\nللمزيد من المعلومات، اتصل بالمشرف."</string>
    -@@ -500,8 +502,6 @@
    -     <string name="clock_seconds_desc" msgid="6282693067130470675">"عرض ثواني الساعة في شريط الحالة. قد يؤثر ذلك في عمر البطارية."</string>
    -     <string name="qs_rearrange" msgid="8060918697551068765">"إعادة ترتيب الإعدادات السريعة"</string>
    -     <string name="show_brightness" msgid="6613930842805942519">"عرض السطوع في الإعدادات السريعة"</string>
    --    <string name="overview_nav_bar_gesture" msgid="8579814204727917764">"تمكين إيماءة تقسيم الشاشة بالتمرير السريع لأعلى"</string>
    --    <string name="overview_nav_bar_gesture_desc" msgid="6329167382305102615">"تمكين الإيماء لإدخال تقسيم الشاشة من خلال التمرير السريع لأعلى من زر النظرة العامة"</string>
    -     <string name="experimental" msgid="6198182315536726162">"إعدادات تجريبية"</string>
    -     <string name="enable_bluetooth_title" msgid="5027037706500635269">"تشغيل البلوتوث؟"</string>
    -     <string name="enable_bluetooth_message" msgid="9106595990708985385">"لتوصيل لوحة المفاتيح بالجهاز اللوحي، يلزمك تشغيل بلوتوث أولاً."</string>
    -@@ -659,4 +659,5 @@
    -     <string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"فتح إعدادات <xliff:g id="ID_1">%s</xliff:g>."</string>
    -     <string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"تعديل ترتيب الإعدادات."</string>
    -     <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"الصفحة <xliff:g id="ID_1">%1$d</xliff:g> من <xliff:g id="ID_2">%2$d</xliff:g>"</string>
    -+    <string name="cant_silence_or_block" msgid="999689262131488625">"لا يمكن كتم صوت الإشعارات أو حظرها"</string>
    - </resources>
    -diff --git a/packages/SystemUI/res/values-az-rAZ/strings.xml b/packages/SystemUI/res/values-az-rAZ/strings.xml
    -index 3d9cc4a..d2f93d2 100644
    ---- a/packages/SystemUI/res/values-az-rAZ/strings.xml
    -+++ b/packages/SystemUI/res/values-az-rAZ/strings.xml
    -@@ -238,7 +238,7 @@
    -     <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"4G məlumatlarına fasilə verildi"</string>
    -     <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"Mobil məlumatlara fasilə verildi"</string>
    -     <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"Məlumatlara fasilə verildi"</string>
    --    <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"Məlumatlar dəsti limitinizi keçdiyiniz üçün cihaz bu dövrənin qalan hissəsi üçün məlumatların istifadəsinə fasilə verib.\n\nDavam etmək operaturunuzdan xərclərə səbəb ola bilər."</string>
    -+    <string name="data_usage_disabled_dialog" msgid="1841738975235283398">"Daha limitini keçdiniz. Artıq mobil data istifadə etmirsiniz.\n\nDavam etsəniz, data istifadəsi üçün ödəniş tətbiq oluna bilər."</string>
    -     <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"Davam et"</string>
    -     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"İnternet bağlantısı yoxdur"</string>
    -     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi qoşulub"</string>
    -@@ -404,6 +404,7 @@
    -     <string name="device_owned_footer" msgid="3802752663326030053">"Cihaz nəzarət altında ola bilər"</string>
    -     <string name="profile_owned_footer" msgid="8021888108553696069">"Profil izlənə bilər"</string>
    -     <string name="vpn_footer" msgid="2388611096129106812">"Şəbəkə nəzərdən keçirilə bilər"</string>
    -+    <string name="branded_vpn_footer" msgid="2168111859226496230">"Şəbəkə nəzərdən keçirilə bilər"</string>
    -     <string name="monitoring_title_device_owned" msgid="7121079311903859610">"Cihaza nəzarət"</string>
    -     <string name="monitoring_title_profile_owned" msgid="6790109874733501487">"Profil izlənməsi"</string>
    -     <string name="monitoring_title" msgid="169206259253048106">"Şəbəkə monitorinqi"</string>
    -@@ -416,6 +417,7 @@
    -     <string name="legacy_vpn_name" msgid="6604123105765737830">"VPN (Virtual Şəxsi Şəbəkələr)"</string>
    -     <string name="monitoring_description_app" msgid="6259179342284742878">"<xliff:g id="APPLICATION">%1$s</xliff:g> tətbiqinə qoşulmusunuz və o, e-məktublar, tətbiq və veb saytlar daxil olmaqla şəbəkə fəaliyyətinizə nəzarət edə bilər."</string>
    -     <string name="monitoring_description_app_personal" msgid="484599052118316268">"<xliff:g id="APPLICATION">%1$s</xliff:g> tətbiqinə qoşulmusunuz və o, e-məktublar, tətbiq və veb saytlar daxil olmaqla şəxsi şəbəkə fəaliyyətinizə nəzarət edə bilər."</string>
    -+    <string name="branded_monitoring_description_app_personal" msgid="2669518213949202599">"<xliff:g id="APPLICATION">%1$s</xliff:g> tətbiqinə qoşulmusunuz və o, e-məktublar, tətbiq və veb saytlar daxil olmaqla şəxsi şəbəkə fəaliyyətinizə nəzarət edə bilər."</string>
    -     <string name="monitoring_description_app_work" msgid="1754325860918060897">"İş profiliniz <xliff:g id="ORGANIZATION">%1$s</xliff:g> tərəfindən idarə olunur. <xliff:g id="APPLICATION">%2$s</xliff:g> tətbiqinə qoşuludur və iş şəbəkə fəaliyyətinizə nəzarət edə bilər, bura e-məktubıar, tətbiq və veb saytlar daxildir.\n\nƏtraflı məlumat üçün administratorunuz ilə əlaqə saxlayın."</string>
    -     <string name="monitoring_description_app_personal_work" msgid="4946600443852045903">"İş profiliniz <xliff:g id="ORGANIZATION">%1$s</xliff:g> tərəfindən idarə olunur. <xliff:g id="APPLICATION_WORK">%2$s</xliff:g> tətbiqinə qoşuludur və iş şəbəkə fəaliyyətinizi idarə edə bilər, bura e-məktubıar, tətbiq və veb saytlar daxildir\n\nSiz, həmçinin, <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g> tətbiqinə də qoşulsunuz və o, şəxsi şəbəkə fəaliyyətinizə nəzarət edə bilər."</string>
    -     <string name="monitoring_description_vpn_app_device_owned" msgid="4970443827043261703">"Sizin cihaz tərəfindən idarə olunur <xliff:g id="ORGANIZATION">%1$s</xliff:g> . \n\n Sizin administrator nəzarət və parametrləri, korporativ giriş, apps, sizin cihaz ilə bağlı məlumat və cihaz yer məlumat idarə edə bilərsiniz. \n\n Siz bağlı olduğunuz <xliff:g id="APPLICATION">%2$s</xliff:g> , E-poçt, apps, və web o cümlədən, şəbəkə fəaliyyətinə nəzarət edə bilər. \n\n Daha ətraflı məlumat üçün, administratora müraciət."</string>
    -@@ -492,8 +494,6 @@
    -     <string name="clock_seconds_desc" msgid="6282693067130470675">"Saatın saniyəsini status panelində göstərin. Batareyaya təsir edə bilər."</string>
    -     <string name="qs_rearrange" msgid="8060918697551068765">"Sürətli Ayarları yenidən tənzimləyin"</string>
    -     <string name="show_brightness" msgid="6613930842805942519">"Sürətli ayarlarda parlaqlılığı göstərin"</string>
    --    <string name="overview_nav_bar_gesture" msgid="8579814204727917764">"Bölünmüş ekran sürüşdürməsi aktiv edin"</string>
    --    <string name="overview_nav_bar_gesture_desc" msgid="6329167382305102615">"Jestlərin icmal düyməsindən yuxarı sürüşdürərək bölünmüş ekrana daxil olmasını aktiv edin"</string>
    -     <string name="experimental" msgid="6198182315536726162">"Eksperimental"</string>
    -     <string name="enable_bluetooth_title" msgid="5027037706500635269">"Bluetooth aktivləşsin?"</string>
    -     <string name="enable_bluetooth_message" msgid="9106595990708985385">"Tabletinizlə klaviaturaya bağlanmaq üçün ilk olaraq Bluetooth\'u aktivləşdirməlisiniz."</string>
    -@@ -651,4 +651,5 @@
    -     <string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"<xliff:g id="ID_1">%s</xliff:g> ayarlarını açın."</string>
    -     <string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"Ayarların sıralanmasını redaktə edin."</string>
    -     <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"<xliff:g id="ID_2">%2$d</xliff:g> səhifədən <xliff:g id="ID_1">%1$d</xliff:g> səhifə"</string>
    -+    <string name="cant_silence_or_block" msgid="999689262131488625">"Bildirişlər susdurula və ya blok edilə bilməz"</string>
    - </resources>
    -diff --git a/packages/SystemUI/res/values-b+sr+Latn/strings.xml b/packages/SystemUI/res/values-b+sr+Latn/strings.xml
    -index f95045c..19d58d5 100644
    ---- a/packages/SystemUI/res/values-b+sr+Latn/strings.xml
    -+++ b/packages/SystemUI/res/values-b+sr+Latn/strings.xml
    -@@ -239,7 +239,7 @@
    -     <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"4G podaci su pauzirani"</string>
    -     <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"Mobilni podaci su pauzirani"</string>
    -     <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"Podaci su pauzirani"</string>
    --    <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"Zbog toga što ste dostigli podešeno ograničenje za podatke, uređaj je pauzirao korišćenje podataka tokom ostatka ovog ciklusa.\n\nAko nastavite, mobilni operater može da vam naplati dodatne troškove."</string>
    -+    <string name="data_usage_disabled_dialog" msgid="1841738975235283398">"Ograničenje potrošnje podataka koje ste podesili je dostignuto. Više ne koristite mobilne podatke.\n\nAko nastavite, možda će biti naplaćeni troškovi za potrošnju podataka."</string>
    -     <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"Nastavi"</string>
    -     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Nema internet veze"</string>
    -     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi je povezan"</string>
    -@@ -406,6 +406,7 @@
    -     <string name="device_owned_footer" msgid="3802752663326030053">"Uređaj se možda nadgleda"</string>
    -     <string name="profile_owned_footer" msgid="8021888108553696069">"Profil se možda nadgleda"</string>
    -     <string name="vpn_footer" msgid="2388611096129106812">"Mreža se možda nadgleda"</string>
    -+    <string name="branded_vpn_footer" msgid="2168111859226496230">"Mreža se možda nadgleda"</string>
    -     <string name="monitoring_title_device_owned" msgid="7121079311903859610">"Nadgledanje uređaja"</string>
    -     <string name="monitoring_title_profile_owned" msgid="6790109874733501487">"Nadgledanje profila"</string>
    -     <string name="monitoring_title" msgid="169206259253048106">"Nadgledanje mreže"</string>
    -@@ -418,6 +419,7 @@
    -     <string name="legacy_vpn_name" msgid="6604123105765737830">"VPN"</string>
    -     <string name="monitoring_description_app" msgid="6259179342284742878">"Povezani ste sa aplikacijom <xliff:g id="APPLICATION">%1$s</xliff:g>, koja može da nadgleda aktivnosti na mreži, uključujući imejlove, aplikacije i veb-sajtove."</string>
    -     <string name="monitoring_description_app_personal" msgid="484599052118316268">"Povezani ste sa aplikacijom <xliff:g id="APPLICATION">%1$s</xliff:g>, koja može da nadgleda aktivnosti na ličnoj mreži, uključujući imejlove, aplikacije i veb-sajtove."</string>
    -+    <string name="branded_monitoring_description_app_personal" msgid="2669518213949202599">"Povezani ste sa aplikacijom <xliff:g id="APPLICATION">%1$s</xliff:g>, koja može da nadgleda aktivnosti na ličnoj mreži, uključujući imejlove, aplikacije i veb-sajtove."</string>
    -     <string name="monitoring_description_app_work" msgid="1754325860918060897">"Profilom za Work upravlja <xliff:g id="ORGANIZATION">%1$s</xliff:g>. Povezan je sa aplikacijom <xliff:g id="APPLICATION">%2$s</xliff:g>, koja može da nadgleda aktivnosti na poslovnoj mreži, uključujući imejlove, aplikacije i veb-sajtove.\n\nViše informacija potražite od administratora."</string>
    -     <string name="monitoring_description_app_personal_work" msgid="4946600443852045903">"Profilom za Work upravlja <xliff:g id="ORGANIZATION">%1$s</xliff:g>. Povezan je sa aplikacijom <xliff:g id="APPLICATION_WORK">%2$s</xliff:g>, koja može da nadgleda aktivnosti na poslovnoj mreži, uključujući imejlove, aplikacije i veb-sajtove.\n\nPovezani ste i sa aplikacijom <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g>, koja može da nadgleda aktivnosti na ličnoj mreži."</string>
    -     <string name="monitoring_description_vpn_app_device_owned" msgid="4970443827043261703">"Uređajem upravlja <xliff:g id="ORGANIZATION">%1$s</xliff:g>.\n\nAdministrator može da nadgleda podešavanja, korporativni pristup, aplikacije, podatke povezane sa uređajem i informacije o lokaciji uređaja, kao i da upravlja njima.\n\nPovezani ste sa aplikacijom <xliff:g id="APPLICATION">%2$s</xliff:g>, koja može da nadgleda aktivnosti na mreži, uključujući imejlove, aplikacije i veb-sajtove.\n\nViše informacija potražite od administratora."</string>
    -@@ -494,8 +496,6 @@
    -     <string name="clock_seconds_desc" msgid="6282693067130470675">"Sekunde na satu se prikazuju na statusnoj traci. To može da utiče na trajanje baterije."</string>
    -     <string name="qs_rearrange" msgid="8060918697551068765">"Preuredi Brza podešavanja"</string>
    -     <string name="show_brightness" msgid="6613930842805942519">"Prikaži osvetljenost u Brzim podešavanjima"</string>
    --    <string name="overview_nav_bar_gesture" msgid="8579814204727917764">"Omogući pokret za prevlačenje nagore za podeljeni ekran"</string>
    --    <string name="overview_nav_bar_gesture_desc" msgid="6329167382305102615">"Omogućava pokret za prelazak na podeljeni ekran prevlačenjem nagore od dugmeta Pregled"</string>
    -     <string name="experimental" msgid="6198182315536726162">"Eksperimentalno"</string>
    -     <string name="enable_bluetooth_title" msgid="5027037706500635269">"Želite li da uključite Bluetooth?"</string>
    -     <string name="enable_bluetooth_message" msgid="9106595990708985385">"Da biste povezali tastaturu sa tabletom, prvo morate da uključite Bluetooth."</string>
    -@@ -653,4 +653,5 @@
    -     <string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"Otvori podešavanja za <xliff:g id="ID_1">%s</xliff:g>."</string>
    -     <string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"Izmeni redosled podešavanja."</string>
    -     <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"<xliff:g id="ID_1">%1$d</xliff:g>. strana od <xliff:g id="ID_2">%2$d</xliff:g>"</string>
    -+    <string name="cant_silence_or_block" msgid="999689262131488625">"Zvuk obaveštenja ne može da se isključi niti ona mogu da se blokiraju"</string>
    - </resources>
    -diff --git a/packages/SystemUI/res/values-be-rBY/strings.xml b/packages/SystemUI/res/values-be-rBY/strings.xml
    -index 325d706..7538a9a 100644
    ---- a/packages/SystemUI/res/values-be-rBY/strings.xml
    -+++ b/packages/SystemUI/res/values-be-rBY/strings.xml
    -@@ -242,7 +242,7 @@
    -     <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"Перадача даных 4G прыпынена"</string>
    -     <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"Мабільная перадача даных прыпынена"</string>
    -     <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"Перадача даных прыпынена"</string>
    --    <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"Быў дасягнуты ліміт перадачы даных, таму прылада прыпыніла перадачу даных на астатнюю частку гэтага цыкла.\n\nУзнаўленне перадачы можа прывесці да спагнання платы вашым аператарам."</string>
    -+    <string name="data_usage_disabled_dialog" msgid="1841738975235283398">"Ліміт даных, які вы задалі, быў дасягнуты. Вы больш не выкарыстоўваеце сотавую перадачу даных.\n\nКалі вы ўзновіце карыстанне, можа спаганяцца плата за выкарыстанне трафіка."</string>
    -     <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"Узнавіць"</string>
    -     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Няма падключэння да Iнтэрнэту"</string>
    -     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi падключаны"</string>
    -@@ -410,6 +410,7 @@
    -     <string name="device_owned_footer" msgid="3802752663326030053">"За прыладай могуць назіраць"</string>
    -     <string name="profile_owned_footer" msgid="8021888108553696069">"За профілем могуць назіраць"</string>
    -     <string name="vpn_footer" msgid="2388611096129106812">"За сеткай могуць назіраць"</string>
    -+    <string name="branded_vpn_footer" msgid="2168111859226496230">"За сеткай могуць назіраць"</string>
    -     <string name="monitoring_title_device_owned" msgid="7121079311903859610">"Маніторынг прылад"</string>
    -     <string name="monitoring_title_profile_owned" msgid="6790109874733501487">"Маніторынг профіляў"</string>
    -     <string name="monitoring_title" msgid="169206259253048106">"Маніторынг сеткі"</string>
    -@@ -422,6 +423,7 @@
    -     <string name="legacy_vpn_name" msgid="6604123105765737830">"VPN"</string>
    -     <string name="monitoring_description_app" msgid="6259179342284742878">"Вы падлучаны да праграмы <xliff:g id="APPLICATION">%1$s</xliff:g>, якая можа сачыць за вашай сеткавай актыўнасцю, уключаючы электронную пошту, праграмы і вэб-сайты."</string>
    -     <string name="monitoring_description_app_personal" msgid="484599052118316268">"Вы падлучаны да праграмы <xliff:g id="APPLICATION">%1$s</xliff:g>, якая сачыць за вашай асабістай сеткавай актыўнасцю, уключаючы электронную пошту, праграмы і вэб-сайты."</string>
    -+    <string name="branded_monitoring_description_app_personal" msgid="2669518213949202599">"Вы падключаны да праграмы <xliff:g id="APPLICATION">%1$s</xliff:g>, якая можа сачыць за вашай асабістай сеткавай дзейнасцю, уключаючы электронную пошту, праграмы і вэб-сайты."</string>
    -     <string name="monitoring_description_app_work" msgid="1754325860918060897">"Ваш працоўны профіль знаходзіцца пад кіраваннем <xliff:g id="ORGANIZATION">%1$s</xliff:g>. Ён падлучаны да праграмы <xliff:g id="APPLICATION">%2$s</xliff:g>, якая можа сачыць за вашай сеткавай актыўнасцю, уключаючы электронную пошту, праграмы і вэб-сайты.\n\nДля атрымання дадатковай інфармацыі звярніцеся да адміністратара."</string>
    -     <string name="monitoring_description_app_personal_work" msgid="4946600443852045903">"Ваш працоўны профіль знаходзіцца пад кіраваннем <xliff:g id="ORGANIZATION">%1$s</xliff:g>. Ён падлучаны да праграмы <xliff:g id="APPLICATION_WORK">%2$s</xliff:g>, якая можа сачыць за вашай сеткавай актыўнасцю, уключаючы электронную пошту, праграмы і вэб-сайты.\n\nВы таксама падлучаны да праграмы <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g>, якая можа сачыць за вашай асабістай сеткавай актыўнасцю."</string>
    -     <string name="monitoring_description_vpn_app_device_owned" msgid="4970443827043261703">"Ваша прылада знаходзіцца пад кіраваннем <xliff:g id="ORGANIZATION">%1$s</xliff:g>.\n\nВаш адміністратар можа сачыць і кіраваць наладамі, доступам да карпаратыўных рэсурсаў, праграмамі, данымі, звязанымі з вашай прыладай, і звесткамі пра месцазнаходжанне прылады.\n\nВы падлучаны да праграмы <xliff:g id="APPLICATION">%2$s</xliff:g>,  якая можа сачыць за вашай сеткавай актыўнасцю, уключаючы электронную пошту, праграмы і вэб-сайты.\n\nДля атрымання дадатковай інфармацыі звярніцеся да адміністратара."</string>
    -@@ -498,8 +500,6 @@
    -     <string name="clock_seconds_desc" msgid="6282693067130470675">"Паказваць секунды гадзінніка на панэлі стану. Можа паўплываць на рэсурс акумулятара."</string>
    -     <string name="qs_rearrange" msgid="8060918697551068765">"Змяніць парадак Хуткіх налад"</string>
    -     <string name="show_brightness" msgid="6613930842805942519">"Паказваць яркасць у Хуткіх наладах"</string>
    --    <string name="overview_nav_bar_gesture" msgid="8579814204727917764">"Уключ. пераход да рэжыму дзялення экрана правядзеннем уверх"</string>
    --    <string name="overview_nav_bar_gesture_desc" msgid="6329167382305102615">"Уключыць пераход да рэжыму дзялення экрана правядзеннем пальцам уверх ад кнопкі «Агляд»"</string>
    -     <string name="experimental" msgid="6198182315536726162">"Эксперыментальныя"</string>
    -     <string name="enable_bluetooth_title" msgid="5027037706500635269">"Уключыць Bluetooth?"</string>
    -     <string name="enable_bluetooth_message" msgid="9106595990708985385">"Для падлучэння клавіятуры да планшэта трэба спачатку ўключыць Bluetooth."</string>
    -@@ -657,4 +657,5 @@
    -     <string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"Адкрыць налады <xliff:g id="ID_1">%s</xliff:g>."</string>
    -     <string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"Змяніць парадак налад."</string>
    -     <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"Старонка <xliff:g id="ID_1">%1$d</xliff:g> з <xliff:g id="ID_2">%2$d</xliff:g>"</string>
    -+    <string name="cant_silence_or_block" msgid="999689262131488625">"Гук паведамленняў нельга адключыць, і іх нельга заблакіраваць"</string>
    - </resources>
    -diff --git a/packages/SystemUI/res/values-bg/strings.xml b/packages/SystemUI/res/values-bg/strings.xml
    -index c5817ee..b184142 100644
    ---- a/packages/SystemUI/res/values-bg/strings.xml
    -+++ b/packages/SystemUI/res/values-bg/strings.xml
    -@@ -238,7 +238,7 @@
    -     <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"Данните от 4G са поставени на пауза"</string>
    -     <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"Мобилните данни са поставени на пауза"</string>
    -     <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"Данните са поставени на пауза"</string>
    --    <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"Тъй като зададеното от вас ограничение за данни бе достигнато, устройството постави преноса им на пауза за остатъка от този цикъл.\n\nВъзобновяването може да доведе до таксуване от оператора ви."</string>
    -+    <string name="data_usage_disabled_dialog" msgid="1841738975235283398">"Достигнахте зададеното от вас ограничение за данните. Вече не използвате мобилната мрежа.\n\nАко възобновите връзката с нея, може да бъдете таксувани за пренос на данни."</string>
    -     <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"Възобновяване"</string>
    -     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Няма връзка с интернет"</string>
    -     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi: Има връзка"</string>
    -@@ -404,6 +404,7 @@
    -     <string name="device_owned_footer" msgid="3802752663326030053">"Устройството може да се наблюдава"</string>
    -     <string name="profile_owned_footer" msgid="8021888108553696069">"Възможно е потребителският профил да се наблюдава"</string>
    -     <string name="vpn_footer" msgid="2388611096129106812">"Мрежата може да се наблюдава"</string>
    -+    <string name="branded_vpn_footer" msgid="2168111859226496230">"Мрежата може да се наблюдава"</string>
    -     <string name="monitoring_title_device_owned" msgid="7121079311903859610">"Наблюдение на устройството"</string>
    -     <string name="monitoring_title_profile_owned" msgid="6790109874733501487">"Наблюдаване на потр. профил"</string>
    -     <string name="monitoring_title" msgid="169206259253048106">"Наблюдение на мрежата"</string>
    -@@ -416,6 +417,7 @@
    -     <string name="legacy_vpn_name" msgid="6604123105765737830">"VPN"</string>
    -     <string name="monitoring_description_app" msgid="6259179342284742878">"Установена е връзка с приложението <xliff:g id="APPLICATION">%1$s</xliff:g>, което може да наблюдава активността ви в мрежата, включително имейли, приложения и уебсайтове."</string>
    -     <string name="monitoring_description_app_personal" msgid="484599052118316268">"Установена е връзка с приложението <xliff:g id="APPLICATION">%1$s</xliff:g>, което може да наблюдава личната ви активност в мрежата, включително имейли, приложения и уебсайтове."</string>
    -+    <string name="branded_monitoring_description_app_personal" msgid="2669518213949202599">"Установена е връзка с приложението <xliff:g id="APPLICATION">%1$s</xliff:g>, което може да наблюдава личната ви активност в мрежата, включително имейли, приложения и уебсайтове."</string>
    -     <string name="monitoring_description_app_work" msgid="1754325860918060897">"Служебният ви потребителски профил се управлява от <xliff:g id="ORGANIZATION">%1$s</xliff:g>. Той е свързан с приложението <xliff:g id="APPLICATION">%2$s</xliff:g>, което може да наблюдава служебната ви активност в мрежата, включително имейли, приложения и уебсайтове.\n\nЗа още информация се свържете с администратора си."</string>
    -     <string name="monitoring_description_app_personal_work" msgid="4946600443852045903">"Служебният ви потребителски профил се управлява от <xliff:g id="ORGANIZATION">%1$s</xliff:g>. Той е свързан с приложението <xliff:g id="APPLICATION_WORK">%2$s</xliff:g>, което може да наблюдава служебната ви активност в мрежата, включително имейли, приложения и уебсайтове.\n\nУстановена е връзка и с приложението <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g>, което може да наблюдава личната ви активност в мрежата."</string>
    -     <string name="monitoring_description_vpn_app_device_owned" msgid="4970443827043261703">"Устройството ви се управлява от <xliff:g id="ORGANIZATION">%1$s</xliff:g>.\n\nАдминистраторът ви може да наблюдава и управлява настройките, корпоративния достъп, приложенията и данните, свързани с устройството ви, включително информацията за местоположението му.\n\nУстановена е връзка с приложението <xliff:g id="APPLICATION">%2$s</xliff:g>, което може да наблюдава активността ви в мрежата, включително имейли, приложения и уебсайтове.\n\nЗа още информация се свържете с администратора си."</string>
    -@@ -492,8 +494,6 @@
    -     <string name="clock_seconds_desc" msgid="6282693067130470675">"Показване на секундите на часовника в лентата на състоянието. Може да се отрази на живота на батерията."</string>
    -     <string name="qs_rearrange" msgid="8060918697551068765">"Пренареждане на бързите настройки"</string>
    -     <string name="show_brightness" msgid="6613930842805942519">"Показване на яркостта от бързите настройки"</string>
    --    <string name="overview_nav_bar_gesture" msgid="8579814204727917764">"Разделяне на екрана с прекарване на пръст нагоре: Активиране"</string>
    --    <string name="overview_nav_bar_gesture_desc" msgid="6329167382305102615">"Активиране на жеста за влизане в режим на разделен екран чрез прокарване на пръст нагоре от бутона за общ преглед"</string>
    -     <string name="experimental" msgid="6198182315536726162">"Експериментални"</string>
    -     <string name="enable_bluetooth_title" msgid="5027037706500635269">"Да се включи ли Bluetooth?"</string>
    -     <string name="enable_bluetooth_message" msgid="9106595990708985385">"За да свържете клавиатурата с таблета си, първо трябва да включите Bluetooth."</string>
    -@@ -651,4 +651,5 @@
    -     <string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"Отваряне на настройките за <xliff:g id="ID_1">%s</xliff:g>."</string>
    -     <string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"Редактиране на подредбата на настройките."</string>
    -     <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"Страница <xliff:g id="ID_1">%1$d</xliff:g> от <xliff:g id="ID_2">%2$d</xliff:g>"</string>
    -+    <string name="cant_silence_or_block" msgid="999689262131488625">"Известията не могат да бъдат заглушавани, нито блокирани"</string>
    - </resources>
    -diff --git a/packages/SystemUI/res/values-bn-rBD/strings.xml b/packages/SystemUI/res/values-bn-rBD/strings.xml
    -index 40076e6..2cd7b04 100644
    ---- a/packages/SystemUI/res/values-bn-rBD/strings.xml
    -+++ b/packages/SystemUI/res/values-bn-rBD/strings.xml
    -@@ -238,7 +238,7 @@
    -     <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"4G ডেটা বিরতি দেওয়া হয়েছে"</string>
    -     <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"সেলুলার ডেটা বিরতি দেওয়া হয়েছে"</string>
    -     <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"ডেট বিরতি দেওয়া হয়েছে"</string>
    --    <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"আপনার সেট ডেটার সীমা অবধি পৌঁছনোর কারনে ডিভাইস এই চক্রের অবশিষ্টাংশের জন্য ডেটা ব্যবহারে বিরতি দেওয়া হয়েছে৷ \n\nপুনরায় চালু করা হলে পরিষেবা প্রদানকারীর দ্বারা চার্জের করা হতে পারে৷"</string>
    -+    <string name="data_usage_disabled_dialog" msgid="1841738975235283398">"আপনার সেটা করা ডেটা সীমা ছাড়িয়ে গেছে৷ আপনি আর সেলুলার ডেটা ব্যবহার করতে পারবেন না৷\n\nআপনি যদি আবার ব্যবহার করতে শুরু করেন তাহলে ডেটা ব্যবহারের জন্য চার্জ লাগতে পারে৷"</string>
    -     <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"পুনঃসূচনা করুন"</string>
    -     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"কোনো ইন্টারনেট সংযোগ নেই"</string>
    -     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"ওয়াই-ফাই সংযুক্ত হয়েছে"</string>
    -@@ -404,6 +404,7 @@
    -     <string name="device_owned_footer" msgid="3802752663326030053">"ডিভাইসটি নিরীক্ষণ করা হতে পারে"</string>
    -     <string name="profile_owned_footer" msgid="8021888108553696069">"প্রোফাইল পর্যবেক্ষণ করা হতে পারে"</string>
    -     <string name="vpn_footer" msgid="2388611096129106812">"নেটওয়ার্ক নিরীক্ষণ করা হতে পারে"</string>
    -+    <string name="branded_vpn_footer" msgid="2168111859226496230">"নেটওয়ার্ক নিরীক্ষণ করা হতে পারে"</string>
    -     <string name="monitoring_title_device_owned" msgid="7121079311903859610">"ডিভাইস নিরীক্ষণ"</string>
    -     <string name="monitoring_title_profile_owned" msgid="6790109874733501487">"প্রোফাইল দেখরেখ করা"</string>
    -     <string name="monitoring_title" msgid="169206259253048106">"নেটওয়ার্ক নিরীক্ষণ"</string>
    -@@ -416,6 +417,7 @@
    -     <string name="legacy_vpn_name" msgid="6604123105765737830">"VPN"</string>
    -     <string name="monitoring_description_app" msgid="6259179342284742878">"আপনি <xliff:g id="APPLICATION">%1$s</xliff:g> -এ সংযুক্ত হয়েছেন, যা ইমেল, অ্যাপ্লিকেশান এবং ওয়েবসাইটগুলি সমেত আপনার নেটওয়ার্ক কার্যকলাপ নিরীক্ষণ করতে পারে৷"</string>
    -     <string name="monitoring_description_app_personal" msgid="484599052118316268">"আপনি <xliff:g id="APPLICATION">%1$s</xliff:g> -এ সংযুক্ত হয়েছেন, যা ইমেল, অ্যাপ্লিকেশান এবং ওয়েবসাইটগুলি সমেত আপনার ব্যক্তিগত নেটওয়ার্ক কার্যকলাপ নিরীক্ষণ করতে পারে৷"</string>
    -+    <string name="branded_monitoring_description_app_personal" msgid="2669518213949202599">"আপনি <xliff:g id="APPLICATION">%1$s</xliff:g> এর সাথে সংযুক্ত হয়েছেন, যা ইমেল, অ্যাপ এবং ওয়েবসাইটগুলি সহ আপনার ব্যক্তিগত নেটওয়ার্কের কার্যকলাপ নিরীক্ষণ করবে৷"</string>
    -     <string name="monitoring_description_app_work" msgid="1754325860918060897">"<xliff:g id="ORGANIZATION">%1$s</xliff:g> আপনার কাজের প্রোফাইল পরিচালনা করে৷ এটি <xliff:g id="APPLICATION">%2$s</xliff:g> -এ সংযুক্ত রয়েছে যা আপনার ইমেল, অ্যাপ্লিকেশান ও ওয়েবসাইটগুলি সহ আপনার কাজের নেটওয়ার্কের কার্যকলাপ নিরীক্ষণ করতে পারে৷\n\nআরো তথ্যের জন্য, আপনার প্রশাসকের সাথে যোগাযোগ করুন৷"</string>
    -     <string name="monitoring_description_app_personal_work" msgid="4946600443852045903">"<xliff:g id="ORGANIZATION">%1$s</xliff:g> আপনার কাজের প্রোফাইল পরিচালনা করে৷ এটি <xliff:g id="APPLICATION_WORK">%2$s</xliff:g> -এ সংযুক্ত রয়েছে যা আপনার ইমেল, অ্যাপ্লিকেশান ও ওয়েবসাইটগুলি সহ আপনার কাজের নেটওয়ার্কের কার্যকলাপ নিরীক্ষণ করতে পারে৷\n\nএছাড়াও আপনি <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g> এর সাথে সংযুক্ত রয়েছেন যা আপনার ব্যক্তিগত নেটওয়ার্কের কার্যকলাপ নিরীক্ষণ করতে পারে৷"</string>
    -     <string name="monitoring_description_vpn_app_device_owned" msgid="4970443827043261703">"<xliff:g id="ORGANIZATION">%1$s</xliff:g> আপনার ডিভাইস পরিচালনা করে৷\n\nআপনার প্রশাসক আপনার ডিভাইসের সাথে সম্পর্কিত সেটিংস, কর্পোরেট অ্যাক্সেস, অ্যাপ্লিকেশান ডেটা এবং ডিভাইসের অবস্থান সম্পর্কিত তথ্য নিরীক্ষণ ও পরিচালনা করতে পারেন৷\n\nআপনি <xliff:g id="APPLICATION">%2$s</xliff:g> এর সাথে সংযুক্ত রয়েছেন যা ইমেল, অ্যাপ্লিকেশান ও ওয়েবসাইটগুলি সহ আপনার নেটওয়ার্কের কার্যকলাপ নিরীক্ষণ করতে পারে৷\n\nআরো তথ্যের জন্য, আপনার প্রশাসকের সাথে যোগাযোগ করুন৷"</string>
    -@@ -492,8 +494,6 @@
    -     <string name="clock_seconds_desc" msgid="6282693067130470675">"স্থিতি দন্ডে ঘড়ির সেকেন্ড দেখায়৷ ব্যাটারি লাইফকে প্রভাবিত করতে পারে৷"</string>
    -     <string name="qs_rearrange" msgid="8060918697551068765">"দ্রুত সেটিংসে পুনরায় সাজান"</string>
    -     <string name="show_brightness" msgid="6613930842805942519">"দ্রুত সেটিংসে উজ্জ্বলতা দেখান"</string>
    --    <string name="overview_nav_bar_gesture" msgid="8579814204727917764">"উপরের দিকে সোয়াইপ করে বিভক্ত-স্ক্রীনে প্রবেশ করার অঙ্গভঙ্গি সক্ষম করুন"</string>
    --    <string name="overview_nav_bar_gesture_desc" msgid="6329167382305102615">"\'এক নজরে\' বোতাম থেকে উপরের দিকে সোয়াইপ করে, বিভক্ত-স্ক্রীনে প্রবেশ করতে অঙ্গভঙ্গি সক্ষম করুন"</string>
    -     <string name="experimental" msgid="6198182315536726162">"পরীক্ষামূলক"</string>
    -     <string name="enable_bluetooth_title" msgid="5027037706500635269">"ব্লুটুথ চালু করবেন?"</string>
    -     <string name="enable_bluetooth_message" msgid="9106595990708985385">"আপনার ট্যাবলেটের সাথে আপনার কীবোর্ড সংযুক্ত করতে, আপনাকে প্রথমে ব্লুটুথ চালু করতে হবে।"</string>
    -@@ -651,4 +651,5 @@
    -     <string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"<xliff:g id="ID_1">%s</xliff:g> সেটিংস খুলুন৷"</string>
    -     <string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"ক্রম বা সেটিংস সম্পাদনা করুন৷"</string>
    -     <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"<xliff:g id="ID_2">%2$d</xliff:g>টির মধ্যে <xliff:g id="ID_1">%1$d</xliff:g> নং পৃষ্ঠা"</string>
    -+    <string name="cant_silence_or_block" msgid="999689262131488625">"বিজ্ঞপ্তিগুলিকে নীরব বা অবরুদ্ধ করা যাবে না"</string>
    - </resources>
    -diff --git a/packages/SystemUI/res/values-bs-rBA-land/strings.xml b/packages/SystemUI/res/values-bs-rBA-land/strings.xml
    -index bdc652a..56a4ad2 100644
    ---- a/packages/SystemUI/res/values-bs-rBA-land/strings.xml
    -+++ b/packages/SystemUI/res/values-bs-rBA-land/strings.xml
    -@@ -19,5 +19,5 @@
    - 
    - <resources xmlns:android="http://schemas.android.com/apk/res/android"
    -     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
    --    <string name="toast_rotation_locked" msgid="7609673011431556092">"Ekran je sada zaključan u pejzažnom prikazu."</string>
    -+    <string name="toast_rotation_locked" msgid="7609673011431556092">"Ekran je sada zaključan u vodoravnom prikazu."</string>
    - </resources>
    -diff --git a/packages/SystemUI/res/values-bs-rBA/strings.xml b/packages/SystemUI/res/values-bs-rBA/strings.xml
    -index dcba67b..3fc98fd 100644
    ---- a/packages/SystemUI/res/values-bs-rBA/strings.xml
    -+++ b/packages/SystemUI/res/values-bs-rBA/strings.xml
    -@@ -239,7 +239,7 @@
    -     <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"4G prijenos podataka je pauzirano"</string>
    -     <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"Mobilni podaci su pauzirani"</string>
    -     <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"Prijenos podataka je pauziran"</string>
    --    <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"Dostigli ste postavljeno ograničenje prijenosa podataka pa je uređaj zaustavio prijenos podataka za preostali dio ovog ciklusa.\n\nAko nastavite, operater vam može naplatiti dodatne troškove."</string>
    -+    <string name="data_usage_disabled_dialog" msgid="1841738975235283398">"Dostigli ste ograničenje za prijenos podataka koje ste postavili. Više ne koristite mobilne podatke.\n\nUkoliko nastavite koristiti mobilne podatke, mogući su troškovi za prijenos podataka."</string>
    -     <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"Nastavi"</string>
    -     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Nema internet veze"</string>
    -     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi veza aktivna"</string>
    -@@ -314,7 +314,7 @@
    -     <string name="quick_settings_notifications_label" msgid="4818156442169154523">"Obavještenja"</string>
    -     <string name="quick_settings_flashlight_label" msgid="2133093497691661546">"Svjetiljka"</string>
    -     <string name="quick_settings_cellular_detail_title" msgid="8575062783675171695">"Mobilni podaci"</string>
    --    <string name="quick_settings_cellular_detail_data_usage" msgid="1964260360259312002">"Korištenje podataka"</string>
    -+    <string name="quick_settings_cellular_detail_data_usage" msgid="1964260360259312002">"Prijenos podataka"</string>
    -     <string name="quick_settings_cellular_detail_remaining_data" msgid="722715415543541249">"Preostala količina podataka"</string>
    -     <string name="quick_settings_cellular_detail_over_limit" msgid="967669665390990427">"Prekoračeno"</string>
    -     <string name="quick_settings_cellular_detail_data_used" msgid="1476810587475761478">"Iskorišteno <xliff:g id="DATA_USED">%s</xliff:g>"</string>
    -@@ -406,6 +406,7 @@
    -     <string name="device_owned_footer" msgid="3802752663326030053">"Uređaj može biti nadziran"</string>
    -     <string name="profile_owned_footer" msgid="8021888108553696069">"Profil može biti nadziran"</string>
    -     <string name="vpn_footer" msgid="2388611096129106812">"Mreža može biti nadzirana"</string>
    -+    <string name="branded_vpn_footer" msgid="2168111859226496230">"Mreža može biti nadzirana"</string>
    -     <string name="monitoring_title_device_owned" msgid="7121079311903859610">"Praćenje uređaja"</string>
    -     <string name="monitoring_title_profile_owned" msgid="6790109874733501487">"Praćenje profila"</string>
    -     <string name="monitoring_title" msgid="169206259253048106">"Praćenje mreže"</string>
    -@@ -418,6 +419,7 @@
    -     <string name="legacy_vpn_name" msgid="6604123105765737830">"VPN"</string>
    -     <string name="monitoring_description_app" msgid="6259179342284742878">"Povezani ste sa aplikacijom <xliff:g id="APPLICATION">%1$s</xliff:g>, koja može pratiti vašu aktivnost na mreži, uključujući e-mailove, aplikacije i web-lokacije."</string>
    -     <string name="monitoring_description_app_personal" msgid="484599052118316268">"Povezani ste sa aplikacijom <xliff:g id="APPLICATION">%1$s</xliff:g>, koja može pratiti vašu aktivnost na privatnoj mreži, uključujući e-mailove, aplikacije i web-lokacije."</string>
    -+    <string name="branded_monitoring_description_app_personal" msgid="2669518213949202599">"Povezani ste na aplikaciju <xliff:g id="APPLICATION">%1$s</xliff:g>, koja može pratiti vaše privatne aktivnosti na mreži, uključujući e-poštu, aplikacije i web stranice."</string>
    -     <string name="monitoring_description_app_work" msgid="1754325860918060897">"Profilom za posao upravlja <xliff:g id="ORGANIZATION">%1$s</xliff:g>. Povezan je sa aplikacijom <xliff:g id="APPLICATION">%2$s</xliff:g>, koja može pratiti vašu aktivnost na radnoj mreži, uključujući e-poštu, aplikacije i web-lokacije.\n\nZa više informacija kontaktirajte svog administratora."</string>
    -     <string name="monitoring_description_app_personal_work" msgid="4946600443852045903">"Profilom za posao upravlja <xliff:g id="ORGANIZATION">%1$s</xliff:g>. Povezan je sa aplikacijom <xliff:g id="APPLICATION_WORK">%2$s</xliff:g>, koja može pratiti vašu aktivnost na radnoj mreži, uključujući e-poštu, aplikacije i web-lokacije.\n\nPovezani ste i sa aplikacijom <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g>, koja može pratiti vašu aktivnost na privatnoj mreži."</string>
    -     <string name="monitoring_description_vpn_app_device_owned" msgid="4970443827043261703">"Vašim uređajem upravlja <xliff:g id="ORGANIZATION">%1$s</xliff:g>.\n\nVaš administrator može pratiti postavke, korporativni pristup, aplikacije, podatke povezane sa vašim uređajem i informacije o lokaciji uređaja, kao i upravljati njima.\n\nPovezani ste sa aplikacijom <xliff:g id="APPLICATION">%2$s</xliff:g>, koja može pratiti vašu aktivnost na mreži, uključujući e-poštu, aplikacije i web-lokacije.\n\nZa više informacija kontaktirajte svog administratora."</string>
    -@@ -496,8 +498,6 @@
    -     <string name="clock_seconds_desc" msgid="6282693067130470675">"Prikaži sekunde na statusnoj traci. Može skratiti trajanje baterije."</string>
    -     <string name="qs_rearrange" msgid="8060918697551068765">"Preuredi \"Brze postavke\""</string>
    -     <string name="show_brightness" msgid="6613930842805942519">"Prikaži osvjetljenje u opciji \"Brze postavke\""</string>
    --    <string name="overview_nav_bar_gesture" msgid="8579814204727917764">"Omogućiti potez za podjelu ekrana prevlačenjem prema gore"</string>
    --    <string name="overview_nav_bar_gesture_desc" msgid="6329167382305102615">"Uključite pokrete prstima da biste ušli u podijeljeni ekran tako što ćete od dugmeta Pregled prevući prstom prema gore"</string>
    -     <string name="experimental" msgid="6198182315536726162">"Eksperimentalno"</string>
    -     <string name="enable_bluetooth_title" msgid="5027037706500635269">"Želiti li uključiti Bluetooth?"</string>
    -     <string name="enable_bluetooth_message" msgid="9106595990708985385">"Da povežete tastaturu sa tabletom, prvo morate uključiti Bluetooth."</string>
    -@@ -655,4 +655,5 @@
    -     <string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"Otvori postavke za: <xliff:g id="ID_1">%s</xliff:g>."</string>
    -     <string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"Urediti raspored postavki."</string>
    -     <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"Stranica <xliff:g id="ID_1">%1$d</xliff:g> od <xliff:g id="ID_2">%2$d</xliff:g>"</string>
    -+    <string name="cant_silence_or_block" msgid="999689262131488625">"Obavještenja nije moguće prigušiti ili blokirati"</string>
    - </resources>
    -diff --git a/packages/SystemUI/res/values-ca/strings.xml b/packages/SystemUI/res/values-ca/strings.xml
    -index 3354f92..483f766 100644
    ---- a/packages/SystemUI/res/values-ca/strings.xml
    -+++ b/packages/SystemUI/res/values-ca/strings.xml
    -@@ -238,7 +238,7 @@
    -     <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"Les dades 4G estan aturades"</string>
    -     <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"Les dades mòbils estan aturades"</string>
    -     <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"Les dades estan aturades"</string>
    --    <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"Com que has arribat al límit de dades establert, s\'ha aturat l\'ús de dades del dispositiu per a la resta d\'aquest cicle.\n\nSi el reprens, l\'operador de telefonia mòbil pot aplicar càrrecs."</string>
    -+    <string name="data_usage_disabled_dialog" msgid="1841738975235283398">"S\'ha assolit el límit de dades establert. Ja no estàs utilitzant dades mòbils. \n\n Si reprens l\'ús de les dades, es poden aplicar càrrecs."</string>
    -     <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"Reprèn"</string>
    -     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"No hi ha connexió a Internet"</string>
    -     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi: connectada"</string>
    -@@ -404,6 +404,7 @@
    -     <string name="device_owned_footer" msgid="3802752663326030053">"És possible que el dispositiu estigui supervisat."</string>
    -     <string name="profile_owned_footer" msgid="8021888108553696069">"El perfil es pot supervisar"</string>
    -     <string name="vpn_footer" msgid="2388611096129106812">"És possible que la xarxa estigui supervisada."</string>
    -+    <string name="branded_vpn_footer" msgid="2168111859226496230">"És possible que la xarxa estigui supervisada"</string>
    -     <string name="monitoring_title_device_owned" msgid="7121079311903859610">"Supervisió del dispositiu"</string>
    -     <string name="monitoring_title_profile_owned" msgid="6790109874733501487">"Supervisió del perfil"</string>
    -     <string name="monitoring_title" msgid="169206259253048106">"Supervisió de la xarxa"</string>
    -@@ -416,6 +417,7 @@
    -     <string name="legacy_vpn_name" msgid="6604123105765737830">"VPN"</string>
    -     <string name="monitoring_description_app" msgid="6259179342284742878">"Estàs connectat a <xliff:g id="APPLICATION">%1$s</xliff:g>, que pot supervisar la teva activitat a la xarxa, com ara els correus electrònics, les aplicacions i els llocs web."</string>
    -     <string name="monitoring_description_app_personal" msgid="484599052118316268">"Estàs connectat a <xliff:g id="APPLICATION">%1$s</xliff:g>, que pot supervisar la teva activitat personal a la xarxa, com ara els correus electrònics, les aplicacions i els llocs web."</string>
    -+    <string name="branded_monitoring_description_app_personal" msgid="2669518213949202599">"Estàs connectat a <xliff:g id="APPLICATION">%1$s</xliff:g>, que pot supervisar la teva activitat personal a la xarxa, com ara els correus electrònics, les aplicacions i els llocs web."</string>
    -     <string name="monitoring_description_app_work" msgid="1754325860918060897">"<xliff:g id="ORGANIZATION">%1$s</xliff:g> gestiona el teu perfil professional. Aquest perfil està connectat a <xliff:g id="APPLICATION">%2$s</xliff:g>, que pot supervisar la teva activitat professional a la xarxa, com ara els correus electrònics, les aplicacions i els llocs web.\n\nPer obtenir més informació, contacta amb l\'administrador."</string>
    -     <string name="monitoring_description_app_personal_work" msgid="4946600443852045903">"<xliff:g id="ORGANIZATION">%1$s</xliff:g> gestiona el teu perfil professional. Aquest perfil està connectat a <xliff:g id="APPLICATION_WORK">%2$s</xliff:g>, que pot supervisar la teva activitat professional a la xarxa, com ara els correus electrònics, les aplicacions i els llocs web.\n\nA més, estàs connectat a <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g>, que també pot supervisar la teva activitat personal a la xarxa."</string>
    -     <string name="monitoring_description_vpn_app_device_owned" msgid="4970443827043261703">"<xliff:g id="ORGANIZATION">%1$s</xliff:g> gestiona el dispositiu.\n\nL\'administrador pot supervisar i gestionar el següent: configuració, accés corporatiu, aplicacions i dades associades amb el dispositiu, inclosa la informació d\'ubicació.\n\nEstàs connectat a <xliff:g id="APPLICATION">%2$s</xliff:g>, que pot supervisar l\'activitat a la xarxa, com ara els correus, les aplicacions i els llocs web.\n\nPer obtenir més informació, contacta amb l\'administrador."</string>
    -@@ -492,8 +494,6 @@
    -     <string name="clock_seconds_desc" msgid="6282693067130470675">"Mostra els segons del rellotge a la barra d\'estat. Això pot afectar la durada de la bateria."</string>
    -     <string name="qs_rearrange" msgid="8060918697551068765">"Reorganitza Configuració ràpida"</string>
    -     <string name="show_brightness" msgid="6613930842805942519">"Mostra la brillantor a Configuració ràpida"</string>
    --    <string name="overview_nav_bar_gesture" msgid="8579814204727917764">"Activa el gest per dividir la pantalla en lliscar cap amunt"</string>
    --    <string name="overview_nav_bar_gesture_desc" msgid="6329167382305102615">"Activa el gest per entrar al mode de pantalla dividida en lliscar cap amunt des del botó Visió general"</string>
    -     <string name="experimental" msgid="6198182315536726162">"Experimental"</string>
    -     <string name="enable_bluetooth_title" msgid="5027037706500635269">"Vols activar el Bluetooth?"</string>
    -     <string name="enable_bluetooth_message" msgid="9106595990708985385">"Per connectar el teclat amb la tauleta, primer has d\'activar el Bluetooth."</string>
    -@@ -651,4 +651,5 @@
    -     <string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"Obre la configuració per a <xliff:g id="ID_1">%s</xliff:g>."</string>
    -     <string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"Edita l\'ordre de la configuració."</string>
    -     <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"Pàgina <xliff:g id="ID_1">%1$d</xliff:g> (<xliff:g id="ID_2">%2$d</xliff:g> en total)"</string>
    -+    <string name="cant_silence_or_block" msgid="999689262131488625">"Les notificacions no es poden silenciar ni bloquejar"</string>
    - </resources>
    -diff --git a/packages/SystemUI/res/values-cs/strings.xml b/packages/SystemUI/res/values-cs/strings.xml
    -index d64e5d9..6adcde3 100644
    ---- a/packages/SystemUI/res/values-cs/strings.xml
    -+++ b/packages/SystemUI/res/values-cs/strings.xml
    -@@ -242,7 +242,7 @@
    -     <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"Data 4G jsou pozastavena"</string>
    -     <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"Mobilní data jsou pozastavena"</string>
    -     <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"Data jsou pozastavena"</string>
    --    <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"Protože jste dosáhli nastaveného limitu dat, zařízení využití dat pro zbytek tohoto cyklu pozastavilo.\n\nObnovení může vést k poplatkům od operátora."</string>
    -+    <string name="data_usage_disabled_dialog" msgid="1841738975235283398">"Byl dosažen limit dat. Používání mobilních dat bylo vypnuto.\n\nPokud jej obnovíte, mohou vám být účtovány poplatky za využití dat."</string>
    -     <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"Pokračovat"</string>
    -     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Žádné přip. k internetu"</string>
    -     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi: připojeno"</string>
    -@@ -410,6 +410,7 @@
    -     <string name="device_owned_footer" msgid="3802752663326030053">"Zařízení může být sledováno"</string>
    -     <string name="profile_owned_footer" msgid="8021888108553696069">"Profil může být monitorován"</string>
    -     <string name="vpn_footer" msgid="2388611096129106812">"Síť může být sledována"</string>
    -+    <string name="branded_vpn_footer" msgid="2168111859226496230">"Síť může být monitorována"</string>
    -     <string name="monitoring_title_device_owned" msgid="7121079311903859610">"Sledování zařízení"</string>
    -     <string name="monitoring_title_profile_owned" msgid="6790109874733501487">"Monitoring profilu"</string>
    -     <string name="monitoring_title" msgid="169206259253048106">"Sledování sítě"</string>
    -@@ -422,6 +423,7 @@
    -     <string name="legacy_vpn_name" msgid="6604123105765737830">"VPN"</string>
    -     <string name="monitoring_description_app" msgid="6259179342284742878">"Jste připojeni k aplikaci <xliff:g id="APPLICATION">%1$s</xliff:g>, která může sledovat vaši aktivitu v síti, včetně e-mailů, aplikací a webů."</string>
    -     <string name="monitoring_description_app_personal" msgid="484599052118316268">"Jste připojeni k aplikaci <xliff:g id="APPLICATION">%1$s</xliff:g>, která může sledovat vaši osobní aktivitu v síti, včetně e-mailů, aplikací a webů."</string>
    -+    <string name="branded_monitoring_description_app_personal" msgid="2669518213949202599">"Jste připojeni k aplikaci <xliff:g id="APPLICATION">%1$s</xliff:g>, která může sledovat vaši osobní aktivitu v síti, včetně e-mailů, aplikací a webů."</string>
    -     <string name="monitoring_description_app_work" msgid="1754325860918060897">"Váš pracovní profil spravuje organizace <xliff:g id="ORGANIZATION">%1$s</xliff:g>. Je připojen k aplikaci <xliff:g id="APPLICATION">%2$s</xliff:g>, která může sledovat vaši aktivitu v síti, včetně e-mailů, aplikací a webů.\n\nO další informace požádejte svého administrátora."</string>
    -     <string name="monitoring_description_app_personal_work" msgid="4946600443852045903">"Váš pracovní profil spravuje organizace <xliff:g id="ORGANIZATION">%1$s</xliff:g>. Je připojen k aplikaci <xliff:g id="APPLICATION_WORK">%2$s</xliff:g>, která může sledovat vaši aktivitu v síti, včetně e-mailů, aplikací a webů.\n\nTaké jste připojeni k aplikaci <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g>, která může sledovat vaši osobní aktivitu v síti."</string>
    -     <string name="monitoring_description_vpn_app_device_owned" msgid="4970443827043261703">"Toto zařízení spravuje organizace <xliff:g id="ORGANIZATION">%1$s</xliff:g>.\n\nAdministrátor může sledovat a spravovat nastavení, firemní přístup, aplikace, data přidružená k tomuto zařízení a informace o jeho poloze.\n\nJste připojeni k aplikaci <xliff:g id="APPLICATION">%2$s</xliff:g>, která může sledovat vaši osobní aktivitu v síti, včetně e-mailů, aplikací a webů.\n\nO další informace požádejte svého administrátora."</string>
    -@@ -498,8 +500,6 @@
    -     <string name="clock_seconds_desc" msgid="6282693067130470675">"Na stavovém řádku se bude zobrazovat sekundová ručička. Může být ovlivněna výdrž baterie."</string>
    -     <string name="qs_rearrange" msgid="8060918697551068765">"Změnit uspořádání Rychlého nastavení"</string>
    -     <string name="show_brightness" msgid="6613930842805942519">"Zobrazit jas v Rychlém nastavení"</string>
    --    <string name="overview_nav_bar_gesture" msgid="8579814204727917764">"Aktivovat rozdělenou obrazovku přejetím prstem nahoru"</string>
    --    <string name="overview_nav_bar_gesture_desc" msgid="6329167382305102615">"Umožňuje aktivovat rozdělenou obrazovku přejetím prstem nahoru od tlačítka Přehled."</string>
    -     <string name="experimental" msgid="6198182315536726162">"Experimentální"</string>
    -     <string name="enable_bluetooth_title" msgid="5027037706500635269">"Zapnout Bluetooth?"</string>
    -     <string name="enable_bluetooth_message" msgid="9106595990708985385">"Chcete-li klávesnici připojit k tabletu, nejdříve musíte zapnout Bluetooth."</string>
    -@@ -657,4 +657,5 @@
    -     <string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"Otevřít nastavení aplikace <xliff:g id="ID_1">%s</xliff:g>."</string>
    -     <string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"Upravit pořadí nastavení."</string>
    -     <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"Stránka <xliff:g id="ID_1">%1$d</xliff:g> z <xliff:g id="ID_2">%2$d</xliff:g>"</string>
    -+    <string name="cant_silence_or_block" msgid="999689262131488625">"Oznámení nelze ztlumit ani blokovat"</string>
    - </resources>
    -diff --git a/packages/SystemUI/res/values-da/strings.xml b/packages/SystemUI/res/values-da/strings.xml
    -index da8daa4..7de602a 100644
    ---- a/packages/SystemUI/res/values-da/strings.xml
    -+++ b/packages/SystemUI/res/values-da/strings.xml
    -@@ -238,7 +238,7 @@
    -     <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"4G-data er sat på pause"</string>
    -     <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"Mobildata er sat på pause"</string>
    -     <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"Data er sat på pause"</string>
    --    <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"Eftersom din fastsatte datagrænse blev nået, har enheden sat dataforbruget på pause i den resterende del af cyklussen.\n\nHvis du genaktiverer dataforbruget, kan det medføre gebyrer fra dit mobilselskab."</string>
    -+    <string name="data_usage_disabled_dialog" msgid="1841738975235283398">"Du har nået den angivne datagrænse. Du vil ikke længere bruge mobildata.\n\nHvis du fortsætter, vil du muligvis blive opkrævet betaling for dit dataforbrug."</string>
    -     <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"Genoptag"</string>
    -     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Ingen internetforb."</string>
    -     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi er forbundet"</string>
    -@@ -304,7 +304,7 @@
    -     <string name="quick_settings_inversion_label" msgid="8790919884718619648">"Byt om på farver"</string>
    -     <string name="quick_settings_color_space_label" msgid="853443689745584770">"Farvekorrigeringstilstand"</string>
    -     <string name="quick_settings_more_settings" msgid="326112621462813682">"Flere indstillinger"</string>
    --    <string name="quick_settings_done" msgid="3402999958839153376">"Udført"</string>
    -+    <string name="quick_settings_done" msgid="3402999958839153376">"Udfør"</string>
    -     <string name="quick_settings_connected" msgid="1722253542984847487">"Tilsluttet"</string>
    -     <string name="quick_settings_connecting" msgid="47623027419264404">"Opretter forbindelse…"</string>
    -     <string name="quick_settings_tethering_label" msgid="7153452060448575549">"Netdeling"</string>
    -@@ -404,6 +404,7 @@
    -     <string name="device_owned_footer" msgid="3802752663326030053">"Enheden kan være overvåget"</string>
    -     <string name="profile_owned_footer" msgid="8021888108553696069">"Profilen kan overvåges"</string>
    -     <string name="vpn_footer" msgid="2388611096129106812">"Netværket kan være overvåget"</string>
    -+    <string name="branded_vpn_footer" msgid="2168111859226496230">"Netværket kan være overvåget"</string>
    -     <string name="monitoring_title_device_owned" msgid="7121079311903859610">"Overvågning af enhed"</string>
    -     <string name="monitoring_title_profile_owned" msgid="6790109874733501487">"Profilovervågning"</string>
    -     <string name="monitoring_title" msgid="169206259253048106">"Overvågning af netværk"</string>
    -@@ -416,6 +417,7 @@
    -     <string name="legacy_vpn_name" msgid="6604123105765737830">"VPN"</string>
    -     <string name="monitoring_description_app" msgid="6259179342284742878">"Du har forbindelse til <xliff:g id="APPLICATION">%1$s</xliff:g>, som kan overvåge din netværksaktivitet, bl.a. e-mails, apps og websites."</string>
    -     <string name="monitoring_description_app_personal" msgid="484599052118316268">"Du har forbindelse til <xliff:g id="APPLICATION">%1$s</xliff:g>, som kan overvåge din private netværksaktivitet, bl.a. e-mails, apps og websites."</string>
    -+    <string name="branded_monitoring_description_app_personal" msgid="2669518213949202599">"Du har forbindelse til <xliff:g id="APPLICATION">%1$s</xliff:g>, som kan overvåge din private netværksaktivitet, bl.a. e-mails, apps og websites."</string>
    -     <string name="monitoring_description_app_work" msgid="1754325860918060897">"Din arbejdsprofil administreres af <xliff:g id="ORGANIZATION">%1$s</xliff:g>. Den er forbundet til <xliff:g id="APPLICATION">%2$s</xliff:g>, som kan overvåge din arbejdsrelaterede netværksaktivitet, bl.a. e-mails, apps og websites.\n\nKontakt din administrator for at få flere oplysninger."</string>
    -     <string name="monitoring_description_app_personal_work" msgid="4946600443852045903">"Din arbejdsprofil administreres af <xliff:g id="ORGANIZATION">%1$s</xliff:g>. Den er forbundet til <xliff:g id="APPLICATION_WORK">%2$s</xliff:g>, som kan overvåge din arbejdsrelaterede netværksaktivitet, bl.a. e-mails, apps og websites.\n\nDu er også forbundet til <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g>, som kan overvåge din private netværksaktivitet."</string>
    -     <string name="monitoring_description_vpn_app_device_owned" msgid="4970443827043261703">"Din enhed administreres af <xliff:g id="ORGANIZATION">%1$s</xliff:g>.\n\nDin administrator kan overvåge og administrere indstillinger, virksomhedens adgang, data tilknyttet din enhed og enhedens stedoplysninger.\n\nDu er forbundet til <xliff:g id="APPLICATION">%2$s</xliff:g>, som kan overvåge din netværksaktivitet, bl.a. e-mails, apps og websites.\n\nKontakt din administrator for at få flere oplysninger."</string>
    -@@ -492,8 +494,6 @@
    -     <string name="clock_seconds_desc" msgid="6282693067130470675">"Vis sekunder i statuslinjen. Dette kan påvirke batteriets levetid."</string>
    -     <string name="qs_rearrange" msgid="8060918697551068765">"Omarranger Hurtige indstillinger"</string>
    -     <string name="show_brightness" msgid="6613930842805942519">"Vis lysstyrke i Hurtige indstillinger"</string>
    --    <string name="overview_nav_bar_gesture" msgid="8579814204727917764">"Aktivér bevægelsen Stryg opad for at dele skærmen"</string>
    --    <string name="overview_nav_bar_gesture_desc" msgid="6329167382305102615">"Aktivér bevægelse for at dele skærmen ved at stryge opad fra knappen Oversigt"</string>
    -     <string name="experimental" msgid="6198182315536726162">"Eksperimentel"</string>
    -     <string name="enable_bluetooth_title" msgid="5027037706500635269">"Vil du slå Bluetooth til?"</string>
    -     <string name="enable_bluetooth_message" msgid="9106595990708985385">"Bluetooth skal være slået til, før du kan knytte dit tastatur til din tablet."</string>
    -@@ -521,7 +521,7 @@
    -     <string name="notification_importance_high" msgid="1729480727023990427">"Se altid smugkig. Ingen afbrydelse af fuld skærm."</string>
    -     <string name="notification_importance_max" msgid="2508384624461849111">"Se altid smugkig, og tillad afbrydelse af fuld skærm."</string>
    -     <string name="notification_more_settings" msgid="816306283396553571">"Flere indstillinger"</string>
    --    <string name="notification_done" msgid="5279426047273930175">"Færdig"</string>
    -+    <string name="notification_done" msgid="5279426047273930175">"Udfør"</string>
    -     <string name="notification_gear_accessibility" msgid="94429150213089611">"Kontrolelementer til underretninger for <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
    -     <string name="battery_panel_title" msgid="7944156115535366613">"Batteriforbrug"</string>
    -     <string name="battery_detail_charging_summary" msgid="1279095653533044008">"Batterisparefunktionen er ikke tilgængelig under opladning"</string>
    -@@ -651,4 +651,5 @@
    -     <string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"Åbn <xliff:g id="ID_1">%s</xliff:g>-indstillinger."</string>
    -     <string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"Rediger rækkefølgen af indstillinger."</string>
    -     <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"Side <xliff:g id="ID_1">%1$d</xliff:g> af <xliff:g id="ID_2">%2$d</xliff:g>"</string>
    -+    <string name="cant_silence_or_block" msgid="999689262131488625">"Underretninger kan ikke ignoreres eller blokeres"</string>
    - </resources>
    -diff --git a/packages/SystemUI/res/values-de/strings.xml b/packages/SystemUI/res/values-de/strings.xml
    -index 46078d9..fc6d9a0 100644
    ---- a/packages/SystemUI/res/values-de/strings.xml
    -+++ b/packages/SystemUI/res/values-de/strings.xml
    -@@ -240,7 +240,7 @@
    -     <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"4G-Daten pausiert"</string>
    -     <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"Mobilfunkdaten pausiert"</string>
    -     <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"Daten pausiert"</string>
    --    <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"Da dein festgelegtes Datenlimit erreicht wurde, hat das Gerät die Datennutzung für den Rest dieses Zeitraums pausiert.\n\nWenn du die Nutzung fortsetzt, entstehen möglicherweise Kosten bei deinem Mobilfunkanbieter."</string>
    -+    <string name="data_usage_disabled_dialog" msgid="1841738975235283398">"Das von dir festgelegte Datenlimit wurde erreicht. Die mobile Datennutzung wurde deaktiviert.\n\nWenn du weiterhin mobile Daten nutzt, können Gebühren anfallen."</string>
    -     <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"Fortsetzen"</string>
    -     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Keine Internetverbindung"</string>
    -     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"WLAN verbunden"</string>
    -@@ -271,7 +271,7 @@
    -     <string name="quick_settings_bluetooth_label" msgid="6304190285170721401">"Bluetooth"</string>
    -     <string name="quick_settings_bluetooth_multiple_devices_label" msgid="3912245565613684735">"Bluetooth (<xliff:g id="NUMBER">%d</xliff:g> Geräte)"</string>
    -     <string name="quick_settings_bluetooth_off_label" msgid="8159652146149219937">"Bluetooth aus"</string>
    --    <string name="quick_settings_bluetooth_detail_empty_text" msgid="4910015762433302860">"Keine Pairing-Geräte verfügbar"</string>
    -+    <string name="quick_settings_bluetooth_detail_empty_text" msgid="4910015762433302860">"Keine gekoppelten Geräte verfügbar"</string>
    -     <string name="quick_settings_brightness_label" msgid="6968372297018755815">"Helligkeit"</string>
    -     <string name="quick_settings_rotation_unlocked_label" msgid="7305323031808150099">"Automatisch drehen"</string>
    -     <string name="accessibility_quick_settings_rotation" msgid="4231661040698488779">"Bildschirm automatisch drehen"</string>
    -@@ -406,6 +406,7 @@
    -     <string name="device_owned_footer" msgid="3802752663326030053">"Aktivität auf dem Gerät kann vom Eigentümer protokolliert werden"</string>
    -     <string name="profile_owned_footer" msgid="8021888108553696069">"Profil wird möglicherweise überwacht."</string>
    -     <string name="vpn_footer" msgid="2388611096129106812">"Das Netzwerk wird möglicherweise überwacht."</string>
    -+    <string name="branded_vpn_footer" msgid="2168111859226496230">"Das Netzwerk wird möglicherweise überwacht"</string>
    -     <string name="monitoring_title_device_owned" msgid="7121079311903859610">"Geräteüberwachung"</string>
    -     <string name="monitoring_title_profile_owned" msgid="6790109874733501487">"Profilüberwachung"</string>
    -     <string name="monitoring_title" msgid="169206259253048106">"Netzwerküberwachung"</string>
    -@@ -418,6 +419,7 @@
    -     <string name="legacy_vpn_name" msgid="6604123105765737830">"VPN"</string>
    -     <string name="monitoring_description_app" msgid="6259179342284742878">"Du bist mit der App <xliff:g id="APPLICATION">%1$s</xliff:g> verbunden, die deine Netzwerkaktivität überwachen kann, einschließlich E-Mails, Apps und Websites."</string>
    -     <string name="monitoring_description_app_personal" msgid="484599052118316268">"Du bist mit der App <xliff:g id="APPLICATION">%1$s</xliff:g> verbunden, die deine persönliche Netzwerkaktivität überwachen kann, einschließlich E-Mails, Apps und Websites."</string>
    -+    <string name="branded_monitoring_description_app_personal" msgid="2669518213949202599">"Du bist mit der App \"<xliff:g id="APPLICATION">%1$s</xliff:g>\" verbunden. Diese kann deine persönlichen Netzwerkaktivitäten erfassen, einschließlich E-Mails, Apps und Websites."</string>
    -     <string name="monitoring_description_app_work" msgid="1754325860918060897">"Dein Arbeitsprofil wird von <xliff:g id="ORGANIZATION">%1$s</xliff:g> verwaltet. Das Profil ist mit der App <xliff:g id="APPLICATION">%2$s</xliff:g> verbunden, die deine geschäftlichen Netzwerkaktivitäten überwachen kann, einschließlich E-Mails, Apps und Websites.\n\nWeitere Informationen erhältst du von deinem Administrator."</string>
    -     <string name="monitoring_description_app_personal_work" msgid="4946600443852045903">"Dein Arbeitsprofil wird von <xliff:g id="ORGANIZATION">%1$s</xliff:g> verwaltet. Das Profil ist mit der App <xliff:g id="APPLICATION_WORK">%2$s</xliff:g> verbunden, die deine geschäftliche Netzwerkaktivität überwachen kann, einschließlich E-Mails, Apps und Websites.\n\nDu bist außerdem mit der App <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g> verbunden, die deine persönliche Netzwerkaktivität überwachen kann."</string>
    -     <string name="monitoring_description_vpn_app_device_owned" msgid="4970443827043261703">"Dein Gerät wird von <xliff:g id="ORGANIZATION">%1$s</xliff:g> verwaltet.\n\nDein Administrator kann die zu deinem Gerät gehörigen Einstellungen, Unternehmenszugriffsrechte, Apps und Daten überwachen und verwalten, einschließlich der Standortinformationen deines Geräts.\n\nDu bist außerdem mit der App <xliff:g id="APPLICATION">%2$s</xliff:g> verbunden, die deine persönliche Netzwerkaktivität überwachen kann, einschließlich E-Mails, Apps und Websites.\n\nWeitere Informationen erhältst du bei deinem Administrator."</string>
    -@@ -494,8 +496,6 @@
    -     <string name="clock_seconds_desc" msgid="6282693067130470675">"Uhrsekunden in der Statusleiste anzeigen. Kann sich auf die Akkulaufzeit auswirken."</string>
    -     <string name="qs_rearrange" msgid="8060918697551068765">"Schnelleinstellungen neu anordnen"</string>
    -     <string name="show_brightness" msgid="6613930842805942519">"Helligkeit in den Schnelleinstellungen anzeigen"</string>
    --    <string name="overview_nav_bar_gesture" msgid="8579814204727917764">"Teilen des Bildschirms durch Wischen nach oben aktivieren"</string>
    --    <string name="overview_nav_bar_gesture_desc" msgid="6329167382305102615">"Aktiviert die Bewegung zum Teilen des Bildschirms, bei der von der Schaltfläche \"Übersicht\" nach oben gewischt wird"</string>
    -     <string name="experimental" msgid="6198182315536726162">"Experimentell"</string>
    -     <string name="enable_bluetooth_title" msgid="5027037706500635269">"Bluetooth aktivieren?"</string>
    -     <string name="enable_bluetooth_message" msgid="9106595990708985385">"Zum Verbinden von Tastatur und Tablet muss Bluetooth aktiviert sein."</string>
    -@@ -653,4 +653,5 @@
    -     <string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"Einstellungen für <xliff:g id="ID_1">%s</xliff:g> öffnen."</string>
    -     <string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"Reihenfolge der Einstellungen bearbeiten."</string>
    -     <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"Seite <xliff:g id="ID_1">%1$d</xliff:g> von <xliff:g id="ID_2">%2$d</xliff:g>"</string>
    -+    <string name="cant_silence_or_block" msgid="999689262131488625">"Benachrichtigungen können nicht stummgeschaltet oder blockiert werden"</string>
    - </resources>
    -diff --git a/packages/SystemUI/res/values-el/strings.xml b/packages/SystemUI/res/values-el/strings.xml
    -index 0a327ab..a9b8bb5 100644
    ---- a/packages/SystemUI/res/values-el/strings.xml
    -+++ b/packages/SystemUI/res/values-el/strings.xml
    -@@ -163,7 +163,7 @@
    -     <string name="accessibility_battery_level_charging" msgid="1147587904439319646">"Φόρτιση μπαταρίας, <xliff:g id="BATTERY_PERCENTAGE">%d</xliff:g> τοις εκατό."</string>
    -     <string name="accessibility_settings_button" msgid="799583911231893380">"Ρυθμίσεις συστήματος."</string>
    -     <string name="accessibility_notifications_button" msgid="4498000369779421892">"Ειδοποιήσεις."</string>
    --    <string name="accessibility_remove_notification" msgid="3603099514902182350">"Εκκαθάριση ειδοποίησης."</string>
    -+    <string name="accessibility_remove_notification" msgid="3603099514902182350">"Διαγραφή ειδοποίησης."</string>
    -     <string name="accessibility_gps_enabled" msgid="3511469499240123019">"Το GPS ενεργοποιήθηκε."</string>
    -     <string name="accessibility_gps_acquiring" msgid="8959333351058967158">"Προσδιορισμός GPS."</string>
    -     <string name="accessibility_tty_enabled" msgid="4613200365379426561">"Το TeleTypewriter ενεργοποιήθηκε."</string>
    -@@ -238,14 +238,14 @@
    -     <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"Τα δεδομένα 4G τέθηκαν σε παύση"</string>
    -     <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"Τα δεδομένα κινητής τηλεφωνίας τέθηκαν σε παύση"</string>
    -     <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"Τα δεδομένα τέθηκαν σε παύση"</string>
    --    <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"Επειδή συμπληρώθηκε το όριο των δεδομένων που ορίστηκε για τη συσκευή σας, η χρήση δεδομένων τέθηκε σε παύση για το υπόλοιπο αυτού του κύκλου.\n\nΗ εκ νέου ενεργοποίησή τους ενδέχεται να επιφέρει χρεώσεις από την εταιρεία κινητής τηλεφωνίας σας."</string>
    -+    <string name="data_usage_disabled_dialog" msgid="1841738975235283398">"Το όριο δεδομένων που ορίσατε έχει εξαντληθεί. Δεν χρησιμοποιείτε πλέον δεδομένα κινητής τηλεφωνίας.\n\nΑν συνεχίσετε, ενδέχεται να ισχύσουν χρεώσεις για τη χρήση δεδομένων."</string>
    -     <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"Συνέχιση"</string>
    -     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Χωρ. σύνδ. στο Διαδ."</string>
    -     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi συνδεδεμένο"</string>
    -     <string name="gps_notification_searching_text" msgid="8574247005642736060">"Αναζήτηση για GPS"</string>
    -     <string name="gps_notification_found_text" msgid="4619274244146446464">"Ρύθμιση τοποθεσίας με GPS"</string>
    -     <string name="accessibility_location_active" msgid="2427290146138169014">"Τα αιτήματα τοποθεσίας έχουν ενεργοποιηθεί"</string>
    --    <string name="accessibility_clear_all" msgid="5235938559247164925">"Εκκαθάριση όλων των ειδοποιήσεων."</string>
    -+    <string name="accessibility_clear_all" msgid="5235938559247164925">"Διαγραφή όλων των ειδοποιήσεων."</string>
    -     <string name="notification_group_overflow_indicator" msgid="1863231301642314183">"+ <xliff:g id="NUMBER">%s</xliff:g>"</string>
    -     <plurals name="notification_group_overflow_description" formatted="false" msgid="4579313201268495404">
    -       <item quantity="other"><xliff:g id="NUMBER_1">%s</xliff:g> επιπλέον ειδοποιήσεις εντός της ομάδας.</item>
    -@@ -323,7 +323,7 @@
    -     <string name="quick_settings_night_display_summary_on" msgid="1814901757887526769">"Ο Νυχτερινός φωτισμός είναι ενεργοποιημένος. Πατήστε για απενεργοποίηση."</string>
    -     <string name="quick_settings_night_display_summary_off" msgid="7892102914128777905">"Ο Νυχτερινός φωτισμός είναι απενεργοποιημένος. Πατήστε για ενεργοποίηση."</string>
    -     <string name="recents_empty_message" msgid="808480104164008572">"Δεν υπάρχουν πρόσφατα στοιχεία"</string>
    --    <string name="recents_empty_message_dismissed_all" msgid="2791312568666558651">"Έχει γίνει εκκαθάριση όλων των στοιχείων"</string>
    -+    <string name="recents_empty_message_dismissed_all" msgid="2791312568666558651">"Έχει γίνει διαγραφή όλων των στοιχείων"</string>
    -     <string name="recents_app_info_button_label" msgid="2890317189376000030">"Πληροφορίες εφαρμογής"</string>
    -     <string name="recents_lock_to_app_button_label" msgid="6942899049072506044">"καρφίτσωμα οθόνης"</string>
    -     <string name="recents_search_bar_label" msgid="8074997400187836677">"αναζήτηση"</string>
    -@@ -404,6 +404,7 @@
    -     <string name="device_owned_footer" msgid="3802752663326030053">"Η συσκευή μπορεί να παρακολουθείται"</string>
    -     <string name="profile_owned_footer" msgid="8021888108553696069">"Το προφίλ ενδέχεται να παρακολουθείται"</string>
    -     <string name="vpn_footer" msgid="2388611096129106812">"Το δίκτυο ενδέχεται να παρακολουθείται"</string>
    -+    <string name="branded_vpn_footer" msgid="2168111859226496230">"Το δίκτυο ενδέχεται να παρακολουθείται"</string>
    -     <string name="monitoring_title_device_owned" msgid="7121079311903859610">"Παρακολούθηση συσκευής"</string>
    -     <string name="monitoring_title_profile_owned" msgid="6790109874733501487">"Παρακολούθηση προφίλ"</string>
    -     <string name="monitoring_title" msgid="169206259253048106">"Παρακολούθηση δικτύου"</string>
    -@@ -416,6 +417,7 @@
    -     <string name="legacy_vpn_name" msgid="6604123105765737830">"VPN"</string>
    -     <string name="monitoring_description_app" msgid="6259179342284742878">"Έχετε συνδεθεί στην εφαρμογή <xliff:g id="APPLICATION">%1$s</xliff:g>, η οποία μπορεί να παρακολουθεί τη δραστηριότητα του δικτύου σας, συμπεριλαμβανομένων μηνυμάτων ηλεκτρονικού ταχυδρομείου, εφαρμογών και ιστότοπων."</string>
    -     <string name="monitoring_description_app_personal" msgid="484599052118316268">"Έχετε συνδεθεί στην εφαρμογή <xliff:g id="APPLICATION">%1$s</xliff:g>, η οποία μπορεί να παρακολουθεί τη δραστηριότητα του προσωπικού σας δικτύου, συμπεριλαμβανομένων μηνυμάτων ηλεκτρονικού ταχυδρομείου, εφαρμογών και ιστότοπων."</string>
    -+    <string name="branded_monitoring_description_app_personal" msgid="2669518213949202599">"Έχετε συνδεθεί στην εφαρμογή <xliff:g id="APPLICATION">%1$s</xliff:g>, η οποία μπορεί να παρακολουθεί τη δραστηριότητα του προσωπικού σας δικτύου, συμπεριλαμβανομένων μηνυμάτων ηλεκτρονικού ταχυδρομείου, εφαρμογών και ιστοτόπων."</string>
    -     <string name="monitoring_description_app_work" msgid="1754325860918060897">"Η διαχείριση του προφίλ εργασίας γίνεται από τον οργανισμό <xliff:g id="ORGANIZATION">%1$s</xliff:g>. Είναι συνδεδεμένο στην εφαρμογή <xliff:g id="APPLICATION">%2$s</xliff:g>, η οποία μπορεί να παρακολουθεί τη δραστηριότητα του δικτύου εργασίας, συμπεριλαμβανομένων μηνυμάτων ηλεκτρονικού ταχυδρομείου, εφαρμογών και ιστότοπων.\n\nΓια περισσότερες πληροφορίες, επικοινωνήστε με το διαχειριστή."</string>
    -     <string name="monitoring_description_app_personal_work" msgid="4946600443852045903">"Η διαχείριση του προφίλ εργασίας γίνεται από τον οργανισμό <xliff:g id="ORGANIZATION">%1$s</xliff:g>. Είναι συνδεδεμένο στην εφαρμογή <xliff:g id="APPLICATION_WORK">%2$s</xliff:g>, η οποία μπορεί να παρακολουθεί τη δραστηριότητα του δικτύου εργασίας, συμπεριλαμβανομένων μηνυμάτων ηλεκτρονικού ταχυδρομείου, εφαρμογών και ιστότοπων.\n\nΕπίσης, είστε συνδεδεμένοι στην εφαρμογή <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g>, η οποία μπορεί να παρακολουθεί τη δραστηριότητα του προσωπικού σας δικτύου."</string>
    -     <string name="monitoring_description_vpn_app_device_owned" msgid="4970443827043261703">"Η διαχείριση της συσκευής γίνεται από <xliff:g id="ORGANIZATION">%1$s</xliff:g>.\n\nΟ διαχειριστής μπορεί να παρακολουθεί και να διαχειρίζεται ρυθμίσεις, εταιρική πρόσβαση, εφαρμογές, δεδομένα σχετικά με τη συσκευή και πληρ. τοποθεσίας της συσκευής.\n\nΕίστε συνδεδ. σε <xliff:g id="APPLICATION">%2$s</xliff:g> που μπορεί να παρακολουθεί τη δραστηρ. του δικτύου εργασίας, όπως μηνύματα ηλεκτρ. ταχυδρομείου, εφαρμογές και ιστότοπους.\n\nΓια περισ. πληροφορίες, επικοινωνήστε με το διαχειριστή."</string>
    -@@ -436,7 +438,7 @@
    -     <string name="quick_settings_reset_confirmation_message" msgid="2235970126803317374">"Θα εμφανιστεί ξανά την επόμενη φορά που θα το ενεργοποιήσετε στις ρυθμίσεις."</string>
    -     <string name="quick_settings_reset_confirmation_button" msgid="2660339101868367515">"Απόκρυψη"</string>
    -     <string name="volumeui_prompt_message" msgid="918680947433389110">"Η εφαρμογή <xliff:g id="APP_NAME">%1$s</xliff:g> θέλει να γίνει το παράθυρο διαλόγου ελέγχου έντασης"</string>
    --    <string name="volumeui_prompt_allow" msgid="7954396902482228786">"Να επιτραπεί"</string>
    -+    <string name="volumeui_prompt_allow" msgid="7954396902482228786">"Να επιτρέπεται"</string>
    -     <string name="volumeui_prompt_deny" msgid="5720663643411696731">"Απόρριψη"</string>
    -     <string name="volumeui_notification_title" msgid="4906770126345910955">"Η εφαρμογή <xliff:g id="APP_NAME">%1$s</xliff:g> αποτελεί το παράθυρο διαλόγου ελέγχου έντασης"</string>
    -     <string name="volumeui_notification_text" msgid="8819536904234337445">"Πατήστε για να επαναφέρετε την αρχική μορφή της εικόνας."</string>
    -@@ -492,8 +494,6 @@
    -     <string name="clock_seconds_desc" msgid="6282693067130470675">"Εμφάνιση δευτερολέπτων ρολογιού στη γραμμή κατάστασης. Ενδέχεται να επηρεάσει τη διάρκεια ζωής της μπαταρίας."</string>
    -     <string name="qs_rearrange" msgid="8060918697551068765">"Αναδιάταξη Γρήγορων ρυθμίσεων"</string>
    -     <string name="show_brightness" msgid="6613930842805942519">"Εμφάνιση φωτεινότητας στις Γρήγορες ρυθμίσεις"</string>
    --    <string name="overview_nav_bar_gesture" msgid="8579814204727917764">"Ενεργοποίηση κίνησης ολίσθησης επάνω για διαχωρισμό οθόνης"</string>
    --    <string name="overview_nav_bar_gesture_desc" msgid="6329167382305102615">"Ενεργοποίηση κίνησης για μετάβαση σε διαχωρισμό οθόνης μέσω ολίσθησης επάνω από το κουμπί \"Επισκόπηση\""</string>
    -     <string name="experimental" msgid="6198182315536726162">"Σε πειραματικό στάδιο"</string>
    -     <string name="enable_bluetooth_title" msgid="5027037706500635269">"Ενεργοποίηση Bluetooth;"</string>
    -     <string name="enable_bluetooth_message" msgid="9106595990708985385">"Για να συνδέσετε το πληκτρολόγιο με το tablet σας, θα πρέπει πρώτα να ενεργοποιήσετε το Bluetooth."</string>
    -@@ -651,4 +651,5 @@
    -     <string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"Άνοιγμα ρυθμίσεων <xliff:g id="ID_1">%s</xliff:g>."</string>
    -     <string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"Επεξεργασία σειράς ρυθμίσεων."</string>
    -     <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"Σελίδα <xliff:g id="ID_1">%1$d</xliff:g> από <xliff:g id="ID_2">%2$d</xliff:g>"</string>
    -+    <string name="cant_silence_or_block" msgid="999689262131488625">"Δεν είναι δυνατή η σίγαση ή ο αποκλεισμός των ειδοποιήσεων"</string>
    - </resources>
    -diff --git a/packages/SystemUI/res/values-en-rAU/strings.xml b/packages/SystemUI/res/values-en-rAU/strings.xml
    -index 9443ad9..bed0f5c 100644
    ---- a/packages/SystemUI/res/values-en-rAU/strings.xml
    -+++ b/packages/SystemUI/res/values-en-rAU/strings.xml
    -@@ -238,7 +238,7 @@
    -     <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"4G data is paused"</string>
    -     <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"Mobile data is paused"</string>
    -     <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"Data is paused"</string>
    --    <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"Because your set data limit was reached, the device has paused data usage for the remainder of this cycle.\n\nResuming may lead to charges from your operator."</string>
    -+    <string name="data_usage_disabled_dialog" msgid="1841738975235283398">"The data limit you have set has been reached. You are no longer using mobile data.\n\nIf you resume, charges may apply for data usage."</string>
    -     <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"Resume"</string>
    -     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"No Internet connection"</string>
    -     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi connected"</string>
    -@@ -404,6 +404,7 @@
    -     <string name="device_owned_footer" msgid="3802752663326030053">"Device may be monitored"</string>
    -     <string name="profile_owned_footer" msgid="8021888108553696069">"Profile may be monitored"</string>
    -     <string name="vpn_footer" msgid="2388611096129106812">"Network may be monitored"</string>
    -+    <string name="branded_vpn_footer" msgid="2168111859226496230">"Network may be monitored"</string>
    -     <string name="monitoring_title_device_owned" msgid="7121079311903859610">"Device monitoring"</string>
    -     <string name="monitoring_title_profile_owned" msgid="6790109874733501487">"Profile monitoring"</string>
    -     <string name="monitoring_title" msgid="169206259253048106">"Network monitoring"</string>
    -@@ -416,6 +417,7 @@
    -     <string name="legacy_vpn_name" msgid="6604123105765737830">"VPN"</string>
    -     <string name="monitoring_description_app" msgid="6259179342284742878">"You\'re connected to <xliff:g id="APPLICATION">%1$s</xliff:g>, which can monitor your network activity including emails, apps and websites."</string>
    -     <string name="monitoring_description_app_personal" msgid="484599052118316268">"You\'re connected to <xliff:g id="APPLICATION">%1$s</xliff:g>, which can monitor your personal network activity, including emails, apps and websites."</string>
    -+    <string name="branded_monitoring_description_app_personal" msgid="2669518213949202599">"You\'re connected to <xliff:g id="APPLICATION">%1$s</xliff:g>, which can monitor your personal network activity, including emails, apps and websites."</string>
    -     <string name="monitoring_description_app_work" msgid="1754325860918060897">"Your work profile is managed by <xliff:g id="ORGANIZATION">%1$s</xliff:g>. It is connected to <xliff:g id="APPLICATION">%2$s</xliff:g>, which can monitor your work network activity, including emails, apps and websites.\n\nFor more information, contact your administrator."</string>
    -     <string name="monitoring_description_app_personal_work" msgid="4946600443852045903">"Your work profile is managed by <xliff:g id="ORGANIZATION">%1$s</xliff:g>. It is connected to <xliff:g id="APPLICATION_WORK">%2$s</xliff:g>, which can monitor your work network activity, including emails, apps and websites.\n\nYou\'re also connected to <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g>, which can monitor your personal network activity."</string>
    -     <string name="monitoring_description_vpn_app_device_owned" msgid="4970443827043261703">"Your device is managed by <xliff:g id="ORGANIZATION">%1$s</xliff:g>.\n\nYour administrator can monitor and manage settings, corporate access, apps, data associated with your device, and your device\'s location information.\n\nYou\'re connected to <xliff:g id="APPLICATION">%2$s</xliff:g>, which can monitor your network activity, including emails, apps, and websites.\n\nFor more information, contact your administrator."</string>
    -@@ -492,8 +494,6 @@
    -     <string name="clock_seconds_desc" msgid="6282693067130470675">"Show clock seconds in the status bar. May impact battery life."</string>
    -     <string name="qs_rearrange" msgid="8060918697551068765">"Rearrange Quick Settings"</string>
    -     <string name="show_brightness" msgid="6613930842805942519">"Show brightness in Quick Settings"</string>
    --    <string name="overview_nav_bar_gesture" msgid="8579814204727917764">"Enable split-screen swipe-up gesture"</string>
    --    <string name="overview_nav_bar_gesture_desc" msgid="6329167382305102615">"Enable gesture to enter split-screen by swiping up from the Overview button"</string>
    -     <string name="experimental" msgid="6198182315536726162">"Experimental"</string>
    -     <string name="enable_bluetooth_title" msgid="5027037706500635269">"Turn on Bluetooth?"</string>
    -     <string name="enable_bluetooth_message" msgid="9106595990708985385">"To connect your keyboard with your tablet, you first have to turn on Bluetooth."</string>
    -@@ -651,4 +651,5 @@
    -     <string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"Open <xliff:g id="ID_1">%s</xliff:g> settings."</string>
    -     <string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"Edit order of settings."</string>
    -     <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"Page <xliff:g id="ID_1">%1$d</xliff:g> of <xliff:g id="ID_2">%2$d</xliff:g>"</string>
    -+    <string name="cant_silence_or_block" msgid="999689262131488625">"Notifications can\'t be silenced or blocked"</string>
    - </resources>
    -diff --git a/packages/SystemUI/res/values-en-rGB/strings.xml b/packages/SystemUI/res/values-en-rGB/strings.xml
    -index 9443ad9..bed0f5c 100644
    ---- a/packages/SystemUI/res/values-en-rGB/strings.xml
    -+++ b/packages/SystemUI/res/values-en-rGB/strings.xml
    -@@ -238,7 +238,7 @@
    -     <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"4G data is paused"</string>
    -     <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"Mobile data is paused"</string>
    -     <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"Data is paused"</string>
    --    <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"Because your set data limit was reached, the device has paused data usage for the remainder of this cycle.\n\nResuming may lead to charges from your operator."</string>
    -+    <string name="data_usage_disabled_dialog" msgid="1841738975235283398">"The data limit you have set has been reached. You are no longer using mobile data.\n\nIf you resume, charges may apply for data usage."</string>
    -     <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"Resume"</string>
    -     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"No Internet connection"</string>
    -     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi connected"</string>
    -@@ -404,6 +404,7 @@
    -     <string name="device_owned_footer" msgid="3802752663326030053">"Device may be monitored"</string>
    -     <string name="profile_owned_footer" msgid="8021888108553696069">"Profile may be monitored"</string>
    -     <string name="vpn_footer" msgid="2388611096129106812">"Network may be monitored"</string>
    -+    <string name="branded_vpn_footer" msgid="2168111859226496230">"Network may be monitored"</string>
    -     <string name="monitoring_title_device_owned" msgid="7121079311903859610">"Device monitoring"</string>
    -     <string name="monitoring_title_profile_owned" msgid="6790109874733501487">"Profile monitoring"</string>
    -     <string name="monitoring_title" msgid="169206259253048106">"Network monitoring"</string>
    -@@ -416,6 +417,7 @@
    -     <string name="legacy_vpn_name" msgid="6604123105765737830">"VPN"</string>
    -     <string name="monitoring_description_app" msgid="6259179342284742878">"You\'re connected to <xliff:g id="APPLICATION">%1$s</xliff:g>, which can monitor your network activity including emails, apps and websites."</string>
    -     <string name="monitoring_description_app_personal" msgid="484599052118316268">"You\'re connected to <xliff:g id="APPLICATION">%1$s</xliff:g>, which can monitor your personal network activity, including emails, apps and websites."</string>
    -+    <string name="branded_monitoring_description_app_personal" msgid="2669518213949202599">"You\'re connected to <xliff:g id="APPLICATION">%1$s</xliff:g>, which can monitor your personal network activity, including emails, apps and websites."</string>
    -     <string name="monitoring_description_app_work" msgid="1754325860918060897">"Your work profile is managed by <xliff:g id="ORGANIZATION">%1$s</xliff:g>. It is connected to <xliff:g id="APPLICATION">%2$s</xliff:g>, which can monitor your work network activity, including emails, apps and websites.\n\nFor more information, contact your administrator."</string>
    -     <string name="monitoring_description_app_personal_work" msgid="4946600443852045903">"Your work profile is managed by <xliff:g id="ORGANIZATION">%1$s</xliff:g>. It is connected to <xliff:g id="APPLICATION_WORK">%2$s</xliff:g>, which can monitor your work network activity, including emails, apps and websites.\n\nYou\'re also connected to <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g>, which can monitor your personal network activity."</string>
    -     <string name="monitoring_description_vpn_app_device_owned" msgid="4970443827043261703">"Your device is managed by <xliff:g id="ORGANIZATION">%1$s</xliff:g>.\n\nYour administrator can monitor and manage settings, corporate access, apps, data associated with your device, and your device\'s location information.\n\nYou\'re connected to <xliff:g id="APPLICATION">%2$s</xliff:g>, which can monitor your network activity, including emails, apps, and websites.\n\nFor more information, contact your administrator."</string>
    -@@ -492,8 +494,6 @@
    -     <string name="clock_seconds_desc" msgid="6282693067130470675">"Show clock seconds in the status bar. May impact battery life."</string>
    -     <string name="qs_rearrange" msgid="8060918697551068765">"Rearrange Quick Settings"</string>
    -     <string name="show_brightness" msgid="6613930842805942519">"Show brightness in Quick Settings"</string>
    --    <string name="overview_nav_bar_gesture" msgid="8579814204727917764">"Enable split-screen swipe-up gesture"</string>
    --    <string name="overview_nav_bar_gesture_desc" msgid="6329167382305102615">"Enable gesture to enter split-screen by swiping up from the Overview button"</string>
    -     <string name="experimental" msgid="6198182315536726162">"Experimental"</string>
    -     <string name="enable_bluetooth_title" msgid="5027037706500635269">"Turn on Bluetooth?"</string>
    -     <string name="enable_bluetooth_message" msgid="9106595990708985385">"To connect your keyboard with your tablet, you first have to turn on Bluetooth."</string>
    -@@ -651,4 +651,5 @@
    -     <string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"Open <xliff:g id="ID_1">%s</xliff:g> settings."</string>
    -     <string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"Edit order of settings."</string>
    -     <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"Page <xliff:g id="ID_1">%1$d</xliff:g> of <xliff:g id="ID_2">%2$d</xliff:g>"</string>
    -+    <string name="cant_silence_or_block" msgid="999689262131488625">"Notifications can\'t be silenced or blocked"</string>
    - </resources>
    -diff --git a/packages/SystemUI/res/values-en-rIN/strings.xml b/packages/SystemUI/res/values-en-rIN/strings.xml
    -index 9443ad9..bed0f5c 100644
    ---- a/packages/SystemUI/res/values-en-rIN/strings.xml
    -+++ b/packages/SystemUI/res/values-en-rIN/strings.xml
    -@@ -238,7 +238,7 @@
    -     <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"4G data is paused"</string>
    -     <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"Mobile data is paused"</string>
    -     <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"Data is paused"</string>
    --    <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"Because your set data limit was reached, the device has paused data usage for the remainder of this cycle.\n\nResuming may lead to charges from your operator."</string>
    -+    <string name="data_usage_disabled_dialog" msgid="1841738975235283398">"The data limit you have set has been reached. You are no longer using mobile data.\n\nIf you resume, charges may apply for data usage."</string>
    -     <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"Resume"</string>
    -     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"No Internet connection"</string>
    -     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi connected"</string>
    -@@ -404,6 +404,7 @@
    -     <string name="device_owned_footer" msgid="3802752663326030053">"Device may be monitored"</string>
    -     <string name="profile_owned_footer" msgid="8021888108553696069">"Profile may be monitored"</string>
    -     <string name="vpn_footer" msgid="2388611096129106812">"Network may be monitored"</string>
    -+    <string name="branded_vpn_footer" msgid="2168111859226496230">"Network may be monitored"</string>
    -     <string name="monitoring_title_device_owned" msgid="7121079311903859610">"Device monitoring"</string>
    -     <string name="monitoring_title_profile_owned" msgid="6790109874733501487">"Profile monitoring"</string>
    -     <string name="monitoring_title" msgid="169206259253048106">"Network monitoring"</string>
    -@@ -416,6 +417,7 @@
    -     <string name="legacy_vpn_name" msgid="6604123105765737830">"VPN"</string>
    -     <string name="monitoring_description_app" msgid="6259179342284742878">"You\'re connected to <xliff:g id="APPLICATION">%1$s</xliff:g>, which can monitor your network activity including emails, apps and websites."</string>
    -     <string name="monitoring_description_app_personal" msgid="484599052118316268">"You\'re connected to <xliff:g id="APPLICATION">%1$s</xliff:g>, which can monitor your personal network activity, including emails, apps and websites."</string>
    -+    <string name="branded_monitoring_description_app_personal" msgid="2669518213949202599">"You\'re connected to <xliff:g id="APPLICATION">%1$s</xliff:g>, which can monitor your personal network activity, including emails, apps and websites."</string>
    -     <string name="monitoring_description_app_work" msgid="1754325860918060897">"Your work profile is managed by <xliff:g id="ORGANIZATION">%1$s</xliff:g>. It is connected to <xliff:g id="APPLICATION">%2$s</xliff:g>, which can monitor your work network activity, including emails, apps and websites.\n\nFor more information, contact your administrator."</string>
    -     <string name="monitoring_description_app_personal_work" msgid="4946600443852045903">"Your work profile is managed by <xliff:g id="ORGANIZATION">%1$s</xliff:g>. It is connected to <xliff:g id="APPLICATION_WORK">%2$s</xliff:g>, which can monitor your work network activity, including emails, apps and websites.\n\nYou\'re also connected to <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g>, which can monitor your personal network activity."</string>
    -     <string name="monitoring_description_vpn_app_device_owned" msgid="4970443827043261703">"Your device is managed by <xliff:g id="ORGANIZATION">%1$s</xliff:g>.\n\nYour administrator can monitor and manage settings, corporate access, apps, data associated with your device, and your device\'s location information.\n\nYou\'re connected to <xliff:g id="APPLICATION">%2$s</xliff:g>, which can monitor your network activity, including emails, apps, and websites.\n\nFor more information, contact your administrator."</string>
    -@@ -492,8 +494,6 @@
    -     <string name="clock_seconds_desc" msgid="6282693067130470675">"Show clock seconds in the status bar. May impact battery life."</string>
    -     <string name="qs_rearrange" msgid="8060918697551068765">"Rearrange Quick Settings"</string>
    -     <string name="show_brightness" msgid="6613930842805942519">"Show brightness in Quick Settings"</string>
    --    <string name="overview_nav_bar_gesture" msgid="8579814204727917764">"Enable split-screen swipe-up gesture"</string>
    --    <string name="overview_nav_bar_gesture_desc" msgid="6329167382305102615">"Enable gesture to enter split-screen by swiping up from the Overview button"</string>
    -     <string name="experimental" msgid="6198182315536726162">"Experimental"</string>
    -     <string name="enable_bluetooth_title" msgid="5027037706500635269">"Turn on Bluetooth?"</string>
    -     <string name="enable_bluetooth_message" msgid="9106595990708985385">"To connect your keyboard with your tablet, you first have to turn on Bluetooth."</string>
    -@@ -651,4 +651,5 @@
    -     <string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"Open <xliff:g id="ID_1">%s</xliff:g> settings."</string>
    -     <string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"Edit order of settings."</string>
    -     <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"Page <xliff:g id="ID_1">%1$d</xliff:g> of <xliff:g id="ID_2">%2$d</xliff:g>"</string>
    -+    <string name="cant_silence_or_block" msgid="999689262131488625">"Notifications can\'t be silenced or blocked"</string>
    - </resources>
    -diff --git a/packages/SystemUI/res/values-es-rUS/strings.xml b/packages/SystemUI/res/values-es-rUS/strings.xml
    -index 602d6b2..485d2e0 100644
    ---- a/packages/SystemUI/res/values-es-rUS/strings.xml
    -+++ b/packages/SystemUI/res/values-es-rUS/strings.xml
    -@@ -240,7 +240,7 @@
    -     <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"Datos 4G pausados"</string>
    -     <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"Datos móviles pausados"</string>
    -     <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"Datos pausados"</string>
    --    <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"Debido que se alcanzó el límite de datos establecido, el dispositivo pausó el uso de datos para el resto de este ciclo.\n\nLa reanudación podría tener como resultado cargos del proveedor."</string>
    -+    <string name="data_usage_disabled_dialog" msgid="1841738975235283398">"Se alcanzó el límite de datos que estableciste. Ya no estás usando datos móviles.\n\nSi reanudas el uso de datos, es posible que se apliquen cargos."</string>
    -     <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"Reanudar"</string>
    -     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Sin conexión a Internet"</string>
    -     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi conectado"</string>
    -@@ -406,6 +406,7 @@
    -     <string name="device_owned_footer" msgid="3802752663326030053">"Es posible que el dispositivo esté supervisado."</string>
    -     <string name="profile_owned_footer" msgid="8021888108553696069">"Es posible que se supervise el perfil."</string>
    -     <string name="vpn_footer" msgid="2388611096129106812">"Es posible que la red esté supervisada."</string>
    -+    <string name="branded_vpn_footer" msgid="2168111859226496230">"Es posible que la red esté supervisada"</string>
    -     <string name="monitoring_title_device_owned" msgid="7121079311903859610">"Supervisión del dispositivo"</string>
    -     <string name="monitoring_title_profile_owned" msgid="6790109874733501487">"Supervisión del perfil"</string>
    -     <string name="monitoring_title" msgid="169206259253048106">"Supervisión de red"</string>
    -@@ -418,6 +419,7 @@
    -     <string name="legacy_vpn_name" msgid="6604123105765737830">"VPN"</string>
    -     <string name="monitoring_description_app" msgid="6259179342284742878">"Tienes conexión a la aplicación <xliff:g id="APPLICATION">%1$s</xliff:g>, que puede supervisar la actividad de la red, incluidos los correos electrónicos, las aplicaciones y los sitios web."</string>
    -     <string name="monitoring_description_app_personal" msgid="484599052118316268">"Tienes conexión a la aplicación <xliff:g id="APPLICATION">%1$s</xliff:g>, que puede supervisar la actividad de la red personal, incluidos los correos electrónicos, las aplicaciones y los sitios web."</string>
    -+    <string name="branded_monitoring_description_app_personal" msgid="2669518213949202599">"Te conectaste a <xliff:g id="APPLICATION">%1$s</xliff:g>, que puede supervisar la actividad de tu red personal, incluidos los correos electrónicos, las apps y los sitios web."</string>
    -     <string name="monitoring_description_app_work" msgid="1754325860918060897">"<xliff:g id="ORGANIZATION">%1$s</xliff:g> administra tu perfil de trabajo. Tiene conexión a <xliff:g id="APPLICATION">%2$s</xliff:g>, que puede supervisar la actividad de tu red de trabajo, incluidos los correos electrónicos, las aplicaciones y los sitios web.\n\nPara obtener más información, comunícate con el administrador."</string>
    -     <string name="monitoring_description_app_personal_work" msgid="4946600443852045903">"<xliff:g id="ORGANIZATION">%1$s</xliff:g> administra tu perfil de trabajo. Tiene conexión a <xliff:g id="APPLICATION_WORK">%2$s</xliff:g>, que puede supervisar la actividad de tu red de trabajo, incluidos los correos electrónicos, las aplicaciones y los sitios web.\n\nTambién tienes conexión a <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g>, que puede supervisar la actividad de la red personal."</string>
    -     <string name="monitoring_description_vpn_app_device_owned" msgid="4970443827043261703">"<xliff:g id="ORGANIZATION">%1$s</xliff:g> administra tu dispositivo.\n\nEl administrador puede supervisar y administrar la configuración, el acceso corporativo, las aplicaciones, los datos asociados al dispositivo y la información de la ubicación.\n\nTienes conexión a <xliff:g id="APPLICATION">%2$s</xliff:g>, que puede supervisar la actividad de la red, incluidos los correos electrónicos, las aplicaciones y los sitios web.\n\nPara obtener más información, comunícate con el administrador."</string>
    -@@ -494,8 +496,6 @@
    -     <string name="clock_seconds_desc" msgid="6282693067130470675">"Muestra los segundos del reloj en la barra de estado. Puede afectar la duración de la batería."</string>
    -     <string name="qs_rearrange" msgid="8060918697551068765">"Reorganizar la Configuración rápida"</string>
    -     <string name="show_brightness" msgid="6613930842805942519">"Mostrar el brillo en la Configuración rápida"</string>
    --    <string name="overview_nav_bar_gesture" msgid="8579814204727917764">"Habilitar gesto de dedo hacia arriba para dividir pantalla"</string>
    --    <string name="overview_nav_bar_gesture_desc" msgid="6329167382305102615">"Habilita el gesto de deslizar el dedo hacia arriba desde el botón Recientes para acceder al modo de pantalla dividida"</string>
    -     <string name="experimental" msgid="6198182315536726162">"Experimental"</string>
    -     <string name="enable_bluetooth_title" msgid="5027037706500635269">"¿Activar Bluetooth?"</string>
    -     <string name="enable_bluetooth_message" msgid="9106595990708985385">"Para conectar el teclado con la tablet, primero debes activar Bluetooth."</string>
    -@@ -653,4 +653,5 @@
    -     <string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"Abrir configuración de <xliff:g id="ID_1">%s</xliff:g>"</string>
    -     <string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"Editar orden de configuración"</string>
    -     <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"Página <xliff:g id="ID_1">%1$d</xliff:g> de <xliff:g id="ID_2">%2$d</xliff:g>"</string>
    -+    <string name="cant_silence_or_block" msgid="999689262131488625">"Las notificaciones no se pueden silenciar ni bloquear"</string>
    - </resources>
    -diff --git a/packages/SystemUI/res/values-es/strings.xml b/packages/SystemUI/res/values-es/strings.xml
    -index ba11d6f..0e0f412 100644
    ---- a/packages/SystemUI/res/values-es/strings.xml
    -+++ b/packages/SystemUI/res/values-es/strings.xml
    -@@ -233,14 +233,14 @@
    -     <string name="accessibility_quick_settings_work_mode_on" msgid="7650588553988014341">"Modo de trabajo activado."</string>
    -     <string name="accessibility_quick_settings_work_mode_changed_off" msgid="5605534876107300711">"Modo de trabajo desactivado."</string>
    -     <string name="accessibility_quick_settings_work_mode_changed_on" msgid="249840330756998612">"Modo de trabajo activado."</string>
    --    <string name="accessibility_quick_settings_data_saver_changed_off" msgid="650231949881093289">"Economizador de Datos desactivado."</string>
    --    <string name="accessibility_quick_settings_data_saver_changed_on" msgid="4218725402373934151">"Economizador de Datos activado."</string>
    -+    <string name="accessibility_quick_settings_data_saver_changed_off" msgid="650231949881093289">"Ahorro de datos desactivado."</string>
    -+    <string name="accessibility_quick_settings_data_saver_changed_on" msgid="4218725402373934151">"Ahorro de datos activado."</string>
    -     <string name="accessibility_brightness" msgid="8003681285547803095">"Brillo de la pantalla"</string>
    -     <string name="data_usage_disabled_dialog_3g_title" msgid="5281770593459841889">"Datos 2G-3G pausados"</string>
    -     <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"Datos 4G pausados"</string>
    -     <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"Datos móviles pausados"</string>
    -     <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"Datos pausados"</string>
    --    <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"Has alcanzado el límite de datos establecido, por lo que el dispositivo ha pausado el uso de datos para el resto de este ciclo.\n\nSi lo reanudas, el operador puede facturar cargos."</string>
    -+    <string name="data_usage_disabled_dialog" msgid="1841738975235283398">"Se ha alcanzado el límite de datos establecido. Ya no estás utilizando datos móviles.\n\nSi vuelves a activar el uso de datos, es posible que se apliquen cargos."</string>
    -     <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"Reanudar"</string>
    -     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Sin conexión a Internet"</string>
    -     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Con conexión Wi-Fi"</string>
    -@@ -406,6 +406,7 @@
    -     <string name="device_owned_footer" msgid="3802752663326030053">"Es posible que este dispositivo esté supervisado"</string>
    -     <string name="profile_owned_footer" msgid="8021888108553696069">"Es posible que se supervise el perfil"</string>
    -     <string name="vpn_footer" msgid="2388611096129106812">"Puede que la red esté supervisada"</string>
    -+    <string name="branded_vpn_footer" msgid="2168111859226496230">"Puede que la red esté supervisada"</string>
    -     <string name="monitoring_title_device_owned" msgid="7121079311903859610">"Supervisión de dispositivo"</string>
    -     <string name="monitoring_title_profile_owned" msgid="6790109874733501487">"Supervisión del perfil"</string>
    -     <string name="monitoring_title" msgid="169206259253048106">"Supervisión de red"</string>
    -@@ -418,6 +419,7 @@
    -     <string name="legacy_vpn_name" msgid="6604123105765737830">"VPN"</string>
    -     <string name="monitoring_description_app" msgid="6259179342284742878">"Estás conectado a <xliff:g id="APPLICATION">%1$s</xliff:g>, que puede controlar tu actividad de red, como correos electrónicos, aplicaciones y sitios web."</string>
    -     <string name="monitoring_description_app_personal" msgid="484599052118316268">"Estas conectado a <xliff:g id="APPLICATION">%1$s</xliff:g>, que puede controlar tu actividad de red personal, como correos electrónicos, aplicaciones y sitios web."</string>
    -+    <string name="branded_monitoring_description_app_personal" msgid="2669518213949202599">"Estas conectado a <xliff:g id="APPLICATION">%1$s</xliff:g>, que puede controlar tu actividad de red personal, como correos electrónicos, aplicaciones y sitios web."</string>
    -     <string name="monitoring_description_app_work" msgid="1754325860918060897">"El administrador de tu perfil de trabajo es <xliff:g id="ORGANIZATION">%1$s</xliff:g> y está conectado a <xliff:g id="APPLICATION">%2$s</xliff:g>, que puede controlar tu actividad de red del trabajo, como correos electrónicos, aplicaciones y sitios web.\n\nPara obtener más información, ponte en contacto con el administrador."</string>
    -     <string name="monitoring_description_app_personal_work" msgid="4946600443852045903">"El administrador de tu perfil de trabajo es <xliff:g id="ORGANIZATION">%1$s</xliff:g> y está conectado a <xliff:g id="APPLICATION_WORK">%2$s</xliff:g>, que puede controlar tu actividad de red, como correos electrónicos, aplicaciones y sitios web.\n\nTú también estás conectado a <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g>, que puede controlar tu actividad de red personal."</string>
    -     <string name="monitoring_description_vpn_app_device_owned" msgid="4970443827043261703">"El administrador de tu dispositivo es <xliff:g id="ORGANIZATION">%1$s</xliff:g>.\n\nTu administrador puede supervisar y administrar los ajustes, el acceso corporativo, las aplicaciones, los datos asociados al dispositivo e información de su ubicación.\n\nEstás conectado a <xliff:g id="APPLICATION">%2$s</xliff:g>, que puede supervisar tu actividad de red, como correos electrónicos, aplicaciones y sitios web.\n\nPara obtener más información, ponte en contacto con tu administrador."</string>
    -@@ -494,8 +496,6 @@
    -     <string name="clock_seconds_desc" msgid="6282693067130470675">"Muestra los segundos del reloj en la barra de estado. Puede afectar a la duración de la batería."</string>
    -     <string name="qs_rearrange" msgid="8060918697551068765">"Reorganizar Ajustes rápidos"</string>
    -     <string name="show_brightness" msgid="6613930842805942519">"Mostrar brillo en Ajustes rápidos"</string>
    --    <string name="overview_nav_bar_gesture" msgid="8579814204727917764">"Habilitar deslizar dedo hacia arriba para dividir pantalla"</string>
    --    <string name="overview_nav_bar_gesture_desc" msgid="6329167382305102615">"Habilita el gesto de deslizar el dedo hacia arriba desde el botón Aplicaciones recientes para acceder al modo de pantalla dividida"</string>
    -     <string name="experimental" msgid="6198182315536726162">"Experimental"</string>
    -     <string name="enable_bluetooth_title" msgid="5027037706500635269">"¿Activar Bluetooth?"</string>
    -     <string name="enable_bluetooth_message" msgid="9106595990708985385">"Para poder conectar tu teclado a tu tablet, debes activar el Bluetooth."</string>
    -@@ -580,9 +580,9 @@
    -     <string name="headset" msgid="4534219457597457353">"Auriculares"</string>
    -     <string name="accessibility_status_bar_headphones" msgid="9156307120060559989">"Auriculares conectados"</string>
    -     <string name="accessibility_status_bar_headset" msgid="8666419213072449202">"Auriculares conectados"</string>
    --    <string name="data_saver" msgid="5037565123367048522">"Economizador de Datos"</string>
    --    <string name="accessibility_data_saver_on" msgid="8454111686783887148">"Economizador de Datos activado"</string>
    --    <string name="accessibility_data_saver_off" msgid="8841582529453005337">"Economizador de Datos desactivado"</string>
    -+    <string name="data_saver" msgid="5037565123367048522">"Ahorro de datos"</string>
    -+    <string name="accessibility_data_saver_on" msgid="8454111686783887148">"Ahorro de datos activado"</string>
    -+    <string name="accessibility_data_saver_off" msgid="8841582529453005337">"Ahorro de datos desactivado"</string>
    -     <string name="switch_bar_on" msgid="1142437840752794229">"Sí"</string>
    -     <string name="switch_bar_off" msgid="8803270596930432874">"No"</string>
    -     <string name="nav_bar" msgid="1993221402773877607">"Barra de navegación"</string>
    -@@ -653,4 +653,5 @@
    -     <string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"Abrir ajustes de <xliff:g id="ID_1">%s</xliff:g>."</string>
    -     <string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"Cambiar el orden de los ajustes."</string>
    -     <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"Página <xliff:g id="ID_1">%1$d</xliff:g> de <xliff:g id="ID_2">%2$d</xliff:g>"</string>
    -+    <string name="cant_silence_or_block" msgid="999689262131488625">"Las notificaciones no se pueden silenciar ni bloquear"</string>
    - </resources>
    -diff --git a/packages/SystemUI/res/values-et-rEE/strings.xml b/packages/SystemUI/res/values-et-rEE/strings.xml
    -index bfc55e9..0cdf8d2 100644
    ---- a/packages/SystemUI/res/values-et-rEE/strings.xml
    -+++ b/packages/SystemUI/res/values-et-rEE/strings.xml
    -@@ -47,7 +47,7 @@
    -     <string name="status_bar_settings_auto_rotation" msgid="3790482541357798421">"Pööra ekraani automaatselt"</string>
    -     <string name="status_bar_settings_mute_label" msgid="554682549917429396">"SUMMUTA"</string>
    -     <string name="status_bar_settings_auto_brightness_label" msgid="511453614962324674">"AUTO"</string>
    --    <string name="status_bar_settings_notifications" msgid="397146176280905137">"Teatised"</string>
    -+    <string name="status_bar_settings_notifications" msgid="397146176280905137">"Märguanded"</string>
    -     <string name="bluetooth_tethered" msgid="7094101612161133267">"Bluetooth on jagatud"</string>
    -     <string name="status_bar_input_method_settings_configure_input_methods" msgid="3504292471512317827">"Seadista sisestusmeetodeid"</string>
    -     <string name="status_bar_use_physical_keyboard" msgid="7551903084416057810">"Füüsiline klaviatuur"</string>
    -@@ -164,7 +164,7 @@
    -     <!-- no translation found for accessibility_battery_level_charging (1147587904439319646) -->
    -     <skip />
    -     <string name="accessibility_settings_button" msgid="799583911231893380">"Süsteemiseaded"</string>
    --    <string name="accessibility_notifications_button" msgid="4498000369779421892">"Teatised"</string>
    -+    <string name="accessibility_notifications_button" msgid="4498000369779421892">"Märguanded"</string>
    -     <string name="accessibility_remove_notification" msgid="3603099514902182350">"Märguande eemaldamine."</string>
    -     <string name="accessibility_gps_enabled" msgid="3511469499240123019">"GPS on lubatud."</string>
    -     <string name="accessibility_gps_acquiring" msgid="8959333351058967158">"GPS-signaali otsimine."</string>
    -@@ -240,7 +240,7 @@
    -     <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"4G andmekasutus on peatatud"</string>
    -     <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"Mobiilse andmeside kasutus on peatatud"</string>
    -     <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"Andmekasutus on peatatud"</string>
    --    <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"Kuna jõudsite andmemahu määratud piirini, peatas seade andmekasutuse ülejäänud tsükliks.\n\nJätkamisel võivad lisanduda operaatoritasud."</string>
    -+    <string name="data_usage_disabled_dialog" msgid="1841738975235283398">"Olete jõudnud enda määratud andmemahupiiranguni. Te ei kasuta enam mobiilset andmesidet.\n\nKui jätkate, võivad rakenduda andmekasutustasud."</string>
    -     <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"Jätka"</string>
    -     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Interneti-ühendus puudub"</string>
    -     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"WiFi on ühendatud"</string>
    -@@ -406,6 +406,7 @@
    -     <string name="device_owned_footer" msgid="3802752663326030053">"Seadet võidakse jälgida"</string>
    -     <string name="profile_owned_footer" msgid="8021888108553696069">"Profiili võidakse jälgida"</string>
    -     <string name="vpn_footer" msgid="2388611096129106812">"Võrku võidakse jälgida"</string>
    -+    <string name="branded_vpn_footer" msgid="2168111859226496230">"Võrku võidakse jälgida"</string>
    -     <string name="monitoring_title_device_owned" msgid="7121079311903859610">"Seadme jälgimine"</string>
    -     <string name="monitoring_title_profile_owned" msgid="6790109874733501487">"Profiili jälgimine"</string>
    -     <string name="monitoring_title" msgid="169206259253048106">"Võrgu jälgimine"</string>
    -@@ -418,6 +419,7 @@
    -     <string name="legacy_vpn_name" msgid="6604123105765737830">"VPN"</string>
    -     <string name="monitoring_description_app" msgid="6259179342284742878">"Teie seade on ühendatud rakendusega <xliff:g id="APPLICATION">%1$s</xliff:g>, mis võib jälgida teie võrgutegevusi, sh meile, rakendusi ja veebisaite."</string>
    -     <string name="monitoring_description_app_personal" msgid="484599052118316268">"Teie seade on ühendatud rakendusega <xliff:g id="APPLICATION">%1$s</xliff:g>, mis võib jälgida teie isiklikke võrgutegevusi, sh meile, rakendusi ja veebisaite."</string>
    -+    <string name="branded_monitoring_description_app_personal" msgid="2669518213949202599">"Olete ühendatud rakendusega <xliff:g id="APPLICATION">%1$s</xliff:g>, mis võib jälgida teie isiklikke võrgutegevusi, sh meile, rakendusi ja veebisaite."</string>
    -     <string name="monitoring_description_app_work" msgid="1754325860918060897">"Teie tööprofiili haldab organisatsioon <xliff:g id="ORGANIZATION">%1$s</xliff:g>. See on ühendatud rakendusega <xliff:g id="APPLICATION">%2$s</xliff:g>, mis võib jälgida teie töökoha võrgutegevusi, sh meile, rakendusi ja veebisaite.\n\nLisateabe saamiseks võtke ühendust administraatoriga."</string>
    -     <string name="monitoring_description_app_personal_work" msgid="4946600443852045903">"Teie tööprofiili haldab organisatsioon <xliff:g id="ORGANIZATION">%1$s</xliff:g>. See on ühendatud rakendusega <xliff:g id="APPLICATION_WORK">%2$s</xliff:g>, mis võib jälgida teie töökoha võrgutegevusi, sh meile, rakendusi ja veebisaite.\n\nTeie seade on ühendatud ka rakendusega <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g>, mis võib jälgida teie isiklikke võrgutegevusi."</string>
    -     <string name="monitoring_description_vpn_app_device_owned" msgid="4970443827043261703">"Teie seadet haldab organisatsioon <xliff:g id="ORGANIZATION">%1$s</xliff:g>.\n\nAdministraator saab jälgida ja hallata seadeid, ettevõttesisest juurdepääsu, rakendusi, seadmega seotud andmeid ja seadme asukohateavet.\n\nOlete ühendatud rakendusega <xliff:g id="APPLICATION">%2$s</xliff:g>, mis saab jälgida teie võrgutegevusi, sh meile, rakendusi ja veebisaite.\n\nLisateabe saamiseks võtke ühendust administraatoriga."</string>
    -@@ -494,8 +496,6 @@
    -     <string name="clock_seconds_desc" msgid="6282693067130470675">"Olekuribal kella sekundite kuvamine. See võib mõjutada aku kasutusaega."</string>
    -     <string name="qs_rearrange" msgid="8060918697551068765">"Korralda kiirseaded ümber"</string>
    -     <string name="show_brightness" msgid="6613930842805942519">"Kuva kiirseadetes heledus"</string>
    --    <string name="overview_nav_bar_gesture" msgid="8579814204727917764">"Luba ülespühkimise liigutus ekraani poolitamiseks"</string>
    --    <string name="overview_nav_bar_gesture_desc" msgid="6329167382305102615">"Lubab žesti, mis poolitab ekraani, kui kasutaja pühib üles nupul Ülevaade."</string>
    -     <string name="experimental" msgid="6198182315536726162">"Eksperimentaalne"</string>
    -     <string name="enable_bluetooth_title" msgid="5027037706500635269">"Kas lülitada Bluetooth sisse?"</string>
    -     <string name="enable_bluetooth_message" msgid="9106595990708985385">"Klaviatuuri ühendamiseks tahvelarvutiga peate esmalt Bluetoothi sisse lülitama."</string>
    -@@ -653,4 +653,5 @@
    -     <string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"Ava teenuse <xliff:g id="ID_1">%s</xliff:g> seaded."</string>
    -     <string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"Muuda seadete järjestust."</string>
    -     <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"Leht <xliff:g id="ID_1">%1$d</xliff:g>/<xliff:g id="ID_2">%2$d</xliff:g>"</string>
    -+    <string name="cant_silence_or_block" msgid="999689262131488625">"Märguandeid ei saa vaigistada ega blokeerida"</string>
    - </resources>
    -diff --git a/packages/SystemUI/res/values-eu-rES/strings.xml b/packages/SystemUI/res/values-eu-rES/strings.xml
    -index a340b3d..9494110 100644
    ---- a/packages/SystemUI/res/values-eu-rES/strings.xml
    -+++ b/packages/SystemUI/res/values-eu-rES/strings.xml
    -@@ -240,7 +240,7 @@
    -     <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"4G datuen erabilera eten da"</string>
    -     <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"Sare mugikorreko datuen erabilera eten da"</string>
    -     <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"Datuen erabilera eten da"</string>
    --    <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"Zehaztuta duzun datuen erabilera-mugara iritsi zarenez, gailuak datuen erabilera eten du zikloa amaitzen den arte.\n\nDatuak erabiltzen jarraitzen baduzu, gastu gehiago ordaindu beharko dizkiozu agian operadoreari."</string>
    -+    <string name="data_usage_disabled_dialog" msgid="1841738975235283398">"Gainditu egin da ezarri duzun datu-muga. Datu-konexioa erabiltzeari utzi diozu.\n\nBerriro hasten bazara erabiltzen, baliteke datuen erabileraren kostua ordaindu behar izatea."</string>
    -     <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"Jarraitu erabiltzen"</string>
    -     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Ez duzu Interneteko konexiorik"</string>
    -     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi konektatuta"</string>
    -@@ -406,6 +406,7 @@
    -     <string name="device_owned_footer" msgid="3802752663326030053">"Baliteke gailua kontrolatuta egotea"</string>
    -     <string name="profile_owned_footer" msgid="8021888108553696069">"Baliteke profila kontrolatuta egotea"</string>
    -     <string name="vpn_footer" msgid="2388611096129106812">"Baliteke sarea kontrolatuta egotea"</string>
    -+    <string name="branded_vpn_footer" msgid="2168111859226496230">"Baliteke sarea kontrolatuta egotea"</string>
    -     <string name="monitoring_title_device_owned" msgid="7121079311903859610">"Gailuen kontrola"</string>
    -     <string name="monitoring_title_profile_owned" msgid="6790109874733501487">"Profila kontrolatzeko aukera"</string>
    -     <string name="monitoring_title" msgid="169206259253048106">"Sareen kontrola"</string>
    -@@ -418,6 +419,7 @@
    -     <string name="legacy_vpn_name" msgid="6604123105765737830">"VPN konexioa"</string>
    -     <string name="monitoring_description_app" msgid="6259179342284742878">"<xliff:g id="APPLICATION">%1$s</xliff:g> aplikaziora konektatuta zaude. Aplikazio horrek sarean egiten dituzun jarduerak kontrola ditzake, mezu elektronikoak, aplikazioak eta webguneak barne."</string>
    -     <string name="monitoring_description_app_personal" msgid="484599052118316268">"<xliff:g id="APPLICATION">%1$s</xliff:g> aplikaziora konektatuta zaude. Aplikazio horrek sarean egiten dituzun jarduera pertsonalak kontrola ditzake, mezu elektronikoak, aplikazioak eta webguneak barne."</string>
    -+    <string name="branded_monitoring_description_app_personal" msgid="2669518213949202599">"<xliff:g id="APPLICATION">%1$s</xliff:g> aplikaziora konektatuta zaude. Aplikazio horrek sarean egiten dituzun jarduera pertsonalak kontrola ditzake, mezu elektronikoak, aplikazioak eta webguneak barne."</string>
    -     <string name="monitoring_description_app_work" msgid="1754325860918060897">"<xliff:g id="ORGANIZATION">%1$s</xliff:g> da laneko profilaren kudeatzailea, eta profila <xliff:g id="APPLICATION">%2$s</xliff:g> aplikaziora konektatuta dago. Aplikazio horrek sarean egiten dituzun laneko jarduerak kontrola ditzake, mezu elektronikoak, aplikazioak eta webguneak barne.\n\nInformazio gehiago lortzeko, jarri administratzailearekin harremanetan."</string>
    -     <string name="monitoring_description_app_personal_work" msgid="4946600443852045903">"<xliff:g id="ORGANIZATION">%1$s</xliff:g> da laneko profilaren kudeatzailea, eta profila <xliff:g id="APPLICATION_WORK">%2$s</xliff:g> aplikaziora konektatuta dago. Aplikazio horrek sarean egiten dituzun laneko jarduerak kontrola ditzake, mezu elektronikoak, aplikazioak eta webguneak barne.\n\nHorrez gain, sarean egiten dituzun jarduera pertsonalak kontrola ditzakeen <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g> aplikaziora konektatuta zaude."</string>
    -     <string name="monitoring_description_vpn_app_device_owned" msgid="4970443827043261703">"<xliff:g id="ORGANIZATION">%1$s</xliff:g> da gailuaren kudeatzailea.\n\nAdministratzaileak ezarpenak, enpresako sarbidea, aplikazioak, gailuarekin lotutako datuak eta gailuaren kokapenari buruzko informazioa kontrola eta kudea ditzake.\n\n<xliff:g id="APPLICATION">%2$s</xliff:g> aplikaziora konektatuta zaude. Aplikazio horrek sarean egiten dituzun jarduerak kontrola ditzake, mezu elektronikoak, aplikazioak eta webguneak barne.\n\nInformazio gehiago lortzeko, jarri administratzailearekin harremanetan."</string>
    -@@ -494,8 +496,6 @@
    -     <string name="clock_seconds_desc" msgid="6282693067130470675">"Erakutsi erlojuko segundoak egoera-barran. Baliteke bateria gehiago erabiltzea."</string>
    -     <string name="qs_rearrange" msgid="8060918697551068765">"Berrantolatu ezarpen bizkorrak"</string>
    -     <string name="show_brightness" msgid="6613930842805942519">"Erakutsi distira Ezarpen bizkorretan"</string>
    --    <string name="overview_nav_bar_gesture" msgid="8579814204727917764">"Gaitu pantaila zatitzeko keinua hatza gora pasatuta"</string>
    --    <string name="overview_nav_bar_gesture_desc" msgid="6329167382305102615">"Sakatu Ikuspegi nagusia botoia eta gaitu hatza gora pasatuta pantaila zatitzeko keinua"</string>
    -     <string name="experimental" msgid="6198182315536726162">"Esperimentala"</string>
    -     <string name="enable_bluetooth_title" msgid="5027037706500635269">"Bluetooth eginbidea aktibatu nahi duzu?"</string>
    -     <string name="enable_bluetooth_message" msgid="9106595990708985385">"Teklatua tabletara konektatzeko, Bluetooth eginbidea aktibatu behar duzu."</string>
    -@@ -653,4 +653,5 @@
    -     <string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"Ireki <xliff:g id="ID_1">%s</xliff:g> ezarpenak."</string>
    -     <string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"Editatu ezarpenen ordena."</string>
    -     <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"<xliff:g id="ID_1">%1$d</xliff:g>/<xliff:g id="ID_2">%2$d</xliff:g> orria"</string>
    -+    <string name="cant_silence_or_block" msgid="999689262131488625">"Jakinarazpenak ezin dira ezkutatu edo blokeatu"</string>
    - </resources>
    -diff --git a/packages/SystemUI/res/values-fa-land/strings.xml b/packages/SystemUI/res/values-fa-land/strings.xml
    -index adc2b11..fe67cf0 100644
    ---- a/packages/SystemUI/res/values-fa-land/strings.xml
    -+++ b/packages/SystemUI/res/values-fa-land/strings.xml
    -@@ -19,5 +19,5 @@
    - 
    - <resources xmlns:android="http://schemas.android.com/apk/res/android"
    -     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
    --    <string name="toast_rotation_locked" msgid="7609673011431556092">"صفحه اکنون در جهت افقی قفل است."</string>
    -+    <string name="toast_rotation_locked" msgid="7609673011431556092">"صفحه اکنون در حالت افقی قفل است."</string>
    - </resources>
    -diff --git a/packages/SystemUI/res/values-fa/strings.xml b/packages/SystemUI/res/values-fa/strings.xml
    -index 58a5d93..abb7e1e 100644
    ---- a/packages/SystemUI/res/values-fa/strings.xml
    -+++ b/packages/SystemUI/res/values-fa/strings.xml
    -@@ -238,7 +238,7 @@
    -     <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"‏داده 4G موقتاً متوقف شده است"</string>
    -     <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"داده شبکه همراه موقتاً متوقف شده است"</string>
    -     <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"داده موقتاً متوقف شده است"</string>
    --    <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"چون به محدودیت داده تنظیم شده رسیده‌اید، دستگاه مصرف داده را برای باقیمانده این دوره موقتاً متوقف کرده است.\n\nاگر ادامه دهید شاید موجب کسر هزینه از طرف شرکت مخابراتی شما شود."</string>
    -+    <string name="data_usage_disabled_dialog" msgid="1841738975235283398">"به حداکثر محدودیت داده‌ای که تنظیم کردید رسیدید. دیگر از داده شبکه تلفن همراه استفاده نمی‌کنید.\n\nدر صورت ازسرگیری، ممکن است مصرف داده هزینه‌هایی دربرداشته باشد."</string>
    -     <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"از سر‌گیری"</string>
    -     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"اتصال اینترنتی ندارید"</string>
    -     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"‏Wi-Fi متصل شد"</string>
    -@@ -254,10 +254,10 @@
    -     <string name="status_bar_notification_inspect_item_title" msgid="5668348142410115323">"تنظیمات اعلان"</string>
    -     <string name="status_bar_notification_app_settings_title" msgid="5525260160341558869">"تنظیمات <xliff:g id="APP_NAME">%s</xliff:g>"</string>
    -     <string name="accessibility_rotation_lock_off" msgid="4062780228931590069">"صفحه به صورت خودکار می‌چرخد."</string>
    --    <string name="accessibility_rotation_lock_on_landscape" msgid="6731197337665366273">"صفحه اکنون در جهت افقی قفل است."</string>
    -+    <string name="accessibility_rotation_lock_on_landscape" msgid="6731197337665366273">"صفحه اکنون در حالت افقی قفل است."</string>
    -     <string name="accessibility_rotation_lock_on_portrait" msgid="5809367521644012115">"صفحه اکنون در جهت عمودی قفل است."</string>
    -     <string name="accessibility_rotation_lock_off_changed" msgid="8134601071026305153">"صفحه اکنون به صورت خودکار می‌چرخد."</string>
    --    <string name="accessibility_rotation_lock_on_landscape_changed" msgid="3135965553707519743">"صفحه اکنون روی جهت افقی قفل شده است."</string>
    -+    <string name="accessibility_rotation_lock_on_landscape_changed" msgid="3135965553707519743">"صفحه اکنون در حالت افقی قفل است."</string>
    -     <string name="accessibility_rotation_lock_on_portrait_changed" msgid="8922481981834012126">"صفحه اکنون روی جهت عمودی قفل شده است."</string>
    -     <string name="dessert_case" msgid="1295161776223959221">"ویترین دسر"</string>
    -     <string name="start_dreams" msgid="5640361424498338327">"محافظ صفحه"</string>
    -@@ -347,8 +347,8 @@
    -     <string name="description_direction_left" msgid="7207478719805562165">"لغزاندن به چپ برای <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
    -     <string name="zen_priority_introduction" msgid="3070506961866919502">"صداها و لرزش‌هایی به جز هشدارها، یادآوری‌ها، رویدادها و تماس‌گیرنده‌هایی که مشخص می‌کنید، مزاحم شما نمی‌شوند."</string>
    -     <string name="zen_priority_customize_button" msgid="7948043278226955063">"سفارشی کردن"</string>
    --    <string name="zen_silence_introduction_voice" msgid="2284540992298200729">"این کار «همه» صداها و لرزش‌ها از جمله هشدارها، موسیقی، ویدیوها و بازی‌ها را مسدود می‌کند. همچنان می‌توانید تماس تلفنی برقرار کنید."</string>
    --    <string name="zen_silence_introduction" msgid="3137882381093271568">"این کار «همه» صداها و لرزش‌ها از جمله هشدارها، موسیقی، ویدیوها و بازی‌ها را مسدود می‌کند."</string>
    -+    <string name="zen_silence_introduction_voice" msgid="2284540992298200729">"این کار «همه» صداها و لرزش‌ها از جمله هشدارها، موسیقی، ویدئوها و بازی‌ها را مسدود می‌کند. همچنان می‌توانید تماس تلفنی برقرار کنید."</string>
    -+    <string name="zen_silence_introduction" msgid="3137882381093271568">"این کار «همه» صداها و لرزش‌ها از جمله هشدارها، موسیقی، ویدئوها و بازی‌ها را مسدود می‌کند."</string>
    -     <string name="keyguard_more_overflow_text" msgid="9195222469041601365">"+<xliff:g id="NUMBER_OF_NOTIFICATIONS">%d</xliff:g>"</string>
    -     <string name="speed_bump_explanation" msgid="1288875699658819755">"اعلان‌های کمتر فوری در زیر"</string>
    -     <string name="notification_tap_again" msgid="7590196980943943842">"دوباره ضربه بزنید تا باز شود"</string>
    -@@ -404,6 +404,7 @@
    -     <string name="device_owned_footer" msgid="3802752663326030053">"ممکن است دستگاه کنترل شود"</string>
    -     <string name="profile_owned_footer" msgid="8021888108553696069">"شاید نمایه کنترل شود"</string>
    -     <string name="vpn_footer" msgid="2388611096129106812">"ممکن است شبکه کنترل شود"</string>
    -+    <string name="branded_vpn_footer" msgid="2168111859226496230">"ممکن است شبکه کنترل شود"</string>
    -     <string name="monitoring_title_device_owned" msgid="7121079311903859610">"کنترل دستگاه"</string>
    -     <string name="monitoring_title_profile_owned" msgid="6790109874733501487">"کنترل نمایه"</string>
    -     <string name="monitoring_title" msgid="169206259253048106">"کنترل شبکه"</string>
    -@@ -416,6 +417,7 @@
    -     <string name="legacy_vpn_name" msgid="6604123105765737830">"VPN"</string>
    -     <string name="monitoring_description_app" msgid="6259179342284742878">"شما به <xliff:g id="APPLICATION">%1$s</xliff:g> وصل شده‌اید، که می‌تواند فعالیت شبکه شما از جمله رایانامه‌، برنامه‌ و وب‌سایت‌ها را کنترل کند."</string>
    -     <string name="monitoring_description_app_personal" msgid="484599052118316268">"شما به <xliff:g id="APPLICATION">%1$s</xliff:g> وصل شده‌اید، که می‌تواند فعالیت شبکه شخصی شما از جمله رایانامه‌، برنامه‌ و وب‌سایت‌ها را کنترل کند."</string>
    -+    <string name="branded_monitoring_description_app_personal" msgid="2669518213949202599">"به <xliff:g id="APPLICATION">%1$s</xliff:g> وصل شده‌اید، که می‌تواند فعالیت شبکه شخصی شما را (ازجمله رایانامه‌‌ها، برنامه‌‌ها و وب‌سایت‌ها) کنترل کند."</string>
    -     <string name="monitoring_description_app_work" msgid="1754325860918060897">"نمایه کاری‌تان توسط <xliff:g id="ORGANIZATION">%1$s</xliff:g> مدیریت می‌شود. این به <xliff:g id="APPLICATION">%2$s</xliff:g> وصل است که فعالیت شبکه کاری‌تان از جمله رایانامه، برنامه و وب‌سایت‌ها را کنترل می‌کند.\n\nبرای دریافت اطلاعات بیشتر، با سرپرستتان تماس بگیرید."</string>
    -     <string name="monitoring_description_app_personal_work" msgid="4946600443852045903">"نمایه کاری شما توسط <xliff:g id="ORGANIZATION">%1$s</xliff:g> مدیریت می‌شود. این به <xliff:g id="APPLICATION_WORK">%2$s</xliff:g> متصل است که می‌تواند فعالیت شبکه کاری‌تان از جمله رایانامه، برنامه و وب‌سایت‌ها را کنترل کند.\n\nشما همچنین به <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g> متصل هستید که می‌تواند فعالیت شبکه شخصی‌تان را کنترل کند."</string>
    -     <string name="monitoring_description_vpn_app_device_owned" msgid="4970443827043261703">"دستگاهتان توسط <xliff:g id="ORGANIZATION">%1$s</xliff:g> مدیریت می‌شود.\n\nسرپرستتان می‌تواند تنظیمات، دسترسی شرکت، برنامه‌ها، داده‌های مرتبط با دستگاهتان و اطلاعات مکان دستگاهتان را کنترل و مدیریت کند.\n\nشما به <xliff:g id="APPLICATION">%2$s</xliff:g> وصل هستید که می‌تواند فعالیت شبکه شما را کنترل کند، از جمله رایانامه‌، برنامه‌ و وب‌سایت‌ها.\n\nبرای دریافت اطلاعات بیشتر، با سرپرستتان تماس بگیرید."</string>
    -@@ -482,7 +484,7 @@
    -     <string name="accessibility_managed_profile" msgid="6613641363112584120">"نمایه کاری"</string>
    -     <string name="tuner_warning_title" msgid="7094689930793031682">"برای بعضی افراد سرگرم‌کننده است اما نه برای همه"</string>
    -     <string name="tuner_warning" msgid="8730648121973575701">"‏«تنظیم‌کننده واسط کاربری سیستم» روش‌های بیشتری برای تنظیم دقیق و سفارشی کردن واسط کاربری Android در اختیار شما قرار می‌دهد. ممکن است این ویژگی‌های آزمایشی تغییر کنند، خراب شوند یا در نسخه‌های آینده جود نداشته باشند. با احتیاط ادامه دهید."</string>
    --    <string name="tuner_persistent_warning" msgid="8597333795565621795">"ممکن است این ویژگی‌های آزمایشی تغییر کنند، خراب شوند یا در نسخه‌های آینده وجود نداشته باشند. با احتیاط ادامه دهید."</string>
    -+    <string name="tuner_persistent_warning" msgid="8597333795565621795">"ممکن است این قابلیت‌های آزمایشی تغییر کنند، خراب شوند یا در نسخه‌های آینده وجود نداشته باشد. بااحتیاط ادامه دهید."</string>
    -     <string name="got_it" msgid="2239653834387972602">"متوجه شدم"</string>
    -     <string name="tuner_toast" msgid="603429811084428439">"تبریک می‌گوییم! «تنظیم‌کننده واسط کاربری سیستم» به «تنظیمات» اضافه شد"</string>
    -     <string name="remove_from_settings" msgid="8389591916603406378">"حذف از تنظیمات"</string>
    -@@ -492,8 +494,6 @@
    -     <string name="clock_seconds_desc" msgid="6282693067130470675">"ثانیه‌های ساعت را در نوار وضعیت نشان می‌دهد. ممکن است بر ماندگاری باتری تأثیر بگذارد."</string>
    -     <string name="qs_rearrange" msgid="8060918697551068765">"ترتیب مجدد در تنظیمات سریع"</string>
    -     <string name="show_brightness" msgid="6613930842805942519">"نمایش روشنایی در تنظیمات سریع"</string>
    --    <string name="overview_nav_bar_gesture" msgid="8579814204727917764">"فعال کردن تقسیم صفحه با اشاره بالا کشیدن"</string>
    --    <string name="overview_nav_bar_gesture_desc" msgid="6329167382305102615">"اشاره ورود به تقسیم صفحه با بالا کشیدن صفحه از دکمه نمای کلی را فعال می‌کند"</string>
    -     <string name="experimental" msgid="6198182315536726162">"آزمایشی"</string>
    -     <string name="enable_bluetooth_title" msgid="5027037706500635269">"بلوتوث روشن شود؟"</string>
    -     <string name="enable_bluetooth_message" msgid="9106595990708985385">"برای مرتبط کردن صفحه‌کلید با رایانه لوحی، ابتدا باید بلوتوث را روشن کنید."</string>
    -@@ -651,4 +651,5 @@
    -     <string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"باز کردن تنظیمات <xliff:g id="ID_1">%s</xliff:g>."</string>
    -     <string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"ویرایش ترتیب تنظیمات."</string>
    -     <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"صفحه <xliff:g id="ID_1">%1$d</xliff:g> از <xliff:g id="ID_2">%2$d</xliff:g>"</string>
    -+    <string name="cant_silence_or_block" msgid="999689262131488625">"نمی‌توان اعلان‌ها را بی‌صدا یا مسدود کرد"</string>
    - </resources>
    -diff --git a/packages/SystemUI/res/values-fa/strings_tv.xml b/packages/SystemUI/res/values-fa/strings_tv.xml
    -index 2894abb..b97a6465 100644
    ---- a/packages/SystemUI/res/values-fa/strings_tv.xml
    -+++ b/packages/SystemUI/res/values-fa/strings_tv.xml
    -@@ -25,7 +25,7 @@
    -     <string name="pip_pause" msgid="8412075640017218862">"مکث"</string>
    -     <string name="pip_hold_home" msgid="340086535668778109">"‏کنترل PIP ‏با نگه‌داشتن "<b>"HOME"</b></string>
    -     <string name="pip_onboarding_title" msgid="7850436557670253991">"تصویر در تصویر"</string>
    --    <string name="pip_onboarding_description" msgid="4028124563309465267">"تا زمانی که ویدیوی دیگری را پخش کنید، این صفحه حالت ویدیو در ویدیوی شما را حفظ می‌کند. برای کنترل آن، دکمه "<b>"صفحه اصلی"</b>" را فشار دهید و نگه دارید."</string>
    -+    <string name="pip_onboarding_description" msgid="4028124563309465267">"تا زمانی که ویدئوی دیگری را پخش کنید، این صفحه حالت ویدئو در ویدئوی شما را حفظ می‌کند. برای کنترل آن، دکمه "<b>"صفحه اصلی"</b>" را فشار دهید و نگه دارید."</string>
    -     <string name="pip_onboarding_button" msgid="3957426748484904611">"متوجه شدم"</string>
    -     <string name="recents_tv_dismiss" msgid="3555093879593377731">"رد کردن"</string>
    -   <string-array name="recents_tv_blacklist_array">
    -diff --git a/packages/SystemUI/res/values-fi/strings.xml b/packages/SystemUI/res/values-fi/strings.xml
    -index 5ff50be..910ac29 100644
    ---- a/packages/SystemUI/res/values-fi/strings.xml
    -+++ b/packages/SystemUI/res/values-fi/strings.xml
    -@@ -238,7 +238,7 @@
    -     <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"4G-tiedonsiirto keskeytettiin"</string>
    -     <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"Mobiilitiedonsiirto keskeytettiin"</string>
    -     <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"Tiedonsiirto keskeytettiin"</string>
    --    <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"Määrittämäsi tiedonsiirtorajoitus saavutettiin, ja laite keskeytti tiedonsiirron tämän kauden loppuajaksi.\n\nOperaattorisi voi veloittaa sinulta lisämaksun, jos jatkat tiedonsiirtoa."</string>
    -+    <string name="data_usage_disabled_dialog" msgid="1841738975235283398">"Määrittämäsi datankäyttöraja on täynnä. Mobiilidata poistettiin käytöstä.\n\nOperaattorisi voi veloittaa sinua, jos jatkat mobiilidatan käyttöä."</string>
    -     <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"Jatka"</string>
    -     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Ei internetyhteyttä"</string>
    -     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi yhdistetty"</string>
    -@@ -404,6 +404,7 @@
    -     <string name="device_owned_footer" msgid="3802752663326030053">"Laitetta voidaan valvoa"</string>
    -     <string name="profile_owned_footer" msgid="8021888108553696069">"Profiilia saatetaan valvoa"</string>
    -     <string name="vpn_footer" msgid="2388611096129106812">"Verkkoa saatetaan valvoa"</string>
    -+    <string name="branded_vpn_footer" msgid="2168111859226496230">"Verkkoa saatetaan valvoa"</string>
    -     <string name="monitoring_title_device_owned" msgid="7121079311903859610">"Laitteiden valvonta"</string>
    -     <string name="monitoring_title_profile_owned" msgid="6790109874733501487">"Profiilin valvonta"</string>
    -     <string name="monitoring_title" msgid="169206259253048106">"Verkon valvonta"</string>
    -@@ -416,6 +417,7 @@
    -     <string name="legacy_vpn_name" msgid="6604123105765737830">"VPN"</string>
    -     <string name="monitoring_description_app" msgid="6259179342284742878">"Olet muodostanut yhteyden sovellukseen <xliff:g id="APPLICATION">%1$s</xliff:g>, joka voi valvoa toimintaasi verkossa. Sovellus voi seurata esimerkiksi avaamiasi sähköposteja, sovelluksia ja verkkosivustoja."</string>
    -     <string name="monitoring_description_app_personal" msgid="484599052118316268">"Olet muodostanut yhteyden sovellukseen <xliff:g id="APPLICATION">%1$s</xliff:g>, joka voi valvoa henkilökohtaista toimintaasi verkossa. Sovellus voi seurata esimerkiksi avaamiasi sähköposteja, sovelluksia ja verkkosivustoja."</string>
    -+    <string name="branded_monitoring_description_app_personal" msgid="2669518213949202599">"Olet muodostanut yhteyden sovellukseen <xliff:g id="APPLICATION">%1$s</xliff:g>, joka voi valvoa henkilökohtaista toimintaasi verkossa. Sovellus voi esimerkiksi seurata avaamiasi sähköposteja, sovelluksia ja verkkosivustoja."</string>
    -     <string name="monitoring_description_app_work" msgid="1754325860918060897">"Työprofiiliasi hallinnoi <xliff:g id="ORGANIZATION">%1$s</xliff:g>. Se on yhteydessä sovellukseen <xliff:g id="APPLICATION">%2$s</xliff:g>, joka voi valvoa työhön liittyvää toimintaasi verkossa. Sovellus voi seurata esimerkiksi avaamiasi sähköposteja, sovelluksia ja verkkosivustoja.\n\nSaat lisätietoja järjestelmänvalvojaltasi."</string>
    -     <string name="monitoring_description_app_personal_work" msgid="4946600443852045903">"Työprofiiliasi hallinnoi <xliff:g id="ORGANIZATION">%1$s</xliff:g>. Se on yhteydessä sovellukseen <xliff:g id="APPLICATION_WORK">%2$s</xliff:g>, joka voi valvoa työhön liittyvää toimintaasi verkossa. Sovellus voi seurata esimerkiksi avaamiasi sähköposteja, sovelluksia ja verkkosivustoja.\n\nLisäksi olet yhteydessä sovellukseen <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g>, joka voi valvoa henkilökohtaista toimintaasi verkossa."</string>
    -     <string name="monitoring_description_vpn_app_device_owned" msgid="4970443827043261703">"Laitettasi hallinnoi <xliff:g id="ORGANIZATION">%1$s</xliff:g>.\n\nJärjestelmänvalvojasi voi valvoa ja hallinnoida laitteesi asetuksia, yrityskäyttöä, sovelluksia, laitteeseesi liittyviä tietoja ja laitteen sijaintitietoja.\n\nOlet yhteydessä sovellukseen <xliff:g id="APPLICATION">%2$s</xliff:g>, joka voi valvoa toimintaasi verkossa. Sovellus voi seurata esimerkiksi avaamiasi sähköposteja, sovelluksia ja verkkosivustoja.\n\nLisätietoja saat järjestelmänvalvojaltasi."</string>
    -@@ -492,8 +494,6 @@
    -     <string name="clock_seconds_desc" msgid="6282693067130470675">"Näytä sekunnit tilapalkin kellossa. Tämä voi vaikuttaa akun kestoon."</string>
    -     <string name="qs_rearrange" msgid="8060918697551068765">"Järjestä pika-asetukset uudelleen"</string>
    -     <string name="show_brightness" msgid="6613930842805942519">"Näytä kirkkaus pika-asetuksissa"</string>
    --    <string name="overview_nav_bar_gesture" msgid="8579814204727917764">"Siirry jaetun näytön tilaan pyyhkäisemällä ylöspäin"</string>
    --    <string name="overview_nav_bar_gesture_desc" msgid="6329167382305102615">"Voit siirtyä jaetun näytön tilaan pyyhkäisemällä Viimeisimmät-painikkeesta ylöspäin."</string>
    -     <string name="experimental" msgid="6198182315536726162">"Kokeellinen"</string>
    -     <string name="enable_bluetooth_title" msgid="5027037706500635269">"Otetaanko Bluetooth käyttöön?"</string>
    -     <string name="enable_bluetooth_message" msgid="9106595990708985385">"Jotta voit yhdistää näppäimistön tablettiisi, sinun on ensin otettava Bluetooth käyttöön."</string>
    -@@ -651,4 +651,5 @@
    -     <string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"Avaa kohteen <xliff:g id="ID_1">%s</xliff:g> asetukset."</string>
    -     <string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"Muokkaa asetusten järjestystä."</string>
    -     <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"Sivu <xliff:g id="ID_1">%1$d</xliff:g>/<xliff:g id="ID_2">%2$d</xliff:g>"</string>
    -+    <string name="cant_silence_or_block" msgid="999689262131488625">"Ilmoituksia ei voi mykistää tai estää"</string>
    - </resources>
    -diff --git a/packages/SystemUI/res/values-fr-rCA/strings.xml b/packages/SystemUI/res/values-fr-rCA/strings.xml
    -index 7d50fee..8c5e46f 100644
    ---- a/packages/SystemUI/res/values-fr-rCA/strings.xml
    -+++ b/packages/SystemUI/res/values-fr-rCA/strings.xml
    -@@ -240,7 +240,7 @@
    -     <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"Données 4G désactivées"</string>
    -     <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"Données cellulaires désactivées"</string>
    -     <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"Données désactivées"</string>
    --    <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"Vous avez atteint le quota de données maximal. La consommation des données a donc été interrompue pour la fin de la période de facturation en cours.\n\nSi vous réactivez les données, votre fournisseur de services risque de vous facturer des frais supplémentaires."</string>
    -+    <string name="data_usage_disabled_dialog" msgid="1841738975235283398">"La limite de données que vous avez définie a été atteinte. Vous n\'utilisez plus les données cellulaires.\n\nSi vous rétablissez la connexion de données cellulaires, des frais peuvent s\'appliquer."</string>
    -     <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"Reprendre"</string>
    -     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Aucune connexion Internet"</string>
    -     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Connecté au Wi-Fi"</string>
    -@@ -406,6 +406,7 @@
    -     <string name="device_owned_footer" msgid="3802752663326030053">"Il est possible que cet appareil soit surveillé."</string>
    -     <string name="profile_owned_footer" msgid="8021888108553696069">"le profil peut être contrôlé"</string>
    -     <string name="vpn_footer" msgid="2388611096129106812">"Le réseau peut être surveillé"</string>
    -+    <string name="branded_vpn_footer" msgid="2168111859226496230">"Le réseau peut être surveillé"</string>
    -     <string name="monitoring_title_device_owned" msgid="7121079311903859610">"Surveillance d\'appareils"</string>
    -     <string name="monitoring_title_profile_owned" msgid="6790109874733501487">"Contrôle de profil"</string>
    -     <string name="monitoring_title" msgid="169206259253048106">"Surveillance réseau"</string>
    -@@ -418,6 +419,7 @@
    -     <string name="legacy_vpn_name" msgid="6604123105765737830">"RPV"</string>
    -     <string name="monitoring_description_app" msgid="6259179342284742878">"Vous êtes connecté à <xliff:g id="APPLICATION">%1$s</xliff:g>. Cette application peut contrôler votre activité sur le réseau, y compris les courriels, les applications et les sites Web."</string>
    -     <string name="monitoring_description_app_personal" msgid="484599052118316268">"Vous êtes connecté à <xliff:g id="APPLICATION">%1$s</xliff:g>. Cette application peut contrôler votre activité personnelle sur le réseau, y compris les courriels, les applications et les sites Web."</string>
    -+    <string name="branded_monitoring_description_app_personal" msgid="2669518213949202599">"Vous êtes connecté à <xliff:g id="APPLICATION">%1$s</xliff:g>. Cette application peut contrôler votre activité personnelle sur le réseau, y compris les courriels, les applications et les sites Web."</string>
    -     <string name="monitoring_description_app_work" msgid="1754325860918060897">"Votre profil professionnel est géré par <xliff:g id="ORGANIZATION">%1$s</xliff:g>. Il est connecté à <xliff:g id="APPLICATION">%2$s</xliff:g>. Cette application peut contrôler votre activité sur le réseau, y compris les courriels, les applications et les sites Web.\n\nPour en savoir plus, communiquez avec votre administrateur."</string>
    -     <string name="monitoring_description_app_personal_work" msgid="4946600443852045903">"Votre profil professionnel est géré par <xliff:g id="ORGANIZATION">%1$s</xliff:g>. Il est connecté à <xliff:g id="APPLICATION_WORK">%2$s</xliff:g>. Cette application peut contrôler votre activité sur le réseau, y compris les courriels, les applications et les sites Web.\n\nVous êtes également connecté à <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g>. Cette application peut contrôler votre activité personnelle sur le réseau."</string>
    -     <string name="monitoring_description_vpn_app_device_owned" msgid="4970443827043261703">"Votre appareil est géré par <xliff:g id="ORGANIZATION">%1$s</xliff:g>.\n\nVotre administrateur peut contrôler et gérer les paramètres, l\'accès aux contenus de l\'entreprise, les applications, les données associées à cet appareil et ses données de localisation.\n\nVous êtes connecté à <xliff:g id="APPLICATION">%2$s</xliff:g>, qui peut contrôler votre activité réseau, y compris les courriels, les applications et les  sites Web.\n\nPour en savoir plus, communiquez avec votre administrateur."</string>
    -@@ -494,8 +496,6 @@
    -     <string name="clock_seconds_desc" msgid="6282693067130470675">"Afficher les secondes sur l\'horloge dans la barre d\'état. Cela peut réduire l\'autonomie de la pile."</string>
    -     <string name="qs_rearrange" msgid="8060918697551068765">"Réorganiser les paramètres rapides"</string>
    -     <string name="show_brightness" msgid="6613930842805942519">"Afficher la luminosité dans les paramètres rapides"</string>
    --    <string name="overview_nav_bar_gesture" msgid="8579814204727917764">"Activer le geste d\'écran partagé en balayant vers le haut"</string>
    --    <string name="overview_nav_bar_gesture_desc" msgid="6329167382305102615">"Activer le geste permettant d\'utiliser l\'écran partagé en balayant l\'écran vers le haut à partir du bouton « Aperçu »"</string>
    -     <string name="experimental" msgid="6198182315536726162">"Fonctions expérimentales"</string>
    -     <string name="enable_bluetooth_title" msgid="5027037706500635269">"Activer Bluetooth?"</string>
    -     <string name="enable_bluetooth_message" msgid="9106595990708985385">"Pour connecter votre clavier à votre tablette, vous devez d\'abord activer la connectivité Bluetooth."</string>
    -@@ -653,4 +653,5 @@
    -     <string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"Ouvrir les paramètres <xliff:g id="ID_1">%s</xliff:g>."</string>
    -     <string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"Modifier l\'ordre des paramètres."</string>
    -     <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"Page <xliff:g id="ID_1">%1$d</xliff:g> sur <xliff:g id="ID_2">%2$d</xliff:g>"</string>
    -+    <string name="cant_silence_or_block" msgid="999689262131488625">"Impossible de désactiver ou de bloquer les notifications"</string>
    - </resources>
    -diff --git a/packages/SystemUI/res/values-fr/strings.xml b/packages/SystemUI/res/values-fr/strings.xml
    -index 447255b..4b58a6d 100644
    ---- a/packages/SystemUI/res/values-fr/strings.xml
    -+++ b/packages/SystemUI/res/values-fr/strings.xml
    -@@ -240,7 +240,7 @@
    -     <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"Données 4G désactivées"</string>
    -     <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"Données mobiles désactivées"</string>
    -     <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"Données désactivées"</string>
    --    <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"Vous avez atteint le quota de données maximal. La consommation des données a donc été interrompue pour la fin de la période de facturation en cours.\n\nSi vous réactivez les données, votre opérateur risque de vous facturer des frais supplémentaires."</string>
    -+    <string name="data_usage_disabled_dialog" msgid="1841738975235283398">"La limite de consommation des données que vous avez définie a été atteinte. Vous n\'utilisez plus les données mobiles.\n\nSi vous les réactivez, des frais pourront être facturés."</string>
    -     <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"Réactiver"</string>
    -     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Aucune connexion Internet"</string>
    -     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Connecté au Wi-Fi"</string>
    -@@ -406,6 +406,7 @@
    -     <string name="device_owned_footer" msgid="3802752663326030053">"Il est possible que cet appareil soit surveillé."</string>
    -     <string name="profile_owned_footer" msgid="8021888108553696069">"Le profil peut être contrôlé."</string>
    -     <string name="vpn_footer" msgid="2388611096129106812">"Il est possible que le réseau soit surveillé."</string>
    -+    <string name="branded_vpn_footer" msgid="2168111859226496230">"Il est possible que le réseau soit surveillé."</string>
    -     <string name="monitoring_title_device_owned" msgid="7121079311903859610">"Contrôle des appareils"</string>
    -     <string name="monitoring_title_profile_owned" msgid="6790109874733501487">"Contrôle du profil"</string>
    -     <string name="monitoring_title" msgid="169206259253048106">"Contrôle du réseau"</string>
    -@@ -418,6 +419,7 @@
    -     <string name="legacy_vpn_name" msgid="6604123105765737830">"VPN"</string>
    -     <string name="monitoring_description_app" msgid="6259179342284742878">"Vous êtes connecté à <xliff:g id="APPLICATION">%1$s</xliff:g>. Cette application peut contrôler votre activité sur le réseau, y compris l\'activité relative aux e-mails, aux applications et aux sites Web."</string>
    -     <string name="monitoring_description_app_personal" msgid="484599052118316268">"Vous êtes connecté à <xliff:g id="APPLICATION">%1$s</xliff:g>. Cette application peut contrôler votre activité personnelle sur le réseau, y compris votre activité relative aux e-mails, aux applications et aux sites Web."</string>
    -+    <string name="branded_monitoring_description_app_personal" msgid="2669518213949202599">"Vous êtes connecté à <xliff:g id="APPLICATION">%1$s</xliff:g>. Cette application peut contrôler votre activité personnelle sur le réseau, y compris les e-mails, les applications et les sites Web."</string>
    -     <string name="monitoring_description_app_work" msgid="1754325860918060897">"Votre profil professionnel est géré par <xliff:g id="ORGANIZATION">%1$s</xliff:g>. Il est connecté à <xliff:g id="APPLICATION">%2$s</xliff:g>. Cette application peut contrôler l\'activité de ce profil sur le réseau, y compris l\'activité relative aux e-mails, aux applications et aux sites Web.\n\nPour en savoir plus, contactez votre administrateur."</string>
    -     <string name="monitoring_description_app_personal_work" msgid="4946600443852045903">"Votre profil professionnel est géré par <xliff:g id="ORGANIZATION">%1$s</xliff:g>. Il est connecté à <xliff:g id="APPLICATION_WORK">%2$s</xliff:g>. Cette application peut contrôler l\'activité de ce profil sur le réseau, y compris l\'activité relative aux e-mails, aux applications et aux sites Web.\n\nVous êtes également connecté à <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g>. Cette application peut surveiller votre activité personnelle sur le réseau."</string>
    -     <string name="monitoring_description_vpn_app_device_owned" msgid="4970443827043261703">"Votre appareil géré par <xliff:g id="ORGANIZATION">%1$s</xliff:g>.\n\nVotre administrateur peut contrôler et gérer les paramètres, l\'accès aux contenus de l\'entreprise, les applications, les données associées à cet appareil et les informations de localisation de celui-ci.\n\nVous êtes connecté à <xliff:g id="APPLICATION">%2$s</xliff:g> qui peut contrôler votre activité sur le réseau (e-mails, applications et sites Web).\n\nPour en savoir plus, contactez votre administrateur."</string>
    -@@ -446,7 +448,7 @@
    -   <string-array name="volume_stream_titles">
    -     <item msgid="5841843895402729630">"Appeler"</item>
    -     <item msgid="5997713001067658559">"Système"</item>
    --    <item msgid="7858983209929864160">"Faire sonner"</item>
    -+    <item msgid="7858983209929864160">"Sonnerie"</item>
    -     <item msgid="1850038478268896762">"Multimédia"</item>
    -     <item msgid="8265110906352372092">"Alarme"</item>
    -     <item msgid="5339394737636839168"></item>
    -@@ -494,8 +496,6 @@
    -     <string name="clock_seconds_desc" msgid="6282693067130470675">"Afficher les secondes dans la barre d\'état. Cela risque de réduire l\'autonomie de la batterie."</string>
    -     <string name="qs_rearrange" msgid="8060918697551068765">"Réorganiser la fenêtre de configuration rapide"</string>
    -     <string name="show_brightness" msgid="6613930842805942519">"Afficher la luminosité dans fenêtre de configuration rapide"</string>
    --    <string name="overview_nav_bar_gesture" msgid="8579814204727917764">"Activer l\'écran partagé en balayant vers le haut"</string>
    --    <string name="overview_nav_bar_gesture_desc" msgid="6329167382305102615">"Activer le geste permettant d\'utiliser l\'écran partagé en balayant l\'écran vers le haut à partir du bouton \"Aperçu\""</string>
    -     <string name="experimental" msgid="6198182315536726162">"Paramètres expérimentaux"</string>
    -     <string name="enable_bluetooth_title" msgid="5027037706500635269">"Activer le Bluetooth ?"</string>
    -     <string name="enable_bluetooth_message" msgid="9106595990708985385">"Pour connecter un clavier à votre tablette, vous devez avoir activé le Bluetooth."</string>
    -@@ -653,4 +653,5 @@
    -     <string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"Ouvrir les paramètres <xliff:g id="ID_1">%s</xliff:g>."</string>
    -     <string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"Modifier l\'ordre des paramètres."</string>
    -     <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"Page <xliff:g id="ID_1">%1$d</xliff:g> sur <xliff:g id="ID_2">%2$d</xliff:g>"</string>
    -+    <string name="cant_silence_or_block" msgid="999689262131488625">"Impossible d\'ignorer ou de bloquer les notifications"</string>
    - </resources>
    -diff --git a/packages/SystemUI/res/values-gl-rES/strings.xml b/packages/SystemUI/res/values-gl-rES/strings.xml
    -index 6d0e366..449c747 100644
    ---- a/packages/SystemUI/res/values-gl-rES/strings.xml
    -+++ b/packages/SystemUI/res/values-gl-rES/strings.xml
    -@@ -240,7 +240,7 @@
    -     <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"Os datos 4G están en pausa"</string>
    -     <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"Os datos de móbiles están en pausa"</string>
    -     <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"Os datos están en pausa"</string>
    --    <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"Como acadaches o límite de datos definido, o dispositivo puxo en pausa o uso de datos para o resto do ciclo.\n\nSe retomas o uso, poden aplicarse cargos do operador."</string>
    -+    <string name="data_usage_disabled_dialog" msgid="1841738975235283398">"Alcanzouse o límite de datos establecido e xa non utilizas datos móbiles.\n\nSe continúas, é posible que se apliquen cargos por uso de datos."</string>
    -     <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"Retomar"</string>
    -     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Sen Internet"</string>
    -     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi conectada"</string>
    -@@ -406,6 +406,7 @@
    -     <string name="device_owned_footer" msgid="3802752663326030053">"É posible que se supervise o dispositivo"</string>
    -     <string name="profile_owned_footer" msgid="8021888108553696069">"O perfil pódese supervisar"</string>
    -     <string name="vpn_footer" msgid="2388611096129106812">"É posible que se supervise a rede"</string>
    -+    <string name="branded_vpn_footer" msgid="2168111859226496230">"É posible que se supervise a rede"</string>
    -     <string name="monitoring_title_device_owned" msgid="7121079311903859610">"Supervisión de dispositivos"</string>
    -     <string name="monitoring_title_profile_owned" msgid="6790109874733501487">"Supervisión do perfil"</string>
    -     <string name="monitoring_title" msgid="169206259253048106">"Supervisión de rede"</string>
    -@@ -418,6 +419,7 @@
    -     <string name="legacy_vpn_name" msgid="6604123105765737830">"VPN"</string>
    -     <string name="monitoring_description_app" msgid="6259179342284742878">"Estás conectado a <xliff:g id="APPLICATION">%1$s</xliff:g>, que pode supervisar a túa actividade na rede, incluídos os correos electrónicos, as aplicacións e os sitios web."</string>
    -     <string name="monitoring_description_app_personal" msgid="484599052118316268">"Estás conectado a <xliff:g id="APPLICATION">%1$s</xliff:g>, que pode supervisar a túa actividade persoal na rede, incluídos os correos electrónicos, as aplicacións e os sitios web."</string>
    -+    <string name="branded_monitoring_description_app_personal" msgid="2669518213949202599">"Estás conectado a <xliff:g id="APPLICATION">%1$s</xliff:g>, que pode supervisar a túa actividade persoal na rede, incluídos os correos electrónicos, as aplicacións e os sitios web."</string>
    -     <string name="monitoring_description_app_work" msgid="1754325860918060897">"O teu perfil de traballo está xestionado por <xliff:g id="ORGANIZATION">%1$s</xliff:g>. Está conectado a <xliff:g id="APPLICATION">%2$s</xliff:g>, que pode supervisar a túa actividade na rede, incluídos os correos electrónicos, as aplicacións e os sitios web.\n\nPara obter máis información, ponte en contacto co teu administrador."</string>
    -     <string name="monitoring_description_app_personal_work" msgid="4946600443852045903">"O teu perfil de traballo está xestionado por <xliff:g id="ORGANIZATION">%1$s</xliff:g>. Está conectado a <xliff:g id="APPLICATION_WORK">%2$s</xliff:g>, que pode supervisar a túa actividade na rede, incluídos os correos electrónicos, as aplicacións e os sitios web.\n\nTamén estás conectado a <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g>, que pode supervisar a túa actividade persoal na rede."</string>
    -     <string name="monitoring_description_vpn_app_device_owned" msgid="4970443827043261703">"O dispositivo está xestionado por <xliff:g id="ORGANIZATION">%1$s</xliff:g>.\n\nO teu administrador pode supervisar e xestionar a configuración, o acceso corporativo, as aplicacións, os datos asociados co dispositivo e a información de localización do dispositivo.\n\nEstás conectado a <xliff:g id="APPLICATION">%2$s</xliff:g>, que pode supervisar a túa actividade na rede: os correos electrónicos, as aplicacións e os sitios web.\n\nPara obter máis información, contacta co teu administrador."</string>
    -@@ -494,8 +496,6 @@
    -     <string name="clock_seconds_desc" msgid="6282693067130470675">"Mostra os segundos do reloxo na barra de estado. Pode influír na duración da batería."</string>
    -     <string name="qs_rearrange" msgid="8060918697551068765">"Reorganizar Configuración rápida"</string>
    -     <string name="show_brightness" msgid="6613930842805942519">"Mostrar brillo en Configuración rápida"</string>
    --    <string name="overview_nav_bar_gesture" msgid="8579814204727917764">"Activar pantalla dividida pasando o dedo cara arriba"</string>
    --    <string name="overview_nav_bar_gesture_desc" msgid="6329167382305102615">"Activa o xesto de pasar o dedo cara arriba desde o botón Visión xeral para acceder ao modo de pantalla dividida"</string>
    -     <string name="experimental" msgid="6198182315536726162">"Experimental"</string>
    -     <string name="enable_bluetooth_title" msgid="5027037706500635269">"Queres activar o Bluetooth?"</string>
    -     <string name="enable_bluetooth_message" msgid="9106595990708985385">"Para conectar o teu teclado coa tableta, primeiro tes que activar o Bluetooth."</string>
    -@@ -653,4 +653,5 @@
    -     <string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"Abrir a configuración de <xliff:g id="ID_1">%s</xliff:g>."</string>
    -     <string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"Editar a orde das opcións de configuración."</string>
    -     <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"Páxina <xliff:g id="ID_1">%1$d</xliff:g> de <xliff:g id="ID_2">%2$d</xliff:g>"</string>
    -+    <string name="cant_silence_or_block" msgid="999689262131488625">"As notificacións non se poden silenciar nin bloquear"</string>
    - </resources>
    -diff --git a/packages/SystemUI/res/values-gu-rIN/strings.xml b/packages/SystemUI/res/values-gu-rIN/strings.xml
    -index 0663b41..5287576 100644
    ---- a/packages/SystemUI/res/values-gu-rIN/strings.xml
    -+++ b/packages/SystemUI/res/values-gu-rIN/strings.xml
    -@@ -238,7 +238,7 @@
    -     <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"4G ડેટા થોભાવ્યો છે"</string>
    -     <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"સેલ્યુલર ડેટા થોભાવ્યો છે"</string>
    -     <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"ડેટા થોભાવ્યો છે"</string>
    --    <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"તમે સેટ કરેલ ડેટા મર્યાદા સુધી પહોંચી ગયા હોવાથી, ઉપકરણે આ ચક્રના શેષ માટે ડેટા વપરાશ થોભાવ્યો છે.\n\nફરીથી શરૂ કરવું તમારા કેરીઅર તરફથી શુલ્ક તરફ દોરી શકે છે."</string>
    -+    <string name="data_usage_disabled_dialog" msgid="1841738975235283398">"તમારા દ્વારા સેટ કરેલ ડેટા મર્યાદા પર તમે પહોંચી ગયાં છો. તમે હવે સેલ્યુલર ડેટાનો ઉપયોગ કરી રહ્યાં નથી.\n\nજો તમે ફરી શરૂ કરો છો, તો ડેટા વપરાશ માટે શુલ્ક લાગુ થઈ શકે છે."</string>
    -     <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"ફરી શરૂ કરો"</string>
    -     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"કોઈ ઇન્ટરનેટ કનેક્શન નથી"</string>
    -     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi કનેક્ટ કર્યું"</string>
    -@@ -404,6 +404,7 @@
    -     <string name="device_owned_footer" msgid="3802752663326030053">"ઉપકરણ મૉનિટર કરી શકાય છે"</string>
    -     <string name="profile_owned_footer" msgid="8021888108553696069">"પ્રોફાઇલ મૉનિટર કરી શકાય છે"</string>
    -     <string name="vpn_footer" msgid="2388611096129106812">"નેટવર્ક મૉનિટર કરી શકાય છે"</string>
    -+    <string name="branded_vpn_footer" msgid="2168111859226496230">"નેટવર્ક મૉનિટર કરવામાં આવી શકે છે"</string>
    -     <string name="monitoring_title_device_owned" msgid="7121079311903859610">"ઉપકરણ નિરીક્ષણ"</string>
    -     <string name="monitoring_title_profile_owned" msgid="6790109874733501487">"પ્રોફાઇલ નિરીક્ષણ"</string>
    -     <string name="monitoring_title" msgid="169206259253048106">"નેટવર્ક મૉનિટરિંગ"</string>
    -@@ -416,6 +417,7 @@
    -     <string name="legacy_vpn_name" msgid="6604123105765737830">"VPN"</string>
    -     <string name="monitoring_description_app" msgid="6259179342284742878">"તમે <xliff:g id="APPLICATION">%1$s</xliff:g> સાથે કનેક્ટ થયાં છો, જે ઇમેઇલ્સ, ઍપ્લિકેશનો અને વેબસાઇટ્સ સહિતની તમારી નેટવર્ક પ્રવૃત્તિને મૉનિટર કરી શકે છે."</string>
    -     <string name="monitoring_description_app_personal" msgid="484599052118316268">"તમે <xliff:g id="APPLICATION">%1$s</xliff:g> સાથે કનેક્ટ થયાં છો, જે ઇમેઇલ્સ, ઍપ્લિકેશનો અને વેબસાઇટ્સ સહિતની તમારી વ્યક્તિગત નેટવર્ક પ્રવૃત્તિને મૉનિટર કરી શકે છે."</string>
    -+    <string name="branded_monitoring_description_app_personal" msgid="2669518213949202599">"તમે <xliff:g id="APPLICATION">%1$s</xliff:g> સાથે કનેક્ટ થયાં છો, જે ઇમેઇલ્સ, ઍપ્લિકેશનો અને વેબસાઇટ્સ સહિત તમારી વ્યક્તિગત નેટવર્ક પ્રવૃત્તિને મૉનિટર કરી શકે છે."</string>
    -     <string name="monitoring_description_app_work" msgid="1754325860918060897">"તમારી કાર્ય પ્રોફાઇલ <xliff:g id="ORGANIZATION">%1$s</xliff:g> દ્વારા સંચાલિત થાય છે. તે <xliff:g id="APPLICATION">%2$s</xliff:g> સાથે કનેક્ટ થયેલ છે, જે ઇમેઇલ્સ, ઍપ્લિકેશનો અને વેબસાઇટ્સ સહિતની તમારી કાર્ય નેટવર્ક પ્રવૃત્તિને મૉનિટર કરી શકે છે.\n\nવધુ માહિતી માટે, તમારા વ્યવસ્થાપકનો સંપર્ક કરો."</string>
    -     <string name="monitoring_description_app_personal_work" msgid="4946600443852045903">"તમારી કાર્ય પ્રોફાઇલ <xliff:g id="ORGANIZATION">%1$s</xliff:g> દ્વારા સંચાલિત થાય છે. તે <xliff:g id="APPLICATION_WORK">%2$s</xliff:g> સાથે કનેક્ટ થયેલ છે, જે ઇમેઇલ્સ, ઍપ્લિકેશનો અને વેબસાઇટ્સ સહિતની તમારી કાર્ય નેટવર્ક પ્રવૃત્તિને મૉનિટર કરી શકે છે.\n\nતમે <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g> સાથે પણ કનેક્ટ થયેલ છો, જે તમારી વ્યક્તિગત નેટવર્ક પ્રવૃત્તિને મૉનિટર કરી શકે છે."</string>
    -     <string name="monitoring_description_vpn_app_device_owned" msgid="4970443827043261703">"તમારું ઉપકરણ <xliff:g id="ORGANIZATION">%1$s</xliff:g> દ્વારા સંચાલિત થાય છે.\n\nતમારા વ્યવસ્થાપક, સેટિંગ્સ, કોર્પોરેટ ઍક્સેસ, ઍપ્લિકેશનો, તમારા ઉપકરણ સાથે સંકળાયેલ ડેટા અને તમારા ઉપકરણની સ્થાન માહિતીને મૉનિટર કરી અને સંચાલિત કરી શકે છે.\n\nતમે <xliff:g id="APPLICATION">%2$s</xliff:g> સાથે કનેક્ટ થયાં છો, જે ઇમેઇલ્સ, ઍપ્લિકેશનો અને વેબસાઇટ્સ સહિતની તમારી નેટવર્ક પ્રવૃત્તિને મૉનિટર કરી શકે છે.\n\nવધુ માહિતી માટે, તમારા વ્યવસ્થાપકનો સંપર્ક કરો."</string>
    -@@ -492,8 +494,6 @@
    -     <string name="clock_seconds_desc" msgid="6282693067130470675">"ઘડિયાળ સેકન્ડ સ્થિતિ બારમાં બતાવો. બૅટરીની આવરદા પર અસર કરી શકે છે."</string>
    -     <string name="qs_rearrange" msgid="8060918697551068765">"ઝડપી સેટિંગ્સને ફરીથી ગોઠવો"</string>
    -     <string name="show_brightness" msgid="6613930842805942519">"ઝડપી સેટિંગ્સમાં તેજ બતાવો"</string>
    --    <string name="overview_nav_bar_gesture" msgid="8579814204727917764">"સ્પ્લિટ-સ્ક્રીન સ્વાઇપ-અપ હાવભાવ સક્ષમ કરો"</string>
    --    <string name="overview_nav_bar_gesture_desc" msgid="6329167382305102615">"વિહંગાવલોકન બટનમાંથી સ્વાઇપ કરીને સ્પ્લિટ-સ્ક્રીનમાં દાખલ થવા માટે હાવભાવ સક્ષમ કરો"</string>
    -     <string name="experimental" msgid="6198182315536726162">"પ્રાયોગિક"</string>
    -     <string name="enable_bluetooth_title" msgid="5027037706500635269">"Bluetooth ચાલુ કરવુ છે?"</string>
    -     <string name="enable_bluetooth_message" msgid="9106595990708985385">"તમારા ટેબ્લેટ સાથે કીબોર્ડ કનેક્ટ કરવા માટે, તમારે પહેલાં Bluetooth ચાલુ કરવાની જરૂર પડશે."</string>
    -@@ -651,4 +651,5 @@
    -     <string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"<xliff:g id="ID_1">%s</xliff:g> સેટિંગ્સ ખોલો."</string>
    -     <string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"સેટિંગ્સનો ક્રમ સંપાદિત કરો."</string>
    -     <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"<xliff:g id="ID_2">%2$d</xliff:g> માંથી <xliff:g id="ID_1">%1$d</xliff:g> પૃષ્ઠ"</string>
    -+    <string name="cant_silence_or_block" msgid="999689262131488625">"સૂચનાઓ શાંત અથવા અવરોધિત કરી શકાતી નથી"</string>
    - </resources>
    -diff --git a/packages/SystemUI/res/values-hi/strings.xml b/packages/SystemUI/res/values-hi/strings.xml
    -index 2924556..5c24fe2 100644
    ---- a/packages/SystemUI/res/values-hi/strings.xml
    -+++ b/packages/SystemUI/res/values-hi/strings.xml
    -@@ -238,7 +238,7 @@
    -     <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"4G डेटा रोक दिया गया है"</string>
    -     <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"सेल्युलर डेटा रोक दिया गया है"</string>
    -     <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"डेटा रोक दिया गया है"</string>
    --    <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"चूंकि आपके निर्धारित डेटा की सीमा, सीमा पर पहुंच गई थी, इसलिए डिवाइस ने इस चक्र के रिमाइंडर के लिए डेटा उपयोग को रोक दिया है.\n\nफिर से शुरू करने से आपके वाहक की ओर से शुल्क लगाया जाता है."</string>
    -+    <string name="data_usage_disabled_dialog" msgid="1841738975235283398">"आपकी सेट की हुई डेटा सीमा समाप्त हो गई है. अब आप सेल्युलर डेटा का उपयोग नहीं कर रहे हैं.\n\nयदि आप फिर से शुरू करते हैं, तो डेटा उपयोग के लिए शुल्क लग सकता है."</string>
    -     <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"फिर से शुरू करें"</string>
    -     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"कोई इंटरनेट कनेक्शन नहीं"</string>
    -     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"वाई-फ़ाई  कनेक्‍ट किया गया"</string>
    -@@ -404,6 +404,7 @@
    -     <string name="device_owned_footer" msgid="3802752663326030053">"डिवाइस को मॉनीटर किया जा सकता है"</string>
    -     <string name="profile_owned_footer" msgid="8021888108553696069">"प्रोफ़ाइल को मॉनीटर किया जा सकता है"</string>
    -     <string name="vpn_footer" msgid="2388611096129106812">"नेटवर्क को मॉनीटर किया जा सकता है"</string>
    -+    <string name="branded_vpn_footer" msgid="2168111859226496230">"नेटवर्क को मॉनिटर किया जा सकता है"</string>
    -     <string name="monitoring_title_device_owned" msgid="7121079311903859610">"डिवाइस को मॉनीटर करना"</string>
    -     <string name="monitoring_title_profile_owned" msgid="6790109874733501487">"प्रोफ़ाइल को मॉनीटर करना"</string>
    -     <string name="monitoring_title" msgid="169206259253048106">"नेटवर्क को मॉनीटर करना"</string>
    -@@ -416,6 +417,7 @@
    -     <string name="legacy_vpn_name" msgid="6604123105765737830">"VPN"</string>
    -     <string name="monitoring_description_app" msgid="6259179342284742878">"आप <xliff:g id="APPLICATION">%1$s</xliff:g> से कनेक्‍ट हैं, जो ईमेल, ऐप्‍स और वेबसाइटों सहित आपकी नेटवर्क गतिविधि की निगरानी कर सकता है."</string>
    -     <string name="monitoring_description_app_personal" msgid="484599052118316268">"आप <xliff:g id="APPLICATION">%1$s</xliff:g> से कनेक्‍ट हैं, जो ईमेल, ऐप्‍स और वेबसाइटों सहित आपकी व्‍यक्‍तिगत नेटवर्क गतिविधि की निगरानी कर सकता है."</string>
    -+    <string name="branded_monitoring_description_app_personal" msgid="2669518213949202599">"आप <xliff:g id="APPLICATION">%1$s</xliff:g> से कनेक्‍ट हैं, जो ईमेल, ऐप्लिकेशन और वेबसाइट सहित आपकी व्‍यक्‍तिगत नेटवर्क गतिविधि को मॉनिटर कर सकता है."</string>
    -     <string name="monitoring_description_app_work" msgid="1754325860918060897">"आपकी कार्य प्रोफ़ाइल <xliff:g id="ORGANIZATION">%1$s</xliff:g> के द्वारा प्रबंधित है. वह <xliff:g id="APPLICATION">%2$s</xliff:g> से कनेक्‍ट है, जो ईमेल, ऐप्‍स और वेबसाइटों सहित आपकी कार्य नेटवर्क गतिविधि की निगरानी कर सकता है.\n\nअधिक जानकारी के लिए, अपने नियंत्रक से संपर्क करें."</string>
    -     <string name="monitoring_description_app_personal_work" msgid="4946600443852045903">"आपकी कार्य प्रोफ़ाइल <xliff:g id="ORGANIZATION">%1$s</xliff:g> के द्वारा प्रबंधित है. वह <xliff:g id="APPLICATION_WORK">%2$s</xliff:g> से कनेक्‍ट है, जो ईमेल, ऐप्‍स और वेबसाइटों सहित आपकी कार्य नेटवर्क गतिविधि की निगरानी कर सकता है.\n\nआप <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g> से भी कनेक्‍ट हैं, जो आपकी व्‍यक्‍तिगत नेटवर्क गतिविधि की निगरानी कर सकता है."</string>
    -     <string name="monitoring_description_vpn_app_device_owned" msgid="4970443827043261703">"आपका डिवाइस <xliff:g id="ORGANIZATION">%1$s</xliff:g> के द्वारा प्रबंधित है.\n\nआपका नियंत्रक सेटिंग, कॉर्पोरेट ऐक्‍सेस, ऐप्स, आपके डिवाइस से संबद्ध डेटा और आपके डिवाइस की स्‍थान जानकारी की निगरानी और उसका प्रबंधन कर सकता है.\n\nआप <xliff:g id="APPLICATION">%2$s</xliff:g> से कनेक्‍ट हैं, जो ईमेल, ऐप्‍स और वेबसाइटों सहित आपकी नेटवर्क गतिविधि की निगरानी कर सकता है.\n\nअधिक जानकारी के लिए, अपने नियंत्रक से संपर्क करें."</string>
    -@@ -492,8 +494,6 @@
    -     <string name="clock_seconds_desc" msgid="6282693067130470675">"स्थिति बार में घड़ी के सेकंड दिखाएं. इससे बैटरी के जीवनकाल पर प्रभाव पड़ सकता है."</string>
    -     <string name="qs_rearrange" msgid="8060918697551068765">"त्वरित सेटिंग को पुन: व्यवस्थित करें"</string>
    -     <string name="show_brightness" msgid="6613930842805942519">"त्वरित सेटिंग में स्क्रीन की रोशनी दिखाएं"</string>
    --    <string name="overview_nav_bar_gesture" msgid="8579814204727917764">"ऊपर स्वाइप करके विभाजित स्क्रीन में जाने का जेस्चर सक्षम करें"</string>
    --    <string name="overview_nav_bar_gesture_desc" msgid="6329167382305102615">"अवलोकन बटन से ऊपर स्वाइप करके स्क्रीन विभाजन में आने का हावभाव सक्षम करें"</string>
    -     <string name="experimental" msgid="6198182315536726162">"प्रयोगात्मक"</string>
    -     <string name="enable_bluetooth_title" msgid="5027037706500635269">"ब्लूटूथ चालू करें?"</string>
    -     <string name="enable_bluetooth_message" msgid="9106595990708985385">"अपने कीबोर्ड को अपने टैबलेट से कनेक्ट करने के लिए, आपको पहले ब्लूटूथ चालू करना होगा."</string>
    -@@ -651,4 +651,5 @@
    -     <string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"<xliff:g id="ID_1">%s</xliff:g> सेटिंग खोलें."</string>
    -     <string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"सेटिंग का क्रम संपादित करें."</string>
    -     <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"पृष्ठ <xliff:g id="ID_2">%2$d</xliff:g> में से <xliff:g id="ID_1">%1$d</xliff:g>"</string>
    -+    <string name="cant_silence_or_block" msgid="999689262131488625">"नोटिफ़िकेशन मौन या अवरुद्ध नहीं किए जा सकते हैं"</string>
    - </resources>
    -diff --git a/packages/SystemUI/res/values-hr/strings.xml b/packages/SystemUI/res/values-hr/strings.xml
    -index 02466d6..df3ccf1 100644
    ---- a/packages/SystemUI/res/values-hr/strings.xml
    -+++ b/packages/SystemUI/res/values-hr/strings.xml
    -@@ -239,7 +239,7 @@
    -     <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"4G podaci pauzirani"</string>
    -     <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"Mobilni podaci pauzirani"</string>
    -     <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"Podaci su pauzirani"</string>
    --    <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"Budući da je dosegnuto postavljeno ograničenje podataka, uređaj je pauzirao upotrebu podataka za preostali dio ovog ciklusa.\n\nMobilni operater može naplatiti daljnju upotrebu."</string>
    -+    <string name="data_usage_disabled_dialog" msgid="1841738975235283398">"Dosegnuto je vaše ograničenje podataka. Više ne upotrebljavate mobilne podatke.\n\nAko nastavite, moguća je naplata za potrošnju podataka."</string>
    -     <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"Nastavi"</string>
    -     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Nema internetske veze"</string>
    -     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi povezan"</string>
    -@@ -406,6 +406,7 @@
    -     <string name="device_owned_footer" msgid="3802752663326030053">"Uređaj se možda nadzire"</string>
    -     <string name="profile_owned_footer" msgid="8021888108553696069">"Profil se možda nadzire"</string>
    -     <string name="vpn_footer" msgid="2388611096129106812">"Mreža se možda nadzire"</string>
    -+    <string name="branded_vpn_footer" msgid="2168111859226496230">"Mreža se možda nadzire"</string>
    -     <string name="monitoring_title_device_owned" msgid="7121079311903859610">"Nadzor uređaja"</string>
    -     <string name="monitoring_title_profile_owned" msgid="6790109874733501487">"Nadzor profila"</string>
    -     <string name="monitoring_title" msgid="169206259253048106">"Nadzor mreže"</string>
    -@@ -418,6 +419,7 @@
    -     <string name="legacy_vpn_name" msgid="6604123105765737830">"VPN"</string>
    -     <string name="monitoring_description_app" msgid="6259179342284742878">"Povezani ste s aplikacijom <xliff:g id="APPLICATION">%1$s</xliff:g> koja može nadzirati vašu aktivnost na mreži, uključujući e-poštu, aplikacije i web-lokacije."</string>
    -     <string name="monitoring_description_app_personal" msgid="484599052118316268">"Povezani ste s aplikacijom <xliff:g id="APPLICATION">%1$s</xliff:g> koja može nadzirati vašu osobnu aktivnost na mreži, uključujući e-poštu, aplikacije i web-lokacije."</string>
    -+    <string name="branded_monitoring_description_app_personal" msgid="2669518213949202599">"Povezani ste s aplikacijom <xliff:g id="APPLICATION">%1$s</xliff:g> koja može nadzirati vašu osobnu aktivnost na mreži, uključujući e-poštu, aplikacije i web-lokacije."</string>
    -     <string name="monitoring_description_app_work" msgid="1754325860918060897">"Vašim poslovnim profilom upravlja <xliff:g id="ORGANIZATION">%1$s</xliff:g>. Povezan je s aplikacijom <xliff:g id="APPLICATION">%2$s</xliff:g> koja može nadzirati vašu poslovnu aktivnost na mreži, uključujući e-poštu, aplikacije i web-lokacije.\n\nObratite se svojem administratoru za više informacija."</string>
    -     <string name="monitoring_description_app_personal_work" msgid="4946600443852045903">"Vašim poslovnim profilom upravlja <xliff:g id="ORGANIZATION">%1$s</xliff:g>. Povezan je s aplikacijom <xliff:g id="APPLICATION_WORK">%2$s</xliff:g> koja može nadzirati vašu poslovnu aktivnost na mreži, uključujući e-poštu, aplikacije i web-lokacije.\n\nPovezani ste i s aplikacijom <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g> koja može nadzirati vašu osobnu aktivnost na mreži."</string>
    -     <string name="monitoring_description_vpn_app_device_owned" msgid="4970443827043261703">"Vašim uređajem upravlja <xliff:g id="ORGANIZATION">%1$s</xliff:g>.\n\nVaš administrator može nadzirati postavke, poslovni pristup, aplikacije, podatke povezane s uređajem i podatke o lokaciji uređaja te upravljati njima.\n\nPovezani ste s aplikacijom <xliff:g id="APPLICATION">%2$s</xliff:g> koja može nadzirati vašu aktivnost na mreži, uključujući e-poštu, aplikacije i web-lokacije.\n\nObratite se svojem administratoru za više informacija."</string>
    -@@ -494,8 +496,6 @@
    -     <string name="clock_seconds_desc" msgid="6282693067130470675">"Prikazuju se sekunde na satu na traci statusa. Može utjecati na trajanje baterije."</string>
    -     <string name="qs_rearrange" msgid="8060918697551068765">"Promijeni raspored Brzih postavki"</string>
    -     <string name="show_brightness" msgid="6613930842805942519">"Prikaži svjetlinu u Brzim postavkama"</string>
    --    <string name="overview_nav_bar_gesture" msgid="8579814204727917764">"Omogući pokret povlačenja prema gore za podijeljen zaslon"</string>
    --    <string name="overview_nav_bar_gesture_desc" msgid="6329167382305102615">"Omogućivanje pokreta za otvaranje podijeljenog zaslona tako da se od gumba Pregled prstom prijeđe prema gore"</string>
    -     <string name="experimental" msgid="6198182315536726162">"Eksperimentalno"</string>
    -     <string name="enable_bluetooth_title" msgid="5027037706500635269">"Želite li uključiti Bluetooth?"</string>
    -     <string name="enable_bluetooth_message" msgid="9106595990708985385">"Da biste povezali tipkovnicu s tabletom, morate uključiti Bluetooth."</string>
    -@@ -653,4 +653,5 @@
    -     <string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"Otvaranje postavki za <xliff:g id="ID_1">%s</xliff:g>."</string>
    -     <string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"Uređivanje redoslijeda postavki."</string>
    -     <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"Stranica <xliff:g id="ID_1">%1$d</xliff:g> od <xliff:g id="ID_2">%2$d</xliff:g>"</string>
    -+    <string name="cant_silence_or_block" msgid="999689262131488625">"Obavijesti se ne mogu utišati niti blokirati"</string>
    - </resources>
    -diff --git a/packages/SystemUI/res/values-hu/strings.xml b/packages/SystemUI/res/values-hu/strings.xml
    -index b89b106..425212a 100644
    ---- a/packages/SystemUI/res/values-hu/strings.xml
    -+++ b/packages/SystemUI/res/values-hu/strings.xml
    -@@ -238,7 +238,7 @@
    -     <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"A 4G adatforgalom szünetel"</string>
    -     <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"A mobilhálózati adatforgalom szünetel"</string>
    -     <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"Az adatforgalom szünetel"</string>
    --    <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"Mivel elérte a beállított adatkorlátot, az eszköz a ciklus fennmaradó részére felfüggesztette az adathasználatot.\n\nHa mégis használja az adatkapcsolatot, akkor szolgáltatója többletköltséget számíthat fel."</string>
    -+    <string name="data_usage_disabled_dialog" msgid="1841738975235283398">"Elérte a beállított adatkorlátot. A továbbiakban nem használ mobiladat-forgalmat.\n\nHa a folytatást választja, szolgáltatója adathasználati díjat számíthat fel."</string>
    -     <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"Folytatás"</string>
    -     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Nincs internet"</string>
    -     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi csatlakoztatva"</string>
    -@@ -404,6 +404,7 @@
    -     <string name="device_owned_footer" msgid="3802752663326030053">"Lehet, hogy az eszközt figyelik"</string>
    -     <string name="profile_owned_footer" msgid="8021888108553696069">"Profilját felügyelhetik"</string>
    -     <string name="vpn_footer" msgid="2388611096129106812">"Lehet, hogy a hálózatot figyelik"</string>
    -+    <string name="branded_vpn_footer" msgid="2168111859226496230">"Lehet, hogy a hálózat felügyelt"</string>
    -     <string name="monitoring_title_device_owned" msgid="7121079311903859610">"Eszközfigyelés"</string>
    -     <string name="monitoring_title_profile_owned" msgid="6790109874733501487">"Profilfelügyelet"</string>
    -     <string name="monitoring_title" msgid="169206259253048106">"Hálózatfigyelés"</string>
    -@@ -416,6 +417,7 @@
    -     <string name="legacy_vpn_name" msgid="6604123105765737830">"VPN"</string>
    -     <string name="monitoring_description_app" msgid="6259179342284742878">"Csatlakoztatta a(z) <xliff:g id="APPLICATION">%1$s</xliff:g> alkalmazást, amely figyelheti hálózati tevékenységét, beleértve az e-maileket, az alkalmazásokat és a webhelyeket."</string>
    -     <string name="monitoring_description_app_personal" msgid="484599052118316268">"Csatlakoztatta a(z) <xliff:g id="APPLICATION">%1$s</xliff:g> alkalmazást, amely figyelheti személyes hálózati tevékenységét, beleértve az e-maileket, az alkalmazásokat és a webhelyeket."</string>
    -+    <string name="branded_monitoring_description_app_personal" msgid="2669518213949202599">"Ön a(z) <xliff:g id="APPLICATION">%1$s</xliff:g> alkalmazáshoz csatlakozik, amely figyelheti személyes hálózati tevékenységét, beleértve az e-maileket, alkalmazásokat és webhelyeket."</string>
    -     <string name="monitoring_description_app_work" msgid="1754325860918060897">"Munkaprofilját a(z) <xliff:g id="ORGANIZATION">%1$s</xliff:g> felügyeli. Csatlakoztatva van hozzá a(z) <xliff:g id="APPLICATION">%2$s</xliff:g> alkalmazás, amely figyelheti az Ön hálózati tevékenységét, beleértve az e-maileket, az alkalmazásokat és a webhelyeket.\n\nTovábbi információért forduljon a rendszergazdájához."</string>
    -     <string name="monitoring_description_app_personal_work" msgid="4946600443852045903">"Munkaprofilját a(z) <xliff:g id="ORGANIZATION">%1$s</xliff:g> felügyeli. Csatlakoztatva van hozzá a(z) <xliff:g id="APPLICATION_WORK">%2$s</xliff:g> alkalmazás, amely figyelheti az Ön hálózati tevékenységét, beleértve az e-maileket, az alkalmazásokat és a webhelyeket.\n\nCsatlakoztatta továbbá a(z) <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g> alkalmazást, amely szintén figyelemmel kísérheti személyes hálózati tevékenységét."</string>
    -     <string name="monitoring_description_vpn_app_device_owned" msgid="4970443827043261703">"Eszközét a következő felügyeli: <xliff:g id="ORGANIZATION">%1$s</xliff:g>.\n\nA rendszergazda figyelemmel kísérheti és módosíthatja beállításait, vállalati hozzáféréseit, alkalmazásait, az eszközéhez társított adatokat és eszköze helyadatait.\n\nÖn a következőhöz csatlakozik: <xliff:g id="APPLICATION">%2$s</xliff:g>, amely (az e-mailekre, alkalmazásokra és webhelyekre is kiterjedően) figyelemmel kísérheti hálózati tevékenységét.\n\nTovábbi információért forduljon a rendszergazdához."</string>
    -@@ -481,7 +483,7 @@
    -     <string name="accessibility_status_bar_hotspot" msgid="4099381329956402865">"Hotspot"</string>
    -     <string name="accessibility_managed_profile" msgid="6613641363112584120">"Munkaprofil"</string>
    -     <string name="tuner_warning_title" msgid="7094689930793031682">"Egyeseknek tetszik, másoknak nem"</string>
    --    <string name="tuner_warning" msgid="8730648121973575701">"A Kezelőfelület-hangoló az Android felhasználói felületének szerkesztéséhez és testreszabásához nyújt további megoldásokat. Ezek a kísérleti funkciók változhatnak vagy megsérülhetnek a későbbi kiadásokban,illetve eltűnhetnek azokból. Körültekintően járjon el."</string>
    -+    <string name="tuner_warning" msgid="8730648121973575701">"A Kezelőfelület-hangoló az Android felhasználói felületének szerkesztéséhez és testreszabásához nyújt további megoldásokat. Ezek a kísérleti funkciók változhatnak vagy megsérülhetnek a későbbi kiadásokban, illetve eltűnhetnek azokból. Körültekintően járjon el."</string>
    -     <string name="tuner_persistent_warning" msgid="8597333795565621795">"Ezek a kísérleti funkciók változhatnak vagy megsérülhetnek a későbbi kiadásokban, illetve eltűnhetnek azokból. Körültekintően járjon el."</string>
    -     <string name="got_it" msgid="2239653834387972602">"Értem"</string>
    -     <string name="tuner_toast" msgid="603429811084428439">"Gratulálunk! A Kezelőfelület-hangolót hozzáadtuk a Beállításokhoz"</string>
    -@@ -492,8 +494,6 @@
    -     <string name="clock_seconds_desc" msgid="6282693067130470675">"Másodpercek megjelenítése az állapotsor óráján. Ez hatással lehet az akkumulátor üzemidejére."</string>
    -     <string name="qs_rearrange" msgid="8060918697551068765">"Gyorsbeállítások átrendezése"</string>
    -     <string name="show_brightness" msgid="6613930842805942519">"Fényerő megjelenítése a gyorsbeállításokban"</string>
    --    <string name="overview_nav_bar_gesture" msgid="8579814204727917764">"Képernyőfelosztó gyors felfelé csúsztatás engedélyezése"</string>
    --    <string name="overview_nav_bar_gesture_desc" msgid="6329167382305102615">"Kézmozdulat engedélyezése osztott képernyős nézet aktiválásához, ha az Áttekintés gombról felfelé húzza az ujját"</string>
    -     <string name="experimental" msgid="6198182315536726162">"Kísérleti"</string>
    -     <string name="enable_bluetooth_title" msgid="5027037706500635269">"Engedélyezi a Bluetooth-kapcsolatot?"</string>
    -     <string name="enable_bluetooth_message" msgid="9106595990708985385">"Ha a billentyűzetet csatlakoztatni szeretné táblagépéhez, először engedélyeznie kell a Bluetooth-kapcsolatot."</string>
    -@@ -651,4 +651,5 @@
    -     <string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"A(z) <xliff:g id="ID_1">%s</xliff:g> beállításainak megnyitása."</string>
    -     <string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"Beállítások sorrendjének szerkesztése."</string>
    -     <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"<xliff:g id="ID_1">%1$d</xliff:g>. oldal, összesen: <xliff:g id="ID_2">%2$d</xliff:g>"</string>
    -+    <string name="cant_silence_or_block" msgid="999689262131488625">"Az értesítéseket nem lehet elnémítani vagy letiltani"</string>
    - </resources>
    -diff --git a/packages/SystemUI/res/values-hy-rAM/strings.xml b/packages/SystemUI/res/values-hy-rAM/strings.xml
    -index d0d6c50..77b1c82 100644
    ---- a/packages/SystemUI/res/values-hy-rAM/strings.xml
    -+++ b/packages/SystemUI/res/values-hy-rAM/strings.xml
    -@@ -32,7 +32,7 @@
    -     <string name="status_bar_no_notifications_title" msgid="4755261167193833213">"Ծանուցումներ չկան"</string>
    -     <string name="status_bar_ongoing_events_title" msgid="1682504513316879202">"Ընթացիկ"</string>
    -     <string name="status_bar_latest_events_title" msgid="6594767438577593172">"Ծանուցումներ"</string>
    --    <string name="battery_low_title" msgid="6456385927409742437">"Մարտկոցը լիցքաթափվում է"</string>
    -+    <string name="battery_low_title" msgid="6456385927409742437">"Մարտկոցի լիցքը սպառվում է"</string>
    -     <string name="battery_low_percent_format" msgid="2900940511201380775">"Մնաց <xliff:g id="PERCENTAGE">%s</xliff:g>"</string>
    -     <string name="battery_low_percent_format_saver_started" msgid="6859235584035338833">"Մնաց <xliff:g id="PERCENTAGE">%s</xliff:g>: Մարտկոցի տնտեսումը միացված է:"</string>
    -     <string name="invalid_charger" msgid="4549105996740522523">"USB լիցքավորումը չի աջակցվում:\nՕգտվեք միայն գործող լիցքավորիչից:"</string>
    -@@ -238,7 +238,7 @@
    -     <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"4Գ տվյալների օգտագործումը դադարեցված է"</string>
    -     <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"Բջջային տվյալների օգտագործումը դադարեցված է"</string>
    -     <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"Տվյալների օգտագործումը դադարեցված է"</string>
    --    <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"Քանի որ ձեր սահմանված տվյալների սահմանաչափը սպառվել է, սարքն այլևս չի օգտագործի տվյալները այս ցիկլի մնացած ընթացքում:\n\nԵթե վերսկսեք, հնարավոր է կիրառվեն գանձումներ ձեր օպերատորի կողմից:"</string>
    -+    <string name="data_usage_disabled_dialog" msgid="1841738975235283398">"Տվյալների օգտագործման համար նշված սահմանաչափը լրացել է: Դուք բջջային տվյալներ այլևս չեք օգտագործում:\n\nԵթե վերսկսեք բջջային տվյալների օգտագործումը, դրա համար կարող են վճարներ գանձվել:"</string>
    -     <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"Վերսկսել"</string>
    -     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Ինտերնետ կապ չկա"</string>
    -     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi-ը միացված է"</string>
    -@@ -404,6 +404,7 @@
    -     <string name="device_owned_footer" msgid="3802752663326030053">"Սարքը կարող է վերահսկվել"</string>
    -     <string name="profile_owned_footer" msgid="8021888108553696069">"Պրոֆիլը կարող է վերահսկվել"</string>
    -     <string name="vpn_footer" msgid="2388611096129106812">"Ցանցը կարող է վերահսկվել"</string>
    -+    <string name="branded_vpn_footer" msgid="2168111859226496230">"Ցանցը կարող է վերահսկվել"</string>
    -     <string name="monitoring_title_device_owned" msgid="7121079311903859610">"Սարքի մշտադիտարկում"</string>
    -     <string name="monitoring_title_profile_owned" msgid="6790109874733501487">"Պրոֆիլի վերահսկում"</string>
    -     <string name="monitoring_title" msgid="169206259253048106">"Ցանցի մշտադիտարկում"</string>
    -@@ -416,6 +417,7 @@
    -     <string name="legacy_vpn_name" msgid="6604123105765737830">"VPN"</string>
    -     <string name="monitoring_description_app" msgid="6259179342284742878">"Դուք կապակցված եք <xliff:g id="APPLICATION">%1$s</xliff:g> հավելվածին, որը կարող է վերահսկել ձեր ցանցի գործունեությունը, այդ թվում նաև էլփոստի հաշիվները, հավելվածները և կայքերը:"</string>
    -     <string name="monitoring_description_app_personal" msgid="484599052118316268">"Դուք կապակցված եք <xliff:g id="APPLICATION">%1$s</xliff:g> հավելվածին, որը կարող է վերահսկել անձնական ցանցում կատարած ձեր գործողությունները, այդ թվում նաև էլփոստի հաշիվները, հավելվածները և կայքերը:"</string>
    -+    <string name="branded_monitoring_description_app_personal" msgid="2669518213949202599">"Դուք կապակցված եք <xliff:g id="APPLICATION">%1$s</xliff:g> հավելվածին, որը կարող է վերահսկել անձնական ցանցում կատարած ձեր գործողությունները, այդ թվում նաև էլփոստի հաշիվները, հավելվածները և կայքերը:"</string>
    -     <string name="monitoring_description_app_work" msgid="1754325860918060897">"Աշխատանքային պրոֆիլի կառավարիչն է՝ <xliff:g id="ORGANIZATION">%1$s</xliff:g>: Այն կապակցված է <xliff:g id="APPLICATION">%2$s</xliff:g> հավելվածին, որը կարող է վերահսկել աշխատանքային ցանցում կատարած գործունեությունը, այդ թվում նաև էլփոստի հաշիվները, հավելվածները և կայքերը:\n\nԼրացուցիչ տեղեկությունների համար դիմեք ադմինիստրատորին:"</string>
    -     <string name="monitoring_description_app_personal_work" msgid="4946600443852045903">"Աշխատանքային պրոֆիլի կառավարիչն է՝ <xliff:g id="ORGANIZATION">%1$s</xliff:g>: Այն կապակցված է <xliff:g id="APPLICATION_WORK">%2$s</xliff:g> հավելվածին, որը կարող է վերահսկել աշխատանքային ցանցում կատարած գործունեությունը, այդ թվում նաև էլփոստի հաշիվները, հավելվածները և կայքերը:\n\nԴուք նույնպես կապակցված եք <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g> հավելվածին, որը կարող է վերահսկել անձնական ցանցում կատարած ձեր գործողությունները:"</string>
    -     <string name="monitoring_description_vpn_app_device_owned" msgid="4970443827043261703">"Սարքի կառավարիչն է՝ <xliff:g id="ORGANIZATION">%1$s</xliff:g>:\n\nԱդմինիստրատորը կարող է վերահսկել և կառավարել կարգավորումները, կորպորատիվ հաշիվը, հավելվածները, սարքի հետ առնչվող և սարքի տեղադրության տվյալները:\n\nՆաև կապակցված եք <xliff:g id="APPLICATION">%2$s</xliff:g> հավելվածին, ինչը կարող է վերահսկել ձեր ցանցի գործունեությունը, այդ թվում նաև՝ էլփոստի հաշիվները, հավելվածները և կայքերը:\n\nԼրացուցիչ տեղեկությունների համար դիմեք ադմինիստրատորին:"</string>
    -@@ -492,8 +494,6 @@
    -     <string name="clock_seconds_desc" msgid="6282693067130470675">"Ցույց տալ ժամացույցի վայրկյանները կարգավիճակի տողում: Կարող է ազդել մարտկոցի աշխատանքի ժամանակի վրա:"</string>
    -     <string name="qs_rearrange" msgid="8060918697551068765">"Վերադասավորել Արագ կարգավորումները"</string>
    -     <string name="show_brightness" msgid="6613930842805942519">"Ցույց տալ պայծառությունն Արագ կարգավորումներում"</string>
    --    <string name="overview_nav_bar_gesture" msgid="8579814204727917764">"Ակտիվացնել մատը վերև սահեցնելով էկրանը տրոհելու ժեստը"</string>
    --    <string name="overview_nav_bar_gesture_desc" msgid="6329167382305102615">"Միացնել Համատեսք կոճակից մատը դեպի վերև սահեցնելու միջոցով տրոհված էկրանի ռեժիմ անցնելու ժեստը"</string>
    -     <string name="experimental" msgid="6198182315536726162">"Փորձնական"</string>
    -     <string name="enable_bluetooth_title" msgid="5027037706500635269">"Միացնե՞լ Bluetooth-ը:"</string>
    -     <string name="enable_bluetooth_message" msgid="9106595990708985385">"Ստեղնաշարը ձեր պլանշետին միացնելու համար նախ անհրաժեշտ է միացնել Bluetooth-ը:"</string>
    -@@ -644,11 +644,12 @@
    -     <string name="accessibility_quick_settings_settings" msgid="6132460890024942157">"Բացել կարգավորումները:"</string>
    -     <string name="accessibility_quick_settings_expand" msgid="2375165227880477530">"Բացել արագ կարգավորումները:"</string>
    -     <string name="accessibility_quick_settings_collapse" msgid="1792625797142648105">"Փակել արագ կարգավորումները:"</string>
    --    <string name="accessibility_quick_settings_alarm_set" msgid="1863000242431528676">"Զարթուցիչը կարգավորված է:"</string>
    -+    <string name="accessibility_quick_settings_alarm_set" msgid="1863000242431528676">"Զարթուցիչը դրված է:"</string>
    -     <string name="accessibility_quick_settings_user" msgid="1567445362870421770">"Մուտք է գործել որպես <xliff:g id="ID_1">%s</xliff:g>"</string>
    -     <string name="accessibility_quick_settings_no_internet" msgid="31890692343084075">"Ինտերնետ կապ չկա:"</string>
    -     <string name="accessibility_quick_settings_open_details" msgid="4230931801728005194">"Բացել մանրամասները:"</string>
    -     <string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"Բացել <xliff:g id="ID_1">%s</xliff:g> կարգավորումները:"</string>
    -     <string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"Խմբագրել կարգավորումների հերթականությունը:"</string>
    -     <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"Էջ <xliff:g id="ID_1">%1$d</xliff:g> / <xliff:g id="ID_2">%2$d</xliff:g>"</string>
    -+    <string name="cant_silence_or_block" msgid="999689262131488625">"Հնարավոր չէ արգելափակել ծանուցումները կամ անջատել դրանց ձայնը"</string>
    - </resources>
    -diff --git a/packages/SystemUI/res/values-in/strings.xml b/packages/SystemUI/res/values-in/strings.xml
    -index ad24d6a..d006add 100644
    ---- a/packages/SystemUI/res/values-in/strings.xml
    -+++ b/packages/SystemUI/res/values-in/strings.xml
    -@@ -238,7 +238,7 @@
    -     <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"Data 4G dijeda"</string>
    -     <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"Data seluler dijeda"</string>
    -     <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"Data dijeda"</string>
    --    <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"Karena batas data yang disetel telah tercapai, perangkat telah menjeda penggunaan data selama sisa waktu siklus ini.\n\nMelanjutkan dapat mengakibatkan tagihan dari operator."</string>
    -+    <string name="data_usage_disabled_dialog" msgid="1841738975235283398">"Batas data yang disetel telah tercapai. Anda tidak menggunakan data seluler lagi.\n\nJika Anda melanjutkan, biaya penggunaan data mungkin berlaku."</string>
    -     <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"Lanjutkan"</string>
    -     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Tidak ada sambungan internet"</string>
    -     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi tersambung"</string>
    -@@ -404,6 +404,7 @@
    -     <string name="device_owned_footer" msgid="3802752663326030053">"Perangkat mungkin dipantau"</string>
    -     <string name="profile_owned_footer" msgid="8021888108553696069">"Profil dapat dipantau"</string>
    -     <string name="vpn_footer" msgid="2388611096129106812">"Jaringan mungkin dipantau"</string>
    -+    <string name="branded_vpn_footer" msgid="2168111859226496230">"Jaringan mungkin dipantau"</string>
    -     <string name="monitoring_title_device_owned" msgid="7121079311903859610">"Pemantauan perangkat"</string>
    -     <string name="monitoring_title_profile_owned" msgid="6790109874733501487">"Pemantauan profil"</string>
    -     <string name="monitoring_title" msgid="169206259253048106">"Pemantauan jaringan"</string>
    -@@ -416,6 +417,7 @@
    -     <string name="legacy_vpn_name" msgid="6604123105765737830">"VPN"</string>
    -     <string name="monitoring_description_app" msgid="6259179342284742878">"Anda tersambung ke <xliff:g id="APPLICATION">%1$s</xliff:g>, yang dapat memantau aktivitas jaringan, termasuk email, aplikasi, dan situs web."</string>
    -     <string name="monitoring_description_app_personal" msgid="484599052118316268">"Anda tersambung ke <xliff:g id="APPLICATION">%1$s</xliff:g>, yang dapat memantau aktivitas jaringan pribadi, termasuk email, aplikasi, dan situs web."</string>
    -+    <string name="branded_monitoring_description_app_personal" msgid="2669518213949202599">"Anda tersambung ke <xliff:g id="APPLICATION">%1$s</xliff:g>, yang dapat memantau aktivitas jaringan pribadi, termasuk email, aplikasi, dan situs web.."</string>
    -     <string name="monitoring_description_app_work" msgid="1754325860918060897">"Profil kerja dikelola oleh <xliff:g id="ORGANIZATION">%1$s</xliff:g> dan tersambung ke <xliff:g id="APPLICATION">%2$s</xliff:g>, yang dapat memantau aktivitas jaringan kerja, termasuk email, aplikasi, dan situs web.\n\nUntuk informasi selengkapnya, hubungi administrator."</string>
    -     <string name="monitoring_description_app_personal_work" msgid="4946600443852045903">"Profil kerja dikelola oleh <xliff:g id="ORGANIZATION">%1$s</xliff:g> dan tersambung ke <xliff:g id="APPLICATION_WORK">%2$s</xliff:g>, yang dapat memantau aktivitas jaringan kerja, termasuk email, aplikasi, dan situs web.\n\nAnda juga tersambung ke <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g>, yang dapat memantau aktivitas jaringan pribadi."</string>
    -     <string name="monitoring_description_vpn_app_device_owned" msgid="4970443827043261703">"Perangkat dikelola oleh <xliff:g id="ORGANIZATION">%1$s</xliff:g>.\n\nAdministrator dapat memantau dan mengelola setelan, akses perusahaan, aplikasi, data terkait perangkat, dan informasi lokasi perangkat.\n\nAnda tersambung ke <xliff:g id="APPLICATION">%2$s</xliff:g>, yang dapat memantau aktivitas jaringan, termasuk email, aplikasi, dan situs web.\n\nUntuk informasi selengkapnya, hubungi administrator."</string>
    -@@ -492,8 +494,6 @@
    -     <string name="clock_seconds_desc" msgid="6282693067130470675">"Tampilkan detik jam di bilah status. Dapat memengaruhi masa pakai baterai."</string>
    -     <string name="qs_rearrange" msgid="8060918697551068765">"Atur Ulang Setelan Cepat"</string>
    -     <string name="show_brightness" msgid="6613930842805942519">"Tampilkan kecerahan di Setelan Cepat"</string>
    --    <string name="overview_nav_bar_gesture" msgid="8579814204727917764">"Aktifkan isyarat gesek atas untuk layar terpisah"</string>
    --    <string name="overview_nav_bar_gesture_desc" msgid="6329167382305102615">"Aktifkan isyarat untuk masuk layar terpisah dengan menggesek tombol Ringkasan ke atas"</string>
    -     <string name="experimental" msgid="6198182315536726162">"Eksperimental"</string>
    -     <string name="enable_bluetooth_title" msgid="5027037706500635269">"Aktifkan Bluetooth?"</string>
    -     <string name="enable_bluetooth_message" msgid="9106595990708985385">"Untuk menghubungkan keyboard dengan tablet, terlebih dahulu aktifkan Bluetooth."</string>
    -@@ -651,4 +651,5 @@
    -     <string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"Buka setelan <xliff:g id="ID_1">%s</xliff:g>."</string>
    -     <string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"Edit urutan setelan."</string>
    -     <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"Halaman <xliff:g id="ID_1">%1$d</xliff:g> dari <xliff:g id="ID_2">%2$d</xliff:g>"</string>
    -+    <string name="cant_silence_or_block" msgid="999689262131488625">"Notifikasi tidak dapat disenyapkan atau diblokir"</string>
    - </resources>
    -diff --git a/packages/SystemUI/res/values-is-rIS/strings.xml b/packages/SystemUI/res/values-is-rIS/strings.xml
    -index a95e28b..26b1e74 100644
    ---- a/packages/SystemUI/res/values-is-rIS/strings.xml
    -+++ b/packages/SystemUI/res/values-is-rIS/strings.xml
    -@@ -238,7 +238,7 @@
    -     <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"Slökkt er á 4G-gögnum"</string>
    -     <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"Slökkt er á farsímagögnum"</string>
    -     <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"Slökkt er á gagnanotkun"</string>
    --    <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"Þar sem gagnahámarkinu var náð hefur tækið slökkt á gagnanotkun það sem eftir er af þessu tímabili.\n\nEf þú heldur áfram kann það að leiða til kostnaðar frá símafyrirtækinu."</string>
    -+    <string name="data_usage_disabled_dialog" msgid="1841738975235283398">"Gagnamörkunum sem þú stilltir hefur verið náð. Þú ert ekki lengur að nota farsímagögn.\n\nEf þú heldur áfram gætu gjöld fyrir gagnanotkun átt við."</string>
    -     <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"Halda áfram"</string>
    -     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Engin nettenging"</string>
    -     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi tengt"</string>
    -@@ -404,6 +404,7 @@
    -     <string name="device_owned_footer" msgid="3802752663326030053">"Hugsanlega er fylgst með tækjum"</string>
    -     <string name="profile_owned_footer" msgid="8021888108553696069">"Hugsanlega er fylgst með þessu sniði"</string>
    -     <string name="vpn_footer" msgid="2388611096129106812">"Hugsanlega er fylgst með netinu"</string>
    -+    <string name="branded_vpn_footer" msgid="2168111859226496230">"Hugsanlega er fylgst með netinu"</string>
    -     <string name="monitoring_title_device_owned" msgid="7121079311903859610">"Tækjaeftirlit"</string>
    -     <string name="monitoring_title_profile_owned" msgid="6790109874733501487">"Fylgst með sniði"</string>
    -     <string name="monitoring_title" msgid="169206259253048106">"Neteftirlit"</string>
    -@@ -416,6 +417,7 @@
    -     <string name="legacy_vpn_name" msgid="6604123105765737830">"VPN"</string>
    -     <string name="monitoring_description_app" msgid="6259179342284742878">"Þú ert með tengingu við <xliff:g id="APPLICATION">%1$s</xliff:g>, sem getur fylgst með netnotkun þinni, þ. á m. tölvupósti, forritum og vefsvæðum."</string>
    -     <string name="monitoring_description_app_personal" msgid="484599052118316268">"Þú ert með tengingu við <xliff:g id="APPLICATION">%1$s</xliff:g>, sem getur fylgst með persónulegri netnotkun þinni, þ. á m. tölvupósti, forritum og vefsvæðum."</string>
    -+    <string name="branded_monitoring_description_app_personal" msgid="2669518213949202599">"Þú ert með tengingu við <xliff:g id="APPLICATION">%1$s</xliff:g>, sem getur fylgst með persónulegri netnotkun þinni, þ. á m. tölvupósti, forritum og vefsvæðum."</string>
    -     <string name="monitoring_description_app_work" msgid="1754325860918060897">"Vinnusniðinu þínu er stjórnað af <xliff:g id="ORGANIZATION">%1$s</xliff:g>. Það er tengt <xliff:g id="APPLICATION">%2$s</xliff:g>, sem getur fylgst með vinnutengdri netnotkun þinni, þar á meðal tölvupósti, forritum og vefsvæðum.\n\nHafðu samband við kerfisstjórann til að fá frekari upplýsingar."</string>
    -     <string name="monitoring_description_app_personal_work" msgid="4946600443852045903">"Vinnusniðinu þínu er stjórnað af <xliff:g id="ORGANIZATION">%1$s</xliff:g>. Það er tengt <xliff:g id="APPLICATION_WORK">%2$s</xliff:g>, sem getur fylgst með vinnutengdri netnotkun þinni, þar á meðal tölvupósti, forritum og vefsvæðum.\n\nÞú ert einnig með tengingu við <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g>, sem getur fylgst með persónulegri netnotkun þinni."</string>
    -     <string name="monitoring_description_vpn_app_device_owned" msgid="4970443827043261703">"Tækinu er stjórnað af <xliff:g id="ORGANIZATION">%1$s</xliff:g>.\n\nKerfisstjórinn þinn getur fylgst með og stjórnað stillingum, fyrirtækjaaðgangi, forritum, gögnum sem tengd eru tækinu og staðsetningarupplýsingum tækisins.\n\nÞú ert með tengingu við <xliff:g id="APPLICATION">%2$s</xliff:g>, sem getur fylgst með netnotkun þinni, þar á meðal tölvupósti, forritum og vefsvæðum.\n\nHafðu samband við kerfisstjórann til að fá frekari upplýsingar."</string>
    -@@ -492,8 +494,6 @@
    -     <string name="clock_seconds_desc" msgid="6282693067130470675">"Sýna sekúndur á klukku í stöðustikunni. Getur haft áhrif á endingu rafhlöðu."</string>
    -     <string name="qs_rearrange" msgid="8060918697551068765">"Endurraða flýtistillingum"</string>
    -     <string name="show_brightness" msgid="6613930842805942519">"Sýna birtustig í flýtistillingum"</string>
    --    <string name="overview_nav_bar_gesture" msgid="8579814204727917764">"Virkja skjáskiptingu með því að strjúka upp"</string>
    --    <string name="overview_nav_bar_gesture_desc" msgid="6329167382305102615">"Virkja skjáskiptingarbendingu með því að strjúka upp frá yfirlitshnappi"</string>
    -     <string name="experimental" msgid="6198182315536726162">"Tilraunastillingar"</string>
    -     <string name="enable_bluetooth_title" msgid="5027037706500635269">"Kveikja á Bluetooth?"</string>
    -     <string name="enable_bluetooth_message" msgid="9106595990708985385">"Til að geta tengt lyklaborðið við spjaldtölvuna þarftu fyrst að kveikja á Bluetooth."</string>
    -@@ -651,4 +651,5 @@
    -     <string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"Opna <xliff:g id="ID_1">%s</xliff:g> stillingar."</string>
    -     <string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"Breyta röð stillinga."</string>
    -     <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"Blaðsíða <xliff:g id="ID_1">%1$d</xliff:g> af <xliff:g id="ID_2">%2$d</xliff:g>"</string>
    -+    <string name="cant_silence_or_block" msgid="999689262131488625">"Ekki er hægt að þagga eða loka á tilkynningar"</string>
    - </resources>
    -diff --git a/packages/SystemUI/res/values-it/strings.xml b/packages/SystemUI/res/values-it/strings.xml
    -index d370b65..d056637 100644
    ---- a/packages/SystemUI/res/values-it/strings.xml
    -+++ b/packages/SystemUI/res/values-it/strings.xml
    -@@ -240,7 +240,7 @@
    -     <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"Dati 4G sospesi"</string>
    -     <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"Dati cellulari sospesi"</string>
    -     <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"Dati sospesi"</string>
    --    <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"Hai raggiunto il tuo limite di dati, pertanto sul dispositivo è stato sospeso l\'utilizzo di dati per la parte rimanente del ciclo.\n\nSe riprendi a utilizzare i dati, l\'operatore potrebbe addebitarti costi."</string>
    -+    <string name="data_usage_disabled_dialog" msgid="1841738975235283398">"È stato raggiunto il limite di dati impostato. La rete dati è stata disattivata.\n\nSe la riattivi, potrebbero essere applicati costi per l\'utilizzo dei dati."</string>
    -     <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"Riprendi"</string>
    -     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Nessuna connessione"</string>
    -     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi connesso"</string>
    -@@ -347,7 +347,7 @@
    -     <string name="description_target_search" msgid="3091587249776033139">"Ricerca"</string>
    -     <string name="description_direction_up" msgid="7169032478259485180">"Su per <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
    -     <string name="description_direction_left" msgid="7207478719805562165">"A sinistra per <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
    --    <string name="zen_priority_introduction" msgid="3070506961866919502">"Non verrai disturbato da suoni e vibrazioni, ad eccezione di sveglie, promemoria, eventi e chiamate da contatti da te specificati."</string>
    -+    <string name="zen_priority_introduction" msgid="3070506961866919502">"Non ti disturberanno: suoni e vibrazioni, ad eccezione di sveglie, promemoria, eventi e chiamate da contatti da te specificati."</string>
    -     <string name="zen_priority_customize_button" msgid="7948043278226955063">"Personalizza"</string>
    -     <string name="zen_silence_introduction_voice" msgid="2284540992298200729">"Verranno bloccati TUTTI i suoni e le vibrazioni, anche di sveglie, musica, video e giochi. Potrai ancora telefonare."</string>
    -     <string name="zen_silence_introduction" msgid="3137882381093271568">"Verranno bloccati TUTTI i suoni e le vibrazioni, anche di sveglie, musica, video e giochi."</string>
    -@@ -406,6 +406,7 @@
    -     <string name="device_owned_footer" msgid="3802752663326030053">"Il dispositivo potrebbe essere monitorato"</string>
    -     <string name="profile_owned_footer" msgid="8021888108553696069">"Il profilo potrebbe essere monitorato"</string>
    -     <string name="vpn_footer" msgid="2388611096129106812">"La rete potrebbe essere monitorata"</string>
    -+    <string name="branded_vpn_footer" msgid="2168111859226496230">"La rete potrebbe essere monitorata"</string>
    -     <string name="monitoring_title_device_owned" msgid="7121079311903859610">"Monitoraggio del dispositivo"</string>
    -     <string name="monitoring_title_profile_owned" msgid="6790109874733501487">"Monitoraggio del profilo"</string>
    -     <string name="monitoring_title" msgid="169206259253048106">"Monitoraggio rete"</string>
    -@@ -418,6 +419,7 @@
    -     <string name="legacy_vpn_name" msgid="6604123105765737830">"VPN"</string>
    -     <string name="monitoring_description_app" msgid="6259179342284742878">"Sei connesso a <xliff:g id="APPLICATION">%1$s</xliff:g>, da cui è possibile monitorare la tua attività di rete, inclusi email, app e siti web."</string>
    -     <string name="monitoring_description_app_personal" msgid="484599052118316268">"Sei connesso a <xliff:g id="APPLICATION">%1$s</xliff:g>, da cui è possibile monitorare la tua attività di rete personale, inclusi email, app e siti web."</string>
    -+    <string name="branded_monitoring_description_app_personal" msgid="2669518213949202599">"Sei collegato a <xliff:g id="APPLICATION">%1$s</xliff:g>, che consente di monitorare la tua attività di rete personale, inclusi siti web, email e app."</string>
    -     <string name="monitoring_description_app_work" msgid="1754325860918060897">"Il tuo profilo di lavoro è gestito da <xliff:g id="ORGANIZATION">%1$s</xliff:g>. È connesso a <xliff:g id="APPLICATION">%2$s</xliff:g>, da cui è possibile monitorare la tua attività di rete lavorativa, inclusi email, app e siti web.\n\nPer ulteriori informazioni, contatta il tuo amministratore."</string>
    -     <string name="monitoring_description_app_personal_work" msgid="4946600443852045903">"Il tuo profilo di lavoro è gestito da <xliff:g id="ORGANIZATION">%1$s</xliff:g>. È connesso a <xliff:g id="APPLICATION_WORK">%2$s</xliff:g>, da cui è possibile monitorare la tua attività di rete lavorativa, inclusi email, app e siti web.\n\nSei connesso anche a <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g>, da cui è possibile monitorare la tua attività di rete personale."</string>
    -     <string name="monitoring_description_vpn_app_device_owned" msgid="4970443827043261703">"Il tuo dispositivo è gestito da <xliff:g id="ORGANIZATION">%1$s</xliff:g>.\n\nL\'amministratore può monitorare e gestire impostazioni, accesso aziendale, app e dati associati al dispositivo, incluse le informazioni sulla posizione del dispositivo.\n\nSei connesso a <xliff:g id="APPLICATION">%2$s</xliff:g>, da cui è possibile monitorare la tua attività di rete, inclusi email, app e siti web.\n\nPer ulteriori informazioni, contatta l\'amministratore."</string>
    -@@ -494,8 +496,6 @@
    -     <string name="clock_seconds_desc" msgid="6282693067130470675">"Mostra i secondi nell\'orologio nella barra di stato. Ciò potrebbe ridurre la durata della carica della batteria."</string>
    -     <string name="qs_rearrange" msgid="8060918697551068765">"Riorganizza Impostazioni rapide"</string>
    -     <string name="show_brightness" msgid="6613930842805942519">"Mostra luminosità in Impostazioni rapide"</string>
    --    <string name="overview_nav_bar_gesture" msgid="8579814204727917764">"Attiva Schermo diviso mediante scorrimento verso l\'alto"</string>
    --    <string name="overview_nav_bar_gesture_desc" msgid="6329167382305102615">"Consente di attivare la modalità Schermo diviso scorrendo verso l\'alto dal pulsante Panoramica"</string>
    -     <string name="experimental" msgid="6198182315536726162">"Sperimentali"</string>
    -     <string name="enable_bluetooth_title" msgid="5027037706500635269">"Attivare il Bluetooth?"</string>
    -     <string name="enable_bluetooth_message" msgid="9106595990708985385">"Per connettere la tastiera al tablet, devi prima attivare il Bluetooth."</string>
    -@@ -653,4 +653,5 @@
    -     <string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"Apri le impostazioni <xliff:g id="ID_1">%s</xliff:g>."</string>
    -     <string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"Modifica l\'ordine delle impostazioni."</string>
    -     <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"Pagina <xliff:g id="ID_1">%1$d</xliff:g> di <xliff:g id="ID_2">%2$d</xliff:g>"</string>
    -+    <string name="cant_silence_or_block" msgid="999689262131488625">"Le notifiche non possono essere disattivate o bloccate"</string>
    - </resources>
    -diff --git a/packages/SystemUI/res/values-it/strings_car.xml b/packages/SystemUI/res/values-it/strings_car.xml
    -index ae26c9e..19c4e2b 100644
    ---- a/packages/SystemUI/res/values-it/strings_car.xml
    -+++ b/packages/SystemUI/res/values-it/strings_car.xml
    -@@ -20,5 +20,5 @@
    - <resources xmlns:android="http://schemas.android.com/apk/res/android"
    -     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
    -     <string name="car_lockscreen_disclaimer_title" msgid="7997539137376896441">"Guida in modo sicuro"</string>
    --    <string name="car_lockscreen_disclaimer_text" msgid="3061224684092952864">"È necessario essere sempre pienamente coscienti delle condizioni di guida e rispettare le leggi vigenti. Le indicazioni stradali potrebbero essere imprecise, incomplete, pericolose, non adatte, vietate o implicare l\'attraversamento di confini. Anche le informazioni sulle attività commerciali potrebbero essere imprecise o incomplete. I dati non vengono forniti in tempo reale e non è possibile garantire la precisione della geolocalizzazione. Non maneggiare il dispositivo mobile e non utilizzare app non progettate per Android Auto durante la guida."</string>
    -+    <string name="car_lockscreen_disclaimer_text" msgid="3061224684092952864">"È necessario essere sempre pienamente informati sulle condizioni della strada e rispettare la legislazione vigente. Le indicazioni stradali potrebbero essere imprecise, incomplete, pericolose, inadatte, vietate o richiedere l\'attraversamento di aree amministrative. Anche le informazioni sugli esercizi commerciali potrebbero essere imprecise o incomplete. I dati forniti non sono aggiornati in tempo reale e non è possibile garantire la precisione della geolocalizzazione. Non maneggiare dispositivi mobili e app non destinate ad Android Auto durante la guida."</string>
    - </resources>
    -diff --git a/packages/SystemUI/res/values-iw/strings.xml b/packages/SystemUI/res/values-iw/strings.xml
    -index 4cf48c2..19a94a3 100644
    ---- a/packages/SystemUI/res/values-iw/strings.xml
    -+++ b/packages/SystemUI/res/values-iw/strings.xml
    -@@ -240,7 +240,7 @@
    -     <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"‏השימוש בנתוני 4G מושהה"</string>
    -     <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"השימוש בנתונים סלולריים מושהה"</string>
    -     <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"השימוש בנתונים מושהה"</string>
    --    <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"מכיוון שהגעת למגבלת הנתונים שהגדרת, המכשיר השהה את השימוש בנתונים עד סוף התקופה.\n\nאם תמשיך, אתה עשוי לקבל חיובים מהספק."</string>
    -+    <string name="data_usage_disabled_dialog" msgid="1841738975235283398">"הגעת למגבלת הנתונים שהגדרת. אתה כבר לא משתמש בנתונים סלולריים.\n\nאם תמשיך, ייתכנו חיובים לשימוש בנתונים."</string>
    -     <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"המשך"</string>
    -     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"אין חיבור לאינטרנט"</string>
    -     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"‏Wi-Fi מחובר"</string>
    -@@ -408,6 +408,7 @@
    -     <string name="device_owned_footer" msgid="3802752663326030053">"ייתכן שהמכשיר נמצא במעקב"</string>
    -     <string name="profile_owned_footer" msgid="8021888108553696069">"ייתכן שהפרופיל נתון למעקב"</string>
    -     <string name="vpn_footer" msgid="2388611096129106812">"ייתכן שהרשת נמצאת במעקב"</string>
    -+    <string name="branded_vpn_footer" msgid="2168111859226496230">"ייתכן שהרשת מנוטרת"</string>
    -     <string name="monitoring_title_device_owned" msgid="7121079311903859610">"מעקב אחר מכשיר"</string>
    -     <string name="monitoring_title_profile_owned" msgid="6790109874733501487">"מעקב אחר פרופיל"</string>
    -     <string name="monitoring_title" msgid="169206259253048106">"מעקב אחר פעילות ברשת"</string>
    -@@ -420,6 +421,7 @@
    -     <string name="legacy_vpn_name" msgid="6604123105765737830">"VPN"</string>
    -     <string name="monitoring_description_app" msgid="6259179342284742878">"אתה מחובר לאפליקציה <xliff:g id="APPLICATION">%1$s</xliff:g>, שיכולה לעקוב אחר הפעילות שלך ברשת, כולל הודעות אימייל, אפליקציות ואתרים."</string>
    -     <string name="monitoring_description_app_personal" msgid="484599052118316268">"אתה מחובר לאפליקציה <xliff:g id="APPLICATION">%1$s</xliff:g>, שיכולה לעקוב אחר הפעילות שלך ברשת הפרטית, כולל הודעות אימייל, אפליקציות ואתרים."</string>
    -+    <string name="branded_monitoring_description_app_personal" msgid="2669518213949202599">"אתה מחובר לאפליקציה <xliff:g id="APPLICATION">%1$s</xliff:g>, שיכולה לעקוב אחר הפעילות שלך ברשת הפרטית, כולל הודעות אימייל, אפליקציות ואתרים."</string>
    -     <string name="monitoring_description_app_work" msgid="1754325860918060897">"פרופיל העבודה שלך מנוהל על ידי <xliff:g id="ORGANIZATION">%1$s</xliff:g>. הוא מחובר לאפליקציה <xliff:g id="APPLICATION">%2$s</xliff:g>, שיכולה לעקוב אחר הפעילות שלך ברשת העסקית, כולל הודעות אימייל, אפליקציות ואתרים.\n\nלמידע נוסף, פנה למנהל המערכת שלך."</string>
    -     <string name="monitoring_description_app_personal_work" msgid="4946600443852045903">"פרופיל העבודה שלך מנוהל על ידי <xliff:g id="ORGANIZATION">%1$s</xliff:g>. הוא מחובר לאפליקציה <xliff:g id="APPLICATION_WORK">%2$s</xliff:g>, שיכולה לעקוב אחר הפעילות שלך ברשת העסקית, כולל הודעות אימייל, אפליקציות ואתרים.\n\nאתה מחובר גם לאפליקציה <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g>, שיכולה לעקוב אחר הפעילות שלך ברשת הפרטית."</string>
    -     <string name="monitoring_description_vpn_app_device_owned" msgid="4970443827043261703">"המכשיר שלך מנוהל על ידי <xliff:g id="ORGANIZATION">%1$s</xliff:g>.\n\nמנהל המערכת שלך יכול לעקוב אחר הגדרות, גישה עסקית, אפליקציות, נתונים המשויכים למכשיר שלך ומידע על מיקום המכשיר, ולנהל אותם.\n\nאתה מחובר לאפליקציה <xliff:g id="APPLICATION">%2$s</xliff:g>, שיכולה לעקוב אחר הפעילות שלך ברשת, כולל הודעות אימייל, אפליקציות ואתרים.\n\nלמידע נוסף, פנה למנהל המערכת שלך."</string>
    -@@ -496,8 +498,6 @@
    -     <string name="clock_seconds_desc" msgid="6282693067130470675">"הצג שניות בשעון בשורת הסטטוס. פעולה זו עשויה להשפיע על אורך חיי הסוללה."</string>
    -     <string name="qs_rearrange" msgid="8060918697551068765">"סידור מחדש של הגדרות מהירות"</string>
    -     <string name="show_brightness" msgid="6613930842805942519">"הצג בהירות בהגדרות מהירות"</string>
    --    <string name="overview_nav_bar_gesture" msgid="8579814204727917764">"הפעל מסך מפוצל על ידי תנועת החלקה כלפי מעלה"</string>
    --    <string name="overview_nav_bar_gesture_desc" msgid="6329167382305102615">"הפעל את התנועה לכניסה למסך מפוצל על ידי החלקה כלפי מעלה מלחצן הסקירה"</string>
    -     <string name="experimental" msgid="6198182315536726162">"ניסיוניות"</string>
    -     <string name="enable_bluetooth_title" msgid="5027037706500635269">"‏האם להפעיל את ה-Bluetooth?"</string>
    -     <string name="enable_bluetooth_message" msgid="9106595990708985385">"‏כדי לחבר את המקלדת לטאבלט, תחילה עליך להפעיל את ה-Bluetooth."</string>
    -@@ -655,4 +655,5 @@
    -     <string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"פתיחת הגדרות של <xliff:g id="ID_1">%s</xliff:g>."</string>
    -     <string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"עריכת סדר ההגדרות."</string>
    -     <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"דף <xliff:g id="ID_1">%1$d</xliff:g> מתוך <xliff:g id="ID_2">%2$d</xliff:g>"</string>
    -+    <string name="cant_silence_or_block" msgid="999689262131488625">"לא ניתן להשתיק או לחסום הודעות"</string>
    - </resources>
    -diff --git a/packages/SystemUI/res/values-ja/strings.xml b/packages/SystemUI/res/values-ja/strings.xml
    -index c42e346..8d51fe6 100644
    ---- a/packages/SystemUI/res/values-ja/strings.xml
    -+++ b/packages/SystemUI/res/values-ja/strings.xml
    -@@ -197,13 +197,13 @@
    -     <string name="accessibility_quick_settings_airplane_on" msgid="6406141469157599296">"機内モードがONです。"</string>
    -     <string name="accessibility_quick_settings_airplane_changed_off" msgid="66846307818850664">"機内モードをOFFにしました。"</string>
    -     <string name="accessibility_quick_settings_airplane_changed_on" msgid="8983005603505087728">"機内モードをONにしました。"</string>
    --    <string name="accessibility_quick_settings_dnd_priority_on" msgid="1448402297221249355">"[通知を非表示]はONで、優先する通知のみです。"</string>
    --    <string name="accessibility_quick_settings_dnd_none_on" msgid="6882582132662613537">"[通知を非表示]はONで、サイレントです。"</string>
    --    <string name="accessibility_quick_settings_dnd_alarms_on" msgid="9152834845587554157">"[通知を非表示]はONで、アラームのみです。"</string>
    --    <string name="accessibility_quick_settings_dnd" msgid="6607873236717185815">"通知を非表示"</string>
    --    <string name="accessibility_quick_settings_dnd_off" msgid="2371832603753738581">"[通知を非表示]はOFFです。"</string>
    --    <string name="accessibility_quick_settings_dnd_changed_off" msgid="898107593453022935">"[通知を非表示]をOFFにしました。"</string>
    --    <string name="accessibility_quick_settings_dnd_changed_on" msgid="4483780856613561039">"[通知を非表示]をONにしました。"</string>
    -+    <string name="accessibility_quick_settings_dnd_priority_on" msgid="1448402297221249355">"マナーモードは ON で、優先する通知のみ許可します。"</string>
    -+    <string name="accessibility_quick_settings_dnd_none_on" msgid="6882582132662613537">"マナーモードは ON で、サイレント モードです。"</string>
    -+    <string name="accessibility_quick_settings_dnd_alarms_on" msgid="9152834845587554157">"マナーモードは ON で、アラームのみ許可します。"</string>
    -+    <string name="accessibility_quick_settings_dnd" msgid="6607873236717185815">"マナーモード"</string>
    -+    <string name="accessibility_quick_settings_dnd_off" msgid="2371832603753738581">"マナーモードは OFF です。"</string>
    -+    <string name="accessibility_quick_settings_dnd_changed_off" msgid="898107593453022935">"マナーモードを OFF にしました。"</string>
    -+    <string name="accessibility_quick_settings_dnd_changed_on" msgid="4483780856613561039">"マナーモードを ON にしました。"</string>
    -     <string name="accessibility_quick_settings_bluetooth" msgid="6341675755803320038">"Bluetooth"</string>
    -     <string name="accessibility_quick_settings_bluetooth_off" msgid="2133631372372064339">"BluetoothがOFFです。"</string>
    -     <string name="accessibility_quick_settings_bluetooth_on" msgid="7681999166216621838">"BluetoothがONです。"</string>
    -@@ -240,7 +240,7 @@
    -     <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"4Gデータは一時停止中です"</string>
    -     <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"モバイルデータは一時停止中です"</string>
    -     <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"データの一時停止"</string>
    --    <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"設定されたデータの上限に達したため、このサイクルの終了までこの端末でのデータの利用を一時停止しました。\n\n再開すると、携帯通信会社から課金される可能性があります。"</string>
    -+    <string name="data_usage_disabled_dialog" msgid="1841738975235283398">"設定されたデータの上限に達しているため、モバイルデータの使用を停止しました。\n\n再開すると、携帯通信会社からデータ使用量に応じた通信料を課金される可能性があります。"</string>
    -     <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"再開"</string>
    -     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"インターネット未接続"</string>
    -     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi接続済み"</string>
    -@@ -264,7 +264,7 @@
    -     <string name="dessert_case" msgid="1295161776223959221">"デザートケース"</string>
    -     <string name="start_dreams" msgid="5640361424498338327">"スクリーン セーバー"</string>
    -     <string name="ethernet_label" msgid="7967563676324087464">"イーサネット"</string>
    --    <string name="quick_settings_dnd_label" msgid="8735855737575028208">"通知を非表示"</string>
    -+    <string name="quick_settings_dnd_label" msgid="8735855737575028208">"マナーモード"</string>
    -     <string name="quick_settings_dnd_priority_label" msgid="483232950670692036">"優先する通知のみ"</string>
    -     <string name="quick_settings_dnd_alarms_label" msgid="2559229444312445858">"アラームのみ"</string>
    -     <string name="quick_settings_dnd_none_label" msgid="5025477807123029478">"サイレント"</string>
    -@@ -406,6 +406,7 @@
    -     <string name="device_owned_footer" msgid="3802752663326030053">"端末が監視されている可能性があります"</string>
    -     <string name="profile_owned_footer" msgid="8021888108553696069">"プロファイルが監視されている可能性があります"</string>
    -     <string name="vpn_footer" msgid="2388611096129106812">"ネットワークが監視されている可能性があります"</string>
    -+    <string name="branded_vpn_footer" msgid="2168111859226496230">"ネットワークが監視されている可能性があります"</string>
    -     <string name="monitoring_title_device_owned" msgid="7121079311903859610">"端末の監視"</string>
    -     <string name="monitoring_title_profile_owned" msgid="6790109874733501487">"プロファイルの監視"</string>
    -     <string name="monitoring_title" msgid="169206259253048106">"ネットワーク監視"</string>
    -@@ -418,6 +419,7 @@
    -     <string name="legacy_vpn_name" msgid="6604123105765737830">"VPN"</string>
    -     <string name="monitoring_description_app" msgid="6259179342284742878">"<xliff:g id="APPLICATION">%1$s</xliff:g>に接続しています。このアプリはあなたのネットワークアクティビティ(メール、アプリ、ウェブサイトなど)を監視できます。"</string>
    -     <string name="monitoring_description_app_personal" msgid="484599052118316268">"<xliff:g id="APPLICATION">%1$s</xliff:g>に接続しています。このアプリはあなたの個人のネットワークアクティビティ(メール、アプリ、ウェブサイトなど)を監視できます。"</string>
    -+    <string name="branded_monitoring_description_app_personal" msgid="2669518213949202599">"「<xliff:g id="APPLICATION">%1$s</xliff:g>」に接続しています。このアプリはあなたの個人のネットワーク アクティビティ(メール、アプリ、ウェブサイトなど)を監視できます。"</string>
    -     <string name="monitoring_description_app_work" msgid="1754325860918060897">"この仕事用プロファイルは<xliff:g id="ORGANIZATION">%1$s</xliff:g>によって管理され、<xliff:g id="APPLICATION">%2$s</xliff:g>に接続しています。このアプリはあなたの仕事のネットワークアクティビティ(メール、アプリ、ウェブサイトなど)を監視できます。\n\n詳しくは管理者にお問い合わせください。"</string>
    -     <string name="monitoring_description_app_personal_work" msgid="4946600443852045903">"この仕事用プロファイルは<xliff:g id="ORGANIZATION">%1$s</xliff:g>によって管理され、<xliff:g id="APPLICATION_WORK">%2$s</xliff:g>に接続しています。このアプリはあなたの仕事のネットワークアクティビティ(メール、アプリ、ウェブサイトなど)を監視できます。\n\n<xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g>にも接続しているため、個人のネットワークアクティビティも監視できます。"</string>
    -     <string name="monitoring_description_vpn_app_device_owned" msgid="4970443827043261703">"この端末は<xliff:g id="ORGANIZATION">%1$s</xliff:g>によって管理されています。\n\n管理者は設定、コーポレートアクセス、アプリ、端末に関連付けられたデータ、端末の位置情報を監視、管理できます。\n\n<xliff:g id="APPLICATION">%2$s</xliff:g>に接続しているため、このアプリもネットワークアクティビティ(メール、アプリ、ウェブサイトなど)を監視できます。\n\n詳しくは管理者にお問い合わせください。"</string>
    -@@ -494,8 +496,6 @@
    -     <string name="clock_seconds_desc" msgid="6282693067130470675">"ステータスバーに時計の秒を表示します。電池使用量に影響する可能性があります。"</string>
    -     <string name="qs_rearrange" msgid="8060918697551068765">"クイック設定を並べ替え"</string>
    -     <string name="show_brightness" msgid="6613930842805942519">"クイック設定に明るさ調整バーを表示する"</string>
    --    <string name="overview_nav_bar_gesture" msgid="8579814204727917764">"上にスワイプして分割画面に切り替える操作を有効にする"</string>
    --    <string name="overview_nav_bar_gesture_desc" msgid="6329167382305102615">"[概要] ボタンから上にスワイプして分割画面に切り替える操作を有効にします"</string>
    -     <string name="experimental" msgid="6198182315536726162">"試験運用版"</string>
    -     <string name="enable_bluetooth_title" msgid="5027037706500635269">"BluetoothをONにしますか?"</string>
    -     <string name="enable_bluetooth_message" msgid="9106595990708985385">"タブレットでキーボードに接続するには、最初にBluetoothをONにする必要があります。"</string>
    -@@ -572,9 +572,9 @@
    -     <string name="keyboard_shortcut_group_applications_youtube" msgid="6555453761294723317">"YouTube"</string>
    -     <string name="keyboard_shortcut_group_applications_calendar" msgid="9043614299194991263">"カレンダー"</string>
    -     <string name="tuner_full_zen_title" msgid="4540823317772234308">"音量調節を表示"</string>
    --    <string name="volume_and_do_not_disturb" msgid="3373784330208603030">"通知の非表示"</string>
    -+    <string name="volume_and_do_not_disturb" msgid="3373784330208603030">"マナーモード"</string>
    -     <string name="volume_dnd_silent" msgid="4363882330723050727">"音量ボタンのショートカット"</string>
    --    <string name="volume_up_silent" msgid="7141255269783588286">"音量上げボタンで [通知を非表示] を OFF にする"</string>
    -+    <string name="volume_up_silent" msgid="7141255269783588286">"音量上げボタンでマナーモードを OFF にする"</string>
    -     <string name="battery" msgid="7498329822413202973">"電池"</string>
    -     <string name="clock" msgid="7416090374234785905">"時計"</string>
    -     <string name="headset" msgid="4534219457597457353">"ヘッドセット"</string>
    -@@ -653,4 +653,5 @@
    -     <string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"<xliff:g id="ID_1">%s</xliff:g> の設定を開きます。"</string>
    -     <string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"設定の順序を編集します。"</string>
    -     <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"ページ <xliff:g id="ID_1">%1$d</xliff:g>/<xliff:g id="ID_2">%2$d</xliff:g>"</string>
    -+    <string name="cant_silence_or_block" msgid="999689262131488625">"通知のサイレント設定やブロックはできません"</string>
    - </resources>
    -diff --git a/packages/SystemUI/res/values-ka-rGE/strings.xml b/packages/SystemUI/res/values-ka-rGE/strings.xml
    -index 6ddcde8..258c904 100644
    ---- a/packages/SystemUI/res/values-ka-rGE/strings.xml
    -+++ b/packages/SystemUI/res/values-ka-rGE/strings.xml
    -@@ -238,7 +238,7 @@
    -     <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"4G მონაცემები შეჩერებულია"</string>
    -     <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"ფიჭური მონაცემები შეჩერებულია"</string>
    -     <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"მონაცემები შეჩერებულია"</string>
    --    <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"რადგან თქვენი მონაცემების ლიმიტი ამოწურულია, მოწყობილობამ შეაჭერა მონაცემების გამოყენება დარჩენილი ციკლისათვის. \n\n შეჯამაბ შეიძლება გამოიწვიოს თქვენს პროვაიდერთან დამატებითი ხარჯები."</string>
    -+    <string name="data_usage_disabled_dialog" msgid="1841738975235283398">"მიღწეულია მონაცემთა მოხმარების თქვენ მიერ მითითებული ლიმიტი. ამიტომ, მობილური ინტერნეტის გამოყენება აღარ ხდება.\n\nგანახლების შემთხვევაში, შეიძლება მობილური ინტერნეტის საფასურის გადახდა მოგიწიოთ."</string>
    -     <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"გაგრძელება"</string>
    -     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"ინტერნეტ კავშირი არ არის"</string>
    -     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi დაკავშირებულია"</string>
    -@@ -404,6 +404,7 @@
    -     <string name="device_owned_footer" msgid="3802752663326030053">"შესაძლოა მოწყობილობის მონიტორინგი არ ხორციელდება"</string>
    -     <string name="profile_owned_footer" msgid="8021888108553696069">"შესაძლოა პროფილზე ხორციელდებოდეს მონიტორინგი"</string>
    -     <string name="vpn_footer" msgid="2388611096129106812">"შესაძლოა ქსელზე ხორციელდება მონიტორინგი"</string>
    -+    <string name="branded_vpn_footer" msgid="2168111859226496230">"ქსელზე შესაძლოა მონიტორინგი ხორციელდებოდეს"</string>
    -     <string name="monitoring_title_device_owned" msgid="7121079311903859610">"მოწყობილობის მონიტორინგი"</string>
    -     <string name="monitoring_title_profile_owned" msgid="6790109874733501487">"პროფილის მონიტორინგი"</string>
    -     <string name="monitoring_title" msgid="169206259253048106">"ქსელის მონიტორინგი"</string>
    -@@ -416,6 +417,7 @@
    -     <string name="legacy_vpn_name" msgid="6604123105765737830">"VPN"</string>
    -     <string name="monitoring_description_app" msgid="6259179342284742878">"თქვენ დაუკავშირდით <xliff:g id="APPLICATION">%1$s</xliff:g>-ს, რომელსაც შეუძლია თქვენი ქსელის აქტივობის, მათ შორის, ელფოსტის, აპებისა და ვებსაიტების მონიტორინგი."</string>
    -     <string name="monitoring_description_app_personal" msgid="484599052118316268">"თქვენ დაუკავშირდით <xliff:g id="APPLICATION">%1$s</xliff:g>-ს, რომელსაც შეუძლია თქვენი პირადი ქსელის აქტივობის, მათ შორის, ელფოსტის, აპებისა და ვებსაიტების მონიტორინგი."</string>
    -+    <string name="branded_monitoring_description_app_personal" msgid="2669518213949202599">"თქვენ დაუკავშირდით <xliff:g id="APPLICATION">%1$s</xliff:g>-ს, რომელსაც თქვენი პირადი ქსელის აქტივობის მონიტორინგი შეუძლია, მათ შორის, ელფოსტის, აპებისა და ვებსაიტების."</string>
    -     <string name="monitoring_description_app_work" msgid="1754325860918060897">"თქვენი სამუშაო პროფილი <xliff:g id="ORGANIZATION">%1$s</xliff:g>-ის მიერ იმართება. ის დაკავშირებულია <xliff:g id="APPLICATION">%2$s</xliff:g>-თან, რომელსაც შეუძლია თქვენი სამსახურის ქსელის აქტივობის, მათ შორის, ელფოსტის, აპებისა და ვებსაიტების მონიტორინგი.\n\nდამატებითი ინფორმაციისთვის მიმართეთ თქვენს ადმინისტრატორს."</string>
    -     <string name="monitoring_description_app_personal_work" msgid="4946600443852045903">"თქვენი სამუშაო პროფილი <xliff:g id="ORGANIZATION">%1$s</xliff:g>-ის მიერ იმართება. ის დაკავშირებულია <xliff:g id="APPLICATION_WORK">%2$s</xliff:g>-თან, რომელსაც შეუძლია თქვენი სამსახურის ქსელის აქტივობის, მათ შორის, ელფოსტის, აპებისა და ვებსაიტების მონიტორინგი.\n\nასევე, დაკავშირებული ხართ <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g>-თან, რომელსაც შეუძლია თქვენი პირადი ქსელის აქტივობის მონიტორინგი."</string>
    -     <string name="monitoring_description_vpn_app_device_owned" msgid="4970443827043261703">"თქვენს მოწყობილობას მართავს <xliff:g id="ORGANIZATION">%1$s</xliff:g>.\n\nადმინისტრატორს შეუძლია თქვენი მოწყობილობასთან ასოცირებული პარამეტრების, კორპორატიული წვდომის, აპებისა და მონაცემების, და ასევე მოწყობილობის მდებარეობის ინფორმაციის მონიტორინგი და მართვა.\n\nთქვენ დაკავშირებული ხართ <xliff:g id="APPLICATION">%2$s</xliff:g>-თან, რომელსაც შეუძლია თქვენი ქსელის აქტივობის, მათ შორის, ელფოსტის, აპებისა და ვებ-საიტების მონიტორინგი.\n\nდამატებითი ინფორმაციისათვის, დაუკავშირდით თქვენს ადმინისტრატორს."</string>
    -@@ -492,8 +494,6 @@
    -     <string name="clock_seconds_desc" msgid="6282693067130470675">"საათის წამების ჩვენება სტატუსის ზოლში. შეიძლება გავლენა იქონიოს ბატარეაზე."</string>
    -     <string name="qs_rearrange" msgid="8060918697551068765">"სწრაფი პარამეტრების გადაწყობა"</string>
    -     <string name="show_brightness" msgid="6613930842805942519">"სიკაშკაშის ჩვენება სწრაფ პარამეტრებში"</string>
    --    <string name="overview_nav_bar_gesture" msgid="8579814204727917764">"ზემოთ გადაფურცვლისას ეკრანის გაყოფის ჟესტის ჩართვა"</string>
    --    <string name="overview_nav_bar_gesture_desc" msgid="6329167382305102615">"მიმოხილვის ღილაკიდან ზემოთ გადაფურცვლისას ეკრანის გაყოფის რეჟიმზე გადასვლის ჟესტის ჩართვა"</string>
    -     <string name="experimental" msgid="6198182315536726162">"ექსპერიმენტული"</string>
    -     <string name="enable_bluetooth_title" msgid="5027037706500635269">"გსურთ Bluetooth-ის ჩართვა?"</string>
    -     <string name="enable_bluetooth_message" msgid="9106595990708985385">"კლავიატურის ტაბლეტთან დასაკავშირებლად, ჯერ უნდა ჩართოთ Bluetooth."</string>
    -@@ -651,4 +651,5 @@
    -     <string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"<xliff:g id="ID_1">%s</xliff:g> პარამეტრების გახსნა."</string>
    -     <string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"პარამეტრების მიმდევრობის რედაქტირება."</string>
    -     <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"გვერდი <xliff:g id="ID_1">%1$d</xliff:g> / <xliff:g id="ID_2">%2$d</xliff:g>-დან"</string>
    -+    <string name="cant_silence_or_block" msgid="999689262131488625">"შეტყობინებების გაჩუმება ან დაბლოკვა ვერ მოხერხდება"</string>
    - </resources>
    -diff --git a/packages/SystemUI/res/values-kk-rKZ/strings.xml b/packages/SystemUI/res/values-kk-rKZ/strings.xml
    -index 2c444e4..25ede61 100644
    ---- a/packages/SystemUI/res/values-kk-rKZ/strings.xml
    -+++ b/packages/SystemUI/res/values-kk-rKZ/strings.xml
    -@@ -238,7 +238,7 @@
    -     <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"4G деректері кідіртілді"</string>
    -     <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"Ұялы деректер кідіртілді"</string>
    -     <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"Деректер кідіртілді"</string>
    --    <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"Орнатылған деректер шегіне жеткендіктен, құрылғы осы циклдың қалған бөлігі бойы деректерді пайдалануды кідіртті.\n\nЖалғастыру оператор ақыларына әкелуі мүмкін."</string>
    -+    <string name="data_usage_disabled_dialog" msgid="1841738975235283398">"Белгіленген деректер шегіне жеттіңіз. Ұялы деректер енді пайдаланылмайды.\n\nЕгер жалғастырсаңыз, деректер трафигі үшін ақы алынуы мүмкін."</string>
    -     <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"Жалғастыру"</string>
    -     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Интернет байланысы жоқ"</string>
    -     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi қосулы"</string>
    -@@ -404,6 +404,7 @@
    -     <string name="device_owned_footer" msgid="3802752663326030053">"Құрылғы бақылануы мүмкін"</string>
    -     <string name="profile_owned_footer" msgid="8021888108553696069">"Профиль бақылануы мүмкін"</string>
    -     <string name="vpn_footer" msgid="2388611096129106812">"Желі бақылауда болуы мүмкін"</string>
    -+    <string name="branded_vpn_footer" msgid="2168111859226496230">"Желі бақылауда болуы мүмкін"</string>
    -     <string name="monitoring_title_device_owned" msgid="7121079311903859610">"Құрылғыны бақылау"</string>
    -     <string name="monitoring_title_profile_owned" msgid="6790109874733501487">"Профильді бақылау"</string>
    -     <string name="monitoring_title" msgid="169206259253048106">"Желіні бақылау"</string>
    -@@ -416,6 +417,7 @@
    -     <string name="legacy_vpn_name" msgid="6604123105765737830">"VPN"</string>
    -     <string name="monitoring_description_app" msgid="6259179342284742878">"Сіз желідегі белсенділігіңізді, соның ішінде электрондық пошталарды, қолданбаларды және веб-сайттарды бақылай алатын <xliff:g id="APPLICATION">%1$s</xliff:g> қолданбасына қосылғансыз."</string>
    -     <string name="monitoring_description_app_personal" msgid="484599052118316268">"Сіз жеке желідегі белсенділігіңізді, соның ішінде электрондық пошталарды, қолданбаларды және веб-сайттарды бақылай алатын <xliff:g id="APPLICATION">%1$s</xliff:g> қолданбасына қосылғансыз."</string>
    -+    <string name="branded_monitoring_description_app_personal" msgid="2669518213949202599">"Жеке желідегі әрекеттеріңізді, соның ішінде электрондық пошта хабарларын, қолданбаларды және вебсайттарды бақылай алатын <xliff:g id="APPLICATION">%1$s</xliff:g> қолданбасына қосылғансыз."</string>
    -     <string name="monitoring_description_app_work" msgid="1754325860918060897">"Жұмыс профиліңізді <xliff:g id="ORGANIZATION">%1$s</xliff:g> басқарады. Ол жұмыс кезінде желідегі белсенділігіңізді, соның ішінде электрондық пошталарды, қолданбаларды және веб-сайттарды бақылай алатын <xliff:g id="APPLICATION">%2$s</xliff:g> қолданбасына қосылған.\n\nҚосымша ақпарат алу үшін әкімшіге хабарласыңыз."</string>
    -     <string name="monitoring_description_app_personal_work" msgid="4946600443852045903">"Жұмыс профиліңізді <xliff:g id="ORGANIZATION">%1$s</xliff:g> басқарады. Ол желідегі белсенділігіңізді, соның ішінде электрондық пошталарды, қолданбаларды және веб-сайттарды бақылай алатын <xliff:g id="APPLICATION_WORK">%2$s</xliff:g> қолданбасына қосылған.\n\nСондай-ақ сіз желідегі жеке белсенділігіңізді бақылай алатын <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g> қолданбасына қосылғансыз."</string>
    -     <string name="monitoring_description_vpn_app_device_owned" msgid="4970443827043261703">"Құрылғыңызды <xliff:g id="ORGANIZATION">%1$s</xliff:g> басқарады.\n\nӘкімші параметрлерді, корпоративтік рұқсатты, қолданбаларды, құрылғыңызбен байланысты деректерді және құрылғының орны туралы ақпаратты бақылай және басқара алады.\n\nСіз желідегі белсенділігіңізді, соның ішінде электрондық пошталарды, қолданбаларды және евб-сайттарды бақылай алатын <xliff:g id="APPLICATION">%2$s</xliff:g> қолданбасына қосылғансыз.\n\nҚосымша ақпарат алу үшін әкімшіге хабарласыңыз."</string>
    -@@ -492,8 +494,6 @@
    -     <string name="clock_seconds_desc" msgid="6282693067130470675">"Күйін көрсету жолағында сағат секундтарын көрсету. Батареяның қызмет көрсету мерзіміне әсер етуі мүмкін."</string>
    -     <string name="qs_rearrange" msgid="8060918697551068765">"Жылдам параметрлерді қайта реттеу"</string>
    -     <string name="show_brightness" msgid="6613930842805942519">"Жылдам параметрлерде жарықтықты көрсету"</string>
    --    <string name="overview_nav_bar_gesture" msgid="8579814204727917764">"Бөлінген экранда жоғары қарай сырғыту қимылын қосу"</string>
    --    <string name="overview_nav_bar_gesture_desc" msgid="6329167382305102615">"\"Шолу\" түймесінен жоғары қарай жанау арқылы бөлінген экранға кіру қимылын қосу"</string>
    -     <string name="experimental" msgid="6198182315536726162">"Эксперименттік"</string>
    -     <string name="enable_bluetooth_title" msgid="5027037706500635269">"Bluetooth функциясын қосу керек пе?"</string>
    -     <string name="enable_bluetooth_message" msgid="9106595990708985385">"Пернетақтаны планшетке қосу үшін алдымен Bluetooth функциясын қосу керек."</string>
    -@@ -651,4 +651,5 @@
    -     <string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"<xliff:g id="ID_1">%s</xliff:g> параметрлерін ашу."</string>
    -     <string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"Параметрлер тәртібін өзгерту."</string>
    -     <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"<xliff:g id="ID_2">%2$d</xliff:g> ішінен <xliff:g id="ID_1">%1$d</xliff:g>"</string>
    -+    <string name="cant_silence_or_block" msgid="999689262131488625">"Хабарландыруды үнсіз режимге қою не бөгеу мүмкін емес"</string>
    - </resources>
    -diff --git a/packages/SystemUI/res/values-km-rKH/strings.xml b/packages/SystemUI/res/values-km-rKH/strings.xml
    -index 0db7abc..f839eb6 100644
    ---- a/packages/SystemUI/res/values-km-rKH/strings.xml
    -+++ b/packages/SystemUI/res/values-km-rKH/strings.xml
    -@@ -238,7 +238,7 @@
    -     <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"ទិន្នន័យ 4G ត្រូវបានផ្អាក"</string>
    -     <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"ទិន្នន័យចល័តត្រូវបានផ្អាក"</string>
    -     <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"ទិន្នន័យត្រូវបានផ្អាក"</string>
    --    <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"ដោយសារទិន្នន័យរបស់អ្នកបានឈានដល់កំណត់ ឧបករណ៍នេះបានផ្អាកការប្រើប្រាស់ទិន្នន័យសម្រាប់ការរំលឹកនៃវគ្គនេះ។\n\nការបន្តប្រើប្រាស់អាចនាំឲ្យមានការគិតប្រាក់ពីក្រុមហ៊ុនផ្តល់សេវាកម្ម។"</string>
    -+    <string name="data_usage_disabled_dialog" msgid="1841738975235283398">"បានឈានដល់កម្រិតទិន្នន័យដែលអ្នកបានកំណត់ហើយ។ ឥឡូវ​អ្នកមិនប្រើទិន្នន័យចល័តទៀតទេ។\n\nអាចនឹងគិតថ្លៃលើការប្រើទិន្នន័យ ប្រសិនបើអ្នកបន្តប្រើឡើងវិញ។"</string>
    -     <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"បន្ត"</string>
    -     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"គ្មាន​ការ​តភ្ជាប់​អ៊ីនធឺណិត"</string>
    -     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"បាន​ភ្ជាប់​វ៉ាយហ្វាយ"</string>
    -@@ -404,6 +404,7 @@
    -     <string name="device_owned_footer" msgid="3802752663326030053">"ឧបករណ៍​អាច​ត្រូវ​បាន​ត្រួតពិនិត្យ"</string>
    -     <string name="profile_owned_footer" msgid="8021888108553696069">"ប្រវត្តិរូបអាចត្រូវបានតាមដាន"</string>
    -     <string name="vpn_footer" msgid="2388611096129106812">"បណ្ដាញ​អាច​ត្រូវ​បាន​ត្រួតពិនិត្យ"</string>
    -+    <string name="branded_vpn_footer" msgid="2168111859226496230">"បណ្ដាញអាចត្រូវបានត្រួតពិនិត្យ"</string>
    -     <string name="monitoring_title_device_owned" msgid="7121079311903859610">"ការ​ត្រួតពិនិត្យ​ឧបករណ៍"</string>
    -     <string name="monitoring_title_profile_owned" msgid="6790109874733501487">"តាមដានប្រវត្ថិរូប"</string>
    -     <string name="monitoring_title" msgid="169206259253048106">"ការ​ត្រួតពិនិត្យ​បណ្ដាញ"</string>
    -@@ -416,6 +417,7 @@
    -     <string name="legacy_vpn_name" msgid="6604123105765737830">"VPN"</string>
    -     <string name="monitoring_description_app" msgid="6259179342284742878">"អ្នកត្រូវបានតភ្ជាប់ទៅ <xliff:g id="APPLICATION">%1$s</xliff:g> ដែលអាចឃ្លាំមើលសកម្មភាពបណ្តាញរបស់អ្នក រាប់បញ្ចូលទាំងអ៊ីមែល កម្មវិធី និងគេហទំព័រ។"</string>
    -     <string name="monitoring_description_app_personal" msgid="484599052118316268">"អ្នកត្រូវបានតភ្ជាប់ទៅ <xliff:g id="APPLICATION">%1$s</xliff:g> ដែលអាចឃ្លាំមើលសកម្មភាពបណ្តាញរបស់អ្នក រាប់បញ្ចូលទាំងអ៊ីមែល កម្មវិធី និងគេហទំព័រ។"</string>
    -+    <string name="branded_monitoring_description_app_personal" msgid="2669518213949202599">"អ្នកត្រូវបានភ្ជាប់ទៅ <xliff:g id="APPLICATION">%1$s</xliff:g> ដែលអាចឃ្លាំមើលសកម្មភាពបណ្តាញរបស់អ្នក រាប់បញ្ចូលទាំងអ៊ីមែល កម្មវិធី និងគេហទំព័រ។"</string>
    -     <string name="monitoring_description_app_work" msgid="1754325860918060897">"ប្រវត្តិរូបការងាររបស់អ្នកត្រូវបានគ្រប់គ្រងដោយ <xliff:g id="ORGANIZATION">%1$s</xliff:g>។ វាត្រូវបានតភ្ជាប់ទៅនឹង <xliff:g id="APPLICATION">%2$s</xliff:g> ដែលអាចឃ្លាំមើលសកម្មភាពបណ្តាញរបស់អ្នក រាប់បញ្ចូលទាំងអ៊ីមែល កម្មវិធី គេហទំព័រ។\n\nសម្រាប់ព័ត៌មានបន្ថែម សូមទាក់ទងអ្នកគ្រប់គ្រប់របស់អ្នក។"</string>
    -     <string name="monitoring_description_app_personal_work" msgid="4946600443852045903">"ប្រវត្តិរូបការងាររបស់អ្នកត្រូវបានគ្រប់គ្រងដោយ <xliff:g id="ORGANIZATION">%1$s</xliff:g>។ វាត្រូវបានតភ្ជាប់ទៅនឹង <xliff:g id="APPLICATION_WORK">%2$s</xliff:g> ដែលអាចឃ្លាំមើលសកម្មភាពបណ្តាញរបស់អ្នក រាប់បញ្ចូលទាំងអ៊ីមែល កម្មវិធី គេហទំព័រ។\n\nអ្នកក៏ត្រូវបានតភ្ជាប់ផងដែរទៅនឹង <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g> ដែលអាចឃ្លាំមើលសកម្មភាពបណ្តាញផ្ទាល់ខ្លួនរបស់អ្នក។"</string>
    -     <string name="monitoring_description_vpn_app_device_owned" msgid="4970443827043261703">"ឧបករណ៍របស់អ្នកត្រូវបានគ្រប់គ្រងដោយ <xliff:g id="ORGANIZATION">%1$s</xliff:g>.\n\nអ្នកគ្រប់គ្រងរបស់អ្នកអាចឃ្លាំមើល និងគ្រប់គ្រងការកំណត់ ការចូលប្រើជាក្រុម កម្មវិធី ទិន្នន័យដែលជាប់ទាក់ទងនឹងឧបករណ៍របស់អ្នក និងព័ត៌មានទីតាំងនៃឧបករណ៍របស់អ្នក។\n\nអ្នកត្រូវបានភ្ជាប់ជាមួយ <xliff:g id="APPLICATION">%2$s</xliff:g> ដែលវាអាចឃ្លាំមើលសកម្មភាពបណ្តាញរបស់អ្នក រួមបញ្ចូលទាំងអ៊ីមែល កម្មវិធី និងគេហទំព័រ។\n\nសម្រាប់ព័ត៌មានបន្ថែម សូមទាក់ទងអ្នកគ្រប់គ្រងរបស់អ្នក។"</string>
    -@@ -492,8 +494,6 @@
    -     <string name="clock_seconds_desc" msgid="6282693067130470675">"បង្ហាញវិនាទីនៅលើរបារស្ថានភាពអាចនឹងប៉ះពាល់ដល់ថាមពលថ្ម។"</string>
    -     <string name="qs_rearrange" msgid="8060918697551068765">"រៀបចំការកំណត់រហ័សឡើងវិញ"</string>
    -     <string name="show_brightness" msgid="6613930842805942519">"បង្ហាញកម្រិតពន្លឺនៅក្នុងការកំណត់រហ័ស"</string>
    --    <string name="overview_nav_bar_gesture" msgid="8579814204727917764">"បើកដំណើរការកាយវិការអូសទៅលើដើម្បីបំបែកអេក្រង់"</string>
    --    <string name="overview_nav_bar_gesture_desc" msgid="6329167382305102615">"បើកដំណើរការកាយវិការដើម្បីបំបែកអេក្រង់ដោយអូសទៅលើចាប់ពីប៊ូតុងទិដ្ឋភាព"</string>
    -     <string name="experimental" msgid="6198182315536726162">"ពិសោធន៍"</string>
    -     <string name="enable_bluetooth_title" msgid="5027037706500635269">"បើកប៊្លូធូសឬ?"</string>
    -     <string name="enable_bluetooth_message" msgid="9106595990708985385">"ដើម្បីភ្ជាប់ក្តារចុចរបស់អ្នកជាមួយនឹងថេប្លេតរបស់អ្នក អ្នកត្រូវតែបើកប៊្លូធូសជាមុនសិន។"</string>
    -@@ -651,4 +651,5 @@
    -     <string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"បើការកំណត់ <xliff:g id="ID_1">%s</xliff:g>"</string>
    -     <string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"កែលំដាប់ការកំណត់"</string>
    -     <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"ទំព័រ <xliff:g id="ID_1">%1$d</xliff:g> នៃ <xliff:g id="ID_2">%2$d</xliff:g>"</string>
    -+    <string name="cant_silence_or_block" msgid="999689262131488625">"ការជូនដំណឹងមិនអាចបិទសំឡេង ឬរារាំងបានទេ"</string>
    - </resources>
    -diff --git a/packages/SystemUI/res/values-kn-rIN/strings.xml b/packages/SystemUI/res/values-kn-rIN/strings.xml
    -index c62a8db..8d9b2dd 100644
    ---- a/packages/SystemUI/res/values-kn-rIN/strings.xml
    -+++ b/packages/SystemUI/res/values-kn-rIN/strings.xml
    -@@ -84,7 +84,7 @@
    -     <string name="accessibility_home" msgid="8217216074895377641">"ಮುಖಪುಟ"</string>
    -     <string name="accessibility_menu" msgid="316839303324695949">"ಮೆನು"</string>
    -     <string name="accessibility_recent" msgid="5208608566793607626">"ಸಮಗ್ರ ನೋಟ"</string>
    --    <string name="accessibility_search_light" msgid="1103867596330271848">"ಹುಡುಕು"</string>
    -+    <string name="accessibility_search_light" msgid="1103867596330271848">"ಹುಡುಕಿ"</string>
    -     <string name="accessibility_camera_button" msgid="8064671582820358152">"ಕ್ಯಾಮರಾ"</string>
    -     <string name="accessibility_phone_button" msgid="6738112589538563574">"ಫೋನ್"</string>
    -     <string name="accessibility_voice_assist_button" msgid="487611083884852965">"ಧ್ವನಿ ಸಹಾಯಕ"</string>
    -@@ -238,7 +238,7 @@
    -     <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"4G ಡೇಟಾ ವಿರಾಮಗೊಳಿಸಲಾಗಿದೆ"</string>
    -     <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"ಸೆಲ್ಯುಲಾರ್ ಡೇಟಾ ವಿರಾಮಗೊಳಿಸಲಾಗಿದೆ"</string>
    -     <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"ಡೇಟಾ ವಿರಾಮಗೊಳಿಸಲಾಗಿದೆ"</string>
    --    <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"ಏಕೆಂದರೆ ನಿಮ್ಮ ಹೊಂದಾಣಿಕೆ ಡೇಟಾ ಮೀತಿಯನ್ನು ತಲುಪಿದೆ, ಈ ಆವರ್ತನೆಯ ಉಳಿದ ಭಾಗಕ್ಕೆ ಸಾಧನವು ಡೇಟಾ ಬಳಕೆಯನ್ನು ವಿರಾಮಗೊಳಿಸಿದೆ.\n\nಮುಂದುವರೆಯುವಿಕೆಯು ನಿಮ್ಮ ವಾಹಕದ ಶುಲ್ಕಗಳಿಗೆ ಕಾರಣವಾಗಬಹುದು."</string>
    -+    <string name="data_usage_disabled_dialog" msgid="1841738975235283398">"ನೀವು ಹೊಂದಿಸಿರುವ ಡೇಟಾ ಮಿತಿ ತಲುಪಿದೆ. ನೀವು ಎಂದಿಗೂ ಸೆಲ್ಯುಲಾರ್ ಡೇಟಾವನ್ನು ಬಳಸದೆ ಇರಬಹುದು.\n\nನೀವು ಮುಂದುವರಿಸಿದರೆ, ಡೇಟಾ ಬಳಕೆಗೆ ಶುಲ್ಕಗಳು ಅನ್ವಯವಾಗಬಹುದು."</string>
    -     <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"ಮುಂದುವರಿಸು"</string>
    -     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"ಇಂಟರ್ನೆಟ್ ಸಂಪರ್ಕವಿಲ್ಲ"</string>
    -     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"ವೈ-ಫೈ ಸಂಪರ್ಕಗೊಂಡಿದೆ"</string>
    -@@ -404,6 +404,7 @@
    -     <string name="device_owned_footer" msgid="3802752663326030053">"ಸಾಧನವನ್ನು ಪರಿವೀಕ್ಷಿಸಬಹುದಾಗಿದೆ"</string>
    -     <string name="profile_owned_footer" msgid="8021888108553696069">"ಪ್ರೊಫೈಲ್ ಅನ್ನು ಪರಿವೀಕ್ಷಿಸಬಹುದಾಗಿದೆ"</string>
    -     <string name="vpn_footer" msgid="2388611096129106812">"ನೆಟ್‌ವರ್ಕ್ ಅನ್ನು ವೀಕ್ಷಿಸಬಹುದಾಗಿ"</string>
    -+    <string name="branded_vpn_footer" msgid="2168111859226496230">"ನೆಟ್‌ವರ್ಕ್ ಅನ್ನು ವೀಕ್ಷಿಸಬಹುದಾಗಿರುತ್ತದೆ"</string>
    -     <string name="monitoring_title_device_owned" msgid="7121079311903859610">"ಸಾಧನ ಪರಿವೀಕ್ಷಣೆ"</string>
    -     <string name="monitoring_title_profile_owned" msgid="6790109874733501487">"ಪ್ರೊಫೈಲ್ ಮೇಲ್ವಿಚಾರಣೆ"</string>
    -     <string name="monitoring_title" msgid="169206259253048106">"ನೆಟ್‌ವರ್ಕ್‌ ಪರಿವೀಕ್ಷಣೆ"</string>
    -@@ -416,6 +417,7 @@
    -     <string name="legacy_vpn_name" msgid="6604123105765737830">"VPN"</string>
    -     <string name="monitoring_description_app" msgid="6259179342284742878">"ನೀವು ಇಮೇಲ್‌ಗಳು, ಅಪ್ಲಿಕೇಶನ್‌ಗಳು ಮತ್ತು ವೆಬ್‌ಸೈಟ್‌ಗಳನ್ನು ಒಳಗೊಂಡಂತೆ ನಿಮ್ಮ ನೆಟ್‌ವರ್ಕ್ ಚಟುವಟಿಕೆಯ ಮೇಲ್ವಿಚಾರಣೆ ಮಾಡಬಹುದಾದ <xliff:g id="APPLICATION">%1$s</xliff:g> ಗೆ ಸಂಪರ್ಕಗೊಂಡಿರುವಿರಿ."</string>
    -     <string name="monitoring_description_app_personal" msgid="484599052118316268">"ನೀವು ಇಮೇಲ್‌ಗಳು, ಅಪ್ಲಿಕೇಶನ್‌ಗಳು ಮತ್ತು ವೆಬ್‌ಸೈಟ್‌ಗಳು ಸೇರಿದಂತೆ ನಿಮ್ಮ ವೈಯಕ್ತಿಕ ನೆಟ್‌ವರ್ಕ್ ಚಟುವಟಿಕೆಯ ಮೇಲ್ವಿಚಾರಣೆ ಮಾಡಬಹುದಾದ <xliff:g id="APPLICATION">%1$s</xliff:g> ಗೆ ಸಂಪರ್ಕಗೊಂಡಿರುವಿರಿ."</string>
    -+    <string name="branded_monitoring_description_app_personal" msgid="2669518213949202599">"ನೀವು ಇಮೇಲ್‌ಗಳು, ಅಪ್ಲಿಕೇಶನ್‌ಗಳು, ಮತ್ತು ವೆಬ್‌ಸೈಟ್‌ಗಳನ್ನು ಒಳಗೊಂಡಂತೆ ನಿಮ್ಮ ವೈಯಕ್ತಿಕ ನೆಟ್‌ವರ್ಕ್ ಚಟುವಟಿಕೆಯ ಮೇಲ್ವಿಚಾರಣೆ ಮಾಡಬಹುದಾದ <xliff:g id="APPLICATION">%1$s</xliff:g> ಗೆ ಸಂಪರ್ಕಗೊಂಡಿರುವಿರಿ."</string>
    -     <string name="monitoring_description_app_work" msgid="1754325860918060897">"ನಿಮ್ಮ ಕೆಲಸದ ಪ್ರೊಫೈಲ್‌ ಅನ್ನು <xliff:g id="ORGANIZATION">%1$s</xliff:g> ಮೂಲಕ ನಿರ್ವಹಿಸಲಾಗುತ್ತಿದೆ. ಇದು ಇಮೇಲ್‌ಗಳು, ಅಪ್ಲಿಕೇಶನ್‌ಗಳು, ಮತ್ತು ವೆಬ್‌ಸೈಟ್‌ಗಳನ್ನು ಒಳಗೊಂಡಂತೆ ನಿಮ್ಮ ಕೆಲಸದ ನೆಟ್‌ವರ್ಕ್ ಚಟುವಟಿಕೆಯ ಮೇಲ್ವಿಚಾರಣೆ ಮಾಡಬಹುದಾದ <xliff:g id="APPLICATION">%2$s</xliff:g> ಗೆ ಸಂಪರ್ಕಗೊಂಡಿದೆ.\n\nಹೆಚ್ಚಿನ ಮಾಹಿತಿಗಾಗಿ, ನಿಮ್ಮ ನಿರ್ವಾಹಕರನ್ನು ಸಂಪರ್ಕಿಸಿ."</string>
    -     <string name="monitoring_description_app_personal_work" msgid="4946600443852045903">"ನಿಮ್ಮ ಕೆಲಸದ ಪ್ರೊಫೈಲ್‌ ಅನ್ನು <xliff:g id="ORGANIZATION">%1$s</xliff:g> ಮೂಲಕ ನಿರ್ವಹಿಸಲಾಗುತ್ತಿದೆ. ಇದು ಇಮೇಲ್‌ಗಳು, ಅಪ್ಲಿಕೇಶನ್‌ಗಳು, ಮತ್ತು ವೆಬ್‌ಸೈಟ್‌ಗಳನ್ನು ಒಳಗೊಂಡಂತೆ ನಿಮ್ಮ ಕೆಲಸದ ನೆಟ್‌ವರ್ಕ್ ಚಟುವಟಿಕೆಯ ಮೇಲ್ವಿಚಾರಣೆ ಮಾಡಬಹುದಾದ <xliff:g id="APPLICATION_WORK">%2$s</xliff:g> ಗೆ ಸಂಪರ್ಕಿತಗೊಂಡಿದೆ.\n\nನೀವು ಕೂಡಾ ವೈಯಕ್ತಿಕ ನೆಟ್‌ವರ್ಕ್ ಚಟುವಟಿಕೆಯ ಮೇಲ್ವಿಚಾರಣೆ ಮಾಡಬಹುದಾದ <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g> ಗೆ ಸಂಪರ್ಕಿತಗೊಂಡಿರುವಿರಿ."</string>
    -     <string name="monitoring_description_vpn_app_device_owned" msgid="4970443827043261703">"ನಿಮ್ಮ ಸಾಧನವನ್ನು <xliff:g id="ORGANIZATION">%1$s</xliff:g> ಮೂಲಕ ನಿರ್ವಹಿಸಲಾಗುತ್ತಿದೆ.\n\nನಿಮ್ಮ ನಿರ್ವಾಹಕರು ಸೆಟ್ಟಿಂಗ್‌ಗಳು, ಕಾರ್ಪೊರೇಟ್ ಪ್ರವೇಶ, ಅಪ್ಲಿಕೇಶನ್‌ಗಳು ಹಾಗೂ ನಿಮ್ಮ ಸಾಧನದೊಂದಿಗೆ ಸಂಬಂಧಿಸಿದ ಡೇಟಾ ಮತ್ತು ನಿಮ್ಮ ಸಾಧನದ ಸ್ಥಳ ಮಾಹಿತಿಯನ್ನು ಮೇಲ್ವಿಚಾರಣೆ ಮಾಡಬಹುದು ಮತ್ತು ನಿರ್ವಹಿಸಬಹುದು.\n\nಇಮೇಲ್‌ಗಳು, ಅಪ್ಲಿಕೇಶನ್‌ಗಳು ಮತ್ತು ವೆಬ್‌ಸೈಟ್‌ಗಳನ್ನು ಒಳಗೊಂಡಂತೆ ನಿಮ್ಮ ನೆಟ್‌ವರ್ಕ್ ಚಟುವಟಿಕೆಯನ್ನು ಮೇಲ್ವಿಚಾರಣೆ ಮಾಡಬಹುದಾದ <xliff:g id="APPLICATION">%2$s</xliff:g> ಗೆ ಸಂಪರ್ಕಿತಗೊಂಡಿರುವಿರಿ.\n\nಹೆಚ್ಚಿನ ಮಾಹಿತಿಗಾಗಿ, ನಿಮ್ಮ ನಿರ್ವಾಹಕರನ್ನು ಸಂಪರ್ಕಿಸಿ."</string>
    -@@ -492,8 +494,6 @@
    -     <string name="clock_seconds_desc" msgid="6282693067130470675">"ಸ್ಥಿತಿ ಪಟ್ಟಿಯಲ್ಲಿ ಗಡಿಯಾರ ಸೆಕೆಂಡುಗಳನ್ನು ತೋರಿಸು. ಇದಕ್ಕೆ ಬ್ಯಾಟರಿ ಬಾಳಿಕೆಯು ಪರಿಣಾಮಬೀರಬಹುದು."</string>
    -     <string name="qs_rearrange" msgid="8060918697551068765">"ತ್ವರಿತ ಸೆಟ್ಟಿಂಗ್‌‌ಗಳನ್ನು ಮರುಹೊಂದಿಸಿ"</string>
    -     <string name="show_brightness" msgid="6613930842805942519">"ತ್ವರಿತ ಸೆಟ್ಟಿಂಗ್‌‌ಗಳಲ್ಲಿ ಪ್ರಖರತೆಯನ್ನು ತೋರಿಸಿ"</string>
    --    <string name="overview_nav_bar_gesture" msgid="8579814204727917764">"ಸ್ಪ್ಲಿಟ್-ಸ್ಕ್ರೀನ್ ಸ್ವೈಪ್-ಅಪ್ ಗೆಶ್ಚರ್ ಸಕ್ರಿಯಗೊಳಿಸಿ"</string>
    --    <string name="overview_nav_bar_gesture_desc" msgid="6329167382305102615">"ಸಮಗ್ರ ನೋಟದ ಬಟನ್‌ನಿಂದ ಮೇಲಕ್ಕೆ ಸ್ವೈಪ್ ಮಾಡಿ ಸ್ಪ್ಲಿಟ್‌-ಸ್ಕ್ರೀನ್ ನಮೂದಿಸಲು ಗೆಸ್ಚರ್‌ ಸಕ್ರಿಯಗೊಳಿಸಿ"</string>
    -     <string name="experimental" msgid="6198182315536726162">"ಪ್ರಾಯೋಗಿಕ"</string>
    -     <string name="enable_bluetooth_title" msgid="5027037706500635269">"ಬ್ಲೂಟೂತ್ ಆನ್ ಮಾಡುವುದೇ?"</string>
    -     <string name="enable_bluetooth_message" msgid="9106595990708985385">"ನಿಮ್ಮ ಕೀಬೋರ್ಡ್ ಅನ್ನು ಟ್ಯಾಬ್ಲೆಟ್‌ಗೆ ಸಂಪರ್ಕಿಸಲು, ನೀವು ಮೊದಲು ಬ್ಲೂಟೂತ್ ಆನ್ ಮಾಡಬೇಕಾಗುತ್ತದೆ."</string>
    -@@ -593,8 +593,8 @@
    -     <string name="add_button" msgid="4134946063432258161">"ಬಟನ್ ಸೇರಿಸು"</string>
    -     <string name="save" msgid="2311877285724540644">"ಉಳಿಸು"</string>
    -     <string name="reset" msgid="2448168080964209908">"ಮರುಹೊಂದಿಸು"</string>
    --    <string name="no_home_title" msgid="1563808595146071549">"ಯಾವುದೇ ಹೋಮ್ ಬಟನ್ ಕಂಡುಬಂದಿಲ್ಲ"</string>
    --    <string name="no_home_message" msgid="5408485011659260911">"ಈ ಸಾಧನವನ್ನು ನ್ಯಾವಿಗೇಟ್ ಮಾಡಲು ಹೋಮ್ ಬಟನ್ ಅಗತ್ಯವಿರುತ್ತದೆ. ಉಳಿಸುವ ಮೊದಲು ದಯವಿಟ್ಟು ಹೋಮ್ ಬಟನ್ ಸೇರಿಸಿ."</string>
    -+    <string name="no_home_title" msgid="1563808595146071549">"ಯಾವುದೇ ಮುಖಪುಟ ಬಟನ್ ಕಂಡುಬಂದಿಲ್ಲ"</string>
    -+    <string name="no_home_message" msgid="5408485011659260911">"ಈ ಸಾಧನವನ್ನು ನ್ಯಾವಿಗೇಟ್ ಮಾಡಲು ಮುಖಪುಟ ಬಟನ್ ಅಗತ್ಯವಿರುತ್ತದೆ. ಉಳಿಸುವ ಮೊದಲು ದಯವಿಟ್ಟು ಮುಖಪುಟ ಬಟನ್ ಸೇರಿಸಿ."</string>
    -     <string name="adjust_button_width" msgid="6138616087197632947">"ಬಟನ್ ಅಳತೆ ಹೊಂದಿಸು"</string>
    -     <string name="clipboard" msgid="1313879395099896312">"ಕ್ಲಿಪ್‌ಬೋರ್ಡ್"</string>
    -     <string name="clipboard_description" msgid="3819919243940546364">"ಐಟಂಗಳನ್ನು ನೇರವಾಗಿ ಕ್ಲಿಪ್‌ಬೋರ್ಡ್‌ಗೆ ಡ್ರ್ಯಾಗ್ ಮಾಡಲು ಕ್ಲಿಪ್‌ಬೋರ್ಡ್ ಅನುಮತಿಸುತ್ತದೆ. ಐಟಂಗಳು ಅಸ್ತಿತ್ವದಲ್ಲಿರುವಾಗ ಅವುಗಳನ್ನು ಕ್ಲಿಪ್‌ಬೋರ್ಡ್‌ನಿಂದ ನೇರವಾಗಿ ಹೊರಗೆ ಹಾಕಬಹುದಾಗಿರುತ್ತದೆ."</string>
    -@@ -651,4 +651,5 @@
    -     <string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"<xliff:g id="ID_1">%s</xliff:g> ಸೆಟ್ಟಿಂಗ್‌ಗಳನ್ನು ತೆರೆಯಿರಿ."</string>
    -     <string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"ಸೆಟ್ಟಿಂಗ್‌ಗಳ ಕ್ರಮವನ್ನು ಎಡಿಟ್ ಮಾಡಿ."</string>
    -     <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"<xliff:g id="ID_2">%2$d</xliff:g> ರಲ್ಲಿ <xliff:g id="ID_1">%1$d</xliff:g> ಪುಟ"</string>
    -+    <string name="cant_silence_or_block" msgid="999689262131488625">"ಸೂಚನೆಗಳನ್ನು ಮೌನವಾಗಿಸಲಾಗುವುದಿಲ್ಲ ಅಥವಾ ತಡೆಹಿಡಿಯಲಾಗುವುದಿಲ್ಲ"</string>
    - </resources>
    -diff --git a/packages/SystemUI/res/values-kn-rIN/strings_tv.xml b/packages/SystemUI/res/values-kn-rIN/strings_tv.xml
    -index 5afb322..edaa8e6 100644
    ---- a/packages/SystemUI/res/values-kn-rIN/strings_tv.xml
    -+++ b/packages/SystemUI/res/values-kn-rIN/strings_tv.xml
    -@@ -25,7 +25,7 @@
    -     <string name="pip_pause" msgid="8412075640017218862">"ವಿರಾಮ"</string>
    -     <string name="pip_hold_home" msgid="340086535668778109">"PIP ನಿಯಂತ್ರಿಸಲು "<b>"HOME"</b>" ಕೀಯನ್ನು ಹಿಡಿದುಕೊಳ್ಳಿ"</string>
    -     <string name="pip_onboarding_title" msgid="7850436557670253991">"ಚಿತ್ರದಲ್ಲಿ ಚಿತ್ರ"</string>
    --    <string name="pip_onboarding_description" msgid="4028124563309465267">"ನೀವು ಮತ್ತೊಂದನ್ನು ಪ್ಲೇ ಮಾಡುವ ತನಕ ಇದು ನಿಮ್ಮ ವೀಡಿಯೋವನ್ನು ವೀಕ್ಷಣೆಯಲ್ಲಿರಿಸುತ್ತದೆ. ಅದನ್ನು ನಿಯಂತ್ರಿಸಲು "<b>"ಹೋಮ್"</b>" ಅನ್ನು ಒತ್ತಿ ಹಿಡಿಯಿರಿ."</string>
    -+    <string name="pip_onboarding_description" msgid="4028124563309465267">"ನೀವು ಮತ್ತೊಂದನ್ನು ಪ್ಲೇ ಮಾಡುವ ತನಕ ಇದು ನಿಮ್ಮ ವೀಡಿಯೋವನ್ನು ವೀಕ್ಷಣೆಯಲ್ಲಿರಿಸುತ್ತದೆ. ಅದನ್ನು ನಿಯಂತ್ರಿಸಲು "<b>"ಮುಖಪುಟ"</b>" ಅನ್ನು ಒತ್ತಿ ಹಿಡಿಯಿರಿ."</string>
    -     <string name="pip_onboarding_button" msgid="3957426748484904611">"ಅರ್ಥವಾಯಿತು"</string>
    -     <string name="recents_tv_dismiss" msgid="3555093879593377731">"ವಜಾಗೊಳಿಸಿ"</string>
    -   <string-array name="recents_tv_blacklist_array">
    -diff --git a/packages/SystemUI/res/values-ko/strings.xml b/packages/SystemUI/res/values-ko/strings.xml
    -index 3c08e92..b3f121c 100644
    ---- a/packages/SystemUI/res/values-ko/strings.xml
    -+++ b/packages/SystemUI/res/values-ko/strings.xml
    -@@ -240,7 +240,7 @@
    -     <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"4G 데이터 사용 중지됨"</string>
    -     <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"모바일 데이터 사용 중지됨"</string>
    -     <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"데이터 사용 중지됨"</string>
    --    <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"설정된 데이터 한도에 도달했기 때문에 기기에서 사이클의 나머지 기간 동안 데이터 사용을 일시 중지했습니다. \n\n데이터 사용을 재개하면 이동통신사 요금이 청구될 수 있습니다."</string>
    -+    <string name="data_usage_disabled_dialog" msgid="1841738975235283398">"설정한 데이터 한도에 도달했습니다. 더 이상 모바일 데이터를 사용하지 않습니다.\n\n계속 사용하면 데이터 사용 요금이 부과될 수 있습니다."</string>
    -     <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"재개"</string>
    -     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"인터넷에 연결되지 않음"</string>
    -     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi 연결됨"</string>
    -@@ -406,6 +406,7 @@
    -     <string name="device_owned_footer" msgid="3802752663326030053">"기기가 모니터링될 수 있음"</string>
    -     <string name="profile_owned_footer" msgid="8021888108553696069">"프로필이 모니터링될 수 있음"</string>
    -     <string name="vpn_footer" msgid="2388611096129106812">"네트워크가 모니터링될 수 있음"</string>
    -+    <string name="branded_vpn_footer" msgid="2168111859226496230">"네트워크가 모니터링될 수 있음"</string>
    -     <string name="monitoring_title_device_owned" msgid="7121079311903859610">"기기 모니터링"</string>
    -     <string name="monitoring_title_profile_owned" msgid="6790109874733501487">"프로필 모니터링"</string>
    -     <string name="monitoring_title" msgid="169206259253048106">"네트워크 모니터링"</string>
    -@@ -418,6 +419,7 @@
    -     <string name="legacy_vpn_name" msgid="6604123105765737830">"VPN"</string>
    -     <string name="monitoring_description_app" msgid="6259179342284742878">"<xliff:g id="APPLICATION">%1$s</xliff:g>에 연결되었습니다. 이 앱은 이메일, 앱, 웹사이트와 같은 내 네트워크 활동을 모니터링할 수 있습니다."</string>
    -     <string name="monitoring_description_app_personal" msgid="484599052118316268">"<xliff:g id="APPLICATION">%1$s</xliff:g>에 연결되었습니다. 이 앱은 이메일, 앱, 웹사이트와 같은 내 네트워크 활동을 모니터링할 수 있습니다."</string>
    -+    <string name="branded_monitoring_description_app_personal" msgid="2669518213949202599">"<xliff:g id="APPLICATION">%1$s</xliff:g>에 연결되었습니다. 이 앱은 이메일, 앱, 웹사이트와 같은 내 개인 네트워크 활동을 모니터링할 수 있습니다."</string>
    -     <string name="monitoring_description_app_work" msgid="1754325860918060897">"직장 프로필은 <xliff:g id="ORGANIZATION">%1$s</xliff:g>에서 관리합니다. 이는 <xliff:g id="APPLICATION">%2$s</xliff:g>에 연결되어 있으며 여기에서 이메일, 앱, 웹사이트와 같은 직장 네트워크 활동을 모니터링할 수 있습니다.\n\n자세한 내용은 관리자에게 문의하세요."</string>
    -     <string name="monitoring_description_app_personal_work" msgid="4946600443852045903">"직장 프로필은 <xliff:g id="ORGANIZATION">%1$s</xliff:g>에서 관리합니다. 이는 <xliff:g id="APPLICATION_WORK">%2$s</xliff:g>에 연결되어 있으며 여기에서 이메일, 앱, 웹사이트와 같은 직장 네트워크 활동을 모니터링할 수 있습니다.\n\n또한 <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g>에 연결되어 있으며, 여기에서 내 개인 네트워크 활동을 모니터링할 수 있습니다."</string>
    -     <string name="monitoring_description_vpn_app_device_owned" msgid="4970443827043261703">"<xliff:g id="ORGANIZATION">%1$s</xliff:g>에서 기기를 관리합니다.\n\n관리자는 설정, 기업 액세스, 앱, 기기와 연결된 데이터, 기기의 위치 정보를 모니터링하고 관리할 수 있습니다.\n\n<xliff:g id="APPLICATION">%2$s</xliff:g>에 연결되어 있으며 여기에서 이메일, 앱, 웹사이트와 같은 내 네트워크 활동을 모니터링할 수 있습니다.\n\n자세한 내용은 관리자에게 문의하세요."</string>
    -@@ -465,7 +467,7 @@
    -     <string name="show_battery_percentage_summary" msgid="3215025775576786037">"충전 중이 아닌 경우 상태 표시줄 아이콘 내에 배터리 잔량 비율 표시"</string>
    -     <string name="quick_settings" msgid="10042998191725428">"빠른 설정"</string>
    -     <string name="status_bar" msgid="4877645476959324760">"상태 표시줄"</string>
    --    <string name="overview" msgid="4018602013895926956">"개요"</string>
    -+    <string name="overview" msgid="4018602013895926956">"최근 사용"</string>
    -     <string name="demo_mode" msgid="2389163018533514619">"데모 모드"</string>
    -     <string name="enable_demo_mode" msgid="4844205668718636518">"데모 모드 사용"</string>
    -     <string name="show_demo_mode" msgid="2018336697782464029">"데모 모드 표시"</string>
    -@@ -494,8 +496,6 @@
    -     <string name="clock_seconds_desc" msgid="6282693067130470675">"상태 표시줄에 시계 초 단위를 표시합니다. 배터리 수명에 영향을 줄 수도 있습니다."</string>
    -     <string name="qs_rearrange" msgid="8060918697551068765">"빠른 설정 재정렬"</string>
    -     <string name="show_brightness" msgid="6613930842805942519">"빠른 설정에서 밝기 표시"</string>
    --    <string name="overview_nav_bar_gesture" msgid="8579814204727917764">"화면 분할 위로 스와이프 동작 사용"</string>
    --    <string name="overview_nav_bar_gesture_desc" msgid="6329167382305102615">"최근 사용 버튼에서 위로 스와이프하기 동작으로 창 분할 모드를 사용 설정합니다."</string>
    -     <string name="experimental" msgid="6198182315536726162">"베타"</string>
    -     <string name="enable_bluetooth_title" msgid="5027037706500635269">"블루투스를 켜시겠습니까?"</string>
    -     <string name="enable_bluetooth_message" msgid="9106595990708985385">"키보드를 태블릿에 연결하려면 먼저 블루투스를 켜야 합니다."</string>
    -@@ -653,4 +653,5 @@
    -     <string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"<xliff:g id="ID_1">%s</xliff:g> 설정 열기"</string>
    -     <string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"설정 순서 수정"</string>
    -     <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"<xliff:g id="ID_2">%2$d</xliff:g>페이지 중 <xliff:g id="ID_1">%1$d</xliff:g>페이지"</string>
    -+    <string name="cant_silence_or_block" msgid="999689262131488625">"알림을 무음으로 설정하거나 차단할 수 없습니다."</string>
    - </resources>
    -diff --git a/packages/SystemUI/res/values-ky-rKG/strings.xml b/packages/SystemUI/res/values-ky-rKG/strings.xml
    -index 7645b93..cb404cb 100644
    ---- a/packages/SystemUI/res/values-ky-rKG/strings.xml
    -+++ b/packages/SystemUI/res/values-ky-rKG/strings.xml
    -@@ -238,7 +238,7 @@
    -     <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"4G дайындары тындырылды"</string>
    -     <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"Уюлдук дайындар тындырылды"</string>
    -     <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"Дайындар тындырылды"</string>
    --    <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"Киргизиле турган дайындар белгиленген эң жогорку чекке жеткендиктен, ушул мерчимдин калган бөлүгүндө түзмөгүңүздө дайындардын колдонулушу тындырылды.\n\nУлантсаңыз, байланыш операторуңузга акы төлөп калышыңыз мүмкүн."</string>
    -+    <string name="data_usage_disabled_dialog" msgid="1841738975235283398">"Трафик сиз койгон чекке жетти. Эми мобилдик дайындарды колдоно албайсыз.\n\nЭгер улантсаңыз, мобилдик дайындарды колдонгонуңуз үчүн акы алынышы мүмкүн."</string>
    -     <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"Улантуу"</string>
    -     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Интернет байланыш жок"</string>
    -     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi байланышта"</string>
    -@@ -404,6 +404,7 @@
    -     <string name="device_owned_footer" msgid="3802752663326030053">"Түзмөктү көзөмөлдөсө болот"</string>
    -     <string name="profile_owned_footer" msgid="8021888108553696069">"Профилди көзөмөлдөсө болот"</string>
    -     <string name="vpn_footer" msgid="2388611096129106812">"Тармак көзөмөлдөнүшү мүмкүн"</string>
    -+    <string name="branded_vpn_footer" msgid="2168111859226496230">"Тармак көзөмөлдөнүшү мүмкүн"</string>
    -     <string name="monitoring_title_device_owned" msgid="7121079311903859610">"Түзмөккө көз салуу"</string>
    -     <string name="monitoring_title_profile_owned" msgid="6790109874733501487">"Профилди көзөмөлдөө"</string>
    -     <string name="monitoring_title" msgid="169206259253048106">"Тармакка көз салуу"</string>
    -@@ -416,6 +417,7 @@
    -     <string name="legacy_vpn_name" msgid="6604123105765737830">"VPN"</string>
    -     <string name="monitoring_description_app" msgid="6259179342284742878">"Электрондук почта, колдонмолор жана вебсайттар сыяктуу тармактык аракеттерди көзөмөлдөй турган <xliff:g id="APPLICATION">%1$s</xliff:g> колдонмосуна туташып турасыз."</string>
    -     <string name="monitoring_description_app_personal" msgid="484599052118316268">"Электрондук почта, колдонмолор жана вебсайттар сыяктуу тармактагы жеке аракеттериңизди көзөмөлдөй турган <xliff:g id="APPLICATION">%1$s</xliff:g> колдонмосуна туташып турасыз."</string>
    -+    <string name="branded_monitoring_description_app_personal" msgid="2669518213949202599">"Электрондук почта, колдонмолор жана вебсайттар сыяктуу тармактагы жеке аракеттериңизди тескей турган <xliff:g id="APPLICATION">%1$s</xliff:g> колдонмосуна туташып турасыз."</string>
    -     <string name="monitoring_description_app_work" msgid="1754325860918060897">"Жумуш профилиңизди <xliff:g id="ORGANIZATION">%1$s</xliff:g> башкарат. Ал электрондук почта, колдонмолор жана вебсайттар сыяктуу жумуш тармагыңыздагы аракеттерди көзөмөлдөй турган <xliff:g id="APPLICATION">%2$s</xliff:g> менен туташкан.\n\nКөбүрөөк маалымат алуу үчүн администраторуңузга кайрылыңыз."</string>
    -     <string name="monitoring_description_app_personal_work" msgid="4946600443852045903">"Жумуш профилиңизди <xliff:g id="ORGANIZATION">%1$s</xliff:g> башкарат. Ал электрондук почта, колдонмолор жана вебсайттар сыяктуу жумуш тармагыңыздагы аракеттерди көзөмөлдөй турган <xliff:g id="APPLICATION_WORK">%2$s</xliff:g> менен туташкан.\n\nМындан тышкары, тармактагы жеке аракеттериңизди көзөмөлдөгөн <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g> колдонмосуна туташып турасыз."</string>
    -     <string name="monitoring_description_vpn_app_device_owned" msgid="4970443827043261703">"Түзмөгүңүздү <xliff:g id="ORGANIZATION">%1$s</xliff:g> башкарат.\nАдминистраторуңуз түзмөгүңүздөгү жөндөөлөрдү, корпоративдик мүмкүнчүлүктү, колдонмолорду, дайындарды, ошону менен катар жайгашкан жер дайындарын башкарып, тийиштүү маалыматты карай алат.\n\nСиз электрондук почталар, колдонмолор жана вебсайттар сыяктуу тармактагы аракеттериңизди тармактагы аракетиңизди тескей турган APPLICATION колдонмосуна туташып турасыз.\n<xliff:g id="APPLICATION">%2$s</xliff:g>Көбүрөөк маалымат алуу үчүн, администраторуңузга кайрылыңыз.\n\n"</string>
    -@@ -492,8 +494,6 @@
    -     <string name="clock_seconds_desc" msgid="6282693067130470675">"Абал тилкесинен сааттын секунддары көрсөтүлсүн. Батареянын кубаты көбүрөөк сарпталышы мүмкүн."</string>
    -     <string name="qs_rearrange" msgid="8060918697551068765">"Ыкчам жөндөөлөрдү кайра коюу"</string>
    -     <string name="show_brightness" msgid="6613930842805942519">"Ыкчам жөндөөлөрдөн жарык деңгээлин көрсөтүү"</string>
    --    <string name="overview_nav_bar_gesture" msgid="8579814204727917764">"Өйдө серпип экранды бөлүү жаңсоосун иштетүү"</string>
    --    <string name="overview_nav_bar_gesture_desc" msgid="6329167382305102615">"Сереп баскычынан өйдө серпип, экранды бөлүү режимин киргизүү үчүн жаңсоону иштетиңиз"</string>
    -     <string name="experimental" msgid="6198182315536726162">"Сынамык"</string>
    -     <string name="enable_bluetooth_title" msgid="5027037706500635269">"Bluetooth күйгүзүлсүнбү?"</string>
    -     <string name="enable_bluetooth_message" msgid="9106595990708985385">"Баскычтобуңузду планшетиңизге туташтыруу үчүн, адегенде Bluetooth\'ту күйгүзүшүңүз керек."</string>
    -@@ -651,4 +651,5 @@
    -     <string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"<xliff:g id="ID_1">%s</xliff:g> жөндөөлөрүн ачуу."</string>
    -     <string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"Жөндөөлөрдүн иретин өзгөртүү."</string>
    -     <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"<xliff:g id="ID_2">%2$d</xliff:g> ичинен <xliff:g id="ID_1">%1$d</xliff:g>-бет"</string>
    -+    <string name="cant_silence_or_block" msgid="999689262131488625">"Эскертмелердин үнүн басууга же бөгөттөөгө болбойт"</string>
    - </resources>
    -diff --git a/packages/SystemUI/res/values-lo-rLA/strings.xml b/packages/SystemUI/res/values-lo-rLA/strings.xml
    -index 6b1fca8..76350cc 100644
    ---- a/packages/SystemUI/res/values-lo-rLA/strings.xml
    -+++ b/packages/SystemUI/res/values-lo-rLA/strings.xml
    -@@ -238,7 +238,7 @@
    -     <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"ຂໍ້​ມູນ 4G ຢຸດ​ຊົ່ວ​ຄາວແລ້ວ"</string>
    -     <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"ຂໍ້​ມູນເຊວ​ລູ​ລາຢຸດ​ຊົ່ວ​ຄາວແລ້ວ"</string>
    -     <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"ຂໍ້​ມູນ​ຢຸດ​ຊົ່ວ​ຄາວແລ້ວ"</string>
    --    <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"ເນື່ອງ​ຈາກວ່າ​ຮອດ​ຂີດ​ຈຳ​ກັດ​ຂໍ້​ມູນ​ທີ່​ຕັ້ງ​ໄວ້​ຂອ​ງ​ທ່ານ​ແລ້ວ, ອຸ​ປະ​ກອນ​ຢຸດ​ການ​ນຳ​ໃຊ້​ຂໍ້​ມູນ​ສຳ​ລັບ​ສ່ວນ​ທີ່​ຍັງ​ເຫຼືອ​ຂອງ​ຮອບ​ວຽນ​ນີ້.\n\nການ​ເລີ່ມ​ຕໍ່​ອາດ​ຈະ​ນຳ​ໄປ​ສູ່​ການ​ປ່ຽນ​ແປງ​ຈາກ​ຜູ້​ໃຫ້​ບໍ​ລິ​ການ​ເຄືອ​ຂ່າຍ​ຂອງ​ທ່ານ."</string>
    -+    <string name="data_usage_disabled_dialog" msgid="1841738975235283398">"ທ່ານໃຊ້ອິນເຕີເນັດຮອດຈຳນວນທີ່ທ່ານຈຳກັດປະລິມານໄວ້ແລ້ວ. ທ່ານຈະບໍ່ນຳໃຊ້ການເຊື່ອມຕໍ່ຜ່ານເຄືອຂ່າຍມືຖືອີກຕໍ່ໄປ.\n\nຫາກທ່ານສືບຕໍ່ໃຊ້ໄປອີກ, ທ່ານອາດຖືກຮຽກເກັບເງິນຄ່າບໍລິການໄດ້."</string>
    -     <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"ເລີ່ມຕໍ່"</string>
    -     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"ບໍ່ມີການເຊື່ອມຕໍ່ອິນເຕີເນັດ"</string>
    -     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"ເຊື່ອມ​ຕໍ່ Wi-​-Fi ແລ້ວ"</string>
    -@@ -404,6 +404,7 @@
    -     <string name="device_owned_footer" msgid="3802752663326030053">"ອຸ​ປະ​ກອນ​ອາດ​ມີ​ການ​ເຝົ້າ​ຕິດ​ຕາມ"</string>
    -     <string name="profile_owned_footer" msgid="8021888108553696069">"ໂປຣ​ໄຟລ໌​ອາດ​ຖືກ​ເຝົ້າ​ຕິດ​ຕາມ​ຢູ່"</string>
    -     <string name="vpn_footer" msgid="2388611096129106812">"​ເຄືອ​ຂ່າຍ​ອາດ​ມີ​ການ​ເຝົ້າ​ຕິດ​ຕາມ"</string>
    -+    <string name="branded_vpn_footer" msgid="2168111859226496230">"ການນຳໃຊ້ເຄືອຂ່າຍອາດມີການກວດສອບຕິດຕາມ"</string>
    -     <string name="monitoring_title_device_owned" msgid="7121079311903859610">"ການກວດ​ສອບ​ຕິດ​ຕາມ​ອຸ​ປະ​ກອນ"</string>
    -     <string name="monitoring_title_profile_owned" msgid="6790109874733501487">"ການ​ຕິດ​ຕາມ​ໂປຣ​ໄຟລ໌"</string>
    -     <string name="monitoring_title" msgid="169206259253048106">"ການກວດ​ສອບ​ຕິດ​ຕາມ​ເຄືອ​ຂ່າຍ"</string>
    -@@ -416,6 +417,7 @@
    -     <string name="legacy_vpn_name" msgid="6604123105765737830">"VPN"</string>
    -     <string name="monitoring_description_app" msgid="6259179342284742878">"ທ່ານເຊື່ອມຕໍ່ກັບ <xliff:g id="APPLICATION">%1$s</xliff:g>, ເຊິ່ງສາມາດຕິດຕາມການເຄື່ອນໄຫວເຄືອຂ່າຍຂອງທ່ານ ລວມທັງອີເມວ, ​ແອັບ ແລະເວັບໄຊທ໌."</string>
    -     <string name="monitoring_description_app_personal" msgid="484599052118316268">"ທ່ານເຊື່ອມຕໍ່ກັບ <xliff:g id="APPLICATION">%1$s</xliff:g>, ເຊິ່ງສາມາດຕິດຕາມການເຄື່ອນໄຫວເຄືອຂ່າຍສ່ວນຕົວຂອງທ່ານ ລວມທັງອີເມວ, ​ແອັບ ແລະເວັບໄຊທ໌."</string>
    -+    <string name="branded_monitoring_description_app_personal" msgid="2669518213949202599">"ທ່ານເຊື່ອມຕໍ່ກັບ <xliff:g id="APPLICATION">%1$s</xliff:g> ແລ້ວ, ເຊິ່ງສາມາດຕິດຕາມການເຄື່ອນໄຫວເຄືອຂ່າຍສ່ວນຕົວຂອງທ່ານ ຮວມທັງອີເມວ, ​ແອັບ ແລະເວັບໄຊໄດ້."</string>
    -     <string name="monitoring_description_app_work" msgid="1754325860918060897">"ໂປຣໄຟລ໌ບ່ອນເຮັດວຽກຂອງທ່ານຖືກຄວບຄຸມໂດຍ <xliff:g id="ORGANIZATION">%1$s</xliff:g>. ມັນຖືກເຊື່ອມຕໍ່ກັບ <xliff:g id="APPLICATION">%2$s</xliff:g>, ເຊິ່ງສາມາດຕິດຕາມການເຄື່ອນໄຫວເຄືອຂ່າຍບ່ອນເຮັດວຽກຂອງທ່ານ ລວມທັງອີເມວ,​ ແອັບ ແລະເວັບໄຊທ໌.\n\nສຳລັບຂໍ້ມູນເພີ່ມເຕີມ, ໃຫ້ຕິດຕໍ່ຜູ້ບໍລິຫານຂອງທ່ານ."</string>
    -     <string name="monitoring_description_app_personal_work" msgid="4946600443852045903">"ໂປຣໄຟລ໌ບ່ອນເຮັດວຽກຂອງທ່ານຖືກຈັດການໂດຍ <xliff:g id="ORGANIZATION">%1$s</xliff:g>. ມັນເຊື່ອມຕໍ່ກັບ <xliff:g id="APPLICATION_WORK">%2$s</xliff:g>, ເຊິ່ງສາມາດຕິດຕາມການເຄື່ອນໄຫວເຄືອຂ່າຍບ່ອນເຮັດວຽກຂອງທ່ານ ລວມທັງອີເມວ, ແອັບ ແລະເວັບໄຊທ໌.\n\nທ່ານເຊື່ອມຕໍ່ກັບ <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g>, ເຊິ່ງສາມາດຕິດຕາມການເຄື່ອນໄຫວເຄືອຂ່າຍສ່ວນຕົວຂອງທ່ານ."</string>
    -     <string name="monitoring_description_vpn_app_device_owned" msgid="4970443827043261703">"ອຸ​ປະ​ກອນ​ຂອງ​ທ່ານ​ຖືກ​ຄຸ້ມ​ຄອງ​ໂດຍ <xliff:g id="ORGANIZATION">%1$s</xliff:g>.\n\nຜູ້​ຄວບ​ຄຸມຂອງ​ທ່ານ​ສາ​ມາດ​ຕິດ​ຕາມ​ກວດ​ກາ ​ແລະ​ການ​ຄຸ້ມ​ຄອງ​ການຕັ້ງ​ຄ່າ, ແອັບ​ການ​ເຂົ້າ​ຫາ​ບໍ​ລິ​ສັດ, ຂໍ້​ມູນ​ທີ່​ກ່ຽວ​ຂ້ອງ​ກັບ​ອຸ​ປະ​ກອນ​ຂອງ​ທ່ານ, ແລະ​ຂໍ້​ມູນທີ່​ຕັ້ງ​ຂອງອຸ​ປະ​ກອນ​ຂອງ​ທ່ານ.\n\nທ່ານ​ເຊື່ອມ​ຕໍ່​ກັບ <xliff:g id="APPLICATION">%2$s</xliff:g> ແລ້ວ, ເຊິ່ງ​ສາ​ມາດ​ຕິດ​ຕາມການ​ເຄື່ອນ​ໄຫວ​ເຄືອ​ຂ່າຍ​ຂອງ​ທ່ານ, ລວມ​ທັງ​ອີ​ເມວ, ແອັບ, ແລະ​ເວັບ​ໄຊ​ທ໌.\n\nສຳ​ລັບ​ຂໍ້​ມູນ​ເພີ່ມ​ເຕີມ, ຕິດ​ຕໍ່​ຜູ້​ຄວບ​ຄຸມ​ຂອງ​ທ່ານ."</string>
    -@@ -492,8 +494,6 @@
    -     <string name="clock_seconds_desc" msgid="6282693067130470675">"ສະ​ແດງວິ​ນາ​ທີ​ໂມງ​ຢູ່​ໃນ​ແຖບ​ສະ​ຖາ​ນະ. ອາດ​ຈະ​ມີ​ຜົນ​ກະ​ທົບ​ຕໍ່​ອາ​ຍຸ​ແບັດ​ເຕີ​ຣີ."</string>
    -     <string name="qs_rearrange" msgid="8060918697551068765">"ຈັດ​ວາງ​ການ​ຕັ້ງ​ຄ່າ​ດ່ວນ​ຄືນ​ໃໝ່"</string>
    -     <string name="show_brightness" msgid="6613930842805942519">"ສະ​ແດງ​ຄວາມ​ແຈ້ງ​ຢູ່​ໃນ​ການ​ຕັ້ງ​ຄ່າ​ດ່ວນ"</string>
    --    <string name="overview_nav_bar_gesture" msgid="8579814204727917764">"ເປີດໃຊ້ທ່າທາງການປັດຂຶ້ນເພື່ອເຂົ້າສູ່ໜ້າຈໍແບບແຍກກັນ"</string>
    --    <string name="overview_nav_bar_gesture_desc" msgid="6329167382305102615">"ເປີດໃຊ້ທ່າທາງເພື່ອເຂົ້າສູ່ໜ້າຈໍແບບແຍກກັນ ໂດຍການປັດຂຶ້ນຈາກປຸ່ມພາບຮວມ"</string>
    -     <string name="experimental" msgid="6198182315536726162">"ຍັງຢູ່ໃນການທົດລອງ"</string>
    -     <string name="enable_bluetooth_title" msgid="5027037706500635269">"ເປີດ​ໃຊ້ Bluetooth ບໍ່?"</string>
    -     <string name="enable_bluetooth_message" msgid="9106595990708985385">"ເພື່ອ​ເຊື່ອມ​ຕໍ່​ແປ້ນ​ພິມ​ຂອງ​ທ່ານ​ກັບ​ແທັບ​ເລັດ​ຂອງ​ທ່ານ, ກ່ອນ​ອື່ນ​ໝົດ​ທ່ານ​ຕ້ອງ​ເປີດ Bluetooth."</string>
    -@@ -651,4 +651,5 @@
    -     <string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"ເປີດການຕັ້ງຄ່າ <xliff:g id="ID_1">%s</xliff:g>."</string>
    -     <string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"ແກ້ໄຂລຳດັບການຕັ້ງຄ່າ."</string>
    -     <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"<xliff:g id="ID_1">%1$d</xliff:g> ຈາກທັງໝົດ <xliff:g id="ID_2">%2$d</xliff:g>"</string>
    -+    <string name="cant_silence_or_block" msgid="999689262131488625">"ບໍ່ສາມາດປິດສຽງ ຫຼື ບລັອກການແຈ້ງເຕືອນໄດ້"</string>
    - </resources>
    -diff --git a/packages/SystemUI/res/values-lt/strings.xml b/packages/SystemUI/res/values-lt/strings.xml
    -index 46e50fb..480d88a 100644
    ---- a/packages/SystemUI/res/values-lt/strings.xml
    -+++ b/packages/SystemUI/res/values-lt/strings.xml
    -@@ -240,7 +240,7 @@
    -     <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"4G duomenys pristabdyti"</string>
    -     <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"Korinio ryšio duomenys pristabdyti"</string>
    -     <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"Duomenys pristabdyti"</string>
    --    <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"Kadangi buvo pasiektas nustatytas duomenų limitas, įrenginys pristabdė duomenų naudojimą likusį šio ciklo laikotarpį.\n\nAtnaujinus gali būti taikomi operatoriaus mokesčiai."</string>
    -+    <string name="data_usage_disabled_dialog" msgid="1841738975235283398">"Pasiektas nustatytas duomenų apribojimas. Nebenaudojate mobiliojo ryšio duomenų.\n\nJei atnaujinsite, gali būti taikomi mokesčiai už duomenų naudojimą."</string>
    -     <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"Atnaujinti"</string>
    -     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Nėra interneto ryš."</string>
    -     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Prisij. prie „Wi-Fi“"</string>
    -@@ -275,10 +275,10 @@
    -     <string name="quick_settings_bluetooth_off_label" msgid="8159652146149219937">"„Bluetooth“ išjungta"</string>
    -     <string name="quick_settings_bluetooth_detail_empty_text" msgid="4910015762433302860">"Nėra pasiekiamų susietų įrenginių"</string>
    -     <string name="quick_settings_brightness_label" msgid="6968372297018755815">"Šviesumas"</string>
    --    <string name="quick_settings_rotation_unlocked_label" msgid="7305323031808150099">"Automatinis kaitaliojimas"</string>
    -+    <string name="quick_settings_rotation_unlocked_label" msgid="7305323031808150099">"Automatinis pasukimas"</string>
    -     <string name="accessibility_quick_settings_rotation" msgid="4231661040698488779">"Automatiškai sukti ekraną"</string>
    -     <string name="accessibility_quick_settings_rotation_value" msgid="1428962304214992318">"Nustatyti kaip <xliff:g id="ID_1">%s</xliff:g>"</string>
    --    <string name="quick_settings_rotation_locked_label" msgid="6359205706154282377">"Kaitaliojimas užrakintas"</string>
    -+    <string name="quick_settings_rotation_locked_label" msgid="6359205706154282377">"Pasukimas užrakintas"</string>
    -     <string name="quick_settings_rotation_locked_portrait_label" msgid="5102691921442135053">"Stačias"</string>
    -     <string name="quick_settings_rotation_locked_landscape_label" msgid="8553157770061178719">"Gulsčias"</string>
    -     <string name="quick_settings_ime_label" msgid="7073463064369468429">"Įvesties metodas"</string>
    -@@ -408,6 +408,7 @@
    -     <string name="device_owned_footer" msgid="3802752663326030053">"Įrenginys gali būti stebimas"</string>
    -     <string name="profile_owned_footer" msgid="8021888108553696069">"Profilis gali būti stebimas"</string>
    -     <string name="vpn_footer" msgid="2388611096129106812">"Tinklas gali būti stebimas"</string>
    -+    <string name="branded_vpn_footer" msgid="2168111859226496230">"Tinklas gali būti stebimas"</string>
    -     <string name="monitoring_title_device_owned" msgid="7121079311903859610">"Įrenginio stebėjimas"</string>
    -     <string name="monitoring_title_profile_owned" msgid="6790109874733501487">"Profilio stebėjimas"</string>
    -     <string name="monitoring_title" msgid="169206259253048106">"Tinklo stebėjimas"</string>
    -@@ -420,6 +421,7 @@
    -     <string name="legacy_vpn_name" msgid="6604123105765737830">"VPN"</string>
    -     <string name="monitoring_description_app" msgid="6259179342284742878">"Esate prisijungę prie programos „<xliff:g id="APPLICATION">%1$s</xliff:g>“, kuri gali stebėti tinklo veiklą, įskaitant el. laiškus, programas ir svetaines."</string>
    -     <string name="monitoring_description_app_personal" msgid="484599052118316268">"Esate prisijungę prie programos „<xliff:g id="APPLICATION">%1$s</xliff:g>“, kuri gali stebėti asmeninio profilio tinklo veiklą, įskaitant el. laiškus, programas ir svetaines."</string>
    -+    <string name="branded_monitoring_description_app_personal" msgid="2669518213949202599">"Esate prisijungę prie programos „<xliff:g id="APPLICATION">%1$s</xliff:g>“, kuri gali stebėti asmeninio tinklo veiklą, įskaitant el. laiškus, programas ir svetaines."</string>
    -     <string name="monitoring_description_app_work" msgid="1754325860918060897">"Darbo profilį tvarko „<xliff:g id="ORGANIZATION">%1$s</xliff:g>“. Jis susietas su programa „<xliff:g id="APPLICATION">%2$s</xliff:g>“, kuri gali stebėti darbo profilio tinklo veiklą, įskaitant el. laiškus, programas ir svetaines.\n\nDaugiau informacijos galite gauti susisiekę su administratoriumi."</string>
    -     <string name="monitoring_description_app_personal_work" msgid="4946600443852045903">"Darbo profilį tvarko „<xliff:g id="ORGANIZATION">%1$s</xliff:g>“. Jis susietas su programa „<xliff:g id="APPLICATION_WORK">%2$s</xliff:g>“, kuri gali stebėti darbo profilio tinklo veiklą, įskaitant el. laiškus, programas ir svetaines.\n\nTaip pat esate prisijungę prie programos „<xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g>“, kuri gali stebėti asmeninio profilio tinklo veiklą."</string>
    -     <string name="monitoring_description_vpn_app_device_owned" msgid="4970443827043261703">"Jūsų įrenginį tvarko „<xliff:g id="ORGANIZATION">%1$s</xliff:g>“.\n\nAdministratorius gali stebėti ir tvarkyti nustatymus, įmonės informacijos pasiekiamumo nustatymus, programas, su įrenginiu susietus duomenis ir įrenginio vietovės informaciją.\n\nEsate prisijungę prie programos „<xliff:g id="APPLICATION">%2$s</xliff:g>“, kuri gali stebėti tinklo veiklą, įskaitant el. laiškus, programas ir svetaines.\n\nDaugiau informacijos galite gauti susisiekę su administratoriumi."</string>
    -@@ -496,8 +498,6 @@
    -     <string name="clock_seconds_desc" msgid="6282693067130470675">"Rodyti laikrodžio sekundes būsenos juostoje. Tai gali paveikti akumuliatoriaus naudojimo laiką."</string>
    -     <string name="qs_rearrange" msgid="8060918697551068765">"Pertvarkyti sparčiuosius nustatymus"</string>
    -     <string name="show_brightness" msgid="6613930842805942519">"Rodyti skaistį sparčiuosiuose nustatymuose"</string>
    --    <string name="overview_nav_bar_gesture" msgid="8579814204727917764">"Įgalinti ekrano skaidymo perbraukimo aukštyn gestą"</string>
    --    <string name="overview_nav_bar_gesture_desc" msgid="6329167382305102615">"Įgalinti gestą, kuriuo galima įjungti skaidytą ekraną, perbraukiant aukštyn nuo apžvalgos mygtuko"</string>
    -     <string name="experimental" msgid="6198182315536726162">"Eksperimentinė versija"</string>
    -     <string name="enable_bluetooth_title" msgid="5027037706500635269">"Įjungti „Bluetooth“?"</string>
    -     <string name="enable_bluetooth_message" msgid="9106595990708985385">"Kad galėtumėte prijungti klaviatūrą prie planšetinio kompiuterio, pirmiausia turite įjungti „Bluetooth“."</string>
    -@@ -655,4 +655,5 @@
    -     <string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"Atidaryti „<xliff:g id="ID_1">%s</xliff:g>“ nustatymus."</string>
    -     <string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"Redaguoti nustatymų tvarką."</string>
    -     <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"<xliff:g id="ID_1">%1$d</xliff:g> psl. iš <xliff:g id="ID_2">%2$d</xliff:g>"</string>
    -+    <string name="cant_silence_or_block" msgid="999689262131488625">"Pranešimų negalima nutildyti arba užblokuoti"</string>
    - </resources>
    -diff --git a/packages/SystemUI/res/values-lv/strings.xml b/packages/SystemUI/res/values-lv/strings.xml
    -index 9efad2e..564a29c 100644
    ---- a/packages/SystemUI/res/values-lv/strings.xml
    -+++ b/packages/SystemUI/res/values-lv/strings.xml
    -@@ -239,7 +239,7 @@
    -     <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"4G datu lietojums ir apturēts"</string>
    -     <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"Mobilo datu lietojums ir apturēts"</string>
    -     <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"Datu lietojums ir apturēts"</string>
    --    <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"Tika sasniegts iestatītais datu lietojuma ierobežojums, tādēļ ierīcē ir apturēts datu lietojums cikla atlikušajā periodā.\n\nJa atsāksiet lietot datus, iespējams, jūsu mobilo sakaru operators iekasēs maksu."</string>
    -+    <string name="data_usage_disabled_dialog" msgid="1841738975235283398">"Ir sasniegts jūsu iestatītais datu ierobežojums. Jūs vairs neizmantojat mobilos datus.\n\nJa atsāksiet, var tikt piemērota maksa par datu lietojumu."</string>
    -     <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"Atsākt"</string>
    -     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Nav interneta sav."</string>
    -     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Izv. sav. ar Wi-Fi"</string>
    -@@ -406,6 +406,7 @@
    -     <string name="device_owned_footer" msgid="3802752663326030053">"Ierīci var pārraudzīt"</string>
    -     <string name="profile_owned_footer" msgid="8021888108553696069">"Profilu var pārraudzīt"</string>
    -     <string name="vpn_footer" msgid="2388611096129106812">"Iespējams, tīklā veiktās darbības tiek pārraudzītas."</string>
    -+    <string name="branded_vpn_footer" msgid="2168111859226496230">"Var tikt pārraudzītas tīklā veiktās darbības."</string>
    -     <string name="monitoring_title_device_owned" msgid="7121079311903859610">"Ierīces pārraudzība"</string>
    -     <string name="monitoring_title_profile_owned" msgid="6790109874733501487">"Profila pārraudzība"</string>
    -     <string name="monitoring_title" msgid="169206259253048106">"Tīkla pārraudzība"</string>
    -@@ -418,6 +419,7 @@
    -     <string name="legacy_vpn_name" msgid="6604123105765737830">"VPN"</string>
    -     <string name="monitoring_description_app" msgid="6259179342284742878">"Ir izveidots savienojums ar lietotni <xliff:g id="APPLICATION">%1$s</xliff:g>, kura var pārraudzīt jūsu tīklā veiktās darbības, tostarp e-pasta ziņojumus, lietotnes un vietnes."</string>
    -     <string name="monitoring_description_app_personal" msgid="484599052118316268">"Ir izveidots savienojums ar lietotni <xliff:g id="APPLICATION">%1$s</xliff:g>, kura var pārraudzīt jūsu tīklā veiktās privātās darbības, tostarp e-pasta ziņojumus, lietotnes un vietnes."</string>
    -+    <string name="branded_monitoring_description_app_personal" msgid="2669518213949202599">"Ir izveidots savienojums ar lietotni <xliff:g id="APPLICATION">%1$s</xliff:g>, kas var pārraudzīt jūsu tīklā veiktās privātās darbības, tostarp e-pasta ziņojumus, lietotnes un vietnes."</string>
    -     <string name="monitoring_description_app_work" msgid="1754325860918060897">"Jūsu darba profilu pārvalda <xliff:g id="ORGANIZATION">%1$s</xliff:g>. Tas ir saistīts ar lietojumprogrammu <xliff:g id="APPLICATION">%2$s</xliff:g>, kura var pārraudzīt jūsu tīklā veiktās darbības, tostarp e-pasta ziņojumus, lietotnes un vietnes.\n\nLai iegūtu plašāku informāciju, sazinieties ar administratoru."</string>
    -     <string name="monitoring_description_app_personal_work" msgid="4946600443852045903">"Jūsu darba profilu pārvalda <xliff:g id="ORGANIZATION">%1$s</xliff:g>. Tas ir saistīts ar lietojumprogrammu <xliff:g id="APPLICATION_WORK">%2$s</xliff:g>, kura var pārraudzīt jūsu tīklā veiktās darbības, tostarp e-pasta ziņojumus, lietotnes un vietnes.\n\nIr piesaistīta arī lietojumprogramma <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g>, kas var pārraudzīt jūsu tīklā veiktās privātās darbības."</string>
    -     <string name="monitoring_description_vpn_app_device_owned" msgid="4970443827043261703">"Jūsu ierīci pārvalda <xliff:g id="ORGANIZATION">%1$s</xliff:g>.\n\nJūsu administrators var pārraudzīt un pārvaldīt iestatījumus, korporatīvo piekļuvi, lietotnes un datus, kas ir saistīti ar šo ierīci, kā arī informāciju par jūsu ierīces atrašanās vietu.\n\nIr piesaistīta lietojumprogramma <xliff:g id="APPLICATION">%2$s</xliff:g>, kas var pārraudzīt jūsu tīklā veiktās darbības, tostarp e-pasta ziņojumus, lietotnes un vietnes.\n\nLai iegūtu plašāku informāciju, sazinieties ar administratoru."</string>
    -@@ -494,8 +496,6 @@
    -     <string name="clock_seconds_desc" msgid="6282693067130470675">"Statusa joslā rādīt pulksteņa sekundes. Var ietekmēt akumulatora darbības laiku."</string>
    -     <string name="qs_rearrange" msgid="8060918697551068765">"Pārkārtot ātros iestatījumus"</string>
    -     <string name="show_brightness" msgid="6613930842805942519">"Rādīt spilgtumu ātrajos iestatījumos"</string>
    --    <string name="overview_nav_bar_gesture" msgid="8579814204727917764">"Iespējot vilkšanu augšup, lai sadalītu ekrānu"</string>
    --    <string name="overview_nav_bar_gesture_desc" msgid="6329167382305102615">"Iespējot žestu ekrāna sadalīšanai, velkot augšup no pogas Pārskats"</string>
    -     <string name="experimental" msgid="6198182315536726162">"Eksperimentāli"</string>
    -     <string name="enable_bluetooth_title" msgid="5027037706500635269">"Vai ieslēgt Bluetooth savienojumu?"</string>
    -     <string name="enable_bluetooth_message" msgid="9106595990708985385">"Lai pievienotu tastatūru planšetdatoram, vispirms ir jāieslēdz Bluetooth savienojums."</string>
    -@@ -653,4 +653,5 @@
    -     <string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"Atvērt <xliff:g id="ID_1">%s</xliff:g> iestatījumus."</string>
    -     <string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"Rediģēt iestatījumu secību."</string>
    -     <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"<xliff:g id="ID_1">%1$d</xliff:g>. lpp. no <xliff:g id="ID_2">%2$d</xliff:g>"</string>
    -+    <string name="cant_silence_or_block" msgid="999689262131488625">"Nevar izslēgt paziņojumu signālu vai tos bloķēt"</string>
    - </resources>
    -diff --git a/packages/SystemUI/res/values-mk-rMK/strings.xml b/packages/SystemUI/res/values-mk-rMK/strings.xml
    -index 549543d..602fdc9 100644
    ---- a/packages/SystemUI/res/values-mk-rMK/strings.xml
    -+++ b/packages/SystemUI/res/values-mk-rMK/strings.xml
    -@@ -238,7 +238,7 @@
    -     <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"Податоците 4G се паузирани"</string>
    -     <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"Мобилните податоци се паузирани"</string>
    -     <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"Податоците се паузирани"</string>
    --    <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"Поради тоа што го достигнавте поставеното ограничување на податоци, уредот го паузираше користењето податоци до крајот на циклусот.\n\nОператорот може да ви наплати ако продолжите."</string>
    -+    <string name="data_usage_disabled_dialog" msgid="1841738975235283398">"Го достигнавте ограничувањето за сообраќај на податоци што сте го поставиле. Веќе не користите мобилен интернет.\n\nДоколку продолжите, ќе ви биде наплатено за потрошениот сообраќај."</string>
    -     <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"Продолжи"</string>
    -     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Нема интернет"</string>
    -     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Поврзано на Wi-Fi"</string>
    -@@ -404,6 +404,7 @@
    -     <string name="device_owned_footer" msgid="3802752663326030053">"Уредот може да се следи"</string>
    -     <string name="profile_owned_footer" msgid="8021888108553696069">"Профилот можеби се следи"</string>
    -     <string name="vpn_footer" msgid="2388611096129106812">"Мрежата може да се следи"</string>
    -+    <string name="branded_vpn_footer" msgid="2168111859226496230">"Мрежата може да се следи"</string>
    -     <string name="monitoring_title_device_owned" msgid="7121079311903859610">"Следење на уредот"</string>
    -     <string name="monitoring_title_profile_owned" msgid="6790109874733501487">"Следење профил"</string>
    -     <string name="monitoring_title" msgid="169206259253048106">"Следење на мрежата"</string>
    -@@ -416,6 +417,7 @@
    -     <string name="legacy_vpn_name" msgid="6604123105765737830">"ВПН"</string>
    -     <string name="monitoring_description_app" msgid="6259179342284742878">"Поврзани сте на <xliff:g id="APPLICATION">%1$s</xliff:g>, којашто може да ја следи вашата активност на мрежата, вклучувајќи ги е-пораките, апликациите и веб-локациите."</string>
    -     <string name="monitoring_description_app_personal" msgid="484599052118316268">"Поврзани сте на <xliff:g id="APPLICATION">%1$s</xliff:g>, којашто може да ја следи вашата лична активност на мрежата, вклучувајќи ги е-пораките, апликациите и веб-локациите."</string>
    -+    <string name="branded_monitoring_description_app_personal" msgid="2669518213949202599">"Поврзани сте на <xliff:g id="APPLICATION">%1$s</xliff:g>, којашто може да ја следи вашата лична активност на мрежата, вклучувајќи ги е-пораките, апликациите и веб-локациите."</string>
    -     <string name="monitoring_description_app_work" msgid="1754325860918060897">"<xliff:g id="ORGANIZATION">%1$s</xliff:g> управува со вашиот работен профил. Истиот е поврзан на <xliff:g id="APPLICATION">%2$s</xliff:g>, којашто може да ја следи вашата работна активност на мрежата, вклучувајќи ги е-пораките, апликациите и веб-локациите.\n\nЗа повеќе информации, контактирајте со администраторот."</string>
    -     <string name="monitoring_description_app_personal_work" msgid="4946600443852045903">"<xliff:g id="ORGANIZATION">%1$s</xliff:g> управува со вашиот работен профил. Истиот е поврзан на <xliff:g id="APPLICATION_WORK">%2$s</xliff:g>, којашто може да ја следи вашата работна активност на мрежата, вклучувајќи ги е-пораките, апликациите и веб-локациите.\n\nВие исто така сте поврзани на <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g>, којашто може да ја следи вашата лична активност на мрежата."</string>
    -     <string name="monitoring_description_vpn_app_device_owned" msgid="4970443827043261703">"<xliff:g id="ORGANIZATION">%1$s</xliff:g> управува со вашиот уред.\n\nВашиот администратор може да ги следи и да управува со параметрите, корпоративниот пристап, апликациите, податоците поврзани со уредот и информациите за локацијата на уредот.\n\nПоврзани сте на <xliff:g id="APPLICATION">%2$s</xliff:g>, којашто може да ја следи вашата активност на мрежата, вклучувајќи ги е-пораките, апликациите и веб-локациите.\n\nЗа повеќе информации, контактирајте со администраторот."</string>
    -@@ -492,8 +494,6 @@
    -     <string name="clock_seconds_desc" msgid="6282693067130470675">"Прикажи ги секундите на часовникот на статусната лента. Може да влијае на траењето на батеријата."</string>
    -     <string name="qs_rearrange" msgid="8060918697551068765">"Преуредете ги Брзи поставки"</string>
    -     <string name="show_brightness" msgid="6613930842805942519">"Прикажете ја осветленоста во Брзи поставки"</string>
    --    <string name="overview_nav_bar_gesture" msgid="8579814204727917764">"Овозможи го гестот повлекување нагоре за поделен екран"</string>
    --    <string name="overview_nav_bar_gesture_desc" msgid="6329167382305102615">"Овозможете гест за отворање поделен екран со повлекување нагоре од копчето Краток преглед"</string>
    -     <string name="experimental" msgid="6198182315536726162">"Експериментално"</string>
    -     <string name="enable_bluetooth_title" msgid="5027037706500635269">"Да се вклучи Bluetooth?"</string>
    -     <string name="enable_bluetooth_message" msgid="9106595990708985385">"За да ја поврзете тастатурата со таблетот, најпрво треба да вклучите Bluetooth."</string>
    -@@ -651,4 +651,5 @@
    -     <string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"Отворете ги поставките на <xliff:g id="ID_1">%s</xliff:g>."</string>
    -     <string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"Уредете го редоследот на поставките."</string>
    -     <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"Страница <xliff:g id="ID_1">%1$d</xliff:g> од <xliff:g id="ID_2">%2$d</xliff:g>"</string>
    -+    <string name="cant_silence_or_block" msgid="999689262131488625">"Известувања не може да се стишат или блокираат"</string>
    - </resources>
    -diff --git a/packages/SystemUI/res/values-ml-rIN/strings.xml b/packages/SystemUI/res/values-ml-rIN/strings.xml
    -index 9f596b8..ddabf90 100644
    ---- a/packages/SystemUI/res/values-ml-rIN/strings.xml
    -+++ b/packages/SystemUI/res/values-ml-rIN/strings.xml
    -@@ -238,7 +238,7 @@
    -     <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"4G ഡാറ്റ താൽക്കാലികമായി നിർത്തി"</string>
    -     <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"സെല്ലുലാർ ഡാറ്റ താൽക്കാലികമായി നിർത്തി"</string>
    -     <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"ഡാറ്റ താൽക്കാലികമായി നിർത്തി"</string>
    --    <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"നിങ്ങൾ നേരത്തെ ക്രമീകരിച്ച ഡാറ്റ പരിധിയിലെത്തിയതിനാൽ, ഈ സൈക്കിളിന്റെ അവശേഷിക്കുന്ന ഡാറ്റ ഉപയോഗം, ഉപകരണം താൽക്കാലികമായി നിർത്തി.\n\nപുനരാരംഭിക്കുന്നത്, നിങ്ങളുടെ കാരിയറിൽ നിന്ന് നിരക്കുകൾക്ക് ഇടയാക്കാം."</string>
    -+    <string name="data_usage_disabled_dialog" msgid="1841738975235283398">"നിങ്ങൾ സജ്ജമാക്കിയ ഡാറ്റ പരിധി എത്തിക്കഴിഞ്ഞു. ഇനിയങ്ങോട്ട് നിങ്ങൾ സെല്ലുലാർ ഡാറ്റ ഉപയോഗിക്കില്ല.\n\nതുടരുകയാണെങ്കിൽ, ഡാറ്റാ ഉപയോഗത്തിന് നിരക്കുകൾ ബാധകമായേക്കാം."</string>
    -     <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"പുനരാരംഭിക്കുക"</string>
    -     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"ഇന്റർനെറ്റ് കണക്ഷൻ ഇല്ല"</string>
    -     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"വൈഫൈ കണക്‌റ്റുചെയ്‌തു"</string>
    -@@ -404,6 +404,7 @@
    -     <string name="device_owned_footer" msgid="3802752663326030053">"ഉപകരണം നിരീക്ഷിക്കപ്പെടാം"</string>
    -     <string name="profile_owned_footer" msgid="8021888108553696069">"പ്രൊഫൈൽ നിരീക്ഷിക്കപ്പെടാം"</string>
    -     <string name="vpn_footer" msgid="2388611096129106812">"നെറ്റ്‌വർക്ക് നിരീക്ഷിക്കപ്പെടാം"</string>
    -+    <string name="branded_vpn_footer" msgid="2168111859226496230">"നെറ്റ്‌വർക്ക് നിരീക്ഷിക്കപ്പെടാം"</string>
    -     <string name="monitoring_title_device_owned" msgid="7121079311903859610">"ഉപകരണം നിരീക്ഷിക്കൽ"</string>
    -     <string name="monitoring_title_profile_owned" msgid="6790109874733501487">"പ്രൊഫൈൽ നിരീക്ഷിക്കൽ"</string>
    -     <string name="monitoring_title" msgid="169206259253048106">"നെറ്റ്‌വർക്ക് നിരീക്ഷിക്കൽ"</string>
    -@@ -416,6 +417,7 @@
    -     <string name="legacy_vpn_name" msgid="6604123105765737830">"VPN"</string>
    -     <string name="monitoring_description_app" msgid="6259179342284742878">"നിങ്ങൾ <xliff:g id="APPLICATION">%1$s</xliff:g> എന്നതിലേക്ക് കണക്റ്റുചെയ്‌തിരിക്കുന്നു, അതിന് ഇമെയിലുകൾ, ആപ്സ്, വെബ്‌സൈറ്റുകൾ എന്നിവ ഉൾപ്പെടെ നിങ്ങളുടെ നെറ്റ്‌വർക്ക് പ്രവർത്തനം നിരീക്ഷിക്കാനാകും."</string>
    -     <string name="monitoring_description_app_personal" msgid="484599052118316268">"നിങ്ങൾ <xliff:g id="APPLICATION">%1$s</xliff:g> എന്നതിലേക്ക് കണക്റ്റുചെയ്‌തിരിക്കുന്നു, അതിന് ഇമെയിലുകൾ, ആപ്സ്, വെബ്‌സൈറ്റുകൾ എന്നിവ ഉൾപ്പെടെ നിങ്ങളുടെ സ്വകാര്യ നെറ്റ്‌വർക്ക് പ്രവർത്തനം നിരീക്ഷിക്കാനാകും."</string>
    -+    <string name="branded_monitoring_description_app_personal" msgid="2669518213949202599">"നിങ്ങൾ <xliff:g id="APPLICATION">%1$s</xliff:g> ആപ്പിലേക്ക് കണക്റ്റുചെയ്‌തിരിക്കുന്നു, ഇമെയിലുകൾ, ആപ്‌സ്, വെബ്‌സൈറ്റുകൾ എന്നിവ ഉൾപ്പെടെ നെറ്റ്‌വർക്ക് ആക്റ്റിവിറ്റി നിരീക്ഷിക്കാൻ ഈ ആപ്പിന് കഴിയും."</string>
    -     <string name="monitoring_description_app_work" msgid="1754325860918060897">"നിങ്ങളുടെ ഔദ്യോഗിക പ്രൊഫൈൽ നിയന്ത്രിക്കുന്നത് <xliff:g id="ORGANIZATION">%1$s</xliff:g> ആണ്. നിങ്ങൾ <xliff:g id="APPLICATION">%2$s</xliff:g> എന്നതിലേക്ക് കണക്റ്റുചെയ്‌തിരിക്കുന്നു, അതിന് ഇമെയിലുകൾ, ആപ്സ്, വെബ്‌സൈറ്റുകൾ എന്നിവ ഉൾപ്പെടെ നിങ്ങളുടെ ഔദ്യോഗിക നെറ്റ്‌വർക്ക് പ്രവർത്തനം നിരീക്ഷിക്കാനാകും.\n\nകൂടുതൽ വിവരങ്ങൾക്ക്, നിങ്ങളുടെ അഡ്‌മിനിസ്‌ട്രേറ്ററെ ബന്ധപ്പെടുക."</string>
    -     <string name="monitoring_description_app_personal_work" msgid="4946600443852045903">"നിങ്ങളുടെ ഔദ്യോഗിക പ്രൊഫൈൽ നിയന്ത്രിക്കുന്നത് <xliff:g id="ORGANIZATION">%1$s</xliff:g> ആണ്. നിങ്ങൾ <xliff:g id="APPLICATION_WORK">%2$s</xliff:g> എന്നതിലേക്ക് കണക്റ്റുചെയ്‌തിരിക്കുന്നു, അതിന് ഇമെയിലുകൾ, ആപ്സ്, വെബ്‌സൈറ്റുകൾ എന്നിവ ഉൾപ്പെടെ നിങ്ങളുടെ ഔദ്യോഗിക നെറ്റ്‌വർക്ക് പ്രവർത്തനം നിരീക്ഷിക്കാനാകും.\n\nനിങ്ങൾ <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g> എന്നതിലേക്കും കണക്റ്റുചെയ്‌തിരിക്കുന്നു, അതിന് നിങ്ങളുടെ സ്വകാര്യ നെറ്റ്‌വർക്ക് പ്രവർത്തനം നിരീക്ഷിക്കാനാകും."</string>
    -     <string name="monitoring_description_vpn_app_device_owned" msgid="4970443827043261703">"നിങ്ങളുടെ ഉപകരണം നിയന്ത്രിക്കുന്നത് <xliff:g id="ORGANIZATION">%1$s</xliff:g> ആണ്.\n\nനിങ്ങളുടെ അഡ്‌മിനിസ്‌ട്രേറ്റർക്ക്, ഉപകരണവുമായി ബന്ധപ്പെട്ട ക്രമീകരണവും കോർപ്പറേറ്റ് ആക്‌സസ്സും അപ്ലിക്കേഷനുകളും വിവരവും ഒപ്പം ഉപകരണത്തിന്റെ ലൊക്കേഷൻ വിവരവും നിരീക്ഷിച്ച് നിയന്ത്രിക്കാനാകും.\n\nഇമെയിലുകളും അപ്ലിക്കേഷനുകളും വെബ്‌സൈറ്റുകളും ഉൾപ്പെടെയുള്ള നെറ്റ്‌വർക്ക് പ്രവർത്തനം നിരീക്ഷിക്കാനാകുന്ന ഒരു <xliff:g id="APPLICATION">%2$s</xliff:g> എന്നതിലേക്കും നിങ്ങൾ കണക്റ്റുചെയ്തിരിക്കുന്നു.\n\nകൂടുതൽ വിവരങ്ങൾക്ക്, അഡ്‌മിനിസ്ട്രേറ്ററെ ബന്ധപ്പെടുക."</string>
    -@@ -492,8 +494,6 @@
    -     <string name="clock_seconds_desc" msgid="6282693067130470675">"സ്റ്റാറ്റസ് ബാറിൽ ക്ലോക്ക് സെക്കൻഡ് കാണിക്കുന്നത് ബാറ്ററിയുടെ ലൈഫിനെ ബാധിക്കാം."</string>
    -     <string name="qs_rearrange" msgid="8060918697551068765">"ദ്രുത ക്രമീകരണം പുനഃസജ്ജീകരിക്കുക"</string>
    -     <string name="show_brightness" msgid="6613930842805942519">"ദ്രുത ക്രമീകരണത്തിൽ തെളിച്ചം കാണിക്കുക"</string>
    --    <string name="overview_nav_bar_gesture" msgid="8579814204727917764">"സ്പ്ലിറ്റ്-സ്ക്രീൻ സ്വൈപ്പ്-അപ്പ് ജെസ്റ്റർ പ്രവർത്തനക്ഷമമാക്കുക"</string>
    --    <string name="overview_nav_bar_gesture_desc" msgid="6329167382305102615">"ചുരുക്കവിവരണ ബട്ടണിൽ നിന്ന് മുകളിലേക്ക് സ്വൈപ്പുചെയ്തുകൊണ്ട് സ്പ്ലിറ്റ്-സ്ക്രീനിലേക്ക് പ്രവേശിക്കാൻ ജെസ്‌റ്റർ പ്രവർത്തനക്ഷമമാക്കുക"</string>
    -     <string name="experimental" msgid="6198182315536726162">"പരീക്ഷണാത്മകം!"</string>
    -     <string name="enable_bluetooth_title" msgid="5027037706500635269">"Bluetooth ഓണാക്കണോ?"</string>
    -     <string name="enable_bluetooth_message" msgid="9106595990708985385">"നിങ്ങളുടെ ടാബ്‌ലെറ്റുമായി കീബോർഡ് കണക്റ്റുചെയ്യുന്നതിന്, ആദ്യം Bluetooth ഓണാക്കേണ്ടതുണ്ട്."</string>
    -@@ -651,4 +651,5 @@
    -     <string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"<xliff:g id="ID_1">%s</xliff:g> ക്രമീകരണം തുറക്കുക."</string>
    -     <string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"ക്രമീകരണ ക്രമം എഡിറ്റുചെയ്യുക."</string>
    -     <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"പേജ് <xliff:g id="ID_1">%1$d</xliff:g> / <xliff:g id="ID_2">%2$d</xliff:g>"</string>
    -+    <string name="cant_silence_or_block" msgid="999689262131488625">"അറിയിപ്പുകൾ നിശബ്ദമാക്കാനോ ബ്ലോക്കുചെയ്യാനോ കഴിയില്ല"</string>
    - </resources>
    -diff --git a/packages/SystemUI/res/values-mn-rMN/strings.xml b/packages/SystemUI/res/values-mn-rMN/strings.xml
    -index f3a2f08..df9e799 100644
    ---- a/packages/SystemUI/res/values-mn-rMN/strings.xml
    -+++ b/packages/SystemUI/res/values-mn-rMN/strings.xml
    -@@ -236,7 +236,7 @@
    -     <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"4G дата-г түр зогсоосон байна"</string>
    -     <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"Гар утасны дата-г түр зогсоосон байна"</string>
    -     <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"Дата-г түр зогсоосон байна"</string>
    --    <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"Таны багц дата эрхийн дээд хэмжээнд хүрсэн байгаа тул төхөөрөмж нь үлдсэн хэсэгт дата хэрэглээг түр зогсоосон байна.\n\nТа үйлдлийг үргэлжлүүлэхийг хүсвэл үйлчилгээ үзүүлж буй үүрэн холбооны газраас нэмж дата эрх авна уу."</string>
    -+    <string name="data_usage_disabled_dialog" msgid="1841738975235283398">"Таны тогтоосон дата хэмжээний хязгаарт хүрсэн байна. Та одоогоор мобайл датаг ашиглаагүй байна.\n\nҮргэлжлүүлсэн тохиолдолд төлбөр гарах болно."</string>
    -     <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"Үргэлжлүүлэх"</string>
    -     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Интернет холболт байхгүй"</string>
    -     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi холбогдсон"</string>
    -@@ -402,6 +402,7 @@
    -     <string name="device_owned_footer" msgid="3802752663326030053">"Төхөөрөмжийг хянах боломжтой"</string>
    -     <string name="profile_owned_footer" msgid="8021888108553696069">"Профайлыг хянаж байж болзошгүй"</string>
    -     <string name="vpn_footer" msgid="2388611096129106812">"Сүлжээ хянагдаж байж болзошгүй"</string>
    -+    <string name="branded_vpn_footer" msgid="2168111859226496230">"Сүлжээг хянаж байж болзошгүй"</string>
    -     <string name="monitoring_title_device_owned" msgid="7121079311903859610">"Төхөөрөмжийн хяналт"</string>
    -     <string name="monitoring_title_profile_owned" msgid="6790109874733501487">"Профайл хяналт"</string>
    -     <string name="monitoring_title" msgid="169206259253048106">"Сүлжээний хяналт"</string>
    -@@ -414,6 +415,7 @@
    -     <string name="legacy_vpn_name" msgid="6604123105765737830">"VPN"</string>
    -     <string name="monitoring_description_app" msgid="6259179342284742878">"Та <xliff:g id="APPLICATION">%1$s</xliff:g>-д холбогдсон бөгөөд энэ нь таны имэйл, апп, вебсайт зэрэг сүлжээний үйл ажиллагааг хянах боломжтой."</string>
    -     <string name="monitoring_description_app_personal" msgid="484599052118316268">"Та <xliff:g id="APPLICATION">%1$s</xliff:g>-д холбогдсон бөгөөд энэ нь таны имэйл, апп, вебсайт зэрэг сүлжээний хувийн үйл ажиллагааг хянах боломжтой."</string>
    -+    <string name="branded_monitoring_description_app_personal" msgid="2669518213949202599">"Та имэйл, апп, вэб хуудас зэрэг хувийн сүлжээнийхээ үйл ажиллагааг хянах боломжтой <xliff:g id="APPLICATION">%1$s</xliff:g>-д холбогдсон байна."</string>
    -     <string name="monitoring_description_app_work" msgid="1754325860918060897">"Таны ажлын профайлыг <xliff:g id="ORGANIZATION">%1$s</xliff:g> удирддаг. Энэ нь <xliff:g id="APPLICATION">%2$s</xliff:g>-тэй холбогдсон бөгөөд таны  имэйл, апп, вебсайт зэрэг сүлжээний үйл ажиллагааг хянах боломжтой.\n\nДэлгэрэнгүй мэдээлэл авахыг хүсвэл админтайгаа холбогдоно уу."</string>
    -     <string name="monitoring_description_app_personal_work" msgid="4946600443852045903">"Таны ажлын профайлыг <xliff:g id="ORGANIZATION">%1$s</xliff:g> удирддаг. Энэ нь <xliff:g id="APPLICATION_WORK">%2$s</xliff:g>-тай холбогдсон бөгөөд таны имэйл, апп, вебсайт зэрэг ажлын сүлжээний үйл ажиллагааг хянах боломжтой.\n\nМөн та <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g>-д холбогдсон бөгөөд энэ нь таны сүлжээний хувийн үйл ажиллагааг хянаж чадна."</string>
    -     <string name="monitoring_description_vpn_app_device_owned" msgid="4970443827043261703">"Таны төхөөрөмжийг <xliff:g id="ORGANIZATION">%1$s</xliff:g> удирддаг.\n\n Танай админ төхөөрөмж, төхөөрөмжийн байршилтай холбоотой өгөгдлийг холбох, тохиргоог өөрчлөх болон хяналт тавих боломжтой.\n\nТа <xliff:g id="APPLICATION">%2$s</xliff:g>-тай холбогдсон бөгөөд ингэснээр таны имэйл,апп, аюулгүй вебсайт зэрэг сүлжээний үйл ажиллагаагаа хянах боломжтой.\n\n Дэлгэрэнгүй мэдээлэл авахыг хүсвэл админтайгаа холбогдоно уу."</string>
    -@@ -492,8 +494,6 @@
    -     <string name="clock_seconds_desc" msgid="6282693067130470675">"Статус талбарт цагийн секундыг харуулах. Энэ нь тэжээлийн цэнэгт нөлөөлж болно."</string>
    -     <string name="qs_rearrange" msgid="8060918697551068765">"Түргэн тохиргоог дахин засварлах"</string>
    -     <string name="show_brightness" msgid="6613930842805942519">"Түргэн тохиргоонд гэрэлтүүлэг харах"</string>
    --    <string name="overview_nav_bar_gesture" msgid="8579814204727917764">"Дэлгэц хуваах дээш шудрах дохиог идэвхжүүлэх"</string>
    --    <string name="overview_nav_bar_gesture_desc" msgid="6329167382305102615">"Тойм товчлуурыг дээш шударч, хуваагдсан дэлгэцэд зангаагаар орох тохиргоог идэвхжүүлэх"</string>
    -     <string name="experimental" msgid="6198182315536726162">"Туршилтын"</string>
    -     <string name="enable_bluetooth_title" msgid="5027037706500635269">"Bluetooth-г асаах уу?"</string>
    -     <string name="enable_bluetooth_message" msgid="9106595990708985385">"Компьютерийн гараа таблетад холбохын тулд эхлээд Bluetooth-г асаана уу."</string>
    -@@ -505,14 +505,14 @@
    -     <string name="tuner_full_importance_settings" msgid="3207312268609236827">"Тэжээлийн мэдэгдлийн удирдлага"</string>
    -     <string name="tuner_full_importance_settings_on" msgid="7545060756610299966">"Идэвхтэй"</string>
    -     <string name="tuner_full_importance_settings_off" msgid="8208165412614935229">"Идэвхгүй"</string>
    --    <string name="power_notification_controls_description" msgid="4372459941671353358">"Тэжээлийн мэдэгдлийн удирдлагын тусламжтайгаар та апп-н мэдэгдэлд 0-5 хүртэлх ач холбогдлын төвшин тогтоох боломжтой. \n\n"<b>"5-р төвшин"</b>" \n- Мэдэгдлийн жагсаалтын хамгийн дээр харуулна \n- Бүтэн дэлгэцэд саад болно \n- Дэлгэцэд тогтмол гарч ирнэ \n\n"<b>"4-р төвшин"</b>" \n- Бүтэн дэлгэцэд саад болохоос сэргийлнэ \n- Дэлгэцэд тогтмол гарч ирнэ \n\n"<b>"3-р төвшин"</b>" \n- Бүтэн дэлгэцэд саад болохоос сэргийлнэ \n- Дэлгэцэд хэзээ ч гарч ирэхгүй \n\n"<b>"2-р төвшин"</b>" \n- Бүтэн дэлгэцэд саад болохоос сэргийлнэ \n- Дэлгэцэд хэзээ ч гарч ирэхгүй \n- Дуу болон чичиргээ хэзээ ч гаргахгүй \n\n"<b>"1-р төвшин"</b>" \n- Бүтэн дэлгэцэд саад болохоос сэргийлнэ \n- Дэлгэцэд хэзээ ч гарч ирэхгүй \n- Дуу болон чичиргээ хэзээ ч гаргахгүй \n- Түгжигдсэн дэлгэц болон статусын самбараас нууна \n- Мэдэгдлийн жагсаалтын доор харуулна \n\n"<b>"0-р төвшин"</b>" \n- Энэ апп-н бүх мэдэгдлийг блоклоно"</string>
    -+    <string name="power_notification_controls_description" msgid="4372459941671353358">"Тэжээлийн мэдэгдлийн удирдлагын тусламжтайгаар та апп-н мэдэгдэлд 0-5 хүртэлх ач холбогдлын түвшин тогтоох боломжтой. \n\n"<b>"5-р түвшин"</b>" \n- Мэдэгдлийн жагсаалтын хамгийн дээр харуулна \n- Бүтэн дэлгэцэд саад болно \n- Дэлгэцэд тогтмол гарч ирнэ \n\n"<b>"4-р түвшин"</b>" \n- Бүтэн дэлгэцэд саад болохоос сэргийлнэ \n- Дэлгэцэд тогтмол гарч ирнэ \n\n"<b>"3-р түвшин"</b>" \n- Бүтэн дэлгэцэд саад болохоос сэргийлнэ \n- Дэлгэцэд хэзээ ч гарч ирэхгүй \n\n"<b>"2-р түвшин"</b>" \n- Бүтэн дэлгэцэд саад болохоос сэргийлнэ \n- Дэлгэцэд хэзээ ч гарч ирэхгүй \n- Дуу болон чичиргээ хэзээ ч гаргахгүй \n\n"<b>"1-р түвшин"</b>" \n- Бүтэн дэлгэцэд саад болохоос сэргийлнэ \n- Дэлгэцэд хэзээ ч гарч ирэхгүй \n- Дуу болон чичиргээ хэзээ ч гаргахгүй \n- Түгжигдсэн дэлгэц болон статусын самбараас нууна \n- Мэдэгдлийн жагсаалтын доор харуулна \n\n"<b>"0-р түвшин"</b>" \n- Энэ апп-н бүх мэдэгдлийг блоклоно"</string>
    -     <string name="user_unspecified_importance" msgid="361613856933432117">"Ач холбогдол: Автомат"</string>
    --    <string name="blocked_importance" msgid="5035073235408414397">"Ач холбогдол: 0-р төвшин"</string>
    --    <string name="min_importance" msgid="560779348928574878">"Ач холбогдол: 1-р төвшин"</string>
    --    <string name="low_importance" msgid="7571498511534140">"Ач холбогдол: 2-р төвшин"</string>
    --    <string name="default_importance" msgid="7609889614553354702">"Ач холбогдол: 3-р төвшин"</string>
    --    <string name="high_importance" msgid="3441537905162782568">"Ач холбогдол: 4-р төвшин"</string>
    --    <string name="max_importance" msgid="4880179829869865275">"Ач холбогдол: 5-р төвшин"</string>
    -+    <string name="blocked_importance" msgid="5035073235408414397">"Ач холбогдол: 0-р түвшин"</string>
    -+    <string name="min_importance" msgid="560779348928574878">"Ач холбогдол: 1-р түвшин"</string>
    -+    <string name="low_importance" msgid="7571498511534140">"Ач холбогдол: 2-р түвшин"</string>
    -+    <string name="default_importance" msgid="7609889614553354702">"Ач холбогдол: 3-р түвшин"</string>
    -+    <string name="high_importance" msgid="3441537905162782568">"Ач холбогдол: 4-р түвшин"</string>
    -+    <string name="max_importance" msgid="4880179829869865275">"Ач холбогдол: 5-р түвшин"</string>
    -     <string name="notification_importance_user_unspecified" msgid="2868359605125272874">"Апп нь мэдэгдэл бүрийн ач холбогдлыг тодорхойлдог."</string>
    -     <string name="notification_importance_blocked" msgid="4237497046867398057">"Энэ апп-н мэдэгдлийг хэзээ ч бүү харуул."</string>
    -     <string name="notification_importance_min" msgid="7844224511187027155">"Бүтэн дэлгэцэд саадгүй, гарч ирэхгүй, дуугүй, чичиргээгүй. Түгжигдсэн дэлгэц, статусын хэсгээс нуух."</string>
    -@@ -651,4 +651,5 @@
    -     <string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"<xliff:g id="ID_1">%s</xliff:g> тохиргоог нээнэ үү."</string>
    -     <string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"Тохиргооны дарааллыг өөрчилнө үү."</string>
    -     <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"<xliff:g id="ID_2">%2$d</xliff:g>-н <xliff:g id="ID_1">%1$d</xliff:g>-р хуудас"</string>
    -+    <string name="cant_silence_or_block" msgid="999689262131488625">"Мэдэгдлийн дууг хаах, эсвэл блоклох боломжгүй"</string>
    - </resources>
    -diff --git a/packages/SystemUI/res/values-mr-rIN/strings.xml b/packages/SystemUI/res/values-mr-rIN/strings.xml
    -index e5c6410..006b9bb 100644
    ---- a/packages/SystemUI/res/values-mr-rIN/strings.xml
    -+++ b/packages/SystemUI/res/values-mr-rIN/strings.xml
    -@@ -238,7 +238,7 @@
    -     <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"4G डेटास विराम दिला आहे"</string>
    -     <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"सेल्युलर डेटास विराम दिला आहे"</string>
    -     <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"डेटास विराम दिला आहे"</string>
    --    <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"आपली सेट केलेली डेटा मर्यादा गाठल्यामुळे, डिव्हाइसने या चक्राच्या उर्वरित डेटा वापरास विराम दिला आहे.\n\nपुन्हा सुरु करण्यामुळे आपल्या वाहकाकडून शुल्क आकारले जाऊ शकते."</string>
    -+    <string name="data_usage_disabled_dialog" msgid="1841738975235283398">"आपण सेट केलेली डेटा मर्यादा गाठली आहे. आपण यापुढे मोबाइल डेटा वापरणार नाही.\n\nआपण पुन: सुरु केल्यास, डेटा वापरासाठी शुल्क आकारले जाऊ शकतात."</string>
    -     <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"पुन्हा सुरु करा"</string>
    -     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"इंटरनेट कनेक्शन नाही"</string>
    -     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"वाय-फाय कनेक्ट केले"</string>
    -@@ -404,6 +404,7 @@
    -     <string name="device_owned_footer" msgid="3802752663326030053">"डिव्हाइसचे परीक्षण केले जाऊ शकते"</string>
    -     <string name="profile_owned_footer" msgid="8021888108553696069">"प्रोफाईलचे परीक्षण केले जाऊ शकते"</string>
    -     <string name="vpn_footer" msgid="2388611096129106812">"नेटवर्कचे परीक्षण केले जाऊ शकते"</string>
    -+    <string name="branded_vpn_footer" msgid="2168111859226496230">"नेटवर्कचे परीक्षण केले जाऊ शकते"</string>
    -     <string name="monitoring_title_device_owned" msgid="7121079311903859610">"डिव्हाइस परीक्षण"</string>
    -     <string name="monitoring_title_profile_owned" msgid="6790109874733501487">"प्रोफाईल परीक्षण"</string>
    -     <string name="monitoring_title" msgid="169206259253048106">"नेटवर्क परीक्षण"</string>
    -@@ -416,6 +417,7 @@
    -     <string name="legacy_vpn_name" msgid="6604123105765737830">"VPN"</string>
    -     <string name="monitoring_description_app" msgid="6259179342284742878">"आपण <xliff:g id="APPLICATION">%1$s</xliff:g> शी कनेक्‍ट केले आहे, जो ईमेल, अ‍ॅप्स आणि वेबसाइटसह आपल्‍या नेटवर्क क्रियाकलापाचे परीक्षण करू शकतो."</string>
    -     <string name="monitoring_description_app_personal" msgid="484599052118316268">"आपण <xliff:g id="APPLICATION">%1$s</xliff:g> शी कनेक्‍ट केले आहे, जो ईमेल, अ‍ॅप्स आणि वेबसाइटसह आपल्‍या वैयक्तिक नेटवर्क क्रियाकलापाचे परीक्षण करू शकतो."</string>
    -+    <string name="branded_monitoring_description_app_personal" msgid="2669518213949202599">"आपण <xliff:g id="APPLICATION">%1$s</xliff:g> शी कनेक्‍ट केले आहे, जो ईमेल, अ‍ॅप्स आणि वेबसाइटसह आपल्‍या वैयक्तिक नेटवर्क क्रियाकलापाचे परीक्षण करू शकतो."</string>
    -     <string name="monitoring_description_app_work" msgid="1754325860918060897">"आपले कार्य प्रोफाईल <xliff:g id="ORGANIZATION">%1$s</xliff:g> द्वारे व्यवस्थापित केले आहे. ते <xliff:g id="APPLICATION">%2$s</xliff:g> शी कनेक्ट केले आहे, जो ईमेल, अ‍ॅप्स आणि वेबसाइटसह आपल्‍या कार्य नेटवर्क क्रियाकलापाचे परीक्षण करू शकतो.\n\nअधिक माहितीसाठी, आपल्‍या प्रशासकाशी संपर्क साधा."</string>
    -     <string name="monitoring_description_app_personal_work" msgid="4946600443852045903">"आपले कार्य प्रोफाईल <xliff:g id="ORGANIZATION">%1$s</xliff:g> द्वारे व्यवस्थापित केले आहे. ते <xliff:g id="APPLICATION_WORK">%2$s</xliff:g> शी कनेक्ट केले आहे, जे ईमेल, अ‍ॅप्स आणि वेबसाइटसह आपल्‍या कार्य नेटवर्क क्रियाकलापाचे परीक्षण करू शकते.\n\nआपण <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g> शी देखील कनेक्‍ट केले आहे, जे आपल्‍या वैयक्तिक नेटवर्क क्रियाकलापाचे परीक्षण करू शकते."</string>
    -     <string name="monitoring_description_vpn_app_device_owned" msgid="4970443827043261703">"आपले डिव्हाइस <xliff:g id="ORGANIZATION">%1$s</xliff:g> द्वारे व्यवस्थापित केले आहे.\n\nआपला प्रशासक आपल्या डिव्हाइसशी संबद्ध सेटिंग्ज, कॉर्पोरेट प्रवेश, अ‍ॅप्स, डेटा आणि आपल्या डिव्हाइसच्या स्थान माहितीचे परीक्षण करू शकतो आणि व्‍यवस्थापित करू शकतो.\n\nआपण <xliff:g id="APPLICATION">%2$s</xliff:g> शी कनेक्ट केले आहे, जो ईमेल, अ‍ॅप्स आणि वेबसाइटसह आपल्या नेटवर्क क्रियाकलापाचे परीक्षण करू शकतो.\n\nअधिक माहितीसाठी, आपल्या प्रशासकाशी संपर्क साधा."</string>
    -@@ -492,8 +494,6 @@
    -     <string name="clock_seconds_desc" msgid="6282693067130470675">"स्टेटस बारमध्‍ये घड्‍याळ सेकंद दर्शवा. कदाचित बॅटरी आयुष्‍य प्रभावित होऊ शकते."</string>
    -     <string name="qs_rearrange" msgid="8060918697551068765">"द्रुत सेटिंग्जची पुनर्रचना करा"</string>
    -     <string name="show_brightness" msgid="6613930842805942519">"द्रुत सेटिंग्जमध्‍ये चमक दर्शवा"</string>
    --    <string name="overview_nav_bar_gesture" msgid="8579814204727917764">"विभाजित-स्क्रीन स्वाइप-अप जेश्चर सक्षम करा"</string>
    --    <string name="overview_nav_bar_gesture_desc" msgid="6329167382305102615">"विहंगावलोकन बटणावरून वर स्वाइप करून विभाजित-स्क्रीन प्रविष्ट करण्यासाठी जेश्चर सक्षम करा"</string>
    -     <string name="experimental" msgid="6198182315536726162">"प्रायोगिक"</string>
    -     <string name="enable_bluetooth_title" msgid="5027037706500635269">"ब्लूटुथ सुरू करायचे?"</string>
    -     <string name="enable_bluetooth_message" msgid="9106595990708985385">"आपला कीबोर्ड आपल्या टॅब्लेटसह कनेक्ट करण्यासाठी, आपल्याला प्रथम ब्लूटुथ चालू करणे आवश्यक आहे."</string>
    -@@ -651,4 +651,5 @@
    -     <string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"<xliff:g id="ID_1">%s</xliff:g> सेटिंग्ज उघडा."</string>
    -     <string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"सेटिंग्जचा क्रम संपादित करा."</string>
    -     <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"पृष्ठ <xliff:g id="ID_2">%2$d</xliff:g> पैकी <xliff:g id="ID_1">%1$d</xliff:g>"</string>
    -+    <string name="cant_silence_or_block" msgid="999689262131488625">"सूचना शांत किंवा अवरोधित केल्या जाऊ शकत नाहीत"</string>
    - </resources>
    -diff --git a/packages/SystemUI/res/values-ms-rMY/strings.xml b/packages/SystemUI/res/values-ms-rMY/strings.xml
    -index 7c543a6..df0faeb 100644
    ---- a/packages/SystemUI/res/values-ms-rMY/strings.xml
    -+++ b/packages/SystemUI/res/values-ms-rMY/strings.xml
    -@@ -238,7 +238,7 @@
    -     <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"Data 4G dijeda"</string>
    -     <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"Data selular dijeda"</string>
    -     <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"Data dijeda"</string>
    --    <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"Oleh kerana had data tetap anda telah dicapai, peranti telah menjeda penggunaan data bagi baki kitaran ini.\n\nMenyambung semula boleh menyebabkan anda dikenakan bayaran daripada pembawa anda."</string>
    -+    <string name="data_usage_disabled_dialog" msgid="1841738975235283398">"Had data yang anda tetapkan telah dicapai. Anda tidak lagi menggunakan data selular.\n\nJika anda menyambung semula, caj mungkin dikenakan untuk penggunaan data."</string>
    -     <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"Sambung semula"</string>
    -     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Tiada smbg Internet"</string>
    -     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi disambungkan"</string>
    -@@ -404,6 +404,7 @@
    -     <string name="device_owned_footer" msgid="3802752663326030053">"Peranti mungkin dipantau"</string>
    -     <string name="profile_owned_footer" msgid="8021888108553696069">"Profil mungkin dipantau"</string>
    -     <string name="vpn_footer" msgid="2388611096129106812">"Rangkaian mungkin dipantau"</string>
    -+    <string name="branded_vpn_footer" msgid="2168111859226496230">"Rangkaian mungkin dipantau"</string>
    -     <string name="monitoring_title_device_owned" msgid="7121079311903859610">"Pemantauan peranti"</string>
    -     <string name="monitoring_title_profile_owned" msgid="6790109874733501487">"Pemantauan profil"</string>
    -     <string name="monitoring_title" msgid="169206259253048106">"Pemantauan rangkaian"</string>
    -@@ -416,6 +417,7 @@
    -     <string name="legacy_vpn_name" msgid="6604123105765737830">"VPN"</string>
    -     <string name="monitoring_description_app" msgid="6259179342284742878">"Anda disambungkan ke <xliff:g id="APPLICATION">%1$s</xliff:g>, yang boleh memantau aktiviti rangkaian anda, termasuk e-mel, apl dan tapak web."</string>
    -     <string name="monitoring_description_app_personal" msgid="484599052118316268">"Anda disambungkan ke <xliff:g id="APPLICATION">%1$s</xliff:g>, yang boleh memantau aktiviti rangkaian peribadi anda, termasuk e-mel, apl dan tapak web."</string>
    -+    <string name="branded_monitoring_description_app_personal" msgid="2669518213949202599">"Anda disambungkan ke <xliff:g id="APPLICATION">%1$s</xliff:g>, yang boleh memantau aktiviti rangkaian peribadi anda, termasuk e-mel, apl dan tapak web."</string>
    -     <string name="monitoring_description_app_work" msgid="1754325860918060897">"Profil kerja anda diurus oleh <xliff:g id="ORGANIZATION">%1$s</xliff:g>. Profil ini disambungkan ke <xliff:g id="APPLICATION">%2$s</xliff:g>, yang boleh memantau aktiviti rangkaian kerja anda, termasuk e-mel, apl dan tapak web.\n\nUntuk mendapatkan maklumat lanjut, sila hubungi pentadbir anda."</string>
    -     <string name="monitoring_description_app_personal_work" msgid="4946600443852045903">"Profil kerja anda diurus oleh <xliff:g id="ORGANIZATION">%1$s</xliff:g>. Profil disambungkan ke <xliff:g id="APPLICATION_WORK">%2$s</xliff:g>, yang boleh memantau aktiviti rangkaian kerja anda, termasuk e-mel, apl dan tapak web.\n\nAnda turut disambungkan ke <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g>, yang boleh memantau aktiviti rangkaian peribadi anda."</string>
    -     <string name="monitoring_description_vpn_app_device_owned" msgid="4970443827043261703">"Peranti anda diurus oleh <xliff:g id="ORGANIZATION">%1$s</xliff:g>.\n\nPentadbir anda boleh memantau dan mengurus tetapan, akses korporat, apl, data yang dikaitkan dengan peranti anda serta maklumat lokasi peranti anda.\n\nAnda disambungkan ke <xliff:g id="APPLICATION">%2$s</xliff:g>, yang boleh memantau aktiviti rangkaian anda, termasuk e-mel, apl dan tapak web.\n\nUntuk mendapatkan maklumat lanjut, hubungi pentadbir anda."</string>
    -@@ -492,8 +494,6 @@
    -     <string name="clock_seconds_desc" msgid="6282693067130470675">"Tunjukkan saat jam dalam bar status. Mungkin menjejaskan hayat bateri."</string>
    -     <string name="qs_rearrange" msgid="8060918697551068765">"Susun Semula Tetapan Pantas"</string>
    -     <string name="show_brightness" msgid="6613930842805942519">"Tunjukkan kecerahan dalam Tetapan Pantas"</string>
    --    <string name="overview_nav_bar_gesture" msgid="8579814204727917764">"Dayakan gerak isyarat leret ke atas utk masuk skrin terpisah"</string>
    --    <string name="overview_nav_bar_gesture_desc" msgid="6329167382305102615">"Dayakan gerak isyarat untuk memasuki skrin terpisah dengan meleret ke atas daripada butang Ikhtisar"</string>
    -     <string name="experimental" msgid="6198182315536726162">"Percubaan"</string>
    -     <string name="enable_bluetooth_title" msgid="5027037706500635269">"Hidupkan Bluetooth?"</string>
    -     <string name="enable_bluetooth_message" msgid="9106595990708985385">"Untuk menyambungkan papan kekunci anda dengan tablet, anda perlu menghidupkan Bluetooth terlebih dahulu."</string>
    -@@ -651,4 +651,5 @@
    -     <string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"Buka tetapan <xliff:g id="ID_1">%s</xliff:g>."</string>
    -     <string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"Edit susunan tetapan."</string>
    -     <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"Halaman <xliff:g id="ID_1">%1$d</xliff:g> daripada <xliff:g id="ID_2">%2$d</xliff:g>"</string>
    -+    <string name="cant_silence_or_block" msgid="999689262131488625">"Pemberitahuan tidak boleh disenyapkan atau disekat"</string>
    - </resources>
    -diff --git a/packages/SystemUI/res/values-my-rMM/strings.xml b/packages/SystemUI/res/values-my-rMM/strings.xml
    -index 56a7249..92ee06e 100644
    ---- a/packages/SystemUI/res/values-my-rMM/strings.xml
    -+++ b/packages/SystemUI/res/values-my-rMM/strings.xml
    -@@ -238,7 +238,7 @@
    -     <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"4G data ခေတ္တရပ်တန့်သည်"</string>
    -     <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"cellular data ခေတ္တရပ်တန့်သည်"</string>
    -     <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"ဒေတာ ခေတ္တရပ်တန့်သည်"</string>
    --    <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"သင့် ဒေတာ အသုံးပြုမှု သတ်မှတ်ထားချက်သို့ ရောက်ရှိသောကြောင့်၊ ဤကာလအတွက် ကျန်ရှိသည့် ဒေတာအသုံးပြုမှုအား စက်ပစ္စည်းမှ ရပ်တန့်ထားသည်။\n\nဆက်လက်သွားပါက သင့်ဖုန်းဝန်ဆောင်မှုမှ သင့်အား ကုန်ကျစရိတ်တောင်းခံလိမ့်မည်။"</string>
    -+    <string name="data_usage_disabled_dialog" msgid="1841738975235283398">"သင်သတ်မှတ်ထားသော ဒေတာကန့်သတ်ချက်သို့ ရောက်နေပါပြီ။ သင်သည် ဆယ်လူလာဒေတာကို အသုံးမပြုတော့ပါ။\n\nသင်ဆက်လုပ်မည်ဆိုလျှင် ဒေတာသုံးစွဲမှုအတွက် အခငွေ ကျသင့်မှုရှိနိုင်ပါသည်။"</string>
    -     <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"ပြန်ဆက်လုပ်ရန်"</string>
    -     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"အင်တာနက်မရှိ"</string>
    -     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"ကြိုးမဲ့ဆက်သွယ်မှု"</string>
    -@@ -404,6 +404,7 @@
    -     <string name="device_owned_footer" msgid="3802752663326030053">"ကိရိယာကို စောင့်ကြပ် နိုင်ပါသည်"</string>
    -     <string name="profile_owned_footer" msgid="8021888108553696069">"ပရိုဖိုင်ကို စောင့်ကြပ်နိုင်သည်"</string>
    -     <string name="vpn_footer" msgid="2388611096129106812">"ကွန်ရက်ကို ကို စောင့်ကြပ် နိုင်ပါသည်"</string>
    -+    <string name="branded_vpn_footer" msgid="2168111859226496230">"ကွန်ရက်ကို စောင့်ကြည့်စစ်ဆေးမှု ရှိနိုင်ပါသည်"</string>
    -     <string name="monitoring_title_device_owned" msgid="7121079311903859610">"ကိရိယာကို စောင့်ကြပ်ခြင်း"</string>
    -     <string name="monitoring_title_profile_owned" msgid="6790109874733501487">"ပရိုဖိုင် စောင့်ကြပ်မှု"</string>
    -     <string name="monitoring_title" msgid="169206259253048106">"ကွန်ရက်ကို စောင့်ကြပ်ခြင်း"</string>
    -@@ -416,6 +417,7 @@
    -     <string name="legacy_vpn_name" msgid="6604123105765737830">"VPN"</string>
    -     <string name="monitoring_description_app" msgid="6259179342284742878">"သင်သည် <xliff:g id="APPLICATION">%1$s</xliff:g> သို့ ချိတ်ဆက်ထားသည်၊ ၎င်းသည် အီးမေးများ၊ အက်ပ်များနှင့် ဝဘ်ဆိုက်များအပါအဝင် သင့်ကွန်ရက်လုပ်ဆောင်ချက်များကို စောင့်ကြည့်နိုင်သည်။"</string>
    -     <string name="monitoring_description_app_personal" msgid="484599052118316268">"သင်သည် <xliff:g id="APPLICATION">%1$s</xliff:g> သို့ ချိတ်ဆက်ထားသည်။ ၎င်းသည် အီးမေးလ်များ၊ အက်ပ်များနှင့် ဝဘ်ဆိုက်များအပါအဝင် သင့်ကွန်ရက်လုပ်ဆောင်ချက်ကို စောင့်ကြည့်နိုင်သည်။"</string>
    -+    <string name="branded_monitoring_description_app_personal" msgid="2669518213949202599">"သင်သည် အီးမေးလ်၊ အက်ပ်နှင့် ဝဘ်ဆိုက်များအပါအဝင် သင့်ကိုယ်ရေးကိုယ်တာ ကွန်ရက်အသုံးပြုမှုကို စောင့်ကြည့်နိုင်သည့် <xliff:g id="APPLICATION">%1$s</xliff:g> သို့ ချိတ်ဆက်ထားပါသည်။"</string>
    -     <string name="monitoring_description_app_work" msgid="1754325860918060897">"သင့်အလုပ်ပရိုဖိုင်ကို <xliff:g id="ORGANIZATION">%1$s</xliff:g> မှစီမံခန့်ခွဲသည်။ ၎င်းကို <xliff:g id="APPLICATION">%2$s</xliff:g> သို့ ချိတ်ဆက်ထားသည်၊ ၎င်းသည် အီးမေးလ်များ၊ အက်ပ်များနှင့် ဝဘ်ဆိုက်များအပါအဝင် သင့်အလုပ်ကွန်ရက်လုပ်ဆောင်ချက်ကို စောင့်ကြည့်နိုင်သည်။ \n\nအချက်အလက်များ ပိုမိုရယူရန် သင်၏ စီမံခန့်ခွဲသူကို ဆက်သွယ်ပါ။"</string>
    -     <string name="monitoring_description_app_personal_work" msgid="4946600443852045903">"သင့်အလုပ် ပရိုဖိုင်ကို <xliff:g id="ORGANIZATION">%1$s</xliff:g> မှစီမံခန့်ခွဲသည်။ ၎င်းကို <xliff:g id="APPLICATION_WORK">%2$s</xliff:g> သို့ ချိတ်ဆက်ထားသည်၊ ၎င်းသည် အီးမေးလ်များ၊ အက်ပ်များနှင့် ဝဘ်ဆိုက်များအပါအဝင် သင့်အလုပ်ကွန်ရက်လုပ်ဆောင်ချက်ကို စောင့်ကြည့်နိုင်သည်။ \n\n သင်သည်<xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g> ကိုလည်း ချိတ်ဆက်ထားသည်၊ ၎င်းသည် သင့်ကိုယ်ပိုင်ကွန်ရက်လုပ်ဆောင်ချက်များကို စောင့်ကြည့်နိုင်သည်။"</string>
    -     <string name="monitoring_description_vpn_app_device_owned" msgid="4970443827043261703">"သင့်စက်ကိရိယာကို <xliff:g id="ORGANIZATION">%1$s</xliff:g> မှစီမံခန့်ခွဲပါသည်။ \n\n စီမံခန့်ခွဲသူသည် ကြိုတင်ပြင်ဆင်မှုများ၊ စုပေါင်းဝင်ရောက်ခွင့်၊ အက်ပ်များ၊ သင့်ကိရိယာနှင့်သက်ဆိုင်သော ဒေတာနှင့် သင့်ကိရိယာ၏ တည်နေရာအချက်အလက်များကို စောင့်ကြည့်ပြီး စီမံခန့်ခွဲနိုင်သည်။ \n\nသင်သည် <xliff:g id="APPLICATION">%2$s</xliff:g> သို့ချိတ်ဆက်ထားသည်၊ ၎င်းသည် အီးမေးလ်များ၊ အက်ပ်များ၊ နှင့် ဝဘ်ဆိုက်များအပါအဝင် သင့်ကွန်ရက်လုပ်ဆောင်ချက်ကို စောင့်ကြည့်နိုင်သည်။ \n\nအချက်အလက်များ ပိုမိုရယူရန် သင်၏ စီမံခန့်ခွဲသူကို ဆက်သွယ်ပါ။"</string>
    -@@ -492,8 +494,6 @@
    -     <string name="clock_seconds_desc" msgid="6282693067130470675">"အခြေအနေပြနေရာမှာ နာရီ စက္ကန့်များကို ပြပါ။ ဘက်ထရီ သက်တမ်းကို အကျိုးသက်ရောက်နိုင်တယ်။"</string>
    -     <string name="qs_rearrange" msgid="8060918697551068765">"အမြန် ဆက်တင်များကို ပြန်စီစဉ်ရန်"</string>
    -     <string name="show_brightness" msgid="6613930842805942519">"အမြန် ဆက်တင်များထဲက တောက်ပမှုကို ပြရန်"</string>
    --    <string name="overview_nav_bar_gesture" msgid="8579814204727917764">"မျက်နှာပြင်ခွဲကြည့်ရန် အပေါ်သို့ပွတ်ဆွဲခြင်း အမူအရာကိုဖွင့်ပါ"</string>
    --    <string name="overview_nav_bar_gesture_desc" msgid="6329167382305102615">"ခြုံကြည့်သည့်ခလုတ်မှ အပေါ်သို့ပွတ်ဆွဲခြင်းဖြင့် မျက်နှာပြင်ခွဲကြည့်ရန် လက်ဟန်ကိုဖွင့်ပါ"</string>
    -     <string name="experimental" msgid="6198182315536726162">"စမ်းသပ်ရေး"</string>
    -     <string name="enable_bluetooth_title" msgid="5027037706500635269">"ဘလူးတုသ် ဖွင့်ရမလား။"</string>
    -     <string name="enable_bluetooth_message" msgid="9106595990708985385">"ကီးဘုတ်ကို တပ်ဘလက်နှင့် ချိတ်ဆက်ရန်၊ ပမထဦးစွာ ဘလူးတုသ်ကို ဖွင့်ပါ။"</string>
    -@@ -588,7 +588,7 @@
    -     <string name="center" msgid="4327473927066010960">"ဌာန"</string>
    -     <string name="end" msgid="125797972524818282">"ပြီးပါပြီ"</string>
    -     <string name="space" msgid="804232271282109749">"နေရာလွတ်ခြားစနစ်"</string>
    --    <string name="menu_ime" msgid="4943221416525250684">"မန်နယူး / ကီးဘုတ်ပြောင်းစနစ်"</string>
    -+    <string name="menu_ime" msgid="4943221416525250684">"မီနူး / ကီးဘုတ်ပြောင်းစနစ်"</string>
    -     <string name="select_button" msgid="1597989540662710653">"ပေါင်းထည့်ရန် ခလုတ်ကိုရွေးပါ"</string>
    -     <string name="add_button" msgid="4134946063432258161">"ခလုတ်ပေါင်းထည့်ပါ"</string>
    -     <string name="save" msgid="2311877285724540644">"သိမ်းရန်"</string>
    -@@ -651,4 +651,5 @@
    -     <string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"<xliff:g id="ID_1">%s</xliff:g> ဆက်တင်များကို ဖွင့်ပါ။"</string>
    -     <string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"ဆက်တင်များ၏ အစီအစဉ်ကို တည်းဖြတ်ပါ။"</string>
    -     <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"စာမျက်နှာ <xliff:g id="ID_2">%2$d</xliff:g> အနက်မှ စာမျက်နှာ <xliff:g id="ID_1">%1$d</xliff:g>"</string>
    -+    <string name="cant_silence_or_block" msgid="999689262131488625">"အကြောင်းကြားချက်များကို အသံတိတ်ခြင်း သို့မဟုတ် ပိတ်ဆို့ခြင်းများ ပြုလုပ်၍ မရပါ"</string>
    - </resources>
    -diff --git a/packages/SystemUI/res/values-nb/strings.xml b/packages/SystemUI/res/values-nb/strings.xml
    -index 3efdd3e..02cb082 100644
    ---- a/packages/SystemUI/res/values-nb/strings.xml
    -+++ b/packages/SystemUI/res/values-nb/strings.xml
    -@@ -238,7 +238,7 @@
    -     <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"4G-data er satt på pause"</string>
    -     <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"Mobildata er satt på pause"</string>
    -     <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"Data er satt på pause"</string>
    --    <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"Fordi den angitte datagrensen ble nådd, har enheten satt databruk på pause for resten av denne syklusen. \n\nHvis du gjenopptar bruken, kan det føre til avgifter fra operatøren din."</string>
    -+    <string name="data_usage_disabled_dialog" msgid="1841738975235283398">"Datagrensen du satte, er nådd. Du bruker ikke mobildata lenger.\n\nHvis du gjenopptar bruk av mobildata, kan gebyrer for databruk påløpe."</string>
    -     <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"Gjenoppta"</string>
    -     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Ingen Internett-forbindelse"</string>
    -     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi tilkoblet"</string>
    -@@ -404,6 +404,7 @@
    -     <string name="device_owned_footer" msgid="3802752663326030053">"Enheten kan være overvåket"</string>
    -     <string name="profile_owned_footer" msgid="8021888108553696069">"Profilen kan overvåkes"</string>
    -     <string name="vpn_footer" msgid="2388611096129106812">"Nettverket kan være overvåket"</string>
    -+    <string name="branded_vpn_footer" msgid="2168111859226496230">"Nettverket kan bli overvåket"</string>
    -     <string name="monitoring_title_device_owned" msgid="7121079311903859610">"Enhetsovervåking"</string>
    -     <string name="monitoring_title_profile_owned" msgid="6790109874733501487">"Profilovervåking"</string>
    -     <string name="monitoring_title" msgid="169206259253048106">"Nettverksovervåking"</string>
    -@@ -416,6 +417,7 @@
    -     <string name="legacy_vpn_name" msgid="6604123105765737830">"VPN"</string>
    -     <string name="monitoring_description_app" msgid="6259179342284742878">"Enheten er koblet til <xliff:g id="APPLICATION">%1$s</xliff:g>, som kan overvåke nettverksaktiviteten din, inkludert e-post, apper og nettsteder."</string>
    -     <string name="monitoring_description_app_personal" msgid="484599052118316268">"Enheten er koblet til <xliff:g id="APPLICATION">%1$s</xliff:g>, som kan overvåke den personlige nettverksaktiviteten din, inkludert e-post, apper og nettsteder."</string>
    -+    <string name="branded_monitoring_description_app_personal" msgid="2669518213949202599">"Enheten er koblet til <xliff:g id="APPLICATION">%1$s</xliff:g>, som kan overvåke den personlige nettverksaktiviteten din, inkludert e-post, apper og nettsteder."</string>
    -     <string name="monitoring_description_app_work" msgid="1754325860918060897">"Work-profilen din administreres av <xliff:g id="ORGANIZATION">%1$s</xliff:g>. Den er koblet til <xliff:g id="APPLICATION">%2$s</xliff:g>, som kan overvåke nettverksaktiviteten din på jobben, inkludert e-post, apper og nettsteder.\n\nFor å få mer informasjon, ta kontakt med administratoren."</string>
    -     <string name="monitoring_description_app_personal_work" msgid="4946600443852045903">"Work-profilen din administreres av <xliff:g id="ORGANIZATION">%1$s</xliff:g>. Den er koblet til <xliff:g id="APPLICATION_WORK">%2$s</xliff:g>, som kan overvåke nettverksaktiviteten din på jobben, inkludert e-post, apper og nettsteder.\n\nDu er også koblet til <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g>, som kan overvåke den personlige nettverksaktiviteten din."</string>
    -     <string name="monitoring_description_vpn_app_device_owned" msgid="4970443827043261703">"Enheten din administreres av <xliff:g id="ORGANIZATION">%1$s</xliff:g>.\n\nAdministratoren din kan overvåke og administrere innstillinger, bedriftstilgang, apper, data tilknyttet enheten din og enhetens posisjonsinformasjon.\n\nDu er koblet til <xliff:g id="APPLICATION">%2$s</xliff:g>, som kan overvåke nettverksaktiviteten din, inkludert e-post, apper og nettsteder.\n\nFor mer informasjon, ta kontakt med administratoren."</string>
    -@@ -492,8 +494,6 @@
    -     <string name="clock_seconds_desc" msgid="6282693067130470675">"Vis sekunder i statusfeltet på klokken. Det kan påvirke batteritiden."</string>
    -     <string name="qs_rearrange" msgid="8060918697551068765">"Omorganiser hurtiginnstillingene"</string>
    -     <string name="show_brightness" msgid="6613930842805942519">"Vis lysstyrke i hurtiginnstillingene"</string>
    --    <string name="overview_nav_bar_gesture" msgid="8579814204727917764">"Slå på delt skjerm ved å sveipe opp"</string>
    --    <string name="overview_nav_bar_gesture_desc" msgid="6329167382305102615">"Slå på bevegelsen for å åpne delt skjerm ved å sveipe opp fra Oversikt-knappen"</string>
    -     <string name="experimental" msgid="6198182315536726162">"På forsøksstadiet"</string>
    -     <string name="enable_bluetooth_title" msgid="5027037706500635269">"Vil du slå på Bluetooth?"</string>
    -     <string name="enable_bluetooth_message" msgid="9106595990708985385">"For å koble tastaturet til nettbrettet ditt må du først slå på Bluetooth."</string>
    -@@ -651,4 +651,5 @@
    -     <string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"Åpne <xliff:g id="ID_1">%s</xliff:g>-innstillingene."</string>
    -     <string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"Endre rekkefølgen på innstillingene."</string>
    -     <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"Side <xliff:g id="ID_1">%1$d</xliff:g> av <xliff:g id="ID_2">%2$d</xliff:g>"</string>
    -+    <string name="cant_silence_or_block" msgid="999689262131488625">"Varslinger kan ikke ignoreres eller blokkeres"</string>
    - </resources>
    -diff --git a/packages/SystemUI/res/values-ne-rNP/strings.xml b/packages/SystemUI/res/values-ne-rNP/strings.xml
    -index 07d0795..79d4b84 100644
    ---- a/packages/SystemUI/res/values-ne-rNP/strings.xml
    -+++ b/packages/SystemUI/res/values-ne-rNP/strings.xml
    -@@ -238,7 +238,7 @@
    -     <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"4G डेटा रोकिएको छ"</string>
    -     <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"सेल्यूलर डेटा रोकिएको छ"</string>
    -     <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"डेटा रोकिएको छ"</string>
    --    <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"तपाईंले सेट गर्नुभएको डेटाको सीमा पुगेकाले, यन्त्रले यस चक्रको बाँकी भागका लागि डेटाको प्रयोग रोकेको छ।\n\nपुन: सुरू गर्दा तपाईंको क्यारियरले शुल्कहरू लिन सक्छ।"</string>
    -+    <string name="data_usage_disabled_dialog" msgid="1841738975235283398">"तपाईँले सेट गर्नुभएको डेटाको सीमामा पुगिएको छ। अबदेखि तपाईँ सेलुलर डेटाको प्रयोग गर्नुहुने छैन। \n\nतपाईँले प्रयोग जारी राख्नुभयो भने डेटा प्रयोगका शुल्कहरू लाग्न सक्छन्।"</string>
    -     <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"पुनः सुरु गर्नुहोस्"</string>
    -     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"इन्टरनेट जडान छैन"</string>
    -     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi जडित"</string>
    -@@ -404,6 +404,7 @@
    -     <string name="device_owned_footer" msgid="3802752663326030053">"उपकरण अनुगमन हुन सक्छ"</string>
    -     <string name="profile_owned_footer" msgid="8021888108553696069">"प्रोफाइल अनुगमन हुन सक्छ"</string>
    -     <string name="vpn_footer" msgid="2388611096129106812">"सञ्जाल अनुगमित हुन सक्छ"</string>
    -+    <string name="branded_vpn_footer" msgid="2168111859226496230">"नेटवर्कको अनुगमन गरिने सम्भावना छ"</string>
    -     <string name="monitoring_title_device_owned" msgid="7121079311903859610">"उपकरण अनुगमन"</string>
    -     <string name="monitoring_title_profile_owned" msgid="6790109874733501487">"प्रोफाइल अनुगमन गर्दै"</string>
    -     <string name="monitoring_title" msgid="169206259253048106">"सञ्जाल अनुगमन"</string>
    -@@ -416,6 +417,7 @@
    -     <string name="legacy_vpn_name" msgid="6604123105765737830">"VPN"</string>
    -     <string name="monitoring_description_app" msgid="6259179342284742878">"तपाईँ <xliff:g id="APPLICATION">%1$s</xliff:g> सँग जडित हुनुहुन्छ जसले इ-मेल, अनुप्रयोगहरू र वेबसाइट लगायतका तपाईँका नेटवर्क गतिविधिको अनुगमन गर्न सक्छ।"</string>
    -     <string name="monitoring_description_app_personal" msgid="484599052118316268">"तपाईँ <xliff:g id="APPLICATION">%1$s</xliff:g> सँग जडित हुनुहुन्छ जसले इ-मेल, अनुप्रयोगहरू र वेबसाइट लगायतका तपाईँको निजी नेटवर्क गतिविधिका अनुगमन गर्न सक्छ।"</string>
    -+    <string name="branded_monitoring_description_app_personal" msgid="2669518213949202599">"तपाईं <xliff:g id="APPLICATION">%1$s</xliff:g> मा जोडिनुभएको छ जसले इमेल, अनुप्रयोग र वेबसाइटहरू लगायतको तपाईंको  व्यक्तिगत नेटवर्क सम्बन्धी गतिविधिको अनुगमन गर्न सक्छ।"</string>
    -     <string name="monitoring_description_app_work" msgid="1754325860918060897">"तपाईँको कार्य प्रोफाइल <xliff:g id="ORGANIZATION">%1$s</xliff:g> द्वारा व्यवस्थापन गरिन्छ। यो <xliff:g id="APPLICATION">%2$s</xliff:g> सँग जोडिएको छ जसले इमेल, अनुप्रयोगहरू, र वेबसाइटहरू लगायतका तपाईँका नेटवर्क गतिविधि अनुगमन गर्न सक्छ।\n\nथप जानकारीको लागि, आफ्नो प्रशासकलाई सम्पर्क गर्नुहोस्।"</string>
    -     <string name="monitoring_description_app_personal_work" msgid="4946600443852045903">"तपाईँको कार्य प्रोफाइल <xliff:g id="ORGANIZATION">%1$s</xliff:g> द्वारा व्यवस्थापन गरिन्छ। यो <xliff:g id="APPLICATION_WORK">%2$s</xliff:g> सँग जोडिएको छ जसले इमेल, अनुप्रयोगहरू, र वेबसाइटहरू लगायतका तपाईँका नेटवर्क गतिविधि अनुगमन गर्न सक्छ।\n\nतपाईँ <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g> सँग पनि जडित हुनुहुन्छ, जसले तपाईँको व्यक्तिगत नेटवर्क गतिविधि अनुगमन गर्न सक्छ।"</string>
    -     <string name="monitoring_description_vpn_app_device_owned" msgid="4970443827043261703">"तपाईँको उपकरण <xliff:g id="ORGANIZATION">%1$s</xliff:g> द्वारा व्यवस्थित गरिन्छ।\n\nतपाईँको प्रशासकले तपाईँको यन्त्र र त्यसको स्थान जानकारीमार्फत सेटिङहरू,  कर्पोरेट पहुँच, अनुप्रयोगहरू, तपाईँको यन्त्रसँग सम्बद्ध डेटा  र तपाईँको यन्त्रको स्थान जानकारीको अनुगमन र व्यवस्थापन गर्न सक्छ।\n\nतपाईँ <xliff:g id="APPLICATION">%2$s</xliff:g> सँग जडित हुनुहुन्छ जसले इमेल, अनुप्रयोगहरू, र वेबसाइटहरू लगायतका तपाईँका नेटवर्क गतिविधिका अनुगमन गर्न सक्छ।\n\nथप जानकारीको लागि तपाईको प्रशासकलाई सम्पर्क गर्नुहोस्।"</string>
    -@@ -492,8 +494,6 @@
    -     <string name="clock_seconds_desc" msgid="6282693067130470675">"वस्तुस्थिति पट्टीको घडीमा सेकेन्ड देखाउनुहोस्। ब्याट्री आयु प्रभावित हुन सक्छ।"</string>
    -     <string name="qs_rearrange" msgid="8060918697551068765">"द्रुत सेटिङहरू पुनः व्यवस्थित गर्नुहोस्"</string>
    -     <string name="show_brightness" msgid="6613930842805942519">"द्रुत सेटिङहरूमा उज्यालो देखाउनुहोस्"</string>
    --    <string name="overview_nav_bar_gesture" msgid="8579814204727917764">"विभाजित-स्क्रिन स्वाइप-अप इशारा सक्षम गर्नुहोस्"</string>
    --    <string name="overview_nav_bar_gesture_desc" msgid="6329167382305102615">"परिदृश्य बटनदेखि माथि स्वाइप गरी विभाजित-स्क्रिन प्रविष्ट गर्न इसारालाई सक्रिय गर्नुहोस्"</string>
    -     <string name="experimental" msgid="6198182315536726162">"प्रयोगात्मक"</string>
    -     <string name="enable_bluetooth_title" msgid="5027037706500635269">"ब्लुटुथ सक्रिय पार्ने हो?"</string>
    -     <string name="enable_bluetooth_message" msgid="9106595990708985385">"आफ्नो ट्याब्लेटसँग किबोर्ड जोड्न, पहिले तपाईँले ब्लुटुथ सक्रिय गर्नुपर्छ।"</string>
    -@@ -651,4 +651,5 @@
    -     <string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"<xliff:g id="ID_1">%s</xliff:g> सम्बन्धी सेटिङहरूलाई खोल्नुहोस्।"</string>
    -     <string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"सेटिङहरूको क्रमलाई सम्पादन गर्नुहोस्।"</string>
    -     <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"<xliff:g id="ID_2">%2$d</xliff:g> मध्ये पृष्ठ <xliff:g id="ID_1">%1$d</xliff:g>"</string>
    -+    <string name="cant_silence_or_block" msgid="999689262131488625">"सूचनाहरूलाई मौन गर्न वा यसमाथि रोक लगाउन मिल्दैन"</string>
    - </resources>
    -diff --git a/packages/SystemUI/res/values-nl/strings.xml b/packages/SystemUI/res/values-nl/strings.xml
    -index 9509229..a2a4365 100644
    ---- a/packages/SystemUI/res/values-nl/strings.xml
    -+++ b/packages/SystemUI/res/values-nl/strings.xml
    -@@ -238,7 +238,7 @@
    -     <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"4G-data zijn onderbroken"</string>
    -     <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"Mobiele gegevens zijn onderbroken"</string>
    -     <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"Gegevens zijn onderbroken"</string>
    --    <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"Omdat de ingestelde gegevenslimiet is bereikt, heeft het apparaat het gegevensverbruik onderbroken voor de rest van deze cyclus.\n\nAls u het gegevensverbruik hervat, kan je provider kosten in rekening brengen."</string>
    -+    <string name="data_usage_disabled_dialog" msgid="1841738975235283398">"De ingestelde datalimiet is bereikt. Je gebruikt geen mobiele data meer.\n\nAls je hervat, kunnen er kosten voor datagebruik in rekening worden gebracht."</string>
    -     <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"Hervatten"</string>
    -     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Geen internetverbinding"</string>
    -     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Verbonden via wifi"</string>
    -@@ -404,6 +404,7 @@
    -     <string name="device_owned_footer" msgid="3802752663326030053">"Apparaat wordt mogelijk gecontroleerd"</string>
    -     <string name="profile_owned_footer" msgid="8021888108553696069">"Profiel kan worden gecontroleerd"</string>
    -     <string name="vpn_footer" msgid="2388611096129106812">"Netwerk kan worden gecontroleerd"</string>
    -+    <string name="branded_vpn_footer" msgid="2168111859226496230">"Netwerk kan worden gecontroleerd"</string>
    -     <string name="monitoring_title_device_owned" msgid="7121079311903859610">"Apparaatcontrole"</string>
    -     <string name="monitoring_title_profile_owned" msgid="6790109874733501487">"Profielcontrole"</string>
    -     <string name="monitoring_title" msgid="169206259253048106">"Netwerkcontrole"</string>
    -@@ -416,6 +417,7 @@
    -     <string name="legacy_vpn_name" msgid="6604123105765737830">"VPN"</string>
    -     <string name="monitoring_description_app" msgid="6259179342284742878">"U bent verbonden met <xliff:g id="APPLICATION">%1$s</xliff:g>, waarmee je netwerkactiviteit kan worden gecontroleerd, inclusief e-mails, apps en websites."</string>
    -     <string name="monitoring_description_app_personal" msgid="484599052118316268">"U bent verbonden met <xliff:g id="APPLICATION">%1$s</xliff:g>, waarmee je persoonlijke netwerkactiviteit kan worden gecontroleerd, inclusief e-mails, apps en websites."</string>
    -+    <string name="branded_monitoring_description_app_personal" msgid="2669518213949202599">"Je bent verbonden met <xliff:g id="APPLICATION">%1$s</xliff:g>, waarmee je persoonlijke netwerkactiviteit kan worden gecontroleerd, inclusief e-mails, apps en websites."</string>
    -     <string name="monitoring_description_app_work" msgid="1754325860918060897">"Je werkprofiel wordt beheerd door <xliff:g id="ORGANIZATION">%1$s</xliff:g>. Deze is verbonden met <xliff:g id="APPLICATION">%2$s</xliff:g>, waarmee je werkgerelateerde netwerkactiviteit kan worden gecontroleerd, inclusief e-mails, apps en websites.\n\nNeem contact op met je beheerder voor meer informatie."</string>
    -     <string name="monitoring_description_app_personal_work" msgid="4946600443852045903">"Je werkprofiel wordt beheerd door <xliff:g id="ORGANIZATION">%1$s</xliff:g>. Deze is verbonden met <xliff:g id="APPLICATION_WORK">%2$s</xliff:g>, waarmee je werkgerelateerde netwerkactiviteit kan worden gecontroleerd, inclusief e-mails, apps en websites.\n\nU bent ook verbonden met <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g>, waarmee je persoonlijke netwerkactiviteit kan worden gecontroleerd."</string>
    -     <string name="monitoring_description_vpn_app_device_owned" msgid="4970443827043261703">"Je apparaat wordt beheerd door <xliff:g id="ORGANIZATION">%1$s</xliff:g>.\n\nJe beheerder kan instellingen, zakelijke toegang, apps, gekoppelde apparaatgegevens en locatiegegevens voor je apparaat controleren en beheren.\n\nU bent verbonden met <xliff:g id="APPLICATION">%2$s</xliff:g> waarmee je netwerkactiviteit kan worden gecontroleerd, inclusief e-mails, apps en websites.\n\nNeem contact op met je beheerder voor meer informatie."</string>
    -@@ -492,8 +494,6 @@
    -     <string name="clock_seconds_desc" msgid="6282693067130470675">"Klokseconden op de statusbalk weergeven. Kan van invloed zijn op de accuduur."</string>
    -     <string name="qs_rearrange" msgid="8060918697551068765">"Snelle instellingen opnieuw indelen"</string>
    -     <string name="show_brightness" msgid="6613930842805942519">"Helderheid weergeven in Snelle instellingen"</string>
    --    <string name="overview_nav_bar_gesture" msgid="8579814204727917764">"Omhoog vegen voor gesplitst scherm inschakelen"</string>
    --    <string name="overview_nav_bar_gesture_desc" msgid="6329167382305102615">"Gebaar inschakelen om gesplitst scherm te openen door vanaf de knop Overzicht omhoog te vegen"</string>
    -     <string name="experimental" msgid="6198182315536726162">"Experimenteel"</string>
    -     <string name="enable_bluetooth_title" msgid="5027037706500635269">"Bluetooth inschakelen?"</string>
    -     <string name="enable_bluetooth_message" msgid="9106595990708985385">"Als je je toetsenbord wilt verbinden met je tablet, moet je eerst Bluetooth inschakelen."</string>
    -@@ -651,4 +651,5 @@
    -     <string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"<xliff:g id="ID_1">%s</xliff:g>-instellingen openen."</string>
    -     <string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"Volgorde van instellingen bewerken."</string>
    -     <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"Pagina <xliff:g id="ID_1">%1$d</xliff:g> van <xliff:g id="ID_2">%2$d</xliff:g>"</string>
    -+    <string name="cant_silence_or_block" msgid="999689262131488625">"Meldingen kunnen niet op stil worden gezet of worden geblokkeerd"</string>
    - </resources>
    -diff --git a/packages/SystemUI/res/values-pa-rIN/strings.xml b/packages/SystemUI/res/values-pa-rIN/strings.xml
    -index 17c1261..e000541 100644
    ---- a/packages/SystemUI/res/values-pa-rIN/strings.xml
    -+++ b/packages/SystemUI/res/values-pa-rIN/strings.xml
    -@@ -238,7 +238,7 @@
    -     <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"4G ਡੈਟਾ ਰੁਕ ਗਿਆ ਹੈ"</string>
    -     <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"ਸੈਲਿਊਲਰ ਡੈਟਾ ਰੁਕ ਗਿਆ ਹੈ"</string>
    -     <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"ਡੈਟਾ ਰੁਕ ਗਿਆ ਹੈ"</string>
    --    <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"ਕਿਉਂਕਿ ਤੁਹਾਡੀ ਸੈਟ ਡੈਟਾ ਸੀਮਾ ਪੂਰੀ ਹੋ ਗਈ ਸੀ,  ਡੀਵਾਈਸ ਨੇ ਇਸ ਬਾਕੀ ਚੱਕਰ ਲਈ ਡੈਟਾ ਉਪਯੋਗ ਰੋਕ ਦਿੱਤਾ ਹੈ।\n\nਇਸਨੂੰ ਦੁਬਾਰਾ ਸ਼ੁਰੂ ਕਰਨ ਨਾਲ ਤੁਹਾਡੇ ਕੈਰੀਅਰ ਵੱਲੋਂ ਖ਼ਰਚੇ ਪਾਏ ਜਾ ਸਕਦੇ ਹਨ।"</string>
    -+    <string name="data_usage_disabled_dialog" msgid="1841738975235283398">"ਤੁਸੀਂ ਤੁਹਾਡੇ ਵੱਲੋਂ ਸੈੱਟ ਕੀਤੀ ਗਈ ਡੈਟਾ ਸੀਮਾ \'ਤੇ ਪਹੁੰਚ ਚੁੱਕੇ ਹੋ। ਤੁਸੀਂ ਹੁਣ ਸੈਲਿਊਲਰ ਡੈਟੇ ਦੀ ਵਰਤੋਂ ਨਹੀਂ ਕਰ ਰਹੇ ਹੋ।\n\nਜੇਕਰ ਤੁਸੀਂ ਮੁੜ-ਸ਼ੁਰੂ ਕਰਦੇ ਹੋ, ਤਾਂ ਡੈਟਾ ਵਰਤੋਂ ਲਈ ਖਰਚੇ ਲਾਗੂ ਹੋ ਸਕਦੇ ਹਨ।"</string>
    -     <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"ਦੁਬਾਰਾ ਸ਼ੁਰੂ ਕਰੋ"</string>
    -     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"ਕੋਈ ਇੰਟਰਨੈਟ ਕਨੈਕਸ਼ਨ ਨਹੀਂ"</string>
    -     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi ਕਨੈਕਟ ਕੀਤਾ"</string>
    -@@ -404,6 +404,7 @@
    -     <string name="device_owned_footer" msgid="3802752663326030053">"ਡੀਵਾਈਸ ਦਾ ਨਿਰੀਖਣ ਕੀਤਾ ਜਾ ਸਕਦਾ ਹੈ"</string>
    -     <string name="profile_owned_footer" msgid="8021888108553696069">"ਪ੍ਰੋਫਾਈਲ ਦਾ ਨਿਰੀਖਣ ਕੀਤਾ ਜਾ ਸਕਦਾ ਹੈ"</string>
    -     <string name="vpn_footer" msgid="2388611096129106812">"ਨੈੱਟਵਰਕ ਦਾ ਨਿਰੀਖਣ ਕੀਤਾ ਜਾ ਸਕਦਾ ਹੈ"</string>
    -+    <string name="branded_vpn_footer" msgid="2168111859226496230">"ਹੋ ਸਕਦਾ ਹੈ ਨੈੱਟਵਰਕ ਦੀ ਨਿਗਰਾਨੀ ਹੋ ਰਹੀ ਹੋਵੇ"</string>
    -     <string name="monitoring_title_device_owned" msgid="7121079311903859610">"ਡੀਵਾਈਸ ਦਾ ਨਿਰੀਖਣ ਕਰਨਾ"</string>
    -     <string name="monitoring_title_profile_owned" msgid="6790109874733501487">"ਪ੍ਰੋਫਾਈਲ ਦਾ ਨਿਰੀਖਣ ਕਰਨਾ"</string>
    -     <string name="monitoring_title" msgid="169206259253048106">"ਨੈੱਟਵਰਕ ਨਿਰੀਖਣ ਕਰ ਰਿਹਾ ਹੈ"</string>
    -@@ -416,6 +417,7 @@
    -     <string name="legacy_vpn_name" msgid="6604123105765737830">"VPN"</string>
    -     <string name="monitoring_description_app" msgid="6259179342284742878">"ਤੁਸੀਂ <xliff:g id="APPLICATION">%1$s</xliff:g> ਨਾਲ ਕਨੈਕਟ ਹੋ, ਜੋ ਈਮੇਲ, ਐਪਸ ਅਤੇ ਵੈਬਸਫ਼ਿਆਂ ਸਮੇਤ ਤੁਹਾਡੀ ਨੈੱਟਵਰਕ ਗਤੀਵਿਧੀ ਦਾ ਨਿਰੀਖਣ ਕਰ ਸਕਦੀ ਹੈ।"</string>
    -     <string name="monitoring_description_app_personal" msgid="484599052118316268">"ਤੁਸੀਂ <xliff:g id="APPLICATION">%1$s</xliff:g> ਨਾਲ ਕਨੈਕਟ ਹੋ, ਜੋ ਈਮੇਲ, ਐਪਸ ਅਤੇ ਵੈਬਸਫ਼ਿਆਂ ਸਮੇਤ ਤੁਹਾਡੀ ਨੈੱਟਵਰਕ ਗਤੀਵਿਧੀ ਦਾ ਨਿਰੀਖਣ ਕਰ ਸਕਦੀ ਹੈ।"</string>
    -+    <string name="branded_monitoring_description_app_personal" msgid="2669518213949202599">"ਤੁਸੀਂ <xliff:g id="APPLICATION">%1$s</xliff:g> ਨਾਲ ਕਨੈਕਟ ਹੋ, ਜੋ ਈਮੇਲਾਂ, ਐਪਾਂ, ਅਤੇ ਵੈੱਬਸਾਈਟਾਂ ਸਮੇਤ ਤੁਹਾਡੀ ਨਿੱਜੀ ਨੈੱਟਵਰਕ ਸਰਗਰਮੀ ਦੀ ਨਿਗਰਾਨੀ ਕਰ ਸਕਦੀ ਹੈ।"</string>
    -     <string name="monitoring_description_app_work" msgid="1754325860918060897">"ਤੁਹਾਡੀ ਕਾਰਜ ਪ੍ਰੋਫ਼ਾਈਲ <xliff:g id="ORGANIZATION">%1$s</xliff:g> ਦੁਆਰਾ ਵਿਵਸਥਿਤ ਕੀਤੀ ਜਾਂਦੀ ਹੈ। ਇਹ <xliff:g id="APPLICATION">%2$s</xliff:g> ਨਾਲ ਕਨੈਕਟ ਹੈ, ਜੋ ਈਮੇਲ, ਐਪਸ ਅਤੇ ਵੈਬਸਫ਼ਿਆਂ ਸਮੇਤ ਤੁਹਾਡੀ ਨੈੱਟਵਰਕ ਗਤੀਵਿਧੀ ਦਾ ਨਿਰੀਖਣ ਕਰ ਸਕਦੀ ਹੈ।\n\nਹੋਰ ਜਾਣਕਾਰੀ ਲਈ, ਆਪਣੇ ਪ੍ਰਬੰਧਕ ਨੂੰ ਸੰਪਰਕ ਕਰੋ।"</string>
    -     <string name="monitoring_description_app_personal_work" msgid="4946600443852045903">"ਤੁਹਾਡੀ ਕਾਰਜ ਪ੍ਰੋਫ਼ਾਈਲ <xliff:g id="ORGANIZATION">%1$s</xliff:g> ਦੁਆਰਾ ਵਿਵਸਥਿਤ ਕੀਤੀ ਜਾਂਦੀ ਹੈ। ਇਹ <xliff:g id="APPLICATION_WORK">%2$s</xliff:g> ਨਾਲ ਕਨੈਕਟ ਹੈ, ਜੋ ਈਮੇਲ, ਐਪਸ ਅਤੇ ਵੈਬਸਫ਼ਿਆਂ ਸਮੇਤ ਤੁਹਾਡੀ ਨੈੱਟਵਰਕ ਗਤੀਵਿਧੀ ਦਾ ਨਿਰੀਖਣ ਕਰ ਸਕਦੀ ਹੈ।\n\nਤੁਸੀਂ <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g> ਨਾਲ ਵੀ ਕਨੈਕਟ ਹੋ, ਜੋ ਤੁਹਾਡੀ ਨਿੱਜੀ ਨੈੱਟਵਰਕ ਗਤੀਵਿਧੀ ਦਾ ਨਿਰੀਖਣ ਕਰ ਸਕਦਾ ਹੈ।"</string>
    -     <string name="monitoring_description_vpn_app_device_owned" msgid="4970443827043261703">"ਤੁਹਾਡੀ ਡੀਵਾਈਸ <xliff:g id="ORGANIZATION">%1$s</xliff:g> ਦੁਆਰਾ ਵਿਵਸਥਿਤ ਕੀਤੀ ਜਾਂਦੀ ਹੈ।\n\nਪ੍ਰਬੰਧਕ ਸੈਟਿੰਗਾਂ, ਕਾਰਪੋਰੇਟ ਪਹੁੰਚ, ਐਪਸ, ਤੁਹਾਡੀ ਡੀਵਾਈਸ ਨਾਲ ਸੰਬੰਧਿਤ ਡੈਟਾ ਅਤੇ ਤੁਹਾਡੀ ਡੀਵਾਈਸ ਦੀ ਨਿਰਧਾਰਿਤ ਸਥਾਨ ਜਾਣਕਾਰੀ ਦਾ ਨਿਰੀਖਣ ਅਤੇ ਉਸਨੂੰ ਵਿਵਸਥਿਤ ਕਰ ਸਕਦਾ ਹੈ।\n\nਤੁਸੀਂ ਇੱਕ <xliff:g id="APPLICATION">%2$s</xliff:g> ਨਾਲ ਕਨੈਕਟ ਹੋ, ਜੋ ਈਮੇਲ, ਐਪਸ ਅਤੇ ਵੈੱਬਪੰਨੇ ਸਮੇਤ ਤੁਹਾਡੀ ਨੈੱਟਵਰਕ ਗਤੀਵਿਧੀ ਦੀ ਨਿਗਰਾਨੀ ਕਰ ਸਕਦਾ ਹੈ।\n\nਹੋਰ ਜਾਣਕਾਰੀ ਲਈ, ਆਪਣੇ ਪ੍ਰਬੰਧਕ ਨੂੰ ਸੰਪਰਕ ਕਰੋ।"</string>
    -@@ -492,8 +494,6 @@
    -     <string name="clock_seconds_desc" msgid="6282693067130470675">"ਸਥਿਤੀ ਬਾਰ ਵਿੱਚ ਘੜੀ ਸਕਿੰਟ ਦਿਖਾਓ। ਬੈਟਰੀ ਸਮਰੱਥਾ ਤੇ ਅਸਰ ਪੈ ਸਕਦਾ ਹੈ।"</string>
    -     <string name="qs_rearrange" msgid="8060918697551068765">"ਤਤਕਾਲ ਸੈਟਿੰਗਾਂ ਨੂੰ ਦੁਬਾਰਾ ਕ੍ਰਮ ਦਿਓ"</string>
    -     <string name="show_brightness" msgid="6613930842805942519">"ਤਤਕਾਲ ਸੈਟਿੰਗਾਂ ਵਿੱਚ ਚਮਕ ਦਿਖਾਓ"</string>
    --    <string name="overview_nav_bar_gesture" msgid="8579814204727917764">"ਸਪਲਿਟ-ਸਕ੍ਰੀਨ ਸਵਾਈਪ-ਅੱਪ ਸੰਕੇਤ ਨੂੰ ਯੋਗ ਬਣਾਓ"</string>
    --    <string name="overview_nav_bar_gesture_desc" msgid="6329167382305102615">"ਰੂਪ-ਰੇਖਾ ਬਟਨ ਤੋਂ ਉੱਪਰ ਵੱਲ ਸਵਾਈਪ ਕਰਨ ਦੁਆਰਾ ਸਪਲਿਟ-ਸਕ੍ਰੀਨ ਵਿੱਚ ਦਾਖਲ ਹੋਣ ਲਈ ਸੰਕੇਤ ਨੂੰ ਯੋਗ ਬਣਾਓ"</string>
    -     <string name="experimental" msgid="6198182315536726162">"ਪ੍ਰਯੋਗਾਤਮਿਕ"</string>
    -     <string name="enable_bluetooth_title" msgid="5027037706500635269">"Bluetooth ਚਾਲੂ ਕਰੋ?"</string>
    -     <string name="enable_bluetooth_message" msgid="9106595990708985385">"ਆਪਣੇ ਟੈਬਲੇਟ ਨਾਲ ਆਪਣਾ ਕੀ-ਬੋਰਡ ਕਨੈਕਟ ਕਰਨ ਲਈ, ਤੁਹਾਨੂੰ ਪਹਿਲਾਂ Bluetooth ਚਾਲੂ ਕਰਨ ਦੀ ਜ਼ਰੂਰਤ ਹੈ।"</string>
    -@@ -651,4 +651,5 @@
    -     <string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"<xliff:g id="ID_1">%s</xliff:g> ਸੈਟਿੰਗਾਂ ਖੋਲ੍ਹੋ।"</string>
    -     <string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"ਸੈਟਿੰਗਾਂ ਦੇ ਕ੍ਰਮ ਦਾ ਸੰਪਾਦਨ ਕਰੋ।"</string>
    -     <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"<xliff:g id="ID_2">%2$d</xliff:g> ਦਾ <xliff:g id="ID_1">%1$d</xliff:g> ਪੰਨਾ"</string>
    -+    <string name="cant_silence_or_block" msgid="999689262131488625">"ਸੂਚਨਾਵਾਂ ਨੂੰ ਖਾਮੋਸ਼ ਜਾਂ ਬਲੌਕ ਨਹੀਂ ਕੀਤਾ ਜਾ ਸਕਦਾ"</string>
    - </resources>
    -diff --git a/packages/SystemUI/res/values-pl/strings.xml b/packages/SystemUI/res/values-pl/strings.xml
    -index c86d26c..46ab85b 100644
    ---- a/packages/SystemUI/res/values-pl/strings.xml
    -+++ b/packages/SystemUI/res/values-pl/strings.xml
    -@@ -240,7 +240,7 @@
    -     <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"Transmisja danych 4G została wstrzymana"</string>
    -     <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"Komórkowa transmisja danych została wstrzymana"</string>
    -     <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"Transmisja danych została wstrzymana"</string>
    --    <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"Ponieważ został osiągnięty ustawiony przez Ciebie limit danych, urządzenie wstrzymało użycie danych na pozostałą część tego cyklu.\n\nWznowienie może spowodować naliczenie opłat przez operatora."</string>
    -+    <string name="data_usage_disabled_dialog" msgid="1841738975235283398">"Osiągnięto ustawiony limit danych. Nie korzystasz już z komórkowej transmisji danych.\n\nJeśli włączysz ją ponownie, może zostać naliczona opłata za transmisję danych."</string>
    -     <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"Wznów"</string>
    -     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Brak internetu"</string>
    -     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi: połączono"</string>
    -@@ -408,6 +408,7 @@
    -     <string name="device_owned_footer" msgid="3802752663326030053">"Urządzenie może być monitorowane"</string>
    -     <string name="profile_owned_footer" msgid="8021888108553696069">"Profil może być monitorowany"</string>
    -     <string name="vpn_footer" msgid="2388611096129106812">"Sieć może być monitorowana"</string>
    -+    <string name="branded_vpn_footer" msgid="2168111859226496230">"Sieć może być monitorowana"</string>
    -     <string name="monitoring_title_device_owned" msgid="7121079311903859610">"Monitorowanie urządzeń"</string>
    -     <string name="monitoring_title_profile_owned" msgid="6790109874733501487">"Monitorowanie profilu"</string>
    -     <string name="monitoring_title" msgid="169206259253048106">"Monitorowanie sieci"</string>
    -@@ -420,6 +421,7 @@
    -     <string name="legacy_vpn_name" msgid="6604123105765737830">"VPN"</string>
    -     <string name="monitoring_description_app" msgid="6259179342284742878">"Masz połączenie z aplikacją <xliff:g id="APPLICATION">%1$s</xliff:g>, która może monitorować Twoją aktywność w sieci, w tym e-maile, aplikacje i strony internetowe."</string>
    -     <string name="monitoring_description_app_personal" msgid="484599052118316268">"Masz połączenie z aplikacją <xliff:g id="APPLICATION">%1$s</xliff:g>, która może monitorować Twoją prywatną aktywność w sieci, w tym e-maile, aplikacje i strony internetowe."</string>
    -+    <string name="branded_monitoring_description_app_personal" msgid="2669518213949202599">"Masz połączenie z aplikacją <xliff:g id="APPLICATION">%1$s</xliff:g>, która może monitorować Twoją prywatną aktywność w sieci, w tym e-maile, aplikacje i strony internetowe."</string>
    -     <string name="monitoring_description_app_work" msgid="1754325860918060897">"Twoim profilem do pracy zarządza <xliff:g id="ORGANIZATION">%1$s</xliff:g>. Profil jest połączony z aplikacją <xliff:g id="APPLICATION">%2$s</xliff:g>, która może monitorować Twoją aktywność w sieci związaną z pracą, w tym e-maile, aplikacje i strony internetowe.\n\nAby dowiedzieć się więcej, skontaktuj się z administratorem."</string>
    -     <string name="monitoring_description_app_personal_work" msgid="4946600443852045903">"Twoim profilem do pracy zarządza <xliff:g id="ORGANIZATION">%1$s</xliff:g>. Profil jest połączony z aplikacją <xliff:g id="APPLICATION_WORK">%2$s</xliff:g>, która może monitorować Twoją aktywność w sieci związaną z pracą, w tym e-maile, aplikacje i strony internetowe.\n\nMasz też połączenie z aplikacją <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g>, która może monitorować Twoją prywatną aktywność w sieci."</string>
    -     <string name="monitoring_description_vpn_app_device_owned" msgid="4970443827043261703">"Twoim urządzeniem zarządza <xliff:g id="ORGANIZATION">%1$s</xliff:g>.\n\nAdministrator może monitorować ustawienia, firmowe uprawnienia dostępu, aplikacje, dane powiązane z urządzeniem i informacje o jego lokalizacji oraz nimi zarządzać.\n\nMasz połączenie z aplikacją <xliff:g id="APPLICATION">%2$s</xliff:g>, która może monitorować Twoją aktywność w sieci, w tym e-maile, aplikacje i strony internetowe.\n\nAby dowiedzieć się więcej, skontaktuj się z administratorem."</string>
    -@@ -496,8 +498,6 @@
    -     <string name="clock_seconds_desc" msgid="6282693067130470675">"Pokaż sekundy na zegarku na pasku stanu. Może mieć wpływ na czas pracy baterii."</string>
    -     <string name="qs_rearrange" msgid="8060918697551068765">"Uporządkuj Szybkie ustawienia"</string>
    -     <string name="show_brightness" msgid="6613930842805942519">"Pokaż jasność w Szybkich ustawieniach"</string>
    --    <string name="overview_nav_bar_gesture" msgid="8579814204727917764">"Włącz dzielenie ekranu gestem przesunięcia w górę"</string>
    --    <string name="overview_nav_bar_gesture_desc" msgid="6329167382305102615">"Włącz dzielenie ekranu po wykonaniu gestu przesunięcia palcem w górę od przycisku Przegląd"</string>
    -     <string name="experimental" msgid="6198182315536726162">"Eksperymentalne"</string>
    -     <string name="enable_bluetooth_title" msgid="5027037706500635269">"Włączyć Bluetooth?"</string>
    -     <string name="enable_bluetooth_message" msgid="9106595990708985385">"Aby połączyć klawiaturę z tabletem, musisz najpierw włączyć Bluetooth."</string>
    -@@ -655,4 +655,5 @@
    -     <string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"Otwórz ustawienia: <xliff:g id="ID_1">%s</xliff:g>."</string>
    -     <string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"Edytuj kolejność ustawień."</string>
    -     <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"Strona <xliff:g id="ID_1">%1$d</xliff:g> z <xliff:g id="ID_2">%2$d</xliff:g>"</string>
    -+    <string name="cant_silence_or_block" msgid="999689262131488625">"Nie można wyciszyć ani zablokować powiadomień"</string>
    - </resources>
    -diff --git a/packages/SystemUI/res/values-pt-rBR/strings.xml b/packages/SystemUI/res/values-pt-rBR/strings.xml
    -index 199dbad..25aeb5f 100644
    ---- a/packages/SystemUI/res/values-pt-rBR/strings.xml
    -+++ b/packages/SystemUI/res/values-pt-rBR/strings.xml
    -@@ -240,7 +240,7 @@
    -     <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"Os dados 4G foram pausados"</string>
    -     <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"Os dados da rede celular foram pausados"</string>
    -     <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"Os dados foram pausados"</string>
    --    <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"Como seu limite de dados definido foi atingido, o dispositivo pausou o uso de dados para o restante deste ciclo.\n\nA retomada pode gerar cobranças por parte da sua operadora."</string>
    -+    <string name="data_usage_disabled_dialog" msgid="1841738975235283398">"O limite de dados que você definiu foi atingido. Você não está mais usando os dados da rede celular.\n\nSe retomar o uso de dados, cobranças poderão ser aplicadas."</string>
    -     <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"Retomar"</string>
    -     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Sem conexão à Internet"</string>
    -     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi conectado"</string>
    -@@ -406,6 +406,7 @@
    -     <string name="device_owned_footer" msgid="3802752663326030053">"O dispositivo pode ser monitorado"</string>
    -     <string name="profile_owned_footer" msgid="8021888108553696069">"O perfil pode ser monitorado"</string>
    -     <string name="vpn_footer" msgid="2388611096129106812">"A rede pode ser monitorada"</string>
    -+    <string name="branded_vpn_footer" msgid="2168111859226496230">"A rede pode ser monitorada"</string>
    -     <string name="monitoring_title_device_owned" msgid="7121079311903859610">"Monitoramento de dispositivos"</string>
    -     <string name="monitoring_title_profile_owned" msgid="6790109874733501487">"Monitoramento de perfis"</string>
    -     <string name="monitoring_title" msgid="169206259253048106">"Monitoramento de rede"</string>
    -@@ -418,6 +419,7 @@
    -     <string name="legacy_vpn_name" msgid="6604123105765737830">"VPN"</string>
    -     <string name="monitoring_description_app" msgid="6259179342284742878">"Você está conectado a <xliff:g id="APPLICATION">%1$s</xliff:g>, que pode monitorar sua atividade na rede, incluindo e-mails, apps e websites."</string>
    -     <string name="monitoring_description_app_personal" msgid="484599052118316268">"Você está conectado a <xliff:g id="APPLICATION">%1$s</xliff:g>, que pode monitorar sua atividade pessoal na rede, incluindo e-mails, apps e websites."</string>
    -+    <string name="branded_monitoring_description_app_personal" msgid="2669518213949202599">"Você está conectado a <xliff:g id="APPLICATION">%1$s</xliff:g>, que pode monitorar sua atividade pessoal na rede, incluindo e-mails, apps e websites."</string>
    -     <string name="monitoring_description_app_work" msgid="1754325860918060897">"Seu perfil de trabalho é gerenciado por <xliff:g id="ORGANIZATION">%1$s</xliff:g>. Ele está conectado a <xliff:g id="APPLICATION">%2$s</xliff:g>, que pode monitorar sua atividade profissional na rede, incluindo e-mails, apps e websites.\n\nPara ver mais informações, entre em contato com seu administrador."</string>
    -     <string name="monitoring_description_app_personal_work" msgid="4946600443852045903">"Seu perfil de trabalho é gerenciado por <xliff:g id="ORGANIZATION">%1$s</xliff:g>. Ele está conectado a <xliff:g id="APPLICATION_WORK">%2$s</xliff:g>, que pode monitorar sua atividade profissional na rede, incluindo e-mails, apps e websites.\n\nVocê também está conectado a <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g>, que pode monitorar sua atividade pessoal na rede."</string>
    -     <string name="monitoring_description_vpn_app_device_owned" msgid="4970443827043261703">"Seu dispositivo é gerenciado por <xliff:g id="ORGANIZATION">%1$s</xliff:g>.\n\nSeu administrador pode monitorar e gerenciar configurações, acesso corporativo, apps, dados associados ao seu dispositivo e informações sobre localização do dispositivo.\n\nVocê está conectado a <xliff:g id="APPLICATION">%2$s</xliff:g>, que pode monitorar suas atividades de rede, incluindo e-mails, apps e websites.\n\nPara ver mais informações, entre em contato com seu administrador."</string>
    -@@ -494,8 +496,6 @@
    -     <string name="clock_seconds_desc" msgid="6282693067130470675">"Mostrar segundos do relógio na barra de status. Pode afetar a duração da bateria."</string>
    -     <string name="qs_rearrange" msgid="8060918697551068765">"Reorganizar \"Configurações rápidas\""</string>
    -     <string name="show_brightness" msgid="6613930842805942519">"Mostrar brilho nas \"Configurações rápidas\""</string>
    --    <string name="overview_nav_bar_gesture" msgid="8579814204727917764">"Ativar gesto para dividir a tela ao deslizar para cima"</string>
    --    <string name="overview_nav_bar_gesture_desc" msgid="6329167382305102615">"Ativa o gesto para entrar no modo de tela dividida deslizando a partir do botão \"Visão geral\""</string>
    -     <string name="experimental" msgid="6198182315536726162">"Experimentais"</string>
    -     <string name="enable_bluetooth_title" msgid="5027037706500635269">"Ativar o Bluetooth?"</string>
    -     <string name="enable_bluetooth_message" msgid="9106595990708985385">"Para conectar o teclado ao tablet, é preciso primeiro ativar o Bluetooth."</string>
    -@@ -653,4 +653,5 @@
    -     <string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"Abrir configurações de <xliff:g id="ID_1">%s</xliff:g>."</string>
    -     <string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"Editar ordem das configurações."</string>
    -     <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"Página <xliff:g id="ID_1">%1$d</xliff:g> de <xliff:g id="ID_2">%2$d</xliff:g>"</string>
    -+    <string name="cant_silence_or_block" msgid="999689262131488625">"Não é possível silenciar ou bloquear as notificações"</string>
    - </resources>
    -diff --git a/packages/SystemUI/res/values-pt-rPT/strings.xml b/packages/SystemUI/res/values-pt-rPT/strings.xml
    -index d3d7f24..79f1c7d 100644
    ---- a/packages/SystemUI/res/values-pt-rPT/strings.xml
    -+++ b/packages/SystemUI/res/values-pt-rPT/strings.xml
    -@@ -238,7 +238,7 @@
    -     <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"Dados 4G em pausa"</string>
    -     <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"Dados de redes móveis em pausa"</string>
    -     <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"Dados em pausa"</string>
    --    <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"Uma vez que foi atingido o limite de dados definido, foi interrompida a utilização de dados no seu dispositivo durante o tempo restante deste ciclo.\n\nSe retomar a utilização, o seu operador pode efetuar cobranças."</string>
    -+    <string name="data_usage_disabled_dialog" msgid="1841738975235283398">"O limite de dados definido foi atingido. Já não está a utilizar dados móveis.\n\nSe retomar, podem aplicar-se custos relativos à utilização de dados."</string>
    -     <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"Retomar"</string>
    -     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Sem ligação internet"</string>
    -     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi ligado"</string>
    -@@ -404,6 +404,7 @@
    -     <string name="device_owned_footer" msgid="3802752663326030053">"O dispositivo pode ser monitorizado"</string>
    -     <string name="profile_owned_footer" msgid="8021888108553696069">"O perfil pode ser monitorizado"</string>
    -     <string name="vpn_footer" msgid="2388611096129106812">"A rede pode ser monitorizada"</string>
    -+    <string name="branded_vpn_footer" msgid="2168111859226496230">"A rede pode ser monitorizada"</string>
    -     <string name="monitoring_title_device_owned" msgid="7121079311903859610">"Monitorização de dispositivos"</string>
    -     <string name="monitoring_title_profile_owned" msgid="6790109874733501487">"Monitorização de perfis"</string>
    -     <string name="monitoring_title" msgid="169206259253048106">"Monitorização da rede"</string>
    -@@ -416,6 +417,7 @@
    -     <string name="legacy_vpn_name" msgid="6604123105765737830">"VPN"</string>
    -     <string name="monitoring_description_app" msgid="6259179342284742878">"Está ligado a <xliff:g id="APPLICATION">%1$s</xliff:g>, que pode monitorizar a atividade da rede, incluindo emails, aplicações e Websites."</string>
    -     <string name="monitoring_description_app_personal" msgid="484599052118316268">"Está ligado a <xliff:g id="APPLICATION">%1$s</xliff:g>, que pode monitorizar a atividade da rede pessoal, incluindo emails, aplicações e Websites."</string>
    -+    <string name="branded_monitoring_description_app_personal" msgid="2669518213949202599">"Está ligado ao <xliff:g id="APPLICATION">%1$s</xliff:g>, que pode monitorizar a atividade da rede pessoal, incluindo emails, aplicações e Websites."</string>
    -     <string name="monitoring_description_app_work" msgid="1754325860918060897">"O seu perfil de trabalho é gerido por <xliff:g id="ORGANIZATION">%1$s</xliff:g>. Está ligado a <xliff:g id="APPLICATION">%2$s</xliff:g>, que pode monitorizar a atividade da rede de trabalho, incluindo emails, aplicações e Websites.\n\nPara obter mais informações, contacte o administrador."</string>
    -     <string name="monitoring_description_app_personal_work" msgid="4946600443852045903">"O seu perfil de trabalho é gerido por <xliff:g id="ORGANIZATION">%1$s</xliff:g>. Está ligado a <xliff:g id="APPLICATION_WORK">%2$s</xliff:g>, que pode monitorizar a atividade da rede de trabalho, incluindo emails, aplicações e Websites.\n\nTambém está ligado a <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g>, que pode monitorizar a atividade da rede pessoal."</string>
    -     <string name="monitoring_description_vpn_app_device_owned" msgid="4970443827043261703">"O seu dispositivo é gerido por <xliff:g id="ORGANIZATION">%1$s</xliff:g>.\n\nO seu administrador pode monitorizar e gerir as definições, o acesso empresarial, as aplicações, os dados associados ao dispositivo e as informações de localização do dispositivo.\n\nEstá ligado a <xliff:g id="APPLICATION">%2$s</xliff:g>, que pode monitorizar a atividade da rede, incluindo emails, aplicações e Websites.\n\nPara obter mais informações, contacte o administrador."</string>
    -@@ -492,8 +494,6 @@
    -     <string name="clock_seconds_desc" msgid="6282693067130470675">"Mostrar segundos do relógio na barra de estado. Pode afetar a autonomia da bateria."</string>
    -     <string name="qs_rearrange" msgid="8060918697551068765">"Reorganizar as Definições rápidas"</string>
    -     <string name="show_brightness" msgid="6613930842805942519">"Mostrar luminosidade nas Definições rápidas"</string>
    --    <string name="overview_nav_bar_gesture" msgid="8579814204727917764">"Ativar gesto de deslize rápido para cima do ecrã dividido"</string>
    --    <string name="overview_nav_bar_gesture_desc" msgid="6329167382305102615">"Ativar o gesto para aceder ao ecrã dividido ao deslizar rapidamente para cima a partir do botão Vista geral"</string>
    -     <string name="experimental" msgid="6198182315536726162">"Experimental"</string>
    -     <string name="enable_bluetooth_title" msgid="5027037706500635269">"Pretende ativar o Bluetooth?"</string>
    -     <string name="enable_bluetooth_message" msgid="9106595990708985385">"Para ligar o teclado ao tablet, tem de ativar primeiro o Bluetooth."</string>
    -@@ -651,4 +651,5 @@
    -     <string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"Abrir as definições de <xliff:g id="ID_1">%s</xliff:g>."</string>
    -     <string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"Editar a ordem das definições."</string>
    -     <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"Página <xliff:g id="ID_1">%1$d</xliff:g> de <xliff:g id="ID_2">%2$d</xliff:g>"</string>
    -+    <string name="cant_silence_or_block" msgid="999689262131488625">"Não é possível silenciar ou bloquear as notificações"</string>
    - </resources>
    -diff --git a/packages/SystemUI/res/values-pt/strings.xml b/packages/SystemUI/res/values-pt/strings.xml
    -index 199dbad..25aeb5f 100644
    ---- a/packages/SystemUI/res/values-pt/strings.xml
    -+++ b/packages/SystemUI/res/values-pt/strings.xml
    -@@ -240,7 +240,7 @@
    -     <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"Os dados 4G foram pausados"</string>
    -     <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"Os dados da rede celular foram pausados"</string>
    -     <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"Os dados foram pausados"</string>
    --    <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"Como seu limite de dados definido foi atingido, o dispositivo pausou o uso de dados para o restante deste ciclo.\n\nA retomada pode gerar cobranças por parte da sua operadora."</string>
    -+    <string name="data_usage_disabled_dialog" msgid="1841738975235283398">"O limite de dados que você definiu foi atingido. Você não está mais usando os dados da rede celular.\n\nSe retomar o uso de dados, cobranças poderão ser aplicadas."</string>
    -     <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"Retomar"</string>
    -     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Sem conexão à Internet"</string>
    -     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi conectado"</string>
    -@@ -406,6 +406,7 @@
    -     <string name="device_owned_footer" msgid="3802752663326030053">"O dispositivo pode ser monitorado"</string>
    -     <string name="profile_owned_footer" msgid="8021888108553696069">"O perfil pode ser monitorado"</string>
    -     <string name="vpn_footer" msgid="2388611096129106812">"A rede pode ser monitorada"</string>
    -+    <string name="branded_vpn_footer" msgid="2168111859226496230">"A rede pode ser monitorada"</string>
    -     <string name="monitoring_title_device_owned" msgid="7121079311903859610">"Monitoramento de dispositivos"</string>
    -     <string name="monitoring_title_profile_owned" msgid="6790109874733501487">"Monitoramento de perfis"</string>
    -     <string name="monitoring_title" msgid="169206259253048106">"Monitoramento de rede"</string>
    -@@ -418,6 +419,7 @@
    -     <string name="legacy_vpn_name" msgid="6604123105765737830">"VPN"</string>
    -     <string name="monitoring_description_app" msgid="6259179342284742878">"Você está conectado a <xliff:g id="APPLICATION">%1$s</xliff:g>, que pode monitorar sua atividade na rede, incluindo e-mails, apps e websites."</string>
    -     <string name="monitoring_description_app_personal" msgid="484599052118316268">"Você está conectado a <xliff:g id="APPLICATION">%1$s</xliff:g>, que pode monitorar sua atividade pessoal na rede, incluindo e-mails, apps e websites."</string>
    -+    <string name="branded_monitoring_description_app_personal" msgid="2669518213949202599">"Você está conectado a <xliff:g id="APPLICATION">%1$s</xliff:g>, que pode monitorar sua atividade pessoal na rede, incluindo e-mails, apps e websites."</string>
    -     <string name="monitoring_description_app_work" msgid="1754325860918060897">"Seu perfil de trabalho é gerenciado por <xliff:g id="ORGANIZATION">%1$s</xliff:g>. Ele está conectado a <xliff:g id="APPLICATION">%2$s</xliff:g>, que pode monitorar sua atividade profissional na rede, incluindo e-mails, apps e websites.\n\nPara ver mais informações, entre em contato com seu administrador."</string>
    -     <string name="monitoring_description_app_personal_work" msgid="4946600443852045903">"Seu perfil de trabalho é gerenciado por <xliff:g id="ORGANIZATION">%1$s</xliff:g>. Ele está conectado a <xliff:g id="APPLICATION_WORK">%2$s</xliff:g>, que pode monitorar sua atividade profissional na rede, incluindo e-mails, apps e websites.\n\nVocê também está conectado a <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g>, que pode monitorar sua atividade pessoal na rede."</string>
    -     <string name="monitoring_description_vpn_app_device_owned" msgid="4970443827043261703">"Seu dispositivo é gerenciado por <xliff:g id="ORGANIZATION">%1$s</xliff:g>.\n\nSeu administrador pode monitorar e gerenciar configurações, acesso corporativo, apps, dados associados ao seu dispositivo e informações sobre localização do dispositivo.\n\nVocê está conectado a <xliff:g id="APPLICATION">%2$s</xliff:g>, que pode monitorar suas atividades de rede, incluindo e-mails, apps e websites.\n\nPara ver mais informações, entre em contato com seu administrador."</string>
    -@@ -494,8 +496,6 @@
    -     <string name="clock_seconds_desc" msgid="6282693067130470675">"Mostrar segundos do relógio na barra de status. Pode afetar a duração da bateria."</string>
    -     <string name="qs_rearrange" msgid="8060918697551068765">"Reorganizar \"Configurações rápidas\""</string>
    -     <string name="show_brightness" msgid="6613930842805942519">"Mostrar brilho nas \"Configurações rápidas\""</string>
    --    <string name="overview_nav_bar_gesture" msgid="8579814204727917764">"Ativar gesto para dividir a tela ao deslizar para cima"</string>
    --    <string name="overview_nav_bar_gesture_desc" msgid="6329167382305102615">"Ativa o gesto para entrar no modo de tela dividida deslizando a partir do botão \"Visão geral\""</string>
    -     <string name="experimental" msgid="6198182315536726162">"Experimentais"</string>
    -     <string name="enable_bluetooth_title" msgid="5027037706500635269">"Ativar o Bluetooth?"</string>
    -     <string name="enable_bluetooth_message" msgid="9106595990708985385">"Para conectar o teclado ao tablet, é preciso primeiro ativar o Bluetooth."</string>
    -@@ -653,4 +653,5 @@
    -     <string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"Abrir configurações de <xliff:g id="ID_1">%s</xliff:g>."</string>
    -     <string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"Editar ordem das configurações."</string>
    -     <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"Página <xliff:g id="ID_1">%1$d</xliff:g> de <xliff:g id="ID_2">%2$d</xliff:g>"</string>
    -+    <string name="cant_silence_or_block" msgid="999689262131488625">"Não é possível silenciar ou bloquear as notificações"</string>
    - </resources>
    -diff --git a/packages/SystemUI/res/values-ro/strings.xml b/packages/SystemUI/res/values-ro/strings.xml
    -index f59721a..408edf3 100644
    ---- a/packages/SystemUI/res/values-ro/strings.xml
    -+++ b/packages/SystemUI/res/values-ro/strings.xml
    -@@ -241,7 +241,7 @@
    -     <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"Conexiunea de date 4G este întreruptă"</string>
    -     <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"Conexiunea de date mobile este întreruptă"</string>
    -     <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"Conexiunea de date este întreruptă"</string>
    --    <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"Deoarece limita setată pentru date a fost atinsă, dispozitivul a întrerupt utilizarea datelor pentru restul acestui ciclu.\n\nReluarea utilizării de date poate genera aplicarea de taxe de către operator."</string>
    -+    <string name="data_usage_disabled_dialog" msgid="1841738975235283398">"A fost atinsă limita de date setată. Datele mobile nu mai sunt folosite \n\nDacă reluați, este posibil să se aplice taxe pentru utilizarea datelor."</string>
    -     <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"Reluați"</string>
    -     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Fără conex. internet"</string>
    -     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi conectat"</string>
    -@@ -329,7 +329,7 @@
    -     <string name="recents_empty_message" msgid="808480104164008572">"Niciun element recent"</string>
    -     <string name="recents_empty_message_dismissed_all" msgid="2791312568666558651">"Ați șters tot"</string>
    -     <string name="recents_app_info_button_label" msgid="2890317189376000030">"Informații despre aplicație"</string>
    --    <string name="recents_lock_to_app_button_label" msgid="6942899049072506044">"fixare pe ecran"</string>
    -+    <string name="recents_lock_to_app_button_label" msgid="6942899049072506044">"fixarea ecranului"</string>
    -     <string name="recents_search_bar_label" msgid="8074997400187836677">"căutare"</string>
    -     <string name="recents_launch_error_message" msgid="2969287838120550506">"<xliff:g id="APP">%s</xliff:g> nu a putut porni."</string>
    -     <string name="recents_launch_disabled_message" msgid="1624523193008871793">"Aplicația <xliff:g id="APP">%s</xliff:g> este dezactivată în modul sigur."</string>
    -@@ -408,6 +408,7 @@
    -     <string name="device_owned_footer" msgid="3802752663326030053">"Dispozitivul poate fi monitorizat"</string>
    -     <string name="profile_owned_footer" msgid="8021888108553696069">"Profilul poate fi monitorizat"</string>
    -     <string name="vpn_footer" msgid="2388611096129106812">"Rețeaua poate fi monitorizată"</string>
    -+    <string name="branded_vpn_footer" msgid="2168111859226496230">"Este posibil ca rețeaua să fie monitorizată"</string>
    -     <string name="monitoring_title_device_owned" msgid="7121079311903859610">"Monitorizarea dispozitivului"</string>
    -     <string name="monitoring_title_profile_owned" msgid="6790109874733501487">"Monitorizarea profilului"</string>
    -     <string name="monitoring_title" msgid="169206259253048106">"Monitorizarea rețelei"</string>
    -@@ -420,6 +421,7 @@
    -     <string name="legacy_vpn_name" msgid="6604123105765737830">"VPN"</string>
    -     <string name="monitoring_description_app" msgid="6259179342284742878">"Sunteți conectat(ă) la <xliff:g id="APPLICATION">%1$s</xliff:g>, care vă poate monitoriza activitatea în rețea, inclusiv e-mailurile, aplicațiile și site-urile."</string>
    -     <string name="monitoring_description_app_personal" msgid="484599052118316268">"Sunteți conectat(ă) la <xliff:g id="APPLICATION">%1$s</xliff:g>, care vă poate monitoriza activitatea în rețeaua personală, inclusiv e-mailurile, aplicațiile și site-urile."</string>
    -+    <string name="branded_monitoring_description_app_personal" msgid="2669518213949202599">"V-ați conectat la aplicația <xliff:g id="APPLICATION">%1$s</xliff:g>, care vă poate monitoriza activitatea personală în rețea, inclusiv e-mailurile, aplicațiile și site-urile accesate."</string>
    -     <string name="monitoring_description_app_work" msgid="1754325860918060897">"Profilul de serviciu este gestionat de <xliff:g id="ORGANIZATION">%1$s</xliff:g>. Este conectat la <xliff:g id="APPLICATION">%2$s</xliff:g>, care vă poate monitoriza activitatea în rețeaua de serviciu, inclusiv e-mailurile, aplicațiile și site-urile.\n\nPentru mai multe informații, contactați administratorul."</string>
    -     <string name="monitoring_description_app_personal_work" msgid="4946600443852045903">"Profilul de serviciu este gestionat de <xliff:g id="ORGANIZATION">%1$s</xliff:g>. Este conectat la <xliff:g id="APPLICATION_WORK">%2$s</xliff:g>, care vă poate monitoriza activitatea în rețeaua de serviciu, inclusiv e-mailurile, aplicațiile și site-urile.\n\nDe asemenea, sunteți conectat(ă) la <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g>, care vă poate monitoriza activitatea în rețeaua personală."</string>
    -     <string name="monitoring_description_vpn_app_device_owned" msgid="4970443827043261703">"Dispozitivul este gestionat de <xliff:g id="ORGANIZATION">%1$s</xliff:g>.\n\nAdministratorul poate monitoriza și gestiona setările, accesul la rețeaua companiei, aplicațiile, datele asociate cu dispozitivul și informațiile privind locația dispozitivului.\n\nSunteți conectat(ă) la <xliff:g id="APPLICATION">%2$s</xliff:g>, care vă poate monitoriza activitatea în rețea, inclusiv e-mailurile, aplicațiile și site-urile.\n\nPentru mai multe informații, contactați administratorul."</string>
    -@@ -496,8 +498,6 @@
    -     <string name="clock_seconds_desc" msgid="6282693067130470675">"Afișează secundele pe ceas în bara de stare. Poate afecta autonomia bateriei."</string>
    -     <string name="qs_rearrange" msgid="8060918697551068765">"Rearanjați Setările rapide"</string>
    -     <string name="show_brightness" msgid="6613930842805942519">"Afișați luminozitatea în Setările rapide"</string>
    --    <string name="overview_nav_bar_gesture" msgid="8579814204727917764">"Activați gestul de accesare a ecranului împărțit prin glisare în sus"</string>
    --    <string name="overview_nav_bar_gesture_desc" msgid="6329167382305102615">"Activați gestul de accesare a ecranului împărțit prin glisarea în sus de la butonul Recente"</string>
    -     <string name="experimental" msgid="6198182315536726162">"Experimentale"</string>
    -     <string name="enable_bluetooth_title" msgid="5027037706500635269">"Activați Bluetooth?"</string>
    -     <string name="enable_bluetooth_message" msgid="9106595990708985385">"Pentru a conecta tastatura la tabletă, mai întâi trebuie să activați Bluetooth."</string>
    -@@ -655,4 +655,5 @@
    -     <string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"Deschideți setările <xliff:g id="ID_1">%s</xliff:g>."</string>
    -     <string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"Editați ordinea setărilor."</string>
    -     <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"Pagina <xliff:g id="ID_1">%1$d</xliff:g> din <xliff:g id="ID_2">%2$d</xliff:g>"</string>
    -+    <string name="cant_silence_or_block" msgid="999689262131488625">"Notificările nu pot fi dezactivate sau blocate"</string>
    - </resources>
    -diff --git a/packages/SystemUI/res/values-ru/strings.xml b/packages/SystemUI/res/values-ru/strings.xml
    -index bee7eed..7efd8fa 100644
    ---- a/packages/SystemUI/res/values-ru/strings.xml
    -+++ b/packages/SystemUI/res/values-ru/strings.xml
    -@@ -242,7 +242,7 @@
    -     <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"Передача данных 4G приостановлена"</string>
    -     <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"Передача мобильных данных приостановлена"</string>
    -     <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"Передача данных приостановлена"</string>
    --    <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"Передача данных выключена до конца цикла, поскольку достигнут установленный вами лимит.\n\nЕсли вы возобновите ее, оператор может взимать плату за дополнительный расход трафика."</string>
    -+    <string name="data_usage_disabled_dialog" msgid="1841738975235283398">"Достигнут установленный вами лимит на передачу мобильных данных.\n\nЕсли вы продолжите, может взиматься дополнительная плата."</string>
    -     <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"Возобновить"</string>
    -     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Нет интернет-подключения"</string>
    -     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi подключено"</string>
    -@@ -410,6 +410,7 @@
    -     <string name="device_owned_footer" msgid="3802752663326030053">"Устройство может контролироваться"</string>
    -     <string name="profile_owned_footer" msgid="8021888108553696069">"Действия в профиле могут отслеживаться"</string>
    -     <string name="vpn_footer" msgid="2388611096129106812">"Сеть может отслеживаться"</string>
    -+    <string name="branded_vpn_footer" msgid="2168111859226496230">"Сеть может отслеживаться"</string>
    -     <string name="monitoring_title_device_owned" msgid="7121079311903859610">"Отслеживание устройств"</string>
    -     <string name="monitoring_title_profile_owned" msgid="6790109874733501487">"Мониторинг профиля"</string>
    -     <string name="monitoring_title" msgid="169206259253048106">"Отслеживание сетей"</string>
    -@@ -422,6 +423,7 @@
    -     <string name="legacy_vpn_name" msgid="6604123105765737830">"Сеть VPN"</string>
    -     <string name="monitoring_description_app" msgid="6259179342284742878">"Запущено приложение \"<xliff:g id="APPLICATION">%1$s</xliff:g>\", которое может отслеживать ваши действия в Интернете, включая работу с электронной почтой, приложениями и веб-сайтами."</string>
    -     <string name="monitoring_description_app_personal" msgid="484599052118316268">"Запущено приложение \"<xliff:g id="APPLICATION">%1$s</xliff:g>\", которое может отслеживать ваши действия в Интернете (выполняемые в личном профиле), включая работу с электронной почтой, приложениями и веб-сайтами."</string>
    -+    <string name="branded_monitoring_description_app_personal" msgid="2669518213949202599">"Запущено приложение \"<xliff:g id="APPLICATION">%1$s</xliff:g>\", которое может отслеживать ваши действия в сети, включая работу с электронной почтой, приложениями и веб-сайтами."</string>
    -     <string name="monitoring_description_app_work" msgid="1754325860918060897">"Вашим рабочим профилем управляет \"<xliff:g id="ORGANIZATION">%1$s</xliff:g>\". Приложение \"<xliff:g id="APPLICATION">%2$s</xliff:g>\" может отслеживать ваши действия в Интернете, включая работу с электронной почтой, приложениями и веб-сайтами.\n\nЗа дополнительной информацией обратитесь к своему администратору."</string>
    -     <string name="monitoring_description_app_personal_work" msgid="4946600443852045903">"Вашим рабочим профилем управляет \"<xliff:g id="ORGANIZATION">%1$s</xliff:g>\". Приложение \"<xliff:g id="APPLICATION_WORK">%2$s</xliff:g>\" может отслеживать ваши действия в Интернете, включая работу с электронной почтой, приложениями и веб-сайтами.\n\nПриложение \"<xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g>\" может отслеживать ваши действия в Интернете, выполняемые в личном профиле."</string>
    -     <string name="monitoring_description_vpn_app_device_owned" msgid="4970443827043261703">"Вашим корпоративным профилем управляет <xliff:g id="ORGANIZATION">%1$s</xliff:g>.\n\nАдминистратор может управлять настройками, корпоративным доступом, приложениями, данными на вашем устройстве, в том числе геоданными, а также просматривать соответствующие сведения.\n\nПриложение <xliff:g id="APPLICATION">%2$s</xliff:g> также может отслеживать ваши действия в сети, включая работу с электронной почтой, приложениями и веб-сайтами.\n\nЗа подробностями обратитесь к своему администратору."</string>
    -@@ -498,8 +500,6 @@
    -     <string name="clock_seconds_desc" msgid="6282693067130470675">"Показывать в строке состояния время с точностью до секунды (заряд батареи может расходоваться быстрее)."</string>
    -     <string name="qs_rearrange" msgid="8060918697551068765">"Изменить порядок Быстрых настроек"</string>
    -     <string name="show_brightness" msgid="6613930842805942519">"Добавить яркость в Быстрые настройки"</string>
    --    <string name="overview_nav_bar_gesture" msgid="8579814204727917764">"Разделять экран пролистыванием вверх"</string>
    --    <string name="overview_nav_bar_gesture_desc" msgid="6329167382305102615">"Включить разделение экрана пролистыванием вверх с кнопки \"Обзор\""</string>
    -     <string name="experimental" msgid="6198182315536726162">"Экспериментальная функция"</string>
    -     <string name="enable_bluetooth_title" msgid="5027037706500635269">"Подключение по Bluetooth"</string>
    -     <string name="enable_bluetooth_message" msgid="9106595990708985385">"Чтобы подключить клавиатуру к планшету, включите Bluetooth."</string>
    -@@ -657,4 +657,5 @@
    -     <string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"Открыть настройки <xliff:g id="ID_1">%s</xliff:g>."</string>
    -     <string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"Изменить порядок быстрых настроек."</string>
    -     <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"Страница <xliff:g id="ID_1">%1$d</xliff:g> из <xliff:g id="ID_2">%2$d</xliff:g>"</string>
    -+    <string name="cant_silence_or_block" msgid="999689262131488625">"Уведомления нельзя блокировать и показывать без звука"</string>
    - </resources>
    -diff --git a/packages/SystemUI/res/values-si-rLK/strings.xml b/packages/SystemUI/res/values-si-rLK/strings.xml
    -index 0811f5e..749231d 100644
    ---- a/packages/SystemUI/res/values-si-rLK/strings.xml
    -+++ b/packages/SystemUI/res/values-si-rLK/strings.xml
    -@@ -238,7 +238,7 @@
    -     <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"4G දත්ත විරාම කර ඇත"</string>
    -     <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"සෙලියුලර් දත්ත විරාම කර ඇත"</string>
    -     <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"දත්ත විරාම කර ඇත"</string>
    --    <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"ඔබ සකසා ඇති දත්ත සීමාවට ළඟා වූ නිසා, උපාංගය මගින් මෙම චක්‍රයේ ඉතිරිය සඳහා දත්ත භාවිතය විරාම කර ඇත. \n\nනැවත පටන් ගැනීමෙන් ඔබගේ වාහකයෙන් අය කිරීම් වලට පොළඹවනු ඇත."</string>
    -+    <string name="data_usage_disabled_dialog" msgid="1841738975235283398">"ඔබ සැකසූ දත්ත සීමාව ළඟා වී ඇත. ඔබ තවදුරටත් සෙලියුලර් දත්ත භාවිත නොකරයි. \n\nඔබ නැවත ආරම්භ කළහොත්, දත්ත භාවිතය සඳහා ගාස්තු අදාළ විය හැකිය."</string>
    -     <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"නැවත පටන්ගන්න"</string>
    -     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"අන්තර්ජාල සම්බන්ධතාවයක් නැත"</string>
    -     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi සම්බන්ධිතයි"</string>
    -@@ -404,6 +404,7 @@
    -     <string name="device_owned_footer" msgid="3802752663326030053">"ඇතැම් විට උපාංගය නිරීක්ෂණය විය හැක"</string>
    -     <string name="profile_owned_footer" msgid="8021888108553696069">"ඇතැම් විට පැතිකඩ නිරීක්ෂණය කරන ලදි"</string>
    -     <string name="vpn_footer" msgid="2388611096129106812">"ඇතැම් විට ජාලය නිරීක්ෂණය විය හැක"</string>
    -+    <string name="branded_vpn_footer" msgid="2168111859226496230">"ඇතැම් විට ජාලය නිරීක්ෂණය විය හැක"</string>
    -     <string name="monitoring_title_device_owned" msgid="7121079311903859610">"උපාංගය නිරීක්ෂණය"</string>
    -     <string name="monitoring_title_profile_owned" msgid="6790109874733501487">"පැතිකඩ නිරීක්ෂණය කිරීම"</string>
    -     <string name="monitoring_title" msgid="169206259253048106">"ජාල නිරීක්ෂණය"</string>
    -@@ -416,6 +417,7 @@
    -     <string name="legacy_vpn_name" msgid="6604123105765737830">"VPN"</string>
    -     <string name="monitoring_description_app" msgid="6259179342284742878">"ඊ-තැපැල්, යෙදුම් සහ වෙබ් අඩවි ඇතුළු ඔබේ ජාල ක්‍රියාකාරකම් නිරීක්ෂණය කළ හැකි, <xliff:g id="APPLICATION">%1$s</xliff:g> වෙත ඔබ සම්බන්ධ වී ඇත."</string>
    -     <string name="monitoring_description_app_personal" msgid="484599052118316268">"ඊ-තැපැල්, යෙදුම් සහ වෙබ් අඩවි ඇතුළු ඔබේ පෞද්ගලික ජාල ක්‍රියාකාරකම් නිරීක්ෂණය කළ හැකි, <xliff:g id="APPLICATION">%1$s</xliff:g> වෙත ඔබ සම්බන්ධ වී ඇත."</string>
    -+    <string name="branded_monitoring_description_app_personal" msgid="2669518213949202599">"ඊ-තැපැල්, යෙදුම් සහ වෙබ් අඩවි ඇතුළු ඔබේ පෞද්ගලික ජාල ක්‍රියාකාරකම් නිරීක්ෂණය කළ හැකි, <xliff:g id="APPLICATION">%1$s</xliff:g> වෙත ඔබ සම්බන්ධ වී ඇත."</string>
    -     <string name="monitoring_description_app_work" msgid="1754325860918060897">"ඔබේ කාර්යාල පැතිකඩ කළමනාකරණය කරන්නේ <xliff:g id="ORGANIZATION">%1$s</xliff:g> විසිනි. එය ඊ-තැපැල්, යෙදුම් සහ වෙබ් අඩවි ඇතුළු ඔබේ කාර්යාල ජාල ක්‍රියාකාරකම් නිරීක්ෂණය කළ හැකි, <xliff:g id="APPLICATION">%2$s</xliff:g> වෙත ඔබ සම්බන්ධ වී ඇත.\n\nවැඩිදුර විස්තර සඳහා, ඔබේ පරිපාලක අමතන්න."</string>
    -     <string name="monitoring_description_app_personal_work" msgid="4946600443852045903">"ඔබේ කාර්යාල පැතිකඩ කළමනාකරණය කරන්නේ <xliff:g id="ORGANIZATION">%1$s</xliff:g> විසිනි. එය ඊ-තැපැල්, යෙදුම් සහ වෙබ් අඩවි ඇතුළු ඔබේ කාර්යාල ජාල ක්‍රියාකාරකම් නිරීක්ෂණය කළ හැකි, <xliff:g id="APPLICATION_WORK">%2$s</xliff:g>, වෙත ඔබ සම්බන්ධ වී ඇත.\n\nඔබ ඔබේ පෞද්ගලික ජාල ක්‍රියාකාරකම් නිරීක්ෂණය කළ හැකි, <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g> වෙතද සම්බන්ධ වී ඇත."</string>
    -     <string name="monitoring_description_vpn_app_device_owned" msgid="4970443827043261703">"ඔබේ උපාංගය කළමනාකරණය කරන්නේ <xliff:g id="ORGANIZATION">%1$s</xliff:g> විසිනි.\n\nඔබේ පරිපාලකට ඔබේ උපාංගය හා සම්බන්ධිත සැකසීම්, ආයතනික ප්‍රවේශය, යෙදුම්, දත්ත සහ ඔබේ උපාංගය තිබෙන ස්ථානයේ තොරතුරු නිරීක්ෂණය කිරීමට සහ කළමනාකරණය කිරීමට හැකිය.\n\nඔබ ඊ-තැපැල්, යෙදුම්, සහ වෙබ් අඩවි ඇතුළු ඔබේ ජාල ක්‍රියාකාරකම් නිරීක්ෂණය කිරීමට හැකි <xliff:g id="APPLICATION">%2$s</xliff:g>, වෙතද සම්බන්ධව ඇත.\n\nවැඩිදුර තොරතුරු සඳහා, ඔබගේ පරිපාලක අමතන්න."</string>
    -@@ -492,8 +494,6 @@
    -     <string name="clock_seconds_desc" msgid="6282693067130470675">"තත්ත්ව තීරුවෙහි ඔරලෝසු තත්පර පෙන්වන්න. බැටරි ආයු කාලයට බලපෑමට හැකිය."</string>
    -     <string name="qs_rearrange" msgid="8060918697551068765">"ඉක්මන් සැකසීම් යළි පිළිවෙළට සකසන්න"</string>
    -     <string name="show_brightness" msgid="6613930842805942519">"ඉක්මන් සැකසීම්වල දීප්තිය පෙන්වන්න"</string>
    --    <string name="overview_nav_bar_gesture" msgid="8579814204727917764">"බෙදුම්-තිරය ඉහළට-ස්වයිප් කිරීමේ අභිනය සබල කරන්න"</string>
    --    <string name="overview_nav_bar_gesture_desc" msgid="6329167382305102615">"දළ විශ්ලේෂණ බොත්තම හරහා ඉහළට ස්වයිප් කිරීමෙන් බෙදුම් තිරයට ඇතුළු වීමට ඉඟිය සබල කිරීම"</string>
    -     <string name="experimental" msgid="6198182315536726162">"පරීක්ෂණාත්මක"</string>
    -     <string name="enable_bluetooth_title" msgid="5027037706500635269">"බ්ලූටූත් ක්‍රියාත්මක කරන්නද?"</string>
    -     <string name="enable_bluetooth_message" msgid="9106595990708985385">"ඔබේ යතුරු පුවරුව ඔබේ ටැබ්ලට් පරිගණකයට සම්බන්ධ කිරීමට, ඔබ පළමුව බ්ලූටූත් ක්‍රියාත්මක කළ යුතුය."</string>
    -@@ -651,4 +651,5 @@
    -     <string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"<xliff:g id="ID_1">%s</xliff:g> සැකසීම් විවෘත කරන්න."</string>
    -     <string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"සැකසීම්වල අනුපිළිවෙළ සංංස්කරණය කරන්න."</string>
    -     <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"<xliff:g id="ID_2">%2$d</xliff:g> න් <xliff:g id="ID_1">%1$d</xliff:g>"</string>
    -+    <string name="cant_silence_or_block" msgid="999689262131488625">"දැනුම්දීම් නිහඬ හෝ අවහිර කළ නොහැකිය"</string>
    - </resources>
    -diff --git a/packages/SystemUI/res/values-sk/strings.xml b/packages/SystemUI/res/values-sk/strings.xml
    -index 304c9a0..8dd2569 100644
    ---- a/packages/SystemUI/res/values-sk/strings.xml
    -+++ b/packages/SystemUI/res/values-sk/strings.xml
    -@@ -242,7 +242,7 @@
    -     <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"Dátové prenosy 4G sú pozastavené"</string>
    -     <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"Mobilné dáta sú pozastavené"</string>
    -     <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"Dáta sú pozastavené"</string>
    --    <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"Keďže ste dosiahli nastavený limit pre mobilné dáta, na zariadení bola pre zvyšok tohto cyklu pozastavená spotreba dát.\n\nJej opätovné spustenie môže mať za následok účtovanie poplatkov vaším operátorom."</string>
    -+    <string name="data_usage_disabled_dialog" msgid="1841738975235283398">"Dosiahli ste nastavený limit dát. Už nepoužívate mobilné dátové pripojenie.\n\nAk ho však obnovíte, môžu vám byť účtované poplatky za spotrebu dát."</string>
    -     <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"Znova spustiť"</string>
    -     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Bez prip. na Internet"</string>
    -     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi: pripojené"</string>
    -@@ -410,6 +410,7 @@
    -     <string name="device_owned_footer" msgid="3802752663326030053">"Zariadenie môže byť sledované"</string>
    -     <string name="profile_owned_footer" msgid="8021888108553696069">"Profil môže byť monitorovaný"</string>
    -     <string name="vpn_footer" msgid="2388611096129106812">"Sieť môže byť sledovaná"</string>
    -+    <string name="branded_vpn_footer" msgid="2168111859226496230">"Sieť môže byť monitorovaná"</string>
    -     <string name="monitoring_title_device_owned" msgid="7121079311903859610">"Sledovanie zariadenia"</string>
    -     <string name="monitoring_title_profile_owned" msgid="6790109874733501487">"Monitorovanie profilu"</string>
    -     <string name="monitoring_title" msgid="169206259253048106">"Sledovanie siete"</string>
    -@@ -422,6 +423,7 @@
    -     <string name="legacy_vpn_name" msgid="6604123105765737830">"VPN"</string>
    -     <string name="monitoring_description_app" msgid="6259179342284742878">"Ste pripojený/-á k aplikácii <xliff:g id="APPLICATION">%1$s</xliff:g>, ktorá môže sledovať vašu aktivitu v sieti vrátane e-mailových správ, aplikácií a webových stránok."</string>
    -     <string name="monitoring_description_app_personal" msgid="484599052118316268">"Ste pripojený/-á k aplikácii <xliff:g id="APPLICATION">%1$s</xliff:g>, ktorá môže sledovať vašu osobnú aktivitu v sieti vrátane e-mailových správ, aplikácií a webových stránok."</string>
    -+    <string name="branded_monitoring_description_app_personal" msgid="2669518213949202599">"Ste pripojený/-á k aplikácii <xliff:g id="APPLICATION">%1$s</xliff:g>, ktorá môže sledovať vašu osobnú aktivitu v sieti vrátane e-mailových správ, aplikácií a webových stránok."</string>
    -     <string name="monitoring_description_app_work" msgid="1754325860918060897">"Váš pracovný profil spravuje organizácia <xliff:g id="ORGANIZATION">%1$s</xliff:g>. Je pripojený k aplikácii <xliff:g id="APPLICATION">%2$s</xliff:g>, ktorá môže sledovať vašu pracovnú aktivitu v sieti vrátane e-mailových správ, aplikácií a webových stránok.\n\nĎalšie informácie získate od svojho správcu."</string>
    -     <string name="monitoring_description_app_personal_work" msgid="4946600443852045903">"Váš pracovný profil spravuje organizácia <xliff:g id="ORGANIZATION">%1$s</xliff:g>. Je pripojený k aplikácii <xliff:g id="APPLICATION_WORK">%2$s</xliff:g>, ktorá môže sledovať vašu pracovnú aktivitu v sieti vrátane e-mailových správ, aplikácií a webových stránok.\n\nSte tiež pripojený/-á k aplikácii <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g>, ktorá môže sledovať vašu osobnú aktivitu v sieti."</string>
    -     <string name="monitoring_description_vpn_app_device_owned" msgid="4970443827043261703">"Vaše zariadenie spravuje organizácia <xliff:g id="ORGANIZATION">%1$s</xliff:g>.\n\nSprávca môže sledovať a spravovať nastavenia, podnikový prístup, aplikácie a údaje priradené k vášmu účtu, ako aj informácie o polohe zariadenia.\n\nSte pripojený/-á k aplikácii <xliff:g id="APPLICATION">%2$s</xliff:g>, ktorá môže sledovať vašu aktivitu v sieti vrátane e-mailových správ, aplikácii a webových stránok.\n\nĎalšie informácie získate od svojho správcu."</string>
    -@@ -498,8 +500,6 @@
    -     <string name="clock_seconds_desc" msgid="6282693067130470675">"Zobrazí sekundy v stavovom riadku. Môže to ovplyvňovať výdrž batérie."</string>
    -     <string name="qs_rearrange" msgid="8060918697551068765">"Zmeniť usporiadanie Rýchlych nastavení"</string>
    -     <string name="show_brightness" msgid="6613930842805942519">"Zobraziť jas v Rýchlych nastaveniach"</string>
    --    <string name="overview_nav_bar_gesture" msgid="8579814204727917764">"Aktivovať rozdelenú obrazovku prejdením prstom"</string>
    --    <string name="overview_nav_bar_gesture_desc" msgid="6329167382305102615">"Umožňuje aktivovať rozdelenú obrazovku prejdením prstom nahor od tlačidla Prehľad"</string>
    -     <string name="experimental" msgid="6198182315536726162">"Experimentálne"</string>
    -     <string name="enable_bluetooth_title" msgid="5027037706500635269">"Zapnúť Bluetooth?"</string>
    -     <string name="enable_bluetooth_message" msgid="9106595990708985385">"Ak chcete klávesnicu pripojiť k tabletu, najprv musíte zapnúť Bluetooth."</string>
    -@@ -571,7 +571,7 @@
    -     <string name="keyboard_shortcut_group_applications_browser" msgid="6465985474000766533">"Prehliadač"</string>
    -     <string name="keyboard_shortcut_group_applications_contacts" msgid="2064197111278436375">"Kontakty"</string>
    -     <string name="keyboard_shortcut_group_applications_email" msgid="6257036897441939004">"E-mail"</string>
    --    <string name="keyboard_shortcut_group_applications_im" msgid="1892749399083161405">"Okamžité správy"</string>
    -+    <string name="keyboard_shortcut_group_applications_im" msgid="1892749399083161405">"Čet"</string>
    -     <string name="keyboard_shortcut_group_applications_music" msgid="4775559515850922780">"Hudba"</string>
    -     <string name="keyboard_shortcut_group_applications_youtube" msgid="6555453761294723317">"YouTube"</string>
    -     <string name="keyboard_shortcut_group_applications_calendar" msgid="9043614299194991263">"Kalendár"</string>
    -@@ -657,4 +657,5 @@
    -     <string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"Otvoriť nastavenia <xliff:g id="ID_1">%s</xliff:g>"</string>
    -     <string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"Upraviť poradie nastavení"</string>
    -     <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"Strana <xliff:g id="ID_1">%1$d</xliff:g> z <xliff:g id="ID_2">%2$d</xliff:g>"</string>
    -+    <string name="cant_silence_or_block" msgid="999689262131488625">"Upozornenia nie je možné stlmiť ani blokovať"</string>
    - </resources>
    -diff --git a/packages/SystemUI/res/values-sl/strings.xml b/packages/SystemUI/res/values-sl/strings.xml
    -index a8bc3d1..fc81a23 100644
    ---- a/packages/SystemUI/res/values-sl/strings.xml
    -+++ b/packages/SystemUI/res/values-sl/strings.xml
    -@@ -242,7 +242,7 @@
    -     <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"Prenos podatkov v omrežju 4G je zaustavljen"</string>
    -     <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"Prenos mobilnih podatkov je zaustavljen"</string>
    -     <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"Prenos podatkov je zaustavljen"</string>
    --    <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"Dosegli ste nastavljeno omejitev količine prenesenih podatkov, zato je naprava zaustavila porabo podatkov za preostanek cikla.\n\nČe nadaljujete s porabo, boste morda morali plačati stroške operaterju."</string>
    -+    <string name="data_usage_disabled_dialog" msgid="1841738975235283398">"Dosegli ste nastavljeno omejitev porabe podatkov. Prenosa podatkov v mobilnih omrežjih ne uporabljate več.\n\nČe nadaljujete, lahko nastanejo stroški prenosa podatkov."</string>
    -     <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"Nadaljuj"</string>
    -     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Ni internetne povez."</string>
    -     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi povezan"</string>
    -@@ -410,6 +410,7 @@
    -     <string name="device_owned_footer" msgid="3802752663326030053">"Naprava je morda nadzorovana"</string>
    -     <string name="profile_owned_footer" msgid="8021888108553696069">"Profil je morda nadziran"</string>
    -     <string name="vpn_footer" msgid="2388611096129106812">"Omrežje je lahko nadzorovano"</string>
    -+    <string name="branded_vpn_footer" msgid="2168111859226496230">"Omrežje je morda nadzorovano"</string>
    -     <string name="monitoring_title_device_owned" msgid="7121079311903859610">"Nadzor naprave"</string>
    -     <string name="monitoring_title_profile_owned" msgid="6790109874733501487">"Nadzor nad profilom"</string>
    -     <string name="monitoring_title" msgid="169206259253048106">"Nadzor omrežja"</string>
    -@@ -422,6 +423,7 @@
    -     <string name="legacy_vpn_name" msgid="6604123105765737830">"VPN"</string>
    -     <string name="monitoring_description_app" msgid="6259179342284742878">"Povezani ste z aplikacijo <xliff:g id="APPLICATION">%1$s</xliff:g>, ki lahko nadzira omrežno dejavnost, vključno z e-pošto, aplikacijami in spletnimi mesti."</string>
    -     <string name="monitoring_description_app_personal" msgid="484599052118316268">"Povezani ste z aplikacijo <xliff:g id="APPLICATION">%1$s</xliff:g>, ki lahko nadzira vašo osebno omrežno dejavnost, vključno z e-pošto, aplikacijami in spletnimi mesti."</string>
    -+    <string name="branded_monitoring_description_app_personal" msgid="2669518213949202599">"Povezani ste z aplikacijo <xliff:g id="APPLICATION">%1$s</xliff:g>, ki lahko nadzira vašo osebno omrežno dejavnost, vključno z e-pošto, aplikacijami in spletnimi mesti."</string>
    -     <string name="monitoring_description_app_work" msgid="1754325860918060897">"Delovni profil upravlja organizacija <xliff:g id="ORGANIZATION">%1$s</xliff:g>. Povezan je z aplikacijo <xliff:g id="APPLICATION">%2$s</xliff:g>, ki lahko nadzira vašo delovno omrežno dejavnost, vključno z e-pošto, aplikacijami in spletnimi mesti.\n\nČe želite več informacij, se obrnite na skrbnika."</string>
    -     <string name="monitoring_description_app_personal_work" msgid="4946600443852045903">"Delovni profil upravlja organizacija <xliff:g id="ORGANIZATION">%1$s</xliff:g>. Povezan je z aplikacijo <xliff:g id="APPLICATION_WORK">%2$s</xliff:g>, ki lahko nadzira vašo delovno omrežno dejavnost, vključno z e-pošto, aplikacijami in spletnimi mesti.\n\nPovezani ste tudi z aplikacijo <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g>, ki lahko nadzira vašo osebno omrežno dejavnost."</string>
    -     <string name="monitoring_description_vpn_app_device_owned" msgid="4970443827043261703">"Napravo upravlja organizcija <xliff:g id="ORGANIZATION">%1$s</xliff:g>.\n\nSkrbnik lahko nadzira in upravlja nastavitve, dostop za podjetje, aplikacije, podatke, povezane z napravo, in podatke o lokaciji naprave.\n\nPovezani ste z aplikacijo <xliff:g id="APPLICATION">%2$s</xliff:g>, ki lahko nadzira omrežno dejavnost, vključno z e-pošto, aplikacijami in spletnimi mesti.\n\nČe želite več informacij, se obrnite na skrbnika."</string>
    -@@ -498,8 +500,6 @@
    -     <string name="clock_seconds_desc" msgid="6282693067130470675">"Prikaže sekunde pri uri v vrstici stanja. To lahko vpliva na čas delovanja pri akumulatorskem napajanju."</string>
    -     <string name="qs_rearrange" msgid="8060918697551068765">"Preuredi hitre nastavitve"</string>
    -     <string name="show_brightness" msgid="6613930842805942519">"Prikaz svetlosti v hitrih nastavitvah"</string>
    --    <string name="overview_nav_bar_gesture" msgid="8579814204727917764">"Omogočanje poteze za razdeljen zaslon z vlečenjem navzgor"</string>
    --    <string name="overview_nav_bar_gesture_desc" msgid="6329167382305102615">"Omogočanje poteze za vklop razdeljenega zaslona, tako da uporabnik od gumba za pregled povleče s prstom navzgor"</string>
    -     <string name="experimental" msgid="6198182315536726162">"Poskusno"</string>
    -     <string name="enable_bluetooth_title" msgid="5027037706500635269">"Želite vklopiti Bluetooth?"</string>
    -     <string name="enable_bluetooth_message" msgid="9106595990708985385">"Če želite povezati tipkovnico in tablični računalnik, vklopite Bluetooth."</string>
    -@@ -657,4 +657,5 @@
    -     <string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"Odpri nastavitve za <xliff:g id="ID_1">%s</xliff:g>."</string>
    -     <string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"Uredi vrstni red nastavitev."</string>
    -     <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"<xliff:g id="ID_1">%1$d</xliff:g>. stran od <xliff:g id="ID_2">%2$d</xliff:g>"</string>
    -+    <string name="cant_silence_or_block" msgid="999689262131488625">"Obvestil ni mogoče utišati ali blokirati"</string>
    - </resources>
    -diff --git a/packages/SystemUI/res/values-sq-rAL/strings.xml b/packages/SystemUI/res/values-sq-rAL/strings.xml
    -index 4bc29aa..68f5685 100644
    ---- a/packages/SystemUI/res/values-sq-rAL/strings.xml
    -+++ b/packages/SystemUI/res/values-sq-rAL/strings.xml
    -@@ -238,7 +238,7 @@
    -     <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"Të dhënat 4G janë ndërprerë"</string>
    -     <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"Të dhënat celulare janë ndërprerë"</string>
    -     <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"Të dhënat janë ndërprerë"</string>
    --    <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"Pajisja jote ka ndërprerë përdorimin e të dhënave për pjesën e mbetur të ciklit sepse është arritur kufiri i caktuar i të dhënave.\n\nVazhdimi mund të sjellë tarifa nga operatori celular."</string>
    -+    <string name="data_usage_disabled_dialog" msgid="1841738975235283398">"Kufiri i të dhënave që ke caktuar është arritur. Nuk po përdor më të dhënat celulare.\n\nNëse vazhdon, mund të zbatohen tarifa për përdorimin e të dhënave."</string>
    -     <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"Rifillo"</string>
    -     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Nuk ka lidhje interneti"</string>
    -     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi është i lidhur"</string>
    -@@ -404,6 +404,7 @@
    -     <string name="device_owned_footer" msgid="3802752663326030053">"Pajisja mund të monitorohet"</string>
    -     <string name="profile_owned_footer" msgid="8021888108553696069">"Profili mund të monitorohet"</string>
    -     <string name="vpn_footer" msgid="2388611096129106812">"Rrjeti mund të jetë i monitoruar"</string>
    -+    <string name="branded_vpn_footer" msgid="2168111859226496230">"Rrjeti mund të jetë i monitoruar"</string>
    -     <string name="monitoring_title_device_owned" msgid="7121079311903859610">"Monitorimi i pajisjes"</string>
    -     <string name="monitoring_title_profile_owned" msgid="6790109874733501487">"Monitorimi i profilit"</string>
    -     <string name="monitoring_title" msgid="169206259253048106">"Monitorimi i rrjetit"</string>
    -@@ -416,6 +417,7 @@
    -     <string name="legacy_vpn_name" msgid="6604123105765737830">"VPN"</string>
    -     <string name="monitoring_description_app" msgid="6259179342284742878">"Je i lidhur me aplikacionin <xliff:g id="APPLICATION">%1$s</xliff:g>, i cili mund të monitorojë aktivitetin tënd në rrjet përfshirë mailet, aplikacionet dhe sajtet e uebit."</string>
    -     <string name="monitoring_description_app_personal" msgid="484599052118316268">"Je i lidhur me aplikacionin <xliff:g id="APPLICATION">%1$s</xliff:g>, i cili mund të monitorojë aktivitetin tënd personal në rrjet, përfshirë mailet, aplikacionet dhe sajtet e uebit."</string>
    -+    <string name="branded_monitoring_description_app_personal" msgid="2669518213949202599">"Je i lidhur me aplikacionin <xliff:g id="APPLICATION">%1$s</xliff:g>, i cili mund të monitorojë aktivitetin tënd personal në rrjet, përfshirë mailet, aplikacionet dhe sajtet e uebit."</string>
    -     <string name="monitoring_description_app_work" msgid="1754325860918060897">"Profili yt i punës menaxhohet nga <xliff:g id="ORGANIZATION">%1$s</xliff:g>. Ai është i lidhur me <xliff:g id="APPLICATION">%2$s</xliff:g>, i cili mund të monitorojë aktivitetin tënd të punës në rrjet, përfshirë mailet, aplikacionet dhe sajtet e uebit.\n\nPër më shumë informacione, kontakto me administratorin tënd."</string>
    -     <string name="monitoring_description_app_personal_work" msgid="4946600443852045903">"Profili yt i punës menaxhohet nga <xliff:g id="ORGANIZATION">%1$s</xliff:g>. Ai është i lidhur me <xliff:g id="APPLICATION_WORK">%2$s</xliff:g>, i cili mund të monitorojë aktivitetin tënd të punës në rrjet, përfshirë mailet, aplikacionet dhe sajtet e uebit.\n\nJe lidhur gjithashtu edhe me <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g>, i cili mund të monitorojë aktivitetin tënd personal në rrjet."</string>
    -     <string name="monitoring_description_vpn_app_device_owned" msgid="4970443827043261703">"Pajisja jote menaxhohet nga <xliff:g id="ORGANIZATION">%1$s</xliff:g>.\n\nAdministratori mund të monitorojë dhe menaxhojë cilësimet, qasjen e korporatës, aplikacionet, të dhënat që shoqërojnë pajisjen tënde si dhe informacionin e vendndodhjes së pajisjes.\n\nJe i lidhur me <xliff:g id="APPLICATION">%2$s</xliff:g>, që mund të monitorojë aktivitetin tënd të punës në rrjet përfshirë mail-at, aplikacionet dhe faqet e internetit.\n\nPër më shumë informacion, kontakto me administratorin tënd."</string>
    -@@ -492,8 +494,6 @@
    -     <string name="clock_seconds_desc" msgid="6282693067130470675">"Trego sekondat e orës në shiritin e statusit. Mund të ndikojë te jeta e baterisë."</string>
    -     <string name="qs_rearrange" msgid="8060918697551068765">"Risistemo Cilësimet e shpejta"</string>
    -     <string name="show_brightness" msgid="6613930842805942519">"Shfaq ndriçimin te Cilësimet e shpejta"</string>
    --    <string name="overview_nav_bar_gesture" msgid="8579814204727917764">"Aktivizo gjestin e rrëshqitjes lart për ekranin e ndarë"</string>
    --    <string name="overview_nav_bar_gesture_desc" msgid="6329167382305102615">"Aktivizo gjestin për të hyrë tek ekrani i ndarë duke rrëshqitur lart nga butoni \"Përmbledhja\""</string>
    -     <string name="experimental" msgid="6198182315536726162">"Eksperimentale"</string>
    -     <string name="enable_bluetooth_title" msgid="5027037706500635269">"Të aktivizohet \"bluetooth-i\"?"</string>
    -     <string name="enable_bluetooth_message" msgid="9106595990708985385">"Për të lidhur tastierën me tabletin, në fillim duhet të aktivizosh \"bluetooth-in\"."</string>
    -@@ -651,4 +651,5 @@
    -     <string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"Hap cilësimet e <xliff:g id="ID_1">%s</xliff:g>."</string>
    -     <string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"Modifiko rendin e cilësimeve."</string>
    -     <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"Faqja <xliff:g id="ID_1">%1$d</xliff:g> nga <xliff:g id="ID_2">%2$d</xliff:g>"</string>
    -+    <string name="cant_silence_or_block" msgid="999689262131488625">"Njoftimet nuk mund të vendosen në heshtje ose të bllokohen"</string>
    - </resources>
    -diff --git a/packages/SystemUI/res/values-sr/strings.xml b/packages/SystemUI/res/values-sr/strings.xml
    -index 16ae7e2..d313054 100644
    ---- a/packages/SystemUI/res/values-sr/strings.xml
    -+++ b/packages/SystemUI/res/values-sr/strings.xml
    -@@ -239,7 +239,7 @@
    -     <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"4G подаци су паузирани"</string>
    -     <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"Мобилни подаци су паузирани"</string>
    -     <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"Подаци су паузирани"</string>
    --    <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"Због тога што сте достигли подешено ограничење за податке, уређај је паузирао коришћење података током остатка овог циклуса.\n\nАко наставите, мобилни оператер може да вам наплати додатне трошкове."</string>
    -+    <string name="data_usage_disabled_dialog" msgid="1841738975235283398">"Ограничење потрошње података које сте подесили је достигнуто. Више не користите мобилне податке.\n\nАко наставите, можда ће бити наплаћени трошкови за потрошњу података."</string>
    -     <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"Настави"</string>
    -     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Нема интернет везе"</string>
    -     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi је повезан"</string>
    -@@ -406,6 +406,7 @@
    -     <string name="device_owned_footer" msgid="3802752663326030053">"Уређај се можда надгледа"</string>
    -     <string name="profile_owned_footer" msgid="8021888108553696069">"Профил се можда надгледа"</string>
    -     <string name="vpn_footer" msgid="2388611096129106812">"Мрежа се можда надгледа"</string>
    -+    <string name="branded_vpn_footer" msgid="2168111859226496230">"Мрежа се можда надгледа"</string>
    -     <string name="monitoring_title_device_owned" msgid="7121079311903859610">"Надгледање уређаја"</string>
    -     <string name="monitoring_title_profile_owned" msgid="6790109874733501487">"Надгледање профила"</string>
    -     <string name="monitoring_title" msgid="169206259253048106">"Надгледање мреже"</string>
    -@@ -418,6 +419,7 @@
    -     <string name="legacy_vpn_name" msgid="6604123105765737830">"VPN"</string>
    -     <string name="monitoring_description_app" msgid="6259179342284742878">"Повезани сте са апликацијом <xliff:g id="APPLICATION">%1$s</xliff:g>, која може да надгледа активности на мрежи, укључујући имејлове, апликације и веб-сајтове."</string>
    -     <string name="monitoring_description_app_personal" msgid="484599052118316268">"Повезани сте са апликацијом <xliff:g id="APPLICATION">%1$s</xliff:g>, која може да надгледа активности на личној мрежи, укључујући имејлове, апликације и веб-сајтове."</string>
    -+    <string name="branded_monitoring_description_app_personal" msgid="2669518213949202599">"Повезани сте са апликацијом <xliff:g id="APPLICATION">%1$s</xliff:g>, која може да надгледа активности на личној мрежи, укључујући имејлове, апликације и веб-сајтове."</string>
    -     <string name="monitoring_description_app_work" msgid="1754325860918060897">"Профилом за Work управља <xliff:g id="ORGANIZATION">%1$s</xliff:g>. Повезан је са апликацијом <xliff:g id="APPLICATION">%2$s</xliff:g>, која може да надгледа активности на пословној мрежи, укључујући имејлове, апликације и веб-сајтове.\n\nВише информација потражите од администратора."</string>
    -     <string name="monitoring_description_app_personal_work" msgid="4946600443852045903">"Профилом за Work управља <xliff:g id="ORGANIZATION">%1$s</xliff:g>. Повезан је са апликацијом <xliff:g id="APPLICATION_WORK">%2$s</xliff:g>, која може да надгледа активности на пословној мрежи, укључујући имејлове, апликације и веб-сајтове.\n\nПовезани сте и са апликацијом <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g>, која може да надгледа активности на личној мрежи."</string>
    -     <string name="monitoring_description_vpn_app_device_owned" msgid="4970443827043261703">"Уређајем управља <xliff:g id="ORGANIZATION">%1$s</xliff:g>.\n\nАдминистратор може да надгледа подешавања, корпоративни приступ, апликације, податке повезане са уређајем и информације о локацији уређаја, као и да управља њима.\n\nПовезани сте са апликацијом <xliff:g id="APPLICATION">%2$s</xliff:g>, која може да надгледа активности на мрежи, укључујући имејлове, апликације и веб-сајтове.\n\nВише информација потражите од администратора."</string>
    -@@ -494,8 +496,6 @@
    -     <string name="clock_seconds_desc" msgid="6282693067130470675">"Секунде на сату се приказују на статусној траци. То може да утиче на трајање батерије."</string>
    -     <string name="qs_rearrange" msgid="8060918697551068765">"Преуреди Брза подешавања"</string>
    -     <string name="show_brightness" msgid="6613930842805942519">"Прикажи осветљеност у Брзим подешавањима"</string>
    --    <string name="overview_nav_bar_gesture" msgid="8579814204727917764">"Омогући покрет за превлачење нагоре за подељени екран"</string>
    --    <string name="overview_nav_bar_gesture_desc" msgid="6329167382305102615">"Омогућава покрет за прелазак на подељени екран превлачењем нагоре од дугмета Преглед"</string>
    -     <string name="experimental" msgid="6198182315536726162">"Експериментално"</string>
    -     <string name="enable_bluetooth_title" msgid="5027037706500635269">"Желите ли да укључите Bluetooth?"</string>
    -     <string name="enable_bluetooth_message" msgid="9106595990708985385">"Да бисте повезали тастатуру са таблетом, прво морате да укључите Bluetooth."</string>
    -@@ -653,4 +653,5 @@
    -     <string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"Отвори подешавања за <xliff:g id="ID_1">%s</xliff:g>."</string>
    -     <string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"Измени редослед подешавања."</string>
    -     <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"<xliff:g id="ID_1">%1$d</xliff:g>. страна од <xliff:g id="ID_2">%2$d</xliff:g>"</string>
    -+    <string name="cant_silence_or_block" msgid="999689262131488625">"Звук обавештења не може да се искључи нити она могу да се блокирају"</string>
    - </resources>
    -diff --git a/packages/SystemUI/res/values-sv/strings.xml b/packages/SystemUI/res/values-sv/strings.xml
    -index e6988d7..8176422 100644
    ---- a/packages/SystemUI/res/values-sv/strings.xml
    -+++ b/packages/SystemUI/res/values-sv/strings.xml
    -@@ -238,7 +238,7 @@
    -     <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"4G-data har pausats"</string>
    -     <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"Mobildata har pausats"</string>
    -     <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"Dataanvändningen har pausats"</string>
    --    <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"Eftersom du har nått den angivna datagränsen har dataanvändningen pausats under resten av perioden.\n\nOm du återupptar dataanvändningen kan avgifter från operatören tillkomma."</string>
    -+    <string name="data_usage_disabled_dialog" msgid="1841738975235283398">"Den angivna datagränsen har uppnåtts. Du använder inte längre mobildata.\n\nOm du fortsätter kan avgifter för dataanvändning tillkomma."</string>
    -     <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"Återuppta"</string>
    -     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Ingen anslutning"</string>
    -     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi-ansluten"</string>
    -@@ -331,7 +331,7 @@
    -     <string name="recents_launch_disabled_message" msgid="1624523193008871793">"<xliff:g id="APP">%s</xliff:g> är inaktiverad i säkert läge."</string>
    -     <string name="recents_stack_action_button_label" msgid="6593727103310426253">"Rensa alla"</string>
    -     <string name="recents_incompatible_app_message" msgid="5075812958564082451">"Appen har inte stöd för delad skärm."</string>
    --    <string name="recents_drag_hint_message" msgid="2649739267073203985">"Dra här om du vill dela upp skärmen"</string>
    -+    <string name="recents_drag_hint_message" msgid="2649739267073203985">"Dra hit för att dela upp skärmen"</string>
    -     <string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"Dela horisontellt"</string>
    -     <string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"Dela vertikalt"</string>
    -     <string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"Dela anpassad"</string>
    -@@ -352,7 +352,7 @@
    -     <string name="keyguard_more_overflow_text" msgid="9195222469041601365">"+<xliff:g id="NUMBER_OF_NOTIFICATIONS">%d</xliff:g>"</string>
    -     <string name="speed_bump_explanation" msgid="1288875699658819755">"Mindre brådskande aviseringar nedan"</string>
    -     <string name="notification_tap_again" msgid="7590196980943943842">"Tryck igen för att öppna"</string>
    --    <string name="keyguard_unlock" msgid="8043466894212841998">"Svep uppåt om du vill låsa upp"</string>
    -+    <string name="keyguard_unlock" msgid="8043466894212841998">"Svep uppåt för att låsa upp"</string>
    -     <string name="phone_hint" msgid="4872890986869209950">"Svep från ikonen och öppna telefonen"</string>
    -     <string name="voice_hint" msgid="8939888732119726665">"Svep från ikonen och öppna röstassistenten"</string>
    -     <string name="camera_hint" msgid="7939688436797157483">"Svep från ikonen och öppna kameran"</string>
    -@@ -404,6 +404,7 @@
    -     <string name="device_owned_footer" msgid="3802752663326030053">"Enheten kan övervakas"</string>
    -     <string name="profile_owned_footer" msgid="8021888108553696069">"Det kan hända att profilen övervakas"</string>
    -     <string name="vpn_footer" msgid="2388611096129106812">"Nätverket kan vara övervakat"</string>
    -+    <string name="branded_vpn_footer" msgid="2168111859226496230">"Nätverket kan vara övervakat"</string>
    -     <string name="monitoring_title_device_owned" msgid="7121079311903859610">"Enhetsövervakning"</string>
    -     <string name="monitoring_title_profile_owned" msgid="6790109874733501487">"Profilövervakning"</string>
    -     <string name="monitoring_title" msgid="169206259253048106">"Nätverksövervakning"</string>
    -@@ -416,6 +417,7 @@
    -     <string name="legacy_vpn_name" msgid="6604123105765737830">"VPN"</string>
    -     <string name="monitoring_description_app" msgid="6259179342284742878">"Du är ansluten till <xliff:g id="APPLICATION">%1$s</xliff:g>, som kan bevaka aktivitet på nätverket, inklusive e-post, appar och webbplatser."</string>
    -     <string name="monitoring_description_app_personal" msgid="484599052118316268">"Du är ansluten till <xliff:g id="APPLICATION">%1$s</xliff:g>, som kan bevaka din privata aktivitet på nätverket, inklusive e-post, appar och webbplatser."</string>
    -+    <string name="branded_monitoring_description_app_personal" msgid="2669518213949202599">"Du är ansluten till <xliff:g id="APPLICATION">%1$s</xliff:g> som kan övervaka din privata aktivitet på nätverket, inklusive e-postmeddelanden, appar och webbplatser."</string>
    -     <string name="monitoring_description_app_work" msgid="1754325860918060897">"Jobbprofilen hanteras av <xliff:g id="ORGANIZATION">%1$s</xliff:g>. Den är ansluten till <xliff:g id="APPLICATION">%2$s</xliff:g>, som kan hantera aktivitet på arbetsplatsens nätverk, inklusive e-post, appar och webbplatser.\n\nKontakta administratören för mer information."</string>
    -     <string name="monitoring_description_app_personal_work" msgid="4946600443852045903">"Jobbprofilen hanteras av <xliff:g id="ORGANIZATION">%1$s</xliff:g>. Den är ansluten till <xliff:g id="APPLICATION_WORK">%2$s</xliff:g>, som kan hantera aktivitet på arbetsplatsens nätverk, inklusive e-post, appar och webbplatser.\n\nDu är även ansluten till <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g>, som kan hantera privat aktivitet på nätverket."</string>
    -     <string name="monitoring_description_vpn_app_device_owned" msgid="4970443827043261703">"Enheten hanteras av <xliff:g id="ORGANIZATION">%1$s</xliff:g>.\n\nAdministratören kan bevaka och hantera inställningar, företagsåtkomst, appar, data som är kopplad till enheten och enhetens platsuppgifter.\n\nDu är ansluten till <xliff:g id="APPLICATION">%2$s</xliff:g>, som kan övervaka aktivitet på nätverket, inklusive e-post. appar och webbplatser .\n\nKontakta administratören för mer information."</string>
    -@@ -492,8 +494,6 @@
    -     <string name="clock_seconds_desc" msgid="6282693067130470675">"Visa klocksekunder i statusfältet. Detta kan påverka batteritiden."</string>
    -     <string name="qs_rearrange" msgid="8060918697551068765">"Ordna snabbinställningarna"</string>
    -     <string name="show_brightness" msgid="6613930842805942519">"Visa ljusstyrka i snabbinställningarna"</string>
    --    <string name="overview_nav_bar_gesture" msgid="8579814204727917764">"Aktivera delad skärm när du sveper uppåt"</string>
    --    <string name="overview_nav_bar_gesture_desc" msgid="6329167382305102615">"Aktivera en rörelse som delar skärmen när du sveper uppåt från knappen Översikt"</string>
    -     <string name="experimental" msgid="6198182315536726162">"Experimentella"</string>
    -     <string name="enable_bluetooth_title" msgid="5027037706500635269">"Vill du aktivera Bluetooth?"</string>
    -     <string name="enable_bluetooth_message" msgid="9106595990708985385">"Om du vill ansluta tangentbordet till surfplattan måste du först aktivera Bluetooth."</string>
    -@@ -651,4 +651,5 @@
    -     <string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"Öppna <xliff:g id="ID_1">%s</xliff:g>-inställningarna."</string>
    -     <string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"Ändra ordning på inställningarna."</string>
    -     <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"Sida <xliff:g id="ID_1">%1$d</xliff:g> av <xliff:g id="ID_2">%2$d</xliff:g>"</string>
    -+    <string name="cant_silence_or_block" msgid="999689262131488625">"Det går inte att tysta eller blockera aviseringar"</string>
    - </resources>
    -diff --git a/packages/SystemUI/res/values-sw/strings.xml b/packages/SystemUI/res/values-sw/strings.xml
    -index 50c6685..f8b825a 100644
    ---- a/packages/SystemUI/res/values-sw/strings.xml
    -+++ b/packages/SystemUI/res/values-sw/strings.xml
    -@@ -238,7 +238,7 @@
    -     <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"Data ya 4G imesitishwa"</string>
    -     <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"Data ya simu ya mkononi imesitishwa"</string>
    -     <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"Data imesitishwa"</string>
    --    <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"Kwa sababu ulifikia kiwango cha juu cha data kilichowekwa, kifaa kimesitisha matumizi ya data katika awamu hii iliyosalia.\n\n Kuendelea kunaweza kusababisha malipo kwa mtoa huduma wako."</string>
    -+    <string name="data_usage_disabled_dialog" msgid="1841738975235283398">"Umefikia kikomo cha data ulichoweka. Hutaweza kutumia tena data ya simu ya mkononi.\n\nIkiwa utaendelea, huenda ukatozwa ada za matumizi ya data."</string>
    -     <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"Endelea"</string>
    -     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Hakuna muunganisho wa mtandao"</string>
    -     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Mtandao-hewa umeunganishwa"</string>
    -@@ -404,6 +404,7 @@
    -     <string name="device_owned_footer" msgid="3802752663326030053">"Huenda kifaa kinafuatiliwa"</string>
    -     <string name="profile_owned_footer" msgid="8021888108553696069">"Huenda wasifu ukafuatiliwa"</string>
    -     <string name="vpn_footer" msgid="2388611096129106812">"Huenda mtandao unafuatiliwa"</string>
    -+    <string name="branded_vpn_footer" msgid="2168111859226496230">"Huenda mtandao unafuatiliwa"</string>
    -     <string name="monitoring_title_device_owned" msgid="7121079311903859610">"Ufuatiliaji wa kifaa"</string>
    -     <string name="monitoring_title_profile_owned" msgid="6790109874733501487">"Ufuatiliaji wasifu"</string>
    -     <string name="monitoring_title" msgid="169206259253048106">"Ufuatiliaji wa mtandao"</string>
    -@@ -416,6 +417,7 @@
    -     <string name="legacy_vpn_name" msgid="6604123105765737830">"VPN"</string>
    -     <string name="monitoring_description_app" msgid="6259179342284742878">"Umeunganishwa kwenye <xliff:g id="APPLICATION">%1$s</xliff:g>, ambayo inaweza kufuatilia shughuli za mtandao wako, ikiwa ni pamoja na barua pepe, programu na tovuti."</string>
    -     <string name="monitoring_description_app_personal" msgid="484599052118316268">"Umeunganishwa kwenye <xliff:g id="APPLICATION">%1$s</xliff:g>, ambayo inaweza kufuatilia shughuli za mtandao wako, ikiwa ni pamoja na barua pepe, programu na tovuti."</string>
    -+    <string name="branded_monitoring_description_app_personal" msgid="2669518213949202599">"Umeunganishwa kwenye <xliff:g id="APPLICATION">%1$s</xliff:g>, ambayo inaweza kufuatilia shughuli za mtandao wako, ikiwa ni pamoja na barua pepe, programu na tovuti."</string>
    -     <string name="monitoring_description_app_work" msgid="1754325860918060897">"Wasifu wako wa kazini unasimamiwa na <xliff:g id="ORGANIZATION">%1$s</xliff:g>. Wasifu huu umeunganishwa kwenye <xliff:g id="APPLICATION">%2$s</xliff:g>, ambayo inaweza kufuatilia shughuli za mtandao wako, ikiwa ni pamoja na barua pepe, programu, na tovuti. \n\nKwa maelezo zaidi, wasiliana na msimamizi wako."</string>
    -     <string name="monitoring_description_app_personal_work" msgid="4946600443852045903">"Wasifu wako wa kazini unasimamiwa na <xliff:g id="ORGANIZATION">%1$s</xliff:g>. Wasifu huu umeunganishwa kwenye <xliff:g id="APPLICATION_WORK">%2$s</xliff:g>, ambayo inaweza kufuatilia mtandao wako wa kazini, ikiwa ni pamoja na barua pepe, programu na tovuti. \n\n Wewe pia umeunganishwa kwenye <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g>, ambayo inaweza kufuatilia shughuli za mtandao wako kibinafsi."</string>
    -     <string name="monitoring_description_vpn_app_device_owned" msgid="4970443827043261703">"Kifaa chako kinasimamiwa na <xliff:g id="ORGANIZATION">%1$s</xliff:g>. \n\nMsimamizi wako anaweza kufuatilia na kudhibiti mipangilio, ufikiaji wa kampuni, programu, data inayohusiana na kifaa chako, na maelezo ya mahali kilipo kifaa chako. \n\n Umeuganishwa kwenye <xliff:g id="APPLICATION">%2$s</xliff:g>, ambayo inaweza kufuatilia shughuli ya mtandao wako, ikiwa ni pamoja na barua pepe, programu, na tovuti. \n\n Kwa maelezo zaidi, wasiliana na msimamizi wako."</string>
    -@@ -492,8 +494,6 @@
    -     <string name="clock_seconds_desc" msgid="6282693067130470675">"Onyesha sekunde za saa katika sehemu ya arifa. Inaweza kuathiri muda wa matumizi ya betri."</string>
    -     <string name="qs_rearrange" msgid="8060918697551068765">"Panga Upya Mipangilio ya Haraka"</string>
    -     <string name="show_brightness" msgid="6613930842805942519">"Onyesha unga\'avu katika Mipangilio ya Haraka"</string>
    --    <string name="overview_nav_bar_gesture" msgid="8579814204727917764">"Ruhusu kugawanya skrini kwa ishara ya kutelezesha kidole juu"</string>
    --    <string name="overview_nav_bar_gesture_desc" msgid="6329167382305102615">"Washa kipengele cha ishara ili utumie skrini iliyogawanywa kwa kutelezesha kidole juu kutoka kitufe cha Muhtasari"</string>
    -     <string name="experimental" msgid="6198182315536726162">"Ya majaribio"</string>
    -     <string name="enable_bluetooth_title" msgid="5027037706500635269">"Je, ungependa kuwasha Bluetooth?"</string>
    -     <string name="enable_bluetooth_message" msgid="9106595990708985385">"Ili uunganishe Kibodi yako kwenye kompyuta yako kibao, lazima kwanza uwashe Bluetooth."</string>
    -@@ -651,4 +651,5 @@
    -     <string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"Fungua mipangilio ya <xliff:g id="ID_1">%s</xliff:g>."</string>
    -     <string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"Badilisha orodha ya mipangilio."</string>
    -     <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"Ukurasa wa <xliff:g id="ID_1">%1$d</xliff:g> kati ya <xliff:g id="ID_2">%2$d</xliff:g>"</string>
    -+    <string name="cant_silence_or_block" msgid="999689262131488625">"Huwezi kuzima wala kuzuia arifa"</string>
    - </resources>
    -diff --git a/packages/SystemUI/res/values-ta-rIN/strings.xml b/packages/SystemUI/res/values-ta-rIN/strings.xml
    -index f0cb530..0080f8e 100644
    ---- a/packages/SystemUI/res/values-ta-rIN/strings.xml
    -+++ b/packages/SystemUI/res/values-ta-rIN/strings.xml
    -@@ -238,7 +238,7 @@
    -     <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"4G டேட்டா இடைநிறுத்தப்பட்டது"</string>
    -     <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"செல்லுலார் தரவு இடைநிறுத்தப்பட்டது"</string>
    -     <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"தரவு இடைநிறுத்தப்பட்டது"</string>
    --    <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"அமைக்கப்பட்ட தரவின் வரம்பை அடைந்துவிட்டதால், இந்தச் சுழற்சியின் மீதமுள்ள நாட்களுக்கான தரவுப் பயன்பாட்டைச் சாதனம் இடைநிறுத்தியுள்ளது.\n\nமீண்டும் தொடங்குவது, மொபைல் நிறுவனக் கட்டணங்களுக்கு உட்படுத்தலாம்."</string>
    -+    <string name="data_usage_disabled_dialog" msgid="1841738975235283398">"நீங்கள் அமைத்த தரவு வரம்பை அடைந்துவிட்டீர்கள். இப்போது செல்லுலார் தரவைப் பயன்படுத்த முடியாது.\n\nமீண்டும் தொடங்கினால், தரவுப் பயன்பாட்டிற்குக் கட்டணங்கள் விதிக்கப்படலாம்."</string>
    -     <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"மீண்டும் தொடங்கு"</string>
    -     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"இணைய இணைப்பு இல்லை"</string>
    -     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"வைஃபை இணைக்கப்பட்டது"</string>
    -@@ -404,6 +404,7 @@
    -     <string name="device_owned_footer" msgid="3802752663326030053">"சாதனம் கண்காணிக்கப்படலாம்"</string>
    -     <string name="profile_owned_footer" msgid="8021888108553696069">"சுயவிவரம் கண்காணிக்கப்படலாம்"</string>
    -     <string name="vpn_footer" msgid="2388611096129106812">"நெட்வொர்க் கண்காணிக்கப்படலாம்"</string>
    -+    <string name="branded_vpn_footer" msgid="2168111859226496230">"நெட்வொர்க் கண்காணிக்கப்படலாம்"</string>
    -     <string name="monitoring_title_device_owned" msgid="7121079311903859610">"சாதனத்தைக் கண்காணித்தல்"</string>
    -     <string name="monitoring_title_profile_owned" msgid="6790109874733501487">"சுயவிவரத்தைக் கண்காணித்தல்"</string>
    -     <string name="monitoring_title" msgid="169206259253048106">"நெட்வொர்க்கைக் கண்காணித்தல்"</string>
    -@@ -416,6 +417,7 @@
    -     <string name="legacy_vpn_name" msgid="6604123105765737830">"VPN"</string>
    -     <string name="monitoring_description_app" msgid="6259179342284742878">"<xliff:g id="APPLICATION">%1$s</xliff:g> உடன் இணைக்கப்பட்டுள்ளீர்கள். இந்தப் பயன்பாட்டால், மின்னஞ்சல்கள், பயன்பாடுகள் மற்றும் இணையதளங்கள் உட்பட உங்கள் நெட்வொர்க் செயல்பாட்டைக் கண்காணிக்க முடியும்."</string>
    -     <string name="monitoring_description_app_personal" msgid="484599052118316268">"<xliff:g id="APPLICATION">%1$s</xliff:g> உடன் இணைக்கப்பட்டுள்ளீர்கள். இந்தப் பயன்பாட்டால், மின்னஞ்சல்கள், பயன்பாடுகள் மற்றும் இணையதளங்கள் உட்பட உங்கள் தனிப்பட்ட நெட்வொர்க் செயல்பாட்டைக் கண்காணிக்க முடியும்."</string>
    -+    <string name="branded_monitoring_description_app_personal" msgid="2669518213949202599">"<xliff:g id="APPLICATION">%1$s</xliff:g> உடன் இணைக்கப்பட்டுள்ளீர்கள். இந்தப் பயன்பாட்டால் மின்னஞ்சல்கள், பயன்பாடுகள், இணையதளங்கள் உட்பட உங்கள் தனிப்பட்ட நெட்வொர்க் செயல்பாட்டைக் கண்காணிக்க முடியும்."</string>
    -     <string name="monitoring_description_app_work" msgid="1754325860918060897">"உங்கள் பணி சுயவிவரத்தை <xliff:g id="ORGANIZATION">%1$s</xliff:g> நிர்வகிக்கிறது. <xliff:g id="APPLICATION">%2$s</xliff:g> உடன் இணைக்கப்பட்டதால், மின்னஞ்சல்கள், பயன்பாடுகள் மற்றும் இணையதளங்கள் உட்பட உங்கள் பணியிட நெட்வொர்க் செயல்பாட்டை அதனால் கண்காணிக்க முடியும்.\n\nகூடுதல் தகவலுக்கு, நிர்வாகியைத் தொடர்புகொள்ளவும்."</string>
    -     <string name="monitoring_description_app_personal_work" msgid="4946600443852045903">"உங்கள் பணி சுயவிவரத்தை <xliff:g id="ORGANIZATION">%1$s</xliff:g> நிர்வகிக்கிறது. <xliff:g id="APPLICATION_WORK">%2$s</xliff:g> உடன் இணைக்கப்பட்டுள்ளதால், மின்னஞ்சல்கள், பயன்பாடுகள் மற்றும் இணையதளங்கள் உட்பட உங்கள் பணியிட நெட்வொர்க் செயல்பாட்டை அதனால் கண்காணிக்க முடியும்.\n\nமேலும் <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g> உடன் இணைக்கப்பட்டுள்ளதால், உங்கள் தனிப்பட்ட நெட்வொர்க் செயல்பாட்டையும் அதனால் கண்காணிக்க முடியும்."</string>
    -     <string name="monitoring_description_vpn_app_device_owned" msgid="4970443827043261703">"சாதனத்தை நிர்வகிப்பது: <xliff:g id="ORGANIZATION">%1$s</xliff:g>.\n\nஉங்கள் நிர்வாகியால் அமைப்புகள், நிறுவன அணுகல், பயன்பாடுகள், சாதனத்துடன் தொடர்புடைய தரவு மற்றும் சாதனத்தின் இருப்பிடத் தகவல் ஆகியவற்றைக் கண்காணிக்கவும் நிர்வகிக்கவும் முடியும்.\n\n<xliff:g id="APPLICATION">%2$s</xliff:g> உடன் இணைக்கப்பட்டதால், மின்னஞ்சல்கள், பயன்பாடுகள் மற்றும் இணையதளங்கள் உட்பட உங்கள் நெட்வொர்க் செயல்பாட்டை அதனால் கண்காணிக்க முடியும்.\n\nகூடுதல் தகவலுக்கு, நிர்வாகியைத் தொடர்புகொள்ளவும்."</string>
    -@@ -492,8 +494,6 @@
    -     <string name="clock_seconds_desc" msgid="6282693067130470675">"நிலைப் பட்டியில் கடிகார வினாடிகளைக் காட்டும். பேட்டரியின் ஆயுளைக் குறைக்கலாம்."</string>
    -     <string name="qs_rearrange" msgid="8060918697551068765">"விரைவு அமைப்புகளை மறுவரிசைப்படுத்து"</string>
    -     <string name="show_brightness" msgid="6613930842805942519">"விரைவு அமைப்புகளில் ஒளிர்வுப் பட்டியைக் காட்டு"</string>
    --    <string name="overview_nav_bar_gesture" msgid="8579814204727917764">"மேலே ஸ்வைப் செய்வதன் மூலம் திரையைப் பிரிக்கும் சைகையை இயக்கு"</string>
    --    <string name="overview_nav_bar_gesture_desc" msgid="6329167382305102615">"மேலோட்டப் பார்வை பொத்தானிலிருந்து மேலே ஸ்வைப் செய்வதன் மூலம், திரைப் பிரிப்பைச் செயலாக்குவதற்கான சைகையை இயக்கும்"</string>
    -     <string name="experimental" msgid="6198182315536726162">"சோதனை முயற்சி"</string>
    -     <string name="enable_bluetooth_title" msgid="5027037706500635269">"புளூடூத்தை இயக்கவா?"</string>
    -     <string name="enable_bluetooth_message" msgid="9106595990708985385">"உங்கள் டேப்லெட்டுடன் விசைப்பலகையை இணைக்க, முதலில் புளூடூத்தை இயக்க வேண்டும்."</string>
    -@@ -651,4 +651,5 @@
    -     <string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"<xliff:g id="ID_1">%s</xliff:g> அமைப்புகளைத் திற."</string>
    -     <string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"அமைப்புகளின் வரிசை முறையைத் திருத்து."</string>
    -     <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"பக்கம் <xliff:g id="ID_1">%1$d</xliff:g> / <xliff:g id="ID_2">%2$d</xliff:g>"</string>
    -+    <string name="cant_silence_or_block" msgid="999689262131488625">"அறிவிப்புகளை ஒலியடக்க அல்லது தடுக்க முடியவில்லை"</string>
    - </resources>
    -diff --git a/packages/SystemUI/res/values-te-rIN/strings.xml b/packages/SystemUI/res/values-te-rIN/strings.xml
    -index e50d47a..a1a85fc 100644
    ---- a/packages/SystemUI/res/values-te-rIN/strings.xml
    -+++ b/packages/SystemUI/res/values-te-rIN/strings.xml
    -@@ -238,7 +238,7 @@
    -     <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"4G డేటా పాజ్ చేయబడింది"</string>
    -     <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"సెల్యులార్ డేటా పాజ్ చేయబడింది"</string>
    -     <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"డేటా పాజ్ చేయబడింది"</string>
    --    <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"మీ సెట్ చేయబడిన డేటా పరిమితిని చేరుకున్నందున పరికరం ఈ సైకిల్‌లో మిగిలిన భాగానికి డేటా వినియోగాన్ని పాజ్ చేసింది.\n\nపునఃప్రారంభించడం వలన మీ క్యారియర్ ఛార్జీలు విధించవచ్చు."</string>
    -+    <string name="data_usage_disabled_dialog" msgid="1841738975235283398">"మీరు సెట్ చేసిన డేటా పరిమితిని చేరుకున్నారు. మీరు ఇప్పుడు సెల్యులార్ డేటాను ఉపయోగించడం లేదు.\n\nమీరు పునఃప్రారంభిస్తే, డేటా వినియోగానికి ఛార్జీలు వర్తించవచ్చు."</string>
    -     <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"పునఃప్రారంభించు"</string>
    -     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"ఇంటర్నెట్ కనెక్షన్ లేదు"</string>
    -     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi కనెక్ట్ చేయబడింది"</string>
    -@@ -404,6 +404,7 @@
    -     <string name="device_owned_footer" msgid="3802752663326030053">"పరికరం పర్యవేక్షించబడవచ్చు"</string>
    -     <string name="profile_owned_footer" msgid="8021888108553696069">"ప్రొఫైల్‌ని పర్యవేక్షించవచ్చు"</string>
    -     <string name="vpn_footer" msgid="2388611096129106812">"నెట్‌వర్క్ పర్యవేక్షించబడవచ్చు"</string>
    -+    <string name="branded_vpn_footer" msgid="2168111859226496230">"నెట్‌వర్క్ పర్యవేక్షించబడవచ్చు"</string>
    -     <string name="monitoring_title_device_owned" msgid="7121079311903859610">"పరికర పర్యవేక్షణ"</string>
    -     <string name="monitoring_title_profile_owned" msgid="6790109874733501487">"ప్రొఫైల్ పర్యవేక్షణ"</string>
    -     <string name="monitoring_title" msgid="169206259253048106">"నెట్‌వర్క్ పర్యవేక్షణ"</string>
    -@@ -416,6 +417,7 @@
    -     <string name="legacy_vpn_name" msgid="6604123105765737830">"VPN"</string>
    -     <string name="monitoring_description_app" msgid="6259179342284742878">"మీరు <xliff:g id="APPLICATION">%1$s</xliff:g>కి కనెక్ట్ చేయబడ్డారు, ఇది ఇమెయిల్‌లు, అనువర్తనాలు మరియు వెబ్‌సైట్‌లతో సహా మీ నెట్‌వర్క్ కార్యాచరణను పర్యవేక్షించగలదు."</string>
    -     <string name="monitoring_description_app_personal" msgid="484599052118316268">"మీరు <xliff:g id="APPLICATION">%1$s</xliff:g>కి కనెక్ట్ చేయబడ్డారు, ఇది ఇమెయిల్‌లు, అనువర్తనాలు మరియు వెబ్‌‍సైట్‌లతో సహా మీ వ్యక్తిగత నెట్‌వర్క్ కార్యాచరణను పర్యవేక్షించగలదు."</string>
    -+    <string name="branded_monitoring_description_app_personal" msgid="2669518213949202599">"మీరు <xliff:g id="APPLICATION">%1$s</xliff:g>కి కనెక్ట్ చేయబడ్డారు, ఇది ఇమెయిల్‌లు, అనువర్తనాలు మరియు వెబ్‌సైట్‌లతో సహా మీ వ్యక్తిగత నెట్‌వర్క్ కార్యాచరణను పర్యవేక్షించగలదు."</string>
    -     <string name="monitoring_description_app_work" msgid="1754325860918060897">"మీ కార్యాలయ ప్రొఫైల్‌ను <xliff:g id="ORGANIZATION">%1$s</xliff:g> నిర్వహిస్తోంది. అలాగే, మీ కార్యాలయ ప్రొఫైల్ <xliff:g id="APPLICATION">%2$s</xliff:g>కి కనెక్ట్ చేయబడింది, ఇది ఇమెయిల్‌లు, అనువర్తనాలు మరియు వెబ్‌సైట్‌లతో సహా మీ కార్యాలయ నెట్‌వర్క్ కార్యాచరణను పర్యవేక్షించగలదు.\n\nమరింత సమాచారం కోసం, మీ నిర్వాహకుడిని సంప్రదించండి."</string>
    -     <string name="monitoring_description_app_personal_work" msgid="4946600443852045903">"మీ కార్యాలయ ప్రొఫైల్‌ను <xliff:g id="ORGANIZATION">%1$s</xliff:g> నిర్వహిస్తోంది. అలాగే, మీ కార్యాలయ ప్రొఫైల్ <xliff:g id="APPLICATION_WORK">%2$s</xliff:g>కి కనెక్ట్ చేయబడింది, ఇది ఇమెయిల్‌లు, అనువర్తనాలు మరియు వెబ్‌సైట్‌లతో సహా మీ కార్యాలయ నెట్‌వర్క్ కార్యాచరణను పర్యవేక్షించగలదు.\n\nమీరు <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g>కి కూడా కనెక్ట్ చేయబడ్డారు, ఇది మీ వ్యక్తిగత నెట్‌వర్క్ కార్యాచరణను పర్యవేక్షించగలదు."</string>
    -     <string name="monitoring_description_vpn_app_device_owned" msgid="4970443827043261703">"మీ పరికరాన్ని <xliff:g id="ORGANIZATION">%1$s</xliff:g> నిర్వహిస్తోంది.\n\nమీ నిర్వాహకుడు సెట్టింగ్‌లను, కార్పొరేట్ ప్రాప్యతను, అనువర్తనాలను, మీ పరికరంతో అనుబంధించిన డేటాను మరియు మీ పరికర స్థాన సమాచారాన్ని పర్యవేక్షించగలరు మరియు నిర్వహించగలరు.\n\nమీరు <xliff:g id="APPLICATION">%2$s</xliff:g>కి కనెక్ట్ చేయబడ్డారు, ఇది ఇమెయిల్‌లు, అనువర్తనాలు మరియు వెబ్‌సైట్‌లతో సహా మీ నెట్‌వర్క్ కార్యాచరణను పర్యవేక్షించగలదు.\n\nమరింత సమాచారం కోసం, మీ నిర్వాహకుడిని సంప్రదించండి."</string>
    -@@ -492,8 +494,6 @@
    -     <string name="clock_seconds_desc" msgid="6282693067130470675">"స్థితి పట్టీలో గడియారం సెకన్లు చూపుతుంది. బ్యాటరీ శక్తి ప్రభావితం చేయవచ్చు."</string>
    -     <string name="qs_rearrange" msgid="8060918697551068765">"శీఘ్ర సెట్టింగ్‌ల ఏర్పాటు క్రమం మార్చు"</string>
    -     <string name="show_brightness" msgid="6613930842805942519">"శీఘ్ర సెట్టింగ్‌ల్లో ప్రకాశం చూపు"</string>
    --    <string name="overview_nav_bar_gesture" msgid="8579814204727917764">"పైకి స్వైప్ చేయడం ద్వారా స్క్రీన్ విభజన సంజ్ఞను ప్రారంభించు"</string>
    --    <string name="overview_nav_bar_gesture_desc" msgid="6329167382305102615">"స్థూలదృష్టి బటన్ నుండి పైకి స్వైప్ చేయడం ద్వారా స్క్రీన్ విభజనలోకి ప్రవేశించడానికి సంజ్ఞను ప్రారంభిస్తుంది"</string>
    -     <string name="experimental" msgid="6198182315536726162">"ప్రయోగాత్మకం"</string>
    -     <string name="enable_bluetooth_title" msgid="5027037706500635269">"బ్లూటూత్ ఆన్ చేయాలా?"</string>
    -     <string name="enable_bluetooth_message" msgid="9106595990708985385">"మీ కీబోర్డ్‌ను మీ టాబ్లెట్‌తో కనెక్ట్ చేయడానికి, మీరు ముందుగా బ్లూటూత్ ఆన్ చేయాలి."</string>
    -@@ -651,4 +651,5 @@
    -     <string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"<xliff:g id="ID_1">%s</xliff:g> సెట్టింగ్‌లను తెరవండి."</string>
    -     <string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"సెట్టింగ్‌ల క్రమాన్ని సవరించండి."</string>
    -     <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"<xliff:g id="ID_2">%2$d</xliff:g>లో <xliff:g id="ID_1">%1$d</xliff:g>వ పేజీ"</string>
    -+    <string name="cant_silence_or_block" msgid="999689262131488625">"నోటిఫికేషన్‌లను నిశ్శబ్దంగా ఉంచలేరు లేదా బ్లాక్ చేయలేరు"</string>
    - </resources>
    -diff --git a/packages/SystemUI/res/values-th/strings.xml b/packages/SystemUI/res/values-th/strings.xml
    -index 7eb227e..805431d 100644
    ---- a/packages/SystemUI/res/values-th/strings.xml
    -+++ b/packages/SystemUI/res/values-th/strings.xml
    -@@ -238,7 +238,7 @@
    -     <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"หยุดการใช้ข้อมูล 4G ชั่วคราวแล้ว"</string>
    -     <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"หยุดการใช้ข้อมูลมือถือชั่วคราวแล้ว"</string>
    -     <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"หยุดการใช้ข้อมูลชั่วคราวแล้ว"</string>
    --    <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"เนื่องจากใช้งานข้อมูลถึงขีดจำกัดที่กำหนดไว้แล้ว อุปกรณ์จึงหยุดการใช้งานข้อมูลไว้ชั่วคราวตลอดระยะเวลาที่เหลือของรอบนี้\n\nการทำให้กลับมาทำงานอีกครั้งอาจทำให้เกิดค่าใช้จ่ายจากผู้ให้บริการ"</string>
    -+    <string name="data_usage_disabled_dialog" msgid="1841738975235283398">"คุณใช้อินเทอร์เน็ตเกินปริมาณที่กำหนดไว้ ระบบจะไม่ใช้เครือข่ายมือถือต่อไป\n\nหากใช้ต่อ อาจมีค่าบริการตามปริมาณการใช้อินเทอร์เน็ต"</string>
    -     <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"ทำต่อ"</string>
    -     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"ไม่มีอินเทอร์เน็ต"</string>
    -     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"เชื่อมต่อ WiFi แล้ว"</string>
    -@@ -404,6 +404,7 @@
    -     <string name="device_owned_footer" msgid="3802752663326030053">"อาจมีการตรวจสอบอุปกรณ์"</string>
    -     <string name="profile_owned_footer" msgid="8021888108553696069">"อาจมีการตรวจสอบโปรไฟล์"</string>
    -     <string name="vpn_footer" msgid="2388611096129106812">"เครือข่ายอาจได้รับการตรวจสอบ"</string>
    -+    <string name="branded_vpn_footer" msgid="2168111859226496230">"เครือข่ายอาจถูกตรวจสอบ"</string>
    -     <string name="monitoring_title_device_owned" msgid="7121079311903859610">"การตรวจสอบอุปกรณ์"</string>
    -     <string name="monitoring_title_profile_owned" msgid="6790109874733501487">"การตรวจสอบโปรไฟล์"</string>
    -     <string name="monitoring_title" msgid="169206259253048106">"การตรวจสอบเครือข่าย"</string>
    -@@ -416,6 +417,7 @@
    -     <string name="legacy_vpn_name" msgid="6604123105765737830">"VPN"</string>
    -     <string name="monitoring_description_app" msgid="6259179342284742878">"คุณเชื่อมต่อกับ <xliff:g id="APPLICATION">%1$s</xliff:g> ซึ่งสามารถตรวจสอบกิจกรรมในเครือข่ายของคุณ รวมถึงอีเมล แอป และเว็บไซต์ได้"</string>
    -     <string name="monitoring_description_app_personal" msgid="484599052118316268">"คุณเชื่อมต่อกับ <xliff:g id="APPLICATION">%1$s</xliff:g> ซึ่งสามารถตรวจสอบกิจกรรมในเครือข่ายส่วนตัวของคุณ รวมถึงอีเมล แอป และเว็บไซต์ได้"</string>
    -+    <string name="branded_monitoring_description_app_personal" msgid="2669518213949202599">"คุณเชื่อมต่อกับ <xliff:g id="APPLICATION">%1$s</xliff:g> ซึ่งสามารถตรวจสอบกิจกรรมในเครือข่ายส่วนตัวของคุณ รวมถึงอีเมล แอป และเว็บไซต์ได้"</string>
    -     <string name="monitoring_description_app_work" msgid="1754325860918060897">"โปรไฟล์งานได้รับการจัดการโดย <xliff:g id="ORGANIZATION">%1$s</xliff:g> โดยมีการเชื่อมต่อกับ <xliff:g id="APPLICATION">%2$s</xliff:g> ซึ่งสามารถตรวจสอบกิจกรรมในเครือข่าย รวมถึงอีเมล แอป และเว็บไซต์ได้\n\nสำหรับข้อมูลเพิ่มเติม โปรดติดต่อผู้ดูแลระบบ"</string>
    -     <string name="monitoring_description_app_personal_work" msgid="4946600443852045903">"โปรไฟล์งานได้รับการจัดการโดย <xliff:g id="ORGANIZATION">%1$s</xliff:g> โดยมีการเชื่อมต่อกับ <xliff:g id="APPLICATION_WORK">%2$s</xliff:g> ซึ่งสามารถตรวจสอบกิจกรรมในเครือข่าย รวมถึงอีเมล แอป และเว็บไซต์ได้\n\nนอกจากนี้ คุณยังเชื่อมต่อกับ <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g> ซึ่งสามารถตรวจสอบกิจกรรมในเครือข่ายส่วนตัวได้"</string>
    -     <string name="monitoring_description_vpn_app_device_owned" msgid="4970443827043261703">"อุปกรณ์ได้รับการจัดการโดย <xliff:g id="ORGANIZATION">%1$s</xliff:g>\n\nผู้ดูและรบบของคุณสามารถตรวจสอบและจัดการการตั้งค่า การเข้าถึงของบริษัท แอป ข้อมูลที่เชื่อมโยงกับอุปกรณ์ และข้อมูลตำแหน่งของอุปกรณ์ได้\n\nคุณมีการเชื่อมต่อกับ <xliff:g id="APPLICATION">%2$s</xliff:g> ซึ่งสามารถตรวจสอบกิจกรรมในเครือข่ายรวมถึงอีเมล แอป และเว็บไซต์ได้\n\nสำหรับข้อมูลเพิ่มเติม โปรดติดต่อผู้ดูแลระบบ"</string>
    -@@ -492,8 +494,6 @@
    -     <string name="clock_seconds_desc" msgid="6282693067130470675">"แสดงวินาทีของนาฬิกาในแถบสถานะ อาจส่งผลต่ออายุแบตเตอรี"</string>
    -     <string name="qs_rearrange" msgid="8060918697551068765">"จัดเรียงการตั้งค่าด่วนใหม่"</string>
    -     <string name="show_brightness" msgid="6613930842805942519">"แสดงความสว่างในการตั้งค่าด่วน"</string>
    --    <string name="overview_nav_bar_gesture" msgid="8579814204727917764">"เปิดใช้ท่าทางสัมผัสการเลื่อนขึ้นเพื่อแยกหน้าจอ"</string>
    --    <string name="overview_nav_bar_gesture_desc" msgid="6329167382305102615">"เปิดใช้ท่าทางสัมผัสเพื่อเข้าสู่โหมดแยกหน้าจอโดยเลื่อนขึ้นจากปุ่มภาพรวม"</string>
    -     <string name="experimental" msgid="6198182315536726162">"ทดสอบ"</string>
    -     <string name="enable_bluetooth_title" msgid="5027037706500635269">"เปิดบลูทูธไหม"</string>
    -     <string name="enable_bluetooth_message" msgid="9106595990708985385">"หากต้องการเชื่อมต่อแป้นพิมพ์กับแท็บเล็ต คุณต้องเปิดบลูทูธก่อน"</string>
    -@@ -651,4 +651,5 @@
    -     <string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"เปิดการตั้งค่า <xliff:g id="ID_1">%s</xliff:g>"</string>
    -     <string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"แก้ไขลำดับการตั้งค่า"</string>
    -     <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"หน้า <xliff:g id="ID_1">%1$d</xliff:g> จาก <xliff:g id="ID_2">%2$d</xliff:g>"</string>
    -+    <string name="cant_silence_or_block" msgid="999689262131488625">"ไม่สามารถปิดเสียงหรือบล็อกการแจ้งเตือน"</string>
    - </resources>
    -diff --git a/packages/SystemUI/res/values-tl/strings.xml b/packages/SystemUI/res/values-tl/strings.xml
    -index ed6830e..89af189 100644
    ---- a/packages/SystemUI/res/values-tl/strings.xml
    -+++ b/packages/SystemUI/res/values-tl/strings.xml
    -@@ -238,7 +238,7 @@
    -     <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"Naka-pause ang 4G data"</string>
    -     <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"Naka-pause ang cellular data"</string>
    -     <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"Naka-pause ang data"</string>
    --    <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"Dahil naabot ang iyong nakatakdang limitasyon sa data, na-pause ng device ang paggamit ng data para sa nalalabing bahagi ng cycle na ito.\n\nMaaaring makakuha ng mga singilin mula sa iyong carrier ang pagpapatuloy."</string>
    -+    <string name="data_usage_disabled_dialog" msgid="1841738975235283398">"Naabot na ang limitasyon sa data na itinakda mo. Hindi ka na gumagamit ng cellular data.\n\nKung magpapatuloy ka, maaari kang masingil para sa paggamit ng data."</string>
    -     <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"Ipagpatuloy"</string>
    -     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Walang koneksyon sa Internet"</string>
    -     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"nakakonekta ang Wi-Fi"</string>
    -@@ -404,6 +404,7 @@
    -     <string name="device_owned_footer" msgid="3802752663326030053">"Maaaring subaybayan ang device"</string>
    -     <string name="profile_owned_footer" msgid="8021888108553696069">"Maaaring subaybayan ang profile"</string>
    -     <string name="vpn_footer" msgid="2388611096129106812">"Maaaring sinusubaybayan ang network"</string>
    -+    <string name="branded_vpn_footer" msgid="2168111859226496230">"Maaaring sinusubaybayan ang network"</string>
    -     <string name="monitoring_title_device_owned" msgid="7121079311903859610">"Pagsubaybay sa device"</string>
    -     <string name="monitoring_title_profile_owned" msgid="6790109874733501487">"Pagsubaybay sa Profile"</string>
    -     <string name="monitoring_title" msgid="169206259253048106">"Pagsubaybay sa network"</string>
    -@@ -416,6 +417,7 @@
    -     <string name="legacy_vpn_name" msgid="6604123105765737830">"VPN"</string>
    -     <string name="monitoring_description_app" msgid="6259179342284742878">"Nakakonekta ka sa <xliff:g id="APPLICATION">%1$s</xliff:g>, na maaaring sumubaybay sa iyong aktibidad sa network kabilang ang mga email, app at website."</string>
    -     <string name="monitoring_description_app_personal" msgid="484599052118316268">"Nakakonekta ka sa <xliff:g id="APPLICATION">%1$s</xliff:g>, na maaaring sumubaybay sa iyong personal na aktibidad sa network, kabilang ang mga email, app at website."</string>
    -+    <string name="branded_monitoring_description_app_personal" msgid="2669518213949202599">"Nakakonekta ka sa <xliff:g id="APPLICATION">%1$s</xliff:g>, na maaaring sumubaybay sa aktibidad sa iyong personal na network, kabilang ang mga email, app at website."</string>
    -     <string name="monitoring_description_app_work" msgid="1754325860918060897">"Ang iyong profile sa trabaho ay pinapamahalaan ng <xliff:g id="ORGANIZATION">%1$s</xliff:g>. Nakakonekta ito sa <xliff:g id="APPLICATION">%2$s</xliff:g>, na maaaring sumubaybay sa iyong aktibidad sa network, kabilang ang mga email, app at website.\n\nPara sa higit pang impormasyon, makipag-ugnayan sa iyong administrator."</string>
    -     <string name="monitoring_description_app_personal_work" msgid="4946600443852045903">"Ang iyong profile sa trabaho ay pinapamahalaan ng <xliff:g id="ORGANIZATION">%1$s</xliff:g>. Nakakonekta ito sa <xliff:g id="APPLICATION_WORK">%2$s</xliff:g>, na maaaring sumubaybay sa iyong aktibidad sa network, kabilang ang mga email, app at website.\n\nNakakonekta ka rin sa <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g>, na maaaring sumubaybay sa iyong personal na aktibidad sa network."</string>
    -     <string name="monitoring_description_vpn_app_device_owned" msgid="4970443827043261703">"Pinapamahalaan ang iyong device ng <xliff:g id="ORGANIZATION">%1$s</xliff:g>.\n\nMaaaring subaybayan at pamahalaan ng iyong administrator ang mga setting, corporate na access, app, data na nauugnay sa iyong device at ang impormasyon ng lokasyon ng iyong device.\n\nNakakonekta ka sa <xliff:g id="APPLICATION">%2$s</xliff:g>, na maaaring subaybayan ang iyong aktibidad sa network, kabilang ang mga email, app at website.\n\nPara sa higit pang impormasyon, makipag-ugnayan sa iyong administrator."</string>
    -@@ -492,8 +494,6 @@
    -     <string name="clock_seconds_desc" msgid="6282693067130470675">"Ipakita ang mga segundo ng orasan sa status bar. Maaaring makaapekto sa tagal ng baterya."</string>
    -     <string name="qs_rearrange" msgid="8060918697551068765">"Ayusing Muli ang Mga Mabilisang Setting"</string>
    -     <string name="show_brightness" msgid="6613930842805942519">"Ipakita ang liwanag sa Mga Mabilisang Setting"</string>
    --    <string name="overview_nav_bar_gesture" msgid="8579814204727917764">"I-enable ang pag-swipe pataas na galaw para sa split-screen"</string>
    --    <string name="overview_nav_bar_gesture_desc" msgid="6329167382305102615">"I-enable ang gesture upang makapasok sa split-screen sa pamamagitan ng pagsa-swipe pataas mula sa button ng Pangkalahatang-ideya"</string>
    -     <string name="experimental" msgid="6198182315536726162">"Pang-eksperimento"</string>
    -     <string name="enable_bluetooth_title" msgid="5027037706500635269">"I-on ang Bluetooth?"</string>
    -     <string name="enable_bluetooth_message" msgid="9106595990708985385">"Upang ikonekta ang iyong keyboard sa iyong tablet, kailangan mo munang i-on ang Bluetooth."</string>
    -@@ -651,4 +651,5 @@
    -     <string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"Buksan ang mga setting ng <xliff:g id="ID_1">%s</xliff:g>."</string>
    -     <string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"I-edit ang pagkakasunud-sunod ng mga setting."</string>
    -     <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"Page <xliff:g id="ID_1">%1$d</xliff:g> ng <xliff:g id="ID_2">%2$d</xliff:g>"</string>
    -+    <string name="cant_silence_or_block" msgid="999689262131488625">"Hindi maaaring i-silent o i-block ang mga notification"</string>
    - </resources>
    -diff --git a/packages/SystemUI/res/values-tr/strings.xml b/packages/SystemUI/res/values-tr/strings.xml
    -index 8fae7975..c17e9fc 100644
    ---- a/packages/SystemUI/res/values-tr/strings.xml
    -+++ b/packages/SystemUI/res/values-tr/strings.xml
    -@@ -238,7 +238,7 @@
    -     <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"4G veri kullanımı duraklatıldı"</string>
    -     <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"Hücresel veri kullanımı duraklatıldı"</string>
    -     <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"Veri kullanımı duraklatıldı"</string>
    --    <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"Ayarlanmış olan veri sınırınıza ulaşıldığından, bu dönemin kalan süresi için cihazda veri kullanımı duraklatıldı.\n\nVeri kullanımını devam ettirmek, operatörünüzün sizden ödeme almasına neden olabilir."</string>
    -+    <string name="data_usage_disabled_dialog" msgid="1841738975235283398">"Ayarladığınız veri limitine ulaşıldı. Artık hücresel verilerinizi kullanmıyorsunuz.\n\nHücresel veri kullanımını devam ettirirseniz veri kullanım ücretleri ödemeniz gerekebilir."</string>
    -     <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"Devam ettir"</string>
    -     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"İnternet bağlantısı yok"</string>
    -     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Kablosuz bağlandı"</string>
    -@@ -404,6 +404,7 @@
    -     <string name="device_owned_footer" msgid="3802752663326030053">"Cihaz izlenebilir"</string>
    -     <string name="profile_owned_footer" msgid="8021888108553696069">"Profil izlenebilir"</string>
    -     <string name="vpn_footer" msgid="2388611096129106812">"Ağ etkinliği izlenebilir"</string>
    -+    <string name="branded_vpn_footer" msgid="2168111859226496230">"Ağ etkinliği izlenebilir"</string>
    -     <string name="monitoring_title_device_owned" msgid="7121079311903859610">"Cihaz izleme"</string>
    -     <string name="monitoring_title_profile_owned" msgid="6790109874733501487">"Profil izleme"</string>
    -     <string name="monitoring_title" msgid="169206259253048106">"Ağ izleme"</string>
    -@@ -416,6 +417,7 @@
    -     <string name="legacy_vpn_name" msgid="6604123105765737830">"VPN"</string>
    -     <string name="monitoring_description_app" msgid="6259179342284742878">"E-postalarınız, uygulamalarınız ve web siteleriniz dahil olmak üzere ağ etkinliğinizi izleyebilen <xliff:g id="APPLICATION">%1$s</xliff:g> uygulamasına bağlısınız."</string>
    -     <string name="monitoring_description_app_personal" msgid="484599052118316268">"E-postalarınız, uygulamalarınız ve web siteleriniz dahil olmak üzere kişisel ağ etkinliğinizi izleyebilen <xliff:g id="APPLICATION">%1$s</xliff:g> uygulamasına bağlısınız."</string>
    -+    <string name="branded_monitoring_description_app_personal" msgid="2669518213949202599">"E-postalarınız, uygulamalarınız ve web siteleriniz dahil olmak üzere kişisel ağ etkinliğinizi izleyebilen <xliff:g id="APPLICATION">%1$s</xliff:g> uygulamasına bağlısınız."</string>
    -     <string name="monitoring_description_app_work" msgid="1754325860918060897">"İş profiliniz <xliff:g id="ORGANIZATION">%1$s</xliff:g> tarafından yönetiliyor. E-postalarınız, uygulamalarınız ve web siteleriniz dahil olmak üzere ağ etkinliğinizi izleyebilen <xliff:g id="APPLICATION">%2$s</xliff:g> uygulamasına bağlı.\n\nDaha fazla bilgi için yöneticinizle iletişim kurun."</string>
    -     <string name="monitoring_description_app_personal_work" msgid="4946600443852045903">"İş profiliniz <xliff:g id="ORGANIZATION">%1$s</xliff:g> tarafından yönetiliyor. E-postalarınız, uygulamalarınız ve web siteleriniz dahil olmak üzere ağ etkinliğinizi izleyebilen <xliff:g id="APPLICATION_WORK">%2$s</xliff:g> uygulamasına bağlı.\n\n Ayrıca kişisel ağ etkinliğinizi izleyebilen <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g> uygulamasına bağlısınız."</string>
    -     <string name="monitoring_description_vpn_app_device_owned" msgid="4970443827043261703">"Cihazınız <xliff:g id="ORGANIZATION">%1$s</xliff:g> tarafından yönetiliyor.\n\nYöneticiniz; ayarları, şirket erişimini, uygulamaları, cihazınızla ilişkilendirilmiş verileri ve cihazınızın konum bilgilerini izleyebilir ve yönetebilir.\n\nE-postalarınız, uygulamalarınız ve web siteleriniz dahil olmak üzere ağ etkinliğinizi izleyebilen <xliff:g id="APPLICATION">%2$s</xliff:g> uygulamasına bağlısınız.\n\nDaha fazla bilgi edinmek için yöneticinizle iletişim kurun."</string>
    -@@ -492,8 +494,6 @@
    -     <string name="clock_seconds_desc" msgid="6282693067130470675">"Durum çubuğunda saatin saniyelerini gösterir. Pil ömrünü etkileyebilir."</string>
    -     <string name="qs_rearrange" msgid="8060918697551068765">"Hızlı Ayarlar\'ı Yeniden Düzenle"</string>
    -     <string name="show_brightness" msgid="6613930842805942519">"Hızlı Ayarlar\'da parlaklığı göster"</string>
    --    <string name="overview_nav_bar_gesture" msgid="8579814204727917764">"Hızlıca yukarı kaydırma hareketiyle ekran bölm. etkinleştir"</string>
    --    <string name="overview_nav_bar_gesture_desc" msgid="6329167382305102615">"Genel bakış düğmesinden yukarı hızlıca kaydırarak bölünmüş ekrana geçme hareketini etkinleştir"</string>
    -     <string name="experimental" msgid="6198182315536726162">"Deneysel"</string>
    -     <string name="enable_bluetooth_title" msgid="5027037706500635269">"Bluetooth açılsın mı?"</string>
    -     <string name="enable_bluetooth_message" msgid="9106595990708985385">"Klavyenizi tabletinize bağlamak için önce Bluetooth\'u açmanız gerekir."</string>
    -@@ -651,4 +651,5 @@
    -     <string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"<xliff:g id="ID_1">%s</xliff:g> ayarlarını aç."</string>
    -     <string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"Ayarların sırasını düzenle."</string>
    -     <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"Sayfa <xliff:g id="ID_1">%1$d</xliff:g> / <xliff:g id="ID_2">%2$d</xliff:g>"</string>
    -+    <string name="cant_silence_or_block" msgid="999689262131488625">"Bildirimler engellenemez veya sesi kapatılamaz"</string>
    - </resources>
    -diff --git a/packages/SystemUI/res/values-uk/strings.xml b/packages/SystemUI/res/values-uk/strings.xml
    -index 7eaf0db..92f1372 100644
    ---- a/packages/SystemUI/res/values-uk/strings.xml
    -+++ b/packages/SystemUI/res/values-uk/strings.xml
    -@@ -242,7 +242,7 @@
    -     <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"Передавання даних 4G призупинено"</string>
    -     <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"Передавання мобільних даних призупинено"</string>
    -     <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"Передавання даних призупинено"</string>
    --    <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"Пристрій призупинив передавання даних до кінця цього циклу, оскільки ваш ліміт перевищено.\n\nЯкщо ви відновите передавання даних, оператор може стягувати додаткову плату."</string>
    -+    <string name="data_usage_disabled_dialog" msgid="1841738975235283398">"Ви досягнули вказаного ліміту даних. Мобільний трафік вимкнено.\n\nЯкщо продовжите, може стягуватися плата за використання трафіку."</string>
    -     <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"Відновити"</string>
    -     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Немає з’єднання"</string>
    -     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi під’єднано"</string>
    -@@ -410,6 +410,7 @@
    -     <string name="device_owned_footer" msgid="3802752663326030053">"Дії на пристрої можуть відстежуватися"</string>
    -     <string name="profile_owned_footer" msgid="8021888108553696069">"Профіль може відстежуватись"</string>
    -     <string name="vpn_footer" msgid="2388611096129106812">"Дії в мережі можуть відстежуватися"</string>
    -+    <string name="branded_vpn_footer" msgid="2168111859226496230">"Мережа може відстежуватися"</string>
    -     <string name="monitoring_title_device_owned" msgid="7121079311903859610">"Відстеження дій на пристрої"</string>
    -     <string name="monitoring_title_profile_owned" msgid="6790109874733501487">"Відстеження профілю"</string>
    -     <string name="monitoring_title" msgid="169206259253048106">"Відстеження дій у мережі"</string>
    -@@ -422,6 +423,7 @@
    -     <string name="legacy_vpn_name" msgid="6604123105765737830">"VPN"</string>
    -     <string name="monitoring_description_app" msgid="6259179342284742878">"Ваш профіль під’єднано до додатка <xliff:g id="APPLICATION">%1$s</xliff:g>, який може відстежувати вашу активність у мережі, зокрема в електронній пошті, додатках і на веб-сайтах."</string>
    -     <string name="monitoring_description_app_personal" msgid="484599052118316268">"Ваш профіль під’єднано до додатка <xliff:g id="APPLICATION">%1$s</xliff:g>, який може відстежувати вашу особисту активність у мережі, зокрема в електронній пошті, додатках і на веб-сайтах."</string>
    -+    <string name="branded_monitoring_description_app_personal" msgid="2669518213949202599">"Ваш профіль під’єднано до додатка <xliff:g id="APPLICATION">%1$s</xliff:g>, який може відстежувати вашу особисту активність у мережі, зокрема доступ до електронної пошти, додатків і веб-сайтів."</string>
    -     <string name="monitoring_description_app_work" msgid="1754325860918060897">"Вашим робочим профілем керує <xliff:g id="ORGANIZATION">%1$s</xliff:g>. Профіль під’єднано до додатка <xliff:g id="APPLICATION">%2$s</xliff:g>, який може відстежувати вашу робочу активність у мережі, зокрема в електронній пошті, додатках і на веб-сайтах.\n\nЗв’яжіться з адміністратором, щоб дізнатися більше."</string>
    -     <string name="monitoring_description_app_personal_work" msgid="4946600443852045903">"Вашим робочим профілем керує <xliff:g id="ORGANIZATION">%1$s</xliff:g>. Профіль під’єднано до додатка <xliff:g id="APPLICATION_WORK">%2$s</xliff:g>, який може відстежувати вашу робочу активність у мережі, зокрема в електронній пошті, додатках і на веб-сайтах.\n\nВаш профіль також під’єднано до додатка <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g>, який може відстежувати вашу особисту активність у мережі."</string>
    -     <string name="monitoring_description_vpn_app_device_owned" msgid="4970443827043261703">"Вашим пристроєм керує організація <xliff:g id="ORGANIZATION">%1$s</xliff:g>.\n\nАдміністратор може відстежувати та контролювати налаштування, корпоративний доступ, додатки, геодані й інші дані, пов’язані з вашим пристроєм.\n\nВаш профіль під’єднано до додатка <xliff:g id="APPLICATION">%2$s</xliff:g>, який може відстежувати вашу активність у мережі, зокрема в електронній пошті, додатках і на веб-сайтах.\n\nЗв’яжіться з адміністратором, щоб дізнатися більше."</string>
    -@@ -498,8 +500,6 @@
    -     <string name="clock_seconds_desc" msgid="6282693067130470675">"Показувати секунди на годиннику в рядку стану. Акумулятор може розряджатися швидше."</string>
    -     <string name="qs_rearrange" msgid="8060918697551068765">"Упорядкувати швидкі налаштування"</string>
    -     <string name="show_brightness" msgid="6613930842805942519">"Показувати панель яскравості у швидких налаштуваннях"</string>
    --    <string name="overview_nav_bar_gesture" msgid="8579814204727917764">"Увімкнути розділення екрана рухом пальця вгору"</string>
    --    <string name="overview_nav_bar_gesture_desc" msgid="6329167382305102615">"Увімкнути жест розділення екрана рухом пальця вгору від кнопки \"Огляд\""</string>
    -     <string name="experimental" msgid="6198182315536726162">"Експериментальні налаштування"</string>
    -     <string name="enable_bluetooth_title" msgid="5027037706500635269">"Увімкнути Bluetooth?"</string>
    -     <string name="enable_bluetooth_message" msgid="9106595990708985385">"Щоб під’єднати клавіатуру до планшета, спершу потрібно ввімкнути Bluetooth."</string>
    -@@ -657,4 +657,5 @@
    -     <string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"Відкрити налаштування <xliff:g id="ID_1">%s</xliff:g>."</string>
    -     <string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"Змінити порядок налаштувань."</string>
    -     <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"Сторінка <xliff:g id="ID_1">%1$d</xliff:g> з <xliff:g id="ID_2">%2$d</xliff:g>"</string>
    -+    <string name="cant_silence_or_block" msgid="999689262131488625">"Сповіщення не можна вимкнути або заблокувати"</string>
    - </resources>
    -diff --git a/packages/SystemUI/res/values-ur-rPK/strings.xml b/packages/SystemUI/res/values-ur-rPK/strings.xml
    -index 5c0ed18..b7b87eb 100644
    ---- a/packages/SystemUI/res/values-ur-rPK/strings.xml
    -+++ b/packages/SystemUI/res/values-ur-rPK/strings.xml
    -@@ -238,7 +238,7 @@
    -     <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"‏4G ڈیٹا موقوف کر دیا گیا"</string>
    -     <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"سیلولر ڈیٹا موقوف کر دیا گیا"</string>
    -     <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"ڈیٹا موقوف کر دیا گیا"</string>
    --    <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"چونکہ آپ کی سیٹ کردہ ڈیٹا کی حد تک پہنچ گیا، لہذا آلہ نے اس سائیکل کے بقیہ حصے کیلئے ڈیٹا کے استعمال کو موقوف کر دیا ہے۔\n\nدوبارہ شروع کرنے سے آپ کے کیریئر سے چارجز لگ سکتے ہیں۔"</string>
    -+    <string name="data_usage_disabled_dialog" msgid="1841738975235283398">"آپ کی سیٹ کردہ ڈیٹا کی حد پوری ہو گئی ہے۔ آپ اب سیلولر ڈیٹا استعمال نہیں کر رہے۔\n\nاگر آپ دوبارہ شروع کرتے ہیں تو ڈیٹا کے استعمال کے چارجز لاگو ہو سکتے ہیں۔"</string>
    -     <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"دوبارہ شروع کریں"</string>
    -     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"کوئی انٹرنیٹ کنکشن نہیں"</string>
    -     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"‏Wi-Fi مربوط ہے"</string>
    -@@ -404,6 +404,7 @@
    -     <string name="device_owned_footer" msgid="3802752663326030053">"آلہ کو مانیٹر کیا جا سکتا ہے"</string>
    -     <string name="profile_owned_footer" msgid="8021888108553696069">"پروفائل کو مانیٹر کیا جا سکتا ہے"</string>
    -     <string name="vpn_footer" msgid="2388611096129106812">"نیٹ ورک کو مانیٹر کیا جا سکتا ہے"</string>
    -+    <string name="branded_vpn_footer" msgid="2168111859226496230">"نیٹ ورک کو شاید مانیٹر کیا جائے"</string>
    -     <string name="monitoring_title_device_owned" msgid="7121079311903859610">"آلہ کو مانیٹر کرنا"</string>
    -     <string name="monitoring_title_profile_owned" msgid="6790109874733501487">"پروفائل کو مانیٹر کرنا"</string>
    -     <string name="monitoring_title" msgid="169206259253048106">"نیٹ ورک کو مانیٹر کرنا"</string>
    -@@ -416,6 +417,7 @@
    -     <string name="legacy_vpn_name" msgid="6604123105765737830">"VPN"</string>
    -     <string name="monitoring_description_app" msgid="6259179342284742878">"آپ <xliff:g id="APPLICATION">%1$s</xliff:g> سے منسلک ہیں، جو ای میلز، ایپس اور ویب سائٹس سمیت آپ کے نیٹ ورک کی سرگرمی مانیٹر کر سکتی ہے۔"</string>
    -     <string name="monitoring_description_app_personal" msgid="484599052118316268">"آپ <xliff:g id="APPLICATION">%1$s</xliff:g> سے منسلک ہیں، جو آپ کے نجی نیٹ ورک کی سرگرمی سمیت ای میلز، ایپس اور ویب سائٹس مانیٹر کر سکتی ہے۔"</string>
    -+    <string name="branded_monitoring_description_app_personal" msgid="2669518213949202599">"آپ <xliff:g id="APPLICATION">%1$s</xliff:g> سے منسلک ہیں، جو ای میلز، ایپس اور ویب سائٹس سمیت آپ کے نجی نیٹ ورک کی سرگرمی مانیٹر کر سکتی ہے۔"</string>
    -     <string name="monitoring_description_app_work" msgid="1754325860918060897">"آپ کا دفتری پروفائل <xliff:g id="ORGANIZATION">%1$s</xliff:g> کے زیر انتظام ہے۔ یہ <xliff:g id="APPLICATION">%2$s</xliff:g> سے منسلک ہے، جو ای میلز، ایپس اور ویب سائٹس سمیت آپ کے نیٹ ورک کی سرگرمی مانیٹر کر سکتی ہے۔\n\nمزید معلومات کیلئے اپنے منتظم سے رابطہ کریں۔"</string>
    -     <string name="monitoring_description_app_personal_work" msgid="4946600443852045903">"آپ کا دفتری پروفائل <xliff:g id="ORGANIZATION">%1$s</xliff:g> کے زیر انتظام ہے۔ یہ <xliff:g id="APPLICATION_WORK">%2$s</xliff:g> سے منسلک ہے، جو ای میلز، ایپس اور ویب سائٹس سمیت آپ کے نیٹ ورک کی سرگرمی مانیٹر کر سکتی ہے۔\n\nآپ <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g> سے بھی منسلک ہیں، جو آپ کے نجی نیٹ ورک کی سرگرمی کو مانیٹر کر سکتی ہے۔"</string>
    -     <string name="monitoring_description_vpn_app_device_owned" msgid="4970443827043261703">"آپ کا آلہ <xliff:g id="ORGANIZATION">%1$s</xliff:g> کے زیر انتظام ہے۔\n\nآپ کا منتظم ترتیبات، کارپوریٹ رسائی، ایپس، آپ کے آلہ سے وابستہ ڈیٹا اور آپ کے آلہ کے مقام کی معلومات کو مانیٹر اور ان کا نظم کر سکتا ہے۔\n\nآپ <xliff:g id="APPLICATION">%2$s</xliff:g> سے منسلک ہیں، جو ای میلز، ایپس اور ویب سائٹس سمیت آپ کے نیٹ ورک کی سرگرمی مانیٹر کر سکتی ہے۔\n\nمزید معلومات کیلئے اپنے منتظم سے رابطہ کریں۔"</string>
    -@@ -492,8 +494,6 @@
    -     <string name="clock_seconds_desc" msgid="6282693067130470675">"گھڑی کے سیکنڈز اسٹیٹس بار میں دکھائیں۔ اس کا بیٹری کی زندگی پر اثر پڑ سکتا ہے۔"</string>
    -     <string name="qs_rearrange" msgid="8060918697551068765">"فوری ترتیبات کو دوبارہ ترتیب دیں"</string>
    -     <string name="show_brightness" msgid="6613930842805942519">"فوری ترتیبات میں چمکیلا پن دکھائیں"</string>
    --    <string name="overview_nav_bar_gesture" msgid="8579814204727917764">"سپلٹ اسکرین کیلئے سوائپ اپ اشارہ فعال کریں"</string>
    --    <string name="overview_nav_bar_gesture_desc" msgid="6329167382305102615">"مجموعی جائزہ بٹن سے سوائپ اپ کرکے سپلٹ اسکرین میں داخل ہونے کیلئے اشارہ فعال کریں"</string>
    -     <string name="experimental" msgid="6198182315536726162">"تجرباتی"</string>
    -     <string name="enable_bluetooth_title" msgid="5027037706500635269">"بلوٹوتھ آن کریں؟"</string>
    -     <string name="enable_bluetooth_message" msgid="9106595990708985385">"اپنے کی بورڈ کو اپنے ٹیبلٹ کے ساتھ منسلک کرنے کیلئے پہلے آپ کو اپنا بلو ٹوتھ آن کرنا ہو گا۔"</string>
    -@@ -651,4 +651,5 @@
    -     <string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"<xliff:g id="ID_1">%s</xliff:g> ترتیبات کھولیں۔"</string>
    -     <string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"ترتیبات کی ترتیب میں ترمیم کریں۔"</string>
    -     <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"صفحہ <xliff:g id="ID_1">%1$d</xliff:g> از <xliff:g id="ID_2">%2$d</xliff:g>"</string>
    -+    <string name="cant_silence_or_block" msgid="999689262131488625">"اطلاعات کو خاموش یا مسدود نہیں کیا جا سکتا"</string>
    - </resources>
    -diff --git a/packages/SystemUI/res/values-uz-rUZ/strings.xml b/packages/SystemUI/res/values-uz-rUZ/strings.xml
    -index ac6194f..61195c5 100644
    ---- a/packages/SystemUI/res/values-uz-rUZ/strings.xml
    -+++ b/packages/SystemUI/res/values-uz-rUZ/strings.xml
    -@@ -240,7 +240,7 @@
    -     <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"4G internet to‘xtatib qo‘yildi"</string>
    -     <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"Mobil internetdan foydalanish to‘xtatib qo‘yildi"</string>
    -     <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"Internetdan foydalanish to‘xtatib qo‘yildi"</string>
    --    <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"Siz o‘rnatgan mobil internet chekloviga yetgani bois joriy hisob-kitob davrining qolgan muddati uchun mobil internetdan foydalanish vaqtinchalik to‘xtatib qo‘yildi.\n\nAgar internetdan foydalanishni davom ettirsangiz, buning uchun uyali aloqa operatoringiz ortiqcha haq talab qilishi mumkin."</string>
    -+    <string name="data_usage_disabled_dialog" msgid="1841738975235283398">"O‘rnatilgan trafik sarflab bo‘lindi. Endi mobil internetdan foydalana olmaysiz.\n\nDavom ettiradigan bo‘lsangiz, trafik uchun to‘lov olinishi mumkin."</string>
    -     <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"Davom etish"</string>
    -     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Internetga ulanmagan"</string>
    -     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi ulandi"</string>
    -@@ -406,6 +406,7 @@
    -     <string name="device_owned_footer" msgid="3802752663326030053">"Qurilma kuzatilishi mumkin"</string>
    -     <string name="profile_owned_footer" msgid="8021888108553696069">"Profil kuzatilishi mumkin"</string>
    -     <string name="vpn_footer" msgid="2388611096129106812">"Tarmoqni kuzatish mumkin"</string>
    -+    <string name="branded_vpn_footer" msgid="2168111859226496230">"Tarmoq kuzatilishi mumkin"</string>
    -     <string name="monitoring_title_device_owned" msgid="7121079311903859610">"Qurilmalarni kuzatish"</string>
    -     <string name="monitoring_title_profile_owned" msgid="6790109874733501487">"Profilni kuzatish"</string>
    -     <string name="monitoring_title" msgid="169206259253048106">"Tarmoqlarni kuzatish"</string>
    -@@ -418,6 +419,7 @@
    -     <string name="legacy_vpn_name" msgid="6604123105765737830">"VPN"</string>
    -     <string name="monitoring_description_app" msgid="6259179342284742878">"<xliff:g id="APPLICATION">%1$s</xliff:g> ilovasi ishga tushirilgan. U internetdagi harakatlaringiz, jumladan, e-pochta, ilova va veb-saytlardagi xatti-harakatlaringizni kuzatishi mumkin."</string>
    -     <string name="monitoring_description_app_personal" msgid="484599052118316268">"<xliff:g id="APPLICATION">%1$s</xliff:g> ilovasi ishga tushirilgan. U internetdagi harakatlaringiz, jumladan, e-pochta, ilova va veb-saytlardagi xatti-harakatlaringizni kuzatishi mumkin."</string>
    -+    <string name="branded_monitoring_description_app_personal" msgid="2669518213949202599">"<xliff:g id="APPLICATION">%1$s</xliff:g> ilovasi ishga tushirilgan. U internetdagi harakatlaringiz, jumladan, e-pochta, ilova va veb-saytlardagi xatti-harakatlaringizni kuzatishi mumkin."</string>
    -     <string name="monitoring_description_app_work" msgid="1754325860918060897">"Sizning ishchi profilingiz <xliff:g id="ORGANIZATION">%1$s</xliff:g> tomonidan boshqariladi. <xliff:g id="APPLICATION">%2$s</xliff:g> ilovasi ish tarmog‘idagi harakatlaringizni, jumladan, e-pochta, ilova va veb-saytlardagi xatti-harakatlaringizni kuzatishi mumkin.\n\nBatafsil ma’lumot olish uchun administrator bilan bog‘laning."</string>
    -     <string name="monitoring_description_app_personal_work" msgid="4946600443852045903">"Sizning ishchi profilingiz <xliff:g id="ORGANIZATION">%1$s</xliff:g> tomonidan boshqariladi. <xliff:g id="APPLICATION_WORK">%2$s</xliff:g> ilovasi ish tarmog‘idagi harakatlaringizni, jumladan, e-pochta, ilova va veb-saytlardagi xatti-harakatlaringizni kuzatishi mumkin.\n\nShuningdek, <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g> ilovasi ham shaxsiy tarmoqdagi harakatlaringizni kuzatishi mumkin."</string>
    -     <string name="monitoring_description_vpn_app_device_owned" msgid="4970443827043261703">"Qurilmangiz <xliff:g id="ORGANIZATION">%1$s</xliff:g> tomonidan boshqariladi.\n\nAdministrator sozlamalar, korporativ kirish huquqi, ilovalar, qurilmangizdagi ma’lumotlar, jumladan, joylashuv ma’lumotlarini boshqarishi mumkin.\n\nShuningdek, siz <xliff:g id="APPLICATION">%2$s</xliff:g> ilovasiga ham ulangansiz. Ushbu ilova internetdagi harakatlaringizni, jumladan, e-pochta, ilovalar va veb-saytlar bilan ishlashingizni kuzata oladi.\n\nBatafsil ma’lumot olish uchun administrator bilan bog‘laning."</string>
    -@@ -494,8 +496,6 @@
    -     <string name="clock_seconds_desc" msgid="6282693067130470675">"Holat panelida soat soniyalari ko‘rsatilsin. Bu batareya resursiga ta’sir qilishi mumkin."</string>
    -     <string name="qs_rearrange" msgid="8060918697551068765">"Tezkor sozlamalarni qayta tartiblash"</string>
    -     <string name="show_brightness" msgid="6613930842805942519">"Tezkor sozlamalarda yorqinlikni ko‘rsatish"</string>
    --    <string name="overview_nav_bar_gesture" msgid="8579814204727917764">"Tepaga surish orqali ekranni ikkiga bo‘lish"</string>
    --    <string name="overview_nav_bar_gesture_desc" msgid="6329167382305102615">"Umumiy ma’lumot tugmasini tepaga surish orqali ekranni bo‘lish ishorasini yoqish"</string>
    -     <string name="experimental" msgid="6198182315536726162">"Tajribaviy"</string>
    -     <string name="enable_bluetooth_title" msgid="5027037706500635269">"Bluetooth yoqilsinmi?"</string>
    -     <string name="enable_bluetooth_message" msgid="9106595990708985385">"Klaviaturani planshetingizga ulash uchun Bluetooth xizmatini yoqishingiz kerak."</string>
    -@@ -653,4 +653,5 @@
    -     <string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"<xliff:g id="ID_1">%s</xliff:g> sozlamalarini ochish."</string>
    -     <string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"Sozlamalar tartibini o‘zgartirish."</string>
    -     <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"<xliff:g id="ID_1">%1$d</xliff:g>-sahifa, jami: <xliff:g id="ID_2">%2$d</xliff:g> ta sahifa"</string>
    -+    <string name="cant_silence_or_block" msgid="999689262131488625">"Bildirishnomalarni bloklab yoki ovozsiz ko‘rinadigan qilib bo‘lmaydi"</string>
    - </resources>
    -diff --git a/packages/SystemUI/res/values-vi/strings.xml b/packages/SystemUI/res/values-vi/strings.xml
    -index 930eebe..6aaab66 100644
    ---- a/packages/SystemUI/res/values-vi/strings.xml
    -+++ b/packages/SystemUI/res/values-vi/strings.xml
    -@@ -238,7 +238,7 @@
    -     <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"Đã tạm dừng dữ liệu 4G"</string>
    -     <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"Đã tạm dừng dữ liệu di động"</string>
    -     <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"Đã tạm dừng dữ liệu"</string>
    --    <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"Vì bạn đã đạt tới giới hạn dữ liệu thiết lập nên thiết bị đã tạm dừng sử dụng dữ liệu cho phần còn lại của chu kỳ này.\n\nTiếp tục có thể dẫn tới nhà cung cấp dịch vụ của bạn sẽ tính phí."</string>
    -+    <string name="data_usage_disabled_dialog" msgid="1841738975235283398">"Đã đạt đến giới hạn dữ liệu mà bạn đặt. Bạn hiện không còn sử dụng dữ liệu di động.\n\nNếu tiếp tục, bạn có thể bị tính phí khi sử dụng dữ liệu."</string>
    -     <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"Tiếp tục"</string>
    -     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Ko có k.nối Internet"</string>
    -     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Đã kết nối Wi-Fi"</string>
    -@@ -404,6 +404,7 @@
    -     <string name="device_owned_footer" msgid="3802752663326030053">"Thiết bị có thể được giám sát"</string>
    -     <string name="profile_owned_footer" msgid="8021888108553696069">"Hồ sơ có thể được giám sát"</string>
    -     <string name="vpn_footer" msgid="2388611096129106812">"Mạng có thể được giám sát"</string>
    -+    <string name="branded_vpn_footer" msgid="2168111859226496230">"Mạng có thể được giám sát"</string>
    -     <string name="monitoring_title_device_owned" msgid="7121079311903859610">"Giám sát thiết bị"</string>
    -     <string name="monitoring_title_profile_owned" msgid="6790109874733501487">"Giám sát hồ sơ"</string>
    -     <string name="monitoring_title" msgid="169206259253048106">"Giám sát mạng"</string>
    -@@ -416,6 +417,7 @@
    -     <string name="legacy_vpn_name" msgid="6604123105765737830">"VPN"</string>
    -     <string name="monitoring_description_app" msgid="6259179342284742878">"Bạn đang kết nối với <xliff:g id="APPLICATION">%1$s</xliff:g>. Ứng dụng này có thể giám sát hoạt động mạng của bạn bao gồm email, ứng dụng và trang web."</string>
    -     <string name="monitoring_description_app_personal" msgid="484599052118316268">"Bạn đang kết nối với <xliff:g id="APPLICATION">%1$s</xliff:g>. Ứng dụng này có thể giám sát hoạt động mạng cá nhân của bạn bao gồm email, ứng dụng và trang web."</string>
    -+    <string name="branded_monitoring_description_app_personal" msgid="2669518213949202599">"Bạn đang kết nối với <xliff:g id="APPLICATION">%1$s</xliff:g>. Ứng dụng này có thể giám sát hoạt động mạng cá nhân của bạn bao gồm email, ứng dụng và trang web."</string>
    -     <string name="monitoring_description_app_work" msgid="1754325860918060897">"Hồ sơ công việc của bạn được quản lý bởi <xliff:g id="ORGANIZATION">%1$s</xliff:g>. Hồ sơ được kết nối với <xliff:g id="APPLICATION">%2$s</xliff:g>, ứng dụng này có thể giám sát hoạt động mạng cơ quan của bạn, bao gồm email, ứng dụng và trang web.\n\nĐể biết thêm thông tin, hãy liên hệ với quản trị viên của bạn."</string>
    -     <string name="monitoring_description_app_personal_work" msgid="4946600443852045903">"Hồ sơ công việc của bạn được quản lý bởi <xliff:g id="ORGANIZATION">%1$s</xliff:g>. Hồ sơ được kết nối với <xliff:g id="APPLICATION_WORK">%2$s</xliff:g>, ứng dụng này có thể giám sát hoạt động mạng cơ quan của bạn, bao gồm email, ứng dụng và trang web.\n\nBạn cũng được kết nối với <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g>, có thể giám sát hoạt động mạng cá nhân của bạn."</string>
    -     <string name="monitoring_description_vpn_app_device_owned" msgid="4970443827043261703">"Thiết bị của bạn được quản lý bởi <xliff:g id="ORGANIZATION">%1$s</xliff:g>.\n\nQuản trị viên có thể giám sát và quản lý cài đặt, quyền truy cập của công ty, ứng dụng, dữ liệu được liên kết với thiết bị của bạn và thông tin về vị trí của thiết bị.\n\nBạn được kết nối với <xliff:g id="APPLICATION">%2$s</xliff:g>. Ứng dụng này có thể giám sát hoạt động mạng của bạn, bao gồm email, ứng dụng và trang web.\n\nĐể biết thêm thông tin, hãy liên hệ với quản trị viên của bạn."</string>
    -@@ -494,8 +496,6 @@
    -     <string name="clock_seconds_desc" msgid="6282693067130470675">"Hiển thị giây đồng hồ trong thanh trạng thái. Có thể ảnh hưởng đến thời lượng pin."</string>
    -     <string name="qs_rearrange" msgid="8060918697551068765">"Sắp xếp lại Cài đặt nhanh"</string>
    -     <string name="show_brightness" msgid="6613930842805942519">"Hiển thị độ sáng trong Cài đặt nhanh"</string>
    --    <string name="overview_nav_bar_gesture" msgid="8579814204727917764">"Bật cử chỉ vuốt lên ở chế độ chia đôi màn hình"</string>
    --    <string name="overview_nav_bar_gesture_desc" msgid="6329167382305102615">"Cho phép cử chỉ truy cập chế độ chia đôi màn hình bằng cách vuốt lên từ nút Tổng quan"</string>
    -     <string name="experimental" msgid="6198182315536726162">"Thử nghiệm"</string>
    -     <string name="enable_bluetooth_title" msgid="5027037706500635269">"Bật Bluetooth?"</string>
    -     <string name="enable_bluetooth_message" msgid="9106595990708985385">"Để kết nối bàn phím với máy tính bảng, trước tiên, bạn phải bật Bluetooth."</string>
    -@@ -653,4 +653,5 @@
    -     <string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"Mở cài đặt <xliff:g id="ID_1">%s</xliff:g>."</string>
    -     <string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"Chỉnh sửa thứ tự cài đặt."</string>
    -     <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"Trang <xliff:g id="ID_1">%1$d</xliff:g> / <xliff:g id="ID_2">%2$d</xliff:g>"</string>
    -+    <string name="cant_silence_or_block" msgid="999689262131488625">"Không thể chặn hoặc tắt tiếng thông báo"</string>
    - </resources>
    -diff --git a/packages/SystemUI/res/values-zh-rCN/strings.xml b/packages/SystemUI/res/values-zh-rCN/strings.xml
    -index 2548c4b..f10d538 100644
    ---- a/packages/SystemUI/res/values-zh-rCN/strings.xml
    -+++ b/packages/SystemUI/res/values-zh-rCN/strings.xml
    -@@ -238,7 +238,7 @@
    -     <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"4G 数据网络已暂停使用"</string>
    -     <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"移动数据网络已暂停使用"</string>
    -     <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"数据网络已暂停使用"</string>
    --    <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"由于使用的数据流量已达到您所设置的上限,因此您的设备已暂停在此周期的剩余时间内使用数据流量。\n\n如果恢复数据流量使用,您的运营商可能会向您收取相应费用。"</string>
    -+    <string name="data_usage_disabled_dialog" msgid="1841738975235283398">"您的数据用量已达到设置的上限。您无法再使用移动数据网络。\n\n如果您继续操作,可能需要支付相应的数据流量费用。"</string>
    -     <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"恢复"</string>
    -     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"未连接互联网"</string>
    -     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"已连接到WLAN网络"</string>
    -@@ -404,6 +404,7 @@
    -     <string name="device_owned_footer" msgid="3802752663326030053">"设备可能会受到监控"</string>
    -     <string name="profile_owned_footer" msgid="8021888108553696069">"资料可能会受到监控"</string>
    -     <string name="vpn_footer" msgid="2388611096129106812">"网络可能会受到监控"</string>
    -+    <string name="branded_vpn_footer" msgid="2168111859226496230">"网络可能会受到监控"</string>
    -     <string name="monitoring_title_device_owned" msgid="7121079311903859610">"设备监测"</string>
    -     <string name="monitoring_title_profile_owned" msgid="6790109874733501487">"资料监控"</string>
    -     <string name="monitoring_title" msgid="169206259253048106">"网络监控"</string>
    -@@ -416,6 +417,7 @@
    -     <string name="legacy_vpn_name" msgid="6604123105765737830">"VPN"</string>
    -     <string name="monitoring_description_app" msgid="6259179342284742878">"您已连接到<xliff:g id="APPLICATION">%1$s</xliff:g>,该应用可以监控您的网络活动,包括收发电子邮件、使用应用和浏览网站。"</string>
    -     <string name="monitoring_description_app_personal" msgid="484599052118316268">"您已连接到<xliff:g id="APPLICATION">%1$s</xliff:g>,该应用可以监控您的个人网络活动,包括收发电子邮件、使用应用和浏览网站。"</string>
    -+    <string name="branded_monitoring_description_app_personal" msgid="2669518213949202599">"您已连接到<xliff:g id="APPLICATION">%1$s</xliff:g>,该应用可以监控您的个人网络活动,包括收发电子邮件、使用应用和浏览网站。"</string>
    -     <string name="monitoring_description_app_work" msgid="1754325860918060897">"您的工作资料由以下单位管理:<xliff:g id="ORGANIZATION">%1$s</xliff:g>。您已连接到<xliff:g id="APPLICATION">%2$s</xliff:g>,该应用可以监控您的工作网络活动,包括收发电子邮件、使用应用和浏览网站。\n\n若要了解详情,请与您单位的管理员联系。"</string>
    -     <string name="monitoring_description_app_personal_work" msgid="4946600443852045903">"您的工作资料由以下单位管理:<xliff:g id="ORGANIZATION">%1$s</xliff:g>。您已连接到<xliff:g id="APPLICATION_WORK">%2$s</xliff:g>,该应用可以监控您的工作网络活动,包括收发电子邮件、使用应用和浏览网站。\n\n此外,您还连接到了<xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g>,该应用可以监控您的个人网络活动。"</string>
    -     <string name="monitoring_description_vpn_app_device_owned" msgid="4970443827043261703">"您的设备由以下单位管理:<xliff:g id="ORGANIZATION">%1$s</xliff:g>。\n\n您单位的管理员可以监控和管理与此设备相关的设置、企业权限、应用、数据以及设备位置信息。\n\n您已连接到<xliff:g id="APPLICATION">%2$s</xliff:g>,该应用可以监控您的网络活动,包括收发电子邮件、使用应用和浏览网站。\n\n若要了解详情,请与您单位的管理员联系。"</string>
    -@@ -492,8 +494,6 @@
    -     <string name="clock_seconds_desc" msgid="6282693067130470675">"在状态栏中显示时钟的秒数。这可能会影响电池的续航时间。"</string>
    -     <string name="qs_rearrange" msgid="8060918697551068765">"重新排列快捷设置"</string>
    -     <string name="show_brightness" msgid="6613930842805942519">"在快捷设置中显示亮度栏"</string>
    --    <string name="overview_nav_bar_gesture" msgid="8579814204727917764">"启用分屏上滑手势"</string>
    --    <string name="overview_nav_bar_gesture_desc" msgid="6329167382305102615">"启用通过从“概览”按钮向上滑动的手势进入分屏模式"</string>
    -     <string name="experimental" msgid="6198182315536726162">"实验性功能"</string>
    -     <string name="enable_bluetooth_title" msgid="5027037706500635269">"要开启蓝牙吗?"</string>
    -     <string name="enable_bluetooth_message" msgid="9106595990708985385">"要将您的键盘连接到平板电脑,您必须先开启蓝牙。"</string>
    -@@ -651,4 +651,5 @@
    -     <string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"打开<xliff:g id="ID_1">%s</xliff:g>设置。"</string>
    -     <string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"修改设置顺序。"</string>
    -     <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"第 <xliff:g id="ID_1">%1$d</xliff:g> 页,共 <xliff:g id="ID_2">%2$d</xliff:g> 页"</string>
    -+    <string name="cant_silence_or_block" msgid="999689262131488625">"无法将通知静音或屏蔽"</string>
    - </resources>
    -diff --git a/packages/SystemUI/res/values-zh-rHK/strings.xml b/packages/SystemUI/res/values-zh-rHK/strings.xml
    -index c0172b1..8405fe5 100644
    ---- a/packages/SystemUI/res/values-zh-rHK/strings.xml
    -+++ b/packages/SystemUI/res/values-zh-rHK/strings.xml
    -@@ -240,7 +240,7 @@
    -     <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"已暫停 4G 數據"</string>
    -     <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"已暫停流動數據"</string>
    -     <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"已暫停使用數據"</string>
    --    <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"由於您已達到設定的數據用量上限,裝置已暫停使用數據,直到週期結束。\n\n如恢復使用數據,流動網絡供應商可能會向您收取費用。"</string>
    -+    <string name="data_usage_disabled_dialog" msgid="1841738975235283398">"已達到您設定的數據上限。系統將停止使用流動數據網絡。\n\n如果您恢復使用流動數據網絡,可能需要支付數據費用。"</string>
    -     <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"恢復"</string>
    -     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"沒有互聯網連線"</string>
    -     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi 已連線"</string>
    -@@ -406,6 +406,7 @@
    -     <string name="device_owned_footer" msgid="3802752663326030053">"裝置可能會受到監控"</string>
    -     <string name="profile_owned_footer" msgid="8021888108553696069">"個人檔案可能受到監控"</string>
    -     <string name="vpn_footer" msgid="2388611096129106812">"網絡可能會受到監控"</string>
    -+    <string name="branded_vpn_footer" msgid="2168111859226496230">"網絡可能會受到監控"</string>
    -     <string name="monitoring_title_device_owned" msgid="7121079311903859610">"裝置監控"</string>
    -     <string name="monitoring_title_profile_owned" msgid="6790109874733501487">"個人檔案監控"</string>
    -     <string name="monitoring_title" msgid="169206259253048106">"網絡監控"</string>
    -@@ -418,6 +419,7 @@
    -     <string name="legacy_vpn_name" msgid="6604123105765737830">"VPN"</string>
    -     <string name="monitoring_description_app" msgid="6259179342284742878">"您已連結至<xliff:g id="APPLICATION">%1$s</xliff:g> ,它能夠監控您的網絡活動,包括電郵、應用程式和網站。"</string>
    -     <string name="monitoring_description_app_personal" msgid="484599052118316268">"您已連結至<xliff:g id="APPLICATION">%1$s</xliff:g>,它能夠監控您的個人網絡活動,包括電郵、應用程式和網站。"</string>
    -+    <string name="branded_monitoring_description_app_personal" msgid="2669518213949202599">"您已連接至「<xliff:g id="APPLICATION">%1$s</xliff:g>」,此應用程式可以監控您的個人網絡活動,包括電郵、應用程式及網站。"</string>
    -     <string name="monitoring_description_app_work" msgid="1754325860918060897">"您的工作設定檔由<xliff:g id="ORGANIZATION">%1$s</xliff:g>管理。它已連結至<xliff:g id="APPLICATION">%2$s</xliff:g>,能夠監控您的工作網絡活動,包括電郵、應用程式和網站。\n\n如需進一步資訊,請聯絡您的管理員。"</string>
    -     <string name="monitoring_description_app_personal_work" msgid="4946600443852045903">"您的工作設定檔由<xliff:g id="ORGANIZATION">%1$s</xliff:g>管理。它已連結至<xliff:g id="APPLICATION_WORK">%2$s</xliff:g>,能夠監控您的工作網絡活動,包括電郵、應用程式和網站。\n\n此外,您亦連結至<xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g>,因此它亦能夠監控您的個人網絡活動。"</string>
    -     <string name="monitoring_description_vpn_app_device_owned" msgid="4970443827043261703">"您的裝置由 <xliff:g id="ORGANIZATION">%1$s</xliff:g> 管理。\n\n您的管理員可以監控及管理您裝置的設定、企業存取、應用程式、資料及位置資訊。\n\n此外,您的裝置連至 <xliff:g id="APPLICATION">%2$s</xliff:g>,它能監控您的網絡活動,包括電郵、應用程式及網站。\n\n如需更多資訊,請聯絡您的管理員。"</string>
    -@@ -494,8 +496,6 @@
    -     <string name="clock_seconds_desc" msgid="6282693067130470675">"在狀態列中顯示時鐘秒數,但可能會影響電池壽命。"</string>
    -     <string name="qs_rearrange" msgid="8060918697551068765">"重新排列快速設定"</string>
    -     <string name="show_brightness" msgid="6613930842805942519">"在快速設定顯示亮度"</string>
    --    <string name="overview_nav_bar_gesture" msgid="8579814204727917764">"啟用分割畫面向上快速滑動手勢"</string>
    --    <string name="overview_nav_bar_gesture_desc" msgid="6329167382305102615">"從 [概覽] 按鈕向上快速滑動,即可使用手勢功能進入分割畫面模式"</string>
    -     <string name="experimental" msgid="6198182315536726162">"實驗版"</string>
    -     <string name="enable_bluetooth_title" msgid="5027037706500635269">"要開啟藍牙嗎?"</string>
    -     <string name="enable_bluetooth_message" msgid="9106595990708985385">"如要將鍵盤連接至平板電腦,請先開啟藍牙。"</string>
    -@@ -653,4 +653,5 @@
    -     <string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"開啟<xliff:g id="ID_1">%s</xliff:g>設定頁面。"</string>
    -     <string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"編輯設定次序。"</string>
    -     <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"第 <xliff:g id="ID_1">%1$d</xliff:g> 頁 (共 <xliff:g id="ID_2">%2$d</xliff:g> 頁)"</string>
    -+    <string name="cant_silence_or_block" msgid="999689262131488625">"通知無法設為靜音或封鎖"</string>
    - </resources>
    -diff --git a/packages/SystemUI/res/values-zh-rTW/strings.xml b/packages/SystemUI/res/values-zh-rTW/strings.xml
    -index 66c1264..b4f2b27 100644
    ---- a/packages/SystemUI/res/values-zh-rTW/strings.xml
    -+++ b/packages/SystemUI/res/values-zh-rTW/strings.xml
    -@@ -238,7 +238,7 @@
    -     <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"已暫停 4G 數據連線"</string>
    -     <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"已暫停行動數據連線"</string>
    -     <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"已暫停數據連線"</string>
    --    <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"由於數據用量已達設定上限,裝置在這個週期的剩餘時間將暫停使用數據連線。\n\n如果恢復使用,行動通訊業者可能會向您收取額外的連線費用。"</string>
    -+    <string name="data_usage_disabled_dialog" msgid="1841738975235283398">"你的數據用量已達設定的用量上限,因此系統已停止使用行動數據連線。\n\n如果你繼續使用行動數據連線,可能需要支付相關的數據傳輸費用。"</string>
    -     <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"恢復連線"</string>
    -     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"沒有網際網路連線"</string>
    -     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi 已連線"</string>
    -@@ -404,6 +404,7 @@
    -     <string name="device_owned_footer" msgid="3802752663326030053">"裝置可能會受到監控"</string>
    -     <string name="profile_owned_footer" msgid="8021888108553696069">"設定檔可能會受到監控"</string>
    -     <string name="vpn_footer" msgid="2388611096129106812">"網路可能會受到監控"</string>
    -+    <string name="branded_vpn_footer" msgid="2168111859226496230">"網路可能會受到監控"</string>
    -     <string name="monitoring_title_device_owned" msgid="7121079311903859610">"裝置監控"</string>
    -     <string name="monitoring_title_profile_owned" msgid="6790109874733501487">"設定檔監控"</string>
    -     <string name="monitoring_title" msgid="169206259253048106">"網路監控"</string>
    -@@ -416,6 +417,7 @@
    -     <string name="legacy_vpn_name" msgid="6604123105765737830">"VPN"</string>
    -     <string name="monitoring_description_app" msgid="6259179342284742878">"由於您已連線至 <xliff:g id="APPLICATION">%1$s</xliff:g>,您的網路活動也會受到這個應用程式監控,包括收發電子郵件、使用應用程式和瀏覽網站。"</string>
    -     <string name="monitoring_description_app_personal" msgid="484599052118316268">"由於您已連線至 <xliff:g id="APPLICATION">%1$s</xliff:g>,您的個人網路活動也會受到這個應用程式監控,包括收發電子郵件、使用應用程式和瀏覽網站。"</string>
    -+    <string name="branded_monitoring_description_app_personal" msgid="2669518213949202599">"由於你已連結至「<xliff:g id="APPLICATION">%1$s</xliff:g>」,你的個人網路活動 (包括收發電子郵件、使用應用程式及瀏覽網站) 可能會受到這個應用程式監控。"</string>
    -     <string name="monitoring_description_app_work" msgid="1754325860918060897">"您的 Work 設定檔是由下列機構管理:<xliff:g id="ORGANIZATION">%1$s</xliff:g>。由於設定檔已連線至 <xliff:g id="APPLICATION">%2$s</xliff:g>,您的工作網路活動也會受到這個應用程式監控,包括收發電子郵件、使用應用程式和瀏覽網站。\n\n詳情請洽您的管理員。"</string>
    -     <string name="monitoring_description_app_personal_work" msgid="4946600443852045903">"您的 Work 設定檔是由下列機構管理:<xliff:g id="ORGANIZATION">%1$s</xliff:g>。由於設定檔已連線至 <xliff:g id="APPLICATION_WORK">%2$s</xliff:g>,您的工作網路活動也會受到這個應用程式監控,包括收發電子郵件、使用應用程式和瀏覽網站。\n\n同時由於您也連線至<xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g>,您的個人網路活動也會受到這個應用程式監控。"</string>
    -     <string name="monitoring_description_vpn_app_device_owned" msgid="4970443827043261703">"您的裝置由下列機構管理:<xliff:g id="ORGANIZATION">%1$s</xliff:g>。\n\n您的管理員可以監控及管理與裝置相關的設定、企業網路存取權、應用程式和資料,以及裝置的位置資訊。\n\n由於您的裝置已連線至 <xliff:g id="APPLICATION">%2$s</xliff:g>,您的網路活動也會受到這個應用程式監控,包括收發電子郵件、使用應用程式和瀏覽網站。\n\n如需詳細資訊,請洽您的管理員。"</string>
    -@@ -492,8 +494,6 @@
    -     <string name="clock_seconds_desc" msgid="6282693067130470675">"在狀態列中顯示時鐘秒數。這可能會影響電池續航力。"</string>
    -     <string name="qs_rearrange" msgid="8060918697551068765">"重新排列快速設定"</string>
    -     <string name="show_brightness" msgid="6613930842805942519">"在快速設定中顯示亮度"</string>
    --    <string name="overview_nav_bar_gesture" msgid="8579814204727917764">"啟用分割畫面向上滑動手勢"</string>
    --    <string name="overview_nav_bar_gesture_desc" msgid="6329167382305102615">"啟用透過從 [總覽] 按鈕向上滑動的手勢進入分割畫面"</string>
    -     <string name="experimental" msgid="6198182315536726162">"實驗性"</string>
    -     <string name="enable_bluetooth_title" msgid="5027037706500635269">"要開啟藍牙功能嗎?"</string>
    -     <string name="enable_bluetooth_message" msgid="9106595990708985385">"如要將鍵盤連線到平板電腦,您必須先開啟藍牙。"</string>
    -@@ -651,4 +651,5 @@
    -     <string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"開啟「<xliff:g id="ID_1">%s</xliff:g>」設定。"</string>
    -     <string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"編輯設定順序。"</string>
    -     <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"第 <xliff:g id="ID_1">%1$d</xliff:g> 頁,共 <xliff:g id="ID_2">%2$d</xliff:g> 頁"</string>
    -+    <string name="cant_silence_or_block" msgid="999689262131488625">"無法關閉通知音效或封鎖通知"</string>
    - </resources>
    -diff --git a/packages/SystemUI/res/values-zu/strings.xml b/packages/SystemUI/res/values-zu/strings.xml
    -index 49bf0bd..c6e4044 100644
    ---- a/packages/SystemUI/res/values-zu/strings.xml
    -+++ b/packages/SystemUI/res/values-zu/strings.xml
    -@@ -238,7 +238,7 @@
    -     <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"4G idatha imisiwe"</string>
    -     <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"Idatha yeselula imisiwe"</string>
    -     <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"Idatha imisiwe"</string>
    --    <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"Ngoba umkhawulo wakho wedatha osethiwe ufinyelelwe, idivayisi imise kancane ukusetshenziswa kwedatha ngesikhumbuzi salo mjikelezo.\n\nUkuqhuba futhi kungaholela kuzindleko kusuka kwinkampani yakho yenethiwekhi."</string>
    -+    <string name="data_usage_disabled_dialog" msgid="1841738975235283398">"Umkhawulo wedatha owusethayo ufikiwe. Awusasebenzisi idatha yeselula.\n\nUma uqalisa kabusha, izindleko zingasebenza ekusetshenzisweni kwedatha."</string>
    -     <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"Qalisa kabusha"</string>
    -     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Alukho uxhumano lwe-Inthanethi"</string>
    -     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"I-Wi-Fi ixhunyiwe"</string>
    -@@ -404,6 +404,7 @@
    -     <string name="device_owned_footer" msgid="3802752663326030053">"Idivayisi inganganyelwa"</string>
    -     <string name="profile_owned_footer" msgid="8021888108553696069">"Iphrofayela ingaqashwa"</string>
    -     <string name="vpn_footer" msgid="2388611096129106812">"Inethiwekhi kungenzeka iqashiwe"</string>
    -+    <string name="branded_vpn_footer" msgid="2168111859226496230">"Inethiwekhi kungenzeka iqashiwe"</string>
    -     <string name="monitoring_title_device_owned" msgid="7121079311903859610">"Ukwengamela idivayisi"</string>
    -     <string name="monitoring_title_profile_owned" msgid="6790109874733501487">"Ukuqapha iphrofayela"</string>
    -     <string name="monitoring_title" msgid="169206259253048106">"Ukuqashwa kwenethiwekhi"</string>
    -@@ -416,6 +417,7 @@
    -     <string name="legacy_vpn_name" msgid="6604123105765737830">"I-VPN"</string>
    -     <string name="monitoring_description_app" msgid="6259179342284742878">"Uxhumeke ku-<xliff:g id="APPLICATION">%1$s</xliff:g>, engahlola umsebenzi wakho wenethiwekhi ofaka ama-imeyili, izinhlelo zokusebenza, namawebhusayithi."</string>
    -     <string name="monitoring_description_app_personal" msgid="484599052118316268">"Uxhumeke ku-<xliff:g id="APPLICATION">%1$s</xliff:g>, engahlola umsebenzi wenethiwekhi yakho yomuntu siqu, ofaka ama-imeyili, izinhlelo zokusebenza, namawebhusayithi."</string>
    -+    <string name="branded_monitoring_description_app_personal" msgid="2669518213949202599">"Uxhumeke ku-<xliff:g id="APPLICATION">%1$s</xliff:g>, engaqapha umsebenzi wakho womuntu siqu wenethiwekhi, ofaka ama-imeyili, izinhlelo zokusebenza, namawebhusayithi."</string>
    -     <string name="monitoring_description_app_work" msgid="1754325860918060897">"Iphrofayela yakho yomsebenzi iphethwe yi-<xliff:g id="ORGANIZATION">%1$s</xliff:g>. Ixhumeke ku-<xliff:g id="APPLICATION">%2$s</xliff:g>, engahlola umsebenzi wenethiwekhi yakho yokusebenza, ofaka ama-imeyili, izinhlelo zokusebenza, namawebhusayithi.\n\nUkuze uthole olunye ulwazi, xhumana nomqondisi wakho."</string>
    -     <string name="monitoring_description_app_personal_work" msgid="4946600443852045903">"Iphrofayela yakho yomsebenzi iphethwe yi-<xliff:g id="ORGANIZATION">%1$s</xliff:g>. Ixhumeke ku-<xliff:g id="APPLICATION_WORK">%2$s</xliff:g>, engahlola umsebenzi wenethiwekhi yakho yomsebenzi, ofaka ama-imeyili, izinhlelo zokusebenza namawebhusayithi.\n\nFuthi uxhumeke ku-<xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g>, engahlola umsebenzi wenethiwekhi yakho yomuntu siqu."</string>
    -     <string name="monitoring_description_vpn_app_device_owned" msgid="4970443827043261703">"Idivayisi yakho iphethwe yi-<xliff:g id="ORGANIZATION">%1$s</xliff:g>.\n\nUmqondisi wakho angaqaphela aphinde aphathe izilungiselelo, ukufinyelela kwezinkampani, izinhlelo zokusebenza, idatha ehlotshaniswa nedivayisi yakho, nolwazi lendawo yedivayisi yakho.\n\nUxhumeke ku-<xliff:g id="APPLICATION">%2$s</xliff:g>, engaqaphela umsebenzi wakho wenethiwekhi, ofaka ama-imeyili, izinhlelo zokusebenza namawebhusayithi.\n\nUkuze uthole olunye ulwazi, xhumana nomqondisi wakho."</string>
    -@@ -492,8 +494,6 @@
    -     <string name="clock_seconds_desc" msgid="6282693067130470675">"Bonisa amasekhondi wewashi kubha yesimo. Ingathinta impilo yebhethri."</string>
    -     <string name="qs_rearrange" msgid="8060918697551068765">"Hlela kabusha izilungiselelo ezisheshayo"</string>
    -     <string name="show_brightness" msgid="6613930842805942519">"Bonisa ukukhanya kuzilungiselelo ezisheshayo"</string>
    --    <string name="overview_nav_bar_gesture" msgid="8579814204727917764">"Nika amandla ukuthinta kokuswayiphela phezulu ukuhlukanisa isikrini"</string>
    --    <string name="overview_nav_bar_gesture_desc" msgid="6329167382305102615">"Nika amandla ukuthinta ukuze ungene ekuhlukaniseni isikrini ngokuswayiphela phezulu kusukela kunkinobho yokubuka konke"</string>
    -     <string name="experimental" msgid="6198182315536726162">"Okokulinga"</string>
    -     <string name="enable_bluetooth_title" msgid="5027037706500635269">"Vula i-Bluetooth?"</string>
    -     <string name="enable_bluetooth_message" msgid="9106595990708985385">"Ukuze uxhume ikhibhodi yakho nethebhulethi yakho, kufanele uqale ngokuvula i-Bluetooth."</string>
    -@@ -651,4 +651,5 @@
    -     <string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"Vula izilungiselelo ze-<xliff:g id="ID_1">%s</xliff:g>."</string>
    -     <string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"Hlela uhlelo lwezilungiselelo."</string>
    -     <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"Ikhasi <xliff:g id="ID_1">%1$d</xliff:g> kwangu-<xliff:g id="ID_2">%2$d</xliff:g>"</string>
    -+    <string name="cant_silence_or_block" msgid="999689262131488625">"Izaziso azikwazi ukuthuliswa noma ukuvinjelwa"</string>
    - </resources>
    -diff --git a/packages/SystemUI/res/values/config.xml b/packages/SystemUI/res/values/config.xml
    -index 8d44048..9eea375 100644
    ---- a/packages/SystemUI/res/values/config.xml
    -+++ b/packages/SystemUI/res/values/config.xml
    -@@ -100,7 +100,7 @@
    - 
    -     <!-- The default tiles to display in QuickSettings -->
    -     <string name="quick_settings_tiles_default" translatable="false">
    --        wifi,cell,battery,dnd,flashlight,rotation,bt,airplane,location
    -+        wifi,cell,battery,dnd,flashlight,rotation,bt,airplane
    -     </string>
    - 
    -     <!-- Tiles native to System UI. Order should match "quick_settings_tiles_default" -->
    -@@ -209,9 +209,6 @@
    -     <!-- Doze: should the significant motion sensor be used as a pulse signal? -->
    -     <bool name="doze_pulse_on_significant_motion">false</bool>
    - 
    --    <!-- Doze: should the pickup sensor be used as a pulse signal? -->
    --    <bool name="doze_pulse_on_pick_up">false</bool>
    --
    -     <!-- Doze: check proximity sensor before pulsing? -->
    -     <bool name="doze_proximity_check_before_pulse">true</bool>
    - 
    -diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
    -index 6c48b25..2ea475a 100644
    ---- a/packages/SystemUI/res/values/strings.xml
    -+++ b/packages/SystemUI/res/values/strings.xml
    -@@ -569,7 +569,7 @@
    -     <!-- Title of dialog shown when data usage has exceeded limit and has been disabled. [CHAR LIMIT=48] -->
    -     <string name="data_usage_disabled_dialog_title">Data is paused</string>
    -     <!-- Body of dialog shown when data usage has exceeded limit and has been disabled. [CHAR LIMIT=NONE] -->
    --    <string name="data_usage_disabled_dialog">Because your set data limit was reached, the device has paused data usage for the remainder of this cycle.\n\nResuming may lead to charges from your carrier.</string>
    -+    <string name="data_usage_disabled_dialog">The data limit you set has been reached. You are no longer using cellular data.\n\nIf you resume, charges may apply for data usage.</string>
    -     <!-- Dialog button indicating that data connection should be re-enabled. [CHAR LIMIT=28] -->
    -     <string name="data_usage_disabled_dialog_enable">Resume</string>
    - 
    -@@ -1001,6 +1001,9 @@
    -     <!-- Footer vpn present text [CHAR LIMIT=50] -->
    -     <string name="vpn_footer">Network may be monitored</string>
    - 
    -+    <!-- Footer vpn present text [CHAR LIMIT=50] -->
    -+    <string name="branded_vpn_footer">Network may be monitored</string>
    -+
    -     <!-- Monitoring dialog title for device owned devices [CHAR LIMIT=35] -->
    -     <string name="monitoring_title_device_owned">Device monitoring</string>
    - 
    -@@ -1037,6 +1040,9 @@
    -     <!-- Monitoring dialog text for single app (inside personal profile) [CHAR LIMIT=400] -->
    -     <string name="monitoring_description_app_personal">You\'re connected to <xliff:g id="application">%1$s</xliff:g>, which can monitor your personal network activity, including emails, apps, and websites.</string>
    - 
    -+    <!-- Monitoring dialog text for single app (inside personal profile) [CHAR LIMIT=400] -->
    -+    <string name="branded_monitoring_description_app_personal">You\'re connected to <xliff:g id="application">%1$s</xliff:g>, which can monitor your personal network activity, including emails, apps, and websites.</string>
    -+
    -     <!-- Monitoring dialog text for single app (inside work profile) [CHAR LIMIT=400] -->
    -     <string name="monitoring_description_app_work">Your work profile is managed by <xliff:g id="organization">%1$s</xliff:g>. It is connected to <xliff:g id="application">%2$s</xliff:g>, which can monitor your work network activity, including emails, apps, and websites.\n\nFor more information, contact your administrator.</string>
    - 
    -@@ -1243,11 +1249,6 @@
    -     <!-- Option to use new paging layout in quick settings [CHAR LIMIT=60] -->
    -     <string name="qs_paging" translatable="false">Use the new Quick Settings</string>
    - 
    --    <!-- Toggle to enable the gesture to enter split-screen by swiping up from the Overview button. [CHAR LIMIT=60]-->
    --    <string name="overview_nav_bar_gesture">Enable split-screen swipe-up gesture</string>
    --    <!-- Description for the toggle to enable the gesture to enter split-screen by swiping up from the Overview button. [CHAR LIMIT=NONE]-->
    --    <string name="overview_nav_bar_gesture_desc">Enable gesture to enter split-screen by swiping up from the Overview button</string>
    --
    -     <!-- Category in the System UI Tuner settings, where new/experimental
    -          settings are -->
    -     <string name="experimental">Experimental</string>
    -@@ -1665,7 +1666,10 @@
    -     <!-- accessibility label for button to edit quick settings [CHAR LIMIT=NONE] -->
    -     <string name="accessibility_quick_settings_edit">Edit order of settings.</string>
    - 
    --    <!-- accessibility label for paging indicator in quick settings [CHAR LIMITi=NONE] -->
    -+    <!-- accessibility label for paging indicator in quick settings [CHAR LIMIT=NONE] -->
    -     <string name="accessibility_quick_settings_page">Page <xliff:g name="current_page" example="1">%1$d</xliff:g> of <xliff:g name="num_pages" example="2">%2$d</xliff:g></string>
    - 
    -+    <!-- Label that replaces other notification controls when the notification is from the system
    -+         and cannot be silenced (see @string/show_silently) or blocked (see @string/block) -->
    -+    <string name="cant_silence_or_block">Notifications can\'t be silenced or blocked</string>
    - </resources>
    -diff --git a/packages/SystemUI/res/values/styles.xml b/packages/SystemUI/res/values/styles.xml
    -index 1ee13e9..c659acf 100644
    ---- a/packages/SystemUI/res/values/styles.xml
    -+++ b/packages/SystemUI/res/values/styles.xml
    -@@ -42,7 +42,7 @@
    -     </style>
    - 
    -     <!-- Theme used for the activity that shows when the system forced an app to be resizable -->
    --    <style name="ForcedResizableTheme" parent="@android:style/Theme.Translucent.NoTitleBar.Fullscreen">
    -+    <style name="ForcedResizableTheme" parent="@android:style/Theme.Translucent.NoTitleBar">
    -         <item name="android:windowBackground">@drawable/forced_resizable_background</item>
    -         <item name="android:statusBarColor">@color/transparent</item>
    -         <item name="android:windowAnimationStyle">@style/Animation.ForcedResizable</item>
    -@@ -217,7 +217,7 @@
    -     <style name="Animation.StatusBar">
    -     </style>
    - 
    --    <style name="systemui_theme" parent="@android:style/Theme.DeviceDefault" />
    -+    <style name="systemui_theme" parent="@*android:style/Theme.DeviceDefault.Settings.Dark" />
    - 
    -     <style name="systemui_theme_remote_input" parent="@android:style/Theme.DeviceDefault.Light">
    -         <item name="android:colorAccent">@color/remote_input_accent</item>
    -diff --git a/packages/SystemUI/res/xml/other_settings.xml b/packages/SystemUI/res/xml/other_settings.xml
    -index 3c872fa..ce636cd 100644
    ---- a/packages/SystemUI/res/xml/other_settings.xml
    -+++ b/packages/SystemUI/res/xml/other_settings.xml
    -@@ -18,11 +18,6 @@
    -                   xmlns:sysui="http://schemas.android.com/apk/res-auto"
    -                   android:title="@string/other">
    - 
    --    <com.android.systemui.tuner.TunerSwitch
    --            android:key="overview_nav_bar_gesture"
    --            android:title="@string/overview_nav_bar_gesture"
    --            android:summary="@string/overview_nav_bar_gesture_desc" />
    --
    -     <!-- importance -->
    -     <Preference
    -             android:key="power_notification_controls"
    -diff --git a/packages/SystemUI/src/com/android/systemui/BootReceiver.java b/packages/SystemUI/src/com/android/systemui/BootReceiver.java
    -deleted file mode 100644
    -index 8e24eeb..0000000
    ---- a/packages/SystemUI/src/com/android/systemui/BootReceiver.java
    -+++ /dev/null
    -@@ -1,46 +0,0 @@
    --/*
    -- * Copyright (C) 2011 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 com.android.systemui;
    --
    --import android.content.BroadcastReceiver;
    --import android.content.ContentResolver;
    --import android.content.Context;
    --import android.content.Intent;
    --import android.provider.Settings;
    --import android.util.Log;
    --
    --/**
    -- * Performs a number of miscellaneous, non-system-critical actions
    -- * after the system has finished booting.
    -- */
    --public class BootReceiver extends BroadcastReceiver {
    --    private static final String TAG = "SystemUIBootReceiver";
    --
    --    @Override
    --    public void onReceive(final Context context, Intent intent) {
    --        try {
    --            // Start the load average overlay, if activated
    --            ContentResolver res = context.getContentResolver();
    --            if (Settings.Global.getInt(res, Settings.Global.SHOW_PROCESSES, 0) != 0) {
    --                Intent loadavg = new Intent(context, com.android.systemui.LoadAverageService.class);
    --                context.startService(loadavg);
    --            }
    --        } catch (Exception e) {
    --            Log.e(TAG, "Can't start load average service", e);
    --        }
    --    }
    --}
    -diff --git a/packages/SystemUI/src/com/android/systemui/LoadAverageService.java b/packages/SystemUI/src/com/android/systemui/LoadAverageService.java
    -deleted file mode 100644
    -index 59ffe03..0000000
    ---- a/packages/SystemUI/src/com/android/systemui/LoadAverageService.java
    -+++ /dev/null
    -@@ -1,315 +0,0 @@
    --/*
    -- * Copyright (C) 2007 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 com.android.systemui;
    --
    --import android.app.Service;
    --import android.content.Context;
    --import android.content.Intent;
    --import android.graphics.Canvas;
    --import android.graphics.Paint;
    --import android.graphics.PixelFormat;
    --import android.os.Handler;
    --import android.os.IBinder;
    --import android.os.Message;
    --import android.view.Gravity;
    --import android.view.View;
    --import android.view.WindowManager;
    --
    --import com.android.internal.os.ProcessCpuTracker;
    --
    --public class LoadAverageService extends Service {
    --    private View mView;
    --
    --    private static final class CpuTracker extends ProcessCpuTracker {
    --        String mLoadText;
    --        int mLoadWidth;
    --
    --        private final Paint mPaint;
    --
    --        CpuTracker(Paint paint) {
    --            super(false);
    --            mPaint = paint;
    --        }
    --
    --        @Override
    --        public void onLoadChanged(float load1, float load5, float load15) {
    --            mLoadText = load1 + " / " + load5 + " / " + load15;
    --            mLoadWidth = (int)mPaint.measureText(mLoadText);
    --        }
    --
    --        @Override
    --        public int onMeasureProcessName(String name) {
    --            return (int)mPaint.measureText(name);
    --        }
    --    }
    --
    --    private class LoadView extends View {
    --        private Handler mHandler = new Handler() {
    --            @Override
    --            public void handleMessage(Message msg) {
    --                if (msg.what == 1) {
    --                    mStats.update();
    --                    updateDisplay();
    --                    Message m = obtainMessage(1);
    --                    sendMessageDelayed(m, 2000);
    --                }
    --            }
    --        };
    --
    --        private final CpuTracker mStats;
    --
    --        private Paint mLoadPaint;
    --        private Paint mAddedPaint;
    --        private Paint mRemovedPaint;
    --        private Paint mShadowPaint;
    --        private Paint mShadow2Paint;
    --        private Paint mIrqPaint;
    --        private Paint mSystemPaint;
    --        private Paint mUserPaint;
    --        private float mAscent;
    --        private int mFH;
    --
    --        private int mNeededWidth;
    --        private int mNeededHeight;
    --
    --        LoadView(Context c) {
    --            super(c);
    --
    --            setPadding(4, 4, 4, 4);
    --            //setBackgroundResource(com.android.internal.R.drawable.load_average_background);
    --
    --            // Need to scale text size by density...  but we won't do it
    --            // linearly, because with higher dps it is nice to squeeze the
    --            // text a bit to fit more of it.  And with lower dps, trying to
    --            // go much smaller will result in unreadable text.
    --            int textSize = 10;
    --            float density = c.getResources().getDisplayMetrics().density;
    --            if (density < 1) {
    --                textSize = 9;
    --            } else {
    --                textSize = (int)(10*density);
    --                if (textSize < 10) {
    --                    textSize = 10;
    --                }
    --            }
    --            mLoadPaint = new Paint();
    --            mLoadPaint.setAntiAlias(true);
    --            mLoadPaint.setTextSize(textSize);
    --            mLoadPaint.setARGB(255, 255, 255, 255);
    --
    --            mAddedPaint = new Paint();
    --            mAddedPaint.setAntiAlias(true);
    --            mAddedPaint.setTextSize(textSize);
    --            mAddedPaint.setARGB(255, 128, 255, 128);
    --
    --            mRemovedPaint = new Paint();
    --            mRemovedPaint.setAntiAlias(true);
    --            mRemovedPaint.setStrikeThruText(true);
    --            mRemovedPaint.setTextSize(textSize);
    --            mRemovedPaint.setARGB(255, 255, 128, 128);
    --
    --            mShadowPaint = new Paint();
    --            mShadowPaint.setAntiAlias(true);
    --            mShadowPaint.setTextSize(textSize);
    --            //mShadowPaint.setFakeBoldText(true);
    --            mShadowPaint.setARGB(192, 0, 0, 0);
    --            mLoadPaint.setShadowLayer(4, 0, 0, 0xff000000);
    --
    --            mShadow2Paint = new Paint();
    --            mShadow2Paint.setAntiAlias(true);
    --            mShadow2Paint.setTextSize(textSize);
    --            //mShadow2Paint.setFakeBoldText(true);
    --            mShadow2Paint.setARGB(192, 0, 0, 0);
    --            mLoadPaint.setShadowLayer(2, 0, 0, 0xff000000);
    --
    --            mIrqPaint = new Paint();
    --            mIrqPaint.setARGB(0x80, 0, 0, 0xff);
    --            mIrqPaint.setShadowLayer(2, 0, 0, 0xff000000);
    --            mSystemPaint = new Paint();
    --            mSystemPaint.setARGB(0x80, 0xff, 0, 0);
    --            mSystemPaint.setShadowLayer(2, 0, 0, 0xff000000);
    --            mUserPaint = new Paint();
    --            mUserPaint.setARGB(0x80, 0, 0xff, 0);
    --            mSystemPaint.setShadowLayer(2, 0, 0, 0xff000000);
    --
    --            mAscent = mLoadPaint.ascent();
    --            float descent = mLoadPaint.descent();
    --            mFH = (int)(descent - mAscent + .5f);
    --
    --            mStats = new CpuTracker(mLoadPaint);
    --            mStats.init();
    --            updateDisplay();
    --        }
    --
    --        @Override
    --        protected void onAttachedToWindow() {
    --            super.onAttachedToWindow();
    --            mHandler.sendEmptyMessage(1);
    --        }
    --
    --        @Override
    --        protected void onDetachedFromWindow() {
    --            super.onDetachedFromWindow();
    --            mHandler.removeMessages(1);
    --        }
    --
    --        @Override
    --        protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
    --            setMeasuredDimension(resolveSize(mNeededWidth, widthMeasureSpec),
    --                    resolveSize(mNeededHeight, heightMeasureSpec));
    --        }
    --
    --        @Override
    --        public void onDraw(Canvas canvas) {
    --            super.onDraw(canvas);
    --            final int W = mNeededWidth;
    --            final int RIGHT = getWidth()-1;
    --
    --            final CpuTracker stats = mStats;
    --            final int userTime = stats.getLastUserTime();
    --            final int systemTime = stats.getLastSystemTime();
    --            final int iowaitTime = stats.getLastIoWaitTime();
    --            final int irqTime = stats.getLastIrqTime();
    --            final int softIrqTime = stats.getLastSoftIrqTime();
    --            final int idleTime = stats.getLastIdleTime();
    --
    --            final int totalTime = userTime+systemTime+iowaitTime+irqTime+softIrqTime+idleTime;
    --            if (totalTime == 0) {
    --                return;
    --            }
    --            int userW = (userTime*W)/totalTime;
    --            int systemW = (systemTime*W)/totalTime;
    --            int irqW = ((iowaitTime+irqTime+softIrqTime)*W)/totalTime;
    --
    --            int paddingRight = getPaddingRight();
    --            int x = RIGHT - paddingRight;
    --            int top = getPaddingTop() + 2;
    --            int bottom = getPaddingTop() + mFH - 2;
    --
    --            if (irqW > 0) {
    --                canvas.drawRect(x-irqW, top, x, bottom, mIrqPaint);
    --                x -= irqW;
    --            }
    --            if (systemW > 0) {
    --                canvas.drawRect(x-systemW, top, x, bottom, mSystemPaint);
    --                x -= systemW;
    --            }
    --            if (userW > 0) {
    --                canvas.drawRect(x-userW, top, x, bottom, mUserPaint);
    --                x -= userW;
    --            }
    --
    --            int y = getPaddingTop() - (int)mAscent;
    --            canvas.drawText(stats.mLoadText, RIGHT-paddingRight-stats.mLoadWidth-1,
    --                    y-1, mShadowPaint);
    --            canvas.drawText(stats.mLoadText, RIGHT-paddingRight-stats.mLoadWidth-1,
    --                    y+1, mShadowPaint);
    --            canvas.drawText(stats.mLoadText, RIGHT-paddingRight-stats.mLoadWidth+1,
    --                    y-1, mShadow2Paint);
    --            canvas.drawText(stats.mLoadText, RIGHT-paddingRight-stats.mLoadWidth+1,
    --                    y+1, mShadow2Paint);
    --            canvas.drawText(stats.mLoadText, RIGHT-paddingRight-stats.mLoadWidth,
    --                    y, mLoadPaint);
    --
    --            int N = stats.countWorkingStats();
    --            for (int i=0; i<N; i++) {
    --                CpuTracker.Stats st = stats.getWorkingStats(i);
    --                y += mFH;
    --                top += mFH;
    --                bottom += mFH;
    --
    --                userW = (st.rel_utime*W)/totalTime;
    --                systemW = (st.rel_stime*W)/totalTime;
    --                x = RIGHT - paddingRight;
    --                if (systemW > 0) {
    --                    canvas.drawRect(x-systemW, top, x, bottom, mSystemPaint);
    --                    x -= systemW;
    --                }
    --                if (userW > 0) {
    --                    canvas.drawRect(x-userW, top, x, bottom, mUserPaint);
    --                    x -= userW;
    --                }
    --
    --                canvas.drawText(st.name, RIGHT-paddingRight-st.nameWidth-1,
    --                        y-1, mShadowPaint);
    --                canvas.drawText(st.name, RIGHT-paddingRight-st.nameWidth-1,
    --                        y+1, mShadowPaint);
    --                canvas.drawText(st.name, RIGHT-paddingRight-st.nameWidth+1,
    --                        y-1, mShadow2Paint);
    --                canvas.drawText(st.name, RIGHT-paddingRight-st.nameWidth+1,
    --                        y+1, mShadow2Paint);
    --                Paint p = mLoadPaint;
    --                if (st.added) p = mAddedPaint;
    --                if (st.removed) p = mRemovedPaint;
    --                canvas.drawText(st.name, RIGHT-paddingRight-st.nameWidth, y, p);
    --            }
    --        }
    --
    --        void updateDisplay() {
    --            final CpuTracker stats = mStats;
    --            final int NW = stats.countWorkingStats();
    --
    --            int maxWidth = stats.mLoadWidth;
    --            for (int i=0; i<NW; i++) {
    --                CpuTracker.Stats st = stats.getWorkingStats(i);
    --                if (st.nameWidth > maxWidth) {
    --                    maxWidth = st.nameWidth;
    --                }
    --            }
    --
    --            int neededWidth = getPaddingLeft() + getPaddingRight() + maxWidth;
    --            int neededHeight = getPaddingTop() + getPaddingBottom() + (mFH*(1+NW));
    --            if (neededWidth != mNeededWidth || neededHeight != mNeededHeight) {
    --                mNeededWidth = neededWidth;
    --                mNeededHeight = neededHeight;
    --                requestLayout();
    --            } else {
    --                invalidate();
    --            }
    --        }
    --    }
    --
    --    @Override
    --    public void onCreate() {
    --        super.onCreate();
    --        mView = new LoadView(this);
    --        WindowManager.LayoutParams params = new WindowManager.LayoutParams(
    --            WindowManager.LayoutParams.MATCH_PARENT,
    --            WindowManager.LayoutParams.WRAP_CONTENT,
    --            WindowManager.LayoutParams.TYPE_SECURE_SYSTEM_OVERLAY,
    --            WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE|
    --            WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE,
    --            PixelFormat.TRANSLUCENT);
    --        params.gravity = Gravity.END | Gravity.TOP;
    --        params.setTitle("Load Average");
    --        WindowManager wm = (WindowManager)getSystemService(WINDOW_SERVICE);
    --        wm.addView(mView, params);
    --    }
    --
    --    @Override
    --    public void onDestroy() {
    --        super.onDestroy();
    --        ((WindowManager)getSystemService(WINDOW_SERVICE)).removeView(mView);
    --        mView = null;
    --    }
    --
    --    @Override
    --    public IBinder onBind(Intent intent) {
    --        return null;
    --    }
    --
    --}
    -diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeLog.java b/packages/SystemUI/src/com/android/systemui/doze/DozeLog.java
    -index 874021a..b3038b9 100644
    ---- a/packages/SystemUI/src/com/android/systemui/doze/DozeLog.java
    -+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeLog.java
    -@@ -35,12 +35,13 @@ public class DozeLog {
    -     private static final int SIZE = Build.IS_DEBUGGABLE ? 400 : 50;
    -     static final SimpleDateFormat FORMAT = new SimpleDateFormat("MM-dd HH:mm:ss.SSS");
    - 
    --    private static final int PULSE_REASONS = 4;
    -+    private static final int PULSE_REASONS = 5;
    - 
    -     public static final int PULSE_REASON_INTENT = 0;
    -     public static final int PULSE_REASON_NOTIFICATION = 1;
    -     public static final int PULSE_REASON_SENSOR_SIGMOTION = 2;
    -     public static final int PULSE_REASON_SENSOR_PICKUP = 3;
    -+    public static final int PULSE_REASON_SENSOR_DOUBLE_TAP = 4;
    - 
    -     private static long[] sTimes;
    -     private static String[] sMessages;
    -@@ -167,6 +168,7 @@ public class DozeLog {
    -             case PULSE_REASON_NOTIFICATION: return "notification";
    -             case PULSE_REASON_SENSOR_SIGMOTION: return "sigmotion";
    -             case PULSE_REASON_SENSOR_PICKUP: return "pickup";
    -+            case PULSE_REASON_SENSOR_DOUBLE_TAP: return "doubletap";
    -             default: throw new IllegalArgumentException("bad reason: " + pulseReason);
    -         }
    -     }
    -diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeService.java b/packages/SystemUI/src/com/android/systemui/doze/DozeService.java
    -index ec4f447..6c35243 100644
    ---- a/packages/SystemUI/src/com/android/systemui/doze/DozeService.java
    -+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeService.java
    -@@ -16,12 +16,14 @@
    - 
    - package com.android.systemui.doze;
    - 
    -+import android.app.ActivityManager;
    - import android.app.UiModeManager;
    - import android.content.BroadcastReceiver;
    - import android.content.Context;
    - import android.content.Intent;
    - import android.content.IntentFilter;
    - import android.content.res.Configuration;
    -+import android.database.ContentObserver;
    - import android.hardware.Sensor;
    - import android.hardware.SensorEvent;
    - import android.hardware.SensorEventListener;
    -@@ -29,14 +31,19 @@ import android.hardware.SensorManager;
    - import android.hardware.TriggerEvent;
    - import android.hardware.TriggerEventListener;
    - import android.media.AudioAttributes;
    -+import android.net.Uri;
    - import android.os.Handler;
    - import android.os.PowerManager;
    - import android.os.SystemClock;
    -+import android.os.UserHandle;
    - import android.os.Vibrator;
    -+import android.provider.Settings;
    - import android.service.dreams.DreamService;
    -+import android.text.TextUtils;
    - import android.util.Log;
    - import android.view.Display;
    - 
    -+import com.android.internal.hardware.AmbientDisplayConfiguration;
    - import com.android.internal.logging.MetricsLogger;
    - import com.android.internal.logging.MetricsProto.MetricsEvent;
    - import com.android.systemui.SystemUIApplication;
    -@@ -45,6 +52,7 @@ import com.android.systemui.statusbar.phone.DozeParameters;
    - import java.io.FileDescriptor;
    - import java.io.PrintWriter;
    - import java.util.Date;
    -+import java.util.List;
    - 
    - public class DozeService extends DreamService {
    -     private static final String TAG = "DozeService";
    -@@ -53,14 +61,19 @@ public class DozeService extends DreamService {
    -     private static final String ACTION_BASE = "com.android.systemui.doze";
    -     private static final String PULSE_ACTION = ACTION_BASE + ".pulse";
    - 
    -+    /**
    -+     * If true, reregisters all trigger sensors when the screen turns off.
    -+     */
    -+    private static final boolean REREGISTER_ALL_SENSORS_ON_SCREEN_OFF = true;
    -+
    -     private final String mTag = String.format(TAG + ".%08x", hashCode());
    -     private final Context mContext = this;
    -     private final DozeParameters mDozeParameters = new DozeParameters(mContext);
    -     private final Handler mHandler = new Handler();
    - 
    -     private DozeHost mHost;
    --    private SensorManager mSensors;
    --    private TriggerSensor mSigMotionSensor;
    -+    private SensorManager mSensorManager;
    -+    private TriggerSensor[] mSensors;
    -     private TriggerSensor mPickupSensor;
    -     private PowerManager mPowerManager;
    -     private PowerManager.WakeLock mWakeLock;
    -@@ -73,6 +86,8 @@ public class DozeService extends DreamService {
    -     private boolean mCarMode;
    -     private long mNotificationPulseTime;
    - 
    -+    private AmbientDisplayConfiguration mConfig;
    -+
    -     public DozeService() {
    -         if (DEBUG) Log.d(mTag, "new DozeService()");
    -         setDebug(DEBUG);
    -@@ -86,8 +101,10 @@ public class DozeService extends DreamService {
    -         pw.print("  mWakeLock: held="); pw.println(mWakeLock.isHeld());
    -         pw.print("  mHost: "); pw.println(mHost);
    -         pw.print("  mBroadcastReceiverRegistered: "); pw.println(mBroadcastReceiverRegistered);
    --        pw.print("  mSigMotionSensor: "); pw.println(mSigMotionSensor);
    --        pw.print("  mPickupSensor:"); pw.println(mPickupSensor);
    -+        for (TriggerSensor s : mSensors) {
    -+            pw.print("  sensor: ");
    -+            pw.println(s);
    -+        }
    -         pw.print("  mDisplayStateSupported: "); pw.println(mDisplayStateSupported);
    -         pw.print("  mPowerSaveActive: "); pw.println(mPowerSaveActive);
    -         pw.print("  mCarMode: "); pw.println(mCarMode);
    -@@ -110,13 +127,26 @@ public class DozeService extends DreamService {
    - 
    -         setWindowless(true);
    - 
    --        mSensors = (SensorManager) mContext.getSystemService(Context.SENSOR_SERVICE);
    --        mSigMotionSensor = new TriggerSensor(Sensor.TYPE_SIGNIFICANT_MOTION,
    --                mDozeParameters.getPulseOnSigMotion(), mDozeParameters.getVibrateOnSigMotion(),
    --                DozeLog.PULSE_REASON_SENSOR_SIGMOTION);
    --        mPickupSensor = new TriggerSensor(Sensor.TYPE_PICK_UP_GESTURE,
    --                mDozeParameters.getPulseOnPickup(), mDozeParameters.getVibrateOnPickup(),
    --                DozeLog.PULSE_REASON_SENSOR_PICKUP);
    -+        mSensorManager = (SensorManager) mContext.getSystemService(Context.SENSOR_SERVICE);
    -+        mConfig = new AmbientDisplayConfiguration(mContext);
    -+        mSensors = new TriggerSensor[] {
    -+                new TriggerSensor(
    -+                        mSensorManager.getDefaultSensor(Sensor.TYPE_SIGNIFICANT_MOTION),
    -+                        null /* setting */,
    -+                        mDozeParameters.getPulseOnSigMotion(),
    -+                        mDozeParameters.getVibrateOnSigMotion(),
    -+                        DozeLog.PULSE_REASON_SENSOR_SIGMOTION),
    -+                mPickupSensor = new TriggerSensor(
    -+                        mSensorManager.getDefaultSensor(Sensor.TYPE_PICK_UP_GESTURE),
    -+                        Settings.Secure.DOZE_PULSE_ON_PICK_UP,
    -+                        mConfig.pulseOnPickupAvailable(), mDozeParameters.getVibrateOnPickup(),
    -+                        DozeLog.PULSE_REASON_SENSOR_PICKUP),
    -+                new TriggerSensor(
    -+                        findSensorWithType(mConfig.doubleTapSensorType()),
    -+                        Settings.Secure.DOZE_PULSE_ON_DOUBLE_TAP, true,
    -+                        mDozeParameters.getVibrateOnPickup(),
    -+                        DozeLog.PULSE_REASON_SENSOR_DOUBLE_TAP)
    -+        };
    -         mPowerManager = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
    -         mWakeLock = mPowerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, TAG);
    -         mWakeLock.setReferenceCounted(true);
    -@@ -159,18 +189,15 @@ public class DozeService extends DreamService {
    -         // Ask the host to get things ready to start dozing.
    -         // Once ready, we call startDozing() at which point the CPU may suspend
    -         // and we will need to acquire a wakelock to do work.
    --        mHost.startDozing(new Runnable() {
    --            @Override
    --            public void run() {
    --                if (mDreaming) {
    --                    startDozing();
    -+        mHost.startDozing(mWakeLock.wrap(() -> {
    -+            if (mDreaming) {
    -+                startDozing();
    - 
    --                    // From this point until onDreamingStopped we will need to hold a
    --                    // wakelock whenever we are doing work.  Note that we never call
    --                    // stopDozing because can we just keep dozing until the bitter end.
    --                }
    -+                // From this point until onDreamingStopped we will need to hold a
    -+                // wakelock whenever we are doing work.  Note that we never call
    -+                // stopDozing because can we just keep dozing until the bitter end.
    -             }
    --        });
    -+        }));
    -     }
    - 
    -     @Override
    -@@ -254,6 +281,9 @@ public class DozeService extends DreamService {
    -             public void onPulseFinished() {
    -                 if (mPulsing && mDreaming) {
    -                     mPulsing = false;
    -+                    if (REREGISTER_ALL_SENSORS_ON_SCREEN_OFF) {
    -+                        reregisterAllSensors();
    -+                    }
    -                     turnDisplayOff();
    -                 }
    -                 mWakeLock.release(); // needs to be unconditional to balance acquire
    -@@ -283,21 +313,41 @@ public class DozeService extends DreamService {
    - 
    -     private void listenForPulseSignals(boolean listen) {
    -         if (DEBUG) Log.d(mTag, "listenForPulseSignals: " + listen);
    --        mSigMotionSensor.setListening(listen);
    --        mPickupSensor.setListening(listen);
    -+        for (TriggerSensor s : mSensors) {
    -+            s.setListening(listen);
    -+        }
    -         listenForBroadcasts(listen);
    -         listenForNotifications(listen);
    -     }
    - 
    -+    private void reregisterAllSensors() {
    -+        for (TriggerSensor s : mSensors) {
    -+            s.setListening(false);
    -+        }
    -+        for (TriggerSensor s : mSensors) {
    -+            s.setListening(true);
    -+        }
    -+    }
    -+
    -     private void listenForBroadcasts(boolean listen) {
    -         if (listen) {
    -             final IntentFilter filter = new IntentFilter(PULSE_ACTION);
    -             filter.addAction(UiModeManager.ACTION_ENTER_CAR_MODE);
    -+            filter.addAction(Intent.ACTION_USER_SWITCHED);
    -             mContext.registerReceiver(mBroadcastReceiver, filter);
    -+
    -+            for (TriggerSensor s : mSensors) {
    -+                if (s.mConfigured && !TextUtils.isEmpty(s.mSetting)) {
    -+                    mContext.getContentResolver().registerContentObserver(
    -+                            Settings.Secure.getUriFor(s.mSetting), false /* descendants */,
    -+                            mSettingsObserver, UserHandle.USER_ALL);
    -+                }
    -+            }
    -             mBroadcastReceiverRegistered = true;
    -         } else {
    -             if (mBroadcastReceiverRegistered) {
    -                 mContext.unregisterReceiver(mBroadcastReceiver);
    -+                mContext.getContentResolver().unregisterContentObserver(mSettingsObserver);
    -             }
    -             mBroadcastReceiverRegistered = false;
    -         }
    -@@ -313,7 +363,7 @@ public class DozeService extends DreamService {
    - 
    -     private void requestNotificationPulse() {
    -         if (DEBUG) Log.d(mTag, "requestNotificationPulse");
    --        if (!mDozeParameters.getPulseOnNotifications()) return;
    -+        if (!mConfig.pulseOnNotificationEnabled(UserHandle.USER_CURRENT)) return;
    -         mNotificationPulseTime = SystemClock.elapsedRealtime();
    -         requestPulse(DozeLog.PULSE_REASON_NOTIFICATION);
    -     }
    -@@ -344,6 +394,23 @@ public class DozeService extends DreamService {
    -                     finishForCarMode();
    -                 }
    -             }
    -+            if (Intent.ACTION_USER_SWITCHED.equals(intent.getAction())) {
    -+                for (TriggerSensor s : mSensors) {
    -+                    s.updateListener();
    -+                }
    -+            }
    -+        }
    -+    };
    -+
    -+    private final ContentObserver mSettingsObserver = new ContentObserver(mHandler) {
    -+        @Override
    -+        public void onChange(boolean selfChange, Uri uri, int userId) {
    -+            if (userId != ActivityManager.getCurrentUser()) {
    -+                return;
    -+            }
    -+            for (TriggerSensor s : mSensors) {
    -+                s.updateListener();
    -+            }
    -         }
    -     };
    - 
    -@@ -375,18 +442,34 @@ public class DozeService extends DreamService {
    -         }
    -     };
    - 
    -+    private Sensor findSensorWithType(String type) {
    -+        if (TextUtils.isEmpty(type)) {
    -+            return null;
    -+        }
    -+        List<Sensor> sensorList = mSensorManager.getSensorList(Sensor.TYPE_ALL);
    -+        for (Sensor s : sensorList) {
    -+            if (type.equals(s.getStringType())) {
    -+                return s;
    -+            }
    -+        }
    -+        return null;
    -+    }
    -+
    -     private class TriggerSensor extends TriggerEventListener {
    --        private final Sensor mSensor;
    --        private final boolean mConfigured;
    --        private final boolean mDebugVibrate;
    --        private final int mPulseReason;
    -+        final Sensor mSensor;
    -+        final boolean mConfigured;
    -+        final boolean mDebugVibrate;
    -+        final int mPulseReason;
    -+        final String mSetting;
    - 
    -         private boolean mRequested;
    -         private boolean mRegistered;
    -         private boolean mDisabled;
    - 
    --        public TriggerSensor(int type, boolean configured, boolean debugVibrate, int pulseReason) {
    --            mSensor = mSensors.getDefaultSensor(type);
    -+        public TriggerSensor(Sensor sensor, String setting, boolean configured,
    -+                boolean debugVibrate, int pulseReason) {
    -+            mSensor = sensor;
    -+            mSetting = setting;
    -             mConfigured = configured;
    -             mDebugVibrate = debugVibrate;
    -             mPulseReason = pulseReason;
    -@@ -404,18 +487,26 @@ public class DozeService extends DreamService {
    -             updateListener();
    -         }
    - 
    --        private void updateListener() {
    -+        public void updateListener() {
    -             if (!mConfigured || mSensor == null) return;
    --            if (mRequested && !mDisabled && !mRegistered) {
    --                mRegistered = mSensors.requestTriggerSensor(this, mSensor);
    -+            if (mRequested && !mDisabled && enabledBySetting() && !mRegistered) {
    -+                mRegistered = mSensorManager.requestTriggerSensor(this, mSensor);
    -                 if (DEBUG) Log.d(mTag, "requestTriggerSensor " + mRegistered);
    -             } else if (mRegistered) {
    --                final boolean rt = mSensors.cancelTriggerSensor(this, mSensor);
    -+                final boolean rt = mSensorManager.cancelTriggerSensor(this, mSensor);
    -                 if (DEBUG) Log.d(mTag, "cancelTriggerSensor " + rt);
    -                 mRegistered = false;
    -             }
    -         }
    - 
    -+        private boolean enabledBySetting() {
    -+            if (TextUtils.isEmpty(mSetting)) {
    -+                return true;
    -+            }
    -+            return Settings.Secure.getIntForUser(mContext.getContentResolver(), mSetting, 1,
    -+                    UserHandle.USER_CURRENT) != 0;
    -+        }
    -+
    -         @Override
    -         public String toString() {
    -             return new StringBuilder("{mRegistered=").append(mRegistered)
    -@@ -484,7 +575,7 @@ public class DozeService extends DreamService {
    - 
    -         public void check() {
    -             if (mFinished || mRegistered) return;
    --            final Sensor sensor = mSensors.getDefaultSensor(Sensor.TYPE_PROXIMITY);
    -+            final Sensor sensor = mSensorManager.getDefaultSensor(Sensor.TYPE_PROXIMITY);
    -             if (sensor == null) {
    -                 if (DEBUG) Log.d(mTag, "No sensor found");
    -                 finishWithResult(RESULT_UNKNOWN);
    -@@ -494,7 +585,8 @@ public class DozeService extends DreamService {
    -             mPickupSensor.setDisabled(true);
    - 
    -             mMaxRange = sensor.getMaximumRange();
    --            mSensors.registerListener(this, sensor, SensorManager.SENSOR_DELAY_NORMAL, 0, mHandler);
    -+            mSensorManager.registerListener(this, sensor, SensorManager.SENSOR_DELAY_NORMAL, 0,
    -+                    mHandler);
    -             mHandler.postDelayed(this, TIMEOUT_DELAY_MS);
    -             mRegistered = true;
    -         }
    -@@ -521,7 +613,7 @@ public class DozeService extends DreamService {
    -             if (mFinished) return;
    -             if (mRegistered) {
    -                 mHandler.removeCallbacks(this);
    --                mSensors.unregisterListener(this);
    -+                mSensorManager.unregisterListener(this);
    -                 // we're done - reenable the pickup sensor
    -                 mPickupSensor.setDisabled(false);
    -                 mRegistered = false;
    -diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardService.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardService.java
    -index 84901ee..b393cf7 100644
    ---- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardService.java
    -+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardService.java
    -@@ -90,10 +90,10 @@ public class KeyguardService extends Service {
    -         }
    - 
    -         @Override // Binder interface
    --        public void setOccluded(boolean isOccluded) {
    -+        public void setOccluded(boolean isOccluded, boolean animate) {
    -             Trace.beginSection("KeyguardService.mBinder#setOccluded");
    -             checkPermission();
    --            mKeyguardViewMediator.setOccluded(isOccluded);
    -+            mKeyguardViewMediator.setOccluded(isOccluded, animate);
    -             Trace.endSection();
    -         }
    - 
    -diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
    -index de0c77b..6103355 100644
    ---- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
    -+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
    -@@ -964,6 +964,7 @@ public class KeyguardViewMediator extends SystemUI {
    -      * if there is a secure lock pattern.
    -      */
    -     public void onDreamingStarted() {
    -+        KeyguardUpdateMonitor.getInstance(mContext).dispatchDreamingStarted();
    -         synchronized (this) {
    -             if (mDeviceInteractive
    -                     && mLockPatternUtils.isSecure(KeyguardUpdateMonitor.getCurrentUser())) {
    -@@ -976,6 +977,7 @@ public class KeyguardViewMediator extends SystemUI {
    -      * A dream stopped.
    -      */
    -     public void onDreamingStopped() {
    -+        KeyguardUpdateMonitor.getInstance(mContext).dispatchDreamingStopped();
    -         synchronized (this) {
    -             if (mDeviceInteractive) {
    -                 cancelDoKeyguardLaterLocked();
    -@@ -1114,11 +1116,11 @@ public class KeyguardViewMediator extends SystemUI {
    -     /**
    -      * Notify us when the keyguard is occluded by another window
    -      */
    --    public void setOccluded(boolean isOccluded) {
    -+    public void setOccluded(boolean isOccluded, boolean animate) {
    -         Trace.beginSection("KeyguardViewMediator#setOccluded");
    -         if (DEBUG) Log.d(TAG, "setOccluded " + isOccluded);
    -         mHandler.removeMessages(SET_OCCLUDED);
    --        Message msg = mHandler.obtainMessage(SET_OCCLUDED, (isOccluded ? 1 : 0), 0);
    -+        Message msg = mHandler.obtainMessage(SET_OCCLUDED, isOccluded ? 1 : 0, animate ? 1 : 0);
    -         mHandler.sendMessage(msg);
    -         Trace.endSection();
    -     }
    -@@ -1126,7 +1128,7 @@ public class KeyguardViewMediator extends SystemUI {
    -     /**
    -      * Handles SET_OCCLUDED message sent by setOccluded()
    -      */
    --    private void handleSetOccluded(boolean isOccluded) {
    -+    private void handleSetOccluded(boolean isOccluded, boolean animate) {
    -         Trace.beginSection("KeyguardViewMediator#handleSetOccluded");
    -         synchronized (KeyguardViewMediator.this) {
    -             if (mHiding && isOccluded) {
    -@@ -1137,7 +1139,7 @@ public class KeyguardViewMediator extends SystemUI {
    - 
    -             if (mOccluded != isOccluded) {
    -                 mOccluded = isOccluded;
    --                mStatusBarKeyguardViewManager.setOccluded(isOccluded);
    -+                mStatusBarKeyguardViewManager.setOccluded(isOccluded, animate);
    -                 updateActivityLockScreenState();
    -                 adjustStatusBarLocked();
    -             }
    -@@ -1468,7 +1470,7 @@ public class KeyguardViewMediator extends SystemUI {
    -                     break;
    -                 case SET_OCCLUDED:
    -                     Trace.beginSection("KeyguardViewMediator#handleMessage SET_OCCLUDED");
    --                    handleSetOccluded(msg.arg1 != 0);
    -+                    handleSetOccluded(msg.arg1 != 0, msg.arg2 != 0);
    -                     Trace.endSection();
    -                     break;
    -                 case KEYGUARD_TIMEOUT:
    -diff --git a/packages/SystemUI/src/com/android/systemui/qs/PagedTileLayout.java b/packages/SystemUI/src/com/android/systemui/qs/PagedTileLayout.java
    -index afedbe3..1c242e9 100644
    ---- a/packages/SystemUI/src/com/android/systemui/qs/PagedTileLayout.java
    -+++ b/packages/SystemUI/src/com/android/systemui/qs/PagedTileLayout.java
    -@@ -88,9 +88,9 @@ public class PagedTileLayout extends ViewPager implements QSTileLayout {
    -         if (mListening == listening) return;
    -         mListening = listening;
    -         if (mListening) {
    --            mPages.get(mPosition).setListening(listening);
    -+            setPageListening(mPosition, true);
    -             if (mOffPage) {
    --                mPages.get(mPosition + 1).setListening(listening);
    -+                setPageListening(mPosition + 1, true);
    -             }
    -         } else {
    -             // Make sure no pages are listening.
    -@@ -131,6 +131,9 @@ public class PagedTileLayout extends ViewPager implements QSTileLayout {
    - 
    -     private void setPageListening(int position, boolean listening) {
    -         if (position >= mPages.size()) return;
    -+        if (isLayoutRtl()) {
    -+            position = mPages.size() - 1 - position;
    -+        }
    -         mPages.get(position).setListening(listening);
    -     }
    - 
    -diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSAnimator.java b/packages/SystemUI/src/com/android/systemui/qs/QSAnimator.java
    -index a21408d..5c8a6e2 100644
    ---- a/packages/SystemUI/src/com/android/systemui/qs/QSAnimator.java
    -+++ b/packages/SystemUI/src/com/android/systemui/qs/QSAnimator.java
    -@@ -160,6 +160,10 @@ public class QSAnimator implements Callback, PageListener, Listener, OnLayoutCha
    - 
    -         for (QSTile<?> tile : tiles) {
    -             QSTileBaseView tileView = mQsPanel.getTileView(tile);
    -+            if (tileView == null) {
    -+                Log.e(TAG, "tileView is null " + tile.getTileSpec());
    -+                continue;
    -+            }
    -             final TextView label = ((QSTileView) tileView).getLabel();
    -             final View tileIcon = tileView.getIcon().getIconView();
    -             if (count < mNumQuickTiles && mAllowFancy) {
    -diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSContainer.java b/packages/SystemUI/src/com/android/systemui/qs/QSContainer.java
    -index 19a5d52..2b28fe6 100644
    ---- a/packages/SystemUI/src/com/android/systemui/qs/QSContainer.java
    -+++ b/packages/SystemUI/src/com/android/systemui/qs/QSContainer.java
    -@@ -320,4 +320,9 @@ public class QSContainer extends FrameLayout {
    -     public int getQsMinExpansionHeight() {
    -         return mHeader.getHeight();
    -     }
    -+
    -+    public void hideImmediately() {
    -+        animate().cancel();
    -+        setY(-mHeader.getHeight());
    -+    }
    - }
    -diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSFooter.java b/packages/SystemUI/src/com/android/systemui/qs/QSFooter.java
    -index 15ae4ad..ccb28e9 100644
    ---- a/packages/SystemUI/src/com/android/systemui/qs/QSFooter.java
    -+++ b/packages/SystemUI/src/com/android/systemui/qs/QSFooter.java
    -@@ -120,11 +120,10 @@ public class QSFooter implements OnClickListener, DialogInterface.OnClickListene
    -             mFooterTextId = R.string.device_owned_footer;
    -             mIsVisible = true;
    -         } else {
    --            mFooterTextId = R.string.vpn_footer;
    -+            boolean isBranded = mSecurityController.isVpnBranded();
    -+            mFooterTextId = isBranded ? R.string.branded_vpn_footer : R.string.vpn_footer;
    -             // Update the VPN footer icon, if needed.
    --            int footerIconId = (mSecurityController.isVpnBranded()
    --                ? R.drawable.ic_qs_branded_vpn
    --                : R.drawable.ic_qs_vpn);
    -+            int footerIconId = isBranded ? R.drawable.ic_qs_branded_vpn : R.drawable.ic_qs_vpn;
    -             if (mFooterIconId != footerIconId) {
    -                 mFooterIconId = footerIconId;
    -                 mMainHandler.post(mUpdateIcon);
    -@@ -148,11 +147,15 @@ public class QSFooter implements OnClickListener, DialogInterface.OnClickListene
    -         String primaryVpn = mSecurityController.getPrimaryVpnName();
    -         String profileVpn = mSecurityController.getProfileVpnName();
    -         boolean managed = mSecurityController.hasProfileOwner();
    -+        boolean isBranded = deviceOwner == null && mSecurityController.isVpnBranded();
    - 
    -         mDialog = new SystemUIDialog(mContext);
    --        mDialog.setTitle(getTitle(deviceOwner));
    --        mDialog.setMessage(getMessage(deviceOwner, profileOwner, primaryVpn, profileVpn, managed));
    --        mDialog.setButton(DialogInterface.BUTTON_POSITIVE, getPositiveButton(), this);
    -+        if (!isBranded) {
    -+            mDialog.setTitle(getTitle(deviceOwner));
    -+        }
    -+        mDialog.setMessage(getMessage(deviceOwner, profileOwner, primaryVpn, profileVpn, managed,
    -+                isBranded));
    -+        mDialog.setButton(DialogInterface.BUTTON_POSITIVE, getPositiveButton(isBranded), this);
    -         if (mSecurityController.isVpnEnabled() && !mSecurityController.isVpnRestricted()) {
    -             mDialog.setButton(DialogInterface.BUTTON_NEGATIVE, getSettingsButton(), this);
    -         }
    -@@ -163,12 +166,12 @@ public class QSFooter implements OnClickListener, DialogInterface.OnClickListene
    -         return mContext.getString(R.string.status_bar_settings_settings_button);
    -     }
    - 
    --    private String getPositiveButton() {
    --        return mContext.getString(R.string.quick_settings_done);
    -+    private String getPositiveButton(boolean isBranded) {
    -+        return mContext.getString(isBranded ? android.R.string.ok : R.string.quick_settings_done);
    -     }
    - 
    -     private String getMessage(String deviceOwner, String profileOwner, String primaryVpn,
    --            String profileVpn, boolean primaryUserIsManaged) {
    -+            String profileVpn, boolean primaryUserIsManaged, boolean isBranded) {
    -         // Show a special warning when the device has device owner, but --
    -         // TODO See b/25779452 -- device owner doesn't actually have monitoring power.
    -         if (deviceOwner != null) {
    -@@ -184,8 +187,13 @@ public class QSFooter implements OnClickListener, DialogInterface.OnClickListene
    -                 return mContext.getString(R.string.monitoring_description_app_personal_work,
    -                         profileOwner, profileVpn, primaryVpn);
    -             } else {
    --                return mContext.getString(R.string.monitoring_description_app_personal,
    --                        primaryVpn);
    -+                if (isBranded) {
    -+                    return mContext.getString(R.string.branded_monitoring_description_app_personal,
    -+                            primaryVpn);
    -+                } else {
    -+                    return mContext.getString(R.string.monitoring_description_app_personal,
    -+                            primaryVpn);
    -+                }
    -             }
    -         } else if (profileVpn != null) {
    -             return mContext.getString(R.string.monitoring_description_app_work,
    -diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/DataUsageDetailView.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/DataUsageDetailView.java
    -index a63eabc..c7b6aea 100644
    ---- a/packages/SystemUI/src/com/android/systemui/qs/tiles/DataUsageDetailView.java
    -+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/DataUsageDetailView.java
    -@@ -115,6 +115,12 @@ public class DataUsageDetailView extends LinearLayout {
    -         final TextView infoBottom = (TextView) findViewById(R.id.usage_info_bottom_text);
    -         infoBottom.setVisibility(bottom != null ? View.VISIBLE : View.GONE);
    -         infoBottom.setText(bottom);
    -+        boolean showLevel = info.warningLevel > 0 || info.limitLevel > 0;
    -+        graph.setVisibility(showLevel ? View.VISIBLE : View.GONE);
    -+        if (!showLevel) {
    -+            infoTop.setVisibility(View.GONE);
    -+        }
    -+
    -     }
    - 
    -     private String formatBytes(long bytes) {
    -diff --git a/packages/SystemUI/src/com/android/systemui/recents/IRecentsNonSystemUserCallbacks.aidl b/packages/SystemUI/src/com/android/systemui/recents/IRecentsNonSystemUserCallbacks.aidl
    -index 9403664..9214eef 100644
    ---- a/packages/SystemUI/src/com/android/systemui/recents/IRecentsNonSystemUserCallbacks.aidl
    -+++ b/packages/SystemUI/src/com/android/systemui/recents/IRecentsNonSystemUserCallbacks.aidl
    -@@ -35,4 +35,5 @@ oneway interface IRecentsNonSystemUserCallbacks {
    -             in Rect initialBounds);
    -     void onDraggingInRecents(float distanceFromTop);
    -     void onDraggingInRecentsEnded(float velocity);
    -+    void showCurrentUserToast(int msgResId, int msgLength);
    - }
    -diff --git a/packages/SystemUI/src/com/android/systemui/recents/Recents.java b/packages/SystemUI/src/com/android/systemui/recents/Recents.java
    -index e117bfe..5b25f05 100644
    ---- a/packages/SystemUI/src/com/android/systemui/recents/Recents.java
    -+++ b/packages/SystemUI/src/com/android/systemui/recents/Recents.java
    -@@ -53,6 +53,7 @@ import com.android.systemui.recents.events.activity.DockedTopTaskEvent;
    - import com.android.systemui.recents.events.activity.RecentsActivityStartingEvent;
    - import com.android.systemui.recents.events.component.RecentsVisibilityChangedEvent;
    - import com.android.systemui.recents.events.component.ScreenPinningRequestEvent;
    -+import com.android.systemui.recents.events.component.ShowUserToastEvent;
    - import com.android.systemui.recents.events.ui.RecentsDrawnEvent;
    - import com.android.systemui.recents.misc.SystemServicesProxy;
    - import com.android.systemui.recents.model.RecentsTaskLoader;
    -@@ -455,8 +456,8 @@ public class Recents extends SystemUI
    -                 mDraggingInRecentsCurrentUser = currentUser;
    -                 return true;
    -             } else {
    --                Toast.makeText(mContext, R.string.recents_incompatible_app_message,
    --                        Toast.LENGTH_SHORT).show();
    -+                EventBus.getDefault().send(new ShowUserToastEvent(
    -+                        R.string.recents_incompatible_app_message, Toast.LENGTH_SHORT));
    -                 return false;
    -             }
    -         } else {
    -@@ -674,6 +675,27 @@ public class Recents extends SystemUI
    -         mImpl.onConfigurationChanged();
    -     }
    - 
    -+    public final void onBusEvent(ShowUserToastEvent event) {
    -+        int currentUser = sSystemServicesProxy.getCurrentUser();
    -+        if (sSystemServicesProxy.isSystemUser(currentUser)) {
    -+            mImpl.onShowCurrentUserToast(event.msgResId, event.msgLength);
    -+        } else {
    -+            if (mSystemToUserCallbacks != null) {
    -+                IRecentsNonSystemUserCallbacks callbacks =
    -+                        mSystemToUserCallbacks.getNonSystemUserRecentsForUser(currentUser);
    -+                if (callbacks != null) {
    -+                    try {
    -+                        callbacks.showCurrentUserToast(event.msgResId, event.msgLength);
    -+                    } catch (RemoteException e) {
    -+                        Log.e(TAG, "Callback failed", e);
    -+                    }
    -+                } else {
    -+                    Log.e(TAG, "No SystemUI callbacks found for user: " + currentUser);
    -+                }
    -+            }
    -+        }
    -+    }
    -+
    -     /**
    -      * Attempts to register with the system user.
    -      */
    -diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java
    -index 7bdb1c4..70642ed 100644
    ---- a/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java
    -+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java
    -@@ -17,6 +17,7 @@
    - package com.android.systemui.recents;
    - 
    - import android.app.Activity;
    -+import android.app.ActivityManager;
    - import android.app.ActivityOptions;
    - import android.app.TaskStackBuilder;
    - import android.content.BroadcastReceiver;
    -@@ -87,6 +88,7 @@ import com.android.systemui.statusbar.BaseStatusBar;
    - 
    - import java.io.FileDescriptor;
    - import java.io.PrintWriter;
    -+import java.util.List;
    - 
    - /**
    -  * The main Recents activity that is started from RecentsComponent.
    -@@ -165,18 +167,39 @@ public class RecentsActivity extends Activity implements ViewTreeObserver.OnPreD
    -      */
    -     final BroadcastReceiver mSystemBroadcastReceiver = new BroadcastReceiver() {
    -         @Override
    --        public void onReceive(Context context, Intent intent) {
    -+        public void onReceive(Context ctx, Intent intent) {
    -             String action = intent.getAction();
    -             if (action.equals(Intent.ACTION_SCREEN_OFF)) {
    -                 // When the screen turns off, dismiss Recents to Home
    -                 dismissRecentsToHomeIfVisible(false);
    -             } else if (action.equals(Intent.ACTION_TIME_CHANGED)) {
    --                // For the time being, if the time changes, then invalidate the
    --                // last-stack-active-time, this ensures that we will just show the last N tasks
    --                // the next time that Recents loads, but prevents really old tasks from showing
    --                // up if the task time is set forward.
    --                Prefs.putLong(RecentsActivity.this, Prefs.Key.OVERVIEW_LAST_STACK_TASK_ACTIVE_TIME,
    --                        0);
    -+                // If the time shifts but the currentTime >= lastStackActiveTime, then that boundary
    -+                // is still valid.  Otherwise, we need to reset the lastStackactiveTime to the
    -+                // currentTime and remove the old tasks in between which would not be previously
    -+                // visible, but currently would be in the new currentTime
    -+                long oldLastStackActiveTime = Prefs.getLong(RecentsActivity.this,
    -+                        Prefs.Key.OVERVIEW_LAST_STACK_TASK_ACTIVE_TIME, -1);
    -+                if (oldLastStackActiveTime != -1) {
    -+                    long currentTime = System.currentTimeMillis();
    -+                    if (currentTime < oldLastStackActiveTime) {
    -+                        // We are only removing tasks that are between the new current time
    -+                        // and the old last stack active time, they were not visible and in the
    -+                        // TaskStack so we don't need to remove any associated TaskViews but we do
    -+                        // need to load the task id's from the system
    -+                        RecentsTaskLoadPlan loadPlan = Recents.getTaskLoader().createLoadPlan(ctx);
    -+                        loadPlan.preloadRawTasks(false /* includeFrontMostExcludedTask */);
    -+                        List<ActivityManager.RecentTaskInfo> tasks = loadPlan.getRawTasks();
    -+                        for (int i = tasks.size() - 1; i >= 0; i--) {
    -+                            ActivityManager.RecentTaskInfo task = tasks.get(i);
    -+                            if (currentTime <= task.lastActiveTime && task.lastActiveTime <
    -+                                    oldLastStackActiveTime) {
    -+                                Recents.getSystemServices().removeTask(task.persistentId);
    -+                            }
    -+                        }
    -+                        Prefs.putLong(RecentsActivity.this,
    -+                                Prefs.Key.OVERVIEW_LAST_STACK_TASK_ACTIVE_TIME, currentTime);
    -+                    }
    -+                }
    -             }
    -         }
    -     };
    -diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java
    -index 2757fc4..42d1b61 100644
    ---- a/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java
    -+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java
    -@@ -40,6 +40,7 @@ import android.view.LayoutInflater;
    - import android.view.ViewConfiguration;
    - import android.view.WindowManager;
    - 
    -+import android.widget.Toast;
    - import com.android.internal.logging.MetricsLogger;
    - import com.android.internal.policy.DockedDividerUtils;
    - import com.android.systemui.R;
    -@@ -200,9 +201,17 @@ public class RecentsImpl implements ActivityOptions.OnAnimationFinishedListener
    -     }
    - 
    -     public void onConfigurationChanged() {
    -+        Resources res = mContext.getResources();
    -         reloadResources();
    -         mDummyStackView.reloadOnConfigurationChange();
    -+        // Update the header bar direction directly as it is not attached to anything and does not
    -+        // layout except in updateHeaderBarLayout()
    -+        mHeaderBar.setLayoutDirection(res.getConfiguration().getLayoutDirection());
    -         mHeaderBar.onConfigurationChanged();
    -+        mHeaderBar.forceLayout();
    -+        mHeaderBar.measure(
    -+                MeasureSpec.makeMeasureSpec(mHeaderBar.getMeasuredWidth(), MeasureSpec.EXACTLY),
    -+                MeasureSpec.makeMeasureSpec(mHeaderBar.getMeasuredHeight(), MeasureSpec.EXACTLY));
    -     }
    - 
    -     /**
    -@@ -211,11 +220,7 @@ public class RecentsImpl implements ActivityOptions.OnAnimationFinishedListener
    -      * {@link Recents#onBusEvent(RecentsVisibilityChangedEvent)}.
    -      */
    -     public void onVisibilityChanged(Context context, boolean visible) {
    --        SystemUIApplication app = (SystemUIApplication) context;
    --        PhoneStatusBar statusBar = app.getComponent(PhoneStatusBar.class);
    --        if (statusBar != null) {
    --            statusBar.updateRecentsVisibility(visible);
    --        }
    -+        Recents.getSystemServices().setRecentsVisibility(visible);
    -     }
    - 
    -     /**
    -@@ -392,6 +397,10 @@ public class RecentsImpl implements ActivityOptions.OnAnimationFinishedListener
    -         EventBus.getDefault().sendOntoMainThread(new DraggingInRecentsEndedEvent(velocity));
    -     }
    - 
    -+    public void onShowCurrentUserToast(int msgResId, int msgLength) {
    -+        Toast.makeText(mContext, msgResId, msgLength).show();
    -+    }
    -+
    -     /**
    -      * Transitions to the next recent task in the stack.
    -      */
    -@@ -621,6 +630,7 @@ public class RecentsImpl implements ActivityOptions.OnAnimationFinishedListener
    -                 synchronized (mHeaderBarLock) {
    -                     if (mHeaderBar.getMeasuredWidth() != taskViewWidth ||
    -                             mHeaderBar.getMeasuredHeight() != mTaskBarHeight) {
    -+                        mHeaderBar.forceLayout();
    -                         mHeaderBar.measure(
    -                                 MeasureSpec.makeMeasureSpec(taskViewWidth, MeasureSpec.EXACTLY),
    -                                 MeasureSpec.makeMeasureSpec(mTaskBarHeight, MeasureSpec.EXACTLY));
    -diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsImplProxy.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsImplProxy.java
    -index 60bf760..ff9e89e 100644
    ---- a/packages/SystemUI/src/com/android/systemui/recents/RecentsImplProxy.java
    -+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsImplProxy.java
    -@@ -38,6 +38,7 @@ public class RecentsImplProxy extends IRecentsNonSystemUserCallbacks.Stub {
    -     private static final int MSG_DOCK_TOP_TASK = 7;
    -     private static final int MSG_ON_DRAGGING_IN_RECENTS = 8;
    -     private static final int MSG_ON_DRAGGING_IN_RECENTS_ENDED = 9;
    -+    private static final int MSG_SHOW_USER_TOAST = 10;
    - 
    -     private RecentsImpl mImpl;
    - 
    -@@ -109,6 +110,11 @@ public class RecentsImplProxy extends IRecentsNonSystemUserCallbacks.Stub {
    -         mHandler.sendMessage(mHandler.obtainMessage(MSG_ON_DRAGGING_IN_RECENTS_ENDED, velocity));
    -     }
    - 
    -+    @Override
    -+    public void showCurrentUserToast(int msgResId, int msgLength) {
    -+        mHandler.sendMessage(mHandler.obtainMessage(MSG_SHOW_USER_TOAST, msgResId, msgLength));
    -+    }
    -+
    -     private final Handler mHandler = new Handler() {
    - 
    -         @Override
    -@@ -147,6 +153,9 @@ public class RecentsImplProxy extends IRecentsNonSystemUserCallbacks.Stub {
    -                 case MSG_ON_DRAGGING_IN_RECENTS_ENDED:
    -                     mImpl.onDraggingInRecentsEnded((Float) msg.obj);
    -                     break;
    -+                case MSG_SHOW_USER_TOAST:
    -+                    mImpl.onShowCurrentUserToast(msg.arg1, msg.arg2);
    -+                    break;
    -                 default:
    -                     super.handleMessage(msg);
    -             }
    -diff --git a/packages/SystemUI/src/com/android/systemui/recents/events/component/ShowUserToastEvent.java b/packages/SystemUI/src/com/android/systemui/recents/events/component/ShowUserToastEvent.java
    -new file mode 100644
    -index 0000000..e2b39c3
    ---- /dev/null
    -+++ b/packages/SystemUI/src/com/android/systemui/recents/events/component/ShowUserToastEvent.java
    -@@ -0,0 +1,33 @@
    -+/*
    -+ * Copyright (C) 2016 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 com.android.systemui.recents.events.component;
    -+
    -+import com.android.systemui.recents.events.EventBus;
    -+
    -+/**
    -+ * This is sent when we want to show a toast for the current user.
    -+ */
    -+public class ShowUserToastEvent extends EventBus.Event {
    -+
    -+    public final int msgResId;
    -+    public final int msgLength;
    -+
    -+    public ShowUserToastEvent(int msgResId, int msgLength) {
    -+        this.msgResId = msgResId;
    -+        this.msgLength = msgLength;
    -+    }
    -+}
    -diff --git a/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java b/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java
    -index b896f8a..930ed79 100644
    ---- a/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java
    -+++ b/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java
    -@@ -69,6 +69,7 @@ import android.util.MutableBoolean;
    - import android.view.Display;
    - import android.view.IAppTransitionAnimationSpecsFuture;
    - import android.view.IDockedStackListener;
    -+import android.view.IWindowManager;
    - import android.view.WindowManager;
    - import android.view.WindowManager.KeyboardShortcutsReceiver;
    - import android.view.WindowManagerGlobal;
    -@@ -120,6 +121,7 @@ public class SystemServicesProxy {
    -     IPackageManager mIpm;
    -     AssistUtils mAssistUtils;
    -     WindowManager mWm;
    -+    IWindowManager mIwm;
    -     UserManager mUm;
    -     Display mDisplay;
    -     String mRecentsPackage;
    -@@ -207,6 +209,7 @@ public class SystemServicesProxy {
    -         mIpm = AppGlobals.getPackageManager();
    -         mAssistUtils = new AssistUtils(context);
    -         mWm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
    -+        mIwm = WindowManagerGlobal.getWindowManagerService();
    -         mUm = UserManager.get(context);
    -         mDisplay = mWm.getDefaultDisplay();
    -         mRecentsPackage = context.getPackageName();
    -@@ -1091,6 +1094,28 @@ public class SystemServicesProxy {
    -         }
    -     }
    - 
    -+    /**
    -+     * Updates the visibility of recents.
    -+     */
    -+    public void setRecentsVisibility(boolean visible) {
    -+        try {
    -+            mIwm.setRecentsVisibility(visible);
    -+        } catch (RemoteException e) {
    -+            Log.e(TAG, "Unable to reach window manager", e);
    -+        }
    -+    }
    -+
    -+    /**
    -+     * Updates the visibility of the picture-in-picture.
    -+     */
    -+    public void setTvPipVisibility(boolean visible) {
    -+        try {
    -+            mIwm.setTvPipVisibility(visible);
    -+        } catch (RemoteException e) {
    -+            Log.e(TAG, "Unable to reach window manager", e);
    -+        }
    -+    }
    -+
    -     private final class H extends Handler {
    -         private static final int ON_TASK_STACK_CHANGED = 1;
    -         private static final int ON_ACTIVITY_PINNED = 2;
    -diff --git a/packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoadPlan.java b/packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoadPlan.java
    -index 1278b73..9b48e4d 100644
    ---- a/packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoadPlan.java
    -+++ b/packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoadPlan.java
    -@@ -248,6 +248,13 @@ public class RecentsTaskLoadPlan {
    -         return mStack;
    -     }
    - 
    -+    /**
    -+     * Returns the raw list of recent tasks.
    -+     */
    -+    public List<ActivityManager.RecentTaskInfo> getRawTasks() {
    -+        return mRawTasks;
    -+    }
    -+
    -     /** Returns whether there are any tasks in any stacks. */
    -     public boolean hasTasks() {
    -         if (mStack != null) {
    -diff --git a/packages/SystemUI/src/com/android/systemui/recents/tv/RecentsTvImpl.java b/packages/SystemUI/src/com/android/systemui/recents/tv/RecentsTvImpl.java
    -index fca8d2d..ef9de53 100644
    ---- a/packages/SystemUI/src/com/android/systemui/recents/tv/RecentsTvImpl.java
    -+++ b/packages/SystemUI/src/com/android/systemui/recents/tv/RecentsTvImpl.java
    -@@ -140,10 +140,6 @@ public class RecentsTvImpl extends RecentsImpl{
    - 
    -     @Override
    -     public void onVisibilityChanged(Context context, boolean visible) {
    --        SystemUIApplication app = (SystemUIApplication) context;
    --        TvStatusBar statusBar = app.getComponent(TvStatusBar.class);
    --        if (statusBar != null) {
    --            statusBar.updateRecentsVisibility(visible);
    --        }
    -+        Recents.getSystemServices().setRecentsVisibility(visible);
    -     }
    - }
    -diff --git a/packages/SystemUI/src/com/android/systemui/recents/tv/animations/HomeRecentsEnterExitAnimationHolder.java b/packages/SystemUI/src/com/android/systemui/recents/tv/animations/HomeRecentsEnterExitAnimationHolder.java
    -index 9faaa4b..a673c8c 100644
    ---- a/packages/SystemUI/src/com/android/systemui/recents/tv/animations/HomeRecentsEnterExitAnimationHolder.java
    -+++ b/packages/SystemUI/src/com/android/systemui/recents/tv/animations/HomeRecentsEnterExitAnimationHolder.java
    -@@ -47,12 +47,13 @@ public class HomeRecentsEnterExitAnimationHolder {
    -     public void startEnterAnimation(boolean isPipShown) {
    -         for(int i = 0; i < mGridView.getChildCount(); i++) {
    -             TaskCardView view = (TaskCardView) mGridView.getChildAt(i);
    -+            long delay = Math.max(mDelay * i, 0);
    -             view.setTranslationX(-mTranslationX);
    -             view.animate()
    -                     .alpha(isPipShown ? mDimAlpha : 1.0f)
    -                     .translationX(0)
    -                     .setDuration(mDuration)
    --                    .setStartDelay(mDelay * i)
    -+                    .setStartDelay(delay)
    -                     .setInterpolator(Interpolators.FAST_OUT_SLOW_IN);
    -         }
    -     }
    -@@ -60,11 +61,12 @@ public class HomeRecentsEnterExitAnimationHolder {
    -     public void startExitAnimation(DismissRecentsToHomeAnimationStarted dismissEvent) {
    -         for(int i = mGridView.getChildCount() - 1; i >= 0; i--) {
    -             TaskCardView view = (TaskCardView) mGridView.getChildAt(i);
    -+            long delay = Math.max(mDelay * (mGridView.getChildCount() - 1 - i), 0);
    -             view.animate()
    -                     .alpha(0.0f)
    -                     .translationXBy(-mTranslationX)
    -                     .setDuration(mDuration)
    --                    .setStartDelay(mDelay * (mGridView.getChildCount() - 1 - i))
    -+                    .setStartDelay(delay)
    -                     .setInterpolator(Interpolators.FAST_OUT_SLOW_IN);
    -             if(i == 0) {
    -                 view.animate().setListener(dismissEvent.getAnimationTrigger()
    -diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackLayoutAlgorithm.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackLayoutAlgorithm.java
    -index 702b076..fce7f9d 100644
    ---- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackLayoutAlgorithm.java
    -+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackLayoutAlgorithm.java
    -@@ -1258,7 +1258,7 @@ public class TaskStackLayoutAlgorithm {
    -         String innerPrefix = prefix + "  ";
    - 
    -         writer.print(prefix); writer.print(TAG);
    --        writer.write(" numStackTasks="); writer.write(mNumStackTasks);
    -+        writer.write(" numStackTasks="); writer.print(mNumStackTasks);
    -         writer.println();
    - 
    -         writer.print(innerPrefix);
    -diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java
    -index 24e75ac..fc580a5 100644
    ---- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java
    -+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java
    -@@ -164,6 +164,8 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal
    -     @ViewDebug.ExportedProperty(category="recents")
    -     private boolean mAwaitingFirstLayout = true;
    -     @ViewDebug.ExportedProperty(category="recents")
    -+    private boolean mLaunchNextAfterFirstMeasure = false;
    -+    @ViewDebug.ExportedProperty(category="recents")
    -     @InitialStateAction
    -     private int mInitialState = INITIAL_STATE_UPDATE_ALL;
    -     @ViewDebug.ExportedProperty(category="recents")
    -@@ -336,6 +338,7 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal
    -         // Since we always animate to the same place in (the initial state), always reset the stack
    -         // to the initial state when resuming
    -         mAwaitingFirstLayout = true;
    -+        mLaunchNextAfterFirstMeasure = false;
    -         mInitialState = INITIAL_STATE_UPDATE_ALL;
    -         requestLayout();
    -     }
    -@@ -676,13 +679,13 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal
    -         for (int i = 0; i < taskViewCount; i++) {
    -             TaskView tv = taskViews.get(i);
    -             Task task = tv.getTask();
    --            int taskIndex = mStack.indexOfStackTask(task);
    --            TaskViewTransform transform = mCurrentTaskTransforms.get(taskIndex);
    - 
    -             if (mIgnoreTasks.contains(task.key)) {
    -                 continue;
    -             }
    - 
    -+            int taskIndex = mStack.indexOfStackTask(task);
    -+            TaskViewTransform transform = mCurrentTaskTransforms.get(taskIndex);
    -             if (animationOverrides != null && animationOverrides.containsKey(task)) {
    -                 animation = animationOverrides.get(task);
    -             }
    -@@ -1223,6 +1226,12 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal
    -                 mInitialState = INITIAL_STATE_UPDATE_NONE;
    -             }
    -         }
    -+        // If we got the launch-next event before the first layout pass, then re-send it after the
    -+        // initial state has been updated
    -+        if (mLaunchNextAfterFirstMeasure) {
    -+            mLaunchNextAfterFirstMeasure = false;
    -+            EventBus.getDefault().post(new LaunchNextTaskRequestEvent());
    -+        }
    - 
    -         // Rebind all the views, including the ignore ones
    -         bindVisibleTaskViews(mStackScroller.getStackScroll(), false /* ignoreTaskOverrides */);
    -@@ -1665,6 +1674,11 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal
    -     }
    - 
    -     public final void onBusEvent(LaunchNextTaskRequestEvent event) {
    -+        if (mAwaitingFirstLayout) {
    -+            mLaunchNextAfterFirstMeasure = true;
    -+            return;
    -+        }
    -+
    -         int launchTaskIndex = mStack.indexOfStackTask(mStack.getLaunchTarget());
    -         if (launchTaskIndex != -1) {
    -             launchTaskIndex = Math.max(0, launchTaskIndex - 1);
    -diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewTouchHandler.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewTouchHandler.java
    -index 67a2595..d44aa84 100644
    ---- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewTouchHandler.java
    -+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewTouchHandler.java
    -@@ -634,6 +634,12 @@ class TaskStackViewTouchHandler implements SwipeHelper.Callback {
    -             }
    - 
    -             int taskIndex = mCurrentTasks.indexOf(task);
    -+            if (taskIndex == -1) {
    -+                // If a task was added to the stack view after the start of the dismiss gesture,
    -+                // just ignore it
    -+                continue;
    -+            }
    -+
    -             TaskViewTransform fromTransform = mCurrentTaskTransforms.get(taskIndex);
    -             TaskViewTransform toTransform = mFinalTaskTransforms.get(taskIndex);
    - 
    -diff --git a/packages/SystemUI/src/com/android/systemui/stackdivider/ForcedResizableInfoActivityController.java b/packages/SystemUI/src/com/android/systemui/stackdivider/ForcedResizableInfoActivityController.java
    -index 5f083d5..5920f46 100644
    ---- a/packages/SystemUI/src/com/android/systemui/stackdivider/ForcedResizableInfoActivityController.java
    -+++ b/packages/SystemUI/src/com/android/systemui/stackdivider/ForcedResizableInfoActivityController.java
    -@@ -20,12 +20,14 @@ import android.app.ActivityOptions;
    - import android.content.Context;
    - import android.content.Intent;
    - import android.os.Handler;
    -+import android.os.UserHandle;
    - import android.util.ArraySet;
    - import android.widget.Toast;
    - 
    - import com.android.systemui.R;
    - import com.android.systemui.recents.events.EventBus;
    - import com.android.systemui.recents.events.activity.AppTransitionFinishedEvent;
    -+import com.android.systemui.recents.events.component.ShowUserToastEvent;
    - import com.android.systemui.recents.misc.SystemServicesProxy;
    - import com.android.systemui.recents.misc.SystemServicesProxy.TaskStackListener;
    - import com.android.systemui.stackdivider.events.StartedDragingEvent;
    -@@ -100,9 +102,8 @@ public class ForcedResizableInfoActivityController {
    -     }
    - 
    -     private void activityDismissingDockedStack() {
    --        Toast toast = Toast.makeText(mContext, R.string.dock_non_resizeble_failed_to_dock_text,
    --                Toast.LENGTH_SHORT);
    --        toast.show();
    -+        EventBus.getDefault().send(new ShowUserToastEvent(
    -+                R.string.dock_non_resizeble_failed_to_dock_text, Toast.LENGTH_SHORT));
    -     }
    - 
    -     private void showPending() {
    -@@ -112,7 +113,7 @@ public class ForcedResizableInfoActivityController {
    -             ActivityOptions options = ActivityOptions.makeBasic();
    -             options.setLaunchTaskId(mPendingTaskIds.valueAt(i));
    -             options.setTaskOverlay(true);
    --            mContext.startActivity(intent, options.toBundle());
    -+            mContext.startActivityAsUser(intent, options.toBundle(), UserHandle.CURRENT);
    -         }
    -         mPendingTaskIds.clear();
    -     }
    -diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/ActivatableNotificationView.java b/packages/SystemUI/src/com/android/systemui/statusbar/ActivatableNotificationView.java
    -index e35ef44..bc46548 100644
    ---- a/packages/SystemUI/src/com/android/systemui/statusbar/ActivatableNotificationView.java
    -+++ b/packages/SystemUI/src/com/android/systemui/statusbar/ActivatableNotificationView.java
    -@@ -593,6 +593,9 @@ public abstract class ActivatableNotificationView extends ExpandableOutlineView
    -             public void onAnimationEnd(Animator animation) {
    -                 updateBackground();
    -                 mBackgroundAnimator = null;
    -+                if (mFadeInFromDarkAnimator == null) {
    -+                    mDimmedBackgroundFadeInAmount = -1;
    -+                }
    -             }
    -         });
    -         mBackgroundAnimator.addUpdateListener(mBackgroundVisibilityUpdater);
    -diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
    -index a1854fa..4866fca 100644
    ---- a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
    -+++ b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
    -@@ -113,8 +113,11 @@ import com.android.systemui.statusbar.stack.NotificationStackScrollLayout;
    - import com.android.systemui.statusbar.stack.StackStateAnimator;
    - 
    - import java.util.ArrayList;
    -+import java.util.Collections;
    -+import java.util.HashSet;
    - import java.util.List;
    - import java.util.Locale;
    -+import java.util.Set;
    - 
    - import static android.service.notification.NotificationListenerService.Ranking.IMPORTANCE_HIGH;
    - 
    -@@ -268,6 +271,8 @@ public abstract class BaseStatusBar extends SystemUI implements
    - 
    -     protected boolean mVrMode;
    - 
    -+    private Set<String> mNonBlockablePkgs;
    -+
    -     @Override  // NotificationData.Environment
    -     public boolean isDeviceProvisioned() {
    -         return mDeviceProvisioned;
    -@@ -824,6 +829,9 @@ public abstract class BaseStatusBar extends SystemUI implements
    -             Slog.e(TAG, "Failed to register VR mode state listener: " + e);
    -         }
    - 
    -+        mNonBlockablePkgs = new ArraySet<String>();
    -+        Collections.addAll(mNonBlockablePkgs, mContext.getResources().getStringArray(
    -+                com.android.internal.R.array.config_nonBlockableNotificationPackages));
    -     }
    - 
    -     protected void notifyUserAboutHiddenNotifications() {
    -@@ -1104,7 +1112,8 @@ public abstract class BaseStatusBar extends SystemUI implements
    -             settingsButton.setVisibility(View.GONE);
    -         }
    - 
    --        guts.bindImportance(pmUser, sbn, mNotificationData.getImportance(sbn.getKey()));
    -+        guts.bindImportance(pmUser, sbn, mNonBlockablePkgs,
    -+                mNotificationData.getImportance(sbn.getKey()));
    - 
    -         final TextView doneButton = (TextView) guts.findViewById(R.id.done);
    -         doneButton.setText(R.string.notification_done);
    -@@ -1697,6 +1706,23 @@ public abstract class BaseStatusBar extends SystemUI implements
    -                         sbn.getPackageContext(mContext),
    -                         contentContainerPublic, mOnClickHandler);
    -             }
    -+
    -+            if (contentViewLocal != null) {
    -+                contentViewLocal.setIsRootNamespace(true);
    -+                contentContainer.setContractedChild(contentViewLocal);
    -+            }
    -+            if (bigContentViewLocal != null) {
    -+                bigContentViewLocal.setIsRootNamespace(true);
    -+                contentContainer.setExpandedChild(bigContentViewLocal);
    -+            }
    -+            if (headsUpContentViewLocal != null) {
    -+                headsUpContentViewLocal.setIsRootNamespace(true);
    -+                contentContainer.setHeadsUpChild(headsUpContentViewLocal);
    -+            }
    -+            if (publicViewLocal != null) {
    -+                publicViewLocal.setIsRootNamespace(true);
    -+                contentContainerPublic.setContractedChild(publicViewLocal);
    -+            }
    -         }
    -         catch (RuntimeException e) {
    -             final String ident = sbn.getPackageName() + "/0x" + Integer.toHexString(sbn.getId());
    -@@ -1704,23 +1730,6 @@ public abstract class BaseStatusBar extends SystemUI implements
    -             return false;
    -         }
    - 
    --        if (contentViewLocal != null) {
    --            contentViewLocal.setIsRootNamespace(true);
    --            contentContainer.setContractedChild(contentViewLocal);
    --        }
    --        if (bigContentViewLocal != null) {
    --            bigContentViewLocal.setIsRootNamespace(true);
    --            contentContainer.setExpandedChild(bigContentViewLocal);
    --        }
    --        if (headsUpContentViewLocal != null) {
    --            headsUpContentViewLocal.setIsRootNamespace(true);
    --            contentContainer.setHeadsUpChild(headsUpContentViewLocal);
    --        }
    --        if (publicViewLocal != null) {
    --            publicViewLocal.setIsRootNamespace(true);
    --            contentContainerPublic.setContractedChild(publicViewLocal);
    --        }
    --
    -         // Extract target SDK version.
    -         try {
    -             ApplicationInfo info = pmUser.getApplicationInfo(sbn.getPackageName(), 0);
    -@@ -1944,9 +1953,18 @@ public abstract class BaseStatusBar extends SystemUI implements
    -                                             .getIdentifier();
    -                                     if (mLockPatternUtils.isSeparateProfileChallengeEnabled(userId)
    -                                             && mKeyguardManager.isDeviceLocked(userId)) {
    --                                        if (startWorkChallengeIfNecessary(userId,
    --                                                intent.getIntentSender(), notificationKey)) {
    --                                            // Show work challenge, do not run pendingintent and
    -+                                        boolean canBypass = false;
    -+                                        try {
    -+                                            canBypass = ActivityManagerNative.getDefault()
    -+                                                    .canBypassWorkChallenge(intent);
    -+                                        } catch (RemoteException e) {
    -+                                        }
    -+                                        // For direct-boot aware activities, they can be shown when
    -+                                        // the device is still locked without triggering the work
    -+                                        // challenge.
    -+                                        if ((!canBypass) && startWorkChallengeIfNecessary(userId,
    -+                                                    intent.getIntentSender(), notificationKey)) {
    -+                                            // Show work challenge, do not run PendingIntent and
    -                                             // remove notification
    -                                             return;
    -                                         }
    -diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/CrossFadeHelper.java b/packages/SystemUI/src/com/android/systemui/statusbar/CrossFadeHelper.java
    -index 123dc69..e8f0925 100644
    ---- a/packages/SystemUI/src/com/android/systemui/statusbar/CrossFadeHelper.java
    -+++ b/packages/SystemUI/src/com/android/systemui/statusbar/CrossFadeHelper.java
    -@@ -48,13 +48,30 @@ public class CrossFadeHelper {
    -     }
    - 
    -     public static void fadeOut(View view, float fadeOutAmount) {
    -+        fadeOut(view, fadeOutAmount, true /* remap */);
    -+    }
    -+
    -+    /**
    -+     * Fade out a view by a given progress amount
    -+     * @param view the view to fade out
    -+     * @param fadeOutAmount how much the view is faded out. 0 means not at all and 1 means fully
    -+     *                      faded out
    -+     * @param remap whether the fade amount should be remapped to the shorter duration
    -+     * {@link #ANIMATION_DURATION_LENGTH} from the normal fade duration
    -+     * {@link StackStateAnimator#ANIMATION_DURATION_STANDARD} in order to have a faster fading.
    -+     *
    -+     * @see #fadeIn(View, float, boolean)
    -+     */
    -+    public static void fadeOut(View view, float fadeOutAmount, boolean remap) {
    -         view.animate().cancel();
    -         if (fadeOutAmount == 1.0f) {
    -             view.setVisibility(View.INVISIBLE);
    -         } else if (view.getVisibility() == View.INVISIBLE) {
    -             view.setVisibility(View.VISIBLE);
    -         }
    --        fadeOutAmount = mapToFadeDuration(fadeOutAmount);
    -+        if (remap) {
    -+            fadeOutAmount = mapToFadeDuration(fadeOutAmount);
    -+        }
    -         float alpha = Interpolators.ALPHA_OUT.getInterpolation(1.0f - fadeOutAmount);
    -         view.setAlpha(alpha);
    -         updateLayerType(view, alpha);
    -@@ -92,11 +109,28 @@ public class CrossFadeHelper {
    -     }
    - 
    -     public static void fadeIn(View view, float fadeInAmount) {
    -+        fadeIn(view, fadeInAmount, true /* remap */);
    -+    }
    -+
    -+    /**
    -+     * Fade in a view by a given progress amount
    -+     * @param view the view to fade in
    -+     * @param fadeInAmount how much the view is faded in. 0 means not at all and 1 means fully
    -+     *                     faded in.
    -+     * @param remap whether the fade amount should be remapped to the shorter duration
    -+     * {@link #ANIMATION_DURATION_LENGTH} from the normal fade duration
    -+     * {@link StackStateAnimator#ANIMATION_DURATION_STANDARD} in order to have a faster fading.
    -+     *
    -+     * @see #fadeOut(View, float, boolean)
    -+     */
    -+    public static void fadeIn(View view, float fadeInAmount, boolean remap) {
    -         view.animate().cancel();
    -         if (view.getVisibility() == View.INVISIBLE) {
    -             view.setVisibility(View.VISIBLE);
    -         }
    --        fadeInAmount = mapToFadeDuration(fadeInAmount);
    -+        if (remap) {
    -+            fadeInAmount = mapToFadeDuration(fadeInAmount);
    -+        }
    -         float alpha = Interpolators.ALPHA_IN.getInterpolation(fadeInAmount);
    -         view.setAlpha(alpha);
    -         updateLayerType(view, alpha);
    -diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/DismissView.java b/packages/SystemUI/src/com/android/systemui/statusbar/DismissView.java
    -index 2045ec8..1d7bede 100644
    ---- a/packages/SystemUI/src/com/android/systemui/statusbar/DismissView.java
    -+++ b/packages/SystemUI/src/com/android/systemui/statusbar/DismissView.java
    -@@ -56,6 +56,8 @@ public class DismissView extends StackScrollerDecorView {
    -     protected void onConfigurationChanged(Configuration newConfig) {
    -         super.onConfigurationChanged(newConfig);
    -         mDismissButton.setText(R.string.clear_all_notifications_text);
    -+        mDismissButton.setContentDescription(
    -+                mContext.getString(R.string.accessibility_clear_all));
    -     }
    - 
    -     public boolean isButtonVisible() {
    -diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
    -index 02fdd3f..caf5447 100644
    ---- a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
    -+++ b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
    -@@ -507,7 +507,7 @@ public class ExpandableNotificationRow extends ActivatableNotificationView {
    -         int intrinsicHeight = getIntrinsicHeight();
    -         mIsPinned = pinned;
    -         if (intrinsicHeight != getIntrinsicHeight()) {
    --            notifyHeightChanged(false);
    -+            notifyHeightChanged(false /* needsAnimation */);
    -         }
    -         if (pinned) {
    -             setIconAnimationRunning(true);
    -@@ -840,8 +840,6 @@ public class ExpandableNotificationRow extends ActivatableNotificationView {
    -     }
    - 
    -     public void resetHeight() {
    --        mMaxExpandHeight = 0;
    --        mHeadsUpHeight = 0;
    -         onHeightReset();
    -         requestLayout();
    -     }
    -@@ -907,6 +905,9 @@ public class ExpandableNotificationRow extends ActivatableNotificationView {
    -     }
    - 
    -     public void resetTranslation() {
    -+        if (mTranslateAnim != null) {
    -+            mTranslateAnim.cancel();
    -+        }
    -         if (mTranslateableViews != null) {
    -             for (int i = 0; i < mTranslateableViews.size(); i++) {
    -                 mTranslateableViews.get(i).setTranslationX(0);
    -@@ -1290,7 +1291,7 @@ public class ExpandableNotificationRow extends ActivatableNotificationView {
    -         }
    -         mHeadsUpHeight = headsUpChild.getHeight();
    -         if (intrinsicBefore != getIntrinsicHeight()) {
    --            notifyHeightChanged(false  /* needsAnimation */);
    -+            notifyHeightChanged(true  /* needsAnimation */);
    -         }
    -     }
    - 
    -@@ -1398,7 +1399,7 @@ public class ExpandableNotificationRow extends ActivatableNotificationView {
    -         if (isChildInGroup()) {
    -             mGroupManager.setGroupExpanded(mStatusBarNotification, true);
    -         }
    --        notifyHeightChanged(false);
    -+        notifyHeightChanged(false /* needsAnimation */);
    -     }
    - 
    -     public void setChildrenExpanded(boolean expanded, boolean animate) {
    -diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardAffordanceView.java b/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardAffordanceView.java
    -index 88f37a3..8b4225a 100644
    ---- a/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardAffordanceView.java
    -+++ b/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardAffordanceView.java
    -@@ -174,7 +174,10 @@ public class KeyguardAffordanceView extends ImageView {
    - 
    -     private void drawBackgroundCircle(Canvas canvas) {
    -         if (mCircleRadius > 0 || mFinishing) {
    --            if (mFinishing && mSupportHardware) {
    -+            if (mFinishing && mSupportHardware && mHwCenterX != null) {
    -+                // Our hardware drawing proparties can be null if the finishing started but we have
    -+                // never drawn before. In that case we are not doing a render thread animation
    -+                // anyway, so we need to use the normal drawing.
    -                 DisplayListCanvas displayListCanvas = (DisplayListCanvas) canvas;
    -                 displayListCanvas.drawCircle(mHwCenterX, mHwCenterY, mHwCircleRadius,
    -                         mHwCirclePaint);
    -diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java b/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java
    -index 6d73ccb..0ef97152 100644
    ---- a/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java
    -+++ b/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java
    -@@ -93,7 +93,7 @@ public class KeyguardIndicationController {
    -                 ServiceManager.getService(BatteryStats.SERVICE_NAME));
    - 
    -         KeyguardUpdateMonitor.getInstance(context).registerCallback(mUpdateMonitor);
    --        context.registerReceiverAsUser(mReceiver, UserHandle.SYSTEM,
    -+        context.registerReceiverAsUser(mTickReceiver, UserHandle.SYSTEM,
    -                 new IntentFilter(Intent.ACTION_TIME_TICK), null, null);
    -     }
    - 
    -@@ -320,9 +320,16 @@ public class KeyguardIndicationController {
    -             super.onFingerprintAuthFailed();
    -             mLastSuccessiveErrorMessage = -1;
    -         }
    -+
    -+        @Override
    -+        public void onUserUnlocked() {
    -+            if (mVisible) {
    -+                updateIndication();
    -+            }
    -+        }
    -     };
    - 
    --    BroadcastReceiver mReceiver = new BroadcastReceiver() {
    -+    BroadcastReceiver mTickReceiver = new BroadcastReceiver() {
    -         @Override
    -         public void onReceive(Context context, Intent intent) {
    -             if (mVisible) {
    -@@ -331,6 +338,7 @@ public class KeyguardIndicationController {
    -         }
    -     };
    - 
    -+
    -     private final Handler mHandler = new Handler() {
    -         @Override
    -         public void handleMessage(Message msg) {
    -diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationContentView.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationContentView.java
    -index 9fd09d9..58d57f6 100644
    ---- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationContentView.java
    -+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationContentView.java
    -@@ -116,6 +116,8 @@ public class NotificationContentView extends FrameLayout {
    -     private boolean mForceSelectNextLayout = true;
    -     private PendingIntent mPreviousExpandedRemoteInputIntent;
    -     private PendingIntent mPreviousHeadsUpRemoteInputIntent;
    -+    private RemoteInputView mCachedExpandedRemoteInput;
    -+    private RemoteInputView mCachedHeadsUpRemoteInput;
    - 
    -     private int mContentHeightAtAnimationStart = UNDEFINED;
    -     private boolean mFocusOnVisibilityChange;
    -@@ -205,7 +207,7 @@ public class NotificationContentView extends FrameLayout {
    -                     && MeasureSpec.getMode(widthMeasureSpec) != MeasureSpec.UNSPECIFIED) {
    -                 singleLineWidthSpec = MeasureSpec.makeMeasureSpec(
    -                         width - mSingleLineWidthIndention + mSingleLineView.getPaddingEnd(),
    --                        MeasureSpec.AT_MOST);
    -+                        MeasureSpec.EXACTLY);
    -             }
    -             mSingleLineView.measure(singleLineWidthSpec,
    -                     MeasureSpec.makeMeasureSpec(maxSize, MeasureSpec.AT_MOST));
    -@@ -298,6 +300,9 @@ public class NotificationContentView extends FrameLayout {
    -             mExpandedRemoteInput.onNotificationUpdateOrReset();
    -             if (mExpandedRemoteInput.isActive()) {
    -                 mPreviousExpandedRemoteInputIntent = mExpandedRemoteInput.getPendingIntent();
    -+                mCachedExpandedRemoteInput = mExpandedRemoteInput;
    -+                mExpandedRemoteInput.dispatchStartTemporaryDetach();
    -+                ((ViewGroup)mExpandedRemoteInput.getParent()).removeView(mExpandedRemoteInput);
    -             }
    -         }
    -         if (mExpandedChild != null) {
    -@@ -310,6 +315,9 @@ public class NotificationContentView extends FrameLayout {
    -             mHeadsUpRemoteInput.onNotificationUpdateOrReset();
    -             if (mHeadsUpRemoteInput.isActive()) {
    -                 mPreviousHeadsUpRemoteInputIntent = mHeadsUpRemoteInput.getPendingIntent();
    -+                mCachedHeadsUpRemoteInput = mHeadsUpRemoteInput;
    -+                mHeadsUpRemoteInput.dispatchStartTemporaryDetach();
    -+                ((ViewGroup)mHeadsUpRemoteInput.getParent()).removeView(mHeadsUpRemoteInput);
    -             }
    -         }
    -         if (mHeadsUpChild != null) {
    -@@ -963,22 +971,35 @@ public class NotificationContentView extends FrameLayout {
    -         View bigContentView = mExpandedChild;
    -         if (bigContentView != null) {
    -             mExpandedRemoteInput = applyRemoteInput(bigContentView, entry, hasRemoteInput,
    --                    mPreviousExpandedRemoteInputIntent);
    -+                    mPreviousExpandedRemoteInputIntent, mCachedExpandedRemoteInput);
    -         } else {
    -             mExpandedRemoteInput = null;
    -         }
    -+        if (mCachedExpandedRemoteInput != null
    -+                && mCachedExpandedRemoteInput != mExpandedRemoteInput) {
    -+            // We had a cached remote input but didn't reuse it. Clean up required.
    -+            mCachedExpandedRemoteInput.dispatchFinishTemporaryDetach();
    -+        }
    -+        mCachedExpandedRemoteInput = null;
    - 
    -         View headsUpContentView = mHeadsUpChild;
    -         if (headsUpContentView != null) {
    -             mHeadsUpRemoteInput = applyRemoteInput(headsUpContentView, entry, hasRemoteInput,
    --                    mPreviousHeadsUpRemoteInputIntent);
    -+                    mPreviousHeadsUpRemoteInputIntent, mCachedHeadsUpRemoteInput);
    -         } else {
    -             mHeadsUpRemoteInput = null;
    -         }
    -+        if (mCachedHeadsUpRemoteInput != null
    -+                && mCachedHeadsUpRemoteInput != mHeadsUpRemoteInput) {
    -+            // We had a cached remote input but didn't reuse it. Clean up required.
    -+            mCachedHeadsUpRemoteInput.dispatchFinishTemporaryDetach();
    -+        }
    -+        mCachedHeadsUpRemoteInput = null;
    -     }
    - 
    -     private RemoteInputView applyRemoteInput(View view, NotificationData.Entry entry,
    --            boolean hasRemoteInput, PendingIntent existingPendingIntent) {
    -+            boolean hasRemoteInput, PendingIntent existingPendingIntent,
    -+            RemoteInputView cachedView) {
    -         View actionContainerCandidate = view.findViewById(
    -                 com.android.internal.R.id.actions_container);
    -         if (actionContainerCandidate instanceof FrameLayout) {
    -@@ -991,15 +1012,22 @@ public class NotificationContentView extends FrameLayout {
    - 
    -             if (existing == null && hasRemoteInput) {
    -                 ViewGroup actionContainer = (FrameLayout) actionContainerCandidate;
    --                RemoteInputView riv = RemoteInputView.inflate(
    --                        mContext, actionContainer, entry, mRemoteInputController);
    --
    --                riv.setVisibility(View.INVISIBLE);
    --                actionContainer.addView(riv, new LayoutParams(
    --                        ViewGroup.LayoutParams.MATCH_PARENT,
    --                        ViewGroup.LayoutParams.MATCH_PARENT)
    --                );
    --                existing = riv;
    -+                if (cachedView == null) {
    -+                    RemoteInputView riv = RemoteInputView.inflate(
    -+                            mContext, actionContainer, entry, mRemoteInputController);
    -+
    -+                    riv.setVisibility(View.INVISIBLE);
    -+                    actionContainer.addView(riv, new LayoutParams(
    -+                            ViewGroup.LayoutParams.MATCH_PARENT,
    -+                            ViewGroup.LayoutParams.MATCH_PARENT)
    -+                    );
    -+                    existing = riv;
    -+                } else {
    -+                    actionContainer.addView(cachedView);
    -+                    cachedView.dispatchFinishTemporaryDetach();
    -+                    cachedView.requestFocus();
    -+                    existing = cachedView;
    -+                }
    -             }
    -             if (hasRemoteInput) {
    -                 int color = entry.notification.getNotification().color;
    -diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationGuts.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationGuts.java
    -index c497cfd..1829e59 100644
    ---- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationGuts.java
    -+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationGuts.java
    -@@ -50,6 +50,8 @@ import com.android.systemui.R;
    - import com.android.systemui.statusbar.stack.StackStateAnimator;
    - import com.android.systemui.tuner.TunerService;
    - 
    -+import java.util.Set;
    -+
    - /**
    -  * The guts of a notification revealed when performing a long press.
    -  */
    -@@ -173,7 +175,7 @@ public class NotificationGuts extends LinearLayout implements TunerService.Tunab
    -     }
    - 
    -     void bindImportance(final PackageManager pm, final StatusBarNotification sbn,
    --            final int importance) {
    -+            final Set<String> nonBlockablePkgs, final int importance) {
    -         mINotificationManager = INotificationManager.Stub.asInterface(
    -                 ServiceManager.getService(Context.NOTIFICATION_SERVICE));
    -         mStartingUserImportance = NotificationListenerService.Ranking.IMPORTANCE_UNSPECIFIED;
    -@@ -182,26 +184,38 @@ public class NotificationGuts extends LinearLayout implements TunerService.Tunab
    -                     mINotificationManager.getImportance(sbn.getPackageName(), sbn.getUid());
    -         } catch (RemoteException e) {}
    -         mNotificationImportance = importance;
    --        boolean systemApp = false;
    --        try {
    --            final PackageInfo info =
    --                    pm.getPackageInfo(sbn.getPackageName(), PackageManager.GET_SIGNATURES);
    --            systemApp = Utils.isSystemPackage(getResources(), pm, info);
    --        } catch (PackageManager.NameNotFoundException e) {
    --            // unlikely.
    --        }
    - 
    -         final View importanceSlider = findViewById(R.id.importance_slider);
    -         final View importanceButtons = findViewById(R.id.importance_buttons);
    --        if (mShowSlider) {
    --            bindSlider(importanceSlider, systemApp);
    --            importanceSlider.setVisibility(View.VISIBLE);
    -+        final View cantTouchThis = findViewById(R.id.cant_silence_or_block);
    -+
    -+        final boolean essentialPackage =
    -+                (nonBlockablePkgs != null && nonBlockablePkgs.contains(sbn.getPackageName()));
    -+        if (essentialPackage) {
    -             importanceButtons.setVisibility(View.GONE);
    -+            importanceSlider.setVisibility(View.GONE);
    -+            cantTouchThis.setVisibility(View.VISIBLE);
    -         } else {
    -+            cantTouchThis.setVisibility(View.GONE);
    -+
    -+            boolean nonBlockable = false;
    -+            try {
    -+                final PackageInfo info =
    -+                        pm.getPackageInfo(sbn.getPackageName(), PackageManager.GET_SIGNATURES);
    -+                nonBlockable = Utils.isSystemPackage(getResources(), pm, info);
    -+            } catch (PackageManager.NameNotFoundException e) {
    -+                // unlikely.
    -+            }
    - 
    --            bindToggles(importanceButtons, mStartingUserImportance, systemApp);
    --            importanceButtons.setVisibility(View.VISIBLE);
    --            importanceSlider.setVisibility(View.GONE);
    -+            if (mShowSlider) {
    -+                bindSlider(importanceSlider, nonBlockable);
    -+                importanceSlider.setVisibility(View.VISIBLE);
    -+                importanceButtons.setVisibility(View.GONE);
    -+            } else {
    -+                bindToggles(importanceButtons, mStartingUserImportance, nonBlockable);
    -+                importanceButtons.setVisibility(View.VISIBLE);
    -+                importanceSlider.setVisibility(View.GONE);
    -+            }
    -         }
    -     }
    - 
    -@@ -221,16 +235,16 @@ public class NotificationGuts extends LinearLayout implements TunerService.Tunab
    -     }
    - 
    -     private int getSelectedImportance() {
    --        if (mSeekBar!= null && mSeekBar.isShown()) {
    -+        if (mSeekBar != null && mSeekBar.isShown()) {
    -             if (mSeekBar.isEnabled()) {
    -                 return mSeekBar.getProgress();
    -             } else {
    -                 return Ranking.IMPORTANCE_UNSPECIFIED;
    -             }
    -         } else {
    --            if (mBlock.isChecked()) {
    -+            if (mBlock != null && mBlock.isChecked()) {
    -                 return Ranking.IMPORTANCE_NONE;
    --            } else if (mSilent.isChecked()) {
    -+            } else if (mSilent != null && mSilent.isChecked()) {
    -                 return Ranking.IMPORTANCE_LOW;
    -             } else {
    -                 return Ranking.IMPORTANCE_UNSPECIFIED;
    -@@ -239,7 +253,7 @@ public class NotificationGuts extends LinearLayout implements TunerService.Tunab
    -     }
    - 
    -     private void bindToggles(final View importanceButtons, final int importance,
    --            final boolean systemApp) {
    -+            final boolean nonBlockable) {
    -         ((RadioGroup) importanceButtons).setOnCheckedChangeListener(
    -                 new RadioGroup.OnCheckedChangeListener() {
    -                     @Override
    -@@ -250,7 +264,7 @@ public class NotificationGuts extends LinearLayout implements TunerService.Tunab
    -         mBlock = (RadioButton) importanceButtons.findViewById(R.id.block_importance);
    -         mSilent = (RadioButton) importanceButtons.findViewById(R.id.silent_importance);
    -         mReset = (RadioButton) importanceButtons.findViewById(R.id.reset_importance);
    --        if (systemApp) {
    -+        if (nonBlockable) {
    -             mBlock.setVisibility(View.GONE);
    -             mReset.setText(mContext.getString(R.string.do_not_silence));
    -         } else {
    -@@ -265,7 +279,7 @@ public class NotificationGuts extends LinearLayout implements TunerService.Tunab
    -         }
    -     }
    - 
    --    private void bindSlider(final View importanceSlider, final boolean systemApp) {
    -+    private void bindSlider(final View importanceSlider, final boolean nonBlockable) {
    -         mActiveSliderTint = ColorStateList.valueOf(Utils.getColorAccent(mContext));
    -         mInactiveSliderTint = loadColorStateList(R.color.notification_guts_disabled_slider_color);
    - 
    -@@ -273,7 +287,7 @@ public class NotificationGuts extends LinearLayout implements TunerService.Tunab
    -         mImportanceTitle = ((TextView) importanceSlider.findViewById(R.id.title));
    -         mSeekBar = (SeekBar) importanceSlider.findViewById(R.id.seekbar);
    - 
    --        final int minProgress = systemApp ?
    -+        final int minProgress = nonBlockable ?
    -                 NotificationListenerService.Ranking.IMPORTANCE_MIN
    -                 : NotificationListenerService.Ranking.IMPORTANCE_NONE;
    -         mSeekBar.setMax(NotificationListenerService.Ranking.IMPORTANCE_MAX);
    -diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/RemoteInputController.java b/packages/SystemUI/src/com/android/systemui/statusbar/RemoteInputController.java
    -index 6cbacea..66cc15d 100644
    ---- a/packages/SystemUI/src/com/android/systemui/statusbar/RemoteInputController.java
    -+++ b/packages/SystemUI/src/com/android/systemui/statusbar/RemoteInputController.java
    -@@ -21,7 +21,9 @@ import com.android.systemui.statusbar.phone.StatusBarWindowManager;
    - import com.android.systemui.statusbar.policy.HeadsUpManager;
    - import com.android.systemui.statusbar.policy.RemoteInputView;
    - 
    -+import android.util.ArrayMap;
    - import android.util.ArraySet;
    -+import android.util.Pair;
    - 
    - import java.lang.ref.WeakReference;
    - import java.util.ArrayList;
    -@@ -31,8 +33,9 @@ import java.util.ArrayList;
    -  */
    - public class RemoteInputController {
    - 
    --    private final ArrayList<WeakReference<NotificationData.Entry>> mOpen = new ArrayList<>();
    --    private final ArraySet<String> mSpinning = new ArraySet<>();
    -+    private final ArrayList<Pair<WeakReference<NotificationData.Entry>, Object>> mOpen
    -+            = new ArrayList<>();
    -+    private final ArrayMap<String, Object> mSpinning = new ArrayMap<>();
    -     private final ArrayList<Callback> mCallbacks = new ArrayList<>(3);
    -     private final HeadsUpManager mHeadsUpManager;
    - 
    -@@ -41,36 +44,72 @@ public class RemoteInputController {
    -         mHeadsUpManager = headsUpManager;
    -     }
    - 
    --    public void addRemoteInput(NotificationData.Entry entry) {
    -+    /**
    -+     * Adds a currently active remote input.
    -+     *
    -+     * @param entry the entry for which a remote input is now active.
    -+     * @param token a token identifying the view that is managing the remote input
    -+     */
    -+    public void addRemoteInput(NotificationData.Entry entry, Object token) {
    -         Preconditions.checkNotNull(entry);
    -+        Preconditions.checkNotNull(token);
    - 
    -         boolean found = pruneWeakThenRemoveAndContains(
    --                entry /* contains */, null /* remove */);
    -+                entry /* contains */, null /* remove */, token /* removeToken */);
    -         if (!found) {
    --            mOpen.add(new WeakReference<>(entry));
    -+            mOpen.add(new Pair<>(new WeakReference<>(entry), token));
    -         }
    - 
    -         apply(entry);
    -     }
    - 
    --    public void removeRemoteInput(NotificationData.Entry entry) {
    -+    /**
    -+     * Removes a currently active remote input.
    -+     *
    -+     * @param entry the entry for which a remote input should be removed.
    -+     * @param token a token identifying the view that is requesting the removal. If non-null,
    -+     *              the entry is only removed if the token matches the last added token for this
    -+     *              entry. If null, the entry is removed regardless.
    -+     */
    -+    public void removeRemoteInput(NotificationData.Entry entry, Object token) {
    -         Preconditions.checkNotNull(entry);
    - 
    --        pruneWeakThenRemoveAndContains(null /* contains */, entry /* remove */);
    -+        pruneWeakThenRemoveAndContains(null /* contains */, entry /* remove */, token);
    - 
    -         apply(entry);
    -     }
    - 
    --    public void addSpinning(String key) {
    --        mSpinning.add(key);
    -+    /**
    -+     * Adds a currently spinning (i.e. sending) remote input.
    -+     *
    -+     * @param key the key of the entry that's spinning.
    -+     * @param token the token of the view managing the remote input.
    -+     */
    -+    public void addSpinning(String key, Object token) {
    -+        Preconditions.checkNotNull(key);
    -+        Preconditions.checkNotNull(token);
    -+
    -+        mSpinning.put(key, token);
    -     }
    - 
    --    public void removeSpinning(String key) {
    --        mSpinning.remove(key);
    -+    /**
    -+     * Removes a currently spinning remote input.
    -+     *
    -+     * @param key the key of the entry for which a remote input should be removed.
    -+     * @param token a token identifying the view that is requesting the removal. If non-null,
    -+     *              the entry is only removed if the token matches the last added token for this
    -+     *              entry. If null, the entry is removed regardless.
    -+     */
    -+    public void removeSpinning(String key, Object token) {
    -+        Preconditions.checkNotNull(key);
    -+
    -+        if (token == null || mSpinning.get(key) == token) {
    -+            mSpinning.remove(key);
    -+        }
    -     }
    - 
    -     public boolean isSpinning(String key) {
    --        return mSpinning.contains(key);
    -+        return mSpinning.containsKey(key);
    -     }
    - 
    -     private void apply(NotificationData.Entry entry) {
    -@@ -86,14 +125,16 @@ public class RemoteInputController {
    -      * @return true if {@param entry} has an active RemoteInput
    -      */
    -     public boolean isRemoteInputActive(NotificationData.Entry entry) {
    --        return pruneWeakThenRemoveAndContains(entry /* contains */, null /* remove */);
    -+        return pruneWeakThenRemoveAndContains(entry /* contains */, null /* remove */,
    -+                null /* removeToken */);
    -     }
    - 
    -     /**
    -      * @return true if any entry has an active RemoteInput
    -      */
    -     public boolean isRemoteInputActive() {
    --        pruneWeakThenRemoveAndContains(null /* contains */, null /* remove */);
    -+        pruneWeakThenRemoveAndContains(null /* contains */, null /* remove */,
    -+                null /* removeToken */);
    -         return !mOpen.isEmpty();
    -     }
    - 
    -@@ -101,17 +142,27 @@ public class RemoteInputController {
    -      * Prunes dangling weak references, removes entries referring to {@param remove} and returns
    -      * whether {@param contains} is part of the array in a single loop.
    -      * @param remove if non-null, removes this entry from the active remote inputs
    -+     * @param removeToken if non-null, only removes an entry if this matches the token when the
    -+     *                    entry was added.
    -      * @return true if {@param contains} is in the set of active remote inputs
    -      */
    -     private boolean pruneWeakThenRemoveAndContains(
    --            NotificationData.Entry contains, NotificationData.Entry remove) {
    -+            NotificationData.Entry contains, NotificationData.Entry remove, Object removeToken) {
    -         boolean found = false;
    -         for (int i = mOpen.size() - 1; i >= 0; i--) {
    --            NotificationData.Entry item = mOpen.get(i).get();
    --            if (item == null || item == remove) {
    -+            NotificationData.Entry item = mOpen.get(i).first.get();
    -+            Object itemToken = mOpen.get(i).second;
    -+            boolean removeTokenMatches = (removeToken == null || itemToken == removeToken);
    -+
    -+            if (item == null || (item == remove && removeTokenMatches)) {
    -                 mOpen.remove(i);
    -             } else if (item == contains) {
    --                found = true;
    -+                if (removeToken != null && removeToken != itemToken) {
    -+                    // We need to update the token. Remove here and let caller reinsert it.
    -+                    mOpen.remove(i);
    -+                } else {
    -+                    found = true;
    -+                }
    -             }
    -         }
    -         return found;
    -@@ -138,7 +189,7 @@ public class RemoteInputController {
    -         // Make a copy because closing the remote inputs will modify mOpen.
    -         ArrayList<NotificationData.Entry> list = new ArrayList<>(mOpen.size());
    -         for (int i = mOpen.size() - 1; i >= 0; i--) {
    --            NotificationData.Entry item = mOpen.get(i).get();
    -+            NotificationData.Entry item = mOpen.get(i).first.get();
    -             if (item != null && item.row != null) {
    -                 list.add(item);
    -             }
    -diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/ViewTransformationHelper.java b/packages/SystemUI/src/com/android/systemui/statusbar/ViewTransformationHelper.java
    -index 1ff2b13..cd6c31f 100644
    ---- a/packages/SystemUI/src/com/android/systemui/statusbar/ViewTransformationHelper.java
    -+++ b/packages/SystemUI/src/com/android/systemui/statusbar/ViewTransformationHelper.java
    -@@ -116,8 +116,7 @@ public class ViewTransformationHelper implements TransformableView {
    -                     ownState.transformViewTo(otherState, transformationAmount);
    -                     otherState.recycle();
    -                 } else {
    --                    // there's no other view available
    --                    CrossFadeHelper.fadeOut(mTransformedViews.get(viewType), transformationAmount);
    -+                    ownState.disappear(transformationAmount, notification);
    -                 }
    -                 ownState.recycle();
    -             }
    -@@ -174,13 +173,7 @@ public class ViewTransformationHelper implements TransformableView {
    -                     ownState.transformViewFrom(otherState, transformationAmount);
    -                     otherState.recycle();
    -                 } else {
    --                    // There's no other view, lets fade us in
    --                    // Certain views need to prepare the fade in and make sure its children are
    --                    // completely visible. An example is the notification header.
    --                    if (transformationAmount == 0.0f) {
    --                        ownState.prepareFadeIn();
    --                    }
    --                    CrossFadeHelper.fadeIn(mTransformedViews.get(viewType), transformationAmount);
    -+                    ownState.appear(transformationAmount, notification);
    -                 }
    -                 ownState.recycle();
    -             }
    -diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/ImageTransformState.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/ImageTransformState.java
    -index 45027c0..e6b3fb8 100644
    ---- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/ImageTransformState.java
    -+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/ImageTransformState.java
    -@@ -21,12 +21,17 @@ import android.util.Pools;
    - import android.view.View;
    - import android.widget.ImageView;
    - 
    -+import com.android.systemui.Interpolators;
    - import com.android.systemui.R;
    -+import com.android.systemui.statusbar.CrossFadeHelper;
    -+import com.android.systemui.statusbar.TransformableView;
    -+import com.android.systemui.statusbar.stack.StackStateAnimator;
    - 
    - /**
    -  * A transform state of a image view.
    - */
    - public class ImageTransformState extends TransformState {
    -+    public static final long ANIMATION_DURATION_LENGTH = 210;
    - 
    -     public static final int ICON_TAG = R.id.image_icon_tag;
    -     private static Pools.SimplePool<ImageTransformState> sInstancePool
    -@@ -49,6 +54,52 @@ public class ImageTransformState extends TransformState {
    -         return super.sameAs(otherState);
    -     }
    - 
    -+    @Override
    -+    public void appear(float transformationAmount, TransformableView otherView) {
    -+        if (otherView instanceof HybridNotificationView) {
    -+            if (transformationAmount == 0.0f) {
    -+                mTransformedView.setPivotY(0);
    -+                mTransformedView.setPivotX(mTransformedView.getWidth() / 2);
    -+                prepareFadeIn();
    -+            }
    -+            transformationAmount = mapToDuration(transformationAmount);
    -+            CrossFadeHelper.fadeIn(mTransformedView, transformationAmount, false /* remap */);
    -+            transformationAmount = Interpolators.LINEAR_OUT_SLOW_IN.getInterpolation(
    -+                    transformationAmount);
    -+            mTransformedView.setScaleX(transformationAmount);
    -+            mTransformedView.setScaleY(transformationAmount);
    -+        } else {
    -+            super.appear(transformationAmount, otherView);
    -+        }
    -+    }
    -+
    -+    @Override
    -+    public void disappear(float transformationAmount, TransformableView otherView) {
    -+        if (otherView instanceof HybridNotificationView) {
    -+            if (transformationAmount == 0.0f) {
    -+                mTransformedView.setPivotY(0);
    -+                mTransformedView.setPivotX(mTransformedView.getWidth() / 2);
    -+            }
    -+            transformationAmount = mapToDuration(1.0f - transformationAmount);
    -+            CrossFadeHelper.fadeOut(mTransformedView, 1.0f - transformationAmount,
    -+                    false /* remap */);
    -+            transformationAmount = Interpolators.LINEAR_OUT_SLOW_IN.getInterpolation(
    -+                    transformationAmount);
    -+            mTransformedView.setScaleX(transformationAmount);
    -+            mTransformedView.setScaleY(transformationAmount);
    -+        } else {
    -+            super.disappear(transformationAmount, otherView);
    -+        }
    -+    }
    -+
    -+    private static float mapToDuration(float scaleAmount) {
    -+        // Assuming a linear interpolator, we can easily map it to our new duration
    -+        scaleAmount = (scaleAmount * StackStateAnimator.ANIMATION_DURATION_STANDARD
    -+                - (StackStateAnimator.ANIMATION_DURATION_STANDARD - ANIMATION_DURATION_LENGTH))
    -+                        / ANIMATION_DURATION_LENGTH;
    -+        return Math.max(Math.min(scaleAmount, 1.0f), 0.0f);
    -+    }
    -+
    -     public Icon getIcon() {
    -         return mIcon;
    -     }
    -diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/TransformState.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/TransformState.java
    -index f0f5c8d..770ec95 100644
    ---- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/TransformState.java
    -+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/TransformState.java
    -@@ -30,6 +30,7 @@ import com.android.systemui.Interpolators;
    - import com.android.systemui.R;
    - import com.android.systemui.statusbar.CrossFadeHelper;
    - import com.android.systemui.statusbar.ExpandableNotificationRow;
    -+import com.android.systemui.statusbar.TransformableView;
    - import com.android.systemui.statusbar.ViewTransformationHelper;
    - 
    - /**
    -@@ -357,6 +358,7 @@ public class TransformState {
    - 
    -     public int[] getLaidOutLocationOnScreen() {
    -         int[] location = getLocationOnScreen();
    -+        // remove translation
    -         location[0] -= mTransformedView.getTranslationX();
    -         location[1] -= mTransformedView.getTranslationY();
    -         return location;
    -@@ -364,6 +366,10 @@ public class TransformState {
    - 
    -     public int[] getLocationOnScreen() {
    -         mTransformedView.getLocationOnScreen(mOwnPosition);
    -+
    -+        // remove scale
    -+        mOwnPosition[0] -= (1.0f - mTransformedView.getScaleX()) * mTransformedView.getPivotX();
    -+        mOwnPosition[1] -= (1.0f - mTransformedView.getScaleY()) * mTransformedView.getPivotY();
    -         return mOwnPosition;
    -     }
    - 
    -@@ -371,6 +377,20 @@ public class TransformState {
    -         return false;
    -     }
    - 
    -+    public void appear(float transformationAmount, TransformableView otherView) {
    -+        // There's no other view, lets fade us in
    -+        // Certain views need to prepare the fade in and make sure its children are
    -+        // completely visible. An example is the notification header.
    -+        if (transformationAmount == 0.0f) {
    -+            prepareFadeIn();
    -+        }
    -+        CrossFadeHelper.fadeIn(mTransformedView, transformationAmount);
    -+    }
    -+
    -+    public void disappear(float transformationAmount, TransformableView otherView) {
    -+        CrossFadeHelper.fadeOut(mTransformedView, transformationAmount);
    -+    }
    -+
    -     public static TransformState createFrom(View view) {
    -         if (view instanceof TextView) {
    -             TextViewTransformState result = TextViewTransformState.obtain();
    -diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeParameters.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeParameters.java
    -index efceed1..9e9bdd7 100644
    ---- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeParameters.java
    -+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeParameters.java
    -@@ -18,11 +18,13 @@ package com.android.systemui.statusbar.phone;
    - 
    - import android.content.Context;
    - import android.os.SystemProperties;
    -+import android.os.UserHandle;
    - import android.text.TextUtils;
    - import android.util.Log;
    - import android.util.MathUtils;
    - import android.util.SparseBooleanArray;
    - 
    -+import com.android.internal.hardware.AmbientDisplayConfiguration;
    - import com.android.systemui.R;
    - 
    - import java.io.PrintWriter;
    -@@ -31,9 +33,6 @@ import java.util.regex.Matcher;
    - import java.util.regex.Pattern;
    - 
    - public class DozeParameters {
    --    private static final String TAG = "DozeParameters";
    --    private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
    --
    -     private static final int MAX_DURATION = 60 * 1000;
    - 
    -     private final Context mContext;
    -@@ -55,10 +54,8 @@ public class DozeParameters {
    -         pw.print("    getPulseOutDuration(): "); pw.println(getPulseOutDuration());
    -         pw.print("    getPulseOnSigMotion(): "); pw.println(getPulseOnSigMotion());
    -         pw.print("    getVibrateOnSigMotion(): "); pw.println(getVibrateOnSigMotion());
    --        pw.print("    getPulseOnPickup(): "); pw.println(getPulseOnPickup());
    -         pw.print("    getVibrateOnPickup(): "); pw.println(getVibrateOnPickup());
    -         pw.print("    getProxCheckBeforePulse(): "); pw.println(getProxCheckBeforePulse());
    --        pw.print("    getPulseOnNotifications(): "); pw.println(getPulseOnNotifications());
    -         pw.print("    getPickupVibrationThreshold(): "); pw.println(getPickupVibrationThreshold());
    -         pw.print("    getPickupSubtypePerformsProxCheck(): ");pw.println(
    -                 dumpPickupSubtypePerformsProxCheck());
    -@@ -84,8 +81,8 @@ public class DozeParameters {
    -         return getPulseInDuration(pickup) + getPulseVisibleDuration() + getPulseOutDuration();
    -     }
    - 
    --    public int getPulseInDuration(boolean pickup) {
    --        return pickup
    -+    public int getPulseInDuration(boolean pickupOrDoubleTap) {
    -+        return pickupOrDoubleTap
    -                 ? getInt("doze.pulse.duration.in.pickup", R.integer.doze_pulse_duration_in_pickup)
    -                 : getInt("doze.pulse.duration.in", R.integer.doze_pulse_duration_in);
    -     }
    -@@ -106,10 +103,6 @@ public class DozeParameters {
    -         return SystemProperties.getBoolean("doze.vibrate.sigmotion", false);
    -     }
    - 
    --    public boolean getPulseOnPickup() {
    --        return getBoolean("doze.pulse.pickup", R.bool.doze_pulse_on_pick_up);
    --    }
    --
    -     public boolean getVibrateOnPickup() {
    -         return SystemProperties.getBoolean("doze.vibrate.pickup", false);
    -     }
    -@@ -118,10 +111,6 @@ public class DozeParameters {
    -         return getBoolean("doze.pulse.proxcheck", R.bool.doze_proximity_check_before_pulse);
    -     }
    - 
    --    public boolean getPulseOnNotifications() {
    --        return getBoolean("doze.pulse.notifications", R.bool.doze_pulse_on_notifications);
    --    }
    --
    -     public int getPickupVibrationThreshold() {
    -         return getInt("doze.pickup.vibration.threshold", R.integer.doze_pickup_vibration_threshold);
    -     }
    -diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeScrimController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeScrimController.java
    -index 7d4515e..b44f5f7 100644
    ---- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeScrimController.java
    -+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeScrimController.java
    -@@ -109,10 +109,11 @@ public class DozeScrimController {
    - 
    -     public void onScreenTurnedOn() {
    -         if (isPulsing()) {
    --            final boolean pickup = mPulseReason == DozeLog.PULSE_REASON_SENSOR_PICKUP;
    -+            final boolean pickupOrDoubleTap = mPulseReason == DozeLog.PULSE_REASON_SENSOR_PICKUP
    -+                    || mPulseReason == DozeLog.PULSE_REASON_SENSOR_DOUBLE_TAP;
    -             startScrimAnimation(true /* inFront */, 0f,
    --                    mDozeParameters.getPulseInDuration(pickup),
    --                    pickup ? Interpolators.LINEAR_OUT_SLOW_IN : Interpolators.ALPHA_OUT,
    -+                    mDozeParameters.getPulseInDuration(pickupOrDoubleTap),
    -+                    pickupOrDoubleTap ? Interpolators.LINEAR_OUT_SLOW_IN : Interpolators.ALPHA_OUT,
    -                     mPulseInFinished);
    -         }
    -     }
    -diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java
    -index 8cabfb9..4d0e5d3 100644
    ---- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java
    -+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java
    -@@ -111,6 +111,7 @@ public class KeyguardBottomAreaView extends FrameLayout implements View.OnClickL
    -     private KeyguardIndicationController mIndicationController;
    -     private AccessibilityController mAccessibilityController;
    -     private PhoneStatusBar mPhoneStatusBar;
    -+    private KeyguardAffordanceHelper mAffordanceHelper;
    - 
    -     private boolean mUserSetupComplete;
    -     private boolean mPrewarmBound;
    -@@ -271,6 +272,10 @@ public class KeyguardBottomAreaView extends FrameLayout implements View.OnClickL
    -         updateCameraVisibility(); // in case onFinishInflate() was called too early
    -     }
    - 
    -+    public void setAffordanceHelper(KeyguardAffordanceHelper affordanceHelper) {
    -+        mAffordanceHelper = affordanceHelper;
    -+    }
    -+
    -     public void setUserSetupComplete(boolean userSetupComplete) {
    -         mUserSetupComplete = userSetupComplete;
    -         updateCameraVisibility();
    -@@ -601,6 +606,9 @@ public class KeyguardBottomAreaView extends FrameLayout implements View.OnClickL
    -             mPreviewContainer.addView(mCameraPreview);
    -             mCameraPreview.setVisibility(visibleBefore ? View.VISIBLE : View.INVISIBLE);
    -         }
    -+        if (mAffordanceHelper != null) {
    -+            mAffordanceHelper.updatePreviews();
    -+        }
    -     }
    - 
    -     private void updateLeftPreview() {
    -@@ -618,6 +626,9 @@ public class KeyguardBottomAreaView extends FrameLayout implements View.OnClickL
    -             mPreviewContainer.addView(mLeftPreview);
    -             mLeftPreview.setVisibility(View.INVISIBLE);
    -         }
    -+        if (mAffordanceHelper != null) {
    -+            mAffordanceHelper.updatePreviews();
    -+        }
    -     }
    - 
    -     public void startFinishDozeAnimation() {
    -@@ -702,6 +713,13 @@ public class KeyguardBottomAreaView extends FrameLayout implements View.OnClickL
    -         public void onStrongAuthStateChanged(int userId) {
    -             mLockIcon.update();
    -         }
    -+
    -+        @Override
    -+        public void onUserUnlocked() {
    -+            inflateCameraPreview();
    -+            updateCameraVisibility();
    -+            updateLeftAffordance();
    -+        }
    -     };
    - 
    -     public void setKeyguardIndicationController(
    -diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarView.java
    -index 93ed139..41b0bb2 100644
    ---- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarView.java
    -+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarView.java
    -@@ -308,6 +308,7 @@ public class KeyguardStatusBarView extends RelativeLayout
    -         super.setVisibility(visibility);
    -         if (visibility != View.VISIBLE) {
    -             mSystemIconsSuperContainer.animate().cancel();
    -+            mSystemIconsSuperContainer.setTranslationX(0);
    -             mMultiUserSwitch.animate().cancel();
    -             mMultiUserSwitch.setAlpha(1f);
    -         } else {
    -diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LightStatusBarController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LightStatusBarController.java
    -index f98b9e5..df4566b 100644
    ---- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LightStatusBarController.java
    -+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LightStatusBarController.java
    -@@ -27,7 +27,7 @@ import static com.android.systemui.statusbar.phone.BarTransitions.MODE_TRANSPARE
    - /**
    -  * Controls how light status bar flag applies to the icons.
    -  */
    --public class LightStatusBarController {
    -+public class LightStatusBarController implements BatteryController.BatteryStateChangeCallback {
    - 
    -     private final StatusBarIconController mIconController;
    -     private final BatteryController mBatteryController;
    -@@ -37,6 +37,7 @@ public class LightStatusBarController {
    -     private int mDockedStackVisibility;
    -     private boolean mFullscreenLight;
    -     private boolean mDockedLight;
    -+    private int mLastStatusBarMode;
    - 
    -     private final Rect mLastFullscreenBounds = new Rect();
    -     private final Rect mLastDockedBounds = new Rect();
    -@@ -45,6 +46,7 @@ public class LightStatusBarController {
    -             BatteryController batteryController) {
    -         mIconController = iconController;
    -         mBatteryController = batteryController;
    -+        batteryController.addStateChangedCallback(this);
    -     }
    - 
    -     public void setFingerprintUnlockController(
    -@@ -73,6 +75,7 @@ public class LightStatusBarController {
    -         }
    -         mFullscreenStackVisibility = newFullscreen;
    -         mDockedStackVisibility = newDocked;
    -+        mLastStatusBarMode = statusBarMode;
    -         mLastFullscreenBounds.set(fullscreenStackBounds);
    -         mLastDockedBounds.set(dockedStackBounds);
    -     }
    -@@ -123,4 +126,16 @@ public class LightStatusBarController {
    -             mIconController.setIconsDark(true, animateChange());
    -         }
    -     }
    -+
    -+    @Override
    -+    public void onBatteryLevelChanged(int level, boolean pluggedIn, boolean charging) {
    -+
    -+    }
    -+
    -+    @Override
    -+    public void onPowerSaveChanged(boolean isPowerSave) {
    -+        onSystemUiVisibilityChanged(mFullscreenStackVisibility, mDockedStackVisibility,
    -+                0 /* mask */, mLastFullscreenBounds, mLastDockedBounds, true /* sbModeChange*/,
    -+                mLastStatusBarMode);
    -+    }
    - }
    -diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
    -index 45d51b0..0bc70b5 100644
    ---- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
    -+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
    -@@ -59,6 +59,8 @@ public class NavigationBarView extends LinearLayout {
    -     // slippery nav bar when everything is disabled, e.g. during setup
    -     final static boolean SLIPPERY_WHEN_DISABLED = true;
    - 
    -+    final static boolean ALTERNATE_CAR_MODE_UI = false;
    -+
    -     final Display mDisplay;
    -     View mCurrentView = null;
    -     View[] mRotatedViews = new View[4];
    -@@ -94,7 +96,8 @@ public class NavigationBarView extends LinearLayout {
    -     private OnVerticalChangedListener mOnVerticalChangedListener;
    -     private boolean mLayoutTransitionsEnabled = true;
    -     private boolean mWakeAndUnlocking;
    --    private boolean mCarMode = false;
    -+    private boolean mUseCarModeUi = false;
    -+    private boolean mInCarMode = false;
    -     private boolean mDockedStackExists;
    - 
    -     private final SparseArray<ButtonDispatcher> mButtonDisatchers = new SparseArray<>();
    -@@ -290,7 +293,9 @@ public class NavigationBarView extends LinearLayout {
    -             mMenuIcon = ctx.getDrawable(R.drawable.ic_sysbar_menu);
    -             mImeIcon = ctx.getDrawable(R.drawable.ic_ime_switcher_default);
    - 
    --            updateCarModeIcons(ctx);
    -+            if (ALTERNATE_CAR_MODE_UI) {
    -+                updateCarModeIcons(ctx);
    -+            }
    -         }
    -     }
    - 
    -@@ -341,14 +346,14 @@ public class NavigationBarView extends LinearLayout {
    -         // carmode, respectively. Recents are not available in CarMode in nav bar so change
    -         // to recent icon is not required.
    -         Drawable backIcon = (backAlt)
    --                ? getBackIconWithAlt(mCarMode, mVertical)
    --                : getBackIcon(mCarMode, mVertical);
    -+                ? getBackIconWithAlt(mUseCarModeUi, mVertical)
    -+                : getBackIcon(mUseCarModeUi, mVertical);
    - 
    -         getBackButton().setImageDrawable(backIcon);
    - 
    -         updateRecentsIcon();
    - 
    --        if (mCarMode) {
    -+        if (mUseCarModeUi) {
    -             getHomeButton().setImageDrawable(mHomeCarModeIcon);
    -         } else {
    -             getHomeButton().setImageDrawable(mHomeDefaultIcon);
    -@@ -376,9 +381,9 @@ public class NavigationBarView extends LinearLayout {
    - 
    -         final boolean disableHome = ((disabledFlags & View.STATUS_BAR_DISABLE_HOME) != 0);
    - 
    --        // Disable recents always in car mode.
    --        boolean disableRecent = (
    --                mCarMode || (disabledFlags & View.STATUS_BAR_DISABLE_RECENT) != 0);
    -+        // Always disable recents when alternate car mode UI is active.
    -+        boolean disableRecent = mUseCarModeUi
    -+                        || ((disabledFlags & View.STATUS_BAR_DISABLE_RECENT) != 0);
    -         final boolean disableBack = ((disabledFlags & View.STATUS_BAR_DISABLE_BACK) != 0)
    -                 && ((mNavigationIconHints & StatusBarManager.NAVIGATION_HINT_BACK_ALT) == 0);
    -         final boolean disableSearch = ((disabledFlags & View.STATUS_BAR_DISABLE_SEARCH) != 0);
    -@@ -623,14 +628,19 @@ public class NavigationBarView extends LinearLayout {
    -         boolean uiCarModeChanged = false;
    -         if (newConfig != null) {
    -             int uiMode = newConfig.uiMode & Configuration.UI_MODE_TYPE_MASK;
    --            if (mCarMode && uiMode != Configuration.UI_MODE_TYPE_CAR) {
    --                mCarMode = false;
    --                uiCarModeChanged = true;
    --                getHomeButton().setCarMode(mCarMode);
    --            } else if (uiMode == Configuration.UI_MODE_TYPE_CAR) {
    --                mCarMode = true;
    --                uiCarModeChanged = true;
    --                getHomeButton().setCarMode(mCarMode);
    -+            final boolean isCarMode = (uiMode == Configuration.UI_MODE_TYPE_CAR);
    -+
    -+            if (isCarMode != mInCarMode) {
    -+                mInCarMode = isCarMode;
    -+                getHomeButton().setCarMode(isCarMode);
    -+
    -+                if (ALTERNATE_CAR_MODE_UI) {
    -+                    mUseCarModeUi = isCarMode;
    -+                    uiCarModeChanged = true;
    -+                } else {
    -+                    // Don't use car mode behavior if ALTERNATE_CAR_MODE_UI not set.
    -+                    mUseCarModeUi = false;
    -+                }
    -             }
    -         }
    -         return uiCarModeChanged;
    -diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
    -index f4b41bb..ede6fd0 100644
    ---- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
    -+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
    -@@ -233,6 +233,7 @@ public class NotificationPanelView extends PanelView implements
    -         mKeyguardBottomArea = (KeyguardBottomAreaView) findViewById(R.id.keyguard_bottom_area);
    -         mQsNavbarScrim = findViewById(R.id.qs_navbar_scrim);
    -         mAfforanceHelper = new KeyguardAffordanceHelper(this, getContext());
    -+        mKeyguardBottomArea.setAffordanceHelper(mAfforanceHelper);
    -         mLastOrientation = getResources().getConfiguration().orientation;
    - 
    -         mQsAutoReinflateContainer =
    -@@ -328,7 +329,7 @@ public class NotificationPanelView extends PanelView implements
    -         } else if (!mQsExpanded) {
    -             setQsExpansion(mQsMinExpansionHeight + mLastOverscroll);
    -         }
    --        updateStackHeight(getExpandedHeight());
    -+        updateExpandedHeight(getExpandedHeight());
    -         updateHeader();
    - 
    -         // If we are running a size change animation, the animation takes care of the height of
    -@@ -376,10 +377,7 @@ public class NotificationPanelView extends PanelView implements
    -         boolean animate = mNotificationStackScroller.isAddOrRemoveAnimationPending();
    -         int stackScrollerPadding;
    -         if (mStatusBarState != StatusBarState.KEYGUARD) {
    --            int bottom = mQsContainer.getHeader().getHeight();
    --            stackScrollerPadding = mStatusBarState == StatusBarState.SHADE
    --                    ? bottom + mQsPeekHeight
    --                    : mKeyguardStatusBar.getHeight();
    -+            stackScrollerPadding = mQsContainer.getHeader().getHeight() + mQsPeekHeight;
    -             mTopPaddingAdjustment = 0;
    -         } else {
    -             mClockPositionAlgorithm.setup(
    -@@ -1004,8 +1002,8 @@ public class NotificationPanelView extends PanelView implements
    -         mKeyguardShowing = keyguardShowing;
    -         mQsContainer.setKeyguardShowing(mKeyguardShowing);
    - 
    --        if (goingToFullShade || (oldState == StatusBarState.KEYGUARD
    --                && statusBarState == StatusBarState.SHADE_LOCKED)) {
    -+        if (oldState == StatusBarState.KEYGUARD
    -+                && (goingToFullShade || statusBarState == StatusBarState.SHADE_LOCKED)) {
    -             animateKeyguardStatusBarOut();
    -             long delay = mStatusBarState == StatusBarState.SHADE_LOCKED
    -                     ? 0 : mStatusBar.calculateGoingToFullShadeDelay();
    -@@ -1019,7 +1017,7 @@ public class NotificationPanelView extends PanelView implements
    -             mKeyguardStatusBar.setVisibility(keyguardShowing ? View.VISIBLE : View.INVISIBLE);
    -             if (keyguardShowing && oldState != mStatusBarState) {
    -                 mKeyguardBottomArea.onKeyguardShowingChanged();
    --                mAfforanceHelper.updatePreviews();
    -+                mQsContainer.hideImmediately();
    -             }
    -         }
    -         if (keyguardShowing) {
    -@@ -1166,6 +1164,7 @@ public class NotificationPanelView extends PanelView implements
    - 
    -     private void updateQsState() {
    -         mQsContainer.setExpanded(mQsExpanded);
    -+        mNotificationStackScroller.setQsExpanded(mQsExpanded);
    -         mNotificationStackScroller.setScrollingEnabled(
    -                 mStatusBarState != StatusBarState.KEYGUARD && (!mQsExpanded
    -                         || mQsExpansionFromOverscroll));
    -@@ -1427,7 +1426,7 @@ public class NotificationPanelView extends PanelView implements
    -             setQsExpansion(mQsMinExpansionHeight
    -                     + t * (getTempQsMaxExpansion() - mQsMinExpansionHeight));
    -         }
    --        updateStackHeight(expandedHeight);
    -+        updateExpandedHeight(expandedHeight);
    -         updateHeader();
    -         updateUnlockIcon();
    -         updateNotificationTranslucency();
    -@@ -1487,7 +1486,7 @@ public class NotificationPanelView extends PanelView implements
    -                 maxQsHeight, mStatusBarState == StatusBarState.KEYGUARD
    -                         ? mClockPositionResult.stackScrollerPadding - mTopPaddingAdjustment
    -                         : 0)
    --                + notificationHeight;
    -+                + notificationHeight + mNotificationStackScroller.getTopPaddingOverflow();
    -         if (totalHeight > mNotificationStackScroller.getHeight()) {
    -             float fullyCollapsedHeight = maxQsHeight
    -                     + mNotificationStackScroller.getLayoutMinHeight();
    -@@ -1730,6 +1729,14 @@ public class NotificationPanelView extends PanelView implements
    -         if (view == null && mQsExpanded) {
    -             return;
    -         }
    -+        ExpandableView firstChildNotGone = mNotificationStackScroller.getFirstChildNotGone();
    -+        ExpandableNotificationRow firstRow = firstChildNotGone instanceof ExpandableNotificationRow
    -+                ? (ExpandableNotificationRow) firstChildNotGone
    -+                : null;
    -+        if (firstRow != null
    -+                && (view == firstRow || (firstRow.getNotificationParent() == firstRow))) {
    -+            requestScrollerTopPaddingUpdate(false);
    -+        }
    -         requestPanelHeightUpdate();
    -     }
    - 
    -@@ -2249,8 +2256,8 @@ public class NotificationPanelView extends PanelView implements
    -         mQsAutoReinflateContainer.setTranslationX(translation);
    -     }
    - 
    --    protected void updateStackHeight(float stackHeight) {
    --        mNotificationStackScroller.setStackHeight(stackHeight);
    -+    protected void updateExpandedHeight(float expandedHeight) {
    -+        mNotificationStackScroller.setExpandedHeight(expandedHeight);
    -         updateKeyguardBottomAreaAlpha();
    -     }
    - 
    -diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java
    -index af85101..a6a5742 100644
    ---- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java
    -+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java
    -@@ -92,6 +92,7 @@ public abstract class PanelView extends FrameLayout {
    -      * Whether an instant expand request is currently pending and we are just waiting for layout.
    -      */
    -     private boolean mInstantExpanding;
    -+    private boolean mAnimateAfterExpanding;
    - 
    -     PanelBar mBar;
    - 
    -@@ -656,7 +657,7 @@ public abstract class PanelView extends FrameLayout {
    -                 vel = 0;
    -             }
    -             mFlingAnimationUtils.apply(animator, mExpandedHeight, target, vel, getHeight());
    --            if (expandBecauseOfFalsing) {
    -+            if (vel == 0) {
    -                 animator.setDuration(350);
    -             }
    -         } else {
    -@@ -870,6 +871,7 @@ public abstract class PanelView extends FrameLayout {
    -         }
    - 
    -         mInstantExpanding = true;
    -+        mAnimateAfterExpanding = animate;
    -         mUpdateFlingOnLayout = false;
    -         abortAnimations();
    -         cancelPeek();
    -@@ -894,7 +896,7 @@ public abstract class PanelView extends FrameLayout {
    -                         if (mStatusBar.getStatusBarWindow().getHeight()
    -                                 != mStatusBar.getStatusBarHeight()) {
    -                             getViewTreeObserver().removeOnGlobalLayoutListener(this);
    --                            if (animate) {
    -+                            if (mAnimateAfterExpanding) {
    -                                 notifyExpandingStarted();
    -                                 fling(0, true /* expand */);
    -                             } else {
    -diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
    -index 96fb7a8..30613bc 100644
    ---- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
    -+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
    -@@ -174,12 +174,14 @@ import com.android.systemui.statusbar.policy.BatteryControllerImpl;
    - import com.android.systemui.statusbar.policy.BluetoothControllerImpl;
    - import com.android.systemui.statusbar.policy.BrightnessMirrorController;
    - import com.android.systemui.statusbar.policy.CastControllerImpl;
    -+import com.android.systemui.statusbar.policy.EncryptionHelper;
    - import com.android.systemui.statusbar.policy.FlashlightController;
    - import com.android.systemui.statusbar.policy.HeadsUpManager;
    - import com.android.systemui.statusbar.policy.HotspotControllerImpl;
    - import com.android.systemui.statusbar.policy.KeyguardMonitor;
    - import com.android.systemui.statusbar.policy.KeyguardUserSwitcher;
    - import com.android.systemui.statusbar.policy.LocationControllerImpl;
    -+import com.android.systemui.statusbar.policy.NetworkController;
    - import com.android.systemui.statusbar.policy.NetworkControllerImpl;
    - import com.android.systemui.statusbar.policy.NextAlarmController;
    - import com.android.systemui.statusbar.policy.PreviewInflater;
    -@@ -279,6 +281,14 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
    -      */
    -     private static final int REMOTE_INPUT_KEPT_ENTRY_AUTO_CANCEL_DELAY = 200;
    - 
    -+    /**
    -+     * Never let the alpha become zero for surfaces that draw with SRC - otherwise the RenderNode
    -+     * won't draw anything and uninitialized memory will show through
    -+     * if mScrimSrcModeEnabled. Note that 0.001 is rounded down to 0 in
    -+     * libhwui.
    -+     */
    -+    private static final float SRC_MIN_ALPHA = 0.002f;
    -+
    -     static {
    -         boolean onlyCoreApps;
    -         boolean freeformWindowManagement;
    -@@ -656,6 +666,15 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
    -     private boolean mNoAnimationOnNextBarModeChange;
    -     private FalsingManager mFalsingManager;
    - 
    -+    private KeyguardUpdateMonitorCallback mUpdateCallback = new KeyguardUpdateMonitorCallback() {
    -+        @Override
    -+        public void onDreamingStateChanged(boolean dreaming) {
    -+            if (dreaming) {
    -+                maybeEscalateHeadsUp();
    -+            }
    -+        }
    -+    };
    -+
    -     @Override
    -     public void start() {
    -         mDisplay = ((WindowManager)mContext.getSystemService(Context.WINDOW_SERVICE))
    -@@ -693,8 +712,8 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
    -         mUnlockMethodCache.addListener(this);
    -         startKeyguard();
    - 
    -+        KeyguardUpdateMonitor.getInstance(mContext).registerCallback(mUpdateCallback);
    -         mDozeServiceHost = new DozeServiceHost();
    --        KeyguardUpdateMonitor.getInstance(mContext).registerCallback(mDozeServiceHost);
    -         putComponent(DozeHost.class, mDozeServiceHost);
    -         putComponent(PhoneStatusBar.class, this);
    - 
    -@@ -878,6 +897,7 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
    - 
    -         initSignalCluster(mStatusBarView);
    -         initSignalCluster(mKeyguardStatusBar);
    -+        initEmergencyCryptkeeperText();
    - 
    -         mFlashlightController = new FlashlightController(mContext);
    -         mKeyguardBottomArea.setFlashlightController(mFlashlightController);
    -@@ -996,6 +1016,24 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
    -         return mStatusBarView;
    -     }
    - 
    -+    private void initEmergencyCryptkeeperText() {
    -+        View emergencyViewStub = mStatusBarWindow.findViewById(R.id.emergency_cryptkeeper_text);
    -+        if (mNetworkController.hasEmergencyCryptKeeperText()) {
    -+            if (emergencyViewStub != null) {
    -+                ((ViewStub) emergencyViewStub).inflate();
    -+            }
    -+            mNetworkController.addSignalCallback(new NetworkController.SignalCallback() {
    -+                @Override
    -+                public void setIsAirplaneMode(NetworkController.IconState icon) {
    -+                    recomputeDisableFlags(true /* animate */);
    -+                }
    -+            });
    -+        } else if (emergencyViewStub != null) {
    -+            ViewGroup parent = (ViewGroup) emergencyViewStub.getParent();
    -+            parent.removeView(emergencyViewStub);
    -+        }
    -+    }
    -+
    -     protected BatteryController createBatteryController() {
    -         return new BatteryControllerImpl(mContext);
    -     }
    -@@ -1681,7 +1719,7 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
    -     protected void performRemoveNotification(StatusBarNotification n, boolean removeView) {
    -         Entry entry = mNotificationData.get(n.getKey());
    -         if (mRemoteInputController.isRemoteInputActive(entry)) {
    --            mRemoteInputController.removeRemoteInput(entry);
    -+            mRemoteInputController.removeRemoteInput(entry, null);
    -         }
    -         super.performRemoveNotification(n, removeView);
    -     }
    -@@ -2209,17 +2247,13 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
    -             if (mBackdrop.getVisibility() != View.VISIBLE) {
    -                 mBackdrop.setVisibility(View.VISIBLE);
    -                 if (allowEnterAnimation) {
    --                    mBackdrop.animate().alpha(1f).withEndAction(new Runnable() {
    --                        @Override
    --                        public void run() {
    --                            mStatusBarWindowManager.setBackdropShowing(true);
    --                        }
    --                    });
    -+                    mBackdrop.setAlpha(SRC_MIN_ALPHA);
    -+                    mBackdrop.animate().alpha(1f);
    -                 } else {
    -                     mBackdrop.animate().cancel();
    -                     mBackdrop.setAlpha(1f);
    --                    mStatusBarWindowManager.setBackdropShowing(true);
    -                 }
    -+                mStatusBarWindowManager.setBackdropShowing(true);
    -                 metaDataChanged = true;
    -                 if (DEBUG_MEDIA) {
    -                     Log.v(TAG, "DEBUG_MEDIA: Fading in album artwork");
    -@@ -2282,11 +2316,7 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
    -                 } else {
    -                     mStatusBarWindowManager.setBackdropShowing(false);
    -                     mBackdrop.animate()
    --                            // Never let the alpha become zero - otherwise the RenderNode
    --                            // won't draw anything and uninitialized memory will show through
    --                            // if mScrimSrcModeEnabled. Note that 0.001 is rounded down to 0 in
    --                            // libhwui.
    --                            .alpha(0.002f)
    -+                            .alpha(SRC_MIN_ALPHA)
    -                             .setInterpolator(Interpolators.ACCELERATE_DECELERATE)
    -                             .setDuration(300)
    -                             .setStartDelay(0)
    -@@ -2301,7 +2331,6 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
    -                             });
    -                     if (mKeyguardFadingAway) {
    -                         mBackdrop.animate()
    --
    -                                 // Make it disappear faster, as the focus should be on the activity
    -                                 // behind.
    -                                 .setDuration(mKeyguardFadingAwayDuration / 2)
    -@@ -2329,6 +2358,14 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
    -             state |= StatusBarManager.DISABLE_NOTIFICATION_ICONS;
    -             state |= StatusBarManager.DISABLE_SYSTEM_INFO;
    -         }
    -+        if (mNetworkController != null && EncryptionHelper.IS_DATA_ENCRYPTED) {
    -+            if (mNetworkController.hasEmergencyCryptKeeperText()) {
    -+                state |= StatusBarManager.DISABLE_NOTIFICATION_ICONS;
    -+            }
    -+            if (!mNetworkController.isRadioOn()) {
    -+                state |= StatusBarManager.DISABLE_SYSTEM_INFO;
    -+            }
    -+        }
    -         return state;
    -     }
    - 
    -@@ -2433,6 +2470,15 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
    -         }
    -     }
    - 
    -+    /**
    -+     * Reapplies the disable flags as last requested by StatusBarManager.
    -+     *
    -+     * This needs to be called if state used by {@link #adjustDisableFlags} changes.
    -+     */
    -+    private void recomputeDisableFlags(boolean animate) {
    -+        disable(mDisabledUnmodified1, mDisabledUnmodified2, animate);
    -+    }
    -+
    -     @Override
    -     protected BaseStatusBar.H createHandler() {
    -         return new PhoneStatusBar.H();
    -@@ -2621,7 +2667,7 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
    -     private void removeRemoteInputEntriesKeptUntilCollapsed() {
    -         for (int i = 0; i < mRemoteInputEntriesToRemoveOnCollapse.size(); i++) {
    -             Entry entry = mRemoteInputEntriesToRemoveOnCollapse.valueAt(i);
    --            mRemoteInputController.removeRemoteInput(entry);
    -+            mRemoteInputController.removeRemoteInput(entry, null);
    -             removeNotification(entry.key, mLatestRankingMap);
    -         }
    -         mRemoteInputEntriesToRemoveOnCollapse.clear();
    -@@ -2685,7 +2731,7 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
    -     public void handleSystemNavigationKey(int key) {
    -         if (SPEW) Log.d(TAG, "handleSystemNavigationKey: " + key);
    -         if (!panelsEnabled() || !mKeyguardMonitor.isDeviceInteractive()
    --                || mKeyguardMonitor.isShowing()) {
    -+                || mKeyguardMonitor.isShowing() && !mKeyguardMonitor.isOccluded()) {
    -             return;
    -         }
    - 
    -@@ -2726,7 +2772,7 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
    - 
    -         visibilityChanged(true);
    -         mWaitingForKeyguardExit = false;
    --        disable(mDisabledUnmodified1, mDisabledUnmodified2, !force /* animate */);
    -+        recomputeDisableFlags(!force /* animate */);
    -         setInteracting(StatusBarManager.WINDOW_STATUS_BAR, true);
    -     }
    - 
    -@@ -2868,7 +2914,7 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
    -         runPostCollapseRunnables();
    -         setInteracting(StatusBarManager.WINDOW_STATUS_BAR, false);
    -         showBouncer();
    --        disable(mDisabledUnmodified1, mDisabledUnmodified2, true /* animate */);
    -+        recomputeDisableFlags(true /* animate */);
    - 
    -         // Trimming will happen later if Keyguard is showing - doing it here might cause a jank in
    -         // the bouncer appear animation.
    -@@ -2986,10 +3032,6 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
    -                 Integer.toHexString(diff)));
    -         boolean sbModeChanged = false;
    -         if (diff != 0) {
    --            // we never set the recents bit via this method, so save the prior state to prevent
    --            // clobbering the bit below
    --            final boolean wasRecentsVisible = (mSystemUiVisibility & View.RECENT_APPS_VISIBLE) > 0;
    --
    -             mSystemUiVisibility = newVal;
    - 
    -             // update low profile
    -@@ -3040,11 +3082,6 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
    -                 mSystemUiVisibility &= ~View.NAVIGATION_BAR_UNHIDE;
    -             }
    - 
    --            // restore the recents bit
    --            if (wasRecentsVisible) {
    --                mSystemUiVisibility |= View.RECENT_APPS_VISIBLE;
    --            }
    --
    -             // send updated sysui visibility to window manager
    -             notifyUiVisibilityChanged(mSystemUiVisibility);
    -         }
    -@@ -3368,6 +3405,9 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
    -         if (KeyguardUpdateMonitor.getInstance(mContext) != null) {
    -             KeyguardUpdateMonitor.getInstance(mContext).dump(fd, pw, args);
    -         }
    -+        if (mFlashlightController != null) {
    -+            mFlashlightController.dump(fd, pw, args);
    -+        }
    - 
    -         FalsingManager.getInstance(mContext).dump(pw);
    -         FalsingLog.dump(pw);
    -@@ -4120,6 +4160,15 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
    -     }
    - 
    -     /**
    -+     * Plays the animation when an activity that was occluding Keyguard goes away.
    -+     */
    -+    public void animateKeyguardUnoccluding() {
    -+        mScrimController.animateKeyguardUnoccluding(500);
    -+        mNotificationPanel.setExpandedFraction(0f);
    -+        animateExpandNotificationsPanel();
    -+    }
    -+
    -+    /**
    -      * Starts the timeout when we try to start the affordances on Keyguard. We usually rely that
    -      * Keyguard goes away via fadeKeyguardAfterLaunchTransition, however, that might not happen
    -      * because the launched app crashed or something else went wrong.
    -@@ -4182,7 +4231,7 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
    -         }
    -         updateKeyguardState(staying, false /* fromShadeLocked */);
    - 
    --        if (viewToClick != null) {
    -+        if (viewToClick != null && viewToClick.isAttachedToWindow()) {
    -             viewToClick.callOnClick();
    -         }
    - 
    -@@ -4237,7 +4286,7 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
    -                 startTime + fadeoutDuration
    -                         - StatusBarIconController.DEFAULT_TINT_ANIMATION_DURATION,
    -                 StatusBarIconController.DEFAULT_TINT_ANIMATION_DURATION);
    --        disable(mDisabledUnmodified1, mDisabledUnmodified2, fadeoutDuration > 0 /* animate */);
    -+        recomputeDisableFlags(fadeoutDuration > 0 /* animate */);
    -     }
    - 
    -     public boolean isKeyguardFadingAway() {
    -@@ -4302,7 +4351,8 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
    -         checkBarModes();
    -         updateMediaMetaData(false, mState != StatusBarState.KEYGUARD);
    -         mKeyguardMonitor.notifyKeyguardState(mStatusBarKeyguardViewManager.isShowing(),
    --                mStatusBarKeyguardViewManager.isSecure());
    -+                mStatusBarKeyguardViewManager.isSecure(),
    -+                mStatusBarKeyguardViewManager.isOccluded());
    -         Trace.endSection();
    -     }
    - 
    -@@ -4437,6 +4487,7 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
    -         }
    -         if (state == StatusBarState.KEYGUARD) {
    -             removeRemoteInputEntriesKeptUntilCollapsed();
    -+            maybeEscalateHeadsUp();
    -         }
    -         mState = state;
    -         mGroupManager.setStatusBarState(state);
    -@@ -4721,7 +4772,7 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
    -     public void setBouncerShowing(boolean bouncerShowing) {
    -         super.setBouncerShowing(bouncerShowing);
    -         mStatusBarView.setBouncerShowing(bouncerShowing);
    --        disable(mDisabledUnmodified1, mDisabledUnmodified2, true /* animate */);
    -+        recomputeDisableFlags(true /* animate */);
    -     }
    - 
    -     public void onStartedGoingToSleep() {
    -@@ -4798,16 +4849,6 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
    -         return false;
    -     }
    - 
    --    public void updateRecentsVisibility(boolean visible) {
    --        // Update the recents visibility flag
    --        if (visible) {
    --            mSystemUiVisibility |= View.RECENT_APPS_VISIBLE;
    --        } else {
    --            mSystemUiVisibility &= ~View.RECENT_APPS_VISIBLE;
    --        }
    --        notifyUiVisibilityChanged(mSystemUiVisibility);
    --    }
    --
    -     @Override
    -     public void showScreenPinningRequest(int taskId) {
    -         if (mKeyguardMonitor.isShowing()) {
    -@@ -4956,7 +4997,7 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
    -         }
    -     }
    - 
    --    private final class DozeServiceHost extends KeyguardUpdateMonitorCallback implements DozeHost  {
    -+    private final class DozeServiceHost implements DozeHost {
    -         // Amount of time to allow to update the time shown on the screen before releasing
    -         // the wakelock.  This timeout is design to compensate for the fact that we don't
    -         // currently have a way to know when time display contents have actually been
    -diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickStatusBarHeader.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickStatusBarHeader.java
    -index 7a2ae22..e4991d5 100644
    ---- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickStatusBarHeader.java
    -+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickStatusBarHeader.java
    -@@ -343,9 +343,7 @@ public class QuickStatusBarHeader extends BaseStatusBarHeader implements
    -             }
    -         } else if (v == mAlarmStatus && mNextAlarm != null) {
    -             PendingIntent showIntent = mNextAlarm.getShowIntent();
    --            if (showIntent != null && showIntent.isActivity()) {
    --                mActivityStarter.startActivity(showIntent.getIntent(), true /* dismissShade */);
    --            }
    -+            mActivityStarter.startPendingIntentDismissingKeyguard(showIntent);
    -         }
    -     }
    - 
    -diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
    -index 8b87a7f..35e084d 100644
    ---- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
    -+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
    -@@ -176,7 +176,7 @@ public class ScrimController implements ViewTreeObserver.OnPreDrawListener,
    -         mSkipFirstFrame = skipFirstFrame;
    -         mOnAnimationFinished = onAnimationFinished;
    - 
    --        if (mKeyguardUpdateMonitor.isUserUnlocked()) {
    -+        if (!mKeyguardUpdateMonitor.needsSlowUnlockTransition()) {
    -             scheduleUpdate();
    - 
    -             // No need to wait for the next frame to be drawn for this case - onPreDraw will execute
    -@@ -196,6 +196,14 @@ public class ScrimController implements ViewTreeObserver.OnPreDrawListener,
    -         }
    -     }
    - 
    -+    public void animateKeyguardUnoccluding(long duration) {
    -+        mAnimateChange = false;
    -+        setScrimBehindColor(0f);
    -+        mAnimateChange = true;
    -+        scheduleUpdate();
    -+        mDurationOverride = duration;
    -+    }
    -+
    -     public void animateGoingToFullShade(long delay, long duration) {
    -         mDurationOverride = duration;
    -         mAnimationDelay = delay;
    -@@ -233,9 +241,9 @@ public class ScrimController implements ViewTreeObserver.OnPreDrawListener,
    -     }
    - 
    -     private float getScrimInFrontAlpha() {
    --        return mKeyguardUpdateMonitor.isUserUnlocked()
    --                ? SCRIM_IN_FRONT_ALPHA
    --                : SCRIM_IN_FRONT_ALPHA_LOCKED;
    -+        return mKeyguardUpdateMonitor.needsSlowUnlockTransition()
    -+                ? SCRIM_IN_FRONT_ALPHA_LOCKED
    -+                : SCRIM_IN_FRONT_ALPHA;
    -     }
    -     private void scheduleUpdate() {
    -         if (mUpdatePending) return;
    -@@ -397,7 +405,7 @@ public class ScrimController implements ViewTreeObserver.OnPreDrawListener,
    -     }
    - 
    -     private Interpolator getInterpolator() {
    --        if (mAnimateKeyguardFadingOut && !mKeyguardUpdateMonitor.isUserUnlocked()) {
    -+        if (mAnimateKeyguardFadingOut && mKeyguardUpdateMonitor.needsSlowUnlockTransition()) {
    -             return KEYGUARD_FADE_OUT_INTERPOLATOR_LOCKED;
    -         } else if (mAnimateKeyguardFadingOut) {
    -             return KEYGUARD_FADE_OUT_INTERPOLATOR;
    -diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
    -index c72f994..664e103 100644
    ---- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
    -+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
    -@@ -242,7 +242,7 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb
    -         return mStatusBarWindowManager.isShowingWallpaper();
    -     }
    - 
    --    public void setOccluded(boolean occluded) {
    -+    public void setOccluded(boolean occluded, boolean animate) {
    -         if (occluded && !mOccluded && mShowing) {
    -             if (mPhoneStatusBar.isInLaunchTransition()) {
    -                 mOccluded = true;
    -@@ -258,9 +258,12 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb
    -             }
    -         }
    -         mOccluded = occluded;
    --        mPhoneStatusBar.updateMediaMetaData(false, false);
    -+        mPhoneStatusBar.updateMediaMetaData(false, animate && !occluded);
    -         mStatusBarWindowManager.setKeyguardOccluded(occluded);
    -         reset();
    -+        if (animate && !occluded) {
    -+            mPhoneStatusBar.animateKeyguardUnoccluding();
    -+        }
    -     }
    - 
    -     public boolean isOccluded() {
    -@@ -288,7 +291,7 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb
    -     public void hide(long startTime, long fadeoutDuration) {
    -         mShowing = false;
    - 
    --        if (!KeyguardUpdateMonitor.getInstance(mContext).isUserUnlocked()) {
    -+        if (KeyguardUpdateMonitor.getInstance(mContext).needsSlowUnlockTransition()) {
    -             fadeoutDuration = KEYGUARD_DISMISS_DURATION_LOCKED;
    -         }
    -         long uptimeMillis = SystemClock.uptimeMillis();
    -diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BatteryControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BatteryControllerImpl.java
    -index b9c7a4b..6726c92 100644
    ---- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BatteryControllerImpl.java
    -+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BatteryControllerImpl.java
    -@@ -53,6 +53,7 @@ public class BatteryControllerImpl extends BroadcastReceiver implements BatteryC
    -     protected boolean mCharged;
    -     protected boolean mPowerSave;
    -     private boolean mTestmode = false;
    -+    private boolean mHasReceivedBattery = false;
    - 
    -     public BatteryControllerImpl(Context context) {
    -         mContext = context;
    -@@ -92,6 +93,7 @@ public class BatteryControllerImpl extends BroadcastReceiver implements BatteryC
    -         synchronized (mChangeCallbacks) {
    -             mChangeCallbacks.add(cb);
    -         }
    -+        if (!mHasReceivedBattery) return;
    -         cb.onBatteryLevelChanged(mLevel, mPluggedIn, mCharging);
    -         cb.onPowerSaveChanged(mPowerSave);
    -     }
    -@@ -108,6 +110,7 @@ public class BatteryControllerImpl extends BroadcastReceiver implements BatteryC
    -         final String action = intent.getAction();
    -         if (action.equals(Intent.ACTION_BATTERY_CHANGED)) {
    -             if (mTestmode && !intent.getBooleanExtra("testmode", false)) return;
    -+            mHasReceivedBattery = true;
    -             mLevel = (int)(100f
    -                     * intent.getIntExtra(BatteryManager.EXTRA_LEVEL, 0)
    -                     / intent.getIntExtra(BatteryManager.EXTRA_SCALE, 100));
    -diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/EmergencyCryptkeeperText.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/EmergencyCryptkeeperText.java
    -new file mode 100644
    -index 0000000..8abfb89
    ---- /dev/null
    -+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/EmergencyCryptkeeperText.java
    -@@ -0,0 +1,124 @@
    -+/*
    -+ * Copyright (C) 2016 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 com.android.systemui.statusbar.policy;
    -+
    -+import android.annotation.Nullable;
    -+import android.content.Context;
    -+import android.content.Intent;
    -+import android.content.IntentFilter;
    -+import android.net.ConnectivityManager;
    -+import android.provider.Settings;
    -+import android.telephony.ServiceState;
    -+import android.telephony.SubscriptionInfo;
    -+import android.text.TextUtils;
    -+import android.util.AttributeSet;
    -+import android.util.Log;
    -+import android.view.ViewGroup;
    -+import android.view.ViewParent;
    -+import android.widget.TextView;
    -+
    -+import com.android.internal.telephony.IccCardConstants;
    -+import com.android.internal.telephony.TelephonyIntents;
    -+import com.android.keyguard.KeyguardUpdateMonitor;
    -+import com.android.keyguard.KeyguardUpdateMonitorCallback;
    -+
    -+import java.util.List;
    -+
    -+public class EmergencyCryptkeeperText extends TextView {
    -+
    -+    private KeyguardUpdateMonitor mKeyguardUpdateMonitor;
    -+    private KeyguardUpdateMonitorCallback mCallback = new KeyguardUpdateMonitorCallback() {
    -+        @Override
    -+        public void onPhoneStateChanged(int phoneState) {
    -+            update();
    -+        }
    -+    };
    -+
    -+    public EmergencyCryptkeeperText(Context context, @Nullable AttributeSet attrs) {
    -+        super(context, attrs);
    -+        setVisibility(GONE);
    -+    }
    -+
    -+    @Override
    -+    protected void onAttachedToWindow() {
    -+        super.onAttachedToWindow();
    -+        mKeyguardUpdateMonitor = KeyguardUpdateMonitor.getInstance(mContext);
    -+        mKeyguardUpdateMonitor.registerCallback(mCallback);
    -+        update();
    -+    }
    -+
    -+    @Override
    -+    protected void onDetachedFromWindow() {
    -+        super.onDetachedFromWindow();
    -+        if (mKeyguardUpdateMonitor != null) {
    -+            mKeyguardUpdateMonitor.removeCallback(mCallback);
    -+        }
    -+    }
    -+
    -+    public void update() {
    -+        boolean hasMobile = ConnectivityManager.from(mContext)
    -+                .isNetworkSupported(ConnectivityManager.TYPE_MOBILE);
    -+        boolean airplaneMode = (Settings.Global.getInt(mContext.getContentResolver(),
    -+                Settings.Global.AIRPLANE_MODE_ON, 0) == 1);
    -+
    -+        if (!hasMobile || airplaneMode) {
    -+            setText(null);
    -+            setVisibility(GONE);
    -+            return;
    -+        }
    -+
    -+        boolean allSimsMissing = true;
    -+        CharSequence displayText = null;
    -+
    -+        List<SubscriptionInfo> subs = mKeyguardUpdateMonitor.getSubscriptionInfo(false);
    -+        final int N = subs.size();
    -+        for (int i = 0; i < N; i++) {
    -+            int subId = subs.get(i).getSubscriptionId();
    -+            IccCardConstants.State simState = mKeyguardUpdateMonitor.getSimState(subId);
    -+            CharSequence carrierName = subs.get(i).getCarrierName();
    -+            if (simState.iccCardExist() && !TextUtils.isEmpty(carrierName)) {
    -+                allSimsMissing = false;
    -+                displayText = carrierName;
    -+            }
    -+        }
    -+        if (allSimsMissing) {
    -+            if (N != 0) {
    -+                // Shows "Emergency calls only" on devices that are voice-capable.
    -+                // This depends on mPlmn containing the text "Emergency calls only" when the radio
    -+                // has some connectivity. Otherwise it should show "No service"
    -+                // Grab the first subscription, because they all should contain the emergency text,
    -+                // described above.
    -+                displayText = subs.get(0).getCarrierName();
    -+            } else {
    -+                // We don't have a SubscriptionInfo to get the emergency calls only from.
    -+                // Grab it from the old sticky broadcast if possible instead. We can use it
    -+                // here because no subscriptions are active, so we don't have
    -+                // to worry about MSIM clashing.
    -+                displayText = getContext().getText(
    -+                        com.android.internal.R.string.emergency_calls_only);
    -+                Intent i = getContext().registerReceiver(null,
    -+                        new IntentFilter(TelephonyIntents.SPN_STRINGS_UPDATED_ACTION));
    -+                if (i != null) {
    -+                    displayText = i.getStringExtra(TelephonyIntents.EXTRA_PLMN);
    -+                }
    -+            }
    -+        }
    -+
    -+        setText(displayText);
    -+        setVisibility(TextUtils.isEmpty(displayText) ? GONE : VISIBLE);
    -+    }
    -+}
    -diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/EncryptionHelper.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/EncryptionHelper.java
    -new file mode 100644
    -index 0000000..639e50c
    ---- /dev/null
    -+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/EncryptionHelper.java
    -@@ -0,0 +1,32 @@
    -+/*
    -+ * Copyright (C) 2016 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 com.android.systemui.statusbar.policy;
    -+
    -+import android.os.SystemProperties;
    -+
    -+/**
    -+ * Helper for determining whether the phone is decrypted yet.
    -+ */
    -+public class EncryptionHelper {
    -+
    -+    public static final boolean IS_DATA_ENCRYPTED = isDataEncrypted();
    -+
    -+    private static boolean isDataEncrypted() {
    -+        String voldState = SystemProperties.get("vold.decrypt");
    -+        return "1".equals(voldState) || "trigger_restart_min_framework".equals(voldState);
    -+    }
    -+}
    -diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/FlashlightController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/FlashlightController.java
    -index 91b21ed..4e9fc76 100644
    ---- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/FlashlightController.java
    -+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/FlashlightController.java
    -@@ -27,6 +27,8 @@ import android.os.Process;
    - import android.text.TextUtils;
    - import android.util.Log;
    - 
    -+import java.io.FileDescriptor;
    -+import java.io.PrintWriter;
    - import java.lang.ref.WeakReference;
    - import java.util.ArrayList;
    - 
    -@@ -80,6 +82,7 @@ public class FlashlightController {
    -     public void setFlashlight(boolean enabled) {
    -         boolean pendingError = false;
    -         synchronized (this) {
    -+            if (mCameraId == null) return;
    -             if (mFlashlightEnabled != enabled) {
    -                 mFlashlightEnabled = enabled;
    -                 try {
    -@@ -235,6 +238,17 @@ public class FlashlightController {
    -         }
    -     };
    - 
    -+    public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
    -+        pw.println("FlashlightController state:");
    -+
    -+        pw.print("  mCameraId=");
    -+        pw.println(mCameraId);
    -+        pw.print("  mFlashlightEnabled=");
    -+        pw.println(mFlashlightEnabled);
    -+        pw.print("  mTorchAvailable=");
    -+        pw.println(mTorchAvailable);
    -+    }
    -+
    -     public interface FlashlightListener {
    - 
    -         /**
    -diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpManager.java
    -index d3ae549..f6c0942 100644
    ---- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpManager.java
    -+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpManager.java
    -@@ -381,7 +381,7 @@ public class HeadsUpManager implements ViewTreeObserver.OnComputeInternalInsetsL
    -     }
    - 
    -     public void onComputeInternalInsets(ViewTreeObserver.InternalInsetsInfo info) {
    --        if (mIsExpanded) {
    -+        if (mIsExpanded || mBar.isBouncerShowing()) {
    -             // The touchable region is always the full area when expanded
    -             return;
    -         }
    -diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonView.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonView.java
    -index 61bac2d..e6066aa 100644
    ---- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonView.java
    -+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonView.java
    -@@ -59,6 +59,7 @@ public class KeyButtonView extends ImageView implements ButtonDispatcher.ButtonI
    -     private AudioManager mAudioManager;
    -     private boolean mGestureAborted;
    -     private boolean mLongClicked;
    -+    private OnClickListener mOnClickListener;
    - 
    -     private final Runnable mCheckLongPress = new Runnable() {
    -         public void run() {
    -@@ -109,6 +110,12 @@ public class KeyButtonView extends ImageView implements ButtonDispatcher.ButtonI
    -         mCode = code;
    -     }
    - 
    -+    @Override
    -+    public void setOnClickListener(OnClickListener onClickListener) {
    -+        super.setOnClickListener(onClickListener);
    -+        mOnClickListener = onClickListener;
    -+    }
    -+
    -     public void loadAsync(String uri) {
    -         new AsyncTask<String, Void, Drawable>() {
    -             @Override
    -@@ -190,6 +197,7 @@ public class KeyButtonView extends ImageView implements ButtonDispatcher.ButtonI
    -                     // Provide the same haptic feedback that the system offers for virtual keys.
    -                     performHapticFeedback(HapticFeedbackConstants.VIRTUAL_KEY);
    -                 }
    -+                playSoundEffect(SoundEffectConstants.CLICK);
    -                 removeCallbacks(mCheckLongPress);
    -                 postDelayed(mCheckLongPress, ViewConfiguration.getLongPressTimeout());
    -                 break;
    -@@ -215,14 +223,14 @@ public class KeyButtonView extends ImageView implements ButtonDispatcher.ButtonI
    -                     if (doIt) {
    -                         sendEvent(KeyEvent.ACTION_UP, 0);
    -                         sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_CLICKED);
    --                        playSoundEffect(SoundEffectConstants.CLICK);
    -                     } else {
    -                         sendEvent(KeyEvent.ACTION_UP, KeyEvent.FLAG_CANCELED);
    -                     }
    -                 } else {
    -                     // no key code, just a regular ImageView
    --                    if (doIt) {
    --                        performClick();
    -+                    if (doIt && mOnClickListener != null) {
    -+                        mOnClickListener.onClick(this);
    -+                        sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_CLICKED);
    -                     }
    -                 }
    -                 removeCallbacks(mCheckLongPress);
    -diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardMonitor.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardMonitor.java
    -index c175180..44816f9 100644
    ---- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardMonitor.java
    -+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardMonitor.java
    -@@ -38,6 +38,7 @@ public final class KeyguardMonitor extends KeyguardUpdateMonitorCallback {
    -     private int mCurrentUser;
    -     private boolean mShowing;
    -     private boolean mSecure;
    -+    private boolean mOccluded;
    -     private boolean mCanSkipBouncer;
    - 
    -     private boolean mListening;
    -@@ -81,6 +82,10 @@ public final class KeyguardMonitor extends KeyguardUpdateMonitorCallback {
    -         return mSecure;
    -     }
    - 
    -+    public boolean isOccluded() {
    -+        return mOccluded;
    -+    }
    -+
    -     public boolean canSkipBouncer() {
    -         return mCanSkipBouncer;
    -     }
    -@@ -99,10 +104,11 @@ public final class KeyguardMonitor extends KeyguardUpdateMonitorCallback {
    -         }
    -     }
    - 
    --    public void notifyKeyguardState(boolean showing, boolean secure) {
    --        if (mShowing == showing && mSecure == secure) return;
    -+    public void notifyKeyguardState(boolean showing, boolean secure, boolean occluded) {
    -+        if (mShowing == showing && mSecure == secure && mOccluded == occluded) return;
    -         mShowing = showing;
    -         mSecure = secure;
    -+        mOccluded = occluded;
    -         notifyKeyguardChanged();
    -     }
    - 
    -diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkController.java
    -index 348e0b0..5f1b871 100644
    ---- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkController.java
    -+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkController.java
    -@@ -41,20 +41,20 @@ public interface NetworkController {
    -     void removeEmergencyListener(EmergencyListener listener);
    - 
    -     public interface SignalCallback {
    --        void setWifiIndicators(boolean enabled, IconState statusIcon, IconState qsIcon,
    --                boolean activityIn, boolean activityOut, String description);
    -+        default void setWifiIndicators(boolean enabled, IconState statusIcon, IconState qsIcon,
    -+                boolean activityIn, boolean activityOut, String description) {}
    - 
    --        void setMobileDataIndicators(IconState statusIcon, IconState qsIcon, int statusType,
    -+        default void setMobileDataIndicators(IconState statusIcon, IconState qsIcon, int statusType,
    -                 int qsType, boolean activityIn, boolean activityOut, String typeContentDescription,
    --                String description, boolean isWide, int subId);
    --        void setSubs(List<SubscriptionInfo> subs);
    --        void setNoSims(boolean show);
    -+                String description, boolean isWide, int subId) {}
    -+        default void setSubs(List<SubscriptionInfo> subs) {}
    -+        default void setNoSims(boolean show) {}
    - 
    --        void setEthernetIndicators(IconState icon);
    -+        default void setEthernetIndicators(IconState icon) {}
    - 
    --        void setIsAirplaneMode(IconState icon);
    -+        default void setIsAirplaneMode(IconState icon) {}
    - 
    --        void setMobileDataEnabled(boolean enabled);
    -+        default void setMobileDataEnabled(boolean enabled) {}
    -     }
    - 
    -     public interface EmergencyListener {
    -diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java
    -index 7893a1a..37e6a2a 100644
    ---- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java
    -+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java
    -@@ -819,6 +819,14 @@ public class NetworkControllerImpl extends BroadcastReceiver
    -         return info;
    -     }
    - 
    -+    public boolean hasEmergencyCryptKeeperText() {
    -+        return EncryptionHelper.IS_DATA_ENCRYPTED;
    -+    }
    -+
    -+    public boolean isRadioOn() {
    -+        return !mAirplaneMode;
    -+    }
    -+
    -     private class SubListener extends OnSubscriptionsChangedListener {
    -         @Override
    -         public void onSubscriptionsChanged() {
    -diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputView.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputView.java
    -index cdd452f..7b1f707 100644
    ---- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputView.java
    -+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputView.java
    -@@ -38,6 +38,7 @@ import android.view.View;
    - import android.view.ViewAnimationUtils;
    - import android.view.ViewGroup;
    - import android.view.ViewParent;
    -+import android.view.accessibility.AccessibilityEvent;
    - import android.view.inputmethod.CompletionInfo;
    - import android.view.inputmethod.EditorInfo;
    - import android.view.inputmethod.InputConnection;
    -@@ -68,6 +69,8 @@ public class RemoteInputView extends LinearLayout implements View.OnClickListene
    -     // A marker object that let's us easily find views of this class.
    -     public static final Object VIEW_TAG = new Object();
    - 
    -+    public final Object mToken = new Object();
    -+
    -     private RemoteEditText mEditText;
    -     private ImageButton mSendButton;
    -     private ProgressBar mProgressBar;
    -@@ -86,6 +89,8 @@ public class RemoteInputView extends LinearLayout implements View.OnClickListene
    -     private int mRevealCy;
    -     private int mRevealR;
    - 
    -+    private boolean mResetting;
    -+
    -     public RemoteInputView(Context context, AttributeSet attrs) {
    -         super(context, attrs);
    -     }
    -@@ -137,8 +142,8 @@ public class RemoteInputView extends LinearLayout implements View.OnClickListene
    -         mSendButton.setVisibility(INVISIBLE);
    -         mProgressBar.setVisibility(VISIBLE);
    -         mEntry.remoteInputText = mEditText.getText();
    --        mController.addSpinning(mEntry.key);
    --        mController.removeRemoteInput(mEntry);
    -+        mController.addSpinning(mEntry.key, mToken);
    -+        mController.removeRemoteInput(mEntry, mToken);
    -         mEditText.mShowImeOnInputConnection = false;
    -         mController.remoteInputSent(mEntry);
    - 
    -@@ -190,7 +195,7 @@ public class RemoteInputView extends LinearLayout implements View.OnClickListene
    -     }
    - 
    -     private void onDefocus(boolean animate) {
    --        mController.removeRemoteInput(mEntry);
    -+        mController.removeRemoteInput(mEntry, mToken);
    -         mEntry.remoteInputText = mEditText.getText();
    - 
    -         // During removal, we get reattached and lose focus. Not hiding in that
    -@@ -229,11 +234,11 @@ public class RemoteInputView extends LinearLayout implements View.OnClickListene
    -     @Override
    -     protected void onDetachedFromWindow() {
    -         super.onDetachedFromWindow();
    --        if (mEntry.row.isChangingPosition()) {
    -+        if (mEntry.row.isChangingPosition() || isTemporarilyDetached()) {
    -             return;
    -         }
    --        mController.removeRemoteInput(mEntry);
    --        mController.removeSpinning(mEntry.key);
    -+        mController.removeRemoteInput(mEntry, mToken);
    -+        mController.removeSpinning(mEntry.key, mToken);
    -     }
    - 
    -     public void setPendingIntent(PendingIntent pendingIntent) {
    -@@ -262,7 +267,7 @@ public class RemoteInputView extends LinearLayout implements View.OnClickListene
    -                 mEntry.notification.getPackageName());
    - 
    -         setVisibility(VISIBLE);
    --        mController.addRemoteInput(mEntry);
    -+        mController.addRemoteInput(mEntry, mToken);
    -         mEditText.setInnerFocusable(true);
    -         mEditText.mShowImeOnInputConnection = true;
    -         mEditText.setText(mEntry.remoteInputText);
    -@@ -281,13 +286,28 @@ public class RemoteInputView extends LinearLayout implements View.OnClickListene
    -     }
    - 
    -     private void reset() {
    -+        mResetting = true;
    -+
    -         mEditText.getText().clear();
    -         mEditText.setEnabled(true);
    -         mSendButton.setVisibility(VISIBLE);
    -         mProgressBar.setVisibility(INVISIBLE);
    --        mController.removeSpinning(mEntry.key);
    -+        mController.removeSpinning(mEntry.key, mToken);
    -         updateSendButton();
    -         onDefocus(false /* animate */);
    -+
    -+        mResetting = false;
    -+    }
    -+
    -+    @Override
    -+    public boolean onRequestSendAccessibilityEvent(View child, AccessibilityEvent event) {
    -+        if (mResetting && child == mEditText) {
    -+            // Suppress text events if it happens during resetting. Ideally this would be
    -+            // suppressed by the text view not being shown, but that doesn't work here because it
    -+            // needs to stay visible for the animation.
    -+            return false;
    -+        }
    -+        return super.onRequestSendAccessibilityEvent(child, event);
    -     }
    - 
    -     private void updateSendButton() {
    -@@ -414,6 +434,24 @@ public class RemoteInputView extends LinearLayout implements View.OnClickListene
    -         mRevealR = r;
    -     }
    - 
    -+    @Override
    -+    public void dispatchStartTemporaryDetach() {
    -+        super.dispatchStartTemporaryDetach();
    -+        // Detach the EditText temporarily such that it doesn't get onDetachedFromWindow and
    -+        // won't lose IME focus.
    -+        detachViewFromParent(mEditText);
    -+    }
    -+
    -+    @Override
    -+    public void dispatchFinishTemporaryDetach() {
    -+        if (isAttachedToWindow()) {
    -+            attachViewToParent(mEditText, 0, mEditText.getLayoutParams());
    -+        } else {
    -+            removeDetachedView(mEditText, false /* animate */);
    -+        }
    -+        super.dispatchFinishTemporaryDetach();
    -+    }
    -+
    -     /**
    -      * An EditText that changes appearance based on whether it's focusable and becomes
    -      * un-focusable whenever the user navigates away from it or it becomes invisible.
    -@@ -430,7 +468,15 @@ public class RemoteInputView extends LinearLayout implements View.OnClickListene
    -         }
    - 
    -         private void defocusIfNeeded(boolean animate) {
    --            if (mRemoteInputView != null && mRemoteInputView.mEntry.row.isChangingPosition()) {
    -+            if (mRemoteInputView != null && mRemoteInputView.mEntry.row.isChangingPosition()
    -+                    || isTemporarilyDetached()) {
    -+                if (isTemporarilyDetached()) {
    -+                    // We might get reattached but then the other one of HUN / expanded might steal
    -+                    // our focus, so we'll need to save our text here.
    -+                    if (mRemoteInputView != null) {
    -+                        mRemoteInputView.mEntry.remoteInputText = getText();
    -+                    }
    -+                }
    -                 return;
    -             }
    -             if (isFocusable() && isEnabled()) {
    -diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/AmbientState.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/AmbientState.java
    -index 50e5b88..81da672 100644
    ---- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/AmbientState.java
    -+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/AmbientState.java
    -@@ -43,6 +43,7 @@ public class AmbientState {
    -     private boolean mShadeExpanded;
    -     private float mMaxHeadsUpTranslation;
    -     private boolean mDismissAllInProgress;
    -+    private int mLayoutMinHeight;
    - 
    -     public int getScrollY() {
    -         return mScrollY;
    -@@ -137,10 +138,6 @@ public class AmbientState {
    -         mStackTranslation = stackTranslation;
    -     }
    - 
    --    public int getLayoutHeight() {
    --        return mLayoutHeight;
    --    }
    --
    -     public void setLayoutHeight(int layoutHeight) {
    -         mLayoutHeight = layoutHeight;
    -     }
    -@@ -154,7 +151,7 @@ public class AmbientState {
    -     }
    - 
    -     public int getInnerHeight() {
    --        return mLayoutHeight - mTopPadding;
    -+        return Math.max(mLayoutHeight - mTopPadding, mLayoutMinHeight);
    -     }
    - 
    -     public boolean isShadeExpanded() {
    -@@ -180,4 +177,8 @@ public class AmbientState {
    -     public boolean isDismissAllInProgress() {
    -         return mDismissAllInProgress;
    -     }
    -+
    -+    public void setLayoutMinHeight(int layoutMinHeight) {
    -+        mLayoutMinHeight = layoutMinHeight;
    -+    }
    - }
    -diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationChildrenContainer.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationChildrenContainer.java
    -index 3c9373b..d7920a9 100644
    ---- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationChildrenContainer.java
    -+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationChildrenContainer.java
    -@@ -123,8 +123,10 @@ public class NotificationChildrenContainer extends ViewGroup {
    -             mDividers.get(i).layout(0, 0, getWidth(), mDividerHeight);
    -         }
    -         if (mOverflowNumber != null) {
    --            mOverflowNumber.layout(getWidth() - mOverflowNumber.getMeasuredWidth(), 0, getWidth(),
    --                    mOverflowNumber.getMeasuredHeight());
    -+            boolean isRtl = getLayoutDirection() == LAYOUT_DIRECTION_RTL;
    -+            int left = (isRtl ? 0 : getWidth() - mOverflowNumber.getMeasuredWidth());
    -+            int right = left + mOverflowNumber.getMeasuredWidth();
    -+            mOverflowNumber.layout(left, 0, right, mOverflowNumber.getMeasuredHeight());
    -         }
    -         if (mNotificationHeader != null) {
    -             mNotificationHeader.layout(0, 0, mNotificationHeader.getMeasuredWidth(),
    -diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
    -index c8c4310..a6fe438 100644
    ---- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
    -+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
    -@@ -111,11 +111,7 @@ public class NotificationStackScrollLayout extends ViewGroup
    -     private int mCurrentStackHeight = Integer.MAX_VALUE;
    -     private final Paint mBackgroundPaint = new Paint();
    - 
    --    /**
    --     * mCurrentStackHeight is the actual stack height, mLastSetStackHeight is the stack height set
    --     * externally from {@link #setStackHeight}
    --     */
    --    private float mLastSetStackHeight;
    -+    private float mExpandedHeight;
    -     private int mOwnScrollY;
    -     private int mMaxLayoutHeight;
    - 
    -@@ -130,7 +126,7 @@ public class NotificationStackScrollLayout extends ViewGroup
    -     private boolean mIsBeingDragged;
    -     private int mLastMotionY;
    -     private int mDownX;
    --    private int mActivePointerId;
    -+    private int mActivePointerId = INVALID_POINTER;
    -     private boolean mTouchIsClick;
    -     private float mInitialTouchX;
    -     private float mInitialTouchY;
    -@@ -216,7 +212,6 @@ public class NotificationStackScrollLayout extends ViewGroup
    -     private float mTopPaddingOverflow;
    -     private boolean mDontReportNextOverScroll;
    -     private boolean mDontClampNextScroll;
    --    private boolean mRequestViewResizeAnimationOnLayout;
    -     private boolean mNeedViewResizeAnimation;
    -     private View mExpandedGroupView;
    -     private boolean mEverythingNeedsAnimation;
    -@@ -355,6 +350,9 @@ public class NotificationStackScrollLayout extends ViewGroup
    -                     return object.getBackgroundFadeAmount();
    -                 }
    -             };
    -+    private boolean mQsExpanded;
    -+    private boolean mForwardScrollable;
    -+    private boolean mBackwardScrollable;
    - 
    -     public NotificationStackScrollLayout(Context context) {
    -         this(context, null);
    -@@ -518,12 +516,9 @@ public class NotificationStackScrollLayout extends ViewGroup
    -         setMaxLayoutHeight(getHeight());
    -         updateContentHeight();
    -         clampScrollPosition();
    --        if (mRequestViewResizeAnimationOnLayout) {
    --            requestAnimationOnViewResize(null);
    --            mRequestViewResizeAnimationOnLayout = false;
    --        }
    -         requestChildrenUpdate();
    -         updateFirstAndLastBackgroundViews();
    -+        updateAlgorithmLayoutMinHeight();
    -     }
    - 
    -     private void requestAnimationOnViewResize(ExpandableNotificationRow row) {
    -@@ -565,9 +560,14 @@ public class NotificationStackScrollLayout extends ViewGroup
    - 
    -     private void updateAlgorithmHeightAndPadding() {
    -         mAmbientState.setLayoutHeight(getLayoutHeight());
    -+        updateAlgorithmLayoutMinHeight();
    -         mAmbientState.setTopPadding(mTopPadding);
    -     }
    - 
    -+    private void updateAlgorithmLayoutMinHeight() {
    -+        mAmbientState.setLayoutMinHeight(mQsExpanded && !onKeyguard() ? getLayoutMinHeight() : 0);
    -+    }
    -+
    -     /**
    -      * Updates the children views according to the stack scroll algorithm. Call this whenever
    -      * modifications to {@link #mOwnScrollY} are performed to reflect it in the view layout.
    -@@ -598,7 +598,7 @@ public class NotificationStackScrollLayout extends ViewGroup
    -                 if (startingPosition < mOwnScrollY) {
    -                     // This child starts off screen, so let's keep it offscreen to keep the others visible
    - 
    --                    mOwnScrollY += childHeight;
    -+                    setOwnScrollY(mOwnScrollY + childHeight);
    -                 }
    -             }
    -         }
    -@@ -621,7 +621,7 @@ public class NotificationStackScrollLayout extends ViewGroup
    -             // Only apply the scroll if we're scrolling the view upwards, or the view is so far up
    -             // that it is not visible anymore.
    -             if (mOwnScrollY < targetScroll || outOfViewScroll < mOwnScrollY) {
    --                mOwnScrollY = targetScroll;
    -+                setOwnScrollY(targetScroll);
    -             }
    -         }
    -     }
    -@@ -641,7 +641,7 @@ public class NotificationStackScrollLayout extends ViewGroup
    -     private void clampScrollPosition() {
    -         int scrollRange = getScrollRange();
    -         if (scrollRange < mOwnScrollY) {
    --            mOwnScrollY = scrollRange;
    -+            setOwnScrollY(scrollRange);
    -         }
    -     }
    - 
    -@@ -664,19 +664,19 @@ public class NotificationStackScrollLayout extends ViewGroup
    -     }
    - 
    -     /**
    --     * Update the height of the stack to a new height.
    -+     * Update the height of the panel.
    -      *
    --     * @param height the new height of the stack
    -+     * @param height the expanded height of the panel
    -      */
    --    public void setStackHeight(float height) {
    --        mLastSetStackHeight = height;
    -+    public void setExpandedHeight(float height) {
    -+        mExpandedHeight = height;
    -         setIsExpanded(height > 0.0f);
    -         int stackHeight;
    -         float translationY;
    -         float appearEndPosition = getAppearEndPosition();
    -         float appearStartPosition = getAppearStartPosition();
    -         if (height >= appearEndPosition) {
    --            translationY = mTopPaddingOverflow;
    -+            translationY = 0;
    -             stackHeight = (int) height;
    -         } else {
    -             float appearFraction = getAppearFraction(height);
    -@@ -703,8 +703,12 @@ public class NotificationStackScrollLayout extends ViewGroup
    -      *         Measured relative to the resting position.
    -      */
    -     private float getExpandTranslationStart() {
    --        int startPosition = mTrackingHeadsUp || mHeadsUpManager.hasPinnedHeadsUp()
    --                ? 0 : -getFirstChildIntrinsicHeight();
    -+        int startPosition = 0;
    -+        if (!mTrackingHeadsUp && !mHeadsUpManager.hasPinnedHeadsUp()) {
    -+            startPosition = - Math.min(getFirstChildIntrinsicHeight(),
    -+                    mMaxLayoutHeight - mIntrinsicPadding - mBottomStackSlowDownHeight
    -+                            - mBottomStackPeekSize);
    -+        }
    -         return startPosition - mTopPadding;
    -     }
    - 
    -@@ -727,7 +731,7 @@ public class NotificationStackScrollLayout extends ViewGroup
    -                 ? mHeadsUpManager.getTopHeadsUpPinnedHeight() + mBottomStackPeekSize
    -                         + mBottomStackSlowDownHeight
    -                 : getLayoutMinHeight();
    --        return firstItemHeight + mTopPadding + mTopPaddingOverflow;
    -+        return firstItemHeight + (onKeyguard() ? mTopPadding : mIntrinsicPadding);
    -     }
    - 
    -     /**
    -@@ -1052,7 +1056,7 @@ public class NotificationStackScrollLayout extends ViewGroup
    -     @Override
    -     public int getMaxExpandHeight(ExpandableView view) {
    -         int maxContentHeight = view.getMaxContentHeight();
    --        if (view.isSummaryWithChildren()) {
    -+        if (view.isSummaryWithChildren() && view.getParent() == this) {
    -             // Faking a measure with the group expanded to simulate how the group would look if
    -             // it was. Doing a calculation here would be highly non-trivial because of the
    -             // algorithm
    -@@ -1067,8 +1071,11 @@ public class NotificationStackScrollLayout extends ViewGroup
    -                     row.getStatusBarNotification());
    -             mGroupExpandedForMeasure = false;
    -             row.setForceUnlocked(false);
    --            int height = mCurrentStackScrollState.getViewStateForView(view).height;
    --            return Math.min(height, maxContentHeight);
    -+            StackViewState viewState = mCurrentStackScrollState.getViewStateForView(view);
    -+            if (viewState != null) {
    -+                // The view could have been removed
    -+                return Math.min(viewState.height, maxContentHeight);
    -+            }
    -         }
    -         return maxContentHeight;
    -     }
    -@@ -1157,6 +1164,10 @@ public class NotificationStackScrollLayout extends ViewGroup
    - 
    -     @Override
    -     public boolean isAntiFalsingNeeded() {
    -+        return onKeyguard();
    -+    }
    -+
    -+    private boolean onKeyguard() {
    -         return mPhoneStatusBar.getBarState() == StatusBarState.KEYGUARD;
    -     }
    - 
    -@@ -1233,7 +1244,7 @@ public class NotificationStackScrollLayout extends ViewGroup
    -         if (!isScrollingEnabled()) {
    -             return false;
    -         }
    --        if (ev.getY() < mQsContainer.getBottom()) {
    -+        if (ev.getY() < mQsContainer.getBottom() && !mIsBeingDragged) {
    -             return false;
    -         }
    -         mForcedScroll = null;
    -@@ -1400,7 +1411,7 @@ public class NotificationStackScrollLayout extends ViewGroup
    -                         false /* onTop */,
    -                         false /* animate */);
    -             }
    --            mOwnScrollY = range;
    -+            setOwnScrollY(range);
    -             scrollAmount = 0.0f;
    -         }
    -         return scrollAmount;
    -@@ -1431,7 +1442,7 @@ public class NotificationStackScrollLayout extends ViewGroup
    -             setOverScrolledPixels(currentTopPixels - newScrollY,
    -                     true /* onTop */,
    -                     false /* animate */);
    --            mOwnScrollY = 0;
    -+            setOwnScrollY(0);
    -             scrollAmount = 0.0f;
    -         }
    -         return scrollAmount;
    -@@ -1646,7 +1657,7 @@ public class NotificationStackScrollLayout extends ViewGroup
    -     }
    - 
    -     private void customScrollTo(int y) {
    --        mOwnScrollY = y;
    -+        setOwnScrollY(y);
    -         updateChildren();
    -     }
    - 
    -@@ -1657,7 +1668,7 @@ public class NotificationStackScrollLayout extends ViewGroup
    -             final int oldX = mScrollX;
    -             final int oldY = mOwnScrollY;
    -             mScrollX = scrollX;
    --            mOwnScrollY = scrollY;
    -+            setOwnScrollY(scrollY);
    -             if (clampedY) {
    -                 springBack();
    -             } else {
    -@@ -1687,12 +1698,12 @@ public class NotificationStackScrollLayout extends ViewGroup
    -             if (overScrolledTop) {
    -                 onTop = true;
    -                 newAmount = -mOwnScrollY;
    --                mOwnScrollY = 0;
    -+                setOwnScrollY(0);
    -                 mDontReportNextOverScroll = true;
    -             } else {
    -                 onTop = false;
    -                 newAmount = mOwnScrollY - scrollRange;
    --                mOwnScrollY = scrollRange;
    -+                setOwnScrollY(scrollRange);
    -             }
    -             setOverScrollAmount(newAmount, onTop, false);
    -             setOverScrollAmount(0.0f, onTop, true);
    -@@ -1820,6 +1831,19 @@ public class NotificationStackScrollLayout extends ViewGroup
    -         if (scrollable != mScrollable) {
    -             mScrollable = scrollable;
    -             setFocusable(scrollable);
    -+            updateForwardAndBackwardScrollability();
    -+        }
    -+    }
    -+
    -+    private void updateForwardAndBackwardScrollability() {
    -+        boolean forwardScrollable = mScrollable && mOwnScrollY < getScrollRange();
    -+        boolean backwardsScrollable = mScrollable && mOwnScrollY > 0;
    -+        boolean changed = forwardScrollable != mForwardScrollable
    -+                || backwardsScrollable != mBackwardScrollable;
    -+        mForwardScrollable = forwardScrollable;
    -+        mBackwardScrollable = backwardsScrollable;
    -+        if (changed) {
    -+            sendAccessibilityEvent(AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED);
    -         }
    -     }
    - 
    -@@ -1829,24 +1853,34 @@ public class NotificationStackScrollLayout extends ViewGroup
    -         }
    -         updateBackgroundBounds();
    -         if (!mCurrentBounds.equals(mBackgroundBounds)) {
    --            if (mAnimateNextBackgroundTop || mAnimateNextBackgroundBottom || areBoundsAnimating()) {
    -+            boolean animate = mAnimateNextBackgroundTop || mAnimateNextBackgroundBottom
    -+                    || areBoundsAnimating();
    -+            if (!isExpanded()) {
    -+                abortBackgroundAnimators();
    -+                animate = false;
    -+            }
    -+            if (animate) {
    -                 startBackgroundAnimation();
    -             } else {
    -                 mCurrentBounds.set(mBackgroundBounds);
    -                 applyCurrentBackgroundBounds();
    -             }
    -         } else {
    --            if (mBottomAnimator != null) {
    --                mBottomAnimator.cancel();
    --            }
    --            if (mTopAnimator != null) {
    --                mTopAnimator.cancel();
    --            }
    -+            abortBackgroundAnimators();
    -         }
    -         mAnimateNextBackgroundBottom = false;
    -         mAnimateNextBackgroundTop = false;
    -     }
    - 
    -+    private void abortBackgroundAnimators() {
    -+        if (mBottomAnimator != null) {
    -+            mBottomAnimator.cancel();
    -+        }
    -+        if (mTopAnimator != null) {
    -+            mTopAnimator.cancel();
    -+        }
    -+    }
    -+
    -     private boolean areBoundsAnimating() {
    -         return mBottomAnimator != null || mTopAnimator != null;
    -     }
    -@@ -1966,9 +2000,9 @@ public class NotificationStackScrollLayout extends ViewGroup
    -     }
    - 
    -     private void applyCurrentBackgroundBounds() {
    --        if (!mFadingOut) {
    --            mScrimController.setExcludedBackgroundArea(mCurrentBounds);
    --        }
    -+        mScrimController.setExcludedBackgroundArea(
    -+                mFadingOut || mParentFadingOut || mAmbientState.isDark() ? null
    -+                        : mCurrentBounds);
    -         invalidate();
    -     }
    - 
    -@@ -1981,6 +2015,7 @@ public class NotificationStackScrollLayout extends ViewGroup
    -         if (!mIsExpanded) {
    -             mBackgroundBounds.top = 0;
    -             mBackgroundBounds.bottom = 0;
    -+            return;
    -         }
    -         ActivatableNotificationView firstView = mFirstVisibleBackgroundChild;
    -         int top = 0;
    -@@ -2078,13 +2113,13 @@ public class NotificationStackScrollLayout extends ViewGroup
    -             float topAmount = getCurrentOverScrollAmount(true);
    -             float bottomAmount = getCurrentOverScrollAmount(false);
    -             if (velocityY < 0 && topAmount > 0) {
    --                mOwnScrollY -= (int) topAmount;
    -+                setOwnScrollY(mOwnScrollY - (int) topAmount);
    -                 mDontReportNextOverScroll = true;
    -                 setOverScrollAmount(0, true, false);
    -                 mMaxOverScroll = Math.abs(velocityY) / 1000f * getRubberBandFactor(true /* onTop */)
    -                         * mOverflingDistance + topAmount;
    -             } else if (velocityY > 0 && bottomAmount > 0) {
    --                mOwnScrollY += bottomAmount;
    -+                setOwnScrollY((int) (mOwnScrollY + bottomAmount));
    -                 setOverScrollAmount(0, false, false);
    -                 mMaxOverScroll = Math.abs(velocityY) / 1000f
    -                         * getRubberBandFactor(false /* onTop */) * mOverflingDistance
    -@@ -2127,26 +2162,22 @@ public class NotificationStackScrollLayout extends ViewGroup
    -      */
    -     public void updateTopPadding(float qsHeight, boolean animate,
    -             boolean ignoreIntrinsicPadding) {
    --        float start = qsHeight;
    --        float stackHeight = getHeight() - start;
    -+        int topPadding = (int) qsHeight;
    -         int minStackHeight = getLayoutMinHeight();
    --        if (stackHeight <= minStackHeight) {
    --            float overflow = minStackHeight - stackHeight;
    --            stackHeight = minStackHeight;
    --            start = getHeight() - stackHeight;
    --            mTopPaddingOverflow = overflow;
    -+        if (topPadding + minStackHeight > getHeight()) {
    -+            mTopPaddingOverflow = topPadding + minStackHeight - getHeight();
    -         } else {
    -             mTopPaddingOverflow = 0;
    -         }
    --        setTopPadding(ignoreIntrinsicPadding ? (int) start : clampPadding((int) start),
    -+        setTopPadding(ignoreIntrinsicPadding ? topPadding : clampPadding(topPadding),
    -                 animate);
    --        setStackHeight(mLastSetStackHeight);
    -+        setExpandedHeight(mExpandedHeight);
    -     }
    - 
    -     public int getLayoutMinHeight() {
    -         int firstChildMinHeight = getFirstChildIntrinsicHeight();
    -         return Math.min(firstChildMinHeight + mBottomStackPeekSize + mBottomStackSlowDownHeight,
    --                mMaxLayoutHeight - mTopPadding);
    -+                mMaxLayoutHeight - mIntrinsicPadding);
    -     }
    - 
    -     public int getFirstChildIntrinsicHeight() {
    -@@ -2439,11 +2470,11 @@ public class NotificationStackScrollLayout extends ViewGroup
    -         if (endPosition <= mOwnScrollY) {
    -             // This child is fully scrolled of the top, so we have to deduct its height from the
    -             // scrollPosition
    --            mOwnScrollY -= childHeight;
    -+            setOwnScrollY(mOwnScrollY - childHeight);
    -         } else if (startingPosition < mOwnScrollY) {
    -             // This child is currently being scrolled into, set the scroll position to the start of
    -             // this child
    --            mOwnScrollY = startingPosition;
    -+            setOwnScrollY(startingPosition);
    -         }
    -     }
    - 
    -@@ -3024,7 +3055,7 @@ public class NotificationStackScrollLayout extends ViewGroup
    -     public void onExpansionStopped() {
    -         mIsExpansionChanging = false;
    -         if (!mIsExpanded) {
    --            mOwnScrollY = 0;
    -+            setOwnScrollY(0);
    -             mPhoneStatusBar.resetUserExpandedStates();
    - 
    -             // lets make sure nothing is in the overlay / transient anymore
    -@@ -3057,7 +3088,7 @@ public class NotificationStackScrollLayout extends ViewGroup
    - 
    -     public void resetScrollPosition() {
    -         mScroller.abortAnimation();
    --        mOwnScrollY = 0;
    -+        setOwnScrollY(0);
    -     }
    - 
    -     private void setIsExpanded(boolean isExpanded) {
    -@@ -3093,10 +3124,14 @@ public class NotificationStackScrollLayout extends ViewGroup
    -         updateScrollPositionOnExpandInBottom(view);
    -         clampScrollPosition();
    -         notifyHeightChangeListener(view);
    -+        ExpandableNotificationRow row = view instanceof ExpandableNotificationRow
    -+                ? (ExpandableNotificationRow) view
    -+                : null;
    -+        if (row != null && (row == mFirstVisibleBackgroundChild
    -+                || row.getNotificationParent() == mFirstVisibleBackgroundChild)) {
    -+            updateAlgorithmLayoutMinHeight();
    -+        }
    -         if (needsAnimation) {
    --            ExpandableNotificationRow row = view instanceof ExpandableNotificationRow
    --                    ? (ExpandableNotificationRow) view
    --                    : null;
    -             requestAnimationOnViewResize(row);
    -         }
    -         requestChildrenUpdate();
    -@@ -3104,9 +3139,6 @@ public class NotificationStackScrollLayout extends ViewGroup
    - 
    -     @Override
    -     public void onReset(ExpandableView view) {
    --        if (mIsExpanded && mAnimationsEnabled) {
    --            mRequestViewResizeAnimationOnLayout = true;
    --        }
    -         updateAnimationState(view);
    -         updateChronometerForChild(view);
    -     }
    -@@ -3125,7 +3157,7 @@ public class NotificationStackScrollLayout extends ViewGroup
    -                 }
    -                 int stackEnd = getStackEndPosition();
    -                 if (endPosition > stackEnd) {
    --                    mOwnScrollY += endPosition - stackEnd;
    -+                    setOwnScrollY((int) (mOwnScrollY + endPosition - stackEnd));
    -                     mDisallowScrollingInThisMotion = true;
    -                 }
    -             }
    -@@ -3382,7 +3414,7 @@ public class NotificationStackScrollLayout extends ViewGroup
    -     }
    - 
    -     private int findDarkAnimationOriginIndex(@Nullable PointF screenLocation) {
    --        if (screenLocation == null || screenLocation.y < mTopPadding + mTopPaddingOverflow) {
    -+        if (screenLocation == null || screenLocation.y < mTopPadding) {
    -             return AnimationEvent.DARK_ANIMATION_ORIGIN_INDEX_ABOVE;
    -         }
    -         if (screenLocation.y > getBottomMostNotificationBottom()) {
    -@@ -3687,15 +3719,14 @@ public class NotificationStackScrollLayout extends ViewGroup
    -     @Override
    -     public void onInitializeAccessibilityNodeInfoInternal(AccessibilityNodeInfo info) {
    -         super.onInitializeAccessibilityNodeInfoInternal(info);
    --        final int scrollRange = getScrollRange();
    --        if (scrollRange > 0) {
    -+        if (mScrollable) {
    -             info.setScrollable(true);
    --            if (mScrollY > 0) {
    -+            if (mBackwardScrollable) {
    -                 info.addAction(
    -                         AccessibilityNodeInfo.AccessibilityAction.ACTION_SCROLL_BACKWARD);
    -                 info.addAction(AccessibilityNodeInfo.AccessibilityAction.ACTION_SCROLL_UP);
    -             }
    --            if (mScrollY < scrollRange) {
    -+            if (mForwardScrollable) {
    -                 info.addAction(AccessibilityNodeInfo.AccessibilityAction.ACTION_SCROLL_FORWARD);
    -                 info.addAction(AccessibilityNodeInfo.AccessibilityAction.ACTION_SCROLL_DOWN);
    -             }
    -@@ -3847,11 +3878,7 @@ public class NotificationStackScrollLayout extends ViewGroup
    -     }
    - 
    -     private void updateFadingState() {
    --        if (mFadingOut || mParentFadingOut || mAmbientState.isDark()) {
    --            mScrimController.setExcludedBackgroundArea(null);
    --        } else {
    --            applyCurrentBackgroundBounds();
    --        }
    -+        applyCurrentBackgroundBounds();
    -         updateSrcDrawing();
    -     }
    - 
    -@@ -3870,6 +3897,18 @@ public class NotificationStackScrollLayout extends ViewGroup
    -         mCurrentStackScrollState.removeViewStateForView(view);
    -     }
    - 
    -+    public void setQsExpanded(boolean qsExpanded) {
    -+        mQsExpanded = qsExpanded;
    -+        updateAlgorithmLayoutMinHeight();
    -+    }
    -+
    -+    public void setOwnScrollY(int ownScrollY) {
    -+        if (ownScrollY != mOwnScrollY) {
    -+            mOwnScrollY = ownScrollY;
    -+            updateForwardAndBackwardScrollability();
    -+        }
    -+    }
    -+
    -     /**
    -      * A listener that is notified when some child locations might have changed.
    -      */
    -@@ -3912,6 +3951,7 @@ public class NotificationStackScrollLayout extends ViewGroup
    -     private class NotificationSwipeHelper extends SwipeHelper {
    -         private static final long SHOW_GEAR_DELAY = 60;
    -         private static final long COVER_GEAR_DELAY = 4000;
    -+        private static final long SWIPE_GEAR_TIMING = 200;
    -         private CheckForDrag mCheckForDrag;
    -         private Runnable mFalsingCheck;
    -         private Handler mHandler;
    -@@ -4028,6 +4068,9 @@ public class NotificationStackScrollLayout extends ViewGroup
    - 
    -             boolean gestureTowardsGear = isTowardsGear(velocity, mCurrIconRow.isIconOnLeft());
    -             boolean gestureFastEnough = Math.abs(velocity) > getEscapeVelocity();
    -+            final double timeForGesture = ev.getEventTime() - ev.getDownTime();
    -+            final boolean showGearForSlowOnGoing = !canChildBeDismissed(animView)
    -+                && timeForGesture >= SWIPE_GEAR_TIMING;
    - 
    -             if (mGearSnappedTo && mCurrIconRow.isVisible()) {
    -                 if (mGearSnappedOnLeft == mCurrIconRow.isIconOnLeft()) {
    -@@ -4052,7 +4095,8 @@ public class NotificationStackScrollLayout extends ViewGroup
    -                 } else {
    -                     dismissOrSnapBack(animView, velocity, ev);
    -                 }
    --            } else if ((!gestureFastEnough && swipedEnoughToShowGear(animView))
    -+            } else if (((!gestureFastEnough || showGearForSlowOnGoing)
    -+                    && swipedEnoughToShowGear(animView))
    -                     || gestureTowardsGear) {
    -                 // Gear has not been snapped to previously and this is gear revealing gesture
    -                 snapToGear(animView, velocity);
    -@@ -4088,7 +4132,7 @@ public class NotificationStackScrollLayout extends ViewGroup
    -             onDragCancelled(animView);
    - 
    -             // If we're on the lockscreen we want to false this.
    --            if (mPhoneStatusBar.getBarState() == StatusBarState.KEYGUARD) {
    -+            if (isAntiFalsingNeeded()) {
    -                 mHandler.removeCallbacks(mFalsingCheck);
    -                 mHandler.postDelayed(mFalsingCheck, COVER_GEAR_DELAY);
    -             }
    -@@ -4104,13 +4148,9 @@ public class NotificationStackScrollLayout extends ViewGroup
    -             final float multiplier = canChildBeDismissed(animView) ? 0.4f : 0.2f;
    -             final float snapBackThreshold = getSpaceForGear(animView) * multiplier;
    -             final float translation = getTranslation(animView);
    --            final boolean fromLeft = translation > 0;
    --            final float absTrans = Math.abs(translation);
    --            final float notiThreshold = getSize(mTranslatingParentView) * 0.4f;
    --
    --            return mCurrIconRow.isVisible() && (mCurrIconRow.isIconOnLeft()
    --                    ? (translation > snapBackThreshold && translation <= notiThreshold)
    --                    : (translation < -snapBackThreshold && translation >= -notiThreshold));
    -+            return !swipedFarEnough() && mCurrIconRow.isVisible() && (mCurrIconRow.isIconOnLeft()
    -+                    ? translation > snapBackThreshold
    -+                    : translation < -snapBackThreshold);
    -         }
    - 
    -         @Override
    -@@ -4151,13 +4191,11 @@ public class NotificationStackScrollLayout extends ViewGroup
    -                 final int rx = (int) ev.getRawX();
    -                 final int ry = (int) ev.getRawY();
    - 
    --                getLocationOnScreen(mTempInt2);
    --                int[] location = new int[2];
    --                view.getLocationOnScreen(location);
    --                final int x = location[0] - mTempInt2[0];
    --                final int y = location[1] - mTempInt2[1];
    -+                view.getLocationOnScreen(mTempInt2);
    -+                final int x = mTempInt2[0];
    -+                final int y = mTempInt2[1];
    -                 Rect rect = new Rect(x, y, x + view.getWidth(), y + height);
    --                if (!rect.contains((int) rx, (int) ry)) {
    -+                if (!rect.contains(rx, ry)) {
    -                     // Touch was outside visible guts / gear notification, close what's visible
    -                     mPhoneStatusBar.dismissPopups(-1, -1, true /* resetGear */, true /* animate */);
    -                 }
    -diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/tv/TvStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/tv/TvStatusBar.java
    -index 2d4900b..3c83921 100644
    ---- a/packages/SystemUI/src/com/android/systemui/statusbar/tv/TvStatusBar.java
    -+++ b/packages/SystemUI/src/com/android/systemui/statusbar/tv/TvStatusBar.java
    -@@ -19,7 +19,6 @@ package com.android.systemui.statusbar.tv;
    - import android.content.ComponentName;
    - import android.graphics.Rect;
    - import android.os.IBinder;
    --import android.os.RemoteException;
    - import android.service.notification.NotificationListenerService.RankingMap;
    - import android.service.notification.StatusBarNotification;
    - import android.view.View;
    -@@ -36,16 +35,6 @@ import com.android.systemui.tv.pip.PipManager;
    - 
    - public class TvStatusBar extends BaseStatusBar {
    - 
    --    /**
    --     * Tracking calls to View.setSystemUiVisibility().
    --     */
    --    int mSystemUiVisibility = View.SYSTEM_UI_FLAG_VISIBLE;
    --
    --    /**
    --     * Last value sent to window manager.
    --     */
    --    private int mLastDispatchedSystemUiVisibility = ~View.SYSTEM_UI_FLAG_VISIBLE;
    --
    -     @Override
    -     public void setIcon(String slot, StatusBarIcon icon) {
    -     }
    -@@ -224,40 +213,6 @@ public class TvStatusBar extends BaseStatusBar {
    -         putComponent(TvStatusBar.class, this);
    -     }
    - 
    --    /**
    --     * Updates the visibility of the picture-in-picture.
    --     */
    --    public void updatePipVisibility(boolean visible) {
    --        if (visible) {
    --            mSystemUiVisibility |= View.TV_PICTURE_IN_PICTURE_VISIBLE;
    --        } else {
    --            mSystemUiVisibility &= ~View.TV_PICTURE_IN_PICTURE_VISIBLE;
    --        }
    --        notifyUiVisibilityChanged(mSystemUiVisibility);
    --    }
    --
    --    /**
    --     * Updates the visibility of the Recents
    --     */
    --    public void updateRecentsVisibility(boolean visible) {
    --        if (visible) {
    --            mSystemUiVisibility |= View.RECENT_APPS_VISIBLE;
    --        } else {
    --            mSystemUiVisibility &= ~View.RECENT_APPS_VISIBLE;
    --        }
    --        notifyUiVisibilityChanged(mSystemUiVisibility);
    --    }
    --
    --    private void notifyUiVisibilityChanged(int vis) {
    --        try {
    --            if (mLastDispatchedSystemUiVisibility != vis) {
    --                mWindowManagerService.statusBarVisibilityChanged(vis);
    --                mLastDispatchedSystemUiVisibility = vis;
    --            }
    --        } catch (RemoteException ex) {
    --        }
    --    }
    --
    -     @Override
    -     public void handleSystemNavigationKey(int arg1) {
    -         // Not implemented
    -diff --git a/packages/SystemUI/src/com/android/systemui/tuner/TunerFragment.java b/packages/SystemUI/src/com/android/systemui/tuner/TunerFragment.java
    -index 70f2fdc..ba50161 100644
    ---- a/packages/SystemUI/src/com/android/systemui/tuner/TunerFragment.java
    -+++ b/packages/SystemUI/src/com/android/systemui/tuner/TunerFragment.java
    -@@ -59,7 +59,10 @@ public class TunerFragment extends PreferenceFragment {
    -     @Override
    -     public void onActivityCreated(Bundle savedInstanceState) {
    -         super.onActivityCreated(savedInstanceState);
    --        getActivity().getActionBar().setDisplayHomeAsUpEnabled(true);
    -+
    -+        if (getActivity().getActionBar() != null) {
    -+            getActivity().getActionBar().setDisplayHomeAsUpEnabled(true);
    -+        }
    -     }
    - 
    -     @Override
    -diff --git a/packages/SystemUI/src/com/android/systemui/tv/pip/PipManager.java b/packages/SystemUI/src/com/android/systemui/tv/pip/PipManager.java
    -index 5e4854c..085e003 100644
    ---- a/packages/SystemUI/src/com/android/systemui/tv/pip/PipManager.java
    -+++ b/packages/SystemUI/src/com/android/systemui/tv/pip/PipManager.java
    -@@ -78,6 +78,18 @@ public class PipManager {
    -         sSettingsPackageAndClassNamePairList.add(new Pair<String, String>(
    -                 "com.google.android.leanbacklauncher",
    -                 "com.google.android.leanbacklauncher.settings.HomeScreenSettingsActivity"));
    -+        sSettingsPackageAndClassNamePairList.add(new Pair<String, String>(
    -+                "com.google.android.apps.mediashell",
    -+                "com.google.android.apps.mediashell.settings.CastSettingsActivity"));
    -+        sSettingsPackageAndClassNamePairList.add(new Pair<String, String>(
    -+                "com.google.android.katniss",
    -+                "com.google.android.katniss.setting.SpeechSettingsActivity"));
    -+        sSettingsPackageAndClassNamePairList.add(new Pair<String, String>(
    -+                "com.google.android.katniss",
    -+                "com.google.android.katniss.setting.SearchSettingsActivity"));
    -+        sSettingsPackageAndClassNamePairList.add(new Pair<String, String>(
    -+                "com.google.android.gsf.notouch",
    -+                "com.google.android.gsf.notouch.UsageDiagnosticsSettingActivity"));
    -     }
    - 
    -     /**
    -@@ -711,10 +723,7 @@ public class PipManager {
    -         return mPipRecentsOverlayManager;
    -     }
    - 
    --    private void updatePipVisibility(boolean visible) {
    --        TvStatusBar statusBar = ((SystemUIApplication) mContext).getComponent(TvStatusBar.class);
    --        if (statusBar != null) {
    --            statusBar.updatePipVisibility(visible);
    --        }
    -+    private void updatePipVisibility(final boolean visible) {
    -+        SystemServicesProxy.getInstance(mContext).setTvPipVisibility(visible);
    -     }
    - }
    -diff --git a/packages/SystemUI/tests/Android.mk b/packages/SystemUI/tests/Android.mk
    -index c9c5805..d122ccc 100644
    ---- a/packages/SystemUI/tests/Android.mk
    -+++ b/packages/SystemUI/tests/Android.mk
    -@@ -58,6 +58,42 @@ LOCAL_STATIC_JAVA_LIBRARIES := \
    - # UI it doesn't own. This is necessary to allow screenshots to be taken
    - LOCAL_CERTIFICATE := platform
    - 
    -+# Provide jack a list of classes to exclude from code coverage.
    -+# This is needed because the SystemUITests compile SystemUI source directly, rather than using
    -+# LOCAL_INSTRUMENTATION_FOR := SystemUI.
    -+#
    -+# We want to exclude the test classes from code coverage measurements, but they share the same
    -+# package as the rest of SystemUI so they can't be easily filtered by package name.
    -+#
    -+# Generate a comma separated list of patterns based on the test source files under src/
    -+# SystemUI classes are in ../src/ so they won't be excluded.
    -+# Example:
    -+#   Input files: src/com/android/systemui/Test.java src/com/android/systemui/AnotherTest.java
    -+#   Generated exclude list: com.android.systemui.Test*,com.android.systemui.AnotherTest*
    -+
    -+# Filter all src files under src/ to just java files
    -+local_java_files := $(filter %.java,$(call all-java-files-under, src))
    -+# Transform java file names into full class names.
    -+# This only works if the class name matches the file name and the directory structure
    -+# matches the package.
    -+local_classes := $(subst /,.,$(patsubst src/%.java,%,$(local_java_files)))
    -+local_comma := ,
    -+local_empty :=
    -+local_space := $(local_empty) $(local_empty)
    -+# Convert class name list to jacoco exclude list
    -+# This appends a * to all classes and replace the space separators with commas.
    -+jacoco_exclude := $(subst $(space),$(comma),$(patsubst %,%*,$(local_classes)))
    -+
    -+LOCAL_JACK_COVERAGE_INCLUDE_FILTER := com.android.systemui.*
    -+LOCAL_JACK_COVERAGE_EXCLUDE_FILTER := com.android.systemui.tests.*,$(jacoco_exclude)
    -+
    - include frameworks/base/packages/SettingsLib/common.mk
    - 
    - include $(BUILD_PACKAGE)
    -+
    -+# Reset variables
    -+local_java_files :=
    -+local_classes :=
    -+local_comma :=
    -+local_space :=
    -+jacoco_exclude :=
    -diff --git a/packages/VpnDialogs/res/values-ro/strings.xml b/packages/VpnDialogs/res/values-ro/strings.xml
    -index 4865e96..e2e1e44 100644
    ---- a/packages/VpnDialogs/res/values-ro/strings.xml
    -+++ b/packages/VpnDialogs/res/values-ro/strings.xml
    -@@ -25,5 +25,5 @@
    -     <string name="duration" msgid="3584782459928719435">"Durată:"</string>
    -     <string name="data_transmitted" msgid="7988167672982199061">"Trimise:"</string>
    -     <string name="data_received" msgid="4062776929376067820">"Primite:"</string>
    --    <string name="data_value_format" msgid="2192466557826897580">"<xliff:g id="NUMBER_0">%1$s</xliff:g> (de) octeți/<xliff:g id="NUMBER_1">%2$s</xliff:g> (de) pachete"</string>
    -+    <string name="data_value_format" msgid="2192466557826897580">"<xliff:g id="NUMBER_0">%1$s</xliff:g>   octeți/<xliff:g id="NUMBER_1">%2$s</xliff:g>   pachete"</string>
    - </resources>
    -diff --git a/packages/WallpaperBackup/src/com/android/wallpaperbackup/WallpaperBackupAgent.java b/packages/WallpaperBackup/src/com/android/wallpaperbackup/WallpaperBackupAgent.java
    -index 3a82f88..ff934ef 100644
    ---- a/packages/WallpaperBackup/src/com/android/wallpaperbackup/WallpaperBackupAgent.java
    -+++ b/packages/WallpaperBackup/src/com/android/wallpaperbackup/WallpaperBackupAgent.java
    -@@ -147,11 +147,12 @@ public class WallpaperBackupAgent extends BackupAgent {
    -             }
    - 
    -             // only back up the wallpapers if we've been told they're eligible
    --            if ((sysEligible || lockEligible) && mWallpaperInfo.exists()) {
    -+            if (mWallpaperInfo.exists()) {
    -                 if (sysChanged || lockChanged || !infoStage.exists()) {
    -                     if (DEBUG) Slog.v(TAG, "New wallpaper configuration; copying");
    -                     FileUtils.copyFileOrThrow(mWallpaperInfo, infoStage);
    -                 }
    -+                if (DEBUG) Slog.v(TAG, "Storing wallpaper metadata");
    -                 fullBackupFile(infoStage, data);
    -             }
    -             if (sysEligible && mWallpaperFile.exists()) {
    -@@ -159,6 +160,7 @@ public class WallpaperBackupAgent extends BackupAgent {
    -                     if (DEBUG) Slog.v(TAG, "New system wallpaper; copying");
    -                     FileUtils.copyFileOrThrow(mWallpaperFile, imageStage);
    -                 }
    -+                if (DEBUG) Slog.v(TAG, "Storing system wallpaper image");
    -                 fullBackupFile(imageStage, data);
    -                 prefs.edit().putInt(SYSTEM_GENERATION, sysGeneration).apply();
    -             }
    -@@ -169,6 +171,7 @@ public class WallpaperBackupAgent extends BackupAgent {
    -                     if (DEBUG) Slog.v(TAG, "New lock wallpaper; copying");
    -                     FileUtils.copyFileOrThrow(mLockWallpaperFile, lockImageStage);
    -                 }
    -+                if (DEBUG) Slog.v(TAG, "Storing lock wallpaper image");
    -                 fullBackupFile(lockImageStage, data);
    -                 prefs.edit().putInt(LOCK_GENERATION, lockGeneration).apply();
    -             }
    -diff --git a/proto/src/metrics_constants.proto b/proto/src/metrics_constants.proto
    -index 5099db7..8a0dfe5 100644
    ---- a/proto/src/metrics_constants.proto
    -+++ b/proto/src/metrics_constants.proto
    -@@ -2207,7 +2207,12 @@ message MetricsEvent {
    -     // CATEGORY: SETTINGS
    -     ACTION_AMBIENT_DISPLAY = 495;
    - 
    -+    // ACTION: Settings -> [sub settings activity] -> Options menu -> Help & Support
    -+    //   SUBTYPE: sub settings classname
    -+    ACTION_SETTING_HELP_AND_FEEDBACK = 496;
    -+
    -     // ---- End N-MR1 Constants, all N-MR1 constants go above this line ----
    -+
    -     // Add new aosp constants above this line.
    -     // END OF AOSP CONSTANTS
    -   }
    -diff --git a/rs/jni/android_renderscript_RenderScript.cpp b/rs/jni/android_renderscript_RenderScript.cpp
    -index aa2a607..37cbd31 100644
    ---- a/rs/jni/android_renderscript_RenderScript.cpp
    -+++ b/rs/jni/android_renderscript_RenderScript.cpp
    -@@ -632,7 +632,7 @@ nScriptIntrinsicBLAS_Single(JNIEnv *_env, jobject _this, jlong con, jlong id, ji
    -     in_allocs[2] = (RsAllocation)C;
    - 
    -     rsScriptForEachMulti((RsContext)con, (RsScript)id, 0,
    --                         in_allocs, sizeof(in_allocs), nullptr,
    -+                         in_allocs, NELEM(in_allocs), nullptr,
    -                          &call, sizeof(call), nullptr, 0);
    - }
    - 
    -diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityGestureDetector.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityGestureDetector.java
    -index 562d950..582b19b 100644
    ---- a/services/accessibility/java/com/android/server/accessibility/AccessibilityGestureDetector.java
    -+++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityGestureDetector.java
    -@@ -341,6 +341,8 @@ class AccessibilityGestureDetector extends GestureDetector.SimpleOnGestureListen
    -         mDoubleTapDetected = false;
    -         mSecondFingerDoubleTap = false;
    -         mGestureStarted = false;
    -+        mGestureDetector.onTouchEvent(MotionEvent.obtain(0L, 0L, MotionEvent.ACTION_CANCEL,
    -+                0.0f, 0.0f, 0));
    -         cancelGesture();
    -     }
    - 
    -diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
    -index 695ea60..e00178f 100644
    ---- a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
    -+++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
    -@@ -2208,6 +2208,8 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub {
    - 
    -         AccessibilityServiceInfo mAccessibilityServiceInfo;
    - 
    -+        // The service that's bound to this instance. Whenever this value is non-null, this
    -+        // object is registered as a death recipient
    -         IBinder mService;
    - 
    -         IAccessibilityServiceClient mServiceInterface;
    -@@ -2342,14 +2344,14 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub {
    -                 }
    -             } else {
    -                 userState.mBindingServices.add(mComponentName);
    --                mService = userState.mUiAutomationServiceClient.asBinder();
    -                 mMainHandler.post(new Runnable() {
    -                     @Override
    -                     public void run() {
    -                         // Simulate asynchronous connection since in onServiceConnected
    -                         // we may modify the state data in case of an error but bind is
    -                         // called while iterating over the data and bad things can happen.
    --                        onServiceConnected(mComponentName, mService);
    -+                        onServiceConnected(mComponentName,
    -+                                userState.mUiAutomationServiceClient.asBinder());
    -                     }
    -                 });
    -                 userState.mUiAutomationService = this;
    -@@ -2441,7 +2443,19 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub {
    -         @Override
    -         public void onServiceConnected(ComponentName componentName, IBinder service) {
    -             synchronized (mLock) {
    --                mService = service;
    -+                if (mService != service) {
    -+                    if (mService != null) {
    -+                        mService.unlinkToDeath(this, 0);
    -+                    }
    -+                    mService = service;
    -+                    try {
    -+                        mService.linkToDeath(this, 0);
    -+                    } catch (RemoteException re) {
    -+                        Slog.e(LOG_TAG, "Failed registering death link");
    -+                        binderDied();
    -+                        return;
    -+                    }
    -+                }
    -                 mServiceInterface = IAccessibilityServiceClient.Stub.asInterface(service);
    -                 UserState userState = getUserStateLocked(mUserId);
    -                 addServiceLocked(this, userState);
    -@@ -3075,7 +3089,6 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub {
    -         }
    - 
    -         public void onAdded() throws RemoteException {
    --            linkToOwnDeathLocked();
    -             final long identity = Binder.clearCallingIdentity();
    -             try {
    -                 mWindowManagerService.addWindowToken(mOverlayWindowToken,
    -@@ -3092,17 +3105,6 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub {
    -             } finally {
    -                 Binder.restoreCallingIdentity(identity);
    -             }
    --            unlinkToOwnDeathLocked();
    --        }
    --
    --        public void linkToOwnDeathLocked() throws RemoteException {
    --            mService.linkToDeath(this, 0);
    --        }
    --
    --        public void unlinkToOwnDeathLocked() {
    --            if (mService != null) {
    --                mService.unlinkToDeath(this, 0);
    --            }
    -         }
    - 
    -         public void resetLocked() {
    -@@ -3115,7 +3117,10 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub {
    -             } catch (RemoteException re) {
    -                 /* ignore */
    -             }
    --            mService = null;
    -+            if (mService != null) {
    -+                mService.unlinkToDeath(this, 0);
    -+                mService = null;
    -+            }
    -             mServiceInterface = null;
    -         }
    - 
    -@@ -3678,13 +3683,6 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub {
    -                 Rect boundsInScreen = mTempRect;
    -                 focus.getBoundsInScreen(boundsInScreen);
    - 
    --                // Clip to the window bounds.
    --                Rect windowBounds = mTempRect1;
    --                getWindowBounds(focus.getWindowId(), windowBounds);
    --                if (!boundsInScreen.intersect(windowBounds)) {
    --                    return false;
    --                }
    --
    -                 // Apply magnification if needed.
    -                 MagnificationSpec spec = getCompatibleMagnificationSpecLocked(focus.getWindowId());
    -                 if (spec != null && !spec.isNop()) {
    -@@ -3692,6 +3690,13 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub {
    -                     boundsInScreen.scale(1 / spec.scale);
    -                 }
    - 
    -+                // Clip to the window bounds.
    -+                Rect windowBounds = mTempRect1;
    -+                getWindowBounds(focus.getWindowId(), windowBounds);
    -+                if (!boundsInScreen.intersect(windowBounds)) {
    -+                    return false;
    -+                }
    -+
    -                 // Clip to the screen bounds.
    -                 Point screenSize = mTempPoint;
    -                 mDefaultDisplay.getRealSize(screenSize);
    -diff --git a/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java b/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java
    -index 9d3889b..b5fcb5c 100644
    ---- a/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java
    -+++ b/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java
    -@@ -2266,6 +2266,7 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku
    -         pw.print(info.updatePeriodMillis);
    -         pw.print(" resizeMode=");
    -         pw.print(info.resizeMode);
    -+        pw.print(" widgetCategory=");
    -         pw.print(info.widgetCategory);
    -         pw.print(" autoAdvanceViewId=");
    -         pw.print(info.autoAdvanceViewId);
    -diff --git a/services/backup/java/com/android/server/backup/BackupManagerService.java b/services/backup/java/com/android/server/backup/BackupManagerService.java
    -index 497eac9..8424b39 100644
    ---- a/services/backup/java/com/android/server/backup/BackupManagerService.java
    -+++ b/services/backup/java/com/android/server/backup/BackupManagerService.java
    -@@ -6057,7 +6057,11 @@ public class BackupManagerService {
    -                                         // the app developer's cert, so they're different on every
    -                                         // device.
    -                                         if (signaturesMatch(sigs, pkgInfo)) {
    --                                            if (pkgInfo.versionCode >= version) {
    -+                                            if ((pkgInfo.applicationInfo.flags
    -+                                                    & ApplicationInfo.FLAG_RESTORE_ANY_VERSION) != 0) {
    -+                                                Slog.i(TAG, "Package has restoreAnyVersion; taking data");
    -+                                                policy = RestorePolicy.ACCEPT;
    -+                                            } else if (pkgInfo.versionCode >= version) {
    -                                                 Slog.i(TAG, "Sig + version match; taking data");
    -                                                 policy = RestorePolicy.ACCEPT;
    -                                             } else {
    -@@ -7479,7 +7483,11 @@ if (MORE_DEBUG) Slog.v(TAG, "   + got " + nRead + "; now wanting " + (size - soF
    -                                         // the app developer's cert, so they're different on every
    -                                         // device.
    -                                         if (signaturesMatch(sigs, pkgInfo)) {
    --                                            if (pkgInfo.versionCode >= version) {
    -+                                            if ((pkgInfo.applicationInfo.flags
    -+                                                    & ApplicationInfo.FLAG_RESTORE_ANY_VERSION) != 0) {
    -+                                                Slog.i(TAG, "Package has restoreAnyVersion; taking data");
    -+                                                policy = RestorePolicy.ACCEPT;
    -+                                            } else if (pkgInfo.versionCode >= version) {
    -                                                 Slog.i(TAG, "Sig + version match; taking data");
    -                                                 policy = RestorePolicy.ACCEPT;
    -                                             } else {
    -diff --git a/services/core/Android.mk b/services/core/Android.mk
    -index b965ce3..3210542 100644
    ---- a/services/core/Android.mk
    -+++ b/services/core/Android.mk
    -@@ -8,6 +8,7 @@ LOCAL_AIDL_INCLUDES := system/netd/server/binder
    - 
    - LOCAL_SRC_FILES += \
    -     $(call all-java-files-under,java) \
    -+    $(call all-proto-files-under, proto) \
    -     java/com/android/server/EventLogTags.logtags \
    -     java/com/android/server/am/EventLogTags.logtags \
    -     ../../../../system/netd/server/binder/android/net/INetd.aidl \
    -@@ -18,6 +19,7 @@ LOCAL_AIDL_INCLUDES += \
    - 
    - LOCAL_JAVA_LIBRARIES := services.net telephony-common
    - LOCAL_STATIC_JAVA_LIBRARIES := tzdata_update
    -+LOCAL_PROTOC_OPTIMIZE_TYPE := nano
    - 
    - ifneq ($(INCREMENTAL_BUILDS),)
    -     LOCAL_PROGUARD_ENABLED := disabled
    -diff --git a/services/core/java/com/android/server/AppOpsService.java b/services/core/java/com/android/server/AppOpsService.java
    -index b5b0cd8..c95b9d5 100644
    ---- a/services/core/java/com/android/server/AppOpsService.java
    -+++ b/services/core/java/com/android/server/AppOpsService.java
    -@@ -597,7 +597,6 @@ public class AppOpsService extends IAppOpsService.Stub {
    -         ArrayList<Callback> repCbs = null;
    -         code = AppOpsManager.opToSwitch(code);
    -         synchronized (this) {
    --            UidState uidState = getUidStateLocked(uid, false);
    -             Op op = getOpLocked(code, uid, packageName, true);
    -             if (op != null) {
    -                 if (op.mode != mode) {
    -@@ -875,7 +874,7 @@ public class AppOpsService extends IAppOpsService.Stub {
    -             return AppOpsManager.MODE_IGNORED;
    -         }
    -         synchronized (this) {
    --            if (isOpRestricted(uid, code, resolvedPackageName)) {
    -+            if (isOpRestrictedLocked(uid, code, resolvedPackageName)) {
    -                 return AppOpsManager.MODE_IGNORED;
    -             }
    -             code = AppOpsManager.opToSwitch(code);
    -@@ -973,7 +972,7 @@ public class AppOpsService extends IAppOpsService.Stub {
    -     public int checkPackage(int uid, String packageName) {
    -         Preconditions.checkNotNull(packageName);
    -         synchronized (this) {
    --            if (getOpsRawLocked(uid, packageName, true) != null) {
    -+            if (packageName != null && getOpsRawLocked(uid, packageName, true) != null) {
    -                 return AppOpsManager.MODE_ALLOWED;
    -             } else {
    -                 return AppOpsManager.MODE_ERRORED;
    -@@ -1024,7 +1023,7 @@ public class AppOpsService extends IAppOpsService.Stub {
    -                 return AppOpsManager.MODE_ERRORED;
    -             }
    -             Op op = getOpLocked(ops, code, true);
    --            if (isOpRestricted(uid, code, packageName)) {
    -+            if (isOpRestrictedLocked(uid, code, packageName)) {
    -                 return AppOpsManager.MODE_IGNORED;
    -             }
    -             if (op.duration == -1) {
    -@@ -1082,7 +1081,7 @@ public class AppOpsService extends IAppOpsService.Stub {
    -                 return AppOpsManager.MODE_ERRORED;
    -             }
    -             Op op = getOpLocked(ops, code, true);
    --            if (isOpRestricted(uid, code, resolvedPackageName)) {
    -+            if (isOpRestrictedLocked(uid, code, resolvedPackageName)) {
    -                 return AppOpsManager.MODE_IGNORED;
    -             }
    -             final int switchCode = AppOpsManager.opToSwitch(code);
    -@@ -1308,7 +1307,7 @@ public class AppOpsService extends IAppOpsService.Stub {
    -         return op;
    -     }
    - 
    --    private boolean isOpRestricted(int uid, int code, String packageName) {
    -+    private boolean isOpRestrictedLocked(int uid, int code, String packageName) {
    -         int userHandle = UserHandle.getUserId(uid);
    -         final int restrictionSetCount = mOpUserRestrictions.size();
    - 
    -@@ -1533,8 +1532,6 @@ public class AppOpsService extends IAppOpsService.Stub {
    - 
    -     void writeState() {
    -         synchronized (mFile) {
    --            List<AppOpsManager.PackageOps> allOps = getPackagesForOps(null);
    --
    -             FileOutputStream stream;
    -             try {
    -                 stream = mFile.startWrite();
    -@@ -1543,15 +1540,33 @@ public class AppOpsService extends IAppOpsService.Stub {
    -                 return;
    -             }
    - 
    -+            SparseArray<UidState> outUidStates = null;
    -+            synchronized (this) {
    -+                final int uidStateCount = mUidStates.size();
    -+                for (int i = 0; i < uidStateCount; i++) {
    -+                    UidState uidState = mUidStates.valueAt(i);
    -+                    SparseIntArray opModes = uidState.opModes;
    -+                    if (opModes != null && opModes.size() > 0) {
    -+                        UidState outUidState = new UidState(uidState.uid);
    -+                        outUidState.opModes = opModes.clone();
    -+                        if (outUidStates == null) {
    -+                            outUidStates = new SparseArray<>();
    -+                        }
    -+                        outUidStates.put(mUidStates.keyAt(i), outUidState);
    -+                    }
    -+                }
    -+            }
    -+            List<AppOpsManager.PackageOps> allOps = getPackagesForOps(null);
    -+
    -             try {
    -                 XmlSerializer out = new FastXmlSerializer();
    -                 out.setOutput(stream, StandardCharsets.UTF_8.name());
    -                 out.startDocument(null, true);
    -                 out.startTag(null, "app-ops");
    - 
    --                final int uidStateCount = mUidStates.size();
    -+                final int uidStateCount = outUidStates != null ? outUidStates.size() : 0;
    -                 for (int i = 0; i < uidStateCount; i++) {
    --                    UidState uidState = mUidStates.valueAt(i);
    -+                    UidState uidState = outUidStates.valueAt(i);
    -                     if (uidState.opModes != null && uidState.opModes.size() > 0) {
    -                         out.startTag(null, "uid");
    -                         out.attribute(null, "n", Integer.toString(uidState.uid));
    -@@ -2210,24 +2225,32 @@ public class AppOpsService extends IAppOpsService.Stub {
    - 
    -     private void setUserRestrictionNoCheck(int code, boolean restricted, IBinder token,
    -             int userHandle, String[] exceptionPackages) {
    --        ClientRestrictionState restrictionState = mOpUserRestrictions.get(token);
    -+        boolean notifyChange = false;
    - 
    --        if (restrictionState == null) {
    --            try {
    --                restrictionState = new ClientRestrictionState(token);
    --            } catch (RemoteException e) {
    --                return;
    -+        synchronized (AppOpsService.this) {
    -+            ClientRestrictionState restrictionState = mOpUserRestrictions.get(token);
    -+
    -+            if (restrictionState == null) {
    -+                try {
    -+                    restrictionState = new ClientRestrictionState(token);
    -+                } catch (RemoteException e) {
    -+                    return;
    -+                }
    -+                mOpUserRestrictions.put(token, restrictionState);
    -             }
    --            mOpUserRestrictions.put(token, restrictionState);
    --        }
    - 
    --        if (restrictionState.setRestriction(code, restricted, exceptionPackages, userHandle)) {
    --            notifyWatchersOfChange(code);
    -+            if (restrictionState.setRestriction(code, restricted, exceptionPackages, userHandle)) {
    -+                notifyChange = true;
    -+            }
    -+
    -+            if (restrictionState.isDefault()) {
    -+                mOpUserRestrictions.remove(token);
    -+                restrictionState.destroy();
    -+            }
    -         }
    - 
    --        if (restrictionState.isDefault()) {
    --            mOpUserRestrictions.remove(token);
    --            restrictionState.destroy();
    -+        if (notifyChange) {
    -+            notifyWatchersOfChange(code);
    -         }
    -     }
    - 
    -@@ -2263,10 +2286,12 @@ public class AppOpsService extends IAppOpsService.Stub {
    -     @Override
    -     public void removeUser(int userHandle) throws RemoteException {
    -         checkSystemUid("removeUser");
    --        final int tokenCount = mOpUserRestrictions.size();
    --        for (int i = tokenCount - 1; i >= 0; i--) {
    --            ClientRestrictionState opRestrictions = mOpUserRestrictions.valueAt(i);
    --            opRestrictions.removeUser(userHandle);
    -+        synchronized (AppOpsService.this) {
    -+            final int tokenCount = mOpUserRestrictions.size();
    -+            for (int i = tokenCount - 1; i >= 0; i--) {
    -+                ClientRestrictionState opRestrictions = mOpUserRestrictions.valueAt(i);
    -+                opRestrictions.removeUser(userHandle);
    -+            }
    -         }
    -     }
    - 
    -diff --git a/services/core/java/com/android/server/BluetoothManagerService.java b/services/core/java/com/android/server/BluetoothManagerService.java
    -index 8c5887f..52be811 100644
    ---- a/services/core/java/com/android/server/BluetoothManagerService.java
    -+++ b/services/core/java/com/android/server/BluetoothManagerService.java
    -@@ -203,7 +203,7 @@ class BluetoothManagerService extends IBluetoothManager.Stub {
    -                     } finally {
    -                         mBluetoothLock.readLock().unlock();
    -                     }
    --                    Slog.d(TAG, "state" + st);
    -+                    Slog.d(TAG, "Airplane Mode change - current state: " + st);
    - 
    -                     if (isAirplaneModeOn()) {
    -                         // Clear registered LE apps to force shut-off
    -@@ -217,6 +217,7 @@ class BluetoothManagerService extends IBluetoothManager.Stub {
    -                                 mBluetoothLock.readLock().lock();
    -                                 if (mBluetooth != null) {
    -                                     mBluetooth.onBrEdrDown();
    -+                                    mEnable = false;
    -                                     mEnableExternal = false;
    -                                 }
    -                             } catch (RemoteException e) {
    -@@ -266,6 +267,7 @@ class BluetoothManagerService extends IBluetoothManager.Stub {
    -         mContext.registerReceiver(mReceiver, filter);
    -         loadStoredNameAndAddress();
    -         if (isBluetoothPersistedStateOn()) {
    -+            if (DBG) Slog.d(TAG, "Startup: Bluetooth persisted state is ON.");
    -             mEnableExternal = true;
    -         }
    - 
    -@@ -292,8 +294,10 @@ class BluetoothManagerService extends IBluetoothManager.Stub {
    -      *  Returns true if the Bluetooth saved state is "on"
    -      */
    -     private final boolean isBluetoothPersistedStateOn() {
    --        return Settings.Global.getInt(mContentResolver,
    --                Settings.Global.BLUETOOTH_ON, 0) != BLUETOOTH_OFF;
    -+        int state = Settings.Global.getInt(mContentResolver,
    -+                                           Settings.Global.BLUETOOTH_ON, -1);
    -+        if (DBG) Slog.d(TAG, "Bluetooth persisted state: " + state);
    -+        return state != BLUETOOTH_OFF;
    -     }
    - 
    -     /**
    -@@ -301,7 +305,7 @@ class BluetoothManagerService extends IBluetoothManager.Stub {
    -      */
    -     private final boolean isBluetoothPersistedStateOnBluetooth() {
    -         return Settings.Global.getInt(mContentResolver,
    --                Settings.Global.BLUETOOTH_ON, 0) == BLUETOOTH_ON_BLUETOOTH;
    -+                Settings.Global.BLUETOOTH_ON, BLUETOOTH_ON_BLUETOOTH) == BLUETOOTH_ON_BLUETOOTH;
    -     }
    - 
    -     /**
    -@@ -309,6 +313,7 @@ class BluetoothManagerService extends IBluetoothManager.Stub {
    -      *
    -      */
    -     private void persistBluetoothSetting(int value) {
    -+        if (DBG) Slog.d(TAG, "Persisting Bluetooth Setting: " + value);
    -         Settings.Global.putInt(mContext.getContentResolver(),
    -                                Settings.Global.BLUETOOTH_ON,
    -                                value);
    -@@ -445,14 +450,16 @@ class BluetoothManagerService extends IBluetoothManager.Stub {
    - 
    -     class ClientDeathRecipient implements IBinder.DeathRecipient {
    -         public void binderDied() {
    --            if (DBG) Slog.d(TAG, "Binder is dead -  unregister Ble App");
    -+            if (DBG) Slog.d(TAG, "Binder is dead - unregister Ble App");
    -             if (mBleAppCount > 0) --mBleAppCount;
    - 
    -             if (mBleAppCount == 0) {
    -                 if (DBG) Slog.d(TAG, "Disabling LE only mode after application crash");
    -                 try {
    -                     mBluetoothLock.readLock().lock();
    --                    if (mBluetooth != null) {
    -+                    if (mBluetooth != null &&
    -+                        mBluetooth.getState() == BluetoothAdapter.STATE_BLE_ON) {
    -+                        mEnable = false;
    -                         mBluetooth.onBrEdrDown();
    -                     }
    -                 } catch (RemoteException e) {
    -@@ -469,6 +476,9 @@ class BluetoothManagerService extends IBluetoothManager.Stub {
    - 
    -     @Override
    -     public boolean isBleScanAlwaysAvailable() {
    -+        if (isAirplaneModeOn() && !mEnable) {
    -+            return false;
    -+        }
    -         try {
    -             return (Settings.Global.getInt(mContentResolver,
    -                     Settings.Global.BLE_SCAN_ALWAYS_AVAILABLE)) != 0;
    -@@ -707,6 +717,7 @@ class BluetoothManagerService extends IBluetoothManager.Stub {
    -             if (mUnbinding) return;
    -             mUnbinding = true;
    -             mHandler.removeMessages(MESSAGE_BLUETOOTH_STATE_CHANGE);
    -+            mHandler.removeMessages(MESSAGE_BIND_PROFILE_SERVICE);
    -             if (mBluetooth != null) {
    -                 //Unregister callback object
    -                 try {
    -@@ -1365,7 +1376,7 @@ class BluetoothManagerService extends IBluetoothManager.Stub {
    -                 {
    -                     int prevState = msg.arg1;
    -                     int newState = msg.arg2;
    --                    if (DBG) Slog.d(TAG, "MESSAGE_BLUETOOTH_STATE_CHANGE: prevState = " + prevState + ", newState=" + newState);
    -+                    if (DBG) Slog.d(TAG, "MESSAGE_BLUETOOTH_STATE_CHANGE: prevState = " + prevState + ", newState =" + newState);
    -                     mState = newState;
    -                     bluetoothStateChangeHandler(prevState, newState);
    -                     // handle error state transition case from TURNING_ON to OFF
    -@@ -1677,6 +1688,7 @@ class BluetoothManagerService extends IBluetoothManager.Stub {
    - 
    -     private void bluetoothStateChangeHandler(int prevState, int newState) {
    -         boolean isStandardBroadcast = true;
    -+        if (DBG) Slog.d(TAG, "bluetoothStateChangeHandler: " + prevState + " ->  " + newState);
    -         if (prevState != newState) {
    -             //Notify all proxy objects first of adapter state change
    -             if (newState == BluetoothAdapter.STATE_BLE_ON ||
    -diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
    -index 989892f..23172a2 100644
    ---- a/services/core/java/com/android/server/ConnectivityService.java
    -+++ b/services/core/java/com/android/server/ConnectivityService.java
    -@@ -24,6 +24,7 @@ import static android.net.ConnectivityManager.TYPE_VPN;
    - import static android.net.ConnectivityManager.getNetworkTypeName;
    - import static android.net.ConnectivityManager.isNetworkTypeValid;
    - import static android.net.NetworkCapabilities.NET_CAPABILITY_CAPTIVE_PORTAL;
    -+import static android.net.NetworkCapabilities.NET_CAPABILITY_FOREGROUND;
    - import static android.net.NetworkCapabilities.NET_CAPABILITY_INTERNET;
    - import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_METERED;
    - import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED;
    -@@ -263,6 +264,11 @@ public class ConnectivityService extends IConnectivityManager.Stub
    -         DONT_REAP
    -     };
    - 
    -+    private enum UnneededFor {
    -+        LINGER,    // Determine whether this network is unneeded and should be lingered.
    -+        TEARDOWN,  // Determine whether this network is unneeded and should be torn down.
    -+    }
    -+
    -     /**
    -      * used internally to change our mobile data enabled flag
    -      */
    -@@ -700,13 +706,13 @@ public class ConnectivityService extends IConnectivityManager.Stub
    -         if (DBG) log("ConnectivityService starting up");
    - 
    -         mMetricsLog = logger;
    --        mDefaultRequest = createInternetRequestForTransport(-1);
    -+        mDefaultRequest = createInternetRequestForTransport(-1, NetworkRequest.Type.REQUEST);
    -         NetworkRequestInfo defaultNRI = new NetworkRequestInfo(null, mDefaultRequest, new Binder());
    -         mNetworkRequests.put(mDefaultRequest, defaultNRI);
    -         mNetworkRequestInfoLogs.log("REGISTER " + defaultNRI);
    - 
    -         mDefaultMobileDataRequest = createInternetRequestForTransport(
    --                NetworkCapabilities.TRANSPORT_CELLULAR);
    -+                NetworkCapabilities.TRANSPORT_CELLULAR, NetworkRequest.Type.BACKGROUND_REQUEST);
    - 
    -         mHandlerThread = createHandlerThread();
    -         mHandlerThread.start();
    -@@ -809,7 +815,7 @@ public class ConnectivityService extends IConnectivityManager.Stub
    -         mTestMode = SystemProperties.get("cm.test.mode").equals("true")
    -                 && SystemProperties.get("ro.build.type").equals("eng");
    - 
    --        mTethering = new Tethering(mContext, mNetd, statsService);
    -+        mTethering = new Tethering(mContext, mNetd, statsService, mPolicyManager);
    - 
    -         mPermissionMonitor = new PermissionMonitor(mContext, mNetd);
    - 
    -@@ -860,15 +866,15 @@ public class ConnectivityService extends IConnectivityManager.Stub
    -                 mContext, mHandler, () -> rematchForAvoidBadWifiUpdate());
    -     }
    - 
    --    private NetworkRequest createInternetRequestForTransport(int transportType) {
    -+    private NetworkRequest createInternetRequestForTransport(
    -+            int transportType, NetworkRequest.Type type) {
    -         NetworkCapabilities netCap = new NetworkCapabilities();
    -         netCap.addCapability(NET_CAPABILITY_INTERNET);
    -         netCap.addCapability(NET_CAPABILITY_NOT_RESTRICTED);
    -         if (transportType > -1) {
    -             netCap.addTransportType(transportType);
    -         }
    --        return new NetworkRequest(netCap, TYPE_NONE, nextNetworkRequestId(),
    --                NetworkRequest.Type.REQUEST);
    -+        return new NetworkRequest(netCap, TYPE_NONE, nextNetworkRequestId(), type);
    -     }
    - 
    -     // Used only for testing.
    -@@ -1982,8 +1988,12 @@ public class ConnectivityService extends IConnectivityManager.Stub
    -         for (NetworkAgentInfo nai : mNetworkAgentInfos.values()) {
    -             pw.println(nai.toString());
    -             pw.increaseIndent();
    --            pw.println(String.format("Requests: %d request/%d total",
    --                    nai.numRequestNetworkRequests(), nai.numNetworkRequests()));
    -+            pw.println(String.format(
    -+                    "Requests: REQUEST:%d LISTEN:%d BACKGROUND_REQUEST:%d total:%d",
    -+                    nai.numForegroundNetworkRequests(),
    -+                    nai.numNetworkRequests() - nai.numRequestNetworkRequests(),
    -+                    nai.numBackgroundNetworkRequests(),
    -+                    nai.numNetworkRequests()));
    -             pw.increaseIndent();
    -             for (int i = 0; i < nai.numNetworkRequests(); i++) {
    -                 pw.println(nai.requestAt(i).toString());
    -@@ -2144,14 +2154,10 @@ public class ConnectivityService extends IConnectivityManager.Stub
    -                 case NetworkAgent.EVENT_NETWORK_CAPABILITIES_CHANGED: {
    -                     final NetworkCapabilities networkCapabilities = (NetworkCapabilities) msg.obj;
    -                     if (networkCapabilities.hasCapability(NET_CAPABILITY_CAPTIVE_PORTAL) ||
    --                            networkCapabilities.hasCapability(NET_CAPABILITY_VALIDATED)) {
    -+                            networkCapabilities.hasCapability(NET_CAPABILITY_VALIDATED) ||
    -+                            networkCapabilities.hasCapability(NET_CAPABILITY_FOREGROUND)) {
    -                         Slog.wtf(TAG, "BUG: " + nai + " has CS-managed capability.");
    -                     }
    --                    if (nai.everConnected && !nai.networkCapabilities.equalImmutableCapabilities(
    --                            networkCapabilities)) {
    --                        Slog.wtf(TAG, "BUG: " + nai + " changed immutable capabilities: "
    --                                + nai.networkCapabilities + " -> " + networkCapabilities);
    --                    }
    -                     updateCapabilities(nai.getCurrentScore(), nai, networkCapabilities);
    -                     break;
    -                 }
    -@@ -2311,15 +2317,13 @@ public class ConnectivityService extends IConnectivityManager.Stub
    -         // 3. If this network is unneeded (which implies it is not lingering), and there is at least
    -         //    one lingered request, start lingering.
    -         nai.updateLingerTimer();
    --        if (nai.isLingering() && nai.numRequestNetworkRequests() > 0) {
    -+        if (nai.isLingering() && nai.numForegroundNetworkRequests() > 0) {
    -             if (DBG) log("Unlingering " + nai.name());
    -             nai.unlinger();
    -             logNetworkEvent(nai, NetworkEvent.NETWORK_UNLINGER);
    --        } else if (unneeded(nai) && nai.getLingerExpiry() > 0) {  // unneeded() calls isLingering()
    -+        } else if (unneeded(nai, UnneededFor.LINGER) && nai.getLingerExpiry() > 0) {
    -             int lingerTime = (int) (nai.getLingerExpiry() - now);
    --            if (DBG) {
    --                Log.d(TAG, "Lingering " + nai.name() + " for " + lingerTime + "ms");
    --            }
    -+            if (DBG) log("Lingering " + nai.name() + " for " + lingerTime + "ms");
    -             nai.linger();
    -             logNetworkEvent(nai, NetworkEvent.NETWORK_LINGER);
    -             notifyNetworkCallbacks(nai, ConnectivityManager.CALLBACK_LOSING, lingerTime);
    -@@ -2498,15 +2502,37 @@ public class ConnectivityService extends IConnectivityManager.Stub
    -         }
    -     }
    - 
    --    // Is nai unneeded by all NetworkRequests (and should be disconnected)?
    --    // This is whether it is satisfying any NetworkRequests or were it to become validated,
    --    // would it have a chance of satisfying any NetworkRequests.
    --    private boolean unneeded(NetworkAgentInfo nai) {
    --        if (!nai.everConnected || nai.isVPN() ||
    --               nai.isLingering() || nai.numRequestNetworkRequests() > 0) {
    -+    // Determines whether the network is the best (or could become the best, if it validated), for
    -+    // none of a particular type of NetworkRequests. The type of NetworkRequests considered depends
    -+    // on the value of reason:
    -+    //
    -+    // - UnneededFor.TEARDOWN: non-listen NetworkRequests. If a network is unneeded for this reason,
    -+    //   then it should be torn down.
    -+    // - UnneededFor.LINGER: foreground NetworkRequests. If a network is unneeded for this reason,
    -+    //   then it should be lingered.
    -+    private boolean unneeded(NetworkAgentInfo nai, UnneededFor reason) {
    -+        final int numRequests;
    -+        switch (reason) {
    -+            case TEARDOWN:
    -+                numRequests = nai.numRequestNetworkRequests();
    -+                break;
    -+            case LINGER:
    -+                numRequests = nai.numForegroundNetworkRequests();
    -+                break;
    -+            default:
    -+                Slog.wtf(TAG, "Invalid reason. Cannot happen.");
    -+                return true;
    -+        }
    -+
    -+        if (!nai.everConnected || nai.isVPN() || nai.isLingering() || numRequests > 0) {
    -             return false;
    -         }
    -         for (NetworkRequestInfo nri : mNetworkRequests.values()) {
    -+            if (reason == UnneededFor.LINGER && nri.request.isBackgroundRequest()) {
    -+                // Background requests don't affect lingering.
    -+                continue;
    -+            }
    -+
    -             // If this Network is already the highest scoring Network for a request, or if
    -             // there is hope for it to become one if it validated, then it is needed.
    -             if (nri.request.isRequest() && nai.satisfies(nri.request) &&
    -@@ -2594,6 +2620,7 @@ public class ConnectivityService extends IConnectivityManager.Stub
    -             boolean wasKept = false;
    -             NetworkAgentInfo nai = mNetworkForRequestId.get(nri.request.requestId);
    -             if (nai != null) {
    -+                boolean wasBackgroundNetwork = nai.isBackgroundNetwork();
    -                 nai.removeRequest(nri.request.requestId);
    -                 if (VDBG) {
    -                     log(" Removing from current network " + nai.name() +
    -@@ -2602,13 +2629,17 @@ public class ConnectivityService extends IConnectivityManager.Stub
    -                 // If there are still lingered requests on this network, don't tear it down,
    -                 // but resume lingering instead.
    -                 updateLingerState(nai, SystemClock.elapsedRealtime());
    --                if (unneeded(nai)) {
    -+                if (unneeded(nai, UnneededFor.TEARDOWN)) {
    -                     if (DBG) log("no live requests for " + nai.name() + "; disconnecting");
    -                     teardownUnneededNetwork(nai);
    -                 } else {
    -                     wasKept = true;
    -                 }
    -                 mNetworkForRequestId.remove(nri.request.requestId);
    -+                if (!wasBackgroundNetwork && nai.isBackgroundNetwork()) {
    -+                    // Went from foreground to background.
    -+                    updateCapabilities(nai.getCurrentScore(), nai, nai.networkCapabilities);
    -+                }
    -             }
    - 
    -             // TODO: remove this code once we know that the Slog.wtf is never hit.
    -@@ -4255,8 +4286,17 @@ public class ConnectivityService extends IConnectivityManager.Stub
    -             enforceAccessPermission();
    -         }
    - 
    --        NetworkRequest networkRequest = new NetworkRequest(
    --                new NetworkCapabilities(networkCapabilities), TYPE_NONE, nextNetworkRequestId(),
    -+        NetworkCapabilities nc = new NetworkCapabilities(networkCapabilities);
    -+        if (!ConnectivityManager.checkChangePermission(mContext)) {
    -+            // Apps without the CHANGE_NETWORK_STATE permission can't use background networks, so
    -+            // make all their listens include NET_CAPABILITY_FOREGROUND. That way, they will get
    -+            // onLost and onAvailable callbacks when networks move in and out of the background.
    -+            // There is no need to do this for requests because an app without CHANGE_NETWORK_STATE
    -+            // can't request networks.
    -+            nc.addCapability(NET_CAPABILITY_FOREGROUND);
    -+        }
    -+
    -+        NetworkRequest networkRequest = new NetworkRequest(nc, TYPE_NONE, nextNetworkRequestId(),
    -                 NetworkRequest.Type.LISTEN);
    -         NetworkRequestInfo nri = new NetworkRequestInfo(messenger, networkRequest, binder);
    -         if (VDBG) log("listenForNetwork for " + nri);
    -@@ -4571,6 +4611,17 @@ public class ConnectivityService extends IConnectivityManager.Stub
    -         mNumDnsEntries = last;
    -     }
    - 
    -+    private String getNetworkPermission(NetworkCapabilities nc) {
    -+        // TODO: make these permission strings AIDL constants instead.
    -+        if (!nc.hasCapability(NET_CAPABILITY_NOT_RESTRICTED)) {
    -+            return NetworkManagementService.PERMISSION_SYSTEM;
    -+        }
    -+        if (!nc.hasCapability(NET_CAPABILITY_FOREGROUND)) {
    -+            return NetworkManagementService.PERMISSION_NETWORK;
    -+        }
    -+        return null;
    -+    }
    -+
    -     /**
    -      * Update the NetworkCapabilities for {@code networkAgent} to {@code networkCapabilities}
    -      * augmented with any stateful capabilities implied from {@code networkAgent}
    -@@ -4583,6 +4634,12 @@ public class ConnectivityService extends IConnectivityManager.Stub
    -      */
    -     private void updateCapabilities(
    -             int oldScore, NetworkAgentInfo nai, NetworkCapabilities networkCapabilities) {
    -+        if (nai.everConnected && !nai.networkCapabilities.equalImmutableCapabilities(
    -+                networkCapabilities)) {
    -+            Slog.wtf(TAG, "BUG: " + nai + " changed immutable capabilities: "
    -+                    + nai.networkCapabilities + " -> " + networkCapabilities);
    -+        }
    -+
    -         // Don't modify caller's NetworkCapabilities.
    -         networkCapabilities = new NetworkCapabilities(networkCapabilities);
    -         if (nai.lastValidated) {
    -@@ -4595,20 +4652,38 @@ public class ConnectivityService extends IConnectivityManager.Stub
    -         } else {
    -             networkCapabilities.removeCapability(NET_CAPABILITY_CAPTIVE_PORTAL);
    -         }
    --        if (!Objects.equals(nai.networkCapabilities, networkCapabilities)) {
    --            if (nai.networkCapabilities.hasCapability(NET_CAPABILITY_NOT_RESTRICTED) !=
    --                    networkCapabilities.hasCapability(NET_CAPABILITY_NOT_RESTRICTED)) {
    --                try {
    --                    mNetd.setNetworkPermission(nai.network.netId,
    --                            networkCapabilities.hasCapability(NET_CAPABILITY_NOT_RESTRICTED) ?
    --                                    null : NetworkManagementService.PERMISSION_SYSTEM);
    --                } catch (RemoteException e) {
    --                    loge("Exception in setNetworkPermission: " + e);
    --                }
    --            }
    --            synchronized (nai) {
    --                nai.networkCapabilities = networkCapabilities;
    -+        if (nai.isBackgroundNetwork()) {
    -+            networkCapabilities.removeCapability(NET_CAPABILITY_FOREGROUND);
    -+        } else {
    -+            networkCapabilities.addCapability(NET_CAPABILITY_FOREGROUND);
    -+        }
    -+
    -+        if (Objects.equals(nai.networkCapabilities, networkCapabilities)) return;
    -+
    -+        final String oldPermission = getNetworkPermission(nai.networkCapabilities);
    -+        final String newPermission = getNetworkPermission(networkCapabilities);
    -+        if (!Objects.equals(oldPermission, newPermission) && nai.created && !nai.isVPN()) {
    -+            try {
    -+                mNetd.setNetworkPermission(nai.network.netId, newPermission);
    -+            } catch (RemoteException e) {
    -+                loge("Exception in setNetworkPermission: " + e);
    -             }
    -+        }
    -+
    -+        final NetworkCapabilities prevNc = nai.networkCapabilities;
    -+        synchronized (nai) {
    -+            nai.networkCapabilities = networkCapabilities;
    -+        }
    -+        if (nai.getCurrentScore() == oldScore &&
    -+                networkCapabilities.equalRequestableCapabilities(prevNc)) {
    -+            // If the requestable capabilities haven't changed, and the score hasn't changed, then
    -+            // the change we're processing can't affect any requests, it can only affect the listens
    -+            // on this network. We might have been called by rematchNetworkAndRequests when a
    -+            // network changed foreground state.
    -+            processListenRequests(nai, true);
    -+        } else {
    -+            // If the requestable capabilities have changed or the score changed, we can't have been
    -+            // called by rematchNetworkAndRequests, so it's safe to start a rematch.
    -             rematchAllNetworksAndRequests(nai, oldScore);
    -             notifyNetworkCallbacks(nai, ConnectivityManager.CALLBACK_CAP_CHANGED);
    -         }
    -@@ -4731,8 +4806,13 @@ public class ConnectivityService extends IConnectivityManager.Stub
    -         // must be no other active linger timers, and we must stop lingering.
    -         oldNetwork.clearLingerState();
    - 
    --        if (unneeded(oldNetwork)) {
    -+        if (unneeded(oldNetwork, UnneededFor.TEARDOWN)) {
    -+            // Tear the network down.
    -             teardownUnneededNetwork(oldNetwork);
    -+        } else {
    -+            // Put the network in the background.
    -+            updateCapabilities(oldNetwork.getCurrentScore(), oldNetwork,
    -+                    oldNetwork.networkCapabilities);
    -         }
    -     }
    - 
    -@@ -4750,6 +4830,31 @@ public class ConnectivityService extends IConnectivityManager.Stub
    -         setDefaultDnsSystemProperties(newNetwork.linkProperties.getDnsServers());
    -     }
    - 
    -+    private void processListenRequests(NetworkAgentInfo nai, boolean capabilitiesChanged) {
    -+        // For consistency with previous behaviour, send onLost callbacks before onAvailable.
    -+        for (NetworkRequestInfo nri : mNetworkRequests.values()) {
    -+            NetworkRequest nr = nri.request;
    -+            if (!nr.isListen()) continue;
    -+            if (nai.isSatisfyingRequest(nr.requestId) && !nai.satisfies(nr)) {
    -+                nai.removeRequest(nri.request.requestId);
    -+                callCallbackForRequest(nri, nai, ConnectivityManager.CALLBACK_LOST, 0);
    -+            }
    -+        }
    -+
    -+        if (capabilitiesChanged) {
    -+            notifyNetworkCallbacks(nai, ConnectivityManager.CALLBACK_CAP_CHANGED);
    -+        }
    -+
    -+        for (NetworkRequestInfo nri : mNetworkRequests.values()) {
    -+            NetworkRequest nr = nri.request;
    -+            if (!nr.isListen()) continue;
    -+            if (nai.satisfies(nr) && !nai.isSatisfyingRequest(nr.requestId)) {
    -+                nai.addRequest(nr);
    -+                notifyNetworkCallback(nai, nri);
    -+            }
    -+        }
    -+    }
    -+
    -     // Handles a network appearing or improving its score.
    -     //
    -     // - Evaluates all current NetworkRequests that can be
    -@@ -4783,13 +4888,25 @@ public class ConnectivityService extends IConnectivityManager.Stub
    -         boolean keep = newNetwork.isVPN();
    -         boolean isNewDefault = false;
    -         NetworkAgentInfo oldDefaultNetwork = null;
    -+
    -+        final boolean wasBackgroundNetwork = newNetwork.isBackgroundNetwork();
    -+        final int score = newNetwork.getCurrentScore();
    -+
    -         if (VDBG) log("rematching " + newNetwork.name());
    -+
    -         // Find and migrate to this Network any NetworkRequests for
    -         // which this network is now the best.
    -         ArrayList<NetworkAgentInfo> affectedNetworks = new ArrayList<NetworkAgentInfo>();
    -         ArrayList<NetworkRequestInfo> addedRequests = new ArrayList<NetworkRequestInfo>();
    --        if (VDBG) log(" network has: " + newNetwork.networkCapabilities);
    -+        NetworkCapabilities nc = newNetwork.networkCapabilities;
    -+        if (VDBG) log(" network has: " + nc);
    -         for (NetworkRequestInfo nri : mNetworkRequests.values()) {
    -+            // Process requests in the first pass and listens in the second pass. This allows us to
    -+            // change a network's capabilities depending on which requests it has. This is only
    -+            // correct if the change in capabilities doesn't affect whether the network satisfies
    -+            // requests or not, and doesn't affect the network's score.
    -+            if (nri.request.isListen()) continue;
    -+
    -             final NetworkAgentInfo currentNetwork = mNetworkForRequestId.get(nri.request.requestId);
    -             final boolean satisfies = newNetwork.satisfies(nri.request);
    -             if (newNetwork == currentNetwork && satisfies) {
    -@@ -4816,10 +4933,9 @@ public class ConnectivityService extends IConnectivityManager.Stub
    -                 if (VDBG) {
    -                     log("currentScore = " +
    -                             (currentNetwork != null ? currentNetwork.getCurrentScore() : 0) +
    --                            ", newScore = " + newNetwork.getCurrentScore());
    -+                            ", newScore = " + score);
    -                 }
    --                if (currentNetwork == null ||
    --                        currentNetwork.getCurrentScore() < newNetwork.getCurrentScore()) {
    -+                if (currentNetwork == null || currentNetwork.getCurrentScore() < score) {
    -                     if (VDBG) log("rematch for " + newNetwork.name());
    -                     if (currentNetwork != null) {
    -                         if (VDBG) log("   accepting network in place of " + currentNetwork.name());
    -@@ -4841,7 +4957,7 @@ public class ConnectivityService extends IConnectivityManager.Stub
    -                     // TODO - this could get expensive if we have alot of requests for this
    -                     // network.  Think about if there is a way to reduce this.  Push
    -                     // netid->request mapping to each factory?
    --                    sendUpdatedScoreToFactories(nri.request, newNetwork.getCurrentScore());
    -+                    sendUpdatedScoreToFactories(nri.request, score);
    -                     if (isDefaultRequest(nri)) {
    -                         isNewDefault = true;
    -                         oldDefaultNetwork = currentNetwork;
    -@@ -4867,16 +4983,14 @@ public class ConnectivityService extends IConnectivityManager.Stub
    -                     mNetworkForRequestId.remove(nri.request.requestId);
    -                     sendUpdatedScoreToFactories(nri.request, 0);
    -                 } else {
    --                    if (nri.request.isRequest()) {
    --                        Slog.wtf(TAG, "BUG: Removing request " + nri.request.requestId + " from " +
    --                                newNetwork.name() +
    --                                " without updating mNetworkForRequestId or factories!");
    --                    }
    -+                    Slog.wtf(TAG, "BUG: Removing request " + nri.request.requestId + " from " +
    -+                            newNetwork.name() +
    -+                            " without updating mNetworkForRequestId or factories!");
    -                 }
    --                // TODO: technically, sending CALLBACK_LOST here is
    --                // incorrect if nri is a request (not a listen) and there
    --                // is a replacement network currently connected that can
    --                // satisfy it. However, the only capability that can both
    -+                // TODO: Technically, sending CALLBACK_LOST here is
    -+                // incorrect if there is a replacement network currently
    -+                // connected that can satisfy nri, which is a request
    -+                // (not a listen). However, the only capability that can both
    -                 // a) be requested and b) change is NET_CAPABILITY_TRUSTED,
    -                 // so this code is only incorrect for a network that loses
    -                 // the TRUSTED capability, which is a rare case.
    -@@ -4901,6 +5015,28 @@ public class ConnectivityService extends IConnectivityManager.Stub
    -             }
    -         }
    - 
    -+        if (!newNetwork.networkCapabilities.equalRequestableCapabilities(nc)) {
    -+            Slog.wtf(TAG, String.format(
    -+                    "BUG: %s changed requestable capabilities during rematch: %s -> %s",
    -+                    nc, newNetwork.networkCapabilities));
    -+        }
    -+        if (newNetwork.getCurrentScore() != score) {
    -+            Slog.wtf(TAG, String.format(
    -+                    "BUG: %s changed score during rematch: %d -> %d",
    -+                    score, newNetwork.getCurrentScore()));
    -+        }
    -+
    -+        // Second pass: process all listens.
    -+        if (wasBackgroundNetwork != newNetwork.isBackgroundNetwork()) {
    -+            // If the network went from background to foreground or vice versa, we need to update
    -+            // its foreground state. It is safe to do this after rematching the requests because
    -+            // NET_CAPABILITY_FOREGROUND does not affect requests, as is not a requestable
    -+            // capability and does not affect the network's score (see the Slog.wtf call above).
    -+            updateCapabilities(score, newNetwork, newNetwork.networkCapabilities);
    -+        } else {
    -+            processListenRequests(newNetwork, false);
    -+        }
    -+
    -         // do this after the default net is switched, but
    -         // before LegacyTypeTracker sends legacy broadcasts
    -         for (NetworkRequestInfo nri : addedRequests) notifyNetworkCallback(newNetwork, nri);
    -@@ -4978,7 +5114,7 @@ public class ConnectivityService extends IConnectivityManager.Stub
    -         }
    -         if (reapUnvalidatedNetworks == ReapUnvalidatedNetworks.REAP) {
    -             for (NetworkAgentInfo nai : mNetworkAgentInfos.values()) {
    --                if (unneeded(nai)) {
    -+                if (unneeded(nai, UnneededFor.TEARDOWN)) {
    -                     if (nai.getLingerExpiry() > 0) {
    -                         // This network has active linger timers and no requests, but is not
    -                         // lingering. Linger it.
    -@@ -5092,6 +5228,10 @@ public class ConnectivityService extends IConnectivityManager.Stub
    -         if (!networkAgent.created
    -                 && (state == NetworkInfo.State.CONNECTED
    -                 || (state == NetworkInfo.State.CONNECTING && networkAgent.isVPN()))) {
    -+
    -+            // A network that has just connected has zero requests and is thus a foreground network.
    -+            networkAgent.networkCapabilities.addCapability(NET_CAPABILITY_FOREGROUND);
    -+
    -             try {
    -                 // This should never fail.  Specifying an already in use NetID will cause failure.
    -                 if (networkAgent.isVPN()) {
    -@@ -5101,9 +5241,7 @@ public class ConnectivityService extends IConnectivityManager.Stub
    -                                 !networkAgent.networkMisc.allowBypass));
    -                 } else {
    -                     mNetd.createPhysicalNetwork(networkAgent.network.netId,
    --                            networkAgent.networkCapabilities.hasCapability(
    --                                    NET_CAPABILITY_NOT_RESTRICTED) ?
    --                                    null : NetworkManagementService.PERMISSION_SYSTEM);
    -+                            getNetworkPermission(networkAgent.networkCapabilities));
    -                 }
    -             } catch (Exception e) {
    -                 loge("Error creating network " + networkAgent.network.netId + ": "
    -@@ -5253,6 +5391,8 @@ public class ConnectivityService extends IConnectivityManager.Stub
    -             NetworkRequest nr = networkAgent.requestAt(i);
    -             NetworkRequestInfo nri = mNetworkRequests.get(nr);
    -             if (VDBG) log(" sending notification for " + nr);
    -+            // TODO: if we're in the middle of a rematch, can we send a CAP_CHANGED callback for
    -+            // a network that no longer satisfies the listen?
    -             if (nri.mPendingIntent == null) {
    -                 callCallbackForRequest(nri, networkAgent, notifyType, arg1);
    -             } else {
    -@@ -5324,7 +5464,7 @@ public class ConnectivityService extends IConnectivityManager.Stub
    - 
    -     @Override
    -     public String getCaptivePortalServerUrl() {
    --        return NetworkMonitor.getCaptivePortalServerUrl(mContext);
    -+        return NetworkMonitor.getCaptivePortalServerHttpUrl(mContext);
    -     }
    - 
    -     @Override
    -diff --git a/services/core/java/com/android/server/DeviceIdleController.java b/services/core/java/com/android/server/DeviceIdleController.java
    -index 488f0e7..4405c1b 100644
    ---- a/services/core/java/com/android/server/DeviceIdleController.java
    -+++ b/services/core/java/com/android/server/DeviceIdleController.java
    -@@ -2726,12 +2726,12 @@ public class DeviceIdleController extends SystemService
    -                 }
    -             }
    -         } else if ("whitelist".equals(cmd)) {
    --            long token = Binder.clearCallingIdentity();
    --            try {
    --                String arg = shell.getNextArg();
    --                if (arg != null) {
    --                    getContext().enforceCallingOrSelfPermission(
    --                            android.Manifest.permission.DEVICE_POWER, null);
    -+            String arg = shell.getNextArg();
    -+            if (arg != null) {
    -+                getContext().enforceCallingOrSelfPermission(
    -+                        android.Manifest.permission.DEVICE_POWER, null);
    -+                long token = Binder.clearCallingIdentity();
    -+                try {
    -                     do {
    -                         if (arg.length() < 1 || (arg.charAt(0) != '-'
    -                                 && arg.charAt(0) != '+' && arg.charAt(0) != '=')) {
    -@@ -2754,30 +2754,30 @@ public class DeviceIdleController extends SystemService
    -                             pw.println(getPowerSaveWhitelistAppInternal(pkg));
    -                         }
    -                     } while ((arg=shell.getNextArg()) != null);
    --                } else {
    --                    synchronized (this) {
    --                        for (int j=0; j<mPowerSaveWhitelistAppsExceptIdle.size(); j++) {
    --                            pw.print("system-excidle,");
    --                            pw.print(mPowerSaveWhitelistAppsExceptIdle.keyAt(j));
    --                            pw.print(",");
    --                            pw.println(mPowerSaveWhitelistAppsExceptIdle.valueAt(j));
    --                        }
    --                        for (int j=0; j<mPowerSaveWhitelistApps.size(); j++) {
    --                            pw.print("system,");
    --                            pw.print(mPowerSaveWhitelistApps.keyAt(j));
    --                            pw.print(",");
    --                            pw.println(mPowerSaveWhitelistApps.valueAt(j));
    --                        }
    --                        for (int j=0; j<mPowerSaveWhitelistUserApps.size(); j++) {
    --                            pw.print("user,");
    --                            pw.print(mPowerSaveWhitelistUserApps.keyAt(j));
    --                            pw.print(",");
    --                            pw.println(mPowerSaveWhitelistUserApps.valueAt(j));
    --                        }
    -+                } finally {
    -+                    Binder.restoreCallingIdentity(token);
    -+                }
    -+            } else {
    -+                synchronized (this) {
    -+                    for (int j=0; j<mPowerSaveWhitelistAppsExceptIdle.size(); j++) {
    -+                        pw.print("system-excidle,");
    -+                        pw.print(mPowerSaveWhitelistAppsExceptIdle.keyAt(j));
    -+                        pw.print(",");
    -+                        pw.println(mPowerSaveWhitelistAppsExceptIdle.valueAt(j));
    -+                    }
    -+                    for (int j=0; j<mPowerSaveWhitelistApps.size(); j++) {
    -+                        pw.print("system,");
    -+                        pw.print(mPowerSaveWhitelistApps.keyAt(j));
    -+                        pw.print(",");
    -+                        pw.println(mPowerSaveWhitelistApps.valueAt(j));
    -+                    }
    -+                    for (int j=0; j<mPowerSaveWhitelistUserApps.size(); j++) {
    -+                        pw.print("user,");
    -+                        pw.print(mPowerSaveWhitelistUserApps.keyAt(j));
    -+                        pw.print(",");
    -+                        pw.println(mPowerSaveWhitelistUserApps.valueAt(j));
    -                     }
    -                 }
    --            } finally {
    --                Binder.restoreCallingIdentity(token);
    -             }
    -         } else if ("tempwhitelist".equals(cmd)) {
    -             String opt;
    -diff --git a/services/core/java/com/android/server/IntentResolver.java b/services/core/java/com/android/server/IntentResolver.java
    -index 3fdcceb..83d374c 100644
    ---- a/services/core/java/com/android/server/IntentResolver.java
    -+++ b/services/core/java/com/android/server/IntentResolver.java
    -@@ -364,6 +364,7 @@ public abstract class IntentResolver<F extends IntentFilter, R extends Object> {
    -             buildResolveList(intent, categories, debug, defaultOnly,
    -                     resolvedType, scheme, listCut.get(i), resultList, userId);
    -         }
    -+        filterResults(resultList);
    -         sortResults(resultList);
    -         return resultList;
    -     }
    -@@ -457,6 +458,7 @@ public abstract class IntentResolver<F extends IntentFilter, R extends Object> {
    -             buildResolveList(intent, categories, debug, defaultOnly,
    -                     resolvedType, scheme, schemeCut, finalList, userId);
    -         }
    -+        filterResults(finalList);
    -         sortResults(finalList);
    - 
    -         if (debug) {
    -@@ -521,6 +523,12 @@ public abstract class IntentResolver<F extends IntentFilter, R extends Object> {
    -         Collections.sort(results, mResolvePrioritySorter);
    -     }
    - 
    -+    /**
    -+     * Apply filtering to the results. This happens before the results are sorted.
    -+     */
    -+    protected void filterResults(List<R> results) {
    -+    }
    -+
    -     protected void dumpFilter(PrintWriter out, String prefix, F filter) {
    -         out.print(prefix); out.println(filter);
    -     }
    -diff --git a/services/core/java/com/android/server/MountService.java b/services/core/java/com/android/server/MountService.java
    -index cdd977b..8430a0b 100644
    ---- a/services/core/java/com/android/server/MountService.java
    -+++ b/services/core/java/com/android/server/MountService.java
    -@@ -1056,6 +1056,10 @@ class MountService extends IMountService.Stub
    -                         || mForceAdoptable) {
    -                     flags |= DiskInfo.FLAG_ADOPTABLE;
    -                 }
    -+                // Adoptable storage isn't currently supported on FBE devices
    -+                if (StorageManager.isFileEncryptedNativeOnly()) {
    -+                    flags &= ~DiskInfo.FLAG_ADOPTABLE;
    -+                }
    -                 mDisks.put(id, new DiskInfo(id, flags));
    -                 break;
    -             }
    -@@ -1433,13 +1437,22 @@ class MountService extends IMountService.Stub
    -      * Decide if volume is mountable per device policies.
    -      */
    -     private boolean isMountDisallowed(VolumeInfo vol) {
    -+        UserManager userManager = mContext.getSystemService(UserManager.class);
    -+
    -+        boolean isUsbRestricted = false;
    -+        if (vol.disk != null && vol.disk.isUsb()) {
    -+            isUsbRestricted = userManager.hasUserRestriction(UserManager.DISALLOW_USB_FILE_TRANSFER,
    -+                    Binder.getCallingUserHandle());
    -+        }
    -+
    -+        boolean isTypeRestricted = false;
    -         if (vol.type == VolumeInfo.TYPE_PUBLIC || vol.type == VolumeInfo.TYPE_PRIVATE) {
    --            final UserManager userManager = mContext.getSystemService(UserManager.class);
    --            return userManager.hasUserRestriction(UserManager.DISALLOW_MOUNT_PHYSICAL_MEDIA,
    -+            isTypeRestricted = userManager
    -+                    .hasUserRestriction(UserManager.DISALLOW_MOUNT_PHYSICAL_MEDIA,
    -                     Binder.getCallingUserHandle());
    --        } else {
    --            return false;
    -         }
    -+
    -+        return isUsbRestricted || isTypeRestricted;
    -     }
    - 
    -     private void enforceAdminUser() {
    -@@ -1985,6 +1998,11 @@ class MountService extends IMountService.Stub
    -         }
    - 
    -         if ((mask & StorageManager.DEBUG_FORCE_ADOPTABLE) != 0) {
    -+            if (StorageManager.isFileEncryptedNativeOnly()) {
    -+                throw new IllegalStateException(
    -+                        "Adoptable storage not available on device with native FBE");
    -+            }
    -+
    -             synchronized (mLock) {
    -                 mForceAdoptable = (flags & StorageManager.DEBUG_FORCE_ADOPTABLE) != 0;
    - 
    -diff --git a/services/core/java/com/android/server/RecoverySystemService.java b/services/core/java/com/android/server/RecoverySystemService.java
    -index 276687f..3c8c699 100644
    ---- a/services/core/java/com/android/server/RecoverySystemService.java
    -+++ b/services/core/java/com/android/server/RecoverySystemService.java
    -@@ -21,6 +21,7 @@ import android.net.LocalSocket;
    - import android.net.LocalSocketAddress;
    - import android.os.IRecoverySystem;
    - import android.os.IRecoverySystemProgressListener;
    -+import android.os.PowerManager;
    - import android.os.RecoverySystem;
    - import android.os.RemoteException;
    - import android.os.SystemProperties;
    -@@ -50,8 +51,15 @@ public final class RecoverySystemService extends SystemService {
    -     // The socket at /dev/socket/uncrypt to communicate with uncrypt.
    -     private static final String UNCRYPT_SOCKET = "uncrypt";
    - 
    -+    // The init services that communicate with /system/bin/uncrypt.
    -+    private static final String INIT_SERVICE_UNCRYPT = "init.svc.uncrypt";
    -+    private static final String INIT_SERVICE_SETUP_BCB = "init.svc.setup-bcb";
    -+    private static final String INIT_SERVICE_CLEAR_BCB = "init.svc.clear-bcb";
    -+
    -     private static final int SOCKET_CONNECTION_MAX_RETRY = 30;
    - 
    -+    private static final Object sRequestLock = new Object();
    -+
    -     private Context mContext;
    - 
    -     public RecoverySystemService(Context context) {
    -@@ -69,95 +77,155 @@ public final class RecoverySystemService extends SystemService {
    -         public boolean uncrypt(String filename, IRecoverySystemProgressListener listener) {
    -             if (DEBUG) Slog.d(TAG, "uncrypt: " + filename);
    - 
    --            mContext.enforceCallingOrSelfPermission(android.Manifest.permission.RECOVERY, null);
    -+            synchronized (sRequestLock) {
    -+                mContext.enforceCallingOrSelfPermission(android.Manifest.permission.RECOVERY, null);
    - 
    --            // Write the filename into UNCRYPT_PACKAGE_FILE to be read by
    --            // uncrypt.
    --            RecoverySystem.UNCRYPT_PACKAGE_FILE.delete();
    -+                final boolean available = checkAndWaitForUncryptService();
    -+                if (!available) {
    -+                    Slog.e(TAG, "uncrypt service is unavailable.");
    -+                    return false;
    -+                }
    - 
    --            try (FileWriter uncryptFile = new FileWriter(RecoverySystem.UNCRYPT_PACKAGE_FILE)) {
    --                uncryptFile.write(filename + "\n");
    --            } catch (IOException e) {
    --                Slog.e(TAG, "IOException when writing \"" + RecoverySystem.UNCRYPT_PACKAGE_FILE +
    --                        "\": ", e);
    --                return false;
    --            }
    -+                // Write the filename into UNCRYPT_PACKAGE_FILE to be read by
    -+                // uncrypt.
    -+                RecoverySystem.UNCRYPT_PACKAGE_FILE.delete();
    - 
    --            // Trigger uncrypt via init.
    --            SystemProperties.set("ctl.start", "uncrypt");
    -+                try (FileWriter uncryptFile = new FileWriter(RecoverySystem.UNCRYPT_PACKAGE_FILE)) {
    -+                    uncryptFile.write(filename + "\n");
    -+                } catch (IOException e) {
    -+                    Slog.e(TAG, "IOException when writing \"" +
    -+                            RecoverySystem.UNCRYPT_PACKAGE_FILE + "\":", e);
    -+                    return false;
    -+                }
    - 
    --            // Connect to the uncrypt service socket.
    --            LocalSocket socket = connectService();
    --            if (socket == null) {
    --                Slog.e(TAG, "Failed to connect to uncrypt socket");
    --                return false;
    --            }
    -+                // Trigger uncrypt via init.
    -+                SystemProperties.set("ctl.start", "uncrypt");
    - 
    --            // Read the status from the socket.
    --            DataInputStream dis = null;
    --            DataOutputStream dos = null;
    --            try {
    --                dis = new DataInputStream(socket.getInputStream());
    --                dos = new DataOutputStream(socket.getOutputStream());
    --                int lastStatus = Integer.MIN_VALUE;
    --                while (true) {
    --                    int status = dis.readInt();
    --                    // Avoid flooding the log with the same message.
    --                    if (status == lastStatus && lastStatus != Integer.MIN_VALUE) {
    --                        continue;
    --                    }
    --                    lastStatus = status;
    --
    --                    if (status >= 0 && status <= 100) {
    --                        // Update status
    --                        Slog.i(TAG, "uncrypt read status: " + status);
    --                        if (listener != null) {
    --                            try {
    --                                listener.onProgress(status);
    --                            } catch (RemoteException ignored) {
    --                                Slog.w(TAG, "RemoteException when posting progress");
    --                            }
    -+                // Connect to the uncrypt service socket.
    -+                LocalSocket socket = connectService();
    -+                if (socket == null) {
    -+                    Slog.e(TAG, "Failed to connect to uncrypt socket");
    -+                    return false;
    -+                }
    -+
    -+                // Read the status from the socket.
    -+                DataInputStream dis = null;
    -+                DataOutputStream dos = null;
    -+                try {
    -+                    dis = new DataInputStream(socket.getInputStream());
    -+                    dos = new DataOutputStream(socket.getOutputStream());
    -+                    int lastStatus = Integer.MIN_VALUE;
    -+                    while (true) {
    -+                        int status = dis.readInt();
    -+                        // Avoid flooding the log with the same message.
    -+                        if (status == lastStatus && lastStatus != Integer.MIN_VALUE) {
    -+                            continue;
    -                         }
    --                        if (status == 100) {
    --                            Slog.i(TAG, "uncrypt successfully finished.");
    --                            // Ack receipt of the final status code. uncrypt
    --                            // waits for the ack so the socket won't be
    --                            // destroyed before we receive the code.
    -+                        lastStatus = status;
    -+
    -+                        if (status >= 0 && status <= 100) {
    -+                            // Update status
    -+                            Slog.i(TAG, "uncrypt read status: " + status);
    -+                            if (listener != null) {
    -+                                try {
    -+                                    listener.onProgress(status);
    -+                                } catch (RemoteException ignored) {
    -+                                    Slog.w(TAG, "RemoteException when posting progress");
    -+                                }
    -+                            }
    -+                            if (status == 100) {
    -+                                Slog.i(TAG, "uncrypt successfully finished.");
    -+                                // Ack receipt of the final status code. uncrypt
    -+                                // waits for the ack so the socket won't be
    -+                                // destroyed before we receive the code.
    -+                                dos.writeInt(0);
    -+                                break;
    -+                            }
    -+                        } else {
    -+                            // Error in /system/bin/uncrypt.
    -+                            Slog.e(TAG, "uncrypt failed with status: " + status);
    -+                            // Ack receipt of the final status code. uncrypt waits
    -+                            // for the ack so the socket won't be destroyed before
    -+                            // we receive the code.
    -                             dos.writeInt(0);
    --                            break;
    -+                            return false;
    -                         }
    --                    } else {
    --                        // Error in /system/bin/uncrypt.
    --                        Slog.e(TAG, "uncrypt failed with status: " + status);
    --                        // Ack receipt of the final status code. uncrypt waits
    --                        // for the ack so the socket won't be destroyed before
    --                        // we receive the code.
    --                        dos.writeInt(0);
    --                        return false;
    -                     }
    -+                } catch (IOException e) {
    -+                    Slog.e(TAG, "IOException when reading status: ", e);
    -+                    return false;
    -+                } finally {
    -+                    IoUtils.closeQuietly(dis);
    -+                    IoUtils.closeQuietly(dos);
    -+                    IoUtils.closeQuietly(socket);
    -                 }
    --            } catch (IOException e) {
    --                Slog.e(TAG, "IOException when reading status: ", e);
    --                return false;
    --            } finally {
    --                IoUtils.closeQuietly(dis);
    --                IoUtils.closeQuietly(dos);
    --                IoUtils.closeQuietly(socket);
    --            }
    - 
    --            return true;
    -+                return true;
    -+            }
    -         }
    - 
    -         @Override // Binder call
    -         public boolean clearBcb() {
    -             if (DEBUG) Slog.d(TAG, "clearBcb");
    --            return setupOrClearBcb(false, null);
    -+            synchronized (sRequestLock) {
    -+                return setupOrClearBcb(false, null);
    -+            }
    -         }
    - 
    -         @Override // Binder call
    -         public boolean setupBcb(String command) {
    -             if (DEBUG) Slog.d(TAG, "setupBcb: [" + command + "]");
    --            return setupOrClearBcb(true, command);
    -+            synchronized (sRequestLock) {
    -+                return setupOrClearBcb(true, command);
    -+            }
    -+        }
    -+
    -+        @Override // Binder call
    -+        public void rebootRecoveryWithCommand(String command) {
    -+            if (DEBUG) Slog.d(TAG, "rebootRecoveryWithCommand: [" + command + "]");
    -+            synchronized (sRequestLock) {
    -+                if (!setupOrClearBcb(true, command)) {
    -+                    return;
    -+                }
    -+
    -+                // Having set up the BCB, go ahead and reboot.
    -+                PowerManager pm = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
    -+                pm.reboot(PowerManager.REBOOT_RECOVERY);
    -+            }
    -+        }
    -+
    -+        /**
    -+         * Check if any of the init services is still running. If so, we cannot
    -+         * start a new uncrypt/setup-bcb/clear-bcb service right away; otherwise
    -+         * it may break the socket communication since init creates / deletes
    -+         * the socket (/dev/socket/uncrypt) on service start / exit.
    -+         */
    -+        private boolean checkAndWaitForUncryptService() {
    -+            for (int retry = 0; retry < SOCKET_CONNECTION_MAX_RETRY; retry++) {
    -+                final String uncryptService = SystemProperties.get(INIT_SERVICE_UNCRYPT);
    -+                final String setupBcbService = SystemProperties.get(INIT_SERVICE_SETUP_BCB);
    -+                final String clearBcbService = SystemProperties.get(INIT_SERVICE_CLEAR_BCB);
    -+                final boolean busy = "running".equals(uncryptService) ||
    -+                        "running".equals(setupBcbService) || "running".equals(clearBcbService);
    -+                if (DEBUG) {
    -+                    Slog.i(TAG, "retry: " + retry + " busy: " + busy +
    -+                            " uncrypt: [" + uncryptService + "]" +
    -+                            " setupBcb: [" + setupBcbService + "]" +
    -+                            " clearBcb: [" + clearBcbService + "]");
    -+                }
    -+
    -+                if (!busy) {
    -+                    return true;
    -+                }
    -+
    -+                try {
    -+                    Thread.sleep(1000);
    -+                } catch (InterruptedException e) {
    -+                    Slog.w(TAG, "Interrupted:", e);
    -+                }
    -+            }
    -+
    -+            return false;
    -         }
    - 
    -         private LocalSocket connectService() {
    -@@ -176,7 +244,7 @@ public final class RecoverySystemService extends SystemService {
    -                     try {
    -                         Thread.sleep(1000);
    -                     } catch (InterruptedException e) {
    --                        Slog.w(TAG, "Interrupted: ", e);
    -+                        Slog.w(TAG, "Interrupted:", e);
    -                     }
    -                 }
    -             }
    -@@ -190,6 +258,12 @@ public final class RecoverySystemService extends SystemService {
    -         private boolean setupOrClearBcb(boolean isSetup, String command) {
    -             mContext.enforceCallingOrSelfPermission(android.Manifest.permission.RECOVERY, null);
    - 
    -+            final boolean available = checkAndWaitForUncryptService();
    -+            if (!available) {
    -+                Slog.e(TAG, "uncrypt service is unavailable.");
    -+                return false;
    -+            }
    -+
    -             if (isSetup) {
    -                 SystemProperties.set("ctl.start", "setup-bcb");
    -             } else {
    -@@ -232,7 +306,7 @@ public final class RecoverySystemService extends SystemService {
    -                     return false;
    -                 }
    -             } catch (IOException e) {
    --                Slog.e(TAG, "IOException when communicating with uncrypt: ", e);
    -+                Slog.e(TAG, "IOException when communicating with uncrypt:", e);
    -                 return false;
    -             } finally {
    -                 IoUtils.closeQuietly(dis);
    -diff --git a/services/core/java/com/android/server/ServiceWatcher.java b/services/core/java/com/android/server/ServiceWatcher.java
    -index 383e25a..2ff036b 100644
    ---- a/services/core/java/com/android/server/ServiceWatcher.java
    -+++ b/services/core/java/com/android/server/ServiceWatcher.java
    -@@ -141,8 +141,12 @@ public class ServiceWatcher implements ServiceConnection {
    -      * <p>
    -      * Note that if there are no matching encryption-aware services, we may not
    -      * bind to a real service until after the current user is unlocked.
    -+     *
    -+     * @returns {@code true} if a potential service implementation was found.
    -      */
    -     public boolean start() {
    -+        if (isServiceMissing()) return false;
    -+
    -         synchronized (mLock) {
    -             bindBestPackageLocked(mServicePackageName, false);
    -         }
    -@@ -174,6 +178,17 @@ public class ServiceWatcher implements ServiceConnection {
    -     }
    - 
    -     /**
    -+     * Check if any instance of this service is present on the device,
    -+     * regardless of it being encryption-aware or not.
    -+     */
    -+    private boolean isServiceMissing() {
    -+        final Intent intent = new Intent(mAction);
    -+        final int flags = PackageManager.MATCH_DIRECT_BOOT_AWARE
    -+                | PackageManager.MATCH_DIRECT_BOOT_UNAWARE;
    -+        return mPm.queryIntentServicesAsUser(intent, flags, mCurrentUserId).isEmpty();
    -+    }
    -+
    -+    /**
    -      * Searches and binds to the best package, or do nothing if the best package
    -      * is already bound, unless force rebinding is requested.
    -      *
    -@@ -181,7 +196,7 @@ public class ServiceWatcher implements ServiceConnection {
    -      *            packages if it is {@code null}.
    -      * @param forceRebind Force a rebinding to the best package if it's already
    -      *            bound.
    --     * @return {@code true} if a valid package was found to bind to.
    -+     * @returns {@code true} if a valid package was found to bind to.
    -      */
    -     private boolean bindBestPackageLocked(String justCheckThisPackage, boolean forceRebind) {
    -         Intent intent = new Intent(mAction);
    -diff --git a/services/core/java/com/android/server/TextServicesManagerService.java b/services/core/java/com/android/server/TextServicesManagerService.java
    -index 4b0d4be..4f02a23 100644
    ---- a/services/core/java/com/android/server/TextServicesManagerService.java
    -+++ b/services/core/java/com/android/server/TextServicesManagerService.java
    -@@ -459,71 +459,75 @@ public class TextServicesManagerService extends ITextServicesManager.Stub {
    -         if (!calledFromValidUser()) {
    -             return null;
    -         }
    -+        final int subtypeHashCode;
    -+        final SpellCheckerInfo sci;
    -+        final Locale systemLocale;
    -         synchronized (mSpellCheckerMap) {
    --            final int subtypeHashCode =
    -+            subtypeHashCode =
    -                     mSettings.getSelectedSpellCheckerSubtype(SpellCheckerSubtype.SUBTYPE_ID_NONE);
    -             if (DBG) {
    -                 Slog.w(TAG, "getCurrentSpellCheckerSubtype: " + subtypeHashCode);
    -             }
    --            final SpellCheckerInfo sci = getCurrentSpellChecker(null);
    --            if (sci == null || sci.getSubtypeCount() == 0) {
    --                if (DBG) {
    --                    Slog.w(TAG, "Subtype not found.");
    -+            sci = getCurrentSpellChecker(null);
    -+            systemLocale = mContext.getResources().getConfiguration().locale;
    -+        }
    -+        if (sci == null || sci.getSubtypeCount() == 0) {
    -+            if (DBG) {
    -+                Slog.w(TAG, "Subtype not found.");
    -+            }
    -+            return null;
    -+        }
    -+        if (subtypeHashCode == SpellCheckerSubtype.SUBTYPE_ID_NONE
    -+                && !allowImplicitlySelectedSubtype) {
    -+            return null;
    -+        }
    -+        String candidateLocale = null;
    -+        if (subtypeHashCode == 0) {
    -+            // Spell checker language settings == "auto"
    -+            final InputMethodManager imm = mContext.getSystemService(InputMethodManager.class);
    -+            if (imm != null) {
    -+                final InputMethodSubtype currentInputMethodSubtype =
    -+                        imm.getCurrentInputMethodSubtype();
    -+                if (currentInputMethodSubtype != null) {
    -+                    final String localeString = currentInputMethodSubtype.getLocale();
    -+                    if (!TextUtils.isEmpty(localeString)) {
    -+                        // 1. Use keyboard locale if available in the spell checker
    -+                        candidateLocale = localeString;
    -+                    }
    -                 }
    --                return null;
    -             }
    --            if (subtypeHashCode == SpellCheckerSubtype.SUBTYPE_ID_NONE
    --                    && !allowImplicitlySelectedSubtype) {
    --                return null;
    -+            if (candidateLocale == null) {
    -+                // 2. Use System locale if available in the spell checker
    -+                candidateLocale = systemLocale.toString();
    -             }
    --            String candidateLocale = null;
    -+        }
    -+        SpellCheckerSubtype candidate = null;
    -+        for (int i = 0; i < sci.getSubtypeCount(); ++i) {
    -+            final SpellCheckerSubtype scs = sci.getSubtypeAt(i);
    -             if (subtypeHashCode == 0) {
    --                // Spell checker language settings == "auto"
    --                final InputMethodManager imm = mContext.getSystemService(InputMethodManager.class);
    --                if (imm != null) {
    --                    final InputMethodSubtype currentInputMethodSubtype =
    --                            imm.getCurrentInputMethodSubtype();
    --                    if (currentInputMethodSubtype != null) {
    --                        final String localeString = currentInputMethodSubtype.getLocale();
    --                        if (!TextUtils.isEmpty(localeString)) {
    --                            // 1. Use keyboard locale if available in the spell checker
    --                            candidateLocale = localeString;
    --                        }
    -+                final String scsLocale = scs.getLocale();
    -+                if (candidateLocale.equals(scsLocale)) {
    -+                    return scs;
    -+                } else if (candidate == null) {
    -+                    if (candidateLocale.length() >= 2 && scsLocale.length() >= 2
    -+                            && candidateLocale.startsWith(scsLocale)) {
    -+                        // Fall back to the applicable language
    -+                        candidate = scs;
    -                     }
    -                 }
    --                if (candidateLocale == null) {
    --                    // 2. Use System locale if available in the spell checker
    --                    candidateLocale = mContext.getResources().getConfiguration().locale.toString();
    --                }
    --            }
    --            SpellCheckerSubtype candidate = null;
    --            for (int i = 0; i < sci.getSubtypeCount(); ++i) {
    --                final SpellCheckerSubtype scs = sci.getSubtypeAt(i);
    --                if (subtypeHashCode == 0) {
    --                    final String scsLocale = scs.getLocale();
    --                    if (candidateLocale.equals(scsLocale)) {
    --                        return scs;
    --                    } else if (candidate == null) {
    --                        if (candidateLocale.length() >= 2 && scsLocale.length() >= 2
    --                                && candidateLocale.startsWith(scsLocale)) {
    --                            // Fall back to the applicable language
    --                            candidate = scs;
    --                        }
    --                    }
    --                } else if (scs.hashCode() == subtypeHashCode) {
    --                    if (DBG) {
    --                        Slog.w(TAG, "Return subtype " + scs.hashCode() + ", input= " + locale
    --                                + ", " + scs.getLocale());
    --                    }
    --                    // 3. Use the user specified spell check language
    --                    return scs;
    -+            } else if (scs.hashCode() == subtypeHashCode) {
    -+                if (DBG) {
    -+                    Slog.w(TAG, "Return subtype " + scs.hashCode() + ", input= " + locale
    -+                            + ", " + scs.getLocale());
    -                 }
    -+                // 3. Use the user specified spell check language
    -+                return scs;
    -             }
    --            // 4. Fall back to the applicable language and return it if not null
    --            // 5. Simply just return it even if it's null which means we could find no suitable
    --            // spell check languages
    --            return candidate;
    -         }
    -+        // 4. Fall back to the applicable language and return it if not null
    -+        // 5. Simply just return it even if it's null which means we could find no suitable
    -+        // spell check languages
    -+        return candidate;
    -     }
    - 
    -     @Override
    -diff --git a/services/core/java/com/android/server/accounts/AccountManagerBackupHelper.java b/services/core/java/com/android/server/accounts/AccountManagerBackupHelper.java
    -new file mode 100644
    -index 0000000..1361a31
    ---- /dev/null
    -+++ b/services/core/java/com/android/server/accounts/AccountManagerBackupHelper.java
    -@@ -0,0 +1,315 @@
    -+/*
    -+ * Copyright (C) 2016 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 com.android.server.accounts;
    -+
    -+import android.accounts.Account;
    -+import android.accounts.AccountManager;
    -+import android.accounts.AccountManagerInternal;
    -+import android.annotation.IntRange;
    -+import android.annotation.NonNull;
    -+import android.content.pm.PackageInfo;
    -+import android.content.pm.PackageManager;
    -+import android.database.Cursor;
    -+import android.database.sqlite.SQLiteDatabase;
    -+import android.os.UserHandle;
    -+import android.text.TextUtils;
    -+import android.util.Log;
    -+import android.util.PackageUtils;
    -+import android.util.Xml;
    -+import com.android.internal.annotations.GuardedBy;
    -+import com.android.internal.content.PackageMonitor;
    -+import com.android.internal.util.FastXmlSerializer;
    -+import com.android.internal.util.XmlUtils;
    -+import org.xmlpull.v1.XmlPullParser;
    -+import org.xmlpull.v1.XmlPullParserException;
    -+import org.xmlpull.v1.XmlSerializer;
    -+
    -+import java.io.ByteArrayInputStream;
    -+import java.io.ByteArrayOutputStream;
    -+import java.io.IOException;
    -+import java.nio.charset.StandardCharsets;
    -+import java.util.ArrayList;
    -+import java.util.List;
    -+
    -+/**
    -+ * Helper class for backup and restore of account access grants.
    -+ */
    -+public final class AccountManagerBackupHelper {
    -+    private static final String TAG = "AccountManagerBackupHelper";
    -+
    -+    private static final long PENDING_RESTORE_TIMEOUT_MILLIS = 60 * 60 * 1000; // 1 hour
    -+
    -+    private static final String TAG_PERMISSIONS = "permissions";
    -+    private static final String TAG_PERMISSION = "permission";
    -+    private static final String ATTR_ACCOUNT_SHA_256 = "account-sha-256";
    -+    private static final String ATTR_PACKAGE = "package";
    -+    private static final String ATTR_DIGEST = "digest";
    -+
    -+    private static final String ACCOUNT_ACCESS_GRANTS = ""
    -+            + "SELECT " + AccountManagerService.ACCOUNTS_NAME + ", "
    -+            + AccountManagerService.GRANTS_GRANTEE_UID
    -+            + " FROM " + AccountManagerService.TABLE_ACCOUNTS
    -+            + ", " + AccountManagerService.TABLE_GRANTS
    -+            + " WHERE " + AccountManagerService.GRANTS_ACCOUNTS_ID
    -+            + "=" + AccountManagerService.ACCOUNTS_ID;
    -+
    -+    private final Object mLock = new Object();
    -+
    -+    private final AccountManagerService mAccountManagerService;
    -+    private final AccountManagerInternal mAccountManagerInternal;
    -+
    -+    @GuardedBy("mLock")
    -+    private List<PendingAppPermission> mRestorePendingAppPermissions;
    -+
    -+    @GuardedBy("mLock")
    -+    private RestorePackageMonitor mRestorePackageMonitor;
    -+
    -+    @GuardedBy("mLock")
    -+    private Runnable mRestoreCancelCommand;
    -+
    -+    public AccountManagerBackupHelper(AccountManagerService accountManagerService,
    -+            AccountManagerInternal accountManagerInternal) {
    -+        mAccountManagerService = accountManagerService;
    -+        mAccountManagerInternal = accountManagerInternal;
    -+    }
    -+
    -+    private final class PendingAppPermission {
    -+        private final @NonNull String accountDigest;
    -+        private final @NonNull String packageName;
    -+        private final @NonNull String certDigest;
    -+        private final @IntRange(from = 0) int userId;
    -+
    -+        public PendingAppPermission(String accountDigest, String packageName,
    -+                String certDigest, int userId) {
    -+            this.accountDigest = accountDigest;
    -+            this.packageName = packageName;
    -+            this.certDigest = certDigest;
    -+            this.userId = userId;
    -+        }
    -+
    -+        public boolean apply(PackageManager packageManager) {
    -+            Account account = null;
    -+            AccountManagerService.UserAccounts accounts = mAccountManagerService
    -+                    .getUserAccounts(userId);
    -+            synchronized (accounts.cacheLock) {
    -+                for (Account[] accountsPerType : accounts.accountCache.values()) {
    -+                    for (Account accountPerType : accountsPerType) {
    -+                        if (accountDigest.equals(PackageUtils.computeSha256Digest(
    -+                                accountPerType.name.getBytes()))) {
    -+                            account = accountPerType;
    -+                            break;
    -+                        }
    -+                    }
    -+                    if (account != null) {
    -+                        break;
    -+                    }
    -+                }
    -+            }
    -+            if (account == null) {
    -+                return false;
    -+            }
    -+            final PackageInfo packageInfo;
    -+            try {
    -+                packageInfo = packageManager.getPackageInfoAsUser(packageName,
    -+                        PackageManager.GET_SIGNATURES, userId);
    -+            } catch (PackageManager.NameNotFoundException e) {
    -+                return false;
    -+            }
    -+            String currentCertDigest = PackageUtils.computeCertSha256Digest(
    -+                    packageInfo.signatures[0]);
    -+            if (!certDigest.equals(currentCertDigest)) {
    -+                return false;
    -+            }
    -+            final int uid = packageInfo.applicationInfo.uid;
    -+            if (!mAccountManagerInternal.hasAccountAccess(account, uid)) {
    -+                mAccountManagerService.grantAppPermission(account,
    -+                        AccountManager.ACCOUNT_ACCESS_TOKEN_TYPE, uid);
    -+            }
    -+            return true;
    -+        }
    -+    }
    -+
    -+    public byte[] backupAccountAccessPermissions(int userId) {
    -+        final AccountManagerService.UserAccounts accounts = mAccountManagerService
    -+                .getUserAccounts(userId);
    -+        synchronized (accounts.cacheLock) {
    -+            SQLiteDatabase db = accounts.openHelper.getReadableDatabase();
    -+            try (
    -+                Cursor cursor = db.rawQuery(ACCOUNT_ACCESS_GRANTS, null);
    -+            ) {
    -+                if (cursor == null || !cursor.moveToFirst()) {
    -+                    return null;
    -+                }
    -+
    -+                final int nameColumnIdx = cursor.getColumnIndex(
    -+                        AccountManagerService.ACCOUNTS_NAME);
    -+                final int uidColumnIdx = cursor.getColumnIndex(
    -+                        AccountManagerService.GRANTS_GRANTEE_UID);
    -+
    -+                ByteArrayOutputStream dataStream = new ByteArrayOutputStream();
    -+                try {
    -+                    final XmlSerializer serializer = new FastXmlSerializer();
    -+                    serializer.setOutput(dataStream, StandardCharsets.UTF_8.name());
    -+                    serializer.startDocument(null, true);
    -+                    serializer.startTag(null, TAG_PERMISSIONS);
    -+
    -+                    PackageManager packageManager = mAccountManagerService.mContext
    -+                            .getPackageManager();
    -+
    -+                    do {
    -+                        final String accountName = cursor.getString(nameColumnIdx);
    -+                        final int uid = cursor.getInt(uidColumnIdx);
    -+
    -+                        final String[] packageNames = packageManager.getPackagesForUid(uid);
    -+                        if (packageNames == null) {
    -+                            continue;
    -+                        }
    -+
    -+                        for (String packageName : packageNames) {
    -+                            String digest = PackageUtils.computePackageCertSha256Digest(
    -+                                    packageManager, packageName, userId);
    -+                            if (digest != null) {
    -+                                serializer.startTag(null, TAG_PERMISSION);
    -+                                serializer.attribute(null, ATTR_ACCOUNT_SHA_256,
    -+                                        PackageUtils.computeSha256Digest(accountName.getBytes()));
    -+                                serializer.attribute(null, ATTR_PACKAGE, packageName);
    -+                                serializer.attribute(null, ATTR_DIGEST, digest);
    -+                                serializer.endTag(null, TAG_PERMISSION);
    -+                            }
    -+                        }
    -+                    } while (cursor.moveToNext());
    -+
    -+                    serializer.endTag(null, TAG_PERMISSIONS);
    -+                    serializer.endDocument();
    -+                    serializer.flush();
    -+                } catch (IOException e) {
    -+                    Log.e(TAG, "Error backing up account access grants", e);
    -+                    return null;
    -+                }
    -+
    -+                return dataStream.toByteArray();
    -+            }
    -+        }
    -+    }
    -+
    -+    public void restoreAccountAccessPermissions(byte[] data, int userId) {
    -+        try {
    -+            ByteArrayInputStream dataStream = new ByteArrayInputStream(data);
    -+            XmlPullParser parser = Xml.newPullParser();
    -+            parser.setInput(dataStream, StandardCharsets.UTF_8.name());
    -+            PackageManager packageManager = mAccountManagerService.mContext.getPackageManager();
    -+
    -+            final int permissionsOuterDepth = parser.getDepth();
    -+            while (XmlUtils.nextElementWithin(parser, permissionsOuterDepth)) {
    -+                if (!TAG_PERMISSIONS.equals(parser.getName())) {
    -+                    continue;
    -+                }
    -+                final int permissionOuterDepth = parser.getDepth();
    -+                while (XmlUtils.nextElementWithin(parser, permissionOuterDepth)) {
    -+                    if (!TAG_PERMISSION.equals(parser.getName())) {
    -+                        continue;
    -+                    }
    -+                    String accountDigest = parser.getAttributeValue(null, ATTR_ACCOUNT_SHA_256);
    -+                    if (TextUtils.isEmpty(accountDigest)) {
    -+                        XmlUtils.skipCurrentTag(parser);
    -+                    }
    -+                    String packageName = parser.getAttributeValue(null, ATTR_PACKAGE);
    -+                    if (TextUtils.isEmpty(packageName)) {
    -+                        XmlUtils.skipCurrentTag(parser);
    -+                    }
    -+                    String digest =  parser.getAttributeValue(null, ATTR_DIGEST);
    -+                    if (TextUtils.isEmpty(digest)) {
    -+                        XmlUtils.skipCurrentTag(parser);
    -+                    }
    -+
    -+                    PendingAppPermission pendingAppPermission = new PendingAppPermission(
    -+                            accountDigest, packageName, digest, userId);
    -+
    -+                    if (!pendingAppPermission.apply(packageManager)) {
    -+                        synchronized (mLock) {
    -+                            // Start watching before add pending to avoid a missed signal
    -+                            if (mRestorePackageMonitor == null) {
    -+                                mRestorePackageMonitor = new RestorePackageMonitor();
    -+                                mRestorePackageMonitor.register(mAccountManagerService.mContext,
    -+                                        mAccountManagerService.mMessageHandler.getLooper(), true);
    -+                            }
    -+                            if (mRestorePendingAppPermissions == null) {
    -+                                mRestorePendingAppPermissions = new ArrayList<>();
    -+                            }
    -+                            mRestorePendingAppPermissions.add(pendingAppPermission);
    -+                        }
    -+                    }
    -+                }
    -+            }
    -+
    -+            // Make sure we eventually prune the in-memory pending restores
    -+            synchronized (mLock) {
    -+                mRestoreCancelCommand = new CancelRestoreCommand();
    -+            }
    -+            mAccountManagerService.mMessageHandler.postDelayed(mRestoreCancelCommand,
    -+                    PENDING_RESTORE_TIMEOUT_MILLIS);
    -+        } catch (XmlPullParserException | IOException e) {
    -+            Log.e(TAG, "Error restoring app permissions", e);
    -+        }
    -+    }
    -+
    -+    private final class RestorePackageMonitor extends PackageMonitor {
    -+        @Override
    -+        public void onPackageAdded(String packageName, int uid) {
    -+            synchronized (mLock) {
    -+                // Can happen if restore is cancelled and there is a notification in flight
    -+                if (mRestorePendingAppPermissions == null) {
    -+                    return;
    -+                }
    -+                if (UserHandle.getUserId(uid) != UserHandle.USER_SYSTEM) {
    -+                    return;
    -+                }
    -+                final int count = mRestorePendingAppPermissions.size();
    -+                for (int i = count - 1; i >= 0; i--) {
    -+                    PendingAppPermission pendingAppPermission =
    -+                            mRestorePendingAppPermissions.get(i);
    -+                    if (!pendingAppPermission.packageName.equals(packageName)) {
    -+                        continue;
    -+                    }
    -+                    if (pendingAppPermission.apply(
    -+                            mAccountManagerService.mContext.getPackageManager())) {
    -+                        mRestorePendingAppPermissions.remove(i);
    -+                    }
    -+                }
    -+                if (mRestorePendingAppPermissions.isEmpty()
    -+                        && mRestoreCancelCommand != null) {
    -+                    mAccountManagerService.mMessageHandler.removeCallbacks(mRestoreCancelCommand);
    -+                    mRestoreCancelCommand.run();
    -+                    mRestoreCancelCommand = null;
    -+                }
    -+            }
    -+        }
    -+    }
    -+
    -+    private final class CancelRestoreCommand implements Runnable {
    -+        @Override
    -+        public void run() {
    -+            synchronized (mLock) {
    -+                mRestorePendingAppPermissions = null;
    -+                if (mRestorePackageMonitor != null) {
    -+                    mRestorePackageMonitor.unregister();
    -+                    mRestorePackageMonitor = null;
    -+                }
    -+            }
    -+        }
    -+    }
    -+}
    -diff --git a/services/core/java/com/android/server/accounts/AccountManagerService.java b/services/core/java/com/android/server/accounts/AccountManagerService.java
    -index b0e8c27..a7a79cd 100644
    ---- a/services/core/java/com/android/server/accounts/AccountManagerService.java
    -+++ b/services/core/java/com/android/server/accounts/AccountManagerService.java
    -@@ -22,6 +22,7 @@ import android.accounts.Account;
    - import android.accounts.AccountAndUser;
    - import android.accounts.AccountAuthenticatorResponse;
    - import android.accounts.AccountManager;
    -+import android.accounts.AccountManagerInternal;
    - import android.accounts.AuthenticatorDescription;
    - import android.accounts.CantAddAccountActivity;
    - import android.accounts.GrantCredentialsPermissionActivity;
    -@@ -29,11 +30,15 @@ import android.accounts.IAccountAuthenticator;
    - import android.accounts.IAccountAuthenticatorResponse;
    - import android.accounts.IAccountManager;
    - import android.accounts.IAccountManagerResponse;
    -+import android.annotation.IntRange;
    - import android.annotation.NonNull;
    -+import android.annotation.Nullable;
    - import android.app.ActivityManager;
    - import android.app.ActivityManagerNative;
    -+import android.app.ActivityThread;
    - import android.app.AppGlobals;
    - import android.app.AppOpsManager;
    -+import android.app.INotificationManager;
    - import android.app.Notification;
    - import android.app.NotificationManager;
    - import android.app.PendingIntent;
    -@@ -46,9 +51,11 @@ import android.content.ContentValues;
    - import android.content.Context;
    - import android.content.Intent;
    - import android.content.IntentFilter;
    -+import android.content.IntentSender;
    - import android.content.ServiceConnection;
    - import android.content.pm.ActivityInfo;
    - import android.content.pm.ApplicationInfo;
    -+import android.content.pm.IPackageManager;
    - import android.content.pm.PackageInfo;
    - import android.content.pm.PackageManager;
    - import android.content.pm.PackageManager.NameNotFoundException;
    -@@ -72,7 +79,9 @@ import android.os.Looper;
    - import android.os.Message;
    - import android.os.Parcel;
    - import android.os.Process;
    -+import android.os.RemoteCallback;
    - import android.os.RemoteException;
    -+import android.os.ServiceManager;
    - import android.os.SystemClock;
    - import android.os.UserHandle;
    - import android.os.UserManager;
    -@@ -85,7 +94,9 @@ import android.util.SparseArray;
    - import android.util.SparseBooleanArray;
    - 
    - import com.android.internal.R;
    -+import com.android.internal.annotations.GuardedBy;
    - import com.android.internal.annotations.VisibleForTesting;
    -+import com.android.internal.content.PackageMonitor;
    - import com.android.internal.util.ArrayUtils;
    - import com.android.internal.util.IndentingPrintWriter;
    - import com.android.internal.util.Preconditions;
    -@@ -115,6 +126,9 @@ import java.util.LinkedHashMap;
    - import java.util.List;
    - import java.util.Map;
    - import java.util.Map.Entry;
    -+import java.util.Objects;
    -+import java.util.UUID;
    -+import java.util.concurrent.CopyOnWriteArrayList;
    - import java.util.concurrent.atomic.AtomicInteger;
    - import java.util.concurrent.atomic.AtomicReference;
    - 
    -@@ -145,13 +159,6 @@ public class AccountManagerService
    -         }
    - 
    -         @Override
    --        public void onBootPhase(int phase) {
    --            if (phase == SystemService.PHASE_ACTIVITY_MANAGER_READY) {
    --                mService.systemReady();
    --            }
    --        }
    --
    --        @Override
    -         public void onUnlockUser(int userHandle) {
    -             mService.onUnlockUser(userHandle);
    -         }
    -@@ -164,13 +171,13 @@ public class AccountManagerService
    - 
    -     private static final int MAX_DEBUG_DB_SIZE = 64;
    - 
    --    private final Context mContext;
    -+    final Context mContext;
    - 
    -     private final PackageManager mPackageManager;
    -     private final AppOpsManager mAppOpsManager;
    -     private UserManager mUserManager;
    - 
    --    private final MessageHandler mMessageHandler;
    -+    final MessageHandler mMessageHandler;
    - 
    -     // Messages that can be sent on mHandler
    -     private static final int MESSAGE_TIMED_OUT = 3;
    -@@ -178,9 +185,9 @@ public class AccountManagerService
    - 
    -     private final IAccountAuthenticatorCache mAuthenticatorCache;
    - 
    --    private static final String TABLE_ACCOUNTS = "accounts";
    --    private static final String ACCOUNTS_ID = "_id";
    --    private static final String ACCOUNTS_NAME = "name";
    -+    static final String TABLE_ACCOUNTS = "accounts";
    -+    static final String ACCOUNTS_ID = "_id";
    -+    static final String ACCOUNTS_NAME = "name";
    -     private static final String ACCOUNTS_TYPE = "type";
    -     private static final String ACCOUNTS_TYPE_COUNT = "count(type)";
    -     private static final String ACCOUNTS_PASSWORD = "password";
    -@@ -194,10 +201,10 @@ public class AccountManagerService
    -     private static final String AUTHTOKENS_TYPE = "type";
    -     private static final String AUTHTOKENS_AUTHTOKEN = "authtoken";
    - 
    --    private static final String TABLE_GRANTS = "grants";
    --    private static final String GRANTS_ACCOUNTS_ID = "accounts_id";
    -+    static final String TABLE_GRANTS = "grants";
    -+    static final String GRANTS_ACCOUNTS_ID = "accounts_id";
    -     private static final String GRANTS_AUTH_TOKEN_TYPE = "auth_token_type";
    --    private static final String GRANTS_GRANTEE_UID = "uid";
    -+    static final String GRANTS_GRANTEE_UID = "uid";
    - 
    -     private static final String TABLE_EXTRAS = "extras";
    -     private static final String EXTRAS_ID = "_id";
    -@@ -237,6 +244,13 @@ public class AccountManagerService
    -             + " AND " + ACCOUNTS_NAME + "=?"
    -             + " AND " + ACCOUNTS_TYPE + "=?";
    - 
    -+    private static final String COUNT_OF_MATCHING_GRANTS_ANY_TOKEN = ""
    -+            + "SELECT COUNT(*) FROM " + TABLE_GRANTS + ", " + TABLE_ACCOUNTS
    -+            + " WHERE " + GRANTS_ACCOUNTS_ID + "=" + ACCOUNTS_ID
    -+            + " AND " + GRANTS_GRANTEE_UID + "=?"
    -+            + " AND " + ACCOUNTS_NAME + "=?"
    -+            + " AND " + ACCOUNTS_TYPE + "=?";
    -+
    -     private static final String SELECTION_AUTHTOKENS_BY_ACCOUNT =
    -             AUTHTOKENS_ACCOUNTS_ID + "=(select _id FROM accounts WHERE name=? AND type=?)";
    - 
    -@@ -257,16 +271,16 @@ public class AccountManagerService
    - 
    -     static class UserAccounts {
    -         private final int userId;
    --        private final DeDatabaseHelper openHelper;
    -+        final DeDatabaseHelper openHelper;
    -         private final HashMap<Pair<Pair<Account, String>, Integer>, Integer>
    -                 credentialsPermissionNotificationIds =
    -                 new HashMap<Pair<Pair<Account, String>, Integer>, Integer>();
    -         private final HashMap<Account, Integer> signinRequiredNotificationIds =
    -                 new HashMap<Account, Integer>();
    --        private final Object cacheLock = new Object();
    -+        final Object cacheLock = new Object();
    -         /** protected by the {@link #cacheLock} */
    --        private final HashMap<String, Account[]> accountCache =
    --                new LinkedHashMap<String, Account[]>();
    -+        final HashMap<String, Account[]> accountCache =
    -+                new LinkedHashMap<>();
    -         /** protected by the {@link #cacheLock} */
    -         private final HashMap<Account, HashMap<String, String>> userDataCache =
    -                 new HashMap<Account, HashMap<String, String>>();
    -@@ -305,6 +319,8 @@ public class AccountManagerService
    - 
    -     private final SparseArray<UserAccounts> mUsers = new SparseArray<>();
    -     private final SparseBooleanArray mLocalUnlockedUsers = new SparseBooleanArray();
    -+    private final CopyOnWriteArrayList<AccountManagerInternal.OnAppPermissionChangeListener>
    -+            mAppPermissionChangeListeners = new CopyOnWriteArrayList<>();
    - 
    -     private static AtomicReference<AccountManagerService> sThis = new AtomicReference<>();
    -     private static final Account[] EMPTY_ACCOUNT_ARRAY = new Account[]{};
    -@@ -376,6 +392,118 @@ public class AccountManagerService
    -                 }
    -             }
    -         }, UserHandle.ALL, userFilter, null, null);
    -+
    -+        LocalServices.addService(AccountManagerInternal.class, new AccountManagerInternalImpl());
    -+
    -+        // Need to cancel account request notifications if the update/install can access the account
    -+        new PackageMonitor() {
    -+            @Override
    -+            public void onPackageAdded(String packageName, int uid) {
    -+                // Called on a handler, and running as the system
    -+                cancelAccountAccessRequestNotificationIfNeeded(uid, true);
    -+            }
    -+
    -+            @Override
    -+            public void onPackageUpdateFinished(String packageName, int uid) {
    -+                // Called on a handler, and running as the system
    -+                cancelAccountAccessRequestNotificationIfNeeded(uid, true);
    -+            }
    -+        }.register(mContext, mMessageHandler.getLooper(), UserHandle.ALL, true);
    -+
    -+        // Cancel account request notification if an app op was preventing the account access
    -+        mAppOpsManager.startWatchingMode(AppOpsManager.OP_GET_ACCOUNTS, null,
    -+                new AppOpsManager.OnOpChangedInternalListener() {
    -+            @Override
    -+            public void onOpChanged(int op, String packageName) {
    -+                try {
    -+                    final int userId = ActivityManager.getCurrentUser();
    -+                    final int uid = mPackageManager.getPackageUidAsUser(packageName, userId);
    -+                    final int mode = mAppOpsManager.checkOpNoThrow(
    -+                            AppOpsManager.OP_GET_ACCOUNTS, uid, packageName);
    -+                    if (mode == AppOpsManager.MODE_ALLOWED) {
    -+                        final long identity = Binder.clearCallingIdentity();
    -+                        try {
    -+                            cancelAccountAccessRequestNotificationIfNeeded(packageName, uid, true);
    -+                        } finally {
    -+                            Binder.restoreCallingIdentity(identity);
    -+                        }
    -+                    }
    -+                } catch (NameNotFoundException e) {
    -+                    /* ignore */
    -+                }
    -+            }
    -+        });
    -+
    -+        // Cancel account request notification if a permission was preventing the account access
    -+        mPackageManager.addOnPermissionsChangeListener(
    -+                (int uid) -> {
    -+            Account[] accounts = null;
    -+            String[] packageNames = mPackageManager.getPackagesForUid(uid);
    -+            if (packageNames != null) {
    -+                final int userId = UserHandle.getUserId(uid);
    -+                final long identity = Binder.clearCallingIdentity();
    -+                try {
    -+                    for (String packageName : packageNames) {
    -+                        if (mContext.getPackageManager().checkPermission(
    -+                                Manifest.permission.GET_ACCOUNTS, packageName)
    -+                                        != PackageManager.PERMISSION_GRANTED) {
    -+                            continue;
    -+                        }
    -+
    -+                        if (accounts == null) {
    -+                            accounts = getAccountsAsUser(null, userId, "android");
    -+                            if (ArrayUtils.isEmpty(accounts)) {
    -+                                return;
    -+                            }
    -+                        }
    -+
    -+                        for (Account account : accounts) {
    -+                            cancelAccountAccessRequestNotificationIfNeeded(
    -+                                    account, uid, packageName, true);
    -+                        }
    -+                    }
    -+                } finally {
    -+                    Binder.restoreCallingIdentity(identity);
    -+                }
    -+            }
    -+        });
    -+    }
    -+
    -+    private void cancelAccountAccessRequestNotificationIfNeeded(int uid,
    -+            boolean checkAccess) {
    -+        Account[] accounts = getAccountsAsUser(null, UserHandle.getUserId(uid), "android");
    -+        for (Account account : accounts) {
    -+            cancelAccountAccessRequestNotificationIfNeeded(account, uid, checkAccess);
    -+        }
    -+    }
    -+
    -+    private void cancelAccountAccessRequestNotificationIfNeeded(String packageName, int uid,
    -+            boolean checkAccess) {
    -+        Account[] accounts = getAccountsAsUser(null, UserHandle.getUserId(uid), "android");
    -+        for (Account account : accounts) {
    -+            cancelAccountAccessRequestNotificationIfNeeded(account, uid, packageName, checkAccess);
    -+        }
    -+    }
    -+
    -+    private void cancelAccountAccessRequestNotificationIfNeeded(Account account, int uid,
    -+            boolean checkAccess) {
    -+        String[] packageNames = mPackageManager.getPackagesForUid(uid);
    -+        if (packageNames != null) {
    -+            for (String packageName : packageNames) {
    -+                cancelAccountAccessRequestNotificationIfNeeded(account, uid,
    -+                        packageName, checkAccess);
    -+            }
    -+        }
    -+    }
    -+
    -+    private void cancelAccountAccessRequestNotificationIfNeeded(Account account,
    -+            int uid, String packageName, boolean checkAccess) {
    -+        if (!checkAccess || hasAccountAccess(account, packageName,
    -+                UserHandle.getUserHandleForUid(uid))) {
    -+            cancelNotification(getCredentialPermissionNotificationId(account,
    -+                    AccountManager.ACCOUNT_ACCESS_TOKEN_TYPE, uid), packageName,
    -+                    UserHandle.getUserHandleForUid(uid));
    -+        }
    -     }
    - 
    -     @Override
    -@@ -393,9 +521,6 @@ public class AccountManagerService
    -         }
    -     }
    - 
    --    public void systemReady() {
    --    }
    --
    -     private UserManager getUserManager() {
    -         if (mUserManager == null) {
    -             mUserManager = UserManager.get(mContext);
    -@@ -566,7 +691,8 @@ public class AccountManagerService
    -                     final ArrayList<String> accountNames = cur.getValue();
    -                     final Account[] accountsForType = new Account[accountNames.size()];
    -                     for (int i = 0; i < accountsForType.length; i++) {
    --                        accountsForType[i] = new Account(accountNames.get(i), accountType);
    -+                        accountsForType[i] = new Account(accountNames.get(i), accountType,
    -+                                UUID.randomUUID().toString());
    -                     }
    -                     accounts.accountCache.put(accountType, accountsForType);
    -                 }
    -@@ -1376,6 +1502,8 @@ public class AccountManagerService
    -             Bundle result = new Bundle();
    -             result.putString(AccountManager.KEY_ACCOUNT_NAME, resultingAccount.name);
    -             result.putString(AccountManager.KEY_ACCOUNT_TYPE, resultingAccount.type);
    -+            result.putString(AccountManager.KEY_ACCOUNT_ACCESS_ID,
    -+                    resultingAccount.getAccessId());
    -             try {
    -                 response.onResult(result);
    -             } catch (RemoteException e) {
    -@@ -1434,8 +1562,10 @@ public class AccountManagerService
    -             /*
    -              * Database transaction was successful. Clean up cached
    -              * data associated with the account in the user profile.
    -+             * The account is now being tracked for remote access.
    -              */
    --            insertAccountIntoCacheLocked(accounts, renamedAccount);
    -+            renamedAccount = insertAccountIntoCacheLocked(accounts, renamedAccount);
    -+
    -             /*
    -              * Extract the data and token caches before removing the
    -              * old account to preserve the user data associated with
    -@@ -1722,6 +1852,21 @@ public class AccountManagerService
    -         } finally {
    -             Binder.restoreCallingIdentity(id);
    -         }
    -+
    -+        if (isChanged) {
    -+            synchronized (accounts.credentialsPermissionNotificationIds) {
    -+                for (Pair<Pair<Account, String>, Integer> key
    -+                        : accounts.credentialsPermissionNotificationIds.keySet()) {
    -+                    if (account.equals(key.first.first)
    -+                            && AccountManager.ACCOUNT_ACCESS_TOKEN_TYPE.equals(key.first.second)) {
    -+                        final int uid = (Integer) key.second;
    -+                        mMessageHandler.post(() -> cancelAccountAccessRequestNotificationIfNeeded(
    -+                                account, uid, false));
    -+                    }
    -+                }
    -+            }
    -+        }
    -+
    -         return isChanged;
    -     }
    - 
    -@@ -2118,7 +2263,7 @@ public class AccountManagerService
    - 
    -         final int callingUid = getCallingUid();
    -         clearCallingIdentity();
    --        if (callingUid != Process.SYSTEM_UID) {
    -+        if (UserHandle.getAppId(callingUid) != Process.SYSTEM_UID) {
    -             throw new SecurityException("can only call from system");
    -         }
    -         int userId = UserHandle.getUserId(callingUid);
    -@@ -2318,9 +2463,11 @@ public class AccountManagerService
    -                         if (result.containsKey(AccountManager.KEY_AUTH_TOKEN_LABEL)) {
    -                             Intent intent = newGrantCredentialsPermissionIntent(
    -                                     account,
    -+                                    null,
    -                                     callerUid,
    -                                     new AccountAuthenticatorResponse(this),
    --                                    authTokenType);
    -+                                    authTokenType,
    -+                                    true);
    -                             Bundle bundle = new Bundle();
    -                             bundle.putParcelable(AccountManager.KEY_INTENT, intent);
    -                             onResult(bundle);
    -@@ -2371,7 +2518,7 @@ public class AccountManagerService
    -                                     intent);
    -                             doNotification(mAccounts,
    -                                     account, result.getString(AccountManager.KEY_AUTH_FAILED_MESSAGE),
    --                                    intent, accounts.userId);
    -+                                    intent, "android", accounts.userId);
    -                         }
    -                     }
    -                     super.onResult(result);
    -@@ -2402,7 +2549,7 @@ public class AccountManagerService
    -     }
    - 
    -     private void createNoCredentialsPermissionNotification(Account account, Intent intent,
    --            int userId) {
    -+            String packageName, int userId) {
    -         int uid = intent.getIntExtra(
    -                 GrantCredentialsPermissionActivity.EXTRAS_REQUESTING_UID, -1);
    -         String authTokenType = intent.getStringExtra(
    -@@ -2430,20 +2577,23 @@ public class AccountManagerService
    -                         PendingIntent.FLAG_CANCEL_CURRENT, null, user))
    -                 .build();
    -         installNotification(getCredentialPermissionNotificationId(
    --                account, authTokenType, uid), n, user);
    -+                account, authTokenType, uid), n, packageName, user.getIdentifier());
    -     }
    - 
    --    private Intent newGrantCredentialsPermissionIntent(Account account, int uid,
    --            AccountAuthenticatorResponse response, String authTokenType) {
    -+    private Intent newGrantCredentialsPermissionIntent(Account account, String packageName,
    -+            int uid, AccountAuthenticatorResponse response, String authTokenType,
    -+            boolean startInNewTask) {
    - 
    -         Intent intent = new Intent(mContext, GrantCredentialsPermissionActivity.class);
    --        // See FLAG_ACTIVITY_NEW_TASK docs for limitations and benefits of the flag.
    --        // Since it was set in Eclair+ we can't change it without breaking apps using
    --        // the intent from a non-Activity context.
    --        intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
    --        intent.addCategory(
    --                String.valueOf(getCredentialPermissionNotificationId(account, authTokenType, uid)));
    - 
    -+        if (startInNewTask) {
    -+            // See FLAG_ACTIVITY_NEW_TASK docs for limitations and benefits of the flag.
    -+            // Since it was set in Eclair+ we can't change it without breaking apps using
    -+            // the intent from a non-Activity context. This is the default behavior.
    -+            intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
    -+        }
    -+        intent.addCategory(String.valueOf(getCredentialPermissionNotificationId(account,
    -+                authTokenType, uid) + (packageName != null ? packageName : "")));
    -         intent.putExtra(GrantCredentialsPermissionActivity.EXTRAS_ACCOUNT, account);
    -         intent.putExtra(GrantCredentialsPermissionActivity.EXTRAS_AUTH_TOKEN_TYPE, authTokenType);
    -         intent.putExtra(GrantCredentialsPermissionActivity.EXTRAS_RESPONSE, response);
    -@@ -3294,6 +3444,137 @@ public class AccountManagerService
    -     }
    - 
    -     @Override
    -+    public boolean hasAccountAccess(@NonNull Account account,  @NonNull String packageName,
    -+            @NonNull UserHandle userHandle) {
    -+        if (UserHandle.getAppId(Binder.getCallingUid()) != Process.SYSTEM_UID) {
    -+            throw new SecurityException("Can be called only by system UID");
    -+        }
    -+        Preconditions.checkNotNull(account, "account cannot be null");
    -+        Preconditions.checkNotNull(packageName, "packageName cannot be null");
    -+        Preconditions.checkNotNull(userHandle, "userHandle cannot be null");
    -+
    -+        final int userId = userHandle.getIdentifier();
    -+
    -+        Preconditions.checkArgumentInRange(userId, 0, Integer.MAX_VALUE, "user must be concrete");
    -+
    -+        try {
    -+            final int uid = mPackageManager.getPackageUidAsUser(packageName, userId);
    -+            return hasAccountAccess(account, packageName, uid);
    -+        } catch (NameNotFoundException e) {
    -+            return false;
    -+        }
    -+    }
    -+
    -+    private boolean hasAccountAccess(@NonNull Account account, @Nullable String packageName,
    -+            int uid) {
    -+        if (packageName == null) {
    -+            String[] packageNames = mPackageManager.getPackagesForUid(uid);
    -+            if (ArrayUtils.isEmpty(packageNames)) {
    -+                return false;
    -+            }
    -+            // For app op checks related to permissions all packages in the UID
    -+            // have the same app op state, so doesn't matter which one we pick.
    -+            packageName = packageNames[0];
    -+        }
    -+
    -+        // Use null token which means any token. Having a token means the package
    -+        // is trusted by the authenticator, hence it is fine to access the account.
    -+        if (permissionIsGranted(account, null, uid, UserHandle.getUserId(uid))) {
    -+            return true;
    -+        }
    -+        // In addition to the permissions required to get an auth token we also allow
    -+        // the account to be accessed by holders of the get accounts permissions.
    -+        return checkUidPermission(Manifest.permission.GET_ACCOUNTS_PRIVILEGED, uid, packageName)
    -+                || checkUidPermission(Manifest.permission.GET_ACCOUNTS, uid, packageName);
    -+    }
    -+
    -+    private boolean checkUidPermission(String permission, int uid, String opPackageName) {
    -+        final long identity = Binder.clearCallingIdentity();
    -+        try {
    -+            IPackageManager pm = ActivityThread.getPackageManager();
    -+            if (pm.checkUidPermission(permission, uid) != PackageManager.PERMISSION_GRANTED) {
    -+                return false;
    -+            }
    -+            final int opCode = AppOpsManager.permissionToOpCode(permission);
    -+            return (opCode == AppOpsManager.OP_NONE || mAppOpsManager.noteOpNoThrow(
    -+                    opCode, uid, opPackageName) == AppOpsManager.MODE_ALLOWED);
    -+        } catch (RemoteException e) {
    -+            /* ignore - local call */
    -+        } finally {
    -+            Binder.restoreCallingIdentity(identity);
    -+        }
    -+        return false;
    -+    }
    -+
    -+    @Override
    -+    public IntentSender createRequestAccountAccessIntentSenderAsUser(@NonNull Account account,
    -+            @NonNull String packageName, @NonNull UserHandle userHandle) {
    -+        if (UserHandle.getAppId(Binder.getCallingUid()) != Process.SYSTEM_UID) {
    -+            throw new SecurityException("Can be called only by system UID");
    -+        }
    -+
    -+        Preconditions.checkNotNull(account, "account cannot be null");
    -+        Preconditions.checkNotNull(packageName, "packageName cannot be null");
    -+        Preconditions.checkNotNull(userHandle, "userHandle cannot be null");
    -+
    -+        final int userId = userHandle.getIdentifier();
    -+
    -+        Preconditions.checkArgumentInRange(userId, 0, Integer.MAX_VALUE, "user must be concrete");
    -+
    -+        final int uid;
    -+        try {
    -+            uid = mPackageManager.getPackageUidAsUser(packageName, userId);
    -+        } catch (NameNotFoundException e) {
    -+            Slog.e(TAG, "Unknown package " + packageName);
    -+            return null;
    -+        }
    -+
    -+        Intent intent = newRequestAccountAccessIntent(account, packageName, uid, null);
    -+
    -+        final long identity = Binder.clearCallingIdentity();
    -+        try {
    -+            return PendingIntent.getActivityAsUser(
    -+                    mContext, 0, intent, PendingIntent.FLAG_ONE_SHOT
    -+                            | PendingIntent.FLAG_CANCEL_CURRENT | PendingIntent.FLAG_IMMUTABLE,
    -+                    null, new UserHandle(userId)).getIntentSender();
    -+        } finally {
    -+            Binder.restoreCallingIdentity(identity);
    -+        }
    -+    }
    -+
    -+    private Intent newRequestAccountAccessIntent(Account account, String packageName,
    -+            int uid, RemoteCallback callback) {
    -+        return newGrantCredentialsPermissionIntent(account, packageName, uid,
    -+                new AccountAuthenticatorResponse(new IAccountAuthenticatorResponse.Stub() {
    -+            @Override
    -+            public void onResult(Bundle value) throws RemoteException {
    -+                handleAuthenticatorResponse(true);
    -+            }
    -+
    -+            @Override
    -+            public void onRequestContinued() {
    -+                /* ignore */
    -+            }
    -+
    -+            @Override
    -+            public void onError(int errorCode, String errorMessage) throws RemoteException {
    -+                handleAuthenticatorResponse(false);
    -+            }
    -+
    -+            private void handleAuthenticatorResponse(boolean accessGranted) throws RemoteException {
    -+                cancelNotification(getCredentialPermissionNotificationId(account,
    -+                        AccountManager.ACCOUNT_ACCESS_TOKEN_TYPE, uid), packageName,
    -+                        UserHandle.getUserHandleForUid(uid));
    -+                if (callback != null) {
    -+                    Bundle result = new Bundle();
    -+                    result.putBoolean(AccountManager.KEY_BOOLEAN_RESULT, accessGranted);
    -+                    callback.sendResult(result);
    -+                }
    -+            }
    -+        }), AccountManager.ACCOUNT_ACCESS_TOKEN_TYPE, false);
    -+    }
    -+
    -+    @Override
    -     public boolean someUserHasAccount(@NonNull final Account account) {
    -         if (!UserHandle.isSameApp(Process.SYSTEM_UID, Binder.getCallingUid())) {
    -             throw new SecurityException("Only system can check for accounts across users");
    -@@ -3798,6 +4079,30 @@ public class AccountManagerService
    -         }
    -     }
    - 
    -+    @Override
    -+    public void onAccountAccessed(String token) throws RemoteException {
    -+        final int uid = Binder.getCallingUid();
    -+        if (UserHandle.getAppId(uid) == Process.SYSTEM_UID) {
    -+            return;
    -+        }
    -+        final int userId = UserHandle.getCallingUserId();
    -+        final long identity = Binder.clearCallingIdentity();
    -+        try {
    -+            for (Account account : getAccounts(userId, mContext.getOpPackageName())) {
    -+                if (Objects.equals(account.getAccessId(), token)) {
    -+                    // An app just accessed the account. At this point it knows about
    -+                    // it and there is not need to hide this account from the app.
    -+                    if (!hasAccountAccess(account, null, uid)) {
    -+                        updateAppPermission(account, AccountManager.ACCOUNT_ACCESS_TOKEN_TYPE,
    -+                                uid, true);
    -+                    }
    -+                }
    -+            }
    -+        } finally {
    -+            Binder.restoreCallingIdentity(identity);
    -+        }
    -+    }
    -+
    -     private abstract class Session extends IAccountAuthenticatorResponse.Stub
    -             implements IBinder.DeathRecipient, ServiceConnection {
    -         IAccountManagerResponse mResponse;
    -@@ -4166,7 +4471,7 @@ public class AccountManagerService
    -         }
    -     }
    - 
    --    private class MessageHandler extends Handler {
    -+    class MessageHandler extends Handler {
    -         MessageHandler(Looper looper) {
    -             super(looper);
    -         }
    -@@ -4933,7 +5238,7 @@ public class AccountManagerService
    -     }
    - 
    -     private void doNotification(UserAccounts accounts, Account account, CharSequence message,
    --            Intent intent, int userId) {
    -+            Intent intent, String packageName, final int userId) {
    -         long identityToken = clearCallingIdentity();
    -         try {
    -             if (Log.isLoggable(TAG, Log.VERBOSE)) {
    -@@ -4943,12 +5248,12 @@ public class AccountManagerService
    -             if (intent.getComponent() != null &&
    -                     GrantCredentialsPermissionActivity.class.getName().equals(
    -                             intent.getComponent().getClassName())) {
    --                createNoCredentialsPermissionNotification(account, intent, userId);
    -+                createNoCredentialsPermissionNotification(account, intent, packageName, userId);
    -             } else {
    -+                Context contextForUser = getContextForUser(new UserHandle(userId));
    -                 final Integer notificationId = getSigninRequiredNotificationId(accounts, account);
    -                 intent.addCategory(String.valueOf(notificationId));
    --                UserHandle user = new UserHandle(userId);
    --                Context contextForUser = getContextForUser(user);
    -+
    -                 final String notificationTitleFormat =
    -                         contextForUser.getText(R.string.notification_title).toString();
    -                 Notification n = new Notification.Builder(contextForUser)
    -@@ -4960,9 +5265,9 @@ public class AccountManagerService
    -                         .setContentText(message)
    -                         .setContentIntent(PendingIntent.getActivityAsUser(
    -                                 mContext, 0, intent, PendingIntent.FLAG_CANCEL_CURRENT,
    --                                null, user))
    -+                                null, new UserHandle(userId)))
    -                         .build();
    --                installNotification(notificationId, n, user);
    -+                installNotification(notificationId, n, packageName, userId);
    -             }
    -         } finally {
    -             restoreCallingIdentity(identityToken);
    -@@ -4970,18 +5275,40 @@ public class AccountManagerService
    -     }
    - 
    -     @VisibleForTesting
    --    protected void installNotification(final int notificationId, final Notification n,
    -+    protected void installNotification(int notificationId, final Notification notification,
    -             UserHandle user) {
    --        ((NotificationManager) mContext.getSystemService(Context.NOTIFICATION_SERVICE))
    --                .notifyAsUser(null, notificationId, n, user);
    -+        installNotification(notificationId, notification, "android", user.getIdentifier());
    -+    }
    -+
    -+    private void installNotification(int notificationId, final Notification notification,
    -+            String packageName, int userId) {
    -+        final long token = clearCallingIdentity();
    -+        try {
    -+            INotificationManager notificationManager = NotificationManager.getService();
    -+            try {
    -+                notificationManager.enqueueNotificationWithTag(packageName, packageName, null,
    -+                        notificationId, notification, new int[1], userId);
    -+            } catch (RemoteException e) {
    -+                /* ignore - local call */
    -+            }
    -+        } finally {
    -+            Binder.restoreCallingIdentity(token);
    -+        }
    -     }
    - 
    -     @VisibleForTesting
    -     protected void cancelNotification(int id, UserHandle user) {
    -+        cancelNotification(id, mContext.getPackageName(), user);
    -+    }
    -+
    -+    protected void cancelNotification(int id, String packageName, UserHandle user) {
    -         long identityToken = clearCallingIdentity();
    -         try {
    --            ((NotificationManager) mContext.getSystemService(Context.NOTIFICATION_SERVICE))
    --                .cancelAsUser(null, id, user);
    -+            INotificationManager service = INotificationManager.Stub.asInterface(
    -+                    ServiceManager.getService(Context.NOTIFICATION_SERVICE));
    -+            service.cancelNotificationWithTag(packageName, null, id, user.getIdentifier());
    -+        } catch (RemoteException e) {
    -+            /* ignore - local call */
    -         } finally {
    -             restoreCallingIdentity(identityToken);
    -         }
    -@@ -5042,18 +5369,40 @@ public class AccountManagerService
    - 
    -     private boolean permissionIsGranted(
    -             Account account, String authTokenType, int callerUid, int userId) {
    --        final boolean isPrivileged = isPrivileged(callerUid);
    --        final boolean fromAuthenticator = account != null
    --                && isAccountManagedByCaller(account.type, callerUid, userId);
    --        final boolean hasExplicitGrants = account != null
    --                && hasExplicitlyGrantedPermission(account, authTokenType, callerUid);
    -+        if (UserHandle.getAppId(callerUid) == Process.SYSTEM_UID) {
    -+            if (Log.isLoggable(TAG, Log.VERBOSE)) {
    -+                Log.v(TAG, "Access to " + account + " granted calling uid is system");
    -+            }
    -+            return true;
    -+        }
    -+
    -+        if (isPrivileged(callerUid)) {
    -+            if (Log.isLoggable(TAG, Log.VERBOSE)) {
    -+                Log.v(TAG, "Access to " + account + " granted calling uid "
    -+                        + callerUid + " privileged");
    -+            }
    -+            return true;
    -+        }
    -+        if (account != null && isAccountManagedByCaller(account.type, callerUid, userId)) {
    -+            if (Log.isLoggable(TAG, Log.VERBOSE)) {
    -+                Log.v(TAG, "Access to " + account + " granted calling uid "
    -+                        + callerUid + " manages the account");
    -+            }
    -+            return true;
    -+        }
    -+        if (account != null && hasExplicitlyGrantedPermission(account, authTokenType, callerUid)) {
    -+            if (Log.isLoggable(TAG, Log.VERBOSE)) {
    -+                Log.v(TAG, "Access to " + account + " granted calling uid "
    -+                        + callerUid + " user granted access");
    -+            }
    -+            return true;
    -+        }
    -+
    -         if (Log.isLoggable(TAG, Log.VERBOSE)) {
    --            Log.v(TAG, "checkGrantsOrCallingUidAgainstAuthenticator: caller uid "
    --                    + callerUid + ", " + account
    --                    + ": is authenticator? " + fromAuthenticator
    --                    + ", has explicit permission? " + hasExplicitGrants);
    -+            Log.v(TAG, "Access to " + account + " not granted for uid " + callerUid);
    -         }
    --        return fromAuthenticator || hasExplicitGrants || isPrivileged;
    -+
    -+        return false;
    -     }
    - 
    -     private boolean isAccountVisibleToCaller(String accountType, int callingUid, int userId,
    -@@ -5137,16 +5486,26 @@ public class AccountManagerService
    - 
    -     private boolean hasExplicitlyGrantedPermission(Account account, String authTokenType,
    -             int callerUid) {
    --        if (callerUid == Process.SYSTEM_UID) {
    -+        if (UserHandle.getAppId(callerUid) == Process.SYSTEM_UID) {
    -             return true;
    -         }
    --        UserAccounts accounts = getUserAccountsForCaller();
    -+        UserAccounts accounts = getUserAccounts(UserHandle.getUserId(callerUid));
    -         synchronized (accounts.cacheLock) {
    -             final SQLiteDatabase db = accounts.openHelper.getReadableDatabase();
    --            String[] args = { String.valueOf(callerUid), authTokenType,
    --                    account.name, account.type};
    --            final boolean permissionGranted =
    --                    DatabaseUtils.longForQuery(db, COUNT_OF_MATCHING_GRANTS, args) != 0;
    -+
    -+            final String query;
    -+            final String[] args;
    -+
    -+            if (authTokenType != null) {
    -+                query = COUNT_OF_MATCHING_GRANTS;
    -+                args = new String[] {String.valueOf(callerUid), authTokenType,
    -+                        account.name, account.type};
    -+            } else {
    -+                query = COUNT_OF_MATCHING_GRANTS_ANY_TOKEN;
    -+                args = new String[] {String.valueOf(callerUid), account.name,
    -+                        account.type};
    -+            }
    -+            final boolean permissionGranted = DatabaseUtils.longForQuery(db, query, args) != 0;
    -             if (!permissionGranted && ActivityManager.isRunningInTestHarness()) {
    -                 // TODO: Skip this check when running automated tests. Replace this
    -                 // with a more general solution.
    -@@ -5245,7 +5604,7 @@ public class AccountManagerService
    -             throws RemoteException {
    -         final int callingUid = getCallingUid();
    - 
    --        if (callingUid != Process.SYSTEM_UID) {
    -+        if (UserHandle.getAppId(callingUid) != Process.SYSTEM_UID) {
    -             throw new SecurityException();
    -         }
    - 
    -@@ -5263,7 +5622,7 @@ public class AccountManagerService
    -      * which is in the system. This means we don't need to protect it with permissions.
    -      * @hide
    -      */
    --    private void grantAppPermission(Account account, String authTokenType, int uid) {
    -+    void grantAppPermission(Account account, String authTokenType, int uid) {
    -         if (account == null || authTokenType == null) {
    -             Log.e(TAG, "grantAppPermission: called with invalid arguments", new Exception());
    -             return;
    -@@ -5287,6 +5646,14 @@ public class AccountManagerService
    -             }
    -             cancelNotification(getCredentialPermissionNotificationId(account, authTokenType, uid),
    -                     UserHandle.of(accounts.userId));
    -+
    -+            cancelAccountAccessRequestNotificationIfNeeded(account, uid, true);
    -+        }
    -+
    -+        // Listeners are a final CopyOnWriteArrayList, hence no lock needed.
    -+        for (AccountManagerInternal.OnAppPermissionChangeListener listener
    -+                : mAppPermissionChangeListeners) {
    -+            mMessageHandler.post(() -> listener.onAppPermissionChanged(account, uid));
    -         }
    -     }
    - 
    -@@ -5320,9 +5687,16 @@ public class AccountManagerService
    -             } finally {
    -                 db.endTransaction();
    -             }
    -+
    -             cancelNotification(getCredentialPermissionNotificationId(account, authTokenType, uid),
    -                     new UserHandle(accounts.userId));
    -         }
    -+
    -+        // Listeners are a final CopyOnWriteArrayList, hence no lock needed.
    -+        for (AccountManagerInternal.OnAppPermissionChangeListener listener
    -+                : mAppPermissionChangeListeners) {
    -+            mMessageHandler.post(() -> listener.onAppPermissionChanged(account, uid));
    -+        }
    -     }
    - 
    -     static final private String stringArrayToString(String[] value) {
    -@@ -5353,16 +5727,22 @@ public class AccountManagerService
    - 
    -     /**
    -      * This assumes that the caller has already checked that the account is not already present.
    -+     * IMPORTANT: The account being inserted will begin to be tracked for access in remote
    -+     * processes and if you will return this account to apps you should return the result.
    -+     * @return The inserted account which is a new instance that is being tracked.
    -      */
    --    private void insertAccountIntoCacheLocked(UserAccounts accounts, Account account) {
    -+    private Account insertAccountIntoCacheLocked(UserAccounts accounts, Account account) {
    -         Account[] accountsForType = accounts.accountCache.get(account.type);
    -         int oldLength = (accountsForType != null) ? accountsForType.length : 0;
    -         Account[] newAccountsForType = new Account[oldLength + 1];
    -         if (accountsForType != null) {
    -             System.arraycopy(accountsForType, 0, newAccountsForType, 0, oldLength);
    -         }
    --        newAccountsForType[oldLength] = account;
    -+        String token = account.getAccessId() != null ? account.getAccessId()
    -+                : UUID.randomUUID().toString();
    -+        newAccountsForType[oldLength] = new Account(account, token);
    -         accounts.accountCache.put(account.type, newAccountsForType);
    -+        return newAccountsForType[oldLength];
    -     }
    - 
    -     private Account[] filterSharedAccounts(UserAccounts userAccounts, Account[] unfiltered,
    -@@ -5604,4 +5984,88 @@ public class AccountManagerService
    -             }
    -         }
    -     }
    -+
    -+    private final class AccountManagerInternalImpl extends AccountManagerInternal {
    -+        private final Object mLock = new Object();
    -+
    -+        @GuardedBy("mLock")
    -+        private AccountManagerBackupHelper mBackupHelper;
    -+
    -+        @Override
    -+        public void requestAccountAccess(@NonNull Account account, @NonNull String packageName,
    -+                @IntRange(from = 0) int userId, @NonNull RemoteCallback callback) {
    -+            if (account == null) {
    -+                Slog.w(TAG, "account cannot be null");
    -+                return;
    -+            }
    -+            if (packageName == null) {
    -+                Slog.w(TAG, "packageName cannot be null");
    -+                return;
    -+            }
    -+            if (userId < UserHandle.USER_SYSTEM) {
    -+                Slog.w(TAG, "user id must be concrete");
    -+                return;
    -+            }
    -+            if (callback == null) {
    -+                Slog.w(TAG, "callback cannot be null");
    -+                return;
    -+            }
    -+
    -+            if (AccountManagerService.this.hasAccountAccess(account, packageName,
    -+                    new UserHandle(userId))) {
    -+                Bundle result = new Bundle();
    -+                result.putBoolean(AccountManager.KEY_BOOLEAN_RESULT, true);
    -+                callback.sendResult(result);
    -+                return;
    -+            }
    -+
    -+            final int uid;
    -+            try {
    -+                uid = mPackageManager.getPackageUidAsUser(packageName, userId);
    -+            } catch (NameNotFoundException e) {
    -+                Slog.e(TAG, "Unknown package " + packageName);
    -+                return;
    -+            }
    -+
    -+            Intent intent = newRequestAccountAccessIntent(account, packageName, uid, callback);
    -+            final UserAccounts userAccounts;
    -+            synchronized (mUsers) {
    -+                userAccounts = mUsers.get(userId);
    -+            }
    -+            doNotification(userAccounts, account, null, intent, packageName, userId);
    -+        }
    -+
    -+        @Override
    -+        public void addOnAppPermissionChangeListener(OnAppPermissionChangeListener listener) {
    -+            // Listeners are a final CopyOnWriteArrayList, hence no lock needed.
    -+            mAppPermissionChangeListeners.add(listener);
    -+        }
    -+
    -+        @Override
    -+        public boolean hasAccountAccess(@NonNull Account account, @IntRange(from = 0) int uid) {
    -+            return AccountManagerService.this.hasAccountAccess(account, null, uid);
    -+        }
    -+
    -+        @Override
    -+        public byte[] backupAccountAccessPermissions(int userId) {
    -+            synchronized (mLock) {
    -+                if (mBackupHelper == null) {
    -+                    mBackupHelper = new AccountManagerBackupHelper(
    -+                            AccountManagerService.this, this);
    -+                }
    -+                return mBackupHelper.backupAccountAccessPermissions(userId);
    -+            }
    -+        }
    -+
    -+        @Override
    -+        public void restoreAccountAccessPermissions(byte[] data, int userId) {
    -+            synchronized (mLock) {
    -+                if (mBackupHelper == null) {
    -+                    mBackupHelper = new AccountManagerBackupHelper(
    -+                            AccountManagerService.this, this);
    -+                }
    -+                mBackupHelper.restoreAccountAccessPermissions(data, userId);
    -+            }
    -+        }
    -+    }
    - }
    -diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
    -index 40f3608..ba10c64 100644
    ---- a/services/core/java/com/android/server/am/ActivityManagerService.java
    -+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
    -@@ -641,7 +641,8 @@ public final class ActivityManagerService extends ActivityManagerNative
    -     boolean mDoingSetFocusedActivity;
    - 
    -     public boolean canShowErrorDialogs() {
    --        return mShowDialogs && !mSleeping && !mShuttingDown;
    -+        return mShowDialogs && !mSleeping && !mShuttingDown
    -+                && mLockScreenShown != LOCK_SCREEN_SHOWN;
    -     }
    - 
    -     private static final class PriorityState {
    -@@ -1158,6 +1159,7 @@ public final class ActivityManagerService extends ActivityManagerNative
    -      * For example, references to the commonly used services.
    -      */
    -     HashMap<String, IBinder> mAppBindArgs;
    -+    HashMap<String, IBinder> mIsolatedAppBindArgs;
    - 
    -     /**
    -      * Temporary to avoid allocations.  Protected by main lock.
    -@@ -2377,22 +2379,21 @@ public final class ActivityManagerService extends ActivityManagerNative
    -                 if (memInfo != null) {
    -                     updateCpuStatsNow();
    -                     long nativeTotalPss = 0;
    -+                    final List<ProcessCpuTracker.Stats> stats;
    -                     synchronized (mProcessCpuTracker) {
    --                        final int N = mProcessCpuTracker.countStats();
    --                        for (int j=0; j<N; j++) {
    --                            ProcessCpuTracker.Stats st = mProcessCpuTracker.getStats(j);
    --                            if (st.vsize <= 0 || st.uid >= Process.FIRST_APPLICATION_UID) {
    --                                // This is definitely an application process; skip it.
    -+                        stats = mProcessCpuTracker.getStats( (st)-> {
    -+                            return st.vsize > 0 && st.uid < Process.FIRST_APPLICATION_UID;
    -+                        });
    -+                    }
    -+                    final int N = stats.size();
    -+                    for (int j = 0; j < N; j++) {
    -+                        synchronized (mPidsSelfLocked) {
    -+                            if (mPidsSelfLocked.indexOfKey(stats.get(j).pid) >= 0) {
    -+                                // This is one of our own processes; skip it.
    -                                 continue;
    -                             }
    --                            synchronized (mPidsSelfLocked) {
    --                                if (mPidsSelfLocked.indexOfKey(st.pid) >= 0) {
    --                                    // This is one of our own processes; skip it.
    --                                    continue;
    --                                }
    --                            }
    --                            nativeTotalPss += Debug.getPss(st.pid, null, null);
    -                         }
    -+                        nativeTotalPss += Debug.getPss(stats.get(j).pid, null, null);
    -                     }
    -                     memInfo.readMemInfo();
    -                     synchronized (ActivityManagerService.this) {
    -@@ -2935,18 +2936,24 @@ public final class ActivityManagerService extends ActivityManagerNative
    -      * lazily setup to make sure the services are running when they're asked for.
    -      */
    -     private HashMap<String, IBinder> getCommonServicesLocked(boolean isolated) {
    -+        // Isolated processes won't get this optimization, so that we don't
    -+        // violate the rules about which services they have access to.
    -+        if (isolated) {
    -+            if (mIsolatedAppBindArgs == null) {
    -+                mIsolatedAppBindArgs = new HashMap<>();
    -+                mIsolatedAppBindArgs.put("package", ServiceManager.getService("package"));
    -+            }
    -+            return mIsolatedAppBindArgs;
    -+        }
    -+
    -         if (mAppBindArgs == null) {
    -             mAppBindArgs = new HashMap<>();
    - 
    --            // Isolated processes won't get this optimization, so that we don't
    --            // violate the rules about which services they have access to.
    --            if (!isolated) {
    --                // Setup the application init args
    --                mAppBindArgs.put("package", ServiceManager.getService("package"));
    --                mAppBindArgs.put("window", ServiceManager.getService("window"));
    --                mAppBindArgs.put(Context.ALARM_SERVICE,
    --                        ServiceManager.getService(Context.ALARM_SERVICE));
    --            }
    -+            // Setup the application init args
    -+            mAppBindArgs.put("package", ServiceManager.getService("package"));
    -+            mAppBindArgs.put("window", ServiceManager.getService("window"));
    -+            mAppBindArgs.put(Context.ALARM_SERVICE,
    -+                    ServiceManager.getService(Context.ALARM_SERVICE));
    -         }
    -         return mAppBindArgs;
    -     }
    -@@ -9576,7 +9583,7 @@ public final class ActivityManagerService extends ActivityManagerNative
    -         for (int i = 0; i < procsToKill.size(); i++) {
    -             ProcessRecord pr = procsToKill.get(i);
    -             if (pr.setSchedGroup == ProcessList.SCHED_GROUP_BACKGROUND
    --                    && pr.curReceiver == null) {
    -+                    && pr.curReceivers.isEmpty()) {
    -                 pr.kill("remove task", true);
    -             } else {
    -                 // We delay killing processes that are not in the background or running a receiver.
    -@@ -13831,7 +13838,7 @@ public final class ActivityManagerService extends ActivityManagerNative
    -                     try {
    -                         java.lang.Process logcat = new ProcessBuilder(
    -                                 "/system/bin/timeout", "-k", "15s", "10s",
    --                                "/system/bin/logcat", "-v", "time", "-b", "events", "-b", "system",
    -+                                "/system/bin/logcat", "-v", "threadtime", "-b", "events", "-b", "system",
    -                                 "-b", "main", "-b", "crash", "-t", String.valueOf(lines))
    -                                         .redirectErrorStream(true).start();
    - 
    -@@ -16521,21 +16528,24 @@ public final class ActivityManagerService extends ActivityManagerNative
    -         }
    -         updateCpuStatsNow();
    -         long[] memtrackTmp = new long[1];
    -+        final List<ProcessCpuTracker.Stats> stats;
    -+        // Get a list of Stats that have vsize > 0
    -         synchronized (mProcessCpuTracker) {
    --            final int N = mProcessCpuTracker.countStats();
    --            for (int i=0; i<N; i++) {
    --                ProcessCpuTracker.Stats st = mProcessCpuTracker.getStats(i);
    --                if (st.vsize > 0) {
    --                    long pss = Debug.getPss(st.pid, null, memtrackTmp);
    --                    if (pss > 0) {
    --                        if (infoMap.indexOfKey(st.pid) < 0) {
    --                            ProcessMemInfo mi = new ProcessMemInfo(st.name, st.pid,
    --                                    ProcessList.NATIVE_ADJ, -1, "native", null);
    --                            mi.pss = pss;
    --                            mi.memtrack = memtrackTmp[0];
    --                            memInfos.add(mi);
    --                        }
    --                    }
    -+            stats = mProcessCpuTracker.getStats((st) -> {
    -+                return st.vsize > 0;
    -+            });
    -+        }
    -+        final int statsCount = stats.size();
    -+        for (int i = 0; i < statsCount; i++) {
    -+            ProcessCpuTracker.Stats st = stats.get(i);
    -+            long pss = Debug.getPss(st.pid, null, memtrackTmp);
    -+            if (pss > 0) {
    -+                if (infoMap.indexOfKey(st.pid) < 0) {
    -+                    ProcessMemInfo mi = new ProcessMemInfo(st.name, st.pid,
    -+                            ProcessList.NATIVE_ADJ, -1, "native", null);
    -+                    mi.pss = pss;
    -+                    mi.memtrack = memtrackTmp[0];
    -+                    memInfos.add(mi);
    -                 }
    -             }
    -         }
    -@@ -17788,6 +17798,7 @@ public final class ActivityManagerService extends ActivityManagerNative
    -                 || Intent.ACTION_MEDIA_BUTTON.equals(action)
    -                 || Intent.ACTION_MEDIA_SCANNER_SCAN_FILE.equals(action)
    -                 || Intent.ACTION_SHOW_KEYBOARD_SHORTCUTS.equals(action)
    -+                || Intent.ACTION_MASTER_CLEAR.equals(action)
    -                 || AppWidgetManager.ACTION_APPWIDGET_CONFIGURE.equals(action)
    -                 || AppWidgetManager.ACTION_APPWIDGET_UPDATE.equals(action)
    -                 || LocationManager.HIGH_POWER_REQUEST_CHANGE_ACTION.equals(action)
    -@@ -19029,7 +19040,7 @@ public final class ActivityManagerService extends ActivityManagerNative
    -                 if ((changes&ActivityInfo.CONFIG_LOCALE) != 0) {
    -                     intent = new Intent(Intent.ACTION_LOCALE_CHANGED);
    -                     intent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
    --                    if (!mProcessesReady) {
    -+	            if (initLocale || !mProcessesReady) {
    -                         intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
    -                     }
    -                     broadcastIntentLocked(null, null, intent,
    -@@ -19146,26 +19157,28 @@ public final class ActivityManagerService extends ActivityManagerNative
    -     // LIFETIME MANAGEMENT
    -     // =========================================================
    - 
    --    // Returns which broadcast queue the app is the current [or imminent] receiver
    --    // on, or 'null' if the app is not an active broadcast recipient.
    --    private BroadcastQueue isReceivingBroadcast(ProcessRecord app) {
    --        BroadcastRecord r = app.curReceiver;
    --        if (r != null) {
    --            return r.queue;
    -+    // Returns whether the app is receiving broadcast.
    -+    // If receiving, fetch all broadcast queues which the app is
    -+    // the current [or imminent] receiver on.
    -+    private boolean isReceivingBroadcastLocked(ProcessRecord app,
    -+            ArraySet<BroadcastQueue> receivingQueues) {
    -+        if (!app.curReceivers.isEmpty()) {
    -+            for (BroadcastRecord r : app.curReceivers) {
    -+                receivingQueues.add(r.queue);
    -+            }
    -+            return true;
    -         }
    - 
    -         // It's not the current receiver, but it might be starting up to become one
    --        synchronized (this) {
    --            for (BroadcastQueue queue : mBroadcastQueues) {
    --                r = queue.mPendingBroadcast;
    --                if (r != null && r.curApp == app) {
    --                    // found it; report which queue it's in
    --                    return queue;
    --                }
    -+        for (BroadcastQueue queue : mBroadcastQueues) {
    -+            final BroadcastRecord r = queue.mPendingBroadcast;
    -+            if (r != null && r.curApp == app) {
    -+                // found it; report which queue it's in
    -+                receivingQueues.add(queue);
    -             }
    -         }
    - 
    --        return null;
    -+        return !receivingQueues.isEmpty();
    -     }
    - 
    -     Association startAssociationLocked(int sourceUid, String sourceProcess, int sourceState,
    -@@ -19332,7 +19345,7 @@ public final class ActivityManagerService extends ActivityManagerNative
    -         int schedGroup;
    -         int procState;
    -         boolean foregroundActivities = false;
    --        BroadcastQueue queue;
    -+        final ArraySet<BroadcastQueue> queues = new ArraySet<BroadcastQueue>();
    -         if (app == TOP_APP) {
    -             // The last app on the list is the foreground app.
    -             adj = ProcessList.FOREGROUND_APP_ADJ;
    -@@ -19346,13 +19359,13 @@ public final class ActivityManagerService extends ActivityManagerNative
    -             schedGroup = ProcessList.SCHED_GROUP_DEFAULT;
    -             app.adjType = "instrumentation";
    -             procState = ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE;
    --        } else if ((queue = isReceivingBroadcast(app)) != null) {
    -+        } else if (isReceivingBroadcastLocked(app, queues)) {
    -             // An app that is currently receiving a broadcast also
    -             // counts as being in the foreground for OOM killer purposes.
    -             // It's placed in a sched group based on the nature of the
    -             // broadcast as reflected by which queue it's active in.
    -             adj = ProcessList.FOREGROUND_APP_ADJ;
    --            schedGroup = (queue == mFgBroadcastQueue)
    -+            schedGroup = (queues.contains(mFgBroadcastQueue))
    -                     ? ProcessList.SCHED_GROUP_DEFAULT : ProcessList.SCHED_GROUP_BACKGROUND;
    -             app.adjType = "broadcast";
    -             procState = ActivityManager.PROCESS_STATE_RECEIVER;
    -@@ -20363,7 +20376,7 @@ public final class ActivityManagerService extends ActivityManagerNative
    -             if (DEBUG_SWITCH || DEBUG_OOM_ADJ) Slog.v(TAG_OOM_ADJ,
    -                     "Setting sched group of " + app.processName
    -                     + " to " + app.curSchedGroup);
    --            if (app.waitingToKill != null && app.curReceiver == null
    -+            if (app.waitingToKill != null && app.curReceivers.isEmpty()
    -                     && app.setSchedGroup == ProcessList.SCHED_GROUP_BACKGROUND) {
    -                 app.kill(app.waitingToKill, true);
    -                 success = false;
    -@@ -20658,8 +20671,11 @@ public final class ActivityManagerService extends ActivityManagerNative
    -             final long now = SystemClock.elapsedRealtime();
    -             Long lastReported = userState.mProviderLastReportedFg.get(authority);
    -             if (lastReported == null || lastReported < now - 60 * 1000L) {
    --                mUsageStatsService.reportContentProviderUsage(
    --                        authority, providerPkgName, app.userId);
    -+                if (mSystemReady) {
    -+                    // Cannot touch the user stats if not system ready
    -+                    mUsageStatsService.reportContentProviderUsage(
    -+                            authority, providerPkgName, app.userId);
    -+                }
    -                 userState.mProviderLastReportedFg.put(authority, now);
    -             }
    -         }
    -@@ -20689,8 +20705,10 @@ public final class ActivityManagerService extends ActivityManagerNative
    -                 isInteraction = nowElapsed > app.fgInteractionTime + SERVICE_USAGE_INTERACTION_TIME;
    -             }
    -         } else {
    --            isInteraction = app.curProcState
    --                    <= ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND;
    -+            // If the app was being forced to the foreground, by say a Toast, then
    -+            // no need to treat it as an interaction
    -+            isInteraction = app.forcingToForeground == null
    -+                    && app.curProcState <= ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND;
    -             app.fgInteractionTime = 0;
    -         }
    -         if (isInteraction && (!app.reportedInteraction
    -@@ -21298,7 +21316,7 @@ public final class ActivityManagerService extends ActivityManagerNative
    -             for (i=mRemovedProcesses.size()-1; i>=0; i--) {
    -                 final ProcessRecord app = mRemovedProcesses.get(i);
    -                 if (app.activities.size() == 0
    --                        && app.curReceiver == null && app.services.size() == 0) {
    -+                        && app.curReceivers.isEmpty() && app.services.size() == 0) {
    -                     Slog.i(
    -                         TAG, "Exiting empty application process "
    -                         + app.toShortString() + " ("
    -@@ -22190,4 +22208,22 @@ public final class ActivityManagerService extends ActivityManagerNative
    -             Binder.restoreCallingIdentity(callingId);
    -         }
    -     }
    -+
    -+    @Override
    -+    public boolean canBypassWorkChallenge(PendingIntent intent) throws RemoteException {
    -+        final int userId = intent.getCreatorUserHandle().getIdentifier();
    -+        if (!mUserController.isUserRunningLocked(userId, ActivityManager.FLAG_AND_LOCKED)) {
    -+            return false;
    -+        }
    -+        IIntentSender target = intent.getTarget();
    -+        if (!(target instanceof PendingIntentRecord)) {
    -+            return false;
    -+        }
    -+        final PendingIntentRecord record = (PendingIntentRecord) target;
    -+        final ResolveInfo rInfo = mStackSupervisor.resolveIntent(record.key.requestIntent,
    -+                record.key.requestResolvedType, userId, PackageManager.MATCH_DIRECT_BOOT_AWARE);
    -+        // For direct boot aware activities, they can be shown without triggering a work challenge
    -+        // before the profile user is unlocked.
    -+        return rInfo != null && rInfo.activityInfo != null;
    -+    }
    - }
    -diff --git a/services/core/java/com/android/server/am/ActivityRecord.java b/services/core/java/com/android/server/am/ActivityRecord.java
    -index 489eb77..3f69712 100755
    ---- a/services/core/java/com/android/server/am/ActivityRecord.java
    -+++ b/services/core/java/com/android/server/am/ActivityRecord.java
    -@@ -17,6 +17,7 @@
    - package com.android.server.am;
    - 
    - import static android.app.ActivityManager.StackId;
    -+import static android.app.ActivityManager.StackId.DOCKED_STACK_ID;
    - import static android.app.ActivityManager.StackId.FREEFORM_WORKSPACE_STACK_ID;
    - import static android.app.ActivityManager.StackId.PINNED_STACK_ID;
    - import static android.content.pm.ActivityInfo.RESIZE_MODE_CROP_WINDOWS;
    -@@ -946,21 +947,25 @@ final class ActivityRecord {
    -         // The activity now gets access to the data associated with this Intent.
    -         service.grantUriPermissionFromIntentLocked(callingUid, packageName,
    -                 intent, getUriPermissionsLocked(), userId);
    --        // We want to immediately deliver the intent to the activity if
    --        // it is currently the top resumed activity...  however, if the
    --        // device is sleeping, then all activities are stopped, so in that
    --        // case we will deliver it if this is the current top activity on its
    --        // stack.
    -         final ReferrerIntent rintent = new ReferrerIntent(intent, referrer);
    -         boolean unsent = true;
    --        if ((state == ActivityState.RESUMED
    --                || (service.isSleepingLocked() && task.stack != null
    --                    && task.stack.topRunningActivityLocked() == this))
    --                && app != null && app.thread != null) {
    -+        final ActivityStack stack = task.stack;
    -+        final boolean isTopActivityInStack =
    -+                stack != null && stack.topRunningActivityLocked() == this;
    -+        final boolean isTopActivityWhileSleeping =
    -+                service.isSleepingLocked() && isTopActivityInStack;
    -+
    -+        // We want to immediately deliver the intent to the activity if:
    -+        // - It is currently resumed or paused. i.e. it is currently visible to the user and we want
    -+        //   the user to see the visual effects caused by the intent delivery now.
    -+        // - The device is sleeping and it is the top activity behind the lock screen (b/6700897).
    -+        if ((state == ActivityState.RESUMED || state == ActivityState.PAUSED
    -+                || isTopActivityWhileSleeping) && app != null && app.thread != null) {
    -             try {
    -                 ArrayList<ReferrerIntent> ar = new ArrayList<>(1);
    -                 ar.add(rintent);
    --                app.thread.scheduleNewIntent(ar, appToken);
    -+                app.thread.scheduleNewIntent(
    -+                        ar, appToken, state == ActivityState.PAUSED /* andPause */);
    -                 unsent = false;
    -             } catch (RemoteException e) {
    -                 Slog.w(TAG, "Exception thrown sending new intent to " + this, e);
    -@@ -1309,8 +1314,12 @@ final class ActivityRecord {
    -                 state == ActivityState.RESUMED;
    -     }
    - 
    --    public void setSleeping(boolean _sleeping) {
    --        if (sleeping == _sleeping) {
    -+    void setSleeping(boolean _sleeping) {
    -+        setSleeping(_sleeping, false);
    -+    }
    -+
    -+    void setSleeping(boolean _sleeping, boolean force) {
    -+        if (!force && sleeping == _sleeping) {
    -             return;
    -         }
    -         if (app != null && app.thread != null) {
    -diff --git a/services/core/java/com/android/server/am/ActivityStack.java b/services/core/java/com/android/server/am/ActivityStack.java
    -index 8c4c0ad..de858e39 100644
    ---- a/services/core/java/com/android/server/am/ActivityStack.java
    -+++ b/services/core/java/com/android/server/am/ActivityStack.java
    -@@ -29,6 +29,7 @@ import static android.content.pm.ActivityInfo.CONFIG_SMALLEST_SCREEN_SIZE;
    - import static android.content.pm.ActivityInfo.FLAG_RESUME_WHILE_PAUSING;
    - import static android.content.pm.ActivityInfo.FLAG_SHOW_FOR_ALL_USERS;
    - import static android.content.res.Configuration.SCREENLAYOUT_UNDEFINED;
    -+import static android.view.Display.DEFAULT_DISPLAY;
    - import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_ADD_REMOVE;
    - import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_ALL;
    - import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_APP;
    -@@ -68,6 +69,7 @@ import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_VISIBILIT
    - import static com.android.server.am.ActivityManagerDebugConfig.TAG_AM;
    - import static com.android.server.am.ActivityManagerDebugConfig.TAG_WITH_CLASS_NAME;
    - import static com.android.server.am.ActivityManagerService.LOCK_SCREEN_SHOWN;
    -+import static com.android.server.am.ActivityManagerService.TAKE_FULLSCREEN_SCREENSHOTS;
    - import static com.android.server.am.ActivityRecord.APPLICATION_ACTIVITY_TYPE;
    - import static com.android.server.am.ActivityRecord.HOME_ACTIVITY_TYPE;
    - import static com.android.server.am.ActivityRecord.STARTING_WINDOW_REMOVED;
    -@@ -669,7 +671,7 @@ final class ActivityStack {
    - 
    -     final boolean isOnHomeDisplay() {
    -         return isAttached() &&
    --                mActivityContainer.mActivityDisplay.mDisplayId == Display.DEFAULT_DISPLAY;
    -+                mActivityContainer.mActivityDisplay.mDisplayId == DEFAULT_DISPLAY;
    -     }
    - 
    -     void moveToFront(String reason) {
    -@@ -1041,22 +1043,32 @@ final class ActivityStack {
    - 
    -         int w = mService.mThumbnailWidth;
    -         int h = mService.mThumbnailHeight;
    -+
    -+        if (w <= 0) {
    -+            Slog.e(TAG, "\tInvalid thumbnail dimensions: " + w + "x" + h);
    -+            return null;
    -+        }
    -+
    -+        if (mStackId == DOCKED_STACK_ID && mStackSupervisor.mIsDockMinimized) {
    -+            // When the docked stack is minimized its app windows are cropped significantly so any
    -+            // screenshot taken will not display the apps contain. So, we avoid taking a screenshot
    -+            // in that case.
    -+            if (DEBUG_SCREENSHOTS) Slog.e(TAG, "\tIn minimized docked stack");
    -+            return null;
    -+        }
    -+
    -         float scale = 1f;
    --        if (w > 0) {
    --            if (DEBUG_SCREENSHOTS) Slog.d(TAG_SCREENSHOTS, "\tTaking screenshot");
    -+        if (DEBUG_SCREENSHOTS) Slog.d(TAG_SCREENSHOTS, "\tTaking screenshot");
    - 
    --            // When this flag is set, we currently take the fullscreen screenshot of the activity
    --            // but scaled to half the size.  This gives us a "good-enough" fullscreen thumbnail to
    --            // use within SystemUI while keeping memory usage low.
    --            if (ActivityManagerService.TAKE_FULLSCREEN_SCREENSHOTS) {
    --                w = h = -1;
    --                scale = mService.mFullscreenThumbnailScale;
    --            }
    --            return mWindowManager.screenshotApplications(who.appToken, Display.DEFAULT_DISPLAY,
    --                    w, h, scale);
    -+        // When this flag is set, we currently take the fullscreen screenshot of the activity but
    -+        // scaled to half the size. This gives us a "good-enough" fullscreen thumbnail to use within
    -+        // SystemUI while keeping memory usage low.
    -+        if (TAKE_FULLSCREEN_SCREENSHOTS) {
    -+            w = h = -1;
    -+            scale = mService.mFullscreenThumbnailScale;
    -         }
    --        Slog.e(TAG, "Invalid thumbnail dimensions: " + w + "x" + h);
    --        return null;
    -+
    -+        return mWindowManager.screenshotApplications(who.appToken, DEFAULT_DISPLAY, w, h, scale);
    -     }
    - 
    -     /**
    -@@ -1308,7 +1320,9 @@ final class ActivityStack {
    -             // It is possible the activity was freezing the screen before it was paused.
    -             // In that case go ahead and remove the freeze this activity has on the screen
    -             // since it is no longer visible.
    --            prev.stopFreezingScreenLocked(true /*force*/);
    -+            if (prev != null) {
    -+                prev.stopFreezingScreenLocked(true /*force*/);
    -+            }
    -             mPausingActivity = null;
    -         }
    - 
    -@@ -1591,11 +1605,6 @@ final class ActivityStack {
    -             return STACK_INVISIBLE;
    -         }
    - 
    --        final boolean isLockscreenShown = mService.mLockScreenShown == LOCK_SCREEN_SHOWN;
    --        if (isLockscreenShown && !StackId.isAllowedOverLockscreen(mStackId)) {
    --            return STACK_INVISIBLE;
    --        }
    --
    -         final ActivityStack focusedStack = mStackSupervisor.getFocusedStack();
    -         final int focusedStackId = focusedStack.mStackId;
    - 
    -@@ -2498,7 +2507,8 @@ final class ActivityStack {
    -                             break;
    -                         }
    -                     }
    --                    next.app.thread.scheduleNewIntent(next.newIntents, next.appToken);
    -+                    next.app.thread.scheduleNewIntent(
    -+                            next.newIntents, next.appToken, false /* andPause */);
    -                 }
    - 
    -                 // Well the app will no longer be stopped.
    -@@ -4396,7 +4406,7 @@ final class ActivityStack {
    -                     mStackSupervisor.getStack(FULLSCREEN_WORKSPACE_STACK_ID);
    -             if (fullscreenStack != null && fullscreenStack.hasVisibleBehindActivity()) {
    -                 final ActivityRecord visibleBehind = fullscreenStack.getVisibleBehindActivity();
    --                mService.setFocusedActivityLocked(visibleBehind, "moveTaskToBack");
    -+                mService.setFocusedActivityLocked(visibleBehind, "moveHomeTaskToBack");
    -                 mStackSupervisor.resumeFocusedStackTopActivityLocked();
    -                 return true;
    -             }
    -@@ -4449,9 +4459,13 @@ final class ActivityStack {
    -             }
    -             final int taskToReturnTo = tr.getTaskToReturnTo();
    -             tr.setTaskToReturnTo(APPLICATION_ACTIVITY_TYPE);
    --            return mStackSupervisor.resumeHomeStackTask(taskToReturnTo, null, "moveTaskToBack");
    -+            return mStackSupervisor.resumeHomeStackTask(taskToReturnTo, null,
    -+                    "moveTaskToBackAndShowHome");
    -         }
    - 
    -+        // Using currently focused activity value from service instead of mResumedActivity,
    -+        // because if this happens when device is locked the mResumedActivity will be null.
    -+        adjustFocusedActivityLocked(mService.mFocusedActivity, "moveTaskToBack");
    -         mStackSupervisor.resumeFocusedStackTopActivityLocked();
    -         return true;
    -     }
    -@@ -4517,15 +4531,6 @@ final class ActivityStack {
    -             return true;
    -         }
    - 
    --        // TODO: We could probably make the condition below just check that the activity state is
    --        // stopped, but also checking the sleep state for now to reduce change impact late in
    --        // development cycle.
    --        if (mService.isSleepingOrShuttingDownLocked() && r.state == ActivityState.STOPPED) {
    --            if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Slog.v(TAG_CONFIGURATION,
    --                    "Skipping config check (stopped while sleeping): " + r);
    --            return true;
    --        }
    --
    -         if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Slog.v(TAG_CONFIGURATION,
    -                 "Ensuring correct configuration: " + r);
    - 
    -diff --git a/services/core/java/com/android/server/am/ActivityStackSupervisor.java b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
    -index a0087c8..c6ab918 100644
    ---- a/services/core/java/com/android/server/am/ActivityStackSupervisor.java
    -+++ b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
    -@@ -3139,11 +3139,14 @@ public final class ActivityStackSupervisor implements DisplayListener {
    -         final boolean nowVisible = allResumedActivitiesVisible();
    -         for (int activityNdx = mStoppingActivities.size() - 1; activityNdx >= 0; --activityNdx) {
    -             ActivityRecord s = mStoppingActivities.get(activityNdx);
    -+            // TODO: Remove mWaitingVisibleActivities list and just remove activity from
    -+            // mStoppingActivities when something else comes up.
    -             boolean waitingVisible = mWaitingVisibleActivities.contains(s);
    -             if (DEBUG_STATES) Slog.v(TAG, "Stopping " + s + ": nowVisible=" + nowVisible
    -                     + " waitingVisible=" + waitingVisible + " finishing=" + s.finishing);
    -             if (waitingVisible && nowVisible) {
    -                 mWaitingVisibleActivities.remove(s);
    -+                waitingVisible = false;
    -                 if (s.finishing) {
    -                     // If this activity is finishing, it is sitting on top of
    -                     // everyone else but we now know it is no longer needed...
    -@@ -3152,7 +3155,6 @@ public final class ActivityStackSupervisor implements DisplayListener {
    -                     // hidden by the activities in front of it.
    -                     if (DEBUG_STATES) Slog.v(TAG, "Before stopping, can hide: " + s);
    -                     mWindowManager.setAppVisibility(s.appToken, false);
    --                    waitingVisible = false;
    -                 }
    -             }
    -             if ((!waitingVisible || mService.isSleepingOrShuttingDownLocked()) && remove) {
    -@@ -3765,6 +3767,12 @@ public final class ActivityStackSupervisor implements DisplayListener {
    - 
    -     void activityRelaunchedLocked(IBinder token) {
    -         mWindowManager.notifyAppRelaunchingFinished(token);
    -+        if (mService.isSleepingOrShuttingDownLocked()) {
    -+            final ActivityRecord r = ActivityRecord.isInStackLocked(token);
    -+            if (r != null) {
    -+                r.setSleeping(true, true);
    -+            }
    -+        }
    -     }
    - 
    -     void activityRelaunchingLocked(ActivityRecord r) {
    -diff --git a/services/core/java/com/android/server/am/ActivityStartInterceptor.java b/services/core/java/com/android/server/am/ActivityStartInterceptor.java
    -index f26e47e..d719c58 100644
    ---- a/services/core/java/com/android/server/am/ActivityStartInterceptor.java
    -+++ b/services/core/java/com/android/server/am/ActivityStartInterceptor.java
    -@@ -29,6 +29,7 @@ import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK;
    - import static android.content.Intent.FLAG_ACTIVITY_TASK_ON_HOME;
    - import static android.content.pm.ApplicationInfo.FLAG_SUSPENDED;
    - 
    -+import android.app.ActivityManager;
    - import android.app.ActivityOptions;
    - import android.app.KeyguardManager;
    - import android.app.admin.DevicePolicyManagerInternal;
    -@@ -210,6 +211,11 @@ class ActivityStartInterceptor {
    -         if (!mService.mUserController.shouldConfirmCredentials(userId)) {
    -             return null;
    -         }
    -+        // Allow direct boot aware activity to be displayed before the user is unlocked.
    -+        if (aInfo.directBootAware && mService.mUserController.isUserRunningLocked(userId,
    -+                ActivityManager.FLAG_AND_LOCKED)) {
    -+            return null;
    -+        }
    -         final IIntentSender target = mService.getIntentSenderLocked(
    -                 INTENT_SENDER_ACTIVITY, callingPackage,
    -                 Binder.getCallingUid(), userId, null, null, 0, new Intent[]{ intent },
    -diff --git a/services/core/java/com/android/server/am/ActivityStarter.java b/services/core/java/com/android/server/am/ActivityStarter.java
    -index bbf09e8..06d8e48 100644
    ---- a/services/core/java/com/android/server/am/ActivityStarter.java
    -+++ b/services/core/java/com/android/server/am/ActivityStarter.java
    -@@ -103,6 +103,7 @@ import android.os.Build;
    - import android.os.Bundle;
    - import android.os.IBinder;
    - import android.os.PowerManagerInternal;
    -+import android.os.Process;
    - import android.os.RemoteException;
    - import android.os.SystemClock;
    - import android.os.UserHandle;
    -@@ -132,6 +133,9 @@ class ActivityStarter {
    -     private static final String TAG_CONFIGURATION = TAG + POSTFIX_CONFIGURATION;
    -     private static final String TAG_USER_LEAVING = TAG + POSTFIX_USER_LEAVING;
    - 
    -+    // TODO b/30204367 remove when the platform fully supports ephemeral applications
    -+    private static final boolean USE_DEFAULT_EPHEMERAL_LAUNCHER = false;
    -+
    -     private final ActivityManagerService mService;
    -     private final ActivityStackSupervisor mSupervisor;
    -     private ActivityStartInterceptor mInterceptor;
    -@@ -456,39 +460,13 @@ class ActivityStarter {
    -         // starts either the intent we resolved here [on install error] or the ephemeral
    -         // app [on install success].
    -         if (rInfo != null && rInfo.ephemeralResolveInfo != null) {
    --            // Create a pending intent to start the intent resolved here.
    --            final IIntentSender failureTarget = mService.getIntentSenderLocked(
    --                    ActivityManager.INTENT_SENDER_ACTIVITY, callingPackage,
    --                    Binder.getCallingUid(), userId, null, null, 0, new Intent[]{ intent },
    --                    new String[]{ resolvedType },
    --                    PendingIntent.FLAG_CANCEL_CURRENT | PendingIntent.FLAG_ONE_SHOT
    --                            | PendingIntent.FLAG_IMMUTABLE, null);
    --
    --            // Create a pending intent to start the ephemeral application; force it to be
    --            // directed to the ephemeral package.
    --            ephemeralIntent.setPackage(rInfo.ephemeralResolveInfo.getPackageName());
    --            final IIntentSender ephemeralTarget = mService.getIntentSenderLocked(
    --                    ActivityManager.INTENT_SENDER_ACTIVITY, callingPackage,
    --                    Binder.getCallingUid(), userId, null, null, 0, new Intent[]{ ephemeralIntent },
    --                    new String[]{ resolvedType },
    --                    PendingIntent.FLAG_CANCEL_CURRENT | PendingIntent.FLAG_ONE_SHOT
    --                            | PendingIntent.FLAG_IMMUTABLE, null);
    --
    --            int flags = intent.getFlags();
    --            intent = new Intent();
    --            intent.setFlags(flags
    --                    | Intent.FLAG_ACTIVITY_NEW_TASK
    --                    | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
    --            intent.putExtra(Intent.EXTRA_PACKAGE_NAME,
    --                    rInfo.ephemeralResolveInfo.getPackageName());
    --            intent.putExtra(Intent.EXTRA_EPHEMERAL_FAILURE, new IntentSender(failureTarget));
    --            intent.putExtra(Intent.EXTRA_EPHEMERAL_SUCCESS, new IntentSender(ephemeralTarget));
    --
    -+            intent = buildEphemeralInstallerIntent(intent, ephemeralIntent,
    -+                    rInfo.ephemeralResolveInfo.getPackageName(), callingPackage, resolvedType,
    -+                    userId);
    -             resolvedType = null;
    -             callingUid = realCallingUid;
    -             callingPid = realCallingPid;
    - 
    --            rInfo = rInfo.ephemeralInstaller;
    -             aInfo = mSupervisor.resolveActivity(intent, rInfo, startFlags, null /*profilerInfo*/);
    -         }
    - 
    -@@ -543,6 +521,58 @@ class ActivityStarter {
    -         return err;
    -     }
    - 
    -+    /**
    -+     * Builds and returns an intent to launch the ephemeral installer.
    -+     */
    -+    private Intent buildEphemeralInstallerIntent(Intent launchIntent, Intent origIntent,
    -+            String ephemeralPackage, String callingPackage, String resolvedType, int userId) {
    -+        final Intent nonEphemeralIntent = new Intent(origIntent);
    -+        nonEphemeralIntent.setFlags(nonEphemeralIntent.getFlags() | Intent.FLAG_IGNORE_EPHEMERAL);
    -+        // Intent that is launched if the ephemeral package couldn't be installed
    -+        // for any reason.
    -+        final IIntentSender failureIntentTarget = mService.getIntentSenderLocked(
    -+                ActivityManager.INTENT_SENDER_ACTIVITY, callingPackage,
    -+                Binder.getCallingUid(), userId, null /*token*/, null /*resultWho*/, 1,
    -+                new Intent[]{ nonEphemeralIntent }, new String[]{ resolvedType },
    -+                PendingIntent.FLAG_CANCEL_CURRENT | PendingIntent.FLAG_ONE_SHOT
    -+                | PendingIntent.FLAG_IMMUTABLE, null /*bOptions*/);
    -+
    -+        final Intent ephemeralIntent;
    -+        if (USE_DEFAULT_EPHEMERAL_LAUNCHER) {
    -+            // Force the intent to be directed to the ephemeral package
    -+            ephemeralIntent = new Intent(origIntent);
    -+            ephemeralIntent.setPackage(ephemeralPackage);
    -+        } else {
    -+            // Success intent goes back to the installer
    -+            ephemeralIntent = new Intent(launchIntent);
    -+        }
    -+
    -+        // Intent that is eventually launched if the ephemeral package was
    -+        // installed successfully. This will actually be launched by a platform
    -+        // broadcast receiver.
    -+        final IIntentSender successIntentTarget = mService.getIntentSenderLocked(
    -+                ActivityManager.INTENT_SENDER_ACTIVITY, callingPackage,
    -+                Binder.getCallingUid(), userId, null /*token*/, null /*resultWho*/, 0,
    -+                new Intent[]{ ephemeralIntent }, new String[]{ resolvedType },
    -+                PendingIntent.FLAG_CANCEL_CURRENT | PendingIntent.FLAG_ONE_SHOT
    -+                | PendingIntent.FLAG_IMMUTABLE, null /*bOptions*/);
    -+
    -+        // Finally build the actual intent to launch the ephemeral installer
    -+        int flags = launchIntent.getFlags();
    -+        final Intent intent = new Intent();
    -+        intent.setFlags(flags
    -+                | Intent.FLAG_ACTIVITY_NEW_TASK
    -+                | Intent.FLAG_ACTIVITY_CLEAR_TASK
    -+                | Intent.FLAG_ACTIVITY_NO_HISTORY
    -+                | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
    -+        intent.putExtra(Intent.EXTRA_PACKAGE_NAME, ephemeralPackage);
    -+        intent.putExtra(Intent.EXTRA_EPHEMERAL_FAILURE, new IntentSender(failureIntentTarget));
    -+        intent.putExtra(Intent.EXTRA_EPHEMERAL_SUCCESS, new IntentSender(successIntentTarget));
    -+        // TODO: Remove when the platform has fully implemented ephemeral apps
    -+        intent.setData(origIntent.getData().buildUpon().clearQuery().build());
    -+        return intent;
    -+    }
    -+
    -     void postStartActivityUncheckedProcessing(
    -             ActivityRecord r, int result, int prevFocusedStackId, ActivityRecord sourceRecord,
    -             ActivityStack targetStack) {
    -@@ -572,6 +602,9 @@ class ActivityStarter {
    -         // If we launched the activity from a no display activity that was launched from the home
    -         // screen, we also need to start recents to un-minimize the docked stack, since the
    -         // noDisplay activity will be finished shortly after.
    -+        // Note that some apps have trampoline activities without noDisplay being set. In that case,
    -+        // we have another heuristic in DockedStackDividerController.notifyAppTransitionStarting
    -+        // that tries to detect that case.
    -         // TODO: We should prevent noDisplay activities from affecting task/stack ordering and
    -         // visibility instead of using this flag.
    -         final boolean noDisplayActivityOverHome = sourceRecord != null
    -diff --git a/services/core/java/com/android/server/am/AppErrors.java b/services/core/java/com/android/server/am/AppErrors.java
    -index 7eff773..0c67c75 100644
    ---- a/services/core/java/com/android/server/am/AppErrors.java
    -+++ b/services/core/java/com/android/server/am/AppErrors.java
    -@@ -22,7 +22,6 @@ import com.android.internal.logging.MetricsProto;
    - import com.android.internal.os.ProcessCpuTracker;
    - import com.android.server.Watchdog;
    - 
    --import android.app.Activity;
    - import android.app.ActivityManager;
    - import android.app.ActivityOptions;
    - import android.app.ActivityThread;
    -@@ -33,10 +32,7 @@ import android.content.ActivityNotFoundException;
    - import android.content.Context;
    - import android.content.Intent;
    - import android.content.pm.ApplicationInfo;
    --import android.content.pm.IPackageDataObserver;
    --import android.content.pm.PackageManager;
    - import android.os.Binder;
    --import android.os.Bundle;
    - import android.os.Message;
    - import android.os.Process;
    - import android.os.RemoteException;
    -@@ -59,7 +55,6 @@ import java.util.ArrayList;
    - import java.util.Collections;
    - import java.util.HashMap;
    - import java.util.Set;
    --import java.util.concurrent.Semaphore;
    - 
    - import static com.android.server.Watchdog.NATIVE_STACKS_OF_INTEREST;
    - import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_ANR;
    -@@ -359,7 +354,7 @@ class AppErrors {
    -                 return;
    -             }
    - 
    --            Message msg = Message.obtain();
    -+            final Message msg = Message.obtain();
    -             msg.what = ActivityManagerService.SHOW_ERROR_UI_MSG;
    - 
    -             task = data.task;
    -@@ -575,6 +570,8 @@ class AppErrors {
    -     boolean handleAppCrashLocked(ProcessRecord app, String reason,
    -             String shortMsg, String longMsg, String stackTrace, AppErrorDialog.Data data) {
    -         long now = SystemClock.uptimeMillis();
    -+        boolean showBackground = Settings.Secure.getInt(mContext.getContentResolver(),
    -+                Settings.Secure.ANR_SHOW_BACKGROUND, 0) != 0;
    - 
    -         Long crashTime;
    -         Long crashTimePersistent;
    -@@ -612,7 +609,9 @@ class AppErrors {
    -                 // processes run critical code.
    -                 mService.removeProcessLocked(app, false, false, "crash");
    -                 mService.mStackSupervisor.resumeFocusedStackTopActivityLocked();
    --                return false;
    -+                if (!showBackground) {
    -+                    return false;
    -+                }
    -             }
    -             mService.mStackSupervisor.resumeFocusedStackTopActivityLocked();
    -         } else {
    -@@ -705,7 +704,7 @@ class AppErrors {
    -             }
    -             final boolean crashSilenced = mAppsNotReportingCrashes != null &&
    -                     mAppsNotReportingCrashes.contains(proc.info.packageName);
    --            if (mService.canShowErrorDialogs() && !crashSilenced) {
    -+            if ((mService.canShowErrorDialogs() || showBackground) && !crashSilenced) {
    -                 proc.crashDialog = new AppErrorDialog(mContext, mService, data);
    -             } else {
    -                 // The device is asleep, so just pretend that the user
    -@@ -942,7 +941,9 @@ class AppErrors {
    -                     null, null, 0, null, null, null, AppOpsManager.OP_NONE,
    -                     null, false, false, MY_PID, Process.SYSTEM_UID, 0 /* TODO: Verify */);
    - 
    --            if (mService.canShowErrorDialogs()) {
    -+            boolean showBackground = Settings.Secure.getInt(mContext.getContentResolver(),
    -+                    Settings.Secure.ANR_SHOW_BACKGROUND, 0) != 0;
    -+            if (mService.canShowErrorDialogs() || showBackground) {
    -                 d = new AppNotRespondingDialog(mService,
    -                         mContext, proc, (ActivityRecord)data.get("activity"),
    -                         msg.arg1 != 0);
    -diff --git a/services/core/java/com/android/server/am/BroadcastQueue.java b/services/core/java/com/android/server/am/BroadcastQueue.java
    -index f78f29c..5c35419 100644
    ---- a/services/core/java/com/android/server/am/BroadcastQueue.java
    -+++ b/services/core/java/com/android/server/am/BroadcastQueue.java
    -@@ -227,7 +227,8 @@ public final class BroadcastQueue {
    - 
    -     public final boolean replaceParallelBroadcastLocked(BroadcastRecord r) {
    -         for (int i = mParallelBroadcasts.size() - 1; i >= 0; i--) {
    --            if (r.intent.filterEquals(mParallelBroadcasts.get(i).intent)) {
    -+            final Intent curIntent = mParallelBroadcasts.get(i).intent;
    -+            if (r.intent.filterEquals(curIntent)) {
    -                 if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST,
    -                         "***** DROPPING PARALLEL ["
    -                 + mQueueName + "]: " + r.intent);
    -@@ -265,7 +266,7 @@ public final class BroadcastQueue {
    - 
    -         r.receiver = app.thread.asBinder();
    -         r.curApp = app;
    --        app.curReceiver = r;
    -+        app.curReceivers.add(r);
    -         app.forceProcessStateUpTo(ActivityManager.PROCESS_STATE_RECEIVER);
    -         mService.updateLruProcessLocked(app, false, null);
    -         mService.updateOomAdjLocked();
    -@@ -293,7 +294,7 @@ public final class BroadcastQueue {
    -                         "Process cur broadcast " + r + ": NOT STARTED!");
    -                 r.receiver = null;
    -                 r.curApp = null;
    --                app.curReceiver = null;
    -+                app.curReceivers.remove(r);
    -             }
    -         }
    -     }
    -@@ -394,8 +395,8 @@ public final class BroadcastQueue {
    -         }
    -         r.receiver = null;
    -         r.intent.setComponent(null);
    --        if (r.curApp != null && r.curApp.curReceiver == r) {
    --            r.curApp.curReceiver = null;
    -+        if (r.curApp != null && r.curApp.curReceivers.contains(r)) {
    -+            r.curApp.curReceivers.remove(r);
    -         }
    -         if (r.curFilter != null) {
    -             r.curFilter.receiverList.curBroadcast = null;
    -@@ -648,7 +649,7 @@ public final class BroadcastQueue {
    -                 // things that directly call the IActivityManager API, which
    -                 // are already core system stuff so don't matter for this.
    -                 r.curApp = filter.receiverList.app;
    --                filter.receiverList.app.curReceiver = r;
    -+                filter.receiverList.app.curReceivers.add(r);
    -                 mService.updateOomAdjLocked(r.curApp);
    -             }
    -         }
    -@@ -676,7 +677,7 @@ public final class BroadcastQueue {
    -                 r.curFilter = null;
    -                 filter.receiverList.curBroadcast = null;
    -                 if (filter.receiverList.app != null) {
    --                    filter.receiverList.app.curReceiver = null;
    -+                    filter.receiverList.app.curReceivers.remove(r);
    -                 }
    -             }
    -         }
    -diff --git a/services/core/java/com/android/server/am/BroadcastRecord.java b/services/core/java/com/android/server/am/BroadcastRecord.java
    -index 3437ae6..1e7911a 100644
    ---- a/services/core/java/com/android/server/am/BroadcastRecord.java
    -+++ b/services/core/java/com/android/server/am/BroadcastRecord.java
    -@@ -219,6 +219,9 @@ final class BroadcastRecord extends Binder {
    -             int _resultCode, String _resultData, Bundle _resultExtras, boolean _serialized,
    -             boolean _sticky, boolean _initialSticky,
    -             int _userId) {
    -+        if (_intent == null) {
    -+            throw new NullPointerException("Can't construct with a null intent");
    -+        }
    -         queue = _queue;
    -         intent = _intent;
    -         targetComp = _intent.getComponent();
    -diff --git a/services/core/java/com/android/server/am/PendingIntentRecord.java b/services/core/java/com/android/server/am/PendingIntentRecord.java
    -index 2467a90..9c08453 100644
    ---- a/services/core/java/com/android/server/am/PendingIntentRecord.java
    -+++ b/services/core/java/com/android/server/am/PendingIntentRecord.java
    -@@ -38,6 +38,7 @@ import com.android.server.am.ActivityStackSupervisor.ActivityContainer;
    - 
    - import java.io.PrintWriter;
    - import java.lang.ref.WeakReference;
    -+import java.util.Objects;
    - 
    - final class PendingIntentRecord extends IIntentSender.Stub {
    -     private static final String TAG = TAG_WITH_CLASS_NAME ? "PendingIntentRecord" : TAG_AM;
    -@@ -102,7 +103,7 @@ final class PendingIntentRecord extends IIntentSender.Stub {
    -             if (requestResolvedType != null) {
    -                 hash = (ODD_PRIME_NUMBER*hash) + requestResolvedType.hashCode();
    -             }
    --            hash = (ODD_PRIME_NUMBER*hash) + _p.hashCode();
    -+            hash = (ODD_PRIME_NUMBER*hash) + (_p != null ? _p.hashCode() : 0);
    -             hash = (ODD_PRIME_NUMBER*hash) + _t;
    -             hashCode = hash;
    -             //Slog.i(ActivityManagerService.TAG, this + " hashCode=0x"
    -@@ -121,20 +122,14 @@ final class PendingIntentRecord extends IIntentSender.Stub {
    -                 if (userId != other.userId){
    -                     return false;
    -                 }
    --                if (!packageName.equals(other.packageName)) {
    -+                if (!Objects.equals(packageName, other.packageName)) {
    -                     return false;
    -                 }
    -                 if (activity != other.activity) {
    -                     return false;
    -                 }
    --                if (who != other.who) {
    --                    if (who != null) {
    --                        if (!who.equals(other.who)) {
    --                            return false;
    --                        }
    --                    } else if (other.who != null) {
    --                        return false;
    --                    }
    -+                if (!Objects.equals(who, other.who)) {
    -+                    return false;
    -                 }
    -                 if (requestCode != other.requestCode) {
    -                     return false;
    -@@ -148,14 +143,8 @@ final class PendingIntentRecord extends IIntentSender.Stub {
    -                         return false;
    -                     }
    -                 }
    --                if (requestResolvedType != other.requestResolvedType) {
    --                    if (requestResolvedType != null) {
    --                        if (!requestResolvedType.equals(other.requestResolvedType)) {
    --                            return false;
    --                        }
    --                    } else if (other.requestResolvedType != null) {
    --                        return false;
    --                    }
    -+                if (!Objects.equals(requestResolvedType, other.requestResolvedType)) {
    -+                    return false;
    -                 }
    -                 if (flags != other.flags) {
    -                     return false;
    -diff --git a/services/core/java/com/android/server/am/ProcessRecord.java b/services/core/java/com/android/server/am/ProcessRecord.java
    -index 3fffefb..49fe79c 100644
    ---- a/services/core/java/com/android/server/am/ProcessRecord.java
    -+++ b/services/core/java/com/android/server/am/ProcessRecord.java
    -@@ -143,7 +143,7 @@ final class ProcessRecord {
    -     Bundle instrumentationArguments;// as given to us
    -     ComponentName instrumentationResultClass;// copy of instrumentationClass
    -     boolean usingWrapper;       // Set to true when process was launched with a wrapper attached
    --    BroadcastRecord curReceiver;// receiver currently running in the app
    -+    final ArraySet<BroadcastRecord> curReceivers = new ArraySet<BroadcastRecord>();// receivers currently running in the app
    -     long lastWakeTime;          // How long proc held wake lock at last check
    -     long lastCpuTime;           // How long proc has run CPU at last check
    -     long curCpuTime;            // How long proc has run CPU most recently
    -@@ -427,8 +427,11 @@ final class ProcessRecord {
    -                 pw.print(prefix); pw.print("  - "); pw.println(conProviders.get(i).toShortString());
    -             }
    -         }
    --        if (curReceiver != null) {
    --            pw.print(prefix); pw.print("curReceiver="); pw.println(curReceiver);
    -+        if (!curReceivers.isEmpty()) {
    -+            pw.print(prefix); pw.println("Current Receivers:");
    -+            for (int i=0; i < curReceivers.size(); i++) {
    -+                pw.print(prefix); pw.print("  - "); pw.println(curReceivers.valueAt(i));
    -+            }
    -         }
    -         if (receivers.size() > 0) {
    -             pw.print(prefix); pw.println("Receivers:");
    -diff --git a/services/core/java/com/android/server/am/TaskPersister.java b/services/core/java/com/android/server/am/TaskPersister.java
    -index 48fecd5..43eb251 100644
    ---- a/services/core/java/com/android/server/am/TaskPersister.java
    -+++ b/services/core/java/com/android/server/am/TaskPersister.java
    -@@ -87,6 +87,8 @@ public class TaskPersister {
    -     private final RecentTasks mRecentTasks;
    -     private final SparseArray<SparseBooleanArray> mTaskIdsInFile = new SparseArray<>();
    -     private final File mTaskIdsDir;
    -+    // To lock file operations in TaskPersister
    -+    private final Object mIoLock = new Object();
    - 
    -     /**
    -      * Value determines write delay mode as follows: < 0 We are Flushing. No delays between writes
    -@@ -195,52 +197,52 @@ public class TaskPersister {
    -             return mTaskIdsInFile.get(userId).clone();
    -         }
    -         final SparseBooleanArray persistedTaskIds = new SparseBooleanArray();
    --        BufferedReader reader = null;
    --        String line;
    --        try {
    --            reader = new BufferedReader(new FileReader(getUserPersistedTaskIdsFile(userId)));
    --            while ((line = reader.readLine()) != null) {
    --                for (String taskIdString : line.split("\\s+")) {
    --                    int id = Integer.parseInt(taskIdString);
    --                    persistedTaskIds.put(id, true);
    -+        synchronized (mIoLock) {
    -+            BufferedReader reader = null;
    -+            String line;
    -+            try {
    -+                reader = new BufferedReader(new FileReader(getUserPersistedTaskIdsFile(userId)));
    -+                while ((line = reader.readLine()) != null) {
    -+                    for (String taskIdString : line.split("\\s+")) {
    -+                        int id = Integer.parseInt(taskIdString);
    -+                        persistedTaskIds.put(id, true);
    -+                    }
    -                 }
    -+            } catch (FileNotFoundException e) {
    -+                // File doesn't exist. Ignore.
    -+            } catch (Exception e) {
    -+                Slog.e(TAG, "Error while reading taskIds file for user " + userId, e);
    -+            } finally {
    -+                IoUtils.closeQuietly(reader);
    -             }
    --        } catch (FileNotFoundException e) {
    --            // File doesn't exist. Ignore.
    --        } catch (Exception e) {
    --            Slog.e(TAG, "Error while reading taskIds file for user " + userId, e);
    --        } finally {
    --            IoUtils.closeQuietly(reader);
    -         }
    -         mTaskIdsInFile.put(userId, persistedTaskIds);
    -         return persistedTaskIds.clone();
    -     }
    - 
    -+
    -     @VisibleForTesting
    --    void maybeWritePersistedTaskIdsForUser(@NonNull SparseBooleanArray taskIds, int userId) {
    -+    void writePersistedTaskIdsForUser(@NonNull SparseBooleanArray taskIds, int userId) {
    -         if (userId < 0) {
    -             return;
    -         }
    --        SparseBooleanArray persistedIdsInFile = mTaskIdsInFile.get(userId);
    --        if (persistedIdsInFile != null && persistedIdsInFile.equals(taskIds)) {
    --            return;
    --        }
    -         final File persistedTaskIdsFile = getUserPersistedTaskIdsFile(userId);
    --        BufferedWriter writer = null;
    --        try {
    --            writer = new BufferedWriter(new FileWriter(persistedTaskIdsFile));
    --            for (int i = 0; i < taskIds.size(); i++) {
    --                if (taskIds.valueAt(i)) {
    --                    writer.write(String.valueOf(taskIds.keyAt(i)));
    --                    writer.newLine();
    -+        synchronized (mIoLock) {
    -+            BufferedWriter writer = null;
    -+            try {
    -+                writer = new BufferedWriter(new FileWriter(persistedTaskIdsFile));
    -+                for (int i = 0; i < taskIds.size(); i++) {
    -+                    if (taskIds.valueAt(i)) {
    -+                        writer.write(String.valueOf(taskIds.keyAt(i)));
    -+                        writer.newLine();
    -+                    }
    -                 }
    -+            } catch (Exception e) {
    -+                Slog.e(TAG, "Error while writing taskIds file for user " + userId, e);
    -+            } finally {
    -+                IoUtils.closeQuietly(writer);
    -             }
    --        } catch (Exception e) {
    --            Slog.e(TAG, "Error while writing taskIds file for user " + userId, e);
    --        } finally {
    --            IoUtils.closeQuietly(writer);
    -         }
    --        mTaskIdsInFile.put(userId, taskIds.clone());
    -     }
    - 
    -     void unloadUserDataFromMemory(int userId) {
    -@@ -543,16 +545,23 @@ public class TaskPersister {
    -     }
    - 
    -     private void writeTaskIdsFiles() {
    --        int candidateUserIds[];
    -+        SparseArray<SparseBooleanArray> changedTaskIdsPerUser = new SparseArray<>();
    -         synchronized (mService) {
    --            candidateUserIds = mRecentTasks.usersWithRecentsLoadedLocked();
    --        }
    --        SparseBooleanArray taskIdsToSave;
    --        for (int userId : candidateUserIds) {
    --            synchronized (mService) {
    --                taskIdsToSave = mRecentTasks.mPersistedTaskIds.get(userId).clone();
    -+            for (int userId : mRecentTasks.usersWithRecentsLoadedLocked()) {
    -+                SparseBooleanArray taskIdsToSave = mRecentTasks.mPersistedTaskIds.get(userId);
    -+                SparseBooleanArray persistedIdsInFile = mTaskIdsInFile.get(userId);
    -+                if (persistedIdsInFile != null && persistedIdsInFile.equals(taskIdsToSave)) {
    -+                    continue;
    -+                } else {
    -+                    SparseBooleanArray taskIdsToSaveCopy = taskIdsToSave.clone();
    -+                    mTaskIdsInFile.put(userId, taskIdsToSaveCopy);
    -+                    changedTaskIdsPerUser.put(userId, taskIdsToSaveCopy);
    -+                }
    -             }
    --            maybeWritePersistedTaskIdsForUser(taskIdsToSave, userId);
    -+        }
    -+        for (int i = 0; i < changedTaskIdsPerUser.size(); i++) {
    -+            writePersistedTaskIdsForUser(changedTaskIdsPerUser.valueAt(i),
    -+                    changedTaskIdsPerUser.keyAt(i));
    -         }
    -     }
    - 
    -diff --git a/services/core/java/com/android/server/am/UriPermission.java b/services/core/java/com/android/server/am/UriPermission.java
    -index 6e371c1..0aa54d9 100644
    ---- a/services/core/java/com/android/server/am/UriPermission.java
    -+++ b/services/core/java/com/android/server/am/UriPermission.java
    -@@ -19,6 +19,7 @@ package com.android.server.am;
    - import android.content.Intent;
    - import android.os.UserHandle;
    - import android.util.ArraySet;
    -+import android.util.Log;
    - import android.util.Slog;
    - 
    - import com.android.server.am.ActivityManagerService.GrantUri;
    -@@ -93,7 +94,16 @@ final class UriPermission {
    -     }
    - 
    -     private void updateModeFlags() {
    -+        final int oldModeFlags = modeFlags;
    -         modeFlags = ownedModeFlags | globalModeFlags | persistableModeFlags | persistedModeFlags;
    -+
    -+        if (Log.isLoggable(TAG, Log.VERBOSE) && (modeFlags != oldModeFlags)) {
    -+            Slog.d(TAG,
    -+                    "Permission for " + targetPkg + " to " + uri + " is changing from 0x"
    -+                            + Integer.toHexString(oldModeFlags) + " to 0x"
    -+                            + Integer.toHexString(modeFlags),
    -+                    new Throwable());
    -+        }
    -     }
    - 
    -     /**
    -diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java
    -index 275870e..a9277ce 100644
    ---- a/services/core/java/com/android/server/audio/AudioService.java
    -+++ b/services/core/java/com/android/server/audio/AudioService.java
    -@@ -5609,6 +5609,8 @@ public class AudioService extends IAudioService.Stub {
    -                 } else { // config == AudioSystem.FORCE_NONE
    -                     mBecomingNoisyIntentDevices |= AudioSystem.DEVICE_OUT_ALL_A2DP;
    -                 }
    -+                sendMsg(mAudioHandler, MSG_REPORT_NEW_ROUTES,
    -+                        SENDMSG_NOOP, 0, 0, null, 0);
    -                 break;
    -             case AudioSystem.FOR_DOCK:
    -                 if (config == AudioSystem.FORCE_ANALOG_DOCK) {
    -diff --git a/services/core/java/com/android/server/audio/FocusRequester.java b/services/core/java/com/android/server/audio/FocusRequester.java
    -index 49be879..cc18114 100644
    ---- a/services/core/java/com/android/server/audio/FocusRequester.java
    -+++ b/services/core/java/com/android/server/audio/FocusRequester.java
    -@@ -40,9 +40,9 @@ public class FocusRequester {
    -     private static final String TAG = "MediaFocusControl";
    -     private static final boolean DEBUG = false;
    - 
    --    private AudioFocusDeathHandler mDeathHandler;
    --    private final IAudioFocusDispatcher mFocusDispatcher; // may be null
    --    private final IBinder mSourceRef;
    -+    private AudioFocusDeathHandler mDeathHandler; // may be null
    -+    private IAudioFocusDispatcher mFocusDispatcher; // may be null
    -+    private final IBinder mSourceRef; // may be null
    -     private final String mClientId;
    -     private final String mPackageName;
    -     private final int mCallingUid;
    -@@ -205,6 +205,7 @@ public class FocusRequester {
    -             if (mSourceRef != null && mDeathHandler != null) {
    -                 mSourceRef.unlinkToDeath(mDeathHandler, 0);
    -                 mDeathHandler = null;
    -+                mFocusDispatcher = null;
    -             }
    -         } catch (java.util.NoSuchElementException e) {
    -             Log.e(TAG, "FocusRequester.release() hit ", e);
    -@@ -275,12 +276,13 @@ public class FocusRequester {
    -             mFocusLossReceived = AudioManager.AUDIOFOCUS_NONE;
    -             mFocusController.notifyExtPolicyFocusGrant_syncAf(toAudioFocusInfo(),
    -                     AudioManager.AUDIOFOCUS_REQUEST_GRANTED);
    --            if (mFocusDispatcher != null) {
    -+            final IAudioFocusDispatcher fd = mFocusDispatcher;
    -+            if (fd != null) {
    -                 if (DEBUG) {
    -                     Log.v(TAG, "dispatching " + focusChangeToString(focusGain) + " to "
    -                         + mClientId);
    -                 }
    --                mFocusDispatcher.dispatchAudioFocusChange(focusGain, mClientId);
    -+                fd.dispatchAudioFocusChange(focusGain, mClientId);
    -             }
    -         } catch (android.os.RemoteException e) {
    -             Log.e(TAG, "Failure to signal gain of audio focus due to: ", e);
    -@@ -311,14 +313,15 @@ public class FocusRequester {
    -                             toAudioFocusInfo(), false /* wasDispatched */);
    -                     return;
    -                 }
    --                if (mFocusDispatcher != null) {
    -+                final IAudioFocusDispatcher fd = mFocusDispatcher;
    -+                if (fd != null) {
    -                     if (DEBUG) {
    -                         Log.v(TAG, "dispatching " + focusChangeToString(mFocusLossReceived) + " to "
    -                             + mClientId);
    -                     }
    -                     mFocusController.notifyExtPolicyFocusLoss_syncAf(
    -                             toAudioFocusInfo(), true /* wasDispatched */);
    --                    mFocusDispatcher.dispatchAudioFocusChange(mFocusLossReceived, mClientId);
    -+                    fd.dispatchAudioFocusChange(mFocusLossReceived, mClientId);
    -                 }
    -             }
    -         } catch (android.os.RemoteException e) {
    -diff --git a/services/core/java/com/android/server/audio/MediaFocusControl.java b/services/core/java/com/android/server/audio/MediaFocusControl.java
    -index 278d70b..206834e 100644
    ---- a/services/core/java/com/android/server/audio/MediaFocusControl.java
    -+++ b/services/core/java/com/android/server/audio/MediaFocusControl.java
    -@@ -160,6 +160,7 @@ public class MediaFocusControl {
    -                     Log.i(TAG, "AudioFocus  removeFocusStackEntry(): removing entry for "
    -                             + clientToRemove);
    -                     stackIterator.remove();
    -+                    // stack entry not used anymore, clear references
    -                     fr.release();
    -                 }
    -             }
    -@@ -171,7 +172,7 @@ public class MediaFocusControl {
    -      * Called synchronized on mAudioFocusLock
    -      * Remove focus listeners from the focus stack for a particular client when it has died.
    -      */
    --    private void removeFocusStackEntryForClient(IBinder cb) {
    -+    private void removeFocusStackEntryOnDeath(IBinder cb) {
    -         // is the owner of the audio focus part of the client to remove?
    -         boolean isTopOfStackForClientToRemove = !mFocusStack.isEmpty() &&
    -                 mFocusStack.peek().hasSameBinder(cb);
    -@@ -181,9 +182,10 @@ public class MediaFocusControl {
    -         while(stackIterator.hasNext()) {
    -             FocusRequester fr = stackIterator.next();
    -             if(fr.hasSameBinder(cb)) {
    --                Log.i(TAG, "AudioFocus  removeFocusStackEntry(): removing entry for " + cb);
    -+                Log.i(TAG, "AudioFocus  removeFocusStackEntryOnDeath(): removing entry for " + cb);
    -                 stackIterator.remove();
    --                // the client just died, no need to unlink to its death
    -+                // stack entry not used anymore, clear references
    -+                fr.release();
    -             }
    -         }
    -         if (isTopOfStackForClientToRemove) {
    -@@ -257,14 +259,9 @@ public class MediaFocusControl {
    - 
    -         public void binderDied() {
    -             synchronized(mAudioFocusLock) {
    --                Log.w(TAG, "  AudioFocus   audio focus client died");
    --                removeFocusStackEntryForClient(mCb);
    -+                removeFocusStackEntryOnDeath(mCb);
    -             }
    -         }
    --
    --        public IBinder getBinder() {
    --            return mCb;
    --        }
    -     }
    - 
    -     /**
    -@@ -420,6 +417,7 @@ public class MediaFocusControl {
    -             // (premature death == death before abandoning focus)
    -             // Register for client death notification
    -             AudioFocusDeathHandler afdh = new AudioFocusDeathHandler(cb);
    -+
    -             try {
    -                 cb.linkToDeath(afdh, 0);
    -             } catch (RemoteException e) {
    -diff --git a/services/core/java/com/android/server/connectivity/IpConnectivityEventBuilder.java b/services/core/java/com/android/server/connectivity/IpConnectivityEventBuilder.java
    -new file mode 100644
    -index 0000000..f1ef947
    ---- /dev/null
    -+++ b/services/core/java/com/android/server/connectivity/IpConnectivityEventBuilder.java
    -@@ -0,0 +1,257 @@
    -+/*
    -+ * Copyright (C) 2016 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 com.android.server.connectivity;
    -+
    -+import android.net.ConnectivityMetricsEvent;
    -+import android.net.metrics.ApfProgramEvent;
    -+import android.net.metrics.ApfStats;
    -+import android.net.metrics.DefaultNetworkEvent;
    -+import android.net.metrics.DhcpClientEvent;
    -+import android.net.metrics.DhcpErrorEvent;
    -+import android.net.metrics.DnsEvent;
    -+import android.net.metrics.IpManagerEvent;
    -+import android.net.metrics.IpReachabilityEvent;
    -+import android.net.metrics.NetworkEvent;
    -+import android.net.metrics.RaEvent;
    -+import android.net.metrics.ValidationProbeEvent;
    -+import android.os.Parcelable;
    -+import com.android.server.connectivity.metrics.IpConnectivityLogClass;
    -+import java.io.IOException;
    -+import java.util.ArrayList;
    -+import java.util.List;
    -+
    -+import static com.android.server.connectivity.metrics.IpConnectivityLogClass.IpConnectivityEvent;
    -+import static com.android.server.connectivity.metrics.IpConnectivityLogClass.IpConnectivityLog;
    -+import static com.android.server.connectivity.metrics.IpConnectivityLogClass.NetworkId;
    -+
    -+/** {@hide} */
    -+final public class IpConnectivityEventBuilder {
    -+    private IpConnectivityEventBuilder() {
    -+    }
    -+
    -+    public static byte[] serialize(int dropped, List<ConnectivityMetricsEvent> events)
    -+            throws IOException {
    -+        final IpConnectivityLog log = new IpConnectivityLog();
    -+        log.events = toProto(events);
    -+        log.droppedEvents = dropped;
    -+        return IpConnectivityLog.toByteArray(log);
    -+    }
    -+
    -+    public static IpConnectivityEvent[] toProto(List<ConnectivityMetricsEvent> eventsIn) {
    -+        final ArrayList<IpConnectivityEvent> eventsOut = new ArrayList<>(eventsIn.size());
    -+        for (ConnectivityMetricsEvent in : eventsIn) {
    -+            final IpConnectivityEvent out = toProto(in);
    -+            if (out == null) {
    -+                continue;
    -+            }
    -+            eventsOut.add(out);
    -+        }
    -+        return eventsOut.toArray(new IpConnectivityEvent[eventsOut.size()]);
    -+    }
    -+
    -+    public static IpConnectivityEvent toProto(ConnectivityMetricsEvent ev) {
    -+        final IpConnectivityEvent out = new IpConnectivityEvent();
    -+        if (!setEvent(out, ev.data)) {
    -+            return null;
    -+        }
    -+        out.timeMs = ev.timestamp;
    -+        return out;
    -+    }
    -+
    -+    private static boolean setEvent(IpConnectivityEvent out, Parcelable in) {
    -+        if (in instanceof DhcpErrorEvent) {
    -+            setDhcpErrorEvent(out, (DhcpErrorEvent) in);
    -+            return true;
    -+        }
    -+
    -+        if (in instanceof DhcpClientEvent) {
    -+            setDhcpClientEvent(out, (DhcpClientEvent) in);
    -+            return true;
    -+        }
    -+
    -+        if (in instanceof DnsEvent) {
    -+            setDnsEvent(out, (DnsEvent) in);
    -+            return true;
    -+        }
    -+
    -+        if (in instanceof IpManagerEvent) {
    -+            setIpManagerEvent(out, (IpManagerEvent) in);
    -+            return true;
    -+        }
    -+
    -+        if (in instanceof IpReachabilityEvent) {
    -+            setIpReachabilityEvent(out, (IpReachabilityEvent) in);
    -+            return true;
    -+        }
    -+
    -+        if (in instanceof DefaultNetworkEvent) {
    -+            setDefaultNetworkEvent(out, (DefaultNetworkEvent) in);
    -+            return true;
    -+        }
    -+
    -+        if (in instanceof NetworkEvent) {
    -+            setNetworkEvent(out, (NetworkEvent) in);
    -+            return true;
    -+        }
    -+
    -+        if (in instanceof ValidationProbeEvent) {
    -+            setValidationProbeEvent(out, (ValidationProbeEvent) in);
    -+            return true;
    -+        }
    -+
    -+        if (in instanceof ApfProgramEvent) {
    -+            setApfProgramEvent(out, (ApfProgramEvent) in);
    -+            return true;
    -+        }
    -+
    -+        if (in instanceof ApfStats) {
    -+            setApfStats(out, (ApfStats) in);
    -+            return true;
    -+        }
    -+
    -+        if (in instanceof RaEvent) {
    -+            setRaEvent(out, (RaEvent) in);
    -+            return true;
    -+        }
    -+
    -+        return false;
    -+    }
    -+
    -+    private static void setDhcpErrorEvent(IpConnectivityEvent out, DhcpErrorEvent in) {
    -+        out.dhcpEvent = new IpConnectivityLogClass.DHCPEvent();
    -+        out.dhcpEvent.ifName = in.ifName;
    -+        out.dhcpEvent.errorCode = in.errorCode;
    -+    }
    -+
    -+    private static void setDhcpClientEvent(IpConnectivityEvent out, DhcpClientEvent in) {
    -+        out.dhcpEvent = new IpConnectivityLogClass.DHCPEvent();
    -+        out.dhcpEvent.ifName = in.ifName;
    -+        out.dhcpEvent.stateTransition = in.msg;
    -+        out.dhcpEvent.durationMs = in.durationMs;
    -+    }
    -+
    -+    private static void setDnsEvent(IpConnectivityEvent out, DnsEvent in) {
    -+        out.dnsLookupBatch = new IpConnectivityLogClass.DNSLookupBatch();
    -+        out.dnsLookupBatch.networkId = netIdOf(in.netId);
    -+        out.dnsLookupBatch.eventTypes = bytesToInts(in.eventTypes);
    -+        out.dnsLookupBatch.returnCodes = bytesToInts(in.returnCodes);
    -+        out.dnsLookupBatch.latenciesMs = in.latenciesMs;
    -+    }
    -+
    -+    private static void setIpManagerEvent(IpConnectivityEvent out, IpManagerEvent in) {
    -+        out.ipProvisioningEvent = new IpConnectivityLogClass.IpProvisioningEvent();
    -+        out.ipProvisioningEvent.ifName = in.ifName;
    -+        out.ipProvisioningEvent.eventType = in.eventType;
    -+        out.ipProvisioningEvent.latencyMs = (int) in.durationMs;
    -+    }
    -+
    -+    private static void setIpReachabilityEvent(IpConnectivityEvent out, IpReachabilityEvent in) {
    -+        out.ipReachabilityEvent = new IpConnectivityLogClass.IpReachabilityEvent();
    -+        out.ipReachabilityEvent.ifName = in.ifName;
    -+        out.ipReachabilityEvent.eventType = in.eventType;
    -+    }
    -+
    -+    private static void setDefaultNetworkEvent(IpConnectivityEvent out, DefaultNetworkEvent in) {
    -+        out.defaultNetworkEvent = new IpConnectivityLogClass.DefaultNetworkEvent();
    -+        out.defaultNetworkEvent.networkId = netIdOf(in.netId);
    -+        out.defaultNetworkEvent.previousNetworkId = netIdOf(in.prevNetId);
    -+        out.defaultNetworkEvent.transportTypes = in.transportTypes;
    -+        out.defaultNetworkEvent.previousNetworkIpSupport = ipSupportOf(in);
    -+    }
    -+
    -+    private static void setNetworkEvent(IpConnectivityEvent out, NetworkEvent in) {
    -+        out.networkEvent = new IpConnectivityLogClass.NetworkEvent();
    -+        out.networkEvent.networkId = netIdOf(in.netId);
    -+        out.networkEvent.eventType = in.eventType;
    -+        out.networkEvent.latencyMs = (int) in.durationMs;
    -+    }
    -+
    -+    private static void setValidationProbeEvent(IpConnectivityEvent out, ValidationProbeEvent in) {
    -+        out.validationProbeEvent = new IpConnectivityLogClass.ValidationProbeEvent();
    -+        out.validationProbeEvent.networkId = netIdOf(in.netId);
    -+        out.validationProbeEvent.latencyMs = (int) in.durationMs;
    -+        out.validationProbeEvent.probeType = in.probeType;
    -+        out.validationProbeEvent.probeResult = in.returnCode;
    -+    }
    -+
    -+    private static void setApfProgramEvent(IpConnectivityEvent out, ApfProgramEvent in) {
    -+        out.apfProgramEvent = new IpConnectivityLogClass.ApfProgramEvent();
    -+        out.apfProgramEvent.lifetime = in.lifetime;
    -+        out.apfProgramEvent.filteredRas = in.filteredRas;
    -+        out.apfProgramEvent.currentRas = in.currentRas;
    -+        out.apfProgramEvent.programLength = in.programLength;
    -+        if (isBitSet(in.flags, ApfProgramEvent.FLAG_MULTICAST_FILTER_ON)) {
    -+            out.apfProgramEvent.dropMulticast = true;
    -+        }
    -+        if (isBitSet(in.flags, ApfProgramEvent.FLAG_HAS_IPV4_ADDRESS)) {
    -+            out.apfProgramEvent.hasIpv4Addr = true;
    -+        }
    -+    }
    -+
    -+    private static void setApfStats(IpConnectivityEvent out, ApfStats in) {
    -+        out.apfStatistics = new IpConnectivityLogClass.ApfStatistics();
    -+        out.apfStatistics.durationMs = in.durationMs;
    -+        out.apfStatistics.receivedRas = in.receivedRas;
    -+        out.apfStatistics.matchingRas = in.matchingRas;
    -+        out.apfStatistics.droppedRas = in.droppedRas;
    -+        out.apfStatistics.zeroLifetimeRas = in.zeroLifetimeRas;
    -+        out.apfStatistics.parseErrors = in.parseErrors;
    -+        out.apfStatistics.programUpdates = in.programUpdates;
    -+        out.apfStatistics.maxProgramSize = in.maxProgramSize;
    -+    }
    -+
    -+    private static void setRaEvent(IpConnectivityEvent out, RaEvent in) {
    -+        out.raEvent = new IpConnectivityLogClass.RaEvent();
    -+        out.raEvent.routerLifetime = in.routerLifetime;
    -+        out.raEvent.prefixValidLifetime = in.prefixValidLifetime;
    -+        out.raEvent.prefixPreferredLifetime = in.prefixPreferredLifetime;
    -+        out.raEvent.routeInfoLifetime = in.routeInfoLifetime;
    -+        out.raEvent.rdnssLifetime = in.rdnssLifetime;
    -+        out.raEvent.dnsslLifetime = in.dnsslLifetime;
    -+    }
    -+
    -+    private static int[] bytesToInts(byte[] in) {
    -+        final int[] out = new int[in.length];
    -+        for (int i = 0; i < in.length; i++) {
    -+            out[i] = in[i] & 0xFF;
    -+        }
    -+        return out;
    -+    }
    -+
    -+    private static NetworkId netIdOf(int netid) {
    -+        final NetworkId ni = new NetworkId();
    -+        ni.networkId = netid;
    -+        return ni;
    -+    }
    -+
    -+    private static int ipSupportOf(DefaultNetworkEvent in) {
    -+        if (in.prevIPv4 && in.prevIPv6) {
    -+            return IpConnectivityLogClass.DefaultNetworkEvent.DUAL;
    -+        }
    -+        if (in.prevIPv6) {
    -+            return IpConnectivityLogClass.DefaultNetworkEvent.IPV6;
    -+        }
    -+        if (in.prevIPv4) {
    -+            return IpConnectivityLogClass.DefaultNetworkEvent.IPV4;
    -+        }
    -+        return IpConnectivityLogClass.DefaultNetworkEvent.NONE;
    -+    }
    -+
    -+    private static boolean isBitSet(int flags, int bit) {
    -+        return (flags & (1 << bit)) != 0;
    -+    }
    -+}
    -diff --git a/services/core/java/com/android/server/connectivity/IpConnectivityMetrics.java b/services/core/java/com/android/server/connectivity/IpConnectivityMetrics.java
    -new file mode 100644
    -index 0000000..bcbcf54
    ---- /dev/null
    -+++ b/services/core/java/com/android/server/connectivity/IpConnectivityMetrics.java
    -@@ -0,0 +1,229 @@
    -+/*
    -+ * Copyright (C) 2016 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 com.android.server.connectivity;
    -+
    -+import android.content.Context;
    -+import android.net.ConnectivityMetricsEvent;
    -+import android.net.IIpConnectivityMetrics;
    -+import android.net.metrics.IpConnectivityLog;
    -+import android.os.IBinder;
    -+import android.os.Parcelable;
    -+import android.text.TextUtils;
    -+import android.util.Base64;
    -+import android.util.Log;
    -+import com.android.internal.annotations.GuardedBy;
    -+import com.android.internal.annotations.VisibleForTesting;
    -+import com.android.server.SystemService;
    -+import java.io.FileDescriptor;
    -+import java.io.IOException;
    -+import java.io.PrintWriter;
    -+import java.util.ArrayList;
    -+
    -+import static com.android.server.connectivity.metrics.IpConnectivityLogClass.IpConnectivityEvent;
    -+
    -+/** {@hide} */
    -+final public class IpConnectivityMetrics extends SystemService {
    -+    private static final String TAG = IpConnectivityMetrics.class.getSimpleName();
    -+    private static final boolean DBG = false;
    -+
    -+    private static final String SERVICE_NAME = IpConnectivityLog.SERVICE_NAME;
    -+
    -+    // Default size of the event buffer. Once the buffer is full, incoming events are dropped.
    -+    private static final int DEFAULT_BUFFER_SIZE = 2000;
    -+
    -+    // Lock ensuring that concurrent manipulations of the event buffer are correct.
    -+    // There are three concurrent operations to synchronize:
    -+    //  - appending events to the buffer.
    -+    //  - iterating throught the buffer.
    -+    //  - flushing the buffer content and replacing it by a new buffer.
    -+    private final Object mLock = new Object();
    -+
    -+    @VisibleForTesting
    -+    public final Impl impl = new Impl();
    -+    private DnsEventListenerService mDnsListener;
    -+
    -+    @GuardedBy("mLock")
    -+    private ArrayList<ConnectivityMetricsEvent> mBuffer;
    -+    @GuardedBy("mLock")
    -+    private int mDropped;
    -+    @GuardedBy("mLock")
    -+    private int mCapacity;
    -+
    -+    public IpConnectivityMetrics(Context ctx) {
    -+        super(ctx);
    -+        initBuffer();
    -+    }
    -+
    -+    @Override
    -+    public void onStart() {
    -+        if (DBG) Log.d(TAG, "onStart");
    -+    }
    -+
    -+    @Override
    -+    public void onBootPhase(int phase) {
    -+        if (phase == SystemService.PHASE_SYSTEM_SERVICES_READY) {
    -+            if (DBG) Log.d(TAG, "onBootPhase");
    -+            mDnsListener = new DnsEventListenerService(getContext());
    -+
    -+            publishBinderService(SERVICE_NAME, impl);
    -+            publishBinderService(mDnsListener.SERVICE_NAME, mDnsListener);
    -+        }
    -+    }
    -+
    -+    @VisibleForTesting
    -+    public int bufferCapacity() {
    -+        return DEFAULT_BUFFER_SIZE; // TODO: read from config
    -+    }
    -+
    -+    private void initBuffer() {
    -+        synchronized (mLock) {
    -+            mDropped = 0;
    -+            mCapacity = bufferCapacity();
    -+            mBuffer = new ArrayList<>(mCapacity);
    -+        }
    -+    }
    -+
    -+    private int append(ConnectivityMetricsEvent event) {
    -+        if (DBG) Log.d(TAG, "logEvent: " + event);
    -+        synchronized (mLock) {
    -+            final int left = mCapacity - mBuffer.size();
    -+            if (event == null) {
    -+                return left;
    -+            }
    -+            if (left == 0) {
    -+                mDropped++;
    -+                return 0;
    -+            }
    -+            mBuffer.add(event);
    -+            return left - 1;
    -+        }
    -+    }
    -+
    -+    private String flushEncodedOutput() {
    -+        final ArrayList<ConnectivityMetricsEvent> events;
    -+        final int dropped;
    -+        synchronized (mLock) {
    -+            events = mBuffer;
    -+            dropped = mDropped;
    -+            initBuffer();
    -+        }
    -+
    -+        final byte[] data;
    -+        try {
    -+            data = IpConnectivityEventBuilder.serialize(dropped, events);
    -+        } catch (IOException e) {
    -+            Log.e(TAG, "could not serialize events", e);
    -+            return "";
    -+        }
    -+
    -+        return Base64.encodeToString(data, Base64.DEFAULT);
    -+    }
    -+
    -+    /**
    -+     * Clears the event buffer and prints its content as a protobuf serialized byte array
    -+     * inside a base64 encoded string.
    -+     */
    -+    private void cmdFlush(FileDescriptor fd, PrintWriter pw, String[] args) {
    -+        pw.print(flushEncodedOutput());
    -+    }
    -+
    -+    /**
    -+     * Prints the content of the event buffer, either using the events ASCII representation
    -+     * or using protobuf text format.
    -+     */
    -+    private void cmdList(FileDescriptor fd, PrintWriter pw, String[] args) {
    -+        final ArrayList<ConnectivityMetricsEvent> events;
    -+        synchronized (mLock) {
    -+            events = new ArrayList(mBuffer);
    -+        }
    -+
    -+        if (args.length > 1 && args[1].equals("proto")) {
    -+            for (IpConnectivityEvent ev : IpConnectivityEventBuilder.toProto(events)) {
    -+                pw.print(ev.toString());
    -+            }
    -+            return;
    -+        }
    -+
    -+        for (ConnectivityMetricsEvent ev : events) {
    -+            pw.println(ev.toString());
    -+        }
    -+    }
    -+
    -+    private void cmdStats(FileDescriptor fd, PrintWriter pw, String[] args) {
    -+        synchronized (mLock) {
    -+            pw.println("Buffered events: " + mBuffer.size());
    -+            pw.println("Buffer capacity: " + mCapacity);
    -+            pw.println("Dropped events: " + mDropped);
    -+        }
    -+        if (mDnsListener != null) {
    -+            mDnsListener.dump(pw);
    -+        }
    -+    }
    -+
    -+    private void cmdDefault(FileDescriptor fd, PrintWriter pw, String[] args) {
    -+        if (args.length == 0) {
    -+            pw.println("No command");
    -+            return;
    -+        }
    -+        pw.println("Unknown command " + TextUtils.join(" ", args));
    -+    }
    -+
    -+    public final class Impl extends IIpConnectivityMetrics.Stub {
    -+        static final String CMD_FLUSH   = "flush";
    -+        static final String CMD_LIST    = "list";
    -+        static final String CMD_STATS   = "stats";
    -+        static final String CMD_DEFAULT = CMD_STATS;
    -+
    -+        @Override
    -+        public int logEvent(ConnectivityMetricsEvent event) {
    -+            enforceConnectivityInternalPermission();
    -+            return append(event);
    -+        }
    -+
    -+        @Override
    -+        public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
    -+            enforceDumpPermission();
    -+            if (DBG) Log.d(TAG, "dumpsys " + TextUtils.join(" ", args));
    -+            final String cmd = (args.length > 0) ? args[0] : CMD_DEFAULT;
    -+            switch (cmd) {
    -+                case CMD_FLUSH:
    -+                    cmdFlush(fd, pw, args);
    -+                    return;
    -+                case CMD_LIST:
    -+                    cmdList(fd, pw, args);
    -+                    return;
    -+                case CMD_STATS:
    -+                    cmdStats(fd, pw, args);
    -+                    return;
    -+                default:
    -+                    cmdDefault(fd, pw, args);
    -+            }
    -+        }
    -+
    -+        private void enforceConnectivityInternalPermission() {
    -+            enforcePermission(android.Manifest.permission.CONNECTIVITY_INTERNAL);
    -+        }
    -+
    -+        private void enforceDumpPermission() {
    -+            enforcePermission(android.Manifest.permission.DUMP);
    -+        }
    -+
    -+        private void enforcePermission(String what) {
    -+            getContext().enforceCallingOrSelfPermission(what, "IpConnectivityMetrics");
    -+        }
    -+    };
    -+}
    -diff --git a/services/core/java/com/android/server/connectivity/MetricsLoggerService.java b/services/core/java/com/android/server/connectivity/MetricsLoggerService.java
    -index 05f1a6e..1c9feb2 100644
    ---- a/services/core/java/com/android/server/connectivity/MetricsLoggerService.java
    -+++ b/services/core/java/com/android/server/connectivity/MetricsLoggerService.java
    -@@ -56,8 +56,6 @@ public class MetricsLoggerService extends SystemService {
    -             if (DBG) Log.d(TAG, "onBootPhase: PHASE_SYSTEM_SERVICES_READY");
    -             publishBinderService(ConnectivityMetricsLogger.CONNECTIVITY_METRICS_LOGGER_SERVICE,
    -                     mBinder);
    --            mDnsListener = new DnsEventListenerService(getContext());
    --            publishBinderService(mDnsListener.SERVICE_NAME, mDnsListener);
    -         }
    -     }
    - 
    -@@ -86,8 +84,6 @@ public class MetricsLoggerService extends SystemService {
    - 
    -     private final ArrayDeque<ConnectivityMetricsEvent> mEvents = new ArrayDeque<>();
    - 
    --    private DnsEventListenerService mDnsListener;
    --
    -     private void enforceConnectivityInternalPermission() {
    -         getContext().enforceCallingOrSelfPermission(
    -                 android.Manifest.permission.CONNECTIVITY_INTERNAL,
    -@@ -219,11 +215,6 @@ public class MetricsLoggerService extends SystemService {
    -                     }
    -                 }
    -             }
    --
    --            pw.println();
    --            if (mDnsListener != null) {
    --                mDnsListener.dump(pw);
    --            }
    -         }
    - 
    -         public long logEvent(ConnectivityMetricsEvent event) {
    -diff --git a/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java b/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java
    -index 9c48aee..2a618bc 100644
    ---- a/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java
    -+++ b/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java
    -@@ -104,14 +104,16 @@ import java.util.TreeSet;
    - // -----------------------------------------------
    - // If a network has no chance of satisfying any requests (even if it were to become validated
    - // and enter state #5), ConnectivityService will disconnect the NetworkAgent's AsyncChannel.
    --// If the network ever for any period of time had satisfied a NetworkRequest (i.e. had been
    --// the highest scoring that satisfied the NetworkRequest's constraints), but is no longer the
    --// highest scoring network for any NetworkRequest, then there will be a 30s pause before
    --// ConnectivityService disconnects the NetworkAgent's AsyncChannel.  During this pause the
    --// network is considered "lingering".  This pause exists to allow network communication to be
    --// wrapped up rather than abruptly terminated.  During this pause if the network begins satisfying
    --// a NetworkRequest, ConnectivityService will cancel the future disconnection of the NetworkAgent's
    --// AsyncChannel, and the network is no longer considered "lingering".
    -+//
    -+// If the network was satisfying a foreground NetworkRequest (i.e. had been the highest scoring that
    -+// satisfied the NetworkRequest's constraints), but is no longer the highest scoring network for any
    -+// foreground NetworkRequest, then there will be a 30s pause to allow network communication to be
    -+// wrapped up rather than abruptly terminated. During this pause the network is said to be
    -+// "lingering". During this pause if the network begins satisfying a foreground NetworkRequest,
    -+// ConnectivityService will cancel the future disconnection of the NetworkAgent's AsyncChannel, and
    -+// the network is no longer considered "lingering". After the linger timer expires, if the network
    -+// is satisfying one or more background NetworkRequests it is kept up in the background. If it is
    -+// not, ConnectivityService disconnects the NetworkAgent's AsyncChannel.
    - public class NetworkAgentInfo implements Comparable<NetworkAgentInfo> {
    - 
    -     public NetworkInfo networkInfo;
    -@@ -230,11 +232,13 @@ public class NetworkAgentInfo implements Comparable<NetworkAgentInfo> {
    - 
    -     // The list of NetworkRequests being satisfied by this Network.
    -     private final SparseArray<NetworkRequest> mNetworkRequests = new SparseArray<>();
    --    // The list of NetworkRequests that this Network previously satisfied with the highest
    --    // score.  A non-empty list indicates that if this Network was validated it is lingered.
    -+
    -     // How many of the satisfied requests are actual requests and not listens.
    -     private int mNumRequestNetworkRequests = 0;
    - 
    -+    // How many of the satisfied requests are of type BACKGROUND_REQUEST.
    -+    private int mNumBackgroundNetworkRequests = 0;
    -+
    -     public final Messenger messenger;
    -     public final AsyncChannel asyncChannel;
    - 
    -@@ -268,6 +272,32 @@ public class NetworkAgentInfo implements Comparable<NetworkAgentInfo> {
    -     //
    -     // These functions must only called on ConnectivityService's main thread.
    - 
    -+    private static final boolean ADD = true;
    -+    private static final boolean REMOVE = false;
    -+
    -+    private void updateRequestCounts(boolean add, NetworkRequest request) {
    -+        int delta = add ? +1 : -1;
    -+        switch (request.type) {
    -+            case REQUEST:
    -+            case TRACK_DEFAULT:
    -+                mNumRequestNetworkRequests += delta;
    -+                break;
    -+
    -+            case BACKGROUND_REQUEST:
    -+                mNumRequestNetworkRequests += delta;
    -+                mNumBackgroundNetworkRequests += delta;
    -+                break;
    -+
    -+            case LISTEN:
    -+                break;
    -+
    -+            case NONE:
    -+            default:
    -+                Log.wtf(TAG, "Unhandled request type " + request.type);
    -+                break;
    -+        }
    -+    }
    -+
    -     /**
    -      * Add {@code networkRequest} to this network as it's satisfied by this network.
    -      * @return true if {@code networkRequest} was added or false if {@code networkRequest} was
    -@@ -276,9 +306,15 @@ public class NetworkAgentInfo implements Comparable<NetworkAgentInfo> {
    -     public boolean addRequest(NetworkRequest networkRequest) {
    -         NetworkRequest existing = mNetworkRequests.get(networkRequest.requestId);
    -         if (existing == networkRequest) return false;
    --        if (existing != null && existing.isRequest()) mNumRequestNetworkRequests--;
    -+        if (existing != null) {
    -+            // Should only happen if the requestId wraps. If that happens lots of other things will
    -+            // be broken as well.
    -+            Log.wtf(TAG, String.format("Duplicate requestId for %s and %s on %s",
    -+                    networkRequest, existing, name()));
    -+            updateRequestCounts(REMOVE, existing);
    -+        }
    -         mNetworkRequests.put(networkRequest.requestId, networkRequest);
    --        if (networkRequest.isRequest()) mNumRequestNetworkRequests++;
    -+        updateRequestCounts(ADD, networkRequest);
    -         return true;
    -     }
    - 
    -@@ -288,9 +324,9 @@ public class NetworkAgentInfo implements Comparable<NetworkAgentInfo> {
    -     public void removeRequest(int requestId) {
    -         NetworkRequest existing = mNetworkRequests.get(requestId);
    -         if (existing == null) return;
    -+        updateRequestCounts(REMOVE, existing);
    -         mNetworkRequests.remove(requestId);
    -         if (existing.isRequest()) {
    --            mNumRequestNetworkRequests--;
    -             unlingerRequest(existing);
    -         }
    -     }
    -@@ -319,12 +355,37 @@ public class NetworkAgentInfo implements Comparable<NetworkAgentInfo> {
    -     }
    - 
    -     /**
    -+     * Returns the number of requests currently satisfied by this network of type
    -+     * {@link android.net.NetworkRequest.Type.BACKGROUND_REQUEST}.
    -+     */
    -+    public int numBackgroundNetworkRequests() {
    -+        return mNumBackgroundNetworkRequests;
    -+    }
    -+
    -+    /**
    -+     * Returns the number of foreground requests currently satisfied by this network.
    -+     */
    -+    public int numForegroundNetworkRequests() {
    -+        return mNumRequestNetworkRequests - mNumBackgroundNetworkRequests;
    -+    }
    -+
    -+    /**
    -      * Returns the number of requests of any type currently satisfied by this network.
    -      */
    -     public int numNetworkRequests() {
    -         return mNetworkRequests.size();
    -     }
    - 
    -+    /**
    -+     * Returns whether the network is a background network. A network is a background network if it
    -+     * is satisfying no foreground requests and at least one background request. (If it did not have
    -+     * a background request, it would be a speculative network that is only being kept up because
    -+     * it might satisfy a request if it validated).
    -+     */
    -+    public boolean isBackgroundNetwork() {
    -+        return !isVPN() && numForegroundNetworkRequests() == 0 && mNumBackgroundNetworkRequests > 0;
    -+    }
    -+
    -     // Does this network satisfy request?
    -     public boolean satisfies(NetworkRequest request) {
    -         return created &&
    -diff --git a/services/core/java/com/android/server/connectivity/NetworkMonitor.java b/services/core/java/com/android/server/connectivity/NetworkMonitor.java
    -index 42d80fc..6eb89fa 100644
    ---- a/services/core/java/com/android/server/connectivity/NetworkMonitor.java
    -+++ b/services/core/java/com/android/server/connectivity/NetworkMonitor.java
    -@@ -23,7 +23,6 @@ import static android.net.CaptivePortal.APP_RETURN_WANTED_AS_IS;
    - import android.app.AlarmManager;
    - import android.app.PendingIntent;
    - import android.content.BroadcastReceiver;
    --import android.content.ComponentName;
    - import android.content.Context;
    - import android.content.Intent;
    - import android.content.IntentFilter;
    -@@ -37,14 +36,12 @@ import android.net.Uri;
    - import android.net.metrics.IpConnectivityLog;
    - import android.net.metrics.NetworkEvent;
    - import android.net.metrics.ValidationProbeEvent;
    -+import android.net.util.Stopwatch;
    - import android.net.wifi.WifiInfo;
    - import android.net.wifi.WifiManager;
    --import android.net.util.Stopwatch;
    - import android.os.Handler;
    - import android.os.Message;
    --import android.os.Process;
    - import android.os.SystemClock;
    --import android.os.SystemProperties;
    - import android.os.UserHandle;
    - import android.provider.Settings;
    - import android.telephony.CellIdentityCdma;
    -@@ -66,27 +63,39 @@ import com.android.internal.annotations.VisibleForTesting;
    - import com.android.internal.util.Protocol;
    - import com.android.internal.util.State;
    - import com.android.internal.util.StateMachine;
    --import com.android.internal.util.WakeupMessage;
    - 
    - import java.io.IOException;
    - import java.net.HttpURLConnection;
    - import java.net.InetAddress;
    - import java.net.MalformedURLException;
    --import java.net.UnknownHostException;
    - import java.net.URL;
    --import java.util.concurrent.CountDownLatch;
    --import java.util.concurrent.atomic.AtomicReference;
    -+import java.net.UnknownHostException;
    - import java.util.List;
    - import java.util.Random;
    -+import java.util.concurrent.CountDownLatch;
    -+import java.util.concurrent.TimeUnit;
    - 
    - /**
    -  * {@hide}
    -  */
    - public class NetworkMonitor extends StateMachine {
    --    private static final boolean DBG = false;
    -     private static final String TAG = NetworkMonitor.class.getSimpleName();
    --    private static final String DEFAULT_SERVER = "connectivitycheck.gstatic.com";
    -+    private static final boolean DBG = false;
    -+
    -+    // Default configuration values for captive portal detection probes.
    -+    // TODO: append a random length parameter to the default HTTPS url.
    -+    // TODO: randomize browser version ids in the default User-Agent String.
    -+    private static final String DEFAULT_HTTPS_URL     = "https://www.google.com/generate_204";
    -+    private static final String DEFAULT_HTTP_URL      =
    -+            "http://connectivitycheck.gstatic.com/generate_204";
    -+    private static final String DEFAULT_FALLBACK_URL  = "http://www.google.com/gen_204";
    -+    private static final String DEFAULT_USER_AGENT    = "Mozilla/5.0 (X11; Linux x86_64) "
    -+                                                      + "AppleWebKit/537.36 (KHTML, like Gecko) "
    -+                                                      + "Chrome/52.0.2743.82 Safari/537.36";
    -+
    -     private static final int SOCKET_TIMEOUT_MS = 10000;
    -+    private static final int PROBE_TIMEOUT_MS  = 3000;
    -+
    -     public static final String ACTION_NETWORK_CONDITIONS_MEASURED =
    -             "android.net.conn.NETWORK_CONDITIONS_MEASURED";
    -     public static final String EXTRA_CONNECTIVITY_TYPE = "extra_connectivity_type";
    -@@ -224,6 +233,9 @@ public class NetworkMonitor extends StateMachine {
    - 
    -     private final Stopwatch mEvaluationTimer = new Stopwatch();
    - 
    -+    // This variable is set before transitioning to the mCaptivePortalState.
    -+    private CaptivePortalProbeResult mLastPortalProbeResult = CaptivePortalProbeResult.FAILED;
    -+
    -     public NetworkMonitor(Context context, Handler handler, NetworkAgentInfo networkAgentInfo,
    -             NetworkRequest defaultRequest) {
    -         this(context, handler, networkAgentInfo, defaultRequest, new IpConnectivityLog());
    -@@ -389,6 +401,8 @@ public class NetworkMonitor extends StateMachine {
    -                                     sendMessage(CMD_CAPTIVE_PORTAL_APP_FINISHED, response);
    -                                 }
    -                             }));
    -+                    intent.putExtra(ConnectivityManager.EXTRA_CAPTIVE_PORTAL_URL,
    -+                            mLastPortalProbeResult.detectUrl);
    -                     intent.setFlags(
    -                             Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT | Intent.FLAG_ACTIVITY_NEW_TASK);
    -                     mContext.startActivityAsUser(intent, UserHandle.CURRENT);
    -@@ -412,14 +426,22 @@ public class NetworkMonitor extends StateMachine {
    -      */
    -     @VisibleForTesting
    -     public static final class CaptivePortalProbeResult {
    --        static final CaptivePortalProbeResult FAILED = new CaptivePortalProbeResult(599, null);
    -+        static final CaptivePortalProbeResult FAILED = new CaptivePortalProbeResult(599);
    - 
    --        final int mHttpResponseCode; // HTTP response code returned from Internet probe.
    --        final String mRedirectUrl;   // Redirect destination returned from Internet probe.
    -+        private final int mHttpResponseCode;  // HTTP response code returned from Internet probe.
    -+        final String redirectUrl;             // Redirect destination returned from Internet probe.
    -+        final String detectUrl;               // URL where a 204 response code indicates
    -+                                              // captive portal has been appeased.
    - 
    --        public CaptivePortalProbeResult(int httpResponseCode, String redirectUrl) {
    -+        public CaptivePortalProbeResult(
    -+                int httpResponseCode, String redirectUrl, String detectUrl) {
    -             mHttpResponseCode = httpResponseCode;
    --            mRedirectUrl = redirectUrl;
    -+            this.redirectUrl = redirectUrl;
    -+            this.detectUrl = detectUrl;
    -+        }
    -+
    -+        public CaptivePortalProbeResult(int httpResponseCode) {
    -+            this(httpResponseCode, null, null);
    -         }
    - 
    -         boolean isSuccessful() { return mHttpResponseCode == 204; }
    -@@ -492,7 +514,8 @@ public class NetworkMonitor extends StateMachine {
    -                         transitionTo(mValidatedState);
    -                     } else if (probeResult.isPortal()) {
    -                         mConnectivityServiceHandler.sendMessage(obtainMessage(EVENT_NETWORK_TESTED,
    --                                NETWORK_TEST_RESULT_INVALID, mNetId, probeResult.mRedirectUrl));
    -+                                NETWORK_TEST_RESULT_INVALID, mNetId, probeResult.redirectUrl));
    -+                        mLastPortalProbeResult = probeResult;
    -                         transitionTo(mCaptivePortalState);
    -                     } else {
    -                         final Message msg = obtainMessage(CMD_REEVALUATE, ++mReevaluateToken, 0);
    -@@ -500,7 +523,7 @@ public class NetworkMonitor extends StateMachine {
    -                         logNetworkEvent(NetworkEvent.NETWORK_VALIDATION_FAILED);
    -                         mConnectivityServiceHandler.sendMessage(obtainMessage(
    -                                 EVENT_NETWORK_TESTED, NETWORK_TEST_RESULT_INVALID, mNetId,
    --                                probeResult.mRedirectUrl));
    -+                                probeResult.redirectUrl));
    -                         if (mAttempts >= BLAME_FOR_EVALUATION_ATTEMPTS) {
    -                             // Don't continue to blame UID forever.
    -                             TrafficStats.clearThreadStatsUid();
    -@@ -585,22 +608,33 @@ public class NetworkMonitor extends StateMachine {
    -         }
    -     }
    - 
    --    private static String getCaptivePortalServerUrl(Context context, boolean isHttps) {
    --        String server = Settings.Global.getString(context.getContentResolver(),
    --                Settings.Global.CAPTIVE_PORTAL_SERVER);
    --        if (server == null) server = DEFAULT_SERVER;
    --        return (isHttps ? "https" : "http") + "://" + server + "/generate_204";
    -+    private static String getCaptivePortalServerHttpsUrl(Context context) {
    -+        return getSetting(context, Settings.Global.CAPTIVE_PORTAL_HTTPS_URL, DEFAULT_HTTPS_URL);
    -+    }
    -+
    -+    public static String getCaptivePortalServerHttpUrl(Context context) {
    -+        return getSetting(context, Settings.Global.CAPTIVE_PORTAL_HTTP_URL, DEFAULT_HTTP_URL);
    -     }
    - 
    --    public static String getCaptivePortalServerUrl(Context context) {
    --        return getCaptivePortalServerUrl(context, false);
    -+    private static String getCaptivePortalFallbackUrl(Context context) {
    -+        return getSetting(context,
    -+                Settings.Global.CAPTIVE_PORTAL_FALLBACK_URL, DEFAULT_FALLBACK_URL);
    -+    }
    -+
    -+    private static String getCaptivePortalUserAgent(Context context) {
    -+        return getSetting(context, Settings.Global.CAPTIVE_PORTAL_USER_AGENT, DEFAULT_USER_AGENT);
    -+    }
    -+
    -+    private static String getSetting(Context context, String symbol, String defaultValue) {
    -+        final String value = Settings.Global.getString(context.getContentResolver(), symbol);
    -+        return value != null ? value : defaultValue;
    -     }
    - 
    -     @VisibleForTesting
    -     protected CaptivePortalProbeResult isCaptivePortal() {
    --        if (!mIsCaptivePortalCheckEnabled) return new CaptivePortalProbeResult(204, null);
    -+        if (!mIsCaptivePortalCheckEnabled) return new CaptivePortalProbeResult(204);
    - 
    --        URL pacUrl = null, httpUrl = null, httpsUrl = null;
    -+        URL pacUrl = null, httpsUrl = null, httpUrl = null, fallbackUrl = null;
    - 
    -         // On networks with a PAC instead of fetching a URL that should result in a 204
    -         // response, we instead simply fetch the PAC script.  This is done for a few reasons:
    -@@ -621,20 +655,17 @@ public class NetworkMonitor extends StateMachine {
    -         //    results for network validation.
    -         final ProxyInfo proxyInfo = mNetworkAgentInfo.linkProperties.getHttpProxy();
    -         if (proxyInfo != null && !Uri.EMPTY.equals(proxyInfo.getPacFileUrl())) {
    --            try {
    --                pacUrl = new URL(proxyInfo.getPacFileUrl().toString());
    --            } catch (MalformedURLException e) {
    --                validationLog("Invalid PAC URL: " + proxyInfo.getPacFileUrl().toString());
    -+            pacUrl = makeURL(proxyInfo.getPacFileUrl().toString());
    -+            if (pacUrl == null) {
    -                 return CaptivePortalProbeResult.FAILED;
    -             }
    -         }
    - 
    -         if (pacUrl == null) {
    --            try {
    --                httpUrl = new URL(getCaptivePortalServerUrl(mContext, false));
    --                httpsUrl = new URL(getCaptivePortalServerUrl(mContext, true));
    --            } catch (MalformedURLException e) {
    --                validationLog("Bad validation URL: " + getCaptivePortalServerUrl(mContext, false));
    -+            httpsUrl = makeURL(getCaptivePortalServerHttpsUrl(mContext));
    -+            httpUrl = makeURL(getCaptivePortalServerHttpUrl(mContext));
    -+            fallbackUrl = makeURL(getCaptivePortalFallbackUrl(mContext));
    -+            if (httpUrl == null || httpsUrl == null) {
    -                 return CaptivePortalProbeResult.FAILED;
    -             }
    -         }
    -@@ -680,7 +711,7 @@ public class NetworkMonitor extends StateMachine {
    -         if (pacUrl != null) {
    -             result = sendHttpProbe(pacUrl, ValidationProbeEvent.PROBE_PAC);
    -         } else if (mUseHttps) {
    --            result = sendParallelHttpProbes(httpsUrl, httpUrl);
    -+            result = sendParallelHttpProbes(httpsUrl, httpUrl, fallbackUrl);
    -         } else {
    -             result = sendHttpProbe(httpUrl, ValidationProbeEvent.PROBE_HTTP);
    -         }
    -@@ -710,6 +741,10 @@ public class NetworkMonitor extends StateMachine {
    -             urlConnection.setConnectTimeout(SOCKET_TIMEOUT_MS);
    -             urlConnection.setReadTimeout(SOCKET_TIMEOUT_MS);
    -             urlConnection.setUseCaches(false);
    -+            final String userAgent = getCaptivePortalUserAgent(mContext);
    -+            if (userAgent != null) {
    -+               urlConnection.setRequestProperty("User-Agent", userAgent);
    -+            }
    - 
    -             // Time how long it takes to get a response to our request
    -             long requestTimestamp = SystemClock.elapsedRealtime();
    -@@ -755,28 +790,24 @@ public class NetworkMonitor extends StateMachine {
    -             }
    -         }
    -         logValidationProbe(probeTimer.stop(), probeType, httpResponseCode);
    --        return new CaptivePortalProbeResult(httpResponseCode, redirectUrl);
    -+        return new CaptivePortalProbeResult(httpResponseCode, redirectUrl, url.toString());
    -     }
    - 
    --    private CaptivePortalProbeResult sendParallelHttpProbes(URL httpsUrl, URL httpUrl) {
    --        // Number of probes to wait for. We might wait for all of them, but we might also return if
    --        // only one of them has replied. For example, we immediately return if the HTTP probe finds
    --        // a captive portal, even if the HTTPS probe is timing out.
    -+    private CaptivePortalProbeResult sendParallelHttpProbes(
    -+            URL httpsUrl, URL httpUrl, URL fallbackUrl) {
    -+        // Number of probes to wait for. If a probe completes with a conclusive answer
    -+        // it shortcuts the latch immediately by forcing the count to 0.
    -         final CountDownLatch latch = new CountDownLatch(2);
    - 
    --        // Which probe result we're going to use. This doesn't need to be atomic, but it does need
    --        // to be final because otherwise we can't set it from the ProbeThreads.
    --        final AtomicReference<CaptivePortalProbeResult> finalResult = new AtomicReference<>();
    --
    -         final class ProbeThread extends Thread {
    -             private final boolean mIsHttps;
    --            private volatile CaptivePortalProbeResult mResult;
    -+            private volatile CaptivePortalProbeResult mResult = CaptivePortalProbeResult.FAILED;
    - 
    -             public ProbeThread(boolean isHttps) {
    -                 mIsHttps = isHttps;
    -             }
    - 
    --            public CaptivePortalProbeResult getResult() {
    -+            public CaptivePortalProbeResult result() {
    -                 return mResult;
    -             }
    - 
    -@@ -788,32 +819,66 @@ public class NetworkMonitor extends StateMachine {
    -                     mResult = sendHttpProbe(httpUrl, ValidationProbeEvent.PROBE_HTTP);
    -                 }
    -                 if ((mIsHttps && mResult.isSuccessful()) || (!mIsHttps && mResult.isPortal())) {
    --                    // HTTPS succeeded, or HTTP found a portal. Don't wait for the other probe.
    --                    finalResult.compareAndSet(null, mResult);
    --                    latch.countDown();
    -+                    // Stop waiting immediately if https succeeds or if http finds a portal.
    -+                    while (latch.getCount() > 0) {
    -+                        latch.countDown();
    -+                    }
    -                 }
    --                // Signal that one probe has completed. If we've already made a decision, or if this
    --                // is the second probe, the latch will be at zero and we'll return a result.
    -+                // Signal this probe has completed.
    -                 latch.countDown();
    -             }
    -         }
    - 
    --        ProbeThread httpsProbe = new ProbeThread(true);
    --        ProbeThread httpProbe = new ProbeThread(false);
    --        httpsProbe.start();
    --        httpProbe.start();
    -+        final ProbeThread httpsProbe = new ProbeThread(true);
    -+        final ProbeThread httpProbe = new ProbeThread(false);
    - 
    -         try {
    --            latch.await();
    -+            httpsProbe.start();
    -+            httpProbe.start();
    -+            latch.await(PROBE_TIMEOUT_MS, TimeUnit.MILLISECONDS);
    -         } catch (InterruptedException e) {
    --            validationLog("Error: probe wait interrupted!");
    -+            validationLog("Error: probes wait interrupted!");
    -             return CaptivePortalProbeResult.FAILED;
    -         }
    - 
    --        // If there was no deciding probe, that means that both probes completed. Return HTTPS.
    --        finalResult.compareAndSet(null, httpsProbe.getResult());
    -+        final CaptivePortalProbeResult httpsResult = httpsProbe.result();
    -+        final CaptivePortalProbeResult httpResult = httpProbe.result();
    -+
    -+        // Look for a conclusive probe result first.
    -+        if (httpResult.isPortal()) {
    -+            return httpResult;
    -+        }
    -+        // httpsResult.isPortal() is not expected, but check it nonetheless.
    -+        if (httpsResult.isPortal() || httpsResult.isSuccessful()) {
    -+            return httpsResult;
    -+        }
    -+        // If a fallback url is specified, use a fallback probe to try again portal detection.
    -+        if (fallbackUrl != null) {
    -+            CaptivePortalProbeResult result =
    -+                    sendHttpProbe(fallbackUrl, ValidationProbeEvent.PROBE_FALLBACK);
    -+            if (result.isPortal()) {
    -+                return result;
    -+            }
    -+        }
    -+        // Otherwise wait until https probe completes and use its result.
    -+        try {
    -+            httpsProbe.join();
    -+        } catch (InterruptedException e) {
    -+            validationLog("Error: https probe wait interrupted!");
    -+            return CaptivePortalProbeResult.FAILED;
    -+        }
    -+        return httpsProbe.result();
    -+    }
    - 
    --        return finalResult.get();
    -+    private URL makeURL(String url) {
    -+        if (url != null) {
    -+            try {
    -+                return new URL(url);
    -+            } catch (MalformedURLException e) {
    -+                validationLog("Bad URL: " + url);
    -+            }
    -+        }
    -+        return null;
    -     }
    - 
    -     /**
    -diff --git a/services/core/java/com/android/server/connectivity/Tethering.java b/services/core/java/com/android/server/connectivity/Tethering.java
    -index 927f8f9..da9c547 100644
    ---- a/services/core/java/com/android/server/connectivity/Tethering.java
    -+++ b/services/core/java/com/android/server/connectivity/Tethering.java
    -@@ -33,6 +33,7 @@ import android.content.res.Resources;
    - import android.hardware.usb.UsbManager;
    - import android.net.ConnectivityManager;
    - import android.net.ConnectivityManager.NetworkCallback;
    -+import android.net.INetworkPolicyManager;
    - import android.net.INetworkStatsService;
    - import android.net.LinkProperties;
    - import android.net.Network;
    -@@ -49,6 +50,7 @@ import android.os.INetworkManagementService;
    - import android.os.Looper;
    - import android.os.Message;
    - import android.os.Parcel;
    -+import android.os.RemoteException;
    - import android.os.ResultReceiver;
    - import android.os.SystemProperties;
    - import android.os.UserHandle;
    -@@ -123,6 +125,7 @@ public class Tethering extends BaseNetworkObserver implements IControlsTethering
    - 
    -     private final INetworkManagementService mNMService;
    -     private final INetworkStatsService mStatsService;
    -+    private final INetworkPolicyManager mPolicyManager;
    -     private final Looper mLooper;
    - 
    -     private static class TetherState {
    -@@ -177,10 +180,11 @@ public class Tethering extends BaseNetworkObserver implements IControlsTethering
    -     private boolean mWifiTetherRequested;
    - 
    -     public Tethering(Context context, INetworkManagementService nmService,
    --            INetworkStatsService statsService) {
    -+            INetworkStatsService statsService, INetworkPolicyManager policyManager) {
    -         mContext = context;
    -         mNMService = nmService;
    -         mStatsService = statsService;
    -+        mPolicyManager = policyManager;
    - 
    -         mPublicSync = new Object();
    - 
    -@@ -401,11 +405,13 @@ public class Tethering extends BaseNetworkObserver implements IControlsTethering
    -         // Check carrier config for entitlement checks
    -         final CarrierConfigManager configManager = (CarrierConfigManager) mContext
    -              .getSystemService(Context.CARRIER_CONFIG_SERVICE);
    --        boolean isEntitlementCheckRequired = configManager.getConfig().getBoolean(
    --             CarrierConfigManager.KEY_REQUIRE_ENTITLEMENT_CHECKS_BOOL);
    --
    --        if (!isEntitlementCheckRequired) {
    --            return false;
    -+        if (configManager != null && configManager.getConfig() != null) {
    -+            // we do have a CarrierConfigManager and it has a config.
    -+            boolean isEntitlementCheckRequired = configManager.getConfig().getBoolean(
    -+                    CarrierConfigManager.KEY_REQUIRE_ENTITLEMENT_CHECKS_BOOL);
    -+            if (!isEntitlementCheckRequired) {
    -+                return false;
    -+            }
    -         }
    -         return (provisionApp.length == 2);
    -     }
    -@@ -622,12 +628,9 @@ public class Tethering extends BaseNetworkObserver implements IControlsTethering
    -     }
    - 
    -     public void untetherAll() {
    --        synchronized (mPublicSync) {
    --            if (DBG) Log.d(TAG, "Untethering " + mTetherStates.keySet());
    --            for (int i = 0; i < mTetherStates.size(); i++) {
    --                untether(mTetherStates.keyAt(i));
    --            }
    --        }
    -+        stopTethering(ConnectivityManager.TETHERING_WIFI);
    -+        stopTethering(ConnectivityManager.TETHERING_USB);
    -+        stopTethering(ConnectivityManager.TETHERING_BLUETOOTH);
    -     }
    - 
    -     public int getLastTetherError(String iface) {
    -@@ -1908,6 +1911,15 @@ public class Tethering extends BaseNetworkObserver implements IControlsTethering
    -                     " with error " + error);
    -         }
    - 
    -+        try {
    -+            // Notify that we're tethering (or not) this interface.
    -+            // This is how data saver for instance knows if the user explicitly
    -+            // turned on tethering (thus keeping us from being in data saver mode).
    -+            mPolicyManager.onTetheringChanged(iface, state == IControlsTethering.STATE_TETHERED);
    -+        } catch (RemoteException e) {
    -+            // Not really very much we can do here.
    -+        }
    -+
    -         switch (state) {
    -             case IControlsTethering.STATE_UNAVAILABLE:
    -             case IControlsTethering.STATE_AVAILABLE:
    -diff --git a/services/core/java/com/android/server/connectivity/tethering/IPv6TetheringInterfaceServices.java b/services/core/java/com/android/server/connectivity/tethering/IPv6TetheringInterfaceServices.java
    -index 7525f30..c2c1a8c 100644
    ---- a/services/core/java/com/android/server/connectivity/tethering/IPv6TetheringInterfaceServices.java
    -+++ b/services/core/java/com/android/server/connectivity/tethering/IPv6TetheringInterfaceServices.java
    -@@ -25,6 +25,7 @@ import android.net.NetworkState;
    - import android.net.RouteInfo;
    - import android.net.ip.RouterAdvertisementDaemon;
    - import android.net.ip.RouterAdvertisementDaemon.RaParams;
    -+import android.net.util.NetdService;
    - import android.os.INetworkManagementService;
    - import android.os.ServiceSpecificException;
    - import android.os.RemoteException;
    -@@ -193,7 +194,7 @@ class IPv6TetheringInterfaceServices {
    - 
    -     private void configureLocalDns(
    -             HashSet<Inet6Address> deprecatedDnses, HashSet<Inet6Address> newDnses) {
    --        INetd netd = getNetdServiceOrNull();
    -+        final INetd netd = NetdService.getInstance();
    -         if (netd == null) {
    -             if (newDnses != null) newDnses.clear();
    -             Log.e(TAG, "No netd service instance available; not setting local IPv6 addresses");
    -@@ -265,18 +266,6 @@ class IPv6TetheringInterfaceServices {
    -         return localRoutes;
    -     }
    - 
    --    private INetd getNetdServiceOrNull() {
    --        if (mNMService != null) {
    --            try {
    --                return mNMService.getNetdService();
    --            } catch (RemoteException ignored) {
    --                // This blocks until netd can be reached, but it can return
    --                // null during a netd crash.
    --            }
    --        }
    --        return null;
    --    }
    --
    -     // Given a prefix like 2001:db8::/64 return 2001:db8::1.
    -     private static Inet6Address getLocalDnsIpFor(IpPrefix localPrefix) {
    -         final byte[] dnsBytes = localPrefix.getRawAddress();
    -diff --git a/services/core/java/com/android/server/content/ContentService.java b/services/core/java/com/android/server/content/ContentService.java
    -index 01b2393..0727629 100644
    ---- a/services/core/java/com/android/server/content/ContentService.java
    -+++ b/services/core/java/com/android/server/content/ContentService.java
    -@@ -482,8 +482,7 @@ public final class ContentService extends IContentService.Stub {
    -             SyncManager syncManager = getSyncManager();
    -             if (syncManager != null) {
    -                 syncManager.scheduleSync(account, userId, uId, authority, extras,
    --                        0 /* no delay */, 0 /* no delay */,
    --                        false /* onlyThoseWithUnkownSyncableState */);
    -+                        SyncStorageEngine.AuthorityInfo.UNDEFINED);
    -             }
    -         } finally {
    -             restoreCallingIdentity(identityToken);
    -@@ -547,12 +546,9 @@ public final class ContentService extends IContentService.Stub {
    -                 getSyncManager().updateOrAddPeriodicSync(info, runAtTime,
    -                         flextime, extras);
    -             } else {
    --                long beforeRuntimeMillis = (flextime) * 1000;
    --                long runtimeMillis = runAtTime * 1000;
    -                 syncManager.scheduleSync(
    -                         request.getAccount(), userId, callerUid, request.getProvider(), extras,
    --                        beforeRuntimeMillis, runtimeMillis,
    --                        false /* onlyThoseWithUnknownSyncableState */);
    -+                        SyncStorageEngine.AuthorityInfo.UNDEFINED);
    -             }
    -         } finally {
    -             restoreCallingIdentity(identityToken);
    -@@ -841,8 +837,8 @@ public final class ContentService extends IContentService.Stub {
    -         try {
    -             SyncManager syncManager = getSyncManager();
    -             if (syncManager != null) {
    --                return syncManager.getIsSyncable(
    --                        account, userId, providerName);
    -+                return syncManager.computeSyncable(
    -+                        account, userId, providerName, false);
    -             }
    -         } finally {
    -             restoreCallingIdentity(identityToken);
    -@@ -858,6 +854,8 @@ public final class ContentService extends IContentService.Stub {
    -         mContext.enforceCallingOrSelfPermission(Manifest.permission.WRITE_SYNC_SETTINGS,
    -                 "no permission to write the sync settings");
    - 
    -+        syncable = normalizeSyncable(syncable);
    -+
    -         int userId = UserHandle.getCallingUserId();
    -         long identityToken = clearCallingIdentity();
    -         try {
    -@@ -1160,6 +1158,15 @@ public final class ContentService extends IContentService.Stub {
    -         }
    -     }
    - 
    -+    private static int normalizeSyncable(int syncable) {
    -+        if (syncable > 0) {
    -+            return SyncStorageEngine.AuthorityInfo.SYNCABLE;
    -+        } else if (syncable == 0) {
    -+            return SyncStorageEngine.AuthorityInfo.NOT_SYNCABLE;
    -+        }
    -+        return SyncStorageEngine.AuthorityInfo.UNDEFINED;
    -+    }
    -+
    -     /**
    -      * Hide this class since it is not part of api,
    -      * but current unittest framework requires it to be public
    -diff --git a/services/core/java/com/android/server/content/SyncManager.java b/services/core/java/com/android/server/content/SyncManager.java
    -index 39ddc3a..653d241 100644
    ---- a/services/core/java/com/android/server/content/SyncManager.java
    -+++ b/services/core/java/com/android/server/content/SyncManager.java
    -@@ -19,6 +19,7 @@ package com.android.server.content;
    - import android.accounts.Account;
    - import android.accounts.AccountAndUser;
    - import android.accounts.AccountManager;
    -+import android.accounts.AccountManagerInternal;
    - import android.app.ActivityManager;
    - import android.app.ActivityManagerNative;
    - import android.app.AppGlobals;
    -@@ -47,6 +48,7 @@ import android.content.pm.ApplicationInfo;
    - import android.content.pm.PackageInfo;
    - import android.content.pm.PackageManager;
    - import android.content.pm.PackageManager.NameNotFoundException;
    -+import android.content.pm.PackageManagerInternal;
    - import android.content.pm.ProviderInfo;
    - import android.content.pm.RegisteredServicesCache;
    - import android.content.pm.RegisteredServicesCacheListener;
    -@@ -64,6 +66,7 @@ import android.os.Looper;
    - import android.os.Message;
    - import android.os.Messenger;
    - import android.os.PowerManager;
    -+import android.os.RemoteCallback;
    - import android.os.RemoteException;
    - import android.os.ServiceManager;
    - import android.os.SystemClock;
    -@@ -79,6 +82,7 @@ import android.util.Log;
    - import android.util.Pair;
    - import android.util.Slog;
    - 
    -+import com.android.internal.util.ArrayUtils;
    - import com.android.server.LocalServices;
    - import com.android.server.job.JobSchedulerInternal;
    - import com.google.android.collect.Lists;
    -@@ -133,6 +137,8 @@ import java.util.Set;
    - public class SyncManager {
    -     static final String TAG = "SyncManager";
    - 
    -+    private static final boolean DEBUG_ACCOUNT_ACCESS = false;
    -+
    -     /** Delay a sync due to local changes this long. In milliseconds */
    -     private static final long LOCAL_SYNC_DELAY;
    - 
    -@@ -194,6 +200,11 @@ public class SyncManager {
    -     private static final String HANDLE_SYNC_ALARM_WAKE_LOCK = "SyncManagerHandleSyncAlarm";
    -     private static final String SYNC_LOOP_WAKE_LOCK = "SyncLoopWakeLock";
    - 
    -+
    -+    private static final int SYNC_OP_STATE_VALID = 0;
    -+    private static final int SYNC_OP_STATE_INVALID = 1;
    -+    private static final int SYNC_OP_STATE_INVALID_NO_ACCOUNT_ACCESS = 2;
    -+
    -     private Context mContext;
    - 
    -     private static final AccountAndUser[] INITIAL_ACCOUNTS_ARRAY = new AccountAndUser[0];
    -@@ -310,6 +321,12 @@ public class SyncManager {
    - 
    -     private final UserManager mUserManager;
    - 
    -+    private final AccountManager mAccountManager;
    -+
    -+    private final AccountManagerInternal mAccountManagerInternal;
    -+
    -+    private final PackageManagerInternal mPackageManagerInternal;
    -+
    -     private List<UserInfo> getAllUsers() {
    -         return mUserManager.getUsers();
    -     }
    -@@ -490,9 +507,7 @@ public class SyncManager {
    -             @Override
    -             public void onSyncRequest(SyncStorageEngine.EndPoint info, int reason, Bundle extras) {
    -                 scheduleSync(info.account, info.userId, reason, info.provider, extras,
    --                        0 /* no flexMillis */,
    --                        0 /* run immediately */,
    --                        false);
    -+                        AuthorityInfo.UNDEFINED);
    -             }
    -         });
    - 
    -@@ -522,8 +537,7 @@ public class SyncManager {
    -                 if (!removed) {
    -                     scheduleSync(null, UserHandle.USER_ALL,
    -                             SyncOperation.REASON_SERVICE_CHANGED,
    --                            type.authority, null, 0 /* no delay */, 0 /* no delay */,
    --                            false /* onlyThoseWithUnkownSyncableState */);
    -+                            type.authority, null, AuthorityInfo.UNDEFINED);
    -                 }
    -             }
    -         }, mSyncHandler);
    -@@ -562,6 +576,19 @@ public class SyncManager {
    -         }
    -         mPowerManager = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
    -         mUserManager = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
    -+        mAccountManager = (AccountManager) mContext.getSystemService(Context.ACCOUNT_SERVICE);
    -+        mAccountManagerInternal = LocalServices.getService(AccountManagerInternal.class);
    -+        mPackageManagerInternal = LocalServices.getService(PackageManagerInternal.class);
    -+
    -+        mAccountManagerInternal.addOnAppPermissionChangeListener((Account account, int uid) -> {
    -+            // If the UID gained access to the account kick-off syncs lacking account access
    -+            if (mAccountManagerInternal.hasAccountAccess(account, uid)) {
    -+                scheduleSync(account, UserHandle.getUserId(uid),
    -+                        SyncOperation.REASON_ACCOUNTS_UPDATED,
    -+                        null, null, AuthorityInfo.SYNCABLE_NO_ACCOUNT_ACCESS);
    -+            }
    -+        });
    -+
    -         mBatteryStats = IBatteryStats.Stub.asInterface(ServiceManager.getService(
    -                 BatteryStats.SERVICE_NAME));
    - 
    -@@ -631,6 +658,37 @@ public class SyncManager {
    -                 mContext.startService(startServiceIntent);
    -             }
    -         });
    -+
    -+        // Sync adapters were able to access the synced account without the accounts
    -+        // permission which circumvents our permission model. Therefore, we require
    -+        // sync adapters that don't have access to the account to get user consent.
    -+        // This can be noisy, therefore we will white-list sync adapters installed
    -+        // before we started checking for account access because they already know
    -+        // the account (they run before) which is the genie is out of the bottle.
    -+        whiteListExistingSyncAdaptersIfNeeded();
    -+    }
    -+
    -+    private void whiteListExistingSyncAdaptersIfNeeded() {
    -+        if (!mSyncStorageEngine.shouldGrantSyncAdaptersAccountAccess()) {
    -+            return;
    -+        }
    -+        List<UserInfo> users = mUserManager.getUsers(true);
    -+        final int userCount = users.size();
    -+        for (int i = 0; i < userCount; i++) {
    -+            UserHandle userHandle = users.get(i).getUserHandle();
    -+            final int userId = userHandle.getIdentifier();
    -+            for (RegisteredServicesCache.ServiceInfo<SyncAdapterType> service
    -+                    : mSyncAdapters.getAllServices(userId)) {
    -+                String packageName = service.componentName.getPackageName();
    -+                for (Account account : mAccountManager.getAccountsByTypeAsUser(
    -+                        service.type.accountType, userHandle)) {
    -+                    if (!canAccessAccount(account, packageName, userId)) {
    -+                        mAccountManager.updateAppPermission(account,
    -+                                AccountManager.ACCOUNT_ACCESS_TOKEN_TYPE, service.uid, true);
    -+                    }
    -+                }
    -+            }
    -+        }
    -     }
    - 
    -     private boolean isDeviceProvisioned() {
    -@@ -655,7 +713,7 @@ public class SyncManager {
    -         return mSyncStorageEngine;
    -     }
    - 
    --    public int getIsSyncable(Account account, int userId, String providerName) {
    -+    private int getIsSyncable(Account account, int userId, String providerName) {
    -         int isSyncable = mSyncStorageEngine.getIsSyncable(account, userId, providerName);
    -         UserInfo userInfo = UserManager.get(mContext).getUserInfo(userId);
    - 
    -@@ -666,22 +724,22 @@ public class SyncManager {
    -         RegisteredServicesCache.ServiceInfo<SyncAdapterType> syncAdapterInfo =
    -                 mSyncAdapters.getServiceInfo(
    -                         SyncAdapterType.newKey(providerName, account.type), userId);
    --        if (syncAdapterInfo == null) return isSyncable;
    -+        if (syncAdapterInfo == null) return AuthorityInfo.NOT_SYNCABLE;
    - 
    -         PackageInfo pInfo = null;
    -         try {
    -             pInfo = AppGlobals.getPackageManager().getPackageInfo(
    -                     syncAdapterInfo.componentName.getPackageName(), 0, userId);
    --            if (pInfo == null) return isSyncable;
    -+            if (pInfo == null) return AuthorityInfo.NOT_SYNCABLE;
    -         } catch (RemoteException re) {
    -             // Shouldn't happen.
    --            return isSyncable;
    -+            return AuthorityInfo.NOT_SYNCABLE;
    -         }
    -         if (pInfo.restrictedAccountType != null
    -                 && pInfo.restrictedAccountType.equals(account.type)) {
    -             return isSyncable;
    -         } else {
    --            return 0;
    -+            return AuthorityInfo.NOT_SYNCABLE;
    -         }
    -     }
    - 
    -@@ -733,13 +791,21 @@ public class SyncManager {
    -      * @param extras a Map of SyncAdapter-specific information to control
    -      *          syncs of a specific provider. Can be null. Is ignored
    -      *          if the url is null.
    --     * @param beforeRuntimeMillis milliseconds before runtimeMillis that this sync can run.
    --     * @param runtimeMillis maximum milliseconds in the future to wait before performing sync.
    --     * @param onlyThoseWithUnkownSyncableState Only sync authorities that have unknown state.
    -+     * @param targetSyncState Only sync authorities that have the specified sync state.
    -+     *           Use {@link AuthorityInfo#UNDEFINED} to sync all authorities.
    -      */
    -     public void scheduleSync(Account requestedAccount, int userId, int reason,
    --            String requestedAuthority, Bundle extras, long beforeRuntimeMillis,
    --            long runtimeMillis, boolean onlyThoseWithUnkownSyncableState) {
    -+                             String requestedAuthority, Bundle extras, int targetSyncState) {
    -+        scheduleSync(requestedAccount, userId, reason, requestedAuthority, extras, targetSyncState,
    -+                0 /* min delay */);
    -+    }
    -+
    -+    /**
    -+     * @param minDelayMillis The sync can't land before this delay expires.
    -+     */
    -+    private void scheduleSync(Account requestedAccount, int userId, int reason,
    -+                             String requestedAuthority, Bundle extras, int targetSyncState,
    -+                             final long minDelayMillis) {
    -         final boolean isLoggable = Log.isLoggable(TAG, Log.VERBOSE);
    -         if (extras == null) {
    -             extras = new Bundle();
    -@@ -749,17 +815,27 @@ public class SyncManager {
    -                     + requestedAuthority);
    -         }
    - 
    --        AccountAndUser[] accounts;
    --        if (requestedAccount != null && userId != UserHandle.USER_ALL) {
    --            accounts = new AccountAndUser[] { new AccountAndUser(requestedAccount, userId) };
    -+        AccountAndUser[] accounts = null;
    -+        if (requestedAccount != null) {
    -+            if (userId != UserHandle.USER_ALL) {
    -+                accounts = new AccountAndUser[]{new AccountAndUser(requestedAccount, userId)};
    -+            } else {
    -+                for (AccountAndUser runningAccount : mRunningAccounts) {
    -+                    if (requestedAccount.equals(runningAccount.account)) {
    -+                        accounts = ArrayUtils.appendElement(AccountAndUser.class,
    -+                                accounts, runningAccount);
    -+                    }
    -+                }
    -+            }
    -         } else {
    -             accounts = mRunningAccounts;
    --            if (accounts.length == 0) {
    --                if (isLoggable) {
    --                    Slog.v(TAG, "scheduleSync: no accounts configured, dropping");
    --                }
    --                return;
    -+        }
    -+
    -+        if (ArrayUtils.isEmpty(accounts)) {
    -+            if (isLoggable) {
    -+                Slog.v(TAG, "scheduleSync: no accounts configured, dropping");
    -             }
    -+            return;
    -         }
    - 
    -         final boolean uploadOnly = extras.getBoolean(ContentResolver.SYNC_EXTRAS_UPLOAD, false);
    -@@ -808,29 +884,45 @@ public class SyncManager {
    -             }
    - 
    -             for (String authority : syncableAuthorities) {
    --                int isSyncable = getIsSyncable(account.account, account.userId,
    --                        authority);
    -+                int isSyncable = computeSyncable(account.account, account.userId, authority);
    -+
    -                 if (isSyncable == AuthorityInfo.NOT_SYNCABLE) {
    -                     continue;
    -                 }
    --                final RegisteredServicesCache.ServiceInfo<SyncAdapterType> syncAdapterInfo;
    --                syncAdapterInfo = mSyncAdapters.getServiceInfo(
    --                        SyncAdapterType.newKey(authority, account.account.type), account.userId);
    -+
    -+                final RegisteredServicesCache.ServiceInfo<SyncAdapterType> syncAdapterInfo =
    -+                        mSyncAdapters.getServiceInfo(SyncAdapterType.newKey(authority,
    -+                                account.account.type), account.userId);
    -                 if (syncAdapterInfo == null) {
    -                     continue;
    -                 }
    -+
    -                 final int owningUid = syncAdapterInfo.uid;
    --                final String owningPackage = syncAdapterInfo.componentName.getPackageName();
    --                try {
    --                    if (ActivityManagerNative.getDefault().getAppStartMode(owningUid,
    --                            owningPackage) == ActivityManager.APP_START_MODE_DISABLED) {
    --                        Slog.w(TAG, "Not scheduling job " + syncAdapterInfo.uid + ":"
    --                                + syncAdapterInfo.componentName
    --                                + " -- package not allowed to start");
    -+
    -+                if (isSyncable == AuthorityInfo.SYNCABLE_NO_ACCOUNT_ACCESS) {
    -+                    if (isLoggable) {
    -+                        Slog.v(TAG, "    Not scheduling sync operation: "
    -+                                + "isSyncable == SYNCABLE_NO_ACCOUNT_ACCESS");
    -+                    }
    -+                    Bundle finalExtras = new Bundle(extras);
    -+                    String packageName = syncAdapterInfo.componentName.getPackageName();
    -+                    // If the app did not run and has no account access, done
    -+                    if (!mPackageManagerInternal.wasPackageEverLaunched(packageName, userId)) {
    -                         continue;
    -                     }
    --                } catch (RemoteException e) {
    -+                    mAccountManagerInternal.requestAccountAccess(account.account,
    -+                            packageName, userId,
    -+                            new RemoteCallback((Bundle result) -> {
    -+                                if (result != null
    -+                                        && result.getBoolean(AccountManager.KEY_BOOLEAN_RESULT)) {
    -+                                    scheduleSync(account.account, userId, reason, authority,
    -+                                            finalExtras, targetSyncState, minDelayMillis);
    -+                                }
    -+                            }
    -+                        ));
    -+                    continue;
    -                 }
    -+
    -                 final boolean allowParallelSyncs = syncAdapterInfo.type.allowParallelSyncs();
    -                 final boolean isAlwaysSyncable = syncAdapterInfo.type.isAlwaysSyncable();
    -                 if (isSyncable < 0 && isAlwaysSyncable) {
    -@@ -838,9 +930,11 @@ public class SyncManager {
    -                             account.account, account.userId, authority, AuthorityInfo.SYNCABLE);
    -                     isSyncable = AuthorityInfo.SYNCABLE;
    -                 }
    --                if (onlyThoseWithUnkownSyncableState && isSyncable >= 0) {
    -+
    -+                if (targetSyncState != AuthorityInfo.UNDEFINED && targetSyncState != isSyncable) {
    -                     continue;
    -                 }
    -+
    -                 if (!syncAdapterInfo.type.supportsUploading() && uploadOnly) {
    -                     continue;
    -                 }
    -@@ -863,7 +957,10 @@ public class SyncManager {
    -                                 account.account, authority, account.userId);
    -                 long delayUntil =
    -                         mSyncStorageEngine.getDelayUntilTime(info);
    --                if (isSyncable < 0) {
    -+
    -+                final String owningPackage = syncAdapterInfo.componentName.getPackageName();
    -+
    -+                if (isSyncable == AuthorityInfo.NOT_INITIALIZED) {
    -                     // Initialisation sync.
    -                     Bundle newExtras = new Bundle();
    -                     newExtras.putBoolean(ContentResolver.SYNC_EXTRAS_INITIALIZE, true);
    -@@ -880,15 +977,14 @@ public class SyncManager {
    -                     postScheduleSyncMessage(
    -                             new SyncOperation(account.account, account.userId,
    -                                     owningUid, owningPackage, reason, source,
    --                                    authority, newExtras, allowParallelSyncs)
    -+                                    authority, newExtras, allowParallelSyncs),
    -+                            minDelayMillis
    -                     );
    --                }
    --                if (!onlyThoseWithUnkownSyncableState) {
    -+                } else if (targetSyncState == AuthorityInfo.UNDEFINED
    -+                        || targetSyncState == isSyncable) {
    -                     if (isLoggable) {
    -                         Slog.v(TAG, "scheduleSync:"
    -                                 + " delay until " + delayUntil
    --                                + " run by " + runtimeMillis
    --                                + " flexMillis " + beforeRuntimeMillis
    -                                 + ", source " + source
    -                                 + ", account " + account
    -                                 + ", authority " + authority
    -@@ -897,13 +993,69 @@ public class SyncManager {
    -                     postScheduleSyncMessage(
    -                             new SyncOperation(account.account, account.userId,
    -                                     owningUid, owningPackage, reason, source,
    --                                    authority, extras, allowParallelSyncs)
    -+                                    authority, extras, allowParallelSyncs),
    -+                            minDelayMillis
    -                     );
    -                 }
    -             }
    -         }
    -     }
    - 
    -+    private int computeSyncable(Account account, int userId, String authority) {
    -+        return computeSyncable(account, userId, authority, true);
    -+    }
    -+
    -+    public int computeSyncable(Account account, int userId, String authority,
    -+            boolean checkAccountAccess) {
    -+        final int status = getIsSyncable(account, userId, authority);
    -+        if (status == AuthorityInfo.NOT_SYNCABLE) {
    -+            return AuthorityInfo.NOT_SYNCABLE;
    -+        }
    -+        final SyncAdapterType type = SyncAdapterType.newKey(authority, account.type);
    -+        final RegisteredServicesCache.ServiceInfo<SyncAdapterType> syncAdapterInfo =
    -+                mSyncAdapters.getServiceInfo(type, userId);
    -+        if (syncAdapterInfo == null) {
    -+            return AuthorityInfo.NOT_SYNCABLE;
    -+        }
    -+        final int owningUid = syncAdapterInfo.uid;
    -+        final String owningPackage = syncAdapterInfo.componentName.getPackageName();
    -+        try {
    -+            if (ActivityManagerNative.getDefault().getAppStartMode(owningUid,
    -+                    owningPackage) == ActivityManager.APP_START_MODE_DISABLED) {
    -+                Slog.w(TAG, "Not scheduling job " + syncAdapterInfo.uid + ":"
    -+                        + syncAdapterInfo.componentName
    -+                        + " -- package not allowed to start");
    -+                return AuthorityInfo.NOT_SYNCABLE;
    -+            }
    -+        } catch (RemoteException e) {
    -+            /* ignore - local call */
    -+        }
    -+        if (checkAccountAccess && !canAccessAccount(account, owningPackage, owningUid)) {
    -+            Log.w(TAG, "Access to " + account + " denied for package "
    -+                    + owningPackage + " in UID " + syncAdapterInfo.uid);
    -+            return AuthorityInfo.SYNCABLE_NO_ACCOUNT_ACCESS;
    -+        }
    -+
    -+        return status;
    -+    }
    -+
    -+    private boolean canAccessAccount(Account account, String packageName, int uid) {
    -+        if (mAccountManager.hasAccountAccess(account, packageName,
    -+                UserHandle.getUserHandleForUid(uid))) {
    -+            return true;
    -+        }
    -+        // We relax the account access rule to also include the system apps as
    -+        // they are trusted and we want to minimize the cases where the user
    -+        // involvement is required to grant access to the synced account.
    -+        try {
    -+            mContext.getPackageManager().getApplicationInfoAsUser(packageName,
    -+                    PackageManager.MATCH_SYSTEM_ONLY, UserHandle.getUserId(uid));
    -+            return true;
    -+        } catch (NameNotFoundException e) {
    -+            return false;
    -+        }
    -+    }
    -+
    -     private void removeSyncsForAuthority(EndPoint info) {
    -         verifyJobScheduler();
    -         List<SyncOperation> ops = getAllPendingSyncs();
    -@@ -953,16 +1105,14 @@ public class SyncManager {
    -     }
    - 
    -     /**
    --     * Schedule sync based on local changes to a provider. Occurs within interval
    --     * [LOCAL_SYNC_DELAY, 2*LOCAL_SYNC_DELAY].
    -+     * Schedule sync based on local changes to a provider. We wait for at least LOCAL_SYNC_DELAY
    -+     * ms to batch syncs.
    -      */
    -     public void scheduleLocalSync(Account account, int userId, int reason, String authority) {
    -         final Bundle extras = new Bundle();
    -         extras.putBoolean(ContentResolver.SYNC_EXTRAS_UPLOAD, true);
    -         scheduleSync(account, userId, reason, authority, extras,
    --                LOCAL_SYNC_DELAY /* earliest run time */,
    --                2 * LOCAL_SYNC_DELAY /* latest sync time. */,
    --                false /* onlyThoseWithUnkownSyncableState */);
    -+                AuthorityInfo.UNDEFINED, LOCAL_SYNC_DELAY);
    -     }
    - 
    -     public SyncAdapterType[] getSyncAdapterTypes(int userId) {
    -@@ -1019,9 +1169,10 @@ public class SyncManager {
    -         mSyncHandler.sendMessageDelayed(monitorMessage, SYNC_MONITOR_WINDOW_LENGTH_MILLIS);
    -     }
    - 
    --    private void postScheduleSyncMessage(SyncOperation syncOperation) {
    --        mSyncHandler.obtainMessage(mSyncHandler.MESSAGE_SCHEDULE_SYNC, syncOperation)
    --                .sendToTarget();
    -+    private void postScheduleSyncMessage(SyncOperation syncOperation, long minDelayMillis) {
    -+        ScheduleSyncMessagePayload payload =
    -+                new ScheduleSyncMessagePayload(syncOperation, minDelayMillis);
    -+        mSyncHandler.obtainMessage(mSyncHandler.MESSAGE_SCHEDULE_SYNC, payload).sendToTarget();
    -     }
    - 
    -     /**
    -@@ -1061,6 +1212,16 @@ public class SyncManager {
    -         }
    -     }
    - 
    -+    private static class ScheduleSyncMessagePayload {
    -+        final SyncOperation syncOperation;
    -+        final long minDelayMillis;
    -+
    -+        ScheduleSyncMessagePayload(SyncOperation syncOperation, long minDelayMillis) {
    -+            this.syncOperation = syncOperation;
    -+            this.minDelayMillis = minDelayMillis;
    -+        }
    -+    }
    -+
    -     private void clearBackoffSetting(EndPoint target) {
    -         Pair<Long, Long> backoff = mSyncStorageEngine.getBackoff(target);
    -         if (backoff != null && backoff.first == SyncStorageEngine.NOT_IN_BACKOFF_MODE &&
    -@@ -1129,7 +1290,7 @@ public class SyncManager {
    -             if (!op.isPeriodic && op.target.matchesSpec(target)) {
    -                 count++;
    -                 getJobScheduler().cancel(op.jobId);
    --                postScheduleSyncMessage(op);
    -+                postScheduleSyncMessage(op, 0 /* min delay */);
    -             }
    -         }
    -         if (Log.isLoggable(TAG, Log.VERBOSE)) {
    -@@ -1421,8 +1582,7 @@ public class SyncManager {
    -                 mContext.getOpPackageName());
    -         for (Account account : accounts) {
    -             scheduleSync(account, userId, SyncOperation.REASON_USER_START, null, null,
    --                    0 /* no delay */, 0 /* No flexMillis */,
    --                    true /* onlyThoseWithUnknownSyncableState */);
    -+                    AuthorityInfo.NOT_INITIALIZED);
    -         }
    -     }
    - 
    -@@ -2285,8 +2445,10 @@ public class SyncManager {
    -                 mDataConnectionIsConnected = readDataConnectionState();
    -                 switch (msg.what) {
    -                     case MESSAGE_SCHEDULE_SYNC:
    --                        SyncOperation op = (SyncOperation) msg.obj;
    --                        scheduleSyncOperationH(op);
    -+                        ScheduleSyncMessagePayload syncPayload =
    -+                                (ScheduleSyncMessagePayload) msg.obj;
    -+                        SyncOperation op = syncPayload.syncOperation;
    -+                        scheduleSyncOperationH(op, syncPayload.minDelayMillis);
    -                         break;
    - 
    -                     case MESSAGE_START_SYNC:
    -@@ -2530,13 +2692,18 @@ public class SyncManager {
    -                 }
    -             }
    - 
    --            if (isOperationValid(op)) {
    --                if (!dispatchSyncOperation(op)) {
    -+            final int syncOpState = computeSyncOpState(op);
    -+            switch (syncOpState) {
    -+                case SYNC_OP_STATE_INVALID_NO_ACCOUNT_ACCESS:
    -+                case SYNC_OP_STATE_INVALID: {
    -                     mSyncJobService.callJobFinished(op.jobId, false);
    --                }
    --            } else {
    -+                } return;
    -+            }
    -+
    -+            if (!dispatchSyncOperation(op)) {
    -                 mSyncJobService.callJobFinished(op.jobId, false);
    -             }
    -+
    -             setAuthorityPendingState(op.target);
    -         }
    - 
    -@@ -2596,8 +2763,8 @@ public class SyncManager {
    - 
    -             if (syncTargets != null) {
    -                 scheduleSync(syncTargets.account, syncTargets.userId,
    --                        SyncOperation.REASON_ACCOUNTS_UPDATED, syncTargets.provider, null, 0, 0,
    --                        true);
    -+                        SyncOperation.REASON_ACCOUNTS_UPDATED, syncTargets.provider,
    -+                null, AuthorityInfo.NOT_INITIALIZED);
    -             }
    -         }
    - 
    -@@ -2665,6 +2832,31 @@ public class SyncManager {
    -                     SyncStorageEngine.SOURCE_PERIODIC, extras,
    -                     syncAdapterInfo.type.allowParallelSyncs(), true, SyncOperation.NO_JOB_ID,
    -                     pollFrequencyMillis, flexMillis);
    -+
    -+            final int syncOpState = computeSyncOpState(op);
    -+            switch (syncOpState) {
    -+                case SYNC_OP_STATE_INVALID_NO_ACCOUNT_ACCESS: {
    -+                    String packageName = op.owningPackage;
    -+                    final int userId = UserHandle.getUserId(op.owningUid);
    -+                    // If the app did not run and has no account access, done
    -+                    if (!mPackageManagerInternal.wasPackageEverLaunched(packageName, userId)) {
    -+                        return;
    -+                    }
    -+                    mAccountManagerInternal.requestAccountAccess(op.target.account,
    -+                            packageName, userId, new RemoteCallback((Bundle result) -> {
    -+                                if (result != null
    -+                                        && result.getBoolean(AccountManager.KEY_BOOLEAN_RESULT)) {
    -+                                    updateOrAddPeriodicSync(target, pollFrequency, flex, extras);
    -+                                }
    -+                            }
    -+                        ));
    -+                } return;
    -+
    -+                case SYNC_OP_STATE_INVALID: {
    -+                    return;
    -+                }
    -+            }
    -+
    -             scheduleSyncOperationH(op);
    -             mSyncStorageEngine.reportChange(ContentResolver.SYNC_OBSERVER_TYPE_SETTINGS);
    -         }
    -@@ -2725,29 +2917,38 @@ public class SyncManager {
    -         /**
    -          * Determine if a sync is no longer valid and should be dropped.
    -          */
    --        private boolean isOperationValid(SyncOperation op) {
    -+        private int computeSyncOpState(SyncOperation op) {
    -             final boolean isLoggable = Log.isLoggable(TAG, Log.VERBOSE);
    -             int state;
    -             final EndPoint target = op.target;
    --            boolean syncEnabled = mSyncStorageEngine.getMasterSyncAutomatically(target.userId);
    -+
    -             // Drop the sync if the account of this operation no longer exists.
    -             AccountAndUser[] accounts = mRunningAccounts;
    -             if (!containsAccountAndUser(accounts, target.account, target.userId)) {
    -                 if (isLoggable) {
    -                     Slog.v(TAG, "    Dropping sync operation: account doesn't exist.");
    -                 }
    --                return false;
    -+                return SYNC_OP_STATE_INVALID;
    -             }
    -             // Drop this sync request if it isn't syncable.
    --            state = getIsSyncable(target.account, target.userId, target.provider);
    --            if (state == 0) {
    -+            state = computeSyncable(target.account, target.userId, target.provider);
    -+            if (state == AuthorityInfo.SYNCABLE_NO_ACCOUNT_ACCESS) {
    -                 if (isLoggable) {
    --                    Slog.v(TAG, "    Dropping sync operation: isSyncable == 0.");
    -+                    Slog.v(TAG, "    Dropping sync operation: "
    -+                            + "isSyncable == SYNCABLE_NO_ACCOUNT_ACCESS");
    -                 }
    --                return false;
    -+                return SYNC_OP_STATE_INVALID_NO_ACCOUNT_ACCESS;
    -+            }
    -+            if (state == AuthorityInfo.NOT_SYNCABLE) {
    -+                if (isLoggable) {
    -+                    Slog.v(TAG, "    Dropping sync operation: isSyncable == NOT_SYNCABLE");
    -+                }
    -+                return SYNC_OP_STATE_INVALID;
    -             }
    --            syncEnabled = syncEnabled && mSyncStorageEngine.getSyncAutomatically(
    --                    target.account, target.userId, target.provider);
    -+
    -+            final boolean syncEnabled = mSyncStorageEngine.getMasterSyncAutomatically(target.userId)
    -+                    && mSyncStorageEngine.getSyncAutomatically(target.account,
    -+                            target.userId, target.provider);
    - 
    -             // We ignore system settings that specify the sync is invalid if:
    -             // 1) It's manual - we try it anyway. When/if it fails it will be rescheduled.
    -@@ -2760,9 +2961,9 @@ public class SyncManager {
    -                 if (isLoggable) {
    -                     Slog.v(TAG, "    Dropping sync operation: disallowed by settings/network.");
    -                 }
    --                return false;
    -+                return SYNC_OP_STATE_INVALID;
    -             }
    --            return true;
    -+            return SYNC_OP_STATE_VALID;
    -         }
    - 
    -         private boolean dispatchSyncOperation(SyncOperation op) {
    -@@ -2930,7 +3131,8 @@ public class SyncManager {
    -                         maybeRescheduleSync(syncResult, syncOperation);
    -                     } else {
    -                         // create a normal sync instance that will respect adapter backoffs
    --                        postScheduleSyncMessage(syncOperation.createOneTimeSyncOperation());
    -+                        postScheduleSyncMessage(syncOperation.createOneTimeSyncOperation(),
    -+                                0 /* min delay */);
    -                     }
    -                     historyMessage = ContentResolver.syncErrorToString(
    -                             syncResultToErrorNumber(syncResult));
    -diff --git a/services/core/java/com/android/server/content/SyncStorageEngine.java b/services/core/java/com/android/server/content/SyncStorageEngine.java
    -index bc3fc6a..069ae73 100644
    ---- a/services/core/java/com/android/server/content/SyncStorageEngine.java
    -+++ b/services/core/java/com/android/server/content/SyncStorageEngine.java
    -@@ -137,7 +137,7 @@ public class SyncStorageEngine extends Handler {
    -     private static final boolean SYNC_ENABLED_DEFAULT = false;
    - 
    -     // the version of the accounts xml file format
    --    private static final int ACCOUNTS_VERSION = 2;
    -+    private static final int ACCOUNTS_VERSION = 3;
    - 
    -     private static HashMap<String, String> sAuthorityRenames;
    -     private static PeriodicSyncAddedListener mPeriodicSyncAddedListener;
    -@@ -211,6 +211,12 @@ public class SyncStorageEngine extends Handler {
    - 
    -     public static class AuthorityInfo {
    -         // Legal values of getIsSyncable
    -+
    -+        /**
    -+         * The syncable state is undefined.
    -+         */
    -+        public static final int UNDEFINED = -2;
    -+
    -         /**
    -          * Default state for a newly installed adapter. An uninitialized adapter will receive an
    -          * initialization sync which are governed by a different set of rules to that of regular
    -@@ -234,6 +240,12 @@ public class SyncStorageEngine extends Handler {
    -          */
    -         public static final int SYNCABLE_NOT_INITIALIZED = 2;
    - 
    -+        /**
    -+         * The adapter is syncable but does not have access to the synced account and needs a
    -+         * user access approval.
    -+         */
    -+        public static final int SYNCABLE_NO_ACCOUNT_ACCESS = 3;
    -+
    -         final EndPoint target;
    -         final int ident;
    -         boolean enabled;
    -@@ -402,6 +414,8 @@ public class SyncStorageEngine extends Handler {
    -     private OnSyncRequestListener mSyncRequestListener;
    -     private OnAuthorityRemovedListener mAuthorityRemovedListener;
    - 
    -+    private boolean mGrantSyncAdaptersAccountAccess;
    -+
    -     private SyncStorageEngine(Context context, File dataDir) {
    -         mContext = context;
    -         sSyncStorageEngine = this;
    -@@ -1404,6 +1418,10 @@ public class SyncStorageEngine extends Handler {
    -         }
    -     }
    - 
    -+    public boolean shouldGrantSyncAdaptersAccountAccess() {
    -+        return mGrantSyncAdaptersAccountAccess;
    -+    }
    -+
    -     /**
    -      * public for testing
    -      */
    -@@ -1458,6 +1476,11 @@ public class SyncStorageEngine extends Handler {
    -                 } catch (NumberFormatException e) {
    -                     version = 0;
    -                 }
    -+
    -+                if (version < 3) {
    -+                    mGrantSyncAdaptersAccountAccess = true;
    -+                }
    -+
    -                 String nextIdString = parser.getAttributeValue(null, XML_ATTR_NEXT_AUTHORITY_ID);
    -                 try {
    -                     int id = (nextIdString == null) ? 0 : Integer.parseInt(nextIdString);
    -diff --git a/services/core/java/com/android/server/display/DisplayManagerService.java b/services/core/java/com/android/server/display/DisplayManagerService.java
    -index 0abd2e7..971989b 100644
    ---- a/services/core/java/com/android/server/display/DisplayManagerService.java
    -+++ b/services/core/java/com/android/server/display/DisplayManagerService.java
    -@@ -1402,6 +1402,9 @@ public final class DisplayManagerService extends SystemService {
    -                 throw new IllegalArgumentException("width, height, and densityDpi must be "
    -                         + "greater than 0");
    -             }
    -+            if (surface != null && surface.isSingleBuffered()) {
    -+                throw new IllegalArgumentException("Surface can't be single-buffered");
    -+            }
    - 
    -             if ((flags & DisplayManager.VIRTUAL_DISPLAY_FLAG_PUBLIC) != 0) {
    -                 flags |= DisplayManager.VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR;
    -@@ -1460,6 +1463,9 @@ public final class DisplayManagerService extends SystemService {
    - 
    -         @Override // Binder call
    -         public void setVirtualDisplaySurface(IVirtualDisplayCallback callback, Surface surface) {
    -+            if (surface != null && surface.isSingleBuffered()) {
    -+                throw new IllegalArgumentException("Surface can't be single-buffered");
    -+            }
    -             final long token = Binder.clearCallingIdentity();
    -             try {
    -                 setVirtualDisplaySurfaceInternal(callback.asBinder(), surface);
    -diff --git a/services/core/java/com/android/server/display/NightDisplayService.java b/services/core/java/com/android/server/display/NightDisplayService.java
    -index 07fa2ce..0ec48b9 100644
    ---- a/services/core/java/com/android/server/display/NightDisplayService.java
    -+++ b/services/core/java/com/android/server/display/NightDisplayService.java
    -@@ -33,8 +33,11 @@ import android.net.Uri;
    - import android.opengl.Matrix;
    - import android.os.Handler;
    - import android.os.Looper;
    -+import android.os.RemoteException;
    - import android.os.UserHandle;
    - import android.provider.Settings.Secure;
    -+import android.service.vr.IVrManager;
    -+import android.service.vr.IVrStateCallbacks;
    - import android.util.MathUtils;
    - import android.util.Slog;
    - import android.view.animation.AnimationUtils;
    -@@ -44,7 +47,9 @@ import com.android.server.SystemService;
    - import com.android.server.twilight.TwilightListener;
    - import com.android.server.twilight.TwilightManager;
    - import com.android.server.twilight.TwilightState;
    -+import com.android.server.vr.VrManagerService;
    - 
    -+import java.util.concurrent.atomic.AtomicBoolean;
    - import java.util.Calendar;
    - import java.util.TimeZone;
    - 
    -@@ -83,6 +88,31 @@ public final class NightDisplayService extends SystemService
    -     private static final ColorMatrixEvaluator COLOR_MATRIX_EVALUATOR = new ColorMatrixEvaluator();
    - 
    -     private final Handler mHandler;
    -+    private final AtomicBoolean mIgnoreAllColorMatrixChanges = new AtomicBoolean();
    -+    private final IVrStateCallbacks mVrStateCallbacks = new IVrStateCallbacks.Stub() {
    -+        @Override
    -+        public void onVrStateChanged(final boolean enabled) {
    -+            // Turn off all night mode display stuff while device is in VR mode.
    -+            mIgnoreAllColorMatrixChanges.set(enabled);
    -+            mHandler.post(new Runnable() {
    -+                @Override
    -+                public void run() {
    -+                    // Cancel in-progress animations
    -+                    if (mColorMatrixAnimator != null) {
    -+                        mColorMatrixAnimator.cancel();
    -+                    }
    -+
    -+                    final DisplayTransformManager dtm =
    -+                            getLocalService(DisplayTransformManager.class);
    -+                    if (enabled) {
    -+                        dtm.setColorMatrix(LEVEL_COLOR_MATRIX_NIGHT_DISPLAY, MATRIX_IDENTITY);
    -+                    } else if (mController.isActivated()) {
    -+                        dtm.setColorMatrix(LEVEL_COLOR_MATRIX_NIGHT_DISPLAY, MATRIX_NIGHT);
    -+                    }
    -+                }
    -+            });
    -+        }
    -+    };
    - 
    -     private int mCurrentUser = UserHandle.USER_NULL;
    -     private ContentObserver mUserSetupObserver;
    -@@ -105,7 +135,17 @@ public final class NightDisplayService extends SystemService
    - 
    -     @Override
    -     public void onBootPhase(int phase) {
    --        if (phase == PHASE_BOOT_COMPLETED) {
    -+        if (phase == PHASE_SYSTEM_SERVICES_READY) {
    -+            IVrManager vrManager =
    -+                    (IVrManager) getBinderService(VrManagerService.VR_MANAGER_BINDER_SERVICE);
    -+            if (vrManager != null) {
    -+                try {
    -+                    vrManager.registerListener(mVrStateCallbacks);
    -+                } catch (RemoteException e) {
    -+                    Slog.e(TAG, "Failed to register VR mode state listener: " + e);
    -+                }
    -+            }
    -+        } else if (phase == PHASE_BOOT_COMPLETED) {
    -             mBootCompleted = true;
    - 
    -             // Register listeners now that boot is complete.
    -@@ -182,6 +222,8 @@ public final class NightDisplayService extends SystemService
    -     }
    - 
    -     private void setUp() {
    -+        Slog.d(TAG, "setUp: currentUser=" + mCurrentUser);
    -+
    -         // Create a new controller for the current user and start listening for changes.
    -         mController = new NightDisplayController(getContext(), mCurrentUser);
    -         mController.setListener(this);
    -@@ -196,6 +238,8 @@ public final class NightDisplayService extends SystemService
    -     }
    - 
    -     private void tearDown() {
    -+        Slog.d(TAG, "tearDown: currentUser=" + mCurrentUser);
    -+
    -         if (mController != null) {
    -             mController.setListener(null);
    -             mController = null;
    -@@ -230,6 +274,11 @@ public final class NightDisplayService extends SystemService
    -                 mColorMatrixAnimator.cancel();
    -             }
    - 
    -+            // Don't do any color matrix change animations if we are ignoring them anyway.
    -+            if (mIgnoreAllColorMatrixChanges.get()) {
    -+                return;
    -+            }
    -+
    -             final DisplayTransformManager dtm = getLocalService(DisplayTransformManager.class);
    -             final float[] from = dtm.getColorMatrix(LEVEL_COLOR_MATRIX_NIGHT_DISPLAY);
    -             final float[] to = mIsActivated ? MATRIX_NIGHT : null;
    -@@ -273,6 +322,8 @@ public final class NightDisplayService extends SystemService
    - 
    -     @Override
    -     public void onAutoModeChanged(int autoMode) {
    -+        Slog.d(TAG, "onAutoModeChanged: autoMode=" + autoMode);
    -+
    -         if (mAutoMode != null) {
    -             mAutoMode.onStop();
    -             mAutoMode = null;
    -@@ -291,6 +342,8 @@ public final class NightDisplayService extends SystemService
    - 
    -     @Override
    -     public void onCustomStartTimeChanged(NightDisplayController.LocalTime startTime) {
    -+        Slog.d(TAG, "onCustomStartTimeChanged: startTime=" + startTime);
    -+
    -         if (mAutoMode != null) {
    -             mAutoMode.onCustomStartTimeChanged(startTime);
    -         }
    -@@ -298,6 +351,8 @@ public final class NightDisplayService extends SystemService
    - 
    -     @Override
    -     public void onCustomEndTimeChanged(NightDisplayController.LocalTime endTime) {
    -+        Slog.d(TAG, "onCustomEndTimeChanged: endTime=" + endTime);
    -+
    -         if (mAutoMode != null) {
    -             mAutoMode.onCustomEndTimeChanged(endTime);
    -         }
    -@@ -419,7 +474,7 @@ public final class NightDisplayService extends SystemService
    - 
    -         @Override
    -         public void onAlarm() {
    --            if (DEBUG) Slog.d(TAG, "onAlarm");
    -+            Slog.d(TAG, "onAlarm");
    -             updateActivated();
    -         }
    -     }
    -@@ -477,7 +532,8 @@ public final class NightDisplayService extends SystemService
    - 
    -         @Override
    -         public void onTwilightStateChanged(@Nullable TwilightState state) {
    --            if (DEBUG) Slog.d(TAG, "onTwilightStateChanged");
    -+            Slog.d(TAG, "onTwilightStateChanged: isNight="
    -+                    + (state == null ? null : state.isNight()));
    -             updateActivated(state);
    -         }
    -     }
    -diff --git a/services/core/java/com/android/server/dreams/DreamController.java b/services/core/java/com/android/server/dreams/DreamController.java
    -index a633996..3072f43 100644
    ---- a/services/core/java/com/android/server/dreams/DreamController.java
    -+++ b/services/core/java/com/android/server/dreams/DreamController.java
    -@@ -24,8 +24,11 @@ import android.content.Context;
    - import android.content.Intent;
    - import android.content.ServiceConnection;
    - import android.os.Binder;
    -+import android.os.Bundle;
    - import android.os.Handler;
    - import android.os.IBinder;
    -+import android.os.IRemoteCallback;
    -+import android.os.PowerManager;
    - import android.os.RemoteException;
    - import android.os.IBinder.DeathRecipient;
    - import android.os.SystemClock;
    -@@ -116,19 +119,19 @@ final class DreamController {
    -     }
    - 
    -     public void startDream(Binder token, ComponentName name,
    --            boolean isTest, boolean canDoze, int userId) {
    -+            boolean isTest, boolean canDoze, int userId, PowerManager.WakeLock wakeLock) {
    -         stopDream(true /*immediate*/);
    - 
    -         Trace.traceBegin(Trace.TRACE_TAG_POWER, "startDream");
    -         try {
    --            // Close the notification shade. Don't need to send to all, but better to be explicit.
    -+            // Close the notification shade. No need to send to all, but better to be explicit.
    -             mContext.sendBroadcastAsUser(mCloseNotificationShadeIntent, UserHandle.ALL);
    - 
    -             Slog.i(TAG, "Starting dream: name=" + name
    -                     + ", isTest=" + isTest + ", canDoze=" + canDoze
    -                     + ", userId=" + userId);
    - 
    --            mCurrentDream = new DreamRecord(token, name, isTest, canDoze, userId);
    -+            mCurrentDream = new DreamRecord(token, name, isTest, canDoze, userId, wakeLock);
    - 
    -             mDreamStartTime = SystemClock.elapsedRealtime();
    -             MetricsLogger.visible(mContext,
    -@@ -230,6 +233,7 @@ final class DreamController {
    -             if (oldDream.mBound) {
    -                 mContext.unbindService(oldDream);
    -             }
    -+            oldDream.releaseWakeLockIfNeeded();
    - 
    -             try {
    -                 mIWindowManager.removeWindowToken(oldDream.mToken);
    -@@ -251,7 +255,8 @@ final class DreamController {
    -     private void attach(IDreamService service) {
    -         try {
    -             service.asBinder().linkToDeath(mCurrentDream, 0);
    --            service.attach(mCurrentDream.mToken, mCurrentDream.mCanDoze);
    -+            service.attach(mCurrentDream.mToken, mCurrentDream.mCanDoze,
    -+                    mCurrentDream.mDreamingStartedCallback);
    -         } catch (RemoteException ex) {
    -             Slog.e(TAG, "The dream service died unexpectedly.", ex);
    -             stopDream(true /*immediate*/);
    -@@ -280,6 +285,7 @@ final class DreamController {
    -         public final boolean mCanDoze;
    -         public final int mUserId;
    - 
    -+        public PowerManager.WakeLock mWakeLock;
    -         public boolean mBound;
    -         public boolean mConnected;
    -         public IDreamService mService;
    -@@ -288,12 +294,17 @@ final class DreamController {
    -         public boolean mWakingGently;
    - 
    -         public DreamRecord(Binder token, ComponentName name,
    --                boolean isTest, boolean canDoze, int userId) {
    -+                boolean isTest, boolean canDoze, int userId, PowerManager.WakeLock wakeLock) {
    -             mToken = token;
    -             mName = name;
    -             mIsTest = isTest;
    -             mCanDoze = canDoze;
    -             mUserId  = userId;
    -+            mWakeLock = wakeLock;
    -+            // Hold the lock while we're waiting for the service to connect and start dreaming.
    -+            // Released after the service has started dreaming, we stop dreaming, or it timed out.
    -+            mWakeLock.acquire();
    -+            mHandler.postDelayed(mReleaseWakeLockIfNeeded, 10000);
    -         }
    - 
    -         // May be called on any thread.
    -@@ -319,6 +330,9 @@ final class DreamController {
    -                     mConnected = true;
    -                     if (mCurrentDream == DreamRecord.this && mService == null) {
    -                         attach(IDreamService.Stub.asInterface(service));
    -+                        // Wake lock will be released once dreaming starts.
    -+                    } else {
    -+                        releaseWakeLockIfNeeded();
    -                     }
    -                 }
    -             });
    -@@ -337,5 +351,23 @@ final class DreamController {
    -                 }
    -             });
    -         }
    -+
    -+        void releaseWakeLockIfNeeded() {
    -+            if (mWakeLock != null) {
    -+                mWakeLock.release();
    -+                mWakeLock = null;
    -+                mHandler.removeCallbacks(mReleaseWakeLockIfNeeded);
    -+            }
    -+        }
    -+
    -+        final Runnable mReleaseWakeLockIfNeeded = this::releaseWakeLockIfNeeded;
    -+
    -+        final IRemoteCallback mDreamingStartedCallback = new IRemoteCallback.Stub() {
    -+            // May be called on any thread.
    -+            @Override
    -+            public void sendResult(Bundle data) throws RemoteException {
    -+                mHandler.post(mReleaseWakeLockIfNeeded);
    -+            }
    -+        };
    -     }
    - }
    -\ No newline at end of file
    -diff --git a/services/core/java/com/android/server/dreams/DreamManagerService.java b/services/core/java/com/android/server/dreams/DreamManagerService.java
    -index a783fa2..1991c00 100644
    ---- a/services/core/java/com/android/server/dreams/DreamManagerService.java
    -+++ b/services/core/java/com/android/server/dreams/DreamManagerService.java
    -@@ -18,6 +18,7 @@ package com.android.server.dreams;
    - 
    - import static android.Manifest.permission.BIND_DREAM_SERVICE;
    - 
    -+import com.android.internal.hardware.AmbientDisplayConfiguration;
    - import com.android.internal.util.DumpUtils;
    - import com.android.server.FgThread;
    - import com.android.server.LocalServices;
    -@@ -88,6 +89,8 @@ public final class DreamManagerService extends SystemService {
    -     private int mCurrentDreamDozeScreenState = Display.STATE_UNKNOWN;
    -     private int mCurrentDreamDozeScreenBrightness = PowerManager.BRIGHTNESS_DEFAULT;
    - 
    -+    private AmbientDisplayConfiguration mDozeConfig;
    -+
    -     public DreamManagerService(Context context) {
    -         super(context);
    -         mContext = context;
    -@@ -97,6 +100,7 @@ public final class DreamManagerService extends SystemService {
    -         mPowerManager = (PowerManager)context.getSystemService(Context.POWER_SERVICE);
    -         mPowerManagerInternal = getLocalService(PowerManagerInternal.class);
    -         mDozeWakeLock = mPowerManager.newWakeLock(PowerManager.DOZE_WAKE_LOCK, TAG);
    -+        mDozeConfig = new AmbientDisplayConfiguration(mContext);
    -     }
    - 
    -     @Override
    -@@ -121,7 +125,7 @@ public final class DreamManagerService extends SystemService {
    -                 }
    -             }, new IntentFilter(Intent.ACTION_USER_SWITCHED), null, mHandler);
    -             mContext.getContentResolver().registerContentObserver(
    --                    Settings.Secure.getUriFor(Settings.Secure.DOZE_ENABLED), false,
    -+                    Settings.Secure.getUriFor(Settings.Secure.DOZE_PULSE_ON_DOUBLE_TAP), false,
    -                     mDozeEnabledObserver, UserHandle.USER_ALL);
    -             writePulseGestureEnabled();
    -         }
    -@@ -326,19 +330,12 @@ public final class DreamManagerService extends SystemService {
    -     }
    - 
    -     private ComponentName getDozeComponent(int userId) {
    --        // Read the component from a system property to facilitate debugging.
    --        // Note that for production devices, the dream should actually be declared in
    --        // a config.xml resource.
    --        String name = Build.IS_DEBUGGABLE ? SystemProperties.get("debug.doze.component") : null;
    --        if (TextUtils.isEmpty(name)) {
    --            // Read the component from a config.xml resource.
    --            // The value should be specified in a resource overlay for the product.
    --            name = mContext.getResources().getString(
    --                    com.android.internal.R.string.config_dozeComponent);
    --        }
    --        boolean enabled = Settings.Secure.getIntForUser(mContext.getContentResolver(),
    --                Settings.Secure.DOZE_ENABLED, 1, userId) != 0;
    --        return TextUtils.isEmpty(name) || !enabled ? null : ComponentName.unflattenFromString(name);
    -+        if (mDozeConfig.enabled(userId)) {
    -+            return ComponentName.unflattenFromString(mDozeConfig.ambientDisplayComponent());
    -+        } else {
    -+            return null;
    -+        }
    -+
    -     }
    - 
    -     private ServiceInfo getServiceInfo(ComponentName name) {
    -@@ -370,12 +367,10 @@ public final class DreamManagerService extends SystemService {
    -         mCurrentDreamCanDoze = canDoze;
    -         mCurrentDreamUserId = userId;
    - 
    --        mHandler.post(new Runnable() {
    --            @Override
    --            public void run() {
    --                mController.startDream(newToken, name, isTest, canDoze, userId);
    --            }
    --        });
    -+        PowerManager.WakeLock wakeLock = mPowerManager
    -+                .newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "startDream");
    -+        mHandler.post(wakeLock.wrap(
    -+                () -> mController.startDream(newToken, name, isTest, canDoze, userId, wakeLock)));
    -     }
    - 
    -     private void stopDreamLocked(final boolean immediate) {
    -diff --git a/services/core/java/com/android/server/emergency/EmergencyAffordanceService.java b/services/core/java/com/android/server/emergency/EmergencyAffordanceService.java
    -new file mode 100644
    -index 0000000..353f450
    ---- /dev/null
    -+++ b/services/core/java/com/android/server/emergency/EmergencyAffordanceService.java
    -@@ -0,0 +1,318 @@
    -+/*
    -+ * Copyright (C) 2016 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 com.android.server.emergency;
    -+
    -+import android.content.BroadcastReceiver;
    -+import android.content.Context;
    -+import android.content.Intent;
    -+import android.content.IntentFilter;
    -+import android.os.Handler;
    -+import android.os.HandlerThread;
    -+import android.os.Looper;
    -+import android.os.Message;
    -+import android.provider.Settings;
    -+import android.telephony.CellInfo;
    -+import android.telephony.CellInfoGsm;
    -+import android.telephony.CellInfoLte;
    -+import android.telephony.CellInfoWcdma;
    -+import android.telephony.CellLocation;
    -+import android.telephony.PhoneStateListener;
    -+import android.telephony.SubscriptionInfo;
    -+import android.telephony.SubscriptionManager;
    -+import android.telephony.TelephonyManager;
    -+
    -+import com.android.server.SystemService;
    -+
    -+import java.util.ArrayList;
    -+import java.util.Arrays;
    -+import java.util.List;
    -+
    -+/**
    -+ * A service that listens to connectivity and SIM card changes and determines if the emergency mode
    -+ * should be enabled
    -+ */
    -+public class EmergencyAffordanceService extends SystemService {
    -+
    -+    private static final String TAG = "EmergencyAffordanceService";
    -+
    -+    private static final int NUM_SCANS_UNTIL_ABORT = 4;
    -+
    -+    private static final int INITIALIZE_STATE = 1;
    -+    private static final int CELL_INFO_STATE_CHANGED = 2;
    -+    private static final int SUBSCRIPTION_CHANGED = 3;
    -+
    -+    /**
    -+     * Global setting, whether the last scan of the sim cards reveal that a sim was inserted that
    -+     * requires the emergency affordance. The value is a boolean (1 or 0).
    -+     * @hide
    -+     */
    -+    private static final String EMERGENCY_SIM_INSERTED_SETTING = "emergency_sim_inserted_before";
    -+
    -+    private final Context mContext;
    -+    private final ArrayList<Integer> mEmergencyCallMccNumbers;
    -+
    -+    private final Object mLock = new Object();
    -+
    -+    private TelephonyManager mTelephonyManager;
    -+    private SubscriptionManager mSubscriptionManager;
    -+    private boolean mEmergencyAffordanceNeeded;
    -+    private MyHandler mHandler;
    -+    private int mScansCompleted;
    -+    private PhoneStateListener mPhoneStateListener = new PhoneStateListener() {
    -+        @Override
    -+        public void onCellInfoChanged(List<CellInfo> cellInfo) {
    -+            if (!isEmergencyAffordanceNeeded()) {
    -+                requestCellScan();
    -+            }
    -+        }
    -+
    -+        @Override
    -+        public void onCellLocationChanged(CellLocation location) {
    -+            if (!isEmergencyAffordanceNeeded()) {
    -+                requestCellScan();
    -+            }
    -+        }
    -+    };
    -+    private BroadcastReceiver mAirplaneModeReceiver = new BroadcastReceiver() {
    -+        @Override
    -+        public void onReceive(Context context, Intent intent) {
    -+            if (Settings.Global.getInt(context.getContentResolver(),
    -+                    Settings.Global.AIRPLANE_MODE_ON, 0) == 0) {
    -+                startScanning();
    -+                requestCellScan();
    -+            }
    -+        }
    -+    };
    -+    private boolean mSimNeedsEmergencyAffordance;
    -+    private boolean mNetworkNeedsEmergencyAffordance;
    -+    private boolean mVoiceCapable;
    -+
    -+    private void requestCellScan() {
    -+        mHandler.obtainMessage(CELL_INFO_STATE_CHANGED).sendToTarget();
    -+    }
    -+
    -+    private SubscriptionManager.OnSubscriptionsChangedListener mSubscriptionChangedListener
    -+            = new SubscriptionManager.OnSubscriptionsChangedListener() {
    -+        @Override
    -+        public void onSubscriptionsChanged() {
    -+            mHandler.obtainMessage(SUBSCRIPTION_CHANGED).sendToTarget();
    -+        }
    -+    };
    -+
    -+    public EmergencyAffordanceService(Context context) {
    -+        super(context);
    -+        mContext = context;
    -+        int[] numbers = context.getResources().getIntArray(
    -+                com.android.internal.R.array.config_emergency_mcc_codes);
    -+        mEmergencyCallMccNumbers = new ArrayList<>(numbers.length);
    -+        for (int i = 0; i < numbers.length; i++) {
    -+            mEmergencyCallMccNumbers.add(numbers[i]);
    -+        }
    -+    }
    -+
    -+    private void updateEmergencyAffordanceNeeded() {
    -+        synchronized (mLock) {
    -+            mEmergencyAffordanceNeeded = mVoiceCapable && (mSimNeedsEmergencyAffordance ||
    -+                    mNetworkNeedsEmergencyAffordance);
    -+            Settings.Global.putInt(mContext.getContentResolver(),
    -+                    Settings.Global.EMERGENCY_AFFORDANCE_NEEDED,
    -+                    mEmergencyAffordanceNeeded ? 1 : 0);
    -+            if (mEmergencyAffordanceNeeded) {
    -+                stopScanning();
    -+            }
    -+        }
    -+    }
    -+
    -+    private void stopScanning() {
    -+        synchronized (mLock) {
    -+            mTelephonyManager.listen(mPhoneStateListener, PhoneStateListener.LISTEN_NONE);
    -+            mScansCompleted = 0;
    -+        }
    -+    }
    -+
    -+    private boolean isEmergencyAffordanceNeeded() {
    -+        synchronized (mLock) {
    -+            return mEmergencyAffordanceNeeded;
    -+        }
    -+    }
    -+
    -+    @Override
    -+    public void onStart() {
    -+    }
    -+
    -+    @Override
    -+    public void onBootPhase(int phase) {
    -+        if (phase == PHASE_THIRD_PARTY_APPS_CAN_START) {
    -+            mTelephonyManager = mContext.getSystemService(TelephonyManager.class);
    -+            mVoiceCapable = mTelephonyManager.isVoiceCapable();
    -+            if (!mVoiceCapable) {
    -+                updateEmergencyAffordanceNeeded();
    -+                return;
    -+            }
    -+            mSubscriptionManager = SubscriptionManager.from(mContext);
    -+            HandlerThread thread = new HandlerThread(TAG);
    -+            thread.start();
    -+            mHandler = new MyHandler(thread.getLooper());
    -+            mHandler.obtainMessage(INITIALIZE_STATE).sendToTarget();
    -+            startScanning();
    -+            IntentFilter filter = new IntentFilter(Intent.ACTION_AIRPLANE_MODE_CHANGED);
    -+            mContext.registerReceiver(mAirplaneModeReceiver, filter);
    -+            mSubscriptionManager.addOnSubscriptionsChangedListener(mSubscriptionChangedListener);
    -+        }
    -+    }
    -+
    -+    private void startScanning() {
    -+        mTelephonyManager.listen(mPhoneStateListener, PhoneStateListener.LISTEN_CELL_INFO
    -+                | PhoneStateListener.LISTEN_CELL_LOCATION);
    -+    }
    -+
    -+    /** Handler to do the heavier work on */
    -+    private class MyHandler extends Handler {
    -+
    -+        public MyHandler(Looper l) {
    -+            super(l);
    -+        }
    -+
    -+        @Override
    -+        public void handleMessage(Message msg) {
    -+            switch (msg.what) {
    -+                case INITIALIZE_STATE:
    -+                    handleInitializeState();
    -+                    break;
    -+                case CELL_INFO_STATE_CHANGED:
    -+                    handleUpdateCellInfo();
    -+                    break;
    -+                case SUBSCRIPTION_CHANGED:
    -+                    handleUpdateSimSubscriptionInfo();
    -+                    break;
    -+            }
    -+        }
    -+    }
    -+
    -+    private void handleInitializeState() {
    -+        if (handleUpdateSimSubscriptionInfo()) {
    -+            return;
    -+        }
    -+        if (handleUpdateCellInfo()) {
    -+            return;
    -+        }
    -+        updateEmergencyAffordanceNeeded();
    -+    }
    -+
    -+    private boolean handleUpdateSimSubscriptionInfo() {
    -+        boolean neededBefore = simNeededAffordanceBefore();
    -+        boolean neededNow = neededBefore;
    -+        List<SubscriptionInfo> activeSubscriptionInfoList =
    -+                mSubscriptionManager.getActiveSubscriptionInfoList();
    -+        if (activeSubscriptionInfoList == null) {
    -+            return neededNow;
    -+        }
    -+        for (SubscriptionInfo info : activeSubscriptionInfoList) {
    -+            int mcc = info.getMcc();
    -+            if (mccRequiresEmergencyAffordance(mcc)) {
    -+                neededNow = true;
    -+                break;
    -+            } else if (mcc != 0 && mcc != Integer.MAX_VALUE){
    -+                // a Sim with a different mcc code was found
    -+                neededNow = false;
    -+            }
    -+            String simOperator  = mTelephonyManager.getSimOperator(info.getSubscriptionId());
    -+            mcc = 0;
    -+            if (simOperator != null && simOperator.length() >= 3) {
    -+                mcc = Integer.parseInt(simOperator.substring(0, 3));
    -+            }
    -+            if (mcc != 0) {
    -+                if (mccRequiresEmergencyAffordance(mcc)) {
    -+                    neededNow = true;
    -+                    break;
    -+                } else {
    -+                    // a Sim with a different mcc code was found
    -+                    neededNow = false;
    -+                }
    -+            }
    -+        }
    -+        if (neededNow != neededBefore) {
    -+            setSimNeedsEmergencyAffordance(neededNow);
    -+        }
    -+        return neededNow;
    -+    }
    -+
    -+    private void setSimNeedsEmergencyAffordance(boolean simNeedsEmergencyAffordance) {
    -+        mSimNeedsEmergencyAffordance = simNeedsEmergencyAffordance;
    -+        Settings.Global.putInt(mContext.getContentResolver(),
    -+                EMERGENCY_SIM_INSERTED_SETTING,
    -+                simNeedsEmergencyAffordance ? 1 : 0);
    -+        updateEmergencyAffordanceNeeded();
    -+    }
    -+
    -+    private boolean simNeededAffordanceBefore() {
    -+        return Settings.Global.getInt(mContext.getContentResolver(),
    -+                "emergency_sim_inserted_before", 0) != 0;
    -+    }
    -+
    -+    private boolean handleUpdateCellInfo() {
    -+        List<CellInfo> cellInfos = mTelephonyManager.getAllCellInfo();
    -+        if (cellInfos == null) {
    -+            return false;
    -+        }
    -+        boolean stopScanningAfterScan = false;
    -+        for (CellInfo cellInfo : cellInfos) {
    -+            int mcc = 0;
    -+            if (cellInfo instanceof CellInfoGsm) {
    -+                mcc = ((CellInfoGsm) cellInfo).getCellIdentity().getMcc();
    -+            } else if (cellInfo instanceof CellInfoLte) {
    -+                mcc = ((CellInfoLte) cellInfo).getCellIdentity().getMcc();
    -+            } else if (cellInfo instanceof CellInfoWcdma) {
    -+                mcc = ((CellInfoWcdma) cellInfo).getCellIdentity().getMcc();
    -+            }
    -+            if (mccRequiresEmergencyAffordance(mcc)) {
    -+                setNetworkNeedsEmergencyAffordance(true);
    -+                return true;
    -+            } else if (mcc != 0 && mcc != Integer.MAX_VALUE) {
    -+                // we found an mcc that isn't in the list, abort
    -+                stopScanningAfterScan = true;
    -+            }
    -+        }
    -+        if (stopScanningAfterScan) {
    -+            stopScanning();
    -+        } else {
    -+            onCellScanFinishedUnsuccessful();
    -+        }
    -+        setNetworkNeedsEmergencyAffordance(false);
    -+        return false;
    -+    }
    -+
    -+    private void setNetworkNeedsEmergencyAffordance(boolean needsAffordance) {
    -+        synchronized (mLock) {
    -+            mNetworkNeedsEmergencyAffordance = needsAffordance;
    -+            updateEmergencyAffordanceNeeded();
    -+        }
    -+    }
    -+
    -+    private void onCellScanFinishedUnsuccessful() {
    -+        synchronized (mLock) {
    -+            mScansCompleted++;
    -+            if (mScansCompleted >= NUM_SCANS_UNTIL_ABORT) {
    -+                stopScanning();
    -+            }
    -+        }
    -+    }
    -+
    -+    private boolean mccRequiresEmergencyAffordance(int mcc) {
    -+        return mEmergencyCallMccNumbers.contains(mcc);
    -+    }
    -+}
    -diff --git a/services/core/java/com/android/server/fingerprint/AuthenticationClient.java b/services/core/java/com/android/server/fingerprint/AuthenticationClient.java
    -index 87da866..5297589 100644
    ---- a/services/core/java/com/android/server/fingerprint/AuthenticationClient.java
    -+++ b/services/core/java/com/android/server/fingerprint/AuthenticationClient.java
    -@@ -115,6 +115,7 @@ public abstract class AuthenticationClient extends ClientMonitor {
    -             final int result = daemon.authenticate(mOpId, getGroupId());
    -             if (result != 0) {
    -                 Slog.w(TAG, "startAuthentication failed, result=" + result);
    -+                MetricsLogger.histogram(getContext(), "fingeprintd_auth_start_error", result);
    -                 onError(FingerprintManager.FINGERPRINT_ERROR_HW_UNAVAILABLE);
    -                 return result;
    -             }
    -diff --git a/services/core/java/com/android/server/fingerprint/EnrollClient.java b/services/core/java/com/android/server/fingerprint/EnrollClient.java
    -index 6a533c9..640a46f 100644
    ---- a/services/core/java/com/android/server/fingerprint/EnrollClient.java
    -+++ b/services/core/java/com/android/server/fingerprint/EnrollClient.java
    -@@ -88,6 +88,7 @@ public abstract class EnrollClient extends ClientMonitor {
    -             final int result = daemon.enroll(mCryptoToken, getGroupId(), timeout);
    -             if (result != 0) {
    -                 Slog.w(TAG, "startEnroll failed, result=" + result);
    -+                MetricsLogger.histogram(getContext(), "fingerprintd_enroll_start_error", result);
    -                 onError(FingerprintManager.FINGERPRINT_ERROR_HW_UNAVAILABLE);
    -                 return result;
    -             }
    -diff --git a/services/core/java/com/android/server/fingerprint/EnumerateClient.java b/services/core/java/com/android/server/fingerprint/EnumerateClient.java
    -index 52dbd5d..26b1916 100644
    ---- a/services/core/java/com/android/server/fingerprint/EnumerateClient.java
    -+++ b/services/core/java/com/android/server/fingerprint/EnumerateClient.java
    -@@ -23,6 +23,7 @@ import android.hardware.fingerprint.IFingerprintServiceReceiver;
    - import android.os.IBinder;
    - import android.os.RemoteException;
    - import android.util.Slog;
    -+import com.android.internal.logging.MetricsLogger;
    - 
    - /**
    -  * A class to keep track of the enumeration state for a given client.
    -@@ -43,6 +44,7 @@ public abstract class EnumerateClient extends ClientMonitor {
    -             if (result != 0) {
    -                 Slog.w(TAG, "start enumerate for user " + getTargetUserId()
    -                     + " failed, result=" + result);
    -+                MetricsLogger.histogram(getContext(), "fingerprintd_enum_start_error", result);
    -                 onError(FingerprintManager.FINGERPRINT_ERROR_HW_UNAVAILABLE);
    -                 return result;
    -             }
    -diff --git a/services/core/java/com/android/server/fingerprint/FingerprintService.java b/services/core/java/com/android/server/fingerprint/FingerprintService.java
    -index 73c8469..6c11794 100644
    ---- a/services/core/java/com/android/server/fingerprint/FingerprintService.java
    -+++ b/services/core/java/com/android/server/fingerprint/FingerprintService.java
    -@@ -194,7 +194,9 @@ public class FingerprintService extends SystemService implements IBinder.DeathRe
    -     @Override
    -     public void binderDied() {
    -         Slog.v(TAG, "fingerprintd died");
    -+        MetricsLogger.count(mContext, "fingerprintd_died", 1);
    -         mDaemon = null;
    -+        mCurrentUserId = UserHandle.USER_CURRENT;
    -         handleError(mHalDeviceId, FingerprintManager.FINGERPRINT_ERROR_HW_UNAVAILABLE);
    -     }
    - 
    -@@ -210,6 +212,7 @@ public class FingerprintService extends SystemService implements IBinder.DeathRe
    -                         updateActiveGroup(ActivityManager.getCurrentUser(), null);
    -                     } else {
    -                         Slog.w(TAG, "Failed to open Fingerprint HAL!");
    -+                        MetricsLogger.count(mContext, "fingerprintd_openhal_error", 1);
    -                         mDaemon = null;
    -                     }
    -                 } catch (RemoteException e) {
    -diff --git a/services/core/java/com/android/server/fingerprint/RemovalClient.java b/services/core/java/com/android/server/fingerprint/RemovalClient.java
    -index bcf2264..f939f41 100644
    ---- a/services/core/java/com/android/server/fingerprint/RemovalClient.java
    -+++ b/services/core/java/com/android/server/fingerprint/RemovalClient.java
    -@@ -24,6 +24,7 @@ import android.os.IBinder;
    - import android.os.RemoteException;
    - import android.os.UserHandle;
    - import android.util.Slog;
    -+import com.android.internal.logging.MetricsLogger;
    - 
    - /**
    -  * A class to keep track of the remove state for a given client.
    -@@ -46,6 +47,7 @@ public abstract class RemovalClient extends ClientMonitor {
    -             final int result = daemon.remove(mFingerId, getGroupId());
    -             if (result != 0) {
    -                 Slog.w(TAG, "startRemove with id = " + mFingerId + " failed, result=" + result);
    -+                MetricsLogger.histogram(getContext(), "fingerprintd_remove_start_error", result);
    -                 onError(FingerprintManager.FINGERPRINT_ERROR_HW_UNAVAILABLE);
    -                 return result;
    -             }
    -diff --git a/services/core/java/com/android/server/hdmi/HdmiControlService.java b/services/core/java/com/android/server/hdmi/HdmiControlService.java
    -index 5dc9d02..72ee218 100644
    ---- a/services/core/java/com/android/server/hdmi/HdmiControlService.java
    -+++ b/services/core/java/com/android/server/hdmi/HdmiControlService.java
    -@@ -2011,6 +2011,9 @@ public final class HdmiControlService extends SystemService {
    -     @ServiceThreadOnly
    -     void standby() {
    -         assertRunOnServiceThread();
    -+        if (!canGoToStandby()) {
    -+            return;
    -+        }
    -         mStandbyMessageReceived = true;
    -         mPowerManager.goToSleep(SystemClock.uptimeMillis(), PowerManager.GO_TO_SLEEP_REASON_HDMI, 0);
    -         // PowerManger will send the broadcast Intent.ACTION_SCREEN_OFF and after this gets
    -@@ -2038,10 +2041,13 @@ public final class HdmiControlService extends SystemService {
    -     @ServiceThreadOnly
    -     private void onStandby(final int standbyAction) {
    -         assertRunOnServiceThread();
    --        if (!canGoToStandby()) return;
    -         mPowerStatus = HdmiControlManager.POWER_STATUS_TRANSIENT_TO_STANDBY;
    -         invokeVendorCommandListenersOnControlStateChanged(false,
    -                 HdmiControlManager.CONTROL_STATE_CHANGED_REASON_STANDBY);
    -+        if (!canGoToStandby()) {
    -+            mPowerStatus = HdmiControlManager.POWER_STATUS_STANDBY;
    -+            return;
    -+        }
    - 
    -         final List<HdmiCecLocalDevice> devices = getAllLocalDevices();
    -         disableDevices(new PendingActionClearedCallback() {
    -diff --git a/services/core/java/com/android/server/job/JobSchedulerService.java b/services/core/java/com/android/server/job/JobSchedulerService.java
    -index 9d93146..bb3e877 100644
    ---- a/services/core/java/com/android/server/job/JobSchedulerService.java
    -+++ b/services/core/java/com/android/server/job/JobSchedulerService.java
    -@@ -217,7 +217,7 @@ public final class JobSchedulerService extends com.android.server.SystemService
    -         private static final int DEFAULT_FG_JOB_COUNT = 4;
    -         private static final int DEFAULT_BG_NORMAL_JOB_COUNT = 6;
    -         private static final int DEFAULT_BG_MODERATE_JOB_COUNT = 4;
    --        private static final int DEFAULT_BG_LOW_JOB_COUNT = 2;
    -+        private static final int DEFAULT_BG_LOW_JOB_COUNT = 1;
    -         private static final int DEFAULT_BG_CRITICAL_JOB_COUNT = 1;
    - 
    -         /**
    -@@ -429,7 +429,18 @@ public final class JobSchedulerService extends com.android.server.SystemService
    -                                         }
    -                                         cancelJobsForUid(pkgUid, true);
    -                                     }
    --                                } catch (RemoteException e) { /* cannot happen */ }
    -+                                } catch (RemoteException|IllegalArgumentException e) {
    -+                                    /*
    -+                                     * IllegalArgumentException means that the package doesn't exist.
    -+                                     * This arises when PACKAGE_CHANGED broadcast delivery has lagged
    -+                                     * behind outright uninstall, so by the time we try to act it's gone.
    -+                                     * We don't need to act on this PACKAGE_CHANGED when this happens;
    -+                                     * we'll get a PACKAGE_REMOVED later and clean up then.
    -+                                     *
    -+                                     * RemoteException can't actually happen; the package manager is
    -+                                     * running in this same process.
    -+                                     */
    -+                                }
    -                                 break;
    -                             }
    -                         }
    -@@ -907,7 +918,11 @@ public final class JobSchedulerService extends com.android.server.SystemService
    -     private boolean isCurrentlyActiveLocked(JobStatus job) {
    -         for (int i=0; i<mActiveServices.size(); i++) {
    -             JobServiceContext serviceContext = mActiveServices.get(i);
    --            final JobStatus running = serviceContext.getRunningJob();
    -+            // The 'unsafe' direct-internal-reference running-job inspector is okay to
    -+            // use here because we are already holding the necessary lock *and* we
    -+            // immediately discard the returned object reference, if any; we return
    -+            // only a boolean state indicator to the caller.
    -+            final JobStatus running = serviceContext.getRunningJobUnsafeLocked();
    -             if (running != null && running.matches(job.getUid(), job.getJobId())) {
    -                 return true;
    -             }
    -diff --git a/services/core/java/com/android/server/job/JobServiceContext.java b/services/core/java/com/android/server/job/JobServiceContext.java
    -index 31528e5..5e495fa 100644
    ---- a/services/core/java/com/android/server/job/JobServiceContext.java
    -+++ b/services/core/java/com/android/server/job/JobServiceContext.java
    -@@ -230,6 +230,15 @@ public class JobServiceContext extends IJobCallback.Stub implements ServiceConne
    -         return job == null ? null : new JobStatus(job);
    -     }
    - 
    -+    /**
    -+     * Internal non-cloning inspection of the currently running job, if any.  The lock
    -+     * must be held when calling this *and* for the entire lifetime of using its returned
    -+     * JobStatus object!
    -+     */
    -+    JobStatus getRunningJobUnsafeLocked() {
    -+        return mRunningJob;
    -+    }
    -+
    -     /** Called externally when a job that was scheduled for execution should be cancelled. */
    -     void cancelExecutingJob(int reason) {
    -         mCallbackHandler.obtainMessage(MSG_CANCEL, reason, 0 /* unused */).sendToTarget();
    -@@ -306,10 +315,24 @@ public class JobServiceContext extends IJobCallback.Stub implements ServiceConne
    -         this.service = IJobService.Stub.asInterface(service);
    -         final PowerManager pm =
    -                 (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
    --        mWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, runningJob.getTag());
    --        mWakeLock.setWorkSource(new WorkSource(runningJob.getSourceUid()));
    --        mWakeLock.setReferenceCounted(false);
    --        mWakeLock.acquire();
    -+        PowerManager.WakeLock wl = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK,
    -+                runningJob.getTag());
    -+        wl.setWorkSource(new WorkSource(runningJob.getSourceUid()));
    -+        wl.setReferenceCounted(false);
    -+        wl.acquire();
    -+        synchronized (mLock) {
    -+            // We use a new wakelock instance per job.  In rare cases there is a race between
    -+            // teardown following job completion/cancellation and new job service spin-up
    -+            // such that if we simply assign mWakeLock to be the new instance, we orphan
    -+            // the currently-live lock instead of cleanly replacing it.  Watch for this and
    -+            // explicitly fast-forward the release if we're in that situation.
    -+            if (mWakeLock != null) {
    -+                Slog.w(TAG, "Bound new job " + runningJob + " but live wakelock " + mWakeLock
    -+                        + " tag=" + mWakeLock.getTag());
    -+                mWakeLock.release();
    -+            }
    -+            mWakeLock = wl;
    -+        }
    -         mCallbackHandler.obtainMessage(MSG_SERVICE_BOUND).sendToTarget();
    -     }
    - 
    -diff --git a/services/core/java/com/android/server/location/GnssLocationProvider.java b/services/core/java/com/android/server/location/GnssLocationProvider.java
    -index 7580cf4..ae98077 100644
    ---- a/services/core/java/com/android/server/location/GnssLocationProvider.java
    -+++ b/services/core/java/com/android/server/location/GnssLocationProvider.java
    -@@ -452,8 +452,12 @@ public class GnssLocationProvider implements LocationProviderInterface {
    -             new ConnectivityManager.NetworkCallback() {
    -         @Override
    -         public void onAvailable(Network network) {
    --            requestUtcTime();
    --            xtraDownloadRequest();
    -+            if (mInjectNtpTimePending == STATE_PENDING_NETWORK) {
    -+                requestUtcTime();
    -+            }
    -+            if (mDownloadXtraDataPending == STATE_PENDING_NETWORK) {
    -+                xtraDownloadRequest();
    -+            }
    -         }
    -     };
    - 
    -@@ -1002,6 +1006,11 @@ public class GnssLocationProvider implements LocationProviderInterface {
    -     }
    - 
    -     private void handleDownloadXtraData() {
    -+        if (!mSupportsXtra) {
    -+            // native code reports xtra not supported, don't try
    -+            Log.d(TAG, "handleDownloadXtraData() called when Xtra not supported");
    -+            return;
    -+        }
    -         if (mDownloadXtraDataPending == STATE_DOWNLOADING) {
    -             // already downloading data
    -             return;
    -@@ -2125,9 +2134,7 @@ public class GnssLocationProvider implements LocationProviderInterface {
    -                     handleInjectNtpTime();
    -                     break;
    -                 case DOWNLOAD_XTRA_DATA:
    --                    if (mSupportsXtra) {
    --                        handleDownloadXtraData();
    --                    }
    -+                    handleDownloadXtraData();
    -                     break;
    -                 case INJECT_NTP_TIME_FINISHED:
    -                     mInjectNtpTimePending = STATE_IDLE;
    -diff --git a/services/core/java/com/android/server/media/MediaSessionService.java b/services/core/java/com/android/server/media/MediaSessionService.java
    -index 2c53af3..34f6aa7 100644
    ---- a/services/core/java/com/android/server/media/MediaSessionService.java
    -+++ b/services/core/java/com/android/server/media/MediaSessionService.java
    -@@ -78,6 +78,8 @@ import java.util.List;
    - public class MediaSessionService extends SystemService implements Monitor {
    -     private static final String TAG = "MediaSessionService";
    -     private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
    -+    // Leave log for media key event always.
    -+    private static final boolean DEBUG_MEDIA_KEY_EVENT = DEBUG || true;
    - 
    -     private static final int WAKELOCK_TIMEOUT = 5000;
    - 
    -@@ -302,7 +304,7 @@ public class MediaSessionService extends SystemService implements Monitor {
    -      */
    -     private void destroySessionLocked(MediaSessionRecord session) {
    -         if (DEBUG) {
    --            Log.d(TAG, "Destroying session : " + session.toString());
    -+            Log.d(TAG, "Destroying " + session);
    -         }
    -         int userId = session.getUserId();
    -         UserRecord user = mUserRecords.get(userId);
    -@@ -408,7 +410,7 @@ public class MediaSessionService extends SystemService implements Monitor {
    -                     if (component != null) {
    -                         if (compName.equals(component)) {
    -                             if (DEBUG) {
    --                                Log.d(TAG, "ok to get sessions: " + component +
    -+                                Log.d(TAG, "ok to get sessions. " + component +
    -                                         " is authorized notification listener");
    -                             }
    -                             return true;
    -@@ -417,7 +419,7 @@ public class MediaSessionService extends SystemService implements Monitor {
    -                 }
    -             }
    -             if (DEBUG) {
    --                Log.d(TAG, "not ok to get sessions, " + compName +
    -+                Log.d(TAG, "not ok to get sessions. " + compName +
    -                         " is not in list of ENABLED_NOTIFICATION_LISTENERS for user " + userId);
    -             }
    -         }
    -@@ -462,7 +464,7 @@ public class MediaSessionService extends SystemService implements Monitor {
    -         mHandler.post(MessageHandler.MSG_SESSIONS_CHANGED, userId, 0);
    - 
    -         if (DEBUG) {
    --            Log.d(TAG, "Created session for package " + callerPackageName + " with tag " + tag);
    -+            Log.d(TAG, "Created session for " + callerPackageName + " with tag " + tag);
    -         }
    -         return session;
    -     }
    -@@ -888,17 +890,16 @@ public class MediaSessionService extends SystemService implements Monitor {
    - 
    -         private void dispatchAdjustVolumeLocked(int suggestedStream, int direction, int flags,
    -                 MediaSessionRecord session) {
    --            if (DEBUG) {
    --                String description = session == null ? null : session.toString();
    --                Log.d(TAG, "Adjusting session " + description + " by " + direction + ". flags="
    --                        + flags + ", suggestedStream=" + suggestedStream);
    --
    --            }
    -             boolean preferSuggestedStream = false;
    -             if (isValidLocalStreamType(suggestedStream)
    -                     && AudioSystem.isStreamActive(suggestedStream, 0)) {
    -                 preferSuggestedStream = true;
    -             }
    -+            if (DEBUG) {
    -+                Log.d(TAG, "Adjusting " + session + " by " + direction + ". flags="
    -+                        + flags + ", suggestedStream=" + suggestedStream
    -+                        + ", preferSuggestedStream=" + preferSuggestedStream);
    -+            }
    -             if (session == null || preferSuggestedStream) {
    -                 if ((flags & AudioManager.FLAG_ACTIVE_MEDIA_ONLY) != 0
    -                         && !AudioSystem.isStreamActive(AudioManager.STREAM_MUSIC, 0)) {
    -@@ -953,8 +954,8 @@ public class MediaSessionService extends SystemService implements Monitor {
    -         private void dispatchMediaKeyEventLocked(KeyEvent keyEvent, boolean needWakeLock,
    -                 MediaSessionRecord session) {
    -             if (session != null) {
    --                if (DEBUG) {
    --                    Log.d(TAG, "Sending media key to " + session.toString());
    -+                if (DEBUG_MEDIA_KEY_EVENT) {
    -+                    Log.d(TAG, "Sending " + keyEvent + " to " + session);
    -                 }
    -                 if (needWakeLock) {
    -                     mKeyEventReceiver.aquireWakeLockLocked();
    -@@ -973,11 +974,6 @@ public class MediaSessionService extends SystemService implements Monitor {
    -                             && user.mRestoredMediaButtonReceiver == null) {
    -                         continue;
    -                     }
    --                    if (DEBUG) {
    --                        Log.d(TAG, "Sending media key to last known PendingIntent "
    --                                + user.mLastMediaButtonReceiver + " or restored Intent "
    --                                + user.mRestoredMediaButtonReceiver);
    --                    }
    -                     if (needWakeLock) {
    -                         mKeyEventReceiver.aquireWakeLockLocked();
    -                     }
    -@@ -986,10 +982,19 @@ public class MediaSessionService extends SystemService implements Monitor {
    -                     mediaButtonIntent.putExtra(Intent.EXTRA_KEY_EVENT, keyEvent);
    -                     try {
    -                         if (user.mLastMediaButtonReceiver != null) {
    -+                            if (DEBUG_MEDIA_KEY_EVENT) {
    -+                                Log.d(TAG, "Sending " + keyEvent
    -+                                        + " to the last known pendingIntent "
    -+                                        + user.mLastMediaButtonReceiver);
    -+                            }
    -                             user.mLastMediaButtonReceiver.send(getContext(),
    -                                     needWakeLock ? mKeyEventReceiver.mLastTimeoutId : -1,
    -                                     mediaButtonIntent, mKeyEventReceiver, mHandler);
    -                         } else {
    -+                            if (DEBUG_MEDIA_KEY_EVENT) {
    -+                                Log.d(TAG, "Sending " + keyEvent + " to the restored intent "
    -+                                        + user.mRestoredMediaButtonReceiver);
    -+                            }
    -                             mediaButtonIntent.setComponent(user.mRestoredMediaButtonReceiver);
    -                             getContext().sendBroadcastAsUser(mediaButtonIntent,
    -                                     UserHandle.of(userId));
    -diff --git a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
    -index f3fc676..d479bfc 100644
    ---- a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
    -+++ b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
    -@@ -90,6 +90,7 @@ import static org.xmlpull.v1.XmlPullParser.START_TAG;
    - 
    - import android.Manifest;
    - import android.annotation.IntDef;
    -+import android.annotation.Nullable;
    - import android.app.ActivityManager;
    - import android.app.AppGlobals;
    - import android.app.AppOpsManager;
    -@@ -141,6 +142,7 @@ import android.os.RemoteCallbackList;
    - import android.os.RemoteException;
    - import android.os.ResultReceiver;
    - import android.os.ServiceManager;
    -+import android.os.Trace;
    - import android.os.UserHandle;
    - import android.os.UserManager;
    - import android.provider.Settings;
    -@@ -164,7 +166,6 @@ import android.util.Xml;
    - import com.android.internal.R;
    - import com.android.internal.annotations.GuardedBy;
    - import com.android.internal.annotations.VisibleForTesting;
    --import com.android.internal.content.PackageMonitor;
    - import com.android.internal.util.ArrayUtils;
    - import com.android.internal.util.FastXmlSerializer;
    - import com.android.internal.util.IndentingPrintWriter;
    -@@ -289,6 +290,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
    -     private static final int MSG_UPDATE_INTERFACE_QUOTA = 10;
    -     private static final int MSG_REMOVE_INTERFACE_QUOTA = 11;
    -     private static final int MSG_RESTRICT_BACKGROUND_BLACKLIST_CHANGED = 12;
    -+    private static final int MSG_SET_FIREWALL_RULES = 13;
    - 
    -     private final Context mContext;
    -     private final IActivityManager mActivityManager;
    -@@ -404,7 +406,6 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
    - 
    -     private final AppOpsManager mAppOps;
    - 
    --    private final MyPackageMonitor mPackageMonitor;
    -     private final IPackageManager mIPm;
    - 
    - 
    -@@ -446,8 +447,6 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
    - 
    -         mAppOps = context.getSystemService(AppOpsManager.class);
    - 
    --        mPackageMonitor = new MyPackageMonitor();
    --
    -         // Expose private service for system components to use.
    -         LocalServices.addService(NetworkPolicyManagerInternal.class,
    -                 new NetworkPolicyManagerInternalImpl());
    -@@ -513,12 +512,13 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
    -             try {
    -                 app = pm.getApplicationInfoAsUser(pkg, PackageManager.MATCH_SYSTEM_ONLY, userId);
    -             } catch (PackageManager.NameNotFoundException e) {
    --                // Should not happen
    --                Slog.wtf(TAG, "No ApplicationInfo for package " + pkg);
    -+                if (LOGD) Slog.d(TAG, "No ApplicationInfo for package " + pkg);
    -+                // Ignore it - some apps on allow-in-data-usage-save are optional.
    -                 continue;
    -             }
    -             if (!app.isPrivilegedApp()) {
    --                Slog.wtf(TAG, "pm.getApplicationInfoAsUser() returned non-privileged app: " + pkg);
    -+                Slog.e(TAG, "addDefaultRestrictBackgroundWhitelistUidsUL(): "
    -+                        + "skipping non-privileged app  " + pkg);
    -                 continue;
    -             }
    -             final int uid = UserHandle.getUid(userId, app.uid);
    -@@ -528,8 +528,9 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
    -                         + "background whitelist. Revoked status: "
    -                         + mRestrictBackgroundWhitelistRevokedUids.get(uid));
    -             if (!mRestrictBackgroundWhitelistRevokedUids.get(uid)) {
    --                Slog.i(TAG, "adding default package " + pkg + " (uid " + uid + " for user "
    --                        + userId + ") to restrict background whitelist");
    -+                if (LOGD)
    -+                    Slog.d(TAG, "adding default package " + pkg + " (uid " + uid + " for user "
    -+                            + userId + ") to restrict background whitelist");
    -                 mRestrictBackgroundWhitelistUids.append(uid, true);
    -                 changed = true;
    -             }
    -@@ -568,117 +569,125 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
    -     }
    - 
    -     public void systemReady() {
    --        if (!isBandwidthControlEnabled()) {
    --            Slog.w(TAG, "bandwidth controls disabled, unable to enforce policy");
    --            return;
    --        }
    --
    --        mUsageStats = LocalServices.getService(UsageStatsManagerInternal.class);
    -+        Trace.traceBegin(Trace.TRACE_TAG_NETWORK, "systemReady");
    -+        try {
    -+            if (!isBandwidthControlEnabled()) {
    -+                Slog.w(TAG, "bandwidth controls disabled, unable to enforce policy");
    -+                return;
    -+            }
    - 
    --        mPackageMonitor.register(mContext, mHandler.getLooper(), UserHandle.ALL, true);
    -+            mUsageStats = LocalServices.getService(UsageStatsManagerInternal.class);
    - 
    --        synchronized (mUidRulesFirstLock) {
    --            synchronized (mNetworkPoliciesSecondLock) {
    --                updatePowerSaveWhitelistUL();
    --                mPowerManagerInternal = LocalServices.getService(PowerManagerInternal.class);
    --                mPowerManagerInternal.registerLowPowerModeObserver(
    --                        new PowerManagerInternal.LowPowerModeListener() {
    --                    @Override
    --                    public void onLowPowerModeChanged(boolean enabled) {
    --                        if (LOGD) Slog.d(TAG, "onLowPowerModeChanged(" + enabled + ")");
    --                        synchronized (mUidRulesFirstLock) {
    --                            if (mRestrictPower != enabled) {
    --                                mRestrictPower = enabled;
    --                                updateRulesForRestrictPowerUL();
    -+            synchronized (mUidRulesFirstLock) {
    -+                synchronized (mNetworkPoliciesSecondLock) {
    -+                    updatePowerSaveWhitelistUL();
    -+                    mPowerManagerInternal = LocalServices.getService(PowerManagerInternal.class);
    -+                    mPowerManagerInternal.registerLowPowerModeObserver(
    -+                            new PowerManagerInternal.LowPowerModeListener() {
    -+                        @Override
    -+                        public void onLowPowerModeChanged(boolean enabled) {
    -+                            if (LOGD) Slog.d(TAG, "onLowPowerModeChanged(" + enabled + ")");
    -+                            synchronized (mUidRulesFirstLock) {
    -+                                if (mRestrictPower != enabled) {
    -+                                    mRestrictPower = enabled;
    -+                                    updateRulesForRestrictPowerUL();
    -+                                }
    -                             }
    -                         }
    --                    }
    --                });
    --                mRestrictPower = mPowerManagerInternal.getLowPowerModeEnabled();
    -+                    });
    -+                    mRestrictPower = mPowerManagerInternal.getLowPowerModeEnabled();
    - 
    --                mSystemReady = true;
    -+                    mSystemReady = true;
    - 
    --                // read policy from disk
    --                readPolicyAL();
    -+                    // read policy from disk
    -+                    readPolicyAL();
    - 
    --                if (addDefaultRestrictBackgroundWhitelistUidsUL()) {
    --                    writePolicyAL();
    --                }
    -+                    if (addDefaultRestrictBackgroundWhitelistUidsUL()) {
    -+                        writePolicyAL();
    -+                    }
    - 
    --                setRestrictBackgroundUL(mRestrictBackground);
    --                updateRulesForGlobalChangeAL(false);
    --                updateNotificationsNL();
    -+                    setRestrictBackgroundUL(mRestrictBackground);
    -+                    updateRulesForGlobalChangeAL(false);
    -+                    updateNotificationsNL();
    -+                }
    -             }
    --        }
    - 
    --        try {
    --            mActivityManager.registerUidObserver(mUidObserver,
    --                    ActivityManager.UID_OBSERVER_PROCSTATE|ActivityManager.UID_OBSERVER_GONE);
    --            mNetworkManager.registerObserver(mAlertObserver);
    --        } catch (RemoteException e) {
    --            // ignored; both services live in system_server
    -+            try {
    -+                mActivityManager.registerUidObserver(mUidObserver,
    -+                        ActivityManager.UID_OBSERVER_PROCSTATE|ActivityManager.UID_OBSERVER_GONE);
    -+                mNetworkManager.registerObserver(mAlertObserver);
    -+            } catch (RemoteException e) {
    -+                // ignored; both services live in system_server
    -+            }
    -+
    -+            // listen for changes to power save whitelist
    -+            final IntentFilter whitelistFilter = new IntentFilter(
    -+                    PowerManager.ACTION_POWER_SAVE_WHITELIST_CHANGED);
    -+            mContext.registerReceiver(mPowerSaveWhitelistReceiver, whitelistFilter, null, mHandler);
    -+
    -+            DeviceIdleController.LocalService deviceIdleService
    -+                    = LocalServices.getService(DeviceIdleController.LocalService.class);
    -+            deviceIdleService.setNetworkPolicyTempWhitelistCallback(mTempPowerSaveChangedCallback);
    -+
    -+            // watch for network interfaces to be claimed
    -+            final IntentFilter connFilter = new IntentFilter(CONNECTIVITY_ACTION);
    -+            mContext.registerReceiver(mConnReceiver, connFilter, CONNECTIVITY_INTERNAL, mHandler);
    -+
    -+            // listen for package changes to update policy
    -+            final IntentFilter packageFilter = new IntentFilter();
    -+            packageFilter.addAction(ACTION_PACKAGE_ADDED);
    -+            packageFilter.addDataScheme("package");
    -+            mContext.registerReceiver(mPackageReceiver, packageFilter, null, mHandler);
    -+
    -+            // listen for UID changes to update policy
    -+            mContext.registerReceiver(
    -+                    mUidRemovedReceiver, new IntentFilter(ACTION_UID_REMOVED), null, mHandler);
    -+
    -+            // listen for user changes to update policy
    -+            final IntentFilter userFilter = new IntentFilter();
    -+            userFilter.addAction(ACTION_USER_ADDED);
    -+            userFilter.addAction(ACTION_USER_REMOVED);
    -+            mContext.registerReceiver(mUserReceiver, userFilter, null, mHandler);
    -+
    -+            // listen for stats update events
    -+            final IntentFilter statsFilter = new IntentFilter(ACTION_NETWORK_STATS_UPDATED);
    -+            mContext.registerReceiver(
    -+                    mStatsReceiver, statsFilter, READ_NETWORK_USAGE_HISTORY, mHandler);
    -+
    -+            // listen for restrict background changes from notifications
    -+            final IntentFilter allowFilter = new IntentFilter(ACTION_ALLOW_BACKGROUND);
    -+            mContext.registerReceiver(mAllowReceiver, allowFilter, MANAGE_NETWORK_POLICY, mHandler);
    -+
    -+            // listen for snooze warning from notifications
    -+            final IntentFilter snoozeWarningFilter = new IntentFilter(ACTION_SNOOZE_WARNING);
    -+            mContext.registerReceiver(mSnoozeWarningReceiver, snoozeWarningFilter,
    -+                    MANAGE_NETWORK_POLICY, mHandler);
    -+
    -+            // listen for configured wifi networks to be removed
    -+            final IntentFilter wifiConfigFilter =
    -+                    new IntentFilter(CONFIGURED_NETWORKS_CHANGED_ACTION);
    -+            mContext.registerReceiver(mWifiConfigReceiver, wifiConfigFilter, null, mHandler);
    -+
    -+            // listen for wifi state changes to catch metered hint
    -+            final IntentFilter wifiStateFilter = new IntentFilter(
    -+                    WifiManager.NETWORK_STATE_CHANGED_ACTION);
    -+            mContext.registerReceiver(mWifiStateReceiver, wifiStateFilter, null, mHandler);
    -+
    -+            mUsageStats.addAppIdleStateChangeListener(new AppIdleStateChangeListener());
    -+        } finally {
    -+            Trace.traceEnd(Trace.TRACE_TAG_NETWORK);
    -         }
    --
    --        // listen for changes to power save whitelist
    --        final IntentFilter whitelistFilter = new IntentFilter(
    --                PowerManager.ACTION_POWER_SAVE_WHITELIST_CHANGED);
    --        mContext.registerReceiver(mPowerSaveWhitelistReceiver, whitelistFilter, null, mHandler);
    --
    --        DeviceIdleController.LocalService deviceIdleService
    --                = LocalServices.getService(DeviceIdleController.LocalService.class);
    --        deviceIdleService.setNetworkPolicyTempWhitelistCallback(mTempPowerSaveChangedCallback);
    --
    --        // watch for network interfaces to be claimed
    --        final IntentFilter connFilter = new IntentFilter(CONNECTIVITY_ACTION);
    --        mContext.registerReceiver(mConnReceiver, connFilter, CONNECTIVITY_INTERNAL, mHandler);
    --
    --        // listen for package changes to update policy
    --        final IntentFilter packageFilter = new IntentFilter();
    --        packageFilter.addAction(ACTION_PACKAGE_ADDED);
    --        packageFilter.addDataScheme("package");
    --        mContext.registerReceiver(mPackageReceiver, packageFilter, null, mHandler);
    --
    --        // listen for UID changes to update policy
    --        mContext.registerReceiver(
    --                mUidRemovedReceiver, new IntentFilter(ACTION_UID_REMOVED), null, mHandler);
    --
    --        // listen for user changes to update policy
    --        final IntentFilter userFilter = new IntentFilter();
    --        userFilter.addAction(ACTION_USER_ADDED);
    --        userFilter.addAction(ACTION_USER_REMOVED);
    --        mContext.registerReceiver(mUserReceiver, userFilter, null, mHandler);
    --
    --        // listen for stats update events
    --        final IntentFilter statsFilter = new IntentFilter(ACTION_NETWORK_STATS_UPDATED);
    --        mContext.registerReceiver(
    --                mStatsReceiver, statsFilter, READ_NETWORK_USAGE_HISTORY, mHandler);
    --
    --        // listen for restrict background changes from notifications
    --        final IntentFilter allowFilter = new IntentFilter(ACTION_ALLOW_BACKGROUND);
    --        mContext.registerReceiver(mAllowReceiver, allowFilter, MANAGE_NETWORK_POLICY, mHandler);
    --
    --        // listen for snooze warning from notifications
    --        final IntentFilter snoozeWarningFilter = new IntentFilter(ACTION_SNOOZE_WARNING);
    --        mContext.registerReceiver(mSnoozeWarningReceiver, snoozeWarningFilter,
    --                MANAGE_NETWORK_POLICY, mHandler);
    --
    --        // listen for configured wifi networks to be removed
    --        final IntentFilter wifiConfigFilter = new IntentFilter(CONFIGURED_NETWORKS_CHANGED_ACTION);
    --        mContext.registerReceiver(mWifiConfigReceiver, wifiConfigFilter, null, mHandler);
    --
    --        // listen for wifi state changes to catch metered hint
    --        final IntentFilter wifiStateFilter = new IntentFilter(
    --                WifiManager.NETWORK_STATE_CHANGED_ACTION);
    --        mContext.registerReceiver(mWifiStateReceiver, wifiStateFilter, null, mHandler);
    --
    --        mUsageStats.addAppIdleStateChangeListener(new AppIdleStateChangeListener());
    --
    -     }
    - 
    -     final private IUidObserver mUidObserver = new IUidObserver.Stub() {
    -         @Override public void onUidStateChanged(int uid, int procState) throws RemoteException {
    --            synchronized (mUidRulesFirstLock) {
    --                updateUidStateUL(uid, procState);
    -+            Trace.traceBegin(Trace.TRACE_TAG_NETWORK, "onUidStateChanged");
    -+            try {
    -+                synchronized (mUidRulesFirstLock) {
    -+                    updateUidStateUL(uid, procState);
    -+                }
    -+            } finally {
    -+                Trace.traceEnd(Trace.TRACE_TAG_NETWORK);
    -             }
    -         }
    - 
    -@@ -702,6 +711,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
    -             synchronized (mUidRulesFirstLock) {
    -                 updatePowerSaveWhitelistUL();
    -                 updateRulesForRestrictPowerUL();
    -+                updateRulesForAppIdleUL();
    -             }
    -         }
    -     };
    -@@ -749,6 +759,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
    -             if (LOGV) Slog.v(TAG, "ACTION_UID_REMOVED for uid=" + uid);
    -             synchronized (mUidRulesFirstLock) {
    -                 mUidPolicy.delete(uid);
    -+                removeRestrictBackgroundWhitelistedUidUL(uid, true, true);
    -                 updateRestrictionRulesForUidUL(uid);
    -                 synchronized (mNetworkPoliciesSecondLock) {
    -                     writePolicyAL();
    -@@ -1426,8 +1437,14 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
    -                 + "; generating default policy");
    - 
    -         // Build default mobile policy, and assume usage cycle starts today
    --        final long warningBytes = mContext.getResources().getInteger(
    --                com.android.internal.R.integer.config_networkPolicyDefaultWarning) * MB_IN_BYTES;
    -+        final int dataWarningConfig = mContext.getResources().getInteger(
    -+                com.android.internal.R.integer.config_networkPolicyDefaultWarning);
    -+        final long warningBytes;
    -+        if (dataWarningConfig == WARNING_DISABLED) {
    -+            warningBytes = WARNING_DISABLED;
    -+        } else {
    -+            warningBytes = dataWarningConfig * MB_IN_BYTES;
    -+        }
    - 
    -         final Time time = new Time();
    -         time.setToNow();
    -@@ -2044,7 +2061,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
    -         // Must whitelist foreground apps before turning data saver mode on.
    -         // TODO: there is no need to iterate through all apps here, just those in the foreground,
    -         // so it could call AM to get the UIDs of such apps, and iterate through them instead.
    --        updateRulesForAllAppsUL(TYPE_RESTRICT_BACKGROUND);
    -+        updateRulesForRestrictBackgroundUL();
    -         try {
    -             if (!mNetworkManager.setDataSaverModeEnabled(mRestrictBackground)) {
    -                 Slog.e(TAG, "Could not change Data Saver Mode on NMS to " + mRestrictBackground);
    -@@ -2201,21 +2218,26 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
    -     @Override
    -     public void setDeviceIdleMode(boolean enabled) {
    -         mContext.enforceCallingOrSelfPermission(MANAGE_NETWORK_POLICY, TAG);
    --
    --        synchronized (mUidRulesFirstLock) {
    --            if (mDeviceIdleMode != enabled) {
    -+        Trace.traceBegin(Trace.TRACE_TAG_NETWORK, "setDeviceIdleMode");
    -+        try {
    -+            synchronized (mUidRulesFirstLock) {
    -+                if (mDeviceIdleMode == enabled) {
    -+                    return;
    -+                }
    -                 mDeviceIdleMode = enabled;
    -                 if (mSystemReady) {
    -                     // Device idle change means we need to rebuild rules for all
    -                     // known apps, so do a global refresh.
    -                     updateRulesForRestrictPowerUL();
    -                 }
    --                if (enabled) {
    --                    EventLogTags.writeDeviceIdleOnPhase("net");
    --                } else {
    --                    EventLogTags.writeDeviceIdleOffPhase("net");
    --                }
    -             }
    -+            if (enabled) {
    -+                EventLogTags.writeDeviceIdleOnPhase("net");
    -+            } else {
    -+                EventLogTags.writeDeviceIdleOffPhase("net");
    -+            }
    -+        } finally {
    -+            Trace.traceEnd(Trace.TRACE_TAG_NETWORK);
    -         }
    -     }
    - 
    -@@ -2503,25 +2525,30 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
    -      * {@link #updateRulesForPowerRestrictionsUL(int)}
    -      */
    -     private void updateUidStateUL(int uid, int uidState) {
    --        final int oldUidState = mUidState.get(uid, ActivityManager.PROCESS_STATE_CACHED_EMPTY);
    --        if (oldUidState != uidState) {
    --            // state changed, push updated rules
    --            mUidState.put(uid, uidState);
    --            updateRestrictBackgroundRulesOnUidStatusChangedUL(uid, oldUidState, uidState);
    --            if (isProcStateAllowedWhileIdleOrPowerSaveMode(oldUidState)
    --                    != isProcStateAllowedWhileIdleOrPowerSaveMode(uidState) ) {
    --                if (isUidIdle(uid)) {
    --                    updateRuleForAppIdleUL(uid);
    --                }
    --                if (mDeviceIdleMode) {
    --                    updateRuleForDeviceIdleUL(uid);
    --                }
    --                if (mRestrictPower) {
    --                    updateRuleForRestrictPowerUL(uid);
    -+        Trace.traceBegin(Trace.TRACE_TAG_NETWORK, "updateUidStateUL");
    -+        try {
    -+            final int oldUidState = mUidState.get(uid, ActivityManager.PROCESS_STATE_CACHED_EMPTY);
    -+            if (oldUidState != uidState) {
    -+                // state changed, push updated rules
    -+                mUidState.put(uid, uidState);
    -+                updateRestrictBackgroundRulesOnUidStatusChangedUL(uid, oldUidState, uidState);
    -+                if (isProcStateAllowedWhileIdleOrPowerSaveMode(oldUidState)
    -+                        != isProcStateAllowedWhileIdleOrPowerSaveMode(uidState) ) {
    -+                    if (isUidIdle(uid)) {
    -+                        updateRuleForAppIdleUL(uid);
    -+                    }
    -+                    if (mDeviceIdleMode) {
    -+                        updateRuleForDeviceIdleUL(uid);
    -+                    }
    -+                    if (mRestrictPower) {
    -+                        updateRuleForRestrictPowerUL(uid);
    -+                    }
    -+                    updateRulesForPowerRestrictionsUL(uid);
    -                 }
    --                updateRulesForPowerRestrictionsUL(uid);
    -+                updateNetworkStats(uid, isUidStateForegroundUL(uidState));
    -             }
    --            updateNetworkStats(uid, isUidStateForegroundUL(uidState));
    -+        } finally {
    -+            Trace.traceEnd(Trace.TRACE_TAG_NETWORK);
    -         }
    -     }
    - 
    -@@ -2574,8 +2601,13 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
    -     }
    - 
    -     void updateRulesForPowerSaveUL() {
    --        updateRulesForWhitelistedPowerSaveUL(mRestrictPower, FIREWALL_CHAIN_POWERSAVE,
    --                mUidFirewallPowerSaveRules);
    -+        Trace.traceBegin(Trace.TRACE_TAG_NETWORK, "updateRulesForPowerSaveUL");
    -+        try {
    -+            updateRulesForWhitelistedPowerSaveUL(mRestrictPower, FIREWALL_CHAIN_POWERSAVE,
    -+                    mUidFirewallPowerSaveRules);
    -+        } finally {
    -+            Trace.traceEnd(Trace.TRACE_TAG_NETWORK);
    -+        }
    -     }
    - 
    -     void updateRuleForRestrictPowerUL(int uid) {
    -@@ -2583,8 +2615,13 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
    -     }
    - 
    -     void updateRulesForDeviceIdleUL() {
    --        updateRulesForWhitelistedPowerSaveUL(mDeviceIdleMode, FIREWALL_CHAIN_DOZABLE,
    --                mUidFirewallDozableRules);
    -+        Trace.traceBegin(Trace.TRACE_TAG_NETWORK, "updateRulesForDeviceIdleUL");
    -+        try {
    -+            updateRulesForWhitelistedPowerSaveUL(mDeviceIdleMode, FIREWALL_CHAIN_DOZABLE,
    -+                    mUidFirewallDozableRules);
    -+        } finally {
    -+            Trace.traceEnd(Trace.TRACE_TAG_NETWORK);
    -+        }
    -     }
    - 
    -     void updateRuleForDeviceIdleUL(int uid) {
    -@@ -2621,10 +2658,10 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
    -                     uidRules.put(mUidState.keyAt(i), FIREWALL_RULE_ALLOW);
    -                 }
    -             }
    --            setUidFirewallRules(chain, uidRules);
    -+            setUidFirewallRulesAsync(chain, uidRules, CHAIN_TOGGLE_ENABLE);
    -+        } else {
    -+            setUidFirewallRulesAsync(chain, null, CHAIN_TOGGLE_DISABLE);
    -         }
    --
    --        enableFirewallChainUL(chain, enabled);
    -     }
    - 
    -     private boolean isWhitelistedBatterySaverUL(int uid) {
    -@@ -2646,27 +2683,32 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
    -     }
    - 
    -     void updateRulesForAppIdleUL() {
    --        final SparseIntArray uidRules = mUidFirewallStandbyRules;
    --        uidRules.clear();
    -+        Trace.traceBegin(Trace.TRACE_TAG_NETWORK, "updateRulesForAppIdleUL");
    -+        try {
    -+            final SparseIntArray uidRules = mUidFirewallStandbyRules;
    -+            uidRules.clear();
    - 
    --        // Fully update the app idle firewall chain.
    --        final List<UserInfo> users = mUserManager.getUsers();
    --        for (int ui = users.size() - 1; ui >= 0; ui--) {
    --            UserInfo user = users.get(ui);
    --            int[] idleUids = mUsageStats.getIdleUidsForUser(user.id);
    --            for (int uid : idleUids) {
    --                if (!mPowerSaveTempWhitelistAppIds.get(UserHandle.getAppId(uid), false)) {
    --                    // quick check: if this uid doesn't have INTERNET permission, it
    --                    // doesn't have network access anyway, so it is a waste to mess
    --                    // with it here.
    --                    if (hasInternetPermissions(uid)) {
    --                        uidRules.put(uid, FIREWALL_RULE_DENY);
    -+            // Fully update the app idle firewall chain.
    -+            final List<UserInfo> users = mUserManager.getUsers();
    -+            for (int ui = users.size() - 1; ui >= 0; ui--) {
    -+                UserInfo user = users.get(ui);
    -+                int[] idleUids = mUsageStats.getIdleUidsForUser(user.id);
    -+                for (int uid : idleUids) {
    -+                    if (!mPowerSaveTempWhitelistAppIds.get(UserHandle.getAppId(uid), false)) {
    -+                        // quick check: if this uid doesn't have INTERNET permission, it
    -+                        // doesn't have network access anyway, so it is a waste to mess
    -+                        // with it here.
    -+                        if (hasInternetPermissions(uid)) {
    -+                            uidRules.put(uid, FIREWALL_RULE_DENY);
    -+                        }
    -                     }
    -                 }
    -             }
    --        }
    - 
    --        setUidFirewallRules(FIREWALL_CHAIN_STANDBY, uidRules);
    -+            setUidFirewallRulesAsync(FIREWALL_CHAIN_STANDBY, uidRules, CHAIN_TOGGLE_NONE);
    -+        } finally {
    -+            Trace.traceEnd(Trace.TRACE_TAG_NETWORK);
    -+        }
    -     }
    - 
    -     void updateRuleForAppIdleUL(int uid) {
    -@@ -2681,9 +2723,31 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
    -         }
    -     }
    - 
    -+    /**
    -+     * Toggle the firewall standby chain and inform listeners if the uid rules have effectively
    -+     * changed.
    -+     */
    -     void updateRulesForAppIdleParoleUL() {
    --        boolean enableChain = !mUsageStats.isAppIdleParoleOn();
    -+        boolean paroled = mUsageStats.isAppIdleParoleOn();
    -+        boolean enableChain = !paroled;
    -         enableFirewallChainUL(FIREWALL_CHAIN_STANDBY, enableChain);
    -+
    -+        int ruleCount = mUidFirewallStandbyRules.size();
    -+        for (int i = 0; i < ruleCount; i++) {
    -+            int uid = mUidFirewallStandbyRules.keyAt(i);
    -+            int oldRules = mUidRules.get(uid);
    -+            if (enableChain) {
    -+                // Chain wasn't enabled before and the other power-related
    -+                // chains are whitelists, so we can clear the
    -+                // MASK_ALL_NETWORKS part of the rules and re-inform listeners if
    -+                // the effective rules result in blocking network access.
    -+                oldRules &= MASK_METERED_NETWORKS;
    -+            } else {
    -+                // Skip if it had no restrictions to begin with
    -+                if ((oldRules & MASK_ALL_NETWORKS) == 0) continue;
    -+            }
    -+            updateRulesForPowerRestrictionsUL(uid, oldRules, paroled);
    -+        }
    -     }
    - 
    -     /**
    -@@ -2691,33 +2755,41 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
    -      * {@link #mRestrictPower}, or {@link #mDeviceIdleMode} value.
    -      */
    -     private void updateRulesForGlobalChangeAL(boolean restrictedNetworksChanged) {
    --        long start;
    --        if (LOGD) start = System.currentTimeMillis();
    --
    --        updateRulesForRestrictPowerUL();
    --        updateRulesForRestrictBackgroundUL();
    -+        Trace.traceBegin(Trace.TRACE_TAG_NETWORK, "updateRulesForGlobalChangeAL");
    -+        try {
    -+            updateRulesForAppIdleUL();
    -+            updateRulesForRestrictPowerUL();
    -+            updateRulesForRestrictBackgroundUL();
    - 
    --        // If the set of restricted networks may have changed, re-evaluate those.
    --        if (restrictedNetworksChanged) {
    --            normalizePoliciesNL();
    --            updateNetworkRulesNL();
    --        }
    --        if (LOGD) {
    --            final long delta = System.currentTimeMillis() - start;
    --            Slog.d(TAG, "updateRulesForGlobalChangeAL(" + restrictedNetworksChanged + ") took "
    --                    + delta + "ms");
    -+            // If the set of restricted networks may have changed, re-evaluate those.
    -+            if (restrictedNetworksChanged) {
    -+                normalizePoliciesNL();
    -+                updateNetworkRulesNL();
    -+            }
    -+        } finally {
    -+            Trace.traceEnd(Trace.TRACE_TAG_NETWORK);
    -         }
    -     }
    - 
    -+    // TODO: rename / document to make it clear these are global (not app-specific) rules
    -     private void updateRulesForRestrictPowerUL() {
    --        updateRulesForDeviceIdleUL();
    --        updateRulesForAppIdleUL();
    --        updateRulesForPowerSaveUL();
    --        updateRulesForAllAppsUL(TYPE_RESTRICT_POWER);
    -+        Trace.traceBegin(Trace.TRACE_TAG_NETWORK, "updateRulesForRestrictPowerUL");
    -+        try {
    -+            updateRulesForDeviceIdleUL();
    -+            updateRulesForPowerSaveUL();
    -+            updateRulesForAllAppsUL(TYPE_RESTRICT_POWER);
    -+        } finally {
    -+            Trace.traceEnd(Trace.TRACE_TAG_NETWORK);
    -+        }
    -     }
    - 
    -     private void updateRulesForRestrictBackgroundUL() {
    --        updateRulesForAllAppsUL(TYPE_RESTRICT_BACKGROUND);
    -+        Trace.traceBegin(Trace.TRACE_TAG_NETWORK, "updateRulesForRestrictBackgroundUL");
    -+        try {
    -+            updateRulesForAllAppsUL(TYPE_RESTRICT_BACKGROUND);
    -+        } finally {
    -+            Trace.traceEnd(Trace.TRACE_TAG_NETWORK);
    -+        }
    -     }
    - 
    -     private static final int TYPE_RESTRICT_BACKGROUND = 1;
    -@@ -2732,33 +2804,42 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
    - 
    -     // TODO: refactor / consolidate all those updateXyz methods, there are way too many of them...
    -     private void updateRulesForAllAppsUL(@RestrictType int type) {
    --        final PackageManager pm = mContext.getPackageManager();
    -+        if (Trace.isTagEnabled(Trace.TRACE_TAG_NETWORK)) {
    -+            Trace.traceBegin(Trace.TRACE_TAG_NETWORK, "updateRulesForRestrictPowerUL-" + type);
    -+        }
    -+        try {
    -+            final PackageManager pm = mContext.getPackageManager();
    - 
    --        // update rules for all installed applications
    --        final List<UserInfo> users = mUserManager.getUsers();
    --        final List<ApplicationInfo> apps = pm.getInstalledApplications(
    --                PackageManager.MATCH_UNINSTALLED_PACKAGES | PackageManager.MATCH_DISABLED_COMPONENTS
    --                        | PackageManager.MATCH_DIRECT_BOOT_AWARE
    --                        | PackageManager.MATCH_DIRECT_BOOT_UNAWARE);
    --
    --        final int usersSize = users.size();
    --        final int appsSize = apps.size();
    --        for (int i = 0; i < usersSize; i++) {
    --            final UserInfo user = users.get(i);
    --            for (int j = 0; j < appsSize; j++) {
    --                final ApplicationInfo app = apps.get(j);
    --                final int uid = UserHandle.getUid(user.id, app.uid);
    --                switch (type) {
    --                    case TYPE_RESTRICT_BACKGROUND:
    --                        updateRulesForDataUsageRestrictionsUL(uid);
    --                        break;
    --                    case TYPE_RESTRICT_POWER:
    --                        updateRulesForPowerRestrictionsUL(uid);
    --                        break;
    --                    default:
    --                        Slog.w(TAG, "Invalid type for updateRulesForAllApps: " + type);
    -+            // update rules for all installed applications
    -+            final List<UserInfo> users = mUserManager.getUsers();
    -+            final List<ApplicationInfo> apps = pm.getInstalledApplications(
    -+                    PackageManager.MATCH_UNINSTALLED_PACKAGES | PackageManager.MATCH_DISABLED_COMPONENTS
    -+                            | PackageManager.MATCH_DIRECT_BOOT_AWARE
    -+                            | PackageManager.MATCH_DIRECT_BOOT_UNAWARE);
    -+
    -+            final int usersSize = users.size();
    -+            final int appsSize = apps.size();
    -+            for (int i = 0; i < usersSize; i++) {
    -+                final UserInfo user = users.get(i);
    -+                for (int j = 0; j < appsSize; j++) {
    -+                    final ApplicationInfo app = apps.get(j);
    -+                    final int uid = UserHandle.getUid(user.id, app.uid);
    -+                    switch (type) {
    -+                        case TYPE_RESTRICT_BACKGROUND:
    -+                            updateRulesForDataUsageRestrictionsUL(uid);
    -+                            break;
    -+                        case TYPE_RESTRICT_POWER:
    -+                            updateRulesForPowerRestrictionsUL(uid);
    -+                            break;
    -+                        default:
    -+                            Slog.w(TAG, "Invalid type for updateRulesForAllApps: " + type);
    -+                    }
    -                 }
    -             }
    -+        } finally {
    -+            if (Trace.isTagEnabled(Trace.TRACE_TAG_NETWORK)) {
    -+                Trace.traceEnd(Trace.TRACE_TAG_NETWORK);
    -+            }
    -         }
    -     }
    - 
    -@@ -3020,14 +3101,34 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
    -      * <strong>NOTE: </strong>This method does not update the firewall rules on {@code netd}.
    -      */
    -     private void updateRulesForPowerRestrictionsUL(int uid) {
    -+        final int oldUidRules = mUidRules.get(uid, RULE_NONE);
    -+
    -+        final int newUidRules = updateRulesForPowerRestrictionsUL(uid, oldUidRules, false);
    -+
    -+        if (newUidRules == RULE_NONE) {
    -+            mUidRules.delete(uid);
    -+        } else {
    -+            mUidRules.put(uid, newUidRules);
    -+        }
    -+    }
    -+
    -+    /**
    -+     * Similar to above but ignores idle state if app standby is currently disabled by parole.
    -+     *
    -+     * @param uid the uid of the app to update rules for
    -+     * @param oldUidRules the current rules for the uid, in order to determine if there's a change
    -+     * @param paroled whether to ignore idle state of apps and only look at other restrictions.
    -+     *
    -+     * @return the new computed rules for the uid
    -+     */
    -+    private int updateRulesForPowerRestrictionsUL(int uid, int oldUidRules, boolean paroled) {
    -         if (!isUidValidForBlacklistRules(uid)) {
    -             if (LOGD) Slog.d(TAG, "no need to update restrict power rules for uid " + uid);
    --            return;
    -+            return RULE_NONE;
    -         }
    - 
    --        final boolean isIdle = isUidIdle(uid);
    -+        final boolean isIdle = !paroled && isUidIdle(uid);
    -         final boolean restrictMode = isIdle || mRestrictPower || mDeviceIdleMode;
    --        final int oldUidRules = mUidRules.get(uid, RULE_NONE);
    -         final boolean isForeground = isUidForegroundOnRestrictPowerUL(uid);
    - 
    -         final boolean isWhitelisted = isWhitelistedBatterySaverUL(uid);
    -@@ -3061,12 +3162,6 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
    -                     + ", oldUidRules=" + uidRulesToString(oldUidRules));
    -         }
    - 
    --        if (newUidRules == RULE_NONE) {
    --            mUidRules.delete(uid);
    --        } else {
    --            mUidRules.put(uid, newUidRules);
    --        }
    --
    -         // Second step: notify listeners if state changed.
    -         if (newRule != oldRule) {
    -             if (newRule == RULE_NONE || (newRule & RULE_ALLOW_ALL) != 0) {
    -@@ -3083,6 +3178,8 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
    -             }
    -             mHandler.obtainMessage(MSG_RULES_CHANGED, uid, newUidRules).sendToTarget();
    -         }
    -+
    -+        return newUidRules;
    -     }
    - 
    -     private class AppIdleStateChangeListener
    -@@ -3302,6 +3399,18 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
    -                     removeInterfaceQuota((String) msg.obj);
    -                     return true;
    -                 }
    -+                case MSG_SET_FIREWALL_RULES: {
    -+                    final int chain = msg.arg1;
    -+                    final int toggle = msg.arg2;
    -+                    final SparseIntArray uidRules = (SparseIntArray) msg.obj;
    -+                    if (uidRules != null) {
    -+                        setUidFirewallRules(chain, uidRules);
    -+                    }
    -+                    if (toggle != CHAIN_TOGGLE_NONE) {
    -+                        enableFirewallChainUL(chain, toggle == CHAIN_TOGGLE_ENABLE);
    -+                    }
    -+                    return true;
    -+                }
    -                 default: {
    -                     return false;
    -                 }
    -@@ -3351,6 +3460,31 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
    -         }
    -     }
    - 
    -+    private static final int CHAIN_TOGGLE_NONE = 0;
    -+    private static final int CHAIN_TOGGLE_ENABLE = 1;
    -+    private static final int CHAIN_TOGGLE_DISABLE = 2;
    -+    @Retention(RetentionPolicy.SOURCE)
    -+    @IntDef(flag = false, value = {
    -+            CHAIN_TOGGLE_NONE,
    -+            CHAIN_TOGGLE_ENABLE,
    -+            CHAIN_TOGGLE_DISABLE
    -+    })
    -+    public @interface ChainToggleType {
    -+    }
    -+
    -+    /**
    -+     * Calls {@link #setUidFirewallRules(int, SparseIntArray)} and
    -+     * {@link #enableFirewallChainUL(int, boolean)} asynchronously.
    -+     *
    -+     * @param chain firewall chain.
    -+     * @param uidRules new UID rules; if {@code null}, only toggles chain state.
    -+     * @param toggle whether the chain should be enabled, disabled, or not changed.
    -+     */
    -+    private void setUidFirewallRulesAsync(int chain, @Nullable SparseIntArray uidRules,
    -+            @ChainToggleType int toggle) {
    -+        mHandler.obtainMessage(MSG_SET_FIREWALL_RULES, chain, toggle, uidRules).sendToTarget();
    -+    }
    -+
    -     /**
    -      * Set uid rules on a particular firewall chain. This is going to synchronize the rules given
    -      * here to netd.  It will clean up dead rules and make sure the target chain only contains rules
    -@@ -3521,18 +3655,6 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
    -         }
    -     }
    - 
    --    private class MyPackageMonitor extends PackageMonitor {
    --
    --        @Override
    --        public void onPackageRemoved(String packageName, int uid) {
    --            if (LOGV) Slog.v(TAG, "onPackageRemoved: " + packageName + " ->" + uid);
    --            synchronized (mUidRulesFirstLock) {
    --                removeRestrictBackgroundWhitelistedUidUL(uid, true, true);
    --                updateRestrictionRulesForUidUL(uid);
    --            }
    --        }
    --    }
    --
    -     private class NetworkPolicyManagerInternalImpl extends NetworkPolicyManagerInternal {
    - 
    -         @Override
    -diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
    -index bb55240..eb85f19 100644
    ---- a/services/core/java/com/android/server/notification/NotificationManagerService.java
    -+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
    -@@ -58,7 +58,6 @@ import android.app.Notification;
    - import android.app.NotificationManager;
    - import android.app.NotificationManager.Policy;
    - import android.app.PendingIntent;
    --import android.app.RemoteInput;
    - import android.app.StatusBarManager;
    - import android.app.backup.BackupManager;
    - import android.app.usage.UsageEvents;
    -@@ -93,7 +92,6 @@ import android.os.IBinder;
    - import android.os.IInterface;
    - import android.os.Looper;
    - import android.os.Message;
    --import android.os.Parcelable;
    - import android.os.Process;
    - import android.os.RemoteException;
    - import android.os.SystemClock;
    -@@ -122,6 +120,8 @@ import android.util.Log;
    - import android.util.Slog;
    - import android.util.SparseArray;
    - import android.util.Xml;
    -+import android.view.WindowManager;
    -+import android.view.WindowManagerInternal;
    - import android.view.accessibility.AccessibilityEvent;
    - import android.view.accessibility.AccessibilityManager;
    - import android.widget.Toast;
    -@@ -138,6 +138,7 @@ import com.android.server.SystemService;
    - import com.android.server.lights.Light;
    - import com.android.server.lights.LightsManager;
    - import com.android.server.notification.ManagedServices.ManagedServiceInfo;
    -+import com.android.server.policy.PhoneWindowManager;
    - import com.android.server.statusbar.StatusBarManagerInternal;
    - import com.android.server.vr.VrManagerInternal;
    - import com.android.server.notification.ManagedServices.UserProfiles;
    -@@ -193,7 +194,7 @@ public class NotificationManagerService extends SystemService {
    -     private static final int MESSAGE_RECONSIDER_RANKING = 1000;
    -     private static final int MESSAGE_RANKING_SORT = 1001;
    - 
    --    static final int LONG_DELAY = 3500; // 3.5 seconds
    -+    static final int LONG_DELAY = PhoneWindowManager.TOAST_WINDOW_TIMEOUT;
    -     static final int SHORT_DELAY = 2000; // 2 seconds
    - 
    -     static final long[] DEFAULT_VIBRATE_PATTERN = {0, 250, 250, 250};
    -@@ -232,6 +233,7 @@ public class NotificationManagerService extends SystemService {
    -     @Nullable StatusBarManagerInternal mStatusBar;
    -     Vibrator mVibrator;
    -     private VrManagerInternal mVrManagerInternal;
    -+    private WindowManagerInternal mWindowManagerInternal;
    - 
    -     final IBinder mForegroundToken = new Binder();
    -     private Handler mHandler;
    -@@ -452,13 +454,15 @@ public class NotificationManagerService extends SystemService {
    -         final String pkg;
    -         final ITransientNotification callback;
    -         int duration;
    -+        Binder token;
    - 
    --        ToastRecord(int pid, String pkg, ITransientNotification callback, int duration)
    --        {
    -+        ToastRecord(int pid, String pkg, ITransientNotification callback, int duration,
    -+                    Binder token) {
    -             this.pid = pid;
    -             this.pkg = pkg;
    -             this.callback = callback;
    -             this.duration = duration;
    -+            this.token = token;
    -         }
    - 
    -         void update(int duration) {
    -@@ -1125,6 +1129,7 @@ public class NotificationManagerService extends SystemService {
    -             mAudioManager = (AudioManager) getContext().getSystemService(Context.AUDIO_SERVICE);
    -             mAudioManagerInternal = getLocalService(AudioManagerInternal.class);
    -             mVrManagerInternal = getLocalService(VrManagerInternal.class);
    -+            mWindowManagerInternal = LocalServices.getService(WindowManagerInternal.class);
    -             mZenModeHelper.onSystemReady();
    -         } else if (phase == SystemService.PHASE_THIRD_PARTY_APPS_CAN_START) {
    -             // This observer will force an update when observe is called, causing us to
    -@@ -1325,10 +1330,13 @@ public class NotificationManagerService extends SystemService {
    -                             }
    -                         }
    - 
    --                        record = new ToastRecord(callingPid, pkg, callback, duration);
    -+                        Binder token = new Binder();
    -+                        mWindowManagerInternal.addWindowToken(token,
    -+                                WindowManager.LayoutParams.TYPE_TOAST);
    -+                        record = new ToastRecord(callingPid, pkg, callback, duration, token);
    -                         mToastQueue.add(record);
    -                         index = mToastQueue.size() - 1;
    --                        keepProcessAliveLocked(callingPid);
    -+                        keepProcessAliveIfNeededLocked(callingPid);
    -                     }
    -                     // If it's at index 0, it's the current toast.  It doesn't matter if it's
    -                     // new or just been updated.  Call back and tell it to show itself.
    -@@ -2991,7 +2999,7 @@ public class NotificationManagerService extends SystemService {
    -         while (record != null) {
    -             if (DBG) Slog.d(TAG, "Show pkg=" + record.pkg + " callback=" + record.callback);
    -             try {
    --                record.callback.show();
    -+                record.callback.show(record.token);
    -                 scheduleTimeoutLocked(record);
    -                 return;
    -             } catch (RemoteException e) {
    -@@ -3002,7 +3010,7 @@ public class NotificationManagerService extends SystemService {
    -                 if (index >= 0) {
    -                     mToastQueue.remove(index);
    -                 }
    --                keepProcessAliveLocked(record.pid);
    -+                keepProcessAliveIfNeededLocked(record.pid);
    -                 if (mToastQueue.size() > 0) {
    -                     record = mToastQueue.get(0);
    -                 } else {
    -@@ -3022,8 +3030,11 @@ public class NotificationManagerService extends SystemService {
    -             // don't worry about this, we're about to remove it from
    -             // the list anyway
    -         }
    --        mToastQueue.remove(index);
    --        keepProcessAliveLocked(record.pid);
    -+
    -+        ToastRecord lastToast = mToastQueue.remove(index);
    -+        mWindowManagerInternal.removeWindowToken(lastToast.token, true);
    -+
    -+        keepProcessAliveIfNeededLocked(record.pid);
    -         if (mToastQueue.size() > 0) {
    -             // Show the next one. If the callback fails, this will remove
    -             // it from the list, so don't assume that the list hasn't changed
    -@@ -3067,7 +3078,7 @@ public class NotificationManagerService extends SystemService {
    -     }
    - 
    -     // lock on mToastQueue
    --    void keepProcessAliveLocked(int pid)
    -+    void keepProcessAliveIfNeededLocked(int pid)
    -     {
    -         int toastCount = 0; // toasts from this pid
    -         ArrayList<ToastRecord> list = mToastQueue;
    -diff --git a/services/core/java/com/android/server/notification/ZenModeConditions.java b/services/core/java/com/android/server/notification/ZenModeConditions.java
    -index 1c12a96..40b0be2 100644
    ---- a/services/core/java/com/android/server/notification/ZenModeConditions.java
    -+++ b/services/core/java/com/android/server/notification/ZenModeConditions.java
    -@@ -99,7 +99,7 @@ public class ZenModeConditions implements ConditionProviders.Callback {
    -     @Override
    -     public void onServiceAdded(ComponentName component) {
    -         if (DEBUG) Log.d(TAG, "onServiceAdded " + component);
    --        mHelper.setConfigAsync(mHelper.getConfig(), "zmc.onServiceAdded");
    -+        mHelper.setConfig(mHelper.getConfig(), "zmc.onServiceAdded");
    -     }
    - 
    -     @Override
    -@@ -113,7 +113,7 @@ public class ZenModeConditions implements ConditionProviders.Callback {
    -             updated |= updateSnoozing(automaticRule);
    -         }
    -         if (updated) {
    --            mHelper.setConfigAsync(config, "conditionChanged");
    -+            mHelper.setConfig(config, "conditionChanged");
    -         }
    -     }
    - 
    -diff --git a/services/core/java/com/android/server/notification/ZenModeHelper.java b/services/core/java/com/android/server/notification/ZenModeHelper.java
    -index c22bfb3..15549d2 100644
    ---- a/services/core/java/com/android/server/notification/ZenModeHelper.java
    -+++ b/services/core/java/com/android/server/notification/ZenModeHelper.java
    -@@ -35,6 +35,7 @@ import android.content.pm.ServiceInfo;
    - import android.content.res.Resources;
    - import android.content.res.XmlResourceParser;
    - import android.database.ContentObserver;
    -+import android.media.AudioAttributes;
    - import android.media.AudioManager;
    - import android.media.AudioManagerInternal;
    - import android.media.AudioSystem;
    -@@ -619,8 +620,10 @@ public class ZenModeHelper {
    -         return setConfigLocked(config, reason, true /*setRingerMode*/);
    -     }
    - 
    --    public void setConfigAsync(ZenModeConfig config, String reason) {
    --        mHandler.postSetConfig(config, reason);
    -+    public void setConfig(ZenModeConfig config, String reason) {
    -+        synchronized (mConfig) {
    -+            setConfigLocked(config, reason);
    -+        }
    -     }
    - 
    -     private boolean setConfigLocked(ZenModeConfig config, String reason, boolean setRingerMode) {
    -@@ -736,13 +739,14 @@ public class ZenModeHelper {
    -         // total silence restrictions
    -         final boolean muteEverything = mZenMode == Global.ZEN_MODE_NO_INTERRUPTIONS;
    - 
    --        for (int i = USAGE_UNKNOWN; i <= USAGE_VIRTUAL_SOURCE; i++) {
    --            if (i == USAGE_NOTIFICATION) {
    --                applyRestrictions(muteNotifications || muteEverything, i);
    --            } else if (i == USAGE_NOTIFICATION_RINGTONE) {
    --                applyRestrictions(muteCalls || muteEverything, i);
    -+        for (int usage : AudioAttributes.SDK_USAGES) {
    -+            final int suppressionBehavior = AudioAttributes.SUPPRESSIBLE_USAGES.get(usage);
    -+            if (suppressionBehavior == AudioAttributes.SUPPRESSIBLE_NOTIFICATION) {
    -+                applyRestrictions(muteNotifications || muteEverything, usage);
    -+            } else if (suppressionBehavior == AudioAttributes.SUPPRESSIBLE_CALL) {
    -+                applyRestrictions(muteCalls || muteEverything, usage);
    -             } else {
    --                applyRestrictions(muteEverything, i);
    -+                applyRestrictions(muteEverything, usage);
    -             }
    -         }
    -     }
    -@@ -1082,7 +1086,6 @@ public class ZenModeHelper {
    -     private final class H extends Handler {
    -         private static final int MSG_DISPATCH = 1;
    -         private static final int MSG_METRICS = 2;
    --        private static final int MSG_SET_CONFIG = 3;
    -         private static final int MSG_APPLY_CONFIG = 4;
    - 
    -         private final class ConfigMessageData {
    -@@ -1090,12 +1093,6 @@ public class ZenModeHelper {
    -             public final String reason;
    -             public final boolean setRingerMode;
    - 
    --            ConfigMessageData(ZenModeConfig config, String reason) {
    --                this.config = config;
    --                this.reason = reason;
    --                this.setRingerMode = false;
    --            }
    --
    -             ConfigMessageData(ZenModeConfig config, String reason, boolean setRingerMode) {
    -                 this.config = config;
    -                 this.reason = reason;
    -@@ -1119,10 +1116,6 @@ public class ZenModeHelper {
    -             sendEmptyMessageDelayed(MSG_METRICS, METRICS_PERIOD_MS);
    -         }
    - 
    --        private void postSetConfig(ZenModeConfig config, String reason) {
    --            sendMessage(obtainMessage(MSG_SET_CONFIG, new ConfigMessageData(config, reason)));
    --        }
    --
    -         private void postApplyConfig(ZenModeConfig config, String reason, boolean setRingerMode) {
    -             sendMessage(obtainMessage(MSG_APPLY_CONFIG,
    -                     new ConfigMessageData(config, reason, setRingerMode)));
    -@@ -1137,12 +1130,6 @@ public class ZenModeHelper {
    -                 case MSG_METRICS:
    -                     mMetrics.emit();
    -                     break;
    --                case MSG_SET_CONFIG:
    --                    ConfigMessageData configData = (ConfigMessageData) msg.obj;
    --                    synchronized (mConfig) {
    --                        setConfigLocked(configData.config, configData.reason);
    --                    }
    --                    break;
    -                 case MSG_APPLY_CONFIG:
    -                     ConfigMessageData applyConfigData = (ConfigMessageData) msg.obj;
    -                     applyConfig(applyConfigData.config, applyConfigData.reason,
    -diff --git a/services/core/java/com/android/server/pm/EphemeralResolverConnection.java b/services/core/java/com/android/server/pm/EphemeralResolverConnection.java
    -index 8d926f5..a6a3774 100644
    ---- a/services/core/java/com/android/server/pm/EphemeralResolverConnection.java
    -+++ b/services/core/java/com/android/server/pm/EphemeralResolverConnection.java
    -@@ -56,11 +56,12 @@ final class EphemeralResolverConnection {
    -     /** Intent used to bind to the service */
    -     private final Intent mIntent;
    - 
    -+    private volatile boolean mBindRequested;
    -     private IEphemeralResolver mRemoteInstance;
    - 
    -     public EphemeralResolverConnection(Context context, ComponentName componentName) {
    -         mContext = context;
    --        mIntent = new Intent().setComponent(componentName);
    -+        mIntent = new Intent(Intent.ACTION_RESOLVE_EPHEMERAL_PACKAGE).setComponent(componentName);
    -     }
    - 
    -     public final List<EphemeralResolveInfo> getEphemeralResolveInfoList(
    -@@ -111,8 +112,11 @@ final class EphemeralResolverConnection {
    -             return;
    -         }
    - 
    --        mContext.bindServiceAsUser(mIntent, mServiceConnection,
    --                Context.BIND_AUTO_CREATE | Context.BIND_FOREGROUND_SERVICE, UserHandle.SYSTEM);
    -+        if (!mBindRequested) {
    -+            mBindRequested = true;
    -+            mContext.bindServiceAsUser(mIntent, mServiceConnection,
    -+                    Context.BIND_AUTO_CREATE | Context.BIND_FOREGROUND_SERVICE, UserHandle.SYSTEM);
    -+        }
    - 
    -         final long startMillis = SystemClock.uptimeMillis();
    -         while (true) {
    -diff --git a/services/core/java/com/android/server/pm/Installer.java b/services/core/java/com/android/server/pm/Installer.java
    -index 72c549f..2e18b1c 100644
    ---- a/services/core/java/com/android/server/pm/Installer.java
    -+++ b/services/core/java/com/android/server/pm/Installer.java
    -@@ -230,6 +230,11 @@ public final class Installer extends SystemService {
    -         mInstaller.execute("move_ab", apkPath, instructionSet, outputPath);
    -     }
    - 
    -+    public void deleteOdex(String apkPath, String instructionSet, String outputPath)
    -+            throws InstallerException {
    -+        mInstaller.execute("delete_odex", apkPath, instructionSet, outputPath);
    -+    }
    -+
    -     private static void assertValidInstructionSet(String instructionSet)
    -             throws InstallerException {
    -         for (String abi : Build.SUPPORTED_ABIS) {
    -diff --git a/services/core/java/com/android/server/pm/LauncherAppsService.java b/services/core/java/com/android/server/pm/LauncherAppsService.java
    -index 53e328c..4387e76 100644
    ---- a/services/core/java/com/android/server/pm/LauncherAppsService.java
    -+++ b/services/core/java/com/android/server/pm/LauncherAppsService.java
    -@@ -631,17 +631,20 @@ public class LauncherAppsService extends SystemService {
    -             public void onPackageAdded(String packageName, int uid) {
    -                 UserHandle user = new UserHandle(getChangingUserId());
    -                 final int n = mListeners.beginBroadcast();
    --                for (int i = 0; i < n; i++) {
    --                    IOnAppsChangedListener listener = mListeners.getBroadcastItem(i);
    --                    BroadcastCookie cookie = (BroadcastCookie) mListeners.getBroadcastCookie(i);
    --                    if (!isEnabledProfileOf(user, cookie.user, "onPackageAdded")) continue;
    --                    try {
    --                        listener.onPackageAdded(user, packageName);
    --                    } catch (RemoteException re) {
    --                        Slog.d(TAG, "Callback failed ", re);
    -+                try {
    -+                    for (int i = 0; i < n; i++) {
    -+                        IOnAppsChangedListener listener = mListeners.getBroadcastItem(i);
    -+                        BroadcastCookie cookie = (BroadcastCookie) mListeners.getBroadcastCookie(i);
    -+                        if (!isEnabledProfileOf(user, cookie.user, "onPackageAdded")) continue;
    -+                        try {
    -+                            listener.onPackageAdded(user, packageName);
    -+                        } catch (RemoteException re) {
    -+                            Slog.d(TAG, "Callback failed ", re);
    -+                        }
    -                     }
    -+                } finally {
    -+                    mListeners.finishBroadcast();
    -                 }
    --                mListeners.finishBroadcast();
    - 
    -                 super.onPackageAdded(packageName, uid);
    -             }
    -@@ -650,17 +653,20 @@ public class LauncherAppsService extends SystemService {
    -             public void onPackageRemoved(String packageName, int uid) {
    -                 UserHandle user = new UserHandle(getChangingUserId());
    -                 final int n = mListeners.beginBroadcast();
    --                for (int i = 0; i < n; i++) {
    --                    IOnAppsChangedListener listener = mListeners.getBroadcastItem(i);
    --                    BroadcastCookie cookie = (BroadcastCookie) mListeners.getBroadcastCookie(i);
    --                    if (!isEnabledProfileOf(user, cookie.user, "onPackageRemoved")) continue;
    --                    try {
    --                        listener.onPackageRemoved(user, packageName);
    --                    } catch (RemoteException re) {
    --                        Slog.d(TAG, "Callback failed ", re);
    -+                try {
    -+                    for (int i = 0; i < n; i++) {
    -+                        IOnAppsChangedListener listener = mListeners.getBroadcastItem(i);
    -+                        BroadcastCookie cookie = (BroadcastCookie) mListeners.getBroadcastCookie(i);
    -+                        if (!isEnabledProfileOf(user, cookie.user, "onPackageRemoved")) continue;
    -+                        try {
    -+                            listener.onPackageRemoved(user, packageName);
    -+                        } catch (RemoteException re) {
    -+                            Slog.d(TAG, "Callback failed ", re);
    -+                        }
    -                     }
    -+                } finally {
    -+                    mListeners.finishBroadcast();
    -                 }
    --                mListeners.finishBroadcast();
    - 
    -                 super.onPackageRemoved(packageName, uid);
    -             }
    -@@ -669,17 +675,20 @@ public class LauncherAppsService extends SystemService {
    -             public void onPackageModified(String packageName) {
    -                 UserHandle user = new UserHandle(getChangingUserId());
    -                 final int n = mListeners.beginBroadcast();
    --                for (int i = 0; i < n; i++) {
    --                    IOnAppsChangedListener listener = mListeners.getBroadcastItem(i);
    --                    BroadcastCookie cookie = (BroadcastCookie) mListeners.getBroadcastCookie(i);
    --                    if (!isEnabledProfileOf(user, cookie.user, "onPackageModified")) continue;
    --                    try {
    --                        listener.onPackageChanged(user, packageName);
    --                    } catch (RemoteException re) {
    --                        Slog.d(TAG, "Callback failed ", re);
    -+                try {
    -+                    for (int i = 0; i < n; i++) {
    -+                        IOnAppsChangedListener listener = mListeners.getBroadcastItem(i);
    -+                        BroadcastCookie cookie = (BroadcastCookie) mListeners.getBroadcastCookie(i);
    -+                        if (!isEnabledProfileOf(user, cookie.user, "onPackageModified")) continue;
    -+                        try {
    -+                            listener.onPackageChanged(user, packageName);
    -+                        } catch (RemoteException re) {
    -+                            Slog.d(TAG, "Callback failed ", re);
    -+                        }
    -                     }
    -+                } finally {
    -+                    mListeners.finishBroadcast();
    -                 }
    --                mListeners.finishBroadcast();
    - 
    -                 super.onPackageModified(packageName);
    -             }
    -@@ -688,17 +697,20 @@ public class LauncherAppsService extends SystemService {
    -             public void onPackagesAvailable(String[] packages) {
    -                 UserHandle user = new UserHandle(getChangingUserId());
    -                 final int n = mListeners.beginBroadcast();
    --                for (int i = 0; i < n; i++) {
    --                    IOnAppsChangedListener listener = mListeners.getBroadcastItem(i);
    --                    BroadcastCookie cookie = (BroadcastCookie) mListeners.getBroadcastCookie(i);
    --                    if (!isEnabledProfileOf(user, cookie.user, "onPackagesAvailable")) continue;
    --                    try {
    --                        listener.onPackagesAvailable(user, packages, isReplacing());
    --                    } catch (RemoteException re) {
    --                        Slog.d(TAG, "Callback failed ", re);
    -+                try {
    -+                    for (int i = 0; i < n; i++) {
    -+                        IOnAppsChangedListener listener = mListeners.getBroadcastItem(i);
    -+                        BroadcastCookie cookie = (BroadcastCookie) mListeners.getBroadcastCookie(i);
    -+                        if (!isEnabledProfileOf(user, cookie.user, "onPackagesAvailable")) continue;
    -+                        try {
    -+                            listener.onPackagesAvailable(user, packages, isReplacing());
    -+                        } catch (RemoteException re) {
    -+                            Slog.d(TAG, "Callback failed ", re);
    -+                        }
    -                     }
    -+                } finally {
    -+                    mListeners.finishBroadcast();
    -                 }
    --                mListeners.finishBroadcast();
    - 
    -                 super.onPackagesAvailable(packages);
    -             }
    -@@ -707,17 +719,20 @@ public class LauncherAppsService extends SystemService {
    -             public void onPackagesUnavailable(String[] packages) {
    -                 UserHandle user = new UserHandle(getChangingUserId());
    -                 final int n = mListeners.beginBroadcast();
    --                for (int i = 0; i < n; i++) {
    --                    IOnAppsChangedListener listener = mListeners.getBroadcastItem(i);
    --                    BroadcastCookie cookie = (BroadcastCookie) mListeners.getBroadcastCookie(i);
    --                    if (!isEnabledProfileOf(user, cookie.user, "onPackagesUnavailable")) continue;
    --                    try {
    --                        listener.onPackagesUnavailable(user, packages, isReplacing());
    --                    } catch (RemoteException re) {
    --                        Slog.d(TAG, "Callback failed ", re);
    -+                try {
    -+                    for (int i = 0; i < n; i++) {
    -+                        IOnAppsChangedListener listener = mListeners.getBroadcastItem(i);
    -+                        BroadcastCookie cookie = (BroadcastCookie) mListeners.getBroadcastCookie(i);
    -+                        if (!isEnabledProfileOf(user, cookie.user, "onPackagesUnavailable")) continue;
    -+                        try {
    -+                            listener.onPackagesUnavailable(user, packages, isReplacing());
    -+                        } catch (RemoteException re) {
    -+                            Slog.d(TAG, "Callback failed ", re);
    -+                        }
    -                     }
    -+                } finally {
    -+                    mListeners.finishBroadcast();
    -                 }
    --                mListeners.finishBroadcast();
    - 
    -                 super.onPackagesUnavailable(packages);
    -             }
    -@@ -726,17 +741,20 @@ public class LauncherAppsService extends SystemService {
    -             public void onPackagesSuspended(String[] packages) {
    -                 UserHandle user = new UserHandle(getChangingUserId());
    -                 final int n = mListeners.beginBroadcast();
    --                for (int i = 0; i < n; i++) {
    --                    IOnAppsChangedListener listener = mListeners.getBroadcastItem(i);
    --                    BroadcastCookie cookie = (BroadcastCookie) mListeners.getBroadcastCookie(i);
    --                    if (!isEnabledProfileOf(user, cookie.user, "onPackagesSuspended")) continue;
    --                    try {
    --                        listener.onPackagesSuspended(user, packages);
    --                    } catch (RemoteException re) {
    --                        Slog.d(TAG, "Callback failed ", re);
    -+                try {
    -+                    for (int i = 0; i < n; i++) {
    -+                        IOnAppsChangedListener listener = mListeners.getBroadcastItem(i);
    -+                        BroadcastCookie cookie = (BroadcastCookie) mListeners.getBroadcastCookie(i);
    -+                        if (!isEnabledProfileOf(user, cookie.user, "onPackagesSuspended")) continue;
    -+                        try {
    -+                            listener.onPackagesSuspended(user, packages);
    -+                        } catch (RemoteException re) {
    -+                            Slog.d(TAG, "Callback failed ", re);
    -+                        }
    -                     }
    -+                } finally {
    -+                    mListeners.finishBroadcast();
    -                 }
    --                mListeners.finishBroadcast();
    - 
    -                 super.onPackagesSuspended(packages);
    -             }
    -@@ -745,17 +763,20 @@ public class LauncherAppsService extends SystemService {
    -             public void onPackagesUnsuspended(String[] packages) {
    -                 UserHandle user = new UserHandle(getChangingUserId());
    -                 final int n = mListeners.beginBroadcast();
    --                for (int i = 0; i < n; i++) {
    --                    IOnAppsChangedListener listener = mListeners.getBroadcastItem(i);
    --                    BroadcastCookie cookie = (BroadcastCookie) mListeners.getBroadcastCookie(i);
    --                    if (!isEnabledProfileOf(user, cookie.user, "onPackagesUnsuspended")) continue;
    --                    try {
    --                        listener.onPackagesUnsuspended(user, packages);
    --                    } catch (RemoteException re) {
    --                        Slog.d(TAG, "Callback failed ", re);
    -+                try {
    -+                    for (int i = 0; i < n; i++) {
    -+                        IOnAppsChangedListener listener = mListeners.getBroadcastItem(i);
    -+                        BroadcastCookie cookie = (BroadcastCookie) mListeners.getBroadcastCookie(i);
    -+                        if (!isEnabledProfileOf(user, cookie.user, "onPackagesUnsuspended")) continue;
    -+                        try {
    -+                            listener.onPackagesUnsuspended(user, packages);
    -+                        } catch (RemoteException re) {
    -+                            Slog.d(TAG, "Callback failed ", re);
    -+                        }
    -                     }
    -+                } finally {
    -+                    mListeners.finishBroadcast();
    -                 }
    --                mListeners.finishBroadcast();
    - 
    -                 super.onPackagesUnsuspended(packages);
    -             }
    -@@ -768,10 +789,10 @@ public class LauncherAppsService extends SystemService {
    - 
    -             private void onShortcutChangedInner(@NonNull String packageName,
    -                     @UserIdInt int userId) {
    -+                final int n = mListeners.beginBroadcast();
    -                 try {
    -                     final UserHandle user = UserHandle.of(userId);
    - 
    --                    final int n = mListeners.beginBroadcast();
    -                     for (int i = 0; i < n; i++) {
    -                         IOnAppsChangedListener listener = mListeners.getBroadcastItem(i);
    -                         BroadcastCookie cookie = (BroadcastCookie) mListeners.getBroadcastCookie(i);
    -@@ -803,10 +824,11 @@ public class LauncherAppsService extends SystemService {
    -                             Slog.d(TAG, "Callback failed ", re);
    -                         }
    -                     }
    --                    mListeners.finishBroadcast();
    -                 } catch (RuntimeException e) {
    -                     // When the user is locked we get IllegalState, so just catch all.
    -                     Log.w(TAG, e.getMessage(), e);
    -+                } finally {
    -+                    mListeners.finishBroadcast();
    -                 }
    -             }
    -         }
    -diff --git a/services/core/java/com/android/server/pm/OtaDexoptService.java b/services/core/java/com/android/server/pm/OtaDexoptService.java
    -index bff6d2d..689917c 100644
    ---- a/services/core/java/com/android/server/pm/OtaDexoptService.java
    -+++ b/services/core/java/com/android/server/pm/OtaDexoptService.java
    -@@ -31,7 +31,7 @@ import android.os.ServiceManager;
    - import android.os.storage.StorageManager;
    - import android.util.Log;
    - import android.util.Slog;
    --
    -+import com.android.internal.logging.MetricsLogger;
    - import com.android.internal.os.InstallerConnection;
    - import com.android.internal.os.InstallerConnection.InstallerException;
    - 
    -@@ -40,6 +40,7 @@ import java.io.FileDescriptor;
    - import java.util.ArrayList;
    - import java.util.Collection;
    - import java.util.List;
    -+import java.util.concurrent.TimeUnit;
    - 
    - /**
    -  * A service for A/B OTA dexopting.
    -@@ -53,6 +54,10 @@ public class OtaDexoptService extends IOtaDexopt.Stub {
    -     // The synthetic library dependencies denoting "no checks."
    -     private final static String[] NO_LIBRARIES = new String[] { "&" };
    - 
    -+    // The amount of "available" (free - low threshold) space necessary at the start of an OTA to
    -+    // not bulk-delete unused apps' odex files.
    -+    private final static long BULK_DELETE_THRESHOLD = 1024 * 1024 * 1024;  // 1GB.
    -+
    -     private final Context mContext;
    -     private final PackageManagerService mPackageManagerService;
    - 
    -@@ -65,6 +70,25 @@ public class OtaDexoptService extends IOtaDexopt.Stub {
    - 
    -     private int completeSize;
    - 
    -+    // MetricsLogger properties.
    -+
    -+    // Space before and after.
    -+    private long availableSpaceBefore;
    -+    private long availableSpaceAfterBulkDelete;
    -+    private long availableSpaceAfterDexopt;
    -+
    -+    // Packages.
    -+    private int importantPackageCount;
    -+    private int otherPackageCount;
    -+
    -+    // Number of dexopt commands. This may be different from the count of packages.
    -+    private int dexoptCommandCountTotal;
    -+    private int dexoptCommandCountExecuted;
    -+
    -+    // For spent time.
    -+    private long otaDexoptTimeStart;
    -+
    -+
    -     public OtaDexoptService(Context context, PackageManagerService packageManagerService) {
    -         this.mContext = context;
    -         this.mPackageManagerService = packageManagerService;
    -@@ -128,6 +152,18 @@ public class OtaDexoptService extends IOtaDexopt.Stub {
    -                     generatePackageDexopts(p, PackageManagerService.REASON_FIRST_BOOT));
    -         }
    -         completeSize = mDexoptCommands.size();
    -+
    -+        long spaceAvailable = getAvailableSpace();
    -+        if (spaceAvailable < BULK_DELETE_THRESHOLD) {
    -+            Log.i(TAG, "Low on space, deleting oat files in an attempt to free up space: "
    -+                    + PackageManagerServiceUtils.packagesToString(others));
    -+            for (PackageParser.Package pkg : others) {
    -+                deleteOatArtifactsOfPackage(pkg);
    -+            }
    -+        }
    -+        long spaceAvailableNow = getAvailableSpace();
    -+
    -+        prepareMetricsLogging(important.size(), others.size(), spaceAvailable, spaceAvailableNow);
    -     }
    - 
    -     @Override
    -@@ -136,6 +172,9 @@ public class OtaDexoptService extends IOtaDexopt.Stub {
    -             Log.i(TAG, "Cleaning up OTA Dexopt state.");
    -         }
    -         mDexoptCommands = null;
    -+        availableSpaceAfterDexopt = getAvailableSpace();
    -+
    -+        performMetricsLogging();
    -     }
    - 
    -     @Override
    -@@ -169,28 +208,67 @@ public class OtaDexoptService extends IOtaDexopt.Stub {
    - 
    -         String next = mDexoptCommands.remove(0);
    - 
    --        if (IsFreeSpaceAvailable()) {
    -+        if (getAvailableSpace() > 0) {
    -+            dexoptCommandCountExecuted++;
    -+
    -             return next;
    -         } else {
    -+            if (DEBUG_DEXOPT) {
    -+                Log.w(TAG, "Not enough space for OTA dexopt, stopping with "
    -+                        + (mDexoptCommands.size() + 1) + " commands left.");
    -+            }
    -             mDexoptCommands.clear();
    -             return "(no free space)";
    -         }
    -     }
    - 
    --    /**
    --     * Check for low space. Returns true if there's space left.
    --     */
    --    private boolean IsFreeSpaceAvailable() {
    --        // TODO: If apps are not installed in the internal /data partition, we should compare
    --        //       against that storage's free capacity.
    -+    private long getMainLowSpaceThreshold() {
    -         File dataDir = Environment.getDataDirectory();
    -         @SuppressWarnings("deprecation")
    -         long lowThreshold = StorageManager.from(mContext).getStorageLowBytes(dataDir);
    -         if (lowThreshold == 0) {
    -             throw new IllegalStateException("Invalid low memory threshold");
    -         }
    -+        return lowThreshold;
    -+    }
    -+
    -+    /**
    -+     * Returns the difference of free space to the low-storage-space threshold. Positive values
    -+     * indicate free bytes.
    -+     */
    -+    private long getAvailableSpace() {
    -+        // TODO: If apps are not installed in the internal /data partition, we should compare
    -+        //       against that storage's free capacity.
    -+        long lowThreshold = getMainLowSpaceThreshold();
    -+
    -+        File dataDir = Environment.getDataDirectory();
    -         long usableSpace = dataDir.getUsableSpace();
    --        return (usableSpace >= lowThreshold);
    -+
    -+        return usableSpace - lowThreshold;
    -+    }
    -+
    -+    private static String getOatDir(PackageParser.Package pkg) {
    -+        if (!pkg.canHaveOatDir()) {
    -+            return null;
    -+        }
    -+        File codePath = new File(pkg.codePath);
    -+        if (codePath.isDirectory()) {
    -+            return PackageDexOptimizer.getOatDir(codePath).getAbsolutePath();
    -+        }
    -+        return null;
    -+    }
    -+
    -+    private void deleteOatArtifactsOfPackage(PackageParser.Package pkg) {
    -+        String[] instructionSets = getAppDexInstructionSets(pkg.applicationInfo);
    -+        for (String codePath : pkg.getAllCodePaths()) {
    -+            for (String isa : instructionSets) {
    -+                try {
    -+                    mPackageManagerService.mInstaller.deleteOdex(codePath, isa, getOatDir(pkg));
    -+                } catch (InstallerException e) {
    -+                    Log.e(TAG, "Failed deleting oat files for " + codePath, e);
    -+                }
    -+            }
    -+        }
    -     }
    - 
    -     /**
    -@@ -271,6 +349,55 @@ public class OtaDexoptService extends IOtaDexopt.Stub {
    -         }
    -     }
    - 
    -+    /**
    -+     * Initialize logging fields.
    -+     */
    -+    private void prepareMetricsLogging(int important, int others, long spaceBegin, long spaceBulk) {
    -+        availableSpaceBefore = spaceBegin;
    -+        availableSpaceAfterBulkDelete = spaceBulk;
    -+        availableSpaceAfterDexopt = 0;
    -+
    -+        importantPackageCount = important;
    -+        otherPackageCount = others;
    -+
    -+        dexoptCommandCountTotal = mDexoptCommands.size();
    -+        dexoptCommandCountExecuted = 0;
    -+
    -+        otaDexoptTimeStart = System.nanoTime();
    -+    }
    -+
    -+    private static int inMegabytes(long value) {
    -+        long in_mega_bytes = value / (1024 * 1024);
    -+        if (in_mega_bytes > Integer.MAX_VALUE) {
    -+            Log.w(TAG, "Recording " + in_mega_bytes + "MB of free space, overflowing range");
    -+            return Integer.MAX_VALUE;
    -+        }
    -+        return (int)in_mega_bytes;
    -+    }
    -+
    -+    private void performMetricsLogging() {
    -+        long finalTime = System.nanoTime();
    -+
    -+        MetricsLogger.histogram(mContext, "ota_dexopt_available_space_before_mb",
    -+                inMegabytes(availableSpaceBefore));
    -+        MetricsLogger.histogram(mContext, "ota_dexopt_available_space_after_bulk_delete_mb",
    -+                inMegabytes(availableSpaceAfterBulkDelete));
    -+        MetricsLogger.histogram(mContext, "ota_dexopt_available_space_after_dexopt_mb",
    -+                inMegabytes(availableSpaceAfterDexopt));
    -+
    -+        MetricsLogger.histogram(mContext, "ota_dexopt_num_important_packages",
    -+                importantPackageCount);
    -+        MetricsLogger.histogram(mContext, "ota_dexopt_num_other_packages", otherPackageCount);
    -+
    -+        MetricsLogger.histogram(mContext, "ota_dexopt_num_commands", dexoptCommandCountTotal);
    -+        MetricsLogger.histogram(mContext, "ota_dexopt_num_commands_executed",
    -+                dexoptCommandCountExecuted);
    -+
    -+        final int elapsedTimeSeconds =
    -+                (int) TimeUnit.NANOSECONDS.toSeconds(finalTime - otaDexoptTimeStart);
    -+        MetricsLogger.histogram(mContext, "ota_dexopt_time_s", elapsedTimeSeconds);
    -+    }
    -+
    -     private static class OTADexoptPackageDexOptimizer extends
    -             PackageDexOptimizer.ForcedUpdatePackageDexOptimizer {
    - 
    -diff --git a/services/core/java/com/android/server/pm/PackageInstallerService.java b/services/core/java/com/android/server/pm/PackageInstallerService.java
    -index 6a56fa6..d25abbf 100644
    ---- a/services/core/java/com/android/server/pm/PackageInstallerService.java
    -+++ b/services/core/java/com/android/server/pm/PackageInstallerService.java
    -@@ -870,13 +870,8 @@ public class PackageInstallerService extends IPackageInstaller.Stub {
    -                 IntentSender statusReceiver, int userId) {
    -         final int callingUid = Binder.getCallingUid();
    -         mPm.enforceCrossUserPermission(callingUid, userId, true, true, "uninstall");
    --        boolean allowSilentUninstall = true;
    -         if ((callingUid != Process.SHELL_UID) && (callingUid != Process.ROOT_UID)) {
    -             mAppOps.checkPackage(callingUid, callerPackageName);
    --            final String installerPackageName = mPm.getInstallerPackageName(packageName);
    --            allowSilentUninstall = mPm.isOrphaned(packageName) ||
    --                    (installerPackageName != null
    --                            && installerPackageName.equals(callerPackageName));
    -         }
    - 
    -         // Check whether the caller is device owner, in which case we do it silently.
    -@@ -887,8 +882,8 @@ public class PackageInstallerService extends IPackageInstaller.Stub {
    - 
    -         final PackageDeleteObserverAdapter adapter = new PackageDeleteObserverAdapter(mContext,
    -                 statusReceiver, packageName, isDeviceOwner, userId);
    --        if (allowSilentUninstall && mContext.checkCallingOrSelfPermission(
    --                android.Manifest.permission.DELETE_PACKAGES) == PackageManager.PERMISSION_GRANTED) {
    -+        if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DELETE_PACKAGES)
    -+                    == PackageManager.PERMISSION_GRANTED) {
    -             // Sweet, call straight through!
    -             mPm.deletePackage(packageName, adapter.getBinder(), userId, flags);
    -         } else if (isDeviceOwner) {
    -diff --git a/services/core/java/com/android/server/pm/PackageInstallerSession.java b/services/core/java/com/android/server/pm/PackageInstallerSession.java
    -index 6cdc40f..2ece99f 100644
    ---- a/services/core/java/com/android/server/pm/PackageInstallerSession.java
    -+++ b/services/core/java/com/android/server/pm/PackageInstallerSession.java
    -@@ -44,6 +44,7 @@ import android.content.pm.PackageParser.ApkLite;
    - import android.content.pm.PackageParser.PackageLite;
    - import android.content.pm.PackageParser.PackageParserException;
    - import android.content.pm.Signature;
    -+import android.os.Binder;
    - import android.os.Bundle;
    - import android.os.FileBridge;
    - import android.os.FileUtils;
    -@@ -109,6 +110,7 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
    -     final int installerUid;
    -     final SessionParams params;
    -     final long createdMillis;
    -+    final int defaultContainerGid;
    - 
    -     /** Staging location where client data is written. */
    -     final File stageDir;
    -@@ -199,13 +201,19 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
    -     private final Handler.Callback mHandlerCallback = new Handler.Callback() {
    -         @Override
    -         public boolean handleMessage(Message msg) {
    -+            // Cache package manager data without the lock held
    -+            final PackageInfo pkgInfo = mPm.getPackageInfo(
    -+                    params.appPackageName, PackageManager.GET_SIGNATURES /*flags*/, userId);
    -+            final ApplicationInfo appInfo = mPm.getApplicationInfo(
    -+                    params.appPackageName, 0, userId);
    -+
    -             synchronized (mLock) {
    -                 if (msg.obj != null) {
    -                     mRemoteObserver = (IPackageInstallObserver2) msg.obj;
    -                 }
    - 
    -                 try {
    --                    commitLocked();
    -+                    commitLocked(pkgInfo, appInfo);
    -                 } catch (PackageManagerException e) {
    -                     final String completeMsg = ExceptionUtils.getCompleteMessage(e);
    -                     Slog.e(TAG, "Commit of session " + sessionId + " failed: " + completeMsg);
    -@@ -264,6 +272,14 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
    -         } else {
    -             mPermissionsAccepted = false;
    -         }
    -+        final long identity = Binder.clearCallingIdentity();
    -+        try {
    -+            final int uid = mPm.getPackageUid(PackageManagerService.DEFAULT_CONTAINER_PACKAGE,
    -+                    PackageManager.MATCH_SYSTEM_ONLY, UserHandle.USER_SYSTEM);
    -+            defaultContainerGid = UserHandle.getSharedAppGid(uid);
    -+        } finally {
    -+            Binder.restoreCallingIdentity(identity);
    -+        }
    -     }
    - 
    -     public SessionInfo generateInfo() {
    -@@ -423,7 +439,13 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
    -             if (!FileUtils.isValidExtFilename(name)) {
    -                 throw new IllegalArgumentException("Invalid name: " + name);
    -             }
    --            final File target = new File(resolveStageDir(), name);
    -+            final File target;
    -+            final long identity = Binder.clearCallingIdentity();
    -+            try {
    -+                target = new File(resolveStageDir(), name);
    -+            } finally {
    -+                Binder.restoreCallingIdentity(identity);
    -+            }
    - 
    -             // TODO: this should delegate to DCS so the system process avoids
    -             // holding open FDs into containers.
    -@@ -520,7 +542,8 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
    -         mHandler.obtainMessage(MSG_COMMIT, adapter.getBinder()).sendToTarget();
    -     }
    - 
    --    private void commitLocked() throws PackageManagerException {
    -+    private void commitLocked(PackageInfo pkgInfo, ApplicationInfo appInfo)
    -+            throws PackageManagerException {
    -         if (mDestroyed) {
    -             throw new PackageManagerException(INSTALL_FAILED_INTERNAL_ERROR, "Session destroyed");
    -         }
    -@@ -538,7 +561,7 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
    -         // Verify that stage looks sane with respect to existing application.
    -         // This currently only ensures packageName, versionCode, and certificate
    -         // consistency.
    --        validateInstallLocked();
    -+        validateInstallLocked(pkgInfo, appInfo);
    - 
    -         Preconditions.checkNotNull(mPackageName);
    -         Preconditions.checkNotNull(mSignatures);
    -@@ -650,7 +673,8 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
    -      * Note that upgrade compatibility is still performed by
    -      * {@link PackageManagerService}.
    -      */
    --    private void validateInstallLocked() throws PackageManagerException {
    -+    private void validateInstallLocked(PackageInfo pkgInfo, ApplicationInfo appInfo)
    -+            throws PackageManagerException {
    -         mPackageName = null;
    -         mVersionCode = -1;
    -         mSignatures = null;
    -@@ -729,10 +753,8 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
    - 
    -         if (removeSplitList.size() > 0) {
    -             // validate split names marked for removal
    --            final int flags = mSignatures == null ? PackageManager.GET_SIGNATURES : 0;
    --            final PackageInfo pkg = mPm.getPackageInfo(params.appPackageName, flags, userId);
    -             for (String splitName : removeSplitList) {
    --                if (!ArrayUtils.contains(pkg.splitNames, splitName)) {
    -+                if (!ArrayUtils.contains(pkgInfo.splitNames, splitName)) {
    -                     throw new PackageManagerException(INSTALL_FAILED_INVALID_APK,
    -                             "Split not found: " + splitName);
    -                 }
    -@@ -740,11 +762,11 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
    - 
    -             // ensure we've got appropriate package name, version code and signatures
    -             if (mPackageName == null) {
    --                mPackageName = pkg.packageName;
    --                mVersionCode = pkg.versionCode;
    -+                mPackageName = pkgInfo.packageName;
    -+                mVersionCode = pkgInfo.versionCode;
    -             }
    -             if (mSignatures == null) {
    --                mSignatures = pkg.signatures;
    -+                mSignatures = pkgInfo.signatures;
    -             }
    -         }
    - 
    -@@ -757,8 +779,7 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
    - 
    -         } else {
    -             // Partial installs must be consistent with existing install
    --            final ApplicationInfo app = mPm.getApplicationInfo(mPackageName, 0, userId);
    --            if (app == null) {
    -+            if (appInfo == null) {
    -                 throw new PackageManagerException(INSTALL_FAILED_INVALID_APK,
    -                         "Missing existing base package for " + mPackageName);
    -             }
    -@@ -766,8 +787,8 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
    -             final PackageLite existing;
    -             final ApkLite existingBase;
    -             try {
    --                existing = PackageParser.parsePackageLite(new File(app.getCodePath()), 0);
    --                existingBase = PackageParser.parseApkLite(new File(app.getBaseCodePath()),
    -+                existing = PackageParser.parsePackageLite(new File(appInfo.getCodePath()), 0);
    -+                existingBase = PackageParser.parseApkLite(new File(appInfo.getBaseCodePath()),
    -                         PackageParser.PARSE_COLLECT_CERTIFICATES);
    -             } catch (PackageParserException e) {
    -                 throw PackageManagerException.from(e);
    -@@ -777,7 +798,7 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
    - 
    -             // Inherit base if not overridden
    -             if (mResolvedBaseFile == null) {
    --                mResolvedBaseFile = new File(app.getBaseCodePath());
    -+                mResolvedBaseFile = new File(appInfo.getBaseCodePath());
    -                 mResolvedInheritedFiles.add(mResolvedBaseFile);
    -             }
    - 
    -@@ -794,7 +815,7 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
    -             }
    - 
    -             // Inherit compiled oat directory.
    --            final File packageInstallDir = (new File(app.getBaseCodePath())).getParentFile();
    -+            final File packageInstallDir = (new File(appInfo.getBaseCodePath())).getParentFile();
    -             mInheritedFilesBase = packageInstallDir;
    -             final File oatDir = new File(packageInstallDir, "oat");
    -             if (oatDir.exists()) {
    -@@ -822,7 +843,8 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
    -         }
    -     }
    - 
    --    private void assertApkConsistent(String tag, ApkLite apk) throws PackageManagerException {
    -+    private void assertApkConsistent(String tag, ApkLite apk)
    -+            throws PackageManagerException {
    -         if (!mPackageName.equals(apk.packageName)) {
    -             throw new PackageManagerException(INSTALL_FAILED_INVALID_APK, tag + " package "
    -                     + apk.packageName + " inconsistent with " + mPackageName);
    -@@ -1035,10 +1057,7 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
    -                     "Failed to finalize container " + cid);
    -         }
    - 
    --        final int uid = mPm.getPackageUid(PackageManagerService.DEFAULT_CONTAINER_PACKAGE,
    --                PackageManager.MATCH_SYSTEM_ONLY, UserHandle.USER_SYSTEM);
    --        final int gid = UserHandle.getSharedAppGid(uid);
    --        if (!PackageHelper.fixSdPermissions(cid, gid, null)) {
    -+        if (!PackageHelper.fixSdPermissions(cid, defaultContainerGid, null)) {
    -             throw new PackageManagerException(INSTALL_FAILED_CONTAINER_ERROR,
    -                     "Failed to fix permissions on container " + cid);
    -         }
    -@@ -1071,7 +1090,12 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
    -                 if (stageDir != null) {
    -                     prepareStageDir(stageDir);
    -                 } else if (stageCid != null) {
    --                    prepareExternalStageCid(stageCid, params.sizeBytes);
    -+                    final long identity = Binder.clearCallingIdentity();
    -+                    try {
    -+                        prepareExternalStageCid(stageCid, params.sizeBytes);
    -+                    } finally {
    -+                        Binder.restoreCallingIdentity(identity);
    -+                    }
    - 
    -                     // TODO: deliver more granular progress for ASEC allocation
    -                     mInternalProgress = 0.25f;
    -diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
    -index f326555..5fd9c58 100644
    ---- a/services/core/java/com/android/server/pm/PackageManagerService.java
    -+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
    -@@ -109,6 +109,7 @@ import android.app.admin.SecurityLog;
    - import android.app.backup.IBackupManager;
    - import android.content.BroadcastReceiver;
    - import android.content.ComponentName;
    -+import android.content.ContentResolver;
    - import android.content.Context;
    - import android.content.IIntentReceiver;
    - import android.content.Intent;
    -@@ -177,6 +178,7 @@ import android.os.Looper;
    - import android.os.Message;
    - import android.os.Parcel;
    - import android.os.ParcelFileDescriptor;
    -+import android.os.PatternMatcher;
    - import android.os.Process;
    - import android.os.RemoteCallbackList;
    - import android.os.RemoteException;
    -@@ -196,6 +198,7 @@ import android.os.storage.StorageManager;
    - import android.os.storage.VolumeInfo;
    - import android.os.storage.VolumeRecord;
    - import android.provider.Settings.Global;
    -+import android.provider.Settings.Secure;
    - import android.security.KeyStore;
    - import android.security.SystemKeyStore;
    - import android.system.ErrnoException;
    -@@ -210,6 +213,7 @@ import android.util.ExceptionUtils;
    - import android.util.Log;
    - import android.util.LogPrinter;
    - import android.util.MathUtils;
    -+import android.util.Pair;
    - import android.util.PrintStreamPrinter;
    - import android.util.Slog;
    - import android.util.SparseArray;
    -@@ -363,7 +367,8 @@ public class PackageManagerService extends IPackageManager.Stub {
    - 
    -     static final boolean CLEAR_RUNTIME_PERMISSIONS_ON_UPGRADE = false;
    - 
    --    private static final boolean DISABLE_EPHEMERAL_APPS = !Build.IS_DEBUGGABLE;
    -+    private static final boolean DISABLE_EPHEMERAL_APPS = false;
    -+    private static final boolean HIDE_EPHEMERAL_APIS = true;
    - 
    -     private static final int RADIO_UID = Process.PHONE_UID;
    -     private static final int LOG_UID = Process.LOG_UID;
    -@@ -455,6 +460,8 @@ public class PackageManagerService extends IPackageManager.Stub {
    - 
    -     private static final String PACKAGE_MIME_TYPE = "application/vnd.android.package-archive";
    - 
    -+    private static final String PACKAGE_SCHEME = "package";
    -+
    -     private static final String VENDOR_OVERLAY_DIR = "/vendor/overlay";
    - 
    -     private static int DEFAULT_EPHEMERAL_HASH_PREFIX_MASK = 0xFFFFF000;
    -@@ -531,6 +538,10 @@ public class PackageManagerService extends IPackageManager.Stub {
    -     final String[] mSeparateProcesses;
    -     final boolean mIsUpgrade;
    -     final boolean mIsPreNUpgrade;
    -+    final boolean mIsPreNMR1Upgrade;
    -+
    -+    @GuardedBy("mPackages")
    -+    private boolean mDexOptDialogShown;
    - 
    -     /** The location for ASEC container files on internal storage. */
    -     final String mAsecInternalPath;
    -@@ -1117,7 +1128,9 @@ public class PackageManagerService extends IPackageManager.Stub {
    - 
    -     final @Nullable String mRequiredVerifierPackage;
    -     final @NonNull String mRequiredInstallerPackage;
    -+    final @NonNull String mRequiredUninstallerPackage;
    -     final @Nullable String mSetupWizardPackage;
    -+    final @Nullable String mStorageManagerPackage;
    -     final @NonNull String mServicesSystemSharedLibraryPackageName;
    -     final @NonNull String mSharedSystemSharedLibraryPackageName;
    - 
    -@@ -2148,6 +2161,18 @@ public class PackageManagerService extends IPackageManager.Stub {
    - 
    -             mFirstBoot = !mSettings.readLPw(sUserManager.getUsers(false));
    - 
    -+            // Clean up orphaned packages for which the code path doesn't exist
    -+            // and they are an update to a system app - caused by bug/32321269
    -+            final int packageSettingCount = mSettings.mPackages.size();
    -+            for (int i = packageSettingCount - 1; i >= 0; i--) {
    -+                PackageSetting ps = mSettings.mPackages.valueAt(i);
    -+                if (!isExternal(ps) && (ps.codePath == null || !ps.codePath.exists())
    -+                        && mSettings.getDisabledSystemPkgLPr(ps.name) != null) {
    -+                    mSettings.mPackages.removeAt(i);
    -+                    mSettings.enableSystemPackageLPw(ps.name);
    -+                }
    -+            }
    -+
    -             if (mFirstBoot) {
    -                 requestCopyPreoptedFiles();
    -             }
    -@@ -2238,6 +2263,8 @@ public class PackageManagerService extends IPackageManager.Stub {
    -             // as there is no profiling data available.
    -             mIsPreNUpgrade = mIsUpgrade && ver.sdkVersion < Build.VERSION_CODES.N;
    - 
    -+            mIsPreNMR1Upgrade = mIsUpgrade && ver.sdkVersion < Build.VERSION_CODES.N_MR1;
    -+
    -             // save off the names of pre-existing system packages prior to scanning; we don't
    -             // want to automatically grant runtime permissions for new system apps
    -             if (mPromoteSystemApps) {
    -@@ -2457,6 +2484,9 @@ public class PackageManagerService extends IPackageManager.Stub {
    -             }
    -             mExpectingBetter.clear();
    - 
    -+            // Resolve the storage manager.
    -+            mStorageManagerPackage = getStorageManagerPackageName();
    -+
    -             // Resolve protected action filters. Only the setup wizard is allowed to
    -             // have a high priority filter for these actions.
    -             mSetupWizardPackage = getSetupWizardPackageName();
    -@@ -2620,6 +2650,7 @@ public class PackageManagerService extends IPackageManager.Stub {
    -             if (!mOnlyCore) {
    -                 mRequiredVerifierPackage = getRequiredButNotReallyRequiredVerifierLPr();
    -                 mRequiredInstallerPackage = getRequiredInstallerLPr();
    -+                mRequiredUninstallerPackage = getRequiredUninstallerLPr();
    -                 mIntentFilterVerifierComponent = getIntentFilterVerifierComponentNameLPr();
    -                 mIntentFilterVerifier = new IntentVerifierProxy(mContext,
    -                         mIntentFilterVerifierComponent);
    -@@ -2630,6 +2661,7 @@ public class PackageManagerService extends IPackageManager.Stub {
    -             } else {
    -                 mRequiredVerifierPackage = null;
    -                 mRequiredInstallerPackage = null;
    -+                mRequiredUninstallerPackage = null;
    -                 mIntentFilterVerifierComponent = null;
    -                 mIntentFilterVerifier = null;
    -                 mServicesSystemSharedLibraryPackageName = null;
    -@@ -2707,10 +2739,11 @@ public class PackageManagerService extends IPackageManager.Stub {
    -                 UserHandle.USER_SYSTEM);
    -         if (matches.size() == 1) {
    -             return matches.get(0).getComponentInfo().packageName;
    --        } else {
    --            Log.e(TAG, "There should probably be exactly one verifier; found " + matches);
    -+        } else if (matches.size() == 0) {
    -+            Log.e(TAG, "There should probably be a verifier, but, none were found");
    -             return null;
    -         }
    -+        throw new RuntimeException("There must be exactly one verifier; found " + matches);
    -     }
    - 
    -     private @NonNull String getRequiredSharedLibraryLPr(String libraryName) {
    -@@ -2742,6 +2775,22 @@ public class PackageManagerService extends IPackageManager.Stub {
    -         }
    -     }
    - 
    -+    private @NonNull String getRequiredUninstallerLPr() {
    -+        final Intent intent = new Intent(Intent.ACTION_UNINSTALL_PACKAGE);
    -+        intent.addCategory(Intent.CATEGORY_DEFAULT);
    -+        intent.setData(Uri.fromParts(PACKAGE_SCHEME, "foo.bar", null));
    -+
    -+        final ResolveInfo resolveInfo = resolveIntent(intent, null,
    -+                MATCH_SYSTEM_ONLY | MATCH_DIRECT_BOOT_AWARE | MATCH_DIRECT_BOOT_UNAWARE,
    -+                UserHandle.USER_SYSTEM);
    -+        if (resolveInfo == null ||
    -+                mResolveActivity.name.equals(resolveInfo.getComponentInfo().name)) {
    -+            throw new RuntimeException("There must be exactly one uninstaller; found "
    -+                    + resolveInfo);
    -+        }
    -+        return resolveInfo.getComponentInfo().packageName;
    -+    }
    -+
    -     private @NonNull ComponentName getIntentFilterVerifierComponentNameLPr() {
    -         final Intent intent = new Intent(Intent.ACTION_INTENT_FILTER_NEEDS_VERIFICATION);
    - 
    -@@ -3078,8 +3127,12 @@ public class PackageManagerService extends IPackageManager.Stub {
    -         flags = updateFlagsForPackage(flags, userId, packageName);
    -         enforceCrossUserPermission(Binder.getCallingUid(), userId,
    -                 false /* requireFullPermission */, false /* checkShell */, "get package info");
    -+
    -         // reader
    -         synchronized (mPackages) {
    -+            // Normalize package name to hanlde renamed packages
    -+            packageName = normalizePackageNameLPr(packageName);
    -+
    -             final boolean matchFactoryOnly = (flags & MATCH_FACTORY_ONLY) != 0;
    -             PackageParser.Package p = null;
    -             if (matchFactoryOnly) {
    -@@ -3280,8 +3333,12 @@ public class PackageManagerService extends IPackageManager.Stub {
    -         flags = updateFlagsForApplication(flags, userId, packageName);
    -         enforceCrossUserPermission(Binder.getCallingUid(), userId,
    -                 false /* requireFullPermission */, false /* checkShell */, "get application info");
    -+
    -         // writer
    -         synchronized (mPackages) {
    -+            // Normalize package name to hanlde renamed packages
    -+            packageName = normalizePackageNameLPr(packageName);
    -+
    -             PackageParser.Package p = mPackages.get(packageName);
    -             if (DEBUG_PACKAGE_INFO) Log.v(
    -                     TAG, "getApplicationInfo " + packageName
    -@@ -3303,6 +3360,11 @@ public class PackageManagerService extends IPackageManager.Stub {
    -         return null;
    -     }
    - 
    -+    private String normalizePackageNameLPr(String packageName) {
    -+        String normalizedPackageName = mSettings.mRenamedPackages.get(packageName);
    -+        return normalizedPackageName != null ? normalizedPackageName : packageName;
    -+    }
    -+
    -     @Override
    -     public void freeStorageAndNotify(final String volumeUuid, final long freeStorageSize,
    -             final IPackageDataObserver observer) {
    -@@ -4722,20 +4784,6 @@ public class PackageManagerService extends IPackageManager.Stub {
    - 
    -             final ResolveInfo bestChoice =
    -                     chooseBestActivity(intent, resolvedType, flags, query, userId);
    --
    --            if (isEphemeralAllowed(intent, query, userId)) {
    --                Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "resolveEphemeral");
    --                final EphemeralResolveInfo ai =
    --                        getEphemeralResolveInfo(intent, resolvedType, userId);
    --                if (ai != null) {
    --                    if (DEBUG_EPHEMERAL) {
    --                        Slog.v(TAG, "Returning an EphemeralResolveInfo");
    --                    }
    --                    bestChoice.ephemeralInstaller = mEphemeralInstallerInfo;
    --                    bestChoice.ephemeralResolveInfo = ai;
    --                }
    --                Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
    --            }
    -             return bestChoice;
    -         } finally {
    -             Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
    -@@ -4776,11 +4824,28 @@ public class PackageManagerService extends IPackageManager.Stub {
    -                 false, false, false, userId);
    -     }
    - 
    -+    private boolean isEphemeralDisabled() {
    -+        // ephemeral apps have been disabled across the board
    -+        if (DISABLE_EPHEMERAL_APPS) {
    -+            return true;
    -+        }
    -+        // system isn't up yet; can't read settings, so, assume no ephemeral apps
    -+        if (!mSystemReady) {
    -+            return true;
    -+        }
    -+        // we can't get a content resolver until the system is ready; these checks must happen last
    -+        final ContentResolver resolver = mContext.getContentResolver();
    -+        if (Global.getInt(resolver, Global.ENABLE_EPHEMERAL_FEATURE, 1) == 0) {
    -+            return true;
    -+        }
    -+        return Secure.getInt(resolver, Secure.WEB_ACTION_ENABLED, 1) == 0;
    -+    }
    - 
    -     private boolean isEphemeralAllowed(
    --            Intent intent, List<ResolveInfo> resolvedActivites, int userId) {
    -+            Intent intent, List<ResolveInfo> resolvedActivities, int userId,
    -+            boolean skipPackageCheck) {
    -         // Short circuit and return early if possible.
    --        if (DISABLE_EPHEMERAL_APPS) {
    -+        if (isEphemeralDisabled()) {
    -             return false;
    -         }
    -         final int callingUser = UserHandle.getCallingUserId();
    -@@ -4793,18 +4858,21 @@ public class PackageManagerService extends IPackageManager.Stub {
    -         if (intent.getComponent() != null) {
    -             return false;
    -         }
    --        if (intent.getPackage() != null) {
    -+        if ((intent.getFlags() & Intent.FLAG_IGNORE_EPHEMERAL) != 0) {
    -+            return false;
    -+        }
    -+        if (!skipPackageCheck && intent.getPackage() != null) {
    -             return false;
    -         }
    -         final boolean isWebUri = hasWebURI(intent);
    --        if (!isWebUri) {
    -+        if (!isWebUri || intent.getData().getHost() == null) {
    -             return false;
    -         }
    -         // Deny ephemeral apps if the user chose _ALWAYS or _ALWAYS_ASK for intent resolution.
    -         synchronized (mPackages) {
    --            final int count = resolvedActivites.size();
    -+            final int count = (resolvedActivities == null ? 0 : resolvedActivities.size());
    -             for (int n = 0; n < count; n++) {
    --                ResolveInfo info = resolvedActivites.get(n);
    -+                ResolveInfo info = resolvedActivities.get(n);
    -                 String packageName = info.activityInfo.packageName;
    -                 PackageSetting ps = mSettings.mPackages.get(packageName);
    -                 if (ps != null) {
    -@@ -4826,19 +4894,19 @@ public class PackageManagerService extends IPackageManager.Stub {
    -         return true;
    -     }
    - 
    --    private EphemeralResolveInfo getEphemeralResolveInfo(Intent intent, String resolvedType,
    --            int userId) {
    --        final int ephemeralPrefixMask = Global.getInt(mContext.getContentResolver(),
    -+    private static EphemeralResolveInfo getEphemeralResolveInfo(
    -+            Context context, EphemeralResolverConnection resolverConnection, Intent intent,
    -+            String resolvedType, int userId, String packageName) {
    -+        final int ephemeralPrefixMask = Global.getInt(context.getContentResolver(),
    -                 Global.EPHEMERAL_HASH_PREFIX_MASK, DEFAULT_EPHEMERAL_HASH_PREFIX_MASK);
    --        final int ephemeralPrefixCount = Global.getInt(mContext.getContentResolver(),
    -+        final int ephemeralPrefixCount = Global.getInt(context.getContentResolver(),
    -                 Global.EPHEMERAL_HASH_PREFIX_COUNT, DEFAULT_EPHEMERAL_HASH_PREFIX_COUNT);
    -         final EphemeralDigest digest = new EphemeralDigest(intent.getData(), ephemeralPrefixMask,
    -                 ephemeralPrefixCount);
    -         final int[] shaPrefix = digest.getDigestPrefix();
    -         final byte[][] digestBytes = digest.getDigestBytes();
    -         final List<EphemeralResolveInfo> ephemeralResolveInfoList =
    --                mEphemeralResolverConnection.getEphemeralResolveInfoList(
    --                        shaPrefix, ephemeralPrefixMask);
    -+                resolverConnection.getEphemeralResolveInfoList(shaPrefix, ephemeralPrefixMask);
    -         if (ephemeralResolveInfoList == null || ephemeralResolveInfoList.size() == 0) {
    -             // No hash prefix match; there are no ephemeral apps for this domain.
    -             return null;
    -@@ -4855,6 +4923,10 @@ public class PackageManagerService extends IPackageManager.Stub {
    -                 if (filters.isEmpty()) {
    -                     continue;
    -                 }
    -+                if (packageName != null
    -+                        && !packageName.equals(ephemeralApplication.getPackageName())) {
    -+                    continue;
    -+                }
    -                 // We have a domain match; resolve the filters to see if anything matches.
    -                 final EphemeralIntentResolver ephemeralResolver = new EphemeralIntentResolver();
    -                 for (int j = filters.size() - 1; j >= 0; --j) {
    -@@ -5258,8 +5330,12 @@ public class PackageManagerService extends IPackageManager.Stub {
    -         }
    - 
    -         // reader
    -+        boolean sortResult = false;
    -+        boolean addEphemeral = false;
    -+        boolean matchEphemeralPackage = false;
    -+        List<ResolveInfo> result;
    -+        final String pkgName = intent.getPackage();
    -         synchronized (mPackages) {
    --            final String pkgName = intent.getPackage();
    -             if (pkgName == null) {
    -                 List<CrossProfileIntentFilter> matchingFilters =
    -                         getMatchingCrossProfileIntentFilters(intent, resolvedType, userId);
    -@@ -5267,15 +5343,16 @@ public class PackageManagerService extends IPackageManager.Stub {
    -                 ResolveInfo xpResolveInfo  = querySkipCurrentProfileIntents(matchingFilters, intent,
    -                         resolvedType, flags, userId);
    -                 if (xpResolveInfo != null) {
    --                    List<ResolveInfo> result = new ArrayList<ResolveInfo>(1);
    --                    result.add(xpResolveInfo);
    --                    return filterIfNotSystemUser(result, userId);
    -+                    List<ResolveInfo> xpResult = new ArrayList<ResolveInfo>(1);
    -+                    xpResult.add(xpResolveInfo);
    -+                    return filterIfNotSystemUser(xpResult, userId);
    -                 }
    - 
    -                 // Check for results in the current profile.
    --                List<ResolveInfo> result = mActivities.queryIntent(
    --                        intent, resolvedType, flags, userId);
    --                result = filterIfNotSystemUser(result, userId);
    -+                result = filterIfNotSystemUser(mActivities.queryIntent(
    -+                        intent, resolvedType, flags, userId), userId);
    -+                addEphemeral =
    -+                        isEphemeralAllowed(intent, result, userId, false /*skipPackageCheck*/);
    - 
    -                 // Check for cross profile results.
    -                 boolean hasNonNegativePriorityResult = hasNonNegativePriority(result);
    -@@ -5287,7 +5364,7 @@ public class PackageManagerService extends IPackageManager.Stub {
    -                             Collections.singletonList(xpResolveInfo), userId).size() > 0;
    -                     if (isVisibleToUser) {
    -                         result.add(xpResolveInfo);
    --                        Collections.sort(result, mResolvePrioritySorter);
    -+                        sortResult = true;
    -                     }
    -                 }
    -                 if (hasWebURI(intent)) {
    -@@ -5303,28 +5380,61 @@ public class PackageManagerService extends IPackageManager.Stub {
    -                             // in the result.
    -                             result.remove(xpResolveInfo);
    -                         }
    --                        if (result.size() == 0) {
    -+                        if (result.size() == 0 && !addEphemeral) {
    -                             result.add(xpDomainInfo.resolveInfo);
    -                             return result;
    -                         }
    --                    } else if (result.size() <= 1) {
    --                        return result;
    -                     }
    --                    result = filterCandidatesWithDomainPreferredActivitiesLPr(intent, flags, result,
    --                            xpDomainInfo, userId);
    --                    Collections.sort(result, mResolvePrioritySorter);
    -+                    if (result.size() > 1 || addEphemeral) {
    -+                        result = filterCandidatesWithDomainPreferredActivitiesLPr(
    -+                                intent, flags, result, xpDomainInfo, userId);
    -+                        sortResult = true;
    -+                    }
    -+                }
    -+            } else {
    -+                final PackageParser.Package pkg = mPackages.get(pkgName);
    -+                if (pkg != null) {
    -+                    result = filterIfNotSystemUser(
    -+                            mActivities.queryIntentForPackage(
    -+                                    intent, resolvedType, flags, pkg.activities, userId),
    -+                            userId);
    -+                } else {
    -+                    // the caller wants to resolve for a particular package; however, there
    -+                    // were no installed results, so, try to find an ephemeral result
    -+                    addEphemeral = isEphemeralAllowed(
    -+                            intent, null /*result*/, userId, true /*skipPackageCheck*/);
    -+                    matchEphemeralPackage = true;
    -+                    result = new ArrayList<ResolveInfo>();
    -                 }
    --                return result;
    -             }
    --            final PackageParser.Package pkg = mPackages.get(pkgName);
    --            if (pkg != null) {
    --                return filterIfNotSystemUser(
    --                        mActivities.queryIntentForPackage(
    --                                intent, resolvedType, flags, pkg.activities, userId),
    --                        userId);
    -+        }
    -+        if (addEphemeral) {
    -+            Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "resolveEphemeral");
    -+            final EphemeralResolveInfo ai = getEphemeralResolveInfo(
    -+                    mContext, mEphemeralResolverConnection, intent, resolvedType, userId,
    -+                    matchEphemeralPackage ? pkgName : null);
    -+            if (ai != null) {
    -+                if (DEBUG_EPHEMERAL) {
    -+                    Slog.v(TAG, "Adding ephemeral installer to the ResolveInfo list");
    -+                }
    -+                final ResolveInfo ephemeralInstaller = new ResolveInfo(mEphemeralInstallerInfo);
    -+                ephemeralInstaller.ephemeralResolveInfo = ai;
    -+                // make sure this resolver is the default
    -+                ephemeralInstaller.isDefault = true;
    -+                ephemeralInstaller.match = IntentFilter.MATCH_CATEGORY_SCHEME_SPECIFIC_PART
    -+                        | IntentFilter.MATCH_ADJUSTMENT_NORMAL;
    -+                // add a non-generic filter
    -+                ephemeralInstaller.filter = new IntentFilter(intent.getAction());
    -+                ephemeralInstaller.filter.addDataPath(
    -+                        intent.getData().getPath(), PatternMatcher.PATTERN_LITERAL);
    -+                result.add(ephemeralInstaller);
    -             }
    --            return new ArrayList<ResolveInfo>();
    -+            Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
    -+        }
    -+        if (sortResult) {
    -+            Collections.sort(result, mResolvePrioritySorter);
    -         }
    -+        return result;
    -     }
    - 
    -     private static class CrossProfileDomainInfo {
    -@@ -6204,7 +6314,7 @@ public class PackageManagerService extends IPackageManager.Stub {
    - 
    -     @Override
    -     public ParceledListSlice<EphemeralApplicationInfo> getEphemeralApplications(int userId) {
    --        if (DISABLE_EPHEMERAL_APPS) {
    -+        if (HIDE_EPHEMERAL_APIS || isEphemeralDisabled()) {
    -             return null;
    -         }
    - 
    -@@ -6228,7 +6338,7 @@ public class PackageManagerService extends IPackageManager.Stub {
    -         enforceCrossUserPermission(Binder.getCallingUid(), userId,
    -                 true /* requireFullPermission */, false /* checkShell */,
    -                 "isEphemeral");
    --        if (DISABLE_EPHEMERAL_APPS) {
    -+        if (HIDE_EPHEMERAL_APIS || isEphemeralDisabled()) {
    -             return false;
    -         }
    - 
    -@@ -6246,7 +6356,7 @@ public class PackageManagerService extends IPackageManager.Stub {
    - 
    -     @Override
    -     public byte[] getEphemeralApplicationCookie(String packageName, int userId) {
    --        if (DISABLE_EPHEMERAL_APPS) {
    -+        if (HIDE_EPHEMERAL_APIS || isEphemeralDisabled()) {
    -             return null;
    -         }
    - 
    -@@ -6264,7 +6374,7 @@ public class PackageManagerService extends IPackageManager.Stub {
    - 
    -     @Override
    -     public boolean setEphemeralApplicationCookie(String packageName, byte[] cookie, int userId) {
    --        if (DISABLE_EPHEMERAL_APPS) {
    -+        if (HIDE_EPHEMERAL_APIS || isEphemeralDisabled()) {
    -             return true;
    -         }
    - 
    -@@ -6282,7 +6392,7 @@ public class PackageManagerService extends IPackageManager.Stub {
    - 
    -     @Override
    -     public Bitmap getEphemeralApplicationIcon(String packageName, int userId) {
    --        if (DISABLE_EPHEMERAL_APPS) {
    -+        if (HIDE_EPHEMERAL_APIS || isEphemeralDisabled()) {
    -             return null;
    -         }
    - 
    -@@ -6612,9 +6722,13 @@ public class PackageManagerService extends IPackageManager.Stub {
    - 
    -     private void collectCertificatesLI(PackageSetting ps, PackageParser.Package pkg, File srcFile,
    -             final int policyFlags) throws PackageManagerException {
    -+        // When upgrading from pre-N MR1, verify the package time stamp using the package
    -+        // directory and not the APK file.
    -+        final long lastModifiedTime = mIsPreNMR1Upgrade
    -+                ? new File(pkg.codePath).lastModified() : getLastModifiedTime(pkg, srcFile);
    -         if (ps != null
    -                 && ps.codePath.equals(srcFile)
    --                && ps.timeStamp == getLastModifiedTime(pkg, srcFile)
    -+                && ps.timeStamp == lastModifiedTime
    -                 && !isCompatSignatureUpdateNeeded(pkg)
    -                 && !isRecoverSignatureUpdateNeeded(pkg)) {
    -             long mSigningKeySetId = ps.keySetData.getProperSigningKeySet();
    -@@ -6636,7 +6750,7 @@ public class PackageManagerService extends IPackageManager.Stub {
    -             Slog.w(TAG, "PackageSetting for " + ps.name
    -                     + " is missing signatures.  Collecting certs again to recover them.");
    -         } else {
    --            Log.i(TAG, srcFile.toString() + " changed; collecting certs");
    -+            Slog.i(TAG, srcFile.toString() + " changed; collecting certs");
    -         }
    - 
    -         try {
    -@@ -7075,7 +7189,11 @@ public class PackageManagerService extends IPackageManager.Stub {
    -                     }
    -                 }
    -                 if (doTrim) {
    --                    if (!isFirstBoot()) {
    -+                    final boolean dexOptDialogShown;
    -+                    synchronized (mPackages) {
    -+                        dexOptDialogShown = mDexOptDialogShown;
    -+                    }
    -+                    if (!isFirstBoot() && dexOptDialogShown) {
    -                         try {
    -                             ActivityManagerNative.getDefault().showBootMessage(
    -                                     mContext.getResources().getString(
    -@@ -7169,6 +7287,9 @@ public class PackageManagerService extends IPackageManager.Stub {
    -                                     numberOfPackagesVisited, numberOfPackagesToDexopt), true);
    -                 } catch (RemoteException e) {
    -                 }
    -+                synchronized (mPackages) {
    -+                    mDexOptDialogShown = true;
    -+                }
    -             }
    - 
    -             // If the OTA updates a system app which was previously preopted to a non-preopted state
    -@@ -8366,6 +8487,10 @@ public class PackageManagerService extends IPackageManager.Stub {
    -             pkg.applicationInfo.flags |= ApplicationInfo.FLAG_FACTORY_TEST;
    -         }
    - 
    -+        if (isSystemApp(pkg)) {
    -+            pkgSetting.isOrphaned = true;
    -+        }
    -+
    -         ArrayList<PackageParser.Package> clientLibPkgs = null;
    - 
    -         if ((scanFlags & SCAN_CHECK_ONLY) != 0) {
    -@@ -8649,7 +8774,9 @@ public class PackageManagerService extends IPackageManager.Stub {
    -             for (i=0; i<N; i++) {
    -                 PackageParser.PermissionGroup pg = pkg.permissionGroups.get(i);
    -                 PackageParser.PermissionGroup cur = mPermissionGroups.get(pg.info.name);
    --                if (cur == null) {
    -+                final String curPackageName = cur == null ? null : cur.info.packageName;
    -+                final boolean isPackageUpdate = pg.info.packageName.equals(curPackageName);
    -+                if (cur == null || isPackageUpdate) {
    -                     mPermissionGroups.put(pg.info.name, pg);
    -                     if ((policyFlags&PackageParser.PARSE_CHATTY) != 0) {
    -                         if (r == null) {
    -@@ -8657,6 +8784,9 @@ public class PackageManagerService extends IPackageManager.Stub {
    -                         } else {
    -                             r.append(' ');
    -                         }
    -+                        if (isPackageUpdate) {
    -+                            r.append("UPD:");
    -+                        }
    -                         r.append(pg.info.name);
    -                     }
    -                 } else {
    -@@ -9189,15 +9319,17 @@ public class PackageManagerService extends IPackageManager.Stub {
    -         mEphemeralInstallerActivity.packageName = pkg.applicationInfo.packageName;
    -         mEphemeralInstallerActivity.processName = pkg.applicationInfo.packageName;
    -         mEphemeralInstallerActivity.launchMode = ActivityInfo.LAUNCH_MULTIPLE;
    --        mEphemeralInstallerActivity.flags = ActivityInfo.FLAG_EXCLUDE_FROM_RECENTS |
    --                ActivityInfo.FLAG_FINISH_ON_CLOSE_SYSTEM_DIALOGS;
    -+        mEphemeralInstallerActivity.flags = ActivityInfo.FLAG_EXCLUDE_FROM_RECENTS
    -+                | ActivityInfo.FLAG_FINISH_ON_CLOSE_SYSTEM_DIALOGS;
    -         mEphemeralInstallerActivity.theme = 0;
    -         mEphemeralInstallerActivity.exported = true;
    -         mEphemeralInstallerActivity.enabled = true;
    -         mEphemeralInstallerInfo.activityInfo = mEphemeralInstallerActivity;
    -         mEphemeralInstallerInfo.priority = 0;
    --        mEphemeralInstallerInfo.preferredOrder = 0;
    --        mEphemeralInstallerInfo.match = 0;
    -+        mEphemeralInstallerInfo.preferredOrder = 1;
    -+        mEphemeralInstallerInfo.isDefault = true;
    -+        mEphemeralInstallerInfo.match = IntentFilter.MATCH_CATEGORY_SCHEME_SPECIFIC_PART
    -+                | IntentFilter.MATCH_ADJUSTMENT_NORMAL;
    - 
    -         if (DEBUG_EPHEMERAL) {
    -             Slog.d(TAG, "Set ephemeral installer activity: " + mEphemeralInstallerComponent);
    -@@ -11165,6 +11297,19 @@ public class PackageManagerService extends IPackageManager.Stub {
    - 
    -     private static final class EphemeralIntentResolver
    -             extends IntentResolver<EphemeralResolveIntentInfo, EphemeralResolveInfo> {
    -+        /**
    -+         * The result that has the highest defined order. Ordering applies on a
    -+         * per-package basis. Mapping is from package name to Pair of order and
    -+         * EphemeralResolveInfo.
    -+         * <p>
    -+         * NOTE: This is implemented as a field variable for convenience and efficiency.
    -+         * By having a field variable, we're able to track filter ordering as soon as
    -+         * a non-zero order is defined. Otherwise, multiple loops across the result set
    -+         * would be needed to apply ordering. If the intent resolver becomes re-entrant,
    -+         * this needs to be contained entirely within {@link #filterResults()}.
    -+         */
    -+        final ArrayMap<String, Pair<Integer, EphemeralResolveInfo>> mOrderResult = new ArrayMap<>();
    -+
    -         @Override
    -         protected EphemeralResolveIntentInfo[] newArray(int size) {
    -             return new EphemeralResolveIntentInfo[size];
    -@@ -11181,7 +11326,51 @@ public class PackageManagerService extends IPackageManager.Stub {
    -             if (!sUserManager.exists(userId)) {
    -                 return null;
    -             }
    --            return info.getEphemeralResolveInfo();
    -+            final String packageName = info.getEphemeralResolveInfo().getPackageName();
    -+            final Integer order = info.getOrder();
    -+            final Pair<Integer, EphemeralResolveInfo> lastOrderResult =
    -+                    mOrderResult.get(packageName);
    -+            // ordering is enabled and this item's order isn't high enough
    -+            if (lastOrderResult != null && lastOrderResult.first >= order) {
    -+                return null;
    -+            }
    -+            final EphemeralResolveInfo res = info.getEphemeralResolveInfo();
    -+            if (order > 0) {
    -+                // non-zero order, enable ordering
    -+                mOrderResult.put(packageName, new Pair<>(order, res));
    -+            }
    -+            return res;
    -+        }
    -+
    -+        @Override
    -+        protected void filterResults(List<EphemeralResolveInfo> results) {
    -+            // only do work if ordering is enabled [most of the time it won't be]
    -+            if (mOrderResult.size() == 0) {
    -+                return;
    -+            }
    -+            int resultSize = results.size();
    -+            for (int i = 0; i < resultSize; i++) {
    -+                final EphemeralResolveInfo info = results.get(i);
    -+                final String packageName = info.getPackageName();
    -+                final Pair<Integer, EphemeralResolveInfo> savedInfo = mOrderResult.get(packageName);
    -+                if (savedInfo == null) {
    -+                    // package doesn't having ordering
    -+                    continue;
    -+                }
    -+                if (savedInfo.second == info) {
    -+                    // circled back to the highest ordered item; remove from order list
    -+                    mOrderResult.remove(savedInfo);
    -+                    if (mOrderResult.size() == 0) {
    -+                        // no more ordered items
    -+                        break;
    -+                    }
    -+                    continue;
    -+                }
    -+                // item has a worse order, remove it from the result list
    -+                results.remove(i);
    -+                resultSize--;
    -+                i--;
    -+            }
    -         }
    -     }
    - 
    -@@ -11250,7 +11439,7 @@ public class PackageManagerService extends IPackageManager.Stub {
    -                     }
    -                     for (int id : resolvedUserIds) {
    -                         final Intent intent = new Intent(action,
    --                                pkg != null ? Uri.fromParts("package", pkg, null) : null);
    -+                                pkg != null ? Uri.fromParts(PACKAGE_SCHEME, pkg, null) : null);
    -                         if (extras != null) {
    -                             intent.putExtras(extras);
    -                         }
    -@@ -11746,6 +11935,12 @@ public class PackageManagerService extends IPackageManager.Stub {
    -             return false;
    -         }
    - 
    -+        if (packageName.equals(mRequiredUninstallerPackage)) {
    -+            Slog.w(TAG, "Cannot suspend/un-suspend package \"" + packageName
    -+                    + "\": required for package uninstallation");
    -+            return false;
    -+        }
    -+
    -         if (packageName.equals(mRequiredVerifierPackage)) {
    -             Slog.w(TAG, "Cannot suspend/un-suspend package \"" + packageName
    -                     + "\": required for package verification");
    -@@ -15310,6 +15505,17 @@ public class PackageManagerService extends IPackageManager.Stub {
    -         Preconditions.checkNotNull(packageName);
    -         Preconditions.checkNotNull(observer);
    -         final int uid = Binder.getCallingUid();
    -+        if (!isOrphaned(packageName)
    -+                && !isCallerAllowedToSilentlyUninstall(uid, packageName)) {
    -+            try {
    -+                final Intent intent = new Intent(Intent.ACTION_UNINSTALL_PACKAGE);
    -+                intent.setData(Uri.fromParts(PACKAGE_SCHEME, packageName, null));
    -+                intent.putExtra(PackageInstaller.EXTRA_CALLBACK, observer.asBinder());
    -+                observer.onUserActionRequired(intent);
    -+            } catch (RemoteException re) {
    -+            }
    -+            return;
    -+        }
    -         final boolean deleteAllUsers = (deleteFlags & PackageManager.DELETE_ALL_USERS) != 0;
    -         final int[] users = deleteAllUsers ? sUserManager.getUserIds() : new int[]{ userId };
    -         if (UserHandle.getUserId(uid) != userId || (deleteAllUsers && users.length > 1)) {
    -@@ -15378,6 +15584,37 @@ public class PackageManagerService extends IPackageManager.Stub {
    -         });
    -     }
    - 
    -+    private boolean isCallerAllowedToSilentlyUninstall(int callingUid, String pkgName) {
    -+        if (callingUid == Process.SHELL_UID || callingUid == Process.ROOT_UID
    -+              || callingUid == Process.SYSTEM_UID) {
    -+            return true;
    -+        }
    -+        final int callingUserId = UserHandle.getUserId(callingUid);
    -+        // If the caller installed the pkgName, then allow it to silently uninstall.
    -+        if (callingUid == getPackageUid(getInstallerPackageName(pkgName), 0, callingUserId)) {
    -+            return true;
    -+        }
    -+
    -+        // Allow package verifier to silently uninstall.
    -+        if (mRequiredVerifierPackage != null &&
    -+                callingUid == getPackageUid(mRequiredVerifierPackage, 0, callingUserId)) {
    -+            return true;
    -+        }
    -+
    -+        // Allow package uninstaller to silently uninstall.
    -+        if (mRequiredUninstallerPackage != null &&
    -+                callingUid == getPackageUid(mRequiredUninstallerPackage, 0, callingUserId)) {
    -+            return true;
    -+        }
    -+
    -+        // Allow storage manager to silently uninstall.
    -+        if (mStorageManagerPackage != null &&
    -+                callingUid == getPackageUid(mStorageManagerPackage, 0, callingUserId)) {
    -+            return true;
    -+        }
    -+        return false;
    -+    }
    -+
    -     private int[] getBlockUninstallForUsers(String packageName, int[] userIds) {
    -         int[] result = EMPTY_INT_ARRAY;
    -         for (int userId : userIds) {
    -@@ -17590,6 +17827,22 @@ Slog.v(TAG, ":: stepped forward, applying functor at tag " + parser.getName());
    -         }
    -     }
    - 
    -+    private @Nullable String getStorageManagerPackageName() {
    -+        final Intent intent = new Intent(StorageManager.ACTION_MANAGE_STORAGE);
    -+
    -+        final List<ResolveInfo> matches = queryIntentActivitiesInternal(intent, null,
    -+                MATCH_SYSTEM_ONLY | MATCH_DIRECT_BOOT_AWARE | MATCH_DIRECT_BOOT_UNAWARE
    -+                        | MATCH_DISABLED_COMPONENTS,
    -+                UserHandle.myUserId());
    -+        if (matches.size() == 1) {
    -+            return matches.get(0).getComponentInfo().packageName;
    -+        } else {
    -+            Slog.e(TAG, "There should probably be exactly one storage manager; found "
    -+                    + matches.size() + ": matches=" + matches);
    -+            return null;
    -+        }
    -+    }
    -+
    -     @Override
    -     public void setApplicationEnabledSetting(String appPackageName,
    -             int newState, int flags, int userId, String callingPackage) {
    -@@ -19463,6 +19716,9 @@ Slog.v(TAG, ":: stepped forward, applying functor at tag " + parser.getName());
    -     private void assertPackageKnown(String volumeUuid, String packageName)
    -             throws PackageManagerException {
    -         synchronized (mPackages) {
    -+            // Normalize package name to handle renamed packages
    -+            packageName = normalizePackageNameLPr(packageName);
    -+
    -             final PackageSetting ps = mSettings.mPackages.get(packageName);
    -             if (ps == null) {
    -                 throw new PackageManagerException("Package " + packageName + " is unknown");
    -@@ -19477,6 +19733,9 @@ Slog.v(TAG, ":: stepped forward, applying functor at tag " + parser.getName());
    -     private void assertPackageKnownAndInstalled(String volumeUuid, String packageName, int userId)
    -             throws PackageManagerException {
    -         synchronized (mPackages) {
    -+            // Normalize package name to handle renamed packages
    -+            packageName = normalizePackageNameLPr(packageName);
    -+
    -             final PackageSetting ps = mSettings.mPackages.get(packageName);
    -             if (ps == null) {
    -                 throw new PackageManagerException("Package " + packageName + " is unknown");
    -@@ -19553,8 +19812,6 @@ Slog.v(TAG, ":: stepped forward, applying functor at tag " + parser.getName());
    -         final File ceDir = Environment.getDataUserCeDirectory(volumeUuid, userId);
    -         final File deDir = Environment.getDataUserDeDirectory(volumeUuid, userId);
    - 
    --        boolean restoreconNeeded = false;
    --
    -         // First look for stale data that doesn't belong, and check if things
    -         // have changed since we did our last restorecon
    -         if ((flags & StorageManager.FLAG_STORAGE_CE) != 0) {
    -@@ -19565,8 +19822,6 @@ Slog.v(TAG, ":: stepped forward, applying functor at tag " + parser.getName());
    -                                 + " was still locked; this would have caused massive data loss!");
    -             }
    - 
    --            restoreconNeeded |= SELinuxMMAC.isRestoreconNeeded(ceDir);
    --
    -             final File[] files = FileUtils.listFilesOrEmpty(ceDir);
    -             for (File file : files) {
    -                 final String packageName = file.getName();
    -@@ -19584,8 +19839,6 @@ Slog.v(TAG, ":: stepped forward, applying functor at tag " + parser.getName());
    -             }
    -         }
    -         if ((flags & StorageManager.FLAG_STORAGE_DE) != 0) {
    --            restoreconNeeded |= SELinuxMMAC.isRestoreconNeeded(deDir);
    --
    -             final File[] files = FileUtils.listFilesOrEmpty(deDir);
    -             for (File file : files) {
    -                 final String packageName = file.getName();
    -@@ -19620,29 +19873,19 @@ Slog.v(TAG, ":: stepped forward, applying functor at tag " + parser.getName());
    -             }
    - 
    -             if (ps.getInstalled(userId)) {
    --                prepareAppDataLIF(ps.pkg, userId, flags, restoreconNeeded);
    -+                prepareAppDataLIF(ps.pkg, userId, flags);
    - 
    -                 if (maybeMigrateAppDataLIF(ps.pkg, userId)) {
    -                     // We may have just shuffled around app data directories, so
    -                     // prepare them one more time
    --                    prepareAppDataLIF(ps.pkg, userId, flags, restoreconNeeded);
    -+                    prepareAppDataLIF(ps.pkg, userId, flags);
    -                 }
    - 
    -                 preparedCount++;
    -             }
    -         }
    - 
    --        if (restoreconNeeded) {
    --            if ((flags & StorageManager.FLAG_STORAGE_CE) != 0) {
    --                SELinuxMMAC.setRestoreconDone(ceDir);
    --            }
    --            if ((flags & StorageManager.FLAG_STORAGE_DE) != 0) {
    --                SELinuxMMAC.setRestoreconDone(deDir);
    --            }
    --        }
    --
    --        Slog.v(TAG, "reconcileAppsData finished " + preparedCount
    --                + " packages; restoreconNeeded was " + restoreconNeeded);
    -+        Slog.v(TAG, "reconcileAppsData finished " + preparedCount + " packages");
    -     }
    - 
    -     /**
    -@@ -19677,9 +19920,8 @@ Slog.v(TAG, ":: stepped forward, applying functor at tag " + parser.getName());
    -             }
    - 
    -             if (ps.getInstalled(user.id)) {
    --                // Whenever an app changes, force a restorecon of its data
    -                 // TODO: when user data is locked, mark that we're still dirty
    --                prepareAppDataLIF(pkg, user.id, flags, true);
    -+                prepareAppDataLIF(pkg, user.id, flags);
    -             }
    -         }
    -     }
    -@@ -19692,24 +19934,22 @@ Slog.v(TAG, ":: stepped forward, applying functor at tag " + parser.getName());
    -      * will try recovering system apps by wiping data; third-party app data is
    -      * left intact.
    -      */
    --    private void prepareAppDataLIF(PackageParser.Package pkg, int userId, int flags,
    --            boolean restoreconNeeded) {
    -+    private void prepareAppDataLIF(PackageParser.Package pkg, int userId, int flags) {
    -         if (pkg == null) {
    -             Slog.wtf(TAG, "Package was null!", new Throwable());
    -             return;
    -         }
    --        prepareAppDataLeafLIF(pkg, userId, flags, restoreconNeeded);
    -+        prepareAppDataLeafLIF(pkg, userId, flags);
    -         final int childCount = (pkg.childPackages != null) ? pkg.childPackages.size() : 0;
    -         for (int i = 0; i < childCount; i++) {
    --            prepareAppDataLeafLIF(pkg.childPackages.get(i), userId, flags, restoreconNeeded);
    -+            prepareAppDataLeafLIF(pkg.childPackages.get(i), userId, flags);
    -         }
    -     }
    - 
    --    private void prepareAppDataLeafLIF(PackageParser.Package pkg, int userId, int flags,
    --            boolean restoreconNeeded) {
    -+    private void prepareAppDataLeafLIF(PackageParser.Package pkg, int userId, int flags) {
    -         if (DEBUG_APP_DATA) {
    -             Slog.v(TAG, "prepareAppData for " + pkg.packageName + " u" + userId + " 0x"
    --                    + Integer.toHexString(flags) + (restoreconNeeded ? " restoreconNeeded" : ""));
    -+                    + Integer.toHexString(flags));
    -         }
    - 
    -         final String volumeUuid = pkg.volumeUuid;
    -@@ -19739,15 +19979,6 @@ Slog.v(TAG, ":: stepped forward, applying functor at tag " + parser.getName());
    -             }
    -         }
    - 
    --        if (restoreconNeeded) {
    --            try {
    --                mInstaller.restoreconAppData(volumeUuid, packageName, userId, flags, appId,
    --                        app.seinfo);
    --            } catch (InstallerException e) {
    --                Slog.e(TAG, "Failed to restorecon for " + packageName + ": " + e);
    --            }
    --        }
    --
    -         if ((flags & StorageManager.FLAG_STORAGE_CE) != 0) {
    -             try {
    -                 // CE storage is unlocked right now, so read out the inode and
    -@@ -20842,6 +21073,13 @@ Slog.v(TAG, ":: stepped forward, applying functor at tag " + parser.getName());
    -         public boolean isPackageDataProtected(int userId, String packageName) {
    -             return mProtectedPackages.isPackageDataProtected(userId, packageName);
    -         }
    -+
    -+        @Override
    -+        public boolean wasPackageEverLaunched(String packageName, int userId) {
    -+            synchronized (mPackages) {
    -+                return mSettings.wasPackageEverLaunchedLPr(packageName, userId);
    -+            }
    -+        }
    -     }
    - 
    -     @Override
    -diff --git a/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java b/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java
    -index 751c585..cfd0af7 100644
    ---- a/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java
    -+++ b/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java
    -@@ -19,6 +19,7 @@ package com.android.server.pm;
    - import static com.android.server.pm.PackageManagerService.DEBUG_DEXOPT;
    - import static com.android.server.pm.PackageManagerService.TAG;
    - 
    -+import android.annotation.NonNull;
    - import android.app.AppGlobals;
    - import android.content.Intent;
    - import android.content.pm.PackageParser;
    -@@ -35,13 +36,9 @@ import java.io.IOException;
    - import java.util.ArrayList;
    - import java.util.Collection;
    - import java.util.Collections;
    --import java.util.Comparator;
    --import java.util.Date;
    --import java.util.HashSet;
    --import java.util.Iterator;
    - import java.util.LinkedList;
    - import java.util.List;
    --import java.util.Set;
    -+import java.util.function.Predicate;
    - 
    - /**
    -  * Class containing helper methods for the PackageManagerService.
    -@@ -67,34 +64,51 @@ public class PackageManagerServiceUtils {
    -         return pkgNames;
    -     }
    - 
    --    private static void filterRecentlyUsedApps(Collection<PackageParser.Package> pkgs,
    --            long estimatedPreviousSystemUseTime,
    --            long dexOptLRUThresholdInMills) {
    --        // Filter out packages that aren't recently used.
    --        int total = pkgs.size();
    --        int skipped = 0;
    --        for (Iterator<PackageParser.Package> i = pkgs.iterator(); i.hasNext();) {
    --            PackageParser.Package pkg = i.next();
    --            long then = pkg.getLatestForegroundPackageUseTimeInMills();
    --            if (then < estimatedPreviousSystemUseTime - dexOptLRUThresholdInMills) {
    --                if (DEBUG_DEXOPT) {
    --                    Log.i(TAG, "Skipping dexopt of " + pkg.packageName +
    --                            " last used in foreground: " +
    --                            ((then == 0) ? "never" : new Date(then)));
    --                }
    --                i.remove();
    --                skipped++;
    --            } else {
    --                if (DEBUG_DEXOPT) {
    --                    Log.i(TAG, "Will dexopt " + pkg.packageName +
    --                            " last used in foreground: " +
    --                            ((then == 0) ? "never" : new Date(then)));
    --                }
    -+    // Sort a list of apps by their last usage, most recently used apps first. The order of
    -+    // packages without usage data is undefined (but they will be sorted after the packages
    -+    // that do have usage data).
    -+    public static void sortPackagesByUsageDate(List<PackageParser.Package> pkgs,
    -+            PackageManagerService packageManagerService) {
    -+        if (!packageManagerService.isHistoricalPackageUsageAvailable()) {
    -+            return;
    -+        }
    -+
    -+        Collections.sort(pkgs, (pkg1, pkg2) ->
    -+                Long.compare(pkg2.getLatestForegroundPackageUseTimeInMills(),
    -+                        pkg1.getLatestForegroundPackageUseTimeInMills()));
    -+    }
    -+
    -+    // Apply the given {@code filter} to all packages in {@code packages}. If tested positive, the
    -+    // package will be removed from {@code packages} and added to {@code result} with its
    -+    // dependencies. If usage data is available, the positive packages will be sorted by usage
    -+    // data (with {@code sortTemp} as temporary storage).
    -+    private static void applyPackageFilter(Predicate<PackageParser.Package> filter,
    -+            Collection<PackageParser.Package> result,
    -+            Collection<PackageParser.Package> packages,
    -+            @NonNull List<PackageParser.Package> sortTemp,
    -+            PackageManagerService packageManagerService) {
    -+        for (PackageParser.Package pkg : packages) {
    -+            if (filter.test(pkg)) {
    -+                sortTemp.add(pkg);
    -             }
    -         }
    --        if (DEBUG_DEXOPT) {
    --            Log.i(TAG, "Skipped dexopt " + skipped + " of " + total);
    -+
    -+        sortPackagesByUsageDate(sortTemp, packageManagerService);
    -+        packages.removeAll(sortTemp);
    -+
    -+        for (PackageParser.Package pkg : sortTemp) {
    -+            result.add(pkg);
    -+
    -+            Collection<PackageParser.Package> deps =
    -+                    packageManagerService.findSharedNonSystemLibraries(pkg);
    -+            if (!deps.isEmpty()) {
    -+                deps.removeAll(result);
    -+                result.addAll(deps);
    -+                packages.removeAll(deps);
    -+            }
    -         }
    -+
    -+        sortTemp.clear();
    -     }
    - 
    -     // Sort apps by importance for dexopt ordering. Important apps are given
    -@@ -104,46 +118,25 @@ public class PackageManagerServiceUtils {
    -             PackageManagerService packageManagerService) {
    -         ArrayList<PackageParser.Package> remainingPkgs = new ArrayList<>(packages);
    -         LinkedList<PackageParser.Package> result = new LinkedList<>();
    -+        ArrayList<PackageParser.Package> sortTemp = new ArrayList<>(remainingPkgs.size());
    - 
    -         // Give priority to core apps.
    --        for (PackageParser.Package pkg : remainingPkgs) {
    --            if (pkg.coreApp) {
    --                if (DEBUG_DEXOPT) {
    --                    Log.i(TAG, "Adding core app " + result.size() + ": " + pkg.packageName);
    --                }
    --                result.add(pkg);
    --            }
    --        }
    --        remainingPkgs.removeAll(result);
    -+        applyPackageFilter((pkg) -> pkg.coreApp, result, remainingPkgs, sortTemp,
    -+                packageManagerService);
    - 
    -         // Give priority to system apps that listen for pre boot complete.
    -         Intent intent = new Intent(Intent.ACTION_PRE_BOOT_COMPLETED);
    --        ArraySet<String> pkgNames = getPackageNamesForIntent(intent, UserHandle.USER_SYSTEM);
    --        for (PackageParser.Package pkg : remainingPkgs) {
    --            if (pkgNames.contains(pkg.packageName)) {
    --                if (DEBUG_DEXOPT) {
    --                    Log.i(TAG, "Adding pre boot system app " + result.size() + ": " +
    --                            pkg.packageName);
    --                }
    --                result.add(pkg);
    --            }
    --        }
    --        remainingPkgs.removeAll(result);
    -+        final ArraySet<String> pkgNames = getPackageNamesForIntent(intent, UserHandle.USER_SYSTEM);
    -+        applyPackageFilter((pkg) -> pkgNames.contains(pkg.packageName), result, remainingPkgs,
    -+                sortTemp, packageManagerService);
    - 
    -         // Give priority to apps used by other apps.
    --        for (PackageParser.Package pkg : remainingPkgs) {
    --            if (PackageDexOptimizer.isUsedByOtherApps(pkg)) {
    --                if (DEBUG_DEXOPT) {
    --                    Log.i(TAG, "Adding app used by other apps " + result.size() + ": " +
    --                            pkg.packageName);
    --                }
    --                result.add(pkg);
    --            }
    --        }
    --        remainingPkgs.removeAll(result);
    -+        applyPackageFilter((pkg) -> PackageDexOptimizer.isUsedByOtherApps(pkg), result,
    -+                remainingPkgs, sortTemp, packageManagerService);
    - 
    -         // Filter out packages that aren't recently used, add all remaining apps.
    -         // TODO: add a property to control this?
    -+        Predicate<PackageParser.Package> remainingPredicate;
    -         if (!remainingPkgs.isEmpty() && packageManagerService.isHistoricalPackageUsageAvailable()) {
    -             if (DEBUG_DEXOPT) {
    -                 Log.i(TAG, "Looking at historical package use");
    -@@ -159,34 +152,24 @@ public class PackageManagerServiceUtils {
    -                     lastUsed.getLatestForegroundPackageUseTimeInMills();
    -             // Be defensive if for some reason package usage has bogus data.
    -             if (estimatedPreviousSystemUseTime != 0) {
    --                filterRecentlyUsedApps(remainingPkgs, estimatedPreviousSystemUseTime,
    --                        SEVEN_DAYS_IN_MILLISECONDS);
    -+                final long cutoffTime = estimatedPreviousSystemUseTime - SEVEN_DAYS_IN_MILLISECONDS;
    -+                remainingPredicate =
    -+                        (pkg) -> pkg.getLatestForegroundPackageUseTimeInMills() >= cutoffTime;
    -+            } else {
    -+                // No meaningful historical info. Take all.
    -+                remainingPredicate = (pkg) -> true;
    -             }
    -+            sortPackagesByUsageDate(remainingPkgs, packageManagerService);
    -+        } else {
    -+            // No historical info. Take all.
    -+            remainingPredicate = (pkg) -> true;
    -         }
    --        result.addAll(remainingPkgs);
    --
    --        // Now go ahead and also add the libraries required for these packages.
    --        // TODO: Think about interleaving things.
    --        Set<PackageParser.Package> dependencies = new HashSet<>();
    --        for (PackageParser.Package p : result) {
    --            dependencies.addAll(packageManagerService.findSharedNonSystemLibraries(p));
    --        }
    --        if (!dependencies.isEmpty()) {
    --            // We might have packages already in `result` that are dependencies
    --            // of other packages. Make sure we don't add those to the list twice.
    --            dependencies.removeAll(result);
    --        }
    --        result.addAll(dependencies);
    -+        applyPackageFilter(remainingPredicate, result, remainingPkgs, sortTemp,
    -+                packageManagerService);
    - 
    -         if (DEBUG_DEXOPT) {
    --            StringBuilder sb = new StringBuilder();
    --            for (PackageParser.Package pkg : result) {
    --                if (sb.length() > 0) {
    --                    sb.append(", ");
    --                }
    --                sb.append(pkg.packageName);
    --            }
    --            Log.i(TAG, "Packages to be dexopted: " + sb.toString());
    -+            Log.i(TAG, "Packages to be dexopted: " + packagesToString(result));
    -+            Log.i(TAG, "Packages skipped from dexopt: " + packagesToString(remainingPkgs));
    -         }
    - 
    -         return result;
    -@@ -203,4 +186,15 @@ public class PackageManagerServiceUtils {
    -             throw ee.rethrowAsIOException();
    -         }
    -     }
    -+
    -+    public static String packagesToString(Collection<PackageParser.Package> c) {
    -+        StringBuilder sb = new StringBuilder();
    -+        for (PackageParser.Package pkg : c) {
    -+            if (sb.length() > 0) {
    -+                sb.append(", ");
    -+            }
    -+            sb.append(pkg.packageName);
    -+        }
    -+        return sb.toString();
    -+    }
    - }
    -diff --git a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
    -index e5ddfd0..3bfa6b8 100644
    ---- a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
    -+++ b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
    -@@ -30,6 +30,10 @@ import android.content.pm.PackageInfo;
    - import android.content.pm.PackageInstaller;
    - import android.content.pm.PackageItemInfo;
    - import android.content.pm.PackageManager;
    -+import android.content.pm.PackageParser;
    -+import android.content.pm.PackageParser.ApkLite;
    -+import android.content.pm.PackageParser.PackageLite;
    -+import android.content.pm.PackageParser.PackageParserException;
    - import android.content.pm.ParceledListSlice;
    - import android.content.pm.PermissionGroupInfo;
    - import android.content.pm.PermissionInfo;
    -@@ -48,6 +52,7 @@ import android.os.SystemProperties;
    - import android.os.UserHandle;
    - import android.text.TextUtils;
    - import android.util.PrintWriterPrinter;
    -+import com.android.internal.content.PackageHelper;
    - import com.android.internal.util.SizedInputStream;
    - 
    - import dalvik.system.DexFile;
    -@@ -137,11 +142,33 @@ class PackageManagerShellCommand extends ShellCommand {
    -     private int runInstall() throws RemoteException {
    -         final PrintWriter pw = getOutPrintWriter();
    -         final InstallParams params = makeInstallParams();
    -+        final String inPath = getNextArg();
    -+        boolean installExternal =
    -+                (params.sessionParams.installFlags & PackageManager.INSTALL_EXTERNAL) != 0;
    -+        if (params.sessionParams.sizeBytes < 0 && inPath != null) {
    -+            File file = new File(inPath);
    -+            if (file.isFile()) {
    -+                if (installExternal) {
    -+                    try {
    -+                        ApkLite baseApk = PackageParser.parseApkLite(file, 0);
    -+                        PackageLite pkgLite = new PackageLite(null, baseApk, null, null, null);
    -+                        params.sessionParams.setSize(
    -+                                PackageHelper.calculateInstalledSize(pkgLite, false,
    -+                                        params.sessionParams.abiOverride));
    -+                    } catch (PackageParserException | IOException e) {
    -+                        pw.println("Error: Failed to parse APK file : " + e);
    -+                        return 1;
    -+                    }
    -+                } else {
    -+                    params.sessionParams.setSize(file.length());
    -+                }
    -+            }
    -+        }
    -+
    -         final int sessionId = doCreateSession(params.sessionParams,
    -                 params.installerPackageName, params.userId);
    -         boolean abandonSession = true;
    -         try {
    --            final String inPath = getNextArg();
    -             if (inPath == null && params.sessionParams.sizeBytes == 0) {
    -                 pw.println("Error: must either specify a package size or an APK file");
    -                 return 1;
    -@@ -1147,14 +1174,15 @@ class PackageManagerShellCommand extends ShellCommand {
    -     private int doWriteSplit(int sessionId, String inPath, long sizeBytes, String splitName,
    -             boolean logSuccess) throws RemoteException {
    -         final PrintWriter pw = getOutPrintWriter();
    --        if ("-".equals(inPath)) {
    --            inPath = null;
    --        } else if (inPath != null) {
    --            final File file = new File(inPath);
    --            if (file.isFile()) {
    --                sizeBytes = file.length();
    --            }
    -+        if (sizeBytes <= 0) {
    -+            pw.println("Error: must specify a APK size");
    -+            return 1;
    -+        }
    -+        if (inPath != null && !"-".equals(inPath)) {
    -+            pw.println("Error: APK content must be streamed");
    -+            return 1;
    -         }
    -+        inPath = null;
    - 
    -         final SessionInfo info = mInterface.getPackageInstaller().getSessionInfo(sessionId);
    - 
    -diff --git a/services/core/java/com/android/server/pm/SELinuxMMAC.java b/services/core/java/com/android/server/pm/SELinuxMMAC.java
    -index 8970556..2176eb1 100644
    ---- a/services/core/java/com/android/server/pm/SELinuxMMAC.java
    -+++ b/services/core/java/com/android/server/pm/SELinuxMMAC.java
    -@@ -19,10 +19,6 @@ package com.android.server.pm;
    - import android.content.pm.PackageParser;
    - import android.content.pm.Signature;
    - import android.os.Environment;
    --import android.os.SystemProperties;
    --import android.system.ErrnoException;
    --import android.system.Os;
    --import android.system.OsConstants;
    - import android.util.Slog;
    - import android.util.Xml;
    - 
    -@@ -34,10 +30,7 @@ import org.xmlpull.v1.XmlPullParserException;
    - import java.io.File;
    - import java.io.FileReader;
    - import java.io.IOException;
    --import java.security.MessageDigest;
    --import java.security.NoSuchAlgorithmException;
    - import java.util.ArrayList;
    --import java.util.Arrays;
    - import java.util.Collections;
    - import java.util.Comparator;
    - import java.util.HashMap;
    -@@ -65,24 +58,10 @@ public final class SELinuxMMAC {
    -     // to synchronize access during policy load and access attempts.
    -     private static List<Policy> sPolicies = new ArrayList<>();
    - 
    --    private static final String PROP_FORCE_RESTORECON = "sys.force_restorecon";
    --
    --    /** Path to version on rootfs */
    --    private static final File VERSION_FILE = new File("/selinux_version");
    --
    -     /** Path to MAC permissions on system image */
    -     private static final File MAC_PERMISSIONS = new File(Environment.getRootDirectory(),
    -             "/etc/security/mac_permissions.xml");
    - 
    --    /** Path to app contexts on rootfs */
    --    private static final File SEAPP_CONTEXTS = new File("/seapp_contexts");
    --
    --    /** Calculated hash of {@link #SEAPP_CONTEXTS} */
    --    private static final byte[] SEAPP_CONTEXTS_HASH = returnHash(SEAPP_CONTEXTS);
    --
    --    /** Attribute where {@link #SEAPP_CONTEXTS_HASH} is stored */
    --    private static final String XATTR_SEAPP_HASH = "user.seapp_hash";
    --
    -     // Append privapp to existing seinfo label
    -     private static final String PRIVILEGED_APP_STR = ":privapp";
    - 
    -@@ -313,66 +292,6 @@ public final class SELinuxMMAC {
    -                     "seinfo=" + pkg.applicationInfo.seinfo);
    -         }
    -     }
    --
    --    /**
    --     * Determines if a recursive restorecon on the given package data directory
    --     * is needed. It does this by comparing the SHA-1 of the seapp_contexts file
    --     * against the stored hash in an xattr.
    --     * <p>
    --     * Note that the xattr isn't in the 'security' namespace, so this should
    --     * only be run on directories owned by the system.
    --     *
    --     * @return Returns true if the restorecon should occur or false otherwise.
    --     */
    --    public static boolean isRestoreconNeeded(File file) {
    --        // To investigate boot timing, allow a property to always force restorecon
    --        if (SystemProperties.getBoolean(PROP_FORCE_RESTORECON, false)) {
    --            return true;
    --        }
    --
    --        try {
    --            final byte[] buf = new byte[20];
    --            final int len = Os.getxattr(file.getAbsolutePath(), XATTR_SEAPP_HASH, buf);
    --            if ((len == 20) && Arrays.equals(SEAPP_CONTEXTS_HASH, buf)) {
    --                return false;
    --            }
    --        } catch (ErrnoException e) {
    --            if (e.errno != OsConstants.ENODATA) {
    --                Slog.e(TAG, "Failed to read seapp hash for " + file, e);
    --            }
    --        }
    --
    --        return true;
    --    }
    --
    --    /**
    --     * Stores the SHA-1 of the seapp_contexts into an xattr.
    --     * <p>
    --     * Note that the xattr isn't in the 'security' namespace, so this should
    --     * only be run on directories owned by the system.
    --     */
    --    public static void setRestoreconDone(File file) {
    --        try {
    --            Os.setxattr(file.getAbsolutePath(), XATTR_SEAPP_HASH, SEAPP_CONTEXTS_HASH, 0);
    --        } catch (ErrnoException e) {
    --            Slog.e(TAG, "Failed to persist seapp hash in " + file, e);
    --        }
    --    }
    --
    --    /**
    --     * Return the SHA-1 of a file.
    --     *
    --     * @param file The path to the file given as a string.
    --     * @return Returns the SHA-1 of the file as a byte array.
    --     */
    --    private static byte[] returnHash(File file) {
    --        try {
    --            final byte[] contents = IoUtils.readFileAsByteArray(file.getAbsolutePath());
    --            return MessageDigest.getInstance("SHA-1").digest(contents);
    --        } catch (IOException | NoSuchAlgorithmException e) {
    --            throw new RuntimeException(e);
    --        }
    --    }
    - }
    - 
    - /**
    -diff --git a/services/core/java/com/android/server/pm/Settings.java b/services/core/java/com/android/server/pm/Settings.java
    -index 5126305..b0c536f 100644
    ---- a/services/core/java/com/android/server/pm/Settings.java
    -+++ b/services/core/java/com/android/server/pm/Settings.java
    -@@ -4154,6 +4154,14 @@ final class Settings {
    -         return pkg.getCurrentEnabledStateLPr(classNameStr, userId);
    -     }
    - 
    -+    boolean wasPackageEverLaunchedLPr(String packageName, int userId) {
    -+        final PackageSetting pkgSetting = mPackages.get(packageName);
    -+        if (pkgSetting == null) {
    -+            throw new IllegalArgumentException("Unknown package: " + packageName);
    -+        }
    -+        return !pkgSetting.getNotLaunched(userId);
    -+    }
    -+
    -     boolean setPackageStoppedStateLPw(PackageManagerService pm, String packageName,
    -             boolean stopped, boolean allowedByPermission, int uid, int userId) {
    -         int appId = UserHandle.getAppId(uid);
    -diff --git a/services/core/java/com/android/server/pm/ShortcutLauncher.java b/services/core/java/com/android/server/pm/ShortcutLauncher.java
    -index df51923..2af1bcb 100644
    ---- a/services/core/java/com/android/server/pm/ShortcutLauncher.java
    -+++ b/services/core/java/com/android/server/pm/ShortcutLauncher.java
    -@@ -17,6 +17,7 @@ package com.android.server.pm;
    - 
    - import android.annotation.NonNull;
    - import android.annotation.UserIdInt;
    -+import android.content.pm.PackageInfo;
    - import android.content.pm.ShortcutInfo;
    - import android.util.ArrayMap;
    - import android.util.ArraySet;
    -@@ -151,6 +152,16 @@ class ShortcutLauncher extends ShortcutPackageItem {
    -         return mPinnedShortcuts.remove(PackageWithUser.of(packageUserId, packageName)) != null;
    -     }
    - 
    -+    public void ensureVersionInfo() {
    -+        final PackageInfo pi = mShortcutUser.mService.getPackageInfoWithSignatures(
    -+                getPackageName(), getPackageUserId());
    -+        if (pi == null) {
    -+            Slog.w(TAG, "Package not found: " + getPackageName());
    -+            return;
    -+        }
    -+        getPackageInfo().updateVersionInfo(pi);
    -+    }
    -+
    -     /**
    -      * Persist.
    -      */
    -@@ -202,7 +213,7 @@ class ShortcutLauncher extends ShortcutPackageItem {
    -                 fromBackup ? ownerUserId
    -                 : ShortcutService.parseIntAttribute(parser, ATTR_LAUNCHER_USER_ID, ownerUserId);
    - 
    --        final ShortcutLauncher ret = new ShortcutLauncher(shortcutUser, launcherUserId,
    -+        final ShortcutLauncher ret = new ShortcutLauncher(shortcutUser, ownerUserId,
    -                 launcherPackageName, launcherUserId);
    - 
    -         ArraySet<String> ids = null;
    -diff --git a/services/core/java/com/android/server/pm/ShortcutPackage.java b/services/core/java/com/android/server/pm/ShortcutPackage.java
    -index 827b88a..38d69ed 100644
    ---- a/services/core/java/com/android/server/pm/ShortcutPackage.java
    -+++ b/services/core/java/com/android/server/pm/ShortcutPackage.java
    -@@ -23,7 +23,6 @@ import android.content.Intent;
    - import android.content.pm.PackageInfo;
    - import android.content.pm.ShortcutInfo;
    - import android.content.res.Resources;
    --import android.os.Bundle;
    - import android.os.PersistableBundle;
    - import android.text.format.Formatter;
    - import android.util.ArrayMap;
    -@@ -145,30 +144,6 @@ class ShortcutPackage extends ShortcutPackageItem {
    -         return mPackageUid;
    -     }
    - 
    --    /**
    --     * Called when a shortcut is about to be published.  At this point we know the publisher
    --     * package
    --     * exists (as opposed to Launcher trying to fetch shortcuts from a non-existent package), so
    --     * we do some initialization for the package.
    --     */
    --    private void ensurePackageVersionInfo() {
    --        // Make sure we have the version code for the app.  We need the version code in
    --        // handlePackageUpdated().
    --        if (getPackageInfo().getVersionCode() < 0) {
    --            final ShortcutService s = mShortcutUser.mService;
    --
    --            final PackageInfo pi = s.getPackageInfo(getPackageName(), getOwnerUserId());
    --            if (pi != null) {
    --                if (ShortcutService.DEBUG) {
    --                    Slog.d(TAG, String.format("Package %s version = %d", getPackageName(),
    --                            pi.versionCode));
    --                }
    --                getPackageInfo().updateVersionInfo(pi);
    --                s.scheduleSaveUser(getOwnerUserId());
    --            }
    --        }
    --    }
    --
    -     @Nullable
    -     public Resources getPackageResources() {
    -         return mShortcutUser.mService.injectGetResourcesForApplicationAsUser(
    -@@ -251,8 +226,6 @@ class ShortcutPackage extends ShortcutPackageItem {
    -         Preconditions.checkArgument(newShortcut.isEnabled(),
    -                 "add/setDynamicShortcuts() cannot publish disabled shortcuts");
    - 
    --        ensurePackageVersionInfo();
    --
    -         newShortcut.addFlags(ShortcutInfo.FLAG_DYNAMIC);
    - 
    -         final ShortcutInfo oldShortcut = mShortcuts.get(newShortcut.getId());
    -@@ -662,17 +635,32 @@ class ShortcutPackage extends ShortcutPackageItem {
    -                 return false; // Shouldn't happen.
    -             }
    - 
    --            if (!isNewApp && !forceRescan) {
    -+            // Always scan the settings app, since its version code is the same for DR and MR1.
    -+            // TODO Fix it properly: b/32554059
    -+            final boolean isSettings = "com.android.settings".equals(getPackageName());
    -+
    -+            if (!isNewApp && !forceRescan && !isSettings) {
    -                 // Return if the package hasn't changed, ie:
    -                 // - version code hasn't change
    -                 // - lastUpdateTime hasn't change
    -                 // - all target activities are still enabled.
    -+
    -+                // Note, system apps timestamps do *not* change after OTAs.  (But they do
    -+                // after an adb sync or a local flash.)
    -+                // This means if a system app's version code doesn't change on an OTA,
    -+                // we don't notice it's updated.  But that's fine since their version code *should*
    -+                // really change on OTAs.
    -                 if ((getPackageInfo().getVersionCode() == pi.versionCode)
    -                         && (getPackageInfo().getLastUpdateTime() == pi.lastUpdateTime)
    -                         && areAllActivitiesStillEnabled()) {
    -                     return false;
    -                 }
    -             }
    -+            if (isSettings) {
    -+                if (ShortcutService.DEBUG) {
    -+                    Slog.d(TAG, "Always scan settings.");
    -+                }
    -+            }
    -         } finally {
    -             s.logDurationStat(Stats.PACKAGE_UPDATE_CHECK, start);
    -         }
    -@@ -1145,6 +1133,17 @@ class ShortcutPackage extends ShortcutPackageItem {
    -         }
    -     }
    - 
    -+    /** @return true if there's any shortcuts that are not manifest shortcuts. */
    -+    public boolean hasNonManifestShortcuts() {
    -+        for (int i = mShortcuts.size() - 1; i >= 0; i--) {
    -+            final ShortcutInfo si = mShortcuts.valueAt(i);
    -+            if (!si.isDeclaredInManifest()) {
    -+                return true;
    -+            }
    -+        }
    -+        return false;
    -+    }
    -+
    -     public void dump(@NonNull PrintWriter pw, @NonNull String prefix) {
    -         pw.println();
    - 
    -diff --git a/services/core/java/com/android/server/pm/ShortcutPackageInfo.java b/services/core/java/com/android/server/pm/ShortcutPackageInfo.java
    -index e7b66fc..4de15de 100644
    ---- a/services/core/java/com/android/server/pm/ShortcutPackageInfo.java
    -+++ b/services/core/java/com/android/server/pm/ShortcutPackageInfo.java
    -@@ -20,6 +20,7 @@ import android.annotation.UserIdInt;
    - import android.content.pm.PackageInfo;
    - import android.util.Slog;
    - 
    -+import com.android.internal.annotations.VisibleForTesting;
    - import com.android.server.backup.BackupUtils;
    - 
    - import libcore.io.Base64;
    -@@ -89,6 +90,7 @@ class ShortcutPackageInfo {
    -         return mLastUpdateTime;
    -     }
    - 
    -+    /** Set {@link #mVersionCode} and {@link #mLastUpdateTime} from a {@link PackageInfo}. */
    -     public void updateVersionInfo(@NonNull PackageInfo pi) {
    -         if (pi != null) {
    -             mVersionCode = pi.versionCode;
    -@@ -119,7 +121,8 @@ class ShortcutPackageInfo {
    -         return true;
    -     }
    - 
    --    public static ShortcutPackageInfo generateForInstalledPackage(
    -+    @VisibleForTesting
    -+    public static ShortcutPackageInfo generateForInstalledPackageForTest(
    -             ShortcutService s, String packageName, @UserIdInt int packageUserId) {
    -         final PackageInfo pi = s.getPackageInfoWithSignatures(packageName, packageUserId);
    -         if (pi.signatures == null || pi.signatures.length == 0) {
    -@@ -132,7 +135,7 @@ class ShortcutPackageInfo {
    -         return ret;
    -     }
    - 
    --    public void refresh(ShortcutService s, ShortcutPackageItem pkg) {
    -+    public void refreshSignature(ShortcutService s, ShortcutPackageItem pkg) {
    -         if (mIsShadow) {
    -             s.wtf("Attempted to refresh package info for shadow package " + pkg.getPackageName()
    -                     + ", user=" + pkg.getOwnerUserId());
    -@@ -145,8 +148,6 @@ class ShortcutPackageInfo {
    -             Slog.w(TAG, "Package not found: " + pkg.getPackageName());
    -             return;
    -         }
    --        mVersionCode = pi.versionCode;
    --        mLastUpdateTime = pi.lastUpdateTime;
    -         mSigHashes = BackupUtils.hashSignatureArray(pi.signatures);
    -     }
    - 
    -diff --git a/services/core/java/com/android/server/pm/ShortcutPackageItem.java b/services/core/java/com/android/server/pm/ShortcutPackageItem.java
    -index 79b5c4e..1f195a7 100644
    ---- a/services/core/java/com/android/server/pm/ShortcutPackageItem.java
    -+++ b/services/core/java/com/android/server/pm/ShortcutPackageItem.java
    -@@ -40,7 +40,7 @@ abstract class ShortcutPackageItem {
    - 
    -     private final ShortcutPackageInfo mPackageInfo;
    - 
    --    protected final ShortcutUser mShortcutUser;
    -+    protected ShortcutUser mShortcutUser;
    - 
    -     protected ShortcutPackageItem(@NonNull ShortcutUser shortcutUser,
    -             int packageUserId, @NonNull String packageName,
    -@@ -51,6 +51,13 @@ abstract class ShortcutPackageItem {
    -         mPackageInfo = Preconditions.checkNotNull(packageInfo);
    -     }
    - 
    -+    /**
    -+     * Change the parent {@link ShortcutUser}.  Need it in the restore code.
    -+     */
    -+    public void replaceUser(ShortcutUser user) {
    -+        mShortcutUser = user;
    -+    }
    -+
    -     public ShortcutUser getUser() {
    -         return mShortcutUser;
    -     }
    -@@ -58,8 +65,7 @@ abstract class ShortcutPackageItem {
    -     /**
    -      * ID of the user who actually has this package running on.  For {@link ShortcutPackage},
    -      * this is the same thing as {@link #getOwnerUserId}, but if it's a {@link ShortcutLauncher} and
    --     * {@link #getOwnerUserId} is of a work profile, then this ID could be the user who owns the
    --     * profile.
    -+     * {@link #getOwnerUserId} is of work profile, then this ID is of the primary user.
    -      */
    -     public int getPackageUserId() {
    -         return mPackageUserId;
    -@@ -79,12 +85,12 @@ abstract class ShortcutPackageItem {
    -         return mPackageInfo;
    -     }
    - 
    --    public void refreshPackageInfoAndSave() {
    -+    public void refreshPackageSignatureAndSave() {
    -         if (mPackageInfo.isShadow()) {
    -             return; // Don't refresh for shadow user.
    -         }
    -         final ShortcutService s = mShortcutUser.mService;
    --        mPackageInfo.refresh(s, this);
    -+        mPackageInfo.refreshSignature(s, this);
    -         s.scheduleSaveUser(getOwnerUserId());
    -     }
    - 
    -diff --git a/services/core/java/com/android/server/pm/ShortcutService.java b/services/core/java/com/android/server/pm/ShortcutService.java
    -index c1fc7f1..13f558e 100644
    ---- a/services/core/java/com/android/server/pm/ShortcutService.java
    -+++ b/services/core/java/com/android/server/pm/ShortcutService.java
    -@@ -54,6 +54,7 @@ import android.graphics.RectF;
    - import android.graphics.drawable.Icon;
    - import android.net.Uri;
    - import android.os.Binder;
    -+import android.os.Build;
    - import android.os.Environment;
    - import android.os.FileUtils;
    - import android.os.Handler;
    -@@ -324,9 +325,29 @@ public class ShortcutService extends IShortcutService.Stub {
    -         int CHECK_LAUNCHER_ACTIVITY = 12;
    -         int IS_ACTIVITY_ENABLED = 13;
    -         int PACKAGE_UPDATE_CHECK = 14;
    --
    --        int COUNT = PACKAGE_UPDATE_CHECK + 1;
    --    }
    -+        int ASYNC_PRELOAD_USER_DELAY = 15;
    -+
    -+        int COUNT = ASYNC_PRELOAD_USER_DELAY + 1;
    -+    }
    -+
    -+    private static final String[] STAT_LABELS = {
    -+            "getHomeActivities()",
    -+            "Launcher permission check",
    -+            "getPackageInfo()",
    -+            "getPackageInfo(SIG)",
    -+            "getApplicationInfo",
    -+            "cleanupDanglingBitmaps",
    -+            "getActivity+metadata",
    -+            "getInstalledPackages",
    -+            "checkPackageChanges",
    -+            "getApplicationResources",
    -+            "resourceNameLookup",
    -+            "getLauncherActivity",
    -+            "checkLauncherActivity",
    -+            "isActivityEnabled",
    -+            "packageUpdateCheck",
    -+            "asyncPreloadUserDelay"
    -+    };
    - 
    -     final Object mStatLock = new Object();
    - 
    -@@ -359,6 +380,12 @@ public class ShortcutService extends IShortcutService.Stub {
    -     @GuardedBy("mLock")
    -     private Exception mLastWtfStacktrace;
    - 
    -+    static class InvalidFileFormatException extends Exception {
    -+        public InvalidFileFormatException(String message, Throwable cause) {
    -+            super(message, cause);
    -+        }
    -+    }
    -+
    -     public ShortcutService(Context context) {
    -         this(context, BackgroundThread.get().getLooper(), /*onyForPackgeManagerApis*/ false);
    -     }
    -@@ -533,19 +560,26 @@ public class ShortcutService extends IShortcutService.Stub {
    -     /** lifecycle event */
    -     void handleUnlockUser(int userId) {
    -         if (DEBUG) {
    --            Slog.d(TAG, "handleUnlockUser: user=" + userId);
    -+        Slog.d(TAG, "handleUnlockUser: user=" + userId);
    -         }
    -         synchronized (mLock) {
    -             mUnlockedUsers.put(userId, true);
    --
    --            // Preload the user's shortcuts.
    --            // Also see if the locale has changed.
    --            // Note as of nyc, the locale is per-user, so the locale shouldn't change
    --            // when the user is locked.  However due to b/30119489 it still happens.
    --            getUserShortcutsLocked(userId).detectLocaleChange();
    --
    --            checkPackageChanges(userId);
    -         }
    -+
    -+        // Preload the user data.
    -+        // Note, we don't use mHandler here but instead just start a new thread.
    -+        // This is because mHandler (which uses com.android.internal.os.BackgroundThread) is very
    -+        // busy at this point and this could take hundreds of milliseconds, which would be too
    -+        // late since the launcher would already have started.
    -+        // So we just create a new thread.  This code runs rarely, so we don't use a thread pool
    -+        // or anything.
    -+        final long start = injectElapsedRealtime();
    -+        injectRunOnNewThread(() -> {
    -+            synchronized (mLock) {
    -+                logDurationStat(Stats.ASYNC_PRELOAD_USER_DELAY, start);
    -+                getUserShortcutsLocked(userId);
    -+            }
    -+        });
    -     }
    - 
    -     /** lifecycle event */
    -@@ -933,7 +967,7 @@ public class ShortcutService extends IShortcutService.Stub {
    -         try {
    -             final ShortcutUser ret = loadUserInternal(userId, in, /* forBackup= */ false);
    -             return ret;
    --        } catch (IOException | XmlPullParserException e) {
    -+        } catch (IOException | XmlPullParserException | InvalidFileFormatException e) {
    -             Slog.e(TAG, "Failed to read file " + file.getBaseFile(), e);
    -             return null;
    -         } finally {
    -@@ -942,7 +976,8 @@ public class ShortcutService extends IShortcutService.Stub {
    -     }
    - 
    -     private ShortcutUser loadUserInternal(@UserIdInt int userId, InputStream is,
    --            boolean fromBackup) throws XmlPullParserException, IOException {
    -+            boolean fromBackup) throws XmlPullParserException, IOException,
    -+            InvalidFileFormatException {
    - 
    -         final BufferedInputStream bis = new BufferedInputStream(is);
    - 
    -@@ -1110,6 +1145,9 @@ public class ShortcutService extends IShortcutService.Stub {
    -                 userPackages = new ShortcutUser(this, userId);
    -             }
    -             mUsers.put(userId, userPackages);
    -+
    -+            // Also when a user's data is first accessed, scan all packages.
    -+            checkPackageChanges(userId);
    -         }
    -         return userPackages;
    -     }
    -@@ -1120,7 +1158,10 @@ public class ShortcutService extends IShortcutService.Stub {
    -         }
    -     }
    - 
    --    /** Return the per-user per-package state. */
    -+    /**
    -+     * Return the per-user per-package state.  If the caller is a publisher, use
    -+     * {@link #getPackageShortcutsForPublisherLocked} instead.
    -+     */
    -     @GuardedBy("mLock")
    -     @NonNull
    -     ShortcutPackage getPackageShortcutsLocked(
    -@@ -1128,6 +1169,16 @@ public class ShortcutService extends IShortcutService.Stub {
    -         return getUserShortcutsLocked(userId).getPackageShortcuts(packageName);
    -     }
    - 
    -+    /** Return the per-user per-package state.  Use this when the caller is a publisher. */
    -+    @GuardedBy("mLock")
    -+    @NonNull
    -+    ShortcutPackage getPackageShortcutsForPublisherLocked(
    -+            @NonNull String packageName, @UserIdInt int userId) {
    -+        final ShortcutPackage ret = getUserShortcutsLocked(userId).getPackageShortcuts(packageName);
    -+        ret.getUser().onCalledByPublisher(packageName);
    -+        return ret;
    -+    }
    -+
    -     @GuardedBy("mLock")
    -     @NonNull
    -     ShortcutLauncher getLauncherShortcutsLocked(
    -@@ -1468,6 +1519,10 @@ public class ShortcutService extends IShortcutService.Stub {
    -         mHandler.post(r);
    -     }
    - 
    -+    void injectRunOnNewThread(Runnable r) {
    -+        new Thread(r).start();
    -+    }
    -+
    -     /**
    -      * @throws IllegalArgumentException if {@code numShortcuts} is bigger than
    -      *                                  {@link #getMaxActivityShortcuts()}.
    -@@ -1592,8 +1647,7 @@ public class ShortcutService extends IShortcutService.Stub {
    -         synchronized (mLock) {
    -             throwIfUserLockedL(userId);
    - 
    --            final ShortcutPackage ps = getPackageShortcutsLocked(packageName, userId);
    --            ps.getUser().onCalledByPublisher(packageName);
    -+            final ShortcutPackage ps = getPackageShortcutsForPublisherLocked(packageName, userId);
    - 
    -             ps.ensureImmutableShortcutsNotIncluded(newShortcuts);
    - 
    -@@ -1644,8 +1698,7 @@ public class ShortcutService extends IShortcutService.Stub {
    -         synchronized (mLock) {
    -             throwIfUserLockedL(userId);
    - 
    --            final ShortcutPackage ps = getPackageShortcutsLocked(packageName, userId);
    --            ps.getUser().onCalledByPublisher(packageName);
    -+            final ShortcutPackage ps = getPackageShortcutsForPublisherLocked(packageName, userId);
    - 
    -             ps.ensureImmutableShortcutsNotIncluded(newShortcuts);
    - 
    -@@ -1725,8 +1778,7 @@ public class ShortcutService extends IShortcutService.Stub {
    -         synchronized (mLock) {
    -             throwIfUserLockedL(userId);
    - 
    --            final ShortcutPackage ps = getPackageShortcutsLocked(packageName, userId);
    --            ps.getUser().onCalledByPublisher(packageName);
    -+            final ShortcutPackage ps = getPackageShortcutsForPublisherLocked(packageName, userId);
    - 
    -             ps.ensureImmutableShortcutsNotIncluded(newShortcuts);
    - 
    -@@ -1775,8 +1827,7 @@ public class ShortcutService extends IShortcutService.Stub {
    -         synchronized (mLock) {
    -             throwIfUserLockedL(userId);
    - 
    --            final ShortcutPackage ps = getPackageShortcutsLocked(packageName, userId);
    --            ps.getUser().onCalledByPublisher(packageName);
    -+            final ShortcutPackage ps = getPackageShortcutsForPublisherLocked(packageName, userId);
    - 
    -             ps.ensureImmutableShortcutsNotIncludedWithIds((List<String>) shortcutIds);
    - 
    -@@ -1805,8 +1856,7 @@ public class ShortcutService extends IShortcutService.Stub {
    -         synchronized (mLock) {
    -             throwIfUserLockedL(userId);
    - 
    --            final ShortcutPackage ps = getPackageShortcutsLocked(packageName, userId);
    --            ps.getUser().onCalledByPublisher(packageName);
    -+            final ShortcutPackage ps = getPackageShortcutsForPublisherLocked(packageName, userId);
    - 
    -             ps.ensureImmutableShortcutsNotIncludedWithIds((List<String>) shortcutIds);
    - 
    -@@ -1828,8 +1878,7 @@ public class ShortcutService extends IShortcutService.Stub {
    -         synchronized (mLock) {
    -             throwIfUserLockedL(userId);
    - 
    --            final ShortcutPackage ps = getPackageShortcutsLocked(packageName, userId);
    --            ps.getUser().onCalledByPublisher(packageName);
    -+            final ShortcutPackage ps = getPackageShortcutsForPublisherLocked(packageName, userId);
    - 
    -             ps.ensureImmutableShortcutsNotIncludedWithIds((List<String>) shortcutIds);
    - 
    -@@ -1853,8 +1902,7 @@ public class ShortcutService extends IShortcutService.Stub {
    -         synchronized (mLock) {
    -             throwIfUserLockedL(userId);
    - 
    --            final ShortcutPackage ps = getPackageShortcutsLocked(packageName, userId);
    --            ps.getUser().onCalledByPublisher(packageName);
    -+            final ShortcutPackage ps = getPackageShortcutsForPublisherLocked(packageName, userId);
    -             ps.deleteAllDynamicShortcuts();
    -         }
    -         packageShortcutsChanged(packageName, userId);
    -@@ -1909,8 +1957,7 @@ public class ShortcutService extends IShortcutService.Stub {
    - 
    -         final ArrayList<ShortcutInfo> ret = new ArrayList<>();
    - 
    --        final ShortcutPackage ps = getPackageShortcutsLocked(packageName, userId);
    --        ps.getUser().onCalledByPublisher(packageName);
    -+        final ShortcutPackage ps = getPackageShortcutsForPublisherLocked(packageName, userId);
    -         ps.findAll(ret, query, cloneFlags);
    - 
    -         return new ParceledListSlice<>(ret);
    -@@ -1931,8 +1978,7 @@ public class ShortcutService extends IShortcutService.Stub {
    -         synchronized (mLock) {
    -             throwIfUserLockedL(userId);
    - 
    --            final ShortcutPackage ps = getPackageShortcutsLocked(packageName, userId);
    --            ps.getUser().onCalledByPublisher(packageName);
    -+            final ShortcutPackage ps = getPackageShortcutsForPublisherLocked(packageName, userId);
    -             return mMaxUpdatesPerInterval - ps.getApiCallCount();
    -         }
    -     }
    -@@ -1971,8 +2017,7 @@ public class ShortcutService extends IShortcutService.Stub {
    -         synchronized (mLock) {
    -             throwIfUserLockedL(userId);
    - 
    --            final ShortcutPackage ps = getPackageShortcutsLocked(packageName, userId);
    --            ps.getUser().onCalledByPublisher(packageName);
    -+            final ShortcutPackage ps = getPackageShortcutsForPublisherLocked(packageName, userId);
    - 
    -             if (ps.findShortcutById(shortcutId) == null) {
    -                 Log.w(TAG, String.format("reportShortcutUsed: package %s doesn't have shortcut %s",
    -@@ -2625,10 +2670,14 @@ public class ShortcutService extends IShortcutService.Stub {
    -             boolean forceRescan) {
    -         final ShortcutUser user = getUserShortcutsLocked(userId);
    - 
    -+        // Note after each OTA, we'll need to rescan all system apps, as their lastUpdateTime
    -+        // is not reliable.
    -         final long now = injectCurrentTimeMillis();
    -+        final boolean afterOta =
    -+                !injectBuildFingerprint().equals(user.getLastAppScanOsFingerprint());
    - 
    -         // Then for each installed app, publish manifest shortcuts when needed.
    --        forUpdatedPackages(userId, lastScanTime, ai -> {
    -+        forUpdatedPackages(userId, lastScanTime, afterOta, ai -> {
    -             user.attemptToRestoreIfNeededAndSave(this, ai.packageName, userId);
    -             user.rescanPackageIfNeeded(ai.packageName, forceRescan);
    -         });
    -@@ -2636,6 +2685,7 @@ public class ShortcutService extends IShortcutService.Stub {
    -         // Write the time just before the scan, because there may be apps that have just
    -         // been updated, and we want to catch them in the next time.
    -         user.setLastAppScanTime(now);
    -+        user.setLastAppScanOsFingerprint(injectBuildFingerprint());
    -         scheduleSaveUser(userId);
    -     }
    - 
    -@@ -2874,7 +2924,7 @@ public class ShortcutService extends IShortcutService.Stub {
    -         return parceledList.getList();
    -     }
    - 
    --    private void forUpdatedPackages(@UserIdInt int userId, long lastScanTime,
    -+    private void forUpdatedPackages(@UserIdInt int userId, long lastScanTime, boolean afterOta,
    -             Consumer<ApplicationInfo> callback) {
    -         if (DEBUG) {
    -             Slog.d(TAG, "forUpdatedPackages for user " + userId + ", lastScanTime=" + lastScanTime);
    -@@ -2886,7 +2936,8 @@ public class ShortcutService extends IShortcutService.Stub {
    -             // If the package has been updated since the last scan time, then scan it.
    -             // Also if it's a system app with no update, lastUpdateTime is not reliable, so
    -             // just scan it.
    --            if (pi.lastUpdateTime >= lastScanTime || isPureSystemApp(pi.applicationInfo)) {
    -+            if (pi.lastUpdateTime >= lastScanTime
    -+                    || (afterOta && isPureSystemApp(pi.applicationInfo))) {
    -                 if (DEBUG) {
    -                     Slog.d(TAG, "Found updated package " + pi.packageName);
    -                 }
    -@@ -3103,9 +3154,19 @@ public class ShortcutService extends IShortcutService.Stub {
    -                 return null;
    -             }
    - 
    --            user.forAllPackageItems(spi -> spi.refreshPackageInfoAndSave());
    -+            // Update the signatures for all packages.
    -+            user.forAllPackageItems(spi -> spi.refreshPackageSignatureAndSave());
    - 
    --            // Then save.
    -+            // Set the version code for the launchers.
    -+            // We shouldn't do this for publisher packages, because we don't want to update the
    -+            // version code without rescanning the manifest.
    -+            user.forAllLaunchers(launcher -> launcher.ensureVersionInfo());
    -+
    -+            // Save to the filesystem.
    -+            scheduleSaveUser(userId);
    -+            saveDirtyInfo();
    -+
    -+            // Then create the backup payload.
    -             final ByteArrayOutputStream os = new ByteArrayOutputStream(32 * 1024);
    -             try {
    -                 saveUserInternalLocked(userId, os, /* forBackup */ true);
    -@@ -3129,15 +3190,16 @@ public class ShortcutService extends IShortcutService.Stub {
    -                 wtf("Can't restore: user " + userId + " is locked or not running");
    -                 return;
    -             }
    --            final ShortcutUser user;
    -+            // Actually do restore.
    -+            final ShortcutUser restored;
    -             final ByteArrayInputStream is = new ByteArrayInputStream(payload);
    -             try {
    --                user = loadUserInternal(userId, is, /* fromBackup */ true);
    --            } catch (XmlPullParserException | IOException e) {
    -+                restored = loadUserInternal(userId, is, /* fromBackup */ true);
    -+            } catch (XmlPullParserException | IOException | InvalidFileFormatException e) {
    -                 Slog.w(TAG, "Restoration failed.", e);
    -                 return;
    -             }
    --            mUsers.put(userId, user);
    -+            getUserShortcutsLocked(userId).mergeRestoredFile(restored);
    - 
    -             // Rescan all packages to re-publish manifest shortcuts and do other checks.
    -             rescanUpdatedPackagesLocked(userId,
    -@@ -3218,23 +3280,9 @@ public class ShortcutService extends IShortcutService.Stub {
    - 
    -             pw.println("  Stats:");
    -             synchronized (mStatLock) {
    --                final String p = "    ";
    --                dumpStatLS(pw, p, Stats.GET_DEFAULT_HOME, "getHomeActivities()");
    --                dumpStatLS(pw, p, Stats.LAUNCHER_PERMISSION_CHECK, "Launcher permission check");
    --
    --                dumpStatLS(pw, p, Stats.GET_PACKAGE_INFO, "getPackageInfo()");
    --                dumpStatLS(pw, p, Stats.GET_PACKAGE_INFO_WITH_SIG, "getPackageInfo(SIG)");
    --                dumpStatLS(pw, p, Stats.GET_APPLICATION_INFO, "getApplicationInfo");
    --                dumpStatLS(pw, p, Stats.CLEANUP_DANGLING_BITMAPS, "cleanupDanglingBitmaps");
    --                dumpStatLS(pw, p, Stats.GET_ACTIVITY_WITH_METADATA, "getActivity+metadata");
    --                dumpStatLS(pw, p, Stats.GET_INSTALLED_PACKAGES, "getInstalledPackages");
    --                dumpStatLS(pw, p, Stats.CHECK_PACKAGE_CHANGES, "checkPackageChanges");
    --                dumpStatLS(pw, p, Stats.GET_APPLICATION_RESOURCES, "getApplicationResources");
    --                dumpStatLS(pw, p, Stats.RESOURCE_NAME_LOOKUP, "resourceNameLookup");
    --                dumpStatLS(pw, p, Stats.GET_LAUNCHER_ACTIVITY, "getLauncherActivity");
    --                dumpStatLS(pw, p, Stats.CHECK_LAUNCHER_ACTIVITY, "checkLauncherActivity");
    --                dumpStatLS(pw, p, Stats.IS_ACTIVITY_ENABLED, "isActivityEnabled");
    --                dumpStatLS(pw, p, Stats.PACKAGE_UPDATE_CHECK, "packageUpdateCheck");
    -+                for (int i = 0; i < Stats.COUNT; i++) {
    -+                    dumpStatLS(pw, "    ", i);
    -+                }
    -             }
    - 
    -             pw.println();
    -@@ -3277,12 +3325,12 @@ public class ShortcutService extends IShortcutService.Stub {
    -         return tobj.format("%Y-%m-%d %H:%M:%S");
    -     }
    - 
    --    private void dumpStatLS(PrintWriter pw, String prefix, int statId, String label) {
    -+    private void dumpStatLS(PrintWriter pw, String prefix, int statId) {
    -         pw.print(prefix);
    -         final int count = mCountStats[statId];
    -         final long dur = mDurationStats[statId];
    -         pw.println(String.format("%s: count=%d, total=%dms, avg=%.1fms",
    --                label, count, dur,
    -+                STAT_LABELS[statId], count, dur,
    -                 (count == 0 ? 0 : ((double) dur) / count)));
    -     }
    - 
    -@@ -3578,6 +3626,12 @@ public class ShortcutService extends IShortcutService.Stub {
    -         Binder.restoreCallingIdentity(token);
    -     }
    - 
    -+    // Injection point.
    -+    @VisibleForTesting
    -+    String injectBuildFingerprint() {
    -+        return Build.FINGERPRINT;
    -+    }
    -+
    -     final void wtf(String message) {
    -         wtf(message, /* exception= */ null);
    -     }
    -diff --git a/services/core/java/com/android/server/pm/ShortcutUser.java b/services/core/java/com/android/server/pm/ShortcutUser.java
    -index ce3ed9c..5d4bfa4 100644
    ---- a/services/core/java/com/android/server/pm/ShortcutUser.java
    -+++ b/services/core/java/com/android/server/pm/ShortcutUser.java
    -@@ -23,12 +23,14 @@ import android.content.pm.ShortcutManager;
    - import android.text.TextUtils;
    - import android.text.format.Formatter;
    - import android.util.ArrayMap;
    -+import android.util.Log;
    - import android.util.Slog;
    - import android.util.SparseArray;
    - 
    - import com.android.internal.annotations.GuardedBy;
    - import com.android.internal.annotations.VisibleForTesting;
    - import com.android.internal.util.Preconditions;
    -+import com.android.server.pm.ShortcutService.InvalidFileFormatException;
    - 
    - import libcore.util.Objects;
    - 
    -@@ -60,6 +62,7 @@ class ShortcutUser {
    - 
    -     // Suffix "2" was added to force rescan all packages after the next OTA.
    -     private static final String ATTR_LAST_APP_SCAN_TIME = "last-app-scan-time2";
    -+    private static final String ATTR_LAST_APP_SCAN_OS_FINGERPRINT = "last-app-scan-fp";
    -     private static final String KEY_USER_ID = "userId";
    -     private static final String KEY_LAUNCHERS = "launchers";
    -     private static final String KEY_PACKAGES = "packages";
    -@@ -125,6 +128,8 @@ class ShortcutUser {
    - 
    -     private long mLastAppScanTime;
    - 
    -+    private String mLastAppScanOsFingerprint;
    -+
    -     public ShortcutUser(ShortcutService service, int userId) {
    -         mService = service;
    -         mUserId = userId;
    -@@ -142,6 +147,14 @@ class ShortcutUser {
    -         mLastAppScanTime = lastAppScanTime;
    -     }
    - 
    -+    public String getLastAppScanOsFingerprint() {
    -+        return mLastAppScanOsFingerprint;
    -+    }
    -+
    -+    public void setLastAppScanOsFingerprint(String lastAppScanOsFingerprint) {
    -+        mLastAppScanOsFingerprint = lastAppScanOsFingerprint;
    -+    }
    -+
    -     // We don't expose this directly to non-test code because only ShortcutUser should add to/
    -     // remove from it.
    -     @VisibleForTesting
    -@@ -153,6 +166,11 @@ class ShortcutUser {
    -         return mPackages.containsKey(packageName);
    -     }
    - 
    -+    private void addPackage(@NonNull ShortcutPackage p) {
    -+        p.replaceUser(this);
    -+        mPackages.put(p.getPackageName(), p);
    -+    }
    -+
    -     public ShortcutPackage removePackage(@NonNull String packageName) {
    -         final ShortcutPackage removed = mPackages.remove(packageName);
    - 
    -@@ -168,7 +186,8 @@ class ShortcutUser {
    -         return mLaunchers;
    -     }
    - 
    --    public void addLauncher(ShortcutLauncher launcher) {
    -+    private void addLauncher(ShortcutLauncher launcher) {
    -+        launcher.replaceUser(this);
    -         mLaunchers.put(PackageWithUser.of(launcher.getPackageUserId(),
    -                 launcher.getPackageName()), launcher);
    -     }
    -@@ -315,11 +334,16 @@ class ShortcutUser {
    -             throws IOException, XmlPullParserException {
    -         out.startTag(null, TAG_ROOT);
    - 
    --        ShortcutService.writeAttr(out, ATTR_KNOWN_LOCALES, mKnownLocales);
    --        ShortcutService.writeAttr(out, ATTR_LAST_APP_SCAN_TIME,
    --                mLastAppScanTime);
    -+        if (!forBackup) {
    -+            // Don't have to back them up.
    -+            ShortcutService.writeAttr(out, ATTR_KNOWN_LOCALES, mKnownLocales);
    -+            ShortcutService.writeAttr(out, ATTR_LAST_APP_SCAN_TIME,
    -+                    mLastAppScanTime);
    -+            ShortcutService.writeAttr(out, ATTR_LAST_APP_SCAN_OS_FINGERPRINT,
    -+                    mLastAppScanOsFingerprint);
    - 
    --        ShortcutService.writeTagValue(out, TAG_LAUNCHER, mLastKnownLauncher);
    -+            ShortcutService.writeTagValue(out, TAG_LAUNCHER, mLastKnownLauncher);
    -+        }
    - 
    -         // Can't use forEachPackageItem due to the checked exceptions.
    -         {
    -@@ -352,53 +376,59 @@ class ShortcutUser {
    -     }
    - 
    -     public static ShortcutUser loadFromXml(ShortcutService s, XmlPullParser parser, int userId,
    --            boolean fromBackup) throws IOException, XmlPullParserException {
    -+            boolean fromBackup) throws IOException, XmlPullParserException, InvalidFileFormatException {
    -         final ShortcutUser ret = new ShortcutUser(s, userId);
    - 
    --        ret.mKnownLocales = ShortcutService.parseStringAttribute(parser,
    --                ATTR_KNOWN_LOCALES);
    --
    --        // If lastAppScanTime is in the future, that means the clock went backwards.
    --        // Just scan all apps again.
    --        final long lastAppScanTime = ShortcutService.parseLongAttribute(parser,
    --                ATTR_LAST_APP_SCAN_TIME);
    --        final long currentTime = s.injectCurrentTimeMillis();
    --        ret.mLastAppScanTime = lastAppScanTime < currentTime ? lastAppScanTime : 0;
    --
    --        final int outerDepth = parser.getDepth();
    --        int type;
    --        while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
    --                && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
    --            if (type != XmlPullParser.START_TAG) {
    --                continue;
    --            }
    --            final int depth = parser.getDepth();
    --            final String tag = parser.getName();
    --
    --            if (depth == outerDepth + 1) {
    --                switch (tag) {
    --                    case TAG_LAUNCHER: {
    --                        ret.mLastKnownLauncher = ShortcutService.parseComponentNameAttribute(
    --                                parser, ATTR_VALUE);
    --                        continue;
    --                    }
    --                    case ShortcutPackage.TAG_ROOT: {
    --                        final ShortcutPackage shortcuts = ShortcutPackage.loadFromXml(
    --                                s, ret, parser, fromBackup);
    --
    --                        // Don't use addShortcut(), we don't need to save the icon.
    --                        ret.mPackages.put(shortcuts.getPackageName(), shortcuts);
    --                        continue;
    --                    }
    --
    --                    case ShortcutLauncher.TAG_ROOT: {
    --                        ret.addLauncher(
    --                                ShortcutLauncher.loadFromXml(parser, ret, userId, fromBackup));
    --                        continue;
    -+        try {
    -+            ret.mKnownLocales = ShortcutService.parseStringAttribute(parser,
    -+                    ATTR_KNOWN_LOCALES);
    -+
    -+            // If lastAppScanTime is in the future, that means the clock went backwards.
    -+            // Just scan all apps again.
    -+            final long lastAppScanTime = ShortcutService.parseLongAttribute(parser,
    -+                    ATTR_LAST_APP_SCAN_TIME);
    -+            final long currentTime = s.injectCurrentTimeMillis();
    -+            ret.mLastAppScanTime = lastAppScanTime < currentTime ? lastAppScanTime : 0;
    -+            ret.mLastAppScanOsFingerprint = ShortcutService.parseStringAttribute(parser,
    -+                    ATTR_LAST_APP_SCAN_OS_FINGERPRINT);
    -+            final int outerDepth = parser.getDepth();
    -+            int type;
    -+            while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
    -+                    && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
    -+                if (type != XmlPullParser.START_TAG) {
    -+                    continue;
    -+                }
    -+                final int depth = parser.getDepth();
    -+                final String tag = parser.getName();
    -+
    -+                if (depth == outerDepth + 1) {
    -+                    switch (tag) {
    -+                        case TAG_LAUNCHER: {
    -+                            ret.mLastKnownLauncher = ShortcutService.parseComponentNameAttribute(
    -+                                    parser, ATTR_VALUE);
    -+                            continue;
    -+                        }
    -+                        case ShortcutPackage.TAG_ROOT: {
    -+                            final ShortcutPackage shortcuts = ShortcutPackage.loadFromXml(
    -+                                    s, ret, parser, fromBackup);
    -+
    -+                            // Don't use addShortcut(), we don't need to save the icon.
    -+                            ret.mPackages.put(shortcuts.getPackageName(), shortcuts);
    -+                            continue;
    -+                        }
    -+
    -+                        case ShortcutLauncher.TAG_ROOT: {
    -+                            ret.addLauncher(
    -+                                    ShortcutLauncher.loadFromXml(parser, ret, userId, fromBackup));
    -+                            continue;
    -+                        }
    -                     }
    -                 }
    -+                ShortcutService.warnForInvalidTag(depth, tag);
    -             }
    --            ShortcutService.warnForInvalidTag(depth, tag);
    -+        } catch (RuntimeException e) {
    -+            throw new ShortcutService.InvalidFileFormatException(
    -+                    "Unable to parse file", e);
    -         }
    -         return ret;
    -     }
    -@@ -447,6 +477,51 @@ class ShortcutUser {
    -         }
    -     }
    - 
    -+    public void mergeRestoredFile(ShortcutUser restored) {
    -+        final ShortcutService s = mService;
    -+        // Note, a restore happens only at the end of setup wizard.  At this point, no apps are
    -+        // installed from Play Store yet, but it's still possible that system apps have already
    -+        // published dynamic shortcuts, since some apps do so on BOOT_COMPLETED.
    -+        // When such a system app has allowbackup=true, then we go ahead and replace all existing
    -+        // shortcuts with the restored shortcuts.  (Then we'll re-publish manifest shortcuts later
    -+        // in the call site.)
    -+        // When such a system app has allowbackup=false, then we'll keep the shortcuts that have
    -+        // already been published.  So we selectively add restored ShortcutPackages here.
    -+        //
    -+        // The same logic applies to launchers, but since launchers shouldn't pin shortcuts
    -+        // without users interaction it's really not a big deal, so we just clear existing
    -+        // ShortcutLauncher instances in mLaunchers and add all the restored ones here.
    -+
    -+        mLaunchers.clear();
    -+        restored.forAllLaunchers(sl -> {
    -+            // If the app is already installed and allowbackup = false, then ignore the restored
    -+            // data.
    -+            if (s.isPackageInstalled(sl.getPackageName(), getUserId())
    -+                    && !s.shouldBackupApp(sl.getPackageName(), getUserId())) {
    -+                return;
    -+            }
    -+            addLauncher(sl);
    -+        });
    -+        restored.forAllPackages(sp -> {
    -+            // If the app is already installed and allowbackup = false, then ignore the restored
    -+            // data.
    -+            if (s.isPackageInstalled(sp.getPackageName(), getUserId())
    -+                    && !s.shouldBackupApp(sp.getPackageName(), getUserId())) {
    -+                return;
    -+            }
    -+
    -+            final ShortcutPackage previous = getPackageShortcutsIfExists(sp.getPackageName());
    -+            if (previous != null && previous.hasNonManifestShortcuts()) {
    -+                Log.w(TAG, "Shortcuts for package " + sp.getPackageName() + " are being restored."
    -+                        + " Existing non-manifeset shortcuts will be overwritten.");
    -+            }
    -+            addPackage(sp);
    -+        });
    -+        // Empty the launchers and packages in restored to avoid accidentally using them.
    -+        restored.mLaunchers.clear();
    -+        restored.mPackages.clear();
    -+    }
    -+
    -     public void dump(@NonNull PrintWriter pw, @NonNull String prefix) {
    -         pw.print(prefix);
    -         pw.print("User: ");
    -@@ -457,6 +532,8 @@ class ShortcutUser {
    -         pw.print(mLastAppScanTime);
    -         pw.print("] ");
    -         pw.print(ShortcutService.formatTime(mLastAppScanTime));
    -+        pw.print("  Last app scan FP: ");
    -+        pw.print(mLastAppScanOsFingerprint);
    -         pw.println();
    - 
    -         prefix += prefix + "  ";
    -diff --git a/services/core/java/com/android/server/pm/UserManagerService.java b/services/core/java/com/android/server/pm/UserManagerService.java
    -index c9ad49a..af055da 100644
    ---- a/services/core/java/com/android/server/pm/UserManagerService.java
    -+++ b/services/core/java/com/android/server/pm/UserManagerService.java
    -@@ -180,7 +180,8 @@ public class UserManagerService extends IUserManager.Stub {
    -             UserInfo.FLAG_MANAGED_PROFILE
    -             | UserInfo.FLAG_EPHEMERAL
    -             | UserInfo.FLAG_RESTRICTED
    --            | UserInfo.FLAG_GUEST;
    -+            | UserInfo.FLAG_GUEST
    -+            | UserInfo.FLAG_DEMO;
    - 
    -     private static final int MIN_USER_ID = 10;
    -     // We need to keep process uid within Integer.MAX_VALUE.
    -diff --git a/services/core/java/com/android/server/policy/GlobalActions.java b/services/core/java/com/android/server/policy/GlobalActions.java
    -index bb91f76..a8bd4d2 100644
    ---- a/services/core/java/com/android/server/policy/GlobalActions.java
    -+++ b/services/core/java/com/android/server/policy/GlobalActions.java
    -@@ -20,6 +20,7 @@ import com.android.internal.app.AlertController;
    - import com.android.internal.app.AlertController.AlertParams;
    - import com.android.internal.logging.MetricsLogger;
    - import com.android.internal.logging.MetricsProto.MetricsEvent;
    -+import com.android.internal.policy.EmergencyAffordanceManager;
    - import com.android.internal.telephony.TelephonyIntents;
    - import com.android.internal.telephony.TelephonyProperties;
    - import com.android.internal.R;
    -@@ -27,7 +28,6 @@ import com.android.internal.widget.LockPatternUtils;
    - 
    - import android.app.ActivityManager;
    - import android.app.ActivityManagerNative;
    --import android.app.AlertDialog;
    - import android.app.Dialog;
    - import android.content.BroadcastReceiver;
    - import android.content.Context;
    -@@ -125,6 +125,7 @@ class GlobalActions implements DialogInterface.OnDismissListener, DialogInterfac
    -     private boolean mHasTelephony;
    -     private boolean mHasVibrator;
    -     private final boolean mShowSilentToggle;
    -+    private final EmergencyAffordanceManager mEmergencyAffordanceManager;
    - 
    -     /**
    -      * @param context everything needs a context :(
    -@@ -159,6 +160,8 @@ class GlobalActions implements DialogInterface.OnDismissListener, DialogInterfac
    - 
    -         mShowSilentToggle = SHOW_SILENT_TOGGLE && !mContext.getResources().getBoolean(
    -                 com.android.internal.R.bool.config_useFixedVolume);
    -+
    -+        mEmergencyAffordanceManager = new EmergencyAffordanceManager(context);
    -     }
    - 
    -     /**
    -@@ -308,6 +311,10 @@ class GlobalActions implements DialogInterface.OnDismissListener, DialogInterfac
    -             addedKeys.add(actionKey);
    -         }
    - 
    -+        if (mEmergencyAffordanceManager.needsEmergencyAffordance()) {
    -+            mItems.add(getEmergencyAction());
    -+        }
    -+
    -         mAdapter = new MyAdapter();
    - 
    -         AlertParams params = new AlertParams(mContext);
    -@@ -493,6 +500,26 @@ class GlobalActions implements DialogInterface.OnDismissListener, DialogInterfac
    -         };
    -     }
    - 
    -+    private Action getEmergencyAction() {
    -+        return new SinglePressAction(com.android.internal.R.drawable.emergency_icon,
    -+                R.string.global_action_emergency) {
    -+            @Override
    -+            public void onPress() {
    -+                mEmergencyAffordanceManager.performEmergencyCall();
    -+            }
    -+
    -+            @Override
    -+            public boolean showDuringKeyguard() {
    -+                return true;
    -+            }
    -+
    -+            @Override
    -+            public boolean showBeforeProvisioning() {
    -+                return true;
    -+            }
    -+        };
    -+    }
    -+
    -     private Action getAssistAction() {
    -         return new SinglePressAction(com.android.internal.R.drawable.ic_action_assist_focused,
    -                 R.string.global_action_assist) {
    -diff --git a/services/core/java/com/android/server/policy/ImmersiveModeConfirmation.java b/services/core/java/com/android/server/policy/ImmersiveModeConfirmation.java
    -index c764833..9bf0476 100644
    ---- a/services/core/java/com/android/server/policy/ImmersiveModeConfirmation.java
    -+++ b/services/core/java/com/android/server/policy/ImmersiveModeConfirmation.java
    -@@ -25,7 +25,9 @@ import android.content.Intent;
    - import android.content.IntentFilter;
    - import android.graphics.PixelFormat;
    - import android.graphics.drawable.ColorDrawable;
    -+import android.os.Binder;
    - import android.os.Handler;
    -+import android.os.IBinder;
    - import android.os.Message;
    - import android.os.RemoteException;
    - import android.os.ServiceManager;
    -@@ -36,7 +38,6 @@ import android.service.vr.IVrManager;
    - import android.service.vr.IVrStateCallbacks;
    - import android.util.DisplayMetrics;
    - import android.util.Slog;
    --import android.util.SparseBooleanArray;
    - import android.view.Gravity;
    - import android.view.MotionEvent;
    - import android.view.View;
    -@@ -66,6 +67,7 @@ public class ImmersiveModeConfirmation {
    -     private final H mHandler;
    -     private final long mShowDelayMs;
    -     private final long mPanicThresholdMs;
    -+    private final IBinder mWindowToken = new Binder();
    - 
    -     private boolean mConfirmed;
    -     private ClingWindowView mClingWindow;
    -@@ -190,13 +192,13 @@ public class ImmersiveModeConfirmation {
    -                 WindowManager.LayoutParams.TYPE_STATUS_BAR_PANEL,
    -                 0
    -                         | WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN
    --                        | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
    -                         | WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED
    -                 ,
    -                 PixelFormat.TRANSLUCENT);
    -         lp.privateFlags |= WindowManager.LayoutParams.PRIVATE_FLAG_SHOW_FOR_ALL_USERS;
    -         lp.setTitle("ImmersiveModeConfirmation");
    -         lp.windowAnimations = com.android.internal.R.style.Animation_ImmersiveModeConfirmation;
    -+        lp.token = getWindowToken();
    -         return lp;
    -     }
    - 
    -@@ -208,6 +210,13 @@ public class ImmersiveModeConfirmation {
    -                 Gravity.CENTER_HORIZONTAL | Gravity.TOP);
    -     }
    - 
    -+    /**
    -+     * @return the window token that's used by all ImmersiveModeConfirmation windows.
    -+     */
    -+    public IBinder getWindowToken() {
    -+        return mWindowToken;
    -+    }
    -+
    -     private class ClingWindowView extends FrameLayout {
    -         private static final int BGCOLOR = 0x80000000;
    -         private static final int OFFSET_DP = 96;
    -diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java
    -index a39add8..74e720f 100644
    ---- a/services/core/java/com/android/server/policy/PhoneWindowManager.java
    -+++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java
    -@@ -140,6 +140,7 @@ import android.view.animation.Animation;
    - import android.view.animation.AnimationSet;
    - import android.view.animation.AnimationUtils;
    - import com.android.internal.R;
    -+import com.android.internal.annotations.GuardedBy;
    - import com.android.internal.logging.MetricsLogger;
    - import com.android.internal.policy.PhoneWindow;
    - import com.android.internal.policy.IShortcutService;
    -@@ -176,12 +177,13 @@ public class PhoneWindowManager implements WindowManagerPolicy {
    -     static final boolean DEBUG_STARTING_WINDOW = false;
    -     static final boolean DEBUG_WAKEUP = false;
    -     static final boolean SHOW_STARTING_ANIMATIONS = true;
    --    static final boolean SHOW_PROCESSES_ON_ALT_MENU = false;
    - 
    -     // Whether to allow dock apps with METADATA_DOCK_HOME to temporarily take over the Home key.
    -     // No longer recommended for desk docks;
    -     static final boolean ENABLE_DESK_DOCK_HOME_CAPTURE = false;
    - 
    -+    static final boolean ALTERNATE_CAR_MODE_NAV_SIZE = false;
    -+
    -     static final int SHORT_PRESS_POWER_NOTHING = 0;
    -     static final int SHORT_PRESS_POWER_GO_TO_SLEEP = 1;
    -     static final int SHORT_PRESS_POWER_REALLY_GO_TO_SLEEP = 2;
    -@@ -301,6 +303,9 @@ public class PhoneWindowManager implements WindowManagerPolicy {
    -     /** Amount of time (in milliseconds) to wait for windows drawn before powering on. */
    -     static final int WAITING_FOR_DRAWN_TIMEOUT = 1000;
    - 
    -+    /** Amount of time (in milliseconds) a toast window can be shown. */
    -+    public static final int TOAST_WINDOW_TIMEOUT = 3500; // 3.5 seconds
    -+
    -     /**
    -      * Lock protecting internal state.  Must not call out into window
    -      * manager with lock held.  (This lock will be acquired in places
    -@@ -585,6 +590,13 @@ public class PhoneWindowManager implements WindowManagerPolicy {
    -     private static final int DISMISS_KEYGUARD_CONTINUE = 2; // Keyguard has been dismissed.
    -     int mDismissKeyguard = DISMISS_KEYGUARD_NONE;
    - 
    -+    /**
    -+     * Indicates that we asked the Keyguard to be dismissed and we just wait for the Keyguard to
    -+     * dismiss itself.
    -+     */
    -+    @GuardedBy("Lw")
    -+    private boolean mCurrentlyDismissingKeyguard;
    -+
    -     /** The window that is currently dismissing the keyguard. Dismissing the keyguard must only
    -      * be done once per window. */
    -     private WindowState mWinDismissingKeyguard;
    -@@ -2229,9 +2241,22 @@ public class PhoneWindowManager implements WindowManagerPolicy {
    -                     attrs.privateFlags &= ~WindowManager.LayoutParams.PRIVATE_FLAG_KEYGUARD;
    -                 }
    -                 break;
    -+
    -             case TYPE_SCREENSHOT:
    -                 attrs.flags |= WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
    -                 break;
    -+
    -+            case TYPE_TOAST:
    -+                // While apps should use the dedicated toast APIs to add such windows
    -+                // it possible legacy apps to add the window directly. Therefore, we
    -+                // make windows added directly by the app behave as a toast as much
    -+                // as possible in terms of timeout and animation.
    -+                if (attrs.hideTimeoutMilliseconds < 0
    -+                        || attrs.hideTimeoutMilliseconds > TOAST_WINDOW_TIMEOUT) {
    -+                    attrs.hideTimeoutMilliseconds = TOAST_WINDOW_TIMEOUT;
    -+                }
    -+                attrs.windowAnimations = com.android.internal.R.style.Animation_Toast;
    -+                break;
    -         }
    - 
    -         if (attrs.type != TYPE_STATUS_BAR) {
    -@@ -2320,22 +2345,24 @@ public class PhoneWindowManager implements WindowManagerPolicy {
    -         mNavigationBarWidthForRotationDefault[mSeascapeRotation] =
    -                 res.getDimensionPixelSize(com.android.internal.R.dimen.navigation_bar_width);
    - 
    --        // Height of the navigation bar when presented horizontally at bottom
    --        mNavigationBarHeightForRotationInCarMode[mPortraitRotation] =
    --        mNavigationBarHeightForRotationInCarMode[mUpsideDownRotation] =
    --                res.getDimensionPixelSize(
    --                        com.android.internal.R.dimen.navigation_bar_height_car_mode);
    --        mNavigationBarHeightForRotationInCarMode[mLandscapeRotation] =
    --        mNavigationBarHeightForRotationInCarMode[mSeascapeRotation] = res.getDimensionPixelSize(
    --                com.android.internal.R.dimen.navigation_bar_height_landscape_car_mode);
    -+        if (ALTERNATE_CAR_MODE_NAV_SIZE) {
    -+            // Height of the navigation bar when presented horizontally at bottom
    -+            mNavigationBarHeightForRotationInCarMode[mPortraitRotation] =
    -+            mNavigationBarHeightForRotationInCarMode[mUpsideDownRotation] =
    -+                    res.getDimensionPixelSize(
    -+                            com.android.internal.R.dimen.navigation_bar_height_car_mode);
    -+            mNavigationBarHeightForRotationInCarMode[mLandscapeRotation] =
    -+            mNavigationBarHeightForRotationInCarMode[mSeascapeRotation] = res.getDimensionPixelSize(
    -+                    com.android.internal.R.dimen.navigation_bar_height_landscape_car_mode);
    - 
    --        // Width of the navigation bar when presented vertically along one side
    --        mNavigationBarWidthForRotationInCarMode[mPortraitRotation] =
    --        mNavigationBarWidthForRotationInCarMode[mUpsideDownRotation] =
    --        mNavigationBarWidthForRotationInCarMode[mLandscapeRotation] =
    --        mNavigationBarWidthForRotationInCarMode[mSeascapeRotation] =
    --                res.getDimensionPixelSize(
    --                        com.android.internal.R.dimen.navigation_bar_width_car_mode);
    -+            // Width of the navigation bar when presented vertically along one side
    -+            mNavigationBarWidthForRotationInCarMode[mPortraitRotation] =
    -+            mNavigationBarWidthForRotationInCarMode[mUpsideDownRotation] =
    -+            mNavigationBarWidthForRotationInCarMode[mLandscapeRotation] =
    -+            mNavigationBarWidthForRotationInCarMode[mSeascapeRotation] =
    -+                    res.getDimensionPixelSize(
    -+                            com.android.internal.R.dimen.navigation_bar_width_car_mode);
    -+        }
    -     }
    - 
    -     /** {@inheritDoc} */
    -@@ -2467,7 +2494,7 @@ public class PhoneWindowManager implements WindowManagerPolicy {
    -     }
    - 
    -     private int getNavigationBarWidth(int rotation, int uiMode) {
    --        if ((uiMode & UI_MODE_TYPE_MASK) == UI_MODE_TYPE_CAR) {
    -+        if (ALTERNATE_CAR_MODE_NAV_SIZE && (uiMode & UI_MODE_TYPE_MASK) == UI_MODE_TYPE_CAR) {
    -             return mNavigationBarWidthForRotationInCarMode[rotation];
    -         } else {
    -             return mNavigationBarWidthForRotationDefault[rotation];
    -@@ -2488,7 +2515,7 @@ public class PhoneWindowManager implements WindowManagerPolicy {
    -     }
    - 
    -     private int getNavigationBarHeight(int rotation, int uiMode) {
    --        if ((uiMode & UI_MODE_TYPE_MASK) == UI_MODE_TYPE_CAR) {
    -+        if (ALTERNATE_CAR_MODE_NAV_SIZE && (uiMode & UI_MODE_TYPE_MASK) == UI_MODE_TYPE_CAR) {
    -             return mNavigationBarHeightForRotationInCarMode[rotation];
    -         } else {
    -             return mNavigationBarHeightForRotationDefault[rotation];
    -@@ -2805,7 +2832,11 @@ public class PhoneWindowManager implements WindowManagerPolicy {
    -             if (mNavigationBarPosition == NAV_BAR_BOTTOM) {
    -                 if (transit == TRANSIT_EXIT
    -                         || transit == TRANSIT_HIDE) {
    --                    return R.anim.dock_bottom_exit;
    -+                    if (isKeyguardShowingAndNotOccluded()) {
    -+                        return R.anim.dock_bottom_exit_keyguard;
    -+                    } else {
    -+                        return R.anim.dock_bottom_exit;
    -+                    }
    -                 } else if (transit == TRANSIT_ENTER
    -                         || transit == TRANSIT_SHOW) {
    -                     return R.anim.dock_bottom_enter;
    -@@ -3125,21 +3156,6 @@ public class PhoneWindowManager implements WindowManagerPolicy {
    -                     mContext.sendOrderedBroadcastAsUser(intent, UserHandle.CURRENT,
    -                             null, null, null, 0, null, null);
    -                     return -1;
    --                } else if (SHOW_PROCESSES_ON_ALT_MENU &&
    --                        (metaState & KeyEvent.META_ALT_ON) == KeyEvent.META_ALT_ON) {
    --                    Intent service = new Intent();
    --                    service.setClassName(mContext, "com.android.server.LoadAverageService");
    --                    ContentResolver res = mContext.getContentResolver();
    --                    boolean shown = Settings.Global.getInt(
    --                            res, Settings.Global.SHOW_PROCESSES, 0) != 0;
    --                    if (!shown) {
    --                        mContext.startService(service);
    --                    } else {
    --                        mContext.stopService(service);
    --                    }
    --                    Settings.Global.putInt(
    --                            res, Settings.Global.SHOW_PROCESSES, shown ? 0 : 1);
    --                    return -1;
    -                 }
    -             }
    -         } else if (keyCode == KeyEvent.KEYCODE_SEARCH) {
    -@@ -3566,10 +3582,11 @@ public class PhoneWindowManager implements WindowManagerPolicy {
    - 
    -     @Override
    -     public boolean canShowDismissingWindowWhileLockedLw() {
    --        // If the keyguard is trusted, it will unlock without a challange. Therefore, windows with
    --        // FLAG_DISMISS_KEYGUARD don't need to be force hidden, as they will unlock the phone right
    --        // away anyways.
    --        return mKeyguardDelegate != null && mKeyguardDelegate.isTrusted();
    -+        // If the keyguard is trusted, it will unlock without a challenge. Therefore, if we are in
    -+        // the process of dismissing Keyguard, we don't need to hide them as the phone will be
    -+        // unlocked right away in any case.
    -+        return mKeyguardDelegate != null && mKeyguardDelegate.isTrusted()
    -+                && mCurrentlyDismissingKeyguard;
    -     }
    - 
    -     private void launchAssistLongPressAction() {
    -@@ -3832,11 +3849,19 @@ public class PhoneWindowManager implements WindowManagerPolicy {
    -     };
    - 
    -     @Override
    -+    public void setRecentsVisibilityLw(boolean visible) {
    -+        mRecentsVisible = visible;
    -+    }
    -+
    -+    @Override
    -+    public void setTvPipVisibilityLw(boolean visible) {
    -+        mTvPictureInPictureVisible = visible;
    -+    }
    -+
    -+    @Override
    -     public int adjustSystemUiVisibilityLw(int visibility) {
    -         mStatusBarController.adjustSystemUiVisibilityLw(mLastSystemUiFlags, visibility);
    -         mNavigationBarController.adjustSystemUiVisibilityLw(mLastSystemUiFlags, visibility);
    --        mRecentsVisible = (visibility & View.RECENT_APPS_VISIBLE) > 0;
    --        mTvPictureInPictureVisible = (visibility & View.TV_PICTURE_IN_PICTURE_VISIBLE) > 0;
    - 
    -         // Reset any bits in mForceClearingStatusBarVisibility that
    -         // are now clear.
    -@@ -5268,22 +5293,30 @@ public class PhoneWindowManager implements WindowManagerPolicy {
    -                 }
    -             } else if (mDismissKeyguard != DISMISS_KEYGUARD_NONE) {
    -                 mKeyguardHidden = false;
    -+                boolean dismissKeyguard = false;
    -                 final boolean trusted = mKeyguardDelegate.isTrusted();
    --                if (trusted) {
    --                    // No need to un-occlude keyguard - we'll dimiss it right away anyways.
    --                } else if (setKeyguardOccludedLw(false)) {
    --                    changes |= FINISH_LAYOUT_REDO_LAYOUT
    --                            | FINISH_LAYOUT_REDO_CONFIG
    --                            | FINISH_LAYOUT_REDO_WALLPAPER;
    --                }
    -                 if (mDismissKeyguard == DISMISS_KEYGUARD_START) {
    -+                    final boolean willDismiss = trusted && mKeyguardOccluded
    -+                            && mKeyguardDelegate != null && mKeyguardDelegate.isShowing();
    -+                    if (willDismiss) {
    -+                        mCurrentlyDismissingKeyguard = true;
    -+                    }
    -+                    dismissKeyguard = true;
    -+                }
    -+
    -+                // If we are currently dismissing Keyguard, there is no need to unocclude it.
    -+                if (!mCurrentlyDismissingKeyguard) {
    -+                    if (setKeyguardOccludedLw(false)) {
    -+                        changes |= FINISH_LAYOUT_REDO_LAYOUT
    -+                                | FINISH_LAYOUT_REDO_CONFIG
    -+                                | FINISH_LAYOUT_REDO_WALLPAPER;
    -+                    }
    -+                }
    -+
    -+                if (dismissKeyguard) {
    -                     // Only launch the next keyguard unlock window once per window.
    --                    mHandler.post(new Runnable() {
    --                        @Override
    --                        public void run() {
    --                            mKeyguardDelegate.dismiss(trusted /* allowWhileOccluded */);
    --                        }
    --                    });
    -+                    mHandler.post(() -> mKeyguardDelegate.dismiss(
    -+                            trusted /* allowWhileOccluded */));
    -                 }
    -             } else {
    -                 mWinDismissingKeyguard = null;
    -@@ -5318,15 +5351,18 @@ public class PhoneWindowManager implements WindowManagerPolicy {
    -         boolean showing = mKeyguardDelegate.isShowing();
    -         if (wasOccluded && !isOccluded && showing) {
    -             mKeyguardOccluded = false;
    --            mKeyguardDelegate.setOccluded(false);
    -+            mKeyguardDelegate.setOccluded(false, true /* animate */);
    -             mStatusBar.getAttrs().privateFlags |= PRIVATE_FLAG_KEYGUARD;
    -             if (!mKeyguardDelegate.hasLockscreenWallpaper()) {
    -                 mStatusBar.getAttrs().flags |= FLAG_SHOW_WALLPAPER;
    -             }
    -+            Animation anim = AnimationUtils.loadAnimation(mContext,
    -+                    com.android.internal.R.anim.wallpaper_open_exit);
    -+            mWindowManagerFuncs.overridePlayingAppAnimationsLw(anim);
    -             return true;
    -         } else if (!wasOccluded && isOccluded && showing) {
    -             mKeyguardOccluded = true;
    --            mKeyguardDelegate.setOccluded(true);
    -+            mKeyguardDelegate.setOccluded(true, false /* animate */);
    -             mStatusBar.getAttrs().privateFlags &= ~PRIVATE_FLAG_KEYGUARD;
    -             mStatusBar.getAttrs().flags &= ~FLAG_SHOW_WALLPAPER;
    -             return true;
    -@@ -5335,6 +5371,14 @@ public class PhoneWindowManager implements WindowManagerPolicy {
    -         }
    -     }
    - 
    -+    private void onKeyguardShowingStateChanged(boolean showing) {
    -+        if (!showing) {
    -+            synchronized (mWindowManagerFuncs.getWindowManagerLock()) {
    -+                mCurrentlyDismissingKeyguard = false;
    -+            }
    -+        }
    -+    }
    -+
    -     private boolean isStatusBarKeyguard() {
    -         return mStatusBar != null
    -                 && (mStatusBar.getAttrs().privateFlags & PRIVATE_FLAG_KEYGUARD) != 0;
    -@@ -5511,7 +5555,14 @@ public class PhoneWindowManager implements WindowManagerPolicy {
    - 
    -                 @Override
    -                 public void onServiceDisconnected(ComponentName name) {
    --                    notifyScreenshotError();
    -+                    synchronized (mScreenshotLock) {
    -+                        if (mScreenshotConnection != null) {
    -+                            mContext.unbindService(mScreenshotConnection);
    -+                            mScreenshotConnection = null;
    -+                            mHandler.removeCallbacks(mScreenshotTimeout);
    -+                            notifyScreenshotError();
    -+                        }
    -+                    }
    -                 }
    -             };
    -             if (mContext.bindServiceAsUser(serviceIntent, conn,
    -@@ -6866,7 +6917,8 @@ public class PhoneWindowManager implements WindowManagerPolicy {
    -     /** {@inheritDoc} */
    -     @Override
    -     public void systemReady() {
    --        mKeyguardDelegate = new KeyguardServiceDelegate(mContext);
    -+        mKeyguardDelegate = new KeyguardServiceDelegate(mContext,
    -+                this::onKeyguardShowingStateChanged);
    -         mKeyguardDelegate.onSystemReady();
    - 
    -         readCameraLensCoverState();
    -@@ -7399,11 +7451,20 @@ public class PhoneWindowManager implements WindowManagerPolicy {
    -     private int updateSystemUiVisibilityLw() {
    -         // If there is no window focused, there will be nobody to handle the events
    -         // anyway, so just hang on in whatever state we're in until things settle down.
    --        final WindowState win = mFocusedWindow != null ? mFocusedWindow
    -+        WindowState winCandidate = mFocusedWindow != null ? mFocusedWindow
    -                 : mTopFullscreenOpaqueWindowState;
    --        if (win == null) {
    -+        if (winCandidate == null) {
    -             return 0;
    -         }
    -+        if (winCandidate.getAttrs().token == mImmersiveModeConfirmation.getWindowToken()) {
    -+            // The immersive mode confirmation should never affect the system bar visibility,
    -+            // otherwise it will unhide the navigation bar and hide itself.
    -+            winCandidate = isStatusBarKeyguard() ? mStatusBar : mTopFullscreenOpaqueWindowState;
    -+            if (winCandidate == null) {
    -+                return 0;
    -+            }
    -+        }
    -+        final WindowState win = winCandidate;
    -         if ((win.getAttrs().privateFlags & PRIVATE_FLAG_KEYGUARD) != 0 && mHideLockScreen == true) {
    -             // We are updating at a point where the keyguard has gotten
    -             // focus, but we were last in a state where the top window is
    -@@ -7748,7 +7809,7 @@ public class PhoneWindowManager implements WindowManagerPolicy {
    -         int delta = newRotation - oldRotation;
    -         if (delta < 0) delta += 4;
    -         // Likewise we don't rotate seamlessly for 180 degree rotations
    --        // in this case the surfaces never resize, and our logic to 
    -+        // in this case the surfaces never resize, and our logic to
    -         // revert the transformations on size change will fail. We could
    -         // fix this in the future with the "tagged" frames idea.
    -         if (delta == Surface.ROTATION_180) {
    -@@ -7938,6 +7999,7 @@ public class PhoneWindowManager implements WindowManagerPolicy {
    -                 pw.print(" mForceStatusBarFromKeyguard=");
    -                 pw.println(mForceStatusBarFromKeyguard);
    -         pw.print(prefix); pw.print("mDismissKeyguard="); pw.print(mDismissKeyguard);
    -+                pw.print(" mCurrentlyDismissingKeyguard="); pw.println(mCurrentlyDismissingKeyguard);
    -                 pw.print(" mWinDismissingKeyguard="); pw.print(mWinDismissingKeyguard);
    -                 pw.print(" mHomePressed="); pw.println(mHomePressed);
    -         pw.print(prefix); pw.print("mAllowLockscreenWhenOn="); pw.print(mAllowLockscreenWhenOn);
    -diff --git a/services/core/java/com/android/server/policy/keyguard/KeyguardServiceDelegate.java b/services/core/java/com/android/server/policy/keyguard/KeyguardServiceDelegate.java
    -index 4fce49e..29a1f07 100644
    ---- a/services/core/java/com/android/server/policy/keyguard/KeyguardServiceDelegate.java
    -+++ b/services/core/java/com/android/server/policy/keyguard/KeyguardServiceDelegate.java
    -@@ -23,6 +23,7 @@ import com.android.internal.policy.IKeyguardDrawnCallback;
    - import com.android.internal.policy.IKeyguardExitCallback;
    - import com.android.internal.policy.IKeyguardService;
    - import com.android.server.UiThread;
    -+import com.android.server.policy.keyguard.KeyguardStateMonitor.OnShowingStateChangedCallback;
    - 
    - import java.io.PrintWriter;
    - 
    -@@ -49,6 +50,7 @@ public class KeyguardServiceDelegate {
    -     private final Handler mScrimHandler;
    -     private final KeyguardState mKeyguardState = new KeyguardState();
    -     private DrawnListener mDrawnListenerWhenConnect;
    -+    private final OnShowingStateChangedCallback mShowingStateChangedCallback;
    - 
    -     private static final class KeyguardState {
    -         KeyguardState() {
    -@@ -116,9 +118,11 @@ public class KeyguardServiceDelegate {
    -         }
    -     };
    - 
    --    public KeyguardServiceDelegate(Context context) {
    -+    public KeyguardServiceDelegate(Context context,
    -+            OnShowingStateChangedCallback showingStateChangedCallback) {
    -         mContext = context;
    -         mScrimHandler = UiThread.getHandler();
    -+        mShowingStateChangedCallback = showingStateChangedCallback;
    -         mScrim = createScrim(context, mScrimHandler);
    -     }
    - 
    -@@ -154,7 +158,7 @@ public class KeyguardServiceDelegate {
    -         public void onServiceConnected(ComponentName name, IBinder service) {
    -             if (DEBUG) Log.v(TAG, "*** Keyguard connected (yay!)");
    -             mKeyguardService = new KeyguardServiceWrapper(mContext,
    --                    IKeyguardService.Stub.asInterface(service));
    -+                    IKeyguardService.Stub.asInterface(service), mShowingStateChangedCallback);
    -             if (mKeyguardState.systemIsReady) {
    -                 // If the system is ready, it means keyguard crashed and restarted.
    -                 mKeyguardService.onSystemReady();
    -@@ -180,7 +184,7 @@ public class KeyguardServiceDelegate {
    -                 mKeyguardService.onBootCompleted();
    -             }
    -             if (mKeyguardState.occluded) {
    --                mKeyguardService.setOccluded(mKeyguardState.occluded);
    -+                mKeyguardService.setOccluded(mKeyguardState.occluded, false /* animate */);
    -             }
    -         }
    - 
    -@@ -232,10 +236,10 @@ public class KeyguardServiceDelegate {
    -         }
    -     }
    - 
    --    public void setOccluded(boolean isOccluded) {
    -+    public void setOccluded(boolean isOccluded, boolean animate) {
    -         if (mKeyguardService != null) {
    --            if (DEBUG) Log.v(TAG, "setOccluded(" + isOccluded + ")");
    --            mKeyguardService.setOccluded(isOccluded);
    -+            if (DEBUG) Log.v(TAG, "setOccluded(" + isOccluded + ") animate=" + animate);
    -+            mKeyguardService.setOccluded(isOccluded, animate);
    -         }
    -         mKeyguardState.occluded = isOccluded;
    -     }
    -diff --git a/services/core/java/com/android/server/policy/keyguard/KeyguardServiceWrapper.java b/services/core/java/com/android/server/policy/keyguard/KeyguardServiceWrapper.java
    -index 55652fe..de906e6 100644
    ---- a/services/core/java/com/android/server/policy/keyguard/KeyguardServiceWrapper.java
    -+++ b/services/core/java/com/android/server/policy/keyguard/KeyguardServiceWrapper.java
    -@@ -26,6 +26,7 @@ import com.android.internal.policy.IKeyguardDrawnCallback;
    - import com.android.internal.policy.IKeyguardExitCallback;
    - import com.android.internal.policy.IKeyguardService;
    - import com.android.internal.policy.IKeyguardStateCallback;
    -+import com.android.server.policy.keyguard.KeyguardStateMonitor.OnShowingStateChangedCallback;
    - 
    - import java.io.PrintWriter;
    - 
    -@@ -39,9 +40,11 @@ public class KeyguardServiceWrapper implements IKeyguardService {
    -     private IKeyguardService mService;
    -     private String TAG = "KeyguardServiceWrapper";
    - 
    --    public KeyguardServiceWrapper(Context context, IKeyguardService service) {
    -+    public KeyguardServiceWrapper(Context context, IKeyguardService service,
    -+            OnShowingStateChangedCallback showingStateChangedCallback) {
    -         mService = service;
    --        mKeyguardStateMonitor = new KeyguardStateMonitor(context, service);
    -+        mKeyguardStateMonitor = new KeyguardStateMonitor(context, service,
    -+                showingStateChangedCallback);
    -     }
    - 
    -     @Override // Binder interface
    -@@ -63,9 +66,9 @@ public class KeyguardServiceWrapper implements IKeyguardService {
    -     }
    - 
    -     @Override // Binder interface
    --    public void setOccluded(boolean isOccluded) {
    -+    public void setOccluded(boolean isOccluded, boolean animate) {
    -         try {
    --            mService.setOccluded(isOccluded);
    -+            mService.setOccluded(isOccluded, animate);
    -         } catch (RemoteException e) {
    -             Slog.w(TAG , "Remote Exception", e);
    -         }
    -diff --git a/services/core/java/com/android/server/policy/keyguard/KeyguardStateMonitor.java b/services/core/java/com/android/server/policy/keyguard/KeyguardStateMonitor.java
    -index 08eaaa9..712b625 100644
    ---- a/services/core/java/com/android/server/policy/keyguard/KeyguardStateMonitor.java
    -+++ b/services/core/java/com/android/server/policy/keyguard/KeyguardStateMonitor.java
    -@@ -49,10 +49,13 @@ public class KeyguardStateMonitor extends IKeyguardStateCallback.Stub {
    -     private int mCurrentUserId;
    - 
    -     private final LockPatternUtils mLockPatternUtils;
    -+    private final OnShowingStateChangedCallback mOnShowingStateChangedCallback;
    - 
    --    public KeyguardStateMonitor(Context context, IKeyguardService service) {
    -+    public KeyguardStateMonitor(Context context, IKeyguardService service,
    -+            OnShowingStateChangedCallback showingStateChangedCallback) {
    -         mLockPatternUtils = new LockPatternUtils(context);
    -         mCurrentUserId = ActivityManager.getCurrentUser();
    -+        mOnShowingStateChangedCallback = showingStateChangedCallback;
    -         try {
    -             service.addStateMonitorCallback(this);
    -         } catch (RemoteException e) {
    -@@ -83,6 +86,7 @@ public class KeyguardStateMonitor extends IKeyguardStateCallback.Stub {
    -     @Override // Binder interface
    -     public void onShowingStateChanged(boolean showing) {
    -         mIsShowing = showing;
    -+        mOnShowingStateChangedCallback.onShowingStateChanged(showing);
    -     }
    - 
    -     @Override // Binder interface
    -@@ -122,4 +126,8 @@ public class KeyguardStateMonitor extends IKeyguardStateCallback.Stub {
    -         pw.println(prefix + "mTrusted=" + mTrusted);
    -         pw.println(prefix + "mCurrentUserId=" + mCurrentUserId);
    -     }
    -+
    -+    public interface OnShowingStateChangedCallback {
    -+        void onShowingStateChanged(boolean showing);
    -+    }
    - }
    -\ No newline at end of file
    -diff --git a/services/core/java/com/android/server/power/PowerManagerService.java b/services/core/java/com/android/server/power/PowerManagerService.java
    -index 2824e6e..01288b8 100644
    ---- a/services/core/java/com/android/server/power/PowerManagerService.java
    -+++ b/services/core/java/com/android/server/power/PowerManagerService.java
    -@@ -808,9 +808,10 @@ public final class PowerManagerService extends SystemService
    -     }
    - 
    -     private void updateLowPowerModeLocked() {
    --        if (mIsPowered && mLowPowerModeSetting) {
    -+        if ((mIsPowered || !mBatteryLevelLow && !mBootCompleted) && mLowPowerModeSetting) {
    -             if (DEBUG_SPEW) {
    --                Slog.d(TAG, "updateLowPowerModeLocked: powered, turning setting off");
    -+                Slog.d(TAG, "updateLowPowerModeLocked: powered or booting with sufficient battery,"
    -+                        + " turning setting off");
    -             }
    -             // Turn setting off if powered
    -             Settings.Global.putInt(mContext.getContentResolver(),
    -@@ -2538,18 +2539,18 @@ public final class PowerManagerService extends SystemService
    - 
    -     boolean setDeviceIdleModeInternal(boolean enabled) {
    -         synchronized (mLock) {
    --            if (mDeviceIdleMode != enabled) {
    --                mDeviceIdleMode = enabled;
    --                updateWakeLockDisabledStatesLocked();
    --                if (enabled) {
    --                    EventLogTags.writeDeviceIdleOnPhase("power");
    --                } else {
    --                    EventLogTags.writeDeviceIdleOffPhase("power");
    --                }
    --                return true;
    -+            if (mDeviceIdleMode == enabled) {
    -+                return false;
    -             }
    --            return false;
    -+            mDeviceIdleMode = enabled;
    -+            updateWakeLockDisabledStatesLocked();
    -+        }
    -+        if (enabled) {
    -+            EventLogTags.writeDeviceIdleOnPhase("power");
    -+        } else {
    -+            EventLogTags.writeDeviceIdleOffPhase("power");
    -         }
    -+        return true;
    -     }
    - 
    -     boolean setLightDeviceIdleModeInternal(boolean enabled) {
    -diff --git a/services/core/java/com/android/server/power/ShutdownThread.java b/services/core/java/com/android/server/power/ShutdownThread.java
    -index 8ce2fd9..44894ed 100644
    ---- a/services/core/java/com/android/server/power/ShutdownThread.java
    -+++ b/services/core/java/com/android/server/power/ShutdownThread.java
    -@@ -717,6 +717,14 @@ public final class ShutdownThread extends Thread {
    -         }
    -         if (!done[0]) {
    -             Log.w(TAG, "Timed out waiting for uncrypt.");
    -+            final int uncryptTimeoutError = 100;
    -+            String timeoutMessage = String.format("uncrypt_time: %d\n" + "uncrypt_error: %d\n",
    -+                    MAX_UNCRYPT_WAIT_TIME / 1000, uncryptTimeoutError);
    -+            try {
    -+                FileUtils.stringToFile(RecoverySystem.UNCRYPT_STATUS_FILE, timeoutMessage);
    -+            } catch (IOException e) {
    -+                Log.e(TAG, "Failed to write timeout message to uncrypt status", e);
    -+            }
    -         }
    -     }
    - }
    -diff --git a/services/core/java/com/android/server/storage/DeviceStorageMonitorService.java b/services/core/java/com/android/server/storage/DeviceStorageMonitorService.java
    -index 0ae1717..90c711a 100644
    ---- a/services/core/java/com/android/server/storage/DeviceStorageMonitorService.java
    -+++ b/services/core/java/com/android/server/storage/DeviceStorageMonitorService.java
    -@@ -87,6 +87,11 @@ public class DeviceStorageMonitorService extends SystemService {
    -     private static final long DEFAULT_DISK_FREE_CHANGE_REPORTING_THRESHOLD = 2 * 1024 * 1024; // 2MB
    -     private static final long DEFAULT_CHECK_INTERVAL = MONITOR_INTERVAL*60*1000;
    - 
    -+    // com.android.internal.R.string.low_internal_storage_view_text_no_boot
    -+    // hard codes 250MB in the message as the storage space required for the
    -+    // boot image.
    -+    private static final long BOOT_IMAGE_STORAGE_REQUIREMENT = 250 * 1024 * 1024;
    -+
    -     private long mFreeMem;  // on /data
    -     private long mFreeMemAfterLastCacheClear;  // on /data
    -     private long mLastReportedFreeMem;
    -@@ -290,9 +295,10 @@ public class DeviceStorageMonitorService extends SystemService {
    -                     mLowMemFlag = false;
    -                 }
    -             }
    --            if (!mLowMemFlag && !mIsBootImageOnDisk) {
    -+            if (!mLowMemFlag && !mIsBootImageOnDisk && mFreeMem < BOOT_IMAGE_STORAGE_REQUIREMENT) {
    -                 Slog.i(TAG, "No boot image on disk due to lack of space. Sending notification");
    -                 sendNotification();
    -+                mLowMemFlag = true;
    -             }
    -             if (mFreeMem < mMemFullThreshold) {
    -                 if (!mMemFullFlag) {
    -@@ -383,7 +389,7 @@ public class DeviceStorageMonitorService extends SystemService {
    - 
    -         @Override
    -         public boolean isMemoryLow() {
    --            return mLowMemFlag || !mIsBootImageOnDisk;
    -+            return mLowMemFlag;
    -         }
    - 
    -         @Override
    -diff --git a/services/core/java/com/android/server/trust/TrustManagerService.java b/services/core/java/com/android/server/trust/TrustManagerService.java
    -index d9c4254..a7b9cf4 100644
    ---- a/services/core/java/com/android/server/trust/TrustManagerService.java
    -+++ b/services/core/java/com/android/server/trust/TrustManagerService.java
    -@@ -102,9 +102,8 @@ public class TrustManagerService extends SystemService {
    -     private static final int MSG_START_USER = 7;
    -     private static final int MSG_CLEANUP_USER = 8;
    -     private static final int MSG_SWITCH_USER = 9;
    --    private static final int MSG_SET_DEVICE_LOCKED = 10;
    --    private static final int MSG_FLUSH_TRUST_USUALLY_MANAGED = 11;
    --    private static final int MSG_UNLOCK_USER = 12;
    -+    private static final int MSG_FLUSH_TRUST_USUALLY_MANAGED = 10;
    -+    private static final int MSG_UNLOCK_USER = 11;
    - 
    -     private static final int TRUST_USUALLY_MANAGED_FLUSH_DELAY = 2 * 60 * 1000;
    - 
    -@@ -317,20 +316,6 @@ public class TrustManagerService extends SystemService {
    -         }
    -     }
    - 
    --    public void setDeviceLockedForUser(int userId, boolean locked) {
    --        if (mLockPatternUtils.isSeparateProfileChallengeEnabled(userId)) {
    --            synchronized (mDeviceLockedForUser) {
    --                mDeviceLockedForUser.put(userId, locked);
    --            }
    --            if (locked) {
    --                try {
    --                    ActivityManagerNative.getDefault().notifyLockedProfile(userId);
    --                } catch (RemoteException e) {
    --                }
    --            }
    --        }
    --    }
    --
    -     boolean isDeviceLockedInner(int userId) {
    -         synchronized (mDeviceLockedForUser) {
    -             return mDeviceLockedForUser.get(userId, true);
    -@@ -838,10 +823,24 @@ public class TrustManagerService extends SystemService {
    -         }
    - 
    -         @Override
    --        public void setDeviceLockedForUser(int userId, boolean value) {
    -+        public void setDeviceLockedForUser(int userId, boolean locked) {
    -             enforceReportPermission();
    --            mHandler.obtainMessage(MSG_SET_DEVICE_LOCKED, value ? 1 : 0, userId)
    --                    .sendToTarget();
    -+            final long identity = Binder.clearCallingIdentity();
    -+            try {
    -+                if (mLockPatternUtils.isSeparateProfileChallengeEnabled(userId)) {
    -+                    synchronized (mDeviceLockedForUser) {
    -+                        mDeviceLockedForUser.put(userId, locked);
    -+                    }
    -+                    if (locked) {
    -+                        try {
    -+                            ActivityManagerNative.getDefault().notifyLockedProfile(userId);
    -+                        } catch (RemoteException e) {
    -+                        }
    -+                    }
    -+                }
    -+            } finally {
    -+                Binder.restoreCallingIdentity(identity);
    -+            }
    -         }
    - 
    -         @Override
    -@@ -917,9 +916,6 @@ public class TrustManagerService extends SystemService {
    -                     mCurrentUser = msg.arg1;
    -                     refreshDeviceLockedForUser(UserHandle.USER_ALL);
    -                     break;
    --                case MSG_SET_DEVICE_LOCKED:
    --                    setDeviceLockedForUser(msg.arg2, msg.arg1 != 0);
    --                    break;
    -                 case MSG_FLUSH_TRUST_USUALLY_MANAGED:
    -                     SparseBooleanArray usuallyManaged;
    -                     synchronized (mTrustUsuallyManagedForUser) {
    -diff --git a/services/core/java/com/android/server/twilight/TwilightService.java b/services/core/java/com/android/server/twilight/TwilightService.java
    -index acd6587..db7df25 100644
    ---- a/services/core/java/com/android/server/twilight/TwilightService.java
    -+++ b/services/core/java/com/android/server/twilight/TwilightService.java
    -@@ -151,7 +151,7 @@ public final class TwilightService extends SystemService
    -     }
    - 
    -     private void startListening() {
    --        if (DEBUG) Slog.d(TAG, "startListening");
    -+        Slog.d(TAG, "startListening");
    - 
    -         // Start listening for location updates (default: low power, max 1h, min 10m).
    -         mLocationManager.requestLocationUpdates(
    -@@ -173,7 +173,7 @@ public final class TwilightService extends SystemService
    -             mTimeChangedReceiver = new BroadcastReceiver() {
    -                 @Override
    -                 public void onReceive(Context context, Intent intent) {
    --                    if (DEBUG) Slog.d(TAG, "onReceive: " + intent);
    -+                    Slog.d(TAG, "onReceive: " + intent);
    -                     updateTwilightState();
    -                 }
    -             };
    -@@ -188,7 +188,7 @@ public final class TwilightService extends SystemService
    -     }
    - 
    -     private void stopListening() {
    --        if (DEBUG) Slog.d(TAG, "stopListening");
    -+        Slog.d(TAG, "stopListening");
    - 
    -         if (mTimeChangedReceiver != null) {
    -             getContext().unregisterReceiver(mTimeChangedReceiver);
    -@@ -241,15 +241,20 @@ public final class TwilightService extends SystemService
    - 
    -     @Override
    -     public void onAlarm() {
    --        if (DEBUG) Slog.d(TAG, "onAlarm");
    -+        Slog.d(TAG, "onAlarm");
    -         updateTwilightState();
    -     }
    - 
    -     @Override
    -     public void onLocationChanged(Location location) {
    --        if (DEBUG) Slog.d(TAG, "onLocationChanged: " + location);
    --        mLastLocation = location;
    --        updateTwilightState();
    -+        if (location != null) {
    -+            Slog.d(TAG, "onLocationChanged:"
    -+                    + " provider=" + location.getProvider()
    -+                    + " accuracy=" + location.getAccuracy()
    -+                    + " time=" + location.getTime());
    -+            mLastLocation = location;
    -+            updateTwilightState();
    -+        }
    -     }
    - 
    -     @Override
    -diff --git a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
    -index 536e646..3720940 100644
    ---- a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
    -+++ b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
    -@@ -89,6 +89,7 @@ import com.android.internal.os.BackgroundThread;
    - import com.android.internal.util.FastXmlSerializer;
    - import com.android.internal.util.JournaledFile;
    - import com.android.server.EventLogTags;
    -+import com.android.server.FgThread;
    - import com.android.server.SystemService;
    - 
    - import libcore.io.IoUtils;
    -@@ -479,6 +480,7 @@ public class WallpaperManagerService extends IWallpaperManager.Stub {
    -     WallpaperData mLastWallpaper;
    -     IWallpaperManagerCallback mKeyguardListener;
    -     boolean mWaitingForUnlock;
    -+    boolean mShuttingDown;
    - 
    -     /**
    -      * ID of the current wallpaper, changed every time anything sets a wallpaper.
    -@@ -589,6 +591,11 @@ public class WallpaperManagerService extends IWallpaperManager.Stub {
    - 
    -     class WallpaperConnection extends IWallpaperConnection.Stub
    -             implements ServiceConnection {
    -+
    -+        /** Time in milliseconds until we expect the wallpaper to reconnect (unless we're in the
    -+         *  middle of an update). If exceeded, the wallpaper gets reset to the system default. */
    -+        private static final long WALLPAPER_RECONNECT_TIMEOUT_MS = 5000;
    -+
    -         final WallpaperInfo mInfo;
    -         final Binder mToken = new Binder();
    -         IWallpaperService mService;
    -@@ -599,6 +606,26 @@ public class WallpaperManagerService extends IWallpaperManager.Stub {
    -         boolean mDimensionsChanged = false;
    -         boolean mPaddingChanged = false;
    - 
    -+        private Runnable mResetRunnable = () -> {
    -+            synchronized (mLock) {
    -+                if (mShuttingDown) {
    -+                    // Don't expect wallpaper services to relaunch during shutdown
    -+                    if (DEBUG) {
    -+                        Slog.i(TAG, "Ignoring relaunch timeout during shutdown");
    -+                    }
    -+                    return;
    -+                }
    -+
    -+                if (!mWallpaper.wallpaperUpdating
    -+                        && mWallpaper.userId == mCurrentUserId) {
    -+                    Slog.w(TAG, "Wallpaper reconnect timed out, "
    -+                            + "reverting to built-in wallpaper!");
    -+                    clearWallpaperLocked(true, FLAG_SYSTEM, mWallpaper.userId,
    -+                            null);
    -+                }
    -+            }
    -+        };
    -+
    -         public WallpaperConnection(WallpaperInfo info, WallpaperData wallpaper) {
    -             mInfo = info;
    -             mWallpaper = wallpaper;
    -@@ -615,6 +642,7 @@ public class WallpaperManagerService extends IWallpaperManager.Stub {
    -                     // locking there and anyway we always need to be able to
    -                     // recover if there is something wrong.
    -                     saveSettingsLocked(mWallpaper.userId);
    -+                    FgThread.getHandler().removeCallbacks(mResetRunnable);
    -                 }
    -             }
    -         }
    -@@ -641,6 +669,12 @@ public class WallpaperManagerService extends IWallpaperManager.Stub {
    -                             clearWallpaperLocked(true, FLAG_SYSTEM, mWallpaper.userId, null);
    -                         } else {
    -                             mWallpaper.lastDiedTime = SystemClock.uptimeMillis();
    -+
    -+                            // If we didn't reset it right away, do so after we couldn't connect to
    -+                            // it for an extended amount of time to avoid having a black wallpaper.
    -+                            FgThread.getHandler().removeCallbacks(mResetRunnable);
    -+                            FgThread.getHandler().postDelayed(mResetRunnable,
    -+                                    WALLPAPER_RECONNECT_TIMEOUT_MS);
    -                         }
    -                         final String flattened = name.flattenToString();
    -                         EventLog.writeEvent(EventLogTags.WP_WALLPAPER_CRASHED,
    -@@ -752,6 +786,10 @@ public class WallpaperManagerService extends IWallpaperManager.Stub {
    -                     if (wallpaper.wallpaperComponent != null
    -                             && wallpaper.wallpaperComponent.getPackageName().equals(packageName)) {
    -                         wallpaper.wallpaperUpdating = true;
    -+                        if (wallpaper.connection != null) {
    -+                            FgThread.getHandler().removeCallbacks(
    -+                                    wallpaper.connection.mResetRunnable);
    -+                        }
    -                     }
    -                 }
    -             }
    -@@ -838,6 +876,7 @@ public class WallpaperManagerService extends IWallpaperManager.Stub {
    -     public WallpaperManagerService(Context context) {
    -         if (DEBUG) Slog.v(TAG, "WallpaperService startup");
    -         mContext = context;
    -+        mShuttingDown = false;
    -         mImageWallpaper = ComponentName.unflattenFromString(
    -                 context.getResources().getString(R.string.image_wallpaper_component));
    -         mIWindowManager = IWindowManager.Stub.asInterface(
    -@@ -902,6 +941,21 @@ public class WallpaperManagerService extends IWallpaperManager.Stub {
    -             }
    -         }, userFilter);
    - 
    -+        final IntentFilter shutdownFilter = new IntentFilter(Intent.ACTION_SHUTDOWN);
    -+        mContext.registerReceiver(new BroadcastReceiver() {
    -+            @Override
    -+            public void onReceive(Context context, Intent intent) {
    -+                if (Intent.ACTION_SHUTDOWN.equals(intent.getAction())) {
    -+                    if (DEBUG) {
    -+                        Slog.i(TAG, "Shutting down");
    -+                    }
    -+                    synchronized (mLock) {
    -+                        mShuttingDown = true;
    -+                    }
    -+                }
    -+            }
    -+        }, shutdownFilter);
    -+
    -         try {
    -             ActivityManagerNative.getDefault().registerUserSwitchObserver(
    -                     new IUserSwitchObserver.Stub() {
    -@@ -1433,7 +1487,7 @@ public class WallpaperManagerService extends IWallpaperManager.Stub {
    -         lockWP.cropHint.set(sysWP.cropHint);
    -         lockWP.width = sysWP.width;
    -         lockWP.height = sysWP.height;
    --        lockWP.allowBackup = false;
    -+        lockWP.allowBackup = sysWP.allowBackup;
    - 
    -         // Migrate the bitmap files outright; no need to copy
    -         try {
    -diff --git a/services/core/java/com/android/server/wm/AccessibilityController.java b/services/core/java/com/android/server/wm/AccessibilityController.java
    -index e5e2175..66b1b3d 100644
    ---- a/services/core/java/com/android/server/wm/AccessibilityController.java
    -+++ b/services/core/java/com/android/server/wm/AccessibilityController.java
    -@@ -644,7 +644,7 @@ final class AccessibilityController {
    -                 final int windowCount = windowList.size();
    -                 for (int i = 0; i < windowCount; i++) {
    -                     WindowState windowState = windowList.get(i);
    --                    if (windowState.isOnScreen() &&
    -+                    if (windowState.isOnScreen() && windowState.isVisibleLw() &&
    -                             !windowState.mWinAnimator.mEnterAnimationPending) {
    -                         outWindows.put(windowState.mLayer, windowState);
    -                     }
    -diff --git a/services/core/java/com/android/server/wm/AppTransition.java b/services/core/java/com/android/server/wm/AppTransition.java
    -index d4d6f32..cd46165 100644
    ---- a/services/core/java/com/android/server/wm/AppTransition.java
    -+++ b/services/core/java/com/android/server/wm/AppTransition.java
    -@@ -374,6 +374,7 @@ public class AppTransition implements Dump {
    - 
    -     void goodToGo(AppWindowAnimator topOpeningAppAnimator, AppWindowAnimator topClosingAppAnimator,
    -             ArraySet<AppWindowToken> openingApps, ArraySet<AppWindowToken> closingApps) {
    -+        int appTransition = mNextAppTransition;
    -         mNextAppTransition = TRANSIT_UNSET;
    -         mAppTransitionState = APP_STATE_RUNNING;
    -         notifyAppTransitionStartingLocked(
    -@@ -382,7 +383,7 @@ public class AppTransition implements Dump {
    -                 topOpeningAppAnimator != null ? topOpeningAppAnimator.animation : null,
    -                 topClosingAppAnimator != null ? topClosingAppAnimator.animation : null);
    -         mService.getDefaultDisplayContentLocked().getDockedDividerController()
    --                .notifyAppTransitionStarting();
    -+                .notifyAppTransitionStarting(openingApps, appTransition);
    - 
    -         // Prolong the start for the transition when docking a task from recents, unless recents
    -         // ended it already then we don't need to wait.
    -diff --git a/services/core/java/com/android/server/wm/AppWindowToken.java b/services/core/java/com/android/server/wm/AppWindowToken.java
    -index 621e43a..b1d2edf 100644
    ---- a/services/core/java/com/android/server/wm/AppWindowToken.java
    -+++ b/services/core/java/com/android/server/wm/AppWindowToken.java
    -@@ -30,6 +30,7 @@ import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME
    - import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
    - import static com.android.server.wm.WindowManagerService.WINDOW_REPLACEMENT_TIMEOUT_DURATION;
    - import static com.android.server.wm.WindowManagerService.H.NOTIFY_ACTIVITY_DRAWN;
    -+import static com.android.server.wm.WindowStateAnimator.STACK_CLIP_NONE;
    - 
    - import com.android.server.input.InputApplicationHandle;
    - import com.android.server.wm.WindowManagerService.H;
    -@@ -44,6 +45,7 @@ import android.util.Slog;
    - import android.view.IApplicationToken;
    - import android.view.View;
    - import android.view.WindowManager;
    -+import android.view.animation.Animation;
    - 
    - import java.io.PrintWriter;
    - import java.util.ArrayDeque;
    -@@ -838,6 +840,21 @@ class AppWindowToken extends WindowToken {
    -         }
    -     }
    - 
    -+    /**
    -+     * See {@link WindowManagerService#overridePlayingAppAnimationsLw}
    -+     */
    -+    void overridePlayingAppAnimations(Animation a) {
    -+        if (mAppAnimator.isAnimating()) {
    -+            final WindowState win = findMainWindow();
    -+            if (win == null) {
    -+                return;
    -+            }
    -+            final int width = win.mContainingFrame.width();
    -+            final int height = win.mContainingFrame.height();
    -+            mAppAnimator.setAnimation(a, width, height, false, STACK_CLIP_NONE);
    -+        }
    -+    }
    -+
    -     @Override
    -     void dump(PrintWriter pw, String prefix) {
    -         super.dump(pw, prefix);
    -diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
    -index 1d57872..e8104c4 100644
    ---- a/services/core/java/com/android/server/wm/DisplayContent.java
    -+++ b/services/core/java/com/android/server/wm/DisplayContent.java
    -@@ -22,12 +22,15 @@ import static android.app.ActivityManager.StackId.PINNED_STACK_ID;
    - import static android.view.WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
    - import static android.view.WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE;
    - import static android.view.WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL;
    -+import static android.view.WindowManager.LayoutParams.TYPE_TOAST;
    - import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_VISIBILITY;
    - import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
    - import static com.android.server.wm.WindowState.RESIZE_HANDLE_WIDTH_IN_DP;
    - 
    - import android.app.ActivityManager.StackId;
    -+import android.graphics.Matrix;
    - import android.graphics.Rect;
    -+import android.graphics.RectF;
    - import android.graphics.Region;
    - import android.graphics.Region.Op;
    - import android.util.DisplayMetrics;
    -@@ -35,6 +38,7 @@ import android.util.Slog;
    - import android.view.Display;
    - import android.view.DisplayInfo;
    - import android.view.Surface;
    -+import android.view.animation.Animation;
    - 
    - import java.io.PrintWriter;
    - import java.util.ArrayList;
    -@@ -100,6 +104,8 @@ class DisplayContent {
    -     /** Save allocating when calculating rects */
    -     private final Rect mTmpRect = new Rect();
    -     private final Rect mTmpRect2 = new Rect();
    -+    private final RectF mTmpRectF = new RectF();
    -+    private final Matrix mTmpMatrix = new Matrix();
    -     private final Region mTmpRegion = new Region();
    - 
    -     /** For gathering Task objects in order. */
    -@@ -236,6 +242,20 @@ class DisplayContent {
    -         out.set(left, top, left + width, top + height);
    -     }
    - 
    -+    private void getLogicalDisplayRect(Rect out, int orientation) {
    -+        getLogicalDisplayRect(out);
    -+
    -+        // Rotate the Rect if needed.
    -+        final int currentRotation = mDisplayInfo.rotation;
    -+        final int rotationDelta = deltaRotation(currentRotation, orientation);
    -+        if (rotationDelta == Surface.ROTATION_90 || rotationDelta == Surface.ROTATION_270) {
    -+            createRotationMatrix(rotationDelta, mBaseDisplayWidth, mBaseDisplayHeight, mTmpMatrix);
    -+            mTmpRectF.set(out);
    -+            mTmpMatrix.mapRect(mTmpRectF);
    -+            mTmpRectF.round(out);
    -+        }
    -+    }
    -+
    -     void getContentRect(Rect out) {
    -         out.set(mContentRect);
    -     }
    -@@ -530,38 +550,51 @@ class DisplayContent {
    -     }
    - 
    -     void rotateBounds(int oldRotation, int newRotation, Rect bounds) {
    --        final int rotationDelta = DisplayContent.deltaRotation(oldRotation, newRotation);
    --        getLogicalDisplayRect(mTmpRect);
    --        switch (rotationDelta) {
    -+        getLogicalDisplayRect(mTmpRect, newRotation);
    -+
    -+        // Compute a transform matrix to undo the coordinate space transformation,
    -+        // and present the window at the same physical position it previously occupied.
    -+        final int deltaRotation = deltaRotation(newRotation, oldRotation);
    -+        createRotationMatrix(deltaRotation, mTmpRect.width(), mTmpRect.height(), mTmpMatrix);
    -+
    -+        mTmpRectF.set(bounds);
    -+        mTmpMatrix.mapRect(mTmpRectF);
    -+        mTmpRectF.round(bounds);
    -+    }
    -+
    -+    static int deltaRotation(int oldRotation, int newRotation) {
    -+        int delta = newRotation - oldRotation;
    -+        if (delta < 0) delta += 4;
    -+        return delta;
    -+    }
    -+
    -+    static void createRotationMatrix(int rotation, float displayWidth, float displayHeight,
    -+            Matrix outMatrix) {
    -+        // For rotations without Z-ordering we don't need the target rectangle's position.
    -+        createRotationMatrix(rotation, 0 /* rectLeft */, 0 /* rectTop */, displayWidth,
    -+                displayHeight, outMatrix);
    -+    }
    -+
    -+    static void createRotationMatrix(int rotation, float rectLeft, float rectTop,
    -+            float displayWidth, float displayHeight, Matrix outMatrix) {
    -+        switch (rotation) {
    -             case Surface.ROTATION_0:
    --                mTmpRect2.set(bounds);
    -+                outMatrix.reset();
    -                 break;
    --            case Surface.ROTATION_90:
    --                mTmpRect2.top = mTmpRect.bottom - bounds.right;
    --                mTmpRect2.left = bounds.top;
    --                mTmpRect2.right = mTmpRect2.left + bounds.height();
    --                mTmpRect2.bottom = mTmpRect2.top + bounds.width();
    -+            case Surface.ROTATION_270:
    -+                outMatrix.setRotate(270, 0, 0);
    -+                outMatrix.postTranslate(0, displayHeight);
    -+                outMatrix.postTranslate(rectTop, 0);
    -                 break;
    -             case Surface.ROTATION_180:
    --                mTmpRect2.top = mTmpRect.bottom - bounds.bottom;
    --                mTmpRect2.left = mTmpRect.right - bounds.right;
    --                mTmpRect2.right = mTmpRect2.left + bounds.width();
    --                mTmpRect2.bottom = mTmpRect2.top + bounds.height();
    -+                outMatrix.reset();
    -                 break;
    --            case Surface.ROTATION_270:
    --                mTmpRect2.top = bounds.left;
    --                mTmpRect2.left = mTmpRect.right - bounds.bottom;
    --                mTmpRect2.right = mTmpRect2.left + bounds.height();
    --                mTmpRect2.bottom = mTmpRect2.top + bounds.width();
    -+            case Surface.ROTATION_90:
    -+                outMatrix.setRotate(90, 0, 0);
    -+                outMatrix.postTranslate(displayWidth, 0);
    -+                outMatrix.postTranslate(-rectTop, rectLeft);
    -                 break;
    -         }
    --        bounds.set(mTmpRect2);
    --    }
    --
    --    static int deltaRotation(int oldRotation, int newRotation) {
    --        int delta = newRotation - oldRotation;
    --        if (delta < 0) delta += 4;
    --        return delta;
    -     }
    - 
    -     public void dump(String prefix, PrintWriter pw) {
    -@@ -637,7 +670,7 @@ class DisplayContent {
    -      */
    -     TaskStack getDockedStackVisibleForUserLocked() {
    -         final TaskStack stack = mService.mStackIdToStack.get(DOCKED_STACK_ID);
    --        return (stack != null && stack.isVisibleForUserLocked()) ? stack : null;
    -+        return (stack != null && stack.isVisibleLocked(true /* ignoreKeyguard */)) ? stack : null;
    -     }
    - 
    -     /**
    -@@ -674,4 +707,48 @@ class DisplayContent {
    - 
    -         return touchedWin;
    -     }
    -+
    -+    /**
    -+     * See {@link WindowManagerService#overridePlayingAppAnimationsLw}.
    -+     */
    -+    void overridePlayingAppAnimationsLw(Animation a) {
    -+        for (int i = mStacks.size() - 1; i >= 0; i--) {
    -+            mStacks.get(i).overridePlayingAppAnimations(a);
    -+        }
    -+    }
    -+
    -+    boolean canAddToastWindowForUid(int uid) {
    -+        // We allow one toast window per UID being shown at a time.
    -+        WindowList windows = getWindowList();
    -+        final int windowCount = windows.size();
    -+        for (int i = 0; i < windowCount; i++) {
    -+            WindowState window = windows.get(i);
    -+            if (window.mAttrs.type == TYPE_TOAST && window.mOwnerUid == uid
    -+                    && !window.isRemovedOrHidden()) {
    -+                return false;
    -+            }
    -+        }
    -+        return true;
    -+    }
    -+
    -+    void scheduleToastWindowsTimeoutIfNeededLocked(WindowState oldFocus,
    -+                                                   WindowState newFocus) {
    -+        if (oldFocus == null || (newFocus != null && newFocus.mOwnerUid == oldFocus.mOwnerUid)) {
    -+            return;
    -+        }
    -+        final int lostFocusUid = oldFocus.mOwnerUid;
    -+        WindowList windows = getWindowList();
    -+        final int windowCount = windows.size();
    -+        for (int i = 0; i < windowCount; i++) {
    -+            WindowState window = windows.get(i);
    -+            if (window.mAttrs.type == TYPE_TOAST && window.mOwnerUid == lostFocusUid) {
    -+                if (!mService.mH.hasMessages(WindowManagerService.H.WINDOW_HIDE_TIMEOUT, window)) {
    -+                    mService.mH.sendMessageDelayed(
    -+                            mService.mH.obtainMessage(
    -+                                    WindowManagerService.H.WINDOW_HIDE_TIMEOUT, window),
    -+                            window.mAttrs.hideTimeoutMilliseconds);
    -+                }
    -+            }
    -+        }
    -+    }
    - }
    -diff --git a/services/core/java/com/android/server/wm/DockedStackDividerController.java b/services/core/java/com/android/server/wm/DockedStackDividerController.java
    -index f93e2ff..6f0a43a 100644
    ---- a/services/core/java/com/android/server/wm/DockedStackDividerController.java
    -+++ b/services/core/java/com/android/server/wm/DockedStackDividerController.java
    -@@ -29,6 +29,7 @@ import static android.view.WindowManager.DOCKED_RIGHT;
    - import static android.view.WindowManager.DOCKED_TOP;
    - import static com.android.server.wm.AppTransition.DEFAULT_APP_TRANSITION_DURATION;
    - import static com.android.server.wm.AppTransition.TOUCH_RESPONSE_INTERPOLATOR;
    -+import static com.android.server.wm.AppTransition.TRANSIT_NONE;
    - import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME;
    - import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
    - import static com.android.server.wm.WindowManagerService.H.NOTIFY_DOCKED_STACK_MINIMIZED_CHANGED;
    -@@ -38,6 +39,7 @@ import android.content.res.Configuration;
    - import android.graphics.Rect;
    - import android.os.RemoteCallbackList;
    - import android.os.RemoteException;
    -+import android.util.ArraySet;
    - import android.util.Slog;
    - import android.view.DisplayInfo;
    - import android.view.IDockedStackListener;
    -@@ -492,8 +494,32 @@ public class DockedStackDividerController implements DimLayerUser {
    -         checkMinimizeChanged(false /* animate */);
    -     }
    - 
    --    void notifyAppTransitionStarting() {
    -+    void notifyAppTransitionStarting(ArraySet<AppWindowToken> openingApps, int appTransition) {
    -+        final boolean wasMinimized = mMinimizedDock;
    -         checkMinimizeChanged(true /* animate */);
    -+
    -+        // We were minimized, and now we are still minimized, but somebody is trying to launch an
    -+        // app in docked stack, better show recent apps so we actually get unminimized! This catches
    -+        // any case that was missed in ActivityStarter.postStartActivityUncheckedProcessing because
    -+        // we couldn't retrace the launch of the app in the docked stack to the launch from
    -+        // homescreen.
    -+        if (wasMinimized && mMinimizedDock && containsAppInDockedStack(openingApps)
    -+                && appTransition != TRANSIT_NONE) {
    -+            mService.showRecentApps(true /* fromHome */);
    -+        }
    -+    }
    -+
    -+    /**
    -+     * @return true if {@param apps} contains an activity in the docked stack, false otherwise.
    -+     */
    -+    private boolean containsAppInDockedStack(ArraySet<AppWindowToken> apps) {
    -+        for (int i = apps.size() - 1; i >= 0; i--) {
    -+            final AppWindowToken token = apps.valueAt(i);
    -+            if (token.mTask != null && token.mTask.mStack.mStackId == DOCKED_STACK_ID) {
    -+                return true;
    -+            }
    -+        }
    -+        return false;
    -     }
    - 
    -     boolean isMinimizedDock() {
    -diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java
    -index 1dcada6..ca183010 100644
    ---- a/services/core/java/com/android/server/wm/Task.java
    -+++ b/services/core/java/com/android/server/wm/Task.java
    -@@ -38,6 +38,7 @@ import android.util.EventLog;
    - import android.util.Slog;
    - import android.view.DisplayInfo;
    - import android.view.Surface;
    -+import android.view.animation.Animation;
    - 
    - import com.android.server.EventLogTags;
    - 
    -@@ -677,19 +678,6 @@ class Task implements DimLayer.DimLayerUser {
    -         return (tokensCount != 0) && mAppTokens.get(tokensCount - 1).showForAllUsers;
    -     }
    - 
    --    boolean isVisibleForUser() {
    --        for (int i = mAppTokens.size() - 1; i >= 0; i--) {
    --            final AppWindowToken appToken = mAppTokens.get(i);
    --            for (int j = appToken.allAppWindows.size() - 1; j >= 0; j--) {
    --                WindowState window = appToken.allAppWindows.get(j);
    --                if (!window.isHiddenFromUserLocked()) {
    --                    return true;
    --                }
    --            }
    --        }
    --        return false;
    --    }
    --
    -     boolean isVisible() {
    -         for (int i = mAppTokens.size() - 1; i >= 0; i--) {
    -             final AppWindowToken appToken = mAppTokens.get(i);
    -@@ -778,6 +766,15 @@ class Task implements DimLayer.DimLayerUser {
    -         return mStack.getDisplayContent().getDisplayInfo();
    -     }
    - 
    -+    /**
    -+     * See {@link WindowManagerService#overridePlayingAppAnimationsLw}
    -+     */
    -+    void overridePlayingAppAnimations(Animation a) {
    -+        for (int i = mAppTokens.size() - 1; i >= 0; i--) {
    -+            mAppTokens.get(i).overridePlayingAppAnimations(a);
    -+        }
    -+    }
    -+
    -     @Override
    -     public String toString() {
    -         return "{taskId=" + mTaskId + " appTokens=" + mAppTokens + " mdr=" + mDeferRemoval + "}";
    -diff --git a/services/core/java/com/android/server/wm/TaskStack.java b/services/core/java/com/android/server/wm/TaskStack.java
    -index 8be5b19..8f8f642 100644
    ---- a/services/core/java/com/android/server/wm/TaskStack.java
    -+++ b/services/core/java/com/android/server/wm/TaskStack.java
    -@@ -44,6 +44,7 @@ import android.util.SparseArray;
    - import android.view.DisplayInfo;
    - import android.view.Surface;
    - import android.view.SurfaceControl;
    -+import android.view.animation.Animation;
    - 
    - import com.android.internal.policy.DividerSnapAlgorithm;
    - import com.android.internal.policy.DividerSnapAlgorithm.SnapTarget;
    -@@ -398,23 +399,21 @@ public class TaskStack implements DimLayer.DimLayerUser,
    -             return false;
    -         }
    - 
    --        final int oldDockSide = mStackId == DOCKED_STACK_ID ? getDockSide() : DOCKED_INVALID;
    -         mTmpRect2.set(mBounds);
    -         mDisplayContent.rotateBounds(mRotation, newRotation, mTmpRect2);
    -         if (mStackId == DOCKED_STACK_ID) {
    -             repositionDockedStackAfterRotation(mTmpRect2);
    -             snapDockedStackAfterRotation(mTmpRect2);
    -             final int newDockSide = getDockSide(mTmpRect2);
    --            if (oldDockSide != newDockSide) {
    --                // Update the dock create mode and clear the dock create bounds, these
    --                // might change after a rotation and the original values will be invalid.
    --                mService.setDockedStackCreateStateLocked(
    --                        (newDockSide == DOCKED_LEFT || newDockSide == DOCKED_TOP)
    --                        ? DOCKED_STACK_CREATE_MODE_TOP_OR_LEFT
    --                        : DOCKED_STACK_CREATE_MODE_BOTTOM_OR_RIGHT,
    --                        null);
    --                mDisplayContent.getDockedDividerController().notifyDockSideChanged(newDockSide);
    --            }
    -+
    -+            // Update the dock create mode and clear the dock create bounds, these
    -+            // might change after a rotation and the original values will be invalid.
    -+            mService.setDockedStackCreateStateLocked(
    -+                    (newDockSide == DOCKED_LEFT || newDockSide == DOCKED_TOP)
    -+                    ? DOCKED_STACK_CREATE_MODE_TOP_OR_LEFT
    -+                    : DOCKED_STACK_CREATE_MODE_BOTTOM_OR_RIGHT,
    -+                    null);
    -+            mDisplayContent.getDockedDividerController().notifyDockSideChanged(newDockSide);
    -         }
    - 
    -         mBoundsAfterRotation.set(mTmpRect2);
    -@@ -890,7 +889,7 @@ public class TaskStack implements DimLayer.DimLayerUser,
    -             mAdjustImeAmount = adjustAmount;
    -             mAdjustDividerAmount = adjustDividerAmount;
    -             updateAdjustedBounds();
    --            return isVisibleForUserLocked();
    -+            return isVisibleLocked(true /* ignoreKeyguard */);
    -         } else {
    -             return false;
    -         }
    -@@ -926,7 +925,7 @@ public class TaskStack implements DimLayer.DimLayerUser,
    -         if (minimizeAmount != mMinimizeAmount) {
    -             mMinimizeAmount = minimizeAmount;
    -             updateAdjustedBounds();
    --            return isVisibleForUserLocked();
    -+            return isVisibleLocked(true /* ignoreKeyguard*/);
    -         } else {
    -             return false;
    -         }
    -@@ -943,7 +942,7 @@ public class TaskStack implements DimLayer.DimLayerUser,
    -     void beginImeAdjustAnimation() {
    -         for (int j = mTasks.size() - 1; j >= 0; j--) {
    -             final Task task = mTasks.get(j);
    --            if (task.isVisibleForUser()) {
    -+            if (task.isVisible()) {
    -                 task.setDragResizing(true, DRAG_RESIZE_MODE_DOCKED_DIVIDER);
    -                 task.addWindowsWaitingForDrawnIfResizingChanged();
    -             }
    -@@ -1233,9 +1232,13 @@ public class TaskStack implements DimLayer.DimLayerUser,
    -     }
    - 
    -     boolean isVisibleLocked() {
    -+        return isVisibleLocked(false /* ignoreKeyguard */);
    -+    }
    -+
    -+    boolean isVisibleLocked(boolean ignoreKeyguard) {
    -         final boolean keyguardOn = mService.mPolicy.isKeyguardShowingOrOccluded()
    -                 && !mService.mAnimator.mKeyguardGoingAway;
    --        if (keyguardOn && !StackId.isAllowedOverLockscreen(mStackId)) {
    -+        if (!ignoreKeyguard && keyguardOn && !StackId.isAllowedOverLockscreen(mStackId)) {
    -             // The keyguard is showing and the stack shouldn't show on top of the keyguard.
    -             return false;
    -         }
    -@@ -1252,20 +1255,6 @@ public class TaskStack implements DimLayer.DimLayerUser,
    -         return false;
    -     }
    - 
    --    /**
    --     * @return true if a the stack is visible for the current in user, ignoring any other visibility
    --     *         aspects, and false otherwise
    --     */
    --    boolean isVisibleForUserLocked() {
    --        for (int i = mTasks.size() - 1; i >= 0; i--) {
    --            final Task task = mTasks.get(i);
    --            if (task.isVisibleForUser()) {
    --                return true;
    --            }
    --        }
    --        return false;
    --    }
    --
    -     boolean isDragResizing() {
    -         return mDragResizing;
    -     }
    -@@ -1379,4 +1368,13 @@ public class TaskStack implements DimLayer.DimLayerUser,
    -     public boolean getBoundsAnimating() {
    -         return mBoundsAnimating;
    -     }
    -+
    -+    /**
    -+     * See {@link WindowManagerService#overridePlayingAppAnimationsLw}
    -+     */
    -+    void overridePlayingAppAnimations(Animation a) {
    -+        for (int i = mTasks.size() - 1; i >= 0; --i) {
    -+            mTasks.get(i).overridePlayingAppAnimations(a);
    -+        }
    -+    }
    - }
    -diff --git a/services/core/java/com/android/server/wm/WallpaperController.java b/services/core/java/com/android/server/wm/WallpaperController.java
    -index 2b66c3a..e7ceba9 100644
    ---- a/services/core/java/com/android/server/wm/WallpaperController.java
    -+++ b/services/core/java/com/android/server/wm/WallpaperController.java
    -@@ -757,14 +757,16 @@ class WallpaperController {
    -                 }
    - 
    -                 // Now stick it in. For apps over wallpaper keep the wallpaper at the bottommost
    --                // layer. For keyguard over wallpaper put the wallpaper under the keyguard.
    -+                // layer. For keyguard over wallpaper put the wallpaper under the lowest window that
    -+                // is currently on screen, i.e. not hidden by policy.
    -                 int insertionIndex = 0;
    -                 if (visible && wallpaperTarget != null) {
    -                     final int type = wallpaperTarget.mAttrs.type;
    -                     final int privateFlags = wallpaperTarget.mAttrs.privateFlags;
    -                     if ((privateFlags & PRIVATE_FLAG_KEYGUARD) != 0
    -                             || type == TYPE_KEYGUARD_SCRIM) {
    --                        insertionIndex = windows.indexOf(wallpaperTarget);
    -+                        insertionIndex = Math.min(windows.indexOf(wallpaperTarget),
    -+                                findLowestWindowOnScreen(windows));
    -                     }
    -                 }
    -                 if (DEBUG_WALLPAPER_LIGHT || DEBUG_WINDOW_MOVEMENT
    -@@ -781,6 +783,21 @@ class WallpaperController {
    -         return changed;
    -     }
    - 
    -+    /**
    -+     * @return The index in {@param windows} of the lowest window that is currently on screen and
    -+     *         not hidden by the policy.
    -+     */
    -+    private int findLowestWindowOnScreen(WindowList windows) {
    -+        final int size = windows.size();
    -+        for (int index = 0; index < size; index++) {
    -+            final WindowState win = windows.get(index);
    -+            if (win.isOnScreen()) {
    -+                return index;
    -+            }
    -+        }
    -+        return Integer.MAX_VALUE;
    -+    }
    -+
    -     boolean adjustWallpaperWindows() {
    -         mService.mWindowPlacerLocked.mWallpaperMayChange = false;
    - 
    -diff --git a/services/core/java/com/android/server/wm/WindowAnimator.java b/services/core/java/com/android/server/wm/WindowAnimator.java
    -index b0d357c..1ee5a22 100644
    ---- a/services/core/java/com/android/server/wm/WindowAnimator.java
    -+++ b/services/core/java/com/android/server/wm/WindowAnimator.java
    -@@ -121,6 +121,9 @@ public class WindowAnimator {
    - 
    -     private final AppTokenList mTmpExitingAppTokens = new AppTokenList();
    - 
    -+    /** The window that was previously hiding the Keyguard. */
    -+    private WindowState mLastShowWinWhenLocked;
    -+
    -     private String forceHidingToString() {
    -         switch (mForceHiding) {
    -             case KEYGUARD_NOT_SHOWN:    return "KEYGUARD_NOT_SHOWN";
    -@@ -221,13 +224,30 @@ public class WindowAnimator {
    -         }
    -     }
    - 
    -+    /**
    -+     * @return The window that is currently hiding the Keyguard, or if it was hiding the Keyguard,
    -+     *         and it's still animating.
    -+     */
    -+    private WindowState getWinShowWhenLockedOrAnimating() {
    -+        final WindowState winShowWhenLocked = (WindowState) mPolicy.getWinShowWhenLockedLw();
    -+        if (winShowWhenLocked != null) {
    -+            return winShowWhenLocked;
    -+        }
    -+        if (mLastShowWinWhenLocked != null && mLastShowWinWhenLocked.isOnScreen()
    -+                && mLastShowWinWhenLocked.isAnimatingLw()
    -+                && (mLastShowWinWhenLocked.mAttrs.flags & FLAG_SHOW_WHEN_LOCKED) != 0) {
    -+            return mLastShowWinWhenLocked;
    -+        }
    -+        return null;
    -+    }
    -+
    -     private boolean shouldForceHide(WindowState win) {
    -         final WindowState imeTarget = mService.mInputMethodTarget;
    -         final boolean showImeOverKeyguard = imeTarget != null && imeTarget.isVisibleNow() &&
    -                 ((imeTarget.getAttrs().flags & FLAG_SHOW_WHEN_LOCKED) != 0
    -                         || !mPolicy.canBeForceHidden(imeTarget, imeTarget.mAttrs));
    - 
    --        final WindowState winShowWhenLocked = (WindowState) mPolicy.getWinShowWhenLockedLw();
    -+        final WindowState winShowWhenLocked = getWinShowWhenLockedOrAnimating();
    -         final AppWindowToken appShowWhenLocked = winShowWhenLocked == null ?
    -                 null : winShowWhenLocked.mAppToken;
    - 
    -@@ -241,7 +261,7 @@ public class WindowAnimator {
    -             allowWhenLocked |= appShowWhenLocked == win.mAppToken
    -                     // Show all SHOW_WHEN_LOCKED windows if some apps are shown over lockscreen
    -                     || (win.mAttrs.flags & FLAG_SHOW_WHEN_LOCKED) != 0
    --                    // Show error dialogs over apps that dismiss keyguard.
    -+                    // Show error dialogs over apps that are shown on lockscreen
    -                     || (win.mAttrs.privateFlags & PRIVATE_FLAG_SYSTEM_ERROR) != 0;
    -         }
    - 
    -@@ -555,6 +575,11 @@ public class WindowAnimator {
    -                 mPostKeyguardExitAnimation = null;
    -             }
    -         }
    -+
    -+        final WindowState winShowWhenLocked = (WindowState) mPolicy.getWinShowWhenLockedLw();
    -+        if (winShowWhenLocked != null) {
    -+            mLastShowWinWhenLocked = winShowWhenLocked;
    -+        }
    -     }
    - 
    -     private void updateWallpaperLocked(int displayId) {
    -diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
    -index eb9ad6c..ca2610a 100644
    ---- a/services/core/java/com/android/server/wm/WindowManagerService.java
    -+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
    -@@ -21,6 +21,7 @@ import android.animation.ValueAnimator;
    - import android.annotation.IntDef;
    - import android.annotation.NonNull;
    - import android.annotation.Nullable;
    -+import android.app.ActivityManager;
    - import android.app.ActivityManagerInternal;
    - import android.app.ActivityManagerNative;
    - import android.app.AppOpsManager;
    -@@ -35,6 +36,7 @@ import android.content.Context;
    - import android.content.Intent;
    - import android.content.IntentFilter;
    - import android.content.pm.ActivityInfo;
    -+import android.content.pm.ApplicationInfo;
    - import android.content.pm.PackageManager;
    - import android.content.res.CompatibilityInfo;
    - import android.content.res.Configuration;
    -@@ -201,6 +203,7 @@ import static android.view.WindowManager.LayoutParams.TYPE_NAVIGATION_BAR;
    - import static android.view.WindowManager.LayoutParams.TYPE_PRIVATE_PRESENTATION;
    - import static android.view.WindowManager.LayoutParams.TYPE_QS_DIALOG;
    - import static android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR;
    -+import static android.view.WindowManager.LayoutParams.TYPE_TOAST;
    - import static android.view.WindowManager.LayoutParams.TYPE_VOICE_INTERACTION;
    - import static android.view.WindowManager.LayoutParams.TYPE_WALLPAPER;
    - import static android.view.WindowManagerGlobal.RELAYOUT_DEFER_SURFACE_DESTROY;
    -@@ -249,6 +252,7 @@ import static com.android.server.wm.WindowManagerDebugConfig.TAG_KEEP_SCREEN_ON;
    - import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME;
    - import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
    - import static com.android.server.wm.WindowStateAnimator.DRAW_PENDING;
    -+import static com.android.server.wm.WindowStateAnimator.STACK_CLIP_NONE;
    - 
    - /** {@hide} */
    - public class WindowManagerService extends IWindowManager.Stub
    -@@ -650,6 +654,12 @@ public class WindowManagerService extends IWindowManager.Stub
    -     WindowManagerInternal.OnHardKeyboardStatusChangeListener mHardKeyboardStatusChangeListener;
    -     SettingsObserver mSettingsObserver;
    - 
    -+    // A count of the windows which are 'seamlessly rotated', e.g. a surface
    -+    // at an old orientation is being transformed. We freeze orientation updates
    -+    // while any windows are seamlessly rotated, so we need to track when this
    -+    // hits zero so we can apply deferred orientation updates.
    -+    int mSeamlessRotationCount = 0;
    -+
    -     private final class SettingsObserver extends ContentObserver {
    -         private final Uri mDisplayInversionEnabledUri =
    -                 Settings.Secure.getUriFor(Settings.Secure.ACCESSIBILITY_DISPLAY_INVERSION_ENABLED);
    -@@ -1868,6 +1878,7 @@ public class WindowManagerService extends IWindowManager.Stub
    -         boolean reportNewConfig = false;
    -         WindowState attachedWindow = null;
    -         long origId;
    -+        final int callingUid = Binder.getCallingUid();
    -         final int type = attrs.type;
    - 
    -         synchronized(mWindowMap) {
    -@@ -1915,6 +1926,8 @@ public class WindowManagerService extends IWindowManager.Stub
    -             boolean addToken = false;
    -             WindowToken token = mTokenMap.get(attrs.token);
    -             AppWindowToken atoken = null;
    -+            boolean addToastWindowRequiresToken = false;
    -+
    -             if (token == null) {
    -                 if (type >= FIRST_APPLICATION_WINDOW && type <= LAST_APPLICATION_WINDOW) {
    -                     Slog.w(TAG_WM, "Attempted to add application window with unknown token "
    -@@ -1951,6 +1964,15 @@ public class WindowManagerService extends IWindowManager.Stub
    -                             + attrs.token + ".  Aborting.");
    -                     return WindowManagerGlobal.ADD_BAD_APP_TOKEN;
    -                 }
    -+                if (type == TYPE_TOAST) {
    -+                    // Apps targeting SDK above N MR1 cannot arbitrary add toast windows.
    -+                    if (doesAddToastWindowRequireToken(attrs.packageName, callingUid,
    -+                            attachedWindow)) {
    -+                        Slog.w(TAG_WM, "Attempted to add a toast window with unknown token "
    -+                                + attrs.token + ".  Aborting.");
    -+                        return WindowManagerGlobal.ADD_BAD_APP_TOKEN;
    -+                    }
    -+                }
    -                 token = new WindowToken(this, attrs.token, -1, false);
    -                 addToken = true;
    -             } else if (type >= FIRST_APPLICATION_WINDOW && type <= LAST_APPLICATION_WINDOW) {
    -@@ -2000,6 +2022,15 @@ public class WindowManagerService extends IWindowManager.Stub
    -                             + attrs.token + ".  Aborting.");
    -                     return WindowManagerGlobal.ADD_BAD_APP_TOKEN;
    -                 }
    -+            } else if (type == TYPE_TOAST) {
    -+                // Apps targeting SDK above N MR1 cannot arbitrary add toast windows.
    -+                addToastWindowRequiresToken = doesAddToastWindowRequireToken(attrs.packageName,
    -+                        callingUid, attachedWindow);
    -+                if (addToastWindowRequiresToken && token.windowType != TYPE_TOAST) {
    -+                    Slog.w(TAG_WM, "Attempted to add a toast window with bad token "
    -+                            + attrs.token + ".  Aborting.");
    -+                    return WindowManagerGlobal.ADD_BAD_APP_TOKEN;
    -+                }
    -             } else if (type == TYPE_QS_DIALOG) {
    -                 if (token.windowType != TYPE_QS_DIALOG) {
    -                     Slog.w(TAG_WM, "Attempted to add QS dialog window with bad token "
    -@@ -2044,6 +2075,36 @@ public class WindowManagerService extends IWindowManager.Stub
    -                 win.openInputChannel(outInputChannel);
    -             }
    - 
    -+            // If adding a toast requires a token for this app we always schedule hiding
    -+            // toast windows to make sure they don't stick around longer then necessary.
    -+            // We hide instead of remove such windows as apps aren't prepared to handle
    -+            // windows being removed under them.
    -+            //
    -+            // If the app is older it can add toasts without a token and hence overlay
    -+            // other apps. To be maximally compatible with these apps we will hide the
    -+            // window after the toast timeout only if the focused window is from another
    -+            // UID, otherwise we allow unlimited duration. When a UID looses focus we
    -+            // schedule hiding all of its toast windows.
    -+            if (type == TYPE_TOAST) {
    -+                if (!getDefaultDisplayContentLocked().canAddToastWindowForUid(callingUid)) {
    -+                    Slog.w(TAG_WM, "Adding more than one toast window for UID at a time.");
    -+                    return WindowManagerGlobal.ADD_DUPLICATE_ADD;
    -+                }
    -+                // Make sure this happens before we moved focus as one can make the
    -+                // toast focusable to force it not being hidden after the timeout.
    -+                // Focusable toasts are always timed out to prevent a focused app to
    -+                // show a focusable toasts while it has focus which will be kept on
    -+                // the screen after the activity goes away.
    -+                if (addToastWindowRequiresToken
    -+                        || (attrs.flags & LayoutParams.FLAG_NOT_FOCUSABLE) == 0
    -+                        || mCurrentFocus == null
    -+                        || mCurrentFocus.mOwnerUid != callingUid) {
    -+                    mH.sendMessageDelayed(
    -+                            mH.obtainMessage(H.WINDOW_HIDE_TIMEOUT, win),
    -+                            win.mAttrs.hideTimeoutMilliseconds);
    -+                }
    -+            }
    -+
    -             // From now on, no exceptions or errors allowed!
    - 
    -             res = WindowManagerGlobal.ADD_OKAY;
    -@@ -2182,11 +2243,6 @@ public class WindowManagerService extends IWindowManager.Stub
    -             if (win.isVisibleOrAdding() && updateOrientationFromAppTokensLocked(false)) {
    -                 reportNewConfig = true;
    -             }
    --            if (attrs.removeTimeoutMilliseconds > 0) {
    --                mH.sendMessageDelayed(
    --                        mH.obtainMessage(H.WINDOW_REMOVE_TIMEOUT, win),
    --                        attrs.removeTimeoutMilliseconds);
    --            }
    -         }
    - 
    -         if (reportNewConfig) {
    -@@ -2198,6 +2254,32 @@ public class WindowManagerService extends IWindowManager.Stub
    -         return res;
    -     }
    - 
    -+    private boolean doesAddToastWindowRequireToken(String packageName, int callingUid,
    -+            WindowState attachedWindow) {
    -+        // Try using the target SDK of the root window
    -+        if (attachedWindow != null) {
    -+            return attachedWindow.mAppToken != null
    -+                    && attachedWindow.mAppToken.targetSdk > Build.VERSION_CODES.N_MR1;
    -+        } else {
    -+            // Otherwise, look at the package
    -+            try {
    -+                ApplicationInfo appInfo = mContext.getPackageManager()
    -+                        .getApplicationInfoAsUser(packageName, 0,
    -+                                UserHandle.getUserId(callingUid));
    -+                if (appInfo.uid != callingUid) {
    -+                    throw new SecurityException("Package " + packageName + " not in UID "
    -+                            + callingUid);
    -+                }
    -+                if (appInfo.targetSdkVersion > Build.VERSION_CODES.N_MR1) {
    -+                    return true;
    -+                }
    -+            } catch (PackageManager.NameNotFoundException e) {
    -+                /* ignore */
    -+            }
    -+        }
    -+        return false;
    -+    }
    -+
    -     /**
    -      * Returns true if we're done setting up any transitions.
    -      */
    -@@ -2908,12 +2990,11 @@ public class WindowManagerService extends IWindowManager.Stub
    -                     }
    -                     result |= RELAYOUT_RES_SURFACE_CHANGED;
    -                 }
    --                final WindowSurfaceController surfaceController = winAnimator.mSurfaceController;
    --                if (viewVisibility == View.VISIBLE && surfaceController != null) {
    -+                if (viewVisibility == View.VISIBLE && winAnimator.hasSurface()) {
    -                     // We already told the client to go invisible, but the message may not be
    -                     // handled yet, or it might want to draw a last frame. If we already have a
    -                     // surface, let the client use that, but don't create new surface at this point.
    --                    surfaceController.getSurface(outSurface);
    -+                    winAnimator.mSurfaceController.getSurface(outSurface);
    -                 } else {
    -                     if (DEBUG_VISIBILITY) Slog.i(TAG_WM, "Releasing surface in: " + win);
    - 
    -@@ -3715,7 +3796,11 @@ public class WindowManagerService extends IWindowManager.Stub
    -         Configuration config = null;
    - 
    -         if (updateOrientationFromAppTokensLocked(false)) {
    --            if (freezeThisOneIfNeeded != null) {
    -+            // If we changed the orientation but mOrientationChangeComplete is
    -+            // already true, we used seamless rotation, and we don't need
    -+            // to freeze the screen.
    -+            if (freezeThisOneIfNeeded != null &&
    -+                    !mWindowPlacerLocked.mOrientationChangeComplete) {
    -                 AppWindowToken atoken = findAppWindowToken(freezeThisOneIfNeeded);
    -                 if (atoken != null) {
    -                     startAppFreezingScreenLocked(atoken);
    -@@ -3784,6 +3869,19 @@ public class WindowManagerService extends IWindowManager.Stub
    -         }
    -     }
    - 
    -+    // If this is true we have updated our desired orientation, but not yet
    -+    // changed the real orientation our applied our screen rotation animation.
    -+    // For example, because a previous screen rotation was in progress.
    -+    boolean rotationNeedsUpdateLocked() {
    -+        int rotation = mPolicy.rotationForOrientationLw(mLastOrientation, mRotation);
    -+        boolean altOrientation = !mPolicy.rotationHasCompatibleMetricsLw(
    -+                mLastOrientation, rotation);
    -+        if (mRotation == rotation && mAltOrientation == altOrientation) {
    -+            return false;
    -+        }
    -+        return true;
    -+    }
    -+
    -     @Override
    -     public int[] setNewConfiguration(Configuration config) {
    -         if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS,
    -@@ -5212,6 +5310,11 @@ public class WindowManagerService extends IWindowManager.Stub
    -         }
    -     }
    - 
    -+    @Override
    -+    public void overridePlayingAppAnimationsLw(Animation a) {
    -+        getDefaultDisplayContentLocked().overridePlayingAppAnimationsLw(a);
    -+    }
    -+
    -     /**
    -      * Re-sizes a stack and its containing tasks.
    -      * @param stackId Id of stack to resize.
    -@@ -6710,6 +6813,13 @@ public class WindowManagerService extends IWindowManager.Stub
    -             if (DEBUG_ORIENTATION) Slog.v(TAG_WM, "Deferring rotation, animation in progress.");
    -             return false;
    -         }
    -+        if (mDisplayFrozen) {
    -+            // Even if the screen rotation animation has finished (e.g. isAnimating
    -+            // returns false), there is still some time where we haven't yet unfrozen
    -+            // the display. We also need to abort rotation here.
    -+            if (DEBUG_ORIENTATION) Slog.v(TAG_WM, "Deferring rotation, still finishing previous rotation");
    -+            return false;
    -+        }
    - 
    -         if (!mDisplayEnabled) {
    -             // No point choosing a rotation if the display is not enabled.
    -@@ -6717,12 +6827,44 @@ public class WindowManagerService extends IWindowManager.Stub
    -             return false;
    -         }
    - 
    -+        final DisplayContent displayContent = getDefaultDisplayContentLocked();
    -+        final WindowList windows = displayContent.getWindowList();
    -+
    -+        final int oldRotation = mRotation;
    -+        int rotation = mPolicy.rotationForOrientationLw(mLastOrientation, mRotation);
    -+        boolean rotateSeamlessly = mPolicy.shouldRotateSeamlessly(oldRotation, rotation);
    -+
    -+        if (rotateSeamlessly) {
    -+            for (int i = windows.size() - 1; i >= 0; i--) {
    -+                WindowState w = windows.get(i);
    -+                // We can't rotate (seamlessly or not) while waiting for the last seamless rotation
    -+                // to complete (that is, waiting for windows to redraw). It's tempting to check
    -+                // w.mSeamlessRotationCount but that could be incorrect in the case of window-removal.
    -+                if (w.mSeamlesslyRotated) {
    -+                    return false;
    -+                }
    -+                // In what can only be called an unfortunate workaround we require
    -+                // seamlessly rotated child windows to have the TRANSFORM_TO_DISPLAY_INVERSE
    -+                // flag. Due to limitations in the client API, there is no way for
    -+                // the client to set this flag in a race free fashion. If we seamlessly rotate
    -+                // a window which does not have this flag, but then gains it, we will get
    -+                // an incorrect visual result (rotated viewfinder). This means if we want to
    -+                // support seamlessly rotating windows which could gain this flag, we can't
    -+                // rotate windows without it. This limits seamless rotation in N to camera framework
    -+                // users, windows without children, and native code. This is unfortunate but
    -+                // having the camera work is our primary goal.
    -+                if (w.isChildWindow() & w.isVisibleNow() &&
    -+                        !w.mWinAnimator.mSurfaceController.getTransformToDisplayInverse()) {
    -+                    rotateSeamlessly = false;
    -+                }
    -+            }
    -+        }
    -+
    -         // TODO: Implement forced rotation changes.
    -         //       Set mAltOrientation to indicate that the application is receiving
    -         //       an orientation that has different metrics than it expected.
    -         //       eg. Portrait instead of Landscape.
    - 
    --        int rotation = mPolicy.rotationForOrientationLw(mLastOrientation, mRotation);
    -         boolean altOrientation = !mPolicy.rotationHasCompatibleMetricsLw(
    -                 mLastOrientation, rotation);
    - 
    -@@ -6735,7 +6877,7 @@ public class WindowManagerService extends IWindowManager.Stub
    - 
    -         if (mRotation == rotation && mAltOrientation == altOrientation) {
    -             // No change.
    --            return false;
    -+             return false;
    -         }
    - 
    -         if (DEBUG_ORIENTATION) {
    -@@ -6745,8 +6887,6 @@ public class WindowManagerService extends IWindowManager.Stub
    -                 + ", lastOrientation=" + mLastOrientation);
    -         }
    - 
    --        int oldRotation = mRotation;
    --
    -         mRotation = rotation;
    -         mAltOrientation = altOrientation;
    -         mPolicy.setRotationLw(mRotation);
    -@@ -6755,7 +6895,6 @@ public class WindowManagerService extends IWindowManager.Stub
    -         mH.removeMessages(H.WINDOW_FREEZE_TIMEOUT);
    -         mH.sendEmptyMessageDelayed(H.WINDOW_FREEZE_TIMEOUT, WINDOW_FREEZE_TIMEOUT_DURATION);
    -         mWaitingForConfig = true;
    --        final DisplayContent displayContent = getDefaultDisplayContentLocked();
    -         displayContent.layoutNeeded = true;
    -         final int[] anim = new int[2];
    -         if (displayContent.isDimming()) {
    -@@ -6763,33 +6902,6 @@ public class WindowManagerService extends IWindowManager.Stub
    -         } else {
    -             mPolicy.selectRotationAnimationLw(anim);
    -         }
    --        boolean rotateSeamlessly = mPolicy.shouldRotateSeamlessly(oldRotation, mRotation);
    --        final WindowList windows = displayContent.getWindowList();
    --        // We can't rotate seamlessly while an existing seamless rotation is still
    --        // waiting on windows to finish drawing.
    --        if (rotateSeamlessly) {
    --            for (int i = windows.size() - 1; i >= 0; i--) {
    --                WindowState w = windows.get(i);
    --                if (w.mSeamlesslyRotated) {
    --                    rotateSeamlessly = false;
    --                    break;
    --                }
    --                // In what can only be called an unfortunate workaround we require
    --                // seamlessly rotated child windows to have the TRANSFORM_TO_DISPLAY_INVERSE
    --                // flag. Due to limitations in the client API, there is no way for
    --                // the client to set this flag in a race free fashion. If we seamlessly rotate
    --                // a window which does not have this flag, but then gains it, we will get
    --                // an incorrect visual result (rotated viewfinder). This means if we want to
    --                // support seamlessly rotating windows which could gain this flag, we can't
    --                // rotate windows without it. This limits seamless rotation in N to camera framework
    --                // users, windows without children, and native code. This is unfortunate but
    --                // having the camera work is our primary goal.
    --                if (w.isChildWindow() & w.isVisibleNow() &&
    --                        !w.mWinAnimator.mSurfaceController.getTransformToDisplayInverse()) {
    --                    rotateSeamlessly = false;
    --                }
    --            }
    --        }
    - 
    -         if (!rotateSeamlessly) {
    -             startFreezingDisplayLocked(inTransaction, anim[0], anim[1]);
    -@@ -6802,6 +6914,10 @@ public class WindowManagerService extends IWindowManager.Stub
    -             // When we are rotating seamlessly, we allow the elements to transition
    -             // to their rotated state independently and without a freeze required.
    -             screenRotationAnimation = null;
    -+
    -+            // We have to reset this in case a window was removed before it
    -+            // finished seamless rotation.
    -+            mSeamlessRotationCount = 0;
    -         }
    - 
    -         // We need to update our screen size information to match the new rotation. If the rotation
    -@@ -8160,7 +8276,7 @@ public class WindowManagerService extends IWindowManager.Stub
    -         public static final int NOTIFY_APP_TRANSITION_FINISHED = 49;
    -         public static final int NOTIFY_STARTING_WINDOW_DRAWN = 50;
    -         public static final int UPDATE_ANIMATION_SCALE = 51;
    --        public static final int WINDOW_REMOVE_TIMEOUT = 52;
    -+        public static final int WINDOW_HIDE_TIMEOUT = 52;
    -         public static final int NOTIFY_DOCKED_STACK_MINIMIZED_CHANGED = 53;
    -         public static final int SEAMLESS_ROTATION_TIMEOUT = 54;
    - 
    -@@ -8780,7 +8896,7 @@ public class WindowManagerService extends IWindowManager.Stub
    -                     mAmInternal.notifyStartingWindowDrawn();
    -                 }
    -                 break;
    --                case WINDOW_REMOVE_TIMEOUT: {
    -+                case WINDOW_HIDE_TIMEOUT: {
    -                     final WindowState window = (WindowState) msg.obj;
    -                     synchronized(mWindowMap) {
    -                         // TODO: This is all about fixing b/21693547
    -@@ -8791,8 +8907,11 @@ public class WindowManagerService extends IWindowManager.Stub
    -                         // running under debugger) to crash (b/29105388). The windows will
    -                         // eventually be removed when the client process finishes.
    -                         // The best we can do for now is remove the FLAG_KEEP_SCREEN_ON
    --                        // and prevent the symptoms of b/21693547.
    -+                        // and prevent the symptoms of b/21693547. Since apps don't
    -+                        // support windows being removed under them we hide the window
    -+                        // and it will be removed when the app dies.
    -                         window.mAttrs.flags &= ~FLAG_KEEP_SCREEN_ON;
    -+                        window.hidePermanentlyLw();
    -                         window.setDisplayLayoutNeeded();
    -                         mWindowPlacerLocked.performSurfacePlacement();
    -                     }
    -@@ -8814,8 +8933,8 @@ public class WindowManagerService extends IWindowManager.Stub
    -                             if (w.mSeamlesslyRotated) {
    -                                 layoutNeeded = true;
    -                                 w.setDisplayLayoutNeeded();
    -+                                markForSeamlessRotation(w, false);
    -                             }
    --                            w.mSeamlesslyRotated = false;
    -                         }
    -                         if (layoutNeeded) {
    -                             mWindowPlacerLocked.performSurfacePlacement();
    -@@ -9110,7 +9229,7 @@ public class WindowManagerService extends IWindowManager.Stub
    -     }
    - 
    -     @Override
    --    public void setForcedDisplayDensity(int displayId, int density) {
    -+    public void setForcedDisplayDensityForUser(int displayId, int density, int userId) {
    -         if (mContext.checkCallingOrSelfPermission(
    -                 android.Manifest.permission.WRITE_SECURE_SETTINGS) !=
    -                 PackageManager.PERMISSION_GRANTED) {
    -@@ -9120,16 +9239,20 @@ public class WindowManagerService extends IWindowManager.Stub
    -         if (displayId != Display.DEFAULT_DISPLAY) {
    -             throw new IllegalArgumentException("Can only set the default display");
    -         }
    -+
    -+        final int targetUserId = ActivityManager.handleIncomingUser(Binder.getCallingPid(),
    -+                Binder.getCallingUid(), userId, false, true, "setForcedDisplayDensityForUser",
    -+                null);
    -         final long ident = Binder.clearCallingIdentity();
    -         try {
    -             synchronized(mWindowMap) {
    -                 final DisplayContent displayContent = getDisplayContentLocked(displayId);
    --                if (displayContent != null) {
    -+                if (displayContent != null && mCurrentUserId == targetUserId) {
    -                     setForcedDisplayDensityLocked(displayContent, density);
    --                    Settings.Secure.putStringForUser(mContext.getContentResolver(),
    --                            Settings.Secure.DISPLAY_DENSITY_FORCED,
    --                            Integer.toString(density), mCurrentUserId);
    -                 }
    -+                Settings.Secure.putStringForUser(mContext.getContentResolver(),
    -+                        Settings.Secure.DISPLAY_DENSITY_FORCED,
    -+                        Integer.toString(density), targetUserId);
    -             }
    -         } finally {
    -             Binder.restoreCallingIdentity(ident);
    -@@ -9137,7 +9260,7 @@ public class WindowManagerService extends IWindowManager.Stub
    -     }
    - 
    -     @Override
    --    public void clearForcedDisplayDensity(int displayId) {
    -+    public void clearForcedDisplayDensityForUser(int displayId, int userId) {
    -         if (mContext.checkCallingOrSelfPermission(
    -                 android.Manifest.permission.WRITE_SECURE_SETTINGS) !=
    -                 PackageManager.PERMISSION_GRANTED) {
    -@@ -9147,16 +9270,20 @@ public class WindowManagerService extends IWindowManager.Stub
    -         if (displayId != Display.DEFAULT_DISPLAY) {
    -             throw new IllegalArgumentException("Can only set the default display");
    -         }
    -+
    -+        final int callingUserId = ActivityManager.handleIncomingUser(Binder.getCallingPid(),
    -+                Binder.getCallingUid(), userId, false, true, "clearForcedDisplayDensityForUser",
    -+                null);
    -         final long ident = Binder.clearCallingIdentity();
    -         try {
    -             synchronized(mWindowMap) {
    -                 final DisplayContent displayContent = getDisplayContentLocked(displayId);
    --                if (displayContent != null) {
    -+                if (displayContent != null && mCurrentUserId == callingUserId) {
    -                     setForcedDisplayDensityLocked(displayContent,
    -                             displayContent.mInitialDisplayDensity);
    --                    Settings.Secure.putStringForUser(mContext.getContentResolver(),
    --                            Settings.Secure.DISPLAY_DENSITY_FORCED, "", mCurrentUserId);
    -                 }
    -+                Settings.Secure.putStringForUser(mContext.getContentResolver(),
    -+                        Settings.Secure.DISPLAY_DENSITY_FORCED, "", callingUserId);
    -             }
    -         } finally {
    -             Binder.restoreCallingIdentity(ident);
    -@@ -9828,6 +9955,12 @@ public class WindowManagerService extends IWindowManager.Stub
    - 
    -             adjustForImeIfNeeded(displayContent);
    - 
    -+            // We may need to schedule some toast windows to be removed. The
    -+            // toasts for an app that does not have input focus are removed
    -+            // within a timeout to prevent apps to redress other apps' UI.
    -+            getDefaultDisplayContentLocked().scheduleToastWindowsTimeoutIfNeededLocked(
    -+                        oldFocus, newFocus);
    -+
    -             Trace.traceEnd(Trace.TRACE_TAG_WINDOW_MANAGER);
    -             return true;
    -         }
    -@@ -10130,6 +10263,32 @@ public class WindowManagerService extends IWindowManager.Stub
    -     }
    - 
    -     @Override
    -+    public void setRecentsVisibility(boolean visible) {
    -+        if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.STATUS_BAR)
    -+                != PackageManager.PERMISSION_GRANTED) {
    -+            throw new SecurityException("Caller does not hold permission "
    -+                    + android.Manifest.permission.STATUS_BAR);
    -+        }
    -+
    -+        synchronized (mWindowMap) {
    -+            mPolicy.setRecentsVisibilityLw(visible);
    -+        }
    -+    }
    -+
    -+    @Override
    -+    public void setTvPipVisibility(boolean visible) {
    -+        if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.STATUS_BAR)
    -+                != PackageManager.PERMISSION_GRANTED) {
    -+            throw new SecurityException("Caller does not hold permission "
    -+                    + android.Manifest.permission.STATUS_BAR);
    -+        }
    -+
    -+        synchronized (mWindowMap) {
    -+            mPolicy.setTvPipVisibilityLw(visible);
    -+        }
    -+    }
    -+
    -+    @Override
    -     public void statusBarVisibilityChanged(int visibility) {
    -         if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.STATUS_BAR)
    -                 != PackageManager.PERMISSION_GRANTED) {
    -@@ -11361,6 +11520,26 @@ public class WindowManagerService extends IWindowManager.Stub
    -         mPolicy.registerShortcutKey(shortcutCode, shortcutKeyReceiver);
    -     }
    - 
    -+    void markForSeamlessRotation(WindowState w, boolean seamlesslyRotated) {
    -+        if (seamlesslyRotated == w.mSeamlesslyRotated) {
    -+            return;
    -+        }
    -+        w.mSeamlesslyRotated = seamlesslyRotated;
    -+        if (seamlesslyRotated) {
    -+            mSeamlessRotationCount++;
    -+        } else {
    -+            mSeamlessRotationCount--;
    -+        }
    -+        if (mSeamlessRotationCount == 0) {
    -+            if (DEBUG_ORIENTATION) {
    -+                Slog.i(TAG, "Performing post-rotate rotation after seamless rotation");
    -+            }
    -+            if (updateRotationUncheckedLocked(false)) {
    -+                mH.sendEmptyMessage(H.SEND_NEW_CONFIGURATION);
    -+            }
    -+        }
    -+    }
    -+
    -     private final class LocalService extends WindowManagerInternal {
    -         @Override
    -         public void requestTraversalFromDisplayManager() {
    -diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
    -index 54f60ef..fbef2c6 100644
    ---- a/services/core/java/com/android/server/wm/WindowState.java
    -+++ b/services/core/java/com/android/server/wm/WindowState.java
    -@@ -166,6 +166,7 @@ final class WindowState implements WindowManagerPolicy.WindowState {
    -     boolean mPolicyVisibility = true;
    -     boolean mPolicyVisibilityAfterAnim = true;
    -     boolean mAppOpVisibility = true;
    -+    boolean mPermanentlyHidden; // the window should never be shown again
    -     boolean mAppFreezing;
    -     boolean mAttachedHidden;    // is our parent window hidden?
    -     boolean mWallpaperVisible;  // for wallpaper, what was last vis report?
    -@@ -1417,7 +1418,7 @@ final class WindowState implements WindowManagerPolicy.WindowState {
    -      */
    -     boolean hasMoved() {
    -         return mHasSurface && (mContentChanged || mMovedByResize)
    --                && !mAnimatingExit && mService.okToDisplay()
    -+                && !mAnimatingExit
    -                 && (mFrame.top != mLastFrame.top || mFrame.left != mLastFrame.left)
    -                 && (mAttachedWindow == null || !mAttachedWindow.hasMoved());
    -     }
    -@@ -1876,6 +1877,11 @@ final class WindowState implements WindowManagerPolicy.WindowState {
    -             // Being hidden due to app op request.
    -             return false;
    -         }
    -+        if (mPermanentlyHidden) {
    -+            // Permanently hidden until the app exists as apps aren't prepared
    -+            // to handle their windows being removed from under them.
    -+            return false;
    -+        }
    -         if (mPolicyVisibility && mPolicyVisibilityAfterAnim) {
    -             // Already showing.
    -             return false;
    -@@ -1966,6 +1972,13 @@ final class WindowState implements WindowManagerPolicy.WindowState {
    -         }
    -     }
    - 
    -+    public void hidePermanentlyLw() {
    -+        if (!mPermanentlyHidden) {
    -+            mPermanentlyHidden = true;
    -+            hideLw(true, true);
    -+        }
    -+    }
    -+
    -     public void pokeDrawLockLw(long timeout) {
    -         if (isVisibleOrAdding()) {
    -             if (mDrawLock == null) {
    -@@ -2615,7 +2628,7 @@ final class WindowState implements WindowManagerPolicy.WindowState {
    -             pw.println(Integer.toHexString(mSystemUiVisibility));
    -         }
    -         if (!mPolicyVisibility || !mPolicyVisibilityAfterAnim || !mAppOpVisibility
    --                || mAttachedHidden) {
    -+                || mAttachedHidden || mPermanentlyHidden) {
    -             pw.print(prefix); pw.print("mPolicyVisibility=");
    -                     pw.print(mPolicyVisibility);
    -                     pw.print(" mPolicyVisibilityAfterAnim=");
    -@@ -2623,6 +2636,7 @@ final class WindowState implements WindowManagerPolicy.WindowState {
    -                     pw.print(" mAppOpVisibility=");
    -                     pw.print(mAppOpVisibility);
    -                     pw.print(" mAttachedHidden="); pw.println(mAttachedHidden);
    -+                    pw.print(" mPermanentlyHidden="); pw.println(mPermanentlyHidden);
    -         }
    -         if (!mRelayoutCalled || mLayoutNeeded) {
    -             pw.print(prefix); pw.print("mRelayoutCalled="); pw.print(mRelayoutCalled);
    -@@ -2947,4 +2961,10 @@ final class WindowState implements WindowManagerPolicy.WindowState {
    -     public boolean isRtl() {
    -         return mMergedConfiguration.getLayoutDirection() == View.LAYOUT_DIRECTION_RTL;
    -     }
    -+
    -+    public boolean isRemovedOrHidden() {
    -+        return mPermanentlyHidden || mAnimatingExit
    -+                || mRemoveOnExit || mWindowRemovalAllowed
    -+                || mViewVisibility == View.GONE;
    -+    }
    - }
    -diff --git a/services/core/java/com/android/server/wm/WindowStateAnimator.java b/services/core/java/com/android/server/wm/WindowStateAnimator.java
    -index 00f4a45..aa8e781 100644
    ---- a/services/core/java/com/android/server/wm/WindowStateAnimator.java
    -+++ b/services/core/java/com/android/server/wm/WindowStateAnimator.java
    -@@ -228,8 +228,6 @@ class WindowStateAnimator {
    -     int mAttrType;
    - 
    -     static final long PENDING_TRANSACTION_FINISH_WAIT_TIME = 100;
    --    long mDeferTransactionUntilFrame = -1;
    --    long mDeferTransactionTime = -1;
    - 
    -     boolean mForceScaleUntilResize;
    - 
    -@@ -1433,7 +1431,7 @@ class WindowStateAnimator {
    -         // If we are undergoing seamless rotation, the surface has already
    -         // been set up to persist at it's old location. We need to freeze
    -         // updates until a resize occurs.
    --        w.mSeamlesslyRotated = w.mSeamlesslyRotated && !mSurfaceResized;
    -+        mService.markForSeamlessRotation(w, w.mSeamlesslyRotated && !mSurfaceResized);
    - 
    -         calculateSurfaceWindowCrop(mTmpClipRect, mTmpFinalClipRect);
    - 
    -@@ -2055,35 +2053,11 @@ class WindowStateAnimator {
    -         if (!mWin.isChildWindow()) {
    -             return;
    -         }
    --        mDeferTransactionUntilFrame = frameNumber;
    --        mDeferTransactionTime = System.currentTimeMillis();
    -         mSurfaceController.deferTransactionUntil(
    -                 mWin.mAttachedWindow.mWinAnimator.mSurfaceController.getHandle(),
    -                 frameNumber);
    -     }
    - 
    --    // Defer the current transaction to the frame number of the last saved transaction.
    --    // We do this to avoid shooting through an unsynchronized transaction while something is
    --    // pending. This is generally fine, as either we will get in on the synchronization,
    --    // or SurfaceFlinger will see that the frame has already occured. The only
    --    // potential problem is in frame number resets so we reset things with a timeout
    --    // every so often to be careful.
    --    void deferToPendingTransaction() {
    --        if (mDeferTransactionUntilFrame < 0) {
    --            return;
    --        }
    --        long time = System.currentTimeMillis();
    --        if (time > mDeferTransactionTime + PENDING_TRANSACTION_FINISH_WAIT_TIME) {
    --            mDeferTransactionTime = -1;
    --            mDeferTransactionUntilFrame = -1;
    --        } else if (mWin.mAttachedWindow != null &&
    --                mWin.mAttachedWindow.mWinAnimator.hasSurface()) {
    --            mSurfaceController.deferTransactionUntil(
    --                    mWin.mAttachedWindow.mWinAnimator.mSurfaceController.getHandle(),
    --                    mDeferTransactionUntilFrame);
    --        }
    --    }
    --
    -     /**
    -      * Sometimes we need to synchronize the first frame of animation with some external event.
    -      * To achieve this, we prolong the start of the animation and keep producing the first frame of
    -@@ -2128,24 +2102,8 @@ class WindowStateAnimator {
    -         // Compute a transform matrix to undo the coordinate space transformation,
    -         // and present the window at the same physical position it previously occupied.
    -         final int deltaRotation = DisplayContent.deltaRotation(newRotation, oldRotation);
    --        switch (deltaRotation) {
    --        case Surface.ROTATION_0:
    --            transform.reset();
    --            break;
    --        case Surface.ROTATION_270:
    --            transform.setRotate(270, 0, 0);
    --            transform.postTranslate(0, displayHeight);
    --            transform.postTranslate(y, 0);
    --            break;
    --        case Surface.ROTATION_180:
    --            transform.reset();
    --            break;
    --        case Surface.ROTATION_90:
    --            transform.setRotate(90, 0, 0);
    --            transform.postTranslate(displayWidth, 0);
    --            transform.postTranslate(-y, x);
    --            break;
    --        }
    -+        DisplayContent.createRotationMatrix(deltaRotation, x, y, displayWidth, displayHeight,
    -+                transform);
    - 
    -         // We have two cases:
    -         //  1. Windows with NATIVE_WINDOW_TRANSFORM_INVERSE_DISPLAY:
    -@@ -2182,7 +2140,7 @@ class WindowStateAnimator {
    -             cropRect.set(0, 0, w.mRequestedWidth, w.mRequestedWidth + w.mRequestedHeight);
    -             mSurfaceController.setCropInTransaction(cropRect, false);
    -         } else {
    --            w.mSeamlesslyRotated = true;
    -+            mService.markForSeamlessRotation(w, true);
    -             transform.getValues(mService.mTmpFloats);
    - 
    -             float DsDx = mService.mTmpFloats[Matrix.MSCALE_X];
    -diff --git a/services/core/java/com/android/server/wm/WindowSurfaceController.java b/services/core/java/com/android/server/wm/WindowSurfaceController.java
    -index c77e572..f5ed9d1 100644
    ---- a/services/core/java/com/android/server/wm/WindowSurfaceController.java
    -+++ b/services/core/java/com/android/server/wm/WindowSurfaceController.java
    -@@ -153,9 +153,9 @@ class WindowSurfaceController {
    -     }
    - 
    -     void destroyInTransaction() {
    --        //        if (SHOW_TRANSACTIONS || SHOW_SURFACE_ALLOC) {
    --        Slog.i(TAG, "Destroying surface " + this + " called by " + Debug.getCallers(8));
    --        //        }
    -+        if (SHOW_TRANSACTIONS || SHOW_SURFACE_ALLOC) {
    -+            Slog.i(TAG, "Destroying surface " + this + " called by " + Debug.getCallers(8));
    -+        }
    -         try {
    -             if (mSurfaceControl != null) {
    -                 mSurfaceControl.destroy();
    -diff --git a/services/core/java/com/android/server/wm/WindowSurfacePlacer.java b/services/core/java/com/android/server/wm/WindowSurfacePlacer.java
    -index fa5e3ca..eba52f9 100644
    ---- a/services/core/java/com/android/server/wm/WindowSurfacePlacer.java
    -+++ b/services/core/java/com/android/server/wm/WindowSurfacePlacer.java
    -@@ -101,6 +101,10 @@ class WindowSurfacePlacer {
    -     static final int SET_WALLPAPER_ACTION_PENDING       = 1 << 5;
    - 
    -     boolean mWallpaperMayChange = false;
    -+    // During an orientation change, we track whether all windows have rendered
    -+    // at the new orientation, and this will be false from changing orientation until that occurs.
    -+    // For seamless rotation cases this always stays true, as the windows complete their orientation
    -+    // changes 1 by 1 without disturbing global state.
    -     boolean mOrientationChangeComplete = true;
    -     boolean mWallpaperActionPending = false;
    - 
    -@@ -717,11 +721,13 @@ class WindowSurfacePlacer {
    -                     final boolean adjustedForMinimizedDockOrIme = task != null
    -                                 && (task.mStack.isAdjustedForMinimizedDockedStack()
    -                                     || task.mStack.isAdjustedForIme());
    --                    if ((w.mAttrs.privateFlags & PRIVATE_FLAG_NO_MOVE_ANIMATION) == 0
    --                            && !w.isDragResizing() && !adjustedForMinimizedDockOrIme
    --                            && (task == null || w.getTask().mStack.hasMovementAnimations())
    --                            && !w.mWinAnimator.mLastHidden) {
    --                        winAnimator.setMoveAnimation(left, top);
    -+                    if (mService.okToDisplay()) {
    -+                        if ((w.mAttrs.privateFlags & PRIVATE_FLAG_NO_MOVE_ANIMATION) == 0
    -+                                && !w.isDragResizing() && !adjustedForMinimizedDockOrIme
    -+                                && (task == null || w.getTask().mStack.hasMovementAnimations())
    -+                                && !w.mWinAnimator.mLastHidden) {
    -+                            winAnimator.setMoveAnimation(left, top);
    -+                        }
    -                     }
    - 
    -                     //TODO (multidisplay): Accessibility supported only for the default display.
    -@@ -742,10 +748,6 @@ class WindowSurfacePlacer {
    - 
    -                 // Moved from updateWindowsAndWallpaperLocked().
    -                 if (w.mHasSurface) {
    --                    // If we have recently synchronized a previous transaction for this
    --                    // window ensure we don't push through an unsynchronized one now.
    --                    winAnimator.deferToPendingTransaction();
    --
    -                     // Take care of the window being ready to display.
    -                     final boolean committed = winAnimator.commitFinishDrawingLocked();
    -                     if (isDefaultDisplay && committed) {
    -@@ -1357,8 +1359,25 @@ class WindowSurfacePlacer {
    -                 "Checking " + appsCount + " opening apps (frozen="
    -                         + mService.mDisplayFrozen + " timeout="
    -                         + mService.mAppTransition.isTimeout() + ")...");
    -+        final ScreenRotationAnimation screenRotationAnimation =
    -+            mService.mAnimator.getScreenRotationAnimationLocked(
    -+                    Display.DEFAULT_DISPLAY);
    -+
    -         int reason = APP_TRANSITION_TIMEOUT;
    -         if (!mService.mAppTransition.isTimeout()) {
    -+            // Imagine the case where we are changing orientation due to an app transition, but a previous
    -+            // orientation change is still in progress. We won't process the orientation change
    -+            // for our transition because we need to wait for the rotation animation to finish.
    -+            // If we start the app transition at this point, we will interrupt it halfway with a new rotation
    -+            // animation after the old one finally finishes. It's better to defer the
    -+            // app transition.
    -+            if (screenRotationAnimation != null && screenRotationAnimation.isAnimating() &&
    -+                    mService.rotationNeedsUpdateLocked()) {
    -+                if (DEBUG_APP_TRANSITIONS) {
    -+                    Slog.v(TAG, "Delaying app transition for screen rotation animation to finish");
    -+                }
    -+                return false;
    -+            }
    -             for (int i = 0; i < appsCount; i++) {
    -                 AppWindowToken wtoken = mService.mOpeningApps.valueAt(i);
    -                 if (DEBUG_APP_TRANSITIONS) Slog.v(TAG,
    -diff --git a/services/core/jni/com_android_server_location_GnssLocationProvider.cpp b/services/core/jni/com_android_server_location_GnssLocationProvider.cpp
    -index e8d4c58..25e819c 100644
    ---- a/services/core/jni/com_android_server_location_GnssLocationProvider.cpp
    -+++ b/services/core/jni/com_android_server_location_GnssLocationProvider.cpp
    -@@ -1087,6 +1087,7 @@ void JavaObject::callSetter(
    -             method_name,
    -             "([B)V");
    -     env_->CallVoidMethod(object_, method, array);
    -+    env_->DeleteLocalRef(array);
    - }
    - 
    - jobject JavaObject::get() {
    -diff --git a/services/core/proto/ipconnectivity.proto b/services/core/proto/ipconnectivity.proto
    -new file mode 100644
    -index 0000000..e0d7f09
    ---- /dev/null
    -+++ b/services/core/proto/ipconnectivity.proto
    -@@ -0,0 +1,274 @@
    -+// LINT: LEGACY_NAMES
    -+syntax = "proto2";
    -+
    -+package clearcut.connectivity;
    -+
    -+option java_package = "com.android.server.connectivity.metrics";
    -+option java_outer_classname = "IpConnectivityLogClass";
    -+
    -+// NetworkId represents the id given by the system to a physical network on the
    -+// Android device. It is used to relates events to each other for devices with
    -+// multiple networks (WiFi, 4G, ...).
    -+message NetworkId {
    -+  // Every network gets assigned a network_id on creation based on order of
    -+  // creation. Thus network_id N is assigned to the network created directly
    -+  // after network N-1. Thus there is no PII involved here. Zero means no
    -+  // network. The value 0 is never assigned to a network.
    -+  optional int32 network_id = 1;
    -+};
    -+
    -+// Logs changes in the system default network. Changes can be 1) acquiring a
    -+// default network with no previous default, 2) a switch of the system default
    -+// network to a new default network, 3) a loss of the system default network.
    -+// This message is associated to android.net.metrics.DefaultNetworkEvent.
    -+message DefaultNetworkEvent {
    -+  // A value of 0 means this is a loss of the system default network.
    -+  optional NetworkId network_id = 1;
    -+
    -+  // A value of 0 means there was no previous default network.
    -+  optional NetworkId previous_network_id = 2;
    -+
    -+  // Whether the network supports IPv4, IPv6, or both.
    -+  enum IPSupport {
    -+    NONE = 0;
    -+    IPV4 = 1;
    -+    IPV6 = 2;
    -+    DUAL = 3;
    -+  };
    -+
    -+  // Best available information about IP support of the previous network when
    -+  // disconnecting or switching to a new default network.
    -+  optional IPSupport previous_network_ip_support = 3;
    -+
    -+  // The transport types of the new default network, represented by
    -+  // TRANSPORT_* constants as defined in NetworkCapabilities.
    -+  repeated int32 transport_types = 4;
    -+};
    -+
    -+// Logs IpReachabilityMonitor probe events and NUD_FAILED events.
    -+// This message is associated to android.net.metrics.IpReachabilityEvent.
    -+message IpReachabilityEvent {
    -+  // The interface name (wlan, rmnet, lo, ...) on which the probe was sent.
    -+  optional string if_name = 1;
    -+
    -+  // The event type code of the probe, represented by constants defined in
    -+  // android.net.metrics.IpReachabilityEvent.
    -+  optional int32 event_type = 2;
    -+};
    -+
    -+// Logs NetworkMonitor and ConnectivityService events related to the state of
    -+// a network: connection, evaluation, validation, lingering, and disconnection.
    -+// This message is associated to android.net.metrics.NetworkEvent.
    -+message NetworkEvent {
    -+  // The id of the network on which this event happened.
    -+  optional NetworkId network_id = 1;
    -+
    -+  // The type of network event, represented by NETWORK_* constants defined in
    -+  // android.net.metrics.NetworkEvent.
    -+  optional int32 event_type = 2;
    -+
    -+  // Only valid after finishing evaluating a network for Internet connectivity.
    -+  // The time it took for this evaluation to complete.
    -+  optional int32 latency_ms = 3;
    -+}
    -+
    -+// Logs individual captive portal probing events that are performed when
    -+// evaluating or reevaluating networks for Internet connectivity.
    -+// This message is associated to android.net.metrics.ValidationProbeEvent.
    -+message ValidationProbeEvent {
    -+  // The id of the network for which the probe was sent.
    -+  optional NetworkId network_id = 1;
    -+
    -+  // The time it took for that probe to complete or time out.
    -+  optional int32 latency_ms = 2;
    -+
    -+  // The type of portal probe, represented by PROBE_* constants defined in
    -+  // android.net.metrics.ValidationProbeEvent.
    -+  optional int32 probe_type = 3;
    -+
    -+  // The http code result of the probe test.
    -+  optional int32 probe_result = 4;
    -+}
    -+
    -+// Logs DNS lookup latencies. Repeated fields must have the same length.
    -+// This message is associated to android.net.metrics.DnsEvent.
    -+message DNSLookupBatch {
    -+  // The id of the network on which the DNS lookups took place.
    -+  optional NetworkId network_id = 1;
    -+
    -+  // The types of the DNS lookups, as defined in android.net.metrics.DnsEvent.
    -+  repeated int32 event_types = 2;
    -+
    -+  // The return values of the DNS resolver for each DNS lookups.
    -+  repeated int32 return_codes = 3;
    -+
    -+  // The time it took for each DNS lookups to complete.
    -+  repeated int32 latencies_ms = 4;
    -+};
    -+
    -+// Represents a DHCP event on a single interface, which can be a DHCPClient
    -+// state transition or a response packet parsing error.
    -+// This message is associated to android.net.metrics.DhcpClientEvent and
    -+// android.net.metrics.DhcpErrorEvent.
    -+message DHCPEvent {
    -+  // The interface name (wlan, rmnet, lo, ...) on which the event happened.
    -+  optional string if_name = 1;
    -+
    -+  oneof value {
    -+    // The name of a state in the DhcpClient state machine, represented by
    -+    // the inner classes of android.net.dhcp.DhcpClient.
    -+    string state_transition = 2;
    -+
    -+    // The error code of a DHCP error, represented by constants defined in
    -+    // android.net.metrics.DhcpErrorEvent.
    -+    int32 error_code = 3;
    -+  }
    -+
    -+  // Lifetime duration in milliseconds of a DhcpClient state, or transition
    -+  // time in milliseconds between specific pairs of DhcpClient's states.
    -+  // Only populated when state_transition is populated.
    -+  optional int32 duration_ms = 4;
    -+}
    -+
    -+// Represents the generation of an Android Packet Filter program.
    -+message ApfProgramEvent {
    -+  // Lifetime of the program in seconds.
    -+  optional int64 lifetime = 1;
    -+
    -+  // Number of RAs filtered by the APF program.
    -+  optional int32 filtered_ras = 2;
    -+
    -+  // Total number of RAs to filter currently tracked by ApfFilter. Can be more
    -+  // than filtered_ras if all available program size was exhausted.
    -+  optional int32 current_ras = 3;
    -+
    -+  // Length of the APF program in bytes.
    -+  optional int32 program_length = 4;
    -+
    -+  // True if the APF program is dropping multicast and broadcast traffic.
    -+  optional bool drop_multicast = 5;
    -+
    -+  // True if the interface on which APF runs has an IPv4 address.
    -+  optional bool has_ipv4_addr = 6;
    -+}
    -+
    -+// Represents Router Advertisement listening statistics for an interface with
    -+// Android Packet Filter enabled.
    -+message ApfStatistics {
    -+  // The time interval in milliseconds these stastistics cover.
    -+  optional int64 duration_ms = 1;
    -+
    -+  // The total number of received RAs.
    -+  optional int32 received_ras = 2;
    -+
    -+  // The total number of received RAs that matched a known RA.
    -+  optional int32 matching_ras = 3;
    -+
    -+  // The total number of received RAs ignored due to the MAX_RAS limit.
    -+  optional int32 dropped_ras = 5;
    -+
    -+  // The total number of received RAs with an effective lifetime of 0 seconds.
    -+  // Effective lifetime for APF is the minimum of all lifetimes in a RA.
    -+  optional int32 zero_lifetime_ras = 6;
    -+
    -+  // The total number of received RAs that could not be parsed.
    -+  optional int32 parse_errors = 7;
    -+
    -+  // The total number of APF program updates triggered by an RA reception.
    -+  optional int32 program_updates = 8;
    -+
    -+  // The maximum APF program size in byte advertised by hardware.
    -+  optional int32 max_program_size = 9;
    -+}
    -+
    -+// Represents the reception of a Router Advertisement packet for an interface
    -+// with Android Packet Filter enabled.
    -+message RaEvent {
    -+  // All lifetime values are expressed in seconds. The default value for an
    -+  // option lifetime that was not present in the RA option list is -1.
    -+  // The lifetime of an option (e.g., the Prefix Information Option) is the
    -+  // minimum lifetime of all such options in the packet.
    -+
    -+  // The value of the router lifetime in the RA packet.
    -+  optional int64 router_lifetime = 1;
    -+
    -+  // Prefix valid lifetime from the prefix information option.
    -+  optional int64 prefix_valid_lifetime = 2;
    -+
    -+  // Prefix preferred lifetime from the prefix information option.
    -+  optional int64 prefix_preferred_lifetime = 3;
    -+
    -+  // Route info lifetime.
    -+  optional int64 route_info_lifetime = 4;
    -+
    -+  // Recursive DNS server lifetime.
    -+  optional int64 rdnss_lifetime = 5;
    -+
    -+  // DNS search list lifetime.
    -+  optional int64 dnssl_lifetime = 6;
    -+}
    -+
    -+// Represents an IP provisioning event in IpManager and how long the
    -+// provisioning action took.
    -+// This message is associated to android.net.metrics.IpManagerEvent.
    -+message IpProvisioningEvent {
    -+  // The interface name (wlan, rmnet, lo, ...) on which the probe was sent.
    -+  optional string if_name = 1;
    -+
    -+  // The code of the IP provisioning event, represented by constants defined in
    -+  // android.net.metrics.IpManagerEvent.
    -+  optional int32 event_type = 2;
    -+
    -+  // The duration of the provisioning action that resulted in this event.
    -+  optional int32 latency_ms = 3;
    -+}
    -+
    -+// Represents one of the IP connectivity event defined in this file.
    -+// Next tag: 12
    -+message IpConnectivityEvent {
    -+  // Time in ms when the event was recorded.
    -+  optional int64 time_ms = 1;
    -+
    -+  // Event type.
    -+  oneof event {
    -+
    -+    // An event about the system default network.
    -+    DefaultNetworkEvent default_network_event = 2;
    -+
    -+    // An IP reachability probe event.
    -+    IpReachabilityEvent ip_reachability_event = 3;
    -+
    -+    // A network lifecycle event.
    -+    NetworkEvent network_event = 4;
    -+
    -+    // A batch of DNS lookups.
    -+    DNSLookupBatch dns_lookup_batch = 5;
    -+
    -+    // A DHCP client event or DHCP receive error.
    -+    DHCPEvent dhcp_event = 6;
    -+
    -+    // An IP provisioning event.
    -+    IpProvisioningEvent ip_provisioning_event = 7;
    -+
    -+    // A network validation probe event.
    -+    ValidationProbeEvent validation_probe_event = 8;
    -+
    -+    // An Android Packet Filter program event.
    -+    ApfProgramEvent apf_program_event = 9;
    -+
    -+    // An Android Packet Filter statistics event.
    -+    ApfStatistics apf_statistics = 10;
    -+
    -+    // An RA packet reception event.
    -+    RaEvent ra_event = 11;
    -+  };
    -+};
    -+
    -+// The information about IP connectivity events.
    -+message IpConnectivityLog {
    -+  // An array of IP connectivity events.
    -+  repeated IpConnectivityEvent events = 1;
    -+
    -+  // The number of events that had to be dropped due to a full buffer.
    -+  optional int32 dropped_events = 2;
    -+};
    -diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
    -index c75b8c2..92aa1b9 100644
    ---- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
    -+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
    -@@ -29,6 +29,7 @@ import static org.xmlpull.v1.XmlPullParser.TEXT;
    - 
    - import android.Manifest.permission;
    - import android.accessibilityservice.AccessibilityServiceInfo;
    -+import android.accounts.Account;
    - import android.accounts.AccountManager;
    - import android.annotation.IntDef;
    - import android.annotation.NonNull;
    -@@ -308,6 +309,12 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
    - 
    -     private static final int DEVICE_ADMIN_DEACTIVATE_TIMEOUT = 10000;
    - 
    -+    /**
    -+     * Minimum timeout in milliseconds after which unlocking with weak auth times out,
    -+     * i.e. the user has to use a strong authentication method like password, PIN or pattern.
    -+     */
    -+    private static final long MINIMUM_STRONG_AUTH_TIMEOUT_MS = 1 * 60 * 60 * 1000; // 1h
    -+
    -     final Context mContext;
    -     final Injector mInjector;
    -     final IPackageManager mIPackageManager;
    -@@ -496,9 +503,9 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
    -                 new MonitoringCertNotificationTask().execute(userId);
    -             }
    -             if (Intent.ACTION_USER_ADDED.equals(action)) {
    --                disableSecurityLoggingIfNotCompliant();
    -+                disableDeviceOwnerManagedSingleUserFeaturesIfNeeded();
    -             } else if (Intent.ACTION_USER_REMOVED.equals(action)) {
    --                disableSecurityLoggingIfNotCompliant();
    -+                disableDeviceOwnerManagedSingleUserFeaturesIfNeeded();
    -                 removeUserData(userHandle);
    -             } else if (Intent.ACTION_USER_STARTED.equals(action)) {
    -                 synchronized (DevicePolicyManagerService.this) {
    -@@ -524,6 +531,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
    - 
    -     static class ActiveAdmin {
    -         private static final String TAG_DISABLE_KEYGUARD_FEATURES = "disable-keyguard-features";
    -+        private static final String TAG_TEST_ONLY_ADMIN = "test-only-admin";
    -         private static final String TAG_DISABLE_CAMERA = "disable-camera";
    -         private static final String TAG_DISABLE_CALLER_ID = "disable-caller-id";
    -         private static final String TAG_DISABLE_CONTACTS_SEARCH = "disable-contacts-search";
    -@@ -548,6 +556,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
    -         private static final String TAG_PERMITTED_IMES = "permitted-imes";
    -         private static final String TAG_MAX_FAILED_PASSWORD_WIPE = "max-failed-password-wipe";
    -         private static final String TAG_MAX_TIME_TO_UNLOCK = "max-time-to-unlock";
    -+        private static final String TAG_STRONG_AUTH_UNLOCK_TIMEOUT = "strong-auth-unlock-timeout";
    -         private static final String TAG_MIN_PASSWORD_NONLETTER = "min-password-nonletter";
    -         private static final String TAG_MIN_PASSWORD_SYMBOLS = "min-password-symbols";
    -         private static final String TAG_MIN_PASSWORD_NUMERIC = "min-password-numeric";
    -@@ -602,6 +611,8 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
    -         static final long DEF_MAXIMUM_TIME_TO_UNLOCK = 0;
    -         long maximumTimeToUnlock = DEF_MAXIMUM_TIME_TO_UNLOCK;
    - 
    -+        long strongAuthUnlockTimeout = 0; // admin doesn't participate by default
    -+
    -         static final int DEF_MAXIMUM_FAILED_PASSWORDS_FOR_WIPE = 0;
    -         int maximumFailedPasswordsForWipe = DEF_MAXIMUM_FAILED_PASSWORDS_FOR_WIPE;
    - 
    -@@ -616,6 +627,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
    -         int disabledKeyguardFeatures = DEF_KEYGUARD_FEATURES_DISABLED;
    - 
    -         boolean encryptionRequested = false;
    -+        boolean testOnlyAdmin = false;
    -         boolean disableCamera = false;
    -         boolean disableCallerId = false;
    -         boolean disableContactsSearch = false;
    -@@ -750,6 +762,11 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
    -                 out.attribute(null, ATTR_VALUE, Long.toString(maximumTimeToUnlock));
    -                 out.endTag(null, TAG_MAX_TIME_TO_UNLOCK);
    -             }
    -+            if (strongAuthUnlockTimeout != DevicePolicyManager.DEFAULT_STRONG_AUTH_TIMEOUT_MS) {
    -+                out.startTag(null, TAG_STRONG_AUTH_UNLOCK_TIMEOUT);
    -+                out.attribute(null, ATTR_VALUE, Long.toString(strongAuthUnlockTimeout));
    -+                out.endTag(null, TAG_STRONG_AUTH_UNLOCK_TIMEOUT);
    -+            }
    -             if (maximumFailedPasswordsForWipe != DEF_MAXIMUM_FAILED_PASSWORDS_FOR_WIPE) {
    -                 out.startTag(null, TAG_MAX_FAILED_PASSWORD_WIPE);
    -                 out.attribute(null, ATTR_VALUE, Integer.toString(maximumFailedPasswordsForWipe));
    -@@ -785,6 +802,11 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
    -                 out.attribute(null, ATTR_VALUE, Boolean.toString(encryptionRequested));
    -                 out.endTag(null, TAG_ENCRYPTION_REQUESTED);
    -             }
    -+            if (testOnlyAdmin) {
    -+                out.startTag(null, TAG_TEST_ONLY_ADMIN);
    -+                out.attribute(null, ATTR_VALUE, Boolean.toString(testOnlyAdmin));
    -+                out.endTag(null, TAG_TEST_ONLY_ADMIN);
    -+            }
    -             if (disableCamera) {
    -                 out.startTag(null, TAG_DISABLE_CAMERA);
    -                 out.attribute(null, ATTR_VALUE, Boolean.toString(disableCamera));
    -@@ -959,6 +981,9 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
    -                 } else if (TAG_MAX_TIME_TO_UNLOCK.equals(tag)) {
    -                     maximumTimeToUnlock = Long.parseLong(
    -                             parser.getAttributeValue(null, ATTR_VALUE));
    -+                } else if (TAG_STRONG_AUTH_UNLOCK_TIMEOUT.equals(tag)) {
    -+                    strongAuthUnlockTimeout = Long.parseLong(
    -+                            parser.getAttributeValue(null, ATTR_VALUE));
    -                 } else if (TAG_MAX_FAILED_PASSWORD_WIPE.equals(tag)) {
    -                     maximumFailedPasswordsForWipe = Integer.parseInt(
    -                             parser.getAttributeValue(null, ATTR_VALUE));
    -@@ -980,6 +1005,9 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
    -                 } else if (TAG_ENCRYPTION_REQUESTED.equals(tag)) {
    -                     encryptionRequested = Boolean.parseBoolean(
    -                             parser.getAttributeValue(null, ATTR_VALUE));
    -+                } else if (TAG_TEST_ONLY_ADMIN.equals(tag)) {
    -+                    testOnlyAdmin = Boolean.parseBoolean(
    -+                            parser.getAttributeValue(null, ATTR_VALUE));
    -                 } else if (TAG_DISABLE_CAMERA.equals(tag)) {
    -                     disableCamera = Boolean.parseBoolean(
    -                             parser.getAttributeValue(null, ATTR_VALUE));
    -@@ -1178,6 +1206,8 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
    - 
    -         void dump(String prefix, PrintWriter pw) {
    -             pw.print(prefix); pw.print("uid="); pw.println(getUid());
    -+            pw.print(prefix); pw.print("testOnlyAdmin=");
    -+            pw.println(testOnlyAdmin);
    -             pw.print(prefix); pw.println("policies:");
    -             ArrayList<DeviceAdminInfo.PolicyInfo> pols = info.getUsedPolicies();
    -             if (pols != null) {
    -@@ -1205,6 +1235,8 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
    -                     pw.println(minimumPasswordNonLetter);
    -             pw.print(prefix); pw.print("maximumTimeToUnlock=");
    -                     pw.println(maximumTimeToUnlock);
    -+            pw.print(prefix); pw.print("strongAuthUnlockTimeout=");
    -+                    pw.println(strongAuthUnlockTimeout);
    -             pw.print(prefix); pw.print("maximumFailedPasswordsForWipe=");
    -                     pw.println(maximumFailedPasswordsForWipe);
    -             pw.print(prefix); pw.print("specifiesGlobalProxy=");
    -@@ -1699,7 +1731,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
    -             if (mOwners.hasDeviceOwner()) {
    -                 mInjector.systemPropertiesSet(PROPERTY_DEVICE_OWNER_PRESENT, "true");
    -                 Slog.i(LOG_TAG, "Set ro.device_owner property to true");
    --                disableSecurityLoggingIfNotCompliant();
    -+                disableDeviceOwnerManagedSingleUserFeaturesIfNeeded();
    -                 if (mInjector.securityLogGetLoggingEnabledProperty()) {
    -                     mSecurityLogMonitor.start();
    -                 }
    -@@ -2828,8 +2860,9 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
    -         synchronized (this) {
    -             long ident = mInjector.binderClearCallingIdentity();
    -             try {
    --                if (!refreshing
    --                        && getActiveAdminUncheckedLocked(adminReceiver, userHandle) != null) {
    -+                final ActiveAdmin existingAdmin
    -+                        = getActiveAdminUncheckedLocked(adminReceiver, userHandle);
    -+                if (!refreshing && existingAdmin != null) {
    -                     throw new IllegalArgumentException("Admin is already added");
    -                 }
    -                 if (policy.mRemovingAdmins.contains(adminReceiver)) {
    -@@ -2837,6 +2870,9 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
    -                             "Trying to set an admin which is being removed");
    -                 }
    -                 ActiveAdmin newAdmin = new ActiveAdmin(info, /* parent */ false);
    -+                newAdmin.testOnlyAdmin =
    -+                        (existingAdmin != null) ? existingAdmin.testOnlyAdmin
    -+                                : isPackageTestOnly(adminReceiver.getPackageName(), userHandle);
    -                 policy.mAdminMap.put(adminReceiver, newAdmin);
    -                 int replaceIndex = -1;
    -                 final int N = policy.mAdminList.size();
    -@@ -2948,23 +2984,13 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
    -         enforceShell("forceRemoveActiveAdmin");
    -         long ident = mInjector.binderClearCallingIdentity();
    -         try {
    --            final ApplicationInfo ai;
    --            try {
    --                ai = mIPackageManager.getApplicationInfo(adminReceiver.getPackageName(),
    --                        0, userHandle);
    --            } catch (RemoteException e) {
    --                throw new IllegalStateException(e);
    --            }
    --            if (ai == null) {
    --                throw new IllegalStateException("Couldn't find package to remove admin "
    --                        + adminReceiver.getPackageName() + " " + userHandle);
    --            }
    --            if ((ai.flags & ApplicationInfo.FLAG_TEST_ONLY) == 0) {
    --                throw new SecurityException("Attempt to remove non-test admin " + adminReceiver
    --                        + adminReceiver + " " + userHandle);
    --            }
    --            // If admin is a device or profile owner tidy that up first.
    -             synchronized (this)  {
    -+                if (!isAdminTestOnlyLocked(adminReceiver, userHandle)) {
    -+                    throw new SecurityException("Attempt to remove non-test admin "
    -+                            + adminReceiver + " " + userHandle);
    -+                }
    -+
    -+                // If admin is a device or profile owner tidy that up first.
    -                 if (isDeviceOwner(adminReceiver, userHandle)) {
    -                     clearDeviceOwnerLocked(getDeviceOwnerAdminLocked(), userHandle);
    -                 }
    -@@ -2976,11 +3002,47 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
    -             }
    -             // Remove the admin skipping sending the broadcast.
    -             removeAdminArtifacts(adminReceiver, userHandle);
    -+            Slog.i(LOG_TAG, "Admin " + adminReceiver + " removed from user " + userHandle);
    -         } finally {
    -             mInjector.binderRestoreCallingIdentity(ident);
    -         }
    -     }
    - 
    -+    /**
    -+     * Return if a given package has testOnly="true", in which case we'll relax certain rules
    -+     * for CTS.
    -+     *
    -+     * DO NOT use this method except in {@link #setActiveAdmin}.  Use {@link #isAdminTestOnlyLocked}
    -+     * to check wehter an active admin is test-only or not.
    -+     *
    -+     * The system allows this flag to be changed when an app is updated, which is not good
    -+     * for us.  So we persist the flag in {@link ActiveAdmin} when an admin is first installed,
    -+     * and used the persisted version in actual checks. (See b/31382361 and b/28928996)
    -+     */
    -+    private boolean isPackageTestOnly(String packageName, int userHandle) {
    -+        final ApplicationInfo ai;
    -+        try {
    -+            ai = mIPackageManager.getApplicationInfo(packageName,
    -+                    (PackageManager.MATCH_DIRECT_BOOT_AWARE
    -+                            | PackageManager.MATCH_DIRECT_BOOT_UNAWARE), userHandle);
    -+        } catch (RemoteException e) {
    -+            throw new IllegalStateException(e);
    -+        }
    -+        if (ai == null) {
    -+            throw new IllegalStateException("Couldn't find package: "
    -+                    + packageName + " on user " + userHandle);
    -+        }
    -+        return (ai.flags & ApplicationInfo.FLAG_TEST_ONLY) != 0;
    -+    }
    -+
    -+    /**
    -+     * See {@link #isPackageTestOnly}.
    -+     */
    -+    private boolean isAdminTestOnlyLocked(ComponentName who, int userHandle) {
    -+        final ActiveAdmin admin = getActiveAdminUncheckedLocked(who, userHandle);
    -+        return (admin != null) && admin.testOnlyAdmin;
    -+    }
    -+
    -     private void enforceShell(String method) {
    -         final int callingUid = Binder.getCallingUid();
    -         if (callingUid != Process.SHELL_UID && callingUid != Process.ROOT_UID) {
    -@@ -3678,12 +3740,16 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
    - 
    -     private boolean isActivePasswordSufficientForUserLocked(
    -             DevicePolicyData policy, int userHandle, boolean parent) {
    --        if (policy.mActivePasswordQuality < getPasswordQuality(null, userHandle, parent)
    --                || policy.mActivePasswordLength < getPasswordMinimumLength(
    -+        final int requiredPasswordQuality = getPasswordQuality(null, userHandle, parent);
    -+        if (policy.mActivePasswordQuality < requiredPasswordQuality) {
    -+            return false;
    -+        }
    -+        if (requiredPasswordQuality >= DevicePolicyManager.PASSWORD_QUALITY_NUMERIC
    -+                && policy.mActivePasswordLength < getPasswordMinimumLength(
    -                         null, userHandle, parent)) {
    -             return false;
    -         }
    --        if (policy.mActivePasswordQuality != DevicePolicyManager.PASSWORD_QUALITY_COMPLEX) {
    -+        if (requiredPasswordQuality != DevicePolicyManager.PASSWORD_QUALITY_COMPLEX) {
    -             return true;
    -         }
    -         return policy.mActivePasswordUpperCase >= getPasswordMinimumUpperCase(
    -@@ -4176,6 +4242,65 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
    -     }
    - 
    -     @Override
    -+    public void setRequiredStrongAuthTimeout(ComponentName who, long timeoutMs,
    -+            boolean parent) {
    -+        if (!mHasFeature) {
    -+            return;
    -+        }
    -+        Preconditions.checkNotNull(who, "ComponentName is null");
    -+        Preconditions.checkArgument(timeoutMs >= 0, "Timeout must not be a negative number.");
    -+        // timeoutMs with value 0 means that the admin doesn't participate
    -+        // timeoutMs is clamped to the interval in case the internal constants change in the future
    -+        if (timeoutMs != 0 && timeoutMs < MINIMUM_STRONG_AUTH_TIMEOUT_MS) {
    -+            timeoutMs = MINIMUM_STRONG_AUTH_TIMEOUT_MS;
    -+        }
    -+        if (timeoutMs > DevicePolicyManager.DEFAULT_STRONG_AUTH_TIMEOUT_MS) {
    -+            timeoutMs = DevicePolicyManager.DEFAULT_STRONG_AUTH_TIMEOUT_MS;
    -+        }
    -+
    -+        final int userHandle = mInjector.userHandleGetCallingUserId();
    -+        synchronized (this) {
    -+            ActiveAdmin ap = getActiveAdminForCallerLocked(who,
    -+                    DeviceAdminInfo.USES_POLICY_PROFILE_OWNER, parent);
    -+            if (ap.strongAuthUnlockTimeout != timeoutMs) {
    -+                ap.strongAuthUnlockTimeout = timeoutMs;
    -+                saveSettingsLocked(userHandle);
    -+            }
    -+        }
    -+    }
    -+
    -+    /**
    -+     * Return a single admin's strong auth unlock timeout or minimum value (strictest) of all
    -+     * admins if who is null.
    -+     * Returns 0 if not configured for the provided admin.
    -+     */
    -+    @Override
    -+    public long getRequiredStrongAuthTimeout(ComponentName who, int userId, boolean parent) {
    -+        if (!mHasFeature) {
    -+            return DevicePolicyManager.DEFAULT_STRONG_AUTH_TIMEOUT_MS;
    -+        }
    -+        enforceFullCrossUsersPermission(userId);
    -+        synchronized (this) {
    -+            if (who != null) {
    -+                ActiveAdmin admin = getActiveAdminUncheckedLocked(who, userId, parent);
    -+                return admin != null ? admin.strongAuthUnlockTimeout : 0;
    -+            }
    -+
    -+            // Return the strictest policy across all participating admins.
    -+            List<ActiveAdmin> admins = getActiveAdminsForLockscreenPoliciesLocked(userId, parent);
    -+
    -+            long strongAuthUnlockTimeout = DevicePolicyManager.DEFAULT_STRONG_AUTH_TIMEOUT_MS;
    -+            for (int i = 0; i < admins.size(); i++) {
    -+                final long timeout = admins.get(i).strongAuthUnlockTimeout;
    -+                if (timeout != 0) { // take only participating admins into account
    -+                    strongAuthUnlockTimeout = Math.min(timeout, strongAuthUnlockTimeout);
    -+                }
    -+            }
    -+            return Math.max(strongAuthUnlockTimeout, MINIMUM_STRONG_AUTH_TIMEOUT_MS);
    -+        }
    -+    }
    -+
    -+    @Override
    -     public void lockNow(boolean parent) {
    -         if (!mHasFeature) {
    -             return;
    -@@ -4517,7 +4642,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
    -      * not installed and therefore not available.
    -      *
    -      * @throws SecurityException if the caller is not a profile or device owner.
    --     * @throws UnsupportedException if the package does not support being set as always-on.
    -+     * @throws UnsupportedOperationException if the package does not support being set as always-on.
    -      */
    -     @Override
    -     public boolean setAlwaysOnVpnPackage(ComponentName admin, String vpnPackage, boolean lockdown)
    -@@ -5713,7 +5838,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
    -                     + " for device owner");
    -         }
    -         synchronized (this) {
    --            enforceCanSetDeviceOwnerLocked(userId);
    -+            enforceCanSetDeviceOwnerLocked(admin, userId);
    -             if (getActiveAdminUncheckedLocked(admin, userId) == null
    -                     || getUserData(userId).mRemovingAdmins.contains(admin)) {
    -                 throw new IllegalArgumentException("Not active admin: " + admin);
    -@@ -5745,6 +5870,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
    -             } finally {
    -                 mInjector.binderRestoreCallingIdentity(ident);
    -             }
    -+            Slog.i(LOG_TAG, "Device owner set: " + admin + " on user " + userId);
    -             return true;
    -         }
    -     }
    -@@ -5866,6 +5992,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
    -             } finally {
    -                 mInjector.binderRestoreCallingIdentity(ident);
    -             }
    -+            Slog.i(LOG_TAG, "Device owner removed: " + deviceOwnerComponent);
    -         }
    -     }
    - 
    -@@ -5881,7 +6008,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
    -         mOwners.clearDeviceOwner();
    -         mOwners.writeDeviceOwner();
    -         updateDeviceOwnerLocked();
    --        disableSecurityLoggingIfNotCompliant();
    -+        disableDeviceOwnerManagedSingleUserFeaturesIfNeeded();
    -         try {
    -             // Reactivate backup service.
    -             mInjector.getIBackupManager().setBackupServiceActive(UserHandle.USER_SYSTEM, true);
    -@@ -5901,7 +6028,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
    -                     + " not installed for userId:" + userHandle);
    -         }
    -         synchronized (this) {
    --            enforceCanSetProfileOwnerLocked(userHandle);
    -+            enforceCanSetProfileOwnerLocked(who, userHandle);
    - 
    -             if (getActiveAdminUncheckedLocked(who, userHandle) == null
    -                     || getUserData(userHandle).mRemovingAdmins.contains(who)) {
    -@@ -5910,6 +6037,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
    - 
    -             mOwners.setProfileOwner(who, ownerName, userHandle);
    -             mOwners.writeProfileOwner(userHandle);
    -+            Slog.i(LOG_TAG, "Profile owner set: " + who + " on user " + userHandle);
    -             return true;
    -         }
    -     }
    -@@ -5934,6 +6062,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
    -             } finally {
    -                 mInjector.binderRestoreCallingIdentity(ident);
    -             }
    -+            Slog.i(LOG_TAG, "Profile owner " + who + " removed from user " + userId);
    -         }
    -     }
    - 
    -@@ -6210,9 +6339,9 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
    -      * The profile owner can only be set before the user setup phase has completed,
    -      * except for:
    -      * - SYSTEM_UID
    --     * - adb if there are not accounts.
    -+     * - adb if there are no accounts. (But see {@link #hasIncompatibleAccountsLocked})
    -      */
    --    private void enforceCanSetProfileOwnerLocked(int userHandle) {
    -+    private void enforceCanSetProfileOwnerLocked(@Nullable ComponentName owner, int userHandle) {
    -         UserInfo info = getUserInfo(userHandle);
    -         if (info == null) {
    -             // User doesn't exist.
    -@@ -6232,8 +6361,8 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
    -         }
    -         int callingUid = mInjector.binderGetCallingUid();
    -         if (callingUid == Process.SHELL_UID || callingUid == Process.ROOT_UID) {
    --            if (hasUserSetupCompleted(userHandle) &&
    --                    AccountManager.get(mContext).getAccountsAsUser(userHandle).length > 0) {
    -+            if (hasUserSetupCompleted(userHandle)
    -+                    && hasIncompatibleAccountsLocked(userHandle, owner)) {
    -                 throw new IllegalStateException("Not allowed to set the profile owner because "
    -                         + "there are already some accounts on the profile");
    -             }
    -@@ -6250,14 +6379,14 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
    -      * The Device owner can only be set by adb or an app with the MANAGE_PROFILE_AND_DEVICE_OWNERS
    -      * permission.
    -      */
    --    private void enforceCanSetDeviceOwnerLocked(int userId) {
    -+    private void enforceCanSetDeviceOwnerLocked(@Nullable ComponentName owner, int userId) {
    -         int callingUid = mInjector.binderGetCallingUid();
    -         boolean isAdb = callingUid == Process.SHELL_UID || callingUid == Process.ROOT_UID;
    -         if (!isAdb) {
    -             enforceCanManageProfileAndDeviceOwners();
    -         }
    - 
    --        final int code = checkSetDeviceOwnerPreCondition(userId, isAdb);
    -+        final int code = checkSetDeviceOwnerPreConditionLocked(owner, userId, isAdb);
    -         switch (code) {
    -             case CODE_OK:
    -                 return;
    -@@ -8474,8 +8603,8 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
    -      * The device owner can only be set before the setup phase of the primary user has completed,
    -      * except for adb command if no accounts or additional users are present on the device.
    -      */
    --    private synchronized @DeviceOwnerPreConditionCode int checkSetDeviceOwnerPreCondition(
    --            int deviceOwnerUserId, boolean isAdb) {
    -+    private synchronized @DeviceOwnerPreConditionCode int checkSetDeviceOwnerPreConditionLocked(
    -+            @Nullable ComponentName owner, int deviceOwnerUserId, boolean isAdb) {
    -         if (mOwners.hasDeviceOwner()) {
    -             return CODE_HAS_DEVICE_OWNER;
    -         }
    -@@ -8492,7 +8621,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
    -                     if (mUserManager.getUserCount() > 1) {
    -                         return CODE_NONSYSTEM_USER_EXISTS;
    -                     }
    --                    if (AccountManager.get(mContext).getAccounts().length > 0) {
    -+                    if (hasIncompatibleAccountsLocked(UserHandle.USER_SYSTEM, owner)) {
    -                         return CODE_ACCOUNTS_NOT_EMPTY;
    -                     }
    -                 } else {
    -@@ -8518,7 +8647,10 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
    -     }
    - 
    -     private boolean isDeviceOwnerProvisioningAllowed(int deviceOwnerUserId) {
    --        return CODE_OK == checkSetDeviceOwnerPreCondition(deviceOwnerUserId, /* isAdb */ false);
    -+        synchronized (this) {
    -+            return CODE_OK == checkSetDeviceOwnerPreConditionLocked(
    -+                    /* owner unknown */ null, deviceOwnerUserId, /* isAdb */ false);
    -+        }
    -     }
    - 
    -     private boolean hasFeatureManagedUsers() {
    -@@ -8850,10 +8982,14 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
    -         return false;
    -     }
    - 
    --    private synchronized void disableSecurityLoggingIfNotCompliant() {
    -+    private synchronized void disableDeviceOwnerManagedSingleUserFeaturesIfNeeded() {
    -         if (!isDeviceOwnerManagedSingleUserDevice()) {
    -             mInjector.securityLogSetLoggingEnabledProperty(false);
    -             Slog.w(LOG_TAG, "Security logging turned off as it's no longer a single user device.");
    -+            if (mOwners.hasDeviceOwner()) {
    -+                setBackupServiceEnabledInternal(false);
    -+                Slog.w(LOG_TAG, "Backup is off as it's a managed device that has more that one user.");
    -+            }
    -         }
    -     }
    - 
    -@@ -9051,6 +9187,8 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
    -             saveSettingsLocked(userHandle);
    -             updateMaximumTimeToLockLocked(userHandle);
    -             policy.mRemovingAdmins.remove(adminReceiver);
    -+
    -+            Slog.i(LOG_TAG, "Device admin " + adminReceiver + " removed from user " + userHandle);
    -         }
    -         // The removed admin might have disabled camera, so update user
    -         // restrictions.
    -@@ -9075,4 +9213,123 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
    -             return policy.mDeviceProvisioningConfigApplied;
    -         }
    -     }
    -+
    -+    /**
    -+     * Return true if a given user has any accounts that'll prevent installing a device or profile
    -+     * owner {@code owner}.
    -+     * - If the user has no accounts, then return false.
    -+     * - Otherwise, if the owner is unknown (== null), or is not test-only, then return true.
    -+     * - Otherwise, if there's any account that does not have ..._ALLOWED, or does have
    -+     *   ..._DISALLOWED, return true.
    -+     * - Otherwise return false.
    -+     */
    -+    private boolean hasIncompatibleAccountsLocked(int userId, @Nullable ComponentName owner) {
    -+        final long token = mInjector.binderClearCallingIdentity();
    -+        try {
    -+            final AccountManager am = AccountManager.get(mContext);
    -+            final Account accounts[] = am.getAccountsAsUser(userId);
    -+            if (accounts.length == 0) {
    -+                return false;
    -+            }
    -+            final String[] feature_allow =
    -+                    { DevicePolicyManager.ACCOUNT_FEATURE_DEVICE_OR_PROFILE_OWNER_ALLOWED };
    -+            final String[] feature_disallow =
    -+                    { DevicePolicyManager.ACCOUNT_FEATURE_DEVICE_OR_PROFILE_OWNER_DISALLOWED };
    -+
    -+            // Even if we find incompatible accounts along the way, we still check all accounts
    -+            // for logging.
    -+            boolean compatible = true;
    -+            for (Account account : accounts) {
    -+                if (hasAccountFeatures(am, account, feature_disallow)) {
    -+                    Log.e(LOG_TAG, account + " has " + feature_disallow[0]);
    -+                    compatible = false;
    -+                }
    -+                if (!hasAccountFeatures(am, account, feature_allow)) {
    -+                    Log.e(LOG_TAG, account + " doesn't have " + feature_allow[0]);
    -+                    compatible = false;
    -+                }
    -+            }
    -+            if (compatible) {
    -+                Log.w(LOG_TAG, "All accounts are compatible");
    -+            } else {
    -+                Log.e(LOG_TAG, "Found incompatible accounts");
    -+            }
    -+
    -+            // Then check if the owner is test-only.
    -+            String log;
    -+            if (owner == null) {
    -+                // Owner is unknown.  Suppose it's not test-only
    -+                compatible = false;
    -+                log = "Only test-only device/profile owner can be installed with accounts";
    -+            } else if (isAdminTestOnlyLocked(owner, userId)) {
    -+                if (compatible) {
    -+                    log = "Installing test-only owner " + owner;
    -+                } else {
    -+                    log = "Can't install test-only owner " + owner + " with incompatible accounts";
    -+                }
    -+            } else {
    -+                compatible = false;
    -+                log = "Can't install non test-only owner " + owner + " with accounts";
    -+            }
    -+            if (compatible) {
    -+                Log.w(LOG_TAG, log);
    -+            } else {
    -+                Log.e(LOG_TAG, log);
    -+            }
    -+            return !compatible;
    -+        } finally {
    -+            mInjector.binderRestoreCallingIdentity(token);
    -+        }
    -+    }
    -+
    -+    private boolean hasAccountFeatures(AccountManager am, Account account, String[] features) {
    -+        try {
    -+            return am.hasFeatures(account, features, null, null).getResult();
    -+        } catch (Exception e) {
    -+            Log.w(LOG_TAG, "Failed to get account feature", e);
    -+            return false;
    -+        }
    -+    }
    -+
    -+    @Override
    -+    public void setBackupServiceEnabled(ComponentName admin, boolean enabled) {
    -+        Preconditions.checkNotNull(admin);
    -+        if (!mHasFeature) {
    -+            return;
    -+        }
    -+        ensureDeviceOwnerManagingSingleUser(admin);
    -+        setBackupServiceEnabledInternal(enabled);
    -+    }
    -+
    -+    private synchronized void setBackupServiceEnabledInternal(boolean enabled) {
    -+        long ident = mInjector.binderClearCallingIdentity();
    -+        try {
    -+            IBackupManager ibm = mInjector.getIBackupManager();
    -+            if (ibm != null) {
    -+                ibm.setBackupServiceActive(UserHandle.USER_SYSTEM, enabled);
    -+            }
    -+        } catch (RemoteException e) {
    -+            throw new IllegalStateException(
    -+                "Failed " + (enabled ? "" : "de") + "activating backup service.", e);
    -+        } finally {
    -+            mInjector.binderRestoreCallingIdentity(ident);
    -+        }
    -+    }
    -+
    -+    @Override
    -+    public boolean isBackupServiceEnabled(ComponentName admin) {
    -+        Preconditions.checkNotNull(admin);
    -+        if (!mHasFeature) {
    -+            return true;
    -+        }
    -+        synchronized (this) {
    -+            getActiveAdminForCallerLocked(admin, DeviceAdminInfo.USES_POLICY_DEVICE_OWNER);
    -+            try {
    -+                IBackupManager ibm = mInjector.getIBackupManager();
    -+                return ibm != null && ibm.isBackupServiceActive(UserHandle.USER_SYSTEM);
    -+            } catch (RemoteException e) {
    -+                throw new IllegalStateException("Failed requesting backup service state.", e);
    -+            }
    -+        }
    -+    }
    - }
    -diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
    -index 97a829e..7ebdd31 100644
    ---- a/services/java/com/android/server/SystemServer.java
    -+++ b/services/java/com/android/server/SystemServer.java
    -@@ -16,7 +16,6 @@
    - 
    - package com.android.server;
    - 
    --import android.app.ActivityManagerNative;
    - import android.app.ActivityThread;
    - import android.app.INotificationManager;
    - import android.app.usage.UsageStatsManagerInternal;
    -@@ -32,7 +31,6 @@ import android.os.Build;
    - import android.os.Environment;
    - import android.os.FactoryTest;
    - import android.os.FileUtils;
    --import android.os.IPowerManager;
    - import android.os.Looper;
    - import android.os.PowerManager;
    - import android.os.RemoteException;
    -@@ -55,17 +53,20 @@ import com.android.internal.app.NightDisplayController;
    - import com.android.internal.os.BinderInternal;
    - import com.android.internal.os.SamplingProfilerIntegration;
    - import com.android.internal.os.ZygoteInit;
    -+import com.android.internal.policy.EmergencyAffordanceManager;
    - import com.android.internal.widget.ILockSettings;
    - import com.android.server.accessibility.AccessibilityManagerService;
    - import com.android.server.am.ActivityManagerService;
    - import com.android.server.audio.AudioService;
    - import com.android.server.camera.CameraService;
    - import com.android.server.clipboard.ClipboardService;
    -+import com.android.server.connectivity.IpConnectivityMetrics;
    - import com.android.server.connectivity.MetricsLoggerService;
    - import com.android.server.devicepolicy.DevicePolicyManagerService;
    - import com.android.server.display.DisplayManagerService;
    - import com.android.server.display.NightDisplayService;
    - import com.android.server.dreams.DreamManagerService;
    -+import com.android.server.emergency.EmergencyAffordanceService;
    - import com.android.server.fingerprint.FingerprintService;
    - import com.android.server.hdmi.HdmiControlService;
    - import com.android.server.input.InputManagerService;
    -@@ -653,6 +654,10 @@ public final class SystemServer {
    -             mSystemServiceManager.startService(MetricsLoggerService.class);
    -             Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
    - 
    -+            traceBeginAndSlog("IpConnectivityMetrics");
    -+            mSystemServiceManager.startService(IpConnectivityMetrics.class);
    -+            Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
    -+
    -             traceBeginAndSlog("PinnerService");
    -             mSystemServiceManager.startService(PinnerService.class);
    -             Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
    -@@ -1080,6 +1085,11 @@ public final class SystemServer {
    -                 Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
    -             }
    - 
    -+            if (!disableNetwork && !disableNonCoreServices && EmergencyAffordanceManager.ENABLED) {
    -+                // EmergencyMode sevice
    -+                mSystemServiceManager.startService(EmergencyAffordanceService.class);
    -+            }
    -+
    -             if (!disableNonCoreServices) {
    -                 // Dreams (interactive idle-time views, a/k/a screen savers, and doze mode)
    -                 mSystemServiceManager.startService(DreamManagerService.class);
    -diff --git a/services/net/Android.mk b/services/net/Android.mk
    -index 336bc45..408794e 100644
    ---- a/services/net/Android.mk
    -+++ b/services/net/Android.mk
    -@@ -7,4 +7,7 @@ LOCAL_MODULE := services.net
    - LOCAL_SRC_FILES += \
    -     $(call all-java-files-under,java)
    - 
    -+LOCAL_AIDL_INCLUDES += \
    -+    system/netd/server/binder
    -+
    - include $(BUILD_STATIC_JAVA_LIBRARY)
    -diff --git a/services/net/java/android/net/apf/ApfFilter.java b/services/net/java/android/net/apf/ApfFilter.java
    -index 4bb0902..4c75452 100644
    ---- a/services/net/java/android/net/apf/ApfFilter.java
    -+++ b/services/net/java/android/net/apf/ApfFilter.java
    -@@ -19,6 +19,7 @@ package android.net.apf;
    - import static android.system.OsConstants.*;
    - 
    - import android.os.SystemClock;
    -+import android.net.LinkAddress;
    - import android.net.LinkProperties;
    - import android.net.NetworkUtils;
    - import android.net.apf.ApfGenerator;
    -@@ -44,6 +45,7 @@ import com.android.internal.util.IndentingPrintWriter;
    - import java.io.FileDescriptor;
    - import java.io.IOException;
    - import java.lang.Thread;
    -+import java.net.Inet4Address;
    - import java.net.Inet6Address;
    - import java.net.InetAddress;
    - import java.net.NetworkInterface;
    -@@ -171,8 +173,8 @@ public class ApfFilter {
    -     private static final int ETH_HEADER_LEN = 14;
    -     private static final int ETH_DEST_ADDR_OFFSET = 0;
    -     private static final int ETH_ETHERTYPE_OFFSET = 12;
    --    private static final byte[] ETH_BROADCAST_MAC_ADDRESS = new byte[]{
    --            (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff };
    -+    private static final byte[] ETH_BROADCAST_MAC_ADDRESS =
    -+            {(byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff };
    -     // TODO: Make these offsets relative to end of link-layer header; don't include ETH_HEADER_LEN.
    -     private static final int IPV4_FRAGMENT_OFFSET_OFFSET = ETH_HEADER_LEN + 6;
    -     // Endianness is not an issue for this constant because the APF interpreter always operates in
    -@@ -181,6 +183,7 @@ public class ApfFilter {
    -     private static final int IPV4_PROTOCOL_OFFSET = ETH_HEADER_LEN + 9;
    -     private static final int IPV4_DEST_ADDR_OFFSET = ETH_HEADER_LEN + 16;
    -     private static final int IPV4_ANY_HOST_ADDRESS = 0;
    -+    private static final int IPV4_BROADCAST_ADDRESS = -1; // 255.255.255.255
    - 
    -     private static final int IPV6_NEXT_HEADER_OFFSET = ETH_HEADER_LEN + 6;
    -     private static final int IPV6_SRC_ADDR_OFFSET = ETH_HEADER_LEN + 8;
    -@@ -188,7 +191,7 @@ public class ApfFilter {
    -     private static final int IPV6_HEADER_LEN = 40;
    -     // The IPv6 all nodes address ff02::1
    -     private static final byte[] IPV6_ALL_NODES_ADDRESS =
    --            new byte[]{ (byte) 0xff, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 };
    -+            { (byte) 0xff, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 };
    - 
    -     private static final int ICMP6_TYPE_OFFSET = ETH_HEADER_LEN + IPV6_HEADER_LEN;
    -     private static final int ICMP6_NEIGHBOR_ANNOUNCEMENT = 136;
    -@@ -206,7 +209,7 @@ public class ApfFilter {
    -     private static final int ARP_OPCODE_OFFSET = ARP_HEADER_OFFSET + 6;
    -     private static final short ARP_OPCODE_REQUEST = 1;
    -     private static final short ARP_OPCODE_REPLY = 2;
    --    private static final byte[] ARP_IPV4_HEADER = new byte[]{
    -+    private static final byte[] ARP_IPV4_HEADER = {
    -             0, 1, // Hardware type: Ethernet (1)
    -             8, 0, // Protocol type: IP (0x0800)
    -             6,    // Hardware size: 6
    -@@ -229,6 +232,9 @@ public class ApfFilter {
    -     // Our IPv4 address, if we have just one, otherwise null.
    -     @GuardedBy("this")
    -     private byte[] mIPv4Address;
    -+    // The subnet prefix length of our IPv4 network. Only valid if mIPv4Address is not null.
    -+    @GuardedBy("this")
    -+    private int mIPv4PrefixLength;
    - 
    -     @VisibleForTesting
    -     ApfFilter(ApfCapabilities apfCapabilities, NetworkInterface networkInterface,
    -@@ -364,26 +370,6 @@ public class ApfFilter {
    - 
    -         // Can't be static because it's in a non-static inner class.
    -         // TODO: Make this static once RA is its own class.
    --        private int uint8(byte b) {
    --            return b & 0xff;
    --        }
    --
    --        private int uint16(short s) {
    --            return s & 0xffff;
    --        }
    --
    --        private long uint32(int i) {
    --            return i & 0xffffffffL;
    --        }
    --
    --        private long getUint16(ByteBuffer buffer, int position) {
    --            return uint16(buffer.getShort(position));
    --        }
    --
    --        private long getUint32(ByteBuffer buffer, int position) {
    --            return uint32(buffer.getInt(position));
    --        }
    --
    -         private void prefixOptionToString(StringBuffer sb, int offset) {
    -             String prefix = IPv6AddresstoString(offset + 16);
    -             int length = uint8(mPacket.get(offset + 2));
    -@@ -737,39 +723,57 @@ public class ApfFilter {
    -         // Here's a basic summary of what the IPv4 filter program does:
    -         //
    -         // if filtering multicast (i.e. multicast lock not held):
    --        //   if it's multicast:
    --        //     drop
    --        //   if it's not broadcast:
    -+        //   if it's DHCP destined to our MAC:
    -         //     pass
    --        //   if it's not DHCP destined to our MAC:
    -+        //   if it's L2 broadcast:
    -+        //     drop
    -+        //   if it's IPv4 multicast:
    -+        //     drop
    -+        //   if it's IPv4 broadcast:
    -         //     drop
    -         // pass
    - 
    -         if (mMulticastFilter) {
    --            // Check for multicast destination address range
    --            gen.addLoad8(Register.R0, IPV4_DEST_ADDR_OFFSET);
    --            gen.addAnd(0xf0);
    --            gen.addJumpIfR0Equals(0xe0, gen.DROP_LABEL);
    -+            final String skipDhcpv4Filter = "skip_dhcp_v4_filter";
    - 
    --            // Drop all broadcasts besides DHCP addressed to us
    --            // If not a broadcast packet, pass
    --            gen.addLoadImmediate(Register.R0, ETH_DEST_ADDR_OFFSET);
    --            gen.addJumpIfBytesNotEqual(Register.R0, ETH_BROADCAST_MAC_ADDRESS, gen.PASS_LABEL);
    --            // If not UDP, drop
    -+            // Pass DHCP addressed to us.
    -+            // Check it's UDP.
    -             gen.addLoad8(Register.R0, IPV4_PROTOCOL_OFFSET);
    --            gen.addJumpIfR0NotEquals(IPPROTO_UDP, gen.DROP_LABEL);
    --            // If fragment, drop. This matches the BPF filter installed by the DHCP client.
    -+            gen.addJumpIfR0NotEquals(IPPROTO_UDP, skipDhcpv4Filter);
    -+            // Check it's not a fragment. This matches the BPF filter installed by the DHCP client.
    -             gen.addLoad16(Register.R0, IPV4_FRAGMENT_OFFSET_OFFSET);
    --            gen.addJumpIfR0AnyBitsSet(IPV4_FRAGMENT_OFFSET_MASK, gen.DROP_LABEL);
    --            // If not to DHCP client port, drop
    -+            gen.addJumpIfR0AnyBitsSet(IPV4_FRAGMENT_OFFSET_MASK, skipDhcpv4Filter);
    -+            // Check it's addressed to DHCP client port.
    -             gen.addLoadFromMemory(Register.R1, gen.IPV4_HEADER_SIZE_MEMORY_SLOT);
    -             gen.addLoad16Indexed(Register.R0, UDP_DESTINATION_PORT_OFFSET);
    --            gen.addJumpIfR0NotEquals(DHCP_CLIENT_PORT, gen.DROP_LABEL);
    --            // If not DHCP to our MAC address, drop
    -+            gen.addJumpIfR0NotEquals(DHCP_CLIENT_PORT, skipDhcpv4Filter);
    -+            // Check it's DHCP to our MAC address.
    -             gen.addLoadImmediate(Register.R0, DHCP_CLIENT_MAC_OFFSET);
    -             // NOTE: Relies on R1 containing IPv4 header offset.
    -             gen.addAddR1();
    --            gen.addJumpIfBytesNotEqual(Register.R0, mHardwareAddress, gen.DROP_LABEL);
    -+            gen.addJumpIfBytesNotEqual(Register.R0, mHardwareAddress, skipDhcpv4Filter);
    -+            gen.addJump(gen.PASS_LABEL);
    -+
    -+            // Drop all multicasts/broadcasts.
    -+            gen.defineLabel(skipDhcpv4Filter);
    -+
    -+            // If IPv4 destination address is in multicast range, drop.
    -+            gen.addLoad8(Register.R0, IPV4_DEST_ADDR_OFFSET);
    -+            gen.addAnd(0xf0);
    -+            gen.addJumpIfR0Equals(0xe0, gen.DROP_LABEL);
    -+
    -+            // If IPv4 broadcast packet, drop regardless of L2 (b/30231088).
    -+            gen.addLoad32(Register.R0, IPV4_DEST_ADDR_OFFSET);
    -+            gen.addJumpIfR0Equals(IPV4_BROADCAST_ADDRESS, gen.DROP_LABEL);
    -+            if (mIPv4Address != null && mIPv4PrefixLength < 31) {
    -+                int broadcastAddr = ipv4BroadcastAddress(mIPv4Address, mIPv4PrefixLength);
    -+                gen.addJumpIfR0Equals(broadcastAddr, gen.DROP_LABEL);
    -+            }
    -+
    -+            // If L2 broadcast packet, drop.
    -+            gen.addLoadImmediate(Register.R0, ETH_DEST_ADDR_OFFSET);
    -+            gen.addJumpIfBytesNotEqual(Register.R0, ETH_BROADCAST_MAC_ADDRESS, gen.PASS_LABEL);
    -+            gen.addJump(gen.DROP_LABEL);
    -         }
    - 
    -         // Otherwise, pass
    -@@ -1062,26 +1066,32 @@ public class ApfFilter {
    +diff --git a/core/java/android/accounts/ChooseTypeAndAccountActivity.java b/core/java/android/accounts/ChooseTypeAndAccountActivity.java
    +index aed7a36..bf96926 100644
    +--- a/core/java/android/accounts/ChooseTypeAndAccountActivity.java
    ++++ b/core/java/android/accounts/ChooseTypeAndAccountActivity.java
    +@@ -250,6 +250,10 @@ public class ChooseTypeAndAccountActivity extends Activity
    +             outState.putParcelableArray(KEY_INSTANCE_STATE_EXISTING_ACCOUNTS, mExistingAccounts);
              }
    -     }
    - 
    --    // Find the single IPv4 address if there is one, otherwise return null.
    --    private static byte[] findIPv4Address(LinkProperties lp) {
    --        byte[] ipv4Address = null;
    --        for (InetAddress inetAddr : lp.getAddresses()) {
    --            byte[] addr = inetAddr.getAddress();
    --            if (addr.length != 4) continue;
    --            // More than one IPv4 address, abort
    --            if (ipv4Address != null && !Arrays.equals(ipv4Address, addr)) return null;
    --            ipv4Address = addr;
    -+    /** Find the single IPv4 LinkAddress if there is one, otherwise return null. */
    -+    private static LinkAddress findIPv4LinkAddress(LinkProperties lp) {
    -+        LinkAddress ipv4Address = null;
    -+        for (LinkAddress address : lp.getLinkAddresses()) {
    -+            if (!(address.getAddress() instanceof Inet4Address)) {
    -+                continue;
    -+            }
    -+            if (ipv4Address != null && !ipv4Address.isSameAddressAs(address)) {
    -+                // More than one IPv4 address, abort.
    -+                return null;
    +         if (mSelectedItemIndex != SELECTED_ITEM_NONE) {
    ++            if (mAccounts == null) {
    ++                final AccountManager accountManager = AccountManager.get(this);
    ++                mAccounts = getAcceptableAccountChoices(accountManager);
     +            }
    -+            ipv4Address = address;
    -         }
    -         return ipv4Address;
    -     }
    - 
    -     public synchronized void setLinkProperties(LinkProperties lp) {
    -         // NOTE: Do not keep a copy of LinkProperties as it would further duplicate state.
    --        byte[] ipv4Address = findIPv4Address(lp);
    --        // If ipv4Address is the same as mIPv4Address, then there's no change, just return.
    --        if (Arrays.equals(ipv4Address, mIPv4Address)) return;
    --        // Otherwise update mIPv4Address and install new program.
    --        mIPv4Address = ipv4Address;
    -+        final LinkAddress ipv4Address = findIPv4LinkAddress(lp);
    -+        final byte[] addr = (ipv4Address != null) ? ipv4Address.getAddress().getAddress() : null;
    -+        final int prefix = (ipv4Address != null) ? ipv4Address.getPrefixLength() : 0;
    -+        if ((prefix == mIPv4PrefixLength) && Arrays.equals(addr, mIPv4Address)) {
    -+            return;
    -+        }
    -+        mIPv4Address = addr;
    -+        mIPv4PrefixLength = prefix;
    -         installNewProgramLocked();
    -     }
    - 
    -@@ -1127,4 +1137,38 @@ public class ApfFilter {
    -             pw.decreaseIndent();
    -         }
    -     }
    -+
    -+    private static int uint8(byte b) {
    -+        return b & 0xff;
    -+    }
    -+
    -+    private static int uint16(short s) {
    -+        return s & 0xffff;
    -+    }
    -+
    -+    private static long uint32(int i) {
    -+        return i & 0xffffffffL;
    -+    }
    -+
    -+    private static long getUint16(ByteBuffer buffer, int position) {
    -+        return uint16(buffer.getShort(position));
    -+    }
    -+
    -+    private static long getUint32(ByteBuffer buffer, int position) {
    -+        return uint32(buffer.getInt(position));
    -+    }
    -+
    -+    // TODO: move to android.net.NetworkUtils
    -+    @VisibleForTesting
    -+    public static int ipv4BroadcastAddress(byte[] addrBytes, int prefixLength) {
    -+        return bytesToInt(addrBytes) | (int) (uint32(-1) >>> prefixLength);
    -+    }
    -+
    -+    @VisibleForTesting
    -+    public static int bytesToInt(byte[] addrBytes) {
    -+        return (uint8(addrBytes[0]) << 24)
    -+                + (uint8(addrBytes[1]) << 16)
    -+                + (uint8(addrBytes[2]) << 8)
    -+                + (uint8(addrBytes[3]));
    -+    }
    - }
    -diff --git a/services/net/java/android/net/dhcp/DhcpPacket.java b/services/net/java/android/net/dhcp/DhcpPacket.java
    -index 9aa66fe..ef4bc02 100644
    ---- a/services/net/java/android/net/dhcp/DhcpPacket.java
    -+++ b/services/net/java/android/net/dhcp/DhcpPacket.java
    -@@ -7,6 +7,7 @@ import android.net.metrics.DhcpErrorEvent;
    - import android.os.Build;
    - import android.os.SystemProperties;
    - import android.system.OsConstants;
    -+import com.android.internal.annotations.VisibleForTesting;
    - 
    - import java.io.UnsupportedEncodingException;
    - import java.net.Inet4Address;
    -@@ -14,9 +15,8 @@ import java.net.UnknownHostException;
    - import java.nio.BufferUnderflowException;
    - import java.nio.ByteBuffer;
    - import java.nio.ByteOrder;
    --import java.nio.charset.StandardCharsets;
    - import java.nio.ShortBuffer;
    --
    -+import java.nio.charset.StandardCharsets;
    - import java.util.ArrayList;
    - import java.util.Arrays;
    - import java.util.List;
    -@@ -725,7 +725,8 @@ abstract class DhcpPacket {
    -      * A subset of the optional parameters are parsed and are stored
    -      * in object fields.
    -      */
    --    public static DhcpPacket decodeFullPacket(ByteBuffer packet, int pktType) throws ParseException
    -+    @VisibleForTesting
    -+    static DhcpPacket decodeFullPacket(ByteBuffer packet, int pktType) throws ParseException
    -     {
    -         // bootp parameters
    -         int transactionId;
    -@@ -894,8 +895,12 @@ abstract class DhcpPacket {
    -                         + 64    // skip server host name (64 chars)
    -                         + 128); // skip boot file name (128 chars)
    - 
    --        int dhcpMagicCookie = packet.getInt();
    -+        // Ensure this is a DHCP packet with a magic cookie, and not BOOTP. http://b/31850211
    -+        if (packet.remaining() < 4) {
    -+            throw new ParseException(DhcpErrorEvent.DHCP_NO_COOKIE, "not a DHCP message");
    -+        }
    - 
    -+        int dhcpMagicCookie = packet.getInt();
    -         if (dhcpMagicCookie != DHCP_MAGIC_COOKIE) {
    -             throw new ParseException(DhcpErrorEvent.DHCP_BAD_MAGIC_COOKIE,
    -                     "Bad magic cookie 0x%08x, should be 0x%08x",
    -@@ -1090,7 +1095,13 @@ abstract class DhcpPacket {
    -     public static DhcpPacket decodeFullPacket(byte[] packet, int length, int pktType)
    -             throws ParseException {
    -         ByteBuffer buffer = ByteBuffer.wrap(packet, 0, length).order(ByteOrder.BIG_ENDIAN);
    --        return decodeFullPacket(buffer, pktType);
    -+        try {
    -+            return decodeFullPacket(buffer, pktType);
    -+        } catch (ParseException e) {
    -+            throw e;
    -+        } catch (Exception e) {
    -+            throw new ParseException(DhcpErrorEvent.PARSING_ERROR, e.getMessage());
    -+        }
    -     }
    - 
    -     /**
    -diff --git a/services/net/java/android/net/ip/IpManager.java b/services/net/java/android/net/ip/IpManager.java
    -index d0ab606..01d9304 100644
    ---- a/services/net/java/android/net/ip/IpManager.java
    -+++ b/services/net/java/android/net/ip/IpManager.java
    -@@ -46,6 +46,7 @@ import android.util.SparseArray;
    - 
    - import com.android.internal.annotations.VisibleForTesting;
    - import com.android.internal.util.IndentingPrintWriter;
    -+import com.android.internal.util.IState;
    - import com.android.internal.util.State;
    - import com.android.internal.util.StateMachine;
    - import com.android.server.net.NetlinkTracker;
    -@@ -358,6 +359,7 @@ public class IpManager extends StateMachine {
    -     }
    - 
    -     public static final String DUMP_ARG = "ipmanager";
    -+    public static final String DUMP_ARG_CONFIRM = "confirm";
    - 
    -     private static final int CMD_STOP = 1;
    -     private static final int CMD_START = 2;
    -@@ -383,6 +385,7 @@ public class IpManager extends StateMachine {
    -     private final State mStoppedState = new StoppedState();
    -     private final State mStoppingState = new StoppingState();
    -     private final State mStartedState = new StartedState();
    -+    private final State mRunningState = new RunningState();
    - 
    -     private final String mTag;
    -     private final Context mContext;
    -@@ -396,6 +399,7 @@ public class IpManager extends StateMachine {
    -     private final WakeupMessage mDhcpActionTimeoutAlarm;
    -     private final AvoidBadWifiTracker mAvoidBadWifiTracker;
    -     private final LocalLog mLocalLog;
    -+    private final MessageHandlingLogger mMsgStateLogger;
    -     private final IpConnectivityLog mMetricsLog = new IpConnectivityLog();
    - 
    -     private NetworkInterface mNetworkInterface;
    -@@ -480,10 +484,12 @@ public class IpManager extends StateMachine {
    -         // Super simple StateMachine.
    -         addState(mStoppedState);
    -         addState(mStartedState);
    -+            addState(mRunningState, mStartedState);
    -         addState(mStoppingState);
    - 
    -         setInitialState(mStoppedState);
    -         mLocalLog = new LocalLog(MAX_LOG_RECORDS);
    -+        mMsgStateLogger = new MessageHandlingLogger();
    -         super.start();
    -     }
    - 
    -@@ -561,6 +567,12 @@ public class IpManager extends StateMachine {
    -     }
    - 
    -     public void dump(FileDescriptor fd, PrintWriter writer, String[] args) {
    -+        if (args.length > 0 && DUMP_ARG_CONFIRM.equals(args[0])) {
    -+            // Execute confirmConfiguration() and take no further action.
    -+            confirmConfiguration();
    -+            return;
    -+        }
    -+
    -         IndentingPrintWriter pw = new IndentingPrintWriter(writer, "  ");
    -         pw.println("APF dump:");
    -         pw.increaseIndent();
    -@@ -574,7 +586,7 @@ public class IpManager extends StateMachine {
    -         pw.decreaseIndent();
    - 
    -         pw.println();
    --        pw.println("StateMachine dump:");
    -+        pw.println(mTag + " StateMachine dump:");
    -         pw.increaseIndent();
    -         mLocalLog.readOnlyLocalLog().dump(fd, pw, args);
    -         pw.decreaseIndent();
    -@@ -593,9 +605,9 @@ public class IpManager extends StateMachine {
    -     @Override
    -     protected String getLogRecString(Message msg) {
    -         final String logLine = String.format(
    --                "%s/%d %d %d %s",
    -+                "%s/%d %d %d %s [%s]",
    -                 mInterfaceName, mNetworkInterface == null ? -1 : mNetworkInterface.getIndex(),
    --                msg.arg1, msg.arg2, Objects.toString(msg.obj));
    -+                msg.arg1, msg.arg2, Objects.toString(msg.obj), mMsgStateLogger);
    - 
    -         final String richerLogLine = getWhatToString(msg.what) + " " + logLine;
    -         mLocalLog.log(richerLogLine);
    -@@ -603,6 +615,7 @@ public class IpManager extends StateMachine {
    -             Log.d(mTag, richerLogLine);
    -         }
    - 
    -+        mMsgStateLogger.reset();
    -         return logLine;
    -     }
    - 
    -@@ -611,7 +624,11 @@ public class IpManager extends StateMachine {
    -         // Don't log EVENT_NETLINK_LINKPROPERTIES_CHANGED. They can be noisy,
    -         // and we already log any LinkProperties change that results in an
    -         // invocation of IpManager.Callback#onLinkPropertiesChange().
    --        return (msg.what != EVENT_NETLINK_LINKPROPERTIES_CHANGED);
    -+        final boolean shouldLog = (msg.what != EVENT_NETLINK_LINKPROPERTIES_CHANGED);
    -+        if (!shouldLog) {
    -+            mMsgStateLogger.reset();
    -+        }
    -+        return shouldLog;
    -     }
    +             if (mSelectedItemIndex == mAccounts.size()) {
    +                 outState.putBoolean(KEY_INSTANCE_STATE_SELECTED_ADD_ACCOUNT, true);
    +             } else {
    +@@ -291,6 +295,10 @@ public class ChooseTypeAndAccountActivity extends Activity
    +         mPendingRequest = REQUEST_NULL;
      
    -     private void getNetworkInterface() {
    -@@ -789,6 +806,11 @@ public class IpManager extends StateMachine {
    -         //         - IPv6 addresses
    -         //         - IPv6 routes
    -         //         - IPv6 DNS servers
    -+        //
    -+        // N.B.: this is fundamentally race-prone and should be fixed by
    -+        // changing NetlinkTracker from a hybrid edge/level model to an
    -+        // edge-only model, or by giving IpManager its own netlink socket(s)
    -+        // so as to track all required information directly.
    -         LinkProperties netlinkLinkProperties = mNetlinkTracker.getLinkProperties();
    -         newLp.setLinkAddresses(netlinkLinkProperties.getLinkAddresses());
    -         for (RouteInfo route : netlinkLinkProperties.getRoutes()) {
    -@@ -960,16 +982,29 @@ public class IpManager extends StateMachine {
    -         return true;
    -     }
    +         if (resultCode == RESULT_CANCELED) {
    ++            if (mAccounts == null) {
    ++                final AccountManager accountManager = AccountManager.get(this);
    ++                mAccounts = getAcceptableAccountChoices(accountManager);
    ++            }
    +             // if canceling out of addAccount and the original state caused us to skip this,
    +             // finish this activity
    +             if (mAccounts.isEmpty()) {
    +diff --git a/libs/hwui/Android.mk b/libs/hwui/Android.mk
    +index cacfce1..0b177b9 100644
    +--- a/libs/hwui/Android.mk
    ++++ b/libs/hwui/Android.mk
    +@@ -149,7 +149,7 @@ endif
      
    -+    private void stopAllIP() {
    -+        // We don't need to worry about routes, just addresses, because:
    -+        //     - disableIpv6() will clear autoconf IPv6 routes as well, and
    -+        //     - we don't get IPv4 routes from netlink
    -+        // so we neither react to nor need to wait for changes in either.
    -+
    -+        try {
    -+            mNwService.disableIpv6(mInterfaceName);
    -+        } catch (Exception e) {
    -+            Log.e(mTag, "Failed to disable IPv6" + e);
    -+        }
    -+
    -+        try {
    -+            mNwService.clearInterfaceAddresses(mInterfaceName);
    -+        } catch (Exception e) {
    -+            Log.e(mTag, "Failed to clear addresses " + e);
    -+        }
    -+    }
    + ifdef HWUI_COMPILE_FOR_PERF
    +     # TODO: Non-arm?
    +-    hwui_cflags += -fno-omit-frame-pointer -marm -mapcs
    ++    hwui_cflags += -fno-omit-frame-pointer -marm 
    + endif
      
    -     class StoppedState extends State {
    -         @Override
    -         public void enter() {
    --            try {
    --                mNwService.disableIpv6(mInterfaceName);
    --                mNwService.clearInterfaceAddresses(mInterfaceName);
    --            } catch (Exception e) {
    --                Log.e(mTag, "Failed to clear addresses or disable IPv6" + e);
    --            }
    -+            stopAllIP();
    + # This has to be lazy-resolved because it depends on the LOCAL_MODULE_CLASS
    +diff --git a/libs/hwui/Snapshot.cpp b/libs/hwui/Snapshot.cpp
    +index 2c9c9d9..7c187fb 100644
    +--- a/libs/hwui/Snapshot.cpp
    ++++ b/libs/hwui/Snapshot.cpp
    +@@ -38,6 +38,7 @@ Snapshot::Snapshot()
    +         , mClipArea(&mClipAreaRoot) {
    +     transform = &mTransformRoot;
    +     region = nullptr;
    ++    mRelativeLightCenter.x = mRelativeLightCenter.y = mRelativeLightCenter.z = 0;
    + }
      
    -             resetLinkProperties();
    -             if (mStartTimeMillis > 0) {
    -@@ -1015,6 +1050,8 @@ public class IpManager extends StateMachine {
    -                 default:
    -                     return NOT_HANDLED;
    -             }
    -+
    -+            mMsgStateLogger.handled(this, getCurrentState());
    -             return HANDLED;
    -         }
    + /**
    +diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationGuts.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationGuts.java
    +index c850a25..1829e59 100644
    +--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationGuts.java
    ++++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationGuts.java
    +@@ -235,16 +235,16 @@ public class NotificationGuts extends LinearLayout implements TunerService.Tunab
          }
    -@@ -1031,6 +1068,13 @@ public class IpManager extends StateMachine {
    -         @Override
    -         public boolean processMessage(Message msg) {
    -             switch (msg.what) {
    -+                case CMD_STOP:
    -+                    break;
    -+
    -+                case DhcpClient.CMD_CLEAR_LINKADDRESS:
    -+                    clearIPv4Address();
    -+                    break;
    -+
    -                 case DhcpClient.CMD_ON_QUIT:
    -                     mDhcpClient = null;
    -                     transitionTo(mStoppedState);
    -@@ -1039,17 +1083,80 @@ public class IpManager extends StateMachine {
    -                 default:
    -                     deferMessage(msg);
    + 
    +     private int getSelectedImportance() {
    +-        if (mSeekBar!= null && mSeekBar.isShown()) {
    ++        if (mSeekBar != null && mSeekBar.isShown()) {
    +             if (mSeekBar.isEnabled()) {
    +                 return mSeekBar.getProgress();
    +             } else {
    +                 return Ranking.IMPORTANCE_UNSPECIFIED;
                  }
    +         } else {
    +-            if (mBlock.isChecked()) {
    ++            if (mBlock != null && mBlock.isChecked()) {
    +                 return Ranking.IMPORTANCE_NONE;
    +-            } else if (mSilent.isChecked()) {
    ++            } else if (mSilent != null && mSilent.isChecked()) {
    +                 return Ranking.IMPORTANCE_LOW;
    +             } else {
    +                 return Ranking.IMPORTANCE_UNSPECIFIED;
    +diff --git a/packages/SystemUI/src/com/android/systemui/tuner/TunerFragment.java b/packages/SystemUI/src/com/android/systemui/tuner/TunerFragment.java
    +index 70f2fdc..ba50161 100644
    +--- a/packages/SystemUI/src/com/android/systemui/tuner/TunerFragment.java
    ++++ b/packages/SystemUI/src/com/android/systemui/tuner/TunerFragment.java
    +@@ -59,7 +59,10 @@ public class TunerFragment extends PreferenceFragment {
    +     @Override
    +     public void onActivityCreated(Bundle savedInstanceState) {
    +         super.onActivityCreated(savedInstanceState);
    +-        getActivity().getActionBar().setDisplayHomeAsUpEnabled(true);
     +
    -+            mMsgStateLogger.handled(this, getCurrentState());
    -             return HANDLED;
    -         }
    ++        if (getActivity().getActionBar() != null) {
    ++            getActivity().getActionBar().setDisplayHomeAsUpEnabled(true);
    ++        }
          }
      
    -     class StartedState extends State {
    --        private boolean mDhcpActionInFlight;
    +     @Override
    +diff --git a/services/core/java/com/android/server/AppOpsService.java b/services/core/java/com/android/server/AppOpsService.java
    +index 4caeba8..c95b9d5 100644
    +--- a/services/core/java/com/android/server/AppOpsService.java
    ++++ b/services/core/java/com/android/server/AppOpsService.java
    +@@ -597,7 +597,6 @@ public class AppOpsService extends IAppOpsService.Stub {
    +         ArrayList<Callback> repCbs = null;
    +         code = AppOpsManager.opToSwitch(code);
    +         synchronized (this) {
    +-            UidState uidState = getUidStateLocked(uid, false);
    +             Op op = getOpLocked(code, uid, packageName, true);
    +             if (op != null) {
    +                 if (op.mode != mode) {
    +@@ -973,7 +972,7 @@ public class AppOpsService extends IAppOpsService.Stub {
    +     public int checkPackage(int uid, String packageName) {
    +         Preconditions.checkNotNull(packageName);
    +         synchronized (this) {
    +-            if (getOpsRawLocked(uid, packageName, true) != null) {
    ++            if (packageName != null && getOpsRawLocked(uid, packageName, true) != null) {
    +                 return AppOpsManager.MODE_ALLOWED;
    +             } else {
    +                 return AppOpsManager.MODE_ERRORED;
    +@@ -1533,8 +1532,6 @@ public class AppOpsService extends IAppOpsService.Stub {
    + 
    +     void writeState() {
    +         synchronized (mFile) {
    +-            List<AppOpsManager.PackageOps> allOps = getPackagesForOps(null);
     -
    -         @Override
    -         public void enter() {
    -             mStartTimeMillis = SystemClock.elapsedRealtime();
    +             FileOutputStream stream;
    +             try {
    +                 stream = mFile.startWrite();
    +@@ -1543,15 +1540,33 @@ public class AppOpsService extends IAppOpsService.Stub {
    +                 return;
    +             }
      
    -+            if (mConfiguration.mProvisioningTimeoutMs > 0) {
    -+                final long alarmTime = SystemClock.elapsedRealtime() +
    -+                        mConfiguration.mProvisioningTimeoutMs;
    -+                mProvisioningTimeoutAlarm.schedule(alarmTime);
    -+            }
    -+
    -+            if (readyToProceed()) {
    -+                transitionTo(mRunningState);
    -+            } else {
    -+                // Clear all IPv4 and IPv6 before proceeding to RunningState.
    -+                // Clean up any leftover state from an abnormal exit from
    -+                // tethering or during an IpManager restart.
    -+                stopAllIP();
    -+            }
    -+        }
    -+
    -+        @Override
    -+        public void exit() {
    -+            mProvisioningTimeoutAlarm.cancel();
    -+        }
    -+
    -+        @Override
    -+        public boolean processMessage(Message msg) {
    -+            switch (msg.what) {
    -+                case CMD_STOP:
    -+                    transitionTo(mStoppingState);
    -+                    break;
    -+
    -+                case EVENT_NETLINK_LINKPROPERTIES_CHANGED:
    -+                    handleLinkPropertiesUpdate(NO_CALLBACKS);
    -+                    if (readyToProceed()) {
    -+                        transitionTo(mRunningState);
    ++            SparseArray<UidState> outUidStates = null;
    ++            synchronized (this) {
    ++                final int uidStateCount = mUidStates.size();
    ++                for (int i = 0; i < uidStateCount; i++) {
    ++                    UidState uidState = mUidStates.valueAt(i);
    ++                    SparseIntArray opModes = uidState.opModes;
    ++                    if (opModes != null && opModes.size() > 0) {
    ++                        UidState outUidState = new UidState(uidState.uid);
    ++                        outUidState.opModes = opModes.clone();
    ++                        if (outUidStates == null) {
    ++                            outUidStates = new SparseArray<>();
    ++                        }
    ++                        outUidStates.put(mUidStates.keyAt(i), outUidState);
     +                    }
    -+                    break;
    -+
    -+                case EVENT_PROVISIONING_TIMEOUT:
    -+                    handleProvisioningFailure();
    -+                    break;
    -+
    -+                default:
    -+                    // It's safe to process messages out of order because the
    -+                    // only message that can both
    -+                    //     a) be received at this time and
    -+                    //     b) affect provisioning state
    -+                    // is EVENT_NETLINK_LINKPROPERTIES_CHANGED (handled above).
    -+                    deferMessage(msg);
    ++                }
     +            }
    ++            List<AppOpsManager.PackageOps> allOps = getPackagesForOps(null);
     +
    -+            mMsgStateLogger.handled(this, getCurrentState());
    -+            return HANDLED;
    -+        }
    -+
    -+        boolean readyToProceed() {
    -+            return (!mLinkProperties.hasIPv4Address() &&
    -+                    !mLinkProperties.hasGlobalIPv6Address());
    -+        }
    -+    }
    -+
    -+    class RunningState extends State {
    -+        private boolean mDhcpActionInFlight;
    -+
    -+        @Override
    -+        public void enter() {
    -             mApfFilter = ApfFilter.maybeCreate(mConfiguration.mApfCapabilities, mNetworkInterface,
    -                     mCallback, mMulticastFiltering);
    -             // TODO: investigate the effects of any multicast filtering racing/interfering with the
    -@@ -1058,12 +1165,6 @@ public class IpManager extends StateMachine {
    -                 mCallback.setFallbackMulticastFilter(mMulticastFiltering);
    -             }
    +             try {
    +                 XmlSerializer out = new FastXmlSerializer();
    +                 out.setOutput(stream, StandardCharsets.UTF_8.name());
    +                 out.startDocument(null, true);
    +                 out.startTag(null, "app-ops");
      
    --            if (mConfiguration.mProvisioningTimeoutMs > 0) {
    --                final long alarmTime = SystemClock.elapsedRealtime() +
    --                        mConfiguration.mProvisioningTimeoutMs;
    --                mProvisioningTimeoutAlarm.schedule(alarmTime);
    --            }
    --
    -             if (mConfiguration.mEnableIPv6) {
    -                 // TODO: Consider transitionTo(mStoppingState) if this fails.
    -                 startIPv6();
    -@@ -1092,7 +1193,6 @@ public class IpManager extends StateMachine {
    +-                final int uidStateCount = mUidStates.size();
    ++                final int uidStateCount = outUidStates != null ? outUidStates.size() : 0;
    +                 for (int i = 0; i < uidStateCount; i++) {
    +-                    UidState uidState = mUidStates.valueAt(i);
    ++                    UidState uidState = outUidStates.valueAt(i);
    +                     if (uidState.opModes != null && uidState.opModes.size() > 0) {
    +                         out.startTag(null, "uid");
    +                         out.attribute(null, "n", Integer.toString(uidState.uid));
    +diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
    +index 5f59e32..23172a2 100644
    +--- a/services/core/java/com/android/server/ConnectivityService.java
    ++++ b/services/core/java/com/android/server/ConnectivityService.java
    +@@ -2992,6 +2992,12 @@ public class ConnectivityService extends IConnectivityManager.Stub
    +         ConnectivityManager.enforceTetherChangePermission(mContext);
    +         if (isTetheringSupported()) {
    +             final int status = mTethering.tether(iface);
    ++            if (status == ConnectivityManager.TETHER_ERROR_NO_ERROR) {
    ++                try {
    ++                    mPolicyManager.onTetheringChanged(iface, true);
    ++                } catch (RemoteException e) {
    ++                }
    ++            }
    +             return status;
    +         } else {
    +             return ConnectivityManager.TETHER_ERROR_UNSUPPORTED;
    +@@ -3005,6 +3011,12 @@ public class ConnectivityService extends IConnectivityManager.Stub
      
    -         @Override
    -         public void exit() {
    --            mProvisioningTimeoutAlarm.cancel();
    -             stopDhcpAction();
    +         if (isTetheringSupported()) {
    +             final int status = mTethering.untether(iface);
    ++            if (status == ConnectivityManager.TETHER_ERROR_NO_ERROR) {
    ++                try {
    ++                    mPolicyManager.onTetheringChanged(iface, false);
    ++                } catch (RemoteException e) {
    ++                }
    ++            }
    +             return status;
    +         } else {
    +             return ConnectivityManager.TETHER_ERROR_UNSUPPORTED;
    +@@ -4909,6 +4921,13 @@ public class ConnectivityService extends IConnectivityManager.Stub
    +             // check if it satisfies the NetworkCapabilities
    +             if (VDBG) log("  checking if request is satisfied: " + nri.request);
    +             if (satisfies) {
    ++                if (nri.request.isListen()) {
    ++                    // This is not a request, it's a callback listener.
    ++                    // Add it to newNetwork regardless of score.
    ++                    if (newNetwork.addRequest(nri.request)) addedRequests.add(nri);
    ++                    continue;
    ++                }
    ++
    +                 // next check if it's better than any current network we're using for
    +                 // this request
    +                 if (VDBG) {
    +diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
    +index 85d2981..ba10c64 100644
    +--- a/services/core/java/com/android/server/am/ActivityManagerService.java
    ++++ b/services/core/java/com/android/server/am/ActivityManagerService.java
    +@@ -9583,7 +9583,7 @@ public final class ActivityManagerService extends ActivityManagerNative
    +         for (int i = 0; i < procsToKill.size(); i++) {
    +             ProcessRecord pr = procsToKill.get(i);
    +             if (pr.setSchedGroup == ProcessList.SCHED_GROUP_BACKGROUND
    +-                    && pr.curReceiver == null) {
    ++                    && pr.curReceivers.isEmpty()) {
    +                 pr.kill("remove task", true);
    +             } else {
    +                 // We delay killing processes that are not in the background or running a receiver.
    +@@ -19157,26 +19157,28 @@ public final class ActivityManagerService extends ActivityManagerNative
    +     // LIFETIME MANAGEMENT
    +     // =========================================================
      
    -             if (mIpReachabilityMonitor != null) {
    -@@ -1189,10 +1289,6 @@ public class IpManager extends StateMachine {
    -                     break;
    -                 }
    +-    // Returns which broadcast queue the app is the current [or imminent] receiver
    +-    // on, or 'null' if the app is not an active broadcast recipient.
    +-    private BroadcastQueue isReceivingBroadcast(ProcessRecord app) {
    +-        BroadcastRecord r = app.curReceiver;
    +-        if (r != null) {
    +-            return r.queue;
    ++    // Returns whether the app is receiving broadcast.
    ++    // If receiving, fetch all broadcast queues which the app is
    ++    // the current [or imminent] receiver on.
    ++    private boolean isReceivingBroadcastLocked(ProcessRecord app,
    ++            ArraySet<BroadcastQueue> receivingQueues) {
    ++        if (!app.curReceivers.isEmpty()) {
    ++            for (BroadcastRecord r : app.curReceivers) {
    ++                receivingQueues.add(r.queue);
    ++            }
    ++            return true;
    +         }
      
    --                case EVENT_PROVISIONING_TIMEOUT:
    --                    handleProvisioningFailure();
    --                    break;
    --
    -                 case EVENT_DHCPACTION_TIMEOUT:
    -                     stopDhcpAction();
    -                     break;
    -@@ -1255,7 +1351,29 @@ public class IpManager extends StateMachine {
    -                 default:
    -                     return NOT_HANDLED;
    +         // It's not the current receiver, but it might be starting up to become one
    +-        synchronized (this) {
    +-            for (BroadcastQueue queue : mBroadcastQueues) {
    +-                r = queue.mPendingBroadcast;
    +-                if (r != null && r.curApp == app) {
    +-                    // found it; report which queue it's in
    +-                    return queue;
    +-                }
    ++        for (BroadcastQueue queue : mBroadcastQueues) {
    ++            final BroadcastRecord r = queue.mPendingBroadcast;
    ++            if (r != null && r.curApp == app) {
    ++                // found it; report which queue it's in
    ++                receivingQueues.add(queue);
                  }
    -+
    -+            mMsgStateLogger.handled(this, getCurrentState());
    -             return HANDLED;
              }
    -     }
    -+
    -+    private static class MessageHandlingLogger {
    -+        public String processedInState;
    -+        public String receivedInState;
    -+
    -+        public void reset() {
    -+            processedInState = null;
    -+            receivedInState = null;
    -+        }
    -+
    -+        public void handled(State processedIn, IState receivedIn) {
    -+            processedInState = processedIn.getClass().getSimpleName();
    -+            receivedInState = receivedIn.getName();
    -+        }
    -+
    -+        public String toString() {
    -+            return String.format("rcvd_in=%s, proc_in=%s",
    -+                                 receivedInState, processedInState);
    -+        }
    -+    }
    - }
    -diff --git a/services/net/java/android/net/util/NetdService.java b/services/net/java/android/net/util/NetdService.java
    -new file mode 100644
    -index 0000000..153cb50
    ---- /dev/null
    -+++ b/services/net/java/android/net/util/NetdService.java
    -@@ -0,0 +1,46 @@
    -+/*
    -+ * Copyright (C) 2016 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 android.net.util;
    -+
    -+import android.net.INetd;
    -+import android.os.ServiceManager;
    -+import android.util.Log;
    -+
    -+
    -+/**
    -+ * @hide
    -+ */
    -+public class NetdService {
    -+    private static final String TAG = NetdService.class.getSimpleName();
    -+    private static final String NETD_SERVICE_NAME = "netd";
    -+
    -+    /**
    -+     * It is the caller's responsibility to check for a null return value
    -+     * and to handle RemoteException errors from invocations on the returned
    -+     * interface if, for example, netd dies and is restarted.
    -+     *
    -+     * @return an INetd instance or null.
    -+     */
    -+    public static INetd getInstance() {
    -+        final INetd netdInstance = INetd.Stub.asInterface(
    -+                ServiceManager.getService(NETD_SERVICE_NAME));
    -+        if (netdInstance == null) {
    -+            Log.w(TAG, "WARNING: returning null INetd instance.");
    -+        }
    -+        return netdInstance;
    -+    }
    -+}
    -diff --git a/services/print/java/com/android/server/print/RemotePrintSpooler.java b/services/print/java/com/android/server/print/RemotePrintSpooler.java
    -index 07cc9c0..07b26e8 100644
    ---- a/services/print/java/com/android/server/print/RemotePrintSpooler.java
    -+++ b/services/print/java/com/android/server/print/RemotePrintSpooler.java
    -@@ -57,6 +57,9 @@ import java.util.concurrent.TimeoutException;
    -  * spooler if needed, to make the timed remote calls, to handle
    -  * remote exceptions, and to bind/unbind to the remote instance as
    -  * needed.
    -+ *
    -+ * The calls might be blocking and need the main thread of to be unblocked to finish. Hence do not
    -+ * call this while holding any monitors that might need to be acquired the main thread.
    -  */
    - final class RemotePrintSpooler {
      
    -diff --git a/services/print/java/com/android/server/print/UserState.java b/services/print/java/com/android/server/print/UserState.java
    -index 05301c1..a91cdb3 100644
    ---- a/services/print/java/com/android/server/print/UserState.java
    -+++ b/services/print/java/com/android/server/print/UserState.java
    -@@ -434,12 +434,12 @@ final class UserState implements PrintSpoolerCallbacks, PrintServiceCallbacks,
    +-        return null;
    ++        return !receivingQueues.isEmpty();
          }
      
    -     public void createPrinterDiscoverySession(@NonNull IPrinterDiscoveryObserver observer) {
    -+        mSpooler.clearCustomPrinterIconCache();
    -+
    -         synchronized (mLock) {
    -             throwIfDestroyedLocked();
    - 
    -             if (mPrinterDiscoverySession == null) {
    --                mSpooler.clearCustomPrinterIconCache();
    --
    -                 // If we do not have a session, tell all service to create one.
    -                 mPrinterDiscoverySession = new PrinterDiscoverySessionMediator(mContext) {
    -                     @Override
    -@@ -731,6 +731,8 @@ final class UserState implements PrintSpoolerCallbacks, PrintServiceCallbacks,
    - 
    -     @Override
    -     public void onCustomPrinterIconLoaded(PrinterId printerId, Icon icon) {
    -+        mSpooler.onCustomPrinterIconLoaded(printerId, icon);
    -+
    -         synchronized (mLock) {
    -             throwIfDestroyedLocked();
    +     Association startAssociationLocked(int sourceUid, String sourceProcess, int sourceState,
    +@@ -19343,7 +19345,7 @@ public final class ActivityManagerService extends ActivityManagerNative
    +         int schedGroup;
    +         int procState;
    +         boolean foregroundActivities = false;
    +-        BroadcastQueue queue;
    ++        final ArraySet<BroadcastQueue> queues = new ArraySet<BroadcastQueue>();
    +         if (app == TOP_APP) {
    +             // The last app on the list is the foreground app.
    +             adj = ProcessList.FOREGROUND_APP_ADJ;
    +@@ -19357,13 +19359,13 @@ public final class ActivityManagerService extends ActivityManagerNative
    +             schedGroup = ProcessList.SCHED_GROUP_DEFAULT;
    +             app.adjType = "instrumentation";
    +             procState = ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE;
    +-        } else if ((queue = isReceivingBroadcast(app)) != null) {
    ++        } else if (isReceivingBroadcastLocked(app, queues)) {
    +             // An app that is currently receiving a broadcast also
    +             // counts as being in the foreground for OOM killer purposes.
    +             // It's placed in a sched group based on the nature of the
    +             // broadcast as reflected by which queue it's active in.
    +             adj = ProcessList.FOREGROUND_APP_ADJ;
    +-            schedGroup = (queue == mFgBroadcastQueue)
    ++            schedGroup = (queues.contains(mFgBroadcastQueue))
    +                     ? ProcessList.SCHED_GROUP_DEFAULT : ProcessList.SCHED_GROUP_BACKGROUND;
    +             app.adjType = "broadcast";
    +             procState = ActivityManager.PROCESS_STATE_RECEIVER;
    +@@ -20374,7 +20376,7 @@ public final class ActivityManagerService extends ActivityManagerNative
    +             if (DEBUG_SWITCH || DEBUG_OOM_ADJ) Slog.v(TAG_OOM_ADJ,
    +                     "Setting sched group of " + app.processName
    +                     + " to " + app.curSchedGroup);
    +-            if (app.waitingToKill != null && app.curReceiver == null
    ++            if (app.waitingToKill != null && app.curReceivers.isEmpty()
    +                     && app.setSchedGroup == ProcessList.SCHED_GROUP_BACKGROUND) {
    +                 app.kill(app.waitingToKill, true);
    +                 success = false;
    +@@ -21314,7 +21316,7 @@ public final class ActivityManagerService extends ActivityManagerNative
    +             for (i=mRemovedProcesses.size()-1; i>=0; i--) {
    +                 final ProcessRecord app = mRemovedProcesses.get(i);
    +                 if (app.activities.size() == 0
    +-                        && app.curReceiver == null && app.services.size() == 0) {
    ++                        && app.curReceivers.isEmpty() && app.services.size() == 0) {
    +                     Slog.i(
    +                         TAG, "Exiting empty application process "
    +                         + app.toShortString() + " ("
    +diff --git a/services/core/java/com/android/server/am/BroadcastQueue.java b/services/core/java/com/android/server/am/BroadcastQueue.java
    +index 8b8e2c4..5c35419 100644
    +--- a/services/core/java/com/android/server/am/BroadcastQueue.java
    ++++ b/services/core/java/com/android/server/am/BroadcastQueue.java
    +@@ -266,7 +266,7 @@ public final class BroadcastQueue {
      
    -@@ -738,7 +740,6 @@ final class UserState implements PrintSpoolerCallbacks, PrintServiceCallbacks,
    -             if (mPrinterDiscoverySession == null) {
    -                 return;
    +         r.receiver = app.thread.asBinder();
    +         r.curApp = app;
    +-        app.curReceiver = r;
    ++        app.curReceivers.add(r);
    +         app.forceProcessStateUpTo(ActivityManager.PROCESS_STATE_RECEIVER);
    +         mService.updateLruProcessLocked(app, false, null);
    +         mService.updateOomAdjLocked();
    +@@ -294,7 +294,7 @@ public final class BroadcastQueue {
    +                         "Process cur broadcast " + r + ": NOT STARTED!");
    +                 r.receiver = null;
    +                 r.curApp = null;
    +-                app.curReceiver = null;
    ++                app.curReceivers.remove(r);
                  }
    --            mSpooler.onCustomPrinterIconLoaded(printerId, icon);
    -             mPrinterDiscoverySession.onCustomPrinterIconLoadedLocked(printerId);
              }
          }
    -@@ -979,18 +980,21 @@ final class UserState implements PrintSpoolerCallbacks, PrintServiceCallbacks,
    -      * Prune persistent state if a print service was uninstalled
    -      */
    -     public void prunePrintServices() {
    -+        ArrayList<ComponentName> installedComponents;
    -+
    -         synchronized (mLock) {
    --            ArrayList<ComponentName> installedComponents = getInstalledComponents();
    -+            installedComponents = getInstalledComponents();
    - 
    -             // Remove unnecessary entries from persistent state "disabled services"
    -             boolean disabledServicesUninstalled = mDisabledServices.retainAll(installedComponents);
    -             if (disabledServicesUninstalled) {
    -                 writeDisabledPrintServicesLocked(mDisabledServices);
    +@@ -395,8 +395,8 @@ public final class BroadcastQueue {
    +         }
    +         r.receiver = null;
    +         r.intent.setComponent(null);
    +-        if (r.curApp != null && r.curApp.curReceiver == r) {
    +-            r.curApp.curReceiver = null;
    ++        if (r.curApp != null && r.curApp.curReceivers.contains(r)) {
    ++            r.curApp.curReceivers.remove(r);
    +         }
    +         if (r.curFilter != null) {
    +             r.curFilter.receiverList.curBroadcast = null;
    +@@ -649,7 +649,7 @@ public final class BroadcastQueue {
    +                 // things that directly call the IActivityManager API, which
    +                 // are already core system stuff so don't matter for this.
    +                 r.curApp = filter.receiverList.app;
    +-                filter.receiverList.app.curReceiver = r;
    ++                filter.receiverList.app.curReceivers.add(r);
    +                 mService.updateOomAdjLocked(r.curApp);
                  }
    --
    --            // Remove unnecessary entries from persistent state "approved services"
    --            mSpooler.pruneApprovedPrintServices(installedComponents);
              }
    -+
    -+        // Remove unnecessary entries from persistent state "approved services"
    -+        mSpooler.pruneApprovedPrintServices(installedComponents);
    -+
    -     }
    - 
    -     private void onConfigurationChangedLocked() {
    -diff --git a/services/retaildemo/java/com/android/server/retaildemo/RetailDemoModeService.java b/services/retaildemo/java/com/android/server/retaildemo/RetailDemoModeService.java
    -index 6b27321..6197c42 100644
    ---- a/services/retaildemo/java/com/android/server/retaildemo/RetailDemoModeService.java
    -+++ b/services/retaildemo/java/com/android/server/retaildemo/RetailDemoModeService.java
    -@@ -44,6 +44,7 @@ import android.hardware.camera2.CameraManager;
    - import android.media.AudioManager;
    - import android.media.AudioSystem;
    - import android.net.Uri;
    -+import android.net.wifi.WifiManager;
    - import android.os.Environment;
    - import android.os.FileUtils;
    - import android.os.Handler;
    -@@ -117,6 +118,7 @@ public class RetailDemoModeService extends SystemService {
    -     private ServiceThread mHandlerThread;
    -     private PendingIntent mResetDemoPendingIntent;
    -     private CameraManager mCameraManager;
    -+    private WifiManager mWifiManager;
    -     private String[] mCameraIdsWithFlash;
    -     private Configuration mSystemUserConfiguration;
    -     private PreloadAppsInstaller mPreloadAppsInstaller;
    -@@ -491,6 +493,7 @@ public class RetailDemoModeService extends SystemService {
    -                                 PowerManager.FULL_WAKE_LOCK | PowerManager.ACQUIRE_CAUSES_WAKEUP,
    -                                 TAG);
    -                 mNm = NotificationManager.from(getContext());
    -+                mWifiManager = (WifiManager) getContext().getSystemService(Context.WIFI_SERVICE);
    -                 mCameraManager = (CameraManager) getContext()
    -                         .getSystemService(Context.CAMERA_SERVICE);
    -                 mCameraIdsWithFlash = getCameraIdsWithFlash();
    -@@ -528,6 +531,9 @@ public class RetailDemoModeService extends SystemService {
    -         mAmi.updatePersistentConfigurationForUser(getSystemUsersConfiguration(), userId);
    -         turnOffAllFlashLights();
    -         muteVolumeStreams();
    -+        if (!mWifiManager.isWifiEnabled()) {
    -+            mWifiManager.setWifiEnabled(true);
    -+        }
    -         // Disable lock screen for demo users.
    -         LockPatternUtils lockPatternUtils = new LockPatternUtils(getContext());
    -         lockPatternUtils.setLockScreenDisabled(true, userId);
    +@@ -677,7 +677,7 @@ public final class BroadcastQueue {
    +                 r.curFilter = null;
    +                 filter.receiverList.curBroadcast = null;
    +                 if (filter.receiverList.app != null) {
    +-                    filter.receiverList.app.curReceiver = null;
    ++                    filter.receiverList.app.curReceivers.remove(r);
    +                 }
    +             }
    +         }
    +diff --git a/services/core/java/com/android/server/am/ProcessRecord.java b/services/core/java/com/android/server/am/ProcessRecord.java
    +index 3fffefb..49fe79c 100644
    +--- a/services/core/java/com/android/server/am/ProcessRecord.java
    ++++ b/services/core/java/com/android/server/am/ProcessRecord.java
    +@@ -143,7 +143,7 @@ final class ProcessRecord {
    +     Bundle instrumentationArguments;// as given to us
    +     ComponentName instrumentationResultClass;// copy of instrumentationClass
    +     boolean usingWrapper;       // Set to true when process was launched with a wrapper attached
    +-    BroadcastRecord curReceiver;// receiver currently running in the app
    ++    final ArraySet<BroadcastRecord> curReceivers = new ArraySet<BroadcastRecord>();// receivers currently running in the app
    +     long lastWakeTime;          // How long proc held wake lock at last check
    +     long lastCpuTime;           // How long proc has run CPU at last check
    +     long curCpuTime;            // How long proc has run CPU most recently
    +@@ -427,8 +427,11 @@ final class ProcessRecord {
    +                 pw.print(prefix); pw.print("  - "); pw.println(conProviders.get(i).toShortString());
    +             }
    +         }
    +-        if (curReceiver != null) {
    +-            pw.print(prefix); pw.print("curReceiver="); pw.println(curReceiver);
    ++        if (!curReceivers.isEmpty()) {
    ++            pw.print(prefix); pw.println("Current Receivers:");
    ++            for (int i=0; i < curReceivers.size(); i++) {
    ++                pw.print(prefix); pw.print("  - "); pw.println(curReceivers.valueAt(i));
    ++            }
    +         }
    +         if (receivers.size() > 0) {
    +             pw.print(prefix); pw.println("Receivers:");
     diff --git a/services/tests/Android.mk b/services/tests/Android.mk
     deleted file mode 100644
     index 40369ee..0000000
    @@ -152619,6 +2071,142 @@ index f680e99..0000000
     -        <intent android:action="actionx"/>
     -    </shortcut>
     -</shortcuts>
    +diff --git a/services/tests/servicestests/src/android/net/ConnectivityMetricsLoggerTest.java b/services/tests/servicestests/src/android/net/ConnectivityMetricsLoggerTest.java
    +deleted file mode 100644
    +index 6d42cce..0000000
    +--- a/services/tests/servicestests/src/android/net/ConnectivityMetricsLoggerTest.java
    ++++ /dev/null
    +@@ -1,130 +0,0 @@
    +-/*
    +- * Copyright (C) 2016, 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 android.net;
    +-
    +-import android.os.Bundle;
    +-import android.os.Parcel;
    +-import java.util.List;
    +-import junit.framework.TestCase;
    +-import org.mockito.ArgumentCaptor;
    +-import org.mockito.Mock;
    +-import org.mockito.MockitoAnnotations;
    +-
    +-import static org.mockito.Mockito.any;
    +-import static org.mockito.Mockito.times;
    +-import static org.mockito.Mockito.verify;
    +-import static org.mockito.Mockito.when;
    +-
    +-public class ConnectivityMetricsLoggerTest extends TestCase {
    +-
    +-    // use same Parcel object everywhere for pointer equality
    +-    static final Bundle FAKE_EV = new Bundle();
    +-    static final int FAKE_COMPONENT = 1;
    +-    static final int FAKE_EVENT = 2;
    +-
    +-    @Mock IConnectivityMetricsLogger mService;
    +-    ArgumentCaptor<ConnectivityMetricsEvent> evCaptor;
    +-    ArgumentCaptor<ConnectivityMetricsEvent[]> evArrayCaptor;
    +-
    +-    ConnectivityMetricsLogger mLog;
    +-
    +-    public void setUp() {
    +-        MockitoAnnotations.initMocks(this);
    +-        evCaptor = ArgumentCaptor.forClass(ConnectivityMetricsEvent.class);
    +-        evArrayCaptor = ArgumentCaptor.forClass(ConnectivityMetricsEvent[].class);
    +-        mLog = new ConnectivityMetricsLogger(mService);
    +-    }
    +-
    +-    public void testLogEvents() throws Exception {
    +-        mLog.logEvent(1, FAKE_COMPONENT, FAKE_EVENT, FAKE_EV);
    +-        mLog.logEvent(2, FAKE_COMPONENT, FAKE_EVENT, FAKE_EV);
    +-        mLog.logEvent(3, FAKE_COMPONENT, FAKE_EVENT, FAKE_EV);
    +-
    +-        List<ConnectivityMetricsEvent> gotEvents = verifyEvents(3);
    +-        assertEventsEqual(expectedEvent(1), gotEvents.get(0));
    +-        assertEventsEqual(expectedEvent(2), gotEvents.get(1));
    +-        assertEventsEqual(expectedEvent(3), gotEvents.get(2));
    +-    }
    +-
    +-    public void testLogEventTriggerThrottling() throws Exception {
    +-        when(mService.logEvent(any())).thenReturn(1234L);
    +-
    +-        mLog.logEvent(1, FAKE_COMPONENT, FAKE_EVENT, FAKE_EV);
    +-        mLog.logEvent(2, FAKE_COMPONENT, FAKE_EVENT, FAKE_EV);
    +-
    +-        List<ConnectivityMetricsEvent> gotEvents = verifyEvents(1);
    +-        assertEventsEqual(expectedEvent(1), gotEvents.get(0));
    +-    }
    +-
    +-    public void testLogEventFails() throws Exception {
    +-        when(mService.logEvent(any())).thenReturn(-1L); // Error.
    +-
    +-        mLog.logEvent(1, FAKE_COMPONENT, FAKE_EVENT, FAKE_EV);
    +-        mLog.logEvent(2, FAKE_COMPONENT, FAKE_EVENT, FAKE_EV);
    +-
    +-        List<ConnectivityMetricsEvent> gotEvents = verifyEvents(1);
    +-        assertEventsEqual(expectedEvent(1), gotEvents.get(0));
    +-    }
    +-
    +-    public void testLogEventWhenThrottling() throws Exception {
    +-        when(mService.logEvent(any())).thenReturn(Long.MAX_VALUE); // Throttled
    +-
    +-        // No events are logged. The service is only called once
    +-        // After that, throttling state is maintained locally.
    +-        mLog.logEvent(1, FAKE_COMPONENT, FAKE_EVENT, FAKE_EV);
    +-        mLog.logEvent(2, FAKE_COMPONENT, FAKE_EVENT, FAKE_EV);
    +-
    +-        List<ConnectivityMetricsEvent> gotEvents = verifyEvents(1);
    +-        assertEventsEqual(expectedEvent(1), gotEvents.get(0));
    +-    }
    +-
    +-    public void testLogEventRecoverFromThrottling() throws Exception {
    +-        final long throttleTimeout = System.currentTimeMillis() + 10;
    +-        when(mService.logEvent(any())).thenReturn(throttleTimeout, 0L);
    +-
    +-        mLog.logEvent(1, FAKE_COMPONENT, FAKE_EVENT, FAKE_EV);
    +-        mLog.logEvent(2, FAKE_COMPONENT, FAKE_EVENT, FAKE_EV);
    +-        mLog.logEvent(3, FAKE_COMPONENT, FAKE_EVENT, FAKE_EV);
    +-        Thread.sleep(100);
    +-        mLog.logEvent(53, FAKE_COMPONENT, FAKE_EVENT, FAKE_EV);
    +-
    +-        List<ConnectivityMetricsEvent> gotEvents = verifyEvents(1);
    +-        assertEventsEqual(expectedEvent(1), gotEvents.get(0));
    +-
    +-        verify(mService, times(1)).logEvents(evArrayCaptor.capture());
    +-        ConnectivityMetricsEvent[] gotOtherEvents = evArrayCaptor.getAllValues().get(0);
    +-        assertEquals(ConnectivityMetricsLogger.TAG_SKIPPED_EVENTS, gotOtherEvents[0].eventTag);
    +-        assertEventsEqual(expectedEvent(53), gotOtherEvents[1]);
    +-    }
    +-
    +-    List<ConnectivityMetricsEvent> verifyEvents(int n) throws Exception {
    +-        verify(mService, times(n)).logEvent(evCaptor.capture());
    +-        return evCaptor.getAllValues();
    +-    }
    +-
    +-    static ConnectivityMetricsEvent expectedEvent(int timestamp) {
    +-        return new ConnectivityMetricsEvent((long)timestamp, FAKE_COMPONENT, FAKE_EVENT, FAKE_EV);
    +-    }
    +-
    +-    /** Outer equality for ConnectivityMetricsEvent to avoid overriding equals() and hashCode(). */
    +-    static void assertEventsEqual(ConnectivityMetricsEvent expected, ConnectivityMetricsEvent got) {
    +-        assertEquals(expected.timestamp, got.timestamp);
    +-        assertEquals(expected.componentTag, got.componentTag);
    +-        assertEquals(expected.eventTag, got.eventTag);
    +-        assertEquals(expected.data, got.data);
    +-    }
    +-}
     diff --git a/services/tests/servicestests/src/android/net/IpUtilsTest.java b/services/tests/servicestests/src/android/net/IpUtilsTest.java
     deleted file mode 100644
     index c2d1608..0000000
    @@ -152907,10 +2495,10 @@ index 221fe0f..0000000
     -}
     diff --git a/services/tests/servicestests/src/android/net/apf/ApfTest.java b/services/tests/servicestests/src/android/net/apf/ApfTest.java
     deleted file mode 100644
    -index bd76118..0000000
    +index f7c61d1..0000000
     --- a/services/tests/servicestests/src/android/net/apf/ApfTest.java
     +++ /dev/null
    -@@ -1,1092 +0,0 @@
    +@@ -1,1195 +0,0 @@
     -/*
     - * Copyright (C) 2012 The Android Open Source Project
     - *
    @@ -152933,6 +2521,9 @@ index bd76118..0000000
     -
     -import com.android.frameworks.servicestests.R;
     -
    +-import android.net.LinkAddress;
    +-import android.net.LinkProperties;
    +-import android.net.NetworkUtils;
     -import android.net.apf.ApfCapabilities;
     -import android.net.apf.ApfFilter;
     -import android.net.apf.ApfGenerator;
    @@ -152941,8 +2532,6 @@ index bd76118..0000000
     -import android.net.ip.IpManager;
     -import android.net.metrics.IpConnectivityLog;
     -import android.net.metrics.RaEvent;
    --import android.net.LinkAddress;
    --import android.net.LinkProperties;
     -import android.os.ConditionVariable;
     -import android.os.Parcelable;
     -import android.system.ErrnoException;
    @@ -152974,7 +2563,7 @@ index bd76118..0000000
     - * Tests for APF program generator and interpreter.
     - *
     - * Build, install and run with:
    -- *  runtest frameworks-services -c com.android.server.ApfTest
    +- *  runtest frameworks-services -c android.net.apf.ApfTest
     - */
     -public class ApfTest extends AndroidTestCase {
     -    private static final int TIMEOUT_MS = 500;
    @@ -152999,21 +2588,45 @@ index bd76118..0000000
     -    private final static boolean DROP_MULTICAST = true;
     -    private final static boolean ALLOW_MULTICAST = false;
     -
    +-    private static String label(int code) {
    +-        switch (code) {
    +-            case PASS: return "PASS";
    +-            case DROP: return "DROP";
    +-            default:   return "UNKNOWN";
    +-        }
    +-    }
    +-
    +-    private static void assertReturnCodesEqual(int expected, int got) {
    +-        assertEquals(label(expected), label(got));
    +-    }
    +-
     -    private void assertVerdict(int expected, byte[] program, byte[] packet, int filterAge) {
    --        assertEquals(expected, apfSimulate(program, packet, filterAge));
    +-        assertReturnCodesEqual(expected, apfSimulate(program, packet, filterAge));
    +-    }
    +-
    +-    private void assertVerdict(int expected, byte[] program, byte[] packet) {
    +-        assertReturnCodesEqual(expected, apfSimulate(program, packet, 0));
     -    }
     -
     -    private void assertPass(byte[] program, byte[] packet, int filterAge) {
     -        assertVerdict(PASS, program, packet, filterAge);
     -    }
     -
    +-    private void assertPass(byte[] program, byte[] packet) {
    +-        assertVerdict(PASS, program, packet);
    +-    }
    +-
     -    private void assertDrop(byte[] program, byte[] packet, int filterAge) {
     -        assertVerdict(DROP, program, packet, filterAge);
     -    }
     -
    +-    private void assertDrop(byte[] program, byte[] packet) {
    +-        assertVerdict(DROP, program, packet);
    +-    }
    +-
     -    private void assertVerdict(int expected, ApfGenerator gen, byte[] packet, int filterAge)
     -            throws IllegalInstructionException {
    --        assertEquals(expected, apfSimulate(gen.generate(), packet, filterAge));
    +-        assertReturnCodesEqual(expected, apfSimulate(gen.generate(), packet, filterAge));
     -    }
     -
     -    private void assertPass(ApfGenerator gen, byte[] packet, int filterAge)
    @@ -153429,7 +3042,7 @@ index bd76118..0000000
     -        gen = new ApfGenerator();
     -        gen.addLoadImmediate(Register.R0, 1);
     -        gen.addJumpIfBytesNotEqual(Register.R0, new byte[]{123}, gen.DROP_LABEL);
    --        byte[] packet123 = new byte[]{0,123,0,0,0,0,0,0,0,0,0,0,0,0,0};
    +-        byte[] packet123 = {0,123,0,0,0,0,0,0,0,0,0,0,0,0,0};
     -        assertPass(gen, packet123, 0);
     -        gen = new ApfGenerator();
     -        gen.addJumpIfBytesNotEqual(Register.R0, new byte[]{123}, gen.DROP_LABEL);
    @@ -153437,7 +3050,7 @@ index bd76118..0000000
     -        gen = new ApfGenerator();
     -        gen.addLoadImmediate(Register.R0, 1);
     -        gen.addJumpIfBytesNotEqual(Register.R0, new byte[]{1,2,30,4,5}, gen.DROP_LABEL);
    --        byte[] packet12345 = new byte[]{0,1,2,3,4,5,0,0,0,0,0,0,0,0,0};
    +-        byte[] packet12345 = {0,1,2,3,4,5,0,0,0,0,0,0,0,0,0};
     -        assertDrop(gen, packet12345, 0);
     -        gen = new ApfGenerator();
     -        gen.addLoadImmediate(Register.R0, 1);
    @@ -153488,12 +3101,12 @@ index bd76118..0000000
     -    }
     -
     -    private static class TestApfFilter extends ApfFilter {
    --        public final static byte[] MOCK_MAC_ADDR = new byte[]{1,2,3,4,5,6};
    +-        public final static byte[] MOCK_MAC_ADDR = {1,2,3,4,5,6};
     -        private FileDescriptor mWriteSocket;
     -
     -        public TestApfFilter(IpManager.Callback ipManagerCallback, boolean multicastFilter,
     -                IpConnectivityLog log) throws Exception {
    --            super(new ApfCapabilities(2, 1536, ARPHRD_ETHER), NetworkInterface.getByName("lo"),
    +-            super(new ApfCapabilities(2, 1700, ARPHRD_ETHER), NetworkInterface.getByName("lo"),
     -                    ipManagerCallback, multicastFilter, log);
     -        }
     -
    @@ -153533,19 +3146,21 @@ index bd76118..0000000
     -    private static final int ETH_HEADER_LEN = 14;
     -    private static final int ETH_DEST_ADDR_OFFSET = 0;
     -    private static final int ETH_ETHERTYPE_OFFSET = 12;
    --    private static final byte[] ETH_BROADCAST_MAC_ADDRESS = new byte[]{
    --        (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff };
    +-    private static final byte[] ETH_BROADCAST_MAC_ADDRESS =
    +-            {(byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff };
     -
     -    private static final int IPV4_VERSION_IHL_OFFSET = ETH_HEADER_LEN + 0;
     -    private static final int IPV4_PROTOCOL_OFFSET = ETH_HEADER_LEN + 9;
     -    private static final int IPV4_DEST_ADDR_OFFSET = ETH_HEADER_LEN + 16;
    +-    private static final byte[] IPV4_BROADCAST_ADDRESS =
    +-            {(byte) 255, (byte) 255, (byte) 255, (byte) 255};
     -
     -    private static final int IPV6_NEXT_HEADER_OFFSET = ETH_HEADER_LEN + 6;
     -    private static final int IPV6_HEADER_LEN = 40;
     -    private static final int IPV6_DEST_ADDR_OFFSET = ETH_HEADER_LEN + 24;
     -    // The IPv6 all nodes address ff02::1
     -    private static final byte[] IPV6_ALL_NODES_ADDRESS =
    --            new byte[]{ (byte) 0xff, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 };
    +-            { (byte) 0xff, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 };
     -
     -    private static final int ICMP6_TYPE_OFFSET = ETH_HEADER_LEN + IPV6_HEADER_LEN;
     -    private static final int ICMP6_ROUTER_ADVERTISEMENT = 134;
    @@ -153583,14 +3198,14 @@ index bd76118..0000000
     -    private static final int DHCP_CLIENT_MAC_OFFSET = ETH_HEADER_LEN + UDP_HEADER_LEN + 48;
     -
     -    private static final int ARP_HEADER_OFFSET = ETH_HEADER_LEN;
    --    private static final byte[] ARP_IPV4_REQUEST_HEADER = new byte[]{
    +-    private static final byte[] ARP_IPV4_REQUEST_HEADER = {
     -            0, 1, // Hardware type: Ethernet (1)
     -            8, 0, // Protocol type: IP (0x0800)
     -            6,    // Hardware size: 6
     -            4,    // Protocol size: 4
     -            0, 1  // Opcode: request (1)
     -    };
    --    private static final byte[] ARP_IPV4_REPLY_HEADER = new byte[]{
    +-    private static final byte[] ARP_IPV4_REPLY_HEADER = {
     -            0, 1, // Hardware type: Ethernet (1)
     -            8, 0, // Protocol type: IP (0x0800)
     -            6,    // Hardware size: 6
    @@ -153599,38 +3214,63 @@ index bd76118..0000000
     -    };
     -    private static final int ARP_TARGET_IP_ADDRESS_OFFSET = ETH_HEADER_LEN + 24;
     -
    --    private static final byte[] MOCK_IPV4_ADDR = new byte[]{10, 0, 0, 1};
    --    private static final byte[] ANOTHER_IPV4_ADDR = new byte[]{10, 0, 0, 2};
    --    private static final byte[] IPV4_ANY_HOST_ADDR = new byte[]{0, 0, 0, 0};
    +-    private static final byte[] MOCK_IPV4_ADDR           = {10, 0, 0, 1};
    +-    private static final byte[] MOCK_BROADCAST_IPV4_ADDR = {10, 0, 31, (byte) 255}; // prefix = 19
    +-    private static final byte[] MOCK_MULTICAST_IPV4_ADDR = {(byte) 224, 0, 0, 1};
    +-    private static final byte[] ANOTHER_IPV4_ADDR        = {10, 0, 0, 2};
    +-    private static final byte[] IPV4_ANY_HOST_ADDR       = {0, 0, 0, 0};
     -
     -    @LargeTest
     -    public void testApfFilterIPv4() throws Exception {
     -        MockIpManagerCallback ipManagerCallback = new MockIpManagerCallback();
    +-        LinkAddress link = new LinkAddress(InetAddress.getByAddress(MOCK_IPV4_ADDR), 19);
    +-        LinkProperties lp = new LinkProperties();
    +-        lp.addLinkAddress(link);
    +-
     -        ApfFilter apfFilter = new TestApfFilter(ipManagerCallback, DROP_MULTICAST, mLog);
    +-        apfFilter.setLinkProperties(lp);
    +-
     -        byte[] program = ipManagerCallback.getApfProgram();
     -
     -        // Verify empty packet of 100 zero bytes is passed
     -        ByteBuffer packet = ByteBuffer.wrap(new byte[100]);
    --        assertPass(program, packet.array(), 0);
    +-        assertPass(program, packet.array());
     -
     -        // Verify unicast IPv4 packet is passed
    +-        put(packet, ETH_DEST_ADDR_OFFSET, TestApfFilter.MOCK_MAC_ADDR);
     -        packet.putShort(ETH_ETHERTYPE_OFFSET, (short)ETH_P_IP);
    --        assertPass(program, packet.array(), 0);
    --
    --        // Verify broadcast IPv4, not DHCP to us, is dropped
    --        packet.put(ETH_BROADCAST_MAC_ADDRESS);
    --        assertDrop(program, packet.array(), 0);
    +-        put(packet, IPV4_DEST_ADDR_OFFSET, MOCK_IPV4_ADDR);
    +-        assertPass(program, packet.array());
    +-
    +-        // Verify L2 unicast to IPv4 broadcast addresses is dropped (b/30231088)
    +-        put(packet, IPV4_DEST_ADDR_OFFSET, IPV4_BROADCAST_ADDRESS);
    +-        assertDrop(program, packet.array());
    +-        put(packet, IPV4_DEST_ADDR_OFFSET, MOCK_BROADCAST_IPV4_ADDR);
    +-        assertDrop(program, packet.array());
    +-
    +-        // Verify multicast/broadcast IPv4, not DHCP to us, is dropped
    +-        put(packet, ETH_DEST_ADDR_OFFSET, ETH_BROADCAST_MAC_ADDRESS);
    +-        assertDrop(program, packet.array());
     -        packet.put(IPV4_VERSION_IHL_OFFSET, (byte)0x45);
    --        assertDrop(program, packet.array(), 0);
    +-        assertDrop(program, packet.array());
     -        packet.put(IPV4_PROTOCOL_OFFSET, (byte)IPPROTO_UDP);
    --        assertDrop(program, packet.array(), 0);
    +-        assertDrop(program, packet.array());
     -        packet.putShort(UDP_DESTINATION_PORT_OFFSET, (short)DHCP_CLIENT_PORT);
    --        assertDrop(program, packet.array(), 0);
    +-        assertDrop(program, packet.array());
    +-        put(packet, IPV4_DEST_ADDR_OFFSET, MOCK_MULTICAST_IPV4_ADDR);
    +-        assertDrop(program, packet.array());
    +-        put(packet, IPV4_DEST_ADDR_OFFSET, MOCK_BROADCAST_IPV4_ADDR);
    +-        assertDrop(program, packet.array());
    +-        put(packet, IPV4_DEST_ADDR_OFFSET, IPV4_BROADCAST_ADDRESS);
    +-        assertDrop(program, packet.array());
     -
     -        // Verify broadcast IPv4 DHCP to us is passed
    --        packet.position(DHCP_CLIENT_MAC_OFFSET);
    --        packet.put(TestApfFilter.MOCK_MAC_ADDR);
    --        assertPass(program, packet.array(), 0);
    +-        put(packet, DHCP_CLIENT_MAC_OFFSET, TestApfFilter.MOCK_MAC_ADDR);
    +-        assertPass(program, packet.array());
    +-
    +-        // Verify unicast IPv4 DHCP to us is passed
    +-        put(packet, ETH_DEST_ADDR_OFFSET, TestApfFilter.MOCK_MAC_ADDR);
    +-        assertPass(program, packet.array());
     -
     -        apfFilter.shutdown();
     -    }
    @@ -153644,82 +3284,108 @@ index bd76118..0000000
     -        // Verify empty IPv6 packet is passed
     -        ByteBuffer packet = ByteBuffer.wrap(new byte[100]);
     -        packet.putShort(ETH_ETHERTYPE_OFFSET, (short)ETH_P_IPV6);
    --        assertPass(program, packet.array(), 0);
    +-        assertPass(program, packet.array());
     -
     -        // Verify empty ICMPv6 packet is passed
     -        packet.put(IPV6_NEXT_HEADER_OFFSET, (byte)IPPROTO_ICMPV6);
    --        assertPass(program, packet.array(), 0);
    +-        assertPass(program, packet.array());
     -
     -        // Verify empty ICMPv6 NA packet is passed
     -        packet.put(ICMP6_TYPE_OFFSET, (byte)ICMP6_NEIGHBOR_ANNOUNCEMENT);
    --        assertPass(program, packet.array(), 0);
    +-        assertPass(program, packet.array());
     -
     -        // Verify ICMPv6 NA to ff02::1 is dropped
    --        packet.position(IPV6_DEST_ADDR_OFFSET);
    --        packet.put(IPV6_ALL_NODES_ADDRESS);
    --        assertDrop(program, packet.array(), 0);
    +-        put(packet, IPV6_DEST_ADDR_OFFSET, IPV6_ALL_NODES_ADDRESS);
    +-        assertDrop(program, packet.array());
     -
     -        apfFilter.shutdown();
     -    }
     -
     -    @LargeTest
     -    public void testApfFilterMulticast() throws Exception {
    +-        final byte[] unicastIpv4Addr   = {(byte)192,0,2,63};
    +-        final byte[] broadcastIpv4Addr = {(byte)192,0,2,(byte)255};
    +-        final byte[] multicastIpv4Addr = {(byte)224,0,0,1};
    +-        final byte[] multicastIpv6Addr = {(byte)0xff,2,0,0,0,0,0,0,0,0,0,0,0,0,0,(byte)0xfb};
    +-
     -        MockIpManagerCallback ipManagerCallback = new MockIpManagerCallback();
    +-        LinkAddress link = new LinkAddress(InetAddress.getByAddress(unicastIpv4Addr), 24);
    +-        LinkProperties lp = new LinkProperties();
    +-        lp.addLinkAddress(link);
    +-
     -        ApfFilter apfFilter = new TestApfFilter(ipManagerCallback, ALLOW_MULTICAST, mLog);
    +-        apfFilter.setLinkProperties(lp);
    +-
     -        byte[] program = ipManagerCallback.getApfProgram();
     -
     -        // Construct IPv4 and IPv6 multicast packets.
     -        ByteBuffer mcastv4packet = ByteBuffer.wrap(new byte[100]);
     -        mcastv4packet.putShort(ETH_ETHERTYPE_OFFSET, (short)ETH_P_IP);
    --        mcastv4packet.position(IPV4_DEST_ADDR_OFFSET);
    --        mcastv4packet.put(new byte[]{(byte)224,0,0,1});
    +-        put(mcastv4packet, IPV4_DEST_ADDR_OFFSET, multicastIpv4Addr);
     -
     -        ByteBuffer mcastv6packet = ByteBuffer.wrap(new byte[100]);
     -        mcastv6packet.putShort(ETH_ETHERTYPE_OFFSET, (short)ETH_P_IPV6);
     -        mcastv6packet.put(IPV6_NEXT_HEADER_OFFSET, (byte)IPPROTO_UDP);
    --        mcastv6packet.position(IPV6_DEST_ADDR_OFFSET);
    --        mcastv6packet.put(new byte[]{(byte)0xff,2,0,0,0,0,0,0,0,0,0,0,0,0,0,(byte)0xfb});
    +-        put(mcastv6packet, IPV6_DEST_ADDR_OFFSET, multicastIpv6Addr);
     -
     -        // Construct IPv4 broadcast packet.
    --        ByteBuffer bcastv4packet = ByteBuffer.wrap(new byte[100]);
    --        bcastv4packet.put(ETH_BROADCAST_MAC_ADDRESS);
    --        bcastv4packet.putShort(ETH_ETHERTYPE_OFFSET, (short)ETH_P_IP);
    --        bcastv4packet.position(IPV4_DEST_ADDR_OFFSET);
    --        bcastv4packet.put(new byte[]{(byte)192,(byte)0,(byte)2,(byte)63});
    +-        ByteBuffer bcastv4packet1 = ByteBuffer.wrap(new byte[100]);
    +-        bcastv4packet1.put(ETH_BROADCAST_MAC_ADDRESS);
    +-        bcastv4packet1.putShort(ETH_ETHERTYPE_OFFSET, (short)ETH_P_IP);
    +-        put(bcastv4packet1, IPV4_DEST_ADDR_OFFSET, multicastIpv4Addr);
    +-
    +-        ByteBuffer bcastv4packet2 = ByteBuffer.wrap(new byte[100]);
    +-        bcastv4packet2.put(ETH_BROADCAST_MAC_ADDRESS);
    +-        bcastv4packet2.putShort(ETH_ETHERTYPE_OFFSET, (short)ETH_P_IP);
    +-        put(bcastv4packet2, IPV4_DEST_ADDR_OFFSET, IPV4_BROADCAST_ADDRESS);
    +-
    +-        // Construct IPv4 broadcast with L2 unicast address packet (b/30231088).
    +-        ByteBuffer bcastv4unicastl2packet = ByteBuffer.wrap(new byte[100]);
    +-        bcastv4unicastl2packet.put(TestApfFilter.MOCK_MAC_ADDR);
    +-        bcastv4unicastl2packet.putShort(ETH_ETHERTYPE_OFFSET, (short)ETH_P_IP);
    +-        put(bcastv4unicastl2packet, IPV4_DEST_ADDR_OFFSET, broadcastIpv4Addr);
     -
     -        // Verify initially disabled multicast filter is off
    --        assertPass(program, bcastv4packet.array(), 0);
    --        assertPass(program, mcastv4packet.array(), 0);
    --        assertPass(program, mcastv6packet.array(), 0);
    +-        assertPass(program, mcastv4packet.array());
    +-        assertPass(program, mcastv6packet.array());
    +-        assertPass(program, bcastv4packet1.array());
    +-        assertPass(program, bcastv4packet2.array());
    +-        assertPass(program, bcastv4unicastl2packet.array());
     -
     -        // Turn on multicast filter and verify it works
     -        ipManagerCallback.resetApfProgramWait();
     -        apfFilter.setMulticastFilter(true);
     -        program = ipManagerCallback.getApfProgram();
    --        assertDrop(program, bcastv4packet.array(), 0);
    --        assertDrop(program, mcastv4packet.array(), 0);
    --        assertDrop(program, mcastv6packet.array(), 0);
    +-        assertDrop(program, mcastv4packet.array());
    +-        assertDrop(program, mcastv6packet.array());
    +-        assertDrop(program, bcastv4packet1.array());
    +-        assertDrop(program, bcastv4packet2.array());
    +-        assertDrop(program, bcastv4unicastl2packet.array());
     -
     -        // Turn off multicast filter and verify it's off
     -        ipManagerCallback.resetApfProgramWait();
     -        apfFilter.setMulticastFilter(false);
     -        program = ipManagerCallback.getApfProgram();
    --        assertPass(program, bcastv4packet.array(), 0);
    --        assertPass(program, mcastv4packet.array(), 0);
    --        assertPass(program, mcastv6packet.array(), 0);
    +-        assertPass(program, mcastv4packet.array());
    +-        assertPass(program, mcastv6packet.array());
    +-        assertPass(program, bcastv4packet1.array());
    +-        assertPass(program, bcastv4packet2.array());
    +-        assertPass(program, bcastv4unicastl2packet.array());
     -
     -        // Verify it can be initialized to on
     -        ipManagerCallback.resetApfProgramWait();
     -        apfFilter.shutdown();
     -        apfFilter = new TestApfFilter(ipManagerCallback, DROP_MULTICAST, mLog);
    +-        apfFilter.setLinkProperties(lp);
     -        program = ipManagerCallback.getApfProgram();
    --        assertDrop(program, bcastv4packet.array(), 0);
    --        assertDrop(program, mcastv4packet.array(), 0);
    --        assertDrop(program, mcastv6packet.array(), 0);
    +-        assertDrop(program, mcastv4packet.array());
    +-        assertDrop(program, mcastv6packet.array());
    +-        assertDrop(program, bcastv4packet1.array());
    +-        assertDrop(program, bcastv4unicastl2packet.array());
     -
     -        // Verify that ICMPv6 multicast is not dropped.
     -        mcastv6packet.put(IPV6_NEXT_HEADER_OFFSET, (byte)IPPROTO_ICMPV6);
    --        assertPass(program, mcastv6packet.array(), 0);
    +-        assertPass(program, mcastv6packet.array());
     -
     -        apfFilter.shutdown();
     -    }
    @@ -153732,17 +3398,17 @@ index bd76118..0000000
     -
     -    private void verifyArpFilter(byte[] program, int filterResult) {
     -        // Verify ARP request packet
    --        assertPass(program, arpRequestBroadcast(MOCK_IPV4_ADDR), 0);
    --        assertVerdict(filterResult, program, arpRequestBroadcast(ANOTHER_IPV4_ADDR), 0);
    --        assertDrop(program, arpRequestBroadcast(IPV4_ANY_HOST_ADDR), 0);
    +-        assertPass(program, arpRequestBroadcast(MOCK_IPV4_ADDR));
    +-        assertVerdict(filterResult, program, arpRequestBroadcast(ANOTHER_IPV4_ADDR));
    +-        assertDrop(program, arpRequestBroadcast(IPV4_ANY_HOST_ADDR));
     -
     -        // Verify unicast ARP reply packet is always accepted.
    --        assertPass(program, arpReplyUnicast(MOCK_IPV4_ADDR), 0);
    --        assertPass(program, arpReplyUnicast(ANOTHER_IPV4_ADDR), 0);
    --        assertPass(program, arpReplyUnicast(IPV4_ANY_HOST_ADDR), 0);
    +-        assertPass(program, arpReplyUnicast(MOCK_IPV4_ADDR));
    +-        assertPass(program, arpReplyUnicast(ANOTHER_IPV4_ADDR));
    +-        assertPass(program, arpReplyUnicast(IPV4_ANY_HOST_ADDR));
     -
     -        // Verify GARP reply packets are always filtered
    --        assertDrop(program, garpReply(), 0);
    +-        assertDrop(program, garpReply());
     -    }
     -
     -    @LargeTest
    @@ -153768,34 +3434,26 @@ index bd76118..0000000
     -    private static byte[] arpRequestBroadcast(byte[] tip) {
     -        ByteBuffer packet = ByteBuffer.wrap(new byte[100]);
     -        packet.putShort(ETH_ETHERTYPE_OFFSET, (short)ETH_P_ARP);
    --        packet.position(ETH_DEST_ADDR_OFFSET);
    --        packet.put(ETH_BROADCAST_MAC_ADDRESS);
    --        packet.position(ARP_HEADER_OFFSET);
    --        packet.put(ARP_IPV4_REQUEST_HEADER);
    --        packet.position(ARP_TARGET_IP_ADDRESS_OFFSET);
    --        packet.put(tip);
    +-        put(packet, ETH_DEST_ADDR_OFFSET, ETH_BROADCAST_MAC_ADDRESS);
    +-        put(packet, ARP_HEADER_OFFSET, ARP_IPV4_REPLY_HEADER);
    +-        put(packet, ARP_TARGET_IP_ADDRESS_OFFSET, tip);
     -        return packet.array();
     -    }
     -
     -    private static byte[] arpReplyUnicast(byte[] tip) {
     -        ByteBuffer packet = ByteBuffer.wrap(new byte[100]);
     -        packet.putShort(ETH_ETHERTYPE_OFFSET, (short)ETH_P_ARP);
    --        packet.position(ARP_HEADER_OFFSET);
    --        packet.put(ARP_IPV4_REPLY_HEADER);
    --        packet.position(ARP_TARGET_IP_ADDRESS_OFFSET);
    --        packet.put(tip);
    +-        put(packet, ARP_HEADER_OFFSET, ARP_IPV4_REPLY_HEADER);
    +-        put(packet, ARP_TARGET_IP_ADDRESS_OFFSET, tip);
     -        return packet.array();
     -    }
     -
     -    private static byte[] garpReply() {
     -        ByteBuffer packet = ByteBuffer.wrap(new byte[100]);
     -        packet.putShort(ETH_ETHERTYPE_OFFSET, (short)ETH_P_ARP);
    --        packet.position(ETH_DEST_ADDR_OFFSET);
    --        packet.put(ETH_BROADCAST_MAC_ADDRESS);
    --        packet.position(ARP_HEADER_OFFSET);
    --        packet.put(ARP_IPV4_REPLY_HEADER);
    --        packet.position(ARP_TARGET_IP_ADDRESS_OFFSET);
    --        packet.put(IPV4_ANY_HOST_ADDR);
    +-        put(packet, ETH_DEST_ADDR_OFFSET, ETH_BROADCAST_MAC_ADDRESS);
    +-        put(packet, ARP_HEADER_OFFSET, ARP_IPV4_REPLY_HEADER);
    +-        put(packet, ARP_TARGET_IP_ADDRESS_OFFSET, IPV4_ANY_HOST_ADDR);
     -        return packet.array();
     -    }
     -
    @@ -153806,22 +3464,22 @@ index bd76118..0000000
     -        byte[] program = ipManagerCallback.getApfProgram();
     -
     -        // Verify new program should drop RA for 1/6th its lifetime
    --        assertDrop(program, packet.array(), 0);
    +-        assertDrop(program, packet.array());
     -        assertDrop(program, packet.array(), lifetime/6);
     -        assertPass(program, packet.array(), lifetime/6 + 1);
     -        assertPass(program, packet.array(), lifetime);
     -
     -        // Verify RA checksum is ignored
     -        packet.putShort(ICMP6_RA_CHECKSUM_OFFSET, (short)12345);
    --        assertDrop(program, packet.array(), 0);
    +-        assertDrop(program, packet.array());
     -        packet.putShort(ICMP6_RA_CHECKSUM_OFFSET, (short)-12345);
    --        assertDrop(program, packet.array(), 0);
    +-        assertDrop(program, packet.array());
     -
     -        // Verify other changes to RA make it not match filter
     -        packet.put(0, (byte)-1);
    --        assertPass(program, packet.array(), 0);
    +-        assertPass(program, packet.array());
     -        packet.put(0, (byte)0);
    --        assertDrop(program, packet.array(), 0);
    +-        assertDrop(program, packet.array());
     -    }
     -
     -    // Test that when ApfFilter is shown the given packet, it generates a program to filter it
    @@ -153886,7 +3544,7 @@ index bd76118..0000000
     -        basePacket.putShort(ICMP6_RA_ROUTER_LIFETIME_OFFSET, (short)1000);
     -        basePacket.position(IPV6_DEST_ADDR_OFFSET);
     -        basePacket.put(IPV6_ALL_NODES_ADDRESS);
    --        assertPass(program, basePacket.array(), 0);
    +-        assertPass(program, basePacket.array());
     -
     -        testRaLifetime(apfFilter, ipManagerCallback, basePacket, 1000);
     -        verifyRaEvent(new RaEvent(1000, -1, -1, -1, -1, -1));
    @@ -153982,6 +3640,13 @@ index bd76118..0000000
     -        return file.getAbsolutePath();
     -    }
     -
    +-    private static void put(ByteBuffer buffer, int position, byte[] bytes) {
    +-        final int original = buffer.position();
    +-        buffer.position(position);
    +-        buffer.put(bytes);
    +-        buffer.position(original);
    +-    }
    +-
     -    /**
     -     * Call the APF interpreter the run {@code program} on {@code packet} pretending the
     -     * filter was installed {@code filter_age} seconds ago.
    @@ -154002,6 +3667,32 @@ index bd76118..0000000
     -     */
     -    private native static boolean compareBpfApf(String filter, String pcap_filename,
     -            byte[] apf_program);
    +-
    +-    public void testBytesToInt() {
    +-        assertEquals(0x00000000, ApfFilter.bytesToInt(IPV4_ANY_HOST_ADDR));
    +-        assertEquals(0xffffffff, ApfFilter.bytesToInt(IPV4_BROADCAST_ADDRESS));
    +-        assertEquals(0x0a000001, ApfFilter.bytesToInt(MOCK_IPV4_ADDR));
    +-        assertEquals(0x0a000002, ApfFilter.bytesToInt(ANOTHER_IPV4_ADDR));
    +-        assertEquals(0x0a001fff, ApfFilter.bytesToInt(MOCK_BROADCAST_IPV4_ADDR));
    +-        assertEquals(0xe0000001, ApfFilter.bytesToInt(MOCK_MULTICAST_IPV4_ADDR));
    +-    }
    +-
    +-    public void testBroadcastAddress() throws Exception {
    +-        assertEqualsIp("255.255.255.255", ApfFilter.ipv4BroadcastAddress(IPV4_ANY_HOST_ADDR, 0));
    +-        assertEqualsIp("0.0.0.0", ApfFilter.ipv4BroadcastAddress(IPV4_ANY_HOST_ADDR, 32));
    +-        assertEqualsIp("0.0.3.255", ApfFilter.ipv4BroadcastAddress(IPV4_ANY_HOST_ADDR, 22));
    +-        assertEqualsIp("0.255.255.255", ApfFilter.ipv4BroadcastAddress(IPV4_ANY_HOST_ADDR, 8));
    +-
    +-        assertEqualsIp("255.255.255.255", ApfFilter.ipv4BroadcastAddress(MOCK_IPV4_ADDR, 0));
    +-        assertEqualsIp("10.0.0.1", ApfFilter.ipv4BroadcastAddress(MOCK_IPV4_ADDR, 32));
    +-        assertEqualsIp("10.0.0.255", ApfFilter.ipv4BroadcastAddress(MOCK_IPV4_ADDR, 24));
    +-        assertEqualsIp("10.0.255.255", ApfFilter.ipv4BroadcastAddress(MOCK_IPV4_ADDR, 16));
    +-    }
    +-
    +-    public void assertEqualsIp(String expected, int got) throws Exception {
    +-        int want = ApfFilter.bytesToInt(InetAddress.getByName(expected).getAddress());
    +-        assertEquals(want, got);
    +-    }
     -}
     diff --git a/services/tests/servicestests/src/android/net/apf/Bpf2Apf.java b/services/tests/servicestests/src/android/net/apf/Bpf2Apf.java
     deleted file mode 100644
    @@ -154338,10 +4029,10 @@ index 220e54d..0000000
     -}
     diff --git a/services/tests/servicestests/src/android/net/dhcp/DhcpPacketTest.java b/services/tests/servicestests/src/android/net/dhcp/DhcpPacketTest.java
     deleted file mode 100644
    -index f8eaf7d..0000000
    +index bc8baa1..0000000
     --- a/services/tests/servicestests/src/android/net/dhcp/DhcpPacketTest.java
     +++ /dev/null
    -@@ -1,772 +0,0 @@
    +@@ -1,939 +0,0 @@
     -/*
     - * Copyright (C) 2015 The Android Open Source Project
     - *
    @@ -154360,24 +4051,22 @@ index f8eaf7d..0000000
     -
     -package android.net.dhcp;
     -
    --import android.net.NetworkUtils;
     -import android.net.DhcpResults;
     -import android.net.LinkAddress;
    +-import android.net.NetworkUtils;
    +-import android.net.metrics.DhcpErrorEvent;
     -import android.system.OsConstants;
     -import android.test.suitebuilder.annotation.SmallTest;
     -import com.android.internal.util.HexDump;
    --
     -import java.net.Inet4Address;
     -import java.nio.ByteBuffer;
     -import java.util.ArrayList;
    --
    --import junit.framework.TestCase;
    --import libcore.util.HexEncoding;
     -import java.util.Arrays;
    +-import java.util.Random;
    +-import junit.framework.TestCase;
     -
     -import static android.net.dhcp.DhcpPacket.*;
     -
    --
     -public class DhcpPacketTest extends TestCase {
     -
     -    private static Inet4Address SERVER_ADDR = v4Address("192.0.2.1");
    @@ -154629,7 +4318,7 @@ index f8eaf7d..0000000
     -        // TODO: Turn all of these into golden files. This will probably require modifying
     -        // Android.mk appropriately, making this into an AndroidTestCase, and adding code to read
     -        // the golden files from the test APK's assets via mContext.getAssets().
    --        final ByteBuffer packet = ByteBuffer.wrap(HexEncoding.decode((
    +-        final ByteBuffer packet = ByteBuffer.wrap(HexDump.hexStringToByteArray(
     -            // IP header.
     -            "451001480000000080118849c0a89003c0a89ff7" +
     -            // UDP header.
    @@ -154648,8 +4337,7 @@ index f8eaf7d..0000000
     -            "0000000000000000000000000000000000000000000000000000000000000000" +
     -            // Options
     -            "638253633501023604c0a89003330400001c200104fffff0000304c0a89ffe06080808080808080404" +
    --            "3a0400000e103b040000189cff00000000000000000000"
    --        ).toCharArray(), false));
    +-            "3a0400000e103b040000189cff00000000000000000000"));
     -
     -        DhcpPacket offerPacket = DhcpPacket.decodeFullPacket(packet, ENCAP_L3);
     -        assertTrue(offerPacket instanceof DhcpOfferPacket);  // Implicitly checks it's non-null.
    @@ -154660,7 +4348,7 @@ index f8eaf7d..0000000
     -
     -    @SmallTest
     -    public void testOffer2() throws Exception {
    --        final ByteBuffer packet = ByteBuffer.wrap(HexEncoding.decode((
    +-        final ByteBuffer packet = ByteBuffer.wrap(HexDump.hexStringToByteArray(
     -            // IP header.
     -            "450001518d0600004011144dc0a82b01c0a82bf7" +
     -            // UDP header.
    @@ -154679,8 +4367,7 @@ index f8eaf7d..0000000
     -            "0000000000000000000000000000000000000000000000000000000000000000" +
     -            // Options
     -            "638253633501023604c0a82b01330400000e103a04000007083b0400000c4e0104ffffff00" +
    --            "1c04c0a82bff0304c0a82b010604c0a82b012b0f414e44524f49445f4d455445524544ff"
    --        ).toCharArray(), false));
    +-            "1c04c0a82bff0304c0a82b010604c0a82b012b0f414e44524f49445f4d455445524544ff"));
     -
     -        assertEquals(337, packet.limit());
     -        DhcpPacket offerPacket = DhcpPacket.decodeFullPacket(packet, ENCAP_L3);
    @@ -154691,6 +4378,185 @@ index f8eaf7d..0000000
     -        assertTrue(dhcpResults.hasMeteredHint());
     -    }
     -
    +-    @SmallTest
    +-    public void testBadIpPacket() throws Exception {
    +-        final byte[] packet = HexDump.hexStringToByteArray(
    +-            // IP header.
    +-            "450001518d0600004011144dc0a82b01c0a82bf7");
    +-
    +-        try {
    +-            DhcpPacket offerPacket = DhcpPacket.decodeFullPacket(packet, packet.length, ENCAP_L3);
    +-        } catch (DhcpPacket.ParseException expected) {
    +-            assertDhcpErrorCodes(DhcpErrorEvent.L3_TOO_SHORT, expected.errorCode);
    +-            return;
    +-        }
    +-        fail("Dhcp packet parsing should have failed");
    +-    }
    +-
    +-    @SmallTest
    +-    public void testBadDhcpPacket() throws Exception {
    +-        final byte[] packet = HexDump.hexStringToByteArray(
    +-            // IP header.
    +-            "450001518d0600004011144dc0a82b01c0a82bf7" +
    +-            // UDP header.
    +-            "00430044013d9ac7" +
    +-            // BOOTP header.
    +-            "02010600dfc23d1f0002000000000000c0a82bf7c0a82b0100000000");
    +-
    +-        try {
    +-            DhcpPacket offerPacket = DhcpPacket.decodeFullPacket(packet, packet.length, ENCAP_L3);
    +-        } catch (DhcpPacket.ParseException expected) {
    +-            assertDhcpErrorCodes(DhcpErrorEvent.L3_TOO_SHORT, expected.errorCode);
    +-            return;
    +-        }
    +-        fail("Dhcp packet parsing should have failed");
    +-    }
    +-
    +-    @SmallTest
    +-    public void testBadTruncatedOffer() throws Exception {
    +-        final byte[] packet = HexDump.hexStringToByteArray(
    +-            // IP header.
    +-            "450001518d0600004011144dc0a82b01c0a82bf7" +
    +-            // UDP header.
    +-            "00430044013d9ac7" +
    +-            // BOOTP header.
    +-            "02010600dfc23d1f0002000000000000c0a82bf7c0a82b0100000000" +
    +-            // MAC address.
    +-            "30766ff2a90c00000000000000000000" +
    +-            // Server name.
    +-            "0000000000000000000000000000000000000000000000000000000000000000" +
    +-            "0000000000000000000000000000000000000000000000000000000000000000" +
    +-            // File, missing one byte
    +-            "0000000000000000000000000000000000000000000000000000000000000000" +
    +-            "0000000000000000000000000000000000000000000000000000000000000000" +
    +-            "0000000000000000000000000000000000000000000000000000000000000000" +
    +-            "00000000000000000000000000000000000000000000000000000000000000");
    +-
    +-        try {
    +-            DhcpPacket offerPacket = DhcpPacket.decodeFullPacket(packet, packet.length, ENCAP_L3);
    +-        } catch (DhcpPacket.ParseException expected) {
    +-            assertDhcpErrorCodes(DhcpErrorEvent.L3_TOO_SHORT, expected.errorCode);
    +-            return;
    +-        }
    +-        fail("Dhcp packet parsing should have failed");
    +-    }
    +-
    +-    @SmallTest
    +-    public void testBadOfferWithoutACookie() throws Exception {
    +-        final byte[] packet = HexDump.hexStringToByteArray(
    +-            // IP header.
    +-            "450001518d0600004011144dc0a82b01c0a82bf7" +
    +-            // UDP header.
    +-            "00430044013d9ac7" +
    +-            // BOOTP header.
    +-            "02010600dfc23d1f0002000000000000c0a82bf7c0a82b0100000000" +
    +-            // MAC address.
    +-            "30766ff2a90c00000000000000000000" +
    +-            // Server name.
    +-            "0000000000000000000000000000000000000000000000000000000000000000" +
    +-            "0000000000000000000000000000000000000000000000000000000000000000" +
    +-            // File.
    +-            "0000000000000000000000000000000000000000000000000000000000000000" +
    +-            "0000000000000000000000000000000000000000000000000000000000000000" +
    +-            "0000000000000000000000000000000000000000000000000000000000000000" +
    +-            "0000000000000000000000000000000000000000000000000000000000000000"
    +-            // No options
    +-            );
    +-
    +-        try {
    +-            DhcpPacket offerPacket = DhcpPacket.decodeFullPacket(packet, packet.length, ENCAP_L3);
    +-        } catch (DhcpPacket.ParseException expected) {
    +-            assertDhcpErrorCodes(DhcpErrorEvent.DHCP_NO_COOKIE, expected.errorCode);
    +-            return;
    +-        }
    +-        fail("Dhcp packet parsing should have failed");
    +-    }
    +-
    +-    @SmallTest
    +-    public void testOfferWithBadCookie() throws Exception {
    +-        final byte[] packet = HexDump.hexStringToByteArray(
    +-            // IP header.
    +-            "450001518d0600004011144dc0a82b01c0a82bf7" +
    +-            // UDP header.
    +-            "00430044013d9ac7" +
    +-            // BOOTP header.
    +-            "02010600dfc23d1f0002000000000000c0a82bf7c0a82b0100000000" +
    +-            // MAC address.
    +-            "30766ff2a90c00000000000000000000" +
    +-            // Server name.
    +-            "0000000000000000000000000000000000000000000000000000000000000000" +
    +-            "0000000000000000000000000000000000000000000000000000000000000000" +
    +-            // File.
    +-            "0000000000000000000000000000000000000000000000000000000000000000" +
    +-            "0000000000000000000000000000000000000000000000000000000000000000" +
    +-            "0000000000000000000000000000000000000000000000000000000000000000" +
    +-            "0000000000000000000000000000000000000000000000000000000000000000" +
    +-            // Bad cookie
    +-            "DEADBEEF3501023604c0a82b01330400000e103a04000007083b0400000c4e0104ffffff00" +
    +-            "1c04c0a82bff0304c0a82b010604c0a82b012b0f414e44524f49445f4d455445524544ff");
    +-
    +-        try {
    +-            DhcpPacket offerPacket = DhcpPacket.decodeFullPacket(packet, packet.length, ENCAP_L3);
    +-        } catch (DhcpPacket.ParseException expected) {
    +-            assertDhcpErrorCodes(DhcpErrorEvent.DHCP_BAD_MAGIC_COOKIE, expected.errorCode);
    +-            return;
    +-        }
    +-        fail("Dhcp packet parsing should have failed");
    +-    }
    +-
    +-    private void assertDhcpErrorCodes(int expected, int got) {
    +-        assertEquals(Integer.toHexString(expected), Integer.toHexString(got));
    +-    }
    +-
    +-    public void testTruncatedOfferPackets() throws Exception {
    +-        final byte[] packet = HexDump.hexStringToByteArray(
    +-            // IP header.
    +-            "450001518d0600004011144dc0a82b01c0a82bf7" +
    +-            // UDP header.
    +-            "00430044013d9ac7" +
    +-            // BOOTP header.
    +-            "02010600dfc23d1f0002000000000000c0a82bf7c0a82b0100000000" +
    +-            // MAC address.
    +-            "30766ff2a90c00000000000000000000" +
    +-            // Server name.
    +-            "0000000000000000000000000000000000000000000000000000000000000000" +
    +-            "0000000000000000000000000000000000000000000000000000000000000000" +
    +-            // File.
    +-            "0000000000000000000000000000000000000000000000000000000000000000" +
    +-            "0000000000000000000000000000000000000000000000000000000000000000" +
    +-            "0000000000000000000000000000000000000000000000000000000000000000" +
    +-            "0000000000000000000000000000000000000000000000000000000000000000" +
    +-            // Options
    +-            "638253633501023604c0a82b01330400000e103a04000007083b0400000c4e0104ffffff00" +
    +-            "1c04c0a82bff0304c0a82b010604c0a82b012b0f414e44524f49445f4d455445524544ff");
    +-
    +-        for (int len = 0; len < packet.length; len++) {
    +-            try {
    +-                DhcpPacket.decodeFullPacket(packet, len, ENCAP_L3);
    +-            } catch (ParseException e) {
    +-                if (e.errorCode == DhcpErrorEvent.PARSING_ERROR) {
    +-                    fail(String.format("bad truncated packet of length %d", len));
    +-                }
    +-            }
    +-        }
    +-    }
    +-
    +-    public void testRandomPackets() throws Exception {
    +-        final int maxRandomPacketSize = 512;
    +-        final Random r = new Random();
    +-        for (int i = 0; i < 10000; i++) {
    +-            byte[] packet = new byte[r.nextInt(maxRandomPacketSize + 1)];
    +-            r.nextBytes(packet);
    +-            try {
    +-                DhcpPacket.decodeFullPacket(packet, packet.length, ENCAP_L3);
    +-            } catch (ParseException e) {
    +-                if (e.errorCode == DhcpErrorEvent.PARSING_ERROR) {
    +-                    fail("bad packet: " + HexDump.toHexString(packet));
    +-                }
    +-            }
    +-        }
    +-    }
    +-
     -    private byte[] mtuBytes(int mtu) {
     -        // 0x1a02: option 26, length 2. 0xff: no more options.
     -        if (mtu > Short.MAX_VALUE - Short.MIN_VALUE) {
    @@ -154698,7 +4564,7 @@ index f8eaf7d..0000000
     -                String.format("Invalid MTU %d, must be 16-bit unsigned", mtu));
     -        }
     -        String hexString = String.format("1a02%04xff", mtu);
    --        return HexEncoding.decode(hexString.toCharArray(), false);
    +-        return HexDump.hexStringToByteArray(hexString);
     -    }
     -
     -    private void checkMtu(ByteBuffer packet, int expectedMtu, byte[] mtuBytes) throws Exception {
    @@ -154716,7 +4582,7 @@ index f8eaf7d..0000000
     -
     -    @SmallTest
     -    public void testMtu() throws Exception {
    --        final ByteBuffer packet = ByteBuffer.wrap(HexEncoding.decode((
    +-        final ByteBuffer packet = ByteBuffer.wrap(HexDump.hexStringToByteArray(
     -            // IP header.
     -            "451001480000000080118849c0a89003c0a89ff7" +
     -            // UDP header.
    @@ -154735,8 +4601,7 @@ index f8eaf7d..0000000
     -            "0000000000000000000000000000000000000000000000000000000000000000" +
     -            // Options
     -            "638253633501023604c0a89003330400001c200104fffff0000304c0a89ffe06080808080808080404" +
    --            "3a0400000e103b040000189cff00000000"
    --        ).toCharArray(), false));
    +-            "3a0400000e103b040000189cff00000000"));
     -
     -        checkMtu(packet, 0, null);
     -        checkMtu(packet, 0, mtuBytes(1501));
    @@ -154753,7 +4618,7 @@ index f8eaf7d..0000000
     -
     -    @SmallTest
     -    public void testBadHwaddrLength() throws Exception {
    --        final ByteBuffer packet = ByteBuffer.wrap(HexEncoding.decode((
    +-        final ByteBuffer packet = ByteBuffer.wrap(HexDump.hexStringToByteArray(
     -            // IP header.
     -            "450001518d0600004011144dc0a82b01c0a82bf7" +
     -            // UDP header.
    @@ -154772,8 +4637,7 @@ index f8eaf7d..0000000
     -            "0000000000000000000000000000000000000000000000000000000000000000" +
     -            // Options
     -            "638253633501023604c0a82b01330400000e103a04000007083b0400000c4e0104ffffff00" +
    --            "1c04c0a82bff0304c0a82b010604c0a82b012b0f414e44524f49445f4d455445524544ff"
    --        ).toCharArray(), false));
    +-            "1c04c0a82bff0304c0a82b010604c0a82b012b0f414e44524f49445f4d455445524544ff"));
     -        String expectedClientMac = "30766FF2A90C";
     -
     -        final int hwAddrLenOffset = 20 + 8 + 2;
    @@ -154830,7 +4694,7 @@ index f8eaf7d..0000000
     -        //    store any information in the overloaded fields).
     -        //
     -        // For now, we just check that it parses correctly.
    --        final ByteBuffer packet = ByteBuffer.wrap(HexEncoding.decode((
    +-        final ByteBuffer packet = ByteBuffer.wrap(HexDump.hexStringToByteArray(
     -            // Ethernet header.
     -            "b4cef6000000e80462236e300800" +
     -            // IP header.
    @@ -154851,8 +4715,7 @@ index f8eaf7d..0000000
     -            "0000000000000000000000000000000000000000000000000000000000000000" +
     -            // Options
     -            "638253633501023604010101010104ffff000033040000a8c03401030304ac1101010604ac110101" +
    --            "0000000000000000000000000000000000000000000000ff000000"
    --        ).toCharArray(), false));
    +-            "0000000000000000000000000000000000000000000000ff000000"));
     -
     -        DhcpPacket offerPacket = DhcpPacket.decodeFullPacket(packet, ENCAP_L2);
     -        assertTrue(offerPacket instanceof DhcpOfferPacket);
    @@ -154863,7 +4726,7 @@ index f8eaf7d..0000000
     -
     -    @SmallTest
     -    public void testBug2111() throws Exception {
    --        final ByteBuffer packet = ByteBuffer.wrap(HexEncoding.decode((
    +-        final ByteBuffer packet = ByteBuffer.wrap(HexDump.hexStringToByteArray(
     -            // IP header.
     -            "4500014c00000000ff119beac3eaf3880a3f5d04" +
     -            // UDP header. TODO: fix invalid checksum (due to MAC address obfuscation).
    @@ -154882,8 +4745,7 @@ index f8eaf7d..0000000
     -            "0000000000000000000000000000000000000000000000000000000000000000" +
     -            // Options.
     -            "638253633501023604c00002fe33040000bfc60104fffff00003040a3f50010608c0000201c0000202" +
    --            "0f0f646f6d61696e3132332e636f2e756b0000000000ff00000000"
    --        ).toCharArray(), false));
    +-            "0f0f646f6d61696e3132332e636f2e756b0000000000ff00000000"));
     -
     -        DhcpPacket offerPacket = DhcpPacket.decodeFullPacket(packet, ENCAP_L3);
     -        assertTrue(offerPacket instanceof DhcpOfferPacket);
    @@ -154894,7 +4756,7 @@ index f8eaf7d..0000000
     -
     -    @SmallTest
     -    public void testBug2136() throws Exception {
    --        final ByteBuffer packet = ByteBuffer.wrap(HexEncoding.decode((
    +-        final ByteBuffer packet = ByteBuffer.wrap(HexDump.hexStringToByteArray(
     -            // Ethernet header.
     -            "bcf5ac000000d0c7890000000800" +
     -            // IP header.
    @@ -154915,8 +4777,7 @@ index f8eaf7d..0000000
     -            "0000000000000000000000000000000000000000000000000000000000000000" +
     -            // Options.
     -            "6382536335010236040a20ff80330400001c200104fffff00003040a20900106089458413494584135" +
    --            "0f0b6c616e63732e61632e756b000000000000000000ff00000000"
    --        ).toCharArray(), false));
    +-            "0f0b6c616e63732e61632e756b000000000000000000ff00000000"));
     -
     -        DhcpPacket offerPacket = DhcpPacket.decodeFullPacket(packet, ENCAP_L2);
     -        assertTrue(offerPacket instanceof DhcpOfferPacket);
    @@ -154928,7 +4789,7 @@ index f8eaf7d..0000000
     -
     -    @SmallTest
     -    public void testUdpServerAnySourcePort() throws Exception {
    --        final ByteBuffer packet = ByteBuffer.wrap(HexEncoding.decode((
    +-        final ByteBuffer packet = ByteBuffer.wrap(HexDump.hexStringToByteArray(
     -            // Ethernet header.
     -            "9cd917000000001c2e0000000800" +
     -            // IP header.
    @@ -154950,8 +4811,7 @@ index f8eaf7d..0000000
     -            "0000000000000000000000000000000000000000000000000000000000000000" +
     -            // Options.
     -            "6382536335010236040a0169fc3304000151800104ffff000003040a0fc817060cd1818003d1819403" +
    --            "d18180060f0777766d2e6564751c040a0fffffff000000"
    --        ).toCharArray(), false));
    +-            "d18180060f0777766d2e6564751c040a0fffffff000000"));
     -
     -        DhcpPacket offerPacket = DhcpPacket.decodeFullPacket(packet, ENCAP_L2);
     -        assertTrue(offerPacket instanceof DhcpOfferPacket);
    @@ -154964,7 +4824,7 @@ index f8eaf7d..0000000
     -
     -    @SmallTest
     -    public void testUdpInvalidDstPort() throws Exception {
    --        final ByteBuffer packet = ByteBuffer.wrap(HexEncoding.decode((
    +-        final ByteBuffer packet = ByteBuffer.wrap(HexDump.hexStringToByteArray(
     -            // Ethernet header.
     -            "9cd917000000001c2e0000000800" +
     -            // IP header.
    @@ -154986,8 +4846,7 @@ index f8eaf7d..0000000
     -            "0000000000000000000000000000000000000000000000000000000000000000" +
     -            // Options.
     -            "6382536335010236040a0169fc3304000151800104ffff000003040a0fc817060cd1818003d1819403" +
    --            "d18180060f0777766d2e6564751c040a0fffffff000000"
    --        ).toCharArray(), false));
    +-            "d18180060f0777766d2e6564751c040a0fffffff000000"));
     -
     -        try {
     -            DhcpPacket.decodeFullPacket(packet, ENCAP_L2);
    @@ -154997,7 +4856,7 @@ index f8eaf7d..0000000
     -
     -    @SmallTest
     -    public void testMultipleRouters() throws Exception {
    --        final ByteBuffer packet = ByteBuffer.wrap(HexEncoding.decode((
    +-        final ByteBuffer packet = ByteBuffer.wrap(HexDump.hexStringToByteArray(
     -            // Ethernet header.
     -            "fc3d93000000" + "081735000000" + "0800" +
     -            // IP header.
    @@ -155018,8 +4877,7 @@ index f8eaf7d..0000000
     -            "0000000000000000000000000000000000000000000000000000000000000000" +
     -            // Options.
     -            "638253633501023604c0abbd023304000070803a04000038403b04000062700104ffffff00" +
    --            "0308c0a8bd01ffffff0006080808080808080404ff000000000000"
    --        ).toCharArray(), false));
    +-            "0308c0a8bd01ffffff0006080808080808080404ff000000000000"));
     -
     -        DhcpPacket offerPacket = DhcpPacket.decodeFullPacket(packet, ENCAP_L2);
     -        assertTrue(offerPacket instanceof DhcpOfferPacket);
    @@ -155114,174 +4972,6 @@ index f8eaf7d..0000000
     -        assertTrue(msg, Arrays.equals(expected, actual));
     -    }
     -}
    -diff --git a/services/tests/servicestests/src/android/net/metrics/IpConnectivityLogTest.java b/services/tests/servicestests/src/android/net/metrics/IpConnectivityLogTest.java
    -deleted file mode 100644
    -index 1433f95..0000000
    ---- a/services/tests/servicestests/src/android/net/metrics/IpConnectivityLogTest.java
    -+++ /dev/null
    -@@ -1,162 +0,0 @@
    --/*
    -- * Copyright (C) 2016, 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 android.net.metrics;
    --
    --import android.os.Bundle;
    --import android.os.Parcel;
    --import android.net.ConnectivityMetricsEvent;
    --import android.net.IConnectivityMetricsLogger;
    --
    --import junit.framework.TestCase;
    --import org.junit.Before;
    --import org.junit.Test;
    --
    --import org.mockito.ArgumentCaptor;
    --import org.mockito.Mock;
    --import org.mockito.MockitoAnnotations;
    --import static org.mockito.Mockito.any;
    --import static org.mockito.Mockito.eq;
    --import static org.mockito.Mockito.timeout;
    --import static org.mockito.Mockito.times;
    --import static org.mockito.Mockito.verify;
    --import static org.mockito.Mockito.when;
    --
    --import java.util.List;
    --
    --public class IpConnectivityLogTest extends TestCase {
    --
    --    // use same Parcel object everywhere for pointer equality
    --    static final Bundle FAKE_EV = new Bundle();
    --
    --    @Mock IConnectivityMetricsLogger mService;
    --    ArgumentCaptor<ConnectivityMetricsEvent> evCaptor;
    --
    --    IpConnectivityLog mLog;
    --
    --    public void setUp() {
    --        MockitoAnnotations.initMocks(this);
    --        evCaptor = ArgumentCaptor.forClass(ConnectivityMetricsEvent.class);
    --        mLog = new IpConnectivityLog(mService);
    --    }
    --
    --    public void testLogEvents() throws Exception {
    --        assertTrue(mLog.log(1, FAKE_EV));
    --        assertTrue(mLog.log(2, FAKE_EV));
    --        assertTrue(mLog.log(3, FAKE_EV));
    --
    --        List<ConnectivityMetricsEvent> gotEvents = verifyEvents(3);
    --        assertEventsEqual(expectedEvent(1), gotEvents.get(0));
    --        assertEventsEqual(expectedEvent(2), gotEvents.get(1));
    --        assertEventsEqual(expectedEvent(3), gotEvents.get(2));
    --    }
    --
    --    public void testLogEventTriggerThrottling() throws Exception {
    --        when(mService.logEvent(any())).thenReturn(1234L);
    --
    --        assertFalse(mLog.log(1, FAKE_EV));
    --    }
    --
    --    public void testLogEventFails() throws Exception {
    --        when(mService.logEvent(any())).thenReturn(-1L); // Error.
    --
    --        assertFalse(mLog.log(1, FAKE_EV));
    --    }
    --
    --    public void testLogEventWhenThrottling() throws Exception {
    --        when(mService.logEvent(any())).thenReturn(Long.MAX_VALUE); // Throttled
    --
    --        // No events are logged. The service is only called once
    --        // After that, throttling state is maintained locally.
    --        assertFalse(mLog.log(1, FAKE_EV));
    --        assertFalse(mLog.log(2, FAKE_EV));
    --
    --        List<ConnectivityMetricsEvent> gotEvents = verifyEvents(1);
    --        assertEventsEqual(expectedEvent(1), gotEvents.get(0));
    --    }
    --
    --    public void testLogEventRecoverFromThrottling() throws Exception {
    --        final long throttleTimeout = System.currentTimeMillis() + 50;
    --        when(mService.logEvent(any())).thenReturn(throttleTimeout, 0L);
    --
    --        assertFalse(mLog.log(1, FAKE_EV));
    --        new Thread() {
    --            public void run() {
    --                busySpinLog();
    --            }
    --        }.start();
    --
    --        List<ConnectivityMetricsEvent> gotEvents = verifyEvents(2, 200);
    --        assertEventsEqual(expectedEvent(1), gotEvents.get(0));
    --        assertEventsEqual(expectedEvent(2), gotEvents.get(1));
    --    }
    --
    --    public void testLogEventRecoverFromThrottlingWithMultipleCallers() throws Exception {
    --        final long throttleTimeout = System.currentTimeMillis() + 50;
    --        when(mService.logEvent(any())).thenReturn(throttleTimeout, 0L);
    --
    --        assertFalse(mLog.log(1, FAKE_EV));
    --        final int nCallers = 10;
    --        for (int i = 0; i < nCallers; i++) {
    --            new Thread() {
    --                public void run() {
    --                    busySpinLog();
    --                }
    --            }.start();
    --        }
    --
    --        List<ConnectivityMetricsEvent> gotEvents = verifyEvents(1 + nCallers, 200);
    --        assertEventsEqual(expectedEvent(1), gotEvents.get(0));
    --        for (int i = 0; i < nCallers; i++) {
    --            assertEventsEqual(expectedEvent(2), gotEvents.get(1 + i));
    --        }
    --    }
    --
    --    void busySpinLog() {
    --        final long timeout = 200;
    --        final long stop = System.currentTimeMillis() + timeout;
    --        try {
    --            while (System.currentTimeMillis() < stop) {
    --                if (mLog.log(2, FAKE_EV)) {
    --                    return;
    --                }
    --                Thread.sleep(10);
    --            }
    --        } catch (InterruptedException e) { }
    --    }
    --
    --    List<ConnectivityMetricsEvent> verifyEvents(int n) throws Exception {
    --        verify(mService, times(n)).logEvent(evCaptor.capture());
    --        return evCaptor.getAllValues();
    --    }
    --
    --    List<ConnectivityMetricsEvent> verifyEvents(int n, int timeoutMs) throws Exception {
    --        verify(mService, timeout(timeoutMs).times(n)).logEvent(evCaptor.capture());
    --        return evCaptor.getAllValues();
    --    }
    --
    --    static ConnectivityMetricsEvent expectedEvent(int timestamp) {
    --        return new ConnectivityMetricsEvent((long)timestamp, 0, 0, FAKE_EV);
    --    }
    --
    --    /** Outer equality for ConnectivityMetricsEvent to avoid overriding equals() and hashCode(). */
    --    static void assertEventsEqual(ConnectivityMetricsEvent expected, ConnectivityMetricsEvent got) {
    --        assertEquals(expected.timestamp, got.timestamp);
    --        assertEquals(expected.componentTag, got.componentTag);
    --        assertEquals(expected.eventTag, got.eventTag);
    --        assertEquals(expected.data, got.data);
    --    }
    --}
     diff --git a/services/tests/servicestests/src/android/net/netlink/NetlinkErrorMessageTest.java b/services/tests/servicestests/src/android/net/netlink/NetlinkErrorMessageTest.java
     deleted file mode 100644
     index e677475..0000000
    @@ -157246,18 +6936,13 @@ index 10b9e7c..0000000
     -    }
     -}
     diff --git a/services/tests/servicestests/src/com/android/server/ConnectivityServiceTest.java b/services/tests/servicestests/src/com/android/server/ConnectivityServiceTest.java
    -index a656acc..c2c6e21 100644
    +index 4af1cf1..c2c6e21 100644
     --- a/services/tests/servicestests/src/com/android/server/ConnectivityServiceTest.java
     +++ b/services/tests/servicestests/src/com/android/server/ConnectivityServiceTest.java
    -@@ -597,7 +597,20 @@ public class ConnectivityServiceTest extends AndroidTestCase {
    +@@ -614,6 +614,19 @@ public class ConnectivityServiceTest extends AndroidTestCase {
    +         }
    +     }
      
    -         @Override
    -         protected CaptivePortalProbeResult isCaptivePortal() {
    --            return new CaptivePortalProbeResult(gen204ProbeResult, gen204ProbeRedirectUrl);
    -+            return new CaptivePortalProbeResult(gen204ProbeResult, gen204ProbeRedirectUrl, null);
    -+        }
    -+    }
    -+
     +    private class WrappedAvoidBadWifiTracker extends AvoidBadWifiTracker {
     +        public boolean configRestrictsAvoidBadWifi;
     +
    @@ -157268,123 +6953,12 @@ index a656acc..c2c6e21 100644
     +        @Override
     +        public boolean configRestrictsAvoidBadWifi() {
     +            return configRestrictsAvoidBadWifi;
    -         }
    -     }
    - 
    -@@ -746,6 +759,7 @@ public class ConnectivityServiceTest extends AndroidTestCase {
    -     }
    - 
    -     public void tearDown() throws Exception {
    -+        setMobileDataAlwaysOn(false);
    -         if (mCellNetworkAgent != null) { mCellNetworkAgent.disconnect(); }
    -         if (mWiFiNetworkAgent != null) { mWiFiNetworkAgent.disconnect(); }
    -         mCellNetworkAgent = mWiFiNetworkAgent = null;
    -@@ -1843,6 +1857,85 @@ public class ConnectivityServiceTest extends AndroidTestCase {
    -         mCm.unregisterNetworkCallback(cellNetworkCallback);
    -     }
    - 
    -+    private void setMobileDataAlwaysOn(boolean enable) {
    -+        ContentResolver cr = mServiceContext.getContentResolver();
    -+        Settings.Global.putInt(cr, Settings.Global.MOBILE_DATA_ALWAYS_ON, enable ? 1 : 0);
    -+        mService.updateMobileDataAlwaysOn();
    -+        mService.waitForIdle();
    -+    }
    -+
    -+    private boolean isForegroundNetwork(MockNetworkAgent network) {
    -+        NetworkCapabilities nc = mCm.getNetworkCapabilities(network.getNetwork());
    -+        assertNotNull(nc);
    -+        return nc.hasCapability(NET_CAPABILITY_FOREGROUND);
    -+    }
    -+
    -+    @SmallTest
    -+    public void testBackgroundNetworks() throws Exception {
    -+        // Create a background request. We can't do this ourselves because ConnectivityService
    -+        // doesn't have an API for it. So just turn on mobile data always on.
    -+        setMobileDataAlwaysOn(true);
    -+        final NetworkRequest request = new NetworkRequest.Builder().build();
    -+        final NetworkRequest fgRequest = new NetworkRequest.Builder()
    -+                .addCapability(NET_CAPABILITY_FOREGROUND).build();
    -+        final TestNetworkCallback callback = new TestNetworkCallback();
    -+        final TestNetworkCallback fgCallback = new TestNetworkCallback();
    -+        mCm.registerNetworkCallback(request, callback);
    -+        mCm.registerNetworkCallback(fgRequest, fgCallback);
    -+
    -+        mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR);
    -+        mCellNetworkAgent.connect(true);
    -+        callback.expectCallback(CallbackState.AVAILABLE, mCellNetworkAgent);
    -+        fgCallback.expectCallback(CallbackState.AVAILABLE, mCellNetworkAgent);
    -+        assertTrue(isForegroundNetwork(mCellNetworkAgent));
    -+
    -+        mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
    -+        mWiFiNetworkAgent.connect(true);
    -+
    -+        // When wifi connects, cell lingers.
    -+        callback.expectCallback(CallbackState.AVAILABLE, mWiFiNetworkAgent);
    -+        fgCallback.expectCallback(CallbackState.AVAILABLE, mWiFiNetworkAgent);
    -+        callback.expectCallback(CallbackState.LOSING, mCellNetworkAgent);
    -+        fgCallback.expectCallback(CallbackState.LOSING, mCellNetworkAgent);
    -+        assertTrue(isForegroundNetwork(mCellNetworkAgent));
    -+        assertTrue(isForegroundNetwork(mWiFiNetworkAgent));
    -+
    -+        // When lingering is complete, cell is still there but is now in the background.
    -+        fgCallback.expectCallback(CallbackState.LOST, mCellNetworkAgent, TEST_LINGER_DELAY_MS);
    -+        callback.assertNoCallback();
    -+        assertFalse(isForegroundNetwork(mCellNetworkAgent));
    -+        assertTrue(isForegroundNetwork(mWiFiNetworkAgent));
    -+
    -+        // File a cell request and check that cell comes into the foreground.
    -+        final NetworkRequest cellRequest = new NetworkRequest.Builder()
    -+                .addTransportType(TRANSPORT_CELLULAR).build();
    -+        final TestNetworkCallback cellCallback = new TestNetworkCallback();
    -+        mCm.requestNetwork(cellRequest, cellCallback);
    -+        cellCallback.expectCallback(CallbackState.AVAILABLE, mCellNetworkAgent);
    -+        fgCallback.expectCallback(CallbackState.AVAILABLE, mCellNetworkAgent);
    -+        callback.assertNoCallback();  // Because the network is already up.
    -+        assertTrue(isForegroundNetwork(mCellNetworkAgent));
    -+        assertTrue(isForegroundNetwork(mWiFiNetworkAgent));
    -+
    -+        // Release the request. The network immediately goes into the background, since it was not
    -+        // lingering.
    -+        mCm.unregisterNetworkCallback(cellCallback);
    -+        fgCallback.expectCallback(CallbackState.LOST, mCellNetworkAgent);
    -+        callback.assertNoCallback();
    -+        assertFalse(isForegroundNetwork(mCellNetworkAgent));
    -+        assertTrue(isForegroundNetwork(mWiFiNetworkAgent));
    -+
    -+        // Disconnect wifi and check that cell is foreground again.
    -+        mWiFiNetworkAgent.disconnect();
    -+        callback.expectCallback(CallbackState.LOST, mWiFiNetworkAgent);
    -+        fgCallback.expectCallback(CallbackState.LOST, mWiFiNetworkAgent);
    -+        fgCallback.expectCallback(CallbackState.AVAILABLE, mCellNetworkAgent);
    -+        assertTrue(isForegroundNetwork(mCellNetworkAgent));
    -+
    -+        mCm.unregisterNetworkCallback(callback);
    -+        mCm.unregisterNetworkCallback(fgCallback);
    ++        }
     +    }
     +
    -     @SmallTest
    -     public void testRequestBenchmark() throws Exception {
    -         // Benchmarks connecting and switching performance in the presence of a large number of
    -@@ -1948,8 +2041,7 @@ public class ConnectivityServiceTest extends AndroidTestCase {
    - 
    -         // Turn on mobile data always on. The factory starts looking again.
    -         testFactory.expectAddRequests(1);
    --        Settings.Global.putInt(cr, Settings.Global.MOBILE_DATA_ALWAYS_ON, 1);
    --        mService.updateMobileDataAlwaysOn();
    -+        setMobileDataAlwaysOn(true);
    -         testFactory.waitForNetworkRequests(2);
    -         assertTrue(testFactory.getMyStartRequested());
    - 
    -@@ -1969,8 +2061,7 @@ public class ConnectivityServiceTest extends AndroidTestCase {
    - 
    -         // Turn off mobile data always on and expect the request to disappear...
    -         testFactory.expectRemoveRequests(1);
    --        Settings.Global.putInt(cr, Settings.Global.MOBILE_DATA_ALWAYS_ON, 0);
    --        mService.updateMobileDataAlwaysOn();
    -+        setMobileDataAlwaysOn(false);
    -         testFactory.waitForNetworkRequests(1);
    - 
    -         // ...  and cell data to be torn down.
    +     private class WrappedConnectivityService extends ConnectivityService {
    +         public WrappedAvoidBadWifiTracker wrappedAvoidBadWifiTracker;
    +         private WrappedNetworkMonitor mLastCreatedNetworkMonitor;
     diff --git a/services/tests/servicestests/src/com/android/server/CountryDetectorServiceTest.java b/services/tests/servicestests/src/com/android/server/CountryDetectorServiceTest.java
     deleted file mode 100644
     index 192c50c..0000000
    @@ -160760,10 +10334,10 @@ index 88dbe70..0000000
     -}
     diff --git a/services/tests/servicestests/src/com/android/server/accounts/AccountManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/accounts/AccountManagerServiceTest.java
     deleted file mode 100644
    -index 404c142..0000000
    +index a3d0afa..0000000
     --- a/services/tests/servicestests/src/com/android/server/accounts/AccountManagerServiceTest.java
     +++ /dev/null
    -@@ -1,456 +0,0 @@
    +@@ -1,466 +0,0 @@
     -/*
     - * Copyright (C) 2009 The Android Open Source Project
     - *
    @@ -160787,6 +10361,7 @@ index 404c142..0000000
     -import static org.mockito.Mockito.when;
     -
     -import android.accounts.Account;
    +-import android.accounts.AccountManagerInternal;
     -import android.accounts.AuthenticatorDescription;
     -import android.app.AppOpsManager;
     -import android.app.Notification;
    @@ -160810,6 +10385,8 @@ index 404c142..0000000
     -import android.test.mock.MockPackageManager;
     -import android.util.Log;
     -
    +-import com.android.server.LocalServices;
    +-
     -import java.io.File;
     -import java.io.FileDescriptor;
     -import java.io.PrintWriter;
    @@ -160839,6 +10416,7 @@ index 404c142..0000000
     -        SQLiteDatabase.deleteDatabase(new File(mAms.getCeDatabaseName(UserHandle.USER_SYSTEM)));
     -        SQLiteDatabase.deleteDatabase(new File(mAms.getDeDatabaseName(UserHandle.USER_SYSTEM)));
     -        SQLiteDatabase.deleteDatabase(new File(mAms.getPreNDatabaseName(UserHandle.USER_SYSTEM)));
    +-        LocalServices.removeServiceForTest(AccountManagerInternal.class);
     -        super.tearDown();
     -    }
     -
    @@ -161048,6 +10626,7 @@ index 404c142..0000000
     -
     -    private AccountManagerService createAccountManagerService(Context mockContext,
     -            Context realContext) {
    +-        LocalServices.removeServiceForTest(AccountManagerInternal.class);
     -        return new MyAccountManagerService(mockContext,
     -                new MyMockPackageManager(), new MockAccountAuthenticatorCache(), realContext);
     -    }
    @@ -161186,6 +10765,11 @@ index 404c142..0000000
     -        public int checkSignatures(final int uid1, final int uid2) {
     -            return PackageManager.SIGNATURE_MATCH;
     -        }
    +-
    +-        @Override
    +-        public void addOnPermissionsChangeListener(
    +-                OnPermissionsChangedListener listener) {
    +-        }
     -    }
     -
     -    static public class MyAccountManagerService extends AccountManagerService {
    @@ -161388,7 +10972,7 @@ index bd9e6d1..0000000
     \ No newline at end of file
     diff --git a/services/tests/servicestests/src/com/android/server/am/TaskPersisterTest.java b/services/tests/servicestests/src/com/android/server/am/TaskPersisterTest.java
     deleted file mode 100644
    -index e440a0d..0000000
    +index 984a484..0000000
     --- a/services/tests/servicestests/src/com/android/server/am/TaskPersisterTest.java
     +++ /dev/null
     @@ -1,85 +0,0 @@
    @@ -161456,7 +11040,7 @@ index e440a0d..0000000
     -        for (int i = 0; i < 100; i++) {
     -            taskIdsOnFile.put(getRandomTaskIdForUser(testUserId), true);
     -        }
    --        mTaskPersister.maybeWritePersistedTaskIdsForUser(taskIdsOnFile, testUserId);
    +-        mTaskPersister.writePersistedTaskIdsForUser(taskIdsOnFile, testUserId);
     -        SparseBooleanArray newTaskIdsOnFile = mTaskPersister
     -                .loadPersistedTaskIdsForUser(testUserId);
     -        assertTrue("TaskIds written differ from TaskIds read back from file",
    @@ -161681,6 +11265,646 @@ index 033b2c9..0000000
     -                && Arrays.equals(expected.latenciesMs, got.latenciesMs));
     -    }
     -}
    +diff --git a/services/tests/servicestests/src/com/android/server/connectivity/IpConnectivityEventBuilderTest.java b/services/tests/servicestests/src/com/android/server/connectivity/IpConnectivityEventBuilderTest.java
    +deleted file mode 100644
    +index aed3635..0000000
    +--- a/services/tests/servicestests/src/com/android/server/connectivity/IpConnectivityEventBuilderTest.java
    ++++ /dev/null
    +@@ -1,359 +0,0 @@
    +-/*
    +- * Copyright (C) 2016 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 com.android.server.connectivity;
    +-
    +-import android.net.ConnectivityMetricsEvent;
    +-import android.net.metrics.ApfProgramEvent;
    +-import android.net.metrics.ApfStats;
    +-import android.net.metrics.DefaultNetworkEvent;
    +-import android.net.metrics.DhcpClientEvent;
    +-import android.net.metrics.DhcpErrorEvent;
    +-import android.net.metrics.DnsEvent;
    +-import android.net.metrics.IpManagerEvent;
    +-import android.net.metrics.IpReachabilityEvent;
    +-import android.net.metrics.NetworkEvent;
    +-import android.net.metrics.RaEvent;
    +-import android.net.metrics.ValidationProbeEvent;
    +-import com.google.protobuf.nano.MessageNano;
    +-import java.util.Arrays;
    +-import junit.framework.TestCase;
    +-
    +-import static com.android.server.connectivity.metrics.IpConnectivityLogClass.IpConnectivityLog;
    +-import static com.android.server.connectivity.MetricsTestUtil.aBool;
    +-import static com.android.server.connectivity.MetricsTestUtil.aByteArray;
    +-import static com.android.server.connectivity.MetricsTestUtil.aLong;
    +-import static com.android.server.connectivity.MetricsTestUtil.aString;
    +-import static com.android.server.connectivity.MetricsTestUtil.aType;
    +-import static com.android.server.connectivity.MetricsTestUtil.anInt;
    +-import static com.android.server.connectivity.MetricsTestUtil.anIntArray;
    +-import static com.android.server.connectivity.MetricsTestUtil.b;
    +-import static com.android.server.connectivity.MetricsTestUtil.describeIpEvent;
    +-import static com.android.server.connectivity.MetricsTestUtil.ipEv;
    +-
    +-public class IpConnectivityEventBuilderTest extends TestCase {
    +-
    +-    public void testDefaultNetworkEventSerialization() {
    +-        ConnectivityMetricsEvent ev = describeIpEvent(
    +-                aType(DefaultNetworkEvent.class),
    +-                anInt(102),
    +-                anIntArray(1, 2, 3),
    +-                anInt(101),
    +-                aBool(true),
    +-                aBool(false));
    +-
    +-        String want = joinLines(
    +-                "dropped_events: 0",
    +-                "events <",
    +-                "  default_network_event <",
    +-                "    network_id <",
    +-                "      network_id: 102",
    +-                "    >",
    +-                "    previous_network_id <",
    +-                "      network_id: 101",
    +-                "    >",
    +-                "    previous_network_ip_support: 1",
    +-                "    transport_types: 1",
    +-                "    transport_types: 2",
    +-                "    transport_types: 3",
    +-                "  >",
    +-                "  time_ms: 1",
    +-                ">");
    +-
    +-        verifySerialization(want, ev);
    +-    }
    +-
    +-    public void testDhcpClientEventSerialization() {
    +-        ConnectivityMetricsEvent ev = describeIpEvent(
    +-                aType(DhcpClientEvent.class),
    +-                aString("wlan0"),
    +-                aString("SomeState"),
    +-                anInt(192));
    +-
    +-        String want = joinLines(
    +-                "dropped_events: 0",
    +-                "events <",
    +-                "  dhcp_event <",
    +-                "    duration_ms: 192",
    +-                "    error_code: 0",
    +-                "    if_name: \"wlan0\"",
    +-                "    state_transition: \"SomeState\"",
    +-                "  >",
    +-                "  time_ms: 1",
    +-                ">");
    +-
    +-        verifySerialization(want, ev);
    +-    }
    +-
    +-    public void testDhcpErrorEventSerialization() {
    +-        ConnectivityMetricsEvent ev = describeIpEvent(
    +-                aType(DhcpErrorEvent.class),
    +-                aString("wlan0"),
    +-                anInt(DhcpErrorEvent.L4_NOT_UDP));
    +-
    +-        String want = joinLines(
    +-                "dropped_events: 0",
    +-                "events <",
    +-                "  dhcp_event <",
    +-                "    duration_ms: 0",
    +-                "    error_code: 50397184",
    +-                "    if_name: \"wlan0\"",
    +-                "    state_transition: \"\"",
    +-                "  >",
    +-                "  time_ms: 1",
    +-                ">");
    +-
    +-        verifySerialization(want, ev);
    +-    }
    +-
    +-    public void testDnsEventSerialization() {
    +-        ConnectivityMetricsEvent ev = describeIpEvent(
    +-                aType(DnsEvent.class),
    +-                anInt(101),
    +-                aByteArray(b(1), b(1), b(2), b(1), b(1), b(1), b(2), b(2)),
    +-                aByteArray(b(0), b(0), b(22), b(3), b(1), b(0), b(200), b(178)),
    +-                anIntArray(3456, 267, 1230, 45, 2111, 450, 638, 1300));
    +-
    +-        String want = joinLines(
    +-                "dropped_events: 0",
    +-                "events <",
    +-                "  dns_lookup_batch <",
    +-                "    event_types: 1",
    +-                "    event_types: 1",
    +-                "    event_types: 2",
    +-                "    event_types: 1",
    +-                "    event_types: 1",
    +-                "    event_types: 1",
    +-                "    event_types: 2",
    +-                "    event_types: 2",
    +-                "    latencies_ms: 3456",
    +-                "    latencies_ms: 267",
    +-                "    latencies_ms: 1230",
    +-                "    latencies_ms: 45",
    +-                "    latencies_ms: 2111",
    +-                "    latencies_ms: 450",
    +-                "    latencies_ms: 638",
    +-                "    latencies_ms: 1300",
    +-                "    network_id <",
    +-                "      network_id: 101",
    +-                "    >",
    +-                "    return_codes: 0",
    +-                "    return_codes: 0",
    +-                "    return_codes: 22",
    +-                "    return_codes: 3",
    +-                "    return_codes: 1",
    +-                "    return_codes: 0",
    +-                "    return_codes: 200",
    +-                "    return_codes: 178",
    +-                "  >",
    +-                "  time_ms: 1",
    +-                ">");
    +-
    +-        verifySerialization(want, ev);
    +-    }
    +-
    +-    public void testIpManagerEventSerialization() {
    +-        ConnectivityMetricsEvent ev = describeIpEvent(
    +-                aType(IpManagerEvent.class),
    +-                aString("wlan0"),
    +-                anInt(IpManagerEvent.PROVISIONING_OK),
    +-                aLong(5678));
    +-
    +-        String want = joinLines(
    +-                "dropped_events: 0",
    +-                "events <",
    +-                "  ip_provisioning_event <",
    +-                "    event_type: 1",
    +-                "    if_name: \"wlan0\"",
    +-                "    latency_ms: 5678",
    +-                "  >",
    +-                "  time_ms: 1",
    +-                ">");
    +-
    +-        verifySerialization(want, ev);
    +-    }
    +-
    +-    public void testIpReachabilityEventSerialization() {
    +-        ConnectivityMetricsEvent ev = describeIpEvent(
    +-                aType(IpReachabilityEvent.class),
    +-                aString("wlan0"),
    +-                anInt(IpReachabilityEvent.NUD_FAILED));
    +-
    +-        String want = joinLines(
    +-                "dropped_events: 0",
    +-                "events <",
    +-                "  ip_reachability_event <",
    +-                "    event_type: 512",
    +-                "    if_name: \"wlan0\"",
    +-                "  >",
    +-                "  time_ms: 1",
    +-                ">");
    +-
    +-        verifySerialization(want, ev);
    +-    }
    +-
    +-    public void testNetworkEventSerialization() {
    +-        ConnectivityMetricsEvent ev = describeIpEvent(
    +-                aType(NetworkEvent.class),
    +-                anInt(100),
    +-                anInt(5),
    +-                aLong(20410));
    +-
    +-        String want = joinLines(
    +-                "dropped_events: 0",
    +-                "events <",
    +-                "  network_event <",
    +-                "    event_type: 5",
    +-                "    latency_ms: 20410",
    +-                "    network_id <",
    +-                "      network_id: 100",
    +-                "    >",
    +-                "  >",
    +-                "  time_ms: 1",
    +-                ">");
    +-
    +-        verifySerialization(want, ev);
    +-    }
    +-
    +-    public void testValidationProbeEventSerialization() {
    +-        ConnectivityMetricsEvent ev = describeIpEvent(
    +-                aType(ValidationProbeEvent.class),
    +-                anInt(120),
    +-                aLong(40730),
    +-                anInt(ValidationProbeEvent.PROBE_HTTP),
    +-                anInt(204));
    +-
    +-        String want = joinLines(
    +-                "dropped_events: 0",
    +-                "events <",
    +-                "  time_ms: 1",
    +-                "  validation_probe_event <",
    +-                "    latency_ms: 40730",
    +-                "    network_id <",
    +-                "      network_id: 120",
    +-                "    >",
    +-                "    probe_result: 204",
    +-                "    probe_type: 1",
    +-                "  >",
    +-                ">");
    +-
    +-        verifySerialization(want, ev);
    +-    }
    +-
    +-    public void testApfProgramEventSerialization() {
    +-        ConnectivityMetricsEvent ev = describeIpEvent(
    +-                aType(ApfProgramEvent.class),
    +-                aLong(200),
    +-                anInt(7),
    +-                anInt(9),
    +-                anInt(2048),
    +-                anInt(3));
    +-
    +-        String want = joinLines(
    +-                "dropped_events: 0",
    +-                "events <",
    +-                "  apf_program_event <",
    +-                "    current_ras: 9",
    +-                "    drop_multicast: true",
    +-                "    filtered_ras: 7",
    +-                "    has_ipv4_addr: true",
    +-                "    lifetime: 200",
    +-                "    program_length: 2048",
    +-                "  >",
    +-                "  time_ms: 1",
    +-                ">");
    +-
    +-        verifySerialization(want, ev);
    +-    }
    +-
    +-    public void testApfStatsSerialization() {
    +-        ConnectivityMetricsEvent ev = describeIpEvent(
    +-                aType(ApfStats.class),
    +-                aLong(45000),
    +-                anInt(10),
    +-                anInt(2),
    +-                anInt(2),
    +-                anInt(1),
    +-                anInt(2),
    +-                anInt(4),
    +-                anInt(2048));
    +-
    +-        String want = joinLines(
    +-                "dropped_events: 0",
    +-                "events <",
    +-                "  apf_statistics <",
    +-                "    dropped_ras: 2",
    +-                "    duration_ms: 45000",
    +-                "    matching_ras: 2",
    +-                "    max_program_size: 2048",
    +-                "    parse_errors: 2",
    +-                "    program_updates: 4",
    +-                "    received_ras: 10",
    +-                "    zero_lifetime_ras: 1",
    +-                "  >",
    +-                "  time_ms: 1",
    +-                ">");
    +-
    +-        verifySerialization(want, ev);
    +-    }
    +-
    +-    public void testRaEventSerialization() {
    +-        ConnectivityMetricsEvent ev = describeIpEvent(
    +-                aType(RaEvent.class),
    +-                aLong(2000),
    +-                aLong(400),
    +-                aLong(300),
    +-                aLong(-1),
    +-                aLong(1000),
    +-                aLong(-1));
    +-
    +-        String want = joinLines(
    +-                "dropped_events: 0",
    +-                "events <",
    +-                "  ra_event <",
    +-                "    dnssl_lifetime: -1",
    +-                "    prefix_preferred_lifetime: 300",
    +-                "    prefix_valid_lifetime: 400",
    +-                "    rdnss_lifetime: 1000",
    +-                "    route_info_lifetime: -1",
    +-                "    router_lifetime: 2000",
    +-                "  >",
    +-                "  time_ms: 1",
    +-                ">");
    +-
    +-        verifySerialization(want, ev);
    +-    }
    +-
    +-    static void verifySerialization(String want, ConnectivityMetricsEvent... input) {
    +-        try {
    +-            byte[] got = IpConnectivityEventBuilder.serialize(0, Arrays.asList(input));
    +-            IpConnectivityLog log = new IpConnectivityLog();
    +-            MessageNano.mergeFrom(log, got);
    +-            assertEquals(want, log.toString());
    +-        } catch (Exception e) {
    +-            fail(e.toString());
    +-        }
    +-    }
    +-
    +-    static String joinLines(String ... elems) {
    +-        StringBuilder b = new StringBuilder();
    +-        for (String s : elems) {
    +-            b.append(s);
    +-            b.append("\n");
    +-        }
    +-        return b.toString();
    +-    }
    +-}
    +diff --git a/services/tests/servicestests/src/com/android/server/connectivity/IpConnectivityMetricsTest.java b/services/tests/servicestests/src/com/android/server/connectivity/IpConnectivityMetricsTest.java
    +deleted file mode 100644
    +index 3fc89b9..0000000
    +--- a/services/tests/servicestests/src/com/android/server/connectivity/IpConnectivityMetricsTest.java
    ++++ /dev/null
    +@@ -1,269 +0,0 @@
    +-/*
    +- * Copyright (C) 2016, 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 com.android.server.connectivity;
    +-
    +-import android.content.Context;
    +-import android.net.ConnectivityMetricsEvent;
    +-import android.net.IIpConnectivityMetrics;
    +-import android.net.metrics.ApfStats;
    +-import android.net.metrics.DefaultNetworkEvent;
    +-import android.net.metrics.DhcpClientEvent;
    +-import android.net.metrics.IpConnectivityLog;
    +-import android.net.metrics.IpManagerEvent;
    +-import android.net.metrics.IpReachabilityEvent;
    +-import android.net.metrics.RaEvent;
    +-import android.net.metrics.ValidationProbeEvent;
    +-import android.os.Parcelable;
    +-import android.util.Base64;
    +-import com.android.server.connectivity.metrics.IpConnectivityLogClass;
    +-import com.google.protobuf.nano.MessageNano;
    +-import java.io.PrintWriter;
    +-import java.io.StringWriter;
    +-import java.util.Collections;
    +-import java.util.Comparator;
    +-import java.util.Iterator;
    +-import java.util.List;
    +-import junit.framework.TestCase;
    +-import org.mockito.ArgumentCaptor;
    +-import org.mockito.Mock;
    +-import org.mockito.MockitoAnnotations;
    +-
    +-import static org.mockito.Mockito.timeout;
    +-import static org.mockito.Mockito.times;
    +-import static org.mockito.Mockito.verify;
    +-
    +-public class IpConnectivityMetricsTest extends TestCase {
    +-    static final IpReachabilityEvent FAKE_EV =
    +-            new IpReachabilityEvent("wlan0", IpReachabilityEvent.NUD_FAILED);
    +-
    +-    @Mock Context mCtx;
    +-    @Mock IIpConnectivityMetrics mMockService;
    +-
    +-    IpConnectivityMetrics mService;
    +-
    +-    public void setUp() {
    +-        MockitoAnnotations.initMocks(this);
    +-        mService = new IpConnectivityMetrics(mCtx);
    +-    }
    +-
    +-    public void testLoggingEvents() throws Exception {
    +-        IpConnectivityLog logger = new IpConnectivityLog(mMockService);
    +-
    +-        assertTrue(logger.log(1, FAKE_EV));
    +-        assertTrue(logger.log(2, FAKE_EV));
    +-        assertTrue(logger.log(3, FAKE_EV));
    +-
    +-        List<ConnectivityMetricsEvent> got = verifyEvents(3);
    +-        assertEventsEqual(expectedEvent(1), got.get(0));
    +-        assertEventsEqual(expectedEvent(2), got.get(1));
    +-        assertEventsEqual(expectedEvent(3), got.get(2));
    +-    }
    +-
    +-    public void testLoggingEventsWithMultipleCallers() throws Exception {
    +-        IpConnectivityLog logger = new IpConnectivityLog(mMockService);
    +-
    +-        final int nCallers = 10;
    +-        final int nEvents = 10;
    +-        for (int n = 0; n < nCallers; n++) {
    +-            final int i = n;
    +-            new Thread() {
    +-                public void run() {
    +-                    for (int j = 0; j < nEvents; j++) {
    +-                        assertTrue(logger.log(i * 100 + j, FAKE_EV));
    +-                    }
    +-                }
    +-            }.start();
    +-        }
    +-
    +-        List<ConnectivityMetricsEvent> got = verifyEvents(nCallers * nEvents, 100);
    +-        Collections.sort(got, EVENT_COMPARATOR);
    +-        Iterator<ConnectivityMetricsEvent> iter = got.iterator();
    +-        for (int i = 0; i < nCallers; i++) {
    +-            for (int j = 0; j < nEvents; j++) {
    +-                int expectedTimestamp = i * 100 + j;
    +-                assertEventsEqual(expectedEvent(expectedTimestamp), iter.next());
    +-            }
    +-        }
    +-    }
    +-
    +-    public void testBufferFlushing() {
    +-        String output1 = getdump("flush");
    +-        assertEquals("", output1);
    +-
    +-        new IpConnectivityLog(mService.impl).log(1, FAKE_EV);
    +-        String output2 = getdump("flush");
    +-        assertFalse("".equals(output2));
    +-
    +-        String output3 = getdump("flush");
    +-        assertEquals("", output3);
    +-    }
    +-
    +-    public void testEndToEndLogging() {
    +-        IpConnectivityLog logger = new IpConnectivityLog(mService.impl);
    +-
    +-        Parcelable[] events = {
    +-            new IpReachabilityEvent("wlan0", IpReachabilityEvent.NUD_FAILED),
    +-            new DhcpClientEvent("wlan0", "SomeState", 192),
    +-            new DefaultNetworkEvent(102, new int[]{1,2,3}, 101, true, false),
    +-            new IpManagerEvent("wlan0", IpManagerEvent.PROVISIONING_OK, 5678),
    +-            new ValidationProbeEvent(120, 40730, ValidationProbeEvent.PROBE_HTTP, 204),
    +-            new ApfStats(45000, 10, 2, 2, 1, 2, 4, 2048),
    +-            new RaEvent(2000, 400, 300, -1, 1000, -1)
    +-        };
    +-
    +-        for (int i = 0; i < events.length; i++) {
    +-            logger.log(100 * (i + 1), events[i]);
    +-        }
    +-
    +-        String want = joinLines(
    +-                "dropped_events: 0",
    +-                "events <",
    +-                "  ip_reachability_event <",
    +-                "    event_type: 512",
    +-                "    if_name: \"wlan0\"",
    +-                "  >",
    +-                "  time_ms: 100",
    +-                ">",
    +-                "events <",
    +-                "  dhcp_event <",
    +-                "    duration_ms: 192",
    +-                "    error_code: 0",
    +-                "    if_name: \"wlan0\"",
    +-                "    state_transition: \"SomeState\"",
    +-                "  >",
    +-                "  time_ms: 200",
    +-                ">",
    +-                "events <",
    +-                "  default_network_event <",
    +-                "    network_id <",
    +-                "      network_id: 102",
    +-                "    >",
    +-                "    previous_network_id <",
    +-                "      network_id: 101",
    +-                "    >",
    +-                "    previous_network_ip_support: 1",
    +-                "    transport_types: 1",
    +-                "    transport_types: 2",
    +-                "    transport_types: 3",
    +-                "  >",
    +-                "  time_ms: 300",
    +-                ">",
    +-                "events <",
    +-                "  ip_provisioning_event <",
    +-                "    event_type: 1",
    +-                "    if_name: \"wlan0\"",
    +-                "    latency_ms: 5678",
    +-                "  >",
    +-                "  time_ms: 400",
    +-                ">",
    +-                "events <",
    +-                "  time_ms: 500",
    +-                "  validation_probe_event <",
    +-                "    latency_ms: 40730",
    +-                "    network_id <",
    +-                "      network_id: 120",
    +-                "    >",
    +-                "    probe_result: 204",
    +-                "    probe_type: 1",
    +-                "  >",
    +-                ">",
    +-                "events <",
    +-                "  apf_statistics <",
    +-                "    dropped_ras: 2",
    +-                "    duration_ms: 45000",
    +-                "    matching_ras: 2",
    +-                "    max_program_size: 2048",
    +-                "    parse_errors: 2",
    +-                "    program_updates: 4",
    +-                "    received_ras: 10",
    +-                "    zero_lifetime_ras: 1",
    +-                "  >",
    +-                "  time_ms: 600",
    +-                ">",
    +-                "events <",
    +-                "  ra_event <",
    +-                "    dnssl_lifetime: -1",
    +-                "    prefix_preferred_lifetime: 300",
    +-                "    prefix_valid_lifetime: 400",
    +-                "    rdnss_lifetime: 1000",
    +-                "    route_info_lifetime: -1",
    +-                "    router_lifetime: 2000",
    +-                "  >",
    +-                "  time_ms: 700",
    +-                ">");
    +-
    +-        verifySerialization(want, getdump("flush"));
    +-    }
    +-
    +-    String getdump(String ... command) {
    +-        StringWriter buffer = new StringWriter();
    +-        PrintWriter writer = new PrintWriter(buffer);
    +-        mService.impl.dump(null, writer, command);
    +-        return buffer.toString();
    +-    }
    +-
    +-    List<ConnectivityMetricsEvent> verifyEvents(int n, int timeoutMs) throws Exception {
    +-        ArgumentCaptor<ConnectivityMetricsEvent> captor =
    +-                ArgumentCaptor.forClass(ConnectivityMetricsEvent.class);
    +-        verify(mMockService, timeout(timeoutMs).times(n)).logEvent(captor.capture());
    +-        return captor.getAllValues();
    +-    }
    +-
    +-    List<ConnectivityMetricsEvent> verifyEvents(int n) throws Exception {
    +-        return verifyEvents(n, 10);
    +-    }
    +-
    +-    static void verifySerialization(String want, String output) {
    +-        try {
    +-            byte[] got = Base64.decode(output, Base64.DEFAULT);
    +-            IpConnectivityLogClass.IpConnectivityLog log =
    +-                    new IpConnectivityLogClass.IpConnectivityLog();
    +-            MessageNano.mergeFrom(log, got);
    +-            assertEquals(want, log.toString());
    +-        } catch (Exception e) {
    +-            fail(e.toString());
    +-        }
    +-    }
    +-
    +-    static String joinLines(String ... elems) {
    +-        StringBuilder b = new StringBuilder();
    +-        for (String s : elems) {
    +-            b.append(s).append("\n");
    +-        }
    +-        return b.toString();
    +-    }
    +-
    +-    static ConnectivityMetricsEvent expectedEvent(int timestamp) {
    +-        return new ConnectivityMetricsEvent((long)timestamp, 0, 0, FAKE_EV);
    +-    }
    +-
    +-    /** Outer equality for ConnectivityMetricsEvent to avoid overriding equals() and hashCode(). */
    +-    static void assertEventsEqual(ConnectivityMetricsEvent expected, ConnectivityMetricsEvent got) {
    +-        assertEquals(expected.timestamp, got.timestamp);
    +-        assertEquals(expected.componentTag, got.componentTag);
    +-        assertEquals(expected.eventTag, got.eventTag);
    +-        assertEquals(expected.data, got.data);
    +-    }
    +-
    +-    static final Comparator<ConnectivityMetricsEvent> EVENT_COMPARATOR =
    +-        new Comparator<ConnectivityMetricsEvent>() {
    +-            @Override
    +-            public int compare(ConnectivityMetricsEvent ev1, ConnectivityMetricsEvent ev2) {
    +-                return (int) (ev1.timestamp - ev2.timestamp);
    +-            }
    +-        };
    +-}
     diff --git a/services/tests/servicestests/src/com/android/server/connectivity/LingerMonitorTest.java b/services/tests/servicestests/src/com/android/server/connectivity/LingerMonitorTest.java
     deleted file mode 100644
     index bce5787..0000000
    @@ -162223,6 +12447,132 @@ index 5f84ea1..0000000
     -        }
     -    };
     -}
    +diff --git a/services/tests/servicestests/src/com/android/server/connectivity/MetricsTestUtil.java b/services/tests/servicestests/src/com/android/server/connectivity/MetricsTestUtil.java
    +deleted file mode 100644
    +index e201012..0000000
    +--- a/services/tests/servicestests/src/com/android/server/connectivity/MetricsTestUtil.java
    ++++ /dev/null
    +@@ -1,120 +0,0 @@
    +-/*
    +- * Copyright (C) 2016 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 com.android.server.connectivity;
    +-
    +-import android.net.ConnectivityMetricsEvent;
    +-import android.net.ConnectivityMetricsLogger;
    +-import android.os.Bundle;
    +-import android.os.Parcel;
    +-import android.os.Parcelable;
    +-
    +-abstract public class MetricsTestUtil {
    +-    private MetricsTestUtil() {
    +-    }
    +-
    +-    static ConnectivityMetricsEvent ipEv(Parcelable p) {
    +-        return ev(ConnectivityMetricsLogger.COMPONENT_TAG_CONNECTIVITY, p);
    +-    }
    +-
    +-    static ConnectivityMetricsEvent telephonyEv() {
    +-        return ev(ConnectivityMetricsLogger.COMPONENT_TAG_TELEPHONY, new Bundle());
    +-    }
    +-
    +-    static ConnectivityMetricsEvent ev(int tag, Parcelable p) {
    +-        return new ConnectivityMetricsEvent(1L, tag, 0, p);
    +-    }
    +-
    +-    // Utiliy interface for describing the content of a Parcel. This relies on
    +-    // the implementation defails of Parcelable and on the fact that the fully
    +-    // qualified Parcelable class names are written as string in the Parcels.
    +-    interface ParcelField {
    +-        void write(Parcel p);
    +-    }
    +-
    +-    static ConnectivityMetricsEvent describeIpEvent(ParcelField... fs) {
    +-        Parcel p = Parcel.obtain();
    +-        for (ParcelField f : fs) {
    +-            f.write(p);
    +-        }
    +-        p.setDataPosition(0);
    +-        return ipEv(p.readParcelable(ClassLoader.getSystemClassLoader()));
    +-    }
    +-
    +-    static ParcelField aType(Class<?> c) {
    +-        return new ParcelField() {
    +-            public void write(Parcel p) {
    +-                p.writeString(c.getName());
    +-            }
    +-        };
    +-    }
    +-
    +-    static ParcelField aBool(boolean b) {
    +-        return aByte((byte) (b ? 1 : 0));
    +-    }
    +-
    +-    static ParcelField aByte(byte b) {
    +-        return new ParcelField() {
    +-            public void write(Parcel p) {
    +-                p.writeByte(b);
    +-            }
    +-        };
    +-    }
    +-
    +-    static ParcelField anInt(int i) {
    +-        return new ParcelField() {
    +-            public void write(Parcel p) {
    +-                p.writeInt(i);
    +-            }
    +-        };
    +-    }
    +-
    +-    static ParcelField aLong(long l) {
    +-        return new ParcelField() {
    +-            public void write(Parcel p) {
    +-                p.writeLong(l);
    +-            }
    +-        };
    +-    }
    +-
    +-    static ParcelField aString(String s) {
    +-        return new ParcelField() {
    +-            public void write(Parcel p) {
    +-                p.writeString(s);
    +-            }
    +-        };
    +-    }
    +-
    +-    static ParcelField aByteArray(byte... ary) {
    +-        return new ParcelField() {
    +-            public void write(Parcel p) {
    +-                p.writeByteArray(ary);
    +-            }
    +-        };
    +-    }
    +-
    +-    static ParcelField anIntArray(int... ary) {
    +-        return new ParcelField() {
    +-            public void write(Parcel p) {
    +-                p.writeIntArray(ary);
    +-            }
    +-        };
    +-    }
    +-
    +-    static byte b(int i) {
    +-        return (byte) i;
    +-    }
    +-}
     diff --git a/services/tests/servicestests/src/com/android/server/connectivity/VpnTest.java b/services/tests/servicestests/src/com/android/server/connectivity/VpnTest.java
     deleted file mode 100644
     index 5d8b843..0000000
    @@ -164163,10 +14513,10 @@ index 6cb4a82..0000000
     -}
     diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
     deleted file mode 100644
    -index 2d96bff..0000000
    +index 11ec7ac..0000000
     --- a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
     +++ /dev/null
    -@@ -1,2131 +0,0 @@
    +@@ -1,2186 +0,0 @@
     -/*
     - * Copyright (C) 2015 The Android Open Source Project
     - *
    @@ -166078,6 +16428,61 @@ index 2d96bff..0000000
     -        verifyScreenTimeoutCall(Integer.MAX_VALUE, false);
     -    }
     -
    +-    public void testSetRequiredStrongAuthTimeout_DeviceOwner() throws Exception {
    +-        mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID;
    +-        setupDeviceOwner();
    +-        mContext.callerPermissions.add(permission.MANAGE_PROFILE_AND_DEVICE_OWNERS);
    +-
    +-        final long MINIMUM_STRONG_AUTH_TIMEOUT_MS = 1 * 60 * 60 * 1000; // 1h
    +-        final long ONE_MINUTE = 60 * 1000;
    +-
    +-        // aggregation should be the default if unset by any admin
    +-        assertEquals(dpm.getRequiredStrongAuthTimeout(null),
    +-                DevicePolicyManager.DEFAULT_STRONG_AUTH_TIMEOUT_MS);
    +-
    +-        // admin not participating by default
    +-        assertEquals(dpm.getRequiredStrongAuthTimeout(admin1), 0);
    +-
    +-        //clamping from the top
    +-        dpm.setRequiredStrongAuthTimeout(admin1,
    +-                DevicePolicyManager.DEFAULT_STRONG_AUTH_TIMEOUT_MS + ONE_MINUTE);
    +-        assertEquals(dpm.getRequiredStrongAuthTimeout(admin1),
    +-                DevicePolicyManager.DEFAULT_STRONG_AUTH_TIMEOUT_MS);
    +-        assertEquals(dpm.getRequiredStrongAuthTimeout(null),
    +-                DevicePolicyManager.DEFAULT_STRONG_AUTH_TIMEOUT_MS);
    +-
    +-        // 0 means default
    +-        dpm.setRequiredStrongAuthTimeout(admin1, 0);
    +-        assertEquals(dpm.getRequiredStrongAuthTimeout(admin1), 0);
    +-        assertEquals(dpm.getRequiredStrongAuthTimeout(null),
    +-                DevicePolicyManager.DEFAULT_STRONG_AUTH_TIMEOUT_MS);
    +-
    +-        // clamping from the bottom
    +-        dpm.setRequiredStrongAuthTimeout(admin1, MINIMUM_STRONG_AUTH_TIMEOUT_MS - ONE_MINUTE);
    +-        assertEquals(dpm.getRequiredStrongAuthTimeout(admin1), MINIMUM_STRONG_AUTH_TIMEOUT_MS);
    +-        assertEquals(dpm.getRequiredStrongAuthTimeout(null), MINIMUM_STRONG_AUTH_TIMEOUT_MS);
    +-
    +-        // value within range
    +-        dpm.setRequiredStrongAuthTimeout(admin1, MINIMUM_STRONG_AUTH_TIMEOUT_MS + ONE_MINUTE);
    +-        assertEquals(dpm.getRequiredStrongAuthTimeout(admin1), MINIMUM_STRONG_AUTH_TIMEOUT_MS
    +-                + ONE_MINUTE);
    +-        assertEquals(dpm.getRequiredStrongAuthTimeout(null), MINIMUM_STRONG_AUTH_TIMEOUT_MS
    +-                + ONE_MINUTE);
    +-
    +-        // reset to default
    +-        dpm.setRequiredStrongAuthTimeout(admin1, 0);
    +-        assertEquals(dpm.getRequiredStrongAuthTimeout(admin1), 0);
    +-        assertEquals(dpm.getRequiredStrongAuthTimeout(null),
    +-                DevicePolicyManager.DEFAULT_STRONG_AUTH_TIMEOUT_MS);
    +-
    +-        // negative value
    +-        try {
    +-            dpm.setRequiredStrongAuthTimeout(admin1, -ONE_MINUTE);
    +-            fail("Didn't throw IllegalArgumentException");
    +-        } catch (IllegalArgumentException iae) {
    +-        }
    +-    }
    +-
     -    private void verifyScreenTimeoutCall(Integer expectedTimeout,
     -            boolean shouldStayOnWhilePluggedInBeCleared) {
     -        if (expectedTimeout == null) {
    @@ -166961,7 +17366,7 @@ index 0783afc..0000000
     -}
     diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DpmTestBase.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DpmTestBase.java
     deleted file mode 100644
    -index c80ca6c..0000000
    +index b4b74b3..0000000
     --- a/services/tests/servicestests/src/com/android/server/devicepolicy/DpmTestBase.java
     +++ /dev/null
     @@ -1,167 +0,0 @@
    @@ -167098,7 +17503,7 @@ index c80ca6c..0000000
     -
     -        doReturn(ai).when(mMockContext.ipackageManager).getApplicationInfo(
     -                eq(admin.getPackageName()),
    --                eq(PackageManager.GET_DISABLED_UNTIL_USED_COMPONENTS),
    +-                anyInt(),
     -                eq(UserHandle.getUserId(packageUid)));
     -
     -        // Set up queryBroadcastReceivers().
    @@ -172654,10 +23059,10 @@ index a6fdee9..0000000
     -}
     diff --git a/services/tests/servicestests/src/com/android/server/pm/BaseShortcutManagerTest.java b/services/tests/servicestests/src/com/android/server/pm/BaseShortcutManagerTest.java
     deleted file mode 100644
    -index 1c7a138..0000000
    +index 792f300..0000000
     --- a/services/tests/servicestests/src/com/android/server/pm/BaseShortcutManagerTest.java
     +++ /dev/null
    -@@ -1,1929 +0,0 @@
    +@@ -1,1952 +0,0 @@
     -/*
     - * Copyright (C) 2016 The Android Open Source Project
     - *
    @@ -173050,6 +23455,11 @@ index 1c7a138..0000000
     -        }
     -
     -        @Override
    +-        void injectRunOnNewThread(Runnable r) {
    +-            runOnHandler(r);
    +-        }
    +-
    +-        @Override
     -        void injectEnforceCallingPermission(String permission, String message) {
     -            if (!mCallerPermissions.contains(permission)) {
     -                throw new SecurityException("Missing permission: " + permission);
    @@ -173062,6 +23472,11 @@ index 1c7a138..0000000
     -        }
     -
     -        @Override
    +-        String injectBuildFingerprint() {
    +-            return mInjectedBuildFingerprint;
    +-        }
    +-
    +-        @Override
     -        void wtf(String message, Throwable th) {
     -            // During tests, WTF is fatal.
     -            fail(message + "  exception: " + th + "\n" + Log.getStackTraceString(th));
    @@ -173183,6 +23598,7 @@ index 1c7a138..0000000
     -    protected Map<String, PackageInfo> mInjectedPackages;
     -
     -    protected Set<PackageWithUser> mUninstalledPackages;
    +-    protected Set<String> mSystemPackages;
     -
     -    protected PackageManager mMockPackageManager;
     -    protected PackageManagerInternal mMockPackageManagerInternal;
    @@ -173283,6 +23699,8 @@ index 1c7a138..0000000
     -    protected static final String PACKAGE_FALLBACK_LAUNCHER_NAME = "fallback";
     -    protected static final int PACKAGE_FALLBACK_LAUNCHER_PRIORITY = -999;
     -
    +-    protected String mInjectedBuildFingerprint = "build1";
    +-
     -    static {
     -        QUERY_ALL.setQueryFlags(
     -                ShortcutQuery.FLAG_GET_ALL_KINDS);
    @@ -173332,6 +23750,7 @@ index 1c7a138..0000000
     -                pi -> pi.applicationInfo.flags &= ~ApplicationInfo.FLAG_ALLOW_BACKUP);
     -
     -        mUninstalledPackages = new HashSet<>();
    +-        mSystemPackages = new HashSet<>();
     -
     -        mInjectedFilePathRoot = new File(getTestContext().getCacheDir(), "test-files");
     -
    @@ -173581,6 +24000,12 @@ index 1c7a138..0000000
     -        });
     -    }
     -
    +-    protected void setPackageLastUpdateTime(String packageName, long value) {
    +-        updatePackageInfo(packageName, pi -> {
    +-            pi.lastUpdateTime = value;
    +-        });
    +-    }
    +-
     -    protected void uninstallPackage(int userId, String packageName) {
     -        if (ENABLE_DUMP) {
     -            Log.v(TAG, "Unnstall package " + packageName + " / " + userId);
    @@ -173612,6 +24037,9 @@ index 1c7a138..0000000
     -        if (mUninstalledPackages.contains(PackageWithUser.of(userId, packageName))) {
     -            ret.applicationInfo.flags &= ~ApplicationInfo.FLAG_INSTALLED;
     -        }
    +-        if (mSystemPackages.contains(packageName)) {
    +-            ret.applicationInfo.flags |= ApplicationInfo.FLAG_SYSTEM;
    +-        }
     -
     -        if (getSignatures) {
     -            ret.signatures = pi.signatures;
    @@ -176203,10 +26631,10 @@ index ebd3633..0000000
     -}
     diff --git a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest1.java b/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest1.java
     deleted file mode 100644
    -index 253334e..0000000
    +index 3cfdc32..0000000
     --- a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest1.java
     +++ /dev/null
    -@@ -1,7159 +0,0 @@
    +@@ -1,7340 +0,0 @@
     -/*
     - * Copyright (C) 2016 The Android Open Source Project
     - *
    @@ -180022,9 +30450,9 @@ index 253334e..0000000
     -        addPackage(CALLING_PACKAGE_1, CALLING_UID_1, 10, "sig1");
     -        addPackage(CALLING_PACKAGE_2, CALLING_UID_1, 10, "sig1", "sig2");
     -
    --        final ShortcutPackageInfo spi1 = ShortcutPackageInfo.generateForInstalledPackage(
    +-        final ShortcutPackageInfo spi1 = ShortcutPackageInfo.generateForInstalledPackageForTest(
     -                mService, CALLING_PACKAGE_1, USER_0);
    --        final ShortcutPackageInfo spi2 = ShortcutPackageInfo.generateForInstalledPackage(
    +-        final ShortcutPackageInfo spi2 = ShortcutPackageInfo.generateForInstalledPackageForTest(
     -                mService, CALLING_PACKAGE_2, USER_0);
     -
     -        checkCanRestoreTo(true, spi1, 10, "sig1");
    @@ -180154,11 +30582,11 @@ index 253334e..0000000
     -        mInjectedPackages.remove(CALLING_PACKAGE_1);
     -        mInjectedPackages.remove(CALLING_PACKAGE_3);
     -
    --        mService.handleUnlockUser(USER_0);
    +-        mService.checkPackageChanges(USER_0);
     -
     -        assertNull(mService.getPackageShortcutForTest(CALLING_PACKAGE_1, "s1", USER_0));
     -        assertNotNull(mService.getPackageShortcutForTest(CALLING_PACKAGE_2, "s1", USER_0));
    --        assertNull(mService.getPackageShortcutForTest(CALLING_PACKAGE_3, "s1", USER_0));
    +-        assertNull(mService.getPackageShortcutForTest(CALLING_PACKAGE_3, "s1", USER_0));  // ---------------
     -        assertNotNull(mService.getPackageShortcutForTest(CALLING_PACKAGE_1, "s1", USER_10));
     -        assertNull(mService.getPackageShortcutForTest(CALLING_PACKAGE_2, "s1", USER_10));
     -        assertNotNull(mService.getPackageShortcutForTest(CALLING_PACKAGE_3, "s1", USER_10));
    @@ -180170,7 +30598,7 @@ index 253334e..0000000
     -        assertFalse(bitmapDirectoryExists(CALLING_PACKAGE_2, USER_10));
     -        assertTrue(bitmapDirectoryExists(CALLING_PACKAGE_3, USER_10));
     -
    --        mService.handleUnlockUser(USER_10);
    +-        mService.checkPackageChanges(USER_10);
     -
     -        assertNull(mService.getPackageShortcutForTest(CALLING_PACKAGE_1, "s1", USER_0));
     -        assertNotNull(mService.getPackageShortcutForTest(CALLING_PACKAGE_2, "s1", USER_0));
    @@ -180363,7 +30791,7 @@ index 253334e..0000000
     -        updatePackageVersion(CALLING_PACKAGE_1, 1);
     -
     -        // Then send the broadcast, to only user-0.
    --                mService.mPackageMonitor.onReceive(getTestContext(),
    +-        mService.mPackageMonitor.onReceive(getTestContext(),
     -                genPackageUpdateIntent(CALLING_PACKAGE_1, USER_0));
     -
     -        waitOnMainThread();
    @@ -180395,10 +30823,13 @@ index 253334e..0000000
     -        mInjectedCurrentTimeMillis = START_TIME + 200;
     -
     -        mRunningUsers.put(USER_10, true);
    +-        mUnlockedUsers.put(USER_10, true);
     -
     -        reset(c0);
     -        reset(c10);
    +-        setPackageLastUpdateTime(CALLING_PACKAGE_1, mInjectedCurrentTimeMillis);
     -        mService.handleUnlockUser(USER_10);
    +-        mService.checkPackageChanges(USER_10);
     -
     -        waitOnMainThread();
     -
    @@ -180430,7 +30861,7 @@ index 253334e..0000000
     -        // Then send the broadcast, to only user-0.
     -                mService.mPackageMonitor.onReceive(getTestContext(),
     -                genPackageUpdateIntent(CALLING_PACKAGE_2, USER_0));
    --        mService.handleUnlockUser(USER_10);
    +-        mService.checkPackageChanges(USER_10);
     -
     -        waitOnMainThread();
     -
    @@ -180452,9 +30883,9 @@ index 253334e..0000000
     -        updatePackageVersion(CALLING_PACKAGE_3, 100);
     -
     -        // Then send the broadcast, to only user-0.
    --                mService.mPackageMonitor.onReceive(getTestContext(),
    +-        mService.mPackageMonitor.onReceive(getTestContext(),
     -                genPackageUpdateIntent(CALLING_PACKAGE_3, USER_0));
    --        mService.handleUnlockUser(USER_10);
    +-        mService.checkPackageChanges(USER_10);
     -
     -        waitOnMainThread();
     -
    @@ -180553,6 +30984,128 @@ index 253334e..0000000
     -        });
     -    }
     -
    +-    public void testHandlePackageUpdate_systemAppUpdate() {
    +-
    +-        // Package1 is a system app.  Package 2 is not a system app, so it's not scanned
    +-        // in this test at all.
    +-        mSystemPackages.add(CALLING_PACKAGE_1);
    +-
    +-        // Initial state: no shortcuts.
    +-        mService.checkPackageChanges(USER_0);
    +-
    +-        assertEquals(mInjectedCurrentTimeMillis,
    +-                mService.getUserShortcutsLocked(USER_0).getLastAppScanTime());
    +-        assertEquals(mInjectedBuildFingerprint,
    +-                mService.getUserShortcutsLocked(USER_0).getLastAppScanOsFingerprint());
    +-
    +-        // They have no shortcuts.
    +-        runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
    +-            assertWith(getCallerShortcuts())
    +-                    .isEmpty();
    +-        });
    +-
    +-        runWithCaller(CALLING_PACKAGE_2, USER_0, () -> {
    +-            assertWith(getCallerShortcuts())
    +-                    .isEmpty();
    +-        });
    +-
    +-        // Next.
    +-        // Update the packages -- now they have 1 manifest shortcut.
    +-        // But checkPackageChanges() don't notice it, since their version code / timestamp haven't
    +-        // changed.
    +-        addManifestShortcutResource(
    +-                new ComponentName(CALLING_PACKAGE_1, ShortcutActivity.class.getName()),
    +-                R.xml.shortcut_1);
    +-        addManifestShortcutResource(
    +-                new ComponentName(CALLING_PACKAGE_2, ShortcutActivity.class.getName()),
    +-                R.xml.shortcut_1);
    +-        mInjectedCurrentTimeMillis += 1000;
    +-        mService.checkPackageChanges(USER_0);
    +-
    +-        runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
    +-            assertWith(getCallerShortcuts())
    +-                    .isEmpty();
    +-        });
    +-        runWithCaller(CALLING_PACKAGE_2, USER_0, () -> {
    +-            assertWith(getCallerShortcuts())
    +-                    .isEmpty();
    +-        });
    +-
    +-        // Next.
    +-        // Update the build finger print.  All system apps will be scanned now.
    +-        mInjectedBuildFingerprint = "update1";
    +-        mInjectedCurrentTimeMillis += 1000;
    +-        mService.checkPackageChanges(USER_0);
    +-
    +-        runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
    +-            assertWith(getCallerShortcuts())
    +-                    .haveIds("ms1");
    +-        });
    +-        runWithCaller(CALLING_PACKAGE_2, USER_0, () -> {
    +-            assertWith(getCallerShortcuts())
    +-                    .isEmpty();
    +-        });
    +-
    +-        // Next.
    +-        // Update manifest shortcuts.
    +-        mInjectedBuildFingerprint = "update2";
    +-        addManifestShortcutResource(
    +-                new ComponentName(CALLING_PACKAGE_1, ShortcutActivity.class.getName()),
    +-                R.xml.shortcut_2);
    +-        addManifestShortcutResource(
    +-                new ComponentName(CALLING_PACKAGE_2, ShortcutActivity.class.getName()),
    +-                R.xml.shortcut_2);
    +-        mInjectedCurrentTimeMillis += 1000;
    +-        mService.checkPackageChanges(USER_0);
    +-
    +-        // Fingerprint hasn't changed, so CALLING_PACKAGE_1 wasn't scanned.
    +-        runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
    +-            assertWith(getCallerShortcuts())
    +-                    .haveIds("ms1");
    +-        });
    +-        runWithCaller(CALLING_PACKAGE_2, USER_0, () -> {
    +-            assertWith(getCallerShortcuts())
    +-                    .isEmpty();
    +-        });
    +-
    +-        // Update the fingerprint, but CALLING_PACKAGE_1's version code hasn't changed, so
    +-        // still not scanned.
    +-        mInjectedBuildFingerprint = "update2";
    +-        mInjectedCurrentTimeMillis += 1000;
    +-        mService.checkPackageChanges(USER_0);
    +-
    +-        runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
    +-            assertWith(getCallerShortcuts())
    +-                    .haveIds("ms1");
    +-        });
    +-        runWithCaller(CALLING_PACKAGE_2, USER_0, () -> {
    +-            assertWith(getCallerShortcuts())
    +-                    .isEmpty();
    +-        });
    +-
    +-        // Now update the version code, so CALLING_PACKAGE_1 is scanned again.
    +-        mInjectedBuildFingerprint = "update3";
    +-        mInjectedCurrentTimeMillis += 1000;
    +-        updatePackageVersion(CALLING_PACKAGE_1, 1);
    +-        mService.checkPackageChanges(USER_0);
    +-
    +-        runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
    +-            assertWith(getCallerShortcuts())
    +-                    .haveIds("ms1", "ms2");
    +-        });
    +-        runWithCaller(CALLING_PACKAGE_2, USER_0, () -> {
    +-            assertWith(getCallerShortcuts())
    +-                    .isEmpty();
    +-        });
    +-
    +-        // Make sure getLastAppScanTime / getLastAppScanOsFingerprint are persisted.
    +-        initService();
    +-        assertEquals(mInjectedCurrentTimeMillis,
    +-                mService.getUserShortcutsLocked(USER_0).getLastAppScanTime());
    +-        assertEquals(mInjectedBuildFingerprint,
    +-                mService.getUserShortcutsLocked(USER_0).getLastAppScanOsFingerprint());
    +-    }
    +-
     -    public void testHandlePackageChanged() {
     -        final ComponentName ACTIVITY1 = new ComponentName(CALLING_PACKAGE_1, "act1");
     -        final ComponentName ACTIVITY2 = new ComponentName(CALLING_PACKAGE_1, "act2");
    @@ -181443,6 +31996,12 @@ index 253334e..0000000
     -    /**
     -     * It's the case with preintalled apps -- when applyRestore() is called, the system
     -     * apps are already installed, so manifest shortcuts need to be re-published.
    +-     *
    +-     * Also, when a restore target app is already installed, and
    +-     * - if it has allowBackup=true, we'll restore normally, so all existing shortcuts will be
    +-     * replaced. (but manifest shortcuts will be re-published anyway.)  We log a warning on
    +-     * logcat.
    +-     * - if it has allowBackup=false, we don't touch any of the existing shortcuts.
     -     */
     -    public void testBackupAndRestore_appAlreadyInstalledWhenRestored() {
     -        // Pre-backup.  Same as testBackupAndRestore_manifestRePublished().
    @@ -181474,6 +32033,19 @@ index 253334e..0000000
     -        mService.mPackageMonitor.onReceive(mServiceContext,
     -                genPackageAddIntent(CALLING_PACKAGE_1, USER_0));
     -
    +-        // Set up shortcuts for package 3, which won't be backed up / restored.
    +-        addManifestShortcutResource(
    +-                new ComponentName(CALLING_PACKAGE_3, ShortcutActivity.class.getName()),
    +-                R.xml.shortcut_1);
    +-        updatePackageVersion(CALLING_PACKAGE_3, 1);
    +-        mService.mPackageMonitor.onReceive(mServiceContext,
    +-                genPackageAddIntent(CALLING_PACKAGE_3, USER_0));
    +-
    +-        runWithCaller(CALLING_PACKAGE_3, USER_0, () -> {
    +-            assertTrue(getManager().setDynamicShortcuts(list(
    +-                    makeShortcut("s1"))));
    +-        });
    +-
     -        // Make sure the manifest shortcuts have been published.
     -        runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
     -            assertWith(getCallerShortcuts())
    @@ -181499,6 +32071,11 @@ index 253334e..0000000
     -                    .areAllDisabled();
     -        });
     -
    +-        runWithCaller(CALLING_PACKAGE_3, USER_0, () -> {
    +-            assertWith(getCallerShortcuts())
    +-                    .haveIds("s1", "ms1");
    +-        });
    +-
     -        // Backup and *without restarting the service, just call applyRestore()*.
     -        {
     -            int prevUid = mInjectedCallingUid;
    @@ -181538,6 +32115,12 @@ index 253334e..0000000
     -                    .areAllNotDynamic()
     -            ;
     -        });
    +-
    +-        // Package 3 still has the same shortcuts.
    +-        runWithCaller(CALLING_PACKAGE_3, USER_0, () -> {
    +-            assertWith(getCallerShortcuts())
    +-                    .haveIds("s1", "ms1");
    +-        });
     -    }
     -
     -    public void testSaveAndLoad_crossProfile() {
    @@ -181715,6 +32298,32 @@ index 253334e..0000000
     -                                buildAllQuery(CALLING_PACKAGE_1), HANDLE_USER_P0);
     -                    });
     -        });
    +-        // Check the user-IDs.
    +-        assertEquals(USER_0,
    +-                mService.getUserShortcutsLocked(USER_0).getPackageShortcuts(CALLING_PACKAGE_1)
    +-                        .getOwnerUserId());
    +-        assertEquals(USER_0,
    +-                mService.getUserShortcutsLocked(USER_0).getPackageShortcuts(CALLING_PACKAGE_1)
    +-                        .getPackageUserId());
    +-        assertEquals(USER_P0,
    +-                mService.getUserShortcutsLocked(USER_P0).getPackageShortcuts(CALLING_PACKAGE_1)
    +-                        .getOwnerUserId());
    +-        assertEquals(USER_P0,
    +-                mService.getUserShortcutsLocked(USER_P0).getPackageShortcuts(CALLING_PACKAGE_1)
    +-                        .getPackageUserId());
    +-
    +-        assertEquals(USER_0,
    +-                mService.getUserShortcutsLocked(USER_0).getLauncherShortcuts(LAUNCHER_1, USER_0)
    +-                        .getOwnerUserId());
    +-        assertEquals(USER_0,
    +-                mService.getUserShortcutsLocked(USER_0).getLauncherShortcuts(LAUNCHER_1, USER_0)
    +-                        .getPackageUserId());
    +-        assertEquals(USER_P0,
    +-                mService.getUserShortcutsLocked(USER_P0).getLauncherShortcuts(LAUNCHER_1, USER_0)
    +-                        .getOwnerUserId());
    +-        assertEquals(USER_0,
    +-                mService.getUserShortcutsLocked(USER_P0).getLauncherShortcuts(LAUNCHER_1, USER_0)
    +-                        .getPackageUserId());
     -    }
     -
     -    public void testOnApplicationActive_permission() {
    @@ -190850,1971 +41459,3 @@ index 1fe5cb7..0000000
     -        assertTrue(message, checker.getAsBoolean());
     -    }
     -}
    -diff --git a/services/usage/java/com/android/server/usage/UsageStatsService.java b/services/usage/java/com/android/server/usage/UsageStatsService.java
    -index 8284773..04104b5 100644
    ---- a/services/usage/java/com/android/server/usage/UsageStatsService.java
    -+++ b/services/usage/java/com/android/server/usage/UsageStatsService.java
    -@@ -94,7 +94,7 @@ public class UsageStatsService extends SystemService implements
    - 
    -     static final String TAG = "UsageStatsService";
    - 
    --    static final boolean DEBUG = false;
    -+    static final boolean DEBUG = false; // Never submit with true
    -     static final boolean COMPRESS_TIME = false;
    - 
    -     private static final long TEN_SECONDS = 10 * 1000;
    -@@ -139,8 +139,8 @@ public class UsageStatsService extends SystemService implements
    -     long mSystemTimeSnapshot;
    - 
    -     boolean mAppIdleEnabled;
    --    boolean mAppIdleParoled;
    --    private boolean mScreenOn;
    -+    boolean mAppIdleTempParoled;
    -+    boolean mCharging;
    -     private long mLastAppIdleParoledTime;
    - 
    -     private volatile boolean mPendingOneTimeCheckIdleStates;
    -@@ -191,7 +191,7 @@ public class UsageStatsService extends SystemService implements
    -         mAppIdleEnabled = getContext().getResources().getBoolean(
    -                 com.android.internal.R.bool.config_enableAutoPowerModes);
    -         if (mAppIdleEnabled) {
    --            IntentFilter deviceStates = new IntentFilter(BatteryManager.ACTION_CHARGING);
    -+            IntentFilter deviceStates = new IntentFilter(Intent.ACTION_BATTERY_CHANGED);
    -             deviceStates.addAction(BatteryManager.ACTION_DISCHARGING);
    -             deviceStates.addAction(PowerManager.ACTION_DEVICE_IDLE_MODE_CHANGED);
    -             getContext().registerReceiver(new DeviceStateReceiver(), deviceStates);
    -@@ -237,7 +237,7 @@ public class UsageStatsService extends SystemService implements
    - 
    -             mSystemServicesReady = true;
    -         } else if (phase == PHASE_BOOT_COMPLETED) {
    --            setAppIdleParoled(getContext().getSystemService(BatteryManager.class).isCharging());
    -+            setChargingState(getContext().getSystemService(BatteryManager.class).isCharging());
    -         }
    -     }
    - 
    -@@ -284,9 +284,8 @@ public class UsageStatsService extends SystemService implements
    -         @Override
    -         public void onReceive(Context context, Intent intent) {
    -             final String action = intent.getAction();
    --            if (BatteryManager.ACTION_CHARGING.equals(action)
    --                    || BatteryManager.ACTION_DISCHARGING.equals(action)) {
    --                setAppIdleParoled(BatteryManager.ACTION_CHARGING.equals(action));
    -+            if (Intent.ACTION_BATTERY_CHANGED.equals(action)) {
    -+                setChargingState(intent.getIntExtra("plugged", 0) != 0);
    -             } else if (PowerManager.ACTION_DEVICE_IDLE_MODE_CHANGED.equals(action)) {
    -                 onDeviceIdleModeChanged();
    -             }
    -@@ -376,12 +375,21 @@ public class UsageStatsService extends SystemService implements
    -         }
    -     }
    - 
    -+    void setChargingState(boolean charging) {
    -+        synchronized (mLock) {
    -+            if (mCharging != charging) {
    -+                mCharging = charging;
    -+                postParoleStateChanged();
    -+            }
    -+        }
    -+    }
    -+
    -     /** Paroled here means temporary pardon from being inactive */
    -     void setAppIdleParoled(boolean paroled) {
    -         synchronized (mLock) {
    --            if (mAppIdleParoled != paroled) {
    --                mAppIdleParoled = paroled;
    --                if (DEBUG) Slog.d(TAG, "Changing paroled to " + mAppIdleParoled);
    -+            if (mAppIdleTempParoled != paroled) {
    -+                mAppIdleTempParoled = paroled;
    -+                if (DEBUG) Slog.d(TAG, "Changing paroled to " + mAppIdleTempParoled);
    -                 if (paroled) {
    -                     postParoleEndTimeout();
    -                 } else {
    -@@ -393,6 +401,12 @@ public class UsageStatsService extends SystemService implements
    -         }
    -     }
    - 
    -+    boolean isParoledOrCharging() {
    -+        synchronized (mLock) {
    -+            return mAppIdleTempParoled || mCharging;
    -+        }
    -+    }
    -+
    -     private void postNextParoleTimeout() {
    -         if (DEBUG) Slog.d(TAG, "Posting MSG_CHECK_PAROLE_TIMEOUT");
    -         mHandler.removeMessages(MSG_CHECK_PAROLE_TIMEOUT);
    -@@ -495,7 +509,7 @@ public class UsageStatsService extends SystemService implements
    -     /** Check if it's been a while since last parole and let idle apps do some work */
    -     void checkParoleTimeout() {
    -         synchronized (mLock) {
    --            if (!mAppIdleParoled) {
    -+            if (!mAppIdleTempParoled) {
    -                 final long timeSinceLastParole = checkAndGetTimeLocked() - mLastAppIdleParoledTime;
    -                 if (timeSinceLastParole > mAppIdleParoleIntervalMillis) {
    -                     if (DEBUG) Slog.d(TAG, "Crossed default parole interval");
    -@@ -786,7 +800,7 @@ public class UsageStatsService extends SystemService implements
    -     }
    - 
    -     boolean isAppIdleFilteredOrParoled(String packageName, int userId, long elapsedRealtime) {
    --        if (mAppIdleParoled) {
    -+        if (isParoledOrCharging()) {
    -             return false;
    -         }
    -         return isAppIdleFiltered(packageName, getAppId(packageName), userId, elapsedRealtime);
    -@@ -989,8 +1003,9 @@ public class UsageStatsService extends SystemService implements
    -     }
    - 
    -     void informParoleStateChanged() {
    -+        final boolean paroled = isParoledOrCharging();
    -         for (AppIdleStateChangeListener listener : mPackageAccessListeners) {
    --            listener.onParoleStateChanged(mAppIdleParoled);
    -+            listener.onParoleStateChanged(paroled);
    -         }
    -     }
    - 
    -@@ -1072,9 +1087,9 @@ public class UsageStatsService extends SystemService implements
    - 
    -             pw.println();
    -             pw.print("mAppIdleEnabled="); pw.print(mAppIdleEnabled);
    --            pw.print(" mAppIdleParoled="); pw.print(mAppIdleParoled);
    --            pw.print(" mScreenOn="); pw.println(mScreenOn);
    --            pw.print("mLastAppIdleParoledTime=");
    -+            pw.print(" mAppIdleTempParoled="); pw.print(mAppIdleTempParoled);
    -+            pw.print(" mCharging="); pw.print(mCharging);
    -+            pw.print(" mLastAppIdleParoledTime=");
    -             TimeUtils.formatDuration(mLastAppIdleParoledTime, pw);
    -             pw.println();
    -         }
    -@@ -1139,7 +1154,8 @@ public class UsageStatsService extends SystemService implements
    -                     break;
    - 
    -                 case MSG_PAROLE_STATE_CHANGED:
    --                    if (DEBUG) Slog.d(TAG, "Parole state changed: " + mAppIdleParoled);
    -+                    if (DEBUG) Slog.d(TAG, "Parole state: " + mAppIdleTempParoled
    -+                            + ", Charging state:" + mCharging);
    -                     informParoleStateChanged();
    -                     break;
    - 
    -@@ -1466,7 +1482,7 @@ public class UsageStatsService extends SystemService implements
    - 
    -         @Override
    -         public boolean isAppIdleParoleOn() {
    --            return mAppIdleParoled;
    -+            return isParoledOrCharging();
    -         }
    - 
    -         @Override
    -diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/DatabaseHelper.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/DatabaseHelper.java
    -index 0dcd152..dd7b5a8 100644
    ---- a/services/voiceinteraction/java/com/android/server/voiceinteraction/DatabaseHelper.java
    -+++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/DatabaseHelper.java
    -@@ -27,6 +27,9 @@ import android.hardware.soundtrigger.SoundTrigger.KeyphraseSoundModel;
    - import android.text.TextUtils;
    - import android.util.Slog;
    - 
    -+import java.util.ArrayList;
    -+import java.util.Arrays;
    -+import java.util.List;
    - import java.util.Locale;
    - import java.util.UUID;
    - 
    -@@ -40,7 +43,7 @@ public class DatabaseHelper extends SQLiteOpenHelper {
    -     static final boolean DBG = false;
    - 
    -     private static final String NAME = "sound_model.db";
    --    private static final int VERSION = 5;
    -+    private static final int VERSION = 6;
    - 
    -     public static interface SoundModelContract {
    -         public static final String TABLE = "sound_model";
    -@@ -58,15 +61,19 @@ public class DatabaseHelper extends SQLiteOpenHelper {
    -     // Table Create Statement
    -     private static final String CREATE_TABLE_SOUND_MODEL = "CREATE TABLE "
    -             + SoundModelContract.TABLE + "("
    --            + SoundModelContract.KEY_MODEL_UUID + " TEXT PRIMARY KEY,"
    --            + SoundModelContract.KEY_VENDOR_UUID + " TEXT, "
    -+            + SoundModelContract.KEY_MODEL_UUID + " TEXT,"
    -+            + SoundModelContract.KEY_VENDOR_UUID + " TEXT,"
    -             + SoundModelContract.KEY_KEYPHRASE_ID + " INTEGER,"
    -             + SoundModelContract.KEY_TYPE + " INTEGER,"
    -             + SoundModelContract.KEY_DATA + " BLOB,"
    -             + SoundModelContract.KEY_RECOGNITION_MODES + " INTEGER,"
    -             + SoundModelContract.KEY_LOCALE + " TEXT,"
    -             + SoundModelContract.KEY_HINT_TEXT + " TEXT,"
    --            + SoundModelContract.KEY_USERS + " TEXT" + ")";
    -+            + SoundModelContract.KEY_USERS + " TEXT,"
    -+            + "PRIMARY KEY (" + SoundModelContract.KEY_KEYPHRASE_ID + ","
    -+                              + SoundModelContract.KEY_LOCALE + ","
    -+                              + SoundModelContract.KEY_USERS + ")"
    -+            + ")";
    - 
    -     public DatabaseHelper(Context context) {
    -         super(context, NAME, null, VERSION);
    -@@ -93,6 +100,44 @@ public class DatabaseHelper extends SQLiteOpenHelper {
    -                 oldVersion++;
    -             }
    -         }
    -+        if (oldVersion == 5) {
    -+            // We need to enforce the new primary key constraint that the
    -+            // keyphrase id, locale, and users are unique. We have to first pull
    -+            // everything out of the database, remove duplicates, create the new
    -+            // table, then push everything back in.
    -+            String selectQuery = "SELECT * FROM " + SoundModelContract.TABLE;
    -+            Cursor c = db.rawQuery(selectQuery, null);
    -+            List<SoundModelRecord> old_records = new ArrayList<SoundModelRecord>();
    -+            try {
    -+                if (c.moveToFirst()) {
    -+                    do {
    -+                        try {
    -+                            old_records.add(new SoundModelRecord(5, c));
    -+                        } catch (Exception e) {
    -+                            Slog.e(TAG, "Failed to extract V5 record", e);
    -+                        }
    -+                    } while (c.moveToNext());
    -+                }
    -+            } finally {
    -+                c.close();
    -+            }
    -+            db.execSQL("DROP TABLE IF EXISTS " + SoundModelContract.TABLE);
    -+            onCreate(db);
    -+            for (SoundModelRecord record : old_records) {
    -+                if (record.ifViolatesV6PrimaryKeyIsFirstOfAnyDuplicates(old_records)) {
    -+                    try {
    -+                        long return_value = record.writeToDatabase(6, db);
    -+                        if (return_value == -1) {
    -+                            Slog.e(TAG, "Database write failed " + record.modelUuid + ": "
    -+                                    + return_value);
    -+                        }
    -+                    } catch (Exception e) {
    -+                        Slog.e(TAG, "Failed to update V6 record " + record.modelUuid, e);
    -+                    }
    -+                }
    -+            }
    -+            oldVersion++;
    -+        }
    -     }
    - 
    -     /**
    -@@ -279,4 +324,93 @@ public class DatabaseHelper extends SQLiteOpenHelper {
    -         }
    -         return users;
    -     }
    -+
    -+    private static class SoundModelRecord {
    -+        public final String modelUuid;
    -+        public final String vendorUuid;
    -+        public final int keyphraseId;
    -+        public final int type;
    -+        public final byte[] data;
    -+        public final int recognitionModes;
    -+        public final String locale;
    -+        public final String hintText;
    -+        public final String users;
    -+
    -+        public SoundModelRecord(int version, Cursor c) {
    -+            modelUuid = c.getString(c.getColumnIndex(SoundModelContract.KEY_MODEL_UUID));
    -+            if (version >= 5) {
    -+                vendorUuid = c.getString(c.getColumnIndex(SoundModelContract.KEY_VENDOR_UUID));
    -+            } else {
    -+                vendorUuid = null;
    -+            }
    -+            keyphraseId = c.getInt(c.getColumnIndex(SoundModelContract.KEY_KEYPHRASE_ID));
    -+            type = c.getInt(c.getColumnIndex(SoundModelContract.KEY_TYPE));
    -+            data = c.getBlob(c.getColumnIndex(SoundModelContract.KEY_DATA));
    -+            recognitionModes = c.getInt(c.getColumnIndex(SoundModelContract.KEY_RECOGNITION_MODES));
    -+            locale = c.getString(c.getColumnIndex(SoundModelContract.KEY_LOCALE));
    -+            hintText = c.getString(c.getColumnIndex(SoundModelContract.KEY_HINT_TEXT));
    -+            users = c.getString(c.getColumnIndex(SoundModelContract.KEY_USERS));
    -+        }
    -+
    -+        private boolean V6PrimaryKeyMatches(SoundModelRecord record) {
    -+          return keyphraseId == record.keyphraseId && stringComparisonHelper(locale, record.locale)
    -+              && stringComparisonHelper(users, record.users);
    -+        }
    -+
    -+        // Returns true if this record is a) the only record with the same V6 primary key, or b) the
    -+        // first record in the list of all records that have the same primary key and equal data.
    -+        // It will return false if a) there are any records that have the same primary key and
    -+        // different data, or b) there is a previous record in the list that has the same primary
    -+        // key and data.
    -+        // Note that 'this' object must be inside the list.
    -+        public boolean ifViolatesV6PrimaryKeyIsFirstOfAnyDuplicates(
    -+                List<SoundModelRecord> records) {
    -+            // First pass - check to see if all the records that have the same primary key have
    -+            // duplicated data.
    -+            for (SoundModelRecord record : records) {
    -+                if (this == record) {
    -+                    continue;
    -+                }
    -+                // If we have different/missing data with the same primary key, then we should drop
    -+                // everything.
    -+                if (this.V6PrimaryKeyMatches(record) && !Arrays.equals(data, record.data)) {
    -+                    return false;
    -+                }
    -+            }
    -+
    -+            // We only want to return true for the first duplicated model.
    -+            for (SoundModelRecord record : records) {
    -+                if (this.V6PrimaryKeyMatches(record)) {
    -+                    return this == record;
    -+                }
    -+            }
    -+            return true;
    -+        }
    -+
    -+        public long writeToDatabase(int version, SQLiteDatabase db) {
    -+            ContentValues values = new ContentValues();
    -+            values.put(SoundModelContract.KEY_MODEL_UUID, modelUuid);
    -+            if (version >= 5) {
    -+                values.put(SoundModelContract.KEY_VENDOR_UUID, vendorUuid);
    -+            }
    -+            values.put(SoundModelContract.KEY_KEYPHRASE_ID, keyphraseId);
    -+            values.put(SoundModelContract.KEY_TYPE, type);
    -+            values.put(SoundModelContract.KEY_DATA, data);
    -+            values.put(SoundModelContract.KEY_RECOGNITION_MODES, recognitionModes);
    -+            values.put(SoundModelContract.KEY_LOCALE, locale);
    -+            values.put(SoundModelContract.KEY_HINT_TEXT, hintText);
    -+            values.put(SoundModelContract.KEY_USERS, users);
    -+
    -+            return db.insertWithOnConflict(
    -+                       SoundModelContract.TABLE, null, values, SQLiteDatabase.CONFLICT_REPLACE);
    -+        }
    -+
    -+        // Helper for checking string equality - including the case when they are null.
    -+        static private boolean stringComparisonHelper(String a, String b) {
    -+          if (a != null) {
    -+            return a.equals(b);
    -+          }
    -+          return a == b;
    -+        }
    -+    }
    - }
    -diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java
    -index 43d2a1f..a04034e 100644
    ---- a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java
    -+++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java
    -@@ -535,6 +535,18 @@ public class VoiceInteractionManagerService extends SystemService {
    -                     + " user=" + userHandle);
    -         }
    - 
    -+        ComponentName getCurAssistant(int userHandle) {
    -+            String curAssistant = Settings.Secure.getStringForUser(
    -+                    mContext.getContentResolver(),
    -+                    Settings.Secure.ASSISTANT, userHandle);
    -+            if (TextUtils.isEmpty(curAssistant)) {
    -+                return null;
    -+            }
    -+            if (DEBUG) Slog.d(TAG, "getCurAssistant curAssistant=" + curAssistant
    -+                    + " user=" + userHandle);
    -+            return ComponentName.unflattenFromString(curAssistant);
    -+        }
    -+
    -         void resetCurAssistant(int userHandle) {
    -             Settings.Secure.putStringForUser(mContext.getContentResolver(),
    -                     Settings.Secure.ASSISTANT, null, userHandle);
    -@@ -1178,6 +1190,7 @@ public class VoiceInteractionManagerService extends SystemService {
    -                 synchronized (VoiceInteractionManagerServiceStub.this) {
    -                     ComponentName curInteractor = getCurInteractor(userHandle);
    -                     ComponentName curRecognizer = getCurRecognizer(userHandle);
    -+                    ComponentName curAssistant = getCurAssistant(userHandle);
    -                     if (curRecognizer == null) {
    -                         // Could a new recognizer appear when we don't have one pre-installed?
    -                         if (anyPackagesAppearing()) {
    -@@ -1196,6 +1209,7 @@ public class VoiceInteractionManagerService extends SystemService {
    -                             // the default config.
    -                             setCurInteractor(null, userHandle);
    -                             setCurRecognizer(null, userHandle);
    -+                            resetCurAssistant(userHandle);
    -                             initForUser(userHandle);
    -                             return;
    -                         }
    -@@ -1212,6 +1226,20 @@ public class VoiceInteractionManagerService extends SystemService {
    -                         return;
    -                     }
    - 
    -+                    if (curAssistant != null) {
    -+                        int change = isPackageDisappearing(curAssistant.getPackageName());
    -+                        if (change == PACKAGE_PERMANENT_CHANGE) {
    -+                            // If the currently set assistant is being removed, then we should
    -+                            // reset back to the default state (which is probably that we prefer
    -+                            // to have the default full voice interactor enabled).
    -+                            setCurInteractor(null, userHandle);
    -+                            setCurRecognizer(null, userHandle);
    -+                            resetCurAssistant(userHandle);
    -+                            initForUser(userHandle);
    -+                            return;
    -+                        }
    -+                    }
    -+
    -                     // There is no interactor, so just deal with a simple recognizer.
    -                     int change = isPackageDisappearing(curRecognizer.getPackageName());
    -                     if (change == PACKAGE_PERMANENT_CHANGE
    -diff --git a/telecomm/java/android/telecom/Connection.java b/telecomm/java/android/telecom/Connection.java
    -index a093d54..8f9c758 100644
    ---- a/telecomm/java/android/telecom/Connection.java
    -+++ b/telecomm/java/android/telecom/Connection.java
    -@@ -327,7 +327,7 @@ public abstract class Connection extends Conferenceable {
    -      *
    -      * @hide
    -      */
    --    public static final int PROPERTY_SHOW_CALLBACK_NUMBER = 1<<0;
    -+    public static final int PROPERTY_EMERGENCY_CALLBACK_MODE = 1<<0;
    - 
    -     /**
    -      * Whether the call is a generic conference, where we do not know the precise state of
    -@@ -420,6 +420,31 @@ public abstract class Connection extends Conferenceable {
    -             "android.telecom.extra.DISABLE_ADD_CALL";
    - 
    -     /**
    -+     * String connection extra key on a {@link Connection} or {@link Conference} which contains the
    -+     * original Connection ID associated with the connection.  Used in
    -+     * {@link RemoteConnectionService} to track the Connection ID which was originally assigned to a
    -+     * connection/conference added via
    -+     * {@link ConnectionService#addExistingConnection(PhoneAccountHandle, Connection)} and
    -+     * {@link ConnectionService#addConference(Conference)} APIs.  This is important to pass to
    -+     * Telecom for when it deals with RemoteConnections.  When the ConnectionManager wraps the
    -+     * {@link RemoteConnection} and {@link RemoteConference} and adds it to Telecom, there needs to
    -+     * be a way to ensure that we don't add the connection again as a duplicate.
    -+     * <p>
    -+     * For example, the TelephonyCS calls addExistingConnection for a Connection with ID
    -+     * {@code TelephonyCS@1}.  The ConnectionManager learns of this via
    -+     * {@link ConnectionService#onRemoteExistingConnectionAdded(RemoteConnection)}, and wraps this
    -+     * in a new {@link Connection} which it adds to Telecom via
    -+     * {@link ConnectionService#addExistingConnection(PhoneAccountHandle, Connection)}.  As part of
    -+     * this process, the wrapped RemoteConnection gets assigned a new ID (e.g. {@code ConnMan@1}).
    -+     * The TelephonyCS will ALSO try to add the existing connection to Telecom, except with the
    -+     * ID it originally referred to the connection as.  Thus Telecom needs to know that the
    -+     * Connection with ID {@code ConnMan@1} is really the same as {@code TelephonyCS@1}.
    -+     * @hide
    -+     */
    -+    public static final String EXTRA_ORIGINAL_CONNECTION_ID =
    -+            "android.telecom.extra.ORIGINAL_CONNECTION_ID";
    -+
    -+    /**
    -      * Connection event used to inform Telecom that it should play the on hold tone.  This is used
    -      * to play a tone when the peer puts the current call on hold.  Sent to Telecom via
    -      * {@link #sendConnectionEvent(String, Bundle)}.
    -@@ -655,8 +680,8 @@ public abstract class Connection extends Conferenceable {
    -             builder.append("Properties:");
    -         }
    - 
    --        if (can(properties, PROPERTY_SHOW_CALLBACK_NUMBER)) {
    --            builder.append(isLong ? " PROPERTY_SHOW_CALLBACK_NUMBER" : " clbk");
    -+        if (can(properties, PROPERTY_EMERGENCY_CALLBACK_MODE)) {
    -+            builder.append(isLong ? " PROPERTY_EMERGENCY_CALLBACK_MODE" : " ecbm");
    -         }
    - 
    -         if (can(properties, PROPERTY_HIGH_DEF_AUDIO)) {
    -@@ -733,7 +758,6 @@ public abstract class Connection extends Conferenceable {
    -      * {@link android.telecom.InCallService.VideoCall}.
    -      */
    -     public static abstract class VideoProvider {
    --
    -         /**
    -          * Video is not being received (no protocol pause was issued).
    -          * @see #handleCallSessionEvent(int)
    -@@ -818,6 +842,14 @@ public abstract class Connection extends Conferenceable {
    -         private static final int MSG_SET_PAUSE_IMAGE = 11;
    -         private static final int MSG_REMOVE_VIDEO_CALLBACK = 12;
    - 
    -+        private static final String SESSION_EVENT_RX_PAUSE_STR = "RX_PAUSE";
    -+        private static final String SESSION_EVENT_RX_RESUME_STR = "RX_RESUME";
    -+        private static final String SESSION_EVENT_TX_START_STR = "TX_START";
    -+        private static final String SESSION_EVENT_TX_STOP_STR = "TX_STOP";
    -+        private static final String SESSION_EVENT_CAMERA_FAILURE_STR = "CAMERA_FAIL";
    -+        private static final String SESSION_EVENT_CAMERA_READY_STR = "CAMERA_READY";
    -+        private static final String SESSION_EVENT_UNKNOWN_STR = "UNKNOWN";
    -+
    -         private VideoProvider.VideoProviderHandler mMessageHandler;
    -         private final VideoProvider.VideoProviderBinder mBinder;
    - 
    -@@ -1328,6 +1360,32 @@ public abstract class Connection extends Conferenceable {
    -                 }
    -             }
    -         }
    -+
    -+        /**
    -+         * Returns a string representation of a call session event.
    -+         *
    -+         * @param event A call session event passed to {@link #handleCallSessionEvent(int)}.
    -+         * @return String representation of the call session event.
    -+         * @hide
    -+         */
    -+        public static String sessionEventToString(int event) {
    -+            switch (event) {
    -+                case SESSION_EVENT_CAMERA_FAILURE:
    -+                    return SESSION_EVENT_CAMERA_FAILURE_STR;
    -+                case SESSION_EVENT_CAMERA_READY:
    -+                    return SESSION_EVENT_CAMERA_READY_STR;
    -+                case SESSION_EVENT_RX_PAUSE:
    -+                    return SESSION_EVENT_RX_PAUSE_STR;
    -+                case SESSION_EVENT_RX_RESUME:
    -+                    return SESSION_EVENT_RX_RESUME_STR;
    -+                case SESSION_EVENT_TX_START:
    -+                    return SESSION_EVENT_TX_START_STR;
    -+                case SESSION_EVENT_TX_STOP:
    -+                    return SESSION_EVENT_TX_STOP_STR;
    -+                default:
    -+                    return SESSION_EVENT_UNKNOWN_STR + " " + event;
    -+            }
    -+        }
    -     }
    - 
    -     private final Listener mConnectionDeathListener = new Listener() {
    -diff --git a/telecomm/java/android/telecom/ConnectionService.java b/telecomm/java/android/telecom/ConnectionService.java
    -index 0c75630..dd55ca9 100644
    ---- a/telecomm/java/android/telecom/ConnectionService.java
    -+++ b/telecomm/java/android/telecom/ConnectionService.java
    -@@ -1347,7 +1347,13 @@ public abstract class ConnectionService extends Service {
    -      */
    -     private String addExistingConnectionInternal(PhoneAccountHandle handle, Connection connection) {
    -         String id;
    --        if (handle == null) {
    -+
    -+        if (connection.getExtras() != null && connection.getExtras()
    -+                .containsKey(Connection.EXTRA_ORIGINAL_CONNECTION_ID)) {
    -+            id = connection.getExtras().getString(Connection.EXTRA_ORIGINAL_CONNECTION_ID);
    -+            Log.d(this, "addExistingConnectionInternal - conn %s reusing original id %s",
    -+                    connection.getTelecomCallId(), id);
    -+        } else if (handle == null) {
    -             // If no phone account handle was provided, we cannot be sure the call ID is unique,
    -             // so just use a random UUID.
    -             id = UUID.randomUUID().toString();
    -@@ -1381,13 +1387,21 @@ public abstract class ConnectionService extends Service {
    -     }
    - 
    -     private String addConferenceInternal(Conference conference) {
    -+        String originalId = null;
    -+        if (conference.getExtras() != null && conference.getExtras()
    -+                .containsKey(Connection.EXTRA_ORIGINAL_CONNECTION_ID)) {
    -+            originalId = conference.getExtras().getString(Connection.EXTRA_ORIGINAL_CONNECTION_ID);
    -+            Log.d(this, "addConferenceInternal: conf %s reusing original id %s",
    -+                    conference.getTelecomCallId(),
    -+                    originalId);
    -+        }
    -         if (mIdByConference.containsKey(conference)) {
    -             Log.w(this, "Re-adding an existing conference: %s.", conference);
    -         } else if (conference != null) {
    -             // Conferences do not (yet) have a PhoneAccountHandle associated with them, so we
    -             // cannot determine a ConnectionService class name to associate with the ID, so use
    -             // a unique UUID (for now).
    --            String id = UUID.randomUUID().toString();
    -+            String id = originalId == null ? UUID.randomUUID().toString() : originalId;
    -             mConferenceById.put(id, conference);
    -             mIdByConference.put(conference, id);
    -             conference.addListener(mConferenceListener);
    -diff --git a/telecomm/java/android/telecom/RemoteConference.java b/telecomm/java/android/telecom/RemoteConference.java
    -index 943da6d..0ef9ec1 100644
    ---- a/telecomm/java/android/telecom/RemoteConference.java
    -+++ b/telecomm/java/android/telecom/RemoteConference.java
    -@@ -311,6 +311,9 @@ public final class RemoteConference {
    - 
    -     /** @hide */
    -     void putExtras(final Bundle extras) {
    -+        if (extras == null) {
    -+            return;
    -+        }
    -         if (mExtras == null) {
    -             mExtras = new Bundle();
    -         }
    -diff --git a/telecomm/java/android/telecom/RemoteConnection.java b/telecomm/java/android/telecom/RemoteConnection.java
    -index dc8eaf6..37fa374 100644
    ---- a/telecomm/java/android/telecom/RemoteConnection.java
    -+++ b/telecomm/java/android/telecom/RemoteConnection.java
    -@@ -638,7 +638,12 @@ public final class RemoteConnection {
    -         mConnectionCapabilities = connection.getConnectionCapabilities();
    -         mConnectionProperties = connection.getConnectionProperties();
    -         mVideoState = connection.getVideoState();
    --        mVideoProvider = new RemoteConnection.VideoProvider(connection.getVideoProvider());
    -+        IVideoProvider videoProvider = connection.getVideoProvider();
    -+        if (videoProvider != null) {
    -+            mVideoProvider = new RemoteConnection.VideoProvider(videoProvider);
    -+        } else {
    -+            mVideoProvider = null;
    -+        }
    -         mIsVoipAudioMode = connection.getIsVoipAudioMode();
    -         mStatusHints = connection.getStatusHints();
    -         mAddress = connection.getHandle();
    -@@ -646,6 +651,14 @@ public final class RemoteConnection {
    -         mCallerDisplayName = connection.getCallerDisplayName();
    -         mCallerDisplayNamePresentation = connection.getCallerDisplayNamePresentation();
    -         mConference = null;
    -+        putExtras(connection.getExtras());
    -+
    -+        // Stash the original connection ID as it exists in the source ConnectionService.
    -+        // Telecom will use this to avoid adding duplicates later.
    -+        // See comments on Connection.EXTRA_ORIGINAL_CONNECTION_ID for more information.
    -+        Bundle newExtras = new Bundle();
    -+        newExtras.putString(Connection.EXTRA_ORIGINAL_CONNECTION_ID, callId);
    -+        putExtras(newExtras);
    -     }
    - 
    -     /**
    -@@ -1343,6 +1356,9 @@ public final class RemoteConnection {
    - 
    -     /** @hide */
    -     void putExtras(final Bundle extras) {
    -+        if (extras == null) {
    -+            return;
    -+        }
    -         if (mExtras == null) {
    -             mExtras = new Bundle();
    -         }
    -diff --git a/telecomm/java/android/telecom/RemoteConnectionService.java b/telecomm/java/android/telecom/RemoteConnectionService.java
    -index c4739ff..1577a0f 100644
    ---- a/telecomm/java/android/telecom/RemoteConnectionService.java
    -+++ b/telecomm/java/android/telecom/RemoteConnectionService.java
    -@@ -214,18 +214,27 @@ final class RemoteConnectionService {
    -                     conference.addConnection(c);
    -                 }
    -             }
    --
    -             if (conference.getConnections().size() == 0) {
    -                 // A conference was created, but none of its connections are ones that have been
    -                 // created by, and therefore being tracked by, this remote connection service. It
    -                 // is of no interest to us.
    -+                Log.d(this, "addConferenceCall - skipping");
    -                 return;
    -             }
    - 
    -             conference.setState(parcel.getState());
    -             conference.setConnectionCapabilities(parcel.getConnectionCapabilities());
    -             conference.setConnectionProperties(parcel.getConnectionProperties());
    -+            conference.putExtras(parcel.getExtras());
    -             mConferenceById.put(callId, conference);
    -+
    -+            // Stash the original connection ID as it exists in the source ConnectionService.
    -+            // Telecom will use this to avoid adding duplicates later.
    -+            // See comments on Connection.EXTRA_ORIGINAL_CONNECTION_ID for more information.
    -+            Bundle newExtras = new Bundle();
    -+            newExtras.putString(Connection.EXTRA_ORIGINAL_CONNECTION_ID, callId);
    -+            conference.putExtras(newExtras);
    -+
    -             conference.registerCallback(new RemoteConference.Callback() {
    -                 @Override
    -                 public void onDestroyed(RemoteConference c) {
    -@@ -331,12 +340,18 @@ final class RemoteConnectionService {
    -         }
    - 
    -         @Override
    --        public void addExistingConnection(String callId, ParcelableConnection connection) {
    --            // TODO: add contents of this method
    --            RemoteConnection remoteConnction = new RemoteConnection(callId,
    -+        public void addExistingConnection(final String callId, ParcelableConnection connection) {
    -+            RemoteConnection remoteConnection = new RemoteConnection(callId,
    -                     mOutgoingConnectionServiceRpc, connection);
    --
    --            mOurConnectionServiceImpl.addRemoteExistingConnection(remoteConnction);
    -+            mConnectionById.put(callId, remoteConnection);
    -+            remoteConnection.registerCallback(new RemoteConnection.Callback() {
    -+                @Override
    -+                public void onDestroyed(RemoteConnection connection) {
    -+                    mConnectionById.remove(callId);
    -+                    maybeDisconnectAdapter();
    -+                }
    -+            });
    -+            mOurConnectionServiceImpl.addRemoteExistingConnection(remoteConnection);
    -         }
    - 
    -         @Override
    -diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java
    -index dc9767c..0847788 100644
    ---- a/telephony/java/android/telephony/CarrierConfigManager.java
    -+++ b/telephony/java/android/telephony/CarrierConfigManager.java
    -@@ -286,13 +286,23 @@ public class CarrierConfigManager {
    -             "carrier_wfc_supports_wifi_only_bool";
    - 
    -     /**
    --     * Default WFC_IMS_mode 0: WIFI_ONLY
    --     *                      1: CELLULAR_PREFERRED
    --     *                      2: WIFI_PREFERRED
    -+     * Default WFC_IMS_MODE for home network   0: WIFI_ONLY
    -+     *                                         1: CELLULAR_PREFERRED
    -+     *                                         2: WIFI_PREFERRED
    -      * @hide
    -      */
    -     public static final String KEY_CARRIER_DEFAULT_WFC_IMS_MODE_INT =
    -             "carrier_default_wfc_ims_mode_int";
    -+
    -+    /**
    -+     * Default WFC_IMS_MODE for roaming
    -+     * See {@link KEY_CARRIER_DEFAULT_WFC_IMS_MODE_INT} for valid values.
    -+     *
    -+     * @hide
    -+     */
    -+    public static final String KEY_CARRIER_DEFAULT_WFC_IMS_ROAMING_MODE_INT =
    -+            "carrier_default_wfc_ims_roaming_mode_int";
    -+
    -     /**
    -      * Default WFC_IMS_enabled: true VoWiFi by default is on
    -      *                          false VoWiFi by default is off
    -@@ -433,18 +443,11 @@ public class CarrierConfigManager {
    -             "disable_severe_when_extreme_disabled_bool";
    - 
    -     /**
    --     * The data call APN retry configuration for default type APN.
    --     * @hide
    --     */
    --    public static final String KEY_CARRIER_DATA_CALL_RETRY_CONFIG_DEFAULT_STRING =
    --            "carrier_data_call_retry_config_default_string";
    --
    --    /**
    --     * The data call APN retry configuration for other type APNs.
    -+     * The data call retry configuration for different types of APN.
    -      * @hide
    -      */
    --    public static final String KEY_CARRIER_DATA_CALL_RETRY_CONFIG_OTHERS_STRING =
    --            "carrier_data_call_retry_config_others_string";
    -+    public static final String KEY_CARRIER_DATA_CALL_RETRY_CONFIG_STRINGS =
    -+            "carrier_data_call_retry_config_strings";
    - 
    -     /**
    -      * Delay between trying APN from the pool
    -@@ -668,6 +671,20 @@ public class CarrierConfigManager {
    -     public static final String KEY_ALLOW_ADDING_APNS_BOOL = "allow_adding_apns_bool";
    - 
    -     /**
    -+     * APN types that user is not allowed to modify
    -+     * @hide
    -+     */
    -+    public static final String KEY_READ_ONLY_APN_TYPES_STRING_ARRAY =
    -+            "read_only_apn_types_string_array";
    -+
    -+    /**
    -+     * APN fields that user is not allowed to modify
    -+     * @hide
    -+     */
    -+    public static final String KEY_READ_ONLY_APN_FIELDS_STRING_ARRAY =
    -+            "read_only_apn_fields_string_array";
    -+
    -+    /**
    -      * Boolean indicating if intent for emergency call state changes should be broadcast
    -      * @hide
    -      */
    -@@ -681,6 +698,16 @@ public class CarrierConfigManager {
    -     public static final String KEY_CARRIER_ADDITIONAL_CBS_CHANNELS_STRINGS =
    -             "carrier_additional_cbs_channels_strings";
    - 
    -+    /**
    -+      * Indicates whether STK LAUNCH_BROWSER command is disabled.
    -+      * If {@code true}, then the browser will not be launched
    -+      * on UI for the LAUNCH_BROWSER STK command.
    -+      * @hide
    -+      */
    -+    public static final String KEY_STK_DISABLE_LAUNCH_BROWSER_BOOL =
    -+            "stk_disable_launch_browser_bool";
    -+
    -+
    -     // These variables are used by the MMS service and exposed through another API, {@link
    -     // SmsManager}. The variable names and string values are copied from there.
    -     public static final String KEY_MMS_ALIAS_ENABLED_BOOL = "aliasEnabled";
    -@@ -870,6 +897,11 @@ public class CarrierConfigManager {
    - 
    -     /**
    -      * Flag indicating whether the carrier supports the Hold command while in an IMS call.
    -+     * <p>
    -+     * The device configuration value {@code config_device_respects_hold_carrier_config} ultimately
    -+     * controls whether this carrier configuration option is used.  Where
    -+     * {@code config_device_respects_hold_carrier_config} is false, the value of the
    -+     * {@link #KEY_ALLOW_HOLD_IN_IMS_CALL_BOOL} carrier configuration option is ignored.
    -      * @hide
    -      */
    -     public static final String KEY_ALLOW_HOLD_IN_IMS_CALL_BOOL = "allow_hold_in_ims_call";
    -@@ -945,6 +977,18 @@ public class CarrierConfigManager {
    -      */
    -     public static final String FILTERED_CNAP_NAMES_STRING_ARRAY = "filtered_cnap_names_string_array";
    - 
    -+    /**
    -+     * Determine whether user can change Wi-Fi Calling preference in roaming.
    -+     * {@code false} - roaming preference {@link KEY_CARRIER_DEFAULT_WFC_IMS_ROAMING_MODE_INT} is
    -+     *                 the same as home preference {@link KEY_CARRIER_DEFAULT_WFC_IMS_MODE_INT}
    -+     *                 and cannot be changed.
    -+     * {@code true}  - roaming preference can be changed by user independently.
    -+     *
    -+     * @hide
    -+     */
    -+    public static final String KEY_EDITABLE_WFC_ROAMING_MODE_BOOL =
    -+            "editable_wfc_roaming_mode_bool";
    -+
    -     /** The default value for every variable. */
    -     private final static PersistableBundle sDefaults;
    - 
    -@@ -967,6 +1011,7 @@ public class CarrierConfigManager {
    -         sDefaults.putBoolean(KEY_CARRIER_DEFAULT_WFC_IMS_ROAMING_ENABLED_BOOL, false);
    -         sDefaults.putBoolean(KEY_CARRIER_PROMOTE_WFC_ON_CALL_FAIL_BOOL, false);
    -         sDefaults.putInt(KEY_CARRIER_DEFAULT_WFC_IMS_MODE_INT, 2);
    -+        sDefaults.putInt(KEY_CARRIER_DEFAULT_WFC_IMS_ROAMING_MODE_INT, 2);
    -         sDefaults.putBoolean(KEY_CARRIER_FORCE_DISABLE_ETWS_CMAS_TEST_BOOL, false);
    -         sDefaults.putBoolean(KEY_CARRIER_VOLTE_PROVISIONING_REQUIRED_BOOL, false);
    -         sDefaults.putBoolean(KEY_CARRIER_VOLTE_TTY_SUPPORTED_BOOL, true);
    -@@ -1014,14 +1059,17 @@ public class CarrierConfigManager {
    -         sDefaults.putString(KEY_CI_ACTION_ON_SYS_UPDATE_EXTRA_VAL_STRING, "");
    -         sDefaults.putBoolean(KEY_CSP_ENABLED_BOOL, false);
    -         sDefaults.putBoolean(KEY_ALLOW_ADDING_APNS_BOOL, true);
    -+        sDefaults.putStringArray(KEY_READ_ONLY_APN_TYPES_STRING_ARRAY, null);
    -+        sDefaults.putStringArray(KEY_READ_ONLY_APN_FIELDS_STRING_ARRAY, null);
    -         sDefaults.putBoolean(KEY_BROADCAST_EMERGENCY_CALL_STATE_CHANGES_BOOL, false);
    -         sDefaults.putBoolean(KEY_ALWAYS_SHOW_EMERGENCY_ALERT_ONOFF_BOOL, false);
    -         sDefaults.putBoolean(KEY_DISABLE_SEVERE_WHEN_EXTREME_DISABLED_BOOL, true);
    --        sDefaults.putString(KEY_CARRIER_DATA_CALL_RETRY_CONFIG_DEFAULT_STRING,
    --                "default_randomization=2000,5000,10000,20000,40000,80000:5000,160000:5000,"
    --                        + "320000:5000,640000:5000,1280000:5000,1800000:5000");
    --        sDefaults.putString(KEY_CARRIER_DATA_CALL_RETRY_CONFIG_OTHERS_STRING,
    --                "max_retries=3, 5000, 5000, 5000");
    -+        sDefaults.putStringArray(KEY_CARRIER_DATA_CALL_RETRY_CONFIG_STRINGS, new String[]{
    -+                "default:default_randomization=2000,5000,10000,20000,40000,80000:5000,160000:5000,"
    -+                        + "320000:5000,640000:5000,1280000:5000,1800000:5000",
    -+                "mms:default_randomization=2000,5000,10000,20000,40000,80000:5000,160000:5000,"
    -+                        + "320000:5000,640000:5000,1280000:5000,1800000:5000",
    -+                "others:max_retries=3, 5000, 5000, 5000"});
    -         sDefaults.putLong(KEY_CARRIER_DATA_CALL_APN_DELAY_DEFAULT_LONG, 20000);
    -         sDefaults.putLong(KEY_CARRIER_DATA_CALL_APN_DELAY_FASTER_LONG, 3000);
    -         sDefaults.putString(KEY_CARRIER_ERI_FILE_NAME_STRING, "eri.xml");
    -@@ -1114,6 +1162,8 @@ public class CarrierConfigManager {
    -         sDefaults.putBoolean(KEY_ENHANCED_4G_LTE_TITLE_VARIANT_BOOL, false);
    -         sDefaults.putBoolean(KEY_NOTIFY_VT_HANDOVER_TO_WIFI_FAILURE_BOOL, false);
    -         sDefaults.putStringArray(FILTERED_CNAP_NAMES_STRING_ARRAY, null);
    -+        sDefaults.putBoolean(KEY_EDITABLE_WFC_ROAMING_MODE_BOOL, false);
    -+        sDefaults.putBoolean(KEY_STK_DISABLE_LAUNCH_BROWSER_BOOL, false);
    -     }
    - 
    -     /**
    -diff --git a/telephony/java/android/telephony/DisconnectCause.java b/telephony/java/android/telephony/DisconnectCause.java
    -index f5e422d..0334254 100644
    ---- a/telephony/java/android/telephony/DisconnectCause.java
    -+++ b/telephony/java/android/telephony/DisconnectCause.java
    -@@ -226,6 +226,13 @@ public class DisconnectCause {
    -      */
    -     public static final int DATA_LIMIT_REACHED = 55;
    - 
    -+    /**
    -+     * The emergency call was terminated because it was dialed on the wrong SIM slot.
    -+     * The call needs to be redialed the other slot.
    -+     * {@hide}
    -+     */
    -+    public static final int DIALED_ON_WRONG_SLOT = 56;
    -+
    -     //*********************************************************************************************
    -     // When adding a disconnect type:
    -     // 1) Please assign the new type the next id value below.
    -@@ -234,14 +241,14 @@ public class DisconnectCause {
    -     // 4) Update toString() with the newly added disconnect type.
    -     // 5) Update android.telecom.DisconnectCauseUtil with any mappings to a telecom.DisconnectCause.
    -     //
    --    // NextId: 56
    -+    // NextId: 57
    -     //*********************************************************************************************
    - 
    -     /** Smallest valid value for call disconnect codes. */
    -     public static final int MINIMUM_VALID_VALUE = NOT_DISCONNECTED;
    - 
    -     /** Largest valid value for call disconnect codes. */
    --    public static final int MAXIMUM_VALID_VALUE = DATA_LIMIT_REACHED;
    -+    public static final int MAXIMUM_VALID_VALUE = DIALED_ON_WRONG_SLOT;
    - 
    -     /** Private constructor to avoid class instantiation. */
    -     private DisconnectCause() {
    -@@ -361,6 +368,8 @@ public class DisconnectCause {
    -             return "DATA_DISABLED";
    -         case DATA_LIMIT_REACHED:
    -             return "DATA_LIMIT_REACHED";
    -+        case DIALED_ON_WRONG_SLOT:
    -+            return "DIALED_ON_WRONG_SLOT";
    -         default:
    -             return "INVALID: " + cause;
    -         }
    -diff --git a/telephony/java/android/telephony/PhoneNumberUtils.java b/telephony/java/android/telephony/PhoneNumberUtils.java
    -index 03d6d21..7350eec 100644
    ---- a/telephony/java/android/telephony/PhoneNumberUtils.java
    -+++ b/telephony/java/android/telephony/PhoneNumberUtils.java
    -@@ -24,6 +24,7 @@ import com.android.i18n.phonenumbers.ShortNumberUtil;
    - 
    - import android.content.Context;
    - import android.content.Intent;
    -+import android.content.res.Resources;
    - import android.database.Cursor;
    - import android.location.CountryDetector;
    - import android.net.Uri;
    -@@ -3021,4 +3022,79 @@ public class PhoneNumberUtils
    -         return SubscriptionManager.getDefaultVoiceSubscriptionId();
    -     }
    -     //==== End of utility methods used only in compareStrictly() =====
    -+
    -+
    -+    /*
    -+     * The config held calling number conversion map, expected to convert to emergency number.
    -+     */
    -+    private static final String[] CONVERT_TO_EMERGENCY_MAP = Resources.getSystem().getStringArray(
    -+            com.android.internal.R.array.config_convert_to_emergency_number_map);
    -+    /**
    -+     * Check whether conversion to emergency number is enabled
    -+     *
    -+     * @return {@code true} when conversion to emergency numbers is enabled,
    -+     *         {@code false} otherwise
    -+     *
    -+     * @hide
    -+     */
    -+    public static boolean isConvertToEmergencyNumberEnabled() {
    -+        return CONVERT_TO_EMERGENCY_MAP != null && CONVERT_TO_EMERGENCY_MAP.length > 0;
    -+    }
    -+
    -+    /**
    -+     * Converts to emergency number based on the conversion map.
    -+     * The conversion map is declared as config_convert_to_emergency_number_map.
    -+     *
    -+     * Make sure {@link #isConvertToEmergencyNumberEnabled} is true before calling
    -+     * this function.
    -+     *
    -+     * @return The converted emergency number if the number matches conversion map,
    -+     * otherwise original number.
    -+     *
    -+     * @hide
    -+     */
    -+    public static String convertToEmergencyNumber(String number) {
    -+        if (TextUtils.isEmpty(number)) {
    -+            return number;
    -+        }
    -+
    -+        String normalizedNumber = normalizeNumber(number);
    -+
    -+        // The number is already emergency number. Skip conversion.
    -+        if (isEmergencyNumber(normalizedNumber)) {
    -+            return number;
    -+        }
    -+
    -+        for (String convertMap : CONVERT_TO_EMERGENCY_MAP) {
    -+            if (DBG) log("convertToEmergencyNumber: " + convertMap);
    -+            String[] entry = null;
    -+            String[] filterNumbers = null;
    -+            String convertedNumber = null;
    -+            if (!TextUtils.isEmpty(convertMap)) {
    -+                entry = convertMap.split(":");
    -+            }
    -+            if (entry != null && entry.length == 2) {
    -+                convertedNumber = entry[1];
    -+                if (!TextUtils.isEmpty(entry[0])) {
    -+                    filterNumbers = entry[0].split(",");
    -+                }
    -+            }
    -+            // Skip if the format of entry is invalid
    -+            if (TextUtils.isEmpty(convertedNumber) || filterNumbers == null
    -+                    || filterNumbers.length == 0) {
    -+                continue;
    -+            }
    -+
    -+            for (String filterNumber : filterNumbers) {
    -+                if (DBG) log("convertToEmergencyNumber: filterNumber = " + filterNumber
    -+                        + ", convertedNumber = " + convertedNumber);
    -+                if (!TextUtils.isEmpty(filterNumber) && filterNumber.equals(normalizedNumber)) {
    -+                    if (DBG) log("convertToEmergencyNumber: Matched. Successfully converted to: "
    -+                            + convertedNumber);
    -+                    return convertedNumber;
    -+                }
    -+            }
    -+        }
    -+        return number;
    -+    }
    - }
    -diff --git a/telephony/java/android/telephony/RadioAccessFamily.java b/telephony/java/android/telephony/RadioAccessFamily.java
    -index b530a64..d657bae 100644
    ---- a/telephony/java/android/telephony/RadioAccessFamily.java
    -+++ b/telephony/java/android/telephony/RadioAccessFamily.java
    -@@ -29,32 +29,38 @@ import com.android.internal.telephony.RILConstants;
    - public class RadioAccessFamily implements Parcelable {
    - 
    -     // Radio Access Family
    -+    // 2G
    -     public static final int RAF_UNKNOWN = (1 <<  ServiceState.RIL_RADIO_TECHNOLOGY_UNKNOWN);
    -+    public static final int RAF_GSM = (1 << ServiceState.RIL_RADIO_TECHNOLOGY_GSM);
    -     public static final int RAF_GPRS = (1 << ServiceState.RIL_RADIO_TECHNOLOGY_GPRS);
    -     public static final int RAF_EDGE = (1 << ServiceState.RIL_RADIO_TECHNOLOGY_EDGE);
    --    public static final int RAF_UMTS = (1 << ServiceState.RIL_RADIO_TECHNOLOGY_UMTS);
    -     public static final int RAF_IS95A = (1 << ServiceState.RIL_RADIO_TECHNOLOGY_IS95A);
    -     public static final int RAF_IS95B = (1 << ServiceState.RIL_RADIO_TECHNOLOGY_IS95B);
    -     public static final int RAF_1xRTT = (1 << ServiceState.RIL_RADIO_TECHNOLOGY_1xRTT);
    -+    // 3G
    -     public static final int RAF_EVDO_0 = (1 << ServiceState.RIL_RADIO_TECHNOLOGY_EVDO_0);
    -     public static final int RAF_EVDO_A = (1 << ServiceState.RIL_RADIO_TECHNOLOGY_EVDO_A);
    --    public static final int RAF_HSDPA = (1 << ServiceState.RIL_RADIO_TECHNOLOGY_HSDPA);
    --    public static final int RAF_HSUPA = (1 << ServiceState.RIL_RADIO_TECHNOLOGY_HSUPA);
    --    public static final int RAF_HSPA = (1 << ServiceState.RIL_RADIO_TECHNOLOGY_HSPA);
    -     public static final int RAF_EVDO_B = (1 << ServiceState.RIL_RADIO_TECHNOLOGY_EVDO_B);
    -     public static final int RAF_EHRPD = (1 << ServiceState.RIL_RADIO_TECHNOLOGY_EHRPD);
    --    public static final int RAF_LTE = (1 << ServiceState.RIL_RADIO_TECHNOLOGY_LTE);
    -+    public static final int RAF_HSUPA = (1 << ServiceState.RIL_RADIO_TECHNOLOGY_HSUPA);
    -+    public static final int RAF_HSDPA = (1 << ServiceState.RIL_RADIO_TECHNOLOGY_HSDPA);
    -+    public static final int RAF_HSPA = (1 << ServiceState.RIL_RADIO_TECHNOLOGY_HSPA);
    -     public static final int RAF_HSPAP = (1 << ServiceState.RIL_RADIO_TECHNOLOGY_HSPAP);
    --    public static final int RAF_GSM = (1 << ServiceState.RIL_RADIO_TECHNOLOGY_GSM);
    -+    public static final int RAF_UMTS = (1 << ServiceState.RIL_RADIO_TECHNOLOGY_UMTS);
    -     public static final int RAF_TD_SCDMA = (1 << ServiceState.RIL_RADIO_TECHNOLOGY_TD_SCDMA);
    -+    // 4G
    -+    public static final int RAF_LTE = (1 << ServiceState.RIL_RADIO_TECHNOLOGY_LTE);
    -     public static final int RAF_LTE_CA = (1 << ServiceState.RIL_RADIO_TECHNOLOGY_LTE_CA);
    - 
    -     // Grouping of RAFs
    -+    // 2G
    -     private static final int GSM = RAF_GSM | RAF_GPRS | RAF_EDGE;
    --    private static final int HS = RAF_HSUPA | RAF_HSDPA | RAF_HSPA | RAF_HSPAP;
    -     private static final int CDMA = RAF_IS95A | RAF_IS95B | RAF_1xRTT;
    -+    // 3G
    -     private static final int EVDO = RAF_EVDO_0 | RAF_EVDO_A | RAF_EVDO_B | RAF_EHRPD;
    -+    private static final int HS = RAF_HSUPA | RAF_HSDPA | RAF_HSPA | RAF_HSPAP;
    -     private static final int WCDMA = HS | RAF_UMTS;
    -+    // 4G
    -     private static final int LTE = RAF_LTE | RAF_LTE_CA;
    - 
    -     /* Phone ID of phone */
    -@@ -239,6 +245,24 @@ public class RadioAccessFamily implements Parcelable {
    -         return raf;
    -     }
    - 
    -+    /**
    -+     * Returns the highest capability of the RadioAccessFamily (4G > 3G > 2G).
    -+     * @param raf The RadioAccessFamily that we wish to filter
    -+     * @return The highest radio capability
    -+     */
    -+    public static int getHighestRafCapability(int raf) {
    -+        if ((LTE & raf) > 0) {
    -+            return TelephonyManager.NETWORK_CLASS_4_G;
    -+        }
    -+        if ((EVDO|HS|WCDMA & raf) > 0) {
    -+            return TelephonyManager.NETWORK_CLASS_3_G;
    -+        }
    -+        if((GSM|CDMA & raf) > 0) {
    -+            return TelephonyManager.NETWORK_CLASS_2_G;
    -+        }
    -+        return TelephonyManager.NETWORK_CLASS_UNKNOWN;
    -+    }
    -+
    -     public static int getNetworkTypeFromRaf(int raf) {
    -         int type;
    - 
    -diff --git a/telephony/java/android/telephony/Rlog.java b/telephony/java/android/telephony/Rlog.java
    -index b4f400f..cd0a012 100644
    ---- a/telephony/java/android/telephony/Rlog.java
    -+++ b/telephony/java/android/telephony/Rlog.java
    -@@ -16,8 +16,15 @@
    - 
    - package android.telephony;
    - 
    -+import android.text.TextUtils;
    - import android.util.Log;
    - 
    -+import android.util.Base64;
    -+
    -+import java.security.MessageDigest;
    -+import java.security.NoSuchAlgorithmException;
    -+
    -+
    - /**
    -  * A class to log strings to the RADIO LOG.
    -  *
    -@@ -87,11 +94,52 @@ public final class Rlog {
    - 
    -     /**
    -      * Redact personally identifiable information for production users.
    --     * If log tag is loggable in verbose mode, return the original string, otherwise return XXX.
    -+     * @param tag used to identify the source of a log message
    -+     * @param pii the personally identifiable information we want to apply secure hash on.
    -+     * @return If tag is loggable in verbose mode or pii is null, return the original input.
    -+     * otherwise return a secure Hash of input pii
    -      */
    -     public static String pii(String tag, Object pii) {
    --        return (isLoggable(tag, Log.VERBOSE) ? String.valueOf(pii) : "XXX");
    -+        String val = String.valueOf(pii);
    -+        if (pii == null || TextUtils.isEmpty(val) || isLoggable(tag, Log.VERBOSE)) {
    -+            return val;
    -+        }
    -+        return "[" + secureHash(val.getBytes()) + "]";
    -     }
    - 
    -+    /**
    -+     * Redact personally identifiable information for production users.
    -+     * @param enablePiiLogging set when caller explicitly want to enable sensitive logging.
    -+     * @param pii the personally identifiable information we want to apply secure hash on.
    -+     * @return If enablePiiLogging is set to true or pii is null, return the original input.
    -+     * otherwise return a secure Hash of input pii
    -+     */
    -+    public static String pii(boolean enablePiiLogging, Object pii) {
    -+        String val = String.valueOf(pii);
    -+        if (pii == null || TextUtils.isEmpty(val) || enablePiiLogging) {
    -+            return val;
    -+        }
    -+        return "[" + secureHash(val.getBytes()) + "]";
    -+    }
    -+
    -+    /**
    -+     * Returns a secure hash (using the SHA1 algorithm) of the provided input.
    -+     *
    -+     * @return the hash
    -+     * @param input the bytes for which the secure hash should be computed.
    -+     */
    -+    private static String secureHash(byte[] input) {
    -+        MessageDigest messageDigest;
    -+
    -+        try {
    -+            messageDigest = MessageDigest.getInstance("SHA-1");
    -+        } catch (NoSuchAlgorithmException e) {
    -+            return "####";
    -+        }
    -+
    -+        byte[] result = messageDigest.digest(input);
    -+        return Base64.encodeToString(
    -+                result, Base64.URL_SAFE | Base64.NO_PADDING | Base64.NO_WRAP);
    -+    }
    - }
    - 
    -diff --git a/telephony/java/android/telephony/SubscriptionInfo.java b/telephony/java/android/telephony/SubscriptionInfo.java
    -index 6229ed9..cf2d27e 100644
    ---- a/telephony/java/android/telephony/SubscriptionInfo.java
    -+++ b/telephony/java/android/telephony/SubscriptionInfo.java
    -@@ -340,7 +340,7 @@ public class SubscriptionInfo implements Parcelable {
    -         String iccIdToPrint = null;
    -         if (iccId != null) {
    -             if (iccId.length() > 9 && !Build.IS_DEBUGGABLE) {
    --                iccIdToPrint = iccId.substring(0, 9) + "XXXXXXXXXXX";
    -+                iccIdToPrint = iccId.substring(0, 9) + Rlog.pii(false, iccId.substring(9));
    -             } else {
    -                 iccIdToPrint = iccId;
    -             }
    -diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
    -index 6e504d1..0257334 100644
    ---- a/telephony/java/android/telephony/TelephonyManager.java
    -+++ b/telephony/java/android/telephony/TelephonyManager.java
    -@@ -1662,6 +1662,12 @@ public class TelephonyManager {
    -         }
    -     }
    - 
    -+    /**
    -+     * Network Class Definitions.
    -+     * Do not change this order, it is used for sorting during emergency calling in
    -+     * {@link TelephonyConnectionService#getFirstPhoneForEmergencyCall()}. Any newer technologies
    -+     * should be added after the current definitions.
    -+     */
    -     /** Unknown network class. {@hide} */
    -     public static final int NETWORK_CLASS_UNKNOWN = 0;
    -     /** Class of broadly defined "2G" networks. {@hide} */
    -diff --git a/telephony/java/com/android/internal/telephony/CallerInfoAsyncQuery.java b/telephony/java/com/android/internal/telephony/CallerInfoAsyncQuery.java
    -index 05cb31e..d4104bd 100644
    ---- a/telephony/java/com/android/internal/telephony/CallerInfoAsyncQuery.java
    -+++ b/telephony/java/com/android/internal/telephony/CallerInfoAsyncQuery.java
    -@@ -176,13 +176,13 @@ public class CallerInfoAsyncQuery {
    -                     // However, if there is any code that this Handler calls (such as in
    -                     // super.handleMessage) that DOES place unexpected messages on the
    -                     // queue, then we need pass these messages on.
    --                    if (DBG) Rlog.d(LOG_TAG, "Unexpected command (CookieWrapper is null): " + msg.what +
    -+                    Rlog.i(LOG_TAG, "Unexpected command (CookieWrapper is null): " + msg.what +
    -                             " ignored by CallerInfoWorkerHandler, passing onto parent.");
    - 
    -                     super.handleMessage(msg);
    -                 } else {
    - 
    --                    if (DBG) Rlog.d(LOG_TAG, "Processing event: " + cw.event + " token (arg1): " + msg.arg1 +
    -+                    Rlog.d(LOG_TAG, "Processing event: " + cw.event + " token (arg1): " + msg.arg1 +
    -                         " command: " + msg.what + " query URI: " + sanitizeUriToString(args.uri));
    - 
    -                     switch (cw.event) {
    -@@ -239,7 +239,7 @@ public class CallerInfoAsyncQuery {
    -          */
    -         @Override
    -         protected void onQueryComplete(int token, Object cookie, Cursor cursor) {
    --            if (DBG) Rlog.d(LOG_TAG, "##### onQueryComplete() #####   query complete for token: " + token);
    -+            Rlog.d(LOG_TAG, "##### onQueryComplete() #####   query complete for token: " + token);
    - 
    -             //get the cookie and notify the listener.
    -             CookieWrapper cw = (CookieWrapper) cookie;
    -@@ -248,7 +248,7 @@ public class CallerInfoAsyncQuery {
    -                 // from within this code.
    -                 // However, if there is any code that calls this method, we should
    -                 // check the parameters to make sure they're viable.
    --                if (DBG) Rlog.d(LOG_TAG, "Cookie is null, ignoring onQueryComplete() request.");
    -+                Rlog.i(LOG_TAG, "Cookie is null, ignoring onQueryComplete() request.");
    -                 if (cursor != null) {
    -                     cursor.close();
    -                 }
    -@@ -333,9 +333,11 @@ public class CallerInfoAsyncQuery {
    - 
    -             //notify the listener that the query is complete.
    -             if (cw.listener != null) {
    --                if (DBG) Rlog.d(LOG_TAG, "notifying listener: " + cw.listener.getClass().toString() +
    -+                Rlog.d(LOG_TAG, "notifying listener: " + cw.listener.getClass().toString() +
    -                              " for token: " + token + mCallerInfo);
    -                 cw.listener.onQueryComplete(token, cw.cookie, mCallerInfo);
    -+            } else {
    -+                Rlog.w(LOG_TAG, "There is no listener to notify for this query.");
    -             }
    - 
    -             if (cursor != null) {
    -diff --git a/telephony/java/com/android/internal/telephony/PhoneConstants.java b/telephony/java/com/android/internal/telephony/PhoneConstants.java
    -index b417a1c..fdc68b9 100644
    ---- a/telephony/java/com/android/internal/telephony/PhoneConstants.java
    -+++ b/telephony/java/com/android/internal/telephony/PhoneConstants.java
    -@@ -140,6 +140,18 @@ public class PhoneConstants {
    -     /** APN type for Emergency PDN. This is not an IA apn, but is used
    -      * for access to carrier services in an emergency call situation. */
    -     public static final String APN_TYPE_EMERGENCY = "emergency";
    -+    /** Array of all APN types */
    -+    public static final String[] APN_TYPES = {APN_TYPE_DEFAULT,
    -+            APN_TYPE_MMS,
    -+            APN_TYPE_SUPL,
    -+            APN_TYPE_DUN,
    -+            APN_TYPE_HIPRI,
    -+            APN_TYPE_FOTA,
    -+            APN_TYPE_IMS,
    -+            APN_TYPE_CBS,
    -+            APN_TYPE_IA,
    -+            APN_TYPE_EMERGENCY
    -+    };
    - 
    -     public static final int RIL_CARD_MAX_APPS    = 8;
    - 
    -diff --git a/tests/Assist/res/drawable/assistant.xml b/tests/Assist/res/drawable/assistant.xml
    -index 2a89dda..56fe2de 100644
    ---- a/tests/Assist/res/drawable/assistant.xml
    -+++ b/tests/Assist/res/drawable/assistant.xml
    -@@ -19,9 +19,6 @@ Copyright (C) 2014 The Android Open Source Project
    -         android:viewportWidth="48.0"
    -         android:viewportHeight="48.0">
    -     <path
    --        android:pathData="M0 0h48v48H0z"
    --        android:fillColor="#00000000"/>
    --    <path
    -         android:fillColor="#FF000000"
    -         android:pathData="M38.0,4.0L10.0,4.0C7.79,4.0 6.0,5.79 6.0,8.0l0.0,28.0c0.0,2.21 1.79,4.0 4.0,4.0l8.0,0.0l6.0,6.0 6.0,-6.0l8.0,0.0c2.21,0.0 4.0,-1.79 4.0,-4.0L36.0,8.0c0.0,-2.21 -1.79,-4.0 -4.0,-4.0zM27.75,25.75L24.0,34.0l-3.75,-8.25L12.0,22.0l8.25,-3.75L24.0,10.0l3.75,8.25L36.0,22.0l-8.25,3.75z"/>
    - </vector>
    -diff --git a/tests/UiBench/AndroidManifest.xml b/tests/UiBench/AndroidManifest.xml
    -index 95bbb21..3d3247c 100644
    ---- a/tests/UiBench/AndroidManifest.xml
    -+++ b/tests/UiBench/AndroidManifest.xml
    -@@ -85,13 +85,21 @@
    -         </activity>
    -         <activity
    -             android:name=".TrivialRecyclerViewActivity"
    --            android:label="General/Trivial Recycler ListView" >
    -+            android:label="General/Trivial RecyclerView" >
    -             <intent-filter>
    -                 <action android:name="android.intent.action.MAIN" />
    -                 <category android:name="com.android.test.uibench.TEST" />
    -             </intent-filter>
    -         </activity>
    -         <activity
    -+            android:name=".SlowBindRecyclerViewActivity"
    -+            android:label="General/Slow Bind RecyclerView" >
    -+        <intent-filter>
    -+            <action android:name="android.intent.action.MAIN" />
    -+            <category android:name="com.android.test.uibench.TEST" />
    -+        </intent-filter>
    -+        </activity>
    -+        <activity
    -             android:name=".ActivityTransition"
    -             android:label="Transitions/Activity Transition" >
    -             <intent-filter>
    -diff --git a/tests/UiBench/src/com/android/test/uibench/SlowBindRecyclerViewActivity.java b/tests/UiBench/src/com/android/test/uibench/SlowBindRecyclerViewActivity.java
    -new file mode 100644
    -index 0000000..e32862f
    ---- /dev/null
    -+++ b/tests/UiBench/src/com/android/test/uibench/SlowBindRecyclerViewActivity.java
    -@@ -0,0 +1,55 @@
    -+/*
    -+ * Copyright (C) 2016 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 com.android.test.uibench;
    -+
    -+import android.content.Context;
    -+import android.os.Trace;
    -+import android.support.v7.widget.GridLayoutManager;
    -+import android.support.v7.widget.RecyclerView;
    -+import com.android.test.uibench.recyclerview.RvBoxAdapter;
    -+import com.android.test.uibench.recyclerview.RvCompatListActivity;
    -+
    -+import java.util.concurrent.TimeUnit;
    -+
    -+public class SlowBindRecyclerViewActivity extends RvCompatListActivity {
    -+    /**
    -+     * Spin wait. Used instead of sleeping so a core is used up for the duration, and so
    -+     * traces/sampled profiling show the sections as expensive, and not just a scheduling mistake.
    -+     */
    -+    private static void spinWaitMs(long ms) {
    -+        long start = System.nanoTime();
    -+        while (System.nanoTime() - start < TimeUnit.MILLISECONDS.toNanos(ms));
    -+    }
    -+
    -+    @Override
    -+    protected RecyclerView.LayoutManager createLayoutManager(Context context) {
    -+        return new GridLayoutManager(context, 3);
    -+    }
    -+
    -+    @Override
    -+    protected RecyclerView.Adapter createAdapter() {
    -+        return new RvBoxAdapter(this, TextUtils.buildSimpleStringList()) {
    -+            @Override
    -+            public void onBindViewHolder(ViewHolder holder, int position) {
    -+                Trace.beginSection("bind item " + position);
    -+
    -+                spinWaitMs(3);
    -+                super.onBindViewHolder(holder, position);
    -+                Trace.endSection();
    -+            }
    -+        };
    -+    }
    -+}
    -diff --git a/tests/UiBench/src/com/android/test/uibench/recyclerview/RvBoxAdapter.java b/tests/UiBench/src/com/android/test/uibench/recyclerview/RvBoxAdapter.java
    -new file mode 100644
    -index 0000000..3440f19
    ---- /dev/null
    -+++ b/tests/UiBench/src/com/android/test/uibench/recyclerview/RvBoxAdapter.java
    -@@ -0,0 +1,99 @@
    -+/*
    -+ * Copyright (C) 2016 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 com.android.test.uibench.recyclerview;
    -+
    -+import android.content.Context;
    -+import android.graphics.Color;
    -+import android.support.v7.widget.RecyclerView;
    -+import android.util.TypedValue;
    -+import android.view.ViewGroup;
    -+import android.widget.TextView;
    -+
    -+import java.util.ArrayList;
    -+import java.util.Collections;
    -+import java.util.List;
    -+
    -+public class RvBoxAdapter extends RecyclerView.Adapter<RvBoxAdapter.ViewHolder> {
    -+
    -+    private int mBackground;
    -+
    -+    private List<String> mValues;
    -+
    -+    public static class ViewHolder extends RecyclerView.ViewHolder {
    -+        public TextView mTextView;
    -+
    -+        public ViewHolder(TextView v) {
    -+            super(v);
    -+            mTextView = v;
    -+        }
    -+
    -+        @Override
    -+        public String toString() {
    -+            return super.toString() + " '" + mTextView.getText();
    -+        }
    -+    }
    -+
    -+    public RvBoxAdapter(Context context, String[] strings) {
    -+        TypedValue val = new TypedValue();
    -+        if (context.getTheme() != null) {
    -+            context.getTheme().resolveAttribute(
    -+                    android.R.attr.selectableItemBackground, val, true);
    -+        }
    -+        mBackground = val.resourceId;
    -+        mValues = new ArrayList<>();
    -+        Collections.addAll(mValues, strings);
    -+    }
    -+
    -+    @Override
    -+    public RvBoxAdapter.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
    -+        final ViewHolder h = new ViewHolder(new TextView(parent.getContext()));
    -+        h.mTextView.setMinimumHeight(128);
    -+        h.mTextView.setPadding(20, 0, 20, 0);
    -+        h.mTextView.setFocusable(true);
    -+        h.mTextView.setBackgroundResource(mBackground);
    -+        RecyclerView.LayoutParams lp = new RecyclerView.LayoutParams(
    -+                ViewGroup.LayoutParams.WRAP_CONTENT,
    -+                ViewGroup.LayoutParams.WRAP_CONTENT);
    -+        lp.leftMargin = 10;
    -+        lp.rightMargin = 5;
    -+        lp.topMargin = 20;
    -+        lp.bottomMargin = 15;
    -+        h.mTextView.setLayoutParams(lp);
    -+        return h;
    -+    }
    -+
    -+    @Override
    -+    public void onBindViewHolder(ViewHolder holder, int position) {
    -+        holder.mTextView.setText(position + ":" + mValues.get(position));
    -+        holder.mTextView.setMinHeight((200 + mValues.get(position).length() * 10));
    -+        holder.mTextView.setBackgroundColor(getBackgroundColor(position));
    -+    }
    -+
    -+    private int getBackgroundColor(int position) {
    -+        switch (position % 4) {
    -+            case 0: return Color.LTGRAY;
    -+            case 1: return Color.RED;
    -+            case 2: return Color.DKGRAY;
    -+            case 3: return Color.BLUE;
    -+        }
    -+        return Color.TRANSPARENT;
    -+    }
    -+
    -+    @Override
    -+    public int getItemCount() {
    -+        return mValues.size();
    -+    }
    -+}
    -diff --git a/tests/UiBench/src/com/android/test/uibench/recyclerview/RvCompatListActivity.java b/tests/UiBench/src/com/android/test/uibench/recyclerview/RvCompatListActivity.java
    -index e08dbc6..939b661 100644
    ---- a/tests/UiBench/src/com/android/test/uibench/recyclerview/RvCompatListActivity.java
    -+++ b/tests/UiBench/src/com/android/test/uibench/recyclerview/RvCompatListActivity.java
    -@@ -26,7 +26,6 @@ import android.support.v7.widget.RecyclerView;
    - import android.view.LayoutInflater;
    - import android.view.View;
    - import android.view.ViewGroup;
    --import android.widget.ArrayAdapter;
    - 
    - import com.android.test.uibench.R;
    - 
    -diff --git a/tools/aapt/Command.cpp b/tools/aapt/Command.cpp
    -index 59da467..ad583a8 100644
    ---- a/tools/aapt/Command.cpp
    -+++ b/tools/aapt/Command.cpp
    -@@ -540,7 +540,7 @@ static bool hasFeature(const char* name, const FeatureGroup& grp,
    - }
    - 
    - static void addImpliedFeature(KeyedVector<String8, ImpliedFeature>* impliedFeatures,
    --                              const char* name, const char* reason, bool sdk23) {
    -+                              const char* name, const String8& reason, bool sdk23) {
    -     String8 name8(name);
    -     ssize_t idx = impliedFeatures->indexOfKey(name8);
    -     if (idx < 0) {
    -@@ -553,7 +553,7 @@ static void addImpliedFeature(KeyedVector<String8, ImpliedFeature>* impliedFeatu
    -     if (feature->impliedBySdk23 && !sdk23) {
    -         feature->impliedBySdk23 = false;
    -     }
    --    feature->reasons.add(String8(reason));
    -+    feature->reasons.add(reason);
    - }
    - 
    - static void printFeatureGroupImpl(const FeatureGroup& grp,
    -@@ -651,50 +651,58 @@ static void addImpliedFeaturesForPermission(const int targetSdk, const String8&
    -                                             bool impliedBySdk23Permission) {
    -     if (name == "android.permission.CAMERA") {
    -         addImpliedFeature(impliedFeatures, "android.hardware.camera",
    --                String8::format("requested %s permission", name.string())
    --                .string(), impliedBySdk23Permission);
    -+                          String8::format("requested %s permission", name.string()),
    -+                          impliedBySdk23Permission);
    -     } else if (name == "android.permission.ACCESS_FINE_LOCATION") {
    --        addImpliedFeature(impliedFeatures, "android.hardware.location.gps",
    --                String8::format("requested %s permission", name.string())
    --                .string(), impliedBySdk23Permission);
    --        addImpliedFeature(impliedFeatures, "android.hardware.location",
    --                String8::format("requested %s permission", name.string())
    --                .string(), impliedBySdk23Permission);
    --    } else if (name == "android.permission.ACCESS_MOCK_LOCATION") {
    -+        if (targetSdk < SDK_LOLLIPOP) {
    -+            addImpliedFeature(impliedFeatures, "android.hardware.location.gps",
    -+                              String8::format("requested %s permission", name.string()),
    -+                              impliedBySdk23Permission);
    -+            addImpliedFeature(impliedFeatures, "android.hardware.location.gps",
    -+                              String8::format("targetSdkVersion < %d", SDK_LOLLIPOP),
    -+                              impliedBySdk23Permission);
    -+        }
    -         addImpliedFeature(impliedFeatures, "android.hardware.location",
    --                String8::format("requested %s permission", name.string())
    --                .string(), impliedBySdk23Permission);
    -+                String8::format("requested %s permission", name.string()),
    -+                impliedBySdk23Permission);
    -     } else if (name == "android.permission.ACCESS_COARSE_LOCATION") {
    --        addImpliedFeature(impliedFeatures, "android.hardware.location.network",
    --                String8::format("requested %s permission", name.string())
    --                .string(), impliedBySdk23Permission);
    -+        if (targetSdk < SDK_LOLLIPOP) {
    -+            addImpliedFeature(impliedFeatures, "android.hardware.location.network",
    -+                              String8::format("requested %s permission", name.string()),
    -+                              impliedBySdk23Permission);
    -+            addImpliedFeature(impliedFeatures, "android.hardware.location.network",
    -+                              String8::format("targetSdkVersion < %d", SDK_LOLLIPOP),
    -+                              impliedBySdk23Permission);
    -+        }
    -         addImpliedFeature(impliedFeatures, "android.hardware.location",
    --                String8::format("requested %s permission", name.string())
    --                .string(), impliedBySdk23Permission);
    --    } else if (name == "android.permission.ACCESS_LOCATION_EXTRA_COMMANDS" ||
    -+                          String8::format("requested %s permission", name.string()),
    -+                          impliedBySdk23Permission);
    -+    } else if (name == "android.permission.ACCESS_MOCK_LOCATION" ||
    -+               name == "android.permission.ACCESS_LOCATION_EXTRA_COMMANDS" ||
    -                name == "android.permission.INSTALL_LOCATION_PROVIDER") {
    -         addImpliedFeature(impliedFeatures, "android.hardware.location",
    --                String8::format("requested %s permission", name.string())
    --                .string(), impliedBySdk23Permission);
    -+                          String8::format("requested %s permission", name.string()),
    -+                          impliedBySdk23Permission);
    -     } else if (name == "android.permission.BLUETOOTH" ||
    -                name == "android.permission.BLUETOOTH_ADMIN") {
    --        if (targetSdk > 4) {
    -+        if (targetSdk > SDK_DONUT) {
    -             addImpliedFeature(impliedFeatures, "android.hardware.bluetooth",
    --                    String8::format("requested %s permission", name.string())
    --                    .string(), impliedBySdk23Permission);
    -+                              String8::format("requested %s permission", name.string()),
    -+                              impliedBySdk23Permission);
    -             addImpliedFeature(impliedFeatures, "android.hardware.bluetooth",
    --                    "targetSdkVersion > 4", impliedBySdk23Permission);
    -+                              String8::format("targetSdkVersion > %d", SDK_DONUT),
    -+                              impliedBySdk23Permission);
    -         }
    -     } else if (name == "android.permission.RECORD_AUDIO") {
    -         addImpliedFeature(impliedFeatures, "android.hardware.microphone",
    --                String8::format("requested %s permission", name.string())
    --                .string(), impliedBySdk23Permission);
    -+                          String8::format("requested %s permission", name.string()),
    -+                          impliedBySdk23Permission);
    -     } else if (name == "android.permission.ACCESS_WIFI_STATE" ||
    -                name == "android.permission.CHANGE_WIFI_STATE" ||
    -                name == "android.permission.CHANGE_WIFI_MULTICAST_STATE") {
    -         addImpliedFeature(impliedFeatures, "android.hardware.wifi",
    --                String8::format("requested %s permission", name.string())
    --                .string(), impliedBySdk23Permission);
    -+                          String8::format("requested %s permission", name.string()),
    -+                          impliedBySdk23Permission);
    -     } else if (name == "android.permission.CALL_PHONE" ||
    -                name == "android.permission.CALL_PRIVILEGED" ||
    -                name == "android.permission.MODIFY_PHONE_STATE" ||
    -@@ -707,8 +715,8 @@ static void addImpliedFeaturesForPermission(const int targetSdk, const String8&
    -                name == "android.permission.WRITE_APN_SETTINGS" ||
    -                name == "android.permission.WRITE_SMS") {
    -         addImpliedFeature(impliedFeatures, "android.hardware.telephony",
    --                String8("requested a telephony permission").string(),
    --                impliedBySdk23Permission);
    -+                          String8("requested a telephony permission"),
    -+                          impliedBySdk23Permission);
    -     }
    - }
    - 
    -@@ -1659,18 +1667,18 @@ int doDump(Bundle* bundle)
    -                             if (error == "") {
    -                                 if (orien == 0 || orien == 6 || orien == 8) {
    -                                     // Requests landscape, sensorLandscape, or reverseLandscape.
    --                                    addImpliedFeature(&impliedFeatures,
    --                                                      "android.hardware.screen.landscape",
    --                                                      "one or more activities have specified a "
    --                                                      "landscape orientation",
    --                                                      false);
    -+                                    addImpliedFeature(
    -+                                            &impliedFeatures, "android.hardware.screen.landscape",
    -+                                            String8("one or more activities have specified a "
    -+                                                    "landscape orientation"),
    -+                                            false);
    -                                 } else if (orien == 1 || orien == 7 || orien == 9) {
    -                                     // Requests portrait, sensorPortrait, or reversePortrait.
    --                                    addImpliedFeature(&impliedFeatures,
    --                                                      "android.hardware.screen.portrait",
    --                                                      "one or more activities have specified a "
    --                                                      "portrait orientation",
    --                                                      false);
    -+                                    addImpliedFeature(
    -+                                            &impliedFeatures, "android.hardware.screen.portrait",
    -+                                            String8("one or more activities have specified a "
    -+                                                    "portrait orientation"),
    -+                                            false);
    -                                 }
    -                             }
    -                         } else if (tag == "uses-library") {
    -@@ -2026,7 +2034,7 @@ int doDump(Bundle* bundle)
    -             // directly or implied, required or not), then the faketouch feature is implied.
    -             if (!hasFeature("android.hardware.touchscreen", commonFeatures, impliedFeatures)) {
    -                 addImpliedFeature(&impliedFeatures, "android.hardware.faketouch",
    --                                  "default feature for all apps", false);
    -+                                  String8("default feature for all apps"), false);
    -             }
    - 
    -             const size_t numFeatureGroups = featureGroups.size();
    -diff --git a/tools/fonts/fontchain_lint.py b/tools/fonts/fontchain_lint.py
    -index 2956d87..7ec46a3e 100755
    ---- a/tools/fonts/fontchain_lint.py
    -+++ b/tools/fonts/fontchain_lint.py
    -@@ -256,8 +256,8 @@ def parse_fonts_xml(fonts_xml_path):
    - 
    - 
    - def check_emoji_coverage(all_emoji, equivalent_emoji):
    --  emoji_font = get_emoji_font()
    --  check_emoji_font_coverage(emoji_font, all_emoji, equivalent_emoji)
    -+    emoji_font = get_emoji_font()
    -+    check_emoji_font_coverage(emoji_font, all_emoji, equivalent_emoji)
    - 
    - 
    - def get_emoji_font():
    -@@ -274,15 +274,12 @@ def check_emoji_font_coverage(emoji_font, all_emoji, equivalent_emoji):
    -         assert sequence in coverage, (
    -             '%s is not supported in the emoji font.' % printable(sequence))
    - 
    --    # disable temporarily - we cover more than this
    --    """
    -     for sequence in coverage:
    -         if sequence in {0x0000, 0x000D, 0x0020}:
    -             # The font needs to support a few extra characters, which is OK
    -             continue
    -         assert sequence in all_emoji, (
    -             'Emoji font should not support %s.' % printable(sequence))
    --    """
    - 
    -     for first, second in sorted(equivalent_emoji.items()):
    -         assert coverage[first] == coverage[second], (
    -@@ -290,8 +287,6 @@ def check_emoji_font_coverage(emoji_font, all_emoji, equivalent_emoji):
    -                 printable(first),
    -                 printable(second)))
    - 
    --    # disable temporarily - some equivalent sequences we don't even know about
    --    """
    -     for glyph in set(coverage.values()):
    -         maps_to_glyph = [seq for seq in coverage if coverage[seq] == glyph]
    -         if len(maps_to_glyph) > 1:
    -@@ -307,7 +302,7 @@ def check_emoji_font_coverage(emoji_font, all_emoji, equivalent_emoji):
    -                 'The sequences %s should not result in the same glyph %s' % (
    -                     printable(equivalent_seqs),
    -                     glyph))
    --    """
    -+
    - 
    - def check_emoji_defaults(default_emoji):
    -     missing_text_chars = _emoji_properties['Emoji'] - default_emoji
    -@@ -334,15 +329,9 @@ def check_emoji_defaults(default_emoji):
    -     # Noto does not have monochrome glyphs for Unicode 7.0 wingdings and
    -     # webdings yet.
    -     missing_text_chars -= _chars_by_age['7.0']
    --    # TODO: Remove these after b/26113320 is fixed
    --    missing_text_chars -= {
    --        0x263A, # WHITE SMILING FACE
    --        0x270C, # VICTORY HAND
    --        0x2744, # SNOWFLAKE
    --        0x2764, # HEAVY BLACK HEART
    --    }
    -     assert missing_text_chars == set(), (
    --        'Text style version of some emoji characters are missing: ' + repr(missing_text_chars))
    -+        'Text style version of some emoji characters are missing: ' +
    -+            repr(missing_text_chars))
    - 
    - 
    - # Setting reverse to true returns a dictionary that maps the values to sets of
    -@@ -362,7 +351,7 @@ def parse_unicode_datafile(file_path, reverse=False):
    -             if not line:
    -                 continue
    - 
    --            chars, prop = line.split(';')
    -+            chars, prop = line.split(';')[:2]
    -             chars = chars.strip()
    -             prop = prop.strip()
    - 
    -@@ -423,26 +412,6 @@ def parse_ucd(ucd_path):
    -     _emoji_zwj_sequences = parse_unicode_datafile(
    -         path.join(ucd_path, 'emoji-zwj-sequences.txt'))
    - 
    --    # filter modern pentathlon, as it seems likely to be removed from final spec
    --    # also filter rifle
    --    def is_excluded(n):
    --        return n in [0x1f93b, 0x1f946]
    --
    --    def contains_excluded(t):
    --        if type(t) == int:
    --            return is_excluded(t)
    --        return any(is_excluded(cp) for cp in t)
    --
    --    # filter modern pentathlon, as it seems likely to be removed from final spec
    --    _emoji_properties['Emoji'] = set(
    --        t for t in _emoji_properties['Emoji'] if not contains_excluded(t))
    --    _emoji_sequences = dict(
    --        (t, v) for (t, v) in _emoji_sequences.items() if not contains_excluded(t))
    --
    --    # add in UN flag
    --    UN_seq = flag_sequence('UN')
    --    _emoji_sequences[UN_seq] = 'Emoji_Flag_Sequence'
    --
    - 
    - def flag_sequence(territory_code):
    -     return tuple(0x1F1E6 + ord(ch) - ord('A') for ch in territory_code)
    -@@ -454,7 +423,8 @@ UNSUPPORTED_FLAGS = frozenset({
    -     flag_sequence('GF'), flag_sequence('GP'), flag_sequence('GS'),
    -     flag_sequence('MF'), flag_sequence('MQ'), flag_sequence('NC'),
    -     flag_sequence('PM'), flag_sequence('RE'), flag_sequence('TF'),
    --    flag_sequence('WF'), flag_sequence('XK'), flag_sequence('YT'),
    -+    flag_sequence('UN'), flag_sequence('WF'), flag_sequence('XK'),
    -+    flag_sequence('YT'),
    - })
    - 
    - EQUIVALENT_FLAGS = {
    -@@ -467,6 +437,22 @@ EQUIVALENT_FLAGS = {
    - 
    - COMBINING_KEYCAP = 0x20E3
    - 
    -+# Characters that Android defaults to emoji style, different from the recommendations in UTR #51
    -+ANDROID_DEFAULT_EMOJI = frozenset({
    -+    0x2600, # BLACK SUN WITH RAYS
    -+    0x2601, # CLOUD
    -+    0x260E, # BLACK TELEPHONE
    -+    0x261D, # WHITE UP POINTING INDEX
    -+    0x263A, # WHITE SMILING FACE
    -+    0x2660, # BLACK SPADE SUIT
    -+    0x2663, # BLACK CLUB SUIT
    -+    0x2665, # BLACK HEART SUIT
    -+    0x2666, # BLACK DIAMOND SUIT
    -+    0x270C, # VICTORY HAND
    -+    0x2744, # SNOWFLAKE
    -+    0x2764, # HEAVY BLACK HEART
    -+})
    -+
    - LEGACY_ANDROID_EMOJI = {
    -     0xFE4E5: flag_sequence('JP'),
    -     0xFE4E6: flag_sequence('US'),
    -@@ -502,7 +488,17 @@ ZWJ_IDENTICALS = {
    - 
    - 
    - def is_fitzpatrick_modifier(cp):
    --  return 0x1f3fb <= cp <= 0x1f3ff
    -+    return 0x1F3FB <= cp <= 0x1F3FF
    -+
    -+
    -+def reverse_emoji(seq):
    -+    rev = list(reversed(seq))
    -+    # if there are fitzpatrick modifiers in the sequence, keep them after
    -+    # the emoji they modify
    -+    for i in xrange(1, len(rev)):
    -+        if is_fitzpatrick_modifier(rev[i-1]):
    -+            rev[i], rev[i-1] = rev[i-1], rev[i]
    -+    return tuple(rev)
    - 
    - 
    - def compute_expected_emoji():
    -@@ -511,26 +507,52 @@ def compute_expected_emoji():
    -     all_sequences = set()
    -     all_sequences.update(_emoji_variation_sequences)
    - 
    -+    # add zwj sequences not in the current emoji-zwj-sequences.txt
    -+    adjusted_emoji_zwj_sequences = dict(_emoji_zwj_sequences)
    -+    adjusted_emoji_zwj_sequences.update(_emoji_zwj_sequences)
    -+    # single parent families
    -+    additional_emoji_zwj = (
    -+        (0x1F468, 0x200D, 0x1F466),
    -+        (0x1F468, 0x200D, 0x1F467),
    -+        (0x1F468, 0x200D, 0x1F466, 0x200D, 0x1F466),
    -+        (0x1F468, 0x200D, 0x1F467, 0x200D, 0x1F466),
    -+        (0x1F468, 0x200D, 0x1F467, 0x200D, 0x1F467),
    -+        (0x1F469, 0x200D, 0x1F466),
    -+        (0x1F469, 0x200D, 0x1F467),
    -+        (0x1F469, 0x200D, 0x1F466, 0x200D, 0x1F466),
    -+        (0x1F469, 0x200D, 0x1F467, 0x200D, 0x1F466),
    -+        (0x1F469, 0x200D, 0x1F467, 0x200D, 0x1F467),
    -+    )
    -+    # sequences formed from man and woman and optional fitzpatrick modifier
    -+    modified_extensions = (
    -+        0x2696,
    -+        0x2708,
    -+        0x1F3A8,
    -+        0x1F680,
    -+        0x1F692,
    -+    )
    -+    for seq in additional_emoji_zwj:
    -+        adjusted_emoji_zwj_sequences[seq] = 'Emoji_ZWJ_Sequence'
    -+    for ext in modified_extensions:
    -+        for base in (0x1F468, 0x1F469):
    -+            seq = (base, 0x200D, ext)
    -+            adjusted_emoji_zwj_sequences[seq] = 'Emoji_ZWJ_Sequence'
    -+            for modifier in range(0x1F3FB, 0x1F400):
    -+                seq = (base, modifier, 0x200D, ext)
    -+                adjusted_emoji_zwj_sequences[seq] = 'Emoji_ZWJ_Sequence'
    -+
    -     for sequence in _emoji_sequences.keys():
    -         sequence = tuple(ch for ch in sequence if ch != EMOJI_VS)
    -         all_sequences.add(sequence)
    -         sequence_pieces.update(sequence)
    - 
    --    for sequence in _emoji_zwj_sequences.keys():
    -+    for sequence in adjusted_emoji_zwj_sequences.keys():
    -         sequence = tuple(ch for ch in sequence if ch != EMOJI_VS)
    -         all_sequences.add(sequence)
    -         sequence_pieces.update(sequence)
    -         # Add reverse of all emoji ZWJ sequences, which are added to the fonts
    -         # as a workaround to get the sequences work in RTL text.
    --        reversed_seq = list(reversed(sequence))
    --        # if there are fitzpatrick modifiers in the sequence, keep them after
    --        # the emoji they modify
    --        for i in xrange(1, len(reversed_seq)):
    --          if is_fitzpatrick_modifier(reversed_seq[i - 1]):
    --            tmp = reversed_seq[i]
    --            reversed_seq[i] = reversed_seq[i-1]
    --            reversed_seq[i-1] = tmp
    --        reversed_seq = tuple(reversed_seq)
    -+        reversed_seq = reverse_emoji(sequence)
    -         all_sequences.add(reversed_seq)
    -         equivalent_emoji[reversed_seq] = sequence
    - 
    -@@ -549,6 +571,7 @@ def compute_expected_emoji():
    -         set(LEGACY_ANDROID_EMOJI.keys()))
    -     default_emoji = (
    -         _emoji_properties['Emoji_Presentation'] |
    -+        ANDROID_DEFAULT_EMOJI |
    -         all_sequences |
    -         set(LEGACY_ANDROID_EMOJI.keys()))
    - 
    -diff --git a/tools/layoutlib/bridge/src/android/view/IWindowManagerImpl.java b/tools/layoutlib/bridge/src/android/view/IWindowManagerImpl.java
    -index 58df301..0c3231b 100644
    ---- a/tools/layoutlib/bridge/src/android/view/IWindowManagerImpl.java
    -+++ b/tools/layoutlib/bridge/src/android/view/IWindowManagerImpl.java
    -@@ -96,7 +96,7 @@ public class IWindowManagerImpl implements IWindowManager {
    -     }
    - 
    -     @Override
    --    public void clearForcedDisplayDensity(int displayId) throws RemoteException {
    -+    public void clearForcedDisplayDensityForUser(int displayId, int userId) throws RemoteException {
    -         // TODO Auto-generated method stub
    -     }
    - 
    -@@ -397,7 +397,8 @@ public class IWindowManagerImpl implements IWindowManager {
    -     }
    - 
    -     @Override
    --    public void setForcedDisplayDensity(int displayId, int density) throws RemoteException {
    -+    public void setForcedDisplayDensityForUser(int displayId, int density, int userId)
    -+            throws RemoteException {
    -         // TODO Auto-generated method stub
    -     }
    - 
    -@@ -459,6 +460,16 @@ public class IWindowManagerImpl implements IWindowManager {
    -     }
    - 
    -     @Override
    -+    public void setRecentsVisibility(boolean visible) {
    -+        // TODO Auto-generated method stub
    -+    }
    -+
    -+    @Override
    -+    public void setTvPipVisibility(boolean visible) {
    -+        // TODO Auto-generated method stub
    -+    }
    -+
    -+    @Override
    -     public void stopAppFreezingScreen(IBinder arg0, boolean arg1) throws RemoteException {
    -         // TODO Auto-generated method stub
    -     }
    -diff --git a/wifi/java/android/net/wifi/WifiConfiguration.java b/wifi/java/android/net/wifi/WifiConfiguration.java
    -index 9d0c20c..d3d5ea0 100644
    ---- a/wifi/java/android/net/wifi/WifiConfiguration.java
    -+++ b/wifi/java/android/net/wifi/WifiConfiguration.java
    -@@ -817,6 +817,7 @@ public class WifiConfiguration implements Parcelable {
    -          */
    -         public static final int NETWORK_SELECTION_ENABLE = 0;
    -         /**
    -+         * @deprecated it is not used any more.
    -          * This network is disabled because higher layer (>2) network is bad
    -          */
    -         public static final int DISABLED_BAD_LINK = 1;
    -@@ -862,7 +863,7 @@ public class WifiConfiguration implements Parcelable {
    -          */
    -         private static final String[] QUALITY_NETWORK_SELECTION_DISABLE_REASON = {
    -                 "NETWORK_SELECTION_ENABLE",
    --                "NETWORK_SELECTION_DISABLED_BAD_LINK",
    -+                "NETWORK_SELECTION_DISABLED_BAD_LINK", // deprecated
    -                 "NETWORK_SELECTION_DISABLED_ASSOCIATION_REJECTION ",
    -                 "NETWORK_SELECTION_DISABLED_AUTHENTICATION_FAILURE",
    -                 "NETWORK_SELECTION_DISABLED_DHCP_FAILURE",
    -diff --git a/wifi/java/android/net/wifi/WifiManager.java b/wifi/java/android/net/wifi/WifiManager.java
    -index bbc3d2f..1633bd9c9 100644
    ---- a/wifi/java/android/net/wifi/WifiManager.java
    -+++ b/wifi/java/android/net/wifi/WifiManager.java
    -@@ -49,6 +49,8 @@ import java.util.concurrent.CountDownLatch;
    -  * This class provides the primary API for managing all aspects of Wi-Fi
    -  * connectivity. Get an instance of this class by calling
    -  * {@link android.content.Context#getSystemService(String) Context.getSystemService(Context.WIFI_SERVICE)}.
    -+ * On releases before NYC, it should only be obtained from an application context, and not from
    -+ * any other derived context to avoid memory leaks within the calling process.
    - 
    -  * It deals with several categories of items:
    -  * <ul>
    -diff --git a/wifi/java/android/net/wifi/WifiScanner.java b/wifi/java/android/net/wifi/WifiScanner.java
    -index 716f1d3..3190ead 100644
    ---- a/wifi/java/android/net/wifi/WifiScanner.java
    -+++ b/wifi/java/android/net/wifi/WifiScanner.java
    -@@ -286,6 +286,12 @@ public class WifiScanner {
    -          * {@hide}
    -          */
    -         private int mBucketsScanned;
    -+        /**
    -+         * Indicates that the scan results received are as a result of a scan of all available
    -+         * channels. This should only be expected to function for single scans.
    -+         * {@hide}
    -+         */
    -+        private boolean mAllChannelsScanned;
    -         /** all scan results discovered in this scan, sorted by timestamp in ascending order */
    -         private ScanResult mResults[];
    - 
    -@@ -298,10 +304,12 @@ public class WifiScanner {
    -         }
    - 
    -         /** {@hide} */
    --        public ScanData(int id, int flags, int bucketsScanned, ScanResult[] results) {
    -+        public ScanData(int id, int flags, int bucketsScanned, boolean allChannelsScanned,
    -+                ScanResult[] results) {
    -             mId = id;
    -             mFlags = flags;
    -             mBucketsScanned = bucketsScanned;
    -+            mAllChannelsScanned = allChannelsScanned;
    -             mResults = results;
    -         }
    - 
    -@@ -309,6 +317,7 @@ public class WifiScanner {
    -             mId = s.mId;
    -             mFlags = s.mFlags;
    -             mBucketsScanned = s.mBucketsScanned;
    -+            mAllChannelsScanned = s.mAllChannelsScanned;
    -             mResults = new ScanResult[s.mResults.length];
    -             for (int i = 0; i < s.mResults.length; i++) {
    -                 ScanResult result = s.mResults[i];
    -@@ -330,6 +339,11 @@ public class WifiScanner {
    -             return mBucketsScanned;
    -         }
    - 
    -+        /** {@hide} */
    -+        public boolean isAllChannelsScanned() {
    -+            return mAllChannelsScanned;
    -+        }
    -+
    -         public ScanResult[] getResults() {
    -             return mResults;
    -         }
    -@@ -345,6 +359,7 @@ public class WifiScanner {
    -                 dest.writeInt(mId);
    -                 dest.writeInt(mFlags);
    -                 dest.writeInt(mBucketsScanned);
    -+                dest.writeInt(mAllChannelsScanned ? 1 : 0);
    -                 dest.writeInt(mResults.length);
    -                 for (int i = 0; i < mResults.length; i++) {
    -                     ScanResult result = mResults[i];
    -@@ -362,12 +377,13 @@ public class WifiScanner {
    -                         int id = in.readInt();
    -                         int flags = in.readInt();
    -                         int bucketsScanned = in.readInt();
    -+                        boolean allChannelsScanned = in.readInt() != 0;
    -                         int n = in.readInt();
    -                         ScanResult results[] = new ScanResult[n];
    -                         for (int i = 0; i < n; i++) {
    -                             results[i] = ScanResult.CREATOR.createFromParcel(in);
    -                         }
    --                        return new ScanData(id, flags, bucketsScanned, results);
    -+                        return new ScanData(id, flags, bucketsScanned, allChannelsScanned, results);
    -                     }
    - 
    -                     public ScanData[] newArray(int size) {
    diff --git a/frameworks_native.patch b/frameworks_native.patch
    index d35a429..4bc0763 100644
    --- a/frameworks_native.patch
    +++ b/frameworks_native.patch
    @@ -1,16 +1,8 @@
     diff --git a/cmds/atrace/atrace.cpp b/cmds/atrace/atrace.cpp
    -index facf300..86c315c 100644
    +index 5885738..86c315c 100644
     --- a/cmds/atrace/atrace.cpp
     +++ b/cmds/atrace/atrace.cpp
    -@@ -102,6 +102,7 @@ static const TracingCategory k_categories[] = {
    -     { "pm",         "Package Manager",  ATRACE_TAG_PACKAGE_MANAGER, { } },
    -     { "ss",         "System Server",    ATRACE_TAG_SYSTEM_SERVER, { } },
    -     { "database",   "Database",         ATRACE_TAG_DATABASE, { } },
    -+    { "network",    "Network",          ATRACE_TAG_NETWORK, { } },
    -     { k_coreServiceCategory, "Core services", 0, { } },
    -     { "sched",      "CPU Scheduling",   0, {
    -         { REQ,      "/sys/kernel/debug/tracing/events/sched/sched_switch/enable" },
    -@@ -593,16 +594,30 @@ static bool verifyKernelTraceFuncs(const char* funcs)
    +@@ -594,16 +594,30 @@ static bool verifyKernelTraceFuncs(const char* funcs)
              return false;
          }
      
    @@ -49,7 +41,7 @@ index facf300..86c315c 100644
          String8 funcList = String8::format("\n%s", buf);
      
          // Make sure that every function listed in funcs is in the list we just
    -@@ -622,8 +637,8 @@ static bool verifyKernelTraceFuncs(const char* funcs)
    +@@ -623,8 +637,8 @@ static bool verifyKernelTraceFuncs(const char* funcs)
              }
              func = strtok(NULL, ",");
          }
    @@ -59,429 +51,6 @@ index facf300..86c315c 100644
          return ok;
      }
      
    -diff --git a/cmds/atrace/atrace.rc b/cmds/atrace/atrace.rc
    -index c2f8891..e3cc9da 100644
    ---- a/cmds/atrace/atrace.rc
    -+++ b/cmds/atrace/atrace.rc
    -@@ -1,6 +1,6 @@
    - ## Permissions to allow system-wide tracing to the kernel trace buffer.
    - ##
    --on boot
    -+on fs
    - 
    - # Allow writing to the kernel trace log.
    -     chmod 0222 /sys/kernel/debug/tracing/trace_marker
    -diff --git a/cmds/dumpstate/dumpstate.cpp b/cmds/dumpstate/dumpstate.cpp
    -index e9f9e57..9321a00 100644
    ---- a/cmds/dumpstate/dumpstate.cpp
    -+++ b/cmds/dumpstate/dumpstate.cpp
    -@@ -149,7 +149,7 @@ void do_mountinfo(int pid, const char *name) {
    - }
    - 
    - void add_mountinfo() {
    --    if (!zip_writer) return;
    -+    if (!is_zipping()) return;
    -     const char *title = "MOUNT INFO";
    -     mount_points.clear();
    -     DurationReporter duration_reporter(title, NULL);
    -@@ -180,8 +180,8 @@ static void dump_dev_files(const char *title, const char *driverpath, const char
    - }
    - 
    - static void dump_systrace() {
    --    if (!zip_writer) {
    --        MYLOGD("Not dumping systrace because zip_writer is not set\n");
    -+    if (!is_zipping()) {
    -+        MYLOGD("Not dumping systrace because dumpstate is not zipping\n");
    -         return;
    -     }
    -     std::string systrace_path = bugreport_dir + "/systrace-" + suffix + ".txt";
    -@@ -237,7 +237,7 @@ static void dump_raft() {
    -         return;
    -     }
    - 
    --    if (!zip_writer) {
    -+    if (!is_zipping()) {
    -         // Write compressed and encoded raft logs to stdout if not zip_writer.
    -         run_command("RAFT LOGS", 600, "logcompressor", "-r", RAFT_DIR, NULL);
    -         return;
    -@@ -575,8 +575,8 @@ static const std::set<std::string> PROBLEMATIC_FILE_EXTENSIONS = {
    - };
    - 
    - bool add_zip_entry_from_fd(const std::string& entry_name, int fd) {
    --    if (!zip_writer) {
    --        MYLOGD("Not adding zip entry %s from fd because zip_writer is not set\n",
    -+    if (!is_zipping()) {
    -+        MYLOGD("Not adding entry %s from fd because dumpstate is not zipping\n",
    -                 entry_name.c_str());
    -         return false;
    -     }
    -@@ -645,8 +645,8 @@ static int _add_file_from_fd(const char *title, const char *path, int fd) {
    - 
    - // TODO: move to util.cpp
    - void add_dir(const char *dir, bool recursive) {
    --    if (!zip_writer) {
    --        MYLOGD("Not adding dir %s because zip_writer is not set\n", dir);
    -+    if (!is_zipping()) {
    -+        MYLOGD("Not adding dir %s because dumpstate is not zipping\n", dir);
    -         return;
    -     }
    -     MYLOGD("Adding dir %s (recursive: %d)\n", dir, recursive);
    -@@ -654,10 +654,14 @@ void add_dir(const char *dir, bool recursive) {
    -     dump_files(NULL, dir, recursive ? skip_none : is_dir, _add_file_from_fd);
    - }
    - 
    -+bool is_zipping() {
    -+    return zip_writer != nullptr;
    -+}
    -+
    - /* adds a text entry entry to the existing zip file. */
    - static bool add_text_zip_entry(const std::string& entry_name, const std::string& content) {
    --    if (!zip_writer) {
    --        MYLOGD("Not adding text zip entry %s because zip_writer is not set\n", entry_name.c_str());
    -+    if (!is_zipping()) {
    -+        MYLOGD("Not adding text entry %s because dumpstate is not zipping\n", entry_name.c_str());
    -         return false;
    -     }
    -     MYLOGD("Adding zip text entry %s\n", entry_name.c_str());
    -@@ -687,10 +691,12 @@ static bool add_text_zip_entry(const std::string& entry_name, const std::string&
    - static void dump_iptables() {
    -     run_command("IPTABLES", 10, "iptables", "-L", "-nvx", NULL);
    -     run_command("IP6TABLES", 10, "ip6tables", "-L", "-nvx", NULL);
    --    run_command("IPTABLE NAT", 10, "iptables", "-t", "nat", "-L", "-nvx", NULL);
    -+    run_command("IPTABLES NAT", 10, "iptables", "-t", "nat", "-L", "-nvx", NULL);
    -     /* no ip6 nat */
    --    run_command("IPTABLE RAW", 10, "iptables", "-t", "raw", "-L", "-nvx", NULL);
    --    run_command("IP6TABLE RAW", 10, "ip6tables", "-t", "raw", "-L", "-nvx", NULL);
    -+    run_command("IPTABLES MANGLE", 10, "iptables", "-t", "mangle", "-L", "-nvx", NULL);
    -+    run_command("IP6TABLES MANGLE", 10, "ip6tables", "-t", "mangle", "-L", "-nvx", NULL);
    -+    run_command("IPTABLES RAW", 10, "iptables", "-t", "raw", "-L", "-nvx", NULL);
    -+    run_command("IP6TABLES RAW", 10, "ip6tables", "-t", "raw", "-L", "-nvx", NULL);
    - }
    - 
    - static void dumpstate(const std::string& screenshot_path, const std::string& version) {
    -@@ -1371,6 +1377,12 @@ int main(int argc, char *argv[]) {
    -     add_mountinfo();
    -     dump_iptables();
    - 
    -+    // Capture any IPSec policies in play.  No keys are exposed here.
    -+    run_command("IP XFRM POLICY", 10, "ip", "xfrm", "policy", nullptr);
    -+
    -+    // Run ss as root so we can see socket marks.
    -+    run_command("DETAILED SOCKET STATE", 10, "ss", "-eionptu", NULL);
    -+
    -     if (!drop_root_user()) {
    -         return -1;
    -     }
    -diff --git a/cmds/dumpstate/dumpstate.h b/cmds/dumpstate/dumpstate.h
    -index 5e083cc..514af59 100644
    ---- a/cmds/dumpstate/dumpstate.h
    -+++ b/cmds/dumpstate/dumpstate.h
    -@@ -87,6 +87,9 @@ extern std::string bugreport_dir;
    - /* root dir for all files copied as-is into the bugreport. */
    - extern const std::string ZIP_ROOT_DIR;
    - 
    -+/* Checkes whether dumpstate is generating a zipped bugreport. */
    -+bool is_zipping();
    -+
    - /* adds a new entry to the existing zip file. */
    - bool add_zip_entry(const std::string& entry_name, const std::string& entry_path);
    - 
    -diff --git a/cmds/installd/commands.cpp b/cmds/installd/commands.cpp
    -index 2014e99..271c75b 100644
    ---- a/cmds/installd/commands.cpp
    -+++ b/cmds/installd/commands.cpp
    -@@ -99,23 +99,69 @@ static std::string create_primary_profile(const std::string& profile_dir) {
    -     return StringPrintf("%s/%s", profile_dir.c_str(), PRIMARY_PROFILE_NAME);
    - }
    - 
    --static int prepare_app_dir(const std::string& path, mode_t target_mode, uid_t uid,
    --        const char* pkgname, const char* seinfo) {
    -+/**
    -+ * Perform restorecon of the given path, but only perform recursive restorecon
    -+ * if the label of that top-level file actually changed.  This can save us
    -+ * significant time by avoiding no-op traversals of large filesystem trees.
    -+ */
    -+static int restorecon_app_data_lazy(const std::string& path, const char* seinfo, uid_t uid) {
    -+    int res = 0;
    -+    char* before = nullptr;
    -+    char* after = nullptr;
    -+
    -+    // Note that SELINUX_ANDROID_RESTORECON_DATADATA flag is set by
    -+    // libselinux. Not needed here.
    -+
    -+    if (lgetfilecon(path.c_str(), &before) < 0) {
    -+        PLOG(ERROR) << "Failed before getfilecon for " << path;
    -+        goto fail;
    -+    }
    -+    if (selinux_android_restorecon_pkgdir(path.c_str(), seinfo, uid, 0) < 0) {
    -+        PLOG(ERROR) << "Failed top-level restorecon for " << path;
    -+        goto fail;
    -+    }
    -+    if (lgetfilecon(path.c_str(), &after) < 0) {
    -+        PLOG(ERROR) << "Failed after getfilecon for " << path;
    -+        goto fail;
    -+    }
    -+
    -+    // If the initial top-level restorecon above changed the label, then go
    -+    // back and restorecon everything recursively
    -+    if (strcmp(before, after)) {
    -+        LOG(DEBUG) << "Detected label change from " << before << " to " << after << " at " << path
    -+                << "; running recursive restorecon";
    -+        if (selinux_android_restorecon_pkgdir(path.c_str(), seinfo, uid,
    -+                SELINUX_ANDROID_RESTORECON_RECURSE) < 0) {
    -+            PLOG(ERROR) << "Failed recursive restorecon for " << path;
    -+            goto fail;
    -+        }
    -+    }
    -+
    -+    goto done;
    -+fail:
    -+    res = -1;
    -+done:
    -+    free(before);
    -+    free(after);
    -+    return res;
    -+}
    -+
    -+static int restorecon_app_data_lazy(const std::string& parent, const char* name, const char* seinfo,
    -+        uid_t uid) {
    -+    return restorecon_app_data_lazy(StringPrintf("%s/%s", parent.c_str(), name), seinfo, uid);
    -+}
    -+
    -+static int prepare_app_dir(const std::string& path, mode_t target_mode, uid_t uid) {
    -     if (fs_prepare_dir_strict(path.c_str(), target_mode, uid, uid) != 0) {
    -         PLOG(ERROR) << "Failed to prepare " << path;
    -         return -1;
    -     }
    --    if (selinux_android_setfilecon(path.c_str(), pkgname, seinfo, uid) < 0) {
    --        PLOG(ERROR) << "Failed to setfilecon " << path;
    --        return -1;
    --    }
    -     return 0;
    - }
    - 
    - static int prepare_app_dir(const std::string& parent, const char* name, mode_t target_mode,
    --        uid_t uid, const char* pkgname, const char* seinfo) {
    --    return prepare_app_dir(StringPrintf("%s/%s", parent.c_str(), name), target_mode, uid, pkgname,
    --            seinfo);
    -+        uid_t uid) {
    -+    return prepare_app_dir(StringPrintf("%s/%s", parent.c_str(), name), target_mode, uid);
    - }
    - 
    - int create_app_data(const char *uuid, const char *pkgname, userid_t userid, int flags,
    -@@ -124,9 +170,16 @@ int create_app_data(const char *uuid, const char *pkgname, userid_t userid, int
    -     mode_t target_mode = target_sdk_version >= MIN_RESTRICTED_HOME_SDK_VERSION ? 0700 : 0751;
    -     if (flags & FLAG_STORAGE_CE) {
    -         auto path = create_data_user_ce_package_path(uuid, userid, pkgname);
    --        if (prepare_app_dir(path, target_mode, uid, pkgname, seinfo) ||
    --                prepare_app_dir(path, "cache", 0771, uid, pkgname, seinfo) ||
    --                prepare_app_dir(path, "code_cache", 0771, uid, pkgname, seinfo)) {
    -+        if (prepare_app_dir(path, target_mode, uid) ||
    -+                prepare_app_dir(path, "cache", 0771, uid) ||
    -+                prepare_app_dir(path, "code_cache", 0771, uid)) {
    -+            return -1;
    -+        }
    -+
    -+        // Consider restorecon over contents if label changed
    -+        if (restorecon_app_data_lazy(path, seinfo, uid) ||
    -+                restorecon_app_data_lazy(path, "cache", seinfo, uid) ||
    -+                restorecon_app_data_lazy(path, "code_cache", seinfo, uid)) {
    -             return -1;
    -         }
    - 
    -@@ -139,11 +192,16 @@ int create_app_data(const char *uuid, const char *pkgname, userid_t userid, int
    -     }
    -     if (flags & FLAG_STORAGE_DE) {
    -         auto path = create_data_user_de_package_path(uuid, userid, pkgname);
    --        if (prepare_app_dir(path, target_mode, uid, pkgname, seinfo)) {
    -+        if (prepare_app_dir(path, target_mode, uid)) {
    -             // TODO: include result once 25796509 is fixed
    -             return 0;
    -         }
    - 
    -+        // Consider restorecon over contents if label changed
    -+        if (restorecon_app_data_lazy(path, seinfo, uid)) {
    -+            return -1;
    -+        }
    -+
    -         if (property_get_bool("dalvik.vm.usejitprofiles")) {
    -             const std::string profile_path = create_data_user_profile_package_path(userid, pkgname);
    -             // read-write-execute only for the app user.
    -@@ -2186,6 +2244,9 @@ int move_ab(const char* apk_path, const char* instruction_set, const char* oat_d
    -         bool art_success = true;
    -         if (!a_image_path.empty()) {
    -             art_success = move_ab_path(b_image_path, a_image_path);
    -+            if (!art_success) {
    -+                unlink(a_image_path.c_str());
    -+            }
    -         }
    - 
    -         success = art_success || kIgnoreAppImageFailure;
    -@@ -2199,5 +2260,35 @@ int move_ab(const char* apk_path, const char* instruction_set, const char* oat_d
    -     return success ? 0 : -1;
    - }
    - 
    -+bool delete_odex(const char *apk_path, const char *instruction_set, const char *oat_dir) {
    -+    // Delete the oat/odex file.
    -+    char out_path[PKG_PATH_MAX];
    -+    if (!create_oat_out_path(apk_path, instruction_set, oat_dir, out_path)) {
    -+        return false;
    -+    }
    -+
    -+    // In case of a permission failure report the issue. Otherwise just print a warning.
    -+    auto unlink_and_check = [](const char* path) -> bool {
    -+        int result = unlink(path);
    -+        if (result != 0) {
    -+            if (errno == EACCES || errno == EPERM) {
    -+                PLOG(ERROR) << "Could not unlink " << path;
    -+                return false;
    -+            }
    -+            PLOG(WARNING) << "Could not unlink " << path;
    -+        }
    -+        return true;
    -+    };
    -+
    -+    // Delete the oat/odex file.
    -+    bool return_value_oat = unlink_and_check(out_path);
    -+
    -+    // Derive and delete the app image.
    -+    bool return_value_art = unlink_and_check(create_image_filename(out_path).c_str());
    -+
    -+    // Report success.
    -+    return return_value_oat && return_value_art;
    -+}
    -+
    - }  // namespace installd
    - }  // namespace android
    -diff --git a/cmds/installd/commands.h b/cmds/installd/commands.h
    -index e990f1b..ba27517 100644
    ---- a/cmds/installd/commands.h
    -+++ b/cmds/installd/commands.h
    -@@ -85,6 +85,9 @@ int link_file(const char *relative_path, const char *from_base, const char *to_b
    - // Move a B version over to the A location. Only works for oat_dir != nullptr.
    - int move_ab(const char *apk_path, const char *instruction_set, const char* oat_dir);
    - 
    -+// Delete odex files generated by dexopt.
    -+bool delete_odex(const char *apk_path, const char *instruction_set, const char *oat_dir);
    -+
    - }  // namespace installd
    - }  // namespace android
    - 
    -diff --git a/cmds/installd/installd.cpp b/cmds/installd/installd.cpp
    -index facbc72..8f883db 100644
    ---- a/cmds/installd/installd.cpp
    -+++ b/cmds/installd/installd.cpp
    -@@ -418,6 +418,11 @@ static int do_move_ab(char **arg, char reply[REPLY_MAX] ATTRIBUTE_UNUSED) {
    -     return move_ab(arg[0], arg[1], arg[2]);
    - }
    - 
    -+static int do_delete_odex(char **arg, char reply[REPLY_MAX] ATTRIBUTE_UNUSED) {
    -+    // apk_path, instruction_set, oat_dir
    -+    return delete_odex(arg[0], arg[1], arg[2]) ? 0 : -1;
    -+}
    -+
    - struct cmdinfo {
    -     const char *name;
    -     unsigned numargs;
    -@@ -453,6 +458,7 @@ struct cmdinfo cmds[] = {
    -     { "move_ab",              3, do_move_ab },
    -     { "merge_profiles",       2, do_merge_profiles },
    -     { "dump_profiles",        3, do_dump_profiles },
    -+    { "delete_odex",          3, do_delete_odex },
    - };
    - 
    - static int readx(int s, void *_buf, int count)
    -diff --git a/data/etc/handheld_core_hardware.xml b/data/etc/handheld_core_hardware.xml
    -index 9cb4d6d..f9464e8 100644
    ---- a/data/etc/handheld_core_hardware.xml
    -+++ b/data/etc/handheld_core_hardware.xml
    -@@ -50,8 +50,8 @@
    -     <!-- Feature to specify if the device support managed users. -->
    -     <feature name="android.software.managed_users" />
    - 
    --    <!-- Feature to specify if the device supports a VR mode. -->
    --    <feature name="android.software.vr.mode" />
    -+    <!-- Feature to specify if the device supports a VR mode.
    -+         feature name="android.software.vr.mode" -->
    -     <!-- Devices with all optimizations required to be a "VR Ready" device that
    -          pass all CTS tests for this feature must include feature
    -          android.hardware.vr.high_performance -->
    -diff --git a/include/gui/BufferQueueCore.h b/include/gui/BufferQueueCore.h
    -index 82bc121..cc5c536 100644
    ---- a/include/gui/BufferQueueCore.h
    -+++ b/include/gui/BufferQueueCore.h
    -@@ -182,6 +182,8 @@ private:
    -     // to this BufferQueue. It defaults to NO_CONNECTED_API, and gets updated
    -     // by the connect and disconnect methods.
    -     int mConnectedApi;
    -+    // PID of the process which last successfully called connect(...)
    -+    pid_t mConnectedPid;
    - 
    -     // mConnectedProducerToken is used to set a binder death notification on
    -     // the producer.
    -diff --git a/include/gui/BufferQueueProducer.h b/include/gui/BufferQueueProducer.h
    -index 838632c..8f613ee 100644
    ---- a/include/gui/BufferQueueProducer.h
    -+++ b/include/gui/BufferQueueProducer.h
    -@@ -135,15 +135,8 @@ public:
    -     virtual status_t connect(const sp<IProducerListener>& listener,
    -             int api, bool producerControlledByApp, QueueBufferOutput* output);
    - 
    --    // disconnect attempts to disconnect a producer API from the BufferQueue.
    --    // Calling this method will cause any subsequent calls to other
    --    // IGraphicBufferProducer methods to fail except for getAllocator and connect.
    --    // Successfully calling connect after this will allow the other methods to
    --    // succeed again.
    --    //
    --    // This method will fail if the the BufferQueue is not currently
    --    // connected to the specified producer API.
    --    virtual status_t disconnect(int api);
    -+    // See IGraphicBufferProducer::disconnect
    -+    virtual status_t disconnect(int api, DisconnectMode mode = DisconnectMode::Api);
    - 
    -     // Attaches a sideband buffer stream to the IGraphicBufferProducer.
    -     //
    -diff --git a/include/gui/IGraphicBufferProducer.h b/include/gui/IGraphicBufferProducer.h
    -index c62bc58..bf427fe 100644
    ---- a/include/gui/IGraphicBufferProducer.h
    -+++ b/include/gui/IGraphicBufferProducer.h
    -@@ -458,17 +458,24 @@ public:
    -     virtual status_t connect(const sp<IProducerListener>& listener,
    -             int api, bool producerControlledByApp, QueueBufferOutput* output) = 0;
    - 
    -+    enum class DisconnectMode {
    -+        // Disconnect only the specified API.
    -+        Api,
    -+        // Disconnect any API originally connected from the process calling disconnect.
    -+        AllLocal
    -+    };
    -+
    -     // disconnect attempts to disconnect a client API from the
    -     // IGraphicBufferProducer.  Calling this method will cause any subsequent
    -     // calls to other IGraphicBufferProducer methods to fail except for
    -     // getAllocator and connect.  Successfully calling connect after this will
    -     // allow the other methods to succeed again.
    -     //
    --    // This method will fail if the the IGraphicBufferProducer is not currently
    --    // connected to the specified client API.
    --    //
    -     // The api should be one of the NATIVE_WINDOW_API_* values in <window.h>
    -     //
    -+    // Alternatively if mode is AllLocal, then the API value is ignored, and any API
    -+    // connected from the same PID calling disconnect will be disconnected.
    -+    //
    -     // Disconnecting from an abandoned IGraphicBufferProducer is legal and
    -     // is considered a no-op.
    -     //
    -@@ -477,7 +484,7 @@ public:
    -     //             * the api specified does not match the one that was connected
    -     //             * api was out of range (see above).
    -     // * DEAD_OBJECT - the token is hosted by an already-dead process
    --    virtual status_t disconnect(int api) = 0;
    -+    virtual status_t disconnect(int api, DisconnectMode mode = DisconnectMode::Api) = 0;
    - 
    -     // Attaches a sideband buffer stream to the IGraphicBufferProducer.
    -     //
     diff --git a/include/gui/ISurfaceComposer.h b/include/gui/ISurfaceComposer.h
     index 74a4123..8dc6f6a 100644
     --- a/include/gui/ISurfaceComposer.h
    @@ -509,44 +78,6 @@ index 74a4123..8dc6f6a 100644
      
          /* Clears the frame statistics for animations.
           *
    -diff --git a/include/gui/Surface.h b/include/gui/Surface.h
    -index 8177ec6..f4a22cb 100644
    ---- a/include/gui/Surface.h
    -+++ b/include/gui/Surface.h
    -@@ -203,7 +203,6 @@ protected:
    -     virtual int lockBuffer_DEPRECATED(ANativeWindowBuffer* buffer);
    - 
    -     virtual int connect(int api);
    --    virtual int disconnect(int api);
    -     virtual int setBufferCount(int bufferCount);
    -     virtual int setBuffersDimensions(uint32_t width, uint32_t height);
    -     virtual int setBuffersUserDimensions(uint32_t width, uint32_t height);
    -@@ -217,6 +216,10 @@ protected:
    -     virtual void setSurfaceDamage(android_native_rect_t* rects, size_t numRects);
    - 
    - public:
    -+    virtual int disconnect(int api,
    -+            IGraphicBufferProducer::DisconnectMode mode =
    -+                    IGraphicBufferProducer::DisconnectMode::Api);
    -+
    -     virtual int setMaxDequeuedBufferCount(int maxDequeuedBuffers);
    -     virtual int setAsyncMode(bool async);
    -     virtual int setSharedBufferMode(bool sharedBufferMode);
    -diff --git a/include/gui/SurfaceComposerClient.h b/include/gui/SurfaceComposerClient.h
    -index b8ee331..c4f88b6 100644
    ---- a/include/gui/SurfaceComposerClient.h
    -+++ b/include/gui/SurfaceComposerClient.h
    -@@ -166,8 +166,8 @@ public:
    -     static status_t getHdrCapabilities(const sp<IBinder>& display,
    -             HdrCapabilities* outCapabilities);
    - 
    --    static void setDisplaySurface(const sp<IBinder>& token,
    --            const sp<IGraphicBufferProducer>& bufferProducer);
    -+    static status_t setDisplaySurface(const sp<IBinder>& token,
    -+            sp<IGraphicBufferProducer> bufferProducer);
    -     static void setDisplayLayerStack(const sp<IBinder>& token,
    -             uint32_t layerStack);
    -     static void setDisplaySize(const sp<IBinder>& token, uint32_t width, uint32_t height);
     diff --git a/libs/binder/IPCThreadState.cpp b/libs/binder/IPCThreadState.cpp
     index d90798f..9b5f0d7 100644
     --- a/libs/binder/IPCThreadState.cpp
    @@ -591,86 +122,6 @@ index 46feb1c..1b4a9c5 100644
      
      LOCAL_MODULE := libgui
      
    -diff --git a/libs/gui/BufferQueueProducer.cpp b/libs/gui/BufferQueueProducer.cpp
    -index 47ab6f2..48b1db8 100644
    ---- a/libs/gui/BufferQueueProducer.cpp
    -+++ b/libs/gui/BufferQueueProducer.cpp
    -@@ -28,6 +28,7 @@
    - 
    - #define EGL_EGLEXT_PROTOTYPES
    - 
    -+#include <binder/IPCThreadState.h>
    - #include <gui/BufferItem.h>
    - #include <gui/BufferQueueCore.h>
    - #include <gui/BufferQueueProducer.h>
    -@@ -1130,7 +1131,7 @@ status_t BufferQueueProducer::connect(const sp<IProducerListener>& listener,
    -             status = BAD_VALUE;
    -             break;
    -     }
    --
    -+    mCore->mConnectedPid = IPCThreadState::self()->getCallingPid();
    -     mCore->mBufferHasBeenQueued = false;
    -     mCore->mDequeueBufferCannotBlock = false;
    -     if (mDequeueTimeout < 0) {
    -@@ -1143,7 +1144,7 @@ status_t BufferQueueProducer::connect(const sp<IProducerListener>& listener,
    -     return status;
    - }
    - 
    --status_t BufferQueueProducer::disconnect(int api) {
    -+status_t BufferQueueProducer::disconnect(int api, DisconnectMode mode) {
    -     ATRACE_CALL();
    -     BQ_LOGV("disconnect: api %d", api);
    - 
    -@@ -1151,6 +1152,14 @@ status_t BufferQueueProducer::disconnect(int api) {
    -     sp<IConsumerListener> listener;
    -     { // Autolock scope
    -         Mutex::Autolock lock(mCore->mMutex);
    -+
    -+        if (mode == DisconnectMode::AllLocal) {
    -+            if (IPCThreadState::self()->getCallingPid() != mCore->mConnectedPid) {
    -+                return NO_ERROR;
    -+            }
    -+            api = BufferQueueCore::CURRENTLY_CONNECTED_API;
    -+        }
    -+
    -         mCore->waitWhileAllocatingLocked();
    - 
    -         if (mCore->mIsAbandoned) {
    -@@ -1189,6 +1198,7 @@ status_t BufferQueueProducer::disconnect(int api) {
    -                             BufferQueueCore::INVALID_BUFFER_SLOT;
    -                     mCore->mConnectedProducerListener = NULL;
    -                     mCore->mConnectedApi = BufferQueueCore::NO_CONNECTED_API;
    -+                    mCore->mConnectedPid = -1;
    -                     mCore->mSidebandStream.clear();
    -                     mCore->mDequeueCondition.broadcast();
    -                     listener = mCore->mConsumerListener;
    -diff --git a/libs/gui/IGraphicBufferProducer.cpp b/libs/gui/IGraphicBufferProducer.cpp
    -index fbd704d..f4ba3bf 100644
    ---- a/libs/gui/IGraphicBufferProducer.cpp
    -+++ b/libs/gui/IGraphicBufferProducer.cpp
    -@@ -270,10 +270,11 @@ public:
    -         return result;
    -     }
    - 
    --    virtual status_t disconnect(int api) {
    -+    virtual status_t disconnect(int api, DisconnectMode mode) {
    -         Parcel data, reply;
    -         data.writeInterfaceToken(IGraphicBufferProducer::getInterfaceDescriptor());
    -         data.writeInt32(api);
    -+        data.writeInt32(static_cast<int32_t>(mode));
    -         status_t result =remote()->transact(DISCONNECT, data, &reply);
    -         if (result != NO_ERROR) {
    -             return result;
    -@@ -621,7 +622,8 @@ status_t BnGraphicBufferProducer::onTransact(
    -         case DISCONNECT: {
    -             CHECK_INTERFACE(IGraphicBufferProducer, data, reply);
    -             int api = data.readInt32();
    --            status_t res = disconnect(api);
    -+            DisconnectMode mode = static_cast<DisconnectMode>(data.readInt32());
    -+            status_t res = disconnect(api, mode);
    -             reply->writeInt32(res);
    -             return NO_ERROR;
    -         }
     diff --git a/libs/gui/ISurfaceComposer.cpp b/libs/gui/ISurfaceComposer.cpp
     index f0b0ada..3577a33 100644
     --- a/libs/gui/ISurfaceComposer.cpp
    @@ -708,152 +159,6 @@ index f0b0ada..3577a33 100644
                  reply->writeInt32(res);
                  return NO_ERROR;
              }
    -diff --git a/libs/gui/Surface.cpp b/libs/gui/Surface.cpp
    -index dbf8114..0838290 100644
    ---- a/libs/gui/Surface.cpp
    -+++ b/libs/gui/Surface.cpp
    -@@ -844,14 +844,14 @@ int Surface::connect(int api, const sp<IProducerListener>& listener) {
    - }
    - 
    - 
    --int Surface::disconnect(int api) {
    -+int Surface::disconnect(int api, IGraphicBufferProducer::DisconnectMode mode) {
    -     ATRACE_CALL();
    -     ALOGV("Surface::disconnect");
    -     Mutex::Autolock lock(mMutex);
    -     mSharedBufferSlot = BufferItem::INVALID_BUFFER_SLOT;
    -     mSharedBufferHasBeenQueued = false;
    -     freeAllBuffers();
    --    int err = mGraphicBufferProducer->disconnect(api);
    -+    int err = mGraphicBufferProducer->disconnect(api, mode);
    -     if (!err) {
    -         mReqFormat = 0;
    -         mReqWidth = 0;
    -@@ -1364,12 +1364,18 @@ status_t Surface::writeToParcel(Parcel* parcel, bool nameAlreadyWritten) const {
    - 
    -     status_t res = OK;
    - 
    --    if (!nameAlreadyWritten) res = parcel->writeString16(name);
    -+    if (!nameAlreadyWritten) {
    -+        res = parcel->writeString16(name);
    -+        if (res != OK) return res;
    - 
    --    if (res == OK) {
    --        res = parcel->writeStrongBinder(
    --                IGraphicBufferProducer::asBinder(graphicBufferProducer));
    -+        /* isSingleBuffered defaults to no */
    -+        res = parcel->writeInt32(0);
    -+        if (res != OK) return res;
    -     }
    -+
    -+    res = parcel->writeStrongBinder(
    -+            IGraphicBufferProducer::asBinder(graphicBufferProducer));
    -+
    -     return res;
    - }
    - 
    -@@ -1380,13 +1386,20 @@ status_t Surface::readFromParcel(const Parcel* parcel) {
    - status_t Surface::readFromParcel(const Parcel* parcel, bool nameAlreadyRead) {
    -     if (parcel == nullptr) return BAD_VALUE;
    - 
    -+    status_t res = OK;
    -     if (!nameAlreadyRead) {
    -         name = readMaybeEmptyString16(parcel);
    -+        // Discard this for now
    -+        int isSingleBuffered;
    -+        res = parcel->readInt32(&isSingleBuffered);
    -+        if (res != OK) {
    -+            return res;
    -+        }
    -     }
    - 
    -     sp<IBinder> binder;
    - 
    --    status_t res = parcel->readStrongBinder(&binder);
    -+    res = parcel->readStrongBinder(&binder);
    -     if (res != OK) return res;
    - 
    -     graphicBufferProducer = interface_cast<IGraphicBufferProducer>(binder);
    -diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp
    -index 3df5f74..b78de2e 100644
    ---- a/libs/gui/SurfaceComposerClient.cpp
    -+++ b/libs/gui/SurfaceComposerClient.cpp
    -@@ -170,8 +170,8 @@ public:
    -     status_t setGeometryAppliesWithResize(const sp<SurfaceComposerClient>& client,
    -             const sp<IBinder>& id);
    - 
    --    void setDisplaySurface(const sp<IBinder>& token,
    --            const sp<IGraphicBufferProducer>& bufferProducer);
    -+    status_t setDisplaySurface(const sp<IBinder>& token,
    -+            sp<IGraphicBufferProducer> bufferProducer);
    -     void setDisplayLayerStack(const sp<IBinder>& token, uint32_t layerStack);
    -     void setDisplayProjection(const sp<IBinder>& token,
    -             uint32_t orientation,
    -@@ -473,12 +473,24 @@ DisplayState& Composer::getDisplayStateLocked(const sp<IBinder>& token) {
    -     return mDisplayStates.editItemAt(static_cast<size_t>(index));
    - }
    - 
    --void Composer::setDisplaySurface(const sp<IBinder>& token,
    --        const sp<IGraphicBufferProducer>& bufferProducer) {
    -+status_t Composer::setDisplaySurface(const sp<IBinder>& token,
    -+        sp<IGraphicBufferProducer> bufferProducer) {
    -+    if (bufferProducer.get() != nullptr) {
    -+        // Make sure that composition can never be stalled by a virtual display
    -+        // consumer that isn't processing buffers fast enough.
    -+        status_t err = bufferProducer->setAsyncMode(true);
    -+        if (err != NO_ERROR) {
    -+            ALOGE("Composer::setDisplaySurface Failed to enable async mode on the "
    -+                    "BufferQueue. This BufferQueue cannot be used for virtual "
    -+                    "display. (%d)", err);
    -+            return err;
    -+        }
    -+    }
    -     Mutex::Autolock _l(mLock);
    -     DisplayState& s(getDisplayStateLocked(token));
    -     s.surface = bufferProducer;
    -     s.what |= DisplayState::eSurfaceChanged;
    -+    return NO_ERROR;
    - }
    - 
    - void Composer::setDisplayLayerStack(const sp<IBinder>& token,
    -@@ -716,9 +728,9 @@ status_t SurfaceComposerClient::setGeometryAppliesWithResize(
    - 
    - // ----------------------------------------------------------------------------
    - 
    --void SurfaceComposerClient::setDisplaySurface(const sp<IBinder>& token,
    --        const sp<IGraphicBufferProducer>& bufferProducer) {
    --    Composer::getInstance().setDisplaySurface(token, bufferProducer);
    -+status_t SurfaceComposerClient::setDisplaySurface(const sp<IBinder>& token,
    -+        sp<IGraphicBufferProducer> bufferProducer) {
    -+    return Composer::getInstance().setDisplaySurface(token, bufferProducer);
    - }
    - 
    - void SurfaceComposerClient::setDisplayLayerStack(const sp<IBinder>& token,
    -diff --git a/libs/gui/tests/SurfaceTextureGL_test.cpp b/libs/gui/tests/SurfaceTextureGL_test.cpp
    -index dddcf92..5311c59 100644
    ---- a/libs/gui/tests/SurfaceTextureGL_test.cpp
    -+++ b/libs/gui/tests/SurfaceTextureGL_test.cpp
    -@@ -115,13 +115,13 @@ TEST_F(SurfaceTextureGLTest, TexturingFromCpuFilledYV12BufferPow2) {
    -     EXPECT_TRUE(checkPixel(63, 63,   0, 133,   0, 255));
    -     EXPECT_TRUE(checkPixel( 0, 63, 255, 127, 255, 255));
    - 
    --    EXPECT_TRUE(checkPixel(22, 19, 100, 255,  74, 255));
    --    EXPECT_TRUE(checkPixel(45, 11, 100, 255,  74, 255));
    --    EXPECT_TRUE(checkPixel(52, 12, 155,   0, 181, 255));
    --    EXPECT_TRUE(checkPixel( 7, 32, 150, 237, 170, 255));
    --    EXPECT_TRUE(checkPixel(31, 54,   0,  71, 117, 255));
    --    EXPECT_TRUE(checkPixel(29, 28,   0, 133,   0, 255));
    --    EXPECT_TRUE(checkPixel(36, 41, 100, 232, 255, 255));
    -+    EXPECT_TRUE(checkPixel(22, 19, 100, 255,  74, 255, 3));
    -+    EXPECT_TRUE(checkPixel(45, 11, 100, 255,  74, 255, 3));
    -+    EXPECT_TRUE(checkPixel(52, 12, 155,   0, 181, 255, 3));
    -+    EXPECT_TRUE(checkPixel( 7, 32, 150, 237, 170, 255, 3));
    -+    EXPECT_TRUE(checkPixel(31, 54,   0,  71, 117, 255, 3));
    -+    EXPECT_TRUE(checkPixel(29, 28,   0, 133,   0, 255, 3));
    -+    EXPECT_TRUE(checkPixel(36, 41, 100, 232, 255, 255, 3));
    - }
    - 
    - TEST_F(SurfaceTextureGLTest, TexturingFromCpuFilledYV12BufferWithCrop) {
     diff --git a/libs/ui/Region.cpp b/libs/ui/Region.cpp
     index ee152bf..9c82295 100644
     --- a/libs/ui/Region.cpp
    @@ -871,18 +176,9 @@ index ee152bf..9c82295 100644
          result.mStorage.clear();
          for (size_t r = 0; r < numRects; ++r) {
     diff --git a/opengl/libs/Android.mk b/opengl/libs/Android.mk
    -index eb86860..038fe4d 100644
    +index 24e4c19..038fe4d 100644
     --- a/opengl/libs/Android.mk
     +++ b/opengl/libs/Android.mk
    -@@ -31,7 +31,7 @@ LOCAL_SRC_FILES:= 	       \
    - 	EGL/Loader.cpp 	       \
    - #
    - 
    --LOCAL_SHARED_LIBRARIES += libcutils libutils liblog libui
    -+LOCAL_SHARED_LIBRARIES += libbinder libcutils libutils liblog libui
    - LOCAL_MODULE:= libEGL
    - LOCAL_LDFLAGS += -Wl,--exclude-libs=ALL
    - LOCAL_SHARED_LIBRARIES += libdl
     @@ -77,7 +77,6 @@ LOCAL_SRC_FILES:= 		\
      	GLES_CM/gl.cpp.arm 	\
      #
    @@ -899,129 +195,6 @@ index eb86860..038fe4d 100644
      LOCAL_ARM_MODE := arm
      LOCAL_SHARED_LIBRARIES += libcutils libutils liblog libEGL
      LOCAL_MODULE:= libGLESv2
    -diff --git a/opengl/libs/EGL/eglApi.cpp b/opengl/libs/EGL/eglApi.cpp
    -index 03abc49..f41e6e2 100644
    ---- a/opengl/libs/EGL/eglApi.cpp
    -+++ b/opengl/libs/EGL/eglApi.cpp
    -@@ -33,6 +33,8 @@
    - #include <cutils/properties.h>
    - #include <cutils/memory.h>
    - 
    -+#include <gui/ISurfaceComposer.h>
    -+
    - #include <ui/GraphicBuffer.h>
    - 
    - #include <utils/KeyedVector.h>
    -@@ -40,6 +42,10 @@
    - #include <utils/String8.h>
    - #include <utils/Trace.h>
    - 
    -+#include "binder/Binder.h"
    -+#include "binder/Parcel.h"
    -+#include "binder/IServiceManager.h"
    -+
    - #include "../egl_impl.h"
    - #include "../hooks.h"
    - 
    -@@ -1872,20 +1878,77 @@ EGLClientBuffer eglCreateNativeClientBufferANDROID(const EGLint *attrib_list)
    -         return setError(EGL_BAD_PARAMETER, (EGLClientBuffer)0);
    -     }
    - 
    --    GraphicBuffer* gBuffer = new GraphicBuffer(width, height, format, usage,
    -+#define CHECK_ERROR_CONDITION(message) \
    -+    if (err != NO_ERROR) { \
    -+        ALOGE(message); \
    -+        goto error_condition; \
    -+    }
    -+
    -+    // The holder is used to destroy the buffer if an error occurs.
    -+    GraphicBuffer* gBuffer = new GraphicBuffer();
    -+    sp<IServiceManager> sm = defaultServiceManager();
    -+    sp<IBinder> surfaceFlinger = sm->getService(String16("SurfaceFlinger"));
    -+    sp<IBinder> allocator;
    -+    Parcel sc_data, sc_reply, data, reply;
    -+    status_t err = NO_ERROR;
    -+    if (sm == NULL) {
    -+        ALOGE("Unable to connect to ServiceManager");
    -+        goto error_condition;
    -+    }
    -+
    -+    // Obtain an allocator.
    -+    if (surfaceFlinger == NULL) {
    -+        ALOGE("Unable to connect to SurfaceFlinger");
    -+        goto error_condition;
    -+    }
    -+    sc_data.writeInterfaceToken(String16("android.ui.ISurfaceComposer"));
    -+    err = surfaceFlinger->transact(
    -+            BnSurfaceComposer::CREATE_GRAPHIC_BUFFER_ALLOC, sc_data, &sc_reply);
    -+    CHECK_ERROR_CONDITION("Unable to obtain allocator from SurfaceFlinger");
    -+    allocator = sc_reply.readStrongBinder();
    -+
    -+    if (allocator == NULL) {
    -+        ALOGE("Unable to obtain an ISurfaceComposer");
    -+        goto error_condition;
    -+    }
    -+    data.writeInterfaceToken(String16("android.ui.IGraphicBufferAlloc"));
    -+    err = data.writeUint32(width);
    -+    CHECK_ERROR_CONDITION("Unable to write width");
    -+    err = data.writeUint32(height);
    -+    CHECK_ERROR_CONDITION("Unable to write height");
    -+    err = data.writeInt32(static_cast<int32_t>(format));
    -+    CHECK_ERROR_CONDITION("Unable to write format");
    -+    err = data.writeUint32(usage);
    -+    CHECK_ERROR_CONDITION("Unable to write usage");
    -+    err = data.writeUtf8AsUtf16(
    -             std::string("[eglCreateNativeClientBufferANDROID pid ") +
    -             std::to_string(getpid()) + ']');
    --    const status_t err = gBuffer->initCheck();
    -+    CHECK_ERROR_CONDITION("Unable to write requestor name");
    -+    err = allocator->transact(IBinder::FIRST_CALL_TRANSACTION, data,
    -+            &reply);
    -+    CHECK_ERROR_CONDITION(
    -+            "Unable to request buffer allocation from surface composer");
    -+    err = reply.readInt32();
    -+    CHECK_ERROR_CONDITION("Unable to obtain buffer from surface composer");
    -+    err = reply.read(*gBuffer);
    -+    CHECK_ERROR_CONDITION("Unable to read buffer from surface composer");
    -+
    -+    err = gBuffer->initCheck();
    -     if (err != NO_ERROR) {
    -         ALOGE("Unable to create native buffer { w=%d, h=%d, f=%d, u=%#x }: %#x",
    -                 width, height, format, usage, err);
    --        // Destroy the buffer.
    --        sp<GraphicBuffer> holder(gBuffer);
    --        return setError(EGL_BAD_ALLOC, (EGLClientBuffer)0);
    -+        goto error_condition;
    -     }
    -     ALOGD("Created new native buffer %p { w=%d, h=%d, f=%d, u=%#x }",
    -             gBuffer, width, height, format, usage);
    -     return static_cast<EGLClientBuffer>(gBuffer->getNativeBuffer());
    -+
    -+#undef CHECK_ERROR_CONDITION
    -+
    -+error_condition:
    -+    // Delete the buffer.
    -+    sp<GraphicBuffer> holder(gBuffer);
    -+    return setError(EGL_BAD_ALLOC, (EGLClientBuffer)0);
    - }
    - 
    - // ----------------------------------------------------------------------------
    -diff --git a/opengl/libs/EGL/egl_display.cpp b/opengl/libs/EGL/egl_display.cpp
    -index e335a6c..1e39aae 100644
    ---- a/opengl/libs/EGL/egl_display.cpp
    -+++ b/opengl/libs/EGL/egl_display.cpp
    -@@ -66,7 +66,10 @@ egl_display_t::~egl_display_t() {
    - 
    - egl_display_t* egl_display_t::get(EGLDisplay dpy) {
    -     uintptr_t index = uintptr_t(dpy)-1U;
    --    return (index >= NUM_DISPLAYS) ? NULL : &sDisplay[index];
    -+    if (index >= NUM_DISPLAYS || !sDisplay[index].isValid()) {
    -+        return nullptr;
    -+    }
    -+    return &sDisplay[index];
    - }
    - 
    - void egl_display_t::addObject(egl_object_t* object) {
     diff --git a/opengl/libs/GLES2/gl2.cpp b/opengl/libs/GLES2/gl2.cpp
     index 6034a8e..f1feeda 100644
     --- a/opengl/libs/GLES2/gl2.cpp
    @@ -1193,172 +366,8 @@ index b9be675..4dec34b 100644
              outCount += 1;
          }
      
    -diff --git a/services/sensorservice/SensorEventConnection.cpp b/services/sensorservice/SensorEventConnection.cpp
    -index c1e1bad..f2f1444 100644
    ---- a/services/sensorservice/SensorEventConnection.cpp
    -+++ b/services/sensorservice/SensorEventConnection.cpp
    -@@ -206,7 +206,7 @@ void SensorService::SensorEventConnection::incrementPendingFlushCount(int32_t ha
    - status_t SensorService::SensorEventConnection::sendEvents(
    -         sensors_event_t const* buffer, size_t numEvents,
    -         sensors_event_t* scratch,
    --        SensorEventConnection const * const * mapFlushEventsToConnections) {
    -+        wp<const SensorEventConnection> const * mapFlushEventsToConnections) {
    -     // filter out events not for this connection
    -     int count = 0;
    -     Mutex::Autolock _l(mConnectionLock);
    -@@ -234,7 +234,7 @@ status_t SensorService::SensorEventConnection::sendEvents(
    -             FlushInfo& flushInfo = mSensorInfo.editValueAt(index);
    -             // Check if there is a pending flush_complete event for this sensor on this connection.
    -             if (buffer[i].type == SENSOR_TYPE_META_DATA && flushInfo.mFirstFlushPending == true &&
    --                    this == mapFlushEventsToConnections[i]) {
    -+                    mapFlushEventsToConnections[i] == this) {
    -                 flushInfo.mFirstFlushPending = false;
    -                 ALOGD_IF(DEBUG_CONNECTIONS, "First flush event for sensor==%d ",
    -                         buffer[i].meta_data.sensor);
    -@@ -255,7 +255,7 @@ status_t SensorService::SensorEventConnection::sendEvents(
    -                 // from the same sensor_handle AND the current connection is mapped to the
    -                 // corresponding flush_complete_event.
    -                 if (buffer[i].type == SENSOR_TYPE_META_DATA) {
    --                    if (this == mapFlushEventsToConnections[i]) {
    -+                    if (mapFlushEventsToConnections[i] == this) {
    -                         scratch[count++] = buffer[i];
    -                     }
    -                     ++i;
    -diff --git a/services/sensorservice/SensorEventConnection.h b/services/sensorservice/SensorEventConnection.h
    -index b796cc0..883c16e 100644
    ---- a/services/sensorservice/SensorEventConnection.h
    -+++ b/services/sensorservice/SensorEventConnection.h
    -@@ -52,7 +52,7 @@ public:
    -                           bool isDataInjectionMode, const String16& opPackageName);
    - 
    -     status_t sendEvents(sensors_event_t const* buffer, size_t count, sensors_event_t* scratch,
    --                        SensorEventConnection const * const * mapFlushEventsToConnections = NULL);
    -+                        wp<const SensorEventConnection> const * mapFlushEventsToConnections = NULL);
    -     bool hasSensor(int32_t handle) const;
    -     bool hasAnySensor() const;
    -     bool hasOneShotSensors() const;
    -diff --git a/services/sensorservice/SensorRecord.cpp b/services/sensorservice/SensorRecord.cpp
    -index 644cfb0..53fb9de 100644
    ---- a/services/sensorservice/SensorRecord.cpp
    -+++ b/services/sensorservice/SensorRecord.cpp
    -@@ -21,13 +21,13 @@
    - namespace android {
    - 
    - SensorService::SensorRecord::SensorRecord(
    --        const sp<SensorEventConnection>& connection)
    -+        const sp<const SensorEventConnection>& connection)
    - {
    -     mConnections.add(connection);
    - }
    - 
    - bool SensorService::SensorRecord::addConnection(
    --        const sp<SensorEventConnection>& connection)
    -+        const sp<const SensorEventConnection>& connection)
    - {
    -     if (mConnections.indexOf(connection) < 0) {
    -         mConnections.add(connection);
    -@@ -37,16 +37,16 @@ bool SensorService::SensorRecord::addConnection(
    - }
    - 
    - bool SensorService::SensorRecord::removeConnection(
    --        const wp<SensorEventConnection>& connection)
    -+        const wp<const SensorEventConnection>& connection)
    - {
    -     ssize_t index = mConnections.indexOf(connection);
    -     if (index >= 0) {
    -         mConnections.removeItemsAt(index, 1);
    -     }
    -     // Remove this connections from the queue of flush() calls made on this sensor.
    --    for (Vector< wp<SensorEventConnection> >::iterator it = mPendingFlushConnections.begin();
    -+    for (Vector< wp<const SensorEventConnection> >::iterator it = mPendingFlushConnections.begin();
    -             it != mPendingFlushConnections.end(); ) {
    --        if (it->unsafe_get() == connection.unsafe_get()) {
    -+        if (*it == connection) {
    -             it = mPendingFlushConnections.erase(it);
    -         } else {
    -             ++it;
    -@@ -56,7 +56,7 @@ bool SensorService::SensorRecord::removeConnection(
    - }
    - 
    - void SensorService::SensorRecord::addPendingFlushConnection(
    --        const sp<SensorEventConnection>& connection) {
    -+        const sp<const SensorEventConnection>& connection) {
    -     mPendingFlushConnections.add(connection);
    - }
    - 
    -@@ -66,10 +66,10 @@ void SensorService::SensorRecord::removeFirstPendingFlushConnection() {
    -     }
    - }
    - 
    --SensorService::SensorEventConnection *
    -+wp<const SensorService::SensorEventConnection>
    -         SensorService::SensorRecord::getFirstPendingFlushConnection() {
    -     if (mPendingFlushConnections.size() > 0) {
    --        return mPendingFlushConnections[0].unsafe_get();
    -+        return mPendingFlushConnections[0];
    -     }
    -     return NULL;
    - }
    -diff --git a/services/sensorservice/SensorRecord.h b/services/sensorservice/SensorRecord.h
    -index 29b970d..5a35410 100644
    ---- a/services/sensorservice/SensorRecord.h
    -+++ b/services/sensorservice/SensorRecord.h
    -@@ -25,20 +25,20 @@ class SensorService;
    - 
    - class SensorService::SensorRecord {
    - public:
    --    SensorRecord(const sp<SensorEventConnection>& connection);
    --    bool addConnection(const sp<SensorEventConnection>& connection);
    --    bool removeConnection(const wp<SensorEventConnection>& connection);
    -+    SensorRecord(const sp<const SensorEventConnection>& connection);
    -+    bool addConnection(const sp<const SensorEventConnection>& connection);
    -+    bool removeConnection(const wp<const SensorEventConnection>& connection);
    -     size_t getNumConnections() const { return mConnections.size(); }
    - 
    --    void addPendingFlushConnection(const sp<SensorEventConnection>& connection);
    -+    void addPendingFlushConnection(const sp<const SensorEventConnection>& connection);
    -     void removeFirstPendingFlushConnection();
    --    SensorEventConnection * getFirstPendingFlushConnection();
    -+    wp<const SensorEventConnection> getFirstPendingFlushConnection();
    -     void clearAllPendingFlushConnections();
    - private:
    --    SortedVector< wp<SensorEventConnection> > mConnections;
    -+    SortedVector< wp<const SensorEventConnection> > mConnections;
    -     // A queue of all flush() calls made on this sensor. Flush complete events
    -     // will be sent in this order.
    --    Vector< wp<SensorEventConnection> > mPendingFlushConnections;
    -+    Vector< wp<const SensorEventConnection> > mPendingFlushConnections;
    - };
    - 
    - }
    -diff --git a/services/sensorservice/SensorService.cpp b/services/sensorservice/SensorService.cpp
    -index a24740b..dbd0624 100644
    ---- a/services/sensorservice/SensorService.cpp
    -+++ b/services/sensorservice/SensorService.cpp
    -@@ -260,7 +260,7 @@ void SensorService::onFirstRef() {
    -             const size_t minBufferSize = SensorEventQueue::MAX_RECEIVE_BUFFER_EVENT_COUNT;
    -             mSensorEventBuffer = new sensors_event_t[minBufferSize];
    -             mSensorEventScratch = new sensors_event_t[minBufferSize];
    --            mMapFlushEventsToConnections = new SensorEventConnection const * [minBufferSize];
    -+            mMapFlushEventsToConnections = new wp<const SensorEventConnection> [minBufferSize];
    -             mCurrentOperatingMode = NORMAL;
    - 
    -             mNextSensorRegIndex = 0;
    -diff --git a/services/sensorservice/SensorService.h b/services/sensorservice/SensorService.h
    -index 1e1ea5a..4a63ef0 100644
    ---- a/services/sensorservice/SensorService.h
    -+++ b/services/sensorservice/SensorService.h
    -@@ -237,7 +237,7 @@ private:
    -     SortedVector< wp<SensorEventConnection> > mActiveConnections;
    -     bool mWakeLockAcquired;
    -     sensors_event_t *mSensorEventBuffer, *mSensorEventScratch;
    --    SensorEventConnection const **mMapFlushEventsToConnections;
    -+    wp<const SensorEventConnection> * mMapFlushEventsToConnections;
    -     std::unordered_map<int, RecentEventLogger*> mRecentEvent;
    -     Mode mCurrentOperatingMode;
    - 
     diff --git a/services/surfaceflinger/Android.mk b/services/surfaceflinger/Android.mk
    -index dc5e97b..cb292ef 100644
    +index ffda035..cb292ef 100644
     --- a/services/surfaceflinger/Android.mk
     +++ b/services/surfaceflinger/Android.mk
     @@ -56,6 +56,9 @@ else
    @@ -1371,255 +380,6 @@ index dc5e97b..cb292ef 100644
      ifeq ($(TARGET_BOARD_PLATFORM),omap4)
          LOCAL_CFLAGS += -DHAS_CONTEXT_PRIORITY
      endif
    -@@ -79,18 +82,36 @@ ifeq ($(TARGET_RUNNING_WITHOUT_SYNC_FRAMEWORK),true)
    -     LOCAL_CFLAGS += -DRUNNING_WITHOUT_SYNC_FRAMEWORK
    - endif
    - 
    --# See build/target/board/generic/BoardConfig.mk for a description of this setting.
    -+# The following two BoardConfig variables define (respectively):
    -+#
    -+#   - The phase offset between hardware vsync and when apps are woken up by the
    -+#     Choreographer callback
    -+#   - The phase offset between hardware vsync and when SurfaceFlinger wakes up
    -+#     to consume input
    -+#
    -+# Their values can be tuned to trade off between display pipeline latency (both
    -+# overall latency and the lengths of the app --> SF and SF --> display phases)
    -+# and frame delivery jitter (which typically manifests as "jank" or "jerkiness"
    -+# while interacting with the device). The default values should produce a
    -+# relatively low amount of jitter at the expense of roughly two frames of
    -+# app --> display latency, and unless significant testing is performed to avoid
    -+# increased display jitter (both manual investigation using systrace [1] and
    -+# automated testing using dumpsys gfxinfo [2] are recommended), they should not
    -+# be modified.
    -+#
    -+# [1] https://developer.android.com/studio/profile/systrace.html
    -+# [2] https://developer.android.com/training/testing/performance.html
    -+
    - ifneq ($(VSYNC_EVENT_PHASE_OFFSET_NS),)
    -     LOCAL_CFLAGS += -DVSYNC_EVENT_PHASE_OFFSET_NS=$(VSYNC_EVENT_PHASE_OFFSET_NS)
    - else
    --    LOCAL_CFLAGS += -DVSYNC_EVENT_PHASE_OFFSET_NS=0
    -+    LOCAL_CFLAGS += -DVSYNC_EVENT_PHASE_OFFSET_NS=1000000
    - endif
    - 
    --# See build/target/board/generic/BoardConfig.mk for a description of this setting.
    - ifneq ($(SF_VSYNC_EVENT_PHASE_OFFSET_NS),)
    -     LOCAL_CFLAGS += -DSF_VSYNC_EVENT_PHASE_OFFSET_NS=$(SF_VSYNC_EVENT_PHASE_OFFSET_NS)
    - else
    --    LOCAL_CFLAGS += -DSF_VSYNC_EVENT_PHASE_OFFSET_NS=0
    -+    LOCAL_CFLAGS += -DSF_VSYNC_EVENT_PHASE_OFFSET_NS=1000000
    - endif
    - 
    - ifneq ($(PRESENT_TIME_OFFSET_FROM_VSYNC_NS),)
    -diff --git a/services/surfaceflinger/DispSync.cpp b/services/surfaceflinger/DispSync.cpp
    -index c67feb3..1a9820d 100644
    ---- a/services/surfaceflinger/DispSync.cpp
    -+++ b/services/surfaceflinger/DispSync.cpp
    -@@ -385,7 +385,7 @@ DispSync::DispSync(const char* name) :
    -     mThread->run("DispSync", PRIORITY_URGENT_DISPLAY + PRIORITY_MORE_FAVORABLE);
    -     // set DispSync to SCHED_FIFO to minimize jitter
    -     struct sched_param param = {0};
    --    param.sched_priority = 1;
    -+    param.sched_priority = 2;
    -     if (sched_setscheduler(mThread->getTid(), SCHED_FIFO, &param) != 0) {
    -         ALOGE("Couldn't set SCHED_FIFO for DispSyncThread");
    -     }
    -diff --git a/services/surfaceflinger/DisplayHardware/HWC2On1Adapter.cpp b/services/surfaceflinger/DisplayHardware/HWC2On1Adapter.cpp
    -index 8bcee39..cc0dfb0 100644
    ---- a/services/surfaceflinger/DisplayHardware/HWC2On1Adapter.cpp
    -+++ b/services/surfaceflinger/DisplayHardware/HWC2On1Adapter.cpp
    -@@ -2305,7 +2305,14 @@ void HWC2On1Adapter::Layer::applyCompositionType(hwc_layer_1_t& hwc1Layer,
    -                 hwc1Layer.compositionType = HWC_FRAMEBUFFER;
    -                 break;
    -             case Composition::SolidColor:
    --                hwc1Layer.compositionType = HWC_BACKGROUND;
    -+                // In theory the following line should work, but since the HWC1
    -+                // version of SurfaceFlinger never used HWC_BACKGROUND, HWC1
    -+                // devices may not work correctly. To be on the safe side, we
    -+                // fall back to client composition.
    -+                //
    -+                // hwc1Layer.compositionType = HWC_BACKGROUND;
    -+                hwc1Layer.compositionType = HWC_FRAMEBUFFER;
    -+                hwc1Layer.flags |= HWC_SKIP_LAYER;
    -                 break;
    -             case Composition::Cursor:
    -                 hwc1Layer.compositionType = HWC_FRAMEBUFFER;
    -diff --git a/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp b/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp
    -index 61bb0bd..2190466 100644
    ---- a/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp
    -+++ b/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp
    -@@ -563,8 +563,8 @@ status_t VirtualDisplaySurface::connect(const sp<IProducerListener>& listener,
    -     return result;
    - }
    - 
    --status_t VirtualDisplaySurface::disconnect(int api) {
    --    return mSource[SOURCE_SINK]->disconnect(api);
    -+status_t VirtualDisplaySurface::disconnect(int api, DisconnectMode mode) {
    -+    return mSource[SOURCE_SINK]->disconnect(api, mode);
    - }
    - 
    - status_t VirtualDisplaySurface::setSidebandStream(const sp<NativeHandle>& /*stream*/) {
    -diff --git a/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.h b/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.h
    -index bf9b39c..70f717f 100644
    ---- a/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.h
    -+++ b/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.h
    -@@ -115,7 +115,7 @@ private:
    -     virtual int query(int what, int* value);
    -     virtual status_t connect(const sp<IProducerListener>& listener,
    -             int api, bool producerControlledByApp, QueueBufferOutput* output);
    --    virtual status_t disconnect(int api);
    -+    virtual status_t disconnect(int api, DisconnectMode mode);
    -     virtual status_t setSidebandStream(const sp<NativeHandle>& stream);
    -     virtual void allocateBuffers(uint32_t width, uint32_t height,
    -             PixelFormat format, uint32_t usage);
    -diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
    -index 785df1a..dfece93 100644
    ---- a/services/surfaceflinger/Layer.cpp
    -+++ b/services/surfaceflinger/Layer.cpp
    -@@ -591,19 +591,25 @@ void Layer::setGeometry(
    -     const Transform& tr(displayDevice->getTransform());
    -     Rect transformedFrame = tr.transform(frame);
    -     auto error = hwcLayer->setDisplayFrame(transformedFrame);
    --    ALOGE_IF(error != HWC2::Error::None, "[%s] Failed to set display frame "
    --            "[%d, %d, %d, %d]: %s (%d)", mName.string(), transformedFrame.left,
    --            transformedFrame.top, transformedFrame.right,
    --            transformedFrame.bottom, to_string(error).c_str(),
    --            static_cast<int32_t>(error));
    -+    if (error != HWC2::Error::None) {
    -+        ALOGE("[%s] Failed to set display frame [%d, %d, %d, %d]: %s (%d)",
    -+                mName.string(), transformedFrame.left, transformedFrame.top,
    -+                transformedFrame.right, transformedFrame.bottom,
    -+                to_string(error).c_str(), static_cast<int32_t>(error));
    -+    } else {
    -+        hwcInfo.displayFrame = transformedFrame;
    -+    }
    - 
    -     FloatRect sourceCrop = computeCrop(displayDevice);
    -     error = hwcLayer->setSourceCrop(sourceCrop);
    --    ALOGE_IF(error != HWC2::Error::None, "[%s] Failed to set source crop "
    --            "[%.3f, %.3f, %.3f, %.3f]: %s (%d)", mName.string(),
    --            sourceCrop.left, sourceCrop.top, sourceCrop.right,
    --            sourceCrop.bottom, to_string(error).c_str(),
    --            static_cast<int32_t>(error));
    -+    if (error != HWC2::Error::None) {
    -+        ALOGE("[%s] Failed to set source crop [%.3f, %.3f, %.3f, %.3f]: "
    -+                "%s (%d)", mName.string(), sourceCrop.left, sourceCrop.top,
    -+                sourceCrop.right, sourceCrop.bottom, to_string(error).c_str(),
    -+                static_cast<int32_t>(error));
    -+    } else {
    -+        hwcInfo.sourceCrop = sourceCrop;
    -+    }
    - 
    -     error = hwcLayer->setPlaneAlpha(s.alpha);
    -     ALOGE_IF(error != HWC2::Error::None, "[%s] Failed to set plane alpha %.3f: "
    -@@ -2235,6 +2241,54 @@ void Layer::dump(String8& result, Colorizer& colorizer) const
    -     }
    - }
    - 
    -+#ifdef USE_HWC2
    -+void Layer::miniDumpHeader(String8& result) {
    -+    result.append("----------------------------------------");
    -+    result.append("---------------------------------------\n");
    -+    result.append(" Layer name\n");
    -+    result.append("           Z | ");
    -+    result.append(" Comp Type | ");
    -+    result.append("  Disp Frame (LTRB) | ");
    -+    result.append("         Source Crop (LTRB)\n");
    -+    result.append("----------------------------------------");
    -+    result.append("---------------------------------------\n");
    -+}
    -+
    -+void Layer::miniDump(String8& result, int32_t hwcId) const {
    -+    if (mHwcLayers.count(hwcId) == 0) {
    -+        return;
    -+    }
    -+
    -+    String8 name;
    -+    if (mName.length() > 77) {
    -+        std::string shortened;
    -+        shortened.append(mName.string(), 36);
    -+        shortened.append("[...]");
    -+        shortened.append(mName.string() + (mName.length() - 36), 36);
    -+        name = shortened.c_str();
    -+    } else {
    -+        name = mName;
    -+    }
    -+
    -+    result.appendFormat(" %s\n", name.string());
    -+
    -+    const Layer::State& layerState(getDrawingState());
    -+    const HWCInfo& hwcInfo = mHwcLayers.at(hwcId);
    -+    result.appendFormat("  %10u | ", layerState.z);
    -+    result.appendFormat("%10s | ",
    -+            to_string(getCompositionType(hwcId)).c_str());
    -+    const Rect& frame = hwcInfo.displayFrame;
    -+    result.appendFormat("%4d %4d %4d %4d | ", frame.left, frame.top,
    -+            frame.right, frame.bottom);
    -+    const FloatRect& crop = hwcInfo.sourceCrop;
    -+    result.appendFormat("%6.1f %6.1f %6.1f %6.1f\n", crop.left, crop.top,
    -+            crop.right, crop.bottom);
    -+
    -+    result.append("- - - - - - - - - - - - - - - - - - - - ");
    -+    result.append("- - - - - - - - - - - - - - - - - - - -\n");
    -+}
    -+#endif
    -+
    - void Layer::dumpFrameStats(String8& result) const {
    -     mFrameTracker.dumpStats(result);
    - }
    -diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h
    -index 6533953..2ce1340 100644
    ---- a/services/surfaceflinger/Layer.h
    -+++ b/services/surfaceflinger/Layer.h
    -@@ -402,6 +402,10 @@ public:
    - 
    -     /* always call base class first */
    -     void dump(String8& result, Colorizer& colorizer) const;
    -+#ifdef USE_HWC2
    -+    static void miniDumpHeader(String8& result);
    -+    void miniDump(String8& result, int32_t hwcId) const;
    -+#endif
    -     void dumpFrameStats(String8& result) const;
    -     void clearFrameStats();
    -     void logFrameStats();
    -@@ -588,6 +592,8 @@ private:
    -         bool forceClientComposition;
    -         HWC2::Composition compositionType;
    -         bool clearClientTarget;
    -+        Rect displayFrame;
    -+        FloatRect sourceCrop;
    -     };
    -     std::unordered_map<int32_t, HWCInfo> mHwcLayers;
    - #else
    -diff --git a/services/surfaceflinger/MonitoredProducer.cpp b/services/surfaceflinger/MonitoredProducer.cpp
    -index 36cfa37..ffaee7a 100644
    ---- a/services/surfaceflinger/MonitoredProducer.cpp
    -+++ b/services/surfaceflinger/MonitoredProducer.cpp
    -@@ -102,8 +102,8 @@ status_t MonitoredProducer::connect(const sp<IProducerListener>& listener,
    -     return mProducer->connect(listener, api, producerControlledByApp, output);
    - }
    - 
    --status_t MonitoredProducer::disconnect(int api) {
    --    return mProducer->disconnect(api);
    -+status_t MonitoredProducer::disconnect(int api, DisconnectMode mode) {
    -+    return mProducer->disconnect(api, mode);
    - }
    - 
    - status_t MonitoredProducer::setSidebandStream(const sp<NativeHandle>& stream) {
    -diff --git a/services/surfaceflinger/MonitoredProducer.h b/services/surfaceflinger/MonitoredProducer.h
    -index f64fe51..66f6cf0 100644
    ---- a/services/surfaceflinger/MonitoredProducer.h
    -+++ b/services/surfaceflinger/MonitoredProducer.h
    -@@ -50,7 +50,7 @@ public:
    -     virtual int query(int what, int* value);
    -     virtual status_t connect(const sp<IProducerListener>& token, int api,
    -             bool producerControlledByApp, QueueBufferOutput* output);
    --    virtual status_t disconnect(int api);
    -+    virtual status_t disconnect(int api, DisconnectMode mode);
    -     virtual status_t setSidebandStream(const sp<NativeHandle>& stream);
    -     virtual void allocateBuffers(uint32_t width, uint32_t height,
    -             PixelFormat format, uint32_t usage);
     diff --git a/services/surfaceflinger/RenderEngine/GLES11RenderEngine.cpp b/services/surfaceflinger/RenderEngine/GLES11RenderEngine.cpp
     index 847cdb3..b2821b7 100644
     --- a/services/surfaceflinger/RenderEngine/GLES11RenderEngine.cpp
    @@ -1862,46 +622,10 @@ index 0259881..5a5910a 100644
              int getStatus() const;
          };
     diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
    -index 2a67f4c..874cdc8 100644
    +index 8db071e..874cdc8 100644
     --- a/services/surfaceflinger/SurfaceFlinger.cpp
     +++ b/services/surfaceflinger/SurfaceFlinger.cpp
    -@@ -471,7 +471,7 @@ void SurfaceFlinger::init() {
    - 
    -         // set SFEventThread to SCHED_FIFO to minimize jitter
    -         struct sched_param param = {0};
    --        param.sched_priority = 1;
    -+        param.sched_priority = 2;
    -         if (sched_setscheduler(mSFEventThread->getTid(), SCHED_FIFO, &param) != 0) {
    -             ALOGE("Couldn't set SCHED_FIFO for SFEventThread");
    -         }
    -@@ -3057,6 +3057,26 @@ void SurfaceFlinger::dumpAllLocked(const Vector<String16>& args, size_t& index,
    -      * VSYNC state
    -      */
    -     mEventThread->dump(result);
    -+    result.append("\n");
    -+
    -+    /*
    -+     * HWC layer minidump
    -+     */
    -+    for (size_t d = 0; d < mDisplays.size(); d++) {
    -+        const sp<const DisplayDevice>& displayDevice(mDisplays[d]);
    -+        int32_t hwcId = displayDevice->getHwcDisplayId();
    -+        if (hwcId == DisplayDevice::DISPLAY_ID_INVALID) {
    -+            continue;
    -+        }
    -+
    -+        result.appendFormat("Display %d HWC layers:\n", hwcId);
    -+        Layer::miniDumpHeader(result);
    -+        for (size_t l = 0; l < count; l++) {
    -+            const sp<Layer>& layer(currentLayers[l]);
    -+            layer->miniDump(result, hwcId);
    -+        }
    -+        result.append("\n");
    -+    }
    - 
    -     /*
    -      * Dump HWComposer state
    -@@ -3418,7 +3438,8 @@ status_t SurfaceFlinger::captureScreen(const sp<IBinder>& display,
    +@@ -3438,7 +3438,8 @@ status_t SurfaceFlinger::captureScreen(const sp<IBinder>& display,
              const sp<IGraphicBufferProducer>& producer,
              Rect sourceCrop, uint32_t reqWidth, uint32_t reqHeight,
              uint32_t minLayerZ, uint32_t maxLayerZ,
    @@ -1911,7 +635,7 @@ index 2a67f4c..874cdc8 100644
      
          if (CC_UNLIKELY(display == 0))
              return BAD_VALUE;
    -@@ -3462,6 +3483,7 @@ status_t SurfaceFlinger::captureScreen(const sp<IBinder>& display,
    +@@ -3482,6 +3483,7 @@ status_t SurfaceFlinger::captureScreen(const sp<IBinder>& display,
              bool useIdentityTransform;
              Transform::orientation_flags rotation;
              status_t result;
    @@ -1919,7 +643,7 @@ index 2a67f4c..874cdc8 100644
              bool isLocalScreenshot;
          public:
              MessageCaptureScreen(SurfaceFlinger* flinger,
    -@@ -3471,12 +3493,13 @@ status_t SurfaceFlinger::captureScreen(const sp<IBinder>& display,
    +@@ -3491,12 +3493,13 @@ status_t SurfaceFlinger::captureScreen(const sp<IBinder>& display,
                      uint32_t minLayerZ, uint32_t maxLayerZ,
                      bool useIdentityTransform,
                      Transform::orientation_flags rotation,
    @@ -1934,7 +658,7 @@ index 2a67f4c..874cdc8 100644
                    isLocalScreenshot(isLocalScreenshot)
              {
              }
    -@@ -3486,9 +3509,10 @@ status_t SurfaceFlinger::captureScreen(const sp<IBinder>& display,
    +@@ -3506,9 +3509,10 @@ status_t SurfaceFlinger::captureScreen(const sp<IBinder>& display,
              virtual bool handler() {
                  Mutex::Autolock _l(flinger->mStateLock);
                  sp<const DisplayDevice> hw(flinger->getDisplayDevice(display));
    @@ -1946,7 +670,7 @@ index 2a67f4c..874cdc8 100644
                  static_cast<GraphicProducerWrapper*>(IInterface::asBinder(producer).get())->exit(result);
                  return true;
              }
    -@@ -3504,7 +3528,7 @@ status_t SurfaceFlinger::captureScreen(const sp<IBinder>& display,
    +@@ -3524,7 +3528,7 @@ status_t SurfaceFlinger::captureScreen(const sp<IBinder>& display,
          sp<MessageBase> msg = new MessageCaptureScreen(this,
                  display, IGraphicBufferProducer::asInterface( wrapper ),
                  sourceCrop, reqWidth, reqHeight, minLayerZ, maxLayerZ,
    @@ -1955,7 +679,7 @@ index 2a67f4c..874cdc8 100644
      
          status_t res = postMessageAsync(msg);
          if (res == NO_ERROR) {
    -@@ -3587,7 +3611,7 @@ status_t SurfaceFlinger::captureScreenImplLocked(
    +@@ -3607,7 +3611,7 @@ status_t SurfaceFlinger::captureScreenImplLocked(
              Rect sourceCrop, uint32_t reqWidth, uint32_t reqHeight,
              uint32_t minLayerZ, uint32_t maxLayerZ,
              bool useIdentityTransform, Transform::orientation_flags rotation,
    @@ -1964,7 +688,7 @@ index 2a67f4c..874cdc8 100644
      {
          ATRACE_CALL();
      
    -@@ -3665,7 +3689,7 @@ status_t SurfaceFlinger::captureScreenImplLocked(
    +@@ -3685,7 +3689,7 @@ status_t SurfaceFlinger::captureScreenImplLocked(
                      if (image != EGL_NO_IMAGE_KHR) {
                          // this binds the given EGLImage as a framebuffer for the
                          // duration of this scope.
    @@ -1973,7 +697,7 @@ index 2a67f4c..874cdc8 100644
                          if (imageBond.getStatus() == NO_ERROR) {
                              // this will in fact render into our dequeued buffer
                              // via an FBO, which means we didn't have to create
    -@@ -3712,6 +3736,16 @@ status_t SurfaceFlinger::captureScreenImplLocked(
    +@@ -3732,6 +3736,16 @@ status_t SurfaceFlinger::captureScreenImplLocked(
                                      ALOGW("captureScreen: error creating EGL fence: %#x", eglGetError());
                                  }
                              }
    @@ -2014,7 +738,7 @@ index b98924b..2c3bd19 100644
          /* ------------------------------------------------------------------------
           * EGL
     diff --git a/services/surfaceflinger/SurfaceFlinger_hwc1.cpp b/services/surfaceflinger/SurfaceFlinger_hwc1.cpp
    -index 650d6b4..ca03830 100644
    +index b0f418c..ca03830 100644
     --- a/services/surfaceflinger/SurfaceFlinger_hwc1.cpp
     +++ b/services/surfaceflinger/SurfaceFlinger_hwc1.cpp
     @@ -466,10 +466,12 @@ void SurfaceFlinger::init() {
    @@ -2022,7 +746,7 @@ index 650d6b4..ca03830 100644
      
          // set SFEventThread to SCHED_FIFO to minimize jitter
     -    struct sched_param param = {0};
    --    param.sched_priority = 1;
    +-    param.sched_priority = 2;
     -    if (sched_setscheduler(mSFEventThread->getTid(), SCHED_FIFO, &param) != 0) {
     -        ALOGE("Couldn't set SCHED_FIFO for SFEventThread");
     +    if (mSFEventThread != NULL) {
    diff --git a/hardware_ril.patch b/hardware_ril.patch
    index 114367f..4b5d125 100644
    --- a/hardware_ril.patch
    +++ b/hardware_ril.patch
    @@ -1,54 +1,12 @@
    -diff --git a/include/telephony/ril.h b/include/telephony/ril.h
    -index 98aa7d3..5fcd901 100644
    ---- a/include/telephony/ril.h
    -+++ b/include/telephony/ril.h
    -@@ -1712,18 +1712,29 @@ typedef struct {
    - /* Tx Power Levels */
    - #define RIL_NUM_TX_POWER_LEVELS     5
    - 
    -+/**
    -+ * Aggregate modem activity information
    -+ */
    - typedef struct {
    - 
    --  /* period (in ms) when modem is power collapsed */
    -+  /* total time (in ms) when modem is in a low power or
    -+   * sleep state
    -+   */
    -   uint32_t sleep_mode_time_ms;
    - 
    --  /* period (in ms) when modem is awake and in idle mode*/
    -+  /* total time (in ms) when modem is awake but neither
    -+   * the transmitter nor receiver are active/awake */
    -   uint32_t idle_mode_time_ms;
    - 
    --  /* period (in ms) for which Tx is active */
    -+  /* total time (in ms) during which the transmitter is active/awake,
    -+   * subdivided by manufacturer-defined device-specific
    -+   * contiguous increasing ranges of transmit power between
    -+   * 0 and the transmitter's maximum transmit power.
    -+   */
    -   uint32_t tx_mode_time_ms[RIL_NUM_TX_POWER_LEVELS];
    - 
    --  /* period (in ms) for which Rx is active */
    -+  /* total time (in ms) for which receiver is active/awake and
    -+   * the transmitter is inactive */
    -   uint32_t rx_mode_time_ms;
    - } RIL_ActivityStatsInfo;
    - 
    -@@ -5101,11 +5112,11 @@ typedef struct {
    - /**
    -  * RIL_REQUEST_GET_ACTIVITY_INFO
    -  *
    -- * Get modem activity statisitics info.
    -+ * Get modem activity information for power consumption estimation.
    -  *
    -- * There can be multiple RIL_REQUEST_GET_ACTIVITY_INFO calls to modem.
    -- * Once the response for the request is sent modem will clear
    -- * current statistics information.
    -+ * Request clear-on-read statistics information that is used for
    -+ * estimating the per-millisecond power consumption of the cellular
    -+ * modem.
    -  *
    -  * "data" is null
    -  * "response" is const RIL_ActivityStatsInfo *
    +diff --git a/libril/ril.cpp b/libril/ril.cpp
    +index d7744c0..561ba55 100644
    +--- a/libril/ril.cpp
    ++++ b/libril/ril.cpp
    +@@ -3804,6 +3804,7 @@ static void responseSimStatusV5(Parcel &p, void *response) {
    +     p.writeInt32(p_cur->universal_pin_state);
    +     p.writeInt32(p_cur->gsm_umts_subscription_app_index);
    +     p.writeInt32(p_cur->cdma_subscription_app_index);
    ++    p.writeInt32(-1);
    + 
    +     sendSimStatusAppInfo(p, p_cur->num_applications, p_cur->applications);
    + }
    diff --git a/system_core.patch b/system_core.patch
    index 335d3d2..6a071bd 100644
    --- a/system_core.patch
    +++ b/system_core.patch
    @@ -1,580 +1,3 @@
    -diff --git a/adb/adb.h b/adb/adb.h
    -index 971b8da..b1d9896 100644
    ---- a/adb/adb.h
    -+++ b/adb/adb.h
    -@@ -160,8 +160,10 @@ int get_available_local_transport_index();
    - int  init_socket_transport(atransport *t, int s, int port, int local);
    - void init_usb_transport(atransport *t, usb_handle *usb, ConnectionState state);
    - 
    -+std::string getEmulatorSerialString(int console_port);
    - #if ADB_HOST
    - atransport* find_emulator_transport_by_adb_port(int adb_port);
    -+atransport* find_emulator_transport_by_console_port(int console_port);
    - #endif
    - 
    - int service_to_fd(const char* name, const atransport* transport);
    -diff --git a/adb/bugreport.cpp b/adb/bugreport.cpp
    -index 9ed44a7..c348dd5 100644
    ---- a/adb/bugreport.cpp
    -+++ b/adb/bugreport.cpp
    -@@ -47,7 +47,7 @@ class BugreportStandardStreamsCallback : public StandardStreamsCallbackInterface
    -           show_progress_(show_progress),
    -           status_(0),
    -           line_() {
    --        SetLineMessage();
    -+        SetLineMessage("generating");
    -     }
    - 
    -     void OnStdout(const char* buffer, int length) {
    -@@ -97,6 +97,7 @@ class BugreportStandardStreamsCallback : public StandardStreamsCallbackInterface
    -                                                           OS_PATH_SEPARATOR, dest_file_.c_str());
    -             }
    -             std::vector<const char*> srcs{src_file_.c_str()};
    -+            SetLineMessage("pulling");
    -             status_ =
    -                 br_->DoSyncPull(srcs, destination.c_str(), true, line_message_.c_str()) ? 0 : 1;
    -             if (status_ != 0) {
    -@@ -111,9 +112,8 @@ class BugreportStandardStreamsCallback : public StandardStreamsCallbackInterface
    -     }
    - 
    -   private:
    --    void SetLineMessage() {
    --        line_message_ =
    --            android::base::StringPrintf("generating %s", adb_basename(dest_file_).c_str());
    -+    void SetLineMessage(const std::string& action) {
    -+        line_message_ = action + " " + adb_basename(dest_file_);
    -     }
    - 
    -     void SetSrcFile(const std::string path) {
    -@@ -121,7 +121,7 @@ class BugreportStandardStreamsCallback : public StandardStreamsCallbackInterface
    -         if (!dest_dir_.empty()) {
    -             // Only uses device-provided name when user passed a directory.
    -             dest_file_ = adb_basename(path);
    --            SetLineMessage();
    -+            SetLineMessage("generating");
    -         }
    -     }
    - 
    -diff --git a/adb/bugreport_test.cpp b/adb/bugreport_test.cpp
    -index 3cd2b6d..1129285 100644
    ---- a/adb/bugreport_test.cpp
    -+++ b/adb/bugreport_test.cpp
    -@@ -189,7 +189,7 @@ TEST_F(BugreportTest, NoArgumentsNDevice) {
    -         .WillOnce(DoAll(WithArg<4>(WriteOnStdout("OK:/device/da_bugreport.zip")),
    -                         WithArg<4>(ReturnCallbackDone())));
    -     EXPECT_CALL(br_, DoSyncPull(ElementsAre(StrEq("/device/da_bugreport.zip")), StrEq(dest_file),
    --                                true, StrEq("generating da_bugreport.zip")))
    -+                                true, StrEq("pulling da_bugreport.zip")))
    -         .WillOnce(Return(true));
    - 
    -     const char* args[] = {"bugreport"};
    -@@ -209,7 +209,7 @@ TEST_F(BugreportTest, NoArgumentsPostNDevice) {
    -                         WithArg<4>(WriteOnStdout("OK:/device/da_bugreport.zip\n")),
    -                         WithArg<4>(ReturnCallbackDone())));
    -     EXPECT_CALL(br_, DoSyncPull(ElementsAre(StrEq("/device/da_bugreport.zip")), StrEq(dest_file),
    --                                true, StrEq("generating da_bugreport.zip")))
    -+                                true, StrEq("pulling da_bugreport.zip")))
    -         .WillOnce(Return(true));
    - 
    -     const char* args[] = {"bugreport"};
    -@@ -223,7 +223,7 @@ TEST_F(BugreportTest, OkNDevice) {
    -         .WillOnce(DoAll(WithArg<4>(WriteOnStdout("OK:/device/bugreport.zip")),
    -                         WithArg<4>(ReturnCallbackDone())));
    -     EXPECT_CALL(br_, DoSyncPull(ElementsAre(StrEq("/device/bugreport.zip")), StrEq("file.zip"),
    --                                true, StrEq("generating file.zip")))
    -+                                true, StrEq("pulling file.zip")))
    -         .WillOnce(Return(true));
    - 
    -     const char* args[] = {"bugreport", "file.zip"};
    -@@ -239,7 +239,7 @@ TEST_F(BugreportTest, OkNDeviceSplitBuffer) {
    -                         WithArg<4>(WriteOnStdout("/bugreport.zip")),
    -                         WithArg<4>(ReturnCallbackDone())));
    -     EXPECT_CALL(br_, DoSyncPull(ElementsAre(StrEq("/device/bugreport.zip")), StrEq("file.zip"),
    --                                true, StrEq("generating file.zip")))
    -+                                true, StrEq("pulling file.zip")))
    -         .WillOnce(Return(true));
    - 
    -     const char* args[] = {"bugreport", "file.zip"};
    -@@ -275,7 +275,7 @@ TEST_F(BugreportTest, OkProgress) {
    -             WithArg<4>(ReturnCallbackDone())));
    -     // clang-format on
    -     EXPECT_CALL(br_, DoSyncPull(ElementsAre(StrEq("/device/bugreport.zip")), StrEq("file.zip"),
    --                                true, StrEq("generating file.zip")))
    -+                                true, StrEq("pulling file.zip")))
    -         .WillOnce(Return(true));
    - 
    -     const char* args[] = {"bugreport", "file.zip"};
    -@@ -294,7 +294,7 @@ TEST_F(BugreportTest, OkDirectory) {
    -                         WithArg<4>(WriteOnStdout("OK:/device/da_bugreport.zip")),
    -                         WithArg<4>(ReturnCallbackDone())));
    -     EXPECT_CALL(br_, DoSyncPull(ElementsAre(StrEq("/device/da_bugreport.zip")), StrEq(dest_file),
    --                                true, StrEq("generating da_bugreport.zip")))
    -+                                true, StrEq("pulling da_bugreport.zip")))
    -         .WillOnce(Return(true));
    - 
    -     const char* args[] = {"bugreport", td.path};
    -@@ -308,7 +308,7 @@ TEST_F(BugreportTest, OkNoExtension) {
    -         .WillOnce(DoAll(WithArg<4>(WriteOnStdout("OK:/device/bugreport.zip\n")),
    -                         WithArg<4>(ReturnCallbackDone())));
    -     EXPECT_CALL(br_, DoSyncPull(ElementsAre(StrEq("/device/bugreport.zip")), StrEq("file.zip"),
    --                                true, StrEq("generating file.zip")))
    -+                                true, StrEq("pulling file.zip")))
    -         .WillOnce(Return(true));
    - 
    -     const char* args[] = {"bugreport", "file"};
    -@@ -327,7 +327,7 @@ TEST_F(BugreportTest, OkNDeviceDirectory) {
    -                         WithArg<4>(WriteOnStdout("OK:/device/da_bugreport.zip")),
    -                         WithArg<4>(ReturnCallbackDone())));
    -     EXPECT_CALL(br_, DoSyncPull(ElementsAre(StrEq("/device/da_bugreport.zip")), StrEq(dest_file),
    --                                true, StrEq("generating da_bugreport.zip")))
    -+                                true, StrEq("pulling da_bugreport.zip")))
    -         .WillOnce(Return(true));
    - 
    -     const char* args[] = {"bugreport", td.path};
    -diff --git a/adb/commandline.cpp b/adb/commandline.cpp
    -index 23827de..51d828a 100644
    ---- a/adb/commandline.cpp
    -+++ b/adb/commandline.cpp
    -@@ -1430,6 +1430,16 @@ static bool _is_valid_ack_reply_fd(const int ack_reply_fd) {
    - #endif
    - }
    - 
    -+static bool _use_legacy_install() {
    -+    FeatureSet features;
    -+    std::string error;
    -+    if (!adb_get_feature_set(&features, &error)) {
    -+        fprintf(stderr, "error: %s\n", error.c_str());
    -+        return true;
    -+    }
    -+    return !CanUseFeature(features, kFeatureCmd);
    -+}
    -+
    - int adb_commandline(int argc, const char **argv) {
    -     int no_daemon = 0;
    -     int is_daemon = 0;
    -@@ -1797,17 +1807,10 @@ int adb_commandline(int argc, const char **argv) {
    -     }
    -     else if (!strcmp(argv[0], "install")) {
    -         if (argc < 2) return usage();
    --        FeatureSet features;
    --        std::string error;
    --        if (!adb_get_feature_set(&features, &error)) {
    --            fprintf(stderr, "error: %s\n", error.c_str());
    --            return 1;
    -+        if (_use_legacy_install()) {
    -+            return install_app_legacy(transport_type, serial, argc, argv);
    -         }
    --
    --        if (CanUseFeature(features, kFeatureCmd)) {
    --            return install_app(transport_type, serial, argc, argv);
    --        }
    --        return install_app_legacy(transport_type, serial, argc, argv);
    -+        return install_app(transport_type, serial, argc, argv);
    -     }
    -     else if (!strcmp(argv[0], "install-multiple")) {
    -         if (argc < 2) return usage();
    -@@ -1815,17 +1818,10 @@ int adb_commandline(int argc, const char **argv) {
    -     }
    -     else if (!strcmp(argv[0], "uninstall")) {
    -         if (argc < 2) return usage();
    --        FeatureSet features;
    --        std::string error;
    --        if (!adb_get_feature_set(&features, &error)) {
    --            fprintf(stderr, "error: %s\n", error.c_str());
    --            return 1;
    -+        if (_use_legacy_install()) {
    -+            return uninstall_app_legacy(transport_type, serial, argc, argv);
    -         }
    --
    --        if (CanUseFeature(features, kFeatureCmd)) {
    --            return uninstall_app(transport_type, serial, argc, argv);
    --        }
    --        return uninstall_app_legacy(transport_type, serial, argc, argv);
    -+        return uninstall_app(transport_type, serial, argc, argv);
    -     }
    -     else if (!strcmp(argv[0], "sync")) {
    -         std::string src;
    -@@ -2031,7 +2027,6 @@ static int install_multiple_app(TransportType transport, const char* serial, int
    -     int i;
    -     struct stat sb;
    -     uint64_t total_size = 0;
    --
    -     // Find all APK arguments starting at end.
    -     // All other arguments passed through verbatim.
    -     int first_apk = -1;
    -@@ -2056,7 +2051,14 @@ static int install_multiple_app(TransportType transport, const char* serial, int
    -         return 1;
    -     }
    - 
    --    std::string cmd = android::base::StringPrintf("exec:pm install-create -S %" PRIu64, total_size);
    -+    std::string install_cmd;
    -+    if (_use_legacy_install()) {
    -+        install_cmd = "exec:pm";
    -+    } else {
    -+        install_cmd = "exec:cmd package";
    -+    }
    -+
    -+    std::string cmd = android::base::StringPrintf("%s install-create -S %" PRIu64, install_cmd.c_str(), total_size);
    -     for (i = 1; i < first_apk; i++) {
    -         cmd += " " + escape_arg(argv[i]);
    -     }
    -@@ -2098,8 +2100,8 @@ static int install_multiple_app(TransportType transport, const char* serial, int
    -         }
    - 
    -         std::string cmd = android::base::StringPrintf(
    --                "exec:pm install-write -S %" PRIu64 " %d %d_%s -",
    --                static_cast<uint64_t>(sb.st_size), session_id, i, adb_basename(file).c_str());
    -+                "%s install-write -S %" PRIu64 " %d %d_%s -",
    -+                install_cmd.c_str(), static_cast<uint64_t>(sb.st_size), session_id, i, adb_basename(file).c_str());
    - 
    -         int localFd = adb_open(file, O_RDONLY);
    -         if (localFd < 0) {
    -@@ -2134,8 +2136,8 @@ static int install_multiple_app(TransportType transport, const char* serial, int
    - finalize_session:
    -     // Commit session if we streamed everything okay; otherwise abandon
    -     std::string service =
    --            android::base::StringPrintf("exec:pm install-%s %d",
    --                                        success ? "commit" : "abandon", session_id);
    -+            android::base::StringPrintf("%s install-%s %d",
    -+                                        install_cmd.c_str(), success ? "commit" : "abandon", session_id);
    -     fd = adb_connect(service, &error);
    -     if (fd < 0) {
    -         fprintf(stderr, "Connect error for finalize: %s\n", error.c_str());
    -diff --git a/adb/transport_local.cpp b/adb/transport_local.cpp
    -index 4f3e1f5..1f5a258 100644
    ---- a/adb/transport_local.cpp
    -+++ b/adb/transport_local.cpp
    -@@ -99,7 +99,8 @@ int local_connect_arbitrary_ports(int console_port, int adb_port, std::string* e
    -     int fd = -1;
    - 
    - #if ADB_HOST
    --    if (find_emulator_transport_by_adb_port(adb_port) != nullptr) {
    -+    if (find_emulator_transport_by_adb_port(adb_port) != nullptr ||
    -+        find_emulator_transport_by_console_port(console_port) != nullptr) {
    -         return -1;
    -     }
    - 
    -@@ -116,7 +117,7 @@ int local_connect_arbitrary_ports(int console_port, int adb_port, std::string* e
    -         D("client: connected on remote on fd %d", fd);
    -         close_on_exec(fd);
    -         disable_tcp_nagle(fd);
    --        std::string serial = android::base::StringPrintf("emulator-%d", console_port);
    -+        std::string serial = getEmulatorSerialString(console_port);
    -         if (register_socket_transport(fd, serial.c_str(), adb_port, 1) == 0) {
    -             return 0;
    -         }
    -@@ -360,6 +361,11 @@ atransport* find_emulator_transport_by_adb_port_locked(int adb_port)
    -     return NULL;
    - }
    - 
    -+std::string getEmulatorSerialString(int console_port)
    -+{
    -+    return android::base::StringPrintf("emulator-%d", console_port);
    -+}
    -+
    - atransport* find_emulator_transport_by_adb_port(int adb_port)
    - {
    -     adb_mutex_lock( &local_transports_lock );
    -@@ -368,6 +374,12 @@ atransport* find_emulator_transport_by_adb_port(int adb_port)
    -     return result;
    - }
    - 
    -+atransport* find_emulator_transport_by_console_port(int console_port)
    -+{
    -+    return find_transport(getEmulatorSerialString(console_port).c_str());
    -+}
    -+
    -+
    - /* Only call this function if you already hold local_transports_lock. */
    - int get_available_local_transport_index_locked()
    - {
    -diff --git a/debuggerd/tombstone.cpp b/debuggerd/tombstone.cpp
    -index fa983fa..dfdf29c 100644
    ---- a/debuggerd/tombstone.cpp
    -+++ b/debuggerd/tombstone.cpp
    -@@ -368,6 +368,7 @@ static void dump_all_maps(Backtrace* backtrace, BacktraceMap* map, log_t* log, p
    -     ALOGE("Cannot get siginfo for %d: %s\n", tid, strerror(errno));
    -   }
    - 
    -+  ScopedBacktraceMapIteratorLock lock(map);
    -   _LOG(log, logtype::MAPS, "\n");
    -   if (!print_fault_address_marker) {
    -     _LOG(log, logtype::MAPS, "memory map:\n");
    -diff --git a/fastboot/fastboot.cpp b/fastboot/fastboot.cpp
    -index c1c3174..2b6cad1 100644
    ---- a/fastboot/fastboot.cpp
    -+++ b/fastboot/fastboot.cpp
    -@@ -116,16 +116,18 @@ static struct {
    - };
    - 
    - static std::string find_item_given_name(const char* img_name, const char* product) {
    --    char *dir;
    --    char path[PATH_MAX + 128];
    -+    char path_c_str[PATH_MAX + 128];
    - 
    -     if(product) {
    --        get_my_path(path);
    --        return android::base::StringPrintf("../../../target/product/%s/%s", product, img_name);
    -+        get_my_path(path_c_str);
    -+        std::string path = path_c_str;
    -+        path.erase(path.find_last_of('/'));
    -+        return android::base::StringPrintf("%s/../../../target/product/%s/%s",
    -+                                           path.c_str(), product, img_name);
    -     }
    - 
    --    dir = getenv("ANDROID_PRODUCT_OUT");
    --    if((dir == 0) || (dir[0] == 0)) {
    -+    char *dir = getenv("ANDROID_PRODUCT_OUT");
    -+    if (dir == nullptr || dir[0] == '\0') {
    -         die("neither -p product specified nor ANDROID_PRODUCT_OUT set");
    -     }
    - 
    -diff --git a/fs_mgr/fs_mgr.c b/fs_mgr/fs_mgr.c
    -index 6de8817..387f708 100644
    ---- a/fs_mgr/fs_mgr.c
    -+++ b/fs_mgr/fs_mgr.c
    -@@ -489,7 +489,7 @@ static int handle_encryptable(const struct fstab_rec* rec)
    -  * first successful mount.
    -  * Returns -1 on error, and  FS_MGR_MNTALL_* otherwise.
    -  */
    --int fs_mgr_mount_all(struct fstab *fstab)
    -+int fs_mgr_mount_all(struct fstab *fstab, int mount_mode)
    - {
    -     int i = 0;
    -     int encryptable = FS_MGR_MNTALL_DEV_NOT_ENCRYPTABLE;
    -@@ -503,8 +503,10 @@ int fs_mgr_mount_all(struct fstab *fstab)
    -     }
    - 
    -     for (i = 0; i < fstab->num_entries; i++) {
    --        /* Don't mount entries that are managed by vold */
    --        if (fstab->recs[i].fs_mgr_flags & (MF_VOLDMANAGED | MF_RECOVERYONLY)) {
    -+        /* Don't mount entries that are managed by vold or not for the mount mode*/
    -+        if ((fstab->recs[i].fs_mgr_flags & (MF_VOLDMANAGED | MF_RECOVERYONLY)) ||
    -+             ((mount_mode == MOUNT_MODE_LATE) && !fs_mgr_is_latemount(&fstab->recs[i])) ||
    -+             ((mount_mode == MOUNT_MODE_EARLY) && fs_mgr_is_latemount(&fstab->recs[i]))) {
    -             continue;
    -         }
    - 
    -diff --git a/fs_mgr/fs_mgr_fstab.c b/fs_mgr/fs_mgr_fstab.c
    -index 45adb34..21b4c74 100644
    ---- a/fs_mgr/fs_mgr_fstab.c
    -+++ b/fs_mgr/fs_mgr_fstab.c
    -@@ -78,6 +78,7 @@ static struct flag_list fs_mgr_flags[] = {
    -     { "formattable", MF_FORMATTABLE },
    -     { "slotselect",  MF_SLOTSELECT },
    -     { "nofail",      MF_NOFAIL },
    -+    { "latemount",   MF_LATEMOUNT },
    -     { "defaults",    0 },
    -     { 0,             0 },
    - };
    -@@ -545,3 +546,8 @@ int fs_mgr_is_nofail(struct fstab_rec *fstab)
    - {
    -     return fstab->fs_mgr_flags & MF_NOFAIL;
    - }
    -+
    -+int fs_mgr_is_latemount(struct fstab_rec *fstab)
    -+{
    -+    return fstab->fs_mgr_flags & MF_LATEMOUNT;
    -+}
    -diff --git a/fs_mgr/fs_mgr_main.c b/fs_mgr/fs_mgr_main.c
    -index e5a00d5..776c13e 100644
    ---- a/fs_mgr/fs_mgr_main.c
    -+++ b/fs_mgr/fs_mgr_main.c
    -@@ -96,7 +96,7 @@ int main(int argc, char *argv[])
    -     fstab = fs_mgr_read_fstab(fstab_file);
    - 
    -     if (a_flag) {
    --        return fs_mgr_mount_all(fstab);
    -+        return fs_mgr_mount_all(fstab, MOUNT_MODE_DEFAULT);
    -     } else if (n_flag) {
    -         return fs_mgr_do_mount(fstab, n_name, n_blk_dev, 0);
    -     } else if (u_flag) {
    -diff --git a/fs_mgr/fs_mgr_priv.h b/fs_mgr/fs_mgr_priv.h
    -index 46975f1..6d9492b 100644
    ---- a/fs_mgr/fs_mgr_priv.h
    -+++ b/fs_mgr/fs_mgr_priv.h
    -@@ -48,7 +48,7 @@ __BEGIN_DECLS
    -  *
    -  *   <fs_mgr_options> is a comma separated list of flags that control the operation of
    -  *                     the fs_mgr program.  The list includes "wait", which will wait till
    -- *                     the <source> file exists, and "check", which requests that the fs_mgr 
    -+ *                     the <source> file exists, and "check", which requests that the fs_mgr
    -  *                     run an fscheck program on the <source> before mounting the filesystem.
    -  *                     If check is specifed on a read-only filesystem, it is ignored.
    -  *                     Also, "encryptable" means that filesystem can be encrypted.
    -@@ -83,6 +83,7 @@ __BEGIN_DECLS
    - #define MF_FORMATTABLE  0x4000
    - #define MF_SLOTSELECT   0x8000
    - #define MF_FORCEFDEORFBE 0x10000
    -+#define MF_LATEMOUNT    0x20000
    - #define MF_NOFAIL       0x40000
    - 
    - #define DM_BUF_SIZE 4096
    -diff --git a/fs_mgr/include/fs_mgr.h b/fs_mgr/include/fs_mgr.h
    -index 46d8f97..7565965 100644
    ---- a/fs_mgr/include/fs_mgr.h
    -+++ b/fs_mgr/include/fs_mgr.h
    -@@ -40,6 +40,13 @@ enum verity_mode {
    -     VERITY_MODE_DEFAULT = VERITY_MODE_RESTART
    - };
    - 
    -+// Mount modes
    -+enum mount_mode {
    -+    MOUNT_MODE_DEFAULT = 0,
    -+    MOUNT_MODE_EARLY = 1,
    -+    MOUNT_MODE_LATE = 2
    -+};
    -+
    - /*
    -  * The entries must be kept in the same order as they were seen in the fstab.
    -  * Unless explicitly requested, a lookup on mount point should always
    -@@ -82,7 +89,7 @@ void fs_mgr_free_fstab(struct fstab *fstab);
    - #define FS_MGR_MNTALL_DEV_NOT_ENCRYPTED 1
    - #define FS_MGR_MNTALL_DEV_NOT_ENCRYPTABLE 0
    - #define FS_MGR_MNTALL_FAIL -1
    --int fs_mgr_mount_all(struct fstab *fstab);
    -+int fs_mgr_mount_all(struct fstab *fstab, int mount_mode);
    - 
    - #define FS_MGR_DOMNT_FAILED -1
    - #define FS_MGR_DOMNT_BUSY -2
    -@@ -110,6 +117,7 @@ int fs_mgr_is_noemulatedsd(const struct fstab_rec *fstab);
    - int fs_mgr_is_notrim(struct fstab_rec *fstab);
    - int fs_mgr_is_formattable(struct fstab_rec *fstab);
    - int fs_mgr_is_nofail(struct fstab_rec *fstab);
    -+int fs_mgr_is_latemount(struct fstab_rec *fstab);
    - int fs_mgr_swapon_all(struct fstab *fstab);
    - 
    - int fs_mgr_do_format(struct fstab_rec *fstab);
    -diff --git a/healthd/healthd.cpp b/healthd/healthd.cpp
    -index d9ac356..2caae78 100644
    ---- a/healthd/healthd.cpp
    -+++ b/healthd/healthd.cpp
    -@@ -136,10 +136,14 @@ static void healthd_mode_nop_battery_update(
    -     struct android::BatteryProperties* /*props*/) {
    - }
    - 
    --int healthd_register_event(int fd, void (*handler)(uint32_t)) {
    -+int healthd_register_event(int fd, void (*handler)(uint32_t), EventWakeup wakeup) {
    -     struct epoll_event ev;
    - 
    --    ev.events = EPOLLIN | EPOLLWAKEUP;
    -+    ev.events = EPOLLIN;
    -+
    -+    if (wakeup == EVENT_WAKEUP_FD)
    -+        ev.events |= EPOLLWAKEUP;
    -+
    -     ev.data.ptr = (void *)handler;
    -     if (epoll_ctl(epollfd, EPOLL_CTL_ADD, fd, &ev) == -1) {
    -         KLOG_ERROR(LOG_TAG,
    -@@ -245,7 +249,7 @@ static void uevent_init(void) {
    -     }
    - 
    -     fcntl(uevent_fd, F_SETFL, O_NONBLOCK);
    --    if (healthd_register_event(uevent_fd, uevent_event))
    -+    if (healthd_register_event(uevent_fd, uevent_event, EVENT_WAKEUP_FD))
    -         KLOG_ERROR(LOG_TAG,
    -                    "register for uevent events failed\n");
    - }
    -@@ -268,7 +272,7 @@ static void wakealarm_init(void) {
    -         return;
    -     }
    - 
    --    if (healthd_register_event(wakealarm_fd, wakealarm_event))
    -+    if (healthd_register_event(wakealarm_fd, wakealarm_event, EVENT_WAKEUP_FD))
    -         KLOG_ERROR(LOG_TAG,
    -                    "Registration of wakealarm event failed\n");
    - 
    -@@ -286,7 +290,6 @@ static void healthd_mainloop(void) {
    -         if (timeout < 0 || (mode_timeout > 0 && mode_timeout < timeout))
    -             timeout = mode_timeout;
    -         nevents = epoll_wait(epollfd, events, eventct, timeout);
    --
    -         if (nevents == -1) {
    -             if (errno == EINTR)
    -                 continue;
    -diff --git a/healthd/healthd_mode_charger.cpp b/healthd/healthd_mode_charger.cpp
    -index 5846626..a6da704 100644
    ---- a/healthd/healthd_mode_charger.cpp
    -+++ b/healthd/healthd_mode_charger.cpp
    -@@ -686,7 +686,7 @@ void healthd_mode_charger_init(struct healthd_config* config)
    -     ret = ev_init(input_callback, charger);
    -     if (!ret) {
    -         epollfd = ev_get_epollfd();
    --        healthd_register_event(epollfd, charger_event_handler);
    -+        healthd_register_event(epollfd, charger_event_handler, EVENT_WAKEUP_FD);
    -     }
    - 
    -     ret = res_create_display_surface("charger/battery_fail", &charger->surf_unknown);
    -diff --git a/healthd/include/healthd/healthd.h b/healthd/include/healthd/healthd.h
    -index 34ea55f..17efbd6 100644
    ---- a/healthd/include/healthd/healthd.h
    -+++ b/healthd/include/healthd/healthd.h
    -@@ -73,9 +73,14 @@ struct healthd_config {
    -     bool (*screen_on)(android::BatteryProperties *props);
    - };
    - 
    -+enum EventWakeup {
    -+    EVENT_NO_WAKEUP_FD,
    -+    EVENT_WAKEUP_FD,
    -+};
    -+
    - // Global helper functions
    - 
    --int healthd_register_event(int fd, void (*handler)(uint32_t));
    -+int healthd_register_event(int fd, void (*handler)(uint32_t), EventWakeup wakeup = EVENT_NO_WAKEUP_FD);
    - void healthd_battery_update();
    - android::status_t healthd_get_property(int id,
    -     struct android::BatteryProperty *val);
    -diff --git a/include/backtrace/BacktraceMap.h b/include/backtrace/BacktraceMap.h
    -index 2373c45..b80045f 100644
    ---- a/include/backtrace/BacktraceMap.h
    -+++ b/include/backtrace/BacktraceMap.h
    -@@ -71,6 +71,12 @@ public:
    -   bool IsWritable(uintptr_t pc) { return GetFlags(pc) & PROT_WRITE; }
    -   bool IsExecutable(uintptr_t pc) { return GetFlags(pc) & PROT_EXEC; }
    - 
    -+  // In order to use the iterators on this object, a caller must
    -+  // call the LockIterator and UnlockIterator function to guarantee
    -+  // that the data does not change while it's being used.
    -+  virtual void LockIterator() {}
    -+  virtual void UnlockIterator() {}
    -+
    -   typedef std::deque<backtrace_map_t>::iterator iterator;
    -   iterator begin() { return maps_.begin(); }
    -   iterator end() { return maps_.end(); }
    -@@ -102,4 +108,18 @@ protected:
    -   pid_t pid_;
    - };
    - 
    -+class ScopedBacktraceMapIteratorLock {
    -+public:
    -+  explicit ScopedBacktraceMapIteratorLock(BacktraceMap* map) : map_(map) {
    -+    map->LockIterator();
    -+  }
    -+
    -+  ~ScopedBacktraceMapIteratorLock() {
    -+    map_->UnlockIterator();
    -+  }
    -+
    -+private:
    -+  BacktraceMap* map_;
    -+};
    -+
    - #endif // _BACKTRACE_BACKTRACE_MAP_H
    -diff --git a/include/cutils/trace.h b/include/cutils/trace.h
    -index c9790ad..19313af 100644
    ---- a/include/cutils/trace.h
    -+++ b/include/cutils/trace.h
    -@@ -70,7 +70,8 @@ __BEGIN_DECLS
    - #define ATRACE_TAG_PACKAGE_MANAGER  (1<<18)
    - #define ATRACE_TAG_SYSTEM_SERVER    (1<<19)
    - #define ATRACE_TAG_DATABASE         (1<<20)
    --#define ATRACE_TAG_LAST             ATRACE_TAG_DATABASE
    -+#define ATRACE_TAG_NETWORK          (1<<21)
    -+#define ATRACE_TAG_LAST             ATRACE_TAG_NETWORK
    - 
    - // Reserved for initialization.
    - #define ATRACE_TAG_NOT_READY        (1ULL<<63)
     diff --git a/include/system/camera.h b/include/system/camera.h
     index 5d0873a..e4c0a47 100644
     --- a/include/system/camera.h
    @@ -689,167 +112,6 @@ index 67541b8..ff343e9 100644
      
      init_cflags += \
          $(init_options) \
    -diff --git a/init/builtins.cpp b/init/builtins.cpp
    -index 70f9194..44217f0 100644
    ---- a/init/builtins.cpp
    -+++ b/init/builtins.cpp
    -@@ -479,9 +479,9 @@ exit_success:
    -  *
    -  * start_index: index of the first path in the args list
    -  */
    --static void import_late(const std::vector<std::string>& args, size_t start_index) {
    -+static void import_late(const std::vector<std::string>& args, size_t start_index, size_t end_index) {
    -     Parser& parser = Parser::GetInstance();
    --    if (args.size() <= start_index) {
    -+    if (end_index <= start_index) {
    -         // Use the default set if no path is given
    -         static const std::vector<std::string> init_directories = {
    -             "/system/etc/init",
    -@@ -493,25 +493,23 @@ static void import_late(const std::vector<std::string>& args, size_t start_index
    -             parser.ParseConfig(dir);
    -         }
    -     } else {
    --        for (size_t i = start_index; i < args.size(); ++i) {
    -+        for (size_t i = start_index; i < end_index; ++i) {
    -             parser.ParseConfig(args[i]);
    -         }
    -     }
    - }
    - 
    --/* mount_all <fstab> [ <path> ]*
    -+/* mount_fstab
    -  *
    -- * This function might request a reboot, in which case it will
    -- * not return.
    -+ *  Call fs_mgr_mount_all() to mount the given fstab
    -  */
    --static int do_mount_all(const std::vector<std::string>& args) {
    -+static int mount_fstab(const char* fstabfile, int mount_mode) {
    -     pid_t pid;
    -     int ret = -1;
    -     int child_ret = -1;
    -     int status;
    -     struct fstab *fstab;
    - 
    --    const char* fstabfile = args[1].c_str();
    -     /*
    -      * Call fs_mgr_mount_all() to mount all filesystems.  We fork(2) and
    -      * do the call in the child to provide protection to the main init
    -@@ -536,7 +534,7 @@ static int do_mount_all(const std::vector<std::string>& args) {
    -         /* child, call fs_mgr_mount_all() */
    -         klog_set_level(6);  /* So we can see what fs_mgr_mount_all() does */
    -         fstab = fs_mgr_read_fstab(fstabfile);
    --        child_ret = fs_mgr_mount_all(fstab);
    -+        child_ret = fs_mgr_mount_all(fstab, mount_mode);
    -         fs_mgr_free_fstab(fstab);
    -         if (child_ret == -1) {
    -             ERROR("fs_mgr_mount_all returned an error\n");
    -@@ -546,28 +544,38 @@ static int do_mount_all(const std::vector<std::string>& args) {
    -         /* fork failed, return an error */
    -         return -1;
    -     }
    -+    return ret;
    -+}
    - 
    --    /* Paths of .rc files are specified at the 2nd argument and beyond */
    --    import_late(args, 2);
    --
    --    if (ret == FS_MGR_MNTALL_DEV_NEEDS_ENCRYPTION) {
    -+/* Queue event based on fs_mgr return code.
    -+ *
    -+ * code: return code of fs_mgr_mount_all
    -+ *
    -+ * This function might request a reboot, in which case it will
    -+ * not return.
    -+ *
    -+ * return code is processed based on input code
    -+ */
    -+static int queue_fs_event(int code) {
    -+    int ret = code;
    -+    if (code == FS_MGR_MNTALL_DEV_NEEDS_ENCRYPTION) {
    -         ActionManager::GetInstance().QueueEventTrigger("encrypt");
    --    } else if (ret == FS_MGR_MNTALL_DEV_MIGHT_BE_ENCRYPTED) {
    -+    } else if (code == FS_MGR_MNTALL_DEV_MIGHT_BE_ENCRYPTED) {
    -         property_set("ro.crypto.state", "encrypted");
    -         property_set("ro.crypto.type", "block");
    -         ActionManager::GetInstance().QueueEventTrigger("defaultcrypto");
    --    } else if (ret == FS_MGR_MNTALL_DEV_NOT_ENCRYPTED) {
    -+    } else if (code == FS_MGR_MNTALL_DEV_NOT_ENCRYPTED) {
    -         property_set("ro.crypto.state", "unencrypted");
    -         ActionManager::GetInstance().QueueEventTrigger("nonencrypted");
    --    } else if (ret == FS_MGR_MNTALL_DEV_NOT_ENCRYPTABLE) {
    -+    } else if (code == FS_MGR_MNTALL_DEV_NOT_ENCRYPTABLE) {
    -         property_set("ro.crypto.state", "unsupported");
    -         ActionManager::GetInstance().QueueEventTrigger("nonencrypted");
    --    } else if (ret == FS_MGR_MNTALL_DEV_NEEDS_RECOVERY) {
    -+    } else if (code == FS_MGR_MNTALL_DEV_NEEDS_RECOVERY) {
    -         /* Setup a wipe via recovery, and reboot into recovery */
    -         ERROR("fs_mgr_mount_all suggested recovery, so wiping data via recovery.\n");
    -         ret = wipe_data_via_recovery("wipe_data_via_recovery");
    -         /* If reboot worked, there is no return. */
    --    } else if (ret == FS_MGR_MNTALL_DEV_FILE_ENCRYPTED) {
    -+    } else if (code == FS_MGR_MNTALL_DEV_FILE_ENCRYPTED) {
    -         if (e4crypt_install_keyring()) {
    -             return -1;
    -         }
    -@@ -577,14 +585,55 @@ static int do_mount_all(const std::vector<std::string>& args) {
    -         // Although encrypted, we have device key, so we do not need to
    -         // do anything different from the nonencrypted case.
    -         ActionManager::GetInstance().QueueEventTrigger("nonencrypted");
    --    } else if (ret > 0) {
    --        ERROR("fs_mgr_mount_all returned unexpected error %d\n", ret);
    -+    } else if (code > 0) {
    -+        ERROR("fs_mgr_mount_all returned unexpected error %d\n", code);
    -     }
    -     /* else ... < 0: error */
    - 
    -     return ret;
    - }
    - 
    -+/* mount_all <fstab> [ <path> ]* [--<options>]*
    -+ *
    -+ * This function might request a reboot, in which case it will
    -+ * not return.
    -+ */
    -+static int do_mount_all(const std::vector<std::string>& args) {
    -+    std::size_t na = 0;
    -+    bool import_rc = true;
    -+    bool queue_event = true;
    -+    int mount_mode = MOUNT_MODE_DEFAULT;
    -+    const char* fstabfile = args[1].c_str();
    -+    std::size_t path_arg_end = args.size();
    -+
    -+    for (na = args.size() - 1; na > 1; --na) {
    -+        if (args[na] == "--early") {
    -+             path_arg_end = na;
    -+             queue_event = false;
    -+             mount_mode = MOUNT_MODE_EARLY;
    -+        } else if (args[na] == "--late") {
    -+            path_arg_end = na;
    -+            import_rc = false;
    -+            mount_mode = MOUNT_MODE_LATE;
    -+        }
    -+    }
    -+
    -+    int ret =  mount_fstab(fstabfile, mount_mode);
    -+
    -+    if (import_rc) {
    -+        /* Paths of .rc files are specified at the 2nd argument and beyond */
    -+        import_late(args, 2, path_arg_end);
    -+    }
    -+
    -+    if (queue_event) {
    -+        /* queue_fs_event will queue event based on mount_fstab return code
    -+         * and return processed return code*/
    -+        ret = queue_fs_event(ret);
    -+    }
    -+
    -+    return ret;
    -+}
    -+
    - static int do_swapon_all(const std::vector<std::string>& args) {
    -     struct fstab *fstab;
    -     int ret;
     diff --git a/init/init.cpp b/init/init.cpp
     index 84da2b9..dc3be38 100644
     --- a/init/init.cpp
    @@ -919,433 +181,11 @@ index 84da2b9..dc3be38 100644
          am.QueueBuiltinAction(keychord_init_action, "keychord_init");
          am.QueueBuiltinAction(console_init_action, "console_init");
      
    -diff --git a/init/init_parser.cpp b/init/init_parser.cpp
    -index b44ca59..f2e5d6d 100644
    ---- a/init/init_parser.cpp
    -+++ b/init/init_parser.cpp
    -@@ -122,14 +122,20 @@ bool Parser::ParseConfigDir(const std::string& path) {
    -         return false;
    -     }
    -     dirent* current_file;
    -+    std::vector<std::string> files;
    -     while ((current_file = readdir(config_dir.get()))) {
    --        std::string current_path =
    --            android::base::StringPrintf("%s/%s", path.c_str(), current_file->d_name);
    -         // Ignore directories and only process regular files.
    -         if (current_file->d_type == DT_REG) {
    --            if (!ParseConfigFile(current_path)) {
    --                ERROR("could not import file '%s'\n", current_path.c_str());
    --            }
    -+            std::string current_path =
    -+                android::base::StringPrintf("%s/%s", path.c_str(), current_file->d_name);
    -+            files.emplace_back(current_path);
    -+        }
    -+    }
    -+    // Sort first so we load files in a consistent order (bug 31996208)
    -+    std::sort(files.begin(), files.end());
    -+    for (const auto& file : files) {
    -+        if (!ParseConfigFile(file)) {
    -+            ERROR("Could not import file '%s'\n", file.c_str());
    -         }
    -     }
    -     return true;
    -diff --git a/init/readme.txt b/init/readme.txt
    -index 4481e24..dad7e06 100644
    ---- a/init/readme.txt
    -+++ b/init/readme.txt
    -@@ -1,4 +1,3 @@
    --
    - Android Init Language
    - ---------------------
    - 
    -@@ -78,6 +77,14 @@ monolithic init .rc files.  This additionally will aid in merge
    - conflict resolution when multiple services are added to the system, as
    - each one will go into a separate file.
    - 
    -+There are two options "early" and "late" in mount_all command
    -+which can be set after optional paths. With "--early" set, the
    -+init executable will skip mounting entries with "latemount" flag
    -+and triggering fs encryption state event. With "--late" set,
    -+init executable will only mount entries with "latemount" flag but skip
    -+importing rc files. By default, no option is set, and mount_all will
    -+mount_all will process all entries in the given fstab.
    -+
    - Actions
    - -------
    - Actions are named sequences of commands.  Actions have a trigger which
    -@@ -291,10 +298,11 @@ mkdir <path> [mode] [owner] [group]
    -    owned by the root user and root group. If provided, the mode, owner and group
    -    will be updated if the directory exists already.
    - 
    --mount_all <fstab> [ <path> ]*
    -+mount_all <fstab> [ <path> ]* [--<option>]
    -    Calls fs_mgr_mount_all on the given fs_mgr-format fstab and imports .rc files
    --   at the specified paths (e.g., on the partitions just mounted). Refer to the
    --   section of "Init .rc Files" for detail.
    -+   at the specified paths (e.g., on the partitions just mounted) with optional
    -+   options "early" and "late".
    -+   Refer to the section of "Init .rc Files" for detail.
    - 
    - mount <type> <device> <dir> [ <flag> ]* [<options>]
    -    Attempt to mount the named device at the directory <dir>
    -diff --git a/libbacktrace/BacktraceMap.cpp b/libbacktrace/BacktraceMap.cpp
    -index ba86632..85f2436 100644
    ---- a/libbacktrace/BacktraceMap.cpp
    -+++ b/libbacktrace/BacktraceMap.cpp
    -@@ -35,8 +35,8 @@ BacktraceMap::~BacktraceMap() {
    - }
    - 
    - void BacktraceMap::FillIn(uintptr_t addr, backtrace_map_t* map) {
    --  for (BacktraceMap::const_iterator it = begin();
    --       it != end(); ++it) {
    -+  ScopedBacktraceMapIteratorLock lock(this);
    -+  for (BacktraceMap::const_iterator it = begin(); it != end(); ++it) {
    -     if (addr >= it->start && addr < it->end) {
    -       *map = *it;
    -       return;
    -diff --git a/libbacktrace/UnwindMap.cpp b/libbacktrace/UnwindMap.cpp
    -index 34d79f9..af79562 100644
    ---- a/libbacktrace/UnwindMap.cpp
    -+++ b/libbacktrace/UnwindMap.cpp
    -@@ -14,6 +14,7 @@
    -  * limitations under the License.
    -  */
    - 
    -+#include <pthread.h>
    - #include <stdint.h>
    - #include <stdlib.h>
    - #include <sys/types.h>
    -@@ -72,6 +73,7 @@ bool UnwindMapRemote::Build() {
    - }
    - 
    - UnwindMapLocal::UnwindMapLocal() : UnwindMap(getpid()), map_created_(false) {
    -+  pthread_rwlock_init(&map_lock_, nullptr);
    - }
    - 
    - UnwindMapLocal::~UnwindMapLocal() {
    -@@ -82,9 +84,14 @@ UnwindMapLocal::~UnwindMapLocal() {
    - }
    - 
    - bool UnwindMapLocal::GenerateMap() {
    -+  // Lock so that multiple threads cannot modify the maps data at the
    -+  // same time.
    -+  pthread_rwlock_wrlock(&map_lock_);
    -+
    -   // It's possible for the map to be regenerated while this loop is occurring.
    -   // If that happens, get the map again, but only try at most three times
    -   // before giving up.
    -+  bool generated = false;
    -   for (int i = 0; i < 3; i++) {
    -     maps_.clear();
    - 
    -@@ -110,12 +117,17 @@ bool UnwindMapLocal::GenerateMap() {
    -     }
    -     // Check to see if the map changed while getting the data.
    -     if (ret != -UNW_EINVAL) {
    --      return true;
    -+      generated = true;
    -+      break;
    -     }
    -   }
    - 
    --  BACK_LOGW("Unable to generate the map.");
    --  return false;
    -+  pthread_rwlock_unlock(&map_lock_);
    -+
    -+  if (!generated) {
    -+    BACK_LOGW("Unable to generate the map.");
    -+  }
    -+  return generated;
    - }
    - 
    - bool UnwindMapLocal::Build() {
    -diff --git a/libbacktrace/UnwindMap.h b/libbacktrace/UnwindMap.h
    -index 111401f..f85b54a 100644
    ---- a/libbacktrace/UnwindMap.h
    -+++ b/libbacktrace/UnwindMap.h
    -@@ -17,6 +17,7 @@
    - #ifndef _LIBBACKTRACE_UNWIND_MAP_H
    - #define _LIBBACKTRACE_UNWIND_MAP_H
    - 
    -+#include <pthread.h>
    - #include <stdint.h>
    - #include <sys/types.h>
    - 
    -@@ -56,10 +57,15 @@ public:
    - 
    -   void FillIn(uintptr_t addr, backtrace_map_t* map) override;
    - 
    -+  void LockIterator() override { pthread_rwlock_rdlock(&map_lock_); }
    -+  void UnlockIterator() override { pthread_rwlock_unlock(&map_lock_); }
    -+
    - private:
    -   bool GenerateMap();
    - 
    -   bool map_created_;
    -+
    -+  pthread_rwlock_t map_lock_;
    - };
    - 
    - #endif // _LIBBACKTRACE_UNWIND_MAP_H
    -diff --git a/libbacktrace/backtrace_test.cpp b/libbacktrace/backtrace_test.cpp
    -index f6b2591..913e12d 100644
    ---- a/libbacktrace/backtrace_test.cpp
    -+++ b/libbacktrace/backtrace_test.cpp
    -@@ -896,6 +896,7 @@ void VerifyMap(pid_t pid) {
    -   std::unique_ptr<BacktraceMap> map(BacktraceMap::Create(pid));
    - 
    -   // Basic test that verifies that the map is in the expected order.
    -+  ScopedBacktraceMapIteratorLock lock(map.get());
    -   std::vector<map_test_t>::const_iterator test_it = test_maps.begin();
    -   for (BacktraceMap::const_iterator it = map->begin(); it != map->end(); ++it) {
    -     ASSERT_TRUE(test_it != test_maps.end());
    -diff --git a/liblog/event_tag_map.c b/liblog/event_tag_map.c
    -index 3cb04cf..345f0d3 100644
    ---- a/liblog/event_tag_map.c
    -+++ b/liblog/event_tag_map.c
    -@@ -99,6 +99,9 @@ LIBLOG_ABI_PUBLIC EventTagMap* android_openEventTagMap(const char* fileName)
    -     if (processFile(newTagMap) != 0)
    -         goto fail;
    - 
    -+    if (fd >= 0)
    -+      close(fd);
    -+
    -     return newTagMap;
    - 
    - fail:
    -diff --git a/liblog/pmsg_writer.c b/liblog/pmsg_writer.c
    -index b338dca..944feba 100644
    ---- a/liblog/pmsg_writer.c
    -+++ b/liblog/pmsg_writer.c
    -@@ -31,8 +31,6 @@
    - #include <private/android_filesystem_config.h>
    - #include <private/android_logger.h>
    - 
    --#include <sys/system_properties.h>
    --
    - #include "config_write.h"
    - #include "log_portability.h"
    - #include "logger.h"
    -@@ -53,25 +51,8 @@ LIBLOG_HIDDEN struct android_log_transport_write pmsgLoggerWrite = {
    -     .write = pmsgWrite,
    - };
    - 
    --static bool pmsgShouldUse = false;
    --
    --// Only use pmsg on eng builds
    --static bool pmsgIsEng() {
    --    char buf[PROP_VALUE_MAX];
    --
    --    if (__system_property_get("ro.build.type", buf) == 0) {
    --        return false;
    --    }
    --
    --    if (!strncmp(buf, "eng", sizeof("eng"))) {
    --        return true;
    --    }
    --    return false;
    --}
    --
    - static int pmsgOpen()
    - {
    --    pmsgShouldUse = pmsgIsEng();
    -     if (pmsgLoggerWrite.context.fd < 0) {
    -         pmsgLoggerWrite.context.fd = TEMP_FAILURE_RETRY(open("/dev/pmsg0", O_WRONLY | O_CLOEXEC));
    -     }
    -@@ -94,7 +75,7 @@ static int pmsgAvailable(log_id_t logId)
    -     }
    -     if ((logId != LOG_ID_SECURITY) &&
    -             (logId != LOG_ID_EVENTS) &&
    --            (!pmsgShouldUse || !__android_log_is_debuggable())) {
    -+            !__android_log_is_debuggable()) {
    -         return -EINVAL;
    -     }
    -     if (pmsgLoggerWrite.context.fd < 0) {
    -@@ -124,7 +105,7 @@ static int pmsgWrite(log_id_t logId, struct timespec *ts,
    -     size_t i, payloadSize;
    -     ssize_t ret;
    - 
    --    if ((logId == LOG_ID_EVENTS) && (!pmsgShouldUse || !__android_log_is_debuggable())) {
    -+    if ((logId == LOG_ID_EVENTS) && !__android_log_is_debuggable()) {
    -         if (vec[0].iov_len < 4) {
    -             return -EINVAL;
    -         }
    -diff --git a/libutils/RefBase.cpp b/libutils/RefBase.cpp
    -index f90e28b..4ead19c 100644
    ---- a/libutils/RefBase.cpp
    -+++ b/libutils/RefBase.cpp
    -@@ -575,15 +575,14 @@ bool RefBase::weakref_type::attemptIncStrong(const void* id)
    -             // grab a strong-reference, which is always safe due to the
    -             // extended life-time.
    -             curCount = impl->mStrong.fetch_add(1, std::memory_order_relaxed);
    --        }
    --
    --        // If the strong reference count has already been incremented by
    --        // someone else, the implementor of onIncStrongAttempted() is holding
    --        // an unneeded reference.  So call onLastStrongRef() here to remove it.
    --        // (No, this is not pretty.)  Note that we MUST NOT do this if we
    --        // are in fact acquiring the first reference.
    --        if (curCount > 0 && curCount < INITIAL_STRONG_VALUE) {
    --            impl->mBase->onLastStrongRef(id);
    -+            // If the strong reference count has already been incremented by
    -+            // someone else, the implementor of onIncStrongAttempted() is holding
    -+            // an unneeded reference.  So call onLastStrongRef() here to remove it.
    -+            // (No, this is not pretty.)  Note that we MUST NOT do this if we
    -+            // are in fact acquiring the first reference.
    -+            if (curCount != 0 && curCount != INITIAL_STRONG_VALUE) {
    -+                impl->mBase->onLastStrongRef(id);
    -+            }
    -         }
    -     }
    -     
    -@@ -593,7 +592,7 @@ bool RefBase::weakref_type::attemptIncStrong(const void* id)
    -     ALOGD("attemptIncStrong of %p from %p: cnt=%d\n", this, id, curCount);
    - #endif
    - 
    --    // curCount is the value of mStrong before we increment ed it.
    -+    // curCount is the value of mStrong before we incremented it.
    -     // Now we need to fix-up the count if it was INITIAL_STRONG_VALUE.
    -     // This must be done safely, i.e.: handle the case where several threads
    -     // were here in attemptIncStrong().
    -diff --git a/libziparchive/zip_archive.cc b/libziparchive/zip_archive.cc
    -index 1f27500..986ee72 100644
    ---- a/libziparchive/zip_archive.cc
    -+++ b/libziparchive/zip_archive.cc
    -@@ -269,9 +269,14 @@ static int32_t MapCentralDirectory0(int fd, const char* debug_file_name,
    -    * Grab the CD offset and size, and the number of entries in the
    -    * archive and verify that they look reasonable.
    -    */
    --  if (eocd->cd_start_offset + eocd->cd_size > eocd_offset) {
    -+  if (static_cast<off64_t>(eocd->cd_start_offset) + eocd->cd_size > eocd_offset) {
    -     ALOGW("Zip: bad offsets (dir %" PRIu32 ", size %" PRIu32 ", eocd %" PRId64 ")",
    -         eocd->cd_start_offset, eocd->cd_size, static_cast<int64_t>(eocd_offset));
    -+#if defined(__ANDROID__)
    -+    if (eocd->cd_start_offset + eocd->cd_size <= eocd_offset) {
    -+      android_errorWriteLog(0x534e4554, "31251826");
    -+    }
    -+#endif
    -     return kInvalidOffset;
    -   }
    -   if (eocd->num_records == 0) {
    -diff --git a/logd/LogBuffer.cpp b/logd/LogBuffer.cpp
    -index 8c30f79..0497a89 100644
    ---- a/logd/LogBuffer.cpp
    -+++ b/logd/LogBuffer.cpp
    -@@ -313,6 +313,9 @@ LogBufferElementCollection::iterator LogBuffer::erase(
    -     LogBufferElement *element = *it;
    -     log_id_t id = element->getLogId();
    - 
    -+    // Remove iterator references in the various lists that will become stale
    -+    // after the element is erased from the main logging list.
    -+
    -     {   // start of scope for uid found iterator
    -         LogBufferIteratorMap::iterator found =
    -             mLastWorstUid[id].find(element->getUid());
    -@@ -322,8 +325,8 @@ LogBufferElementCollection::iterator LogBuffer::erase(
    -         }
    -     }
    - 
    --    if (element->getUid() == AID_SYSTEM) {
    --        // start of scope for pid found iterator
    -+    {   // start of scope for pid found iterator
    -+        // element->getUid() may not be AID_SYSTEM for next-best-watermark.
    -         LogBufferPidIteratorMap::iterator found =
    -             mLastWorstPidOfSystem[id].find(element->getPid());
    -         if ((found != mLastWorstPidOfSystem[id].end())
    -@@ -639,6 +642,7 @@ bool LogBuffer::prune(log_id_t id, unsigned long pruneRows, uid_t caller_uid) {
    -                 ++it;
    -                 continue;
    -             }
    -+            // below this point element->getLogId() == id
    - 
    -             if (leading && (!mLastSet[id] || ((*mLast[id])->getLogId() != id))) {
    -                 mLast[id] = it;
    -@@ -691,7 +695,9 @@ bool LogBuffer::prune(log_id_t id, unsigned long pruneRows, uid_t caller_uid) {
    -                         && ((!gc && (element->getPid() == worstPid))
    -                             || (mLastWorstPidOfSystem[id].find(element->getPid())
    -                                 == mLastWorstPidOfSystem[id].end()))) {
    --                    mLastWorstPidOfSystem[id][element->getUid()] = it;
    -+                    // element->getUid() may not be AID_SYSTEM, next best
    -+                    // watermark if current one empty.
    -+                    mLastWorstPidOfSystem[id][element->getPid()] = it;
    -                 }
    -                 if ((!gc && !worstPid && (element->getUid() == worst))
    -                         || (mLastWorstUid[id].find(element->getUid())
    -@@ -709,6 +715,8 @@ bool LogBuffer::prune(log_id_t id, unsigned long pruneRows, uid_t caller_uid) {
    -                 ++it;
    -                 continue;
    -             }
    -+            // key == worst below here
    -+            // If worstPid set, then element->getPid() == worstPid below here
    - 
    -             pruneRows--;
    -             if (pruneRows == 0) {
    -@@ -732,6 +740,8 @@ bool LogBuffer::prune(log_id_t id, unsigned long pruneRows, uid_t caller_uid) {
    -                     if (worstPid && (!gc
    -                                 || (mLastWorstPidOfSystem[id].find(worstPid)
    -                                     == mLastWorstPidOfSystem[id].end()))) {
    -+                        // element->getUid() may not be AID_SYSTEM, next best
    -+                        // watermark if current one empty.
    -                         mLastWorstPidOfSystem[id][worstPid] = it;
    -                     }
    -                     if ((!gc && !worstPid) || (mLastWorstUid[id].find(worst)
     diff --git a/rootdir/init.rc b/rootdir/init.rc
    -index 56379db..7a5c9b3 100644
    +index a9b6af0..7a5c9b3 100644
     --- a/rootdir/init.rc
     +++ b/rootdir/init.rc
    -@@ -236,6 +236,9 @@ on init
    - 
    -     export DOWNLOAD_CACHE /data/cache
    - 
    -+    # set RLIMIT_NICE to allow priorities from 19 to -20
    -+    setrlimit 13 40 40
    -+
    - # Healthd can trigger a full boot from charger mode by signaling this
    - # property when the power button is held.
    - on property:sys.boot_from_charger_mode=1
    -@@ -258,6 +261,11 @@ on firmware_mounts_complete
    - # Mount filesystems and start core system services.
    - on late-init
    -     trigger early-fs
    -+
    -+    # Mount fstab in init.{$device}.rc by mount_all command. Optional parameter
    -+    # '--early' can be specified to skip entries with 'latemount'.
    -+    # /system and /vendor must be mounted by the end of the fs stage,
    -+    # while /data is optional.
    -     trigger fs
    -     trigger post-fs
    - 
    -@@ -266,9 +274,18 @@ on late-init
    -     # issued fs triggers have completed.
    -     trigger load_system_props_action
    - 
    -+    # Mount fstab in init.{$device}.rc by mount_all with '--late' parameter
    -+    # to only mount entries with 'latemount'. This is needed if '--early' is
    -+    # specified in the previous mount_all command on the fs stage.
    -+    # With /system mounted and properties form /system + /factory available,
    -+    # some services can be started.
    -+    trigger late-fs
    -+
    -     # Now we can mount /data. File encryption requires keymaster to decrypt
    --    # /data, which in turn can only be loaded when system properties are present
    -+    # /data, which in turn can only be loaded when system properties are present.
    -     trigger post-fs-data
    -+
    -+    # Load persist properties and override properties (if enabled) from /data.
    -     trigger load_persist_props_action
    - 
    -     # Remove a file to wake up anything waiting for firmware.
    -@@ -484,9 +501,6 @@ on boot
    -     hostname localhost
    -     domainname localdomain
    - 
    --    # set RLIMIT_NICE to allow priorities from 19 to -20
    --    setrlimit 13 40 40
    --
    -     # Memory management.  Basic kernel parameters, and allow the high
    -     # level system server to be able to adjust the kernel OOM driver
    -     # parameters to match how it is managing things.
    -@@ -654,6 +668,6 @@ on property:ro.debuggable=1
    +@@ -668,6 +668,6 @@ on property:ro.debuggable=1
          chmod 0773 /data/misc/trace
          start console
      
    @@ -1355,47 +195,3 @@ index 56379db..7a5c9b3 100644
     +#service flash_recovery /system/bin/install-recovery.sh
     +#    class main
     +#    oneshot
    -diff --git a/sdcard/sdcard.c b/sdcard/sdcard.c
    -index 9480e4a..13ebaf1 100644
    ---- a/sdcard/sdcard.c
    -+++ b/sdcard/sdcard.c
    -@@ -1221,7 +1221,13 @@ static int handle_open(struct fuse* fuse, struct fuse_handler* handler,
    -     }
    -     out.fh = ptr_to_id(h);
    -     out.open_flags = 0;
    -+
    -+#ifdef FUSE_SHORTCIRCUIT
    -+    out.lower_fd = h->fd;
    -+#else
    -     out.padding = 0;
    -+#endif
    -+
    -     fuse_reply(fuse, hdr->unique, &out, sizeof(out));
    -     return NO_STATUS;
    - }
    -@@ -1385,7 +1391,13 @@ static int handle_opendir(struct fuse* fuse, struct fuse_handler* handler,
    -     }
    -     out.fh = ptr_to_id(h);
    -     out.open_flags = 0;
    -+
    -+#ifdef FUSE_SHORTCIRCUIT
    -+    out.lower_fd = -1;
    -+#else
    -     out.padding = 0;
    -+#endif
    -+
    -     fuse_reply(fuse, hdr->unique, &out, sizeof(out));
    -     return NO_STATUS;
    - }
    -@@ -1467,6 +1479,11 @@ static int handle_init(struct fuse* fuse, struct fuse_handler* handler,
    -     out.major = FUSE_KERNEL_VERSION;
    -     out.max_readahead = req->max_readahead;
    -     out.flags = FUSE_ATOMIC_O_TRUNC | FUSE_BIG_WRITES;
    -+
    -+#ifdef FUSE_SHORTCIRCUIT
    -+    out.flags |= FUSE_SHORTCIRCUIT;
    -+#endif
    -+
    -     out.max_background = 32;
    -     out.congestion_threshold = 32;
    -     out.max_write = MAX_WRITE;
    diff --git a/system_sepolicy.patch b/system_sepolicy.patch
    index f35473d..1c95f0f 100644
    --- a/system_sepolicy.patch
    +++ b/system_sepolicy.patch
    @@ -11,18 +11,6 @@ index e9dd7b3..ef2bd9d 100644
      neverallow { appdomain -bluetooth } self:capability2 *;
      
      # Block device access.
    -diff --git a/bootanim.te b/bootanim.te
    -index e18654c..c3091ab 100644
    ---- a/bootanim.te
    -+++ b/bootanim.te
    -@@ -19,6 +19,7 @@ allow bootanim audio_device:chr_file rw_file_perms;
    - 
    - allow bootanim audioserver_service:service_manager find;
    - allow bootanim surfaceflinger_service:service_manager find;
    -+allow bootanim audioserver_service:service_manager find;
    - 
    - # Allow access to ion memory allocation device
    - allow bootanim ion_device:chr_file rw_file_perms;
     diff --git a/domain.te b/domain.te
     index 45569de..21c9df2 100644
     --- a/domain.te
    @@ -110,28 +98,6 @@ index 45569de..21c9df2 100644
      
      neverallow {
        domain
    -diff --git a/dumpstate.te b/dumpstate.te
    -index dda8a58..115bb09 100644
    ---- a/dumpstate.te
    -+++ b/dumpstate.te
    -@@ -5,6 +5,7 @@ type dumpstate_exec, exec_type, file_type;
    - init_daemon_domain(dumpstate)
    - net_domain(dumpstate)
    - binder_use(dumpstate)
    -+wakelock_use(dumpstate)
    - 
    - # Allow setting process priority, protect from OOM killer, and dropping
    - # privileges by switching UID / GID
    -@@ -136,6 +137,9 @@ control_logd(dumpstate)
    - allow dumpstate net_data_file:dir search;
    - allow dumpstate net_data_file:file r_file_perms;
    - 
    -+# List sockets via ss.
    -+allow dumpstate self:netlink_tcpdiag_socket { create_socket_perms nlmsg_read };
    -+
    - # Access /data/tombstones.
    - allow dumpstate tombstone_data_file:dir r_dir_perms;
    - allow dumpstate tombstone_data_file:file r_file_perms;
     diff --git a/file.te b/file.te
     index 84af4a7..55910d2 100644
     --- a/file.te
    @@ -145,31 +111,6 @@ index 84af4a7..55910d2 100644
      type fuse, sdcard_type, fs_type, mlstrustedobject;
      type sdcardfs, sdcard_type, fs_type, mlstrustedobject;
      type vfat, sdcard_type, fs_type, mlstrustedobject;
    -diff --git a/otapreopt_chroot.te b/otapreopt_chroot.te
    -index fcba7b1..1c5f2ee 100644
    ---- a/otapreopt_chroot.te
    -+++ b/otapreopt_chroot.te
    -@@ -10,6 +10,8 @@ allow otapreopt_chroot self:capability { sys_admin sys_chroot };
    - # This is required to mount /vendor.
    - allow otapreopt_chroot block_device:dir search;
    - allow otapreopt_chroot labeledfs:filesystem mount;
    -+# Mounting /vendor can have this side-effect. Ignore denial.
    -+dontaudit otapreopt_chroot kernel:process setsched;
    - 
    - # Allow to transition to postinstall_ota, to run otapreopt in its own sandbox.
    - domain_auto_trans(otapreopt_chroot, postinstall_file, postinstall_dexopt)
    -diff --git a/platform_app.te b/platform_app.te
    -index 0d3bdba..d4a27ad 100644
    ---- a/platform_app.te
    -+++ b/platform_app.te
    -@@ -45,6 +45,7 @@ allow platform_app drmserver_service:service_manager find;
    - allow platform_app mediaserver_service:service_manager find;
    - allow platform_app mediaextractor_service:service_manager find;
    - allow platform_app mediacodec_service:service_manager find;
    -+allow platform_app mediadrmserver_service:service_manager find;
    - allow platform_app persistent_data_block_service:service_manager find;
    - allow platform_app radio_service:service_manager find;
    - allow platform_app surfaceflinger_service:service_manager find;
     diff --git a/priv_app.te b/priv_app.te
     index 85516a6..e1f96d5 100644
     --- a/priv_app.te
    @@ -183,35 +124,6 @@ index 85516a6..e1f96d5 100644
      
      # Do not allow privileged apps to register services.
      # Only trusted components of Android should be registering
    -diff --git a/service.te b/service.te
    -index 6b5838c..e7a30f9 100644
    ---- a/service.te
    -+++ b/service.te
    -@@ -39,6 +39,7 @@ type contexthub_service, app_api_service, system_server_service, service_manager
    - type IProxyService_service, app_api_service, system_server_service, service_manager_type;
    - type commontime_management_service, system_server_service, service_manager_type;
    - type connectivity_service, app_api_service, system_server_service, service_manager_type;
    -+type connmetrics_service, app_api_service, system_server_service, service_manager_type;
    - type consumer_ir_service, app_api_service, system_server_service, service_manager_type;
    - type content_service, app_api_service, system_server_service, service_manager_type;
    - type country_detector_service, app_api_service, system_server_service, service_manager_type;
    -diff --git a/service_contexts b/service_contexts
    -index 0ddbdc1..dd7e49f 100644
    ---- a/service_contexts
    -+++ b/service_contexts
    -@@ -19,9 +19,10 @@ carrier_config                            u:object_r:radio_service:s0
    - clipboard                                 u:object_r:clipboard_service:s0
    - com.android.net.IProxyService             u:object_r:IProxyService_service:s0
    - commontime_management                     u:object_r:commontime_management_service:s0
    --common_time.clock                        u:object_r:mediaserver_service:s0
    --common_time.config                       u:object_r:mediaserver_service:s0
    -+common_time.clock                         u:object_r:mediaserver_service:s0
    -+common_time.config                        u:object_r:mediaserver_service:s0
    - connectivity                              u:object_r:connectivity_service:s0
    -+connmetrics                               u:object_r:connmetrics_service:s0
    - consumer_ir                               u:object_r:consumer_ir_service:s0
    - content                                   u:object_r:content_service:s0
    - contexthub_service                        u:object_r:contexthub_service:s0
     diff --git a/untrusted_app.te b/untrusted_app.te
     index 35c811c..19cfc64 100644
     --- a/untrusted_app.te
    
    From 277dc18e1f4a926e37e0ae1944ba93520c6663fb Mon Sep 17 00:00:00 2001
    From: AndDiSa <anddisa@googlemail.com>
    Date: Fri, 16 Dec 2016 20:58:11 +0100
    Subject: [PATCH 057/159] update patches
    
    Change-Id: I94e7039c5fdb68166f0b673cf6da6b1b69c91770
    ---
     frameworks_av.patch   | 98 ++++++++++++++++++++++++++++++++++---------
     frameworks_base.patch | 29 +++++++++++++
     2 files changed, 108 insertions(+), 19 deletions(-)
    
    diff --git a/frameworks_av.patch b/frameworks_av.patch
    index 9af12f4..c56a00d 100644
    --- a/frameworks_av.patch
    +++ b/frameworks_av.patch
    @@ -18,7 +18,7 @@ index 7e36c5e..aca7a19 100644
      include $(BUILD_EXECUTABLE)
     +endif
     diff --git a/include/media/stagefright/MediaBufferGroup.h b/include/media/stagefright/MediaBufferGroup.h
    -index 3051406..e0e5856 100644
    +index 3051406..870bb9b 100644
     --- a/include/media/stagefright/MediaBufferGroup.h
     +++ b/include/media/stagefright/MediaBufferGroup.h
     @@ -49,7 +49,10 @@ public:
    @@ -26,7 +26,7 @@ index 3051406..e0e5856 100644
          // size of at least requstedSize.
          status_t acquire_buffer(
     -            MediaBuffer **buffer, bool nonBlocking = false, size_t requestedSize = 0);
    -+            MediaBuffer **buffer, bool nonBlocking, size_t requestedSize);
    ++            MediaBuffer **buffer, bool nonBlocking, size_t requestedSize = 0);
     +
     +    status_t acquire_buffer(MediaBuffer **buffer);
     +    status_t acquire_buffer(MediaBuffer **buffer, bool nonBlocking);
    @@ -34,7 +34,7 @@ index 3051406..e0e5856 100644
          size_t buffers() const { return mBuffers.size(); }
      
     diff --git a/media/libstagefright/ACodec.cpp b/media/libstagefright/ACodec.cpp
    -index 37fd5a5..706ba4e 100644
    +index 37fd5a5..77a2a39 100644
     --- a/media/libstagefright/ACodec.cpp
     +++ b/media/libstagefright/ACodec.cpp
     @@ -804,13 +804,22 @@ status_t ACodec::allocateBuffersOnPort(OMX_U32 portIndex) {
    @@ -75,7 +75,26 @@ index 37fd5a5..706ba4e 100644
              uint32_t usageBits;
              if (mOMX->getParameter(
                      mNode, (OMX_INDEXTYPE)OMX_IndexParamConsumerUsageBits,
    -@@ -6036,6 +6053,9 @@ void ACodec::BaseState::onInputBufferFilled(const sp<AMessage> &msg) {
    +@@ -4274,7 +4291,9 @@ status_t ACodec::setupAVCEncoderParameters(const sp<AMessage> &msg) {
    + 
    +         h264type.eProfile = static_cast<OMX_VIDEO_AVCPROFILETYPE>(profile);
    +         h264type.eLevel = static_cast<OMX_VIDEO_AVCLEVELTYPE>(level);
    +-    } else {
    ++    }
    ++#ifdef USE_AVC_BASELINE_PROFILE
    ++      else {
    +         h264type.eProfile = OMX_VIDEO_AVCProfileBaseline;
    + #if 0   /* DON'T YET DEFAULT TO HIGHEST PROFILE */
    +         // Use largest supported profile for AVC recording if profile is not specified.
    +@@ -4287,6 +4306,7 @@ status_t ACodec::setupAVCEncoderParameters(const sp<AMessage> &msg) {
    +         }
    + #endif
    +     }
    ++#endif
    + 
    +     ALOGI("setupAVCEncoderParameters with [profile: %s] [level: %s]",
    +             asString(h264type.eProfile), asString(h264type.eLevel));
    +@@ -6036,6 +6056,9 @@ void ACodec::BaseState::onInputBufferFilled(const sp<AMessage> &msg) {
                      status_t err2 = OK;
                      switch (metaType) {
                      case kMetadataBufferTypeInvalid:
    @@ -85,7 +104,7 @@ index 37fd5a5..706ba4e 100644
                          break;
      #ifndef OMX_ANDROID_COMPILE_AS_32BIT_ON_64BIT_PLATFORMS
                      case kMetadataBufferTypeNativeHandleSource:
    -@@ -6267,6 +6287,10 @@ bool ACodec::BaseState::onOMXFillBufferDone(
    +@@ -6267,6 +6290,10 @@ bool ACodec::BaseState::onOMXFillBufferDone(
                      native_handle_t *handle = NULL;
                      VideoNativeHandleMetadata &nativeMeta =
                          *(VideoNativeHandleMetadata *)info->mData->data();
    @@ -96,7 +115,7 @@ index 37fd5a5..706ba4e 100644
                      if (info->mData->size() >= sizeof(nativeMeta)
                              && nativeMeta.eType == kMetadataBufferTypeNativeHandleSource) {
      #ifdef OMX_ANDROID_COMPILE_AS_32BIT_ON_64BIT_PLATFORMS
    -@@ -6276,6 +6300,12 @@ bool ACodec::BaseState::onOMXFillBufferDone(
    +@@ -6276,6 +6303,12 @@ bool ACodec::BaseState::onOMXFillBufferDone(
                          handle = (native_handle_t *)nativeMeta.pHandle;
      #endif
                      }
    @@ -109,7 +128,7 @@ index 37fd5a5..706ba4e 100644
                      info->mData->meta()->setPointer("handle", handle);
                      info->mData->meta()->setInt32("rangeOffset", rangeOffset);
                      info->mData->meta()->setInt32("rangeLength", rangeLength);
    -@@ -6968,10 +6998,12 @@ void ACodec::LoadedState::onCreateInputSurface(
    +@@ -6968,10 +7001,12 @@ void ACodec::LoadedState::onCreateInputSurface(
              err = mCodec->mOMX->createInputSurface(
                      mCodec->mNode, kPortIndexInput, dataSpace, &bufferProducer,
                      &mCodec->mInputMetadataType);
    @@ -122,7 +141,7 @@ index 37fd5a5..706ba4e 100644
          }
      
          if (err == OK) {
    -@@ -7014,10 +7046,12 @@ void ACodec::LoadedState::onSetInputSurface(
    +@@ -7014,10 +7049,12 @@ void ACodec::LoadedState::onSetInputSurface(
              err = mCodec->mOMX->setInputSurface(
                      mCodec->mNode, kPortIndexInput, surface->getBufferConsumer(),
                      &mCodec->mInputMetadataType);
    @@ -136,10 +155,21 @@ index 37fd5a5..706ba4e 100644
      
          if (err == OK) {
     diff --git a/media/libstagefright/Android.mk b/media/libstagefright/Android.mk
    -index 3848502..c06f6a4 100644
    +index 3848502..1635375 100644
     --- a/media/libstagefright/Android.mk
     +++ b/media/libstagefright/Android.mk
    -@@ -124,6 +124,10 @@ LOCAL_SHARED_LIBRARIES += \
    +@@ -102,6 +102,10 @@ LOCAL_SHARED_LIBRARIES := \
    +         libz \
    +         libpowermanager
    + 
    ++ifeq ($(TARGET_USE_AVC_BASELINE_PROFILE), true)
    ++LOCAL_CFLAGS += -DUSE_AVC_BASELINE_PROFILE
    ++endif
    ++
    + LOCAL_STATIC_LIBRARIES := \
    +         libstagefright_color_conversion \
    +         libyuv_static \
    +@@ -124,6 +128,10 @@ LOCAL_SHARED_LIBRARIES += \
              libdl \
              libRScpp \
      
    @@ -151,9 +181,18 @@ index 3848502..c06f6a4 100644
      
      # enable experiments only in userdebug and eng builds
     diff --git a/media/libstagefright/CameraSource.cpp b/media/libstagefright/CameraSource.cpp
    -index 893da89..c9f60ec 100644
    +index 893da89..0bc6847 100644
     --- a/media/libstagefright/CameraSource.cpp
     +++ b/media/libstagefright/CameraSource.cpp
    +@@ -1117,7 +1117,7 @@ void CameraSource::releaseRecordingFrameHandle(native_handle_t* handle) {
    +         int64_t token = IPCThreadState::self()->clearCallingIdentity();
    +         mCamera->releaseRecordingFrameHandle(handle);
    +         IPCThreadState::self()->restoreCallingIdentity(token);
    +-    } else {
    ++    } else if (handle != nullptr) {
    +         native_handle_close(handle);
    +         native_handle_delete(handle);
    +     }
     @@ -1250,6 +1250,10 @@ void CameraSource::processBufferQueueFrame(BufferItem& buffer) {
      MetadataBufferType CameraSource::metaDataStoredInVideoBuffers() const {
          ALOGV("metaDataStoredInVideoBuffers");
    @@ -251,19 +290,13 @@ index 54f768a..1334f93 100644
          mCondition.signal();
      }
     diff --git a/media/libstagefright/omx/Android.mk b/media/libstagefright/omx/Android.mk
    -index e4fbd81..c262782 100644
    +index e4fbd81..8fc788f 100644
     --- a/media/libstagefright/omx/Android.mk
     +++ b/media/libstagefright/omx/Android.mk
    -@@ -31,6 +31,18 @@ LOCAL_SHARED_LIBRARIES :=               \
    +@@ -31,6 +31,12 @@ LOCAL_SHARED_LIBRARIES :=               \
              libstagefright_foundation       \
              libdl
      
    -+ifneq ($(TARGET_USES_MEDIA_EXTENSIONS),true)
    -+ifeq ($(TARGET_HAS_LEGACY_CAMERA_HAL1),true)
    -+LOCAL_CFLAGS += -DCAMCORDER_GRALLOC_SOURCE
    -+endif
    -+endif
    -+
     +ifneq ($(TARGET_USES_MEDIA_EXTENSIONS),true)
     +ifeq ($(TARGET_HAS_LEGACY_CAMERA_HAL1),true)
     +LOCAL_CFLAGS += -DCAMCORDER_GRALLOC_SOURCE
    @@ -394,6 +427,33 @@ index ecddc48..0abe6ac 100644
          registerExtensions();
          ProcessState::self()->startThreadPool();
          IPCThreadState::self()->joinThreadPool();
    +diff --git a/services/audioflinger/AudioFlinger.cpp b/services/audioflinger/AudioFlinger.cpp
    +index 1785a03..d5499f0 100644
    +--- a/services/audioflinger/AudioFlinger.cpp
    ++++ b/services/audioflinger/AudioFlinger.cpp
    +@@ -1509,7 +1509,8 @@ sp<IAudioRecord> AudioFlinger::openRecord(
    +     }
    + 
    +     // check calling permissions
    +-    if (!recordingAllowed(opPackageName, tid, clientUid)) {
    ++    if (!isTrustedCallingUid(callingUid) &&
    ++		!recordingAllowed(opPackageName, tid, clientUid)) {
    +         ALOGE("openRecord() permission denied: recording not allowed");
    +         lStatus = PERMISSION_DENIED;
    +         goto Exit;
    +diff --git a/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp b/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp
    +index c9b3abc..57d26e6 100644
    +--- a/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp
    ++++ b/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp
    +@@ -318,7 +318,7 @@ status_t AudioPolicyService::getInputForAttr(const audio_attributes_t *attr,
    +             case AudioPolicyInterface::API_INPUT_TELEPHONY_RX:
    +                 // FIXME: use the same permission as for remote submix for now.
    +             case AudioPolicyInterface::API_INPUT_MIX_CAPTURE:
    +-                if (!captureAudioOutputAllowed(pid, uid)) {
    ++                if (!isTrustedCallingUid(callingUid) && !captureAudioOutputAllowed(pid, uid)) {
    +                     ALOGE("getInputForAttr() permission denied: capture not allowed");
    +                     status = PERMISSION_DENIED;
    +                 }
     diff --git a/services/camera/libcameraservice/Android.mk b/services/camera/libcameraservice/Android.mk
     index 8d7f71c..d98ad47 100644
     --- a/services/camera/libcameraservice/Android.mk
    diff --git a/frameworks_base.patch b/frameworks_base.patch
    index c91c6a1..8104107 100644
    --- a/frameworks_base.patch
    +++ b/frameworks_base.patch
    @@ -24,6 +24,35 @@ index aed7a36..bf96926 100644
                  // if canceling out of addAccount and the original state caused us to skip this,
                  // finish this activity
                  if (mAccounts.isEmpty()) {
    +diff --git a/core/res/res/xml/config_webview_packages.xml b/core/res/res/xml/config_webview_packages.xml
    +index f062b59..574f7c1 100644
    +--- a/core/res/res/xml/config_webview_packages.xml
    ++++ b/core/res/res/xml/config_webview_packages.xml
    +@@ -15,7 +15,22 @@
    + -->
    + 
    + <webviewproviders>
    +-    <!-- The default WebView implementation -->
    +-    <webviewprovider description="Android WebView" packageName="com.android.webview" availableByDefault="true">
    ++
    ++    <webviewprovider description="Chrome Stable" packageName="com.android.chrome" availableByDefault="true">
    ++        <signature>MIIEQzCCAyugAwIBAgIJAMLgh0ZkSjCNMA0GCSqGSIb3DQEBBAUAMHQxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpDYWxpZm9ybmlhMRYwFAYDVQQHEw1Nb3VudGFpbiBWaWV3MRQwEgYDVQQKEwtHb29nbGUgSW5jLjEQMA4GA1UECxMHQW5kcm9pZDEQMA4GA1UEAxMHQW5kcm9pZDAeFw0wODA4MjEyMzEzMzRaFw0zNjAxMDcyMzEzMzRaMHQxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpDYWxpZm9ybmlhMRYwFAYDVQQHEw1Nb3VudGFpbiBWaWV3MRQwEgYDVQQKEwtHb29nbGUgSW5jLjEQMA4GA1UECxMHQW5kcm9pZDEQMA4GA1UEAxMHQW5kcm9pZDCCASAwDQYJKoZIhvcNAQEBBQADggENADCCAQgCggEBAKtWLgDYO6IIrgqWbxJOKdoR8qtW0I9Y4sypEwPpt1TTcvZApxsdyxMJZ2JORland2qSGT2y5b+3JKkedxiLDmpHpDsz2WCbdxgxRczfey5YZnTJ4VZbH0xqWVW/8lGmPav5xVwnIiJS6HXk+BVKZF+JcWjAsb/GEuq/eFdpuzSqeYTcfi6idkyugwfYwXFU1+5fZKUaRKYCwkkFQVfcAs1fXA5V+++FGfvjJ/CxURaSxaBvGdGDhfXE28LWuT9ozCl5xw4Yq5OGazvV24mZVSoOO0yZ31j7kYvtwYK6NeADwbSxDdJEqO4k//0zOHKrUiGYXtqw/A0LFFtqoZKFjnkCAQOjgdkwgdYwHQYDVR0OBBYEFMd9jMIhF1Ylmn/Tgt9r45jk14alMIGmBgNVHSMEgZ4wgZuAFMd9jMIhF1Ylmn/Tgt9r45jk14aloXikdjB0MQswCQYDVQQGEwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTEWMBQGA1UEBxMNTW91bnRhaW4gVmlldzEUMBIGA1UEChMLR29vZ2xlIEluYy4xEDAOBgNVBAsTB0FuZHJvaWQxEDAOBgNVBAMTB0FuZHJvaWSCCQDC4IdGZEowjTAMBgNVHRMEBTADAQH/MA0GCSqGSIb3DQEBBAUAA4IBAQBt0lLO74UwLDYKqs6Tm8/yzKkEu116FmH4rkaymUIE0P9KaMftGlMexFlaYjzmB2OxZyl6euNXEsQH8gjwyxCUKRJNexBiGcCEyj6z+a1fuHHvkiaai+KL8W1EyNmgjmyy8AW7P+LLlkR+ho5zEHatRbM/YAnqGcFh5iZBqpknHf1SKMXFh4dd239FJ1jWYfbMDMy3NS5CTMQ2XFI1MvcyUTdZPErjQfTbQe3aDQsQcafEQPD+nqActifKZ0Np0IS9L9kR/wbNvyz6ENwPiTrjV2KRkEjH78ZMcUQXg0L3BYHJ3lc69Vs5Ddf9uUGGMYldX3WfMBEmh/9iFBDAaTCK</signature>
    ++    </webviewprovider>
    ++    <webviewprovider description="Chrome Beta" packageName="com.chrome.beta">
    ++        <signature>MIIDwzCCAqugAwIBAgIJAOoj9MXoVhH6MA0GCSqGSIb3DQEBBQUAMHgxCzAJBgNVBAYTAlVTMRMwEQYDVQQIDApDYWxpZm9ybmlhMRYwFAYDVQQHDA1Nb3VudGFpbiBWaWV3MRQwEgYDVQQKDAtHb29nbGUgSW5jLjEQMA4GA1UECwwHQW5kcm9pZDEUMBIGA1UEAwwLY2hyb21lX2JldGEwHhcNMTYwMjI5MTUxNTIzWhcNNDMwNzE3MTUxNTIzWjB4MQswCQYDVQQGEwJVUzETMBEGA1UECAwKQ2FsaWZvcm5pYTEWMBQGA1UEBwwNTW91bnRhaW4gVmlldzEUMBIGA1UECgwLR29vZ2xlIEluYy4xEDAOBgNVBAsMB0FuZHJvaWQxFDASBgNVBAMMC2Nocm9tZV9iZXRhMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAo/wW27nRxVqGbFOyXr8jtv2pc2Ke8XMr6Sfs+3JK2licVaAljGFpLtWH4wUdb50w/QQSPALNLSSyuK/94rtp5Jjs4RSJI+whuewV/R6El+mFXBO3Ek5/op4UrOsR91IM4emvS67Ji2u8gp5EmttVgJtllFZCbtZLPmKuTaOkOB+EdWIxrYiHVEEaAcQpEHa9UgWUZ0bMfPj8j3F0w+Ak2ttmTjoFGLaZjuBAYwfdctN1b0sdLT9Lif45kMCb8QwPp0F9/ozs0rrTc+I6vnTS8kfFQfk7GIE4Hgm+cYQEHkIA6gLJxUVWvPZGdulAZw7wPt/neOkazHNZPcV4pYuNLQIDAQABo1AwTjAdBgNVHQ4EFgQU5t7dhcZfOSixRsiJ1E46JhzPlwowHwYDVR0jBBgwFoAU5t7dhcZfOSixRsiJ1E46JhzPlwowDAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQUFAAOCAQEAZO2jB8P1d8ki3KZILvp27a2VM3DInlp8I8UgG3gh7nBQfTrnZr5M1PL8eFHqX7MEvAiGCMTcrPklEhjtcHK/c7BcdeCWq6oL56UK3JTl33RxJcjmjrz3e3VI6ehRSm1feNAkMD0Nr2RWr2LCYheAEmwTPtluLOJS+i7WhnXJzBtg5UpUFEbdFYenqUbDzya+cUVp0197k7hUTs8/Hxs0wf79o/TZXzTBq9eYQkiITonRN8+5QCBl1XmZKV0IHkzGFES1RP+fTiZpIjZT+W4tasHgs9QTTks4CCpyHBAy+uy7tApe1AxCzihgecCfUN1hWIltKwGZS6EE0bu0OXPzaQ==</signature>
    ++    </webviewprovider>
    ++    <webviewprovider description="Chrome Dev" packageName="com.chrome.dev">
    ++        <signature>MIIDwTCCAqmgAwIBAgIJAOSN+O0cdii5MA0GCSqGSIb3DQEBBQUAMHcxCzAJBgNVBAYTAlVTMRMwEQYDVQQIDApDYWxpZm9ybmlhMRYwFAYDVQQHDA1Nb3VudGFpbiBWaWV3MRQwEgYDVQQKDAtHb29nbGUgSW5jLjEQMA4GA1UECwwHQW5kcm9pZDETMBEGA1UEAwwKY2hyb21lX2RldjAeFw0xNjAyMjkxNzUwMDdaFw00MzA3MTcxNzUwMDdaMHcxCzAJBgNVBAYTAlVTMRMwEQYDVQQIDApDYWxpZm9ybmlhMRYwFAYDVQQHDA1Nb3VudGFpbiBWaWV3MRQwEgYDVQQKDAtHb29nbGUgSW5jLjEQMA4GA1UECwwHQW5kcm9pZDETMBEGA1UEAwwKY2hyb21lX2RldjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBANOYPj6Y9rVt8xizSHDYjDEkDfFZAgSiZ9T6tevkQXsFyfaq3Gk3h2qssi29G6cTPJ2VXFKlVB71wSXv5p9/LEcDQPWQiO3Q2cLmgUXxyhJWXI3g96tPAhZQX2q6SC37ZQdiBR/raMO70DAkvCyBGtNplsvutzSE3oZ7LYfzB8vTbe7zCh3fDYSS/7xb3ZVvFqydHS40uVq1qqg1S80Pge7tW3pDGsPMZN7yA4yfmsvA1rbHm9N8t3Rc9hqzh6OxNAAgRB535YcsWL7iF+mpdFILXk3jLYT0nMvMnB83rsdgnRREjlGQYHl2mh8+6CqujsW/eICDq/LR6BYDyqHhk0ECAwEAAaNQME4wHQYDVR0OBBYEFKzsl07JglgpbeYDYGqsgqRDo+01MB8GA1UdIwQYMBaAFKzsl07JglgpbeYDYGqsgqRDo+01MAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEFBQADggEBACka6SFF6xAcj8L8O6R36++E09DTiGZEjvKT8eIycgcQQ+p1WUmPb6M2EJpN6zvvSE62ussmXdzf8rIyc0JXA8jbViZt62Y39epNENFxPTLN9QzXlT+w8AW73Ka3cnbOuL5EgoDl8fM79WVlARY3X+wB/jGNrkiGIdRm2IZIeAodWgC2mtXMiferyYBKz2/F2bhnU6DwgCbegS8trFjEWviijWdJ+lBdobn7LRc3orZCtHl8UyvRDi7cye3sK9y3BM39k0g20F21wTNHAonnvL6zbuNgpd+UEsVxDpOeWrEdBFN7Md0CI2wnu8eA8ljJD45v0WWMEoxsIi131g5piNM=</signature>
    ++    </webviewprovider>
    ++    <webviewprovider description="Chrome Canary" packageName="com.chrome.canary">
    ++        <signature>MIIDxzCCAq+gAwIBAgIJAML7APITsgV7MA0GCSqGSIb3DQEBBQUAMHoxCzAJBgNVBAYTAlVTMRMwEQYDVQQIDApDYWxpZm9ybmlhMRYwFAYDVQQHDA1Nb3VudGFpbiBWaWV3MRQwEgYDVQQKDAtHb29nbGUgSW5jLjEQMA4GA1UECwwHQW5kcm9pZDEWMBQGA1UEAwwNY2hyb21lX2NhbmFyeTAeFw0xNjAyMjkxOTA5MDdaFw00MzA3MTcxOTA5MDdaMHoxCzAJBgNVBAYTAlVTMRMwEQYDVQQIDApDYWxpZm9ybmlhMRYwFAYDVQQHDA1Nb3VudGFpbiBWaWV3MRQwEgYDVQQKDAtHb29nbGUgSW5jLjEQMA4GA1UECwwHQW5kcm9pZDEWMBQGA1UEAwwNY2hyb21lX2NhbmFyeTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBANXfeAoZlr0ya1HBzIfAz/nLLjpPJeAPvuX5dueaxmiQgv2hNG22acriFuiiJI6TU0t8AIVJD5Ifbc4OOuA0zeFhdzWWGnmTRH6x27WI7bzOKnAqOvv21ZBmE9i8Vo++K13xWdTs3qVn1bn9oUONxFu0wKDzXYZhoj1Jom0RZGjXm16xuPlEuOzMcjiNBDoYuxPAXkMcK/G1gP4P4nAV8Rd/GGIjKRS/SUtcShhoAMOQhs4WIEkUrvEVRwhBDIbpM87oFbCVdBH38r0XS6F6CdhPJsKFhoEfq4c01HZqNmDpCPA8AAcCuSWqmXoTIqs7OqkWgduE2bInbWU7WMaTl+kCAwEAAaNQME4wHQYDVR0OBBYEFB/AsC4iPAqaLoNytNSx29qByI7+MB8GA1UdIwQYMBaAFB/AsC4iPAqaLoNytNSx29qByI7+MAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEFBQADggEBAMb2Td3ro/+MGVnCPAbwBSOZMVLUKGqt6zr8CShW9mtFHnmy29EaWSYYAj1M4+6Vpkq85NsgBEck7rnUjV8A3Q0NKdTys1KRKJqVvQRBN6SwqQenSf/abxQCa8Z+69rh+3BkIU1HLtu5lrMDZwon5H91L5mpORn6vItd20uW132lwSDeUEW2CHslTrodoFuTUcSUlRiq/URfUH3baO1QHXkxpQwrBPKL5deJfcZnxh5MAtAGSQL7gHvayEFlDppETXdDO7vgGTH2dEK2TjKWALbGiKkxSqjRyTNt4/FOj10TqNRdUamj+ydVJgzGQ8bki4Vc6NnKm/r4asusxapkVR4=</signature>
    +     </webviewprovider>
    ++    <webviewprovider description="Google WebView" packageName="com.google.android.webview" availableByDefault="true">
    ++<signature>MIIDuzCCAqOgAwIBAgIJANi6DgBQG4ZTMA0GCSqGSIb3DQEBBQUAMHQxCzAJBgNVBAYTAlVTMRMwEQYDVQQIDApDYWxpZm9ybmlhMRYwFAYDVQQHDA1Nb3VudGFpbiBWaWV3MRQwEgYDVQQKDAtHb29nbGUgSW5jLjEQMA4GA1UECwwHQW5kcm9pZDEQMA4GA1UEAwwHd2VidmlldzAeFw0xNDA4MDgyMzIwMjBaFw00MTEyMjQyMzIwMjBaMHQxCzAJBgNVBAYTAlVTMRMwEQYDVQQIDApDYWxpZm9ybmlhMRYwFAYDVQQHDA1Nb3VudGFpbiBWaWV3MRQwEgYDVQQKDAtHb29nbGUgSW5jLjEQMA4GA1UECwwHQW5kcm9pZDEQMA4GA1UEAwwHd2VidmlldzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMbtaFX0r5aZJMAbPVMAgK1ZZ29dTn91VsGxXv2hqrQo7IpqEy2JmPvPnoMsSiuTAe+UcQy8oKDQ2aYVSAd1DGIy+nSRyFTt3LSIAdwSBkB1qT4a+OqkpsR6bSNXQXQ18lCQu9gREY3h3QlYBQAyzRxw4hRGlrXAzuSz1Ec4W+6x4nLG5DG61MAMR8ClF9XSqbmGB3kyZ70A0X9OPYYxiMWP1ExaYvpaVqjyZZcrPwr+vtW8oCuGBUtHpBUH3OoG+9s2YMcgLG7vCK9awKDqlPcJSpIAAj6uGs4gORmkqxZRMskLSTWbhP4p+3Ap8jYzTVB6Y1/DMVmYTWRMcPW0macCAwEAAaNQME4wHQYDVR0OBBYEFJ6bAR6/QVm4w9LRSGQiaR5Rhp3TMB8GA1UdIwQYMBaAFJ6bAR6/QVm4w9LRSGQiaR5Rhp3TMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEFBQADggEBAEQu8QiVxax7/diEiJrgKE1LwdXsIygJK/KnaKdnYEkAQpeu/QmrLiycm+OFbL1qHJIB7OuI/PQBUtcaNSiJSCVgtwtEbZWWIdsynqG/Nf4aGOndXegSQNRH54M05sRHLoeRycPrY7xQlEwGikNFR76+5UdwFBQI3Gn22g6puJnVukQm/wXQ+ajoiS4QclrNlixoDQsZ4STLH4+Wju2wIWKFFArIhVEIlbamq+p6BghuzH3aIz/Fy0YTQKi7SA+0fuNeCaqlSm5pYSt6p5CH89y1Fr+wFc5r3iLRnUwRcy08ESC7bZJnxV3d/YQ5valTxBbzku/dQbXVj/xg69H8l8M</signature>
    ++</webviewprovider>
    ++  <!-- The default WebView implementation -->
    ++    <webviewprovider description="AOSP WebView" packageName="com.android.webview" availableByDefault="true" isFallback="true" />
    + </webviewproviders>
     diff --git a/libs/hwui/Android.mk b/libs/hwui/Android.mk
     index cacfce1..0b177b9 100644
     --- a/libs/hwui/Android.mk
    
    From 12f548bb378bd01f4492efe5f352ae8ba68b8661 Mon Sep 17 00:00:00 2001
    From: AndDiSa <anddisa@googlemail.com>
    Date: Wed, 4 Jan 2017 18:15:46 +0100
    Subject: [PATCH 058/159] update to android_7.1.1_r9
    
    Change-Id: I897647e740aaa68bea1c658626d1bae717db62ff
    ---
     default.xml | 2 +-
     1 file changed, 1 insertion(+), 1 deletion(-)
    
    diff --git a/default.xml b/default.xml
    index e411ddc..8ea53ec 100644
    --- a/default.xml
    +++ b/default.xml
    @@ -9,7 +9,7 @@
                fetch="https://github.com/millosr/" />
       <remote  name="unlegacy"
                fetch="https://github.com/Unlegacy-Android/" />
    -  <default revision="refs/tags/android-7.1.1_r4"
    +  <default revision="refs/tags/android-7.1.1_r9"
                remote="aosp"
                sync-j="4" />
     
    
    From fa076631e4e31a82f34d02eaf526121f22a6e745 Mon Sep 17 00:00:00 2001
    From: AndDiSa <anddisa@googlemail.com>
    Date: Thu, 5 Jan 2017 20:05:47 +0100
    Subject: [PATCH 059/159] update patches
    
    Change-Id: I4b6ba9f0c6f07cbcd80125f89b0dde360fa76239
    ---
     build.patch             |  23 +++
     default.xml             |   2 +-
     frameworks_av.patch     | 329 +++++++++++++++++++++++++++++++++++++++-
     frameworks_base.patch   | 173 +++++++++++++++++++++
     frameworks_native.patch |  33 ++++
     5 files changed, 556 insertions(+), 4 deletions(-)
    
    diff --git a/build.patch b/build.patch
    index b699411..663e46c 100644
    --- a/build.patch
    +++ b/build.patch
    @@ -1,3 +1,13 @@
    +diff --git a/core/build_id.mk b/core/build_id.mk
    +index c3d6c40..1576856 100644
    +--- a/core/build_id.mk
    ++++ b/core/build_id.mk
    +@@ -18,4 +18,4 @@
    + # (like "CRB01").  It must be a single word, and is
    + # capitalized by convention.
    + 
    +-export BUILD_ID=NMF26O
    ++export BUILD_ID=NMF26V
     diff --git a/core/main.mk b/core/main.mk
     index a612f83..921eb32 100644
     --- a/core/main.mk
    @@ -213,6 +223,19 @@ index 0000000..9c12bc0
     +
     +ALL_PREBUILT += $(INSTALLED_KERNEL_TARGET)
     +endif
    +diff --git a/core/version_defaults.mk b/core/version_defaults.mk
    +index 2c8a21f..550fc70 100644
    +--- a/core/version_defaults.mk
    ++++ b/core/version_defaults.mk
    +@@ -114,7 +114,7 @@ ifeq "" "$(PLATFORM_SECURITY_PATCH)"
    +     #  It must be of the form "YYYY-MM-DD" on production devices.
    +     #  It must match one of the Android Security Patch Level strings of the Public Security Bulletins.
    +     #  If there is no $PLATFORM_SECURITY_PATCH set, keep it empty.
    +-      PLATFORM_SECURITY_PATCH := 2016-12-05
    ++      PLATFORM_SECURITY_PATCH := 2017-01-05
    + endif
    + 
    + ifeq "" "$(PLATFORM_BASE_OS)"
     diff --git a/core/version_defaults_BACKUP_20377.mk b/core/version_defaults_BACKUP_20377.mk
     new file mode 100644
     index 0000000..eb97b11
    diff --git a/default.xml b/default.xml
    index 8ea53ec..01d8d32 100644
    --- a/default.xml
    +++ b/default.xml
    @@ -425,7 +425,7 @@
       <project path="packages/apps/Test/connectivity" name="platform/packages/apps/Test/connectivity" />
       <project path="packages/apps/TvSettings" name="platform/packages/apps/TvSettings" groups="generic_fs" />
       <project path="packages/apps/UnifiedEmail" name="platform/packages/apps/UnifiedEmail" groups="pdk-fs" />
    -  <project path="packages/apps/WallpaperPicker" name="platform/packages/apps/WallpaperPicker" />
    +<!--  <project path="packages/apps/WallpaperPicker" name="platform/packages/apps/WallpaperPicker" /> -->
       <project path="packages/experimental" name="platform/packages/experimental" />
       <project path="packages/inputmethods/LatinIME" name="platform/packages/inputmethods/LatinIME" groups="pdk-fs" />
       <project path="packages/inputmethods/OpenWnn" name="platform/packages/inputmethods/OpenWnn" groups="pdk-fs" />
    diff --git a/frameworks_av.patch b/frameworks_av.patch
    index c56a00d..b5436c6 100644
    --- a/frameworks_av.patch
    +++ b/frameworks_av.patch
    @@ -33,6 +33,155 @@ index 3051406..870bb9b 100644
      
          size_t buffers() const { return mBuffers.size(); }
      
    +diff --git a/media/libeffects/lvm/wrapper/Bundle/EffectBundle.cpp b/media/libeffects/lvm/wrapper/Bundle/EffectBundle.cpp
    +index a1892e4..ed38584 100644
    +--- a/media/libeffects/lvm/wrapper/Bundle/EffectBundle.cpp
    ++++ b/media/libeffects/lvm/wrapper/Bundle/EffectBundle.cpp
    +@@ -2357,8 +2357,12 @@ int Equalizer_getParameter(EffectContext     *pContext,
    + 
    +     case EQ_PARAM_BAND_LEVEL:
    +         param2 = *pParamTemp;
    +-        if (param2 >= FIVEBAND_NUMBANDS) {
    ++        if (param2 < 0 || param2 >= FIVEBAND_NUMBANDS) {
    +             status = -EINVAL;
    ++            if (param2 < 0) {
    ++                android_errorWriteLog(0x534e4554, "32438598");
    ++                ALOGW("\tERROR Equalizer_getParameter() EQ_PARAM_BAND_LEVEL band %d", param2);
    ++            }
    +             break;
    +         }
    +         *(int16_t *)pValue = (int16_t)EqualizerGetBandLevel(pContext, param2);
    +@@ -2368,8 +2372,12 @@ int Equalizer_getParameter(EffectContext     *pContext,
    + 
    +     case EQ_PARAM_CENTER_FREQ:
    +         param2 = *pParamTemp;
    +-        if (param2 >= FIVEBAND_NUMBANDS) {
    ++        if (param2 < 0 || param2 >= FIVEBAND_NUMBANDS) {
    +             status = -EINVAL;
    ++            if (param2 < 0) {
    ++                android_errorWriteLog(0x534e4554, "32436341");
    ++                ALOGW("\tERROR Equalizer_getParameter() EQ_PARAM_CENTER_FREQ band %d", param2);
    ++            }
    +             break;
    +         }
    +         *(int32_t *)pValue = EqualizerGetCentreFrequency(pContext, param2);
    +@@ -2379,8 +2387,12 @@ int Equalizer_getParameter(EffectContext     *pContext,
    + 
    +     case EQ_PARAM_BAND_FREQ_RANGE:
    +         param2 = *pParamTemp;
    +-        if (param2 >= FIVEBAND_NUMBANDS) {
    ++        if (param2 < 0 || param2 >= FIVEBAND_NUMBANDS) {
    +             status = -EINVAL;
    ++            if (param2 < 0) {
    ++                android_errorWriteLog(0x534e4554, "32247948");
    ++                ALOGW("\tERROR Equalizer_getParameter() EQ_PARAM_BAND_FREQ_RANGE band %d", param2);
    ++            }
    +             break;
    +         }
    +         EqualizerGetBandFreqRange(pContext, param2, (uint32_t *)pValue, ((uint32_t *)pValue + 1));
    +@@ -2407,9 +2419,13 @@ int Equalizer_getParameter(EffectContext     *pContext,
    + 
    +     case EQ_PARAM_GET_PRESET_NAME:
    +         param2 = *pParamTemp;
    +-        if (param2 >= EqualizerGetNumPresets()) {
    +-        //if (param2 >= 20) {     // AGO FIX
    ++        if ((param2 < 0 && param2 != PRESET_CUSTOM) ||  param2 >= EqualizerGetNumPresets()) {
    +             status = -EINVAL;
    ++            if (param2 < 0) {
    ++                android_errorWriteLog(0x534e4554, "32448258");
    ++                ALOGE("\tERROR Equalizer_getParameter() EQ_PARAM_GET_PRESET_NAME preset %d",
    ++                        param2);
    ++            }
    +             break;
    +         }
    +         name = (char *)pValue;
    +@@ -2479,8 +2495,12 @@ int Equalizer_setParameter (EffectContext *pContext, void *pParam, void *pValue)
    +         band =  *pParamTemp;
    +         level = (int32_t)(*(int16_t *)pValue);
    +         //ALOGV("\tEqualizer_setParameter() EQ_PARAM_BAND_LEVEL band %d, level %d", band, level);
    +-        if (band >= FIVEBAND_NUMBANDS) {
    ++        if (band < 0 || band >= FIVEBAND_NUMBANDS) {
    +             status = -EINVAL;
    ++            if (band < 0) {
    ++                android_errorWriteLog(0x534e4554, "32095626");
    ++                ALOGE("\tERROR Equalizer_setParameter() EQ_PARAM_BAND_LEVEL band %d", band);
    ++            }
    +             break;
    +         }
    +         EqualizerSetBandLevel(pContext, band, level);
    +diff --git a/media/libeffects/visualizer/EffectVisualizer.cpp b/media/libeffects/visualizer/EffectVisualizer.cpp
    +index 21fddb1..b7d27d6 100644
    +--- a/media/libeffects/visualizer/EffectVisualizer.cpp
    ++++ b/media/libeffects/visualizer/EffectVisualizer.cpp
    +@@ -59,6 +59,8 @@ enum visualizer_state_e {
    + 
    + #define DISCARD_MEASUREMENTS_TIME_MS 2000 // discard measurements older than this number of ms
    + 
    ++#define MAX_LATENCY_MS 3000 // 3 seconds of latency for audio pipeline
    ++
    + // maximum number of buffers for which we keep track of the measurements
    + #define MEASUREMENT_WINDOW_MAX_SIZE_IN_BUFFERS 25 // note: buffer index is stored in uint8_t
    + 
    +@@ -521,18 +523,29 @@ int Visualizer_command(effect_handle_t self, uint32_t cmdCode, uint32_t cmdSize,
    +             break;
    +         }
    +         switch (*(uint32_t *)p->data) {
    +-        case VISUALIZER_PARAM_CAPTURE_SIZE:
    +-            pContext->mCaptureSize = *((uint32_t *)p->data + 1);
    +-            ALOGV("set mCaptureSize = %" PRIu32, pContext->mCaptureSize);
    +-            break;
    ++        case VISUALIZER_PARAM_CAPTURE_SIZE: {
    ++            const uint32_t captureSize = *((uint32_t *)p->data + 1);
    ++            if (captureSize > VISUALIZER_CAPTURE_SIZE_MAX) {
    ++                android_errorWriteLog(0x534e4554, "31781965");
    ++                *(int32_t *)pReplyData = -EINVAL;
    ++                ALOGW("set mCaptureSize = %u > %u", captureSize, VISUALIZER_CAPTURE_SIZE_MAX);
    ++            } else {
    ++                pContext->mCaptureSize = captureSize;
    ++                ALOGV("set mCaptureSize = %u", captureSize);
    ++            }
    ++            } break;
    +         case VISUALIZER_PARAM_SCALING_MODE:
    +             pContext->mScalingMode = *((uint32_t *)p->data + 1);
    +             ALOGV("set mScalingMode = %" PRIu32, pContext->mScalingMode);
    +             break;
    +-        case VISUALIZER_PARAM_LATENCY:
    +-            pContext->mLatency = *((uint32_t *)p->data + 1);
    +-            ALOGV("set mLatency = %" PRIu32, pContext->mLatency);
    +-            break;
    ++        case VISUALIZER_PARAM_LATENCY: {
    ++            uint32_t latency = *((uint32_t *)p->data + 1);
    ++            if (latency > MAX_LATENCY_MS) {
    ++                latency = MAX_LATENCY_MS; // clamp latency b/31781965
    ++            }
    ++            pContext->mLatency = latency;
    ++            ALOGV("set mLatency = %u", latency);
    ++            } break;
    +         case VISUALIZER_PARAM_MEASUREMENT_MODE:
    +             pContext->mMeasurementMode = *((uint32_t *)p->data + 1);
    +             ALOGV("set mMeasurementMode = %" PRIu32, pContext->mMeasurementMode);
    +@@ -571,10 +584,18 @@ int Visualizer_command(effect_handle_t self, uint32_t cmdCode, uint32_t cmdSize,
    +                 if (latencyMs < 0) {
    +                     latencyMs = 0;
    +                 }
    +-                const uint32_t deltaSmpl =
    +-                    pContext->mConfig.inputCfg.samplingRate * latencyMs / 1000;
    +-                int32_t capturePoint = pContext->mCaptureIdx - captureSize - deltaSmpl;
    ++                uint32_t deltaSmpl = captureSize
    ++                        + pContext->mConfig.inputCfg.samplingRate * latencyMs / 1000;
    ++
    ++                // large sample rate, latency, or capture size, could cause overflow.
    ++                // do not offset more than the size of buffer.
    ++                if (deltaSmpl > CAPTURE_BUF_SIZE) {
    ++                    android_errorWriteLog(0x534e4554, "31781965");
    ++                    deltaSmpl = CAPTURE_BUF_SIZE;
    ++                }
    + 
    ++                int32_t capturePoint = pContext->mCaptureIdx - deltaSmpl;
    ++                // a negative capturePoint means we wrap the buffer.
    +                 if (capturePoint < 0) {
    +                     uint32_t size = -capturePoint;
    +                     if (size > captureSize) {
     diff --git a/media/libstagefright/ACodec.cpp b/media/libstagefright/ACodec.cpp
     index 37fd5a5..77a2a39 100644
     --- a/media/libstagefright/ACodec.cpp
    @@ -268,6 +417,43 @@ index 15ff569..0e9b4e6 100644
      
          (*buffer)->setObserver(this);
          (*buffer)->add_ref();
    +diff --git a/media/libstagefright/VBRISeeker.cpp b/media/libstagefright/VBRISeeker.cpp
    +index 58f2c60..5b8f23a 100644
    +--- a/media/libstagefright/VBRISeeker.cpp
    ++++ b/media/libstagefright/VBRISeeker.cpp
    +@@ -83,8 +83,23 @@ sp<VBRISeeker> VBRISeeker::CreateFromSource(
    +          scale,
    +          entrySize);
    + 
    ++    if (entrySize > 4) {
    ++        ALOGE("invalid VBRI entry size: %zu", entrySize);
    ++        return NULL;
    ++    }
    ++
    ++    sp<VBRISeeker> seeker = new (std::nothrow) VBRISeeker;
    ++    if (seeker == NULL) {
    ++        ALOGW("Couldn't allocate VBRISeeker");
    ++        return NULL;
    ++    }
    ++
    +     size_t totalEntrySize = numEntries * entrySize;
    +-    uint8_t *buffer = new uint8_t[totalEntrySize];
    ++    uint8_t *buffer = new (std::nothrow) uint8_t[totalEntrySize];
    ++    if (!buffer) {
    ++        ALOGW("Couldn't allocate %zu bytes", totalEntrySize);
    ++        return NULL;
    ++    }
    + 
    +     n = source->readAt(pos + sizeof(vbriHeader), buffer, totalEntrySize);
    +     if (n < (ssize_t)totalEntrySize) {
    +@@ -94,7 +109,6 @@ sp<VBRISeeker> VBRISeeker::CreateFromSource(
    +         return NULL;
    +     }
    + 
    +-    sp<VBRISeeker> seeker = new VBRISeeker;
    +     seeker->mBasePos = post_id3_pos + frameSize;
    +     // only update mDurationUs if the calculated duration is valid (non zero)
    +     // otherwise, leave duration at -1 so that getDuration() and getOffsetForTime()
     diff --git a/media/libstagefright/foundation/MediaBufferGroup.cpp b/media/libstagefright/foundation/MediaBufferGroup.cpp
     index 54f768a..1334f93 100644
     --- a/media/libstagefright/foundation/MediaBufferGroup.cpp
    @@ -289,6 +475,111 @@ index 54f768a..1334f93 100644
      void MediaBufferGroup::signalBufferReturned(MediaBuffer *) {
          mCondition.signal();
      }
    +diff --git a/media/libstagefright/id3/ID3.cpp b/media/libstagefright/id3/ID3.cpp
    +index 3942158..33f79fd 100644
    +--- a/media/libstagefright/id3/ID3.cpp
    ++++ b/media/libstagefright/id3/ID3.cpp
    +@@ -836,20 +836,21 @@ void ID3::Iterator::findFrame() {
    +     }
    + }
    + 
    +-static size_t StringSize(const uint8_t *start, uint8_t encoding) {
    ++// return includes terminator;  if unterminated, returns > limit
    ++static size_t StringSize(const uint8_t *start, size_t limit, uint8_t encoding) {
    ++
    +     if (encoding == 0x00 || encoding == 0x03) {
    +         // ISO 8859-1 or UTF-8
    +-        return strlen((const char *)start) + 1;
    ++        return strnlen((const char *)start, limit) + 1;
    +     }
    + 
    +     // UCS-2
    +     size_t n = 0;
    +-    while (start[n] != '\0' || start[n + 1] != '\0') {
    ++    while ((n+1 < limit) && (start[n] != '\0' || start[n + 1] != '\0')) {
    +         n += 2;
    +     }
    +-
    +-    // Add size of null termination.
    +-    return n + 2;
    ++    n += 2;
    ++    return n;
    + }
    + 
    + const void *
    +@@ -870,11 +871,19 @@ ID3::getAlbumArt(size_t *length, String8 *mime) const {
    + 
    +         if (mVersion == ID3_V2_3 || mVersion == ID3_V2_4) {
    +             uint8_t encoding = data[0];
    +-            mime->setTo((const char *)&data[1]);
    +-            size_t mimeLen = strlen((const char *)&data[1]) + 1;
    ++            size_t consumed = 1;
    ++
    ++            // *always* in an 8-bit encoding
    ++            size_t mimeLen = StringSize(&data[consumed], size - consumed, 0x00);
    ++            if (mimeLen > size - consumed) {
    ++                ALOGW("bogus album art size: mime");
    ++                return NULL;
    ++            }
    ++            mime->setTo((const char *)&data[consumed]);
    ++            consumed += mimeLen;
    + 
    + #if 0
    +-            uint8_t picType = data[1 + mimeLen];
    ++            uint8_t picType = data[consumed];
    +             if (picType != 0x03) {
    +                 // Front Cover Art
    +                 it.next();
    +@@ -882,20 +891,30 @@ ID3::getAlbumArt(size_t *length, String8 *mime) const {
    +             }
    + #endif
    + 
    +-            size_t descLen = StringSize(&data[2 + mimeLen], encoding);
    ++            consumed++;
    ++            if (consumed >= size) {
    ++                ALOGW("bogus album art size: pic type");
    ++                return NULL;
    ++            }
    ++
    ++            size_t descLen = StringSize(&data[consumed], size - consumed, encoding);
    ++            consumed += descLen;
    + 
    +-            if (size < 2 ||
    +-                    size - 2 < mimeLen ||
    +-                    size - 2 - mimeLen < descLen) {
    +-                ALOGW("bogus album art sizes");
    ++            if (consumed >= size) {
    ++                ALOGW("bogus album art size: description");
    +                 return NULL;
    +             }
    +-            *length = size - 2 - mimeLen - descLen;
    + 
    +-            return &data[2 + mimeLen + descLen];
    ++            *length = size - consumed;
    ++
    ++            return &data[consumed];
    +         } else {
    +             uint8_t encoding = data[0];
    + 
    ++            if (size <= 5) {
    ++                return NULL;
    ++            }
    ++
    +             if (!memcmp(&data[1], "PNG", 3)) {
    +                 mime->setTo("image/png");
    +             } else if (!memcmp(&data[1], "JPG", 3)) {
    +@@ -915,7 +934,10 @@ ID3::getAlbumArt(size_t *length, String8 *mime) const {
    +             }
    + #endif
    + 
    +-            size_t descLen = StringSize(&data[5], encoding);
    ++            size_t descLen = StringSize(&data[5], size - 5, encoding);
    ++            if (descLen > size - 5) {
    ++                return NULL;
    ++            }
    + 
    +             *length = size - 5 - descLen;
    + 
     diff --git a/media/libstagefright/omx/Android.mk b/media/libstagefright/omx/Android.mk
     index e4fbd81..8fc788f 100644
     --- a/media/libstagefright/omx/Android.mk
    @@ -332,7 +623,7 @@ index 6132a2c..7f0d270 100644
      
      void OMXMaster::addPlugin(const char *libname) {
     diff --git a/media/libstagefright/omx/OMXNodeInstance.cpp b/media/libstagefright/omx/OMXNodeInstance.cpp
    -index 5f903a9..3cf9c3b 100644
    +index 5f903a9..2fa9989 100644
     --- a/media/libstagefright/omx/OMXNodeInstance.cpp
     +++ b/media/libstagefright/omx/OMXNodeInstance.cpp
     @@ -795,7 +795,11 @@ status_t OMXNodeInstance::useBuffer(
    @@ -347,7 +638,21 @@ index 5f903a9..3cf9c3b 100644
          OMX_U8 *data = static_cast<OMX_U8 *>(params->pointer());
          // allocate backup buffer
          if (useBackup) {
    -@@ -1286,7 +1290,11 @@ status_t OMXNodeInstance::allocateBufferWithBackup(
    +@@ -805,13 +809,6 @@ status_t OMXNodeInstance::useBuffer(
    +         }
    +         memset(data, 0, allottedSize);
    + 
    +-        // if we are not connecting the buffers, the sizes must match
    +-        if (allottedSize != params->size()) {
    +-            CLOG_ERROR(useBuffer, BAD_VALUE, SIMPLE_BUFFER(portIndex, (size_t)allottedSize, data));
    +-            delete[] data;
    +-            return BAD_VALUE;
    +-        }
    +-
    +         buffer_meta = new BufferMeta(
    +                 params, portIndex, false /* copyToOmx */, false /* copyFromOmx */, data);
    +     } else {
    +@@ -1286,7 +1283,11 @@ status_t OMXNodeInstance::allocateBufferWithBackup(
          }
      
          // metadata buffers are not connected cross process; only copy if not meta
    @@ -359,7 +664,7 @@ index 5f903a9..3cf9c3b 100644
      
          BufferMeta *buffer_meta = new BufferMeta(
                  params, portIndex,
    -@@ -1404,10 +1412,30 @@ status_t OMXNodeInstance::emptyBuffer(
    +@@ -1404,10 +1405,30 @@ status_t OMXNodeInstance::emptyBuffer(
          BufferMeta *buffer_meta =
              static_cast<BufferMeta *>(header->pAppPrivate);
      
    @@ -441,6 +746,24 @@ index 1785a03..d5499f0 100644
              ALOGE("openRecord() permission denied: recording not allowed");
              lStatus = PERMISSION_DENIED;
              goto Exit;
    +diff --git a/services/audioflinger/Effects.cpp b/services/audioflinger/Effects.cpp
    +index 9711f2d..bb3067f 100644
    +--- a/services/audioflinger/Effects.cpp
    ++++ b/services/audioflinger/Effects.cpp
    +@@ -600,6 +600,13 @@ status_t AudioFlinger::EffectModule::command(uint32_t cmdCode,
    +         android_errorWriteLog(0x534e4554, "29251553");
    +         return -EINVAL;
    +     }
    ++    if (cmdCode == EFFECT_CMD_GET_PARAM &&
    ++            (sizeof(effect_param_t) > cmdSize ||
    ++                    ((effect_param_t *)pCmdData)->psize > cmdSize
    ++                                                          - sizeof(effect_param_t))) {
    ++        android_errorWriteLog(0x534e4554, "32438594");
    ++        return -EINVAL;
    ++    }
    +     if ((cmdCode == EFFECT_CMD_SET_PARAM
    +             || cmdCode == EFFECT_CMD_SET_PARAM_DEFERRED) &&  // DEFERRED not generally used
    +         (sizeof(effect_param_t) > cmdSize
     diff --git a/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp b/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp
     index c9b3abc..57d26e6 100644
     --- a/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp
    diff --git a/frameworks_base.patch b/frameworks_base.patch
    index 8104107..6a9dbee 100644
    --- a/frameworks_base.patch
    +++ b/frameworks_base.patch
    @@ -24,6 +24,127 @@ index aed7a36..bf96926 100644
                  // if canceling out of addAccount and the original state caused us to skip this,
                  // finish this activity
                  if (mAccounts.isEmpty()) {
    +diff --git a/core/jni/com_android_internal_os_Zygote.cpp b/core/jni/com_android_internal_os_Zygote.cpp
    +index d1fe07b..f94c861 100644
    +--- a/core/jni/com_android_internal_os_Zygote.cpp
    ++++ b/core/jni/com_android_internal_os_Zygote.cpp
    +@@ -454,6 +454,20 @@ static pid_t ForkAndSpecializeCommon(JNIEnv* env, uid_t uid, gid_t gid, jintArra
    +   SetForkLoad(true);
    + #endif
    + 
    ++  sigset_t sigchld;
    ++  sigemptyset(&sigchld);
    ++  sigaddset(&sigchld, SIGCHLD);
    ++
    ++  // Temporarily block SIGCHLD during forks. The SIGCHLD handler might
    ++  // log, which would result in the logging FDs we close being reopened.
    ++  // This would cause failures because the FDs are not whitelisted.
    ++  //
    ++  // Note that the zygote process is single threaded at this point.
    ++  if (sigprocmask(SIG_BLOCK, &sigchld, nullptr) == -1) {
    ++    ALOGE("sigprocmask(SIG_SETMASK, { SIGCHLD }) failed: %s", strerror(errno));
    ++    RuntimeAbort(env, __LINE__, "Call to sigprocmask(SIG_BLOCK, { SIGCHLD }) failed.");
    ++  }
    ++
    +   // Close any logging related FDs before we start evaluating the list of
    +   // file descriptors.
    +   __android_log_close();
    +@@ -485,6 +499,11 @@ static pid_t ForkAndSpecializeCommon(JNIEnv* env, uid_t uid, gid_t gid, jintArra
    +       RuntimeAbort(env, __LINE__, "Unable to reopen whitelisted descriptors.");
    +     }
    + 
    ++    if (sigprocmask(SIG_UNBLOCK, &sigchld, nullptr) == -1) {
    ++      ALOGE("sigprocmask(SIG_SETMASK, { SIGCHLD }) failed: %s", strerror(errno));
    ++      RuntimeAbort(env, __LINE__, "Call to sigprocmask(SIG_UNBLOCK, { SIGCHLD }) failed.");
    ++    }
    ++
    +     // Keep capabilities across UID change, unless we're staying root.
    +     if (uid != 0) {
    +       EnableKeepCapabilities(env);
    +@@ -618,6 +637,11 @@ static pid_t ForkAndSpecializeCommon(JNIEnv* env, uid_t uid, gid_t gid, jintArra
    +     SetForkLoad(false);
    + #endif
    + 
    ++    // We blocked SIGCHLD prior to a fork, we unblock it here.
    ++    if (sigprocmask(SIG_UNBLOCK, &sigchld, nullptr) == -1) {
    ++      ALOGE("sigprocmask(SIG_SETMASK, { SIGCHLD }) failed: %s", strerror(errno));
    ++      RuntimeAbort(env, __LINE__, "Call to sigprocmask(SIG_UNBLOCK, { SIGCHLD }) failed.");
    ++    }
    +   }
    +   return pid;
    + }
    +diff --git a/core/jni/fd_utils-inl.h b/core/jni/fd_utils-inl.h
    +index c67662b..d1129a3e 100644
    +--- a/core/jni/fd_utils-inl.h
    ++++ b/core/jni/fd_utils-inl.h
    +@@ -239,9 +239,22 @@ class FileDescriptorInfo {
    +     is_sock(false) {
    +   }
    + 
    ++  static bool StartsWith(const std::string& str, const std::string& prefix) {
    ++    return str.compare(0, prefix.size(), prefix) == 0;
    ++  }
    ++
    ++  static bool EndsWith(const std::string& str, const std::string& suffix) {
    ++    if (suffix.size() > str.size()) {
    ++      return false;
    ++    }
    ++
    ++    return str.compare(str.size() - suffix.size(), suffix.size(), suffix) == 0;
    ++  }
    ++
    +   // Returns true iff. a given path is whitelisted. A path is whitelisted
    +   // if it belongs to the whitelist (see kPathWhitelist) or if it's a path
    +-  // under /system/framework that ends with ".jar".
    ++  // under /system/framework that ends with ".jar" or if it is a system
    ++  // framework overlay.
    +   static bool IsWhitelisted(const std::string& path) {
    +     for (size_t i = 0; i < (sizeof(kPathWhitelist) / sizeof(kPathWhitelist[0])); ++i) {
    +       if (kPathWhitelist[i] == path) {
    +@@ -251,10 +264,41 @@ class FileDescriptorInfo {
    + 
    +     static const std::string kFrameworksPrefix = "/system/framework/";
    +     static const std::string kJarSuffix = ".jar";
    +-    if (path.compare(0, kFrameworksPrefix.size(), kFrameworksPrefix) == 0 &&
    +-        path.compare(path.size() - kJarSuffix.size(), kJarSuffix.size(), kJarSuffix) == 0) {
    ++    if (StartsWith(path, kFrameworksPrefix) && EndsWith(path, kJarSuffix)) {
    +       return true;
    +     }
    ++
    ++    // Whitelist files needed for Runtime Resource Overlay, like these:
    ++    // /system/vendor/overlay/framework-res.apk
    ++    // /system/vendor/overlay-subdir/pg/framework-res.apk
    ++    // /data/resource-cache/system@vendor@overlay@framework-res.apk@idmap
    ++    // /data/resource-cache/system@vendor@overlay-subdir@pg@framework-res.apk@idmap
    ++    // See AssetManager.cpp for more details on overlay-subdir.
    ++    static const std::string kOverlayDir = "/system/vendor/overlay/";
    ++    static const std::string kVendorOverlayDir = "/vendor/overlay";
    ++    static const std::string kOverlaySubdir = "/system/vendor/overlay-subdir/";
    ++    static const std::string kApkSuffix = ".apk";
    ++
    ++    if ((StartsWith(path, kOverlayDir) || StartsWith(path, kOverlaySubdir)
    ++         || StartsWith(path, kVendorOverlayDir))
    ++        && EndsWith(path, kApkSuffix)
    ++        && path.find("/../") == std::string::npos) {
    ++      return true;
    ++    }
    ++
    ++    static const std::string kOverlayIdmapPrefix = "/data/resource-cache/";
    ++    static const std::string kOverlayIdmapSuffix = ".apk@idmap";
    ++    if (StartsWith(path, kOverlayIdmapPrefix) && EndsWith(path, kOverlayIdmapSuffix)
    ++        && path.find("/../") == std::string::npos) {
    ++      return true;
    ++    }
    ++
    ++    // All regular files that are placed under this path are whitelisted automatically.
    ++    static const std::string kZygoteWhitelistPath = "/vendor/zygote_whitelist/";
    ++    if (StartsWith(path, kZygoteWhitelistPath) && path.find("/../") == std::string::npos) {
    ++      return true;
    ++    }
    ++
    +     return false;
    +   }
    + 
     diff --git a/core/res/res/xml/config_webview_packages.xml b/core/res/res/xml/config_webview_packages.xml
     index f062b59..574f7c1 100644
     --- a/core/res/res/xml/config_webview_packages.xml
    @@ -53,6 +174,18 @@ index f062b59..574f7c1 100644
     +  <!-- The default WebView implementation -->
     +    <webviewprovider description="AOSP WebView" packageName="com.android.webview" availableByDefault="true" isFallback="true" />
      </webviewproviders>
    +diff --git a/libs/androidfw/AssetManager.cpp b/libs/androidfw/AssetManager.cpp
    +index 07044d0..7a10343 100644
    +--- a/libs/androidfw/AssetManager.cpp
    ++++ b/libs/androidfw/AssetManager.cpp
    +@@ -804,6 +804,7 @@ void AssetManager::addSystemOverlays(const char* pathOverlaysList,
    +             sharedRes->add(oass, oidmap, offset + 1, false);
    +             const_cast<AssetManager*>(this)->mAssetPaths.add(oap);
    +             const_cast<AssetManager*>(this)->mZipSet.addOverlay(targetPackagePath, oap);
    ++            delete oidmap;
    +         }
    +     }
    + 
     diff --git a/libs/hwui/Android.mk b/libs/hwui/Android.mk
     index cacfce1..0b177b9 100644
     --- a/libs/hwui/Android.mk
    @@ -78,6 +211,20 @@ index 2c9c9d9..7c187fb 100644
      }
      
      /**
    +diff --git a/packages/ExternalStorageProvider/src/com/android/externalstorage/ExternalStorageProvider.java b/packages/ExternalStorageProvider/src/com/android/externalstorage/ExternalStorageProvider.java
    +index 3ef9b8e..10e5dcc 100644
    +--- a/packages/ExternalStorageProvider/src/com/android/externalstorage/ExternalStorageProvider.java
    ++++ b/packages/ExternalStorageProvider/src/com/android/externalstorage/ExternalStorageProvider.java
    +@@ -161,7 +161,8 @@ public class ExternalStorageProvider extends DocumentsProvider {
    +                     final VolumeInfo privateVol = mStorageManager.findPrivateForEmulated(volume);
    +                     title = mStorageManager.getBestVolumeDescription(privateVol);
    +                 }
    +-            } else if (volume.getType() == VolumeInfo.TYPE_PUBLIC) {
    ++            } else if (volume.getType() == VolumeInfo.TYPE_PUBLIC
    ++                    && volume.getMountUserId() == userId) {
    +                 rootId = volume.getFsUuid();
    +                 title = mStorageManager.getBestVolumeDescription(volume);
    +             } else {
     diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationGuts.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationGuts.java
     index c850a25..1829e59 100644
     --- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationGuts.java
    @@ -405,6 +552,32 @@ index 3fffefb..49fe79c 100644
              }
              if (receivers.size() > 0) {
                  pw.print(prefix); pw.println("Receivers:");
    +diff --git a/services/net/java/android/net/dhcp/DhcpClient.java b/services/net/java/android/net/dhcp/DhcpClient.java
    +index ffbea9f..8dd05b1 100644
    +--- a/services/net/java/android/net/dhcp/DhcpClient.java
    ++++ b/services/net/java/android/net/dhcp/DhcpClient.java
    +@@ -40,6 +40,7 @@ import android.os.SystemClock;
    + import android.system.ErrnoException;
    + import android.system.Os;
    + import android.system.PacketSocketAddress;
    ++import android.util.EventLog;
    + import android.util.Log;
    + import android.util.SparseArray;
    + import android.util.TimeUtils;
    +@@ -369,6 +370,13 @@ public class DhcpClient extends StateMachine {
    +                     if (PACKET_DBG) {
    +                         Log.d(TAG, HexDump.dumpHexString(mPacket, 0, length));
    +                     }
    ++                    if (e.errorCode == DhcpErrorEvent.DHCP_NO_COOKIE) {
    ++                        int snetTagId = 0x534e4554;
    ++                        String bugId = "31850211";
    ++                        int uid = -1;
    ++                        String data = DhcpPacket.ParseException.class.getName();
    ++                        EventLog.writeEvent(snetTagId, bugId, uid, data);
    ++                    }
    +                     logError(e.errorCode);
    +                 }
    +             }
     diff --git a/services/tests/Android.mk b/services/tests/Android.mk
     deleted file mode 100644
     index 40369ee..0000000
    diff --git a/frameworks_native.patch b/frameworks_native.patch
    index 4bc0763..81db338 100644
    --- a/frameworks_native.patch
    +++ b/frameworks_native.patch
    @@ -51,6 +51,27 @@ index 5885738..86c315c 100644
          return ok;
      }
      
    +diff --git a/include/binder/Parcel.h b/include/binder/Parcel.h
    +index 1c355c4..2490b82 100644
    +--- a/include/binder/Parcel.h
    ++++ b/include/binder/Parcel.h
    +@@ -589,8 +589,16 @@ status_t Parcel::unsafeReadTypedVector(
    +         return UNEXPECTED_NULL;
    +     }
    + 
    ++    if (val->max_size() < size) {
    ++        return NO_MEMORY;
    ++    }
    ++
    +     val->resize(size);
    + 
    ++    if (val->size() < size) {
    ++        return NO_MEMORY;
    ++    }
    ++
    +     for (auto& v: *val) {
    +         status = (this->*read_func)(&v);
    + 
     diff --git a/include/gui/ISurfaceComposer.h b/include/gui/ISurfaceComposer.h
     index 74a4123..8dc6f6a 100644
     --- a/include/gui/ISurfaceComposer.h
    @@ -122,6 +143,18 @@ index 46feb1c..1b4a9c5 100644
      
      LOCAL_MODULE := libgui
      
    +diff --git a/libs/gui/BufferQueueConsumer.cpp b/libs/gui/BufferQueueConsumer.cpp
    +index ca2a374..73d2042 100644
    +--- a/libs/gui/BufferQueueConsumer.cpp
    ++++ b/libs/gui/BufferQueueConsumer.cpp
    +@@ -715,6 +715,7 @@ status_t BufferQueueConsumer::setTransformHint(uint32_t hint) {
    + }
    + 
    + sp<NativeHandle> BufferQueueConsumer::getSidebandStream() const {
    ++    Mutex::Autolock lock(mCore->mMutex);
    +     return mCore->mSidebandStream;
    + }
    + 
     diff --git a/libs/gui/ISurfaceComposer.cpp b/libs/gui/ISurfaceComposer.cpp
     index f0b0ada..3577a33 100644
     --- a/libs/gui/ISurfaceComposer.cpp
    
    From 443401f20fd99df366eae9b1a9e5bce218187db4 Mon Sep 17 00:00:00 2001
    From: AndDiSa <anddisa@googlemail.com>
    Date: Sat, 7 Jan 2017 10:38:10 +0100
    Subject: [PATCH 060/159] update patches
    
    Change-Id: I4eff189cae2df9e07d42f95d9c698d452019e7c5
    ---
     build.patch             |  23 ---
     frameworks_av.patch     | 329 +---------------------------------------
     frameworks_base.patch   | 229 +---------------------------
     frameworks_native.patch |  33 ----
     4 files changed, 6 insertions(+), 608 deletions(-)
    
    diff --git a/build.patch b/build.patch
    index 663e46c..b699411 100644
    --- a/build.patch
    +++ b/build.patch
    @@ -1,13 +1,3 @@
    -diff --git a/core/build_id.mk b/core/build_id.mk
    -index c3d6c40..1576856 100644
    ---- a/core/build_id.mk
    -+++ b/core/build_id.mk
    -@@ -18,4 +18,4 @@
    - # (like "CRB01").  It must be a single word, and is
    - # capitalized by convention.
    - 
    --export BUILD_ID=NMF26O
    -+export BUILD_ID=NMF26V
     diff --git a/core/main.mk b/core/main.mk
     index a612f83..921eb32 100644
     --- a/core/main.mk
    @@ -223,19 +213,6 @@ index 0000000..9c12bc0
     +
     +ALL_PREBUILT += $(INSTALLED_KERNEL_TARGET)
     +endif
    -diff --git a/core/version_defaults.mk b/core/version_defaults.mk
    -index 2c8a21f..550fc70 100644
    ---- a/core/version_defaults.mk
    -+++ b/core/version_defaults.mk
    -@@ -114,7 +114,7 @@ ifeq "" "$(PLATFORM_SECURITY_PATCH)"
    -     #  It must be of the form "YYYY-MM-DD" on production devices.
    -     #  It must match one of the Android Security Patch Level strings of the Public Security Bulletins.
    -     #  If there is no $PLATFORM_SECURITY_PATCH set, keep it empty.
    --      PLATFORM_SECURITY_PATCH := 2016-12-05
    -+      PLATFORM_SECURITY_PATCH := 2017-01-05
    - endif
    - 
    - ifeq "" "$(PLATFORM_BASE_OS)"
     diff --git a/core/version_defaults_BACKUP_20377.mk b/core/version_defaults_BACKUP_20377.mk
     new file mode 100644
     index 0000000..eb97b11
    diff --git a/frameworks_av.patch b/frameworks_av.patch
    index b5436c6..3d65417 100644
    --- a/frameworks_av.patch
    +++ b/frameworks_av.patch
    @@ -33,155 +33,6 @@ index 3051406..870bb9b 100644
      
          size_t buffers() const { return mBuffers.size(); }
      
    -diff --git a/media/libeffects/lvm/wrapper/Bundle/EffectBundle.cpp b/media/libeffects/lvm/wrapper/Bundle/EffectBundle.cpp
    -index a1892e4..ed38584 100644
    ---- a/media/libeffects/lvm/wrapper/Bundle/EffectBundle.cpp
    -+++ b/media/libeffects/lvm/wrapper/Bundle/EffectBundle.cpp
    -@@ -2357,8 +2357,12 @@ int Equalizer_getParameter(EffectContext     *pContext,
    - 
    -     case EQ_PARAM_BAND_LEVEL:
    -         param2 = *pParamTemp;
    --        if (param2 >= FIVEBAND_NUMBANDS) {
    -+        if (param2 < 0 || param2 >= FIVEBAND_NUMBANDS) {
    -             status = -EINVAL;
    -+            if (param2 < 0) {
    -+                android_errorWriteLog(0x534e4554, "32438598");
    -+                ALOGW("\tERROR Equalizer_getParameter() EQ_PARAM_BAND_LEVEL band %d", param2);
    -+            }
    -             break;
    -         }
    -         *(int16_t *)pValue = (int16_t)EqualizerGetBandLevel(pContext, param2);
    -@@ -2368,8 +2372,12 @@ int Equalizer_getParameter(EffectContext     *pContext,
    - 
    -     case EQ_PARAM_CENTER_FREQ:
    -         param2 = *pParamTemp;
    --        if (param2 >= FIVEBAND_NUMBANDS) {
    -+        if (param2 < 0 || param2 >= FIVEBAND_NUMBANDS) {
    -             status = -EINVAL;
    -+            if (param2 < 0) {
    -+                android_errorWriteLog(0x534e4554, "32436341");
    -+                ALOGW("\tERROR Equalizer_getParameter() EQ_PARAM_CENTER_FREQ band %d", param2);
    -+            }
    -             break;
    -         }
    -         *(int32_t *)pValue = EqualizerGetCentreFrequency(pContext, param2);
    -@@ -2379,8 +2387,12 @@ int Equalizer_getParameter(EffectContext     *pContext,
    - 
    -     case EQ_PARAM_BAND_FREQ_RANGE:
    -         param2 = *pParamTemp;
    --        if (param2 >= FIVEBAND_NUMBANDS) {
    -+        if (param2 < 0 || param2 >= FIVEBAND_NUMBANDS) {
    -             status = -EINVAL;
    -+            if (param2 < 0) {
    -+                android_errorWriteLog(0x534e4554, "32247948");
    -+                ALOGW("\tERROR Equalizer_getParameter() EQ_PARAM_BAND_FREQ_RANGE band %d", param2);
    -+            }
    -             break;
    -         }
    -         EqualizerGetBandFreqRange(pContext, param2, (uint32_t *)pValue, ((uint32_t *)pValue + 1));
    -@@ -2407,9 +2419,13 @@ int Equalizer_getParameter(EffectContext     *pContext,
    - 
    -     case EQ_PARAM_GET_PRESET_NAME:
    -         param2 = *pParamTemp;
    --        if (param2 >= EqualizerGetNumPresets()) {
    --        //if (param2 >= 20) {     // AGO FIX
    -+        if ((param2 < 0 && param2 != PRESET_CUSTOM) ||  param2 >= EqualizerGetNumPresets()) {
    -             status = -EINVAL;
    -+            if (param2 < 0) {
    -+                android_errorWriteLog(0x534e4554, "32448258");
    -+                ALOGE("\tERROR Equalizer_getParameter() EQ_PARAM_GET_PRESET_NAME preset %d",
    -+                        param2);
    -+            }
    -             break;
    -         }
    -         name = (char *)pValue;
    -@@ -2479,8 +2495,12 @@ int Equalizer_setParameter (EffectContext *pContext, void *pParam, void *pValue)
    -         band =  *pParamTemp;
    -         level = (int32_t)(*(int16_t *)pValue);
    -         //ALOGV("\tEqualizer_setParameter() EQ_PARAM_BAND_LEVEL band %d, level %d", band, level);
    --        if (band >= FIVEBAND_NUMBANDS) {
    -+        if (band < 0 || band >= FIVEBAND_NUMBANDS) {
    -             status = -EINVAL;
    -+            if (band < 0) {
    -+                android_errorWriteLog(0x534e4554, "32095626");
    -+                ALOGE("\tERROR Equalizer_setParameter() EQ_PARAM_BAND_LEVEL band %d", band);
    -+            }
    -             break;
    -         }
    -         EqualizerSetBandLevel(pContext, band, level);
    -diff --git a/media/libeffects/visualizer/EffectVisualizer.cpp b/media/libeffects/visualizer/EffectVisualizer.cpp
    -index 21fddb1..b7d27d6 100644
    ---- a/media/libeffects/visualizer/EffectVisualizer.cpp
    -+++ b/media/libeffects/visualizer/EffectVisualizer.cpp
    -@@ -59,6 +59,8 @@ enum visualizer_state_e {
    - 
    - #define DISCARD_MEASUREMENTS_TIME_MS 2000 // discard measurements older than this number of ms
    - 
    -+#define MAX_LATENCY_MS 3000 // 3 seconds of latency for audio pipeline
    -+
    - // maximum number of buffers for which we keep track of the measurements
    - #define MEASUREMENT_WINDOW_MAX_SIZE_IN_BUFFERS 25 // note: buffer index is stored in uint8_t
    - 
    -@@ -521,18 +523,29 @@ int Visualizer_command(effect_handle_t self, uint32_t cmdCode, uint32_t cmdSize,
    -             break;
    -         }
    -         switch (*(uint32_t *)p->data) {
    --        case VISUALIZER_PARAM_CAPTURE_SIZE:
    --            pContext->mCaptureSize = *((uint32_t *)p->data + 1);
    --            ALOGV("set mCaptureSize = %" PRIu32, pContext->mCaptureSize);
    --            break;
    -+        case VISUALIZER_PARAM_CAPTURE_SIZE: {
    -+            const uint32_t captureSize = *((uint32_t *)p->data + 1);
    -+            if (captureSize > VISUALIZER_CAPTURE_SIZE_MAX) {
    -+                android_errorWriteLog(0x534e4554, "31781965");
    -+                *(int32_t *)pReplyData = -EINVAL;
    -+                ALOGW("set mCaptureSize = %u > %u", captureSize, VISUALIZER_CAPTURE_SIZE_MAX);
    -+            } else {
    -+                pContext->mCaptureSize = captureSize;
    -+                ALOGV("set mCaptureSize = %u", captureSize);
    -+            }
    -+            } break;
    -         case VISUALIZER_PARAM_SCALING_MODE:
    -             pContext->mScalingMode = *((uint32_t *)p->data + 1);
    -             ALOGV("set mScalingMode = %" PRIu32, pContext->mScalingMode);
    -             break;
    --        case VISUALIZER_PARAM_LATENCY:
    --            pContext->mLatency = *((uint32_t *)p->data + 1);
    --            ALOGV("set mLatency = %" PRIu32, pContext->mLatency);
    --            break;
    -+        case VISUALIZER_PARAM_LATENCY: {
    -+            uint32_t latency = *((uint32_t *)p->data + 1);
    -+            if (latency > MAX_LATENCY_MS) {
    -+                latency = MAX_LATENCY_MS; // clamp latency b/31781965
    -+            }
    -+            pContext->mLatency = latency;
    -+            ALOGV("set mLatency = %u", latency);
    -+            } break;
    -         case VISUALIZER_PARAM_MEASUREMENT_MODE:
    -             pContext->mMeasurementMode = *((uint32_t *)p->data + 1);
    -             ALOGV("set mMeasurementMode = %" PRIu32, pContext->mMeasurementMode);
    -@@ -571,10 +584,18 @@ int Visualizer_command(effect_handle_t self, uint32_t cmdCode, uint32_t cmdSize,
    -                 if (latencyMs < 0) {
    -                     latencyMs = 0;
    -                 }
    --                const uint32_t deltaSmpl =
    --                    pContext->mConfig.inputCfg.samplingRate * latencyMs / 1000;
    --                int32_t capturePoint = pContext->mCaptureIdx - captureSize - deltaSmpl;
    -+                uint32_t deltaSmpl = captureSize
    -+                        + pContext->mConfig.inputCfg.samplingRate * latencyMs / 1000;
    -+
    -+                // large sample rate, latency, or capture size, could cause overflow.
    -+                // do not offset more than the size of buffer.
    -+                if (deltaSmpl > CAPTURE_BUF_SIZE) {
    -+                    android_errorWriteLog(0x534e4554, "31781965");
    -+                    deltaSmpl = CAPTURE_BUF_SIZE;
    -+                }
    - 
    -+                int32_t capturePoint = pContext->mCaptureIdx - deltaSmpl;
    -+                // a negative capturePoint means we wrap the buffer.
    -                 if (capturePoint < 0) {
    -                     uint32_t size = -capturePoint;
    -                     if (size > captureSize) {
     diff --git a/media/libstagefright/ACodec.cpp b/media/libstagefright/ACodec.cpp
     index 37fd5a5..77a2a39 100644
     --- a/media/libstagefright/ACodec.cpp
    @@ -417,43 +268,6 @@ index 15ff569..0e9b4e6 100644
      
          (*buffer)->setObserver(this);
          (*buffer)->add_ref();
    -diff --git a/media/libstagefright/VBRISeeker.cpp b/media/libstagefright/VBRISeeker.cpp
    -index 58f2c60..5b8f23a 100644
    ---- a/media/libstagefright/VBRISeeker.cpp
    -+++ b/media/libstagefright/VBRISeeker.cpp
    -@@ -83,8 +83,23 @@ sp<VBRISeeker> VBRISeeker::CreateFromSource(
    -          scale,
    -          entrySize);
    - 
    -+    if (entrySize > 4) {
    -+        ALOGE("invalid VBRI entry size: %zu", entrySize);
    -+        return NULL;
    -+    }
    -+
    -+    sp<VBRISeeker> seeker = new (std::nothrow) VBRISeeker;
    -+    if (seeker == NULL) {
    -+        ALOGW("Couldn't allocate VBRISeeker");
    -+        return NULL;
    -+    }
    -+
    -     size_t totalEntrySize = numEntries * entrySize;
    --    uint8_t *buffer = new uint8_t[totalEntrySize];
    -+    uint8_t *buffer = new (std::nothrow) uint8_t[totalEntrySize];
    -+    if (!buffer) {
    -+        ALOGW("Couldn't allocate %zu bytes", totalEntrySize);
    -+        return NULL;
    -+    }
    - 
    -     n = source->readAt(pos + sizeof(vbriHeader), buffer, totalEntrySize);
    -     if (n < (ssize_t)totalEntrySize) {
    -@@ -94,7 +109,6 @@ sp<VBRISeeker> VBRISeeker::CreateFromSource(
    -         return NULL;
    -     }
    - 
    --    sp<VBRISeeker> seeker = new VBRISeeker;
    -     seeker->mBasePos = post_id3_pos + frameSize;
    -     // only update mDurationUs if the calculated duration is valid (non zero)
    -     // otherwise, leave duration at -1 so that getDuration() and getOffsetForTime()
     diff --git a/media/libstagefright/foundation/MediaBufferGroup.cpp b/media/libstagefright/foundation/MediaBufferGroup.cpp
     index 54f768a..1334f93 100644
     --- a/media/libstagefright/foundation/MediaBufferGroup.cpp
    @@ -475,111 +289,6 @@ index 54f768a..1334f93 100644
      void MediaBufferGroup::signalBufferReturned(MediaBuffer *) {
          mCondition.signal();
      }
    -diff --git a/media/libstagefright/id3/ID3.cpp b/media/libstagefright/id3/ID3.cpp
    -index 3942158..33f79fd 100644
    ---- a/media/libstagefright/id3/ID3.cpp
    -+++ b/media/libstagefright/id3/ID3.cpp
    -@@ -836,20 +836,21 @@ void ID3::Iterator::findFrame() {
    -     }
    - }
    - 
    --static size_t StringSize(const uint8_t *start, uint8_t encoding) {
    -+// return includes terminator;  if unterminated, returns > limit
    -+static size_t StringSize(const uint8_t *start, size_t limit, uint8_t encoding) {
    -+
    -     if (encoding == 0x00 || encoding == 0x03) {
    -         // ISO 8859-1 or UTF-8
    --        return strlen((const char *)start) + 1;
    -+        return strnlen((const char *)start, limit) + 1;
    -     }
    - 
    -     // UCS-2
    -     size_t n = 0;
    --    while (start[n] != '\0' || start[n + 1] != '\0') {
    -+    while ((n+1 < limit) && (start[n] != '\0' || start[n + 1] != '\0')) {
    -         n += 2;
    -     }
    --
    --    // Add size of null termination.
    --    return n + 2;
    -+    n += 2;
    -+    return n;
    - }
    - 
    - const void *
    -@@ -870,11 +871,19 @@ ID3::getAlbumArt(size_t *length, String8 *mime) const {
    - 
    -         if (mVersion == ID3_V2_3 || mVersion == ID3_V2_4) {
    -             uint8_t encoding = data[0];
    --            mime->setTo((const char *)&data[1]);
    --            size_t mimeLen = strlen((const char *)&data[1]) + 1;
    -+            size_t consumed = 1;
    -+
    -+            // *always* in an 8-bit encoding
    -+            size_t mimeLen = StringSize(&data[consumed], size - consumed, 0x00);
    -+            if (mimeLen > size - consumed) {
    -+                ALOGW("bogus album art size: mime");
    -+                return NULL;
    -+            }
    -+            mime->setTo((const char *)&data[consumed]);
    -+            consumed += mimeLen;
    - 
    - #if 0
    --            uint8_t picType = data[1 + mimeLen];
    -+            uint8_t picType = data[consumed];
    -             if (picType != 0x03) {
    -                 // Front Cover Art
    -                 it.next();
    -@@ -882,20 +891,30 @@ ID3::getAlbumArt(size_t *length, String8 *mime) const {
    -             }
    - #endif
    - 
    --            size_t descLen = StringSize(&data[2 + mimeLen], encoding);
    -+            consumed++;
    -+            if (consumed >= size) {
    -+                ALOGW("bogus album art size: pic type");
    -+                return NULL;
    -+            }
    -+
    -+            size_t descLen = StringSize(&data[consumed], size - consumed, encoding);
    -+            consumed += descLen;
    - 
    --            if (size < 2 ||
    --                    size - 2 < mimeLen ||
    --                    size - 2 - mimeLen < descLen) {
    --                ALOGW("bogus album art sizes");
    -+            if (consumed >= size) {
    -+                ALOGW("bogus album art size: description");
    -                 return NULL;
    -             }
    --            *length = size - 2 - mimeLen - descLen;
    - 
    --            return &data[2 + mimeLen + descLen];
    -+            *length = size - consumed;
    -+
    -+            return &data[consumed];
    -         } else {
    -             uint8_t encoding = data[0];
    - 
    -+            if (size <= 5) {
    -+                return NULL;
    -+            }
    -+
    -             if (!memcmp(&data[1], "PNG", 3)) {
    -                 mime->setTo("image/png");
    -             } else if (!memcmp(&data[1], "JPG", 3)) {
    -@@ -915,7 +934,10 @@ ID3::getAlbumArt(size_t *length, String8 *mime) const {
    -             }
    - #endif
    - 
    --            size_t descLen = StringSize(&data[5], encoding);
    -+            size_t descLen = StringSize(&data[5], size - 5, encoding);
    -+            if (descLen > size - 5) {
    -+                return NULL;
    -+            }
    - 
    -             *length = size - 5 - descLen;
    - 
     diff --git a/media/libstagefright/omx/Android.mk b/media/libstagefright/omx/Android.mk
     index e4fbd81..8fc788f 100644
     --- a/media/libstagefright/omx/Android.mk
    @@ -623,7 +332,7 @@ index 6132a2c..7f0d270 100644
      
      void OMXMaster::addPlugin(const char *libname) {
     diff --git a/media/libstagefright/omx/OMXNodeInstance.cpp b/media/libstagefright/omx/OMXNodeInstance.cpp
    -index 5f903a9..2fa9989 100644
    +index 43a50ae..2fa9989 100644
     --- a/media/libstagefright/omx/OMXNodeInstance.cpp
     +++ b/media/libstagefright/omx/OMXNodeInstance.cpp
     @@ -795,7 +795,11 @@ status_t OMXNodeInstance::useBuffer(
    @@ -638,21 +347,7 @@ index 5f903a9..2fa9989 100644
          OMX_U8 *data = static_cast<OMX_U8 *>(params->pointer());
          // allocate backup buffer
          if (useBackup) {
    -@@ -805,13 +809,6 @@ status_t OMXNodeInstance::useBuffer(
    -         }
    -         memset(data, 0, allottedSize);
    - 
    --        // if we are not connecting the buffers, the sizes must match
    --        if (allottedSize != params->size()) {
    --            CLOG_ERROR(useBuffer, BAD_VALUE, SIMPLE_BUFFER(portIndex, (size_t)allottedSize, data));
    --            delete[] data;
    --            return BAD_VALUE;
    --        }
    --
    -         buffer_meta = new BufferMeta(
    -                 params, portIndex, false /* copyToOmx */, false /* copyFromOmx */, data);
    -     } else {
    -@@ -1286,7 +1283,11 @@ status_t OMXNodeInstance::allocateBufferWithBackup(
    +@@ -1279,7 +1283,11 @@ status_t OMXNodeInstance::allocateBufferWithBackup(
          }
      
          // metadata buffers are not connected cross process; only copy if not meta
    @@ -664,7 +359,7 @@ index 5f903a9..2fa9989 100644
      
          BufferMeta *buffer_meta = new BufferMeta(
                  params, portIndex,
    -@@ -1404,10 +1405,30 @@ status_t OMXNodeInstance::emptyBuffer(
    +@@ -1397,10 +1405,30 @@ status_t OMXNodeInstance::emptyBuffer(
          BufferMeta *buffer_meta =
              static_cast<BufferMeta *>(header->pAppPrivate);
      
    @@ -746,24 +441,6 @@ index 1785a03..d5499f0 100644
              ALOGE("openRecord() permission denied: recording not allowed");
              lStatus = PERMISSION_DENIED;
              goto Exit;
    -diff --git a/services/audioflinger/Effects.cpp b/services/audioflinger/Effects.cpp
    -index 9711f2d..bb3067f 100644
    ---- a/services/audioflinger/Effects.cpp
    -+++ b/services/audioflinger/Effects.cpp
    -@@ -600,6 +600,13 @@ status_t AudioFlinger::EffectModule::command(uint32_t cmdCode,
    -         android_errorWriteLog(0x534e4554, "29251553");
    -         return -EINVAL;
    -     }
    -+    if (cmdCode == EFFECT_CMD_GET_PARAM &&
    -+            (sizeof(effect_param_t) > cmdSize ||
    -+                    ((effect_param_t *)pCmdData)->psize > cmdSize
    -+                                                          - sizeof(effect_param_t))) {
    -+        android_errorWriteLog(0x534e4554, "32438594");
    -+        return -EINVAL;
    -+    }
    -     if ((cmdCode == EFFECT_CMD_SET_PARAM
    -             || cmdCode == EFFECT_CMD_SET_PARAM_DEFERRED) &&  // DEFERRED not generally used
    -         (sizeof(effect_param_t) > cmdSize
     diff --git a/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp b/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp
     index c9b3abc..57d26e6 100644
     --- a/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp
    diff --git a/frameworks_base.patch b/frameworks_base.patch
    index 6a9dbee..ee5fd81 100644
    --- a/frameworks_base.patch
    +++ b/frameworks_base.patch
    @@ -24,127 +24,6 @@ index aed7a36..bf96926 100644
                  // if canceling out of addAccount and the original state caused us to skip this,
                  // finish this activity
                  if (mAccounts.isEmpty()) {
    -diff --git a/core/jni/com_android_internal_os_Zygote.cpp b/core/jni/com_android_internal_os_Zygote.cpp
    -index d1fe07b..f94c861 100644
    ---- a/core/jni/com_android_internal_os_Zygote.cpp
    -+++ b/core/jni/com_android_internal_os_Zygote.cpp
    -@@ -454,6 +454,20 @@ static pid_t ForkAndSpecializeCommon(JNIEnv* env, uid_t uid, gid_t gid, jintArra
    -   SetForkLoad(true);
    - #endif
    - 
    -+  sigset_t sigchld;
    -+  sigemptyset(&sigchld);
    -+  sigaddset(&sigchld, SIGCHLD);
    -+
    -+  // Temporarily block SIGCHLD during forks. The SIGCHLD handler might
    -+  // log, which would result in the logging FDs we close being reopened.
    -+  // This would cause failures because the FDs are not whitelisted.
    -+  //
    -+  // Note that the zygote process is single threaded at this point.
    -+  if (sigprocmask(SIG_BLOCK, &sigchld, nullptr) == -1) {
    -+    ALOGE("sigprocmask(SIG_SETMASK, { SIGCHLD }) failed: %s", strerror(errno));
    -+    RuntimeAbort(env, __LINE__, "Call to sigprocmask(SIG_BLOCK, { SIGCHLD }) failed.");
    -+  }
    -+
    -   // Close any logging related FDs before we start evaluating the list of
    -   // file descriptors.
    -   __android_log_close();
    -@@ -485,6 +499,11 @@ static pid_t ForkAndSpecializeCommon(JNIEnv* env, uid_t uid, gid_t gid, jintArra
    -       RuntimeAbort(env, __LINE__, "Unable to reopen whitelisted descriptors.");
    -     }
    - 
    -+    if (sigprocmask(SIG_UNBLOCK, &sigchld, nullptr) == -1) {
    -+      ALOGE("sigprocmask(SIG_SETMASK, { SIGCHLD }) failed: %s", strerror(errno));
    -+      RuntimeAbort(env, __LINE__, "Call to sigprocmask(SIG_UNBLOCK, { SIGCHLD }) failed.");
    -+    }
    -+
    -     // Keep capabilities across UID change, unless we're staying root.
    -     if (uid != 0) {
    -       EnableKeepCapabilities(env);
    -@@ -618,6 +637,11 @@ static pid_t ForkAndSpecializeCommon(JNIEnv* env, uid_t uid, gid_t gid, jintArra
    -     SetForkLoad(false);
    - #endif
    - 
    -+    // We blocked SIGCHLD prior to a fork, we unblock it here.
    -+    if (sigprocmask(SIG_UNBLOCK, &sigchld, nullptr) == -1) {
    -+      ALOGE("sigprocmask(SIG_SETMASK, { SIGCHLD }) failed: %s", strerror(errno));
    -+      RuntimeAbort(env, __LINE__, "Call to sigprocmask(SIG_UNBLOCK, { SIGCHLD }) failed.");
    -+    }
    -   }
    -   return pid;
    - }
    -diff --git a/core/jni/fd_utils-inl.h b/core/jni/fd_utils-inl.h
    -index c67662b..d1129a3e 100644
    ---- a/core/jni/fd_utils-inl.h
    -+++ b/core/jni/fd_utils-inl.h
    -@@ -239,9 +239,22 @@ class FileDescriptorInfo {
    -     is_sock(false) {
    -   }
    - 
    -+  static bool StartsWith(const std::string& str, const std::string& prefix) {
    -+    return str.compare(0, prefix.size(), prefix) == 0;
    -+  }
    -+
    -+  static bool EndsWith(const std::string& str, const std::string& suffix) {
    -+    if (suffix.size() > str.size()) {
    -+      return false;
    -+    }
    -+
    -+    return str.compare(str.size() - suffix.size(), suffix.size(), suffix) == 0;
    -+  }
    -+
    -   // Returns true iff. a given path is whitelisted. A path is whitelisted
    -   // if it belongs to the whitelist (see kPathWhitelist) or if it's a path
    --  // under /system/framework that ends with ".jar".
    -+  // under /system/framework that ends with ".jar" or if it is a system
    -+  // framework overlay.
    -   static bool IsWhitelisted(const std::string& path) {
    -     for (size_t i = 0; i < (sizeof(kPathWhitelist) / sizeof(kPathWhitelist[0])); ++i) {
    -       if (kPathWhitelist[i] == path) {
    -@@ -251,10 +264,41 @@ class FileDescriptorInfo {
    - 
    -     static const std::string kFrameworksPrefix = "/system/framework/";
    -     static const std::string kJarSuffix = ".jar";
    --    if (path.compare(0, kFrameworksPrefix.size(), kFrameworksPrefix) == 0 &&
    --        path.compare(path.size() - kJarSuffix.size(), kJarSuffix.size(), kJarSuffix) == 0) {
    -+    if (StartsWith(path, kFrameworksPrefix) && EndsWith(path, kJarSuffix)) {
    -       return true;
    -     }
    -+
    -+    // Whitelist files needed for Runtime Resource Overlay, like these:
    -+    // /system/vendor/overlay/framework-res.apk
    -+    // /system/vendor/overlay-subdir/pg/framework-res.apk
    -+    // /data/resource-cache/system@vendor@overlay@framework-res.apk@idmap
    -+    // /data/resource-cache/system@vendor@overlay-subdir@pg@framework-res.apk@idmap
    -+    // See AssetManager.cpp for more details on overlay-subdir.
    -+    static const std::string kOverlayDir = "/system/vendor/overlay/";
    -+    static const std::string kVendorOverlayDir = "/vendor/overlay";
    -+    static const std::string kOverlaySubdir = "/system/vendor/overlay-subdir/";
    -+    static const std::string kApkSuffix = ".apk";
    -+
    -+    if ((StartsWith(path, kOverlayDir) || StartsWith(path, kOverlaySubdir)
    -+         || StartsWith(path, kVendorOverlayDir))
    -+        && EndsWith(path, kApkSuffix)
    -+        && path.find("/../") == std::string::npos) {
    -+      return true;
    -+    }
    -+
    -+    static const std::string kOverlayIdmapPrefix = "/data/resource-cache/";
    -+    static const std::string kOverlayIdmapSuffix = ".apk@idmap";
    -+    if (StartsWith(path, kOverlayIdmapPrefix) && EndsWith(path, kOverlayIdmapSuffix)
    -+        && path.find("/../") == std::string::npos) {
    -+      return true;
    -+    }
    -+
    -+    // All regular files that are placed under this path are whitelisted automatically.
    -+    static const std::string kZygoteWhitelistPath = "/vendor/zygote_whitelist/";
    -+    if (StartsWith(path, kZygoteWhitelistPath) && path.find("/../") == std::string::npos) {
    -+      return true;
    -+    }
    -+
    -     return false;
    -   }
    - 
     diff --git a/core/res/res/xml/config_webview_packages.xml b/core/res/res/xml/config_webview_packages.xml
     index f062b59..574f7c1 100644
     --- a/core/res/res/xml/config_webview_packages.xml
    @@ -174,18 +53,6 @@ index f062b59..574f7c1 100644
     +  <!-- The default WebView implementation -->
     +    <webviewprovider description="AOSP WebView" packageName="com.android.webview" availableByDefault="true" isFallback="true" />
      </webviewproviders>
    -diff --git a/libs/androidfw/AssetManager.cpp b/libs/androidfw/AssetManager.cpp
    -index 07044d0..7a10343 100644
    ---- a/libs/androidfw/AssetManager.cpp
    -+++ b/libs/androidfw/AssetManager.cpp
    -@@ -804,6 +804,7 @@ void AssetManager::addSystemOverlays(const char* pathOverlaysList,
    -             sharedRes->add(oass, oidmap, offset + 1, false);
    -             const_cast<AssetManager*>(this)->mAssetPaths.add(oap);
    -             const_cast<AssetManager*>(this)->mZipSet.addOverlay(targetPackagePath, oap);
    -+            delete oidmap;
    -         }
    -     }
    - 
     diff --git a/libs/hwui/Android.mk b/libs/hwui/Android.mk
     index cacfce1..0b177b9 100644
     --- a/libs/hwui/Android.mk
    @@ -211,20 +78,6 @@ index 2c9c9d9..7c187fb 100644
      }
      
      /**
    -diff --git a/packages/ExternalStorageProvider/src/com/android/externalstorage/ExternalStorageProvider.java b/packages/ExternalStorageProvider/src/com/android/externalstorage/ExternalStorageProvider.java
    -index 3ef9b8e..10e5dcc 100644
    ---- a/packages/ExternalStorageProvider/src/com/android/externalstorage/ExternalStorageProvider.java
    -+++ b/packages/ExternalStorageProvider/src/com/android/externalstorage/ExternalStorageProvider.java
    -@@ -161,7 +161,8 @@ public class ExternalStorageProvider extends DocumentsProvider {
    -                     final VolumeInfo privateVol = mStorageManager.findPrivateForEmulated(volume);
    -                     title = mStorageManager.getBestVolumeDescription(privateVol);
    -                 }
    --            } else if (volume.getType() == VolumeInfo.TYPE_PUBLIC) {
    -+            } else if (volume.getType() == VolumeInfo.TYPE_PUBLIC
    -+                    && volume.getMountUserId() == userId) {
    -                 rootId = volume.getFsUuid();
    -                 title = mStorageManager.getBestVolumeDescription(volume);
    -             } else {
     diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationGuts.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationGuts.java
     index c850a25..1829e59 100644
     --- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationGuts.java
    @@ -552,32 +405,6 @@ index 3fffefb..49fe79c 100644
              }
              if (receivers.size() > 0) {
                  pw.print(prefix); pw.println("Receivers:");
    -diff --git a/services/net/java/android/net/dhcp/DhcpClient.java b/services/net/java/android/net/dhcp/DhcpClient.java
    -index ffbea9f..8dd05b1 100644
    ---- a/services/net/java/android/net/dhcp/DhcpClient.java
    -+++ b/services/net/java/android/net/dhcp/DhcpClient.java
    -@@ -40,6 +40,7 @@ import android.os.SystemClock;
    - import android.system.ErrnoException;
    - import android.system.Os;
    - import android.system.PacketSocketAddress;
    -+import android.util.EventLog;
    - import android.util.Log;
    - import android.util.SparseArray;
    - import android.util.TimeUtils;
    -@@ -369,6 +370,13 @@ public class DhcpClient extends StateMachine {
    -                     if (PACKET_DBG) {
    -                         Log.d(TAG, HexDump.dumpHexString(mPacket, 0, length));
    -                     }
    -+                    if (e.errorCode == DhcpErrorEvent.DHCP_NO_COOKIE) {
    -+                        int snetTagId = 0x534e4554;
    -+                        String bugId = "31850211";
    -+                        int uid = -1;
    -+                        String data = DhcpPacket.ParseException.class.getName();
    -+                        EventLog.writeEvent(snetTagId, bugId, uid, data);
    -+                    }
    -                     logError(e.errorCode);
    -                 }
    -             }
     diff --git a/services/tests/Android.mk b/services/tests/Android.mk
     deleted file mode 100644
     index 40369ee..0000000
    @@ -4231,10 +4058,10 @@ index 220e54d..0000000
     -}
     diff --git a/services/tests/servicestests/src/android/net/dhcp/DhcpPacketTest.java b/services/tests/servicestests/src/android/net/dhcp/DhcpPacketTest.java
     deleted file mode 100644
    -index bc8baa1..0000000
    +index b4e9db7..0000000
     --- a/services/tests/servicestests/src/android/net/dhcp/DhcpPacketTest.java
     +++ /dev/null
    -@@ -1,939 +0,0 @@
    +@@ -1,889 +0,0 @@
     -/*
     - * Copyright (C) 2015 The Android Open Source Project
     - *
    @@ -4264,7 +4091,6 @@ index bc8baa1..0000000
     -import java.nio.ByteBuffer;
     -import java.util.ArrayList;
     -import java.util.Arrays;
    --import java.util.Random;
     -import junit.framework.TestCase;
     -
     -import static android.net.dhcp.DhcpPacket.*;
    @@ -4668,7 +4494,7 @@ index bc8baa1..0000000
     -        try {
     -            DhcpPacket offerPacket = DhcpPacket.decodeFullPacket(packet, packet.length, ENCAP_L3);
     -        } catch (DhcpPacket.ParseException expected) {
    --            assertDhcpErrorCodes(DhcpErrorEvent.DHCP_NO_COOKIE, expected.errorCode);
    +-            assertDhcpErrorCodes(DhcpErrorEvent.PARSING_ERROR, expected.errorCode);
     -            return;
     -        }
     -        fail("Dhcp packet parsing should have failed");
    @@ -4710,55 +4536,6 @@ index bc8baa1..0000000
     -        assertEquals(Integer.toHexString(expected), Integer.toHexString(got));
     -    }
     -
    --    public void testTruncatedOfferPackets() throws Exception {
    --        final byte[] packet = HexDump.hexStringToByteArray(
    --            // IP header.
    --            "450001518d0600004011144dc0a82b01c0a82bf7" +
    --            // UDP header.
    --            "00430044013d9ac7" +
    --            // BOOTP header.
    --            "02010600dfc23d1f0002000000000000c0a82bf7c0a82b0100000000" +
    --            // MAC address.
    --            "30766ff2a90c00000000000000000000" +
    --            // Server name.
    --            "0000000000000000000000000000000000000000000000000000000000000000" +
    --            "0000000000000000000000000000000000000000000000000000000000000000" +
    --            // File.
    --            "0000000000000000000000000000000000000000000000000000000000000000" +
    --            "0000000000000000000000000000000000000000000000000000000000000000" +
    --            "0000000000000000000000000000000000000000000000000000000000000000" +
    --            "0000000000000000000000000000000000000000000000000000000000000000" +
    --            // Options
    --            "638253633501023604c0a82b01330400000e103a04000007083b0400000c4e0104ffffff00" +
    --            "1c04c0a82bff0304c0a82b010604c0a82b012b0f414e44524f49445f4d455445524544ff");
    --
    --        for (int len = 0; len < packet.length; len++) {
    --            try {
    --                DhcpPacket.decodeFullPacket(packet, len, ENCAP_L3);
    --            } catch (ParseException e) {
    --                if (e.errorCode == DhcpErrorEvent.PARSING_ERROR) {
    --                    fail(String.format("bad truncated packet of length %d", len));
    --                }
    --            }
    --        }
    --    }
    --
    --    public void testRandomPackets() throws Exception {
    --        final int maxRandomPacketSize = 512;
    --        final Random r = new Random();
    --        for (int i = 0; i < 10000; i++) {
    --            byte[] packet = new byte[r.nextInt(maxRandomPacketSize + 1)];
    --            r.nextBytes(packet);
    --            try {
    --                DhcpPacket.decodeFullPacket(packet, packet.length, ENCAP_L3);
    --            } catch (ParseException e) {
    --                if (e.errorCode == DhcpErrorEvent.PARSING_ERROR) {
    --                    fail("bad packet: " + HexDump.toHexString(packet));
    --                }
    --            }
    --        }
    --    }
    --
     -    private byte[] mtuBytes(int mtu) {
     -        // 0x1a02: option 26, length 2. 0xff: no more options.
     -        if (mtu > Short.MAX_VALUE - Short.MIN_VALUE) {
    diff --git a/frameworks_native.patch b/frameworks_native.patch
    index 81db338..4bc0763 100644
    --- a/frameworks_native.patch
    +++ b/frameworks_native.patch
    @@ -51,27 +51,6 @@ index 5885738..86c315c 100644
          return ok;
      }
      
    -diff --git a/include/binder/Parcel.h b/include/binder/Parcel.h
    -index 1c355c4..2490b82 100644
    ---- a/include/binder/Parcel.h
    -+++ b/include/binder/Parcel.h
    -@@ -589,8 +589,16 @@ status_t Parcel::unsafeReadTypedVector(
    -         return UNEXPECTED_NULL;
    -     }
    - 
    -+    if (val->max_size() < size) {
    -+        return NO_MEMORY;
    -+    }
    -+
    -     val->resize(size);
    - 
    -+    if (val->size() < size) {
    -+        return NO_MEMORY;
    -+    }
    -+
    -     for (auto& v: *val) {
    -         status = (this->*read_func)(&v);
    - 
     diff --git a/include/gui/ISurfaceComposer.h b/include/gui/ISurfaceComposer.h
     index 74a4123..8dc6f6a 100644
     --- a/include/gui/ISurfaceComposer.h
    @@ -143,18 +122,6 @@ index 46feb1c..1b4a9c5 100644
      
      LOCAL_MODULE := libgui
      
    -diff --git a/libs/gui/BufferQueueConsumer.cpp b/libs/gui/BufferQueueConsumer.cpp
    -index ca2a374..73d2042 100644
    ---- a/libs/gui/BufferQueueConsumer.cpp
    -+++ b/libs/gui/BufferQueueConsumer.cpp
    -@@ -715,6 +715,7 @@ status_t BufferQueueConsumer::setTransformHint(uint32_t hint) {
    - }
    - 
    - sp<NativeHandle> BufferQueueConsumer::getSidebandStream() const {
    -+    Mutex::Autolock lock(mCore->mMutex);
    -     return mCore->mSidebandStream;
    - }
    - 
     diff --git a/libs/gui/ISurfaceComposer.cpp b/libs/gui/ISurfaceComposer.cpp
     index f0b0ada..3577a33 100644
     --- a/libs/gui/ISurfaceComposer.cpp
    
    From e710fb987606c916a3adaa3839b616519531cf44 Mon Sep 17 00:00:00 2001
    From: AndDiSa <anddisa@googlemail.com>
    Date: Fri, 20 Jan 2017 17:19:26 +0100
    Subject: [PATCH 061/159] update patches
    
    Change-Id: Ifab24e933ee028a6315d38a858714e441a1e08bf
    ---
     build.patch         |  6 +++---
     default.xml         |  1 +
     frameworks_av.patch | 31 +++++++++++++++++++++++++++++--
     3 files changed, 33 insertions(+), 5 deletions(-)
    
    diff --git a/build.patch b/build.patch
    index b699411..d8aad41 100644
    --- a/build.patch
    +++ b/build.patch
    @@ -13,7 +13,7 @@ index a612f83..921eb32 100644
      
     diff --git a/core/tasks/kernel.mk b/core/tasks/kernel.mk
     new file mode 100644
    -index 0000000..9c12bc0
    +index 0000000..ee76dc2
     --- /dev/null
     +++ b/core/tasks/kernel.mk
     @@ -0,0 +1,196 @@
    @@ -158,10 +158,10 @@ index 0000000..9c12bc0
     +        ifeq ($(HOST_OS),darwin)
     +            ARM_CROSS_COMPILE:=CROSS_COMPILE="$(ccache) $(ANDROID_BUILD_TOP)/prebuilts/gcc/darwin-x86/arm/$(TARGET_KERNEL_CUSTOM_TOOLCHAIN)/bin/arm-eabi-"
     +        else
    -+            ARM_CROSS_COMPILE:=CROSS_COMPILE="$(ccache) $(ANDROID_BUILD_TOP)/prebuilts/gcc/linux-x86/arm/$(TARGET_KERNEL_CUSTOM_TOOLCHAIN)/bin/arm-linux-androidkernel-"
    ++            ARM_CROSS_COMPILE:=CROSS_COMPILE="$(ccache) $(ANDROID_BUILD_TOP)/prebuilts/gcc/linux-x86/arm/$(TARGET_KERNEL_CUSTOM_TOOLCHAIN)/bin/arm-eabi-"
     +        endif
     +    else
    -+        ARM_CROSS_COMPILE:=CROSS_COMPILE="$(ccache) $(ARM_EABI_TOOLCHAIN)/arm-linux-androidkernel-"
    ++        ARM_CROSS_COMPILE:=CROSS_COMPILE="$(ccache) $(ARM_EABI_TOOLCHAIN)/arm-eabi-"
     +    endif
     +    ccache = 
     +endif
    diff --git a/default.xml b/default.xml
    index 01d8d32..3e4a36b 100644
    --- a/default.xml
    +++ b/default.xml
    @@ -458,6 +458,7 @@
       <project path="prebuilts/eclipse-build-deps" name="platform/prebuilts/eclipse-build-deps" groups="notdefault,eclipse" />
       <project path="prebuilts/gcc/linux-x86/aarch64/aarch64-linux-android-4.9" name="platform/prebuilts/gcc/linux-x86/aarch64/aarch64-linux-android-4.9" groups="pdk,linux,arm" />
       <project path="prebuilts/gcc/linux-x86/arm/arm-linux-androideabi-4.9" name="platform/prebuilts/gcc/linux-x86/arm/arm-linux-androideabi-4.9" groups="pdk,linux,arm" />
    +  <project path="prebuilts/gcc/linux-x86/arm/arm-eabi-4.8" name="platform/prebuilts/gcc/linux-x86/arm/arm-eabi-4.8" groups="pdk,linux,arm" />
       <project path="prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.11-4.8" name="platform/prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.11-4.8" groups="pdk,linux" />
       <project path="prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.15-4.8" name="platform/prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.15-4.8"  groups="pdk,linux" />
       <project path="prebuilts/gcc/linux-x86/host/x86_64-w64-mingw32-4.8" name="platform/prebuilts/gcc/linux-x86/host/x86_64-w64-mingw32-4.8" groups="pdk-fs" />
    diff --git a/frameworks_av.patch b/frameworks_av.patch
    index 3d65417..50664b6 100644
    --- a/frameworks_av.patch
    +++ b/frameworks_av.patch
    @@ -204,6 +204,21 @@ index 893da89..0bc6847 100644
          // Output buffers will contain metadata if camera sends us buffer in metadata mode or via
          // buffer queue.
          switch (mVideoBufferMode) {
    +diff --git a/media/libstagefright/MediaSource.cpp b/media/libstagefright/MediaSource.cpp
    +index a17757a..f1ad5c5 100644
    +--- a/media/libstagefright/MediaSource.cpp
    ++++ b/media/libstagefright/MediaSource.cpp
    +@@ -22,4 +22,10 @@ MediaSource::MediaSource() {}
    + 
    + MediaSource::~MediaSource() {}
    + 
    ++extern "C" {
    ++bool _ZNK7android11MediaSource11ReadOptions9getSeekToEPxPNS1_8SeekModeE(android::IMediaSource::ReadOptions *readOptions, int64_t *time_us, android::IMediaSource::ReadOptions::SeekMode *mode) {
    ++    bool res = readOptions->getSeekTo(time_us, mode);
    ++    return res;
    ++}
    ++}
    + }  // namespace android
     diff --git a/media/libstagefright/SurfaceMediaSource.cpp b/media/libstagefright/SurfaceMediaSource.cpp
     index 15ff569..0e9b4e6 100644
     --- a/media/libstagefright/SurfaceMediaSource.cpp
    @@ -269,10 +284,22 @@ index 15ff569..0e9b4e6 100644
          (*buffer)->setObserver(this);
          (*buffer)->add_ref();
     diff --git a/media/libstagefright/foundation/MediaBufferGroup.cpp b/media/libstagefright/foundation/MediaBufferGroup.cpp
    -index 54f768a..1334f93 100644
    +index 54f768a..8200bf1 100644
     --- a/media/libstagefright/foundation/MediaBufferGroup.cpp
     +++ b/media/libstagefright/foundation/MediaBufferGroup.cpp
    -@@ -179,6 +179,16 @@ status_t MediaBufferGroup::acquire_buffer(
    +@@ -99,6 +99,11 @@ MediaBufferGroup::~MediaBufferGroup() {
    +     }
    + }
    + 
    ++extern "C" int _ZN7android16MediaBufferGroupC1Ej(unsigned int);
    ++extern "C" int _ZN7android16MediaBufferGroupC1Ev() {
    ++    return _ZN7android16MediaBufferGroupC1Ej(0);
    ++}
    ++
    + void MediaBufferGroup::add_buffer(MediaBuffer *buffer) {
    +     Mutex::Autolock autoLock(mLock);
    + 
    +@@ -179,6 +184,16 @@ status_t MediaBufferGroup::acquire_buffer(
          // Never gets here.
      }
      
    
    From 781e8613eb67b24723697722e72b9baf5588f165 Mon Sep 17 00:00:00 2001
    From: AndDiSa <anddisa@googlemail.com>
    Date: Fri, 20 Jan 2017 18:27:35 +0100
    Subject: [PATCH 062/159] update projects and branches
    
    Change-Id: I226625595d17cbd6e29b3c581aad9f0d872c2879
    ---
     default.xml | 4 ++--
     1 file changed, 2 insertions(+), 2 deletions(-)
    
    diff --git a/default.xml b/default.xml
    index 3e4a36b..eef9b18 100644
    --- a/default.xml
    +++ b/default.xml
    @@ -30,7 +30,7 @@
       <project path="developers/demos" name="platform/developers/demos" />
       <project path="developers/samples/android" name="platform/developers/samples/android" />
       <project path="development" name="platform/development" groups="pdk-cw-fs,pdk-fs" />
    -  <project path="device/asus/grouper" name="android_device_asus_grouper" remote="ads" revision="ads-7.0.1" groups="device,grouper" />
    +  <project path="device/asus/grouper" name="android_device_asus_grouper" remote="ads" revision="ads-7.1.0" groups="device,grouper" />
       <project path="device/asus/tilapia" name="device_asus_tilapia" remote="millosr" revision="ads-7.0.1" groups="device,grouper" />
       <project path="device/common" name="device/common" groups="pdk-cw-fs,pdk-fs" />
       <project path="device/generic/arm64" name="device/generic/arm64" groups="pdk" />
    @@ -515,5 +515,5 @@
       <project path="vendor/elan" name="proprietary_vendor_elan" remote="ads" revision="oct-mm" />
       <project path="vendor/invensense" name="proprietary_vendor_invensense" remote="ads" revision="ads-7.0.1" />
       <project path="vendor/nvidia" name="proprietary_vendor_nvidia" remote="ads" revision="ads-7.0.1" />
    -  <project path="vendor/widevine" name="proprietary_vendor_widevine" remote="unlegacy" revision="aosp-7.1" />
    +  <project path="vendor/widevine" name="proprietary_vendor_widevine" remote="ads" revision="ads-7.1.0" />
     </manifest>
    
    From ccd5f0a960bb53ec4390dac8290b390d93de8ad4 Mon Sep 17 00:00:00 2001
    From: AndDiSa <anddisa@googlemail.com>
    Date: Tue, 7 Feb 2017 07:51:48 +0100
    Subject: [PATCH 063/159] update to android-7.1.1_r20
    
    Change-Id: I3bb81299cd4dbf57af08896fa709af24f3efe8aa
    ---
     default.xml | 2 +-
     1 file changed, 1 insertion(+), 1 deletion(-)
    
    diff --git a/default.xml b/default.xml
    index eef9b18..c9aaee6 100644
    --- a/default.xml
    +++ b/default.xml
    @@ -9,7 +9,7 @@
                fetch="https://github.com/millosr/" />
       <remote  name="unlegacy"
                fetch="https://github.com/Unlegacy-Android/" />
    -  <default revision="refs/tags/android-7.1.1_r9"
    +  <default revision="refs/tags/android-7.1.1_r20"
                remote="aosp"
                sync-j="4" />
     
    
    From 93df3a8c9fa0608c5ca59449369f0f42439ae860 Mon Sep 17 00:00:00 2001
    From: AndDiSa <anddisa@googlemail.com>
    Date: Tue, 7 Feb 2017 17:14:39 +0100
    Subject: [PATCH 064/159] update patches
    
    Change-Id: I0cd2e092b941b5a8d67d6dd6435a264885a74a3d
    ---
     bionic.patch            |  222 +++
     frameworks_av.patch     |  123 +-
     frameworks_base.patch   |   14 +-
     frameworks_native.patch | 3890 +--------------------------------------
     system_core.patch       |    4 +-
     5 files changed, 451 insertions(+), 3802 deletions(-)
     create mode 100644 bionic.patch
    
    diff --git a/bionic.patch b/bionic.patch
    new file mode 100644
    index 0000000..625c884
    --- /dev/null
    +++ b/bionic.patch
    @@ -0,0 +1,222 @@
    +diff --git a/libc/arch-arm/arm.mk b/libc/arch-arm/arm.mk
    +index 76f465e..21b6152 100644
    +--- a/libc/arch-arm/arm.mk
    ++++ b/libc/arch-arm/arm.mk
    +@@ -1,6 +1,7 @@
    + # 32-bit arm.
    + 
    + libc_bionic_src_files_arm += \
    ++    arch-arm/generic/bionic/memchr.S \
    +     arch-arm/generic/bionic/memcmp.S \
    +     arch-arm/generic/bionic/memcpy.S \
    +     arch-arm/generic/bionic/memset.S \
    +@@ -13,7 +14,8 @@ libc_bionic_src_files_exclude_arm += \
    +     bionic/__memset_chk.cpp \
    + 
    + libc_openbsd_src_files_exclude_arm += \
    +-    upstream-openbsd/lib/libc/string/strcpy.c \
    ++    upstream-openbsd/lib/libc/string/memchr.c \
    ++    upstream-openbsd/lib/libc/string/strcpy.c
    + 
    + #
    + # Inherently architecture-specific code.
    +diff --git a/libc/arch-arm/generic/bionic/memchr.S b/libc/arch-arm/generic/bionic/memchr.S
    +new file mode 100644
    +index 0000000..cb00d82
    +--- /dev/null
    ++++ b/libc/arch-arm/generic/bionic/memchr.S
    +@@ -0,0 +1,155 @@
    ++/* Copyright (c) 2010-2015, Linaro Limited
    ++   All rights reserved.
    ++
    ++   Redistribution and use in source and binary forms, with or without
    ++   modification, are permitted provided that the following conditions
    ++   are met:
    ++
    ++      * Redistributions of source code must retain the above copyright
    ++      notice, this list of conditions and the following disclaimer.
    ++
    ++      * Redistributions in binary form must reproduce the above copyright
    ++      notice, this list of conditions and the following disclaimer in the
    ++      documentation and/or other materials provided with the distribution.
    ++
    ++      * Neither the name of Linaro Limited nor the names of its
    ++      contributors may be used to endorse or promote products derived
    ++      from this software without specific prior written permission.
    ++
    ++   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
    ++   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
    ++   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
    ++   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
    ++   HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
    ++   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
    ++   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
    ++   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
    ++   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
    ++   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
    ++   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
    ++ */
    ++
    ++/*
    ++   Written by Dave Gilbert <david.gilbert@linaro.org>
    ++
    ++   This memchr routine is optimised on a Cortex-A9 and should work on
    ++   all ARMv7 processors.   It has a fast past for short sizes, and has
    ++   an optimised path for large data sets; the worst case is finding the
    ++   match early in a large data set.
    ++
    ++ */
    ++
    ++#include <private/bionic_asm.h>
    ++
    ++@ 2011-02-07 david.gilbert@linaro.org
    ++@    Extracted from local git a5b438d861
    ++@ 2011-07-14 david.gilbert@linaro.org
    ++@    Import endianness fix from local git ea786f1b
    ++@ 2011-12-07 david.gilbert@linaro.org
    ++@    Removed unneeded cbz from align loop
    ++
    ++	.syntax unified
    ++	.arch armv7-a
    ++
    ++@ this lets us check a flag in a 00/ff byte easily in either endianness
    ++#ifdef __ARMEB__
    ++#define CHARTSTMASK(c) 1<<(31-(c*8))
    ++#else
    ++#define CHARTSTMASK(c) 1<<(c*8)
    ++#endif
    ++	.text
    ++	.thumb
    ++
    ++@ ---------------------------------------------------------------------------
    ++	.thumb_func
    ++ENTRY(memchr)
    ++	.p2align 4,,15
    ++	@ r0 = start of memory to scan
    ++	@ r1 = character to look for
    ++	@ r2 = length
    ++	@ returns r0 = pointer to character or NULL if not found
    ++	and	r1,r1,#0xff	@ Don't think we can trust the caller to actually pass a char
    ++
    ++	cmp	r2,#16		@ If it's short don't bother with anything clever
    ++	blt	20f
    ++
    ++	tst	r0, #7		@ If it's already aligned skip the next bit
    ++	beq	10f
    ++
    ++	@ Work up to an aligned point
    ++5:
    ++	ldrb	r3, [r0],#1
    ++	subs	r2, r2, #1
    ++	cmp	r3, r1
    ++	beq	50f		@ If it matches exit found
    ++	tst	r0, #7
    ++	bne	5b		@ If not aligned yet then do next byte
    ++
    ++10:
    ++	@ At this point, we are aligned, we know we have at least 8 bytes to work with
    ++	push	{r4,r5,r6,r7}
    ++	orr	r1, r1, r1, lsl #8	@ expand the match word across to all bytes
    ++	orr	r1, r1, r1, lsl #16
    ++	bic	r4, r2, #7	@ Number of double words to work with
    ++	mvns	r7, #0		@ all F's
    ++	movs	r3, #0
    ++
    ++15:
    ++	ldrd    r5,r6,[r0],#8
    ++	subs	r4, r4, #8
    ++	eor	r5,r5, r1	@ Get it so that r5,r6 have 00's where the bytes match the target
    ++	eor	r6,r6, r1
    ++	uadd8	r5, r5, r7	@ Parallel add 0xff - sets the GE bits for anything that wasn't 0
    ++	sel	r5, r3, r7	@ bytes are 00 for none-00 bytes, or ff for 00 bytes - NOTE INVERSION
    ++	uadd8	r6, r6, r7	@ Parallel add 0xff - sets the GE bits for anything that wasn't 0
    ++	sel	r6, r5, r7	@ chained....bytes are 00 for none-00 bytes, or ff for 00 bytes - NOTE INVERSION
    ++	cbnz	r6, 60f
    ++	bne	15b		@ (Flags from the subs above) If not run out of bytes then go around again
    ++
    ++	pop	{r4,r5,r6,r7}
    ++	and	r1,r1,#0xff	@ Get r1 back to a single character from the expansion above
    ++	and	r2,r2,#7	@ Leave the count remaining as the number after the double words have been done
    ++
    ++20:
    ++	cbz	r2, 40f		@ 0 length or hit the end already then not found
    ++
    ++21:  @ Post aligned section, or just a short call
    ++	ldrb	r3,[r0],#1
    ++	subs	r2,r2,#1
    ++	eor	r3,r3,r1	@ r3 = 0 if match - doesn't break flags from sub
    ++	cbz	r3, 50f
    ++	bne	21b		@ on r2 flags
    ++
    ++40:
    ++	movs	r0,#0		@ not found
    ++	bx	lr
    ++
    ++50:
    ++	subs	r0,r0,#1	@ found
    ++	bx	lr
    ++
    ++60:  @ We're here because the fast path found a hit - now we have to track down exactly which word it was
    ++	@ r0 points to the start of the double word after the one that was tested
    ++	@ r5 has the 00/ff pattern for the first word, r6 has the chained value
    ++	cmp	r5, #0
    ++	itte	eq
    ++	moveq	r5, r6		@ the end is in the 2nd word
    ++	subeq	r0,r0,#3	@ Points to 2nd byte of 2nd word
    ++	subne	r0,r0,#7	@ or 2nd byte of 1st word
    ++
    ++	@ r0 currently points to the 3rd byte of the word containing the hit
    ++	tst	r5, # CHARTSTMASK(0)	@ 1st character
    ++	bne	61f
    ++	adds	r0,r0,#1
    ++	tst	r5, # CHARTSTMASK(1)	@ 2nd character
    ++	ittt	eq
    ++	addeq	r0,r0,#1
    ++	tsteq	r5, # (3<<15)		@ 2nd & 3rd character
    ++	@ If not the 3rd must be the last one
    ++	addeq	r0,r0,#1
    ++
    ++61:
    ++	pop	{r4,r5,r6,r7}
    ++	subs	r0,r0,#1
    ++	bx	lr
    ++END(memchr)
    +diff --git a/linker/Android.mk b/linker/Android.mk
    +index 4a4ca5c..0d592c9 100644
    +--- a/linker/Android.mk
    ++++ b/linker/Android.mk
    +@@ -54,6 +54,10 @@ ifeq ($(TARGET_IS_64_BIT),true)
    + LOCAL_CPPFLAGS += -DTARGET_IS_64_BIT
    + endif
    + 
    ++ifeq ($(TARGET_NEEDS_PLATFORM_TEXT_RELOCATIONS),true)
    ++LOCAL_CPPFLAGS += -DTARGET_NEEDS_PLATFORM_TEXT_RELOCATIONS
    ++endif
    ++
    + # We need to access Bionic private headers in the linker.
    + LOCAL_CFLAGS += -I$(LOCAL_PATH)/../libc/
    + 
    +diff --git a/linker/linker.cpp b/linker/linker.cpp
    +index 9dc928e..2a665b5 100644
    +--- a/linker/linker.cpp
    ++++ b/linker/linker.cpp
    +@@ -3950,11 +3950,18 @@ bool soinfo::link_image(const soinfo_list_t& global_group, const soinfo_list_t&
    + #if !defined(__LP64__)
    +   if (has_text_relocations) {
    +     // Fail if app is targeting sdk version > 22
    +-    if (get_application_target_sdk_version() > 22) {
    ++#if !defined(__i386__) // ffmpeg says that they require text relocations on x86
    ++#if defined(TARGET_NEEDS_PLATFORM_TEXT_RELOCATIONS)
    ++    if (get_application_target_sdk_version() != __ANDROID_API__
    ++        && get_application_target_sdk_version() > 22) {
    ++#else
    ++     if (get_application_target_sdk_version() > 22) {
    ++#endif
    +       PRINT("%s: has text relocations", get_realpath());
    +       DL_ERR("%s: has text relocations", get_realpath());
    +       return false;
    +     }
    ++#endif
    +     // Make segments writable to allow text relocations to work properly. We will later call
    +     // phdr_table_protect_segments() after all of them are applied.
    +     DL_WARN("%s has text relocations. This is wasting memory and prevents "
    diff --git a/frameworks_av.patch b/frameworks_av.patch
    index 50664b6..05d7c91 100644
    --- a/frameworks_av.patch
    +++ b/frameworks_av.patch
    @@ -33,6 +33,29 @@ index 3051406..870bb9b 100644
      
          size_t buffers() const { return mBuffers.size(); }
      
    +diff --git a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp
    +index dc4e5d4..b64d899 100644
    +--- a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp
    ++++ b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp
    +@@ -1534,6 +1534,7 @@ void NuPlayer::restartAudio(
    +     mRenderer->flush(true /* audio */, false /* notifyComplete */);
    +     if (mVideoDecoder != NULL) {
    +         mRenderer->flush(false /* audio */, false /* notifyComplete */);
    ++        flushDecoder(false /* audio */, false /*needShutdown*/);
    +     }
    + 
    +     performSeek(currentPositionUs);
    +@@ -1545,6 +1546,10 @@ void NuPlayer::restartAudio(
    +     if (needsToCreateAudioDecoder) {
    +         instantiateDecoder(true /* audio */, &mAudioDecoder, !forceNonOffload);
    +     }
    ++    if (mVideoDecoder != NULL) {
    ++        // After a flush without shutdown, decoder is paused.
    ++        mVideoDecoder->signalResume(false /* needNotify */);
    ++    }
    + }
    + 
    + void NuPlayer::determineAudioModeChange(const sp<AMessage> &audioFormat) {
     diff --git a/media/libstagefright/ACodec.cpp b/media/libstagefright/ACodec.cpp
     index 37fd5a5..77a2a39 100644
     --- a/media/libstagefright/ACodec.cpp
    @@ -204,6 +227,21 @@ index 893da89..0bc6847 100644
          // Output buffers will contain metadata if camera sends us buffer in metadata mode or via
          // buffer queue.
          switch (mVideoBufferMode) {
    +diff --git a/media/libstagefright/MediaCodecList.cpp b/media/libstagefright/MediaCodecList.cpp
    +index 0fb5072..a25c47d 100644
    +--- a/media/libstagefright/MediaCodecList.cpp
    ++++ b/media/libstagefright/MediaCodecList.cpp
    +@@ -1165,7 +1165,9 @@ void MediaCodecList::findMatchingCodecs(
    +         CHECK(info != NULL);
    +         AString componentName = info->getCodecName();
    + 
    +-        if (!((flags & kHardwareCodecsOnly) && !isSoftwareCodec(componentName))) {
    ++        if ((flags & kHardwareCodecsOnly) && isSoftwareCodec(componentName)) {
    ++            ALOGV("skipping SW codec '%s'", componentName.c_str());
    ++        } else {
    +             matches->push(componentName);
    +             ALOGV("matching '%s'", componentName.c_str());
    +         }
     diff --git a/media/libstagefright/MediaSource.cpp b/media/libstagefright/MediaSource.cpp
     index a17757a..f1ad5c5 100644
     --- a/media/libstagefright/MediaSource.cpp
    @@ -219,6 +257,57 @@ index a17757a..f1ad5c5 100644
     +}
     +}
      }  // namespace android
    +diff --git a/media/libstagefright/SampleTable.cpp b/media/libstagefright/SampleTable.cpp
    +index eb1f193..770681a 100644
    +--- a/media/libstagefright/SampleTable.cpp
    ++++ b/media/libstagefright/SampleTable.cpp
    +@@ -567,6 +567,10 @@ status_t SampleTable::setSyncSampleParams(off64_t data_offset, size_t data_size)
    +     }
    + 
    +     for (size_t i = 0; i < mNumSyncSamples; ++i) {
    ++        if (mSyncSamples[i] == 0) {
    ++            ALOGE("b/32423862, unexpected zero value in stss");
    ++            continue;
    ++        }
    +         mSyncSamples[i] = ntohl(mSyncSamples[i]) - 1;
    +     }
    + 
    +diff --git a/media/libstagefright/StagefrightMetadataRetriever.cpp b/media/libstagefright/StagefrightMetadataRetriever.cpp
    +index be5067d..2fef7ca 100644
    +--- a/media/libstagefright/StagefrightMetadataRetriever.cpp
    ++++ b/media/libstagefright/StagefrightMetadataRetriever.cpp
    +@@ -483,6 +483,10 @@ VideoFrame *StagefrightMetadataRetriever::getFrameAtTime(
    +     for (i = 0; i < n; ++i) {
    +         sp<MetaData> meta = mExtractor->getTrackMetaData(i);
    + 
    ++        if (meta == NULL) {
    ++            continue;
    ++        }
    ++
    +         const char *mime;
    +         CHECK(meta->findCString(kKeyMIMEType, &mime));
    + 
    +@@ -652,6 +656,10 @@ void StagefrightMetadataRetriever::parseMetaData() {
    + 
    +     size_t numTracks = mExtractor->countTracks();
    + 
    ++    if (numTracks == 0) {      //If no tracks available, corrupt or not valid stream
    ++        return;
    ++    }
    ++
    +     char tmp[32];
    +     sprintf(tmp, "%zu", numTracks);
    + 
    +@@ -675,6 +683,9 @@ void StagefrightMetadataRetriever::parseMetaData() {
    +     String8 timedTextLang;
    +     for (size_t i = 0; i < numTracks; ++i) {
    +         sp<MetaData> trackMeta = mExtractor->getTrackMetaData(i);
    ++        if (trackMeta == NULL) {
    ++            continue;
    ++        }
    + 
    +         int64_t durationUs;
    +         if (trackMeta->findInt64(kKeyDuration, &durationUs)) {
     diff --git a/media/libstagefright/SurfaceMediaSource.cpp b/media/libstagefright/SurfaceMediaSource.cpp
     index 15ff569..0e9b4e6 100644
     --- a/media/libstagefright/SurfaceMediaSource.cpp
    @@ -316,6 +405,22 @@ index 54f768a..8200bf1 100644
      void MediaBufferGroup::signalBufferReturned(MediaBuffer *) {
          mCondition.signal();
      }
    +diff --git a/media/libstagefright/httplive/LiveSession.cpp b/media/libstagefright/httplive/LiveSession.cpp
    +index 7abc019..590146d 100644
    +--- a/media/libstagefright/httplive/LiveSession.cpp
    ++++ b/media/libstagefright/httplive/LiveSession.cpp
    +@@ -157,6 +157,11 @@ bool LiveSession::BandwidthEstimator::estimateBandwidth(
    +     }
    + 
    +     *bandwidthBps = ((double)mTotalTransferBytes * 8E6 / mTotalTransferTimeUs);
    ++    static const int32_t kMaxBandwidthBps = 0x7fffffff / 7;
    ++    if (*bandwidthBps > kMaxBandwidthBps) {
    ++        ALOGW("Override bandwidth because it's too huge. %d -> %d", *bandwidthBps, kMaxBandwidthBps);
    ++        *bandwidthBps = kMaxBandwidthBps;
    ++    }
    +     mPrevEstimates.push_back(*bandwidthBps);
    +     while (mPrevEstimates.size() > 3) {
    +         mPrevEstimates.erase(mPrevEstimates.begin());
     diff --git a/media/libstagefright/omx/Android.mk b/media/libstagefright/omx/Android.mk
     index e4fbd81..8fc788f 100644
     --- a/media/libstagefright/omx/Android.mk
    @@ -497,10 +602,22 @@ index 8d7f71c..d98ad47 100644
      
      include $(BUILD_SHARED_LIBRARY)
     diff --git a/services/camera/libcameraservice/CameraService.cpp b/services/camera/libcameraservice/CameraService.cpp
    -index d0df6d1..a0c74d8 100644
    +index d0df6d1..0083738 100644
     --- a/services/camera/libcameraservice/CameraService.cpp
     +++ b/services/camera/libcameraservice/CameraService.cpp
    -@@ -831,7 +831,11 @@ String8 CameraService::toString(std::set<userid_t> intSet) {
    +@@ -273,7 +273,10 @@ void CameraService::onFirstRef()
    + 
    + sp<ICameraServiceProxy> CameraService::getCameraServiceProxy() {
    +     sp<IServiceManager> sm = defaultServiceManager();
    +-    sp<IBinder> binder = sm->getService(String16("media.camera.proxy"));
    ++    // Use checkService because cameraserver normally starts before the
    ++    // system server and the proxy service. So the long timeout that getService
    ++    // has before giving up is inappropriate.
    ++    sp<IBinder> binder = sm->checkService(String16("media.camera.proxy"));
    +     if (binder == nullptr) {
    +         return nullptr;
    +     }
    +@@ -831,7 +834,11 @@ String8 CameraService::toString(std::set<userid_t> intSet) {
      Status CameraService::initializeShimMetadata(int cameraId) {
          int uid = getCallingUid();
      
    @@ -512,7 +629,7 @@ index d0df6d1..a0c74d8 100644
          String8 id = String8::format("%d", cameraId);
          Status ret = Status::ok();
          sp<Client> tmp = nullptr;
    -@@ -912,7 +916,9 @@ Status CameraService::getLegacyParametersLazy(int cameraId,
    +@@ -912,7 +919,9 @@ Status CameraService::getLegacyParametersLazy(int cameraId,
      static bool isTrustedCallingUid(uid_t uid) {
          switch (uid) {
              case AID_MEDIA:        // mediaserver
    diff --git a/frameworks_base.patch b/frameworks_base.patch
    index ee5fd81..8cac5a1 100644
    --- a/frameworks_base.patch
    +++ b/frameworks_base.patch
    @@ -229,10 +229,10 @@ index 5f59e32..23172a2 100644
                      // this request
                      if (VDBG) {
     diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
    -index 85d2981..ba10c64 100644
    +index bc9d58e..d2dc0d0 100644
     --- a/services/core/java/com/android/server/am/ActivityManagerService.java
     +++ b/services/core/java/com/android/server/am/ActivityManagerService.java
    -@@ -9583,7 +9583,7 @@ public final class ActivityManagerService extends ActivityManagerNative
    +@@ -9590,7 +9590,7 @@ public final class ActivityManagerService extends ActivityManagerNative
              for (int i = 0; i < procsToKill.size(); i++) {
                  ProcessRecord pr = procsToKill.get(i);
                  if (pr.setSchedGroup == ProcessList.SCHED_GROUP_BACKGROUND
    @@ -241,7 +241,7 @@ index 85d2981..ba10c64 100644
                      pr.kill("remove task", true);
                  } else {
                      // We delay killing processes that are not in the background or running a receiver.
    -@@ -19157,26 +19157,28 @@ public final class ActivityManagerService extends ActivityManagerNative
    +@@ -19204,26 +19204,28 @@ public final class ActivityManagerService extends ActivityManagerNative
          // LIFETIME MANAGEMENT
          // =========================================================
      
    @@ -284,7 +284,7 @@ index 85d2981..ba10c64 100644
          }
      
          Association startAssociationLocked(int sourceUid, String sourceProcess, int sourceState,
    -@@ -19343,7 +19345,7 @@ public final class ActivityManagerService extends ActivityManagerNative
    +@@ -19390,7 +19392,7 @@ public final class ActivityManagerService extends ActivityManagerNative
              int schedGroup;
              int procState;
              boolean foregroundActivities = false;
    @@ -293,7 +293,7 @@ index 85d2981..ba10c64 100644
              if (app == TOP_APP) {
                  // The last app on the list is the foreground app.
                  adj = ProcessList.FOREGROUND_APP_ADJ;
    -@@ -19357,13 +19359,13 @@ public final class ActivityManagerService extends ActivityManagerNative
    +@@ -19404,13 +19406,13 @@ public final class ActivityManagerService extends ActivityManagerNative
                  schedGroup = ProcessList.SCHED_GROUP_DEFAULT;
                  app.adjType = "instrumentation";
                  procState = ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE;
    @@ -309,7 +309,7 @@ index 85d2981..ba10c64 100644
                          ? ProcessList.SCHED_GROUP_DEFAULT : ProcessList.SCHED_GROUP_BACKGROUND;
                  app.adjType = "broadcast";
                  procState = ActivityManager.PROCESS_STATE_RECEIVER;
    -@@ -20374,7 +20376,7 @@ public final class ActivityManagerService extends ActivityManagerNative
    +@@ -20421,7 +20423,7 @@ public final class ActivityManagerService extends ActivityManagerNative
                  if (DEBUG_SWITCH || DEBUG_OOM_ADJ) Slog.v(TAG_OOM_ADJ,
                          "Setting sched group of " + app.processName
                          + " to " + app.curSchedGroup);
    @@ -318,7 +318,7 @@ index 85d2981..ba10c64 100644
                          && app.setSchedGroup == ProcessList.SCHED_GROUP_BACKGROUND) {
                      app.kill(app.waitingToKill, true);
                      success = false;
    -@@ -21314,7 +21316,7 @@ public final class ActivityManagerService extends ActivityManagerNative
    +@@ -21361,7 +21363,7 @@ public final class ActivityManagerService extends ActivityManagerNative
                  for (i=mRemovedProcesses.size()-1; i>=0; i--) {
                      final ProcessRecord app = mRemovedProcesses.get(i);
                      if (app.activities.size() == 0
    diff --git a/frameworks_native.patch b/frameworks_native.patch
    index 4bc0763..617194a 100644
    --- a/frameworks_native.patch
    +++ b/frameworks_native.patch
    @@ -51,6 +51,18 @@ index 5885738..86c315c 100644
          return ok;
      }
      
    +diff --git a/cmds/flatland/GLHelper.cpp b/cmds/flatland/GLHelper.cpp
    +index ddf3aa8..5c04f6c 100644
    +--- a/cmds/flatland/GLHelper.cpp
    ++++ b/cmds/flatland/GLHelper.cpp
    +@@ -365,6 +365,7 @@ static bool compileShaderLines(GLenum shaderType, const char* const* lines,
    +     if (!result) {
    +         fprintf(stderr, "Shader source:\n");
    +         printShaderSource(lines);
    ++        delete[] src;
    +         return false;
    +     }
    +     delete[] src;
     diff --git a/include/gui/ISurfaceComposer.h b/include/gui/ISurfaceComposer.h
     index 74a4123..8dc6f6a 100644
     --- a/include/gui/ISurfaceComposer.h
    @@ -159,6 +171,34 @@ index f0b0ada..3577a33 100644
                  reply->writeInt32(res);
                  return NO_ERROR;
              }
    +diff --git a/libs/ui/Gralloc1On0Adapter.cpp b/libs/ui/Gralloc1On0Adapter.cpp
    +index d5b88de..ec7df31 100644
    +--- a/libs/ui/Gralloc1On0Adapter.cpp
    ++++ b/libs/ui/Gralloc1On0Adapter.cpp
    +@@ -288,6 +288,7 @@ gralloc1_error_t Gralloc1On0Adapter::allocateWithIdHook(
    + gralloc1_error_t Gralloc1On0Adapter::retain(
    +         const std::shared_ptr<Buffer>& buffer)
    + {
    ++    std::lock_guard<std::mutex> lock(mBufferMutex);
    +     buffer->retain();
    +     return GRALLOC1_ERROR_NONE;
    + }
    +@@ -295,6 +296,7 @@ gralloc1_error_t Gralloc1On0Adapter::retain(
    + gralloc1_error_t Gralloc1On0Adapter::release(
    +         const std::shared_ptr<Buffer>& buffer)
    + {
    ++    std::lock_guard<std::mutex> lock(mBufferMutex);
    +     if (!buffer->release()) {
    +         return GRALLOC1_ERROR_NONE;
    +     }
    +@@ -314,7 +316,6 @@ gralloc1_error_t Gralloc1On0Adapter::release(
    +         }
    +     }
    + 
    +-    std::lock_guard<std::mutex> lock(mBufferMutex);
    +     mBuffers.erase(handle);
    +     return GRALLOC1_ERROR_NONE;
    + }
     diff --git a/libs/ui/Region.cpp b/libs/ui/Region.cpp
     index ee152bf..9c82295 100644
     --- a/libs/ui/Region.cpp
    @@ -366,6 +406,19 @@ index b9be675..4dec34b 100644
              outCount += 1;
          }
      
    +diff --git a/services/inputflinger/InputWindow.h b/services/inputflinger/InputWindow.h
    +index e243637..4794b47 100644
    +--- a/services/inputflinger/InputWindow.h
    ++++ b/services/inputflinger/InputWindow.h
    +@@ -101,7 +101,7 @@ struct InputWindowInfo {
    +         TYPE_NAVIGATION_BAR     = FIRST_SYSTEM_WINDOW+19,
    +         TYPE_VOLUME_OVERLAY = FIRST_SYSTEM_WINDOW+20,
    +         TYPE_BOOT_PROGRESS = FIRST_SYSTEM_WINDOW+21,
    +-        TYPE_MAGNIFICATION_OVERLAY = FIRST_SYSTEM_WINDOW+22,
    ++        TYPE_MAGNIFICATION_OVERLAY = FIRST_SYSTEM_WINDOW+27,
    +         TYPE_DOCK_DIVIDER = FIRST_SYSTEM_WINDOW+34,
    +         LAST_SYSTEM_WINDOW      = 2999,
    +     };
     diff --git a/services/surfaceflinger/Android.mk b/services/surfaceflinger/Android.mk
     index ffda035..cb292ef 100644
     --- a/services/surfaceflinger/Android.mk
    @@ -380,6 +433,19 @@ index ffda035..cb292ef 100644
      ifeq ($(TARGET_BOARD_PLATFORM),omap4)
          LOCAL_CFLAGS += -DHAS_CONTEXT_PRIORITY
      endif
    +diff --git a/services/surfaceflinger/DisplayHardware/HWComposer_hwc1.cpp b/services/surfaceflinger/DisplayHardware/HWComposer_hwc1.cpp
    +index ef41658..086acc9 100644
    +--- a/services/surfaceflinger/DisplayHardware/HWComposer_hwc1.cpp
    ++++ b/services/surfaceflinger/DisplayHardware/HWComposer_hwc1.cpp
    +@@ -1260,7 +1260,7 @@ void HWComposer::dump(String8& result) const {
    +     }
    + 
    +     if (mHwc && mHwc->dump) {
    +-        const size_t SIZE = 4096;
    ++        const size_t SIZE = 16*1024;
    +         char buffer[SIZE];
    +         mHwc->dump(mHwc, buffer, SIZE);
    +         result.append(buffer);
     diff --git a/services/surfaceflinger/RenderEngine/GLES11RenderEngine.cpp b/services/surfaceflinger/RenderEngine/GLES11RenderEngine.cpp
     index 847cdb3..b2821b7 100644
     --- a/services/surfaceflinger/RenderEngine/GLES11RenderEngine.cpp
    @@ -737,6 +803,40 @@ index b98924b..2c3bd19 100644
      
          /* ------------------------------------------------------------------------
           * EGL
    +diff --git a/services/surfaceflinger/SurfaceFlingerConsumer.cpp b/services/surfaceflinger/SurfaceFlingerConsumer.cpp
    +index e0e4c61..6f2520b 100644
    +--- a/services/surfaceflinger/SurfaceFlingerConsumer.cpp
    ++++ b/services/surfaceflinger/SurfaceFlingerConsumer.cpp
    +@@ -70,6 +70,14 @@ status_t SurfaceFlingerConsumer::updateTexImage(BufferRejecter* rejecter,
    +         return err;
    +     }
    + 
    ++    if (autoRefresh) {
    ++        *autoRefresh = item.mAutoRefresh;
    ++    }
    ++
    ++    if (queuedBuffer) {
    ++        *queuedBuffer = item.mQueuedBuffer;
    ++    }
    ++
    +     // We call the rejecter here, in case the caller has a reason to
    +     // not accept this buffer.  This is used by SurfaceFlinger to
    +     // reject buffers which have the wrong size
    +@@ -79,14 +87,6 @@ status_t SurfaceFlingerConsumer::updateTexImage(BufferRejecter* rejecter,
    +         return BUFFER_REJECTED;
    +     }
    + 
    +-    if (autoRefresh) {
    +-        *autoRefresh = item.mAutoRefresh;
    +-    }
    +-
    +-    if (queuedBuffer) {
    +-        *queuedBuffer = item.mQueuedBuffer;
    +-    }
    +-
    +     // Release the previous buffer.
    + #ifdef USE_HWC2
    +     err = updateAndReleaseLocked(item, &mPendingRelease);
     diff --git a/services/surfaceflinger/SurfaceFlinger_hwc1.cpp b/services/surfaceflinger/SurfaceFlinger_hwc1.cpp
     index b0f418c..ca03830 100644
     --- a/services/surfaceflinger/SurfaceFlinger_hwc1.cpp
    @@ -873,3793 +973,3 @@ index b0f418c..ca03830 100644
                              if (DEBUG_SCREENSHOTS) {
                                  uint32_t* pixels = new uint32_t[reqWidth*reqHeight];
                                  getRenderEngine().readPixels(0, 0, reqWidth, reqHeight, pixels);
    -diff --git a/services/surfaceflinger/SurfaceFlinger_hwc1.cpp.orig b/services/surfaceflinger/SurfaceFlinger_hwc1.cpp.orig
    -new file mode 100644
    -index 0000000..709bbff
    ---- /dev/null
    -+++ b/services/surfaceflinger/SurfaceFlinger_hwc1.cpp.orig
    -@@ -0,0 +1,3784 @@
    -+/*
    -+ * Copyright (C) 2007 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.
    -+ */
    -+
    -+#define ATRACE_TAG ATRACE_TAG_GRAPHICS
    -+
    -+#include <stdint.h>
    -+#include <sys/types.h>
    -+#include <errno.h>
    -+#include <math.h>
    -+#include <dlfcn.h>
    -+#include <inttypes.h>
    -+#include <stdatomic.h>
    -+
    -+#include <EGL/egl.h>
    -+
    -+#include <cutils/log.h>
    -+#include <cutils/properties.h>
    -+
    -+#include <binder/IPCThreadState.h>
    -+#include <binder/IServiceManager.h>
    -+#include <binder/MemoryHeapBase.h>
    -+#include <binder/PermissionCache.h>
    -+
    -+#include <ui/DisplayInfo.h>
    -+#include <ui/DisplayStatInfo.h>
    -+
    -+#include <gui/BitTube.h>
    -+#include <gui/BufferQueue.h>
    -+#include <gui/GuiConfig.h>
    -+#include <gui/IDisplayEventConnection.h>
    -+#include <gui/Surface.h>
    -+#include <gui/GraphicBufferAlloc.h>
    -+
    -+#include <ui/GraphicBufferAllocator.h>
    -+#include <ui/HdrCapabilities.h>
    -+#include <ui/PixelFormat.h>
    -+#include <ui/UiConfig.h>
    -+
    -+#include <utils/misc.h>
    -+#include <utils/String8.h>
    -+#include <utils/String16.h>
    -+#include <utils/StopWatch.h>
    -+#include <utils/Timers.h>
    -+#include <utils/Trace.h>
    -+
    -+#include <private/android_filesystem_config.h>
    -+#include <private/gui/SyncFeatures.h>
    -+
    -+#include <set>
    -+
    -+#include "Client.h"
    -+#include "clz.h"
    -+#include "Colorizer.h"
    -+#include "DdmConnection.h"
    -+#include "DisplayDevice.h"
    -+#include "DispSync.h"
    -+#include "EventControlThread.h"
    -+#include "EventThread.h"
    -+#include "Layer.h"
    -+#include "LayerDim.h"
    -+#include "SurfaceFlinger.h"
    -+
    -+#include "DisplayHardware/FramebufferSurface.h"
    -+#include "DisplayHardware/HWComposer.h"
    -+#include "DisplayHardware/VirtualDisplaySurface.h"
    -+
    -+#include "Effects/Daltonizer.h"
    -+
    -+#include "RenderEngine/RenderEngine.h"
    -+#include <cutils/compiler.h>
    -+
    -+#define DISPLAY_COUNT       1
    -+
    -+/*
    -+ * DEBUG_SCREENSHOTS: set to true to check that screenshots are not all
    -+ * black pixels.
    -+ */
    -+#define DEBUG_SCREENSHOTS   false
    -+
    -+EGLAPI const char* eglQueryStringImplementationANDROID(EGLDisplay dpy, EGLint name);
    -+
    -+namespace android {
    -+
    -+// This is the phase offset in nanoseconds of the software vsync event
    -+// relative to the vsync event reported by HWComposer.  The software vsync
    -+// event is when SurfaceFlinger and Choreographer-based applications run each
    -+// frame.
    -+//
    -+// This phase offset allows adjustment of the minimum latency from application
    -+// wake-up (by Choregographer) time to the time at which the resulting window
    -+// image is displayed.  This value may be either positive (after the HW vsync)
    -+// or negative (before the HW vsync).  Setting it to 0 will result in a
    -+// minimum latency of two vsync periods because the app and SurfaceFlinger
    -+// will run just after the HW vsync.  Setting it to a positive number will
    -+// result in the minimum latency being:
    -+//
    -+//     (2 * VSYNC_PERIOD - (vsyncPhaseOffsetNs % VSYNC_PERIOD))
    -+//
    -+// Note that reducing this latency makes it more likely for the applications
    -+// to not have their window content image ready in time.  When this happens
    -+// the latency will end up being an additional vsync period, and animations
    -+// will hiccup.  Therefore, this latency should be tuned somewhat
    -+// conservatively (or at least with awareness of the trade-off being made).
    -+static const int64_t vsyncPhaseOffsetNs = VSYNC_EVENT_PHASE_OFFSET_NS;
    -+
    -+// This is the phase offset at which SurfaceFlinger's composition runs.
    -+static const int64_t sfVsyncPhaseOffsetNs = SF_VSYNC_EVENT_PHASE_OFFSET_NS;
    -+
    -+// ---------------------------------------------------------------------------
    -+
    -+const String16 sHardwareTest("android.permission.HARDWARE_TEST");
    -+const String16 sAccessSurfaceFlinger("android.permission.ACCESS_SURFACE_FLINGER");
    -+const String16 sReadFramebuffer("android.permission.READ_FRAME_BUFFER");
    -+const String16 sDump("android.permission.DUMP");
    -+
    -+// ---------------------------------------------------------------------------
    -+
    -+SurfaceFlinger::SurfaceFlinger()
    -+    :   BnSurfaceComposer(),
    -+        mTransactionFlags(0),
    -+        mTransactionPending(false),
    -+        mAnimTransactionPending(false),
    -+        mLayersRemoved(false),
    -+        mRepaintEverything(0),
    -+        mRenderEngine(NULL),
    -+        mBootTime(systemTime()),
    -+        mVisibleRegionsDirty(false),
    -+        mHwWorkListDirty(false),
    -+        mAnimCompositionPending(false),
    -+        mDebugRegion(0),
    -+        mDebugDDMS(0),
    -+        mDebugDisableHWC(0),
    -+        mDebugDisableTransformHint(0),
    -+        mDebugInSwapBuffers(0),
    -+        mLastSwapBufferTime(0),
    -+        mDebugInTransaction(0),
    -+        mLastTransactionTime(0),
    -+        mBootFinished(false),
    -+        mForceFullDamage(false),
    -+        mPrimaryDispSync("PrimaryDispSync"),
    -+        mPrimaryHWVsyncEnabled(false),
    -+        mHWVsyncAvailable(false),
    -+        mDaltonize(false),
    -+        mHasColorMatrix(false),
    -+        mHasPoweredOff(false),
    -+        mFrameBuckets(),
    -+        mTotalTime(0),
    -+        mLastSwapTime(0)
    -+{
    -+    ALOGI("SurfaceFlinger is starting");
    -+
    -+    // debugging stuff...
    -+    char value[PROPERTY_VALUE_MAX];
    -+
    -+    property_get("ro.bq.gpu_to_cpu_unsupported", value, "0");
    -+    mGpuToCpuSupported = !atoi(value);
    -+
    -+    property_get("debug.sf.showupdates", value, "0");
    -+    mDebugRegion = atoi(value);
    -+
    -+    property_get("debug.sf.ddms", value, "0");
    -+    mDebugDDMS = atoi(value);
    -+    if (mDebugDDMS) {
    -+        if (!startDdmConnection()) {
    -+            // start failed, and DDMS debugging not enabled
    -+            mDebugDDMS = 0;
    -+        }
    -+    }
    -+    ALOGI_IF(mDebugRegion, "showupdates enabled");
    -+    ALOGI_IF(mDebugDDMS, "DDMS debugging enabled");
    -+
    -+    property_get("debug.sf.disable_hwc_vds", value, "0");
    -+    mUseHwcVirtualDisplays = !atoi(value);
    -+    ALOGI_IF(!mUseHwcVirtualDisplays, "Disabling HWC virtual displays");
    -+}
    -+
    -+void SurfaceFlinger::onFirstRef()
    -+{
    -+    mEventQueue.init(this);
    -+}
    -+
    -+SurfaceFlinger::~SurfaceFlinger()
    -+{
    -+    EGLDisplay display = eglGetDisplay(EGL_DEFAULT_DISPLAY);
    -+    eglMakeCurrent(display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
    -+    eglTerminate(display);
    -+}
    -+
    -+void SurfaceFlinger::binderDied(const wp<IBinder>& /* who */)
    -+{
    -+    // the window manager died on us. prepare its eulogy.
    -+
    -+    // restore initial conditions (default device unblank, etc)
    -+    initializeDisplays();
    -+
    -+    // restart the boot-animation
    -+    startBootAnim();
    -+}
    -+
    -+sp<ISurfaceComposerClient> SurfaceFlinger::createConnection()
    -+{
    -+    sp<ISurfaceComposerClient> bclient;
    -+    sp<Client> client(new Client(this));
    -+    status_t err = client->initCheck();
    -+    if (err == NO_ERROR) {
    -+        bclient = client;
    -+    }
    -+    return bclient;
    -+}
    -+
    -+sp<IBinder> SurfaceFlinger::createDisplay(const String8& displayName,
    -+        bool secure)
    -+{
    -+    class DisplayToken : public BBinder {
    -+        sp<SurfaceFlinger> flinger;
    -+        virtual ~DisplayToken() {
    -+             // no more references, this display must be terminated
    -+             Mutex::Autolock _l(flinger->mStateLock);
    -+             flinger->mCurrentState.displays.removeItem(this);
    -+             flinger->setTransactionFlags(eDisplayTransactionNeeded);
    -+         }
    -+     public:
    -+        DisplayToken(const sp<SurfaceFlinger>& flinger)
    -+            : flinger(flinger) {
    -+        }
    -+    };
    -+
    -+    sp<BBinder> token = new DisplayToken(this);
    -+
    -+    Mutex::Autolock _l(mStateLock);
    -+    DisplayDeviceState info(DisplayDevice::DISPLAY_VIRTUAL, secure);
    -+    info.displayName = displayName;
    -+    mCurrentState.displays.add(token, info);
    -+
    -+    return token;
    -+}
    -+
    -+void SurfaceFlinger::destroyDisplay(const sp<IBinder>& display) {
    -+    Mutex::Autolock _l(mStateLock);
    -+
    -+    ssize_t idx = mCurrentState.displays.indexOfKey(display);
    -+    if (idx < 0) {
    -+        ALOGW("destroyDisplay: invalid display token");
    -+        return;
    -+    }
    -+
    -+    const DisplayDeviceState& info(mCurrentState.displays.valueAt(idx));
    -+    if (!info.isVirtualDisplay()) {
    -+        ALOGE("destroyDisplay called for non-virtual display");
    -+        return;
    -+    }
    -+
    -+    mCurrentState.displays.removeItemsAt(idx);
    -+    setTransactionFlags(eDisplayTransactionNeeded);
    -+}
    -+
    -+void SurfaceFlinger::createBuiltinDisplayLocked(DisplayDevice::DisplayType type) {
    -+    ALOGW_IF(mBuiltinDisplays[type],
    -+            "Overwriting display token for display type %d", type);
    -+    mBuiltinDisplays[type] = new BBinder();
    -+    // All non-virtual displays are currently considered secure.
    -+    DisplayDeviceState info(type, true);
    -+    mCurrentState.displays.add(mBuiltinDisplays[type], info);
    -+}
    -+
    -+sp<IBinder> SurfaceFlinger::getBuiltInDisplay(int32_t id) {
    -+    if (uint32_t(id) >= DisplayDevice::NUM_BUILTIN_DISPLAY_TYPES) {
    -+        ALOGE("getDefaultDisplay: id=%d is not a valid default display id", id);
    -+        return NULL;
    -+    }
    -+    return mBuiltinDisplays[id];
    -+}
    -+
    -+sp<IGraphicBufferAlloc> SurfaceFlinger::createGraphicBufferAlloc()
    -+{
    -+    sp<GraphicBufferAlloc> gba(new GraphicBufferAlloc());
    -+    return gba;
    -+}
    -+
    -+void SurfaceFlinger::bootFinished()
    -+{
    -+    const nsecs_t now = systemTime();
    -+    const nsecs_t duration = now - mBootTime;
    -+    ALOGI("Boot is finished (%ld ms)", long(ns2ms(duration)) );
    -+    mBootFinished = true;
    -+
    -+    // wait patiently for the window manager death
    -+    const String16 name("window");
    -+    sp<IBinder> window(defaultServiceManager()->getService(name));
    -+    if (window != 0) {
    -+        window->linkToDeath(static_cast<IBinder::DeathRecipient*>(this));
    -+    }
    -+
    -+    // stop boot animation
    -+    // formerly we would just kill the process, but we now ask it to exit so it
    -+    // can choose where to stop the animation.
    -+    property_set("service.bootanim.exit", "1");
    -+
    -+    const int LOGTAG_SF_STOP_BOOTANIM = 60110;
    -+    LOG_EVENT_LONG(LOGTAG_SF_STOP_BOOTANIM,
    -+                   ns2ms(systemTime(SYSTEM_TIME_MONOTONIC)));
    -+}
    -+
    -+void SurfaceFlinger::deleteTextureAsync(uint32_t texture) {
    -+    class MessageDestroyGLTexture : public MessageBase {
    -+        RenderEngine& engine;
    -+        uint32_t texture;
    -+    public:
    -+        MessageDestroyGLTexture(RenderEngine& engine, uint32_t texture)
    -+            : engine(engine), texture(texture) {
    -+        }
    -+        virtual bool handler() {
    -+            engine.deleteTextures(1, &texture);
    -+            return true;
    -+        }
    -+    };
    -+    postMessageAsync(new MessageDestroyGLTexture(getRenderEngine(), texture));
    -+}
    -+
    -+class DispSyncSource : public VSyncSource, private DispSync::Callback {
    -+public:
    -+    DispSyncSource(DispSync* dispSync, nsecs_t phaseOffset, bool traceVsync,
    -+        const char* name) :
    -+            mName(name),
    -+            mValue(0),
    -+            mTraceVsync(traceVsync),
    -+            mVsyncOnLabel(String8::format("VsyncOn-%s", name)),
    -+            mVsyncEventLabel(String8::format("VSYNC-%s", name)),
    -+            mDispSync(dispSync),
    -+            mCallbackMutex(),
    -+            mCallback(),
    -+            mVsyncMutex(),
    -+            mPhaseOffset(phaseOffset),
    -+            mEnabled(false) {}
    -+
    -+    virtual ~DispSyncSource() {}
    -+
    -+    virtual void setVSyncEnabled(bool enable) {
    -+        Mutex::Autolock lock(mVsyncMutex);
    -+        if (enable) {
    -+            status_t err = mDispSync->addEventListener(mName, mPhaseOffset,
    -+                    static_cast<DispSync::Callback*>(this));
    -+            if (err != NO_ERROR) {
    -+                ALOGE("error registering vsync callback: %s (%d)",
    -+                        strerror(-err), err);
    -+            }
    -+            //ATRACE_INT(mVsyncOnLabel.string(), 1);
    -+        } else {
    -+            status_t err = mDispSync->removeEventListener(
    -+                    static_cast<DispSync::Callback*>(this));
    -+            if (err != NO_ERROR) {
    -+                ALOGE("error unregistering vsync callback: %s (%d)",
    -+                        strerror(-err), err);
    -+            }
    -+            //ATRACE_INT(mVsyncOnLabel.string(), 0);
    -+        }
    -+        mEnabled = enable;
    -+    }
    -+
    -+    virtual void setCallback(const sp<VSyncSource::Callback>& callback) {
    -+        Mutex::Autolock lock(mCallbackMutex);
    -+        mCallback = callback;
    -+    }
    -+
    -+    virtual void setPhaseOffset(nsecs_t phaseOffset) {
    -+        Mutex::Autolock lock(mVsyncMutex);
    -+
    -+        // Normalize phaseOffset to [0, period)
    -+        auto period = mDispSync->getPeriod();
    -+        phaseOffset %= period;
    -+        if (phaseOffset < 0) {
    -+            // If we're here, then phaseOffset is in (-period, 0). After this
    -+            // operation, it will be in (0, period)
    -+            phaseOffset += period;
    -+        }
    -+        mPhaseOffset = phaseOffset;
    -+
    -+        // If we're not enabled, we don't need to mess with the listeners
    -+        if (!mEnabled) {
    -+            return;
    -+        }
    -+
    -+        // Remove the listener with the old offset
    -+        status_t err = mDispSync->removeEventListener(
    -+                static_cast<DispSync::Callback*>(this));
    -+        if (err != NO_ERROR) {
    -+            ALOGE("error unregistering vsync callback: %s (%d)",
    -+                    strerror(-err), err);
    -+        }
    -+
    -+        // Add a listener with the new offset
    -+        err = mDispSync->addEventListener(mName, mPhaseOffset,
    -+                static_cast<DispSync::Callback*>(this));
    -+        if (err != NO_ERROR) {
    -+            ALOGE("error registering vsync callback: %s (%d)",
    -+                    strerror(-err), err);
    -+        }
    -+    }
    -+
    -+private:
    -+    virtual void onDispSyncEvent(nsecs_t when) {
    -+        sp<VSyncSource::Callback> callback;
    -+        {
    -+            Mutex::Autolock lock(mCallbackMutex);
    -+            callback = mCallback;
    -+
    -+            if (mTraceVsync) {
    -+                mValue = (mValue + 1) % 2;
    -+                ATRACE_INT(mVsyncEventLabel.string(), mValue);
    -+            }
    -+        }
    -+
    -+        if (callback != NULL) {
    -+            callback->onVSyncEvent(when);
    -+        }
    -+    }
    -+
    -+    const char* const mName;
    -+
    -+    int mValue;
    -+
    -+    const bool mTraceVsync;
    -+    const String8 mVsyncOnLabel;
    -+    const String8 mVsyncEventLabel;
    -+
    -+    DispSync* mDispSync;
    -+
    -+    Mutex mCallbackMutex; // Protects the following
    -+    sp<VSyncSource::Callback> mCallback;
    -+
    -+    Mutex mVsyncMutex; // Protects the following
    -+    nsecs_t mPhaseOffset;
    -+    bool mEnabled;
    -+};
    -+
    -+void SurfaceFlinger::init() {
    -+    ALOGI(  "SurfaceFlinger's main thread ready to run. "
    -+            "Initializing graphics H/W...");
    -+
    -+    Mutex::Autolock _l(mStateLock);
    -+
    -+    // initialize EGL for the default display
    -+    mEGLDisplay = eglGetDisplay(EGL_DEFAULT_DISPLAY);
    -+    eglInitialize(mEGLDisplay, NULL, NULL);
    -+
    -+    // start the EventThread
    -+    sp<VSyncSource> vsyncSrc = new DispSyncSource(&mPrimaryDispSync,
    -+            vsyncPhaseOffsetNs, true, "app");
    -+    mEventThread = new EventThread(vsyncSrc, *this);
    -+    sp<VSyncSource> sfVsyncSrc = new DispSyncSource(&mPrimaryDispSync,
    -+            sfVsyncPhaseOffsetNs, true, "sf");
    -+    mSFEventThread = new EventThread(sfVsyncSrc, *this);
    -+    mEventQueue.setEventThread(mSFEventThread);
    -+
    -+    // set SFEventThread to SCHED_FIFO to minimize jitter
    -+<<<<<<< HEAD
    -+    if (mSFEventThread != NULL) {
    -+        struct sched_param param = {0};
    -+        param.sched_priority = 1;
    -+        if (sched_setscheduler(mSFEventThread->getTid(), SCHED_FIFO, &param) != 0) {
    -+            ALOGE("Couldn't set SCHED_FIFO for SFEventThread");
    -+        }
    -+=======
    -+    struct sched_param param = {0};
    -+    param.sched_priority = 2;
    -+    if (sched_setscheduler(mSFEventThread->getTid(), SCHED_FIFO, &param) != 0) {
    -+        ALOGE("Couldn't set SCHED_FIFO for SFEventThread");
    -+>>>>>>> android-7.1.1_r1
    -+    }
    -+
    -+    // Initialize the H/W composer object.  There may or may not be an
    -+    // actual hardware composer underneath.
    -+    mHwc = new HWComposer(this,
    -+            *static_cast<HWComposer::EventHandler *>(this));
    -+
    -+    // get a RenderEngine for the given display / config (can't fail)
    -+    mRenderEngine = RenderEngine::create(mEGLDisplay, mHwc->getVisualID());
    -+
    -+    // retrieve the EGL context that was selected/created
    -+    mEGLContext = mRenderEngine->getEGLContext();
    -+
    -+    LOG_ALWAYS_FATAL_IF(mEGLContext == EGL_NO_CONTEXT,
    -+            "couldn't create EGLContext");
    -+
    -+    // initialize our non-virtual displays
    -+    for (size_t i=0 ; i<DisplayDevice::NUM_BUILTIN_DISPLAY_TYPES ; i++) {
    -+        DisplayDevice::DisplayType type((DisplayDevice::DisplayType)i);
    -+        // set-up the displays that are already connected
    -+        if (mHwc->isConnected(i) || type==DisplayDevice::DISPLAY_PRIMARY) {
    -+            // All non-virtual displays are currently considered secure.
    -+            bool isSecure = true;
    -+            createBuiltinDisplayLocked(type);
    -+            wp<IBinder> token = mBuiltinDisplays[i];
    -+
    -+            sp<IGraphicBufferProducer> producer;
    -+            sp<IGraphicBufferConsumer> consumer;
    -+            BufferQueue::createBufferQueue(&producer, &consumer,
    -+                    new GraphicBufferAlloc());
    -+
    -+            sp<FramebufferSurface> fbs = new FramebufferSurface(*mHwc, i,
    -+                    consumer);
    -+            int32_t hwcId = allocateHwcDisplayId(type);
    -+            sp<DisplayDevice> hw = new DisplayDevice(this,
    -+                    type, hwcId, mHwc->getFormat(hwcId), isSecure, token,
    -+                    fbs, producer,
    -+                    mRenderEngine->getEGLConfig());
    -+            if (i > DisplayDevice::DISPLAY_PRIMARY) {
    -+                // FIXME: currently we don't get blank/unblank requests
    -+                // for displays other than the main display, so we always
    -+                // assume a connected display is unblanked.
    -+                ALOGD("marking display %zu as acquired/unblanked", i);
    -+                hw->setPowerMode(HWC_POWER_MODE_NORMAL);
    -+            }
    -+            mDisplays.add(token, hw);
    -+        }
    -+    }
    -+
    -+    // make the GLContext current so that we can create textures when creating Layers
    -+    // (which may happens before we render something)
    -+    getDefaultDisplayDevice()->makeCurrent(mEGLDisplay, mEGLContext);
    -+
    -+    mEventControlThread = new EventControlThread(this);
    -+    mEventControlThread->run("EventControl", PRIORITY_URGENT_DISPLAY);
    -+
    -+    // set a fake vsync period if there is no HWComposer
    -+    if (mHwc->initCheck() != NO_ERROR) {
    -+        mPrimaryDispSync.setPeriod(16666667);
    -+    }
    -+
    -+    // initialize our drawing state
    -+    mDrawingState = mCurrentState;
    -+
    -+    // set initial conditions (e.g. unblank default device)
    -+    initializeDisplays();
    -+
    -+    mRenderEngine->primeCache();
    -+
    -+    // start boot animation
    -+    startBootAnim();
    -+}
    -+
    -+int32_t SurfaceFlinger::allocateHwcDisplayId(DisplayDevice::DisplayType type) {
    -+    return (uint32_t(type) < DisplayDevice::NUM_BUILTIN_DISPLAY_TYPES) ?
    -+            type : mHwc->allocateDisplayId();
    -+}
    -+
    -+void SurfaceFlinger::startBootAnim() {
    -+    // start boot animation
    -+    property_set("service.bootanim.exit", "0");
    -+    property_set("ctl.start", "bootanim");
    -+}
    -+
    -+size_t SurfaceFlinger::getMaxTextureSize() const {
    -+    return mRenderEngine->getMaxTextureSize();
    -+}
    -+
    -+size_t SurfaceFlinger::getMaxViewportDims() const {
    -+    return mRenderEngine->getMaxViewportDims();
    -+}
    -+
    -+// ----------------------------------------------------------------------------
    -+
    -+bool SurfaceFlinger::authenticateSurfaceTexture(
    -+        const sp<IGraphicBufferProducer>& bufferProducer) const {
    -+    Mutex::Autolock _l(mStateLock);
    -+    sp<IBinder> surfaceTextureBinder(IInterface::asBinder(bufferProducer));
    -+    return mGraphicBufferProducerList.indexOf(surfaceTextureBinder) >= 0;
    -+}
    -+
    -+status_t SurfaceFlinger::getDisplayConfigs(const sp<IBinder>& display,
    -+        Vector<DisplayInfo>* configs) {
    -+    if ((configs == NULL) || (display.get() == NULL)) {
    -+        return BAD_VALUE;
    -+    }
    -+
    -+    int32_t type = getDisplayType(display);
    -+    if (type < 0) return type;
    -+
    -+    // TODO: Not sure if display density should handled by SF any longer
    -+    class Density {
    -+        static int getDensityFromProperty(char const* propName) {
    -+            char property[PROPERTY_VALUE_MAX];
    -+            int density = 0;
    -+            if (property_get(propName, property, NULL) > 0) {
    -+                density = atoi(property);
    -+            }
    -+            return density;
    -+        }
    -+    public:
    -+        static int getEmuDensity() {
    -+            return getDensityFromProperty("qemu.sf.lcd_density"); }
    -+        static int getBuildDensity()  {
    -+            return getDensityFromProperty("ro.sf.lcd_density"); }
    -+    };
    -+
    -+    configs->clear();
    -+
    -+    const Vector<HWComposer::DisplayConfig>& hwConfigs =
    -+            getHwComposer().getConfigs(type);
    -+    for (size_t c = 0; c < hwConfigs.size(); ++c) {
    -+        const HWComposer::DisplayConfig& hwConfig = hwConfigs[c];
    -+        DisplayInfo info = DisplayInfo();
    -+
    -+        float xdpi = hwConfig.xdpi;
    -+        float ydpi = hwConfig.ydpi;
    -+
    -+        if (type == DisplayDevice::DISPLAY_PRIMARY) {
    -+            // The density of the device is provided by a build property
    -+            float density = Density::getBuildDensity() / 160.0f;
    -+            if (density == 0) {
    -+                // the build doesn't provide a density -- this is wrong!
    -+                // use xdpi instead
    -+                ALOGE("ro.sf.lcd_density must be defined as a build property");
    -+                density = xdpi / 160.0f;
    -+            }
    -+            if (Density::getEmuDensity()) {
    -+                // if "qemu.sf.lcd_density" is specified, it overrides everything
    -+                xdpi = ydpi = density = Density::getEmuDensity();
    -+                density /= 160.0f;
    -+            }
    -+            info.density = density;
    -+
    -+            // TODO: this needs to go away (currently needed only by webkit)
    -+            sp<const DisplayDevice> hw(getDefaultDisplayDevice());
    -+            info.orientation = hw->getOrientation();
    -+        } else {
    -+            // TODO: where should this value come from?
    -+            static const int TV_DENSITY = 213;
    -+            info.density = TV_DENSITY / 160.0f;
    -+            info.orientation = 0;
    -+        }
    -+
    -+        char value[PROPERTY_VALUE_MAX];
    -+        property_get("ro.sf.hwrotation", value, "0");
    -+        int additionalRot = atoi(value) / 90;
    -+        if ((type == DisplayDevice::DISPLAY_PRIMARY) && (additionalRot & DisplayState::eOrientationSwapMask)) {
    -+            info.h = hwConfig.width;
    -+            info.w = hwConfig.height;
    -+            info.xdpi = ydpi;
    -+            info.ydpi = xdpi;
    -+        }
    -+        else {
    -+            info.w = hwConfig.width;
    -+            info.h = hwConfig.height;
    -+            info.xdpi = xdpi;
    -+            info.ydpi = ydpi;
    -+        }
    -+        info.fps = float(1e9 / hwConfig.refresh);
    -+        info.appVsyncOffset = VSYNC_EVENT_PHASE_OFFSET_NS;
    -+
    -+        // This is how far in advance a buffer must be queued for
    -+        // presentation at a given time.  If you want a buffer to appear
    -+        // on the screen at time N, you must submit the buffer before
    -+        // (N - presentationDeadline).
    -+        //
    -+        // Normally it's one full refresh period (to give SF a chance to
    -+        // latch the buffer), but this can be reduced by configuring a
    -+        // DispSync offset.  Any additional delays introduced by the hardware
    -+        // composer or panel must be accounted for here.
    -+        //
    -+        // We add an additional 1ms to allow for processing time and
    -+        // differences between the ideal and actual refresh rate.
    -+        info.presentationDeadline =
    -+                hwConfig.refresh - SF_VSYNC_EVENT_PHASE_OFFSET_NS + 1000000;
    -+
    -+        // All non-virtual displays are currently considered secure.
    -+        info.secure = true;
    -+
    -+        configs->push_back(info);
    -+    }
    -+
    -+    return NO_ERROR;
    -+}
    -+
    -+status_t SurfaceFlinger::getDisplayStats(const sp<IBinder>& /* display */,
    -+        DisplayStatInfo* stats) {
    -+    if (stats == NULL) {
    -+        return BAD_VALUE;
    -+    }
    -+
    -+    // FIXME for now we always return stats for the primary display
    -+    memset(stats, 0, sizeof(*stats));
    -+    stats->vsyncTime   = mPrimaryDispSync.computeNextRefresh(0);
    -+    stats->vsyncPeriod = mPrimaryDispSync.getPeriod();
    -+    return NO_ERROR;
    -+}
    -+
    -+int SurfaceFlinger::getActiveConfig(const sp<IBinder>& display) {
    -+    sp<DisplayDevice> device(getDisplayDevice(display));
    -+    if (device != NULL) {
    -+        return device->getActiveConfig();
    -+    }
    -+    return BAD_VALUE;
    -+}
    -+
    -+void SurfaceFlinger::setActiveConfigInternal(const sp<DisplayDevice>& hw, int mode) {
    -+    ALOGD("Set active config mode=%d, type=%d flinger=%p", mode, hw->getDisplayType(),
    -+          this);
    -+    int32_t type = hw->getDisplayType();
    -+    int currentMode = hw->getActiveConfig();
    -+
    -+    if (mode == currentMode) {
    -+        ALOGD("Screen type=%d is already mode=%d", hw->getDisplayType(), mode);
    -+        return;
    -+    }
    -+
    -+    if (type >= DisplayDevice::NUM_BUILTIN_DISPLAY_TYPES) {
    -+        ALOGW("Trying to set config for virtual display");
    -+        return;
    -+    }
    -+
    -+    hw->setActiveConfig(mode);
    -+    getHwComposer().setActiveConfig(type, mode);
    -+}
    -+
    -+status_t SurfaceFlinger::setActiveConfig(const sp<IBinder>& display, int mode) {
    -+    class MessageSetActiveConfig: public MessageBase {
    -+        SurfaceFlinger& mFlinger;
    -+        sp<IBinder> mDisplay;
    -+        int mMode;
    -+    public:
    -+        MessageSetActiveConfig(SurfaceFlinger& flinger, const sp<IBinder>& disp,
    -+                               int mode) :
    -+            mFlinger(flinger), mDisplay(disp) { mMode = mode; }
    -+        virtual bool handler() {
    -+            Vector<DisplayInfo> configs;
    -+            mFlinger.getDisplayConfigs(mDisplay, &configs);
    -+            if (mMode < 0 || mMode >= static_cast<int>(configs.size())) {
    -+                ALOGE("Attempt to set active config = %d for display with %zu configs",
    -+                        mMode, configs.size());
    -+            }
    -+            sp<DisplayDevice> hw(mFlinger.getDisplayDevice(mDisplay));
    -+            if (hw == NULL) {
    -+                ALOGE("Attempt to set active config = %d for null display %p",
    -+                        mMode, mDisplay.get());
    -+            } else if (hw->getDisplayType() >= DisplayDevice::DISPLAY_VIRTUAL) {
    -+                ALOGW("Attempt to set active config = %d for virtual display",
    -+                        mMode);
    -+            } else {
    -+                mFlinger.setActiveConfigInternal(hw, mMode);
    -+            }
    -+            return true;
    -+        }
    -+    };
    -+    sp<MessageBase> msg = new MessageSetActiveConfig(*this, display, mode);
    -+    postMessageSync(msg);
    -+    return NO_ERROR;
    -+}
    -+
    -+status_t SurfaceFlinger::getDisplayColorModes(const sp<IBinder>& display,
    -+        Vector<android_color_mode_t>* outColorModes) {
    -+    if (outColorModes == nullptr || display.get() == nullptr) {
    -+        return BAD_VALUE;
    -+    }
    -+
    -+    int32_t type = getDisplayType(display);
    -+    if (type < 0) return type;
    -+
    -+    std::set<android_color_mode_t> colorModes;
    -+    for (const HWComposer::DisplayConfig& hwConfig : getHwComposer().getConfigs(type)) {
    -+        colorModes.insert(hwConfig.colorMode);
    -+    }
    -+
    -+    outColorModes->clear();
    -+    std::copy(colorModes.cbegin(), colorModes.cend(), std::back_inserter(*outColorModes));
    -+
    -+    return NO_ERROR;
    -+}
    -+
    -+android_color_mode_t SurfaceFlinger::getActiveColorMode(const sp<IBinder>& display) {
    -+    if (display.get() == nullptr) return static_cast<android_color_mode_t>(BAD_VALUE);
    -+
    -+    int32_t type = getDisplayType(display);
    -+    if (type < 0) return static_cast<android_color_mode_t>(type);
    -+
    -+    return getHwComposer().getColorMode(type);
    -+}
    -+
    -+status_t SurfaceFlinger::setActiveColorMode(const sp<IBinder>& display,
    -+        android_color_mode_t colorMode) {
    -+    if (display.get() == nullptr || colorMode < 0) {
    -+        return BAD_VALUE;
    -+    }
    -+
    -+    int32_t type = getDisplayType(display);
    -+    if (type < 0) return type;
    -+    const Vector<HWComposer::DisplayConfig>& hwConfigs = getHwComposer().getConfigs(type);
    -+    HWComposer::DisplayConfig desiredConfig = hwConfigs[getHwComposer().getCurrentConfig(type)];
    -+    desiredConfig.colorMode = colorMode;
    -+    for (size_t c = 0; c < hwConfigs.size(); ++c) {
    -+        const HWComposer::DisplayConfig config = hwConfigs[c];
    -+        if (config == desiredConfig) {
    -+            return setActiveConfig(display, c);
    -+        }
    -+    }
    -+    return BAD_VALUE;
    -+}
    -+
    -+status_t SurfaceFlinger::clearAnimationFrameStats() {
    -+    Mutex::Autolock _l(mStateLock);
    -+    mAnimFrameTracker.clearStats();
    -+    return NO_ERROR;
    -+}
    -+
    -+status_t SurfaceFlinger::getAnimationFrameStats(FrameStats* outStats) const {
    -+    Mutex::Autolock _l(mStateLock);
    -+    mAnimFrameTracker.getStats(outStats);
    -+    return NO_ERROR;
    -+}
    -+
    -+status_t SurfaceFlinger::getHdrCapabilities(const sp<IBinder>& /*display*/,
    -+        HdrCapabilities* outCapabilities) const {
    -+    // HWC1 does not provide HDR capabilities
    -+    *outCapabilities = HdrCapabilities();
    -+    return NO_ERROR;
    -+}
    -+
    -+// ----------------------------------------------------------------------------
    -+
    -+sp<IDisplayEventConnection> SurfaceFlinger::createDisplayEventConnection() {
    -+    return mEventThread->createEventConnection();
    -+}
    -+
    -+// ----------------------------------------------------------------------------
    -+
    -+void SurfaceFlinger::waitForEvent() {
    -+    mEventQueue.waitMessage();
    -+}
    -+
    -+void SurfaceFlinger::signalTransaction() {
    -+    mEventQueue.invalidate();
    -+}
    -+
    -+void SurfaceFlinger::signalLayerUpdate() {
    -+    mEventQueue.invalidate();
    -+}
    -+
    -+void SurfaceFlinger::signalRefresh() {
    -+    mEventQueue.refresh();
    -+}
    -+
    -+status_t SurfaceFlinger::postMessageAsync(const sp<MessageBase>& msg,
    -+        nsecs_t reltime, uint32_t /* flags */) {
    -+    return mEventQueue.postMessage(msg, reltime);
    -+}
    -+
    -+status_t SurfaceFlinger::postMessageSync(const sp<MessageBase>& msg,
    -+        nsecs_t reltime, uint32_t /* flags */) {
    -+    status_t res = mEventQueue.postMessage(msg, reltime);
    -+    if (res == NO_ERROR) {
    -+        msg->wait();
    -+    }
    -+    return res;
    -+}
    -+
    -+void SurfaceFlinger::run() {
    -+    do {
    -+        waitForEvent();
    -+    } while (true);
    -+}
    -+
    -+void SurfaceFlinger::enableHardwareVsync() {
    -+    Mutex::Autolock _l(mHWVsyncLock);
    -+    if (!mPrimaryHWVsyncEnabled && mHWVsyncAvailable) {
    -+        mPrimaryDispSync.beginResync();
    -+        //eventControl(HWC_DISPLAY_PRIMARY, SurfaceFlinger::EVENT_VSYNC, true);
    -+        mEventControlThread->setVsyncEnabled(true);
    -+        mPrimaryHWVsyncEnabled = true;
    -+    }
    -+}
    -+
    -+void SurfaceFlinger::resyncToHardwareVsync(bool makeAvailable) {
    -+    Mutex::Autolock _l(mHWVsyncLock);
    -+
    -+    if (makeAvailable) {
    -+        mHWVsyncAvailable = true;
    -+    } else if (!mHWVsyncAvailable) {
    -+        // Hardware vsync is not currently available, so abort the resync
    -+        // attempt for now
    -+        return;
    -+    }
    -+
    -+    const nsecs_t period =
    -+            getHwComposer().getRefreshPeriod(HWC_DISPLAY_PRIMARY);
    -+
    -+    mPrimaryDispSync.reset();
    -+    mPrimaryDispSync.setPeriod(period);
    -+
    -+    if (!mPrimaryHWVsyncEnabled) {
    -+        mPrimaryDispSync.beginResync();
    -+        //eventControl(HWC_DISPLAY_PRIMARY, SurfaceFlinger::EVENT_VSYNC, true);
    -+        mEventControlThread->setVsyncEnabled(true);
    -+        mPrimaryHWVsyncEnabled = true;
    -+    }
    -+}
    -+
    -+void SurfaceFlinger::disableHardwareVsync(bool makeUnavailable) {
    -+    Mutex::Autolock _l(mHWVsyncLock);
    -+    if (mPrimaryHWVsyncEnabled) {
    -+        //eventControl(HWC_DISPLAY_PRIMARY, SurfaceFlinger::EVENT_VSYNC, false);
    -+        mEventControlThread->setVsyncEnabled(false);
    -+        mPrimaryDispSync.endResync();
    -+        mPrimaryHWVsyncEnabled = false;
    -+    }
    -+    if (makeUnavailable) {
    -+        mHWVsyncAvailable = false;
    -+    }
    -+}
    -+
    -+void SurfaceFlinger::resyncWithRateLimit() {
    -+    static constexpr nsecs_t kIgnoreDelay = ms2ns(500);
    -+    if (systemTime() - mLastSwapTime > kIgnoreDelay) {
    -+        resyncToHardwareVsync(false);
    -+    }
    -+}
    -+
    -+void SurfaceFlinger::onVSyncReceived(int type, nsecs_t timestamp) {
    -+    bool needsHwVsync = false;
    -+
    -+    { // Scope for the lock
    -+        Mutex::Autolock _l(mHWVsyncLock);
    -+        if (type == 0 && mPrimaryHWVsyncEnabled) {
    -+            needsHwVsync = mPrimaryDispSync.addResyncSample(timestamp);
    -+        }
    -+    }
    -+
    -+    if (needsHwVsync) {
    -+        enableHardwareVsync();
    -+    } else {
    -+        disableHardwareVsync(false);
    -+    }
    -+}
    -+
    -+void SurfaceFlinger::onHotplugReceived(int type, bool connected) {
    -+    if (mEventThread == NULL) {
    -+        // This is a temporary workaround for b/7145521.  A non-null pointer
    -+        // does not mean EventThread has finished initializing, so this
    -+        // is not a correct fix.
    -+        ALOGW("WARNING: EventThread not started, ignoring hotplug");
    -+        return;
    -+    }
    -+
    -+    if (uint32_t(type) < DisplayDevice::NUM_BUILTIN_DISPLAY_TYPES) {
    -+        Mutex::Autolock _l(mStateLock);
    -+        if (connected) {
    -+            createBuiltinDisplayLocked((DisplayDevice::DisplayType)type);
    -+        } else {
    -+            mCurrentState.displays.removeItem(mBuiltinDisplays[type]);
    -+            mBuiltinDisplays[type].clear();
    -+        }
    -+        setTransactionFlags(eDisplayTransactionNeeded);
    -+
    -+        // Defer EventThread notification until SF has updated mDisplays.
    -+    }
    -+}
    -+
    -+void SurfaceFlinger::eventControl(int disp, int event, int enabled) {
    -+    ATRACE_CALL();
    -+    getHwComposer().eventControl(disp, event, enabled);
    -+}
    -+
    -+void SurfaceFlinger::onMessageReceived(int32_t what) {
    -+    ATRACE_CALL();
    -+    switch (what) {
    -+        case MessageQueue::INVALIDATE: {
    -+            bool refreshNeeded = handleMessageTransaction();
    -+            refreshNeeded |= handleMessageInvalidate();
    -+            refreshNeeded |= mRepaintEverything;
    -+            if (refreshNeeded) {
    -+                // Signal a refresh if a transaction modified the window state,
    -+                // a new buffer was latched, or if HWC has requested a full
    -+                // repaint
    -+                signalRefresh();
    -+            }
    -+            break;
    -+        }
    -+        case MessageQueue::REFRESH: {
    -+            handleMessageRefresh();
    -+            break;
    -+        }
    -+    }
    -+}
    -+
    -+bool SurfaceFlinger::handleMessageTransaction() {
    -+    uint32_t transactionFlags = peekTransactionFlags(eTransactionMask);
    -+    if (transactionFlags) {
    -+        handleTransaction(transactionFlags);
    -+        return true;
    -+    }
    -+    return false;
    -+}
    -+
    -+bool SurfaceFlinger::handleMessageInvalidate() {
    -+    ATRACE_CALL();
    -+    return handlePageFlip();
    -+}
    -+
    -+void SurfaceFlinger::handleMessageRefresh() {
    -+    ATRACE_CALL();
    -+
    -+    nsecs_t refreshStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
    -+
    -+    preComposition();
    -+    rebuildLayerStacks();
    -+    setUpHWComposer();
    -+    doDebugFlashRegions();
    -+    doComposition();
    -+    postComposition(refreshStartTime);
    -+}
    -+
    -+void SurfaceFlinger::doDebugFlashRegions()
    -+{
    -+    // is debugging enabled
    -+    if (CC_LIKELY(!mDebugRegion))
    -+        return;
    -+
    -+    const bool repaintEverything = mRepaintEverything;
    -+    for (size_t dpy=0 ; dpy<mDisplays.size() ; dpy++) {
    -+        const sp<DisplayDevice>& hw(mDisplays[dpy]);
    -+        if (hw->isDisplayOn()) {
    -+            // transform the dirty region into this screen's coordinate space
    -+            const Region dirtyRegion(hw->getDirtyRegion(repaintEverything));
    -+            if (!dirtyRegion.isEmpty()) {
    -+                // redraw the whole screen
    -+                doComposeSurfaces(hw, Region(hw->bounds()));
    -+
    -+                // and draw the dirty region
    -+                const int32_t height = hw->getHeight();
    -+                RenderEngine& engine(getRenderEngine());
    -+                engine.fillRegionWithColor(dirtyRegion, height, 1, 0, 1, 1);
    -+
    -+                hw->compositionComplete();
    -+                hw->swapBuffers(getHwComposer());
    -+            }
    -+        }
    -+    }
    -+
    -+    postFramebuffer();
    -+
    -+    if (mDebugRegion > 1) {
    -+        usleep(mDebugRegion * 1000);
    -+    }
    -+
    -+    HWComposer& hwc(getHwComposer());
    -+    if (hwc.initCheck() == NO_ERROR) {
    -+        status_t err = hwc.prepare();
    -+        ALOGE_IF(err, "HWComposer::prepare failed (%s)", strerror(-err));
    -+    }
    -+}
    -+
    -+void SurfaceFlinger::preComposition()
    -+{
    -+    bool needExtraInvalidate = false;
    -+    const LayerVector& layers(mDrawingState.layersSortedByZ);
    -+    const size_t count = layers.size();
    -+    for (size_t i=0 ; i<count ; i++) {
    -+        if (layers[i]->onPreComposition()) {
    -+            needExtraInvalidate = true;
    -+        }
    -+    }
    -+    if (needExtraInvalidate) {
    -+        signalLayerUpdate();
    -+    }
    -+}
    -+
    -+void SurfaceFlinger::postComposition(nsecs_t refreshStartTime)
    -+{
    -+    const LayerVector& layers(mDrawingState.layersSortedByZ);
    -+    const size_t count = layers.size();
    -+    for (size_t i=0 ; i<count ; i++) {
    -+        bool frameLatched = layers[i]->onPostComposition();
    -+        if (frameLatched) {
    -+            recordBufferingStats(layers[i]->getName().string(),
    -+                    layers[i]->getOccupancyHistory(false));
    -+        }
    -+    }
    -+
    -+    const HWComposer& hwc = getHwComposer();
    -+    sp<Fence> presentFence = hwc.getDisplayFence(HWC_DISPLAY_PRIMARY);
    -+
    -+    if (presentFence->isValid()) {
    -+        if (mPrimaryDispSync.addPresentFence(presentFence)) {
    -+            enableHardwareVsync();
    -+        } else {
    -+            disableHardwareVsync(false);
    -+        }
    -+    }
    -+
    -+    const sp<const DisplayDevice> hw(getDefaultDisplayDevice());
    -+    if (kIgnorePresentFences) {
    -+        if (hw->isDisplayOn()) {
    -+            enableHardwareVsync();
    -+        }
    -+    }
    -+
    -+    mFenceTracker.addFrame(refreshStartTime, presentFence,
    -+            hw->getVisibleLayersSortedByZ(), hw->getClientTargetAcquireFence());
    -+
    -+    if (mAnimCompositionPending) {
    -+        mAnimCompositionPending = false;
    -+
    -+        if (presentFence->isValid()) {
    -+            mAnimFrameTracker.setActualPresentFence(presentFence);
    -+        } else {
    -+            // The HWC doesn't support present fences, so use the refresh
    -+            // timestamp instead.
    -+            nsecs_t presentTime = hwc.getRefreshTimestamp(HWC_DISPLAY_PRIMARY);
    -+            mAnimFrameTracker.setActualPresentTime(presentTime);
    -+        }
    -+        mAnimFrameTracker.advanceFrame();
    -+    }
    -+
    -+    if (hw->getPowerMode() == HWC_POWER_MODE_OFF) {
    -+        return;
    -+    }
    -+
    -+    nsecs_t currentTime = systemTime();
    -+    if (mHasPoweredOff) {
    -+        mHasPoweredOff = false;
    -+    } else {
    -+        nsecs_t period = mPrimaryDispSync.getPeriod();
    -+        nsecs_t elapsedTime = currentTime - mLastSwapTime;
    -+        size_t numPeriods = static_cast<size_t>(elapsedTime / period);
    -+        if (numPeriods < NUM_BUCKETS - 1) {
    -+            mFrameBuckets[numPeriods] += elapsedTime;
    -+        } else {
    -+            mFrameBuckets[NUM_BUCKETS - 1] += elapsedTime;
    -+        }
    -+        mTotalTime += elapsedTime;
    -+    }
    -+    mLastSwapTime = currentTime;
    -+}
    -+
    -+void SurfaceFlinger::rebuildLayerStacks() {
    -+    // rebuild the visible layer list per screen
    -+    if (CC_UNLIKELY(mVisibleRegionsDirty)) {
    -+        ATRACE_CALL();
    -+        mVisibleRegionsDirty = false;
    -+        invalidateHwcGeometry();
    -+
    -+        const LayerVector& layers(mDrawingState.layersSortedByZ);
    -+        for (size_t dpy=0 ; dpy<mDisplays.size() ; dpy++) {
    -+            Region opaqueRegion;
    -+            Region dirtyRegion;
    -+            Vector< sp<Layer> > layersSortedByZ;
    -+            const sp<DisplayDevice>& hw(mDisplays[dpy]);
    -+            const Transform& tr(hw->getTransform());
    -+            const Rect bounds(hw->getBounds());
    -+            if (hw->isDisplayOn()) {
    -+                SurfaceFlinger::computeVisibleRegions(layers,
    -+                        hw->getLayerStack(), dirtyRegion, opaqueRegion);
    -+
    -+                const size_t count = layers.size();
    -+                for (size_t i=0 ; i<count ; i++) {
    -+                    const sp<Layer>& layer(layers[i]);
    -+                    const Layer::State& s(layer->getDrawingState());
    -+                    if (s.layerStack == hw->getLayerStack()) {
    -+                        Region drawRegion(tr.transform(
    -+                                layer->visibleNonTransparentRegion));
    -+                        drawRegion.andSelf(bounds);
    -+                        if (!drawRegion.isEmpty()) {
    -+                            layersSortedByZ.add(layer);
    -+                        }
    -+                    }
    -+                }
    -+            }
    -+            hw->setVisibleLayersSortedByZ(layersSortedByZ);
    -+            hw->undefinedRegion.set(bounds);
    -+            hw->undefinedRegion.subtractSelf(tr.transform(opaqueRegion));
    -+            hw->dirtyRegion.orSelf(dirtyRegion);
    -+        }
    -+    }
    -+}
    -+
    -+void SurfaceFlinger::setUpHWComposer() {
    -+    for (size_t dpy=0 ; dpy<mDisplays.size() ; dpy++) {
    -+        bool dirty = !mDisplays[dpy]->getDirtyRegion(false).isEmpty();
    -+        bool empty = mDisplays[dpy]->getVisibleLayersSortedByZ().size() == 0;
    -+        bool wasEmpty = !mDisplays[dpy]->lastCompositionHadVisibleLayers;
    -+
    -+        // If nothing has changed (!dirty), don't recompose.
    -+        // If something changed, but we don't currently have any visible layers,
    -+        //   and didn't when we last did a composition, then skip it this time.
    -+        // The second rule does two things:
    -+        // - When all layers are removed from a display, we'll emit one black
    -+        //   frame, then nothing more until we get new layers.
    -+        // - When a display is created with a private layer stack, we won't
    -+        //   emit any black frames until a layer is added to the layer stack.
    -+        bool mustRecompose = dirty && !(empty && wasEmpty);
    -+
    -+        ALOGV_IF(mDisplays[dpy]->getDisplayType() == DisplayDevice::DISPLAY_VIRTUAL,
    -+                "dpy[%zu]: %s composition (%sdirty %sempty %swasEmpty)", dpy,
    -+                mustRecompose ? "doing" : "skipping",
    -+                dirty ? "+" : "-",
    -+                empty ? "+" : "-",
    -+                wasEmpty ? "+" : "-");
    -+
    -+        mDisplays[dpy]->beginFrame(mustRecompose);
    -+
    -+        if (mustRecompose) {
    -+            mDisplays[dpy]->lastCompositionHadVisibleLayers = !empty;
    -+        }
    -+    }
    -+
    -+    HWComposer& hwc(getHwComposer());
    -+    if (hwc.initCheck() == NO_ERROR) {
    -+        // build the h/w work list
    -+        if (CC_UNLIKELY(mHwWorkListDirty)) {
    -+            mHwWorkListDirty = false;
    -+            for (size_t dpy=0 ; dpy<mDisplays.size() ; dpy++) {
    -+                sp<const DisplayDevice> hw(mDisplays[dpy]);
    -+                const int32_t id = hw->getHwcDisplayId();
    -+                if (id >= 0) {
    -+                    const Vector< sp<Layer> >& currentLayers(
    -+                        hw->getVisibleLayersSortedByZ());
    -+                    const size_t count = currentLayers.size();
    -+                    if (hwc.createWorkList(id, count) == NO_ERROR) {
    -+                        HWComposer::LayerListIterator cur = hwc.begin(id);
    -+                        const HWComposer::LayerListIterator end = hwc.end(id);
    -+                        for (size_t i=0 ; cur!=end && i<count ; ++i, ++cur) {
    -+                            const sp<Layer>& layer(currentLayers[i]);
    -+                            layer->setGeometry(hw, *cur);
    -+                            if (mDebugDisableHWC || mDebugRegion || mDaltonize || mHasColorMatrix) {
    -+                                cur->setSkip(true);
    -+                            }
    -+                        }
    -+                    }
    -+                }
    -+            }
    -+        }
    -+
    -+        // set the per-frame data
    -+        for (size_t dpy=0 ; dpy<mDisplays.size() ; dpy++) {
    -+            sp<const DisplayDevice> hw(mDisplays[dpy]);
    -+            const int32_t id = hw->getHwcDisplayId();
    -+            if (id >= 0) {
    -+                const Vector< sp<Layer> >& currentLayers(
    -+                    hw->getVisibleLayersSortedByZ());
    -+                const size_t count = currentLayers.size();
    -+                HWComposer::LayerListIterator cur = hwc.begin(id);
    -+                const HWComposer::LayerListIterator end = hwc.end(id);
    -+                for (size_t i=0 ; cur!=end && i<count ; ++i, ++cur) {
    -+                    /*
    -+                     * update the per-frame h/w composer data for each layer
    -+                     * and build the transparent region of the FB
    -+                     */
    -+                    const sp<Layer>& layer(currentLayers[i]);
    -+                    layer->setPerFrameData(hw, *cur);
    -+                }
    -+            }
    -+        }
    -+
    -+        // If possible, attempt to use the cursor overlay on each display.
    -+        for (size_t dpy=0 ; dpy<mDisplays.size() ; dpy++) {
    -+            sp<const DisplayDevice> hw(mDisplays[dpy]);
    -+            const int32_t id = hw->getHwcDisplayId();
    -+            if (id >= 0) {
    -+                const Vector< sp<Layer> >& currentLayers(
    -+                    hw->getVisibleLayersSortedByZ());
    -+                const size_t count = currentLayers.size();
    -+                HWComposer::LayerListIterator cur = hwc.begin(id);
    -+                const HWComposer::LayerListIterator end = hwc.end(id);
    -+                for (size_t i=0 ; cur!=end && i<count ; ++i, ++cur) {
    -+                    const sp<Layer>& layer(currentLayers[i]);
    -+                    if (layer->isPotentialCursor()) {
    -+                        cur->setIsCursorLayerHint();
    -+                        break;
    -+                    }
    -+                }
    -+            }
    -+        }
    -+
    -+        status_t err = hwc.prepare();
    -+        ALOGE_IF(err, "HWComposer::prepare failed (%s)", strerror(-err));
    -+
    -+        for (size_t dpy=0 ; dpy<mDisplays.size() ; dpy++) {
    -+            sp<const DisplayDevice> hw(mDisplays[dpy]);
    -+            hw->prepareFrame(hwc);
    -+        }
    -+    }
    -+}
    -+
    -+void SurfaceFlinger::doComposition() {
    -+    ATRACE_CALL();
    -+    const bool repaintEverything = android_atomic_and(0, &mRepaintEverything);
    -+    for (size_t dpy=0 ; dpy<mDisplays.size() ; dpy++) {
    -+        const sp<DisplayDevice>& hw(mDisplays[dpy]);
    -+        if (hw->isDisplayOn()) {
    -+            // transform the dirty region into this screen's coordinate space
    -+            const Region dirtyRegion(hw->getDirtyRegion(repaintEverything));
    -+
    -+            // repaint the framebuffer (if needed)
    -+            doDisplayComposition(hw, dirtyRegion);
    -+
    -+            hw->dirtyRegion.clear();
    -+            hw->flip(hw->swapRegion);
    -+            hw->swapRegion.clear();
    -+        }
    -+        // inform the h/w that we're done compositing
    -+        hw->compositionComplete();
    -+    }
    -+    postFramebuffer();
    -+}
    -+
    -+void SurfaceFlinger::postFramebuffer()
    -+{
    -+    ATRACE_CALL();
    -+
    -+    const nsecs_t now = systemTime();
    -+    mDebugInSwapBuffers = now;
    -+
    -+    HWComposer& hwc(getHwComposer());
    -+    if (hwc.initCheck() == NO_ERROR) {
    -+        if (!hwc.supportsFramebufferTarget()) {
    -+            // EGL spec says:
    -+            //   "surface must be bound to the calling thread's current context,
    -+            //    for the current rendering API."
    -+            getDefaultDisplayDevice()->makeCurrent(mEGLDisplay, mEGLContext);
    -+        }
    -+        hwc.commit();
    -+    }
    -+
    -+    // make the default display current because the VirtualDisplayDevice code cannot
    -+    // deal with dequeueBuffer() being called outside of the composition loop; however
    -+    // the code below can call glFlush() which is allowed (and does in some case) call
    -+    // dequeueBuffer().
    -+    getDefaultDisplayDevice()->makeCurrent(mEGLDisplay, mEGLContext);
    -+
    -+    for (size_t dpy=0 ; dpy<mDisplays.size() ; dpy++) {
    -+        sp<const DisplayDevice> hw(mDisplays[dpy]);
    -+        const Vector< sp<Layer> >& currentLayers(hw->getVisibleLayersSortedByZ());
    -+        hw->onSwapBuffersCompleted(hwc);
    -+        const size_t count = currentLayers.size();
    -+        int32_t id = hw->getHwcDisplayId();
    -+        if (id >=0 && hwc.initCheck() == NO_ERROR) {
    -+            HWComposer::LayerListIterator cur = hwc.begin(id);
    -+            const HWComposer::LayerListIterator end = hwc.end(id);
    -+            for (size_t i = 0; cur != end && i < count; ++i, ++cur) {
    -+                currentLayers[i]->onLayerDisplayed(hw, &*cur);
    -+            }
    -+        } else {
    -+            for (size_t i = 0; i < count; i++) {
    -+                currentLayers[i]->onLayerDisplayed(hw, NULL);
    -+            }
    -+        }
    -+    }
    -+
    -+    mLastSwapBufferTime = systemTime() - now;
    -+    mDebugInSwapBuffers = 0;
    -+
    -+    uint32_t flipCount = getDefaultDisplayDevice()->getPageFlipCount();
    -+    if (flipCount % LOG_FRAME_STATS_PERIOD == 0) {
    -+        logFrameStats();
    -+    }
    -+}
    -+
    -+void SurfaceFlinger::handleTransaction(uint32_t transactionFlags)
    -+{
    -+    ATRACE_CALL();
    -+
    -+    // here we keep a copy of the drawing state (that is the state that's
    -+    // going to be overwritten by handleTransactionLocked()) outside of
    -+    // mStateLock so that the side-effects of the State assignment
    -+    // don't happen with mStateLock held (which can cause deadlocks).
    -+    State drawingState(mDrawingState);
    -+
    -+    Mutex::Autolock _l(mStateLock);
    -+    const nsecs_t now = systemTime();
    -+    mDebugInTransaction = now;
    -+
    -+    // Here we're guaranteed that some transaction flags are set
    -+    // so we can call handleTransactionLocked() unconditionally.
    -+    // We call getTransactionFlags(), which will also clear the flags,
    -+    // with mStateLock held to guarantee that mCurrentState won't change
    -+    // until the transaction is committed.
    -+
    -+    transactionFlags = getTransactionFlags(eTransactionMask);
    -+    handleTransactionLocked(transactionFlags);
    -+
    -+    mLastTransactionTime = systemTime() - now;
    -+    mDebugInTransaction = 0;
    -+    invalidateHwcGeometry();
    -+    // here the transaction has been committed
    -+}
    -+
    -+void SurfaceFlinger::handleTransactionLocked(uint32_t transactionFlags)
    -+{
    -+    const LayerVector& currentLayers(mCurrentState.layersSortedByZ);
    -+    const size_t count = currentLayers.size();
    -+
    -+    // Notify all layers of available frames
    -+    for (size_t i = 0; i < count; ++i) {
    -+        currentLayers[i]->notifyAvailableFrames();
    -+    }
    -+
    -+    /*
    -+     * Traversal of the children
    -+     * (perform the transaction for each of them if needed)
    -+     */
    -+
    -+    if (transactionFlags & eTraversalNeeded) {
    -+        for (size_t i=0 ; i<count ; i++) {
    -+            const sp<Layer>& layer(currentLayers[i]);
    -+            uint32_t trFlags = layer->getTransactionFlags(eTransactionNeeded);
    -+            if (!trFlags) continue;
    -+
    -+            const uint32_t flags = layer->doTransaction(0);
    -+            if (flags & Layer::eVisibleRegion)
    -+                mVisibleRegionsDirty = true;
    -+        }
    -+    }
    -+
    -+    /*
    -+     * Perform display own transactions if needed
    -+     */
    -+
    -+    if (transactionFlags & eDisplayTransactionNeeded) {
    -+        // here we take advantage of Vector's copy-on-write semantics to
    -+        // improve performance by skipping the transaction entirely when
    -+        // know that the lists are identical
    -+        const KeyedVector<  wp<IBinder>, DisplayDeviceState>& curr(mCurrentState.displays);
    -+        const KeyedVector<  wp<IBinder>, DisplayDeviceState>& draw(mDrawingState.displays);
    -+        if (!curr.isIdenticalTo(draw)) {
    -+            mVisibleRegionsDirty = true;
    -+            const size_t cc = curr.size();
    -+                  size_t dc = draw.size();
    -+
    -+            // find the displays that were removed
    -+            // (ie: in drawing state but not in current state)
    -+            // also handle displays that changed
    -+            // (ie: displays that are in both lists)
    -+            for (size_t i=0 ; i<dc ; i++) {
    -+                const ssize_t j = curr.indexOfKey(draw.keyAt(i));
    -+                if (j < 0) {
    -+                    // in drawing state but not in current state
    -+                    if (!draw[i].isMainDisplay()) {
    -+                        // Call makeCurrent() on the primary display so we can
    -+                        // be sure that nothing associated with this display
    -+                        // is current.
    -+                        const sp<const DisplayDevice> defaultDisplay(getDefaultDisplayDevice());
    -+                        defaultDisplay->makeCurrent(mEGLDisplay, mEGLContext);
    -+                        sp<DisplayDevice> hw(getDisplayDevice(draw.keyAt(i)));
    -+                        if (hw != NULL)
    -+                            hw->disconnect(getHwComposer());
    -+                        if (draw[i].type < DisplayDevice::NUM_BUILTIN_DISPLAY_TYPES)
    -+                            mEventThread->onHotplugReceived(draw[i].type, false);
    -+                        mDisplays.removeItem(draw.keyAt(i));
    -+                    } else {
    -+                        ALOGW("trying to remove the main display");
    -+                    }
    -+                } else {
    -+                    // this display is in both lists. see if something changed.
    -+                    const DisplayDeviceState& state(curr[j]);
    -+                    const wp<IBinder>& display(curr.keyAt(j));
    -+                    const sp<IBinder> state_binder = IInterface::asBinder(state.surface);
    -+                    const sp<IBinder> draw_binder = IInterface::asBinder(draw[i].surface);
    -+                    if (state_binder != draw_binder) {
    -+                        // changing the surface is like destroying and
    -+                        // recreating the DisplayDevice, so we just remove it
    -+                        // from the drawing state, so that it get re-added
    -+                        // below.
    -+                        sp<DisplayDevice> hw(getDisplayDevice(display));
    -+                        if (hw != NULL)
    -+                            hw->disconnect(getHwComposer());
    -+                        mDisplays.removeItem(display);
    -+                        mDrawingState.displays.removeItemsAt(i);
    -+                        dc--; i--;
    -+                        // at this point we must loop to the next item
    -+                        continue;
    -+                    }
    -+
    -+                    const sp<DisplayDevice> disp(getDisplayDevice(display));
    -+                    if (disp != NULL) {
    -+                        if (state.layerStack != draw[i].layerStack) {
    -+                            disp->setLayerStack(state.layerStack);
    -+                        }
    -+                        if ((state.orientation != draw[i].orientation)
    -+                                || (state.viewport != draw[i].viewport)
    -+                                || (state.frame != draw[i].frame))
    -+                        {
    -+                            disp->setProjection(state.orientation,
    -+                                    state.viewport, state.frame);
    -+                        }
    -+                        if (state.width != draw[i].width || state.height != draw[i].height) {
    -+                            disp->setDisplaySize(state.width, state.height);
    -+                        }
    -+                    }
    -+                }
    -+            }
    -+
    -+            // find displays that were added
    -+            // (ie: in current state but not in drawing state)
    -+            for (size_t i=0 ; i<cc ; i++) {
    -+                if (draw.indexOfKey(curr.keyAt(i)) < 0) {
    -+                    const DisplayDeviceState& state(curr[i]);
    -+
    -+                    sp<DisplaySurface> dispSurface;
    -+                    sp<IGraphicBufferProducer> producer;
    -+                    sp<IGraphicBufferProducer> bqProducer;
    -+                    sp<IGraphicBufferConsumer> bqConsumer;
    -+                    BufferQueue::createBufferQueue(&bqProducer, &bqConsumer,
    -+                            new GraphicBufferAlloc());
    -+
    -+                    int32_t hwcDisplayId = -1;
    -+                    if (state.isVirtualDisplay()) {
    -+                        // Virtual displays without a surface are dormant:
    -+                        // they have external state (layer stack, projection,
    -+                        // etc.) but no internal state (i.e. a DisplayDevice).
    -+                        if (state.surface != NULL) {
    -+
    -+                            int width = 0;
    -+                            int status = state.surface->query(
    -+                                    NATIVE_WINDOW_WIDTH, &width);
    -+                            ALOGE_IF(status != NO_ERROR,
    -+                                    "Unable to query width (%d)", status);
    -+                            int height = 0;
    -+                            status = state.surface->query(
    -+                                    NATIVE_WINDOW_HEIGHT, &height);
    -+                            ALOGE_IF(status != NO_ERROR,
    -+                                    "Unable to query height (%d)", status);
    -+                            if (mUseHwcVirtualDisplays &&
    -+                                    (MAX_VIRTUAL_DISPLAY_DIMENSION == 0 ||
    -+                                    (width <= MAX_VIRTUAL_DISPLAY_DIMENSION &&
    -+                                     height <= MAX_VIRTUAL_DISPLAY_DIMENSION))) {
    -+                                hwcDisplayId = allocateHwcDisplayId(state.type);
    -+                            }
    -+
    -+                            sp<VirtualDisplaySurface> vds = new VirtualDisplaySurface(
    -+                                    *mHwc, hwcDisplayId, state.surface,
    -+                                    bqProducer, bqConsumer, state.displayName);
    -+
    -+                            dispSurface = vds;
    -+                            producer = vds;
    -+                        }
    -+                    } else {
    -+                        ALOGE_IF(state.surface!=NULL,
    -+                                "adding a supported display, but rendering "
    -+                                "surface is provided (%p), ignoring it",
    -+                                state.surface.get());
    -+                        hwcDisplayId = allocateHwcDisplayId(state.type);
    -+                        // for supported (by hwc) displays we provide our
    -+                        // own rendering surface
    -+                        dispSurface = new FramebufferSurface(*mHwc, state.type,
    -+                                bqConsumer);
    -+                        producer = bqProducer;
    -+                    }
    -+
    -+                    const wp<IBinder>& display(curr.keyAt(i));
    -+                    if (dispSurface != NULL) {
    -+                        sp<DisplayDevice> hw = new DisplayDevice(this,
    -+                                state.type, hwcDisplayId,
    -+                                mHwc->getFormat(hwcDisplayId), state.isSecure,
    -+                                display, dispSurface, producer,
    -+                                mRenderEngine->getEGLConfig());
    -+                        hw->setLayerStack(state.layerStack);
    -+                        hw->setProjection(state.orientation,
    -+                                state.viewport, state.frame);
    -+                        hw->setDisplayName(state.displayName);
    -+                        mDisplays.add(display, hw);
    -+                        if (state.isVirtualDisplay()) {
    -+                            if (hwcDisplayId >= 0) {
    -+                                mHwc->setVirtualDisplayProperties(hwcDisplayId,
    -+                                        hw->getWidth(), hw->getHeight(),
    -+                                        hw->getFormat());
    -+                            }
    -+                        } else {
    -+                            mEventThread->onHotplugReceived(state.type, true);
    -+                        }
    -+                    }
    -+                }
    -+            }
    -+        }
    -+    }
    -+
    -+    if (transactionFlags & (eTraversalNeeded|eDisplayTransactionNeeded)) {
    -+        // The transform hint might have changed for some layers
    -+        // (either because a display has changed, or because a layer
    -+        // as changed).
    -+        //
    -+        // Walk through all the layers in currentLayers,
    -+        // and update their transform hint.
    -+        //
    -+        // If a layer is visible only on a single display, then that
    -+        // display is used to calculate the hint, otherwise we use the
    -+        // default display.
    -+        //
    -+        // NOTE: we do this here, rather than in rebuildLayerStacks() so that
    -+        // the hint is set before we acquire a buffer from the surface texture.
    -+        //
    -+        // NOTE: layer transactions have taken place already, so we use their
    -+        // drawing state. However, SurfaceFlinger's own transaction has not
    -+        // happened yet, so we must use the current state layer list
    -+        // (soon to become the drawing state list).
    -+        //
    -+        sp<const DisplayDevice> disp;
    -+        uint32_t currentlayerStack = 0;
    -+        for (size_t i=0; i<count; i++) {
    -+            // NOTE: we rely on the fact that layers are sorted by
    -+            // layerStack first (so we don't have to traverse the list
    -+            // of displays for every layer).
    -+            const sp<Layer>& layer(currentLayers[i]);
    -+            uint32_t layerStack = layer->getDrawingState().layerStack;
    -+            if (i==0 || currentlayerStack != layerStack) {
    -+                currentlayerStack = layerStack;
    -+                // figure out if this layerstack is mirrored
    -+                // (more than one display) if so, pick the default display,
    -+                // if not, pick the only display it's on.
    -+                disp.clear();
    -+                for (size_t dpy=0 ; dpy<mDisplays.size() ; dpy++) {
    -+                    sp<const DisplayDevice> hw(mDisplays[dpy]);
    -+                    if (hw->getLayerStack() == currentlayerStack) {
    -+                        if (disp == NULL) {
    -+                            disp = hw;
    -+                        } else {
    -+                            disp = NULL;
    -+                            break;
    -+                        }
    -+                    }
    -+                }
    -+            }
    -+            if (disp == NULL) {
    -+                // NOTE: TEMPORARY FIX ONLY. Real fix should cause layers to
    -+                // redraw after transform hint changes. See bug 8508397.
    -+
    -+                // could be null when this layer is using a layerStack
    -+                // that is not visible on any display. Also can occur at
    -+                // screen off/on times.
    -+                disp = getDefaultDisplayDevice();
    -+            }
    -+            layer->updateTransformHint(disp);
    -+        }
    -+    }
    -+
    -+
    -+    /*
    -+     * Perform our own transaction if needed
    -+     */
    -+
    -+    const LayerVector& layers(mDrawingState.layersSortedByZ);
    -+    if (currentLayers.size() > layers.size()) {
    -+        // layers have been added
    -+        mVisibleRegionsDirty = true;
    -+    }
    -+
    -+    // some layers might have been removed, so
    -+    // we need to update the regions they're exposing.
    -+    if (mLayersRemoved) {
    -+        mLayersRemoved = false;
    -+        mVisibleRegionsDirty = true;
    -+        const size_t count = layers.size();
    -+        for (size_t i=0 ; i<count ; i++) {
    -+            const sp<Layer>& layer(layers[i]);
    -+            if (currentLayers.indexOf(layer) < 0) {
    -+                // this layer is not visible anymore
    -+                // TODO: we could traverse the tree from front to back and
    -+                //       compute the actual visible region
    -+                // TODO: we could cache the transformed region
    -+                const Layer::State& s(layer->getDrawingState());
    -+                Region visibleReg = s.active.transform.transform(
    -+                        Region(Rect(s.active.w, s.active.h)));
    -+                invalidateLayerStack(s.layerStack, visibleReg);
    -+            }
    -+        }
    -+    }
    -+
    -+    commitTransaction();
    -+
    -+    updateCursorAsync();
    -+}
    -+
    -+void SurfaceFlinger::updateCursorAsync()
    -+{
    -+    HWComposer& hwc(getHwComposer());
    -+    for (size_t dpy=0 ; dpy<mDisplays.size() ; dpy++) {
    -+        sp<const DisplayDevice> hw(mDisplays[dpy]);
    -+        const int32_t id = hw->getHwcDisplayId();
    -+        if (id < 0) {
    -+            continue;
    -+        }
    -+        const Vector< sp<Layer> >& currentLayers(
    -+            hw->getVisibleLayersSortedByZ());
    -+        const size_t count = currentLayers.size();
    -+        HWComposer::LayerListIterator cur = hwc.begin(id);
    -+        const HWComposer::LayerListIterator end = hwc.end(id);
    -+        for (size_t i=0 ; cur!=end && i<count ; ++i, ++cur) {
    -+            if (cur->getCompositionType() != HWC_CURSOR_OVERLAY) {
    -+                continue;
    -+            }
    -+            const sp<Layer>& layer(currentLayers[i]);
    -+            Rect cursorPos = layer->getPosition(hw);
    -+            hwc.setCursorPositionAsync(id, cursorPos);
    -+            break;
    -+        }
    -+    }
    -+}
    -+
    -+void SurfaceFlinger::commitTransaction()
    -+{
    -+    if (!mLayersPendingRemoval.isEmpty()) {
    -+        // Notify removed layers now that they can't be drawn from
    -+        for (size_t i = 0; i < mLayersPendingRemoval.size(); i++) {
    -+            recordBufferingStats(mLayersPendingRemoval[i]->getName().string(),
    -+                    mLayersPendingRemoval[i]->getOccupancyHistory(true));
    -+            mLayersPendingRemoval[i]->onRemoved();
    -+        }
    -+        mLayersPendingRemoval.clear();
    -+    }
    -+
    -+    // If this transaction is part of a window animation then the next frame
    -+    // we composite should be considered an animation as well.
    -+    mAnimCompositionPending = mAnimTransactionPending;
    -+
    -+    mDrawingState = mCurrentState;
    -+    mTransactionPending = false;
    -+    mAnimTransactionPending = false;
    -+    mTransactionCV.broadcast();
    -+}
    -+
    -+void SurfaceFlinger::computeVisibleRegions(
    -+        const LayerVector& currentLayers, uint32_t layerStack,
    -+        Region& outDirtyRegion, Region& outOpaqueRegion)
    -+{
    -+    ATRACE_CALL();
    -+
    -+    Region aboveOpaqueLayers;
    -+    Region aboveCoveredLayers;
    -+    Region dirty;
    -+
    -+    outDirtyRegion.clear();
    -+
    -+    size_t i = currentLayers.size();
    -+    while (i--) {
    -+        const sp<Layer>& layer = currentLayers[i];
    -+
    -+        // start with the whole surface at its current location
    -+        const Layer::State& s(layer->getDrawingState());
    -+
    -+        // only consider the layers on the given layer stack
    -+        if (s.layerStack != layerStack)
    -+            continue;
    -+
    -+        /*
    -+         * opaqueRegion: area of a surface that is fully opaque.
    -+         */
    -+        Region opaqueRegion;
    -+
    -+        /*
    -+         * visibleRegion: area of a surface that is visible on screen
    -+         * and not fully transparent. This is essentially the layer's
    -+         * footprint minus the opaque regions above it.
    -+         * Areas covered by a translucent surface are considered visible.
    -+         */
    -+        Region visibleRegion;
    -+
    -+        /*
    -+         * coveredRegion: area of a surface that is covered by all
    -+         * visible regions above it (which includes the translucent areas).
    -+         */
    -+        Region coveredRegion;
    -+
    -+        /*
    -+         * transparentRegion: area of a surface that is hinted to be completely
    -+         * transparent. This is only used to tell when the layer has no visible
    -+         * non-transparent regions and can be removed from the layer list. It
    -+         * does not affect the visibleRegion of this layer or any layers
    -+         * beneath it. The hint may not be correct if apps don't respect the
    -+         * SurfaceView restrictions (which, sadly, some don't).
    -+         */
    -+        Region transparentRegion;
    -+
    -+
    -+        // handle hidden surfaces by setting the visible region to empty
    -+        if (CC_LIKELY(layer->isVisible())) {
    -+            const bool translucent = !layer->isOpaque(s);
    -+            Rect bounds(s.active.transform.transform(layer->computeBounds()));
    -+            visibleRegion.set(bounds);
    -+            if (!visibleRegion.isEmpty()) {
    -+                // Remove the transparent area from the visible region
    -+                if (translucent) {
    -+                    const Transform tr(s.active.transform);
    -+                    if (tr.preserveRects()) {
    -+                        // transform the transparent region
    -+                        transparentRegion = tr.transform(s.activeTransparentRegion);
    -+                    } else {
    -+                        // transformation too complex, can't do the
    -+                        // transparent region optimization.
    -+                        transparentRegion.clear();
    -+                    }
    -+                }
    -+
    -+                // compute the opaque region
    -+                const int32_t layerOrientation = s.active.transform.getOrientation();
    -+                if (s.alpha==255 && !translucent &&
    -+                        ((layerOrientation & Transform::ROT_INVALID) == false)) {
    -+                    // the opaque region is the layer's footprint
    -+                    opaqueRegion = visibleRegion;
    -+                }
    -+            }
    -+        }
    -+
    -+        // Clip the covered region to the visible region
    -+        coveredRegion = aboveCoveredLayers.intersect(visibleRegion);
    -+
    -+        // Update aboveCoveredLayers for next (lower) layer
    -+        aboveCoveredLayers.orSelf(visibleRegion);
    -+
    -+        // subtract the opaque region covered by the layers above us
    -+        visibleRegion.subtractSelf(aboveOpaqueLayers);
    -+
    -+        // compute this layer's dirty region
    -+        if (layer->contentDirty) {
    -+            // we need to invalidate the whole region
    -+            dirty = visibleRegion;
    -+            // as well, as the old visible region
    -+            dirty.orSelf(layer->visibleRegion);
    -+            layer->contentDirty = false;
    -+        } else {
    -+            /* compute the exposed region:
    -+             *   the exposed region consists of two components:
    -+             *   1) what's VISIBLE now and was COVERED before
    -+             *   2) what's EXPOSED now less what was EXPOSED before
    -+             *
    -+             * note that (1) is conservative, we start with the whole
    -+             * visible region but only keep what used to be covered by
    -+             * something -- which mean it may have been exposed.
    -+             *
    -+             * (2) handles areas that were not covered by anything but got
    -+             * exposed because of a resize.
    -+             */
    -+            const Region newExposed = visibleRegion - coveredRegion;
    -+            const Region oldVisibleRegion = layer->visibleRegion;
    -+            const Region oldCoveredRegion = layer->coveredRegion;
    -+            const Region oldExposed = oldVisibleRegion - oldCoveredRegion;
    -+            dirty = (visibleRegion&oldCoveredRegion) | (newExposed-oldExposed);
    -+        }
    -+        dirty.subtractSelf(aboveOpaqueLayers);
    -+
    -+        // accumulate to the screen dirty region
    -+        outDirtyRegion.orSelf(dirty);
    -+
    -+        // Update aboveOpaqueLayers for next (lower) layer
    -+        aboveOpaqueLayers.orSelf(opaqueRegion);
    -+
    -+        // Store the visible region in screen space
    -+        layer->setVisibleRegion(visibleRegion);
    -+        layer->setCoveredRegion(coveredRegion);
    -+        layer->setVisibleNonTransparentRegion(
    -+                visibleRegion.subtract(transparentRegion));
    -+    }
    -+
    -+    outOpaqueRegion = aboveOpaqueLayers;
    -+}
    -+
    -+void SurfaceFlinger::invalidateLayerStack(uint32_t layerStack,
    -+        const Region& dirty) {
    -+    for (size_t dpy=0 ; dpy<mDisplays.size() ; dpy++) {
    -+        const sp<DisplayDevice>& hw(mDisplays[dpy]);
    -+        if (hw->getLayerStack() == layerStack) {
    -+            hw->dirtyRegion.orSelf(dirty);
    -+        }
    -+    }
    -+}
    -+
    -+bool SurfaceFlinger::handlePageFlip()
    -+{
    -+    Region dirtyRegion;
    -+
    -+    bool visibleRegions = false;
    -+    const LayerVector& layers(mDrawingState.layersSortedByZ);
    -+    bool frameQueued = false;
    -+
    -+    // Store the set of layers that need updates. This set must not change as
    -+    // buffers are being latched, as this could result in a deadlock.
    -+    // Example: Two producers share the same command stream and:
    -+    // 1.) Layer 0 is latched
    -+    // 2.) Layer 0 gets a new frame
    -+    // 2.) Layer 1 gets a new frame
    -+    // 3.) Layer 1 is latched.
    -+    // Display is now waiting on Layer 1's frame, which is behind layer 0's
    -+    // second frame. But layer 0's second frame could be waiting on display.
    -+    Vector<Layer*> layersWithQueuedFrames;
    -+    for (size_t i = 0, count = layers.size(); i<count ; i++) {
    -+        const sp<Layer>& layer(layers[i]);
    -+        if (layer->hasQueuedFrame()) {
    -+            frameQueued = true;
    -+            if (layer->shouldPresentNow(mPrimaryDispSync)) {
    -+                layersWithQueuedFrames.push_back(layer.get());
    -+            } else {
    -+                layer->useEmptyDamage();
    -+            }
    -+        } else {
    -+            layer->useEmptyDamage();
    -+        }
    -+    }
    -+    for (size_t i = 0, count = layersWithQueuedFrames.size() ; i<count ; i++) {
    -+        Layer* layer = layersWithQueuedFrames[i];
    -+        const Region dirty(layer->latchBuffer(visibleRegions));
    -+        layer->useSurfaceDamage();
    -+        const Layer::State& s(layer->getDrawingState());
    -+        invalidateLayerStack(s.layerStack, dirty);
    -+    }
    -+
    -+    mVisibleRegionsDirty |= visibleRegions;
    -+
    -+    // If we will need to wake up at some time in the future to deal with a
    -+    // queued frame that shouldn't be displayed during this vsync period, wake
    -+    // up during the next vsync period to check again.
    -+    if (frameQueued && layersWithQueuedFrames.empty()) {
    -+        signalLayerUpdate();
    -+    }
    -+
    -+    // Only continue with the refresh if there is actually new work to do
    -+    return !layersWithQueuedFrames.empty();
    -+}
    -+
    -+void SurfaceFlinger::invalidateHwcGeometry()
    -+{
    -+    mHwWorkListDirty = true;
    -+}
    -+
    -+
    -+void SurfaceFlinger::doDisplayComposition(const sp<const DisplayDevice>& hw,
    -+        const Region& inDirtyRegion)
    -+{
    -+    // We only need to actually compose the display if:
    -+    // 1) It is being handled by hardware composer, which may need this to
    -+    //    keep its virtual display state machine in sync, or
    -+    // 2) There is work to be done (the dirty region isn't empty)
    -+    bool isHwcDisplay = hw->getHwcDisplayId() >= 0;
    -+    if (!isHwcDisplay && inDirtyRegion.isEmpty()) {
    -+        return;
    -+    }
    -+
    -+    Region dirtyRegion(inDirtyRegion);
    -+
    -+    // compute the invalid region
    -+    hw->swapRegion.orSelf(dirtyRegion);
    -+
    -+    uint32_t flags = hw->getFlags();
    -+    if (flags & DisplayDevice::SWAP_RECTANGLE) {
    -+        // we can redraw only what's dirty, but since SWAP_RECTANGLE only
    -+        // takes a rectangle, we must make sure to update that whole
    -+        // rectangle in that case
    -+        dirtyRegion.set(hw->swapRegion.bounds());
    -+    } else {
    -+        if (flags & DisplayDevice::PARTIAL_UPDATES) {
    -+            // We need to redraw the rectangle that will be updated
    -+            // (pushed to the framebuffer).
    -+            // This is needed because PARTIAL_UPDATES only takes one
    -+            // rectangle instead of a region (see DisplayDevice::flip())
    -+            dirtyRegion.set(hw->swapRegion.bounds());
    -+        } else {
    -+            // we need to redraw everything (the whole screen)
    -+            dirtyRegion.set(hw->bounds());
    -+            hw->swapRegion = dirtyRegion;
    -+        }
    -+    }
    -+
    -+    if (CC_LIKELY(!mDaltonize && !mHasColorMatrix)) {
    -+        if (!doComposeSurfaces(hw, dirtyRegion)) return;
    -+    } else {
    -+        RenderEngine& engine(getRenderEngine());
    -+        mat4 colorMatrix = mColorMatrix;
    -+        if (mDaltonize) {
    -+            colorMatrix = colorMatrix * mDaltonizer();
    -+        }
    -+        mat4 oldMatrix = engine.setupColorTransform(colorMatrix);
    -+        doComposeSurfaces(hw, dirtyRegion);
    -+        engine.setupColorTransform(oldMatrix);
    -+    }
    -+
    -+    // update the swap region and clear the dirty region
    -+    hw->swapRegion.orSelf(dirtyRegion);
    -+
    -+    // swap buffers (presentation)
    -+    hw->swapBuffers(getHwComposer());
    -+}
    -+
    -+bool SurfaceFlinger::doComposeSurfaces(const sp<const DisplayDevice>& hw, const Region& dirty)
    -+{
    -+    RenderEngine& engine(getRenderEngine());
    -+    const int32_t id = hw->getHwcDisplayId();
    -+    HWComposer& hwc(getHwComposer());
    -+    HWComposer::LayerListIterator cur = hwc.begin(id);
    -+    const HWComposer::LayerListIterator end = hwc.end(id);
    -+
    -+    bool hasGlesComposition = hwc.hasGlesComposition(id);
    -+    if (hasGlesComposition) {
    -+        if (!hw->makeCurrent(mEGLDisplay, mEGLContext)) {
    -+            ALOGW("DisplayDevice::makeCurrent failed. Aborting surface composition for display %s",
    -+                  hw->getDisplayName().string());
    -+            eglMakeCurrent(mEGLDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
    -+            if(!getDefaultDisplayDevice()->makeCurrent(mEGLDisplay, mEGLContext)) {
    -+              ALOGE("DisplayDevice::makeCurrent on default display failed. Aborting.");
    -+            }
    -+            return false;
    -+        }
    -+
    -+        // Never touch the framebuffer if we don't have any framebuffer layers
    -+        const bool hasHwcComposition = hwc.hasHwcComposition(id);
    -+        if (hasHwcComposition) {
    -+            // when using overlays, we assume a fully transparent framebuffer
    -+            // NOTE: we could reduce how much we need to clear, for instance
    -+            // remove where there are opaque FB layers. however, on some
    -+            // GPUs doing a "clean slate" clear might be more efficient.
    -+            // We'll revisit later if needed.
    -+            engine.clearWithColor(0, 0, 0, 0);
    -+        } else {
    -+            // we start with the whole screen area
    -+            const Region bounds(hw->getBounds());
    -+
    -+            // we remove the scissor part
    -+            // we're left with the letterbox region
    -+            // (common case is that letterbox ends-up being empty)
    -+            const Region letterbox(bounds.subtract(hw->getScissor()));
    -+
    -+            // compute the area to clear
    -+            Region region(hw->undefinedRegion.merge(letterbox));
    -+
    -+            // but limit it to the dirty region
    -+            region.andSelf(dirty);
    -+
    -+            // screen is already cleared here
    -+            if (!region.isEmpty()) {
    -+                // can happen with SurfaceView
    -+                drawWormhole(hw, region);
    -+            }
    -+        }
    -+
    -+        if (hw->getDisplayType() != DisplayDevice::DISPLAY_PRIMARY) {
    -+            // just to be on the safe side, we don't set the
    -+            // scissor on the main display. It should never be needed
    -+            // anyways (though in theory it could since the API allows it).
    -+            const Rect& bounds(hw->getBounds());
    -+            const Rect& scissor(hw->getScissor());
    -+            if (scissor != bounds) {
    -+                // scissor doesn't match the screen's dimensions, so we
    -+                // need to clear everything outside of it and enable
    -+                // the GL scissor so we don't draw anything where we shouldn't
    -+
    -+                // enable scissor for this frame
    -+                const uint32_t height = hw->getHeight();
    -+                engine.setScissor(scissor.left, height - scissor.bottom,
    -+                        scissor.getWidth(), scissor.getHeight());
    -+            }
    -+        }
    -+    }
    -+
    -+    /*
    -+     * and then, render the layers targeted at the framebuffer
    -+     */
    -+
    -+    const Vector< sp<Layer> >& layers(hw->getVisibleLayersSortedByZ());
    -+    const size_t count = layers.size();
    -+    const Transform& tr = hw->getTransform();
    -+    if (cur != end) {
    -+        // we're using h/w composer
    -+        for (size_t i=0 ; i<count && cur!=end ; ++i, ++cur) {
    -+            const sp<Layer>& layer(layers[i]);
    -+            const Region clip(dirty.intersect(tr.transform(layer->visibleRegion)));
    -+            if (!clip.isEmpty()) {
    -+                switch (cur->getCompositionType()) {
    -+                    case HWC_CURSOR_OVERLAY:
    -+                    case HWC_OVERLAY: {
    -+                        const Layer::State& state(layer->getDrawingState());
    -+                        if ((cur->getHints() & HWC_HINT_CLEAR_FB)
    -+                                && i
    -+                                && layer->isOpaque(state) && (state.alpha == 0xFF)
    -+                                && hasGlesComposition) {
    -+                            // never clear the very first layer since we're
    -+                            // guaranteed the FB is already cleared
    -+                            layer->clearWithOpenGL(hw, clip);
    -+                        }
    -+                        break;
    -+                    }
    -+                    case HWC_FRAMEBUFFER: {
    -+                        layer->draw(hw, clip);
    -+                        break;
    -+                    }
    -+                    case HWC_FRAMEBUFFER_TARGET: {
    -+                        // this should not happen as the iterator shouldn't
    -+                        // let us get there.
    -+                        ALOGW("HWC_FRAMEBUFFER_TARGET found in hwc list (index=%zu)", i);
    -+                        break;
    -+                    }
    -+                }
    -+            }
    -+            layer->setAcquireFence(hw, *cur);
    -+        }
    -+    } else {
    -+        // we're not using h/w composer
    -+        for (size_t i=0 ; i<count ; ++i) {
    -+            const sp<Layer>& layer(layers[i]);
    -+            const Region clip(dirty.intersect(
    -+                    tr.transform(layer->visibleRegion)));
    -+            if (!clip.isEmpty()) {
    -+                layer->draw(hw, clip);
    -+            }
    -+        }
    -+    }
    -+
    -+    // disable scissor at the end of the frame
    -+    engine.disableScissor();
    -+    return true;
    -+}
    -+
    -+void SurfaceFlinger::drawWormhole(const sp<const DisplayDevice>& hw, const Region& region) const {
    -+    const int32_t height = hw->getHeight();
    -+    RenderEngine& engine(getRenderEngine());
    -+    engine.fillRegionWithColor(region, height, 0, 0, 0, 0);
    -+}
    -+
    -+status_t SurfaceFlinger::addClientLayer(const sp<Client>& client,
    -+        const sp<IBinder>& handle,
    -+        const sp<IGraphicBufferProducer>& gbc,
    -+        const sp<Layer>& lbc)
    -+{
    -+    // add this layer to the current state list
    -+    {
    -+        Mutex::Autolock _l(mStateLock);
    -+        if (mCurrentState.layersSortedByZ.size() >= MAX_LAYERS) {
    -+            return NO_MEMORY;
    -+        }
    -+        mCurrentState.layersSortedByZ.add(lbc);
    -+        mGraphicBufferProducerList.add(IInterface::asBinder(gbc));
    -+    }
    -+
    -+    // attach this layer to the client
    -+    client->attachLayer(handle, lbc);
    -+
    -+    return NO_ERROR;
    -+}
    -+
    -+status_t SurfaceFlinger::removeLayer(const wp<Layer>& weakLayer) {
    -+    Mutex::Autolock _l(mStateLock);
    -+    sp<Layer> layer = weakLayer.promote();
    -+    if (layer == nullptr) {
    -+        // The layer has already been removed, carry on
    -+        return NO_ERROR;
    -+    }
    -+
    -+    ssize_t index = mCurrentState.layersSortedByZ.remove(layer);
    -+    if (index >= 0) {
    -+        mLayersPendingRemoval.push(layer);
    -+        mLayersRemoved = true;
    -+        setTransactionFlags(eTransactionNeeded);
    -+        return NO_ERROR;
    -+    }
    -+    return status_t(index);
    -+}
    -+
    -+uint32_t SurfaceFlinger::peekTransactionFlags(uint32_t /* flags */) {
    -+    return android_atomic_release_load(&mTransactionFlags);
    -+}
    -+
    -+uint32_t SurfaceFlinger::getTransactionFlags(uint32_t flags) {
    -+    return android_atomic_and(~flags, &mTransactionFlags) & flags;
    -+}
    -+
    -+uint32_t SurfaceFlinger::setTransactionFlags(uint32_t flags) {
    -+    uint32_t old = android_atomic_or(flags, &mTransactionFlags);
    -+    if ((old & flags)==0) { // wake the server up
    -+        signalTransaction();
    -+    }
    -+    return old;
    -+}
    -+
    -+void SurfaceFlinger::setTransactionState(
    -+        const Vector<ComposerState>& state,
    -+        const Vector<DisplayState>& displays,
    -+        uint32_t flags)
    -+{
    -+    ATRACE_CALL();
    -+    Mutex::Autolock _l(mStateLock);
    -+    uint32_t transactionFlags = 0;
    -+
    -+    if (flags & eAnimation) {
    -+        // For window updates that are part of an animation we must wait for
    -+        // previous animation "frames" to be handled.
    -+        while (mAnimTransactionPending) {
    -+            status_t err = mTransactionCV.waitRelative(mStateLock, s2ns(5));
    -+            if (CC_UNLIKELY(err != NO_ERROR)) {
    -+                // just in case something goes wrong in SF, return to the
    -+                // caller after a few seconds.
    -+                ALOGW_IF(err == TIMED_OUT, "setTransactionState timed out "
    -+                        "waiting for previous animation frame");
    -+                mAnimTransactionPending = false;
    -+                break;
    -+            }
    -+        }
    -+    }
    -+
    -+    size_t count = displays.size();
    -+    for (size_t i=0 ; i<count ; i++) {
    -+        const DisplayState& s(displays[i]);
    -+        transactionFlags |= setDisplayStateLocked(s);
    -+    }
    -+
    -+    count = state.size();
    -+    for (size_t i=0 ; i<count ; i++) {
    -+        const ComposerState& s(state[i]);
    -+        // Here we need to check that the interface we're given is indeed
    -+        // one of our own. A malicious client could give us a NULL
    -+        // IInterface, or one of its own or even one of our own but a
    -+        // different type. All these situations would cause us to crash.
    -+        //
    -+        // NOTE: it would be better to use RTTI as we could directly check
    -+        // that we have a Client*. however, RTTI is disabled in Android.
    -+        if (s.client != NULL) {
    -+            sp<IBinder> binder = IInterface::asBinder(s.client);
    -+            if (binder != NULL) {
    -+                String16 desc(binder->getInterfaceDescriptor());
    -+                if (desc == ISurfaceComposerClient::descriptor) {
    -+                    sp<Client> client( static_cast<Client *>(s.client.get()) );
    -+                    transactionFlags |= setClientStateLocked(client, s.state);
    -+                }
    -+            }
    -+        }
    -+    }
    -+
    -+    // If a synchronous transaction is explicitly requested without any changes,
    -+    // force a transaction anyway. This can be used as a flush mechanism for
    -+    // previous async transactions.
    -+    if (transactionFlags == 0 && (flags & eSynchronous)) {
    -+        transactionFlags = eTransactionNeeded;
    -+    }
    -+
    -+    if (transactionFlags) {
    -+        // this triggers the transaction
    -+        setTransactionFlags(transactionFlags);
    -+
    -+        // if this is a synchronous transaction, wait for it to take effect
    -+        // before returning.
    -+        if (flags & eSynchronous) {
    -+            mTransactionPending = true;
    -+        }
    -+        if (flags & eAnimation) {
    -+            mAnimTransactionPending = true;
    -+        }
    -+        while (mTransactionPending) {
    -+            status_t err = mTransactionCV.waitRelative(mStateLock, s2ns(5));
    -+            if (CC_UNLIKELY(err != NO_ERROR)) {
    -+                // just in case something goes wrong in SF, return to the
    -+                // called after a few seconds.
    -+                ALOGW_IF(err == TIMED_OUT, "setTransactionState timed out!");
    -+                mTransactionPending = false;
    -+                break;
    -+            }
    -+        }
    -+    }
    -+}
    -+
    -+uint32_t SurfaceFlinger::setDisplayStateLocked(const DisplayState& s)
    -+{
    -+    ssize_t dpyIdx = mCurrentState.displays.indexOfKey(s.token);
    -+    if (dpyIdx < 0)
    -+        return 0;
    -+
    -+    uint32_t flags = 0;
    -+    DisplayDeviceState& disp(mCurrentState.displays.editValueAt(dpyIdx));
    -+    if (disp.isValid()) {
    -+        const uint32_t what = s.what;
    -+        if (what & DisplayState::eSurfaceChanged) {
    -+            if (IInterface::asBinder(disp.surface) != IInterface::asBinder(s.surface)) {
    -+                disp.surface = s.surface;
    -+                flags |= eDisplayTransactionNeeded;
    -+            }
    -+        }
    -+        if (what & DisplayState::eLayerStackChanged) {
    -+            if (disp.layerStack != s.layerStack) {
    -+                disp.layerStack = s.layerStack;
    -+                flags |= eDisplayTransactionNeeded;
    -+            }
    -+        }
    -+        if (what & DisplayState::eDisplayProjectionChanged) {
    -+            if (disp.orientation != s.orientation) {
    -+                disp.orientation = s.orientation;
    -+                flags |= eDisplayTransactionNeeded;
    -+            }
    -+            if (disp.frame != s.frame) {
    -+                disp.frame = s.frame;
    -+                flags |= eDisplayTransactionNeeded;
    -+            }
    -+            if (disp.viewport != s.viewport) {
    -+                disp.viewport = s.viewport;
    -+                flags |= eDisplayTransactionNeeded;
    -+            }
    -+        }
    -+        if (what & DisplayState::eDisplaySizeChanged) {
    -+            if (disp.width != s.width) {
    -+                disp.width = s.width;
    -+                flags |= eDisplayTransactionNeeded;
    -+            }
    -+            if (disp.height != s.height) {
    -+                disp.height = s.height;
    -+                flags |= eDisplayTransactionNeeded;
    -+            }
    -+        }
    -+    }
    -+    return flags;
    -+}
    -+
    -+uint32_t SurfaceFlinger::setClientStateLocked(
    -+        const sp<Client>& client,
    -+        const layer_state_t& s)
    -+{
    -+    uint32_t flags = 0;
    -+    sp<Layer> layer(client->getLayerUser(s.surface));
    -+    if (layer != 0) {
    -+        const uint32_t what = s.what;
    -+        bool geometryAppliesWithResize =
    -+                what & layer_state_t::eGeometryAppliesWithResize;
    -+        if (what & layer_state_t::ePositionChanged) {
    -+            if (layer->setPosition(s.x, s.y, !geometryAppliesWithResize)) {
    -+                flags |= eTraversalNeeded;
    -+            }
    -+        }
    -+        if (what & layer_state_t::eLayerChanged) {
    -+            // NOTE: index needs to be calculated before we update the state
    -+            ssize_t idx = mCurrentState.layersSortedByZ.indexOf(layer);
    -+            if (layer->setLayer(s.z) && idx >= 0) {
    -+                mCurrentState.layersSortedByZ.removeAt(idx);
    -+                mCurrentState.layersSortedByZ.add(layer);
    -+                // we need traversal (state changed)
    -+                // AND transaction (list changed)
    -+                flags |= eTransactionNeeded|eTraversalNeeded;
    -+            }
    -+        }
    -+        if (what & layer_state_t::eSizeChanged) {
    -+            if (layer->setSize(s.w, s.h)) {
    -+                flags |= eTraversalNeeded;
    -+            }
    -+        }
    -+        if (what & layer_state_t::eAlphaChanged) {
    -+            if (layer->setAlpha(uint8_t(255.0f*s.alpha+0.5f)))
    -+                flags |= eTraversalNeeded;
    -+        }
    -+        if (what & layer_state_t::eMatrixChanged) {
    -+            if (layer->setMatrix(s.matrix))
    -+                flags |= eTraversalNeeded;
    -+        }
    -+        if (what & layer_state_t::eTransparentRegionChanged) {
    -+            if (layer->setTransparentRegionHint(s.transparentRegion))
    -+                flags |= eTraversalNeeded;
    -+        }
    -+        if (what & layer_state_t::eFlagsChanged) {
    -+            if (layer->setFlags(s.flags, s.mask))
    -+                flags |= eTraversalNeeded;
    -+        }
    -+        if (what & layer_state_t::eCropChanged) {
    -+            if (layer->setCrop(s.crop, !geometryAppliesWithResize))
    -+                flags |= eTraversalNeeded;
    -+        }
    -+        if (what & layer_state_t::eFinalCropChanged) {
    -+            if (layer->setFinalCrop(s.finalCrop))
    -+                flags |= eTraversalNeeded;
    -+        }
    -+        if (what & layer_state_t::eLayerStackChanged) {
    -+            // NOTE: index needs to be calculated before we update the state
    -+            ssize_t idx = mCurrentState.layersSortedByZ.indexOf(layer);
    -+            if (layer->setLayerStack(s.layerStack) && idx >= 0) {
    -+                mCurrentState.layersSortedByZ.removeAt(idx);
    -+                mCurrentState.layersSortedByZ.add(layer);
    -+                // we need traversal (state changed)
    -+                // AND transaction (list changed)
    -+                flags |= eTransactionNeeded|eTraversalNeeded;
    -+            }
    -+        }
    -+        if (what & layer_state_t::eDeferTransaction) {
    -+            layer->deferTransactionUntil(s.handle, s.frameNumber);
    -+            // We don't trigger a traversal here because if no other state is
    -+            // changed, we don't want this to cause any more work
    -+        }
    -+        if (what & layer_state_t::eOverrideScalingModeChanged) {
    -+            layer->setOverrideScalingMode(s.overrideScalingMode);
    -+            // We don't trigger a traversal here because if no other state is
    -+            // changed, we don't want this to cause any more work
    -+        }
    -+    }
    -+    return flags;
    -+}
    -+
    -+status_t SurfaceFlinger::createLayer(
    -+        const String8& name,
    -+        const sp<Client>& client,
    -+        uint32_t w, uint32_t h, PixelFormat format, uint32_t flags,
    -+        sp<IBinder>* handle, sp<IGraphicBufferProducer>* gbp)
    -+{
    -+    //ALOGD("createLayer for (%d x %d), name=%s", w, h, name.string());
    -+    if (int32_t(w|h) < 0) {
    -+        ALOGE("createLayer() failed, w or h is negative (w=%d, h=%d)",
    -+                int(w), int(h));
    -+        return BAD_VALUE;
    -+    }
    -+
    -+    status_t result = NO_ERROR;
    -+
    -+    sp<Layer> layer;
    -+
    -+    switch (flags & ISurfaceComposerClient::eFXSurfaceMask) {
    -+        case ISurfaceComposerClient::eFXSurfaceNormal:
    -+            result = createNormalLayer(client,
    -+                    name, w, h, flags, format,
    -+                    handle, gbp, &layer);
    -+            break;
    -+        case ISurfaceComposerClient::eFXSurfaceDim:
    -+            result = createDimLayer(client,
    -+                    name, w, h, flags,
    -+                    handle, gbp, &layer);
    -+            break;
    -+        default:
    -+            result = BAD_VALUE;
    -+            break;
    -+    }
    -+
    -+    if (result != NO_ERROR) {
    -+        return result;
    -+    }
    -+
    -+    result = addClientLayer(client, *handle, *gbp, layer);
    -+    if (result != NO_ERROR) {
    -+        return result;
    -+    }
    -+
    -+    setTransactionFlags(eTransactionNeeded);
    -+    return result;
    -+}
    -+
    -+status_t SurfaceFlinger::createNormalLayer(const sp<Client>& client,
    -+        const String8& name, uint32_t w, uint32_t h, uint32_t flags, PixelFormat& format,
    -+        sp<IBinder>* handle, sp<IGraphicBufferProducer>* gbp, sp<Layer>* outLayer)
    -+{
    -+    // initialize the surfaces
    -+    switch (format) {
    -+    case PIXEL_FORMAT_TRANSPARENT:
    -+    case PIXEL_FORMAT_TRANSLUCENT:
    -+        format = PIXEL_FORMAT_RGBA_8888;
    -+        break;
    -+    case PIXEL_FORMAT_OPAQUE:
    -+        format = PIXEL_FORMAT_RGBX_8888;
    -+        break;
    -+    }
    -+
    -+    *outLayer = new Layer(this, client, name, w, h, flags);
    -+    status_t err = (*outLayer)->setBuffers(w, h, format, flags);
    -+    if (err == NO_ERROR) {
    -+        *handle = (*outLayer)->getHandle();
    -+        *gbp = (*outLayer)->getProducer();
    -+    }
    -+
    -+    ALOGE_IF(err, "createNormalLayer() failed (%s)", strerror(-err));
    -+    return err;
    -+}
    -+
    -+status_t SurfaceFlinger::createDimLayer(const sp<Client>& client,
    -+        const String8& name, uint32_t w, uint32_t h, uint32_t flags,
    -+        sp<IBinder>* handle, sp<IGraphicBufferProducer>* gbp, sp<Layer>* outLayer)
    -+{
    -+    *outLayer = new LayerDim(this, client, name, w, h, flags);
    -+    *handle = (*outLayer)->getHandle();
    -+    *gbp = (*outLayer)->getProducer();
    -+    return NO_ERROR;
    -+}
    -+
    -+status_t SurfaceFlinger::onLayerRemoved(const sp<Client>& client, const sp<IBinder>& handle)
    -+{
    -+    // called by the window manager when it wants to remove a Layer
    -+    status_t err = NO_ERROR;
    -+    sp<Layer> l(client->getLayerUser(handle));
    -+    if (l != NULL) {
    -+        err = removeLayer(l);
    -+        ALOGE_IF(err<0 && err != NAME_NOT_FOUND,
    -+                "error removing layer=%p (%s)", l.get(), strerror(-err));
    -+    }
    -+    return err;
    -+}
    -+
    -+status_t SurfaceFlinger::onLayerDestroyed(const wp<Layer>& layer)
    -+{
    -+    // called by ~LayerCleaner() when all references to the IBinder (handle)
    -+    // are gone
    -+    return removeLayer(layer);
    -+}
    -+
    -+// ---------------------------------------------------------------------------
    -+
    -+void SurfaceFlinger::onInitializeDisplays() {
    -+    // reset screen orientation and use primary layer stack
    -+    Vector<ComposerState> state;
    -+    Vector<DisplayState> displays;
    -+    DisplayState d;
    -+    d.what = DisplayState::eDisplayProjectionChanged |
    -+             DisplayState::eLayerStackChanged;
    -+    d.token = mBuiltinDisplays[DisplayDevice::DISPLAY_PRIMARY];
    -+    d.layerStack = 0;
    -+    d.orientation = DisplayState::eOrientationDefault;
    -+    d.frame.makeInvalid();
    -+    d.viewport.makeInvalid();
    -+    d.width = 0;
    -+    d.height = 0;
    -+    displays.add(d);
    -+    setTransactionState(state, displays, 0);
    -+    setPowerModeInternal(getDisplayDevice(d.token), HWC_POWER_MODE_NORMAL);
    -+
    -+    const nsecs_t period =
    -+            getHwComposer().getRefreshPeriod(HWC_DISPLAY_PRIMARY);
    -+    mAnimFrameTracker.setDisplayRefreshPeriod(period);
    -+}
    -+
    -+void SurfaceFlinger::initializeDisplays() {
    -+    class MessageScreenInitialized : public MessageBase {
    -+        SurfaceFlinger* flinger;
    -+    public:
    -+        MessageScreenInitialized(SurfaceFlinger* flinger) : flinger(flinger) { }
    -+        virtual bool handler() {
    -+            flinger->onInitializeDisplays();
    -+            return true;
    -+        }
    -+    };
    -+    sp<MessageBase> msg = new MessageScreenInitialized(this);
    -+    postMessageAsync(msg);  // we may be called from main thread, use async message
    -+}
    -+
    -+void SurfaceFlinger::setPowerModeInternal(const sp<DisplayDevice>& hw,
    -+        int mode) {
    -+    ALOGD("Set power mode=%d, type=%d flinger=%p", mode, hw->getDisplayType(),
    -+            this);
    -+    int32_t type = hw->getDisplayType();
    -+    int currentMode = hw->getPowerMode();
    -+
    -+    if (mode == currentMode) {
    -+        ALOGD("Screen type=%d is already mode=%d", hw->getDisplayType(), mode);
    -+        return;
    -+    }
    -+
    -+    hw->setPowerMode(mode);
    -+    if (type >= DisplayDevice::NUM_BUILTIN_DISPLAY_TYPES) {
    -+        ALOGW("Trying to set power mode for virtual display");
    -+        return;
    -+    }
    -+
    -+    if (currentMode == HWC_POWER_MODE_OFF) {
    -+        // Turn on the display
    -+        getHwComposer().setPowerMode(type, mode);
    -+        if (type == DisplayDevice::DISPLAY_PRIMARY) {
    -+            // FIXME: eventthread only knows about the main display right now
    -+            mEventThread->onScreenAcquired();
    -+            resyncToHardwareVsync(true);
    -+        }
    -+
    -+        mVisibleRegionsDirty = true;
    -+        mHasPoweredOff = true;
    -+        repaintEverything();
    -+
    -+        struct sched_param param = {0};
    -+        param.sched_priority = 1;
    -+        if (sched_setscheduler(0, SCHED_FIFO, &param) != 0) {
    -+            ALOGW("Couldn't set SCHED_FIFO on display on");
    -+        }
    -+    } else if (mode == HWC_POWER_MODE_OFF) {
    -+        // Turn off the display
    -+        struct sched_param param = {0};
    -+        if (sched_setscheduler(0, SCHED_OTHER, &param) != 0) {
    -+            ALOGW("Couldn't set SCHED_OTHER on display off");
    -+        }
    -+
    -+        if (type == DisplayDevice::DISPLAY_PRIMARY) {
    -+            disableHardwareVsync(true); // also cancels any in-progress resync
    -+
    -+            // FIXME: eventthread only knows about the main display right now
    -+            mEventThread->onScreenReleased();
    -+        }
    -+
    -+        getHwComposer().setPowerMode(type, mode);
    -+        mVisibleRegionsDirty = true;
    -+        // from this point on, SF will stop drawing on this display
    -+    } else {
    -+        getHwComposer().setPowerMode(type, mode);
    -+    }
    -+}
    -+
    -+void SurfaceFlinger::setPowerMode(const sp<IBinder>& display, int mode) {
    -+    class MessageSetPowerMode: public MessageBase {
    -+        SurfaceFlinger& mFlinger;
    -+        sp<IBinder> mDisplay;
    -+        int mMode;
    -+    public:
    -+        MessageSetPowerMode(SurfaceFlinger& flinger,
    -+                const sp<IBinder>& disp, int mode) : mFlinger(flinger),
    -+                    mDisplay(disp) { mMode = mode; }
    -+        virtual bool handler() {
    -+            sp<DisplayDevice> hw(mFlinger.getDisplayDevice(mDisplay));
    -+            if (hw == NULL) {
    -+                ALOGE("Attempt to set power mode = %d for null display %p",
    -+                        mMode, mDisplay.get());
    -+            } else if (hw->getDisplayType() >= DisplayDevice::DISPLAY_VIRTUAL) {
    -+                ALOGW("Attempt to set power mode = %d for virtual display",
    -+                        mMode);
    -+            } else {
    -+                mFlinger.setPowerModeInternal(hw, mMode);
    -+            }
    -+            return true;
    -+        }
    -+    };
    -+    sp<MessageBase> msg = new MessageSetPowerMode(*this, display, mode);
    -+    postMessageSync(msg);
    -+}
    -+
    -+// ---------------------------------------------------------------------------
    -+
    -+status_t SurfaceFlinger::dump(int fd, const Vector<String16>& args)
    -+{
    -+    String8 result;
    -+
    -+    IPCThreadState* ipc = IPCThreadState::self();
    -+    const int pid = ipc->getCallingPid();
    -+    const int uid = ipc->getCallingUid();
    -+    if ((uid != AID_SHELL) &&
    -+            !PermissionCache::checkPermission(sDump, pid, uid)) {
    -+        result.appendFormat("Permission Denial: "
    -+                "can't dump SurfaceFlinger from pid=%d, uid=%d\n", pid, uid);
    -+    } else {
    -+        // Try to get the main lock, but give up after one second
    -+        // (this would indicate SF is stuck, but we want to be able to
    -+        // print something in dumpsys).
    -+        status_t err = mStateLock.timedLock(s2ns(1));
    -+        bool locked = (err == NO_ERROR);
    -+        if (!locked) {
    -+            result.appendFormat(
    -+                    "SurfaceFlinger appears to be unresponsive (%s [%d]), "
    -+                    "dumping anyways (no locks held)\n", strerror(-err), err);
    -+        }
    -+
    -+        bool dumpAll = true;
    -+        size_t index = 0;
    -+        size_t numArgs = args.size();
    -+        if (numArgs) {
    -+            if ((index < numArgs) &&
    -+                    (args[index] == String16("--list"))) {
    -+                index++;
    -+                listLayersLocked(args, index, result);
    -+                dumpAll = false;
    -+            }
    -+
    -+            if ((index < numArgs) &&
    -+                    (args[index] == String16("--latency"))) {
    -+                index++;
    -+                dumpStatsLocked(args, index, result);
    -+                dumpAll = false;
    -+            }
    -+
    -+            if ((index < numArgs) &&
    -+                    (args[index] == String16("--latency-clear"))) {
    -+                index++;
    -+                clearStatsLocked(args, index, result);
    -+                dumpAll = false;
    -+            }
    -+
    -+            if ((index < numArgs) &&
    -+                    (args[index] == String16("--dispsync"))) {
    -+                index++;
    -+                mPrimaryDispSync.dump(result);
    -+                dumpAll = false;
    -+            }
    -+
    -+            if ((index < numArgs) &&
    -+                    (args[index] == String16("--static-screen"))) {
    -+                index++;
    -+                dumpStaticScreenStats(result);
    -+                dumpAll = false;
    -+            }
    -+
    -+            if ((index < numArgs) &&
    -+                    (args[index] == String16("--fences"))) {
    -+                index++;
    -+                mFenceTracker.dump(&result);
    -+                dumpAll = false;
    -+            }
    -+        }
    -+
    -+        if (dumpAll) {
    -+            dumpAllLocked(args, index, result);
    -+        }
    -+
    -+        if (locked) {
    -+            mStateLock.unlock();
    -+        }
    -+    }
    -+    write(fd, result.string(), result.size());
    -+    return NO_ERROR;
    -+}
    -+
    -+void SurfaceFlinger::listLayersLocked(const Vector<String16>& /* args */,
    -+        size_t& /* index */, String8& result) const
    -+{
    -+    const LayerVector& currentLayers = mCurrentState.layersSortedByZ;
    -+    const size_t count = currentLayers.size();
    -+    for (size_t i=0 ; i<count ; i++) {
    -+        const sp<Layer>& layer(currentLayers[i]);
    -+        result.appendFormat("%s\n", layer->getName().string());
    -+    }
    -+}
    -+
    -+void SurfaceFlinger::dumpStatsLocked(const Vector<String16>& args, size_t& index,
    -+        String8& result) const
    -+{
    -+    String8 name;
    -+    if (index < args.size()) {
    -+        name = String8(args[index]);
    -+        index++;
    -+    }
    -+
    -+    const nsecs_t period =
    -+            getHwComposer().getRefreshPeriod(HWC_DISPLAY_PRIMARY);
    -+    result.appendFormat("%" PRId64 "\n", period);
    -+
    -+    if (name.isEmpty()) {
    -+        mAnimFrameTracker.dumpStats(result);
    -+    } else {
    -+        const LayerVector& currentLayers = mCurrentState.layersSortedByZ;
    -+        const size_t count = currentLayers.size();
    -+        for (size_t i=0 ; i<count ; i++) {
    -+            const sp<Layer>& layer(currentLayers[i]);
    -+            if (name == layer->getName()) {
    -+                layer->dumpFrameStats(result);
    -+            }
    -+        }
    -+    }
    -+}
    -+
    -+void SurfaceFlinger::clearStatsLocked(const Vector<String16>& args, size_t& index,
    -+        String8& /* result */)
    -+{
    -+    String8 name;
    -+    if (index < args.size()) {
    -+        name = String8(args[index]);
    -+        index++;
    -+    }
    -+
    -+    const LayerVector& currentLayers = mCurrentState.layersSortedByZ;
    -+    const size_t count = currentLayers.size();
    -+    for (size_t i=0 ; i<count ; i++) {
    -+        const sp<Layer>& layer(currentLayers[i]);
    -+        if (name.isEmpty() || (name == layer->getName())) {
    -+            layer->clearFrameStats();
    -+        }
    -+    }
    -+
    -+    mAnimFrameTracker.clearStats();
    -+}
    -+
    -+// This should only be called from the main thread.  Otherwise it would need
    -+// the lock and should use mCurrentState rather than mDrawingState.
    -+void SurfaceFlinger::logFrameStats() {
    -+    const LayerVector& drawingLayers = mDrawingState.layersSortedByZ;
    -+    const size_t count = drawingLayers.size();
    -+    for (size_t i=0 ; i<count ; i++) {
    -+        const sp<Layer>& layer(drawingLayers[i]);
    -+        layer->logFrameStats();
    -+    }
    -+
    -+    mAnimFrameTracker.logAndResetStats(String8("<win-anim>"));
    -+}
    -+
    -+/*static*/ void SurfaceFlinger::appendSfConfigString(String8& result)
    -+{
    -+    static const char* config =
    -+            " [sf"
    -+#ifdef HAS_CONTEXT_PRIORITY
    -+            " HAS_CONTEXT_PRIORITY"
    -+#endif
    -+#ifdef NEVER_DEFAULT_TO_ASYNC_MODE
    -+            " NEVER_DEFAULT_TO_ASYNC_MODE"
    -+#endif
    -+#ifdef TARGET_DISABLE_TRIPLE_BUFFERING
    -+            " TARGET_DISABLE_TRIPLE_BUFFERING"
    -+#endif
    -+            "]";
    -+    result.append(config);
    -+}
    -+
    -+void SurfaceFlinger::dumpStaticScreenStats(String8& result) const
    -+{
    -+    result.appendFormat("Static screen stats:\n");
    -+    for (size_t b = 0; b < NUM_BUCKETS - 1; ++b) {
    -+        float bucketTimeSec = mFrameBuckets[b] / 1e9;
    -+        float percent = 100.0f *
    -+                static_cast<float>(mFrameBuckets[b]) / mTotalTime;
    -+        result.appendFormat("  < %zd frames: %.3f s (%.1f%%)\n",
    -+                b + 1, bucketTimeSec, percent);
    -+    }
    -+    float bucketTimeSec = mFrameBuckets[NUM_BUCKETS - 1] / 1e9;
    -+    float percent = 100.0f *
    -+            static_cast<float>(mFrameBuckets[NUM_BUCKETS - 1]) / mTotalTime;
    -+    result.appendFormat("  %zd+ frames: %.3f s (%.1f%%)\n",
    -+            NUM_BUCKETS - 1, bucketTimeSec, percent);
    -+}
    -+
    -+void SurfaceFlinger::recordBufferingStats(const char* layerName,
    -+        std::vector<OccupancyTracker::Segment>&& history) {
    -+    Mutex::Autolock lock(mBufferingStatsMutex);
    -+    auto& stats = mBufferingStats[layerName];
    -+    for (const auto& segment : history) {
    -+        if (!segment.usedThirdBuffer) {
    -+            stats.twoBufferTime += segment.totalTime;
    -+        }
    -+        if (segment.occupancyAverage < 1.0f) {
    -+            stats.doubleBufferedTime += segment.totalTime;
    -+        } else if (segment.occupancyAverage < 2.0f) {
    -+            stats.tripleBufferedTime += segment.totalTime;
    -+        }
    -+        ++stats.numSegments;
    -+        stats.totalTime += segment.totalTime;
    -+    }
    -+}
    -+
    -+void SurfaceFlinger::dumpBufferingStats(String8& result) const {
    -+    result.append("Buffering stats:\n");
    -+    result.append("  [Layer name] <Active time> <Two buffer> "
    -+            "<Double buffered> <Triple buffered>\n");
    -+    Mutex::Autolock lock(mBufferingStatsMutex);
    -+    typedef std::tuple<std::string, float, float, float> BufferTuple;
    -+    std::map<float, BufferTuple, std::greater<float>> sorted;
    -+    for (const auto& statsPair : mBufferingStats) {
    -+        const char* name = statsPair.first.c_str();
    -+        const BufferingStats& stats = statsPair.second;
    -+        if (stats.numSegments == 0) {
    -+            continue;
    -+        }
    -+        float activeTime = ns2ms(stats.totalTime) / 1000.0f;
    -+        float twoBufferRatio = static_cast<float>(stats.twoBufferTime) /
    -+                stats.totalTime;
    -+        float doubleBufferRatio = static_cast<float>(
    -+                stats.doubleBufferedTime) / stats.totalTime;
    -+        float tripleBufferRatio = static_cast<float>(
    -+                stats.tripleBufferedTime) / stats.totalTime;
    -+        sorted.insert({activeTime, {name, twoBufferRatio,
    -+                doubleBufferRatio, tripleBufferRatio}});
    -+    }
    -+    for (const auto& sortedPair : sorted) {
    -+        float activeTime = sortedPair.first;
    -+        const BufferTuple& values = sortedPair.second;
    -+        result.appendFormat("  [%s] %.2f %.3f %.3f %.3f\n",
    -+                std::get<0>(values).c_str(), activeTime,
    -+                std::get<1>(values), std::get<2>(values),
    -+                std::get<3>(values));
    -+    }
    -+    result.append("\n");
    -+}
    -+
    -+void SurfaceFlinger::dumpAllLocked(const Vector<String16>& args, size_t& index,
    -+        String8& result) const
    -+{
    -+    bool colorize = false;
    -+    if (index < args.size()
    -+            && (args[index] == String16("--color"))) {
    -+        colorize = true;
    -+        index++;
    -+    }
    -+
    -+    Colorizer colorizer(colorize);
    -+
    -+    // figure out if we're stuck somewhere
    -+    const nsecs_t now = systemTime();
    -+    const nsecs_t inSwapBuffers(mDebugInSwapBuffers);
    -+    const nsecs_t inTransaction(mDebugInTransaction);
    -+    nsecs_t inSwapBuffersDuration = (inSwapBuffers) ? now-inSwapBuffers : 0;
    -+    nsecs_t inTransactionDuration = (inTransaction) ? now-inTransaction : 0;
    -+
    -+    /*
    -+     * Dump library configuration.
    -+     */
    -+
    -+    colorizer.bold(result);
    -+    result.append("Build configuration:");
    -+    colorizer.reset(result);
    -+    appendSfConfigString(result);
    -+    appendUiConfigString(result);
    -+    appendGuiConfigString(result);
    -+    result.append("\n");
    -+
    -+    colorizer.bold(result);
    -+    result.append("Sync configuration: ");
    -+    colorizer.reset(result);
    -+    result.append(SyncFeatures::getInstance().toString());
    -+    result.append("\n");
    -+
    -+    colorizer.bold(result);
    -+    result.append("DispSync configuration: ");
    -+    colorizer.reset(result);
    -+    result.appendFormat("app phase %" PRId64 " ns, sf phase %" PRId64 " ns, "
    -+            "present offset %d ns (refresh %" PRId64 " ns)",
    -+        vsyncPhaseOffsetNs, sfVsyncPhaseOffsetNs, PRESENT_TIME_OFFSET_FROM_VSYNC_NS,
    -+        mHwc->getRefreshPeriod(HWC_DISPLAY_PRIMARY));
    -+    result.append("\n");
    -+
    -+    // Dump static screen stats
    -+    result.append("\n");
    -+    dumpStaticScreenStats(result);
    -+    result.append("\n");
    -+
    -+    dumpBufferingStats(result);
    -+
    -+    /*
    -+     * Dump the visible layer list
    -+     */
    -+    const LayerVector& currentLayers = mCurrentState.layersSortedByZ;
    -+    const size_t count = currentLayers.size();
    -+    colorizer.bold(result);
    -+    result.appendFormat("Visible layers (count = %zu)\n", count);
    -+    colorizer.reset(result);
    -+    for (size_t i=0 ; i<count ; i++) {
    -+        const sp<Layer>& layer(currentLayers[i]);
    -+        layer->dump(result, colorizer);
    -+    }
    -+
    -+    /*
    -+     * Dump Display state
    -+     */
    -+
    -+    colorizer.bold(result);
    -+    result.appendFormat("Displays (%zu entries)\n", mDisplays.size());
    -+    colorizer.reset(result);
    -+    for (size_t dpy=0 ; dpy<mDisplays.size() ; dpy++) {
    -+        const sp<const DisplayDevice>& hw(mDisplays[dpy]);
    -+        hw->dump(result);
    -+    }
    -+
    -+    /*
    -+     * Dump SurfaceFlinger global state
    -+     */
    -+
    -+    colorizer.bold(result);
    -+    result.append("SurfaceFlinger global state:\n");
    -+    colorizer.reset(result);
    -+
    -+    HWComposer& hwc(getHwComposer());
    -+    sp<const DisplayDevice> hw(getDefaultDisplayDevice());
    -+
    -+    colorizer.bold(result);
    -+    result.appendFormat("EGL implementation : %s\n",
    -+            eglQueryStringImplementationANDROID(mEGLDisplay, EGL_VERSION));
    -+    colorizer.reset(result);
    -+    result.appendFormat("%s\n",
    -+            eglQueryStringImplementationANDROID(mEGLDisplay, EGL_EXTENSIONS));
    -+
    -+    mRenderEngine->dump(result);
    -+
    -+    hw->undefinedRegion.dump(result, "undefinedRegion");
    -+    result.appendFormat("  orientation=%d, isDisplayOn=%d\n",
    -+            hw->getOrientation(), hw->isDisplayOn());
    -+    result.appendFormat(
    -+            "  last eglSwapBuffers() time: %f us\n"
    -+            "  last transaction time     : %f us\n"
    -+            "  transaction-flags         : %08x\n"
    -+            "  refresh-rate              : %f fps\n"
    -+            "  x-dpi                     : %f\n"
    -+            "  y-dpi                     : %f\n"
    -+            "  gpu_to_cpu_unsupported    : %d\n"
    -+            ,
    -+            mLastSwapBufferTime/1000.0,
    -+            mLastTransactionTime/1000.0,
    -+            mTransactionFlags,
    -+            1e9 / hwc.getRefreshPeriod(HWC_DISPLAY_PRIMARY),
    -+            hwc.getDpiX(HWC_DISPLAY_PRIMARY),
    -+            hwc.getDpiY(HWC_DISPLAY_PRIMARY),
    -+            !mGpuToCpuSupported);
    -+
    -+    result.appendFormat("  eglSwapBuffers time: %f us\n",
    -+            inSwapBuffersDuration/1000.0);
    -+
    -+    result.appendFormat("  transaction time: %f us\n",
    -+            inTransactionDuration/1000.0);
    -+
    -+    /*
    -+     * VSYNC state
    -+     */
    -+    mEventThread->dump(result);
    -+
    -+    /*
    -+     * Dump HWComposer state
    -+     */
    -+    colorizer.bold(result);
    -+    result.append("h/w composer state:\n");
    -+    colorizer.reset(result);
    -+    result.appendFormat("  h/w composer %s and %s\n",
    -+            hwc.initCheck()==NO_ERROR ? "present" : "not present",
    -+                    (mDebugDisableHWC || mDebugRegion || mDaltonize
    -+                            || mHasColorMatrix) ? "disabled" : "enabled");
    -+    hwc.dump(result);
    -+
    -+    /*
    -+     * Dump gralloc state
    -+     */
    -+    const GraphicBufferAllocator& alloc(GraphicBufferAllocator::get());
    -+    alloc.dump(result);
    -+}
    -+
    -+const Vector< sp<Layer> >&
    -+SurfaceFlinger::getLayerSortedByZForHwcDisplay(int id) {
    -+    // Note: mStateLock is held here
    -+    wp<IBinder> dpy;
    -+    for (size_t i=0 ; i<mDisplays.size() ; i++) {
    -+        if (mDisplays.valueAt(i)->getHwcDisplayId() == id) {
    -+            dpy = mDisplays.keyAt(i);
    -+            break;
    -+        }
    -+    }
    -+    if (dpy == NULL) {
    -+        ALOGE("getLayerSortedByZForHwcDisplay: invalid hwc display id %d", id);
    -+        // Just use the primary display so we have something to return
    -+        dpy = getBuiltInDisplay(DisplayDevice::DISPLAY_PRIMARY);
    -+    }
    -+    return getDisplayDevice(dpy)->getVisibleLayersSortedByZ();
    -+}
    -+
    -+bool SurfaceFlinger::startDdmConnection()
    -+{
    -+    void* libddmconnection_dso =
    -+            dlopen("libsurfaceflinger_ddmconnection.so", RTLD_NOW);
    -+    if (!libddmconnection_dso) {
    -+        return false;
    -+    }
    -+    void (*DdmConnection_start)(const char* name);
    -+    DdmConnection_start =
    -+            (decltype(DdmConnection_start))dlsym(libddmconnection_dso, "DdmConnection_start");
    -+    if (!DdmConnection_start) {
    -+        dlclose(libddmconnection_dso);
    -+        return false;
    -+    }
    -+    (*DdmConnection_start)(getServiceName());
    -+    return true;
    -+}
    -+
    -+status_t SurfaceFlinger::onTransact(
    -+    uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
    -+{
    -+    switch (code) {
    -+        case CREATE_CONNECTION:
    -+        case CREATE_DISPLAY:
    -+        case SET_TRANSACTION_STATE:
    -+        case BOOT_FINISHED:
    -+        case CLEAR_ANIMATION_FRAME_STATS:
    -+        case GET_ANIMATION_FRAME_STATS:
    -+        case SET_POWER_MODE:
    -+        case GET_HDR_CAPABILITIES:
    -+        {
    -+            // codes that require permission check
    -+            IPCThreadState* ipc = IPCThreadState::self();
    -+            const int pid = ipc->getCallingPid();
    -+            const int uid = ipc->getCallingUid();
    -+            if ((uid != AID_GRAPHICS && uid != AID_SYSTEM) &&
    -+                    !PermissionCache::checkPermission(sAccessSurfaceFlinger, pid, uid)) {
    -+                ALOGE("Permission Denial: "
    -+                        "can't access SurfaceFlinger pid=%d, uid=%d", pid, uid);
    -+                return PERMISSION_DENIED;
    -+            }
    -+            break;
    -+        }
    -+        case CAPTURE_SCREEN:
    -+        {
    -+            // codes that require permission check
    -+            IPCThreadState* ipc = IPCThreadState::self();
    -+            const int pid = ipc->getCallingPid();
    -+            const int uid = ipc->getCallingUid();
    -+            if ((uid != AID_GRAPHICS) &&
    -+                    !PermissionCache::checkPermission(sReadFramebuffer, pid, uid)) {
    -+                ALOGE("Permission Denial: "
    -+                        "can't read framebuffer pid=%d, uid=%d", pid, uid);
    -+                return PERMISSION_DENIED;
    -+            }
    -+            break;
    -+        }
    -+    }
    -+
    -+    status_t err = BnSurfaceComposer::onTransact(code, data, reply, flags);
    -+    if (err == UNKNOWN_TRANSACTION || err == PERMISSION_DENIED) {
    -+        CHECK_INTERFACE(ISurfaceComposer, data, reply);
    -+        if (CC_UNLIKELY(!PermissionCache::checkCallingPermission(sHardwareTest))) {
    -+            IPCThreadState* ipc = IPCThreadState::self();
    -+            const int pid = ipc->getCallingPid();
    -+            const int uid = ipc->getCallingUid();
    -+            ALOGE("Permission Denial: "
    -+                    "can't access SurfaceFlinger pid=%d, uid=%d", pid, uid);
    -+            return PERMISSION_DENIED;
    -+        }
    -+        int n;
    -+        switch (code) {
    -+            case 1000: // SHOW_CPU, NOT SUPPORTED ANYMORE
    -+            case 1001: // SHOW_FPS, NOT SUPPORTED ANYMORE
    -+                return NO_ERROR;
    -+            case 1002:  // SHOW_UPDATES
    -+                n = data.readInt32();
    -+                mDebugRegion = n ? n : (mDebugRegion ? 0 : 1);
    -+                invalidateHwcGeometry();
    -+                repaintEverything();
    -+                return NO_ERROR;
    -+            case 1004:{ // repaint everything
    -+                repaintEverything();
    -+                return NO_ERROR;
    -+            }
    -+            case 1005:{ // force transaction
    -+                setTransactionFlags(
    -+                        eTransactionNeeded|
    -+                        eDisplayTransactionNeeded|
    -+                        eTraversalNeeded);
    -+                return NO_ERROR;
    -+            }
    -+            case 1006:{ // send empty update
    -+                signalRefresh();
    -+                return NO_ERROR;
    -+            }
    -+            case 1008:  // toggle use of hw composer
    -+                n = data.readInt32();
    -+                mDebugDisableHWC = n ? 1 : 0;
    -+                invalidateHwcGeometry();
    -+                repaintEverything();
    -+                return NO_ERROR;
    -+            case 1009:  // toggle use of transform hint
    -+                n = data.readInt32();
    -+                mDebugDisableTransformHint = n ? 1 : 0;
    -+                invalidateHwcGeometry();
    -+                repaintEverything();
    -+                return NO_ERROR;
    -+            case 1010:  // interrogate.
    -+                reply->writeInt32(0);
    -+                reply->writeInt32(0);
    -+                reply->writeInt32(mDebugRegion);
    -+                reply->writeInt32(0);
    -+                reply->writeInt32(mDebugDisableHWC);
    -+                return NO_ERROR;
    -+            case 1013: {
    -+                Mutex::Autolock _l(mStateLock);
    -+                sp<const DisplayDevice> hw(getDefaultDisplayDevice());
    -+                reply->writeInt32(hw->getPageFlipCount());
    -+                return NO_ERROR;
    -+            }
    -+            case 1014: {
    -+                // daltonize
    -+                n = data.readInt32();
    -+                switch (n % 10) {
    -+                    case 1:
    -+                        mDaltonizer.setType(ColorBlindnessType::Protanomaly);
    -+                        break;
    -+                    case 2:
    -+                        mDaltonizer.setType(ColorBlindnessType::Deuteranomaly);
    -+                        break;
    -+                    case 3:
    -+                        mDaltonizer.setType(ColorBlindnessType::Tritanomaly);
    -+                        break;
    -+                }
    -+                if (n >= 10) {
    -+                    mDaltonizer.setMode(ColorBlindnessMode::Correction);
    -+                } else {
    -+                    mDaltonizer.setMode(ColorBlindnessMode::Simulation);
    -+                }
    -+                mDaltonize = n > 0;
    -+                invalidateHwcGeometry();
    -+                repaintEverything();
    -+                return NO_ERROR;
    -+            }
    -+            case 1015: {
    -+                // apply a color matrix
    -+                n = data.readInt32();
    -+                mHasColorMatrix = n ? 1 : 0;
    -+                if (n) {
    -+                    // color matrix is sent as mat3 matrix followed by vec3
    -+                    // offset, then packed into a mat4 where the last row is
    -+                    // the offset and extra values are 0
    -+                    for (size_t i = 0 ; i < 4; i++) {
    -+                      for (size_t j = 0; j < 4; j++) {
    -+                          mColorMatrix[i][j] = data.readFloat();
    -+                      }
    -+                    }
    -+                } else {
    -+                    mColorMatrix = mat4();
    -+                }
    -+                invalidateHwcGeometry();
    -+                repaintEverything();
    -+                return NO_ERROR;
    -+            }
    -+            // This is an experimental interface
    -+            // Needs to be shifted to proper binder interface when we productize
    -+            case 1016: {
    -+                n = data.readInt32();
    -+                mPrimaryDispSync.setRefreshSkipCount(n);
    -+                return NO_ERROR;
    -+            }
    -+            case 1017: {
    -+                n = data.readInt32();
    -+                mForceFullDamage = static_cast<bool>(n);
    -+                return NO_ERROR;
    -+            }
    -+            case 1018: { // Modify Choreographer's phase offset
    -+                n = data.readInt32();
    -+                mEventThread->setPhaseOffset(static_cast<nsecs_t>(n));
    -+                return NO_ERROR;
    -+            }
    -+            case 1019: { // Modify SurfaceFlinger's phase offset
    -+                n = data.readInt32();
    -+                mSFEventThread->setPhaseOffset(static_cast<nsecs_t>(n));
    -+                return NO_ERROR;
    -+            }
    -+            case 1021: { // Disable HWC virtual displays
    -+                n = data.readInt32();
    -+                mUseHwcVirtualDisplays = !n;
    -+                return NO_ERROR;
    -+            }
    -+        }
    -+    }
    -+    return err;
    -+}
    -+
    -+void SurfaceFlinger::repaintEverything() {
    -+    android_atomic_or(1, &mRepaintEverything);
    -+    signalTransaction();
    -+}
    -+
    -+// ---------------------------------------------------------------------------
    -+// Capture screen into an IGraphiBufferProducer
    -+// ---------------------------------------------------------------------------
    -+
    -+/* The code below is here to handle b/8734824
    -+ *
    -+ * We create a IGraphicBufferProducer wrapper that forwards all calls
    -+ * from the surfaceflinger thread to the calling binder thread, where they
    -+ * are executed. This allows the calling thread in the calling process to be
    -+ * reused and not depend on having "enough" binder threads to handle the
    -+ * requests.
    -+ */
    -+class GraphicProducerWrapper : public BBinder, public MessageHandler {
    -+    /* Parts of GraphicProducerWrapper are run on two different threads,
    -+     * communicating by sending messages via Looper but also by shared member
    -+     * data. Coherence maintenance is subtle and in places implicit (ugh).
    -+     *
    -+     * Don't rely on Looper's sendMessage/handleMessage providing
    -+     * release/acquire semantics for any data not actually in the Message.
    -+     * Data going from surfaceflinger to binder threads needs to be
    -+     * synchronized explicitly.
    -+     *
    -+     * Barrier open/wait do provide release/acquire semantics. This provides
    -+     * implicit synchronization for data coming back from binder to
    -+     * surfaceflinger threads.
    -+     */
    -+
    -+    sp<IGraphicBufferProducer> impl;
    -+    sp<Looper> looper;
    -+    status_t result;
    -+    bool exitPending;
    -+    bool exitRequested;
    -+    Barrier barrier;
    -+    uint32_t code;
    -+    Parcel const* data;
    -+    Parcel* reply;
    -+
    -+    enum {
    -+        MSG_API_CALL,
    -+        MSG_EXIT
    -+    };
    -+
    -+    /*
    -+     * Called on surfaceflinger thread. This is called by our "fake"
    -+     * BpGraphicBufferProducer. We package the data and reply Parcel and
    -+     * forward them to the binder thread.
    -+     */
    -+    virtual status_t transact(uint32_t code,
    -+            const Parcel& data, Parcel* reply, uint32_t /* flags */) {
    -+        this->code = code;
    -+        this->data = &data;
    -+        this->reply = reply;
    -+        if (exitPending) {
    -+            // if we've exited, we run the message synchronously right here.
    -+            // note (JH): as far as I can tell from looking at the code, this
    -+            // never actually happens. if it does, i'm not sure if it happens
    -+            // on the surfaceflinger or binder thread.
    -+            handleMessage(Message(MSG_API_CALL));
    -+        } else {
    -+            barrier.close();
    -+            // Prevent stores to this->{code, data, reply} from being
    -+            // reordered later than the construction of Message.
    -+            atomic_thread_fence(memory_order_release);
    -+            looper->sendMessage(this, Message(MSG_API_CALL));
    -+            barrier.wait();
    -+        }
    -+        return result;
    -+    }
    -+
    -+    /*
    -+     * here we run on the binder thread. All we've got to do is
    -+     * call the real BpGraphicBufferProducer.
    -+     */
    -+    virtual void handleMessage(const Message& message) {
    -+        int what = message.what;
    -+        // Prevent reads below from happening before the read from Message
    -+        atomic_thread_fence(memory_order_acquire);
    -+        if (what == MSG_API_CALL) {
    -+            result = IInterface::asBinder(impl)->transact(code, data[0], reply);
    -+            barrier.open();
    -+        } else if (what == MSG_EXIT) {
    -+            exitRequested = true;
    -+        }
    -+    }
    -+
    -+public:
    -+    GraphicProducerWrapper(const sp<IGraphicBufferProducer>& impl)
    -+    :   impl(impl),
    -+        looper(new Looper(true)),
    -+        result(NO_ERROR),
    -+        exitPending(false),
    -+        exitRequested(false),
    -+        code(0),
    -+        data(NULL),
    -+        reply(NULL)
    -+    {}
    -+
    -+    // Binder thread
    -+    status_t waitForResponse() {
    -+        do {
    -+            looper->pollOnce(-1);
    -+        } while (!exitRequested);
    -+        return result;
    -+    }
    -+
    -+    // Client thread
    -+    void exit(status_t result) {
    -+        this->result = result;
    -+        exitPending = true;
    -+        // Ensure this->result is visible to the binder thread before it
    -+        // handles the message.
    -+        atomic_thread_fence(memory_order_release);
    -+        looper->sendMessage(this, Message(MSG_EXIT));
    -+    }
    -+};
    -+
    -+
    -+status_t SurfaceFlinger::captureScreen(const sp<IBinder>& display,
    -+        const sp<IGraphicBufferProducer>& producer,
    -+        Rect sourceCrop, uint32_t reqWidth, uint32_t reqHeight,
    -+        uint32_t minLayerZ, uint32_t maxLayerZ,
    -+        bool useIdentityTransform, ISurfaceComposer::Rotation rotation,
    -+        bool useReadPixels) {
    -+
    -+    if (CC_UNLIKELY(display == 0))
    -+        return BAD_VALUE;
    -+
    -+    if (CC_UNLIKELY(producer == 0))
    -+        return BAD_VALUE;
    -+
    -+    // if we have secure windows on this display, never allow the screen capture
    -+    // unless the producer interface is local (i.e.: we can take a screenshot for
    -+    // ourselves).
    -+    bool isLocalScreenshot = IInterface::asBinder(producer)->localBinder();
    -+
    -+    // Convert to surfaceflinger's internal rotation type.
    -+    Transform::orientation_flags rotationFlags;
    -+    switch (rotation) {
    -+        case ISurfaceComposer::eRotateNone:
    -+            rotationFlags = Transform::ROT_0;
    -+            break;
    -+        case ISurfaceComposer::eRotate90:
    -+            rotationFlags = Transform::ROT_90;
    -+            break;
    -+        case ISurfaceComposer::eRotate180:
    -+            rotationFlags = Transform::ROT_180;
    -+            break;
    -+        case ISurfaceComposer::eRotate270:
    -+            rotationFlags = Transform::ROT_270;
    -+            break;
    -+        default:
    -+            rotationFlags = Transform::ROT_0;
    -+            ALOGE("Invalid rotation passed to captureScreen(): %d\n", rotation);
    -+            break;
    -+    }
    -+
    -+    class MessageCaptureScreen : public MessageBase {
    -+        SurfaceFlinger* flinger;
    -+        sp<IBinder> display;
    -+        sp<IGraphicBufferProducer> producer;
    -+        Rect sourceCrop;
    -+        uint32_t reqWidth, reqHeight;
    -+        uint32_t minLayerZ,maxLayerZ;
    -+        bool useIdentityTransform;
    -+        Transform::orientation_flags rotation;
    -+        status_t result;
    -+        bool useReadPixels;
    -+        bool isLocalScreenshot;
    -+    public:
    -+        MessageCaptureScreen(SurfaceFlinger* flinger,
    -+                const sp<IBinder>& display,
    -+                const sp<IGraphicBufferProducer>& producer,
    -+                Rect sourceCrop, uint32_t reqWidth, uint32_t reqHeight,
    -+                uint32_t minLayerZ, uint32_t maxLayerZ,
    -+                bool useIdentityTransform,
    -+                Transform::orientation_flags rotation,
    -+                bool isLocalScreenshot, bool useReadPixels)
    -+            : flinger(flinger), display(display), producer(producer),
    -+              sourceCrop(sourceCrop), reqWidth(reqWidth), reqHeight(reqHeight),
    -+              minLayerZ(minLayerZ), maxLayerZ(maxLayerZ),
    -+              useIdentityTransform(useIdentityTransform),
    -+              rotation(rotation), result(PERMISSION_DENIED),
    -+              useReadPixels(useReadPixels),
    -+              isLocalScreenshot(isLocalScreenshot)
    -+        {
    -+        }
    -+        status_t getResult() const {
    -+            return result;
    -+        }
    -+        virtual bool handler() {
    -+            Mutex::Autolock _l(flinger->mStateLock);
    -+            sp<const DisplayDevice> hw(flinger->getDisplayDevice(display));
    -+            bool useReadPixels = this->useReadPixels && !flinger->mGpuToCpuSupported;
    -+            result = flinger->captureScreenImplLocked(hw, producer,
    -+                    sourceCrop, reqWidth, reqHeight, minLayerZ, maxLayerZ,
    -+                    useIdentityTransform, rotation, isLocalScreenshot, useReadPixels);
    -+            static_cast<GraphicProducerWrapper*>(IInterface::asBinder(producer).get())->exit(result);
    -+            return true;
    -+        }
    -+    };
    -+
    -+    // this creates a "fake" BBinder which will serve as a "fake" remote
    -+    // binder to receive the marshaled calls and forward them to the
    -+    // real remote (a BpGraphicBufferProducer)
    -+    sp<GraphicProducerWrapper> wrapper = new GraphicProducerWrapper(producer);
    -+
    -+    // the asInterface() call below creates our "fake" BpGraphicBufferProducer
    -+    // which does the marshaling work forwards to our "fake remote" above.
    -+    sp<MessageBase> msg = new MessageCaptureScreen(this,
    -+            display, IGraphicBufferProducer::asInterface( wrapper ),
    -+            sourceCrop, reqWidth, reqHeight, minLayerZ, maxLayerZ,
    -+            useIdentityTransform, rotationFlags, isLocalScreenshot, useReadPixels);
    -+
    -+    status_t res = postMessageAsync(msg);
    -+    if (res == NO_ERROR) {
    -+        res = wrapper->waitForResponse();
    -+    }
    -+    return res;
    -+}
    -+
    -+
    -+void SurfaceFlinger::renderScreenImplLocked(
    -+        const sp<const DisplayDevice>& hw,
    -+        Rect sourceCrop, uint32_t reqWidth, uint32_t reqHeight,
    -+        uint32_t minLayerZ, uint32_t maxLayerZ,
    -+        bool yswap, bool useIdentityTransform, Transform::orientation_flags rotation)
    -+{
    -+    ATRACE_CALL();
    -+    RenderEngine& engine(getRenderEngine());
    -+
    -+    // get screen geometry
    -+    const int32_t hw_w = hw->getWidth();
    -+    const int32_t hw_h = hw->getHeight();
    -+    const bool filtering = static_cast<int32_t>(reqWidth) != hw_w ||
    -+                           static_cast<int32_t>(reqHeight) != hw_h;
    -+
    -+    // if a default or invalid sourceCrop is passed in, set reasonable values
    -+    if (sourceCrop.width() == 0 || sourceCrop.height() == 0 ||
    -+            !sourceCrop.isValid()) {
    -+        sourceCrop.setLeftTop(Point(0, 0));
    -+        sourceCrop.setRightBottom(Point(hw_w, hw_h));
    -+    }
    -+
    -+    // ensure that sourceCrop is inside screen
    -+    if (sourceCrop.left < 0) {
    -+        ALOGE("Invalid crop rect: l = %d (< 0)", sourceCrop.left);
    -+    }
    -+    if (sourceCrop.right > hw_w) {
    -+        ALOGE("Invalid crop rect: r = %d (> %d)", sourceCrop.right, hw_w);
    -+    }
    -+    if (sourceCrop.top < 0) {
    -+        ALOGE("Invalid crop rect: t = %d (< 0)", sourceCrop.top);
    -+    }
    -+    if (sourceCrop.bottom > hw_h) {
    -+        ALOGE("Invalid crop rect: b = %d (> %d)", sourceCrop.bottom, hw_h);
    -+    }
    -+
    -+    // make sure to clear all GL error flags
    -+    engine.checkErrors();
    -+
    -+    // set-up our viewport
    -+    engine.setViewportAndProjection(
    -+        reqWidth, reqHeight, sourceCrop, hw_h, yswap, rotation);
    -+    engine.disableTexturing();
    -+
    -+    // redraw the screen entirely...
    -+    engine.clearWithColor(0, 0, 0, 1);
    -+
    -+    const LayerVector& layers( mDrawingState.layersSortedByZ );
    -+    const size_t count = layers.size();
    -+    for (size_t i=0 ; i<count ; ++i) {
    -+        const sp<Layer>& layer(layers[i]);
    -+        const Layer::State& state(layer->getDrawingState());
    -+        if (state.layerStack == hw->getLayerStack()) {
    -+            if (state.z >= minLayerZ && state.z <= maxLayerZ) {
    -+                if (layer->isVisible()) {
    -+                    if (filtering) layer->setFiltering(true);
    -+                    layer->draw(hw, useIdentityTransform);
    -+                    if (filtering) layer->setFiltering(false);
    -+                }
    -+            }
    -+        }
    -+    }
    -+
    -+    // compositionComplete is needed for older driver
    -+    hw->compositionComplete();
    -+    hw->setViewportAndProjection();
    -+}
    -+
    -+
    -+status_t SurfaceFlinger::captureScreenImplLocked(
    -+        const sp<const DisplayDevice>& hw,
    -+        const sp<IGraphicBufferProducer>& producer,
    -+        Rect sourceCrop, uint32_t reqWidth, uint32_t reqHeight,
    -+        uint32_t minLayerZ, uint32_t maxLayerZ,
    -+        bool useIdentityTransform, Transform::orientation_flags rotation,
    -+        bool isLocalScreenshot, bool useReadPixels)
    -+{
    -+    ATRACE_CALL();
    -+
    -+    // get screen geometry
    -+    uint32_t hw_w = hw->getWidth();
    -+    uint32_t hw_h = hw->getHeight();
    -+
    -+    if (rotation & Transform::ROT_90) {
    -+        std::swap(hw_w, hw_h);
    -+    }
    -+
    -+    if ((reqWidth > hw_w) || (reqHeight > hw_h)) {
    -+        ALOGE("size mismatch (%d, %d) > (%d, %d)",
    -+                reqWidth, reqHeight, hw_w, hw_h);
    -+        return BAD_VALUE;
    -+    }
    -+
    -+    reqWidth  = (!reqWidth)  ? hw_w : reqWidth;
    -+    reqHeight = (!reqHeight) ? hw_h : reqHeight;
    -+
    -+    bool secureLayerIsVisible = false;
    -+    const LayerVector& layers(mDrawingState.layersSortedByZ);
    -+    const size_t count = layers.size();
    -+    for (size_t i = 0 ; i < count ; ++i) {
    -+        const sp<Layer>& layer(layers[i]);
    -+        const Layer::State& state(layer->getDrawingState());
    -+        if (state.layerStack == hw->getLayerStack() && state.z >= minLayerZ &&
    -+                state.z <= maxLayerZ && layer->isVisible() &&
    -+                layer->isSecure()) {
    -+            secureLayerIsVisible = true;
    -+        }
    -+    }
    -+
    -+    if (!isLocalScreenshot && secureLayerIsVisible) {
    -+        ALOGW("FB is protected: PERMISSION_DENIED");
    -+        return PERMISSION_DENIED;
    -+    }
    -+
    -+    // create a surface (because we're a producer, and we need to
    -+    // dequeue/queue a buffer)
    -+    sp<Surface> sur = new Surface(producer, false);
    -+    ANativeWindow* window = sur.get();
    -+
    -+    status_t result = native_window_api_connect(window, NATIVE_WINDOW_API_EGL);
    -+    if (result == NO_ERROR) {
    -+        uint32_t usage = GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN |
    -+                        GRALLOC_USAGE_HW_RENDER | GRALLOC_USAGE_HW_TEXTURE;
    -+
    -+        int err = 0;
    -+        err = native_window_set_buffers_dimensions(window, reqWidth, reqHeight);
    -+        err |= native_window_set_scaling_mode(window, NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW);
    -+        err |= native_window_set_buffers_format(window, HAL_PIXEL_FORMAT_RGBA_8888);
    -+        err |= native_window_set_usage(window, usage);
    -+
    -+        if (err == NO_ERROR) {
    -+            ANativeWindowBuffer* buffer;
    -+            /* TODO: Once we have the sync framework everywhere this can use
    -+             * server-side waits on the fence that dequeueBuffer returns.
    -+             */
    -+            result = native_window_dequeue_buffer_and_wait(window,  &buffer);
    -+            if (result == NO_ERROR) {
    -+                int syncFd = -1;
    -+                // create an EGLImage from the buffer so we can later
    -+                // turn it into a texture
    -+                EGLImageKHR image = eglCreateImageKHR(mEGLDisplay, EGL_NO_CONTEXT,
    -+                        EGL_NATIVE_BUFFER_ANDROID, buffer, NULL);
    -+                if (image != EGL_NO_IMAGE_KHR) {
    -+                    // this binds the given EGLImage as a framebuffer for the
    -+                    // duration of this scope.
    -+                    RenderEngine::BindImageAsFramebuffer imageBond(getRenderEngine(), image, useReadPixels, reqWidth, reqHeight);
    -+                    if (imageBond.getStatus() == NO_ERROR) {
    -+                        // this will in fact render into our dequeued buffer
    -+                        // via an FBO, which means we didn't have to create
    -+                        // an EGLSurface and therefore we're not
    -+                        // dependent on the context's EGLConfig.
    -+                        renderScreenImplLocked(
    -+                            hw, sourceCrop, reqWidth, reqHeight, minLayerZ, maxLayerZ, true,
    -+                            useIdentityTransform, rotation);
    -+
    -+                        // Attempt to create a sync khr object that can produce a sync point. If that
    -+                        // isn't available, create a non-dupable sync object in the fallback path and
    -+                        // wait on it directly.
    -+                        EGLSyncKHR sync;
    -+                        if (!DEBUG_SCREENSHOTS) {
    -+                           sync = eglCreateSyncKHR(mEGLDisplay, EGL_SYNC_NATIVE_FENCE_ANDROID, NULL);
    -+                           // native fence fd will not be populated until flush() is done.
    -+                           getRenderEngine().flush();
    -+                        } else {
    -+                            sync = EGL_NO_SYNC_KHR;
    -+                        }
    -+                        if (sync != EGL_NO_SYNC_KHR) {
    -+                            // get the sync fd
    -+                            syncFd = eglDupNativeFenceFDANDROID(mEGLDisplay, sync);
    -+                            if (syncFd == EGL_NO_NATIVE_FENCE_FD_ANDROID) {
    -+                                ALOGW("captureScreen: failed to dup sync khr object");
    -+                                syncFd = -1;
    -+                            }
    -+                            eglDestroySyncKHR(mEGLDisplay, sync);
    -+                        } else {
    -+                            // fallback path
    -+                            sync = eglCreateSyncKHR(mEGLDisplay, EGL_SYNC_FENCE_KHR, NULL);
    -+                            if (sync != EGL_NO_SYNC_KHR) {
    -+                                EGLint result = eglClientWaitSyncKHR(mEGLDisplay, sync,
    -+                                    EGL_SYNC_FLUSH_COMMANDS_BIT_KHR, 2000000000 /*2 sec*/);
    -+                                EGLint eglErr = eglGetError();
    -+                                if (result == EGL_TIMEOUT_EXPIRED_KHR) {
    -+                                    ALOGW("captureScreen: fence wait timed out");
    -+                                } else {
    -+                                    ALOGW_IF(eglErr != EGL_SUCCESS,
    -+                                            "captureScreen: error waiting on EGL fence: %#x", eglErr);
    -+                                }
    -+                                eglDestroySyncKHR(mEGLDisplay, sync);
    -+                            } else {
    -+                                ALOGW("captureScreen: error creating EGL fence: %#x", eglGetError());
    -+                            }
    -+                        }
    -+
    -+                        if (useReadPixels) {
    -+                            sp<GraphicBuffer> buf = static_cast<GraphicBuffer*>(buffer);
    -+                            void* vaddr;
    -+                            if (buf->lock(GRALLOC_USAGE_SW_WRITE_OFTEN, &vaddr) == NO_ERROR) {
    -+                                getRenderEngine().readPixels(0, 0, buffer->stride, reqHeight, (uint32_t *)vaddr);
    -+                                buf->unlock();
    -+                            }
    -+                        }
    -+
    -+                        if (DEBUG_SCREENSHOTS) {
    -+                            uint32_t* pixels = new uint32_t[reqWidth*reqHeight];
    -+                            getRenderEngine().readPixels(0, 0, reqWidth, reqHeight, pixels);
    -+                            checkScreenshot(reqWidth, reqHeight, reqWidth, pixels,
    -+                                    hw, minLayerZ, maxLayerZ);
    -+                            delete [] pixels;
    -+                        }
    -+
    -+                    } else {
    -+                        ALOGE("got GL_FRAMEBUFFER_COMPLETE_OES error while taking screenshot");
    -+                        result = INVALID_OPERATION;
    -+                        window->cancelBuffer(window, buffer, syncFd);
    -+                        buffer = NULL;
    -+                    }
    -+                    // destroy our image
    -+                    eglDestroyImageKHR(mEGLDisplay, image);
    -+                } else {
    -+                    result = BAD_VALUE;
    -+                }
    -+                if (buffer) {
    -+                    // queueBuffer takes ownership of syncFd
    -+                    result = window->queueBuffer(window, buffer, syncFd);
    -+                }
    -+            }
    -+        } else {
    -+            result = BAD_VALUE;
    -+        }
    -+        native_window_api_disconnect(window, NATIVE_WINDOW_API_EGL);
    -+    }
    -+
    -+    return result;
    -+}
    -+
    -+bool SurfaceFlinger::getFrameTimestamps(const Layer& layer,
    -+        uint64_t frameNumber, FrameTimestamps* outTimestamps) {
    -+    return mFenceTracker.getFrameTimestamps(layer, frameNumber, outTimestamps);
    -+}
    -+
    -+void SurfaceFlinger::checkScreenshot(size_t w, size_t s, size_t h, void const* vaddr,
    -+        const sp<const DisplayDevice>& hw, uint32_t minLayerZ, uint32_t maxLayerZ) {
    -+    if (DEBUG_SCREENSHOTS) {
    -+        for (size_t y=0 ; y<h ; y++) {
    -+            uint32_t const * p = (uint32_t const *)vaddr + y*s;
    -+            for (size_t x=0 ; x<w ; x++) {
    -+                if (p[x] != 0xFF000000) return;
    -+            }
    -+        }
    -+        ALOGE("*** we just took a black screenshot ***\n"
    -+                "requested minz=%d, maxz=%d, layerStack=%d",
    -+                minLayerZ, maxLayerZ, hw->getLayerStack());
    -+        const LayerVector& layers( mDrawingState.layersSortedByZ );
    -+        const size_t count = layers.size();
    -+        for (size_t i=0 ; i<count ; ++i) {
    -+            const sp<Layer>& layer(layers[i]);
    -+            const Layer::State& state(layer->getDrawingState());
    -+            const bool visible = (state.layerStack == hw->getLayerStack())
    -+                                && (state.z >= minLayerZ && state.z <= maxLayerZ)
    -+                                && (layer->isVisible());
    -+            ALOGE("%c index=%zu, name=%s, layerStack=%d, z=%d, visible=%d, flags=%x, alpha=%x",
    -+                    visible ? '+' : '-',
    -+                            i, layer->getName().string(), state.layerStack, state.z,
    -+                            layer->isVisible(), state.flags, state.alpha);
    -+        }
    -+    }
    -+}
    -+
    -+// ---------------------------------------------------------------------------
    -+
    -+SurfaceFlinger::LayerVector::LayerVector() {
    -+}
    -+
    -+SurfaceFlinger::LayerVector::LayerVector(const LayerVector& rhs)
    -+    : SortedVector<sp<Layer> >(rhs) {
    -+}
    -+
    -+int SurfaceFlinger::LayerVector::do_compare(const void* lhs,
    -+    const void* rhs) const
    -+{
    -+    // sort layers per layer-stack, then by z-order and finally by sequence
    -+    const sp<Layer>& l(*reinterpret_cast<const sp<Layer>*>(lhs));
    -+    const sp<Layer>& r(*reinterpret_cast<const sp<Layer>*>(rhs));
    -+
    -+    uint32_t ls = l->getCurrentState().layerStack;
    -+    uint32_t rs = r->getCurrentState().layerStack;
    -+    if (ls != rs)
    -+        return ls - rs;
    -+
    -+    uint32_t lz = l->getCurrentState().z;
    -+    uint32_t rz = r->getCurrentState().z;
    -+    if (lz != rz)
    -+        return lz - rz;
    -+
    -+    return l->sequence - r->sequence;
    -+}
    -+
    -+// ---------------------------------------------------------------------------
    -+
    -+SurfaceFlinger::DisplayDeviceState::DisplayDeviceState()
    -+    : type(DisplayDevice::DISPLAY_ID_INVALID),
    -+      layerStack(DisplayDevice::NO_LAYER_STACK),
    -+      orientation(0),
    -+      width(0),
    -+      height(0),
    -+      isSecure(false) {
    -+}
    -+
    -+SurfaceFlinger::DisplayDeviceState::DisplayDeviceState(
    -+    DisplayDevice::DisplayType type, bool isSecure)
    -+    : type(type),
    -+      layerStack(DisplayDevice::NO_LAYER_STACK),
    -+      orientation(0),
    -+      width(0),
    -+      height(0),
    -+      isSecure(isSecure) {
    -+    viewport.makeInvalid();
    -+    frame.makeInvalid();
    -+}
    -+
    -+// ---------------------------------------------------------------------------
    -+
    -+}; // namespace android
    -+
    -+
    -+#if defined(__gl_h_)
    -+#error "don't include gl/gl.h in this file"
    -+#endif
    -+
    -+#if defined(__gl2_h_)
    -+#error "don't include gl2/gl2.h in this file"
    -+#endif
    diff --git a/system_core.patch b/system_core.patch
    index 6a071bd..52b8f46 100644
    --- a/system_core.patch
    +++ b/system_core.patch
    @@ -182,10 +182,10 @@ index 84da2b9..dc3be38 100644
          am.QueueBuiltinAction(console_init_action, "console_init");
      
     diff --git a/rootdir/init.rc b/rootdir/init.rc
    -index a9b6af0..7a5c9b3 100644
    +index a22d5c1..90d4ae0 100644
     --- a/rootdir/init.rc
     +++ b/rootdir/init.rc
    -@@ -668,6 +668,6 @@ on property:ro.debuggable=1
    +@@ -664,6 +664,6 @@ on property:ro.debuggable=1
          chmod 0773 /data/misc/trace
          start console
      
    
    From bb7694367769da3269cd31b2de40fb50b49694aa Mon Sep 17 00:00:00 2001
    From: AndDiSa <anddisa@googlemail.com>
    Date: Tue, 7 Mar 2017 18:56:58 +0100
    Subject: [PATCH 065/159] update to android-7.1.1_r25
    
    Change-Id: Ic92a72ac224c5d0f92b281706cc663c84a8deda0
    ---
     default.xml | 2 +-
     1 file changed, 1 insertion(+), 1 deletion(-)
    
    diff --git a/default.xml b/default.xml
    index c9aaee6..de9f558 100644
    --- a/default.xml
    +++ b/default.xml
    @@ -9,7 +9,7 @@
                fetch="https://github.com/millosr/" />
       <remote  name="unlegacy"
                fetch="https://github.com/Unlegacy-Android/" />
    -  <default revision="refs/tags/android-7.1.1_r20"
    +  <default revision="refs/tags/android-7.1.1_r25"
                remote="aosp"
                sync-j="4" />
     
    
    From b820052f549b9314ee40c5b3a7d6d0e550e43f07 Mon Sep 17 00:00:00 2001
    From: AndDiSa <anddisa@googlemail.com>
    Date: Wed, 8 Mar 2017 21:37:31 +0100
    Subject: [PATCH 066/159] update patches
    
    Change-Id: Ic647ef5da112d4329c814ede14904d5f67dee627
    ---
     build.patch             |  17 +
     frameworks_av.patch     | 100 +++++-
     frameworks_base.patch   |  20 +-
     frameworks_native.patch | 708 +++++++++++++++++++++++++++++++++++++++-
     4 files changed, 810 insertions(+), 35 deletions(-)
    
    diff --git a/build.patch b/build.patch
    index d8aad41..074d519 100644
    --- a/build.patch
    +++ b/build.patch
    @@ -889,3 +889,20 @@ index 0000000..2c8a21f
     +  # anyone trying to parse it as an integer will probably get "0".
     +  BUILD_NUMBER := eng.$(shell echo $${USER:0:6}).$(shell $(DATE) +%Y%m%d.%H%M%S)
     +endif
    +diff --git a/target/product/core.mk b/target/product/core.mk
    +index 0a4e0fd..5508c12 100644
    +--- a/target/product/core.mk
    ++++ b/target/product/core.mk
    +@@ -1,3 +1,4 @@
    ++
    + #
    + # Copyright (C) 2007 The Android Open Source Project
    + #
    +@@ -55,7 +56,6 @@ PRODUCT_PACKAGES += \
    +     SharedStorageBackup \
    +     StorageManager \
    +     Telecom \
    +-    TeleService \
    +     VpnDialogs \
    +     MmsService
    + 
    diff --git a/frameworks_av.patch b/frameworks_av.patch
    index 05d7c91..97781f3 100644
    --- a/frameworks_av.patch
    +++ b/frameworks_av.patch
    @@ -1,3 +1,38 @@
    +diff --git a/camera/ICameraClient.cpp b/camera/ICameraClient.cpp
    +index 68cbfb8..8a7430f 100644
    +--- a/camera/ICameraClient.cpp
    ++++ b/camera/ICameraClient.cpp
    +@@ -50,7 +50,12 @@ public:
    +         data.writeInterfaceToken(ICameraClient::getInterfaceDescriptor());
    +         data.writeInt32(msgType);
    +         data.writeInt32(ext1);
    +-        data.writeInt32(ext2);
    ++        if ((msgType == CAMERA_MSG_PREVIEW_FRAME) && (ext1 == CAMERA_FRAME_DATA_FD)) {
    ++            ALOGD("notifyCallback: CAMERA_MSG_PREVIEW_FRAME fd = %d", ext2);
    ++            data.writeFileDescriptor(ext2);
    ++        } else {
    ++            data.writeInt32(ext2);
    ++        }
    +         remote()->transact(NOTIFY_CALLBACK, data, &reply, IBinder::FLAG_ONEWAY);
    +     }
    + 
    +@@ -105,8 +110,14 @@ status_t BnCameraClient::onTransact(
    +             ALOGV("NOTIFY_CALLBACK");
    +             CHECK_INTERFACE(ICameraClient, data, reply);
    +             int32_t msgType = data.readInt32();
    +-            int32_t ext1 = data.readInt32();
    +-            int32_t ext2 = data.readInt32();
    ++            int32_t ext1    = data.readInt32();
    ++            int32_t ext2    = 0;
    ++            if ((msgType == CAMERA_MSG_PREVIEW_FRAME) && (ext1 == CAMERA_FRAME_DATA_FD)) {
    ++                ext2 = data.readFileDescriptor();
    ++                ALOGD("onTransact: CAMERA_MSG_PREVIEW_FRAME fd = %d", ext2);
    ++            } else {
    ++                ext2 = data.readInt32();
    ++            }
    +             notifyCallback(msgType, ext1, ext2);
    +             return NO_ERROR;
    +         } break;
     diff --git a/camera/cameraserver/Android.mk b/camera/cameraserver/Android.mk
     index 7e36c5e..aca7a19 100644
     --- a/camera/cameraserver/Android.mk
    @@ -17,6 +52,40 @@ index 7e36c5e..aca7a19 100644
      
      include $(BUILD_EXECUTABLE)
     +endif
    +diff --git a/camera/ndk/NdkCaptureRequest.cpp b/camera/ndk/NdkCaptureRequest.cpp
    +index 77b9a33..7c37955 100644
    +--- a/camera/ndk/NdkCaptureRequest.cpp
    ++++ b/camera/ndk/NdkCaptureRequest.cpp
    +@@ -51,8 +51,13 @@ camera_status_t ACaptureRequest_addTarget(
    +         ACaptureRequest* req, const ACameraOutputTarget* target) {
    +     ATRACE_CALL();
    +     if (req == nullptr || req->targets == nullptr || target == nullptr) {
    ++        void* req_targets;
    ++        if (req != nullptr)
    ++            req_targets = req->targets;
    ++        else
    ++            req_targets = nullptr;
    +         ALOGE("%s: Error: invalid input: req %p, req-targets %p, target %p",
    +-                __FUNCTION__, req, req->targets, target);
    ++                __FUNCTION__, req, req_targets, target);
    +         return ACAMERA_ERROR_INVALID_PARAMETER;
    +     }
    +     auto pair = req->targets->mOutputs.insert(*target);
    +@@ -67,8 +72,13 @@ camera_status_t ACaptureRequest_removeTarget(
    +         ACaptureRequest* req, const ACameraOutputTarget* target) {
    +     ATRACE_CALL();
    +     if (req == nullptr || req->targets == nullptr || target == nullptr) {
    ++        void* req_targets;
    ++        if (req != nullptr)
    ++            req_targets = req->targets;
    ++        else
    ++            req_targets = nullptr;
    +         ALOGE("%s: Error: invalid input: req %p, req-targets %p, target %p",
    +-                __FUNCTION__, req, req->targets, target);
    ++                __FUNCTION__, req, req_targets, target);
    +         return ACAMERA_ERROR_INVALID_PARAMETER;
    +     }
    +     req->targets->mOutputs.erase(*target);
     diff --git a/include/media/stagefright/MediaBufferGroup.h b/include/media/stagefright/MediaBufferGroup.h
     index 3051406..870bb9b 100644
     --- a/include/media/stagefright/MediaBufferGroup.h
    @@ -257,21 +326,6 @@ index a17757a..f1ad5c5 100644
     +}
     +}
      }  // namespace android
    -diff --git a/media/libstagefright/SampleTable.cpp b/media/libstagefright/SampleTable.cpp
    -index eb1f193..770681a 100644
    ---- a/media/libstagefright/SampleTable.cpp
    -+++ b/media/libstagefright/SampleTable.cpp
    -@@ -567,6 +567,10 @@ status_t SampleTable::setSyncSampleParams(off64_t data_offset, size_t data_size)
    -     }
    - 
    -     for (size_t i = 0; i < mNumSyncSamples; ++i) {
    -+        if (mSyncSamples[i] == 0) {
    -+            ALOGE("b/32423862, unexpected zero value in stss");
    -+            continue;
    -+        }
    -         mSyncSamples[i] = ntohl(mSyncSamples[i]) - 1;
    -     }
    - 
     diff --git a/media/libstagefright/StagefrightMetadataRetriever.cpp b/media/libstagefright/StagefrightMetadataRetriever.cpp
     index be5067d..2fef7ca 100644
     --- a/media/libstagefright/StagefrightMetadataRetriever.cpp
    @@ -560,7 +614,7 @@ index ecddc48..0abe6ac 100644
          ProcessState::self()->startThreadPool();
          IPCThreadState::self()->joinThreadPool();
     diff --git a/services/audioflinger/AudioFlinger.cpp b/services/audioflinger/AudioFlinger.cpp
    -index 1785a03..d5499f0 100644
    +index fec3a57..a0ef28c 100644
     --- a/services/audioflinger/AudioFlinger.cpp
     +++ b/services/audioflinger/AudioFlinger.cpp
     @@ -1509,7 +1509,8 @@ sp<IAudioRecord> AudioFlinger::openRecord(
    @@ -573,8 +627,20 @@ index 1785a03..d5499f0 100644
              ALOGE("openRecord() permission denied: recording not allowed");
              lStatus = PERMISSION_DENIED;
              goto Exit;
    +diff --git a/services/audiopolicy/common/managerdefinitions/src/Serializer.cpp b/services/audiopolicy/common/managerdefinitions/src/Serializer.cpp
    +index 3e5bb7d..2ecd6b1 100644
    +--- a/services/audiopolicy/common/managerdefinitions/src/Serializer.cpp
    ++++ b/services/audiopolicy/common/managerdefinitions/src/Serializer.cpp
    +@@ -383,6 +383,7 @@ status_t RouteTraits::deserialize(_xmlDoc */*doc*/, const _xmlNode *root, PtrEle
    +             sp<AudioPort> source = ctx->findPortByTagName(String8(devTag));
    +             if (source == NULL) {
    +                 ALOGE("%s: no source found with name=%s", __FUNCTION__, devTag);
    ++                free(sourcesLiteral);
    +                 return BAD_VALUE;
    +             }
    +             sources.add(source);
     diff --git a/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp b/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp
    -index c9b3abc..57d26e6 100644
    +index a75e3dd..67bacd1 100644
     --- a/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp
     +++ b/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp
     @@ -318,7 +318,7 @@ status_t AudioPolicyService::getInputForAttr(const audio_attributes_t *attr,
    diff --git a/frameworks_base.patch b/frameworks_base.patch
    index 8cac5a1..81dfa63 100644
    --- a/frameworks_base.patch
    +++ b/frameworks_base.patch
    @@ -229,7 +229,7 @@ index 5f59e32..23172a2 100644
                      // this request
                      if (VDBG) {
     diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
    -index bc9d58e..d2dc0d0 100644
    +index bc9d58e..9ed5af9 100644
     --- a/services/core/java/com/android/server/am/ActivityManagerService.java
     +++ b/services/core/java/com/android/server/am/ActivityManagerService.java
     @@ -9590,7 +9590,7 @@ public final class ActivityManagerService extends ActivityManagerNative
    @@ -241,7 +241,15 @@ index bc9d58e..d2dc0d0 100644
                      pr.kill("remove task", true);
                  } else {
                      // We delay killing processes that are not in the background or running a receiver.
    -@@ -19204,26 +19204,28 @@ public final class ActivityManagerService extends ActivityManagerNative
    +@@ -16933,6 +16933,7 @@ public final class ActivityManagerService extends ActivityManagerNative
    + 
    +         app.crashing = false;
    +         app.notResponding = false;
    ++        app.renderThreadTid = 0;
    + 
    +         app.resetPackageList(mProcessStats);
    +         app.unlinkDeathRecipient();
    +@@ -19204,26 +19205,28 @@ public final class ActivityManagerService extends ActivityManagerNative
          // LIFETIME MANAGEMENT
          // =========================================================
      
    @@ -284,7 +292,7 @@ index bc9d58e..d2dc0d0 100644
          }
      
          Association startAssociationLocked(int sourceUid, String sourceProcess, int sourceState,
    -@@ -19390,7 +19392,7 @@ public final class ActivityManagerService extends ActivityManagerNative
    +@@ -19390,7 +19393,7 @@ public final class ActivityManagerService extends ActivityManagerNative
              int schedGroup;
              int procState;
              boolean foregroundActivities = false;
    @@ -293,7 +301,7 @@ index bc9d58e..d2dc0d0 100644
              if (app == TOP_APP) {
                  // The last app on the list is the foreground app.
                  adj = ProcessList.FOREGROUND_APP_ADJ;
    -@@ -19404,13 +19406,13 @@ public final class ActivityManagerService extends ActivityManagerNative
    +@@ -19404,13 +19407,13 @@ public final class ActivityManagerService extends ActivityManagerNative
                  schedGroup = ProcessList.SCHED_GROUP_DEFAULT;
                  app.adjType = "instrumentation";
                  procState = ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE;
    @@ -309,7 +317,7 @@ index bc9d58e..d2dc0d0 100644
                          ? ProcessList.SCHED_GROUP_DEFAULT : ProcessList.SCHED_GROUP_BACKGROUND;
                  app.adjType = "broadcast";
                  procState = ActivityManager.PROCESS_STATE_RECEIVER;
    -@@ -20421,7 +20423,7 @@ public final class ActivityManagerService extends ActivityManagerNative
    +@@ -20421,7 +20424,7 @@ public final class ActivityManagerService extends ActivityManagerNative
                  if (DEBUG_SWITCH || DEBUG_OOM_ADJ) Slog.v(TAG_OOM_ADJ,
                          "Setting sched group of " + app.processName
                          + " to " + app.curSchedGroup);
    @@ -318,7 +326,7 @@ index bc9d58e..d2dc0d0 100644
                          && app.setSchedGroup == ProcessList.SCHED_GROUP_BACKGROUND) {
                      app.kill(app.waitingToKill, true);
                      success = false;
    -@@ -21361,7 +21363,7 @@ public final class ActivityManagerService extends ActivityManagerNative
    +@@ -21361,7 +21364,7 @@ public final class ActivityManagerService extends ActivityManagerNative
                  for (i=mRemovedProcesses.size()-1; i>=0; i--) {
                      final ProcessRecord app = mRemovedProcesses.get(i);
                      if (app.activities.size() == 0
    diff --git a/frameworks_native.patch b/frameworks_native.patch
    index 617194a..113c81d 100644
    --- a/frameworks_native.patch
    +++ b/frameworks_native.patch
    @@ -63,6 +63,29 @@ index ddf3aa8..5c04f6c 100644
              return false;
          }
          delete[] src;
    +diff --git a/cmds/installd/commands.cpp b/cmds/installd/commands.cpp
    +index 271c75b..cadcd1e 100644
    +--- a/cmds/installd/commands.cpp
    ++++ b/cmds/installd/commands.cpp
    +@@ -238,11 +238,15 @@ int migrate_app_data(const char *uuid, const char *pkgname, userid_t userid, int
    +     auto ce_path = create_data_user_ce_package_path(uuid, userid, pkgname);
    +     auto de_path = create_data_user_de_package_path(uuid, userid, pkgname);
    + 
    +-    // If neither directory is marked as default, assume CE is default
    ++    // If neither directory is marked as default, use DE if requested by
    ++    // the app (and it exists), otherwise assume CE.
    +     if (getxattr(ce_path.c_str(), kXattrDefault, nullptr, 0) == -1
    +             && getxattr(de_path.c_str(), kXattrDefault, nullptr, 0) == -1) {
    +-        if (setxattr(ce_path.c_str(), kXattrDefault, nullptr, 0, 0) != 0) {
    +-            PLOG(ERROR) << "Failed to mark default storage " << ce_path;
    ++        struct stat s;
    ++        const char *data_path = (flags & FLAG_STORAGE_DE) && !stat(de_path.c_str(), &s)
    ++                ? de_path.c_str() : ce_path.c_str();
    ++        if (setxattr(data_path, kXattrDefault, nullptr, 0, 0) != 0) {
    ++            PLOG(ERROR) << "Failed to mark default storage " << data_path;
    +             return -1;
    +         }
    +     }
     diff --git a/include/gui/ISurfaceComposer.h b/include/gui/ISurfaceComposer.h
     index 74a4123..8dc6f6a 100644
     --- a/include/gui/ISurfaceComposer.h
    @@ -90,6 +113,114 @@ index 74a4123..8dc6f6a 100644
      
          /* Clears the frame statistics for animations.
           *
    +diff --git a/include/ui/FramebufferNativeWindow.h b/include/ui/FramebufferNativeWindow.h
    +new file mode 100644
    +index 0000000..2eb1cc1
    +--- /dev/null
    ++++ b/include/ui/FramebufferNativeWindow.h
    +@@ -0,0 +1,102 @@
    ++/*
    ++ * Copyright (C) 2007 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.
    ++ */
    ++
    ++#ifndef INCLUDED_FROM_FRAMEBUFFER_NATIVE_WINDOW_CPP
    ++//#warning "FramebufferNativeWindow is deprecated"
    ++#endif
    ++
    ++#ifndef ANDROID_FRAMEBUFFER_NATIVE_WINDOW_H
    ++#define ANDROID_FRAMEBUFFER_NATIVE_WINDOW_H
    ++
    ++#include <stdint.h>
    ++#include <sys/types.h>
    ++
    ++#include <EGL/egl.h>
    ++
    ++#include <utils/threads.h>
    ++#include <utils/String8.h>
    ++
    ++#include <ui/ANativeObjectBase.h>
    ++#include <ui/Rect.h>
    ++
    ++#define MIN_NUM_FRAME_BUFFERS  2
    ++#define MAX_NUM_FRAME_BUFFERS  3
    ++
    ++extern "C" EGLNativeWindowType android_createDisplaySurface(void);
    ++
    ++// ---------------------------------------------------------------------------
    ++namespace android {
    ++// ---------------------------------------------------------------------------
    ++
    ++class Surface;
    ++class NativeBuffer;
    ++
    ++// ---------------------------------------------------------------------------
    ++
    ++class FramebufferNativeWindow 
    ++    : public ANativeObjectBase<
    ++        ANativeWindow, 
    ++        FramebufferNativeWindow, 
    ++        LightRefBase<FramebufferNativeWindow> >
    ++{
    ++public:
    ++    FramebufferNativeWindow(); 
    ++
    ++    framebuffer_device_t const * getDevice() const { return fbDev; } 
    ++
    ++    bool isUpdateOnDemand() const { return mUpdateOnDemand; }
    ++    status_t setUpdateRectangle(const Rect& updateRect);
    ++    status_t compositionComplete();
    ++
    ++    void dump(String8& result);
    ++
    ++    // for debugging only
    ++    int getCurrentBufferIndex() const;
    ++
    ++private:
    ++    friend class LightRefBase<FramebufferNativeWindow>;    
    ++    ~FramebufferNativeWindow(); // this class cannot be overloaded
    ++    static int setSwapInterval(ANativeWindow* window, int interval);
    ++    static int dequeueBuffer(ANativeWindow* window, ANativeWindowBuffer** buffer, int* fenceFd);
    ++    static int queueBuffer(ANativeWindow* window, ANativeWindowBuffer* buffer, int fenceFd);
    ++    static int query(const ANativeWindow* window, int what, int* value);
    ++    static int perform(ANativeWindow* window, int operation, ...);
    ++
    ++    static int dequeueBuffer_DEPRECATED(ANativeWindow* window, ANativeWindowBuffer** buffer);
    ++    static int queueBuffer_DEPRECATED(ANativeWindow* window, ANativeWindowBuffer* buffer);
    ++    static int lockBuffer_DEPRECATED(ANativeWindow* window, ANativeWindowBuffer* buffer);
    ++
    ++    framebuffer_device_t* fbDev;
    ++    alloc_device_t* grDev;
    ++
    ++    sp<NativeBuffer> buffers[MAX_NUM_FRAME_BUFFERS];
    ++    sp<NativeBuffer> front;
    ++    
    ++    mutable Mutex mutex;
    ++    Condition mCondition;
    ++    int32_t mNumBuffers;
    ++    int32_t mNumFreeBuffers;
    ++    int32_t mBufferHead;
    ++    int32_t mCurrentBufferIndex;
    ++    bool mUpdateOnDemand;
    ++};
    ++    
    ++// ---------------------------------------------------------------------------
    ++}; // namespace android
    ++// ---------------------------------------------------------------------------
    ++
    ++#endif // ANDROID_FRAMEBUFFER_NATIVE_WINDOW_H
    ++
     diff --git a/libs/binder/IPCThreadState.cpp b/libs/binder/IPCThreadState.cpp
     index d90798f..9b5f0d7 100644
     --- a/libs/binder/IPCThreadState.cpp
    @@ -171,6 +302,452 @@ index f0b0ada..3577a33 100644
                  reply->writeInt32(res);
                  return NO_ERROR;
              }
    +diff --git a/libs/gui/Surface.cpp b/libs/gui/Surface.cpp
    +index 0838290..0bb142b 100644
    +--- a/libs/gui/Surface.cpp
    ++++ b/libs/gui/Surface.cpp
    +@@ -1260,6 +1260,7 @@ status_t Surface::lock(
    +         }
    + 
    +         // figure out if we can copy the frontbuffer back
    ++        int backBufferSlot(getSlotFromBufferLocked(backBuffer.get()));
    +         const sp<GraphicBuffer>& frontBuffer(mPostedBuffer);
    +         const bool canCopyBack = (frontBuffer != 0 &&
    +                 backBuffer->width  == frontBuffer->width &&
    +@@ -1267,15 +1268,23 @@ status_t Surface::lock(
    +                 backBuffer->format == frontBuffer->format);
    + 
    +         if (canCopyBack) {
    +-            // copy the area that is invalid and not repainted this round
    +-            const Region copyback(mDirtyRegion.subtract(newDirtyRegion));
    ++            Mutex::Autolock lock(mMutex);
    ++            Region oldDirtyRegion;
    ++            if(mSlots[backBufferSlot].dirtyRegion.isEmpty()) {
    ++                oldDirtyRegion.set(bounds);
    ++            } else {
    ++                for(int i = 0 ; i < NUM_BUFFER_SLOTS; i++ ) {
    ++                    if(i != backBufferSlot && !mSlots[i].dirtyRegion.isEmpty())
    ++                        oldDirtyRegion.orSelf(mSlots[i].dirtyRegion);
    ++                }
    ++            }
    ++            const Region copyback(oldDirtyRegion.subtract(newDirtyRegion));
    +             if (!copyback.isEmpty())
    +                 copyBlt(backBuffer, frontBuffer, copyback);
    +         } else {
    +             // if we can't copy-back anything, modify the user's dirty
    +             // region to make sure they redraw the whole buffer
    +             newDirtyRegion.set(bounds);
    +-            mDirtyRegion.clear();
    +             Mutex::Autolock lock(mMutex);
    +             for (size_t i=0 ; i<NUM_BUFFER_SLOTS ; i++) {
    +                 mSlots[i].dirtyRegion.clear();
    +@@ -1285,15 +1294,9 @@ status_t Surface::lock(
    + 
    +         { // scope for the lock
    +             Mutex::Autolock lock(mMutex);
    +-            int backBufferSlot(getSlotFromBufferLocked(backBuffer.get()));
    +-            if (backBufferSlot >= 0) {
    +-                Region& dirtyRegion(mSlots[backBufferSlot].dirtyRegion);
    +-                mDirtyRegion.subtract(dirtyRegion);
    +-                dirtyRegion = newDirtyRegion;
    +-            }
    ++            mSlots[backBufferSlot].dirtyRegion = newDirtyRegion;
    +         }
    + 
    +-        mDirtyRegion.orSelf(newDirtyRegion);
    +         if (inOutDirtyBounds) {
    +             *inOutDirtyBounds = newDirtyRegion.getBounds();
    +         }
    +diff --git a/libs/ui/Android.mk b/libs/ui/Android.mk
    +index e690ede..3927031 100644
    +--- a/libs/ui/Android.mk
    ++++ b/libs/ui/Android.mk
    +@@ -36,6 +36,7 @@ LOCAL_CPPFLAGS += -Wno-padded
    + 
    + LOCAL_SRC_FILES := \
    + 	Fence.cpp \
    ++        FramebufferNativeWindow.cpp \
    + 	FrameStats.cpp \
    + 	Gralloc1.cpp \
    + 	Gralloc1On0Adapter.cpp \
    +diff --git a/libs/ui/FramebufferNativeWindow.cpp b/libs/ui/FramebufferNativeWindow.cpp
    +new file mode 100644
    +index 0000000..3ead25c
    +--- /dev/null
    ++++ b/libs/ui/FramebufferNativeWindow.cpp
    +@@ -0,0 +1,372 @@
    ++/*
    ++**
    ++** Copyright 2007 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.
    ++*/
    ++
    ++#define LOG_TAG "FramebufferNativeWindow"
    ++
    ++#include <stdlib.h>
    ++#include <stdio.h>
    ++#include <string.h>
    ++#include <errno.h>
    ++
    ++#include <cutils/log.h>
    ++#include <cutils/atomic.h>
    ++#include <utils/threads.h>
    ++#include <utils/RefBase.h>
    ++
    ++#include <ui/ANativeObjectBase.h>
    ++#include <ui/Fence.h>
    ++#define INCLUDED_FROM_FRAMEBUFFER_NATIVE_WINDOW_CPP
    ++#include <ui/FramebufferNativeWindow.h>
    ++#undef INCLUDED_FROM_FRAMEBUFFER_NATIVE_WINDOW_CPP
    ++#include <ui/Rect.h>
    ++
    ++#include <EGL/egl.h>
    ++
    ++#include <hardware/hardware.h>
    ++#include <hardware/gralloc.h>
    ++
    ++// ----------------------------------------------------------------------------
    ++namespace android {
    ++// ----------------------------------------------------------------------------
    ++
    ++class NativeBuffer final
    ++    : public ANativeObjectBase<
    ++        ANativeWindowBuffer,
    ++        NativeBuffer,
    ++        LightRefBase<NativeBuffer>>
    ++{
    ++public:
    ++    NativeBuffer(int w, int h, int f, int u) : BASE() {
    ++        ANativeWindowBuffer::width  = w;
    ++        ANativeWindowBuffer::height = h;
    ++        ANativeWindowBuffer::format = f;
    ++        ANativeWindowBuffer::usage  = u;
    ++    }
    ++private:
    ++    friend class LightRefBase<NativeBuffer>;
    ++};
    ++
    ++
    ++/*
    ++ * This implements the (main) framebuffer management. This class is used
    ++ * mostly by SurfaceFlinger, but also by command line GL application.
    ++ *
    ++ * In fact this is an implementation of ANativeWindow on top of
    ++ * the framebuffer.
    ++ *
    ++ * Currently it is pretty simple, it manages only two buffers (the front and
    ++ * back buffer).
    ++ *
    ++ */
    ++
    ++FramebufferNativeWindow::FramebufferNativeWindow()
    ++    : BASE(), fbDev(0), grDev(0), mUpdateOnDemand(false)
    ++{
    ++    hw_module_t const* module;
    ++    if (hw_get_module(GRALLOC_HARDWARE_MODULE_ID, &module) == 0) {
    ++        int err;
    ++        int i;
    ++        err = framebuffer_open(module, &fbDev);
    ++        ALOGE_IF(err, "couldn't open framebuffer HAL (%s)", strerror(-err));
    ++
    ++        err = gralloc_open(module, &grDev);
    ++        ALOGE_IF(err, "couldn't open gralloc HAL (%s)", strerror(-err));
    ++
    ++        // bail out if we can't initialize the modules
    ++        if (!fbDev || !grDev)
    ++            return;
    ++
    ++        mUpdateOnDemand = (fbDev->setUpdateRect != 0);
    ++
    ++        // initialize the buffer FIFO
    ++        if(fbDev->numFramebuffers >= MIN_NUM_FRAME_BUFFERS &&
    ++           fbDev->numFramebuffers <= MAX_NUM_FRAME_BUFFERS){
    ++            mNumBuffers = fbDev->numFramebuffers;
    ++        } else {
    ++            mNumBuffers = MIN_NUM_FRAME_BUFFERS;
    ++        }
    ++        mNumFreeBuffers = mNumBuffers;
    ++        mBufferHead = mNumBuffers-1;
    ++
    ++        /*
    ++         * This does not actually change the framebuffer format. It merely
    ++         * fakes this format to surfaceflinger so that when it creates
    ++         * framebuffer surfaces it will use this format. It's really a giant
    ++         * HACK to allow interworking with buggy gralloc+GPU driver
    ++         * implementations. You should *NEVER* need to set this for shipping
    ++         * devices.
    ++         */
    ++#ifdef FRAMEBUFFER_FORCE_FORMAT
    ++        *((uint32_t *)&fbDev->format) = FRAMEBUFFER_FORCE_FORMAT;
    ++#endif
    ++
    ++        for (i = 0; i < mNumBuffers; i++) {
    ++            buffers[i] = new NativeBuffer(
    ++                    static_cast<int>(fbDev->width),
    ++                    static_cast<int>(fbDev->height),
    ++                    fbDev->format, GRALLOC_USAGE_HW_FB);
    ++        }
    ++
    ++        for (i = 0; i < mNumBuffers; i++) {
    ++            err = grDev->alloc(grDev,
    ++                    static_cast<int>(fbDev->width),
    ++                    static_cast<int>(fbDev->height),
    ++                    fbDev->format, GRALLOC_USAGE_HW_FB,
    ++                    &buffers[i]->handle, &buffers[i]->stride);
    ++
    ++            ALOGE_IF(err, "fb buffer %d allocation failed w=%d, h=%d, err=%s",
    ++                    i, fbDev->width, fbDev->height, strerror(-err));
    ++
    ++            if (err) {
    ++                mNumBuffers = i;
    ++                mNumFreeBuffers = i;
    ++                mBufferHead = mNumBuffers-1;
    ++                break;
    ++            }
    ++        }
    ++
    ++        const_cast<uint32_t&>(ANativeWindow::flags) = fbDev->flags;
    ++        const_cast<float&>(ANativeWindow::xdpi) = fbDev->xdpi;
    ++        const_cast<float&>(ANativeWindow::ydpi) = fbDev->ydpi;
    ++        const_cast<int&>(ANativeWindow::minSwapInterval) =
    ++            fbDev->minSwapInterval;
    ++        const_cast<int&>(ANativeWindow::maxSwapInterval) =
    ++            fbDev->maxSwapInterval;
    ++    } else {
    ++        ALOGE("Couldn't get gralloc module");
    ++    }
    ++
    ++    ANativeWindow::setSwapInterval = setSwapInterval;
    ++    ANativeWindow::dequeueBuffer = dequeueBuffer;
    ++    ANativeWindow::queueBuffer = queueBuffer;
    ++    ANativeWindow::query = query;
    ++    ANativeWindow::perform = perform;
    ++
    ++    ANativeWindow::dequeueBuffer_DEPRECATED = dequeueBuffer_DEPRECATED;
    ++    ANativeWindow::lockBuffer_DEPRECATED = lockBuffer_DEPRECATED;
    ++    ANativeWindow::queueBuffer_DEPRECATED = queueBuffer_DEPRECATED;
    ++}
    ++
    ++FramebufferNativeWindow::~FramebufferNativeWindow()
    ++{
    ++    if (grDev) {
    ++        for(int i = 0; i < mNumBuffers; i++) {
    ++            if (buffers[i] != NULL) {
    ++                grDev->free(grDev, buffers[i]->handle);
    ++            }
    ++        }
    ++        gralloc_close(grDev);
    ++    }
    ++
    ++    if (fbDev) {
    ++        framebuffer_close(fbDev);
    ++    }
    ++}
    ++
    ++status_t FramebufferNativeWindow::setUpdateRectangle(const Rect& r)
    ++{
    ++    if (!mUpdateOnDemand) {
    ++        return INVALID_OPERATION;
    ++    }
    ++    return fbDev->setUpdateRect(fbDev, r.left, r.top, r.width(), r.height());
    ++}
    ++
    ++status_t FramebufferNativeWindow::compositionComplete()
    ++{
    ++    if (fbDev->compositionComplete) {
    ++        return fbDev->compositionComplete(fbDev);
    ++    }
    ++    return INVALID_OPERATION;
    ++}
    ++
    ++int FramebufferNativeWindow::setSwapInterval(
    ++        ANativeWindow* window, int interval)
    ++{
    ++    framebuffer_device_t* fb = getSelf(window)->fbDev;
    ++    return fb->setSwapInterval(fb, interval);
    ++}
    ++
    ++void FramebufferNativeWindow::dump(String8& result) {
    ++    if (fbDev->common.version >= 1 && fbDev->dump) {
    ++        const size_t SIZE = 4096;
    ++        char buffer[SIZE];
    ++
    ++        fbDev->dump(fbDev, buffer, SIZE);
    ++        result.append(buffer);
    ++    }
    ++}
    ++
    ++// only for debugging / logging
    ++int FramebufferNativeWindow::getCurrentBufferIndex() const
    ++{
    ++    Mutex::Autolock _l(mutex);
    ++    const int index = mCurrentBufferIndex;
    ++    return index;
    ++}
    ++
    ++int FramebufferNativeWindow::dequeueBuffer_DEPRECATED(ANativeWindow* window,
    ++        ANativeWindowBuffer** buffer)
    ++{
    ++    int fenceFd = -1;
    ++    int result = dequeueBuffer(window, buffer, &fenceFd);
    ++    sp<Fence> fence(new Fence(fenceFd));
    ++    int waitResult = fence->wait(Fence::TIMEOUT_NEVER);
    ++    if (waitResult != OK) {
    ++        ALOGE("dequeueBuffer_DEPRECATED: Fence::wait returned an "
    ++                "error: %d", waitResult);
    ++        return waitResult;
    ++    }
    ++    return result;
    ++}
    ++
    ++int FramebufferNativeWindow::dequeueBuffer(ANativeWindow* window,
    ++        ANativeWindowBuffer** buffer, int* fenceFd)
    ++{
    ++    FramebufferNativeWindow* self = getSelf(window);
    ++    Mutex::Autolock _l(self->mutex);
    ++
    ++    int index = self->mBufferHead++;
    ++    if (self->mBufferHead >= self->mNumBuffers)
    ++        self->mBufferHead = 0;
    ++
    ++    // wait for a free non-front buffer
    ++    while (self->mNumFreeBuffers < 2) {
    ++        self->mCondition.wait(self->mutex);
    ++    }
    ++    ALOG_ASSERT(self->buffers[index] != self->front, "");
    ++
    ++    // get this buffer
    ++    self->mNumFreeBuffers--;
    ++    self->mCurrentBufferIndex = index;
    ++
    ++    *buffer = self->buffers[index].get();
    ++    *fenceFd = -1;
    ++
    ++    return 0;
    ++}
    ++
    ++int FramebufferNativeWindow::lockBuffer_DEPRECATED(ANativeWindow* /*window*/,
    ++        ANativeWindowBuffer* /*buffer*/)
    ++{
    ++    return NO_ERROR;
    ++}
    ++
    ++int FramebufferNativeWindow::queueBuffer_DEPRECATED(ANativeWindow* window,
    ++        ANativeWindowBuffer* buffer)
    ++{
    ++    return queueBuffer(window, buffer, -1);
    ++}
    ++
    ++int FramebufferNativeWindow::queueBuffer(ANativeWindow* window,
    ++        ANativeWindowBuffer* buffer, int fenceFd)
    ++{
    ++    FramebufferNativeWindow* self = getSelf(window);
    ++    Mutex::Autolock _l(self->mutex);
    ++    framebuffer_device_t* fb = self->fbDev;
    ++    buffer_handle_t handle = static_cast<NativeBuffer*>(buffer)->handle;
    ++
    ++    sp<Fence> fence(new Fence(fenceFd));
    ++    fence->wait(Fence::TIMEOUT_NEVER);
    ++
    ++    int res = fb->post(fb, handle);
    ++    self->front = static_cast<NativeBuffer*>(buffer);
    ++    self->mNumFreeBuffers++;
    ++    self->mCondition.broadcast();
    ++    return res;
    ++}
    ++
    ++int FramebufferNativeWindow::query(const ANativeWindow* window,
    ++        int what, int* value)
    ++{
    ++    const FramebufferNativeWindow* self = getSelf(window);
    ++    Mutex::Autolock _l(self->mutex);
    ++    framebuffer_device_t* fb = self->fbDev;
    ++    switch (what) {
    ++        case NATIVE_WINDOW_WIDTH:
    ++            *value = static_cast<int>(fb->width);
    ++            return NO_ERROR;
    ++        case NATIVE_WINDOW_HEIGHT:
    ++            *value = static_cast<int>(fb->height);
    ++            return NO_ERROR;
    ++        case NATIVE_WINDOW_FORMAT:
    ++            *value = fb->format;
    ++            return NO_ERROR;
    ++        case NATIVE_WINDOW_CONCRETE_TYPE:
    ++            *value = NATIVE_WINDOW_FRAMEBUFFER;
    ++            return NO_ERROR;
    ++        case NATIVE_WINDOW_QUEUES_TO_WINDOW_COMPOSER:
    ++            *value = 0;
    ++            return NO_ERROR;
    ++        case NATIVE_WINDOW_DEFAULT_WIDTH:
    ++            *value = static_cast<int>(fb->width);
    ++            return NO_ERROR;
    ++        case NATIVE_WINDOW_DEFAULT_HEIGHT:
    ++            *value = static_cast<int>(fb->height);
    ++            return NO_ERROR;
    ++        case NATIVE_WINDOW_TRANSFORM_HINT:
    ++            *value = 0;
    ++            return NO_ERROR;
    ++    }
    ++    *value = 0;
    ++    return BAD_VALUE;
    ++}
    ++
    ++int FramebufferNativeWindow::perform(ANativeWindow* /*window*/,
    ++        int operation, ...)
    ++{
    ++    switch (operation) {
    ++        case NATIVE_WINDOW_CONNECT:
    ++        case NATIVE_WINDOW_DISCONNECT:
    ++        case NATIVE_WINDOW_SET_USAGE:
    ++        case NATIVE_WINDOW_SET_BUFFERS_GEOMETRY:
    ++        case NATIVE_WINDOW_SET_BUFFERS_DIMENSIONS:
    ++        case NATIVE_WINDOW_SET_BUFFERS_FORMAT:
    ++        case NATIVE_WINDOW_SET_BUFFERS_TRANSFORM:
    ++        case NATIVE_WINDOW_API_CONNECT:
    ++        case NATIVE_WINDOW_API_DISCONNECT:
    ++            // TODO: we should implement these
    ++            return NO_ERROR;
    ++
    ++        case NATIVE_WINDOW_LOCK:
    ++        case NATIVE_WINDOW_UNLOCK_AND_POST:
    ++        case NATIVE_WINDOW_SET_CROP:
    ++        case NATIVE_WINDOW_SET_BUFFER_COUNT:
    ++        case NATIVE_WINDOW_SET_BUFFERS_TIMESTAMP:
    ++        case NATIVE_WINDOW_SET_SCALING_MODE:
    ++            return INVALID_OPERATION;
    ++    }
    ++    return NAME_NOT_FOUND;
    ++}
    ++
    ++// ----------------------------------------------------------------------------
    ++}; // namespace android
    ++// ----------------------------------------------------------------------------
    ++
    ++using android::sp;
    ++using android::FramebufferNativeWindow;
    ++
    ++EGLNativeWindowType android_createDisplaySurface(void)
    ++{
    ++    FramebufferNativeWindow* w;
    ++    w = new FramebufferNativeWindow();
    ++    if (w->getDevice() == NULL) {
    ++        // get a ref so it can be destroyed when we exit this block
    ++        sp<FramebufferNativeWindow> ref(w);
    ++        return NULL;
    ++    }
    ++    return static_cast<EGLNativeWindowType>(w);
    ++}
     diff --git a/libs/ui/Gralloc1On0Adapter.cpp b/libs/ui/Gralloc1On0Adapter.cpp
     index d5b88de..ec7df31 100644
     --- a/libs/ui/Gralloc1On0Adapter.cpp
    @@ -433,6 +1010,19 @@ index ffda035..cb292ef 100644
      ifeq ($(TARGET_BOARD_PLATFORM),omap4)
          LOCAL_CFLAGS += -DHAS_CONTEXT_PRIORITY
      endif
    +diff --git a/services/surfaceflinger/DisplayDevice.cpp b/services/surfaceflinger/DisplayDevice.cpp
    +index 5c2c0ad..1f2e554 100644
    +--- a/services/surfaceflinger/DisplayDevice.cpp
    ++++ b/services/surfaceflinger/DisplayDevice.cpp
    +@@ -166,7 +166,7 @@ DisplayDevice::DisplayDevice(
    +     setProjection(DisplayState::eOrientationDefault, mViewport, mFrame);
    + 
    + #ifdef NUM_FRAMEBUFFER_SURFACE_BUFFERS
    +-    surface->allocateBuffers();
    ++    mSurface->allocateBuffers();
    + #endif
    + }
    + 
     diff --git a/services/surfaceflinger/DisplayHardware/HWComposer_hwc1.cpp b/services/surfaceflinger/DisplayHardware/HWComposer_hwc1.cpp
     index ef41658..086acc9 100644
     --- a/services/surfaceflinger/DisplayHardware/HWComposer_hwc1.cpp
    @@ -446,6 +1036,60 @@ index ef41658..086acc9 100644
              char buffer[SIZE];
              mHwc->dump(mHwc, buffer, SIZE);
              result.append(buffer);
    +diff --git a/services/surfaceflinger/DisplayHardware/HWComposer_hwc1.h b/services/surfaceflinger/DisplayHardware/HWComposer_hwc1.h
    +index 170e382..0f0c65d 100644
    +--- a/services/surfaceflinger/DisplayHardware/HWComposer_hwc1.h
    ++++ b/services/surfaceflinger/DisplayHardware/HWComposer_hwc1.h
    +@@ -236,6 +236,9 @@ public:
    +         bool operator != (const LayerListIterator& rhs) const {
    +             return !operator==(rhs);
    +         }
    ++        bool operator ! () const {
    ++             return !mLayerList;
    ++        }
    +     };
    + 
    +     // Returns an iterator to the beginning of the layer list
    +diff --git a/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp b/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp
    +index 2190466..8c36d85 100644
    +--- a/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp
    ++++ b/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp
    +@@ -344,6 +344,13 @@ status_t VirtualDisplaySurface::dequeueBuffer(Source source,
    +         PixelFormat format, uint32_t usage, int* sslot, sp<Fence>* fence) {
    +     LOG_FATAL_IF(mDisplayId < 0, "mDisplayId=%d but should not be < 0.", mDisplayId);
    + 
    ++    // Exclude video encoder usage flag from scratch buffer usage flags
    ++    if (source == SOURCE_SCRATCH) {
    ++        usage &= ~(GRALLOC_USAGE_HW_VIDEO_ENCODER);
    ++        VDS_LOGV("dequeueBuffer(%s): updated scratch buffer usage flags=%#x",
    ++                dbgSourceStr(source), usage);
    ++    }
    ++
    +     status_t result = mSource[source]->dequeueBuffer(sslot, fence,
    +             mSinkBufferWidth, mSinkBufferHeight, format, usage);
    +     if (result < 0)
    +diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
    +index dfece93..646014a 100644
    +--- a/services/surfaceflinger/Layer.cpp
    ++++ b/services/surfaceflinger/Layer.cpp
    +@@ -2055,11 +2055,16 @@ Region Layer::latchBuffer(bool& recomputeVisibleRegions)
    + 
    +             // Remove any stale buffers that have been dropped during
    +             // updateTexImage
    +-            while (mQueueItems[0].mFrameNumber != currentFrameNumber) {
    ++            while ((mQueuedFrames > 0) && (mQueueItems[0].mFrameNumber != currentFrameNumber)) {
    +                 mQueueItems.removeAt(0);
    +                 android_atomic_dec(&mQueuedFrames);
    +             }
    + 
    ++            if (mQueuedFrames == 0) {
    ++                ALOGE("[%s] mQueuedFrames is zero !!", mName.string());
    ++                return outDirtyRegion;
    ++            }
    ++
    +             mQueueItems.removeAt(0);
    +         }
    + 
     diff --git a/services/surfaceflinger/RenderEngine/GLES11RenderEngine.cpp b/services/surfaceflinger/RenderEngine/GLES11RenderEngine.cpp
     index 847cdb3..b2821b7 100644
     --- a/services/surfaceflinger/RenderEngine/GLES11RenderEngine.cpp
    @@ -838,11 +1482,34 @@ index e0e4c61..6f2520b 100644
      #ifdef USE_HWC2
          err = updateAndReleaseLocked(item, &mPendingRelease);
     diff --git a/services/surfaceflinger/SurfaceFlinger_hwc1.cpp b/services/surfaceflinger/SurfaceFlinger_hwc1.cpp
    -index b0f418c..ca03830 100644
    +index b0f418c..94c95a6 100644
     --- a/services/surfaceflinger/SurfaceFlinger_hwc1.cpp
     +++ b/services/surfaceflinger/SurfaceFlinger_hwc1.cpp
    -@@ -466,10 +466,12 @@ void SurfaceFlinger::init() {
    -     mEventQueue.setEventThread(mSFEventThread);
    +@@ -457,19 +457,28 @@ void SurfaceFlinger::init() {
    +     eglInitialize(mEGLDisplay, NULL, NULL);
    + 
    +     // start the EventThread
    +-    sp<VSyncSource> vsyncSrc = new DispSyncSource(&mPrimaryDispSync,
    +-            vsyncPhaseOffsetNs, true, "app");
    +-    mEventThread = new EventThread(vsyncSrc, *this);
    +-    sp<VSyncSource> sfVsyncSrc = new DispSyncSource(&mPrimaryDispSync,
    +-            sfVsyncPhaseOffsetNs, true, "sf");
    +-    mSFEventThread = new EventThread(sfVsyncSrc, *this);
    +-    mEventQueue.setEventThread(mSFEventThread);
    ++    if (vsyncPhaseOffsetNs != sfVsyncPhaseOffsetNs) {
    ++        sp<VSyncSource> vsyncSrc = new DispSyncSource(&mPrimaryDispSync,
    ++                vsyncPhaseOffsetNs, true, "app");
    ++        mEventThread = new EventThread(vsyncSrc, *this);
    ++        sp<VSyncSource> sfVsyncSrc = new DispSyncSource(&mPrimaryDispSync,
    ++                sfVsyncPhaseOffsetNs, true, "sf");
    ++        mSFEventThread = new EventThread(sfVsyncSrc, *this);
    ++        mEventQueue.setEventThread(mSFEventThread);
    ++    } else {
    ++        sp<VSyncSource> vsyncSrc = new DispSyncSource(&mPrimaryDispSync,
    ++                         vsyncPhaseOffsetNs, true, "sf-app");
    ++        mEventThread = new EventThread(vsyncSrc, *this);
    ++        mEventQueue.setEventThread(mEventThread);
    ++    }
      
          // set SFEventThread to SCHED_FIFO to minimize jitter
     -    struct sched_param param = {0};
    @@ -858,7 +1525,7 @@ index b0f418c..ca03830 100644
          }
      
      
    -@@ -635,10 +637,21 @@ status_t SurfaceFlinger::getDisplayConfigs(const sp<IBinder>& display,
    +@@ -635,10 +644,21 @@ status_t SurfaceFlinger::getDisplayConfigs(const sp<IBinder>& display,
                  info.orientation = 0;
              }
      
    @@ -884,7 +1551,24 @@ index b0f418c..ca03830 100644
              info.fps = float(1e9 / hwConfig.refresh);
              info.appVsyncOffset = VSYNC_EVENT_PHASE_OFFSET_NS;
      
    -@@ -3331,7 +3344,8 @@ status_t SurfaceFlinger::captureScreen(const sp<IBinder>& display,
    +@@ -3187,12 +3207,14 @@ status_t SurfaceFlinger::onTransact(
    +             }
    +             case 1018: { // Modify Choreographer's phase offset
    +                 n = data.readInt32();
    +-                mEventThread->setPhaseOffset(static_cast<nsecs_t>(n));
    ++                if (mEventThread != NULL)
    ++                    mEventThread->setPhaseOffset(static_cast<nsecs_t>(n));
    +                 return NO_ERROR;
    +             }
    +             case 1019: { // Modify SurfaceFlinger's phase offset
    +                 n = data.readInt32();
    +-                mSFEventThread->setPhaseOffset(static_cast<nsecs_t>(n));
    ++                if (mSFEventThread != NULL)
    ++                    mSFEventThread->setPhaseOffset(static_cast<nsecs_t>(n));
    +                 return NO_ERROR;
    +             }
    +             case 1021: { // Disable HWC virtual displays
    +@@ -3331,7 +3353,8 @@ status_t SurfaceFlinger::captureScreen(const sp<IBinder>& display,
              const sp<IGraphicBufferProducer>& producer,
              Rect sourceCrop, uint32_t reqWidth, uint32_t reqHeight,
              uint32_t minLayerZ, uint32_t maxLayerZ,
    @@ -894,7 +1578,7 @@ index b0f418c..ca03830 100644
      
          if (CC_UNLIKELY(display == 0))
              return BAD_VALUE;
    -@@ -3375,6 +3389,7 @@ status_t SurfaceFlinger::captureScreen(const sp<IBinder>& display,
    +@@ -3375,6 +3398,7 @@ status_t SurfaceFlinger::captureScreen(const sp<IBinder>& display,
              bool useIdentityTransform;
              Transform::orientation_flags rotation;
              status_t result;
    @@ -902,7 +1586,7 @@ index b0f418c..ca03830 100644
              bool isLocalScreenshot;
          public:
              MessageCaptureScreen(SurfaceFlinger* flinger,
    -@@ -3384,12 +3399,13 @@ status_t SurfaceFlinger::captureScreen(const sp<IBinder>& display,
    +@@ -3384,12 +3408,13 @@ status_t SurfaceFlinger::captureScreen(const sp<IBinder>& display,
                      uint32_t minLayerZ, uint32_t maxLayerZ,
                      bool useIdentityTransform,
                      Transform::orientation_flags rotation,
    @@ -917,7 +1601,7 @@ index b0f418c..ca03830 100644
                    isLocalScreenshot(isLocalScreenshot)
              {
              }
    -@@ -3399,9 +3415,10 @@ status_t SurfaceFlinger::captureScreen(const sp<IBinder>& display,
    +@@ -3399,9 +3424,10 @@ status_t SurfaceFlinger::captureScreen(const sp<IBinder>& display,
              virtual bool handler() {
                  Mutex::Autolock _l(flinger->mStateLock);
                  sp<const DisplayDevice> hw(flinger->getDisplayDevice(display));
    @@ -929,7 +1613,7 @@ index b0f418c..ca03830 100644
                  static_cast<GraphicProducerWrapper*>(IInterface::asBinder(producer).get())->exit(result);
                  return true;
              }
    -@@ -3417,7 +3434,7 @@ status_t SurfaceFlinger::captureScreen(const sp<IBinder>& display,
    +@@ -3417,7 +3443,7 @@ status_t SurfaceFlinger::captureScreen(const sp<IBinder>& display,
          sp<MessageBase> msg = new MessageCaptureScreen(this,
                  display, IGraphicBufferProducer::asInterface( wrapper ),
                  sourceCrop, reqWidth, reqHeight, minLayerZ, maxLayerZ,
    @@ -938,7 +1622,7 @@ index b0f418c..ca03830 100644
      
          status_t res = postMessageAsync(msg);
          if (res == NO_ERROR) {
    -@@ -3502,7 +3519,7 @@ status_t SurfaceFlinger::captureScreenImplLocked(
    +@@ -3502,7 +3528,7 @@ status_t SurfaceFlinger::captureScreenImplLocked(
              Rect sourceCrop, uint32_t reqWidth, uint32_t reqHeight,
              uint32_t minLayerZ, uint32_t maxLayerZ,
              bool useIdentityTransform, Transform::orientation_flags rotation,
    @@ -947,7 +1631,7 @@ index b0f418c..ca03830 100644
      {
          ATRACE_CALL();
      
    -@@ -3572,7 +3589,7 @@ status_t SurfaceFlinger::captureScreenImplLocked(
    +@@ -3572,7 +3598,7 @@ status_t SurfaceFlinger::captureScreenImplLocked(
                      if (image != EGL_NO_IMAGE_KHR) {
                          // this binds the given EGLImage as a framebuffer for the
                          // duration of this scope.
    @@ -956,7 +1640,7 @@ index b0f418c..ca03830 100644
                          if (imageBond.getStatus() == NO_ERROR) {
                              // this will in fact render into our dequeued buffer
                              // via an FBO, which means we didn't have to create
    -@@ -3619,6 +3636,16 @@ status_t SurfaceFlinger::captureScreenImplLocked(
    +@@ -3619,6 +3645,16 @@ status_t SurfaceFlinger::captureScreenImplLocked(
                                      ALOGW("captureScreen: error creating EGL fence: %#x", eglGetError());
                                  }
                              }
    
    From 8a9c49504ba1e844fd2c7cd02d2be5825ea811aa Mon Sep 17 00:00:00 2001
    From: AndDiSa <anddisa@googlemail.com>
    Date: Tue, 28 Mar 2017 18:54:16 +0200
    Subject: [PATCH 067/159] update vendor/nndia/grouper to branch ads-7.1.0
    
    Change-Id: I83bd015172af4a56e552ee2d9d77aa2724b948b1
    ---
     default.xml | 2 +-
     1 file changed, 1 insertion(+), 1 deletion(-)
    
    diff --git a/default.xml b/default.xml
    index de9f558..98361f1 100644
    --- a/default.xml
    +++ b/default.xml
    @@ -514,6 +514,6 @@
       <project path="vendor/broadcom" name="proprietary_vendor_broadcom" remote="ads" revision="ads-7.0.1" />
       <project path="vendor/elan" name="proprietary_vendor_elan" remote="ads" revision="oct-mm" />
       <project path="vendor/invensense" name="proprietary_vendor_invensense" remote="ads" revision="ads-7.0.1" />
    -  <project path="vendor/nvidia" name="proprietary_vendor_nvidia" remote="ads" revision="ads-7.0.1" />
    +  <project path="vendor/nvidia" name="proprietary_vendor_nvidia" remote="ads" revision="ads-7.1.0" />
       <project path="vendor/widevine" name="proprietary_vendor_widevine" remote="ads" revision="ads-7.1.0" />
     </manifest>
    
    From 72c06137e781f4dd47fb45ce34fdc2b3d5ff3aec Mon Sep 17 00:00:00 2001
    From: AndDiSa <anddisa@googlemail.com>
    Date: Thu, 30 Mar 2017 21:10:30 +0200
    Subject: [PATCH 068/159] add PerformamceControl application
    
    Change-Id: I9b201b0afdc132a3fa778d1f44651e189d2c034c
    ---
     default.xml | 1 +
     1 file changed, 1 insertion(+)
    
    diff --git a/default.xml b/default.xml
    index 98361f1..2c54ba2 100644
    --- a/default.xml
    +++ b/default.xml
    @@ -408,6 +408,7 @@
       <project path="packages/apps/Nfc" name="platform/packages/apps/Nfc" groups="apps_nfc,pdk-fs" />
       <project path="packages/apps/OneTimeInitializer" name="platform/packages/apps/OneTimeInitializer" groups="pdk-fs" />
       <project path="packages/apps/PackageInstaller" name="platform/packages/apps/PackageInstaller" groups="pdk-fs" />
    +  <project path="packages/apps/PerformanceControl" name="android_packages_apps_PerformanceControl" remote="ads" revision="cm-13.0" />
       <project path="packages/apps/Phone" name="platform/packages/apps/Phone" groups="pdk-fs" />
       <project path="packages/apps/PhoneCommon" name="platform/packages/apps/PhoneCommon" groups="pdk-cw-fs,pdk-fs"/>
       <project path="packages/apps/Protips" name="platform/packages/apps/Protips" groups="pdk-fs" />
    
    From 363e0fdc4a74f276c1445605fc071cfd9f4fc28b Mon Sep 17 00:00:00 2001
    From: AndDiSa <anddisa@googlemail.com>
    Date: Tue, 4 Apr 2017 17:54:52 +0200
    Subject: [PATCH 069/159] update to android-7.1.2_r5
    
    Change-Id: I974e94a9e8fd84240ee2db95f87488d0e111e914
    ---
     default.xml | 2 +-
     1 file changed, 1 insertion(+), 1 deletion(-)
    
    diff --git a/default.xml b/default.xml
    index 2c54ba2..e8d9650 100644
    --- a/default.xml
    +++ b/default.xml
    @@ -9,7 +9,7 @@
                fetch="https://github.com/millosr/" />
       <remote  name="unlegacy"
                fetch="https://github.com/Unlegacy-Android/" />
    -  <default revision="refs/tags/android-7.1.1_r25"
    +  <default revision="refs/tags/android-7.1.2_r5"
                remote="aosp"
                sync-j="4" />
     
    
    From b6692baca5d648700e58648b87934e61b8d22b09 Mon Sep 17 00:00:00 2001
    From: AndDiSa <anddisa@googlemail.com>
    Date: Fri, 7 Apr 2017 11:49:41 +0200
    Subject: [PATCH 070/159] update patches
    
    Change-Id: Idb17797c0ebf3805953d52d0a18eda71ee4b382b
    ---
     bionic.patch                 |  815 ++++++++++++++++++++++++
     build.patch                  |  289 +++++++++
     frameworks_av.patch          |  162 ++++-
     frameworks_base.patch        | 1131 +++++++++++++++++++---------------
     frameworks_native.patch      |   74 +--
     frameworks_op_net_wifi.patch |   48 ++
     frameworks_support.patch     |  369 +++++++++++
     system_core.patch            |    8 +-
     system_sepolicy.patch        |    2 +-
     9 files changed, 2342 insertions(+), 556 deletions(-)
     create mode 100644 frameworks_op_net_wifi.patch
     create mode 100644 frameworks_support.patch
    
    diff --git a/bionic.patch b/bionic.patch
    index 625c884..07f6382 100644
    --- a/bionic.patch
    +++ b/bionic.patch
    @@ -1,3 +1,25 @@
    +diff --git a/libc/Android.bp b/libc/Android.bp
    +index 950b848..4cae16c 100644
    +--- a/libc/Android.bp
    ++++ b/libc/Android.bp
    +@@ -867,14 +867,14 @@ cc_library_static {
    +             cortex_a7: {
    +                 srcs: [
    +                     "arch-arm/cortex-a7/bionic/memset.S",
    +-                    "arch-arm/cortex-a7/bionic/memcpy.S",
    +-                    "arch-arm/cortex-a7/bionic/__strcat_chk.S",
    +-                    "arch-arm/cortex-a7/bionic/__strcpy_chk.S",
    + 
    ++                    "arch-arm/cortex-a15/bionic/memcpy.S",
    +                     "arch-arm/cortex-a15/bionic/stpcpy.S",
    +                     "arch-arm/cortex-a15/bionic/strcat.S",
    ++                    "arch-arm/cortex-a15/bionic/__strcat_chk.S",
    +                     "arch-arm/cortex-a15/bionic/strcmp.S",
    +                     "arch-arm/cortex-a15/bionic/strcpy.S",
    ++                    "arch-arm/cortex-a15/bionic/__strcpy_chk.S",
    +                     "arch-arm/cortex-a15/bionic/strlen.S",
    + 
    +                     "arch-arm/denver/bionic/memmove.S",
     diff --git a/libc/arch-arm/arm.mk b/libc/arch-arm/arm.mk
     index 76f465e..21b6152 100644
     --- a/libc/arch-arm/arm.mk
    @@ -20,6 +42,727 @@ index 76f465e..21b6152 100644
      
      #
      # Inherently architecture-specific code.
    +diff --git a/libc/arch-arm/cortex-a7/bionic/__strcat_chk.S b/libc/arch-arm/cortex-a7/bionic/__strcat_chk.S
    +deleted file mode 100644
    +index 9c44b9d..0000000
    +--- a/libc/arch-arm/cortex-a7/bionic/__strcat_chk.S
    ++++ /dev/null
    +@@ -1,214 +0,0 @@
    +-/*
    +- * Copyright (C) 2013 The Android Open Source Project
    +- * All rights reserved.
    +- *
    +- * Redistribution and use in source and binary forms, with or without
    +- * modification, are permitted provided that the following conditions
    +- * are met:
    +- *  * Redistributions of source code must retain the above copyright
    +- *    notice, this list of conditions and the following disclaimer.
    +- *  * Redistributions in binary form must reproduce the above copyright
    +- *    notice, this list of conditions and the following disclaimer in
    +- *    the documentation and/or other materials provided with the
    +- *    distribution.
    +- *
    +- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
    +- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
    +- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
    +- * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
    +- * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
    +- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
    +- * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
    +- * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
    +- * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
    +- * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
    +- * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
    +- * SUCH DAMAGE.
    +- */
    +-
    +-#include <private/bionic_asm.h>
    +-#include <private/libc_events.h>
    +-
    +-    .syntax unified
    +-
    +-    .thumb
    +-    .thumb_func
    +-
    +-// Get the length of src string, then get the source of the dst string.
    +-// Check that the two lengths together don't exceed the threshold, then
    +-// do a memcpy of the data.
    +-ENTRY(__strcat_chk)
    +-    pld     [r0, #0]
    +-    push    {r0, lr}
    +-    .cfi_def_cfa_offset 8
    +-    .cfi_rel_offset r0, 0
    +-    .cfi_rel_offset lr, 4
    +-    push    {r4, r5}
    +-    .cfi_adjust_cfa_offset 8
    +-    .cfi_rel_offset r4, 0
    +-    .cfi_rel_offset r5, 4
    +-
    +-    mov     lr, r2
    +-
    +-    // Save the dst register to r5
    +-    mov     r5, r0
    +-
    +-    // Zero out r4
    +-    eor     r4, r4, r4
    +-
    +-    // r1 contains the address of the string to count.
    +-.L_strlen_start:
    +-    mov     r0, r1
    +-    ands    r3, r1, #7
    +-    beq     .L_mainloop
    +-
    +-    // Align to a double word (64 bits).
    +-    rsb     r3, r3, #8
    +-    lsls    ip, r3, #31
    +-    beq     .L_align_to_32
    +-
    +-    ldrb    r2, [r1], #1
    +-    cbz     r2, .L_update_count_and_finish
    +-
    +-.L_align_to_32:
    +-    bcc     .L_align_to_64
    +-    ands    ip, r3, #2
    +-    beq     .L_align_to_64
    +-
    +-    ldrb    r2, [r1], #1
    +-    cbz     r2, .L_update_count_and_finish
    +-    ldrb    r2, [r1], #1
    +-    cbz     r2, .L_update_count_and_finish
    +-
    +-.L_align_to_64:
    +-    tst     r3, #4
    +-    beq     .L_mainloop
    +-    ldr     r3, [r1], #4
    +-
    +-    sub     ip, r3, #0x01010101
    +-    bic     ip, ip, r3
    +-    ands    ip, ip, #0x80808080
    +-    bne     .L_zero_in_second_register
    +-
    +-    .p2align 2
    +-.L_mainloop:
    +-    ldrd    r2, r3, [r1], #8
    +-
    +-    pld     [r1, #64]
    +-
    +-    sub     ip, r2, #0x01010101
    +-    bic     ip, ip, r2
    +-    ands    ip, ip, #0x80808080
    +-    bne     .L_zero_in_first_register
    +-
    +-    sub     ip, r3, #0x01010101
    +-    bic     ip, ip, r3
    +-    ands    ip, ip, #0x80808080
    +-    bne     .L_zero_in_second_register
    +-    b       .L_mainloop
    +-
    +-.L_update_count_and_finish:
    +-    sub     r3, r1, r0
    +-    sub     r3, r3, #1
    +-    b       .L_finish
    +-
    +-.L_zero_in_first_register:
    +-    sub     r3, r1, r0
    +-    lsls    r2, ip, #17
    +-    bne     .L_sub8_and_finish
    +-    bcs     .L_sub7_and_finish
    +-    lsls    ip, ip, #1
    +-    bne     .L_sub6_and_finish
    +-
    +-    sub     r3, r3, #5
    +-    b       .L_finish
    +-
    +-.L_sub8_and_finish:
    +-    sub     r3, r3, #8
    +-    b       .L_finish
    +-
    +-.L_sub7_and_finish:
    +-    sub     r3, r3, #7
    +-    b       .L_finish
    +-
    +-.L_sub6_and_finish:
    +-    sub     r3, r3, #6
    +-    b       .L_finish
    +-
    +-.L_zero_in_second_register:
    +-    sub     r3, r1, r0
    +-    lsls    r2, ip, #17
    +-    bne     .L_sub4_and_finish
    +-    bcs     .L_sub3_and_finish
    +-    lsls    ip, ip, #1
    +-    bne     .L_sub2_and_finish
    +-
    +-    sub     r3, r3, #1
    +-    b       .L_finish
    +-
    +-.L_sub4_and_finish:
    +-    sub     r3, r3, #4
    +-    b       .L_finish
    +-
    +-.L_sub3_and_finish:
    +-    sub     r3, r3, #3
    +-    b       .L_finish
    +-
    +-.L_sub2_and_finish:
    +-    sub     r3, r3, #2
    +-
    +-.L_finish:
    +-    cmp     r4, #0
    +-    bne     .L_strlen_done
    +-
    +-    // Time to get the dst string length.
    +-    mov     r1, r5
    +-
    +-    // Save the original source address to r5.
    +-    mov     r5, r0
    +-
    +-    // Save the current length (adding 1 for the terminator).
    +-    add     r4, r3, #1
    +-    b       .L_strlen_start
    +-
    +-    // r0 holds the pointer to the dst string.
    +-    // r3 holds the dst string length.
    +-    // r4 holds the src string length + 1.
    +-.L_strlen_done:
    +-    add     r2, r3, r4
    +-    cmp     r2, lr
    +-    itt     hi
    +-    movhi   r0, lr
    +-    bhi     .L_strcat_chk_failed
    +-
    +-    // Set up the registers for the memcpy code.
    +-    mov     r1, r5
    +-    pld     [r1, #64]
    +-    mov     r2, r4
    +-    add     r0, r0, r3
    +-    pop     {r4, r5}
    +-    .cfi_adjust_cfa_offset -8
    +-    .cfi_restore r4
    +-    .cfi_restore r5
    +-
    +-#include "memcpy_base.S"
    +-
    +-    // Undo the above cfi directives
    +-    .cfi_adjust_cfa_offset 8
    +-    .cfi_rel_offset r4, 0
    +-    .cfi_rel_offset r5, 4
    +-.L_strcat_chk_failed:
    +-    ldr     r0, error_message
    +-    ldr     r1, error_code
    +-1:
    +-    add     r0, pc
    +-    bl      __fortify_chk_fail
    +-error_code:
    +-    .word   BIONIC_EVENT_STRCAT_BUFFER_OVERFLOW
    +-error_message:
    +-    .word   error_string-(1b+4)
    +-END(__strcat_chk)
    +-
    +-    .data
    +-error_string:
    +-    .string "strcat: prevented write past end of buffer"
    +diff --git a/libc/arch-arm/cortex-a7/bionic/__strcpy_chk.S b/libc/arch-arm/cortex-a7/bionic/__strcpy_chk.S
    +deleted file mode 100644
    +index bbcb9af..0000000
    +--- a/libc/arch-arm/cortex-a7/bionic/__strcpy_chk.S
    ++++ /dev/null
    +@@ -1,176 +0,0 @@
    +-/*
    +- * Copyright (C) 2013 The Android Open Source Project
    +- * All rights reserved.
    +- *
    +- * Redistribution and use in source and binary forms, with or without
    +- * modification, are permitted provided that the following conditions
    +- * are met:
    +- *  * Redistributions of source code must retain the above copyright
    +- *    notice, this list of conditions and the following disclaimer.
    +- *  * Redistributions in binary form must reproduce the above copyright
    +- *    notice, this list of conditions and the following disclaimer in
    +- *    the documentation and/or other materials provided with the
    +- *    distribution.
    +- *
    +- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
    +- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
    +- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
    +- * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
    +- * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
    +- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
    +- * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
    +- * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
    +- * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
    +- * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
    +- * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
    +- * SUCH DAMAGE.
    +- */
    +-
    +-#include <private/bionic_asm.h>
    +-#include <private/libc_events.h>
    +-
    +-    .syntax unified
    +-
    +-    .thumb
    +-    .thumb_func
    +-
    +-// Get the length of the source string first, then do a memcpy of the data
    +-// instead of a strcpy.
    +-ENTRY(__strcpy_chk)
    +-    pld     [r0, #0]
    +-    push    {r0, lr}
    +-    .cfi_def_cfa_offset 8
    +-    .cfi_rel_offset r0, 0
    +-    .cfi_rel_offset lr, 4
    +-
    +-    mov     lr, r2
    +-    mov     r0, r1
    +-
    +-    ands    r3, r1, #7
    +-    beq     .L_mainloop
    +-
    +-    // Align to a double word (64 bits).
    +-    rsb     r3, r3, #8
    +-    lsls    ip, r3, #31
    +-    beq     .L_align_to_32
    +-
    +-    ldrb    r2, [r0], #1
    +-    cbz     r2, .L_update_count_and_finish
    +-
    +-.L_align_to_32:
    +-    bcc     .L_align_to_64
    +-    ands    ip, r3, #2
    +-    beq     .L_align_to_64
    +-
    +-    ldrb    r2, [r0], #1
    +-    cbz     r2, .L_update_count_and_finish
    +-    ldrb    r2, [r0], #1
    +-    cbz     r2, .L_update_count_and_finish
    +-
    +-.L_align_to_64:
    +-    tst     r3, #4
    +-    beq     .L_mainloop
    +-    ldr     r3, [r0], #4
    +-
    +-    sub     ip, r3, #0x01010101
    +-    bic     ip, ip, r3
    +-    ands    ip, ip, #0x80808080
    +-    bne     .L_zero_in_second_register
    +-
    +-    .p2align 2
    +-.L_mainloop:
    +-    ldrd    r2, r3, [r0], #8
    +-
    +-    pld     [r0, #64]
    +-
    +-    sub     ip, r2, #0x01010101
    +-    bic     ip, ip, r2
    +-    ands    ip, ip, #0x80808080
    +-    bne     .L_zero_in_first_register
    +-
    +-    sub     ip, r3, #0x01010101
    +-    bic     ip, ip, r3
    +-    ands    ip, ip, #0x80808080
    +-    bne     .L_zero_in_second_register
    +-    b       .L_mainloop
    +-
    +-.L_update_count_and_finish:
    +-    sub     r3, r0, r1
    +-    sub     r3, r3, #1
    +-    b       .L_check_size
    +-
    +-.L_zero_in_first_register:
    +-    sub     r3, r0, r1
    +-    lsls    r2, ip, #17
    +-    bne     .L_sub8_and_finish
    +-    bcs     .L_sub7_and_finish
    +-    lsls    ip, ip, #1
    +-    bne     .L_sub6_and_finish
    +-
    +-    sub     r3, r3, #5
    +-    b       .L_check_size
    +-
    +-.L_sub8_and_finish:
    +-    sub     r3, r3, #8
    +-    b       .L_check_size
    +-
    +-.L_sub7_and_finish:
    +-    sub     r3, r3, #7
    +-    b       .L_check_size
    +-
    +-.L_sub6_and_finish:
    +-    sub     r3, r3, #6
    +-    b       .L_check_size
    +-
    +-.L_zero_in_second_register:
    +-    sub     r3, r0, r1
    +-    lsls    r2, ip, #17
    +-    bne     .L_sub4_and_finish
    +-    bcs     .L_sub3_and_finish
    +-    lsls    ip, ip, #1
    +-    bne     .L_sub2_and_finish
    +-
    +-    sub     r3, r3, #1
    +-    b       .L_check_size
    +-
    +-.L_sub4_and_finish:
    +-    sub     r3, r3, #4
    +-    b       .L_check_size
    +-
    +-.L_sub3_and_finish:
    +-    sub     r3, r3, #3
    +-    b       .L_check_size
    +-
    +-.L_sub2_and_finish:
    +-    sub     r3, r3, #2
    +-
    +-.L_check_size:
    +-    pld     [r1, #0]
    +-    pld     [r1, #64]
    +-    ldr     r0, [sp]
    +-
    +-    // Add 1 for copy length to get the string terminator.
    +-    add     r2, r3, #1
    +-
    +-    cmp     r2, lr
    +-    itt     hi
    +-    movhi   r0, r2
    +-    bhi     .L_strcpy_chk_failed
    +-
    +-#include "memcpy_base.S"
    +-
    +-.L_strcpy_chk_failed:
    +-    ldr     r0, error_message
    +-    ldr     r1, error_code
    +-1:
    +-    add     r0, pc
    +-    bl      __fortify_chk_fail
    +-error_code:
    +-    .word   BIONIC_EVENT_STRCPY_BUFFER_OVERFLOW
    +-error_message:
    +-    .word   error_string-(1b+4)
    +-END(__strcpy_chk)
    +-
    +-    .data
    +-error_string:
    +-    .string "strcpy: prevented write past end of buffer"
    +diff --git a/libc/arch-arm/cortex-a7/bionic/memcpy.S b/libc/arch-arm/cortex-a7/bionic/memcpy.S
    +deleted file mode 100644
    +index 4d76989..0000000
    +--- a/libc/arch-arm/cortex-a7/bionic/memcpy.S
    ++++ /dev/null
    +@@ -1,107 +0,0 @@
    +-/*
    +- * Copyright (C) 2008 The Android Open Source Project
    +- * All rights reserved.
    +- *
    +- * Redistribution and use in source and binary forms, with or without
    +- * modification, are permitted provided that the following conditions
    +- * are met:
    +- *  * Redistributions of source code must retain the above copyright
    +- *    notice, this list of conditions and the following disclaimer.
    +- *  * Redistributions in binary form must reproduce the above copyright
    +- *    notice, this list of conditions and the following disclaimer in
    +- *    the documentation and/or other materials provided with the
    +- *    distribution.
    +- *
    +- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
    +- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
    +- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
    +- * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
    +- * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
    +- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
    +- * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
    +- * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
    +- * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
    +- * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
    +- * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
    +- * SUCH DAMAGE.
    +- */
    +-/*
    +- * Copyright (c) 2013 ARM Ltd
    +- * All rights reserved.
    +- *
    +- * Redistribution and use in source and binary forms, with or without
    +- * modification, are permitted provided that the following conditions
    +- * are met:
    +- * 1. Redistributions of source code must retain the above copyright
    +- *    notice, this list of conditions and the following disclaimer.
    +- * 2. Redistributions in binary form must reproduce the above copyright
    +- *    notice, this list of conditions and the following disclaimer in the
    +- *    documentation and/or other materials provided with the distribution.
    +- * 3. The name of the company may not be used to endorse or promote
    +- *    products derived from this software without specific prior written
    +- *    permission.
    +- *
    +- * THIS SOFTWARE IS PROVIDED BY ARM LTD ``AS IS'' AND ANY EXPRESS OR IMPLIED
    +- * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
    +- * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
    +- * IN NO EVENT SHALL ARM LTD BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
    +- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
    +- * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
    +- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
    +- * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
    +- * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
    +- * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
    +- */
    +-
    +-#include <private/bionic_asm.h>
    +-#include <private/libc_events.h>
    +-
    +-        .text
    +-        .syntax unified
    +-        .fpu    neon
    +-
    +-ENTRY(__memcpy_chk)
    +-        cmp r2, r3
    +-        bls memcpy
    +-
    +-        // Preserve lr for backtrace.
    +-        push        {lr}
    +-        .cfi_def_cfa_offset 4
    +-        .cfi_rel_offset lr, 0
    +-        bl          .L_memcpy_chk_fail
    +-END(__memcpy_chk)
    +-
    +-// Prototype: void *memcpy (void *dst, const void *src, size_t count).
    +-ENTRY(memcpy)
    +-        pld     [r1, #64]
    +-        push    {r0, lr}
    +-        .cfi_def_cfa_offset 8
    +-        .cfi_rel_offset r0, 0
    +-        .cfi_rel_offset lr, 4
    +-
    +-#include "memcpy_base.S"
    +-
    +-        // Undo the cfi instructions from above.
    +-        .cfi_def_cfa_offset 0
    +-        .cfi_restore r0
    +-        .cfi_restore lr
    +-.L_memcpy_chk_fail:
    +-        // Preserve lr for backtrace.
    +-        push    {lr}
    +-        .cfi_adjust_cfa_offset 4
    +-        .cfi_rel_offset lr, 0
    +-
    +-        ldr     r0, error_message
    +-        ldr     r1, error_code
    +-1:
    +-        add     r0, pc
    +-        bl      __fortify_chk_fail
    +-error_code:
    +-        .word   BIONIC_EVENT_MEMCPY_BUFFER_OVERFLOW
    +-error_message:
    +-        .word   error_string-(1b+8)
    +-END(memcpy)
    +-
    +-        .data
    +-error_string:
    +-        .string "memcpy: prevented write past end of buffer"
    +diff --git a/libc/arch-arm/cortex-a7/bionic/memcpy_base.S b/libc/arch-arm/cortex-a7/bionic/memcpy_base.S
    +deleted file mode 100644
    +index 4ff982b..0000000
    +--- a/libc/arch-arm/cortex-a7/bionic/memcpy_base.S
    ++++ /dev/null
    +@@ -1,176 +0,0 @@
    +-/*
    +- * Copyright (C) 2008 The Android Open Source Project
    +- * All rights reserved.
    +- *
    +- * Redistribution and use in source and binary forms, with or without
    +- * modification, are permitted provided that the following conditions
    +- * are met:
    +- *  * Redistributions of source code must retain the above copyright
    +- *    notice, this list of conditions and the following disclaimer.
    +- *  * Redistributions in binary form must reproduce the above copyright
    +- *    notice, this list of conditions and the following disclaimer in
    +- *    the documentation and/or other materials provided with the
    +- *    distribution.
    +- *
    +- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
    +- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
    +- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
    +- * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
    +- * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
    +- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
    +- * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
    +- * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
    +- * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
    +- * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
    +- * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
    +- * SUCH DAMAGE.
    +- */
    +-/*
    +- * Copyright (c) 2013 ARM Ltd
    +- * All rights reserved.
    +- *
    +- * Redistribution and use in source and binary forms, with or without
    +- * modification, are permitted provided that the following conditions
    +- * are met:
    +- * 1. Redistributions of source code must retain the above copyright
    +- *    notice, this list of conditions and the following disclaimer.
    +- * 2. Redistributions in binary form must reproduce the above copyright
    +- *    notice, this list of conditions and the following disclaimer in the
    +- *    documentation and/or other materials provided with the distribution.
    +- * 3. The name of the company may not be used to endorse or promote
    +- *    products derived from this software without specific prior written
    +- *    permission.
    +- *
    +- * THIS SOFTWARE IS PROVIDED BY ARM LTD ``AS IS'' AND ANY EXPRESS OR IMPLIED
    +- * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
    +- * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
    +- * IN NO EVENT SHALL ARM LTD BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
    +- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
    +- * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
    +- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
    +- * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
    +- * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
    +- * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
    +- */
    +-
    +-.L_memcpy_base:
    +-        // Assumes that n >= 0, and dst, src are valid pointers.
    +-        // For any sizes less than 832 use the neon code that doesn't
    +-        // care about the src alignment. This avoids any checks
    +-        // for src alignment, and offers the best improvement since
    +-        // smaller sized copies are dominated by the overhead of
    +-        // the pre and post main loop.
    +-        // For larger copies, if src and dst cannot both be aligned to
    +-        // word boundaries, use the neon code.
    +-        // For all other copies, align dst to a double word boundary
    +-        // and copy using LDRD/STRD instructions.
    +-
    +-        cmp     r2, #16
    +-        blo     .L_copy_less_than_16_unknown_align
    +-
    +-.L_copy_unknown_alignment:
    +-        // Unknown alignment of src and dst.
    +-        // Assumes that the first few bytes have already been prefetched.
    +-
    +-        // Align destination to 128 bits. The mainloop store instructions
    +-        // require this alignment or they will throw an exception.
    +-        rsb         r3, r0, #0
    +-        ands        r3, r3, #0xF
    +-        beq         2f
    +-
    +-        // Copy up to 15 bytes (count in r3).
    +-        sub         r2, r2, r3
    +-        movs        ip, r3, lsl #31
    +-
    +-        itt         mi
    +-        ldrbmi      lr, [r1], #1
    +-        strbmi      lr, [r0], #1
    +-        itttt       cs
    +-        ldrbcs      ip, [r1], #1
    +-        ldrbcs      lr, [r1], #1
    +-        strbcs      ip, [r0], #1
    +-        strbcs      lr, [r0], #1
    +-
    +-        movs        ip, r3, lsl #29
    +-        bge         1f
    +-        // Copies 4 bytes, dst 32 bits aligned before, at least 64 bits after.
    +-        vld4.8      {d0[0], d1[0], d2[0], d3[0]}, [r1]!
    +-        vst4.8      {d0[0], d1[0], d2[0], d3[0]}, [r0, :32]!
    +-1:      bcc         2f
    +-        // Copies 8 bytes, dst 64 bits aligned before, at least 128 bits after.
    +-        vld1.8      {d0}, [r1]!
    +-        vst1.8      {d0}, [r0, :64]!
    +-
    +-2:      cmp         r2, #256
    +-        ble         .L_copy_loop
    +-
    +-        // Make sure DST is 64 BYTE aligned.
    +-        rsb         r3, r0, #0
    +-        ands        r3, r3, #0x30
    +-        beq         .L_copy_loop
    +-
    +-        sub         r2, r2, r3
    +-        cmp         r3, #0x10
    +-        beq         .L_copy_16
    +-
    +-        vld1.8      {d0  - d3},   [r1]!
    +-        vst1.8      {d0  - d3},   [r0, :128]!
    +-        ands        r3, r3, #0x10
    +-        beq         .L_copy_loop
    +-
    +-.L_copy_16:
    +-        vld1.8      {d0, d1}, [r1]!
    +-        vst1.8      {d0, d1}, [r0, :128]!
    +-
    +-.L_copy_loop:
    +-        // Make sure we have at least 64 bytes to copy.
    +-        subs        r2, r2, #64
    +-        blo         2f
    +-
    +-1:      // The main loop copies 64 bytes at a time.
    +-        vld1.8      {d0  - d3},   [r1]!
    +-        vst1.8      {d0  - d3},   [r0, :128]!
    +-        pld         [r1, #(64*4)]
    +-        subs        r2, r2, #64
    +-        vld1.8      {d4  - d7},   [r1]!
    +-        vst1.8      {d4  - d7},   [r0, :128]!
    +-        bhs         1b
    +-
    +-2:      // Fix-up the remaining count and make sure we have >= 32 bytes left.
    +-        adds        r2, r2, #32
    +-        blo         3f
    +-
    +-        // 32 bytes. These cache lines were already preloaded.
    +-        vld1.8      {d0 - d3},  [r1]!
    +-        sub         r2, r2, #32
    +-        vst1.8      {d0 - d3},  [r0, :128]!
    +-3:      // Less than 32 left.
    +-        add         r2, r2, #32
    +-        tst         r2, #0x10
    +-        beq         .L_copy_less_than_16_unknown_align
    +-        // Copies 16 bytes, destination 128 bits aligned.
    +-        vld1.8      {d0, d1}, [r1]!
    +-        vst1.8      {d0, d1}, [r0, :128]!
    +-
    +-.L_copy_less_than_16_unknown_align:
    +-        // Copy up to 15 bytes (count in r2).
    +-        movs        ip, r2, lsl #29
    +-        bcc         1f
    +-        vld1.8      {d0}, [r1]!
    +-        vst1.8      {d0}, [r0]!
    +-1:      bge         2f
    +-        vld4.8      {d0[0], d1[0], d2[0], d3[0]}, [r1]!
    +-        vst4.8      {d0[0], d1[0], d2[0], d3[0]}, [r0]!
    +-
    +-2:      // Copy 0 to 4 bytes.
    +-        lsls        r2, r2, #31
    +-        itt         ne
    +-        ldrbne      lr, [r1], #1
    +-        strbne      lr, [r0], #1
    +-        itttt       cs
    +-        ldrbcs      ip, [r1], #1
    +-        ldrbcs      lr, [r1]
    +-        strbcs      ip, [r0], #1
    +-        strbcs      lr, [r0]
    +-
    +-        pop         {r0, pc}
    +diff --git a/libc/arch-arm/cortex-a7/cortex-a7.mk b/libc/arch-arm/cortex-a7/cortex-a7.mk
    +index 199eb11..f570d0f 100644
    +--- a/libc/arch-arm/cortex-a7/cortex-a7.mk
    ++++ b/libc/arch-arm/cortex-a7/cortex-a7.mk
    +@@ -13,16 +13,16 @@ libc_bionic_src_files_exclude_arm += \
    +     bionic/__strcpy_chk.cpp \
    + 
    + libc_bionic_src_files_arm += \
    +-    arch-arm/cortex-a7/bionic/memcpy.S \
    +     arch-arm/cortex-a7/bionic/memset.S \
    +-    arch-arm/cortex-a7/bionic/__strcat_chk.S \
    +-    arch-arm/cortex-a7/bionic/__strcpy_chk.S \
    + 
    + libc_bionic_src_files_arm += \
    ++    arch-arm/cortex-a15/bionic/memcpy.S \
    +     arch-arm/cortex-a15/bionic/stpcpy.S \
    +     arch-arm/cortex-a15/bionic/strcat.S \
    ++    arch-arm/cortex-a15/bionic/__strcat_chk.S \
    +     arch-arm/cortex-a15/bionic/strcmp.S \
    +     arch-arm/cortex-a15/bionic/strcpy.S \
    ++    arch-arm/cortex-a15/bionic/__strcpy_chk.S \
    +     arch-arm/cortex-a15/bionic/strlen.S \
    + 
    + libc_bionic_src_files_arm += \
     diff --git a/libc/arch-arm/generic/bionic/memchr.S b/libc/arch-arm/generic/bionic/memchr.S
     new file mode 100644
     index 0000000..cb00d82
    @@ -181,6 +924,22 @@ index 0000000..cb00d82
     +	subs	r0,r0,#1
     +	bx	lr
     +END(memchr)
    +diff --git a/libc/malloc_debug/backtrace.cpp b/libc/malloc_debug/backtrace.cpp
    +index 75a255c..18ce8b8 100644
    +--- a/libc/malloc_debug/backtrace.cpp
    ++++ b/libc/malloc_debug/backtrace.cpp
    +@@ -142,8 +142,6 @@ std::string backtrace_string(const uintptr_t* frames, size_t frame_count) {
    +     if (dladdr(reinterpret_cast<void*>(frames[frame_num]), &info) != 0) {
    +       offset = reinterpret_cast<uintptr_t>(info.dli_saddr);
    +       symbol = info.dli_sname;
    +-    } else {
    +-      info.dli_fname = nullptr;
    +     }
    + 
    +     uintptr_t rel_pc = offset;
    +diff --git a/libc/zoneinfo/tzdata b/libc/zoneinfo/tzdata
    +index 577ede6..57bff7b 100644
    +Binary files a/libc/zoneinfo/tzdata and b/libc/zoneinfo/tzdata differ
     diff --git a/linker/Android.mk b/linker/Android.mk
     index 4a4ca5c..0d592c9 100644
     --- a/linker/Android.mk
    @@ -220,3 +979,59 @@ index 9dc928e..2a665b5 100644
          // Make segments writable to allow text relocations to work properly. We will later call
          // phdr_table_protect_segments() after all of them are applied.
          DL_WARN("%s has text relocations. This is wasting memory and prevents "
    +diff --git a/tests/sys_prctl_test.cpp b/tests/sys_prctl_test.cpp
    +index f0ac1c3..5a563c1 100644
    +--- a/tests/sys_prctl_test.cpp
    ++++ b/tests/sys_prctl_test.cpp
    +@@ -14,19 +14,11 @@
    +  * limitations under the License.
    +  */
    + 
    +-#include <inttypes.h>
    +-#include <stdio.h>
    ++#include <gtest/gtest.h>
    ++
    + #include <sys/mman.h>
    + #include <sys/prctl.h>
    + #include <unistd.h>
    +-
    +-#include <string>
    +-#include <vector>
    +-
    +-#include <gtest/gtest.h>
    +-
    +-#include "android-base/file.h"
    +-#include "android-base/strings.h"
    + #include "private/bionic_prctl.h"
    + 
    + // http://b/20017123.
    +@@ -37,26 +29,9 @@ TEST(sys_prctl, bug_20017123) {
    +   ASSERT_NE(MAP_FAILED, p);
    +   ASSERT_EQ(0, mprotect(p, page_size, PROT_NONE));
    +   ASSERT_NE(-1, prctl(PR_SET_VMA, PR_SET_VMA_ANON_NAME, p, page_size * 3, "anonymous map space"));
    +-  // Now read the maps and verify that there are no overlapped maps.
    +-  std::string file_data;
    +-  ASSERT_TRUE(android::base::ReadFileToString("/proc/self/maps", &file_data));
    +-
    +-  uintptr_t last_end = 0;
    +-  std::vector<std::string> lines = android::base::Split(file_data, "\n");
    +-  for (size_t i = 0; i < lines.size(); i++) {
    +-    if (lines[i].empty()) {
    +-      continue;
    +-    }
    +-    uintptr_t start;
    +-    uintptr_t end;
    +-    ASSERT_EQ(2, sscanf(lines[i].c_str(), "%" SCNxPTR "-%" SCNxPTR " ", &start, &end))
    +-        << "Failed to parse line: " << lines[i];
    +-    // This will never fail on the first line, so no need to do any special checking.
    +-    ASSERT_GE(start, last_end)
    +-        << "Overlapping map detected:\n" << lines[i -1] << '\n' << lines[i] << '\n';
    +-    last_end = end;
    +-  }
    +-
    ++  volatile char* vp = reinterpret_cast<volatile char*>(p);
    ++  // Below memory access causes SEGV if the memory map is screwed up.
    ++  *(vp + page_size) = 0;
    +   ASSERT_EQ(0, munmap(p, page_size * 3));
    + #else
    +   GTEST_LOG_(INFO) << "This test does nothing as it tests an Android specific kernel feature.";
    diff --git a/build.patch b/build.patch
    index 074d519..b8262af 100644
    --- a/build.patch
    +++ b/build.patch
    @@ -1,3 +1,105 @@
    +diff --git a/core/build_id.mk.orig b/core/build_id.mk.orig
    +new file mode 100644
    +index 0000000..e508d48
    +--- /dev/null
    ++++ b/core/build_id.mk.orig
    +@@ -0,0 +1,25 @@
    ++#
    ++# 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.
    ++#
    ++# BUILD_ID is usually used to specify the branch name
    ++# (like "MAIN") or a branch name and a release candidate
    ++# (like "CRB01").  It must be a single word, and is
    ++# capitalized by convention.
    ++
    ++<<<<<<< HEAD
    ++export BUILD_ID=NOF27B
    ++=======
    ++export BUILD_ID=N2G47J
    ++>>>>>>> android-7.1.2_r5
    +diff --git a/core/combo/arch/arm/armv7-a-neon.mk b/core/combo/arch/arm/armv7-a-neon.mk
    +index 5d5b050..b0e1e25 100644
    +--- a/core/combo/arch/arm/armv7-a-neon.mk
    ++++ b/core/combo/arch/arm/armv7-a-neon.mk
    +@@ -8,36 +8,48 @@ ARCH_ARM_HAVE_NEON              := true
    + 
    + local_arch_has_lpae := false
    + 
    +-ifneq (,$(filter cortex-a15 krait denver,$(TARGET_$(combo_2nd_arch_prefix)CPU_VARIANT)))
    ++ifneq (,$(filter cortex-a15 denver krait,$(TARGET_$(combo_2nd_arch_prefix)CPU_VARIANT)))
    + 	# TODO: krait is not a cortex-a15, we set the variant to cortex-a15 so that
    + 	#       hardware divide operations are generated. This should be removed and a
    + 	#       krait CPU variant added to GCC. For clang we specify -mcpu for krait in
    + 	#       core/clang/arm.mk.
    +-	arch_variant_cflags := -mcpu=cortex-a15
    ++	arch_variant_cflags := -mcpu=cortex-a15 -mfpu=neon-vfpv4
    + 
    + 	local_arch_has_lpae := true
    + 	arch_variant_ldflags := \
    + 		-Wl,--no-fix-cortex-a8
    + else
    +-ifeq ($(strip $(TARGET_$(combo_2nd_arch_prefix)CPU_VARIANT)),cortex-a8)
    +-	arch_variant_cflags := -mcpu=cortex-a8
    ++ifeq ($(strip $(TARGET_$(combo_2nd_arch_prefix)CPU_VARIANT)),cortex-a9)
    ++	arch_variant_cflags := -mcpu=cortex-a9 -mfpu=neon
    ++	arch_variant_ldflags := \
    ++		-Wl,--no-fix-cortex-a8
    ++else
    ++ifneq (,$(filter cortex-a8 scorpion,$(TARGET_$(combo_2nd_arch_prefix)CPU_VARIANT)))
    ++	arch_variant_cflags := -mcpu=cortex-a8 -mfpu=neon
    + 	arch_variant_ldflags := \
    + 		-Wl,--fix-cortex-a8
    + else
    + ifneq (,$(filter cortex-a7 cortex-a53 cortex-a53.a57,$(TARGET_$(combo_2nd_arch_prefix)CPU_VARIANT)))
    +-	arch_variant_cflags := -mcpu=cortex-a7
    ++	arch_variant_cflags := -mcpu=cortex-a7 -mfpu=neon-vfpv4
    + 
    + 	local_arch_has_lpae := true
    + 	arch_variant_ldflags := \
    + 		-Wl,--no-fix-cortex-a8
    + else
    +-	arch_variant_cflags := -march=armv7-a
    ++ifeq ($(strip $(TARGET_$(combo_2nd_arch_prefix)CPU_VARIANT)),cortex-a5)
    ++	arch_variant_cflags := -mcpu=cortex-a7 -mfpu=neon-vfpv4
    ++	arch_variant_ldflags := \
    ++		-Wl,--no-fix-cortex-a8
    ++else
    ++	arch_variant_cflags := -march=armv7-a -mfpu=neon
    + 	# Generic ARM might be a Cortex A8 -- better safe than sorry
    + 	arch_variant_ldflags := \
    + 		-Wl,--fix-cortex-a8
    + endif
    + endif
    + endif
    ++endif
    ++endif
    + 
    + ifeq (true,$(local_arch_has_lpae))
    + 	# Fake an ARM compiler flag as these processors support LPAE which GCC/clang
    +@@ -50,5 +62,9 @@ endif
    + local_arch_has_lpae :=
    + 
    + arch_variant_cflags += \
    +-    -mfloat-abi=softfp \
    +-    -mfpu=neon
    ++	-mfloat-abi=softfp
    ++
    ++ifneq ($(strip $(TARGET_$(combo_2nd_arch_prefix)FPU_VARIANT)),)
    ++arch_variant_cflags += \
    ++	-mfpu=$(TARGET_$(combo_2nd_arch_prefix)FPU_VARIANT)
    ++endif
     diff --git a/core/main.mk b/core/main.mk
     index a612f83..921eb32 100644
     --- a/core/main.mk
    @@ -213,6 +315,193 @@ index 0000000..ee76dc2
     +
     +ALL_PREBUILT += $(INSTALLED_KERNEL_TARGET)
     +endif
    +diff --git a/core/version_defaults.mk.orig b/core/version_defaults.mk.orig
    +new file mode 100644
    +index 0000000..9720bb1
    +--- /dev/null
    ++++ b/core/version_defaults.mk.orig
    +@@ -0,0 +1,181 @@
    ++#
    ++# 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.
    ++#
    ++
    ++#
    ++# Handle various build version information.
    ++#
    ++# Guarantees that the following are defined:
    ++#     PLATFORM_VERSION
    ++#     PLATFORM_SDK_VERSION
    ++#     PLATFORM_VERSION_CODENAME
    ++#     DEFAULT_APP_TARGET_SDK
    ++#     BUILD_ID
    ++#     BUILD_NUMBER
    ++#     BUILD_DATETIME
    ++#     PLATFORM_SECURITY_PATCH
    ++#
    ++
    ++# Look for an optional file containing overrides of the defaults,
    ++# but don't cry if we don't find it.  We could just use -include, but
    ++# the build.prop target also wants INTERNAL_BUILD_ID_MAKEFILE to be set
    ++# if the file exists.
    ++#
    ++INTERNAL_BUILD_ID_MAKEFILE := $(wildcard $(BUILD_SYSTEM)/build_id.mk)
    ++ifneq "" "$(INTERNAL_BUILD_ID_MAKEFILE)"
    ++  include $(INTERNAL_BUILD_ID_MAKEFILE)
    ++endif
    ++
    ++ifeq "" "$(PLATFORM_VERSION)"
    ++  # This is the canonical definition of the platform version,
    ++  # which is the version that we reveal to the end user.
    ++  # Update this value when the platform version changes (rather
    ++  # than overriding it somewhere else).  Can be an arbitrary string.
    ++
    ++  # When you add a new PLATFORM_VERSION which will result in a new
    ++  # PLATFORM_SDK_VERSION please ensure you add a corresponding isAtLeast*
    ++  # method in the following java file:
    ++  # frameworks/support/compat/gingerbread/android/support/v4/os/BuildCompat.java
    ++
    ++  # When you change PLATFORM_VERSION for a given PLATFORM_SDK_VERSION
    ++  # please add that PLATFORM_VERSION to the following text file:
    ++  # cts/tests/tests/os/assets/platform_versions.txt
    ++  PLATFORM_VERSION := 7.1.2
    ++endif
    ++
    ++ifeq "" "$(PLATFORM_SDK_VERSION)"
    ++  # This is the canonical definition of the SDK version, which defines
    ++  # the set of APIs and functionality available in the platform.  It
    ++  # is a single integer that increases monotonically as updates to
    ++  # the SDK are released.  It should only be incremented when the APIs for
    ++  # the new release are frozen (so that developers don't write apps against
    ++  # intermediate builds).  During development, this number remains at the
    ++  # SDK version the branch is based on and PLATFORM_VERSION_CODENAME holds
    ++  # the code-name of the new development work.
    ++
    ++  # When you change PLATFORM_SDK_VERSION please ensure you also update the
    ++  # corresponding methods for isAtLeast* in the following java file:
    ++  # frameworks/support/compat/gingerbread/android/support/v4/os/BuildCompat.java
    ++
    ++  # When you increment the PLATFORM_SDK_VERSION please ensure you also
    ++  # clear out the following text file of all older PLATFORM_VERSION's:
    ++  # cts/tests/tests/os/assets/platform_versions.txt
    ++  PLATFORM_SDK_VERSION := 25
    ++endif
    ++
    ++ifeq "" "$(PLATFORM_JACK_MIN_SDK_VERSION)"
    ++  # This is definition of the min SDK version given to Jack for the current
    ++  # platform. For released version it should be the same as
    ++  # PLATFORM_SDK_VERSION. During development, this number may be incremented
    ++  # before PLATFORM_SDK_VERSION if the plateform starts to add new java
    ++  # language supports.
    ++  PLATFORM_JACK_MIN_SDK_VERSION := 25
    ++endif
    ++
    ++ifeq "" "$(PLATFORM_VERSION_CODENAME)"
    ++  # This is the current development code-name, if the build is not a final
    ++  # release build.  If this is a final release build, it is simply "REL".
    ++  PLATFORM_VERSION_CODENAME := REL
    ++
    ++  # This is all of the development codenames that are active.  Should be either
    ++  # the same as PLATFORM_VERSION_CODENAME or a comma-separated list of additional
    ++  # codenames after PLATFORM_VERSION_CODENAME.
    ++  PLATFORM_VERSION_ALL_CODENAMES := $(PLATFORM_VERSION_CODENAME)
    ++endif
    ++
    ++ifeq "REL" "$(PLATFORM_VERSION_CODENAME)"
    ++  PLATFORM_PREVIEW_SDK_VERSION := 0
    ++else
    ++  ifeq "" "$(PLATFORM_PREVIEW_SDK_VERSION)"
    ++    # This is the definition of a preview SDK version over and above the current
    ++    # platform SDK version. Unlike the platform SDK version, a higher value
    ++    # for preview SDK version does NOT mean that all prior preview APIs are
    ++    # included. Packages reading this value to determine compatibility with
    ++    # known APIs should check that this value is precisely equal to the preview
    ++    # SDK version the package was built for, otherwise it should fall back to
    ++    # assuming the device can only support APIs as of the previous official
    ++    # public release.
    ++    # This value will always be 0 for release builds.
    ++    PLATFORM_PREVIEW_SDK_VERSION := 0
    ++  endif
    ++endif
    ++
    ++ifeq "" "$(DEFAULT_APP_TARGET_SDK)"
    ++  # This is the default minSdkVersion and targetSdkVersion to use for
    ++  # all .apks created by the build system.  It can be overridden by explicitly
    ++  # setting these in the .apk's AndroidManifest.xml.  It is either the code
    ++  # name of the development build or, if this is a release build, the official
    ++  # SDK version of this release.
    ++  ifeq "REL" "$(PLATFORM_VERSION_CODENAME)"
    ++    DEFAULT_APP_TARGET_SDK := $(PLATFORM_SDK_VERSION)
    ++  else
    ++    DEFAULT_APP_TARGET_SDK := $(PLATFORM_VERSION_CODENAME)
    ++  endif
    ++endif
    ++
    ++ifeq "" "$(PLATFORM_SECURITY_PATCH)"
    ++    #  Used to indicate the security patch that has been applied to the device.
    ++    #  It must signify that the build includes all security patches issued up through the designated Android Public Security Bulletin.
    ++    #  It must be of the form "YYYY-MM-DD" on production devices.
    ++    #  It must match one of the Android Security Patch Level strings of the Public Security Bulletins.
    ++    #  If there is no $PLATFORM_SECURITY_PATCH set, keep it empty.
    ++<<<<<<< HEAD
    ++      PLATFORM_SECURITY_PATCH := 2017-03-05
    ++=======
    ++      PLATFORM_SECURITY_PATCH := 2017-04-05
    ++>>>>>>> android-7.1.2_r5
    ++endif
    ++
    ++ifeq "" "$(PLATFORM_BASE_OS)"
    ++  # Used to indicate the base os applied to the device.
    ++  # Can be an arbitrary string, but must be a single word.
    ++  #
    ++  # If there is no $PLATFORM_BASE_OS set, keep it empty.
    ++  PLATFORM_BASE_OS :=
    ++endif
    ++
    ++ifeq "" "$(BUILD_ID)"
    ++  # Used to signify special builds.  E.g., branches and/or releases,
    ++  # like "M5-RC7".  Can be an arbitrary string, but must be a single
    ++  # word and a valid file name.
    ++  #
    ++  # If there is no BUILD_ID set, make it obvious.
    ++  BUILD_ID := UNKNOWN
    ++endif
    ++
    ++ifeq "" "$(BUILD_DATETIME)"
    ++  # Used to reproduce builds by setting the same time. Must be the number
    ++  # of seconds since the Epoch.
    ++  BUILD_DATETIME := $(shell date +%s)
    ++endif
    ++
    ++ifneq (,$(findstring Darwin,$(shell uname -sm)))
    ++DATE := date -r $(BUILD_DATETIME)
    ++else
    ++DATE := date -d @$(BUILD_DATETIME)
    ++endif
    ++
    ++ifeq "" "$(BUILD_NUMBER)"
    ++  # BUILD_NUMBER should be set to the source control value that
    ++  # represents the current state of the source code.  E.g., a
    ++  # perforce changelist number or a git hash.  Can be an arbitrary string
    ++  # (to allow for source control that uses something other than numbers),
    ++  # but must be a single word and a valid file name.
    ++  #
    ++  # If no BUILD_NUMBER is set, create a useful "I am an engineering build
    ++  # from this date/time" value.  Make it start with a non-digit so that
    ++  # anyone trying to parse it as an integer will probably get "0".
    ++  BUILD_NUMBER := eng.$(shell echo $${USER:0:6}).$(shell $(DATE) +%Y%m%d.%H%M%S)
    ++endif
     diff --git a/core/version_defaults_BACKUP_20377.mk b/core/version_defaults_BACKUP_20377.mk
     new file mode 100644
     index 0000000..eb97b11
    diff --git a/frameworks_av.patch b/frameworks_av.patch
    index 97781f3..bc42afd 100644
    --- a/frameworks_av.patch
    +++ b/frameworks_av.patch
    @@ -52,6 +52,17 @@ index 7e36c5e..aca7a19 100644
      
      include $(BUILD_EXECUTABLE)
     +endif
    +diff --git a/camera/cameraserver/main_cameraserver.cpp b/camera/cameraserver/main_cameraserver.cpp
    +index f4be468..ea80ad4 100644
    +--- a/camera/cameraserver/main_cameraserver.cpp
    ++++ b/camera/cameraserver/main_cameraserver.cpp
    +@@ -31,5 +31,6 @@ int main(int argc __unused, char** argv __unused)
    +     ALOGI("ServiceManager: %p", sm.get());
    +     CameraService::instantiate();
    +     ProcessState::self()->startThreadPool();
    ++    IPCThreadState::self()->disableBackgroundScheduling(true);
    +     IPCThreadState::self()->joinThreadPool();
    + }
     diff --git a/camera/ndk/NdkCaptureRequest.cpp b/camera/ndk/NdkCaptureRequest.cpp
     index 77b9a33..7c37955 100644
     --- a/camera/ndk/NdkCaptureRequest.cpp
    @@ -126,7 +137,7 @@ index dc4e5d4..b64d899 100644
      
      void NuPlayer::determineAudioModeChange(const sp<AMessage> &audioFormat) {
     diff --git a/media/libstagefright/ACodec.cpp b/media/libstagefright/ACodec.cpp
    -index 37fd5a5..77a2a39 100644
    +index 37fd5a5..337fb2d 100644
     --- a/media/libstagefright/ACodec.cpp
     +++ b/media/libstagefright/ACodec.cpp
     @@ -804,13 +804,22 @@ status_t ACodec::allocateBuffersOnPort(OMX_U32 portIndex) {
    @@ -152,7 +163,30 @@ index 37fd5a5..77a2a39 100644
                      bufSize = max(sizeof(VideoGrallocMetadata), sizeof(VideoNativeMetadata));
                  } else if (portIndex == kPortIndexInput && type == kMetadataBufferTypeCameraSource) {
                      bufSize = max(bufSize, sizeof(VideoNativeMetadata));
    -@@ -1766,6 +1775,14 @@ status_t ACodec::configureCodec(
    +@@ -1052,6 +1061,12 @@ status_t ACodec::configureOutputBuffersFromNativeWindow(
    +     // 2. try to allocate two (2) additional buffers to reduce starvation from
    +     //    the consumer
    +     //    plus an extra buffer to account for incorrect minUndequeuedBufs
    ++#ifdef BOARD_CANT_REALLOCATE_OMX_BUFFERS
    ++    // Some devices don't like to set OMX_IndexParamPortDefinition at this
    ++    // point (even with an unmodified def), so skip it if possible.
    ++    // This check was present in KitKat.
    ++    if (def.nBufferCountActual < def.nBufferCountMin + *minUndequeuedBuffers) {
    ++#endif
    +     for (OMX_U32 extraBuffers = 2 + 1; /* condition inside loop */; extraBuffers--) {
    +         OMX_U32 newBufferCount =
    +             def.nBufferCountMin + *minUndequeuedBuffers + extraBuffers;
    +@@ -1071,6 +1086,9 @@ status_t ACodec::configureOutputBuffersFromNativeWindow(
    +             return err;
    +         }
    +     }
    ++#ifdef BOARD_CANT_REALLOCATE_OMX_BUFFERS
    ++    }
    ++#endif
    + 
    +     err = native_window_set_buffer_count(
    +             mNativeWindow.get(), def.nBufferCountActual);
    +@@ -1766,6 +1784,14 @@ status_t ACodec::configureCodec(
                  mInputMetadataType = (MetadataBufferType)storeMeta;
              }
      
    @@ -167,7 +201,7 @@ index 37fd5a5..77a2a39 100644
              uint32_t usageBits;
              if (mOMX->getParameter(
                      mNode, (OMX_INDEXTYPE)OMX_IndexParamConsumerUsageBits,
    -@@ -4274,7 +4291,9 @@ status_t ACodec::setupAVCEncoderParameters(const sp<AMessage> &msg) {
    +@@ -4274,7 +4300,9 @@ status_t ACodec::setupAVCEncoderParameters(const sp<AMessage> &msg) {
      
              h264type.eProfile = static_cast<OMX_VIDEO_AVCPROFILETYPE>(profile);
              h264type.eLevel = static_cast<OMX_VIDEO_AVCLEVELTYPE>(level);
    @@ -178,7 +212,7 @@ index 37fd5a5..77a2a39 100644
              h264type.eProfile = OMX_VIDEO_AVCProfileBaseline;
      #if 0   /* DON'T YET DEFAULT TO HIGHEST PROFILE */
              // Use largest supported profile for AVC recording if profile is not specified.
    -@@ -4287,6 +4306,7 @@ status_t ACodec::setupAVCEncoderParameters(const sp<AMessage> &msg) {
    +@@ -4287,6 +4315,7 @@ status_t ACodec::setupAVCEncoderParameters(const sp<AMessage> &msg) {
              }
      #endif
          }
    @@ -186,7 +220,23 @@ index 37fd5a5..77a2a39 100644
      
          ALOGI("setupAVCEncoderParameters with [profile: %s] [level: %s]",
                  asString(h264type.eProfile), asString(h264type.eLevel));
    -@@ -6036,6 +6056,9 @@ void ACodec::BaseState::onInputBufferFilled(const sp<AMessage> &msg) {
    +@@ -4762,6 +4791,7 @@ bool ACodec::describeDefaultColorFormat(DescribeColorFormat2Params &params) {
    +         fmt != OMX_COLOR_FormatYUV420PackedPlanar &&
    +         fmt != OMX_COLOR_FormatYUV420SemiPlanar &&
    +         fmt != OMX_COLOR_FormatYUV420PackedSemiPlanar &&
    ++        fmt != OMX_TI_COLOR_FormatYUV420PackedSemiPlanar &&
    +         fmt != (OMX_COLOR_FORMATTYPE)HAL_PIXEL_FORMAT_YV12) {
    +         ALOGW("do not know color format 0x%x = %d", fmt, fmt);
    +         return false;
    +@@ -4838,6 +4868,7 @@ bool ACodec::describeDefaultColorFormat(DescribeColorFormat2Params &params) {
    +         case OMX_COLOR_FormatYUV420SemiPlanar:
    +             // FIXME: NV21 for sw-encoder, NV12 for decoder and hw-encoder
    +         case OMX_COLOR_FormatYUV420PackedSemiPlanar:
    ++        case OMX_TI_COLOR_FormatYUV420PackedSemiPlanar:
    +             // NV12
    +             image.mPlane[image.U].mOffset = params.nStride * params.nSliceHeight;
    +             image.mPlane[image.U].mColInc = 2;
    +@@ -6036,6 +6067,9 @@ void ACodec::BaseState::onInputBufferFilled(const sp<AMessage> &msg) {
                      status_t err2 = OK;
                      switch (metaType) {
                      case kMetadataBufferTypeInvalid:
    @@ -196,7 +246,7 @@ index 37fd5a5..77a2a39 100644
                          break;
      #ifndef OMX_ANDROID_COMPILE_AS_32BIT_ON_64BIT_PLATFORMS
                      case kMetadataBufferTypeNativeHandleSource:
    -@@ -6267,6 +6290,10 @@ bool ACodec::BaseState::onOMXFillBufferDone(
    +@@ -6267,6 +6301,10 @@ bool ACodec::BaseState::onOMXFillBufferDone(
                      native_handle_t *handle = NULL;
                      VideoNativeHandleMetadata &nativeMeta =
                          *(VideoNativeHandleMetadata *)info->mData->data();
    @@ -207,7 +257,7 @@ index 37fd5a5..77a2a39 100644
                      if (info->mData->size() >= sizeof(nativeMeta)
                              && nativeMeta.eType == kMetadataBufferTypeNativeHandleSource) {
      #ifdef OMX_ANDROID_COMPILE_AS_32BIT_ON_64BIT_PLATFORMS
    -@@ -6276,6 +6303,12 @@ bool ACodec::BaseState::onOMXFillBufferDone(
    +@@ -6276,6 +6314,12 @@ bool ACodec::BaseState::onOMXFillBufferDone(
                          handle = (native_handle_t *)nativeMeta.pHandle;
      #endif
                      }
    @@ -220,7 +270,7 @@ index 37fd5a5..77a2a39 100644
                      info->mData->meta()->setPointer("handle", handle);
                      info->mData->meta()->setInt32("rangeOffset", rangeOffset);
                      info->mData->meta()->setInt32("rangeLength", rangeLength);
    -@@ -6968,10 +7001,12 @@ void ACodec::LoadedState::onCreateInputSurface(
    +@@ -6968,10 +7012,12 @@ void ACodec::LoadedState::onCreateInputSurface(
              err = mCodec->mOMX->createInputSurface(
                      mCodec->mNode, kPortIndexInput, dataSpace, &bufferProducer,
                      &mCodec->mInputMetadataType);
    @@ -233,7 +283,7 @@ index 37fd5a5..77a2a39 100644
          }
      
          if (err == OK) {
    -@@ -7014,10 +7049,12 @@ void ACodec::LoadedState::onSetInputSurface(
    +@@ -7014,10 +7060,12 @@ void ACodec::LoadedState::onSetInputSurface(
              err = mCodec->mOMX->setInputSurface(
                      mCodec->mNode, kPortIndexInput, surface->getBufferConsumer(),
                      &mCodec->mInputMetadataType);
    @@ -247,7 +297,7 @@ index 37fd5a5..77a2a39 100644
      
          if (err == OK) {
     diff --git a/media/libstagefright/Android.mk b/media/libstagefright/Android.mk
    -index 3848502..1635375 100644
    +index 3848502..07f926c 100644
     --- a/media/libstagefright/Android.mk
     +++ b/media/libstagefright/Android.mk
     @@ -102,6 +102,10 @@ LOCAL_SHARED_LIBRARIES := \
    @@ -272,6 +322,17 @@ index 3848502..1635375 100644
      LOCAL_CFLAGS += -Wno-multichar -Werror -Wno-error=deprecated-declarations -Wall
      
      # enable experiments only in userdebug and eng builds
    +@@ -131,6 +139,10 @@ ifneq (,$(filter userdebug eng,$(TARGET_BUILD_VARIANT)))
    + LOCAL_CFLAGS += -DENABLE_STAGEFRIGHT_EXPERIMENTS
    + endif
    + 
    ++ifeq ($(TARGET_BOARD_PLATFORM),omap4)
    ++LOCAL_CFLAGS += -DBOARD_CANT_REALLOCATE_OMX_BUFFERS
    ++endif
    ++
    + LOCAL_CLANG := true
    + LOCAL_SANITIZE := unsigned-integer-overflow signed-integer-overflow
    + 
     diff --git a/media/libstagefright/CameraSource.cpp b/media/libstagefright/CameraSource.cpp
     index 893da89..0bc6847 100644
     --- a/media/libstagefright/CameraSource.cpp
    @@ -326,6 +387,19 @@ index a17757a..f1ad5c5 100644
     +}
     +}
      }  // namespace android
    +diff --git a/media/libstagefright/SampleTable.cpp b/media/libstagefright/SampleTable.cpp
    +index ee5fdf0..fb5305d 100644
    +--- a/media/libstagefright/SampleTable.cpp
    ++++ b/media/libstagefright/SampleTable.cpp
    +@@ -517,6 +517,8 @@ status_t SampleTable::setSyncSampleParams(off64_t data_offset, size_t data_size)
    +         return ERROR_MALFORMED;
    +     }
    + 
    ++    mSyncSampleOffset = data_offset;
    ++
    +     uint8_t header[8];
    +     if (mDataSource->readAt(
    +                 data_offset, header, sizeof(header)) < (ssize_t)sizeof(header)) {
     diff --git a/media/libstagefright/StagefrightMetadataRetriever.cpp b/media/libstagefright/StagefrightMetadataRetriever.cpp
     index be5067d..2fef7ca 100644
     --- a/media/libstagefright/StagefrightMetadataRetriever.cpp
    @@ -426,11 +500,27 @@ index 15ff569..0e9b4e6 100644
      
          (*buffer)->setObserver(this);
          (*buffer)->add_ref();
    +diff --git a/media/libstagefright/avc_utils.cpp b/media/libstagefright/avc_utils.cpp
    +index 763381e..e5819ed 100644
    +--- a/media/libstagefright/avc_utils.cpp
    ++++ b/media/libstagefright/avc_utils.cpp
    +@@ -479,7 +479,10 @@ bool IsAVCReferenceFrame(const sp<ABuffer> &accessUnit) {
    +     const uint8_t *nalStart;
    +     size_t nalSize;
    +     while (getNextNALUnit(&data, &size, &nalStart, &nalSize, true) == OK) {
    +-        CHECK_GT(nalSize, 0u);
    ++        if (nalSize == 0u) {
    ++            ALOGW("skipping empty nal unit from potentially malformed bitstream");
    ++            continue;
    ++        }
    + 
    +         unsigned nalType = nalStart[0] & 0x1f;
    + 
     diff --git a/media/libstagefright/foundation/MediaBufferGroup.cpp b/media/libstagefright/foundation/MediaBufferGroup.cpp
    -index 54f768a..8200bf1 100644
    +index 8e4d064..66992d7 100644
     --- a/media/libstagefright/foundation/MediaBufferGroup.cpp
     +++ b/media/libstagefright/foundation/MediaBufferGroup.cpp
    -@@ -99,6 +99,11 @@ MediaBufferGroup::~MediaBufferGroup() {
    +@@ -105,6 +105,11 @@ MediaBufferGroup::~MediaBufferGroup() {
          }
      }
      
    @@ -442,7 +532,7 @@ index 54f768a..8200bf1 100644
      void MediaBufferGroup::add_buffer(MediaBuffer *buffer) {
          Mutex::Autolock autoLock(mLock);
      
    -@@ -179,6 +184,16 @@ status_t MediaBufferGroup::acquire_buffer(
    +@@ -198,6 +203,16 @@ status_t MediaBufferGroup::acquire_buffer(
          // Never gets here.
      }
      
    @@ -493,7 +583,7 @@ index e4fbd81..8fc788f 100644
      LOCAL_CFLAGS += -Werror -Wall
      LOCAL_CLANG := true
     diff --git a/media/libstagefright/omx/GraphicBufferSource.cpp b/media/libstagefright/omx/GraphicBufferSource.cpp
    -index 93d6584..50cc940 100644
    +index 0c4056d..da77c48 100644
     --- a/media/libstagefright/omx/GraphicBufferSource.cpp
     +++ b/media/libstagefright/omx/GraphicBufferSource.cpp
     @@ -724,6 +724,8 @@ bool GraphicBufferSource::repeatLatestBuffer_l() {
    @@ -668,7 +758,7 @@ index 8d7f71c..d98ad47 100644
      
      include $(BUILD_SHARED_LIBRARY)
     diff --git a/services/camera/libcameraservice/CameraService.cpp b/services/camera/libcameraservice/CameraService.cpp
    -index d0df6d1..0083738 100644
    +index 6124fed..de7ea03 100644
     --- a/services/camera/libcameraservice/CameraService.cpp
     +++ b/services/camera/libcameraservice/CameraService.cpp
     @@ -273,7 +273,10 @@ void CameraService::onFirstRef()
    @@ -720,3 +810,45 @@ index 266fb03..3c2b98a 100644
      }
      
      status_t CameraClient::setVideoBufferMode(int32_t videoBufferMode) {
    +diff --git a/services/soundtrigger/SoundTriggerHwService.cpp b/services/soundtrigger/SoundTriggerHwService.cpp
    +index eebc487..74d0c70 100644
    +--- a/services/soundtrigger/SoundTriggerHwService.cpp
    ++++ b/services/soundtrigger/SoundTriggerHwService.cpp
    +@@ -278,6 +278,37 @@ void SoundTriggerHwService::sendRecognitionEvent(struct sound_trigger_recognitio
    +      if (module == NULL) {
    +          return;
    +      }
    ++    struct sound_trigger_phrase_recognition_event newEvent;
    ++    if (event-> type == SOUND_MODEL_TYPE_KEYPHRASE && event->data_size != 0
    ++        && event->data_offset != sizeof(struct sound_trigger_phrase_recognition_event)) {
    ++        // set some defaults for the phrase if the recognition event won't be parsed properly
    ++        // TODO: read defaults from the config
    ++
    ++        memset(&newEvent, 0, sizeof(struct sound_trigger_phrase_recognition_event));
    ++
    ++        sp<Model> model = module->getModel(event->model);
    ++
    ++        newEvent.num_phrases = 1;
    ++        newEvent.phrase_extras[0].id = 100;
    ++        newEvent.phrase_extras[0].recognition_modes = RECOGNITION_MODE_VOICE_TRIGGER;
    ++        newEvent.phrase_extras[0].confidence_level = 100;
    ++        newEvent.phrase_extras[0].num_levels = 1;
    ++        newEvent.phrase_extras[0].levels[0].level = 100;
    ++        newEvent.phrase_extras[0].levels[0].user_id = 100;
    ++        newEvent.common.status = event->status;
    ++        newEvent.common.type = event->type;
    ++        newEvent.common.model = event->model;
    ++        newEvent.common.capture_available = event->capture_available;
    ++        newEvent.common.capture_session = event->capture_session;
    ++        newEvent.common.capture_delay_ms = event->capture_delay_ms;
    ++        newEvent.common.capture_preamble_ms = event->capture_preamble_ms;
    ++        newEvent.common.trigger_in_data = event->trigger_in_data;
    ++        newEvent.common.audio_config = event->audio_config;
    ++        newEvent.common.data_size = event->data_size;
    ++        newEvent.common.data_offset = sizeof(struct sound_trigger_phrase_recognition_event);
    ++
    ++         event = &newEvent.common;
    ++     }
    +      sp<IMemory> eventMemory = prepareRecognitionEvent_l(event);
    +      if (eventMemory == 0) {
    +          return;
    diff --git a/frameworks_base.patch b/frameworks_base.patch
    index 81dfa63..75080a3 100644
    --- a/frameworks_base.patch
    +++ b/frameworks_base.patch
    @@ -24,6 +24,128 @@ index aed7a36..bf96926 100644
                  // if canceling out of addAccount and the original state caused us to skip this,
                  // finish this activity
                  if (mAccounts.isEmpty()) {
    +diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java
    +index 0dd9c63..bcdf3f4 100644
    +--- a/core/java/android/app/Notification.java
    ++++ b/core/java/android/app/Notification.java
    +@@ -1761,7 +1761,9 @@ public class Notification implements Parcelable
    +         if (this.actions != null) {
    +             that.actions = new Action[this.actions.length];
    +             for(int i=0; i<this.actions.length; i++) {
    +-                that.actions[i] = this.actions[i].clone();
    ++                if ( this.actions[i] != null) {
    ++                    that.actions[i] = this.actions[i].clone();
    ++                }
    +             }
    +         }
    + 
    +@@ -3108,7 +3110,9 @@ public class Notification implements Parcelable
    +          * @param action The action to add.
    +          */
    +         public Builder addAction(Action action) {
    +-            mActions.add(action);
    ++            if (action != null) {
    ++                mActions.add(action);
    ++            }
    +             return this;
    +         }
    + 
    +@@ -3122,7 +3126,9 @@ public class Notification implements Parcelable
    +         public Builder setActions(Action... actions) {
    +             mActions.clear();
    +             for (int i = 0; i < actions.length; i++) {
    +-                mActions.add(actions[i]);
    ++                if (actions[i] != null) {
    ++                    mActions.add(actions[i]);
    ++                }
    +             }
    +             return this;
    +         }
    +diff --git a/core/java/android/app/ResourcesManager.java b/core/java/android/app/ResourcesManager.java
    +index 5cc064e..4916c1c 100644
    +--- a/core/java/android/app/ResourcesManager.java
    ++++ b/core/java/android/app/ResourcesManager.java
    +@@ -826,7 +826,8 @@ public class ResourcesManager {
    + 
    +             for (int i = mResourceImpls.size() - 1; i >= 0; i--) {
    +                 ResourcesKey key = mResourceImpls.keyAt(i);
    +-                ResourcesImpl r = mResourceImpls.valueAt(i).get();
    ++                WeakReference<ResourcesImpl> weakImplRef = mResourceImpls.valueAt(i);
    ++                ResourcesImpl r = weakImplRef != null ? weakImplRef.get() : null;
    +                 if (r != null) {
    +                     if (DEBUG || DEBUG_CONFIGURATION) Slog.v(TAG, "Changing resources "
    +                             + r + " config to: " + config);
    +@@ -890,8 +891,9 @@ public class ResourcesManager {
    + 
    +             final int implCount = mResourceImpls.size();
    +             for (int i = 0; i < implCount; i++) {
    +-                final ResourcesImpl impl = mResourceImpls.valueAt(i).get();
    +                 final ResourcesKey key = mResourceImpls.keyAt(i);
    ++                final WeakReference<ResourcesImpl> weakImplRef = mResourceImpls.valueAt(i);
    ++                final ResourcesImpl impl = weakImplRef != null ? weakImplRef.get() : null;
    +                 if (impl != null && key.mResDir.equals(assetPath)) {
    +                     if (!ArrayUtils.contains(key.mLibDirs, libAsset)) {
    +                         final int newLibAssetCount = 1 +
    +diff --git a/core/java/android/content/pm/RegisteredServicesCache.java b/core/java/android/content/pm/RegisteredServicesCache.java
    +index a110383..aea843a 100644
    +--- a/core/java/android/content/pm/RegisteredServicesCache.java
    ++++ b/core/java/android/content/pm/RegisteredServicesCache.java
    +@@ -390,15 +390,17 @@ public abstract class RegisteredServicesCache<V> {
    +     @VisibleForTesting
    +     protected boolean inSystemImage(int callerUid) {
    +         String[] packages = mContext.getPackageManager().getPackagesForUid(callerUid);
    +-        for (String name : packages) {
    +-            try {
    +-                PackageInfo packageInfo =
    +-                        mContext.getPackageManager().getPackageInfo(name, 0 /* flags */);
    +-                if ((packageInfo.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0) {
    +-                    return true;
    ++        if (packages != null) {
    ++            for (String name : packages) {
    ++                try {
    ++                    PackageInfo packageInfo =
    ++                            mContext.getPackageManager().getPackageInfo(name, 0 /* flags */);
    ++                    if ((packageInfo.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0) {
    ++                        return true;
    ++                    }
    ++                } catch (PackageManager.NameNotFoundException e) {
    ++                    return false;
    +                 }
    +-            } catch (PackageManager.NameNotFoundException e) {
    +-                return false;
    +             }
    +         }
    +         return false;
    +diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
    +index a8209af..4766d33 100755
    +--- a/core/java/android/provider/Settings.java
    ++++ b/core/java/android/provider/Settings.java
    +@@ -3559,6 +3559,12 @@ public final class Settings {
    +         public static final Validator LOCK_TO_APP_ENABLED_VALIDATOR = sBooleanValidator;
    + 
    +         /**
    ++         * Whether to wake the screen with the home key, the value is boolean.
    ++         * @hide
    ++         */
    ++        public static final String HOME_WAKE_SCREEN = "home_wake_screen";
    ++
    ++        /**
    +          * I am the lolrus.
    +          * <p>
    +          * Nonzero values indicate that the user has a bukkit.
    +diff --git a/core/java/com/android/internal/app/procstats/ProcessState.java b/core/java/com/android/internal/app/procstats/ProcessState.java
    +index 8c5df08..8c2c236 100644
    +--- a/core/java/com/android/internal/app/procstats/ProcessState.java
    ++++ b/core/java/com/android/internal/app/procstats/ProcessState.java
    +@@ -379,7 +379,7 @@ public final class ProcessState {
    + 
    +     public void setState(int state, long now) {
    +         ensureNotDead();
    +-        if (mCurState != state) {
    ++        if (!mDead && (mCurState != state)) {
    +             //Slog.i(TAG, "Setting state in " + mName + "/" + mPackage + ": " + state);
    +             commitStateTime(now);
    +             mCurState = state;
     diff --git a/core/res/res/xml/config_webview_packages.xml b/core/res/res/xml/config_webview_packages.xml
     index f062b59..574f7c1 100644
     --- a/core/res/res/xml/config_webview_packages.xml
    @@ -78,11 +200,142 @@ index 2c9c9d9..7c187fb 100644
      }
      
      /**
    +diff --git a/packages/SystemUI/res/values/config.xml b/packages/SystemUI/res/values/config.xml
    +index 0fa9a85..925f368 100644
    +--- a/packages/SystemUI/res/values/config.xml
    ++++ b/packages/SystemUI/res/values/config.xml
    +@@ -105,7 +105,7 @@
    + 
    +     <!-- Tiles native to System UI. Order should match "quick_settings_tiles_default" -->
    +     <string name="quick_settings_tiles_stock" translatable="false">
    +-        wifi,cell,battery,dnd,flashlight,rotation,bt,airplane,location,hotspot,inversion,saver,work,cast,night
    ++        wifi,cell,battery,dnd,flashlight,rotation,bt,airplane,location,immersive,hotspot,inversion,saver,work,cast,night
    +     </string>
    + 
    +     <!-- The tiles to display in QuickSettings -->
    +diff --git a/packages/SystemUI/src/com/android/systemui/settings/CurrentUserTracker.java b/packages/SystemUI/src/com/android/systemui/settings/CurrentUserTracker.java
    +index dd80750..005206f 100644
    +--- a/packages/SystemUI/src/com/android/systemui/settings/CurrentUserTracker.java
    ++++ b/packages/SystemUI/src/com/android/systemui/settings/CurrentUserTracker.java
    +@@ -22,39 +22,93 @@ import android.content.Context;
    + import android.content.Intent;
    + import android.content.IntentFilter;
    + 
    +-public abstract class CurrentUserTracker extends BroadcastReceiver {
    ++import java.util.ArrayList;
    ++import java.util.List;
    ++import java.util.function.Consumer;
    + 
    +-    private Context mContext;
    +-    private int mCurrentUserId;
    ++public abstract class CurrentUserTracker {
    ++    private final UserReceiver mUserReceiver;
    ++
    ++    private Consumer<Integer> mCallback = this::onUserSwitched;
    + 
    +     public CurrentUserTracker(Context context) {
    +-        mContext = context;
    ++        mUserReceiver = UserReceiver.getInstance(context);
    +     }
    + 
    +     public int getCurrentUserId() {
    +-        return mCurrentUserId;
    +-    }
    +-
    +-    @Override
    +-    public void onReceive(Context context, Intent intent) {
    +-        if (Intent.ACTION_USER_SWITCHED.equals(intent.getAction())) {
    +-            int oldUserId = mCurrentUserId;
    +-            mCurrentUserId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0);
    +-            if (oldUserId != mCurrentUserId) {
    +-                onUserSwitched(mCurrentUserId);
    +-            }
    +-        }
    ++        return mUserReceiver.getCurrentUserId();
    +     }
    + 
    +     public void startTracking() {
    +-        mCurrentUserId = ActivityManager.getCurrentUser();
    +-        IntentFilter filter = new IntentFilter(Intent.ACTION_USER_SWITCHED);
    +-        mContext.registerReceiver(this, filter);
    ++        mUserReceiver.addTracker(mCallback);
    +     }
    + 
    +     public void stopTracking() {
    +-        mContext.unregisterReceiver(this);
    ++        mUserReceiver.removeTracker(mCallback);
    +     }
    + 
    +     public abstract void onUserSwitched(int newUserId);
    ++
    ++    private static class UserReceiver extends BroadcastReceiver {
    ++        private static UserReceiver sInstance;
    ++
    ++        private Context mAppContext;
    ++        private boolean mReceiverRegistered;
    ++        private int mCurrentUserId;
    ++
    ++        private List<Consumer<Integer>> mCallbacks = new ArrayList<>();
    ++
    ++        private UserReceiver(Context context) {
    ++            mAppContext = context.getApplicationContext();
    ++        }
    ++
    ++        static UserReceiver getInstance(Context context) {
    ++            if (sInstance == null) {
    ++                sInstance = new UserReceiver(context);
    ++            }
    ++            return sInstance;
    ++        }
    ++
    ++        @Override
    ++        public void onReceive(Context context, Intent intent) {
    ++            if (Intent.ACTION_USER_SWITCHED.equals(intent.getAction())) {
    ++                notifyUserSwitched(intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0));
    ++            }
    ++        }
    ++
    ++        public int getCurrentUserId() {
    ++            return mCurrentUserId;
    ++        }
    ++
    ++        private void addTracker(Consumer<Integer> callback) {
    ++            if (!mCallbacks.contains(callback)) {
    ++                mCallbacks.add(callback);
    ++            }
    ++            if (!mReceiverRegistered) {
    ++                mCurrentUserId = ActivityManager.getCurrentUser();
    ++                IntentFilter filter = new IntentFilter(Intent.ACTION_USER_SWITCHED);
    ++                mAppContext.registerReceiver(this, filter);
    ++                mReceiverRegistered = true;
    ++            }
    ++        }
    ++
    ++        private void removeTracker(Consumer<Integer> callback) {
    ++            if (mCallbacks.contains(callback)) {
    ++                mCallbacks.remove(callback);
    ++                if (mCallbacks.size() == 0 && mReceiverRegistered) {
    ++                    mAppContext.unregisterReceiver(this);
    ++                    mReceiverRegistered = false;
    ++                }
    ++            }
    ++        }
    ++
    ++        private void notifyUserSwitched(int newUserId) {
    ++            if (mCurrentUserId != newUserId) {
    ++                mCurrentUserId = newUserId;
    ++                for (Consumer<Integer> consumer : mCallbacks) {
    ++                    consumer.accept(newUserId);
    ++                }
    ++            }
    ++        }
    ++    }
    + }
     diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationGuts.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationGuts.java
    -index c850a25..1829e59 100644
    +index 63d2891..1829e59 100644
     --- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationGuts.java
     +++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationGuts.java
    -@@ -235,16 +235,16 @@ public class NotificationGuts extends LinearLayout implements TunerService.Tunab
    +@@ -235,7 +235,7 @@ public class NotificationGuts extends LinearLayout implements TunerService.Tunab
          }
      
          private int getSelectedImportance() {
    @@ -91,17 +344,6 @@ index c850a25..1829e59 100644
                  if (mSeekBar.isEnabled()) {
                      return mSeekBar.getProgress();
                  } else {
    -                 return Ranking.IMPORTANCE_UNSPECIFIED;
    -             }
    -         } else {
    --            if (mBlock.isChecked()) {
    -+            if (mBlock != null && mBlock.isChecked()) {
    -                 return Ranking.IMPORTANCE_NONE;
    --            } else if (mSilent.isChecked()) {
    -+            } else if (mSilent != null && mSilent.isChecked()) {
    -                 return Ranking.IMPORTANCE_LOW;
    -             } else {
    -                 return Ranking.IMPORTANCE_UNSPECIFIED;
     diff --git a/packages/SystemUI/src/com/android/systemui/tuner/TunerFragment.java b/packages/SystemUI/src/com/android/systemui/tuner/TunerFragment.java
     index 70f2fdc..ba50161 100644
     --- a/packages/SystemUI/src/com/android/systemui/tuner/TunerFragment.java
    @@ -184,11 +426,116 @@ index 4caeba8..c95b9d5 100644
                          if (uidState.opModes != null && uidState.opModes.size() > 0) {
                              out.startTag(null, "uid");
                              out.attribute(null, "n", Integer.toString(uidState.uid));
    +diff --git a/services/core/java/com/android/server/BluetoothManagerService.java b/services/core/java/com/android/server/BluetoothManagerService.java
    +index 2a6f9d2..7ba1fe4 100644
    +--- a/services/core/java/com/android/server/BluetoothManagerService.java
    ++++ b/services/core/java/com/android/server/BluetoothManagerService.java
    +@@ -55,6 +55,7 @@ import android.os.UserManager;
    + import android.provider.Settings;
    + import android.provider.Settings.SettingNotFoundException;
    + import android.util.Slog;
    ++import java.util.concurrent.locks.ReentrantReadWriteLock;
    + 
    + import java.io.FileDescriptor;
    + import java.io.PrintWriter;
    +@@ -122,6 +123,7 @@ class BluetoothManagerService extends IBluetoothManager.Stub {
    +     private static final int SERVICE_IBLUETOOTHGATT = 2;
    + 
    +     private final Context mContext;
    ++    private static int mBleAppCount = 0;
    + 
    +     // Locks are not provided for mName and mAddress.
    +     // They are accessed in handler or broadcast receiver, same thread context.
    +@@ -172,6 +174,8 @@ class BluetoothManagerService extends IBluetoothManager.Stub {
    +     // configuration from external IBinder call which is used to
    +     // synchronize with broadcast receiver.
    +     private boolean mQuietEnableExternal;
    ++    // configuarion from external IBinder call which is used to
    ++    // synchronize with broadcast receiver.
    +     private boolean mEnableExternal;
    + 
    +     // Map of apps registered to keep BLE scanning on.
    +@@ -351,6 +355,7 @@ class BluetoothManagerService extends IBluetoothManager.Stub {
    + 
    +     /**
    +      *  Save the Bluetooth on/off state
    ++     *
    +      */
    +     private void persistBluetoothSetting(int value) {
    +         if (DBG) Slog.d(TAG, "Persisting Bluetooth Setting: " + value);
    +@@ -644,7 +649,11 @@ class BluetoothManagerService extends IBluetoothManager.Stub {
    +             if (isBluetoothPersistedStateOnBluetooth() || !isBleAppPresent()) {
    +                 // This triggers transition to STATE_ON
    +                 mBluetooth.onLeServiceUp();
    ++
    ++                // waive WRITE_SECURE_SETTINGS permission check
    ++                long callingIdentity = Binder.clearCallingIdentity();
    +                 persistBluetoothSetting(BLUETOOTH_ON_BLUETOOTH);
    ++                Binder.restoreCallingIdentity(callingIdentity);
    +             }
    +         } catch (RemoteException e) {
    +             Slog.e(TAG,"Unable to call onServiceUp", e);
    +@@ -727,6 +736,8 @@ class BluetoothManagerService extends IBluetoothManager.Stub {
    +             }
    +         }
    + 
    ++        mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
    ++                                                "Need BLUETOOTH ADMIN permission");
    +         if (DBG) {
    +             Slog.d(TAG,"enable(" + packageName + "):  mBluetooth =" + mBluetooth +
    +                     " mBinding = " + mBinding + " mState = " +
    +@@ -770,7 +781,10 @@ class BluetoothManagerService extends IBluetoothManager.Stub {
    + 
    +         synchronized(mReceiver) {
    +             if (persist) {
    ++                // waive WRITE_SECURE_SETTINGS permission check
    ++                long callingIdentity = Binder.clearCallingIdentity();
    +                 persistBluetoothSetting(BLUETOOTH_OFF);
    ++                Binder.restoreCallingIdentity(callingIdentity);
    +             }
    +             mEnableExternal = false;
    +             sendDisableMsg(packageName);
    +@@ -827,8 +841,11 @@ class BluetoothManagerService extends IBluetoothManager.Stub {
    +                 } catch (RemoteException re) {
    +                     Slog.e(TAG, "Unable to unregister BluetoothCallback",re);
    +                 }
    ++
    ++                if (DBG) Slog.d(TAG, "Sending unbind request.");
    +                 mBluetoothBinder = null;
    +                 mBluetooth = null;
    ++                //Unbind
    +                 mContext.unbindService(mConnection);
    +                 mUnbinding = false;
    +                 mBinding = false;
    +@@ -1103,6 +1120,7 @@ class BluetoothManagerService extends IBluetoothManager.Stub {
    +      * Inform BluetoothAdapter instances that Adapter service is up
    +      */
    +     private void sendBluetoothServiceUpCallback() {
    ++        if (DBG) Slog.d(TAG,"Calling onBluetoothServiceUp callbacks");
    +         try {
    +             int n = mCallbacks.beginBroadcast();
    +             Slog.d(TAG,"Broadcasting onBluetoothServiceUp() to " + n + " receivers.");
    +@@ -1121,6 +1139,7 @@ class BluetoothManagerService extends IBluetoothManager.Stub {
    +      * Inform BluetoothAdapter instances that Adapter service is down
    +      */
    +     private void sendBluetoothServiceDownCallback() {
    ++        if (DBG) Slog.d(TAG,"Calling onBluetoothServiceDown callbacks");
    +         try {
    +             int n = mCallbacks.beginBroadcast();
    +             Slog.d(TAG,"Broadcasting onBluetoothServiceDown() to " + n + " receivers.");
    +@@ -1236,6 +1255,7 @@ class BluetoothManagerService extends IBluetoothManager.Stub {
    + 
    +         @Override
    +         public void handleMessage(Message msg) {
    ++            if (DBG) Slog.d (TAG, "Message: " + msg.what);
    +             switch (msg.what) {
    +                 case MESSAGE_GET_NAME_AND_ADDRESS:
    +                     if (DBG) Slog.d(TAG, "MESSAGE_GET_NAME_AND_ADDRESS");
     diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
    -index 5f59e32..23172a2 100644
    +index 2693272..f2368ed 100644
     --- a/services/core/java/com/android/server/ConnectivityService.java
     +++ b/services/core/java/com/android/server/ConnectivityService.java
    -@@ -2992,6 +2992,12 @@ public class ConnectivityService extends IConnectivityManager.Stub
    +@@ -3007,6 +3007,12 @@ public class ConnectivityService extends IConnectivityManager.Stub
              ConnectivityManager.enforceTetherChangePermission(mContext);
              if (isTetheringSupported()) {
                  final int status = mTethering.tether(iface);
    @@ -201,7 +548,7 @@ index 5f59e32..23172a2 100644
                  return status;
              } else {
                  return ConnectivityManager.TETHER_ERROR_UNSUPPORTED;
    -@@ -3005,6 +3011,12 @@ public class ConnectivityService extends IConnectivityManager.Stub
    +@@ -3020,6 +3026,12 @@ public class ConnectivityService extends IConnectivityManager.Stub
      
              if (isTetheringSupported()) {
                  final int status = mTethering.untether(iface);
    @@ -214,7 +561,7 @@ index 5f59e32..23172a2 100644
                  return status;
              } else {
                  return ConnectivityManager.TETHER_ERROR_UNSUPPORTED;
    -@@ -4909,6 +4921,13 @@ public class ConnectivityService extends IConnectivityManager.Stub
    +@@ -4924,6 +4936,13 @@ public class ConnectivityService extends IConnectivityManager.Stub
                  // check if it satisfies the NetworkCapabilities
                  if (VDBG) log("  checking if request is satisfied: " + nri.request);
                  if (satisfies) {
    @@ -228,191 +575,69 @@ index 5f59e32..23172a2 100644
                      // next check if it's better than any current network we're using for
                      // this request
                      if (VDBG) {
    -diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
    -index bc9d58e..9ed5af9 100644
    ---- a/services/core/java/com/android/server/am/ActivityManagerService.java
    -+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
    -@@ -9590,7 +9590,7 @@ public final class ActivityManagerService extends ActivityManagerNative
    -         for (int i = 0; i < procsToKill.size(); i++) {
    -             ProcessRecord pr = procsToKill.get(i);
    -             if (pr.setSchedGroup == ProcessList.SCHED_GROUP_BACKGROUND
    --                    && pr.curReceiver == null) {
    -+                    && pr.curReceivers.isEmpty()) {
    -                 pr.kill("remove task", true);
    -             } else {
    -                 // We delay killing processes that are not in the background or running a receiver.
    -@@ -16933,6 +16933,7 @@ public final class ActivityManagerService extends ActivityManagerNative
    - 
    -         app.crashing = false;
    -         app.notResponding = false;
    -+        app.renderThreadTid = 0;
    - 
    -         app.resetPackageList(mProcessStats);
    -         app.unlinkDeathRecipient();
    -@@ -19204,26 +19205,28 @@ public final class ActivityManagerService extends ActivityManagerNative
    -     // LIFETIME MANAGEMENT
    -     // =========================================================
    - 
    --    // Returns which broadcast queue the app is the current [or imminent] receiver
    --    // on, or 'null' if the app is not an active broadcast recipient.
    --    private BroadcastQueue isReceivingBroadcast(ProcessRecord app) {
    --        BroadcastRecord r = app.curReceiver;
    --        if (r != null) {
    --            return r.queue;
    -+    // Returns whether the app is receiving broadcast.
    -+    // If receiving, fetch all broadcast queues which the app is
    -+    // the current [or imminent] receiver on.
    -+    private boolean isReceivingBroadcastLocked(ProcessRecord app,
    -+            ArraySet<BroadcastQueue> receivingQueues) {
    -+        if (!app.curReceivers.isEmpty()) {
    -+            for (BroadcastRecord r : app.curReceivers) {
    -+                receivingQueues.add(r.queue);
    -+            }
    -+            return true;
    -         }
    - 
    -         // It's not the current receiver, but it might be starting up to become one
    --        synchronized (this) {
    --            for (BroadcastQueue queue : mBroadcastQueues) {
    --                r = queue.mPendingBroadcast;
    --                if (r != null && r.curApp == app) {
    --                    // found it; report which queue it's in
    --                    return queue;
    --                }
    -+        for (BroadcastQueue queue : mBroadcastQueues) {
    -+            final BroadcastRecord r = queue.mPendingBroadcast;
    -+            if (r != null && r.curApp == app) {
    -+                // found it; report which queue it's in
    -+                receivingQueues.add(queue);
    +diff --git a/services/core/java/com/android/server/am/ActivityStackSupervisor.java b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
    +index c6ab918..d848081 100644
    +--- a/services/core/java/com/android/server/am/ActivityStackSupervisor.java
    ++++ b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
    +@@ -2747,6 +2747,9 @@ public final class ActivityStackSupervisor implements DisplayListener {
                  }
              }
    - 
    --        return null;
    -+        return !receivingQueues.isEmpty();
    +         checkReadyForSleepLocked();
    ++        if (mGoingToSleep.isHeld()) {
    ++            mGoingToSleep.release();
    ++        }
          }
      
    -     Association startAssociationLocked(int sourceUid, String sourceProcess, int sourceState,
    -@@ -19390,7 +19393,7 @@ public final class ActivityManagerService extends ActivityManagerNative
    -         int schedGroup;
    -         int procState;
    -         boolean foregroundActivities = false;
    --        BroadcastQueue queue;
    -+        final ArraySet<BroadcastQueue> queues = new ArraySet<BroadcastQueue>();
    -         if (app == TOP_APP) {
    -             // The last app on the list is the foreground app.
    -             adj = ProcessList.FOREGROUND_APP_ADJ;
    -@@ -19404,13 +19407,13 @@ public final class ActivityManagerService extends ActivityManagerNative
    -             schedGroup = ProcessList.SCHED_GROUP_DEFAULT;
    -             app.adjType = "instrumentation";
    -             procState = ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE;
    --        } else if ((queue = isReceivingBroadcast(app)) != null) {
    -+        } else if (isReceivingBroadcastLocked(app, queues)) {
    -             // An app that is currently receiving a broadcast also
    -             // counts as being in the foreground for OOM killer purposes.
    -             // It's placed in a sched group based on the nature of the
    -             // broadcast as reflected by which queue it's active in.
    -             adj = ProcessList.FOREGROUND_APP_ADJ;
    --            schedGroup = (queue == mFgBroadcastQueue)
    -+            schedGroup = (queues.contains(mFgBroadcastQueue))
    -                     ? ProcessList.SCHED_GROUP_DEFAULT : ProcessList.SCHED_GROUP_BACKGROUND;
    -             app.adjType = "broadcast";
    -             procState = ActivityManager.PROCESS_STATE_RECEIVER;
    -@@ -20421,7 +20424,7 @@ public final class ActivityManagerService extends ActivityManagerNative
    -             if (DEBUG_SWITCH || DEBUG_OOM_ADJ) Slog.v(TAG_OOM_ADJ,
    -                     "Setting sched group of " + app.processName
    -                     + " to " + app.curSchedGroup);
    --            if (app.waitingToKill != null && app.curReceiver == null
    -+            if (app.waitingToKill != null && app.curReceivers.isEmpty()
    -                     && app.setSchedGroup == ProcessList.SCHED_GROUP_BACKGROUND) {
    -                 app.kill(app.waitingToKill, true);
    -                 success = false;
    -@@ -21361,7 +21364,7 @@ public final class ActivityManagerService extends ActivityManagerNative
    -             for (i=mRemovedProcesses.size()-1; i>=0; i--) {
    -                 final ProcessRecord app = mRemovedProcesses.get(i);
    -                 if (app.activities.size() == 0
    --                        && app.curReceiver == null && app.services.size() == 0) {
    -+                        && app.curReceivers.isEmpty() && app.services.size() == 0) {
    -                     Slog.i(
    -                         TAG, "Exiting empty application process "
    -                         + app.toShortString() + " ("
    -diff --git a/services/core/java/com/android/server/am/BroadcastQueue.java b/services/core/java/com/android/server/am/BroadcastQueue.java
    -index 8b8e2c4..5c35419 100644
    ---- a/services/core/java/com/android/server/am/BroadcastQueue.java
    -+++ b/services/core/java/com/android/server/am/BroadcastQueue.java
    -@@ -266,7 +266,7 @@ public final class BroadcastQueue {
    +     boolean shutdownLocked(int timeout) {
    +@@ -2856,9 +2859,6 @@ public final class ActivityStackSupervisor implements DisplayListener {
      
    -         r.receiver = app.thread.asBinder();
    -         r.curApp = app;
    --        app.curReceiver = r;
    -+        app.curReceivers.add(r);
    -         app.forceProcessStateUpTo(ActivityManager.PROCESS_STATE_RECEIVER);
    -         mService.updateLruProcessLocked(app, false, null);
    -         mService.updateOomAdjLocked();
    -@@ -294,7 +294,7 @@ public final class BroadcastQueue {
    -                         "Process cur broadcast " + r + ": NOT STARTED!");
    -                 r.receiver = null;
    -                 r.curApp = null;
    --                app.curReceiver = null;
    -+                app.curReceivers.remove(r);
    -             }
    -         }
    -     }
    -@@ -395,8 +395,8 @@ public final class BroadcastQueue {
    -         }
    -         r.receiver = null;
    -         r.intent.setComponent(null);
    --        if (r.curApp != null && r.curApp.curReceiver == r) {
    --            r.curApp.curReceiver = null;
    -+        if (r.curApp != null && r.curApp.curReceivers.contains(r)) {
    -+            r.curApp.curReceivers.remove(r);
    -         }
    -         if (r.curFilter != null) {
    -             r.curFilter.receiverList.curBroadcast = null;
    -@@ -649,7 +649,7 @@ public final class BroadcastQueue {
    -                 // things that directly call the IActivityManager API, which
    -                 // are already core system stuff so don't matter for this.
    -                 r.curApp = filter.receiverList.app;
    --                filter.receiverList.app.curReceiver = r;
    -+                filter.receiverList.app.curReceivers.add(r);
    -                 mService.updateOomAdjLocked(r.curApp);
    -             }
    +         removeSleepTimeouts();
    + 
    +-        if (mGoingToSleep.isHeld()) {
    +-            mGoingToSleep.release();
    +-        }
    +         if (mService.mShuttingDown) {
    +             mService.notifyAll();
              }
    -@@ -677,7 +677,7 @@ public final class BroadcastQueue {
    -                 r.curFilter = null;
    -                 filter.receiverList.curBroadcast = null;
    -                 if (filter.receiverList.app != null) {
    --                    filter.receiverList.app.curReceiver = null;
    -+                    filter.receiverList.app.curReceivers.remove(r);
    +diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
    +index 39e2914..1e95d28 100644
    +--- a/services/core/java/com/android/server/pm/PackageManagerService.java
    ++++ b/services/core/java/com/android/server/pm/PackageManagerService.java
    +@@ -423,7 +423,7 @@ public class PackageManagerService extends IPackageManager.Stub {
    +      * one gets run at the next available charging+idle time.  This final mandatory
    +      * no-fstrim check kicks in only of the other scheduling criteria is never met.
    +      */
    +-    private static final long DEFAULT_MANDATORY_FSTRIM_INTERVAL = 3 * DateUtils.DAY_IN_MILLIS;
    ++    private static final long DEFAULT_MANDATORY_FSTRIM_INTERVAL = 1 * DateUtils.DAY_IN_MILLIS;
    + 
    +     /**
    +      * Whether verification is enabled by default.
    +diff --git a/services/net/java/android/net/dhcp/DhcpClient.java b/services/net/java/android/net/dhcp/DhcpClient.java
    +index ffbea9f..8dd05b1 100644
    +--- a/services/net/java/android/net/dhcp/DhcpClient.java
    ++++ b/services/net/java/android/net/dhcp/DhcpClient.java
    +@@ -40,6 +40,7 @@ import android.os.SystemClock;
    + import android.system.ErrnoException;
    + import android.system.Os;
    + import android.system.PacketSocketAddress;
    ++import android.util.EventLog;
    + import android.util.Log;
    + import android.util.SparseArray;
    + import android.util.TimeUtils;
    +@@ -369,6 +370,13 @@ public class DhcpClient extends StateMachine {
    +                     if (PACKET_DBG) {
    +                         Log.d(TAG, HexDump.dumpHexString(mPacket, 0, length));
    +                     }
    ++                    if (e.errorCode == DhcpErrorEvent.DHCP_NO_COOKIE) {
    ++                        int snetTagId = 0x534e4554;
    ++                        String bugId = "31850211";
    ++                        int uid = -1;
    ++                        String data = DhcpPacket.ParseException.class.getName();
    ++                        EventLog.writeEvent(snetTagId, bugId, uid, data);
    ++                    }
    +                     logError(e.errorCode);
                      }
                  }
    -         }
    -diff --git a/services/core/java/com/android/server/am/ProcessRecord.java b/services/core/java/com/android/server/am/ProcessRecord.java
    -index 3fffefb..49fe79c 100644
    ---- a/services/core/java/com/android/server/am/ProcessRecord.java
    -+++ b/services/core/java/com/android/server/am/ProcessRecord.java
    -@@ -143,7 +143,7 @@ final class ProcessRecord {
    -     Bundle instrumentationArguments;// as given to us
    -     ComponentName instrumentationResultClass;// copy of instrumentationClass
    -     boolean usingWrapper;       // Set to true when process was launched with a wrapper attached
    --    BroadcastRecord curReceiver;// receiver currently running in the app
    -+    final ArraySet<BroadcastRecord> curReceivers = new ArraySet<BroadcastRecord>();// receivers currently running in the app
    -     long lastWakeTime;          // How long proc held wake lock at last check
    -     long lastCpuTime;           // How long proc has run CPU at last check
    -     long curCpuTime;            // How long proc has run CPU most recently
    -@@ -427,8 +427,11 @@ final class ProcessRecord {
    -                 pw.print(prefix); pw.print("  - "); pw.println(conProviders.get(i).toShortString());
    -             }
    -         }
    --        if (curReceiver != null) {
    --            pw.print(prefix); pw.print("curReceiver="); pw.println(curReceiver);
    -+        if (!curReceivers.isEmpty()) {
    -+            pw.print(prefix); pw.println("Current Receivers:");
    -+            for (int i=0; i < curReceivers.size(); i++) {
    -+                pw.print(prefix); pw.print("  - "); pw.println(curReceivers.valueAt(i));
    -+            }
    -         }
    -         if (receivers.size() > 0) {
    -             pw.print(prefix); pw.println("Receivers:");
     diff --git a/services/tests/Android.mk b/services/tests/Android.mk
     deleted file mode 100644
     index 40369ee..0000000
    @@ -424,10 +649,10 @@ index 40369ee..0000000
     -include $(call all-makefiles-under, $(LOCAL_PATH))
     diff --git a/services/tests/servicestests/Android.mk b/services/tests/servicestests/Android.mk
     deleted file mode 100644
    -index 50e0662..0000000
    +index 7886b5e..0000000
     --- a/services/tests/servicestests/Android.mk
     +++ /dev/null
    -@@ -1,81 +0,0 @@
    +@@ -1,87 +0,0 @@
     -#########################################################################
     -# Build FrameworksServicesTests package
     -#########################################################################
    @@ -451,7 +676,8 @@ index 50e0662..0000000
     -    guava \
     -    android-support-test \
     -    mockito-target \
    --    ShortcutManagerTestUtils
    +-    ShortcutManagerTestUtils \
    +-    truth-prebuilt
     -
     -LOCAL_JAVA_LIBRARIES := android.test.runner
     -
    @@ -476,6 +702,11 @@ index 50e0662..0000000
     -
     -LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
     -
    +-# Code coverage puts us over the dex limit, so enable multi-dex for coverage-enabled builds
    +-ifeq (true,$(EMMA_INSTRUMENT))
    +-LOCAL_JACK_FLAGS := --multi-dex native
    +-endif # EMMA_INSTRUMENT_STATIC
    +-
     -include $(BUILD_PACKAGE)
     -
     -#########################################################################
    @@ -2532,10 +2763,10 @@ index 221fe0f..0000000
     -}
     diff --git a/services/tests/servicestests/src/android/net/apf/ApfTest.java b/services/tests/servicestests/src/android/net/apf/ApfTest.java
     deleted file mode 100644
    -index f7c61d1..0000000
    +index 6092fdd..0000000
     --- a/services/tests/servicestests/src/android/net/apf/ApfTest.java
     +++ /dev/null
    -@@ -1,1195 +0,0 @@
    +@@ -1,1205 +0,0 @@
     -/*
     - * Copyright (C) 2012 The Android Open Source Project
     - *
    @@ -3198,9 +3429,13 @@ index f7c61d1..0000000
     -    // The IPv6 all nodes address ff02::1
     -    private static final byte[] IPV6_ALL_NODES_ADDRESS =
     -            { (byte) 0xff, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 };
    +-    private static final byte[] IPV6_ALL_ROUTERS_ADDRESS =
    +-            { (byte) 0xff, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2 };
     -
     -    private static final int ICMP6_TYPE_OFFSET = ETH_HEADER_LEN + IPV6_HEADER_LEN;
    +-    private static final int ICMP6_ROUTER_SOLICITATION = 133;
     -    private static final int ICMP6_ROUTER_ADVERTISEMENT = 134;
    +-    private static final int ICMP6_NEIGHBOR_SOLICITATION = 135;
     -    private static final int ICMP6_NEIGHBOR_ANNOUNCEMENT = 136;
     -
     -    private static final int ICMP6_RA_HEADER_LEN = 16;
    @@ -3335,6 +3570,12 @@ index f7c61d1..0000000
     -        put(packet, IPV6_DEST_ADDR_OFFSET, IPV6_ALL_NODES_ADDRESS);
     -        assertDrop(program, packet.array());
     -
    +-        // Verify ICMPv6 RS to any is dropped
    +-        packet.put(ICMP6_TYPE_OFFSET, (byte)ICMP6_ROUTER_SOLICITATION);
    +-        assertDrop(program, packet.array());
    +-        put(packet, IPV6_DEST_ADDR_OFFSET, IPV6_ALL_ROUTERS_ADDRESS);
    +-        assertDrop(program, packet.array());
    +-
     -        apfFilter.shutdown();
     -    }
     -
    @@ -4066,10 +4307,10 @@ index 220e54d..0000000
     -}
     diff --git a/services/tests/servicestests/src/android/net/dhcp/DhcpPacketTest.java b/services/tests/servicestests/src/android/net/dhcp/DhcpPacketTest.java
     deleted file mode 100644
    -index b4e9db7..0000000
    +index bc8baa1..0000000
     --- a/services/tests/servicestests/src/android/net/dhcp/DhcpPacketTest.java
     +++ /dev/null
    -@@ -1,889 +0,0 @@
    +@@ -1,939 +0,0 @@
     -/*
     - * Copyright (C) 2015 The Android Open Source Project
     - *
    @@ -4099,6 +4340,7 @@ index b4e9db7..0000000
     -import java.nio.ByteBuffer;
     -import java.util.ArrayList;
     -import java.util.Arrays;
    +-import java.util.Random;
     -import junit.framework.TestCase;
     -
     -import static android.net.dhcp.DhcpPacket.*;
    @@ -4502,7 +4744,7 @@ index b4e9db7..0000000
     -        try {
     -            DhcpPacket offerPacket = DhcpPacket.decodeFullPacket(packet, packet.length, ENCAP_L3);
     -        } catch (DhcpPacket.ParseException expected) {
    --            assertDhcpErrorCodes(DhcpErrorEvent.PARSING_ERROR, expected.errorCode);
    +-            assertDhcpErrorCodes(DhcpErrorEvent.DHCP_NO_COOKIE, expected.errorCode);
     -            return;
     -        }
     -        fail("Dhcp packet parsing should have failed");
    @@ -4544,6 +4786,55 @@ index b4e9db7..0000000
     -        assertEquals(Integer.toHexString(expected), Integer.toHexString(got));
     -    }
     -
    +-    public void testTruncatedOfferPackets() throws Exception {
    +-        final byte[] packet = HexDump.hexStringToByteArray(
    +-            // IP header.
    +-            "450001518d0600004011144dc0a82b01c0a82bf7" +
    +-            // UDP header.
    +-            "00430044013d9ac7" +
    +-            // BOOTP header.
    +-            "02010600dfc23d1f0002000000000000c0a82bf7c0a82b0100000000" +
    +-            // MAC address.
    +-            "30766ff2a90c00000000000000000000" +
    +-            // Server name.
    +-            "0000000000000000000000000000000000000000000000000000000000000000" +
    +-            "0000000000000000000000000000000000000000000000000000000000000000" +
    +-            // File.
    +-            "0000000000000000000000000000000000000000000000000000000000000000" +
    +-            "0000000000000000000000000000000000000000000000000000000000000000" +
    +-            "0000000000000000000000000000000000000000000000000000000000000000" +
    +-            "0000000000000000000000000000000000000000000000000000000000000000" +
    +-            // Options
    +-            "638253633501023604c0a82b01330400000e103a04000007083b0400000c4e0104ffffff00" +
    +-            "1c04c0a82bff0304c0a82b010604c0a82b012b0f414e44524f49445f4d455445524544ff");
    +-
    +-        for (int len = 0; len < packet.length; len++) {
    +-            try {
    +-                DhcpPacket.decodeFullPacket(packet, len, ENCAP_L3);
    +-            } catch (ParseException e) {
    +-                if (e.errorCode == DhcpErrorEvent.PARSING_ERROR) {
    +-                    fail(String.format("bad truncated packet of length %d", len));
    +-                }
    +-            }
    +-        }
    +-    }
    +-
    +-    public void testRandomPackets() throws Exception {
    +-        final int maxRandomPacketSize = 512;
    +-        final Random r = new Random();
    +-        for (int i = 0; i < 10000; i++) {
    +-            byte[] packet = new byte[r.nextInt(maxRandomPacketSize + 1)];
    +-            r.nextBytes(packet);
    +-            try {
    +-                DhcpPacket.decodeFullPacket(packet, packet.length, ENCAP_L3);
    +-            } catch (ParseException e) {
    +-                if (e.errorCode == DhcpErrorEvent.PARSING_ERROR) {
    +-                    fail("bad packet: " + HexDump.toHexString(packet));
    +-                }
    +-            }
    +-        }
    +-    }
    +-
     -    private byte[] mtuBytes(int mtu) {
     -        // 0x1a02: option 26, length 2. 0xff: no more options.
     -        if (mtu > Short.MAX_VALUE - Short.MIN_VALUE) {
    @@ -6923,10 +7214,10 @@ index 10b9e7c..0000000
     -    }
     -}
     diff --git a/services/tests/servicestests/src/com/android/server/ConnectivityServiceTest.java b/services/tests/servicestests/src/com/android/server/ConnectivityServiceTest.java
    -index 4af1cf1..c2c6e21 100644
    +index 65f9399..012bdd8 100644
     --- a/services/tests/servicestests/src/com/android/server/ConnectivityServiceTest.java
     +++ b/services/tests/servicestests/src/com/android/server/ConnectivityServiceTest.java
    -@@ -614,6 +614,19 @@ public class ConnectivityServiceTest extends AndroidTestCase {
    +@@ -620,6 +620,19 @@ public class ConnectivityServiceTest extends AndroidTestCase {
              }
          }
      
    @@ -11049,215 +11340,12 @@ index 984a484..0000000
     -    }
     -}
     \ No newline at end of file
    -diff --git a/services/tests/servicestests/src/com/android/server/connectivity/DnsEventListenerServiceTest.java b/services/tests/servicestests/src/com/android/server/connectivity/DnsEventListenerServiceTest.java
    -deleted file mode 100644
    -index 033b2c9..0000000
    ---- a/services/tests/servicestests/src/com/android/server/connectivity/DnsEventListenerServiceTest.java
    -+++ /dev/null
    -@@ -1,197 +0,0 @@
    --/*
    -- * Copyright (C) 2016, 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 com.android.server.connectivity;
    --
    --import android.net.ConnectivityManager.NetworkCallback;
    --import android.net.ConnectivityManager;
    --import android.net.Network;
    --import android.net.metrics.DnsEvent;
    --import android.net.metrics.IDnsEventListener;
    --import android.net.metrics.IpConnectivityLog;
    --
    --import junit.framework.TestCase;
    --import org.junit.Before;
    --import org.junit.Test;
    --import static org.junit.Assert.assertArrayEquals;
    --import static org.junit.Assert.assertTrue;
    --
    --import org.mockito.ArgumentCaptor;
    --import org.mockito.Mock;
    --import org.mockito.Mockito;
    --import org.mockito.MockitoAnnotations;
    --import static org.mockito.Mockito.any;
    --import static org.mockito.Mockito.anyInt;
    --import static org.mockito.Mockito.eq;
    --import static org.mockito.Mockito.timeout;
    --import static org.mockito.Mockito.times;
    --import static org.mockito.Mockito.verify;
    --
    --import java.io.FileOutputStream;
    --import java.io.PrintWriter;
    --import java.util.Arrays;
    --import java.util.List;
    --import java.util.OptionalInt;
    --import java.util.stream.IntStream;
    --
    --public class DnsEventListenerServiceTest extends TestCase {
    --
    --    // TODO: read from DnsEventListenerService after this constant is read from system property
    --    static final int BATCH_SIZE = 100;
    --    static final int EVENT_TYPE = IDnsEventListener.EVENT_GETADDRINFO;
    --    // TODO: read from IDnsEventListener
    --    static final int RETURN_CODE = 1;
    --
    --    static final byte[] EVENT_TYPES  = new byte[BATCH_SIZE];
    --    static final byte[] RETURN_CODES = new byte[BATCH_SIZE];
    --    static final int[] LATENCIES     = new int[BATCH_SIZE];
    --    static {
    --        for (int i = 0; i < BATCH_SIZE; i++) {
    --            EVENT_TYPES[i] = EVENT_TYPE;
    --            RETURN_CODES[i] = RETURN_CODE;
    --            LATENCIES[i] = i;
    --        }
    --    }
    --
    --    DnsEventListenerService mDnsService;
    --
    --    @Mock ConnectivityManager mCm;
    --    @Mock IpConnectivityLog mLog;
    --    ArgumentCaptor<NetworkCallback> mCallbackCaptor;
    --    ArgumentCaptor<DnsEvent> mEvCaptor;
    --
    --    public void setUp() {
    --        MockitoAnnotations.initMocks(this);
    --        mCallbackCaptor = ArgumentCaptor.forClass(NetworkCallback.class);
    --        mEvCaptor = ArgumentCaptor.forClass(DnsEvent.class);
    --        mDnsService = new DnsEventListenerService(mCm, mLog);
    --
    --        verify(mCm, times(1)).registerNetworkCallback(any(), mCallbackCaptor.capture());
    --    }
    --
    --    public void testOneBatch() throws Exception {
    --        log(105, LATENCIES);
    --        log(106, Arrays.copyOf(LATENCIES, BATCH_SIZE - 1)); // one lookup short of a batch event
    --
    --        verifyLoggedEvents(new DnsEvent(105, EVENT_TYPES, RETURN_CODES, LATENCIES));
    --
    --        log(106, Arrays.copyOfRange(LATENCIES, BATCH_SIZE - 1, BATCH_SIZE));
    --
    --        mEvCaptor = ArgumentCaptor.forClass(DnsEvent.class); // reset argument captor
    --        verifyLoggedEvents(
    --            new DnsEvent(105, EVENT_TYPES, RETURN_CODES, LATENCIES),
    --            new DnsEvent(106, EVENT_TYPES, RETURN_CODES, LATENCIES));
    --    }
    --
    --    public void testSeveralBatches() throws Exception {
    --        log(105, LATENCIES);
    --        log(106, LATENCIES);
    --        log(105, LATENCIES);
    --        log(107, LATENCIES);
    --
    --        verifyLoggedEvents(
    --            new DnsEvent(105, EVENT_TYPES, RETURN_CODES, LATENCIES),
    --            new DnsEvent(106, EVENT_TYPES, RETURN_CODES, LATENCIES),
    --            new DnsEvent(105, EVENT_TYPES, RETURN_CODES, LATENCIES),
    --            new DnsEvent(107, EVENT_TYPES, RETURN_CODES, LATENCIES));
    --    }
    --
    --    public void testBatchAndNetworkLost() throws Exception {
    --        byte[] eventTypes = Arrays.copyOf(EVENT_TYPES, 20);
    --        byte[] returnCodes = Arrays.copyOf(RETURN_CODES, 20);
    --        int[] latencies = Arrays.copyOf(LATENCIES, 20);
    --
    --        log(105, LATENCIES);
    --        log(105, latencies);
    --        mCallbackCaptor.getValue().onLost(new Network(105));
    --        log(105, LATENCIES);
    --
    --        verifyLoggedEvents(
    --            new DnsEvent(105, eventTypes, returnCodes, latencies),
    --            new DnsEvent(105, EVENT_TYPES, RETURN_CODES, LATENCIES),
    --            new DnsEvent(105, EVENT_TYPES, RETURN_CODES, LATENCIES));
    --    }
    --
    --    public void testConcurrentBatchesAndDumps() throws Exception {
    --        final long stop = System.currentTimeMillis() + 100;
    --        final PrintWriter pw = new PrintWriter(new FileOutputStream("/dev/null"));
    --        new Thread() {
    --            public void run() {
    --                while (System.currentTimeMillis() < stop) {
    --                    mDnsService.dump(pw);
    --                }
    --            }
    --        }.start();
    --
    --        logAsync(105, LATENCIES);
    --        logAsync(106, LATENCIES);
    --        logAsync(107, LATENCIES);
    --
    --        verifyLoggedEvents(500,
    --            new DnsEvent(105, EVENT_TYPES, RETURN_CODES, LATENCIES),
    --            new DnsEvent(106, EVENT_TYPES, RETURN_CODES, LATENCIES),
    --            new DnsEvent(107, EVENT_TYPES, RETURN_CODES, LATENCIES));
    --    }
    --
    --    public void testConcurrentBatchesAndNetworkLoss() throws Exception {
    --        logAsync(105, LATENCIES);
    --        Thread.sleep(10L);
    --        // call onLost() asynchronously to logAsync's onDnsEvent() calls.
    --        mCallbackCaptor.getValue().onLost(new Network(105));
    --
    --        // do not verify unpredictable batch
    --        verify(mLog, timeout(500).times(1)).log(any());
    --    }
    --
    --    void log(int netId, int[] latencies) {
    --        for (int l : latencies) {
    --            mDnsService.onDnsEvent(netId, EVENT_TYPE, RETURN_CODE, l);
    --        }
    --    }
    --
    --    void logAsync(int netId, int[] latencies) {
    --        new Thread() {
    --            public void run() {
    --                log(netId, latencies);
    --            }
    --        }.start();
    --    }
    --
    --    void verifyLoggedEvents(DnsEvent... expected) {
    --        verifyLoggedEvents(0, expected);
    --    }
    --
    --    void verifyLoggedEvents(int wait, DnsEvent... expectedEvents) {
    --        verify(mLog, timeout(wait).times(expectedEvents.length)).log(mEvCaptor.capture());
    --        for (DnsEvent got : mEvCaptor.getAllValues()) {
    --            OptionalInt index = IntStream.range(0, expectedEvents.length)
    --                    .filter(i -> eventsEqual(expectedEvents[i], got))
    --                    .findFirst();
    --            // Don't match same expected event more than once.
    --            index.ifPresent(i -> expectedEvents[i] = null);
    --            assertTrue(index.isPresent());
    --        }
    --    }
    --
    --    /** equality function for DnsEvent to avoid overriding equals() and hashCode(). */
    --    static boolean eventsEqual(DnsEvent expected, DnsEvent got) {
    --        return (expected == got) || ((expected != null) && (got != null)
    --                && (expected.netId == got.netId)
    --                && Arrays.equals(expected.eventTypes, got.eventTypes)
    --                && Arrays.equals(expected.returnCodes, got.returnCodes)
    --                && Arrays.equals(expected.latenciesMs, got.latenciesMs));
    --    }
    --}
     diff --git a/services/tests/servicestests/src/com/android/server/connectivity/IpConnectivityEventBuilderTest.java b/services/tests/servicestests/src/com/android/server/connectivity/IpConnectivityEventBuilderTest.java
     deleted file mode 100644
    -index aed3635..0000000
    +index 011e505..0000000
     --- a/services/tests/servicestests/src/com/android/server/connectivity/IpConnectivityEventBuilderTest.java
     +++ /dev/null
    -@@ -1,359 +0,0 @@
    +@@ -1,389 +0,0 @@
     -/*
     - * Copyright (C) 2016 The Android Open Source Project
     - *
    @@ -11276,6 +11364,17 @@ index aed3635..0000000
     -
     -package com.android.server.connectivity;
     -
    +-import static com.android.server.connectivity.MetricsTestUtil.aBool;
    +-import static com.android.server.connectivity.MetricsTestUtil.aByteArray;
    +-import static com.android.server.connectivity.MetricsTestUtil.aLong;
    +-import static com.android.server.connectivity.MetricsTestUtil.aString;
    +-import static com.android.server.connectivity.MetricsTestUtil.aType;
    +-import static com.android.server.connectivity.MetricsTestUtil.anInt;
    +-import static com.android.server.connectivity.MetricsTestUtil.anIntArray;
    +-import static com.android.server.connectivity.MetricsTestUtil.b;
    +-import static com.android.server.connectivity.MetricsTestUtil.describeIpEvent;
    +-import static com.android.server.connectivity.metrics.IpConnectivityLogClass.IpConnectivityLog;
    +-
     -import android.net.ConnectivityMetricsEvent;
     -import android.net.metrics.ApfProgramEvent;
     -import android.net.metrics.ApfStats;
    @@ -11288,24 +11387,13 @@ index aed3635..0000000
     -import android.net.metrics.NetworkEvent;
     -import android.net.metrics.RaEvent;
     -import android.net.metrics.ValidationProbeEvent;
    --import com.google.protobuf.nano.MessageNano;
    +-import android.test.suitebuilder.annotation.SmallTest;
     -import java.util.Arrays;
     -import junit.framework.TestCase;
     -
    --import static com.android.server.connectivity.metrics.IpConnectivityLogClass.IpConnectivityLog;
    --import static com.android.server.connectivity.MetricsTestUtil.aBool;
    --import static com.android.server.connectivity.MetricsTestUtil.aByteArray;
    --import static com.android.server.connectivity.MetricsTestUtil.aLong;
    --import static com.android.server.connectivity.MetricsTestUtil.aString;
    --import static com.android.server.connectivity.MetricsTestUtil.aType;
    --import static com.android.server.connectivity.MetricsTestUtil.anInt;
    --import static com.android.server.connectivity.MetricsTestUtil.anIntArray;
    --import static com.android.server.connectivity.MetricsTestUtil.b;
    --import static com.android.server.connectivity.MetricsTestUtil.describeIpEvent;
    --import static com.android.server.connectivity.MetricsTestUtil.ipEv;
    --
     -public class IpConnectivityEventBuilderTest extends TestCase {
     -
    +-    @SmallTest
     -    public void testDefaultNetworkEventSerialization() {
     -        ConnectivityMetricsEvent ev = describeIpEvent(
     -                aType(DefaultNetworkEvent.class),
    @@ -11318,6 +11406,8 @@ index aed3635..0000000
     -        String want = joinLines(
     -                "dropped_events: 0",
     -                "events <",
    +-                "  time_ms: 1",
    +-                "  transport: 0",
     -                "  default_network_event <",
     -                "    network_id <",
     -                "      network_id: 102",
    @@ -11330,12 +11420,13 @@ index aed3635..0000000
     -                "    transport_types: 2",
     -                "    transport_types: 3",
     -                "  >",
    --                "  time_ms: 1",
    --                ">");
    +-                ">",
    +-                "version: 2");
     -
     -        verifySerialization(want, ev);
     -    }
     -
    +-    @SmallTest
     -    public void testDhcpClientEventSerialization() {
     -        ConnectivityMetricsEvent ev = describeIpEvent(
     -                aType(DhcpClientEvent.class),
    @@ -11346,18 +11437,20 @@ index aed3635..0000000
     -        String want = joinLines(
     -                "dropped_events: 0",
     -                "events <",
    +-                "  time_ms: 1",
    +-                "  transport: 0",
     -                "  dhcp_event <",
     -                "    duration_ms: 192",
    --                "    error_code: 0",
     -                "    if_name: \"wlan0\"",
     -                "    state_transition: \"SomeState\"",
     -                "  >",
    --                "  time_ms: 1",
    --                ">");
    +-                ">",
    +-                "version: 2");
     -
     -        verifySerialization(want, ev);
     -    }
     -
    +-    @SmallTest
     -    public void testDhcpErrorEventSerialization() {
     -        ConnectivityMetricsEvent ev = describeIpEvent(
     -                aType(DhcpErrorEvent.class),
    @@ -11367,18 +11460,20 @@ index aed3635..0000000
     -        String want = joinLines(
     -                "dropped_events: 0",
     -                "events <",
    +-                "  time_ms: 1",
    +-                "  transport: 0",
     -                "  dhcp_event <",
     -                "    duration_ms: 0",
    --                "    error_code: 50397184",
     -                "    if_name: \"wlan0\"",
    --                "    state_transition: \"\"",
    +-                "    error_code: 50397184",
     -                "  >",
    --                "  time_ms: 1",
    --                ">");
    +-                ">",
    +-                "version: 2");
     -
     -        verifySerialization(want, ev);
     -    }
     -
    +-    @SmallTest
     -    public void testDnsEventSerialization() {
     -        ConnectivityMetricsEvent ev = describeIpEvent(
     -                aType(DnsEvent.class),
    @@ -11390,6 +11485,8 @@ index aed3635..0000000
     -        String want = joinLines(
     -                "dropped_events: 0",
     -                "events <",
    +-                "  time_ms: 1",
    +-                "  transport: 0",
     -                "  dns_lookup_batch <",
     -                "    event_types: 1",
     -                "    event_types: 1",
    @@ -11419,12 +11516,13 @@ index aed3635..0000000
     -                "    return_codes: 200",
     -                "    return_codes: 178",
     -                "  >",
    --                "  time_ms: 1",
    --                ">");
    +-                ">",
    +-                "version: 2");
     -
     -        verifySerialization(want, ev);
     -    }
     -
    +-    @SmallTest
     -    public void testIpManagerEventSerialization() {
     -        ConnectivityMetricsEvent ev = describeIpEvent(
     -                aType(IpManagerEvent.class),
    @@ -11435,17 +11533,20 @@ index aed3635..0000000
     -        String want = joinLines(
     -                "dropped_events: 0",
     -                "events <",
    +-                "  time_ms: 1",
    +-                "  transport: 0",
     -                "  ip_provisioning_event <",
     -                "    event_type: 1",
     -                "    if_name: \"wlan0\"",
     -                "    latency_ms: 5678",
     -                "  >",
    --                "  time_ms: 1",
    --                ">");
    +-                ">",
    +-                "version: 2");
     -
     -        verifySerialization(want, ev);
     -    }
     -
    +-    @SmallTest
     -    public void testIpReachabilityEventSerialization() {
     -        ConnectivityMetricsEvent ev = describeIpEvent(
     -                aType(IpReachabilityEvent.class),
    @@ -11455,16 +11556,19 @@ index aed3635..0000000
     -        String want = joinLines(
     -                "dropped_events: 0",
     -                "events <",
    +-                "  time_ms: 1",
    +-                "  transport: 0",
     -                "  ip_reachability_event <",
     -                "    event_type: 512",
     -                "    if_name: \"wlan0\"",
     -                "  >",
    --                "  time_ms: 1",
    --                ">");
    +-                ">",
    +-                "version: 2");
     -
     -        verifySerialization(want, ev);
     -    }
     -
    +-    @SmallTest
     -    public void testNetworkEventSerialization() {
     -        ConnectivityMetricsEvent ev = describeIpEvent(
     -                aType(NetworkEvent.class),
    @@ -11475,6 +11579,8 @@ index aed3635..0000000
     -        String want = joinLines(
     -                "dropped_events: 0",
     -                "events <",
    +-                "  time_ms: 1",
    +-                "  transport: 0",
     -                "  network_event <",
     -                "    event_type: 5",
     -                "    latency_ms: 20410",
    @@ -11482,12 +11588,13 @@ index aed3635..0000000
     -                "      network_id: 100",
     -                "    >",
     -                "  >",
    --                "  time_ms: 1",
    --                ">");
    +-                ">",
    +-                "version: 2");
     -
     -        verifySerialization(want, ev);
     -    }
     -
    +-    @SmallTest
     -    public void testValidationProbeEventSerialization() {
     -        ConnectivityMetricsEvent ev = describeIpEvent(
     -                aType(ValidationProbeEvent.class),
    @@ -11500,6 +11607,7 @@ index aed3635..0000000
     -                "dropped_events: 0",
     -                "events <",
     -                "  time_ms: 1",
    +-                "  transport: 0",
     -                "  validation_probe_event <",
     -                "    latency_ms: 40730",
     -                "    network_id <",
    @@ -11508,11 +11616,13 @@ index aed3635..0000000
     -                "    probe_result: 204",
     -                "    probe_type: 1",
     -                "  >",
    --                ">");
    +-                ">",
    +-                "version: 2");
     -
     -        verifySerialization(want, ev);
     -    }
     -
    +-    @SmallTest
     -    public void testApfProgramEventSerialization() {
     -        ConnectivityMetricsEvent ev = describeIpEvent(
     -                aType(ApfProgramEvent.class),
    @@ -11525,6 +11635,8 @@ index aed3635..0000000
     -        String want = joinLines(
     -                "dropped_events: 0",
     -                "events <",
    +-                "  time_ms: 1",
    +-                "  transport: 0",
     -                "  apf_program_event <",
     -                "    current_ras: 9",
     -                "    drop_multicast: true",
    @@ -11533,12 +11645,13 @@ index aed3635..0000000
     -                "    lifetime: 200",
     -                "    program_length: 2048",
     -                "  >",
    --                "  time_ms: 1",
    --                ">");
    +-                ">",
    +-                "version: 2");
     -
     -        verifySerialization(want, ev);
     -    }
     -
    +-    @SmallTest
     -    public void testApfStatsSerialization() {
     -        ConnectivityMetricsEvent ev = describeIpEvent(
     -                aType(ApfStats.class),
    @@ -11554,6 +11667,8 @@ index aed3635..0000000
     -        String want = joinLines(
     -                "dropped_events: 0",
     -                "events <",
    +-                "  time_ms: 1",
    +-                "  transport: 0",
     -                "  apf_statistics <",
     -                "    dropped_ras: 2",
     -                "    duration_ms: 45000",
    @@ -11564,12 +11679,13 @@ index aed3635..0000000
     -                "    received_ras: 10",
     -                "    zero_lifetime_ras: 1",
     -                "  >",
    --                "  time_ms: 1",
    --                ">");
    +-                ">",
    +-                "version: 2");
     -
     -        verifySerialization(want, ev);
     -    }
     -
    +-    @SmallTest
     -    public void testRaEventSerialization() {
     -        ConnectivityMetricsEvent ev = describeIpEvent(
     -                aType(RaEvent.class),
    @@ -11583,6 +11699,8 @@ index aed3635..0000000
     -        String want = joinLines(
     -                "dropped_events: 0",
     -                "events <",
    +-                "  time_ms: 1",
    +-                "  transport: 0",
     -                "  ra_event <",
     -                "    dnssl_lifetime: -1",
     -                "    prefix_preferred_lifetime: 300",
    @@ -11591,17 +11709,17 @@ index aed3635..0000000
     -                "    route_info_lifetime: -1",
     -                "    router_lifetime: 2000",
     -                "  >",
    --                "  time_ms: 1",
    --                ">");
    +-                ">",
    +-                "version: 2");
     -
     -        verifySerialization(want, ev);
     -    }
     -
     -    static void verifySerialization(String want, ConnectivityMetricsEvent... input) {
     -        try {
    --            byte[] got = IpConnectivityEventBuilder.serialize(0, Arrays.asList(input));
    --            IpConnectivityLog log = new IpConnectivityLog();
    --            MessageNano.mergeFrom(log, got);
    +-            byte[] got = IpConnectivityEventBuilder.serialize(0,
    +-                    IpConnectivityEventBuilder.toProto(Arrays.asList(input)));
    +-            IpConnectivityLog log = IpConnectivityLog.parseFrom(got);
     -            assertEquals(want, log.toString());
     -        } catch (Exception e) {
     -            fail(e.toString());
    @@ -11619,10 +11737,10 @@ index aed3635..0000000
     -}
     diff --git a/services/tests/servicestests/src/com/android/server/connectivity/IpConnectivityMetricsTest.java b/services/tests/servicestests/src/com/android/server/connectivity/IpConnectivityMetricsTest.java
     deleted file mode 100644
    -index 3fc89b9..0000000
    +index 450653c..0000000
     --- a/services/tests/servicestests/src/com/android/server/connectivity/IpConnectivityMetricsTest.java
     +++ /dev/null
    -@@ -1,269 +0,0 @@
    +@@ -1,296 +0,0 @@
     -/*
     - * Copyright (C) 2016, The Android Open Source Project
     - *
    @@ -11641,9 +11759,13 @@ index 3fc89b9..0000000
     -
     -package com.android.server.connectivity;
     -
    +-import static org.mockito.Mockito.timeout;
    +-import static org.mockito.Mockito.verify;
    +-
     -import android.content.Context;
     -import android.net.ConnectivityMetricsEvent;
     -import android.net.IIpConnectivityMetrics;
    +-import android.net.metrics.ApfProgramEvent;
     -import android.net.metrics.ApfStats;
     -import android.net.metrics.DefaultNetworkEvent;
     -import android.net.metrics.DhcpClientEvent;
    @@ -11653,9 +11775,9 @@ index 3fc89b9..0000000
     -import android.net.metrics.RaEvent;
     -import android.net.metrics.ValidationProbeEvent;
     -import android.os.Parcelable;
    +-import android.test.suitebuilder.annotation.SmallTest;
     -import android.util.Base64;
     -import com.android.server.connectivity.metrics.IpConnectivityLogClass;
    --import com.google.protobuf.nano.MessageNano;
     -import java.io.PrintWriter;
     -import java.io.StringWriter;
     -import java.util.Collections;
    @@ -11667,10 +11789,6 @@ index 3fc89b9..0000000
     -import org.mockito.Mock;
     -import org.mockito.MockitoAnnotations;
     -
    --import static org.mockito.Mockito.timeout;
    --import static org.mockito.Mockito.times;
    --import static org.mockito.Mockito.verify;
    --
     -public class IpConnectivityMetricsTest extends TestCase {
     -    static final IpReachabilityEvent FAKE_EV =
     -            new IpReachabilityEvent("wlan0", IpReachabilityEvent.NUD_FAILED);
    @@ -11682,9 +11800,10 @@ index 3fc89b9..0000000
     -
     -    public void setUp() {
     -        MockitoAnnotations.initMocks(this);
    --        mService = new IpConnectivityMetrics(mCtx);
    +-        mService = new IpConnectivityMetrics(mCtx, (ctx) -> 2000);
     -    }
     -
    +-    @SmallTest
     -    public void testLoggingEvents() throws Exception {
     -        IpConnectivityLog logger = new IpConnectivityLog(mMockService);
     -
    @@ -11698,6 +11817,7 @@ index 3fc89b9..0000000
     -        assertEventsEqual(expectedEvent(3), got.get(2));
     -    }
     -
    +-    @SmallTest
     -    public void testLoggingEventsWithMultipleCallers() throws Exception {
     -        IpConnectivityLog logger = new IpConnectivityLog(mMockService);
     -
    @@ -11725,6 +11845,7 @@ index 3fc89b9..0000000
     -        }
     -    }
     -
    +-    @SmallTest
     -    public void testBufferFlushing() {
     -        String output1 = getdump("flush");
     -        assertEquals("", output1);
    @@ -11737,6 +11858,29 @@ index 3fc89b9..0000000
     -        assertEquals("", output3);
     -    }
     -
    +-    @SmallTest
    +-    public void testRateLimiting() {
    +-        final IpConnectivityLog logger = new IpConnectivityLog(mService.impl);
    +-        final ApfProgramEvent ev = new ApfProgramEvent(0, 0, 0, 0, 0);
    +-        final long fakeTimestamp = 1;
    +-
    +-        int attempt = 100; // More than burst quota, but less than buffer size.
    +-        for (int i = 0; i < attempt; i++) {
    +-            logger.log(ev);
    +-        }
    +-
    +-        String output1 = getdump("flush");
    +-        assertFalse("".equals(output1));
    +-
    +-        for (int i = 0; i < attempt; i++) {
    +-            assertFalse("expected event to be dropped", logger.log(fakeTimestamp, ev));
    +-        }
    +-
    +-        String output2 = getdump("flush");
    +-        assertEquals("", output2);
    +-    }
    +-
    +-    @SmallTest
     -    public void testEndToEndLogging() {
     -        IpConnectivityLog logger = new IpConnectivityLog(mService.impl);
     -
    @@ -11757,22 +11901,25 @@ index 3fc89b9..0000000
     -        String want = joinLines(
     -                "dropped_events: 0",
     -                "events <",
    +-                "  time_ms: 100",
    +-                "  transport: 0",
     -                "  ip_reachability_event <",
     -                "    event_type: 512",
     -                "    if_name: \"wlan0\"",
     -                "  >",
    --                "  time_ms: 100",
     -                ">",
     -                "events <",
    +-                "  time_ms: 200",
    +-                "  transport: 0",
     -                "  dhcp_event <",
     -                "    duration_ms: 192",
    --                "    error_code: 0",
     -                "    if_name: \"wlan0\"",
     -                "    state_transition: \"SomeState\"",
     -                "  >",
    --                "  time_ms: 200",
     -                ">",
     -                "events <",
    +-                "  time_ms: 300",
    +-                "  transport: 0",
     -                "  default_network_event <",
     -                "    network_id <",
     -                "      network_id: 102",
    @@ -11785,18 +11932,19 @@ index 3fc89b9..0000000
     -                "    transport_types: 2",
     -                "    transport_types: 3",
     -                "  >",
    --                "  time_ms: 300",
     -                ">",
     -                "events <",
    +-                "  time_ms: 400",
    +-                "  transport: 0",
     -                "  ip_provisioning_event <",
     -                "    event_type: 1",
     -                "    if_name: \"wlan0\"",
     -                "    latency_ms: 5678",
     -                "  >",
    --                "  time_ms: 400",
     -                ">",
     -                "events <",
     -                "  time_ms: 500",
    +-                "  transport: 0",
     -                "  validation_probe_event <",
     -                "    latency_ms: 40730",
     -                "    network_id <",
    @@ -11807,6 +11955,8 @@ index 3fc89b9..0000000
     -                "  >",
     -                ">",
     -                "events <",
    +-                "  time_ms: 600",
    +-                "  transport: 0",
     -                "  apf_statistics <",
     -                "    dropped_ras: 2",
     -                "    duration_ms: 45000",
    @@ -11817,9 +11967,10 @@ index 3fc89b9..0000000
     -                "    received_ras: 10",
     -                "    zero_lifetime_ras: 1",
     -                "  >",
    --                "  time_ms: 600",
     -                ">",
     -                "events <",
    +-                "  time_ms: 700",
    +-                "  transport: 0",
     -                "  ra_event <",
     -                "    dnssl_lifetime: -1",
     -                "    prefix_preferred_lifetime: 300",
    @@ -11828,8 +11979,8 @@ index 3fc89b9..0000000
     -                "    route_info_lifetime: -1",
     -                "    router_lifetime: 2000",
     -                "  >",
    --                "  time_ms: 700",
    --                ">");
    +-                ">",
    +-                "version: 2");
     -
     -        verifySerialization(want, getdump("flush"));
     -    }
    @@ -11856,8 +12007,7 @@ index 3fc89b9..0000000
     -        try {
     -            byte[] got = Base64.decode(output, Base64.DEFAULT);
     -            IpConnectivityLogClass.IpConnectivityLog log =
    --                    new IpConnectivityLogClass.IpConnectivityLog();
    --            MessageNano.mergeFrom(log, got);
    +-                    IpConnectivityLogClass.IpConnectivityLog.parseFrom(got);
     -            assertEquals(want, log.toString());
     -        } catch (Exception e) {
     -            fail(e.toString());
    @@ -11885,12 +12035,7 @@ index 3fc89b9..0000000
     -    }
     -
     -    static final Comparator<ConnectivityMetricsEvent> EVENT_COMPARATOR =
    --        new Comparator<ConnectivityMetricsEvent>() {
    --            @Override
    --            public int compare(ConnectivityMetricsEvent ev1, ConnectivityMetricsEvent ev2) {
    --                return (int) (ev1.timestamp - ev2.timestamp);
    --            }
    --        };
    +-        Comparator.comparingLong((ev) -> ev.timestamp);
     -}
     diff --git a/services/tests/servicestests/src/com/android/server/connectivity/LingerMonitorTest.java b/services/tests/servicestests/src/com/android/server/connectivity/LingerMonitorTest.java
     deleted file mode 100644
    @@ -16735,10 +16880,10 @@ index 3da61d6..0000000
     -}
     diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DpmMockContext.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DpmMockContext.java
     deleted file mode 100644
    -index 0783afc..0000000
    +index 956d83a..0000000
     --- a/services/tests/servicestests/src/com/android/server/devicepolicy/DpmMockContext.java
     +++ /dev/null
    -@@ -1,612 +0,0 @@
    +@@ -1,619 +0,0 @@
     -/*
     - * Copyright (C) 2015 The Android Open Source Project
     - *
    @@ -16757,8 +16902,15 @@ index 0783afc..0000000
     -
     -package com.android.server.devicepolicy;
     -
    --import com.android.internal.widget.LockPatternUtils;
    +-import static org.mockito.Matchers.anyBoolean;
    +-import static org.mockito.Matchers.anyInt;
    +-import static org.mockito.Matchers.eq;
    +-import static org.mockito.Mockito.mock;
    +-import static org.mockito.Mockito.spy;
    +-import static org.mockito.Mockito.when;
     -
    +-import android.accounts.Account;
    +-import android.accounts.AccountManager;
     -import android.app.IActivityManager;
     -import android.app.NotificationManager;
     -import android.app.backup.IBackupManager;
    @@ -16785,6 +16937,8 @@ index 0783afc..0000000
     -import android.test.mock.MockContext;
     -import android.view.IWindowManager;
     -
    +-import com.android.internal.widget.LockPatternUtils;
    +-
     -import org.junit.Assert;
     -import org.mockito.invocation.InvocationOnMock;
     -import org.mockito.stubbing.Answer;
    @@ -16793,13 +16947,6 @@ index 0783afc..0000000
     -import java.util.ArrayList;
     -import java.util.List;
     -
    --import static org.mockito.Matchers.anyBoolean;
    --import static org.mockito.Matchers.anyInt;
    --import static org.mockito.Matchers.eq;
    --import static org.mockito.Mockito.mock;
    --import static org.mockito.Mockito.spy;
    --import static org.mockito.Mockito.when;
    --
     -/**
     - * Context used throughout DPMS tests.
     - */
    @@ -17005,6 +17152,7 @@ index 0783afc..0000000
     -    public final SettingsForMock settings;
     -    public final MockContentResolver contentResolver;
     -    public final TelephonyManager telephonyManager;
    +-    public final AccountManager accountManager;
     -
     -    /** Note this is a partial mock, not a real mock. */
     -    public final PackageManager packageManager;
    @@ -17039,6 +17187,7 @@ index 0783afc..0000000
     -        wifiManager = mock(WifiManager.class);
     -        settings = mock(SettingsForMock.class);
     -        telephonyManager = mock(TelephonyManager.class);
    +-        accountManager = mock(AccountManager.class);
     -
     -        // Package manager is huge, so we use a partial mock instead.
     -        packageManager = spy(context.getPackageManager());
    @@ -17101,6 +17250,7 @@ index 0783afc..0000000
     -                    }
     -                }
     -        );
    +-        when(accountManager.getAccountsAsUser(anyInt())).thenReturn(new Account[0]);
     -
     -
     -        // Create a data directory.
    @@ -17159,6 +17309,8 @@ index 0783afc..0000000
     -                return powerManager;
     -            case Context.WIFI_SERVICE:
     -                return wifiManager;
    +-            case Context.ACCOUNT_SERVICE:
    +-                return accountManager;
     -        }
     -        throw new UnsupportedOperationException();
     -    }
    @@ -26618,10 +26770,10 @@ index ebd3633..0000000
     -}
     diff --git a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest1.java b/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest1.java
     deleted file mode 100644
    -index 3cfdc32..0000000
    +index cd48f36..0000000
     --- a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest1.java
     +++ /dev/null
    -@@ -1,7340 +0,0 @@
    +@@ -1,7349 +0,0 @@
     -/*
     - * Copyright (C) 2016 The Android Open Source Project
     - *
    @@ -31562,6 +31714,9 @@ index 3cfdc32..0000000
     -            assertEquals(0, mManager.getDynamicShortcuts().size());
     -            assertEquals(0, mManager.getPinnedShortcuts().size());
     -        });
    +-        assertFalse(mService.getPackageShortcutForTest(CALLING_PACKAGE_1, USER_0)
    +-                .getPackageInfo().isShadow());
    +-
     -
     -        installPackage(USER_0, CALLING_PACKAGE_2);
     -        runWithCaller(CALLING_PACKAGE_2, USER_0, () -> {
    @@ -31570,6 +31725,8 @@ index 3cfdc32..0000000
     -                    mManager.getPinnedShortcuts()),
     -                    "s1", "s2", "s3");
     -        });
    +-        assertFalse(mService.getPackageShortcutForTest(CALLING_PACKAGE_2, USER_0)
    +-                .getPackageInfo().isShadow());
     -
     -        installPackage(USER_0, LAUNCHER_1);
     -        runWithCaller(LAUNCHER_1, USER_0, () -> {
    @@ -31693,6 +31850,8 @@ index 3cfdc32..0000000
     -                    mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_3), HANDLE_USER_0))
     -                    /* empty */);
     -        });
    +-        assertFalse(mService.getLauncherShortcutForTest(LAUNCHER_1, USER_0)
    +-                .getPackageInfo().isShadow());
     -
     -        runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
     -            assertEquals(0, mManager.getDynamicShortcuts().size());
    @@ -31715,6 +31874,8 @@ index 3cfdc32..0000000
     -                    mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_3), HANDLE_USER_0))
     -                    /* empty */);
     -        });
    +-        assertFalse(mService.getLauncherShortcutForTest(LAUNCHER_2, USER_0)
    +-                .getPackageInfo().isShadow());
     -
     -        installPackage(USER_0, CALLING_PACKAGE_3);
     -        runWithCaller(CALLING_PACKAGE_3, USER_0, () -> {
    diff --git a/frameworks_native.patch b/frameworks_native.patch
    index 113c81d..1f4576c 100644
    --- a/frameworks_native.patch
    +++ b/frameworks_native.patch
    @@ -252,10 +252,10 @@ index f13f49f..e45b5f1 100644
              
      }; // namespace android
     diff --git a/libs/gui/Android.mk b/libs/gui/Android.mk
    -index 46feb1c..1b4a9c5 100644
    +index 9e2fc2b..12d2148 100644
     --- a/libs/gui/Android.mk
     +++ b/libs/gui/Android.mk
    -@@ -84,6 +84,9 @@ LOCAL_SHARED_LIBRARIES := \
    +@@ -86,6 +86,9 @@ LOCAL_SHARED_LIBRARIES := \
      	libutils \
      	liblog
      
    @@ -748,34 +748,6 @@ index 0000000..3ead25c
     +    }
     +    return static_cast<EGLNativeWindowType>(w);
     +}
    -diff --git a/libs/ui/Gralloc1On0Adapter.cpp b/libs/ui/Gralloc1On0Adapter.cpp
    -index d5b88de..ec7df31 100644
    ---- a/libs/ui/Gralloc1On0Adapter.cpp
    -+++ b/libs/ui/Gralloc1On0Adapter.cpp
    -@@ -288,6 +288,7 @@ gralloc1_error_t Gralloc1On0Adapter::allocateWithIdHook(
    - gralloc1_error_t Gralloc1On0Adapter::retain(
    -         const std::shared_ptr<Buffer>& buffer)
    - {
    -+    std::lock_guard<std::mutex> lock(mBufferMutex);
    -     buffer->retain();
    -     return GRALLOC1_ERROR_NONE;
    - }
    -@@ -295,6 +296,7 @@ gralloc1_error_t Gralloc1On0Adapter::retain(
    - gralloc1_error_t Gralloc1On0Adapter::release(
    -         const std::shared_ptr<Buffer>& buffer)
    - {
    -+    std::lock_guard<std::mutex> lock(mBufferMutex);
    -     if (!buffer->release()) {
    -         return GRALLOC1_ERROR_NONE;
    -     }
    -@@ -314,7 +316,6 @@ gralloc1_error_t Gralloc1On0Adapter::release(
    -         }
    -     }
    - 
    --    std::lock_guard<std::mutex> lock(mBufferMutex);
    -     mBuffers.erase(handle);
    -     return GRALLOC1_ERROR_NONE;
    - }
     diff --git a/libs/ui/Region.cpp b/libs/ui/Region.cpp
     index ee152bf..9c82295 100644
     --- a/libs/ui/Region.cpp
    @@ -1069,10 +1041,10 @@ index 2190466..8c36d85 100644
                  mSinkBufferWidth, mSinkBufferHeight, format, usage);
          if (result < 0)
     diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
    -index dfece93..646014a 100644
    +index 3ffa655..3bb26ee 100644
     --- a/services/surfaceflinger/Layer.cpp
     +++ b/services/surfaceflinger/Layer.cpp
    -@@ -2055,11 +2055,16 @@ Region Layer::latchBuffer(bool& recomputeVisibleRegions)
    +@@ -2056,11 +2056,16 @@ Region Layer::latchBuffer(bool& recomputeVisibleRegions)
      
                  // Remove any stale buffers that have been dropped during
                  // updateTexImage
    @@ -1332,10 +1304,10 @@ index 0259881..5a5910a 100644
              int getStatus() const;
          };
     diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
    -index 8db071e..874cdc8 100644
    +index 8e7e577..a04684c 100644
     --- a/services/surfaceflinger/SurfaceFlinger.cpp
     +++ b/services/surfaceflinger/SurfaceFlinger.cpp
    -@@ -3438,7 +3438,8 @@ status_t SurfaceFlinger::captureScreen(const sp<IBinder>& display,
    +@@ -3437,7 +3437,8 @@ status_t SurfaceFlinger::captureScreen(const sp<IBinder>& display,
              const sp<IGraphicBufferProducer>& producer,
              Rect sourceCrop, uint32_t reqWidth, uint32_t reqHeight,
              uint32_t minLayerZ, uint32_t maxLayerZ,
    @@ -1345,7 +1317,7 @@ index 8db071e..874cdc8 100644
      
          if (CC_UNLIKELY(display == 0))
              return BAD_VALUE;
    -@@ -3482,6 +3483,7 @@ status_t SurfaceFlinger::captureScreen(const sp<IBinder>& display,
    +@@ -3481,6 +3482,7 @@ status_t SurfaceFlinger::captureScreen(const sp<IBinder>& display,
              bool useIdentityTransform;
              Transform::orientation_flags rotation;
              status_t result;
    @@ -1353,7 +1325,7 @@ index 8db071e..874cdc8 100644
              bool isLocalScreenshot;
          public:
              MessageCaptureScreen(SurfaceFlinger* flinger,
    -@@ -3491,12 +3493,13 @@ status_t SurfaceFlinger::captureScreen(const sp<IBinder>& display,
    +@@ -3490,12 +3492,13 @@ status_t SurfaceFlinger::captureScreen(const sp<IBinder>& display,
                      uint32_t minLayerZ, uint32_t maxLayerZ,
                      bool useIdentityTransform,
                      Transform::orientation_flags rotation,
    @@ -1368,7 +1340,7 @@ index 8db071e..874cdc8 100644
                    isLocalScreenshot(isLocalScreenshot)
              {
              }
    -@@ -3506,9 +3509,10 @@ status_t SurfaceFlinger::captureScreen(const sp<IBinder>& display,
    +@@ -3505,9 +3508,10 @@ status_t SurfaceFlinger::captureScreen(const sp<IBinder>& display,
              virtual bool handler() {
                  Mutex::Autolock _l(flinger->mStateLock);
                  sp<const DisplayDevice> hw(flinger->getDisplayDevice(display));
    @@ -1380,7 +1352,7 @@ index 8db071e..874cdc8 100644
                  static_cast<GraphicProducerWrapper*>(IInterface::asBinder(producer).get())->exit(result);
                  return true;
              }
    -@@ -3524,7 +3528,7 @@ status_t SurfaceFlinger::captureScreen(const sp<IBinder>& display,
    +@@ -3523,7 +3527,7 @@ status_t SurfaceFlinger::captureScreen(const sp<IBinder>& display,
          sp<MessageBase> msg = new MessageCaptureScreen(this,
                  display, IGraphicBufferProducer::asInterface( wrapper ),
                  sourceCrop, reqWidth, reqHeight, minLayerZ, maxLayerZ,
    @@ -1389,7 +1361,7 @@ index 8db071e..874cdc8 100644
      
          status_t res = postMessageAsync(msg);
          if (res == NO_ERROR) {
    -@@ -3607,7 +3611,7 @@ status_t SurfaceFlinger::captureScreenImplLocked(
    +@@ -3606,7 +3610,7 @@ status_t SurfaceFlinger::captureScreenImplLocked(
              Rect sourceCrop, uint32_t reqWidth, uint32_t reqHeight,
              uint32_t minLayerZ, uint32_t maxLayerZ,
              bool useIdentityTransform, Transform::orientation_flags rotation,
    @@ -1398,7 +1370,7 @@ index 8db071e..874cdc8 100644
      {
          ATRACE_CALL();
      
    -@@ -3685,7 +3689,7 @@ status_t SurfaceFlinger::captureScreenImplLocked(
    +@@ -3684,7 +3688,7 @@ status_t SurfaceFlinger::captureScreenImplLocked(
                      if (image != EGL_NO_IMAGE_KHR) {
                          // this binds the given EGLImage as a framebuffer for the
                          // duration of this scope.
    @@ -1407,7 +1379,7 @@ index 8db071e..874cdc8 100644
                          if (imageBond.getStatus() == NO_ERROR) {
                              // this will in fact render into our dequeued buffer
                              // via an FBO, which means we didn't have to create
    -@@ -3732,6 +3736,16 @@ status_t SurfaceFlinger::captureScreenImplLocked(
    +@@ -3731,6 +3735,16 @@ status_t SurfaceFlinger::captureScreenImplLocked(
                                      ALOGW("captureScreen: error creating EGL fence: %#x", eglGetError());
                                  }
                              }
    @@ -1482,7 +1454,7 @@ index e0e4c61..6f2520b 100644
      #ifdef USE_HWC2
          err = updateAndReleaseLocked(item, &mPendingRelease);
     diff --git a/services/surfaceflinger/SurfaceFlinger_hwc1.cpp b/services/surfaceflinger/SurfaceFlinger_hwc1.cpp
    -index b0f418c..94c95a6 100644
    +index b32f652..512f63d 100644
     --- a/services/surfaceflinger/SurfaceFlinger_hwc1.cpp
     +++ b/services/surfaceflinger/SurfaceFlinger_hwc1.cpp
     @@ -457,19 +457,28 @@ void SurfaceFlinger::init() {
    @@ -1551,7 +1523,7 @@ index b0f418c..94c95a6 100644
              info.fps = float(1e9 / hwConfig.refresh);
              info.appVsyncOffset = VSYNC_EVENT_PHASE_OFFSET_NS;
      
    -@@ -3187,12 +3207,14 @@ status_t SurfaceFlinger::onTransact(
    +@@ -3186,12 +3206,14 @@ status_t SurfaceFlinger::onTransact(
                  }
                  case 1018: { // Modify Choreographer's phase offset
                      n = data.readInt32();
    @@ -1568,7 +1540,7 @@ index b0f418c..94c95a6 100644
                      return NO_ERROR;
                  }
                  case 1021: { // Disable HWC virtual displays
    -@@ -3331,7 +3353,8 @@ status_t SurfaceFlinger::captureScreen(const sp<IBinder>& display,
    +@@ -3330,7 +3352,8 @@ status_t SurfaceFlinger::captureScreen(const sp<IBinder>& display,
              const sp<IGraphicBufferProducer>& producer,
              Rect sourceCrop, uint32_t reqWidth, uint32_t reqHeight,
              uint32_t minLayerZ, uint32_t maxLayerZ,
    @@ -1578,7 +1550,7 @@ index b0f418c..94c95a6 100644
      
          if (CC_UNLIKELY(display == 0))
              return BAD_VALUE;
    -@@ -3375,6 +3398,7 @@ status_t SurfaceFlinger::captureScreen(const sp<IBinder>& display,
    +@@ -3374,6 +3397,7 @@ status_t SurfaceFlinger::captureScreen(const sp<IBinder>& display,
              bool useIdentityTransform;
              Transform::orientation_flags rotation;
              status_t result;
    @@ -1586,7 +1558,7 @@ index b0f418c..94c95a6 100644
              bool isLocalScreenshot;
          public:
              MessageCaptureScreen(SurfaceFlinger* flinger,
    -@@ -3384,12 +3408,13 @@ status_t SurfaceFlinger::captureScreen(const sp<IBinder>& display,
    +@@ -3383,12 +3407,13 @@ status_t SurfaceFlinger::captureScreen(const sp<IBinder>& display,
                      uint32_t minLayerZ, uint32_t maxLayerZ,
                      bool useIdentityTransform,
                      Transform::orientation_flags rotation,
    @@ -1601,7 +1573,7 @@ index b0f418c..94c95a6 100644
                    isLocalScreenshot(isLocalScreenshot)
              {
              }
    -@@ -3399,9 +3424,10 @@ status_t SurfaceFlinger::captureScreen(const sp<IBinder>& display,
    +@@ -3398,9 +3423,10 @@ status_t SurfaceFlinger::captureScreen(const sp<IBinder>& display,
              virtual bool handler() {
                  Mutex::Autolock _l(flinger->mStateLock);
                  sp<const DisplayDevice> hw(flinger->getDisplayDevice(display));
    @@ -1613,7 +1585,7 @@ index b0f418c..94c95a6 100644
                  static_cast<GraphicProducerWrapper*>(IInterface::asBinder(producer).get())->exit(result);
                  return true;
              }
    -@@ -3417,7 +3443,7 @@ status_t SurfaceFlinger::captureScreen(const sp<IBinder>& display,
    +@@ -3416,7 +3442,7 @@ status_t SurfaceFlinger::captureScreen(const sp<IBinder>& display,
          sp<MessageBase> msg = new MessageCaptureScreen(this,
                  display, IGraphicBufferProducer::asInterface( wrapper ),
                  sourceCrop, reqWidth, reqHeight, minLayerZ, maxLayerZ,
    @@ -1622,7 +1594,7 @@ index b0f418c..94c95a6 100644
      
          status_t res = postMessageAsync(msg);
          if (res == NO_ERROR) {
    -@@ -3502,7 +3528,7 @@ status_t SurfaceFlinger::captureScreenImplLocked(
    +@@ -3501,7 +3527,7 @@ status_t SurfaceFlinger::captureScreenImplLocked(
              Rect sourceCrop, uint32_t reqWidth, uint32_t reqHeight,
              uint32_t minLayerZ, uint32_t maxLayerZ,
              bool useIdentityTransform, Transform::orientation_flags rotation,
    @@ -1631,7 +1603,7 @@ index b0f418c..94c95a6 100644
      {
          ATRACE_CALL();
      
    -@@ -3572,7 +3598,7 @@ status_t SurfaceFlinger::captureScreenImplLocked(
    +@@ -3571,7 +3597,7 @@ status_t SurfaceFlinger::captureScreenImplLocked(
                      if (image != EGL_NO_IMAGE_KHR) {
                          // this binds the given EGLImage as a framebuffer for the
                          // duration of this scope.
    @@ -1640,7 +1612,7 @@ index b0f418c..94c95a6 100644
                          if (imageBond.getStatus() == NO_ERROR) {
                              // this will in fact render into our dequeued buffer
                              // via an FBO, which means we didn't have to create
    -@@ -3619,6 +3645,16 @@ status_t SurfaceFlinger::captureScreenImplLocked(
    +@@ -3618,6 +3644,16 @@ status_t SurfaceFlinger::captureScreenImplLocked(
                                      ALOGW("captureScreen: error creating EGL fence: %#x", eglGetError());
                                  }
                              }
    diff --git a/frameworks_op_net_wifi.patch b/frameworks_op_net_wifi.patch
    new file mode 100644
    index 0000000..ee4bdc8
    --- /dev/null
    +++ b/frameworks_op_net_wifi.patch
    @@ -0,0 +1,48 @@
    +diff --git a/service/java/com/android/server/wifi/WifiStateMachine.java b/service/java/com/android/server/wifi/WifiStateMachine.java
    +index 89aabcf..7802b3d 100644
    +--- a/service/java/com/android/server/wifi/WifiStateMachine.java
    ++++ b/service/java/com/android/server/wifi/WifiStateMachine.java
    +@@ -2329,7 +2329,7 @@ public class WifiStateMachine extends StateMachine implements WifiNative.WifiRss
    + 
    +     @Override
    +     public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
    +-        if (args.length > 1 && WifiMetrics.PROTO_DUMP_ARG.equals(args[0])
    ++        if (args != null && args.length > 1 && WifiMetrics.PROTO_DUMP_ARG.equals(args[0])
    +                 && WifiMetrics.CLEAN_DUMP_ARG.equals(args[1])) {
    +             // Dump only wifi metrics serialized proto bytes (base64)
    +             updateWifiMetrics();
    +@@ -4340,6 +4340,12 @@ public class WifiStateMachine extends StateMachine implements WifiNative.WifiRss
    +             logStateAndMessage(message, this);
    +             switch (message.what) {
    +                 case CMD_START_SUPPLICANT:
    ++                   /* Stop a running supplicant after a runtime restart
    ++                    * Avoids issues with drivers that do not handle interface down
    ++                    * on a running supplicant properly.
    ++                    */
    ++                    mWifiMonitor.killSupplicant(mP2pSupported);
    ++
    +                     if (mWifiNative.loadDriver()) {
    +                         try {
    +                             mNwService.wifiFirmwareReload(mInterfaceName, "STA");
    +@@ -4372,12 +4378,6 @@ public class WifiStateMachine extends StateMachine implements WifiNative.WifiRss
    +                             loge("Unable to change interface settings: " + ie);
    +                         }
    + 
    +-                       /* Stop a running supplicant after a runtime restart
    +-                        * Avoids issues with drivers that do not handle interface down
    +-                        * on a running supplicant properly.
    +-                        */
    +-                        mWifiMonitor.killSupplicant(mP2pSupported);
    +-
    +                         if (mWifiNative.startHal() == false) {
    +                             /* starting HAL is optional */
    +                             loge("Failed to start HAL");
    +@@ -5527,7 +5527,7 @@ public class WifiStateMachine extends StateMachine implements WifiNative.WifiRss
    +                     // If we have COMPLETED a connection to a BSSID, start doing
    +                     // DNAv4/DNAv6 -style probing for on-link neighbors of
    +                     // interest (e.g. routers); harmless if none are configured.
    +-                    if (state == SupplicantState.COMPLETED) {
    ++                    if (isRoaming() && state == SupplicantState.COMPLETED) {
    +                         mIpManager.confirmConfiguration();
    +                     }
    +                     break;
    diff --git a/frameworks_support.patch b/frameworks_support.patch
    new file mode 100644
    index 0000000..46e0f3e
    --- /dev/null
    +++ b/frameworks_support.patch
    @@ -0,0 +1,369 @@
    +diff --git a/compat/java/android/support/v4/view/ViewCompat.java b/compat/java/android/support/v4/view/ViewCompat.java
    +index 9637e65..cc3cc26 100644
    +--- a/compat/java/android/support/v4/view/ViewCompat.java
    ++++ b/compat/java/android/support/v4/view/ViewCompat.java
    +@@ -541,11 +541,11 @@ public class ViewCompat {
    +         }
    +         @Override
    +         public void postInvalidateOnAnimation(View view) {
    +-            view.invalidate();
    ++            view.postInvalidate();
    +         }
    +         @Override
    +         public void postInvalidateOnAnimation(View view, int left, int top, int right, int bottom) {
    +-            view.invalidate(left, top, right, bottom);
    ++            view.postInvalidate(left, top, right, bottom);
    +         }
    +         @Override
    +         public void postOnAnimation(View view, Runnable action) {
    +diff --git a/design/src/android/support/design/widget/BottomSheetBehavior.java b/design/src/android/support/design/widget/BottomSheetBehavior.java
    +index c3362a8..b913de1 100644
    +--- a/design/src/android/support/design/widget/BottomSheetBehavior.java
    ++++ b/design/src/android/support/design/widget/BottomSheetBehavior.java
    +@@ -385,7 +385,8 @@ public class BottomSheetBehavior<V extends View> extends CoordinatorLayout.Behav
    +             setStateInternal(STATE_EXPANDED);
    +             return;
    +         }
    +-        if (target != mNestedScrollingChildRef.get() || !mNestedScrolled) {
    ++        if (mNestedScrollingChildRef == null || target != mNestedScrollingChildRef.get()
    ++                || !mNestedScrolled) {
    +             return;
    +         }
    +         int top;
    +diff --git a/fragment/java/android/support/v4/app/FragmentHostCallback.java b/fragment/java/android/support/v4/app/FragmentHostCallback.java
    +index 75fde03..5c256d3 100644
    +--- a/fragment/java/android/support/v4/app/FragmentHostCallback.java
    ++++ b/fragment/java/android/support/v4/app/FragmentHostCallback.java
    +@@ -304,13 +304,9 @@ public abstract class FragmentHostCallback<E> extends FragmentContainer {
    +             mAllLoaderManagers = new SimpleArrayMap<String, LoaderManager>();
    +         }
    +         LoaderManagerImpl lm = (LoaderManagerImpl) mAllLoaderManagers.get(who);
    +-        if (lm == null) {
    +-            if (create) {
    +-                lm = new LoaderManagerImpl(who, this, started);
    +-                mAllLoaderManagers.put(who, lm);
    +-            }
    +-        } else {
    +-            lm.updateHostController(this);
    ++        if (lm == null && create) {
    ++            lm = new LoaderManagerImpl(who, this, started);
    ++            mAllLoaderManagers.put(who, lm);
    +         }
    +         return lm;
    +     }
    +@@ -350,6 +346,11 @@ public abstract class FragmentHostCallback<E> extends FragmentContainer {
    +     }
    + 
    +     void restoreLoaderNonConfig(SimpleArrayMap<String, LoaderManager> loaderManagers) {
    ++        if (loaderManagers != null) {
    ++            for (int i = 0, N = loaderManagers.size(); i < N; i++) {
    ++                ((LoaderManagerImpl) loaderManagers.valueAt(i)).updateHostController(this);
    ++            }
    ++        }
    +         mAllLoaderManagers = loaderManagers;
    +     }
    + 
    +diff --git a/fragment/java/android/support/v4/app/FragmentManager.java b/fragment/java/android/support/v4/app/FragmentManager.java
    +index 3baf4f9..5996c9d 100644
    +--- a/fragment/java/android/support/v4/app/FragmentManager.java
    ++++ b/fragment/java/android/support/v4/app/FragmentManager.java
    +@@ -2146,26 +2146,36 @@ final class FragmentManagerImpl extends FragmentManager implements LayoutInflate
    + 
    +     public void dispatchCreate() {
    +         mStateSaved = false;
    ++        mExecutingActions = true;
    +         moveToState(Fragment.CREATED, false);
    ++        mExecutingActions = false;
    +     }
    + 
    +     public void dispatchActivityCreated() {
    +         mStateSaved = false;
    ++        mExecutingActions = true;
    +         moveToState(Fragment.ACTIVITY_CREATED, false);
    ++        mExecutingActions = false;
    +     }
    + 
    +     public void dispatchStart() {
    +         mStateSaved = false;
    ++        mExecutingActions = true;
    +         moveToState(Fragment.STARTED, false);
    ++        mExecutingActions = false;
    +     }
    + 
    +     public void dispatchResume() {
    +         mStateSaved = false;
    ++        mExecutingActions = true;
    +         moveToState(Fragment.RESUMED, false);
    ++        mExecutingActions = false;
    +     }
    + 
    +     public void dispatchPause() {
    ++        mExecutingActions = true;
    +         moveToState(Fragment.STARTED, false);
    ++        mExecutingActions = false;
    +     }
    + 
    +     public void dispatchStop() {
    +@@ -2174,21 +2184,29 @@ final class FragmentManagerImpl extends FragmentManager implements LayoutInflate
    +         // them.
    +         mStateSaved = true;
    + 
    ++        mExecutingActions = true;
    +         moveToState(Fragment.STOPPED, false);
    ++        mExecutingActions = false;
    +     }
    + 
    +     public void dispatchReallyStop() {
    ++        mExecutingActions = true;
    +         moveToState(Fragment.ACTIVITY_CREATED, false);
    ++        mExecutingActions = false;
    +     }
    + 
    +     public void dispatchDestroyView() {
    ++        mExecutingActions = true;
    +         moveToState(Fragment.CREATED, false);
    ++        mExecutingActions = false;
    +     }
    + 
    +     public void dispatchDestroy() {
    +         mDestroyed = true;
    +         execPendingActions();
    ++        mExecutingActions = true;
    +         moveToState(Fragment.INITIALIZING, false);
    ++        mExecutingActions = false;
    +         mHost = null;
    +         mContainer = null;
    +         mParent = null;
    +diff --git a/fragment/tests/java/android/support/v4/app/ReentrantFragment.java b/fragment/tests/java/android/support/v4/app/ReentrantFragment.java
    +new file mode 100644
    +index 0000000..472245d
    +--- /dev/null
    ++++ b/fragment/tests/java/android/support/v4/app/ReentrantFragment.java
    +@@ -0,0 +1,69 @@
    ++/*
    ++ * Copyright (C) 2017 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 android.support.v4.app;
    ++
    ++import android.os.Bundle;
    ++
    ++public class ReentrantFragment extends StrictFragment {
    ++    private static final String FROM_STATE = "fromState";
    ++    private static final String TO_STATE = "toState";
    ++    int mFromState = 0;
    ++    int mToState = 0;
    ++    boolean mIsRestored;
    ++
    ++    public static ReentrantFragment create(int fromState, int toState) {
    ++        ReentrantFragment fragment = new ReentrantFragment();
    ++        fragment.mFromState = fromState;
    ++        fragment.mToState = toState;
    ++        fragment.mIsRestored = false;
    ++        return fragment;
    ++    }
    ++
    ++    @Override
    ++    public void onStateChanged(int fromState) {
    ++        super.onStateChanged(fromState);
    ++        // We execute the transaction when shutting down or after restoring
    ++        if (fromState == mFromState && mState == mToState
    ++                && (mToState < mFromState || mIsRestored)) {
    ++            executeTransaction();
    ++        }
    ++    }
    ++
    ++    private void executeTransaction() {
    ++        getFragmentManager().beginTransaction()
    ++                .add(new StrictFragment(), "should throw")
    ++                .commitNow();
    ++    }
    ++
    ++    @Override
    ++    public void onSaveInstanceState(Bundle outState) {
    ++        super.onSaveInstanceState(outState);
    ++        outState.putInt(FROM_STATE, mFromState);
    ++        outState.putInt(TO_STATE, mToState);
    ++    }
    ++
    ++    @Override
    ++    public void onCreate(Bundle savedInstanceState) {
    ++        if (savedInstanceState != null) {
    ++            mFromState = savedInstanceState.getInt(FROM_STATE);
    ++            mToState = savedInstanceState.getInt(TO_STATE);
    ++            mIsRestored = true;
    ++        }
    ++        super.onCreate(savedInstanceState);
    ++    }
    ++}
    ++
    +diff --git a/fragment/tests/java/android/support/v4/app/StrictFragment.java b/fragment/tests/java/android/support/v4/app/StrictFragment.java
    +index dfda814..d91c161 100644
    +--- a/fragment/tests/java/android/support/v4/app/StrictFragment.java
    ++++ b/fragment/tests/java/android/support/v4/app/StrictFragment.java
    +@@ -51,6 +51,10 @@ public class StrictFragment extends Fragment {
    +         return "(unknown " + state + ")";
    +     }
    + 
    ++    public void onStateChanged(int fromState) {
    ++        checkGetActivity();
    ++    }
    ++
    +     public void checkGetActivity() {
    +         if (getActivity() == null) {
    +             throw new IllegalStateException("getActivity() returned null at unexpected time");
    +@@ -92,7 +96,7 @@ public class StrictFragment extends Fragment {
    +         mCalledOnAttach = true;
    +         checkState("onAttach", DETACHED);
    +         mState = ATTACHED;
    +-        checkGetActivity();
    ++        onStateChanged(DETACHED);
    +     }
    + 
    +     @Override
    +@@ -104,7 +108,7 @@ public class StrictFragment extends Fragment {
    +         mCalledOnCreate = true;
    +         checkState("onCreate", ATTACHED);
    +         mState = CREATED;
    +-        checkGetActivity();
    ++        onStateChanged(ATTACHED);
    +     }
    + 
    +     @Override
    +@@ -112,8 +116,9 @@ public class StrictFragment extends Fragment {
    +         super.onActivityCreated(savedInstanceState);
    +         mCalledOnActivityCreated = true;
    +         checkState("onActivityCreated", ATTACHED, CREATED);
    ++        int fromState = mState;
    +         mState = ACTIVITY_CREATED;
    +-        checkGetActivity();
    ++        onStateChanged(fromState);
    +     }
    + 
    +     @Override
    +@@ -122,7 +127,7 @@ public class StrictFragment extends Fragment {
    +         mCalledOnStart = true;
    +         checkState("onStart", ACTIVITY_CREATED);
    +         mState = STARTED;
    +-        checkGetActivity();
    ++        onStateChanged(ACTIVITY_CREATED);
    +     }
    + 
    +     @Override
    +@@ -131,7 +136,7 @@ public class StrictFragment extends Fragment {
    +         mCalledOnResume = true;
    +         checkState("onResume", STARTED);
    +         mState = RESUMED;
    +-        checkGetActivity();
    ++        onStateChanged(STARTED);
    +     }
    + 
    +     @Override
    +@@ -148,7 +153,7 @@ public class StrictFragment extends Fragment {
    +         mCalledOnPause = true;
    +         checkState("onPause", RESUMED);
    +         mState = STARTED;
    +-        checkGetActivity();
    ++        onStateChanged(RESUMED);
    +     }
    + 
    +     @Override
    +@@ -157,7 +162,7 @@ public class StrictFragment extends Fragment {
    +         mCalledOnStop = true;
    +         checkState("onStop", STARTED);
    +         mState = CREATED;
    +-        checkGetActivity();
    ++        onStateChanged(STARTED);
    +     }
    + 
    +     @Override
    +@@ -166,7 +171,7 @@ public class StrictFragment extends Fragment {
    +         mCalledOnDestroy = true;
    +         checkState("onDestroy", CREATED);
    +         mState = ATTACHED;
    +-        checkGetActivity();
    ++        onStateChanged(CREATED);
    +     }
    + 
    +     @Override
    +@@ -174,7 +179,8 @@ public class StrictFragment extends Fragment {
    +         super.onDetach();
    +         mCalledOnDetach = true;
    +         checkState("onDestroy", CREATED, ATTACHED);
    ++        int fromState = mState;
    +         mState = DETACHED;
    +-        checkGetActivity();
    ++        onStateChanged(fromState);
    +     }
    + }
    +diff --git a/v7/recyclerview/src/android/support/v7/widget/RecyclerView.java b/v7/recyclerview/src/android/support/v7/widget/RecyclerView.java
    +index b640f79..8c57dc8 100644
    +--- a/v7/recyclerview/src/android/support/v7/widget/RecyclerView.java
    ++++ b/v7/recyclerview/src/android/support/v7/widget/RecyclerView.java
    +@@ -11160,6 +11160,11 @@ public class RecyclerView extends ViewGroup implements ScrollingView, NestedScro
    +                 }
    +             }
    +         }
    ++
    ++        @Override
    ++        public void onAnimationStarted(ViewHolder item) {
    ++            //do nothing
    ++        }
    +     }
    + 
    +     /**
    +@@ -11329,7 +11334,7 @@ public class RecyclerView extends ViewGroup implements ScrollingView, NestedScro
    +          *
    +          * @param listener The listener that must be called.
    +          */
    +-        void setListener(ItemAnimatorListener listener) {
    ++        protected void setListener(ItemAnimatorListener listener) {
    +             mListener = listener;
    +         }
    + 
    +@@ -11695,6 +11700,9 @@ public class RecyclerView extends ViewGroup implements ScrollingView, NestedScro
    +          */
    +         public final void dispatchAnimationStarted(ViewHolder viewHolder) {
    +             onAnimationStarted(viewHolder);
    ++            if (mListener != null) {
    ++                mListener.onAnimationStarted(viewHolder);
    ++            }
    +         }
    + 
    +         /**
    +@@ -11724,7 +11732,7 @@ public class RecyclerView extends ViewGroup implements ScrollingView, NestedScro
    +          * equivalent to calling {@link #isRunning()}.
    +          * @return true if there are any item animations currently running, false otherwise.
    +          */
    +-        public final boolean isRunning(ItemAnimatorFinishedListener listener) {
    ++        public boolean isRunning(ItemAnimatorFinishedListener listener) {
    +             boolean running = isRunning();
    +             if (listener != null) {
    +                 if (!running) {
    +@@ -11818,11 +11826,11 @@ public class RecyclerView extends ViewGroup implements ScrollingView, NestedScro
    + 
    +         /**
    +          * The interface to be implemented by listeners to animation events from this
    +-         * ItemAnimator. This is used internally and is not intended for developers to
    +-         * create directly.
    ++         * ItemAnimator.
    +          */
    +-        interface ItemAnimatorListener {
    ++        protected interface ItemAnimatorListener {
    +             void onAnimationFinished(ViewHolder item);
    ++            void onAnimationStarted(ViewHolder item);
    +         }
    + 
    +         /**
    diff --git a/system_core.patch b/system_core.patch
    index 52b8f46..c8a09ed 100644
    --- a/system_core.patch
    +++ b/system_core.patch
    @@ -113,7 +113,7 @@ index 67541b8..ff343e9 100644
      init_cflags += \
          $(init_options) \
     diff --git a/init/init.cpp b/init/init.cpp
    -index 84da2b9..dc3be38 100644
    +index cd2d2e6..81628a1 100644
     --- a/init/init.cpp
     +++ b/init/init.cpp
     @@ -296,55 +296,6 @@ static bool __attribute__((unused)) set_mmap_rnd_bits_min(int start, int min, bo
    @@ -172,7 +172,7 @@ index 84da2b9..dc3be38 100644
      static int keychord_init_action(const std::vector<std::string>& args)
      {
          keychord_init();
    -@@ -695,7 +646,7 @@ int main(int argc, char** argv) {
    +@@ -701,7 +652,7 @@ int main(int argc, char** argv) {
          am.QueueBuiltinAction(wait_for_coldboot_done_action, "wait_for_coldboot_done");
          // ... so that we can start queuing up actions that require stuff from /dev.
          am.QueueBuiltinAction(mix_hwrng_into_linux_rng_action, "mix_hwrng_into_linux_rng");
    @@ -182,10 +182,10 @@ index 84da2b9..dc3be38 100644
          am.QueueBuiltinAction(console_init_action, "console_init");
      
     diff --git a/rootdir/init.rc b/rootdir/init.rc
    -index a22d5c1..90d4ae0 100644
    +index df60f65..f4de4a2 100644
     --- a/rootdir/init.rc
     +++ b/rootdir/init.rc
    -@@ -664,6 +664,6 @@ on property:ro.debuggable=1
    +@@ -665,6 +665,6 @@ on property:ro.debuggable=1
          chmod 0773 /data/misc/trace
          start console
      
    diff --git a/system_sepolicy.patch b/system_sepolicy.patch
    index 1c95f0f..1d9a08e 100644
    --- a/system_sepolicy.patch
    +++ b/system_sepolicy.patch
    @@ -99,7 +99,7 @@ index 45569de..21c9df2 100644
      neverallow {
        domain
     diff --git a/file.te b/file.te
    -index 84af4a7..55910d2 100644
    +index 87cec82..bdc7cbe 100644
     --- a/file.te
     +++ b/file.te
     @@ -46,6 +46,8 @@ type devpts, fs_type, mlstrustedobject;
    
    From 761d0e319691b938480c2dc403df585a1ecc6365 Mon Sep 17 00:00:00 2001
    From: AndDiSa <anddisa@googlemail.com>
    Date: Fri, 7 Apr 2017 12:03:14 +0200
    Subject: [PATCH 071/159] update patches
    
    Change-Id: I0e9ac531b525f1e2202afc01634f68318ef31277
    ---
     build.patch | 218 ----------------------------------------------------
     1 file changed, 218 deletions(-)
    
    diff --git a/build.patch b/build.patch
    index b8262af..5246b91 100644
    --- a/build.patch
    +++ b/build.patch
    @@ -1,34 +1,3 @@
    -diff --git a/core/build_id.mk.orig b/core/build_id.mk.orig
    -new file mode 100644
    -index 0000000..e508d48
    ---- /dev/null
    -+++ b/core/build_id.mk.orig
    -@@ -0,0 +1,25 @@
    -+#
    -+# 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.
    -+#
    -+# BUILD_ID is usually used to specify the branch name
    -+# (like "MAIN") or a branch name and a release candidate
    -+# (like "CRB01").  It must be a single word, and is
    -+# capitalized by convention.
    -+
    -+<<<<<<< HEAD
    -+export BUILD_ID=NOF27B
    -+=======
    -+export BUILD_ID=N2G47J
    -+>>>>>>> android-7.1.2_r5
     diff --git a/core/combo/arch/arm/armv7-a-neon.mk b/core/combo/arch/arm/armv7-a-neon.mk
     index 5d5b050..b0e1e25 100644
     --- a/core/combo/arch/arm/armv7-a-neon.mk
    @@ -315,193 +284,6 @@ index 0000000..ee76dc2
     +
     +ALL_PREBUILT += $(INSTALLED_KERNEL_TARGET)
     +endif
    -diff --git a/core/version_defaults.mk.orig b/core/version_defaults.mk.orig
    -new file mode 100644
    -index 0000000..9720bb1
    ---- /dev/null
    -+++ b/core/version_defaults.mk.orig
    -@@ -0,0 +1,181 @@
    -+#
    -+# 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.
    -+#
    -+
    -+#
    -+# Handle various build version information.
    -+#
    -+# Guarantees that the following are defined:
    -+#     PLATFORM_VERSION
    -+#     PLATFORM_SDK_VERSION
    -+#     PLATFORM_VERSION_CODENAME
    -+#     DEFAULT_APP_TARGET_SDK
    -+#     BUILD_ID
    -+#     BUILD_NUMBER
    -+#     BUILD_DATETIME
    -+#     PLATFORM_SECURITY_PATCH
    -+#
    -+
    -+# Look for an optional file containing overrides of the defaults,
    -+# but don't cry if we don't find it.  We could just use -include, but
    -+# the build.prop target also wants INTERNAL_BUILD_ID_MAKEFILE to be set
    -+# if the file exists.
    -+#
    -+INTERNAL_BUILD_ID_MAKEFILE := $(wildcard $(BUILD_SYSTEM)/build_id.mk)
    -+ifneq "" "$(INTERNAL_BUILD_ID_MAKEFILE)"
    -+  include $(INTERNAL_BUILD_ID_MAKEFILE)
    -+endif
    -+
    -+ifeq "" "$(PLATFORM_VERSION)"
    -+  # This is the canonical definition of the platform version,
    -+  # which is the version that we reveal to the end user.
    -+  # Update this value when the platform version changes (rather
    -+  # than overriding it somewhere else).  Can be an arbitrary string.
    -+
    -+  # When you add a new PLATFORM_VERSION which will result in a new
    -+  # PLATFORM_SDK_VERSION please ensure you add a corresponding isAtLeast*
    -+  # method in the following java file:
    -+  # frameworks/support/compat/gingerbread/android/support/v4/os/BuildCompat.java
    -+
    -+  # When you change PLATFORM_VERSION for a given PLATFORM_SDK_VERSION
    -+  # please add that PLATFORM_VERSION to the following text file:
    -+  # cts/tests/tests/os/assets/platform_versions.txt
    -+  PLATFORM_VERSION := 7.1.2
    -+endif
    -+
    -+ifeq "" "$(PLATFORM_SDK_VERSION)"
    -+  # This is the canonical definition of the SDK version, which defines
    -+  # the set of APIs and functionality available in the platform.  It
    -+  # is a single integer that increases monotonically as updates to
    -+  # the SDK are released.  It should only be incremented when the APIs for
    -+  # the new release are frozen (so that developers don't write apps against
    -+  # intermediate builds).  During development, this number remains at the
    -+  # SDK version the branch is based on and PLATFORM_VERSION_CODENAME holds
    -+  # the code-name of the new development work.
    -+
    -+  # When you change PLATFORM_SDK_VERSION please ensure you also update the
    -+  # corresponding methods for isAtLeast* in the following java file:
    -+  # frameworks/support/compat/gingerbread/android/support/v4/os/BuildCompat.java
    -+
    -+  # When you increment the PLATFORM_SDK_VERSION please ensure you also
    -+  # clear out the following text file of all older PLATFORM_VERSION's:
    -+  # cts/tests/tests/os/assets/platform_versions.txt
    -+  PLATFORM_SDK_VERSION := 25
    -+endif
    -+
    -+ifeq "" "$(PLATFORM_JACK_MIN_SDK_VERSION)"
    -+  # This is definition of the min SDK version given to Jack for the current
    -+  # platform. For released version it should be the same as
    -+  # PLATFORM_SDK_VERSION. During development, this number may be incremented
    -+  # before PLATFORM_SDK_VERSION if the plateform starts to add new java
    -+  # language supports.
    -+  PLATFORM_JACK_MIN_SDK_VERSION := 25
    -+endif
    -+
    -+ifeq "" "$(PLATFORM_VERSION_CODENAME)"
    -+  # This is the current development code-name, if the build is not a final
    -+  # release build.  If this is a final release build, it is simply "REL".
    -+  PLATFORM_VERSION_CODENAME := REL
    -+
    -+  # This is all of the development codenames that are active.  Should be either
    -+  # the same as PLATFORM_VERSION_CODENAME or a comma-separated list of additional
    -+  # codenames after PLATFORM_VERSION_CODENAME.
    -+  PLATFORM_VERSION_ALL_CODENAMES := $(PLATFORM_VERSION_CODENAME)
    -+endif
    -+
    -+ifeq "REL" "$(PLATFORM_VERSION_CODENAME)"
    -+  PLATFORM_PREVIEW_SDK_VERSION := 0
    -+else
    -+  ifeq "" "$(PLATFORM_PREVIEW_SDK_VERSION)"
    -+    # This is the definition of a preview SDK version over and above the current
    -+    # platform SDK version. Unlike the platform SDK version, a higher value
    -+    # for preview SDK version does NOT mean that all prior preview APIs are
    -+    # included. Packages reading this value to determine compatibility with
    -+    # known APIs should check that this value is precisely equal to the preview
    -+    # SDK version the package was built for, otherwise it should fall back to
    -+    # assuming the device can only support APIs as of the previous official
    -+    # public release.
    -+    # This value will always be 0 for release builds.
    -+    PLATFORM_PREVIEW_SDK_VERSION := 0
    -+  endif
    -+endif
    -+
    -+ifeq "" "$(DEFAULT_APP_TARGET_SDK)"
    -+  # This is the default minSdkVersion and targetSdkVersion to use for
    -+  # all .apks created by the build system.  It can be overridden by explicitly
    -+  # setting these in the .apk's AndroidManifest.xml.  It is either the code
    -+  # name of the development build or, if this is a release build, the official
    -+  # SDK version of this release.
    -+  ifeq "REL" "$(PLATFORM_VERSION_CODENAME)"
    -+    DEFAULT_APP_TARGET_SDK := $(PLATFORM_SDK_VERSION)
    -+  else
    -+    DEFAULT_APP_TARGET_SDK := $(PLATFORM_VERSION_CODENAME)
    -+  endif
    -+endif
    -+
    -+ifeq "" "$(PLATFORM_SECURITY_PATCH)"
    -+    #  Used to indicate the security patch that has been applied to the device.
    -+    #  It must signify that the build includes all security patches issued up through the designated Android Public Security Bulletin.
    -+    #  It must be of the form "YYYY-MM-DD" on production devices.
    -+    #  It must match one of the Android Security Patch Level strings of the Public Security Bulletins.
    -+    #  If there is no $PLATFORM_SECURITY_PATCH set, keep it empty.
    -+<<<<<<< HEAD
    -+      PLATFORM_SECURITY_PATCH := 2017-03-05
    -+=======
    -+      PLATFORM_SECURITY_PATCH := 2017-04-05
    -+>>>>>>> android-7.1.2_r5
    -+endif
    -+
    -+ifeq "" "$(PLATFORM_BASE_OS)"
    -+  # Used to indicate the base os applied to the device.
    -+  # Can be an arbitrary string, but must be a single word.
    -+  #
    -+  # If there is no $PLATFORM_BASE_OS set, keep it empty.
    -+  PLATFORM_BASE_OS :=
    -+endif
    -+
    -+ifeq "" "$(BUILD_ID)"
    -+  # Used to signify special builds.  E.g., branches and/or releases,
    -+  # like "M5-RC7".  Can be an arbitrary string, but must be a single
    -+  # word and a valid file name.
    -+  #
    -+  # If there is no BUILD_ID set, make it obvious.
    -+  BUILD_ID := UNKNOWN
    -+endif
    -+
    -+ifeq "" "$(BUILD_DATETIME)"
    -+  # Used to reproduce builds by setting the same time. Must be the number
    -+  # of seconds since the Epoch.
    -+  BUILD_DATETIME := $(shell date +%s)
    -+endif
    -+
    -+ifneq (,$(findstring Darwin,$(shell uname -sm)))
    -+DATE := date -r $(BUILD_DATETIME)
    -+else
    -+DATE := date -d @$(BUILD_DATETIME)
    -+endif
    -+
    -+ifeq "" "$(BUILD_NUMBER)"
    -+  # BUILD_NUMBER should be set to the source control value that
    -+  # represents the current state of the source code.  E.g., a
    -+  # perforce changelist number or a git hash.  Can be an arbitrary string
    -+  # (to allow for source control that uses something other than numbers),
    -+  # but must be a single word and a valid file name.
    -+  #
    -+  # If no BUILD_NUMBER is set, create a useful "I am an engineering build
    -+  # from this date/time" value.  Make it start with a non-digit so that
    -+  # anyone trying to parse it as an integer will probably get "0".
    -+  BUILD_NUMBER := eng.$(shell echo $${USER:0:6}).$(shell $(DATE) +%Y%m%d.%H%M%S)
    -+endif
     diff --git a/core/version_defaults_BACKUP_20377.mk b/core/version_defaults_BACKUP_20377.mk
     new file mode 100644
     index 0000000..eb97b11
    
    From 502e183e3b4d647585b2bc03791ffada562d4410 Mon Sep 17 00:00:00 2001
    From: AndDiSa <anddisa@googlemail.com>
    Date: Sun, 30 Apr 2017 18:42:27 +0200
    Subject: [PATCH 072/159] switch to nAOSP-7.1.2 from millosr for tilapia
    
    Change-Id: I0698492fcbda24df0e7d479e74f10f201cee6d41
    ---
     default.xml | 2 +-
     1 file changed, 1 insertion(+), 1 deletion(-)
    
    diff --git a/default.xml b/default.xml
    index e8d9650..f901f83 100644
    --- a/default.xml
    +++ b/default.xml
    @@ -31,7 +31,7 @@
       <project path="developers/samples/android" name="platform/developers/samples/android" />
       <project path="development" name="platform/development" groups="pdk-cw-fs,pdk-fs" />
       <project path="device/asus/grouper" name="android_device_asus_grouper" remote="ads" revision="ads-7.1.0" groups="device,grouper" />
    -  <project path="device/asus/tilapia" name="device_asus_tilapia" remote="millosr" revision="ads-7.0.1" groups="device,grouper" />
    +  <project path="device/asus/tilapia" name="device_asus_tilapia" remote="millosr" revision="nAOSP-7.1.0" groups="device,grouper" />
       <project path="device/common" name="device/common" groups="pdk-cw-fs,pdk-fs" />
       <project path="device/generic/arm64" name="device/generic/arm64" groups="pdk" />
       <project path="device/generic/armv7-a-neon" name="device/generic/armv7-a-neon" groups="pdk" />
    
    From 729f6e53f758d9d355d9359438d623394ecc0593 Mon Sep 17 00:00:00 2001
    From: AndDiSa <anddisa@googlemail.com>
    Date: Tue, 2 May 2017 18:33:24 +0200
    Subject: [PATCH 073/159] update to android-7.1.2_r10
    
    Change-Id: Ifcb1fb02125514f6a2765faa2836a7e142d6b8fc
    ---
     default.xml | 2 +-
     1 file changed, 1 insertion(+), 1 deletion(-)
    
    diff --git a/default.xml b/default.xml
    index f901f83..4935bf4 100644
    --- a/default.xml
    +++ b/default.xml
    @@ -9,7 +9,7 @@
                fetch="https://github.com/millosr/" />
       <remote  name="unlegacy"
                fetch="https://github.com/Unlegacy-Android/" />
    -  <default revision="refs/tags/android-7.1.2_r5"
    +  <default revision="refs/tags/android-7.1.2_r10"
                remote="aosp"
                sync-j="4" />
     
    
    From 06ca75948432491a5e2888bf82833a503e6c6725 Mon Sep 17 00:00:00 2001
    From: AndDiSa <anddisa@googlemail.com>
    Date: Tue, 2 May 2017 19:03:06 +0200
    Subject: [PATCH 074/159] update to nAOSP-7.1.2 for tilapia
    
    Change-Id: Iebe18e1c75344c4c1154bf0dfc4dfa80bb240de6
    ---
     default.xml | 2 +-
     1 file changed, 1 insertion(+), 1 deletion(-)
    
    diff --git a/default.xml b/default.xml
    index 4935bf4..c484bb4 100644
    --- a/default.xml
    +++ b/default.xml
    @@ -31,7 +31,7 @@
       <project path="developers/samples/android" name="platform/developers/samples/android" />
       <project path="development" name="platform/development" groups="pdk-cw-fs,pdk-fs" />
       <project path="device/asus/grouper" name="android_device_asus_grouper" remote="ads" revision="ads-7.1.0" groups="device,grouper" />
    -  <project path="device/asus/tilapia" name="device_asus_tilapia" remote="millosr" revision="nAOSP-7.1.0" groups="device,grouper" />
    +  <project path="device/asus/tilapia" name="device_asus_tilapia" remote="millosr" revision="nAOSP-7.1.2" groups="device,grouper" />
       <project path="device/common" name="device/common" groups="pdk-cw-fs,pdk-fs" />
       <project path="device/generic/arm64" name="device/generic/arm64" groups="pdk" />
       <project path="device/generic/armv7-a-neon" name="device/generic/armv7-a-neon" groups="pdk" />
    
    From 1c9f95c1412e86a9ea1f7ae428193413c2c2d704 Mon Sep 17 00:00:00 2001
    From: AndDiSa <anddisa@googlemail.com>
    Date: Fri, 5 May 2017 20:13:11 +0200
    Subject: [PATCH 075/159] update patches
    
    Change-Id: Icc2277cf13c9f49699977129a4b207caea6261ea
    ---
     bionic.patch          | 815 ------------------------------------------
     frameworks_av.patch   | 139 +------
     frameworks_base.patch |   2 +-
     system_sepolicy.patch |   4 +-
     4 files changed, 13 insertions(+), 947 deletions(-)
    
    diff --git a/bionic.patch b/bionic.patch
    index 07f6382..625c884 100644
    --- a/bionic.patch
    +++ b/bionic.patch
    @@ -1,25 +1,3 @@
    -diff --git a/libc/Android.bp b/libc/Android.bp
    -index 950b848..4cae16c 100644
    ---- a/libc/Android.bp
    -+++ b/libc/Android.bp
    -@@ -867,14 +867,14 @@ cc_library_static {
    -             cortex_a7: {
    -                 srcs: [
    -                     "arch-arm/cortex-a7/bionic/memset.S",
    --                    "arch-arm/cortex-a7/bionic/memcpy.S",
    --                    "arch-arm/cortex-a7/bionic/__strcat_chk.S",
    --                    "arch-arm/cortex-a7/bionic/__strcpy_chk.S",
    - 
    -+                    "arch-arm/cortex-a15/bionic/memcpy.S",
    -                     "arch-arm/cortex-a15/bionic/stpcpy.S",
    -                     "arch-arm/cortex-a15/bionic/strcat.S",
    -+                    "arch-arm/cortex-a15/bionic/__strcat_chk.S",
    -                     "arch-arm/cortex-a15/bionic/strcmp.S",
    -                     "arch-arm/cortex-a15/bionic/strcpy.S",
    -+                    "arch-arm/cortex-a15/bionic/__strcpy_chk.S",
    -                     "arch-arm/cortex-a15/bionic/strlen.S",
    - 
    -                     "arch-arm/denver/bionic/memmove.S",
     diff --git a/libc/arch-arm/arm.mk b/libc/arch-arm/arm.mk
     index 76f465e..21b6152 100644
     --- a/libc/arch-arm/arm.mk
    @@ -42,727 +20,6 @@ index 76f465e..21b6152 100644
      
      #
      # Inherently architecture-specific code.
    -diff --git a/libc/arch-arm/cortex-a7/bionic/__strcat_chk.S b/libc/arch-arm/cortex-a7/bionic/__strcat_chk.S
    -deleted file mode 100644
    -index 9c44b9d..0000000
    ---- a/libc/arch-arm/cortex-a7/bionic/__strcat_chk.S
    -+++ /dev/null
    -@@ -1,214 +0,0 @@
    --/*
    -- * Copyright (C) 2013 The Android Open Source Project
    -- * All rights reserved.
    -- *
    -- * Redistribution and use in source and binary forms, with or without
    -- * modification, are permitted provided that the following conditions
    -- * are met:
    -- *  * Redistributions of source code must retain the above copyright
    -- *    notice, this list of conditions and the following disclaimer.
    -- *  * Redistributions in binary form must reproduce the above copyright
    -- *    notice, this list of conditions and the following disclaimer in
    -- *    the documentation and/or other materials provided with the
    -- *    distribution.
    -- *
    -- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
    -- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
    -- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
    -- * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
    -- * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
    -- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
    -- * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
    -- * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
    -- * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
    -- * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
    -- * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
    -- * SUCH DAMAGE.
    -- */
    --
    --#include <private/bionic_asm.h>
    --#include <private/libc_events.h>
    --
    --    .syntax unified
    --
    --    .thumb
    --    .thumb_func
    --
    --// Get the length of src string, then get the source of the dst string.
    --// Check that the two lengths together don't exceed the threshold, then
    --// do a memcpy of the data.
    --ENTRY(__strcat_chk)
    --    pld     [r0, #0]
    --    push    {r0, lr}
    --    .cfi_def_cfa_offset 8
    --    .cfi_rel_offset r0, 0
    --    .cfi_rel_offset lr, 4
    --    push    {r4, r5}
    --    .cfi_adjust_cfa_offset 8
    --    .cfi_rel_offset r4, 0
    --    .cfi_rel_offset r5, 4
    --
    --    mov     lr, r2
    --
    --    // Save the dst register to r5
    --    mov     r5, r0
    --
    --    // Zero out r4
    --    eor     r4, r4, r4
    --
    --    // r1 contains the address of the string to count.
    --.L_strlen_start:
    --    mov     r0, r1
    --    ands    r3, r1, #7
    --    beq     .L_mainloop
    --
    --    // Align to a double word (64 bits).
    --    rsb     r3, r3, #8
    --    lsls    ip, r3, #31
    --    beq     .L_align_to_32
    --
    --    ldrb    r2, [r1], #1
    --    cbz     r2, .L_update_count_and_finish
    --
    --.L_align_to_32:
    --    bcc     .L_align_to_64
    --    ands    ip, r3, #2
    --    beq     .L_align_to_64
    --
    --    ldrb    r2, [r1], #1
    --    cbz     r2, .L_update_count_and_finish
    --    ldrb    r2, [r1], #1
    --    cbz     r2, .L_update_count_and_finish
    --
    --.L_align_to_64:
    --    tst     r3, #4
    --    beq     .L_mainloop
    --    ldr     r3, [r1], #4
    --
    --    sub     ip, r3, #0x01010101
    --    bic     ip, ip, r3
    --    ands    ip, ip, #0x80808080
    --    bne     .L_zero_in_second_register
    --
    --    .p2align 2
    --.L_mainloop:
    --    ldrd    r2, r3, [r1], #8
    --
    --    pld     [r1, #64]
    --
    --    sub     ip, r2, #0x01010101
    --    bic     ip, ip, r2
    --    ands    ip, ip, #0x80808080
    --    bne     .L_zero_in_first_register
    --
    --    sub     ip, r3, #0x01010101
    --    bic     ip, ip, r3
    --    ands    ip, ip, #0x80808080
    --    bne     .L_zero_in_second_register
    --    b       .L_mainloop
    --
    --.L_update_count_and_finish:
    --    sub     r3, r1, r0
    --    sub     r3, r3, #1
    --    b       .L_finish
    --
    --.L_zero_in_first_register:
    --    sub     r3, r1, r0
    --    lsls    r2, ip, #17
    --    bne     .L_sub8_and_finish
    --    bcs     .L_sub7_and_finish
    --    lsls    ip, ip, #1
    --    bne     .L_sub6_and_finish
    --
    --    sub     r3, r3, #5
    --    b       .L_finish
    --
    --.L_sub8_and_finish:
    --    sub     r3, r3, #8
    --    b       .L_finish
    --
    --.L_sub7_and_finish:
    --    sub     r3, r3, #7
    --    b       .L_finish
    --
    --.L_sub6_and_finish:
    --    sub     r3, r3, #6
    --    b       .L_finish
    --
    --.L_zero_in_second_register:
    --    sub     r3, r1, r0
    --    lsls    r2, ip, #17
    --    bne     .L_sub4_and_finish
    --    bcs     .L_sub3_and_finish
    --    lsls    ip, ip, #1
    --    bne     .L_sub2_and_finish
    --
    --    sub     r3, r3, #1
    --    b       .L_finish
    --
    --.L_sub4_and_finish:
    --    sub     r3, r3, #4
    --    b       .L_finish
    --
    --.L_sub3_and_finish:
    --    sub     r3, r3, #3
    --    b       .L_finish
    --
    --.L_sub2_and_finish:
    --    sub     r3, r3, #2
    --
    --.L_finish:
    --    cmp     r4, #0
    --    bne     .L_strlen_done
    --
    --    // Time to get the dst string length.
    --    mov     r1, r5
    --
    --    // Save the original source address to r5.
    --    mov     r5, r0
    --
    --    // Save the current length (adding 1 for the terminator).
    --    add     r4, r3, #1
    --    b       .L_strlen_start
    --
    --    // r0 holds the pointer to the dst string.
    --    // r3 holds the dst string length.
    --    // r4 holds the src string length + 1.
    --.L_strlen_done:
    --    add     r2, r3, r4
    --    cmp     r2, lr
    --    itt     hi
    --    movhi   r0, lr
    --    bhi     .L_strcat_chk_failed
    --
    --    // Set up the registers for the memcpy code.
    --    mov     r1, r5
    --    pld     [r1, #64]
    --    mov     r2, r4
    --    add     r0, r0, r3
    --    pop     {r4, r5}
    --    .cfi_adjust_cfa_offset -8
    --    .cfi_restore r4
    --    .cfi_restore r5
    --
    --#include "memcpy_base.S"
    --
    --    // Undo the above cfi directives
    --    .cfi_adjust_cfa_offset 8
    --    .cfi_rel_offset r4, 0
    --    .cfi_rel_offset r5, 4
    --.L_strcat_chk_failed:
    --    ldr     r0, error_message
    --    ldr     r1, error_code
    --1:
    --    add     r0, pc
    --    bl      __fortify_chk_fail
    --error_code:
    --    .word   BIONIC_EVENT_STRCAT_BUFFER_OVERFLOW
    --error_message:
    --    .word   error_string-(1b+4)
    --END(__strcat_chk)
    --
    --    .data
    --error_string:
    --    .string "strcat: prevented write past end of buffer"
    -diff --git a/libc/arch-arm/cortex-a7/bionic/__strcpy_chk.S b/libc/arch-arm/cortex-a7/bionic/__strcpy_chk.S
    -deleted file mode 100644
    -index bbcb9af..0000000
    ---- a/libc/arch-arm/cortex-a7/bionic/__strcpy_chk.S
    -+++ /dev/null
    -@@ -1,176 +0,0 @@
    --/*
    -- * Copyright (C) 2013 The Android Open Source Project
    -- * All rights reserved.
    -- *
    -- * Redistribution and use in source and binary forms, with or without
    -- * modification, are permitted provided that the following conditions
    -- * are met:
    -- *  * Redistributions of source code must retain the above copyright
    -- *    notice, this list of conditions and the following disclaimer.
    -- *  * Redistributions in binary form must reproduce the above copyright
    -- *    notice, this list of conditions and the following disclaimer in
    -- *    the documentation and/or other materials provided with the
    -- *    distribution.
    -- *
    -- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
    -- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
    -- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
    -- * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
    -- * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
    -- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
    -- * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
    -- * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
    -- * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
    -- * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
    -- * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
    -- * SUCH DAMAGE.
    -- */
    --
    --#include <private/bionic_asm.h>
    --#include <private/libc_events.h>
    --
    --    .syntax unified
    --
    --    .thumb
    --    .thumb_func
    --
    --// Get the length of the source string first, then do a memcpy of the data
    --// instead of a strcpy.
    --ENTRY(__strcpy_chk)
    --    pld     [r0, #0]
    --    push    {r0, lr}
    --    .cfi_def_cfa_offset 8
    --    .cfi_rel_offset r0, 0
    --    .cfi_rel_offset lr, 4
    --
    --    mov     lr, r2
    --    mov     r0, r1
    --
    --    ands    r3, r1, #7
    --    beq     .L_mainloop
    --
    --    // Align to a double word (64 bits).
    --    rsb     r3, r3, #8
    --    lsls    ip, r3, #31
    --    beq     .L_align_to_32
    --
    --    ldrb    r2, [r0], #1
    --    cbz     r2, .L_update_count_and_finish
    --
    --.L_align_to_32:
    --    bcc     .L_align_to_64
    --    ands    ip, r3, #2
    --    beq     .L_align_to_64
    --
    --    ldrb    r2, [r0], #1
    --    cbz     r2, .L_update_count_and_finish
    --    ldrb    r2, [r0], #1
    --    cbz     r2, .L_update_count_and_finish
    --
    --.L_align_to_64:
    --    tst     r3, #4
    --    beq     .L_mainloop
    --    ldr     r3, [r0], #4
    --
    --    sub     ip, r3, #0x01010101
    --    bic     ip, ip, r3
    --    ands    ip, ip, #0x80808080
    --    bne     .L_zero_in_second_register
    --
    --    .p2align 2
    --.L_mainloop:
    --    ldrd    r2, r3, [r0], #8
    --
    --    pld     [r0, #64]
    --
    --    sub     ip, r2, #0x01010101
    --    bic     ip, ip, r2
    --    ands    ip, ip, #0x80808080
    --    bne     .L_zero_in_first_register
    --
    --    sub     ip, r3, #0x01010101
    --    bic     ip, ip, r3
    --    ands    ip, ip, #0x80808080
    --    bne     .L_zero_in_second_register
    --    b       .L_mainloop
    --
    --.L_update_count_and_finish:
    --    sub     r3, r0, r1
    --    sub     r3, r3, #1
    --    b       .L_check_size
    --
    --.L_zero_in_first_register:
    --    sub     r3, r0, r1
    --    lsls    r2, ip, #17
    --    bne     .L_sub8_and_finish
    --    bcs     .L_sub7_and_finish
    --    lsls    ip, ip, #1
    --    bne     .L_sub6_and_finish
    --
    --    sub     r3, r3, #5
    --    b       .L_check_size
    --
    --.L_sub8_and_finish:
    --    sub     r3, r3, #8
    --    b       .L_check_size
    --
    --.L_sub7_and_finish:
    --    sub     r3, r3, #7
    --    b       .L_check_size
    --
    --.L_sub6_and_finish:
    --    sub     r3, r3, #6
    --    b       .L_check_size
    --
    --.L_zero_in_second_register:
    --    sub     r3, r0, r1
    --    lsls    r2, ip, #17
    --    bne     .L_sub4_and_finish
    --    bcs     .L_sub3_and_finish
    --    lsls    ip, ip, #1
    --    bne     .L_sub2_and_finish
    --
    --    sub     r3, r3, #1
    --    b       .L_check_size
    --
    --.L_sub4_and_finish:
    --    sub     r3, r3, #4
    --    b       .L_check_size
    --
    --.L_sub3_and_finish:
    --    sub     r3, r3, #3
    --    b       .L_check_size
    --
    --.L_sub2_and_finish:
    --    sub     r3, r3, #2
    --
    --.L_check_size:
    --    pld     [r1, #0]
    --    pld     [r1, #64]
    --    ldr     r0, [sp]
    --
    --    // Add 1 for copy length to get the string terminator.
    --    add     r2, r3, #1
    --
    --    cmp     r2, lr
    --    itt     hi
    --    movhi   r0, r2
    --    bhi     .L_strcpy_chk_failed
    --
    --#include "memcpy_base.S"
    --
    --.L_strcpy_chk_failed:
    --    ldr     r0, error_message
    --    ldr     r1, error_code
    --1:
    --    add     r0, pc
    --    bl      __fortify_chk_fail
    --error_code:
    --    .word   BIONIC_EVENT_STRCPY_BUFFER_OVERFLOW
    --error_message:
    --    .word   error_string-(1b+4)
    --END(__strcpy_chk)
    --
    --    .data
    --error_string:
    --    .string "strcpy: prevented write past end of buffer"
    -diff --git a/libc/arch-arm/cortex-a7/bionic/memcpy.S b/libc/arch-arm/cortex-a7/bionic/memcpy.S
    -deleted file mode 100644
    -index 4d76989..0000000
    ---- a/libc/arch-arm/cortex-a7/bionic/memcpy.S
    -+++ /dev/null
    -@@ -1,107 +0,0 @@
    --/*
    -- * Copyright (C) 2008 The Android Open Source Project
    -- * All rights reserved.
    -- *
    -- * Redistribution and use in source and binary forms, with or without
    -- * modification, are permitted provided that the following conditions
    -- * are met:
    -- *  * Redistributions of source code must retain the above copyright
    -- *    notice, this list of conditions and the following disclaimer.
    -- *  * Redistributions in binary form must reproduce the above copyright
    -- *    notice, this list of conditions and the following disclaimer in
    -- *    the documentation and/or other materials provided with the
    -- *    distribution.
    -- *
    -- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
    -- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
    -- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
    -- * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
    -- * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
    -- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
    -- * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
    -- * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
    -- * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
    -- * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
    -- * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
    -- * SUCH DAMAGE.
    -- */
    --/*
    -- * Copyright (c) 2013 ARM Ltd
    -- * All rights reserved.
    -- *
    -- * Redistribution and use in source and binary forms, with or without
    -- * modification, are permitted provided that the following conditions
    -- * are met:
    -- * 1. Redistributions of source code must retain the above copyright
    -- *    notice, this list of conditions and the following disclaimer.
    -- * 2. Redistributions in binary form must reproduce the above copyright
    -- *    notice, this list of conditions and the following disclaimer in the
    -- *    documentation and/or other materials provided with the distribution.
    -- * 3. The name of the company may not be used to endorse or promote
    -- *    products derived from this software without specific prior written
    -- *    permission.
    -- *
    -- * THIS SOFTWARE IS PROVIDED BY ARM LTD ``AS IS'' AND ANY EXPRESS OR IMPLIED
    -- * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
    -- * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
    -- * IN NO EVENT SHALL ARM LTD BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
    -- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
    -- * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
    -- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
    -- * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
    -- * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
    -- * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
    -- */
    --
    --#include <private/bionic_asm.h>
    --#include <private/libc_events.h>
    --
    --        .text
    --        .syntax unified
    --        .fpu    neon
    --
    --ENTRY(__memcpy_chk)
    --        cmp r2, r3
    --        bls memcpy
    --
    --        // Preserve lr for backtrace.
    --        push        {lr}
    --        .cfi_def_cfa_offset 4
    --        .cfi_rel_offset lr, 0
    --        bl          .L_memcpy_chk_fail
    --END(__memcpy_chk)
    --
    --// Prototype: void *memcpy (void *dst, const void *src, size_t count).
    --ENTRY(memcpy)
    --        pld     [r1, #64]
    --        push    {r0, lr}
    --        .cfi_def_cfa_offset 8
    --        .cfi_rel_offset r0, 0
    --        .cfi_rel_offset lr, 4
    --
    --#include "memcpy_base.S"
    --
    --        // Undo the cfi instructions from above.
    --        .cfi_def_cfa_offset 0
    --        .cfi_restore r0
    --        .cfi_restore lr
    --.L_memcpy_chk_fail:
    --        // Preserve lr for backtrace.
    --        push    {lr}
    --        .cfi_adjust_cfa_offset 4
    --        .cfi_rel_offset lr, 0
    --
    --        ldr     r0, error_message
    --        ldr     r1, error_code
    --1:
    --        add     r0, pc
    --        bl      __fortify_chk_fail
    --error_code:
    --        .word   BIONIC_EVENT_MEMCPY_BUFFER_OVERFLOW
    --error_message:
    --        .word   error_string-(1b+8)
    --END(memcpy)
    --
    --        .data
    --error_string:
    --        .string "memcpy: prevented write past end of buffer"
    -diff --git a/libc/arch-arm/cortex-a7/bionic/memcpy_base.S b/libc/arch-arm/cortex-a7/bionic/memcpy_base.S
    -deleted file mode 100644
    -index 4ff982b..0000000
    ---- a/libc/arch-arm/cortex-a7/bionic/memcpy_base.S
    -+++ /dev/null
    -@@ -1,176 +0,0 @@
    --/*
    -- * Copyright (C) 2008 The Android Open Source Project
    -- * All rights reserved.
    -- *
    -- * Redistribution and use in source and binary forms, with or without
    -- * modification, are permitted provided that the following conditions
    -- * are met:
    -- *  * Redistributions of source code must retain the above copyright
    -- *    notice, this list of conditions and the following disclaimer.
    -- *  * Redistributions in binary form must reproduce the above copyright
    -- *    notice, this list of conditions and the following disclaimer in
    -- *    the documentation and/or other materials provided with the
    -- *    distribution.
    -- *
    -- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
    -- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
    -- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
    -- * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
    -- * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
    -- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
    -- * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
    -- * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
    -- * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
    -- * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
    -- * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
    -- * SUCH DAMAGE.
    -- */
    --/*
    -- * Copyright (c) 2013 ARM Ltd
    -- * All rights reserved.
    -- *
    -- * Redistribution and use in source and binary forms, with or without
    -- * modification, are permitted provided that the following conditions
    -- * are met:
    -- * 1. Redistributions of source code must retain the above copyright
    -- *    notice, this list of conditions and the following disclaimer.
    -- * 2. Redistributions in binary form must reproduce the above copyright
    -- *    notice, this list of conditions and the following disclaimer in the
    -- *    documentation and/or other materials provided with the distribution.
    -- * 3. The name of the company may not be used to endorse or promote
    -- *    products derived from this software without specific prior written
    -- *    permission.
    -- *
    -- * THIS SOFTWARE IS PROVIDED BY ARM LTD ``AS IS'' AND ANY EXPRESS OR IMPLIED
    -- * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
    -- * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
    -- * IN NO EVENT SHALL ARM LTD BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
    -- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
    -- * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
    -- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
    -- * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
    -- * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
    -- * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
    -- */
    --
    --.L_memcpy_base:
    --        // Assumes that n >= 0, and dst, src are valid pointers.
    --        // For any sizes less than 832 use the neon code that doesn't
    --        // care about the src alignment. This avoids any checks
    --        // for src alignment, and offers the best improvement since
    --        // smaller sized copies are dominated by the overhead of
    --        // the pre and post main loop.
    --        // For larger copies, if src and dst cannot both be aligned to
    --        // word boundaries, use the neon code.
    --        // For all other copies, align dst to a double word boundary
    --        // and copy using LDRD/STRD instructions.
    --
    --        cmp     r2, #16
    --        blo     .L_copy_less_than_16_unknown_align
    --
    --.L_copy_unknown_alignment:
    --        // Unknown alignment of src and dst.
    --        // Assumes that the first few bytes have already been prefetched.
    --
    --        // Align destination to 128 bits. The mainloop store instructions
    --        // require this alignment or they will throw an exception.
    --        rsb         r3, r0, #0
    --        ands        r3, r3, #0xF
    --        beq         2f
    --
    --        // Copy up to 15 bytes (count in r3).
    --        sub         r2, r2, r3
    --        movs        ip, r3, lsl #31
    --
    --        itt         mi
    --        ldrbmi      lr, [r1], #1
    --        strbmi      lr, [r0], #1
    --        itttt       cs
    --        ldrbcs      ip, [r1], #1
    --        ldrbcs      lr, [r1], #1
    --        strbcs      ip, [r0], #1
    --        strbcs      lr, [r0], #1
    --
    --        movs        ip, r3, lsl #29
    --        bge         1f
    --        // Copies 4 bytes, dst 32 bits aligned before, at least 64 bits after.
    --        vld4.8      {d0[0], d1[0], d2[0], d3[0]}, [r1]!
    --        vst4.8      {d0[0], d1[0], d2[0], d3[0]}, [r0, :32]!
    --1:      bcc         2f
    --        // Copies 8 bytes, dst 64 bits aligned before, at least 128 bits after.
    --        vld1.8      {d0}, [r1]!
    --        vst1.8      {d0}, [r0, :64]!
    --
    --2:      cmp         r2, #256
    --        ble         .L_copy_loop
    --
    --        // Make sure DST is 64 BYTE aligned.
    --        rsb         r3, r0, #0
    --        ands        r3, r3, #0x30
    --        beq         .L_copy_loop
    --
    --        sub         r2, r2, r3
    --        cmp         r3, #0x10
    --        beq         .L_copy_16
    --
    --        vld1.8      {d0  - d3},   [r1]!
    --        vst1.8      {d0  - d3},   [r0, :128]!
    --        ands        r3, r3, #0x10
    --        beq         .L_copy_loop
    --
    --.L_copy_16:
    --        vld1.8      {d0, d1}, [r1]!
    --        vst1.8      {d0, d1}, [r0, :128]!
    --
    --.L_copy_loop:
    --        // Make sure we have at least 64 bytes to copy.
    --        subs        r2, r2, #64
    --        blo         2f
    --
    --1:      // The main loop copies 64 bytes at a time.
    --        vld1.8      {d0  - d3},   [r1]!
    --        vst1.8      {d0  - d3},   [r0, :128]!
    --        pld         [r1, #(64*4)]
    --        subs        r2, r2, #64
    --        vld1.8      {d4  - d7},   [r1]!
    --        vst1.8      {d4  - d7},   [r0, :128]!
    --        bhs         1b
    --
    --2:      // Fix-up the remaining count and make sure we have >= 32 bytes left.
    --        adds        r2, r2, #32
    --        blo         3f
    --
    --        // 32 bytes. These cache lines were already preloaded.
    --        vld1.8      {d0 - d3},  [r1]!
    --        sub         r2, r2, #32
    --        vst1.8      {d0 - d3},  [r0, :128]!
    --3:      // Less than 32 left.
    --        add         r2, r2, #32
    --        tst         r2, #0x10
    --        beq         .L_copy_less_than_16_unknown_align
    --        // Copies 16 bytes, destination 128 bits aligned.
    --        vld1.8      {d0, d1}, [r1]!
    --        vst1.8      {d0, d1}, [r0, :128]!
    --
    --.L_copy_less_than_16_unknown_align:
    --        // Copy up to 15 bytes (count in r2).
    --        movs        ip, r2, lsl #29
    --        bcc         1f
    --        vld1.8      {d0}, [r1]!
    --        vst1.8      {d0}, [r0]!
    --1:      bge         2f
    --        vld4.8      {d0[0], d1[0], d2[0], d3[0]}, [r1]!
    --        vst4.8      {d0[0], d1[0], d2[0], d3[0]}, [r0]!
    --
    --2:      // Copy 0 to 4 bytes.
    --        lsls        r2, r2, #31
    --        itt         ne
    --        ldrbne      lr, [r1], #1
    --        strbne      lr, [r0], #1
    --        itttt       cs
    --        ldrbcs      ip, [r1], #1
    --        ldrbcs      lr, [r1]
    --        strbcs      ip, [r0], #1
    --        strbcs      lr, [r0]
    --
    --        pop         {r0, pc}
    -diff --git a/libc/arch-arm/cortex-a7/cortex-a7.mk b/libc/arch-arm/cortex-a7/cortex-a7.mk
    -index 199eb11..f570d0f 100644
    ---- a/libc/arch-arm/cortex-a7/cortex-a7.mk
    -+++ b/libc/arch-arm/cortex-a7/cortex-a7.mk
    -@@ -13,16 +13,16 @@ libc_bionic_src_files_exclude_arm += \
    -     bionic/__strcpy_chk.cpp \
    - 
    - libc_bionic_src_files_arm += \
    --    arch-arm/cortex-a7/bionic/memcpy.S \
    -     arch-arm/cortex-a7/bionic/memset.S \
    --    arch-arm/cortex-a7/bionic/__strcat_chk.S \
    --    arch-arm/cortex-a7/bionic/__strcpy_chk.S \
    - 
    - libc_bionic_src_files_arm += \
    -+    arch-arm/cortex-a15/bionic/memcpy.S \
    -     arch-arm/cortex-a15/bionic/stpcpy.S \
    -     arch-arm/cortex-a15/bionic/strcat.S \
    -+    arch-arm/cortex-a15/bionic/__strcat_chk.S \
    -     arch-arm/cortex-a15/bionic/strcmp.S \
    -     arch-arm/cortex-a15/bionic/strcpy.S \
    -+    arch-arm/cortex-a15/bionic/__strcpy_chk.S \
    -     arch-arm/cortex-a15/bionic/strlen.S \
    - 
    - libc_bionic_src_files_arm += \
     diff --git a/libc/arch-arm/generic/bionic/memchr.S b/libc/arch-arm/generic/bionic/memchr.S
     new file mode 100644
     index 0000000..cb00d82
    @@ -924,22 +181,6 @@ index 0000000..cb00d82
     +	subs	r0,r0,#1
     +	bx	lr
     +END(memchr)
    -diff --git a/libc/malloc_debug/backtrace.cpp b/libc/malloc_debug/backtrace.cpp
    -index 75a255c..18ce8b8 100644
    ---- a/libc/malloc_debug/backtrace.cpp
    -+++ b/libc/malloc_debug/backtrace.cpp
    -@@ -142,8 +142,6 @@ std::string backtrace_string(const uintptr_t* frames, size_t frame_count) {
    -     if (dladdr(reinterpret_cast<void*>(frames[frame_num]), &info) != 0) {
    -       offset = reinterpret_cast<uintptr_t>(info.dli_saddr);
    -       symbol = info.dli_sname;
    --    } else {
    --      info.dli_fname = nullptr;
    -     }
    - 
    -     uintptr_t rel_pc = offset;
    -diff --git a/libc/zoneinfo/tzdata b/libc/zoneinfo/tzdata
    -index 577ede6..57bff7b 100644
    -Binary files a/libc/zoneinfo/tzdata and b/libc/zoneinfo/tzdata differ
     diff --git a/linker/Android.mk b/linker/Android.mk
     index 4a4ca5c..0d592c9 100644
     --- a/linker/Android.mk
    @@ -979,59 +220,3 @@ index 9dc928e..2a665b5 100644
          // Make segments writable to allow text relocations to work properly. We will later call
          // phdr_table_protect_segments() after all of them are applied.
          DL_WARN("%s has text relocations. This is wasting memory and prevents "
    -diff --git a/tests/sys_prctl_test.cpp b/tests/sys_prctl_test.cpp
    -index f0ac1c3..5a563c1 100644
    ---- a/tests/sys_prctl_test.cpp
    -+++ b/tests/sys_prctl_test.cpp
    -@@ -14,19 +14,11 @@
    -  * limitations under the License.
    -  */
    - 
    --#include <inttypes.h>
    --#include <stdio.h>
    -+#include <gtest/gtest.h>
    -+
    - #include <sys/mman.h>
    - #include <sys/prctl.h>
    - #include <unistd.h>
    --
    --#include <string>
    --#include <vector>
    --
    --#include <gtest/gtest.h>
    --
    --#include "android-base/file.h"
    --#include "android-base/strings.h"
    - #include "private/bionic_prctl.h"
    - 
    - // http://b/20017123.
    -@@ -37,26 +29,9 @@ TEST(sys_prctl, bug_20017123) {
    -   ASSERT_NE(MAP_FAILED, p);
    -   ASSERT_EQ(0, mprotect(p, page_size, PROT_NONE));
    -   ASSERT_NE(-1, prctl(PR_SET_VMA, PR_SET_VMA_ANON_NAME, p, page_size * 3, "anonymous map space"));
    --  // Now read the maps and verify that there are no overlapped maps.
    --  std::string file_data;
    --  ASSERT_TRUE(android::base::ReadFileToString("/proc/self/maps", &file_data));
    --
    --  uintptr_t last_end = 0;
    --  std::vector<std::string> lines = android::base::Split(file_data, "\n");
    --  for (size_t i = 0; i < lines.size(); i++) {
    --    if (lines[i].empty()) {
    --      continue;
    --    }
    --    uintptr_t start;
    --    uintptr_t end;
    --    ASSERT_EQ(2, sscanf(lines[i].c_str(), "%" SCNxPTR "-%" SCNxPTR " ", &start, &end))
    --        << "Failed to parse line: " << lines[i];
    --    // This will never fail on the first line, so no need to do any special checking.
    --    ASSERT_GE(start, last_end)
    --        << "Overlapping map detected:\n" << lines[i -1] << '\n' << lines[i] << '\n';
    --    last_end = end;
    --  }
    --
    -+  volatile char* vp = reinterpret_cast<volatile char*>(p);
    -+  // Below memory access causes SEGV if the memory map is screwed up.
    -+  *(vp + page_size) = 0;
    -   ASSERT_EQ(0, munmap(p, page_size * 3));
    - #else
    -   GTEST_LOG_(INFO) << "This test does nothing as it tests an Android specific kernel feature.";
    diff --git a/frameworks_av.patch b/frameworks_av.patch
    index bc42afd..67ca1db 100644
    --- a/frameworks_av.patch
    +++ b/frameworks_av.patch
    @@ -52,17 +52,6 @@ index 7e36c5e..aca7a19 100644
      
      include $(BUILD_EXECUTABLE)
     +endif
    -diff --git a/camera/cameraserver/main_cameraserver.cpp b/camera/cameraserver/main_cameraserver.cpp
    -index f4be468..ea80ad4 100644
    ---- a/camera/cameraserver/main_cameraserver.cpp
    -+++ b/camera/cameraserver/main_cameraserver.cpp
    -@@ -31,5 +31,6 @@ int main(int argc __unused, char** argv __unused)
    -     ALOGI("ServiceManager: %p", sm.get());
    -     CameraService::instantiate();
    -     ProcessState::self()->startThreadPool();
    -+    IPCThreadState::self()->disableBackgroundScheduling(true);
    -     IPCThreadState::self()->joinThreadPool();
    - }
     diff --git a/camera/ndk/NdkCaptureRequest.cpp b/camera/ndk/NdkCaptureRequest.cpp
     index 77b9a33..7c37955 100644
     --- a/camera/ndk/NdkCaptureRequest.cpp
    @@ -137,7 +126,7 @@ index dc4e5d4..b64d899 100644
      
      void NuPlayer::determineAudioModeChange(const sp<AMessage> &audioFormat) {
     diff --git a/media/libstagefright/ACodec.cpp b/media/libstagefright/ACodec.cpp
    -index 37fd5a5..337fb2d 100644
    +index 37fd5a5..77a2a39 100644
     --- a/media/libstagefright/ACodec.cpp
     +++ b/media/libstagefright/ACodec.cpp
     @@ -804,13 +804,22 @@ status_t ACodec::allocateBuffersOnPort(OMX_U32 portIndex) {
    @@ -163,30 +152,7 @@ index 37fd5a5..337fb2d 100644
                      bufSize = max(sizeof(VideoGrallocMetadata), sizeof(VideoNativeMetadata));
                  } else if (portIndex == kPortIndexInput && type == kMetadataBufferTypeCameraSource) {
                      bufSize = max(bufSize, sizeof(VideoNativeMetadata));
    -@@ -1052,6 +1061,12 @@ status_t ACodec::configureOutputBuffersFromNativeWindow(
    -     // 2. try to allocate two (2) additional buffers to reduce starvation from
    -     //    the consumer
    -     //    plus an extra buffer to account for incorrect minUndequeuedBufs
    -+#ifdef BOARD_CANT_REALLOCATE_OMX_BUFFERS
    -+    // Some devices don't like to set OMX_IndexParamPortDefinition at this
    -+    // point (even with an unmodified def), so skip it if possible.
    -+    // This check was present in KitKat.
    -+    if (def.nBufferCountActual < def.nBufferCountMin + *minUndequeuedBuffers) {
    -+#endif
    -     for (OMX_U32 extraBuffers = 2 + 1; /* condition inside loop */; extraBuffers--) {
    -         OMX_U32 newBufferCount =
    -             def.nBufferCountMin + *minUndequeuedBuffers + extraBuffers;
    -@@ -1071,6 +1086,9 @@ status_t ACodec::configureOutputBuffersFromNativeWindow(
    -             return err;
    -         }
    -     }
    -+#ifdef BOARD_CANT_REALLOCATE_OMX_BUFFERS
    -+    }
    -+#endif
    - 
    -     err = native_window_set_buffer_count(
    -             mNativeWindow.get(), def.nBufferCountActual);
    -@@ -1766,6 +1784,14 @@ status_t ACodec::configureCodec(
    +@@ -1766,6 +1775,14 @@ status_t ACodec::configureCodec(
                  mInputMetadataType = (MetadataBufferType)storeMeta;
              }
      
    @@ -201,7 +167,7 @@ index 37fd5a5..337fb2d 100644
              uint32_t usageBits;
              if (mOMX->getParameter(
                      mNode, (OMX_INDEXTYPE)OMX_IndexParamConsumerUsageBits,
    -@@ -4274,7 +4300,9 @@ status_t ACodec::setupAVCEncoderParameters(const sp<AMessage> &msg) {
    +@@ -4274,7 +4291,9 @@ status_t ACodec::setupAVCEncoderParameters(const sp<AMessage> &msg) {
      
              h264type.eProfile = static_cast<OMX_VIDEO_AVCPROFILETYPE>(profile);
              h264type.eLevel = static_cast<OMX_VIDEO_AVCLEVELTYPE>(level);
    @@ -212,7 +178,7 @@ index 37fd5a5..337fb2d 100644
              h264type.eProfile = OMX_VIDEO_AVCProfileBaseline;
      #if 0   /* DON'T YET DEFAULT TO HIGHEST PROFILE */
              // Use largest supported profile for AVC recording if profile is not specified.
    -@@ -4287,6 +4315,7 @@ status_t ACodec::setupAVCEncoderParameters(const sp<AMessage> &msg) {
    +@@ -4287,6 +4306,7 @@ status_t ACodec::setupAVCEncoderParameters(const sp<AMessage> &msg) {
              }
      #endif
          }
    @@ -220,23 +186,7 @@ index 37fd5a5..337fb2d 100644
      
          ALOGI("setupAVCEncoderParameters with [profile: %s] [level: %s]",
                  asString(h264type.eProfile), asString(h264type.eLevel));
    -@@ -4762,6 +4791,7 @@ bool ACodec::describeDefaultColorFormat(DescribeColorFormat2Params &params) {
    -         fmt != OMX_COLOR_FormatYUV420PackedPlanar &&
    -         fmt != OMX_COLOR_FormatYUV420SemiPlanar &&
    -         fmt != OMX_COLOR_FormatYUV420PackedSemiPlanar &&
    -+        fmt != OMX_TI_COLOR_FormatYUV420PackedSemiPlanar &&
    -         fmt != (OMX_COLOR_FORMATTYPE)HAL_PIXEL_FORMAT_YV12) {
    -         ALOGW("do not know color format 0x%x = %d", fmt, fmt);
    -         return false;
    -@@ -4838,6 +4868,7 @@ bool ACodec::describeDefaultColorFormat(DescribeColorFormat2Params &params) {
    -         case OMX_COLOR_FormatYUV420SemiPlanar:
    -             // FIXME: NV21 for sw-encoder, NV12 for decoder and hw-encoder
    -         case OMX_COLOR_FormatYUV420PackedSemiPlanar:
    -+        case OMX_TI_COLOR_FormatYUV420PackedSemiPlanar:
    -             // NV12
    -             image.mPlane[image.U].mOffset = params.nStride * params.nSliceHeight;
    -             image.mPlane[image.U].mColInc = 2;
    -@@ -6036,6 +6067,9 @@ void ACodec::BaseState::onInputBufferFilled(const sp<AMessage> &msg) {
    +@@ -6036,6 +6056,9 @@ void ACodec::BaseState::onInputBufferFilled(const sp<AMessage> &msg) {
                      status_t err2 = OK;
                      switch (metaType) {
                      case kMetadataBufferTypeInvalid:
    @@ -246,7 +196,7 @@ index 37fd5a5..337fb2d 100644
                          break;
      #ifndef OMX_ANDROID_COMPILE_AS_32BIT_ON_64BIT_PLATFORMS
                      case kMetadataBufferTypeNativeHandleSource:
    -@@ -6267,6 +6301,10 @@ bool ACodec::BaseState::onOMXFillBufferDone(
    +@@ -6267,6 +6290,10 @@ bool ACodec::BaseState::onOMXFillBufferDone(
                      native_handle_t *handle = NULL;
                      VideoNativeHandleMetadata &nativeMeta =
                          *(VideoNativeHandleMetadata *)info->mData->data();
    @@ -257,7 +207,7 @@ index 37fd5a5..337fb2d 100644
                      if (info->mData->size() >= sizeof(nativeMeta)
                              && nativeMeta.eType == kMetadataBufferTypeNativeHandleSource) {
      #ifdef OMX_ANDROID_COMPILE_AS_32BIT_ON_64BIT_PLATFORMS
    -@@ -6276,6 +6314,12 @@ bool ACodec::BaseState::onOMXFillBufferDone(
    +@@ -6276,6 +6303,12 @@ bool ACodec::BaseState::onOMXFillBufferDone(
                          handle = (native_handle_t *)nativeMeta.pHandle;
      #endif
                      }
    @@ -270,7 +220,7 @@ index 37fd5a5..337fb2d 100644
                      info->mData->meta()->setPointer("handle", handle);
                      info->mData->meta()->setInt32("rangeOffset", rangeOffset);
                      info->mData->meta()->setInt32("rangeLength", rangeLength);
    -@@ -6968,10 +7012,12 @@ void ACodec::LoadedState::onCreateInputSurface(
    +@@ -6968,10 +7001,12 @@ void ACodec::LoadedState::onCreateInputSurface(
              err = mCodec->mOMX->createInputSurface(
                      mCodec->mNode, kPortIndexInput, dataSpace, &bufferProducer,
                      &mCodec->mInputMetadataType);
    @@ -283,7 +233,7 @@ index 37fd5a5..337fb2d 100644
          }
      
          if (err == OK) {
    -@@ -7014,10 +7060,12 @@ void ACodec::LoadedState::onSetInputSurface(
    +@@ -7014,10 +7049,12 @@ void ACodec::LoadedState::onSetInputSurface(
              err = mCodec->mOMX->setInputSurface(
                      mCodec->mNode, kPortIndexInput, surface->getBufferConsumer(),
                      &mCodec->mInputMetadataType);
    @@ -297,7 +247,7 @@ index 37fd5a5..337fb2d 100644
      
          if (err == OK) {
     diff --git a/media/libstagefright/Android.mk b/media/libstagefright/Android.mk
    -index 3848502..07f926c 100644
    +index 3848502..1635375 100644
     --- a/media/libstagefright/Android.mk
     +++ b/media/libstagefright/Android.mk
     @@ -102,6 +102,10 @@ LOCAL_SHARED_LIBRARIES := \
    @@ -322,17 +272,6 @@ index 3848502..07f926c 100644
      LOCAL_CFLAGS += -Wno-multichar -Werror -Wno-error=deprecated-declarations -Wall
      
      # enable experiments only in userdebug and eng builds
    -@@ -131,6 +139,10 @@ ifneq (,$(filter userdebug eng,$(TARGET_BUILD_VARIANT)))
    - LOCAL_CFLAGS += -DENABLE_STAGEFRIGHT_EXPERIMENTS
    - endif
    - 
    -+ifeq ($(TARGET_BOARD_PLATFORM),omap4)
    -+LOCAL_CFLAGS += -DBOARD_CANT_REALLOCATE_OMX_BUFFERS
    -+endif
    -+
    - LOCAL_CLANG := true
    - LOCAL_SANITIZE := unsigned-integer-overflow signed-integer-overflow
    - 
     diff --git a/media/libstagefright/CameraSource.cpp b/media/libstagefright/CameraSource.cpp
     index 893da89..0bc6847 100644
     --- a/media/libstagefright/CameraSource.cpp
    @@ -500,22 +439,6 @@ index 15ff569..0e9b4e6 100644
      
          (*buffer)->setObserver(this);
          (*buffer)->add_ref();
    -diff --git a/media/libstagefright/avc_utils.cpp b/media/libstagefright/avc_utils.cpp
    -index 763381e..e5819ed 100644
    ---- a/media/libstagefright/avc_utils.cpp
    -+++ b/media/libstagefright/avc_utils.cpp
    -@@ -479,7 +479,10 @@ bool IsAVCReferenceFrame(const sp<ABuffer> &accessUnit) {
    -     const uint8_t *nalStart;
    -     size_t nalSize;
    -     while (getNextNALUnit(&data, &size, &nalStart, &nalSize, true) == OK) {
    --        CHECK_GT(nalSize, 0u);
    -+        if (nalSize == 0u) {
    -+            ALOGW("skipping empty nal unit from potentially malformed bitstream");
    -+            continue;
    -+        }
    - 
    -         unsigned nalType = nalStart[0] & 0x1f;
    - 
     diff --git a/media/libstagefright/foundation/MediaBufferGroup.cpp b/media/libstagefright/foundation/MediaBufferGroup.cpp
     index 8e4d064..66992d7 100644
     --- a/media/libstagefright/foundation/MediaBufferGroup.cpp
    @@ -810,45 +733,3 @@ index 266fb03..3c2b98a 100644
      }
      
      status_t CameraClient::setVideoBufferMode(int32_t videoBufferMode) {
    -diff --git a/services/soundtrigger/SoundTriggerHwService.cpp b/services/soundtrigger/SoundTriggerHwService.cpp
    -index eebc487..74d0c70 100644
    ---- a/services/soundtrigger/SoundTriggerHwService.cpp
    -+++ b/services/soundtrigger/SoundTriggerHwService.cpp
    -@@ -278,6 +278,37 @@ void SoundTriggerHwService::sendRecognitionEvent(struct sound_trigger_recognitio
    -      if (module == NULL) {
    -          return;
    -      }
    -+    struct sound_trigger_phrase_recognition_event newEvent;
    -+    if (event-> type == SOUND_MODEL_TYPE_KEYPHRASE && event->data_size != 0
    -+        && event->data_offset != sizeof(struct sound_trigger_phrase_recognition_event)) {
    -+        // set some defaults for the phrase if the recognition event won't be parsed properly
    -+        // TODO: read defaults from the config
    -+
    -+        memset(&newEvent, 0, sizeof(struct sound_trigger_phrase_recognition_event));
    -+
    -+        sp<Model> model = module->getModel(event->model);
    -+
    -+        newEvent.num_phrases = 1;
    -+        newEvent.phrase_extras[0].id = 100;
    -+        newEvent.phrase_extras[0].recognition_modes = RECOGNITION_MODE_VOICE_TRIGGER;
    -+        newEvent.phrase_extras[0].confidence_level = 100;
    -+        newEvent.phrase_extras[0].num_levels = 1;
    -+        newEvent.phrase_extras[0].levels[0].level = 100;
    -+        newEvent.phrase_extras[0].levels[0].user_id = 100;
    -+        newEvent.common.status = event->status;
    -+        newEvent.common.type = event->type;
    -+        newEvent.common.model = event->model;
    -+        newEvent.common.capture_available = event->capture_available;
    -+        newEvent.common.capture_session = event->capture_session;
    -+        newEvent.common.capture_delay_ms = event->capture_delay_ms;
    -+        newEvent.common.capture_preamble_ms = event->capture_preamble_ms;
    -+        newEvent.common.trigger_in_data = event->trigger_in_data;
    -+        newEvent.common.audio_config = event->audio_config;
    -+        newEvent.common.data_size = event->data_size;
    -+        newEvent.common.data_offset = sizeof(struct sound_trigger_phrase_recognition_event);
    -+
    -+         event = &newEvent.common;
    -+     }
    -      sp<IMemory> eventMemory = prepareRecognitionEvent_l(event);
    -      if (eventMemory == 0) {
    -          return;
    diff --git a/frameworks_base.patch b/frameworks_base.patch
    index 75080a3..2968407 100644
    --- a/frameworks_base.patch
    +++ b/frameworks_base.patch
    @@ -600,7 +600,7 @@ index c6ab918..d848081 100644
                  mService.notifyAll();
              }
     diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
    -index 39e2914..1e95d28 100644
    +index b6a9940..11b5832a 100644
     --- a/services/core/java/com/android/server/pm/PackageManagerService.java
     +++ b/services/core/java/com/android/server/pm/PackageManagerService.java
     @@ -423,7 +423,7 @@ public class PackageManagerService extends IPackageManager.Stub {
    diff --git a/system_sepolicy.patch b/system_sepolicy.patch
    index 1d9a08e..cf14445 100644
    --- a/system_sepolicy.patch
    +++ b/system_sepolicy.patch
    @@ -12,14 +12,14 @@ index e9dd7b3..ef2bd9d 100644
      
      # Block device access.
     diff --git a/domain.te b/domain.te
    -index 45569de..21c9df2 100644
    +index 45569de..5e705c6 100644
     --- a/domain.te
     +++ b/domain.te
     @@ -159,6 +159,7 @@ neverallow {
        -dumpstate
        -system_server
        userdebug_or_eng(`-perfprofd')
    -+  userdebug_or_eng(`-procrank')
    ++#  userdebug_or_eng(`-procrank')
      } self:capability sys_ptrace;
      
      # Limit device node creation to these whitelisted domains.
    
    From 5a774af016beba532ec4de73c2b3579f93b60b0b Mon Sep 17 00:00:00 2001
    From: AndDiSa <anddisa@googlemail.com>
    Date: Sun, 7 May 2017 10:19:26 +0200
    Subject: [PATCH 076/159] update patches
    
    Change-Id: Ie595a7d83a7cdd839fbaf420c82ff4d8679fcf4d
    ---
     hardware_ril.patch | 12 +++++++++++-
     1 file changed, 11 insertions(+), 1 deletion(-)
    
    diff --git a/hardware_ril.patch b/hardware_ril.patch
    index 4b5d125..fa1247c 100644
    --- a/hardware_ril.patch
    +++ b/hardware_ril.patch
    @@ -1,5 +1,5 @@
     diff --git a/libril/ril.cpp b/libril/ril.cpp
    -index d7744c0..561ba55 100644
    +index d7744c0..05119b1 100644
     --- a/libril/ril.cpp
     +++ b/libril/ril.cpp
     @@ -3804,6 +3804,7 @@ static void responseSimStatusV5(Parcel &p, void *response) {
    @@ -10,3 +10,13 @@ index d7744c0..561ba55 100644
      
          sendSimStatusAppInfo(p, p_cur->num_applications, p_cur->applications);
      }
    +@@ -5401,6 +5402,9 @@ void RIL_onUnsolicitedResponse(int unsolResponse, const void *data,
    +             p.writeInt32(newState);
    +             appendPrintBuf("%s {%s}", printBuf,
    +                 radioStateToString(CALL_ONSTATEREQUEST(soc_id)));
    ++            if (newState == RADIO_STATE_UNAVAILABLE) {
    ++                abort(); // kill rild process
    ++            }
    +         break;
    + 
    + 
    
    From 6917ad40c02fb2e74173fe2aceea901953331975 Mon Sep 17 00:00:00 2001
    From: AndDiSa <anddisa@googlemail.com>
    Date: Wed, 7 Jun 2017 17:49:59 +0200
    Subject: [PATCH 077/159] update to android-7.1.2_r16
    
    Change-Id: I0020db7621dac35e173a5631aecbcbbb911c5741
    ---
     default.xml | 2 +-
     1 file changed, 1 insertion(+), 1 deletion(-)
    
    diff --git a/default.xml b/default.xml
    index c484bb4..80a111c 100644
    --- a/default.xml
    +++ b/default.xml
    @@ -9,7 +9,7 @@
                fetch="https://github.com/millosr/" />
       <remote  name="unlegacy"
                fetch="https://github.com/Unlegacy-Android/" />
    -  <default revision="refs/tags/android-7.1.2_r10"
    +  <default revision="refs/tags/android-7.1.2_r16"
                remote="aosp"
                sync-j="4" />
     
    
    From 6cfb355fb51dfa5505409b87794a1ca1f3fc56a5 Mon Sep 17 00:00:00 2001
    From: AndDiSa <anddisa@googlemail.com>
    Date: Thu, 8 Jun 2017 18:03:43 +0200
    Subject: [PATCH 078/159] update patches
    
    Change-Id: Ib2a610688325f9f74e2560dcc6687a6f7f961c55
    ---
     bionic.patch            | 22 +++++++++++++++++++++-
     build.patch             | 38 ++++++++++++++++++++++++++++++++++++++
     frameworks_native.patch |  4 ++--
     system_core.patch       |  4 ++--
     system_sepolicy.patch   |  4 ++--
     5 files changed, 65 insertions(+), 7 deletions(-)
    
    diff --git a/bionic.patch b/bionic.patch
    index 625c884..132d7dc 100644
    --- a/bionic.patch
    +++ b/bionic.patch
    @@ -197,9 +197,29 @@ index 4a4ca5c..0d592c9 100644
      LOCAL_CFLAGS += -I$(LOCAL_PATH)/../libc/
      
     diff --git a/linker/linker.cpp b/linker/linker.cpp
    -index 9dc928e..2a665b5 100644
    +index 9dc928e..0ac26c6 100644
     --- a/linker/linker.cpp
     +++ b/linker/linker.cpp
    +@@ -560,7 +560,7 @@ static bool realpath_fd(int fd, std::string* realpath) {
    +   std::vector<char> buf(PATH_MAX), proc_self_fd(PATH_MAX);
    +   __libc_format_buffer(&proc_self_fd[0], proc_self_fd.size(), "/proc/self/fd/%d", fd);
    +   if (readlink(&proc_self_fd[0], &buf[0], buf.size()) == -1) {
    +-    PRINT("readlink(\"%s\") failed: %s [fd=%d]", &proc_self_fd[0], strerror(errno), fd);
    ++//    PRINT("readlink(\"%s\") failed: %s [fd=%d]", &proc_self_fd[0], strerror(errno), fd);
    +     return false;
    +   }
    + 
    +@@ -1545,8 +1545,8 @@ static int open_library_in_zipfile(ZipArchiveCache* zip_archive_cache,
    +   if (realpath_fd(fd, realpath)) {
    +     *realpath += separator;
    +   } else {
    +-    PRINT("warning: unable to get realpath for the library \"%s\". Will use given path.",
    +-          normalized_path.c_str());
    ++//    PRINT("warning: unable to get realpath for the library \"%s\". Will use given path.",
    ++//          normalized_path.c_str());
    +     *realpath = normalized_path;
    +   }
    + 
     @@ -3950,11 +3950,18 @@ bool soinfo::link_image(const soinfo_list_t& global_group, const soinfo_list_t&
      #if !defined(__LP64__)
        if (has_text_relocations) {
    diff --git a/build.patch b/build.patch
    index 5246b91..ad934ad 100644
    --- a/build.patch
    +++ b/build.patch
    @@ -1,3 +1,15 @@
    +diff --git a/core/Makefile b/core/Makefile
    +index d8b4ef8..2f962aa 100644
    +--- a/core/Makefile
    ++++ b/core/Makefile
    +@@ -247,6 +247,7 @@ endif
    + 			TARGET_CPU_ABI="$(TARGET_CPU_ABI)" \
    + 			TARGET_CPU_ABI2="$(TARGET_CPU_ABI2)" \
    + 			TARGET_AAPT_CHARACTERISTICS="$(TARGET_AAPT_CHARACTERISTICS)" \
    ++			$(PRODUCT_BUILD_PROP_OVERRIDES) \
    + 	        bash $(BUILDINFO_SH) >> $@
    + 	$(hide) $(foreach file,$(system_prop_file), \
    + 		if [ -f "$(file)" ]; then \
     diff --git a/core/combo/arch/arm/armv7-a-neon.mk b/core/combo/arch/arm/armv7-a-neon.mk
     index 5d5b050..b0e1e25 100644
     --- a/core/combo/arch/arm/armv7-a-neon.mk
    @@ -82,6 +94,32 @@ index a612f83..921eb32 100644
      endif
      
      
    +diff --git a/core/product.mk b/core/product.mk
    +index 332b015..447ebbc 100644
    +--- a/core/product.mk
    ++++ b/core/product.mk
    +@@ -73,6 +73,7 @@ endef
    + #
    + 
    + _product_var_list := \
    ++    PRODUCT_BUILD_PROP_OVERRIDES \
    +     PRODUCT_NAME \
    +     PRODUCT_MODEL \
    +     PRODUCT_LOCALES \
    +diff --git a/core/product_config.mk b/core/product_config.mk
    +index 6438d51..2204f78 100644
    +--- a/core/product_config.mk
    ++++ b/core/product_config.mk
    +@@ -363,6 +363,9 @@ endif
    + PRODUCT_DEFAULT_PROPERTY_OVERRIDES := \
    +     $(strip $(PRODUCTS.$(INTERNAL_PRODUCT).PRODUCT_DEFAULT_PROPERTY_OVERRIDES))
    + 
    ++PRODUCT_BUILD_PROP_OVERRIDES := \
    ++	$(strip $(PRODUCTS.$(INTERNAL_PRODUCT).PRODUCT_BUILD_PROP_OVERRIDES))
    ++
    + # Should we use the default resources or add any product specific overlays
    + PRODUCT_PACKAGE_OVERLAYS := \
    +     $(strip $(PRODUCTS.$(INTERNAL_PRODUCT).PRODUCT_PACKAGE_OVERLAYS))
     diff --git a/core/tasks/kernel.mk b/core/tasks/kernel.mk
     new file mode 100644
     index 0000000..ee76dc2
    diff --git a/frameworks_native.patch b/frameworks_native.patch
    index 1f4576c..43cd0f0 100644
    --- a/frameworks_native.patch
    +++ b/frameworks_native.patch
    @@ -222,10 +222,10 @@ index 0000000..2eb1cc1
     +#endif // ANDROID_FRAMEBUFFER_NATIVE_WINDOW_H
     +
     diff --git a/libs/binder/IPCThreadState.cpp b/libs/binder/IPCThreadState.cpp
    -index d90798f..9b5f0d7 100644
    +index eccc400..3efebf7 100644
     --- a/libs/binder/IPCThreadState.cpp
     +++ b/libs/binder/IPCThreadState.cpp
    -@@ -330,6 +330,7 @@ void IPCThreadState::shutdown()
    +@@ -331,6 +331,7 @@ void IPCThreadState::shutdown()
                  delete st;
                  pthread_setspecific(gTLS, NULL);
              }
    diff --git a/system_core.patch b/system_core.patch
    index c8a09ed..9b9295f 100644
    --- a/system_core.patch
    +++ b/system_core.patch
    @@ -182,10 +182,10 @@ index cd2d2e6..81628a1 100644
          am.QueueBuiltinAction(console_init_action, "console_init");
      
     diff --git a/rootdir/init.rc b/rootdir/init.rc
    -index df60f65..f4de4a2 100644
    +index 7dc9e55..adc062b 100644
     --- a/rootdir/init.rc
     +++ b/rootdir/init.rc
    -@@ -665,6 +665,6 @@ on property:ro.debuggable=1
    +@@ -656,6 +656,6 @@ on property:ro.debuggable=1
          chmod 0773 /data/misc/trace
          start console
      
    diff --git a/system_sepolicy.patch b/system_sepolicy.patch
    index cf14445..1d9a08e 100644
    --- a/system_sepolicy.patch
    +++ b/system_sepolicy.patch
    @@ -12,14 +12,14 @@ index e9dd7b3..ef2bd9d 100644
      
      # Block device access.
     diff --git a/domain.te b/domain.te
    -index 45569de..5e705c6 100644
    +index 45569de..21c9df2 100644
     --- a/domain.te
     +++ b/domain.te
     @@ -159,6 +159,7 @@ neverallow {
        -dumpstate
        -system_server
        userdebug_or_eng(`-perfprofd')
    -+#  userdebug_or_eng(`-procrank')
    ++  userdebug_or_eng(`-procrank')
      } self:capability sys_ptrace;
      
      # Limit device node creation to these whitelisted domains.
    
    From 09496b9ec115785e795233fb83c790a1d45b4e35 Mon Sep 17 00:00:00 2001
    From: AndDiSa <anddisa@googlemail.com>
    Date: Thu, 6 Jul 2017 18:30:16 +0200
    Subject: [PATCH 079/159] update to android-7.1.2_r27
    
    Change-Id: I5686e8195ba8416c7a3a6d039f552a2854ab5fb2
    ---
     default.xml | 2 +-
     1 file changed, 1 insertion(+), 1 deletion(-)
    
    diff --git a/default.xml b/default.xml
    index 80a111c..8a6ebe4 100644
    --- a/default.xml
    +++ b/default.xml
    @@ -9,7 +9,7 @@
                fetch="https://github.com/millosr/" />
       <remote  name="unlegacy"
                fetch="https://github.com/Unlegacy-Android/" />
    -  <default revision="refs/tags/android-7.1.2_r16"
    +  <default revision="refs/tags/android-7.1.2_r27"
                remote="aosp"
                sync-j="4" />
     
    
    From f75984d041edcc4ca14638c2c018a7f691226ce4 Mon Sep 17 00:00:00 2001
    From: AndDiSa <anddisa@googlemail.com>
    Date: Fri, 7 Jul 2017 18:24:12 +0200
    Subject: [PATCH 080/159] update patches
    
    Change-Id: I29028439fa52802d6e5b75dd3d5e87531b43cebd
    ---
     bionic.patch            |  4 +--
     default.xml             |  1 -
     frameworks_av.patch     |  8 ++---
     frameworks_base.patch   | 74 +++++++++++++++++++++++++++++++++++++++++
     frameworks_native.patch |  8 ++---
     5 files changed, 84 insertions(+), 11 deletions(-)
    
    diff --git a/bionic.patch b/bionic.patch
    index 132d7dc..cac729b 100644
    --- a/bionic.patch
    +++ b/bionic.patch
    @@ -197,7 +197,7 @@ index 4a4ca5c..0d592c9 100644
      LOCAL_CFLAGS += -I$(LOCAL_PATH)/../libc/
      
     diff --git a/linker/linker.cpp b/linker/linker.cpp
    -index 9dc928e..0ac26c6 100644
    +index a043b85..cd1874f 100644
     --- a/linker/linker.cpp
     +++ b/linker/linker.cpp
     @@ -560,7 +560,7 @@ static bool realpath_fd(int fd, std::string* realpath) {
    @@ -220,7 +220,7 @@ index 9dc928e..0ac26c6 100644
          *realpath = normalized_path;
        }
      
    -@@ -3950,11 +3950,18 @@ bool soinfo::link_image(const soinfo_list_t& global_group, const soinfo_list_t&
    +@@ -3953,11 +3953,18 @@ bool soinfo::link_image(const soinfo_list_t& global_group, const soinfo_list_t&
      #if !defined(__LP64__)
        if (has_text_relocations) {
          // Fail if app is targeting sdk version > 22
    diff --git a/default.xml b/default.xml
    index 8a6ebe4..47f4250 100644
    --- a/default.xml
    +++ b/default.xml
    @@ -236,7 +236,6 @@
       <project path="external/objenesis" name="platform/external/objenesis" groups="pdk-cw-fs,pdk-fs" />
       <project path="external/okhttp" name="platform/external/okhttp" groups="pdk-cw-fs,pdk-fs" />
       <project path="external/opencv" name="platform/external/opencv" groups="pdk-cw-fs,pdk-fs" />
    -  <project path="external/opencv3" name="platform/external/opencv3" />
       <project path="external/owasp/sanitizer" name="platform/external/owasp/sanitizer" groups="pdk-fs" />
       <project path="external/parameter-framework" name="platform/external/parameter-framework" groups="pdk-fs" />
       <project path="external/pcre" name="platform/external/pcre" groups="pdk" />
    diff --git a/frameworks_av.patch b/frameworks_av.patch
    index 67ca1db..fdbb792 100644
    --- a/frameworks_av.patch
    +++ b/frameworks_av.patch
    @@ -531,10 +531,10 @@ index 6132a2c..7f0d270 100644
      
      void OMXMaster::addPlugin(const char *libname) {
     diff --git a/media/libstagefright/omx/OMXNodeInstance.cpp b/media/libstagefright/omx/OMXNodeInstance.cpp
    -index 43a50ae..2fa9989 100644
    +index c3514b3..8c26f94 100644
     --- a/media/libstagefright/omx/OMXNodeInstance.cpp
     +++ b/media/libstagefright/omx/OMXNodeInstance.cpp
    -@@ -795,7 +795,11 @@ status_t OMXNodeInstance::useBuffer(
    +@@ -801,7 +801,11 @@ status_t OMXNodeInstance::useBuffer(
          // metadata buffers are not connected cross process
          // use a backup buffer instead of the actual buffer
          BufferMeta *buffer_meta;
    @@ -546,7 +546,7 @@ index 43a50ae..2fa9989 100644
          OMX_U8 *data = static_cast<OMX_U8 *>(params->pointer());
          // allocate backup buffer
          if (useBackup) {
    -@@ -1279,7 +1283,11 @@ status_t OMXNodeInstance::allocateBufferWithBackup(
    +@@ -1297,7 +1301,11 @@ status_t OMXNodeInstance::allocateBufferWithBackup(
          }
      
          // metadata buffers are not connected cross process; only copy if not meta
    @@ -558,7 +558,7 @@ index 43a50ae..2fa9989 100644
      
          BufferMeta *buffer_meta = new BufferMeta(
                  params, portIndex,
    -@@ -1397,10 +1405,30 @@ status_t OMXNodeInstance::emptyBuffer(
    +@@ -1415,10 +1423,30 @@ status_t OMXNodeInstance::emptyBuffer(
          BufferMeta *buffer_meta =
              static_cast<BufferMeta *>(header->pAppPrivate);
      
    diff --git a/frameworks_base.patch b/frameworks_base.patch
    index 2968407..7d71827 100644
    --- a/frameworks_base.patch
    +++ b/frameworks_base.patch
    @@ -146,6 +146,21 @@ index 8c5df08..8c2c236 100644
                  //Slog.i(TAG, "Setting state in " + mName + "/" + mPackage + ": " + state);
                  commitStateTime(now);
                  mCurState = state;
    +diff --git a/core/java/com/android/internal/os/ZygoteInit.java b/core/java/com/android/internal/os/ZygoteInit.java
    +index e4f573b..0d3f50c 100644
    +--- a/core/java/com/android/internal/os/ZygoteInit.java
    ++++ b/core/java/com/android/internal/os/ZygoteInit.java
    +@@ -245,8 +245,8 @@ public class ZygoteInit {
    + 
    +     private static void preloadOpenGL() {
    +         String driverPackageName = SystemProperties.get(PROPERTY_GFX_DRIVER);
    +-        if (!SystemProperties.getBoolean(PROPERTY_DISABLE_OPENGL_PRELOADING, false) ||
    +-                driverPackageName == null || driverPackageName.isEmpty()) {
    ++        if (!SystemProperties.getBoolean(PROPERTY_DISABLE_OPENGL_PRELOADING, false) &&
    ++                (driverPackageName == null || driverPackageName.isEmpty())) {
    +             EGL14.eglGetDisplay(EGL14.EGL_DEFAULT_DISPLAY);
    +         }
    +     }
     diff --git a/core/res/res/xml/config_webview_packages.xml b/core/res/res/xml/config_webview_packages.xml
     index f062b59..574f7c1 100644
     --- a/core/res/res/xml/config_webview_packages.xml
    @@ -612,6 +627,65 @@ index b6a9940..11b5832a 100644
      
          /**
           * Whether verification is enabled by default.
    +diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java
    +index 889c52a..11585b4 100644
    +--- a/services/core/java/com/android/server/policy/PhoneWindowManager.java
    ++++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java
    +@@ -491,6 +491,9 @@ public class PhoneWindowManager implements WindowManagerPolicy {
    +     boolean mTranslucentDecorEnabled = true;
    +     boolean mUseTvRouting;
    + 
    ++    // Behavior of home wake
    ++    boolean mHomeWakeScreen;
    ++
    +     int mPointerLocationMode = 0; // guarded by mLock
    + 
    +     // The last window we were told about in focusChanged.
    +@@ -877,6 +880,10 @@ public class PhoneWindowManager implements WindowManagerPolicy {
    +             resolver.registerContentObserver(Settings.Global.getUriFor(
    +                     Settings.Global.POLICY_CONTROL), false, this,
    +                     UserHandle.USER_ALL);
    ++            resolver.registerContentObserver(Settings.System.getUriFor(
    ++                    Settings.System.HOME_WAKE_SCREEN), false, this,
    ++                    UserHandle.USER_ALL);
    ++
    +             updateSettings();
    +         }
    + 
    +@@ -2067,6 +2074,8 @@ public class PhoneWindowManager implements WindowManagerPolicy {
    +                     Settings.Secure.INCALL_BACK_BUTTON_BEHAVIOR,
    +                     Settings.Secure.INCALL_BACK_BUTTON_BEHAVIOR_DEFAULT,
    +                     UserHandle.USER_CURRENT);
    ++            mHomeWakeScreen = (Settings.System.getIntForUser(resolver,
    ++                    Settings.System.HOME_WAKE_SCREEN, 1, UserHandle.USER_CURRENT) == 1);
    + 
    +             // Configure wake gesture.
    +             boolean wakeGestureEnabledSetting = Settings.Secure.getIntForUser(resolver,
    +@@ -3881,8 +3890,9 @@ public class PhoneWindowManager implements WindowManagerPolicy {
    +                 awakenDreams();
    +             }
    +             hideRecentApps(false, true);
    +-        } else {
    +-            // Otherwise, just launch Home
    ++        } else if (mScreenOnFully) {
    ++            // check if screen is fully on before going home
    ++            // to avoid hardware home button wake going home
    +             sendCloseSystemWindows(SYSTEM_DIALOG_REASON_HOME_KEY);
    +             startDockOrHome(true /*fromHomeKey*/, awakenFromDreams);
    +         }
    +@@ -5884,6 +5894,12 @@ public class PhoneWindowManager implements WindowManagerPolicy {
    +                 break;
    +             }
    + 
    ++            case KeyEvent.KEYCODE_HOME:
    ++                if (down && !interactive && mHomeWakeScreen) {
    ++                    isWakeKey = true;
    ++                }
    ++                break;
    ++
    +             case KeyEvent.KEYCODE_ENDCALL: {
    +                 result &= ~ACTION_PASS_TO_USER;
    +                 if (down) {
     diff --git a/services/net/java/android/net/dhcp/DhcpClient.java b/services/net/java/android/net/dhcp/DhcpClient.java
     index ffbea9f..8dd05b1 100644
     --- a/services/net/java/android/net/dhcp/DhcpClient.java
    diff --git a/frameworks_native.patch b/frameworks_native.patch
    index 43cd0f0..21604d2 100644
    --- a/frameworks_native.patch
    +++ b/frameworks_native.patch
    @@ -303,10 +303,10 @@ index f0b0ada..3577a33 100644
                  return NO_ERROR;
              }
     diff --git a/libs/gui/Surface.cpp b/libs/gui/Surface.cpp
    -index 0838290..0bb142b 100644
    +index 5a2ca8d..16ccbc3 100644
     --- a/libs/gui/Surface.cpp
     +++ b/libs/gui/Surface.cpp
    -@@ -1260,6 +1260,7 @@ status_t Surface::lock(
    +@@ -1266,6 +1266,7 @@ status_t Surface::lock(
              }
      
              // figure out if we can copy the frontbuffer back
    @@ -314,7 +314,7 @@ index 0838290..0bb142b 100644
              const sp<GraphicBuffer>& frontBuffer(mPostedBuffer);
              const bool canCopyBack = (frontBuffer != 0 &&
                      backBuffer->width  == frontBuffer->width &&
    -@@ -1267,15 +1268,23 @@ status_t Surface::lock(
    +@@ -1273,15 +1274,23 @@ status_t Surface::lock(
                      backBuffer->format == frontBuffer->format);
      
              if (canCopyBack) {
    @@ -341,7 +341,7 @@ index 0838290..0bb142b 100644
                  Mutex::Autolock lock(mMutex);
                  for (size_t i=0 ; i<NUM_BUFFER_SLOTS ; i++) {
                      mSlots[i].dirtyRegion.clear();
    -@@ -1285,15 +1294,9 @@ status_t Surface::lock(
    +@@ -1291,15 +1300,9 @@ status_t Surface::lock(
      
              { // scope for the lock
                  Mutex::Autolock lock(mMutex);
    
    From 4a8ab497371397d3926eb64b048eb5e272f4f952 Mon Sep 17 00:00:00 2001
    From: AndDiSa <anddisa@googlemail.com>
    Date: Sat, 8 Jul 2017 10:58:52 +0200
    Subject: [PATCH 081/159] update patches
    
    Change-Id: I05639670f24553c71347933ec0ce9b6fbdfc9ce7
    ---
     hardware_broadcom_wlan.patch | 63 ++++++++++++++++++++++++++++++++++++
     1 file changed, 63 insertions(+)
     create mode 100644 hardware_broadcom_wlan.patch
    
    diff --git a/hardware_broadcom_wlan.patch b/hardware_broadcom_wlan.patch
    new file mode 100644
    index 0000000..d9fce91
    --- /dev/null
    +++ b/hardware_broadcom_wlan.patch
    @@ -0,0 +1,63 @@
    +diff --git a/bcmdhd/wifi_hal/gscan.cpp b/bcmdhd/wifi_hal/gscan.cpp
    +index 07155e2..73bfe8c 100644
    +--- a/bcmdhd/wifi_hal/gscan.cpp
    ++++ b/bcmdhd/wifi_hal/gscan.cpp
    +@@ -1436,30 +1436,38 @@ public:
    +         if (result < 0) {
    +             return result;
    +         }
    +-
    +-        struct nlattr * attr = request.attr_start(GSCAN_ATTRIBUTE_SIGNIFICANT_CHANGE_BSSIDS);
    +-
    +-        for (int i = 0; i < mParams.num_bssid; i++) {
    +-            nlattr *attr2 = request.attr_start(i);
    +-            if (attr2 == NULL) {
    ++        result = request.put_u16(GSCAN_ATTRIBUTE_NUM_BSSID, mParams.num_bssid);
    ++        if (result < 0) {
    ++            return result;
    ++        }
    ++        if (mParams.num_bssid != 0) {
    ++            nlattr* attr = request.attr_start(GSCAN_ATTRIBUTE_SIGNIFICANT_CHANGE_BSSIDS);
    ++            if (attr == NULL) {
    +                 return WIFI_ERROR_OUT_OF_MEMORY;
    +             }
    +-            result = request.put_addr(GSCAN_ATTRIBUTE_BSSID, mParams.ap[i].bssid);
    +-            if (result < 0) {
    +-                return result;
    +-            }
    +-            result = request.put_u8(GSCAN_ATTRIBUTE_RSSI_HIGH, mParams.ap[i].high);
    +-            if (result < 0) {
    +-                return result;
    +-            }
    +-            result = request.put_u8(GSCAN_ATTRIBUTE_RSSI_LOW, mParams.ap[i].low);
    +-            if (result < 0) {
    +-                return result;
    ++
    ++            for (int i = 0; i < mParams.num_bssid; i++) {
    ++                nlattr* attr2 = request.attr_start(i);
    ++                if (attr2 == NULL) {
    ++                    return WIFI_ERROR_OUT_OF_MEMORY;
    ++                }
    ++                result = request.put_addr(GSCAN_ATTRIBUTE_BSSID, mParams.ap[i].bssid);
    ++                if (result < 0) {
    ++                    return result;
    ++                }
    ++                result = request.put_u8(GSCAN_ATTRIBUTE_RSSI_HIGH, mParams.ap[i].high);
    ++                if (result < 0) {
    ++                    return result;
    ++                }
    ++                result = request.put_u8(GSCAN_ATTRIBUTE_RSSI_LOW, mParams.ap[i].low);
    ++                if (result < 0) {
    ++                    return result;
    ++                }
    ++                request.attr_end(attr2);
    +             }
    +-            request.attr_end(attr2);
    +-        }
    + 
    +-        request.attr_end(attr);
    ++            request.attr_end(attr);
    ++        }
    +         request.attr_end(data);
    + 
    +         return result;
    
    From 9766baf9e4706b4c3a8b8ffcb03abe97eb05e1ab Mon Sep 17 00:00:00 2001
    From: AndDiSa <anddisa@googlemail.com>
    Date: Fri, 11 Aug 2017 11:02:37 +0200
    Subject: [PATCH 082/159] update patches
    
    Change-Id: Ib019dd6d6221379526f9f5717e6ee85f5691acbd
    ---
     bionic.patch                 | 594 +++++++++++++++++++++++++++--------
     default.xml                  |   2 +-
     frameworks_av.patch          |   6 +-
     hardware_broadcom_wlan.patch |  63 ----
     system_sepolicy.patch        |  24 +-
     5 files changed, 477 insertions(+), 212 deletions(-)
    
    diff --git a/bionic.patch b/bionic.patch
    index cac729b..bc655ad 100644
    --- a/bionic.patch
    +++ b/bionic.patch
    @@ -22,165 +22,486 @@ index 76f465e..21b6152 100644
      # Inherently architecture-specific code.
     diff --git a/libc/arch-arm/generic/bionic/memchr.S b/libc/arch-arm/generic/bionic/memchr.S
     new file mode 100644
    -index 0000000..cb00d82
    +index 0000000..490cdb7
     --- /dev/null
     +++ b/libc/arch-arm/generic/bionic/memchr.S
    -@@ -0,0 +1,155 @@
    -+/* Copyright (c) 2010-2015, Linaro Limited
    +@@ -0,0 +1,200 @@
    ++/* Copyright (c) 2015 ARM Ltd.
     +   All rights reserved.
     +
     +   Redistribution and use in source and binary forms, with or without
    -+   modification, are permitted provided that the following conditions
    -+   are met:
    ++   modification, are permitted provided that the following conditions are met:
    ++       * Redistributions of source code must retain the above copyright
    ++	 notice, this list of conditions and the following disclaimer.
    ++       * Redistributions in binary form must reproduce the above copyright
    ++	 notice, this list of conditions and the following disclaimer in the
    ++	 documentation and/or other materials provided with the distribution.
    ++       * Neither the name of the Linaro nor the
    ++	 names of its contributors may be used to endorse or promote products
    ++	 derived from this software without specific prior written permission.
     +
    -+      * Redistributions of source code must retain the above copyright
    -+      notice, this list of conditions and the following disclaimer.
    -+
    -+      * Redistributions in binary form must reproduce the above copyright
    -+      notice, this list of conditions and the following disclaimer in the
    -+      documentation and/or other materials provided with the distribution.
    -+
    -+      * Neither the name of Linaro Limited nor the names of its
    -+      contributors may be used to endorse or promote products derived
    -+      from this software without specific prior written permission.
    -+
    -+   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
    ++  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
     +   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
     +   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
    -+   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
    ++   A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT
     +   HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
     +   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
     +   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     +   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     +   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     +   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
    -+   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
    -+ */
    ++   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.  */
     +
    -+/*
    -+   Written by Dave Gilbert <david.gilbert@linaro.org>
    -+
    -+   This memchr routine is optimised on a Cortex-A9 and should work on
    -+   all ARMv7 processors.   It has a fast past for short sizes, and has
    -+   an optimised path for large data sets; the worst case is finding the
    -+   match early in a large data set.
    -+
    -+ */
     +
     +#include <private/bionic_asm.h>
     +
    -+@ 2011-02-07 david.gilbert@linaro.org
    -+@    Extracted from local git a5b438d861
    -+@ 2011-07-14 david.gilbert@linaro.org
    -+@    Import endianness fix from local git ea786f1b
    -+@ 2011-12-07 david.gilbert@linaro.org
    -+@    Removed unneeded cbz from align loop
    -+
     +	.syntax unified
     +	.arch armv7-a
    -+
    -+@ this lets us check a flag in a 00/ff byte easily in either endianness
    -+#ifdef __ARMEB__
    -+#define CHARTSTMASK(c) 1<<(31-(c*8))
    -+#else
    -+#define CHARTSTMASK(c) 1<<(c*8)
    -+#endif
    ++	.fpu neon
     +	.text
     +	.thumb
    -+
    -+@ ---------------------------------------------------------------------------
     +	.thumb_func
    -+ENTRY(memchr)
     +	.p2align 4,,15
    -+	@ r0 = start of memory to scan
    -+	@ r1 = character to look for
    -+	@ r2 = length
    -+	@ returns r0 = pointer to character or NULL if not found
    -+	and	r1,r1,#0xff	@ Don't think we can trust the caller to actually pass a char
    -+
    -+	cmp	r2,#16		@ If it's short don't bother with anything clever
    -+	blt	20f
    -+
    -+	tst	r0, #7		@ If it's already aligned skip the next bit
    -+	beq	10f
    -+
    -+	@ Work up to an aligned point
    -+5:
    -+	ldrb	r3, [r0],#1
    -+	subs	r2, r2, #1
    -+	cmp	r3, r1
    -+	beq	50f		@ If it matches exit found
    -+	tst	r0, #7
    -+	bne	5b		@ If not aligned yet then do next byte
    -+
    -+10:
    -+	@ At this point, we are aligned, we know we have at least 8 bytes to work with
    -+	push	{r4,r5,r6,r7}
    -+	orr	r1, r1, r1, lsl #8	@ expand the match word across to all bytes
    -+	orr	r1, r1, r1, lsl #16
    -+	bic	r4, r2, #7	@ Number of double words to work with
    -+	mvns	r7, #0		@ all F's
    -+	movs	r3, #0
    -+
    -+15:
    -+	ldrd    r5,r6,[r0],#8
    -+	subs	r4, r4, #8
    -+	eor	r5,r5, r1	@ Get it so that r5,r6 have 00's where the bytes match the target
    -+	eor	r6,r6, r1
    -+	uadd8	r5, r5, r7	@ Parallel add 0xff - sets the GE bits for anything that wasn't 0
    -+	sel	r5, r3, r7	@ bytes are 00 for none-00 bytes, or ff for 00 bytes - NOTE INVERSION
    -+	uadd8	r6, r6, r7	@ Parallel add 0xff - sets the GE bits for anything that wasn't 0
    -+	sel	r6, r5, r7	@ chained....bytes are 00 for none-00 bytes, or ff for 00 bytes - NOTE INVERSION
    -+	cbnz	r6, 60f
    -+	bne	15b		@ (Flags from the subs above) If not run out of bytes then go around again
    -+
    -+	pop	{r4,r5,r6,r7}
    -+	and	r1,r1,#0xff	@ Get r1 back to a single character from the expansion above
    -+	and	r2,r2,#7	@ Leave the count remaining as the number after the double words have been done
    -+
    -+20:
    -+	cbz	r2, 40f		@ 0 length or hit the end already then not found
    -+
    -+21:  @ Post aligned section, or just a short call
    -+	ldrb	r3,[r0],#1
    -+	subs	r2,r2,#1
    -+	eor	r3,r3,r1	@ r3 = 0 if match - doesn't break flags from sub
    -+	cbz	r3, 50f
    -+	bne	21b		@ on r2 flags
    -+
    -+40:
    -+	movs	r0,#0		@ not found
    ++	.align 4
    ++
    ++/* Arguments */
    ++#define srcin           r0
    ++#define chrin           r1
    ++#define cntin           r2
    ++
    ++/* Retval */
    ++#define result          r0      /* Live range does not overlap with srcin */
    ++
    ++/* Working registers */
    ++#define src             r1      /* Live range does not overlap with chrin */
    ++#define tmp             r3
    ++#define synd            r0      /* No overlap with srcin or result */
    ++#define soff            r12
    ++
    ++/* Working NEON registers */
    ++#define vrepchr         q0
    ++#define vdata0          q1
    ++#define vdata0_0        d2      /* Lower half of vdata0 */
    ++#define vdata0_1        d3      /* Upper half of vdata0 */
    ++#define vdata1          q2
    ++#define vdata1_0        d4      /* Lower half of vhas_chr0 */
    ++#define vdata1_1        d5      /* Upper half of vhas_chr0 */
    ++#define vrepmask        q3
    ++#define vrepmask0       d6
    ++#define vrepmask1       d7
    ++#define vend            q4
    ++#define vend0           d8
    ++#define vend1           d9
    ++
    ++/*
    ++ * Core algorithm:
    ++ *
    ++ * For each 32-byte chunk we calculate a 32-bit syndrome value, with one bit per
    ++ * byte. Each bit is set if the relevant byte matched the requested character
    ++ * and cleared otherwise. Since the bits in the syndrome reflect exactly the
    ++ * order in which things occur in the original string, counting trailing zeros
    ++ * allows to identify exactly which byte has matched.
    ++ */
    ++
    ++ENTRY(memchr)
    ++	.cfi_sections .debug_frame
    ++	/* Use a simple loop if there are less than 8 bytes to search.  */
    ++	cmp	cntin, #7
    ++	bhi	.Llargestr
    ++
    ++.Lsmallstr:
    ++	subs	cntin, cntin, #1
    ++	blt	.Lnotfound	/* Return not found if reached end.  */
    ++	ldrb	tmp, [srcin], #1
    ++	cmp	tmp, chrin
    ++	bne	.Lsmallstr	/* Loop again if not found.  */
    ++	/* Otherwise fixup address and return.  */
    ++	sub	result, result, #1
     +	bx	lr
     +
    -+50:
    -+	subs	r0,r0,#1	@ found
    ++.Llargestr:
    ++	vdup.8	vrepchr, chrin	/* Duplicate char across all lanes. */
    ++	/*
    ++	 * Magic constant 0x8040201008040201 allows us to identify which lane
    ++	 * matches the requested byte.
    ++	 */
    ++	movw	tmp, #0x0201
    ++	movt	tmp, #0x0804
    ++	lsl	soff, tmp, #4
    ++	vmov	vrepmask0, tmp, soff
    ++	vmov	vrepmask1, tmp, soff
    ++	/* Work with aligned 32-byte chunks */
    ++	bic	src, srcin, #31
    ++	ands	soff, srcin, #31
    ++	beq	.Lloopintro	/* Go straight to main loop if it's aligned. */
    ++
    ++	/*
    ++	 * Input string is not 32-byte aligned. We calculate the syndrome
    ++	 * value for the aligned 32 bytes block containing the first bytes
    ++	 * and mask the irrelevant part.
    ++	 */
    ++	vld1.8		{vdata0, vdata1}, [src:256]!
    ++	sub		tmp, soff, #32
    ++	adds		cntin, cntin, tmp
    ++	vceq.i8		vdata0, vdata0, vrepchr
    ++	vceq.i8		vdata1, vdata1, vrepchr
    ++	vand		vdata0, vdata0, vrepmask
    ++	vand		vdata1, vdata1, vrepmask
    ++	vpadd.i8	vdata0_0, vdata0_0, vdata0_1
    ++	vpadd.i8	vdata1_0, vdata1_0, vdata1_1
    ++	vpadd.i8	vdata0_0, vdata0_0, vdata1_0
    ++	vpadd.i8	vdata0_0, vdata0_0, vdata0_0
    ++	vmov.32		synd, vdata0_0[0]
    ++
    ++	/* Clear the soff lower bits */
    ++	lsr		synd, synd, soff
    ++	lsl		synd, synd, soff
    ++	/* The first block can also be the last */
    ++	bls		.Lmasklast
    ++	/* Have we found something already? */
    ++	cbnz		synd, .Ltail
    ++
    ++.Lloopintro:
    ++	vpush	{vend}
    ++	/* 264/265 correspond to d8/d9 for q4 */
    ++	.cfi_adjust_cfa_offset	16
    ++	.cfi_rel_offset	264, 0
    ++	.cfi_rel_offset	265, 8
    ++	.p2align 3,,7
    ++
    ++.Lloop:
    ++	vld1.8		{vdata0, vdata1}, [src:256]!
    ++	subs		cntin, cntin, #32
    ++	vceq.i8		vdata0, vdata0, vrepchr
    ++	vceq.i8		vdata1, vdata1, vrepchr
    ++	/* If we're out of data we finish regardless of the result. */
    ++	bls		.Lend
    ++	/* Use a fast check for the termination condition. */
    ++	vorr		vend, vdata0, vdata1
    ++	vorr		vend0, vend0, vend1
    ++	vmov		synd, tmp, vend0
    ++	orrs		synd, synd, tmp
    ++	/* We're not out of data, loop if we haven't found the character. */
    ++	beq		.Lloop
    ++
    ++.Lend:
    ++	vpop		{vend}
    ++	.cfi_adjust_cfa_offset	-16
    ++	.cfi_restore	264
    ++	.cfi_restore	265
    ++
    ++	/* Termination condition found, let's calculate the syndrome value. */
    ++	vand		vdata0, vdata0, vrepmask
    ++	vand		vdata1, vdata1, vrepmask
    ++	vpadd.i8	vdata0_0, vdata0_0, vdata0_1
    ++	vpadd.i8	vdata1_0, vdata1_0, vdata1_1
    ++	vpadd.i8	vdata0_0, vdata0_0, vdata1_0
    ++	vpadd.i8	vdata0_0, vdata0_0, vdata0_0
    ++	vmov.32		synd, vdata0_0[0]
    ++	cbz		synd, .Lnotfound
    ++	bhi		.Ltail
    ++
    ++.Lmasklast:
    ++	/* Clear the (-cntin) upper bits to avoid out-of-bounds matches. */
    ++	neg	cntin, cntin
    ++	lsl	synd, synd, cntin
    ++	lsrs	synd, synd, cntin
    ++	it	eq
    ++	moveq	src, #0	/* If no match, set src to 0 so the retval is 0. */
    ++
    ++.Ltail:
    ++	/* Count the trailing zeros using bit reversing */
    ++	rbit	synd, synd
    ++	/* Compensate the last post-increment */
    ++	sub	src, src, #32
    ++	/* Count the leading zeros */
    ++	clz	synd, synd
    ++	/* Compute the potential result and return */
    ++	add	result, src, synd
     +	bx	lr
     +
    -+60:  @ We're here because the fast path found a hit - now we have to track down exactly which word it was
    -+	@ r0 points to the start of the double word after the one that was tested
    -+	@ r5 has the 00/ff pattern for the first word, r6 has the chained value
    -+	cmp	r5, #0
    -+	itte	eq
    -+	moveq	r5, r6		@ the end is in the 2nd word
    -+	subeq	r0,r0,#3	@ Points to 2nd byte of 2nd word
    -+	subne	r0,r0,#7	@ or 2nd byte of 1st word
    -+
    -+	@ r0 currently points to the 3rd byte of the word containing the hit
    -+	tst	r5, # CHARTSTMASK(0)	@ 1st character
    -+	bne	61f
    -+	adds	r0,r0,#1
    -+	tst	r5, # CHARTSTMASK(1)	@ 2nd character
    -+	ittt	eq
    -+	addeq	r0,r0,#1
    -+	tsteq	r5, # (3<<15)		@ 2nd & 3rd character
    -+	@ If not the 3rd must be the last one
    -+	addeq	r0,r0,#1
    -+
    -+61:
    -+	pop	{r4,r5,r6,r7}
    -+	subs	r0,r0,#1
    ++.Lnotfound:
    ++	/* Set result to NULL if not found and return */
    ++	mov	result, #0
     +	bx	lr
    ++
     +END(memchr)
    +diff --git a/libc/arch-arm/include/machine/cpu-features.h b/libc/arch-arm/include/machine/cpu-features.h
    +index fc8c80d..8e7f950 100644
    +--- a/libc/arch-arm/include/machine/cpu-features.h
    ++++ b/libc/arch-arm/include/machine/cpu-features.h
    +@@ -33,7 +33,9 @@
    +  * so try to guess it.
    +  */
    + #ifndef __ARM_ARCH__
    +-#  if defined __ARM_ARCH_7__   || defined __ARM_ARCH_7A__ || \
    ++#  if defined __ARM_ARCH_8__ || defined __ARM_ARCH_8A__
    ++#    define __ARM_ARCH__ 8
    ++#  elif defined __ARM_ARCH_7__   || defined __ARM_ARCH_7A__ || \
    +         defined __ARM_ARCH_7R__  || defined __ARM_ARCH_7M__
    + #    define __ARM_ARCH__ 7
    + #  elif defined __ARM_ARCH_6__   || defined __ARM_ARCH_6J__ || \
    +diff --git a/libc/bionic/jemalloc.h b/libc/bionic/jemalloc.h
    +index fceb323..f7e8770 100644
    +--- a/libc/bionic/jemalloc.h
    ++++ b/libc/bionic/jemalloc.h
    +@@ -26,6 +26,7 @@
    + __BEGIN_DECLS
    + 
    + struct mallinfo je_mallinfo();
    ++int je_mallopt(int, int);
    + int je_iterate(uintptr_t, size_t, void (*)(uintptr_t, size_t, void*), void*);
    + void je_malloc_disable();
    + void je_malloc_enable();
    +diff --git a/libc/bionic/jemalloc_wrapper.cpp b/libc/bionic/jemalloc_wrapper.cpp
    +index e33d560..266b966 100644
    +--- a/libc/bionic/jemalloc_wrapper.cpp
    ++++ b/libc/bionic/jemalloc_wrapper.cpp
    +@@ -14,6 +14,7 @@
    +  * limitations under the License.
    +  */
    + 
    ++#include <malloc.h>
    + #include <sys/param.h>
    + #include <unistd.h>
    + 
    +@@ -46,3 +47,38 @@ void* je_memalign_round_up_boundary(size_t boundary, size_t size) {
    +   }
    +   return je_memalign(boundary, size);
    + }
    ++
    ++int je_mallopt(int param, int value) {
    ++  // The only parameter we currently understand is M_DECAY_TIME.
    ++  if (param == M_DECAY_TIME) {
    ++    // Only support setting the value to 1 or 0.
    ++    ssize_t decay_time;
    ++    if (value) {
    ++      decay_time = 1;
    ++    } else {
    ++      decay_time = 0;
    ++    }
    ++    // First get the total number of arenas.
    ++    unsigned narenas;
    ++    size_t sz = sizeof(unsigned);
    ++    if (je_mallctl("arenas.narenas", &narenas, &sz, nullptr, 0) != 0) {
    ++      return 0;
    ++    }
    ++
    ++    // Set the decay time for any arenas that will be created in the future.
    ++    if (je_mallctl("arenas.decay_time", nullptr, nullptr, &decay_time, sizeof(decay_time)) != 0) {
    ++      return 0;
    ++    }
    ++
    ++    // Change the decay on the already existing arenas.
    ++    char buffer[100];
    ++    for (unsigned i = 0; i < narenas; i++) {
    ++      snprintf(buffer, sizeof(buffer), "arena.%d.decay_time", i);
    ++      if (je_mallctl(buffer, nullptr, nullptr, &decay_time, sizeof(decay_time)) != 0) {
    ++        break;
    ++      }
    ++    }
    ++    return 1;
    ++  }
    ++  return 0;
    ++}
    +diff --git a/libc/bionic/malloc_common.cpp b/libc/bionic/malloc_common.cpp
    +index e050619..8053535 100644
    +--- a/libc/bionic/malloc_common.cpp
    ++++ b/libc/bionic/malloc_common.cpp
    +@@ -68,6 +68,7 @@ static constexpr MallocDispatch __libc_malloc_default_dispatch
    +     Malloc(iterate),
    +     Malloc(malloc_disable),
    +     Malloc(malloc_enable),
    ++    Malloc(mallopt),
    +   };
    + 
    + // In a VM process, this is set to 1 after fork()ing out of zygote.
    +@@ -101,6 +102,14 @@ extern "C" struct mallinfo mallinfo() {
    +   return Malloc(mallinfo)();
    + }
    + 
    ++extern "C" int mallopt(int param, int value) {
    ++  auto _mallopt = __libc_globals->malloc_dispatch.mallopt;
    ++  if (__predict_false(_mallopt != nullptr)) {
    ++    return _mallopt(param, value);
    ++  }
    ++  return Malloc(mallopt)(param, value);
    ++}
    ++
    + extern "C" void* malloc(size_t bytes) {
    +   auto _malloc = __libc_globals->malloc_dispatch.malloc;
    +   if (__predict_false(_malloc != nullptr)) {
    +@@ -248,6 +257,10 @@ static bool InitMalloc(void* malloc_impl_handler, MallocDispatch* table, const c
    +                                           prefix, "mallinfo")) {
    +     return false;
    +   }
    ++  if (!InitMallocFunction<MallocMallopt>(malloc_impl_handler, &table->mallopt,
    ++                                         prefix, "mallopt")) {
    ++    return false;
    ++  }
    +   if (!InitMallocFunction<MallocMalloc>(malloc_impl_handler, &table->malloc,
    +                                         prefix, "malloc")) {
    +     return false;
    +diff --git a/libc/include/malloc.h b/libc/include/malloc.h
    +index 87555a9..f0cdf82 100644
    +--- a/libc/include/malloc.h
    ++++ b/libc/include/malloc.h
    +@@ -70,6 +70,11 @@ extern struct mallinfo mallinfo(void);
    +  */
    + extern int malloc_info(int, FILE *);
    + 
    ++/* mallopt options */
    ++#define M_DECAY_TIME -100
    ++
    ++int mallopt(int, int) __INTRODUCED_IN(26);
    ++
    + __END_DECLS
    + 
    + #endif  /* LIBC_INCLUDE_MALLOC_H_ */
    +diff --git a/libc/libc.arm.map b/libc/libc.arm.map
    +index 38f8437..52698b6 100644
    +--- a/libc/libc.arm.map
    ++++ b/libc/libc.arm.map
    +@@ -1494,4 +1494,5 @@ LIBC_PLATFORM {
    +     malloc_disable;
    +     malloc_enable;
    +     malloc_iterate;
    ++    mallopt;
    + } LIBC_N;
    +diff --git a/libc/libc.arm64.map b/libc/libc.arm64.map
    +index afbd0ee..db7368d 100644
    +--- a/libc/libc.arm64.map
    ++++ b/libc/libc.arm64.map
    +@@ -1209,4 +1209,5 @@ LIBC_PLATFORM {
    +     malloc_disable;
    +     malloc_enable;
    +     malloc_iterate;
    ++    mallopt;
    + } LIBC_N;
    +diff --git a/libc/libc.mips.map b/libc/libc.mips.map
    +index 46c835b..2e272f5 100644
    +--- a/libc/libc.mips.map
    ++++ b/libc/libc.mips.map
    +@@ -1335,4 +1335,5 @@ LIBC_PLATFORM {
    +     malloc_disable;
    +     malloc_enable;
    +     malloc_iterate;
    ++    mallopt;
    + } LIBC_N;
    +diff --git a/libc/libc.mips64.map b/libc/libc.mips64.map
    +index afbd0ee..db7368d 100644
    +--- a/libc/libc.mips64.map
    ++++ b/libc/libc.mips64.map
    +@@ -1209,4 +1209,5 @@ LIBC_PLATFORM {
    +     malloc_disable;
    +     malloc_enable;
    +     malloc_iterate;
    ++    mallopt;
    + } LIBC_N;
    +diff --git a/libc/libc.x86.map b/libc/libc.x86.map
    +index 9417d56..6598e3d 100644
    +--- a/libc/libc.x86.map
    ++++ b/libc/libc.x86.map
    +@@ -1334,4 +1334,5 @@ LIBC_PLATFORM {
    +     malloc_disable;
    +     malloc_enable;
    +     malloc_iterate;
    ++    mallopt;
    + } LIBC_N;
    +diff --git a/libc/libc.x86_64.map b/libc/libc.x86_64.map
    +index afbd0ee..db7368d 100644
    +--- a/libc/libc.x86_64.map
    ++++ b/libc/libc.x86_64.map
    +@@ -1209,4 +1209,5 @@ LIBC_PLATFORM {
    +     malloc_disable;
    +     malloc_enable;
    +     malloc_iterate;
    ++    mallopt;
    + } LIBC_N;
    +diff --git a/libc/malloc_debug/malloc_debug.cpp b/libc/malloc_debug/malloc_debug.cpp
    +index 1ee7689..329e725 100644
    +--- a/libc/malloc_debug/malloc_debug.cpp
    ++++ b/libc/malloc_debug/malloc_debug.cpp
    +@@ -76,6 +76,7 @@ void* debug_memalign(size_t alignment, size_t bytes);
    + void* debug_realloc(void* pointer, size_t bytes);
    + void* debug_calloc(size_t nmemb, size_t bytes);
    + struct mallinfo debug_mallinfo();
    ++int debug_mallopt(int param, int value);
    + int debug_posix_memalign(void** memptr, size_t alignment, size_t size);
    + int debug_iterate(uintptr_t base, size_t size,
    +     void (*callback)(uintptr_t base, size_t size, void* arg), void* arg);
    +@@ -584,6 +585,10 @@ struct mallinfo debug_mallinfo() {
    +   return g_dispatch->mallinfo();
    + }
    + 
    ++int debug_mallopt(int param, int value) {
    ++  return g_dispatch->mallopt(param, value);
    ++}
    ++
    + int debug_posix_memalign(void** memptr, size_t alignment, size_t size) {
    +   if (DebugCallsDisabled()) {
    +     return g_dispatch->posix_memalign(memptr, alignment, size);
    +diff --git a/libc/malloc_debug/tests/malloc_debug_unit_tests.cpp b/libc/malloc_debug/tests/malloc_debug_unit_tests.cpp
    +index 014b913..8014f06 100644
    +--- a/libc/malloc_debug/tests/malloc_debug_unit_tests.cpp
    ++++ b/libc/malloc_debug/tests/malloc_debug_unit_tests.cpp
    +@@ -58,6 +58,7 @@ void debug_get_malloc_leak_info(uint8_t**, size_t*, size_t*, size_t*, size_t*);
    + void debug_free_malloc_leak_info(uint8_t*);
    + 
    + struct mallinfo debug_mallinfo();
    ++int debug_mallopt(int, int);
    + 
    + #if defined(HAVE_DEPRECATED_MALLOC_FUNCS)
    + void* debug_pvalloc(size_t);
    +@@ -125,6 +126,7 @@ MallocDispatch MallocDebugTest::dispatch = {
    +   nullptr,
    +   nullptr,
    +   nullptr,
    ++  mallopt,
    + };
    + 
    + void VerifyAllocCalls() {
    +@@ -1471,6 +1473,20 @@ TEST_F(MallocDebugTest, debug_mallinfo) {
    +   ASSERT_STREQ("", getFakeLogPrint().c_str());
    + }
    + 
    ++TEST_F(MallocDebugTest, debug_mallopt) {
    ++  Init("guard");
    ++
    ++  void* pointer = debug_malloc(150);
    ++  ASSERT_TRUE(pointer != nullptr);
    ++
    ++  EXPECT_EQ(0, debug_mallopt(-1000, 1));
    ++
    ++  debug_free(pointer);
    ++
    ++  ASSERT_STREQ("", getFakeLogBuf().c_str());
    ++  ASSERT_STREQ("", getFakeLogPrint().c_str());
    ++}
    ++
    + TEST_F(MallocDebugTest, debug_posix_memalign) {
    +   Init("guard");
    + 
    +diff --git a/libc/private/bionic_malloc_dispatch.h b/libc/private/bionic_malloc_dispatch.h
    +index 02a092f..cdae466 100644
    +--- a/libc/private/bionic_malloc_dispatch.h
    ++++ b/libc/private/bionic_malloc_dispatch.h
    +@@ -45,6 +45,7 @@ typedef void* (*MallocRealloc)(void*, size_t);
    + typedef int (*MallocIterate)(uintptr_t, size_t, void (*)(uintptr_t, size_t, void*), void*);
    + typedef void (*MallocMallocDisable)();
    + typedef void (*MallocMallocEnable)();
    ++typedef int (*MallocMallopt)(int, int);
    + 
    + #if defined(HAVE_DEPRECATED_MALLOC_FUNCS)
    + typedef void* (*MallocPvalloc)(size_t);
    +@@ -69,6 +70,7 @@ struct MallocDispatch {
    +   MallocIterate iterate;
    +   MallocMallocDisable malloc_disable;
    +   MallocMallocEnable malloc_enable;
    ++  MallocMallopt mallopt;
    + } __attribute__((aligned(32)));
    + 
    + #endif
     diff --git a/linker/Android.mk b/linker/Android.mk
     index 4a4ca5c..0d592c9 100644
     --- a/linker/Android.mk
    @@ -240,3 +561,18 @@ index a043b85..cd1874f 100644
          // Make segments writable to allow text relocations to work properly. We will later call
          // phdr_table_protect_segments() after all of them are applied.
          DL_WARN("%s has text relocations. This is wasting memory and prevents "
    +diff --git a/tests/malloc_test.cpp b/tests/malloc_test.cpp
    +index 8fba1c4..a7b9d52 100644
    +--- a/tests/malloc_test.cpp
    ++++ b/tests/malloc_test.cpp
    +@@ -500,3 +500,10 @@ TEST(malloc, verify_alignment) {
    +   delete[] values_64;
    +   delete[] values_ldouble;
    + }
    ++
    ++TEST(malloc, mallopt_smoke) {
    ++  errno = 0;
    ++  ASSERT_EQ(0, mallopt(-1000, 1));
    ++  // mallopt doesn't set errno.
    ++  ASSERT_EQ(0, errno);
    ++}
    diff --git a/default.xml b/default.xml
    index 47f4250..9963d4a 100644
    --- a/default.xml
    +++ b/default.xml
    @@ -9,7 +9,7 @@
                fetch="https://github.com/millosr/" />
       <remote  name="unlegacy"
                fetch="https://github.com/Unlegacy-Android/" />
    -  <default revision="refs/tags/android-7.1.2_r27"
    +  <default revision="refs/tags/android-7.1.2_r33"
                remote="aosp"
                sync-j="4" />
     
    diff --git a/frameworks_av.patch b/frameworks_av.patch
    index fdbb792..36a3471 100644
    --- a/frameworks_av.patch
    +++ b/frameworks_av.patch
    @@ -506,10 +506,10 @@ index e4fbd81..8fc788f 100644
      LOCAL_CFLAGS += -Werror -Wall
      LOCAL_CLANG := true
     diff --git a/media/libstagefright/omx/GraphicBufferSource.cpp b/media/libstagefright/omx/GraphicBufferSource.cpp
    -index 0c4056d..da77c48 100644
    +index e1bcd28..5f21eac 100644
     --- a/media/libstagefright/omx/GraphicBufferSource.cpp
     +++ b/media/libstagefright/omx/GraphicBufferSource.cpp
    -@@ -724,6 +724,8 @@ bool GraphicBufferSource::repeatLatestBuffer_l() {
    +@@ -736,6 +736,8 @@ bool GraphicBufferSource::repeatLatestBuffer_l() {
      
      void GraphicBufferSource::setLatestBuffer_l(
              const BufferItem &item, bool dropped) {
    @@ -531,7 +531,7 @@ index 6132a2c..7f0d270 100644
      
      void OMXMaster::addPlugin(const char *libname) {
     diff --git a/media/libstagefright/omx/OMXNodeInstance.cpp b/media/libstagefright/omx/OMXNodeInstance.cpp
    -index c3514b3..8c26f94 100644
    +index e7aaead..8752b4e 100644
     --- a/media/libstagefright/omx/OMXNodeInstance.cpp
     +++ b/media/libstagefright/omx/OMXNodeInstance.cpp
     @@ -801,7 +801,11 @@ status_t OMXNodeInstance::useBuffer(
    diff --git a/hardware_broadcom_wlan.patch b/hardware_broadcom_wlan.patch
    index d9fce91..e69de29 100644
    --- a/hardware_broadcom_wlan.patch
    +++ b/hardware_broadcom_wlan.patch
    @@ -1,63 +0,0 @@
    -diff --git a/bcmdhd/wifi_hal/gscan.cpp b/bcmdhd/wifi_hal/gscan.cpp
    -index 07155e2..73bfe8c 100644
    ---- a/bcmdhd/wifi_hal/gscan.cpp
    -+++ b/bcmdhd/wifi_hal/gscan.cpp
    -@@ -1436,30 +1436,38 @@ public:
    -         if (result < 0) {
    -             return result;
    -         }
    --
    --        struct nlattr * attr = request.attr_start(GSCAN_ATTRIBUTE_SIGNIFICANT_CHANGE_BSSIDS);
    --
    --        for (int i = 0; i < mParams.num_bssid; i++) {
    --            nlattr *attr2 = request.attr_start(i);
    --            if (attr2 == NULL) {
    -+        result = request.put_u16(GSCAN_ATTRIBUTE_NUM_BSSID, mParams.num_bssid);
    -+        if (result < 0) {
    -+            return result;
    -+        }
    -+        if (mParams.num_bssid != 0) {
    -+            nlattr* attr = request.attr_start(GSCAN_ATTRIBUTE_SIGNIFICANT_CHANGE_BSSIDS);
    -+            if (attr == NULL) {
    -                 return WIFI_ERROR_OUT_OF_MEMORY;
    -             }
    --            result = request.put_addr(GSCAN_ATTRIBUTE_BSSID, mParams.ap[i].bssid);
    --            if (result < 0) {
    --                return result;
    --            }
    --            result = request.put_u8(GSCAN_ATTRIBUTE_RSSI_HIGH, mParams.ap[i].high);
    --            if (result < 0) {
    --                return result;
    --            }
    --            result = request.put_u8(GSCAN_ATTRIBUTE_RSSI_LOW, mParams.ap[i].low);
    --            if (result < 0) {
    --                return result;
    -+
    -+            for (int i = 0; i < mParams.num_bssid; i++) {
    -+                nlattr* attr2 = request.attr_start(i);
    -+                if (attr2 == NULL) {
    -+                    return WIFI_ERROR_OUT_OF_MEMORY;
    -+                }
    -+                result = request.put_addr(GSCAN_ATTRIBUTE_BSSID, mParams.ap[i].bssid);
    -+                if (result < 0) {
    -+                    return result;
    -+                }
    -+                result = request.put_u8(GSCAN_ATTRIBUTE_RSSI_HIGH, mParams.ap[i].high);
    -+                if (result < 0) {
    -+                    return result;
    -+                }
    -+                result = request.put_u8(GSCAN_ATTRIBUTE_RSSI_LOW, mParams.ap[i].low);
    -+                if (result < 0) {
    -+                    return result;
    -+                }
    -+                request.attr_end(attr2);
    -             }
    --            request.attr_end(attr2);
    --        }
    - 
    --        request.attr_end(attr);
    -+            request.attr_end(attr);
    -+        }
    -         request.attr_end(data);
    - 
    -         return result;
    diff --git a/system_sepolicy.patch b/system_sepolicy.patch
    index 1d9a08e..c5fcbd7 100644
    --- a/system_sepolicy.patch
    +++ b/system_sepolicy.patch
    @@ -12,18 +12,10 @@ index e9dd7b3..ef2bd9d 100644
      
      # Block device access.
     diff --git a/domain.te b/domain.te
    -index 45569de..21c9df2 100644
    +index 45569de..5aee09e 100644
     --- a/domain.te
     +++ b/domain.te
    -@@ -159,6 +159,7 @@ neverallow {
    -   -dumpstate
    -   -system_server
    -   userdebug_or_eng(`-perfprofd')
    -+  userdebug_or_eng(`-procrank')
    - } self:capability sys_ptrace;
    - 
    - # Limit device node creation to these whitelisted domains.
    -@@ -267,6 +268,7 @@ neverallow { domain -init -ueventd } device:chr_file { open read write };
    +@@ -267,6 +267,7 @@ neverallow { domain -init -ueventd } device:chr_file { open read write };
      # this capability, including device-specific domains.
      neverallow { domain -kernel -init -recovery -vold -zygote -update_engine -otapreopt_chroot } { fs_type -sdcard_type }:filesystem { mount remount relabelfrom relabelto };
      
    @@ -31,7 +23,7 @@ index 45569de..21c9df2 100644
      #
      # Assert that, to the extent possible, we're not loading executable content from
      # outside the rootfs or /system partition except for a few whitelisted domains.
    -@@ -292,7 +294,9 @@ neverallow domain { cache_file cache_backup_file cache_private_backup_file cache
    +@@ -292,7 +293,9 @@ neverallow domain { cache_file cache_backup_file cache_private_backup_file cache
      # Protect most domains from executing arbitrary content from /data.
      neverallow {
        domain
    @@ -42,7 +34,7 @@ index 45569de..21c9df2 100644
      } {
        data_file_type
        -dalvikcache_data_file
    -@@ -379,6 +383,8 @@ neverallow {
    +@@ -379,6 +382,8 @@ neverallow {
        -cppreopts
        -dex2oat
        -otapreopt_slot
    @@ -51,7 +43,7 @@ index 45569de..21c9df2 100644
      } dalvikcache_data_file:file no_w_file_perms;
      
      neverallow {
    -@@ -390,6 +396,7 @@ neverallow {
    +@@ -390,6 +395,7 @@ neverallow {
        -dex2oat
        -zygote
        -otapreopt_slot
    @@ -59,7 +51,7 @@ index 45569de..21c9df2 100644
      } dalvikcache_data_file:dir no_w_dir_perms;
      
      # Only system_server should be able to send commands via the zygote socket
    -@@ -428,13 +435,13 @@ neverallow { domain userdebug_or_eng(`-dumpstate -shell -su') } su_exec:file no_
    +@@ -428,13 +434,13 @@ neverallow { domain userdebug_or_eng(`-dumpstate -shell -su') } su_exec:file no_
      # The only exceptions are for NDK text relocations associated with
      # https://code.google.com/p/android/issues/detail?id=23203
      # which, long term, need to go away.
    @@ -80,7 +72,7 @@ index 45569de..21c9df2 100644
      
      # Do not allow making the stack or heap executable.
      # We would also like to minimize execmem but it seems to be
    -@@ -443,7 +450,7 @@ neverallow * self:process { execstack execheap };
    +@@ -443,7 +449,7 @@ neverallow * self:process { execstack execheap };
      
      # prohibit non-zygote spawned processes from using shared libraries
      # with text relocations. b/20013628 .
    @@ -89,7 +81,7 @@ index 45569de..21c9df2 100644
      
      neverallow { domain -init } proc:{ file dir } mounton;
      
    -@@ -570,7 +577,7 @@ neverallow * domain:file { execute execute_no_trans entrypoint };
    +@@ -570,7 +576,7 @@ neverallow * domain:file { execute execute_no_trans entrypoint };
      # Instead, if access to part of debugfs is desired, it should have a
      # more specific label.
      # TODO: fix system_server and dumpstate
    
    From 8ff58efcf50c1174d4e8053401748a4cb0643320 Mon Sep 17 00:00:00 2001
    From: AndDiSa <anddisa@googlemail.com>
    Date: Fri, 22 Sep 2017 17:08:19 +0200
    Subject: [PATCH 083/159] Remove external/jhead and external/libgdx
    
    Change-Id: Id6afa495ab14d414e794f8810502924f3513d244
    ---
     default.xml | 2 --
     1 file changed, 2 deletions(-)
    
    diff --git a/default.xml b/default.xml
    index 9963d4a..6c1e78a 100644
    --- a/default.xml
    +++ b/default.xml
    @@ -150,7 +150,6 @@
       <project path="external/jdiff" name="platform/external/jdiff" groups="pdk-cw-fs,pdk-fs" />
       <project path="external/jemalloc" name="platform/external/jemalloc" groups="pdk" />
       <project path="external/jetty" name="platform/external/jetty" groups="pdk-fs" />
    -  <project path="external/jhead" name="platform/external/jhead" groups="pdk" />
       <project path="external/jline" name="platform/external/jline" groups="notdefault,tradefed" />
       <project path="external/jmdns" name="platform/external/jmdns" groups="pdk-cw-fs,pdk-fs" />
       <project path="external/jsilver" name="platform/external/jsilver" groups="pdk-cw-fs,pdk-fs" />
    @@ -174,7 +173,6 @@
       <project path="external/libdaemon" name="platform/external/libdaemon" />
       <project path="external/libevent" name="platform/external/libevent" />
       <project path="external/libexif" name="platform/external/libexif" groups="pdk-cw-fs,pdk-fs" />
    -  <project path="external/libgdx" name="platform/external/libgdx" groups="pdk" />
       <project path="external/libgsm" name="platform/external/libgsm" groups="pdk" />
       <project path="external/libhevc" name="platform/external/libhevc" groups="pdk-fs" />
       <project path="external/libjpeg-turbo" name="platform/external/libjpeg-turbo" groups="pdk" />
    
    From 74d4bab76eac9eca6dfffd9a094b09405113e5ca Mon Sep 17 00:00:00 2001
    From: AndDiSa <anddisa@googlemail.com>
    Date: Sat, 23 Sep 2017 09:38:58 +0200
    Subject: [PATCH 084/159] update patches
    
    Change-Id: I08385535db80636ad13e51fea08151069a95e8e8
    ---
     build.patch                   |  13 +
     external_libavc.patch         | 418 ++++++++++++++++++++++
     external_libhevc.patch        | 255 +++++++++++++
     external_libnfc-nxp.patch     |  13 +
     external_skia.patch           |  50 +++
     external_sonivox.patch        |  27 ++
     external_sqlite.patch         | 406 +++++++++++++++++++++
     external_tremolo.patch        |  99 ++++++
     frameworks_av.patch           | 649 +++++++++++++++++++++++++++++++++-
     frameworks_base.patch         | 298 ++++++++++++++++
     frameworks_minikin.patch      |  72 ++++
     hardware_libhardware.patch    |  45 +++
     hardware_qcom_audio.patch     |  18 +
     hardware_ril.patch            |  14 +-
     packages_apps_messaging.patch |  28 ++
     packages_apps_nfc.patch       |  62 ++++
     packages_apps_settings.patch  |  45 +++
     17 files changed, 2506 insertions(+), 6 deletions(-)
     create mode 100644 external_libavc.patch
     create mode 100644 external_libhevc.patch
     create mode 100644 external_libnfc-nxp.patch
     create mode 100644 external_skia.patch
     create mode 100644 external_sonivox.patch
     create mode 100644 external_sqlite.patch
     create mode 100644 external_tremolo.patch
     create mode 100644 frameworks_minikin.patch
     create mode 100644 hardware_libhardware.patch
     create mode 100644 hardware_qcom_audio.patch
     create mode 100644 packages_apps_messaging.patch
     create mode 100644 packages_apps_nfc.patch
     create mode 100644 packages_apps_settings.patch
    
    diff --git a/build.patch b/build.patch
    index ad934ad..df69bcd 100644
    --- a/build.patch
    +++ b/build.patch
    @@ -322,6 +322,19 @@ index 0000000..ee76dc2
     +
     +ALL_PREBUILT += $(INSTALLED_KERNEL_TARGET)
     +endif
    +diff --git a/core/version_defaults.mk b/core/version_defaults.mk
    +index 7c96344..638983f 100644
    +--- a/core/version_defaults.mk
    ++++ b/core/version_defaults.mk
    +@@ -131,7 +131,7 @@ ifeq "" "$(PLATFORM_SECURITY_PATCH)"
    +     #  It must be of the form "YYYY-MM-DD" on production devices.
    +     #  It must match one of the Android Security Patch Level strings of the Public Security Bulletins.
    +     #  If there is no $PLATFORM_SECURITY_PATCH set, keep it empty.
    +-    PLATFORM_SECURITY_PATCH := 2017-08-05
    ++    PLATFORM_SECURITY_PATCH := 2017-09-05
    + endif
    + 
    + ifeq "" "$(PLATFORM_BASE_OS)"
     diff --git a/core/version_defaults_BACKUP_20377.mk b/core/version_defaults_BACKUP_20377.mk
     new file mode 100644
     index 0000000..eb97b11
    diff --git a/external_libavc.patch b/external_libavc.patch
    new file mode 100644
    index 0000000..ae21b4f
    --- /dev/null
    +++ b/external_libavc.patch
    @@ -0,0 +1,418 @@
    +diff --git a/decoder/ih264d_api.c b/decoder/ih264d_api.c
    +index 2cde456..7c3f750 100644
    +--- a/decoder/ih264d_api.c
    ++++ b/decoder/ih264d_api.c
    +@@ -1623,6 +1623,89 @@ UWORD32 ih264d_map_error(UWORD32 i4_err_status)
    + 
    + }
    + 
    ++UWORD32 ih264d_get_outbuf_size(WORD32 pic_wd,
    ++                               UWORD32 pic_ht,
    ++                               UWORD8 u1_chroma_format,
    ++                               UWORD32 *p_buf_size)
    ++{
    ++    UWORD32 u4_min_num_out_bufs = 0;
    ++
    ++    if(u1_chroma_format == IV_YUV_420P)
    ++        u4_min_num_out_bufs = MIN_OUT_BUFS_420;
    ++    else if(u1_chroma_format == IV_YUV_422ILE)
    ++        u4_min_num_out_bufs = MIN_OUT_BUFS_422ILE;
    ++    else if(u1_chroma_format == IV_RGB_565)
    ++        u4_min_num_out_bufs = MIN_OUT_BUFS_RGB565;
    ++    else if((u1_chroma_format == IV_YUV_420SP_UV)
    ++                    || (u1_chroma_format == IV_YUV_420SP_VU))
    ++        u4_min_num_out_bufs = MIN_OUT_BUFS_420SP;
    ++
    ++    if(u1_chroma_format == IV_YUV_420P)
    ++    {
    ++        p_buf_size[0] = (pic_wd * pic_ht);
    ++        p_buf_size[1] = (pic_wd * pic_ht) >> 2;
    ++        p_buf_size[2] = (pic_wd * pic_ht) >> 2;
    ++    }
    ++    else if(u1_chroma_format == IV_YUV_422ILE)
    ++    {
    ++        p_buf_size[0] = (pic_wd * pic_ht) * 2;
    ++        p_buf_size[1] = p_buf_size[2] = 0;
    ++    }
    ++    else if(u1_chroma_format == IV_RGB_565)
    ++    {
    ++        p_buf_size[0] = (pic_wd * pic_ht) * 2;
    ++        p_buf_size[1] = p_buf_size[2] = 0;
    ++    }
    ++    else if((u1_chroma_format == IV_YUV_420SP_UV)
    ++                    || (u1_chroma_format == IV_YUV_420SP_VU))
    ++    {
    ++        p_buf_size[0] = (pic_wd * pic_ht);
    ++        p_buf_size[1] = (pic_wd * pic_ht) >> 1;
    ++        p_buf_size[2] = 0;
    ++    }
    ++
    ++    return u4_min_num_out_bufs;
    ++}
    ++
    ++WORD32 check_app_out_buf_size(dec_struct_t *ps_dec)
    ++{
    ++    UWORD32 au4_min_out_buf_size[IVD_VIDDEC_MAX_IO_BUFFERS];
    ++    UWORD32 u4_min_num_out_bufs, i;
    ++    UWORD32 pic_wd, pic_ht;
    ++
    ++    if(0 == ps_dec->u4_share_disp_buf)
    ++    {
    ++        pic_wd = ps_dec->u2_disp_width;
    ++        pic_ht = ps_dec->u2_disp_height;
    ++
    ++    }
    ++    else
    ++    {
    ++        /* In case of shared mode, do not check validity of ps_dec->ps_out_buffer */
    ++        return (IV_SUCCESS);
    ++    }
    ++
    ++    if(ps_dec->u4_app_disp_width > pic_wd)
    ++        pic_wd = ps_dec->u4_app_disp_width;
    ++
    ++    u4_min_num_out_bufs = ih264d_get_outbuf_size(pic_wd, pic_ht,
    ++                                                 ps_dec->u1_chroma_format,
    ++                                                 &au4_min_out_buf_size[0]);
    ++
    ++    if(ps_dec->ps_out_buffer->u4_num_bufs < u4_min_num_out_bufs)
    ++        return IV_FAIL;
    ++
    ++    for(i = 0; i < u4_min_num_out_bufs; i++)
    ++    {
    ++        if(ps_dec->ps_out_buffer->u4_min_out_buf_size[i]
    ++                        < au4_min_out_buf_size[i])
    ++            return (IV_FAIL);
    ++    }
    ++
    ++    return (IV_SUCCESS);
    ++}
    ++
    ++
    + /*****************************************************************************/
    + /*                                                                           */
    + /*  Function Name :  ih264d_video_decode                                     */
    +@@ -1865,6 +1948,13 @@ WORD32 ih264d_video_decode(iv_obj_t *dec_hdl, void *pv_api_ip, void *pv_api_op)
    +                                       &(ps_dec->s_disp_op));
    +         if(0 == ps_dec->s_disp_op.u4_error_code)
    +         {
    ++            /* check output buffer size given by the application */
    ++            if(check_app_out_buf_size(ps_dec) != IV_SUCCESS)
    ++            {
    ++                ps_dec_op->u4_error_code= IVD_DISP_FRM_ZERO_OP_BUF_SIZE;
    ++                return (IV_FAIL);
    ++            }
    ++
    +             ps_dec->u4_fmt_conv_cur_row = 0;
    +             ps_dec->u4_fmt_conv_num_rows = ps_dec->s_disp_frame_info.u4_y_ht;
    +             ih264d_format_convert(ps_dec, &(ps_dec->s_disp_op),
    +@@ -2094,7 +2184,8 @@ WORD32 ih264d_video_decode(iv_obj_t *dec_hdl, void *pv_api_ip, void *pv_api_op)
    +                             || (ret == IVD_MEM_ALLOC_FAILED)
    +                             || (ret == ERROR_UNAVAIL_PICBUF_T)
    +                             || (ret == ERROR_UNAVAIL_MVBUF_T)
    +-                            || (ret == ERROR_INV_SPS_PPS_T))
    ++                            || (ret == ERROR_INV_SPS_PPS_T)
    ++                            || (ret == IVD_DISP_FRM_ZERO_OP_BUF_SIZE))
    +             {
    +                 ps_dec->u4_slice_start_code_found = 0;
    +                 break;
    +@@ -2843,27 +2934,15 @@ WORD32 ih264d_get_buf_info(iv_obj_t *dec_hdl, void *pv_api_ip, void *pv_api_op)
    +     UWORD16 pic_wd, pic_ht;
    +     ivd_ctl_getbufinfo_op_t *ps_ctl_op =
    +                     (ivd_ctl_getbufinfo_op_t*)pv_api_op;
    ++    UWORD32 au4_min_out_buf_size[IVD_VIDDEC_MAX_IO_BUFFERS];
    +     UNUSED(pv_api_ip);
    ++
    +     ps_ctl_op->u4_error_code = 0;
    + 
    +     ps_dec = (dec_struct_t *)(dec_hdl->pv_codec_handle);
    + 
    +     ps_ctl_op->u4_min_num_in_bufs = MIN_IN_BUFS;
    +-    if(ps_dec->u1_chroma_format == IV_YUV_420P)
    +-        ps_ctl_op->u4_min_num_out_bufs = MIN_OUT_BUFS_420;
    +-    else if(ps_dec->u1_chroma_format == IV_YUV_422ILE)
    +-        ps_ctl_op->u4_min_num_out_bufs = MIN_OUT_BUFS_422ILE;
    +-    else if(ps_dec->u1_chroma_format == IV_RGB_565)
    +-        ps_ctl_op->u4_min_num_out_bufs = MIN_OUT_BUFS_RGB565;
    +-    else if((ps_dec->u1_chroma_format == IV_YUV_420SP_UV)
    +-                    || (ps_dec->u1_chroma_format == IV_YUV_420SP_VU))
    +-        ps_ctl_op->u4_min_num_out_bufs = MIN_OUT_BUFS_420SP;
    + 
    +-    else
    +-    {
    +-        //Invalid chroma format; Error code may be updated, verify in testing if needed
    +-        return IV_FAIL;
    +-    }
    + 
    +     ps_ctl_op->u4_num_disp_bufs = 1;
    + 
    +@@ -2930,37 +3009,15 @@ WORD32 ih264d_get_buf_info(iv_obj_t *dec_hdl, void *pv_api_ip, void *pv_api_op)
    +                         ps_ctl_op->u4_num_disp_bufs, 32);
    +     }
    + 
    +-    /*!*/
    +-    if(ps_dec->u1_chroma_format == IV_YUV_420P)
    +-    {
    +-        ps_ctl_op->u4_min_out_buf_size[0] = (pic_wd * pic_ht);
    +-        ps_ctl_op->u4_min_out_buf_size[1] = (pic_wd * pic_ht)
    +-                        >> 2;
    +-        ps_ctl_op->u4_min_out_buf_size[2] = (pic_wd * pic_ht)
    +-                        >> 2;
    +-    }
    +-    else if(ps_dec->u1_chroma_format == IV_YUV_422ILE)
    +-    {
    +-        ps_ctl_op->u4_min_out_buf_size[0] = (pic_wd * pic_ht)
    +-                        * 2;
    +-        ps_ctl_op->u4_min_out_buf_size[1] =
    +-                        ps_ctl_op->u4_min_out_buf_size[2] = 0;
    +-    }
    +-    else if(ps_dec->u1_chroma_format == IV_RGB_565)
    +-    {
    +-        ps_ctl_op->u4_min_out_buf_size[0] = (pic_wd * pic_ht)
    +-                        * 2;
    +-        ps_ctl_op->u4_min_out_buf_size[1] =
    +-                        ps_ctl_op->u4_min_out_buf_size[2] = 0;
    +-    }
    +-    else if((ps_dec->u1_chroma_format == IV_YUV_420SP_UV)
    +-                    || (ps_dec->u1_chroma_format == IV_YUV_420SP_VU))
    ++    ps_ctl_op->u4_min_num_out_bufs = ih264d_get_outbuf_size(
    ++                    pic_wd, pic_ht, ps_dec->u1_chroma_format,
    ++                    &au4_min_out_buf_size[0]);
    ++
    ++    for(i = 0; i < ps_ctl_op->u4_min_num_out_bufs; i++)
    +     {
    +-        ps_ctl_op->u4_min_out_buf_size[0] = (pic_wd * pic_ht);
    +-        ps_ctl_op->u4_min_out_buf_size[1] = (pic_wd * pic_ht)
    +-                        >> 1;
    +-        ps_ctl_op->u4_min_out_buf_size[2] = 0;
    ++        ps_ctl_op->u4_min_out_buf_size[i] = au4_min_out_buf_size[i];
    +     }
    ++
    +     ps_dec->u4_num_disp_bufs_requested = ps_ctl_op->u4_num_disp_bufs;
    + 
    +     return IV_SUCCESS;
    +diff --git a/decoder/ih264d_parse_bslice.c b/decoder/ih264d_parse_bslice.c
    +index 772964a..db64ce9 100644
    +--- a/decoder/ih264d_parse_bslice.c
    ++++ b/decoder/ih264d_parse_bslice.c
    +@@ -1531,10 +1531,7 @@ WORD32 ih264d_parse_bslice(dec_struct_t * ps_dec, UWORD16 u2_first_mb_in_slice)
    +             }
    + 
    +             num_entries = ((2 * num_entries) + 1);
    +-            if(BASE_PROFILE_IDC != ps_dec->ps_cur_sps->u1_profile_idc)
    +-            {
    +-                num_entries *= 2;
    +-            }
    ++            num_entries *= 2;
    + 
    +             size = num_entries * sizeof(void *);
    +             size += PAD_MAP_IDX_POC * sizeof(void *);
    +diff --git a/decoder/ih264d_parse_pslice.c b/decoder/ih264d_parse_pslice.c
    +index bcfbe05..d6b0f23 100644
    +--- a/decoder/ih264d_parse_pslice.c
    ++++ b/decoder/ih264d_parse_pslice.c
    +@@ -1696,10 +1696,8 @@ WORD32 ih264d_mark_err_slice_skip(dec_struct_t * ps_dec,
    +             num_entries = 1;
    +         }
    +         num_entries = ((2 * num_entries) + 1);
    +-        if(BASE_PROFILE_IDC != ps_dec->ps_cur_sps->u1_profile_idc)
    +-        {
    +-            num_entries *= 2;
    +-        }
    ++        num_entries *= 2;
    ++
    +         size = num_entries * sizeof(void *);
    +         size += PAD_MAP_IDX_POC * sizeof(void *);
    + 
    +@@ -2063,10 +2061,7 @@ WORD32 ih264d_parse_pslice(dec_struct_t *ps_dec, UWORD16 u2_first_mb_in_slice)
    +                 num_entries = 1;
    +             }
    +             num_entries = ((2 * num_entries) + 1);
    +-            if(BASE_PROFILE_IDC != ps_dec->ps_cur_sps->u1_profile_idc)
    +-            {
    +-                num_entries *= 2;
    +-            }
    ++            num_entries *= 2;
    + 
    +             size = num_entries * sizeof(void *);
    +             size += PAD_MAP_IDX_POC * sizeof(void *);
    +diff --git a/decoder/ih264d_parse_slice.c b/decoder/ih264d_parse_slice.c
    +index fad2dff..bdfccb6 100644
    +--- a/decoder/ih264d_parse_slice.c
    ++++ b/decoder/ih264d_parse_slice.c
    +@@ -72,6 +72,7 @@
    + #include "ih264d_parse_islice.h"
    + #define RET_LAST_SKIP  0x80000000
    + 
    ++WORD32 check_app_out_buf_size(dec_struct_t *ps_dec);
    + /*!
    +  **************************************************************************
    +  * \if Function name : ih264d_form_pred_weight_matrix \endif
    +@@ -181,6 +182,10 @@ WORD32 ih264d_start_of_pic(dec_struct_t *ps_dec,
    + 
    +     H264_MUTEX_LOCK(&ps_dec->process_disp_mutex);
    + 
    ++    /* check output buffer size given by the application */
    ++    if(check_app_out_buf_size(ps_dec) != IV_SUCCESS)
    ++        return IVD_DISP_FRM_ZERO_OP_BUF_SIZE;
    ++
    +     ps_prev_poc->i4_pic_order_cnt_lsb = ps_cur_poc->i4_pic_order_cnt_lsb;
    +     ps_prev_poc->i4_pic_order_cnt_msb = ps_cur_poc->i4_pic_order_cnt_msb;
    +     ps_prev_poc->i4_delta_pic_order_cnt_bottom =
    +@@ -436,11 +441,23 @@ WORD32 ih264d_start_of_pic(dec_struct_t *ps_dec,
    +         ps_dec->au1_pic_buf_ref_flag[cur_pic_buf_id] = 0;
    + 
    +         {
    +-            /*make first entry of list0 point to cur pic,so that if first Islice is in error, ref pic struct will have valid entries*/
    ++            /*make first entry of list0 and list1 point to cur pic,
    ++             *so that if first slice is in error, ref pic struct will have valid entries*/
    +             ps_dec->ps_ref_pic_buf_lx[0] = ps_dec->ps_dpb_mgr->ps_init_dpb[0];
    ++            ps_dec->ps_ref_pic_buf_lx[1] = ps_dec->ps_dpb_mgr->ps_init_dpb[1];
    +             *(ps_dec->ps_dpb_mgr->ps_init_dpb[0][0]) = *ps_cur_pic;
    +             /* Initialize for field reference as well */
    +             *(ps_dec->ps_dpb_mgr->ps_init_dpb[0][MAX_REF_BUFS]) = *ps_cur_pic;
    ++
    ++            *(ps_dec->ps_dpb_mgr->ps_mod_dpb[0][0]) = *ps_cur_pic;
    ++            /* Initialize for field reference as well */
    ++            *(ps_dec->ps_dpb_mgr->ps_mod_dpb[0][MAX_REF_BUFS]) = *ps_cur_pic;
    ++            *(ps_dec->ps_dpb_mgr->ps_init_dpb[1][0]) = *ps_cur_pic;
    ++            /* Initialize for field reference as well */
    ++            *(ps_dec->ps_dpb_mgr->ps_init_dpb[1][MAX_REF_BUFS]) = *ps_cur_pic;
    ++            *(ps_dec->ps_dpb_mgr->ps_mod_dpb[1][0]) = *ps_cur_pic;
    ++            /* Initialize for field reference as well */
    ++            *(ps_dec->ps_dpb_mgr->ps_mod_dpb[1][MAX_REF_BUFS]) = *ps_cur_pic;
    +         }
    + 
    +         if(!ps_dec->ps_cur_pic)
    +@@ -1785,10 +1802,8 @@ WORD32 ih264d_parse_decode_slice(UWORD8 u1_is_idr_slice,
    +             num_entries = 1;
    +         }
    +         num_entries = ((2 * num_entries) + 1);
    +-        if(BASE_PROFILE_IDC != ps_dec->ps_cur_sps->u1_profile_idc)
    +-        {
    +-            num_entries *= 2;
    +-        }
    ++        num_entries *= 2;
    ++
    + 
    +         size = num_entries * sizeof(void *);
    +         size += PAD_MAP_IDX_POC * sizeof(void *);
    +diff --git a/decoder/ih264d_process_bslice.c b/decoder/ih264d_process_bslice.c
    +index 7784110..42fad03 100644
    +--- a/decoder/ih264d_process_bslice.c
    ++++ b/decoder/ih264d_process_bslice.c
    +@@ -1212,7 +1212,8 @@ void ih264d_init_ref_idx_lx_b(dec_struct_t *ps_dec)
    +     struct dpb_info_t *ps_next_dpb;
    +     WORD32 i_cur_poc, i_max_st_poc, i_min_st_poc, i_ref_poc, i_temp_poc;
    +     WORD8 i;
    +-    UWORD8 u1_max_lt_index, u1_min_lt_index, u1_lt_index;
    ++    UWORD8 u1_max_lt_index, u1_min_lt_index;
    ++    UWORD32 u4_lt_index;
    +     UWORD8 u1_field_pic_flag;
    +     dec_slice_params_t *ps_cur_slice;
    +     UWORD8 u1_L0, u1_L1;
    +@@ -1264,9 +1265,9 @@ void ih264d_init_ref_idx_lx_b(dec_struct_t *ps_dec)
    +     }
    +     for(i = 0; i < ps_dpb_mgr->u1_num_lt_ref_bufs; i++)
    +     {
    +-        u1_lt_index = ps_next_dpb->u1_lt_idx;
    +-        u1_max_lt_index = (UWORD8)(MAX(u1_max_lt_index, u1_lt_index));
    +-        u1_min_lt_index = (UWORD8)(MIN(u1_min_lt_index, u1_lt_index));
    ++        u4_lt_index = ps_next_dpb->u1_lt_idx;
    ++        u1_max_lt_index = (UWORD8)(MAX(u1_max_lt_index, u4_lt_index));
    ++        u1_min_lt_index = (UWORD8)(MIN(u1_min_lt_index, u4_lt_index));
    + 
    +         /* Chase the next link */
    +         ps_next_dpb = ps_next_dpb->ps_prev_long;
    +@@ -1333,12 +1334,12 @@ void ih264d_init_ref_idx_lx_b(dec_struct_t *ps_dec)
    +     /* Start from ST head */
    + 
    +     u1_num_short_term_bufs = u1_L0;
    +-    for(u1_lt_index = u1_min_lt_index; u1_lt_index <= u1_max_lt_index; u1_lt_index++)
    ++    for(u4_lt_index = u1_min_lt_index; u4_lt_index <= u1_max_lt_index; u4_lt_index++)
    +     {
    +         ps_next_dpb = ps_dpb_mgr->ps_dpb_ht_head;
    +         for(i = 0; i < ps_dpb_mgr->u1_num_lt_ref_bufs; i++)
    +         {
    +-            if(ps_next_dpb->u1_lt_idx == u1_lt_index)
    ++            if(ps_next_dpb->u1_lt_idx == u4_lt_index)
    +             {
    +                 ih264d_insert_pic_in_ref_pic_listx(ps_ref_pic_buf_lx,
    +                                                    ps_next_dpb->ps_pic_buf);
    +@@ -1466,13 +1467,13 @@ void ih264d_init_ref_idx_lx_b(dec_struct_t *ps_dec)
    +         /* Start from ST head */
    +         u1_num_short_term_bufs = u1_L1;
    + 
    +-        for(u1_lt_index = u1_min_lt_index; u1_lt_index <= u1_max_lt_index;
    +-                        u1_lt_index++)
    ++        for(u4_lt_index = u1_min_lt_index; u4_lt_index <= u1_max_lt_index;
    ++                        u4_lt_index++)
    +         {
    +             ps_next_dpb = ps_dpb_mgr->ps_dpb_ht_head;
    +             for(i = 0; i < ps_dpb_mgr->u1_num_lt_ref_bufs; i++)
    +             {
    +-                if(ps_next_dpb->u1_lt_idx == u1_lt_index)
    ++                if(ps_next_dpb->u1_lt_idx == u4_lt_index)
    +                 {
    +                     ih264d_insert_pic_in_ref_pic_listx(ps_ref_pic_buf_lx,
    +                                                        ps_next_dpb->ps_pic_buf);
    +diff --git a/decoder/ih264d_process_pslice.c b/decoder/ih264d_process_pslice.c
    +index 95ac557..efda5cf 100644
    +--- a/decoder/ih264d_process_pslice.c
    ++++ b/decoder/ih264d_process_pslice.c
    +@@ -971,7 +971,8 @@ void ih264d_init_ref_idx_lx_p(dec_struct_t *ps_dec)
    +     dpb_manager_t *ps_dpb_mgr;
    +     struct dpb_info_t *ps_next_dpb;
    +     WORD8 i;
    +-    UWORD8 u1_max_lt_index, u1_min_lt_index, u1_lt_index;
    ++    UWORD8 u1_max_lt_index, u1_min_lt_index;
    ++    UWORD32 u4_lt_index;
    +     UWORD8 u1_field_pic_flag;
    +     dec_slice_params_t *ps_cur_slice;
    +     UWORD8 u1_L0;
    +@@ -1018,9 +1019,9 @@ void ih264d_init_ref_idx_lx_p(dec_struct_t *ps_dec)
    + 
    +         for(i = 0; i < ps_dpb_mgr->u1_num_lt_ref_bufs; i++)
    +         {
    +-            u1_lt_index = ps_next_dpb->u1_lt_idx;
    +-            u1_max_lt_index = (UWORD8)(MAX(u1_max_lt_index, u1_lt_index));
    +-            u1_min_lt_index = (UWORD8)(MIN(u1_min_lt_index, u1_lt_index));
    ++            u4_lt_index = ps_next_dpb->u1_lt_idx;
    ++            u1_max_lt_index = (UWORD8)(MAX(u1_max_lt_index, u4_lt_index));
    ++            u1_min_lt_index = (UWORD8)(MIN(u1_min_lt_index, u4_lt_index));
    + 
    +             /* Chase the next link */
    +             ps_next_dpb = ps_next_dpb->ps_prev_long;
    +@@ -1065,13 +1066,13 @@ void ih264d_init_ref_idx_lx_p(dec_struct_t *ps_dec)
    +     /* Arrange all Long term buffers in ascending order, in LongtermIndex */
    +     /* Start from LT head */
    +     u1_num_short_term_bufs = u1_L0;
    +-    for(u1_lt_index = u1_min_lt_index; u1_lt_index <= u1_max_lt_index;
    +-                    u1_lt_index++)
    ++    for(u4_lt_index = u1_min_lt_index; u4_lt_index <= u1_max_lt_index;
    ++                    u4_lt_index++)
    +     {
    +         ps_next_dpb = ps_dpb_mgr->ps_dpb_ht_head;
    +         for(i = 0; i < ps_dpb_mgr->u1_num_lt_ref_bufs; i++)
    +         {
    +-            if(ps_next_dpb->u1_lt_idx == u1_lt_index)
    ++            if(ps_next_dpb->u1_lt_idx == u4_lt_index)
    +             {
    +                 ih264d_insert_pic_in_ref_pic_listx(ps_ref_pic_buf_lx,
    +                                                    ps_next_dpb->ps_pic_buf);
    +diff --git a/decoder/ih264d_utils.c b/decoder/ih264d_utils.c
    +index 4f6deca..7d7475d 100644
    +--- a/decoder/ih264d_utils.c
    ++++ b/decoder/ih264d_utils.c
    +@@ -1979,10 +1979,7 @@ WORD16 ih264d_allocate_dynamic_bufs(dec_struct_t * ps_dec)
    +         num_entries = 1;
    +     }
    +     num_entries = ((2 * num_entries) + 1);
    +-    if(BASE_PROFILE_IDC != ps_dec->ps_cur_sps->u1_profile_idc)
    +-    {
    +-        num_entries *= 2;
    +-    }
    ++    num_entries *= 2;
    + 
    +     size = num_entries * sizeof(void *);
    +     size += PAD_MAP_IDX_POC * sizeof(void *);
    diff --git a/external_libhevc.patch b/external_libhevc.patch
    new file mode 100644
    index 0000000..86b70fe
    --- /dev/null
    +++ b/external_libhevc.patch
    @@ -0,0 +1,255 @@
    +diff --git a/common/ihevc_structs.h b/common/ihevc_structs.h
    +index 93d2ad4..baa6375 100644
    +--- a/common/ihevc_structs.h
    ++++ b/common/ihevc_structs.h
    +@@ -644,33 +644,33 @@ typedef struct
    +      * if 1, , for the highest temporal sub-layers, the temporal distance between the HRD output times
    +      * of consecutive pictures in output order is constrained refer to Table E-6
    +      */
    +-    UWORD8 au1_fixed_pic_rate_general_flag[6];
    ++    UWORD8 au1_fixed_pic_rate_general_flag[VPS_MAX_SUB_LAYERS];
    + 
    +-    UWORD8 au1_fixed_pic_rate_within_cvs_flag[6];
    ++    UWORD8 au1_fixed_pic_rate_within_cvs_flag[VPS_MAX_SUB_LAYERS];
    + 
    +     /**
    +      * if 1, , for the highest temporal sub-layers, the temporal distance (in clock ticks) between the
    +      * element units that specify HRD output times of consecutive pictures in output order is constrained
    +      * refer to Table E-6
    +      */
    +-    UWORD8 au1_elemental_duration_in_tc_minus1[6];
    ++    UWORD8 au1_elemental_duration_in_tc_minus1[VPS_MAX_SUB_LAYERS];
    + 
    +     /**
    +      * specifies the HRD operational mode
    +      */
    +-    UWORD8 au1_low_delay_hrd_flag[6];
    ++    UWORD8 au1_low_delay_hrd_flag[VPS_MAX_SUB_LAYERS];
    + 
    +     /**
    +      * 1 specifies the number of alternative CPB specifications in the
    +      * bitstream of the cvs when HighestTid is equal to i
    +      */
    +-    UWORD8 au1_cpb_cnt_minus1[6];
    ++    UWORD8 au1_cpb_cnt_minus1[VPS_MAX_SUB_LAYERS];
    + 
    + 
    +     /**
    +      * VUI level Sub-layer HRD parameters
    +      */
    +-    sub_lyr_hrd_params_t as_sub_layer_hrd_params[6];
    ++    sub_lyr_hrd_params_t as_sub_layer_hrd_params[VPS_MAX_SUB_LAYERS];
    + 
    + }hrd_params_t;
    + 
    +diff --git a/decoder/ihevcd_decode.c b/decoder/ihevcd_decode.c
    +index d656519..87c3bd7 100644
    +--- a/decoder/ihevcd_decode.c
    ++++ b/decoder/ihevcd_decode.c
    +@@ -81,6 +81,7 @@
    + #define NUM_FRAMES_LIMIT 0x7FFFFFFF
    + #endif
    + 
    ++IHEVCD_ERROR_T ihevcd_check_out_buf_size(codec_t *ps_codec);
    + IHEVCD_ERROR_T ihevcd_fmt_conv(codec_t *ps_codec,
    +                                process_ctxt_t *ps_proc,
    +                                UWORD8 *pu1_y_dst,
    +@@ -471,6 +472,10 @@ WORD32 ihevcd_decode(iv_obj_t *ps_codec_obj, void *pv_api_ip, void *pv_api_op)
    +                 ihevcd_init_proc_ctxt(ps_proc, 0);
    +             }
    + 
    ++            /* Output buffer check */
    ++            ret = ihevcd_check_out_buf_size(ps_codec);
    ++            RETURN_IF((ret != (IHEVCD_ERROR_T)IHEVCD_SUCCESS), ret);
    ++
    +             /* Set remaining number of rows to be processed */
    +             ret = ihevcd_fmt_conv(ps_codec, &ps_codec->as_process[prev_proc_idx],
    +                                   ps_dec_ip->s_out_buffer.pu1_bufs[0],
    +diff --git a/decoder/ihevcd_parse_headers.c b/decoder/ihevcd_parse_headers.c
    +index c0f1564..29a309d 100644
    +--- a/decoder/ihevcd_parse_headers.c
    ++++ b/decoder/ihevcd_parse_headers.c
    +@@ -1285,15 +1285,31 @@ IHEVCD_ERROR_T ihevcd_parse_sps(codec_t *ps_codec)
    +     {
    + 
    +         UEV_PARSE("pic_crop_left_offset", value, ps_bitstrm);
    ++        if (value >= ps_sps->i2_pic_width_in_luma_samples)
    ++        {
    ++            return IHEVCD_INVALID_PARAMETER;
    ++        }
    +         ps_sps->i2_pic_crop_left_offset = value;
    + 
    +         UEV_PARSE("pic_crop_right_offset", value, ps_bitstrm);
    ++        if (value >= ps_sps->i2_pic_width_in_luma_samples)
    ++        {
    ++            return IHEVCD_INVALID_PARAMETER;
    ++        }
    +         ps_sps->i2_pic_crop_right_offset = value;
    + 
    +         UEV_PARSE("pic_crop_top_offset", value, ps_bitstrm);
    ++        if (value >= ps_sps->i2_pic_height_in_luma_samples)
    ++        {
    ++            return IHEVCD_INVALID_PARAMETER;
    ++        }
    +         ps_sps->i2_pic_crop_top_offset = value;
    + 
    +         UEV_PARSE("pic_crop_bottom_offset", value, ps_bitstrm);
    ++        if (value >= ps_sps->i2_pic_height_in_luma_samples)
    ++        {
    ++            return IHEVCD_INVALID_PARAMETER;
    ++        }
    +         ps_sps->i2_pic_crop_bottom_offset = value;
    +     }
    +     else
    +diff --git a/decoder/ihevcd_parse_slice.c b/decoder/ihevcd_parse_slice.c
    +index 126b14c..9f92a0d 100644
    +--- a/decoder/ihevcd_parse_slice.c
    ++++ b/decoder/ihevcd_parse_slice.c
    +@@ -2708,6 +2708,17 @@ IHEVCD_ERROR_T ihevcd_parse_slice_data(codec_t *ps_codec)
    +         {
    +             tu_t *ps_tu = ps_codec->s_parse.ps_tu;
    +             pu_t *ps_pu = ps_codec->s_parse.ps_pu;
    ++            WORD32 pu_skip_wd, pu_skip_ht;
    ++            WORD32 rows_remaining, cols_remaining;
    ++
    ++            /* Set pu wd and ht based on whether the ctb is complete or not */
    ++            rows_remaining = ps_sps->i2_pic_height_in_luma_samples
    ++                            - (ps_codec->s_parse.i4_ctb_y << ps_sps->i1_log2_ctb_size);
    ++            pu_skip_ht = MIN(ctb_size, rows_remaining);
    ++
    ++            cols_remaining = ps_sps->i2_pic_width_in_luma_samples
    ++                            - (ps_codec->s_parse.i4_ctb_x << ps_sps->i1_log2_ctb_size);
    ++            pu_skip_wd = MIN(ctb_size, cols_remaining);
    + 
    +             ps_tu->b1_cb_cbf = 0;
    +             ps_tu->b1_cr_cbf = 0;
    +@@ -2731,8 +2742,8 @@ IHEVCD_ERROR_T ihevcd_parse_slice_data(codec_t *ps_codec)
    +             ps_pu->b2_part_idx = 0;
    +             ps_pu->b4_pos_x = 0;
    +             ps_pu->b4_pos_y = 0;
    +-            ps_pu->b4_wd = (ctb_size >> 2) - 1;
    +-            ps_pu->b4_ht = (ctb_size >> 2) - 1;
    ++            ps_pu->b4_wd = (pu_skip_wd >> 2) - 1;
    ++            ps_pu->b4_ht = (pu_skip_ht >> 2) - 1;
    +             ps_pu->b1_intra_flag = 0;
    +             ps_pu->b3_part_mode = ps_codec->s_parse.s_cu.i4_part_mode;
    +             ps_pu->b1_merge_flag = 1;
    +diff --git a/decoder/ihevcd_utils.c b/decoder/ihevcd_utils.c
    +index 7d76577..14cdd2b 100755
    +--- a/decoder/ihevcd_utils.c
    ++++ b/decoder/ihevcd_utils.c
    +@@ -662,6 +662,103 @@ IHEVCD_ERROR_T ihevcd_mv_buf_mgr_add_bufs(codec_t *ps_codec)
    + *******************************************************************************
    + *
    + * @brief
    ++*  Output buffer check
    ++*
    ++* @par Description:
    ++*  Check for the number of buffers and buffer sizes of output buffer
    ++*
    ++* @param[in] ps_codec
    ++*  Pointer to codec context
    ++*
    ++* @returns  Error from IHEVCD_ERROR_T
    ++*
    ++* @remarks
    ++*
    ++*
    ++*******************************************************************************
    ++*/
    ++IHEVCD_ERROR_T ihevcd_check_out_buf_size(codec_t *ps_codec)
    ++{
    ++    ivd_out_bufdesc_t *ps_out_buffer = ps_codec->ps_out_buffer;
    ++    UWORD32 au4_min_out_buf_size[IVD_VIDDEC_MAX_IO_BUFFERS];
    ++    UWORD32 u4_min_num_out_bufs = 0, i;
    ++    UWORD32 wd, ht;
    ++
    ++    if(0 == ps_codec->i4_share_disp_buf)
    ++    {
    ++        wd = ps_codec->i4_disp_wd;
    ++        ht = ps_codec->i4_disp_ht;
    ++    }
    ++    else
    ++    {
    ++        /* In case of shared mode, do not check validity of ps_codec->ps_out_buffer */
    ++        return (IHEVCD_ERROR_T)IHEVCD_SUCCESS;
    ++    }
    ++
    ++    if(ps_codec->e_chroma_fmt == IV_YUV_420P)
    ++        u4_min_num_out_bufs = MIN_OUT_BUFS_420;
    ++    else if(ps_codec->e_chroma_fmt == IV_YUV_422ILE)
    ++        u4_min_num_out_bufs = MIN_OUT_BUFS_422ILE;
    ++    else if(ps_codec->e_chroma_fmt == IV_RGB_565)
    ++        u4_min_num_out_bufs = MIN_OUT_BUFS_RGB565;
    ++    else if(ps_codec->e_chroma_fmt == IV_RGBA_8888)
    ++        u4_min_num_out_bufs = MIN_OUT_BUFS_RGBA8888;
    ++    else if((ps_codec->e_chroma_fmt == IV_YUV_420SP_UV)
    ++                    || (ps_codec->e_chroma_fmt == IV_YUV_420SP_VU))
    ++        u4_min_num_out_bufs = MIN_OUT_BUFS_420SP;
    ++
    ++    if(ps_codec->e_chroma_fmt == IV_YUV_420P)
    ++    {
    ++        au4_min_out_buf_size[0] = (wd * ht);
    ++        au4_min_out_buf_size[1] = (wd * ht) >> 2;
    ++        au4_min_out_buf_size[2] = (wd * ht) >> 2;
    ++    }
    ++    else if(ps_codec->e_chroma_fmt == IV_YUV_422ILE)
    ++    {
    ++        au4_min_out_buf_size[0] = (wd * ht) * 2;
    ++        au4_min_out_buf_size[1] =
    ++                        au4_min_out_buf_size[2] = 0;
    ++    }
    ++    else if(ps_codec->e_chroma_fmt == IV_RGB_565)
    ++    {
    ++        au4_min_out_buf_size[0] = (wd * ht) * 2;
    ++        au4_min_out_buf_size[1] =
    ++                        au4_min_out_buf_size[2] = 0;
    ++    }
    ++    else if(ps_codec->e_chroma_fmt == IV_RGBA_8888)
    ++    {
    ++        au4_min_out_buf_size[0] = (wd * ht) * 4;
    ++        au4_min_out_buf_size[1] =
    ++                        au4_min_out_buf_size[2] = 0;
    ++    }
    ++    else if((ps_codec->e_chroma_fmt == IV_YUV_420SP_UV)
    ++                    || (ps_codec->e_chroma_fmt == IV_YUV_420SP_VU))
    ++    {
    ++        au4_min_out_buf_size[0] = (wd * ht);
    ++        au4_min_out_buf_size[1] = (wd * ht) >> 1;
    ++        au4_min_out_buf_size[2] = 0;
    ++    }
    ++
    ++    if(ps_out_buffer->u4_num_bufs < u4_min_num_out_bufs)
    ++    {
    ++        return (IHEVCD_ERROR_T)IV_FAIL;
    ++    }
    ++
    ++    for (i = 0 ; i < u4_min_num_out_bufs; i++)
    ++    {
    ++        if(ps_out_buffer->u4_min_out_buf_size[i] < au4_min_out_buf_size[i])
    ++        {
    ++            return (IHEVCD_ERROR_T)IV_FAIL;
    ++        }
    ++    }
    ++
    ++    return (IHEVCD_ERROR_T)IHEVCD_SUCCESS;
    ++}
    ++
    ++/**
    ++*******************************************************************************
    ++*
    ++* @brief
    + *  Picture level initializations required during parsing
    + *
    + * @par Description:
    +@@ -713,6 +810,10 @@ IHEVCD_ERROR_T ihevcd_parse_pic_init(codec_t *ps_codec)
    +         ps_codec->s_parse.i4_first_pic_init = 1;
    +     }
    + 
    ++    /* Output buffer check */
    ++    ret = ihevcd_check_out_buf_size(ps_codec);
    ++    RETURN_IF((ret != (IHEVCD_ERROR_T)IHEVCD_SUCCESS), ret);
    ++
    +     /* Initialize all the slice headers' slice addresses to zero */
    +     {
    +         WORD32 slice_idx;
    diff --git a/external_libnfc-nxp.patch b/external_libnfc-nxp.patch
    new file mode 100644
    index 0000000..380aafb
    --- /dev/null
    +++ b/external_libnfc-nxp.patch
    @@ -0,0 +1,13 @@
    +diff --git a/src/phHal4Nfc.c b/src/phHal4Nfc.c
    +index 0a1b13c..2023736 100644
    +--- a/src/phHal4Nfc.c
    ++++ b/src/phHal4Nfc.c
    +@@ -306,7 +306,7 @@ phHal4Nfc_Configure_Layers(
    + #include <utils/Log.h>
    + #include <dlfcn.h>
    + 
    +-#define FW_PATH "/vendor/firmware/libpn544_fw.so"
    ++#define FW_PATH "/vendor/lib/libpn544_fw.so"
    + 
    + const unsigned char *nxp_nfc_full_version = NULL;
    + const unsigned char *nxp_nfc_fw = NULL;
    diff --git a/external_skia.patch b/external_skia.patch
    new file mode 100644
    index 0000000..ebc9f24
    --- /dev/null
    +++ b/external_skia.patch
    @@ -0,0 +1,50 @@
    +diff --git a/resources/invalid_images/b38116746.ico b/resources/invalid_images/b38116746.ico
    +new file mode 100644
    +index 0000000..35ee5b5
    +Binary files /dev/null and b/resources/invalid_images/b38116746.ico differ
    +diff --git a/src/codec/SkIcoCodec.cpp b/src/codec/SkIcoCodec.cpp
    +index dc4222a..8b3d26d 100644
    +--- a/src/codec/SkIcoCodec.cpp
    ++++ b/src/codec/SkIcoCodec.cpp
    +@@ -14,6 +14,7 @@
    + #include "SkStream.h"
    + #include "SkTDArray.h"
    + #include "SkTSort.h"
    ++#include "../private/SkTemplates.h"
    + 
    + /*
    +  * Checks the start of the stream to see if the image is an Ico or Cur
    +@@ -128,12 +129,18 @@ SkCodec* SkIcoCodec::NewFromStream(SkStream* stream) {
    +         bytesRead = offset;
    + 
    +         // Create a new stream for the embedded codec
    +-        SkAutoTUnref<SkData> data(
    +-                SkData::NewFromStream(inputStream.get(), size));
    +-        if (nullptr == data.get()) {
    ++        SkAutoFree buffer(sk_malloc_flags(size, 0));
    ++        if (!buffer.get()) {
    ++            SkCodecPrintf("Warning: OOM trying to create embedded stream.\n");
    ++            break;
    ++        }
    ++
    ++        if (inputStream->read(buffer.get(), size) != size) {
    +             SkCodecPrintf("Warning: could not create embedded stream.\n");
    +             break;
    +         }
    ++
    ++        SkAutoTUnref<SkData> data(SkData::NewFromMalloc(buffer.detach(), size));
    +         SkAutoTDelete<SkMemoryStream> embeddedStream(new SkMemoryStream(data.get()));
    +         bytesRead += size;
    + 
    +diff --git a/tests/BadIcoTest.cpp b/tests/BadIcoTest.cpp
    +index c387e15..f6b1c46 100644
    +--- a/tests/BadIcoTest.cpp
    ++++ b/tests/BadIcoTest.cpp
    +@@ -22,6 +22,7 @@ DEF_TEST(BadImage, reporter) {
    +         "ico_fuzz1.ico",
    +         "skbug3442.webp",
    +         "skbug3429.webp",
    ++        "b38116746.ico",
    +     };
    + 
    +     const char* badImagesFolder = "invalid_images";
    diff --git a/external_sonivox.patch b/external_sonivox.patch
    new file mode 100644
    index 0000000..a3a99fa
    --- /dev/null
    +++ b/external_sonivox.patch
    @@ -0,0 +1,27 @@
    +diff --git a/arm-wt-22k/lib_src/eas_wtsynth.c b/arm-wt-22k/lib_src/eas_wtsynth.c
    +index 9fcda7b..8488fe2 100644
    +--- a/arm-wt-22k/lib_src/eas_wtsynth.c
    ++++ b/arm-wt-22k/lib_src/eas_wtsynth.c
    +@@ -28,6 +28,7 @@
    + */
    + 
    + // includes
    ++#define LOG_TAG "SYNTH"
    + #include "log/log.h"
    + #include <cutils/log.h>
    + 
    +@@ -557,6 +558,14 @@ static EAS_BOOL WT_UpdateVoice (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth, S_SYNTH
    +     else
    +         temp += (pVoice->note + pSynth->globalTranspose) * 100;
    +     intFrame.frame.phaseIncrement = WT_UpdatePhaseInc(pWTVoice, pArt, pChannel, temp);
    ++    temp = pWTVoice->loopEnd - pWTVoice->loopStart;
    ++    if (temp != 0) {
    ++        temp = temp << NUM_PHASE_FRAC_BITS;
    ++        if (intFrame.frame.phaseIncrement > temp) {
    ++            ALOGW("%p phaseIncrement=%d", pWTVoice, (int)intFrame.frame.phaseIncrement);
    ++            intFrame.frame.phaseIncrement %= temp;
    ++        }
    ++    }
    + 
    +     /* call into engine to generate samples */
    +     intFrame.pAudioBuffer = pVoiceMgr->voiceBuffer;
    diff --git a/external_sqlite.patch b/external_sqlite.patch
    new file mode 100644
    index 0000000..a5fb9ae
    --- /dev/null
    +++ b/external_sqlite.patch
    @@ -0,0 +1,406 @@
    +diff --git a/README.version b/README.version
    +index 96cdf7f..6fe7d18 100644
    +--- a/README.version
    ++++ b/README.version
    +@@ -1,3 +1,3 @@
    +-URL: https://www.sqlite.org/2015/sqlite-amalgamation-3090200.zip
    ++URL: https://sqlite.org/src/tarball/SQLite-69906880.tar.gz?uuid=69906880cee1f246cce494672402e0c7f29bd4ec19c437d26d603870d2bd625d
    + Version: 3.9.2
    + BugComponent: 24950
    +diff --git a/dist/Android.patch b/dist/Android.patch
    +index 58557e6..f766487 100644
    +--- a/dist/Android.patch
    ++++ b/dist/Android.patch
    +@@ -1,6 +1,6 @@
    + diff -r -u -d orig/shell.c ./shell.c
    +---- orig/shell.c	2015-11-03 01:44:04.000000000 -0800
    +-+++ ./shell.c	2015-12-23 09:50:51.081951250 -0800
    ++--- orig/shell.c	2017-07-21 01:25:18.136530117 -0700
    +++++ ./shell.c	2017-07-21 01:25:55.316260658 -0700
    + @@ -52,6 +52,12 @@
    +  #endif
    +  #include <ctype.h>
    +@@ -38,9 +38,9 @@ diff -r -u -d orig/shell.c ./shell.c
    +  }
    +  
    + diff -r -u -d orig/sqlite3.c ./sqlite3.c
    +---- orig/sqlite3.c	2015-11-03 01:44:04.000000000 -0800
    +-+++ ./sqlite3.c	2015-12-23 09:50:51.113951381 -0800
    +-@@ -26470,6 +26470,13 @@
    ++--- orig/sqlite3.c	2017-07-21 01:25:18.524527313 -0700
    +++++ ./sqlite3.c	2017-07-21 01:25:55.356260367 -0700
    ++@@ -26474,6 +26474,13 @@
    +  /* #include "sqliteInt.h" */
    +  #if SQLITE_OS_UNIX              /* This file is used on unix only */
    +  
    +@@ -54,7 +54,7 @@ diff -r -u -d orig/sqlite3.c ./sqlite3.c
    +  /*
    +  ** There are various methods for file locking used for concurrency
    +  ** control:
    +-@@ -27024,7 +27031,12 @@
    ++@@ -27028,7 +27035,12 @@
    +  #else
    +    { "pread64",      (sqlite3_syscall_ptr)0,          0  },
    +  #endif
    +@@ -67,7 +67,7 @@ diff -r -u -d orig/sqlite3.c ./sqlite3.c
    +  
    +    { "write",        (sqlite3_syscall_ptr)write,      0  },
    +  #define osWrite     ((ssize_t(*)(int,const void*,size_t))aSyscall[11].pCurrent)
    +-@@ -27042,8 +27054,14 @@
    ++@@ -27046,8 +27058,14 @@
    +  #else
    +    { "pwrite64",     (sqlite3_syscall_ptr)0,          0  },
    +  #endif
    +@@ -82,7 +82,7 @@ diff -r -u -d orig/sqlite3.c ./sqlite3.c
    +  
    +    { "fchmod",       (sqlite3_syscall_ptr)fchmod,     0  },
    +  #define osFchmod    ((int(*)(int,mode_t))aSyscall[14].pCurrent)
    +-@@ -30292,7 +30310,7 @@
    ++@@ -30296,7 +30314,7 @@
    +    SimulateIOError( rc=1 );
    +    if( rc!=0 ){
    +      storeLastErrno((unixFile*)id, errno);
    +@@ -91,7 +91,7 @@ diff -r -u -d orig/sqlite3.c ./sqlite3.c
    +    }
    +    *pSize = buf.st_size;
    +  
    +-@@ -30328,7 +30346,7 @@
    ++@@ -30332,7 +30350,7 @@
    +      struct stat buf;              /* Used to hold return values of fstat() */
    +     
    +      if( osFstat(pFile->h, &buf) ){
    +@@ -100,7 +100,7 @@ diff -r -u -d orig/sqlite3.c ./sqlite3.c
    +      }
    +  
    +      nSize = ((nByte+pFile->szChunk-1) / pFile->szChunk) * pFile->szChunk;
    +-@@ -30913,7 +30931,7 @@
    ++@@ -30917,7 +30935,7 @@
    +      ** with the same permissions.
    +      */
    +      if( osFstat(pDbFd->h, &sStat) && pInode->bProcessLock==0 ){
    +@@ -109,7 +109,7 @@ diff -r -u -d orig/sqlite3.c ./sqlite3.c
    +        goto shm_open_err;
    +      }
    +  
    +-@@ -32260,7 +32278,7 @@
    ++@@ -32264,7 +32282,7 @@
    +        *pUid = sStat.st_uid;
    +        *pGid = sStat.st_gid;
    +      }else{
    +@@ -118,7 +118,7 @@ diff -r -u -d orig/sqlite3.c ./sqlite3.c
    +      }
    +    }else if( flags & SQLITE_OPEN_DELETEONCLOSE ){
    +      *pMode = 0600;
    +-@@ -108046,7 +108064,7 @@
    ++@@ -108062,7 +108080,7 @@
    +    }
    +    if( pDb->pSchema->file_format>SQLITE_MAX_FILE_FORMAT ){
    +      sqlite3SetString(pzErrMsg, db, "unsupported file format");
    +@@ -127,7 +127,7 @@ diff -r -u -d orig/sqlite3.c ./sqlite3.c
    +      goto initone_error_out;
    +    }
    +  
    +-@@ -139786,16 +139804,28 @@
    ++@@ -139799,16 +139817,28 @@
    +    ** module with sqlite.
    +    */
    +    if( SQLITE_OK==rc 
    +diff --git a/dist/orig/sqlite3.c b/dist/orig/sqlite3.c
    +index 0ae407d..f943a00 100644
    +--- a/dist/orig/sqlite3.c
    ++++ b/dist/orig/sqlite3.c
    +@@ -327,7 +327,7 @@ extern "C" {
    + */
    + #define SQLITE_VERSION        "3.9.2"
    + #define SQLITE_VERSION_NUMBER 3009002
    +-#define SQLITE_SOURCE_ID      "2015-11-02 18:31:45 bda77dda9697c463c3d0704014d51627fceee328"
    ++#define SQLITE_SOURCE_ID      "2017-07-21 07:45:23 69906880cee1f246cce494672402e0c7f29bd4ec19c437d26d603870d2bd625d"
    + 
    + /*
    + ** CAPI3REF: Run-Time Library Version Numbers
    +@@ -4566,6 +4566,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_value_bytes16(sqlite3_value*);
    + SQLITE_API double SQLITE_STDCALL sqlite3_value_double(sqlite3_value*);
    + SQLITE_API int SQLITE_STDCALL sqlite3_value_int(sqlite3_value*);
    + SQLITE_API sqlite3_int64 SQLITE_STDCALL sqlite3_value_int64(sqlite3_value*);
    ++SQLITE_API void *SQLITE_STDCALL sqlite3_value_pointer(sqlite3_value*);
    + SQLITE_API const unsigned char *SQLITE_STDCALL sqlite3_value_text(sqlite3_value*);
    + SQLITE_API const void *SQLITE_STDCALL sqlite3_value_text16(sqlite3_value*);
    + SQLITE_API const void *SQLITE_STDCALL sqlite3_value_text16le(sqlite3_value*);
    +@@ -4878,6 +4879,7 @@ SQLITE_API void SQLITE_STDCALL sqlite3_result_error_code(sqlite3_context*, int);
    + SQLITE_API void SQLITE_STDCALL sqlite3_result_int(sqlite3_context*, int);
    + SQLITE_API void SQLITE_STDCALL sqlite3_result_int64(sqlite3_context*, sqlite3_int64);
    + SQLITE_API void SQLITE_STDCALL sqlite3_result_null(sqlite3_context*);
    ++SQLITE_API void SQLITE_STDCALL sqlite3_result_pointer(sqlite3_context*, void*);
    + SQLITE_API void SQLITE_STDCALL sqlite3_result_text(sqlite3_context*, const char*, int, void(*)(void*));
    + SQLITE_API void SQLITE_STDCALL sqlite3_result_text64(sqlite3_context*, const char*,sqlite3_uint64,
    +                            void(*)(void*), unsigned char encoding);
    +@@ -15415,6 +15417,7 @@ struct Mem {
    +     double r;           /* Real value used when MEM_Real is set in flags */
    +     i64 i;              /* Integer value used when MEM_Int is set in flags */
    +     int nZero;          /* Used when bit MEM_Zero is set in flags */
    ++    void *pPtr;         /* Pointer when flags==MEM_Ptr|MEM_Null */
    +     FuncDef *pDef;      /* Used only when flags==MEM_Agg */
    +     RowSet *pRowSet;    /* Used only when flags==MEM_RowSet */
    +     VdbeFrame *pFrame;  /* Used when flags==MEM_Frame */
    +@@ -15472,6 +15475,7 @@ struct Mem {
    + ** policy for Mem.z.  The MEM_Term flag tells us whether or not the
    + ** string is \000 or \u0000 terminated
    + */
    ++#define MEM_Ptr       0x8000   /* u.pPtr is valid if type==SQLITE_NULL */
    + #define MEM_Term      0x0200   /* String rep is nul terminated */
    + #define MEM_Dyn       0x0400   /* Need to call Mem.xDel() on Mem.z */
    + #define MEM_Static    0x0800   /* Mem.z points to a static string */
    +@@ -15487,7 +15491,7 @@ struct Mem {
    + ** Clear any existing type flags from a Mem and replace them with f
    + */
    + #define MemSetTypeFlag(p, f) \
    +-   ((p)->flags = ((p)->flags&~(MEM_TypeMask|MEM_Zero))|f)
    ++   ((p)->flags = ((p)->flags&~(MEM_TypeMask|MEM_Zero|MEM_Ptr))|f)
    + 
    + /*
    + ** Return true if a memory cell is not marked as invalid.  This macro
    +@@ -71138,6 +71142,11 @@ SQLITE_API sqlite_int64 SQLITE_STDCALL sqlite3_value_int64(sqlite3_value *pVal){
    + SQLITE_API unsigned int SQLITE_STDCALL sqlite3_value_subtype(sqlite3_value *pVal){
    +   return ((Mem*)pVal)->eSubtype;
    + }
    ++SQLITE_API void *SQLITE_STDCALL sqlite3_value_pointer(sqlite3_value *pVal){
    ++  Mem *p = (Mem*)pVal;
    ++  if( (p->flags&(MEM_TypeMask|MEM_Ptr))==(MEM_Null|MEM_Ptr) ) return p->u.pPtr;
    ++  return 0;
    ++}
    + SQLITE_API const unsigned char *SQLITE_STDCALL sqlite3_value_text(sqlite3_value *pVal){
    +   return (const unsigned char *)sqlite3ValueText(pVal, SQLITE_UTF8);
    + }
    +@@ -71312,6 +71321,13 @@ SQLITE_API void SQLITE_STDCALL sqlite3_result_int64(sqlite3_context *pCtx, i64 i
    +   assert( sqlite3_mutex_held(pCtx->pOut->db->mutex) );
    +   sqlite3VdbeMemSetInt64(pCtx->pOut, iVal);
    + }
    ++SQLITE_API void SQLITE_STDCALL sqlite3_result_pointer(sqlite3_context *pCtx, void *pPtr){
    ++  assert( sqlite3_mutex_held(pCtx->pOut->db->mutex) );
    ++  sqlite3VdbeMemSetNull(pCtx->pOut);
    ++  assert( (pCtx->pOut->flags & (MEM_TypeMask|MEM_Ptr))==MEM_Null );
    ++  pCtx->pOut->flags |= MEM_Ptr;
    ++  pCtx->pOut->u.pPtr = pPtr;
    ++}
    + SQLITE_API void SQLITE_STDCALL sqlite3_result_null(sqlite3_context *pCtx){
    +   assert( sqlite3_mutex_held(pCtx->pOut->db->mutex) );
    +   sqlite3VdbeMemSetNull(pCtx->pOut);
    +@@ -139172,7 +139188,7 @@ static int fts3ColumnMethod(
    +   }else if( iCol==p->nColumn ){
    +     /* The extra column whose name is the same as the table.
    +     ** Return a blob which is a pointer to the cursor.  */
    +-    sqlite3_result_blob(pCtx, &pCsr, sizeof(pCsr), SQLITE_TRANSIENT);
    ++    sqlite3_result_pointer(pCtx, pCsr);
    +   }else if( iCol==p->nColumn+2 && pCsr->pExpr ){
    +     sqlite3_result_int64(pCtx, pCsr->iLangid);
    +   }else{
    +@@ -139384,16 +139400,13 @@ static int fts3FunctionArg(
    +   sqlite3_value *pVal,            /* argv[0] passed to function */
    +   Fts3Cursor **ppCsr              /* OUT: Store cursor handle here */
    + ){
    +-  Fts3Cursor *pRet;
    +-  if( sqlite3_value_type(pVal)!=SQLITE_BLOB 
    +-   || sqlite3_value_bytes(pVal)!=sizeof(Fts3Cursor *)
    +-  ){
    ++  Fts3Cursor *pRet = (Fts3Cursor*)sqlite3_value_pointer(pVal);
    ++  if( pRet==0 ){
    +     char *zErr = sqlite3_mprintf("illegal first argument to %s", zFunc);
    +     sqlite3_result_error(pContext, zErr, -1);
    +     sqlite3_free(zErr);
    +     return SQLITE_ERROR;
    +   }
    +-  memcpy(&pRet, sqlite3_value_blob(pVal), sizeof(Fts3Cursor *));
    +   *ppCsr = pRet;
    +   return SQLITE_OK;
    + }
    +@@ -180602,7 +180615,7 @@ static void fts5SourceIdFunc(
    +   sqlite3_value **apVal           /* Function arguments */
    + ){
    +   assert( nArg==0 );
    +-  sqlite3_result_text(pCtx, "fts5: 2015-11-02 18:31:45 bda77dda9697c463c3d0704014d51627fceee328", -1, SQLITE_TRANSIENT);
    ++  sqlite3_result_text(pCtx, "fts5: 2017-07-21 07:45:23 69906880cee1f246cce494672402e0c7f29bd4ec19c437d26d603870d2bd625d", -1, SQLITE_TRANSIENT);
    + }
    + 
    + static int fts5Init(sqlite3 *db){
    +diff --git a/dist/orig/sqlite3.h b/dist/orig/sqlite3.h
    +index 7cca0ac..a0c0e4e 100644
    +--- a/dist/orig/sqlite3.h
    ++++ b/dist/orig/sqlite3.h
    +@@ -113,7 +113,7 @@ extern "C" {
    + */
    + #define SQLITE_VERSION        "3.9.2"
    + #define SQLITE_VERSION_NUMBER 3009002
    +-#define SQLITE_SOURCE_ID      "2015-11-02 18:31:45 bda77dda9697c463c3d0704014d51627fceee328"
    ++#define SQLITE_SOURCE_ID      "2017-07-21 07:45:23 69906880cee1f246cce494672402e0c7f29bd4ec19c437d26d603870d2bd625d"
    + 
    + /*
    + ** CAPI3REF: Run-Time Library Version Numbers
    +@@ -4352,6 +4352,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_value_bytes16(sqlite3_value*);
    + SQLITE_API double SQLITE_STDCALL sqlite3_value_double(sqlite3_value*);
    + SQLITE_API int SQLITE_STDCALL sqlite3_value_int(sqlite3_value*);
    + SQLITE_API sqlite3_int64 SQLITE_STDCALL sqlite3_value_int64(sqlite3_value*);
    ++SQLITE_API void *SQLITE_STDCALL sqlite3_value_pointer(sqlite3_value*);
    + SQLITE_API const unsigned char *SQLITE_STDCALL sqlite3_value_text(sqlite3_value*);
    + SQLITE_API const void *SQLITE_STDCALL sqlite3_value_text16(sqlite3_value*);
    + SQLITE_API const void *SQLITE_STDCALL sqlite3_value_text16le(sqlite3_value*);
    +@@ -4664,6 +4665,7 @@ SQLITE_API void SQLITE_STDCALL sqlite3_result_error_code(sqlite3_context*, int);
    + SQLITE_API void SQLITE_STDCALL sqlite3_result_int(sqlite3_context*, int);
    + SQLITE_API void SQLITE_STDCALL sqlite3_result_int64(sqlite3_context*, sqlite3_int64);
    + SQLITE_API void SQLITE_STDCALL sqlite3_result_null(sqlite3_context*);
    ++SQLITE_API void SQLITE_STDCALL sqlite3_result_pointer(sqlite3_context*, void*);
    + SQLITE_API void SQLITE_STDCALL sqlite3_result_text(sqlite3_context*, const char*, int, void(*)(void*));
    + SQLITE_API void SQLITE_STDCALL sqlite3_result_text64(sqlite3_context*, const char*,sqlite3_uint64,
    +                            void(*)(void*), unsigned char encoding);
    +diff --git a/dist/sqlite3.c b/dist/sqlite3.c
    +index b0536a4..715b2f7 100644
    +--- a/dist/sqlite3.c
    ++++ b/dist/sqlite3.c
    +@@ -327,7 +327,7 @@ extern "C" {
    + */
    + #define SQLITE_VERSION        "3.9.2"
    + #define SQLITE_VERSION_NUMBER 3009002
    +-#define SQLITE_SOURCE_ID      "2015-11-02 18:31:45 bda77dda9697c463c3d0704014d51627fceee328"
    ++#define SQLITE_SOURCE_ID      "2017-07-21 07:45:23 69906880cee1f246cce494672402e0c7f29bd4ec19c437d26d603870d2bd625d"
    + 
    + /*
    + ** CAPI3REF: Run-Time Library Version Numbers
    +@@ -4566,6 +4566,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_value_bytes16(sqlite3_value*);
    + SQLITE_API double SQLITE_STDCALL sqlite3_value_double(sqlite3_value*);
    + SQLITE_API int SQLITE_STDCALL sqlite3_value_int(sqlite3_value*);
    + SQLITE_API sqlite3_int64 SQLITE_STDCALL sqlite3_value_int64(sqlite3_value*);
    ++SQLITE_API void *SQLITE_STDCALL sqlite3_value_pointer(sqlite3_value*);
    + SQLITE_API const unsigned char *SQLITE_STDCALL sqlite3_value_text(sqlite3_value*);
    + SQLITE_API const void *SQLITE_STDCALL sqlite3_value_text16(sqlite3_value*);
    + SQLITE_API const void *SQLITE_STDCALL sqlite3_value_text16le(sqlite3_value*);
    +@@ -4878,6 +4879,7 @@ SQLITE_API void SQLITE_STDCALL sqlite3_result_error_code(sqlite3_context*, int);
    + SQLITE_API void SQLITE_STDCALL sqlite3_result_int(sqlite3_context*, int);
    + SQLITE_API void SQLITE_STDCALL sqlite3_result_int64(sqlite3_context*, sqlite3_int64);
    + SQLITE_API void SQLITE_STDCALL sqlite3_result_null(sqlite3_context*);
    ++SQLITE_API void SQLITE_STDCALL sqlite3_result_pointer(sqlite3_context*, void*);
    + SQLITE_API void SQLITE_STDCALL sqlite3_result_text(sqlite3_context*, const char*, int, void(*)(void*));
    + SQLITE_API void SQLITE_STDCALL sqlite3_result_text64(sqlite3_context*, const char*,sqlite3_uint64,
    +                            void(*)(void*), unsigned char encoding);
    +@@ -15415,6 +15417,7 @@ struct Mem {
    +     double r;           /* Real value used when MEM_Real is set in flags */
    +     i64 i;              /* Integer value used when MEM_Int is set in flags */
    +     int nZero;          /* Used when bit MEM_Zero is set in flags */
    ++    void *pPtr;         /* Pointer when flags==MEM_Ptr|MEM_Null */
    +     FuncDef *pDef;      /* Used only when flags==MEM_Agg */
    +     RowSet *pRowSet;    /* Used only when flags==MEM_RowSet */
    +     VdbeFrame *pFrame;  /* Used when flags==MEM_Frame */
    +@@ -15472,6 +15475,7 @@ struct Mem {
    + ** policy for Mem.z.  The MEM_Term flag tells us whether or not the
    + ** string is \000 or \u0000 terminated
    + */
    ++#define MEM_Ptr       0x8000   /* u.pPtr is valid if type==SQLITE_NULL */
    + #define MEM_Term      0x0200   /* String rep is nul terminated */
    + #define MEM_Dyn       0x0400   /* Need to call Mem.xDel() on Mem.z */
    + #define MEM_Static    0x0800   /* Mem.z points to a static string */
    +@@ -15487,7 +15491,7 @@ struct Mem {
    + ** Clear any existing type flags from a Mem and replace them with f
    + */
    + #define MemSetTypeFlag(p, f) \
    +-   ((p)->flags = ((p)->flags&~(MEM_TypeMask|MEM_Zero))|f)
    ++   ((p)->flags = ((p)->flags&~(MEM_TypeMask|MEM_Zero|MEM_Ptr))|f)
    + 
    + /*
    + ** Return true if a memory cell is not marked as invalid.  This macro
    +@@ -71156,6 +71160,11 @@ SQLITE_API sqlite_int64 SQLITE_STDCALL sqlite3_value_int64(sqlite3_value *pVal){
    + SQLITE_API unsigned int SQLITE_STDCALL sqlite3_value_subtype(sqlite3_value *pVal){
    +   return ((Mem*)pVal)->eSubtype;
    + }
    ++SQLITE_API void *SQLITE_STDCALL sqlite3_value_pointer(sqlite3_value *pVal){
    ++  Mem *p = (Mem*)pVal;
    ++  if( (p->flags&(MEM_TypeMask|MEM_Ptr))==(MEM_Null|MEM_Ptr) ) return p->u.pPtr;
    ++  return 0;
    ++}
    + SQLITE_API const unsigned char *SQLITE_STDCALL sqlite3_value_text(sqlite3_value *pVal){
    +   return (const unsigned char *)sqlite3ValueText(pVal, SQLITE_UTF8);
    + }
    +@@ -71330,6 +71339,13 @@ SQLITE_API void SQLITE_STDCALL sqlite3_result_int64(sqlite3_context *pCtx, i64 i
    +   assert( sqlite3_mutex_held(pCtx->pOut->db->mutex) );
    +   sqlite3VdbeMemSetInt64(pCtx->pOut, iVal);
    + }
    ++SQLITE_API void SQLITE_STDCALL sqlite3_result_pointer(sqlite3_context *pCtx, void *pPtr){
    ++  assert( sqlite3_mutex_held(pCtx->pOut->db->mutex) );
    ++  sqlite3VdbeMemSetNull(pCtx->pOut);
    ++  assert( (pCtx->pOut->flags & (MEM_TypeMask|MEM_Ptr))==MEM_Null );
    ++  pCtx->pOut->flags |= MEM_Ptr;
    ++  pCtx->pOut->u.pPtr = pPtr;
    ++}
    + SQLITE_API void SQLITE_STDCALL sqlite3_result_null(sqlite3_context *pCtx){
    +   assert( sqlite3_mutex_held(pCtx->pOut->db->mutex) );
    +   sqlite3VdbeMemSetNull(pCtx->pOut);
    +@@ -139190,7 +139206,7 @@ static int fts3ColumnMethod(
    +   }else if( iCol==p->nColumn ){
    +     /* The extra column whose name is the same as the table.
    +     ** Return a blob which is a pointer to the cursor.  */
    +-    sqlite3_result_blob(pCtx, &pCsr, sizeof(pCsr), SQLITE_TRANSIENT);
    ++    sqlite3_result_pointer(pCtx, pCsr);
    +   }else if( iCol==p->nColumn+2 && pCsr->pExpr ){
    +     sqlite3_result_int64(pCtx, pCsr->iLangid);
    +   }else{
    +@@ -139402,16 +139418,13 @@ static int fts3FunctionArg(
    +   sqlite3_value *pVal,            /* argv[0] passed to function */
    +   Fts3Cursor **ppCsr              /* OUT: Store cursor handle here */
    + ){
    +-  Fts3Cursor *pRet;
    +-  if( sqlite3_value_type(pVal)!=SQLITE_BLOB 
    +-   || sqlite3_value_bytes(pVal)!=sizeof(Fts3Cursor *)
    +-  ){
    ++  Fts3Cursor *pRet = (Fts3Cursor*)sqlite3_value_pointer(pVal);
    ++  if( pRet==0 ){
    +     char *zErr = sqlite3_mprintf("illegal first argument to %s", zFunc);
    +     sqlite3_result_error(pContext, zErr, -1);
    +     sqlite3_free(zErr);
    +     return SQLITE_ERROR;
    +   }
    +-  memcpy(&pRet, sqlite3_value_blob(pVal), sizeof(Fts3Cursor *));
    +   *ppCsr = pRet;
    +   return SQLITE_OK;
    + }
    +@@ -180632,7 +180645,7 @@ static void fts5SourceIdFunc(
    +   sqlite3_value **apVal           /* Function arguments */
    + ){
    +   assert( nArg==0 );
    +-  sqlite3_result_text(pCtx, "fts5: 2015-11-02 18:31:45 bda77dda9697c463c3d0704014d51627fceee328", -1, SQLITE_TRANSIENT);
    ++  sqlite3_result_text(pCtx, "fts5: 2017-07-21 07:45:23 69906880cee1f246cce494672402e0c7f29bd4ec19c437d26d603870d2bd625d", -1, SQLITE_TRANSIENT);
    + }
    + 
    + static int fts5Init(sqlite3 *db){
    +diff --git a/dist/sqlite3.h b/dist/sqlite3.h
    +index 7cca0ac..a0c0e4e 100644
    +--- a/dist/sqlite3.h
    ++++ b/dist/sqlite3.h
    +@@ -113,7 +113,7 @@ extern "C" {
    + */
    + #define SQLITE_VERSION        "3.9.2"
    + #define SQLITE_VERSION_NUMBER 3009002
    +-#define SQLITE_SOURCE_ID      "2015-11-02 18:31:45 bda77dda9697c463c3d0704014d51627fceee328"
    ++#define SQLITE_SOURCE_ID      "2017-07-21 07:45:23 69906880cee1f246cce494672402e0c7f29bd4ec19c437d26d603870d2bd625d"
    + 
    + /*
    + ** CAPI3REF: Run-Time Library Version Numbers
    +@@ -4352,6 +4352,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_value_bytes16(sqlite3_value*);
    + SQLITE_API double SQLITE_STDCALL sqlite3_value_double(sqlite3_value*);
    + SQLITE_API int SQLITE_STDCALL sqlite3_value_int(sqlite3_value*);
    + SQLITE_API sqlite3_int64 SQLITE_STDCALL sqlite3_value_int64(sqlite3_value*);
    ++SQLITE_API void *SQLITE_STDCALL sqlite3_value_pointer(sqlite3_value*);
    + SQLITE_API const unsigned char *SQLITE_STDCALL sqlite3_value_text(sqlite3_value*);
    + SQLITE_API const void *SQLITE_STDCALL sqlite3_value_text16(sqlite3_value*);
    + SQLITE_API const void *SQLITE_STDCALL sqlite3_value_text16le(sqlite3_value*);
    +@@ -4664,6 +4665,7 @@ SQLITE_API void SQLITE_STDCALL sqlite3_result_error_code(sqlite3_context*, int);
    + SQLITE_API void SQLITE_STDCALL sqlite3_result_int(sqlite3_context*, int);
    + SQLITE_API void SQLITE_STDCALL sqlite3_result_int64(sqlite3_context*, sqlite3_int64);
    + SQLITE_API void SQLITE_STDCALL sqlite3_result_null(sqlite3_context*);
    ++SQLITE_API void SQLITE_STDCALL sqlite3_result_pointer(sqlite3_context*, void*);
    + SQLITE_API void SQLITE_STDCALL sqlite3_result_text(sqlite3_context*, const char*, int, void(*)(void*));
    + SQLITE_API void SQLITE_STDCALL sqlite3_result_text64(sqlite3_context*, const char*,sqlite3_uint64,
    +                            void(*)(void*), unsigned char encoding);
    +diff --git a/dist/version b/dist/version
    +deleted file mode 100644
    +index 6fadefa..0000000
    +--- a/dist/version
    ++++ /dev/null
    +@@ -1 +0,0 @@
    +-downloaded from http://www.sqlite.org/2014/sqlite-amalgamation-3080600.zip
    diff --git a/external_tremolo.patch b/external_tremolo.patch
    new file mode 100644
    index 0000000..dae3d8e
    --- /dev/null
    +++ b/external_tremolo.patch
    @@ -0,0 +1,99 @@
    +diff --git a/Tremolo/res012.c b/Tremolo/res012.c
    +index 513d9ad..d6495fb 100644
    +--- a/Tremolo/res012.c
    ++++ b/Tremolo/res012.c
    +@@ -126,10 +126,13 @@ int res_inverse(vorbis_dsp_state *vd,vorbis_info_residue *info,
    + 
    +       if(used){
    + 
    +-        char **partword=(char **)alloca(ch*sizeof(*partword));
    +-        for(j=0;j<ch;j++)
    +-          partword[j]=(char *)alloca(partwords*partitions_per_word*
    +-                                     sizeof(*partword[j]));
    ++        char **partword=(char **)_ogg_calloc(ch,sizeof(*partword));
    ++        if(partword==NULL)goto cleanup1;
    ++        for(j=0;j<ch;j++){
    ++          partword[j]=(char *)_ogg_malloc(partwords*partitions_per_word*
    ++                                          sizeof(*partword[j]));
    ++          if(partword[j]==NULL)goto cleanup1;
    ++        }
    + 
    +         for(s=0;s<info->stages;s++){
    + 
    +@@ -147,7 +150,7 @@ int res_inverse(vorbis_dsp_state *vd,vorbis_info_residue *info,
    + 
    +               for(j=0;j<ch;j++){
    +                 int temp=vorbis_book_decode(phrasebook,&vd->opb);
    +-                if(temp==-1)goto eopbreak;
    ++                if(temp==-1)goto cleanup1;
    + 
    +                 /* this can be done quickly in assembly due to the quotient
    +                    always being at most six bits */
    +@@ -171,16 +174,23 @@ int res_inverse(vorbis_dsp_state *vd,vorbis_info_residue *info,
    +                   if(info->type){
    +                     if(vorbis_book_decodev_add(stagebook,in[j]+offset,&vd->opb,
    +                                                samples_per_partition,-8)==-1)
    +-                      goto eopbreak;
    ++                      goto cleanup1;
    +                   }else{
    +                     if(vorbis_book_decodevs_add(stagebook,in[j]+offset,&vd->opb,
    +                                                 samples_per_partition,-8)==-1)
    +-                      goto eopbreak;
    ++                      goto cleanup1;
    +                   }
    +                 }
    +               }
    +           }
    +         }
    ++ cleanup1:
    ++        if(partword){
    ++          for(j=0;j<ch;j++){
    ++            if(partword[j])_ogg_free(partword[j]);
    ++          }
    ++          _ogg_free(partword);
    ++        }
    +       }
    +     }
    +   }else{
    +@@ -193,11 +203,12 @@ int res_inverse(vorbis_dsp_state *vd,vorbis_info_residue *info,
    +       int partwords=(partvals+partitions_per_word-1)/partitions_per_word;
    + 
    +       char *partword=
    +-        (char *)alloca(partwords*partitions_per_word*sizeof(*partword));
    ++        (char *)_ogg_malloc(partwords*partitions_per_word*sizeof(*partword));
    ++      if(partword==NULL)goto cleanup2;
    +       int beginoff=info->begin/ch;
    + 
    +       for(i=0;i<ch;i++)if(nonzero[i])break;
    +-      if(i==ch)return(0); /* no nonzero vectors */
    ++      if(i==ch)goto cleanup2; /* no nonzero vectors */
    + 
    +       samples_per_partition/=ch;
    + 
    +@@ -212,7 +223,7 @@ int res_inverse(vorbis_dsp_state *vd,vorbis_info_residue *info,
    + 
    +             /* fetch the partition word */
    +             temp=vorbis_book_decode(phrasebook,&vd->opb);
    +-            if(temp==-1)goto eopbreak;
    ++            if(temp==-1)goto cleanup2;
    + 
    +             /* this can be done quickly in assembly due to the quotient
    +                always being at most six bits */
    +@@ -233,14 +244,15 @@ int res_inverse(vorbis_dsp_state *vd,vorbis_info_residue *info,
    +                               i*samples_per_partition+beginoff,ch,
    +                               &vd->opb,
    +                               samples_per_partition,-8)==-1)
    +-                      goto eopbreak;
    ++                      goto cleanup2;
    +               }
    +           }
    +         }
    +       }
    ++ cleanup2:
    ++      if(partword)_ogg_free(partword);
    +     }
    +   }
    +- eopbreak:
    + 
    +   return 0;
    + }
    diff --git a/frameworks_av.patch b/frameworks_av.patch
    index 36a3471..22966f3 100644
    --- a/frameworks_av.patch
    +++ b/frameworks_av.patch
    @@ -102,6 +102,139 @@ index 3051406..870bb9b 100644
      
          size_t buffers() const { return mBuffers.size(); }
      
    +diff --git a/media/libeffects/lvm/wrapper/Bundle/EffectBundle.cpp b/media/libeffects/lvm/wrapper/Bundle/EffectBundle.cpp
    +index dcf3fa0..07ea818 100644
    +--- a/media/libeffects/lvm/wrapper/Bundle/EffectBundle.cpp
    ++++ b/media/libeffects/lvm/wrapper/Bundle/EffectBundle.cpp
    +@@ -2439,6 +2439,13 @@ int Equalizer_getParameter(EffectContext     *pContext,
    +             }
    +             break;
    +         }
    ++
    ++        if (*pValueSize < 1) {
    ++            status = -EINVAL;
    ++            android_errorWriteLog(0x534e4554, "37536407");
    ++            break;
    ++        }
    ++
    +         name = (char *)pValue;
    +         strncpy(name, EqualizerGetPresetName(param2), *pValueSize - 1);
    +         name[*pValueSize - 1] = 0;
    +diff --git a/media/libmedia/IDataSource.cpp b/media/libmedia/IDataSource.cpp
    +index 51c9938..5ad39fe 100644
    +--- a/media/libmedia/IDataSource.cpp
    ++++ b/media/libmedia/IDataSource.cpp
    +@@ -54,8 +54,16 @@ struct BpDataSource : public BpInterface<IDataSource> {
    +         data.writeInterfaceToken(IDataSource::getInterfaceDescriptor());
    +         data.writeInt64(offset);
    +         data.writeInt64(size);
    +-        remote()->transact(READ_AT, data, &reply);
    +-        return reply.readInt64();
    ++        status_t err = remote()->transact(READ_AT, data, &reply);
    ++        if (err != OK) {
    ++            return err;
    ++        }
    ++        int64_t value = 0;
    ++        err = reply.readInt64(&value);
    ++        if (err != OK) {
    ++            return err;
    ++        }
    ++        return (ssize_t)value;
    +     }
    + 
    +     virtual status_t getSize(off64_t* size) {
    +diff --git a/media/libmediaplayerservice/MediaPlayerService.cpp b/media/libmediaplayerservice/MediaPlayerService.cpp
    +index bd16e91..6e689e6 100644
    +--- a/media/libmediaplayerservice/MediaPlayerService.cpp
    ++++ b/media/libmediaplayerservice/MediaPlayerService.cpp
    +@@ -82,6 +82,9 @@
    + #include "HTTPBase.h"
    + #include "RemoteDisplay.h"
    + 
    ++static const int kDumpLockRetries = 50;
    ++static const int kDumpLockSleepUs = 20000;
    ++
    + namespace {
    + using android::media::Metadata;
    + using android::status_t;
    +@@ -405,12 +408,32 @@ status_t MediaPlayerService::Client::dump(int fd, const Vector<String16>& args)
    +     snprintf(buffer, 255, "  pid(%d), connId(%d), status(%d), looping(%s)\n",
    +             mPid, mConnId, mStatus, mLoop?"true": "false");
    +     result.append(buffer);
    ++
    ++    sp<MediaPlayerBase> p;
    ++    sp<AudioOutput> audioOutput;
    ++    bool locked = false;
    ++    for (int i = 0; i < kDumpLockRetries; ++i) {
    ++        if (mLock.tryLock() == NO_ERROR) {
    ++            locked = true;
    ++            break;
    ++        }
    ++        usleep(kDumpLockSleepUs);
    ++    }
    ++
    ++    if (locked) {
    ++        p = mPlayer;
    ++        audioOutput = mAudioOutput;
    ++        mLock.unlock();
    ++    } else {
    ++        result.append("  lock is taken, no dump from player and audio output\n");
    ++    }
    +     write(fd, result.string(), result.size());
    +-    if (mPlayer != NULL) {
    +-        mPlayer->dump(fd, args);
    ++
    ++    if (p != NULL) {
    ++        p->dump(fd, args);
    +     }
    +-    if (mAudioOutput != 0) {
    +-        mAudioOutput->dump(fd, args);
    ++    if (audioOutput != 0) {
    ++        audioOutput->dump(fd, args);
    +     }
    +     write(fd, "\n", 1);
    +     return NO_ERROR;
    +@@ -590,7 +613,10 @@ MediaPlayerService::Client::Client(
    + MediaPlayerService::Client::~Client()
    + {
    +     ALOGV("Client(%d) destructor pid = %d", mConnId, mPid);
    +-    mAudioOutput.clear();
    ++    {
    ++        Mutex::Autolock l(mLock);
    ++        mAudioOutput.clear();
    ++    }
    +     wp<Client> client(this);
    +     disconnect();
    +     mService->removeClient(client);
    +@@ -609,10 +635,9 @@ void MediaPlayerService::Client::disconnect()
    +         Mutex::Autolock l(mLock);
    +         p = mPlayer;
    +         mClient.clear();
    ++        mPlayer.clear();
    +     }
    + 
    +-    mPlayer.clear();
    +-
    +     // clear the notification to prevent callbacks to dead client
    +     // and reset the player. We assume the player will serialize
    +     // access to itself if necessary.
    +@@ -633,7 +658,7 @@ void MediaPlayerService::Client::disconnect()
    + sp<MediaPlayerBase> MediaPlayerService::Client::createPlayer(player_type playerType)
    + {
    +     // determine if we have the right player type
    +-    sp<MediaPlayerBase> p = mPlayer;
    ++    sp<MediaPlayerBase> p = getPlayer();
    +     if ((p != NULL) && (p->playerType() != playerType)) {
    +         ALOGV("delete player");
    +         p.clear();
    +@@ -721,6 +746,7 @@ void MediaPlayerService::Client::setDataSource_post(
    +     }
    + 
    +     if (mStatus == OK) {
    ++        Mutex::Autolock l(mLock);
    +         mPlayer = p;
    +     }
    + }
     diff --git a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp
     index dc4e5d4..b64d899 100644
     --- a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp
    @@ -273,10 +406,25 @@ index 3848502..1635375 100644
      
      # enable experiments only in userdebug and eng builds
     diff --git a/media/libstagefright/CameraSource.cpp b/media/libstagefright/CameraSource.cpp
    -index 893da89..0bc6847 100644
    +index 893da89..2152454 100644
     --- a/media/libstagefright/CameraSource.cpp
     +++ b/media/libstagefright/CameraSource.cpp
    -@@ -1117,7 +1117,7 @@ void CameraSource::releaseRecordingFrameHandle(native_handle_t* handle) {
    +@@ -950,6 +950,14 @@ void CameraSource::releaseRecordingFrame(const sp<IMemory>& frame) {
    + 
    +         if (handle != nullptr) {
    +             // Frame contains a VideoNativeHandleMetadata. Send the handle back to camera.
    ++            ssize_t offset;
    ++            size_t size;
    ++            sp<IMemoryHeap> heap = frame->getMemory(&offset, &size);
    ++            if (heap->getHeapID() != mMemoryHeapBase->getHeapID()) {
    ++                ALOGE("%s: Mismatched heap ID, ignoring release (got %x, expected %x)",
    ++		     __FUNCTION__, heap->getHeapID(), mMemoryHeapBase->getHeapID());
    ++                return;
    ++            }
    +             releaseRecordingFrameHandle(handle);
    +             mMemoryBases.push_back(frame);
    +             mMemoryBaseAvailableCond.signal();
    +@@ -1117,7 +1125,7 @@ void CameraSource::releaseRecordingFrameHandle(native_handle_t* handle) {
              int64_t token = IPCThreadState::self()->clearCallingIdentity();
              mCamera->releaseRecordingFrameHandle(handle);
              IPCThreadState::self()->restoreCallingIdentity(token);
    @@ -285,7 +433,7 @@ index 893da89..0bc6847 100644
              native_handle_close(handle);
              native_handle_delete(handle);
          }
    -@@ -1250,6 +1250,10 @@ void CameraSource::processBufferQueueFrame(BufferItem& buffer) {
    +@@ -1250,6 +1258,10 @@ void CameraSource::processBufferQueueFrame(BufferItem& buffer) {
      MetadataBufferType CameraSource::metaDataStoredInVideoBuffers() const {
          ALOGV("metaDataStoredInVideoBuffers");
      
    @@ -296,6 +444,193 @@ index 893da89..0bc6847 100644
          // Output buffers will contain metadata if camera sends us buffer in metadata mode or via
          // buffer queue.
          switch (mVideoBufferMode) {
    +diff --git a/media/libstagefright/MPEG4Extractor.cpp b/media/libstagefright/MPEG4Extractor.cpp
    +index 5441714..2cc43c1 100644
    +--- a/media/libstagefright/MPEG4Extractor.cpp
    ++++ b/media/libstagefright/MPEG4Extractor.cpp
    +@@ -72,6 +72,7 @@ public:
    +                 Vector<SidxEntry> &sidx,
    +                 const Trex *trex,
    +                 off64_t firstMoofOffset);
    ++    virtual status_t init();
    + 
    +     virtual status_t start(MetaData *params = NULL);
    +     virtual status_t stop();
    +@@ -2148,7 +2149,10 @@ status_t MPEG4Extractor::parseChunk(off64_t *offset, int depth) {
    +             *offset += chunk_size;
    + 
    +             if (underQTMetaPath(mPath, 3)) {
    +-                parseQTMetaKey(data_offset, chunk_data_size);
    ++                status_t err = parseQTMetaKey(data_offset, chunk_data_size);
    ++                if (err != OK) {
    ++                    return err;
    ++                }
    +             }
    +             break;
    +         }
    +@@ -2307,7 +2311,10 @@ status_t MPEG4Extractor::parseChunk(off64_t *offset, int depth) {
    + 
    +         case FOURCC('s', 'i', 'd', 'x'):
    +         {
    +-            parseSegmentIndex(data_offset, chunk_data_size);
    ++            status_t err = parseSegmentIndex(data_offset, chunk_data_size);
    ++            if (err != OK) {
    ++                return err;
    ++            }
    +             *offset += chunk_size;
    +             return UNKNOWN_ERROR; // stop parsing after sidx
    +         }
    +@@ -2349,7 +2356,10 @@ status_t MPEG4Extractor::parseChunk(off64_t *offset, int depth) {
    +             // check if we're parsing 'ilst' for meta keys
    +             // if so, treat type as a number (key-id).
    +             if (underQTMetaPath(mPath, 3)) {
    +-                parseQTMetaVal(chunk_type, data_offset, chunk_data_size);
    ++                status_t err = parseQTMetaVal(chunk_type, data_offset, chunk_data_size);
    ++                if (err != OK) {
    ++                    return err;
    ++                }
    +             }
    + 
    +             *offset += chunk_size;
    +@@ -2984,6 +2994,13 @@ status_t MPEG4Extractor::parse3GPPMetaData(off64_t offset, size_t size, int dept
    +         }
    +         case FOURCC('y', 'r', 'r', 'c'):
    +         {
    ++            if (size < 6) {
    ++                delete[] buffer;
    ++                buffer = NULL;
    ++                ALOGE("b/62133227");
    ++                android_errorWriteLog(0x534e4554, "62133227");
    ++                return ERROR_MALFORMED;
    ++            }
    +             char tmp[5];
    +             uint16_t year = U16_AT(&buffer[4]);
    + 
    +@@ -3006,6 +3023,8 @@ status_t MPEG4Extractor::parse3GPPMetaData(off64_t offset, size_t size, int dept
    + 
    +         // smallest possible valid UTF-16 string w BOM: 0xfe 0xff 0x00 0x00
    +         if (size < 6) {
    ++            delete[] buffer;
    ++            buffer = NULL;
    +             return ERROR_MALFORMED;
    +         }
    + 
    +@@ -3174,9 +3193,13 @@ sp<IMediaSource> MPEG4Extractor::getTrack(size_t index) {
    +         }
    +     }
    + 
    +-    return new MPEG4Source(this,
    ++    sp<MPEG4Source> source =  new MPEG4Source(this,
    +             track->meta, mDataSource, track->timescale, track->sampleTable,
    +             mSidxEntries, trex, mMoofOffset);
    ++    if (source->init() != OK) {
    ++        return NULL;
    ++    }
    ++    return source;
    + }
    + 
    + // static
    +@@ -3573,6 +3596,7 @@ MPEG4Source::MPEG4Source(
    +       mTrex(trex),
    +       mFirstMoofOffset(firstMoofOffset),
    +       mCurrentMoofOffset(firstMoofOffset),
    ++      mNextMoofOffset(-1),
    +       mCurrentTime(0),
    +       mCurrentSampleInfoAllocSize(0),
    +       mCurrentSampleInfoSizes(NULL),
    +@@ -3637,10 +3661,14 @@ MPEG4Source::MPEG4Source(
    + 
    +     CHECK(format->findInt32(kKeyTrackID, &mTrackId));
    + 
    ++}
    ++
    ++status_t MPEG4Source::init() {
    +     if (mFirstMoofOffset != 0) {
    +         off64_t offset = mFirstMoofOffset;
    +-        parseChunk(&offset);
    ++        return parseChunk(&offset);
    +     }
    ++    return OK;
    + }
    + 
    + MPEG4Source::~MPEG4Source() {
    +@@ -3767,13 +3795,35 @@ status_t MPEG4Source::parseChunk(off64_t *offset) {
    + 
    +                 while (true) {
    +                     if (mDataSource->readAt(*offset, hdr, 8) < 8) {
    +-                        return ERROR_END_OF_STREAM;
    ++                        // no more box to the end of file.
    ++                        break;
    +                     }
    +                     chunk_size = ntohl(hdr[0]);
    +                     chunk_type = ntohl(hdr[1]);
    ++                    if (chunk_size == 1) {
    ++                        // ISO/IEC 14496-12:2012, 8.8.4 Movie Fragment Box, moof is a Box
    ++                        // which is defined in 4.2 Object Structure.
    ++                        // When chunk_size==1, 8 bytes follows as "largesize".
    ++                        if (mDataSource->readAt(*offset + 8, &chunk_size, 8) < 8) {
    ++                            return ERROR_IO;
    ++                        }
    ++                        chunk_size = ntoh64(chunk_size);
    ++                        if (chunk_size < 16) {
    ++                            // The smallest valid chunk is 16 bytes long in this case.
    ++                            return ERROR_MALFORMED;
    ++                        }
    ++                    } else if (chunk_size == 0) {
    ++                        // next box extends to end of file.
    ++                    } else if (chunk_size < 8) {
    ++                        // The smallest valid chunk is 8 bytes long in this case.
    ++                        return ERROR_MALFORMED;
    ++                    }
    ++
    +                     if (chunk_type == FOURCC('m', 'o', 'o', 'f')) {
    +                         mNextMoofOffset = *offset;
    +                         break;
    ++                    } else if (chunk_size == 0) {
    ++                        break;
    +                     }
    +                     *offset += chunk_size;
    +                 }
    +@@ -4651,17 +4701,25 @@ status_t MPEG4Source::fragmentedRead(
    +                 totalOffset += se->mSize;
    +             }
    +             mCurrentMoofOffset = totalOffset;
    ++            mNextMoofOffset = -1;
    +             mCurrentSamples.clear();
    +             mCurrentSampleIndex = 0;
    +-            parseChunk(&totalOffset);
    ++            status_t err = parseChunk(&totalOffset);
    ++            if (err != OK) {
    ++                return err;
    ++            }
    +             mCurrentTime = totalTime * mTimescale / 1000000ll;
    +         } else {
    +             // without sidx boxes, we can only seek to 0
    +             mCurrentMoofOffset = mFirstMoofOffset;
    ++            mNextMoofOffset = -1;
    +             mCurrentSamples.clear();
    +             mCurrentSampleIndex = 0;
    +             off64_t tmp = mCurrentMoofOffset;
    +-            parseChunk(&tmp);
    ++            status_t err = parseChunk(&tmp);
    ++            if (err != OK) {
    ++                return err;
    ++            }
    +             mCurrentTime = 0;
    +         }
    + 
    +@@ -4690,7 +4748,10 @@ status_t MPEG4Source::fragmentedRead(
    +             mCurrentMoofOffset = nextMoof;
    +             mCurrentSamples.clear();
    +             mCurrentSampleIndex = 0;
    +-            parseChunk(&nextMoof);
    ++            status_t err = parseChunk(&nextMoof);
    ++            if (err != OK) {
    ++                return err;
    ++            }
    +             if (mCurrentSampleIndex >= mCurrentSamples.size()) {
    +                 return ERROR_END_OF_STREAM;
    +             }
     diff --git a/media/libstagefright/MediaCodecList.cpp b/media/libstagefright/MediaCodecList.cpp
     index 0fb5072..a25c47d 100644
     --- a/media/libstagefright/MediaCodecList.cpp
    @@ -439,6 +774,215 @@ index 15ff569..0e9b4e6 100644
      
          (*buffer)->setObserver(this);
          (*buffer)->add_ref();
    +diff --git a/media/libstagefright/codecs/aacenc/SoftAACEncoder2.cpp b/media/libstagefright/codecs/aacenc/SoftAACEncoder2.cpp
    +index f00a5d1..44415e2 100644
    +--- a/media/libstagefright/codecs/aacenc/SoftAACEncoder2.cpp
    ++++ b/media/libstagefright/codecs/aacenc/SoftAACEncoder2.cpp
    +@@ -16,6 +16,7 @@
    + 
    + //#define LOG_NDEBUG 0
    + #define LOG_TAG "SoftAACEncoder2"
    ++#include <log/log.h>
    + #include <utils/Log.h>
    + 
    + #include "SoftAACEncoder2.h"
    +@@ -61,6 +62,7 @@ SoftAACEncoder2::SoftAACEncoder2(
    +       mSentCodecSpecificData(false),
    +       mInputSize(0),
    +       mInputFrame(NULL),
    ++      mAllocatedFrameSize(0),
    +       mInputTimeUs(-1ll),
    +       mSawInputEOS(false),
    +       mSignalledError(false) {
    +@@ -565,6 +567,15 @@ void SoftAACEncoder2::onQueueFilled(OMX_U32 /* portIndex */) {
    + 
    +             if (mInputFrame == NULL) {
    +                 mInputFrame = new int16_t[numBytesPerInputFrame / sizeof(int16_t)];
    ++                mAllocatedFrameSize = numBytesPerInputFrame;
    ++            } else if (mAllocatedFrameSize != numBytesPerInputFrame) {
    ++                ALOGE("b/34621073: changed size from %d to %d",
    ++                        (int)mAllocatedFrameSize, (int)numBytesPerInputFrame);
    ++                android_errorWriteLog(0x534e4554,"34621073");
    ++                delete mInputFrame;
    ++                mInputFrame = new int16_t[numBytesPerInputFrame / sizeof(int16_t)];
    ++                mAllocatedFrameSize = numBytesPerInputFrame;
    ++
    +             }
    + 
    +             if (mInputSize == 0) {
    +@@ -715,6 +726,7 @@ void SoftAACEncoder2::onReset() {
    +     delete[] mInputFrame;
    +     mInputFrame = NULL;
    +     mInputSize = 0;
    ++    mAllocatedFrameSize = 0;
    + 
    +     mSentCodecSpecificData = false;
    +     mInputTimeUs = -1ll;
    +diff --git a/media/libstagefright/codecs/aacenc/SoftAACEncoder2.h b/media/libstagefright/codecs/aacenc/SoftAACEncoder2.h
    +index f1b81e1..123fd25 100644
    +--- a/media/libstagefright/codecs/aacenc/SoftAACEncoder2.h
    ++++ b/media/libstagefright/codecs/aacenc/SoftAACEncoder2.h
    +@@ -62,6 +62,7 @@ private:
    +     bool mSentCodecSpecificData;
    +     size_t mInputSize;
    +     int16_t *mInputFrame;
    ++    size_t mAllocatedFrameSize;
    +     int64_t mInputTimeUs;
    + 
    +     bool mSawInputEOS;
    +diff --git a/media/libstagefright/codecs/mpeg2dec/SoftMPEG2.cpp b/media/libstagefright/codecs/mpeg2dec/SoftMPEG2.cpp
    +index 5ed037a..7297f40 100644
    +--- a/media/libstagefright/codecs/mpeg2dec/SoftMPEG2.cpp
    ++++ b/media/libstagefright/codecs/mpeg2dec/SoftMPEG2.cpp
    +@@ -68,6 +68,7 @@ SoftMPEG2::SoftMPEG2(
    +             kProfileLevels, ARRAY_SIZE(kProfileLevels),
    +             320 /* width */, 240 /* height */, callbacks,
    +             appData, component),
    ++      mCodecCtx(NULL),
    +       mMemRecords(NULL),
    +       mFlushOutBuffer(NULL),
    +       mOmxColorFormat(OMX_COLOR_FormatYUV420Planar),
    +@@ -75,25 +76,29 @@ SoftMPEG2::SoftMPEG2(
    +       mNewWidth(mWidth),
    +       mNewHeight(mHeight),
    +       mChangingResolution(false),
    ++      mSignalledError(false),
    +       mStride(mWidth) {
    +     initPorts(kNumBuffers, INPUT_BUF_SIZE, kNumBuffers, CODEC_MIME_TYPE);
    + 
    +     // If input dump is enabled, then open create an empty file
    +     GENERATE_FILE_NAMES();
    +     CREATE_DUMP_FILE(mInFile);
    +-
    +-    CHECK_EQ(initDecoder(), (status_t)OK);
    + }
    + 
    + SoftMPEG2::~SoftMPEG2() {
    +-    CHECK_EQ(deInitDecoder(), (status_t)OK);
    ++    if (OK != deInitDecoder()) {
    ++        ALOGE("Failed to deinit decoder");
    ++        notify(OMX_EventError, OMX_ErrorUnsupportedSetting, 0, NULL);
    ++        mSignalledError = true;
    ++        return;
    ++    }
    + }
    + 
    + 
    +-static size_t getMinTimestampIdx(OMX_S64 *pNTimeStamp, bool *pIsTimeStampValid) {
    ++static ssize_t getMinTimestampIdx(OMX_S64 *pNTimeStamp, bool *pIsTimeStampValid) {
    +     OMX_S64 minTimeStamp = LLONG_MAX;
    +-    int idx = -1;
    +-    for (size_t i = 0; i < MAX_TIME_STAMPS; i++) {
    ++    ssize_t idx = -1;
    ++    for (ssize_t i = 0; i < MAX_TIME_STAMPS; i++) {
    +         if (pIsTimeStampValid[i]) {
    +             if (pNTimeStamp[i] < minTimeStamp) {
    +                 minTimeStamp = pNTimeStamp[i];
    +@@ -204,6 +209,7 @@ status_t SoftMPEG2::resetDecoder() {
    +     setNumCores();
    + 
    +     mStride = 0;
    ++    mSignalledError = false;
    + 
    +     return OK;
    + }
    +@@ -433,6 +439,7 @@ status_t SoftMPEG2::deInitDecoder() {
    + 
    +     mInitNeeded = true;
    +     mChangingResolution = false;
    ++    mCodecCtx = NULL;
    + 
    +     return OK;
    + }
    +@@ -444,10 +451,11 @@ status_t SoftMPEG2::reInitDecoder() {
    + 
    +     ret = initDecoder();
    +     if (OK != ret) {
    +-        ALOGE("Create failure");
    ++        ALOGE("Failed to initialize decoder");
    +         deInitDecoder();
    +-        return NO_MEMORY;
    ++        return ret;
    +     }
    ++    mSignalledError = false;
    +     return OK;
    + }
    + 
    +@@ -586,10 +594,22 @@ void SoftMPEG2::onPortFlushCompleted(OMX_U32 portIndex) {
    + void SoftMPEG2::onQueueFilled(OMX_U32 portIndex) {
    +     UNUSED(portIndex);
    + 
    ++    if (mSignalledError) {
    ++        return;
    ++    }
    +     if (mOutputPortSettingsChange != NONE) {
    +         return;
    +     }
    + 
    ++    if (NULL == mCodecCtx) {
    ++        if (OK != initDecoder()) {
    ++            ALOGE("Failed to initialize decoder");
    ++            notify(OMX_EventError, OMX_ErrorUnsupportedSetting, 0, NULL);
    ++            mSignalledError = true;
    ++            return;
    ++        }
    ++    }
    ++
    +     List<BufferInfo *> &inQueue = getPortQueue(kInputPortIndex);
    +     List<BufferInfo *> &outQueue = getPortQueue(kOutputPortIndex);
    + 
    +@@ -642,7 +662,9 @@ void SoftMPEG2::onQueueFilled(OMX_U32 portIndex) {
    +             bool portWillReset = false;
    +             handlePortSettingsChange(&portWillReset, mNewWidth, mNewHeight);
    + 
    +-            CHECK_EQ(reInitDecoder(), (status_t)OK);
    ++            if (OK != reInitDecoder()) {
    ++                ALOGE("Failed to reinitialize decoder");
    ++            }
    +             return;
    +         }
    + 
    +@@ -715,7 +737,10 @@ void SoftMPEG2::onQueueFilled(OMX_U32 portIndex) {
    +                 bool portWillReset = false;
    +                 handlePortSettingsChange(&portWillReset, s_dec_op.u4_pic_wd, s_dec_op.u4_pic_ht);
    + 
    +-                CHECK_EQ(reInitDecoder(), (status_t)OK);
    ++                if (OK != reInitDecoder()) {
    ++                    ALOGE("Failed to reinitialize decoder");
    ++                    return;
    ++                }
    + 
    +                 if (setDecodeArgs(&s_dec_ip, &s_dec_op, inHeader, outHeader, timeStampIx)) {
    +                     ivdec_api_function(mCodecCtx, (void *)&s_dec_ip, (void *)&s_dec_op);
    +@@ -768,10 +793,15 @@ void SoftMPEG2::onQueueFilled(OMX_U32 portIndex) {
    +             }
    + 
    +             if (s_dec_op.u4_output_present) {
    +-                size_t timeStampIdx;
    ++                ssize_t timeStampIdx;
    +                 outHeader->nFilledLen = (mWidth * mHeight * 3) / 2;
    + 
    +                 timeStampIdx = getMinTimestampIdx(mTimeStamps, mTimeStampsValid);
    ++                if (timeStampIdx < 0) {
    ++                    ALOGE("b/62872863, Invalid timestamp index!");
    ++                    android_errorWriteLog(0x534e4554, "62872863");
    ++                    return;
    ++                }
    +                 outHeader->nTimeStamp = mTimeStamps[timeStampIdx];
    +                 mTimeStampsValid[timeStampIdx] = false;
    + 
    +diff --git a/media/libstagefright/codecs/mpeg2dec/SoftMPEG2.h b/media/libstagefright/codecs/mpeg2dec/SoftMPEG2.h
    +index 700ef5f..1285c5b 100644
    +--- a/media/libstagefright/codecs/mpeg2dec/SoftMPEG2.h
    ++++ b/media/libstagefright/codecs/mpeg2dec/SoftMPEG2.h
    +@@ -106,6 +106,7 @@ private:
    +     // codec. So the codec is switching to decode the new resolution.
    +     bool mChangingResolution;
    +     bool mFlushNeeded;
    ++    bool mSignalledError;
    +     bool mWaitForI;
    +     size_t mStride;
    + 
     diff --git a/media/libstagefright/foundation/MediaBufferGroup.cpp b/media/libstagefright/foundation/MediaBufferGroup.cpp
     index 8e4d064..66992d7 100644
     --- a/media/libstagefright/foundation/MediaBufferGroup.cpp
    @@ -488,6 +1032,22 @@ index 7abc019..590146d 100644
          mPrevEstimates.push_back(*bandwidthBps);
          while (mPrevEstimates.size() > 3) {
              mPrevEstimates.erase(mPrevEstimates.begin());
    +diff --git a/media/libstagefright/mpeg2ts/ESQueue.cpp b/media/libstagefright/mpeg2ts/ESQueue.cpp
    +index 96ca405..7599c13 100644
    +--- a/media/libstagefright/mpeg2ts/ESQueue.cpp
    ++++ b/media/libstagefright/mpeg2ts/ESQueue.cpp
    +@@ -716,6 +716,11 @@ sp<ABuffer> ElementaryStreamQueue::dequeueAccessUnitAAC() {
    +         bits.skipBits(2);
    + 
    +         unsigned aac_frame_length = bits.getBits(13);
    ++        if (aac_frame_length == 0){
    ++            ALOGE("b/62673179, Invalid AAC frame length!");
    ++            android_errorWriteLog(0x534e4554, "62673179");
    ++            return NULL;
    ++        }
    + 
    +         bits.skipBits(11);  // adts_buffer_fullness
    + 
     diff --git a/media/libstagefright/omx/Android.mk b/media/libstagefright/omx/Android.mk
     index e4fbd81..8fc788f 100644
     --- a/media/libstagefright/omx/Android.mk
    @@ -640,6 +1200,89 @@ index fec3a57..a0ef28c 100644
              ALOGE("openRecord() permission denied: recording not allowed");
              lStatus = PERMISSION_DENIED;
              goto Exit;
    +diff --git a/services/audioflinger/Effects.cpp b/services/audioflinger/Effects.cpp
    +index f908d6d..b588685 100644
    +--- a/services/audioflinger/Effects.cpp
    ++++ b/services/audioflinger/Effects.cpp
    +@@ -1309,6 +1309,24 @@ status_t AudioFlinger::EffectHandle::command(uint32_t cmdCode,
    +     ALOGVV("command(), cmdCode: %d, mHasControl: %d, mEffect: %p",
    +             cmdCode, mHasControl, mEffect.unsafe_get());
    + 
    ++    // reject commands reserved for internal use by audio framework if coming from outside
    ++    // of audioserver
    ++    switch(cmdCode) {
    ++        case EFFECT_CMD_ENABLE:
    ++        case EFFECT_CMD_DISABLE:
    ++        case EFFECT_CMD_SET_PARAM:
    ++        case EFFECT_CMD_SET_PARAM_DEFERRED:
    ++        case EFFECT_CMD_SET_PARAM_COMMIT:
    ++        case EFFECT_CMD_GET_PARAM:
    ++            break;
    ++        default:
    ++            if (cmdCode >= EFFECT_CMD_FIRST_PROPRIETARY) {
    ++                break;
    ++            }
    ++            android_errorWriteLog(0x534e4554, "62019992");
    ++            return BAD_VALUE;
    ++    }
    ++
    +     if (cmdCode == EFFECT_CMD_ENABLE) {
    +         if (*replySize < sizeof(int)) {
    +             android_errorWriteLog(0x534e4554, "32095713");
    +diff --git a/services/audioflinger/Tracks.cpp b/services/audioflinger/Tracks.cpp
    +index f18b88d..a3f3ea5 100644
    +--- a/services/audioflinger/Tracks.cpp
    ++++ b/services/audioflinger/Tracks.cpp
    +@@ -141,9 +141,11 @@ AudioFlinger::ThreadBase::TrackBase::TrackBase(
    +             return;
    +         }
    +     } else {
    +-        // this syntax avoids calling the audio_track_cblk_t constructor twice
    +-        mCblk = (audio_track_cblk_t *) new uint8_t[size];
    +-        // assume mCblk != NULL
    ++        mCblk = (audio_track_cblk_t *) malloc(size);
    ++        if (mCblk == NULL) {
    ++            ALOGE("not enough memory for AudioTrack size=%zu", size);
    ++            return;
    ++        }
    +     }
    + 
    +     // construct the shared structure in-place.
    +@@ -235,10 +237,9 @@ AudioFlinger::ThreadBase::TrackBase::~TrackBase()
    +     // delete the proxy before deleting the shared memory it refers to, to avoid dangling reference
    +     delete mServerProxy;
    +     if (mCblk != NULL) {
    ++        mCblk->~audio_track_cblk_t();   // destroy our shared-structure.
    +         if (mClient == 0) {
    +-            delete mCblk;
    +-        } else {
    +-            mCblk->~audio_track_cblk_t();   // destroy our shared-structure.
    ++            free(mCblk);
    +         }
    +     }
    +     mCblkMemory.clear();    // free the shared memory before releasing the heap it belongs to
    +@@ -398,6 +399,21 @@ AudioFlinger::PlaybackThread::Track::Track(
    +         mAudioTrackServerProxy = new AudioTrackServerProxy(mCblk, mBuffer, frameCount,
    +                 mFrameSize, !isExternalTrack(), sampleRate);
    +     } else {
    ++        // Is the shared buffer of sufficient size?
    ++        // (frameCount * mFrameSize) is <= SIZE_MAX, checked in TrackBase.
    ++        if (sharedBuffer->size() < frameCount * mFrameSize) {
    ++            // Workaround: clear out mCblk to indicate track hasn't been properly created.
    ++            mCblk->~audio_track_cblk_t();   // destroy our shared-structure.
    ++            if (mClient == 0) {
    ++                free(mCblk);
    ++            }
    ++            mCblk = NULL;
    ++
    ++            mSharedBuffer.clear(); // release shared buffer early
    ++            android_errorWriteLog(0x534e4554, "38340117");
    ++            return;
    ++        }
    ++
    +         mAudioTrackServerProxy = new StaticAudioTrackServerProxy(mCblk, mBuffer, frameCount,
    +                 mFrameSize);
    +     }
     diff --git a/services/audiopolicy/common/managerdefinitions/src/Serializer.cpp b/services/audiopolicy/common/managerdefinitions/src/Serializer.cpp
     index 3e5bb7d..2ecd6b1 100644
     --- a/services/audiopolicy/common/managerdefinitions/src/Serializer.cpp
    diff --git a/frameworks_base.patch b/frameworks_base.patch
    index 7d71827..2c72791 100644
    --- a/frameworks_base.patch
    +++ b/frameworks_base.patch
    @@ -1,3 +1,15 @@
    +diff --git a/api/system-current.txt b/api/system-current.txt
    +index 0fe164a..6b6f7e9 100644
    +--- a/api/system-current.txt
    ++++ b/api/system-current.txt
    +@@ -112,6 +112,7 @@ package android {
    +     field public static final java.lang.String GRANT_RUNTIME_PERMISSIONS = "android.permission.GRANT_RUNTIME_PERMISSIONS";
    +     field public static final java.lang.String HARDWARE_TEST = "android.permission.HARDWARE_TEST";
    +     field public static final java.lang.String HDMI_CEC = "android.permission.HDMI_CEC";
    ++    field public static final java.lang.String HIDE_NON_SYSTEM_OVERLAY_WINDOWS = "android.permission.HIDE_NON_SYSTEM_OVERLAY_WINDOWS";
    +     field public static final java.lang.String INJECT_EVENTS = "android.permission.INJECT_EVENTS";
    +     field public static final java.lang.String INSTALL_GRANT_RUNTIME_PERMISSIONS = "android.permission.INSTALL_GRANT_RUNTIME_PERMISSIONS";
    +     field public static final java.lang.String INSTALL_LOCATION_PROVIDER = "android.permission.INSTALL_LOCATION_PROVIDER";
     diff --git a/core/java/android/accounts/ChooseTypeAndAccountActivity.java b/core/java/android/accounts/ChooseTypeAndAccountActivity.java
     index aed7a36..bf96926 100644
     --- a/core/java/android/accounts/ChooseTypeAndAccountActivity.java
    @@ -133,6 +145,52 @@ index a8209af..4766d33 100755
               * I am the lolrus.
               * <p>
               * Nonzero values indicate that the user has a bukkit.
    +diff --git a/core/java/android/view/WindowManager.java b/core/java/android/view/WindowManager.java
    +index 395f738..169f7e1 100644
    +--- a/core/java/android/view/WindowManager.java
    ++++ b/core/java/android/view/WindowManager.java
    +@@ -655,6 +655,25 @@ public interface WindowManager extends ViewManager {
    +          */
    +         public static final int LAST_SYSTEM_WINDOW      = 2999;
    + 
    ++        /**
    ++         * Return true if the window type is an alert window.
    ++         *
    ++         * @param type The window type.
    ++         * @return If the window type is an alert window.
    ++         * @hide
    ++         */
    ++        public static boolean isSystemAlertWindowType(int type) {
    ++            switch (type) {
    ++                case TYPE_PHONE:
    ++                case TYPE_PRIORITY_PHONE:
    ++                case TYPE_SYSTEM_ALERT:
    ++                case TYPE_SYSTEM_ERROR:
    ++                case TYPE_SYSTEM_OVERLAY:
    ++                    return true;
    ++            }
    ++            return false;
    ++        }
    ++
    +         /** @deprecated this is ignored, this value is set automatically when needed. */
    +         @Deprecated
    +         public static final int MEMORY_TYPE_NORMAL = 0;
    +@@ -1263,6 +1282,15 @@ public interface WindowManager extends ViewManager {
    +         public static final int PRIVATE_FLAG_SUSTAINED_PERFORMANCE_MODE = 0x00040000;
    + 
    +         /**
    ++         * Flag to indicate that any window added by an application process that is of type
    ++         * {@link #TYPE_TOAST} or that requires
    ++         * {@link android.app.AppOpsManager#OP_SYSTEM_ALERT_WINDOW} permission should be hidden when
    ++         * this window is visible.
    ++         * @hide
    ++         */
    ++        public static final int PRIVATE_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS = 0x00080000;
    ++
    ++        /**
    +          * Control flags that are private to the platform.
    +          * @hide
    +          */
     diff --git a/core/java/com/android/internal/app/procstats/ProcessState.java b/core/java/com/android/internal/app/procstats/ProcessState.java
     index 8c5df08..8c2c236 100644
     --- a/core/java/com/android/internal/app/procstats/ProcessState.java
    @@ -161,6 +219,26 @@ index e4f573b..0d3f50c 100644
                  EGL14.eglGetDisplay(EGL14.EGL_DEFAULT_DISPLAY);
              }
          }
    +diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
    +index 011884c..a5035ee 100644
    +--- a/core/res/AndroidManifest.xml
    ++++ b/core/res/AndroidManifest.xml
    +@@ -2154,6 +2154,15 @@
    +     <permission android:name="android.permission.INTERNAL_SYSTEM_WINDOW"
    +         android:protectionLevel="signature" />
    + 
    ++    <!-- @SystemApi Allows an application to use
    ++        {@link android.view.WindowManager.LayoutsParams#PRIVATE_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS}
    ++        to hide non-system-overlay windows.
    ++        <p>Not for use by third-party applications.
    ++        @hide
    ++    -->
    ++    <permission android:name="android.permission.HIDE_NON_SYSTEM_OVERLAY_WINDOWS"
    ++        android:protectionLevel="signature|installer" />
    ++
    +     <!-- @SystemApi Allows an application to manage (create, destroy,
    +          Z-order) application tokens in the window manager.
    +          <p>Not for use by third-party applications.
     diff --git a/core/res/res/xml/config_webview_packages.xml b/core/res/res/xml/config_webview_packages.xml
     index f062b59..574f7c1 100644
     --- a/core/res/res/xml/config_webview_packages.xml
    @@ -686,6 +764,226 @@ index 889c52a..11585b4 100644
                  case KeyEvent.KEYCODE_ENDCALL: {
                      result &= ~ACTION_PASS_TO_USER;
                      if (down) {
    +diff --git a/services/core/java/com/android/server/wm/Session.java b/services/core/java/com/android/server/wm/Session.java
    +index 08c0a4b..b5c4202 100644
    +--- a/services/core/java/com/android/server/wm/Session.java
    ++++ b/services/core/java/com/android/server/wm/Session.java
    +@@ -16,6 +16,9 @@
    + 
    + package com.android.server.wm;
    + 
    ++import static android.Manifest.permission.HIDE_NON_SYSTEM_OVERLAY_WINDOWS;
    ++import static android.Manifest.permission.INTERNAL_SYSTEM_WINDOW;
    ++import static android.content.pm.PackageManager.PERMISSION_GRANTED;
    + import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_DRAG;
    + import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_TASK_POSITIONING;
    + import static com.android.server.wm.WindowManagerDebugConfig.SHOW_LIGHT_TRANSACTIONS;
    +@@ -67,6 +70,8 @@ final class Session extends IWindowSession.Stub
    +     final int mUid;
    +     final int mPid;
    +     final String mStringName;
    ++    final boolean mCanAddInternalSystemWindow;
    ++    final boolean mCanHideNonSystemOverlayWindows;
    +     SurfaceSession mSurfaceSession;
    +     int mNumWindow = 0;
    +     boolean mClientDead = false;
    +@@ -80,6 +85,10 @@ final class Session extends IWindowSession.Stub
    +         mInputContext = inputContext;
    +         mUid = Binder.getCallingUid();
    +         mPid = Binder.getCallingPid();
    ++        mCanAddInternalSystemWindow = service.mContext.checkCallingOrSelfPermission(
    ++                INTERNAL_SYSTEM_WINDOW) == PERMISSION_GRANTED;
    ++        mCanHideNonSystemOverlayWindows = service.mContext.checkCallingOrSelfPermission(
    ++                HIDE_NON_SYSTEM_OVERLAY_WINDOWS) == PERMISSION_GRANTED;
    +         mLastReportedAnimatorScale = service.getCurrentAnimatorScale();
    +         StringBuilder sb = new StringBuilder();
    +         sb.append("Session{");
    +diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
    +index ca2610a..0d97059 100644
    +--- a/services/core/java/com/android/server/wm/WindowManagerService.java
    ++++ b/services/core/java/com/android/server/wm/WindowManagerService.java
    +@@ -490,6 +490,9 @@ public class WindowManagerService extends IWindowManager.Stub
    +      */
    +     final ArrayList<WindowState> mForceRemoves = new ArrayList<>();
    + 
    ++    /** List of window currently causing non-system overlay windows to be hidden. */
    ++    private ArrayList<WindowState> mHidingNonSystemOverlayWindows = new ArrayList<WindowState>();
    ++
    +     /**
    +      * Windows that clients are waiting to have drawn.
    +      */
    +@@ -2129,6 +2132,9 @@ public class WindowManagerService extends IWindowManager.Stub
    +                 }
    +             }
    + 
    ++            final boolean hideSystemAlertWindows = !mHidingNonSystemOverlayWindows.isEmpty();
    ++            win.setForceHideNonSystemOverlayWindowIfNeeded(hideSystemAlertWindows);
    ++
    +             if (type == TYPE_APPLICATION_STARTING && token.appWindowToken != null) {
    +                 token.appWindowToken.startingWindow = win;
    +                 if (DEBUG_STARTING_WINDOW) Slog.v (TAG_WM, "addWindow: " + token.appWindowToken
    +@@ -2576,6 +2582,7 @@ public class WindowManagerService extends IWindowManager.Stub
    + 
    +         mPendingRemove.remove(win);
    +         mResizingWindows.remove(win);
    ++        updateNonSystemOverlayWindowsVisibilityIfNeeded(win, false /* surfaceShown */);
    +         mWindowsChanged = true;
    +         if (DEBUG_WINDOW_MOVEMENT) Slog.v(TAG_WM, "Final remove of window: " + win);
    + 
    +@@ -11771,4 +11778,34 @@ public class WindowManagerService extends IWindowManager.Stub
    +             }
    +         }
    +     }
    ++
    ++    void updateNonSystemOverlayWindowsVisibilityIfNeeded(WindowState win, boolean surfaceShown) {
    ++        if (!win.hideNonSystemOverlayWindowsWhenVisible()) {
    ++            return;
    ++        }
    ++        final boolean systemAlertWindowsHidden = !mHidingNonSystemOverlayWindows.isEmpty();
    ++        if (surfaceShown) {
    ++            if (!mHidingNonSystemOverlayWindows.contains(win)) {
    ++                mHidingNonSystemOverlayWindows.add(win);
    ++            }
    ++        } else {
    ++            mHidingNonSystemOverlayWindows.remove(win);
    ++        }
    ++
    ++        final boolean hideSystemAlertWindows = !mHidingNonSystemOverlayWindows.isEmpty();
    ++
    ++        if (systemAlertWindowsHidden == hideSystemAlertWindows) {
    ++            return;
    ++        }
    ++
    ++        final int numDisplays = mDisplayContents.size();
    ++        for (int displayNdx = 0; displayNdx < numDisplays; ++displayNdx) {
    ++            final WindowList windows = mDisplayContents.valueAt(displayNdx).getWindowList();
    ++            final int numWindows = windows.size();
    ++            for (int winNdx = 0; winNdx < numWindows; ++winNdx) {
    ++                final WindowState w = windows.get(winNdx);
    ++                w.setForceHideNonSystemOverlayWindowIfNeeded(hideSystemAlertWindows);
    ++            }
    ++        }
    ++    }
    + }
    +diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
    +index fbef2c6..228ef1a 100644
    +--- a/services/core/java/com/android/server/wm/WindowState.java
    ++++ b/services/core/java/com/android/server/wm/WindowState.java
    +@@ -79,6 +79,7 @@ import static android.view.WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON;
    + import static android.view.WindowManager.LayoutParams.LAST_SUB_WINDOW;
    + import static android.view.WindowManager.LayoutParams.MATCH_PARENT;
    + import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_COMPATIBLE_WINDOW;
    ++import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS;
    + import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_KEYGUARD;
    + import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_LAYOUT_CHILD_WINDOW_IN_PARENT_FRAME;
    + import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_WILL_NOT_REPLACE_ON_RELAUNCH;
    +@@ -91,7 +92,9 @@ import static android.view.WindowManager.LayoutParams.TYPE_DRAWN_APPLICATION;
    + import static android.view.WindowManager.LayoutParams.TYPE_DOCK_DIVIDER;
    + import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD;
    + import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD_DIALOG;
    ++import static android.view.WindowManager.LayoutParams.TYPE_TOAST;
    + import static android.view.WindowManager.LayoutParams.TYPE_WALLPAPER;
    ++import static android.view.WindowManager.LayoutParams.isSystemAlertWindowType;
    + import static android.view.WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER;
    + import static com.android.server.wm.DragResizeMode.DRAG_RESIZE_MODE_DOCKED_DIVIDER;
    + import static com.android.server.wm.DragResizeMode.DRAG_RESIZE_MODE_FREEFORM;
    +@@ -141,6 +144,7 @@ final class WindowState implements WindowManagerPolicy.WindowState {
    +     final int mAppOp;
    +     // UserId and appId of the owner. Don't display windows of non-current user.
    +     final int mOwnerUid;
    ++    final boolean mOwnerCanAddInternalSystemWindow;
    +     final IWindowId mWindowId;
    +     WindowToken mToken;
    +     WindowToken mRootToken;
    +@@ -167,6 +171,8 @@ final class WindowState implements WindowManagerPolicy.WindowState {
    +     boolean mPolicyVisibilityAfterAnim = true;
    +     boolean mAppOpVisibility = true;
    +     boolean mPermanentlyHidden; // the window should never be shown again
    ++    // This is a non-system overlay window that is currently force hidden.
    ++    private boolean mForceHideNonSystemOverlayWindow;
    +     boolean mAppFreezing;
    +     boolean mAttachedHidden;    // is our parent window hidden?
    +     boolean mWallpaperVisible;  // for wallpaper, what was last vis report?
    +@@ -522,6 +528,7 @@ final class WindowState implements WindowManagerPolicy.WindowState {
    +         mAppOp = appOp;
    +         mToken = token;
    +         mOwnerUid = s.mUid;
    ++        mOwnerCanAddInternalSystemWindow = s.mCanAddInternalSystemWindow;
    +         mWindowId = new IWindowId.Stub() {
    +             @Override
    +             public void registerFocusObserver(IWindowFocusObserver observer) {
    +@@ -1882,6 +1889,10 @@ final class WindowState implements WindowManagerPolicy.WindowState {
    +             // to handle their windows being removed from under them.
    +             return false;
    +         }
    ++        if (mForceHideNonSystemOverlayWindow) {
    ++            // This is an alert window that is currently force hidden.
    ++            return false;
    ++        }
    +         if (mPolicyVisibility && mPolicyVisibilityAfterAnim) {
    +             // Already showing.
    +             return false;
    +@@ -1955,6 +1966,22 @@ final class WindowState implements WindowManagerPolicy.WindowState {
    +         return true;
    +     }
    + 
    ++    void setForceHideNonSystemOverlayWindowIfNeeded(boolean forceHide) {
    ++        if (mOwnerCanAddInternalSystemWindow
    ++                || (!isSystemAlertWindowType(mAttrs.type) && mAttrs.type != TYPE_TOAST)) {
    ++            return;
    ++        }
    ++        if (mForceHideNonSystemOverlayWindow == forceHide) {
    ++            return;
    ++        }
    ++        mForceHideNonSystemOverlayWindow = forceHide;
    ++        if (forceHide) {
    ++            hideLw(true /* doAnimation */, true /* requestAnim */);
    ++        } else {
    ++            showLw(true /* doAnimation */, true /* requestAnim */);
    ++        }
    ++    }
    ++
    +     public void setAppOpVisibilityLw(boolean state) {
    +         if (mAppOpVisibility != state) {
    +             mAppOpVisibility = state;
    +@@ -2755,6 +2782,17 @@ final class WindowState implements WindowManagerPolicy.WindowState {
    +         }
    +     }
    + 
    ++    /**
    ++     * Returns true if any window added by an application process that if of type
    ++     * {@link android.view.WindowManager.LayoutParams#TYPE_TOAST} or that requires that requires
    ++     * {@link android.app.AppOpsManager#OP_SYSTEM_ALERT_WINDOW} permission should be hidden when
    ++     * this window is visible.
    ++     */
    ++    boolean hideNonSystemOverlayWindowsWhenVisible() {
    ++        return (mAttrs.privateFlags & PRIVATE_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS) != 0
    ++                && mSession.mCanHideNonSystemOverlayWindows;
    ++    }
    ++
    +     String makeInputChannelName() {
    +         return Integer.toHexString(System.identityHashCode(this))
    +             + " " + getWindowTag();
    +diff --git a/services/core/java/com/android/server/wm/WindowStateAnimator.java b/services/core/java/com/android/server/wm/WindowStateAnimator.java
    +index aa8e781..ec3208b 100644
    +--- a/services/core/java/com/android/server/wm/WindowStateAnimator.java
    ++++ b/services/core/java/com/android/server/wm/WindowStateAnimator.java
    +@@ -582,6 +582,7 @@ class WindowStateAnimator {
    +             //dump();
    +             mLastHidden = true;
    +             if (mSurfaceController != null) {
    ++                mService.updateNonSystemOverlayWindowsVisibilityIfNeeded(mWin, false);
    +                 mSurfaceController.hideInTransaction(reason);
    +             }
    +         }
    +@@ -1814,6 +1815,7 @@ class WindowStateAnimator {
    +         if (!shown)
    +             return false;
    + 
    ++        mService.updateNonSystemOverlayWindowsVisibilityIfNeeded(mWin, true);
    +         if (mWin.mTurnOnScreen) {
    +             if (DEBUG_VISIBILITY) Slog.v(TAG, "Show surface turning screen on: " + mWin);
    +             mWin.mTurnOnScreen = false;
     diff --git a/services/net/java/android/net/dhcp/DhcpClient.java b/services/net/java/android/net/dhcp/DhcpClient.java
     index ffbea9f..8dd05b1 100644
     --- a/services/net/java/android/net/dhcp/DhcpClient.java
    diff --git a/frameworks_minikin.patch b/frameworks_minikin.patch
    new file mode 100644
    index 0000000..531f80b
    --- /dev/null
    +++ b/frameworks_minikin.patch
    @@ -0,0 +1,72 @@
    +diff --git a/libs/minikin/CmapCoverage.cpp b/libs/minikin/CmapCoverage.cpp
    +index 2961d2f..c02526c 100644
    +--- a/libs/minikin/CmapCoverage.cpp
    ++++ b/libs/minikin/CmapCoverage.cpp
    +@@ -37,15 +37,25 @@ static uint32_t readU32(const uint8_t* data, size_t offset) {
    +         ((uint32_t)data[offset + 2]) << 8 | ((uint32_t)data[offset + 3]);
    + }
    + 
    +-static void addRange(vector<uint32_t> &coverage, uint32_t start, uint32_t end) {
    ++// The start must be larger than or equal to coverage.back() if coverage is not empty.
    ++// Returns true if the range is appended. Otherwise returns false as an error.
    ++static bool addRange(vector<uint32_t> &coverage, uint32_t start, uint32_t end) {
    + #ifdef VERBOSE_DEBUG
    +     ALOGD("adding range %d-%d\n", start, end);
    + #endif
    +     if (coverage.empty() || coverage.back() < start) {
    +         coverage.push_back(start);
    +         coverage.push_back(end);
    +-    } else {
    ++        return true;
    ++    } else if (coverage.back() == start) {
    +         coverage.back() = end;
    ++        return true;
    ++    } else {
    ++        // Reject unordered range input since SparseBitSet assumes that the given range vector is
    ++        // sorted. OpenType specification says cmap entries are sorted in order of code point
    ++        // values, thus for OpenType compliant font files, we don't reach here.
    ++        android_errorWriteLog(0x534e4554, "32178311");
    ++        return false;
    +     }
    + }
    + 
    +@@ -74,11 +84,15 @@ static bool getCoverageFormat4(vector<uint32_t>& coverage, const uint8_t* data,
    +         if (rangeOffset == 0) {
    +             uint32_t delta = readU16(data, kHeaderSize + 2 * (2 * segCount + i));
    +             if (((end + delta) & 0xffff) > end - start) {
    +-                addRange(coverage, start, end + 1);
    ++                if (!addRange(coverage, start, end + 1)) {
    ++                    return false;
    ++                }
    +             } else {
    +                 for (uint32_t j = start; j < end + 1; j++) {
    +                     if (((j + delta) & 0xffff) != 0) {
    +-                        addRange(coverage, j, j + 1);
    ++                        if (!addRange(coverage, j, j + 1)) {
    ++                            return false;
    ++                        }
    +                     }
    +                 }
    +             }
    +@@ -92,7 +106,9 @@ static bool getCoverageFormat4(vector<uint32_t>& coverage, const uint8_t* data,
    +                 }
    +                 uint32_t glyphId = readU16(data, actualRangeOffset);
    +                 if (glyphId != 0) {
    +-                    addRange(coverage, j, j + 1);
    ++                    if (!addRange(coverage, j, j + 1)) {
    ++                        return false;
    ++                    }
    +                 }
    +             }
    +         }
    +@@ -126,7 +142,9 @@ static bool getCoverageFormat12(vector<uint32_t>& coverage, const uint8_t* data,
    +             android_errorWriteLog(0x534e4554, "26413177");
    +             return false;
    +         }
    +-        addRange(coverage, start, end + 1);  // file is inclusive, vector is exclusive
    ++        if (!addRange(coverage, start, end + 1)) {  // file is inclusive, vector is exclusive
    ++            return false;
    ++        }
    +     }
    +     return true;
    + }
    diff --git a/hardware_libhardware.patch b/hardware_libhardware.patch
    new file mode 100644
    index 0000000..9c529aa
    --- /dev/null
    +++ b/hardware_libhardware.patch
    @@ -0,0 +1,45 @@
    +diff --git a/include/hardware/power.h b/include/hardware/power.h
    +index bd8216e..968e478 100644
    +--- a/include/hardware/power.h
    ++++ b/include/hardware/power.h
    +@@ -65,7 +65,11 @@ typedef enum {
    +     POWER_HINT_SUSTAINED_PERFORMANCE = 0x00000006,
    +     POWER_HINT_VR_MODE = 0x00000007,
    +     POWER_HINT_LAUNCH = 0x00000008,
    +-    POWER_HINT_DISABLE_TOUCH = 0x00000009
    ++    POWER_HINT_DISABLE_TOUCH = 0x00000009,
    ++    POWER_HINT_CPU_BOOST    = 0x00000010,
    ++    POWER_HINT_LAUNCH_BOOST = 0x00000011,
    ++    POWER_HINT_AUDIO        = 0x00000020,
    ++    POWER_HINT_SET_PROFILE  = 0x00000030
    + } power_hint_t;
    + 
    + typedef enum {
    +@@ -257,6 +261,12 @@ typedef struct power_module {
    +      *     The data parameter is non-zero when touch could be disabled, and zero
    +      *     when touch needs to be re-enabled.
    +      *
    ++     * POWER_HINT_CPU_BOOST
    ++     *
    ++     *     An operation is happening where it would be ideal for the CPU to
    ++     *     be boosted for a specific duration. The data parameter is an
    ++     *     integer value of the boost duration in microseconds.
    ++     *
    +      * A particular platform may choose to ignore any hint.
    +      *
    +      * availability: version 0.2
    +diff --git a/modules/sensors/multihal.cpp b/modules/sensors/multihal.cpp
    +index f38d90d..4acc93e 100644
    +--- a/modules/sensors/multihal.cpp
    ++++ b/modules/sensors/multihal.cpp
    +@@ -527,8 +527,8 @@ static void lazy_init_modules() {
    +         pthread_mutex_unlock(&init_modules_mutex);
    +         return;
    +     }
    +-    std::vector<std::string> *so_paths = new std::vector<std::string>();
    +-    get_so_paths(so_paths);
    ++    std::vector<std::string> so_paths;
    ++    get_so_paths(&so_paths);
    + 
    +     // dlopen the module files and cache their module symbols in sub_hw_modules
    +     sub_hw_modules = new std::vector<hw_module_t *>();
    diff --git a/hardware_qcom_audio.patch b/hardware_qcom_audio.patch
    new file mode 100644
    index 0000000..744db5f
    --- /dev/null
    +++ b/hardware_qcom_audio.patch
    @@ -0,0 +1,18 @@
    +diff --git a/post_proc/equalizer.c b/post_proc/equalizer.c
    +index 8c9449a..4e4552f 100644
    +--- a/post_proc/equalizer.c
    ++++ b/post_proc/equalizer.c
    +@@ -334,6 +334,13 @@ int equalizer_get_parameter(effect_context_t *context, effect_param_t *p,
    +                 }
    +                 break;
    +         }
    ++
    ++        if (p->vsize < 1) {
    ++            p->status = -EINVAL;
    ++            android_errorWriteLog(0x534e4554, "37536407");
    ++            break;
    ++        }
    ++
    +         name = (char *)value;
    +         strlcpy(name, equalizer_get_preset_name(eq_ctxt, param2), p->vsize - 1);
    +         name[p->vsize - 1] = 0;
    diff --git a/hardware_ril.patch b/hardware_ril.patch
    index fa1247c..149fa0b 100644
    --- a/hardware_ril.patch
    +++ b/hardware_ril.patch
    @@ -1,8 +1,16 @@
     diff --git a/libril/ril.cpp b/libril/ril.cpp
    -index d7744c0..05119b1 100644
    +index d7744c0..3f78619 100644
     --- a/libril/ril.cpp
     +++ b/libril/ril.cpp
    -@@ -3804,6 +3804,7 @@ static void responseSimStatusV5(Parcel &p, void *response) {
    +@@ -3698,6 +3698,7 @@ static int responseSSData(Parcel &p, void *response, size_t responselen) {
    +     p.writeInt32(p_cur->teleserviceType);
    +     p.writeInt32(p_cur->serviceClass);
    +     p.writeInt32(p_cur->result);
    ++    p.writeInt32(-1);
    + 
    +     if (isServiceTypeCfQuery(p_cur->serviceType, p_cur->requestType)) {
    +         RLOGD("responseSSData CF type, num of Cf elements %d", p_cur->cfData.numValidIndexes);
    +@@ -3804,6 +3805,7 @@ static void responseSimStatusV5(Parcel &p, void *response) {
          p.writeInt32(p_cur->universal_pin_state);
          p.writeInt32(p_cur->gsm_umts_subscription_app_index);
          p.writeInt32(p_cur->cdma_subscription_app_index);
    @@ -10,7 +18,7 @@ index d7744c0..05119b1 100644
      
          sendSimStatusAppInfo(p, p_cur->num_applications, p_cur->applications);
      }
    -@@ -5401,6 +5402,9 @@ void RIL_onUnsolicitedResponse(int unsolResponse, const void *data,
    +@@ -5401,6 +5403,9 @@ void RIL_onUnsolicitedResponse(int unsolResponse, const void *data,
                  p.writeInt32(newState);
                  appendPrintBuf("%s {%s}", printBuf,
                      radioStateToString(CALL_ONSTATEREQUEST(soc_id)));
    diff --git a/packages_apps_messaging.patch b/packages_apps_messaging.patch
    new file mode 100644
    index 0000000..447d1a9
    --- /dev/null
    +++ b/packages_apps_messaging.patch
    @@ -0,0 +1,28 @@
    +diff --git a/src/com/android/messaging/datamodel/media/GifImageResource.java b/src/com/android/messaging/datamodel/media/GifImageResource.java
    +index d50cf47..6801165 100644
    +--- a/src/com/android/messaging/datamodel/media/GifImageResource.java
    ++++ b/src/com/android/messaging/datamodel/media/GifImageResource.java
    +@@ -23,6 +23,7 @@ import android.support.rastermill.FrameSequence;
    + import android.support.rastermill.FrameSequenceDrawable;
    + 
    + import com.android.messaging.util.Assert;
    ++import com.android.messaging.util.LogUtil;
    + 
    + import java.io.IOException;
    + import java.io.InputStream;
    +@@ -55,7 +56,14 @@ public class GifImageResource extends ImageResource {
    + 
    +     @Override
    +     public Drawable getDrawable(Resources resources) {
    +-        return new FrameSequenceDrawable(mFrameSequence);
    ++        try {
    ++            return new FrameSequenceDrawable(mFrameSequence);
    ++        } catch (final Exception e) {
    ++            // Malicious gif images can make platform throw different kind of exceptions. Catch
    ++            // them all.
    ++            LogUtil.e(LogUtil.BUGLE_TAG, "Error getting drawable for GIF", e);
    ++            return null;
    ++        }
    +     }
    + 
    +     @Override
    diff --git a/packages_apps_nfc.patch b/packages_apps_nfc.patch
    new file mode 100644
    index 0000000..ef1866e
    --- /dev/null
    +++ b/packages_apps_nfc.patch
    @@ -0,0 +1,62 @@
    +diff --git a/src/com/android/nfc/BeamShareActivity.java b/src/com/android/nfc/BeamShareActivity.java
    +index 5b8acac..f06bfdb 100644
    +--- a/src/com/android/nfc/BeamShareActivity.java
    ++++ b/src/com/android/nfc/BeamShareActivity.java
    +@@ -19,6 +19,8 @@ package com.android.nfc;
    + import java.util.ArrayList;
    + 
    + import android.app.Activity;
    ++import android.app.ActivityManager;
    ++import android.app.ActivityManagerNative;
    + import android.app.AlertDialog;
    + import android.content.BroadcastReceiver;
    + import android.content.Context;
    +@@ -26,6 +28,7 @@ import android.content.DialogInterface;
    + import android.content.ClipData;
    + import android.content.Intent;
    + import android.content.IntentFilter;
    ++import android.content.pm.PackageManager;
    + import android.net.Uri;
    + import android.nfc.BeamShareData;
    + import android.nfc.NdefMessage;
    +@@ -33,8 +36,11 @@ import android.nfc.NdefRecord;
    + import android.nfc.NfcAdapter;
    + import android.os.Bundle;
    + import android.os.UserHandle;
    ++import android.os.RemoteException;
    + import android.util.Log;
    ++import android.util.EventLog;
    + import android.webkit.URLUtil;
    ++import android.Manifest.permission;
    + 
    + import com.android.internal.R;
    + 
    +@@ -211,16 +217,26 @@ public class BeamShareActivity extends Activity {
    +             int numValidUris = 0;
    +             for (Uri uri : mUris) {
    +                 try {
    ++                    int uid = ActivityManagerNative.getDefault().getLaunchedFromUid(getActivityToken());
    ++                    if (uri.getScheme().equalsIgnoreCase("file") &&
    ++                            getApplicationContext().checkPermission(permission.READ_EXTERNAL_STORAGE, -1, uid) !=
    ++                            PackageManager.PERMISSION_GRANTED) {
    ++                        Log.e(TAG, "File based Uri doesn't have External Storage Permission.");
    ++                        EventLog.writeEvent(0x534e4554, "37287958", uid, uri.getPath());
    ++                        break;
    ++                    }
    +                     grantUriPermission("com.android.nfc", uri, Intent.FLAG_GRANT_READ_URI_PERMISSION);
    +                     uriArray[numValidUris++] = uri;
    +                     if (DBG) Log.d(TAG, "Found uri: " + uri);
    +                 } catch (SecurityException e) {
    +                     Log.e(TAG, "Security exception granting uri permission to NFC process.");
    +-                    numValidUris = 0;
    ++                    break;
    ++                } catch (RemoteException e) {
    ++                    Log.e(TAG, "Remote exception accessing uid of the calling process.");
    +                     break;
    +                 }
    +             }
    +-            if (numValidUris > 0) {
    ++            if (numValidUris != 0 && numValidUris == mUris.size()) {
    +                 shareData = new BeamShareData(null, uriArray, myUserHandle, 0);
    +             } else {
    +                 // No uris left
    diff --git a/packages_apps_settings.patch b/packages_apps_settings.patch
    new file mode 100644
    index 0000000..db57824
    --- /dev/null
    +++ b/packages_apps_settings.patch
    @@ -0,0 +1,45 @@
    +diff --git a/AndroidManifest.xml b/AndroidManifest.xml
    +index 2ec976d..c155cf7 100644
    +--- a/AndroidManifest.xml
    ++++ b/AndroidManifest.xml
    +@@ -86,6 +86,7 @@
    +     <uses-permission android:name="android.permission.PEERS_MAC_ADDRESS"/>
    +     <uses-permission android:name="android.permission.MANAGE_NOTIFICATIONS"/>
    +     <uses-permission android:name="android.permission.DELETE_PACKAGES"/>
    ++    <uses-permission android:name="android.permission.HIDE_NON_SYSTEM_OVERLAY_WINDOWS" />
    + 
    +     <application android:label="@string/settings_label"
    +             android:icon="@mipmap/ic_launcher_settings"
    +diff --git a/src/com/android/settings/accessibility/ToggleAccessibilityServicePreferenceFragment.java b/src/com/android/settings/accessibility/ToggleAccessibilityServicePreferenceFragment.java
    +index 196a4ab..1f69768 100644
    +--- a/src/com/android/settings/accessibility/ToggleAccessibilityServicePreferenceFragment.java
    ++++ b/src/com/android/settings/accessibility/ToggleAccessibilityServicePreferenceFragment.java
    +@@ -39,6 +39,8 @@ import android.view.MenuInflater;
    + import android.view.MenuItem;
    + import android.view.MotionEvent;
    + import android.view.View;
    ++import android.view.Window;
    ++import android.view.WindowManager;
    + import android.view.accessibility.AccessibilityManager;
    + import android.widget.ImageView;
    + import android.widget.LinearLayout;
    +@@ -55,6 +57,8 @@ import com.android.settingslib.accessibility.AccessibilityUtils;
    + 
    + import java.util.List;
    + 
    ++import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS;
    ++
    + public class ToggleAccessibilityServicePreferenceFragment
    +         extends ToggleFeaturePreferenceFragment implements DialogInterface.OnClickListener {
    + 
    +@@ -178,6 +182,10 @@ public class ToggleAccessibilityServicePreferenceFragment
    + 
    +                 ad.create();
    +                 ad.getButton(AlertDialog.BUTTON_POSITIVE).setOnTouchListener(filterTouchListener);
    ++                Window window = ad.getWindow();
    ++                WindowManager.LayoutParams params = window.getAttributes();
    ++                params.privateFlags |= PRIVATE_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS;
    ++                window.setAttributes(params);
    +                 return ad;
    +             }
    +             case DIALOG_ID_DISABLE_WARNING: {
    
    From cf8bcb6ec63ba603afb12f774781f9d27482c450 Mon Sep 17 00:00:00 2001
    From: AndDiSa <anddisa@googlemail.com>
    Date: Sat, 23 Sep 2017 10:39:05 +0200
    Subject: [PATCH 085/159] update patches
    
    Change-Id: I9a6119526e93d0f733b4762d5eeee2232a157a3c
    ---
     system_bt.patch | 341 ++++++++++++++++++++++++++++++++++++++++++++++++
     1 file changed, 341 insertions(+)
     create mode 100644 system_bt.patch
    
    diff --git a/system_bt.patch b/system_bt.patch
    new file mode 100644
    index 0000000..8729075
    --- /dev/null
    +++ b/system_bt.patch
    @@ -0,0 +1,341 @@
    +diff --git a/bta/pan/bta_pan_act.c b/bta/pan/bta_pan_act.c
    +index 1995478..b1678d8 100644
    +--- a/bta/pan/bta_pan_act.c
    ++++ b/bta/pan/bta_pan_act.c
    +@@ -28,6 +28,8 @@
    + 
    + #include "bta_api.h"
    + #include "bta_sys.h"
    ++#include <cutils/log.h>
    ++
    + #include "bt_common.h"
    + #include "pan_api.h"
    + #include "bta_pan_api.h"
    +@@ -176,6 +178,14 @@ static void bta_pan_data_buf_ind_cback(UINT16 handle, BD_ADDR src, BD_ADDR dst,
    + 
    +     if (sizeof(tBTA_PAN_DATA_PARAMS) > p_buf->offset) {
    +         /* offset smaller than data structure in front of actual data */
    ++        if (sizeof(BT_HDR) + sizeof(tBTA_PAN_DATA_PARAMS) + p_buf->len >
    ++            PAN_BUF_SIZE) {
    ++          android_errorWriteLog(0x534e4554, "63146237");
    ++          APPL_TRACE_ERROR("%s: received buffer length too large: %d", __func__,
    ++                           p_buf->len);
    ++          osi_free(p_buf);
    ++          return;
    ++        }
    +         p_new_buf = (BT_HDR *)osi_malloc(PAN_BUF_SIZE);
    +         memcpy((UINT8 *)(p_new_buf + 1) + sizeof(tBTA_PAN_DATA_PARAMS),
    +                (UINT8 *)(p_buf + 1) + p_buf->offset, p_buf->len);
    +diff --git a/stack/avdt/avdt_api.c b/stack/avdt/avdt_api.c
    +index 98ef5f7..258f424 100644
    +--- a/stack/avdt/avdt_api.c
    ++++ b/stack/avdt/avdt_api.c
    +@@ -1208,7 +1208,7 @@ UINT16 AVDT_SendReport(UINT8 handle, AVDT_REPORT_TYPE type,
    +         /* build SR - assume fit in one packet */
    +         p_tbl = avdt_ad_tc_tbl_by_type(AVDT_CHAN_REPORT, p_scb->p_ccb, p_scb);
    +         if (p_tbl->state == AVDT_AD_ST_OPEN) {
    +-            BT_HDR *p_pkt = (BT_HDR *)osi_malloc(p_tbl->peer_mtu);
    ++            BT_HDR* p_pkt = (BT_HDR*)osi_malloc(p_tbl->peer_mtu + sizeof(BT_HDR));
    + 
    +             p_pkt->offset = L2CAP_MIN_OFFSET;
    +             p = (UINT8 *)(p_pkt + 1) + p_pkt->offset;
    +diff --git a/stack/bnep/bnep_main.c b/stack/bnep/bnep_main.c
    +index 078a72e..9b01472 100644
    +--- a/stack/bnep/bnep_main.c
    ++++ b/stack/bnep/bnep_main.c
    +@@ -575,7 +575,8 @@ static void bnep_data_ind (UINT16 l2cap_cid, BT_HDR *p_buf)
    +             p_bcb->con_state != BNEP_STATE_CONNECTED &&
    +             extension_present && p && rem_len)
    +         {
    +-            p_bcb->p_pending_data = (BT_HDR *)osi_malloc(rem_len);
    ++            osi_free(p_bcb->p_pending_data);
    ++            p_bcb->p_pending_data = (BT_HDR*)osi_malloc(rem_len + sizeof(BT_HDR));
    +             memcpy((UINT8 *)(p_bcb->p_pending_data + 1), p, rem_len);
    +             p_bcb->p_pending_data->len    = rem_len;
    +             p_bcb->p_pending_data->offset = 0;
    +diff --git a/stack/bnep/bnep_utils.c b/stack/bnep/bnep_utils.c
    +index 13fb189..2250634 100644
    +--- a/stack/bnep/bnep_utils.c
    ++++ b/stack/bnep/bnep_utils.c
    +@@ -154,7 +154,7 @@ void bnepu_release_bcb (tBNEP_CONN *p_bcb)
    + 
    +     /* Drop any response pointer we may be holding */
    +     p_bcb->con_state        = BNEP_STATE_IDLE;
    +-    p_bcb->p_pending_data   = NULL;
    ++    osi_free_and_reset((void**)&p_bcb->p_pending_data);
    + 
    +     /* Free transmit queue */
    +     while (!fixed_queue_is_empty(p_bcb->xmit_q))
    +@@ -762,24 +762,43 @@ void bnep_process_setup_conn_responce (tBNEP_CONN *p_bcb, UINT8 *p_setup)
    + UINT8 *bnep_process_control_packet (tBNEP_CONN *p_bcb, UINT8 *p, UINT16 *rem_len, BOOLEAN is_ext)
    + {
    +     UINT8       control_type;
    +-    BOOLEAN     bad_pkt = FALSE;
    +     UINT16      len, ext_len = 0;
    + 
    ++    if (p == NULL || rem_len == NULL) {
    ++       if (rem_len != NULL) *rem_len = 0;
    ++       BNEP_TRACE_DEBUG("%s: invalid packet: p = %p rem_len = %p", __func__, p,
    ++                        rem_len);
    ++       return NULL;
    ++    }
    ++    UINT16 rem_len_orig = *rem_len;
    ++
    +     if (is_ext)
    +     {
    ++        if (*rem_len < 1) goto bad_packet_length;
    +         ext_len = *p++;
    +         *rem_len = *rem_len - 1;
    +     }
    + 
    ++    if (*rem_len < 1) goto bad_packet_length;
    +     control_type = *p++;
    +     *rem_len = *rem_len - 1;
    + 
    +-    BNEP_TRACE_EVENT ("BNEP processing control packet rem_len %d, is_ext %d, ctrl_type %d", *rem_len, is_ext, control_type);
    ++    BNEP_TRACE_EVENT (
    ++       "%s: BNEP processing control packet rem_len %d, is_ext %d, ctrl_type %d",
    ++       __func__, *rem_len, is_ext, control_type);
    + 
    +     switch (control_type)
    +     {
    +     case BNEP_CONTROL_COMMAND_NOT_UNDERSTOOD:
    +-        BNEP_TRACE_ERROR ("BNEP Received Cmd not understood for ctl pkt type: %d", *p);
    ++       if (*rem_len < 1) {
    ++         BNEP_TRACE_ERROR(
    ++             "%s: Received BNEP_CONTROL_COMMAND_NOT_UNDERSTOOD with bad length",
    ++             __func__);
    ++         goto bad_packet_length;
    ++       }
    ++       BNEP_TRACE_ERROR(
    ++           "%s: Received BNEP_CONTROL_COMMAND_NOT_UNDERSTOOD for pkt type: %d",
    ++           __func__, *p);
    +         p++;
    +         *rem_len = *rem_len - 1;
    +         break;
    +@@ -788,9 +807,10 @@ UINT8 *bnep_process_control_packet (tBNEP_CONN *p_bcb, UINT8 *p, UINT16 *rem_len
    +         len = *p++;
    +         if (*rem_len < ((2 * len) + 1))
    +         {
    +-            bad_pkt = TRUE;
    +-            BNEP_TRACE_ERROR ("BNEP Received Setup message with bad length");
    +-            break;
    ++            BNEP_TRACE_ERROR(
    ++                "%s: Received BNEP_SETUP_CONNECTION_REQUEST_MSG with bad length",
    ++                __func__);
    ++            goto bad_packet_length;
    +         }
    +         if (!is_ext)
    +             bnep_process_setup_conn_req (p_bcb, p, (UINT8)len);
    +@@ -799,6 +819,12 @@ UINT8 *bnep_process_control_packet (tBNEP_CONN *p_bcb, UINT8 *p, UINT16 *rem_len
    +         break;
    + 
    +     case BNEP_SETUP_CONNECTION_RESPONSE_MSG:
    ++        if (*rem_len < 2) {
    ++          BNEP_TRACE_ERROR(
    ++              "%s: Received BNEP_SETUP_CONNECTION_RESPONSE_MSG with bad length",
    ++              __func__);
    ++          goto bad_packet_length;
    ++        }
    +         if (!is_ext)
    +             bnep_process_setup_conn_responce (p_bcb, p);
    +         p += 2;
    +@@ -809,9 +835,10 @@ UINT8 *bnep_process_control_packet (tBNEP_CONN *p_bcb, UINT8 *p, UINT16 *rem_len
    +         BE_STREAM_TO_UINT16 (len, p);
    +         if (*rem_len < (len + 2))
    +         {
    +-            bad_pkt = TRUE;
    +-            BNEP_TRACE_ERROR ("BNEP Received Filter set message with bad length");
    +-            break;
    ++           BNEP_TRACE_ERROR(
    ++               "%s: Received BNEP_FILTER_NET_TYPE_SET_MSG with bad length",
    ++               __func__);
    ++           goto bad_packet_length;
    +         }
    +         bnepu_process_peer_filter_set (p_bcb, p, len);
    +         p += len;
    +@@ -819,6 +846,12 @@ UINT8 *bnep_process_control_packet (tBNEP_CONN *p_bcb, UINT8 *p, UINT16 *rem_len
    +         break;
    + 
    +     case BNEP_FILTER_NET_TYPE_RESPONSE_MSG:
    ++        if (*rem_len < 2) {
    ++          BNEP_TRACE_ERROR(
    ++              "%s: Received BNEP_FILTER_NET_TYPE_RESPONSE_MSG with bad length",
    ++              __func__);
    ++          goto bad_packet_length;
    ++        }
    +         bnepu_process_peer_filter_rsp (p_bcb, p);
    +         p += 2;
    +         *rem_len = *rem_len - 2;
    +@@ -828,9 +861,10 @@ UINT8 *bnep_process_control_packet (tBNEP_CONN *p_bcb, UINT8 *p, UINT16 *rem_len
    +         BE_STREAM_TO_UINT16 (len, p);
    +         if (*rem_len < (len + 2))
    +         {
    +-            bad_pkt = TRUE;
    +-            BNEP_TRACE_ERROR ("BNEP Received Multicast Filter Set message with bad length");
    +-            break;
    ++           BNEP_TRACE_ERROR (
    ++               "%s: Received BNEP_FILTER_MULTI_ADDR_SET_MSG with bad length",
    ++               __func__);
    ++           goto bad_packet_length;
    +         }
    +         bnepu_process_peer_multicast_filter_set (p_bcb, p, len);
    +         p += len;
    +@@ -838,30 +872,38 @@ UINT8 *bnep_process_control_packet (tBNEP_CONN *p_bcb, UINT8 *p, UINT16 *rem_len
    +         break;
    + 
    +     case BNEP_FILTER_MULTI_ADDR_RESPONSE_MSG:
    ++        if (*rem_len < 2) {
    ++          BNEP_TRACE_ERROR(
    ++              "%s: Received BNEP_FILTER_MULTI_ADDR_RESPONSE_MSG with bad length",
    ++              __func__);
    ++          goto bad_packet_length;
    ++        }
    +         bnepu_process_multicast_filter_rsp (p_bcb, p);
    +         p += 2;
    +         *rem_len = *rem_len - 2;
    +         break;
    + 
    +     default :
    +-        BNEP_TRACE_ERROR ("BNEP - bad ctl pkt type: %d", control_type);
    ++        BNEP_TRACE_ERROR("%s: BNEP - bad ctl pkt type: %d", __func__,
    ++                         control_type);
    +         bnep_send_command_not_understood (p_bcb, control_type);
    +-        if (is_ext)
    +-        {
    ++        if (is_ext && (ext_len > 0)) {
    ++            if (*rem_len < (ext_len - 1)) {
    ++               goto bad_packet_length;
    ++            }
    +             p += (ext_len - 1);
    +             *rem_len -= (ext_len - 1);
    +         }
    +         break;
    +     }
    + 
    +-    if (bad_pkt)
    +-    {
    +-        BNEP_TRACE_ERROR ("BNEP - bad ctl pkt length: %d", *rem_len);
    +-        *rem_len = 0;
    +-        return NULL;
    +-    }
    +-
    +     return p;
    ++
    ++bad_packet_length:
    ++  BNEP_TRACE_ERROR("%s: bad control packet length: original=%d remaining=%d",
    ++                   __func__, rem_len_orig, *rem_len);
    ++  *rem_len = 0;
    ++  return NULL;
    + }
    + 
    + 
    +diff --git a/stack/l2cap/l2cap_client.c b/stack/l2cap/l2cap_client.c
    +index 7e8b3cb..ce58cdc 100644
    +--- a/stack/l2cap/l2cap_client.c
    ++++ b/stack/l2cap/l2cap_client.c
    +@@ -370,7 +370,7 @@ static void fragment_packet(l2cap_client_t *client, buffer_t *packet) {
    +   assert(packet != NULL);
    + 
    +   // TODO(sharvil): eliminate copy into BT_HDR.
    +-  BT_HDR *bt_packet = osi_malloc(buffer_length(packet) + L2CAP_MIN_OFFSET);
    ++  BT_HDR *bt_packet = osi_malloc(buffer_length(packet) + L2CAP_MIN_OFFSET + sizeof(BT_HDR));
    +   bt_packet->offset = L2CAP_MIN_OFFSET;
    +   bt_packet->len = buffer_length(packet);
    +   memcpy(bt_packet->data + bt_packet->offset, buffer_ptr(packet), buffer_length(packet));
    +@@ -384,7 +384,7 @@ static void fragment_packet(l2cap_client_t *client, buffer_t *packet) {
    +       break;
    +     }
    + 
    +-    BT_HDR *fragment = osi_malloc(client->remote_mtu + L2CAP_MIN_OFFSET);
    ++    BT_HDR *fragment = osi_malloc(client->remote_mtu + L2CAP_MIN_OFFSET + sizeof(BT_HDR));
    +     fragment->offset = L2CAP_MIN_OFFSET;
    +     fragment->len = client->remote_mtu;
    +     memcpy(fragment->data + fragment->offset, bt_packet->data + bt_packet->offset, client->remote_mtu);
    +diff --git a/stack/mcap/mca_cact.c b/stack/mcap/mca_cact.c
    +index 583a342..6694ff7 100644
    +--- a/stack/mcap/mca_cact.c
    ++++ b/stack/mcap/mca_cact.c
    +@@ -122,7 +122,7 @@ void mca_ccb_snd_req(tMCA_CCB *p_ccb, tMCA_CCB_EVT *p_data)
    +         p_ccb->p_tx_req = p_msg;
    +         if (!p_ccb->cong)
    +         {
    +-            BT_HDR *p_pkt = (BT_HDR *)osi_malloc(MCA_CTRL_MTU);
    ++            BT_HDR *p_pkt = (BT_HDR *)osi_malloc(MCA_CTRL_MTU + sizeof(BT_HDR));
    + 
    +             p_pkt->offset = L2CAP_MIN_OFFSET;
    +             p = p_start = (UINT8*)(p_pkt + 1) + L2CAP_MIN_OFFSET;
    +@@ -164,7 +164,7 @@ void mca_ccb_snd_rsp(tMCA_CCB *p_ccb, tMCA_CCB_EVT *p_data)
    +     tMCA_CCB_MSG *p_msg = (tMCA_CCB_MSG *)p_data;
    +     UINT8   *p, *p_start;
    +     BOOLEAN chk_mdl = FALSE;
    +-    BT_HDR *p_pkt = (BT_HDR *)osi_malloc(MCA_CTRL_MTU);
    ++    BT_HDR *p_pkt = (BT_HDR *)osi_malloc(MCA_CTRL_MTU + sizeof(BT_HDR));
    + 
    +     MCA_TRACE_DEBUG("%s cong=%d req=%d", __func__, p_ccb->cong, p_msg->op_code);
    +     /* assume that API functions verified the parameters */
    +@@ -404,7 +404,7 @@ void mca_ccb_hdl_req(tMCA_CCB *p_ccb, tMCA_CCB_EVT *p_data)
    + 
    +     if (((reject_code != MCA_RSP_SUCCESS) && (evt_data.hdr.op_code != MCA_OP_SYNC_INFO_IND))
    +         || send_rsp) {
    +-        BT_HDR *p_buf = (BT_HDR *)osi_malloc(MCA_CTRL_MTU);
    ++        BT_HDR *p_buf = (BT_HDR *)osi_malloc(MCA_CTRL_MTU + sizeof(BT_HDR));
    +         p_buf->offset = L2CAP_MIN_OFFSET;
    +         p = p_start = (UINT8*)(p_buf + 1) + L2CAP_MIN_OFFSET;
    +         *p++ = reject_opcode;
    +diff --git a/stack/pan/pan_main.c b/stack/pan/pan_main.c
    +index 5c3a367..044469d 100644
    +--- a/stack/pan/pan_main.c
    ++++ b/stack/pan/pan_main.c
    +@@ -221,6 +221,38 @@ void pan_conn_ind_cb (UINT16 handle,
    +         BNEP_ConnectResp (handle, BNEP_CONN_FAILED_DST_UUID);
    +         return;
    +     }
    ++    /* Check for valid interactions between the three PAN profile roles */
    ++    /*
    ++     * For reference, see Table 1 in PAN Profile v1.0 spec.
    ++     * Note: the remote is the initiator.
    ++     */
    ++    bool is_valid_interaction = false;
    ++    switch (remote_uuid->uu.uuid16) {
    ++      case UUID_SERVCLASS_NAP:
    ++      case UUID_SERVCLASS_GN:
    ++         if (local_uuid->uu.uuid16 == UUID_SERVCLASS_PANU)
    ++          is_valid_interaction = true;
    ++        break;
    ++      case UUID_SERVCLASS_PANU:
    ++        is_valid_interaction = true;
    ++        break;
    ++    }
    ++    /*
    ++     * Explicitly disable connections to the local PANU if the remote is
    ++     * not PANU.
    ++     */
    ++    if ((local_uuid->uu.uuid16 == UUID_SERVCLASS_PANU) &&
    ++        (remote_uuid->uu.uuid16 != UUID_SERVCLASS_PANU)) {
    ++      is_valid_interaction = false;
    ++    }
    ++    if (!is_valid_interaction) {
    ++      PAN_TRACE_ERROR(
    ++          "PAN Connection failed because of invalid PAN profile roles "
    ++          "interaction: Remote UUID 0x%x Local UUID 0x%x",
    ++          remote_uuid->uu.uuid16, local_uuid->uu.uuid16);
    ++      BNEP_ConnectResp(handle, BNEP_CONN_FAILED_SRC_UUID);
    ++      return;
    ++    }
    + 
    +     /* Requested destination role is */
    +     if (local_uuid->uu.uuid16 == UUID_SERVCLASS_PANU)
    +diff --git a/stack/sdp/sdp_server.c b/stack/sdp/sdp_server.c
    +index 627f4cf..5b0bde4 100644
    +--- a/stack/sdp/sdp_server.c
    ++++ b/stack/sdp/sdp_server.c
    +@@ -230,7 +230,7 @@ static void process_service_search (tCONN_CB *p_ccb, UINT16 trans_num,
    +         }
    +         BE_STREAM_TO_UINT16 (cont_offset, p_req);
    + 
    +-        if (cont_offset != p_ccb->cont_offset)
    ++        if (cont_offset != p_ccb->cont_offset || num_rsp_handles < cont_offset)
    +         {
    +             sdpu_build_n_send_error (p_ccb, trans_num, SDP_INVALID_CONT_STATE,
    +                                      SDP_TEXT_BAD_CONT_INX);
    
    From 122e2c74b85a20894b16d20d41f20de8265386c3 Mon Sep 17 00:00:00 2001
    From: AndDiSa <anddisa@googlemail.com>
    Date: Sat, 7 Oct 2017 12:16:00 +0200
    Subject: [PATCH 086/159] update patches
    
    Change-Id: I54ba20df125f8ec3293642e2df1bb1c1d8a61f86
    ---
     build.patch                  |   4 +-
     external_libhevc.patch       |  32 +-
     external_tremolo.patch       | 751 ++++++++++++++++++++++++++++++++++-
     frameworks_av.patch          | 238 ++++++++++-
     frameworks_base.patch        | 105 +++++
     hardware_broadcom_wlan.patch |  63 +++
     hardware_ril.patch           |  42 +-
     libcore.patch                |  66 +++
     system_sepolicy.patch        |  24 +-
     9 files changed, 1292 insertions(+), 33 deletions(-)
     create mode 100644 libcore.patch
    
    diff --git a/build.patch b/build.patch
    index df69bcd..f7d6580 100644
    --- a/build.patch
    +++ b/build.patch
    @@ -323,7 +323,7 @@ index 0000000..ee76dc2
     +ALL_PREBUILT += $(INSTALLED_KERNEL_TARGET)
     +endif
     diff --git a/core/version_defaults.mk b/core/version_defaults.mk
    -index 7c96344..638983f 100644
    +index 7c96344..9ff3565 100644
     --- a/core/version_defaults.mk
     +++ b/core/version_defaults.mk
     @@ -131,7 +131,7 @@ ifeq "" "$(PLATFORM_SECURITY_PATCH)"
    @@ -331,7 +331,7 @@ index 7c96344..638983f 100644
          #  It must match one of the Android Security Patch Level strings of the Public Security Bulletins.
          #  If there is no $PLATFORM_SECURITY_PATCH set, keep it empty.
     -    PLATFORM_SECURITY_PATCH := 2017-08-05
    -+    PLATFORM_SECURITY_PATCH := 2017-09-05
    ++    PLATFORM_SECURITY_PATCH := 2017-10-05
      endif
      
      ifeq "" "$(PLATFORM_BASE_OS)"
    diff --git a/external_libhevc.patch b/external_libhevc.patch
    index 86b70fe..ff18293 100644
    --- a/external_libhevc.patch
    +++ b/external_libhevc.patch
    @@ -43,7 +43,7 @@ index 93d2ad4..baa6375 100644
      }hrd_params_t;
      
     diff --git a/decoder/ihevcd_decode.c b/decoder/ihevcd_decode.c
    -index d656519..87c3bd7 100644
    +index d656519..7b82e84 100644
     --- a/decoder/ihevcd_decode.c
     +++ b/decoder/ihevcd_decode.c
     @@ -81,6 +81,7 @@
    @@ -65,8 +65,16 @@ index d656519..87c3bd7 100644
                  /* Set remaining number of rows to be processed */
                  ret = ihevcd_fmt_conv(ps_codec, &ps_codec->as_process[prev_proc_idx],
                                        ps_dec_ip->s_out_buffer.pu1_bufs[0],
    +@@ -628,7 +633,6 @@ WORD32 ihevcd_decode(iv_obj_t *ps_codec_obj, void *pv_api_ip, void *pv_api_op)
    + 
    +         if(IHEVCD_IGNORE_SLICE == ret)
    +         {
    +-            ps_codec->s_parse.i4_cur_slice_idx = MAX(0, (ps_codec->s_parse.i4_cur_slice_idx - 1));
    +             ps_codec->pu1_inp_bitsbuf += (nal_ofst + nal_len);
    +             ps_codec->i4_bytes_remaining -= (nal_ofst + nal_len);
    + 
     diff --git a/decoder/ihevcd_parse_headers.c b/decoder/ihevcd_parse_headers.c
    -index c0f1564..29a309d 100644
    +index c0f1564..06f35a3 100644
     --- a/decoder/ihevcd_parse_headers.c
     +++ b/decoder/ihevcd_parse_headers.c
     @@ -1285,15 +1285,31 @@ IHEVCD_ERROR_T ihevcd_parse_sps(codec_t *ps_codec)
    @@ -101,6 +109,26 @@ index c0f1564..29a309d 100644
              ps_sps->i2_pic_crop_bottom_offset = value;
          }
          else
    +@@ -1797,6 +1813,19 @@ IHEVCD_ERROR_T ihevcd_parse_pps(codec_t *ps_codec)
    +     BITS_PARSE("tiles_enabled_flag", value, ps_bitstrm, 1);
    +     ps_pps->i1_tiles_enabled_flag = value;
    + 
    ++    /* When tiles are enabled and width or height is >= 4096,
    ++     * CTB Size should at least be 32. 16x16 CTBs can result
    ++     * in tile position greater than 255 for 4096,
    ++     * which decoder does not support.
    ++     */
    ++    if((ps_pps->i1_tiles_enabled_flag) &&
    ++                    (ps_sps->i1_log2_ctb_size == 4) &&
    ++                    ((ps_sps->i2_pic_width_in_luma_samples >= 4096) ||
    ++                    (ps_sps->i2_pic_height_in_luma_samples >= 4096)))
    ++    {
    ++        return IHEVCD_INVALID_HEADER;
    ++    }
    ++
    +     BITS_PARSE("entropy_coding_sync_enabled_flag", value, ps_bitstrm, 1);
    +     ps_pps->i1_entropy_coding_sync_enabled_flag = value;
    + 
     diff --git a/decoder/ihevcd_parse_slice.c b/decoder/ihevcd_parse_slice.c
     index 126b14c..9f92a0d 100644
     --- a/decoder/ihevcd_parse_slice.c
    diff --git a/external_tremolo.patch b/external_tremolo.patch
    index dae3d8e..e6ee1e9 100644
    --- a/external_tremolo.patch
    +++ b/external_tremolo.patch
    @@ -1,8 +1,745 @@
    +diff --git a/Tremolo/codebook.c b/Tremolo/codebook.c
    +index 4d0dd91..467640d 100644
    +--- a/Tremolo/codebook.c
    ++++ b/Tremolo/codebook.c
    +@@ -59,7 +59,7 @@ int _ilog(unsigned int v){
    + }
    + 
    + static ogg_uint32_t decpack(long entry,long used_entry,long quantvals,
    +-			    codebook *b,oggpack_buffer *opb,int maptype){
    ++                            codebook *b,oggpack_buffer *opb,int maptype){
    +   ogg_uint32_t ret=0;
    +   int j;
    + 
    +@@ -72,13 +72,13 @@ static ogg_uint32_t decpack(long entry,long used_entry,long quantvals,
    +     if(maptype==1){
    +       /* vals are already read into temporary column vector here */
    +       for(j=0;j<b->dim;j++){
    +-	ogg_uint32_t off=entry%quantvals;
    +-	entry/=quantvals;
    +-	ret|=((ogg_uint16_t *)(b->q_val))[off]<<(b->q_bits*j);
    ++        ogg_uint32_t off=entry%quantvals;
    ++        entry/=quantvals;
    ++        ret|=((ogg_uint16_t *)(b->q_val))[off]<<(b->q_bits*j);
    +       }
    +     }else{
    +       for(j=0;j<b->dim;j++)
    +-	ret|=oggpack_read(opb,b->q_bits)<<(b->q_bits*j);
    ++        ret|=oggpack_read(opb,b->q_bits)<<(b->q_bits*j);
    +     }
    +     return ret;
    + 
    +@@ -144,7 +144,7 @@ static int _determine_leaf_words(int nodeb, int leafwidth){
    + /* given a list of word lengths, number of used entries, and byte
    +    width of a leaf, generate the decode table */
    + static int _make_words(char *l,long n,ogg_uint32_t *r,long quantvals,
    +-		       codebook *b, oggpack_buffer *opb,int maptype){
    ++                       codebook *b, oggpack_buffer *opb,int maptype){
    +   long i,j,count=0;
    +   long top=0;
    +   ogg_uint32_t marker[MARKER_SIZE];
    +@@ -164,54 +164,54 @@ static int _make_words(char *l,long n,ogg_uint32_t *r,long quantvals,
    +           ALOGE("b/23881715");
    +           return 1;
    +         }
    +-	ogg_uint32_t entry=marker[length];
    +-	long chase=0;
    +-	if(count && !entry)return -1; /* overpopulated tree! */
    +-
    +-	/* chase the tree as far as it's already populated, fill in past */
    +-	for(j=0;j<length-1;j++){
    +-	  int bit=(entry>>(length-j-1))&1;
    +-	  if(chase>=top){
    +-	    if (chase < 0 || chase >= n) return 1;
    +-	    top++;
    +-	    r[chase*2]=top;
    +-	    r[chase*2+1]=0;
    +-	  }else
    +-	    if (chase < 0 || chase >= n || chase*2+bit > n*2+1) return 1;
    +-	    if(!r[chase*2+bit])
    +-	      r[chase*2+bit]=top;
    +-	  chase=r[chase*2+bit];
    +-	  if (chase < 0 || chase >= n) return 1;
    +-	}
    +-	{
    +-	  int bit=(entry>>(length-j-1))&1;
    +-	  if(chase>=top){
    +-	    top++;
    +-	    r[chase*2+1]=0;
    +-	  }
    +-	  r[chase*2+bit]= decpack(i,count++,quantvals,b,opb,maptype) |
    +-	    0x80000000;
    +-	}
    +-
    +-	/* Look to see if the next shorter marker points to the node
    +-	   above. if so, update it and repeat.  */
    +-	for(j=length;j>0;j--){
    +-	  if(marker[j]&1){
    +-	    marker[j]=marker[j-1]<<1;
    +-	    break;
    +-	  }
    +-	  marker[j]++;
    +-	}
    +-
    +-	/* prune the tree; the implicit invariant says all the longer
    +-	   markers were dangling from our just-taken node.  Dangle them
    +-	   from our *new* node. */
    +-	for(j=length+1;j<MARKER_SIZE;j++)
    +-	  if((marker[j]>>1) == entry){
    +-	    entry=marker[j];
    +-	    marker[j]=marker[j-1]<<1;
    +-	  }else
    +-	    break;
    ++        ogg_uint32_t entry=marker[length];
    ++        long chase=0;
    ++        if(count && !entry)return -1; /* overpopulated tree! */
    ++
    ++        /* chase the tree as far as it's already populated, fill in past */
    ++        for(j=0;j<length-1;j++){
    ++          int bit=(entry>>(length-j-1))&1;
    ++          if(chase>=top){
    ++            if (chase < 0 || chase >= n) return 1;
    ++            top++;
    ++            r[chase*2]=top;
    ++            r[chase*2+1]=0;
    ++          }else
    ++            if (chase < 0 || chase >= n || chase*2+bit > n*2+1) return 1;
    ++            if(!r[chase*2+bit])
    ++              r[chase*2+bit]=top;
    ++          chase=r[chase*2+bit];
    ++          if (chase < 0 || chase >= n) return 1;
    ++        }
    ++        {
    ++          int bit=(entry>>(length-j-1))&1;
    ++          if(chase>=top){
    ++            top++;
    ++            r[chase*2+1]=0;
    ++          }
    ++          r[chase*2+bit]= decpack(i,count++,quantvals,b,opb,maptype) |
    ++            0x80000000;
    ++        }
    ++
    ++        /* Look to see if the next shorter marker points to the node
    ++           above. if so, update it and repeat.  */
    ++        for(j=length;j>0;j--){
    ++          if(marker[j]&1){
    ++            marker[j]=marker[j-1]<<1;
    ++            break;
    ++          }
    ++          marker[j]++;
    ++        }
    ++
    ++        /* prune the tree; the implicit invariant says all the longer
    ++           markers were dangling from our just-taken node.  Dangle them
    ++           from our *new* node. */
    ++        for(j=length+1;j<MARKER_SIZE;j++)
    ++          if((marker[j]>>1) == entry){
    ++            entry=marker[j];
    ++            marker[j]=marker[j-1]<<1;
    ++          }else
    ++            break;
    +       }
    +     }
    +   }
    +@@ -234,7 +234,7 @@ static int _make_words(char *l,long n,ogg_uint32_t *r,long quantvals,
    + }
    + 
    + static int _make_decode_table(codebook *s,char *lengthlist,long quantvals,
    +-			      oggpack_buffer *opb,int maptype){
    ++                              oggpack_buffer *opb,int maptype){
    +   int i;
    +   ogg_uint32_t *work;
    + 
    +@@ -251,7 +251,7 @@ static int _make_decode_table(codebook *s,char *lengthlist,long quantvals,
    +     /* +1 (rather than -2) is to accommodate 0 and 1 sized books,
    +        which are specialcased to nodeb==4 */
    +     if(_make_words(lengthlist,s->entries,
    +-		   s->dec_table,quantvals,s,opb,maptype))return 1;
    ++                   s->dec_table,quantvals,s,opb,maptype))return 1;
    + 
    +     return 0;
    +   }
    +@@ -265,20 +265,20 @@ static int _make_decode_table(codebook *s,char *lengthlist,long quantvals,
    +   if (s->used_entries > INT_MAX/(s->dec_leafw+1)) goto error_out;
    +   if (s->dec_nodeb && s->used_entries * (s->dec_leafw+1) > INT_MAX/s->dec_nodeb) goto error_out;
    +   s->dec_table=_ogg_malloc((s->used_entries*(s->dec_leafw+1)-2)*
    +-			   s->dec_nodeb);
    ++                           s->dec_nodeb);
    +   if (!s->dec_table) goto error_out;
    + 
    +   if(s->dec_leafw==1){
    +     switch(s->dec_nodeb){
    +     case 1:
    +       for(i=0;i<s->used_entries*2-2;i++)
    +-	  ((unsigned char *)s->dec_table)[i]=(unsigned char)
    +-	    (((work[i] & 0x80000000UL) >> 24) | work[i]);
    ++          ((unsigned char *)s->dec_table)[i]=(unsigned char)
    ++            (((work[i] & 0x80000000UL) >> 24) | work[i]);
    +       break;
    +     case 2:
    +       for(i=0;i<s->used_entries*2-2;i++)
    +-	  ((ogg_uint16_t *)s->dec_table)[i]=(ogg_uint16_t)
    +-	    (((work[i] & 0x80000000UL) >> 16) | work[i]);
    ++          ((ogg_uint16_t *)s->dec_table)[i]=(ogg_uint16_t)
    ++            (((work[i] & 0x80000000UL) >> 16) | work[i]);
    +       break;
    +     }
    + 
    +@@ -290,62 +290,62 @@ static int _make_decode_table(codebook *s,char *lengthlist,long quantvals,
    +       unsigned char *out=(unsigned char *)s->dec_table;
    + 
    +       for(i=s->used_entries*2-4;i>=0;i-=2){
    +-	if(work[i]&0x80000000UL){
    +-	  if(work[i+1]&0x80000000UL){
    +-	    top-=4;
    +-	    out[top]=(work[i]>>8 & 0x7f)|0x80;
    +-	    out[top+1]=(work[i+1]>>8 & 0x7f)|0x80;
    +-	    out[top+2]=work[i] & 0xff;
    +-	    out[top+3]=work[i+1] & 0xff;
    +-	  }else{
    +-	    top-=3;
    +-	    out[top]=(work[i]>>8 & 0x7f)|0x80;
    +-	    out[top+1]=work[work[i+1]*2];
    +-	    out[top+2]=work[i] & 0xff;
    +-	  }
    +-	}else{
    +-	  if(work[i+1]&0x80000000UL){
    +-	    top-=3;
    +-	    out[top]=work[work[i]*2];
    +-	    out[top+1]=(work[i+1]>>8 & 0x7f)|0x80;
    +-	    out[top+2]=work[i+1] & 0xff;
    +-	  }else{
    +-	    top-=2;
    +-	    out[top]=work[work[i]*2];
    +-	    out[top+1]=work[work[i+1]*2];
    +-	  }
    +-	}
    +-	work[i]=top;
    ++        if(work[i]&0x80000000UL){
    ++          if(work[i+1]&0x80000000UL){
    ++            top-=4;
    ++            out[top]=(work[i]>>8 & 0x7f)|0x80;
    ++            out[top+1]=(work[i+1]>>8 & 0x7f)|0x80;
    ++            out[top+2]=work[i] & 0xff;
    ++            out[top+3]=work[i+1] & 0xff;
    ++          }else{
    ++            top-=3;
    ++            out[top]=(work[i]>>8 & 0x7f)|0x80;
    ++            out[top+1]=work[work[i+1]*2];
    ++            out[top+2]=work[i] & 0xff;
    ++          }
    ++        }else{
    ++          if(work[i+1]&0x80000000UL){
    ++            top-=3;
    ++            out[top]=work[work[i]*2];
    ++            out[top+1]=(work[i+1]>>8 & 0x7f)|0x80;
    ++            out[top+2]=work[i+1] & 0xff;
    ++          }else{
    ++            top-=2;
    ++            out[top]=work[work[i]*2];
    ++            out[top+1]=work[work[i+1]*2];
    ++          }
    ++        }
    ++        work[i]=top;
    +       }
    +     }else{
    +       ogg_uint16_t *out=(ogg_uint16_t *)s->dec_table;
    +       for(i=s->used_entries*2-4;i>=0;i-=2){
    +-	if(work[i]&0x80000000UL){
    +-	  if(work[i+1]&0x80000000UL){
    +-	    top-=4;
    +-	    out[top]=(work[i]>>16 & 0x7fff)|0x8000;
    +-	    out[top+1]=(work[i+1]>>16 & 0x7fff)|0x8000;
    +-	    out[top+2]=work[i] & 0xffff;
    +-	    out[top+3]=work[i+1] & 0xffff;
    +-	  }else{
    +-	    top-=3;
    +-	    out[top]=(work[i]>>16 & 0x7fff)|0x8000;
    +-	    out[top+1]=work[work[i+1]*2];
    +-	    out[top+2]=work[i] & 0xffff;
    +-	  }
    +-	}else{
    +-	  if(work[i+1]&0x80000000UL){
    +-	    top-=3;
    +-	    out[top]=work[work[i]*2];
    +-	    out[top+1]=(work[i+1]>>16 & 0x7fff)|0x8000;
    +-	    out[top+2]=work[i+1] & 0xffff;
    +-	  }else{
    +-	    top-=2;
    +-	    out[top]=work[work[i]*2];
    +-	    out[top+1]=work[work[i+1]*2];
    +-	  }
    +-	}
    +-	work[i]=top;
    ++        if(work[i]&0x80000000UL){
    ++          if(work[i+1]&0x80000000UL){
    ++            top-=4;
    ++            out[top]=(work[i]>>16 & 0x7fff)|0x8000;
    ++            out[top+1]=(work[i+1]>>16 & 0x7fff)|0x8000;
    ++            out[top+2]=work[i] & 0xffff;
    ++            out[top+3]=work[i+1] & 0xffff;
    ++          }else{
    ++            top-=3;
    ++            out[top]=(work[i]>>16 & 0x7fff)|0x8000;
    ++            out[top+1]=work[work[i+1]*2];
    ++            out[top+2]=work[i] & 0xffff;
    ++          }
    ++        }else{
    ++          if(work[i+1]&0x80000000UL){
    ++            top-=3;
    ++            out[top]=work[work[i]*2];
    ++            out[top+1]=(work[i+1]>>16 & 0x7fff)|0x8000;
    ++            out[top+2]=work[i+1] & 0xffff;
    ++          }else{
    ++            top-=2;
    ++            out[top]=work[work[i]*2];
    ++            out[top+1]=work[work[i+1]*2];
    ++          }
    ++        }
    ++        work[i]=top;
    +       }
    +     }
    +   }
    +@@ -436,23 +436,23 @@ int vorbis_book_unpack(oggpack_buffer *opb,codebook *s){
    +       /* yes, unused entries */
    + 
    +       for(i=0;i<s->entries;i++){
    +-	if(oggpack_read(opb,1)){
    +-	  long num=oggpack_read(opb,5);
    +-	  if(num==-1)goto _eofout;
    +-	  lengthlist[i]=(char)(num+1);
    +-	  s->used_entries++;
    +-	  if(num+1>s->dec_maxlength)s->dec_maxlength=num+1;
    +-	}else
    +-	  lengthlist[i]=0;
    ++        if(oggpack_read(opb,1)){
    ++          long num=oggpack_read(opb,5);
    ++          if(num==-1)goto _eofout;
    ++          lengthlist[i]=(char)(num+1);
    ++          s->used_entries++;
    ++          if(num+1>s->dec_maxlength)s->dec_maxlength=num+1;
    ++        }else
    ++          lengthlist[i]=0;
    +       }
    +     }else{
    +       /* all entries used; no tagging */
    +       s->used_entries=s->entries;
    +       for(i=0;i<s->entries;i++){
    +-	long num=oggpack_read(opb,5);
    +-	if(num==-1)goto _eofout;
    +-	lengthlist[i]=(char)(num+1);
    +-	if(num+1>s->dec_maxlength)s->dec_maxlength=num+1;
    ++        long num=oggpack_read(opb,5);
    ++        if(num==-1)goto _eofout;
    ++        lengthlist[i]=(char)(num+1);
    ++        if(num+1>s->dec_maxlength)s->dec_maxlength=num+1;
    +       }
    +     }
    + 
    +@@ -467,12 +467,12 @@ int vorbis_book_unpack(oggpack_buffer *opb,codebook *s){
    +       if (!lengthlist) goto _eofout;
    + 
    +       for(i=0;i<s->entries;){
    +-	long num=oggpack_read(opb,_ilog(s->entries-i));
    +-	if(num<0)goto _eofout;
    +-	for(j=0;j<num && i<s->entries;j++,i++)
    +-	  lengthlist[i]=(char)length;
    +-	s->dec_maxlength=length;
    +-	length++;
    ++        long num=oggpack_read(opb,_ilog(s->entries-i));
    ++        if(num<0)goto _eofout;
    ++        for(j=0;j<num && i<s->entries;j++,i++)
    ++          lengthlist[i]=(char)length;
    ++        s->dec_maxlength=length;
    ++        length++;
    +       }
    +     }
    +     break;
    +@@ -524,55 +524,55 @@ int vorbis_book_unpack(oggpack_buffer *opb,codebook *s){
    + 
    + 
    +       if(total1<=4 && total1<=total2){
    +-	/* use dec_type 1: vector of packed values */
    +-
    +-	/* need quantized values before  */
    +-	s->q_val=calloc(sizeof(ogg_uint16_t), quantvals);
    +-	if (!s->q_val) goto _eofout;
    +-	for(i=0;i<quantvals;i++)
    +-	  ((ogg_uint16_t *)s->q_val)[i]=(ogg_uint16_t)oggpack_read(opb,s->q_bits);
    +-
    +-	if(oggpack_eop(opb)){
    +-	  goto _eofout;
    +-	}
    +-
    +-	s->dec_type=1;
    +-	s->dec_nodeb=_determine_node_bytes(s->used_entries,
    +-					   (s->q_bits*s->dim+8)/8);
    +-	s->dec_leafw=_determine_leaf_words(s->dec_nodeb,
    +-					   (s->q_bits*s->dim+8)/8);
    +-	if(_make_decode_table(s,lengthlist,quantvals,opb,maptype)){
    +-	  goto _errout;
    +-	}
    +-
    +-	free(s->q_val);
    +-	s->q_val=0;
    ++        /* use dec_type 1: vector of packed values */
    ++
    ++        /* need quantized values before  */
    ++        s->q_val=calloc(sizeof(ogg_uint16_t), quantvals);
    ++        if (!s->q_val) goto _eofout;
    ++        for(i=0;i<quantvals;i++)
    ++          ((ogg_uint16_t *)s->q_val)[i]=(ogg_uint16_t)oggpack_read(opb,s->q_bits);
    ++
    ++        if(oggpack_eop(opb)){
    ++          goto _eofout;
    ++        }
    ++
    ++        s->dec_type=1;
    ++        s->dec_nodeb=_determine_node_bytes(s->used_entries,
    ++                                           (s->q_bits*s->dim+8)/8);
    ++        s->dec_leafw=_determine_leaf_words(s->dec_nodeb,
    ++                                           (s->q_bits*s->dim+8)/8);
    ++        if(_make_decode_table(s,lengthlist,quantvals,opb,maptype)){
    ++          goto _errout;
    ++        }
    ++
    ++        free(s->q_val);
    ++        s->q_val=0;
    + 
    +       }else{
    +-	/* use dec_type 2: packed vector of column offsets */
    +-
    +-	/* need quantized values before */
    +-	if(s->q_bits<=8){
    +-	  s->q_val=_ogg_malloc(quantvals);
    +-	  if (!s->q_val) goto _eofout;
    +-	  for(i=0;i<quantvals;i++)
    +-	    ((unsigned char *)s->q_val)[i]=(unsigned char)oggpack_read(opb,s->q_bits);
    +-	}else{
    +-	  s->q_val=_ogg_malloc(quantvals*2);
    +-	  if (!s->q_val) goto _eofout;
    +-	  for(i=0;i<quantvals;i++)
    +-	    ((ogg_uint16_t *)s->q_val)[i]=(ogg_uint16_t)oggpack_read(opb,s->q_bits);
    +-	}
    +-
    +-	if(oggpack_eop(opb))goto _eofout;
    +-
    +-	s->q_pack=_ilog(quantvals-1);
    +-	s->dec_type=2;
    +-	s->dec_nodeb=_determine_node_bytes(s->used_entries,
    +-					   (_ilog(quantvals-1)*s->dim+8)/8);
    +-	s->dec_leafw=_determine_leaf_words(s->dec_nodeb,
    +-					   (_ilog(quantvals-1)*s->dim+8)/8);
    +-	if(_make_decode_table(s,lengthlist,quantvals,opb,maptype))goto _errout;
    ++        /* use dec_type 2: packed vector of column offsets */
    ++
    ++        /* need quantized values before */
    ++        if(s->q_bits<=8){
    ++          s->q_val=_ogg_malloc(quantvals);
    ++          if (!s->q_val) goto _eofout;
    ++          for(i=0;i<quantvals;i++)
    ++            ((unsigned char *)s->q_val)[i]=(unsigned char)oggpack_read(opb,s->q_bits);
    ++        }else{
    ++          s->q_val=_ogg_malloc(quantvals*2);
    ++          if (!s->q_val) goto _eofout;
    ++          for(i=0;i<quantvals;i++)
    ++            ((ogg_uint16_t *)s->q_val)[i]=(ogg_uint16_t)oggpack_read(opb,s->q_bits);
    ++        }
    ++
    ++        if(oggpack_eop(opb))goto _eofout;
    ++
    ++        s->q_pack=_ilog(quantvals-1);
    ++        s->dec_type=2;
    ++        s->dec_nodeb=_determine_node_bytes(s->used_entries,
    ++                                           (_ilog(quantvals-1)*s->dim+8)/8);
    ++        s->dec_leafw=_determine_leaf_words(s->dec_nodeb,
    ++                                           (_ilog(quantvals-1)*s->dim+8)/8);
    ++        if(_make_decode_table(s,lengthlist,quantvals,opb,maptype))goto _errout;
    + 
    +       }
    +     }
    +@@ -604,11 +604,11 @@ int vorbis_book_unpack(oggpack_buffer *opb,codebook *s){
    +       s->q_val=_ogg_malloc(s->q_pack*s->used_entries);
    + 
    +       if(s->q_bits<=8){
    +-	for(i=0;i<s->used_entries*s->dim;i++)
    +-	  ((unsigned char *)(s->q_val))[i]=(unsigned char)oggpack_read(opb,s->q_bits);
    ++        for(i=0;i<s->used_entries*s->dim;i++)
    ++          ((unsigned char *)(s->q_val))[i]=(unsigned char)oggpack_read(opb,s->q_bits);
    +       }else{
    +-	for(i=0;i<s->used_entries*s->dim;i++)
    +-	  ((ogg_uint16_t *)(s->q_val))[i]=(ogg_uint16_t)oggpack_read(opb,s->q_bits);
    ++        for(i=0;i<s->used_entries*s->dim;i++)
    ++          ((ogg_uint16_t *)(s->q_val))[i]=(ogg_uint16_t)oggpack_read(opb,s->q_bits);
    +       }
    +     }
    +     break;
    +@@ -646,7 +646,7 @@ ogg_uint32_t decode_packed_entry_number(codebook *book,
    +                                         oggpack_buffer *b);
    + #else
    + static inline ogg_uint32_t decode_packed_entry_number(codebook *book,
    +-						      oggpack_buffer *b){
    ++                                                      oggpack_buffer *b){
    +   ogg_uint32_t chase=0;
    +   int  read=book->dec_maxlength;
    +   long lok = oggpack_look(b,read),i;
    +@@ -669,8 +669,8 @@ static inline ogg_uint32_t decode_packed_entry_number(codebook *book,
    +       unsigned char *t=(unsigned char *)book->dec_table;
    + 
    +       for(i=0;i<read;i++){
    +-	chase=t[chase*2+((lok>>i)&1)];
    +-	if(chase&0x80UL)break;
    ++        chase=t[chase*2+((lok>>i)&1)];
    ++        if(chase&0x80UL)break;
    +       }
    +       chase&=0x7fUL;
    +       break;
    +@@ -681,13 +681,13 @@ static inline ogg_uint32_t decode_packed_entry_number(codebook *book,
    +       /* 8/16 - Used by infile2 */
    +       unsigned char *t=(unsigned char *)book->dec_table;
    +       for(i=0;i<read;i++){
    +-	int bit=(lok>>i)&1;
    +-	int next=t[chase+bit];
    +-	if(next&0x80){
    +-	  chase= (next<<8) | t[chase+bit+1+(!bit || t[chase]&0x80)];
    +-	  break;
    +-	}
    +-	chase=next;
    ++        int bit=(lok>>i)&1;
    ++        int next=t[chase+bit];
    ++        if(next&0x80){
    ++          chase= (next<<8) | t[chase+bit+1+(!bit || t[chase]&0x80)];
    ++          break;
    ++        }
    ++        chase=next;
    +       }
    +       //chase&=0x7fffUL;
    +       chase&=~0x8000UL;
    +@@ -698,8 +698,8 @@ static inline ogg_uint32_t decode_packed_entry_number(codebook *book,
    +       /* book->dec_nodeb==2, book->dec_leafw==1 */
    +       /* 16/16 - Used */
    +       for(i=0;i<read;i++){
    +-	chase=((ogg_uint16_t *)(book->dec_table))[chase*2+((lok>>i)&1)];
    +-	if(chase&0x8000UL)break;
    ++        chase=((ogg_uint16_t *)(book->dec_table))[chase*2+((lok>>i)&1)];
    ++        if(chase&0x8000UL)break;
    +       }
    +       //chase&=0x7fffUL;
    +       chase&=~0x8000UL;
    +@@ -711,13 +711,13 @@ static inline ogg_uint32_t decode_packed_entry_number(codebook *book,
    +       /* 16/32 - Used by infile2 */
    +       ogg_uint16_t *t=(ogg_uint16_t *)book->dec_table;
    +       for(i=0;i<read;i++){
    +-	int bit=(lok>>i)&1;
    +-	int next=t[chase+bit];
    +-	if(next&0x8000){
    +-	  chase= (next<<16) | t[chase+bit+1+(!bit || t[chase]&0x8000)];
    +-	  break;
    +-	}
    +-	chase=next;
    ++        int bit=(lok>>i)&1;
    ++        int next=t[chase+bit];
    ++        if(next&0x8000){
    ++          chase= (next<<16) | t[chase+bit+1+(!bit || t[chase]&0x8000)];
    ++          break;
    ++        }
    ++        chase=next;
    +       }
    +       //chase&=0x7fffffffUL;
    +       chase&=~0x80000000UL;
    +@@ -727,8 +727,8 @@ static inline ogg_uint32_t decode_packed_entry_number(codebook *book,
    +     {
    +       //Output("32/32");
    +       for(i=0;i<read;i++){
    +-	chase=((ogg_uint32_t *)(book->dec_table))[chase*2+((lok>>i)&1)];
    +-	if(chase&0x80000000UL)break;
    ++        chase=((ogg_uint32_t *)(book->dec_table))[chase*2+((lok>>i)&1)];
    ++        if(chase&0x80000000UL)break;
    +       }
    +       //chase&=0x7fffffffUL;
    +       chase&=~0x80000000UL;
    +@@ -777,9 +777,9 @@ static int decode_map(codebook *s, oggpack_buffer *b, ogg_int32_t *v, int point)
    +     int mask=(1<<s->q_pack)-1;
    +     for(i=0;i<s->dim;i++){
    +       if(s->q_bits<=8)
    +-	v[i]=((unsigned char *)(s->q_val))[entry&mask];
    ++        v[i]=((unsigned char *)(s->q_val))[entry&mask];
    +       else
    +-	v[i]=((ogg_uint16_t *)(s->q_val))[entry&mask];
    ++        v[i]=((ogg_uint16_t *)(s->q_val))[entry&mask];
    +       entry>>=s->q_pack;
    +     }
    +     break;
    +@@ -790,10 +790,10 @@ static int decode_map(codebook *s, oggpack_buffer *b, ogg_int32_t *v, int point)
    + 
    +     if(s->q_bits<=8){
    +       for(i=0;i<s->dim;i++)
    +-	v[i]=((unsigned char *)ptr)[i];
    ++        v[i]=((unsigned char *)ptr)[i];
    +     }else{
    +       for(i=0;i<s->dim;i++)
    +-	v[i]=((ogg_uint16_t *)ptr)[i];
    ++        v[i]=((ogg_uint16_t *)ptr)[i];
    +     }
    +     break;
    +   }
    +@@ -823,7 +823,7 @@ static int decode_map(codebook *s, oggpack_buffer *b, ogg_int32_t *v, int point)
    + 
    +     if(s->q_seq)
    +       for(i=1;i<s->dim;i++)
    +-	v[i]+=v[i-1];
    ++        v[i]+=v[i-1];
    +   }
    + 
    +   return 0;
    +@@ -832,7 +832,7 @@ static int decode_map(codebook *s, oggpack_buffer *b, ogg_int32_t *v, int point)
    + 
    + /* returns 0 on OK or -1 on eof *************************************/
    + long vorbis_book_decodevs_add(codebook *book,ogg_int32_t *a,
    +-			      oggpack_buffer *b,int n,int point){
    ++                              oggpack_buffer *b,int n,int point){
    +   if(book->used_entries>0){
    +     int step=n/book->dim;
    +     ogg_int32_t *v = book->dec_buf;//(ogg_int32_t *)alloca(sizeof(*v)*book->dim);
    +@@ -842,14 +842,14 @@ long vorbis_book_decodevs_add(codebook *book,ogg_int32_t *a,
    +     for (j=0;j<step;j++){
    +       if(decode_map(book,b,v,point))return -1;
    +       for(i=0,o=j;i<book->dim;i++,o+=step)
    +-	a[o]+=v[i];
    ++        a[o]+=v[i];
    +     }
    +   }
    +   return 0;
    + }
    + 
    + long vorbis_book_decodev_add(codebook *book,ogg_int32_t *a,
    +-			     oggpack_buffer *b,int n,int point){
    ++                             oggpack_buffer *b,int n,int point){
    +   if(book->used_entries>0){
    +     ogg_int32_t *v = book->dec_buf;//(ogg_int32_t *)alloca(sizeof(*v)*book->dim);
    +     int i,j;
    +@@ -857,15 +857,15 @@ long vorbis_book_decodev_add(codebook *book,ogg_int32_t *a,
    +     if (!v) return -1;
    +     for(i=0;i<n;){
    +       if(decode_map(book,b,v,point))return -1;
    +-      for (j=0;j<book->dim;j++)
    +-	a[i++]+=v[j];
    ++      for (j=0;j<book->dim && i < n;j++)
    ++        a[i++]+=v[j];
    +     }
    +   }
    +   return 0;
    + }
    + 
    + long vorbis_book_decodev_set(codebook *book,ogg_int32_t *a,
    +-			     oggpack_buffer *b,int n,int point){
    ++                             oggpack_buffer *b,int n,int point){
    +   if(book->used_entries>0){
    +     ogg_int32_t *v = book->dec_buf;//(ogg_int32_t *)alloca(sizeof(*v)*book->dim);
    +     int i,j;
    +@@ -873,15 +873,15 @@ long vorbis_book_decodev_set(codebook *book,ogg_int32_t *a,
    +     if (!v) return -1;
    +     for(i=0;i<n;){
    +       if(decode_map(book,b,v,point))return -1;
    +-      for (j=0;j<book->dim;j++)
    +-	a[i++]=v[j];
    ++      for (j=0;j<book->dim && i < n;j++)
    ++        a[i++]=v[j];
    +     }
    +   }else{
    +     int i,j;
    + 
    +     for(i=0;i<n;){
    +-      for (j=0;j<book->dim;j++)
    +-	a[i++]=0;
    ++      for (j=0;j<book->dim && i < n;j++)
    ++        a[i++]=0;
    +     }
    +   }
    + 
    +@@ -890,12 +890,12 @@ long vorbis_book_decodev_set(codebook *book,ogg_int32_t *a,
    + 
    + #ifndef ONLY_C
    + long vorbis_book_decodevv_add(codebook *book,ogg_int32_t **a,
    +-			      long offset,int ch,
    +-			      oggpack_buffer *b,int n,int point);
    ++                              long offset,int ch,
    ++                              oggpack_buffer *b,int n,int point);
    + #else
    + long vorbis_book_decodevv_add(codebook *book,ogg_int32_t **a,
    +-			      long offset,int ch,
    +-			      oggpack_buffer *b,int n,int point){
    ++                              long offset,int ch,
    ++                              oggpack_buffer *b,int n,int point){
    +   if(book->used_entries>0){
    + 
    +     ogg_int32_t *v = book->dec_buf;//(ogg_int32_t *)alloca(sizeof(*v)*book->dim);
    +@@ -905,12 +905,12 @@ long vorbis_book_decodevv_add(codebook *book,ogg_int32_t **a,
    +     if (!v) return -1;
    +     for(i=offset;i<offset+n;){
    +       if(decode_map(book,b,v,point))return -1;
    +-      for (j=0;j<book->dim;j++){
    +-	a[chptr++][i]+=v[j];
    +-	if(chptr==ch){
    +-	  chptr=0;
    +-	  i++;
    +-	}
    ++      for (j=0;j<book->dim && i < offset + n;j++){
    ++        a[chptr++][i]+=v[j];
    ++        if(chptr==ch){
    ++          chptr=0;
    ++          i++;
    ++        }
    +       }
    +     }
    +   }
    +diff --git a/Tremolo/dpen.s b/Tremolo/dpen.s
    +index 7e4f1ed..344e41b 100644
    +--- a/Tremolo/dpen.s
    ++++ b/Tremolo/dpen.s
    +@@ -430,6 +430,8 @@ vbdvva_loop1:
    + 	LDR	r0, [r9, # 5*4]		@ r0 = book->dim
    + 	LDR	r1, [r9, #14*4]		@ r1 = v = dec_buf
    + vbdvva_loop2:
    ++	CMP	r5,#0
    ++	BLE	vbdvva_exit
    + 	LDR	r2, [r10],#4		@ r2 = a[chptr++]
    + 	LDR	r12,[r1], #4		@ r1 = v[j++]
    + 	CMP	r10,r8			@ if (chptr == ch)
     diff --git a/Tremolo/res012.c b/Tremolo/res012.c
    -index 513d9ad..d6495fb 100644
    +index 513d9ad..ac09671 100644
     --- a/Tremolo/res012.c
     +++ b/Tremolo/res012.c
    -@@ -126,10 +126,13 @@ int res_inverse(vorbis_dsp_state *vd,vorbis_info_residue *info,
    +@@ -65,9 +65,9 @@ int res_unpack(vorbis_info_residue *info,
    +   if(info->type>2 || info->type<0)goto errout;
    +   info->begin=oggpack_read(opb,24);
    +   info->end=oggpack_read(opb,24);
    +-  info->grouping=oggpack_read(opb,24)+1;
    +-  info->partitions=(char)(oggpack_read(opb,6)+1);
    +-  info->groupbook=(unsigned char)oggpack_read(opb,8);
    ++  info->grouping=oggpack_read(opb,24)+1;              // "partition size" in spec
    ++  info->partitions=(char)(oggpack_read(opb,6)+1);     // "classification" in spec
    ++  info->groupbook=(unsigned char)oggpack_read(opb,8); // "classbook" in spec
    +   if(info->groupbook>=ci->books)goto errout;
    + 
    +   info->stagemasks=_ogg_malloc(info->partitions*sizeof(*info->stagemasks));
    +@@ -94,6 +94,15 @@ int res_unpack(vorbis_info_residue *info,
    + 
    +   if(oggpack_eop(opb))goto errout;
    + 
    ++  // According to the Vorbis spec (paragraph 8.6.2 "packet decode"), residue
    ++  // begin and end should be limited to the maximum possible vector size in
    ++  // case they exceed it. However doing that makes the decoder crash further
    ++  // down, so we return an error instead.
    ++  int limit = (info->type == 2 ? vi->channels : 1) * ci->blocksizes[1] / 2;
    ++  if (info->begin > info->end ||
    ++          info->end > limit) {
    ++      goto errout;
    ++  }
    +   return 0;
    +  errout:
    +   res_clear_info(info);
    +@@ -126,10 +135,13 @@ int res_inverse(vorbis_dsp_state *vd,vorbis_info_residue *info,
      
            if(used){
      
    @@ -20,7 +757,7 @@ index 513d9ad..d6495fb 100644
      
              for(s=0;s<info->stages;s++){
      
    -@@ -147,7 +150,7 @@ int res_inverse(vorbis_dsp_state *vd,vorbis_info_residue *info,
    +@@ -147,7 +159,7 @@ int res_inverse(vorbis_dsp_state *vd,vorbis_info_residue *info,
      
                    for(j=0;j<ch;j++){
                      int temp=vorbis_book_decode(phrasebook,&vd->opb);
    @@ -29,7 +766,7 @@ index 513d9ad..d6495fb 100644
      
                      /* this can be done quickly in assembly due to the quotient
                         always being at most six bits */
    -@@ -171,16 +174,23 @@ int res_inverse(vorbis_dsp_state *vd,vorbis_info_residue *info,
    +@@ -171,16 +183,23 @@ int res_inverse(vorbis_dsp_state *vd,vorbis_info_residue *info,
                        if(info->type){
                          if(vorbis_book_decodev_add(stagebook,in[j]+offset,&vd->opb,
                                                     samples_per_partition,-8)==-1)
    @@ -55,7 +792,7 @@ index 513d9ad..d6495fb 100644
            }
          }
        }else{
    -@@ -193,11 +203,12 @@ int res_inverse(vorbis_dsp_state *vd,vorbis_info_residue *info,
    +@@ -193,11 +212,12 @@ int res_inverse(vorbis_dsp_state *vd,vorbis_info_residue *info,
            int partwords=(partvals+partitions_per_word-1)/partitions_per_word;
      
            char *partword=
    @@ -70,7 +807,7 @@ index 513d9ad..d6495fb 100644
      
            samples_per_partition/=ch;
      
    -@@ -212,7 +223,7 @@ int res_inverse(vorbis_dsp_state *vd,vorbis_info_residue *info,
    +@@ -212,7 +232,7 @@ int res_inverse(vorbis_dsp_state *vd,vorbis_info_residue *info,
      
                  /* fetch the partition word */
                  temp=vorbis_book_decode(phrasebook,&vd->opb);
    @@ -79,7 +816,7 @@ index 513d9ad..d6495fb 100644
      
                  /* this can be done quickly in assembly due to the quotient
                     always being at most six bits */
    -@@ -233,14 +244,15 @@ int res_inverse(vorbis_dsp_state *vd,vorbis_info_residue *info,
    +@@ -233,14 +253,15 @@ int res_inverse(vorbis_dsp_state *vd,vorbis_info_residue *info,
                                    i*samples_per_partition+beginoff,ch,
                                    &vd->opb,
                                    samples_per_partition,-8)==-1)
    diff --git a/frameworks_av.patch b/frameworks_av.patch
    index 22966f3..3f21777 100644
    --- a/frameworks_av.patch
    +++ b/frameworks_av.patch
    @@ -102,6 +102,21 @@ index 3051406..870bb9b 100644
      
          size_t buffers() const { return mBuffers.size(); }
      
    +diff --git a/media/libeffects/downmix/EffectDownmix.c b/media/libeffects/downmix/EffectDownmix.c
    +index 9823c55..cb4be75 100644
    +--- a/media/libeffects/downmix/EffectDownmix.c
    ++++ b/media/libeffects/downmix/EffectDownmix.c
    +@@ -445,6 +445,10 @@ static int Downmix_Command(effect_handle_t self, uint32_t cmdCode, uint32_t cmdS
    +             return -EINVAL;
    +         }
    +         effect_param_t *cmd = (effect_param_t *) pCmdData;
    ++        if (cmd->psize != sizeof(int32_t)) {
    ++            android_errorWriteLog(0x534e4554, "63662938");
    ++            return -EINVAL;
    ++        }
    +         *(int *)pReplyData = Downmix_setParameter(pDownmixer, *(int32_t *)cmd->data,
    +                 cmd->vsize, cmd->data + sizeof(int32_t));
    +         break;
     diff --git a/media/libeffects/lvm/wrapper/Bundle/EffectBundle.cpp b/media/libeffects/lvm/wrapper/Bundle/EffectBundle.cpp
     index dcf3fa0..07ea818 100644
     --- a/media/libeffects/lvm/wrapper/Bundle/EffectBundle.cpp
    @@ -120,6 +135,94 @@ index dcf3fa0..07ea818 100644
              name = (char *)pValue;
              strncpy(name, EqualizerGetPresetName(param2), *pValueSize - 1);
              name[*pValueSize - 1] = 0;
    +diff --git a/media/libeffects/lvm/wrapper/Reverb/EffectReverb.cpp b/media/libeffects/lvm/wrapper/Reverb/EffectReverb.cpp
    +index 4dc8b45..19892dd 100644
    +--- a/media/libeffects/lvm/wrapper/Reverb/EffectReverb.cpp
    ++++ b/media/libeffects/lvm/wrapper/Reverb/EffectReverb.cpp
    +@@ -180,12 +180,13 @@ int  Reverb_init            (ReverbContext *pContext);
    + void Reverb_free            (ReverbContext *pContext);
    + int  Reverb_setConfig       (ReverbContext *pContext, effect_config_t *pConfig);
    + void Reverb_getConfig       (ReverbContext *pContext, effect_config_t *pConfig);
    +-int  Reverb_setParameter    (ReverbContext *pContext, void *pParam, void *pValue);
    ++int  Reverb_setParameter    (ReverbContext *pContext, void *pParam, void *pValue, int vsize);
    + int  Reverb_getParameter    (ReverbContext *pContext,
    +                              void          *pParam,
    +                              uint32_t      *pValueSize,
    +                              void          *pValue);
    + int Reverb_LoadPreset       (ReverbContext   *pContext);
    ++int Reverb_paramValueSize   (int32_t param);
    + 
    + /* Effect Library Interface Implementation */
    + 
    +@@ -1747,12 +1748,13 @@ int Reverb_getParameter(ReverbContext *pContext,
    + //  pContext         - handle to instance data
    + //  pParam           - pointer to parameter
    + //  pValue           - pointer to value
    ++//  vsize            - value size
    + //
    + // Outputs:
    + //
    + //----------------------------------------------------------------------------
    + 
    +-int Reverb_setParameter (ReverbContext *pContext, void *pParam, void *pValue){
    ++int Reverb_setParameter (ReverbContext *pContext, void *pParam, void *pValue, int vsize){
    +     int status = 0;
    +     int16_t level;
    +     int16_t ratio;
    +@@ -1776,6 +1778,11 @@ int Reverb_setParameter (ReverbContext *pContext, void *pParam, void *pValue){
    +         return 0;
    +     }
    + 
    ++    if (vsize < Reverb_paramValueSize(param)) {
    ++        android_errorWriteLog(0x534e4554, "63526567");
    ++        return -EINVAL;
    ++    }
    ++
    +     switch (param){
    +         case REVERB_PARAM_PROPERTIES:
    +             ALOGV("\tReverb_setParameter() REVERB_PARAM_PROPERTIES");
    +@@ -1851,6 +1858,31 @@ int Reverb_setParameter (ReverbContext *pContext, void *pParam, void *pValue){
    +     return status;
    + } /* end Reverb_setParameter */
    + 
    ++
    ++/**
    ++ * returns the size in bytes of the value of each environmental reverb parameter
    ++ */
    ++int Reverb_paramValueSize(int32_t param) {
    ++    switch (param) {
    ++    case REVERB_PARAM_ROOM_LEVEL:
    ++    case REVERB_PARAM_ROOM_HF_LEVEL:
    ++    case REVERB_PARAM_REFLECTIONS_LEVEL:
    ++    case REVERB_PARAM_REVERB_LEVEL:
    ++        return sizeof(int16_t); // millibel
    ++    case REVERB_PARAM_DECAY_TIME:
    ++    case REVERB_PARAM_REFLECTIONS_DELAY:
    ++    case REVERB_PARAM_REVERB_DELAY:
    ++        return sizeof(uint32_t); // milliseconds
    ++    case REVERB_PARAM_DECAY_HF_RATIO:
    ++    case REVERB_PARAM_DIFFUSION:
    ++    case REVERB_PARAM_DENSITY:
    ++        return sizeof(int16_t); // permille
    ++    case REVERB_PARAM_PROPERTIES:
    ++        return sizeof(s_reverb_settings); // struct of all reverb properties
    ++    }
    ++    return sizeof(int32_t);
    ++}
    ++
    + } // namespace
    + } // namespace
    + 
    +@@ -2022,7 +2054,8 @@ int Reverb_command(effect_handle_t  self,
    + 
    +             *(int *)pReplyData = android::Reverb_setParameter(pContext,
    +                                                              (void *)p->data,
    +-                                                              p->data + p->psize);
    ++                                                              p->data + p->psize,
    ++                                                              p->vsize);
    +         } break;
    + 
    +         case EFFECT_CMD_ENABLE:
     diff --git a/media/libmedia/IDataSource.cpp b/media/libmedia/IDataSource.cpp
     index 51c9938..5ad39fe 100644
     --- a/media/libmedia/IDataSource.cpp
    @@ -445,7 +548,7 @@ index 893da89..2152454 100644
          // buffer queue.
          switch (mVideoBufferMode) {
     diff --git a/media/libstagefright/MPEG4Extractor.cpp b/media/libstagefright/MPEG4Extractor.cpp
    -index 5441714..2cc43c1 100644
    +index 5441714..4a33e7a 100644
     --- a/media/libstagefright/MPEG4Extractor.cpp
     +++ b/media/libstagefright/MPEG4Extractor.cpp
     @@ -72,6 +72,7 @@ public:
    @@ -456,7 +559,46 @@ index 5441714..2cc43c1 100644
      
          virtual status_t start(MetaData *params = NULL);
          virtual status_t stop();
    -@@ -2148,7 +2149,10 @@ status_t MPEG4Extractor::parseChunk(off64_t *offset, int depth) {
    +@@ -935,6 +936,12 @@ status_t MPEG4Extractor::parseChunk(off64_t *offset, int depth) {
    +                 ALOGE("moov: depth %d", depth);
    +                 return ERROR_MALFORMED;
    +             }
    ++
    ++            if (chunk_type == FOURCC('m', 'o', 'o', 'v') && mInitCheck == OK) {
    ++                ALOGE("duplicate moov");
    ++                return ERROR_MALFORMED;
    ++            }
    ++
    +             if (chunk_type == FOURCC('m', 'o', 'o', 'f') && !mMoofFound) {
    +                 // store the offset of the first segment
    +                 mMoofFound = true;
    +@@ -1008,6 +1015,12 @@ status_t MPEG4Extractor::parseChunk(off64_t *offset, int depth) {
    +                 if (!mLastTrack->meta->findInt32(kKeyTrackID, &trackId)) {
    +                     mLastTrack->skipTrack = true;
    +                 }
    ++
    ++                status_t err = verifyTrack(mLastTrack);
    ++                if (err != OK) {
    ++                    mLastTrack->skipTrack = true;
    ++                }
    ++
    +                 if (mLastTrack->skipTrack) {
    +                     Track *cur = mFirstTrack;
    + 
    +@@ -1025,12 +1038,6 @@ status_t MPEG4Extractor::parseChunk(off64_t *offset, int depth) {
    + 
    +                     return OK;
    +                 }
    +-
    +-                status_t err = verifyTrack(mLastTrack);
    +-
    +-                if (err != OK) {
    +-                    return err;
    +-                }
    +             } else if (chunk_type == FOURCC('m', 'o', 'o', 'v')) {
    +                 mInitCheck = OK;
    + 
    +@@ -2148,7 +2155,10 @@ status_t MPEG4Extractor::parseChunk(off64_t *offset, int depth) {
                  *offset += chunk_size;
      
                  if (underQTMetaPath(mPath, 3)) {
    @@ -468,7 +610,7 @@ index 5441714..2cc43c1 100644
                  }
                  break;
              }
    -@@ -2307,7 +2311,10 @@ status_t MPEG4Extractor::parseChunk(off64_t *offset, int depth) {
    +@@ -2307,7 +2317,10 @@ status_t MPEG4Extractor::parseChunk(off64_t *offset, int depth) {
      
              case FOURCC('s', 'i', 'd', 'x'):
              {
    @@ -480,7 +622,7 @@ index 5441714..2cc43c1 100644
                  *offset += chunk_size;
                  return UNKNOWN_ERROR; // stop parsing after sidx
              }
    -@@ -2349,7 +2356,10 @@ status_t MPEG4Extractor::parseChunk(off64_t *offset, int depth) {
    +@@ -2349,7 +2362,10 @@ status_t MPEG4Extractor::parseChunk(off64_t *offset, int depth) {
                  // check if we're parsing 'ilst' for meta keys
                  // if so, treat type as a number (key-id).
                  if (underQTMetaPath(mPath, 3)) {
    @@ -492,7 +634,7 @@ index 5441714..2cc43c1 100644
                  }
      
                  *offset += chunk_size;
    -@@ -2984,6 +2994,13 @@ status_t MPEG4Extractor::parse3GPPMetaData(off64_t offset, size_t size, int dept
    +@@ -2984,6 +3000,13 @@ status_t MPEG4Extractor::parse3GPPMetaData(off64_t offset, size_t size, int dept
              }
              case FOURCC('y', 'r', 'r', 'c'):
              {
    @@ -506,7 +648,7 @@ index 5441714..2cc43c1 100644
                  char tmp[5];
                  uint16_t year = U16_AT(&buffer[4]);
      
    -@@ -3006,6 +3023,8 @@ status_t MPEG4Extractor::parse3GPPMetaData(off64_t offset, size_t size, int dept
    +@@ -3006,6 +3029,8 @@ status_t MPEG4Extractor::parse3GPPMetaData(off64_t offset, size_t size, int dept
      
              // smallest possible valid UTF-16 string w BOM: 0xfe 0xff 0x00 0x00
              if (size < 6) {
    @@ -515,7 +657,7 @@ index 5441714..2cc43c1 100644
                  return ERROR_MALFORMED;
              }
      
    -@@ -3174,9 +3193,13 @@ sp<IMediaSource> MPEG4Extractor::getTrack(size_t index) {
    +@@ -3174,9 +3199,13 @@ sp<IMediaSource> MPEG4Extractor::getTrack(size_t index) {
              }
          }
      
    @@ -530,7 +672,7 @@ index 5441714..2cc43c1 100644
      }
      
      // static
    -@@ -3573,6 +3596,7 @@ MPEG4Source::MPEG4Source(
    +@@ -3573,6 +3602,7 @@ MPEG4Source::MPEG4Source(
            mTrex(trex),
            mFirstMoofOffset(firstMoofOffset),
            mCurrentMoofOffset(firstMoofOffset),
    @@ -538,7 +680,7 @@ index 5441714..2cc43c1 100644
            mCurrentTime(0),
            mCurrentSampleInfoAllocSize(0),
            mCurrentSampleInfoSizes(NULL),
    -@@ -3637,10 +3661,14 @@ MPEG4Source::MPEG4Source(
    +@@ -3637,10 +3667,14 @@ MPEG4Source::MPEG4Source(
      
          CHECK(format->findInt32(kKeyTrackID, &mTrackId));
      
    @@ -554,7 +696,7 @@ index 5441714..2cc43c1 100644
      }
      
      MPEG4Source::~MPEG4Source() {
    -@@ -3767,13 +3795,35 @@ status_t MPEG4Source::parseChunk(off64_t *offset) {
    +@@ -3767,13 +3801,35 @@ status_t MPEG4Source::parseChunk(off64_t *offset) {
      
                      while (true) {
                          if (mDataSource->readAt(*offset, hdr, 8) < 8) {
    @@ -591,7 +733,7 @@ index 5441714..2cc43c1 100644
                          }
                          *offset += chunk_size;
                      }
    -@@ -4651,17 +4701,25 @@ status_t MPEG4Source::fragmentedRead(
    +@@ -4651,17 +4707,25 @@ status_t MPEG4Source::fragmentedRead(
                      totalOffset += se->mSize;
                  }
                  mCurrentMoofOffset = totalOffset;
    @@ -619,7 +761,7 @@ index 5441714..2cc43c1 100644
                  mCurrentTime = 0;
              }
      
    -@@ -4690,7 +4748,10 @@ status_t MPEG4Source::fragmentedRead(
    +@@ -4690,7 +4754,10 @@ status_t MPEG4Source::fragmentedRead(
                  mCurrentMoofOffset = nextMoof;
                  mCurrentSamples.clear();
                  mCurrentSampleIndex = 0;
    @@ -661,8 +803,23 @@ index a17757a..f1ad5c5 100644
     +}
     +}
      }  // namespace android
    +diff --git a/media/libstagefright/OggExtractor.cpp b/media/libstagefright/OggExtractor.cpp
    +index ebbe510..752f2fe 100644
    +--- a/media/libstagefright/OggExtractor.cpp
    ++++ b/media/libstagefright/OggExtractor.cpp
    +@@ -578,6 +578,10 @@ status_t MyOpusExtractor::readNextPacket(MediaBuffer **out) {
    +             }
    +             // First two pages are header pages.
    +             if (err == ERROR_END_OF_STREAM || mCurrentPage.mPageNo > 2) {
    ++                if (mBuf != NULL) {
    ++                    mBuf->release();
    ++                    mBuf = NULL;
    ++                }
    +                 break;
    +             }
    +             curGranulePosition = mCurrentPage.mGranulePosition;
     diff --git a/media/libstagefright/SampleTable.cpp b/media/libstagefright/SampleTable.cpp
    -index ee5fdf0..fb5305d 100644
    +index ee5fdf0..597896b 100644
     --- a/media/libstagefright/SampleTable.cpp
     +++ b/media/libstagefright/SampleTable.cpp
     @@ -517,6 +517,8 @@ status_t SampleTable::setSyncSampleParams(off64_t data_offset, size_t data_size)
    @@ -674,6 +831,20 @@ index ee5fdf0..fb5305d 100644
          uint8_t header[8];
          if (mDataSource->readAt(
                      data_offset, header, sizeof(header)) < (ssize_t)sizeof(header)) {
    +@@ -561,7 +563,7 @@ status_t SampleTable::setSyncSampleParams(off64_t data_offset, size_t data_size)
    + 
    +     if (mDataSource->readAt(data_offset + 8, mSyncSamples,
    +             (size_t)allocSize) != (ssize_t)allocSize) {
    +-        delete mSyncSamples;
    ++        delete[] mSyncSamples;
    +         mSyncSamples = NULL;
    +         return ERROR_IO;
    +     }
    +@@ -987,4 +989,3 @@ int32_t SampleTable::getCompositionTimeOffset(uint32_t sampleIndex) {
    + }
    + 
    + }  // namespace android
    +-
     diff --git a/media/libstagefright/StagefrightMetadataRetriever.cpp b/media/libstagefright/StagefrightMetadataRetriever.cpp
     index be5067d..2fef7ca 100644
     --- a/media/libstagefright/StagefrightMetadataRetriever.cpp
    @@ -1016,6 +1187,20 @@ index 8e4d064..66992d7 100644
      void MediaBufferGroup::signalBufferReturned(MediaBuffer *) {
          mCondition.signal();
      }
    +diff --git a/media/libstagefright/foundation/base64.cpp b/media/libstagefright/foundation/base64.cpp
    +index 7da7db9..cc89064 100644
    +--- a/media/libstagefright/foundation/base64.cpp
    ++++ b/media/libstagefright/foundation/base64.cpp
    +@@ -78,8 +78,7 @@ sp<ABuffer> decodeBase64(const AString &s) {
    +         accum = (accum << 6) | value;
    + 
    +         if (((i + 1) % 4) == 0) {
    +-            out[j++] = (accum >> 16);
    +-
    ++            if (j < outLen) { out[j++] = (accum >> 16); }
    +             if (j < outLen) { out[j++] = (accum >> 8) & 0xff; }
    +             if (j < outLen) { out[j++] = accum & 0xff; }
    + 
     diff --git a/media/libstagefright/httplive/LiveSession.cpp b/media/libstagefright/httplive/LiveSession.cpp
     index 7abc019..590146d 100644
     --- a/media/libstagefright/httplive/LiveSession.cpp
    @@ -1149,6 +1334,33 @@ index e7aaead..8752b4e 100644
              header->nOffset = 0;
          } else {
              // rangeLength and rangeOffset must be a subset of the allocated data in the buffer.
    +diff --git a/media/libstagefright/omx/SimpleSoftOMXComponent.cpp b/media/libstagefright/omx/SimpleSoftOMXComponent.cpp
    +index 7c975f7..76cbbc4 100644
    +--- a/media/libstagefright/omx/SimpleSoftOMXComponent.cpp
    ++++ b/media/libstagefright/omx/SimpleSoftOMXComponent.cpp
    +@@ -199,6 +199,13 @@ OMX_ERRORTYPE SimpleSoftOMXComponent::useBuffer(
    +     Mutex::Autolock autoLock(mLock);
    +     CHECK_LT(portIndex, mPorts.size());
    + 
    ++    PortInfo *port = &mPorts.editItemAt(portIndex);
    ++    if (size < port->mDef.nBufferSize) {
    ++        ALOGE("b/63522430, Buffer size is too small.");
    ++        android_errorWriteLog(0x534e4554, "63522430");
    ++        return OMX_ErrorBadParameter;
    ++    }
    ++
    +     *header = new OMX_BUFFERHEADERTYPE;
    +     (*header)->nSize = sizeof(OMX_BUFFERHEADERTYPE);
    +     (*header)->nVersion.s.nVersionMajor = 1;
    +@@ -221,8 +228,6 @@ OMX_ERRORTYPE SimpleSoftOMXComponent::useBuffer(
    +     (*header)->nOutputPortIndex = portIndex;
    +     (*header)->nInputPortIndex = portIndex;
    + 
    +-    PortInfo *port = &mPorts.editItemAt(portIndex);
    +-
    +     CHECK(mState == OMX_StateLoaded || port->mDef.bEnabled == OMX_FALSE);
    + 
    +     CHECK_LT(port->mBuffers.size(), port->mDef.nBufferCountActual);
     diff --git a/media/mediaserver/Android.mk b/media/mediaserver/Android.mk
     index 1738df8..c2b9c1f 100644
     --- a/media/mediaserver/Android.mk
    diff --git a/frameworks_base.patch b/frameworks_base.patch
    index 2c72791..6cf4474 100644
    --- a/frameworks_base.patch
    +++ b/frameworks_base.patch
    @@ -145,6 +145,19 @@ index a8209af..4766d33 100755
               * I am the lolrus.
               * <p>
               * Nonzero values indicate that the user has a bukkit.
    +diff --git a/core/java/android/service/gatekeeper/GateKeeperResponse.java b/core/java/android/service/gatekeeper/GateKeeperResponse.java
    +index a512957..6ca6d8a 100644
    +--- a/core/java/android/service/gatekeeper/GateKeeperResponse.java
    ++++ b/core/java/android/service/gatekeeper/GateKeeperResponse.java
    +@@ -85,6 +85,8 @@ public final class GateKeeperResponse implements Parcelable {
    +             if (mPayload != null) {
    +                 dest.writeInt(mPayload.length);
    +                 dest.writeByteArray(mPayload);
    ++            } else {
    ++                dest.writeInt(0);
    +             }
    +         }
    +     }
     diff --git a/core/java/android/view/WindowManager.java b/core/java/android/view/WindowManager.java
     index 395f738..169f7e1 100644
     --- a/core/java/android/view/WindowManager.java
    @@ -422,6 +435,34 @@ index dd80750..005206f 100644
     +                }
     +            }
     +        }
    ++    }
    + }
    +diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
    +index 9d22b4a..7639b3d 100644
    +--- a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
    ++++ b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
    +@@ -2679,4 +2679,23 @@ public abstract class BaseStatusBar extends SystemUI implements
    +             mAssistManager.startAssist(args);
    +         }
    +     }
    ++
    ++    public boolean isCameraAllowedByAdmin() {
    ++       if (mDevicePolicyManager.getCameraDisabled(null, mCurrentUserId)) {
    ++           return false;
    ++       } else if (isKeyguardShowing() && isKeyguardSecure()) {
    ++           // Check if the admin has disabled the camera specifically for the keyguard
    ++           return (mDevicePolicyManager.getKeyguardDisabledFeatures(null, mCurrentUserId)
    ++                   & DevicePolicyManager.KEYGUARD_DISABLE_SECURE_CAMERA) == 0;
    ++       }
    ++       return true;
    ++    }
    ++
    ++    public boolean isKeyguardShowing() {
    ++        if (mStatusBarKeyguardViewManager == null) {
    ++            Slog.i(TAG, "isKeyguardShowing() called before startKeyguard(), returning true");
    ++            return true;
    ++        }
    ++        return mStatusBarKeyguardViewManager.isShowing();
     +    }
      }
     diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationGuts.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationGuts.java
    @@ -437,6 +478,70 @@ index 63d2891..1829e59 100644
                  if (mSeekBar.isEnabled()) {
                      return mSeekBar.getProgress();
                  } else {
    +diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java
    +index 4d0e5d3..c674a82 100644
    +--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java
    ++++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java
    +@@ -305,7 +305,10 @@ public class KeyguardBottomAreaView extends FrameLayout implements View.OnClickL
    +             return;
    +         }
    +         ResolveInfo resolved = resolveCameraIntent();
    +-        boolean visible = !isCameraDisabledByDpm() && resolved != null
    ++        boolean isCameraDisabled =
    ++                (mPhoneStatusBar != null) && !mPhoneStatusBar.isCameraAllowedByAdmin();
    ++        boolean visible = !isCameraDisabled
    ++                && resolved != null
    +                 && getResources().getBoolean(R.bool.config_keyguardShowCameraAffordance)
    +                 && mUserSetupComplete;
    +         mCameraImageView.setVisibility(visible ? View.VISIBLE : View.GONE);
    +@@ -339,24 +342,6 @@ public class KeyguardBottomAreaView extends FrameLayout implements View.OnClickL
    +                 && pm.resolveActivity(PHONE_INTENT, 0) != null;
    +     }
    + 
    +-    private boolean isCameraDisabledByDpm() {
    +-        final DevicePolicyManager dpm =
    +-                (DevicePolicyManager) getContext().getSystemService(Context.DEVICE_POLICY_SERVICE);
    +-        if (dpm != null && mPhoneStatusBar != null) {
    +-            try {
    +-                final int userId = ActivityManagerNative.getDefault().getCurrentUser().id;
    +-                final int disabledFlags = dpm.getKeyguardDisabledFeatures(null, userId);
    +-                final  boolean disabledBecauseKeyguardSecure =
    +-                        (disabledFlags & DevicePolicyManager.KEYGUARD_DISABLE_SECURE_CAMERA) != 0
    +-                                && mPhoneStatusBar.isKeyguardSecure();
    +-                return dpm.getCameraDisabled(null) || disabledBecauseKeyguardSecure;
    +-            } catch (RemoteException e) {
    +-                Log.e(TAG, "Can't get userId", e);
    +-            }
    +-        }
    +-        return false;
    +-    }
    +-
    +     private void watchForCameraPolicyChanges() {
    +         final IntentFilter filter = new IntentFilter();
    +         filter.addAction(DevicePolicyManager.ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED);
    +diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
    +index 9c700b4..ca08ab1 100644
    +--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
    ++++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
    +@@ -31,6 +31,7 @@ import android.graphics.Paint;
    + import android.graphics.Rect;
    + import android.util.AttributeSet;
    + import android.util.MathUtils;
    ++import android.util.EventLog;
    + import android.view.MotionEvent;
    + import android.view.VelocityTracker;
    + import android.view.View;
    +@@ -2330,6 +2331,10 @@ public class NotificationPanelView extends PanelView implements
    +      * @param keyguardIsShowing whether keyguard is being shown
    +      */
    +     public boolean canCameraGestureBeLaunched(boolean keyguardIsShowing) {
    ++        if (!mStatusBar.isCameraAllowedByAdmin()) {
    ++            EventLog.writeEvent(0x534e4554, "63787722", -1, "");
    ++            return false;
    ++        }
    +         ResolveInfo resolveInfo = mKeyguardBottomArea.resolveCameraIntent();
    +         String packageToLaunch = (resolveInfo == null || resolveInfo.activityInfo == null)
    +                 ? null : resolveInfo.activityInfo.packageName;
     diff --git a/packages/SystemUI/src/com/android/systemui/tuner/TunerFragment.java b/packages/SystemUI/src/com/android/systemui/tuner/TunerFragment.java
     index 70f2fdc..ba50161 100644
     --- a/packages/SystemUI/src/com/android/systemui/tuner/TunerFragment.java
    diff --git a/hardware_broadcom_wlan.patch b/hardware_broadcom_wlan.patch
    index e69de29..d9fce91 100644
    --- a/hardware_broadcom_wlan.patch
    +++ b/hardware_broadcom_wlan.patch
    @@ -0,0 +1,63 @@
    +diff --git a/bcmdhd/wifi_hal/gscan.cpp b/bcmdhd/wifi_hal/gscan.cpp
    +index 07155e2..73bfe8c 100644
    +--- a/bcmdhd/wifi_hal/gscan.cpp
    ++++ b/bcmdhd/wifi_hal/gscan.cpp
    +@@ -1436,30 +1436,38 @@ public:
    +         if (result < 0) {
    +             return result;
    +         }
    +-
    +-        struct nlattr * attr = request.attr_start(GSCAN_ATTRIBUTE_SIGNIFICANT_CHANGE_BSSIDS);
    +-
    +-        for (int i = 0; i < mParams.num_bssid; i++) {
    +-            nlattr *attr2 = request.attr_start(i);
    +-            if (attr2 == NULL) {
    ++        result = request.put_u16(GSCAN_ATTRIBUTE_NUM_BSSID, mParams.num_bssid);
    ++        if (result < 0) {
    ++            return result;
    ++        }
    ++        if (mParams.num_bssid != 0) {
    ++            nlattr* attr = request.attr_start(GSCAN_ATTRIBUTE_SIGNIFICANT_CHANGE_BSSIDS);
    ++            if (attr == NULL) {
    +                 return WIFI_ERROR_OUT_OF_MEMORY;
    +             }
    +-            result = request.put_addr(GSCAN_ATTRIBUTE_BSSID, mParams.ap[i].bssid);
    +-            if (result < 0) {
    +-                return result;
    +-            }
    +-            result = request.put_u8(GSCAN_ATTRIBUTE_RSSI_HIGH, mParams.ap[i].high);
    +-            if (result < 0) {
    +-                return result;
    +-            }
    +-            result = request.put_u8(GSCAN_ATTRIBUTE_RSSI_LOW, mParams.ap[i].low);
    +-            if (result < 0) {
    +-                return result;
    ++
    ++            for (int i = 0; i < mParams.num_bssid; i++) {
    ++                nlattr* attr2 = request.attr_start(i);
    ++                if (attr2 == NULL) {
    ++                    return WIFI_ERROR_OUT_OF_MEMORY;
    ++                }
    ++                result = request.put_addr(GSCAN_ATTRIBUTE_BSSID, mParams.ap[i].bssid);
    ++                if (result < 0) {
    ++                    return result;
    ++                }
    ++                result = request.put_u8(GSCAN_ATTRIBUTE_RSSI_HIGH, mParams.ap[i].high);
    ++                if (result < 0) {
    ++                    return result;
    ++                }
    ++                result = request.put_u8(GSCAN_ATTRIBUTE_RSSI_LOW, mParams.ap[i].low);
    ++                if (result < 0) {
    ++                    return result;
    ++                }
    ++                request.attr_end(attr2);
    +             }
    +-            request.attr_end(attr2);
    +-        }
    + 
    +-        request.attr_end(attr);
    ++            request.attr_end(attr);
    ++        }
    +         request.attr_end(data);
    + 
    +         return result;
    diff --git a/hardware_ril.patch b/hardware_ril.patch
    index 149fa0b..0e0143f 100644
    --- a/hardware_ril.patch
    +++ b/hardware_ril.patch
    @@ -1,5 +1,5 @@
     diff --git a/libril/ril.cpp b/libril/ril.cpp
    -index d7744c0..3f78619 100644
    +index d7744c0..bba8e0c 100644
     --- a/libril/ril.cpp
     +++ b/libril/ril.cpp
     @@ -3698,6 +3698,7 @@ static int responseSSData(Parcel &p, void *response, size_t responselen) {
    @@ -18,6 +18,46 @@ index d7744c0..3f78619 100644
      
          sendSimStatusAppInfo(p, p_cur->num_applications, p_cur->applications);
      }
    +@@ -4419,12 +4421,12 @@ static void debugCallback (int fd, short flags, void *param) {
    +     int data;
    +     unsigned int qxdm_data[6];
    +     const char *deactData[1] = {"1"};
    +-    char *actData[1];
    +     RIL_Dial dialData;
    +     int hangupData[1] = {1};
    +     int number;
    +     char **args;
    +     RIL_SOCKET_ID socket_id = RIL_SOCKET_1;
    ++    int MAX_DIAL_ADDRESS = 128;
    +     int sim_id = 0;
    + 
    +     RLOGI("debugCallback for socket %s", rilSocketIdToString(socket_id));
    +@@ -4571,12 +4573,6 @@ static void debugCallback (int fd, short flags, void *param) {
    +             // Set network selection automatic.
    +             issueLocalRequest(RIL_REQUEST_SET_NETWORK_SELECTION_AUTOMATIC, NULL, 0, socket_id);
    +             break;
    +-        case 6:
    +-            RLOGI("Debug port: Setup Data Call, Apn :%s\n", args[1]);
    +-            actData[0] = args[1];
    +-            issueLocalRequest(RIL_REQUEST_SETUP_DATA_CALL, &actData,
    +-                              sizeof(actData), socket_id);
    +-            break;
    +         case 7:
    +             RLOGI("Debug port: Deactivate Data Call");
    +             issueLocalRequest(RIL_REQUEST_DEACTIVATE_DATA_CALL, &deactData,
    +@@ -4585,6 +4581,12 @@ static void debugCallback (int fd, short flags, void *param) {
    +         case 8:
    +             RLOGI("Debug port: Dial Call");
    +             dialData.clir = 0;
    ++            if (strlen(args[1]) > MAX_DIAL_ADDRESS) {
    ++                RLOGE("Debug port: Error calling Dial");
    ++                freeDebugCallbackArgs(number, args);
    ++                close(acceptFD);
    ++                return;
    ++            }
    +             dialData.address = args[1];
    +             issueLocalRequest(RIL_REQUEST_DIAL, &dialData, sizeof(dialData), socket_id);
    +             break;
     @@ -5401,6 +5403,9 @@ void RIL_onUnsolicitedResponse(int unsolResponse, const void *data,
                  p.writeInt32(newState);
                  appendPrintBuf("%s {%s}", printBuf,
    diff --git a/libcore.patch b/libcore.patch
    new file mode 100644
    index 0000000..a931e19
    --- /dev/null
    +++ b/libcore.patch
    @@ -0,0 +1,66 @@
    +diff --git a/libart/src/main/java/java/lang/AndroidHardcodedSystemProperties.java b/libart/src/main/java/java/lang/AndroidHardcodedSystemProperties.java
    +index 13e9317..7e79e28 100644
    +--- a/libart/src/main/java/java/lang/AndroidHardcodedSystemProperties.java
    ++++ b/libart/src/main/java/java/lang/AndroidHardcodedSystemProperties.java
    +@@ -87,7 +87,7 @@ public final class AndroidHardcodedSystemProperties {
    +         // Hardcode MessagePattern apostrophe mode to be default. b/27265238
    +         { "android.icu.text.MessagePattern.ApostropheMode", null },
    + 
    +-        // Hardcode "sun.io.useCanonCaches" to use the default (on). b/28174137
    ++        // Hardcode "sun.io.useCanonCaches" to use the default (off). b/28174137, b/62301183
    +         { "sun.io.useCanonCaches", null },
    +         { "sun.io.useCanonPrefixCache", null },
    + 
    +@@ -108,4 +108,3 @@ public final class AndroidHardcodedSystemProperties {
    +         { "com.sun.security.preserveOldDCEncoding", null },
    +     };
    + }
    +-
    +diff --git a/luni/src/test/java/libcore/java/io/FileTest.java b/luni/src/test/java/libcore/java/io/FileTest.java
    +index 5d5317a..04de751 100644
    +--- a/luni/src/test/java/libcore/java/io/FileTest.java
    ++++ b/luni/src/test/java/libcore/java/io/FileTest.java
    +@@ -368,4 +368,25 @@ public class FileTest extends junit.framework.TestCase {
    +         assertEquals("/foo/bar", new File("/foo/", "/bar/").getPath());
    +         assertEquals("/foo/bar", new File("/foo", "/bar//").getPath());
    +     }
    ++
    ++    // http://b/62301183
    ++    public void test_canonicalCachesAreOff() throws Exception {
    ++        File tempDir = createTemporaryDirectory();
    ++        File f1 = new File(tempDir, "testCannonCachesOff1");
    ++        f1.createNewFile();
    ++        File f2  = new File(tempDir, "testCannonCachesOff2");
    ++        f2.createNewFile();
    ++        File symlinkFile = new File(tempDir, "symlink");
    ++
    ++        // Create a symlink from symlink to f1 and populate canonical path cache
    ++        assertEquals(0, Runtime.getRuntime().exec("ln -s " + f1.getAbsolutePath() + " " + symlinkFile.getAbsolutePath()).waitFor());
    ++        assertEquals(symlinkFile.getCanonicalPath(), f1.getCanonicalPath());
    ++
    ++        // Remove it and replace it with a symlink to f2 (using java File/Files would flush caches).
    ++        assertEquals(0, Runtime.getRuntime().exec("rm " + symlinkFile.getAbsolutePath()).waitFor());
    ++        assertEquals(0, Runtime.getRuntime().exec("ln -s " + f2.getAbsolutePath() + " " + symlinkFile.getAbsolutePath()).waitFor());
    ++
    ++        // Did we cache canonical path results? hope not!
    ++        assertEquals(symlinkFile.getCanonicalPath(), f2.getCanonicalPath());
    ++    }
    + }
    +diff --git a/ojluni/src/main/java/java/io/FileSystem.java b/ojluni/src/main/java/java/io/FileSystem.java
    +index aa00fa9..7db1651 100755
    +--- a/ojluni/src/main/java/java/io/FileSystem.java
    ++++ b/ojluni/src/main/java/java/io/FileSystem.java
    +@@ -232,8 +232,11 @@ abstract class FileSystem {
    + 
    +     // Flags for enabling/disabling performance optimizations for file
    +     // name canonicalization
    +-    static boolean useCanonCaches      = true;
    +-    static boolean useCanonPrefixCache = true;
    ++    // Android-changed: Disabled caches for security reasons (b/62301183)
    ++    //static boolean useCanonCaches      = true;
    ++    //static boolean useCanonPrefixCache = true;
    ++    static boolean useCanonCaches      = false;
    ++    static boolean useCanonPrefixCache = false;
    + 
    +     private static boolean getBooleanProperty(String prop, boolean defaultVal) {
    +         String val = System.getProperty(prop);
    diff --git a/system_sepolicy.patch b/system_sepolicy.patch
    index c5fcbd7..1d9a08e 100644
    --- a/system_sepolicy.patch
    +++ b/system_sepolicy.patch
    @@ -12,10 +12,18 @@ index e9dd7b3..ef2bd9d 100644
      
      # Block device access.
     diff --git a/domain.te b/domain.te
    -index 45569de..5aee09e 100644
    +index 45569de..21c9df2 100644
     --- a/domain.te
     +++ b/domain.te
    -@@ -267,6 +267,7 @@ neverallow { domain -init -ueventd } device:chr_file { open read write };
    +@@ -159,6 +159,7 @@ neverallow {
    +   -dumpstate
    +   -system_server
    +   userdebug_or_eng(`-perfprofd')
    ++  userdebug_or_eng(`-procrank')
    + } self:capability sys_ptrace;
    + 
    + # Limit device node creation to these whitelisted domains.
    +@@ -267,6 +268,7 @@ neverallow { domain -init -ueventd } device:chr_file { open read write };
      # this capability, including device-specific domains.
      neverallow { domain -kernel -init -recovery -vold -zygote -update_engine -otapreopt_chroot } { fs_type -sdcard_type }:filesystem { mount remount relabelfrom relabelto };
      
    @@ -23,7 +31,7 @@ index 45569de..5aee09e 100644
      #
      # Assert that, to the extent possible, we're not loading executable content from
      # outside the rootfs or /system partition except for a few whitelisted domains.
    -@@ -292,7 +293,9 @@ neverallow domain { cache_file cache_backup_file cache_private_backup_file cache
    +@@ -292,7 +294,9 @@ neverallow domain { cache_file cache_backup_file cache_private_backup_file cache
      # Protect most domains from executing arbitrary content from /data.
      neverallow {
        domain
    @@ -34,7 +42,7 @@ index 45569de..5aee09e 100644
      } {
        data_file_type
        -dalvikcache_data_file
    -@@ -379,6 +382,8 @@ neverallow {
    +@@ -379,6 +383,8 @@ neverallow {
        -cppreopts
        -dex2oat
        -otapreopt_slot
    @@ -43,7 +51,7 @@ index 45569de..5aee09e 100644
      } dalvikcache_data_file:file no_w_file_perms;
      
      neverallow {
    -@@ -390,6 +395,7 @@ neverallow {
    +@@ -390,6 +396,7 @@ neverallow {
        -dex2oat
        -zygote
        -otapreopt_slot
    @@ -51,7 +59,7 @@ index 45569de..5aee09e 100644
      } dalvikcache_data_file:dir no_w_dir_perms;
      
      # Only system_server should be able to send commands via the zygote socket
    -@@ -428,13 +434,13 @@ neverallow { domain userdebug_or_eng(`-dumpstate -shell -su') } su_exec:file no_
    +@@ -428,13 +435,13 @@ neverallow { domain userdebug_or_eng(`-dumpstate -shell -su') } su_exec:file no_
      # The only exceptions are for NDK text relocations associated with
      # https://code.google.com/p/android/issues/detail?id=23203
      # which, long term, need to go away.
    @@ -72,7 +80,7 @@ index 45569de..5aee09e 100644
      
      # Do not allow making the stack or heap executable.
      # We would also like to minimize execmem but it seems to be
    -@@ -443,7 +449,7 @@ neverallow * self:process { execstack execheap };
    +@@ -443,7 +450,7 @@ neverallow * self:process { execstack execheap };
      
      # prohibit non-zygote spawned processes from using shared libraries
      # with text relocations. b/20013628 .
    @@ -81,7 +89,7 @@ index 45569de..5aee09e 100644
      
      neverallow { domain -init } proc:{ file dir } mounton;
      
    -@@ -570,7 +576,7 @@ neverallow * domain:file { execute execute_no_trans entrypoint };
    +@@ -570,7 +577,7 @@ neverallow * domain:file { execute execute_no_trans entrypoint };
      # Instead, if access to part of debugfs is desired, it should have a
      # more specific label.
      # TODO: fix system_server and dumpstate
    
    From 7cda9c15adbb6dbec08406d6c4c4c3c6a518c264 Mon Sep 17 00:00:00 2001
    From: AndDiSa <anddisa@googlemail.com>
    Date: Thu, 19 Oct 2017 19:51:04 +0200
    Subject: [PATCH 087/159] update patches
    
    Change-Id: Iaec7bc13e09ce3fba10b0c0f228a4075304fdb78
    ---
     external_wpa_supplicant_8.patch | 3722 +++++++++++++++++++++++++++++++
     1 file changed, 3722 insertions(+)
     create mode 100644 external_wpa_supplicant_8.patch
    
    diff --git a/external_wpa_supplicant_8.patch b/external_wpa_supplicant_8.patch
    new file mode 100644
    index 0000000..41d8d87
    --- /dev/null
    +++ b/external_wpa_supplicant_8.patch
    @@ -0,0 +1,3722 @@
    +diff --git a/hostapd/Android.mk b/hostapd/Android.mk
    +index 67ca129..588fed9 100644
    +--- a/hostapd/Android.mk
    ++++ b/hostapd/Android.mk
    +@@ -210,11 +210,6 @@ L_CFLAGS += -DCONFIG_RSN_PREAUTH
    + CONFIG_L2_PACKET=y
    + endif
    + 
    +-ifdef CONFIG_PEERKEY
    +-L_CFLAGS += -DCONFIG_PEERKEY
    +-OBJS += src/ap/peerkey_auth.c
    +-endif
    +-
    + ifdef CONFIG_HS20
    + NEED_AES_OMAC1=y
    + CONFIG_PROXYARP=y
    +diff --git a/hostapd/Makefile b/hostapd/Makefile
    +index fa4af82..7a5781f 100644
    +--- a/hostapd/Makefile
    ++++ b/hostapd/Makefile
    +@@ -248,11 +248,6 @@ CFLAGS += -DCONFIG_RSN_PREAUTH
    + CONFIG_L2_PACKET=y
    + endif
    + 
    +-ifdef CONFIG_PEERKEY
    +-CFLAGS += -DCONFIG_PEERKEY
    +-OBJS += ../src/ap/peerkey_auth.o
    +-endif
    +-
    + ifdef CONFIG_HS20
    + NEED_AES_OMAC1=y
    + CONFIG_PROXYARP=y
    +diff --git a/hostapd/android.config b/hostapd/android.config
    +index e382c40..e8fd2df 100644
    +--- a/hostapd/android.config
    ++++ b/hostapd/android.config
    +@@ -44,9 +44,6 @@ CONFIG_DRIVER_NL80211_QCA=y
    + # WPA2/IEEE 802.11i RSN pre-authentication
    + #CONFIG_RSN_PREAUTH=y
    + 
    +-# PeerKey handshake for Station to Station Link (IEEE 802.11e DLS)
    +-#CONFIG_PEERKEY=y
    +-
    + # IEEE 802.11w (management frame protection)
    + # This version is an experimental implementation based on IEEE 802.11w/D1.0
    + # draft and is subject to change since the standard has not yet been finalized.
    +diff --git a/hostapd/config_file.c b/hostapd/config_file.c
    +index c35d5ae..8f49179 100644
    +--- a/hostapd/config_file.c
    ++++ b/hostapd/config_file.c
    +@@ -2515,10 +2515,9 @@ static int hostapd_config_fill(struct hostapd_config *conf,
    + 		os_free(bss->rsn_preauth_interfaces);
    + 		bss->rsn_preauth_interfaces = os_strdup(pos);
    + #endif /* CONFIG_RSN_PREAUTH */
    +-#ifdef CONFIG_PEERKEY
    + 	} else if (os_strcmp(buf, "peerkey") == 0) {
    +-		bss->peerkey = atoi(pos);
    +-#endif /* CONFIG_PEERKEY */
    ++		wpa_printf(MSG_INFO,
    ++			   "Line %d: Obsolete peerkey parameter ignored", line);
    + #ifdef CONFIG_IEEE80211R
    + 	} else if (os_strcmp(buf, "mobility_domain") == 0) {
    + 		if (os_strlen(pos) != 2 * MOBILITY_DOMAIN_ID_LEN ||
    +diff --git a/hostapd/ctrl_iface.c b/hostapd/ctrl_iface.c
    +index a87f117..09e3bc4 100644
    +--- a/hostapd/ctrl_iface.c
    ++++ b/hostapd/ctrl_iface.c
    +@@ -1531,6 +1531,67 @@ static int hostapd_ctrl_iface_mgmt_tx(struct hostapd_data *hapd, char *cmd)
    + }
    + 
    + 
    ++static int hostapd_ctrl_iface_mgmt_tx_status_process(struct hostapd_data *hapd,
    ++						     char *cmd)
    ++{
    ++	char *pos, *param;
    ++	size_t len;
    ++	u8 *buf;
    ++	int stype = 0, ok = 0;
    ++	union wpa_event_data event;
    ++
    ++	if (!hapd->ext_mgmt_frame_handling)
    ++		return -1;
    ++
    ++	/* stype=<val> ok=<0/1> buf=<frame hexdump> */
    ++
    ++	wpa_printf(MSG_DEBUG, "External MGMT TX status process: %s", cmd);
    ++
    ++	pos = cmd;
    ++	param = os_strstr(pos, "stype=");
    ++	if (param) {
    ++		param += 6;
    ++		stype = atoi(param);
    ++	}
    ++
    ++	param = os_strstr(pos, " ok=");
    ++	if (param) {
    ++		param += 4;
    ++		ok = atoi(param);
    ++	}
    ++
    ++	param = os_strstr(pos, " buf=");
    ++	if (!param)
    ++		return -1;
    ++	param += 5;
    ++
    ++	len = os_strlen(param);
    ++	if (len & 1)
    ++		return -1;
    ++	len /= 2;
    ++
    ++	buf = os_malloc(len);
    ++	if (!buf || hexstr2bin(param, buf, len) < 0) {
    ++		os_free(buf);
    ++		return -1;
    ++	}
    ++
    ++	os_memset(&event, 0, sizeof(event));
    ++	event.tx_status.type = WLAN_FC_TYPE_MGMT;
    ++	event.tx_status.data = buf;
    ++	event.tx_status.data_len = len;
    ++	event.tx_status.stype = stype;
    ++	event.tx_status.ack = ok;
    ++	hapd->ext_mgmt_frame_handling = 0;
    ++	wpa_supplicant_event(hapd, EVENT_TX_STATUS, &event);
    ++	hapd->ext_mgmt_frame_handling = 1;
    ++
    ++	os_free(buf);
    ++
    ++	return 0;
    ++}
    ++
    ++
    + static int hostapd_ctrl_iface_eapol_rx(struct hostapd_data *hapd, char *cmd)
    + {
    + 	char *pos;
    +@@ -2258,6 +2319,10 @@ static int hostapd_ctrl_iface_receive_process(struct hostapd_data *hapd,
    + 	} else if (os_strncmp(buf, "MGMT_TX ", 8) == 0) {
    + 		if (hostapd_ctrl_iface_mgmt_tx(hapd, buf + 8))
    + 			reply_len = -1;
    ++	} else if (os_strncmp(buf, "MGMT_TX_STATUS_PROCESS ", 23) == 0) {
    ++		if (hostapd_ctrl_iface_mgmt_tx_status_process(hapd,
    ++							      buf + 23) < 0)
    ++			reply_len = -1;
    + 	} else if (os_strncmp(buf, "EAPOL_RX ", 9) == 0) {
    + 		if (hostapd_ctrl_iface_eapol_rx(hapd, buf + 9) < 0)
    + 			reply_len = -1;
    +diff --git a/hostapd/defconfig b/hostapd/defconfig
    +index f7b60e0..5ee37dd 100644
    +--- a/hostapd/defconfig
    ++++ b/hostapd/defconfig
    +@@ -50,9 +50,6 @@ CONFIG_IAPP=y
    + # WPA2/IEEE 802.11i RSN pre-authentication
    + CONFIG_RSN_PREAUTH=y
    + 
    +-# PeerKey handshake for Station to Station Link (IEEE 802.11e DLS)
    +-CONFIG_PEERKEY=y
    +-
    + # IEEE 802.11w (management frame protection)
    + CONFIG_IEEE80211W=y
    + 
    +diff --git a/hostapd/hostapd.conf b/hostapd/hostapd.conf
    +index d943a43..1648fd0 100644
    +--- a/hostapd/hostapd.conf
    ++++ b/hostapd/hostapd.conf
    +@@ -1192,12 +1192,6 @@ own_ip_addr=127.0.0.1
    + # one.
    + #rsn_preauth_interfaces=eth0
    + 
    +-# peerkey: Whether PeerKey negotiation for direct links (IEEE 802.11e) is
    +-# allowed. This is only used with RSN/WPA2.
    +-# 0 = disabled (default)
    +-# 1 = enabled
    +-#peerkey=1
    +-
    + # ieee80211w: Whether management frame protection (MFP) is enabled
    + # 0 = disabled (default)
    + # 1 = optional
    +diff --git a/src/ap/Makefile b/src/ap/Makefile
    +index 98788fe..d67405f 100644
    +--- a/src/ap/Makefile
    ++++ b/src/ap/Makefile
    +@@ -45,7 +45,6 @@ LIB_OBJS= \
    + 	ieee802_1x.o \
    + 	ndisc_snoop.o \
    + 	p2p_hostapd.o \
    +-	peerkey_auth.o \
    + 	pmksa_cache_auth.o \
    + 	preauth_auth.o \
    + 	sta_info.o \
    +diff --git a/src/ap/ap_config.h b/src/ap/ap_config.h
    +index 2d07c67..4b00c29 100644
    +--- a/src/ap/ap_config.h
    ++++ b/src/ap/ap_config.h
    +@@ -322,7 +322,6 @@ struct hostapd_bss_config {
    + 	int rsn_pairwise;
    + 	int rsn_preauth;
    + 	char *rsn_preauth_interfaces;
    +-	int peerkey;
    + 
    + #ifdef CONFIG_IEEE80211R
    + 	/* IEEE 802.11r - Fast BSS Transition */
    +diff --git a/src/ap/ieee802_11.c b/src/ap/ieee802_11.c
    +index 6a373c5..b1cfb51 100644
    +--- a/src/ap/ieee802_11.c
    ++++ b/src/ap/ieee802_11.c
    +@@ -1774,6 +1774,7 @@ static int add_associated_sta(struct hostapd_data *hapd,
    + {
    + 	struct ieee80211_ht_capabilities ht_cap;
    + 	struct ieee80211_vht_capabilities vht_cap;
    ++	int set = 1;
    + 
    + 	/*
    + 	 * Remove the STA entry to ensure the STA PS state gets cleared and
    +@@ -1781,9 +1782,18 @@ static int add_associated_sta(struct hostapd_data *hapd,
    + 	 * FT-over-the-DS, where a station re-associates back to the same AP but
    + 	 * skips the authentication flow, or if working with a driver that
    + 	 * does not support full AP client state.
    ++	 *
    ++	 * Skip this if the STA has already completed FT reassociation and the
    ++	 * TK has been configured since the TX/RX PN must not be reset to 0 for
    ++	 * the same key.
    + 	 */
    +-	if (!sta->added_unassoc)
    ++	if (!sta->added_unassoc &&
    ++	    (!(sta->flags & WLAN_STA_AUTHORIZED) ||
    ++	     !wpa_auth_sta_ft_tk_already_set(sta->wpa_sm))) {
    + 		hostapd_drv_sta_remove(hapd, sta->addr);
    ++		wpa_auth_sm_event(sta->wpa_sm, WPA_DRV_STA_REMOVED);
    ++		set = 0;
    ++	}
    + 
    + #ifdef CONFIG_IEEE80211N
    + 	if (sta->flags & WLAN_STA_HT)
    +@@ -1805,11 +1815,11 @@ static int add_associated_sta(struct hostapd_data *hapd,
    + 			    sta->flags & WLAN_STA_HT ? &ht_cap : NULL,
    + 			    sta->flags & WLAN_STA_VHT ? &vht_cap : NULL,
    + 			    sta->flags | WLAN_STA_ASSOC, sta->qosinfo,
    +-			    sta->vht_opmode, sta->added_unassoc)) {
    ++			    sta->vht_opmode, set)) {
    + 		hostapd_logger(hapd, sta->addr,
    + 			       HOSTAPD_MODULE_IEEE80211, HOSTAPD_LEVEL_NOTICE,
    + 			       "Could not %s STA to kernel driver",
    +-			       sta->added_unassoc ? "set" : "add");
    ++			       set ? "set" : "add");
    + 
    + 		if (sta->added_unassoc) {
    + 			hostapd_drv_sta_remove(hapd, sta->addr);
    +@@ -2883,8 +2893,16 @@ void ieee802_11_mgmt_cb(struct hostapd_data *hapd, const u8 *buf, size_t len,
    + 
    + #ifdef CONFIG_TESTING_OPTIONS
    + 	if (hapd->ext_mgmt_frame_handling) {
    +-		wpa_msg(hapd->msg_ctx, MSG_INFO, "MGMT-TX-STATUS stype=%u ok=%d",
    +-			stype, ok);
    ++		size_t hex_len = 2 * len + 1;
    ++		char *hex = os_malloc(hex_len);
    ++
    ++		if (hex) {
    ++			wpa_snprintf_hex(hex, hex_len, buf, len);
    ++			wpa_msg(hapd->msg_ctx, MSG_INFO,
    ++				"MGMT-TX-STATUS stype=%u ok=%d buf=%s",
    ++				stype, ok, hex);
    ++			os_free(hex);
    ++		}
    + 		return;
    + 	}
    + #endif /* CONFIG_TESTING_OPTIONS */
    +diff --git a/src/ap/peerkey_auth.c b/src/ap/peerkey_auth.c
    +deleted file mode 100644
    +index efc1d7e..0000000
    +--- a/src/ap/peerkey_auth.c
    ++++ /dev/null
    +@@ -1,396 +0,0 @@
    +-/*
    +- * hostapd - PeerKey for Direct Link Setup (DLS)
    +- * Copyright (c) 2006-2009, Jouni Malinen <j@w1.fi>
    +- *
    +- * This software may be distributed under the terms of the BSD license.
    +- * See README for more details.
    +- */
    +-
    +-#include "utils/includes.h"
    +-
    +-#include "utils/common.h"
    +-#include "utils/eloop.h"
    +-#include "crypto/sha1.h"
    +-#include "crypto/sha256.h"
    +-#include "crypto/random.h"
    +-#include "wpa_auth.h"
    +-#include "wpa_auth_i.h"
    +-#include "wpa_auth_ie.h"
    +-
    +-#ifdef CONFIG_PEERKEY
    +-
    +-static void wpa_stsl_step(void *eloop_ctx, void *timeout_ctx)
    +-{
    +-#if 0
    +-	struct wpa_authenticator *wpa_auth = eloop_ctx;
    +-	struct wpa_stsl_negotiation *neg = timeout_ctx;
    +-#endif
    +-
    +-	/* TODO: ? */
    +-}
    +-
    +-
    +-struct wpa_stsl_search {
    +-	const u8 *addr;
    +-	struct wpa_state_machine *sm;
    +-};
    +-
    +-
    +-static int wpa_stsl_select_sta(struct wpa_state_machine *sm, void *ctx)
    +-{
    +-	struct wpa_stsl_search *search = ctx;
    +-	if (os_memcmp(search->addr, sm->addr, ETH_ALEN) == 0) {
    +-		search->sm = sm;
    +-		return 1;
    +-	}
    +-	return 0;
    +-}
    +-
    +-
    +-static void wpa_smk_send_error(struct wpa_authenticator *wpa_auth,
    +-			       struct wpa_state_machine *sm, const u8 *peer,
    +-			       u16 mui, u16 error_type)
    +-{
    +-	u8 kde[2 + RSN_SELECTOR_LEN + ETH_ALEN +
    +-	       2 + RSN_SELECTOR_LEN + sizeof(struct rsn_error_kde)];
    +-	u8 *pos;
    +-	struct rsn_error_kde error;
    +-
    +-	wpa_auth_logger(wpa_auth, sm->addr, LOGGER_DEBUG,
    +-			"Sending SMK Error");
    +-
    +-	pos = kde;
    +-
    +-	if (peer) {
    +-		pos = wpa_add_kde(pos, RSN_KEY_DATA_MAC_ADDR, peer, ETH_ALEN,
    +-				  NULL, 0);
    +-	}
    +-
    +-	error.mui = host_to_be16(mui);
    +-	error.error_type = host_to_be16(error_type);
    +-	pos = wpa_add_kde(pos, RSN_KEY_DATA_ERROR,
    +-			  (u8 *) &error, sizeof(error), NULL, 0);
    +-
    +-	__wpa_send_eapol(wpa_auth, sm,
    +-			 WPA_KEY_INFO_SECURE | WPA_KEY_INFO_MIC |
    +-			 WPA_KEY_INFO_SMK_MESSAGE | WPA_KEY_INFO_ERROR,
    +-			 NULL, NULL, kde, pos - kde, 0, 0, 0);
    +-}
    +-
    +-
    +-void wpa_smk_m1(struct wpa_authenticator *wpa_auth,
    +-		struct wpa_state_machine *sm, struct wpa_eapol_key *key,
    +-		const u8 *key_data, size_t key_data_len)
    +-{
    +-	struct wpa_eapol_ie_parse kde;
    +-	struct wpa_stsl_search search;
    +-	u8 *buf, *pos;
    +-	size_t buf_len;
    +-
    +-	if (wpa_parse_kde_ies(key_data, key_data_len, &kde) < 0) {
    +-		wpa_printf(MSG_INFO, "RSN: Failed to parse KDEs in SMK M1");
    +-		return;
    +-	}
    +-
    +-	if (kde.rsn_ie == NULL || kde.mac_addr == NULL ||
    +-	    kde.mac_addr_len < ETH_ALEN) {
    +-		wpa_printf(MSG_INFO, "RSN: No RSN IE or MAC address KDE in "
    +-			   "SMK M1");
    +-		return;
    +-	}
    +-
    +-	/* Initiator = sm->addr; Peer = kde.mac_addr */
    +-
    +-	search.addr = kde.mac_addr;
    +-	search.sm = NULL;
    +-	if (wpa_auth_for_each_sta(wpa_auth, wpa_stsl_select_sta, &search) ==
    +-	    0 || search.sm == NULL) {
    +-		wpa_printf(MSG_DEBUG, "RSN: SMK handshake with " MACSTR
    +-			   " aborted - STA not associated anymore",
    +-			   MAC2STR(kde.mac_addr));
    +-		wpa_smk_send_error(wpa_auth, sm, kde.mac_addr, STK_MUI_SMK,
    +-				   STK_ERR_STA_NR);
    +-		/* FIX: wpa_stsl_remove(wpa_auth, neg); */
    +-		return;
    +-	}
    +-
    +-	buf_len = kde.rsn_ie_len + 2 + RSN_SELECTOR_LEN + ETH_ALEN;
    +-	buf = os_malloc(buf_len);
    +-	if (buf == NULL)
    +-		return;
    +-	/* Initiator RSN IE */
    +-	os_memcpy(buf, kde.rsn_ie, kde.rsn_ie_len);
    +-	pos = buf + kde.rsn_ie_len;
    +-	/* Initiator MAC Address */
    +-	pos = wpa_add_kde(pos, RSN_KEY_DATA_MAC_ADDR, sm->addr, ETH_ALEN,
    +-			  NULL, 0);
    +-
    +-	/* SMK M2:
    +-	 * EAPOL-Key(S=1, M=1, A=1, I=0, K=0, SM=1, KeyRSC=0, Nonce=INonce,
    +-	 *           MIC=MIC, DataKDs=(RSNIE_I, MAC_I KDE)
    +-	 */
    +-
    +-	wpa_auth_logger(wpa_auth, search.sm->addr, LOGGER_DEBUG,
    +-			"Sending SMK M2");
    +-
    +-	__wpa_send_eapol(wpa_auth, search.sm,
    +-			 WPA_KEY_INFO_SECURE | WPA_KEY_INFO_MIC |
    +-			 WPA_KEY_INFO_ACK | WPA_KEY_INFO_SMK_MESSAGE,
    +-			 NULL, key->key_nonce, buf, pos - buf, 0, 0, 0);
    +-
    +-	os_free(buf);
    +-}
    +-
    +-
    +-static void wpa_send_smk_m4(struct wpa_authenticator *wpa_auth,
    +-			    struct wpa_state_machine *sm,
    +-			    struct wpa_eapol_key *key,
    +-			    struct wpa_eapol_ie_parse *kde,
    +-			    const u8 *smk)
    +-{
    +-	u8 *buf, *pos;
    +-	size_t buf_len;
    +-	u32 lifetime;
    +-
    +-	/* SMK M4:
    +-	 * EAPOL-Key(S=1, M=1, A=0, I=1, K=0, SM=1, KeyRSC=0, Nonce=PNonce,
    +-	 *           MIC=MIC, DataKDs=(MAC_I KDE, INonce KDE, SMK KDE,
    +-	 *           Lifetime KDE)
    +-	 */
    +-
    +-	buf_len = 2 + RSN_SELECTOR_LEN + ETH_ALEN +
    +-		2 + RSN_SELECTOR_LEN + WPA_NONCE_LEN +
    +-		2 + RSN_SELECTOR_LEN + PMK_LEN + WPA_NONCE_LEN +
    +-		2 + RSN_SELECTOR_LEN + sizeof(lifetime);
    +-	pos = buf = os_malloc(buf_len);
    +-	if (buf == NULL)
    +-		return;
    +-
    +-	/* Initiator MAC Address */
    +-	pos = wpa_add_kde(pos, RSN_KEY_DATA_MAC_ADDR, kde->mac_addr, ETH_ALEN,
    +-			  NULL, 0);
    +-
    +-	/* Initiator Nonce */
    +-	pos = wpa_add_kde(pos, RSN_KEY_DATA_NONCE, kde->nonce, WPA_NONCE_LEN,
    +-			  NULL, 0);
    +-
    +-	/* SMK with PNonce */
    +-	pos = wpa_add_kde(pos, RSN_KEY_DATA_SMK, smk, PMK_LEN,
    +-			  key->key_nonce, WPA_NONCE_LEN);
    +-
    +-	/* Lifetime */
    +-	lifetime = htonl(43200); /* dot11RSNAConfigSMKLifetime */
    +-	pos = wpa_add_kde(pos, RSN_KEY_DATA_LIFETIME,
    +-			  (u8 *) &lifetime, sizeof(lifetime), NULL, 0);
    +-
    +-	wpa_auth_logger(sm->wpa_auth, sm->addr, LOGGER_DEBUG,
    +-			"Sending SMK M4");
    +-
    +-	__wpa_send_eapol(wpa_auth, sm,
    +-			 WPA_KEY_INFO_SECURE | WPA_KEY_INFO_MIC |
    +-			 WPA_KEY_INFO_INSTALL | WPA_KEY_INFO_SMK_MESSAGE,
    +-			 NULL, key->key_nonce, buf, pos - buf, 0, 1, 0);
    +-
    +-	os_free(buf);
    +-}
    +-
    +-
    +-static void wpa_send_smk_m5(struct wpa_authenticator *wpa_auth,
    +-			    struct wpa_state_machine *sm,
    +-			    struct wpa_eapol_key *key,
    +-			    struct wpa_eapol_ie_parse *kde,
    +-			    const u8 *smk, const u8 *peer)
    +-{
    +-	u8 *buf, *pos;
    +-	size_t buf_len;
    +-	u32 lifetime;
    +-
    +-	/* SMK M5:
    +-	 * EAPOL-Key(S=1, M=1, A=0, I=0, K=0, SM=1, KeyRSC=0, Nonce=INonce,
    +-	 *           MIC=MIC, DataKDs=(RSNIE_P, MAC_P KDE, PNonce, SMK KDE,
    +-	 *                             Lifetime KDE))
    +-	 */
    +-
    +-	buf_len = kde->rsn_ie_len +
    +-		2 + RSN_SELECTOR_LEN + ETH_ALEN +
    +-		2 + RSN_SELECTOR_LEN + WPA_NONCE_LEN +
    +-		2 + RSN_SELECTOR_LEN + PMK_LEN + WPA_NONCE_LEN +
    +-		2 + RSN_SELECTOR_LEN + sizeof(lifetime);
    +-	pos = buf = os_malloc(buf_len);
    +-	if (buf == NULL)
    +-		return;
    +-
    +-	/* Peer RSN IE */
    +-	os_memcpy(pos, kde->rsn_ie, kde->rsn_ie_len);
    +-	pos += kde->rsn_ie_len;
    +-
    +-	/* Peer MAC Address */
    +-	pos = wpa_add_kde(pos, RSN_KEY_DATA_MAC_ADDR, peer, ETH_ALEN, NULL, 0);
    +-
    +-	/* PNonce */
    +-	pos = wpa_add_kde(pos, RSN_KEY_DATA_NONCE, key->key_nonce,
    +-			  WPA_NONCE_LEN, NULL, 0);
    +-
    +-	/* SMK and INonce */
    +-	pos = wpa_add_kde(pos, RSN_KEY_DATA_SMK, smk, PMK_LEN,
    +-			  kde->nonce, WPA_NONCE_LEN);
    +-
    +-	/* Lifetime */
    +-	lifetime = htonl(43200); /* dot11RSNAConfigSMKLifetime */
    +-	pos = wpa_add_kde(pos, RSN_KEY_DATA_LIFETIME,
    +-			  (u8 *) &lifetime, sizeof(lifetime), NULL, 0);
    +-
    +-	wpa_auth_logger(sm->wpa_auth, sm->addr, LOGGER_DEBUG,
    +-			"Sending SMK M5");
    +-
    +-	__wpa_send_eapol(wpa_auth, sm,
    +-			 WPA_KEY_INFO_SECURE | WPA_KEY_INFO_MIC |
    +-			 WPA_KEY_INFO_SMK_MESSAGE,
    +-			 NULL, kde->nonce, buf, pos - buf, 0, 1, 0);
    +-
    +-	os_free(buf);
    +-}
    +-
    +-
    +-void wpa_smk_m3(struct wpa_authenticator *wpa_auth,
    +-		struct wpa_state_machine *sm, struct wpa_eapol_key *key,
    +-		const u8 *key_data, size_t key_data_len)
    +-{
    +-	struct wpa_eapol_ie_parse kde;
    +-	struct wpa_stsl_search search;
    +-	u8 smk[32], buf[ETH_ALEN + 8 + 2 * WPA_NONCE_LEN], *pos;
    +-
    +-	if (wpa_parse_kde_ies(key_data, key_data_len, &kde) < 0) {
    +-		wpa_printf(MSG_INFO, "RSN: Failed to parse KDEs in SMK M3");
    +-		return;
    +-	}
    +-
    +-	if (kde.rsn_ie == NULL ||
    +-	    kde.mac_addr == NULL || kde.mac_addr_len < ETH_ALEN ||
    +-	    kde.nonce == NULL || kde.nonce_len < WPA_NONCE_LEN) {
    +-		wpa_printf(MSG_INFO, "RSN: No RSN IE, MAC address KDE, or "
    +-			   "Nonce KDE in SMK M3");
    +-		return;
    +-	}
    +-
    +-	/* Peer = sm->addr; Initiator = kde.mac_addr;
    +-	 * Peer Nonce = key->key_nonce; Initiator Nonce = kde.nonce */
    +-
    +-	search.addr = kde.mac_addr;
    +-	search.sm = NULL;
    +-	if (wpa_auth_for_each_sta(wpa_auth, wpa_stsl_select_sta, &search) ==
    +-	    0 || search.sm == NULL) {
    +-		wpa_printf(MSG_DEBUG, "RSN: SMK handshake with " MACSTR
    +-			   " aborted - STA not associated anymore",
    +-			   MAC2STR(kde.mac_addr));
    +-		wpa_smk_send_error(wpa_auth, sm, kde.mac_addr, STK_MUI_SMK,
    +-				   STK_ERR_STA_NR);
    +-		/* FIX: wpa_stsl_remove(wpa_auth, neg); */
    +-		return;
    +-	}
    +-
    +-	if (random_get_bytes(smk, PMK_LEN)) {
    +-		wpa_printf(MSG_DEBUG, "RSN: Failed to generate SMK");
    +-		return;
    +-	}
    +-
    +-	/* SMK = PRF-256(Random number, "SMK Derivation",
    +-	 *               AA || Time || INonce || PNonce)
    +-	 */
    +-	os_memcpy(buf, wpa_auth->addr, ETH_ALEN);
    +-	pos = buf + ETH_ALEN;
    +-	wpa_get_ntp_timestamp(pos);
    +-	pos += 8;
    +-	os_memcpy(pos, kde.nonce, WPA_NONCE_LEN);
    +-	pos += WPA_NONCE_LEN;
    +-	os_memcpy(pos, key->key_nonce, WPA_NONCE_LEN);
    +-#ifdef CONFIG_IEEE80211W
    +-	sha256_prf(smk, PMK_LEN, "SMK Derivation", buf, sizeof(buf),
    +-		   smk, PMK_LEN);
    +-#else /* CONFIG_IEEE80211W */
    +-	sha1_prf(smk, PMK_LEN, "SMK Derivation", buf, sizeof(buf),
    +-		 smk, PMK_LEN);
    +-#endif /* CONFIG_IEEE80211W */
    +-
    +-	wpa_hexdump_key(MSG_DEBUG, "RSN: SMK", smk, PMK_LEN);
    +-
    +-	wpa_send_smk_m4(wpa_auth, sm, key, &kde, smk);
    +-	wpa_send_smk_m5(wpa_auth, search.sm, key, &kde, smk, sm->addr);
    +-
    +-	/* Authenticator does not need SMK anymore and it is required to forget
    +-	 * it. */
    +-	os_memset(smk, 0, sizeof(*smk));
    +-}
    +-
    +-
    +-void wpa_smk_error(struct wpa_authenticator *wpa_auth,
    +-		   struct wpa_state_machine *sm,
    +-		   const u8 *key_data, size_t key_data_len)
    +-{
    +-	struct wpa_eapol_ie_parse kde;
    +-	struct wpa_stsl_search search;
    +-	struct rsn_error_kde error;
    +-	u16 mui, error_type;
    +-
    +-	if (wpa_parse_kde_ies(key_data, key_data_len, &kde) < 0) {
    +-		wpa_printf(MSG_INFO, "RSN: Failed to parse KDEs in SMK Error");
    +-		return;
    +-	}
    +-
    +-	if (kde.mac_addr == NULL || kde.mac_addr_len < ETH_ALEN ||
    +-	    kde.error == NULL || kde.error_len < sizeof(error)) {
    +-		wpa_printf(MSG_INFO, "RSN: No MAC address or Error KDE in "
    +-			   "SMK Error");
    +-		return;
    +-	}
    +-
    +-	search.addr = kde.mac_addr;
    +-	search.sm = NULL;
    +-	if (wpa_auth_for_each_sta(wpa_auth, wpa_stsl_select_sta, &search) ==
    +-	    0 || search.sm == NULL) {
    +-		wpa_printf(MSG_DEBUG, "RSN: Peer STA " MACSTR " not "
    +-			   "associated for SMK Error message from " MACSTR,
    +-			   MAC2STR(kde.mac_addr), MAC2STR(sm->addr));
    +-		return;
    +-	}
    +-
    +-	os_memcpy(&error, kde.error, sizeof(error));
    +-	mui = be_to_host16(error.mui);
    +-	error_type = be_to_host16(error.error_type);
    +-	wpa_auth_vlogger(wpa_auth, sm->addr, LOGGER_INFO,
    +-			 "STA reported SMK Error: Peer " MACSTR
    +-			 " MUI %d Error Type %d",
    +-			 MAC2STR(kde.mac_addr), mui, error_type);
    +-
    +-	wpa_smk_send_error(wpa_auth, search.sm, sm->addr, mui, error_type);
    +-}
    +-
    +-
    +-int wpa_stsl_remove(struct wpa_authenticator *wpa_auth,
    +-		    struct wpa_stsl_negotiation *neg)
    +-{
    +-	struct wpa_stsl_negotiation *pos, *prev;
    +-
    +-	if (wpa_auth == NULL)
    +-		return -1;
    +-	pos = wpa_auth->stsl_negotiations;
    +-	prev = NULL;
    +-	while (pos) {
    +-		if (pos == neg) {
    +-			if (prev)
    +-				prev->next = pos->next;
    +-			else
    +-				wpa_auth->stsl_negotiations = pos->next;
    +-
    +-			eloop_cancel_timeout(wpa_stsl_step, wpa_auth, pos);
    +-			os_free(pos);
    +-			return 0;
    +-		}
    +-		prev = pos;
    +-		pos = pos->next;
    +-	}
    +-
    +-	return -1;
    +-}
    +-
    +-#endif /* CONFIG_PEERKEY */
    +diff --git a/src/ap/wpa_auth.c b/src/ap/wpa_auth.c
    +index 3587086..e5974ff 100644
    +--- a/src/ap/wpa_auth.c
    ++++ b/src/ap/wpa_auth.c
    +@@ -879,8 +879,7 @@ void wpa_receive(struct wpa_authenticator *wpa_auth,
    + 	struct wpa_eapol_key *key;
    + 	struct wpa_eapol_key_192 *key192;
    + 	u16 key_info, key_data_length;
    +-	enum { PAIRWISE_2, PAIRWISE_4, GROUP_2, REQUEST,
    +-	       SMK_M1, SMK_M3, SMK_ERROR } msg;
    ++	enum { PAIRWISE_2, PAIRWISE_4, GROUP_2, REQUEST } msg;
    + 	char *msgtxt;
    + 	struct wpa_eapol_ie_parse kde;
    + 	int ft;
    +@@ -950,19 +949,12 @@ void wpa_receive(struct wpa_authenticator *wpa_auth,
    + 	/* FIX: verify that the EAPOL-Key frame was encrypted if pairwise keys
    + 	 * are set */
    + 
    +-	if ((key_info & (WPA_KEY_INFO_SMK_MESSAGE | WPA_KEY_INFO_REQUEST)) ==
    +-	    (WPA_KEY_INFO_SMK_MESSAGE | WPA_KEY_INFO_REQUEST)) {
    +-		if (key_info & WPA_KEY_INFO_ERROR) {
    +-			msg = SMK_ERROR;
    +-			msgtxt = "SMK Error";
    +-		} else {
    +-			msg = SMK_M1;
    +-			msgtxt = "SMK M1";
    +-		}
    +-	} else if (key_info & WPA_KEY_INFO_SMK_MESSAGE) {
    +-		msg = SMK_M3;
    +-		msgtxt = "SMK M3";
    +-	} else if (key_info & WPA_KEY_INFO_REQUEST) {
    ++	if (key_info & WPA_KEY_INFO_SMK_MESSAGE) {
    ++		wpa_printf(MSG_DEBUG, "WPA: Ignore SMK message");
    ++		return;
    ++	}
    ++
    ++	if (key_info & WPA_KEY_INFO_REQUEST) {
    + 		msg = REQUEST;
    + 		msgtxt = "Request";
    + 	} else if (!(key_info & WPA_KEY_INFO_KEY_TYPE)) {
    +@@ -976,7 +968,6 @@ void wpa_receive(struct wpa_authenticator *wpa_auth,
    + 		msgtxt = "2/4 Pairwise";
    + 	}
    + 
    +-	/* TODO: key_info type validation for PeerKey */
    + 	if (msg == REQUEST || msg == PAIRWISE_2 || msg == PAIRWISE_4 ||
    + 	    msg == GROUP_2) {
    + 		u16 ver = key_info & WPA_KEY_INFO_TYPE_MASK;
    +@@ -1204,28 +1195,6 @@ continue_processing:
    + 			return;
    + 		}
    + 		break;
    +-#ifdef CONFIG_PEERKEY
    +-	case SMK_M1:
    +-	case SMK_M3:
    +-	case SMK_ERROR:
    +-		if (!wpa_auth->conf.peerkey) {
    +-			wpa_printf(MSG_DEBUG, "RSN: SMK M1/M3/Error, but "
    +-				   "PeerKey use disabled - ignoring message");
    +-			return;
    +-		}
    +-		if (!sm->PTK_valid) {
    +-			wpa_auth_logger(wpa_auth, sm->addr, LOGGER_INFO,
    +-					"received EAPOL-Key msg SMK in "
    +-					"invalid state - dropped");
    +-			return;
    +-		}
    +-		break;
    +-#else /* CONFIG_PEERKEY */
    +-	case SMK_M1:
    +-	case SMK_M3:
    +-	case SMK_ERROR:
    +-		return; /* STSL disabled - ignore SMK messages */
    +-#endif /* CONFIG_PEERKEY */
    + 	case REQUEST:
    + 		break;
    + 	}
    +@@ -1277,12 +1246,7 @@ continue_processing:
    + 		 * even though MAC address KDE is not normally encrypted,
    + 		 * supplicant is allowed to encrypt it.
    + 		 */
    +-		if (msg == SMK_ERROR) {
    +-#ifdef CONFIG_PEERKEY
    +-			wpa_smk_error(wpa_auth, sm, key_data, key_data_length);
    +-#endif /* CONFIG_PEERKEY */
    +-			return;
    +-		} else if (key_info & WPA_KEY_INFO_ERROR) {
    ++		if (key_info & WPA_KEY_INFO_ERROR) {
    + 			if (wpa_receive_error_report(
    + 				    wpa_auth, sm,
    + 				    !(key_info & WPA_KEY_INFO_KEY_TYPE)) > 0)
    +@@ -1292,11 +1256,6 @@ continue_processing:
    + 					"received EAPOL-Key Request for new "
    + 					"4-Way Handshake");
    + 			wpa_request_new_ptk(sm);
    +-#ifdef CONFIG_PEERKEY
    +-		} else if (msg == SMK_M1) {
    +-			wpa_smk_m1(wpa_auth, sm, key, key_data,
    +-				   key_data_length);
    +-#endif /* CONFIG_PEERKEY */
    + 		} else if (key_data_length > 0 &&
    + 			   wpa_parse_kde_ies(key_data, key_data_length,
    + 					     &kde) == 0 &&
    +@@ -1335,13 +1294,6 @@ continue_processing:
    + 		wpa_replay_counter_mark_invalid(sm->key_replay, NULL);
    + 	}
    + 
    +-#ifdef CONFIG_PEERKEY
    +-	if (msg == SMK_M3) {
    +-		wpa_smk_m3(wpa_auth, sm, key, key_data, key_data_length);
    +-		return;
    +-	}
    +-#endif /* CONFIG_PEERKEY */
    +-
    + 	os_free(sm->last_rx_eapol_key);
    + 	sm->last_rx_eapol_key = os_malloc(data_len);
    + 	if (sm->last_rx_eapol_key == NULL)
    +@@ -1484,11 +1436,11 @@ void __wpa_send_eapol(struct wpa_authenticator *wpa_auth,
    + 	WPA_PUT_BE16(key->key_info, key_info);
    + 
    + 	alg = pairwise ? sm->pairwise : wpa_auth->conf.wpa_group;
    +-	WPA_PUT_BE16(key->key_length, wpa_cipher_key_len(alg));
    +-	if (key_info & WPA_KEY_INFO_SMK_MESSAGE)
    ++	if (sm->wpa == WPA_VERSION_WPA2 && !pairwise)
    + 		WPA_PUT_BE16(key->key_length, 0);
    ++	else
    ++		WPA_PUT_BE16(key->key_length, wpa_cipher_key_len(alg));
    + 
    +-	/* FIX: STSL: what to use as key_replay_counter? */
    + 	for (i = RSNA_MAX_EAPOL_RETRIES - 1; i > 0; i--) {
    + 		sm->key_replay[i].valid = sm->key_replay[i - 1].valid;
    + 		os_memcpy(sm->key_replay[i].counter,
    +@@ -1745,6 +1697,9 @@ int wpa_auth_sm_event(struct wpa_state_machine *sm, enum wpa_event event)
    + #else /* CONFIG_IEEE80211R */
    + 		break;
    + #endif /* CONFIG_IEEE80211R */
    ++	case WPA_DRV_STA_REMOVED:
    ++		sm->tk_already_set = FALSE;
    ++		return 0;
    + 	}
    + 
    + #ifdef CONFIG_IEEE80211R
    +@@ -1898,6 +1853,21 @@ SM_STATE(WPA_PTK, AUTHENTICATION2)
    + }
    + 
    + 
    ++static int wpa_auth_sm_ptk_update(struct wpa_state_machine *sm)
    ++{
    ++	if (random_get_bytes(sm->ANonce, WPA_NONCE_LEN)) {
    ++		wpa_printf(MSG_ERROR,
    ++			   "WPA: Failed to get random data for ANonce");
    ++		sm->Disconnect = TRUE;
    ++		return -1;
    ++	}
    ++	wpa_hexdump(MSG_DEBUG, "WPA: Assign new ANonce", sm->ANonce,
    ++		    WPA_NONCE_LEN);
    ++	sm->TimeoutCtr = 0;
    ++	return 0;
    ++}
    ++
    ++
    + SM_STATE(WPA_PTK, INITPMK)
    + {
    + 	u8 msk[2 * PMK_LEN];
    +@@ -2455,9 +2425,12 @@ SM_STEP(WPA_PTK)
    + 		SM_ENTER(WPA_PTK, AUTHENTICATION);
    + 	else if (sm->ReAuthenticationRequest)
    + 		SM_ENTER(WPA_PTK, AUTHENTICATION2);
    +-	else if (sm->PTKRequest)
    +-		SM_ENTER(WPA_PTK, PTKSTART);
    +-	else switch (sm->wpa_ptk_state) {
    ++	else if (sm->PTKRequest) {
    ++		if (wpa_auth_sm_ptk_update(sm) < 0)
    ++			SM_ENTER(WPA_PTK, DISCONNECTED);
    ++		else
    ++			SM_ENTER(WPA_PTK, PTKSTART);
    ++	} else switch (sm->wpa_ptk_state) {
    + 	case WPA_PTK_INITIALIZE:
    + 		break;
    + 	case WPA_PTK_DISCONNECT:
    +@@ -3250,6 +3223,14 @@ int wpa_auth_sta_wpa_version(struct wpa_state_machine *sm)
    + }
    + 
    + 
    ++int wpa_auth_sta_ft_tk_already_set(struct wpa_state_machine *sm)
    ++{
    ++	if (!sm || !wpa_key_mgmt_ft(sm->wpa_key_mgmt))
    ++		return 0;
    ++	return sm->tk_already_set;
    ++}
    ++
    ++
    + int wpa_auth_sta_clear_pmksa(struct wpa_state_machine *sm,
    + 			     struct rsn_pmksa_cache_entry *entry)
    + {
    +diff --git a/src/ap/wpa_auth.h b/src/ap/wpa_auth.h
    +index 0de8d97..032b0a3 100644
    +--- a/src/ap/wpa_auth.h
    ++++ b/src/ap/wpa_auth.h
    +@@ -147,7 +147,6 @@ struct wpa_auth_config {
    + 	int rsn_pairwise;
    + 	int rsn_preauth;
    + 	int eapol_version;
    +-	int peerkey;
    + 	int wmm_enabled;
    + 	int wmm_uapsd;
    + 	int disable_pmksa_caching;
    +@@ -267,7 +266,7 @@ void wpa_receive(struct wpa_authenticator *wpa_auth,
    + 		 u8 *data, size_t data_len);
    + enum wpa_event {
    + 	WPA_AUTH, WPA_ASSOC, WPA_DISASSOC, WPA_DEAUTH, WPA_REAUTH,
    +-	WPA_REAUTH_EAPOL, WPA_ASSOC_FT
    ++	WPA_REAUTH_EAPOL, WPA_ASSOC_FT, WPA_DRV_STA_REMOVED
    + };
    + void wpa_remove_ptk(struct wpa_state_machine *sm);
    + int wpa_auth_sm_event(struct wpa_state_machine *sm, enum wpa_event event);
    +@@ -280,6 +279,7 @@ int wpa_auth_pairwise_set(struct wpa_state_machine *sm);
    + int wpa_auth_get_pairwise(struct wpa_state_machine *sm);
    + int wpa_auth_sta_key_mgmt(struct wpa_state_machine *sm);
    + int wpa_auth_sta_wpa_version(struct wpa_state_machine *sm);
    ++int wpa_auth_sta_ft_tk_already_set(struct wpa_state_machine *sm);
    + int wpa_auth_sta_clear_pmksa(struct wpa_state_machine *sm,
    + 			     struct rsn_pmksa_cache_entry *entry);
    + struct rsn_pmksa_cache_entry *
    +diff --git a/src/ap/wpa_auth_ft.c b/src/ap/wpa_auth_ft.c
    +index 42242a5..e63b99a 100644
    +--- a/src/ap/wpa_auth_ft.c
    ++++ b/src/ap/wpa_auth_ft.c
    +@@ -780,6 +780,14 @@ void wpa_ft_install_ptk(struct wpa_state_machine *sm)
    + 		return;
    + 	}
    + 
    ++	if (sm->tk_already_set) {
    ++		/* Must avoid TK reconfiguration to prevent clearing of TX/RX
    ++		 * PN in the driver */
    ++		wpa_printf(MSG_DEBUG,
    ++			   "FT: Do not re-install same PTK to the driver");
    ++		return;
    ++	}
    ++
    + 	/* FIX: add STA entry to kernel/driver here? The set_key will fail
    + 	 * most likely without this.. At the moment, STA entry is added only
    + 	 * after association has been completed. This function will be called
    +@@ -792,6 +800,7 @@ void wpa_ft_install_ptk(struct wpa_state_machine *sm)
    + 
    + 	/* FIX: MLME-SetProtection.Request(TA, Tx_Rx) */
    + 	sm->pairwise_set = TRUE;
    ++	sm->tk_already_set = TRUE;
    + }
    + 
    + 
    +@@ -898,6 +907,7 @@ static int wpa_ft_process_auth_req(struct wpa_state_machine *sm,
    + 
    + 	sm->pairwise = pairwise;
    + 	sm->PTK_valid = TRUE;
    ++	sm->tk_already_set = FALSE;
    + 	wpa_ft_install_ptk(sm);
    + 
    + 	buflen = 2 + sizeof(struct rsn_mdie) + 2 + sizeof(struct rsn_ftie) +
    +diff --git a/src/ap/wpa_auth_glue.c b/src/ap/wpa_auth_glue.c
    +index 5fe0987..cbc1dbc 100644
    +--- a/src/ap/wpa_auth_glue.c
    ++++ b/src/ap/wpa_auth_glue.c
    +@@ -44,7 +44,6 @@ static void hostapd_wpa_auth_conf(struct hostapd_bss_config *conf,
    + 	wconf->rsn_pairwise = conf->rsn_pairwise;
    + 	wconf->rsn_preauth = conf->rsn_preauth;
    + 	wconf->eapol_version = conf->eapol_version;
    +-	wconf->peerkey = conf->peerkey;
    + 	wconf->wmm_enabled = conf->wmm_enabled;
    + 	wconf->wmm_uapsd = conf->wmm_uapsd;
    + 	wconf->disable_pmksa_caching = conf->disable_pmksa_caching;
    +diff --git a/src/ap/wpa_auth_i.h b/src/ap/wpa_auth_i.h
    +index 72b7eb3..b781605 100644
    +--- a/src/ap/wpa_auth_i.h
    ++++ b/src/ap/wpa_auth_i.h
    +@@ -65,6 +65,7 @@ struct wpa_state_machine {
    + 	struct wpa_ptk PTK;
    + 	Boolean PTK_valid;
    + 	Boolean pairwise_set;
    ++	Boolean tk_already_set;
    + 	int keycount;
    + 	Boolean Pair;
    + 	struct wpa_key_replay_counter {
    +@@ -230,20 +231,6 @@ int wpa_auth_for_each_auth(struct wpa_authenticator *wpa_auth,
    + 			   int (*cb)(struct wpa_authenticator *a, void *ctx),
    + 			   void *cb_ctx);
    + 
    +-#ifdef CONFIG_PEERKEY
    +-int wpa_stsl_remove(struct wpa_authenticator *wpa_auth,
    +-		    struct wpa_stsl_negotiation *neg);
    +-void wpa_smk_error(struct wpa_authenticator *wpa_auth,
    +-		   struct wpa_state_machine *sm,
    +-		   const u8 *key_data, size_t key_data_len);
    +-void wpa_smk_m1(struct wpa_authenticator *wpa_auth,
    +-		struct wpa_state_machine *sm, struct wpa_eapol_key *key,
    +-		const u8 *key_data, size_t key_data_len);
    +-void wpa_smk_m3(struct wpa_authenticator *wpa_auth,
    +-		struct wpa_state_machine *sm, struct wpa_eapol_key *key,
    +-		const u8 *key_data, size_t key_data_len);
    +-#endif /* CONFIG_PEERKEY */
    +-
    + #ifdef CONFIG_IEEE80211R
    + int wpa_write_mdie(struct wpa_auth_config *conf, u8 *buf, size_t len);
    + int wpa_write_ftie(struct wpa_auth_config *conf, const u8 *r0kh_id,
    +diff --git a/src/ap/wpa_auth_ie.c b/src/ap/wpa_auth_ie.c
    +index f79783b..8f855b8 100644
    +--- a/src/ap/wpa_auth_ie.c
    ++++ b/src/ap/wpa_auth_ie.c
    +@@ -230,8 +230,6 @@ int wpa_write_rsn_ie(struct wpa_auth_config *conf, u8 *buf, size_t len,
    + 	capab = 0;
    + 	if (conf->rsn_preauth)
    + 		capab |= WPA_CAPABILITY_PREAUTH;
    +-	if (conf->peerkey)
    +-		capab |= WPA_CAPABILITY_PEERKEY_ENABLED;
    + 	if (conf->wmm_enabled) {
    + 		/* 4 PTKSA replay counters when using WMM */
    + 		capab |= (RSN_NUM_REPLAY_COUNTERS_16 << 2);
    +@@ -815,36 +813,6 @@ static int wpa_parse_generic(const u8 *pos, const u8 *end,
    + 		return 0;
    + 	}
    + 
    +-#ifdef CONFIG_PEERKEY
    +-	if (pos[1] > RSN_SELECTOR_LEN + 2 &&
    +-	    RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_SMK) {
    +-		ie->smk = pos + 2 + RSN_SELECTOR_LEN;
    +-		ie->smk_len = pos[1] - RSN_SELECTOR_LEN;
    +-		return 0;
    +-	}
    +-
    +-	if (pos[1] > RSN_SELECTOR_LEN + 2 &&
    +-	    RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_NONCE) {
    +-		ie->nonce = pos + 2 + RSN_SELECTOR_LEN;
    +-		ie->nonce_len = pos[1] - RSN_SELECTOR_LEN;
    +-		return 0;
    +-	}
    +-
    +-	if (pos[1] > RSN_SELECTOR_LEN + 2 &&
    +-	    RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_LIFETIME) {
    +-		ie->lifetime = pos + 2 + RSN_SELECTOR_LEN;
    +-		ie->lifetime_len = pos[1] - RSN_SELECTOR_LEN;
    +-		return 0;
    +-	}
    +-
    +-	if (pos[1] > RSN_SELECTOR_LEN + 2 &&
    +-	    RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_ERROR) {
    +-		ie->error = pos + 2 + RSN_SELECTOR_LEN;
    +-		ie->error_len = pos[1] - RSN_SELECTOR_LEN;
    +-		return 0;
    +-	}
    +-#endif /* CONFIG_PEERKEY */
    +-
    + #ifdef CONFIG_IEEE80211W
    + 	if (pos[1] > RSN_SELECTOR_LEN + 2 &&
    + 	    RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_IGTK) {
    +diff --git a/src/ap/wpa_auth_ie.h b/src/ap/wpa_auth_ie.h
    +index d2067ba..0e2b3df 100644
    +--- a/src/ap/wpa_auth_ie.h
    ++++ b/src/ap/wpa_auth_ie.h
    +@@ -19,16 +19,6 @@ struct wpa_eapol_ie_parse {
    + 	size_t gtk_len;
    + 	const u8 *mac_addr;
    + 	size_t mac_addr_len;
    +-#ifdef CONFIG_PEERKEY
    +-	const u8 *smk;
    +-	size_t smk_len;
    +-	const u8 *nonce;
    +-	size_t nonce_len;
    +-	const u8 *lifetime;
    +-	size_t lifetime_len;
    +-	const u8 *error;
    +-	size_t error_len;
    +-#endif /* CONFIG_PEERKEY */
    + #ifdef CONFIG_IEEE80211W
    + 	const u8 *igtk;
    + 	size_t igtk_len;
    +diff --git a/src/common/privsep_commands.h b/src/common/privsep_commands.h
    +index 8dff303..15a1bfc 100644
    +--- a/src/common/privsep_commands.h
    ++++ b/src/common/privsep_commands.h
    +@@ -84,7 +84,6 @@ enum privsep_event {
    + 	PRIVSEP_EVENT_MICHAEL_MIC_FAILURE,
    + 	PRIVSEP_EVENT_INTERFACE_STATUS,
    + 	PRIVSEP_EVENT_PMKID_CANDIDATE,
    +-	PRIVSEP_EVENT_STKSTART,
    + 	PRIVSEP_EVENT_FT_RESPONSE,
    + 	PRIVSEP_EVENT_RX_EAPOL,
    + 	PRIVSEP_EVENT_SCAN_STARTED,
    +diff --git a/src/common/wpa_common.c b/src/common/wpa_common.c
    +index d6295b2..41a49d0 100644
    +--- a/src/common/wpa_common.c
    ++++ b/src/common/wpa_common.c
    +@@ -133,10 +133,6 @@ int wpa_eapol_key_mic(const u8 *key, size_t key_len, int akmp, int ver,
    +  * PTK = PRF-X(PMK, "Pairwise key expansion",
    +  *             Min(AA, SA) || Max(AA, SA) ||
    +  *             Min(ANonce, SNonce) || Max(ANonce, SNonce))
    +- *
    +- * STK = PRF-X(SMK, "Peer key expansion",
    +- *             Min(MAC_I, MAC_P) || Max(MAC_I, MAC_P) ||
    +- *             Min(INonce, PNonce) || Max(INonce, PNonce))
    +  */
    + int wpa_pmk_to_ptk(const u8 *pmk, size_t pmk_len, const char *label,
    + 		   const u8 *addr1, const u8 *addr2,
    +@@ -147,6 +143,11 @@ int wpa_pmk_to_ptk(const u8 *pmk, size_t pmk_len, const char *label,
    + 	u8 tmp[WPA_KCK_MAX_LEN + WPA_KEK_MAX_LEN + WPA_TK_MAX_LEN];
    + 	size_t ptk_len;
    + 
    ++	if (pmk_len == 0) {
    ++		wpa_printf(MSG_ERROR, "WPA: No PMK set for PT derivation");
    ++		return -1;
    ++	}
    ++
    + 	if (os_memcmp(addr1, addr2, ETH_ALEN) < 0) {
    + 		os_memcpy(data, addr1, ETH_ALEN);
    + 		os_memcpy(data + ETH_ALEN, addr2, ETH_ALEN);
    +diff --git a/src/common/wpa_common.h b/src/common/wpa_common.h
    +index af1d0f0..642b28c 100644
    +--- a/src/common/wpa_common.h
    ++++ b/src/common/wpa_common.h
    +@@ -88,12 +88,6 @@ RSN_SELECTOR(0x00, 0x0f, 0xac, 13)
    + #endif
    + #define RSN_KEY_DATA_MAC_ADDR RSN_SELECTOR(0x00, 0x0f, 0xac, 3)
    + #define RSN_KEY_DATA_PMKID RSN_SELECTOR(0x00, 0x0f, 0xac, 4)
    +-#ifdef CONFIG_PEERKEY
    +-#define RSN_KEY_DATA_SMK RSN_SELECTOR(0x00, 0x0f, 0xac, 5)
    +-#define RSN_KEY_DATA_NONCE RSN_SELECTOR(0x00, 0x0f, 0xac, 6)
    +-#define RSN_KEY_DATA_LIFETIME RSN_SELECTOR(0x00, 0x0f, 0xac, 7)
    +-#define RSN_KEY_DATA_ERROR RSN_SELECTOR(0x00, 0x0f, 0xac, 8)
    +-#endif /* CONFIG_PEERKEY */
    + #ifdef CONFIG_IEEE80211W
    + #define RSN_KEY_DATA_IGTK RSN_SELECTOR(0x00, 0x0f, 0xac, 9)
    + #endif /* CONFIG_IEEE80211W */
    +@@ -215,8 +209,20 @@ struct wpa_ptk {
    + 	size_t kck_len;
    + 	size_t kek_len;
    + 	size_t tk_len;
    ++	int installed; /* 1 if key has already been installed to driver */
    + };
    + 
    ++struct wpa_gtk {
    ++	u8 gtk[WPA_GTK_MAX_LEN];
    ++	size_t gtk_len;
    ++};
    ++
    ++#ifdef CONFIG_IEEE80211W
    ++struct wpa_igtk {
    ++	u8 igtk[WPA_IGTK_MAX_LEN];
    ++	size_t igtk_len;
    ++};
    ++#endif /* CONFIG_IEEE80211W */
    + 
    + /* WPA IE version 1
    +  * 00-50-f2:1 (OUI:OUI type)
    +@@ -271,22 +277,6 @@ struct rsn_ie_hdr {
    + } STRUCT_PACKED;
    + 
    + 
    +-#ifdef CONFIG_PEERKEY
    +-enum {
    +-	STK_MUI_4WAY_STA_AP = 1,
    +-	STK_MUI_4WAY_STAT_STA = 2,
    +-	STK_MUI_GTK = 3,
    +-	STK_MUI_SMK = 4
    +-};
    +-
    +-enum {
    +-	STK_ERR_STA_NR = 1,
    +-	STK_ERR_STA_NRSN = 2,
    +-	STK_ERR_CPHR_NS = 3,
    +-	STK_ERR_NO_STSL = 4
    +-};
    +-#endif /* CONFIG_PEERKEY */
    +-
    + struct rsn_error_kde {
    + 	be16 mui;
    + 	be16 error_type;
    +diff --git a/src/drivers/driver.h b/src/drivers/driver.h
    +index b7e0d16..bae4777 100644
    +--- a/src/drivers/driver.h
    ++++ b/src/drivers/driver.h
    +@@ -3648,17 +3648,6 @@ enum wpa_event_type {
    + 	EVENT_PMKID_CANDIDATE,
    + 
    + 	/**
    +-	 * EVENT_STKSTART - Request STK handshake (MLME-STKSTART.request)
    +-	 *
    +-	 * This event can be used to inform wpa_supplicant about desire to set
    +-	 * up secure direct link connection between two stations as defined in
    +-	 * IEEE 802.11e with a new PeerKey mechanism that replaced the original
    +-	 * STAKey negotiation. The caller will need to set peer address for the
    +-	 * event.
    +-	 */
    +-	EVENT_STKSTART,
    +-
    +-	/**
    + 	 * EVENT_TDLS - Request TDLS operation
    + 	 *
    + 	 * This event can be used to request a TDLS operation to be performed.
    +@@ -4298,13 +4287,6 @@ union wpa_event_data {
    + 	} pmkid_candidate;
    + 
    + 	/**
    +-	 * struct stkstart - Data for EVENT_STKSTART
    +-	 */
    +-	struct stkstart {
    +-		u8 peer[ETH_ALEN];
    +-	} stkstart;
    +-
    +-	/**
    + 	 * struct tdls - Data for EVENT_TDLS
    + 	 */
    + 	struct tdls {
    +diff --git a/src/drivers/driver_common.c b/src/drivers/driver_common.c
    +index b32d35f..7c35277 100644
    +--- a/src/drivers/driver_common.c
    ++++ b/src/drivers/driver_common.c
    +@@ -35,7 +35,6 @@ const char * event_to_string(enum wpa_event_type event)
    + 	E2S(ASSOCINFO);
    + 	E2S(INTERFACE_STATUS);
    + 	E2S(PMKID_CANDIDATE);
    +-	E2S(STKSTART);
    + 	E2S(TDLS);
    + 	E2S(FT_RESPONSE);
    + 	E2S(IBSS_RSN_START);
    +diff --git a/src/drivers/driver_privsep.c b/src/drivers/driver_privsep.c
    +index 43d4193..6fd298d 100644
    +--- a/src/drivers/driver_privsep.c
    ++++ b/src/drivers/driver_privsep.c
    +@@ -464,19 +464,6 @@ static void wpa_driver_privsep_event_pmkid_candidate(void *ctx, u8 *buf,
    + }
    + 
    + 
    +-static void wpa_driver_privsep_event_stkstart(void *ctx, u8 *buf, size_t len)
    +-{
    +-	union wpa_event_data data;
    +-
    +-	if (len != ETH_ALEN)
    +-		return;
    +-
    +-	os_memset(&data, 0, sizeof(data));
    +-	os_memcpy(data.stkstart.peer, buf, ETH_ALEN);
    +-	wpa_supplicant_event(ctx, EVENT_STKSTART, &data);
    +-}
    +-
    +-
    + static void wpa_driver_privsep_event_ft_response(void *ctx, u8 *buf,
    + 						 size_t len)
    + {
    +@@ -570,10 +557,6 @@ static void wpa_driver_privsep_receive(int sock, void *eloop_ctx,
    + 		wpa_driver_privsep_event_pmkid_candidate(drv->ctx, event_buf,
    + 							 event_len);
    + 		break;
    +-	case PRIVSEP_EVENT_STKSTART:
    +-		wpa_driver_privsep_event_stkstart(drv->ctx, event_buf,
    +-						  event_len);
    +-		break;
    + 	case PRIVSEP_EVENT_FT_RESPONSE:
    + 		wpa_driver_privsep_event_ft_response(drv->ctx, event_buf,
    + 						     event_len);
    +diff --git a/src/drivers/driver_wext.c b/src/drivers/driver_wext.c
    +index 791cd5d..e149ed2 100644
    +--- a/src/drivers/driver_wext.c
    ++++ b/src/drivers/driver_wext.c
    +@@ -290,15 +290,6 @@ wpa_driver_wext_event_wireless_custom(void *ctx, char *custom)
    + 	done:
    + 		os_free(resp_ies);
    + 		os_free(req_ies);
    +-#ifdef CONFIG_PEERKEY
    +-	} else if (os_strncmp(custom, "STKSTART.request=", 17) == 0) {
    +-		if (hwaddr_aton(custom + 17, data.stkstart.peer)) {
    +-			wpa_printf(MSG_DEBUG, "WEXT: unrecognized "
    +-				   "STKSTART.request '%s'", custom + 17);
    +-			return;
    +-		}
    +-		wpa_supplicant_event(ctx, EVENT_STKSTART, &data);
    +-#endif /* CONFIG_PEERKEY */
    + 	}
    + }
    + 
    +@@ -472,7 +463,7 @@ static void wpa_driver_wext_event_wireless(struct wpa_driver_wext_data *drv,
    + 				drv->assoc_resp_ies = NULL;
    + 				wpa_supplicant_event(drv->ctx, EVENT_DISASSOC,
    + 						     NULL);
    +-			
    ++
    + 			} else {
    + 				wpa_driver_wext_event_assoc_ies(drv);
    + 				wpa_supplicant_event(drv->ctx, EVENT_ASSOC,
    +diff --git a/src/rsn_supp/Makefile b/src/rsn_supp/Makefile
    +index d5e61fe..c2d81f2 100644
    +--- a/src/rsn_supp/Makefile
    ++++ b/src/rsn_supp/Makefile
    +@@ -10,7 +10,6 @@ include ../lib.rules
    + 
    + CFLAGS += -DCONFIG_IEEE80211W
    + CFLAGS += -DCONFIG_IEEE80211R
    +-CFLAGS += -DCONFIG_PEERKEY
    + CFLAGS += -DCONFIG_TDLS
    + CFLAGS += -DCONFIG_WNM
    + CFLAGS += -DIEEE8021X_EAPOL
    +@@ -18,7 +17,6 @@ CFLAGS += -DIEEE8021X_EAPOL
    + LIB_OBJS= \
    + 	pmksa_cache.o \
    + 	wpa_ft.o \
    +-	peerkey.o \
    + 	tdls.o \
    + 	preauth.o \
    + 	wpa.o \
    +diff --git a/src/rsn_supp/peerkey.c b/src/rsn_supp/peerkey.c
    +deleted file mode 100644
    +index 79764d9..0000000
    +--- a/src/rsn_supp/peerkey.c
    ++++ /dev/null
    +@@ -1,1155 +0,0 @@
    +-/*
    +- * WPA Supplicant - PeerKey for Direct Link Setup (DLS)
    +- * Copyright (c) 2006-2015, Jouni Malinen <j@w1.fi>
    +- *
    +- * This software may be distributed under the terms of the BSD license.
    +- * See README for more details.
    +- */
    +-
    +-#include "includes.h"
    +-
    +-#ifdef CONFIG_PEERKEY
    +-
    +-#include "common.h"
    +-#include "eloop.h"
    +-#include "crypto/sha1.h"
    +-#include "crypto/sha256.h"
    +-#include "crypto/random.h"
    +-#include "common/ieee802_11_defs.h"
    +-#include "wpa.h"
    +-#include "wpa_i.h"
    +-#include "wpa_ie.h"
    +-#include "peerkey.h"
    +-
    +-
    +-static u8 * wpa_add_ie(u8 *pos, const u8 *ie, size_t ie_len)
    +-{
    +-	os_memcpy(pos, ie, ie_len);
    +-	return pos + ie_len;
    +-}
    +-
    +-
    +-static u8 * wpa_add_kde(u8 *pos, u32 kde, const u8 *data, size_t data_len)
    +-{
    +-	*pos++ = WLAN_EID_VENDOR_SPECIFIC;
    +-	*pos++ = RSN_SELECTOR_LEN + data_len;
    +-	RSN_SELECTOR_PUT(pos, kde);
    +-	pos += RSN_SELECTOR_LEN;
    +-	os_memcpy(pos, data, data_len);
    +-	pos += data_len;
    +-	return pos;
    +-}
    +-
    +-
    +-static void wpa_supplicant_smk_timeout(void *eloop_ctx, void *timeout_ctx)
    +-{
    +-#if 0
    +-	struct wpa_sm *sm = eloop_ctx;
    +-	struct wpa_peerkey *peerkey = timeout_ctx;
    +-#endif
    +-	/* TODO: time out SMK and any STK that was generated using this SMK */
    +-}
    +-
    +-
    +-static void wpa_supplicant_peerkey_free(struct wpa_sm *sm,
    +-					struct wpa_peerkey *peerkey)
    +-{
    +-	eloop_cancel_timeout(wpa_supplicant_smk_timeout, sm, peerkey);
    +-	os_free(peerkey);
    +-}
    +-
    +-
    +-static int wpa_supplicant_send_smk_error(struct wpa_sm *sm, const u8 *dst,
    +-					 const u8 *peer,
    +-					 u16 mui, u16 error_type, int ver)
    +-{
    +-	size_t rlen;
    +-	struct wpa_eapol_key *err;
    +-	struct wpa_eapol_key_192 *err192;
    +-	struct rsn_error_kde error;
    +-	u8 *rbuf, *pos;
    +-	size_t kde_len;
    +-	u16 key_info;
    +-
    +-	kde_len = 2 + RSN_SELECTOR_LEN + sizeof(error);
    +-	if (peer)
    +-		kde_len += 2 + RSN_SELECTOR_LEN + ETH_ALEN;
    +-
    +-	rbuf = wpa_sm_alloc_eapol(sm, IEEE802_1X_TYPE_EAPOL_KEY,
    +-				  NULL, sizeof(*err) + kde_len, &rlen,
    +-				  (void *) &err);
    +-	if (rbuf == NULL)
    +-		return -1;
    +-	err192 = (struct wpa_eapol_key_192 *) err;
    +-
    +-	err->type = EAPOL_KEY_TYPE_RSN;
    +-	key_info = ver | WPA_KEY_INFO_SMK_MESSAGE | WPA_KEY_INFO_MIC |
    +-		WPA_KEY_INFO_SECURE | WPA_KEY_INFO_ERROR |
    +-		WPA_KEY_INFO_REQUEST;
    +-	WPA_PUT_BE16(err->key_info, key_info);
    +-	WPA_PUT_BE16(err->key_length, 0);
    +-	os_memcpy(err->replay_counter, sm->request_counter,
    +-		  WPA_REPLAY_COUNTER_LEN);
    +-	inc_byte_array(sm->request_counter, WPA_REPLAY_COUNTER_LEN);
    +-
    +-	WPA_PUT_BE16(err->key_data_length, (u16) kde_len);
    +-	pos = (u8 *) (err + 1);
    +-
    +-	if (peer) {
    +-		/* Peer MAC Address KDE */
    +-		pos = wpa_add_kde(pos, RSN_KEY_DATA_MAC_ADDR, peer, ETH_ALEN);
    +-	}
    +-
    +-	/* Error KDE */
    +-	error.mui = host_to_be16(mui);
    +-	error.error_type = host_to_be16(error_type);
    +-	wpa_add_kde(pos, RSN_KEY_DATA_ERROR, (u8 *) &error, sizeof(error));
    +-
    +-	if (peer) {
    +-		wpa_printf(MSG_DEBUG, "RSN: Sending EAPOL-Key SMK Error (peer "
    +-			   MACSTR " mui %d error_type %d)",
    +-			   MAC2STR(peer), mui, error_type);
    +-	} else {
    +-		wpa_printf(MSG_DEBUG, "RSN: Sending EAPOL-Key SMK Error "
    +-			   "(mui %d error_type %d)", mui, error_type);
    +-	}
    +-
    +-	wpa_eapol_key_send(sm, sm->ptk.kck, sm->ptk.kck_len, ver, dst,
    +-			   ETH_P_EAPOL, rbuf, rlen, err192->key_mic);
    +-
    +-	return 0;
    +-}
    +-
    +-
    +-static int wpa_supplicant_send_smk_m3(struct wpa_sm *sm,
    +-				      const unsigned char *src_addr,
    +-				      const struct wpa_eapol_key *key,
    +-				      int ver, struct wpa_peerkey *peerkey)
    +-{
    +-	size_t rlen;
    +-	struct wpa_eapol_key *reply;
    +-	struct wpa_eapol_key_192 *reply192;
    +-	u8 *rbuf, *pos;
    +-	size_t kde_len;
    +-	u16 key_info;
    +-
    +-	/* KDEs: Peer RSN IE, Initiator MAC Address, Initiator Nonce */
    +-	kde_len = peerkey->rsnie_p_len +
    +-		2 + RSN_SELECTOR_LEN + ETH_ALEN +
    +-		2 + RSN_SELECTOR_LEN + WPA_NONCE_LEN;
    +-
    +-	rbuf = wpa_sm_alloc_eapol(sm, IEEE802_1X_TYPE_EAPOL_KEY,
    +-				  NULL, sizeof(*reply) + kde_len, &rlen,
    +-				  (void *) &reply);
    +-	if (rbuf == NULL)
    +-		return -1;
    +-	reply192 = (struct wpa_eapol_key_192 *) reply;
    +-
    +-	reply->type = EAPOL_KEY_TYPE_RSN;
    +-	key_info = ver | WPA_KEY_INFO_SMK_MESSAGE | WPA_KEY_INFO_MIC |
    +-		WPA_KEY_INFO_SECURE;
    +-	WPA_PUT_BE16(reply->key_info, key_info);
    +-	WPA_PUT_BE16(reply->key_length, 0);
    +-	os_memcpy(reply->replay_counter, key->replay_counter,
    +-		  WPA_REPLAY_COUNTER_LEN);
    +-
    +-	os_memcpy(reply->key_nonce, peerkey->pnonce, WPA_NONCE_LEN);
    +-
    +-	WPA_PUT_BE16(reply->key_data_length, (u16) kde_len);
    +-	pos = (u8 *) (reply + 1);
    +-
    +-	/* Peer RSN IE */
    +-	pos = wpa_add_ie(pos, peerkey->rsnie_p, peerkey->rsnie_p_len);
    +-
    +-	/* Initiator MAC Address KDE */
    +-	pos = wpa_add_kde(pos, RSN_KEY_DATA_MAC_ADDR, peerkey->addr, ETH_ALEN);
    +-
    +-	/* Initiator Nonce */
    +-	wpa_add_kde(pos, RSN_KEY_DATA_NONCE, peerkey->inonce, WPA_NONCE_LEN);
    +-
    +-	wpa_printf(MSG_DEBUG, "RSN: Sending EAPOL-Key SMK M3");
    +-	wpa_eapol_key_send(sm, sm->ptk.kck, sm->ptk.kck_len, ver, src_addr,
    +-			   ETH_P_EAPOL, rbuf, rlen, reply192->key_mic);
    +-
    +-	return 0;
    +-}
    +-
    +-
    +-static int wpa_supplicant_process_smk_m2(
    +-	struct wpa_sm *sm, const unsigned char *src_addr,
    +-	const struct wpa_eapol_key *key, size_t extra_len, int ver)
    +-{
    +-	struct wpa_peerkey *peerkey;
    +-	struct wpa_eapol_ie_parse kde;
    +-	struct wpa_ie_data ie;
    +-	int cipher;
    +-	struct rsn_ie_hdr *hdr;
    +-	u8 *pos;
    +-
    +-	wpa_printf(MSG_DEBUG, "RSN: Received SMK M2");
    +-
    +-	if (!sm->peerkey_enabled || sm->proto != WPA_PROTO_RSN) {
    +-		wpa_printf(MSG_INFO, "RSN: SMK handshake not allowed for "
    +-			   "the current network");
    +-		return -1;
    +-	}
    +-
    +-	if (wpa_supplicant_parse_ies((const u8 *) (key + 1), extra_len, &kde) <
    +-	    0) {
    +-		wpa_printf(MSG_INFO, "RSN: Failed to parse KDEs in SMK M2");
    +-		return -1;
    +-	}
    +-
    +-	if (kde.rsn_ie == NULL || kde.mac_addr == NULL ||
    +-	    kde.mac_addr_len < ETH_ALEN) {
    +-		wpa_printf(MSG_INFO, "RSN: No RSN IE or MAC address KDE in "
    +-			   "SMK M2");
    +-		return -1;
    +-	}
    +-
    +-	wpa_printf(MSG_DEBUG, "RSN: SMK M2 - SMK initiator " MACSTR,
    +-		   MAC2STR(kde.mac_addr));
    +-
    +-	if (kde.rsn_ie_len > PEERKEY_MAX_IE_LEN) {
    +-		wpa_printf(MSG_INFO, "RSN: Too long Initiator RSN IE in SMK "
    +-			   "M2");
    +-		return -1;
    +-	}
    +-
    +-	if (wpa_parse_wpa_ie_rsn(kde.rsn_ie, kde.rsn_ie_len, &ie) < 0) {
    +-		wpa_printf(MSG_INFO, "RSN: Failed to parse RSN IE in SMK M2");
    +-		return -1;
    +-	}
    +-
    +-	cipher = wpa_pick_pairwise_cipher(ie.pairwise_cipher &
    +-					  sm->allowed_pairwise_cipher, 0);
    +-	if (cipher < 0) {
    +-		wpa_printf(MSG_INFO, "RSN: No acceptable cipher in SMK M2");
    +-		wpa_supplicant_send_smk_error(sm, src_addr, kde.mac_addr,
    +-					      STK_MUI_SMK, STK_ERR_CPHR_NS,
    +-					      ver);
    +-		return -1;
    +-	}
    +-	wpa_printf(MSG_DEBUG, "RSN: Using %s for PeerKey",
    +-		   wpa_cipher_txt(cipher));
    +-
    +-	/* TODO: find existing entry and if found, use that instead of adding
    +-	 * a new one; how to handle the case where both ends initiate at the
    +-	 * same time? */
    +-	peerkey = os_zalloc(sizeof(*peerkey));
    +-	if (peerkey == NULL)
    +-		return -1;
    +-	os_memcpy(peerkey->addr, kde.mac_addr, ETH_ALEN);
    +-	os_memcpy(peerkey->inonce, key->key_nonce, WPA_NONCE_LEN);
    +-	os_memcpy(peerkey->rsnie_i, kde.rsn_ie, kde.rsn_ie_len);
    +-	peerkey->rsnie_i_len = kde.rsn_ie_len;
    +-	peerkey->cipher = cipher;
    +-	peerkey->akmp = ie.key_mgmt;
    +-
    +-	if (random_get_bytes(peerkey->pnonce, WPA_NONCE_LEN)) {
    +-		wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
    +-			"WPA: Failed to get random data for PNonce");
    +-		wpa_supplicant_peerkey_free(sm, peerkey);
    +-		return -1;
    +-	}
    +-
    +-	hdr = (struct rsn_ie_hdr *) peerkey->rsnie_p;
    +-	hdr->elem_id = WLAN_EID_RSN;
    +-	WPA_PUT_LE16(hdr->version, RSN_VERSION);
    +-	pos = (u8 *) (hdr + 1);
    +-	/* Group Suite can be anything for SMK RSN IE; receiver will just
    +-	 * ignore it. */
    +-	RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_CCMP);
    +-	pos += RSN_SELECTOR_LEN;
    +-	/* Include only the selected cipher in pairwise cipher suite */
    +-	WPA_PUT_LE16(pos, 1);
    +-	pos += 2;
    +-	RSN_SELECTOR_PUT(pos, wpa_cipher_to_suite(WPA_PROTO_RSN, cipher));
    +-	pos += RSN_SELECTOR_LEN;
    +-
    +-	hdr->len = (pos - peerkey->rsnie_p) - 2;
    +-	peerkey->rsnie_p_len = pos - peerkey->rsnie_p;
    +-	wpa_hexdump(MSG_DEBUG, "WPA: RSN IE for SMK handshake",
    +-		    peerkey->rsnie_p, peerkey->rsnie_p_len);
    +-
    +-	wpa_supplicant_send_smk_m3(sm, src_addr, key, ver, peerkey);
    +-
    +-	peerkey->next = sm->peerkey;
    +-	sm->peerkey = peerkey;
    +-
    +-	return 0;
    +-}
    +-
    +-
    +-/**
    +- * rsn_smkid - Derive SMK identifier
    +- * @smk: Station master key (32 bytes)
    +- * @pnonce: Peer Nonce
    +- * @mac_p: Peer MAC address
    +- * @inonce: Initiator Nonce
    +- * @mac_i: Initiator MAC address
    +- * @akmp: Negotiated AKM
    +- *
    +- * 8.5.1.4 Station to station (STK) key hierarchy
    +- * SMKID = HMAC-SHA1-128(SMK, "SMK Name" || PNonce || MAC_P || INonce || MAC_I)
    +- */
    +-static void rsn_smkid(const u8 *smk, const u8 *pnonce, const u8 *mac_p,
    +-		      const u8 *inonce, const u8 *mac_i, u8 *smkid,
    +-		      int akmp)
    +-{
    +-	char *title = "SMK Name";
    +-	const u8 *addr[5];
    +-	const size_t len[5] = { 8, WPA_NONCE_LEN, ETH_ALEN, WPA_NONCE_LEN,
    +-				ETH_ALEN };
    +-	unsigned char hash[SHA256_MAC_LEN];
    +-
    +-	addr[0] = (u8 *) title;
    +-	addr[1] = pnonce;
    +-	addr[2] = mac_p;
    +-	addr[3] = inonce;
    +-	addr[4] = mac_i;
    +-
    +-#ifdef CONFIG_IEEE80211W
    +-	if (wpa_key_mgmt_sha256(akmp))
    +-		hmac_sha256_vector(smk, PMK_LEN, 5, addr, len, hash);
    +-	else
    +-#endif /* CONFIG_IEEE80211W */
    +-		hmac_sha1_vector(smk, PMK_LEN, 5, addr, len, hash);
    +-	os_memcpy(smkid, hash, PMKID_LEN);
    +-}
    +-
    +-
    +-static void wpa_supplicant_send_stk_1_of_4(struct wpa_sm *sm,
    +-					   struct wpa_peerkey *peerkey)
    +-{
    +-	size_t mlen;
    +-	struct wpa_eapol_key *msg;
    +-	u8 *mbuf;
    +-	size_t kde_len;
    +-	u16 key_info, ver;
    +-
    +-	kde_len = 2 + RSN_SELECTOR_LEN + PMKID_LEN;
    +-
    +-	mbuf = wpa_sm_alloc_eapol(sm, IEEE802_1X_TYPE_EAPOL_KEY, NULL,
    +-				  sizeof(*msg) + kde_len, &mlen,
    +-				  (void *) &msg);
    +-	if (mbuf == NULL)
    +-		return;
    +-
    +-	msg->type = EAPOL_KEY_TYPE_RSN;
    +-
    +-	if (peerkey->cipher != WPA_CIPHER_TKIP)
    +-		ver = WPA_KEY_INFO_TYPE_HMAC_SHA1_AES;
    +-	else
    +-		ver = WPA_KEY_INFO_TYPE_HMAC_MD5_RC4;
    +-
    +-	key_info = ver | WPA_KEY_INFO_KEY_TYPE | WPA_KEY_INFO_ACK;
    +-	WPA_PUT_BE16(msg->key_info, key_info);
    +-
    +-	if (peerkey->cipher != WPA_CIPHER_TKIP)
    +-		WPA_PUT_BE16(msg->key_length, 16);
    +-	else
    +-		WPA_PUT_BE16(msg->key_length, 32);
    +-
    +-	os_memcpy(msg->replay_counter, peerkey->replay_counter,
    +-		  WPA_REPLAY_COUNTER_LEN);
    +-	inc_byte_array(peerkey->replay_counter, WPA_REPLAY_COUNTER_LEN);
    +-
    +-	WPA_PUT_BE16(msg->key_data_length, kde_len);
    +-	wpa_add_kde((u8 *) (msg + 1), RSN_KEY_DATA_PMKID,
    +-		    peerkey->smkid, PMKID_LEN);
    +-
    +-	if (random_get_bytes(peerkey->inonce, WPA_NONCE_LEN)) {
    +-		wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
    +-			"RSN: Failed to get random data for INonce (STK)");
    +-		os_free(mbuf);
    +-		return;
    +-	}
    +-	wpa_hexdump(MSG_DEBUG, "RSN: INonce for STK 4-Way Handshake",
    +-		    peerkey->inonce, WPA_NONCE_LEN);
    +-	os_memcpy(msg->key_nonce, peerkey->inonce, WPA_NONCE_LEN);
    +-
    +-	wpa_printf(MSG_DEBUG, "RSN: Sending EAPOL-Key STK 1/4 to " MACSTR,
    +-		   MAC2STR(peerkey->addr));
    +-	wpa_eapol_key_send(sm, NULL, 0, ver, peerkey->addr, ETH_P_EAPOL,
    +-			   mbuf, mlen, NULL);
    +-}
    +-
    +-
    +-static void wpa_supplicant_send_stk_3_of_4(struct wpa_sm *sm,
    +-					   struct wpa_peerkey *peerkey)
    +-{
    +-	size_t mlen;
    +-	struct wpa_eapol_key *msg;
    +-	u8 *mbuf, *pos;
    +-	size_t kde_len;
    +-	u16 key_info, ver;
    +-	be32 lifetime;
    +-
    +-	kde_len = peerkey->rsnie_i_len +
    +-		2 + RSN_SELECTOR_LEN + sizeof(lifetime);
    +-
    +-	mbuf = wpa_sm_alloc_eapol(sm, IEEE802_1X_TYPE_EAPOL_KEY, NULL,
    +-				  sizeof(*msg) + kde_len, &mlen,
    +-				  (void *) &msg);
    +-	if (mbuf == NULL)
    +-		return;
    +-
    +-	msg->type = EAPOL_KEY_TYPE_RSN;
    +-
    +-	if (peerkey->cipher != WPA_CIPHER_TKIP)
    +-		ver = WPA_KEY_INFO_TYPE_HMAC_SHA1_AES;
    +-	else
    +-		ver = WPA_KEY_INFO_TYPE_HMAC_MD5_RC4;
    +-
    +-	key_info = ver | WPA_KEY_INFO_KEY_TYPE | WPA_KEY_INFO_ACK |
    +-		WPA_KEY_INFO_MIC | WPA_KEY_INFO_SECURE;
    +-	WPA_PUT_BE16(msg->key_info, key_info);
    +-
    +-	if (peerkey->cipher != WPA_CIPHER_TKIP)
    +-		WPA_PUT_BE16(msg->key_length, 16);
    +-	else
    +-		WPA_PUT_BE16(msg->key_length, 32);
    +-
    +-	os_memcpy(msg->replay_counter, peerkey->replay_counter,
    +-		  WPA_REPLAY_COUNTER_LEN);
    +-	inc_byte_array(peerkey->replay_counter, WPA_REPLAY_COUNTER_LEN);
    +-
    +-	WPA_PUT_BE16(msg->key_data_length, kde_len);
    +-	pos = (u8 *) (msg + 1);
    +-	pos = wpa_add_ie(pos, peerkey->rsnie_i, peerkey->rsnie_i_len);
    +-	lifetime = host_to_be32(peerkey->lifetime);
    +-	wpa_add_kde(pos, RSN_KEY_DATA_LIFETIME,
    +-		    (u8 *) &lifetime, sizeof(lifetime));
    +-
    +-	os_memcpy(msg->key_nonce, peerkey->inonce, WPA_NONCE_LEN);
    +-
    +-	wpa_printf(MSG_DEBUG, "RSN: Sending EAPOL-Key STK 3/4 to " MACSTR,
    +-		   MAC2STR(peerkey->addr));
    +-	wpa_eapol_key_send(sm, peerkey->stk.kck, peerkey->stk.kck_len, ver,
    +-			   peerkey->addr, ETH_P_EAPOL, mbuf, mlen,
    +-			   msg->key_mic);
    +-}
    +-
    +-
    +-static int wpa_supplicant_process_smk_m4(struct wpa_peerkey *peerkey,
    +-					 struct wpa_eapol_ie_parse *kde)
    +-{
    +-	wpa_printf(MSG_DEBUG, "RSN: Received SMK M4 (Initiator " MACSTR ")",
    +-		   MAC2STR(kde->mac_addr));
    +-
    +-	if (os_memcmp(kde->smk + PMK_LEN, peerkey->pnonce, WPA_NONCE_LEN) != 0)
    +-	{
    +-		wpa_printf(MSG_INFO, "RSN: PNonce in SMK KDE does not "
    +-			   "match with the one used in SMK M3");
    +-		return -1;
    +-	}
    +-
    +-	if (os_memcmp(kde->nonce, peerkey->inonce, WPA_NONCE_LEN) != 0) {
    +-		wpa_printf(MSG_INFO, "RSN: INonce in SMK M4 did not "
    +-			   "match with the one received in SMK M2");
    +-		return -1;
    +-	}
    +-
    +-	return 0;
    +-}
    +-
    +-
    +-static int wpa_supplicant_process_smk_m5(struct wpa_sm *sm,
    +-					 const unsigned char *src_addr,
    +-					 const struct wpa_eapol_key *key,
    +-					 int ver,
    +-					 struct wpa_peerkey *peerkey,
    +-					 struct wpa_eapol_ie_parse *kde)
    +-{
    +-	int cipher;
    +-	struct wpa_ie_data ie;
    +-
    +-	wpa_printf(MSG_DEBUG, "RSN: Received SMK M5 (Peer " MACSTR ")",
    +-		   MAC2STR(kde->mac_addr));
    +-	if (kde->rsn_ie == NULL || kde->rsn_ie_len > PEERKEY_MAX_IE_LEN ||
    +-	    wpa_parse_wpa_ie_rsn(kde->rsn_ie, kde->rsn_ie_len, &ie) < 0) {
    +-		wpa_printf(MSG_INFO, "RSN: No RSN IE in SMK M5");
    +-		/* TODO: abort negotiation */
    +-		return -1;
    +-	}
    +-
    +-	if (os_memcmp(key->key_nonce, peerkey->inonce, WPA_NONCE_LEN) != 0) {
    +-		wpa_printf(MSG_INFO, "RSN: Key Nonce in SMK M5 does "
    +-			   "not match with INonce used in SMK M1");
    +-		return -1;
    +-	}
    +-
    +-	if (os_memcmp(kde->smk + PMK_LEN, peerkey->inonce, WPA_NONCE_LEN) != 0)
    +-	{
    +-		wpa_printf(MSG_INFO, "RSN: INonce in SMK KDE does not "
    +-			   "match with the one used in SMK M1");
    +-		return -1;
    +-	}
    +-
    +-	os_memcpy(peerkey->rsnie_p, kde->rsn_ie, kde->rsn_ie_len);
    +-	peerkey->rsnie_p_len = kde->rsn_ie_len;
    +-	os_memcpy(peerkey->pnonce, kde->nonce, WPA_NONCE_LEN);
    +-
    +-	cipher = wpa_pick_pairwise_cipher(ie.pairwise_cipher &
    +-					  sm->allowed_pairwise_cipher, 0);
    +-	if (cipher < 0) {
    +-		wpa_printf(MSG_INFO, "RSN: SMK Peer STA " MACSTR " selected "
    +-			   "unacceptable cipher", MAC2STR(kde->mac_addr));
    +-		wpa_supplicant_send_smk_error(sm, src_addr, kde->mac_addr,
    +-					      STK_MUI_SMK, STK_ERR_CPHR_NS,
    +-					      ver);
    +-		/* TODO: abort negotiation */
    +-		return -1;
    +-	}
    +-	wpa_printf(MSG_DEBUG, "RSN: Using %s for PeerKey",
    +-		   wpa_cipher_txt(cipher));
    +-	peerkey->cipher = cipher;
    +-
    +-	return 0;
    +-}
    +-
    +-
    +-static int wpa_supplicant_process_smk_m45(
    +-	struct wpa_sm *sm, const unsigned char *src_addr,
    +-	const struct wpa_eapol_key *key, size_t extra_len, int ver)
    +-{
    +-	struct wpa_peerkey *peerkey;
    +-	struct wpa_eapol_ie_parse kde;
    +-	u32 lifetime;
    +-
    +-	if (!sm->peerkey_enabled || sm->proto != WPA_PROTO_RSN) {
    +-		wpa_printf(MSG_DEBUG, "RSN: SMK handshake not allowed for "
    +-			   "the current network");
    +-		return -1;
    +-	}
    +-
    +-	if (wpa_supplicant_parse_ies((const u8 *) (key + 1), extra_len, &kde) <
    +-	    0) {
    +-		wpa_printf(MSG_INFO, "RSN: Failed to parse KDEs in SMK M4/M5");
    +-		return -1;
    +-	}
    +-
    +-	if (kde.mac_addr == NULL || kde.mac_addr_len < ETH_ALEN ||
    +-	    kde.nonce == NULL || kde.nonce_len < WPA_NONCE_LEN ||
    +-	    kde.smk == NULL || kde.smk_len < PMK_LEN + WPA_NONCE_LEN ||
    +-	    kde.lifetime == NULL || kde.lifetime_len < 4) {
    +-		wpa_printf(MSG_INFO, "RSN: No MAC Address, Nonce, SMK, or "
    +-			   "Lifetime KDE in SMK M4/M5");
    +-		return -1;
    +-	}
    +-
    +-	for (peerkey = sm->peerkey; peerkey; peerkey = peerkey->next) {
    +-		if (os_memcmp(peerkey->addr, kde.mac_addr, ETH_ALEN) == 0 &&
    +-		    os_memcmp(peerkey->initiator ? peerkey->inonce :
    +-			   peerkey->pnonce,
    +-			   key->key_nonce, WPA_NONCE_LEN) == 0)
    +-			break;
    +-	}
    +-	if (peerkey == NULL) {
    +-		wpa_printf(MSG_INFO, "RSN: No matching SMK handshake found "
    +-			   "for SMK M4/M5: peer " MACSTR,
    +-			   MAC2STR(kde.mac_addr));
    +-		return -1;
    +-	}
    +-
    +-	if (peerkey->initiator) {
    +-		if (wpa_supplicant_process_smk_m5(sm, src_addr, key, ver,
    +-						  peerkey, &kde) < 0)
    +-			return -1;
    +-	} else {
    +-		if (wpa_supplicant_process_smk_m4(peerkey, &kde) < 0)
    +-			return -1;
    +-	}
    +-
    +-	os_memcpy(peerkey->smk, kde.smk, PMK_LEN);
    +-	peerkey->smk_complete = 1;
    +-	wpa_hexdump_key(MSG_DEBUG, "RSN: SMK", peerkey->smk, PMK_LEN);
    +-	lifetime = WPA_GET_BE32(kde.lifetime);
    +-	wpa_printf(MSG_DEBUG, "RSN: SMK lifetime %u seconds", lifetime);
    +-	if (lifetime > 1000000000)
    +-		lifetime = 1000000000; /* avoid overflowing eloop time */
    +-	peerkey->lifetime = lifetime;
    +-	eloop_register_timeout(lifetime, 0, wpa_supplicant_smk_timeout,
    +-			       sm, peerkey);
    +-
    +-	if (peerkey->initiator) {
    +-		rsn_smkid(peerkey->smk, peerkey->pnonce, peerkey->addr,
    +-			  peerkey->inonce, sm->own_addr, peerkey->smkid,
    +-			  peerkey->akmp);
    +-		wpa_supplicant_send_stk_1_of_4(sm, peerkey);
    +-	} else {
    +-		rsn_smkid(peerkey->smk, peerkey->pnonce, sm->own_addr,
    +-			  peerkey->inonce, peerkey->addr, peerkey->smkid,
    +-			  peerkey->akmp);
    +-	}
    +-	wpa_hexdump(MSG_DEBUG, "RSN: SMKID", peerkey->smkid, PMKID_LEN);
    +-
    +-	return 0;
    +-}
    +-
    +-
    +-static int wpa_supplicant_process_smk_error(
    +-	struct wpa_sm *sm, const unsigned char *src_addr,
    +-	const struct wpa_eapol_key *key, size_t extra_len)
    +-{
    +-	struct wpa_eapol_ie_parse kde;
    +-	struct rsn_error_kde error;
    +-	u8 peer[ETH_ALEN];
    +-	u16 error_type;
    +-
    +-	wpa_printf(MSG_DEBUG, "RSN: Received SMK Error");
    +-
    +-	if (!sm->peerkey_enabled || sm->proto != WPA_PROTO_RSN) {
    +-		wpa_printf(MSG_DEBUG, "RSN: SMK handshake not allowed for "
    +-			   "the current network");
    +-		return -1;
    +-	}
    +-
    +-	if (wpa_supplicant_parse_ies((const u8 *) (key + 1), extra_len, &kde) <
    +-	    0) {
    +-		wpa_printf(MSG_INFO, "RSN: Failed to parse KDEs in SMK Error");
    +-		return -1;
    +-	}
    +-
    +-	if (kde.error == NULL || kde.error_len < sizeof(error)) {
    +-		wpa_printf(MSG_INFO, "RSN: No Error KDE in SMK Error");
    +-		return -1;
    +-	}
    +-
    +-	if (kde.mac_addr && kde.mac_addr_len >= ETH_ALEN)
    +-		os_memcpy(peer, kde.mac_addr, ETH_ALEN);
    +-	else
    +-		os_memset(peer, 0, ETH_ALEN);
    +-	os_memcpy(&error, kde.error, sizeof(error));
    +-	error_type = be_to_host16(error.error_type);
    +-	wpa_msg(sm->ctx->msg_ctx, MSG_INFO,
    +-		"RSN: SMK Error KDE received: MUI %d error_type %d peer "
    +-		MACSTR,
    +-		be_to_host16(error.mui), error_type,
    +-		MAC2STR(peer));
    +-
    +-	if (kde.mac_addr &&
    +-	    (error_type == STK_ERR_STA_NR || error_type == STK_ERR_STA_NRSN ||
    +-	     error_type == STK_ERR_CPHR_NS)) {
    +-		struct wpa_peerkey *peerkey;
    +-
    +-		for (peerkey = sm->peerkey; peerkey; peerkey = peerkey->next) {
    +-			if (os_memcmp(peerkey->addr, kde.mac_addr, ETH_ALEN) ==
    +-			    0)
    +-				break;
    +-		}
    +-		if (peerkey == NULL) {
    +-			wpa_printf(MSG_DEBUG, "RSN: No matching SMK handshake "
    +-				   "found for SMK Error");
    +-			return -1;
    +-		}
    +-		/* TODO: abort SMK/STK handshake and remove all related keys */
    +-	}
    +-
    +-	return 0;
    +-}
    +-
    +-
    +-static void wpa_supplicant_process_stk_1_of_4(struct wpa_sm *sm,
    +-					      struct wpa_peerkey *peerkey,
    +-					      const struct wpa_eapol_key *key,
    +-					      u16 ver, const u8 *key_data,
    +-					      size_t key_data_len)
    +-{
    +-	struct wpa_eapol_ie_parse ie;
    +-	size_t kde_buf_len;
    +-	struct wpa_ptk *stk;
    +-	u8 buf[8], *kde_buf, *pos;
    +-	be32 lifetime;
    +-
    +-	wpa_printf(MSG_DEBUG, "RSN: RX message 1 of STK 4-Way Handshake from "
    +-		   MACSTR " (ver=%d)", MAC2STR(peerkey->addr), ver);
    +-
    +-	os_memset(&ie, 0, sizeof(ie));
    +-
    +-	/* RSN: msg 1/4 should contain SMKID for the selected SMK */
    +-	wpa_hexdump(MSG_DEBUG, "RSN: msg 1/4 key data", key_data, key_data_len);
    +-	if (wpa_supplicant_parse_ies(key_data, key_data_len, &ie) < 0 ||
    +-	    ie.pmkid == NULL) {
    +-		wpa_printf(MSG_DEBUG, "RSN: No SMKID in STK 1/4");
    +-		return;
    +-	}
    +-	if (os_memcmp_const(ie.pmkid, peerkey->smkid, PMKID_LEN) != 0) {
    +-		wpa_hexdump(MSG_DEBUG, "RSN: Unknown SMKID in STK 1/4",
    +-			    ie.pmkid, PMKID_LEN);
    +-		return;
    +-	}
    +-
    +-	if (random_get_bytes(peerkey->pnonce, WPA_NONCE_LEN)) {
    +-		wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
    +-			"RSN: Failed to get random data for PNonce");
    +-		return;
    +-	}
    +-	wpa_hexdump(MSG_DEBUG, "WPA: Renewed PNonce",
    +-		    peerkey->pnonce, WPA_NONCE_LEN);
    +-
    +-	/* Calculate STK which will be stored as a temporary STK until it has
    +-	 * been verified when processing message 3/4. */
    +-	stk = &peerkey->tstk;
    +-	wpa_pmk_to_ptk(peerkey->smk, PMK_LEN, "Peer key expansion",
    +-		       sm->own_addr, peerkey->addr,
    +-		       peerkey->pnonce, key->key_nonce,
    +-		       stk, peerkey->akmp, peerkey->cipher);
    +-	/* Supplicant: swap tx/rx Mic keys */
    +-	os_memcpy(buf, &stk->tk[16], 8);
    +-	os_memcpy(&stk->tk[16], &stk->tk[24], 8);
    +-	os_memcpy(&stk->tk[24], buf, 8);
    +-	peerkey->tstk_set = 1;
    +-
    +-	kde_buf_len = peerkey->rsnie_p_len +
    +-		2 + RSN_SELECTOR_LEN + sizeof(lifetime) +
    +-		2 + RSN_SELECTOR_LEN + PMKID_LEN;
    +-	kde_buf = os_malloc(kde_buf_len);
    +-	if (kde_buf == NULL)
    +-		return;
    +-	pos = kde_buf;
    +-	pos = wpa_add_ie(pos, peerkey->rsnie_p, peerkey->rsnie_p_len);
    +-	lifetime = host_to_be32(peerkey->lifetime);
    +-	pos = wpa_add_kde(pos, RSN_KEY_DATA_LIFETIME,
    +-			  (u8 *) &lifetime, sizeof(lifetime));
    +-	wpa_add_kde(pos, RSN_KEY_DATA_PMKID, peerkey->smkid, PMKID_LEN);
    +-
    +-	if (wpa_supplicant_send_2_of_4(sm, peerkey->addr, key, ver,
    +-				       peerkey->pnonce, kde_buf, kde_buf_len,
    +-				       stk)) {
    +-		os_free(kde_buf);
    +-		return;
    +-	}
    +-	os_free(kde_buf);
    +-
    +-	os_memcpy(peerkey->inonce, key->key_nonce, WPA_NONCE_LEN);
    +-}
    +-
    +-
    +-static void wpa_supplicant_update_smk_lifetime(struct wpa_sm *sm,
    +-					       struct wpa_peerkey *peerkey,
    +-					       struct wpa_eapol_ie_parse *kde)
    +-{
    +-	u32 lifetime;
    +-
    +-	if (kde->lifetime == NULL || kde->lifetime_len < sizeof(lifetime))
    +-		return;
    +-
    +-	lifetime = WPA_GET_BE32(kde->lifetime);
    +-
    +-	if (lifetime >= peerkey->lifetime) {
    +-		wpa_printf(MSG_DEBUG, "RSN: Peer used SMK lifetime %u seconds "
    +-			   "which is larger than or equal to own value %u "
    +-			   "seconds - ignored", lifetime, peerkey->lifetime);
    +-		return;
    +-	}
    +-
    +-	wpa_printf(MSG_DEBUG, "RSN: Peer used shorter SMK lifetime %u seconds "
    +-		   "(own was %u seconds) - updated",
    +-		   lifetime, peerkey->lifetime);
    +-	peerkey->lifetime = lifetime;
    +-
    +-	eloop_cancel_timeout(wpa_supplicant_smk_timeout, sm, peerkey);
    +-	eloop_register_timeout(lifetime, 0, wpa_supplicant_smk_timeout,
    +-			       sm, peerkey);
    +-}
    +-
    +-
    +-static void wpa_supplicant_process_stk_2_of_4(struct wpa_sm *sm,
    +-					      struct wpa_peerkey *peerkey,
    +-					      const struct wpa_eapol_key *key,
    +-					      u16 ver, const u8 *key_data,
    +-					      size_t key_data_len)
    +-{
    +-	struct wpa_eapol_ie_parse kde;
    +-
    +-	wpa_printf(MSG_DEBUG, "RSN: RX message 2 of STK 4-Way Handshake from "
    +-		   MACSTR " (ver=%d)", MAC2STR(peerkey->addr), ver);
    +-
    +-	os_memset(&kde, 0, sizeof(kde));
    +-
    +-	/* RSN: msg 2/4 should contain SMKID for the selected SMK and RSN IE
    +-	 * from the peer. It may also include Lifetime KDE. */
    +-	wpa_hexdump(MSG_DEBUG, "RSN: msg 2/4 key data", key_data, key_data_len);
    +-	if (wpa_supplicant_parse_ies(key_data, key_data_len, &kde) < 0 ||
    +-	    kde.pmkid == NULL || kde.rsn_ie == NULL) {
    +-		wpa_printf(MSG_DEBUG, "RSN: No SMKID or RSN IE in STK 2/4");
    +-		return;
    +-	}
    +-
    +-	if (os_memcmp_const(kde.pmkid, peerkey->smkid, PMKID_LEN) != 0) {
    +-		wpa_hexdump(MSG_DEBUG, "RSN: Unknown SMKID in STK 2/4",
    +-			    kde.pmkid, PMKID_LEN);
    +-		return;
    +-	}
    +-
    +-	if (kde.rsn_ie_len != peerkey->rsnie_p_len ||
    +-	    os_memcmp(kde.rsn_ie, peerkey->rsnie_p, kde.rsn_ie_len) != 0) {
    +-		wpa_printf(MSG_INFO, "RSN: Peer RSN IE in SMK and STK "
    +-			   "handshakes did not match");
    +-		wpa_hexdump(MSG_DEBUG, "RSN: Peer RSN IE in SMK handshake",
    +-			    peerkey->rsnie_p, peerkey->rsnie_p_len);
    +-		wpa_hexdump(MSG_DEBUG, "RSN: Peer RSN IE in STK handshake",
    +-			    kde.rsn_ie, kde.rsn_ie_len);
    +-		return;
    +-	}
    +-
    +-	wpa_supplicant_update_smk_lifetime(sm, peerkey, &kde);
    +-
    +-	wpa_supplicant_send_stk_3_of_4(sm, peerkey);
    +-	os_memcpy(peerkey->pnonce, key->key_nonce, WPA_NONCE_LEN);
    +-}
    +-
    +-
    +-static void wpa_supplicant_process_stk_3_of_4(struct wpa_sm *sm,
    +-					      struct wpa_peerkey *peerkey,
    +-					      const struct wpa_eapol_key *key,
    +-					      u16 ver, const u8 *key_data,
    +-					      size_t key_data_len)
    +-{
    +-	struct wpa_eapol_ie_parse kde;
    +-	size_t key_len;
    +-	const u8 *_key;
    +-	u8 key_buf[32], rsc[6];
    +-
    +-	wpa_printf(MSG_DEBUG, "RSN: RX message 3 of STK 4-Way Handshake from "
    +-		   MACSTR " (ver=%d)", MAC2STR(peerkey->addr), ver);
    +-
    +-	os_memset(&kde, 0, sizeof(kde));
    +-
    +-	/* RSN: msg 3/4 should contain Initiator RSN IE. It may also include
    +-	 * Lifetime KDE. */
    +-	wpa_hexdump(MSG_DEBUG, "RSN: msg 3/4 key data", key_data, key_data_len);
    +-	if (wpa_supplicant_parse_ies(key_data, key_data_len, &kde) < 0) {
    +-		wpa_printf(MSG_DEBUG, "RSN: Failed to parse key data in "
    +-			   "STK 3/4");
    +-		return;
    +-	}
    +-
    +-	if (kde.rsn_ie_len != peerkey->rsnie_i_len ||
    +-	    os_memcmp(kde.rsn_ie, peerkey->rsnie_i, kde.rsn_ie_len) != 0) {
    +-		wpa_printf(MSG_INFO, "RSN: Initiator RSN IE in SMK and STK "
    +-			   "handshakes did not match");
    +-		wpa_hexdump(MSG_DEBUG, "RSN: Initiator RSN IE in SMK "
    +-			    "handshake",
    +-			    peerkey->rsnie_i, peerkey->rsnie_i_len);
    +-		wpa_hexdump(MSG_DEBUG, "RSN: Initiator RSN IE in STK "
    +-			    "handshake",
    +-			    kde.rsn_ie, kde.rsn_ie_len);
    +-		return;
    +-	}
    +-
    +-	if (os_memcmp(peerkey->inonce, key->key_nonce, WPA_NONCE_LEN) != 0) {
    +-		wpa_printf(MSG_WARNING, "RSN: INonce from message 1 of STK "
    +-			   "4-Way Handshake differs from 3 of STK 4-Way "
    +-			   "Handshake - drop packet (src=" MACSTR ")",
    +-			   MAC2STR(peerkey->addr));
    +-		return;
    +-	}
    +-
    +-	wpa_supplicant_update_smk_lifetime(sm, peerkey, &kde);
    +-
    +-	if (wpa_supplicant_send_4_of_4(sm, peerkey->addr, key, ver,
    +-				       WPA_GET_BE16(key->key_info),
    +-				       &peerkey->stk))
    +-		return;
    +-
    +-	_key = peerkey->stk.tk;
    +-	if (peerkey->cipher == WPA_CIPHER_TKIP) {
    +-		/* Swap Tx/Rx keys for Michael MIC */
    +-		os_memcpy(key_buf, _key, 16);
    +-		os_memcpy(key_buf + 16, _key + 24, 8);
    +-		os_memcpy(key_buf + 24, _key + 16, 8);
    +-		_key = key_buf;
    +-		key_len = 32;
    +-	} else
    +-		key_len = 16;
    +-
    +-	os_memset(rsc, 0, 6);
    +-	if (wpa_sm_set_key(sm, peerkey->cipher, peerkey->addr, 0, 1,
    +-			   rsc, sizeof(rsc), _key, key_len) < 0) {
    +-		os_memset(key_buf, 0, sizeof(key_buf));
    +-		wpa_printf(MSG_WARNING, "RSN: Failed to set STK to the "
    +-			   "driver.");
    +-		return;
    +-	}
    +-	os_memset(key_buf, 0, sizeof(key_buf));
    +-}
    +-
    +-
    +-static void wpa_supplicant_process_stk_4_of_4(struct wpa_sm *sm,
    +-					      struct wpa_peerkey *peerkey,
    +-					      const struct wpa_eapol_key *key,
    +-					      u16 ver)
    +-{
    +-	u8 rsc[6];
    +-
    +-	wpa_printf(MSG_DEBUG, "RSN: RX message 4 of STK 4-Way Handshake from "
    +-		   MACSTR " (ver=%d)", MAC2STR(peerkey->addr), ver);
    +-
    +-	os_memset(rsc, 0, 6);
    +-	if (wpa_sm_set_key(sm, peerkey->cipher, peerkey->addr, 0, 1,
    +-			   rsc, sizeof(rsc), peerkey->stk.tk,
    +-			   peerkey->cipher == WPA_CIPHER_TKIP ? 32 : 16) < 0) {
    +-		wpa_printf(MSG_WARNING, "RSN: Failed to set STK to the "
    +-			   "driver.");
    +-		return;
    +-	}
    +-}
    +-
    +-
    +-/**
    +- * peerkey_verify_eapol_key_mic - Verify PeerKey MIC
    +- * @sm: Pointer to WPA state machine data from wpa_sm_init()
    +- * @peerkey: Pointer to the PeerKey data for the peer
    +- * @key: Pointer to the EAPOL-Key frame header
    +- * @ver: Version bits from EAPOL-Key Key Info
    +- * @buf: Pointer to the beginning of EAPOL-Key frame
    +- * @len: Length of the EAPOL-Key frame
    +- * Returns: 0 on success, -1 on failure
    +- */
    +-int peerkey_verify_eapol_key_mic(struct wpa_sm *sm,
    +-				 struct wpa_peerkey *peerkey,
    +-				 struct wpa_eapol_key_192 *key, u16 ver,
    +-				 const u8 *buf, size_t len)
    +-{
    +-	u8 mic[WPA_EAPOL_KEY_MIC_MAX_LEN];
    +-	size_t mic_len = 16;
    +-	int ok = 0;
    +-
    +-	if (peerkey->initiator && !peerkey->stk_set) {
    +-		wpa_pmk_to_ptk(peerkey->smk, PMK_LEN, "Peer key expansion",
    +-			       sm->own_addr, peerkey->addr,
    +-			       peerkey->inonce, key->key_nonce,
    +-			       &peerkey->stk, peerkey->akmp, peerkey->cipher);
    +-		peerkey->stk_set = 1;
    +-	}
    +-
    +-	os_memcpy(mic, key->key_mic, mic_len);
    +-	if (peerkey->tstk_set) {
    +-		os_memset(key->key_mic, 0, mic_len);
    +-		wpa_eapol_key_mic(peerkey->tstk.kck, peerkey->tstk.kck_len,
    +-				  sm->key_mgmt, ver, buf, len, key->key_mic);
    +-		if (os_memcmp_const(mic, key->key_mic, mic_len) != 0) {
    +-			wpa_printf(MSG_WARNING, "RSN: Invalid EAPOL-Key MIC "
    +-				   "when using TSTK - ignoring TSTK");
    +-		} else {
    +-			ok = 1;
    +-			peerkey->tstk_set = 0;
    +-			peerkey->stk_set = 1;
    +-			os_memcpy(&peerkey->stk, &peerkey->tstk,
    +-				  sizeof(peerkey->stk));
    +-			os_memset(&peerkey->tstk, 0, sizeof(peerkey->tstk));
    +-		}
    +-	}
    +-
    +-	if (!ok && peerkey->stk_set) {
    +-		os_memset(key->key_mic, 0, mic_len);
    +-		wpa_eapol_key_mic(peerkey->stk.kck, peerkey->stk.kck_len,
    +-				  sm->key_mgmt, ver, buf, len, key->key_mic);
    +-		if (os_memcmp_const(mic, key->key_mic, mic_len) != 0) {
    +-			wpa_printf(MSG_WARNING, "RSN: Invalid EAPOL-Key MIC "
    +-				   "- dropping packet");
    +-			return -1;
    +-		}
    +-		ok = 1;
    +-	}
    +-
    +-	if (!ok) {
    +-		wpa_printf(MSG_WARNING, "RSN: Could not verify EAPOL-Key MIC "
    +-			   "- dropping packet");
    +-		return -1;
    +-	}
    +-
    +-	os_memcpy(peerkey->replay_counter, key->replay_counter,
    +-		  WPA_REPLAY_COUNTER_LEN);
    +-	peerkey->replay_counter_set = 1;
    +-	return 0;
    +-}
    +-
    +-
    +-/**
    +- * wpa_sm_stkstart - Send EAPOL-Key Request for STK handshake (STK M1)
    +- * @sm: Pointer to WPA state machine data from wpa_sm_init()
    +- * @peer: MAC address of the peer STA
    +- * Returns: 0 on success, or -1 on failure
    +- *
    +- * Send an EAPOL-Key Request to the current authenticator to start STK
    +- * handshake with the peer.
    +- */
    +-int wpa_sm_stkstart(struct wpa_sm *sm, const u8 *peer)
    +-{
    +-	size_t rlen, kde_len;
    +-	struct wpa_eapol_key *req;
    +-	int key_info, ver;
    +-	u8 bssid[ETH_ALEN], *rbuf, *pos, *count_pos;
    +-	u16 count;
    +-	struct rsn_ie_hdr *hdr;
    +-	struct wpa_peerkey *peerkey;
    +-	struct wpa_ie_data ie;
    +-
    +-	if (sm->proto != WPA_PROTO_RSN || !sm->ptk_set || !sm->peerkey_enabled)
    +-		return -1;
    +-
    +-	if (sm->ap_rsn_ie &&
    +-	    wpa_parse_wpa_ie_rsn(sm->ap_rsn_ie, sm->ap_rsn_ie_len, &ie) == 0 &&
    +-	    !(ie.capabilities & WPA_CAPABILITY_PEERKEY_ENABLED)) {
    +-		wpa_printf(MSG_DEBUG, "RSN: Current AP does not support STK");
    +-		return -1;
    +-	}
    +-
    +-	if (sm->pairwise_cipher != WPA_CIPHER_TKIP)
    +-		ver = WPA_KEY_INFO_TYPE_HMAC_SHA1_AES;
    +-	else
    +-		ver = WPA_KEY_INFO_TYPE_HMAC_MD5_RC4;
    +-
    +-	if (wpa_sm_get_bssid(sm, bssid) < 0) {
    +-		wpa_printf(MSG_WARNING, "Failed to read BSSID for EAPOL-Key "
    +-			   "SMK M1");
    +-		return -1;
    +-	}
    +-
    +-	/* TODO: find existing entry and if found, use that instead of adding
    +-	 * a new one */
    +-	peerkey = os_zalloc(sizeof(*peerkey));
    +-	if (peerkey == NULL)
    +-		return -1;
    +-	peerkey->initiator = 1;
    +-	os_memcpy(peerkey->addr, peer, ETH_ALEN);
    +-	peerkey->akmp = sm->key_mgmt;
    +-
    +-	/* SMK M1:
    +-	 * EAPOL-Key(S=1, M=1, A=0, I=0, K=0, SM=1, KeyRSC=0, Nonce=INonce,
    +-	 *           MIC=MIC, DataKDs=(RSNIE_I, MAC_P KDE))
    +-	 */
    +-
    +-	hdr = (struct rsn_ie_hdr *) peerkey->rsnie_i;
    +-	hdr->elem_id = WLAN_EID_RSN;
    +-	WPA_PUT_LE16(hdr->version, RSN_VERSION);
    +-	pos = (u8 *) (hdr + 1);
    +-	/* Group Suite can be anything for SMK RSN IE; receiver will just
    +-	 * ignore it. */
    +-	RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_CCMP);
    +-	pos += RSN_SELECTOR_LEN;
    +-	count_pos = pos;
    +-	pos += 2;
    +-
    +-	count = rsn_cipher_put_suites(pos, sm->allowed_pairwise_cipher);
    +-	pos += count * RSN_SELECTOR_LEN;
    +-	WPA_PUT_LE16(count_pos, count);
    +-
    +-	hdr->len = (pos - peerkey->rsnie_i) - 2;
    +-	peerkey->rsnie_i_len = pos - peerkey->rsnie_i;
    +-	wpa_hexdump(MSG_DEBUG, "WPA: RSN IE for SMK handshake",
    +-		    peerkey->rsnie_i, peerkey->rsnie_i_len);
    +-
    +-	kde_len = peerkey->rsnie_i_len + 2 + RSN_SELECTOR_LEN + ETH_ALEN;
    +-
    +-	rbuf = wpa_sm_alloc_eapol(sm, IEEE802_1X_TYPE_EAPOL_KEY, NULL,
    +-				  sizeof(*req) + kde_len, &rlen,
    +-				  (void *) &req);
    +-	if (rbuf == NULL) {
    +-		wpa_supplicant_peerkey_free(sm, peerkey);
    +-		return -1;
    +-	}
    +-
    +-	req->type = EAPOL_KEY_TYPE_RSN;
    +-	key_info = WPA_KEY_INFO_SMK_MESSAGE | WPA_KEY_INFO_MIC |
    +-		WPA_KEY_INFO_SECURE | WPA_KEY_INFO_REQUEST | ver;
    +-	WPA_PUT_BE16(req->key_info, key_info);
    +-	WPA_PUT_BE16(req->key_length, 0);
    +-	os_memcpy(req->replay_counter, sm->request_counter,
    +-		  WPA_REPLAY_COUNTER_LEN);
    +-	inc_byte_array(sm->request_counter, WPA_REPLAY_COUNTER_LEN);
    +-
    +-	if (random_get_bytes(peerkey->inonce, WPA_NONCE_LEN)) {
    +-		wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
    +-			"WPA: Failed to get random data for INonce");
    +-		os_free(rbuf);
    +-		wpa_supplicant_peerkey_free(sm, peerkey);
    +-		return -1;
    +-	}
    +-	os_memcpy(req->key_nonce, peerkey->inonce, WPA_NONCE_LEN);
    +-	wpa_hexdump(MSG_DEBUG, "WPA: INonce for SMK handshake",
    +-		    req->key_nonce, WPA_NONCE_LEN);
    +-
    +-	WPA_PUT_BE16(req->key_data_length, (u16) kde_len);
    +-	pos = (u8 *) (req + 1);
    +-
    +-	/* Initiator RSN IE */
    +-	pos = wpa_add_ie(pos, peerkey->rsnie_i, peerkey->rsnie_i_len);
    +-	/* Peer MAC address KDE */
    +-	wpa_add_kde(pos, RSN_KEY_DATA_MAC_ADDR, peer, ETH_ALEN);
    +-
    +-	wpa_printf(MSG_INFO, "RSN: Sending EAPOL-Key SMK M1 Request (peer "
    +-		   MACSTR ")", MAC2STR(peer));
    +-	wpa_eapol_key_send(sm, sm->ptk.kck, sm->ptk.kck_len, ver, bssid,
    +-			   ETH_P_EAPOL, rbuf, rlen, req->key_mic);
    +-
    +-	peerkey->next = sm->peerkey;
    +-	sm->peerkey = peerkey;
    +-
    +-	return 0;
    +-}
    +-
    +-
    +-/**
    +- * peerkey_deinit - Free PeerKey values
    +- * @sm: Pointer to WPA state machine data from wpa_sm_init()
    +- */
    +-void peerkey_deinit(struct wpa_sm *sm)
    +-{
    +-	struct wpa_peerkey *prev, *peerkey = sm->peerkey;
    +-	while (peerkey) {
    +-		prev = peerkey;
    +-		peerkey = peerkey->next;
    +-		wpa_supplicant_peerkey_free(sm, prev);
    +-	}
    +-	sm->peerkey = NULL;
    +-}
    +-
    +-
    +-void peerkey_rx_eapol_4way(struct wpa_sm *sm, struct wpa_peerkey *peerkey,
    +-			   struct wpa_eapol_key *key, u16 key_info, u16 ver,
    +-			   const u8 *key_data, size_t key_data_len)
    +-{
    +-	if ((key_info & (WPA_KEY_INFO_MIC | WPA_KEY_INFO_ACK)) ==
    +-	    (WPA_KEY_INFO_MIC | WPA_KEY_INFO_ACK)) {
    +-		/* 3/4 STK 4-Way Handshake */
    +-		wpa_supplicant_process_stk_3_of_4(sm, peerkey, key, ver,
    +-						  key_data, key_data_len);
    +-	} else if (key_info & WPA_KEY_INFO_ACK) {
    +-		/* 1/4 STK 4-Way Handshake */
    +-		wpa_supplicant_process_stk_1_of_4(sm, peerkey, key, ver,
    +-						  key_data, key_data_len);
    +-	} else if (key_info & WPA_KEY_INFO_SECURE) {
    +-		/* 4/4 STK 4-Way Handshake */
    +-		wpa_supplicant_process_stk_4_of_4(sm, peerkey, key, ver);
    +-	} else {
    +-		/* 2/4 STK 4-Way Handshake */
    +-		wpa_supplicant_process_stk_2_of_4(sm, peerkey, key, ver,
    +-						  key_data, key_data_len);
    +-	}
    +-}
    +-
    +-
    +-void peerkey_rx_eapol_smk(struct wpa_sm *sm, const u8 *src_addr,
    +-			  struct wpa_eapol_key *key, size_t extra_len,
    +-			  u16 key_info, u16 ver)
    +-{
    +-	if (key_info & WPA_KEY_INFO_ERROR) {
    +-		/* SMK Error */
    +-		wpa_supplicant_process_smk_error(sm, src_addr, key, extra_len);
    +-	} else if (key_info & WPA_KEY_INFO_ACK) {
    +-		/* SMK M2 */
    +-		wpa_supplicant_process_smk_m2(sm, src_addr, key, extra_len,
    +-					      ver);
    +-	} else {
    +-		/* SMK M4 or M5 */
    +-		wpa_supplicant_process_smk_m45(sm, src_addr, key, extra_len,
    +-					       ver);
    +-	}
    +-}
    +-
    +-#endif /* CONFIG_PEERKEY */
    +diff --git a/src/rsn_supp/peerkey.h b/src/rsn_supp/peerkey.h
    +deleted file mode 100644
    +index 6ccd948..0000000
    +--- a/src/rsn_supp/peerkey.h
    ++++ /dev/null
    +@@ -1,82 +0,0 @@
    +-/*
    +- * WPA Supplicant - PeerKey for Direct Link Setup (DLS)
    +- * Copyright (c) 2006-2015, Jouni Malinen <j@w1.fi>
    +- *
    +- * This software may be distributed under the terms of the BSD license.
    +- * See README for more details.
    +- */
    +-
    +-#ifndef PEERKEY_H
    +-#define PEERKEY_H
    +-
    +-#define PEERKEY_MAX_IE_LEN 80
    +-struct wpa_peerkey {
    +-	struct wpa_peerkey *next;
    +-	int initiator; /* whether this end was initator for SMK handshake */
    +-	u8 addr[ETH_ALEN]; /* other end MAC address */
    +-	u8 inonce[WPA_NONCE_LEN]; /* Initiator Nonce */
    +-	u8 pnonce[WPA_NONCE_LEN]; /* Peer Nonce */
    +-	u8 rsnie_i[PEERKEY_MAX_IE_LEN]; /* Initiator RSN IE */
    +-	size_t rsnie_i_len;
    +-	u8 rsnie_p[PEERKEY_MAX_IE_LEN]; /* Peer RSN IE */
    +-	size_t rsnie_p_len;
    +-	u8 smk[PMK_LEN];
    +-	int smk_complete;
    +-	u8 smkid[PMKID_LEN];
    +-	u32 lifetime;
    +-	int cipher; /* Selected cipher (WPA_CIPHER_*) */
    +-	u8 replay_counter[WPA_REPLAY_COUNTER_LEN];
    +-	int replay_counter_set;
    +-	int akmp;
    +-
    +-	struct wpa_ptk stk, tstk;
    +-	int stk_set, tstk_set;
    +-};
    +-
    +-
    +-#ifdef CONFIG_PEERKEY
    +-
    +-int peerkey_verify_eapol_key_mic(struct wpa_sm *sm,
    +-				 struct wpa_peerkey *peerkey,
    +-				 struct wpa_eapol_key_192 *key, u16 ver,
    +-				 const u8 *buf, size_t len);
    +-void peerkey_rx_eapol_4way(struct wpa_sm *sm, struct wpa_peerkey *peerkey,
    +-			   struct wpa_eapol_key *key, u16 key_info, u16 ver,
    +-			   const u8 *key_data, size_t key_data_len);
    +-void peerkey_rx_eapol_smk(struct wpa_sm *sm, const u8 *src_addr,
    +-			  struct wpa_eapol_key *key, size_t extra_len,
    +-			  u16 key_info, u16 ver);
    +-void peerkey_deinit(struct wpa_sm *sm);
    +-
    +-#else /* CONFIG_PEERKEY */
    +-
    +-static inline int
    +-peerkey_verify_eapol_key_mic(struct wpa_sm *sm,
    +-			     struct wpa_peerkey *peerkey,
    +-			     struct wpa_eapol_key *key, u16 ver,
    +-			     const u8 *buf, size_t len)
    +-{
    +-	return -1;
    +-}
    +-
    +-static inline void
    +-peerkey_rx_eapol_4way(struct wpa_sm *sm, struct wpa_peerkey *peerkey,
    +-		      struct wpa_eapol_key *key, u16 key_info, u16 ver,
    +-		      const u8 *key_data, size_t key_data_len)
    +-{
    +-}
    +-
    +-static inline void
    +-peerkey_rx_eapol_smk(struct wpa_sm *sm, const u8 *src_addr,
    +-		     struct wpa_eapol_key *key, size_t extra_len,
    +-		     u16 key_info, u16 ver)
    +-{
    +-}
    +-
    +-static inline void peerkey_deinit(struct wpa_sm *sm)
    +-{
    +-}
    +-
    +-#endif /* CONFIG_PEERKEY */
    +-
    +-#endif /* PEERKEY_H */
    +diff --git a/src/rsn_supp/tdls.c b/src/rsn_supp/tdls.c
    +index e424168..9eb9738 100644
    +--- a/src/rsn_supp/tdls.c
    ++++ b/src/rsn_supp/tdls.c
    +@@ -112,6 +112,7 @@ struct wpa_tdls_peer {
    + 		u8 tk[16]; /* TPK-TK; assuming only CCMP will be used */
    + 	} tpk;
    + 	int tpk_set;
    ++	int tk_set; /* TPK-TK configured to the driver */
    + 	int tpk_success;
    + 	int tpk_in_progress;
    + 
    +@@ -192,6 +193,20 @@ static int wpa_tdls_set_key(struct wpa_sm *sm, struct wpa_tdls_peer *peer)
    + 	u8 rsc[6];
    + 	enum wpa_alg alg;
    + 
    ++	if (peer->tk_set) {
    ++		/*
    ++		 * This same TPK-TK has already been configured to the driver
    ++		 * and this new configuration attempt (likely due to an
    ++		 * unexpected retransmitted frame) would result in clearing
    ++		 * the TX/RX sequence number which can break security, so must
    ++		 * not allow that to happen.
    ++		 */
    ++		wpa_printf(MSG_INFO, "TDLS: TPK-TK for the peer " MACSTR
    ++			   " has already been configured to the driver - do not reconfigure",
    ++			   MAC2STR(peer->addr));
    ++		return -1;
    ++	}
    ++
    + 	os_memset(rsc, 0, 6);
    + 
    + 	switch (peer->cipher) {
    +@@ -209,12 +224,15 @@ static int wpa_tdls_set_key(struct wpa_sm *sm, struct wpa_tdls_peer *peer)
    + 		return -1;
    + 	}
    + 
    ++	wpa_printf(MSG_DEBUG, "TDLS: Configure pairwise key for peer " MACSTR,
    ++		   MAC2STR(peer->addr));
    + 	if (wpa_sm_set_key(sm, alg, peer->addr, -1, 1,
    + 			   rsc, sizeof(rsc), peer->tpk.tk, key_len) < 0) {
    + 		wpa_printf(MSG_WARNING, "TDLS: Failed to set TPK to the "
    + 			   "driver");
    + 		return -1;
    + 	}
    ++	peer->tk_set = 1;
    + 	return 0;
    + }
    + 
    +@@ -696,7 +714,7 @@ static void wpa_tdls_peer_clear(struct wpa_sm *sm, struct wpa_tdls_peer *peer)
    + 	peer->cipher = 0;
    + 	peer->qos_info = 0;
    + 	peer->wmm_capable = 0;
    +-	peer->tpk_set = peer->tpk_success = 0;
    ++	peer->tk_set = peer->tpk_set = peer->tpk_success = 0;
    + 	peer->chan_switch_enabled = 0;
    + 	os_memset(&peer->tpk, 0, sizeof(peer->tpk));
    + 	os_memset(peer->inonce, 0, WPA_NONCE_LEN);
    +@@ -1159,6 +1177,7 @@ skip_rsnie:
    + 		wpa_tdls_peer_free(sm, peer);
    + 		return -1;
    + 	}
    ++	peer->tk_set = 0; /* A new nonce results in a new TK */
    + 	wpa_hexdump(MSG_DEBUG, "TDLS: Initiator Nonce for TPK handshake",
    + 		    peer->inonce, WPA_NONCE_LEN);
    + 	os_memcpy(ftie->Snonce, peer->inonce, WPA_NONCE_LEN);
    +@@ -1751,6 +1770,19 @@ static int wpa_tdls_addset_peer(struct wpa_sm *sm, struct wpa_tdls_peer *peer,
    + }
    + 
    + 
    ++static int tdls_nonce_set(const u8 *nonce)
    ++{
    ++	int i;
    ++
    ++	for (i = 0; i < WPA_NONCE_LEN; i++) {
    ++		if (nonce[i])
    ++			return 1;
    ++	}
    ++
    ++	return 0;
    ++}
    ++
    ++
    + static int wpa_tdls_process_tpk_m1(struct wpa_sm *sm, const u8 *src_addr,
    + 				   const u8 *buf, size_t len)
    + {
    +@@ -2004,7 +2036,8 @@ skip_rsn:
    + 	peer->rsnie_i_len = kde.rsn_ie_len;
    + 	peer->cipher = cipher;
    + 
    +-	if (os_memcmp(peer->inonce, ftie->Snonce, WPA_NONCE_LEN) != 0) {
    ++	if (os_memcmp(peer->inonce, ftie->Snonce, WPA_NONCE_LEN) != 0 ||
    ++	    !tdls_nonce_set(peer->inonce)) {
    + 		/*
    + 		 * There is no point in updating the RNonce for every obtained
    + 		 * TPK M1 frame (e.g., retransmission due to timeout) with the
    +@@ -2020,6 +2053,7 @@ skip_rsn:
    + 				"TDLS: Failed to get random data for responder nonce");
    + 			goto error;
    + 		}
    ++		peer->tk_set = 0; /* A new nonce results in a new TK */
    + 	}
    + 
    + #if 0
    +diff --git a/src/rsn_supp/wpa.c b/src/rsn_supp/wpa.c
    +index 3c47879..a22e36d 100644
    +--- a/src/rsn_supp/wpa.c
    ++++ b/src/rsn_supp/wpa.c
    +@@ -21,7 +21,6 @@
    + #include "pmksa_cache.h"
    + #include "wpa_i.h"
    + #include "wpa_ie.h"
    +-#include "peerkey.h"
    + 
    + 
    + static const u8 null_rsc[8] = { 0, 0, 0, 0, 0, 0, 0, 0 };
    +@@ -500,7 +499,8 @@ static void wpa_supplicant_process_1_of_4(struct wpa_sm *sm,
    + 	/* Calculate PTK which will be stored as a temporary PTK until it has
    + 	 * been verified when processing message 3/4. */
    + 	ptk = &sm->tptk;
    +-	wpa_derive_ptk(sm, src_addr, key, ptk);
    ++	if (wpa_derive_ptk(sm, src_addr, key, ptk) < 0)
    ++		goto failed;
    + 	if (sm->pairwise_cipher == WPA_CIPHER_TKIP) {
    + 		u8 buf[8];
    + 		/* Supplicant: swap tx/rx Mic keys */
    +@@ -510,7 +510,6 @@ static void wpa_supplicant_process_1_of_4(struct wpa_sm *sm,
    + 		os_memset(buf, 0, sizeof(buf));
    + 	}
    + 	sm->tptk_set = 1;
    +-	sm->tk_to_set = 1;
    + 
    + 	kde = sm->assoc_wpa_ie;
    + 	kde_len = sm->assoc_wpa_ie_len;
    +@@ -615,7 +614,7 @@ static int wpa_supplicant_install_ptk(struct wpa_sm *sm,
    + 	enum wpa_alg alg;
    + 	const u8 *key_rsc;
    + 
    +-	if (!sm->tk_to_set) {
    ++	if (sm->ptk.installed) {
    + 		wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG,
    + 			"WPA: Do not re-install same PTK to the driver");
    + 		return 0;
    +@@ -659,7 +658,7 @@ static int wpa_supplicant_install_ptk(struct wpa_sm *sm,
    + 
    + 	/* TK is not needed anymore in supplicant */
    + 	os_memset(sm->ptk.tk, 0, WPA_TK_MAX_LEN);
    +-	sm->tk_to_set = 0;
    ++	sm->ptk.installed = 1;
    + 
    + 	if (sm->wpa_ptk_rekey) {
    + 		eloop_cancel_timeout(wpa_sm_rekey_ptk, sm, NULL);
    +@@ -709,11 +708,23 @@ struct wpa_gtk_data {
    + 
    + static int wpa_supplicant_install_gtk(struct wpa_sm *sm,
    + 				      const struct wpa_gtk_data *gd,
    +-				      const u8 *key_rsc)
    ++				      const u8 *key_rsc, int wnm_sleep)
    + {
    + 	const u8 *_gtk = gd->gtk;
    + 	u8 gtk_buf[32];
    + 
    ++	/* Detect possible key reinstallation */
    ++	if ((sm->gtk.gtk_len == (size_t) gd->gtk_len &&
    ++	     os_memcmp(sm->gtk.gtk, gd->gtk, sm->gtk.gtk_len) == 0) ||
    ++	    (sm->gtk_wnm_sleep.gtk_len == (size_t) gd->gtk_len &&
    ++	     os_memcmp(sm->gtk_wnm_sleep.gtk, gd->gtk,
    ++		       sm->gtk_wnm_sleep.gtk_len) == 0)) {
    ++		wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG,
    ++			"WPA: Not reinstalling already in-use GTK to the driver (keyidx=%d tx=%d len=%d)",
    ++			gd->keyidx, gd->tx, gd->gtk_len);
    ++		return 0;
    ++	}
    ++
    + 	wpa_hexdump_key(MSG_DEBUG, "WPA: Group Key", gd->gtk, gd->gtk_len);
    + 	wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG,
    + 		"WPA: Installing GTK to the driver (keyidx=%d tx=%d len=%d)",
    +@@ -748,6 +759,15 @@ static int wpa_supplicant_install_gtk(struct wpa_sm *sm,
    + 	}
    + 	os_memset(gtk_buf, 0, sizeof(gtk_buf));
    + 
    ++	if (wnm_sleep) {
    ++		sm->gtk_wnm_sleep.gtk_len = gd->gtk_len;
    ++		os_memcpy(sm->gtk_wnm_sleep.gtk, gd->gtk,
    ++			  sm->gtk_wnm_sleep.gtk_len);
    ++	} else {
    ++		sm->gtk.gtk_len = gd->gtk_len;
    ++		os_memcpy(sm->gtk.gtk, gd->gtk, sm->gtk.gtk_len);
    ++	}
    ++
    + 	return 0;
    + }
    + 
    +@@ -840,7 +860,7 @@ static int wpa_supplicant_pairwise_gtk(struct wpa_sm *sm,
    + 	    (wpa_supplicant_check_group_cipher(sm, sm->group_cipher,
    + 					       gtk_len, gtk_len,
    + 					       &gd.key_rsc_len, &gd.alg) ||
    +-	     wpa_supplicant_install_gtk(sm, &gd, key_rsc))) {
    ++	     wpa_supplicant_install_gtk(sm, &gd, key_rsc, 0))) {
    + 		wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG,
    + 			"RSN: Failed to install GTK");
    + 		os_memset(&gd, 0, sizeof(gd));
    +@@ -854,6 +874,58 @@ static int wpa_supplicant_pairwise_gtk(struct wpa_sm *sm,
    + }
    + 
    + 
    ++#ifdef CONFIG_IEEE80211W
    ++static int wpa_supplicant_install_igtk(struct wpa_sm *sm,
    ++				       const struct wpa_igtk_kde *igtk,
    ++				       int wnm_sleep)
    ++{
    ++	size_t len = wpa_cipher_key_len(sm->mgmt_group_cipher);
    ++	u16 keyidx = WPA_GET_LE16(igtk->keyid);
    ++
    ++	/* Detect possible key reinstallation */
    ++	if ((sm->igtk.igtk_len == len &&
    ++	     os_memcmp(sm->igtk.igtk, igtk->igtk, sm->igtk.igtk_len) == 0) ||
    ++	    (sm->igtk_wnm_sleep.igtk_len == len &&
    ++	     os_memcmp(sm->igtk_wnm_sleep.igtk, igtk->igtk,
    ++		       sm->igtk_wnm_sleep.igtk_len) == 0)) {
    ++		wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG,
    ++			"WPA: Not reinstalling already in-use IGTK to the driver (keyidx=%d)",
    ++			keyidx);
    ++		return  0;
    ++	}
    ++
    ++	wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG,
    ++		"WPA: IGTK keyid %d pn %02x%02x%02x%02x%02x%02x",
    ++		keyidx, MAC2STR(igtk->pn));
    ++	wpa_hexdump_key(MSG_DEBUG, "WPA: IGTK", igtk->igtk, len);
    ++	if (keyidx > 4095) {
    ++		wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
    ++			"WPA: Invalid IGTK KeyID %d", keyidx);
    ++		return -1;
    ++	}
    ++	if (wpa_sm_set_key(sm, wpa_cipher_to_alg(sm->mgmt_group_cipher),
    ++			   broadcast_ether_addr,
    ++			   keyidx, 0, igtk->pn, sizeof(igtk->pn),
    ++			   igtk->igtk, len) < 0) {
    ++		wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
    ++			"WPA: Failed to configure IGTK to the driver");
    ++		return -1;
    ++	}
    ++
    ++	if (wnm_sleep) {
    ++		sm->igtk_wnm_sleep.igtk_len = len;
    ++		os_memcpy(sm->igtk_wnm_sleep.igtk, igtk->igtk,
    ++			  sm->igtk_wnm_sleep.igtk_len);
    ++	} else {
    ++		sm->igtk.igtk_len = len;
    ++		os_memcpy(sm->igtk.igtk, igtk->igtk, sm->igtk.igtk_len);
    ++	}
    ++
    ++	return 0;
    ++}
    ++#endif /* CONFIG_IEEE80211W */
    ++
    ++
    + static int ieee80211w_set_keys(struct wpa_sm *sm,
    + 			       struct wpa_eapol_ie_parse *ie)
    + {
    +@@ -864,30 +936,14 @@ static int ieee80211w_set_keys(struct wpa_sm *sm,
    + 	if (ie->igtk) {
    + 		size_t len;
    + 		const struct wpa_igtk_kde *igtk;
    +-		u16 keyidx;
    ++
    + 		len = wpa_cipher_key_len(sm->mgmt_group_cipher);
    + 		if (ie->igtk_len != WPA_IGTK_KDE_PREFIX_LEN + len)
    + 			return -1;
    ++
    + 		igtk = (const struct wpa_igtk_kde *) ie->igtk;
    +-		keyidx = WPA_GET_LE16(igtk->keyid);
    +-		wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG, "WPA: IGTK keyid %d "
    +-			"pn %02x%02x%02x%02x%02x%02x",
    +-			keyidx, MAC2STR(igtk->pn));
    +-		wpa_hexdump_key(MSG_DEBUG, "WPA: IGTK",
    +-				igtk->igtk, len);
    +-		if (keyidx > 4095) {
    +-			wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
    +-				"WPA: Invalid IGTK KeyID %d", keyidx);
    +-			return -1;
    +-		}
    +-		if (wpa_sm_set_key(sm, wpa_cipher_to_alg(sm->mgmt_group_cipher),
    +-				   broadcast_ether_addr,
    +-				   keyidx, 0, igtk->pn, sizeof(igtk->pn),
    +-				   igtk->igtk, len) < 0) {
    +-			wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
    +-				"WPA: Failed to configure IGTK to the driver");
    ++		if (wpa_supplicant_install_igtk(sm, igtk, 0) < 0)
    + 			return -1;
    +-		}
    + 	}
    + 
    + 	return 0;
    +@@ -1536,7 +1592,7 @@ static void wpa_supplicant_process_1_of_2(struct wpa_sm *sm,
    + 	if (wpa_supplicant_rsc_relaxation(sm, key->key_rsc))
    + 		key_rsc = null_rsc;
    + 
    +-	if (wpa_supplicant_install_gtk(sm, &gd, key_rsc) ||
    ++	if (wpa_supplicant_install_gtk(sm, &gd, key_rsc, 0) ||
    + 	    wpa_supplicant_send_2_of_2(sm, key, ver, key_info) < 0)
    + 		goto failed;
    + 	os_memset(&gd, 0, sizeof(gd));
    +@@ -1587,6 +1643,14 @@ static int wpa_supplicant_verify_eapol_key_mic(struct wpa_sm *sm,
    + 			sm->ptk_set = 1;
    + 			os_memcpy(&sm->ptk, &sm->tptk, sizeof(sm->ptk));
    + 			os_memset(&sm->tptk, 0, sizeof(sm->tptk));
    ++			/*
    ++			 * This assures the same TPTK in sm->tptk can never be
    ++			 * copied twice to sm->pkt as the new PTK. In
    ++			 * combination with the installed flag in the wpa_ptk
    ++			 * struct, this assures the same PTK is only installed
    ++			 * once.
    ++			 */
    ++			sm->renew_snonce = 1;
    + 		}
    + 	}
    + 
    +@@ -1767,7 +1831,6 @@ int wpa_sm_rx_eapol(struct wpa_sm *sm, const u8 *src_addr,
    + 	u16 key_info, ver;
    + 	u8 *tmp = NULL;
    + 	int ret = -1;
    +-	struct wpa_peerkey *peerkey = NULL;
    + 	u8 *key_data;
    + 	size_t mic_len, keyhdrlen;
    + 
    +@@ -1941,44 +2004,7 @@ int wpa_sm_rx_eapol(struct wpa_sm *sm, const u8 *src_addr,
    + 		goto out;
    + 	}
    + 
    +-#ifdef CONFIG_PEERKEY
    +-	for (peerkey = sm->peerkey; peerkey; peerkey = peerkey->next) {
    +-		if (os_memcmp(peerkey->addr, src_addr, ETH_ALEN) == 0)
    +-			break;
    +-	}
    +-
    +-	if (!(key_info & WPA_KEY_INFO_SMK_MESSAGE) && peerkey) {
    +-		if (!peerkey->initiator && peerkey->replay_counter_set &&
    +-		    os_memcmp(key->replay_counter, peerkey->replay_counter,
    +-			      WPA_REPLAY_COUNTER_LEN) <= 0) {
    +-			wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
    +-				"RSN: EAPOL-Key Replay Counter did not "
    +-				"increase (STK) - dropping packet");
    +-			goto out;
    +-		} else if (peerkey->initiator) {
    +-			u8 _tmp[WPA_REPLAY_COUNTER_LEN];
    +-			os_memcpy(_tmp, key->replay_counter,
    +-				  WPA_REPLAY_COUNTER_LEN);
    +-			inc_byte_array(_tmp, WPA_REPLAY_COUNTER_LEN);
    +-			if (os_memcmp(_tmp, peerkey->replay_counter,
    +-				      WPA_REPLAY_COUNTER_LEN) != 0) {
    +-				wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG,
    +-					"RSN: EAPOL-Key Replay "
    +-					"Counter did not match (STK) - "
    +-					"dropping packet");
    +-				goto out;
    +-			}
    +-		}
    +-	}
    +-
    +-	if (peerkey && peerkey->initiator && (key_info & WPA_KEY_INFO_ACK)) {
    +-		wpa_msg(sm->ctx->msg_ctx, MSG_INFO,
    +-			"RSN: Ack bit in key_info from STK peer");
    +-		goto out;
    +-	}
    +-#endif /* CONFIG_PEERKEY */
    +-
    +-	if (!peerkey && sm->rx_replay_counter_set &&
    ++	if (sm->rx_replay_counter_set &&
    + 	    os_memcmp(key->replay_counter, sm->rx_replay_counter,
    + 		      WPA_REPLAY_COUNTER_LEN) <= 0) {
    + 		wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
    +@@ -1987,11 +2013,13 @@ int wpa_sm_rx_eapol(struct wpa_sm *sm, const u8 *src_addr,
    + 		goto out;
    + 	}
    + 
    +-	if (!(key_info & (WPA_KEY_INFO_ACK | WPA_KEY_INFO_SMK_MESSAGE))
    +-#ifdef CONFIG_PEERKEY
    +-	    && (peerkey == NULL || !peerkey->initiator)
    +-#endif /* CONFIG_PEERKEY */
    +-		) {
    ++	if (key_info & WPA_KEY_INFO_SMK_MESSAGE) {
    ++		wpa_msg(sm->ctx->msg_ctx, MSG_INFO,
    ++			"WPA: Unsupported SMK bit in key_info");
    ++		goto out;
    ++	}
    ++
    ++	if (!(key_info & WPA_KEY_INFO_ACK)) {
    + 		wpa_msg(sm->ctx->msg_ctx, MSG_INFO,
    + 			"WPA: No Ack bit in key_info");
    + 		goto out;
    +@@ -2003,17 +2031,10 @@ int wpa_sm_rx_eapol(struct wpa_sm *sm, const u8 *src_addr,
    + 		goto out;
    + 	}
    + 
    +-	if ((key_info & WPA_KEY_INFO_MIC) && !peerkey &&
    ++	if ((key_info & WPA_KEY_INFO_MIC) &&
    + 	    wpa_supplicant_verify_eapol_key_mic(sm, key192, ver, tmp, data_len))
    + 		goto out;
    + 
    +-#ifdef CONFIG_PEERKEY
    +-	if ((key_info & WPA_KEY_INFO_MIC) && peerkey &&
    +-	    peerkey_verify_eapol_key_mic(sm, peerkey, key192, ver, tmp,
    +-					 data_len))
    +-		goto out;
    +-#endif /* CONFIG_PEERKEY */
    +-
    + 	if ((sm->proto == WPA_PROTO_RSN || sm->proto == WPA_PROTO_OSEN) &&
    + 	    (key_info & WPA_KEY_INFO_ENCR_KEY_DATA)) {
    + 		if (wpa_supplicant_decrypt_key_data(sm, key, ver, key_data,
    +@@ -2028,11 +2049,7 @@ int wpa_sm_rx_eapol(struct wpa_sm *sm, const u8 *src_addr,
    + 				"non-zero key index");
    + 			goto out;
    + 		}
    +-		if (peerkey) {
    +-			/* PeerKey 4-Way Handshake */
    +-			peerkey_rx_eapol_4way(sm, peerkey, key, key_info, ver,
    +-					      key_data, key_data_len);
    +-		} else if (key_info & WPA_KEY_INFO_MIC) {
    ++		if (key_info & WPA_KEY_INFO_MIC) {
    + 			/* 3/4 4-Way Handshake */
    + 			wpa_supplicant_process_3_of_4(sm, key, ver, key_data,
    + 						      key_data_len);
    +@@ -2042,10 +2059,6 @@ int wpa_sm_rx_eapol(struct wpa_sm *sm, const u8 *src_addr,
    + 						      ver, key_data,
    + 						      key_data_len);
    + 		}
    +-	} else if (key_info & WPA_KEY_INFO_SMK_MESSAGE) {
    +-		/* PeerKey SMK Handshake */
    +-		peerkey_rx_eapol_smk(sm, src_addr, key, key_data_len, key_info,
    +-				     ver);
    + 	} else {
    + 		if (key_info & WPA_KEY_INFO_MIC) {
    + 			/* 1/2 Group Key Handshake */
    +@@ -2286,7 +2299,6 @@ void wpa_sm_deinit(struct wpa_sm *sm)
    + 	os_free(sm->ap_rsn_ie);
    + 	wpa_sm_drop_sa(sm);
    + 	os_free(sm->ctx);
    +-	peerkey_deinit(sm);
    + #ifdef CONFIG_IEEE80211R
    + 	os_free(sm->assoc_resp_ies);
    + #endif /* CONFIG_IEEE80211R */
    +@@ -2307,7 +2319,7 @@ void wpa_sm_deinit(struct wpa_sm *sm)
    +  */
    + void wpa_sm_notify_assoc(struct wpa_sm *sm, const u8 *bssid)
    + {
    +-	int clear_ptk = 1;
    ++	int clear_keys = 1;
    + 
    + 	if (sm == NULL)
    + 		return;
    +@@ -2333,11 +2345,11 @@ void wpa_sm_notify_assoc(struct wpa_sm *sm, const u8 *bssid)
    + 		/* Prepare for the next transition */
    + 		wpa_ft_prepare_auth_request(sm, NULL);
    + 
    +-		clear_ptk = 0;
    ++		clear_keys = 0;
    + 	}
    + #endif /* CONFIG_IEEE80211R */
    + 
    +-	if (clear_ptk) {
    ++	if (clear_keys) {
    + 		/*
    + 		 * IEEE 802.11, 8.4.10: Delete PTK SA on (re)association if
    + 		 * this is not part of a Fast BSS Transition.
    +@@ -2347,6 +2359,12 @@ void wpa_sm_notify_assoc(struct wpa_sm *sm, const u8 *bssid)
    + 		os_memset(&sm->ptk, 0, sizeof(sm->ptk));
    + 		sm->tptk_set = 0;
    + 		os_memset(&sm->tptk, 0, sizeof(sm->tptk));
    ++		os_memset(&sm->gtk, 0, sizeof(sm->gtk));
    ++		os_memset(&sm->gtk_wnm_sleep, 0, sizeof(sm->gtk_wnm_sleep));
    ++#ifdef CONFIG_IEEE80211W
    ++		os_memset(&sm->igtk, 0, sizeof(sm->igtk));
    ++		os_memset(&sm->igtk_wnm_sleep, 0, sizeof(sm->igtk_wnm_sleep));
    ++#endif /* CONFIG_IEEE80211W */
    + 	}
    + 
    + #ifdef CONFIG_TDLS
    +@@ -2370,7 +2388,6 @@ void wpa_sm_notify_disassoc(struct wpa_sm *sm)
    + {
    + 	eloop_cancel_timeout(wpa_sm_start_preauth, sm, NULL);
    + 	eloop_cancel_timeout(wpa_sm_rekey_ptk, sm, NULL);
    +-	peerkey_deinit(sm);
    + 	rsn_preauth_deinit(sm);
    + 	pmksa_cache_clear_current(sm);
    + 	if (wpa_sm_get_state(sm) == WPA_4WAY_HANDSHAKE)
    +@@ -2378,6 +2395,9 @@ void wpa_sm_notify_disassoc(struct wpa_sm *sm)
    + #ifdef CONFIG_TDLS
    + 	wpa_tdls_disassoc(sm);
    + #endif /* CONFIG_TDLS */
    ++#ifdef CONFIG_IEEE80211R
    ++	sm->ft_reassoc_completed = 0;
    ++#endif /* CONFIG_IEEE80211R */
    + 
    + 	/* Keys are not needed in the WPA state machine anymore */
    + 	wpa_sm_drop_sa(sm);
    +@@ -2402,6 +2422,8 @@ void wpa_sm_set_pmk(struct wpa_sm *sm, const u8 *pmk, size_t pmk_len,
    + 	if (sm == NULL)
    + 		return;
    + 
    ++	wpa_hexdump_key(MSG_DEBUG, "WPA: Set PMK based on external data",
    ++			pmk, pmk_len);
    + 	sm->pmk_len = pmk_len;
    + 	os_memcpy(sm->pmk, pmk, pmk_len);
    + 
    +@@ -2432,11 +2454,15 @@ void wpa_sm_set_pmk_from_pmksa(struct wpa_sm *sm)
    + 		return;
    + 
    + 	if (sm->cur_pmksa) {
    ++		wpa_hexdump_key(MSG_DEBUG,
    ++				"WPA: Set PMK based on current PMKSA",
    ++				sm->cur_pmksa->pmk, sm->cur_pmksa->pmk_len);
    + 		sm->pmk_len = sm->cur_pmksa->pmk_len;
    + 		os_memcpy(sm->pmk, sm->cur_pmksa->pmk, sm->pmk_len);
    + 	} else {
    +-		sm->pmk_len = PMK_LEN;
    +-		os_memset(sm->pmk, 0, PMK_LEN);
    ++		wpa_printf(MSG_DEBUG, "WPA: No current PMKSA - clear PMK");
    ++		sm->pmk_len = 0;
    ++		os_memset(sm->pmk, 0, PMK_LEN_MAX);
    + 	}
    + }
    + 
    +@@ -2484,7 +2510,6 @@ void wpa_sm_set_config(struct wpa_sm *sm, struct rsn_supp_config *config)
    + 
    + 	if (config) {
    + 		sm->network_ctx = config->network_ctx;
    +-		sm->peerkey_enabled = config->peerkey_enabled;
    + 		sm->allowed_pairwise_cipher = config->allowed_pairwise_cipher;
    + 		sm->proactive_key_caching = config->proactive_key_caching;
    + 		sm->eap_workaround = config->eap_workaround;
    +@@ -2499,7 +2524,6 @@ void wpa_sm_set_config(struct wpa_sm *sm, struct rsn_supp_config *config)
    + 		sm->wpa_rsc_relaxation = config->wpa_rsc_relaxation;
    + 	} else {
    + 		sm->network_ctx = NULL;
    +-		sm->peerkey_enabled = 0;
    + 		sm->allowed_pairwise_cipher = 0;
    + 		sm->proactive_key_caching = 0;
    + 		sm->eap_workaround = 0;
    +@@ -2877,6 +2901,12 @@ void wpa_sm_drop_sa(struct wpa_sm *sm)
    + 	os_memset(sm->pmk, 0, sizeof(sm->pmk));
    + 	os_memset(&sm->ptk, 0, sizeof(sm->ptk));
    + 	os_memset(&sm->tptk, 0, sizeof(sm->tptk));
    ++	os_memset(&sm->gtk, 0, sizeof(sm->gtk));
    ++	os_memset(&sm->gtk_wnm_sleep, 0, sizeof(sm->gtk_wnm_sleep));
    ++#ifdef CONFIG_IEEE80211W
    ++	os_memset(&sm->igtk, 0, sizeof(sm->igtk));
    ++	os_memset(&sm->igtk_wnm_sleep, 0, sizeof(sm->igtk_wnm_sleep));
    ++#endif /* CONFIG_IEEE80211W */
    + #ifdef CONFIG_IEEE80211R
    + 	os_memset(sm->xxkey, 0, sizeof(sm->xxkey));
    + 	os_memset(sm->pmk_r0, 0, sizeof(sm->pmk_r0));
    +@@ -2940,7 +2970,7 @@ int wpa_wnmsleep_install_key(struct wpa_sm *sm, u8 subelem_id, u8 *buf)
    + 
    + 		wpa_hexdump_key(MSG_DEBUG, "Install GTK (WNM SLEEP)",
    + 				gd.gtk, gd.gtk_len);
    +-		if (wpa_supplicant_install_gtk(sm, &gd, key_rsc)) {
    ++		if (wpa_supplicant_install_gtk(sm, &gd, key_rsc, 1)) {
    + 			os_memset(&gd, 0, sizeof(gd));
    + 			wpa_printf(MSG_DEBUG, "Failed to install the GTK in "
    + 				   "WNM mode");
    +@@ -2949,29 +2979,11 @@ int wpa_wnmsleep_install_key(struct wpa_sm *sm, u8 subelem_id, u8 *buf)
    + 		os_memset(&gd, 0, sizeof(gd));
    + #ifdef CONFIG_IEEE80211W
    + 	} else if (subelem_id == WNM_SLEEP_SUBELEM_IGTK) {
    +-		struct wpa_igtk_kde igd;
    +-		u16 keyidx;
    +-
    +-		os_memset(&igd, 0, sizeof(igd));
    +-		keylen = wpa_cipher_key_len(sm->mgmt_group_cipher);
    +-		os_memcpy(igd.keyid, buf + 2, 2);
    +-		os_memcpy(igd.pn, buf + 4, 6);
    +-
    +-		keyidx = WPA_GET_LE16(igd.keyid);
    +-		os_memcpy(igd.igtk, buf + 10, keylen);
    +-
    +-		wpa_hexdump_key(MSG_DEBUG, "Install IGTK (WNM SLEEP)",
    +-				igd.igtk, keylen);
    +-		if (wpa_sm_set_key(sm, wpa_cipher_to_alg(sm->mgmt_group_cipher),
    +-				   broadcast_ether_addr,
    +-				   keyidx, 0, igd.pn, sizeof(igd.pn),
    +-				   igd.igtk, keylen) < 0) {
    +-			wpa_printf(MSG_DEBUG, "Failed to install the IGTK in "
    +-				   "WNM mode");
    +-			os_memset(&igd, 0, sizeof(igd));
    ++		const struct wpa_igtk_kde *igtk;
    ++
    ++		igtk = (const struct wpa_igtk_kde *) (buf + 2);
    ++		if (wpa_supplicant_install_igtk(sm, igtk, 1) < 0)
    + 			return -1;
    +-		}
    +-		os_memset(&igd, 0, sizeof(igd));
    + #endif /* CONFIG_IEEE80211W */
    + 	} else {
    + 		wpa_printf(MSG_DEBUG, "Unknown element id");
    +@@ -2983,27 +2995,6 @@ int wpa_wnmsleep_install_key(struct wpa_sm *sm, u8 subelem_id, u8 *buf)
    + #endif /* CONFIG_WNM */
    + 
    + 
    +-#ifdef CONFIG_PEERKEY
    +-int wpa_sm_rx_eapol_peerkey(struct wpa_sm *sm, const u8 *src_addr,
    +-			    const u8 *buf, size_t len)
    +-{
    +-	struct wpa_peerkey *peerkey;
    +-
    +-	for (peerkey = sm->peerkey; peerkey; peerkey = peerkey->next) {
    +-		if (os_memcmp(peerkey->addr, src_addr, ETH_ALEN) == 0)
    +-			break;
    +-	}
    +-
    +-	if (!peerkey)
    +-		return 0;
    +-
    +-	wpa_sm_rx_eapol(sm, src_addr, buf, len);
    +-
    +-	return 1;
    +-}
    +-#endif /* CONFIG_PEERKEY */
    +-
    +-
    + #ifdef CONFIG_P2P
    + 
    + int wpa_sm_get_p2p_ip_addr(struct wpa_sm *sm, u8 *buf)
    +diff --git a/src/rsn_supp/wpa.h b/src/rsn_supp/wpa.h
    +index c89799a..b55baac 100644
    +--- a/src/rsn_supp/wpa.h
    ++++ b/src/rsn_supp/wpa.h
    +@@ -95,7 +95,6 @@ enum wpa_sm_conf_params {
    + 
    + struct rsn_supp_config {
    + 	void *network_ctx;
    +-	int peerkey_enabled;
    + 	int allowed_pairwise_cipher; /* bitfield of WPA_CIPHER_* */
    + 	int proactive_key_caching;
    + 	int eap_workaround;
    +@@ -329,23 +328,6 @@ static inline void wpa_sm_set_ptk_kck_kek(struct wpa_sm *sm, const u8 *ptk_kck,
    + 
    + #endif /* CONFIG_NO_WPA */
    + 
    +-#ifdef CONFIG_PEERKEY
    +-int wpa_sm_stkstart(struct wpa_sm *sm, const u8 *peer);
    +-int wpa_sm_rx_eapol_peerkey(struct wpa_sm *sm, const u8 *src_addr,
    +-			    const u8 *buf, size_t len);
    +-#else /* CONFIG_PEERKEY */
    +-static inline int wpa_sm_stkstart(struct wpa_sm *sm, const u8 *peer)
    +-{
    +-	return -1;
    +-}
    +-
    +-static inline int wpa_sm_rx_eapol_peerkey(struct wpa_sm *sm, const u8 *src_addr,
    +-					  const u8 *buf, size_t len)
    +-{
    +-	return 0;
    +-}
    +-#endif /* CONFIG_PEERKEY */
    +-
    + #ifdef CONFIG_IEEE80211R
    + 
    + int wpa_sm_set_ft_params(struct wpa_sm *sm, const u8 *ies, size_t ies_len);
    +diff --git a/src/rsn_supp/wpa_ft.c b/src/rsn_supp/wpa_ft.c
    +index 205793e..d45bb45 100644
    +--- a/src/rsn_supp/wpa_ft.c
    ++++ b/src/rsn_supp/wpa_ft.c
    +@@ -153,6 +153,7 @@ static u8 * wpa_ft_gen_req_ies(struct wpa_sm *sm, size_t *len,
    + 	u16 capab;
    + 
    + 	sm->ft_completed = 0;
    ++	sm->ft_reassoc_completed = 0;
    + 
    + 	buf_len = 2 + sizeof(struct rsn_mdie) + 2 + sizeof(struct rsn_ftie) +
    + 		2 + sm->r0kh_id_len + ric_ies_len + 100;
    +@@ -681,6 +682,11 @@ int wpa_ft_validate_reassoc_resp(struct wpa_sm *sm, const u8 *ies,
    + 		return -1;
    + 	}
    + 
    ++	if (sm->ft_reassoc_completed) {
    ++		wpa_printf(MSG_DEBUG, "FT: Reassociation has already been completed for this FT protocol instance - ignore unexpected retransmission");
    ++		return 0;
    ++	}
    ++
    + 	if (wpa_ft_parse_ies(ies, ies_len, &parse) < 0) {
    + 		wpa_printf(MSG_DEBUG, "FT: Failed to parse IEs");
    + 		return -1;
    +@@ -781,6 +787,8 @@ int wpa_ft_validate_reassoc_resp(struct wpa_sm *sm, const u8 *ies,
    + 		return -1;
    + 	}
    + 
    ++	sm->ft_reassoc_completed = 1;
    ++
    + 	if (wpa_ft_process_gtk_subelem(sm, parse.gtk, parse.gtk_len) < 0)
    + 		return -1;
    + 
    +diff --git a/src/rsn_supp/wpa_i.h b/src/rsn_supp/wpa_i.h
    +index f653ba6..2243613 100644
    +--- a/src/rsn_supp/wpa_i.h
    ++++ b/src/rsn_supp/wpa_i.h
    +@@ -11,7 +11,6 @@
    + 
    + #include "utils/list.h"
    + 
    +-struct wpa_peerkey;
    + struct wpa_tdls_peer;
    + struct wpa_eapol_key;
    + 
    +@@ -24,13 +23,18 @@ struct wpa_sm {
    + 	struct wpa_ptk ptk, tptk;
    + 	int ptk_set, tptk_set;
    + 	unsigned int msg_3_of_4_ok:1;
    +-	unsigned int tk_to_set:1;
    + 	u8 snonce[WPA_NONCE_LEN];
    + 	u8 anonce[WPA_NONCE_LEN]; /* ANonce from the last 1/4 msg */
    + 	int renew_snonce;
    + 	u8 rx_replay_counter[WPA_REPLAY_COUNTER_LEN];
    + 	int rx_replay_counter_set;
    + 	u8 request_counter[WPA_REPLAY_COUNTER_LEN];
    ++	struct wpa_gtk gtk;
    ++	struct wpa_gtk gtk_wnm_sleep;
    ++#ifdef CONFIG_IEEE80211W
    ++	struct wpa_igtk igtk;
    ++	struct wpa_igtk igtk_wnm_sleep;
    ++#endif /* CONFIG_IEEE80211W */
    + 
    + 	struct eapol_sm *eapol; /* EAPOL state machine from upper level code */
    + 
    +@@ -52,7 +56,6 @@ struct wpa_sm {
    + 	int fast_reauth; /* whether EAP fast re-authentication is enabled */
    + 
    + 	void *network_ctx;
    +-	int peerkey_enabled;
    + 	int allowed_pairwise_cipher; /* bitfield of WPA_CIPHER_* */
    + 	int proactive_key_caching;
    + 	int eap_workaround;
    +@@ -89,9 +92,6 @@ struct wpa_sm {
    + 	u8 *ap_wpa_ie, *ap_rsn_ie;
    + 	size_t ap_wpa_ie_len, ap_rsn_ie_len;
    + 
    +-#ifdef CONFIG_PEERKEY
    +-	struct wpa_peerkey *peerkey;
    +-#endif /* CONFIG_PEERKEY */
    + #ifdef CONFIG_TDLS
    + 	struct wpa_tdls_peer *tdls;
    + 	int tdls_prohibited;
    +@@ -123,6 +123,7 @@ struct wpa_sm {
    + 	size_t r0kh_id_len;
    + 	u8 r1kh_id[FT_R1KH_ID_LEN];
    + 	int ft_completed;
    ++	int ft_reassoc_completed;
    + 	int over_the_ds_in_progress;
    + 	u8 target_ap[ETH_ALEN]; /* over-the-DS target AP */
    + 	int set_ptk_after_assoc;
    +diff --git a/src/rsn_supp/wpa_ie.c b/src/rsn_supp/wpa_ie.c
    +index c44844e..4e0c3f4 100644
    +--- a/src/rsn_supp/wpa_ie.c
    ++++ b/src/rsn_supp/wpa_ie.c
    +@@ -405,44 +405,6 @@ static int wpa_parse_generic(const u8 *pos, const u8 *end,
    + 		return 0;
    + 	}
    + 
    +-#ifdef CONFIG_PEERKEY
    +-	if (pos[1] > RSN_SELECTOR_LEN + 2 &&
    +-	    RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_SMK) {
    +-		ie->smk = pos + 2 + RSN_SELECTOR_LEN;
    +-		ie->smk_len = pos[1] - RSN_SELECTOR_LEN;
    +-		wpa_hexdump_key(MSG_DEBUG, "WPA: SMK in EAPOL-Key",
    +-				pos, pos[1] + 2);
    +-		return 0;
    +-	}
    +-
    +-	if (pos[1] > RSN_SELECTOR_LEN + 2 &&
    +-	    RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_NONCE) {
    +-		ie->nonce = pos + 2 + RSN_SELECTOR_LEN;
    +-		ie->nonce_len = pos[1] - RSN_SELECTOR_LEN;
    +-		wpa_hexdump(MSG_DEBUG, "WPA: Nonce in EAPOL-Key",
    +-			    pos, pos[1] + 2);
    +-		return 0;
    +-	}
    +-
    +-	if (pos[1] > RSN_SELECTOR_LEN + 2 &&
    +-	    RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_LIFETIME) {
    +-		ie->lifetime = pos + 2 + RSN_SELECTOR_LEN;
    +-		ie->lifetime_len = pos[1] - RSN_SELECTOR_LEN;
    +-		wpa_hexdump(MSG_DEBUG, "WPA: Lifetime in EAPOL-Key",
    +-			    pos, pos[1] + 2);
    +-		return 0;
    +-	}
    +-
    +-	if (pos[1] > RSN_SELECTOR_LEN + 2 &&
    +-	    RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_ERROR) {
    +-		ie->error = pos + 2 + RSN_SELECTOR_LEN;
    +-		ie->error_len = pos[1] - RSN_SELECTOR_LEN;
    +-		wpa_hexdump(MSG_DEBUG, "WPA: Error in EAPOL-Key",
    +-			    pos, pos[1] + 2);
    +-		return 0;
    +-	}
    +-#endif /* CONFIG_PEERKEY */
    +-
    + #ifdef CONFIG_IEEE80211W
    + 	if (pos[1] > RSN_SELECTOR_LEN + 2 &&
    + 	    RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_IGTK) {
    +diff --git a/src/rsn_supp/wpa_ie.h b/src/rsn_supp/wpa_ie.h
    +index fe95af0..0e72af5 100644
    +--- a/src/rsn_supp/wpa_ie.h
    ++++ b/src/rsn_supp/wpa_ie.h
    +@@ -21,16 +21,6 @@ struct wpa_eapol_ie_parse {
    + 	size_t gtk_len;
    + 	const u8 *mac_addr;
    + 	size_t mac_addr_len;
    +-#ifdef CONFIG_PEERKEY
    +-	const u8 *smk;
    +-	size_t smk_len;
    +-	const u8 *nonce;
    +-	size_t nonce_len;
    +-	const u8 *lifetime;
    +-	size_t lifetime_len;
    +-	const u8 *error;
    +-	size_t error_len;
    +-#endif /* CONFIG_PEERKEY */
    + #ifdef CONFIG_IEEE80211W
    + 	const u8 *igtk;
    + 	size_t igtk_len;
    +diff --git a/wpa_supplicant/Android.mk b/wpa_supplicant/Android.mk
    +index f65076c..71236a5 100644
    +--- a/wpa_supplicant/Android.mk
    ++++ b/wpa_supplicant/Android.mk
    +@@ -247,15 +247,10 @@ ifdef CONFIG_TDLS_TESTING
    + L_CFLAGS += -DCONFIG_TDLS_TESTING
    + endif
    + 
    +-ifdef CONFIG_PEERKEY
    +-L_CFLAGS += -DCONFIG_PEERKEY
    +-endif
    +-
    + ifndef CONFIG_NO_WPA
    + OBJS += src/rsn_supp/wpa.c
    + OBJS += src/rsn_supp/preauth.c
    + OBJS += src/rsn_supp/pmksa_cache.c
    +-OBJS += src/rsn_supp/peerkey.c
    + OBJS += src/rsn_supp/wpa_ie.c
    + OBJS += src/common/wpa_common.c
    + NEED_AES=y
    +@@ -860,9 +855,6 @@ OBJS += src/ap/pmksa_cache_auth.c
    + ifdef CONFIG_IEEE80211R
    + OBJS += src/ap/wpa_auth_ft.c
    + endif
    +-ifdef CONFIG_PEERKEY
    +-OBJS += src/ap/peerkey_auth.c
    +-endif
    + endif
    + 
    + ifdef CONFIG_ACS
    +diff --git a/wpa_supplicant/Makefile b/wpa_supplicant/Makefile
    +index 550d44b..b057f7f 100644
    +--- a/wpa_supplicant/Makefile
    ++++ b/wpa_supplicant/Makefile
    +@@ -286,15 +286,10 @@ ifdef CONFIG_TDLS_TESTING
    + CFLAGS += -DCONFIG_TDLS_TESTING
    + endif
    + 
    +-ifdef CONFIG_PEERKEY
    +-CFLAGS += -DCONFIG_PEERKEY
    +-endif
    +-
    + ifndef CONFIG_NO_WPA
    + OBJS += ../src/rsn_supp/wpa.o
    + OBJS += ../src/rsn_supp/preauth.o
    + OBJS += ../src/rsn_supp/pmksa_cache.o
    +-OBJS += ../src/rsn_supp/peerkey.o
    + OBJS += ../src/rsn_supp/wpa_ie.o
    + OBJS += ../src/common/wpa_common.o
    + NEED_AES=y
    +@@ -907,9 +902,6 @@ OBJS += ../src/ap/pmksa_cache_auth.o
    + ifdef CONFIG_IEEE80211R
    + OBJS += ../src/ap/wpa_auth_ft.o
    + endif
    +-ifdef CONFIG_PEERKEY
    +-OBJS += ../src/ap/peerkey_auth.o
    +-endif
    + endif
    + 
    + ifdef CONFIG_ACS
    +diff --git a/wpa_supplicant/android.config b/wpa_supplicant/android.config
    +index 0a8bf98..8eb6443 100644
    +--- a/wpa_supplicant/android.config
    ++++ b/wpa_supplicant/android.config
    +@@ -263,9 +263,6 @@ CONFIG_ELOOP=eloop
    + # none = Empty template
    + CONFIG_L2_PACKET=linux
    + 
    +-# PeerKey handshake for Station to Station Link (IEEE 802.11e DLS)
    +-CONFIG_PEERKEY=y
    +-
    + # IEEE 802.11w (management frame protection), also known as PMF
    + # Driver support is also needed for IEEE 802.11w.
    + CONFIG_IEEE80211W=y
    +diff --git a/wpa_supplicant/config.c b/wpa_supplicant/config.c
    +index 4376676..6cbbe2d 100644
    +--- a/wpa_supplicant/config.c
    ++++ b/wpa_supplicant/config.c
    +@@ -1810,6 +1810,24 @@ static char * wpa_config_write_mesh_basic_rates(const struct parse_data *data,
    + #endif /* CONFIG_MESH */
    + 
    + 
    ++static int wpa_config_parse_peerkey(const struct parse_data *data,
    ++				    struct wpa_ssid *ssid, int line,
    ++				    const char *value)
    ++{
    ++	wpa_printf(MSG_INFO, "NOTE: Obsolete peerkey parameter ignored");
    ++	return 0;
    ++}
    ++
    ++
    ++#ifndef NO_CONFIG_WRITE
    ++static char * wpa_config_write_peerkey(const struct parse_data *data,
    ++				       struct wpa_ssid *ssid)
    ++{
    ++	return NULL;
    ++}
    ++#endif /* NO_CONFIG_WRITE */
    ++
    ++
    + /* Helper macros for network block parser */
    + 
    + #ifdef OFFSET
    +@@ -1984,7 +2002,7 @@ static const struct parse_data ssid_fields[] = {
    + #ifdef CONFIG_IEEE80211W
    + 	{ INT_RANGE(ieee80211w, 0, 2) },
    + #endif /* CONFIG_IEEE80211W */
    +-	{ INT_RANGE(peerkey, 0, 1) },
    ++	{ FUNC(peerkey) /* obsolete - removed */ },
    + 	{ INT_RANGE(mixed_cell, 0, 1) },
    + 	{ INT_RANGE(frequency, 0, 65000) },
    + 	{ INT_RANGE(fixed_freq, 0, 1) },
    +diff --git a/wpa_supplicant/config_file.c b/wpa_supplicant/config_file.c
    +index 38061f1..1d317fc 100644
    +--- a/wpa_supplicant/config_file.c
    ++++ b/wpa_supplicant/config_file.c
    +@@ -752,7 +752,6 @@ static void wpa_config_write_network(FILE *f, struct wpa_ssid *ssid)
    + #endif /* CONFIG_ACS */
    + 	write_int(f, "proactive_key_caching", ssid->proactive_key_caching, -1);
    + 	INT(disabled);
    +-	INT(peerkey);
    + 	INT(mixed_cell);
    + 	INT(max_oper_chwidth);
    + 	INT(pbss);
    +diff --git a/wpa_supplicant/config_ssid.h b/wpa_supplicant/config_ssid.h
    +index eb7b87b..5b6f426 100644
    +--- a/wpa_supplicant/config_ssid.h
    ++++ b/wpa_supplicant/config_ssid.h
    +@@ -388,17 +388,6 @@ struct wpa_ssid {
    + 	int disabled_for_connect;
    + 
    + 	/**
    +-	 * peerkey -  Whether PeerKey handshake for direct links is allowed
    +-	 *
    +-	 * This is only used when both RSN/WPA2 and IEEE 802.11e (QoS) are
    +-	 * enabled.
    +-	 *
    +-	 * 0 = disabled (default)
    +-	 * 1 = enabled
    +-	 */
    +-	int peerkey;
    +-
    +-	/**
    + 	 * id_str - Network identifier string for external scripts
    + 	 *
    + 	 * This value is passed to external ctrl_iface monitors in
    +diff --git a/wpa_supplicant/config_winreg.c b/wpa_supplicant/config_winreg.c
    +index 199f04f..ca70474 100644
    +--- a/wpa_supplicant/config_winreg.c
    ++++ b/wpa_supplicant/config_winreg.c
    +@@ -924,7 +924,6 @@ static int wpa_config_write_network(HKEY hk, struct wpa_ssid *ssid, int id)
    + 	write_int(netw, "proactive_key_caching", ssid->proactive_key_caching,
    + 		  -1);
    + 	INT(disabled);
    +-	INT(peerkey);
    + #ifdef CONFIG_IEEE80211W
    + 	write_int(netw, "ieee80211w", ssid->ieee80211w,
    + 		  MGMT_FRAME_PROTECTION_DEFAULT);
    +diff --git a/wpa_supplicant/ctrl_iface.c b/wpa_supplicant/ctrl_iface.c
    +index 8574437..80f1d41 100644
    +--- a/wpa_supplicant/ctrl_iface.c
    ++++ b/wpa_supplicant/ctrl_iface.c
    +@@ -575,27 +575,6 @@ static int wpa_supplicant_ctrl_iface_preauth(struct wpa_supplicant *wpa_s,
    + #endif /* IEEE8021X_EAPOL */
    + 
    + 
    +-#ifdef CONFIG_PEERKEY
    +-/* MLME-STKSTART.request(peer) */
    +-static int wpa_supplicant_ctrl_iface_stkstart(
    +-	struct wpa_supplicant *wpa_s, char *addr)
    +-{
    +-	u8 peer[ETH_ALEN];
    +-
    +-	if (hwaddr_aton(addr, peer)) {
    +-		wpa_printf(MSG_DEBUG, "CTRL_IFACE STKSTART: invalid "
    +-			   "address '%s'", addr);
    +-		return -1;
    +-	}
    +-
    +-	wpa_printf(MSG_DEBUG, "CTRL_IFACE STKSTART " MACSTR,
    +-		   MAC2STR(peer));
    +-
    +-	return wpa_sm_stkstart(wpa_s->wpa, peer);
    +-}
    +-#endif /* CONFIG_PEERKEY */
    +-
    +-
    + #ifdef CONFIG_TDLS
    + 
    + static int wpa_supplicant_ctrl_iface_tdls_discover(
    +@@ -8502,11 +8481,6 @@ char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s,
    + 		if (wpa_supplicant_ctrl_iface_preauth(wpa_s, buf + 8))
    + 			reply_len = -1;
    + #endif /* IEEE8021X_EAPOL */
    +-#ifdef CONFIG_PEERKEY
    +-	} else if (os_strncmp(buf, "STKSTART ", 9) == 0) {
    +-		if (wpa_supplicant_ctrl_iface_stkstart(wpa_s, buf + 9))
    +-			reply_len = -1;
    +-#endif /* CONFIG_PEERKEY */
    + #ifdef CONFIG_IEEE80211R
    + 	} else if (os_strncmp(buf, "FT_DS ", 6) == 0) {
    + 		if (wpa_supplicant_ctrl_iface_ft_ds(wpa_s, buf + 6))
    +diff --git a/wpa_supplicant/defconfig b/wpa_supplicant/defconfig
    +index 1d05198..5531386 100644
    +--- a/wpa_supplicant/defconfig
    ++++ b/wpa_supplicant/defconfig
    +@@ -288,9 +288,6 @@ CONFIG_BACKEND=file
    + # bridge interfaces (commit 'bridge: respect RFC2863 operational state')').
    + #CONFIG_NO_LINUX_PACKET_SOCKET_WAR=y
    + 
    +-# PeerKey handshake for Station to Station Link (IEEE 802.11e DLS)
    +-CONFIG_PEERKEY=y
    +-
    + # IEEE 802.11w (management frame protection), also known as PMF
    + # Driver support is also needed for IEEE 802.11w.
    + #CONFIG_IEEE80211W=y
    +diff --git a/wpa_supplicant/events.c b/wpa_supplicant/events.c
    +index 1b3d8a9..46f2924 100644
    +--- a/wpa_supplicant/events.c
    ++++ b/wpa_supplicant/events.c
    +@@ -2790,18 +2790,6 @@ wpa_supplicant_event_interface_status(struct wpa_supplicant *wpa_s,
    + }
    + 
    + 
    +-#ifdef CONFIG_PEERKEY
    +-static void
    +-wpa_supplicant_event_stkstart(struct wpa_supplicant *wpa_s,
    +-			      union wpa_event_data *data)
    +-{
    +-	if (data == NULL)
    +-		return;
    +-	wpa_sm_stkstart(wpa_s->wpa, data->stkstart.peer);
    +-}
    +-#endif /* CONFIG_PEERKEY */
    +-
    +-
    + #ifdef CONFIG_TDLS
    + static void wpa_supplicant_event_tdls(struct wpa_supplicant *wpa_s,
    + 				      union wpa_event_data *data)
    +@@ -3490,11 +3478,6 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event,
    + 	case EVENT_PMKID_CANDIDATE:
    + 		wpa_supplicant_event_pmkid_candidate(wpa_s, data);
    + 		break;
    +-#ifdef CONFIG_PEERKEY
    +-	case EVENT_STKSTART:
    +-		wpa_supplicant_event_stkstart(wpa_s, data);
    +-		break;
    +-#endif /* CONFIG_PEERKEY */
    + #ifdef CONFIG_TDLS
    + 	case EVENT_TDLS:
    + 		wpa_supplicant_event_tdls(wpa_s, data);
    +diff --git a/wpa_supplicant/wnm_sta.c b/wpa_supplicant/wnm_sta.c
    +index f77d51a..7dc1909 100644
    +--- a/wpa_supplicant/wnm_sta.c
    ++++ b/wpa_supplicant/wnm_sta.c
    +@@ -259,7 +259,7 @@ static void ieee802_11_rx_wnmsleep_resp(struct wpa_supplicant *wpa_s,
    + 
    + 	if (!wpa_s->wnmsleep_used) {
    + 		wpa_printf(MSG_DEBUG,
    +-			   "WNM: Ignore WNM-Sleep Mode Response frame since WNM-Sleep Mode has not been used in this association");
    ++			   "WNM: Ignore WNM-Sleep Mode Response frame since WNM-Sleep Mode operation has not been requested");
    + 		return;
    + 	}
    + 
    +@@ -298,6 +298,8 @@ static void ieee802_11_rx_wnmsleep_resp(struct wpa_supplicant *wpa_s,
    + 		return;
    + 	}
    + 
    ++	wpa_s->wnmsleep_used = 0;
    ++
    + 	if (wnmsleep_ie->status == WNM_STATUS_SLEEP_ACCEPT ||
    + 	    wnmsleep_ie->status == WNM_STATUS_SLEEP_EXIT_ACCEPT_GTK_UPDATE) {
    + 		wpa_printf(MSG_DEBUG, "Successfully recv WNM-Sleep Response "
    +diff --git a/wpa_supplicant/wpa_cli.c b/wpa_supplicant/wpa_cli.c
    +index 36a7a4e..ac1a36f 100644
    +--- a/wpa_supplicant/wpa_cli.c
    ++++ b/wpa_supplicant/wpa_cli.c
    +@@ -861,13 +861,6 @@ static int wpa_cli_cmd_bss_flush(struct wpa_ctrl *ctrl, int argc, char *argv[])
    + }
    + 
    + 
    +-static int wpa_cli_cmd_stkstart(struct wpa_ctrl *ctrl, int argc,
    +-				char *argv[])
    +-{
    +-	return wpa_cli_cmd(ctrl, "STKSTART", 1, argc, argv);
    +-}
    +-
    +-
    + static int wpa_cli_cmd_ft_ds(struct wpa_ctrl *ctrl, int argc, char *argv[])
    + {
    + 	return wpa_cli_cmd(ctrl, "FT_DS", 1, argc, argv);
    +@@ -1582,7 +1575,7 @@ static const char *network_fields[] = {
    + #ifdef CONFIG_IEEE80211W
    + 	"ieee80211w",
    + #endif /* CONFIG_IEEE80211W */
    +-	"peerkey", "mixed_cell", "frequency", "fixed_freq",
    ++	"mixed_cell", "frequency", "fixed_freq",
    + #ifdef CONFIG_MESH
    + 	"mesh_basic_rates", "dot11MeshMaxRetries",
    + 	"dot11MeshRetryTimeout", "dot11MeshConfirmTimeout",
    +@@ -3107,9 +3100,6 @@ static const struct wpa_cli_cmd wpa_cli_commands[] = {
    + 	{ "bss_flush", wpa_cli_cmd_bss_flush, NULL,
    + 	  cli_cmd_flag_none,
    + 	  "<value> = set BSS flush age (0 by default)" },
    +-	{ "stkstart", wpa_cli_cmd_stkstart, NULL,
    +-	  cli_cmd_flag_none,
    +-	  "<addr> = request STK negotiation with <addr>" },
    + 	{ "ft_ds", wpa_cli_cmd_ft_ds, wpa_cli_complete_bss,
    + 	  cli_cmd_flag_none,
    + 	  "<addr> = request over-the-DS FT with <addr>" },
    +diff --git a/wpa_supplicant/wpa_priv.c b/wpa_supplicant/wpa_priv.c
    +index 511df4f..483b6d8 100644
    +--- a/wpa_supplicant/wpa_priv.c
    ++++ b/wpa_supplicant/wpa_priv.c
    +@@ -990,12 +990,6 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event,
    + 				    &data->pmkid_candidate,
    + 				    sizeof(struct pmkid_candidate));
    + 		break;
    +-	case EVENT_STKSTART:
    +-		if (data == NULL)
    +-			return;
    +-		wpa_priv_send_event(iface, PRIVSEP_EVENT_STKSTART,
    +-				    &data->stkstart.peer, ETH_ALEN);
    +-		break;
    + 	case EVENT_FT_RESPONSE:
    + 		wpa_priv_send_ft_response(iface, data);
    + 		break;
    +diff --git a/wpa_supplicant/wpa_supplicant.c b/wpa_supplicant/wpa_supplicant.c
    +index 51bb245..aba93da 100644
    +--- a/wpa_supplicant/wpa_supplicant.c
    ++++ b/wpa_supplicant/wpa_supplicant.c
    +@@ -3238,16 +3238,6 @@ void wpa_supplicant_rx_eapol(void *ctx, const u8 *src_addr,
    + 	wpa_dbg(wpa_s, MSG_DEBUG, "RX EAPOL from " MACSTR, MAC2STR(src_addr));
    + 	wpa_hexdump(MSG_MSGDUMP, "RX EAPOL", buf, len);
    + 
    +-#ifdef CONFIG_PEERKEY
    +-	if (wpa_s->wpa_state > WPA_ASSOCIATED && wpa_s->current_ssid &&
    +-	    wpa_s->current_ssid->peerkey &&
    +-	    !(wpa_s->drv_flags & WPA_DRIVER_FLAGS_4WAY_HANDSHAKE) &&
    +-	    wpa_sm_rx_eapol_peerkey(wpa_s->wpa, src_addr, buf, len) == 1) {
    +-		wpa_dbg(wpa_s, MSG_DEBUG, "RSN: Processed PeerKey EAPOL-Key");
    +-		return;
    +-	}
    +-#endif /* CONFIG_PEERKEY */
    +-
    + 	if (wpa_s->wpa_state < WPA_ASSOCIATED ||
    + 	    (wpa_s->last_eapol_matches_bssid &&
    + #ifdef CONFIG_AP
    +diff --git a/wpa_supplicant/wpa_supplicant.conf b/wpa_supplicant/wpa_supplicant.conf
    +index e55b380..512116a 100644
    +--- a/wpa_supplicant/wpa_supplicant.conf
    ++++ b/wpa_supplicant/wpa_supplicant.conf
    +@@ -865,12 +865,6 @@ fast_reauth=1
    + # hex without quotation, e.g., 0102030405)
    + # wep_tx_keyidx: Default WEP key index (TX) (0..3)
    + #
    +-# peerkey: Whether PeerKey negotiation for direct links (IEEE 802.11e DLS) is
    +-# allowed. This is only used with RSN/WPA2.
    +-# 0 = disabled (default)
    +-# 1 = enabled
    +-#peerkey=1
    +-#
    + # wpa_ptk_rekey: Maximum lifetime for PTK in seconds. This can be used to
    + # enforce rekeying of PTK to mitigate some attacks against TKIP deficiencies.
    + #
    +diff --git a/wpa_supplicant/wpas_glue.c b/wpa_supplicant/wpas_glue.c
    +index f84c8b9..8c1d4fc 100644
    +--- a/wpa_supplicant/wpas_glue.c
    ++++ b/wpa_supplicant/wpas_glue.c
    +@@ -1105,7 +1105,6 @@ void wpa_supplicant_rsn_supp_set_config(struct wpa_supplicant *wpa_s,
    + 	if (ssid) {
    + 		os_memset(&conf, 0, sizeof(conf));
    + 		conf.network_ctx = ssid;
    +-		conf.peerkey_enabled = ssid->peerkey;
    + 		conf.allowed_pairwise_cipher = ssid->pairwise_cipher;
    + #ifdef IEEE8021X_EAPOL
    + 		conf.proactive_key_caching = ssid->proactive_key_caching < 0 ?
    
    From a9a701c1e3a1186c519d579166a04f671090e1f9 Mon Sep 17 00:00:00 2001
    From: AndDiSa <anddisa@googlemail.com>
    Date: Sat, 11 Nov 2017 13:33:03 +0100
    Subject: [PATCH 088/159] update patches
    
    Change-Id: I8f400b51f2e686942bffb0e51b143ab22ee73557
    ---
     build.patch             |  680 +----
     external_libavc.patch   |   34 +-
     external_libhevc.patch  |   18 +
     external_libmpeg2.patch |  301 ++
     frameworks_av.patch     | 6249 ++++++++++++++++++++++++++++++++-------
     frameworks_base.patch   |  121 +
     frameworks_native.patch |  927 +++++-
     system_bt.patch         |  774 +++++
     system_core.patch       |   62 +
     9 files changed, 7386 insertions(+), 1780 deletions(-)
     create mode 100644 external_libmpeg2.patch
    
    diff --git a/build.patch b/build.patch
    index f7d6580..9d73d78 100644
    --- a/build.patch
    +++ b/build.patch
    @@ -323,7 +323,7 @@ index 0000000..ee76dc2
     +ALL_PREBUILT += $(INSTALLED_KERNEL_TARGET)
     +endif
     diff --git a/core/version_defaults.mk b/core/version_defaults.mk
    -index 7c96344..9ff3565 100644
    +index 7c96344..2f05807 100644
     --- a/core/version_defaults.mk
     +++ b/core/version_defaults.mk
     @@ -131,7 +131,7 @@ ifeq "" "$(PLATFORM_SECURITY_PATCH)"
    @@ -331,686 +331,10 @@ index 7c96344..9ff3565 100644
          #  It must match one of the Android Security Patch Level strings of the Public Security Bulletins.
          #  If there is no $PLATFORM_SECURITY_PATCH set, keep it empty.
     -    PLATFORM_SECURITY_PATCH := 2017-08-05
    -+    PLATFORM_SECURITY_PATCH := 2017-10-05
    ++    PLATFORM_SECURITY_PATCH := 2017-11-06
      endif
      
      ifeq "" "$(PLATFORM_BASE_OS)"
    -diff --git a/core/version_defaults_BACKUP_20377.mk b/core/version_defaults_BACKUP_20377.mk
    -new file mode 100644
    -index 0000000..eb97b11
    ---- /dev/null
    -+++ b/core/version_defaults_BACKUP_20377.mk
    -@@ -0,0 +1,164 @@
    -+#
    -+# 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.
    -+#
    -+
    -+#
    -+# Handle various build version information.
    -+#
    -+# Guarantees that the following are defined:
    -+#     PLATFORM_VERSION
    -+#     PLATFORM_SDK_VERSION
    -+#     PLATFORM_VERSION_CODENAME
    -+#     DEFAULT_APP_TARGET_SDK
    -+#     BUILD_ID
    -+#     BUILD_NUMBER
    -+#     BUILD_DATETIME
    -+#     PLATFORM_SECURITY_PATCH
    -+#
    -+
    -+# Look for an optional file containing overrides of the defaults,
    -+# but don't cry if we don't find it.  We could just use -include, but
    -+# the build.prop target also wants INTERNAL_BUILD_ID_MAKEFILE to be set
    -+# if the file exists.
    -+#
    -+INTERNAL_BUILD_ID_MAKEFILE := $(wildcard $(BUILD_SYSTEM)/build_id.mk)
    -+ifneq "" "$(INTERNAL_BUILD_ID_MAKEFILE)"
    -+  include $(INTERNAL_BUILD_ID_MAKEFILE)
    -+endif
    -+
    -+ifeq "" "$(PLATFORM_VERSION)"
    -+  # This is the canonical definition of the platform version,
    -+  # which is the version that we reveal to the end user.
    -+  # Update this value when the platform version changes (rather
    -+  # than overriding it somewhere else).  Can be an arbitrary string.
    -+  PLATFORM_VERSION := 7.1.1
    -+endif
    -+
    -+ifeq "" "$(PLATFORM_SDK_VERSION)"
    -+  # This is the canonical definition of the SDK version, which defines
    -+  # the set of APIs and functionality available in the platform.  It
    -+  # is a single integer that increases monotonically as updates to
    -+  # the SDK are released.  It should only be incremented when the APIs for
    -+  # the new release are frozen (so that developers don't write apps against
    -+  # intermediate builds).  During development, this number remains at the
    -+  # SDK version the branch is based on and PLATFORM_VERSION_CODENAME holds
    -+  # the code-name of the new development work.
    -+  PLATFORM_SDK_VERSION := 25
    -+endif
    -+
    -+ifeq "" "$(PLATFORM_JACK_MIN_SDK_VERSION)"
    -+  # This is definition of the min SDK version given to Jack for the current
    -+  # platform. For released version it should be the same as
    -+  # PLATFORM_SDK_VERSION. During development, this number may be incremented
    -+  # before PLATFORM_SDK_VERSION if the plateform starts to add new java
    -+  # language supports.
    -+  PLATFORM_JACK_MIN_SDK_VERSION := 25
    -+endif
    -+
    -+ifeq "" "$(PLATFORM_VERSION_CODENAME)"
    -+  # This is the current development code-name, if the build is not a final
    -+  # release build.  If this is a final release build, it is simply "REL".
    -+  PLATFORM_VERSION_CODENAME := REL
    -+
    -+  # This is all of the development codenames that are active.  Should be either
    -+  # the same as PLATFORM_VERSION_CODENAME or a comma-separated list of additional
    -+  # codenames after PLATFORM_VERSION_CODENAME.
    -+  PLATFORM_VERSION_ALL_CODENAMES := $(PLATFORM_VERSION_CODENAME)
    -+endif
    -+
    -+ifeq "REL" "$(PLATFORM_VERSION_CODENAME)"
    -+  PLATFORM_PREVIEW_SDK_VERSION := 0
    -+else
    -+  ifeq "" "$(PLATFORM_PREVIEW_SDK_VERSION)"
    -+    # This is the definition of a preview SDK version over and above the current
    -+    # platform SDK version. Unlike the platform SDK version, a higher value
    -+    # for preview SDK version does NOT mean that all prior preview APIs are
    -+    # included. Packages reading this value to determine compatibility with
    -+    # known APIs should check that this value is precisely equal to the preview
    -+    # SDK version the package was built for, otherwise it should fall back to
    -+    # assuming the device can only support APIs as of the previous official
    -+    # public release.
    -+    # This value will always be 0 for release builds.
    -+    PLATFORM_PREVIEW_SDK_VERSION := 0
    -+  endif
    -+endif
    -+
    -+ifeq "" "$(DEFAULT_APP_TARGET_SDK)"
    -+  # This is the default minSdkVersion and targetSdkVersion to use for
    -+  # all .apks created by the build system.  It can be overridden by explicitly
    -+  # setting these in the .apk's AndroidManifest.xml.  It is either the code
    -+  # name of the development build or, if this is a release build, the official
    -+  # SDK version of this release.
    -+  ifeq "REL" "$(PLATFORM_VERSION_CODENAME)"
    -+    DEFAULT_APP_TARGET_SDK := $(PLATFORM_SDK_VERSION)
    -+  else
    -+    DEFAULT_APP_TARGET_SDK := $(PLATFORM_VERSION_CODENAME)
    -+  endif
    -+endif
    -+
    -+ifeq "" "$(PLATFORM_SECURITY_PATCH)"
    -+    #  Used to indicate the security patch that has been applied to the device.
    -+    #  It must signify that the build includes all security patches issued up through the designated Android Public Security Bulletin.
    -+    #  It must be of the form "YYYY-MM-DD" on production devices.
    -+    #  It must match one of the Android Security Patch Level strings of the Public Security Bulletins.
    -+    #  If there is no $PLATFORM_SECURITY_PATCH set, keep it empty.
    -+<<<<<<< HEAD
    -+      PLATFORM_SECURITY_PATCH := 2016-11-05
    -+=======
    -+      PLATFORM_SECURITY_PATCH := 2016-12-05
    -+>>>>>>> android-7.1.1_r1
    -+endif
    -+
    -+ifeq "" "$(PLATFORM_BASE_OS)"
    -+  # Used to indicate the base os applied to the device.
    -+  # Can be an arbitrary string, but must be a single word.
    -+  #
    -+  # If there is no $PLATFORM_BASE_OS set, keep it empty.
    -+  PLATFORM_BASE_OS :=
    -+endif
    -+
    -+ifeq "" "$(BUILD_ID)"
    -+  # Used to signify special builds.  E.g., branches and/or releases,
    -+  # like "M5-RC7".  Can be an arbitrary string, but must be a single
    -+  # word and a valid file name.
    -+  #
    -+  # If there is no BUILD_ID set, make it obvious.
    -+  BUILD_ID := UNKNOWN
    -+endif
    -+
    -+ifeq "" "$(BUILD_DATETIME)"
    -+  # Used to reproduce builds by setting the same time. Must be the number
    -+  # of seconds since the Epoch.
    -+  BUILD_DATETIME := $(shell date +%s)
    -+endif
    -+
    -+ifneq (,$(findstring Darwin,$(shell uname -sm)))
    -+DATE := date -r $(BUILD_DATETIME)
    -+else
    -+DATE := date -d @$(BUILD_DATETIME)
    -+endif
    -+
    -+ifeq "" "$(BUILD_NUMBER)"
    -+  # BUILD_NUMBER should be set to the source control value that
    -+  # represents the current state of the source code.  E.g., a
    -+  # perforce changelist number or a git hash.  Can be an arbitrary string
    -+  # (to allow for source control that uses something other than numbers),
    -+  # but must be a single word and a valid file name.
    -+  #
    -+  # If no BUILD_NUMBER is set, create a useful "I am an engineering build
    -+  # from this date/time" value.  Make it start with a non-digit so that
    -+  # anyone trying to parse it as an integer will probably get "0".
    -+  BUILD_NUMBER := eng.$(shell echo $${USER:0:6}).$(shell $(DATE) +%Y%m%d.%H%M%S)
    -+endif
    -diff --git a/core/version_defaults_BASE_20377.mk b/core/version_defaults_BASE_20377.mk
    -new file mode 100644
    -index 0000000..b0dfc75
    ---- /dev/null
    -+++ b/core/version_defaults_BASE_20377.mk
    -@@ -0,0 +1,168 @@
    -+#
    -+# 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.
    -+#
    -+
    -+#
    -+# Handle various build version information.
    -+#
    -+# Guarantees that the following are defined:
    -+#     PLATFORM_VERSION
    -+#     PLATFORM_SDK_VERSION
    -+#     PLATFORM_VERSION_CODENAME
    -+#     DEFAULT_APP_TARGET_SDK
    -+#     BUILD_ID
    -+#     BUILD_NUMBER
    -+#     BUILD_DATETIME
    -+#     PLATFORM_SECURITY_PATCH
    -+#
    -+
    -+# Look for an optional file containing overrides of the defaults,
    -+# but don't cry if we don't find it.  We could just use -include, but
    -+# the build.prop target also wants INTERNAL_BUILD_ID_MAKEFILE to be set
    -+# if the file exists.
    -+#
    -+INTERNAL_BUILD_ID_MAKEFILE := $(wildcard $(BUILD_SYSTEM)/build_id.mk)
    -+ifneq "" "$(INTERNAL_BUILD_ID_MAKEFILE)"
    -+  include $(INTERNAL_BUILD_ID_MAKEFILE)
    -+endif
    -+
    -+ifeq "" "$(PLATFORM_VERSION)"
    -+  # This is the canonical definition of the platform version,
    -+  # which is the version that we reveal to the end user.
    -+  # Update this value when the platform version changes (rather
    -+  # than overriding it somewhere else).  Can be an arbitrary string.
    -+  PLATFORM_VERSION := 7.1
    -+endif
    -+
    -+ifeq "" "$(PLATFORM_SDK_VERSION)"
    -+  # This is the canonical definition of the SDK version, which defines
    -+  # the set of APIs and functionality available in the platform.  It
    -+  # is a single integer that increases monotonically as updates to
    -+  # the SDK are released.  It should only be incremented when the APIs for
    -+  # the new release are frozen (so that developers don't write apps against
    -+  # intermediate builds).  During development, this number remains at the
    -+  # SDK version the branch is based on and PLATFORM_VERSION_CODENAME holds
    -+  # the code-name of the new development work.
    -+  PLATFORM_SDK_VERSION := 25
    -+endif
    -+
    -+ifeq "" "$(PLATFORM_JACK_MIN_SDK_VERSION)"
    -+  # This is definition of the min SDK version given to Jack for the current
    -+  # platform. For released version it should be the same as
    -+  # PLATFORM_SDK_VERSION. During development, this number may be incremented
    -+  # before PLATFORM_SDK_VERSION if the plateform starts to add new java
    -+  # language supports.
    -+  PLATFORM_JACK_MIN_SDK_VERSION := 25
    -+endif
    -+
    -+ifeq "" "$(PLATFORM_VERSION_CODENAME)"
    -+  # This is the current development code-name, if the build is not a final
    -+  # release build.  If this is a final release build, it is simply "REL".
    -+  PLATFORM_VERSION_CODENAME := REL
    -+
    -+  # This is all of the development codenames that are active.  Should be either
    -+  # the same as PLATFORM_VERSION_CODENAME or a comma-separated list of additional
    -+  # codenames after PLATFORM_VERSION_CODENAME.
    -+  PLATFORM_VERSION_ALL_CODENAMES := $(PLATFORM_VERSION_CODENAME)
    -+endif
    -+
    -+ifeq "REL" "$(PLATFORM_VERSION_CODENAME)"
    -+  PLATFORM_PREVIEW_SDK_VERSION := 0
    -+else
    -+  ifeq "" "$(PLATFORM_PREVIEW_SDK_VERSION)"
    -+    # This is the definition of a preview SDK version over and above the current
    -+    # platform SDK version. Unlike the platform SDK version, a higher value
    -+    # for preview SDK version does NOT mean that all prior preview APIs are
    -+    # included. Packages reading this value to determine compatibility with
    -+    # known APIs should check that this value is precisely equal to the preview
    -+    # SDK version the package was built for, otherwise it should fall back to
    -+    # assuming the device can only support APIs as of the previous official
    -+    # public release.
    -+    # This value will always be 0 for release builds.
    -+    PLATFORM_PREVIEW_SDK_VERSION := 0
    -+  endif
    -+endif
    -+
    -+ifeq "" "$(DEFAULT_APP_TARGET_SDK)"
    -+  # This is the default minSdkVersion and targetSdkVersion to use for
    -+  # all .apks created by the build system.  It can be overridden by explicitly
    -+  # setting these in the .apk's AndroidManifest.xml.  It is either the code
    -+  # name of the development build or, if this is a release build, the official
    -+  # SDK version of this release.
    -+  ifeq "REL" "$(PLATFORM_VERSION_CODENAME)"
    -+    DEFAULT_APP_TARGET_SDK := $(PLATFORM_SDK_VERSION)
    -+  else
    -+    DEFAULT_APP_TARGET_SDK := $(PLATFORM_VERSION_CODENAME)
    -+  endif
    -+endif
    -+
    -+ifeq "" "$(PLATFORM_SECURITY_PATCH)"
    -+<<<<<<< Temporary merge branch 1
    -+  # Used to indicate the security patch that has been applied to the device.
    -+  # Must be of the form "YYYY-MM-DD" on production devices.
    -+  #
    -+  # If there is no $PLATFORM_SECURITY_PATCH set, keep it empty.
    -+  PLATFORM_SECURITY_PATCH := 2016-10-05
    -+=======
    -+    #  Used to indicate the security patch that has been applied to the device.
    -+    #  It must signify that the build includes all security patches issued up through the designated Android Public Security Bulletin.
    -+    #  It must be of the form "YYYY-MM-DD" on production devices.
    -+    #  It must match one of the Android Security Patch Level strings of the Public Security Bulletins.
    -+    #  If there is no $PLATFORM_SECURITY_PATCH set, keep it empty.
    -+      PLATFORM_SECURITY_PATCH := 2016-10-05
    -+>>>>>>> Temporary merge branch 2
    -+endif
    -+
    -+ifeq "" "$(PLATFORM_BASE_OS)"
    -+  # Used to indicate the base os applied to the device.
    -+  # Can be an arbitrary string, but must be a single word.
    -+  #
    -+  # If there is no $PLATFORM_BASE_OS set, keep it empty.
    -+  PLATFORM_BASE_OS :=
    -+endif
    -+
    -+ifeq "" "$(BUILD_ID)"
    -+  # Used to signify special builds.  E.g., branches and/or releases,
    -+  # like "M5-RC7".  Can be an arbitrary string, but must be a single
    -+  # word and a valid file name.
    -+  #
    -+  # If there is no BUILD_ID set, make it obvious.
    -+  BUILD_ID := UNKNOWN
    -+endif
    -+
    -+ifeq "" "$(BUILD_DATETIME)"
    -+  # Used to reproduce builds by setting the same time. Must be the number
    -+  # of seconds since the Epoch.
    -+  BUILD_DATETIME := $(shell date +%s)
    -+endif
    -+
    -+ifneq (,$(findstring Darwin,$(shell uname -sm)))
    -+DATE := date -r $(BUILD_DATETIME)
    -+else
    -+DATE := date -d @$(BUILD_DATETIME)
    -+endif
    -+
    -+ifeq "" "$(BUILD_NUMBER)"
    -+  # BUILD_NUMBER should be set to the source control value that
    -+  # represents the current state of the source code.  E.g., a
    -+  # perforce changelist number or a git hash.  Can be an arbitrary string
    -+  # (to allow for source control that uses something other than numbers),
    -+  # but must be a single word and a valid file name.
    -+  #
    -+  # If no BUILD_NUMBER is set, create a useful "I am an engineering build
    -+  # from this date/time" value.  Make it start with a non-digit so that
    -+  # anyone trying to parse it as an integer will probably get "0".
    -+  BUILD_NUMBER := eng.$(shell echo $${USER:0:6}).$(shell $(DATE) +%Y%m%d.%H%M%S)
    -+endif
    -diff --git a/core/version_defaults_LOCAL_20377.mk b/core/version_defaults_LOCAL_20377.mk
    -new file mode 100644
    -index 0000000..47dc01c
    ---- /dev/null
    -+++ b/core/version_defaults_LOCAL_20377.mk
    -@@ -0,0 +1,160 @@
    -+#
    -+# 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.
    -+#
    -+
    -+#
    -+# Handle various build version information.
    -+#
    -+# Guarantees that the following are defined:
    -+#     PLATFORM_VERSION
    -+#     PLATFORM_SDK_VERSION
    -+#     PLATFORM_VERSION_CODENAME
    -+#     DEFAULT_APP_TARGET_SDK
    -+#     BUILD_ID
    -+#     BUILD_NUMBER
    -+#     BUILD_DATETIME
    -+#     PLATFORM_SECURITY_PATCH
    -+#
    -+
    -+# Look for an optional file containing overrides of the defaults,
    -+# but don't cry if we don't find it.  We could just use -include, but
    -+# the build.prop target also wants INTERNAL_BUILD_ID_MAKEFILE to be set
    -+# if the file exists.
    -+#
    -+INTERNAL_BUILD_ID_MAKEFILE := $(wildcard $(BUILD_SYSTEM)/build_id.mk)
    -+ifneq "" "$(INTERNAL_BUILD_ID_MAKEFILE)"
    -+  include $(INTERNAL_BUILD_ID_MAKEFILE)
    -+endif
    -+
    -+ifeq "" "$(PLATFORM_VERSION)"
    -+  # This is the canonical definition of the platform version,
    -+  # which is the version that we reveal to the end user.
    -+  # Update this value when the platform version changes (rather
    -+  # than overriding it somewhere else).  Can be an arbitrary string.
    -+  PLATFORM_VERSION := 7.1
    -+endif
    -+
    -+ifeq "" "$(PLATFORM_SDK_VERSION)"
    -+  # This is the canonical definition of the SDK version, which defines
    -+  # the set of APIs and functionality available in the platform.  It
    -+  # is a single integer that increases monotonically as updates to
    -+  # the SDK are released.  It should only be incremented when the APIs for
    -+  # the new release are frozen (so that developers don't write apps against
    -+  # intermediate builds).  During development, this number remains at the
    -+  # SDK version the branch is based on and PLATFORM_VERSION_CODENAME holds
    -+  # the code-name of the new development work.
    -+  PLATFORM_SDK_VERSION := 25
    -+endif
    -+
    -+ifeq "" "$(PLATFORM_JACK_MIN_SDK_VERSION)"
    -+  # This is definition of the min SDK version given to Jack for the current
    -+  # platform. For released version it should be the same as
    -+  # PLATFORM_SDK_VERSION. During development, this number may be incremented
    -+  # before PLATFORM_SDK_VERSION if the plateform starts to add new java
    -+  # language supports.
    -+  PLATFORM_JACK_MIN_SDK_VERSION := 25
    -+endif
    -+
    -+ifeq "" "$(PLATFORM_VERSION_CODENAME)"
    -+  # This is the current development code-name, if the build is not a final
    -+  # release build.  If this is a final release build, it is simply "REL".
    -+  PLATFORM_VERSION_CODENAME := REL
    -+
    -+  # This is all of the development codenames that are active.  Should be either
    -+  # the same as PLATFORM_VERSION_CODENAME or a comma-separated list of additional
    -+  # codenames after PLATFORM_VERSION_CODENAME.
    -+  PLATFORM_VERSION_ALL_CODENAMES := $(PLATFORM_VERSION_CODENAME)
    -+endif
    -+
    -+ifeq "REL" "$(PLATFORM_VERSION_CODENAME)"
    -+  PLATFORM_PREVIEW_SDK_VERSION := 0
    -+else
    -+  ifeq "" "$(PLATFORM_PREVIEW_SDK_VERSION)"
    -+    # This is the definition of a preview SDK version over and above the current
    -+    # platform SDK version. Unlike the platform SDK version, a higher value
    -+    # for preview SDK version does NOT mean that all prior preview APIs are
    -+    # included. Packages reading this value to determine compatibility with
    -+    # known APIs should check that this value is precisely equal to the preview
    -+    # SDK version the package was built for, otherwise it should fall back to
    -+    # assuming the device can only support APIs as of the previous official
    -+    # public release.
    -+    # This value will always be 0 for release builds.
    -+    PLATFORM_PREVIEW_SDK_VERSION := 0
    -+  endif
    -+endif
    -+
    -+ifeq "" "$(DEFAULT_APP_TARGET_SDK)"
    -+  # This is the default minSdkVersion and targetSdkVersion to use for
    -+  # all .apks created by the build system.  It can be overridden by explicitly
    -+  # setting these in the .apk's AndroidManifest.xml.  It is either the code
    -+  # name of the development build or, if this is a release build, the official
    -+  # SDK version of this release.
    -+  ifeq "REL" "$(PLATFORM_VERSION_CODENAME)"
    -+    DEFAULT_APP_TARGET_SDK := $(PLATFORM_SDK_VERSION)
    -+  else
    -+    DEFAULT_APP_TARGET_SDK := $(PLATFORM_VERSION_CODENAME)
    -+  endif
    -+endif
    -+
    -+ifeq "" "$(PLATFORM_SECURITY_PATCH)"
    -+    #  Used to indicate the security patch that has been applied to the device.
    -+    #  It must signify that the build includes all security patches issued up through the designated Android Public Security Bulletin.
    -+    #  It must be of the form "YYYY-MM-DD" on production devices.
    -+    #  It must match one of the Android Security Patch Level strings of the Public Security Bulletins.
    -+    #  If there is no $PLATFORM_SECURITY_PATCH set, keep it empty.
    -+      PLATFORM_SECURITY_PATCH := 2016-11-05
    -+endif
    -+
    -+ifeq "" "$(PLATFORM_BASE_OS)"
    -+  # Used to indicate the base os applied to the device.
    -+  # Can be an arbitrary string, but must be a single word.
    -+  #
    -+  # If there is no $PLATFORM_BASE_OS set, keep it empty.
    -+  PLATFORM_BASE_OS :=
    -+endif
    -+
    -+ifeq "" "$(BUILD_ID)"
    -+  # Used to signify special builds.  E.g., branches and/or releases,
    -+  # like "M5-RC7".  Can be an arbitrary string, but must be a single
    -+  # word and a valid file name.
    -+  #
    -+  # If there is no BUILD_ID set, make it obvious.
    -+  BUILD_ID := UNKNOWN
    -+endif
    -+
    -+ifeq "" "$(BUILD_DATETIME)"
    -+  # Used to reproduce builds by setting the same time. Must be the number
    -+  # of seconds since the Epoch.
    -+  BUILD_DATETIME := $(shell date +%s)
    -+endif
    -+
    -+ifneq (,$(findstring Darwin,$(shell uname -sm)))
    -+DATE := date -r $(BUILD_DATETIME)
    -+else
    -+DATE := date -d @$(BUILD_DATETIME)
    -+endif
    -+
    -+ifeq "" "$(BUILD_NUMBER)"
    -+  # BUILD_NUMBER should be set to the source control value that
    -+  # represents the current state of the source code.  E.g., a
    -+  # perforce changelist number or a git hash.  Can be an arbitrary string
    -+  # (to allow for source control that uses something other than numbers),
    -+  # but must be a single word and a valid file name.
    -+  #
    -+  # If no BUILD_NUMBER is set, create a useful "I am an engineering build
    -+  # from this date/time" value.  Make it start with a non-digit so that
    -+  # anyone trying to parse it as an integer will probably get "0".
    -+  BUILD_NUMBER := eng.$(shell echo $${USER:0:6}).$(shell $(DATE) +%Y%m%d.%H%M%S)
    -+endif
    -diff --git a/core/version_defaults_REMOTE_20377.mk b/core/version_defaults_REMOTE_20377.mk
    -new file mode 100644
    -index 0000000..2c8a21f
    ---- /dev/null
    -+++ b/core/version_defaults_REMOTE_20377.mk
    -@@ -0,0 +1,160 @@
    -+#
    -+# 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.
    -+#
    -+
    -+#
    -+# Handle various build version information.
    -+#
    -+# Guarantees that the following are defined:
    -+#     PLATFORM_VERSION
    -+#     PLATFORM_SDK_VERSION
    -+#     PLATFORM_VERSION_CODENAME
    -+#     DEFAULT_APP_TARGET_SDK
    -+#     BUILD_ID
    -+#     BUILD_NUMBER
    -+#     BUILD_DATETIME
    -+#     PLATFORM_SECURITY_PATCH
    -+#
    -+
    -+# Look for an optional file containing overrides of the defaults,
    -+# but don't cry if we don't find it.  We could just use -include, but
    -+# the build.prop target also wants INTERNAL_BUILD_ID_MAKEFILE to be set
    -+# if the file exists.
    -+#
    -+INTERNAL_BUILD_ID_MAKEFILE := $(wildcard $(BUILD_SYSTEM)/build_id.mk)
    -+ifneq "" "$(INTERNAL_BUILD_ID_MAKEFILE)"
    -+  include $(INTERNAL_BUILD_ID_MAKEFILE)
    -+endif
    -+
    -+ifeq "" "$(PLATFORM_VERSION)"
    -+  # This is the canonical definition of the platform version,
    -+  # which is the version that we reveal to the end user.
    -+  # Update this value when the platform version changes (rather
    -+  # than overriding it somewhere else).  Can be an arbitrary string.
    -+  PLATFORM_VERSION := 7.1.1
    -+endif
    -+
    -+ifeq "" "$(PLATFORM_SDK_VERSION)"
    -+  # This is the canonical definition of the SDK version, which defines
    -+  # the set of APIs and functionality available in the platform.  It
    -+  # is a single integer that increases monotonically as updates to
    -+  # the SDK are released.  It should only be incremented when the APIs for
    -+  # the new release are frozen (so that developers don't write apps against
    -+  # intermediate builds).  During development, this number remains at the
    -+  # SDK version the branch is based on and PLATFORM_VERSION_CODENAME holds
    -+  # the code-name of the new development work.
    -+  PLATFORM_SDK_VERSION := 25
    -+endif
    -+
    -+ifeq "" "$(PLATFORM_JACK_MIN_SDK_VERSION)"
    -+  # This is definition of the min SDK version given to Jack for the current
    -+  # platform. For released version it should be the same as
    -+  # PLATFORM_SDK_VERSION. During development, this number may be incremented
    -+  # before PLATFORM_SDK_VERSION if the plateform starts to add new java
    -+  # language supports.
    -+  PLATFORM_JACK_MIN_SDK_VERSION := 25
    -+endif
    -+
    -+ifeq "" "$(PLATFORM_VERSION_CODENAME)"
    -+  # This is the current development code-name, if the build is not a final
    -+  # release build.  If this is a final release build, it is simply "REL".
    -+  PLATFORM_VERSION_CODENAME := REL
    -+
    -+  # This is all of the development codenames that are active.  Should be either
    -+  # the same as PLATFORM_VERSION_CODENAME or a comma-separated list of additional
    -+  # codenames after PLATFORM_VERSION_CODENAME.
    -+  PLATFORM_VERSION_ALL_CODENAMES := $(PLATFORM_VERSION_CODENAME)
    -+endif
    -+
    -+ifeq "REL" "$(PLATFORM_VERSION_CODENAME)"
    -+  PLATFORM_PREVIEW_SDK_VERSION := 0
    -+else
    -+  ifeq "" "$(PLATFORM_PREVIEW_SDK_VERSION)"
    -+    # This is the definition of a preview SDK version over and above the current
    -+    # platform SDK version. Unlike the platform SDK version, a higher value
    -+    # for preview SDK version does NOT mean that all prior preview APIs are
    -+    # included. Packages reading this value to determine compatibility with
    -+    # known APIs should check that this value is precisely equal to the preview
    -+    # SDK version the package was built for, otherwise it should fall back to
    -+    # assuming the device can only support APIs as of the previous official
    -+    # public release.
    -+    # This value will always be 0 for release builds.
    -+    PLATFORM_PREVIEW_SDK_VERSION := 0
    -+  endif
    -+endif
    -+
    -+ifeq "" "$(DEFAULT_APP_TARGET_SDK)"
    -+  # This is the default minSdkVersion and targetSdkVersion to use for
    -+  # all .apks created by the build system.  It can be overridden by explicitly
    -+  # setting these in the .apk's AndroidManifest.xml.  It is either the code
    -+  # name of the development build or, if this is a release build, the official
    -+  # SDK version of this release.
    -+  ifeq "REL" "$(PLATFORM_VERSION_CODENAME)"
    -+    DEFAULT_APP_TARGET_SDK := $(PLATFORM_SDK_VERSION)
    -+  else
    -+    DEFAULT_APP_TARGET_SDK := $(PLATFORM_VERSION_CODENAME)
    -+  endif
    -+endif
    -+
    -+ifeq "" "$(PLATFORM_SECURITY_PATCH)"
    -+    #  Used to indicate the security patch that has been applied to the device.
    -+    #  It must signify that the build includes all security patches issued up through the designated Android Public Security Bulletin.
    -+    #  It must be of the form "YYYY-MM-DD" on production devices.
    -+    #  It must match one of the Android Security Patch Level strings of the Public Security Bulletins.
    -+    #  If there is no $PLATFORM_SECURITY_PATCH set, keep it empty.
    -+      PLATFORM_SECURITY_PATCH := 2016-12-05
    -+endif
    -+
    -+ifeq "" "$(PLATFORM_BASE_OS)"
    -+  # Used to indicate the base os applied to the device.
    -+  # Can be an arbitrary string, but must be a single word.
    -+  #
    -+  # If there is no $PLATFORM_BASE_OS set, keep it empty.
    -+  PLATFORM_BASE_OS :=
    -+endif
    -+
    -+ifeq "" "$(BUILD_ID)"
    -+  # Used to signify special builds.  E.g., branches and/or releases,
    -+  # like "M5-RC7".  Can be an arbitrary string, but must be a single
    -+  # word and a valid file name.
    -+  #
    -+  # If there is no BUILD_ID set, make it obvious.
    -+  BUILD_ID := UNKNOWN
    -+endif
    -+
    -+ifeq "" "$(BUILD_DATETIME)"
    -+  # Used to reproduce builds by setting the same time. Must be the number
    -+  # of seconds since the Epoch.
    -+  BUILD_DATETIME := $(shell date +%s)
    -+endif
    -+
    -+ifneq (,$(findstring Darwin,$(shell uname -sm)))
    -+DATE := date -r $(BUILD_DATETIME)
    -+else
    -+DATE := date -d @$(BUILD_DATETIME)
    -+endif
    -+
    -+ifeq "" "$(BUILD_NUMBER)"
    -+  # BUILD_NUMBER should be set to the source control value that
    -+  # represents the current state of the source code.  E.g., a
    -+  # perforce changelist number or a git hash.  Can be an arbitrary string
    -+  # (to allow for source control that uses something other than numbers),
    -+  # but must be a single word and a valid file name.
    -+  #
    -+  # If no BUILD_NUMBER is set, create a useful "I am an engineering build
    -+  # from this date/time" value.  Make it start with a non-digit so that
    -+  # anyone trying to parse it as an integer will probably get "0".
    -+  BUILD_NUMBER := eng.$(shell echo $${USER:0:6}).$(shell $(DATE) +%Y%m%d.%H%M%S)
    -+endif
     diff --git a/target/product/core.mk b/target/product/core.mk
     index 0a4e0fd..5508c12 100644
     --- a/target/product/core.mk
    diff --git a/external_libavc.patch b/external_libavc.patch
    index ae21b4f..f425abb 100644
    --- a/external_libavc.patch
    +++ b/external_libavc.patch
    @@ -1,5 +1,5 @@
     diff --git a/decoder/ih264d_api.c b/decoder/ih264d_api.c
    -index 2cde456..7c3f750 100644
    +index 2cde456..d86aaee 100644
     --- a/decoder/ih264d_api.c
     +++ b/decoder/ih264d_api.c
     @@ -1623,6 +1623,89 @@ UWORD32 ih264d_map_error(UWORD32 i4_err_status)
    @@ -116,7 +116,35 @@ index 2cde456..7c3f750 100644
                  {
                      ps_dec->u4_slice_start_code_found = 0;
                      break;
    -@@ -2843,27 +2934,15 @@ WORD32 ih264d_get_buf_info(iv_obj_t *dec_hdl, void *pv_api_ip, void *pv_api_op)
    +@@ -2148,7 +2239,7 @@ WORD32 ih264d_video_decode(iv_obj_t *dec_hdl, void *pv_api_ip, void *pv_api_op)
    +     }
    +     while(( header_data_left == 1)||(frame_data_left == 1));
    + 
    +-    if((ps_dec->u4_slice_start_code_found == 1)
    ++    if((ps_dec->u4_pic_buf_got == 1)
    +             && (ret != IVD_MEM_ALLOC_FAILED)
    +             && ps_dec->u2_total_mbs_coded < ps_dec->u2_frm_ht_in_mbs * ps_dec->u2_frm_wd_in_mbs)
    +     {
    +@@ -2290,7 +2381,7 @@ WORD32 ih264d_video_decode(iv_obj_t *dec_hdl, void *pv_api_ip, void *pv_api_op)
    + 
    +     }
    + 
    +-    if((ps_dec->u4_slice_start_code_found == 1)
    ++    if((ps_dec->u4_pic_buf_got == 1)
    +                     && (ERROR_DANGLING_FIELD_IN_PIC != i4_err_status))
    +     {
    +         /*
    +@@ -2316,8 +2407,7 @@ WORD32 ih264d_video_decode(iv_obj_t *dec_hdl, void *pv_api_ip, void *pv_api_op)
    +         /* if new frame in not found (if we are still getting slices from previous frame)
    +          * ih264d_deblock_display is not called. Such frames will not be added to reference /display
    +          */
    +-        if (((ps_dec->ps_dec_err_status->u1_err_flag & REJECT_CUR_PIC) == 0)
    +-                && (ps_dec->u4_pic_buf_got == 1))
    ++        if ((ps_dec->ps_dec_err_status->u1_err_flag & REJECT_CUR_PIC) == 0)
    +         {
    +             /* Calling Function to deblock Picture and Display */
    +             ret = ih264d_deblock_display(ps_dec);
    +@@ -2843,27 +2933,15 @@ WORD32 ih264d_get_buf_info(iv_obj_t *dec_hdl, void *pv_api_ip, void *pv_api_op)
          UWORD16 pic_wd, pic_ht;
          ivd_ctl_getbufinfo_op_t *ps_ctl_op =
                          (ivd_ctl_getbufinfo_op_t*)pv_api_op;
    @@ -146,7 +174,7 @@ index 2cde456..7c3f750 100644
      
          ps_ctl_op->u4_num_disp_bufs = 1;
      
    -@@ -2930,37 +3009,15 @@ WORD32 ih264d_get_buf_info(iv_obj_t *dec_hdl, void *pv_api_ip, void *pv_api_op)
    +@@ -2930,37 +3008,15 @@ WORD32 ih264d_get_buf_info(iv_obj_t *dec_hdl, void *pv_api_ip, void *pv_api_op)
                              ps_ctl_op->u4_num_disp_bufs, 32);
          }
      
    diff --git a/external_libhevc.patch b/external_libhevc.patch
    index ff18293..cace2c6 100644
    --- a/external_libhevc.patch
    +++ b/external_libhevc.patch
    @@ -42,6 +42,24 @@ index 93d2ad4..baa6375 100644
      
      }hrd_params_t;
      
    +diff --git a/decoder/ihevcd_api.c b/decoder/ihevcd_api.c
    +index c661083..51e9670 100644
    +--- a/decoder/ihevcd_api.c
    ++++ b/decoder/ihevcd_api.c
    +@@ -1867,10 +1867,10 @@ WORD32 ihevcd_allocate_dynamic_bufs(codec_t *ps_codec)
    +     }
    + 
    +     /* Max CTBs in a row */
    +-    size  = wd / MIN_CTB_SIZE + 2 /* Top row and bottom row extra. This ensures accessing left,top in first row
    +-                                              and right in last row will not result in invalid access*/;
    ++    size  = wd / MIN_CTB_SIZE;
    +     /* Max CTBs in a column */
    +-    size *= ht / MIN_CTB_SIZE;
    ++    size *= (ht / MIN_CTB_SIZE + 2) /* Top row and bottom row extra. This ensures accessing left,top in first row
    ++                                              and right in last row will not result in invalid access*/;
    + 
    +     size *= sizeof(UWORD16);
    +     pv_buf = ps_codec->pf_aligned_alloc(pv_mem_ctxt, 128, size);
     diff --git a/decoder/ihevcd_decode.c b/decoder/ihevcd_decode.c
     index d656519..7b82e84 100644
     --- a/decoder/ihevcd_decode.c
    diff --git a/external_libmpeg2.patch b/external_libmpeg2.patch
    new file mode 100644
    index 0000000..cace2c6
    --- /dev/null
    +++ b/external_libmpeg2.patch
    @@ -0,0 +1,301 @@
    +diff --git a/common/ihevc_structs.h b/common/ihevc_structs.h
    +index 93d2ad4..baa6375 100644
    +--- a/common/ihevc_structs.h
    ++++ b/common/ihevc_structs.h
    +@@ -644,33 +644,33 @@ typedef struct
    +      * if 1, , for the highest temporal sub-layers, the temporal distance between the HRD output times
    +      * of consecutive pictures in output order is constrained refer to Table E-6
    +      */
    +-    UWORD8 au1_fixed_pic_rate_general_flag[6];
    ++    UWORD8 au1_fixed_pic_rate_general_flag[VPS_MAX_SUB_LAYERS];
    + 
    +-    UWORD8 au1_fixed_pic_rate_within_cvs_flag[6];
    ++    UWORD8 au1_fixed_pic_rate_within_cvs_flag[VPS_MAX_SUB_LAYERS];
    + 
    +     /**
    +      * if 1, , for the highest temporal sub-layers, the temporal distance (in clock ticks) between the
    +      * element units that specify HRD output times of consecutive pictures in output order is constrained
    +      * refer to Table E-6
    +      */
    +-    UWORD8 au1_elemental_duration_in_tc_minus1[6];
    ++    UWORD8 au1_elemental_duration_in_tc_minus1[VPS_MAX_SUB_LAYERS];
    + 
    +     /**
    +      * specifies the HRD operational mode
    +      */
    +-    UWORD8 au1_low_delay_hrd_flag[6];
    ++    UWORD8 au1_low_delay_hrd_flag[VPS_MAX_SUB_LAYERS];
    + 
    +     /**
    +      * 1 specifies the number of alternative CPB specifications in the
    +      * bitstream of the cvs when HighestTid is equal to i
    +      */
    +-    UWORD8 au1_cpb_cnt_minus1[6];
    ++    UWORD8 au1_cpb_cnt_minus1[VPS_MAX_SUB_LAYERS];
    + 
    + 
    +     /**
    +      * VUI level Sub-layer HRD parameters
    +      */
    +-    sub_lyr_hrd_params_t as_sub_layer_hrd_params[6];
    ++    sub_lyr_hrd_params_t as_sub_layer_hrd_params[VPS_MAX_SUB_LAYERS];
    + 
    + }hrd_params_t;
    + 
    +diff --git a/decoder/ihevcd_api.c b/decoder/ihevcd_api.c
    +index c661083..51e9670 100644
    +--- a/decoder/ihevcd_api.c
    ++++ b/decoder/ihevcd_api.c
    +@@ -1867,10 +1867,10 @@ WORD32 ihevcd_allocate_dynamic_bufs(codec_t *ps_codec)
    +     }
    + 
    +     /* Max CTBs in a row */
    +-    size  = wd / MIN_CTB_SIZE + 2 /* Top row and bottom row extra. This ensures accessing left,top in first row
    +-                                              and right in last row will not result in invalid access*/;
    ++    size  = wd / MIN_CTB_SIZE;
    +     /* Max CTBs in a column */
    +-    size *= ht / MIN_CTB_SIZE;
    ++    size *= (ht / MIN_CTB_SIZE + 2) /* Top row and bottom row extra. This ensures accessing left,top in first row
    ++                                              and right in last row will not result in invalid access*/;
    + 
    +     size *= sizeof(UWORD16);
    +     pv_buf = ps_codec->pf_aligned_alloc(pv_mem_ctxt, 128, size);
    +diff --git a/decoder/ihevcd_decode.c b/decoder/ihevcd_decode.c
    +index d656519..7b82e84 100644
    +--- a/decoder/ihevcd_decode.c
    ++++ b/decoder/ihevcd_decode.c
    +@@ -81,6 +81,7 @@
    + #define NUM_FRAMES_LIMIT 0x7FFFFFFF
    + #endif
    + 
    ++IHEVCD_ERROR_T ihevcd_check_out_buf_size(codec_t *ps_codec);
    + IHEVCD_ERROR_T ihevcd_fmt_conv(codec_t *ps_codec,
    +                                process_ctxt_t *ps_proc,
    +                                UWORD8 *pu1_y_dst,
    +@@ -471,6 +472,10 @@ WORD32 ihevcd_decode(iv_obj_t *ps_codec_obj, void *pv_api_ip, void *pv_api_op)
    +                 ihevcd_init_proc_ctxt(ps_proc, 0);
    +             }
    + 
    ++            /* Output buffer check */
    ++            ret = ihevcd_check_out_buf_size(ps_codec);
    ++            RETURN_IF((ret != (IHEVCD_ERROR_T)IHEVCD_SUCCESS), ret);
    ++
    +             /* Set remaining number of rows to be processed */
    +             ret = ihevcd_fmt_conv(ps_codec, &ps_codec->as_process[prev_proc_idx],
    +                                   ps_dec_ip->s_out_buffer.pu1_bufs[0],
    +@@ -628,7 +633,6 @@ WORD32 ihevcd_decode(iv_obj_t *ps_codec_obj, void *pv_api_ip, void *pv_api_op)
    + 
    +         if(IHEVCD_IGNORE_SLICE == ret)
    +         {
    +-            ps_codec->s_parse.i4_cur_slice_idx = MAX(0, (ps_codec->s_parse.i4_cur_slice_idx - 1));
    +             ps_codec->pu1_inp_bitsbuf += (nal_ofst + nal_len);
    +             ps_codec->i4_bytes_remaining -= (nal_ofst + nal_len);
    + 
    +diff --git a/decoder/ihevcd_parse_headers.c b/decoder/ihevcd_parse_headers.c
    +index c0f1564..06f35a3 100644
    +--- a/decoder/ihevcd_parse_headers.c
    ++++ b/decoder/ihevcd_parse_headers.c
    +@@ -1285,15 +1285,31 @@ IHEVCD_ERROR_T ihevcd_parse_sps(codec_t *ps_codec)
    +     {
    + 
    +         UEV_PARSE("pic_crop_left_offset", value, ps_bitstrm);
    ++        if (value >= ps_sps->i2_pic_width_in_luma_samples)
    ++        {
    ++            return IHEVCD_INVALID_PARAMETER;
    ++        }
    +         ps_sps->i2_pic_crop_left_offset = value;
    + 
    +         UEV_PARSE("pic_crop_right_offset", value, ps_bitstrm);
    ++        if (value >= ps_sps->i2_pic_width_in_luma_samples)
    ++        {
    ++            return IHEVCD_INVALID_PARAMETER;
    ++        }
    +         ps_sps->i2_pic_crop_right_offset = value;
    + 
    +         UEV_PARSE("pic_crop_top_offset", value, ps_bitstrm);
    ++        if (value >= ps_sps->i2_pic_height_in_luma_samples)
    ++        {
    ++            return IHEVCD_INVALID_PARAMETER;
    ++        }
    +         ps_sps->i2_pic_crop_top_offset = value;
    + 
    +         UEV_PARSE("pic_crop_bottom_offset", value, ps_bitstrm);
    ++        if (value >= ps_sps->i2_pic_height_in_luma_samples)
    ++        {
    ++            return IHEVCD_INVALID_PARAMETER;
    ++        }
    +         ps_sps->i2_pic_crop_bottom_offset = value;
    +     }
    +     else
    +@@ -1797,6 +1813,19 @@ IHEVCD_ERROR_T ihevcd_parse_pps(codec_t *ps_codec)
    +     BITS_PARSE("tiles_enabled_flag", value, ps_bitstrm, 1);
    +     ps_pps->i1_tiles_enabled_flag = value;
    + 
    ++    /* When tiles are enabled and width or height is >= 4096,
    ++     * CTB Size should at least be 32. 16x16 CTBs can result
    ++     * in tile position greater than 255 for 4096,
    ++     * which decoder does not support.
    ++     */
    ++    if((ps_pps->i1_tiles_enabled_flag) &&
    ++                    (ps_sps->i1_log2_ctb_size == 4) &&
    ++                    ((ps_sps->i2_pic_width_in_luma_samples >= 4096) ||
    ++                    (ps_sps->i2_pic_height_in_luma_samples >= 4096)))
    ++    {
    ++        return IHEVCD_INVALID_HEADER;
    ++    }
    ++
    +     BITS_PARSE("entropy_coding_sync_enabled_flag", value, ps_bitstrm, 1);
    +     ps_pps->i1_entropy_coding_sync_enabled_flag = value;
    + 
    +diff --git a/decoder/ihevcd_parse_slice.c b/decoder/ihevcd_parse_slice.c
    +index 126b14c..9f92a0d 100644
    +--- a/decoder/ihevcd_parse_slice.c
    ++++ b/decoder/ihevcd_parse_slice.c
    +@@ -2708,6 +2708,17 @@ IHEVCD_ERROR_T ihevcd_parse_slice_data(codec_t *ps_codec)
    +         {
    +             tu_t *ps_tu = ps_codec->s_parse.ps_tu;
    +             pu_t *ps_pu = ps_codec->s_parse.ps_pu;
    ++            WORD32 pu_skip_wd, pu_skip_ht;
    ++            WORD32 rows_remaining, cols_remaining;
    ++
    ++            /* Set pu wd and ht based on whether the ctb is complete or not */
    ++            rows_remaining = ps_sps->i2_pic_height_in_luma_samples
    ++                            - (ps_codec->s_parse.i4_ctb_y << ps_sps->i1_log2_ctb_size);
    ++            pu_skip_ht = MIN(ctb_size, rows_remaining);
    ++
    ++            cols_remaining = ps_sps->i2_pic_width_in_luma_samples
    ++                            - (ps_codec->s_parse.i4_ctb_x << ps_sps->i1_log2_ctb_size);
    ++            pu_skip_wd = MIN(ctb_size, cols_remaining);
    + 
    +             ps_tu->b1_cb_cbf = 0;
    +             ps_tu->b1_cr_cbf = 0;
    +@@ -2731,8 +2742,8 @@ IHEVCD_ERROR_T ihevcd_parse_slice_data(codec_t *ps_codec)
    +             ps_pu->b2_part_idx = 0;
    +             ps_pu->b4_pos_x = 0;
    +             ps_pu->b4_pos_y = 0;
    +-            ps_pu->b4_wd = (ctb_size >> 2) - 1;
    +-            ps_pu->b4_ht = (ctb_size >> 2) - 1;
    ++            ps_pu->b4_wd = (pu_skip_wd >> 2) - 1;
    ++            ps_pu->b4_ht = (pu_skip_ht >> 2) - 1;
    +             ps_pu->b1_intra_flag = 0;
    +             ps_pu->b3_part_mode = ps_codec->s_parse.s_cu.i4_part_mode;
    +             ps_pu->b1_merge_flag = 1;
    +diff --git a/decoder/ihevcd_utils.c b/decoder/ihevcd_utils.c
    +index 7d76577..14cdd2b 100755
    +--- a/decoder/ihevcd_utils.c
    ++++ b/decoder/ihevcd_utils.c
    +@@ -662,6 +662,103 @@ IHEVCD_ERROR_T ihevcd_mv_buf_mgr_add_bufs(codec_t *ps_codec)
    + *******************************************************************************
    + *
    + * @brief
    ++*  Output buffer check
    ++*
    ++* @par Description:
    ++*  Check for the number of buffers and buffer sizes of output buffer
    ++*
    ++* @param[in] ps_codec
    ++*  Pointer to codec context
    ++*
    ++* @returns  Error from IHEVCD_ERROR_T
    ++*
    ++* @remarks
    ++*
    ++*
    ++*******************************************************************************
    ++*/
    ++IHEVCD_ERROR_T ihevcd_check_out_buf_size(codec_t *ps_codec)
    ++{
    ++    ivd_out_bufdesc_t *ps_out_buffer = ps_codec->ps_out_buffer;
    ++    UWORD32 au4_min_out_buf_size[IVD_VIDDEC_MAX_IO_BUFFERS];
    ++    UWORD32 u4_min_num_out_bufs = 0, i;
    ++    UWORD32 wd, ht;
    ++
    ++    if(0 == ps_codec->i4_share_disp_buf)
    ++    {
    ++        wd = ps_codec->i4_disp_wd;
    ++        ht = ps_codec->i4_disp_ht;
    ++    }
    ++    else
    ++    {
    ++        /* In case of shared mode, do not check validity of ps_codec->ps_out_buffer */
    ++        return (IHEVCD_ERROR_T)IHEVCD_SUCCESS;
    ++    }
    ++
    ++    if(ps_codec->e_chroma_fmt == IV_YUV_420P)
    ++        u4_min_num_out_bufs = MIN_OUT_BUFS_420;
    ++    else if(ps_codec->e_chroma_fmt == IV_YUV_422ILE)
    ++        u4_min_num_out_bufs = MIN_OUT_BUFS_422ILE;
    ++    else if(ps_codec->e_chroma_fmt == IV_RGB_565)
    ++        u4_min_num_out_bufs = MIN_OUT_BUFS_RGB565;
    ++    else if(ps_codec->e_chroma_fmt == IV_RGBA_8888)
    ++        u4_min_num_out_bufs = MIN_OUT_BUFS_RGBA8888;
    ++    else if((ps_codec->e_chroma_fmt == IV_YUV_420SP_UV)
    ++                    || (ps_codec->e_chroma_fmt == IV_YUV_420SP_VU))
    ++        u4_min_num_out_bufs = MIN_OUT_BUFS_420SP;
    ++
    ++    if(ps_codec->e_chroma_fmt == IV_YUV_420P)
    ++    {
    ++        au4_min_out_buf_size[0] = (wd * ht);
    ++        au4_min_out_buf_size[1] = (wd * ht) >> 2;
    ++        au4_min_out_buf_size[2] = (wd * ht) >> 2;
    ++    }
    ++    else if(ps_codec->e_chroma_fmt == IV_YUV_422ILE)
    ++    {
    ++        au4_min_out_buf_size[0] = (wd * ht) * 2;
    ++        au4_min_out_buf_size[1] =
    ++                        au4_min_out_buf_size[2] = 0;
    ++    }
    ++    else if(ps_codec->e_chroma_fmt == IV_RGB_565)
    ++    {
    ++        au4_min_out_buf_size[0] = (wd * ht) * 2;
    ++        au4_min_out_buf_size[1] =
    ++                        au4_min_out_buf_size[2] = 0;
    ++    }
    ++    else if(ps_codec->e_chroma_fmt == IV_RGBA_8888)
    ++    {
    ++        au4_min_out_buf_size[0] = (wd * ht) * 4;
    ++        au4_min_out_buf_size[1] =
    ++                        au4_min_out_buf_size[2] = 0;
    ++    }
    ++    else if((ps_codec->e_chroma_fmt == IV_YUV_420SP_UV)
    ++                    || (ps_codec->e_chroma_fmt == IV_YUV_420SP_VU))
    ++    {
    ++        au4_min_out_buf_size[0] = (wd * ht);
    ++        au4_min_out_buf_size[1] = (wd * ht) >> 1;
    ++        au4_min_out_buf_size[2] = 0;
    ++    }
    ++
    ++    if(ps_out_buffer->u4_num_bufs < u4_min_num_out_bufs)
    ++    {
    ++        return (IHEVCD_ERROR_T)IV_FAIL;
    ++    }
    ++
    ++    for (i = 0 ; i < u4_min_num_out_bufs; i++)
    ++    {
    ++        if(ps_out_buffer->u4_min_out_buf_size[i] < au4_min_out_buf_size[i])
    ++        {
    ++            return (IHEVCD_ERROR_T)IV_FAIL;
    ++        }
    ++    }
    ++
    ++    return (IHEVCD_ERROR_T)IHEVCD_SUCCESS;
    ++}
    ++
    ++/**
    ++*******************************************************************************
    ++*
    ++* @brief
    + *  Picture level initializations required during parsing
    + *
    + * @par Description:
    +@@ -713,6 +810,10 @@ IHEVCD_ERROR_T ihevcd_parse_pic_init(codec_t *ps_codec)
    +         ps_codec->s_parse.i4_first_pic_init = 1;
    +     }
    + 
    ++    /* Output buffer check */
    ++    ret = ihevcd_check_out_buf_size(ps_codec);
    ++    RETURN_IF((ret != (IHEVCD_ERROR_T)IHEVCD_SUCCESS), ret);
    ++
    +     /* Initialize all the slice headers' slice addresses to zero */
    +     {
    +         WORD32 slice_idx;
    diff --git a/frameworks_av.patch b/frameworks_av.patch
    index 3f21777..638db3d 100644
    --- a/frameworks_av.patch
    +++ b/frameworks_av.patch
    @@ -52,6 +52,17 @@ index 7e36c5e..aca7a19 100644
      
      include $(BUILD_EXECUTABLE)
     +endif
    +diff --git a/camera/cameraserver/main_cameraserver.cpp b/camera/cameraserver/main_cameraserver.cpp
    +index f4be468..ea80ad4 100644
    +--- a/camera/cameraserver/main_cameraserver.cpp
    ++++ b/camera/cameraserver/main_cameraserver.cpp
    +@@ -31,5 +31,6 @@ int main(int argc __unused, char** argv __unused)
    +     ALOGI("ServiceManager: %p", sm.get());
    +     CameraService::instantiate();
    +     ProcessState::self()->startThreadPool();
    ++    IPCThreadState::self()->disableBackgroundScheduling(true);
    +     IPCThreadState::self()->joinThreadPool();
    + }
     diff --git a/camera/ndk/NdkCaptureRequest.cpp b/camera/ndk/NdkCaptureRequest.cpp
     index 77b9a33..7c37955 100644
     --- a/camera/ndk/NdkCaptureRequest.cpp
    @@ -118,1200 +129,4601 @@ index 9823c55..cb4be75 100644
                      cmd->vsize, cmd->data + sizeof(int32_t));
              break;
     diff --git a/media/libeffects/lvm/wrapper/Bundle/EffectBundle.cpp b/media/libeffects/lvm/wrapper/Bundle/EffectBundle.cpp
    -index dcf3fa0..07ea818 100644
    +index dcf3fa0..b26e74c 100644
     --- a/media/libeffects/lvm/wrapper/Bundle/EffectBundle.cpp
     +++ b/media/libeffects/lvm/wrapper/Bundle/EffectBundle.cpp
    -@@ -2439,6 +2439,13 @@ int Equalizer_getParameter(EffectContext     *pContext,
    -             }
    -             break;
    -         }
    +@@ -16,7 +16,7 @@
    +  */
    + 
    + #define LOG_TAG "Bundle"
    +-#define ARRAY_SIZE(array) (sizeof array / sizeof array[0])
    ++#define ARRAY_SIZE(array) (sizeof (array) / sizeof (array)[0])
    + //#define LOG_NDEBUG 0
    + 
    + #include <assert.h>
    +@@ -25,28 +25,37 @@
    + #include <stdlib.h>
    + #include <string.h>
    + 
    +-#include <cutils/log.h>
    ++#include <log/log.h>
     +
    -+        if (*pValueSize < 1) {
    -+            status = -EINVAL;
    -+            android_errorWriteLog(0x534e4554, "37536407");
    -+            break;
    -+        }
    + #include "EffectBundle.h"
    + #include "math.h"
    + 
    +-
    + // effect_handle_t interface implementation for bass boost
    + extern "C" const struct effect_interface_s gLvmEffectInterface;
    + 
    ++// Turn on VERY_VERY_VERBOSE_LOGGING to log parameter get and set for effects.
     +
    -         name = (char *)pValue;
    -         strncpy(name, EqualizerGetPresetName(param2), *pValueSize - 1);
    -         name[*pValueSize - 1] = 0;
    -diff --git a/media/libeffects/lvm/wrapper/Reverb/EffectReverb.cpp b/media/libeffects/lvm/wrapper/Reverb/EffectReverb.cpp
    -index 4dc8b45..19892dd 100644
    ---- a/media/libeffects/lvm/wrapper/Reverb/EffectReverb.cpp
    -+++ b/media/libeffects/lvm/wrapper/Reverb/EffectReverb.cpp
    -@@ -180,12 +180,13 @@ int  Reverb_init            (ReverbContext *pContext);
    - void Reverb_free            (ReverbContext *pContext);
    - int  Reverb_setConfig       (ReverbContext *pContext, effect_config_t *pConfig);
    - void Reverb_getConfig       (ReverbContext *pContext, effect_config_t *pConfig);
    --int  Reverb_setParameter    (ReverbContext *pContext, void *pParam, void *pValue);
    -+int  Reverb_setParameter    (ReverbContext *pContext, void *pParam, void *pValue, int vsize);
    - int  Reverb_getParameter    (ReverbContext *pContext,
    -                              void          *pParam,
    -                              uint32_t      *pValueSize,
    -                              void          *pValue);
    - int Reverb_LoadPreset       (ReverbContext   *pContext);
    -+int Reverb_paramValueSize   (int32_t param);
    ++//#define VERY_VERY_VERBOSE_LOGGING
    ++#ifdef VERY_VERY_VERBOSE_LOGGING
    ++#define ALOGVV ALOGV
    ++#else
    ++#define ALOGVV(a...) do { } while (false)
    ++#endif
    ++
    + #define LVM_ERROR_CHECK(LvmStatus, callingFunc, calledFunc){\
    +-        if (LvmStatus == LVM_NULLADDRESS){\
    ++        if ((LvmStatus) == LVM_NULLADDRESS){\
    +             ALOGV("\tLVM_ERROR : Parameter error - "\
    +                     "null pointer returned by %s in %s\n\n\n\n", callingFunc, calledFunc);\
    +         }\
    +-        if (LvmStatus == LVM_ALIGNMENTERROR){\
    ++        if ((LvmStatus) == LVM_ALIGNMENTERROR){\
    +             ALOGV("\tLVM_ERROR : Parameter error - "\
    +                     "bad alignment returned by %s in %s\n\n\n\n", callingFunc, calledFunc);\
    +         }\
    +-        if (LvmStatus == LVM_INVALIDNUMSAMPLES){\
    ++        if ((LvmStatus) == LVM_INVALIDNUMSAMPLES){\
    +             ALOGV("\tLVM_ERROR : Parameter error - "\
    +                     "bad number of samples returned by %s in %s\n\n\n\n", callingFunc, calledFunc);\
    +         }\
    +-        if (LvmStatus == LVM_OUTOFRANGE){\
    ++        if ((LvmStatus) == LVM_OUTOFRANGE){\
    +             ALOGV("\tLVM_ERROR : Parameter error - "\
    +                     "out of range returned by %s in %s\n", callingFunc, calledFunc);\
    +         }\
    +@@ -138,26 +147,43 @@ int  LvmEffect_disable         (EffectContext *pContext);
    + void LvmEffect_free            (EffectContext *pContext);
    + int  Effect_setConfig          (EffectContext *pContext, effect_config_t *pConfig);
    + void Effect_getConfig          (EffectContext *pContext, effect_config_t *pConfig);
    +-int  BassBoost_setParameter    (EffectContext *pContext, void *pParam, void *pValue);
    ++int  BassBoost_setParameter    (EffectContext *pContext,
    ++                                uint32_t       paramSize,
    ++                                void          *pParam,
    ++                                uint32_t       valueSize,
    ++                                void          *pValue);
    + int  BassBoost_getParameter    (EffectContext *pContext,
    +-                               void           *pParam,
    +-                               uint32_t       *pValueSize,
    +-                               void           *pValue);
    +-int  Virtualizer_setParameter  (EffectContext *pContext, void *pParam, void *pValue);
    ++                                uint32_t       paramSize,
    ++                                void          *pParam,
    ++                                uint32_t      *pValueSize,
    ++                                void          *pValue);
    ++int  Virtualizer_setParameter  (EffectContext *pContext,
    ++                                uint32_t       paramSize,
    ++                                void          *pParam,
    ++                                uint32_t       valueSize,
    ++                                void          *pValue);
    + int  Virtualizer_getParameter  (EffectContext *pContext,
    +-                               void           *pParam,
    +-                               uint32_t       *pValueSize,
    +-                               void           *pValue);
    ++                                uint32_t       paramSize,
    ++                                void          *pParam,
    ++                                uint32_t      *pValueSize,
    ++                                void          *pValue);
    + int  Equalizer_setParameter    (EffectContext *pContext,
    +-                               void *pParam,
    +-                               uint32_t valueSize,
    +-                               void *pValue);
    ++                                uint32_t       paramSize,
    ++                                void          *pParam,
    ++                                uint32_t       valueSize,
    ++                                void          *pValue);
    + int  Equalizer_getParameter    (EffectContext *pContext,
    ++                                uint32_t       paramSize,
    +                                 void          *pParam,
    +                                 uint32_t      *pValueSize,
    +                                 void          *pValue);
    +-int  Volume_setParameter       (EffectContext *pContext, void *pParam, void *pValue);
    ++int  Volume_setParameter       (EffectContext *pContext,
    ++                                uint32_t       paramSize,
    ++                                void          *pParam,
    ++                                uint32_t       valueSize,
    ++                                void          *pValue);
    + int  Volume_getParameter       (EffectContext *pContext,
    ++                                uint32_t       paramSize,
    +                                 void          *pParam,
    +                                 uint32_t      *pValueSize,
    +                                 void          *pValue);
    +@@ -343,8 +369,10 @@ exit:
    +             }
    +             delete pContext;
    +         }
    +-        *pHandle = (effect_handle_t)NULL;
    ++        if (pHandle != NULL)
    ++          *pHandle = (effect_handle_t)NULL;
    +     } else {
    ++      if (pHandle != NULL)
    +         *pHandle = (effect_handle_t)pContext;
    +     }
    +     ALOGV("\tEffectCreate end..\n\n");
    +@@ -504,8 +532,6 @@ void LvmGlobalBundle_init(){
    + //----------------------------------------------------------------------------
      
    - /* Effect Library Interface Implementation */
    + int LvmBundle_init(EffectContext *pContext){
    +-    int status;
    +-
    +     ALOGV("\tLvmBundle_init start");
      
    -@@ -1747,12 +1748,13 @@ int Reverb_getParameter(ReverbContext *pContext,
    - //  pContext         - handle to instance data
    - //  pParam           - pointer to parameter
    - //  pValue           - pointer to value
    -+//  vsize            - value size
    - //
    - // Outputs:
    +     pContext->config.inputCfg.accessMode                    = EFFECT_BUFFER_ACCESS_READ;
    +@@ -719,7 +745,6 @@ int LvmBundle_process(LVM_INT16        *pIn,
    +                       int              frameCount,
    +                       EffectContext    *pContext){
    + 
    +-    LVM_ControlParams_t     ActiveParams;                           /* Current control Parameters */
    +     LVM_ReturnStatus_en     LvmStatus = LVM_SUCCESS;                /* Function call status */
    +     LVM_INT16               *pOutTmp;
    + 
    +@@ -1043,7 +1068,6 @@ int LvmEffect_disable(EffectContext *pContext){
    + 
    + void LvmEffect_free(EffectContext *pContext){
    +     LVM_ReturnStatus_en     LvmStatus=LVM_SUCCESS;         /* Function call status */
    +-    LVM_ControlParams_t     params;                        /* Control Parameters */
    +     LVM_MemTab_t            MemTab;
    + 
    +     /* Free the algorithm memory */
    +@@ -2011,61 +2035,54 @@ int32_t VolumeEnableStereoPosition(EffectContext *pContext, uint32_t enabled){
      //
      //----------------------------------------------------------------------------
      
    --int Reverb_setParameter (ReverbContext *pContext, void *pParam, void *pValue){
    -+int Reverb_setParameter (ReverbContext *pContext, void *pParam, void *pValue, int vsize){
    +-int BassBoost_getParameter(EffectContext     *pContext,
    +-                           void              *pParam,
    +-                           uint32_t          *pValueSize,
    +-                           void              *pValue){
    ++int BassBoost_getParameter(EffectContext *pContext,
    ++                           uint32_t       paramSize,
    ++                           void          *pParam,
    ++                           uint32_t      *pValueSize,
    ++                           void          *pValue) {
          int status = 0;
    -     int16_t level;
    -     int16_t ratio;
    -@@ -1776,6 +1778,11 @@ int Reverb_setParameter (ReverbContext *pContext, void *pParam, void *pValue){
    -         return 0;
    +-    int32_t *pParamTemp = (int32_t *)pParam;
    +-    int32_t param = *pParamTemp++;
    +-    int32_t param2;
    +-    char *name;
    ++    int32_t *params = (int32_t *)pParam;
    + 
    +-    //ALOGV("\tBassBoost_getParameter start");
    ++    ALOGVV("%s start", __func__);
    + 
    +-    switch (param){
    ++    if (paramSize < sizeof(int32_t)) {
    ++        ALOGV("%s invalid paramSize: %u", __func__, paramSize);
    ++        return -EINVAL;
    ++    }
    ++    switch (params[0]) {
    +         case BASSBOOST_PARAM_STRENGTH_SUPPORTED:
    +-            if (*pValueSize != sizeof(uint32_t)){
    +-                ALOGV("\tLVM_ERROR : BassBoost_getParameter() invalid pValueSize1 %d", *pValueSize);
    +-                return -EINVAL;
    +-            }
    +-            *pValueSize = sizeof(uint32_t);
    +-            break;
    +-        case BASSBOOST_PARAM_STRENGTH:
    +-            if (*pValueSize != sizeof(int16_t)){
    +-                ALOGV("\tLVM_ERROR : BassBoost_getParameter() invalid pValueSize2 %d", *pValueSize);
    +-                return -EINVAL;
    ++            if (*pValueSize != sizeof(uint32_t)) {  // legacy: check equality here.
    ++                ALOGV("%s BASSBOOST_PARAM_STRENGTH_SUPPORTED invalid *pValueSize %u",
    ++                        __func__, *pValueSize);
    ++                status = -EINVAL;
    ++                break;
    +             }
    +-            *pValueSize = sizeof(int16_t);
    +-            break;
    ++            // no need to set *pValueSize
    + 
    +-        default:
    +-            ALOGV("\tLVM_ERROR : BassBoost_getParameter() invalid param %d", param);
    +-            return -EINVAL;
    +-    }
    +-
    +-    switch (param){
    +-        case BASSBOOST_PARAM_STRENGTH_SUPPORTED:
    +             *(uint32_t *)pValue = 1;
    +-
    +-            //ALOGV("\tBassBoost_getParameter() BASSBOOST_PARAM_STRENGTH_SUPPORTED Value is %d",
    +-            //        *(uint32_t *)pValue);
    ++            ALOGVV("%s BASSBOOST_PARAM_STRENGTH_SUPPORTED %u", __func__, *(uint32_t *)pValue);
    +             break;
    + 
    +         case BASSBOOST_PARAM_STRENGTH:
    +-            *(int16_t *)pValue = BassGetStrength(pContext);
    ++            if (*pValueSize != sizeof(int16_t)) {  // legacy: check equality here.
    ++                ALOGV("%s BASSBOOST_PARAM_STRENGTH invalid *pValueSize %u",
    ++                        __func__, *pValueSize);
    ++                status = -EINVAL;
    ++                break;
    ++            }
    ++            // no need to set *pValueSize
    + 
    +-            //ALOGV("\tBassBoost_getParameter() BASSBOOST_PARAM_STRENGTH Value is %d",
    +-            //        *(int16_t *)pValue);
    ++            *(int16_t *)pValue = BassGetStrength(pContext);
    ++            ALOGVV("%s BASSBOOST_PARAM_STRENGTH %d", __func__, *(int16_t *)pValue);
    +             break;
    + 
    +         default:
    +-            ALOGV("\tLVM_ERROR : BassBoost_getParameter() invalid param %d", param);
    ++            ALOGV("%s invalid param %d", __func__, params[0]);
    +             status = -EINVAL;
    +             break;
          }
      
    -+    if (vsize < Reverb_paramValueSize(param)) {
    -+        android_errorWriteLog(0x534e4554, "63526567");
    +-    //ALOGV("\tBassBoost_getParameter end");
    ++    ALOGVV("%s end param: %d, status: %d", __func__, params[0], status);
    +     return status;
    + } /* end BassBoost_getParameter */
    + 
    +@@ -2084,27 +2101,42 @@ int BassBoost_getParameter(EffectContext     *pContext,
    + //
    + //----------------------------------------------------------------------------
    + 
    +-int BassBoost_setParameter (EffectContext *pContext, void *pParam, void *pValue){
    ++int BassBoost_setParameter(EffectContext *pContext,
    ++                           uint32_t       paramSize,
    ++                           void          *pParam,
    ++                           uint32_t       valueSize,
    ++                           void          *pValue) {
    +     int status = 0;
    +-    int16_t strength;
    +-    int32_t *pParamTemp = (int32_t *)pParam;
    ++    int32_t *params = (int32_t *)pParam;
    + 
    +-    //ALOGV("\tBassBoost_setParameter start");
    ++    ALOGVV("%s start", __func__);
    + 
    +-    switch (*pParamTemp){
    +-        case BASSBOOST_PARAM_STRENGTH:
    +-            strength = *(int16_t *)pValue;
    +-            //ALOGV("\tBassBoost_setParameter() BASSBOOST_PARAM_STRENGTH value is %d", strength);
    +-            //ALOGV("\tBassBoost_setParameter() Calling pBassBoost->BassSetStrength");
    ++    if (paramSize != sizeof(int32_t)) {  // legacy: check equality here.
    ++        ALOGV("%s invalid paramSize: %u", __func__, paramSize);
     +        return -EINVAL;
     +    }
    ++    switch (params[0]) {
    ++        case BASSBOOST_PARAM_STRENGTH: {
    ++            if (valueSize < sizeof(int16_t)) {
    ++                ALOGV("%s BASSBOOST_PARAM_STRENGTH invalid valueSize: %u", __func__, valueSize);
    ++                status = -EINVAL;
    ++                break;
    ++            }
     +
    -     switch (param){
    -         case REVERB_PARAM_PROPERTIES:
    -             ALOGV("\tReverb_setParameter() REVERB_PARAM_PROPERTIES");
    -@@ -1851,6 +1858,31 @@ int Reverb_setParameter (ReverbContext *pContext, void *pParam, void *pValue){
    ++            const int16_t strength = *(int16_t *)pValue;
    ++            ALOGVV("%s BASSBOOST_PARAM_STRENGTH %d", __func__, strength);
    ++            ALOGVV("%s BASSBOOST_PARAM_STRENGTH Calling BassSetStrength", __func__);
    +             BassSetStrength(pContext, (int32_t)strength);
    +-            //ALOGV("\tBassBoost_setParameter() Called pBassBoost->BassSetStrength");
    +-           break;
    ++            ALOGVV("%s BASSBOOST_PARAM_STRENGTH Called BassSetStrength", __func__);
    ++        } break;
    ++
    +         default:
    +-            ALOGV("\tLVM_ERROR : BassBoost_setParameter() invalid param %d", *pParamTemp);
    ++            ALOGV("%s invalid param %d", __func__, params[0]);
    ++            status = -EINVAL;
    +             break;
    +     }
    + 
    +-    //ALOGV("\tBassBoost_setParameter end");
    ++    ALOGVV("%s end param: %d, status: %d", __func__, params[0], status);
          return status;
    - } /* end Reverb_setParameter */
    + } /* end BassBoost_setParameter */
      
    -+
    -+/**
    -+ * returns the size in bytes of the value of each environmental reverb parameter
    -+ */
    -+int Reverb_paramValueSize(int32_t param) {
    -+    switch (param) {
    -+    case REVERB_PARAM_ROOM_LEVEL:
    -+    case REVERB_PARAM_ROOM_HF_LEVEL:
    -+    case REVERB_PARAM_REFLECTIONS_LEVEL:
    -+    case REVERB_PARAM_REVERB_LEVEL:
    -+        return sizeof(int16_t); // millibel
    -+    case REVERB_PARAM_DECAY_TIME:
    -+    case REVERB_PARAM_REFLECTIONS_DELAY:
    -+    case REVERB_PARAM_REVERB_DELAY:
    -+        return sizeof(uint32_t); // milliseconds
    -+    case REVERB_PARAM_DECAY_HF_RATIO:
    -+    case REVERB_PARAM_DIFFUSION:
    -+    case REVERB_PARAM_DENSITY:
    -+        return sizeof(int16_t); // permille
    -+    case REVERB_PARAM_PROPERTIES:
    -+        return sizeof(s_reverb_settings); // struct of all reverb properties
    +@@ -2129,93 +2161,97 @@ int BassBoost_setParameter (EffectContext *pContext, void *pParam, void *pValue)
    + //
    + //----------------------------------------------------------------------------
    + 
    +-int Virtualizer_getParameter(EffectContext        *pContext,
    +-                             void                 *pParam,
    +-                             uint32_t             *pValueSize,
    +-                             void                 *pValue){
    ++int Virtualizer_getParameter(EffectContext *pContext,
    ++                             uint32_t       paramSize,
    ++                             void          *pParam,
    ++                             uint32_t      *pValueSize,
    ++                             void          *pValue) {
    +     int status = 0;
    +-    int32_t *pParamTemp = (int32_t *)pParam;
    +-    int32_t param = *pParamTemp++;
    +-    char *name;
    ++    int32_t *params = (int32_t *)pParam;
    + 
    +-    //ALOGV("\tVirtualizer_getParameter start");
    ++    ALOGVV("%s start", __func__);
    + 
    +-    switch (param){
    ++    if (paramSize < sizeof(int32_t)) {
    ++        ALOGV("%s invalid paramSize: %u", __func__, paramSize);
    ++        return -EINVAL;
     +    }
    -+    return sizeof(int32_t);
    -+}
    ++    switch (params[0]) {
    +         case VIRTUALIZER_PARAM_STRENGTH_SUPPORTED:
    +-            if (*pValueSize != sizeof(uint32_t)){
    +-                ALOGV("\tLVM_ERROR : Virtualizer_getParameter() invalid pValueSize %d",*pValueSize);
    +-                return -EINVAL;
    +-            }
    +-            *pValueSize = sizeof(uint32_t);
    +-            break;
    +-        case VIRTUALIZER_PARAM_STRENGTH:
    +-            if (*pValueSize != sizeof(int16_t)){
    +-                ALOGV("\tLVM_ERROR : Virtualizer_getParameter() invalid pValueSize2 %d",*pValueSize);
    +-                return -EINVAL;
    +-            }
    +-            *pValueSize = sizeof(int16_t);
    +-            break;
    +-        case VIRTUALIZER_PARAM_VIRTUAL_SPEAKER_ANGLES:
    +-            // return value size can only be interpreted as relative to input value,
    +-            // deferring validity check to below
    +-            break;
    +-        case VIRTUALIZER_PARAM_VIRTUALIZATION_MODE:
    +-            if (*pValueSize != sizeof(uint32_t)){
    +-                ALOGV("\tLVM_ERROR : Virtualizer_getParameter() invalid pValueSize %d",*pValueSize);
    +-                return -EINVAL;
    ++            if (*pValueSize != sizeof(uint32_t)) { // legacy: check equality here.
    ++                ALOGV("%s VIRTUALIZER_PARAM_STRENGTH_SUPPORTED invalid *pValueSize %u",
    ++                        __func__, *pValueSize);
    ++                status = -EINVAL;
    ++                break;
    +             }
    +-            *pValueSize = sizeof(uint32_t);
    +-            break;
    +-        default:
    +-            ALOGV("\tLVM_ERROR : Virtualizer_getParameter() invalid param %d", param);
    +-            return -EINVAL;
    +-    }
    ++            // no need to set *pValueSize
    + 
    +-    switch (param){
    +-        case VIRTUALIZER_PARAM_STRENGTH_SUPPORTED:
    +             *(uint32_t *)pValue = 1;
    +-
    +-            //ALOGV("\tVirtualizer_getParameter() VIRTUALIZER_PARAM_STRENGTH_SUPPORTED Value is %d",
    +-            //        *(uint32_t *)pValue);
    ++            ALOGVV("%s VIRTUALIZER_PARAM_STRENGTH_SUPPORTED %d", __func__, *(uint32_t *)pValue);
    +             break;
    + 
    +         case VIRTUALIZER_PARAM_STRENGTH:
    ++            if (*pValueSize != sizeof(int16_t)) { // legacy: check equality here.
    ++                ALOGV("%s VIRTUALIZER_PARAM_STRENGTH invalid *pValueSize %u",
    ++                        __func__, *pValueSize);
    ++                status = -EINVAL;
    ++                break;
    ++            }
    ++            // no need to set *pValueSize
     +
    - } // namespace
    - } // namespace
    +             *(int16_t *)pValue = VirtualizerGetStrength(pContext);
      
    -@@ -2022,7 +2054,8 @@ int Reverb_command(effect_handle_t  self,
    +-            //ALOGV("\tVirtualizer_getParameter() VIRTUALIZER_PARAM_STRENGTH Value is %d",
    +-            //        *(int16_t *)pValue);
    ++            ALOGVV("%s VIRTUALIZER_PARAM_STRENGTH %d", __func__, *(int16_t *)pValue);
    +             break;
      
    -             *(int *)pReplyData = android::Reverb_setParameter(pContext,
    -                                                              (void *)p->data,
    --                                                              p->data + p->psize);
    -+                                                              p->data + p->psize,
    -+                                                              p->vsize);
    -         } break;
    +         case VIRTUALIZER_PARAM_VIRTUAL_SPEAKER_ANGLES: {
    +-            const audio_channel_mask_t channelMask = (audio_channel_mask_t) *pParamTemp++;
    +-            const audio_devices_t deviceType = (audio_devices_t) *pParamTemp;
    +-            uint32_t nbChannels = audio_channel_count_from_out_mask(channelMask);
    +-            if (*pValueSize < 3 * nbChannels * sizeof(int32_t)){
    +-                ALOGV("\tLVM_ERROR : Virtualizer_getParameter() invalid pValueSize %d",*pValueSize);
    +-                return -EINVAL;
    ++            if (paramSize < 3 * sizeof(int32_t)) {
    ++                ALOGV("%s VIRTUALIZER_PARAM_SPEAKER_ANGLES invalid paramSize: %u",
    ++                        __func__, paramSize);
    ++                status = -EINVAL;
    ++                break;
    ++            }
    ++
    ++            const audio_channel_mask_t channelMask = (audio_channel_mask_t) params[1];
    ++            const audio_devices_t deviceType = (audio_devices_t) params[2];
    ++            const uint32_t nbChannels = audio_channel_count_from_out_mask(channelMask);
    ++            const uint32_t valueSizeRequired = 3 * nbChannels * sizeof(int32_t);
    ++            if (*pValueSize < valueSizeRequired) {
    ++                ALOGV("%s VIRTUALIZER_PARAM_SPEAKER_ANGLES invalid *pValueSize %u",
    ++                        __func__, *pValueSize);
    ++                status = -EINVAL;
    ++                break;
    +             }
    ++            *pValueSize = valueSizeRequired;
    ++
    +             // verify the configuration is supported
    +             status = VirtualizerIsConfigurationSupported(channelMask, deviceType);
    +             if (status == 0) {
    +-                ALOGV("VIRTUALIZER_PARAM_VIRTUAL_SPEAKER_ANGLES supports mask=0x%x device=0x%x",
    +-                        channelMask, deviceType);
    ++                ALOGV("%s VIRTUALIZER_PARAM_VIRTUAL_SPEAKER_ANGLES mask=0x%x device=0x%x",
    ++                        __func__, channelMask, deviceType);
    +                 // configuration is supported, get the angles
    +                 VirtualizerGetSpeakerAngles(channelMask, deviceType, (int32_t *)pValue);
    +             }
    +-            }
    +-            break;
    ++        } break;
      
    -         case EFFECT_CMD_ENABLE:
    -diff --git a/media/libmedia/IDataSource.cpp b/media/libmedia/IDataSource.cpp
    -index 51c9938..5ad39fe 100644
    ---- a/media/libmedia/IDataSource.cpp
    -+++ b/media/libmedia/IDataSource.cpp
    -@@ -54,8 +54,16 @@ struct BpDataSource : public BpInterface<IDataSource> {
    -         data.writeInterfaceToken(IDataSource::getInterfaceDescriptor());
    -         data.writeInt64(offset);
    -         data.writeInt64(size);
    --        remote()->transact(READ_AT, data, &reply);
    --        return reply.readInt64();
    -+        status_t err = remote()->transact(READ_AT, data, &reply);
    -+        if (err != OK) {
    -+            return err;
    -+        }
    -+        int64_t value = 0;
    -+        err = reply.readInt64(&value);
    -+        if (err != OK) {
    -+            return err;
    -+        }
    -+        return (ssize_t)value;
    +         case VIRTUALIZER_PARAM_VIRTUALIZATION_MODE:
    +-            *(uint32_t *)pValue  = (uint32_t) VirtualizerGetVirtualizationMode(pContext);
    ++            if (*pValueSize != sizeof(uint32_t)) { // legacy: check equality here.
    ++                ALOGV("%s VIRTUALIZER_PARAM_VIRTUALIZATION_MODE invalid *pValueSize %u",
    ++                        __func__, *pValueSize);
    ++                status = -EINVAL;
    ++                break;
    ++            }
    ++            // no need to set *pValueSize
    ++
    ++            *(uint32_t *)pValue = (uint32_t) VirtualizerGetVirtualizationMode(pContext);
    +             break;
    + 
    +         default:
    +-            ALOGV("\tLVM_ERROR : Virtualizer_getParameter() invalid param %d", param);
    ++            ALOGV("%s invalid param %d", __func__, params[0]);
    +             status = -EINVAL;
    +             break;
          }
      
    -     virtual status_t getSize(off64_t* size) {
    -diff --git a/media/libmediaplayerservice/MediaPlayerService.cpp b/media/libmediaplayerservice/MediaPlayerService.cpp
    -index bd16e91..6e689e6 100644
    ---- a/media/libmediaplayerservice/MediaPlayerService.cpp
    -+++ b/media/libmediaplayerservice/MediaPlayerService.cpp
    -@@ -82,6 +82,9 @@
    - #include "HTTPBase.h"
    - #include "RemoteDisplay.h"
    +-    ALOGV("\tVirtualizer_getParameter end returning status=%d", status);
    ++    ALOGVV("%s end param: %d, status: %d", __func__, params[0], status);
    +     return status;
    + } /* end Virtualizer_getParameter */
      
    -+static const int kDumpLockRetries = 50;
    -+static const int kDumpLockSleepUs = 20000;
    -+
    - namespace {
    - using android::media::Metadata;
    - using android::status_t;
    -@@ -405,12 +408,32 @@ status_t MediaPlayerService::Client::dump(int fd, const Vector<String16>& args)
    -     snprintf(buffer, 255, "  pid(%d), connId(%d), status(%d), looping(%s)\n",
    -             mPid, mConnId, mStatus, mLoop?"true": "false");
    -     result.append(buffer);
    -+
    -+    sp<MediaPlayerBase> p;
    -+    sp<AudioOutput> audioOutput;
    -+    bool locked = false;
    -+    for (int i = 0; i < kDumpLockRetries; ++i) {
    -+        if (mLock.tryLock() == NO_ERROR) {
    -+            locked = true;
    -+            break;
    -+        }
    -+        usleep(kDumpLockSleepUs);
    +@@ -2234,37 +2270,57 @@ int Virtualizer_getParameter(EffectContext        *pContext,
    + //
    + //----------------------------------------------------------------------------
    + 
    +-int Virtualizer_setParameter (EffectContext *pContext, void *pParam, void *pValue){
    ++int Virtualizer_setParameter(EffectContext *pContext,
    ++                             uint32_t       paramSize,
    ++                             void          *pParam,
    ++                             uint32_t       valueSize,
    ++                             void          *pValue) {
    +     int status = 0;
    +-    int16_t strength;
    +-    int32_t *pParamTemp = (int32_t *)pParam;
    +-    int32_t param = *pParamTemp++;
    ++    int32_t *params = (int32_t *)pParam;
    + 
    +-    //ALOGV("\tVirtualizer_setParameter start");
    ++    ALOGVV("%s start", __func__);
    + 
    +-    switch (param){
    +-        case VIRTUALIZER_PARAM_STRENGTH:
    +-            strength = *(int16_t *)pValue;
    +-            //ALOGV("\tVirtualizer_setParameter() VIRTUALIZER_PARAM_STRENGTH value is %d", strength);
    +-            //ALOGV("\tVirtualizer_setParameter() Calling pVirtualizer->setStrength");
    ++    if (paramSize != sizeof(int32_t)) { // legacy: check equality here.
    ++        ALOGV("%s invalid paramSize: %u", __func__, paramSize);
    ++        return -EINVAL;
     +    }
    ++    switch (params[0]) {
    ++        case VIRTUALIZER_PARAM_STRENGTH: {
    ++            if (valueSize < sizeof(int16_t)) {
    ++                ALOGV("%s VIRTUALIZER_PARAM_STRENGTH invalid valueSize: %u", __func__, valueSize);
    ++                status = -EINVAL;
    ++                break;
    ++            }
     +
    -+    if (locked) {
    -+        p = mPlayer;
    -+        audioOutput = mAudioOutput;
    -+        mLock.unlock();
    -+    } else {
    -+        result.append("  lock is taken, no dump from player and audio output\n");
    -+    }
    -     write(fd, result.string(), result.size());
    --    if (mPlayer != NULL) {
    --        mPlayer->dump(fd, args);
    ++            const int16_t strength = *(int16_t *)pValue;
    ++            ALOGVV("%s VIRTUALIZER_PARAM_STRENGTH %d", __func__, strength);
    ++            ALOGVV("%s VIRTUALIZER_PARAM_STRENGTH Calling VirtualizerSetStrength", __func__);
    +             VirtualizerSetStrength(pContext, (int32_t)strength);
    +-            //ALOGV("\tVirtualizer_setParameter() Called pVirtualizer->setStrength");
    +-           break;
    ++            ALOGVV("%s VIRTUALIZER_PARAM_STRENGTH Called VirtualizerSetStrength", __func__);
    ++        } break;
    + 
    +         case VIRTUALIZER_PARAM_FORCE_VIRTUALIZATION_MODE: {
    +-            const audio_devices_t deviceType = *(audio_devices_t *) pValue;
    +-            status = VirtualizerForceVirtualizationMode(pContext, deviceType);
    +-            //ALOGV("VIRTUALIZER_PARAM_FORCE_VIRTUALIZATION_MODE device=0x%x result=%d",
    +-            //        deviceType, status);
    ++            if (valueSize < sizeof(int32_t)) {
    ++                ALOGV("%s VIRTUALIZER_PARAM_FORCE_VIRTUALIZATION_MODE invalid valueSize: %u",
    ++                        __func__, valueSize);
    ++                android_errorWriteLog(0x534e4554, "64478003");
    ++                status = -EINVAL;
    ++                break;
    +             }
    +-            break;
     +
    -+    if (p != NULL) {
    -+        p->dump(fd, args);
    -     }
    --    if (mAudioOutput != 0) {
    --        mAudioOutput->dump(fd, args);
    -+    if (audioOutput != 0) {
    -+        audioOutput->dump(fd, args);
    -     }
    -     write(fd, "\n", 1);
    -     return NO_ERROR;
    -@@ -590,7 +613,10 @@ MediaPlayerService::Client::Client(
    - MediaPlayerService::Client::~Client()
    - {
    -     ALOGV("Client(%d) destructor pid = %d", mConnId, mPid);
    --    mAudioOutput.clear();
    -+    {
    -+        Mutex::Autolock l(mLock);
    -+        mAudioOutput.clear();
    -+    }
    -     wp<Client> client(this);
    -     disconnect();
    -     mService->removeClient(client);
    -@@ -609,10 +635,9 @@ void MediaPlayerService::Client::disconnect()
    -         Mutex::Autolock l(mLock);
    -         p = mPlayer;
    -         mClient.clear();
    -+        mPlayer.clear();
    ++            const audio_devices_t deviceType = (audio_devices_t)*(int32_t *)pValue;
    ++            status = VirtualizerForceVirtualizationMode(pContext, deviceType);
    ++            ALOGVV("%s VIRTUALIZER_PARAM_FORCE_VIRTUALIZATION_MODE device=%#x result=%d",
    ++                    __func__, deviceType, status);
    ++        } break;
    + 
    +         default:
    +-            ALOGV("\tLVM_ERROR : Virtualizer_setParameter() invalid param %d", param);
    ++            ALOGV("%s invalid param %d", __func__, params[0]);
    ++            status = -EINVAL;
    +             break;
          }
      
    --    mPlayer.clear();
    --
    -     // clear the notification to prevent callbacks to dead client
    -     // and reset the player. We assume the player will serialize
    -     // access to itself if necessary.
    -@@ -633,7 +658,7 @@ void MediaPlayerService::Client::disconnect()
    - sp<MediaPlayerBase> MediaPlayerService::Client::createPlayer(player_type playerType)
    - {
    -     // determine if we have the right player type
    --    sp<MediaPlayerBase> p = mPlayer;
    -+    sp<MediaPlayerBase> p = getPlayer();
    -     if ((p != NULL) && (p->playerType() != playerType)) {
    -         ALOGV("delete player");
    -         p.clear();
    -@@ -721,6 +746,7 @@ void MediaPlayerService::Client::setDataSource_post(
    -     }
    +-    //ALOGV("\tVirtualizer_setParameter end");
    ++    ALOGVV("%s end param: %d, status: %d", __func__, params[0], status);
    +     return status;
    + } /* end Virtualizer_setParameter */
      
    -     if (mStatus == OK) {
    -+        Mutex::Autolock l(mLock);
    -         mPlayer = p;
    -     }
    - }
    -diff --git a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp
    -index dc4e5d4..b64d899 100644
    ---- a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp
    -+++ b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp
    -@@ -1534,6 +1534,7 @@ void NuPlayer::restartAudio(
    -     mRenderer->flush(true /* audio */, false /* notifyComplete */);
    -     if (mVideoDecoder != NULL) {
    -         mRenderer->flush(false /* audio */, false /* notifyComplete */);
    -+        flushDecoder(false /* audio */, false /*needShutdown*/);
    -     }
    +@@ -2288,168 +2344,215 @@ int Virtualizer_setParameter (EffectContext *pContext, void *pParam, void *pValu
    + // Side Effects:
    + //
    + //----------------------------------------------------------------------------
    +-int Equalizer_getParameter(EffectContext     *pContext,
    +-                           void              *pParam,
    +-                           uint32_t          *pValueSize,
    +-                           void              *pValue){
    ++int Equalizer_getParameter(EffectContext *pContext,
    ++                           uint32_t       paramSize,
    ++                           void          *pParam,
    ++                           uint32_t      *pValueSize,
    ++                           void          *pValue) {
    +     int status = 0;
    +-    int bMute = 0;
    +-    int32_t *pParamTemp = (int32_t *)pParam;
    +-    int32_t param = *pParamTemp++;
    +-    int32_t param2;
    +-    char *name;
    ++    int32_t *params = (int32_t *)pParam;
      
    -     performSeek(currentPositionUs);
    -@@ -1545,6 +1546,10 @@ void NuPlayer::restartAudio(
    -     if (needsToCreateAudioDecoder) {
    -         instantiateDecoder(true /* audio */, &mAudioDecoder, !forceNonOffload);
    -     }
    -+    if (mVideoDecoder != NULL) {
    -+        // After a flush without shutdown, decoder is paused.
    -+        mVideoDecoder->signalResume(false /* needNotify */);
    +-    //ALOGV("\tEqualizer_getParameter start");
    ++    ALOGVV("%s start", __func__);
    + 
    +-    switch (param) {
    ++    if (paramSize < sizeof(int32_t)) {
    ++        ALOGV("%s invalid paramSize: %u", __func__, paramSize);
    ++        return -EINVAL;
     +    }
    - }
    ++    switch (params[0]) {
    +     case EQ_PARAM_NUM_BANDS:
    +-    case EQ_PARAM_CUR_PRESET:
    +-    case EQ_PARAM_GET_NUM_OF_PRESETS:
    +-    case EQ_PARAM_BAND_LEVEL:
    +-    case EQ_PARAM_GET_BAND:
    +-        if (*pValueSize < sizeof(int16_t)) {
    +-            ALOGV("\tLVM_ERROR : Equalizer_getParameter() invalid pValueSize 1  %d", *pValueSize);
    +-            return -EINVAL;
    ++        if (*pValueSize < sizeof(uint16_t)) {
    ++            ALOGV("%s EQ_PARAM_NUM_BANDS invalid *pValueSize %u", __func__, *pValueSize);
    ++            status = -EINVAL;
    ++            break;
    +         }
    +-        *pValueSize = sizeof(int16_t);
    +-        break;
    ++        *pValueSize = sizeof(uint16_t);
      
    - void NuPlayer::determineAudioModeChange(const sp<AMessage> &audioFormat) {
    -diff --git a/media/libstagefright/ACodec.cpp b/media/libstagefright/ACodec.cpp
    -index 37fd5a5..77a2a39 100644
    ---- a/media/libstagefright/ACodec.cpp
    -+++ b/media/libstagefright/ACodec.cpp
    -@@ -804,13 +804,22 @@ status_t ACodec::allocateBuffersOnPort(OMX_U32 portIndex) {
    -             } else if (type == kMetadataBufferTypeNativeHandleSource) {
    -                 bufSize = sizeof(VideoNativeHandleMetadata);
    -             }
    -+#ifdef CAMCORDER_GRALLOC_SOURCE
    -+            else if (type == kMetadataBufferTypeGrallocSource) {
    -+                bufSize = sizeof(VideoGrallocMetadata);
    -+            }
    -+#endif
    +-    case EQ_PARAM_LEVEL_RANGE:
    +-        if (*pValueSize < 2 * sizeof(int16_t)) {
    +-            ALOGV("\tLVM_ERROR : Equalizer_getParameter() invalid pValueSize 2  %d", *pValueSize);
    +-            return -EINVAL;
    +-        }
    +-        *pValueSize = 2 * sizeof(int16_t);
    ++        *(uint16_t *)pValue = (uint16_t)FIVEBAND_NUMBANDS;
    ++        ALOGVV("%s EQ_PARAM_NUM_BANDS %u", __func__, *(uint16_t *)pValue);
    +         break;
    +-    case EQ_PARAM_BAND_FREQ_RANGE:
    +-        if (*pValueSize < 2 * sizeof(int32_t)) {
    +-            ALOGV("\tLVM_ERROR : Equalizer_getParameter() invalid pValueSize 3  %d", *pValueSize);
    +-            return -EINVAL;
    ++
    ++    case EQ_PARAM_CUR_PRESET:
    ++        if (*pValueSize < sizeof(uint16_t)) {
    ++            ALOGV("%s EQ_PARAM_CUR_PRESET invalid *pValueSize %u", __func__, *pValueSize);
    ++            status = -EINVAL;
    ++            break;
    +         }
    +-        *pValueSize = 2 * sizeof(int32_t);
    ++        *pValueSize = sizeof(uint16_t);
    ++
    ++        *(uint16_t *)pValue = (uint16_t)EqualizerGetPreset(pContext);
    ++        ALOGVV("%s EQ_PARAM_CUR_PRESET %u", __func__, *(uint16_t *)pValue);
    +         break;
      
    -             // If using gralloc or native source input metadata buffers, allocate largest
    -             // metadata size as we prefer to generate native source metadata, but component
    -             // may require gralloc source. For camera source, allocate at least enough
    -             // size for native metadata buffers.
    -             size_t allottedSize = bufSize;
    -+#ifdef CAMCORDER_GRALLOC_SOURCE
    -+            if (portIndex == kPortIndexInput && type >= kMetadataBufferTypeGrallocSource) {
    -+#else
    -             if (portIndex == kPortIndexInput && type == kMetadataBufferTypeANWBuffer) {
    -+#endif
    -                 bufSize = max(sizeof(VideoGrallocMetadata), sizeof(VideoNativeMetadata));
    -             } else if (portIndex == kPortIndexInput && type == kMetadataBufferTypeCameraSource) {
    -                 bufSize = max(bufSize, sizeof(VideoNativeMetadata));
    -@@ -1766,6 +1775,14 @@ status_t ACodec::configureCodec(
    -             mInputMetadataType = (MetadataBufferType)storeMeta;
    +-    case EQ_PARAM_CENTER_FREQ:
    +-        if (*pValueSize < sizeof(int32_t)) {
    +-            ALOGV("\tLVM_ERROR : Equalizer_getParameter() invalid pValueSize 5  %d", *pValueSize);
    +-            return -EINVAL;
    ++    case EQ_PARAM_GET_NUM_OF_PRESETS:
    ++        if (*pValueSize < sizeof(uint16_t)) {
    ++            ALOGV("%s EQ_PARAM_GET_NUM_OF_PRESETS invalid *pValueSize %u", __func__, *pValueSize);
    ++            status = -EINVAL;
    ++            break;
              }
    +-        *pValueSize = sizeof(int32_t);
    +-        break;
    ++        *pValueSize = sizeof(uint16_t);
      
    -+#ifdef CAMCORDER_GRALLOC_SOURCE
    -+        // For this specific case we could be using camera source even if storeMetaDataInBuffers
    -+        // returns Gralloc source. Pretend that we are; this will force us to use nBufferSize.
    -+        if (mInputMetadataType == kMetadataBufferTypeGrallocSource) {
    -+            mInputMetadataType = kMetadataBufferTypeCameraSource;
    +-    case EQ_PARAM_GET_PRESET_NAME:
    ++        *(uint16_t *)pValue = (uint16_t)EqualizerGetNumPresets();
    ++        ALOGVV("%s EQ_PARAM_GET_NUM_OF_PRESETS %u", __func__, *(uint16_t *)pValue);
    +         break;
    + 
    +-    case EQ_PARAM_PROPERTIES:
    +-        if (*pValueSize < (2 + FIVEBAND_NUMBANDS) * sizeof(uint16_t)) {
    +-            ALOGV("\tLVM_ERROR : Equalizer_getParameter() invalid pValueSize 1  %d", *pValueSize);
    +-            return -EINVAL;
    ++    case EQ_PARAM_GET_BAND: {
    ++        if (paramSize < 2 * sizeof(int32_t)) {
    ++            ALOGV("%s EQ_PARAM_GET_BAND invalid paramSize: %u", __func__, paramSize);
    ++            status = -EINVAL;
    ++            break;
    +         }
    +-        *pValueSize = (2 + FIVEBAND_NUMBANDS) * sizeof(uint16_t);
    +-        break;
    ++        if (*pValueSize < sizeof(uint16_t)) {
    ++            ALOGV("%s EQ_PARAM_GET_BAND invalid *pValueSize %u", __func__, *pValueSize);
    ++            status = -EINVAL;
    ++            break;
     +        }
    -+#endif
    ++        *pValueSize = sizeof(uint16_t);
    + 
    +-    default:
    +-        ALOGV("\tLVM_ERROR : Equalizer_getParameter unknown param %d", param);
    +-        return -EINVAL;
    +-    }
    ++        const int32_t frequency = params[1];
    ++        *(uint16_t *)pValue = (uint16_t)EqualizerGetBand(pContext, frequency);
    ++        ALOGVV("%s EQ_PARAM_GET_BAND frequency %d, band %u",
    ++                __func__, frequency, *(uint16_t *)pValue);
    ++    } break;
    + 
    +-    switch (param) {
    +-    case EQ_PARAM_NUM_BANDS:
    +-        *(uint16_t *)pValue = (uint16_t)FIVEBAND_NUMBANDS;
    +-        //ALOGV("\tEqualizer_getParameter() EQ_PARAM_NUM_BANDS %d", *(int16_t *)pValue);
    +-        break;
    ++    case EQ_PARAM_BAND_LEVEL: {
    ++        if (paramSize < 2 * sizeof(int32_t)) {
    ++            ALOGV("%s EQ_PARAM_BAND_LEVEL invalid paramSize %u", __func__, paramSize);
    ++            status = -EINVAL;
    ++            break;
    ++        }
    ++        if (*pValueSize < sizeof(int16_t)) {
    ++            ALOGV("%s EQ_PARAM_BAND_LEVEL invalid *pValueSize %u", __func__, *pValueSize);
    ++            status = -EINVAL;
    ++            break;
    ++        }
    ++        *pValueSize = sizeof(int16_t);
     +
    -         uint32_t usageBits;
    -         if (mOMX->getParameter(
    -                 mNode, (OMX_INDEXTYPE)OMX_IndexParamConsumerUsageBits,
    -@@ -4274,7 +4291,9 @@ status_t ACodec::setupAVCEncoderParameters(const sp<AMessage> &msg) {
    ++        const int32_t band = params[1];
    ++        if (band < 0 || band >= FIVEBAND_NUMBANDS) {
    ++            if (band < 0) {
    ++                android_errorWriteLog(0x534e4554, "32438598");
    ++                ALOGW("%s EQ_PARAM_BAND_LEVEL invalid band %d", __func__, band);
    ++            }
    ++            status = -EINVAL;
    ++            break;
    ++        }
    ++        *(int16_t *)pValue = (int16_t)EqualizerGetBandLevel(pContext, band);
    ++        ALOGVV("%s EQ_PARAM_BAND_LEVEL band %d, level %d",
    ++                __func__, band, *(int16_t *)pValue);
    ++    } break;
      
    -         h264type.eProfile = static_cast<OMX_VIDEO_AVCPROFILETYPE>(profile);
    -         h264type.eLevel = static_cast<OMX_VIDEO_AVCLEVELTYPE>(level);
    --    } else {
    -+    }
    -+#ifdef USE_AVC_BASELINE_PROFILE
    -+      else {
    -         h264type.eProfile = OMX_VIDEO_AVCProfileBaseline;
    - #if 0   /* DON'T YET DEFAULT TO HIGHEST PROFILE */
    -         // Use largest supported profile for AVC recording if profile is not specified.
    -@@ -4287,6 +4306,7 @@ status_t ACodec::setupAVCEncoderParameters(const sp<AMessage> &msg) {
    -         }
    - #endif
    -     }
    -+#endif
    +     case EQ_PARAM_LEVEL_RANGE:
    ++        if (*pValueSize < 2 * sizeof(int16_t)) {
    ++            ALOGV("%s EQ_PARAM_LEVEL_RANGE invalid *pValueSize %u", __func__, *pValueSize);
    ++            status = -EINVAL;
    ++            break;
    ++        }
    ++        *pValueSize = 2 * sizeof(int16_t);
    ++
    +         *(int16_t *)pValue = -1500;
    +         *((int16_t *)pValue + 1) = 1500;
    +-        //ALOGV("\tEqualizer_getParameter() EQ_PARAM_LEVEL_RANGE min %d, max %d",
    +-        //      *(int16_t *)pValue, *((int16_t *)pValue + 1));
    ++        ALOGVV("%s EQ_PARAM_LEVEL_RANGE min %d, max %d",
    ++                __func__, *(int16_t *)pValue, *((int16_t *)pValue + 1));
    +         break;
      
    -     ALOGI("setupAVCEncoderParameters with [profile: %s] [level: %s]",
    -             asString(h264type.eProfile), asString(h264type.eLevel));
    -@@ -6036,6 +6056,9 @@ void ACodec::BaseState::onInputBufferFilled(const sp<AMessage> &msg) {
    -                 status_t err2 = OK;
    -                 switch (metaType) {
    -                 case kMetadataBufferTypeInvalid:
    -+#ifdef CAMCORDER_GRALLOC_SOURCE
    -+                case kMetadataBufferTypeCameraSource:
    -+#endif
    -                     break;
    - #ifndef OMX_ANDROID_COMPILE_AS_32BIT_ON_64BIT_PLATFORMS
    -                 case kMetadataBufferTypeNativeHandleSource:
    -@@ -6267,6 +6290,10 @@ bool ACodec::BaseState::onOMXFillBufferDone(
    -                 native_handle_t *handle = NULL;
    -                 VideoNativeHandleMetadata &nativeMeta =
    -                     *(VideoNativeHandleMetadata *)info->mData->data();
    -+#ifdef CAMCORDER_GRALLOC_SOURCE
    -+                VideoGrallocMetadata &grallocMeta =
    -+                    *(VideoGrallocMetadata *)info->mData->data();
    -+#endif
    -                 if (info->mData->size() >= sizeof(nativeMeta)
    -                         && nativeMeta.eType == kMetadataBufferTypeNativeHandleSource) {
    - #ifdef OMX_ANDROID_COMPILE_AS_32BIT_ON_64BIT_PLATFORMS
    -@@ -6276,6 +6303,12 @@ bool ACodec::BaseState::onOMXFillBufferDone(
    -                     handle = (native_handle_t *)nativeMeta.pHandle;
    - #endif
    -                 }
    -+#ifdef CAMCORDER_GRALLOC_SOURCE
    -+                else if (info->mData->size() >= sizeof(grallocMeta)
    -+                        && grallocMeta.eType == kMetadataBufferTypeGrallocSource) {
    -+                    handle = (native_handle_t *)(uintptr_t)grallocMeta.pHandle;
    -+                }
    -+#endif
    -                 info->mData->meta()->setPointer("handle", handle);
    -                 info->mData->meta()->setInt32("rangeOffset", rangeOffset);
    -                 info->mData->meta()->setInt32("rangeLength", rangeLength);
    -@@ -6968,10 +7001,12 @@ void ACodec::LoadedState::onCreateInputSurface(
    -         err = mCodec->mOMX->createInputSurface(
    -                 mCodec->mNode, kPortIndexInput, dataSpace, &bufferProducer,
    -                 &mCodec->mInputMetadataType);
    -+#ifndef CAMCORDER_GRALLOC_SOURCE
    -         // framework uses ANW buffers internally instead of gralloc handles
    -         if (mCodec->mInputMetadataType == kMetadataBufferTypeGrallocSource) {
    -             mCodec->mInputMetadataType = kMetadataBufferTypeANWBuffer;
    +-    case EQ_PARAM_BAND_LEVEL:
    +-        param2 = *pParamTemp;
    +-        if (param2 < 0 || param2 >= FIVEBAND_NUMBANDS) {
    ++    case EQ_PARAM_BAND_FREQ_RANGE: {
    ++        if (paramSize < 2 * sizeof(int32_t)) {
    ++            ALOGV("%s EQ_PARAM_BAND_FREQ_RANGE invalid paramSize: %u", __func__, paramSize);
    +             status = -EINVAL;
    +-            if (param2 < 0) {
    +-                android_errorWriteLog(0x534e4554, "32438598");
    +-                ALOGW("\tERROR Equalizer_getParameter() EQ_PARAM_BAND_LEVEL band %d", param2);
    +-            }
    +             break;
              }
    -+#endif
    -     }
    +-        *(int16_t *)pValue = (int16_t)EqualizerGetBandLevel(pContext, param2);
    +-        //ALOGV("\tEqualizer_getParameter() EQ_PARAM_BAND_LEVEL band %d, level %d",
    +-        //      param2, *(int32_t *)pValue);
    +-        break;
    +-
    +-    case EQ_PARAM_CENTER_FREQ:
    +-        param2 = *pParamTemp;
    +-        if (param2 < 0 || param2 >= FIVEBAND_NUMBANDS) {
    ++        if (*pValueSize < 2 * sizeof(int32_t)) {
    ++            ALOGV("%s EQ_PARAM_BAND_FREQ_RANGE invalid *pValueSize %u", __func__, *pValueSize);
    +             status = -EINVAL;
    +-            if (param2 < 0) {
    +-                android_errorWriteLog(0x534e4554, "32436341");
    +-                ALOGW("\tERROR Equalizer_getParameter() EQ_PARAM_CENTER_FREQ band %d", param2);
    +-            }
    +             break;
    +         }
    +-        *(int32_t *)pValue = EqualizerGetCentreFrequency(pContext, param2);
    +-        //ALOGV("\tEqualizer_getParameter() EQ_PARAM_CENTER_FREQ band %d, frequency %d",
    +-        //      param2, *(int32_t *)pValue);
    +-        break;
    ++        *pValueSize = 2 * sizeof(int32_t);
      
    -     if (err == OK) {
    -@@ -7014,10 +7049,12 @@ void ACodec::LoadedState::onSetInputSurface(
    -         err = mCodec->mOMX->setInputSurface(
    -                 mCodec->mNode, kPortIndexInput, surface->getBufferConsumer(),
    -                 &mCodec->mInputMetadataType);
    -+#ifndef CAMCORDER_GRALLOC_SOURCE
    -         // framework uses ANW buffers internally instead of gralloc handles
    -         if (mCodec->mInputMetadataType == kMetadataBufferTypeGrallocSource) {
    -             mCodec->mInputMetadataType = kMetadataBufferTypeANWBuffer;
    +-    case EQ_PARAM_BAND_FREQ_RANGE:
    +-        param2 = *pParamTemp;
    +-        if (param2 < 0 || param2 >= FIVEBAND_NUMBANDS) {
    +-            status = -EINVAL;
    +-            if (param2 < 0) {
    ++        const int32_t band = params[1];
    ++        if (band < 0 || band >= FIVEBAND_NUMBANDS) {
    ++            if (band < 0) {
    +                 android_errorWriteLog(0x534e4554, "32247948");
    +-                ALOGW("\tERROR Equalizer_getParameter() EQ_PARAM_BAND_FREQ_RANGE band %d", param2);
    ++                ALOGW("%s EQ_PARAM_BAND_FREQ_RANGE invalid band %d",
    ++                        __func__, band);
    +             }
    ++            status = -EINVAL;
    +             break;
              }
    -+#endif
    -     }
    +-        EqualizerGetBandFreqRange(pContext, param2, (uint32_t *)pValue, ((uint32_t *)pValue + 1));
    +-        //ALOGV("\tEqualizer_getParameter() EQ_PARAM_BAND_FREQ_RANGE band %d, min %d, max %d",
    +-        //      param2, *(int32_t *)pValue, *((int32_t *)pValue + 1));
    +-        break;
    ++        EqualizerGetBandFreqRange(pContext, band, (uint32_t *)pValue, ((uint32_t *)pValue + 1));
    ++        ALOGVV("%s EQ_PARAM_BAND_FREQ_RANGE band %d, min %d, max %d",
    ++                __func__, band, *(int32_t *)pValue, *((int32_t *)pValue + 1));
      
    -     if (err == OK) {
    -diff --git a/media/libstagefright/Android.mk b/media/libstagefright/Android.mk
    -index 3848502..1635375 100644
    ---- a/media/libstagefright/Android.mk
    -+++ b/media/libstagefright/Android.mk
    -@@ -102,6 +102,10 @@ LOCAL_SHARED_LIBRARIES := \
    -         libz \
    -         libpowermanager
    +-    case EQ_PARAM_GET_BAND:
    +-        param2 = *pParamTemp;
    +-        *(uint16_t *)pValue = (uint16_t)EqualizerGetBand(pContext, param2);
    +-        //ALOGV("\tEqualizer_getParameter() EQ_PARAM_GET_BAND frequency %d, band %d",
    +-        //      param2, *(uint16_t *)pValue);
    +-        break;
    ++    } break;
      
    -+ifeq ($(TARGET_USE_AVC_BASELINE_PROFILE), true)
    -+LOCAL_CFLAGS += -DUSE_AVC_BASELINE_PROFILE
    -+endif
    +-    case EQ_PARAM_CUR_PRESET:
    +-        *(uint16_t *)pValue = (uint16_t)EqualizerGetPreset(pContext);
    +-        //ALOGV("\tEqualizer_getParameter() EQ_PARAM_CUR_PRESET %d", *(int32_t *)pValue);
    +-        break;
    ++    case EQ_PARAM_CENTER_FREQ: {
    ++        if (paramSize < 2 * sizeof(int32_t)) {
    ++            ALOGV("%s EQ_PARAM_CENTER_FREQ invalid paramSize: %u", __func__, paramSize);
    ++            status = -EINVAL;
    ++            break;
    ++        }
    ++        if (*pValueSize < sizeof(int32_t)) {
    ++            ALOGV("%s EQ_PARAM_CENTER_FREQ invalid *pValueSize %u", __func__, *pValueSize);
    ++            status = -EINVAL;
    ++            break;
    ++        }
    ++        *pValueSize = sizeof(int32_t);
    + 
    +-    case EQ_PARAM_GET_NUM_OF_PRESETS:
    +-        *(uint16_t *)pValue = (uint16_t)EqualizerGetNumPresets();
    +-        //ALOGV("\tEqualizer_getParameter() EQ_PARAM_GET_NUM_OF_PRESETS %d", *(int16_t *)pValue);
    +-        break;
    ++        const int32_t band = params[1];
    ++        if (band < 0 || band >= FIVEBAND_NUMBANDS) {
    ++            status = -EINVAL;
    ++            if (band < 0) {
    ++                android_errorWriteLog(0x534e4554, "32436341");
    ++                ALOGW("%s EQ_PARAM_CENTER_FREQ invalid band %d", __func__, band);
    ++            }
    ++            break;
    ++        }
    ++        *(int32_t *)pValue = EqualizerGetCentreFrequency(pContext, band);
    ++        ALOGVV("%s EQ_PARAM_CENTER_FREQ band %d, frequency %d",
    ++                __func__, band, *(int32_t *)pValue);
    ++    } break;
    + 
    +-    case EQ_PARAM_GET_PRESET_NAME:
    +-        param2 = *pParamTemp;
    +-        if ((param2 < 0 && param2 != PRESET_CUSTOM) ||  param2 >= EqualizerGetNumPresets()) {
    ++    case EQ_PARAM_GET_PRESET_NAME: {
    ++        if (paramSize < 2 * sizeof(int32_t)) {
    ++            ALOGV("%s EQ_PARAM_PRESET_NAME invalid paramSize: %u", __func__, paramSize);
    +             status = -EINVAL;
    +-            if (param2 < 0) {
    ++            break;
    ++        }
    ++        if (*pValueSize < 1) {
    ++            android_errorWriteLog(0x534e4554, "37536407");
    ++            status = -EINVAL;
    ++            break;
    ++        }
     +
    - LOCAL_STATIC_LIBRARIES := \
    -         libstagefright_color_conversion \
    -         libyuv_static \
    -@@ -124,6 +128,10 @@ LOCAL_SHARED_LIBRARIES += \
    -         libdl \
    -         libRScpp \
    ++        const int32_t preset = params[1];
    ++        if ((preset < 0 && preset != PRESET_CUSTOM) ||  preset >= EqualizerGetNumPresets()) {
    ++            if (preset < 0) {
    +                 android_errorWriteLog(0x534e4554, "32448258");
    +-                ALOGE("\tERROR Equalizer_getParameter() EQ_PARAM_GET_PRESET_NAME preset %d",
    +-                        param2);
    ++                ALOGE("%s EQ_PARAM_GET_PRESET_NAME preset %d", __func__, preset);
    +             }
    ++            status = -EINVAL;
    +             break;
    +         }
    +-        name = (char *)pValue;
    +-        strncpy(name, EqualizerGetPresetName(param2), *pValueSize - 1);
    ++
    ++        char * const name = (char *)pValue;
    ++        strncpy(name, EqualizerGetPresetName(preset), *pValueSize - 1);
    +         name[*pValueSize - 1] = 0;
    +         *pValueSize = strlen(name) + 1;
    +-        //ALOGV("\tEqualizer_getParameter() EQ_PARAM_GET_PRESET_NAME preset %d, name %s len %d",
    +-        //      param2, gEqualizerPresets[param2].name, *pValueSize);
    +-        break;
    ++        ALOGVV("%s EQ_PARAM_GET_PRESET_NAME preset %d, name %s len %d",
    ++                __func__, preset, gEqualizerPresets[preset].name, *pValueSize);
    ++
    ++    } break;
      
    -+ifeq ($(TARGET_HAS_LEGACY_CAMERA_HAL1),true)
    -+LOCAL_CFLAGS += -DCAMCORDER_GRALLOC_SOURCE
    -+endif
    +     case EQ_PARAM_PROPERTIES: {
    ++        constexpr uint32_t requiredValueSize = (2 + FIVEBAND_NUMBANDS) * sizeof(uint16_t);
    ++        if (*pValueSize < requiredValueSize) {
    ++            ALOGV("%s EQ_PARAM_PROPERTIES invalid *pValueSize %u", __func__, *pValueSize);
    ++            status = -EINVAL;
    ++            break;
    ++        }
    ++        *pValueSize = requiredValueSize;
     +
    - LOCAL_CFLAGS += -Wno-multichar -Werror -Wno-error=deprecated-declarations -Wall
    +         int16_t *p = (int16_t *)pValue;
    +-        ALOGV("\tEqualizer_getParameter() EQ_PARAM_PROPERTIES");
    ++        ALOGV("%s EQ_PARAM_PROPERTIES", __func__);
    +         p[0] = (int16_t)EqualizerGetPreset(pContext);
    +         p[1] = (int16_t)FIVEBAND_NUMBANDS;
    +         for (int i = 0; i < FIVEBAND_NUMBANDS; i++) {
    +@@ -2458,12 +2561,12 @@ int Equalizer_getParameter(EffectContext     *pContext,
    +     } break;
      
    - # enable experiments only in userdebug and eng builds
    -diff --git a/media/libstagefright/CameraSource.cpp b/media/libstagefright/CameraSource.cpp
    -index 893da89..2152454 100644
    ---- a/media/libstagefright/CameraSource.cpp
    -+++ b/media/libstagefright/CameraSource.cpp
    -@@ -950,6 +950,14 @@ void CameraSource::releaseRecordingFrame(const sp<IMemory>& frame) {
    - 
    -         if (handle != nullptr) {
    -             // Frame contains a VideoNativeHandleMetadata. Send the handle back to camera.
    -+            ssize_t offset;
    -+            size_t size;
    -+            sp<IMemoryHeap> heap = frame->getMemory(&offset, &size);
    -+            if (heap->getHeapID() != mMemoryHeapBase->getHeapID()) {
    -+                ALOGE("%s: Mismatched heap ID, ignoring release (got %x, expected %x)",
    -+		     __FUNCTION__, heap->getHeapID(), mMemoryHeapBase->getHeapID());
    -+                return;
    -+            }
    -             releaseRecordingFrameHandle(handle);
    -             mMemoryBases.push_back(frame);
    -             mMemoryBaseAvailableCond.signal();
    -@@ -1117,7 +1125,7 @@ void CameraSource::releaseRecordingFrameHandle(native_handle_t* handle) {
    -         int64_t token = IPCThreadState::self()->clearCallingIdentity();
    -         mCamera->releaseRecordingFrameHandle(handle);
    -         IPCThreadState::self()->restoreCallingIdentity(token);
    --    } else {
    -+    } else if (handle != nullptr) {
    -         native_handle_close(handle);
    -         native_handle_delete(handle);
    +     default:
    +-        ALOGV("\tLVM_ERROR : Equalizer_getParameter() invalid param %d", param);
    ++        ALOGV("%s invalid param %d", __func__, params[0]);
    +         status = -EINVAL;
    +         break;
          }
    -@@ -1250,6 +1258,10 @@ void CameraSource::processBufferQueueFrame(BufferItem& buffer) {
    - MetadataBufferType CameraSource::metaDataStoredInVideoBuffers() const {
    -     ALOGV("metaDataStoredInVideoBuffers");
      
    -+#ifdef CAMCORDER_GRALLOC_SOURCE
    -+    return kMetadataBufferTypeGrallocSource;
    -+#endif
    +-    //GV("\tEqualizer_getParameter end\n");
    ++    ALOGVV("%s end param: %d, status: %d", __func__, params[0], status);
    +     return status;
    + } /* end Equalizer_getParameter */
    + 
    +@@ -2483,74 +2586,89 @@ int Equalizer_getParameter(EffectContext     *pContext,
    + // Outputs:
    + //
    + //----------------------------------------------------------------------------
    +-int Equalizer_setParameter (EffectContext *pContext,
    +-                            void *pParam,
    +-                            uint32_t valueSize,
    +-                            void *pValue) {
    ++int Equalizer_setParameter(EffectContext *pContext,
    ++                           uint32_t       paramSize,
    ++                           void          *pParam,
    ++                           uint32_t       valueSize,
    ++                           void          *pValue) {
    +     int status = 0;
    +-    int32_t preset;
    +-    int32_t band;
    +-    int32_t level;
    +-    int32_t *pParamTemp = (int32_t *)pParam;
    +-    int32_t param = *pParamTemp++;
    ++    int32_t *params = (int32_t *)pParam;
    + 
    ++    ALOGVV("%s start", __func__);
    + 
    +-    //ALOGV("\tEqualizer_setParameter start");
    +-    switch (param) {
    +-    case EQ_PARAM_CUR_PRESET:
    ++    if (paramSize < sizeof(int32_t)) {
    ++        ALOGV("%s invalid paramSize: %u", __func__, paramSize);
    ++        return -EINVAL;
    ++    }
    ++    switch (params[0]) {
    ++    case EQ_PARAM_CUR_PRESET: {
    +         if (valueSize < sizeof(int16_t)) {
    +-          status = -EINVAL;
    +-          break;
    ++            ALOGV("%s EQ_PARAM_CUR_PRESET invalid valueSize %u", __func__, valueSize);
    ++            status = -EINVAL;
    ++            break;
    +         }
    +-        preset = (int32_t)(*(uint16_t *)pValue);
    ++        const int32_t preset = (int32_t)*(uint16_t *)pValue;
    + 
    +-        //ALOGV("\tEqualizer_setParameter() EQ_PARAM_CUR_PRESET %d", preset);
    +-        if ((preset >= EqualizerGetNumPresets())||(preset < 0)) {
    ++        ALOGVV("%s EQ_PARAM_CUR_PRESET %d", __func__, preset);
    ++        if (preset >= EqualizerGetNumPresets() || preset < 0) {
    ++            ALOGV("%s EQ_PARAM_CUR_PRESET invalid preset %d", __func__, preset);
    +             status = -EINVAL;
    +             break;
    +         }
    +         EqualizerSetPreset(pContext, preset);
    +-        break;
    +-    case EQ_PARAM_BAND_LEVEL:
    ++    } break;
     +
    -     // Output buffers will contain metadata if camera sends us buffer in metadata mode or via
    -     // buffer queue.
    -     switch (mVideoBufferMode) {
    -diff --git a/media/libstagefright/MPEG4Extractor.cpp b/media/libstagefright/MPEG4Extractor.cpp
    -index 5441714..4a33e7a 100644
    ---- a/media/libstagefright/MPEG4Extractor.cpp
    -+++ b/media/libstagefright/MPEG4Extractor.cpp
    -@@ -72,6 +72,7 @@ public:
    -                 Vector<SidxEntry> &sidx,
    -                 const Trex *trex,
    -                 off64_t firstMoofOffset);
    -+    virtual status_t init();
    ++    case EQ_PARAM_BAND_LEVEL: {
    ++        if (paramSize < 2 * sizeof(int32_t)) {
    ++            ALOGV("%s EQ_PARAM_BAND_LEVEL invalid paramSize: %u", __func__, paramSize);
    ++            status = -EINVAL;
    ++            break;
    ++        }
    +         if (valueSize < sizeof(int16_t)) {
    +-          status = -EINVAL;
    +-          break;
    ++            ALOGV("%s EQ_PARAM_BAND_LEVEL invalid valueSize %u", __func__, valueSize);
    ++            status = -EINVAL;
    ++            break;
    +         }
    +-        band =  *pParamTemp;
    +-        level = (int32_t)(*(int16_t *)pValue);
    +-        //ALOGV("\tEqualizer_setParameter() EQ_PARAM_BAND_LEVEL band %d, level %d", band, level);
    ++        const int32_t band =  params[1];
    ++        const int32_t level = (int32_t)*(int16_t *)pValue;
    ++        ALOGVV("%s EQ_PARAM_BAND_LEVEL band %d, level %d", __func__, band, level);
    +         if (band < 0 || band >= FIVEBAND_NUMBANDS) {
    +-            status = -EINVAL;
    +             if (band < 0) {
    +                 android_errorWriteLog(0x534e4554, "32095626");
    +-                ALOGE("\tERROR Equalizer_setParameter() EQ_PARAM_BAND_LEVEL band %d", band);
    ++                ALOGE("%s EQ_PARAM_BAND_LEVEL invalid band %d", __func__, band);
    +             }
    ++            status = -EINVAL;
    +             break;
    +         }
    +         EqualizerSetBandLevel(pContext, band, level);
    +-        break;
    ++    } break;
    ++
    +     case EQ_PARAM_PROPERTIES: {
    +-        //ALOGV("\tEqualizer_setParameter() EQ_PARAM_PROPERTIES");
    ++        ALOGVV("%s EQ_PARAM_PROPERTIES", __func__);
    +         if (valueSize < sizeof(int16_t)) {
    +-          status = -EINVAL;
    +-          break;
    ++            ALOGV("%s EQ_PARAM_PROPERTIES invalid valueSize %u", __func__, valueSize);
    ++            status = -EINVAL;
    ++            break;
    +         }
    +         int16_t *p = (int16_t *)pValue;
    +         if ((int)p[0] >= EqualizerGetNumPresets()) {
    ++            ALOGV("%s EQ_PARAM_PROPERTIES invalid preset %d", __func__, (int)p[0]);
    +             status = -EINVAL;
    +             break;
    +         }
    +         if (p[0] >= 0) {
    +             EqualizerSetPreset(pContext, (int)p[0]);
    +         } else {
    +-            if (valueSize < (2 + FIVEBAND_NUMBANDS) * sizeof(int16_t)) {
    ++            constexpr uint32_t valueSizeRequired = (2 + FIVEBAND_NUMBANDS) * sizeof(int16_t);
    ++            if (valueSize < valueSizeRequired) {
    +               android_errorWriteLog(0x534e4554, "37563371");
    +-              ALOGE("\tERROR Equalizer_setParameter() EQ_PARAM_PROPERTIES valueSize %d < %d",
    +-                    (int)valueSize, (int)((2 + FIVEBAND_NUMBANDS) * sizeof(int16_t)));
    ++              ALOGE("%s EQ_PARAM_PROPERTIES invalid valueSize %u < %u",
    ++                      __func__, valueSize, valueSizeRequired);
    +               status = -EINVAL;
    +               break;
    +             }
    +             if ((int)p[1] != FIVEBAND_NUMBANDS) {
    ++                ALOGV("%s EQ_PARAM_PROPERTIES invalid bands %d", __func__, (int)p[1]);
    +                 status = -EINVAL;
    +                 break;
    +             }
    +@@ -2559,13 +2677,14 @@ int Equalizer_setParameter (EffectContext *pContext,
    +             }
    +         }
    +     } break;
    ++
    +     default:
    +-        ALOGV("\tLVM_ERROR : Equalizer_setParameter() invalid param %d", param);
    ++        ALOGV("%s invalid param %d", __func__, params[0]);
    +         status = -EINVAL;
    +         break;
    +     }
      
    -     virtual status_t start(MetaData *params = NULL);
    -     virtual status_t stop();
    -@@ -935,6 +936,12 @@ status_t MPEG4Extractor::parseChunk(off64_t *offset, int depth) {
    -                 ALOGE("moov: depth %d", depth);
    -                 return ERROR_MALFORMED;
    +-    //ALOGV("\tEqualizer_setParameter end");
    ++    ALOGVV("%s end param: %d, status: %d", __func__, params[0], status);
    +     return status;
    + } /* end Equalizer_setParameter */
    + 
    +@@ -2590,81 +2709,92 @@ int Equalizer_setParameter (EffectContext *pContext,
    + //
    + //----------------------------------------------------------------------------
    + 
    +-int Volume_getParameter(EffectContext     *pContext,
    +-                        void              *pParam,
    +-                        uint32_t          *pValueSize,
    +-                        void              *pValue){
    ++int Volume_getParameter(EffectContext *pContext,
    ++                        uint32_t       paramSize,
    ++                        void          *pParam,
    ++                        uint32_t      *pValueSize,
    ++                        void          *pValue) {
    +     int status = 0;
    +-    int bMute = 0;
    +-    int32_t *pParamTemp = (int32_t *)pParam;
    +-    int32_t param = *pParamTemp++;;
    +-    char *name;
    ++    int32_t *params = (int32_t *)pParam;
    + 
    +-    //ALOGV("\tVolume_getParameter start");
    ++    ALOGVV("%s start", __func__);
    + 
    +-    switch (param){
    ++    if (paramSize < sizeof(int32_t)) {
    ++        ALOGV("%s invalid paramSize: %u", __func__, paramSize);
    ++        return -EINVAL;
    ++    }
    ++    switch (params[0]) {
    +         case VOLUME_PARAM_LEVEL:
    +-        case VOLUME_PARAM_MAXLEVEL:
    +-        case VOLUME_PARAM_STEREOPOSITION:
    +-            if (*pValueSize != sizeof(int16_t)){
    +-                ALOGV("\tLVM_ERROR : Volume_getParameter() invalid pValueSize 1  %d", *pValueSize);
    +-                return -EINVAL;
    +-            }
    +-            *pValueSize = sizeof(int16_t);
    +-            break;
    +-
    +-        case VOLUME_PARAM_MUTE:
    +-        case VOLUME_PARAM_ENABLESTEREOPOSITION:
    +-            if (*pValueSize < sizeof(int32_t)){
    +-                ALOGV("\tLVM_ERROR : Volume_getParameter() invalid pValueSize 2  %d", *pValueSize);
    +-                return -EINVAL;
    ++            if (*pValueSize != sizeof(int16_t)) { // legacy: check equality here.
    ++                ALOGV("%s VOLUME_PARAM_LEVEL invalid *pValueSize %u", __func__, *pValueSize);
    ++                status = -EINVAL;
    ++                break;
                  }
    +-            *pValueSize = sizeof(int32_t);
    +-            break;
    ++            // no need to set *pValueSize
    + 
    +-        default:
    +-            ALOGV("\tLVM_ERROR : Volume_getParameter unknown param %d", param);
    +-            return -EINVAL;
    +-    }
    +-
    +-    switch (param){
    +-        case VOLUME_PARAM_LEVEL:
    +             status = VolumeGetVolumeLevel(pContext, (int16_t *)(pValue));
    +-            //ALOGV("\tVolume_getParameter() VOLUME_PARAM_LEVEL Value is %d",
    +-            //        *(int16_t *)pValue);
    ++            ALOGVV("%s VOLUME_PARAM_LEVEL %d", __func__, *(int16_t *)pValue);
    +             break;
    + 
    +         case VOLUME_PARAM_MAXLEVEL:
    ++            if (*pValueSize != sizeof(int16_t)) { // legacy: check equality here.
    ++                ALOGV("%s VOLUME_PARAM_MAXLEVEL invalid *pValueSize %u", __func__, *pValueSize);
    ++                status = -EINVAL;
    ++                break;
    ++            }
    ++            // no need to set *pValueSize
     +
    -+            if (chunk_type == FOURCC('m', 'o', 'o', 'v') && mInitCheck == OK) {
    -+                ALOGE("duplicate moov");
    -+                return ERROR_MALFORMED;
    ++            // in millibel
    +             *(int16_t *)pValue = 0;
    +-            //ALOGV("\tVolume_getParameter() VOLUME_PARAM_MAXLEVEL Value is %d",
    +-            //        *(int16_t *)pValue);
    ++            ALOGVV("%s VOLUME_PARAM_MAXLEVEL %d", __func__, *(int16_t *)pValue);
    +             break;
    + 
    +         case VOLUME_PARAM_STEREOPOSITION:
    ++            if (*pValueSize != sizeof(int16_t)) { // legacy: check equality here.
    ++                ALOGV("%s VOLUME_PARAM_STEREOPOSITION invalid *pValueSize %u",
    ++                        __func__, *pValueSize);
    ++                status = -EINVAL;
    ++                break;
     +            }
    ++            // no need to set *pValueSize
     +
    -             if (chunk_type == FOURCC('m', 'o', 'o', 'f') && !mMoofFound) {
    -                 // store the offset of the first segment
    -                 mMoofFound = true;
    -@@ -1008,6 +1015,12 @@ status_t MPEG4Extractor::parseChunk(off64_t *offset, int depth) {
    -                 if (!mLastTrack->meta->findInt32(kKeyTrackID, &trackId)) {
    -                     mLastTrack->skipTrack = true;
    -                 }
    +             VolumeGetStereoPosition(pContext, (int16_t *)pValue);
    +-            //ALOGV("\tVolume_getParameter() VOLUME_PARAM_STEREOPOSITION Value is %d",
    +-            //        *(int16_t *)pValue);
    ++            ALOGVV("%s VOLUME_PARAM_STEREOPOSITION %d", __func__, *(int16_t *)pValue);
    +             break;
    + 
    +         case VOLUME_PARAM_MUTE:
    ++            if (*pValueSize < sizeof(uint32_t)) {
    ++                ALOGV("%s VOLUME_PARAM_MUTE invalid *pValueSize %u", __func__, *pValueSize);
    ++                status = -EINVAL;
    ++                break;
    ++            }
    ++            *pValueSize = sizeof(uint32_t);
     +
    -+                status_t err = verifyTrack(mLastTrack);
    -+                if (err != OK) {
    -+                    mLastTrack->skipTrack = true;
    -+                }
    +             status = VolumeGetMute(pContext, (uint32_t *)pValue);
    +-            ALOGV("\tVolume_getParameter() VOLUME_PARAM_MUTE Value is %d",
    +-                    *(uint32_t *)pValue);
    ++            ALOGV("%s VOLUME_PARAM_MUTE %u", __func__, *(uint32_t *)pValue);
    +             break;
    + 
    +         case VOLUME_PARAM_ENABLESTEREOPOSITION:
    ++            if (*pValueSize < sizeof(int32_t)) {
    ++                ALOGV("%s VOLUME_PARAM_ENABLESTEREOPOSITION invalid *pValueSize %u",
    ++                        __func__, *pValueSize);
    ++                status = -EINVAL;
    ++                break;
    ++            }
    ++            *pValueSize = sizeof(int32_t);
     +
    -                 if (mLastTrack->skipTrack) {
    -                     Track *cur = mFirstTrack;
    +             *(int32_t *)pValue = pContext->pBundledContext->bStereoPositionEnabled;
    +-            //ALOGV("\tVolume_getParameter() VOLUME_PARAM_ENABLESTEREOPOSITION Value is %d",
    +-            //        *(uint32_t *)pValue);
    ++            ALOGVV("%s VOLUME_PARAM_ENABLESTEREOPOSITION %d", __func__, *(int32_t *)pValue);
    ++
    +             break;
      
    -@@ -1025,12 +1038,6 @@ status_t MPEG4Extractor::parseChunk(off64_t *offset, int depth) {
    +         default:
    +-            ALOGV("\tLVM_ERROR : Volume_getParameter() invalid param %d", param);
    ++            ALOGV("%s invalid param %d", __func__, params[0]);
    +             status = -EINVAL;
    +             break;
    +     }
      
    -                     return OK;
    -                 }
    --
    --                status_t err = verifyTrack(mLastTrack);
    --
    --                if (err != OK) {
    --                    return err;
    --                }
    -             } else if (chunk_type == FOURCC('m', 'o', 'o', 'v')) {
    -                 mInitCheck = OK;
    +-    //ALOGV("\tVolume_getParameter end");
    ++    ALOGVV("%s end param: %d, status: %d", __func__, params[0], status);
    +     return status;
    + } /* end Volume_getParameter */
      
    -@@ -2148,7 +2155,10 @@ status_t MPEG4Extractor::parseChunk(off64_t *offset, int depth) {
    -             *offset += chunk_size;
    +@@ -2684,55 +2814,87 @@ int Volume_getParameter(EffectContext     *pContext,
    + //
    + //----------------------------------------------------------------------------
      
    -             if (underQTMetaPath(mPath, 3)) {
    --                parseQTMetaKey(data_offset, chunk_data_size);
    -+                status_t err = parseQTMetaKey(data_offset, chunk_data_size);
    -+                if (err != OK) {
    -+                    return err;
    -+                }
    -             }
    -             break;
    -         }
    -@@ -2307,7 +2317,10 @@ status_t MPEG4Extractor::parseChunk(off64_t *offset, int depth) {
    +-int Volume_setParameter (EffectContext *pContext, void *pParam, void *pValue){
    +-    int      status = 0;
    +-    int16_t  level;
    +-    int16_t  position;
    +-    uint32_t mute;
    +-    uint32_t positionEnabled;
    +-    int32_t *pParamTemp = (int32_t *)pParam;
    +-    int32_t param = *pParamTemp++;
    ++int Volume_setParameter(EffectContext *pContext,
    ++                        uint32_t       paramSize,
    ++                        void          *pParam,
    ++                        uint32_t       valueSize,
    ++                        void          *pValue) {
    ++    int status = 0;
    ++    int32_t *params = (int32_t *)pParam;
      
    -         case FOURCC('s', 'i', 'd', 'x'):
    -         {
    --            parseSegmentIndex(data_offset, chunk_data_size);
    -+            status_t err = parseSegmentIndex(data_offset, chunk_data_size);
    -+            if (err != OK) {
    -+                return err;
    +-    //ALOGV("\tVolume_setParameter start");
    ++    ALOGVV("%s start", __func__);
    + 
    +-    switch (param){
    +-        case VOLUME_PARAM_LEVEL:
    +-            level = *(int16_t *)pValue;
    +-            //ALOGV("\tVolume_setParameter() VOLUME_PARAM_LEVEL value is %d", level);
    +-            //ALOGV("\tVolume_setParameter() Calling pVolume->setVolumeLevel");
    +-            status = VolumeSetVolumeLevel(pContext, (int16_t)level);
    +-            //ALOGV("\tVolume_setParameter() Called pVolume->setVolumeLevel");
    +-            break;
    ++    if (paramSize < sizeof(int32_t)) {
    ++        ALOGV("%s invalid paramSize: %u", __func__, paramSize);
    ++        return -EINVAL;
    ++    }
    ++    switch (params[0]) {
    ++        case VOLUME_PARAM_LEVEL: {
    ++            if (valueSize < sizeof(int16_t)) {
    ++                ALOGV("%s VOLUME_PARAM_LEVEL invalid valueSize %u", __func__, valueSize);
    ++                status = -EINVAL;
    ++                break;
     +            }
    -             *offset += chunk_size;
    -             return UNKNOWN_ERROR; // stop parsing after sidx
    -         }
    -@@ -2349,7 +2362,10 @@ status_t MPEG4Extractor::parseChunk(off64_t *offset, int depth) {
    -             // check if we're parsing 'ilst' for meta keys
    -             // if so, treat type as a number (key-id).
    -             if (underQTMetaPath(mPath, 3)) {
    --                parseQTMetaVal(chunk_type, data_offset, chunk_data_size);
    -+                status_t err = parseQTMetaVal(chunk_type, data_offset, chunk_data_size);
    -+                if (err != OK) {
    -+                    return err;
    -+                }
    -             }
      
    -             *offset += chunk_size;
    -@@ -2984,6 +3000,13 @@ status_t MPEG4Extractor::parse3GPPMetaData(off64_t offset, size_t size, int dept
    -         }
    -         case FOURCC('y', 'r', 'r', 'c'):
    -         {
    -+            if (size < 6) {
    -+                delete[] buffer;
    -+                buffer = NULL;
    -+                ALOGE("b/62133227");
    -+                android_errorWriteLog(0x534e4554, "62133227");
    -+                return ERROR_MALFORMED;
    +-        case VOLUME_PARAM_MUTE:
    +-            mute = *(uint32_t *)pValue;
    +-            //ALOGV("\tVolume_setParameter() Calling pVolume->setMute, mute is %d", mute);
    +-            //ALOGV("\tVolume_setParameter() Calling pVolume->setMute");
    ++            const int16_t level = *(int16_t *)pValue;
    ++            ALOGVV("%s VOLUME_PARAM_LEVEL %d", __func__, level);
    ++            ALOGVV("%s VOLUME_PARAM_LEVEL Calling VolumeSetVolumeLevel", __func__);
    ++            status = VolumeSetVolumeLevel(pContext, level);
    ++            ALOGVV("%s VOLUME_PARAM_LEVEL Called VolumeSetVolumeLevel", __func__);
    ++        } break;
    ++
    ++        case VOLUME_PARAM_MUTE: {
    ++            if (valueSize < sizeof(uint32_t)) {
    ++                ALOGV("%s VOLUME_PARAM_MUTE invalid valueSize %u", __func__, valueSize);
    ++                android_errorWriteLog(0x534e4554, "64477217");
    ++                status = -EINVAL;
    ++                break;
     +            }
    -             char tmp[5];
    -             uint16_t year = U16_AT(&buffer[4]);
    ++
    ++            const uint32_t mute = *(uint32_t *)pValue;
    ++            ALOGVV("%s VOLUME_PARAM_MUTE %d", __func__, mute);
    ++            ALOGVV("%s VOLUME_PARAM_MUTE Calling VolumeSetMute", __func__);
    +             status = VolumeSetMute(pContext, mute);
    +-            //ALOGV("\tVolume_setParameter() Called pVolume->setMute");
    +-            break;
    ++            ALOGVV("%s VOLUME_PARAM_MUTE Called VolumeSetMute", __func__);
    ++        } break;
      
    -@@ -3006,6 +3029,8 @@ status_t MPEG4Extractor::parse3GPPMetaData(off64_t offset, size_t size, int dept
    +-        case VOLUME_PARAM_ENABLESTEREOPOSITION:
    +-            positionEnabled = *(uint32_t *)pValue;
    +-            status = VolumeEnableStereoPosition(pContext, positionEnabled);
    +-            status = VolumeSetStereoPosition(pContext, pContext->pBundledContext->positionSaved);
    +-            //ALOGV("\tVolume_setParameter() VOLUME_PARAM_ENABLESTEREOPOSITION called");
    +-            break;
    ++        case VOLUME_PARAM_ENABLESTEREOPOSITION: {
    ++            if (valueSize < sizeof(uint32_t)) {
    ++                ALOGV("%s VOLUME_PARAM_ENABLESTEREOPOSITION invalid valueSize %u",
    ++                        __func__, valueSize);
    ++                status = -EINVAL;
    ++                break;
    ++            }
      
    -         // smallest possible valid UTF-16 string w BOM: 0xfe 0xff 0x00 0x00
    -         if (size < 6) {
    -+            delete[] buffer;
    -+            buffer = NULL;
    -             return ERROR_MALFORMED;
    -         }
    +-        case VOLUME_PARAM_STEREOPOSITION:
    +-            position = *(int16_t *)pValue;
    +-            //ALOGV("\tVolume_setParameter() VOLUME_PARAM_STEREOPOSITION value is %d", position);
    +-            //ALOGV("\tVolume_setParameter() Calling pVolume->VolumeSetStereoPosition");
    +-            status = VolumeSetStereoPosition(pContext, (int16_t)position);
    +-            //ALOGV("\tVolume_setParameter() Called pVolume->VolumeSetStereoPosition");
    +-            break;
    ++            const uint32_t positionEnabled = *(uint32_t *)pValue;
    ++            status = VolumeEnableStereoPosition(pContext, positionEnabled)
    ++                    ?: VolumeSetStereoPosition(pContext, pContext->pBundledContext->positionSaved);
    ++            ALOGVV("%s VOLUME_PARAM_ENABLESTEREOPOSITION called", __func__);
    ++        } break;
    ++
    ++        case VOLUME_PARAM_STEREOPOSITION: {
    ++            if (valueSize < sizeof(int16_t)) {
    ++                ALOGV("%s VOLUME_PARAM_STEREOPOSITION invalid valueSize %u", __func__, valueSize);
    ++                status = -EINVAL;
    ++                break;
    ++            }
    ++
    ++            const int16_t position = *(int16_t *)pValue;
    ++            ALOGVV("%s VOLUME_PARAM_STEREOPOSITION %d", __func__, position);
    ++            ALOGVV("%s VOLUME_PARAM_STEREOPOSITION Calling VolumeSetStereoPosition",
    ++                    __func__);
    ++            status = VolumeSetStereoPosition(pContext, position);
    ++            ALOGVV("%s VOLUME_PARAM_STEREOPOSITION Called VolumeSetStereoPosition",
    ++                    __func__);
    ++        } break;
      
    -@@ -3174,9 +3199,13 @@ sp<IMediaSource> MPEG4Extractor::getTrack(size_t index) {
    -         }
    +         default:
    +-            ALOGV("\tLVM_ERROR : Volume_setParameter() invalid param %d", param);
    ++            ALOGV("%s invalid param %d", __func__, params[0]);
    ++            status = -EINVAL;
    +             break;
          }
      
    --    return new MPEG4Source(this,
    -+    sp<MPEG4Source> source =  new MPEG4Source(this,
    -             track->meta, mDataSource, track->timescale, track->sampleTable,
    -             mSidxEntries, trex, mMoofOffset);
    -+    if (source->init() != OK) {
    -+        return NULL;
    -+    }
    -+    return source;
    - }
    +-    //ALOGV("\tVolume_setParameter end");
    ++    ALOGVV("%s end param: %d, status: %d", __func__, params[0], status);
    +     return status;
    + } /* end Volume_setParameter */
      
    - // static
    -@@ -3573,6 +3602,7 @@ MPEG4Source::MPEG4Source(
    -       mTrex(trex),
    -       mFirstMoofOffset(firstMoofOffset),
    -       mCurrentMoofOffset(firstMoofOffset),
    -+      mNextMoofOffset(-1),
    -       mCurrentTime(0),
    -       mCurrentSampleInfoAllocSize(0),
    -       mCurrentSampleInfoSizes(NULL),
    -@@ -3637,10 +3667,14 @@ MPEG4Source::MPEG4Source(
    +@@ -2928,11 +3090,8 @@ int Effect_process(effect_handle_t     self,
    +                               audio_buffer_t         *inBuffer,
    +                               audio_buffer_t         *outBuffer){
    +     EffectContext * pContext = (EffectContext *) self;
    +-    LVM_ReturnStatus_en     LvmStatus = LVM_SUCCESS;                /* Function call status */
    +     int    status = 0;
    +     int    processStatus = 0;
    +-    LVM_INT16   *in  = (LVM_INT16 *)inBuffer->raw;
    +-    LVM_INT16   *out = (LVM_INT16 *)outBuffer->raw;
      
    -     CHECK(format->findInt32(kKeyTrackID, &mTrackId));
    + //ALOGV("\tEffect_process Start : Enabled = %d     Called = %d (%8d %8d %8d)",
    + //pContext->pBundledContext->NumberEffectsEnabled,pContext->pBundledContext->NumberEffectsCalled,
    +@@ -3053,6 +3212,13 @@ int Effect_process(effect_handle_t     self,
    +     return status;
    + }   /* end Effect_process */
      
    ++// The value offset of an effect parameter is computed by rounding up
    ++// the parameter size to the next 32 bit alignment.
    ++static inline uint32_t computeParamVOffset(const effect_param_t *p) {
    ++    return ((p->psize + sizeof(int32_t) - 1) / sizeof(int32_t)) *
    ++            sizeof(int32_t);
     +}
     +
    -+status_t MPEG4Source::init() {
    -     if (mFirstMoofOffset != 0) {
    -         off64_t offset = mFirstMoofOffset;
    --        parseChunk(&offset);
    -+        return parseChunk(&offset);
    -     }
    -+    return OK;
    - }
    + /* Effect Control Interface Implementation: Command */
    + int Effect_command(effect_handle_t  self,
    +                               uint32_t            cmdCode,
    +@@ -3061,7 +3227,6 @@ int Effect_command(effect_handle_t  self,
    +                               uint32_t            *replySize,
    +                               void                *pReplyData){
    +     EffectContext * pContext = (EffectContext *) self;
    +-    int retsize;
      
    - MPEG4Source::~MPEG4Source() {
    -@@ -3767,13 +3801,35 @@ status_t MPEG4Source::parseChunk(off64_t *offset) {
    +     //ALOGV("\t\nEffect_command start");
      
    -                 while (true) {
    -                     if (mDataSource->readAt(*offset, hdr, 8) < 8) {
    --                        return ERROR_END_OF_STREAM;
    -+                        // no more box to the end of file.
    -+                        break;
    -                     }
    -                     chunk_size = ntohl(hdr[0]);
    -                     chunk_type = ntohl(hdr[1]);
    -+                    if (chunk_size == 1) {
    -+                        // ISO/IEC 14496-12:2012, 8.8.4 Movie Fragment Box, moof is a Box
    -+                        // which is defined in 4.2 Object Structure.
    -+                        // When chunk_size==1, 8 bytes follows as "largesize".
    -+                        if (mDataSource->readAt(*offset + 8, &chunk_size, 8) < 8) {
    -+                            return ERROR_IO;
    -+                        }
    -+                        chunk_size = ntoh64(chunk_size);
    -+                        if (chunk_size < 16) {
    -+                            // The smallest valid chunk is 16 bytes long in this case.
    -+                            return ERROR_MALFORMED;
    -+                        }
    -+                    } else if (chunk_size == 0) {
    -+                        // next box extends to end of file.
    -+                    } else if (chunk_size < 8) {
    -+                        // The smallest valid chunk is 8 bytes long in this case.
    -+                        return ERROR_MALFORMED;
    -+                    }
    -+
    -                     if (chunk_type == FOURCC('m', 'o', 'o', 'f')) {
    -                         mNextMoofOffset = *offset;
    -                         break;
    -+                    } else if (chunk_size == 0) {
    -+                        break;
    -                     }
    -                     *offset += chunk_size;
    -                 }
    -@@ -4651,17 +4707,25 @@ status_t MPEG4Source::fragmentedRead(
    -                 totalOffset += se->mSize;
    +@@ -3164,8 +3329,7 @@ int Effect_command(effect_handle_t  self,
    +                 ALOGV("\tLVM_ERROR : EFFECT_CMD_GET_PARAM: psize too big");
    +                 return -EINVAL;
                  }
    -             mCurrentMoofOffset = totalOffset;
    -+            mNextMoofOffset = -1;
    -             mCurrentSamples.clear();
    -             mCurrentSampleIndex = 0;
    --            parseChunk(&totalOffset);
    -+            status_t err = parseChunk(&totalOffset);
    -+            if (err != OK) {
    -+                return err;
    -+            }
    -             mCurrentTime = totalTime * mTimescale / 1000000ll;
    -         } else {
    -             // without sidx boxes, we can only seek to 0
    -             mCurrentMoofOffset = mFirstMoofOffset;
    -+            mNextMoofOffset = -1;
    -             mCurrentSamples.clear();
    -             mCurrentSampleIndex = 0;
    -             off64_t tmp = mCurrentMoofOffset;
    --            parseChunk(&tmp);
    -+            status_t err = parseChunk(&tmp);
    -+            if (err != OK) {
    -+                return err;
    -+            }
    -             mCurrentTime = 0;
    -         }
    +-            uint32_t paddedParamSize = ((p->psize + sizeof(int32_t) - 1) / sizeof(int32_t)) *
    +-                    sizeof(int32_t);
    ++            const uint32_t paddedParamSize = computeParamVOffset(p);
    +             if ((EFFECT_PARAM_SIZE_MAX - sizeof(effect_param_t) < paddedParamSize) ||
    +                 (EFFECT_PARAM_SIZE_MAX - sizeof(effect_param_t) - paddedParamSize <
    +                     p->vsize)) {
    +@@ -3187,6 +3351,7 @@ int Effect_command(effect_handle_t  self,
    +             uint32_t voffset = paddedParamSize;
    +             if(pContext->EffectType == LVM_BASS_BOOST){
    +                 p->status = android::BassBoost_getParameter(pContext,
    ++                                                            p->psize,
    +                                                             p->data,
    +                                                             &p->vsize,
    +                                                             p->data + voffset);
    +@@ -3199,6 +3364,7 @@ int Effect_command(effect_handle_t  self,
      
    -@@ -4690,7 +4754,10 @@ status_t MPEG4Source::fragmentedRead(
    -             mCurrentMoofOffset = nextMoof;
    -             mCurrentSamples.clear();
    -             mCurrentSampleIndex = 0;
    --            parseChunk(&nextMoof);
    -+            status_t err = parseChunk(&nextMoof);
    -+            if (err != OK) {
    -+                return err;
    -+            }
    -             if (mCurrentSampleIndex >= mCurrentSamples.size()) {
    -                 return ERROR_END_OF_STREAM;
    -             }
    -diff --git a/media/libstagefright/MediaCodecList.cpp b/media/libstagefright/MediaCodecList.cpp
    -index 0fb5072..a25c47d 100644
    ---- a/media/libstagefright/MediaCodecList.cpp
    -+++ b/media/libstagefright/MediaCodecList.cpp
    -@@ -1165,7 +1165,9 @@ void MediaCodecList::findMatchingCodecs(
    -         CHECK(info != NULL);
    -         AString componentName = info->getCodecName();
    +             if(pContext->EffectType == LVM_VIRTUALIZER){
    +                 p->status = android::Virtualizer_getParameter(pContext,
    ++                                                              p->psize,
    +                                                               (void *)p->data,
    +                                                               &p->vsize,
    +                                                               p->data + voffset);
    +@@ -3213,6 +3379,7 @@ int Effect_command(effect_handle_t  self,
    +                 //ALOGV("\tEqualizer_command cmdCode Case: "
    +                 //        "EFFECT_CMD_GET_PARAM start");
    +                 p->status = android::Equalizer_getParameter(pContext,
    ++                                                            p->psize,
    +                                                             p->data,
    +                                                             &p->vsize,
    +                                                             p->data + voffset);
    +@@ -3227,6 +3394,7 @@ int Effect_command(effect_handle_t  self,
    +             if(pContext->EffectType == LVM_VOLUME){
    +                 //ALOGV("\tVolume_command cmdCode Case: EFFECT_CMD_GET_PARAM start");
    +                 p->status = android::Volume_getParameter(pContext,
    ++                                                         p->psize,
    +                                                          (void *)p->data,
    +                                                          &p->vsize,
    +                                                          p->data + voffset);
    +@@ -3256,13 +3424,9 @@ int Effect_command(effect_handle_t  self,
    +                             "EFFECT_CMD_SET_PARAM: ERROR");
    +                     return -EINVAL;
    +                 }
    +-                effect_param_t *p = (effect_param_t *) pCmdData;
      
    --        if (!((flags & kHardwareCodecsOnly) && !isSoftwareCodec(componentName))) {
    -+        if ((flags & kHardwareCodecsOnly) && isSoftwareCodec(componentName)) {
    -+            ALOGV("skipping SW codec '%s'", componentName.c_str());
    -+        } else {
    -             matches->push(componentName);
    -             ALOGV("matching '%s'", componentName.c_str());
    -         }
    -diff --git a/media/libstagefright/MediaSource.cpp b/media/libstagefright/MediaSource.cpp
    -index a17757a..f1ad5c5 100644
    ---- a/media/libstagefright/MediaSource.cpp
    -+++ b/media/libstagefright/MediaSource.cpp
    -@@ -22,4 +22,10 @@ MediaSource::MediaSource() {}
    +-                if (p->psize != sizeof(int32_t)){
    +-                    ALOGV("\tLVM_ERROR : BassBoost_command cmdCode Case: "
    +-                            "EFFECT_CMD_SET_PARAM: ERROR, psize is not sizeof(int32_t)");
    +-                    return -EINVAL;
    +-                }
    ++                effect_param_t * const p = (effect_param_t *) pCmdData;
    ++                const uint32_t voffset = computeParamVOffset(p);
      
    - MediaSource::~MediaSource() {}
    +                 //ALOGV("\tnBassBoost_command cmdSize is %d\n"
    +                 //        "\tsizeof(effect_param_t) is  %d\n"
    +@@ -3272,8 +3436,10 @@ int Effect_command(effect_handle_t  self,
    +                 //        cmdSize, sizeof(effect_param_t), p->psize, p->vsize );
      
    -+extern "C" {
    -+bool _ZNK7android11MediaSource11ReadOptions9getSeekToEPxPNS1_8SeekModeE(android::IMediaSource::ReadOptions *readOptions, int64_t *time_us, android::IMediaSource::ReadOptions::SeekMode *mode) {
    -+    bool res = readOptions->getSeekTo(time_us, mode);
    -+    return res;
    -+}
    -+}
    - }  // namespace android
    -diff --git a/media/libstagefright/OggExtractor.cpp b/media/libstagefright/OggExtractor.cpp
    -index ebbe510..752f2fe 100644
    ---- a/media/libstagefright/OggExtractor.cpp
    -+++ b/media/libstagefright/OggExtractor.cpp
    -@@ -578,6 +578,10 @@ status_t MyOpusExtractor::readNextPacket(MediaBuffer **out) {
    +                 *(int *)pReplyData = android::BassBoost_setParameter(pContext,
    +-                                                                    (void *)p->data,
    +-                                                                    p->data + p->psize);
    ++                                                                     p->psize,
    ++                                                                     (void *)p->data,
    ++                                                                     p->vsize,
    ++                                                                     p->data + voffset);
                  }
    -             // First two pages are header pages.
    -             if (err == ERROR_END_OF_STREAM || mCurrentPage.mPageNo > 2) {
    -+                if (mBuf != NULL) {
    -+                    mBuf->release();
    -+                    mBuf = NULL;
    -+                }
    -                 break;
    +             if(pContext->EffectType == LVM_VIRTUALIZER){
    +               // Warning this log will fail to properly read an int32_t value, assumes int16_t
    +@@ -3291,13 +3457,9 @@ int Effect_command(effect_handle_t  self,
    +                             "EFFECT_CMD_SET_PARAM: ERROR");
    +                     return -EINVAL;
    +                 }
    +-                effect_param_t *p = (effect_param_t *) pCmdData;
    + 
    +-                if (p->psize != sizeof(int32_t)){
    +-                    ALOGV("\tLVM_ERROR : Virtualizer_command cmdCode Case: "
    +-                            "EFFECT_CMD_SET_PARAM: ERROR, psize is not sizeof(int32_t)");
    +-                    return -EINVAL;
    +-                }
    ++                effect_param_t * const p = (effect_param_t *) pCmdData;
    ++                const uint32_t voffset = computeParamVOffset(p);
    + 
    +                 //ALOGV("\tnVirtualizer_command cmdSize is %d\n"
    +                 //        "\tsizeof(effect_param_t) is  %d\n"
    +@@ -3307,8 +3469,10 @@ int Effect_command(effect_handle_t  self,
    +                 //        cmdSize, sizeof(effect_param_t), p->psize, p->vsize );
    + 
    +                 *(int *)pReplyData = android::Virtualizer_setParameter(pContext,
    +-                                                                      (void *)p->data,
    +-                                                                       p->data + p->psize);
    ++                                                                       p->psize,
    ++                                                                       (void *)p->data,
    ++                                                                       p->vsize,
    ++                                                                       p->data + voffset);
                  }
    -             curGranulePosition = mCurrentPage.mGranulePosition;
    -diff --git a/media/libstagefright/SampleTable.cpp b/media/libstagefright/SampleTable.cpp
    -index ee5fdf0..597896b 100644
    ---- a/media/libstagefright/SampleTable.cpp
    -+++ b/media/libstagefright/SampleTable.cpp
    -@@ -517,6 +517,8 @@ status_t SampleTable::setSyncSampleParams(off64_t data_offset, size_t data_size)
    -         return ERROR_MALFORMED;
    -     }
    +             if(pContext->EffectType == LVM_EQUALIZER){
    +                //ALOGV("\tEqualizer_command cmdCode Case: "
    +@@ -3324,12 +3488,15 @@ int Effect_command(effect_handle_t  self,
    +                             "EFFECT_CMD_SET_PARAM: ERROR");
    +                     return -EINVAL;
    +                 }
    +-                effect_param_t *p = (effect_param_t *) pCmdData;
    ++
    ++                effect_param_t * const p = (effect_param_t *) pCmdData;
    ++                const uint32_t voffset = computeParamVOffset(p);
      
    -+    mSyncSampleOffset = data_offset;
    +                 *(int *)pReplyData = android::Equalizer_setParameter(pContext,
    +-                                                                    (void *)p->data,
    +-                                                                    p->vsize,
    +-                                                                    p->data + p->psize);
    ++                                                                     p->psize,
    ++                                                                     (void *)p->data,
    ++                                                                     p->vsize,
    ++                                                                     p->data + voffset);
    +             }
    +             if(pContext->EffectType == LVM_VOLUME){
    +                 //ALOGV("\tVolume_command cmdCode Case: EFFECT_CMD_SET_PARAM start");
    +@@ -3346,11 +3513,15 @@ int Effect_command(effect_handle_t  self,
    +                             "EFFECT_CMD_SET_PARAM: ERROR");
    +                     return -EINVAL;
    +                 }
    +-                effect_param_t *p = (effect_param_t *) pCmdData;
     +
    -     uint8_t header[8];
    -     if (mDataSource->readAt(
    -                 data_offset, header, sizeof(header)) < (ssize_t)sizeof(header)) {
    -@@ -561,7 +563,7 @@ status_t SampleTable::setSyncSampleParams(off64_t data_offset, size_t data_size)
    ++                effect_param_t * const p = (effect_param_t *) pCmdData;
    ++                const uint32_t voffset = computeParamVOffset(p);
      
    -     if (mDataSource->readAt(data_offset + 8, mSyncSamples,
    -             (size_t)allocSize) != (ssize_t)allocSize) {
    --        delete mSyncSamples;
    -+        delete[] mSyncSamples;
    -         mSyncSamples = NULL;
    -         return ERROR_IO;
    -     }
    -@@ -987,4 +989,3 @@ int32_t SampleTable::getCompositionTimeOffset(uint32_t sampleIndex) {
    - }
    +                 *(int *)pReplyData = android::Volume_setParameter(pContext,
    +-                                                                 (void *)p->data,
    +-                                                                 p->data + p->psize);
    ++                                                                  p->psize,
    ++                                                                  (void *)p->data,
    ++                                                                  p->vsize,
    ++                                                                  p->data + voffset);
    +             }
    +             //ALOGV("\tEffect_command cmdCode Case: EFFECT_CMD_SET_PARAM end");
    +         } break;
    +@@ -3461,7 +3632,6 @@ int Effect_command(effect_handle_t  self,
    +             int16_t  leftdB, rightdB;
    +             int16_t  maxdB, pandB;
    +             int32_t  vol_ret[2] = {1<<24,1<<24}; // Apply no volume
    +-            int      status = 0;
    +             LVM_ControlParams_t     ActiveParams;           /* Current control Parameters */
    +             LVM_ReturnStatus_en     LvmStatus=LVM_SUCCESS;  /* Function call status */
      
    - }  // namespace android
    --
    -diff --git a/media/libstagefright/StagefrightMetadataRetriever.cpp b/media/libstagefright/StagefrightMetadataRetriever.cpp
    -index be5067d..2fef7ca 100644
    ---- a/media/libstagefright/StagefrightMetadataRetriever.cpp
    -+++ b/media/libstagefright/StagefrightMetadataRetriever.cpp
    -@@ -483,6 +483,10 @@ VideoFrame *StagefrightMetadataRetriever::getFrameAtTime(
    -     for (i = 0; i < n; ++i) {
    -         sp<MetaData> meta = mExtractor->getTrackMetaData(i);
    +diff --git a/media/libeffects/lvm/wrapper/Reverb/EffectReverb.cpp b/media/libeffects/lvm/wrapper/Reverb/EffectReverb.cpp
    +index 4dc8b45..19892dd 100644
    +--- a/media/libeffects/lvm/wrapper/Reverb/EffectReverb.cpp
    ++++ b/media/libeffects/lvm/wrapper/Reverb/EffectReverb.cpp
    +@@ -180,12 +180,13 @@ int  Reverb_init            (ReverbContext *pContext);
    + void Reverb_free            (ReverbContext *pContext);
    + int  Reverb_setConfig       (ReverbContext *pContext, effect_config_t *pConfig);
    + void Reverb_getConfig       (ReverbContext *pContext, effect_config_t *pConfig);
    +-int  Reverb_setParameter    (ReverbContext *pContext, void *pParam, void *pValue);
    ++int  Reverb_setParameter    (ReverbContext *pContext, void *pParam, void *pValue, int vsize);
    + int  Reverb_getParameter    (ReverbContext *pContext,
    +                              void          *pParam,
    +                              uint32_t      *pValueSize,
    +                              void          *pValue);
    + int Reverb_LoadPreset       (ReverbContext   *pContext);
    ++int Reverb_paramValueSize   (int32_t param);
      
    -+        if (meta == NULL) {
    -+            continue;
    -+        }
    -+
    -         const char *mime;
    -         CHECK(meta->findCString(kKeyMIMEType, &mime));
    + /* Effect Library Interface Implementation */
      
    -@@ -652,6 +656,10 @@ void StagefrightMetadataRetriever::parseMetaData() {
    +@@ -1747,12 +1748,13 @@ int Reverb_getParameter(ReverbContext *pContext,
    + //  pContext         - handle to instance data
    + //  pParam           - pointer to parameter
    + //  pValue           - pointer to value
    ++//  vsize            - value size
    + //
    + // Outputs:
    + //
    + //----------------------------------------------------------------------------
      
    -     size_t numTracks = mExtractor->countTracks();
    +-int Reverb_setParameter (ReverbContext *pContext, void *pParam, void *pValue){
    ++int Reverb_setParameter (ReverbContext *pContext, void *pParam, void *pValue, int vsize){
    +     int status = 0;
    +     int16_t level;
    +     int16_t ratio;
    +@@ -1776,6 +1778,11 @@ int Reverb_setParameter (ReverbContext *pContext, void *pParam, void *pValue){
    +         return 0;
    +     }
      
    -+    if (numTracks == 0) {      //If no tracks available, corrupt or not valid stream
    -+        return;
    ++    if (vsize < Reverb_paramValueSize(param)) {
    ++        android_errorWriteLog(0x534e4554, "63526567");
    ++        return -EINVAL;
     +    }
     +
    -     char tmp[32];
    -     sprintf(tmp, "%zu", numTracks);
    +     switch (param){
    +         case REVERB_PARAM_PROPERTIES:
    +             ALOGV("\tReverb_setParameter() REVERB_PARAM_PROPERTIES");
    +@@ -1851,6 +1858,31 @@ int Reverb_setParameter (ReverbContext *pContext, void *pParam, void *pValue){
    +     return status;
    + } /* end Reverb_setParameter */
      
    -@@ -675,6 +683,9 @@ void StagefrightMetadataRetriever::parseMetaData() {
    -     String8 timedTextLang;
    -     for (size_t i = 0; i < numTracks; ++i) {
    -         sp<MetaData> trackMeta = mExtractor->getTrackMetaData(i);
    -+        if (trackMeta == NULL) {
    -+            continue;
    -+        }
    ++
    ++/**
    ++ * returns the size in bytes of the value of each environmental reverb parameter
    ++ */
    ++int Reverb_paramValueSize(int32_t param) {
    ++    switch (param) {
    ++    case REVERB_PARAM_ROOM_LEVEL:
    ++    case REVERB_PARAM_ROOM_HF_LEVEL:
    ++    case REVERB_PARAM_REFLECTIONS_LEVEL:
    ++    case REVERB_PARAM_REVERB_LEVEL:
    ++        return sizeof(int16_t); // millibel
    ++    case REVERB_PARAM_DECAY_TIME:
    ++    case REVERB_PARAM_REFLECTIONS_DELAY:
    ++    case REVERB_PARAM_REVERB_DELAY:
    ++        return sizeof(uint32_t); // milliseconds
    ++    case REVERB_PARAM_DECAY_HF_RATIO:
    ++    case REVERB_PARAM_DIFFUSION:
    ++    case REVERB_PARAM_DENSITY:
    ++        return sizeof(int16_t); // permille
    ++    case REVERB_PARAM_PROPERTIES:
    ++        return sizeof(s_reverb_settings); // struct of all reverb properties
    ++    }
    ++    return sizeof(int32_t);
    ++}
    ++
    + } // namespace
    + } // namespace
      
    -         int64_t durationUs;
    -         if (trackMeta->findInt64(kKeyDuration, &durationUs)) {
    -diff --git a/media/libstagefright/SurfaceMediaSource.cpp b/media/libstagefright/SurfaceMediaSource.cpp
    -index 15ff569..0e9b4e6 100644
    ---- a/media/libstagefright/SurfaceMediaSource.cpp
    -+++ b/media/libstagefright/SurfaceMediaSource.cpp
    -@@ -129,7 +129,11 @@ status_t SurfaceMediaSource::setFrameRate(int32_t fps)
    +@@ -2022,7 +2054,8 @@ int Reverb_command(effect_handle_t  self,
      
    - MetadataBufferType SurfaceMediaSource::metaDataStoredInVideoBuffers() const {
    -     ALOGV("isMetaDataStoredInVideoBuffers");
    -+#ifdef CAMCORDER_GRALLOC_SOURCE
    -+    return kMetadataBufferTypeGrallocSource;
    -+#else
    -     return kMetadataBufferTypeANWBuffer;
    -+#endif
    +             *(int *)pReplyData = android::Reverb_setParameter(pContext,
    +                                                              (void *)p->data,
    +-                                                              p->data + p->psize);
    ++                                                              p->data + p->psize,
    ++                                                              p->vsize);
    +         } break;
    + 
    +         case EFFECT_CMD_ENABLE:
    +diff --git a/media/libmedia/IDataSource.cpp b/media/libmedia/IDataSource.cpp
    +index 51c9938..5ad39fe 100644
    +--- a/media/libmedia/IDataSource.cpp
    ++++ b/media/libmedia/IDataSource.cpp
    +@@ -54,8 +54,16 @@ struct BpDataSource : public BpInterface<IDataSource> {
    +         data.writeInterfaceToken(IDataSource::getInterfaceDescriptor());
    +         data.writeInt64(offset);
    +         data.writeInt64(size);
    +-        remote()->transact(READ_AT, data, &reply);
    +-        return reply.readInt64();
    ++        status_t err = remote()->transact(READ_AT, data, &reply);
    ++        if (err != OK) {
    ++            return err;
    ++        }
    ++        int64_t value = 0;
    ++        err = reply.readInt64(&value);
    ++        if (err != OK) {
    ++            return err;
    ++        }
    ++        return (ssize_t)value;
    +     }
    + 
    +     virtual status_t getSize(off64_t* size) {
    +diff --git a/media/libmediaplayerservice/MediaPlayerService.cpp b/media/libmediaplayerservice/MediaPlayerService.cpp
    +index bd16e91..6e689e6 100644
    +--- a/media/libmediaplayerservice/MediaPlayerService.cpp
    ++++ b/media/libmediaplayerservice/MediaPlayerService.cpp
    +@@ -82,6 +82,9 @@
    + #include "HTTPBase.h"
    + #include "RemoteDisplay.h"
    + 
    ++static const int kDumpLockRetries = 50;
    ++static const int kDumpLockSleepUs = 20000;
    ++
    + namespace {
    + using android::media::Metadata;
    + using android::status_t;
    +@@ -405,12 +408,32 @@ status_t MediaPlayerService::Client::dump(int fd, const Vector<String16>& args)
    +     snprintf(buffer, 255, "  pid(%d), connId(%d), status(%d), looping(%s)\n",
    +             mPid, mConnId, mStatus, mLoop?"true": "false");
    +     result.append(buffer);
    ++
    ++    sp<MediaPlayerBase> p;
    ++    sp<AudioOutput> audioOutput;
    ++    bool locked = false;
    ++    for (int i = 0; i < kDumpLockRetries; ++i) {
    ++        if (mLock.tryLock() == NO_ERROR) {
    ++            locked = true;
    ++            break;
    ++        }
    ++        usleep(kDumpLockSleepUs);
    ++    }
    ++
    ++    if (locked) {
    ++        p = mPlayer;
    ++        audioOutput = mAudioOutput;
    ++        mLock.unlock();
    ++    } else {
    ++        result.append("  lock is taken, no dump from player and audio output\n");
    ++    }
    +     write(fd, result.string(), result.size());
    +-    if (mPlayer != NULL) {
    +-        mPlayer->dump(fd, args);
    ++
    ++    if (p != NULL) {
    ++        p->dump(fd, args);
    +     }
    +-    if (mAudioOutput != 0) {
    +-        mAudioOutput->dump(fd, args);
    ++    if (audioOutput != 0) {
    ++        audioOutput->dump(fd, args);
    +     }
    +     write(fd, "\n", 1);
    +     return NO_ERROR;
    +@@ -590,7 +613,10 @@ MediaPlayerService::Client::Client(
    + MediaPlayerService::Client::~Client()
    + {
    +     ALOGV("Client(%d) destructor pid = %d", mConnId, mPid);
    +-    mAudioOutput.clear();
    ++    {
    ++        Mutex::Autolock l(mLock);
    ++        mAudioOutput.clear();
    ++    }
    +     wp<Client> client(this);
    +     disconnect();
    +     mService->removeClient(client);
    +@@ -609,10 +635,9 @@ void MediaPlayerService::Client::disconnect()
    +         Mutex::Autolock l(mLock);
    +         p = mPlayer;
    +         mClient.clear();
    ++        mPlayer.clear();
    +     }
    + 
    +-    mPlayer.clear();
    +-
    +     // clear the notification to prevent callbacks to dead client
    +     // and reset the player. We assume the player will serialize
    +     // access to itself if necessary.
    +@@ -633,7 +658,7 @@ void MediaPlayerService::Client::disconnect()
    + sp<MediaPlayerBase> MediaPlayerService::Client::createPlayer(player_type playerType)
    + {
    +     // determine if we have the right player type
    +-    sp<MediaPlayerBase> p = mPlayer;
    ++    sp<MediaPlayerBase> p = getPlayer();
    +     if ((p != NULL) && (p->playerType() != playerType)) {
    +         ALOGV("delete player");
    +         p.clear();
    +@@ -721,6 +746,7 @@ void MediaPlayerService::Client::setDataSource_post(
    +     }
    + 
    +     if (mStatus == OK) {
    ++        Mutex::Autolock l(mLock);
    +         mPlayer = p;
    +     }
      }
    +diff --git a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp
    +index dc4e5d4..b64d899 100644
    +--- a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp
    ++++ b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp
    +@@ -1534,6 +1534,7 @@ void NuPlayer::restartAudio(
    +     mRenderer->flush(true /* audio */, false /* notifyComplete */);
    +     if (mVideoDecoder != NULL) {
    +         mRenderer->flush(false /* audio */, false /* notifyComplete */);
    ++        flushDecoder(false /* audio */, false /*needShutdown*/);
    +     }
      
    - int32_t SurfaceMediaSource::getFrameRate( ) const {
    -@@ -250,6 +254,35 @@ sp<MetaData> SurfaceMediaSource::getFormat()
    -     return meta;
    +     performSeek(currentPositionUs);
    +@@ -1545,6 +1546,10 @@ void NuPlayer::restartAudio(
    +     if (needsToCreateAudioDecoder) {
    +         instantiateDecoder(true /* audio */, &mAudioDecoder, !forceNonOffload);
    +     }
    ++    if (mVideoDecoder != NULL) {
    ++        // After a flush without shutdown, decoder is paused.
    ++        mVideoDecoder->signalResume(false /* needNotify */);
    ++    }
      }
      
    + void NuPlayer::determineAudioModeChange(const sp<AMessage> &audioFormat) {
    +diff --git a/media/libstagefright/ACodec.cpp b/media/libstagefright/ACodec.cpp
    +index 37fd5a5..337fb2d 100644
    +--- a/media/libstagefright/ACodec.cpp
    ++++ b/media/libstagefright/ACodec.cpp
    +@@ -804,13 +804,22 @@ status_t ACodec::allocateBuffersOnPort(OMX_U32 portIndex) {
    +             } else if (type == kMetadataBufferTypeNativeHandleSource) {
    +                 bufSize = sizeof(VideoNativeHandleMetadata);
    +             }
     +#ifdef CAMCORDER_GRALLOC_SOURCE
    -+// Pass the data to the MediaBuffer. Pass in only the metadata
    -+// The metadata passed consists of two parts:
    -+// 1. First, there is an integer indicating that it is a GRAlloc
    -+// source (kMetadataBufferTypeGrallocSource)
    -+// 2. This is followed by the buffer_handle_t that is a handle to the
    -+// GRalloc buffer. The encoder needs to interpret this GRalloc handle
    -+// and encode the frames.
    -+// --------------------------------------------------------------
    -+// |  kMetadataBufferTypeGrallocSource | sizeof(buffer_handle_t) |
    -+// --------------------------------------------------------------
    -+// Note: Call only when you have the lock
    -+static void passMetadataBuffer(MediaBuffer **buffer,
    -+        buffer_handle_t bufferHandle) {
    -+    *buffer = new MediaBuffer(4 + sizeof(buffer_handle_t));
    -+    char *data = (char *)(*buffer)->data();
    -+    if (data == NULL) {
    -+        ALOGE("Cannot allocate memory for metadata buffer!");
    -+        return;
    -+    }
    -+    OMX_U32 type = kMetadataBufferTypeGrallocSource;
    -+    memcpy(data, &type, 4);
    -+    memcpy(data + 4, &bufferHandle, sizeof(buffer_handle_t));
    -+
    -+    ALOGV("handle = %p, , offset = %zu, length = %zu",
    -+            bufferHandle, (*buffer)->range_length(), (*buffer)->range_offset());
    -+}
    ++            else if (type == kMetadataBufferTypeGrallocSource) {
    ++                bufSize = sizeof(VideoGrallocMetadata);
    ++            }
     +#endif
    -+
    - // Pass the data to the MediaBuffer. Pass in only the metadata
    - // Note: Call only when you have the lock
    - void SurfaceMediaSource::passMetadataBuffer_l(MediaBuffer **buffer,
    -@@ -352,7 +385,11 @@ status_t SurfaceMediaSource::read(
    -     mNumFramesEncoded++;
    -     // Pass the data to the MediaBuffer. Pass in only the metadata
      
    +             // If using gralloc or native source input metadata buffers, allocate largest
    +             // metadata size as we prefer to generate native source metadata, but component
    +             // may require gralloc source. For camera source, allocate at least enough
    +             // size for native metadata buffers.
    +             size_t allottedSize = bufSize;
     +#ifdef CAMCORDER_GRALLOC_SOURCE
    -+    passMetadataBuffer(buffer, mSlots[mCurrentSlot].mGraphicBuffer->handle);
    ++            if (portIndex == kPortIndexInput && type >= kMetadataBufferTypeGrallocSource) {
     +#else
    -     passMetadataBuffer_l(buffer, mSlots[mCurrentSlot].mGraphicBuffer->getNativeBuffer());
    +             if (portIndex == kPortIndexInput && type == kMetadataBufferTypeANWBuffer) {
    ++#endif
    +                 bufSize = max(sizeof(VideoGrallocMetadata), sizeof(VideoNativeMetadata));
    +             } else if (portIndex == kPortIndexInput && type == kMetadataBufferTypeCameraSource) {
    +                 bufSize = max(bufSize, sizeof(VideoNativeMetadata));
    +@@ -1052,6 +1061,12 @@ status_t ACodec::configureOutputBuffersFromNativeWindow(
    +     // 2. try to allocate two (2) additional buffers to reduce starvation from
    +     //    the consumer
    +     //    plus an extra buffer to account for incorrect minUndequeuedBufs
    ++#ifdef BOARD_CANT_REALLOCATE_OMX_BUFFERS
    ++    // Some devices don't like to set OMX_IndexParamPortDefinition at this
    ++    // point (even with an unmodified def), so skip it if possible.
    ++    // This check was present in KitKat.
    ++    if (def.nBufferCountActual < def.nBufferCountMin + *minUndequeuedBuffers) {
    ++#endif
    +     for (OMX_U32 extraBuffers = 2 + 1; /* condition inside loop */; extraBuffers--) {
    +         OMX_U32 newBufferCount =
    +             def.nBufferCountMin + *minUndequeuedBuffers + extraBuffers;
    +@@ -1071,6 +1086,9 @@ status_t ACodec::configureOutputBuffersFromNativeWindow(
    +             return err;
    +         }
    +     }
    ++#ifdef BOARD_CANT_REALLOCATE_OMX_BUFFERS
    ++    }
     +#endif
      
    -     (*buffer)->setObserver(this);
    -     (*buffer)->add_ref();
    -diff --git a/media/libstagefright/codecs/aacenc/SoftAACEncoder2.cpp b/media/libstagefright/codecs/aacenc/SoftAACEncoder2.cpp
    -index f00a5d1..44415e2 100644
    ---- a/media/libstagefright/codecs/aacenc/SoftAACEncoder2.cpp
    -+++ b/media/libstagefright/codecs/aacenc/SoftAACEncoder2.cpp
    -@@ -16,6 +16,7 @@
    - 
    - //#define LOG_NDEBUG 0
    - #define LOG_TAG "SoftAACEncoder2"
    -+#include <log/log.h>
    - #include <utils/Log.h>
    - 
    - #include "SoftAACEncoder2.h"
    -@@ -61,6 +62,7 @@ SoftAACEncoder2::SoftAACEncoder2(
    -       mSentCodecSpecificData(false),
    -       mInputSize(0),
    -       mInputFrame(NULL),
    -+      mAllocatedFrameSize(0),
    -       mInputTimeUs(-1ll),
    -       mSawInputEOS(false),
    -       mSignalledError(false) {
    -@@ -565,6 +567,15 @@ void SoftAACEncoder2::onQueueFilled(OMX_U32 /* portIndex */) {
    +     err = native_window_set_buffer_count(
    +             mNativeWindow.get(), def.nBufferCountActual);
    +@@ -1766,6 +1784,14 @@ status_t ACodec::configureCodec(
    +             mInputMetadataType = (MetadataBufferType)storeMeta;
    +         }
      
    -             if (mInputFrame == NULL) {
    -                 mInputFrame = new int16_t[numBytesPerInputFrame / sizeof(int16_t)];
    -+                mAllocatedFrameSize = numBytesPerInputFrame;
    -+            } else if (mAllocatedFrameSize != numBytesPerInputFrame) {
    -+                ALOGE("b/34621073: changed size from %d to %d",
    -+                        (int)mAllocatedFrameSize, (int)numBytesPerInputFrame);
    -+                android_errorWriteLog(0x534e4554,"34621073");
    -+                delete mInputFrame;
    -+                mInputFrame = new int16_t[numBytesPerInputFrame / sizeof(int16_t)];
    -+                mAllocatedFrameSize = numBytesPerInputFrame;
    ++#ifdef CAMCORDER_GRALLOC_SOURCE
    ++        // For this specific case we could be using camera source even if storeMetaDataInBuffers
    ++        // returns Gralloc source. Pretend that we are; this will force us to use nBufferSize.
    ++        if (mInputMetadataType == kMetadataBufferTypeGrallocSource) {
    ++            mInputMetadataType = kMetadataBufferTypeCameraSource;
    ++        }
    ++#endif
     +
    -             }
    +         uint32_t usageBits;
    +         if (mOMX->getParameter(
    +                 mNode, (OMX_INDEXTYPE)OMX_IndexParamConsumerUsageBits,
    +@@ -4274,7 +4300,9 @@ status_t ACodec::setupAVCEncoderParameters(const sp<AMessage> &msg) {
      
    -             if (mInputSize == 0) {
    -@@ -715,6 +726,7 @@ void SoftAACEncoder2::onReset() {
    -     delete[] mInputFrame;
    -     mInputFrame = NULL;
    -     mInputSize = 0;
    -+    mAllocatedFrameSize = 0;
    +         h264type.eProfile = static_cast<OMX_VIDEO_AVCPROFILETYPE>(profile);
    +         h264type.eLevel = static_cast<OMX_VIDEO_AVCLEVELTYPE>(level);
    +-    } else {
    ++    }
    ++#ifdef USE_AVC_BASELINE_PROFILE
    ++      else {
    +         h264type.eProfile = OMX_VIDEO_AVCProfileBaseline;
    + #if 0   /* DON'T YET DEFAULT TO HIGHEST PROFILE */
    +         // Use largest supported profile for AVC recording if profile is not specified.
    +@@ -4287,6 +4315,7 @@ status_t ACodec::setupAVCEncoderParameters(const sp<AMessage> &msg) {
    +         }
    + #endif
    +     }
    ++#endif
      
    -     mSentCodecSpecificData = false;
    -     mInputTimeUs = -1ll;
    -diff --git a/media/libstagefright/codecs/aacenc/SoftAACEncoder2.h b/media/libstagefright/codecs/aacenc/SoftAACEncoder2.h
    -index f1b81e1..123fd25 100644
    ---- a/media/libstagefright/codecs/aacenc/SoftAACEncoder2.h
    -+++ b/media/libstagefright/codecs/aacenc/SoftAACEncoder2.h
    -@@ -62,6 +62,7 @@ private:
    -     bool mSentCodecSpecificData;
    -     size_t mInputSize;
    -     int16_t *mInputFrame;
    -+    size_t mAllocatedFrameSize;
    -     int64_t mInputTimeUs;
    +     ALOGI("setupAVCEncoderParameters with [profile: %s] [level: %s]",
    +             asString(h264type.eProfile), asString(h264type.eLevel));
    +@@ -4762,6 +4791,7 @@ bool ACodec::describeDefaultColorFormat(DescribeColorFormat2Params &params) {
    +         fmt != OMX_COLOR_FormatYUV420PackedPlanar &&
    +         fmt != OMX_COLOR_FormatYUV420SemiPlanar &&
    +         fmt != OMX_COLOR_FormatYUV420PackedSemiPlanar &&
    ++        fmt != OMX_TI_COLOR_FormatYUV420PackedSemiPlanar &&
    +         fmt != (OMX_COLOR_FORMATTYPE)HAL_PIXEL_FORMAT_YV12) {
    +         ALOGW("do not know color format 0x%x = %d", fmt, fmt);
    +         return false;
    +@@ -4838,6 +4868,7 @@ bool ACodec::describeDefaultColorFormat(DescribeColorFormat2Params &params) {
    +         case OMX_COLOR_FormatYUV420SemiPlanar:
    +             // FIXME: NV21 for sw-encoder, NV12 for decoder and hw-encoder
    +         case OMX_COLOR_FormatYUV420PackedSemiPlanar:
    ++        case OMX_TI_COLOR_FormatYUV420PackedSemiPlanar:
    +             // NV12
    +             image.mPlane[image.U].mOffset = params.nStride * params.nSliceHeight;
    +             image.mPlane[image.U].mColInc = 2;
    +@@ -6036,6 +6067,9 @@ void ACodec::BaseState::onInputBufferFilled(const sp<AMessage> &msg) {
    +                 status_t err2 = OK;
    +                 switch (metaType) {
    +                 case kMetadataBufferTypeInvalid:
    ++#ifdef CAMCORDER_GRALLOC_SOURCE
    ++                case kMetadataBufferTypeCameraSource:
    ++#endif
    +                     break;
    + #ifndef OMX_ANDROID_COMPILE_AS_32BIT_ON_64BIT_PLATFORMS
    +                 case kMetadataBufferTypeNativeHandleSource:
    +@@ -6267,6 +6301,10 @@ bool ACodec::BaseState::onOMXFillBufferDone(
    +                 native_handle_t *handle = NULL;
    +                 VideoNativeHandleMetadata &nativeMeta =
    +                     *(VideoNativeHandleMetadata *)info->mData->data();
    ++#ifdef CAMCORDER_GRALLOC_SOURCE
    ++                VideoGrallocMetadata &grallocMeta =
    ++                    *(VideoGrallocMetadata *)info->mData->data();
    ++#endif
    +                 if (info->mData->size() >= sizeof(nativeMeta)
    +                         && nativeMeta.eType == kMetadataBufferTypeNativeHandleSource) {
    + #ifdef OMX_ANDROID_COMPILE_AS_32BIT_ON_64BIT_PLATFORMS
    +@@ -6276,6 +6314,12 @@ bool ACodec::BaseState::onOMXFillBufferDone(
    +                     handle = (native_handle_t *)nativeMeta.pHandle;
    + #endif
    +                 }
    ++#ifdef CAMCORDER_GRALLOC_SOURCE
    ++                else if (info->mData->size() >= sizeof(grallocMeta)
    ++                        && grallocMeta.eType == kMetadataBufferTypeGrallocSource) {
    ++                    handle = (native_handle_t *)(uintptr_t)grallocMeta.pHandle;
    ++                }
    ++#endif
    +                 info->mData->meta()->setPointer("handle", handle);
    +                 info->mData->meta()->setInt32("rangeOffset", rangeOffset);
    +                 info->mData->meta()->setInt32("rangeLength", rangeLength);
    +@@ -6968,10 +7012,12 @@ void ACodec::LoadedState::onCreateInputSurface(
    +         err = mCodec->mOMX->createInputSurface(
    +                 mCodec->mNode, kPortIndexInput, dataSpace, &bufferProducer,
    +                 &mCodec->mInputMetadataType);
    ++#ifndef CAMCORDER_GRALLOC_SOURCE
    +         // framework uses ANW buffers internally instead of gralloc handles
    +         if (mCodec->mInputMetadataType == kMetadataBufferTypeGrallocSource) {
    +             mCodec->mInputMetadataType = kMetadataBufferTypeANWBuffer;
    +         }
    ++#endif
    +     }
      
    -     bool mSawInputEOS;
    -diff --git a/media/libstagefright/codecs/mpeg2dec/SoftMPEG2.cpp b/media/libstagefright/codecs/mpeg2dec/SoftMPEG2.cpp
    -index 5ed037a..7297f40 100644
    ---- a/media/libstagefright/codecs/mpeg2dec/SoftMPEG2.cpp
    -+++ b/media/libstagefright/codecs/mpeg2dec/SoftMPEG2.cpp
    -@@ -68,6 +68,7 @@ SoftMPEG2::SoftMPEG2(
    -             kProfileLevels, ARRAY_SIZE(kProfileLevels),
    -             320 /* width */, 240 /* height */, callbacks,
    -             appData, component),
    -+      mCodecCtx(NULL),
    -       mMemRecords(NULL),
    -       mFlushOutBuffer(NULL),
    -       mOmxColorFormat(OMX_COLOR_FormatYUV420Planar),
    -@@ -75,25 +76,29 @@ SoftMPEG2::SoftMPEG2(
    -       mNewWidth(mWidth),
    -       mNewHeight(mHeight),
    -       mChangingResolution(false),
    -+      mSignalledError(false),
    -       mStride(mWidth) {
    -     initPorts(kNumBuffers, INPUT_BUF_SIZE, kNumBuffers, CODEC_MIME_TYPE);
    +     if (err == OK) {
    +@@ -7014,10 +7060,12 @@ void ACodec::LoadedState::onSetInputSurface(
    +         err = mCodec->mOMX->setInputSurface(
    +                 mCodec->mNode, kPortIndexInput, surface->getBufferConsumer(),
    +                 &mCodec->mInputMetadataType);
    ++#ifndef CAMCORDER_GRALLOC_SOURCE
    +         // framework uses ANW buffers internally instead of gralloc handles
    +         if (mCodec->mInputMetadataType == kMetadataBufferTypeGrallocSource) {
    +             mCodec->mInputMetadataType = kMetadataBufferTypeANWBuffer;
    +         }
    ++#endif
    +     }
      
    -     // If input dump is enabled, then open create an empty file
    -     GENERATE_FILE_NAMES();
    -     CREATE_DUMP_FILE(mInFile);
    --
    --    CHECK_EQ(initDecoder(), (status_t)OK);
    - }
    +     if (err == OK) {
    +diff --git a/media/libstagefright/Android.mk b/media/libstagefright/Android.mk
    +index 3848502..07f926c 100644
    +--- a/media/libstagefright/Android.mk
    ++++ b/media/libstagefright/Android.mk
    +@@ -102,6 +102,10 @@ LOCAL_SHARED_LIBRARIES := \
    +         libz \
    +         libpowermanager
      
    - SoftMPEG2::~SoftMPEG2() {
    --    CHECK_EQ(deInitDecoder(), (status_t)OK);
    -+    if (OK != deInitDecoder()) {
    -+        ALOGE("Failed to deinit decoder");
    -+        notify(OMX_EventError, OMX_ErrorUnsupportedSetting, 0, NULL);
    -+        mSignalledError = true;
    -+        return;
    -+    }
    - }
    ++ifeq ($(TARGET_USE_AVC_BASELINE_PROFILE), true)
    ++LOCAL_CFLAGS += -DUSE_AVC_BASELINE_PROFILE
    ++endif
    ++
    + LOCAL_STATIC_LIBRARIES := \
    +         libstagefright_color_conversion \
    +         libyuv_static \
    +@@ -124,6 +128,10 @@ LOCAL_SHARED_LIBRARIES += \
    +         libdl \
    +         libRScpp \
      
    ++ifeq ($(TARGET_HAS_LEGACY_CAMERA_HAL1),true)
    ++LOCAL_CFLAGS += -DCAMCORDER_GRALLOC_SOURCE
    ++endif
    ++
    + LOCAL_CFLAGS += -Wno-multichar -Werror -Wno-error=deprecated-declarations -Wall
      
    --static size_t getMinTimestampIdx(OMX_S64 *pNTimeStamp, bool *pIsTimeStampValid) {
    -+static ssize_t getMinTimestampIdx(OMX_S64 *pNTimeStamp, bool *pIsTimeStampValid) {
    -     OMX_S64 minTimeStamp = LLONG_MAX;
    --    int idx = -1;
    --    for (size_t i = 0; i < MAX_TIME_STAMPS; i++) {
    -+    ssize_t idx = -1;
    -+    for (ssize_t i = 0; i < MAX_TIME_STAMPS; i++) {
    -         if (pIsTimeStampValid[i]) {
    -             if (pNTimeStamp[i] < minTimeStamp) {
    -                 minTimeStamp = pNTimeStamp[i];
    -@@ -204,6 +209,7 @@ status_t SoftMPEG2::resetDecoder() {
    -     setNumCores();
    + # enable experiments only in userdebug and eng builds
    +@@ -131,6 +139,10 @@ ifneq (,$(filter userdebug eng,$(TARGET_BUILD_VARIANT)))
    + LOCAL_CFLAGS += -DENABLE_STAGEFRIGHT_EXPERIMENTS
    + endif
      
    -     mStride = 0;
    -+    mSignalledError = false;
    ++ifeq ($(TARGET_BOARD_PLATFORM),omap4)
    ++LOCAL_CFLAGS += -DBOARD_CANT_REALLOCATE_OMX_BUFFERS
    ++endif
    ++
    + LOCAL_CLANG := true
    + LOCAL_SANITIZE := unsigned-integer-overflow signed-integer-overflow
      
    -     return OK;
    - }
    -@@ -433,6 +439,7 @@ status_t SoftMPEG2::deInitDecoder() {
    +diff --git a/media/libstagefright/CameraSource.cpp b/media/libstagefright/CameraSource.cpp
    +index 893da89..2152454 100644
    +--- a/media/libstagefright/CameraSource.cpp
    ++++ b/media/libstagefright/CameraSource.cpp
    +@@ -950,6 +950,14 @@ void CameraSource::releaseRecordingFrame(const sp<IMemory>& frame) {
      
    -     mInitNeeded = true;
    -     mChangingResolution = false;
    -+    mCodecCtx = NULL;
    +         if (handle != nullptr) {
    +             // Frame contains a VideoNativeHandleMetadata. Send the handle back to camera.
    ++            ssize_t offset;
    ++            size_t size;
    ++            sp<IMemoryHeap> heap = frame->getMemory(&offset, &size);
    ++            if (heap->getHeapID() != mMemoryHeapBase->getHeapID()) {
    ++                ALOGE("%s: Mismatched heap ID, ignoring release (got %x, expected %x)",
    ++		     __FUNCTION__, heap->getHeapID(), mMemoryHeapBase->getHeapID());
    ++                return;
    ++            }
    +             releaseRecordingFrameHandle(handle);
    +             mMemoryBases.push_back(frame);
    +             mMemoryBaseAvailableCond.signal();
    +@@ -1117,7 +1125,7 @@ void CameraSource::releaseRecordingFrameHandle(native_handle_t* handle) {
    +         int64_t token = IPCThreadState::self()->clearCallingIdentity();
    +         mCamera->releaseRecordingFrameHandle(handle);
    +         IPCThreadState::self()->restoreCallingIdentity(token);
    +-    } else {
    ++    } else if (handle != nullptr) {
    +         native_handle_close(handle);
    +         native_handle_delete(handle);
    +     }
    +@@ -1250,6 +1258,10 @@ void CameraSource::processBufferQueueFrame(BufferItem& buffer) {
    + MetadataBufferType CameraSource::metaDataStoredInVideoBuffers() const {
    +     ALOGV("metaDataStoredInVideoBuffers");
      
    -     return OK;
    - }
    -@@ -444,10 +451,11 @@ status_t SoftMPEG2::reInitDecoder() {
    ++#ifdef CAMCORDER_GRALLOC_SOURCE
    ++    return kMetadataBufferTypeGrallocSource;
    ++#endif
    ++
    +     // Output buffers will contain metadata if camera sends us buffer in metadata mode or via
    +     // buffer queue.
    +     switch (mVideoBufferMode) {
    +diff --git a/media/libstagefright/MPEG4Extractor.cpp b/media/libstagefright/MPEG4Extractor.cpp
    +index 5441714..4a33e7a 100644
    +--- a/media/libstagefright/MPEG4Extractor.cpp
    ++++ b/media/libstagefright/MPEG4Extractor.cpp
    +@@ -72,6 +72,7 @@ public:
    +                 Vector<SidxEntry> &sidx,
    +                 const Trex *trex,
    +                 off64_t firstMoofOffset);
    ++    virtual status_t init();
      
    -     ret = initDecoder();
    -     if (OK != ret) {
    --        ALOGE("Create failure");
    -+        ALOGE("Failed to initialize decoder");
    -         deInitDecoder();
    --        return NO_MEMORY;
    -+        return ret;
    -     }
    -+    mSignalledError = false;
    -     return OK;
    - }
    +     virtual status_t start(MetaData *params = NULL);
    +     virtual status_t stop();
    +@@ -935,6 +936,12 @@ status_t MPEG4Extractor::parseChunk(off64_t *offset, int depth) {
    +                 ALOGE("moov: depth %d", depth);
    +                 return ERROR_MALFORMED;
    +             }
    ++
    ++            if (chunk_type == FOURCC('m', 'o', 'o', 'v') && mInitCheck == OK) {
    ++                ALOGE("duplicate moov");
    ++                return ERROR_MALFORMED;
    ++            }
    ++
    +             if (chunk_type == FOURCC('m', 'o', 'o', 'f') && !mMoofFound) {
    +                 // store the offset of the first segment
    +                 mMoofFound = true;
    +@@ -1008,6 +1015,12 @@ status_t MPEG4Extractor::parseChunk(off64_t *offset, int depth) {
    +                 if (!mLastTrack->meta->findInt32(kKeyTrackID, &trackId)) {
    +                     mLastTrack->skipTrack = true;
    +                 }
    ++
    ++                status_t err = verifyTrack(mLastTrack);
    ++                if (err != OK) {
    ++                    mLastTrack->skipTrack = true;
    ++                }
    ++
    +                 if (mLastTrack->skipTrack) {
    +                     Track *cur = mFirstTrack;
      
    -@@ -586,10 +594,22 @@ void SoftMPEG2::onPortFlushCompleted(OMX_U32 portIndex) {
    - void SoftMPEG2::onQueueFilled(OMX_U32 portIndex) {
    -     UNUSED(portIndex);
    +@@ -1025,12 +1038,6 @@ status_t MPEG4Extractor::parseChunk(off64_t *offset, int depth) {
      
    -+    if (mSignalledError) {
    -+        return;
    -+    }
    -     if (mOutputPortSettingsChange != NONE) {
    -         return;
    +                     return OK;
    +                 }
    +-
    +-                status_t err = verifyTrack(mLastTrack);
    +-
    +-                if (err != OK) {
    +-                    return err;
    +-                }
    +             } else if (chunk_type == FOURCC('m', 'o', 'o', 'v')) {
    +                 mInitCheck = OK;
    + 
    +@@ -2148,7 +2155,10 @@ status_t MPEG4Extractor::parseChunk(off64_t *offset, int depth) {
    +             *offset += chunk_size;
    + 
    +             if (underQTMetaPath(mPath, 3)) {
    +-                parseQTMetaKey(data_offset, chunk_data_size);
    ++                status_t err = parseQTMetaKey(data_offset, chunk_data_size);
    ++                if (err != OK) {
    ++                    return err;
    ++                }
    +             }
    +             break;
    +         }
    +@@ -2307,7 +2317,10 @@ status_t MPEG4Extractor::parseChunk(off64_t *offset, int depth) {
    + 
    +         case FOURCC('s', 'i', 'd', 'x'):
    +         {
    +-            parseSegmentIndex(data_offset, chunk_data_size);
    ++            status_t err = parseSegmentIndex(data_offset, chunk_data_size);
    ++            if (err != OK) {
    ++                return err;
    ++            }
    +             *offset += chunk_size;
    +             return UNKNOWN_ERROR; // stop parsing after sidx
    +         }
    +@@ -2349,7 +2362,10 @@ status_t MPEG4Extractor::parseChunk(off64_t *offset, int depth) {
    +             // check if we're parsing 'ilst' for meta keys
    +             // if so, treat type as a number (key-id).
    +             if (underQTMetaPath(mPath, 3)) {
    +-                parseQTMetaVal(chunk_type, data_offset, chunk_data_size);
    ++                status_t err = parseQTMetaVal(chunk_type, data_offset, chunk_data_size);
    ++                if (err != OK) {
    ++                    return err;
    ++                }
    +             }
    + 
    +             *offset += chunk_size;
    +@@ -2984,6 +3000,13 @@ status_t MPEG4Extractor::parse3GPPMetaData(off64_t offset, size_t size, int dept
    +         }
    +         case FOURCC('y', 'r', 'r', 'c'):
    +         {
    ++            if (size < 6) {
    ++                delete[] buffer;
    ++                buffer = NULL;
    ++                ALOGE("b/62133227");
    ++                android_errorWriteLog(0x534e4554, "62133227");
    ++                return ERROR_MALFORMED;
    ++            }
    +             char tmp[5];
    +             uint16_t year = U16_AT(&buffer[4]);
    + 
    +@@ -3006,6 +3029,8 @@ status_t MPEG4Extractor::parse3GPPMetaData(off64_t offset, size_t size, int dept
    + 
    +         // smallest possible valid UTF-16 string w BOM: 0xfe 0xff 0x00 0x00
    +         if (size < 6) {
    ++            delete[] buffer;
    ++            buffer = NULL;
    +             return ERROR_MALFORMED;
    +         }
    + 
    +@@ -3174,9 +3199,13 @@ sp<IMediaSource> MPEG4Extractor::getTrack(size_t index) {
    +         }
          }
      
    -+    if (NULL == mCodecCtx) {
    -+        if (OK != initDecoder()) {
    -+            ALOGE("Failed to initialize decoder");
    -+            notify(OMX_EventError, OMX_ErrorUnsupportedSetting, 0, NULL);
    -+            mSignalledError = true;
    -+            return;
    +-    return new MPEG4Source(this,
    ++    sp<MPEG4Source> source =  new MPEG4Source(this,
    +             track->meta, mDataSource, track->timescale, track->sampleTable,
    +             mSidxEntries, trex, mMoofOffset);
    ++    if (source->init() != OK) {
    ++        return NULL;
    ++    }
    ++    return source;
    + }
    + 
    + // static
    +@@ -3573,6 +3602,7 @@ MPEG4Source::MPEG4Source(
    +       mTrex(trex),
    +       mFirstMoofOffset(firstMoofOffset),
    +       mCurrentMoofOffset(firstMoofOffset),
    ++      mNextMoofOffset(-1),
    +       mCurrentTime(0),
    +       mCurrentSampleInfoAllocSize(0),
    +       mCurrentSampleInfoSizes(NULL),
    +@@ -3637,10 +3667,14 @@ MPEG4Source::MPEG4Source(
    + 
    +     CHECK(format->findInt32(kKeyTrackID, &mTrackId));
    + 
    ++}
    ++
    ++status_t MPEG4Source::init() {
    +     if (mFirstMoofOffset != 0) {
    +         off64_t offset = mFirstMoofOffset;
    +-        parseChunk(&offset);
    ++        return parseChunk(&offset);
    +     }
    ++    return OK;
    + }
    + 
    + MPEG4Source::~MPEG4Source() {
    +@@ -3767,13 +3801,35 @@ status_t MPEG4Source::parseChunk(off64_t *offset) {
    + 
    +                 while (true) {
    +                     if (mDataSource->readAt(*offset, hdr, 8) < 8) {
    +-                        return ERROR_END_OF_STREAM;
    ++                        // no more box to the end of file.
    ++                        break;
    +                     }
    +                     chunk_size = ntohl(hdr[0]);
    +                     chunk_type = ntohl(hdr[1]);
    ++                    if (chunk_size == 1) {
    ++                        // ISO/IEC 14496-12:2012, 8.8.4 Movie Fragment Box, moof is a Box
    ++                        // which is defined in 4.2 Object Structure.
    ++                        // When chunk_size==1, 8 bytes follows as "largesize".
    ++                        if (mDataSource->readAt(*offset + 8, &chunk_size, 8) < 8) {
    ++                            return ERROR_IO;
    ++                        }
    ++                        chunk_size = ntoh64(chunk_size);
    ++                        if (chunk_size < 16) {
    ++                            // The smallest valid chunk is 16 bytes long in this case.
    ++                            return ERROR_MALFORMED;
    ++                        }
    ++                    } else if (chunk_size == 0) {
    ++                        // next box extends to end of file.
    ++                    } else if (chunk_size < 8) {
    ++                        // The smallest valid chunk is 8 bytes long in this case.
    ++                        return ERROR_MALFORMED;
    ++                    }
    ++
    +                     if (chunk_type == FOURCC('m', 'o', 'o', 'f')) {
    +                         mNextMoofOffset = *offset;
    +                         break;
    ++                    } else if (chunk_size == 0) {
    ++                        break;
    +                     }
    +                     *offset += chunk_size;
    +                 }
    +@@ -4651,17 +4707,25 @@ status_t MPEG4Source::fragmentedRead(
    +                 totalOffset += se->mSize;
    +             }
    +             mCurrentMoofOffset = totalOffset;
    ++            mNextMoofOffset = -1;
    +             mCurrentSamples.clear();
    +             mCurrentSampleIndex = 0;
    +-            parseChunk(&totalOffset);
    ++            status_t err = parseChunk(&totalOffset);
    ++            if (err != OK) {
    ++                return err;
    ++            }
    +             mCurrentTime = totalTime * mTimescale / 1000000ll;
    +         } else {
    +             // without sidx boxes, we can only seek to 0
    +             mCurrentMoofOffset = mFirstMoofOffset;
    ++            mNextMoofOffset = -1;
    +             mCurrentSamples.clear();
    +             mCurrentSampleIndex = 0;
    +             off64_t tmp = mCurrentMoofOffset;
    +-            parseChunk(&tmp);
    ++            status_t err = parseChunk(&tmp);
    ++            if (err != OK) {
    ++                return err;
    ++            }
    +             mCurrentTime = 0;
    +         }
    + 
    +@@ -4690,7 +4754,10 @@ status_t MPEG4Source::fragmentedRead(
    +             mCurrentMoofOffset = nextMoof;
    +             mCurrentSamples.clear();
    +             mCurrentSampleIndex = 0;
    +-            parseChunk(&nextMoof);
    ++            status_t err = parseChunk(&nextMoof);
    ++            if (err != OK) {
    ++                return err;
    ++            }
    +             if (mCurrentSampleIndex >= mCurrentSamples.size()) {
    +                 return ERROR_END_OF_STREAM;
    +             }
    +diff --git a/media/libstagefright/MediaCodecList.cpp b/media/libstagefright/MediaCodecList.cpp
    +index 0fb5072..a25c47d 100644
    +--- a/media/libstagefright/MediaCodecList.cpp
    ++++ b/media/libstagefright/MediaCodecList.cpp
    +@@ -1165,7 +1165,9 @@ void MediaCodecList::findMatchingCodecs(
    +         CHECK(info != NULL);
    +         AString componentName = info->getCodecName();
    + 
    +-        if (!((flags & kHardwareCodecsOnly) && !isSoftwareCodec(componentName))) {
    ++        if ((flags & kHardwareCodecsOnly) && isSoftwareCodec(componentName)) {
    ++            ALOGV("skipping SW codec '%s'", componentName.c_str());
    ++        } else {
    +             matches->push(componentName);
    +             ALOGV("matching '%s'", componentName.c_str());
    +         }
    +diff --git a/media/libstagefright/MediaSource.cpp b/media/libstagefright/MediaSource.cpp
    +index a17757a..f1ad5c5 100644
    +--- a/media/libstagefright/MediaSource.cpp
    ++++ b/media/libstagefright/MediaSource.cpp
    +@@ -22,4 +22,10 @@ MediaSource::MediaSource() {}
    + 
    + MediaSource::~MediaSource() {}
    + 
    ++extern "C" {
    ++bool _ZNK7android11MediaSource11ReadOptions9getSeekToEPxPNS1_8SeekModeE(android::IMediaSource::ReadOptions *readOptions, int64_t *time_us, android::IMediaSource::ReadOptions::SeekMode *mode) {
    ++    bool res = readOptions->getSeekTo(time_us, mode);
    ++    return res;
    ++}
    ++}
    + }  // namespace android
    +diff --git a/media/libstagefright/OggExtractor.cpp b/media/libstagefright/OggExtractor.cpp
    +index ebbe510..752f2fe 100644
    +--- a/media/libstagefright/OggExtractor.cpp
    ++++ b/media/libstagefright/OggExtractor.cpp
    +@@ -578,6 +578,10 @@ status_t MyOpusExtractor::readNextPacket(MediaBuffer **out) {
    +             }
    +             // First two pages are header pages.
    +             if (err == ERROR_END_OF_STREAM || mCurrentPage.mPageNo > 2) {
    ++                if (mBuf != NULL) {
    ++                    mBuf->release();
    ++                    mBuf = NULL;
    ++                }
    +                 break;
    +             }
    +             curGranulePosition = mCurrentPage.mGranulePosition;
    +diff --git a/media/libstagefright/SampleTable.cpp b/media/libstagefright/SampleTable.cpp
    +index ee5fdf0..597896b 100644
    +--- a/media/libstagefright/SampleTable.cpp
    ++++ b/media/libstagefright/SampleTable.cpp
    +@@ -517,6 +517,8 @@ status_t SampleTable::setSyncSampleParams(off64_t data_offset, size_t data_size)
    +         return ERROR_MALFORMED;
    +     }
    + 
    ++    mSyncSampleOffset = data_offset;
    ++
    +     uint8_t header[8];
    +     if (mDataSource->readAt(
    +                 data_offset, header, sizeof(header)) < (ssize_t)sizeof(header)) {
    +@@ -561,7 +563,7 @@ status_t SampleTable::setSyncSampleParams(off64_t data_offset, size_t data_size)
    + 
    +     if (mDataSource->readAt(data_offset + 8, mSyncSamples,
    +             (size_t)allocSize) != (ssize_t)allocSize) {
    +-        delete mSyncSamples;
    ++        delete[] mSyncSamples;
    +         mSyncSamples = NULL;
    +         return ERROR_IO;
    +     }
    +@@ -987,4 +989,3 @@ int32_t SampleTable::getCompositionTimeOffset(uint32_t sampleIndex) {
    + }
    + 
    + }  // namespace android
    +-
    +diff --git a/media/libstagefright/StagefrightMetadataRetriever.cpp b/media/libstagefright/StagefrightMetadataRetriever.cpp
    +index be5067d..2fef7ca 100644
    +--- a/media/libstagefright/StagefrightMetadataRetriever.cpp
    ++++ b/media/libstagefright/StagefrightMetadataRetriever.cpp
    +@@ -483,6 +483,10 @@ VideoFrame *StagefrightMetadataRetriever::getFrameAtTime(
    +     for (i = 0; i < n; ++i) {
    +         sp<MetaData> meta = mExtractor->getTrackMetaData(i);
    + 
    ++        if (meta == NULL) {
    ++            continue;
    ++        }
    ++
    +         const char *mime;
    +         CHECK(meta->findCString(kKeyMIMEType, &mime));
    + 
    +@@ -652,6 +656,10 @@ void StagefrightMetadataRetriever::parseMetaData() {
    + 
    +     size_t numTracks = mExtractor->countTracks();
    + 
    ++    if (numTracks == 0) {      //If no tracks available, corrupt or not valid stream
    ++        return;
    ++    }
    ++
    +     char tmp[32];
    +     sprintf(tmp, "%zu", numTracks);
    + 
    +@@ -675,6 +683,9 @@ void StagefrightMetadataRetriever::parseMetaData() {
    +     String8 timedTextLang;
    +     for (size_t i = 0; i < numTracks; ++i) {
    +         sp<MetaData> trackMeta = mExtractor->getTrackMetaData(i);
    ++        if (trackMeta == NULL) {
    ++            continue;
    ++        }
    + 
    +         int64_t durationUs;
    +         if (trackMeta->findInt64(kKeyDuration, &durationUs)) {
    +diff --git a/media/libstagefright/SurfaceMediaSource.cpp b/media/libstagefright/SurfaceMediaSource.cpp
    +index 15ff569..547267c 100644
    +--- a/media/libstagefright/SurfaceMediaSource.cpp
    ++++ b/media/libstagefright/SurfaceMediaSource.cpp
    +@@ -129,7 +129,11 @@ status_t SurfaceMediaSource::setFrameRate(int32_t fps)
    + 
    + MetadataBufferType SurfaceMediaSource::metaDataStoredInVideoBuffers() const {
    +     ALOGV("isMetaDataStoredInVideoBuffers");
    ++#ifdef CAMCORDER_GRALLOC_SOURCE
    ++    return kMetadataBufferTypeGrallocSource;
    ++#else
    +     return kMetadataBufferTypeANWBuffer;
    ++#endif
    + }
    + 
    + int32_t SurfaceMediaSource::getFrameRate( ) const {
    +@@ -250,6 +254,35 @@ sp<MetaData> SurfaceMediaSource::getFormat()
    +     return meta;
    + }
    + 
    ++#ifdef CAMCORDER_GRALLOC_SOURCE
    ++// Pass the data to the MediaBuffer. Pass in only the metadata
    ++// The metadata passed consists of two parts:
    ++// 1. First, there is an integer indicating that it is a GRAlloc
    ++// source (kMetadataBufferTypeGrallocSource)
    ++// 2. This is followed by the buffer_handle_t that is a handle to the
    ++// GRalloc buffer. The encoder needs to interpret this GRalloc handle
    ++// and encode the frames.
    ++// --------------------------------------------------------------
    ++// |  kMetadataBufferTypeGrallocSource | sizeof(buffer_handle_t) |
    ++// --------------------------------------------------------------
    ++// Note: Call only when you have the lock
    ++static void passMetadataBuffer(MediaBuffer **buffer,
    ++        buffer_handle_t bufferHandle) {
    ++    *buffer = new MediaBuffer(4 + sizeof(buffer_handle_t));
    ++    char *data = (char *)(*buffer)->data();
    ++    if (data == NULL) {
    ++        ALOGE("Cannot allocate memory for metadata buffer!");
    ++        return;
    ++    }
    ++    OMX_U32 type = kMetadataBufferTypeGrallocSource;
    ++    memcpy(data, &type, 4);
    ++    memcpy(data + 4, &bufferHandle, sizeof(buffer_handle_t));
    ++
    ++    ALOGV("handle = %p, , offset = %zu, length = %zu",
    ++            bufferHandle, (*buffer)->range_length(), (*buffer)->range_offset());
    ++}
    ++#endif
    ++
    + // Pass the data to the MediaBuffer. Pass in only the metadata
    + // Note: Call only when you have the lock
    + void SurfaceMediaSource::passMetadataBuffer_l(MediaBuffer **buffer,
    +@@ -352,7 +385,11 @@ status_t SurfaceMediaSource::read(
    +     mNumFramesEncoded++;
    +     // Pass the data to the MediaBuffer. Pass in only the metadata
    + 
    ++#ifdef CAMCORDER_GRALLOC_SOURCE
    ++    passMetadataBuffer(buffer, mSlots[mCurrentSlot].mGraphicBuffer->handle);
    ++#else
    +     passMetadataBuffer_l(buffer, mSlots[mCurrentSlot].mGraphicBuffer->getNativeBuffer());
    ++#endif
    + 
    +     (*buffer)->setObserver(this);
    +     (*buffer)->add_ref();
    +@@ -388,9 +425,12 @@ void SurfaceMediaSource::signalBufferReturned(MediaBuffer *buffer) {
    +     Mutex::Autolock lock(mMutex);
    + 
    +     buffer_handle_t bufferHandle = getMediaBufferHandle(buffer);
    ++    ANativeWindowBuffer* curNativeHandle = NULL;
    + 
    +     for (size_t i = 0; i < mCurrentBuffers.size(); i++) {
    +-        if (mCurrentBuffers[i]->handle == bufferHandle) {
    ++        curNativeHandle = mCurrentBuffers[i]->getNativeBuffer();
    ++        if ((mCurrentBuffers[i]->handle == bufferHandle) ||
    ++            ((buffer_handle_t)curNativeHandle == bufferHandle)) {
    +             mCurrentBuffers.removeAt(i);
    +             foundBuffer = true;
    +             break;
    +@@ -406,7 +446,10 @@ void SurfaceMediaSource::signalBufferReturned(MediaBuffer *buffer) {
    +             continue;
    +         }
    + 
    +-        if (bufferHandle == mSlots[id].mGraphicBuffer->handle) {
    ++        curNativeHandle = mSlots[id].mGraphicBuffer->getNativeBuffer();
    ++
    ++        if ((bufferHandle == mSlots[id].mGraphicBuffer->handle) ||
    ++            (bufferHandle == (buffer_handle_t)curNativeHandle)) {
    +             ALOGV("Slot %d returned, matches handle = %p", id,
    +                     mSlots[id].mGraphicBuffer->handle);
    + 
    +diff --git a/media/libstagefright/avc_utils.cpp b/media/libstagefright/avc_utils.cpp
    +index 763381e..e5819ed 100644
    +--- a/media/libstagefright/avc_utils.cpp
    ++++ b/media/libstagefright/avc_utils.cpp
    +@@ -479,7 +479,10 @@ bool IsAVCReferenceFrame(const sp<ABuffer> &accessUnit) {
    +     const uint8_t *nalStart;
    +     size_t nalSize;
    +     while (getNextNALUnit(&data, &size, &nalStart, &nalSize, true) == OK) {
    +-        CHECK_GT(nalSize, 0u);
    ++        if (nalSize == 0u) {
    ++            ALOGW("skipping empty nal unit from potentially malformed bitstream");
    ++            continue;
    ++        }
    + 
    +         unsigned nalType = nalStart[0] & 0x1f;
    + 
    +diff --git a/media/libstagefright/codecs/aacenc/SoftAACEncoder2.cpp b/media/libstagefright/codecs/aacenc/SoftAACEncoder2.cpp
    +index f00a5d1..44415e2 100644
    +--- a/media/libstagefright/codecs/aacenc/SoftAACEncoder2.cpp
    ++++ b/media/libstagefright/codecs/aacenc/SoftAACEncoder2.cpp
    +@@ -16,6 +16,7 @@
    + 
    + //#define LOG_NDEBUG 0
    + #define LOG_TAG "SoftAACEncoder2"
    ++#include <log/log.h>
    + #include <utils/Log.h>
    + 
    + #include "SoftAACEncoder2.h"
    +@@ -61,6 +62,7 @@ SoftAACEncoder2::SoftAACEncoder2(
    +       mSentCodecSpecificData(false),
    +       mInputSize(0),
    +       mInputFrame(NULL),
    ++      mAllocatedFrameSize(0),
    +       mInputTimeUs(-1ll),
    +       mSawInputEOS(false),
    +       mSignalledError(false) {
    +@@ -565,6 +567,15 @@ void SoftAACEncoder2::onQueueFilled(OMX_U32 /* portIndex */) {
    + 
    +             if (mInputFrame == NULL) {
    +                 mInputFrame = new int16_t[numBytesPerInputFrame / sizeof(int16_t)];
    ++                mAllocatedFrameSize = numBytesPerInputFrame;
    ++            } else if (mAllocatedFrameSize != numBytesPerInputFrame) {
    ++                ALOGE("b/34621073: changed size from %d to %d",
    ++                        (int)mAllocatedFrameSize, (int)numBytesPerInputFrame);
    ++                android_errorWriteLog(0x534e4554,"34621073");
    ++                delete mInputFrame;
    ++                mInputFrame = new int16_t[numBytesPerInputFrame / sizeof(int16_t)];
    ++                mAllocatedFrameSize = numBytesPerInputFrame;
    ++
    +             }
    + 
    +             if (mInputSize == 0) {
    +@@ -715,6 +726,7 @@ void SoftAACEncoder2::onReset() {
    +     delete[] mInputFrame;
    +     mInputFrame = NULL;
    +     mInputSize = 0;
    ++    mAllocatedFrameSize = 0;
    + 
    +     mSentCodecSpecificData = false;
    +     mInputTimeUs = -1ll;
    +diff --git a/media/libstagefright/codecs/aacenc/SoftAACEncoder2.h b/media/libstagefright/codecs/aacenc/SoftAACEncoder2.h
    +index f1b81e1..123fd25 100644
    +--- a/media/libstagefright/codecs/aacenc/SoftAACEncoder2.h
    ++++ b/media/libstagefright/codecs/aacenc/SoftAACEncoder2.h
    +@@ -62,6 +62,7 @@ private:
    +     bool mSentCodecSpecificData;
    +     size_t mInputSize;
    +     int16_t *mInputFrame;
    ++    size_t mAllocatedFrameSize;
    +     int64_t mInputTimeUs;
    + 
    +     bool mSawInputEOS;
    +diff --git a/media/libstagefright/codecs/mpeg2dec/SoftMPEG2.cpp b/media/libstagefright/codecs/mpeg2dec/SoftMPEG2.cpp
    +index 5ed037a..7297f40 100644
    +--- a/media/libstagefright/codecs/mpeg2dec/SoftMPEG2.cpp
    ++++ b/media/libstagefright/codecs/mpeg2dec/SoftMPEG2.cpp
    +@@ -68,6 +68,7 @@ SoftMPEG2::SoftMPEG2(
    +             kProfileLevels, ARRAY_SIZE(kProfileLevels),
    +             320 /* width */, 240 /* height */, callbacks,
    +             appData, component),
    ++      mCodecCtx(NULL),
    +       mMemRecords(NULL),
    +       mFlushOutBuffer(NULL),
    +       mOmxColorFormat(OMX_COLOR_FormatYUV420Planar),
    +@@ -75,25 +76,29 @@ SoftMPEG2::SoftMPEG2(
    +       mNewWidth(mWidth),
    +       mNewHeight(mHeight),
    +       mChangingResolution(false),
    ++      mSignalledError(false),
    +       mStride(mWidth) {
    +     initPorts(kNumBuffers, INPUT_BUF_SIZE, kNumBuffers, CODEC_MIME_TYPE);
    + 
    +     // If input dump is enabled, then open create an empty file
    +     GENERATE_FILE_NAMES();
    +     CREATE_DUMP_FILE(mInFile);
    +-
    +-    CHECK_EQ(initDecoder(), (status_t)OK);
    + }
    + 
    + SoftMPEG2::~SoftMPEG2() {
    +-    CHECK_EQ(deInitDecoder(), (status_t)OK);
    ++    if (OK != deInitDecoder()) {
    ++        ALOGE("Failed to deinit decoder");
    ++        notify(OMX_EventError, OMX_ErrorUnsupportedSetting, 0, NULL);
    ++        mSignalledError = true;
    ++        return;
    ++    }
    + }
    + 
    + 
    +-static size_t getMinTimestampIdx(OMX_S64 *pNTimeStamp, bool *pIsTimeStampValid) {
    ++static ssize_t getMinTimestampIdx(OMX_S64 *pNTimeStamp, bool *pIsTimeStampValid) {
    +     OMX_S64 minTimeStamp = LLONG_MAX;
    +-    int idx = -1;
    +-    for (size_t i = 0; i < MAX_TIME_STAMPS; i++) {
    ++    ssize_t idx = -1;
    ++    for (ssize_t i = 0; i < MAX_TIME_STAMPS; i++) {
    +         if (pIsTimeStampValid[i]) {
    +             if (pNTimeStamp[i] < minTimeStamp) {
    +                 minTimeStamp = pNTimeStamp[i];
    +@@ -204,6 +209,7 @@ status_t SoftMPEG2::resetDecoder() {
    +     setNumCores();
    + 
    +     mStride = 0;
    ++    mSignalledError = false;
    + 
    +     return OK;
    + }
    +@@ -433,6 +439,7 @@ status_t SoftMPEG2::deInitDecoder() {
    + 
    +     mInitNeeded = true;
    +     mChangingResolution = false;
    ++    mCodecCtx = NULL;
    + 
    +     return OK;
    + }
    +@@ -444,10 +451,11 @@ status_t SoftMPEG2::reInitDecoder() {
    + 
    +     ret = initDecoder();
    +     if (OK != ret) {
    +-        ALOGE("Create failure");
    ++        ALOGE("Failed to initialize decoder");
    +         deInitDecoder();
    +-        return NO_MEMORY;
    ++        return ret;
    +     }
    ++    mSignalledError = false;
    +     return OK;
    + }
    + 
    +@@ -586,10 +594,22 @@ void SoftMPEG2::onPortFlushCompleted(OMX_U32 portIndex) {
    + void SoftMPEG2::onQueueFilled(OMX_U32 portIndex) {
    +     UNUSED(portIndex);
    + 
    ++    if (mSignalledError) {
    ++        return;
    ++    }
    +     if (mOutputPortSettingsChange != NONE) {
    +         return;
    +     }
    + 
    ++    if (NULL == mCodecCtx) {
    ++        if (OK != initDecoder()) {
    ++            ALOGE("Failed to initialize decoder");
    ++            notify(OMX_EventError, OMX_ErrorUnsupportedSetting, 0, NULL);
    ++            mSignalledError = true;
    ++            return;
    ++        }
    ++    }
    ++
    +     List<BufferInfo *> &inQueue = getPortQueue(kInputPortIndex);
    +     List<BufferInfo *> &outQueue = getPortQueue(kOutputPortIndex);
    + 
    +@@ -642,7 +662,9 @@ void SoftMPEG2::onQueueFilled(OMX_U32 portIndex) {
    +             bool portWillReset = false;
    +             handlePortSettingsChange(&portWillReset, mNewWidth, mNewHeight);
    + 
    +-            CHECK_EQ(reInitDecoder(), (status_t)OK);
    ++            if (OK != reInitDecoder()) {
    ++                ALOGE("Failed to reinitialize decoder");
    ++            }
    +             return;
    +         }
    + 
    +@@ -715,7 +737,10 @@ void SoftMPEG2::onQueueFilled(OMX_U32 portIndex) {
    +                 bool portWillReset = false;
    +                 handlePortSettingsChange(&portWillReset, s_dec_op.u4_pic_wd, s_dec_op.u4_pic_ht);
    + 
    +-                CHECK_EQ(reInitDecoder(), (status_t)OK);
    ++                if (OK != reInitDecoder()) {
    ++                    ALOGE("Failed to reinitialize decoder");
    ++                    return;
    ++                }
    + 
    +                 if (setDecodeArgs(&s_dec_ip, &s_dec_op, inHeader, outHeader, timeStampIx)) {
    +                     ivdec_api_function(mCodecCtx, (void *)&s_dec_ip, (void *)&s_dec_op);
    +@@ -768,10 +793,15 @@ void SoftMPEG2::onQueueFilled(OMX_U32 portIndex) {
    +             }
    + 
    +             if (s_dec_op.u4_output_present) {
    +-                size_t timeStampIdx;
    ++                ssize_t timeStampIdx;
    +                 outHeader->nFilledLen = (mWidth * mHeight * 3) / 2;
    + 
    +                 timeStampIdx = getMinTimestampIdx(mTimeStamps, mTimeStampsValid);
    ++                if (timeStampIdx < 0) {
    ++                    ALOGE("b/62872863, Invalid timestamp index!");
    ++                    android_errorWriteLog(0x534e4554, "62872863");
    ++                    return;
    ++                }
    +                 outHeader->nTimeStamp = mTimeStamps[timeStampIdx];
    +                 mTimeStampsValid[timeStampIdx] = false;
    + 
    +diff --git a/media/libstagefright/codecs/mpeg2dec/SoftMPEG2.h b/media/libstagefright/codecs/mpeg2dec/SoftMPEG2.h
    +index 700ef5f..1285c5b 100644
    +--- a/media/libstagefright/codecs/mpeg2dec/SoftMPEG2.h
    ++++ b/media/libstagefright/codecs/mpeg2dec/SoftMPEG2.h
    +@@ -106,6 +106,7 @@ private:
    +     // codec. So the codec is switching to decode the new resolution.
    +     bool mChangingResolution;
    +     bool mFlushNeeded;
    ++    bool mSignalledError;
    +     bool mWaitForI;
    +     size_t mStride;
    + 
    +diff --git a/media/libstagefright/foundation/MediaBufferGroup.cpp b/media/libstagefright/foundation/MediaBufferGroup.cpp
    +index 8e4d064..66992d7 100644
    +--- a/media/libstagefright/foundation/MediaBufferGroup.cpp
    ++++ b/media/libstagefright/foundation/MediaBufferGroup.cpp
    +@@ -105,6 +105,11 @@ MediaBufferGroup::~MediaBufferGroup() {
    +     }
    + }
    + 
    ++extern "C" int _ZN7android16MediaBufferGroupC1Ej(unsigned int);
    ++extern "C" int _ZN7android16MediaBufferGroupC1Ev() {
    ++    return _ZN7android16MediaBufferGroupC1Ej(0);
    ++}
    ++
    + void MediaBufferGroup::add_buffer(MediaBuffer *buffer) {
    +     Mutex::Autolock autoLock(mLock);
    + 
    +@@ -198,6 +203,16 @@ status_t MediaBufferGroup::acquire_buffer(
    +     // Never gets here.
    + }
    + 
    ++status_t MediaBufferGroup::acquire_buffer(
    ++       MediaBuffer **out) {
    ++   return acquire_buffer(out, false, 0);
    ++}
    ++
    ++status_t MediaBufferGroup::acquire_buffer(
    ++        MediaBuffer **out, bool nonBlocking) {
    ++    return acquire_buffer(out, nonBlocking, 0);
    ++}
    ++
    + void MediaBufferGroup::signalBufferReturned(MediaBuffer *) {
    +     mCondition.signal();
    + }
    +diff --git a/media/libstagefright/foundation/base64.cpp b/media/libstagefright/foundation/base64.cpp
    +index 7da7db9..cc89064 100644
    +--- a/media/libstagefright/foundation/base64.cpp
    ++++ b/media/libstagefright/foundation/base64.cpp
    +@@ -78,8 +78,7 @@ sp<ABuffer> decodeBase64(const AString &s) {
    +         accum = (accum << 6) | value;
    + 
    +         if (((i + 1) % 4) == 0) {
    +-            out[j++] = (accum >> 16);
    +-
    ++            if (j < outLen) { out[j++] = (accum >> 16); }
    +             if (j < outLen) { out[j++] = (accum >> 8) & 0xff; }
    +             if (j < outLen) { out[j++] = accum & 0xff; }
    + 
    +diff --git a/media/libstagefright/httplive/LiveSession.cpp b/media/libstagefright/httplive/LiveSession.cpp
    +index 7abc019..590146d 100644
    +--- a/media/libstagefright/httplive/LiveSession.cpp
    ++++ b/media/libstagefright/httplive/LiveSession.cpp
    +@@ -157,6 +157,11 @@ bool LiveSession::BandwidthEstimator::estimateBandwidth(
    +     }
    + 
    +     *bandwidthBps = ((double)mTotalTransferBytes * 8E6 / mTotalTransferTimeUs);
    ++    static const int32_t kMaxBandwidthBps = 0x7fffffff / 7;
    ++    if (*bandwidthBps > kMaxBandwidthBps) {
    ++        ALOGW("Override bandwidth because it's too huge. %d -> %d", *bandwidthBps, kMaxBandwidthBps);
    ++        *bandwidthBps = kMaxBandwidthBps;
    ++    }
    +     mPrevEstimates.push_back(*bandwidthBps);
    +     while (mPrevEstimates.size() > 3) {
    +         mPrevEstimates.erase(mPrevEstimates.begin());
    +diff --git a/media/libstagefright/include/OMXNodeInstance.h b/media/libstagefright/include/OMXNodeInstance.h
    +index 94cf15a..dd396e8 100644
    +--- a/media/libstagefright/include/OMXNodeInstance.h
    ++++ b/media/libstagefright/include/OMXNodeInstance.h
    +@@ -175,7 +175,7 @@ private:
    +     KeyedVector<OMX::buffer_id, OMX_BUFFERHEADERTYPE *> mBufferIDToBufferHeader;
    +     KeyedVector<OMX_BUFFERHEADERTYPE *, OMX::buffer_id> mBufferHeaderToBufferID;
    + 
    +-    // metadata and secure buffer type tracking
    ++    // metadata and secure buffer types and graphic buffer mode tracking
    +     MetadataBufferType mMetadataType[2];
    +     enum SecureBufferType {
    +         kSecureBufferTypeUnknown,
    +@@ -183,6 +183,7 @@ private:
    +         kSecureBufferTypeNativeHandle,
    +     };
    +     SecureBufferType mSecureBufferType[2];
    ++    bool mGraphicBufferEnabled[2];
    + 
    +     // For debug support
    +     char *mName;
    +diff --git a/media/libstagefright/include/OMXNodeInstance.h.orig b/media/libstagefright/include/OMXNodeInstance.h.orig
    +new file mode 100644
    +index 0000000..f65a409
    +--- /dev/null
    ++++ b/media/libstagefright/include/OMXNodeInstance.h.orig
    +@@ -0,0 +1,282 @@
    ++/*
    ++ * Copyright (C) 2009 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.
    ++ */
    ++
    ++#ifndef OMX_NODE_INSTANCE_H_
    ++
    ++#define OMX_NODE_INSTANCE_H_
    ++
    ++#include "OMX.h"
    ++
    ++#include <utils/RefBase.h>
    ++#include <utils/SortedVector.h>
    ++#include <utils/threads.h>
    ++
    ++namespace android {
    ++
    ++class IOMXObserver;
    ++struct OMXMaster;
    ++class GraphicBufferSource;
    ++
    ++struct OMXNodeInstance {
    ++    OMXNodeInstance(
    ++            OMX *owner, const sp<IOMXObserver> &observer, const char *name);
    ++
    ++    void setHandle(OMX::node_id node_id, OMX_HANDLETYPE handle);
    ++
    ++    OMX *owner();
    ++    sp<IOMXObserver> observer();
    ++    OMX::node_id nodeID();
    ++
    ++    status_t freeNode(OMXMaster *master);
    ++
    ++    status_t sendCommand(OMX_COMMANDTYPE cmd, OMX_S32 param);
    ++    status_t getParameter(OMX_INDEXTYPE index, void *params, size_t size);
    ++
    ++    status_t setParameter(
    ++            OMX_INDEXTYPE index, const void *params, size_t size);
    ++
    ++    status_t getConfig(OMX_INDEXTYPE index, void *params, size_t size);
    ++    status_t setConfig(OMX_INDEXTYPE index, const void *params, size_t size);
    ++
    ++    status_t getState(OMX_STATETYPE* state);
    ++
    ++    status_t enableNativeBuffers(OMX_U32 portIndex, OMX_BOOL graphic, OMX_BOOL enable);
    ++
    ++    status_t getGraphicBufferUsage(OMX_U32 portIndex, OMX_U32* usage);
    ++
    ++    status_t storeMetaDataInBuffers(
    ++            OMX_U32 portIndex, OMX_BOOL enable, MetadataBufferType *type);
    ++
    ++    status_t prepareForAdaptivePlayback(
    ++            OMX_U32 portIndex, OMX_BOOL enable,
    ++            OMX_U32 maxFrameWidth, OMX_U32 maxFrameHeight);
    ++
    ++    status_t configureVideoTunnelMode(
    ++            OMX_U32 portIndex, OMX_BOOL tunneled,
    ++            OMX_U32 audioHwSync, native_handle_t **sidebandHandle);
    ++
    ++    status_t useBuffer(
    ++            OMX_U32 portIndex, const sp<IMemory> &params,
    ++            OMX::buffer_id *buffer, OMX_U32 allottedSize);
    ++
    ++    status_t useGraphicBuffer(
    ++            OMX_U32 portIndex, const sp<GraphicBuffer> &graphicBuffer,
    ++            OMX::buffer_id *buffer);
    ++
    ++    status_t updateGraphicBufferInMeta(
    ++            OMX_U32 portIndex, const sp<GraphicBuffer> &graphicBuffer,
    ++            OMX::buffer_id buffer);
    ++
    ++    status_t updateNativeHandleInMeta(
    ++            OMX_U32 portIndex, const sp<NativeHandle> &nativeHandle,
    ++            OMX::buffer_id buffer);
    ++
    ++    status_t createInputSurface(
    ++            OMX_U32 portIndex, android_dataspace dataSpace,
    ++            sp<IGraphicBufferProducer> *bufferProducer,
    ++            MetadataBufferType *type);
    ++
    ++    static status_t createPersistentInputSurface(
    ++            sp<IGraphicBufferProducer> *bufferProducer,
    ++            sp<IGraphicBufferConsumer> *bufferConsumer);
    ++
    ++    status_t setInputSurface(
    ++            OMX_U32 portIndex, const sp<IGraphicBufferConsumer> &bufferConsumer,
    ++            MetadataBufferType *type);
    ++
    ++    status_t signalEndOfInputStream();
    ++
    ++    void signalEvent(OMX_EVENTTYPE event, OMX_U32 arg1, OMX_U32 arg2);
    ++
    ++    status_t allocateSecureBuffer(
    ++            OMX_U32 portIndex, size_t size, OMX::buffer_id *buffer,
    ++            void **buffer_data, sp<NativeHandle> *native_handle);
    ++
    ++    status_t allocateBufferWithBackup(
    ++            OMX_U32 portIndex, const sp<IMemory> &params,
    ++            OMX::buffer_id *buffer, OMX_U32 allottedSize);
    ++
    ++    status_t freeBuffer(OMX_U32 portIndex, OMX::buffer_id buffer);
    ++
    ++    status_t fillBuffer(OMX::buffer_id buffer, int fenceFd);
    ++
    ++    status_t emptyBuffer(
    ++            OMX::buffer_id buffer,
    ++            OMX_U32 rangeOffset, OMX_U32 rangeLength,
    ++            OMX_U32 flags, OMX_TICKS timestamp, int fenceFd);
    ++
    ++    status_t emptyGraphicBuffer(
    ++            OMX_BUFFERHEADERTYPE *header, const sp<GraphicBuffer> &buffer,
    ++            OMX_U32 flags, OMX_TICKS timestamp, int fenceFd);
    ++
    ++    status_t getExtensionIndex(
    ++            const char *parameterName, OMX_INDEXTYPE *index);
    ++
    ++    status_t setInternalOption(
    ++            OMX_U32 portIndex,
    ++            IOMX::InternalOptionType type,
    ++            const void *data,
    ++            size_t size);
    ++
    ++    bool isSecure() const {
    ++        return mIsSecure;
    ++    }
    ++
    ++    // handles messages and removes them from the list
    ++    void onMessages(std::list<omx_message> &messages);
    ++    void onMessage(const omx_message &msg);
    ++    void onObserverDied(OMXMaster *master);
    ++    void onGetHandleFailed();
    ++    void onEvent(OMX_EVENTTYPE event, OMX_U32 arg1, OMX_U32 arg2);
    ++
    ++    static OMX_CALLBACKTYPE kCallbacks;
    ++
    ++private:
    ++    Mutex mLock;
    ++
    ++    OMX *mOwner;
    ++    OMX::node_id mNodeID;
    ++    OMX_HANDLETYPE mHandle;
    ++    sp<IOMXObserver> mObserver;
    ++    bool mDying;
    ++    bool mSailed;  // configuration is set (no more meta-mode changes)
    ++    bool mQueriedProhibitedExtensions;
    ++    SortedVector<OMX_INDEXTYPE> mProhibitedExtensions;
    ++    bool mIsSecure;
    ++
    ++    // Lock only covers mGraphicBufferSource.  We can't always use mLock
    ++    // because of rare instances where we'd end up locking it recursively.
    ++    Mutex mGraphicBufferSourceLock;
    ++    // Access this through getGraphicBufferSource().
    ++    sp<GraphicBufferSource> mGraphicBufferSource;
    ++
    ++
    ++    struct ActiveBuffer {
    ++        OMX_U32 mPortIndex;
    ++        OMX::buffer_id mID;
    ++    };
    ++    Vector<ActiveBuffer> mActiveBuffers;
    ++    // for buffer ptr to buffer id translation
    ++    Mutex mBufferIDLock;
    ++    uint32_t mBufferIDCount;
    ++    KeyedVector<OMX::buffer_id, OMX_BUFFERHEADERTYPE *> mBufferIDToBufferHeader;
    ++    KeyedVector<OMX_BUFFERHEADERTYPE *, OMX::buffer_id> mBufferHeaderToBufferID;
    ++
    ++<<<<<<< HEAD
    ++    // metadata and secure buffer type tracking
    ++=======
    ++    bool mLegacyAdaptiveExperiment;
    ++    IOMX::PortMode mPortMode[2];
    ++    // metadata and secure buffer types and graphic buffer mode tracking
    ++>>>>>>> f630233... Track graphic buffer mode in OMXNodeInstance
    ++    MetadataBufferType mMetadataType[2];
    ++    enum SecureBufferType {
    ++        kSecureBufferTypeUnknown,
    ++        kSecureBufferTypeOpaque,
    ++        kSecureBufferTypeNativeHandle,
    ++    };
    ++    SecureBufferType mSecureBufferType[2];
    ++    bool mGraphicBufferEnabled[2];
    ++
    ++    // For debug support
    ++    char *mName;
    ++    int DEBUG;
    ++    size_t mNumPortBuffers[2];  // modified under mLock, read outside for debug
    ++    Mutex mDebugLock;
    ++    // following are modified and read under mDebugLock
    ++    int DEBUG_BUMP;
    ++    SortedVector<OMX_BUFFERHEADERTYPE *> mInputBuffersWithCodec, mOutputBuffersWithCodec;
    ++    size_t mDebugLevelBumpPendingBuffers[2];
    ++    void bumpDebugLevel_l(size_t numInputBuffers, size_t numOutputBuffers);
    ++    void unbumpDebugLevel_l(size_t portIndex);
    ++
    ++    ~OMXNodeInstance();
    ++
    ++    void addActiveBuffer(OMX_U32 portIndex, OMX::buffer_id id);
    ++    void removeActiveBuffer(OMX_U32 portIndex, OMX::buffer_id id);
    ++    void freeActiveBuffers();
    ++
    ++    // For buffer id management
    ++    OMX::buffer_id makeBufferID(OMX_BUFFERHEADERTYPE *bufferHeader);
    ++    OMX_BUFFERHEADERTYPE *findBufferHeader(OMX::buffer_id buffer, OMX_U32 portIndex);
    ++    OMX::buffer_id findBufferID(OMX_BUFFERHEADERTYPE *bufferHeader);
    ++    void invalidateBufferID(OMX::buffer_id buffer);
    ++
    ++    bool isProhibitedIndex_l(OMX_INDEXTYPE index);
    ++
    ++    status_t useGraphicBuffer2_l(
    ++            OMX_U32 portIndex, const sp<GraphicBuffer> &graphicBuffer,
    ++            OMX::buffer_id *buffer);
    ++    static OMX_ERRORTYPE OnEvent(
    ++            OMX_IN OMX_HANDLETYPE hComponent,
    ++            OMX_IN OMX_PTR pAppData,
    ++            OMX_IN OMX_EVENTTYPE eEvent,
    ++            OMX_IN OMX_U32 nData1,
    ++            OMX_IN OMX_U32 nData2,
    ++            OMX_IN OMX_PTR pEventData);
    ++
    ++    static OMX_ERRORTYPE OnEmptyBufferDone(
    ++            OMX_IN OMX_HANDLETYPE hComponent,
    ++            OMX_IN OMX_PTR pAppData,
    ++            OMX_IN OMX_BUFFERHEADERTYPE *pBuffer);
    ++
    ++    static OMX_ERRORTYPE OnFillBufferDone(
    ++            OMX_IN OMX_HANDLETYPE hComponent,
    ++            OMX_IN OMX_PTR pAppData,
    ++            OMX_IN OMX_BUFFERHEADERTYPE *pBuffer);
    ++
    ++    status_t storeMetaDataInBuffers_l(
    ++            OMX_U32 portIndex, OMX_BOOL enable, MetadataBufferType *type);
    ++
    ++    // Stores fence into buffer if it is ANWBuffer type and has enough space.
    ++    // otherwise, waits for the fence to signal.  Takes ownership of |fenceFd|.
    ++    status_t storeFenceInMeta_l(
    ++            OMX_BUFFERHEADERTYPE *header, int fenceFd, OMX_U32 portIndex);
    ++
    ++    // Retrieves the fence from buffer if ANWBuffer type and has enough space. Otherwise, returns -1
    ++    int retrieveFenceFromMeta_l(
    ++            OMX_BUFFERHEADERTYPE *header, OMX_U32 portIndex);
    ++
    ++    status_t emptyBuffer_l(
    ++            OMX_BUFFERHEADERTYPE *header,
    ++            OMX_U32 flags, OMX_TICKS timestamp, intptr_t debugAddr, int fenceFd);
    ++
    ++    // Updates the graphic buffer handle in the metadata buffer for |buffer| and |header| to
    ++    // |graphicBuffer|'s handle. If |updateCodecBuffer| is true, the update will happen in
    ++    // the actual codec buffer (use this if not using emptyBuffer (with no _l) later to
    ++    // pass the buffer to the codec, as only emptyBuffer copies the backup buffer to the codec
    ++    // buffer.)
    ++    status_t updateGraphicBufferInMeta_l(
    ++            OMX_U32 portIndex, const sp<GraphicBuffer> &graphicBuffer,
    ++            OMX::buffer_id buffer, OMX_BUFFERHEADERTYPE *header, bool updateCodecBuffer);
    ++
    ++    status_t createGraphicBufferSource(
    ++            OMX_U32 portIndex, sp<IGraphicBufferConsumer> consumer /* nullable */,
    ++            MetadataBufferType *type);
    ++    sp<GraphicBufferSource> getGraphicBufferSource();
    ++    void setGraphicBufferSource(const sp<GraphicBufferSource>& bufferSource);
    ++
    ++    // Handles |msg|, and may modify it. Returns true iff completely handled it and
    ++    // |msg| does not need to be sent to the event listener.
    ++    bool handleMessage(omx_message &msg);
    ++
    ++    OMXNodeInstance(const OMXNodeInstance &);
    ++    OMXNodeInstance &operator=(const OMXNodeInstance &);
    ++};
    ++
    ++}  // namespace android
    ++
    ++#endif  // OMX_NODE_INSTANCE_H_
    +diff --git a/media/libstagefright/mpeg2ts/ESQueue.cpp b/media/libstagefright/mpeg2ts/ESQueue.cpp
    +index 96ca405..7599c13 100644
    +--- a/media/libstagefright/mpeg2ts/ESQueue.cpp
    ++++ b/media/libstagefright/mpeg2ts/ESQueue.cpp
    +@@ -716,6 +716,11 @@ sp<ABuffer> ElementaryStreamQueue::dequeueAccessUnitAAC() {
    +         bits.skipBits(2);
    + 
    +         unsigned aac_frame_length = bits.getBits(13);
    ++        if (aac_frame_length == 0){
    ++            ALOGE("b/62673179, Invalid AAC frame length!");
    ++            android_errorWriteLog(0x534e4554, "62673179");
    ++            return NULL;
    ++        }
    + 
    +         bits.skipBits(11);  // adts_buffer_fullness
    + 
    +diff --git a/media/libstagefright/omx/Android.mk b/media/libstagefright/omx/Android.mk
    +index e4fbd81..8fc788f 100644
    +--- a/media/libstagefright/omx/Android.mk
    ++++ b/media/libstagefright/omx/Android.mk
    +@@ -31,6 +31,12 @@ LOCAL_SHARED_LIBRARIES :=               \
    +         libstagefright_foundation       \
    +         libdl
    + 
    ++ifneq ($(TARGET_USES_MEDIA_EXTENSIONS),true)
    ++ifeq ($(TARGET_HAS_LEGACY_CAMERA_HAL1),true)
    ++LOCAL_CFLAGS += -DCAMCORDER_GRALLOC_SOURCE
    ++endif
    ++endif
    ++
    + LOCAL_MODULE:= libstagefright_omx
    + LOCAL_CFLAGS += -Werror -Wall
    + LOCAL_CLANG := true
    +diff --git a/media/libstagefright/omx/GraphicBufferSource.cpp b/media/libstagefright/omx/GraphicBufferSource.cpp
    +index e1bcd28..5f21eac 100644
    +--- a/media/libstagefright/omx/GraphicBufferSource.cpp
    ++++ b/media/libstagefright/omx/GraphicBufferSource.cpp
    +@@ -736,6 +736,8 @@ bool GraphicBufferSource::repeatLatestBuffer_l() {
    + 
    + void GraphicBufferSource::setLatestBuffer_l(
    +         const BufferItem &item, bool dropped) {
    ++    ALOGV("setLatestBuffer_l");
    ++
    +     if (mLatestBufferId >= 0) {
    +         if (mBufferUseCount[mLatestBufferId] == 0) {
    +             releaseBuffer(mLatestBufferId, mLatestBufferFrameNum,
    +diff --git a/media/libstagefright/omx/OMXMaster.cpp b/media/libstagefright/omx/OMXMaster.cpp
    +index 6132a2c..7f0d270 100644
    +--- a/media/libstagefright/omx/OMXMaster.cpp
    ++++ b/media/libstagefright/omx/OMXMaster.cpp
    +@@ -69,6 +69,7 @@ OMXMaster::~OMXMaster() {
    + 
    + void OMXMaster::addVendorPlugin() {
    +     addPlugin("libstagefrighthw.so");
    ++    addPlugin("libsomxcore.so");
    + }
    + 
    + void OMXMaster::addPlugin(const char *libname) {
    +diff --git a/media/libstagefright/omx/OMXNodeInstance.cpp b/media/libstagefright/omx/OMXNodeInstance.cpp
    +index e7aaead..a0a746e 100644
    +--- a/media/libstagefright/omx/OMXNodeInstance.cpp
    ++++ b/media/libstagefright/omx/OMXNodeInstance.cpp
    +@@ -226,6 +226,8 @@ OMXNodeInstance::OMXNodeInstance(
    +     mMetadataType[1] = kMetadataBufferTypeInvalid;
    +     mSecureBufferType[0] = kSecureBufferTypeUnknown;
    +     mSecureBufferType[1] = kSecureBufferTypeUnknown;
    ++    mGraphicBufferEnabled[0] = false;
    ++    mGraphicBufferEnabled[1] = false;
    +     mIsSecure = AString(name).endsWith(".secure");
    + }
    + 
    +@@ -562,6 +564,12 @@ status_t OMXNodeInstance::enableNativeBuffers(
    +             } else if (mSecureBufferType[portIndex] == kSecureBufferTypeUnknown) {
    +                 mSecureBufferType[portIndex] = kSecureBufferTypeOpaque;
    +             }
    ++        } else {
    ++            if (err == OMX_ErrorNone) {
    ++                mGraphicBufferEnabled[portIndex] = enable;
    ++            } else if (enable) {
    ++                mGraphicBufferEnabled[portIndex] = false;
    ++            }
    +         }
    +     } else {
    +         CLOG_ERROR_IF(enable, getExtensionIndex, err, "%s", name);
    +@@ -801,7 +809,11 @@ status_t OMXNodeInstance::useBuffer(
    +     // metadata buffers are not connected cross process
    +     // use a backup buffer instead of the actual buffer
    +     BufferMeta *buffer_meta;
    ++#ifdef CAMCORDER_GRALLOC_SOURCE
    ++    bool useBackup = false;
    ++#else
    +     bool useBackup = mMetadataType[portIndex] != kMetadataBufferTypeInvalid;
    ++#endif
    +     OMX_U8 *data = static_cast<OMX_U8 *>(params->pointer());
    +     // allocate backup buffer
    +     if (useBackup) {
    +@@ -1297,7 +1309,11 @@ status_t OMXNodeInstance::allocateBufferWithBackup(
    +     }
    + 
    +     // metadata buffers are not connected cross process; only copy if not meta
    ++#ifdef CAMCORDER_GRALLOC_SOURCE
    ++    bool copy = true;
    ++#else
    +     bool copy = mMetadataType[portIndex] == kMetadataBufferTypeInvalid;
    ++#endif
    + 
    +     BufferMeta *buffer_meta = new BufferMeta(
    +             params, portIndex,
    +@@ -1415,10 +1431,30 @@ status_t OMXNodeInstance::emptyBuffer(
    +     BufferMeta *buffer_meta =
    +         static_cast<BufferMeta *>(header->pAppPrivate);
    + 
    ++#ifndef CAMCORDER_GRALLOC_SOURCE
    +     // set up proper filled length if component is configured for gralloc metadata mode
    +     // ignore rangeOffset in this case (as client may be assuming ANW meta buffers).
    +     if (mMetadataType[kPortIndexInput] == kMetadataBufferTypeGrallocSource) {
    +         header->nFilledLen = rangeLength ? sizeof(VideoGrallocMetadata) : 0;
    ++#else
    ++    sp<ABuffer> backup = buffer_meta->getBuffer(header, true /* backup */, false /* limit */);
    ++    sp<ABuffer> codec = buffer_meta->getBuffer(header, false /* backup */, false /* limit */);
    ++
    ++    // convert incoming ANW meta buffers if component is configured for gralloc metadata mode
    ++    // ignore rangeOffset in this case
    ++    if (mMetadataType[kPortIndexInput] == kMetadataBufferTypeGrallocSource
    ++            && backup->capacity() >= sizeof(VideoNativeMetadata)
    ++            && codec->capacity() >= sizeof(VideoGrallocMetadata)
    ++            && ((VideoNativeMetadata *)backup->base())->eType
    ++                    == kMetadataBufferTypeANWBuffer) {
    ++        VideoNativeMetadata &backupMeta = *(VideoNativeMetadata *)backup->base();
    ++        VideoGrallocMetadata &codecMeta = *(VideoGrallocMetadata *)codec->base();
    ++        CLOG_BUFFER(emptyBuffer, "converting ANWB %p to handle %p",
    ++                backupMeta.pBuffer, backupMeta.pBuffer->handle);
    ++        codecMeta.pHandle = backupMeta.pBuffer != NULL ? backupMeta.pBuffer->handle : NULL;
    ++        codecMeta.eType = kMetadataBufferTypeGrallocSource;
    ++        header->nFilledLen = rangeLength ? sizeof(codecMeta) : 0;
    ++#endif
    +         header->nOffset = 0;
    +     } else {
    +         // rangeLength and rangeOffset must be a subset of the allocated data in the buffer.
    +diff --git a/media/libstagefright/omx/OMXNodeInstance.cpp.orig b/media/libstagefright/omx/OMXNodeInstance.cpp.orig
    +new file mode 100644
    +index 0000000..968cc1b
    +--- /dev/null
    ++++ b/media/libstagefright/omx/OMXNodeInstance.cpp.orig
    +@@ -0,0 +1,2131 @@
    ++/*
    ++ * Copyright (C) 2009 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.
    ++ */
    ++
    ++//#define LOG_NDEBUG 0
    ++#define LOG_TAG "OMXNodeInstance"
    ++#include <utils/Log.h>
    ++
    ++#include <inttypes.h>
    ++
    ++#include "../include/OMXNodeInstance.h"
    ++#include "OMXMaster.h"
    ++#include "OMXUtils.h"
    ++#include "GraphicBufferSource.h"
    ++
    ++#include <OMX_Component.h>
    ++#include <OMX_IndexExt.h>
    ++#include <OMX_AsString.h>
    ++
    ++#include <binder/IMemory.h>
    ++#include <cutils/properties.h>
    ++#include <gui/BufferQueue.h>
    ++#include <HardwareAPI.h>
    ++#include <media/stagefright/foundation/ADebug.h>
    ++#include <media/stagefright/foundation/ABuffer.h>
    ++#include <media/stagefright/MediaErrors.h>
    ++#include <utils/misc.h>
    ++#include <utils/NativeHandle.h>
    ++
    ++static const OMX_U32 kPortIndexInput = 0;
    ++static const OMX_U32 kPortIndexOutput = 1;
    ++
    ++#define CLOGW(fmt, ...) ALOGW("[%x:%s] " fmt, mNodeID, mName, ##__VA_ARGS__)
    ++
    ++#define CLOG_ERROR_IF(cond, fn, err, fmt, ...) \
    ++    ALOGE_IF(cond, #fn "(%x:%s, " fmt ") ERROR: %s(%#x)", \
    ++    mNodeID, mName, ##__VA_ARGS__, asString(err), err)
    ++#define CLOG_ERROR(fn, err, fmt, ...) CLOG_ERROR_IF(true, fn, err, fmt, ##__VA_ARGS__)
    ++#define CLOG_IF_ERROR(fn, err, fmt, ...) \
    ++    CLOG_ERROR_IF((err) != OMX_ErrorNone, fn, err, fmt, ##__VA_ARGS__)
    ++
    ++#define CLOGI_(level, fn, fmt, ...) \
    ++    ALOGI_IF(DEBUG >= (level), #fn "(%x:%s, " fmt ")", mNodeID, mName, ##__VA_ARGS__)
    ++#define CLOGD_(level, fn, fmt, ...) \
    ++    ALOGD_IF(DEBUG >= (level), #fn "(%x:%s, " fmt ")", mNodeID, mName, ##__VA_ARGS__)
    ++
    ++#define CLOG_LIFE(fn, fmt, ...)     CLOGI_(ADebug::kDebugLifeCycle,     fn, fmt, ##__VA_ARGS__)
    ++#define CLOG_STATE(fn, fmt, ...)    CLOGI_(ADebug::kDebugState,         fn, fmt, ##__VA_ARGS__)
    ++#define CLOG_CONFIG(fn, fmt, ...)   CLOGI_(ADebug::kDebugConfig,        fn, fmt, ##__VA_ARGS__)
    ++#define CLOG_INTERNAL(fn, fmt, ...) CLOGD_(ADebug::kDebugInternalState, fn, fmt, ##__VA_ARGS__)
    ++
    ++#define CLOG_DEBUG_IF(cond, fn, fmt, ...) \
    ++    ALOGD_IF(cond, #fn "(%x, " fmt ")", mNodeID, ##__VA_ARGS__)
    ++
    ++#define CLOG_BUFFER(fn, fmt, ...) \
    ++    CLOG_DEBUG_IF(DEBUG >= ADebug::kDebugAll, fn, fmt, ##__VA_ARGS__)
    ++#define CLOG_BUMPED_BUFFER(fn, fmt, ...) \
    ++    CLOG_DEBUG_IF(DEBUG_BUMP >= ADebug::kDebugAll, fn, fmt, ##__VA_ARGS__)
    ++
    ++/* buffer formatting */
    ++#define BUFFER_FMT(port, fmt, ...) "%s:%u " fmt, portString(port), (port), ##__VA_ARGS__
    ++#define NEW_BUFFER_FMT(buffer_id, port, fmt, ...) \
    ++    BUFFER_FMT(port, fmt ") (#%zu => %#x", ##__VA_ARGS__, mActiveBuffers.size(), (buffer_id))
    ++
    ++#define SIMPLE_BUFFER(port, size, data) BUFFER_FMT(port, "%zu@%p", (size), (data))
    ++#define SIMPLE_NEW_BUFFER(buffer_id, port, size, data) \
    ++    NEW_BUFFER_FMT(buffer_id, port, "%zu@%p", (size), (data))
    ++
    ++#define EMPTY_BUFFER(addr, header, fenceFd) "%#x [%u@%p fc=%d]", \
    ++    (addr), (header)->nAllocLen, (header)->pBuffer, (fenceFd)
    ++#define FULL_BUFFER(addr, header, fenceFd) "%#" PRIxPTR " [%u@%p (%u..+%u) f=%x ts=%lld fc=%d]", \
    ++    (intptr_t)(addr), (header)->nAllocLen, (header)->pBuffer, \
    ++    (header)->nOffset, (header)->nFilledLen, (header)->nFlags, (header)->nTimeStamp, (fenceFd)
    ++
    ++#define WITH_STATS_WRAPPER(fmt, ...) fmt " { IN=%zu/%zu OUT=%zu/%zu }", ##__VA_ARGS__, \
    ++    mInputBuffersWithCodec.size(), mNumPortBuffers[kPortIndexInput], \
    ++    mOutputBuffersWithCodec.size(), mNumPortBuffers[kPortIndexOutput]
    ++// TRICKY: this is needed so formatting macros expand before substitution
    ++#define WITH_STATS(fmt, ...) WITH_STATS_WRAPPER(fmt, ##__VA_ARGS__)
    ++
    ++namespace android {
    ++
    ++struct BufferMeta {
    ++    BufferMeta(
    ++            const sp<IMemory> &mem, OMX_U32 portIndex, bool copyToOmx,
    ++            bool copyFromOmx, OMX_U8 *backup)
    ++        : mMem(mem),
    ++          mCopyFromOmx(copyFromOmx),
    ++          mCopyToOmx(copyToOmx),
    ++          mPortIndex(portIndex),
    ++          mBackup(backup) {
    ++    }
    ++
    ++    BufferMeta(size_t size, OMX_U32 portIndex)
    ++        : mSize(size),
    ++          mCopyFromOmx(false),
    ++          mCopyToOmx(false),
    ++          mPortIndex(portIndex),
    ++          mBackup(NULL) {
    ++    }
    ++
    ++    BufferMeta(const sp<GraphicBuffer> &graphicBuffer, OMX_U32 portIndex)
    ++        : mGraphicBuffer(graphicBuffer),
    ++          mCopyFromOmx(false),
    ++          mCopyToOmx(false),
    ++          mPortIndex(portIndex),
    ++          mBackup(NULL) {
    ++    }
    ++
    ++    void CopyFromOMX(const OMX_BUFFERHEADERTYPE *header) {
    ++        if (!mCopyFromOmx) {
    ++            return;
    ++        }
    ++
    ++        // check component returns proper range
    ++        sp<ABuffer> codec = getBuffer(header, false /* backup */, true /* limit */);
    ++
    ++        memcpy((OMX_U8 *)mMem->pointer() + header->nOffset, codec->data(), codec->size());
    ++    }
    ++
    ++    void CopyToOMX(const OMX_BUFFERHEADERTYPE *header) {
    ++        if (!mCopyToOmx) {
    ++            return;
    ++        }
    ++
    ++        memcpy(header->pBuffer + header->nOffset,
    ++                (const OMX_U8 *)mMem->pointer() + header->nOffset,
    ++                header->nFilledLen);
    ++    }
    ++
    ++    // return either the codec or the backup buffer
    ++    sp<ABuffer> getBuffer(const OMX_BUFFERHEADERTYPE *header, bool backup, bool limit) {
    ++        sp<ABuffer> buf;
    ++        if (backup && mMem != NULL) {
    ++            buf = new ABuffer(mMem->pointer(), mMem->size());
    ++        } else {
    ++            buf = new ABuffer(header->pBuffer, header->nAllocLen);
    ++        }
    ++        if (limit) {
    ++            if (header->nOffset + header->nFilledLen > header->nOffset
    ++                    && header->nOffset + header->nFilledLen <= header->nAllocLen) {
    ++                buf->setRange(header->nOffset, header->nFilledLen);
    ++            } else {
    ++                buf->setRange(0, 0);
    ++            }
    ++        }
    ++        return buf;
    ++    }
    ++
    ++    void setGraphicBuffer(const sp<GraphicBuffer> &graphicBuffer) {
    ++        mGraphicBuffer = graphicBuffer;
    ++    }
    ++
    ++    void setNativeHandle(const sp<NativeHandle> &nativeHandle) {
    ++        mNativeHandle = nativeHandle;
    ++    }
    ++
    ++    OMX_U32 getPortIndex() {
    ++        return mPortIndex;
    ++    }
    ++
    ++    ~BufferMeta() {
    ++        delete[] mBackup;
    ++    }
    ++
    ++private:
    ++    sp<GraphicBuffer> mGraphicBuffer;
    ++    sp<NativeHandle> mNativeHandle;
    ++    sp<IMemory> mMem;
    ++    size_t mSize;
    ++    bool mCopyFromOmx;
    ++    bool mCopyToOmx;
    ++    OMX_U32 mPortIndex;
    ++    OMX_U8 *mBackup;
    ++
    ++    BufferMeta(const BufferMeta &);
    ++    BufferMeta &operator=(const BufferMeta &);
    ++};
    ++
    ++// static
    ++OMX_CALLBACKTYPE OMXNodeInstance::kCallbacks = {
    ++    &OnEvent, &OnEmptyBufferDone, &OnFillBufferDone
    ++};
    ++
    ++static inline const char *portString(OMX_U32 portIndex) {
    ++    switch (portIndex) {
    ++        case kPortIndexInput:  return "Input";
    ++        case kPortIndexOutput: return "Output";
    ++        case ~0U:              return "All";
    ++        default:               return "port";
    ++    }
    ++}
    ++
    ++OMXNodeInstance::OMXNodeInstance(
    ++        OMX *owner, const sp<IOMXObserver> &observer, const char *name)
    ++    : mOwner(owner),
    ++      mNodeID(0),
    ++      mHandle(NULL),
    ++      mObserver(observer),
    ++      mDying(false),
    ++      mSailed(false),
    ++      mQueriedProhibitedExtensions(false),
    ++      mBufferIDCount(0)
    ++{
    ++    mName = ADebug::GetDebugName(name);
    ++    DEBUG = ADebug::GetDebugLevelFromProperty(name, "debug.stagefright.omx-debug");
    ++    ALOGV("debug level for %s is %d", name, DEBUG);
    ++    DEBUG_BUMP = DEBUG;
    ++    mNumPortBuffers[0] = 0;
    ++    mNumPortBuffers[1] = 0;
    ++    mDebugLevelBumpPendingBuffers[0] = 0;
    ++    mDebugLevelBumpPendingBuffers[1] = 0;
    ++    mMetadataType[0] = kMetadataBufferTypeInvalid;
    ++    mMetadataType[1] = kMetadataBufferTypeInvalid;
    ++    mSecureBufferType[0] = kSecureBufferTypeUnknown;
    ++    mSecureBufferType[1] = kSecureBufferTypeUnknown;
    ++    mGraphicBufferEnabled[0] = false;
    ++    mGraphicBufferEnabled[1] = false;
    ++    mIsSecure = AString(name).endsWith(".secure");
    ++}
    ++
    ++OMXNodeInstance::~OMXNodeInstance() {
    ++    free(mName);
    ++    CHECK(mHandle == NULL);
    ++}
    ++
    ++void OMXNodeInstance::setHandle(OMX::node_id node_id, OMX_HANDLETYPE handle) {
    ++    mNodeID = node_id;
    ++    CLOG_LIFE(allocateNode, "handle=%p", handle);
    ++    CHECK(mHandle == NULL);
    ++    mHandle = handle;
    ++}
    ++
    ++sp<GraphicBufferSource> OMXNodeInstance::getGraphicBufferSource() {
    ++    Mutex::Autolock autoLock(mGraphicBufferSourceLock);
    ++    return mGraphicBufferSource;
    ++}
    ++
    ++void OMXNodeInstance::setGraphicBufferSource(
    ++        const sp<GraphicBufferSource>& bufferSource) {
    ++    Mutex::Autolock autoLock(mGraphicBufferSourceLock);
    ++    CLOG_INTERNAL(setGraphicBufferSource, "%p", bufferSource.get());
    ++    mGraphicBufferSource = bufferSource;
    ++}
    ++
    ++OMX *OMXNodeInstance::owner() {
    ++    return mOwner;
    ++}
    ++
    ++sp<IOMXObserver> OMXNodeInstance::observer() {
    ++    return mObserver;
    ++}
    ++
    ++OMX::node_id OMXNodeInstance::nodeID() {
    ++    return mNodeID;
    ++}
    ++
    ++status_t OMXNodeInstance::freeNode(OMXMaster *master) {
    ++    CLOG_LIFE(freeNode, "handle=%p", mHandle);
    ++    static int32_t kMaxNumIterations = 10;
    ++
    ++    // exit if we have already freed the node
    ++    if (mHandle == NULL) {
    ++        return OK;
    ++    }
    ++
    ++    // Transition the node from its current state all the way down
    ++    // to "Loaded".
    ++    // This ensures that all active buffers are properly freed even
    ++    // for components that don't do this themselves on a call to
    ++    // "FreeHandle".
    ++
    ++    // The code below may trigger some more events to be dispatched
    ++    // by the OMX component - we want to ignore them as our client
    ++    // does not expect them.
    ++    mDying = true;
    ++
    ++    OMX_STATETYPE state;
    ++    CHECK_EQ(OMX_GetState(mHandle, &state), OMX_ErrorNone);
    ++    switch (state) {
    ++        case OMX_StateExecuting:
    ++        {
    ++            ALOGV("forcing Executing->Idle");
    ++            sendCommand(OMX_CommandStateSet, OMX_StateIdle);
    ++            OMX_ERRORTYPE err;
    ++            int32_t iteration = 0;
    ++            while ((err = OMX_GetState(mHandle, &state)) == OMX_ErrorNone
    ++                    && state != OMX_StateIdle
    ++                    && state != OMX_StateInvalid) {
    ++                if (++iteration > kMaxNumIterations) {
    ++                    CLOGW("failed to enter Idle state (now %s(%d), aborting.",
    ++                            asString(state), state);
    ++                    state = OMX_StateInvalid;
    ++                    break;
    ++                }
    ++
    ++                usleep(100000);
    ++            }
    ++            CHECK_EQ(err, OMX_ErrorNone);
    ++
    ++            if (state == OMX_StateInvalid) {
    ++                break;
    ++            }
    ++
    ++            // fall through
    ++        }
    ++
    ++        case OMX_StateIdle:
    ++        {
    ++            ALOGV("forcing Idle->Loaded");
    ++            sendCommand(OMX_CommandStateSet, OMX_StateLoaded);
    ++
    ++            freeActiveBuffers();
    ++
    ++            OMX_ERRORTYPE err;
    ++            int32_t iteration = 0;
    ++            while ((err = OMX_GetState(mHandle, &state)) == OMX_ErrorNone
    ++                    && state != OMX_StateLoaded
    ++                    && state != OMX_StateInvalid) {
    ++                if (++iteration > kMaxNumIterations) {
    ++                    CLOGW("failed to enter Loaded state (now %s(%d), aborting.",
    ++                            asString(state), state);
    ++                    state = OMX_StateInvalid;
    ++                    break;
    ++                }
    ++
    ++                ALOGV("waiting for Loaded state...");
    ++                usleep(100000);
    ++            }
    ++            CHECK_EQ(err, OMX_ErrorNone);
    ++
    ++            // fall through
    ++        }
    ++
    ++        case OMX_StateLoaded:
    ++        case OMX_StateInvalid:
    ++            break;
    ++
    ++        default:
    ++            LOG_ALWAYS_FATAL("unknown state %s(%#x).", asString(state), state);
    ++            break;
    ++    }
    ++
    ++    ALOGV("[%x:%s] calling destroyComponentInstance", mNodeID, mName);
    ++    OMX_ERRORTYPE err = master->destroyComponentInstance(
    ++            static_cast<OMX_COMPONENTTYPE *>(mHandle));
    ++
    ++    mHandle = NULL;
    ++    CLOG_IF_ERROR(freeNode, err, "");
    ++    free(mName);
    ++    mName = NULL;
    ++
    ++    mOwner->invalidateNodeID(mNodeID);
    ++    mNodeID = 0;
    ++
    ++    ALOGV("OMXNodeInstance going away.");
    ++    delete this;
    ++
    ++    return StatusFromOMXError(err);
    ++}
    ++
    ++status_t OMXNodeInstance::sendCommand(
    ++        OMX_COMMANDTYPE cmd, OMX_S32 param) {
    ++    if (cmd == OMX_CommandStateSet) {
    ++        // There are no configurations past first StateSet command.
    ++        mSailed = true;
    ++    }
    ++    const sp<GraphicBufferSource> bufferSource(getGraphicBufferSource());
    ++    if (bufferSource != NULL && cmd == OMX_CommandStateSet) {
    ++        if (param == OMX_StateIdle) {
    ++            // Initiating transition from Executing -> Idle
    ++            // ACodec is waiting for all buffers to be returned, do NOT
    ++            // submit any more buffers to the codec.
    ++            bufferSource->omxIdle();
    ++        } else if (param == OMX_StateLoaded) {
    ++            // Initiating transition from Idle/Executing -> Loaded
    ++            // Buffers are about to be freed.
    ++            bufferSource->omxLoaded();
    ++            setGraphicBufferSource(NULL);
    ++        }
    ++
    ++        // fall through
    ++    }
    ++
    ++    Mutex::Autolock autoLock(mLock);
    ++
    ++    // bump internal-state debug level for 2 input and output frames past a command
    ++    {
    ++        Mutex::Autolock _l(mDebugLock);
    ++        bumpDebugLevel_l(2 /* numInputBuffers */, 2 /* numOutputBuffers */);
    ++    }
    ++
    ++    const char *paramString =
    ++        cmd == OMX_CommandStateSet ? asString((OMX_STATETYPE)param) : portString(param);
    ++    CLOG_STATE(sendCommand, "%s(%d), %s(%d)", asString(cmd), cmd, paramString, param);
    ++    OMX_ERRORTYPE err = OMX_SendCommand(mHandle, cmd, param, NULL);
    ++    CLOG_IF_ERROR(sendCommand, err, "%s(%d), %s(%d)", asString(cmd), cmd, paramString, param);
    ++    return StatusFromOMXError(err);
    ++}
    ++
    ++bool OMXNodeInstance::isProhibitedIndex_l(OMX_INDEXTYPE index) {
    ++    // these extensions can only be used from OMXNodeInstance, not by clients directly.
    ++    static const char *restricted_extensions[] = {
    ++        "OMX.google.android.index.storeMetaDataInBuffers",
    ++        "OMX.google.android.index.storeANWBufferInMetadata",
    ++        "OMX.google.android.index.prepareForAdaptivePlayback",
    ++        "OMX.google.android.index.configureVideoTunnelMode",
    ++        "OMX.google.android.index.useAndroidNativeBuffer2",
    ++        "OMX.google.android.index.useAndroidNativeBuffer",
    ++        "OMX.google.android.index.enableAndroidNativeBuffers",
    ++        "OMX.google.android.index.allocateNativeHandle",
    ++        "OMX.google.android.index.getAndroidNativeBufferUsage",
    ++    };
    ++
    ++    if ((index > OMX_IndexComponentStartUnused && index <= OMX_IndexParamStandardComponentRole)
    ++            || (index > OMX_IndexPortStartUnused && index <= OMX_IndexParamCompBufferSupplier)
    ++            || (index > OMX_IndexAudioStartUnused && index <= OMX_IndexConfigAudioChannelVolume)
    ++            || (index > OMX_IndexVideoStartUnused && index <= OMX_IndexConfigVideoNalSize)
    ++            || (index > OMX_IndexCommonStartUnused
    ++                    && index <= OMX_IndexConfigCommonTransitionEffect)
    ++            || (index > (OMX_INDEXTYPE)OMX_IndexExtAudioStartUnused
    ++                    && index <= (OMX_INDEXTYPE)OMX_IndexParamAudioProfileQuerySupported)
    ++            || (index > (OMX_INDEXTYPE)OMX_IndexExtVideoStartUnused
    ++                    && index <= (OMX_INDEXTYPE)OMX_IndexConfigAndroidVideoTemporalLayering)
    ++            || (index > (OMX_INDEXTYPE)OMX_IndexExtOtherStartUnused
    ++                    && index <= (OMX_INDEXTYPE)OMX_IndexParamConsumerUsageBits)) {
    ++        return false;
    ++    }
    ++
    ++    if (!mQueriedProhibitedExtensions) {
    ++        for (size_t i = 0; i < NELEM(restricted_extensions); ++i) {
    ++            OMX_INDEXTYPE ext;
    ++            if (OMX_GetExtensionIndex(mHandle, (OMX_STRING)restricted_extensions[i], &ext) == OMX_ErrorNone) {
    ++                mProhibitedExtensions.add(ext);
    ++            }
    ++        }
    ++        mQueriedProhibitedExtensions = true;
    ++    }
    ++
    ++    return mProhibitedExtensions.indexOf(index) >= 0;
    ++}
    ++
    ++status_t OMXNodeInstance::getParameter(
    ++        OMX_INDEXTYPE index, void *params, size_t /* size */) {
    ++    Mutex::Autolock autoLock(mLock);
    ++
    ++    if (isProhibitedIndex_l(index)) {
    ++        android_errorWriteLog(0x534e4554, "29422020");
    ++        return BAD_INDEX;
    ++    }
    ++
    ++    OMX_ERRORTYPE err = OMX_GetParameter(mHandle, index, params);
    ++    OMX_INDEXEXTTYPE extIndex = (OMX_INDEXEXTTYPE)index;
    ++    // some errors are expected for getParameter
    ++    if (err != OMX_ErrorNoMore) {
    ++        CLOG_IF_ERROR(getParameter, err, "%s(%#x)", asString(extIndex), index);
    ++    }
    ++    return StatusFromOMXError(err);
    ++}
    ++
    ++status_t OMXNodeInstance::setParameter(
    ++        OMX_INDEXTYPE index, const void *params, size_t size) {
    ++    Mutex::Autolock autoLock(mLock);
    ++    OMX_INDEXEXTTYPE extIndex = (OMX_INDEXEXTTYPE)index;
    ++    CLOG_CONFIG(setParameter, "%s(%#x), %zu@%p)", asString(extIndex), index, size, params);
    ++
    ++    if (isProhibitedIndex_l(index)) {
    ++        android_errorWriteLog(0x534e4554, "29422020");
    ++        return BAD_INDEX;
    ++    }
    ++
    ++    OMX_ERRORTYPE err = OMX_SetParameter(
    ++            mHandle, index, const_cast<void *>(params));
    ++    CLOG_IF_ERROR(setParameter, err, "%s(%#x)", asString(extIndex), index);
    ++    return StatusFromOMXError(err);
    ++}
    ++
    ++status_t OMXNodeInstance::getConfig(
    ++        OMX_INDEXTYPE index, void *params, size_t /* size */) {
    ++    Mutex::Autolock autoLock(mLock);
    ++
    ++    if (isProhibitedIndex_l(index)) {
    ++        android_errorWriteLog(0x534e4554, "29422020");
    ++        return BAD_INDEX;
    ++    }
    ++
    ++    OMX_ERRORTYPE err = OMX_GetConfig(mHandle, index, params);
    ++    OMX_INDEXEXTTYPE extIndex = (OMX_INDEXEXTTYPE)index;
    ++    // some errors are expected for getConfig
    ++    if (err != OMX_ErrorNoMore) {
    ++        CLOG_IF_ERROR(getConfig, err, "%s(%#x)", asString(extIndex), index);
    ++    }
    ++    return StatusFromOMXError(err);
    ++}
    ++
    ++status_t OMXNodeInstance::setConfig(
    ++        OMX_INDEXTYPE index, const void *params, size_t size) {
    ++    Mutex::Autolock autoLock(mLock);
    ++    OMX_INDEXEXTTYPE extIndex = (OMX_INDEXEXTTYPE)index;
    ++    CLOG_CONFIG(setConfig, "%s(%#x), %zu@%p)", asString(extIndex), index, size, params);
    ++
    ++    if (isProhibitedIndex_l(index)) {
    ++        android_errorWriteLog(0x534e4554, "29422020");
    ++        return BAD_INDEX;
    ++    }
    ++
    ++    OMX_ERRORTYPE err = OMX_SetConfig(
    ++            mHandle, index, const_cast<void *>(params));
    ++    CLOG_IF_ERROR(setConfig, err, "%s(%#x)", asString(extIndex), index);
    ++    return StatusFromOMXError(err);
    ++}
    ++
    ++status_t OMXNodeInstance::getState(OMX_STATETYPE* state) {
    ++    Mutex::Autolock autoLock(mLock);
    ++
    ++    OMX_ERRORTYPE err = OMX_GetState(mHandle, state);
    ++    CLOG_IF_ERROR(getState, err, "");
    ++    return StatusFromOMXError(err);
    ++}
    ++
    ++status_t OMXNodeInstance::enableNativeBuffers(
    ++        OMX_U32 portIndex, OMX_BOOL graphic, OMX_BOOL enable) {
    ++    if (portIndex >= NELEM(mSecureBufferType)) {
    ++        ALOGE("b/31385713, portIndex(%u)", portIndex);
    ++        android_errorWriteLog(0x534e4554, "31385713");
    ++        return BAD_VALUE;
    ++    }
    ++
    ++    Mutex::Autolock autoLock(mLock);
    ++    CLOG_CONFIG(enableNativeBuffers, "%s:%u%s, %d", portString(portIndex), portIndex,
    ++                graphic ? ", graphic" : "", enable);
    ++    OMX_STRING name = const_cast<OMX_STRING>(
    ++            graphic ? "OMX.google.android.index.enableAndroidNativeBuffers"
    ++                    : "OMX.google.android.index.allocateNativeHandle");
    ++
    ++    OMX_INDEXTYPE index;
    ++    OMX_ERRORTYPE err = OMX_GetExtensionIndex(mHandle, name, &index);
    ++
    ++    if (err == OMX_ErrorNone) {
    ++        EnableAndroidNativeBuffersParams params;
    ++        InitOMXParams(&params);
    ++        params.nPortIndex = portIndex;
    ++        params.enable = enable;
    ++
    ++        err = OMX_SetParameter(mHandle, index, &params);
    ++        CLOG_IF_ERROR(setParameter, err, "%s(%#x): %s:%u en=%d", name, index,
    ++                      portString(portIndex), portIndex, enable);
    ++        if (!graphic) {
    ++            if (err == OMX_ErrorNone) {
    ++                mSecureBufferType[portIndex] =
    ++                    enable ? kSecureBufferTypeNativeHandle : kSecureBufferTypeOpaque;
    ++            } else if (mSecureBufferType[portIndex] == kSecureBufferTypeUnknown) {
    ++                mSecureBufferType[portIndex] = kSecureBufferTypeOpaque;
    ++            }
    ++        } else {
    ++            if (err == OMX_ErrorNone) {
    ++                mGraphicBufferEnabled[portIndex] = enable;
    ++            } else if (enable) {
    ++                mGraphicBufferEnabled[portIndex] = false;
    ++            }
    ++        }
    ++    } else {
    ++        CLOG_ERROR_IF(enable, getExtensionIndex, err, "%s", name);
    ++        if (!graphic) {
    ++            // Extension not supported, check for manual override with system property
    ++            // This is a temporary workaround until partners support the OMX extension
    ++            char value[PROPERTY_VALUE_MAX];
    ++            if (property_get("media.mediadrmservice.enable", value, NULL)
    ++                && (!strcmp("1", value) || !strcasecmp("true", value))) {
    ++                CLOG_CONFIG(enableNativeBuffers, "system property override: using native-handles");
    ++                mSecureBufferType[portIndex] = kSecureBufferTypeNativeHandle;
    ++            } else if (mSecureBufferType[portIndex] == kSecureBufferTypeUnknown) {
    ++                mSecureBufferType[portIndex] = kSecureBufferTypeOpaque;
    ++            }
    ++            err = OMX_ErrorNone;
    ++        }
    ++    }
    ++
    ++    return StatusFromOMXError(err);
    ++}
    ++
    ++status_t OMXNodeInstance::getGraphicBufferUsage(
    ++        OMX_U32 portIndex, OMX_U32* usage) {
    ++    Mutex::Autolock autoLock(mLock);
    ++
    ++    OMX_INDEXTYPE index;
    ++    OMX_STRING name = const_cast<OMX_STRING>(
    ++            "OMX.google.android.index.getAndroidNativeBufferUsage");
    ++    OMX_ERRORTYPE err = OMX_GetExtensionIndex(mHandle, name, &index);
    ++
    ++    if (err != OMX_ErrorNone) {
    ++        CLOG_ERROR(getExtensionIndex, err, "%s", name);
    ++        return StatusFromOMXError(err);
    ++    }
    ++
    ++    GetAndroidNativeBufferUsageParams params;
    ++    InitOMXParams(&params);
    ++    params.nPortIndex = portIndex;
    ++
    ++    err = OMX_GetParameter(mHandle, index, &params);
    ++    if (err != OMX_ErrorNone) {
    ++        CLOG_ERROR(getParameter, err, "%s(%#x): %s:%u", name, index,
    ++                portString(portIndex), portIndex);
    ++        return StatusFromOMXError(err);
    ++    }
    ++
    ++    *usage = params.nUsage;
    ++
    ++    return OK;
    ++}
    ++
    ++status_t OMXNodeInstance::storeMetaDataInBuffers(
    ++        OMX_U32 portIndex, OMX_BOOL enable, MetadataBufferType *type) {
    ++    Mutex::Autolock autolock(mLock);
    ++    CLOG_CONFIG(storeMetaDataInBuffers, "%s:%u en:%d", portString(portIndex), portIndex, enable);
    ++    return storeMetaDataInBuffers_l(portIndex, enable, type);
    ++}
    ++
    ++status_t OMXNodeInstance::storeMetaDataInBuffers_l(
    ++        OMX_U32 portIndex, OMX_BOOL enable, MetadataBufferType *type) {
    ++    if (mSailed) {
    ++        android_errorWriteLog(0x534e4554, "29422020");
    ++        return INVALID_OPERATION;
    ++    }
    ++    if (portIndex != kPortIndexInput && portIndex != kPortIndexOutput) {
    ++        android_errorWriteLog(0x534e4554, "26324358");
    ++        if (type != NULL) {
    ++            *type = kMetadataBufferTypeInvalid;
    ++        }
    ++        return BAD_VALUE;
    ++    }
    ++
    ++    OMX_INDEXTYPE index;
    ++    OMX_STRING name = const_cast<OMX_STRING>(
    ++            "OMX.google.android.index.storeMetaDataInBuffers");
    ++
    ++    OMX_STRING nativeBufferName = const_cast<OMX_STRING>(
    ++            "OMX.google.android.index.storeANWBufferInMetadata");
    ++    MetadataBufferType negotiatedType;
    ++    MetadataBufferType requestedType = type != NULL ? *type : kMetadataBufferTypeANWBuffer;
    ++
    ++    StoreMetaDataInBuffersParams params;
    ++    InitOMXParams(&params);
    ++    params.nPortIndex = portIndex;
    ++    params.bStoreMetaData = enable;
    ++
    ++    OMX_ERRORTYPE err =
    ++        requestedType == kMetadataBufferTypeANWBuffer
    ++                ? OMX_GetExtensionIndex(mHandle, nativeBufferName, &index)
    ++                : OMX_ErrorUnsupportedIndex;
    ++    OMX_ERRORTYPE xerr = err;
    ++    if (err == OMX_ErrorNone) {
    ++        err = OMX_SetParameter(mHandle, index, &params);
    ++        if (err == OMX_ErrorNone) {
    ++            name = nativeBufferName; // set name for debugging
    ++            negotiatedType = requestedType;
    ++        }
    ++    }
    ++    if (err != OMX_ErrorNone) {
    ++        err = OMX_GetExtensionIndex(mHandle, name, &index);
    ++        xerr = err;
    ++        if (err == OMX_ErrorNone) {
    ++            negotiatedType =
    ++                requestedType == kMetadataBufferTypeANWBuffer
    ++                        ? kMetadataBufferTypeGrallocSource : requestedType;
    ++            err = OMX_SetParameter(mHandle, index, &params);
    ++        }
    ++    }
    ++
    ++    // don't log loud error if component does not support metadata mode on the output
    ++    if (err != OMX_ErrorNone) {
    ++        if (err == OMX_ErrorUnsupportedIndex && portIndex == kPortIndexOutput) {
    ++            CLOGW("component does not support metadata mode; using fallback");
    ++        } else if (xerr != OMX_ErrorNone) {
    ++            CLOG_ERROR(getExtensionIndex, xerr, "%s", name);
    ++        } else {
    ++            CLOG_ERROR(setParameter, err, "%s(%#x): %s:%u en=%d type=%d", name, index,
    ++                    portString(portIndex), portIndex, enable, negotiatedType);
    ++        }
    ++        negotiatedType = mMetadataType[portIndex];
    ++    } else {
    ++        if (!enable) {
    ++            negotiatedType = kMetadataBufferTypeInvalid;
    ++        }
    ++        mMetadataType[portIndex] = negotiatedType;
    ++    }
    ++    CLOG_CONFIG(storeMetaDataInBuffers, "%s:%u %srequested %s:%d negotiated %s:%d",
    ++            portString(portIndex), portIndex, enable ? "" : "UN",
    ++            asString(requestedType), requestedType, asString(negotiatedType), negotiatedType);
    ++
    ++    if (type != NULL) {
    ++        *type = negotiatedType;
    ++    }
    ++
    ++    return StatusFromOMXError(err);
    ++}
    ++
    ++status_t OMXNodeInstance::prepareForAdaptivePlayback(
    ++        OMX_U32 portIndex, OMX_BOOL enable, OMX_U32 maxFrameWidth,
    ++        OMX_U32 maxFrameHeight) {
    ++    Mutex::Autolock autolock(mLock);
    ++    if (mSailed) {
    ++        android_errorWriteLog(0x534e4554, "29422020");
    ++        return INVALID_OPERATION;
    ++    }
    ++    CLOG_CONFIG(prepareForAdaptivePlayback, "%s:%u en=%d max=%ux%u",
    ++            portString(portIndex), portIndex, enable, maxFrameWidth, maxFrameHeight);
    ++
    ++    OMX_INDEXTYPE index;
    ++    OMX_STRING name = const_cast<OMX_STRING>(
    ++            "OMX.google.android.index.prepareForAdaptivePlayback");
    ++
    ++    OMX_ERRORTYPE err = OMX_GetExtensionIndex(mHandle, name, &index);
    ++    if (err != OMX_ErrorNone) {
    ++        CLOG_ERROR_IF(enable, getExtensionIndex, err, "%s", name);
    ++        return StatusFromOMXError(err);
    ++    }
    ++
    ++    PrepareForAdaptivePlaybackParams params;
    ++    InitOMXParams(&params);
    ++    params.nPortIndex = portIndex;
    ++    params.bEnable = enable;
    ++    params.nMaxFrameWidth = maxFrameWidth;
    ++    params.nMaxFrameHeight = maxFrameHeight;
    ++
    ++    err = OMX_SetParameter(mHandle, index, &params);
    ++    CLOG_IF_ERROR(setParameter, err, "%s(%#x): %s:%u en=%d max=%ux%u", name, index,
    ++            portString(portIndex), portIndex, enable, maxFrameWidth, maxFrameHeight);
    ++    return StatusFromOMXError(err);
    ++}
    ++
    ++status_t OMXNodeInstance::configureVideoTunnelMode(
    ++        OMX_U32 portIndex, OMX_BOOL tunneled, OMX_U32 audioHwSync,
    ++        native_handle_t **sidebandHandle) {
    ++    Mutex::Autolock autolock(mLock);
    ++    if (mSailed) {
    ++        android_errorWriteLog(0x534e4554, "29422020");
    ++        return INVALID_OPERATION;
    ++    }
    ++    CLOG_CONFIG(configureVideoTunnelMode, "%s:%u tun=%d sync=%u",
    ++            portString(portIndex), portIndex, tunneled, audioHwSync);
    ++
    ++    OMX_INDEXTYPE index;
    ++    OMX_STRING name = const_cast<OMX_STRING>(
    ++            "OMX.google.android.index.configureVideoTunnelMode");
    ++
    ++    OMX_ERRORTYPE err = OMX_GetExtensionIndex(mHandle, name, &index);
    ++    if (err != OMX_ErrorNone) {
    ++        CLOG_ERROR_IF(tunneled, getExtensionIndex, err, "%s", name);
    ++        return StatusFromOMXError(err);
    ++    }
    ++
    ++    ConfigureVideoTunnelModeParams tunnelParams;
    ++    InitOMXParams(&tunnelParams);
    ++    tunnelParams.nPortIndex = portIndex;
    ++    tunnelParams.bTunneled = tunneled;
    ++    tunnelParams.nAudioHwSync = audioHwSync;
    ++    err = OMX_SetParameter(mHandle, index, &tunnelParams);
    ++    if (err != OMX_ErrorNone) {
    ++        CLOG_ERROR(setParameter, err, "%s(%#x): %s:%u tun=%d sync=%u", name, index,
    ++                portString(portIndex), portIndex, tunneled, audioHwSync);
    ++        return StatusFromOMXError(err);
    ++    }
    ++
    ++    err = OMX_GetParameter(mHandle, index, &tunnelParams);
    ++    if (err != OMX_ErrorNone) {
    ++        CLOG_ERROR(getParameter, err, "%s(%#x): %s:%u tun=%d sync=%u", name, index,
    ++                portString(portIndex), portIndex, tunneled, audioHwSync);
    ++        return StatusFromOMXError(err);
    ++    }
    ++    if (sidebandHandle) {
    ++        *sidebandHandle = (native_handle_t*)tunnelParams.pSidebandWindow;
    ++    }
    ++
    ++    return OK;
    ++}
    ++
    ++status_t OMXNodeInstance::useBuffer(
    ++        OMX_U32 portIndex, const sp<IMemory> &params,
    ++        OMX::buffer_id *buffer, OMX_U32 allottedSize) {
    ++    if (params == NULL || buffer == NULL) {
    ++        ALOGE("b/25884056");
    ++        return BAD_VALUE;
    ++    }
    ++
    ++    Mutex::Autolock autoLock(mLock);
    ++    if (allottedSize > params->size() || portIndex >= NELEM(mNumPortBuffers)) {
    ++        return BAD_VALUE;
    ++    }
    ++
    ++    if (!mSailed) {
    ++        ALOGE("b/35467458");
    ++        android_errorWriteLog(0x534e4554, "35467458");
    ++        return BAD_VALUE;
    ++    }
    ++
    ++<<<<<<< HEAD
    ++    // metadata buffers are not connected cross process
    ++    // use a backup buffer instead of the actual buffer
    ++    BufferMeta *buffer_meta;
    ++#ifdef CAMCORDER_GRALLOC_SOURCE
    ++    bool useBackup = false;
    ++#else
    ++    bool useBackup = mMetadataType[portIndex] != kMetadataBufferTypeInvalid;
    ++#endif
    ++    OMX_U8 *data = static_cast<OMX_U8 *>(params->pointer());
    ++    // allocate backup buffer
    ++    if (useBackup) {
    ++        data = new (std::nothrow) OMX_U8[allottedSize];
    ++        if (data == NULL) {
    ++            return NO_MEMORY;
    ++=======
    ++    switch (omxBuffer.mBufferType) {
    ++        case OMXBuffer::kBufferTypePreset:
    ++            return useBuffer_l(portIndex, NULL, NULL, buffer);
    ++
    ++        case OMXBuffer::kBufferTypeSharedMem:
    ++            return useBuffer_l(portIndex, omxBuffer.mMem, NULL, buffer);
    ++
    ++        case OMXBuffer::kBufferTypeANWBuffer:
    ++            return useGraphicBuffer_l(portIndex, omxBuffer.mGraphicBuffer, buffer);
    ++
    ++        case OMXBuffer::kBufferTypeHidlMemory: {
    ++                sp<IHidlMemory> hidlMemory = mapMemory(omxBuffer.mHidlMemory);
    ++                return useBuffer_l(portIndex, NULL, hidlMemory, buffer);
    ++            }
    ++        default:
    ++            break;
    ++    }
    ++
    ++    return BAD_VALUE;
    ++}
    ++
    ++status_t OMXNodeInstance::useBuffer_l(
    ++        OMX_U32 portIndex, const sp<IMemory> &params,
    ++        const sp<IHidlMemory> &hParams, IOMX::buffer_id *buffer) {
    ++
    ++    BufferMeta *buffer_meta;
    ++    OMX_BUFFERHEADERTYPE *header;
    ++    OMX_ERRORTYPE err = OMX_ErrorNone;
    ++    bool isMetadata = mMetadataType[portIndex] != kMetadataBufferTypeInvalid;
    ++
    ++    if (!isMetadata && mGraphicBufferEnabled[portIndex]) {
    ++        ALOGE("b/62948670");
    ++        android_errorWriteLog(0x534e4554, "62948670");
    ++        return INVALID_OPERATION;
    ++    }
    ++
    ++    size_t paramsSize;
    ++    void* paramsPointer;
    ++    if (params != NULL && hParams != NULL) {
    ++        return BAD_VALUE;
    ++    }
    ++    if (params != NULL) {
    ++        paramsPointer = params->pointer();
    ++        paramsSize = params->size();
    ++    } else if (hParams != NULL) {
    ++        paramsPointer = hParams->getPointer();
    ++        paramsSize = hParams->getSize();
    ++    } else {
    ++        paramsPointer = nullptr;
    ++    }
    ++
    ++    OMX_U32 allottedSize;
    ++    if (isMetadata) {
    ++        if (mMetadataType[portIndex] == kMetadataBufferTypeGrallocSource) {
    ++            allottedSize = sizeof(VideoGrallocMetadata);
    ++        } else if (mMetadataType[portIndex] == kMetadataBufferTypeANWBuffer) {
    ++            allottedSize = sizeof(VideoNativeMetadata);
    ++        } else if (mMetadataType[portIndex] == kMetadataBufferTypeNativeHandleSource) {
    ++            allottedSize = sizeof(VideoNativeHandleMetadata);
    ++        } else {
    ++            return BAD_VALUE;
    ++>>>>>>> f630233... Track graphic buffer mode in OMXNodeInstance
    ++        }
    ++        memset(data, 0, allottedSize);
    ++
    ++        buffer_meta = new BufferMeta(
    ++                params, portIndex, false /* copyToOmx */, false /* copyFromOmx */, data);
    ++    } else {
    ++        buffer_meta = new BufferMeta(
    ++                params, portIndex, false /* copyToOmx */, false /* copyFromOmx */, NULL);
    ++    }
    ++
    ++    OMX_BUFFERHEADERTYPE *header;
    ++
    ++    OMX_ERRORTYPE err = OMX_UseBuffer(
    ++            mHandle, &header, portIndex, buffer_meta,
    ++            allottedSize, data);
    ++
    ++    if (err != OMX_ErrorNone) {
    ++        CLOG_ERROR(useBuffer, err, SIMPLE_BUFFER(
    ++                portIndex, (size_t)allottedSize, data));
    ++
    ++        delete buffer_meta;
    ++        buffer_meta = NULL;
    ++
    ++        *buffer = 0;
    ++
    ++        return StatusFromOMXError(err);
    ++    }
    ++
    ++    CHECK_EQ(header->pAppPrivate, buffer_meta);
    ++
    ++    *buffer = makeBufferID(header);
    ++
    ++    addActiveBuffer(portIndex, *buffer);
    ++
    ++    sp<GraphicBufferSource> bufferSource(getGraphicBufferSource());
    ++    if (bufferSource != NULL && portIndex == kPortIndexInput) {
    ++        bufferSource->addCodecBuffer(header);
    ++    }
    ++
    ++    CLOG_BUFFER(useBuffer, NEW_BUFFER_FMT(
    ++            *buffer, portIndex, "%u(%zu)@%p", allottedSize, params->size(), params->pointer()));
    ++    return OK;
    ++}
    ++
    ++status_t OMXNodeInstance::useGraphicBuffer2_l(
    ++        OMX_U32 portIndex, const sp<GraphicBuffer>& graphicBuffer,
    ++        OMX::buffer_id *buffer) {
    ++    if (graphicBuffer == NULL || buffer == NULL) {
    ++        ALOGE("b/25884056");
    ++        return BAD_VALUE;
    ++    }
    ++
    ++    // port definition
    ++    OMX_PARAM_PORTDEFINITIONTYPE def;
    ++    InitOMXParams(&def);
    ++    def.nPortIndex = portIndex;
    ++    OMX_ERRORTYPE err = OMX_GetParameter(mHandle, OMX_IndexParamPortDefinition, &def);
    ++    if (err != OMX_ErrorNone) {
    ++        OMX_INDEXTYPE index = OMX_IndexParamPortDefinition;
    ++        CLOG_ERROR(getParameter, err, "%s(%#x): %s:%u",
    ++                asString(index), index, portString(portIndex), portIndex);
    ++        return UNKNOWN_ERROR;
    ++    }
    ++
    ++    BufferMeta *bufferMeta = new BufferMeta(graphicBuffer, portIndex);
    ++
    ++    OMX_BUFFERHEADERTYPE *header = NULL;
    ++    OMX_U8* bufferHandle = const_cast<OMX_U8*>(
    ++            reinterpret_cast<const OMX_U8*>(graphicBuffer->handle));
    ++
    ++    err = OMX_UseBuffer(
    ++            mHandle,
    ++            &header,
    ++            portIndex,
    ++            bufferMeta,
    ++            def.nBufferSize,
    ++            bufferHandle);
    ++
    ++    if (err != OMX_ErrorNone) {
    ++        CLOG_ERROR(useBuffer, err, BUFFER_FMT(portIndex, "%u@%p", def.nBufferSize, bufferHandle));
    ++        delete bufferMeta;
    ++        bufferMeta = NULL;
    ++        *buffer = 0;
    ++        return StatusFromOMXError(err);
    ++    }
    ++
    ++    CHECK_EQ(header->pBuffer, bufferHandle);
    ++    CHECK_EQ(header->pAppPrivate, bufferMeta);
    ++
    ++    *buffer = makeBufferID(header);
    ++
    ++    addActiveBuffer(portIndex, *buffer);
    ++    CLOG_BUFFER(useGraphicBuffer2, NEW_BUFFER_FMT(
    ++            *buffer, portIndex, "%u@%p", def.nBufferSize, bufferHandle));
    ++    return OK;
    ++}
    ++
    ++// XXX: This function is here for backwards compatibility.  Once the OMX
    ++// implementations have been updated this can be removed and useGraphicBuffer2
    ++// can be renamed to useGraphicBuffer.
    ++status_t OMXNodeInstance::useGraphicBuffer(
    ++        OMX_U32 portIndex, const sp<GraphicBuffer>& graphicBuffer,
    ++        OMX::buffer_id *buffer) {
    ++    if (graphicBuffer == NULL || buffer == NULL) {
    ++        ALOGE("b/25884056");
    ++        return BAD_VALUE;
    ++    }
    ++    Mutex::Autolock autoLock(mLock);
    ++
    ++    if (!mGraphicBufferEnabled[portIndex]) {
    ++        // Report error if this is not in graphic buffer mode.
    ++        ALOGE("b/62948670");
    ++        android_errorWriteLog(0x534e4554, "62948670");
    ++        return INVALID_OPERATION;
    ++    }
    ++
    ++    // See if the newer version of the extension is present.
    ++    OMX_INDEXTYPE index;
    ++    if (OMX_GetExtensionIndex(
    ++            mHandle,
    ++            const_cast<OMX_STRING>("OMX.google.android.index.useAndroidNativeBuffer2"),
    ++            &index) == OMX_ErrorNone) {
    ++        return useGraphicBuffer2_l(portIndex, graphicBuffer, buffer);
    ++    }
    ++
    ++    OMX_STRING name = const_cast<OMX_STRING>(
    ++        "OMX.google.android.index.useAndroidNativeBuffer");
    ++    OMX_ERRORTYPE err = OMX_GetExtensionIndex(mHandle, name, &index);
    ++    if (err != OMX_ErrorNone) {
    ++        CLOG_ERROR(getExtensionIndex, err, "%s", name);
    ++        return StatusFromOMXError(err);
    ++    }
    ++
    ++    BufferMeta *bufferMeta = new BufferMeta(graphicBuffer, portIndex);
    ++
    ++    OMX_BUFFERHEADERTYPE *header;
    ++
    ++    OMX_VERSIONTYPE ver;
    ++    ver.s.nVersionMajor = 1;
    ++    ver.s.nVersionMinor = 0;
    ++    ver.s.nRevision = 0;
    ++    ver.s.nStep = 0;
    ++    UseAndroidNativeBufferParams params = {
    ++        sizeof(UseAndroidNativeBufferParams), ver, portIndex, bufferMeta,
    ++        &header, graphicBuffer,
    ++    };
    ++
    ++    err = OMX_SetParameter(mHandle, index, &params);
    ++
    ++    if (err != OMX_ErrorNone) {
    ++        CLOG_ERROR(setParameter, err, "%s(%#x): %s:%u meta=%p GB=%p", name, index,
    ++                portString(portIndex), portIndex, bufferMeta, graphicBuffer->handle);
    ++
    ++        delete bufferMeta;
    ++        bufferMeta = NULL;
    ++
    ++        *buffer = 0;
    ++
    ++        return StatusFromOMXError(err);
    ++    }
    ++
    ++    CHECK_EQ(header->pAppPrivate, bufferMeta);
    ++
    ++    *buffer = makeBufferID(header);
    ++
    ++    addActiveBuffer(portIndex, *buffer);
    ++    CLOG_BUFFER(useGraphicBuffer, NEW_BUFFER_FMT(
    ++            *buffer, portIndex, "GB=%p", graphicBuffer->handle));
    ++    return OK;
    ++}
    ++
    ++status_t OMXNodeInstance::updateGraphicBufferInMeta_l(
    ++        OMX_U32 portIndex, const sp<GraphicBuffer>& graphicBuffer,
    ++        OMX::buffer_id buffer, OMX_BUFFERHEADERTYPE *header, bool updateCodecBuffer) {
    ++    // No need to check |graphicBuffer| since NULL is valid for it as below.
    ++    if (header == NULL) {
    ++        ALOGE("b/25884056");
    ++        return BAD_VALUE;
    ++    }
    ++
    ++    if (portIndex != kPortIndexInput && portIndex != kPortIndexOutput) {
    ++        return BAD_VALUE;
    ++    }
    ++
    ++    BufferMeta *bufferMeta = (BufferMeta *)(header->pAppPrivate);
    ++    sp<ABuffer> data = bufferMeta->getBuffer(
    ++            header, !updateCodecBuffer /* backup */, false /* limit */);
    ++    bufferMeta->setGraphicBuffer(graphicBuffer);
    ++    MetadataBufferType metaType = mMetadataType[portIndex];
    ++    // we use gralloc source only in the codec buffers
    ++    if (metaType == kMetadataBufferTypeGrallocSource && !updateCodecBuffer) {
    ++        metaType = kMetadataBufferTypeANWBuffer;
    ++    }
    ++    if (metaType == kMetadataBufferTypeGrallocSource
    ++            && data->capacity() >= sizeof(VideoGrallocMetadata)) {
    ++        VideoGrallocMetadata &metadata = *(VideoGrallocMetadata *)(data->data());
    ++        metadata.eType = kMetadataBufferTypeGrallocSource;
    ++        metadata.pHandle = graphicBuffer == NULL ? NULL : graphicBuffer->handle;
    ++    } else if (metaType == kMetadataBufferTypeANWBuffer
    ++            && data->capacity() >= sizeof(VideoNativeMetadata)) {
    ++        VideoNativeMetadata &metadata = *(VideoNativeMetadata *)(data->data());
    ++        metadata.eType = kMetadataBufferTypeANWBuffer;
    ++        metadata.pBuffer = graphicBuffer == NULL ? NULL : graphicBuffer->getNativeBuffer();
    ++        metadata.nFenceFd = -1;
    ++    } else {
    ++        CLOG_ERROR(updateGraphicBufferInMeta, BAD_VALUE, "%s:%u, %#x bad type (%d) or size (%u)",
    ++            portString(portIndex), portIndex, buffer, mMetadataType[portIndex], header->nAllocLen);
    ++        return BAD_VALUE;
    ++    }
    ++
    ++    CLOG_BUFFER(updateGraphicBufferInMeta, "%s:%u, %#x := %p",
    ++            portString(portIndex), portIndex, buffer,
    ++            graphicBuffer == NULL ? NULL : graphicBuffer->handle);
    ++    return OK;
    ++}
    ++
    ++status_t OMXNodeInstance::updateGraphicBufferInMeta(
    ++        OMX_U32 portIndex, const sp<GraphicBuffer>& graphicBuffer,
    ++        OMX::buffer_id buffer) {
    ++    Mutex::Autolock autoLock(mLock);
    ++    OMX_BUFFERHEADERTYPE *header = findBufferHeader(buffer, portIndex);
    ++    // update backup buffer for input, codec buffer for output
    ++    return updateGraphicBufferInMeta_l(
    ++            portIndex, graphicBuffer, buffer, header,
    ++            true /* updateCodecBuffer */);
    ++}
    ++
    ++status_t OMXNodeInstance::updateNativeHandleInMeta(
    ++        OMX_U32 portIndex, const sp<NativeHandle>& nativeHandle, OMX::buffer_id buffer) {
    ++    Mutex::Autolock autoLock(mLock);
    ++    OMX_BUFFERHEADERTYPE *header = findBufferHeader(buffer, portIndex);
    ++    // No need to check |nativeHandle| since NULL is valid for it as below.
    ++    if (header == NULL) {
    ++        ALOGE("b/25884056");
    ++        return BAD_VALUE;
    ++    }
    ++
    ++    if (portIndex != kPortIndexInput && portIndex != kPortIndexOutput) {
    ++        return BAD_VALUE;
    ++    }
    ++
    ++    BufferMeta *bufferMeta = (BufferMeta *)(header->pAppPrivate);
    ++    // update backup buffer
    ++    sp<ABuffer> data = bufferMeta->getBuffer(
    ++            header, false /* backup */, false /* limit */);
    ++    bufferMeta->setNativeHandle(nativeHandle);
    ++    if (mMetadataType[portIndex] == kMetadataBufferTypeNativeHandleSource
    ++            && data->capacity() >= sizeof(VideoNativeHandleMetadata)) {
    ++        VideoNativeHandleMetadata &metadata = *(VideoNativeHandleMetadata *)(data->data());
    ++        metadata.eType = mMetadataType[portIndex];
    ++        metadata.pHandle =
    ++            nativeHandle == NULL ? NULL : const_cast<native_handle*>(nativeHandle->handle());
    ++    } else {
    ++        CLOG_ERROR(updateNativeHandleInMeta, BAD_VALUE, "%s:%u, %#x bad type (%d) or size (%zu)",
    ++            portString(portIndex), portIndex, buffer, mMetadataType[portIndex], data->capacity());
    ++        return BAD_VALUE;
    ++    }
    ++
    ++    CLOG_BUFFER(updateNativeHandleInMeta, "%s:%u, %#x := %p",
    ++            portString(portIndex), portIndex, buffer,
    ++            nativeHandle == NULL ? NULL : nativeHandle->handle());
    ++    return OK;
    ++}
    ++
    ++status_t OMXNodeInstance::createGraphicBufferSource(
    ++        OMX_U32 portIndex, sp<IGraphicBufferConsumer> bufferConsumer, MetadataBufferType *type) {
    ++    status_t err;
    ++
    ++    // only allow graphic source on input port, when there are no allocated buffers yet
    ++    if (portIndex != kPortIndexInput) {
    ++        android_errorWriteLog(0x534e4554, "29422020");
    ++        return BAD_VALUE;
    ++    } else if (mNumPortBuffers[portIndex] > 0) {
    ++        android_errorWriteLog(0x534e4554, "29422020");
    ++        return INVALID_OPERATION;
    ++    }
    ++
    ++    const sp<GraphicBufferSource> surfaceCheck = getGraphicBufferSource();
    ++    if (surfaceCheck != NULL) {
    ++        if (portIndex < NELEM(mMetadataType) && type != NULL) {
    ++            *type = mMetadataType[portIndex];
     +        }
    ++        return ALREADY_EXISTS;
     +    }
     +
    -     List<BufferInfo *> &inQueue = getPortQueue(kInputPortIndex);
    -     List<BufferInfo *> &outQueue = getPortQueue(kOutputPortIndex);
    - 
    -@@ -642,7 +662,9 @@ void SoftMPEG2::onQueueFilled(OMX_U32 portIndex) {
    -             bool portWillReset = false;
    -             handlePortSettingsChange(&portWillReset, mNewWidth, mNewHeight);
    - 
    --            CHECK_EQ(reInitDecoder(), (status_t)OK);
    -+            if (OK != reInitDecoder()) {
    -+                ALOGE("Failed to reinitialize decoder");
    -+            }
    -             return;
    -         }
    - 
    -@@ -715,7 +737,10 @@ void SoftMPEG2::onQueueFilled(OMX_U32 portIndex) {
    -                 bool portWillReset = false;
    -                 handlePortSettingsChange(&portWillReset, s_dec_op.u4_pic_wd, s_dec_op.u4_pic_ht);
    - 
    --                CHECK_EQ(reInitDecoder(), (status_t)OK);
    -+                if (OK != reInitDecoder()) {
    -+                    ALOGE("Failed to reinitialize decoder");
    -+                    return;
    -+                }
    - 
    -                 if (setDecodeArgs(&s_dec_ip, &s_dec_op, inHeader, outHeader, timeStampIx)) {
    -                     ivdec_api_function(mCodecCtx, (void *)&s_dec_ip, (void *)&s_dec_op);
    -@@ -768,10 +793,15 @@ void SoftMPEG2::onQueueFilled(OMX_U32 portIndex) {
    -             }
    - 
    -             if (s_dec_op.u4_output_present) {
    --                size_t timeStampIdx;
    -+                ssize_t timeStampIdx;
    -                 outHeader->nFilledLen = (mWidth * mHeight * 3) / 2;
    - 
    -                 timeStampIdx = getMinTimestampIdx(mTimeStamps, mTimeStampsValid);
    -+                if (timeStampIdx < 0) {
    -+                    ALOGE("b/62872863, Invalid timestamp index!");
    -+                    android_errorWriteLog(0x534e4554, "62872863");
    -+                    return;
    -+                }
    -                 outHeader->nTimeStamp = mTimeStamps[timeStampIdx];
    -                 mTimeStampsValid[timeStampIdx] = false;
    - 
    -diff --git a/media/libstagefright/codecs/mpeg2dec/SoftMPEG2.h b/media/libstagefright/codecs/mpeg2dec/SoftMPEG2.h
    -index 700ef5f..1285c5b 100644
    ---- a/media/libstagefright/codecs/mpeg2dec/SoftMPEG2.h
    -+++ b/media/libstagefright/codecs/mpeg2dec/SoftMPEG2.h
    -@@ -106,6 +106,7 @@ private:
    -     // codec. So the codec is switching to decode the new resolution.
    -     bool mChangingResolution;
    -     bool mFlushNeeded;
    -+    bool mSignalledError;
    -     bool mWaitForI;
    -     size_t mStride;
    - 
    -diff --git a/media/libstagefright/foundation/MediaBufferGroup.cpp b/media/libstagefright/foundation/MediaBufferGroup.cpp
    -index 8e4d064..66992d7 100644
    ---- a/media/libstagefright/foundation/MediaBufferGroup.cpp
    -+++ b/media/libstagefright/foundation/MediaBufferGroup.cpp
    -@@ -105,6 +105,11 @@ MediaBufferGroup::~MediaBufferGroup() {
    -     }
    - }
    - 
    -+extern "C" int _ZN7android16MediaBufferGroupC1Ej(unsigned int);
    -+extern "C" int _ZN7android16MediaBufferGroupC1Ev() {
    -+    return _ZN7android16MediaBufferGroupC1Ej(0);
    ++    // Input buffers will hold meta-data (ANativeWindowBuffer references).
    ++    if (type != NULL) {
    ++        *type = kMetadataBufferTypeANWBuffer;
    ++    }
    ++    err = storeMetaDataInBuffers_l(portIndex, OMX_TRUE, type);
    ++    if (err != OK) {
    ++        return err;
    ++    }
    ++
    ++    // Retrieve the width and height of the graphic buffer, set when the
    ++    // codec was configured.
    ++    OMX_PARAM_PORTDEFINITIONTYPE def;
    ++    InitOMXParams(&def);
    ++    def.nPortIndex = portIndex;
    ++    OMX_ERRORTYPE oerr = OMX_GetParameter(
    ++            mHandle, OMX_IndexParamPortDefinition, &def);
    ++    if (oerr != OMX_ErrorNone) {
    ++        OMX_INDEXTYPE index = OMX_IndexParamPortDefinition;
    ++        CLOG_ERROR(getParameter, oerr, "%s(%#x): %s:%u",
    ++                asString(index), index, portString(portIndex), portIndex);
    ++        return UNKNOWN_ERROR;
    ++    }
    ++
    ++    if (def.format.video.eColorFormat != OMX_COLOR_FormatAndroidOpaque) {
    ++        CLOGW("createInputSurface requires COLOR_FormatSurface "
    ++                "(AndroidOpaque) color format instead of %s(%#x)",
    ++                asString(def.format.video.eColorFormat), def.format.video.eColorFormat);
    ++        return INVALID_OPERATION;
    ++    }
    ++
    ++    uint32_t usageBits;
    ++    oerr = OMX_GetParameter(
    ++            mHandle, (OMX_INDEXTYPE)OMX_IndexParamConsumerUsageBits, &usageBits);
    ++    if (oerr != OMX_ErrorNone) {
    ++        usageBits = 0;
    ++    }
    ++
    ++    sp<GraphicBufferSource> bufferSource = new GraphicBufferSource(this,
    ++            def.format.video.nFrameWidth,
    ++            def.format.video.nFrameHeight,
    ++            def.nBufferCountActual,
    ++            usageBits,
    ++            bufferConsumer);
    ++
    ++    if ((err = bufferSource->init()) != OK) {
    ++        return err;
    ++    }
    ++    setGraphicBufferSource(bufferSource);
    ++
    ++    return OK;
     +}
     +
    - void MediaBufferGroup::add_buffer(MediaBuffer *buffer) {
    -     Mutex::Autolock autoLock(mLock);
    - 
    -@@ -198,6 +203,16 @@ status_t MediaBufferGroup::acquire_buffer(
    -     // Never gets here.
    - }
    - 
    -+status_t MediaBufferGroup::acquire_buffer(
    -+       MediaBuffer **out) {
    -+   return acquire_buffer(out, false, 0);
    ++status_t OMXNodeInstance::createInputSurface(
    ++        OMX_U32 portIndex, android_dataspace dataSpace,
    ++        sp<IGraphicBufferProducer> *bufferProducer, MetadataBufferType *type) {
    ++    if (bufferProducer == NULL) {
    ++        ALOGE("b/25884056");
    ++        return BAD_VALUE;
    ++    }
    ++
    ++    Mutex::Autolock autolock(mLock);
    ++    status_t err = createGraphicBufferSource(portIndex, NULL /* bufferConsumer */, type);
    ++
    ++    if (err != OK) {
    ++        return err;
    ++    }
    ++
    ++    mGraphicBufferSource->setDefaultDataSpace(dataSpace);
    ++
    ++    *bufferProducer = mGraphicBufferSource->getIGraphicBufferProducer();
    ++    return OK;
     +}
     +
    -+status_t MediaBufferGroup::acquire_buffer(
    -+        MediaBuffer **out, bool nonBlocking) {
    -+    return acquire_buffer(out, nonBlocking, 0);
    ++//static
    ++status_t OMXNodeInstance::createPersistentInputSurface(
    ++        sp<IGraphicBufferProducer> *bufferProducer,
    ++        sp<IGraphicBufferConsumer> *bufferConsumer) {
    ++    if (bufferProducer == NULL || bufferConsumer == NULL) {
    ++        ALOGE("b/25884056");
    ++        return BAD_VALUE;
    ++    }
    ++    String8 name("GraphicBufferSource");
    ++
    ++    sp<IGraphicBufferProducer> producer;
    ++    sp<IGraphicBufferConsumer> consumer;
    ++    BufferQueue::createBufferQueue(&producer, &consumer);
    ++    consumer->setConsumerName(name);
    ++    consumer->setConsumerUsageBits(GRALLOC_USAGE_HW_VIDEO_ENCODER);
    ++
    ++    sp<BufferQueue::ProxyConsumerListener> proxy =
    ++        new BufferQueue::ProxyConsumerListener(NULL);
    ++    status_t err = consumer->consumerConnect(proxy, false);
    ++    if (err != NO_ERROR) {
    ++        ALOGE("Error connecting to BufferQueue: %s (%d)",
    ++                strerror(-err), err);
    ++        return err;
    ++    }
    ++
    ++    *bufferProducer = producer;
    ++    *bufferConsumer = consumer;
    ++
    ++    return OK;
     +}
     +
    - void MediaBufferGroup::signalBufferReturned(MediaBuffer *) {
    -     mCondition.signal();
    - }
    -diff --git a/media/libstagefright/foundation/base64.cpp b/media/libstagefright/foundation/base64.cpp
    -index 7da7db9..cc89064 100644
    ---- a/media/libstagefright/foundation/base64.cpp
    -+++ b/media/libstagefright/foundation/base64.cpp
    -@@ -78,8 +78,7 @@ sp<ABuffer> decodeBase64(const AString &s) {
    -         accum = (accum << 6) | value;
    - 
    -         if (((i + 1) % 4) == 0) {
    --            out[j++] = (accum >> 16);
    --
    -+            if (j < outLen) { out[j++] = (accum >> 16); }
    -             if (j < outLen) { out[j++] = (accum >> 8) & 0xff; }
    -             if (j < outLen) { out[j++] = accum & 0xff; }
    - 
    -diff --git a/media/libstagefright/httplive/LiveSession.cpp b/media/libstagefright/httplive/LiveSession.cpp
    -index 7abc019..590146d 100644
    ---- a/media/libstagefright/httplive/LiveSession.cpp
    -+++ b/media/libstagefright/httplive/LiveSession.cpp
    -@@ -157,6 +157,11 @@ bool LiveSession::BandwidthEstimator::estimateBandwidth(
    -     }
    - 
    -     *bandwidthBps = ((double)mTotalTransferBytes * 8E6 / mTotalTransferTimeUs);
    -+    static const int32_t kMaxBandwidthBps = 0x7fffffff / 7;
    -+    if (*bandwidthBps > kMaxBandwidthBps) {
    -+        ALOGW("Override bandwidth because it's too huge. %d -> %d", *bandwidthBps, kMaxBandwidthBps);
    -+        *bandwidthBps = kMaxBandwidthBps;
    ++status_t OMXNodeInstance::setInputSurface(
    ++        OMX_U32 portIndex, const sp<IGraphicBufferConsumer> &bufferConsumer,
    ++        MetadataBufferType *type) {
    ++    Mutex::Autolock autolock(mLock);
    ++    return createGraphicBufferSource(portIndex, bufferConsumer, type);
    ++}
    ++
    ++void OMXNodeInstance::signalEvent(OMX_EVENTTYPE event, OMX_U32 arg1, OMX_U32 arg2) {
    ++    mOwner->OnEvent(mNodeID, event, arg1, arg2, NULL);
    ++}
    ++
    ++status_t OMXNodeInstance::signalEndOfInputStream() {
    ++    // For non-Surface input, the MediaCodec should convert the call to a
    ++    // pair of requests (dequeue input buffer, queue input buffer with EOS
    ++    // flag set).  Seems easier than doing the equivalent from here.
    ++    sp<GraphicBufferSource> bufferSource(getGraphicBufferSource());
    ++    if (bufferSource == NULL) {
    ++        CLOGW("signalEndOfInputStream can only be used with Surface input");
    ++        return INVALID_OPERATION;
     +    }
    -     mPrevEstimates.push_back(*bandwidthBps);
    -     while (mPrevEstimates.size() > 3) {
    -         mPrevEstimates.erase(mPrevEstimates.begin());
    -diff --git a/media/libstagefright/mpeg2ts/ESQueue.cpp b/media/libstagefright/mpeg2ts/ESQueue.cpp
    -index 96ca405..7599c13 100644
    ---- a/media/libstagefright/mpeg2ts/ESQueue.cpp
    -+++ b/media/libstagefright/mpeg2ts/ESQueue.cpp
    -@@ -716,6 +716,11 @@ sp<ABuffer> ElementaryStreamQueue::dequeueAccessUnitAAC() {
    -         bits.skipBits(2);
    - 
    -         unsigned aac_frame_length = bits.getBits(13);
    -+        if (aac_frame_length == 0){
    -+            ALOGE("b/62673179, Invalid AAC frame length!");
    -+            android_errorWriteLog(0x534e4554, "62673179");
    -+            return NULL;
    -+        }
    - 
    -         bits.skipBits(11);  // adts_buffer_fullness
    - 
    -diff --git a/media/libstagefright/omx/Android.mk b/media/libstagefright/omx/Android.mk
    -index e4fbd81..8fc788f 100644
    ---- a/media/libstagefright/omx/Android.mk
    -+++ b/media/libstagefright/omx/Android.mk
    -@@ -31,6 +31,12 @@ LOCAL_SHARED_LIBRARIES :=               \
    -         libstagefright_foundation       \
    -         libdl
    - 
    -+ifneq ($(TARGET_USES_MEDIA_EXTENSIONS),true)
    -+ifeq ($(TARGET_HAS_LEGACY_CAMERA_HAL1),true)
    -+LOCAL_CFLAGS += -DCAMCORDER_GRALLOC_SOURCE
    -+endif
    -+endif
    ++    return bufferSource->signalEndOfInputStream();
    ++}
     +
    - LOCAL_MODULE:= libstagefright_omx
    - LOCAL_CFLAGS += -Werror -Wall
    - LOCAL_CLANG := true
    -diff --git a/media/libstagefright/omx/GraphicBufferSource.cpp b/media/libstagefright/omx/GraphicBufferSource.cpp
    -index e1bcd28..5f21eac 100644
    ---- a/media/libstagefright/omx/GraphicBufferSource.cpp
    -+++ b/media/libstagefright/omx/GraphicBufferSource.cpp
    -@@ -736,6 +736,8 @@ bool GraphicBufferSource::repeatLatestBuffer_l() {
    - 
    - void GraphicBufferSource::setLatestBuffer_l(
    -         const BufferItem &item, bool dropped) {
    -+    ALOGV("setLatestBuffer_l");
    ++status_t OMXNodeInstance::allocateSecureBuffer(
    ++        OMX_U32 portIndex, size_t size, OMX::buffer_id *buffer,
    ++        void **buffer_data, sp<NativeHandle> *native_handle) {
    ++    if (buffer == NULL || buffer_data == NULL || native_handle == NULL) {
    ++        ALOGE("b/25884056");
    ++        return BAD_VALUE;
    ++    }
     +
    -     if (mLatestBufferId >= 0) {
    -         if (mBufferUseCount[mLatestBufferId] == 0) {
    -             releaseBuffer(mLatestBufferId, mLatestBufferFrameNum,
    -diff --git a/media/libstagefright/omx/OMXMaster.cpp b/media/libstagefright/omx/OMXMaster.cpp
    -index 6132a2c..7f0d270 100644
    ---- a/media/libstagefright/omx/OMXMaster.cpp
    -+++ b/media/libstagefright/omx/OMXMaster.cpp
    -@@ -69,6 +69,7 @@ OMXMaster::~OMXMaster() {
    - 
    - void OMXMaster::addVendorPlugin() {
    -     addPlugin("libstagefrighthw.so");
    -+    addPlugin("libsomxcore.so");
    - }
    - 
    - void OMXMaster::addPlugin(const char *libname) {
    -diff --git a/media/libstagefright/omx/OMXNodeInstance.cpp b/media/libstagefright/omx/OMXNodeInstance.cpp
    -index e7aaead..8752b4e 100644
    ---- a/media/libstagefright/omx/OMXNodeInstance.cpp
    -+++ b/media/libstagefright/omx/OMXNodeInstance.cpp
    -@@ -801,7 +801,11 @@ status_t OMXNodeInstance::useBuffer(
    -     // metadata buffers are not connected cross process
    -     // use a backup buffer instead of the actual buffer
    -     BufferMeta *buffer_meta;
    -+#ifdef CAMCORDER_GRALLOC_SOURCE
    -+    bool useBackup = false;
    -+#else
    -     bool useBackup = mMetadataType[portIndex] != kMetadataBufferTypeInvalid;
    -+#endif
    -     OMX_U8 *data = static_cast<OMX_U8 *>(params->pointer());
    -     // allocate backup buffer
    -     if (useBackup) {
    -@@ -1297,7 +1301,11 @@ status_t OMXNodeInstance::allocateBufferWithBackup(
    -     }
    - 
    -     // metadata buffers are not connected cross process; only copy if not meta
    ++    if (portIndex >= NELEM(mSecureBufferType)) {
    ++        ALOGE("b/31385713, portIndex(%u)", portIndex);
    ++        android_errorWriteLog(0x534e4554, "31385713");
    ++        return BAD_VALUE;
    ++    }
    ++
    ++    Mutex::Autolock autoLock(mLock);
    ++
    ++    if (!mSailed) {
    ++        ALOGE("b/35467458");
    ++        android_errorWriteLog(0x534e4554, "35467458");
    ++        return BAD_VALUE;
    ++    }
    ++
    ++    BufferMeta *buffer_meta = new BufferMeta(size, portIndex);
    ++
    ++    OMX_BUFFERHEADERTYPE *header;
    ++
    ++    OMX_ERRORTYPE err = OMX_AllocateBuffer(
    ++            mHandle, &header, portIndex, buffer_meta, size);
    ++
    ++    if (err != OMX_ErrorNone) {
    ++        CLOG_ERROR(allocateBuffer, err, BUFFER_FMT(portIndex, "%zu@", size));
    ++        delete buffer_meta;
    ++        buffer_meta = NULL;
    ++
    ++        *buffer = 0;
    ++
    ++        return StatusFromOMXError(err);
    ++    }
    ++
    ++    CHECK_EQ(header->pAppPrivate, buffer_meta);
    ++
    ++    *buffer = makeBufferID(header);
    ++    if (mSecureBufferType[portIndex] == kSecureBufferTypeNativeHandle) {
    ++        *buffer_data = NULL;
    ++        *native_handle = NativeHandle::create(
    ++                (native_handle_t *)header->pBuffer, false /* ownsHandle */);
    ++    } else {
    ++        *buffer_data = header->pBuffer;
    ++        *native_handle = NULL;
    ++    }
    ++
    ++    addActiveBuffer(portIndex, *buffer);
    ++
    ++    sp<GraphicBufferSource> bufferSource(getGraphicBufferSource());
    ++    if (bufferSource != NULL && portIndex == kPortIndexInput) {
    ++        bufferSource->addCodecBuffer(header);
    ++    }
    ++    CLOG_BUFFER(allocateSecureBuffer, NEW_BUFFER_FMT(
    ++            *buffer, portIndex, "%zu@%p:%p", size, *buffer_data,
    ++            *native_handle == NULL ? NULL : (*native_handle)->handle()));
    ++
    ++    return OK;
    ++}
    ++
    ++status_t OMXNodeInstance::allocateBufferWithBackup(
    ++        OMX_U32 portIndex, const sp<IMemory> &params,
    ++        OMX::buffer_id *buffer, OMX_U32 allottedSize) {
    ++    if (params == NULL || buffer == NULL) {
    ++        ALOGE("b/25884056");
    ++        return BAD_VALUE;
    ++    }
    ++
    ++    Mutex::Autolock autoLock(mLock);
    ++    if (allottedSize > params->size() || portIndex >= NELEM(mNumPortBuffers)) {
    ++        return BAD_VALUE;
    ++    }
    ++
    ++    if (!mSailed) {
    ++        ALOGE("b/35467458");
    ++        android_errorWriteLog(0x534e4554, "35467458");
    ++        return BAD_VALUE;
    ++    }
    ++
    ++    // metadata buffers are not connected cross process; only copy if not meta
     +#ifdef CAMCORDER_GRALLOC_SOURCE
     +    bool copy = true;
     +#else
    -     bool copy = mMetadataType[portIndex] == kMetadataBufferTypeInvalid;
    ++    bool copy = mMetadataType[portIndex] == kMetadataBufferTypeInvalid;
     +#endif
    - 
    -     BufferMeta *buffer_meta = new BufferMeta(
    -             params, portIndex,
    -@@ -1415,10 +1423,30 @@ status_t OMXNodeInstance::emptyBuffer(
    -     BufferMeta *buffer_meta =
    -         static_cast<BufferMeta *>(header->pAppPrivate);
    - 
    ++
    ++    BufferMeta *buffer_meta = new BufferMeta(
    ++            params, portIndex,
    ++            (portIndex == kPortIndexInput) && copy /* copyToOmx */,
    ++            (portIndex == kPortIndexOutput) && copy /* copyFromOmx */,
    ++            NULL /* data */);
    ++
    ++    OMX_BUFFERHEADERTYPE *header;
    ++
    ++    OMX_ERRORTYPE err = OMX_AllocateBuffer(
    ++            mHandle, &header, portIndex, buffer_meta, allottedSize);
    ++    if (err != OMX_ErrorNone) {
    ++        CLOG_ERROR(allocateBufferWithBackup, err,
    ++                SIMPLE_BUFFER(portIndex, (size_t)allottedSize, params->pointer()));
    ++        delete buffer_meta;
    ++        buffer_meta = NULL;
    ++
    ++        *buffer = 0;
    ++
    ++        return StatusFromOMXError(err);
    ++    }
    ++
    ++    CHECK_EQ(header->pAppPrivate, buffer_meta);
    ++
    ++    *buffer = makeBufferID(header);
    ++
    ++    addActiveBuffer(portIndex, *buffer);
    ++
    ++    sp<GraphicBufferSource> bufferSource(getGraphicBufferSource());
    ++    if (bufferSource != NULL && portIndex == kPortIndexInput) {
    ++        bufferSource->addCodecBuffer(header);
    ++    }
    ++
    ++    CLOG_BUFFER(allocateBufferWithBackup, NEW_BUFFER_FMT(*buffer, portIndex, "%zu@%p :> %u@%p",
    ++            params->size(), params->pointer(), allottedSize, header->pBuffer));
    ++
    ++    return OK;
    ++}
    ++
    ++status_t OMXNodeInstance::freeBuffer(
    ++        OMX_U32 portIndex, OMX::buffer_id buffer) {
    ++    Mutex::Autolock autoLock(mLock);
    ++    CLOG_BUFFER(freeBuffer, "%s:%u %#x", portString(portIndex), portIndex, buffer);
    ++
    ++    removeActiveBuffer(portIndex, buffer);
    ++
    ++    OMX_BUFFERHEADERTYPE *header = findBufferHeader(buffer, portIndex);
    ++    if (header == NULL) {
    ++        ALOGE("b/25884056");
    ++        return BAD_VALUE;
    ++    }
    ++    BufferMeta *buffer_meta = static_cast<BufferMeta *>(header->pAppPrivate);
    ++
    ++    OMX_ERRORTYPE err = OMX_FreeBuffer(mHandle, portIndex, header);
    ++    CLOG_IF_ERROR(freeBuffer, err, "%s:%u %#x", portString(portIndex), portIndex, buffer);
    ++
    ++    delete buffer_meta;
    ++    buffer_meta = NULL;
    ++    invalidateBufferID(buffer);
    ++
    ++    return StatusFromOMXError(err);
    ++}
    ++
    ++status_t OMXNodeInstance::fillBuffer(OMX::buffer_id buffer, int fenceFd) {
    ++    Mutex::Autolock autoLock(mLock);
    ++
    ++    OMX_BUFFERHEADERTYPE *header = findBufferHeader(buffer, kPortIndexOutput);
    ++    if (header == NULL) {
    ++        ALOGE("b/25884056");
    ++        return BAD_VALUE;
    ++    }
    ++    header->nFilledLen = 0;
    ++    header->nOffset = 0;
    ++    header->nFlags = 0;
    ++
    ++    // meta now owns fenceFd
    ++    status_t res = storeFenceInMeta_l(header, fenceFd, kPortIndexOutput);
    ++    if (res != OK) {
    ++        CLOG_ERROR(fillBuffer::storeFenceInMeta, res, EMPTY_BUFFER(buffer, header, fenceFd));
    ++        return res;
    ++    }
    ++
    ++    {
    ++        Mutex::Autolock _l(mDebugLock);
    ++        mOutputBuffersWithCodec.add(header);
    ++        CLOG_BUMPED_BUFFER(fillBuffer, WITH_STATS(EMPTY_BUFFER(buffer, header, fenceFd)));
    ++    }
    ++
    ++    OMX_ERRORTYPE err = OMX_FillThisBuffer(mHandle, header);
    ++    if (err != OMX_ErrorNone) {
    ++        CLOG_ERROR(fillBuffer, err, EMPTY_BUFFER(buffer, header, fenceFd));
    ++        Mutex::Autolock _l(mDebugLock);
    ++        mOutputBuffersWithCodec.remove(header);
    ++    }
    ++    return StatusFromOMXError(err);
    ++}
    ++
    ++status_t OMXNodeInstance::emptyBuffer(
    ++        OMX::buffer_id buffer,
    ++        OMX_U32 rangeOffset, OMX_U32 rangeLength,
    ++        OMX_U32 flags, OMX_TICKS timestamp, int fenceFd) {
    ++    Mutex::Autolock autoLock(mLock);
    ++
    ++    // no emptybuffer if using input surface
    ++    if (getGraphicBufferSource() != NULL) {
    ++        android_errorWriteLog(0x534e4554, "29422020");
    ++        return INVALID_OPERATION;
    ++    }
    ++
    ++    OMX_BUFFERHEADERTYPE *header = findBufferHeader(buffer, kPortIndexInput);
    ++    if (header == NULL) {
    ++        ALOGE("b/25884056");
    ++        return BAD_VALUE;
    ++    }
    ++    BufferMeta *buffer_meta =
    ++        static_cast<BufferMeta *>(header->pAppPrivate);
    ++
     +#ifndef CAMCORDER_GRALLOC_SOURCE
    -     // set up proper filled length if component is configured for gralloc metadata mode
    -     // ignore rangeOffset in this case (as client may be assuming ANW meta buffers).
    -     if (mMetadataType[kPortIndexInput] == kMetadataBufferTypeGrallocSource) {
    -         header->nFilledLen = rangeLength ? sizeof(VideoGrallocMetadata) : 0;
    ++    // set up proper filled length if component is configured for gralloc metadata mode
    ++    // ignore rangeOffset in this case (as client may be assuming ANW meta buffers).
    ++    if (mMetadataType[kPortIndexInput] == kMetadataBufferTypeGrallocSource) {
    ++        header->nFilledLen = rangeLength ? sizeof(VideoGrallocMetadata) : 0;
     +#else
     +    sp<ABuffer> backup = buffer_meta->getBuffer(header, true /* backup */, false /* limit */);
     +    sp<ABuffer> codec = buffer_meta->getBuffer(header, false /* backup */, false /* limit */);
    @@ -1331,9 +4743,609 @@ index e7aaead..8752b4e 100644
     +        codecMeta.eType = kMetadataBufferTypeGrallocSource;
     +        header->nFilledLen = rangeLength ? sizeof(codecMeta) : 0;
     +#endif
    -         header->nOffset = 0;
    -     } else {
    -         // rangeLength and rangeOffset must be a subset of the allocated data in the buffer.
    ++        header->nOffset = 0;
    ++    } else {
    ++        // rangeLength and rangeOffset must be a subset of the allocated data in the buffer.
    ++        // corner case: we permit rangeOffset == end-of-buffer with rangeLength == 0.
    ++        if (rangeOffset > header->nAllocLen
    ++                || rangeLength > header->nAllocLen - rangeOffset) {
    ++            CLOG_ERROR(emptyBuffer, OMX_ErrorBadParameter, FULL_BUFFER(NULL, header, fenceFd));
    ++            if (fenceFd >= 0) {
    ++                ::close(fenceFd);
    ++            }
    ++            return BAD_VALUE;
    ++        }
    ++        header->nFilledLen = rangeLength;
    ++        header->nOffset = rangeOffset;
    ++
    ++        buffer_meta->CopyToOMX(header);
    ++    }
    ++
    ++    return emptyBuffer_l(header, flags, timestamp, (intptr_t)buffer, fenceFd);
    ++}
    ++
    ++// log queued buffer activity for the next few input and/or output frames
    ++// if logging at internal state level
    ++void OMXNodeInstance::bumpDebugLevel_l(size_t numInputBuffers, size_t numOutputBuffers) {
    ++    if (DEBUG == ADebug::kDebugInternalState) {
    ++        DEBUG_BUMP = ADebug::kDebugAll;
    ++        if (numInputBuffers > 0) {
    ++            mDebugLevelBumpPendingBuffers[kPortIndexInput] = numInputBuffers;
    ++        }
    ++        if (numOutputBuffers > 0) {
    ++            mDebugLevelBumpPendingBuffers[kPortIndexOutput] = numOutputBuffers;
    ++        }
    ++    }
    ++}
    ++
    ++void OMXNodeInstance::unbumpDebugLevel_l(size_t portIndex) {
    ++    if (mDebugLevelBumpPendingBuffers[portIndex]) {
    ++        --mDebugLevelBumpPendingBuffers[portIndex];
    ++    }
    ++    if (!mDebugLevelBumpPendingBuffers[0]
    ++            && !mDebugLevelBumpPendingBuffers[1]) {
    ++        DEBUG_BUMP = DEBUG;
    ++    }
    ++}
    ++
    ++status_t OMXNodeInstance::storeFenceInMeta_l(
    ++        OMX_BUFFERHEADERTYPE *header, int fenceFd, OMX_U32 portIndex) {
    ++    // propagate fence if component supports it; wait for it otherwise
    ++    OMX_U32 metaSize = portIndex == kPortIndexInput ? header->nFilledLen : header->nAllocLen;
    ++    if (mMetadataType[portIndex] == kMetadataBufferTypeANWBuffer
    ++            && metaSize >= sizeof(VideoNativeMetadata)) {
    ++        VideoNativeMetadata &nativeMeta = *(VideoNativeMetadata *)(header->pBuffer);
    ++        if (nativeMeta.nFenceFd >= 0) {
    ++            ALOGE("fence (%d) already exists in meta", nativeMeta.nFenceFd);
    ++            if (fenceFd >= 0) {
    ++                ::close(fenceFd);
    ++            }
    ++            return ALREADY_EXISTS;
    ++        }
    ++        nativeMeta.nFenceFd = fenceFd;
    ++    } else if (fenceFd >= 0) {
    ++        CLOG_BUFFER(storeFenceInMeta, "waiting for fence %d", fenceFd);
    ++        sp<Fence> fence = new Fence(fenceFd);
    ++        return fence->wait(IOMX::kFenceTimeoutMs);
    ++    }
    ++    return OK;
    ++}
    ++
    ++int OMXNodeInstance::retrieveFenceFromMeta_l(
    ++        OMX_BUFFERHEADERTYPE *header, OMX_U32 portIndex) {
    ++    OMX_U32 metaSize = portIndex == kPortIndexInput ? header->nAllocLen : header->nFilledLen;
    ++    int fenceFd = -1;
    ++    if (mMetadataType[portIndex] == kMetadataBufferTypeANWBuffer
    ++            && header->nAllocLen >= sizeof(VideoNativeMetadata)) {
    ++        VideoNativeMetadata &nativeMeta = *(VideoNativeMetadata *)(header->pBuffer);
    ++        if (nativeMeta.eType == kMetadataBufferTypeANWBuffer) {
    ++            fenceFd = nativeMeta.nFenceFd;
    ++            nativeMeta.nFenceFd = -1;
    ++        }
    ++        if (metaSize < sizeof(nativeMeta) && fenceFd >= 0) {
    ++            CLOG_ERROR(foundFenceInEmptyMeta, BAD_VALUE, FULL_BUFFER(
    ++                    NULL, header, nativeMeta.nFenceFd));
    ++            fenceFd = -1;
    ++        }
    ++    }
    ++    return fenceFd;
    ++}
    ++
    ++status_t OMXNodeInstance::emptyBuffer_l(
    ++        OMX_BUFFERHEADERTYPE *header, OMX_U32 flags, OMX_TICKS timestamp,
    ++        intptr_t debugAddr, int fenceFd) {
    ++    header->nFlags = flags;
    ++    header->nTimeStamp = timestamp;
    ++
    ++    status_t res = storeFenceInMeta_l(header, fenceFd, kPortIndexInput);
    ++    if (res != OK) {
    ++        CLOG_ERROR(emptyBuffer::storeFenceInMeta, res, WITH_STATS(
    ++                FULL_BUFFER(debugAddr, header, fenceFd)));
    ++        return res;
    ++    }
    ++
    ++    {
    ++        Mutex::Autolock _l(mDebugLock);
    ++        mInputBuffersWithCodec.add(header);
    ++
    ++        // bump internal-state debug level for 2 input frames past a buffer with CSD
    ++        if ((flags & OMX_BUFFERFLAG_CODECCONFIG) != 0) {
    ++            bumpDebugLevel_l(2 /* numInputBuffers */, 0 /* numOutputBuffers */);
    ++        }
    ++
    ++        CLOG_BUMPED_BUFFER(emptyBuffer, WITH_STATS(FULL_BUFFER(debugAddr, header, fenceFd)));
    ++    }
    ++
    ++    OMX_ERRORTYPE err = OMX_EmptyThisBuffer(mHandle, header);
    ++    CLOG_IF_ERROR(emptyBuffer, err, FULL_BUFFER(debugAddr, header, fenceFd));
    ++
    ++    {
    ++        Mutex::Autolock _l(mDebugLock);
    ++        if (err != OMX_ErrorNone) {
    ++            mInputBuffersWithCodec.remove(header);
    ++        } else if (!(flags & OMX_BUFFERFLAG_CODECCONFIG)) {
    ++            unbumpDebugLevel_l(kPortIndexInput);
    ++        }
    ++    }
    ++
    ++    return StatusFromOMXError(err);
    ++}
    ++
    ++// like emptyBuffer, but the data is already in header->pBuffer
    ++status_t OMXNodeInstance::emptyGraphicBuffer(
    ++        OMX_BUFFERHEADERTYPE *header, const sp<GraphicBuffer> &graphicBuffer,
    ++        OMX_U32 flags, OMX_TICKS timestamp, int fenceFd) {
    ++    if (header == NULL) {
    ++        ALOGE("b/25884056");
    ++        return BAD_VALUE;
    ++    }
    ++
    ++    Mutex::Autolock autoLock(mLock);
    ++    OMX::buffer_id buffer = findBufferID(header);
    ++    status_t err = updateGraphicBufferInMeta_l(
    ++            kPortIndexInput, graphicBuffer, buffer, header,
    ++            true /* updateCodecBuffer */);
    ++    if (err != OK) {
    ++        CLOG_ERROR(emptyGraphicBuffer, err, FULL_BUFFER(
    ++                (intptr_t)header->pBuffer, header, fenceFd));
    ++        return err;
    ++    }
    ++
    ++    header->nOffset = 0;
    ++    if (graphicBuffer == NULL) {
    ++        header->nFilledLen = 0;
    ++    } else if (mMetadataType[kPortIndexInput] == kMetadataBufferTypeGrallocSource) {
    ++        header->nFilledLen = sizeof(VideoGrallocMetadata);
    ++    } else {
    ++        header->nFilledLen = sizeof(VideoNativeMetadata);
    ++    }
    ++    return emptyBuffer_l(header, flags, timestamp, (intptr_t)header->pBuffer, fenceFd);
    ++}
    ++
    ++status_t OMXNodeInstance::getExtensionIndex(
    ++        const char *parameterName, OMX_INDEXTYPE *index) {
    ++    Mutex::Autolock autoLock(mLock);
    ++
    ++    OMX_ERRORTYPE err = OMX_GetExtensionIndex(
    ++            mHandle, const_cast<char *>(parameterName), index);
    ++
    ++    return StatusFromOMXError(err);
    ++}
    ++
    ++inline static const char *asString(IOMX::InternalOptionType i, const char *def = "??") {
    ++    switch (i) {
    ++        case IOMX::INTERNAL_OPTION_SUSPEND:           return "SUSPEND";
    ++        case IOMX::INTERNAL_OPTION_REPEAT_PREVIOUS_FRAME_DELAY:
    ++            return "REPEAT_PREVIOUS_FRAME_DELAY";
    ++        case IOMX::INTERNAL_OPTION_MAX_TIMESTAMP_GAP: return "MAX_TIMESTAMP_GAP";
    ++        case IOMX::INTERNAL_OPTION_MAX_FPS:           return "MAX_FPS";
    ++        case IOMX::INTERNAL_OPTION_START_TIME:        return "START_TIME";
    ++        case IOMX::INTERNAL_OPTION_TIME_LAPSE:        return "TIME_LAPSE";
    ++        case IOMX::INTERNAL_OPTION_TIME_OFFSET:       return "TIME_OFFSET";
    ++        default:                                      return def;
    ++    }
    ++}
    ++
    ++template<typename T>
    ++static bool getInternalOption(
    ++        const void *data, size_t size, T *out) {
    ++    if (size != sizeof(T)) {
    ++        return false;
    ++    }
    ++    *out = *(T*)data;
    ++    return true;
    ++}
    ++
    ++status_t OMXNodeInstance::setInternalOption(
    ++        OMX_U32 portIndex,
    ++        IOMX::InternalOptionType type,
    ++        const void *data,
    ++        size_t size) {
    ++    CLOG_CONFIG(setInternalOption, "%s(%d): %s:%u %zu@%p",
    ++            asString(type), type, portString(portIndex), portIndex, size, data);
    ++    switch (type) {
    ++        case IOMX::INTERNAL_OPTION_SUSPEND:
    ++        case IOMX::INTERNAL_OPTION_REPEAT_PREVIOUS_FRAME_DELAY:
    ++        case IOMX::INTERNAL_OPTION_MAX_TIMESTAMP_GAP:
    ++        case IOMX::INTERNAL_OPTION_MAX_FPS:
    ++        case IOMX::INTERNAL_OPTION_START_TIME:
    ++        case IOMX::INTERNAL_OPTION_TIME_LAPSE:
    ++        case IOMX::INTERNAL_OPTION_TIME_OFFSET:
    ++        case IOMX::INTERNAL_OPTION_COLOR_ASPECTS:
    ++        {
    ++            const sp<GraphicBufferSource> &bufferSource =
    ++                getGraphicBufferSource();
    ++
    ++            if (bufferSource == NULL || portIndex != kPortIndexInput) {
    ++                CLOGW("setInternalOption is only for Surface input");
    ++                return ERROR_UNSUPPORTED;
    ++            }
    ++
    ++            if (type == IOMX::INTERNAL_OPTION_SUSPEND) {
    ++                bool suspend;
    ++                if (!getInternalOption(data, size, &suspend)) {
    ++                    return INVALID_OPERATION;
    ++                }
    ++
    ++                CLOG_CONFIG(setInternalOption, "suspend=%d", suspend);
    ++                bufferSource->suspend(suspend);
    ++            } else if (type == IOMX::INTERNAL_OPTION_REPEAT_PREVIOUS_FRAME_DELAY) {
    ++                int64_t delayUs;
    ++                if (!getInternalOption(data, size, &delayUs)) {
    ++                    return INVALID_OPERATION;
    ++                }
    ++
    ++                CLOG_CONFIG(setInternalOption, "delayUs=%lld", (long long)delayUs);
    ++                return bufferSource->setRepeatPreviousFrameDelayUs(delayUs);
    ++            } else if (type == IOMX::INTERNAL_OPTION_TIME_OFFSET) {
    ++                int64_t timeOffsetUs;
    ++                if (!getInternalOption(data, size, &timeOffsetUs)) {
    ++                    return INVALID_OPERATION;
    ++                }
    ++                CLOG_CONFIG(setInternalOption, "bufferOffsetUs=%lld", (long long)timeOffsetUs);
    ++                return bufferSource->setInputBufferTimeOffset(timeOffsetUs);
    ++            } else if (type == IOMX::INTERNAL_OPTION_MAX_TIMESTAMP_GAP) {
    ++                int64_t maxGapUs;
    ++                if (!getInternalOption(data, size, &maxGapUs)) {
    ++                    return INVALID_OPERATION;
    ++                }
    ++
    ++                CLOG_CONFIG(setInternalOption, "gapUs=%lld", (long long)maxGapUs);
    ++                return bufferSource->setMaxTimestampGapUs(maxGapUs);
    ++            } else if (type == IOMX::INTERNAL_OPTION_MAX_FPS) {
    ++                float maxFps;
    ++                if (!getInternalOption(data, size, &maxFps)) {
    ++                    return INVALID_OPERATION;
    ++                }
    ++
    ++                CLOG_CONFIG(setInternalOption, "maxFps=%f", maxFps);
    ++                return bufferSource->setMaxFps(maxFps);
    ++            } else if (type == IOMX::INTERNAL_OPTION_START_TIME) {
    ++                int64_t skipFramesBeforeUs;
    ++                if (!getInternalOption(data, size, &skipFramesBeforeUs)) {
    ++                    return INVALID_OPERATION;
    ++                }
    ++
    ++                CLOG_CONFIG(setInternalOption, "beforeUs=%lld", (long long)skipFramesBeforeUs);
    ++                bufferSource->setSkipFramesBeforeUs(skipFramesBeforeUs);
    ++            } else if (type == IOMX::INTERNAL_OPTION_TIME_LAPSE) {
    ++                GraphicBufferSource::TimeLapseConfig config;
    ++                if (!getInternalOption(data, size, &config)) {
    ++                    return INVALID_OPERATION;
    ++                }
    ++
    ++                CLOG_CONFIG(setInternalOption, "perFrameUs=%lld perCaptureUs=%lld",
    ++                        (long long)config.mTimePerFrameUs, (long long)config.mTimePerCaptureUs);
    ++
    ++                return bufferSource->setTimeLapseConfig(config);
    ++            } else if (type == IOMX::INTERNAL_OPTION_COLOR_ASPECTS) {
    ++                ColorAspects aspects;
    ++                if (!getInternalOption(data, size, &aspects)) {
    ++                    return INVALID_OPERATION;
    ++                }
    ++
    ++                CLOG_CONFIG(setInternalOption, "setting color aspects");
    ++                bufferSource->setColorAspects(aspects);
    ++            }
    ++
    ++            return OK;
    ++        }
    ++
    ++        default:
    ++            return ERROR_UNSUPPORTED;
    ++    }
    ++}
    ++
    ++bool OMXNodeInstance::handleMessage(omx_message &msg) {
    ++    const sp<GraphicBufferSource>& bufferSource(getGraphicBufferSource());
    ++
    ++    if (msg.type == omx_message::FILL_BUFFER_DONE) {
    ++        OMX_BUFFERHEADERTYPE *buffer =
    ++            findBufferHeader(msg.u.extended_buffer_data.buffer, kPortIndexOutput);
    ++        if (buffer == NULL) {
    ++            ALOGE("b/25884056");
    ++            return false;
    ++        }
    ++
    ++        {
    ++            Mutex::Autolock _l(mDebugLock);
    ++            mOutputBuffersWithCodec.remove(buffer);
    ++
    ++            CLOG_BUMPED_BUFFER(
    ++                    FBD, WITH_STATS(FULL_BUFFER(
    ++                            msg.u.extended_buffer_data.buffer, buffer, msg.fenceFd)));
    ++
    ++            unbumpDebugLevel_l(kPortIndexOutput);
    ++        }
    ++
    ++        BufferMeta *buffer_meta =
    ++            static_cast<BufferMeta *>(buffer->pAppPrivate);
    ++
    ++        if (buffer->nOffset + buffer->nFilledLen < buffer->nOffset
    ++                || buffer->nOffset + buffer->nFilledLen > buffer->nAllocLen) {
    ++            CLOG_ERROR(onFillBufferDone, OMX_ErrorBadParameter,
    ++                    FULL_BUFFER(NULL, buffer, msg.fenceFd));
    ++        }
    ++        buffer_meta->CopyFromOMX(buffer);
    ++
    ++        if (bufferSource != NULL) {
    ++            // fix up the buffer info (especially timestamp) if needed
    ++            bufferSource->codecBufferFilled(buffer);
    ++
    ++            msg.u.extended_buffer_data.timestamp = buffer->nTimeStamp;
    ++        }
    ++    } else if (msg.type == omx_message::EMPTY_BUFFER_DONE) {
    ++        OMX_BUFFERHEADERTYPE *buffer =
    ++            findBufferHeader(msg.u.buffer_data.buffer, kPortIndexInput);
    ++        if (buffer == NULL) {
    ++            return false;
    ++        }
    ++
    ++        {
    ++            Mutex::Autolock _l(mDebugLock);
    ++            mInputBuffersWithCodec.remove(buffer);
    ++
    ++            CLOG_BUMPED_BUFFER(
    ++                    EBD, WITH_STATS(EMPTY_BUFFER(msg.u.buffer_data.buffer, buffer, msg.fenceFd)));
    ++        }
    ++
    ++        if (bufferSource != NULL) {
    ++            // This is one of the buffers used exclusively by
    ++            // GraphicBufferSource.
    ++            // Don't dispatch a message back to ACodec, since it doesn't
    ++            // know that anyone asked to have the buffer emptied and will
    ++            // be very confused.
    ++            bufferSource->codecBufferEmptied(buffer, msg.fenceFd);
    ++            return true;
    ++        }
    ++    }
    ++
    ++    return false;
    ++}
    ++
    ++void OMXNodeInstance::onMessages(std::list<omx_message> &messages) {
    ++    for (std::list<omx_message>::iterator it = messages.begin(); it != messages.end(); ) {
    ++        if (handleMessage(*it)) {
    ++            messages.erase(it++);
    ++        } else {
    ++            ++it;
    ++        }
    ++    }
    ++
    ++    if (!messages.empty()) {
    ++        mObserver->onMessages(messages);
    ++    }
    ++}
    ++
    ++void OMXNodeInstance::onObserverDied(OMXMaster *master) {
    ++    ALOGE("!!! Observer died. Quickly, do something, ... anything...");
    ++
    ++    // Try to force shutdown of the node and hope for the best.
    ++    freeNode(master);
    ++}
    ++
    ++void OMXNodeInstance::onGetHandleFailed() {
    ++    delete this;
    ++}
    ++
    ++// OMXNodeInstance::OnEvent calls OMX::OnEvent, which then calls here.
    ++// Don't try to acquire mLock here -- in rare circumstances this will hang.
    ++void OMXNodeInstance::onEvent(
    ++        OMX_EVENTTYPE event, OMX_U32 arg1, OMX_U32 arg2) {
    ++    const char *arg1String = "??";
    ++    const char *arg2String = "??";
    ++    ADebug::Level level = ADebug::kDebugInternalState;
    ++
    ++    switch (event) {
    ++        case OMX_EventCmdComplete:
    ++            arg1String = asString((OMX_COMMANDTYPE)arg1);
    ++            switch (arg1) {
    ++                case OMX_CommandStateSet:
    ++                    arg2String = asString((OMX_STATETYPE)arg2);
    ++                    level = ADebug::kDebugState;
    ++                    break;
    ++                case OMX_CommandFlush:
    ++                case OMX_CommandPortEnable:
    ++                {
    ++                    // bump internal-state debug level for 2 input and output frames
    ++                    Mutex::Autolock _l(mDebugLock);
    ++                    bumpDebugLevel_l(2 /* numInputBuffers */, 2 /* numOutputBuffers */);
    ++                }
    ++                // fall through
    ++                default:
    ++                    arg2String = portString(arg2);
    ++            }
    ++            break;
    ++        case OMX_EventError:
    ++            arg1String = asString((OMX_ERRORTYPE)arg1);
    ++            level = ADebug::kDebugLifeCycle;
    ++            break;
    ++        case OMX_EventPortSettingsChanged:
    ++            arg2String = asString((OMX_INDEXEXTTYPE)arg2);
    ++            // fall through
    ++        default:
    ++            arg1String = portString(arg1);
    ++    }
    ++
    ++    CLOGI_(level, onEvent, "%s(%x), %s(%x), %s(%x)",
    ++            asString(event), event, arg1String, arg1, arg2String, arg2);
    ++    const sp<GraphicBufferSource>& bufferSource(getGraphicBufferSource());
    ++
    ++    if (bufferSource != NULL
    ++            && event == OMX_EventCmdComplete
    ++            && arg1 == OMX_CommandStateSet
    ++            && arg2 == OMX_StateExecuting) {
    ++        bufferSource->omxExecuting();
    ++    }
    ++
    ++    // allow configuration if we return to the loaded state
    ++    if (event == OMX_EventCmdComplete
    ++            && arg1 == OMX_CommandStateSet
    ++            && arg2 == OMX_StateLoaded) {
    ++        mSailed = false;
    ++    }
    ++}
    ++
    ++// static
    ++OMX_ERRORTYPE OMXNodeInstance::OnEvent(
    ++        OMX_IN OMX_HANDLETYPE /* hComponent */,
    ++        OMX_IN OMX_PTR pAppData,
    ++        OMX_IN OMX_EVENTTYPE eEvent,
    ++        OMX_IN OMX_U32 nData1,
    ++        OMX_IN OMX_U32 nData2,
    ++        OMX_IN OMX_PTR pEventData) {
    ++    if (pAppData == NULL) {
    ++        ALOGE("b/25884056");
    ++        return OMX_ErrorBadParameter;
    ++    }
    ++    OMXNodeInstance *instance = static_cast<OMXNodeInstance *>(pAppData);
    ++    if (instance->mDying) {
    ++        return OMX_ErrorNone;
    ++    }
    ++    return instance->owner()->OnEvent(
    ++            instance->nodeID(), eEvent, nData1, nData2, pEventData);
    ++}
    ++
    ++// static
    ++OMX_ERRORTYPE OMXNodeInstance::OnEmptyBufferDone(
    ++        OMX_IN OMX_HANDLETYPE /* hComponent */,
    ++        OMX_IN OMX_PTR pAppData,
    ++        OMX_IN OMX_BUFFERHEADERTYPE* pBuffer) {
    ++    if (pAppData == NULL) {
    ++        ALOGE("b/25884056");
    ++        return OMX_ErrorBadParameter;
    ++    }
    ++    OMXNodeInstance *instance = static_cast<OMXNodeInstance *>(pAppData);
    ++    if (instance->mDying) {
    ++        return OMX_ErrorNone;
    ++    }
    ++    int fenceFd = instance->retrieveFenceFromMeta_l(pBuffer, kPortIndexOutput);
    ++    return instance->owner()->OnEmptyBufferDone(instance->nodeID(),
    ++            instance->findBufferID(pBuffer), pBuffer, fenceFd);
    ++}
    ++
    ++// static
    ++OMX_ERRORTYPE OMXNodeInstance::OnFillBufferDone(
    ++        OMX_IN OMX_HANDLETYPE /* hComponent */,
    ++        OMX_IN OMX_PTR pAppData,
    ++        OMX_IN OMX_BUFFERHEADERTYPE* pBuffer) {
    ++    if (pAppData == NULL) {
    ++        ALOGE("b/25884056");
    ++        return OMX_ErrorBadParameter;
    ++    }
    ++    OMXNodeInstance *instance = static_cast<OMXNodeInstance *>(pAppData);
    ++    if (instance->mDying) {
    ++        return OMX_ErrorNone;
    ++    }
    ++    int fenceFd = instance->retrieveFenceFromMeta_l(pBuffer, kPortIndexOutput);
    ++    return instance->owner()->OnFillBufferDone(instance->nodeID(),
    ++            instance->findBufferID(pBuffer), pBuffer, fenceFd);
    ++}
    ++
    ++void OMXNodeInstance::addActiveBuffer(OMX_U32 portIndex, OMX::buffer_id id) {
    ++    ActiveBuffer active;
    ++    active.mPortIndex = portIndex;
    ++    active.mID = id;
    ++    mActiveBuffers.push(active);
    ++
    ++    if (portIndex < NELEM(mNumPortBuffers)) {
    ++        ++mNumPortBuffers[portIndex];
    ++    }
    ++}
    ++
    ++void OMXNodeInstance::removeActiveBuffer(
    ++        OMX_U32 portIndex, OMX::buffer_id id) {
    ++    for (size_t i = 0; i < mActiveBuffers.size(); ++i) {
    ++        if (mActiveBuffers[i].mPortIndex == portIndex
    ++                && mActiveBuffers[i].mID == id) {
    ++            mActiveBuffers.removeItemsAt(i);
    ++
    ++            if (portIndex < NELEM(mNumPortBuffers)) {
    ++                --mNumPortBuffers[portIndex];
    ++            }
    ++            return;
    ++        }
    ++    }
    ++
    ++     CLOGW("Attempt to remove an active buffer [%#x] we know nothing about...", id);
    ++}
    ++
    ++void OMXNodeInstance::freeActiveBuffers() {
    ++    // Make sure to count down here, as freeBuffer will in turn remove
    ++    // the active buffer from the vector...
    ++    for (size_t i = mActiveBuffers.size(); i > 0;) {
    ++        i--;
    ++        freeBuffer(mActiveBuffers[i].mPortIndex, mActiveBuffers[i].mID);
    ++    }
    ++}
    ++
    ++OMX::buffer_id OMXNodeInstance::makeBufferID(OMX_BUFFERHEADERTYPE *bufferHeader) {
    ++    if (bufferHeader == NULL) {
    ++        return 0;
    ++    }
    ++    Mutex::Autolock autoLock(mBufferIDLock);
    ++    OMX::buffer_id buffer;
    ++    do { // handle the very unlikely case of ID overflow
    ++        if (++mBufferIDCount == 0) {
    ++            ++mBufferIDCount;
    ++        }
    ++        buffer = (OMX::buffer_id)mBufferIDCount;
    ++    } while (mBufferIDToBufferHeader.indexOfKey(buffer) >= 0);
    ++    mBufferIDToBufferHeader.add(buffer, bufferHeader);
    ++    mBufferHeaderToBufferID.add(bufferHeader, buffer);
    ++    return buffer;
    ++}
    ++
    ++OMX_BUFFERHEADERTYPE *OMXNodeInstance::findBufferHeader(
    ++        OMX::buffer_id buffer, OMX_U32 portIndex) {
    ++    if (buffer == 0) {
    ++        return NULL;
    ++    }
    ++    Mutex::Autolock autoLock(mBufferIDLock);
    ++    ssize_t index = mBufferIDToBufferHeader.indexOfKey(buffer);
    ++    if (index < 0) {
    ++        CLOGW("findBufferHeader: buffer %u not found", buffer);
    ++        return NULL;
    ++    }
    ++    OMX_BUFFERHEADERTYPE *header = mBufferIDToBufferHeader.valueAt(index);
    ++    BufferMeta *buffer_meta =
    ++        static_cast<BufferMeta *>(header->pAppPrivate);
    ++    if (buffer_meta->getPortIndex() != portIndex) {
    ++        CLOGW("findBufferHeader: buffer %u found but with incorrect port index.", buffer);
    ++        android_errorWriteLog(0x534e4554, "28816827");
    ++        return NULL;
    ++    }
    ++    return header;
    ++}
    ++
    ++OMX::buffer_id OMXNodeInstance::findBufferID(OMX_BUFFERHEADERTYPE *bufferHeader) {
    ++    if (bufferHeader == NULL) {
    ++        return 0;
    ++    }
    ++    Mutex::Autolock autoLock(mBufferIDLock);
    ++    ssize_t index = mBufferHeaderToBufferID.indexOfKey(bufferHeader);
    ++    if (index < 0) {
    ++        CLOGW("findBufferID: bufferHeader %p not found", bufferHeader);
    ++        return 0;
    ++    }
    ++    return mBufferHeaderToBufferID.valueAt(index);
    ++}
    ++
    ++void OMXNodeInstance::invalidateBufferID(OMX::buffer_id buffer) {
    ++    if (buffer == 0) {
    ++        return;
    ++    }
    ++    Mutex::Autolock autoLock(mBufferIDLock);
    ++    ssize_t index = mBufferIDToBufferHeader.indexOfKey(buffer);
    ++    if (index < 0) {
    ++        CLOGW("invalidateBufferID: buffer %u not found", buffer);
    ++        return;
    ++    }
    ++    mBufferHeaderToBufferID.removeItem(mBufferIDToBufferHeader.valueAt(index));
    ++    mBufferIDToBufferHeader.removeItemsAt(index);
    ++}
    ++
    ++}  // namespace android
     diff --git a/media/libstagefright/omx/SimpleSoftOMXComponent.cpp b/media/libstagefright/omx/SimpleSoftOMXComponent.cpp
     index 7c975f7..76cbbc4 100644
     --- a/media/libstagefright/omx/SimpleSoftOMXComponent.cpp
    @@ -1398,6 +5410,99 @@ index ecddc48..0abe6ac 100644
          registerExtensions();
          ProcessState::self()->startThreadPool();
          IPCThreadState::self()->joinThreadPool();
    +diff --git a/media/mtp/MtpServer.cpp b/media/mtp/MtpServer.cpp
    +index e39dcdd..65a2415 100644
    +--- a/media/mtp/MtpServer.cpp
    ++++ b/media/mtp/MtpServer.cpp
    +@@ -136,20 +136,9 @@ void MtpServer::removeStorage(MtpStorage* storage) {
    + }
    + 
    + MtpStorage* MtpServer::getStorage(MtpStorageID id) {
    +-    if (id == 0)
    +-        return mStorages[0];
    +-    for (size_t i = 0; i < mStorages.size(); i++) {
    +-        MtpStorage* storage = mStorages[i];
    +-        if (storage->getStorageID() == id)
    +-            return storage;
    +-    }
    +-    return NULL;
    +-}
    ++     Mutex::Autolock autoLock(mMutex);
    + 
    +-bool MtpServer::hasStorage(MtpStorageID id) {
    +-    if (id == 0 || id == 0xFFFFFFFF)
    +-        return mStorages.size() > 0;
    +-    return (getStorage(id) != NULL);
    ++    return getStorageLocked(id);
    + }
    + 
    + void MtpServer::run() {
    +@@ -254,6 +243,23 @@ void MtpServer::sendObjectRemoved(MtpObjectHandle handle) {
    +     sendEvent(MTP_EVENT_OBJECT_REMOVED, handle);
    + }
    + 
    ++MtpStorage* MtpServer::getStorageLocked(MtpStorageID id) {
    ++    if (id == 0)
    ++        return mStorages.empty() ? NULL : mStorages[0];
    ++    for (size_t i = 0; i < mStorages.size(); i++) {
    ++        MtpStorage* storage = mStorages[i];
    ++        if (storage->getStorageID() == id)
    ++            return storage;
    ++    }
    ++    return NULL;
    ++}
    ++
    ++bool MtpServer::hasStorage(MtpStorageID id) {
    ++    if (id == 0 || id == 0xFFFFFFFF)
    ++        return mStorages.size() > 0;
    ++    return (getStorageLocked(id) != NULL);
    ++}
    ++
    + void MtpServer::sendStoreAdded(MtpStorageID id) {
    +     ALOGV("sendStoreAdded %08X\n", id);
    +     sendEvent(MTP_EVENT_STORE_ADDED, id);
    +@@ -537,7 +543,7 @@ MtpResponseCode MtpServer::doGetStorageInfo() {
    +         return MTP_RESPONSE_INVALID_PARAMETER;
    + 
    +     MtpStorageID id = mRequest.getParameter(1);
    +-    MtpStorage* storage = getStorage(id);
    ++    MtpStorage* storage = getStorageLocked(id);
    +     if (!storage)
    +         return MTP_RESPONSE_INVALID_STORAGE_ID;
    + 
    +@@ -888,7 +894,7 @@ MtpResponseCode MtpServer::doSendObjectInfo() {
    +     if (mRequest.getParameterCount() < 2)
    +         return MTP_RESPONSE_INVALID_PARAMETER;
    +     MtpStorageID storageID = mRequest.getParameter(1);
    +-    MtpStorage* storage = getStorage(storageID);
    ++    MtpStorage* storage = getStorageLocked(storageID);
    +     MtpObjectHandle parent = mRequest.getParameter(2);
    +     if (!storage)
    +         return MTP_RESPONSE_INVALID_STORAGE_ID;
    +diff --git a/media/mtp/MtpServer.h b/media/mtp/MtpServer.h
    +index b3a11e0..cd543c8 100644
    +--- a/media/mtp/MtpServer.h
    ++++ b/media/mtp/MtpServer.h
    +@@ -95,8 +95,6 @@ public:
    +     virtual             ~MtpServer();
    + 
    +     MtpStorage*         getStorage(MtpStorageID id);
    +-    inline bool         hasStorage() { return mStorages.size() > 0; }
    +-    bool                hasStorage(MtpStorageID id);
    +     void                addStorage(MtpStorage* storage);
    +     void                removeStorage(MtpStorage* storage);
    + 
    +@@ -107,6 +105,10 @@ public:
    +     void                sendDevicePropertyChanged(MtpDeviceProperty property);
    + 
    + private:
    ++    MtpStorage*         getStorageLocked(MtpStorageID id);
    ++    inline bool         hasStorage() { return mStorages.size() > 0; }
    ++    bool                hasStorage(MtpStorageID id);
    ++
    +     void                sendStoreAdded(MtpStorageID id);
    +     void                sendStoreRemoved(MtpStorageID id);
    +     void                sendEvent(MtpEventCode code, uint32_t param1);
     diff --git a/services/audioflinger/AudioFlinger.cpp b/services/audioflinger/AudioFlinger.cpp
     index fec3a57..a0ef28c 100644
     --- a/services/audioflinger/AudioFlinger.cpp
    @@ -1588,3 +5693,45 @@ index 266fb03..3c2b98a 100644
      }
      
      status_t CameraClient::setVideoBufferMode(int32_t videoBufferMode) {
    +diff --git a/services/soundtrigger/SoundTriggerHwService.cpp b/services/soundtrigger/SoundTriggerHwService.cpp
    +index eebc487..74d0c70 100644
    +--- a/services/soundtrigger/SoundTriggerHwService.cpp
    ++++ b/services/soundtrigger/SoundTriggerHwService.cpp
    +@@ -278,6 +278,37 @@ void SoundTriggerHwService::sendRecognitionEvent(struct sound_trigger_recognitio
    +      if (module == NULL) {
    +          return;
    +      }
    ++    struct sound_trigger_phrase_recognition_event newEvent;
    ++    if (event-> type == SOUND_MODEL_TYPE_KEYPHRASE && event->data_size != 0
    ++        && event->data_offset != sizeof(struct sound_trigger_phrase_recognition_event)) {
    ++        // set some defaults for the phrase if the recognition event won't be parsed properly
    ++        // TODO: read defaults from the config
    ++
    ++        memset(&newEvent, 0, sizeof(struct sound_trigger_phrase_recognition_event));
    ++
    ++        sp<Model> model = module->getModel(event->model);
    ++
    ++        newEvent.num_phrases = 1;
    ++        newEvent.phrase_extras[0].id = 100;
    ++        newEvent.phrase_extras[0].recognition_modes = RECOGNITION_MODE_VOICE_TRIGGER;
    ++        newEvent.phrase_extras[0].confidence_level = 100;
    ++        newEvent.phrase_extras[0].num_levels = 1;
    ++        newEvent.phrase_extras[0].levels[0].level = 100;
    ++        newEvent.phrase_extras[0].levels[0].user_id = 100;
    ++        newEvent.common.status = event->status;
    ++        newEvent.common.type = event->type;
    ++        newEvent.common.model = event->model;
    ++        newEvent.common.capture_available = event->capture_available;
    ++        newEvent.common.capture_session = event->capture_session;
    ++        newEvent.common.capture_delay_ms = event->capture_delay_ms;
    ++        newEvent.common.capture_preamble_ms = event->capture_preamble_ms;
    ++        newEvent.common.trigger_in_data = event->trigger_in_data;
    ++        newEvent.common.audio_config = event->audio_config;
    ++        newEvent.common.data_size = event->data_size;
    ++        newEvent.common.data_offset = sizeof(struct sound_trigger_phrase_recognition_event);
    ++
    ++         event = &newEvent.common;
    ++     }
    +      sp<IMemory> eventMemory = prepareRecognitionEvent_l(event);
    +      if (eventMemory == 0) {
    +          return;
    diff --git a/frameworks_base.patch b/frameworks_base.patch
    index 6cf4474..07c4014 100644
    --- a/frameworks_base.patch
    +++ b/frameworks_base.patch
    @@ -232,6 +232,73 @@ index e4f573b..0d3f50c 100644
                  EGL14.eglGetDisplay(EGL14.EGL_DEFAULT_DISPLAY);
              }
          }
    +diff --git a/core/jni/android_util_Binder.cpp b/core/jni/android_util_Binder.cpp
    +index 5559d48..bee11db 100644
    +--- a/core/jni/android_util_Binder.cpp
    ++++ b/core/jni/android_util_Binder.cpp
    +@@ -132,6 +132,14 @@ static struct strict_mode_callback_offsets_t
    +     jmethodID mCallback;
    + } gStrictModeCallbackOffsets;
    + 
    ++static struct thread_dispatch_offsets_t
    ++{
    ++    // Class state.
    ++    jclass mClass;
    ++    jmethodID mDispatchUncaughtException;
    ++    jmethodID mCurrentThread;
    ++} gThreadDispatchOffsets;
    ++
    + // ****************************************************************************
    + // ****************************************************************************
    + // ****************************************************************************
    +@@ -165,6 +173,23 @@ static JNIEnv* javavm_to_jnienv(JavaVM* vm)
    +     return vm->GetEnv((void **)&env, JNI_VERSION_1_4) >= 0 ? env : NULL;
    + }
    + 
    ++// Report a java.lang.Error (or subclass). This may terminate the runtime.
    ++static void report_java_lang_error(JNIEnv* env, jthrowable error)
    ++{
    ++    // Try to run the uncaught exception machinery.
    ++    jobject thread = env->CallStaticObjectMethod(gThreadDispatchOffsets.mClass,
    ++            gThreadDispatchOffsets.mCurrentThread);
    ++    if (thread != nullptr) {
    ++        env->CallVoidMethod(thread, gThreadDispatchOffsets.mDispatchUncaughtException,
    ++                error);
    ++        // Should not return here, unless more errors occured.
    ++    }
    ++    // Some error occurred that meant that either dispatchUncaughtException could not be
    ++    // called or that it had an error itself (as this should be unreachable under normal
    ++    // conditions). Clear the exception.
    ++    env->ExceptionClear();
    ++}
    ++
    + static void report_exception(JNIEnv* env, jthrowable excep, const char* msg)
    + {
    +     env->ExceptionClear();
    +@@ -191,6 +216,10 @@ static void report_exception(JNIEnv* env, jthrowable excep, const char* msg)
    +     }
    + 
    +     if (env->IsInstanceOf(excep, gErrorOffsets.mClass)) {
    ++        // Try to report the error. This should not return under normal circumstances.
    ++        report_java_lang_error(env, excep);
    ++        // The traditional handling: re-raise and abort.
    ++
    +         /*
    +          * It's an Error: Reraise the exception, detach this thread, and
    +          * wait for the fireworks. Die even more blatantly after a minute
    +@@ -1318,5 +1347,12 @@ int register_android_os_Binder(JNIEnv* env)
    +     gStrictModeCallbackOffsets.mCallback = GetStaticMethodIDOrDie(env, clazz,
    +             "onBinderStrictModePolicyChange", "(I)V");
    + 
    ++    clazz = FindClassOrDie(env, "java/lang/Thread");
    ++    gThreadDispatchOffsets.mClass = MakeGlobalRefOrDie(env, clazz);
    ++    gThreadDispatchOffsets.mDispatchUncaughtException = GetMethodIDOrDie(env, clazz,
    ++            "dispatchUncaughtException", "(Ljava/lang/Throwable;)V");
    ++    gThreadDispatchOffsets.mCurrentThread = GetStaticMethodIDOrDie(env, clazz, "currentThread",
    ++            "()Ljava/lang/Thread;");
    ++
    +     return 0;
    + }
     diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
     index 011884c..a5035ee 100644
     --- a/core/res/AndroidManifest.xml
    @@ -1089,6 +1156,60 @@ index aa8e781..ec3208b 100644
              if (mWin.mTurnOnScreen) {
                  if (DEBUG_VISIBILITY) Slog.v(TAG, "Show surface turning screen on: " + mWin);
                  mWin.mTurnOnScreen = false;
    +diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
    +index e3b6ecc..ff63b08 100644
    +--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
    ++++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
    +@@ -71,6 +71,7 @@ import android.content.pm.PackageManager;
    + import android.content.pm.PackageManager.NameNotFoundException;
    + import android.content.pm.PackageManagerInternal;
    + import android.content.pm.ParceledListSlice;
    ++import android.content.pm.PermissionInfo;
    + import android.content.pm.ResolveInfo;
    + import android.content.pm.ServiceInfo;
    + import android.content.pm.UserInfo;
    +@@ -123,6 +124,7 @@ import android.telephony.TelephonyManager;
    + import android.text.TextUtils;
    + import android.util.ArrayMap;
    + import android.util.ArraySet;
    ++import android.util.EventLog;
    + import android.util.Log;
    + import android.util.Pair;
    + import android.util.Slog;
    +@@ -8621,6 +8623,10 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
    +                         < android.os.Build.VERSION_CODES.M) {
    +                     return false;
    +                 }
    ++                if (!isRuntimePermission(permission)) {
    ++                    EventLog.writeEvent(0x534e4554, "62623498", user.getIdentifier(), "");
    ++                    return false;
    ++                }
    +                 final PackageManager packageManager = mContext.getPackageManager();
    +                 switch (grantState) {
    +                     case DevicePolicyManager.PERMISSION_GRANT_STATE_GRANTED: {
    +@@ -8646,6 +8652,8 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
    +                 return true;
    +             } catch (SecurityException se) {
    +                 return false;
    ++            } catch (NameNotFoundException e) {
    ++                return false;
    +             } finally {
    +                 mInjector.binderRestoreCallingIdentity(ident);
    +             }
    +@@ -8691,6 +8699,13 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
    +         }
    +     }
    + 
    ++    public boolean isRuntimePermission(String permissionName) throws NameNotFoundException {
    ++        PackageManager packageManager = mContext.getPackageManager();
    ++        PermissionInfo permissionInfo = packageManager.getPermissionInfo(permissionName, 0);
    ++        return (permissionInfo.protectionLevel & PermissionInfo.PROTECTION_MASK_BASE)
    ++                == PermissionInfo.PROTECTION_DANGEROUS;
    ++    }
    ++
    +     @Override
    +     public boolean isProvisioningAllowed(String action) {
    +         if (!mHasFeature) {
     diff --git a/services/net/java/android/net/dhcp/DhcpClient.java b/services/net/java/android/net/dhcp/DhcpClient.java
     index ffbea9f..8dd05b1 100644
     --- a/services/net/java/android/net/dhcp/DhcpClient.java
    diff --git a/frameworks_native.patch b/frameworks_native.patch
    index 21604d2..a5e2a4b 100644
    --- a/frameworks_native.patch
    +++ b/frameworks_native.patch
    @@ -86,6 +86,25 @@ index 271c75b..cadcd1e 100644
                  return -1;
              }
          }
    +diff --git a/include/binder/Parcel.h b/include/binder/Parcel.h
    +index 2490b82..1e3d02f 100644
    +--- a/include/binder/Parcel.h
    ++++ b/include/binder/Parcel.h
    +@@ -476,7 +476,13 @@ private:
    +             return val.flatten(buffer, size, fds, count);
    +         }
    +         virtual status_t unflatten(void const* buffer, size_t size, int const* fds, size_t count) {
    +-            return const_cast<Flattenable<T>&>(val).unflatten(buffer, size, fds, count);
    ++            status_t err = const_cast<Flattenable<T>&>(val).unflatten(buffer, size, fds, count);
    ++            if (err != NO_ERROR) {
    ++                for (size_t i = 0; i < count; i++) {
    ++                    close(fds[i]);
    ++                }
    ++            }
    ++            return err;
    +         }
    +     };
    +     status_t write(const FlattenableHelperInterface& val);
     diff --git a/include/gui/ISurfaceComposer.h b/include/gui/ISurfaceComposer.h
     index 74a4123..8dc6f6a 100644
     --- a/include/gui/ISurfaceComposer.h
    @@ -221,6 +240,33 @@ index 0000000..2eb1cc1
     +
     +#endif // ANDROID_FRAMEBUFFER_NATIVE_WINDOW_H
     +
    +diff --git a/libs/binder/AppOpsManager.cpp b/libs/binder/AppOpsManager.cpp
    +index 9a061a0..8f97544 100644
    +--- a/libs/binder/AppOpsManager.cpp
    ++++ b/libs/binder/AppOpsManager.cpp
    +@@ -53,7 +53,8 @@ sp<IAppOpsService> AppOpsManager::getService()
    +                 ALOGI("Waiting for app ops service");
    +             } else if ((uptimeMillis()-startTime) > 10000) {
    +                 ALOGW("Waiting too long for app ops service, giving up");
    +-                return NULL;
    ++                service = NULL;
    ++                break;
    +             }
    +             sleep(1);
    +         } else {
    +diff --git a/libs/binder/Binder.cpp b/libs/binder/Binder.cpp
    +index c4d47ca..d04074e 100644
    +--- a/libs/binder/Binder.cpp
    ++++ b/libs/binder/Binder.cpp
    +@@ -240,6 +240,8 @@ status_t BBinder::onTransact(
    +             if (resultReceiver != NULL) {
    +                 resultReceiver->send(INVALID_OPERATION);
    +             }
    ++
    ++            return NO_ERROR;
    +         }
    + 
    +         case SYSPROPS_TRANSACTION: {
     diff --git a/libs/binder/IPCThreadState.cpp b/libs/binder/IPCThreadState.cpp
     index eccc400..3efebf7 100644
     --- a/libs/binder/IPCThreadState.cpp
    @@ -265,6 +311,42 @@ index 9e2fc2b..12d2148 100644
      
      LOCAL_MODULE := libgui
      
    +diff --git a/libs/gui/BufferQueueProducer.cpp b/libs/gui/BufferQueueProducer.cpp
    +index ff85eb5..6dc7fec 100644
    +--- a/libs/gui/BufferQueueProducer.cpp
    ++++ b/libs/gui/BufferQueueProducer.cpp
    +@@ -721,6 +721,7 @@ status_t BufferQueueProducer::attachBuffer(int* outSlot,
    +     mSlots[*outSlot].mFence = Fence::NO_FENCE;
    +     mSlots[*outSlot].mRequestBufferCalled = true;
    +     mSlots[*outSlot].mAcquireCalled = false;
    ++    mSlots[*outSlot].mNeedsReallocation = false;
    +     mCore->mActiveBuffers.insert(found);
    +     VALIDATE_CONSISTENCY();
    + 
    +@@ -1279,6 +1280,13 @@ void BufferQueueProducer::allocateBuffers(uint32_t width, uint32_t height,
    +             allocFormat = format != 0 ? format : mCore->mDefaultBufferFormat;
    +             allocUsage = usage | mCore->mConsumerUsageBits;
    + 
    ++            // If mTransformHint is set, the EGL implementation will request buffers
    ++            // with pre-rotated size. So here we need to swap the width and height
    ++            // to avoid the buffers being freed and reallocated when dequeueBuffer()
    ++            // gets called later.
    ++            if (mCore->mTransformHint != 0) {
    ++                std::swap(allocWidth, allocHeight);
    ++            }
    +             mCore->mIsAllocating = true;
    +         } // Autolock scope
    + 
    +@@ -1303,6 +1311,9 @@ void BufferQueueProducer::allocateBuffers(uint32_t width, uint32_t height,
    +             Mutex::Autolock lock(mCore->mMutex);
    +             uint32_t checkWidth = width > 0 ? width : mCore->mDefaultWidth;
    +             uint32_t checkHeight = height > 0 ? height : mCore->mDefaultHeight;
    ++            if (mCore->mTransformHint != 0) {
    ++                std::swap(checkWidth, checkHeight);
    ++            }
    +             PixelFormat checkFormat = format != 0 ?
    +                     format : mCore->mDefaultBufferFormat;
    +             uint32_t checkUsage = usage | mCore->mConsumerUsageBits;
     diff --git a/libs/gui/ISurfaceComposer.cpp b/libs/gui/ISurfaceComposer.cpp
     index f0b0ada..3577a33 100644
     --- a/libs/gui/ISurfaceComposer.cpp
    @@ -748,6 +830,18 @@ index 0000000..3ead25c
     +    }
     +    return static_cast<EGLNativeWindowType>(w);
     +}
    +diff --git a/libs/ui/GraphicBuffer.cpp b/libs/ui/GraphicBuffer.cpp
    +index 97b948d..0bb0941 100644
    +--- a/libs/ui/GraphicBuffer.cpp
    ++++ b/libs/ui/GraphicBuffer.cpp
    +@@ -394,6 +394,7 @@ status_t GraphicBuffer::unflatten(
    +         status_t err = mBufferMapper.registerBuffer(this);
    +         if (err != NO_ERROR) {
    +             width = height = stride = format = usage = 0;
    ++            native_handle_delete(const_cast<native_handle*>(handle));
    +             handle = NULL;
    +             ALOGE("unflatten: registerBuffer failed: %s (%d)",
    +                     strerror(-err), err);
     diff --git a/libs/ui/Region.cpp b/libs/ui/Region.cpp
     index ee152bf..9c82295 100644
     --- a/libs/ui/Region.cpp
    @@ -765,7 +859,7 @@ index ee152bf..9c82295 100644
          result.mStorage.clear();
          for (size_t r = 0; r < numRects; ++r) {
     diff --git a/opengl/libs/Android.mk b/opengl/libs/Android.mk
    -index 24e4c19..038fe4d 100644
    +index 24e4c19..ffd0dbc 100644
     --- a/opengl/libs/Android.mk
     +++ b/opengl/libs/Android.mk
     @@ -77,7 +77,6 @@ LOCAL_SRC_FILES:= 		\
    @@ -784,113 +878,748 @@ index 24e4c19..038fe4d 100644
      LOCAL_ARM_MODE := arm
      LOCAL_SHARED_LIBRARIES += libcutils libutils liblog libEGL
      LOCAL_MODULE:= libGLESv2
    +@@ -133,7 +131,6 @@ LOCAL_SRC_FILES:= \
    + 	GLES2/gl2.cpp   \
    + #
    + 
    +-LOCAL_CLANG := false
    + LOCAL_ARM_MODE := arm
    + LOCAL_SHARED_LIBRARIES += libcutils libutils liblog libEGL
    + LOCAL_MODULE:= libGLESv3
     diff --git a/opengl/libs/GLES2/gl2.cpp b/opengl/libs/GLES2/gl2.cpp
    -index 6034a8e..f1feeda 100644
    +index 6034a8e..6dd87c2 100644
     --- a/opengl/libs/GLES2/gl2.cpp
     +++ b/opengl/libs/GLES2/gl2.cpp
    -@@ -59,7 +59,7 @@ using namespace android;
    -             :                                                   \
    -             : [tls] "J"(TLS_SLOT_OPENGL_API*4),                 \
    -               [api] "J"(__builtin_offsetof(gl_hooks_t, gl._api))    \
    +@@ -34,39 +34,65 @@ using namespace android;
    + 
    + #undef API_ENTRY
    + #undef CALL_GL_API
    ++#undef CALL_GL_API_INTERNAL_CALL
    ++#undef CALL_GL_API_INTERNAL_SET_RETURN_VALUE
    ++#undef CALL_GL_API_INTERNAL_DO_RETURN
    + #undef CALL_GL_API_RETURN
    + 
    + #if USE_SLOW_BINDING
    + 
    +     #define API_ENTRY(_api) _api
    + 
    +-    #define CALL_GL_API(_api, ...)                                       \
    ++    #define CALL_GL_API_INTERNAL_CALL(_api, ...)                         \
    +         gl_hooks_t::gl_t const * const _c = &getGlThreadSpecific()->gl;  \
    +         if (_c) return _c->_api(__VA_ARGS__);
    + 
    ++    #define CALL_GL_API_INTERNAL_SET_RETURN_VALUE return 0;
    ++
    ++    // This stays blank, since void functions will implicitly return, and
    ++    // all of the other functions will return 0 based on the previous macro.
    ++    #define CALL_GL_API_INTERNAL_DO_RETURN
    ++
    + #elif defined(__arm__)
    + 
    +     #define GET_TLS(reg) "mrc p15, 0, " #reg ", c13, c0, 3 \n"
    + 
    +-    #define API_ENTRY(_api) __attribute__((noinline)) _api
    +-
    +-    #define CALL_GL_API(_api, ...)                              \
    +-         asm volatile(                                          \
    +-            GET_TLS(r12)                                        \
    +-            "ldr   r12, [r12, %[tls]] \n"                       \
    +-            "cmp   r12, #0            \n"                       \
    +-            "ldrne pc,  [r12, %[api]] \n"                       \
    +-            :                                                   \
    +-            : [tls] "J"(TLS_SLOT_OPENGL_API*4),                 \
    +-              [api] "J"(__builtin_offsetof(gl_hooks_t, gl._api))    \
     -            : "r12"                                             \
    -+            : "r0", "r1", "r2", "r3", "r12"                     \
    -             );
    +-            );
    ++    #define API_ENTRY(_api) __attribute__((naked,noinline)) _api
    ++
    ++    #define CALL_GL_API_INTERNAL_CALL(_api, ...)                 \
    ++        asm volatile(                                            \
    ++            GET_TLS(r12)                                         \
    ++            "ldr   r12, [r12, %[tls]] \n"                        \
    ++            "cmp   r12, #0            \n"                        \
    ++            "ldrne pc,  [r12, %[api]] \n"                        \
    ++            :                                                    \
    ++            : [tls] "J"(TLS_SLOT_OPENGL_API*4),                  \
    ++              [api] "J"(__builtin_offsetof(gl_hooks_t, gl._api)) \
    ++            : "r0", "r1", "r2", "r3", "r12"                      \
    ++        );
    ++
    ++    #define CALL_GL_API_INTERNAL_SET_RETURN_VALUE \
    ++        asm volatile(                             \
    ++            "mov r0, #0 \n"                       \
    ++            :                                     \
    ++            :                                     \
    ++            : "r0"                                \
    ++        );
    ++
    ++
    ++    #define CALL_GL_API_INTERNAL_DO_RETURN \
    ++        asm volatile(                      \
    ++            "bx lr \n"                     \
    ++            :                              \
    ++            :                              \
    ++            : "r0"                         \
    ++        );
      
      #elif defined(__aarch64__)
    -@@ -77,7 +77,7 @@ using namespace android;
    + 
    +-    #define API_ENTRY(_api) __attribute__((noinline)) _api
    ++    #define API_ENTRY(_api) __attribute__((naked,noinline)) _api
    + 
    +-    #define CALL_GL_API(_api, ...)                                  \
    ++    #define CALL_GL_API_INTERNAL_CALL(_api, ...)                    \
    +         asm volatile(                                               \
    +             "mrs x16, tpidr_el0\n"                                  \
    +             "ldr x16, [x16, %[tls]]\n"                              \
    +@@ -77,121 +103,173 @@ using namespace android;
                  :                                                       \
                  : [tls] "i" (TLS_SLOT_OPENGL_API * sizeof(void*)),      \
                    [api] "i" (__builtin_offsetof(gl_hooks_t, gl._api))   \
     -            : "x16"                                                 \
     +            : "x0", "x1", "x2", "x3", "x4", "x5", "x6", "x7", "x16" \
    ++        );
    ++
    ++    #define CALL_GL_API_INTERNAL_SET_RETURN_VALUE \
    ++        asm volatile(                             \
    ++            "mov w0, wzr \n"                      \
    ++            :                                     \
    ++            :                                     \
    ++            : "w0"                                \
    ++        );
    ++
    ++    #define CALL_GL_API_INTERNAL_DO_RETURN \
    ++        asm volatile(                      \
    ++            "ret \n"                       \
    ++            :                              \
    ++            :                              \
    ++            :                              \
              );
      
      #elif defined(__i386__)
    -@@ -115,7 +115,9 @@ using namespace android;
    -             : [fn] "=r" (fn)                                        \
    + 
    +-    #define API_ENTRY(_api) __attribute__((noinline,optimize("omit-frame-pointer"))) _api
    ++    #define API_ENTRY(_api) __attribute__((naked,noinline)) _api
    + 
    +-    #define CALL_GL_API(_api, ...)                                  \
    +-        register void** fn;                                         \
    ++    #define CALL_GL_API_INTERNAL_CALL(_api, ...)                    \
    +         __asm__ volatile(                                           \
    +-            "mov %%gs:0, %[fn]\n"                                   \
    +-            "mov %P[tls](%[fn]), %[fn]\n"                           \
    +-            "test %[fn], %[fn]\n"                                   \
    ++            "mov %%gs:0, %%eax\n"                                   \
    ++            "mov %P[tls](%%eax), %%eax\n"                           \
    ++            "test %%eax, %%eax\n"                                   \
    +             "je 1f\n"                                               \
    +-            "jmp *%P[api](%[fn])\n"                                 \
    ++            "jmp *%P[api](%%eax)\n"                                 \
    +             "1:\n"                                                  \
    +-            : [fn] "=r" (fn)                                        \
    ++            :                                                       \
                  : [tls] "i" (TLS_SLOT_OPENGL_API*sizeof(void*)),        \
                    [api] "i" (__builtin_offsetof(gl_hooks_t, gl._api))   \
     -            : "cc"                                                  \
    ++            : "cc", "%eax"                                          \
    +             );
    + 
    ++    #define CALL_GL_API_INTERNAL_SET_RETURN_VALUE \
    ++        __asm__ volatile(                         \
    ++            "xor %%eax, %%eax\n"                  \
    ++            :                                     \
    ++            :                                     \
    ++            : "%eax"                              \
    ++        );
    ++
    ++    #define CALL_GL_API_INTERNAL_DO_RETURN \
    ++        __asm__ volatile(                  \
    ++            "ret\n"                        \
    ++            :                              \
    ++            :                              \
    ++            :                              \
    ++        );
    ++
    + #elif defined(__x86_64__)
    + 
    +-    #define API_ENTRY(_api) __attribute__((noinline,optimize("omit-frame-pointer"))) _api
    ++    #define API_ENTRY(_api) __attribute__((naked,noinline)) _api
    + 
    +-    #define CALL_GL_API(_api, ...)                                  \
    +-         register void** fn;                                        \
    +-         __asm__ volatile(                                          \
    +-            "mov %%fs:0, %[fn]\n"                                   \
    +-            "mov %P[tls](%[fn]), %[fn]\n"                           \
    +-            "test %[fn], %[fn]\n"                                   \
    ++    #define CALL_GL_API_INTERNAL_CALL(_api, ...)                    \
    ++        __asm__ volatile(                                           \
    ++            "mov %%fs:0, %%rax\n"                                   \
    ++            "mov %P[tls](%%rax), %%rax\n"                           \
    ++            "test %%rax, %%rax\n"                                   \
    +             "je 1f\n"                                               \
    +-            "jmp *%P[api](%[fn])\n"                                 \
    ++            "jmp *%P[api](%%rax)\n"                                 \
    +             "1:\n"                                                  \
    +-            : [fn] "=r" (fn)                                        \
    ++            :                                                       \
    +             : [tls] "i" (TLS_SLOT_OPENGL_API*sizeof(void*)),        \
    +               [api] "i" (__builtin_offsetof(gl_hooks_t, gl._api))   \
    +-            : "cc"                                                  \
    +-            );
     +            : "cc", "%rdi", "%rsi", "%rdx", "%rcx", "%r8", "%r9",   \
     +              "%xmm0", "%xmm1", "%xmm2", "%xmm3", "%xmm4", "%xmm5", \
     +              "%xmm6", "%xmm7"                                      \
    -             );
    ++        );
    ++
    ++    #define CALL_GL_API_INTERNAL_SET_RETURN_VALUE \
    ++        __asm__ volatile(                         \
    ++            "xor %%eax, %%eax\n"                  \
    ++            :                                     \
    ++            :                                     \
    ++            : "%eax"                              \
    ++        );
    ++
    ++    #define CALL_GL_API_INTERNAL_DO_RETURN \
    ++        __asm__ volatile(                  \
    ++            "retq\n"                       \
    ++            :                              \
    ++            :                              \
    ++            :                              \
    ++        );
      
      #elif defined(__mips64)
    -@@ -148,7 +150,7 @@ using namespace android;
    -           [v0] "=&r"(_v0)                                     \
    -         : [OPENGL_API] "I"(TLS_SLOT_OPENGL_API*sizeof(void*)),\
    -           [API] "I"(__builtin_offsetof(gl_hooks_t, gl._api))  \
    + 
    +-    #define API_ENTRY(_api) __attribute__((noinline)) _api
    +-
    +-    #define CALL_GL_API(_api, ...)                            \
    +-    register unsigned long _t0 asm("$12");                    \
    +-    register unsigned long _fn asm("$25");                    \
    +-    register unsigned long _tls asm("$3");                    \
    +-    register unsigned long _v0 asm("$2");                     \
    +-    asm volatile(                                             \
    +-        ".set  push\n\t"                                      \
    +-        ".set  noreorder\n\t"                                 \
    +-        "rdhwr %[tls], $29\n\t"                               \
    +-        "ld    %[t0], %[OPENGL_API](%[tls])\n\t"              \
    +-        "beqz  %[t0], 1f\n\t"                                 \
    +-        " move %[fn], $ra\n\t"                                \
    +-        "ld    %[t0], %[API](%[t0])\n\t"                      \
    +-        "beqz  %[t0], 1f\n\t"                                 \
    +-        " nop\n\t"                                            \
    +-        "move  %[fn], %[t0]\n\t"                              \
    +-        "1:\n\t"                                              \
    +-        "jalr  $0, %[fn]\n\t"                                 \
    +-        " move %[v0], $0\n\t"                                 \
    +-        ".set  pop\n\t"                                       \
    +-        : [fn] "=c"(_fn),                                     \
    +-          [tls] "=&r"(_tls),                                  \
    +-          [t0] "=&r"(_t0),                                    \
    +-          [v0] "=&r"(_v0)                                     \
    +-        : [OPENGL_API] "I"(TLS_SLOT_OPENGL_API*sizeof(void*)),\
    +-          [API] "I"(__builtin_offsetof(gl_hooks_t, gl._api))  \
     -        :                                                     \
    -+        : "$4", "$5", "$6", "$7", "$8", "$9", "$10", "$11"    \
    ++    #define API_ENTRY(_api) __attribute__((naked,noinline)) _api
    ++
    ++    // t0:  $12
    ++    // fn:  $25
    ++    // tls: $3
    ++    // v0:  $2
    ++    #define CALL_GL_API_INTERNAL_CALL(_api, ...)                  \
    ++        asm volatile(                                             \
    ++            ".set  push\n\t"                                      \
    ++            ".set  noreorder\n\t"                                 \
    ++            "rdhwr $3, $29\n\t"                                   \
    ++            "ld    $12, %[OPENGL_API]($3)\n\t"                    \
    ++            "beqz  $12, 1f\n\t"                                   \
    ++            " move $25, $ra\n\t"                                  \
    ++            "ld    $12, %[API]($12)\n\t"                          \
    ++            "beqz  $12, 1f\n\t"                                   \
    ++            " nop\n\t"                                            \
    ++            "move  $25, $12\n\t"                                  \
    ++            "1:\n\t"                                              \
    ++            "jalr  $0, $25\n\t"                                   \
    ++            " move $2, $0\n\t"                                    \
    ++            ".set  pop\n\t"                                       \
    ++            :                                                     \
    ++            : [OPENGL_API] "I"(TLS_SLOT_OPENGL_API*sizeof(void*)),\
    ++              [API] "I"(__builtin_offsetof(gl_hooks_t, gl._api))  \
    ++            : "$2", "$3", "$4", "$5", "$6", "$7", "$8", "$9",     \
    ++              "$10", "$11", "$12", "$25"                          \
              );
      
    ++    #define CALL_GL_API_INTERNAL_SET_RETURN_VALUE
    ++    #define CALL_GL_API_INTERNAL_DO_RETURN
    ++
      #elif defined(__mips__)
    -@@ -182,7 +184,7 @@ using namespace android;
    -               [v0] "=&r"(_v0)                                    \
    + 
    +-    #define API_ENTRY(_api) __attribute__((noinline)) _api
    ++    #define API_ENTRY(_api) __attribute__((naked,noinline)) _api
    + 
    +-    #define CALL_GL_API(_api, ...)                               \
    +-        register unsigned int _t0 asm("$8");                     \
    +-        register unsigned int _fn asm("$25");                    \
    +-        register unsigned int _tls asm("$3");                    \
    +-        register unsigned int _v0 asm("$2");                     \
    ++    // t0:  $8
    ++    // fn:  $25
    ++    // tls: $3
    ++    // v0:  $2
    ++    #define CALL_GL_API_INTERNAL_CALL(_api, ...)                 \
    +         asm volatile(                                            \
    +             ".set  push\n\t"                                     \
    +             ".set  noreorder\n\t"                                \
    +             ".set  mips32r2\n\t"                                 \
    +-            "rdhwr %[tls], $29\n\t"                              \
    +-            "lw    %[t0], %[OPENGL_API](%[tls])\n\t"             \
    +-            "beqz  %[t0], 1f\n\t"                                \
    +-            " move %[fn],$ra\n\t"                                \
    +-            "lw    %[t0], %[API](%[t0])\n\t"                     \
    +-            "beqz  %[t0], 1f\n\t"                                \
    ++            "rdhwr $3, $29\n\t"                                  \
    ++            "lw    $3, %[OPENGL_API]($3)\n\t"                    \
    ++            "beqz  $3, 1f\n\t"                                   \
    ++            " move $25,$ra\n\t"                                  \
    ++            "lw    $3, %[API]($3)\n\t"                           \
    ++            "beqz  $3, 1f\n\t"                                   \
    +             " nop\n\t"                                           \
    +-            "move  %[fn], %[t0]\n\t"                             \
    ++            "move  $25, $3\n\t"                                  \
    +             "1:\n\t"                                             \
    +-            "jalr  $0, %[fn]\n\t"                                \
    +-            " move %[v0], $0\n\t"                                \
    ++            "jalr  $0, $25\n\t"                                  \
    ++            " move $2, $0\n\t"                                   \
    +             ".set  pop\n\t"                                      \
    +-            : [fn] "=c"(_fn),                                    \
    +-              [tls] "=&r"(_tls),                                 \
    +-              [t0] "=&r"(_t0),                                   \
    +-              [v0] "=&r"(_v0)                                    \
    ++            :                                                    \
                  : [OPENGL_API] "I"(TLS_SLOT_OPENGL_API*4),           \
                    [API] "I"(__builtin_offsetof(gl_hooks_t, gl._api)) \
     -            :                                                    \
    -+            : "$4", "$5", "$6", "$7"                             \
    -             );
    +-            );
    ++            : "$2", "$3", "$4", "$5", "$6", "$7", "$8", "$25"    \
    ++        );
      
    - #endif
    +-#endif
    ++    #define CALL_GL_API_INTERNAL_SET_RETURN_VALUE
    ++    #define CALL_GL_API_INTERNAL_DO_RETURN
    + 
    +-#define CALL_GL_API_RETURN(_api, ...) \
    +-    CALL_GL_API(_api, __VA_ARGS__) \
    +-    return 0;
    ++#endif
    + 
    ++#define CALL_GL_API(_api, ...) \
    ++    CALL_GL_API_INTERNAL_CALL(_api, __VA_ARGS__) \
    ++    CALL_GL_API_INTERNAL_DO_RETURN
    + 
    ++#define CALL_GL_API_RETURN(_api, ...) \
    ++    CALL_GL_API_INTERNAL_CALL(_api, __VA_ARGS__) \
    ++    CALL_GL_API_INTERNAL_SET_RETURN_VALUE \
    ++    CALL_GL_API_INTERNAL_DO_RETURN
    + 
    + extern "C" {
    + #pragma GCC diagnostic ignored "-Wunused-parameter"
    +@@ -202,6 +280,9 @@ extern "C" {
    + 
    + #undef API_ENTRY
    + #undef CALL_GL_API
    ++#undef CALL_GL_API_INTERNAL_CALL
    ++#undef CALL_GL_API_INTERNAL_SET_RETURN_VALUE
    ++#undef CALL_GL_API_INTERNAL_DO_RETURN
    + #undef CALL_GL_API_RETURN
    + 
    + /*
     diff --git a/opengl/libs/GLES_CM/gl.cpp b/opengl/libs/GLES_CM/gl.cpp
    -index b1b31f8..fc7f2e1 100644
    +index b1b31f8..8bde4e5 100644
     --- a/opengl/libs/GLES_CM/gl.cpp
     +++ b/opengl/libs/GLES_CM/gl.cpp
    -@@ -115,7 +115,7 @@ GL_API void GL_APIENTRY glWeightPointerOESBounds(GLint size, GLenum type,
    -             :                                                   \
    -             : [tls] "J"(TLS_SLOT_OPENGL_API*4),                 \
    -               [api] "J"(__builtin_offsetof(gl_hooks_t, gl._api))    \
    +@@ -90,39 +90,65 @@ GL_API void GL_APIENTRY glWeightPointerOESBounds(GLint size, GLenum type,
    + 
    + #undef API_ENTRY
    + #undef CALL_GL_API
    ++#undef CALL_GL_API_INTERNAL_CALL
    ++#undef CALL_GL_API_INTERNAL_SET_RETURN_VALUE
    ++#undef CALL_GL_API_INTERNAL_DO_RETURN
    + #undef CALL_GL_API_RETURN
    + 
    + #if USE_SLOW_BINDING
    + 
    +     #define API_ENTRY(_api) _api
    + 
    +-    #define CALL_GL_API(_api, ...)                                       \
    ++    #define CALL_GL_API_INTERNAL_CALL(_api, ...)                         \
    +         gl_hooks_t::gl_t const * const _c = &getGlThreadSpecific()->gl;  \
    +         if (_c) return _c->_api(__VA_ARGS__);
    + 
    ++    #define CALL_GL_API_INTERNAL_SET_RETURN_VALUE return 0;
    ++
    ++    // This stays blank, since void functions will implicitly return, and
    ++    // all of the other functions will return 0 based on the previous macro.
    ++    #define CALL_GL_API_INTERNAL_DO_RETURN
    ++
    + #elif defined(__arm__)
    + 
    +     #define GET_TLS(reg) "mrc p15, 0, " #reg ", c13, c0, 3 \n"
    + 
    +-    #define API_ENTRY(_api) __attribute__((noinline)) _api
    ++    #define API_ENTRY(_api) __attribute__((naked,noinline)) _api
    + 
    +-    #define CALL_GL_API(_api, ...)                              \
    +-         asm volatile(                                          \
    +-            GET_TLS(r12)                                        \
    +-            "ldr   r12, [r12, %[tls]] \n"                       \
    +-            "cmp   r12, #0            \n"                       \
    +-            "ldrne pc,  [r12, %[api]] \n"                       \
    +-            :                                                   \
    +-            : [tls] "J"(TLS_SLOT_OPENGL_API*4),                 \
    +-              [api] "J"(__builtin_offsetof(gl_hooks_t, gl._api))    \
     -            : "r12"                                             \
    -+            : "r0", "r1", "r2", "r3", "r12"                     \
    -             );
    +-            );
    ++    #define CALL_GL_API_INTERNAL_CALL(_api, ...)                 \
    ++        asm volatile(                                            \
    ++            GET_TLS(r12)                                         \
    ++            "ldr   r12, [r12, %[tls]] \n"                        \
    ++            "cmp   r12, #0            \n"                        \
    ++            "ldrne pc,  [r12, %[api]] \n"                        \
    ++            :                                                    \
    ++            : [tls] "J"(TLS_SLOT_OPENGL_API*4),                  \
    ++              [api] "J"(__builtin_offsetof(gl_hooks_t, gl._api)) \
    ++            : "r0", "r1", "r2", "r3", "r12"                      \
    ++        );
    ++
    ++    #define CALL_GL_API_INTERNAL_SET_RETURN_VALUE \
    ++        asm volatile(                             \
    ++            "mov r0, #0 \n"                       \
    ++            :                                     \
    ++            :                                     \
    ++            : "r0"                                \
    ++        );
    ++
    ++
    ++    #define CALL_GL_API_INTERNAL_DO_RETURN \
    ++        asm volatile(                      \
    ++            "bx lr \n"                     \
    ++            :                              \
    ++            :                              \
    ++            : "r0"                         \
    ++        );
      
      #elif defined(__aarch64__)
    -@@ -133,7 +133,7 @@ GL_API void GL_APIENTRY glWeightPointerOESBounds(GLint size, GLenum type,
    + 
    +-    #define API_ENTRY(_api) __attribute__((noinline)) _api
    ++    #define API_ENTRY(_api) __attribute__((naked,noinline)) _api
    + 
    +-    #define CALL_GL_API(_api, ...)                                  \
    ++    #define CALL_GL_API_INTERNAL_CALL(_api, ...)                    \
    +         asm volatile(                                               \
    +             "mrs x16, tpidr_el0\n"                                  \
    +             "ldr x16, [x16, %[tls]]\n"                              \
    +@@ -133,120 +159,173 @@ GL_API void GL_APIENTRY glWeightPointerOESBounds(GLint size, GLenum type,
                  :                                                       \
                  : [tls] "i" (TLS_SLOT_OPENGL_API * sizeof(void*)),      \
                    [api] "i" (__builtin_offsetof(gl_hooks_t, gl._api))   \
     -            : "x16"                                                 \
     +            : "x0", "x1", "x2", "x3", "x4", "x5", "x6", "x7", "x16" \
    ++        );
    ++
    ++    #define CALL_GL_API_INTERNAL_SET_RETURN_VALUE \
    ++        asm volatile(                             \
    ++            "mov w0, wzr \n"                      \
    ++            :                                     \
    ++            :                                     \
    ++            : "w0"                                \
    ++        );
    ++
    ++    #define CALL_GL_API_INTERNAL_DO_RETURN \
    ++        asm volatile(                      \
    ++            "ret \n"                       \
    ++            :                              \
    ++            :                              \
    ++            :                              \
              );
      
      #elif defined(__i386__)
    -@@ -171,7 +171,9 @@ GL_API void GL_APIENTRY glWeightPointerOESBounds(GLint size, GLenum type,
    -             : [fn] "=r" (fn)                                        \
    + 
    +-    #define API_ENTRY(_api) __attribute__((noinline,optimize("omit-frame-pointer"))) _api
    ++    #define API_ENTRY(_api) __attribute__((naked,noinline)) _api
    + 
    +-    #define CALL_GL_API(_api, ...)                                  \
    +-        register void* fn;                                          \
    ++    #define CALL_GL_API_INTERNAL_CALL(_api, ...)                    \
    +         __asm__ volatile(                                           \
    +-            "mov %%gs:0, %[fn]\n"                                   \
    +-            "mov %P[tls](%[fn]), %[fn]\n"                           \
    +-            "test %[fn], %[fn]\n"                                   \
    ++            "mov %%gs:0, %%eax\n"                                   \
    ++            "mov %P[tls](%%eax), %%eax\n"                           \
    ++            "test %%eax, %%eax\n"                                   \
    +             "je 1f\n"                                               \
    +-            "jmp *%P[api](%[fn])\n"                                 \
    ++            "jmp *%P[api](%%eax)\n"                                 \
    +             "1:\n"                                                  \
    +-            : [fn] "=r" (fn)                                        \
    ++            :                                                       \
    +             : [tls] "i" (TLS_SLOT_OPENGL_API*sizeof(void*)),        \
    +               [api] "i" (__builtin_offsetof(gl_hooks_t, gl._api))   \
    +-            : "cc"                                                  \
    +-            );
    ++            : "cc", "%eax"                                          \
    ++        );
    ++
    ++    #define CALL_GL_API_INTERNAL_SET_RETURN_VALUE \
    ++        __asm__ volatile(                         \
    ++            "xor %%eax, %%eax\n"                  \
    ++            :                                     \
    ++            :                                     \
    ++            : "%eax"                              \
    ++        );
    ++
    ++    #define CALL_GL_API_INTERNAL_DO_RETURN \
    ++        __asm__ volatile(                  \
    ++            "ret\n"                        \
    ++            :                              \
    ++            :                              \
    ++            :                              \
    ++        );
    + 
    + #elif defined(__x86_64__)
    + 
    +-    #define API_ENTRY(_api) __attribute__((noinline,optimize("omit-frame-pointer"))) _api
    ++    #define API_ENTRY(_api) __attribute__((naked,noinline)) _api
    + 
    +-    #define CALL_GL_API(_api, ...)                                  \
    +-         register void** fn;                                        \
    +-         __asm__ volatile(                                          \
    +-            "mov %%fs:0, %[fn]\n"                                   \
    +-            "mov %P[tls](%[fn]), %[fn]\n"                           \
    +-            "test %[fn], %[fn]\n"                                   \
    ++    #define CALL_GL_API_INTERNAL_CALL(_api, ...)                    \
    ++        __asm__ volatile(                                           \
    ++            "mov %%fs:0, %%rax\n"                                   \
    ++            "mov %P[tls](%%rax), %%rax\n"                           \
    ++            "test %%rax, %%rax\n"                                   \
    +             "je 1f\n"                                               \
    +-            "jmp *%P[api](%[fn])\n"                                 \
    ++            "jmp *%P[api](%%rax)\n"                                 \
    +             "1:\n"                                                  \
    +-            : [fn] "=r" (fn)                                        \
    ++            :                                                       \
                  : [tls] "i" (TLS_SLOT_OPENGL_API*sizeof(void*)),        \
                    [api] "i" (__builtin_offsetof(gl_hooks_t, gl._api))   \
     -            : "cc"                                                  \
    +-            );
     +            : "cc", "%rdi", "%rsi", "%rdx", "%rcx", "%r8", "%r9",   \
     +              "%xmm0", "%xmm1", "%xmm2", "%xmm3", "%xmm4", "%xmm5", \
     +              "%xmm6", "%xmm7"                                      \
    -             );
    ++        );
    ++
    ++    #define CALL_GL_API_INTERNAL_SET_RETURN_VALUE \
    ++        __asm__ volatile(                         \
    ++            "xor %%eax, %%eax\n"                  \
    ++            :                                     \
    ++            :                                     \
    ++            : "%eax"                              \
    ++        );
    ++
    ++    #define CALL_GL_API_INTERNAL_DO_RETURN \
    ++        __asm__ volatile(                  \
    ++            "retq\n"                       \
    ++            :                              \
    ++            :                              \
    ++            :                              \
    ++        );
      
      #elif defined(__mips64)
    -@@ -204,7 +206,7 @@ GL_API void GL_APIENTRY glWeightPointerOESBounds(GLint size, GLenum type,
    -           [v0] "=&r"(_v0)                                     \
    -         : [OPENGL_API] "I"(TLS_SLOT_OPENGL_API*sizeof(void*)),\
    -           [API] "I"(__builtin_offsetof(gl_hooks_t, gl._api))  \
    + 
    +-    #define API_ENTRY(_api) __attribute__((noinline)) _api
    +-
    +-    #define CALL_GL_API(_api, ...)                            \
    +-    register unsigned long _t0 asm("$12");                    \
    +-    register unsigned long _fn asm("$25");                    \
    +-    register unsigned long _tls asm("$3");                    \
    +-    register unsigned long _v0 asm("$2");                     \
    +-    asm volatile(                                             \
    +-        ".set  push\n\t"                                      \
    +-        ".set  noreorder\n\t"                                 \
    +-        "rdhwr %[tls], $29\n\t"                               \
    +-        "ld    %[t0], %[OPENGL_API](%[tls])\n\t"              \
    +-        "beqz  %[t0], 1f\n\t"                                 \
    +-        " move %[fn], $ra\n\t"                                \
    +-        "ld    %[t0], %[API](%[t0])\n\t"                      \
    +-        "beqz  %[t0], 1f\n\t"                                 \
    +-        " nop\n\t"                                            \
    +-        "move  %[fn], %[t0]\n\t"                              \
    +-        "1:\n\t"                                              \
    +-        "jalr  $0, %[fn]\n\t"                                 \
    +-        " move %[v0], $0\n\t"                                 \
    +-        ".set  pop\n\t"                                       \
    +-        : [fn] "=c"(_fn),                                     \
    +-          [tls] "=&r"(_tls),                                  \
    +-          [t0] "=&r"(_t0),                                    \
    +-          [v0] "=&r"(_v0)                                     \
    +-        : [OPENGL_API] "I"(TLS_SLOT_OPENGL_API*sizeof(void*)),\
    +-          [API] "I"(__builtin_offsetof(gl_hooks_t, gl._api))  \
     -        :                                                     \
    -+        : "$4", "$5", "$6", "$7", "$8", "$9", "$10", "$11"    \
    ++    #define API_ENTRY(_api) __attribute__((naked,noinline)) _api
    ++
    ++    // t0:  $12
    ++    // fn:  $25
    ++    // tls: $3
    ++    // v0:  $2
    ++    #define CALL_GL_API_INTERNAL_CALL(_api, ...)                  \
    ++        asm volatile(                                             \
    ++            ".set  push\n\t"                                      \
    ++            ".set  noreorder\n\t"                                 \
    ++            "rdhwr $3, $29\n\t"                                   \
    ++            "ld    $12, %[OPENGL_API]($3)\n\t"                    \
    ++            "beqz  $12, 1f\n\t"                                   \
    ++            " move $25, $ra\n\t"                                  \
    ++            "ld    $12, %[API]($12)\n\t"                          \
    ++            "beqz  $12, 1f\n\t"                                   \
    ++            " nop\n\t"                                            \
    ++            "move  $25, $12\n\t"                                  \
    ++            "1:\n\t"                                              \
    ++            "jalr  $0, $25\n\t"                                   \
    ++            " move $2, $0\n\t"                                    \
    ++            ".set  pop\n\t"                                       \
    ++            :                                                     \
    ++            : [OPENGL_API] "I"(TLS_SLOT_OPENGL_API*sizeof(void*)),\
    ++              [API] "I"(__builtin_offsetof(gl_hooks_t, gl._api))  \
    ++            : "$2", "$3", "$4", "$5", "$6", "$7", "$8", "$9",     \
    ++              "$10", "$11", "$12", "$25"                          \
              );
      
    ++    #define CALL_GL_API_INTERNAL_SET_RETURN_VALUE
    ++    #define CALL_GL_API_INTERNAL_DO_RETURN
    ++
      #elif defined(__mips__)
    -@@ -238,7 +240,7 @@ GL_API void GL_APIENTRY glWeightPointerOESBounds(GLint size, GLenum type,
    -               [v0] "=&r"(_v0)                                    \
    + 
    +-    #define API_ENTRY(_api) __attribute__((noinline)) _api
    ++    #define API_ENTRY(_api) __attribute__((naked,noinline)) _api
    + 
    +-    #define CALL_GL_API(_api, ...)                               \
    +-        register unsigned int _t0 asm("$8");                     \
    +-        register unsigned int _fn asm("$25");                    \
    +-        register unsigned int _tls asm("$3");                    \
    +-        register unsigned int _v0 asm("$2");                     \
    ++    // t0:  $8
    ++    // fn:  $25
    ++    // tls: $3
    ++    // v0:  $2
    ++    #define CALL_GL_API_INTERNAL_CALL(_api, ...)                 \
    +         asm volatile(                                            \
    +             ".set  push\n\t"                                     \
    +             ".set  noreorder\n\t"                                \
    +             ".set  mips32r2\n\t"                                 \
    +-            "rdhwr %[tls], $29\n\t"                              \
    +-            "lw    %[t0], %[OPENGL_API](%[tls])\n\t"             \
    +-            "beqz  %[t0], 1f\n\t"                                \
    +-            " move %[fn], $ra\n\t"                               \
    +-            "lw    %[t0], %[API](%[t0])\n\t"                     \
    +-            "beqz  %[t0], 1f\n\t"                                \
    ++            "rdhwr $3, $29\n\t"                                  \
    ++            "lw    $3, %[OPENGL_API]($3)\n\t"                    \
    ++            "beqz  $3, 1f\n\t"                                   \
    ++            " move $25,$ra\n\t"                                  \
    ++            "lw    $3, %[API]($3)\n\t"                           \
    ++            "beqz  $3, 1f\n\t"                                   \
    +             " nop\n\t"                                           \
    +-            "move  %[fn], %[t0]\n\t"                             \
    ++            "move  $25, $3\n\t"                                  \
    +             "1:\n\t"                                             \
    +-            "jalr  $0, %[fn]\n\t"                                \
    +-            " move %[v0], $0\n\t"                                \
    ++            "jalr  $0, $25\n\t"                                  \
    ++            " move $2, $0\n\t"                                   \
    +             ".set  pop\n\t"                                      \
    +-            : [fn] "=c"(_fn),                                    \
    +-              [tls] "=&r"(_tls),                                 \
    +-              [t0] "=&r"(_t0),                                   \
    +-              [v0] "=&r"(_v0)                                    \
    ++            :                                                    \
                  : [OPENGL_API] "I"(TLS_SLOT_OPENGL_API*4),           \
                    [API] "I"(__builtin_offsetof(gl_hooks_t, gl._api)) \
     -            :                                                    \
    -+            : "$4", "$5", "$6", "$7"                             \
    -             );
    +-            );
    ++            : "$2", "$3", "$4", "$5", "$6", "$7", "$8", "$25"    \
    ++        );
    ++
    ++    #define CALL_GL_API_INTERNAL_SET_RETURN_VALUE
    ++    #define CALL_GL_API_INTERNAL_DO_RETURN
      
      #endif
    + 
    +-#define CALL_GL_API_RETURN(_api, ...) \
    +-    CALL_GL_API(_api, __VA_ARGS__) \
    +-    return 0;
    ++#define CALL_GL_API(_api, ...) \
    ++    CALL_GL_API_INTERNAL_CALL(_api, __VA_ARGS__) \
    ++    CALL_GL_API_INTERNAL_DO_RETURN
    + 
    ++#define CALL_GL_API_RETURN(_api, ...) \
    ++    CALL_GL_API_INTERNAL_CALL(_api, __VA_ARGS__) \
    ++    CALL_GL_API_INTERNAL_SET_RETURN_VALUE \
    ++    CALL_GL_API_INTERNAL_DO_RETURN
    + 
    + extern "C" {
    + #pragma GCC diagnostic ignored "-Wunused-parameter"
    +@@ -257,6 +336,9 @@ extern "C" {
    + 
    + #undef API_ENTRY
    + #undef CALL_GL_API
    ++#undef CALL_GL_API_INTERNAL_CALL
    ++#undef CALL_GL_API_INTERNAL_SET_RETURN_VALUE
    ++#undef CALL_GL_API_INTERNAL_DO_RETURN
    + #undef CALL_GL_API_RETURN
    + 
    + /*
     diff --git a/services/inputflinger/InputReader.cpp b/services/inputflinger/InputReader.cpp
    -index b9be675..4dec34b 100644
    +index b9be675..eff3deb 100644
     --- a/services/inputflinger/InputReader.cpp
     +++ b/services/inputflinger/InputReader.cpp
    -@@ -6652,6 +6652,7 @@ void MultiTouchInputMapper::syncTouch(nsecs_t when, RawState* outState) {
    +@@ -2169,6 +2169,10 @@ void KeyboardInputMapper::configure(nsecs_t when,
    +             mOrientation = DISPLAY_ORIENTATION_0;
    +         }
    +     }
    ++
    ++    if (!changes || (changes & InputReaderConfiguration::CHANGE_SWAP_KEYS)) {
    ++        mSwapKeys = config->swapKeys;
    ++    }
    + }
    + 
    + void KeyboardInputMapper::configureParameters() {
    +@@ -2327,10 +2331,27 @@ void KeyboardInputMapper::processKey(nsecs_t when, bool down, int32_t scanCode,
    + 
    +     NotifyKeyArgs args(when, getDeviceId(), mSource, policyFlags,
    +             down ? AKEY_EVENT_ACTION_DOWN : AKEY_EVENT_ACTION_UP,
    +-            AKEY_EVENT_FLAG_FROM_SYSTEM, keyCode, scanCode, keyMetaState, downTime);
    ++            AKEY_EVENT_FLAG_FROM_SYSTEM, getAdjustedKeyCode(keyCode),
    ++            scanCode, keyMetaState, downTime);
    +     getListener()->notifyKey(&args);
    + }
    + 
    ++int KeyboardInputMapper::getAdjustedKeyCode(int keyCode) {
    ++    switch (keyCode) {
    ++        case AKEYCODE_BACK:
    ++            if (mSwapKeys) {
    ++                return AKEYCODE_APP_SWITCH;
    ++            }
    ++            break;
    ++        case AKEYCODE_APP_SWITCH:
    ++            if (mSwapKeys) {
    ++                return AKEYCODE_BACK;
    ++            }
    ++            break;
    ++    }
    ++    return keyCode;
    ++}
    ++
    + ssize_t KeyboardInputMapper::findKeyDown(int32_t scanCode) {
    +     size_t n = mKeyDowns.size();
    +     for (size_t i = 0; i < n; i++) {
    +@@ -6652,6 +6673,7 @@ void MultiTouchInputMapper::syncTouch(nsecs_t when, RawState* outState) {
          size_t inCount = mMultiTouchMotionAccumulator.getSlotCount();
          size_t outCount = 0;
          BitSet32 newPointerIdBits;
    @@ -898,7 +1627,7 @@ index b9be675..4dec34b 100644
      
          for (size_t inIndex = 0; inIndex < inCount; inIndex++) {
              const MultiTouchMotionAccumulator::Slot* inSlot =
    -@@ -6696,33 +6697,33 @@ void MultiTouchInputMapper::syncTouch(nsecs_t when, RawState* outState) {
    +@@ -6696,33 +6718,33 @@ void MultiTouchInputMapper::syncTouch(nsecs_t when, RawState* outState) {
              outPointer.isHovering = isHovering;
      
              // Assign pointer id using tracking id if available.
    @@ -955,6 +1684,58 @@ index b9be675..4dec34b 100644
              outCount += 1;
          }
      
    +diff --git a/services/inputflinger/InputReader.h b/services/inputflinger/InputReader.h
    +index 076f3d6..52cfb72 100644
    +--- a/services/inputflinger/InputReader.h
    ++++ b/services/inputflinger/InputReader.h
    +@@ -144,6 +144,9 @@ struct InputReaderConfiguration {
    +         // The presence of an external stylus has changed.
    +         CHANGE_EXTERNAL_STYLUS_PRESENCE = 1 << 7,
    + 
    ++        // Swap keys changed.
    ++        CHANGE_SWAP_KEYS = 1 << 8,
    ++
    +         // All devices must be reopened.
    +         CHANGE_MUST_REOPEN = 1 << 31,
    +     };
    +@@ -231,6 +234,9 @@ struct InputReaderConfiguration {
    +     // True to show the location of touches on the touch screen as spots.
    +     bool showTouches;
    + 
    ++    // Swap back with recents button
    ++    bool swapKeys;
    ++
    +     InputReaderConfiguration() :
    +             virtualKeyQuietTime(0),
    +             pointerVelocityControlParameters(1.0f, 500.0f, 3000.0f, 3.0f),
    +@@ -247,7 +253,8 @@ struct InputReaderConfiguration {
    +             pointerGestureSwipeMaxWidthRatio(0.25f),
    +             pointerGestureMovementSpeedRatio(0.8f),
    +             pointerGestureZoomSpeedRatio(0.3f),
    +-            showTouches(false) { }
    ++            showTouches(false),
    ++            swapKeys(false) { }
    + 
    +     bool getDisplayInfo(bool external, DisplayViewport* outViewport) const;
    +     void setDisplayInfo(bool external, const DisplayViewport& viewport);
    +@@ -1136,6 +1143,8 @@ private:
    + 
    +     int32_t mOrientation; // orientation for dpad keys
    + 
    ++    bool mSwapKeys; // swap back with recents button
    ++
    +     Vector<KeyDown> mKeyDowns; // keys that are down
    +     int32_t mMetaState;
    +     nsecs_t mDownTime; // time of most recent key down
    +@@ -1166,6 +1175,8 @@ private:
    + 
    +     bool updateMetaStateIfNeeded(int32_t keyCode, bool down);
    + 
    ++    int getAdjustedKeyCode(int keyCode);
    ++
    +     ssize_t findKeyDown(int32_t scanCode);
    + 
    +     void resetLedState();
     diff --git a/services/inputflinger/InputWindow.h b/services/inputflinger/InputWindow.h
     index e243637..4794b47 100644
     --- a/services/inputflinger/InputWindow.h
    @@ -969,7 +1750,7 @@ index e243637..4794b47 100644
              LAST_SYSTEM_WINDOW      = 2999,
          };
     diff --git a/services/surfaceflinger/Android.mk b/services/surfaceflinger/Android.mk
    -index ffda035..cb292ef 100644
    +index ffda035..3f96b35 100644
     --- a/services/surfaceflinger/Android.mk
     +++ b/services/surfaceflinger/Android.mk
     @@ -56,6 +56,9 @@ else
    @@ -982,6 +1763,37 @@ index ffda035..cb292ef 100644
      ifeq ($(TARGET_BOARD_PLATFORM),omap4)
          LOCAL_CFLAGS += -DHAS_CONTEXT_PRIORITY
      endif
    +@@ -99,16 +102,28 @@ endif
    + # [1] https://developer.android.com/studio/profile/systrace.html
    + # [2] https://developer.android.com/training/testing/performance.html
    + 
    ++# On HWC2, SurfaceFlinger races against hardware vsync on untuned video-mode
    ++# panels, which can result in a significant number of dropped frames. HWC1
    ++# does not have this issue, so set the offsets to 1ms on HWC2 and 0ms for HWC1.
    ++
    + ifneq ($(VSYNC_EVENT_PHASE_OFFSET_NS),)
    +     LOCAL_CFLAGS += -DVSYNC_EVENT_PHASE_OFFSET_NS=$(VSYNC_EVENT_PHASE_OFFSET_NS)
    + else
    +-    LOCAL_CFLAGS += -DVSYNC_EVENT_PHASE_OFFSET_NS=1000000
    ++    ifeq ($(TARGET_USES_HWC2),true)
    ++        LOCAL_CFLAGS += -DVSYNC_EVENT_PHASE_OFFSET_NS=1000000
    ++    else
    ++        LOCAL_CFLAGS += -DVSYNC_EVENT_PHASE_OFFSET_NS=0
    ++    endif
    + endif
    + 
    + ifneq ($(SF_VSYNC_EVENT_PHASE_OFFSET_NS),)
    +     LOCAL_CFLAGS += -DSF_VSYNC_EVENT_PHASE_OFFSET_NS=$(SF_VSYNC_EVENT_PHASE_OFFSET_NS)
    + else
    +-    LOCAL_CFLAGS += -DSF_VSYNC_EVENT_PHASE_OFFSET_NS=1000000
    ++    ifeq ($(TARGET_USES_HWC2),true)
    ++        LOCAL_CFLAGS += -DSF_VSYNC_EVENT_PHASE_OFFSET_NS=1000000
    ++    else
    ++        LOCAL_CFLAGS += -DSF_VSYNC_EVENT_PHASE_OFFSET_NS=0
    ++    endif
    + endif
    + 
    + ifneq ($(PRESENT_TIME_OFFSET_FROM_VSYNC_NS),)
     diff --git a/services/surfaceflinger/DisplayDevice.cpp b/services/surfaceflinger/DisplayDevice.cpp
     index 5c2c0ad..1f2e554 100644
     --- a/services/surfaceflinger/DisplayDevice.cpp
    @@ -1041,10 +1853,29 @@ index 2190466..8c36d85 100644
                  mSinkBufferWidth, mSinkBufferHeight, format, usage);
          if (result < 0)
     diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
    -index 3ffa655..3bb26ee 100644
    +index 3ffa655..f8de24d 100644
     --- a/services/surfaceflinger/Layer.cpp
     +++ b/services/surfaceflinger/Layer.cpp
    -@@ -2056,11 +2056,16 @@ Region Layer::latchBuffer(bool& recomputeVisibleRegions)
    +@@ -55,6 +55,7 @@
    + 
    + #define DEBUG_RESIZE    0
    + 
    ++#define MAX_POSITION 32767
    + namespace android {
    + 
    + // ---------------------------------------------------------------------------
    +@@ -1574,6 +1575,10 @@ uint32_t Layer::setTransactionFlags(uint32_t flags) {
    + bool Layer::setPosition(float x, float y, bool immediate) {
    +     if (mCurrentState.requested.transform.tx() == x && mCurrentState.requested.transform.ty() == y)
    +         return false;
    ++    if ((y > MAX_POSITION) || (x > MAX_POSITION)) {
    ++        ALOGE("%s:: failed %s  x = %f y = %f",__FUNCTION__,mName.string(),x, y);
    ++        return false;
    ++    }
    +     mCurrentState.sequence++;
    + 
    +     // We update the requested and active position simultaneously because
    +@@ -2056,11 +2061,16 @@ Region Layer::latchBuffer(bool& recomputeVisibleRegions)
      
                  // Remove any stale buffers that have been dropped during
                  // updateTexImage
    diff --git a/system_bt.patch b/system_bt.patch
    index 8729075..fb68cea 100644
    --- a/system_bt.patch
    +++ b/system_bt.patch
    @@ -26,6 +26,780 @@ index 1995478..b1678d8 100644
              p_new_buf = (BT_HDR *)osi_malloc(PAN_BUF_SIZE);
              memcpy((UINT8 *)(p_new_buf + 1) + sizeof(tBTA_PAN_DATA_PARAMS),
                     (UINT8 *)(p_buf + 1) + p_buf->offset, p_buf->len);
    +diff --git a/btif/src/btif_sdp_server.cc b/btif/src/btif_sdp_server.cc
    +new file mode 100644
    +index 0000000..b84d694
    +--- /dev/null
    ++++ b/btif/src/btif_sdp_server.cc
    +@@ -0,0 +1,768 @@
    ++/******************************************************************************
    ++ *
    ++ * Copyright (C) 2014 Samsung System LSI
    ++ *
    ++ *  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.
    ++ *
    ++ ******************************************************************************/
    ++
    ++/*******************************************************************************
    ++ *
    ++ *  Filename:      btif_sdp_server.cc
    ++ *  Description:   SDP server Bluetooth Interface to create and remove SDP
    ++ *                 records.
    ++ *                 To be used in combination with the RFCOMM/L2CAP(LE) sockets.
    ++ *
    ++ *
    ++ ******************************************************************************/
    ++
    ++#define LOG_TAG "bt_btif_sdp_server"
    ++
    ++#include <pthread.h>
    ++#include <stdlib.h>
    ++#include <string.h>
    ++
    ++#include <mutex>
    ++
    ++#include <hardware/bluetooth.h>
    ++#include <hardware/bt_sdp.h>
    ++
    ++#include "bta_sdp_api.h"
    ++#include "bta_sys.h"
    ++#include "btif_common.h"
    ++#include "btif_sock_util.h"
    ++#include "btif_util.h"
    ++#include "osi/include/allocator.h"
    ++#include "utl.h"
    ++
    ++// Protects the sdp_slots array from concurrent access.
    ++static std::recursive_mutex sdp_lock;
    ++
    ++/**
    ++ * The need for a state variable have been reduced to two states.
    ++ * The remaining state control is handled by program flow
    ++ */
    ++typedef enum {
    ++  SDP_RECORD_FREE = 0,
    ++  SDP_RECORD_ALLOCED,
    ++} sdp_state_t;
    ++
    ++typedef struct {
    ++  sdp_state_t state;
    ++  int sdp_handle;
    ++  bluetooth_sdp_record* record_data;
    ++} sdp_slot_t;
    ++
    ++#define MAX_SDP_SLOTS 128
    ++static sdp_slot_t sdp_slots[MAX_SDP_SLOTS];
    ++
    ++/*****************************************************************************
    ++ * LOCAL Functions
    ++ *****************************************************************************/
    ++static int add_maps_sdp(const bluetooth_sdp_mas_record* rec);
    ++static int add_mapc_sdp(const bluetooth_sdp_mns_record* rec);
    ++static int add_pbaps_sdp(const bluetooth_sdp_pse_record* rec);
    ++static int add_opps_sdp(const bluetooth_sdp_ops_record* rec);
    ++static int add_saps_sdp(const bluetooth_sdp_sap_record* rec);
    ++bt_status_t remove_sdp_record(int record_id);
    ++static int free_sdp_slot(int id);
    ++
    ++/******************************************************************************
    ++ * WARNING: Functions below are not called in BTU context.
    ++ * Introduced to make it possible to create SDP records from JAVA with both a
    ++ * RFCOMM channel and a L2CAP PSM.
    ++ * Overall architecture:
    ++ *  1) JAVA calls createRecord() which returns a pseudo ID which at a later
    ++ *     point will be linked to a specific SDP handle.
    ++ *  2) createRecord() requests the BTU task(thread) to call a callback in SDP
    ++ *     which creates the actual record, and updates the ID<->SDPHandle map
    ++ *     based on the ID beeing passed to BTA as user_data.
    ++ *****************************************************************************/
    ++
    ++static void init_sdp_slots() {
    ++  int i;
    ++  memset(sdp_slots, 0, sizeof(sdp_slot_t) * MAX_SDP_SLOTS);
    ++  /* if SDP_RECORD_FREE is zero - no need to set the value */
    ++  if (SDP_RECORD_FREE != 0) {
    ++    for (i = 0; i < MAX_SDP_SLOTS; i++) {
    ++      sdp_slots[i].state = SDP_RECORD_FREE;
    ++    }
    ++  }
    ++}
    ++
    ++bt_status_t sdp_server_init() {
    ++  BTIF_TRACE_DEBUG("Sdp Server %s", __func__);
    ++  init_sdp_slots();
    ++  return BT_STATUS_SUCCESS;
    ++}
    ++
    ++void sdp_server_cleanup() {
    ++  BTIF_TRACE_DEBUG("Sdp Server %s", __func__);
    ++  std::unique_lock<std::recursive_mutex> lock(sdp_lock);
    ++  int i;
    ++  for (i = 0; i < MAX_SDP_SLOTS; i++) {
    ++    /*remove_sdp_record(i); we cannot send messages to the other threads, since
    ++    * they might
    ++    *                       have been shut down already. Just do local cleanup.
    ++    */
    ++    free_sdp_slot(i);
    ++  }
    ++}
    ++
    ++int get_sdp_records_size(bluetooth_sdp_record* in_record, int count) {
    ++  bluetooth_sdp_record* record = in_record;
    ++  int records_size = 0;
    ++  int i;
    ++  for (i = 0; i < count; i++) {
    ++    record = &in_record[i];
    ++    records_size += sizeof(bluetooth_sdp_record);
    ++    records_size += record->hdr.service_name_length;
    ++    if (record->hdr.service_name_length > 0) {
    ++      records_size++; /* + '\0' termination of string */
    ++    }
    ++    records_size += record->hdr.user1_ptr_len;
    ++    records_size += record->hdr.user2_ptr_len;
    ++  }
    ++  return records_size;
    ++}
    ++
    ++/* Deep copy all content of in_records into out_records.
    ++ * out_records must point to a chunk of memory large enough to contain all
    ++ * the data. Use getSdpRecordsSize() to calculate the needed size. */
    ++void copy_sdp_records(bluetooth_sdp_record* in_records,
    ++                      bluetooth_sdp_record* out_records, int count) {
    ++  int i;
    ++  bluetooth_sdp_record* in_record;
    ++  bluetooth_sdp_record* out_record;
    ++  char* free_ptr =
    ++      (char*)(&out_records[count]); /* set pointer to after the last entry */
    ++
    ++  for (i = 0; i < count; i++) {
    ++    in_record = &in_records[i];
    ++    out_record = &out_records[i];
    ++    *out_record = *in_record;
    ++
    ++    if (in_record->hdr.service_name == NULL ||
    ++        in_record->hdr.service_name_length == 0) {
    ++      out_record->hdr.service_name = NULL;
    ++      out_record->hdr.service_name_length = 0;
    ++    } else {
    ++      out_record->hdr.service_name = free_ptr;  // Update service_name pointer
    ++      // Copy string
    ++      memcpy(free_ptr, in_record->hdr.service_name,
    ++             in_record->hdr.service_name_length);
    ++      free_ptr += in_record->hdr.service_name_length;
    ++      *(free_ptr) = '\0';  // Set '\0' termination of string
    ++      free_ptr++;
    ++    }
    ++    if (in_record->hdr.user1_ptr != NULL) {
    ++      out_record->hdr.user1_ptr = (uint8_t*)free_ptr;  // Update pointer
    ++      memcpy(free_ptr, in_record->hdr.user1_ptr,
    ++             in_record->hdr.user1_ptr_len);  // Copy content
    ++      free_ptr += in_record->hdr.user1_ptr_len;
    ++    }
    ++    if (in_record->hdr.user2_ptr != NULL) {
    ++      out_record->hdr.user2_ptr = (uint8_t*)free_ptr;  // Update pointer
    ++      memcpy(free_ptr, in_record->hdr.user2_ptr,
    ++             in_record->hdr.user2_ptr_len);  // Copy content
    ++      free_ptr += in_record->hdr.user2_ptr_len;
    ++    }
    ++  }
    ++  return;
    ++}
    ++
    ++/* Reserve a slot in sdp_slots, copy data and set a reference to the copy.
    ++ * The record_data will contain both the record and any data pointed to by
    ++ * the record.
    ++ * Currently this covers:
    ++ *   service_name string,
    ++ *   user1_ptr and
    ++ *   user2_ptr. */
    ++static int alloc_sdp_slot(bluetooth_sdp_record* in_record) {
    ++  int record_size = get_sdp_records_size(in_record, 1);
    ++  /* We are optimists here, and preallocate the record.
    ++   * This is to reduce the time we hold the sdp_lock. */
    ++  bluetooth_sdp_record* record = (bluetooth_sdp_record*)osi_malloc(record_size);
    ++
    ++  copy_sdp_records(in_record, record, 1);
    ++  {
    ++    std::unique_lock<std::recursive_mutex> lock(sdp_lock);
    ++    for (int i = 0; i < MAX_SDP_SLOTS; i++) {
    ++      if (sdp_slots[i].state == SDP_RECORD_FREE) {
    ++        sdp_slots[i].state = SDP_RECORD_ALLOCED;
    ++        sdp_slots[i].record_data = record;
    ++        return i;
    ++      }
    ++    }
    ++  }
    ++  APPL_TRACE_ERROR("%s() failed - no more free slots!", __func__);
    ++  /* Rearly the optimist is too optimistic, and cleanup is needed...*/
    ++  osi_free(record);
    ++  return -1;
    ++}
    ++
    ++static int free_sdp_slot(int id) {
    ++  int handle = -1;
    ++  bluetooth_sdp_record* record = NULL;
    ++  if (id < 0 || id >= MAX_SDP_SLOTS) {
    ++    android_errorWriteLog(0x534e4554, "37502513");
    ++    APPL_TRACE_ERROR("%s() failed - id %d is invalid", __func__, id);
    ++    return handle;
    ++  }
    ++
    ++  {
    ++    std::unique_lock<std::recursive_mutex> lock(sdp_lock);
    ++    handle = sdp_slots[id].sdp_handle;
    ++    sdp_slots[id].sdp_handle = 0;
    ++    if (sdp_slots[id].state != SDP_RECORD_FREE) {
    ++      /* safe a copy of the pointer, and free after unlock() */
    ++      record = sdp_slots[id].record_data;
    ++    }
    ++    sdp_slots[id].state = SDP_RECORD_FREE;
    ++  }
    ++
    ++  if (record != NULL) {
    ++    osi_free(record);
    ++  } else {
    ++    // Record have already been freed
    ++    handle = -1;
    ++  }
    ++  return handle;
    ++}
    ++
    ++/***
    ++ * Use this to get a reference to a SDP slot AND change the state to
    ++ * SDP_RECORD_CREATE_INITIATED.
    ++ */
    ++static const sdp_slot_t* start_create_sdp(int id) {
    ++  if (id >= MAX_SDP_SLOTS) {
    ++    APPL_TRACE_ERROR("%s() failed - id %d is invalid", __func__, id);
    ++    return NULL;
    ++  }
    ++
    ++  std::unique_lock<std::recursive_mutex> lock(sdp_lock);
    ++  if (sdp_slots[id].state != SDP_RECORD_ALLOCED) {
    ++    /* The record have been removed before this event occurred - e.g. deinit */
    ++    APPL_TRACE_ERROR(
    ++        "%s() failed - state for id %d is "
    ++        "sdp_slots[id].state = %d expected %d",
    ++        __func__, id, sdp_slots[id].state, SDP_RECORD_ALLOCED);
    ++    return NULL;
    ++  }
    ++
    ++  return &(sdp_slots[id]);
    ++}
    ++
    ++static void set_sdp_handle(int id, int handle) {
    ++  std::unique_lock<std::recursive_mutex> lock(sdp_lock);
    ++  sdp_slots[id].sdp_handle = handle;
    ++  BTIF_TRACE_DEBUG("%s() id=%d to handle=0x%08x", __func__, id, handle);
    ++}
    ++
    ++bt_status_t create_sdp_record(bluetooth_sdp_record* record,
    ++                              int* record_handle) {
    ++  int handle;
    ++
    ++  handle = alloc_sdp_slot(record);
    ++  BTIF_TRACE_DEBUG("%s() handle = 0x%08x", __func__, handle);
    ++
    ++  if (handle < 0) return BT_STATUS_FAIL;
    ++
    ++  BTA_SdpCreateRecordByUser(INT_TO_PTR(handle));
    ++
    ++  *record_handle = handle;
    ++
    ++  return BT_STATUS_SUCCESS;
    ++}
    ++
    ++bt_status_t remove_sdp_record(int record_id) {
    ++  int handle;
    ++
    ++  /* Get the Record handle, and free the slot */
    ++  handle = free_sdp_slot(record_id);
    ++  BTIF_TRACE_DEBUG("Sdp Server %s id=%d to handle=0x%08x", __func__, record_id,
    ++                   handle);
    ++
    ++  /* Pass the actual record handle */
    ++  if (handle > 0) {
    ++    BTA_SdpRemoveRecordByUser(INT_TO_PTR(handle));
    ++    return BT_STATUS_SUCCESS;
    ++  }
    ++  BTIF_TRACE_DEBUG("Sdp Server %s - record already removed - or never created",
    ++                   __func__);
    ++  return BT_STATUS_FAIL;
    ++}
    ++
    ++/******************************************************************************
    ++ * CALLBACK FUNCTIONS
    ++ * Called in BTA context to create/remove SDP records.
    ++ ******************************************************************************/
    ++
    ++void on_create_record_event(int id) {
    ++  /*
    ++   * 1) Fetch the record pointer, and change its state?
    ++   * 2) switch on the type to create the correct record
    ++   * 3) Update state on completion
    ++   * 4) What to do at fail?
    ++   * */
    ++  BTIF_TRACE_DEBUG("Sdp Server %s", __func__);
    ++  const sdp_slot_t* sdp_slot = start_create_sdp(id);
    ++  /* In the case we are shutting down, sdp_slot is NULL */
    ++  if (sdp_slot != NULL) {
    ++    bluetooth_sdp_record* record = sdp_slot->record_data;
    ++    int handle = -1;
    ++    switch (record->hdr.type) {
    ++      case SDP_TYPE_MAP_MAS:
    ++        handle = add_maps_sdp(&record->mas);
    ++        break;
    ++      case SDP_TYPE_MAP_MNS:
    ++        handle = add_mapc_sdp(&record->mns);
    ++        break;
    ++      case SDP_TYPE_PBAP_PSE:
    ++        handle = add_pbaps_sdp(&record->pse);
    ++        break;
    ++      case SDP_TYPE_OPP_SERVER:
    ++        handle = add_opps_sdp(&record->ops);
    ++        break;
    ++      case SDP_TYPE_SAP_SERVER:
    ++        handle = add_saps_sdp(&record->sap);
    ++        break;
    ++      case SDP_TYPE_PBAP_PCE:
    ++      //        break; not yet supported
    ++      default:
    ++        BTIF_TRACE_DEBUG("Record type %d is not supported", record->hdr.type);
    ++        break;
    ++    }
    ++    if (handle != -1) {
    ++      set_sdp_handle(id, handle);
    ++    }
    ++  }
    ++}
    ++
    ++void on_remove_record_event(int handle) {
    ++  BTIF_TRACE_DEBUG("Sdp Server %s", __func__);
    ++
    ++  // User data carries the actual SDP handle, not the ID.
    ++  if (handle != -1 && handle != 0) {
    ++    bool result;
    ++    result = SDP_DeleteRecord(handle);
    ++    if (result == false) {
    ++      BTIF_TRACE_ERROR("  Unable to remove handle 0x%08x", handle);
    ++    }
    ++  }
    ++}
    ++
    ++/****
    ++ * Below the actual functions accessing BTA context data - hence only call from
    ++ * BTA context!
    ++ */
    ++
    ++/* Create a MAP MAS SDP record based on information stored in a
    ++ * bluetooth_sdp_mas_record */
    ++static int add_maps_sdp(const bluetooth_sdp_mas_record* rec) {
    ++  tSDP_PROTOCOL_ELEM protoList[3];
    ++  uint16_t service = UUID_SERVCLASS_MESSAGE_ACCESS;
    ++  uint16_t browse = UUID_SERVCLASS_PUBLIC_BROWSE_GROUP;
    ++  bool status = true;
    ++  uint32_t sdp_handle = 0;
    ++  uint8_t temp[4];
    ++  uint8_t* p_temp = temp;
    ++
    ++  APPL_TRACE_DEBUG(
    ++      "%s(): MASID = 0x%02x, scn 0x%02x, psm = 0x%04x\n  service name %s",
    ++      __func__, rec->mas_instance_id, rec->hdr.rfcomm_channel_number,
    ++      rec->hdr.l2cap_psm, rec->hdr.service_name);
    ++
    ++  APPL_TRACE_DEBUG("  msg_types: 0x%02x, feature_bits: 0x%08x",
    ++                   rec->supported_message_types, rec->supported_features);
    ++
    ++  sdp_handle = SDP_CreateRecord();
    ++  if (sdp_handle == 0) {
    ++    APPL_TRACE_ERROR("%s() - Unable to register MAPS Service", __func__);
    ++    return sdp_handle;
    ++  }
    ++
    ++  /* add service class */
    ++  status &= SDP_AddServiceClassIdList(sdp_handle, 1, &service);
    ++  memset(protoList, 0, 3 * sizeof(tSDP_PROTOCOL_ELEM));
    ++
    ++  /* add protocol list, including RFCOMM scn */
    ++  protoList[0].protocol_uuid = UUID_PROTOCOL_L2CAP;
    ++  protoList[0].num_params = 0;
    ++  protoList[1].protocol_uuid = UUID_PROTOCOL_RFCOMM;
    ++  protoList[1].num_params = 1;
    ++  protoList[1].params[0] = rec->hdr.rfcomm_channel_number;
    ++  protoList[2].protocol_uuid = UUID_PROTOCOL_OBEX;
    ++  protoList[2].num_params = 0;
    ++  status &= SDP_AddProtocolList(sdp_handle, 3, protoList);
    ++
    ++  /* Add a name entry */
    ++  status &= SDP_AddAttribute(sdp_handle, (uint16_t)ATTR_ID_SERVICE_NAME,
    ++                             (uint8_t)TEXT_STR_DESC_TYPE,
    ++                             (uint32_t)(rec->hdr.service_name_length + 1),
    ++                             (uint8_t*)rec->hdr.service_name);
    ++
    ++  /* Add in the Bluetooth Profile Descriptor List */
    ++  status &= SDP_AddProfileDescriptorList(sdp_handle, UUID_SERVCLASS_MAP_PROFILE,
    ++                                         rec->hdr.profile_version);
    ++
    ++  /* Add MAS instance ID */
    ++  status &=
    ++      SDP_AddAttribute(sdp_handle, ATTR_ID_MAS_INSTANCE_ID, UINT_DESC_TYPE,
    ++                       (uint32_t)1, (uint8_t*)&rec->mas_instance_id);
    ++
    ++  /* Add supported message types */
    ++  status &=
    ++      SDP_AddAttribute(sdp_handle, ATTR_ID_SUPPORTED_MSG_TYPE, UINT_DESC_TYPE,
    ++                       (uint32_t)1, (uint8_t*)&rec->supported_message_types);
    ++
    ++  /* Add supported feature */
    ++  UINT32_TO_BE_STREAM(p_temp, rec->supported_features);
    ++  status &= SDP_AddAttribute(sdp_handle, ATTR_ID_MAP_SUPPORTED_FEATURES,
    ++                             UINT_DESC_TYPE, (uint32_t)4, temp);
    ++
    ++  /* Add the L2CAP PSM if present */
    ++  if (rec->hdr.l2cap_psm != -1) {
    ++    p_temp = temp;  // The macro modifies p_temp, hence rewind.
    ++    UINT16_TO_BE_STREAM(p_temp, rec->hdr.l2cap_psm);
    ++    status &= SDP_AddAttribute(sdp_handle, ATTR_ID_GOEP_L2CAP_PSM,
    ++                               UINT_DESC_TYPE, (uint32_t)2, temp);
    ++  }
    ++
    ++  /* Make the service browseable */
    ++  status &=
    ++      SDP_AddUuidSequence(sdp_handle, ATTR_ID_BROWSE_GROUP_LIST, 1, &browse);
    ++
    ++  if (!status) {
    ++    SDP_DeleteRecord(sdp_handle);
    ++    sdp_handle = 0;
    ++    APPL_TRACE_ERROR("%s() FAILED", __func__);
    ++  } else {
    ++    bta_sys_add_uuid(service); /* UUID_SERVCLASS_MESSAGE_ACCESS */
    ++    APPL_TRACE_DEBUG("%s():  SDP Registered (handle 0x%08x)", __func__,
    ++                     sdp_handle);
    ++  }
    ++  return sdp_handle;
    ++}
    ++
    ++/* Create a MAP MNS SDP record based on information stored in a
    ++ * bluetooth_sdp_mns_record */
    ++static int add_mapc_sdp(const bluetooth_sdp_mns_record* rec) {
    ++  tSDP_PROTOCOL_ELEM protoList[3];
    ++  uint16_t service = UUID_SERVCLASS_MESSAGE_NOTIFICATION;
    ++  uint16_t browse = UUID_SERVCLASS_PUBLIC_BROWSE_GROUP;
    ++  bool status = true;
    ++  uint32_t sdp_handle = 0;
    ++  uint8_t temp[4];
    ++  uint8_t* p_temp = temp;
    ++
    ++  APPL_TRACE_DEBUG("%s(): scn 0x%02x, psm = 0x%04x\n  service name %s",
    ++                   __func__, rec->hdr.rfcomm_channel_number, rec->hdr.l2cap_psm,
    ++                   rec->hdr.service_name);
    ++
    ++  APPL_TRACE_DEBUG("  feature_bits: 0x%08x", rec->supported_features);
    ++
    ++  sdp_handle = SDP_CreateRecord();
    ++  if (sdp_handle == 0) {
    ++    APPL_TRACE_ERROR("%s(): Unable to register MAP Notification Service",
    ++                     __func__);
    ++    return sdp_handle;
    ++  }
    ++
    ++  /* add service class */
    ++  status &= SDP_AddServiceClassIdList(sdp_handle, 1, &service);
    ++  memset(protoList, 0, 3 * sizeof(tSDP_PROTOCOL_ELEM));
    ++
    ++  /* add protocol list, including RFCOMM scn */
    ++  protoList[0].protocol_uuid = UUID_PROTOCOL_L2CAP;
    ++  protoList[0].num_params = 0;
    ++  protoList[1].protocol_uuid = UUID_PROTOCOL_RFCOMM;
    ++  protoList[1].num_params = 1;
    ++  protoList[1].params[0] = rec->hdr.rfcomm_channel_number;
    ++  protoList[2].protocol_uuid = UUID_PROTOCOL_OBEX;
    ++  protoList[2].num_params = 0;
    ++  status &= SDP_AddProtocolList(sdp_handle, 3, protoList);
    ++
    ++  /* Add a name entry */
    ++  status &= SDP_AddAttribute(sdp_handle, (uint16_t)ATTR_ID_SERVICE_NAME,
    ++                             (uint8_t)TEXT_STR_DESC_TYPE,
    ++                             (uint32_t)(rec->hdr.service_name_length + 1),
    ++                             (uint8_t*)rec->hdr.service_name);
    ++
    ++  /* Add in the Bluetooth Profile Descriptor List */
    ++  status &= SDP_AddProfileDescriptorList(sdp_handle, UUID_SERVCLASS_MAP_PROFILE,
    ++                                         rec->hdr.profile_version);
    ++
    ++  /* Add supported feature */
    ++  UINT32_TO_BE_STREAM(p_temp, rec->supported_features);
    ++  status &= SDP_AddAttribute(sdp_handle, ATTR_ID_MAP_SUPPORTED_FEATURES,
    ++                             UINT_DESC_TYPE, (uint32_t)4, temp);
    ++
    ++  /* Add the L2CAP PSM if present */
    ++  if (rec->hdr.l2cap_psm != -1) {
    ++    p_temp = temp;  // The macro modifies p_temp, hence rewind.
    ++    UINT16_TO_BE_STREAM(p_temp, rec->hdr.l2cap_psm);
    ++    status &= SDP_AddAttribute(sdp_handle, ATTR_ID_GOEP_L2CAP_PSM,
    ++                               UINT_DESC_TYPE, (uint32_t)2, temp);
    ++  }
    ++
    ++  /* Make the service browseable */
    ++  status &=
    ++      SDP_AddUuidSequence(sdp_handle, ATTR_ID_BROWSE_GROUP_LIST, 1, &browse);
    ++
    ++  if (!status) {
    ++    SDP_DeleteRecord(sdp_handle);
    ++    sdp_handle = 0;
    ++    APPL_TRACE_ERROR("%s() FAILED", __func__);
    ++  } else {
    ++    bta_sys_add_uuid(service); /* UUID_SERVCLASS_MESSAGE_ACCESS */
    ++    APPL_TRACE_DEBUG("%s():  SDP Registered (handle 0x%08x)", __func__,
    ++                     sdp_handle);
    ++  }
    ++  return sdp_handle;
    ++}
    ++
    ++/* Create a PBAP Server SDP record based on information stored in a
    ++ * bluetooth_sdp_pse_record */
    ++static int add_pbaps_sdp(const bluetooth_sdp_pse_record* rec) {
    ++  tSDP_PROTOCOL_ELEM protoList[3];
    ++  uint16_t service = UUID_SERVCLASS_PBAP_PSE;
    ++  uint16_t browse = UUID_SERVCLASS_PUBLIC_BROWSE_GROUP;
    ++  bool status = true;
    ++  uint32_t sdp_handle = 0;
    ++  uint8_t temp[4];
    ++  uint8_t* p_temp = temp;
    ++
    ++  APPL_TRACE_DEBUG("%s(): scn 0x%02x, psm = 0x%04x\n  service name %s",
    ++                   __func__, rec->hdr.rfcomm_channel_number, rec->hdr.l2cap_psm,
    ++                   rec->hdr.service_name);
    ++
    ++  APPL_TRACE_DEBUG("  supported_repositories: 0x%08x, feature_bits: 0x%08x",
    ++                   rec->supported_repositories, rec->supported_features);
    ++
    ++  sdp_handle = SDP_CreateRecord();
    ++  if (sdp_handle == 0) {
    ++    APPL_TRACE_ERROR("%s(): Unable to register PBAP Server Service", __func__);
    ++    return sdp_handle;
    ++  }
    ++
    ++  /* add service class */
    ++  status &= SDP_AddServiceClassIdList(sdp_handle, 1, &service);
    ++  memset(protoList, 0, 3 * sizeof(tSDP_PROTOCOL_ELEM));
    ++
    ++  /* add protocol list, including RFCOMM scn */
    ++  protoList[0].protocol_uuid = UUID_PROTOCOL_L2CAP;
    ++  protoList[0].num_params = 0;
    ++  protoList[1].protocol_uuid = UUID_PROTOCOL_RFCOMM;
    ++  protoList[1].num_params = 1;
    ++  protoList[1].params[0] = rec->hdr.rfcomm_channel_number;
    ++  protoList[2].protocol_uuid = UUID_PROTOCOL_OBEX;
    ++  protoList[2].num_params = 0;
    ++  status &= SDP_AddProtocolList(sdp_handle, 3, protoList);
    ++
    ++  /* Add a name entry */
    ++  status &= SDP_AddAttribute(sdp_handle, (uint16_t)ATTR_ID_SERVICE_NAME,
    ++                             (uint8_t)TEXT_STR_DESC_TYPE,
    ++                             (uint32_t)(rec->hdr.service_name_length + 1),
    ++                             (uint8_t*)rec->hdr.service_name);
    ++
    ++  /* Add in the Bluetooth Profile Descriptor List */
    ++  status &= SDP_AddProfileDescriptorList(
    ++      sdp_handle, UUID_SERVCLASS_PHONE_ACCESS, rec->hdr.profile_version);
    ++
    ++  /* Add supported repositories 1 byte */
    ++  status &= SDP_AddAttribute(sdp_handle, ATTR_ID_SUPPORTED_REPOSITORIES,
    ++                             UINT_DESC_TYPE, (uint32_t)1,
    ++                             (uint8_t*)&rec->supported_repositories);
    ++
    ++  /* Add supported feature 4 bytes*/
    ++  UINT32_TO_BE_STREAM(p_temp, rec->supported_features);
    ++  status &= SDP_AddAttribute(sdp_handle, ATTR_ID_PBAP_SUPPORTED_FEATURES,
    ++                             UINT_DESC_TYPE, (uint32_t)4, temp);
    ++
    ++  /* Add the L2CAP PSM if present */
    ++  if (rec->hdr.l2cap_psm != -1) {
    ++    p_temp = temp;  // The macro modifies p_temp, hence rewind.
    ++    UINT16_TO_BE_STREAM(p_temp, rec->hdr.l2cap_psm);
    ++    status &= SDP_AddAttribute(sdp_handle, ATTR_ID_GOEP_L2CAP_PSM,
    ++                               UINT_DESC_TYPE, (uint32_t)2, temp);
    ++  }
    ++
    ++  /* Make the service browseable */
    ++  status &=
    ++      SDP_AddUuidSequence(sdp_handle, ATTR_ID_BROWSE_GROUP_LIST, 1, &browse);
    ++
    ++  if (!status) {
    ++    SDP_DeleteRecord(sdp_handle);
    ++    sdp_handle = 0;
    ++    APPL_TRACE_ERROR("%s() FAILED", __func__);
    ++  } else {
    ++    bta_sys_add_uuid(service); /* UUID_SERVCLASS_MESSAGE_ACCESS */
    ++    APPL_TRACE_DEBUG("%s():  SDP Registered (handle 0x%08x)", __func__,
    ++                     sdp_handle);
    ++  }
    ++  return sdp_handle;
    ++}
    ++
    ++/* Create a OPP Server SDP record based on information stored in a
    ++ * bluetooth_sdp_ops_record */
    ++static int add_opps_sdp(const bluetooth_sdp_ops_record* rec) {
    ++  tSDP_PROTOCOL_ELEM protoList[3];
    ++  uint16_t service = UUID_SERVCLASS_OBEX_OBJECT_PUSH;
    ++  uint16_t browse = UUID_SERVCLASS_PUBLIC_BROWSE_GROUP;
    ++  uint8_t type_len[rec->supported_formats_list_len];
    ++  uint8_t desc_type[rec->supported_formats_list_len];
    ++  uint8_t* type_value[rec->supported_formats_list_len];
    ++  bool status = true;
    ++  uint32_t sdp_handle = 0;
    ++  uint8_t temp[4];
    ++  uint8_t* p_temp = temp;
    ++  tBTA_UTL_COD cod;
    ++  int i, j;
    ++
    ++  APPL_TRACE_DEBUG("%s(): scn 0x%02x, psm = 0x%04x\n  service name %s",
    ++                   __func__, rec->hdr.rfcomm_channel_number, rec->hdr.l2cap_psm,
    ++                   rec->hdr.service_name);
    ++
    ++  APPL_TRACE_DEBUG("  supported formats count: %d",
    ++                   rec->supported_formats_list_len);
    ++
    ++  sdp_handle = SDP_CreateRecord();
    ++  if (sdp_handle == 0) {
    ++    APPL_TRACE_ERROR("%s(): Unable to register Object Push Server Service",
    ++                     __func__);
    ++    return sdp_handle;
    ++  }
    ++
    ++  /* add service class */
    ++  status &= SDP_AddServiceClassIdList(sdp_handle, 1, &service);
    ++  memset(protoList, 0, 3 * sizeof(tSDP_PROTOCOL_ELEM));
    ++
    ++  /* add protocol list, including RFCOMM scn */
    ++  protoList[0].protocol_uuid = UUID_PROTOCOL_L2CAP;
    ++  protoList[0].num_params = 0;
    ++  protoList[1].protocol_uuid = UUID_PROTOCOL_RFCOMM;
    ++  protoList[1].num_params = 1;
    ++  protoList[1].params[0] = rec->hdr.rfcomm_channel_number;
    ++  protoList[2].protocol_uuid = UUID_PROTOCOL_OBEX;
    ++  protoList[2].num_params = 0;
    ++  status &= SDP_AddProtocolList(sdp_handle, 3, protoList);
    ++
    ++  /* Add a name entry */
    ++  status &= SDP_AddAttribute(sdp_handle, (uint16_t)ATTR_ID_SERVICE_NAME,
    ++                             (uint8_t)TEXT_STR_DESC_TYPE,
    ++                             (uint32_t)(rec->hdr.service_name_length + 1),
    ++                             (uint8_t*)rec->hdr.service_name);
    ++
    ++  /* Add in the Bluetooth Profile Descriptor List */
    ++  status &= SDP_AddProfileDescriptorList(
    ++      sdp_handle, UUID_SERVCLASS_OBEX_OBJECT_PUSH, rec->hdr.profile_version);
    ++
    ++  /* add sequence for supported types */
    ++  for (i = 0, j = 0; i < rec->supported_formats_list_len; i++) {
    ++    type_value[j] = (uint8_t*)&rec->supported_formats_list[i];
    ++    desc_type[j] = UINT_DESC_TYPE;
    ++    type_len[j++] = 1;
    ++  }
    ++
    ++  status &=
    ++      SDP_AddSequence(sdp_handle, (uint16_t)ATTR_ID_SUPPORTED_FORMATS_LIST,
    ++                      (uint8_t)rec->supported_formats_list_len, desc_type,
    ++                      type_len, type_value);
    ++
    ++  /* Add the L2CAP PSM if present */
    ++  if (rec->hdr.l2cap_psm != -1) {
    ++    p_temp = temp;  // The macro modifies p_temp, hence rewind.
    ++    UINT16_TO_BE_STREAM(p_temp, rec->hdr.l2cap_psm);
    ++    status &= SDP_AddAttribute(sdp_handle, ATTR_ID_GOEP_L2CAP_PSM,
    ++                               UINT_DESC_TYPE, (uint32_t)2, temp);
    ++  }
    ++
    ++  /* Make the service browseable */
    ++  status &=
    ++      SDP_AddUuidSequence(sdp_handle, ATTR_ID_BROWSE_GROUP_LIST, 1, &browse);
    ++
    ++  if (!status) {
    ++    SDP_DeleteRecord(sdp_handle);
    ++    sdp_handle = 0;
    ++    APPL_TRACE_ERROR("%s() FAILED", __func__);
    ++  } else {
    ++    /* set class of device */
    ++    cod.service = BTM_COD_SERVICE_OBJ_TRANSFER;
    ++    utl_set_device_class(&cod, BTA_UTL_SET_COD_SERVICE_CLASS);
    ++
    ++    bta_sys_add_uuid(service); /* UUID_SERVCLASS_OBEX_OBJECT_PUSH */
    ++    APPL_TRACE_DEBUG("%s():  SDP Registered (handle 0x%08x)", __func__,
    ++                     sdp_handle);
    ++  }
    ++  return sdp_handle;
    ++}
    ++
    ++// Create a Sim Access Profile SDP record based on information stored in a
    ++// bluetooth_sdp_sap_record.
    ++static int add_saps_sdp(const bluetooth_sdp_sap_record* rec) {
    ++  tSDP_PROTOCOL_ELEM protoList[2];
    ++  uint16_t services[2];
    ++  uint16_t browse = UUID_SERVCLASS_PUBLIC_BROWSE_GROUP;
    ++  bool status = true;
    ++  uint32_t sdp_handle = 0;
    ++
    ++  APPL_TRACE_DEBUG("%s(): scn 0x%02x, service name %s", __func__,
    ++                   rec->hdr.rfcomm_channel_number, rec->hdr.service_name);
    ++
    ++  sdp_handle = SDP_CreateRecord();
    ++  if (sdp_handle == 0) {
    ++    APPL_TRACE_ERROR("%s(): Unable to register SAPS Service", __func__);
    ++    return sdp_handle;
    ++  }
    ++
    ++  services[0] = UUID_SERVCLASS_SAP;
    ++  services[1] = UUID_SERVCLASS_GENERIC_TELEPHONY;
    ++
    ++  // add service class
    ++  status &= SDP_AddServiceClassIdList(sdp_handle, 2, services);
    ++  memset(protoList, 0, 2 * sizeof(tSDP_PROTOCOL_ELEM));
    ++
    ++  // add protocol list, including RFCOMM scn
    ++  protoList[0].protocol_uuid = UUID_PROTOCOL_L2CAP;
    ++  protoList[0].num_params = 0;
    ++  protoList[1].protocol_uuid = UUID_PROTOCOL_RFCOMM;
    ++  protoList[1].num_params = 1;
    ++  protoList[1].params[0] = rec->hdr.rfcomm_channel_number;
    ++  status &= SDP_AddProtocolList(sdp_handle, 2, protoList);
    ++
    ++  // Add a name entry
    ++  status &= SDP_AddAttribute(sdp_handle, (uint16_t)ATTR_ID_SERVICE_NAME,
    ++                             (uint8_t)TEXT_STR_DESC_TYPE,
    ++                             (uint32_t)(rec->hdr.service_name_length + 1),
    ++                             (uint8_t*)rec->hdr.service_name);
    ++
    ++  // Add in the Bluetooth Profile Descriptor List
    ++  status &= SDP_AddProfileDescriptorList(sdp_handle, UUID_SERVCLASS_SAP,
    ++                                         rec->hdr.profile_version);
    ++
    ++  // Make the service browseable
    ++  status &=
    ++      SDP_AddUuidSequence(sdp_handle, ATTR_ID_BROWSE_GROUP_LIST, 1, &browse);
    ++
    ++  if (!status) {
    ++    SDP_DeleteRecord(sdp_handle);
    ++    sdp_handle = 0;
    ++    APPL_TRACE_ERROR("%s(): FAILED deleting record", __func__);
    ++  } else {
    ++    bta_sys_add_uuid(UUID_SERVCLASS_SAP);
    ++    APPL_TRACE_DEBUG("%s(): SDP Registered (handle 0x%08x)", __func__,
    ++                     sdp_handle);
    ++  }
    ++  return sdp_handle;
    ++}
     diff --git a/stack/avdt/avdt_api.c b/stack/avdt/avdt_api.c
     index 98ef5f7..258f424 100644
     --- a/stack/avdt/avdt_api.c
    diff --git a/system_core.patch b/system_core.patch
    index 9b9295f..1138952 100644
    --- a/system_core.patch
    +++ b/system_core.patch
    @@ -99,6 +99,21 @@ index 5d0873a..e4c0a47 100644
       * The metadata of the frame data.
       */
      typedef struct camera_frame_metadata {
    +diff --git a/include/utils/Unicode.h b/include/utils/Unicode.h
    +index cddbab4..b152579 100644
    +--- a/include/utils/Unicode.h
    ++++ b/include/utils/Unicode.h
    +@@ -22,6 +22,10 @@
    + 
    + extern "C" {
    + 
    ++#ifndef SSIZE_MAX
    ++#define SSIZE_MAX ((size_t)SIZE_MAX/2)
    ++#endif
    ++
    + // Standard string functions on char16_t strings.
    + int strcmp16(const char16_t *, const char16_t *);
    + int strncmp16(const char16_t *s1, const char16_t *s2, size_t n);
     diff --git a/init/Android.mk b/init/Android.mk
     index 67541b8..ff343e9 100644
     --- a/init/Android.mk
    @@ -181,6 +196,53 @@ index cd2d2e6..81628a1 100644
          am.QueueBuiltinAction(keychord_init_action, "keychord_init");
          am.QueueBuiltinAction(console_init_action, "console_init");
      
    +diff --git a/libutils/Unicode.cpp b/libutils/Unicode.cpp
    +index ba084f6..22c5b29 100644
    +--- a/libutils/Unicode.cpp
    ++++ b/libutils/Unicode.cpp
    +@@ -178,7 +178,15 @@ ssize_t utf32_to_utf8_length(const char32_t *src, size_t src_len)
    +     size_t ret = 0;
    +     const char32_t *end = src + src_len;
    +     while (src < end) {
    +-        ret += utf32_codepoint_utf8_length(*src++);
    ++        size_t char_len = utf32_codepoint_utf8_length(*src++);
    ++        if (SSIZE_MAX - char_len < ret) {
    ++            // If this happens, we would overflow the ssize_t type when
    ++            // returning from this function, so we cannot express how
    ++            // long this string is in an ssize_t.
    ++            android_errorWriteLog(0x534e4554, "37723026");
    ++            return -1;
    ++        }
    ++        ret += char_len;
    +     }
    +     return ret;
    + }
    +@@ -438,14 +446,23 @@ ssize_t utf16_to_utf8_length(const char16_t *src, size_t src_len)
    +     size_t ret = 0;
    +     const char16_t* const end = src + src_len;
    +     while (src < end) {
    ++        size_t char_len;
    +         if ((*src & 0xFC00) == 0xD800 && (src + 1) < end
    +                 && (*(src + 1) & 0xFC00) == 0xDC00) {
    +             // surrogate pairs are always 4 bytes.
    +-            ret += 4;
    ++            char_len = 4;
    +             src += 2;
    +         } else {
    +-            ret += utf32_codepoint_utf8_length((char32_t) *src++);
    ++            char_len = utf32_codepoint_utf8_length((char32_t)*src++);
    ++        }
    ++        if (SSIZE_MAX - char_len < ret) {
    ++            // If this happens, we would overflow the ssize_t type when
    ++            // returning from this function, so we cannot express how
    ++            // long this string is in an ssize_t.
    ++            android_errorWriteLog(0x534e4554, "37723026");
    ++            return -1;
    +         }
    ++        ret += char_len;
    +     }
    +     return ret;
    + }
     diff --git a/rootdir/init.rc b/rootdir/init.rc
     index 7dc9e55..adc062b 100644
     --- a/rootdir/init.rc
    
    From 5d0b6d30c4c8ae8f4533dba8cdc321a2d378a573 Mon Sep 17 00:00:00 2001
    From: AndDiSa <anddisa@googlemail.com>
    Date: Sat, 9 Dec 2017 10:14:59 +0100
    Subject: [PATCH 089/159] update patches
    
    Change-Id: I9d63895575348d2e05733490ca49ce2fb32d0f64
    ---
     build.patch                  |    4 +-
     external_libavc.patch        |  131 ++-
     external_libhevc.patch       |   36 +-
     external_libmpeg2.patch      |   36 +-
     external_skia.patch          | 2146 ++++++++++++++++++++++++++++++++++
     frameworks_av.patch          | 1888 +++++++-----------------------
     frameworks_base.patch        |  238 ++++
     frameworks_minikin.patch     |   45 +-
     packages_apps_settings.patch |   84 ++
     system_bt.patch              |  961 ++-------------
     system_core.patch            |  110 +-
     11 files changed, 3339 insertions(+), 2340 deletions(-)
    
    diff --git a/build.patch b/build.patch
    index 9d73d78..0190f84 100644
    --- a/build.patch
    +++ b/build.patch
    @@ -323,7 +323,7 @@ index 0000000..ee76dc2
     +ALL_PREBUILT += $(INSTALLED_KERNEL_TARGET)
     +endif
     diff --git a/core/version_defaults.mk b/core/version_defaults.mk
    -index 7c96344..2f05807 100644
    +index 7c96344..e4077cf 100644
     --- a/core/version_defaults.mk
     +++ b/core/version_defaults.mk
     @@ -131,7 +131,7 @@ ifeq "" "$(PLATFORM_SECURITY_PATCH)"
    @@ -331,7 +331,7 @@ index 7c96344..2f05807 100644
          #  It must match one of the Android Security Patch Level strings of the Public Security Bulletins.
          #  If there is no $PLATFORM_SECURITY_PATCH set, keep it empty.
     -    PLATFORM_SECURITY_PATCH := 2017-08-05
    -+    PLATFORM_SECURITY_PATCH := 2017-11-06
    ++    PLATFORM_SECURITY_PATCH := 2017-12-05
      endif
      
      ifeq "" "$(PLATFORM_BASE_OS)"
    diff --git a/external_libavc.patch b/external_libavc.patch
    index f425abb..aa6f727 100644
    --- a/external_libavc.patch
    +++ b/external_libavc.patch
    @@ -1,5 +1,5 @@
     diff --git a/decoder/ih264d_api.c b/decoder/ih264d_api.c
    -index 2cde456..d86aaee 100644
    +index 2cde456..5ef49b1 100644
     --- a/decoder/ih264d_api.c
     +++ b/decoder/ih264d_api.c
     @@ -1623,6 +1623,89 @@ UWORD32 ih264d_map_error(UWORD32 i4_err_status)
    @@ -92,7 +92,17 @@ index 2cde456..d86aaee 100644
      /*****************************************************************************/
      /*                                                                           */
      /*  Function Name :  ih264d_video_decode                                     */
    -@@ -1865,6 +1948,13 @@ WORD32 ih264d_video_decode(iv_obj_t *dec_hdl, void *pv_api_ip, void *pv_api_op)
    +@@ -1721,7 +1804,8 @@ WORD32 ih264d_video_decode(iv_obj_t *dec_hdl, void *pv_api_ip, void *pv_api_op)
    +                     && ps_dec->i4_decode_header == 0)
    +     {
    +         UWORD32 i;
    +-        if(ps_dec->ps_out_buffer->u4_num_bufs == 0)
    ++        if((ps_dec->ps_out_buffer->u4_num_bufs == 0) ||
    ++           (ps_dec->ps_out_buffer->u4_num_bufs > IVD_VIDDEC_MAX_IO_BUFFERS))
    +         {
    +             ps_dec_op->u4_error_code |= 1 << IVD_UNSUPPORTEDPARAM;
    +             ps_dec_op->u4_error_code |= IVD_DISP_FRM_ZERO_OP_BUFS;
    +@@ -1865,6 +1949,13 @@ WORD32 ih264d_video_decode(iv_obj_t *dec_hdl, void *pv_api_ip, void *pv_api_op)
                                            &(ps_dec->s_disp_op));
              if(0 == ps_dec->s_disp_op.u4_error_code)
              {
    @@ -106,7 +116,7 @@ index 2cde456..d86aaee 100644
                  ps_dec->u4_fmt_conv_cur_row = 0;
                  ps_dec->u4_fmt_conv_num_rows = ps_dec->s_disp_frame_info.u4_y_ht;
                  ih264d_format_convert(ps_dec, &(ps_dec->s_disp_op),
    -@@ -2094,7 +2184,8 @@ WORD32 ih264d_video_decode(iv_obj_t *dec_hdl, void *pv_api_ip, void *pv_api_op)
    +@@ -2094,7 +2185,8 @@ WORD32 ih264d_video_decode(iv_obj_t *dec_hdl, void *pv_api_ip, void *pv_api_op)
                                  || (ret == IVD_MEM_ALLOC_FAILED)
                                  || (ret == ERROR_UNAVAIL_PICBUF_T)
                                  || (ret == ERROR_UNAVAIL_MVBUF_T)
    @@ -116,7 +126,7 @@ index 2cde456..d86aaee 100644
                  {
                      ps_dec->u4_slice_start_code_found = 0;
                      break;
    -@@ -2148,7 +2239,7 @@ WORD32 ih264d_video_decode(iv_obj_t *dec_hdl, void *pv_api_ip, void *pv_api_op)
    +@@ -2148,7 +2240,7 @@ WORD32 ih264d_video_decode(iv_obj_t *dec_hdl, void *pv_api_ip, void *pv_api_op)
          }
          while(( header_data_left == 1)||(frame_data_left == 1));
      
    @@ -125,7 +135,7 @@ index 2cde456..d86aaee 100644
                  && (ret != IVD_MEM_ALLOC_FAILED)
                  && ps_dec->u2_total_mbs_coded < ps_dec->u2_frm_ht_in_mbs * ps_dec->u2_frm_wd_in_mbs)
          {
    -@@ -2290,7 +2381,7 @@ WORD32 ih264d_video_decode(iv_obj_t *dec_hdl, void *pv_api_ip, void *pv_api_op)
    +@@ -2290,7 +2382,7 @@ WORD32 ih264d_video_decode(iv_obj_t *dec_hdl, void *pv_api_ip, void *pv_api_op)
      
          }
      
    @@ -134,7 +144,7 @@ index 2cde456..d86aaee 100644
                          && (ERROR_DANGLING_FIELD_IN_PIC != i4_err_status))
          {
              /*
    -@@ -2316,8 +2407,7 @@ WORD32 ih264d_video_decode(iv_obj_t *dec_hdl, void *pv_api_ip, void *pv_api_op)
    +@@ -2316,8 +2408,7 @@ WORD32 ih264d_video_decode(iv_obj_t *dec_hdl, void *pv_api_ip, void *pv_api_op)
              /* if new frame in not found (if we are still getting slices from previous frame)
               * ih264d_deblock_display is not called. Such frames will not be added to reference /display
               */
    @@ -144,7 +154,7 @@ index 2cde456..d86aaee 100644
              {
                  /* Calling Function to deblock Picture and Display */
                  ret = ih264d_deblock_display(ps_dec);
    -@@ -2843,27 +2933,15 @@ WORD32 ih264d_get_buf_info(iv_obj_t *dec_hdl, void *pv_api_ip, void *pv_api_op)
    +@@ -2843,27 +2934,15 @@ WORD32 ih264d_get_buf_info(iv_obj_t *dec_hdl, void *pv_api_ip, void *pv_api_op)
          UWORD16 pic_wd, pic_ht;
          ivd_ctl_getbufinfo_op_t *ps_ctl_op =
                          (ivd_ctl_getbufinfo_op_t*)pv_api_op;
    @@ -174,7 +184,7 @@ index 2cde456..d86aaee 100644
      
          ps_ctl_op->u4_num_disp_bufs = 1;
      
    -@@ -2930,37 +3008,15 @@ WORD32 ih264d_get_buf_info(iv_obj_t *dec_hdl, void *pv_api_ip, void *pv_api_op)
    +@@ -2930,37 +3009,15 @@ WORD32 ih264d_get_buf_info(iv_obj_t *dec_hdl, void *pv_api_ip, void *pv_api_op)
                              ps_ctl_op->u4_num_disp_bufs, 32);
          }
      
    @@ -220,10 +230,85 @@ index 2cde456..d86aaee 100644
      
          return IV_SUCCESS;
     diff --git a/decoder/ih264d_parse_bslice.c b/decoder/ih264d_parse_bslice.c
    -index 772964a..db64ce9 100644
    +index 772964a..f087f8d 100644
     --- a/decoder/ih264d_parse_bslice.c
     +++ b/decoder/ih264d_parse_bslice.c
    -@@ -1531,10 +1531,7 @@ WORD32 ih264d_parse_bslice(dec_struct_t * ps_dec, UWORD16 u2_first_mb_in_slice)
    +@@ -1197,7 +1197,8 @@ void ih264d_get_implicit_weights(dec_struct_t *ps_dec)
    +     struct pic_buffer_t *ps_pic_buff0, *ps_pic_buff1;
    +     WORD16 i2_dist_scale_factor;
    +     WORD16 i16_tb, i16_td, i16_tx;
    +-    UWORD32 u4_poc0, u4_poc1;
    ++    WORD32 i4_tb, i4_td;
    ++    WORD32 i4_poc0, i4_poc1;
    +     UWORD32 ui_temp0, ui_temp1;
    +     UWORD8 uc_num_ref_idx_l0_active, uc_num_ref_idx_l1_active;
    + 
    +@@ -1210,18 +1211,18 @@ void ih264d_get_implicit_weights(dec_struct_t *ps_dec)
    +     for(i = 0; i < uc_num_ref_idx_l0_active; i++)
    +     {
    +         ps_pic_buff0 = ps_dec->ps_ref_pic_buf_lx[0][i];
    +-        u4_poc0 = ps_pic_buff0->i4_avg_poc;
    ++        i4_poc0 = ps_pic_buff0->i4_avg_poc;
    +         for(j = 0; j < uc_num_ref_idx_l1_active; j++)
    +         {
    +             ps_pic_buff1 = ps_dec->ps_ref_pic_buf_lx[1][j];
    +-            u4_poc1 = ps_pic_buff1->i4_avg_poc;
    ++            i4_poc1 = ps_pic_buff1->i4_avg_poc;
    + 
    +-            if(u4_poc1 != u4_poc0)
    ++            if(i4_poc1 != i4_poc0)
    +             {
    +-                i16_tb = ps_dec->ps_cur_pic->i4_poc - u4_poc0;
    +-                i16_tb = CLIP3(-128, 127, i16_tb);
    +-                i16_td = u4_poc1 - u4_poc0;
    +-                i16_td = CLIP3(-128, 127, i16_td);
    ++                i4_tb = ps_dec->ps_cur_pic->i4_poc - i4_poc0;
    ++                i16_tb = CLIP3(-128, 127, i4_tb);
    ++                i4_td = i4_poc1 - i4_poc0;
    ++                i16_td = CLIP3(-128, 127, i4_td);
    +                 i16_tx = (16384 + ABS(SIGN_POW2_DIV(i16_td, 1))) / i16_td;
    +                 i2_dist_scale_factor = CLIP3(-1024, 1023,
    +                                             (((i16_tb * i16_tx) + 32) >> 6));
    +@@ -1272,7 +1273,7 @@ void ih264d_get_implicit_weights(dec_struct_t *ps_dec)
    +                     u2_l0_idx += MAX_REF_BUFS;
    +                 }
    +                 ps_pic_buff0 = ps_dec->ps_ref_pic_buf_lx[0][u2_l0_idx];
    +-                u4_poc0 = ps_pic_buff0->i4_poc;
    ++                i4_poc0 = ps_pic_buff0->i4_poc;
    +                 for(j = 0; j < (uc_num_ref_idx_l1_active << 1); j++)
    +                 {
    +                     UWORD16 u2_l1_idx;
    +@@ -1285,13 +1286,13 @@ void ih264d_get_implicit_weights(dec_struct_t *ps_dec)
    +                         u2_l1_idx += MAX_REF_BUFS;
    +                     }
    +                     ps_pic_buff1 = ps_dec->ps_ref_pic_buf_lx[1][u2_l1_idx];
    +-                    u4_poc1 = ps_pic_buff1->i4_poc;
    +-                    if(u4_poc1 != u4_poc0)
    ++                    i4_poc1 = ps_pic_buff1->i4_poc;
    ++                    if(i4_poc1 != i4_poc0)
    +                     {
    +-                        i16_tb = i4_cur_poc - u4_poc0;
    +-                        i16_tb = CLIP3(-128, 127, i16_tb);
    +-                        i16_td = u4_poc1 - u4_poc0;
    +-                        i16_td = CLIP3(-128, 127, i16_td);
    ++                        i4_tb = i4_cur_poc - i4_poc0;
    ++                        i16_tb = CLIP3(-128, 127, i4_tb);
    ++                        i4_td = i4_poc1 - i4_poc0;
    ++                        i16_td = CLIP3(-128, 127, i4_td);
    +                         i16_tx = (16384 + ABS(SIGN_POW2_DIV(i16_td, 1)))
    +                                         / i16_td;
    +                         i2_dist_scale_factor = CLIP3(
    +@@ -1398,7 +1399,8 @@ WORD32 ih264d_parse_bslice(dec_struct_t * ps_dec, UWORD16 u2_first_mb_in_slice)
    +         {
    +             u1_max_ref_idx = MAX_FRAMES << 1;
    +         }
    +-        if((u4_temp > u1_max_ref_idx) || (ui_temp1 > u1_max_ref_idx))
    ++        if((u4_temp > u1_max_ref_idx) || (ui_temp1 > u1_max_ref_idx)
    ++                        || (u4_temp < 1) || (ui_temp1 < 1))
    +         {
    +             return ERROR_NUM_REF;
    +         }
    +@@ -1531,10 +1533,7 @@ WORD32 ih264d_parse_bslice(dec_struct_t * ps_dec, UWORD16 u2_first_mb_in_slice)
                  }
      
                  num_entries = ((2 * num_entries) + 1);
    @@ -236,7 +321,7 @@ index 772964a..db64ce9 100644
                  size = num_entries * sizeof(void *);
                  size += PAD_MAP_IDX_POC * sizeof(void *);
     diff --git a/decoder/ih264d_parse_pslice.c b/decoder/ih264d_parse_pslice.c
    -index bcfbe05..d6b0f23 100644
    +index bcfbe05..9b9256b 100644
     --- a/decoder/ih264d_parse_pslice.c
     +++ b/decoder/ih264d_parse_pslice.c
     @@ -1696,10 +1696,8 @@ WORD32 ih264d_mark_err_slice_skip(dec_struct_t * ps_dec,
    @@ -252,6 +337,15 @@ index bcfbe05..d6b0f23 100644
              size = num_entries * sizeof(void *);
              size += PAD_MAP_IDX_POC * sizeof(void *);
      
    +@@ -1963,7 +1961,7 @@ WORD32 ih264d_parse_pslice(dec_struct_t *ps_dec, UWORD16 u2_first_mb_in_slice)
    + 
    + 
    +         UWORD8 u1_max_ref_idx = MAX_FRAMES << u1_field_pic_flag;
    +-        if(u4_temp > u1_max_ref_idx)
    ++        if(u4_temp > u1_max_ref_idx || u4_temp < 1)
    +         {
    +             return ERROR_NUM_REF;
    +         }
     @@ -2063,10 +2061,7 @@ WORD32 ih264d_parse_pslice(dec_struct_t *ps_dec, UWORD16 u2_first_mb_in_slice)
                      num_entries = 1;
                  }
    @@ -265,7 +359,7 @@ index bcfbe05..d6b0f23 100644
                  size = num_entries * sizeof(void *);
                  size += PAD_MAP_IDX_POC * sizeof(void *);
     diff --git a/decoder/ih264d_parse_slice.c b/decoder/ih264d_parse_slice.c
    -index fad2dff..bdfccb6 100644
    +index fad2dff..2d8a9af 100644
     --- a/decoder/ih264d_parse_slice.c
     +++ b/decoder/ih264d_parse_slice.c
     @@ -72,6 +72,7 @@
    @@ -312,7 +406,18 @@ index fad2dff..bdfccb6 100644
              }
      
              if(!ps_dec->ps_cur_pic)
    -@@ -1785,10 +1802,8 @@ WORD32 ih264d_parse_decode_slice(UWORD8 u1_is_idr_slice,
    +@@ -1365,9 +1382,8 @@ WORD32 ih264d_parse_decode_slice(UWORD8 u1_is_idr_slice,
    +         if(ps_dec->u1_dangling_field == 1)
    +         {
    +             ps_dec->u1_second_field = 1 - ps_dec->u1_second_field;
    +-            ps_cur_slice->u1_bottom_field_flag = u1_bottom_field_flag;
    +-            ps_dec->u2_prv_frame_num = u2_frame_num;
    +             ps_dec->u1_first_slice_in_stream = 0;
    ++            ps_dec->u1_top_bottom_decoded = TOP_FIELD_ONLY | BOT_FIELD_ONLY;
    +             return ERROR_DANGLING_FIELD_IN_PIC;
    +         }
    + 
    +@@ -1785,10 +1801,8 @@ WORD32 ih264d_parse_decode_slice(UWORD8 u1_is_idr_slice,
                  num_entries = 1;
              }
              num_entries = ((2 * num_entries) + 1);
    diff --git a/external_libhevc.patch b/external_libhevc.patch
    index cace2c6..dee93db 100644
    --- a/external_libhevc.patch
    +++ b/external_libhevc.patch
    @@ -43,9 +43,18 @@ index 93d2ad4..baa6375 100644
      }hrd_params_t;
      
     diff --git a/decoder/ihevcd_api.c b/decoder/ihevcd_api.c
    -index c661083..51e9670 100644
    +index c661083..2ae90b0 100644
     --- a/decoder/ihevcd_api.c
     +++ b/decoder/ihevcd_api.c
    +@@ -1215,7 +1215,7 @@ WORD32 ihevcd_allocate_static_bufs(iv_obj_t **pps_codec_obj,
    + 
    +     /* Request memory for static bitstream buffer which holds bitstream after emulation prevention */
    +     size = MIN_BITSBUF_SIZE;
    +-    pv_buf = pf_aligned_alloc(pv_mem_ctxt, 128, size);
    ++    pv_buf = pf_aligned_alloc(pv_mem_ctxt, 128, size + 16); //Alloc extra for parse optimization
    +     RETURN_IF((NULL == pv_buf), IV_FAIL);
    +     ps_codec->pu1_bitsbuf_static = pv_buf;
    +     ps_codec->u4_bitsbuf_size_static = size;
     @@ -1867,10 +1867,10 @@ WORD32 ihevcd_allocate_dynamic_bufs(codec_t *ps_codec)
          }
      
    @@ -60,8 +69,17 @@ index c661083..51e9670 100644
      
          size *= sizeof(UWORD16);
          pv_buf = ps_codec->pf_aligned_alloc(pv_mem_ctxt, 128, size);
    +@@ -1908,7 +1908,7 @@ WORD32 ihevcd_allocate_dynamic_bufs(codec_t *ps_codec)
    +     size = wd * ht;
    +     if(size > MIN_BITSBUF_SIZE)
    +     {
    +-        pv_buf = ps_codec->pf_aligned_alloc(pv_mem_ctxt, 128, size);
    ++        pv_buf = ps_codec->pf_aligned_alloc(pv_mem_ctxt, 128, size + 16); //Alloc extra for parse optimization
    +         RETURN_IF((NULL == pv_buf), IV_FAIL);
    +         ps_codec->pu1_bitsbuf_dynamic = pv_buf;
    +         ps_codec->u4_bitsbuf_size_dynamic = size;
     diff --git a/decoder/ihevcd_decode.c b/decoder/ihevcd_decode.c
    -index d656519..7b82e84 100644
    +index d656519..04ad8f5 100644
     --- a/decoder/ihevcd_decode.c
     +++ b/decoder/ihevcd_decode.c
     @@ -81,6 +81,7 @@
    @@ -72,7 +90,17 @@ index d656519..7b82e84 100644
      IHEVCD_ERROR_T ihevcd_fmt_conv(codec_t *ps_codec,
                                     process_ctxt_t *ps_proc,
                                     UWORD8 *pu1_y_dst,
    -@@ -471,6 +472,10 @@ WORD32 ihevcd_decode(iv_obj_t *ps_codec_obj, void *pv_api_ip, void *pv_api_op)
    +@@ -420,7 +421,8 @@ WORD32 ihevcd_decode(iv_obj_t *ps_codec_obj, void *pv_api_ip, void *pv_api_op)
    +     if(0 == ps_codec->i4_share_disp_buf && ps_codec->i4_header_mode == 0)
    +     {
    +         UWORD32 i;
    +-        if(ps_dec_ip->s_out_buffer.u4_num_bufs == 0)
    ++        if((ps_dec_ip->s_out_buffer.u4_num_bufs <= 0) ||
    ++           (ps_dec_ip->s_out_buffer.u4_num_bufs > IVD_VIDDEC_MAX_IO_BUFFERS))
    +         {
    +             ps_dec_op->u4_error_code |= 1 << IVD_UNSUPPORTEDPARAM;
    +             ps_dec_op->u4_error_code |= IVD_DISP_FRM_ZERO_OP_BUFS;
    +@@ -471,6 +473,10 @@ WORD32 ihevcd_decode(iv_obj_t *ps_codec_obj, void *pv_api_ip, void *pv_api_op)
                      ihevcd_init_proc_ctxt(ps_proc, 0);
                  }
      
    @@ -83,7 +111,7 @@ index d656519..7b82e84 100644
                  /* Set remaining number of rows to be processed */
                  ret = ihevcd_fmt_conv(ps_codec, &ps_codec->as_process[prev_proc_idx],
                                        ps_dec_ip->s_out_buffer.pu1_bufs[0],
    -@@ -628,7 +633,6 @@ WORD32 ihevcd_decode(iv_obj_t *ps_codec_obj, void *pv_api_ip, void *pv_api_op)
    +@@ -628,7 +634,6 @@ WORD32 ihevcd_decode(iv_obj_t *ps_codec_obj, void *pv_api_ip, void *pv_api_op)
      
              if(IHEVCD_IGNORE_SLICE == ret)
              {
    diff --git a/external_libmpeg2.patch b/external_libmpeg2.patch
    index cace2c6..dee93db 100644
    --- a/external_libmpeg2.patch
    +++ b/external_libmpeg2.patch
    @@ -43,9 +43,18 @@ index 93d2ad4..baa6375 100644
      }hrd_params_t;
      
     diff --git a/decoder/ihevcd_api.c b/decoder/ihevcd_api.c
    -index c661083..51e9670 100644
    +index c661083..2ae90b0 100644
     --- a/decoder/ihevcd_api.c
     +++ b/decoder/ihevcd_api.c
    +@@ -1215,7 +1215,7 @@ WORD32 ihevcd_allocate_static_bufs(iv_obj_t **pps_codec_obj,
    + 
    +     /* Request memory for static bitstream buffer which holds bitstream after emulation prevention */
    +     size = MIN_BITSBUF_SIZE;
    +-    pv_buf = pf_aligned_alloc(pv_mem_ctxt, 128, size);
    ++    pv_buf = pf_aligned_alloc(pv_mem_ctxt, 128, size + 16); //Alloc extra for parse optimization
    +     RETURN_IF((NULL == pv_buf), IV_FAIL);
    +     ps_codec->pu1_bitsbuf_static = pv_buf;
    +     ps_codec->u4_bitsbuf_size_static = size;
     @@ -1867,10 +1867,10 @@ WORD32 ihevcd_allocate_dynamic_bufs(codec_t *ps_codec)
          }
      
    @@ -60,8 +69,17 @@ index c661083..51e9670 100644
      
          size *= sizeof(UWORD16);
          pv_buf = ps_codec->pf_aligned_alloc(pv_mem_ctxt, 128, size);
    +@@ -1908,7 +1908,7 @@ WORD32 ihevcd_allocate_dynamic_bufs(codec_t *ps_codec)
    +     size = wd * ht;
    +     if(size > MIN_BITSBUF_SIZE)
    +     {
    +-        pv_buf = ps_codec->pf_aligned_alloc(pv_mem_ctxt, 128, size);
    ++        pv_buf = ps_codec->pf_aligned_alloc(pv_mem_ctxt, 128, size + 16); //Alloc extra for parse optimization
    +         RETURN_IF((NULL == pv_buf), IV_FAIL);
    +         ps_codec->pu1_bitsbuf_dynamic = pv_buf;
    +         ps_codec->u4_bitsbuf_size_dynamic = size;
     diff --git a/decoder/ihevcd_decode.c b/decoder/ihevcd_decode.c
    -index d656519..7b82e84 100644
    +index d656519..04ad8f5 100644
     --- a/decoder/ihevcd_decode.c
     +++ b/decoder/ihevcd_decode.c
     @@ -81,6 +81,7 @@
    @@ -72,7 +90,17 @@ index d656519..7b82e84 100644
      IHEVCD_ERROR_T ihevcd_fmt_conv(codec_t *ps_codec,
                                     process_ctxt_t *ps_proc,
                                     UWORD8 *pu1_y_dst,
    -@@ -471,6 +472,10 @@ WORD32 ihevcd_decode(iv_obj_t *ps_codec_obj, void *pv_api_ip, void *pv_api_op)
    +@@ -420,7 +421,8 @@ WORD32 ihevcd_decode(iv_obj_t *ps_codec_obj, void *pv_api_ip, void *pv_api_op)
    +     if(0 == ps_codec->i4_share_disp_buf && ps_codec->i4_header_mode == 0)
    +     {
    +         UWORD32 i;
    +-        if(ps_dec_ip->s_out_buffer.u4_num_bufs == 0)
    ++        if((ps_dec_ip->s_out_buffer.u4_num_bufs <= 0) ||
    ++           (ps_dec_ip->s_out_buffer.u4_num_bufs > IVD_VIDDEC_MAX_IO_BUFFERS))
    +         {
    +             ps_dec_op->u4_error_code |= 1 << IVD_UNSUPPORTEDPARAM;
    +             ps_dec_op->u4_error_code |= IVD_DISP_FRM_ZERO_OP_BUFS;
    +@@ -471,6 +473,10 @@ WORD32 ihevcd_decode(iv_obj_t *ps_codec_obj, void *pv_api_ip, void *pv_api_op)
                      ihevcd_init_proc_ctxt(ps_proc, 0);
                  }
      
    @@ -83,7 +111,7 @@ index d656519..7b82e84 100644
                  /* Set remaining number of rows to be processed */
                  ret = ihevcd_fmt_conv(ps_codec, &ps_codec->as_process[prev_proc_idx],
                                        ps_dec_ip->s_out_buffer.pu1_bufs[0],
    -@@ -628,7 +633,6 @@ WORD32 ihevcd_decode(iv_obj_t *ps_codec_obj, void *pv_api_ip, void *pv_api_op)
    +@@ -628,7 +634,6 @@ WORD32 ihevcd_decode(iv_obj_t *ps_codec_obj, void *pv_api_ip, void *pv_api_op)
      
              if(IHEVCD_IGNORE_SLICE == ret)
              {
    diff --git a/external_skia.patch b/external_skia.patch
    index ebc9f24..9e0708e 100644
    --- a/external_skia.patch
    +++ b/external_skia.patch
    @@ -1,3 +1,134 @@
    +diff --git a/Android.mk b/Android.mk
    +index 77c258a..4dbd17b 100644
    +--- a/Android.mk
    ++++ b/Android.mk
    +@@ -643,7 +643,6 @@ LOCAL_SRC_FILES := \
    + 	src/utils/SkPatchGrid.cpp \
    + 	src/utils/SkPatchUtils.cpp \
    + 	src/utils/SkRGBAToYUV.cpp \
    +-	src/utils/SkRTConf.cpp \
    + 	src/utils/SkTextBox.cpp \
    + 	src/utils/SkTextureCompressor.cpp \
    + 	src/utils/SkTextureCompressor_ASTC.cpp \
    +diff --git a/dm/Android.mk b/dm/Android.mk
    +index e51da0f..f362c99 100644
    +--- a/dm/Android.mk
    ++++ b/dm/Android.mk
    +@@ -213,7 +213,6 @@ LOCAL_SRC_FILES := \
    + 	../tests/PremulAlphaRoundTripTest.cpp \
    + 	../tests/QuickRejectTest.cpp \
    + 	../tests/RRectInPathTest.cpp \
    +-	../tests/RTConfRegistryTest.cpp \
    + 	../tests/RTreeTest.cpp \
    + 	../tests/RandomTest.cpp \
    + 	../tests/ReadPixelsTest.cpp \
    +diff --git a/include/core/SkOSFile.h b/include/core/SkOSFile.h
    +index f977327..cb775e2 100644
    +--- a/include/core/SkOSFile.h
    ++++ b/include/core/SkOSFile.h
    +@@ -31,20 +31,12 @@ FILE* sk_fopen(const char path[], SkFILE_Flags);
    + void    sk_fclose(FILE*);
    + 
    + size_t  sk_fgetsize(FILE*);
    +-/** Return true if the file could seek back to the beginning
    +-*/
    +-bool    sk_frewind(FILE*);
    + 
    +-size_t  sk_fread(void* buffer, size_t byteCount, FILE*);
    + size_t  sk_fwrite(const void* buffer, size_t byteCount, FILE*);
    + 
    +-char*   sk_fgets(char* str, int size, FILE* f);
    +-
    + void    sk_fflush(FILE*);
    + void    sk_fsync(FILE*);
    + 
    +-bool    sk_fseek(FILE*, size_t);
    +-bool    sk_fmove(FILE*, long);
    + size_t  sk_ftell(FILE*);
    + 
    + /** Maps a file into memory. Returns the address and length on success, NULL otherwise.
    +@@ -80,8 +72,9 @@ bool    sk_exists(const char *path, SkFILE_Flags = (SkFILE_Flags)0);
    + // Returns true if a directory exists at this path.
    + bool    sk_isdir(const char *path);
    + 
    +-// Have we reached the end of the file?
    +-int sk_feof(FILE *);
    ++// Like pread, but may affect the file position marker.
    ++// Returns the number of bytes read or SIZE_MAX if failed.
    ++size_t sk_qread(FILE*, void* buffer, size_t count, size_t offset);
    + 
    + 
    + // Create a new directory at this path; returns true if successful.
    +diff --git a/include/core/SkStream.h b/include/core/SkStream.h
    +index 4502416..265fb64 100644
    +--- a/include/core/SkStream.h
    ++++ b/include/core/SkStream.h
    +@@ -11,8 +11,9 @@
    + #include "SkRefCnt.h"
    + #include "SkScalar.h"
    + 
    +-class SkData;
    ++#include <memory>
    + 
    ++class SkData;
    + class SkStream;
    + class SkStreamRewindable;
    + class SkStreamSeekable;
    +@@ -231,28 +232,20 @@ public:
    +     /** Initialize the stream by calling sk_fopen on the specified path.
    +      *  This internal stream will be closed in the destructor.
    +      */
    +-    explicit SkFILEStream(const char path[] = NULL);
    ++    explicit SkFILEStream(const char path[] = nullptr);
    + 
    +-    enum Ownership {
    +-        kCallerPasses_Ownership,
    +-        kCallerRetains_Ownership
    +-    };
    +     /** Initialize the stream with an existing C file stream.
    +-     *  While this stream exists, it assumes exclusive access to the C file stream.
    +-     *  The C file stream will be closed in the destructor unless the caller specifies
    +-     *  kCallerRetains_Ownership.
    ++     *  The C file stream will be closed in the destructor.
    +      */
    +-    explicit SkFILEStream(FILE* file, Ownership ownership = kCallerPasses_Ownership);
    ++    explicit SkFILEStream(FILE* file);
    + 
    +     virtual ~SkFILEStream();
    + 
    +     /** Returns true if the current path could be opened. */
    +-    bool isValid() const { return fFILE != NULL; }
    ++    bool isValid() const { return fFILE != nullptr; }
    + 
    +-    /** Close the current file, and open a new file with the specified path.
    +-     *  If path is NULL, just close the current file.
    +-     */
    +-    void setPath(const char path[]);
    ++    /** Close this SkFILEStream. */
    ++    void close();
    + 
    +     size_t read(void* buffer, size_t size) override;
    +     bool isAtEnd() const override;
    +@@ -270,11 +263,14 @@ public:
    +     const void* getMemoryBase() override;
    + 
    + private:
    +-    FILE*     fFILE;
    +-    SkString    fName;
    +-    Ownership   fOwnership;
    +-    // fData is lazilly initialized when needed.
    +-    mutable SkAutoTUnref<SkData> fData;
    ++    explicit SkFILEStream(std::shared_ptr<FILE>, size_t size, size_t offset);
    ++    explicit SkFILEStream(std::shared_ptr<FILE>, size_t size, size_t offset, size_t originalOffset);
    ++
    ++    std::shared_ptr<FILE> fFILE;
    ++    // My own council will I keep on sizes and offsets.
    ++    size_t fSize;
    ++    size_t fOffset;
    ++    size_t fOriginalOffset;
    + 
    +     typedef SkStreamAsset INHERITED;
    + };
     diff --git a/resources/invalid_images/b38116746.ico b/resources/invalid_images/b38116746.ico
     new file mode 100644
     index 0000000..35ee5b5
    @@ -36,6 +167,352 @@ index dc4222a..8b3d26d 100644
              SkAutoTDelete<SkMemoryStream> embeddedStream(new SkMemoryStream(data.get()));
              bytesRead += size;
      
    +diff --git a/src/codec/SkIcoCodec.h b/src/codec/SkIcoCodec.h
    +index 9a3f248..5a3740d 100644
    +--- a/src/codec/SkIcoCodec.h
    ++++ b/src/codec/SkIcoCodec.h
    +@@ -8,6 +8,7 @@
    + #include "SkCodec.h"
    + #include "SkImageInfo.h"
    + #include "SkStream.h"
    ++#include "SkTArray.h"
    + #include "SkTypes.h"
    + 
    + /*
    +diff --git a/src/codec/SkWebpCodec.cpp b/src/codec/SkWebpCodec.cpp
    +index 6cfb385..8acd205 100644
    +--- a/src/codec/SkWebpCodec.cpp
    ++++ b/src/codec/SkWebpCodec.cpp
    +@@ -235,7 +235,10 @@ SkCodec::Result SkWebpCodec::onGetPixels(const SkImageInfo& dstInfo, void* dst,
    +     while (true) {
    +         const size_t bytesRead = stream()->read(buffer, BUFFER_SIZE);
    +         if (0 == bytesRead) {
    +-            WebPIDecGetRGB(idec, rowsDecoded, NULL, NULL, NULL);
    ++            if (!WebPIDecGetRGB(idec, rowsDecoded, NULL, NULL, NULL)
    ++                    || rowsDecoded && *rowsDecoded <= 0) {
    ++                return kInvalidInput;
    ++            }
    +             return kIncompleteInput;
    +         }
    + 
    +diff --git a/src/core/SkPath.cpp b/src/core/SkPath.cpp
    +index 320448a..9eb5cd1 100644
    +--- a/src/core/SkPath.cpp
    ++++ b/src/core/SkPath.cpp
    +@@ -2082,6 +2082,7 @@ size_t SkPath::readFromMemory(const void* storage, size_t length) {
    + 
    + ///////////////////////////////////////////////////////////////////////////////
    + 
    ++#include "SkString.h"
    + #include "SkStringUtils.h"
    + #include "SkStream.h"
    + 
    +diff --git a/src/core/SkStream.cpp b/src/core/SkStream.cpp
    +index 9529308..4f00768 100644
    +--- a/src/core/SkStream.cpp
    ++++ b/src/core/SkStream.cpp
    +@@ -180,105 +180,95 @@ bool SkWStream::writeStream(SkStream* stream, size_t length) {
    + 
    + ///////////////////////////////////////////////////////////////////////////////
    + 
    +-SkFILEStream::SkFILEStream(const char file[]) : fName(file), fOwnership(kCallerPasses_Ownership) {
    +-    fFILE = file ? sk_fopen(fName.c_str(), kRead_SkFILE_Flag) : nullptr;
    +-}
    ++SkFILEStream::SkFILEStream(std::shared_ptr<FILE> file, size_t size,
    ++                           size_t offset, size_t originalOffset)
    ++    : fFILE(std::move(file))
    ++    , fSize(size)
    ++    , fOffset(SkTMin(offset, fSize))
    ++    , fOriginalOffset(SkTMin(originalOffset, fSize))
    ++{ }
    + 
    +-SkFILEStream::SkFILEStream(FILE* file, Ownership ownership)
    +-    : fFILE(file)
    +-    , fOwnership(ownership) {
    +-}
    ++SkFILEStream::SkFILEStream(std::shared_ptr<FILE> file, size_t size, size_t offset)
    ++    : SkFILEStream(std::move(file), size, offset, offset)
    ++{ }
    ++
    ++SkFILEStream::SkFILEStream(FILE* file)
    ++    : SkFILEStream(std::shared_ptr<FILE>(file, sk_fclose),
    ++                   file ? sk_fgetsize(file) : 0,
    ++                   file ? sk_ftell(file) : 0)
    ++{ }
    ++
    ++
    ++SkFILEStream::SkFILEStream(const char path[])
    ++    : SkFILEStream(path ? sk_fopen(path, kRead_SkFILE_Flag) : nullptr)
    ++{ }
    + 
    + SkFILEStream::~SkFILEStream() {
    +-    if (fFILE && fOwnership != kCallerRetains_Ownership) {
    +-        sk_fclose(fFILE);
    +-    }
    ++    this->close();
    + }
    + 
    +-void SkFILEStream::setPath(const char path[]) {
    +-    fName.set(path);
    +-    if (fFILE) {
    +-        sk_fclose(fFILE);
    +-        fFILE = nullptr;
    +-    }
    +-    if (path) {
    +-        fFILE = sk_fopen(fName.c_str(), kRead_SkFILE_Flag);
    +-    }
    ++void SkFILEStream::close() {
    ++    fFILE.reset();
    ++    fSize = 0;
    ++    fOffset = 0;
    + }
    + 
    + size_t SkFILEStream::read(void* buffer, size_t size) {
    +-    if (fFILE) {
    +-        return sk_fread(buffer, size, fFILE);
    ++    if (size > fSize - fOffset) {
    ++        size = fSize - fOffset;
    ++    }
    ++    size_t bytesRead = size;
    ++    if (buffer) {
    ++        bytesRead = sk_qread(fFILE.get(), buffer, size, fOffset);
    ++    }
    ++    if (bytesRead == SIZE_MAX) {
    ++        return 0;
    +     }
    +-    return 0;
    ++    fOffset += bytesRead;
    ++    return bytesRead;
    + }
    + 
    + bool SkFILEStream::isAtEnd() const {
    +-    return sk_feof(fFILE);
    ++    if (fOffset == fSize) {
    ++        return true;
    ++    }
    ++    return fOffset >= sk_fgetsize(fFILE.get());
    + }
    + 
    + bool SkFILEStream::rewind() {
    +-    if (fFILE) {
    +-        if (sk_frewind(fFILE)) {
    +-            return true;
    +-        }
    +-        // we hit an error
    +-        sk_fclose(fFILE);
    +-        fFILE = nullptr;
    +-    }
    +-    return false;
    ++    // TODO: fOriginalOffset instead of 0.
    ++    fOffset = 0;
    ++    return true;
    + }
    + 
    + SkStreamAsset* SkFILEStream::duplicate() const {
    +-    if (nullptr == fFILE) {
    +-        return new SkMemoryStream();
    +-    }
    +-
    +-    if (fData.get()) {
    +-        return new SkMemoryStream(fData);
    +-    }
    +-
    +-    if (!fName.isEmpty()) {
    +-        SkAutoTDelete<SkFILEStream> that(new SkFILEStream(fName.c_str()));
    +-        if (sk_fidentical(that->fFILE, this->fFILE)) {
    +-            return that.detach();
    +-        }
    +-    }
    +-
    +-    fData.reset(SkData::NewFromFILE(fFILE));
    +-    if (nullptr == fData.get()) {
    +-        return nullptr;
    +-    }
    +-    return new SkMemoryStream(fData);
    ++    // TODO: fOriginalOffset instead of 0.
    ++    return new SkFILEStream(fFILE, fSize, 0, fOriginalOffset);
    + }
    + 
    + size_t SkFILEStream::getPosition() const {
    +-    return sk_ftell(fFILE);
    ++    return fOffset;
    + }
    + 
    + bool SkFILEStream::seek(size_t position) {
    +-    return sk_fseek(fFILE, position);
    ++    fOffset = position > fSize ? fSize : position;
    ++    return true;
    + }
    + 
    + bool SkFILEStream::move(long offset) {
    +-    return sk_fmove(fFILE, offset);
    ++    return this->seek(fOffset + offset);
    + }
    + 
    + SkStreamAsset* SkFILEStream::fork() const {
    +-    SkAutoTDelete<SkStreamAsset> that(this->duplicate());
    +-    that->seek(this->getPosition());
    +-    return that.detach();
    ++    return new SkFILEStream(fFILE, fSize, fOffset, fOriginalOffset);
    + }
    + 
    + size_t SkFILEStream::getLength() const {
    +-    return sk_fgetsize(fFILE);
    ++    return fSize;
    + }
    + 
    + const void* SkFILEStream::getMemoryBase() {
    +-    if (nullptr == fData.get()) {
    +-        return nullptr;
    +-    }
    +-    return fData->data();
    ++    return nullptr;
    + }
    + 
    + ///////////////////////////////////////////////////////////////////////////////
    +diff --git a/src/ports/SkOSFile_posix.cpp b/src/ports/SkOSFile_posix.cpp
    +index 396de68..48b5b95 100644
    +--- a/src/ports/SkOSFile_posix.cpp
    ++++ b/src/ports/SkOSFile_posix.cpp
    +@@ -95,6 +95,18 @@ void* sk_fmmap(FILE* f, size_t* size) {
    +     return sk_fdmmap(fd, size);
    + }
    + 
    ++size_t sk_qread(FILE* file, void* buffer, size_t count, size_t offset) {
    ++    int fd = sk_fileno(file);
    ++    if (fd < 0) {
    ++        return SIZE_MAX;
    ++    }
    ++    ssize_t bytesRead = pread(fd, buffer, count, offset);
    ++    if (bytesRead < 0) {
    ++        return SIZE_MAX;
    ++    }
    ++    return bytesRead;
    ++}
    ++
    + ////////////////////////////////////////////////////////////////////////////
    + 
    + struct SkOSFileIterData {
    +diff --git a/src/ports/SkOSFile_stdio.cpp b/src/ports/SkOSFile_stdio.cpp
    +index 915b87b..ee997e9 100644
    +--- a/src/ports/SkOSFile_stdio.cpp
    ++++ b/src/ports/SkOSFile_stdio.cpp
    +@@ -80,15 +80,6 @@ FILE* sk_fopen(const char path[], SkFILE_Flags flags) {
    +     return file;
    + }
    + 
    +-char* sk_fgets(char* str, int size, FILE* f) {
    +-    return fgets(str, size, (FILE *)f);
    +-}
    +-
    +-int sk_feof(FILE *f) {
    +-    // no :: namespace qualifier because it breaks android
    +-    return feof((FILE *)f);
    +-}
    +-
    + size_t sk_fgetsize(FILE* f) {
    +     SkASSERT(f);
    + 
    +@@ -107,32 +98,6 @@ size_t sk_fgetsize(FILE* f) {
    +     return size;
    + }
    + 
    +-bool sk_frewind(FILE* f) {
    +-    SkASSERT(f);
    +-    ::rewind(f);
    +-    return true;
    +-}
    +-
    +-size_t sk_fread(void* buffer, size_t byteCount, FILE* f) {
    +-    SkASSERT(f);
    +-    if (buffer == nullptr) {
    +-        size_t curr = ftell(f);
    +-        if ((long)curr == -1) {
    +-            SkDEBUGF(("sk_fread: ftell(%p) returned -1 feof:%d ferror:%d\n", f, feof(f), ferror(f)));
    +-            return 0;
    +-        }
    +-        int err = fseek(f, (long)byteCount, SEEK_CUR);
    +-        if (err != 0) {
    +-            SkDEBUGF(("sk_fread: fseek(%d) tell:%d failed with feof:%d ferror:%d returned:%d\n",
    +-                        byteCount, curr, feof(f), ferror(f), err));
    +-            return 0;
    +-        }
    +-        return byteCount;
    +-    }
    +-    else
    +-        return fread(buffer, 1, byteCount, f);
    +-}
    +-
    + size_t sk_fwrite(const void* buffer, size_t byteCount, FILE* f) {
    +     SkASSERT(f);
    +     return fwrite(buffer, 1, byteCount, f);
    +@@ -151,16 +116,6 @@ void sk_fsync(FILE* f) {
    + #endif
    + }
    + 
    +-bool sk_fseek(FILE* f, size_t byteCount) {
    +-    int err = fseek(f, (long)byteCount, SEEK_SET);
    +-    return err == 0;
    +-}
    +-
    +-bool sk_fmove(FILE* f, long byteCount) {
    +-    int err = fseek(f, byteCount, SEEK_CUR);
    +-    return err == 0;
    +-}
    +-
    + size_t sk_ftell(FILE* f) {
    +     long curr = ftell(f);
    +     if (curr < 0) {
    +@@ -170,8 +125,9 @@ size_t sk_ftell(FILE* f) {
    + }
    + 
    + void sk_fclose(FILE* f) {
    +-    SkASSERT(f);
    +-    fclose(f);
    ++    if (f) {
    ++        fclose(f);
    ++    }
    + }
    + 
    + bool sk_isdir(const char *path) {
    +diff --git a/src/ports/SkOSFile_win.cpp b/src/ports/SkOSFile_win.cpp
    +index 6bdf9ab..414393a 100644
    +--- a/src/ports/SkOSFile_win.cpp
    ++++ b/src/ports/SkOSFile_win.cpp
    +@@ -124,6 +124,33 @@ void* sk_fmmap(FILE* f, size_t* length) {
    +     return sk_fdmmap(fileno, length);
    + }
    + 
    ++size_t sk_qread(FILE* file, void* buffer, size_t count, size_t offset) {
    ++    int fileno = sk_fileno(file);
    ++    HANDLE fileHandle = (HANDLE)_get_osfhandle(fileno);
    ++    if (INVALID_HANDLE_VALUE == file) {
    ++        return SIZE_MAX;
    ++    }
    ++
    ++    OVERLAPPED overlapped = {0};
    ++    ULARGE_INTEGER winOffset;
    ++    winOffset.QuadPart = offset;
    ++    overlapped.Offset = winOffset.LowPart;
    ++    overlapped.OffsetHigh = winOffset.HighPart;
    ++
    ++    if (!SkTFitsIn<DWORD>(count)) {
    ++        count = std::numeric_limits<DWORD>::max();
    ++    }
    ++
    ++    DWORD bytesRead;
    ++    if (ReadFile(fileHandle, buffer, static_cast<DWORD>(count), &bytesRead, &overlapped)) {
    ++        return bytesRead;
    ++    }
    ++    if (GetLastError() == ERROR_HANDLE_EOF) {
    ++        return 0;
    ++    }
    ++    return SIZE_MAX;
    ++}
    ++
    + ////////////////////////////////////////////////////////////////////////////
    + 
    + struct SkOSFileIterData {
     diff --git a/tests/BadIcoTest.cpp b/tests/BadIcoTest.cpp
     index c387e15..f6b1c46 100644
     --- a/tests/BadIcoTest.cpp
    @@ -48,3 +525,1672 @@ index c387e15..f6b1c46 100644
          };
      
          const char* badImagesFolder = "invalid_images";
    +diff --git a/tests/CodecTest.cpp b/tests/CodecTest.cpp
    +new file mode 100644
    +index 0000000..6bb0f1b
    +--- /dev/null
    ++++ b/tests/CodecTest.cpp
    +@@ -0,0 +1,1615 @@
    ++/*
    ++ * Copyright 2015 Google Inc.
    ++ *
    ++ * Use of this source code is governed by a BSD-style license that can be
    ++ * found in the LICENSE file.
    ++ */
    ++
    ++#include "FakeStreams.h"
    ++#include "Resources.h"
    ++#include "SkAndroidCodec.h"
    ++#include "SkAutoMalloc.h"
    ++#include "SkBitmap.h"
    ++#include "SkCodec.h"
    ++#include "SkCodecImageGenerator.h"
    ++#include "SkColorSpace_XYZ.h"
    ++#include "SkColorSpacePriv.h"
    ++#include "SkData.h"
    ++#include "SkFrontBufferedStream.h"
    ++#include "SkImageEncoder.h"
    ++#include "SkImageEncoderPriv.h"
    ++#include "SkMD5.h"
    ++#include "SkOSPath.h"
    ++#include "SkPngChunkReader.h"
    ++#include "SkRandom.h"
    ++#include "SkStream.h"
    ++#include "SkStreamPriv.h"
    ++#include "Test.h"
    ++
    ++#include "png.h"
    ++
    ++#include "sk_tool_utils.h"
    ++
    ++#if PNG_LIBPNG_VER_MAJOR == 1 && PNG_LIBPNG_VER_MINOR < 5
    ++    // FIXME (scroggo): Google3 needs to be updated to use a newer version of libpng. In
    ++    // the meantime, we had to break some pieces of SkPngCodec in order to support Google3.
    ++    // The parts that are broken are likely not used by Google3.
    ++    #define SK_PNG_DISABLE_TESTS
    ++#endif
    ++
    ++static void md5(const SkBitmap& bm, SkMD5::Digest* digest) {
    ++    SkAutoLockPixels autoLockPixels(bm);
    ++    SkASSERT(bm.getPixels());
    ++    SkMD5 md5;
    ++    size_t rowLen = bm.info().bytesPerPixel() * bm.width();
    ++    for (int y = 0; y < bm.height(); ++y) {
    ++        md5.write(bm.getAddr(0, y), rowLen);
    ++    }
    ++    md5.finish(*digest);
    ++}
    ++
    ++/**
    ++ *  Compute the digest for bm and compare it to a known good digest.
    ++ *  @param r Reporter to assert that bm's digest matches goodDigest.
    ++ *  @param goodDigest The known good digest to compare to.
    ++ *  @param bm The bitmap to test.
    ++ */
    ++static void compare_to_good_digest(skiatest::Reporter* r, const SkMD5::Digest& goodDigest,
    ++                           const SkBitmap& bm) {
    ++    SkMD5::Digest digest;
    ++    md5(bm, &digest);
    ++    REPORTER_ASSERT(r, digest == goodDigest);
    ++}
    ++
    ++/**
    ++ *  Test decoding an SkCodec to a particular SkImageInfo.
    ++ *
    ++ *  Calling getPixels(info) should return expectedResult, and if goodDigest is non nullptr,
    ++ *  the resulting decode should match.
    ++ */
    ++template<typename Codec>
    ++static void test_info(skiatest::Reporter* r, Codec* codec, const SkImageInfo& info,
    ++                      SkCodec::Result expectedResult, const SkMD5::Digest* goodDigest) {
    ++    SkBitmap bm;
    ++    bm.allocPixels(info);
    ++    SkAutoLockPixels autoLockPixels(bm);
    ++
    ++    SkCodec::Result result = codec->getPixels(info, bm.getPixels(), bm.rowBytes());
    ++    REPORTER_ASSERT(r, result == expectedResult);
    ++
    ++    if (goodDigest) {
    ++        compare_to_good_digest(r, *goodDigest, bm);
    ++    }
    ++}
    ++
    ++SkIRect generate_random_subset(SkRandom* rand, int w, int h) {
    ++    SkIRect rect;
    ++    do {
    ++        rect.fLeft = rand->nextRangeU(0, w);
    ++        rect.fTop = rand->nextRangeU(0, h);
    ++        rect.fRight = rand->nextRangeU(0, w);
    ++        rect.fBottom = rand->nextRangeU(0, h);
    ++        rect.sort();
    ++    } while (rect.isEmpty());
    ++    return rect;
    ++}
    ++
    ++static void test_incremental_decode(skiatest::Reporter* r, SkCodec* codec, const SkImageInfo& info,
    ++        const SkMD5::Digest& goodDigest) {
    ++    SkBitmap bm;
    ++    bm.allocPixels(info);
    ++    SkAutoLockPixels autoLockPixels(bm);
    ++
    ++    REPORTER_ASSERT(r, SkCodec::kSuccess == codec->startIncrementalDecode(info, bm.getPixels(),
    ++                                                                          bm.rowBytes()));
    ++
    ++    REPORTER_ASSERT(r, SkCodec::kSuccess == codec->incrementalDecode());
    ++
    ++    compare_to_good_digest(r, goodDigest, bm);
    ++}
    ++
    ++// Test in stripes, similar to DM's kStripe_Mode
    ++static void test_in_stripes(skiatest::Reporter* r, SkCodec* codec, const SkImageInfo& info,
    ++                            const SkMD5::Digest& goodDigest) {
    ++    SkBitmap bm;
    ++    bm.allocPixels(info);
    ++    bm.eraseColor(SK_ColorYELLOW);
    ++
    ++    const int height = info.height();
    ++    // Note that if numStripes does not evenly divide height there will be an extra
    ++    // stripe.
    ++    const int numStripes = 4;
    ++
    ++    if (numStripes > height) {
    ++        // Image is too small.
    ++        return;
    ++    }
    ++
    ++    const int stripeHeight = height / numStripes;
    ++
    ++    // Iterate through the image twice. Once to decode odd stripes, and once for even.
    ++    for (int oddEven = 1; oddEven >= 0; oddEven--) {
    ++        for (int y = oddEven * stripeHeight; y < height; y += 2 * stripeHeight) {
    ++            SkIRect subset = SkIRect::MakeLTRB(0, y, info.width(),
    ++                                               SkTMin(y + stripeHeight, height));
    ++            SkCodec::Options options;
    ++            options.fSubset = &subset;
    ++            if (SkCodec::kSuccess != codec->startIncrementalDecode(info, bm.getAddr(0, y),
    ++                        bm.rowBytes(), &options)) {
    ++                ERRORF(r, "failed to start incremental decode!\ttop: %i\tbottom%i\n",
    ++                       subset.top(), subset.bottom());
    ++                return;
    ++            }
    ++            if (SkCodec::kSuccess != codec->incrementalDecode()) {
    ++                ERRORF(r, "failed incremental decode starting from line %i\n", y);
    ++                return;
    ++            }
    ++        }
    ++    }
    ++
    ++    compare_to_good_digest(r, goodDigest, bm);
    ++}
    ++
    ++template<typename Codec>
    ++static void test_codec(skiatest::Reporter* r, Codec* codec, SkBitmap& bm, const SkImageInfo& info,
    ++        const SkISize& size, SkCodec::Result expectedResult, SkMD5::Digest* digest,
    ++        const SkMD5::Digest* goodDigest) {
    ++
    ++    REPORTER_ASSERT(r, info.dimensions() == size);
    ++    bm.allocPixels(info);
    ++    SkAutoLockPixels autoLockPixels(bm);
    ++
    ++    SkCodec::Result result = codec->getPixels(info, bm.getPixels(), bm.rowBytes());
    ++    REPORTER_ASSERT(r, result == expectedResult);
    ++
    ++    md5(bm, digest);
    ++    if (goodDigest) {
    ++        REPORTER_ASSERT(r, *digest == *goodDigest);
    ++    }
    ++
    ++    {
    ++        // Test decoding to 565
    ++        SkImageInfo info565 = info.makeColorType(kRGB_565_SkColorType);
    ++        if (info.alphaType() == kOpaque_SkAlphaType) {
    ++            // Decoding to 565 should succeed.
    ++            SkBitmap bm565;
    ++            bm565.allocPixels(info565);
    ++            SkAutoLockPixels alp(bm565);
    ++
    ++            // This will allow comparison even if the image is incomplete.
    ++            bm565.eraseColor(SK_ColorBLACK);
    ++
    ++            REPORTER_ASSERT(r, expectedResult == codec->getPixels(info565,
    ++                    bm565.getPixels(), bm565.rowBytes()));
    ++
    ++            SkMD5::Digest digest565;
    ++            md5(bm565, &digest565);
    ++
    ++            // A dumb client's request for non-opaque should also succeed.
    ++            for (auto alpha : { kPremul_SkAlphaType, kUnpremul_SkAlphaType }) {
    ++                info565 = info565.makeAlphaType(alpha);
    ++                test_info(r, codec, info565, expectedResult, &digest565);
    ++            }
    ++        } else {
    ++            test_info(r, codec, info565, SkCodec::kInvalidConversion, nullptr);
    ++        }
    ++    }
    ++
    ++    if (codec->getInfo().colorType() == kGray_8_SkColorType) {
    ++        SkImageInfo grayInfo = codec->getInfo();
    ++        SkBitmap grayBm;
    ++        grayBm.allocPixels(grayInfo);
    ++        SkAutoLockPixels alp(grayBm);
    ++
    ++        grayBm.eraseColor(SK_ColorBLACK);
    ++
    ++        REPORTER_ASSERT(r, expectedResult == codec->getPixels(grayInfo,
    ++                grayBm.getPixels(), grayBm.rowBytes()));
    ++
    ++        SkMD5::Digest grayDigest;
    ++        md5(grayBm, &grayDigest);
    ++
    ++        for (auto alpha : { kPremul_SkAlphaType, kUnpremul_SkAlphaType }) {
    ++            grayInfo = grayInfo.makeAlphaType(alpha);
    ++            test_info(r, codec, grayInfo, expectedResult, &grayDigest);
    ++        }
    ++    }
    ++
    ++    // Verify that re-decoding gives the same result.  It is interesting to check this after
    ++    // a decode to 565, since choosing to decode to 565 may result in some of the decode
    ++    // options being modified.  These options should return to their defaults on another
    ++    // decode to kN32, so the new digest should match the old digest.
    ++    test_info(r, codec, info, expectedResult, digest);
    ++
    ++    {
    ++        // Check alpha type conversions
    ++        if (info.alphaType() == kOpaque_SkAlphaType) {
    ++            test_info(r, codec, info.makeAlphaType(kUnpremul_SkAlphaType),
    ++                      expectedResult, digest);
    ++            test_info(r, codec, info.makeAlphaType(kPremul_SkAlphaType),
    ++                      expectedResult, digest);
    ++        } else {
    ++            // Decoding to opaque should fail
    ++            test_info(r, codec, info.makeAlphaType(kOpaque_SkAlphaType),
    ++                      SkCodec::kInvalidConversion, nullptr);
    ++            SkAlphaType otherAt = info.alphaType();
    ++            if (kPremul_SkAlphaType == otherAt) {
    ++                otherAt = kUnpremul_SkAlphaType;
    ++            } else {
    ++                otherAt = kPremul_SkAlphaType;
    ++            }
    ++            // The other non-opaque alpha type should always succeed, but not match.
    ++            test_info(r, codec, info.makeAlphaType(otherAt), expectedResult, nullptr);
    ++        }
    ++    }
    ++}
    ++
    ++static bool supports_partial_scanlines(const char path[]) {
    ++    static const char* const exts[] = {
    ++        "jpg", "jpeg", "png", "webp"
    ++        "JPG", "JPEG", "PNG", "WEBP"
    ++    };
    ++
    ++    for (uint32_t i = 0; i < SK_ARRAY_COUNT(exts); i++) {
    ++        if (SkStrEndsWith(path, exts[i])) {
    ++            return true;
    ++        }
    ++    }
    ++    return false;
    ++}
    ++
    ++// FIXME: Break up this giant function
    ++static void check(skiatest::Reporter* r,
    ++                  const char path[],
    ++                  SkISize size,
    ++                  bool supportsScanlineDecoding,
    ++                  bool supportsSubsetDecoding,
    ++                  bool supportsIncomplete,
    ++                  bool supportsNewScanlineDecoding = false) {
    ++
    ++    std::unique_ptr<SkStream> stream(GetResourceAsStream(path));
    ++    if (!stream) {
    ++        return;
    ++    }
    ++
    ++    std::unique_ptr<SkCodec> codec(nullptr);
    ++    bool isIncomplete = supportsIncomplete;
    ++    if (isIncomplete) {
    ++        size_t size = stream->getLength();
    ++        sk_sp<SkData> data((SkData::MakeFromStream(stream.get(), 2 * size / 3)));
    ++        codec.reset(SkCodec::NewFromData(data));
    ++    } else {
    ++        codec.reset(SkCodec::NewFromStream(stream.release()));
    ++    }
    ++    if (!codec) {
    ++        ERRORF(r, "Unable to decode '%s'", path);
    ++        return;
    ++    }
    ++
    ++    // Test full image decodes with SkCodec
    ++    SkMD5::Digest codecDigest;
    ++    const SkImageInfo info = codec->getInfo().makeColorType(kN32_SkColorType);
    ++    SkBitmap bm;
    ++    SkCodec::Result expectedResult = isIncomplete ? SkCodec::kIncompleteInput : SkCodec::kSuccess;
    ++    test_codec(r, codec.get(), bm, info, size, expectedResult, &codecDigest, nullptr);
    ++
    ++    // Scanline decoding follows.
    ++
    ++    if (supportsNewScanlineDecoding && !isIncomplete) {
    ++        test_incremental_decode(r, codec.get(), info, codecDigest);
    ++        // This is only supported by codecs that use incremental decoding to
    ++        // support subset decodes - png and jpeg (once SkJpegCodec is
    ++        // converted).
    ++        if (SkStrEndsWith(path, "png") || SkStrEndsWith(path, "PNG")) {
    ++            test_in_stripes(r, codec.get(), info, codecDigest);
    ++        }
    ++    }
    ++
    ++    // Need to call startScanlineDecode() first.
    ++    REPORTER_ASSERT(r, codec->getScanlines(bm.getAddr(0, 0), 1, 0) == 0);
    ++    REPORTER_ASSERT(r, !codec->skipScanlines(1));
    ++    const SkCodec::Result startResult = codec->startScanlineDecode(info);
    ++    if (supportsScanlineDecoding) {
    ++        bm.eraseColor(SK_ColorYELLOW);
    ++
    ++        REPORTER_ASSERT(r, startResult == SkCodec::kSuccess);
    ++
    ++        for (int y = 0; y < info.height(); y++) {
    ++            const int lines = codec->getScanlines(bm.getAddr(0, y), 1, 0);
    ++            if (!isIncomplete) {
    ++                REPORTER_ASSERT(r, 1 == lines);
    ++            }
    ++        }
    ++        // verify that scanline decoding gives the same result.
    ++        if (SkCodec::kTopDown_SkScanlineOrder == codec->getScanlineOrder()) {
    ++            compare_to_good_digest(r, codecDigest, bm);
    ++        }
    ++
    ++        // Cannot continue to decode scanlines beyond the end
    ++        REPORTER_ASSERT(r, codec->getScanlines(bm.getAddr(0, 0), 1, 0)
    ++                == 0);
    ++
    ++        // Interrupting a scanline decode with a full decode starts from
    ++        // scratch
    ++        REPORTER_ASSERT(r, codec->startScanlineDecode(info) == SkCodec::kSuccess);
    ++        const int lines = codec->getScanlines(bm.getAddr(0, 0), 1, 0);
    ++        if (!isIncomplete) {
    ++            REPORTER_ASSERT(r, lines == 1);
    ++        }
    ++        REPORTER_ASSERT(r, codec->getPixels(bm.info(), bm.getPixels(), bm.rowBytes())
    ++                == expectedResult);
    ++        REPORTER_ASSERT(r, codec->getScanlines(bm.getAddr(0, 0), 1, 0)
    ++                == 0);
    ++        REPORTER_ASSERT(r, codec->skipScanlines(1)
    ++                == 0);
    ++
    ++        // Test partial scanline decodes
    ++        if (supports_partial_scanlines(path) && info.width() >= 3) {
    ++            SkCodec::Options options;
    ++            int width = info.width();
    ++            int height = info.height();
    ++            SkIRect subset = SkIRect::MakeXYWH(2 * (width / 3), 0, width / 3, height);
    ++            options.fSubset = &subset;
    ++
    ++            const SkCodec::Result partialStartResult = codec->startScanlineDecode(info, &options,
    ++                    nullptr, nullptr);
    ++            REPORTER_ASSERT(r, partialStartResult == SkCodec::kSuccess);
    ++
    ++            for (int y = 0; y < height; y++) {
    ++                const int lines = codec->getScanlines(bm.getAddr(0, y), 1, 0);
    ++                if (!isIncomplete) {
    ++                    REPORTER_ASSERT(r, 1 == lines);
    ++                }
    ++            }
    ++        }
    ++    } else {
    ++        REPORTER_ASSERT(r, startResult == SkCodec::kUnimplemented);
    ++    }
    ++
    ++    // The rest of this function tests decoding subsets, and will decode an arbitrary number of
    ++    // random subsets.
    ++    // Do not attempt to decode subsets of an image of only once pixel, since there is no
    ++    // meaningful subset.
    ++    if (size.width() * size.height() == 1) {
    ++        return;
    ++    }
    ++
    ++    SkRandom rand;
    ++    SkIRect subset;
    ++    SkCodec::Options opts;
    ++    opts.fSubset = &subset;
    ++    for (int i = 0; i < 5; i++) {
    ++        subset = generate_random_subset(&rand, size.width(), size.height());
    ++        SkASSERT(!subset.isEmpty());
    ++        const bool supported = codec->getValidSubset(&subset);
    ++        REPORTER_ASSERT(r, supported == supportsSubsetDecoding);
    ++
    ++        SkImageInfo subsetInfo = info.makeWH(subset.width(), subset.height());
    ++        SkBitmap bm;
    ++        bm.allocPixels(subsetInfo);
    ++        const SkCodec::Result result = codec->getPixels(bm.info(), bm.getPixels(), bm.rowBytes(),
    ++                                                        &opts, nullptr, nullptr);
    ++
    ++        if (supportsSubsetDecoding) {
    ++            if (expectedResult == SkCodec::kSuccess) {
    ++                REPORTER_ASSERT(r, result == expectedResult);
    ++            }
    ++            // Webp is the only codec that supports subsets, and it will have modified the subset
    ++            // to have even left/top.
    ++            REPORTER_ASSERT(r, SkIsAlign2(subset.fLeft) && SkIsAlign2(subset.fTop));
    ++        } else {
    ++            // No subsets will work.
    ++            REPORTER_ASSERT(r, result == SkCodec::kUnimplemented);
    ++        }
    ++    }
    ++
    ++    // SkAndroidCodec tests
    ++    if (supportsScanlineDecoding || supportsSubsetDecoding || supportsNewScanlineDecoding) {
    ++
    ++        std::unique_ptr<SkStream> stream(GetResourceAsStream(path));
    ++        if (!stream) {
    ++            return;
    ++        }
    ++
    ++        std::unique_ptr<SkAndroidCodec> androidCodec(nullptr);
    ++        if (isIncomplete) {
    ++            size_t size = stream->getLength();
    ++            sk_sp<SkData> data((SkData::MakeFromStream(stream.get(), 2 * size / 3)));
    ++            androidCodec.reset(SkAndroidCodec::NewFromData(data));
    ++        } else {
    ++            androidCodec.reset(SkAndroidCodec::NewFromStream(stream.release()));
    ++        }
    ++        if (!androidCodec) {
    ++            ERRORF(r, "Unable to decode '%s'", path);
    ++            return;
    ++        }
    ++
    ++        SkBitmap bm;
    ++        SkMD5::Digest androidCodecDigest;
    ++        test_codec(r, androidCodec.get(), bm, info, size, expectedResult, &androidCodecDigest,
    ++                   &codecDigest);
    ++    }
    ++
    ++    if (!isIncomplete) {
    ++        // Test SkCodecImageGenerator
    ++        std::unique_ptr<SkStream> stream(GetResourceAsStream(path));
    ++        sk_sp<SkData> fullData(SkData::MakeFromStream(stream.get(), stream->getLength()));
    ++        std::unique_ptr<SkImageGenerator> gen(
    ++                SkCodecImageGenerator::MakeFromEncodedCodec(fullData));
    ++        SkBitmap bm;
    ++        bm.allocPixels(info);
    ++        SkAutoLockPixels autoLockPixels(bm);
    ++        REPORTER_ASSERT(r, gen->getPixels(info, bm.getPixels(), bm.rowBytes()));
    ++        compare_to_good_digest(r, codecDigest, bm);
    ++
    ++#ifndef SK_PNG_DISABLE_TESTS
    ++        // Test using SkFrontBufferedStream, as Android does
    ++        SkStream* bufferedStream = SkFrontBufferedStream::Create(
    ++                new SkMemoryStream(std::move(fullData)), SkCodec::MinBufferedBytesNeeded());
    ++        REPORTER_ASSERT(r, bufferedStream);
    ++        codec.reset(SkCodec::NewFromStream(bufferedStream));
    ++        REPORTER_ASSERT(r, codec);
    ++        if (codec) {
    ++            test_info(r, codec.get(), info, SkCodec::kSuccess, &codecDigest);
    ++        }
    ++#endif
    ++    }
    ++
    ++    // If we've just tested incomplete decodes, let's run the same test again on full decodes.
    ++    if (isIncomplete) {
    ++        check(r, path, size, supportsScanlineDecoding, supportsSubsetDecoding, false,
    ++              supportsNewScanlineDecoding);
    ++    }
    ++}
    ++
    ++DEF_TEST(Codec_wbmp, r) {
    ++    check(r, "mandrill.wbmp", SkISize::Make(512, 512), true, false, true);
    ++}
    ++
    ++DEF_TEST(Codec_webp, r) {
    ++    check(r, "baby_tux.webp", SkISize::Make(386, 395), false, true, true);
    ++    check(r, "color_wheel.webp", SkISize::Make(128, 128), false, true, true);
    ++    check(r, "yellow_rose.webp", SkISize::Make(400, 301), false, true, true);
    ++}
    ++
    ++DEF_TEST(Codec_bmp, r) {
    ++    check(r, "randPixels.bmp", SkISize::Make(8, 8), true, false, true);
    ++    check(r, "rle.bmp", SkISize::Make(320, 240), true, false, true);
    ++}
    ++
    ++DEF_TEST(Codec_ico, r) {
    ++    // FIXME: We are not ready to test incomplete ICOs
    ++    // These two tests examine interestingly different behavior:
    ++    // Decodes an embedded BMP image
    ++    check(r, "color_wheel.ico", SkISize::Make(128, 128), true, false, false);
    ++    // Decodes an embedded PNG image
    ++    check(r, "google_chrome.ico", SkISize::Make(256, 256), false, false, false, true);
    ++}
    ++
    ++DEF_TEST(Codec_gif, r) {
    ++    check(r, "box.gif", SkISize::Make(200, 55), false, false, true, true);
    ++    check(r, "color_wheel.gif", SkISize::Make(128, 128), false, false, true, true);
    ++    // randPixels.gif is too small to test incomplete
    ++    check(r, "randPixels.gif", SkISize::Make(8, 8), false, false, false, true);
    ++}
    ++
    ++DEF_TEST(Codec_jpg, r) {
    ++    check(r, "CMYK.jpg", SkISize::Make(642, 516), true, false, true);
    ++    check(r, "color_wheel.jpg", SkISize::Make(128, 128), true, false, true);
    ++    // grayscale.jpg is too small to test incomplete
    ++    check(r, "grayscale.jpg", SkISize::Make(128, 128), true, false, false);
    ++    check(r, "mandrill_512_q075.jpg", SkISize::Make(512, 512), true, false, true);
    ++    // randPixels.jpg is too small to test incomplete
    ++    check(r, "randPixels.jpg", SkISize::Make(8, 8), true, false, false);
    ++}
    ++
    ++DEF_TEST(Codec_png, r) {
    ++    check(r, "arrow.png", SkISize::Make(187, 312), false, false, true, true);
    ++    check(r, "baby_tux.png", SkISize::Make(240, 246), false, false, true, true);
    ++    check(r, "color_wheel.png", SkISize::Make(128, 128), false, false, true, true);
    ++    // half-transparent-white-pixel.png is too small to test incomplete
    ++    check(r, "half-transparent-white-pixel.png", SkISize::Make(1, 1), false, false, false, true);
    ++    check(r, "mandrill_128.png", SkISize::Make(128, 128), false, false, true, true);
    ++    check(r, "mandrill_16.png", SkISize::Make(16, 16), false, false, true, true);
    ++    check(r, "mandrill_256.png", SkISize::Make(256, 256), false, false, true, true);
    ++    check(r, "mandrill_32.png", SkISize::Make(32, 32), false, false, true, true);
    ++    check(r, "mandrill_512.png", SkISize::Make(512, 512), false, false, true, true);
    ++    check(r, "mandrill_64.png", SkISize::Make(64, 64), false, false, true, true);
    ++    check(r, "plane.png", SkISize::Make(250, 126), false, false, true, true);
    ++    check(r, "plane_interlaced.png", SkISize::Make(250, 126), false, false, true, true);
    ++    check(r, "randPixels.png", SkISize::Make(8, 8), false, false, true, true);
    ++    check(r, "yellow_rose.png", SkISize::Make(400, 301), false, false, true, true);
    ++}
    ++
    ++// Disable RAW tests for Win32.
    ++#if defined(SK_CODEC_DECODES_RAW) && (!defined(_WIN32))
    ++DEF_TEST(Codec_raw, r) {
    ++    check(r, "sample_1mp.dng", SkISize::Make(600, 338), false, false, false);
    ++    check(r, "sample_1mp_rotated.dng", SkISize::Make(600, 338), false, false, false);
    ++    check(r, "dng_with_preview.dng", SkISize::Make(600, 338), true, false, false);
    ++}
    ++#endif
    ++
    ++static void test_invalid_stream(skiatest::Reporter* r, const void* stream, size_t len) {
    ++    // Neither of these calls should return a codec. Bots should catch us if we leaked anything.
    ++    SkCodec* codec = SkCodec::NewFromStream(new SkMemoryStream(stream, len, false));
    ++    REPORTER_ASSERT(r, !codec);
    ++
    ++    SkAndroidCodec* androidCodec =
    ++            SkAndroidCodec::NewFromStream(new SkMemoryStream(stream, len, false));
    ++    REPORTER_ASSERT(r, !androidCodec);
    ++}
    ++
    ++// Ensure that SkCodec::NewFromStream handles freeing the passed in SkStream,
    ++// even on failure. Test some bad streams.
    ++DEF_TEST(Codec_leaks, r) {
    ++    // No codec should claim this as their format, so this tests SkCodec::NewFromStream.
    ++    const char nonSupportedStream[] = "hello world";
    ++    // The other strings should look like the beginning of a file type, so we'll call some
    ++    // internal version of NewFromStream, which must also delete the stream on failure.
    ++    const unsigned char emptyPng[] = { 0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a };
    ++    const unsigned char emptyJpeg[] = { 0xFF, 0xD8, 0xFF };
    ++    const char emptyWebp[] = "RIFF1234WEBPVP";
    ++    const char emptyBmp[] = { 'B', 'M' };
    ++    const char emptyIco[] = { '\x00', '\x00', '\x01', '\x00' };
    ++    const char emptyGif[] = "GIFVER";
    ++
    ++    test_invalid_stream(r, nonSupportedStream, sizeof(nonSupportedStream));
    ++    test_invalid_stream(r, emptyPng, sizeof(emptyPng));
    ++    test_invalid_stream(r, emptyJpeg, sizeof(emptyJpeg));
    ++    test_invalid_stream(r, emptyWebp, sizeof(emptyWebp));
    ++    test_invalid_stream(r, emptyBmp, sizeof(emptyBmp));
    ++    test_invalid_stream(r, emptyIco, sizeof(emptyIco));
    ++    test_invalid_stream(r, emptyGif, sizeof(emptyGif));
    ++}
    ++
    ++DEF_TEST(Codec_null, r) {
    ++    // Attempting to create an SkCodec or an SkAndroidCodec with null should not
    ++    // crash.
    ++    SkCodec* codec = SkCodec::NewFromStream(nullptr);
    ++    REPORTER_ASSERT(r, !codec);
    ++
    ++    SkAndroidCodec* androidCodec = SkAndroidCodec::NewFromStream(nullptr);
    ++    REPORTER_ASSERT(r, !androidCodec);
    ++}
    ++
    ++static void test_dimensions(skiatest::Reporter* r, const char path[]) {
    ++    // Create the codec from the resource file
    ++    std::unique_ptr<SkStream> stream(GetResourceAsStream(path));
    ++    if (!stream) {
    ++        return;
    ++    }
    ++    std::unique_ptr<SkAndroidCodec> codec(SkAndroidCodec::NewFromStream(stream.release()));
    ++    if (!codec) {
    ++        ERRORF(r, "Unable to create codec '%s'", path);
    ++        return;
    ++    }
    ++
    ++    // Check that the decode is successful for a variety of scales
    ++    for (int sampleSize = 1; sampleSize < 32; sampleSize++) {
    ++        // Scale the output dimensions
    ++        SkISize scaledDims = codec->getSampledDimensions(sampleSize);
    ++        SkImageInfo scaledInfo = codec->getInfo()
    ++                .makeWH(scaledDims.width(), scaledDims.height())
    ++                .makeColorType(kN32_SkColorType);
    ++
    ++        // Set up for the decode
    ++        size_t rowBytes = scaledDims.width() * sizeof(SkPMColor);
    ++        size_t totalBytes = scaledInfo.getSafeSize(rowBytes);
    ++        SkAutoTMalloc<SkPMColor> pixels(totalBytes);
    ++
    ++        SkAndroidCodec::AndroidOptions options;
    ++        options.fSampleSize = sampleSize;
    ++        SkCodec::Result result =
    ++                codec->getAndroidPixels(scaledInfo, pixels.get(), rowBytes, &options);
    ++        REPORTER_ASSERT(r, SkCodec::kSuccess == result);
    ++    }
    ++}
    ++
    ++// Ensure that onGetScaledDimensions returns valid image dimensions to use for decodes
    ++DEF_TEST(Codec_Dimensions, r) {
    ++    // JPG
    ++    test_dimensions(r, "CMYK.jpg");
    ++    test_dimensions(r, "color_wheel.jpg");
    ++    test_dimensions(r, "grayscale.jpg");
    ++    test_dimensions(r, "mandrill_512_q075.jpg");
    ++    test_dimensions(r, "randPixels.jpg");
    ++
    ++    // Decoding small images with very large scaling factors is a potential
    ++    // source of bugs and crashes.  We disable these tests in Gold because
    ++    // tiny images are not very useful to look at.
    ++    // Here we make sure that we do not crash or access illegal memory when
    ++    // performing scaled decodes on small images.
    ++    test_dimensions(r, "1x1.png");
    ++    test_dimensions(r, "2x2.png");
    ++    test_dimensions(r, "3x3.png");
    ++    test_dimensions(r, "3x1.png");
    ++    test_dimensions(r, "1x1.png");
    ++    test_dimensions(r, "16x1.png");
    ++    test_dimensions(r, "1x16.png");
    ++    test_dimensions(r, "mandrill_16.png");
    ++
    ++    // RAW
    ++// Disable RAW tests for Win32.
    ++#if defined(SK_CODEC_DECODES_RAW) && (!defined(_WIN32))
    ++    test_dimensions(r, "sample_1mp.dng");
    ++    test_dimensions(r, "sample_1mp_rotated.dng");
    ++    test_dimensions(r, "dng_with_preview.dng");
    ++#endif
    ++}
    ++
    ++static void test_invalid(skiatest::Reporter* r, const char path[]) {
    ++    std::unique_ptr<SkStream> stream(GetResourceAsStream(path));
    ++    if (!stream) {
    ++        return;
    ++    }
    ++    std::unique_ptr<SkCodec> codec(SkCodec::NewFromStream(stream.release()));
    ++    REPORTER_ASSERT(r, nullptr == codec);
    ++}
    ++
    ++DEF_TEST(Codec_Empty, r) {
    ++    // Test images that should not be able to create a codec
    ++    test_invalid(r, "empty_images/zero-dims.gif");
    ++    test_invalid(r, "empty_images/zero-embedded.ico");
    ++    test_invalid(r, "empty_images/zero-width.bmp");
    ++    test_invalid(r, "empty_images/zero-height.bmp");
    ++    test_invalid(r, "empty_images/zero-width.jpg");
    ++    test_invalid(r, "empty_images/zero-height.jpg");
    ++    test_invalid(r, "empty_images/zero-width.png");
    ++    test_invalid(r, "empty_images/zero-height.png");
    ++    test_invalid(r, "empty_images/zero-width.wbmp");
    ++    test_invalid(r, "empty_images/zero-height.wbmp");
    ++    // This image is an ico with an embedded mask-bmp.  This is illegal.
    ++    test_invalid(r, "invalid_images/mask-bmp-ico.ico");
    ++    // It is illegal for a webp frame to not be fully contained by the canvas.
    ++    test_invalid(r, "invalid_images/invalid-offset.webp");
    ++#if defined(SK_CODEC_DECODES_RAW) && (!defined(_WIN32))
    ++    test_invalid(r, "empty_images/zero_height.tiff");
    ++#endif
    ++}
    ++
    ++static void test_invalid_parameters(skiatest::Reporter* r, const char path[]) {
    ++    std::unique_ptr<SkStream> stream(GetResourceAsStream(path));
    ++    if (!stream) {
    ++        return;
    ++    }
    ++    std::unique_ptr<SkCodec> decoder(SkCodec::NewFromStream(stream.release()));
    ++    if (!decoder) {
    ++        SkDebugf("Missing codec for %s\n", path);
    ++        return;
    ++    }
    ++
    ++    const SkImageInfo info = decoder->getInfo().makeColorType(kIndex_8_SkColorType);
    ++
    ++    // This should return kSuccess because kIndex8 is supported.
    ++    SkPMColor colorStorage[256];
    ++    int colorCount;
    ++    SkCodec::Result result = decoder->startScanlineDecode(info, nullptr, colorStorage,
    ++                                                          &colorCount);
    ++    if (SkCodec::kSuccess == result) {
    ++        // This should return kInvalidParameters because, in kIndex_8 mode, we must pass in a valid
    ++        // colorPtr and a valid colorCountPtr.
    ++        result = decoder->startScanlineDecode(info, nullptr, nullptr, nullptr);
    ++        REPORTER_ASSERT(r, SkCodec::kInvalidParameters == result);
    ++        result = decoder->startScanlineDecode(info);
    ++        REPORTER_ASSERT(r, SkCodec::kInvalidParameters == result);
    ++    } else if (SkCodec::kUnimplemented == result) {
    ++        // New method should be supported:
    ++        SkBitmap bm;
    ++        sk_sp<SkColorTable> colorTable(new SkColorTable(colorStorage, 256));
    ++        bm.allocPixels(info, nullptr, colorTable.get());
    ++        result = decoder->startIncrementalDecode(info, bm.getPixels(), bm.rowBytes(), nullptr,
    ++                                                 colorStorage, &colorCount);
    ++        REPORTER_ASSERT(r, SkCodec::kSuccess == result);
    ++        result = decoder->startIncrementalDecode(info, bm.getPixels(), bm.rowBytes());
    ++        REPORTER_ASSERT(r, SkCodec::kInvalidParameters == result);
    ++    } else {
    ++        // The test is uninteresting if kIndex8 is not supported
    ++        ERRORF(r, "Should not call test_invalid_parameters for non-Index8 file: %s\n", path);
    ++        return;
    ++    }
    ++
    ++}
    ++
    ++DEF_TEST(Codec_Params, r) {
    ++    test_invalid_parameters(r, "index8.png");
    ++    test_invalid_parameters(r, "mandrill.wbmp");
    ++}
    ++
    ++#ifdef PNG_READ_UNKNOWN_CHUNKS_SUPPORTED
    ++
    ++#ifndef SK_PNG_DISABLE_TESTS   // reading chunks does not work properly with older versions.
    ++                               // It does not appear that anyone in Google3 is reading chunks.
    ++
    ++static void codex_test_write_fn(png_structp png_ptr, png_bytep data, png_size_t len) {
    ++    SkWStream* sk_stream = (SkWStream*)png_get_io_ptr(png_ptr);
    ++    if (!sk_stream->write(data, len)) {
    ++        png_error(png_ptr, "sk_write_fn Error!");
    ++    }
    ++}
    ++
    ++DEF_TEST(Codec_pngChunkReader, r) {
    ++    // Create a dummy bitmap. Use unpremul RGBA for libpng.
    ++    SkBitmap bm;
    ++    const int w = 1;
    ++    const int h = 1;
    ++    const SkImageInfo bmInfo = SkImageInfo::Make(w, h, kRGBA_8888_SkColorType,
    ++                                                 kUnpremul_SkAlphaType);
    ++    bm.setInfo(bmInfo);
    ++    bm.allocPixels();
    ++    bm.eraseColor(SK_ColorBLUE);
    ++    SkMD5::Digest goodDigest;
    ++    md5(bm, &goodDigest);
    ++
    ++    // Write to a png file.
    ++    png_structp png = png_create_write_struct(PNG_LIBPNG_VER_STRING, nullptr, nullptr, nullptr);
    ++    REPORTER_ASSERT(r, png);
    ++    if (!png) {
    ++        return;
    ++    }
    ++
    ++    png_infop info = png_create_info_struct(png);
    ++    REPORTER_ASSERT(r, info);
    ++    if (!info) {
    ++        png_destroy_write_struct(&png, nullptr);
    ++        return;
    ++    }
    ++
    ++    if (setjmp(png_jmpbuf(png))) {
    ++        ERRORF(r, "failed writing png");
    ++        png_destroy_write_struct(&png, &info);
    ++        return;
    ++    }
    ++
    ++    SkDynamicMemoryWStream wStream;
    ++    png_set_write_fn(png, (void*) (&wStream), codex_test_write_fn, nullptr);
    ++
    ++    png_set_IHDR(png, info, (png_uint_32)w, (png_uint_32)h, 8,
    ++                 PNG_COLOR_TYPE_RGB_ALPHA, PNG_INTERLACE_NONE,
    ++                 PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT);
    ++
    ++    // Create some chunks that match the Android framework's use.
    ++    static png_unknown_chunk gUnknowns[] = {
    ++        { "npOl", (png_byte*)"outline", sizeof("outline"), PNG_HAVE_IHDR },
    ++        { "npLb", (png_byte*)"layoutBounds", sizeof("layoutBounds"), PNG_HAVE_IHDR },
    ++        { "npTc", (png_byte*)"ninePatchData", sizeof("ninePatchData"), PNG_HAVE_IHDR },
    ++    };
    ++
    ++    png_set_keep_unknown_chunks(png, PNG_HANDLE_CHUNK_ALWAYS, (png_byte*)"npOl\0npLb\0npTc\0", 3);
    ++    png_set_unknown_chunks(png, info, gUnknowns, SK_ARRAY_COUNT(gUnknowns));
    ++#if PNG_LIBPNG_VER < 10600
    ++    /* Deal with unknown chunk location bug in 1.5.x and earlier */
    ++    png_set_unknown_chunk_location(png, info, 0, PNG_HAVE_IHDR);
    ++    png_set_unknown_chunk_location(png, info, 1, PNG_HAVE_IHDR);
    ++#endif
    ++
    ++    png_write_info(png, info);
    ++
    ++    for (int j = 0; j < h; j++) {
    ++        png_bytep row = (png_bytep)(bm.getAddr(0, j));
    ++        png_write_rows(png, &row, 1);
    ++    }
    ++    png_write_end(png, info);
    ++    png_destroy_write_struct(&png, &info);
    ++
    ++    class ChunkReader : public SkPngChunkReader {
    ++    public:
    ++        ChunkReader(skiatest::Reporter* r)
    ++            : fReporter(r)
    ++        {
    ++            this->reset();
    ++        }
    ++
    ++        bool readChunk(const char tag[], const void* data, size_t length) override {
    ++            for (size_t i = 0; i < SK_ARRAY_COUNT(gUnknowns); ++i) {
    ++                if (!strcmp(tag, (const char*) gUnknowns[i].name)) {
    ++                    // Tag matches. This should have been the first time we see it.
    ++                    REPORTER_ASSERT(fReporter, !fSeen[i]);
    ++                    fSeen[i] = true;
    ++
    ++                    // Data and length should match
    ++                    REPORTER_ASSERT(fReporter, length == gUnknowns[i].size);
    ++                    REPORTER_ASSERT(fReporter, !strcmp((const char*) data,
    ++                                                       (const char*) gUnknowns[i].data));
    ++                    return true;
    ++                }
    ++            }
    ++            ERRORF(fReporter, "Saw an unexpected unknown chunk.");
    ++            return true;
    ++        }
    ++
    ++        bool allHaveBeenSeen() {
    ++            bool ret = true;
    ++            for (auto seen : fSeen) {
    ++                ret &= seen;
    ++            }
    ++            return ret;
    ++        }
    ++
    ++        void reset() {
    ++            sk_bzero(fSeen, sizeof(fSeen));
    ++        }
    ++
    ++    private:
    ++        skiatest::Reporter* fReporter;  // Unowned
    ++        bool fSeen[3];
    ++    };
    ++
    ++    ChunkReader chunkReader(r);
    ++
    ++    // Now read the file with SkCodec.
    ++    std::unique_ptr<SkCodec> codec(SkCodec::NewFromData(wStream.detachAsData(), &chunkReader));
    ++    REPORTER_ASSERT(r, codec);
    ++    if (!codec) {
    ++        return;
    ++    }
    ++
    ++    // Now compare to the original.
    ++    SkBitmap decodedBm;
    ++    decodedBm.setInfo(codec->getInfo());
    ++    decodedBm.allocPixels();
    ++    SkCodec::Result result = codec->getPixels(codec->getInfo(), decodedBm.getPixels(),
    ++                                              decodedBm.rowBytes());
    ++    REPORTER_ASSERT(r, SkCodec::kSuccess == result);
    ++
    ++    if (decodedBm.colorType() != bm.colorType()) {
    ++        SkBitmap tmp;
    ++        bool success = decodedBm.copyTo(&tmp, bm.colorType());
    ++        REPORTER_ASSERT(r, success);
    ++        if (!success) {
    ++            return;
    ++        }
    ++
    ++        tmp.swap(decodedBm);
    ++    }
    ++
    ++    compare_to_good_digest(r, goodDigest, decodedBm);
    ++    REPORTER_ASSERT(r, chunkReader.allHaveBeenSeen());
    ++
    ++    // Decoding again will read the chunks again.
    ++    chunkReader.reset();
    ++    REPORTER_ASSERT(r, !chunkReader.allHaveBeenSeen());
    ++    result = codec->getPixels(codec->getInfo(), decodedBm.getPixels(), decodedBm.rowBytes());
    ++    REPORTER_ASSERT(r, SkCodec::kSuccess == result);
    ++    REPORTER_ASSERT(r, chunkReader.allHaveBeenSeen());
    ++}
    ++#endif // SK_PNG_DISABLE_TESTS
    ++#endif // PNG_READ_UNKNOWN_CHUNKS_SUPPORTED
    ++
    ++// Stream that can only peek up to a limit
    ++class LimitedPeekingMemStream : public SkStream {
    ++public:
    ++    LimitedPeekingMemStream(sk_sp<SkData> data, size_t limit)
    ++        : fStream(std::move(data))
    ++        , fLimit(limit) {}
    ++
    ++    size_t peek(void* buf, size_t bytes) const override {
    ++        return fStream.peek(buf, SkTMin(bytes, fLimit));
    ++    }
    ++    size_t read(void* buf, size_t bytes) override {
    ++        return fStream.read(buf, bytes);
    ++    }
    ++    bool rewind() override {
    ++        return fStream.rewind();
    ++    }
    ++    bool isAtEnd() const override {
    ++        return fStream.isAtEnd();
    ++    }
    ++private:
    ++    SkMemoryStream fStream;
    ++    const size_t   fLimit;
    ++};
    ++
    ++// Disable RAW tests for Win32.
    ++#if defined(SK_CODEC_DECODES_RAW) && (!defined(_WIN32))
    ++// Test that the RawCodec works also for not asset stream. This will test the code path using
    ++// SkRawBufferedStream instead of SkRawAssetStream.
    ++DEF_TEST(Codec_raw_notseekable, r) {
    ++    const char* path = "dng_with_preview.dng";
    ++    SkString fullPath(GetResourcePath(path));
    ++    sk_sp<SkData> data(SkData::MakeFromFileName(fullPath.c_str()));
    ++    if (!data) {
    ++        SkDebugf("Missing resource '%s'\n", path);
    ++        return;
    ++    }
    ++
    ++    std::unique_ptr<SkCodec> codec(SkCodec::NewFromStream(new NotAssetMemStream(std::move(data))));
    ++    REPORTER_ASSERT(r, codec);
    ++
    ++    test_info(r, codec.get(), codec->getInfo(), SkCodec::kSuccess, nullptr);
    ++}
    ++#endif
    ++
    ++// Test that even if webp_parse_header fails to peek enough, it will fall back to read()
    ++// + rewind() and succeed.
    ++DEF_TEST(Codec_webp_peek, r) {
    ++    const char* path = "baby_tux.webp";
    ++    SkString fullPath(GetResourcePath(path));
    ++    auto data = SkData::MakeFromFileName(fullPath.c_str());
    ++    if (!data) {
    ++        SkDebugf("Missing resource '%s'\n", path);
    ++        return;
    ++    }
    ++
    ++    // The limit is less than webp needs to peek or read.
    ++    std::unique_ptr<SkCodec> codec(SkCodec::NewFromStream(
    ++                                 new LimitedPeekingMemStream(data, 25)));
    ++    REPORTER_ASSERT(r, codec);
    ++
    ++    test_info(r, codec.get(), codec->getInfo(), SkCodec::kSuccess, nullptr);
    ++
    ++    // Similarly, a stream which does not peek should still succeed.
    ++    codec.reset(SkCodec::NewFromStream(new LimitedPeekingMemStream(data, 0)));
    ++    REPORTER_ASSERT(r, codec);
    ++
    ++    test_info(r, codec.get(), codec->getInfo(), SkCodec::kSuccess, nullptr);
    ++}
    ++
    ++// SkCodec's wbmp decoder was initially unnecessarily restrictive.
    ++// It required the second byte to be zero. The wbmp specification allows
    ++// a couple of bits to be 1 (so long as they do not overlap with 0x9F).
    ++// Test that SkCodec now supports an image with these bits set.
    ++DEF_TEST(Codec_wbmp_restrictive, r) {
    ++    const char* path = "mandrill.wbmp";
    ++    std::unique_ptr<SkStream> stream(GetResourceAsStream(path));
    ++    if (!stream) {
    ++        return;
    ++    }
    ++
    ++    // Modify the stream to contain a second byte with some bits set.
    ++    auto data = SkCopyStreamToData(stream.get());
    ++    uint8_t* writeableData = static_cast<uint8_t*>(data->writable_data());
    ++    writeableData[1] = static_cast<uint8_t>(~0x9F);
    ++
    ++    // SkCodec should support this.
    ++    std::unique_ptr<SkCodec> codec(SkCodec::NewFromData(data));
    ++    REPORTER_ASSERT(r, codec);
    ++    if (!codec) {
    ++        return;
    ++    }
    ++    test_info(r, codec.get(), codec->getInfo(), SkCodec::kSuccess, nullptr);
    ++}
    ++
    ++// wbmp images have a header that can be arbitrarily large, depending on the
    ++// size of the image. We cap the size at 65535, meaning we only need to look at
    ++// 8 bytes to determine whether we can read the image. This is important
    ++// because SkCodec only passes 14 bytes to SkWbmpCodec to determine whether the
    ++// image is a wbmp.
    ++DEF_TEST(Codec_wbmp_max_size, r) {
    ++    const unsigned char maxSizeWbmp[] = { 0x00, 0x00,           // Header
    ++                                          0x83, 0xFF, 0x7F,     // W: 65535
    ++                                          0x83, 0xFF, 0x7F };   // H: 65535
    ++    std::unique_ptr<SkStream> stream(new SkMemoryStream(maxSizeWbmp, sizeof(maxSizeWbmp), false));
    ++    std::unique_ptr<SkCodec> codec(SkCodec::NewFromStream(stream.release()));
    ++
    ++    REPORTER_ASSERT(r, codec);
    ++    if (!codec) return;
    ++
    ++    REPORTER_ASSERT(r, codec->getInfo().width() == 65535);
    ++    REPORTER_ASSERT(r, codec->getInfo().height() == 65535);
    ++
    ++    // Now test an image which is too big. Any image with a larger header (i.e.
    ++    // has bigger width/height) is also too big.
    ++    const unsigned char tooBigWbmp[] = { 0x00, 0x00,           // Header
    ++                                         0x84, 0x80, 0x00,     // W: 65536
    ++                                         0x84, 0x80, 0x00 };   // H: 65536
    ++    stream.reset(new SkMemoryStream(tooBigWbmp, sizeof(tooBigWbmp), false));
    ++    codec.reset(SkCodec::NewFromStream(stream.release()));
    ++
    ++    REPORTER_ASSERT(r, !codec);
    ++}
    ++
    ++DEF_TEST(Codec_jpeg_rewind, r) {
    ++    const char* path = "mandrill_512_q075.jpg";
    ++    sk_sp<SkData> data(GetResourceAsData(path));
    ++    if (!data) {
    ++        return;
    ++    }
    ++
    ++    data = SkData::MakeSubset(data.get(), 0, data->size() / 2);
    ++    std::unique_ptr<SkAndroidCodec> codec(SkAndroidCodec::NewFromData(data));
    ++    if (!codec) {
    ++        ERRORF(r, "Unable to create codec '%s'.", path);
    ++        return;
    ++    }
    ++
    ++    const int width = codec->getInfo().width();
    ++    const int height = codec->getInfo().height();
    ++    size_t rowBytes = sizeof(SkPMColor) * width;
    ++    SkAutoMalloc pixelStorage(height * rowBytes);
    ++
    ++    // Perform a sampled decode.
    ++    SkAndroidCodec::AndroidOptions opts;
    ++    opts.fSampleSize = 12;
    ++    auto sampledInfo = codec->getInfo().makeWH(width / 12, height / 12);
    ++    auto result = codec->getAndroidPixels(sampledInfo, pixelStorage.get(), rowBytes, &opts);
    ++    REPORTER_ASSERT(r, SkCodec::kIncompleteInput == result);
    ++
    ++    // Rewind the codec and perform a full image decode.
    ++    result = codec->getPixels(codec->getInfo(), pixelStorage.get(), rowBytes);
    ++    REPORTER_ASSERT(r, SkCodec::kIncompleteInput == result);
    ++
    ++    // Now perform a subset decode.
    ++    {
    ++        opts.fSampleSize = 1;
    ++        SkIRect subset = SkIRect::MakeWH(100, 100);
    ++        opts.fSubset = &subset;
    ++        result = codec->getAndroidPixels(codec->getInfo().makeWH(100, 100), pixelStorage.get(),
    ++                                         rowBytes, &opts);
    ++        // Though we only have half the data, it is enough to decode this subset.
    ++        REPORTER_ASSERT(r, SkCodec::kSuccess == result);
    ++    }
    ++
    ++    // Perform another full image decode.  ASAN will detect if we look at the subset when it is
    ++    // out of scope.  This would happen if we depend on the old state in the codec.
    ++    // This tests two layers of bugs: both SkJpegCodec::readRows and SkCodec::fillIncompleteImage
    ++    // used to look at the old subset.
    ++    opts.fSubset = nullptr;
    ++    result = codec->getAndroidPixels(codec->getInfo(), pixelStorage.get(), rowBytes, &opts);
    ++    REPORTER_ASSERT(r, SkCodec::kIncompleteInput == result);
    ++}
    ++
    ++static void check_color_xform(skiatest::Reporter* r, const char* path) {
    ++    std::unique_ptr<SkAndroidCodec> codec(SkAndroidCodec::NewFromStream(GetResourceAsStream(path)));
    ++
    ++    SkAndroidCodec::AndroidOptions opts;
    ++    opts.fSampleSize = 3;
    ++    const int subsetWidth = codec->getInfo().width() / 2;
    ++    const int subsetHeight = codec->getInfo().height() / 2;
    ++    SkIRect subset = SkIRect::MakeWH(subsetWidth, subsetHeight);
    ++    opts.fSubset = &subset;
    ++
    ++    const int dstWidth = subsetWidth / opts.fSampleSize;
    ++    const int dstHeight = subsetHeight / opts.fSampleSize;
    ++    sk_sp<SkData> data = SkData::MakeFromFileName(
    ++            GetResourcePath("icc_profiles/HP_ZR30w.icc").c_str());
    ++    sk_sp<SkColorSpace> colorSpace = SkColorSpace::MakeICC(data->data(), data->size());
    ++    SkImageInfo dstInfo = codec->getInfo().makeWH(dstWidth, dstHeight)
    ++                                          .makeColorType(kN32_SkColorType)
    ++                                          .makeColorSpace(colorSpace);
    ++
    ++    size_t rowBytes = dstInfo.minRowBytes();
    ++    SkAutoMalloc pixelStorage(dstInfo.getSafeSize(rowBytes));
    ++    SkCodec::Result result = codec->getAndroidPixels(dstInfo, pixelStorage.get(), rowBytes, &opts);
    ++    REPORTER_ASSERT(r, SkCodec::kSuccess == result);
    ++}
    ++
    ++DEF_TEST(Codec_ColorXform, r) {
    ++    check_color_xform(r, "mandrill_512_q075.jpg");
    ++    check_color_xform(r, "mandrill_512.png");
    ++}
    ++
    ++static bool color_type_match(SkColorType origColorType, SkColorType codecColorType) {
    ++    switch (origColorType) {
    ++        case kRGBA_8888_SkColorType:
    ++        case kBGRA_8888_SkColorType:
    ++            return kRGBA_8888_SkColorType == codecColorType ||
    ++                   kBGRA_8888_SkColorType == codecColorType;
    ++        default:
    ++            return origColorType == codecColorType;
    ++    }
    ++}
    ++
    ++static bool alpha_type_match(SkAlphaType origAlphaType, SkAlphaType codecAlphaType) {
    ++    switch (origAlphaType) {
    ++        case kUnpremul_SkAlphaType:
    ++        case kPremul_SkAlphaType:
    ++            return kUnpremul_SkAlphaType == codecAlphaType ||
    ++                    kPremul_SkAlphaType == codecAlphaType;
    ++        default:
    ++            return origAlphaType == codecAlphaType;
    ++    }
    ++}
    ++
    ++static void check_round_trip(skiatest::Reporter* r, SkCodec* origCodec, const SkImageInfo& info) {
    ++    SkBitmap bm1;
    ++    SkPMColor colors[256];
    ++    sk_sp<SkColorTable> colorTable1(new SkColorTable(colors, 256));
    ++    bm1.allocPixels(info, nullptr, colorTable1.get());
    ++    int numColors;
    ++    SkCodec::Result result = origCodec->getPixels(info, bm1.getPixels(), bm1.rowBytes(), nullptr,
    ++                                                  const_cast<SkPMColor*>(colorTable1->readColors()),
    ++                                                  &numColors);
    ++    // This will fail to update colorTable1->count() but is fine for the purpose of this test.
    ++    REPORTER_ASSERT(r, SkCodec::kSuccess == result);
    ++
    ++    // Encode the image to png.
    ++    sk_sp<SkData> data =
    ++            sk_sp<SkData>(sk_tool_utils::EncodeImageToData(bm1, SkEncodedImageFormat::kPNG, 100));
    ++
    ++    std::unique_ptr<SkCodec> codec(SkCodec::NewFromData(data));
    ++    REPORTER_ASSERT(r, color_type_match(info.colorType(), codec->getInfo().colorType()));
    ++    REPORTER_ASSERT(r, alpha_type_match(info.alphaType(), codec->getInfo().alphaType()));
    ++
    ++    SkBitmap bm2;
    ++    sk_sp<SkColorTable> colorTable2(new SkColorTable(colors, 256));
    ++    bm2.allocPixels(info, nullptr, colorTable2.get());
    ++    result = codec->getPixels(info, bm2.getPixels(), bm2.rowBytes(), nullptr,
    ++                              const_cast<SkPMColor*>(colorTable2->readColors()), &numColors);
    ++    REPORTER_ASSERT(r, SkCodec::kSuccess == result);
    ++
    ++    SkMD5::Digest d1, d2;
    ++    md5(bm1, &d1);
    ++    md5(bm2, &d2);
    ++    REPORTER_ASSERT(r, d1 == d2);
    ++}
    ++
    ++DEF_TEST(Codec_PngRoundTrip, r) {
    ++    const char* path = "mandrill_512_q075.jpg";
    ++    std::unique_ptr<SkStream> stream(GetResourceAsStream(path));
    ++    std::unique_ptr<SkCodec> codec(SkCodec::NewFromStream(stream.release()));
    ++
    ++    SkColorType colorTypesOpaque[] = {
    ++            kRGB_565_SkColorType, kRGBA_8888_SkColorType, kBGRA_8888_SkColorType
    ++    };
    ++    for (SkColorType colorType : colorTypesOpaque) {
    ++        SkImageInfo newInfo = codec->getInfo().makeColorType(colorType);
    ++        check_round_trip(r, codec.get(), newInfo);
    ++    }
    ++
    ++    path = "grayscale.jpg";
    ++    stream.reset(GetResourceAsStream(path));
    ++    codec.reset(SkCodec::NewFromStream(stream.release()));
    ++    check_round_trip(r, codec.get(), codec->getInfo());
    ++
    ++    path = "yellow_rose.png";
    ++    stream.reset(GetResourceAsStream(path));
    ++    codec.reset(SkCodec::NewFromStream(stream.release()));
    ++
    ++    SkColorType colorTypesWithAlpha[] = {
    ++            kRGBA_8888_SkColorType, kBGRA_8888_SkColorType
    ++    };
    ++    SkAlphaType alphaTypes[] = {
    ++            kUnpremul_SkAlphaType, kPremul_SkAlphaType
    ++    };
    ++    for (SkColorType colorType : colorTypesWithAlpha) {
    ++        for (SkAlphaType alphaType : alphaTypes) {
    ++            // Set color space to nullptr because color correct premultiplies do not round trip.
    ++            SkImageInfo newInfo = codec->getInfo().makeColorType(colorType)
    ++                                                  .makeAlphaType(alphaType)
    ++                                                  .makeColorSpace(nullptr);
    ++            check_round_trip(r, codec.get(), newInfo);
    ++        }
    ++    }
    ++
    ++    path = "index8.png";
    ++    stream.reset(GetResourceAsStream(path));
    ++    codec.reset(SkCodec::NewFromStream(stream.release()));
    ++
    ++    for (SkAlphaType alphaType : alphaTypes) {
    ++        SkImageInfo newInfo = codec->getInfo().makeAlphaType(alphaType)
    ++                                              .makeColorSpace(nullptr);
    ++        check_round_trip(r, codec.get(), newInfo);
    ++    }
    ++}
    ++
    ++static void test_conversion_possible(skiatest::Reporter* r, const char* path,
    ++                                     bool supportsScanlineDecoder,
    ++                                     bool supportsIncrementalDecoder) {
    ++    std::unique_ptr<SkStream> stream(GetResourceAsStream(path));
    ++    if (!stream) {
    ++        return;
    ++    }
    ++
    ++    std::unique_ptr<SkCodec> codec(SkCodec::NewFromStream(stream.release()));
    ++    if (!codec) {
    ++        ERRORF(r, "failed to create a codec for %s", path);
    ++        return;
    ++    }
    ++
    ++    SkImageInfo infoF16 = codec->getInfo().makeColorType(kRGBA_F16_SkColorType);
    ++
    ++    SkBitmap bm;
    ++    bm.allocPixels(infoF16);
    ++    SkCodec::Result result = codec->getPixels(infoF16, bm.getPixels(), bm.rowBytes());
    ++    REPORTER_ASSERT(r, SkCodec::kInvalidConversion == result);
    ++
    ++    result = codec->startScanlineDecode(infoF16);
    ++    if (supportsScanlineDecoder) {
    ++        REPORTER_ASSERT(r, SkCodec::kInvalidConversion == result);
    ++    } else {
    ++        REPORTER_ASSERT(r, SkCodec::kUnimplemented == result);
    ++    }
    ++
    ++    result = codec->startIncrementalDecode(infoF16, bm.getPixels(), bm.rowBytes());
    ++    if (supportsIncrementalDecoder) {
    ++        REPORTER_ASSERT(r, SkCodec::kInvalidConversion == result);
    ++    } else {
    ++        REPORTER_ASSERT(r, SkCodec::kUnimplemented == result);
    ++    }
    ++
    ++    SkASSERT(SkColorSpace_Base::Type::kXYZ == as_CSB(infoF16.colorSpace())->type());
    ++    SkColorSpace_XYZ* csXYZ = static_cast<SkColorSpace_XYZ*>(infoF16.colorSpace());
    ++    infoF16 = infoF16.makeColorSpace(csXYZ->makeLinearGamma());
    ++    result = codec->getPixels(infoF16, bm.getPixels(), bm.rowBytes());
    ++    REPORTER_ASSERT(r, SkCodec::kSuccess == result);
    ++    result = codec->startScanlineDecode(infoF16);
    ++    if (supportsScanlineDecoder) {
    ++        REPORTER_ASSERT(r, SkCodec::kSuccess == result);
    ++    } else {
    ++        REPORTER_ASSERT(r, SkCodec::kUnimplemented == result);
    ++    }
    ++
    ++    result = codec->startIncrementalDecode(infoF16, bm.getPixels(), bm.rowBytes());
    ++    if (supportsIncrementalDecoder) {
    ++        REPORTER_ASSERT(r, SkCodec::kSuccess == result);
    ++    } else {
    ++        REPORTER_ASSERT(r, SkCodec::kUnimplemented == result);
    ++    }
    ++}
    ++
    ++DEF_TEST(Codec_F16ConversionPossible, r) {
    ++    test_conversion_possible(r, "color_wheel.webp", false, false);
    ++    test_conversion_possible(r, "mandrill_512_q075.jpg", true, false);
    ++    test_conversion_possible(r, "yellow_rose.png", false, true);
    ++}
    ++
    ++static void decode_frame(skiatest::Reporter* r, SkCodec* codec, size_t frame) {
    ++    SkBitmap bm;
    ++    auto info = codec->getInfo().makeColorType(kN32_SkColorType);
    ++    bm.allocPixels(info);
    ++
    ++    SkCodec::Options opts;
    ++    opts.fFrameIndex = frame;
    ++    REPORTER_ASSERT(r, SkCodec::kSuccess == codec->getPixels(info,
    ++            bm.getPixels(), bm.rowBytes(), &opts, nullptr, nullptr));
    ++}
    ++
    ++// For an animated image, we should only read enough to decode the requested
    ++// frame if the client never calls getFrameInfo.
    ++DEF_TEST(Codec_skipFullParse, r) {
    ++    auto path = "test640x479.gif";
    ++    SkStream* stream(GetResourceAsStream(path));
    ++    if (!stream) {
    ++        return;
    ++    }
    ++
    ++    // Note that we cheat and hold on to the stream pointer, but SkCodec will
    ++    // take ownership. We will not refer to the stream after the SkCodec
    ++    // deletes it.
    ++    std::unique_ptr<SkCodec> codec(SkCodec::NewFromStream(stream));
    ++    if (!codec) {
    ++        ERRORF(r, "Failed to create codec for %s", path);
    ++        return;
    ++    }
    ++
    ++    REPORTER_ASSERT(r, stream->hasPosition());
    ++    const size_t sizePosition = stream->getPosition();
    ++    REPORTER_ASSERT(r, stream->hasLength() && sizePosition < stream->getLength());
    ++
    ++    // This should read more of the stream, but not the whole stream.
    ++    decode_frame(r, codec.get(), 0);
    ++    const size_t positionAfterFirstFrame = stream->getPosition();
    ++    REPORTER_ASSERT(r, positionAfterFirstFrame > sizePosition
    ++                       && positionAfterFirstFrame < stream->getLength());
    ++
    ++    // Again, this should read more of the stream.
    ++    decode_frame(r, codec.get(), 2);
    ++    const size_t positionAfterThirdFrame = stream->getPosition();
    ++    REPORTER_ASSERT(r, positionAfterThirdFrame > positionAfterFirstFrame
    ++                       && positionAfterThirdFrame < stream->getLength());
    ++
    ++    // This does not need to read any more of the stream, since it has already
    ++    // parsed the second frame.
    ++    decode_frame(r, codec.get(), 1);
    ++    REPORTER_ASSERT(r, stream->getPosition() == positionAfterThirdFrame);
    ++
    ++    // This should read the rest of the frames.
    ++    decode_frame(r, codec.get(), 3);
    ++    const size_t finalPosition = stream->getPosition();
    ++    REPORTER_ASSERT(r, finalPosition > positionAfterThirdFrame);
    ++
    ++    // There may be more data in the stream.
    ++    auto frameInfo = codec->getFrameInfo();
    ++    REPORTER_ASSERT(r, frameInfo.size() == 4);
    ++    REPORTER_ASSERT(r, stream->getPosition() >= finalPosition);
    ++}
    ++
    ++// Only rewinds up to a limit.
    ++class LimitedRewindingStream : public SkStream {
    ++public:
    ++    static SkStream* Make(const char path[], size_t limit) {
    ++        SkStream* stream = GetResourceAsStream(path);
    ++        if (!stream) {
    ++            return nullptr;
    ++        }
    ++        return new LimitedRewindingStream(stream, limit);
    ++    }
    ++
    ++    size_t read(void* buffer, size_t size) override {
    ++        const size_t bytes = fStream->read(buffer, size);
    ++        fPosition += bytes;
    ++        return bytes;
    ++    }
    ++
    ++    bool isAtEnd() const override {
    ++        return fStream->isAtEnd();
    ++    }
    ++
    ++    bool rewind() override {
    ++        if (fPosition <= fLimit && fStream->rewind()) {
    ++            fPosition = 0;
    ++            return true;
    ++        }
    ++
    ++        return false;
    ++    }
    ++
    ++private:
    ++    std::unique_ptr<SkStream> fStream;
    ++    const size_t              fLimit;
    ++    size_t                    fPosition;
    ++
    ++    LimitedRewindingStream(SkStream* stream, size_t limit)
    ++        : fStream(stream)
    ++        , fLimit(limit)
    ++        , fPosition(0)
    ++    {
    ++        SkASSERT(fStream);
    ++    }
    ++};
    ++
    ++DEF_TEST(Codec_fallBack, r) {
    ++    // SkAndroidCodec needs to be able to fall back to scanline decoding
    ++    // if incremental decoding does not work. Make sure this does not
    ++    // require a rewind.
    ++
    ++    // Formats that currently do not support incremental decoding
    ++    auto files = {
    ++            "CMYK.jpg",
    ++            "color_wheel.ico",
    ++            "mandrill.wbmp",
    ++            "randPixels.bmp",
    ++            };
    ++    for (auto file : files) {
    ++        SkStream* stream = LimitedRewindingStream::Make(file, 14);
    ++        if (!stream) {
    ++            SkDebugf("Missing resources (%s). Set --resourcePath.\n", file);
    ++            return;
    ++        }
    ++
    ++        std::unique_ptr<SkCodec> codec(SkCodec::NewFromStream(stream));
    ++        if (!codec) {
    ++            ERRORF(r, "Failed to create codec for %s,", file);
    ++            continue;
    ++        }
    ++
    ++        SkImageInfo info = codec->getInfo().makeColorType(kN32_SkColorType);
    ++        SkBitmap bm;
    ++        bm.allocPixels(info);
    ++
    ++        if (SkCodec::kUnimplemented != codec->startIncrementalDecode(info, bm.getPixels(),
    ++                bm.rowBytes())) {
    ++            ERRORF(r, "Is scanline decoding now implemented for %s?", file);
    ++            continue;
    ++        }
    ++
    ++        // Scanline decoding should not require a rewind.
    ++        SkCodec::Result result = codec->startScanlineDecode(info);
    ++        if (SkCodec::kSuccess != result) {
    ++            ERRORF(r, "Scanline decoding failed for %s with %i", file, result);
    ++        }
    ++    }
    ++}
    ++
    ++// This test verifies that we fixed an assert statement that fired when reusing a png codec
    ++// after scaling.
    ++DEF_TEST(Codec_reusePng, r) {
    ++    std::unique_ptr<SkStream> stream(GetResourceAsStream("plane.png"));
    ++    if (!stream) {
    ++        return;
    ++    }
    ++
    ++    std::unique_ptr<SkAndroidCodec> codec(SkAndroidCodec::NewFromStream(stream.release()));
    ++    if (!codec) {
    ++        ERRORF(r, "Failed to create codec\n");
    ++        return;
    ++    }
    ++
    ++    SkAndroidCodec::AndroidOptions opts;
    ++    opts.fSampleSize = 5;
    ++    auto size = codec->getSampledDimensions(opts.fSampleSize);
    ++    auto info = codec->getInfo().makeWH(size.fWidth, size.fHeight).makeColorType(kN32_SkColorType);
    ++    SkBitmap bm;
    ++    bm.allocPixels(info);
    ++    auto result = codec->getAndroidPixels(info, bm.getPixels(), bm.rowBytes(), &opts);
    ++    REPORTER_ASSERT(r, result == SkCodec::kSuccess);
    ++
    ++    info = codec->getInfo().makeColorType(kN32_SkColorType);
    ++    bm.allocPixels(info);
    ++    opts.fSampleSize = 1;
    ++    result = codec->getAndroidPixels(info, bm.getPixels(), bm.rowBytes(), &opts);
    ++    REPORTER_ASSERT(r, result == SkCodec::kSuccess);
    ++}
    ++
    ++DEF_TEST(Codec_rowsDecoded, r) {
    ++    auto file = "plane_interlaced.png";
    ++    std::unique_ptr<SkStream> stream(GetResourceAsStream(file));
    ++    if (!stream) {
    ++        return;
    ++    }
    ++
    ++    // This is enough to read the header etc, but no rows.
    ++    auto data = SkData::MakeFromStream(stream.get(), 99);
    ++    std::unique_ptr<SkCodec> codec(SkCodec::NewFromData(data));
    ++    if (!codec) {
    ++        ERRORF(r, "Failed to create codec\n");
    ++        return;
    ++    }
    ++
    ++    auto info = codec->getInfo().makeColorType(kN32_SkColorType);
    ++    SkBitmap bm;
    ++    bm.allocPixels(info);
    ++    auto result = codec->startIncrementalDecode(info, bm.getPixels(), bm.rowBytes());
    ++    REPORTER_ASSERT(r, result == SkCodec::kSuccess);
    ++
    ++    // This is an arbitrary value. The important fact is that it is not zero, and rowsDecoded
    ++    // should get set to zero by incrementalDecode.
    ++    int rowsDecoded = 77;
    ++    result = codec->incrementalDecode(&rowsDecoded);
    ++    REPORTER_ASSERT(r, result == SkCodec::kIncompleteInput);
    ++    REPORTER_ASSERT(r, rowsDecoded == 0);
    ++}
    ++
    ++static void test_invalid_images(skiatest::Reporter* r, const char* path, bool shouldSucceed) {
    ++    SkBitmap bitmap;
    ++    const bool success = GetResourceAsBitmap(path, &bitmap);
    ++    REPORTER_ASSERT(r, success == shouldSucceed);
    ++}
    ++
    ++DEF_TEST(Codec_InvalidImages, r) {
    ++    // ASAN will complain if there is an issue.
    ++    test_invalid_images(r, "invalid_images/int_overflow.ico", false);
    ++    test_invalid_images(r, "invalid_images/skbug5887.gif", true);
    ++    test_invalid_images(r, "invalid_images/many-progressive-scans.jpg", false);
    ++}
    ++
    ++DEF_TEST(Codec_InvalidBmp, r) {
    ++    // These files report values that have caused problems with SkFILEStreams.
    ++    // They are invalid, and should not create SkCodecs.
    ++    for (auto* bmp : { "b33651913.bmp", "b34778578.bmp" } ) {
    ++        SkString path = SkOSPath::Join("invalid_images", bmp);
    ++        path = GetResourcePath(path.c_str());
    ++        std::unique_ptr<SkFILEStream> stream(new SkFILEStream(path.c_str()));
    ++        if (!stream->isValid()) {
    ++            return;
    ++        }
    ++
    ++        std::unique_ptr<SkCodec> codec(SkCodec::NewFromStream(stream.release()));
    ++        REPORTER_ASSERT(r, !codec);
    ++    }
    ++}
    ++
    ++DEF_TEST(Codec_InvalidRLEBmp, r) {
    ++    auto* stream = GetResourceAsStream("invalid_images/b33251605.bmp");
    ++    if (!stream) {
    ++        return;
    ++    }
    ++
    ++    std::unique_ptr<SkCodec> codec(SkCodec::NewFromStream(stream));
    ++    REPORTER_ASSERT(r, codec);
    ++
    ++    test_info(r, codec.get(), codec->getInfo(), SkCodec::kIncompleteInput, nullptr);
    ++}
    ++
    ++DEF_TEST(Codec_InvalidAnimated, r) {
    ++    // ASAN will complain if there is an issue.
    ++    auto path = "invalid_images/skbug6046.gif";
    ++    auto* stream = GetResourceAsStream(path);
    ++    if (!stream) {
    ++        return;
    ++    }
    ++
    ++    std::unique_ptr<SkCodec> codec(SkCodec::NewFromStream(stream));
    ++    REPORTER_ASSERT(r, codec);
    ++    if (!codec) {
    ++        return;
    ++    }
    ++
    ++    const auto info = codec->getInfo().makeColorType(kN32_SkColorType);
    ++    SkBitmap bm;
    ++    bm.allocPixels(info);
    ++
    ++    auto frameInfos = codec->getFrameInfo();
    ++    SkCodec::Options opts;
    ++    for (size_t i = 0; i < frameInfos.size(); i++) {
    ++        opts.fFrameIndex = i;
    ++        opts.fHasPriorFrame = frameInfos[i].fRequiredFrame == i - 1;
    ++        auto result = codec->startIncrementalDecode(info, bm.getPixels(), bm.rowBytes(), &opts);
    ++        if (result != SkCodec::kSuccess) {
    ++            ERRORF(r, "Failed to start decoding frame %i (out of %i) with error %i\n", i,
    ++                   frameInfos.size(), result);
    ++            continue;
    ++        }
    ++
    ++        codec->incrementalDecode();
    ++    }
    ++}
    ++
    ++static void encode_format(SkDynamicMemoryWStream* stream, const SkPixmap& pixmap,
    ++                          const SkEncodeOptions& opts, SkEncodedImageFormat format) {
    ++    switch (format) {
    ++        case SkEncodedImageFormat::kPNG:
    ++            SkEncodeImageAsPNG(stream, pixmap, opts);
    ++            break;
    ++        case SkEncodedImageFormat::kJPEG:
    ++            SkEncodeImageAsJPEG(stream, pixmap, opts);
    ++            break;
    ++        case SkEncodedImageFormat::kWEBP:
    ++            SkEncodeImageAsWEBP(stream, pixmap, opts);
    ++            break;
    ++        default:
    ++            SkASSERT(false);
    ++            break;
    ++    }
    ++}
    ++
    ++static void test_encode_icc(skiatest::Reporter* r, SkEncodedImageFormat format,
    ++                            SkTransferFunctionBehavior unpremulBehavior) {
    ++    // Test with sRGB color space.
    ++    SkBitmap srgbBitmap;
    ++    SkImageInfo srgbInfo = SkImageInfo::MakeS32(1, 1, kOpaque_SkAlphaType);
    ++    srgbBitmap.allocPixels(srgbInfo);
    ++    *srgbBitmap.getAddr32(0, 0) = 0;
    ++    SkPixmap pixmap;
    ++    srgbBitmap.peekPixels(&pixmap);
    ++    SkDynamicMemoryWStream srgbBuf;
    ++    SkEncodeOptions opts;
    ++    opts.fUnpremulBehavior = unpremulBehavior;
    ++    encode_format(&srgbBuf, pixmap, opts, format);
    ++    sk_sp<SkData> srgbData = srgbBuf.detachAsData();
    ++    std::unique_ptr<SkCodec> srgbCodec(SkCodec::NewFromData(srgbData));
    ++    REPORTER_ASSERT(r, srgbCodec->getInfo().colorSpace() == SkColorSpace::MakeSRGB().get());
    ++
    ++    // Test with P3 color space.
    ++    SkDynamicMemoryWStream p3Buf;
    ++    sk_sp<SkColorSpace> p3 = SkColorSpace::MakeRGB(SkColorSpace::kSRGB_RenderTargetGamma,
    ++                                                   SkColorSpace::kDCIP3_D65_Gamut);
    ++    pixmap.setColorSpace(p3);
    ++    encode_format(&p3Buf, pixmap, opts, format);
    ++    sk_sp<SkData> p3Data = p3Buf.detachAsData();
    ++    std::unique_ptr<SkCodec> p3Codec(SkCodec::NewFromData(p3Data));
    ++    REPORTER_ASSERT(r, p3Codec->getInfo().colorSpace()->gammaCloseToSRGB());
    ++    SkMatrix44 mat0(SkMatrix44::kUninitialized_Constructor);
    ++    SkMatrix44 mat1(SkMatrix44::kUninitialized_Constructor);
    ++    bool success = p3->toXYZD50(&mat0);
    ++    REPORTER_ASSERT(r, success);
    ++    success = p3Codec->getInfo().colorSpace()->toXYZD50(&mat1);
    ++    REPORTER_ASSERT(r, success);
    ++
    ++    for (int i = 0; i < 4; i++) {
    ++        for (int j = 0; j < 4; j++) {
    ++            REPORTER_ASSERT(r, color_space_almost_equal(mat0.get(i, j), mat1.get(i, j)));
    ++        }
    ++    }
    ++}
    ++
    ++DEF_TEST(Codec_EncodeICC, r) {
    ++    test_encode_icc(r, SkEncodedImageFormat::kPNG, SkTransferFunctionBehavior::kRespect);
    ++    test_encode_icc(r, SkEncodedImageFormat::kJPEG, SkTransferFunctionBehavior::kRespect);
    ++    test_encode_icc(r, SkEncodedImageFormat::kWEBP, SkTransferFunctionBehavior::kRespect);
    ++    test_encode_icc(r, SkEncodedImageFormat::kPNG, SkTransferFunctionBehavior::kIgnore);
    ++    test_encode_icc(r, SkEncodedImageFormat::kJPEG, SkTransferFunctionBehavior::kIgnore);
    ++    test_encode_icc(r, SkEncodedImageFormat::kWEBP, SkTransferFunctionBehavior::kIgnore);
    ++}
    ++
    ++DEF_TEST(Codec_webp_rowsDecoded, r) {
    ++    const char* path = "baby_tux.webp";
    ++    sk_sp<SkData> data(GetResourceAsData(path));
    ++    if (!data) {
    ++        return;
    ++    }
    ++
    ++    // Truncate this file so that the header is available but no rows can be
    ++    // decoded. This should create a codec but fail to decode.
    ++    size_t truncatedSize = 5000;
    ++    sk_sp<SkData> subset = SkData::MakeSubset(data.get(), 0, truncatedSize);
    ++    std::unique_ptr<SkCodec> codec(SkCodec::NewFromData(std::move(subset)));
    ++    if (!codec) {
    ++        ERRORF(r, "Failed to create a codec for %s truncated to only %lu bytes",
    ++               path, truncatedSize);
    ++        return;
    ++    }
    ++
    ++    test_info(r, codec.get(), codec->getInfo(), SkCodec::kInvalidInput, nullptr);
    ++}
    +diff --git a/tests/PathOpsExtendedTest.cpp b/tests/PathOpsExtendedTest.cpp
    +index c96cbcd..9e2dfbe 100644
    +--- a/tests/PathOpsExtendedTest.cpp
    ++++ b/tests/PathOpsExtendedTest.cpp
    +@@ -595,7 +595,7 @@ void initializeTests(skiatest::Reporter* reporter, const char* test) {
    +             inData.setCount((int) inFile.getLength());
    +             size_t inLen = inData.count();
    +             inFile.read(inData.begin(), inLen);
    +-            inFile.setPath(nullptr);
    ++            inFile.close();
    +             char* insert = strstr(inData.begin(), marker);
    +             if (insert) {
    +                 insert += sizeof(marker) - 1;
    +diff --git a/tests/StreamTest.cpp b/tests/StreamTest.cpp
    +index a3df8d7..031cc1a 100644
    +--- a/tests/StreamTest.cpp
    ++++ b/tests/StreamTest.cpp
    +@@ -67,7 +67,7 @@ static void test_filestreams(skiatest::Reporter* reporter, const char* tmpDir) {
    + 
    +     {
    +         FILE* file = ::fopen(path.c_str(), "rb");
    +-        SkFILEStream stream(file, SkFILEStream::kCallerPasses_Ownership);
    ++        SkFILEStream stream(file);
    +         REPORTER_ASSERT(reporter, stream.isValid());
    +         test_loop_stream(reporter, &stream, s, 26, 100);
    + 
    +diff --git a/tools/chrome_fuzz.cpp b/tools/chrome_fuzz.cpp
    +index f49e126..ff14b5b 100644
    +--- a/tools/chrome_fuzz.cpp
    ++++ b/tools/chrome_fuzz.cpp
    +@@ -8,6 +8,8 @@
    + #include "SkOSFile.h"
    + #include "SkString.h"
    + 
    ++#include <stdio.h>
    ++
    + static const int kBitmapSize = 24;
    + 
    + static bool read_test_case(const char* filename, SkString* testdata) {
    +@@ -22,7 +24,7 @@ static bool read_test_case(const char* filename, SkString* testdata) {
    +     return false;
    +   }
    +   testdata->resize(len);
    +-  (void) sk_fread(testdata->writable_str(), len, file);
    ++  (void) fread(testdata->writable_str(), len, file);
    +   return true;
    + }
    + 
    diff --git a/frameworks_av.patch b/frameworks_av.patch
    index 638db3d..78f16d8 100644
    --- a/frameworks_av.patch
    +++ b/frameworks_av.patch
    @@ -97,6 +97,74 @@ index 77b9a33..7c37955 100644
              return ACAMERA_ERROR_INVALID_PARAMETER;
          }
          req->targets->mOutputs.erase(*target);
    +diff --git a/cmds/stagefright/stagefright.cpp b/cmds/stagefright/stagefright.cpp
    +index ca68722..cd284f6 100644
    +--- a/cmds/stagefright/stagefright.cpp
    ++++ b/cmds/stagefright/stagefright.cpp
    +@@ -1037,6 +1037,10 @@ int main(int argc, char **argv) {
    +                 bool haveVideo = false;
    +                 for (size_t i = 0; i < numTracks; ++i) {
    +                     sp<IMediaSource> source = extractor->getTrack(i);
    ++                    if (source == nullptr) {
    ++                        fprintf(stderr, "skip NULL track %zu, track count %zu.\n", i, numTracks);
    ++                        continue;
    ++                    }
    + 
    +                     const char *mime;
    +                     CHECK(source->getFormat()->findCString(
    +@@ -1099,6 +1103,10 @@ int main(int argc, char **argv) {
    +                 }
    + 
    +                 mediaSource = extractor->getTrack(i);
    ++                if (mediaSource == nullptr) {
    ++                    fprintf(stderr, "skip NULL track %zu, total tracks %zu.\n", i, numTracks);
    ++                    return -1;
    ++                }
    +             }
    +         }
    + 
    +diff --git a/cmds/stagefright/stream.cpp b/cmds/stagefright/stream.cpp
    +index bca3832..cf59357 100644
    +--- a/cmds/stagefright/stream.cpp
    ++++ b/cmds/stagefright/stream.cpp
    +@@ -171,7 +171,8 @@ MyConvertingStreamSource::MyConvertingStreamSource(const char *filename)
    +     mWriter = new MPEG2TSWriter(
    +             this, &MyConvertingStreamSource::WriteDataWrapper);
    + 
    +-    for (size_t i = 0; i < extractor->countTracks(); ++i) {
    ++    size_t numTracks = extractor->countTracks();
    ++    for (size_t i = 0; i < numTracks; ++i) {
    +         const sp<MetaData> &meta = extractor->getTrackMetaData(i);
    + 
    +         const char *mime;
    +@@ -181,7 +182,12 @@ MyConvertingStreamSource::MyConvertingStreamSource(const char *filename)
    +             continue;
    +         }
    + 
    +-        CHECK_EQ(mWriter->addSource(extractor->getTrack(i)), (status_t)OK);
    ++        sp<IMediaSource> track = extractor->getTrack(i);
    ++        if (track == nullptr) {
    ++            fprintf(stderr, "skip NULL track %zu, total tracks %zu\n", i, numTracks);
    ++            continue;
    ++        }
    ++        CHECK_EQ(mWriter->addSource(track), (status_t)OK);
    +     }
    + 
    +     CHECK_EQ(mWriter->start(), (status_t)OK);
    +diff --git a/include/media/IMediaExtractor.h b/include/media/IMediaExtractor.h
    +index 34b15e9..743ef7f 100644
    +--- a/include/media/IMediaExtractor.h
    ++++ b/include/media/IMediaExtractor.h
    +@@ -30,6 +30,9 @@ public:
    +     DECLARE_META_INTERFACE(MediaExtractor);
    + 
    +     virtual size_t countTracks() = 0;
    ++    // This function could return NULL IMediaSource even when index is within the
    ++    // track count returned by countTracks, since it's possible the track is malformed
    ++    // and it's not detected during countTracks call.
    +     virtual sp<IMediaSource> getTrack(size_t index) = 0;
    + 
    +     enum GetTrackMetaDataFlags {
     diff --git a/include/media/stagefright/MediaBufferGroup.h b/include/media/stagefright/MediaBufferGroup.h
     index 3051406..870bb9b 100644
     --- a/include/media/stagefright/MediaBufferGroup.h
    @@ -129,1464 +197,23 @@ index 9823c55..cb4be75 100644
                      cmd->vsize, cmd->data + sizeof(int32_t));
              break;
     diff --git a/media/libeffects/lvm/wrapper/Bundle/EffectBundle.cpp b/media/libeffects/lvm/wrapper/Bundle/EffectBundle.cpp
    -index dcf3fa0..b26e74c 100644
    +index dcf3fa0..07ea818 100644
     --- a/media/libeffects/lvm/wrapper/Bundle/EffectBundle.cpp
     +++ b/media/libeffects/lvm/wrapper/Bundle/EffectBundle.cpp
    -@@ -16,7 +16,7 @@
    -  */
    - 
    - #define LOG_TAG "Bundle"
    --#define ARRAY_SIZE(array) (sizeof array / sizeof array[0])
    -+#define ARRAY_SIZE(array) (sizeof (array) / sizeof (array)[0])
    - //#define LOG_NDEBUG 0
    - 
    - #include <assert.h>
    -@@ -25,28 +25,37 @@
    - #include <stdlib.h>
    - #include <string.h>
    - 
    --#include <cutils/log.h>
    -+#include <log/log.h>
    -+
    - #include "EffectBundle.h"
    - #include "math.h"
    - 
    --
    - // effect_handle_t interface implementation for bass boost
    - extern "C" const struct effect_interface_s gLvmEffectInterface;
    - 
    -+// Turn on VERY_VERY_VERBOSE_LOGGING to log parameter get and set for effects.
    -+
    -+//#define VERY_VERY_VERBOSE_LOGGING
    -+#ifdef VERY_VERY_VERBOSE_LOGGING
    -+#define ALOGVV ALOGV
    -+#else
    -+#define ALOGVV(a...) do { } while (false)
    -+#endif
    -+
    - #define LVM_ERROR_CHECK(LvmStatus, callingFunc, calledFunc){\
    --        if (LvmStatus == LVM_NULLADDRESS){\
    -+        if ((LvmStatus) == LVM_NULLADDRESS){\
    -             ALOGV("\tLVM_ERROR : Parameter error - "\
    -                     "null pointer returned by %s in %s\n\n\n\n", callingFunc, calledFunc);\
    -         }\
    --        if (LvmStatus == LVM_ALIGNMENTERROR){\
    -+        if ((LvmStatus) == LVM_ALIGNMENTERROR){\
    -             ALOGV("\tLVM_ERROR : Parameter error - "\
    -                     "bad alignment returned by %s in %s\n\n\n\n", callingFunc, calledFunc);\
    -         }\
    --        if (LvmStatus == LVM_INVALIDNUMSAMPLES){\
    -+        if ((LvmStatus) == LVM_INVALIDNUMSAMPLES){\
    -             ALOGV("\tLVM_ERROR : Parameter error - "\
    -                     "bad number of samples returned by %s in %s\n\n\n\n", callingFunc, calledFunc);\
    -         }\
    --        if (LvmStatus == LVM_OUTOFRANGE){\
    -+        if ((LvmStatus) == LVM_OUTOFRANGE){\
    -             ALOGV("\tLVM_ERROR : Parameter error - "\
    -                     "out of range returned by %s in %s\n", callingFunc, calledFunc);\
    -         }\
    -@@ -138,26 +147,43 @@ int  LvmEffect_disable         (EffectContext *pContext);
    - void LvmEffect_free            (EffectContext *pContext);
    - int  Effect_setConfig          (EffectContext *pContext, effect_config_t *pConfig);
    - void Effect_getConfig          (EffectContext *pContext, effect_config_t *pConfig);
    --int  BassBoost_setParameter    (EffectContext *pContext, void *pParam, void *pValue);
    -+int  BassBoost_setParameter    (EffectContext *pContext,
    -+                                uint32_t       paramSize,
    -+                                void          *pParam,
    -+                                uint32_t       valueSize,
    -+                                void          *pValue);
    - int  BassBoost_getParameter    (EffectContext *pContext,
    --                               void           *pParam,
    --                               uint32_t       *pValueSize,
    --                               void           *pValue);
    --int  Virtualizer_setParameter  (EffectContext *pContext, void *pParam, void *pValue);
    -+                                uint32_t       paramSize,
    -+                                void          *pParam,
    -+                                uint32_t      *pValueSize,
    -+                                void          *pValue);
    -+int  Virtualizer_setParameter  (EffectContext *pContext,
    -+                                uint32_t       paramSize,
    -+                                void          *pParam,
    -+                                uint32_t       valueSize,
    -+                                void          *pValue);
    - int  Virtualizer_getParameter  (EffectContext *pContext,
    --                               void           *pParam,
    --                               uint32_t       *pValueSize,
    --                               void           *pValue);
    -+                                uint32_t       paramSize,
    -+                                void          *pParam,
    -+                                uint32_t      *pValueSize,
    -+                                void          *pValue);
    - int  Equalizer_setParameter    (EffectContext *pContext,
    --                               void *pParam,
    --                               uint32_t valueSize,
    --                               void *pValue);
    -+                                uint32_t       paramSize,
    -+                                void          *pParam,
    -+                                uint32_t       valueSize,
    -+                                void          *pValue);
    - int  Equalizer_getParameter    (EffectContext *pContext,
    -+                                uint32_t       paramSize,
    -                                 void          *pParam,
    -                                 uint32_t      *pValueSize,
    -                                 void          *pValue);
    --int  Volume_setParameter       (EffectContext *pContext, void *pParam, void *pValue);
    -+int  Volume_setParameter       (EffectContext *pContext,
    -+                                uint32_t       paramSize,
    -+                                void          *pParam,
    -+                                uint32_t       valueSize,
    -+                                void          *pValue);
    - int  Volume_getParameter       (EffectContext *pContext,
    -+                                uint32_t       paramSize,
    -                                 void          *pParam,
    -                                 uint32_t      *pValueSize,
    -                                 void          *pValue);
    -@@ -343,8 +369,10 @@ exit:
    -             }
    -             delete pContext;
    -         }
    --        *pHandle = (effect_handle_t)NULL;
    -+        if (pHandle != NULL)
    -+          *pHandle = (effect_handle_t)NULL;
    -     } else {
    -+      if (pHandle != NULL)
    -         *pHandle = (effect_handle_t)pContext;
    -     }
    -     ALOGV("\tEffectCreate end..\n\n");
    -@@ -504,8 +532,6 @@ void LvmGlobalBundle_init(){
    - //----------------------------------------------------------------------------
    - 
    - int LvmBundle_init(EffectContext *pContext){
    --    int status;
    --
    -     ALOGV("\tLvmBundle_init start");
    - 
    -     pContext->config.inputCfg.accessMode                    = EFFECT_BUFFER_ACCESS_READ;
    -@@ -719,7 +745,6 @@ int LvmBundle_process(LVM_INT16        *pIn,
    -                       int              frameCount,
    -                       EffectContext    *pContext){
    - 
    --    LVM_ControlParams_t     ActiveParams;                           /* Current control Parameters */
    -     LVM_ReturnStatus_en     LvmStatus = LVM_SUCCESS;                /* Function call status */
    -     LVM_INT16               *pOutTmp;
    - 
    -@@ -1043,7 +1068,6 @@ int LvmEffect_disable(EffectContext *pContext){
    - 
    - void LvmEffect_free(EffectContext *pContext){
    -     LVM_ReturnStatus_en     LvmStatus=LVM_SUCCESS;         /* Function call status */
    --    LVM_ControlParams_t     params;                        /* Control Parameters */
    -     LVM_MemTab_t            MemTab;
    - 
    -     /* Free the algorithm memory */
    -@@ -2011,61 +2035,54 @@ int32_t VolumeEnableStereoPosition(EffectContext *pContext, uint32_t enabled){
    - //
    - //----------------------------------------------------------------------------
    - 
    --int BassBoost_getParameter(EffectContext     *pContext,
    --                           void              *pParam,
    --                           uint32_t          *pValueSize,
    --                           void              *pValue){
    -+int BassBoost_getParameter(EffectContext *pContext,
    -+                           uint32_t       paramSize,
    -+                           void          *pParam,
    -+                           uint32_t      *pValueSize,
    -+                           void          *pValue) {
    -     int status = 0;
    --    int32_t *pParamTemp = (int32_t *)pParam;
    --    int32_t param = *pParamTemp++;
    --    int32_t param2;
    --    char *name;
    -+    int32_t *params = (int32_t *)pParam;
    - 
    --    //ALOGV("\tBassBoost_getParameter start");
    -+    ALOGVV("%s start", __func__);
    - 
    --    switch (param){
    -+    if (paramSize < sizeof(int32_t)) {
    -+        ALOGV("%s invalid paramSize: %u", __func__, paramSize);
    -+        return -EINVAL;
    -+    }
    -+    switch (params[0]) {
    -         case BASSBOOST_PARAM_STRENGTH_SUPPORTED:
    --            if (*pValueSize != sizeof(uint32_t)){
    --                ALOGV("\tLVM_ERROR : BassBoost_getParameter() invalid pValueSize1 %d", *pValueSize);
    --                return -EINVAL;
    --            }
    --            *pValueSize = sizeof(uint32_t);
    --            break;
    --        case BASSBOOST_PARAM_STRENGTH:
    --            if (*pValueSize != sizeof(int16_t)){
    --                ALOGV("\tLVM_ERROR : BassBoost_getParameter() invalid pValueSize2 %d", *pValueSize);
    --                return -EINVAL;
    -+            if (*pValueSize != sizeof(uint32_t)) {  // legacy: check equality here.
    -+                ALOGV("%s BASSBOOST_PARAM_STRENGTH_SUPPORTED invalid *pValueSize %u",
    -+                        __func__, *pValueSize);
    -+                status = -EINVAL;
    -+                break;
    -             }
    --            *pValueSize = sizeof(int16_t);
    --            break;
    -+            // no need to set *pValueSize
    - 
    --        default:
    --            ALOGV("\tLVM_ERROR : BassBoost_getParameter() invalid param %d", param);
    --            return -EINVAL;
    --    }
    --
    --    switch (param){
    --        case BASSBOOST_PARAM_STRENGTH_SUPPORTED:
    -             *(uint32_t *)pValue = 1;
    --
    --            //ALOGV("\tBassBoost_getParameter() BASSBOOST_PARAM_STRENGTH_SUPPORTED Value is %d",
    --            //        *(uint32_t *)pValue);
    -+            ALOGVV("%s BASSBOOST_PARAM_STRENGTH_SUPPORTED %u", __func__, *(uint32_t *)pValue);
    -             break;
    - 
    -         case BASSBOOST_PARAM_STRENGTH:
    --            *(int16_t *)pValue = BassGetStrength(pContext);
    -+            if (*pValueSize != sizeof(int16_t)) {  // legacy: check equality here.
    -+                ALOGV("%s BASSBOOST_PARAM_STRENGTH invalid *pValueSize %u",
    -+                        __func__, *pValueSize);
    -+                status = -EINVAL;
    -+                break;
    -+            }
    -+            // no need to set *pValueSize
    - 
    --            //ALOGV("\tBassBoost_getParameter() BASSBOOST_PARAM_STRENGTH Value is %d",
    --            //        *(int16_t *)pValue);
    -+            *(int16_t *)pValue = BassGetStrength(pContext);
    -+            ALOGVV("%s BASSBOOST_PARAM_STRENGTH %d", __func__, *(int16_t *)pValue);
    -             break;
    - 
    -         default:
    --            ALOGV("\tLVM_ERROR : BassBoost_getParameter() invalid param %d", param);
    -+            ALOGV("%s invalid param %d", __func__, params[0]);
    -             status = -EINVAL;
    -             break;
    -     }
    - 
    --    //ALOGV("\tBassBoost_getParameter end");
    -+    ALOGVV("%s end param: %d, status: %d", __func__, params[0], status);
    -     return status;
    - } /* end BassBoost_getParameter */
    - 
    -@@ -2084,27 +2101,42 @@ int BassBoost_getParameter(EffectContext     *pContext,
    - //
    - //----------------------------------------------------------------------------
    - 
    --int BassBoost_setParameter (EffectContext *pContext, void *pParam, void *pValue){
    -+int BassBoost_setParameter(EffectContext *pContext,
    -+                           uint32_t       paramSize,
    -+                           void          *pParam,
    -+                           uint32_t       valueSize,
    -+                           void          *pValue) {
    -     int status = 0;
    --    int16_t strength;
    --    int32_t *pParamTemp = (int32_t *)pParam;
    -+    int32_t *params = (int32_t *)pParam;
    - 
    --    //ALOGV("\tBassBoost_setParameter start");
    -+    ALOGVV("%s start", __func__);
    - 
    --    switch (*pParamTemp){
    --        case BASSBOOST_PARAM_STRENGTH:
    --            strength = *(int16_t *)pValue;
    --            //ALOGV("\tBassBoost_setParameter() BASSBOOST_PARAM_STRENGTH value is %d", strength);
    --            //ALOGV("\tBassBoost_setParameter() Calling pBassBoost->BassSetStrength");
    -+    if (paramSize != sizeof(int32_t)) {  // legacy: check equality here.
    -+        ALOGV("%s invalid paramSize: %u", __func__, paramSize);
    -+        return -EINVAL;
    -+    }
    -+    switch (params[0]) {
    -+        case BASSBOOST_PARAM_STRENGTH: {
    -+            if (valueSize < sizeof(int16_t)) {
    -+                ALOGV("%s BASSBOOST_PARAM_STRENGTH invalid valueSize: %u", __func__, valueSize);
    -+                status = -EINVAL;
    -+                break;
    -+            }
    -+
    -+            const int16_t strength = *(int16_t *)pValue;
    -+            ALOGVV("%s BASSBOOST_PARAM_STRENGTH %d", __func__, strength);
    -+            ALOGVV("%s BASSBOOST_PARAM_STRENGTH Calling BassSetStrength", __func__);
    -             BassSetStrength(pContext, (int32_t)strength);
    --            //ALOGV("\tBassBoost_setParameter() Called pBassBoost->BassSetStrength");
    --           break;
    -+            ALOGVV("%s BASSBOOST_PARAM_STRENGTH Called BassSetStrength", __func__);
    -+        } break;
    -+
    -         default:
    --            ALOGV("\tLVM_ERROR : BassBoost_setParameter() invalid param %d", *pParamTemp);
    -+            ALOGV("%s invalid param %d", __func__, params[0]);
    -+            status = -EINVAL;
    -             break;
    -     }
    - 
    --    //ALOGV("\tBassBoost_setParameter end");
    -+    ALOGVV("%s end param: %d, status: %d", __func__, params[0], status);
    -     return status;
    - } /* end BassBoost_setParameter */
    - 
    -@@ -2129,93 +2161,97 @@ int BassBoost_setParameter (EffectContext *pContext, void *pParam, void *pValue)
    - //
    - //----------------------------------------------------------------------------
    - 
    --int Virtualizer_getParameter(EffectContext        *pContext,
    --                             void                 *pParam,
    --                             uint32_t             *pValueSize,
    --                             void                 *pValue){
    -+int Virtualizer_getParameter(EffectContext *pContext,
    -+                             uint32_t       paramSize,
    -+                             void          *pParam,
    -+                             uint32_t      *pValueSize,
    -+                             void          *pValue) {
    -     int status = 0;
    --    int32_t *pParamTemp = (int32_t *)pParam;
    --    int32_t param = *pParamTemp++;
    --    char *name;
    -+    int32_t *params = (int32_t *)pParam;
    - 
    --    //ALOGV("\tVirtualizer_getParameter start");
    -+    ALOGVV("%s start", __func__);
    - 
    --    switch (param){
    -+    if (paramSize < sizeof(int32_t)) {
    -+        ALOGV("%s invalid paramSize: %u", __func__, paramSize);
    -+        return -EINVAL;
    -+    }
    -+    switch (params[0]) {
    -         case VIRTUALIZER_PARAM_STRENGTH_SUPPORTED:
    --            if (*pValueSize != sizeof(uint32_t)){
    --                ALOGV("\tLVM_ERROR : Virtualizer_getParameter() invalid pValueSize %d",*pValueSize);
    --                return -EINVAL;
    --            }
    --            *pValueSize = sizeof(uint32_t);
    --            break;
    --        case VIRTUALIZER_PARAM_STRENGTH:
    --            if (*pValueSize != sizeof(int16_t)){
    --                ALOGV("\tLVM_ERROR : Virtualizer_getParameter() invalid pValueSize2 %d",*pValueSize);
    --                return -EINVAL;
    --            }
    --            *pValueSize = sizeof(int16_t);
    --            break;
    --        case VIRTUALIZER_PARAM_VIRTUAL_SPEAKER_ANGLES:
    --            // return value size can only be interpreted as relative to input value,
    --            // deferring validity check to below
    --            break;
    --        case VIRTUALIZER_PARAM_VIRTUALIZATION_MODE:
    --            if (*pValueSize != sizeof(uint32_t)){
    --                ALOGV("\tLVM_ERROR : Virtualizer_getParameter() invalid pValueSize %d",*pValueSize);
    --                return -EINVAL;
    -+            if (*pValueSize != sizeof(uint32_t)) { // legacy: check equality here.
    -+                ALOGV("%s VIRTUALIZER_PARAM_STRENGTH_SUPPORTED invalid *pValueSize %u",
    -+                        __func__, *pValueSize);
    -+                status = -EINVAL;
    -+                break;
    -             }
    --            *pValueSize = sizeof(uint32_t);
    --            break;
    --        default:
    --            ALOGV("\tLVM_ERROR : Virtualizer_getParameter() invalid param %d", param);
    --            return -EINVAL;
    --    }
    -+            // no need to set *pValueSize
    - 
    --    switch (param){
    --        case VIRTUALIZER_PARAM_STRENGTH_SUPPORTED:
    -             *(uint32_t *)pValue = 1;
    --
    --            //ALOGV("\tVirtualizer_getParameter() VIRTUALIZER_PARAM_STRENGTH_SUPPORTED Value is %d",
    --            //        *(uint32_t *)pValue);
    -+            ALOGVV("%s VIRTUALIZER_PARAM_STRENGTH_SUPPORTED %d", __func__, *(uint32_t *)pValue);
    -             break;
    - 
    -         case VIRTUALIZER_PARAM_STRENGTH:
    -+            if (*pValueSize != sizeof(int16_t)) { // legacy: check equality here.
    -+                ALOGV("%s VIRTUALIZER_PARAM_STRENGTH invalid *pValueSize %u",
    -+                        __func__, *pValueSize);
    -+                status = -EINVAL;
    -+                break;
    -+            }
    -+            // no need to set *pValueSize
    -+
    -             *(int16_t *)pValue = VirtualizerGetStrength(pContext);
    - 
    --            //ALOGV("\tVirtualizer_getParameter() VIRTUALIZER_PARAM_STRENGTH Value is %d",
    --            //        *(int16_t *)pValue);
    -+            ALOGVV("%s VIRTUALIZER_PARAM_STRENGTH %d", __func__, *(int16_t *)pValue);
    -             break;
    - 
    -         case VIRTUALIZER_PARAM_VIRTUAL_SPEAKER_ANGLES: {
    --            const audio_channel_mask_t channelMask = (audio_channel_mask_t) *pParamTemp++;
    --            const audio_devices_t deviceType = (audio_devices_t) *pParamTemp;
    --            uint32_t nbChannels = audio_channel_count_from_out_mask(channelMask);
    --            if (*pValueSize < 3 * nbChannels * sizeof(int32_t)){
    --                ALOGV("\tLVM_ERROR : Virtualizer_getParameter() invalid pValueSize %d",*pValueSize);
    --                return -EINVAL;
    -+            if (paramSize < 3 * sizeof(int32_t)) {
    -+                ALOGV("%s VIRTUALIZER_PARAM_SPEAKER_ANGLES invalid paramSize: %u",
    -+                        __func__, paramSize);
    -+                status = -EINVAL;
    -+                break;
    -+            }
    -+
    -+            const audio_channel_mask_t channelMask = (audio_channel_mask_t) params[1];
    -+            const audio_devices_t deviceType = (audio_devices_t) params[2];
    -+            const uint32_t nbChannels = audio_channel_count_from_out_mask(channelMask);
    -+            const uint32_t valueSizeRequired = 3 * nbChannels * sizeof(int32_t);
    -+            if (*pValueSize < valueSizeRequired) {
    -+                ALOGV("%s VIRTUALIZER_PARAM_SPEAKER_ANGLES invalid *pValueSize %u",
    -+                        __func__, *pValueSize);
    -+                status = -EINVAL;
    -+                break;
    -             }
    -+            *pValueSize = valueSizeRequired;
    -+
    -             // verify the configuration is supported
    -             status = VirtualizerIsConfigurationSupported(channelMask, deviceType);
    -             if (status == 0) {
    --                ALOGV("VIRTUALIZER_PARAM_VIRTUAL_SPEAKER_ANGLES supports mask=0x%x device=0x%x",
    --                        channelMask, deviceType);
    -+                ALOGV("%s VIRTUALIZER_PARAM_VIRTUAL_SPEAKER_ANGLES mask=0x%x device=0x%x",
    -+                        __func__, channelMask, deviceType);
    -                 // configuration is supported, get the angles
    -                 VirtualizerGetSpeakerAngles(channelMask, deviceType, (int32_t *)pValue);
    -             }
    --            }
    --            break;
    -+        } break;
    - 
    -         case VIRTUALIZER_PARAM_VIRTUALIZATION_MODE:
    --            *(uint32_t *)pValue  = (uint32_t) VirtualizerGetVirtualizationMode(pContext);
    -+            if (*pValueSize != sizeof(uint32_t)) { // legacy: check equality here.
    -+                ALOGV("%s VIRTUALIZER_PARAM_VIRTUALIZATION_MODE invalid *pValueSize %u",
    -+                        __func__, *pValueSize);
    -+                status = -EINVAL;
    -+                break;
    -+            }
    -+            // no need to set *pValueSize
    -+
    -+            *(uint32_t *)pValue = (uint32_t) VirtualizerGetVirtualizationMode(pContext);
    -             break;
    - 
    -         default:
    --            ALOGV("\tLVM_ERROR : Virtualizer_getParameter() invalid param %d", param);
    -+            ALOGV("%s invalid param %d", __func__, params[0]);
    -             status = -EINVAL;
    -             break;
    -     }
    - 
    --    ALOGV("\tVirtualizer_getParameter end returning status=%d", status);
    -+    ALOGVV("%s end param: %d, status: %d", __func__, params[0], status);
    -     return status;
    - } /* end Virtualizer_getParameter */
    - 
    -@@ -2234,37 +2270,57 @@ int Virtualizer_getParameter(EffectContext        *pContext,
    - //
    - //----------------------------------------------------------------------------
    - 
    --int Virtualizer_setParameter (EffectContext *pContext, void *pParam, void *pValue){
    -+int Virtualizer_setParameter(EffectContext *pContext,
    -+                             uint32_t       paramSize,
    -+                             void          *pParam,
    -+                             uint32_t       valueSize,
    -+                             void          *pValue) {
    -     int status = 0;
    --    int16_t strength;
    --    int32_t *pParamTemp = (int32_t *)pParam;
    --    int32_t param = *pParamTemp++;
    -+    int32_t *params = (int32_t *)pParam;
    - 
    --    //ALOGV("\tVirtualizer_setParameter start");
    -+    ALOGVV("%s start", __func__);
    - 
    --    switch (param){
    --        case VIRTUALIZER_PARAM_STRENGTH:
    --            strength = *(int16_t *)pValue;
    --            //ALOGV("\tVirtualizer_setParameter() VIRTUALIZER_PARAM_STRENGTH value is %d", strength);
    --            //ALOGV("\tVirtualizer_setParameter() Calling pVirtualizer->setStrength");
    -+    if (paramSize != sizeof(int32_t)) { // legacy: check equality here.
    -+        ALOGV("%s invalid paramSize: %u", __func__, paramSize);
    -+        return -EINVAL;
    -+    }
    -+    switch (params[0]) {
    -+        case VIRTUALIZER_PARAM_STRENGTH: {
    -+            if (valueSize < sizeof(int16_t)) {
    -+                ALOGV("%s VIRTUALIZER_PARAM_STRENGTH invalid valueSize: %u", __func__, valueSize);
    -+                status = -EINVAL;
    -+                break;
    -+            }
    -+
    -+            const int16_t strength = *(int16_t *)pValue;
    -+            ALOGVV("%s VIRTUALIZER_PARAM_STRENGTH %d", __func__, strength);
    -+            ALOGVV("%s VIRTUALIZER_PARAM_STRENGTH Calling VirtualizerSetStrength", __func__);
    -             VirtualizerSetStrength(pContext, (int32_t)strength);
    --            //ALOGV("\tVirtualizer_setParameter() Called pVirtualizer->setStrength");
    --           break;
    -+            ALOGVV("%s VIRTUALIZER_PARAM_STRENGTH Called VirtualizerSetStrength", __func__);
    -+        } break;
    - 
    -         case VIRTUALIZER_PARAM_FORCE_VIRTUALIZATION_MODE: {
    --            const audio_devices_t deviceType = *(audio_devices_t *) pValue;
    --            status = VirtualizerForceVirtualizationMode(pContext, deviceType);
    --            //ALOGV("VIRTUALIZER_PARAM_FORCE_VIRTUALIZATION_MODE device=0x%x result=%d",
    --            //        deviceType, status);
    -+            if (valueSize < sizeof(int32_t)) {
    -+                ALOGV("%s VIRTUALIZER_PARAM_FORCE_VIRTUALIZATION_MODE invalid valueSize: %u",
    -+                        __func__, valueSize);
    -+                android_errorWriteLog(0x534e4554, "64478003");
    -+                status = -EINVAL;
    -+                break;
    +@@ -2439,6 +2439,13 @@ int Equalizer_getParameter(EffectContext     *pContext,
                  }
    --            break;
    -+
    -+            const audio_devices_t deviceType = (audio_devices_t)*(int32_t *)pValue;
    -+            status = VirtualizerForceVirtualizationMode(pContext, deviceType);
    -+            ALOGVV("%s VIRTUALIZER_PARAM_FORCE_VIRTUALIZATION_MODE device=%#x result=%d",
    -+                    __func__, deviceType, status);
    -+        } break;
    - 
    -         default:
    --            ALOGV("\tLVM_ERROR : Virtualizer_setParameter() invalid param %d", param);
    -+            ALOGV("%s invalid param %d", __func__, params[0]);
    -+            status = -EINVAL;
                  break;
    -     }
    - 
    --    //ALOGV("\tVirtualizer_setParameter end");
    -+    ALOGVV("%s end param: %d, status: %d", __func__, params[0], status);
    -     return status;
    - } /* end Virtualizer_setParameter */
    - 
    -@@ -2288,168 +2344,215 @@ int Virtualizer_setParameter (EffectContext *pContext, void *pParam, void *pValu
    - // Side Effects:
    - //
    - //----------------------------------------------------------------------------
    --int Equalizer_getParameter(EffectContext     *pContext,
    --                           void              *pParam,
    --                           uint32_t          *pValueSize,
    --                           void              *pValue){
    -+int Equalizer_getParameter(EffectContext *pContext,
    -+                           uint32_t       paramSize,
    -+                           void          *pParam,
    -+                           uint32_t      *pValueSize,
    -+                           void          *pValue) {
    -     int status = 0;
    --    int bMute = 0;
    --    int32_t *pParamTemp = (int32_t *)pParam;
    --    int32_t param = *pParamTemp++;
    --    int32_t param2;
    --    char *name;
    -+    int32_t *params = (int32_t *)pParam;
    - 
    --    //ALOGV("\tEqualizer_getParameter start");
    -+    ALOGVV("%s start", __func__);
    - 
    --    switch (param) {
    -+    if (paramSize < sizeof(int32_t)) {
    -+        ALOGV("%s invalid paramSize: %u", __func__, paramSize);
    -+        return -EINVAL;
    -+    }
    -+    switch (params[0]) {
    -     case EQ_PARAM_NUM_BANDS:
    --    case EQ_PARAM_CUR_PRESET:
    --    case EQ_PARAM_GET_NUM_OF_PRESETS:
    --    case EQ_PARAM_BAND_LEVEL:
    --    case EQ_PARAM_GET_BAND:
    --        if (*pValueSize < sizeof(int16_t)) {
    --            ALOGV("\tLVM_ERROR : Equalizer_getParameter() invalid pValueSize 1  %d", *pValueSize);
    --            return -EINVAL;
    -+        if (*pValueSize < sizeof(uint16_t)) {
    -+            ALOGV("%s EQ_PARAM_NUM_BANDS invalid *pValueSize %u", __func__, *pValueSize);
    -+            status = -EINVAL;
    -+            break;
    -         }
    --        *pValueSize = sizeof(int16_t);
    --        break;
    -+        *pValueSize = sizeof(uint16_t);
    - 
    --    case EQ_PARAM_LEVEL_RANGE:
    --        if (*pValueSize < 2 * sizeof(int16_t)) {
    --            ALOGV("\tLVM_ERROR : Equalizer_getParameter() invalid pValueSize 2  %d", *pValueSize);
    --            return -EINVAL;
    --        }
    --        *pValueSize = 2 * sizeof(int16_t);
    -+        *(uint16_t *)pValue = (uint16_t)FIVEBAND_NUMBANDS;
    -+        ALOGVV("%s EQ_PARAM_NUM_BANDS %u", __func__, *(uint16_t *)pValue);
    -         break;
    --    case EQ_PARAM_BAND_FREQ_RANGE:
    --        if (*pValueSize < 2 * sizeof(int32_t)) {
    --            ALOGV("\tLVM_ERROR : Equalizer_getParameter() invalid pValueSize 3  %d", *pValueSize);
    --            return -EINVAL;
    -+
    -+    case EQ_PARAM_CUR_PRESET:
    -+        if (*pValueSize < sizeof(uint16_t)) {
    -+            ALOGV("%s EQ_PARAM_CUR_PRESET invalid *pValueSize %u", __func__, *pValueSize);
    -+            status = -EINVAL;
    -+            break;
    -         }
    --        *pValueSize = 2 * sizeof(int32_t);
    -+        *pValueSize = sizeof(uint16_t);
    -+
    -+        *(uint16_t *)pValue = (uint16_t)EqualizerGetPreset(pContext);
    -+        ALOGVV("%s EQ_PARAM_CUR_PRESET %u", __func__, *(uint16_t *)pValue);
    -         break;
    - 
    --    case EQ_PARAM_CENTER_FREQ:
    --        if (*pValueSize < sizeof(int32_t)) {
    --            ALOGV("\tLVM_ERROR : Equalizer_getParameter() invalid pValueSize 5  %d", *pValueSize);
    --            return -EINVAL;
    -+    case EQ_PARAM_GET_NUM_OF_PRESETS:
    -+        if (*pValueSize < sizeof(uint16_t)) {
    -+            ALOGV("%s EQ_PARAM_GET_NUM_OF_PRESETS invalid *pValueSize %u", __func__, *pValueSize);
    -+            status = -EINVAL;
    -+            break;
    -         }
    --        *pValueSize = sizeof(int32_t);
    --        break;
    -+        *pValueSize = sizeof(uint16_t);
    - 
    --    case EQ_PARAM_GET_PRESET_NAME:
    -+        *(uint16_t *)pValue = (uint16_t)EqualizerGetNumPresets();
    -+        ALOGVV("%s EQ_PARAM_GET_NUM_OF_PRESETS %u", __func__, *(uint16_t *)pValue);
    -         break;
    - 
    --    case EQ_PARAM_PROPERTIES:
    --        if (*pValueSize < (2 + FIVEBAND_NUMBANDS) * sizeof(uint16_t)) {
    --            ALOGV("\tLVM_ERROR : Equalizer_getParameter() invalid pValueSize 1  %d", *pValueSize);
    --            return -EINVAL;
    -+    case EQ_PARAM_GET_BAND: {
    -+        if (paramSize < 2 * sizeof(int32_t)) {
    -+            ALOGV("%s EQ_PARAM_GET_BAND invalid paramSize: %u", __func__, paramSize);
    -+            status = -EINVAL;
    -+            break;
              }
    --        *pValueSize = (2 + FIVEBAND_NUMBANDS) * sizeof(uint16_t);
    --        break;
    -+        if (*pValueSize < sizeof(uint16_t)) {
    -+            ALOGV("%s EQ_PARAM_GET_BAND invalid *pValueSize %u", __func__, *pValueSize);
    -+            status = -EINVAL;
    -+            break;
    -+        }
    -+        *pValueSize = sizeof(uint16_t);
    - 
    --    default:
    --        ALOGV("\tLVM_ERROR : Equalizer_getParameter unknown param %d", param);
    --        return -EINVAL;
    --    }
    -+        const int32_t frequency = params[1];
    -+        *(uint16_t *)pValue = (uint16_t)EqualizerGetBand(pContext, frequency);
    -+        ALOGVV("%s EQ_PARAM_GET_BAND frequency %d, band %u",
    -+                __func__, frequency, *(uint16_t *)pValue);
    -+    } break;
    - 
    --    switch (param) {
    --    case EQ_PARAM_NUM_BANDS:
    --        *(uint16_t *)pValue = (uint16_t)FIVEBAND_NUMBANDS;
    --        //ALOGV("\tEqualizer_getParameter() EQ_PARAM_NUM_BANDS %d", *(int16_t *)pValue);
    --        break;
    -+    case EQ_PARAM_BAND_LEVEL: {
    -+        if (paramSize < 2 * sizeof(int32_t)) {
    -+            ALOGV("%s EQ_PARAM_BAND_LEVEL invalid paramSize %u", __func__, paramSize);
    -+            status = -EINVAL;
    -+            break;
    -+        }
    -+        if (*pValueSize < sizeof(int16_t)) {
    -+            ALOGV("%s EQ_PARAM_BAND_LEVEL invalid *pValueSize %u", __func__, *pValueSize);
    -+            status = -EINVAL;
    -+            break;
    -+        }
    -+        *pValueSize = sizeof(int16_t);
     +
    -+        const int32_t band = params[1];
    -+        if (band < 0 || band >= FIVEBAND_NUMBANDS) {
    -+            if (band < 0) {
    -+                android_errorWriteLog(0x534e4554, "32438598");
    -+                ALOGW("%s EQ_PARAM_BAND_LEVEL invalid band %d", __func__, band);
    -+            }
    -+            status = -EINVAL;
    -+            break;
    -+        }
    -+        *(int16_t *)pValue = (int16_t)EqualizerGetBandLevel(pContext, band);
    -+        ALOGVV("%s EQ_PARAM_BAND_LEVEL band %d, level %d",
    -+                __func__, band, *(int16_t *)pValue);
    -+    } break;
    - 
    -     case EQ_PARAM_LEVEL_RANGE:
    -+        if (*pValueSize < 2 * sizeof(int16_t)) {
    -+            ALOGV("%s EQ_PARAM_LEVEL_RANGE invalid *pValueSize %u", __func__, *pValueSize);
    -+            status = -EINVAL;
    -+            break;
    -+        }
    -+        *pValueSize = 2 * sizeof(int16_t);
    -+
    -         *(int16_t *)pValue = -1500;
    -         *((int16_t *)pValue + 1) = 1500;
    --        //ALOGV("\tEqualizer_getParameter() EQ_PARAM_LEVEL_RANGE min %d, max %d",
    --        //      *(int16_t *)pValue, *((int16_t *)pValue + 1));
    -+        ALOGVV("%s EQ_PARAM_LEVEL_RANGE min %d, max %d",
    -+                __func__, *(int16_t *)pValue, *((int16_t *)pValue + 1));
    -         break;
    - 
    --    case EQ_PARAM_BAND_LEVEL:
    --        param2 = *pParamTemp;
    --        if (param2 < 0 || param2 >= FIVEBAND_NUMBANDS) {
    -+    case EQ_PARAM_BAND_FREQ_RANGE: {
    -+        if (paramSize < 2 * sizeof(int32_t)) {
    -+            ALOGV("%s EQ_PARAM_BAND_FREQ_RANGE invalid paramSize: %u", __func__, paramSize);
    -             status = -EINVAL;
    --            if (param2 < 0) {
    --                android_errorWriteLog(0x534e4554, "32438598");
    --                ALOGW("\tERROR Equalizer_getParameter() EQ_PARAM_BAND_LEVEL band %d", param2);
    --            }
    -             break;
    -         }
    --        *(int16_t *)pValue = (int16_t)EqualizerGetBandLevel(pContext, param2);
    --        //ALOGV("\tEqualizer_getParameter() EQ_PARAM_BAND_LEVEL band %d, level %d",
    --        //      param2, *(int32_t *)pValue);
    --        break;
    --
    --    case EQ_PARAM_CENTER_FREQ:
    --        param2 = *pParamTemp;
    --        if (param2 < 0 || param2 >= FIVEBAND_NUMBANDS) {
    -+        if (*pValueSize < 2 * sizeof(int32_t)) {
    -+            ALOGV("%s EQ_PARAM_BAND_FREQ_RANGE invalid *pValueSize %u", __func__, *pValueSize);
    -             status = -EINVAL;
    --            if (param2 < 0) {
    --                android_errorWriteLog(0x534e4554, "32436341");
    --                ALOGW("\tERROR Equalizer_getParameter() EQ_PARAM_CENTER_FREQ band %d", param2);
    --            }
    -             break;
    -         }
    --        *(int32_t *)pValue = EqualizerGetCentreFrequency(pContext, param2);
    --        //ALOGV("\tEqualizer_getParameter() EQ_PARAM_CENTER_FREQ band %d, frequency %d",
    --        //      param2, *(int32_t *)pValue);
    --        break;
    -+        *pValueSize = 2 * sizeof(int32_t);
    - 
    --    case EQ_PARAM_BAND_FREQ_RANGE:
    --        param2 = *pParamTemp;
    --        if (param2 < 0 || param2 >= FIVEBAND_NUMBANDS) {
    --            status = -EINVAL;
    --            if (param2 < 0) {
    -+        const int32_t band = params[1];
    -+        if (band < 0 || band >= FIVEBAND_NUMBANDS) {
    -+            if (band < 0) {
    -                 android_errorWriteLog(0x534e4554, "32247948");
    --                ALOGW("\tERROR Equalizer_getParameter() EQ_PARAM_BAND_FREQ_RANGE band %d", param2);
    -+                ALOGW("%s EQ_PARAM_BAND_FREQ_RANGE invalid band %d",
    -+                        __func__, band);
    -             }
    -+            status = -EINVAL;
    -             break;
    -         }
    --        EqualizerGetBandFreqRange(pContext, param2, (uint32_t *)pValue, ((uint32_t *)pValue + 1));
    --        //ALOGV("\tEqualizer_getParameter() EQ_PARAM_BAND_FREQ_RANGE band %d, min %d, max %d",
    --        //      param2, *(int32_t *)pValue, *((int32_t *)pValue + 1));
    --        break;
    -+        EqualizerGetBandFreqRange(pContext, band, (uint32_t *)pValue, ((uint32_t *)pValue + 1));
    -+        ALOGVV("%s EQ_PARAM_BAND_FREQ_RANGE band %d, min %d, max %d",
    -+                __func__, band, *(int32_t *)pValue, *((int32_t *)pValue + 1));
    - 
    --    case EQ_PARAM_GET_BAND:
    --        param2 = *pParamTemp;
    --        *(uint16_t *)pValue = (uint16_t)EqualizerGetBand(pContext, param2);
    --        //ALOGV("\tEqualizer_getParameter() EQ_PARAM_GET_BAND frequency %d, band %d",
    --        //      param2, *(uint16_t *)pValue);
    --        break;
    -+    } break;
    - 
    --    case EQ_PARAM_CUR_PRESET:
    --        *(uint16_t *)pValue = (uint16_t)EqualizerGetPreset(pContext);
    --        //ALOGV("\tEqualizer_getParameter() EQ_PARAM_CUR_PRESET %d", *(int32_t *)pValue);
    --        break;
    -+    case EQ_PARAM_CENTER_FREQ: {
    -+        if (paramSize < 2 * sizeof(int32_t)) {
    -+            ALOGV("%s EQ_PARAM_CENTER_FREQ invalid paramSize: %u", __func__, paramSize);
    -+            status = -EINVAL;
    -+            break;
    -+        }
    -+        if (*pValueSize < sizeof(int32_t)) {
    -+            ALOGV("%s EQ_PARAM_CENTER_FREQ invalid *pValueSize %u", __func__, *pValueSize);
    -+            status = -EINVAL;
    -+            break;
    -+        }
    -+        *pValueSize = sizeof(int32_t);
    - 
    --    case EQ_PARAM_GET_NUM_OF_PRESETS:
    --        *(uint16_t *)pValue = (uint16_t)EqualizerGetNumPresets();
    --        //ALOGV("\tEqualizer_getParameter() EQ_PARAM_GET_NUM_OF_PRESETS %d", *(int16_t *)pValue);
    --        break;
    -+        const int32_t band = params[1];
    -+        if (band < 0 || band >= FIVEBAND_NUMBANDS) {
    -+            status = -EINVAL;
    -+            if (band < 0) {
    -+                android_errorWriteLog(0x534e4554, "32436341");
    -+                ALOGW("%s EQ_PARAM_CENTER_FREQ invalid band %d", __func__, band);
    -+            }
    -+            break;
    -+        }
    -+        *(int32_t *)pValue = EqualizerGetCentreFrequency(pContext, band);
    -+        ALOGVV("%s EQ_PARAM_CENTER_FREQ band %d, frequency %d",
    -+                __func__, band, *(int32_t *)pValue);
    -+    } break;
    - 
    --    case EQ_PARAM_GET_PRESET_NAME:
    --        param2 = *pParamTemp;
    --        if ((param2 < 0 && param2 != PRESET_CUSTOM) ||  param2 >= EqualizerGetNumPresets()) {
    -+    case EQ_PARAM_GET_PRESET_NAME: {
    -+        if (paramSize < 2 * sizeof(int32_t)) {
    -+            ALOGV("%s EQ_PARAM_PRESET_NAME invalid paramSize: %u", __func__, paramSize);
    -             status = -EINVAL;
    --            if (param2 < 0) {
    -+            break;
    -+        }
     +        if (*pValueSize < 1) {
    -+            android_errorWriteLog(0x534e4554, "37536407");
     +            status = -EINVAL;
    ++            android_errorWriteLog(0x534e4554, "37536407");
     +            break;
     +        }
     +
    -+        const int32_t preset = params[1];
    -+        if ((preset < 0 && preset != PRESET_CUSTOM) ||  preset >= EqualizerGetNumPresets()) {
    -+            if (preset < 0) {
    -                 android_errorWriteLog(0x534e4554, "32448258");
    --                ALOGE("\tERROR Equalizer_getParameter() EQ_PARAM_GET_PRESET_NAME preset %d",
    --                        param2);
    -+                ALOGE("%s EQ_PARAM_GET_PRESET_NAME preset %d", __func__, preset);
    -             }
    -+            status = -EINVAL;
    -             break;
    -         }
    --        name = (char *)pValue;
    --        strncpy(name, EqualizerGetPresetName(param2), *pValueSize - 1);
    -+
    -+        char * const name = (char *)pValue;
    -+        strncpy(name, EqualizerGetPresetName(preset), *pValueSize - 1);
    +         name = (char *)pValue;
    +         strncpy(name, EqualizerGetPresetName(param2), *pValueSize - 1);
              name[*pValueSize - 1] = 0;
    -         *pValueSize = strlen(name) + 1;
    --        //ALOGV("\tEqualizer_getParameter() EQ_PARAM_GET_PRESET_NAME preset %d, name %s len %d",
    --        //      param2, gEqualizerPresets[param2].name, *pValueSize);
    --        break;
    -+        ALOGVV("%s EQ_PARAM_GET_PRESET_NAME preset %d, name %s len %d",
    -+                __func__, preset, gEqualizerPresets[preset].name, *pValueSize);
    -+
    -+    } break;
    - 
    -     case EQ_PARAM_PROPERTIES: {
    -+        constexpr uint32_t requiredValueSize = (2 + FIVEBAND_NUMBANDS) * sizeof(uint16_t);
    -+        if (*pValueSize < requiredValueSize) {
    -+            ALOGV("%s EQ_PARAM_PROPERTIES invalid *pValueSize %u", __func__, *pValueSize);
    -+            status = -EINVAL;
    -+            break;
    -+        }
    -+        *pValueSize = requiredValueSize;
    -+
    -         int16_t *p = (int16_t *)pValue;
    --        ALOGV("\tEqualizer_getParameter() EQ_PARAM_PROPERTIES");
    -+        ALOGV("%s EQ_PARAM_PROPERTIES", __func__);
    -         p[0] = (int16_t)EqualizerGetPreset(pContext);
    -         p[1] = (int16_t)FIVEBAND_NUMBANDS;
    -         for (int i = 0; i < FIVEBAND_NUMBANDS; i++) {
    -@@ -2458,12 +2561,12 @@ int Equalizer_getParameter(EffectContext     *pContext,
    -     } break;
    - 
    -     default:
    --        ALOGV("\tLVM_ERROR : Equalizer_getParameter() invalid param %d", param);
    -+        ALOGV("%s invalid param %d", __func__, params[0]);
    -         status = -EINVAL;
    -         break;
    -     }
    - 
    --    //GV("\tEqualizer_getParameter end\n");
    -+    ALOGVV("%s end param: %d, status: %d", __func__, params[0], status);
    -     return status;
    - } /* end Equalizer_getParameter */
    - 
    -@@ -2483,74 +2586,89 @@ int Equalizer_getParameter(EffectContext     *pContext,
    - // Outputs:
    - //
    - //----------------------------------------------------------------------------
    --int Equalizer_setParameter (EffectContext *pContext,
    --                            void *pParam,
    --                            uint32_t valueSize,
    --                            void *pValue) {
    -+int Equalizer_setParameter(EffectContext *pContext,
    -+                           uint32_t       paramSize,
    -+                           void          *pParam,
    -+                           uint32_t       valueSize,
    -+                           void          *pValue) {
    -     int status = 0;
    --    int32_t preset;
    --    int32_t band;
    --    int32_t level;
    --    int32_t *pParamTemp = (int32_t *)pParam;
    --    int32_t param = *pParamTemp++;
    -+    int32_t *params = (int32_t *)pParam;
    - 
    -+    ALOGVV("%s start", __func__);
    - 
    --    //ALOGV("\tEqualizer_setParameter start");
    --    switch (param) {
    --    case EQ_PARAM_CUR_PRESET:
    -+    if (paramSize < sizeof(int32_t)) {
    -+        ALOGV("%s invalid paramSize: %u", __func__, paramSize);
    -+        return -EINVAL;
    -+    }
    -+    switch (params[0]) {
    -+    case EQ_PARAM_CUR_PRESET: {
    -         if (valueSize < sizeof(int16_t)) {
    --          status = -EINVAL;
    --          break;
    -+            ALOGV("%s EQ_PARAM_CUR_PRESET invalid valueSize %u", __func__, valueSize);
    -+            status = -EINVAL;
    -+            break;
    -         }
    --        preset = (int32_t)(*(uint16_t *)pValue);
    -+        const int32_t preset = (int32_t)*(uint16_t *)pValue;
    - 
    --        //ALOGV("\tEqualizer_setParameter() EQ_PARAM_CUR_PRESET %d", preset);
    --        if ((preset >= EqualizerGetNumPresets())||(preset < 0)) {
    -+        ALOGVV("%s EQ_PARAM_CUR_PRESET %d", __func__, preset);
    -+        if (preset >= EqualizerGetNumPresets() || preset < 0) {
    -+            ALOGV("%s EQ_PARAM_CUR_PRESET invalid preset %d", __func__, preset);
    -             status = -EINVAL;
    -             break;
    -         }
    -         EqualizerSetPreset(pContext, preset);
    --        break;
    --    case EQ_PARAM_BAND_LEVEL:
    -+    } break;
    -+
    -+    case EQ_PARAM_BAND_LEVEL: {
    -+        if (paramSize < 2 * sizeof(int32_t)) {
    -+            ALOGV("%s EQ_PARAM_BAND_LEVEL invalid paramSize: %u", __func__, paramSize);
    -+            status = -EINVAL;
    -+            break;
    -+        }
    -         if (valueSize < sizeof(int16_t)) {
    --          status = -EINVAL;
    --          break;
    -+            ALOGV("%s EQ_PARAM_BAND_LEVEL invalid valueSize %u", __func__, valueSize);
    -+            status = -EINVAL;
    -+            break;
    -         }
    --        band =  *pParamTemp;
    --        level = (int32_t)(*(int16_t *)pValue);
    --        //ALOGV("\tEqualizer_setParameter() EQ_PARAM_BAND_LEVEL band %d, level %d", band, level);
    -+        const int32_t band =  params[1];
    -+        const int32_t level = (int32_t)*(int16_t *)pValue;
    -+        ALOGVV("%s EQ_PARAM_BAND_LEVEL band %d, level %d", __func__, band, level);
    -         if (band < 0 || band >= FIVEBAND_NUMBANDS) {
    --            status = -EINVAL;
    -             if (band < 0) {
    -                 android_errorWriteLog(0x534e4554, "32095626");
    --                ALOGE("\tERROR Equalizer_setParameter() EQ_PARAM_BAND_LEVEL band %d", band);
    -+                ALOGE("%s EQ_PARAM_BAND_LEVEL invalid band %d", __func__, band);
    -             }
    -+            status = -EINVAL;
    -             break;
    -         }
    -         EqualizerSetBandLevel(pContext, band, level);
    --        break;
    -+    } break;
    -+
    -     case EQ_PARAM_PROPERTIES: {
    --        //ALOGV("\tEqualizer_setParameter() EQ_PARAM_PROPERTIES");
    -+        ALOGVV("%s EQ_PARAM_PROPERTIES", __func__);
    -         if (valueSize < sizeof(int16_t)) {
    --          status = -EINVAL;
    --          break;
    -+            ALOGV("%s EQ_PARAM_PROPERTIES invalid valueSize %u", __func__, valueSize);
    -+            status = -EINVAL;
    -+            break;
    -         }
    -         int16_t *p = (int16_t *)pValue;
    -         if ((int)p[0] >= EqualizerGetNumPresets()) {
    -+            ALOGV("%s EQ_PARAM_PROPERTIES invalid preset %d", __func__, (int)p[0]);
    -             status = -EINVAL;
    -             break;
    -         }
    -         if (p[0] >= 0) {
    -             EqualizerSetPreset(pContext, (int)p[0]);
    -         } else {
    --            if (valueSize < (2 + FIVEBAND_NUMBANDS) * sizeof(int16_t)) {
    -+            constexpr uint32_t valueSizeRequired = (2 + FIVEBAND_NUMBANDS) * sizeof(int16_t);
    -+            if (valueSize < valueSizeRequired) {
    -               android_errorWriteLog(0x534e4554, "37563371");
    --              ALOGE("\tERROR Equalizer_setParameter() EQ_PARAM_PROPERTIES valueSize %d < %d",
    --                    (int)valueSize, (int)((2 + FIVEBAND_NUMBANDS) * sizeof(int16_t)));
    -+              ALOGE("%s EQ_PARAM_PROPERTIES invalid valueSize %u < %u",
    -+                      __func__, valueSize, valueSizeRequired);
    -               status = -EINVAL;
    -               break;
    -             }
    -             if ((int)p[1] != FIVEBAND_NUMBANDS) {
    -+                ALOGV("%s EQ_PARAM_PROPERTIES invalid bands %d", __func__, (int)p[1]);
    -                 status = -EINVAL;
    -                 break;
    -             }
    -@@ -2559,13 +2677,14 @@ int Equalizer_setParameter (EffectContext *pContext,
    -             }
    -         }
    -     } break;
    -+
    -     default:
    --        ALOGV("\tLVM_ERROR : Equalizer_setParameter() invalid param %d", param);
    -+        ALOGV("%s invalid param %d", __func__, params[0]);
    -         status = -EINVAL;
    -         break;
    -     }
    - 
    --    //ALOGV("\tEqualizer_setParameter end");
    -+    ALOGVV("%s end param: %d, status: %d", __func__, params[0], status);
    -     return status;
    - } /* end Equalizer_setParameter */
    - 
    -@@ -2590,81 +2709,92 @@ int Equalizer_setParameter (EffectContext *pContext,
    - //
    - //----------------------------------------------------------------------------
    - 
    --int Volume_getParameter(EffectContext     *pContext,
    --                        void              *pParam,
    --                        uint32_t          *pValueSize,
    --                        void              *pValue){
    -+int Volume_getParameter(EffectContext *pContext,
    -+                        uint32_t       paramSize,
    -+                        void          *pParam,
    -+                        uint32_t      *pValueSize,
    -+                        void          *pValue) {
    -     int status = 0;
    --    int bMute = 0;
    --    int32_t *pParamTemp = (int32_t *)pParam;
    --    int32_t param = *pParamTemp++;;
    --    char *name;
    -+    int32_t *params = (int32_t *)pParam;
    - 
    --    //ALOGV("\tVolume_getParameter start");
    -+    ALOGVV("%s start", __func__);
    - 
    --    switch (param){
    -+    if (paramSize < sizeof(int32_t)) {
    -+        ALOGV("%s invalid paramSize: %u", __func__, paramSize);
    -+        return -EINVAL;
    -+    }
    -+    switch (params[0]) {
    -         case VOLUME_PARAM_LEVEL:
    --        case VOLUME_PARAM_MAXLEVEL:
    --        case VOLUME_PARAM_STEREOPOSITION:
    --            if (*pValueSize != sizeof(int16_t)){
    --                ALOGV("\tLVM_ERROR : Volume_getParameter() invalid pValueSize 1  %d", *pValueSize);
    --                return -EINVAL;
    --            }
    --            *pValueSize = sizeof(int16_t);
    --            break;
    --
    --        case VOLUME_PARAM_MUTE:
    --        case VOLUME_PARAM_ENABLESTEREOPOSITION:
    --            if (*pValueSize < sizeof(int32_t)){
    --                ALOGV("\tLVM_ERROR : Volume_getParameter() invalid pValueSize 2  %d", *pValueSize);
    --                return -EINVAL;
    -+            if (*pValueSize != sizeof(int16_t)) { // legacy: check equality here.
    -+                ALOGV("%s VOLUME_PARAM_LEVEL invalid *pValueSize %u", __func__, *pValueSize);
    -+                status = -EINVAL;
    -+                break;
    -             }
    --            *pValueSize = sizeof(int32_t);
    --            break;
    -+            // no need to set *pValueSize
    - 
    --        default:
    --            ALOGV("\tLVM_ERROR : Volume_getParameter unknown param %d", param);
    --            return -EINVAL;
    --    }
    --
    --    switch (param){
    --        case VOLUME_PARAM_LEVEL:
    -             status = VolumeGetVolumeLevel(pContext, (int16_t *)(pValue));
    --            //ALOGV("\tVolume_getParameter() VOLUME_PARAM_LEVEL Value is %d",
    --            //        *(int16_t *)pValue);
    -+            ALOGVV("%s VOLUME_PARAM_LEVEL %d", __func__, *(int16_t *)pValue);
    -             break;
    - 
    -         case VOLUME_PARAM_MAXLEVEL:
    -+            if (*pValueSize != sizeof(int16_t)) { // legacy: check equality here.
    -+                ALOGV("%s VOLUME_PARAM_MAXLEVEL invalid *pValueSize %u", __func__, *pValueSize);
    -+                status = -EINVAL;
    -+                break;
    -+            }
    -+            // no need to set *pValueSize
    -+
    -+            // in millibel
    -             *(int16_t *)pValue = 0;
    --            //ALOGV("\tVolume_getParameter() VOLUME_PARAM_MAXLEVEL Value is %d",
    --            //        *(int16_t *)pValue);
    -+            ALOGVV("%s VOLUME_PARAM_MAXLEVEL %d", __func__, *(int16_t *)pValue);
    -             break;
    - 
    -         case VOLUME_PARAM_STEREOPOSITION:
    -+            if (*pValueSize != sizeof(int16_t)) { // legacy: check equality here.
    -+                ALOGV("%s VOLUME_PARAM_STEREOPOSITION invalid *pValueSize %u",
    -+                        __func__, *pValueSize);
    -+                status = -EINVAL;
    -+                break;
    -+            }
    -+            // no need to set *pValueSize
    -+
    -             VolumeGetStereoPosition(pContext, (int16_t *)pValue);
    --            //ALOGV("\tVolume_getParameter() VOLUME_PARAM_STEREOPOSITION Value is %d",
    --            //        *(int16_t *)pValue);
    -+            ALOGVV("%s VOLUME_PARAM_STEREOPOSITION %d", __func__, *(int16_t *)pValue);
    -             break;
    - 
    -         case VOLUME_PARAM_MUTE:
    -+            if (*pValueSize < sizeof(uint32_t)) {
    -+                ALOGV("%s VOLUME_PARAM_MUTE invalid *pValueSize %u", __func__, *pValueSize);
    -+                status = -EINVAL;
    -+                break;
    -+            }
    -+            *pValueSize = sizeof(uint32_t);
    -+
    -             status = VolumeGetMute(pContext, (uint32_t *)pValue);
    --            ALOGV("\tVolume_getParameter() VOLUME_PARAM_MUTE Value is %d",
    --                    *(uint32_t *)pValue);
    -+            ALOGV("%s VOLUME_PARAM_MUTE %u", __func__, *(uint32_t *)pValue);
    -             break;
    - 
    -         case VOLUME_PARAM_ENABLESTEREOPOSITION:
    -+            if (*pValueSize < sizeof(int32_t)) {
    -+                ALOGV("%s VOLUME_PARAM_ENABLESTEREOPOSITION invalid *pValueSize %u",
    -+                        __func__, *pValueSize);
    -+                status = -EINVAL;
    -+                break;
    -+            }
    -+            *pValueSize = sizeof(int32_t);
    -+
    -             *(int32_t *)pValue = pContext->pBundledContext->bStereoPositionEnabled;
    --            //ALOGV("\tVolume_getParameter() VOLUME_PARAM_ENABLESTEREOPOSITION Value is %d",
    --            //        *(uint32_t *)pValue);
    -+            ALOGVV("%s VOLUME_PARAM_ENABLESTEREOPOSITION %d", __func__, *(int32_t *)pValue);
    -+
    -             break;
    - 
    -         default:
    --            ALOGV("\tLVM_ERROR : Volume_getParameter() invalid param %d", param);
    -+            ALOGV("%s invalid param %d", __func__, params[0]);
    -             status = -EINVAL;
    -             break;
    -     }
    - 
    --    //ALOGV("\tVolume_getParameter end");
    -+    ALOGVV("%s end param: %d, status: %d", __func__, params[0], status);
    -     return status;
    - } /* end Volume_getParameter */
    - 
    -@@ -2684,55 +2814,87 @@ int Volume_getParameter(EffectContext     *pContext,
    - //
    - //----------------------------------------------------------------------------
    - 
    --int Volume_setParameter (EffectContext *pContext, void *pParam, void *pValue){
    --    int      status = 0;
    --    int16_t  level;
    --    int16_t  position;
    --    uint32_t mute;
    --    uint32_t positionEnabled;
    --    int32_t *pParamTemp = (int32_t *)pParam;
    --    int32_t param = *pParamTemp++;
    -+int Volume_setParameter(EffectContext *pContext,
    -+                        uint32_t       paramSize,
    -+                        void          *pParam,
    -+                        uint32_t       valueSize,
    -+                        void          *pValue) {
    -+    int status = 0;
    -+    int32_t *params = (int32_t *)pParam;
    - 
    --    //ALOGV("\tVolume_setParameter start");
    -+    ALOGVV("%s start", __func__);
    - 
    --    switch (param){
    --        case VOLUME_PARAM_LEVEL:
    --            level = *(int16_t *)pValue;
    --            //ALOGV("\tVolume_setParameter() VOLUME_PARAM_LEVEL value is %d", level);
    --            //ALOGV("\tVolume_setParameter() Calling pVolume->setVolumeLevel");
    --            status = VolumeSetVolumeLevel(pContext, (int16_t)level);
    --            //ALOGV("\tVolume_setParameter() Called pVolume->setVolumeLevel");
    --            break;
    -+    if (paramSize < sizeof(int32_t)) {
    -+        ALOGV("%s invalid paramSize: %u", __func__, paramSize);
    -+        return -EINVAL;
    -+    }
    -+    switch (params[0]) {
    -+        case VOLUME_PARAM_LEVEL: {
    -+            if (valueSize < sizeof(int16_t)) {
    -+                ALOGV("%s VOLUME_PARAM_LEVEL invalid valueSize %u", __func__, valueSize);
    -+                status = -EINVAL;
    -+                break;
    -+            }
    - 
    --        case VOLUME_PARAM_MUTE:
    --            mute = *(uint32_t *)pValue;
    --            //ALOGV("\tVolume_setParameter() Calling pVolume->setMute, mute is %d", mute);
    --            //ALOGV("\tVolume_setParameter() Calling pVolume->setMute");
    -+            const int16_t level = *(int16_t *)pValue;
    -+            ALOGVV("%s VOLUME_PARAM_LEVEL %d", __func__, level);
    -+            ALOGVV("%s VOLUME_PARAM_LEVEL Calling VolumeSetVolumeLevel", __func__);
    -+            status = VolumeSetVolumeLevel(pContext, level);
    -+            ALOGVV("%s VOLUME_PARAM_LEVEL Called VolumeSetVolumeLevel", __func__);
    -+        } break;
    -+
    -+        case VOLUME_PARAM_MUTE: {
    -+            if (valueSize < sizeof(uint32_t)) {
    -+                ALOGV("%s VOLUME_PARAM_MUTE invalid valueSize %u", __func__, valueSize);
    -+                android_errorWriteLog(0x534e4554, "64477217");
    -+                status = -EINVAL;
    -+                break;
    -+            }
    -+
    -+            const uint32_t mute = *(uint32_t *)pValue;
    -+            ALOGVV("%s VOLUME_PARAM_MUTE %d", __func__, mute);
    -+            ALOGVV("%s VOLUME_PARAM_MUTE Calling VolumeSetMute", __func__);
    -             status = VolumeSetMute(pContext, mute);
    --            //ALOGV("\tVolume_setParameter() Called pVolume->setMute");
    --            break;
    -+            ALOGVV("%s VOLUME_PARAM_MUTE Called VolumeSetMute", __func__);
    -+        } break;
    - 
    --        case VOLUME_PARAM_ENABLESTEREOPOSITION:
    --            positionEnabled = *(uint32_t *)pValue;
    --            status = VolumeEnableStereoPosition(pContext, positionEnabled);
    --            status = VolumeSetStereoPosition(pContext, pContext->pBundledContext->positionSaved);
    --            //ALOGV("\tVolume_setParameter() VOLUME_PARAM_ENABLESTEREOPOSITION called");
    --            break;
    -+        case VOLUME_PARAM_ENABLESTEREOPOSITION: {
    -+            if (valueSize < sizeof(uint32_t)) {
    -+                ALOGV("%s VOLUME_PARAM_ENABLESTEREOPOSITION invalid valueSize %u",
    -+                        __func__, valueSize);
    -+                status = -EINVAL;
    -+                break;
    -+            }
    - 
    --        case VOLUME_PARAM_STEREOPOSITION:
    --            position = *(int16_t *)pValue;
    --            //ALOGV("\tVolume_setParameter() VOLUME_PARAM_STEREOPOSITION value is %d", position);
    --            //ALOGV("\tVolume_setParameter() Calling pVolume->VolumeSetStereoPosition");
    --            status = VolumeSetStereoPosition(pContext, (int16_t)position);
    --            //ALOGV("\tVolume_setParameter() Called pVolume->VolumeSetStereoPosition");
    --            break;
    -+            const uint32_t positionEnabled = *(uint32_t *)pValue;
    -+            status = VolumeEnableStereoPosition(pContext, positionEnabled)
    -+                    ?: VolumeSetStereoPosition(pContext, pContext->pBundledContext->positionSaved);
    -+            ALOGVV("%s VOLUME_PARAM_ENABLESTEREOPOSITION called", __func__);
    -+        } break;
    -+
    -+        case VOLUME_PARAM_STEREOPOSITION: {
    -+            if (valueSize < sizeof(int16_t)) {
    -+                ALOGV("%s VOLUME_PARAM_STEREOPOSITION invalid valueSize %u", __func__, valueSize);
    -+                status = -EINVAL;
    -+                break;
    -+            }
    -+
    -+            const int16_t position = *(int16_t *)pValue;
    -+            ALOGVV("%s VOLUME_PARAM_STEREOPOSITION %d", __func__, position);
    -+            ALOGVV("%s VOLUME_PARAM_STEREOPOSITION Calling VolumeSetStereoPosition",
    -+                    __func__);
    -+            status = VolumeSetStereoPosition(pContext, position);
    -+            ALOGVV("%s VOLUME_PARAM_STEREOPOSITION Called VolumeSetStereoPosition",
    -+                    __func__);
    -+        } break;
    - 
    -         default:
    --            ALOGV("\tLVM_ERROR : Volume_setParameter() invalid param %d", param);
    -+            ALOGV("%s invalid param %d", __func__, params[0]);
    -+            status = -EINVAL;
    -             break;
    -     }
    - 
    --    //ALOGV("\tVolume_setParameter end");
    -+    ALOGVV("%s end param: %d, status: %d", __func__, params[0], status);
    -     return status;
    - } /* end Volume_setParameter */
    - 
    -@@ -2928,11 +3090,8 @@ int Effect_process(effect_handle_t     self,
    -                               audio_buffer_t         *inBuffer,
    -                               audio_buffer_t         *outBuffer){
    -     EffectContext * pContext = (EffectContext *) self;
    --    LVM_ReturnStatus_en     LvmStatus = LVM_SUCCESS;                /* Function call status */
    -     int    status = 0;
    -     int    processStatus = 0;
    --    LVM_INT16   *in  = (LVM_INT16 *)inBuffer->raw;
    --    LVM_INT16   *out = (LVM_INT16 *)outBuffer->raw;
    - 
    - //ALOGV("\tEffect_process Start : Enabled = %d     Called = %d (%8d %8d %8d)",
    - //pContext->pBundledContext->NumberEffectsEnabled,pContext->pBundledContext->NumberEffectsCalled,
    -@@ -3053,6 +3212,13 @@ int Effect_process(effect_handle_t     self,
    -     return status;
    - }   /* end Effect_process */
    - 
    -+// The value offset of an effect parameter is computed by rounding up
    -+// the parameter size to the next 32 bit alignment.
    -+static inline uint32_t computeParamVOffset(const effect_param_t *p) {
    -+    return ((p->psize + sizeof(int32_t) - 1) / sizeof(int32_t)) *
    -+            sizeof(int32_t);
    -+}
    -+
    - /* Effect Control Interface Implementation: Command */
    - int Effect_command(effect_handle_t  self,
    -                               uint32_t            cmdCode,
    -@@ -3061,7 +3227,6 @@ int Effect_command(effect_handle_t  self,
    -                               uint32_t            *replySize,
    -                               void                *pReplyData){
    -     EffectContext * pContext = (EffectContext *) self;
    --    int retsize;
    - 
    -     //ALOGV("\t\nEffect_command start");
    - 
    -@@ -3164,8 +3329,7 @@ int Effect_command(effect_handle_t  self,
    -                 ALOGV("\tLVM_ERROR : EFFECT_CMD_GET_PARAM: psize too big");
    -                 return -EINVAL;
    -             }
    --            uint32_t paddedParamSize = ((p->psize + sizeof(int32_t) - 1) / sizeof(int32_t)) *
    --                    sizeof(int32_t);
    -+            const uint32_t paddedParamSize = computeParamVOffset(p);
    -             if ((EFFECT_PARAM_SIZE_MAX - sizeof(effect_param_t) < paddedParamSize) ||
    -                 (EFFECT_PARAM_SIZE_MAX - sizeof(effect_param_t) - paddedParamSize <
    -                     p->vsize)) {
    -@@ -3187,6 +3351,7 @@ int Effect_command(effect_handle_t  self,
    -             uint32_t voffset = paddedParamSize;
    -             if(pContext->EffectType == LVM_BASS_BOOST){
    -                 p->status = android::BassBoost_getParameter(pContext,
    -+                                                            p->psize,
    -                                                             p->data,
    -                                                             &p->vsize,
    -                                                             p->data + voffset);
    -@@ -3199,6 +3364,7 @@ int Effect_command(effect_handle_t  self,
    - 
    -             if(pContext->EffectType == LVM_VIRTUALIZER){
    -                 p->status = android::Virtualizer_getParameter(pContext,
    -+                                                              p->psize,
    -                                                               (void *)p->data,
    -                                                               &p->vsize,
    -                                                               p->data + voffset);
    -@@ -3213,6 +3379,7 @@ int Effect_command(effect_handle_t  self,
    -                 //ALOGV("\tEqualizer_command cmdCode Case: "
    -                 //        "EFFECT_CMD_GET_PARAM start");
    -                 p->status = android::Equalizer_getParameter(pContext,
    -+                                                            p->psize,
    -                                                             p->data,
    -                                                             &p->vsize,
    -                                                             p->data + voffset);
    -@@ -3227,6 +3394,7 @@ int Effect_command(effect_handle_t  self,
    -             if(pContext->EffectType == LVM_VOLUME){
    -                 //ALOGV("\tVolume_command cmdCode Case: EFFECT_CMD_GET_PARAM start");
    -                 p->status = android::Volume_getParameter(pContext,
    -+                                                         p->psize,
    -                                                          (void *)p->data,
    -                                                          &p->vsize,
    -                                                          p->data + voffset);
    -@@ -3256,13 +3424,9 @@ int Effect_command(effect_handle_t  self,
    -                             "EFFECT_CMD_SET_PARAM: ERROR");
    -                     return -EINVAL;
    -                 }
    --                effect_param_t *p = (effect_param_t *) pCmdData;
    - 
    --                if (p->psize != sizeof(int32_t)){
    --                    ALOGV("\tLVM_ERROR : BassBoost_command cmdCode Case: "
    --                            "EFFECT_CMD_SET_PARAM: ERROR, psize is not sizeof(int32_t)");
    --                    return -EINVAL;
    --                }
    -+                effect_param_t * const p = (effect_param_t *) pCmdData;
    -+                const uint32_t voffset = computeParamVOffset(p);
    - 
    -                 //ALOGV("\tnBassBoost_command cmdSize is %d\n"
    -                 //        "\tsizeof(effect_param_t) is  %d\n"
    -@@ -3272,8 +3436,10 @@ int Effect_command(effect_handle_t  self,
    -                 //        cmdSize, sizeof(effect_param_t), p->psize, p->vsize );
    - 
    -                 *(int *)pReplyData = android::BassBoost_setParameter(pContext,
    --                                                                    (void *)p->data,
    --                                                                    p->data + p->psize);
    -+                                                                     p->psize,
    -+                                                                     (void *)p->data,
    -+                                                                     p->vsize,
    -+                                                                     p->data + voffset);
    -             }
    -             if(pContext->EffectType == LVM_VIRTUALIZER){
    -               // Warning this log will fail to properly read an int32_t value, assumes int16_t
    -@@ -3291,13 +3457,9 @@ int Effect_command(effect_handle_t  self,
    -                             "EFFECT_CMD_SET_PARAM: ERROR");
    -                     return -EINVAL;
    -                 }
    --                effect_param_t *p = (effect_param_t *) pCmdData;
    - 
    --                if (p->psize != sizeof(int32_t)){
    --                    ALOGV("\tLVM_ERROR : Virtualizer_command cmdCode Case: "
    --                            "EFFECT_CMD_SET_PARAM: ERROR, psize is not sizeof(int32_t)");
    --                    return -EINVAL;
    --                }
    -+                effect_param_t * const p = (effect_param_t *) pCmdData;
    -+                const uint32_t voffset = computeParamVOffset(p);
    - 
    -                 //ALOGV("\tnVirtualizer_command cmdSize is %d\n"
    -                 //        "\tsizeof(effect_param_t) is  %d\n"
    -@@ -3307,8 +3469,10 @@ int Effect_command(effect_handle_t  self,
    -                 //        cmdSize, sizeof(effect_param_t), p->psize, p->vsize );
    - 
    -                 *(int *)pReplyData = android::Virtualizer_setParameter(pContext,
    --                                                                      (void *)p->data,
    --                                                                       p->data + p->psize);
    -+                                                                       p->psize,
    -+                                                                       (void *)p->data,
    -+                                                                       p->vsize,
    -+                                                                       p->data + voffset);
    -             }
    -             if(pContext->EffectType == LVM_EQUALIZER){
    -                //ALOGV("\tEqualizer_command cmdCode Case: "
    -@@ -3324,12 +3488,15 @@ int Effect_command(effect_handle_t  self,
    -                             "EFFECT_CMD_SET_PARAM: ERROR");
    -                     return -EINVAL;
    -                 }
    --                effect_param_t *p = (effect_param_t *) pCmdData;
    -+
    -+                effect_param_t * const p = (effect_param_t *) pCmdData;
    -+                const uint32_t voffset = computeParamVOffset(p);
    - 
    -                 *(int *)pReplyData = android::Equalizer_setParameter(pContext,
    --                                                                    (void *)p->data,
    --                                                                    p->vsize,
    --                                                                    p->data + p->psize);
    -+                                                                     p->psize,
    -+                                                                     (void *)p->data,
    -+                                                                     p->vsize,
    -+                                                                     p->data + voffset);
    -             }
    -             if(pContext->EffectType == LVM_VOLUME){
    -                 //ALOGV("\tVolume_command cmdCode Case: EFFECT_CMD_SET_PARAM start");
    -@@ -3346,11 +3513,15 @@ int Effect_command(effect_handle_t  self,
    -                             "EFFECT_CMD_SET_PARAM: ERROR");
    -                     return -EINVAL;
    -                 }
    --                effect_param_t *p = (effect_param_t *) pCmdData;
    -+
    -+                effect_param_t * const p = (effect_param_t *) pCmdData;
    -+                const uint32_t voffset = computeParamVOffset(p);
    - 
    -                 *(int *)pReplyData = android::Volume_setParameter(pContext,
    --                                                                 (void *)p->data,
    --                                                                 p->data + p->psize);
    -+                                                                  p->psize,
    -+                                                                  (void *)p->data,
    -+                                                                  p->vsize,
    -+                                                                  p->data + voffset);
    -             }
    -             //ALOGV("\tEffect_command cmdCode Case: EFFECT_CMD_SET_PARAM end");
    -         } break;
    -@@ -3461,7 +3632,6 @@ int Effect_command(effect_handle_t  self,
    -             int16_t  leftdB, rightdB;
    -             int16_t  maxdB, pandB;
    -             int32_t  vol_ret[2] = {1<<24,1<<24}; // Apply no volume
    --            int      status = 0;
    -             LVM_ControlParams_t     ActiveParams;           /* Current control Parameters */
    -             LVM_ReturnStatus_en     LvmStatus=LVM_SUCCESS;  /* Function call status */
    - 
     diff --git a/media/libeffects/lvm/wrapper/Reverb/EffectReverb.cpp b/media/libeffects/lvm/wrapper/Reverb/EffectReverb.cpp
     index 4dc8b45..19892dd 100644
     --- a/media/libeffects/lvm/wrapper/Reverb/EffectReverb.cpp
    @@ -1698,6 +325,67 @@ index 51c9938..5ad39fe 100644
          }
      
          virtual status_t getSize(off64_t* size) {
    +diff --git a/media/libmedia/IDrm.cpp b/media/libmedia/IDrm.cpp
    +index 51a1130..393286d 100644
    +--- a/media/libmedia/IDrm.cpp
    ++++ b/media/libmedia/IDrm.cpp
    +@@ -559,8 +559,13 @@ IMPLEMENT_META_INTERFACE(Drm, "android.drm.IDrm");
    + 
    + void BnDrm::readVector(const Parcel &data, Vector<uint8_t> &vector) const {
    +     uint32_t size = data.readInt32();
    +-    vector.insertAt((size_t)0, size);
    +-    data.read(vector.editArray(), size);
    ++    if (vector.insertAt((size_t)0, size) < 0) {
    ++        vector.clear();
    ++    }
    ++    if (data.read(vector.editArray(), size) != NO_ERROR) {
    ++        vector.clear();
    ++        android_errorWriteWithInfoLog(0x534e4554, "62872384", -1, NULL, 0);
    ++    }
    + }
    + 
    + void BnDrm::writeVector(Parcel *reply, Vector<uint8_t> const &vector) const {
    +diff --git a/media/libmedia/IMediaExtractor.cpp b/media/libmedia/IMediaExtractor.cpp
    +index 72d1d7c..4be1118 100644
    +--- a/media/libmedia/IMediaExtractor.cpp
    ++++ b/media/libmedia/IMediaExtractor.cpp
    +@@ -209,11 +209,16 @@ String8 ExtractorInstance::toString() const {
    +     for (size_t i = 0; i < tracks.size(); i++) {
    +         const String8 desc = trackDescriptions.itemAt(i);
    +         str.appendFormat("    track {%s} ", desc.string());
    +-        const sp<IMediaSource> source = tracks.itemAt(i).promote();
    +-        if (source == NULL) {
    +-            str.append(": deleted\n");
    ++        wp<IMediaSource> wSource = tracks.itemAt(i);
    ++        if (wSource == NULL) {
    ++            str.append(": null\n");
    +         } else {
    +-            str.appendFormat(": active\n");
    ++            const sp<IMediaSource> source = wSource.promote();
    ++            if (source == NULL) {
    ++                str.append(": deleted\n");
    ++            } else {
    ++                str.appendFormat(": active\n");
    ++            }
    +         }
    +     }
    +     return str;
    +@@ -232,9 +237,14 @@ void registerMediaSource(
    +         if (extractor != NULL && extractor == ex) {
    +             if (instance.tracks.size() > 5) {
    +                 instance.tracks.resize(5);
    ++                instance.trackDescriptions.resize(5);
    +             }
    +             instance.tracks.push_front(source);
    +-            instance.trackDescriptions.add(source->getFormat()->toString());
    ++            if (source != NULL) {
    ++                instance.trackDescriptions.push_front(source->getFormat()->toString());
    ++            } else {
    ++                instance.trackDescriptions.push_front(String8::empty());
    ++            }
    +             break;
    +         }
    +     }
     diff --git a/media/libmediaplayerservice/MediaPlayerService.cpp b/media/libmediaplayerservice/MediaPlayerService.cpp
     index bd16e91..6e689e6 100644
     --- a/media/libmediaplayerservice/MediaPlayerService.cpp
    @@ -1813,6 +501,22 @@ index dc4e5d4..b64d899 100644
      }
      
      void NuPlayer::determineAudioModeChange(const sp<AMessage> &audioFormat) {
    +diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp b/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp
    +index 594128c..caaa735 100644
    +--- a/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp
    ++++ b/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp
    +@@ -631,6 +631,11 @@ bool NuPlayer::Decoder::handleAnOutputBuffer(
    +     sp<ABuffer> buffer;
    +     mCodec->getOutputBuffer(index, &buffer);
    + 
    ++    if (buffer == NULL) {
    ++        handleError(UNKNOWN_ERROR);
    ++        return false;
    ++    }
    ++
    +     if (index >= mOutputBuffers.size()) {
    +         for (size_t i = mOutputBuffers.size(); i <= index; ++i) {
    +             mOutputBuffers.add();
     diff --git a/media/libstagefright/ACodec.cpp b/media/libstagefright/ACodec.cpp
     index 37fd5a5..337fb2d 100644
     --- a/media/libstagefright/ACodec.cpp
    @@ -2050,7 +754,7 @@ index 893da89..2152454 100644
          // buffer queue.
          switch (mVideoBufferMode) {
     diff --git a/media/libstagefright/MPEG4Extractor.cpp b/media/libstagefright/MPEG4Extractor.cpp
    -index 5441714..4a33e7a 100644
    +index 5441714..2037923 100644
     --- a/media/libstagefright/MPEG4Extractor.cpp
     +++ b/media/libstagefright/MPEG4Extractor.cpp
     @@ -72,6 +72,7 @@ public:
    @@ -2136,6 +840,15 @@ index 5441714..4a33e7a 100644
                  }
      
                  *offset += chunk_size;
    +@@ -2906,7 +2922,7 @@ status_t MPEG4Extractor::parseColorInfo(off64_t offset, size_t size) {
    + 
    +     int32_t type = U32_AT(&buffer[0]);
    +     if ((type == FOURCC('n', 'c', 'l', 'x') && size >= 11)
    +-            || (type == FOURCC('n', 'c', 'l', 'c' && size >= 10))) {
    ++            || (type == FOURCC('n', 'c', 'l', 'c') && size >= 10)) {
    +         int32_t primaries = U16_AT(&buffer[4]);
    +         int32_t transfer = U16_AT(&buffer[6]);
    +         int32_t coeffs = U16_AT(&buffer[8]);
     @@ -2984,6 +3000,13 @@ status_t MPEG4Extractor::parse3GPPMetaData(off64_t offset, size_t size, int dept
              }
              case FOURCC('y', 'r', 'r', 'c'):
    @@ -2235,7 +948,16 @@ index 5441714..4a33e7a 100644
                          }
                          *offset += chunk_size;
                      }
    -@@ -4651,17 +4707,25 @@ status_t MPEG4Source::fragmentedRead(
    +@@ -4431,6 +4487,8 @@ status_t MPEG4Source::read(
    +         }
    +         if (size > mBuffer->size()) {
    +             ALOGE("buffer too small: %zu > %zu", size, mBuffer->size());
    ++            mBuffer->release();
    ++            mBuffer = NULL;
    +             return ERROR_BUFFER_TOO_SMALL;
    +         }
    +     }
    +@@ -4651,17 +4709,25 @@ status_t MPEG4Source::fragmentedRead(
                      totalOffset += se->mSize;
                  }
                  mCurrentMoofOffset = totalOffset;
    @@ -2263,7 +985,7 @@ index 5441714..4a33e7a 100644
                  mCurrentTime = 0;
              }
      
    -@@ -4690,7 +4754,10 @@ status_t MPEG4Source::fragmentedRead(
    +@@ -4690,7 +4756,10 @@ status_t MPEG4Source::fragmentedRead(
                  mCurrentMoofOffset = nextMoof;
                  mCurrentSamples.clear();
                  mCurrentSampleIndex = 0;
    @@ -2275,6 +997,15 @@ index 5441714..4a33e7a 100644
                  if (mCurrentSampleIndex >= mCurrentSamples.size()) {
                      return ERROR_END_OF_STREAM;
                  }
    +@@ -4712,6 +4781,8 @@ status_t MPEG4Source::fragmentedRead(
    +         }
    +         if (size > mBuffer->size()) {
    +             ALOGE("buffer too small: %zu > %zu", size, mBuffer->size());
    ++            mBuffer->release();
    ++            mBuffer = NULL;
    +             return ERROR_BUFFER_TOO_SMALL;
    +         }
    +     }
     diff --git a/media/libstagefright/MediaCodecList.cpp b/media/libstagefright/MediaCodecList.cpp
     index 0fb5072..a25c47d 100644
     --- a/media/libstagefright/MediaCodecList.cpp
    @@ -2305,6 +1036,21 @@ index a17757a..f1ad5c5 100644
     +}
     +}
      }  // namespace android
    +diff --git a/media/libstagefright/NuMediaExtractor.cpp b/media/libstagefright/NuMediaExtractor.cpp
    +index 4558b3c..c3e8f20 100644
    +--- a/media/libstagefright/NuMediaExtractor.cpp
    ++++ b/media/libstagefright/NuMediaExtractor.cpp
    +@@ -305,6 +305,10 @@ status_t NuMediaExtractor::selectTrack(size_t index) {
    + 
    +     sp<IMediaSource> source = mImpl->getTrack(index);
    + 
    ++    if (source == nullptr) {
    ++        return ERROR_MALFORMED;
    ++    }
    ++
    +     status_t ret = source->start();
    +     if (ret != OK) {
    +         return ret;
     diff --git a/media/libstagefright/OggExtractor.cpp b/media/libstagefright/OggExtractor.cpp
     index ebbe510..752f2fe 100644
     --- a/media/libstagefright/OggExtractor.cpp
    @@ -2545,6 +1291,19 @@ index f1b81e1..123fd25 100644
          int64_t mInputTimeUs;
      
          bool mSawInputEOS;
    +diff --git a/media/libstagefright/codecs/m4v_h263/dec/src/vlc_decode.cpp b/media/libstagefright/codecs/m4v_h263/dec/src/vlc_decode.cpp
    +index f7192b1c..7202f98 100644
    +--- a/media/libstagefright/codecs/m4v_h263/dec/src/vlc_decode.cpp
    ++++ b/media/libstagefright/codecs/m4v_h263/dec/src/vlc_decode.cpp
    +@@ -560,7 +560,7 @@ int PV_VlcDecMCBPC_com_inter_H263(BitstreamDecVideo *stream)
    + 
    +     BitstreamShow13Bits(stream, &code);
    + 
    +-    if (code == 0)
    ++    if (code < 8)
    +     {
    +         return VLC_CODE_ERROR;
    +     }
     diff --git a/media/libstagefright/codecs/mpeg2dec/SoftMPEG2.cpp b/media/libstagefright/codecs/mpeg2dec/SoftMPEG2.cpp
     index 5ed037a..7297f40 100644
     --- a/media/libstagefright/codecs/mpeg2dec/SoftMPEG2.cpp
    @@ -3129,7 +1888,7 @@ index 6132a2c..7f0d270 100644
      
      void OMXMaster::addPlugin(const char *libname) {
     diff --git a/media/libstagefright/omx/OMXNodeInstance.cpp b/media/libstagefright/omx/OMXNodeInstance.cpp
    -index e7aaead..a0a746e 100644
    +index e7aaead..f60a79c 100644
     --- a/media/libstagefright/omx/OMXNodeInstance.cpp
     +++ b/media/libstagefright/omx/OMXNodeInstance.cpp
     @@ -226,6 +226,8 @@ OMXNodeInstance::OMXNodeInstance(
    @@ -3141,7 +1900,16 @@ index e7aaead..a0a746e 100644
          mIsSecure = AString(name).endsWith(".secure");
      }
      
    -@@ -562,6 +564,12 @@ status_t OMXNodeInstance::enableNativeBuffers(
    +@@ -351,6 +353,8 @@ status_t OMXNodeInstance::freeNode(OMXMaster *master) {
    +             break;
    +     }
    + 
    ++    Mutex::Autolock _l(mLock);
    ++
    +     ALOGV("[%x:%s] calling destroyComponentInstance", mNodeID, mName);
    +     OMX_ERRORTYPE err = master->destroyComponentInstance(
    +             static_cast<OMX_COMPONENTTYPE *>(mHandle));
    +@@ -562,6 +566,12 @@ status_t OMXNodeInstance::enableNativeBuffers(
                  } else if (mSecureBufferType[portIndex] == kSecureBufferTypeUnknown) {
                      mSecureBufferType[portIndex] = kSecureBufferTypeOpaque;
                  }
    @@ -3154,7 +1922,17 @@ index e7aaead..a0a746e 100644
              }
          } else {
              CLOG_ERROR_IF(enable, getExtensionIndex, err, "%s", name);
    -@@ -801,7 +809,11 @@ status_t OMXNodeInstance::useBuffer(
    +@@ -798,10 +808,21 @@ status_t OMXNodeInstance::useBuffer(
    +         return BAD_VALUE;
    +     }
    + 
    ++    if (mMetadataType[portIndex] == kMetadataBufferTypeInvalid
    ++            && mGraphicBufferEnabled[portIndex]) {
    ++        ALOGE("b/62948670");
    ++        android_errorWriteLog(0x534e4554, "62948670");
    ++        return INVALID_OPERATION;
    ++    }
    ++
          // metadata buffers are not connected cross process
          // use a backup buffer instead of the actual buffer
          BufferMeta *buffer_meta;
    @@ -3166,9 +1944,43 @@ index e7aaead..a0a746e 100644
          OMX_U8 *data = static_cast<OMX_U8 *>(params->pointer());
          // allocate backup buffer
          if (useBackup) {
    -@@ -1297,7 +1309,11 @@ status_t OMXNodeInstance::allocateBufferWithBackup(
    +@@ -916,6 +937,13 @@ status_t OMXNodeInstance::useGraphicBuffer(
    +         return BAD_VALUE;
    +     }
    +     Mutex::Autolock autoLock(mLock);
    ++    if (!mGraphicBufferEnabled[portIndex]
    ++            || mMetadataType[portIndex] != kMetadataBufferTypeInvalid) {
    ++        // Report error if this is not in graphic buffer mode.
    ++        ALOGE("b/62948670");
    ++        android_errorWriteLog(0x534e4554, "62948670");
    ++        return INVALID_OPERATION;
    ++    }
    + 
    +     // See if the newer version of the extension is present.
    +     OMX_INDEXTYPE index;
    +@@ -1235,6 +1263,12 @@ status_t OMXNodeInstance::allocateSecureBuffer(
    +         return BAD_VALUE;
    +     }
    + 
    ++    if (mSecureBufferType[portIndex] == kSecureBufferTypeUnknown) {
    ++        ALOGE("b/63522818");
    ++        android_errorWriteLog(0x534e4554, "63522818");
    ++        return ERROR_UNSUPPORTED;
    ++    }
    ++
    +     BufferMeta *buffer_meta = new BufferMeta(size, portIndex);
    + 
    +     OMX_BUFFERHEADERTYPE *header;
    +@@ -1296,8 +1330,18 @@ status_t OMXNodeInstance::allocateBufferWithBackup(
    +         return BAD_VALUE;
          }
      
    ++    if (mSecureBufferType[portIndex] != kSecureBufferTypeUnknown) {
    ++        ALOGE("b/63522818");
    ++        android_errorWriteLog(0x534e4554, "63522818");
    ++        return ERROR_UNSUPPORTED;
    ++    }
    ++
          // metadata buffers are not connected cross process; only copy if not meta
     +#ifdef CAMCORDER_GRALLOC_SOURCE
     +    bool copy = true;
    @@ -3178,7 +1990,7 @@ index e7aaead..a0a746e 100644
      
          BufferMeta *buffer_meta = new BufferMeta(
                  params, portIndex,
    -@@ -1415,10 +1431,30 @@ status_t OMXNodeInstance::emptyBuffer(
    +@@ -1415,10 +1459,30 @@ status_t OMXNodeInstance::emptyBuffer(
          BufferMeta *buffer_meta =
              static_cast<BufferMeta *>(header->pAppPrivate);
      
    @@ -5613,7 +4425,7 @@ index 3e5bb7d..2ecd6b1 100644
                  }
                  sources.add(source);
     diff --git a/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp b/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp
    -index a75e3dd..67bacd1 100644
    +index a75e3dd..cf81d9a 100644
     --- a/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp
     +++ b/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp
     @@ -318,7 +318,7 @@ status_t AudioPolicyService::getInputForAttr(const audio_attributes_t *attr,
    @@ -5625,6 +4437,22 @@ index a75e3dd..67bacd1 100644
                          ALOGE("getInputForAttr() permission denied: capture not allowed");
                          status = PERMISSION_DENIED;
                      }
    +@@ -665,6 +665,7 @@ status_t AudioPolicyService::acquireSoundTriggerSession(audio_session_t *session
    +                                        audio_io_handle_t *ioHandle,
    +                                        audio_devices_t *device)
    + {
    ++    Mutex::Autolock _l(mLock);
    +     if (mAudioPolicyManager == NULL) {
    +         return NO_INIT;
    +     }
    +@@ -674,6 +675,7 @@ status_t AudioPolicyService::acquireSoundTriggerSession(audio_session_t *session
    + 
    + status_t AudioPolicyService::releaseSoundTriggerSession(audio_session_t session)
    + {
    ++    Mutex::Autolock _l(mLock);
    +     if (mAudioPolicyManager == NULL) {
    +         return NO_INIT;
    +     }
     diff --git a/services/camera/libcameraservice/Android.mk b/services/camera/libcameraservice/Android.mk
     index 8d7f71c..d98ad47 100644
     --- a/services/camera/libcameraservice/Android.mk
    @@ -5694,7 +4522,7 @@ index 266fb03..3c2b98a 100644
      
      status_t CameraClient::setVideoBufferMode(int32_t videoBufferMode) {
     diff --git a/services/soundtrigger/SoundTriggerHwService.cpp b/services/soundtrigger/SoundTriggerHwService.cpp
    -index eebc487..74d0c70 100644
    +index eebc487..9d98a30 100644
     --- a/services/soundtrigger/SoundTriggerHwService.cpp
     +++ b/services/soundtrigger/SoundTriggerHwService.cpp
     @@ -278,6 +278,37 @@ void SoundTriggerHwService::sendRecognitionEvent(struct sound_trigger_recognitio
    @@ -5735,3 +4563,151 @@ index eebc487..74d0c70 100644
           sp<IMemory> eventMemory = prepareRecognitionEvent_l(event);
           if (eventMemory == 0) {
               return;
    +@@ -505,6 +536,8 @@ void SoundTriggerHwService::Module::detach() {
    +     if (!captureHotwordAllowed()) {
    +         return;
    +     }
    ++    Vector<audio_session_t> releasedSessions;
    ++
    +     {
    +         AutoMutex lock(mLock);
    +         for (size_t i = 0; i < mModels.size(); i++) {
    +@@ -514,9 +547,16 @@ void SoundTriggerHwService::Module::detach() {
    +                 mHwDevice->stop_recognition(mHwDevice, model->mHandle);
    +             }
    +             mHwDevice->unload_sound_model(mHwDevice, model->mHandle);
    ++            releasedSessions.add(model->mCaptureSession);
    +         }
    +         mModels.clear();
    +     }
    ++
    ++    for (size_t i = 0; i < releasedSessions.size(); i++) {
    ++        // do not call AudioSystem methods with mLock held
    ++        AudioSystem::releaseSoundTriggerSession(releasedSessions[i]);
    ++    }
    ++
    +     if (mClient != 0) {
    +         IInterface::asBinder(mClient)->unlinkToDeath(this);
    +     }
    +@@ -558,33 +598,43 @@ status_t SoundTriggerHwService::Module::loadSoundModel(const sp<IMemory>& modelM
    +         return BAD_VALUE;
    +     }
    + 
    +-    AutoMutex lock(mLock);
    +-
    +-    if (mModels.size() >= mDescriptor.properties.max_sound_models) {
    +-        ALOGW("loadSoundModel(): Not loading, max number of models (%d) would be exceeded",
    +-              mDescriptor.properties.max_sound_models);
    +-        return INVALID_OPERATION;
    +-    }
    +-
    +-    status_t status = mHwDevice->load_sound_model(mHwDevice, sound_model,
    +-                                                  SoundTriggerHwService::soundModelCallback,
    +-                                                  this, handle);
    +-
    +-    if (status != NO_ERROR) {
    +-        return status;
    +-    }
    +     audio_session_t session;
    +     audio_io_handle_t ioHandle;
    +     audio_devices_t device;
    +-
    +-    status = AudioSystem::acquireSoundTriggerSession(&session, &ioHandle, &device);
    ++    // do not call AudioSystem methods with mLock held
    ++    status_t status = AudioSystem::acquireSoundTriggerSession(&session, &ioHandle, &device);
    +     if (status != NO_ERROR) {
    +         return status;
    +     }
    + 
    +-    sp<Model> model = new Model(*handle, session, ioHandle, device, sound_model->type);
    +-    mModels.replaceValueFor(*handle, model);
    ++    {
    ++        AutoMutex lock(mLock);
    ++
    ++        if (mModels.size() >= mDescriptor.properties.max_sound_models) {
    ++            ALOGW("loadSoundModel(): Not loading, max number of models (%d) would be exceeded",
    ++                  mDescriptor.properties.max_sound_models);
    ++            status = INVALID_OPERATION;
    ++            goto exit;
    ++        }
    + 
    ++        status_t status = mHwDevice->load_sound_model(mHwDevice,
    ++                                                      sound_model,
    ++                                                      SoundTriggerHwService::soundModelCallback,
    ++                                                      this,
    ++                                                      handle);
    ++        if (status != NO_ERROR) {
    ++            goto exit;
    ++        }
    ++
    ++        sp<Model> model = new Model(*handle, session, ioHandle, device, sound_model->type);
    ++        mModels.replaceValueFor(*handle, model);
    ++    }
    ++
    ++exit:
    ++    if (status != NO_ERROR) {
    ++        // do not call AudioSystem methods with mLock held
    ++        AudioSystem::releaseSoundTriggerSession(session);
    ++    }
    +     return status;
    + }
    + 
    +@@ -594,25 +644,26 @@ status_t SoundTriggerHwService::Module::unloadSoundModel(sound_model_handle_t ha
    +     if (!captureHotwordAllowed()) {
    +         return PERMISSION_DENIED;
    +     }
    ++    status_t status;
    ++    audio_session_t session;
    + 
    +-    AutoMutex lock(mLock);
    +-    return unloadSoundModel_l(handle);
    +-}
    +-
    +-status_t SoundTriggerHwService::Module::unloadSoundModel_l(sound_model_handle_t handle)
    +-{
    +-    ssize_t index = mModels.indexOfKey(handle);
    +-    if (index < 0) {
    +-        return BAD_VALUE;
    +-    }
    +-    sp<Model> model = mModels.valueAt(index);
    +-    mModels.removeItem(handle);
    +-    if (model->mState == Model::STATE_ACTIVE) {
    +-        mHwDevice->stop_recognition(mHwDevice, model->mHandle);
    +-        model->mState = Model::STATE_IDLE;
    +-    }
    +-    AudioSystem::releaseSoundTriggerSession(model->mCaptureSession);
    +-    return mHwDevice->unload_sound_model(mHwDevice, handle);
    ++    {
    ++      AutoMutex lock(mLock);
    ++      ssize_t index = mModels.indexOfKey(handle);
    ++      if (index < 0) {
    ++          return BAD_VALUE;
    ++      }
    ++      sp<Model> model = mModels.valueAt(index);
    ++      mModels.removeItem(handle);
    ++      if (model->mState == Model::STATE_ACTIVE) {
    ++          mHwDevice->stop_recognition(mHwDevice, model->mHandle);
    ++          model->mState = Model::STATE_IDLE;
    ++      }
    ++      status = mHwDevice->unload_sound_model(mHwDevice, handle);
    ++      session = model->mCaptureSession;
    ++    }
    ++    AudioSystem::releaseSoundTriggerSession(session);
    ++    return status;
    + }
    + 
    + status_t SoundTriggerHwService::Module::startRecognition(sound_model_handle_t handle,
    +diff --git a/services/soundtrigger/SoundTriggerHwService.h b/services/soundtrigger/SoundTriggerHwService.h
    +index 2619a5f..d05dacd 100644
    +--- a/services/soundtrigger/SoundTriggerHwService.h
    ++++ b/services/soundtrigger/SoundTriggerHwService.h
    +@@ -141,9 +141,6 @@ public:
    + 
    +     private:
    + 
    +-       status_t unloadSoundModel_l(sound_model_handle_t handle);
    +-
    +-
    +         Mutex                                  mLock;
    +         wp<SoundTriggerHwService>              mService;
    +         struct sound_trigger_hw_device*        mHwDevice;
    diff --git a/frameworks_base.patch b/frameworks_base.patch
    index 07c4014..cfb7f28 100644
    --- a/frameworks_base.patch
    +++ b/frameworks_base.patch
    @@ -232,6 +232,20 @@ index e4f573b..0d3f50c 100644
                  EGL14.eglGetDisplay(EGL14.EGL_DEFAULT_DISPLAY);
              }
          }
    +diff --git a/core/jni/android/graphics/BitmapFactory.cpp b/core/jni/android/graphics/BitmapFactory.cpp
    +index 4001283..0a14361 100644
    +--- a/core/jni/android/graphics/BitmapFactory.cpp
    ++++ b/core/jni/android/graphics/BitmapFactory.cpp
    +@@ -587,8 +587,7 @@ static jobject nativeDecodeFileDescriptor(JNIEnv* env, jobject clazz, jobject fi
    +         return nullObjectReturn("Could not open file");
    +     }
    + 
    +-    std::unique_ptr<SkFILEStream> fileStream(new SkFILEStream(file,
    +-            SkFILEStream::kCallerPasses_Ownership));
    ++    std::unique_ptr<SkFILEStream> fileStream(new SkFILEStream(file));
    + 
    +     // If there is no offset for the file descriptor, we use SkFILEStream directly.
    +     if (::lseek(descriptor, 0, SEEK_CUR) == 0) {
     diff --git a/core/jni/android_util_Binder.cpp b/core/jni/android_util_Binder.cpp
     index 5559d48..bee11db 100644
     --- a/core/jni/android_util_Binder.cpp
    @@ -373,6 +387,20 @@ index 2c9c9d9..7c187fb 100644
      }
      
      /**
    +diff --git a/media/jni/android_media_ExifInterface.cpp b/media/jni/android_media_ExifInterface.cpp
    +index 731deae..20f9ef6 100644
    +--- a/media/jni/android_media_ExifInterface.cpp
    ++++ b/media/jni/android_media_ExifInterface.cpp
    +@@ -390,8 +390,7 @@ static jobject ExifInterface_getRawAttributesFromFileDescriptor(
    +     // Rewind the file descriptor.
    +     fseek(file, 0L, SEEK_SET);
    + 
    +-    std::unique_ptr<SkFILEStream> fileStream(new SkFILEStream(file,
    +-                SkFILEStream::kCallerPasses_Ownership));
    ++    std::unique_ptr<SkFILEStream> fileStream(new SkFILEStream(file));
    +     return getRawAttributes(env, fileStream.get(), false);
    + }
    + 
     diff --git a/packages/SystemUI/res/values/config.xml b/packages/SystemUI/res/values/config.xml
     index 0fa9a85..925f368 100644
     --- a/packages/SystemUI/res/values/config.xml
    @@ -840,6 +868,21 @@ index 2693272..f2368ed 100644
                      // next check if it's better than any current network we're using for
                      // this request
                      if (VDBG) {
    +diff --git a/services/core/java/com/android/server/accounts/AccountManagerService.java b/services/core/java/com/android/server/accounts/AccountManagerService.java
    +index a7a79cd..a085b71 100644
    +--- a/services/core/java/com/android/server/accounts/AccountManagerService.java
    ++++ b/services/core/java/com/android/server/accounts/AccountManagerService.java
    +@@ -4184,6 +4184,10 @@ public class AccountManagerService
    +         protected void checkKeyIntent(
    +                 int authUid,
    +                 Intent intent) throws SecurityException {
    ++            intent.setFlags(intent.getFlags() & ~(Intent.FLAG_GRANT_READ_URI_PERMISSION
    ++                    | Intent.FLAG_GRANT_WRITE_URI_PERMISSION
    ++                    | Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION
    ++                    | Intent.FLAG_GRANT_PREFIX_URI_PERMISSION));
    +             long bid = Binder.clearCallingIdentity();
    +             try {
    +                 PackageManager pm = mContext.getPackageManager();
     diff --git a/services/core/java/com/android/server/am/ActivityStackSupervisor.java b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
     index c6ab918..d848081 100644
     --- a/services/core/java/com/android/server/am/ActivityStackSupervisor.java
    @@ -864,6 +907,201 @@ index c6ab918..d848081 100644
              if (mService.mShuttingDown) {
                  mService.notifyAll();
              }
    +diff --git a/services/core/java/com/android/server/clipboard/ClipboardService.java b/services/core/java/com/android/server/clipboard/ClipboardService.java
    +index 66aa403..bdd2d2b 100644
    +--- a/services/core/java/com/android/server/clipboard/ClipboardService.java
    ++++ b/services/core/java/com/android/server/clipboard/ClipboardService.java
    +@@ -20,6 +20,7 @@ import android.app.ActivityManagerNative;
    + import android.app.AppGlobals;
    + import android.app.AppOpsManager;
    + import android.app.IActivityManager;
    ++import android.app.KeyguardManager;
    + import android.content.BroadcastReceiver;
    + import android.content.ClipData;
    + import android.content.ClipDescription;
    +@@ -255,7 +256,7 @@ public class ClipboardService extends IClipboard.Stub {
    +     public ClipData getPrimaryClip(String pkg) {
    +         synchronized (this) {
    +             if (mAppOps.noteOp(AppOpsManager.OP_READ_CLIPBOARD, Binder.getCallingUid(),
    +-                    pkg) != AppOpsManager.MODE_ALLOWED) {
    ++                    pkg) != AppOpsManager.MODE_ALLOWED || isDeviceLocked()) {
    +                 return null;
    +             }
    +             addActiveOwnerLocked(Binder.getCallingUid(), pkg);
    +@@ -266,7 +267,7 @@ public class ClipboardService extends IClipboard.Stub {
    +     public ClipDescription getPrimaryClipDescription(String callingPackage) {
    +         synchronized (this) {
    +             if (mAppOps.checkOp(AppOpsManager.OP_READ_CLIPBOARD, Binder.getCallingUid(),
    +-                    callingPackage) != AppOpsManager.MODE_ALLOWED) {
    ++                    callingPackage) != AppOpsManager.MODE_ALLOWED || isDeviceLocked()) {
    +                 return null;
    +             }
    +             PerUserClipboard clipboard = getClipboard();
    +@@ -277,7 +278,7 @@ public class ClipboardService extends IClipboard.Stub {
    +     public boolean hasPrimaryClip(String callingPackage) {
    +         synchronized (this) {
    +             if (mAppOps.checkOp(AppOpsManager.OP_READ_CLIPBOARD, Binder.getCallingUid(),
    +-                    callingPackage) != AppOpsManager.MODE_ALLOWED) {
    ++                    callingPackage) != AppOpsManager.MODE_ALLOWED || isDeviceLocked()) {
    +                 return false;
    +             }
    +             return getClipboard().primaryClip != null;
    +@@ -301,7 +302,7 @@ public class ClipboardService extends IClipboard.Stub {
    +     public boolean hasClipboardText(String callingPackage) {
    +         synchronized (this) {
    +             if (mAppOps.checkOp(AppOpsManager.OP_READ_CLIPBOARD, Binder.getCallingUid(),
    +-                    callingPackage) != AppOpsManager.MODE_ALLOWED) {
    ++                    callingPackage) != AppOpsManager.MODE_ALLOWED || isDeviceLocked()) {
    +                 return false;
    +             }
    +             PerUserClipboard clipboard = getClipboard();
    +@@ -313,6 +314,11 @@ public class ClipboardService extends IClipboard.Stub {
    +         }
    +     }
    + 
    ++    private boolean isDeviceLocked() {
    ++        final KeyguardManager keyguardManager = mContext.getSystemService(KeyguardManager.class);
    ++        return keyguardManager != null && keyguardManager.isDeviceLocked();
    ++    }
    ++
    +     private final void checkUriOwnerLocked(Uri uri, int uid) {
    +         if (!"content".equals(uri.getScheme())) {
    +             return;
    +diff --git a/services/core/java/com/android/server/content/SyncStorageEngine.java b/services/core/java/com/android/server/content/SyncStorageEngine.java
    +index 069ae73..f804fa1 100644
    +--- a/services/core/java/com/android/server/content/SyncStorageEngine.java
    ++++ b/services/core/java/com/android/server/content/SyncStorageEngine.java
    +@@ -18,6 +18,7 @@ package com.android.server.content;
    + 
    + import android.accounts.Account;
    + import android.accounts.AccountAndUser;
    ++import android.accounts.AccountManager;
    + import android.app.backup.BackupManager;
    + import android.content.ComponentName;
    + import android.content.ContentResolver;
    +@@ -27,6 +28,7 @@ import android.content.PeriodicSync;
    + import android.content.SyncInfo;
    + import android.content.SyncRequest;
    + import android.content.SyncStatusInfo;
    ++import android.content.pm.PackageManager;
    + import android.database.Cursor;
    + import android.database.sqlite.SQLiteDatabase;
    + import android.database.sqlite.SQLiteException;
    +@@ -350,6 +352,50 @@ public class SyncStorageEngine extends Handler {
    +         void onAuthorityRemoved(EndPoint removedAuthority);
    +     }
    + 
    ++    /**
    ++     * Validator that maintains a lazy cache of accounts and providers to tell if an authority or
    ++     * account is valid.
    ++     */
    ++    private static class AccountAuthorityValidator {
    ++        final private AccountManager mAccountManager;
    ++        final private PackageManager mPackageManager;
    ++        final private SparseArray<Account[]> mAccountsCache;
    ++        final private SparseArray<ArrayMap<String, Boolean>> mProvidersPerUserCache;
    ++
    ++        AccountAuthorityValidator(Context context) {
    ++            mAccountManager = context.getSystemService(AccountManager.class);
    ++            mPackageManager = context.getPackageManager();
    ++            mAccountsCache = new SparseArray<>();
    ++            mProvidersPerUserCache = new SparseArray<>();
    ++        }
    ++
    ++        // An account is valid if an installed authenticator has previously created that account
    ++        // on the device
    ++        boolean isAccountValid(Account account, int userId) {
    ++            Account[] accountsForUser = mAccountsCache.get(userId);
    ++            if (accountsForUser == null) {
    ++                accountsForUser = mAccountManager.getAccountsAsUser(userId);
    ++                mAccountsCache.put(userId, accountsForUser);
    ++            }
    ++            return ArrayUtils.contains(accountsForUser, account);
    ++        }
    ++
    ++        // An authority is only valid if it has a content provider installed on the system
    ++        boolean isAuthorityValid(String authority, int userId) {
    ++            ArrayMap<String, Boolean> authorityMap = mProvidersPerUserCache.get(userId);
    ++            if (authorityMap == null) {
    ++                authorityMap = new ArrayMap<>();
    ++                mProvidersPerUserCache.put(userId, authorityMap);
    ++            }
    ++            if (!authorityMap.containsKey(authority)) {
    ++                authorityMap.put(authority, mPackageManager.resolveContentProviderAsUser(authority,
    ++                        PackageManager.MATCH_DIRECT_BOOT_AWARE
    ++                                | PackageManager.MATCH_DIRECT_BOOT_UNAWARE, userId) != null);
    ++            }
    ++            return authorityMap.get(authority);
    ++        }
    ++    }
    ++
    +     // Primary list of all syncable authorities.  Also our global lock.
    +     private final SparseArray<AuthorityInfo> mAuthorities =
    +             new SparseArray<AuthorityInfo>();
    +@@ -1502,12 +1548,13 @@ public class SyncStorageEngine extends Handler {
    +                 eventType = parser.next();
    +                 AuthorityInfo authority = null;
    +                 PeriodicSync periodicSync = null;
    ++                AccountAuthorityValidator validator = new AccountAuthorityValidator(mContext);
    +                 do {
    +                     if (eventType == XmlPullParser.START_TAG) {
    +                         tagName = parser.getName();
    +                         if (parser.getDepth() == 2) {
    +                             if ("authority".equals(tagName)) {
    +-                                authority = parseAuthority(parser, version);
    ++                                authority = parseAuthority(parser, version, validator);
    +                                 periodicSync = null;
    +                                 if (authority != null) {
    +                                     if (authority.ident > highestAuthorityId) {
    +@@ -1636,7 +1683,8 @@ public class SyncStorageEngine extends Handler {
    +         mMasterSyncAutomatically.put(userId, listen);
    +     }
    + 
    +-    private AuthorityInfo parseAuthority(XmlPullParser parser, int version) {
    ++    private AuthorityInfo parseAuthority(XmlPullParser parser, int version,
    ++            AccountAuthorityValidator validator) {
    +         AuthorityInfo authority = null;
    +         int id = -1;
    +         try {
    +@@ -1676,21 +1724,26 @@ public class SyncStorageEngine extends Handler {
    +                 if (Log.isLoggable(TAG_FILE, Log.VERBOSE)) {
    +                     Slog.v(TAG_FILE, "Creating authority entry");
    +                 }
    +-                EndPoint info = null;
    +                 if (accountName != null && authorityName != null) {
    +-                    info = new EndPoint(
    ++                    EndPoint info = new EndPoint(
    +                             new Account(accountName, accountType),
    +                             authorityName, userId);
    +-                }
    +-                if (info != null) {
    +-                    authority = getOrCreateAuthorityLocked(info, id, false);
    +-                    // If the version is 0 then we are upgrading from a file format that did not
    +-                    // know about periodic syncs. In that case don't clear the list since we
    +-                    // want the default, which is a daily periodic sync.
    +-                    // Otherwise clear out this default list since we will populate it later with
    +-                    // the periodic sync descriptions that are read from the configuration file.
    +-                    if (version > 0) {
    +-                        authority.periodicSyncs.clear();
    ++                    if (validator.isAccountValid(info.account, userId)
    ++                            && validator.isAuthorityValid(authorityName, userId)) {
    ++                        authority = getOrCreateAuthorityLocked(info, id, false);
    ++                        // If the version is 0 then we are upgrading from a file format that did not
    ++                        // know about periodic syncs. In that case don't clear the list since we
    ++                        // want the default, which is a daily periodic sync.
    ++                        // Otherwise clear out this default list since we will populate it later
    ++                        // with
    ++                        // the periodic sync descriptions that are read from the configuration file.
    ++                        if (version > 0) {
    ++                            authority.periodicSyncs.clear();
    ++                        }
    ++                    } else {
    ++                        EventLog.writeEvent(0x534e4554, "35028827", -1,
    ++                                "account:" + info.account + " provider:" + authorityName + " user:"
    ++                                        + userId);
    +                     }
    +                 }
    +             }
     diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
     index b6a9940..11b5832a 100644
     --- a/services/core/java/com/android/server/pm/PackageManagerService.java
    diff --git a/frameworks_minikin.patch b/frameworks_minikin.patch
    index 531f80b..f0c3eef 100644
    --- a/frameworks_minikin.patch
    +++ b/frameworks_minikin.patch
    @@ -1,8 +1,17 @@
     diff --git a/libs/minikin/CmapCoverage.cpp b/libs/minikin/CmapCoverage.cpp
    -index 2961d2f..c02526c 100644
    +index 2961d2f..da1cf3e 100644
     --- a/libs/minikin/CmapCoverage.cpp
     +++ b/libs/minikin/CmapCoverage.cpp
    -@@ -37,15 +37,25 @@ static uint32_t readU32(const uint8_t* data, size_t offset) {
    +@@ -25,6 +25,8 @@ using std::vector;
    + #include <minikin/SparseBitSet.h>
    + #include <minikin/CmapCoverage.h>
    + 
    ++#include "MinikinInternal.h"
    ++
    + namespace android {
    + 
    + // These could perhaps be optimized to use __builtin_bswap16 and friends.
    +@@ -37,15 +39,25 @@ static uint32_t readU32(const uint8_t* data, size_t offset) {
              ((uint32_t)data[offset + 2]) << 8 | ((uint32_t)data[offset + 3]);
      }
      
    @@ -30,7 +39,7 @@ index 2961d2f..c02526c 100644
          }
      }
      
    -@@ -74,11 +84,15 @@ static bool getCoverageFormat4(vector<uint32_t>& coverage, const uint8_t* data,
    +@@ -74,11 +86,15 @@ static bool getCoverageFormat4(vector<uint32_t>& coverage, const uint8_t* data,
              if (rangeOffset == 0) {
                  uint32_t delta = readU16(data, kHeaderSize + 2 * (2 * segCount + i));
                  if (((end + delta) & 0xffff) > end - start) {
    @@ -48,7 +57,7 @@ index 2961d2f..c02526c 100644
                          }
                      }
                  }
    -@@ -92,7 +106,9 @@ static bool getCoverageFormat4(vector<uint32_t>& coverage, const uint8_t* data,
    +@@ -92,7 +108,9 @@ static bool getCoverageFormat4(vector<uint32_t>& coverage, const uint8_t* data,
                      }
                      uint32_t glyphId = readU16(data, actualRangeOffset);
                      if (glyphId != 0) {
    @@ -59,14 +68,40 @@ index 2961d2f..c02526c 100644
                      }
                  }
              }
    -@@ -126,7 +142,9 @@ static bool getCoverageFormat12(vector<uint32_t>& coverage, const uint8_t* data,
    +@@ -126,7 +144,22 @@ static bool getCoverageFormat12(vector<uint32_t>& coverage, const uint8_t* data,
                  android_errorWriteLog(0x534e4554, "26413177");
                  return false;
              }
     -        addRange(coverage, start, end + 1);  // file is inclusive, vector is exclusive
    ++
    ++        // No need to read outside of Unicode code point range.
    ++        if (start > MAX_UNICODE_CODE_POINT) {
    ++            return true;
    ++        }
    ++        if (end > MAX_UNICODE_CODE_POINT) {
    ++            // file is inclusive, vector is exclusive
    ++            addRange(coverage, start, MAX_UNICODE_CODE_POINT + 1);
    ++            if (end == 0xFFFFFFFF) {
    ++                android_errorWriteLog(0x534e4554, "62134807");
    ++            }
    ++            return true;
    ++        }
     +        if (!addRange(coverage, start, end + 1)) {  // file is inclusive, vector is exclusive
     +            return false;
     +        }
          }
          return true;
      }
    +diff --git a/libs/minikin/MinikinInternal.h b/libs/minikin/MinikinInternal.h
    +index 88cc947..c6c5b29 100644
    +--- a/libs/minikin/MinikinInternal.h
    ++++ b/libs/minikin/MinikinInternal.h
    +@@ -47,6 +47,8 @@ bool isEmojiModifier(uint32_t c);
    + 
    + hb_blob_t* getFontTable(MinikinFont* minikinFont, uint32_t tag);
    + 
    ++constexpr uint32_t MAX_UNICODE_CODE_POINT = 0x10FFFF;
    ++
    + // An RAII wrapper for hb_blob_t
    + class HbBlob {
    + public:
    diff --git a/packages_apps_settings.patch b/packages_apps_settings.patch
    index db57824..f64357e 100644
    --- a/packages_apps_settings.patch
    +++ b/packages_apps_settings.patch
    @@ -10,6 +10,90 @@ index 2ec976d..c155cf7 100644
      
          <application android:label="@string/settings_label"
                  android:icon="@mipmap/ic_launcher_settings"
    +diff --git a/src/com/android/settings/ActivityPicker.java b/src/com/android/settings/ActivityPicker.java
    +index 2c3436f..ae61944 100644
    +--- a/src/com/android/settings/ActivityPicker.java
    ++++ b/src/com/android/settings/ActivityPicker.java
    +@@ -78,6 +78,10 @@ public class ActivityPicker extends AlertActivity implements
    +         Parcelable parcel = intent.getParcelableExtra(Intent.EXTRA_INTENT);
    +         if (parcel instanceof Intent) {
    +             mBaseIntent = (Intent) parcel;
    ++            mBaseIntent.setFlags(mBaseIntent.getFlags() & ~(Intent.FLAG_GRANT_READ_URI_PERMISSION
    ++                    | Intent.FLAG_GRANT_WRITE_URI_PERMISSION
    ++                    | Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION
    ++                    | Intent.FLAG_GRANT_PREFIX_URI_PERMISSION));
    +         } else {
    +             mBaseIntent = new Intent(Intent.ACTION_MAIN, null);
    +             mBaseIntent.addCategory(Intent.CATEGORY_DEFAULT);
    +diff --git a/src/com/android/settings/DeviceAdminAdd.java b/src/com/android/settings/DeviceAdminAdd.java
    +index 9d4d895..2f6afd7 100644
    +--- a/src/com/android/settings/DeviceAdminAdd.java
    ++++ b/src/com/android/settings/DeviceAdminAdd.java
    +@@ -16,6 +16,8 @@
    + 
    + package com.android.settings;
    + 
    ++import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS;
    ++
    + import android.app.Activity;
    + import android.app.ActivityManagerNative;
    + import android.app.AlertDialog;
    +@@ -88,7 +90,6 @@ public class DeviceAdminAdd extends Activity {
    +     Handler mHandler;
    + 
    +     DevicePolicyManager mDPM;
    +-    AppOpsManager mAppOps;
    +     DeviceAdminInfo mDeviceAdmin;
    +     CharSequence mAddMsgText;
    +     String mProfileOwnerName;
    +@@ -113,19 +114,17 @@ public class DeviceAdminAdd extends Activity {
    +     boolean mWaitingForRemoveMsg;
    +     boolean mAddingProfileOwner;
    +     boolean mAdminPoliciesInitialized;
    +-    int mCurSysAppOpMode;
    +-    int mCurToastAppOpMode;
    + 
    +     boolean mIsCalledFromSupportDialog = false;
    + 
    +     @Override
    +     protected void onCreate(Bundle icicle) {
    +         super.onCreate(icicle);
    ++        getWindow().addPrivateFlags(PRIVATE_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS);
    + 
    +         mHandler = new Handler(getMainLooper());
    + 
    +         mDPM = (DevicePolicyManager)getSystemService(Context.DEVICE_POLICY_SERVICE);
    +-        mAppOps = (AppOpsManager)getSystemService(Context.APP_OPS_SERVICE);
    +         PackageManager packageManager = getPackageManager();
    + 
    +         if ((getIntent().getFlags()&Intent.FLAG_ACTIVITY_NEW_TASK) != 0) {
    +@@ -447,24 +446,14 @@ public class DeviceAdminAdd extends Activity {
    +     @Override
    +     protected void onResume() {
    +         super.onResume();
    ++        mActionButton.setEnabled(true);
    +         updateInterface();
    +-        // As long as we are running, don't let this admin overlay stuff on top of the screen.
    +-        final int uid = mDeviceAdmin.getActivityInfo().applicationInfo.uid;
    +-        final String pkg = mDeviceAdmin.getActivityInfo().applicationInfo.packageName;
    +-        mCurSysAppOpMode = mAppOps.checkOp(AppOpsManager.OP_SYSTEM_ALERT_WINDOW, uid, pkg);
    +-        mCurToastAppOpMode = mAppOps.checkOp(AppOpsManager.OP_TOAST_WINDOW, uid, pkg);
    +-        mAppOps.setMode(AppOpsManager.OP_SYSTEM_ALERT_WINDOW, uid, pkg, AppOpsManager.MODE_IGNORED);
    +-        mAppOps.setMode(AppOpsManager.OP_TOAST_WINDOW, uid, pkg, AppOpsManager.MODE_IGNORED);
    +     }
    + 
    +     @Override
    +     protected void onPause() {
    +         super.onPause();
    +-        // As long as we are running, don't let this admin overlay stuff on top of the screen.
    +-        final int uid = mDeviceAdmin.getActivityInfo().applicationInfo.uid;
    +-        final String pkg = mDeviceAdmin.getActivityInfo().applicationInfo.packageName;
    +-        mAppOps.setMode(AppOpsManager.OP_SYSTEM_ALERT_WINDOW, uid, pkg, mCurSysAppOpMode);
    +-        mAppOps.setMode(AppOpsManager.OP_TOAST_WINDOW, uid, pkg, mCurToastAppOpMode);
    ++        mActionButton.setEnabled(false);
    +         try {
    +             ActivityManagerNative.getDefault().resumeAppSwitches();
    +         } catch (RemoteException e) {
     diff --git a/src/com/android/settings/accessibility/ToggleAccessibilityServicePreferenceFragment.java b/src/com/android/settings/accessibility/ToggleAccessibilityServicePreferenceFragment.java
     index 196a4ab..1f69768 100644
     --- a/src/com/android/settings/accessibility/ToggleAccessibilityServicePreferenceFragment.java
    diff --git a/system_bt.patch b/system_bt.patch
    index fb68cea..cb27095 100644
    --- a/system_bt.patch
    +++ b/system_bt.patch
    @@ -1,807 +1,60 @@
    +diff --git a/bta/gatt/bta_gattc_cache.c b/bta/gatt/bta_gattc_cache.c
    +index 63c4246..45d2588 100644
    +--- a/bta/gatt/bta_gattc_cache.c
    ++++ b/bta/gatt/bta_gattc_cache.c
    +@@ -1551,7 +1551,7 @@ bool bta_gattc_cache_load(tBTA_GATTC_CLCB *p_clcb)
    + 
    +     attr = osi_malloc(sizeof(tBTA_GATTC_NV_ATTR) * num_attr);
    + 
    +-    if (fread(attr, sizeof(tBTA_GATTC_NV_ATTR), 0xFF, fd) != num_attr) {
    ++    if (fread(attr, sizeof(tBTA_GATTC_NV_ATTR), num_attr, fd) != num_attr) {
    +         APPL_TRACE_ERROR("%s: can't read GATT attributes: %s", __func__, fname);
    +         goto done;
    +     }
     diff --git a/bta/pan/bta_pan_act.c b/bta/pan/bta_pan_act.c
    -index 1995478..b1678d8 100644
    +index 1995478..f80dca1 100644
     --- a/bta/pan/bta_pan_act.c
     +++ b/bta/pan/bta_pan_act.c
    -@@ -28,6 +28,8 @@
    +@@ -26,6 +26,8 @@
    + 
    + #if defined(PAN_INCLUDED) && (PAN_INCLUDED == TRUE)
      
    - #include "bta_api.h"
    - #include "bta_sys.h"
     +#include <cutils/log.h>
     +
    + #include "bta_api.h"
    + #include "bta_sys.h"
      #include "bt_common.h"
    - #include "pan_api.h"
    - #include "bta_pan_api.h"
     @@ -176,6 +178,14 @@ static void bta_pan_data_buf_ind_cback(UINT16 handle, BD_ADDR src, BD_ADDR dst,
      
          if (sizeof(tBTA_PAN_DATA_PARAMS) > p_buf->offset) {
              /* offset smaller than data structure in front of actual data */
     +        if (sizeof(BT_HDR) + sizeof(tBTA_PAN_DATA_PARAMS) + p_buf->len >
     +            PAN_BUF_SIZE) {
    -+          android_errorWriteLog(0x534e4554, "63146237");
    -+          APPL_TRACE_ERROR("%s: received buffer length too large: %d", __func__,
    -+                           p_buf->len);
    -+          osi_free(p_buf);
    -+          return;
    ++            android_errorWriteLog(0x534e4554, "63146237");
    ++            APPL_TRACE_ERROR("%s: received buffer length too large: %d", __func__,
    ++                             p_buf->len);
    ++            osi_free(p_buf);
    ++            return;
     +        }
              p_new_buf = (BT_HDR *)osi_malloc(PAN_BUF_SIZE);
              memcpy((UINT8 *)(p_new_buf + 1) + sizeof(tBTA_PAN_DATA_PARAMS),
                     (UINT8 *)(p_buf + 1) + p_buf->offset, p_buf->len);
    -diff --git a/btif/src/btif_sdp_server.cc b/btif/src/btif_sdp_server.cc
    -new file mode 100644
    -index 0000000..b84d694
    ---- /dev/null
    -+++ b/btif/src/btif_sdp_server.cc
    -@@ -0,0 +1,768 @@
    -+/******************************************************************************
    -+ *
    -+ * Copyright (C) 2014 Samsung System LSI
    -+ *
    -+ *  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.
    -+ *
    -+ ******************************************************************************/
    -+
    -+/*******************************************************************************
    -+ *
    -+ *  Filename:      btif_sdp_server.cc
    -+ *  Description:   SDP server Bluetooth Interface to create and remove SDP
    -+ *                 records.
    -+ *                 To be used in combination with the RFCOMM/L2CAP(LE) sockets.
    -+ *
    -+ *
    -+ ******************************************************************************/
    -+
    -+#define LOG_TAG "bt_btif_sdp_server"
    -+
    -+#include <pthread.h>
    -+#include <stdlib.h>
    -+#include <string.h>
    -+
    -+#include <mutex>
    -+
    -+#include <hardware/bluetooth.h>
    -+#include <hardware/bt_sdp.h>
    -+
    -+#include "bta_sdp_api.h"
    -+#include "bta_sys.h"
    -+#include "btif_common.h"
    -+#include "btif_sock_util.h"
    -+#include "btif_util.h"
    -+#include "osi/include/allocator.h"
    -+#include "utl.h"
    -+
    -+// Protects the sdp_slots array from concurrent access.
    -+static std::recursive_mutex sdp_lock;
    -+
    -+/**
    -+ * The need for a state variable have been reduced to two states.
    -+ * The remaining state control is handled by program flow
    -+ */
    -+typedef enum {
    -+  SDP_RECORD_FREE = 0,
    -+  SDP_RECORD_ALLOCED,
    -+} sdp_state_t;
    -+
    -+typedef struct {
    -+  sdp_state_t state;
    -+  int sdp_handle;
    -+  bluetooth_sdp_record* record_data;
    -+} sdp_slot_t;
    -+
    -+#define MAX_SDP_SLOTS 128
    -+static sdp_slot_t sdp_slots[MAX_SDP_SLOTS];
    -+
    -+/*****************************************************************************
    -+ * LOCAL Functions
    -+ *****************************************************************************/
    -+static int add_maps_sdp(const bluetooth_sdp_mas_record* rec);
    -+static int add_mapc_sdp(const bluetooth_sdp_mns_record* rec);
    -+static int add_pbaps_sdp(const bluetooth_sdp_pse_record* rec);
    -+static int add_opps_sdp(const bluetooth_sdp_ops_record* rec);
    -+static int add_saps_sdp(const bluetooth_sdp_sap_record* rec);
    -+bt_status_t remove_sdp_record(int record_id);
    -+static int free_sdp_slot(int id);
    -+
    -+/******************************************************************************
    -+ * WARNING: Functions below are not called in BTU context.
    -+ * Introduced to make it possible to create SDP records from JAVA with both a
    -+ * RFCOMM channel and a L2CAP PSM.
    -+ * Overall architecture:
    -+ *  1) JAVA calls createRecord() which returns a pseudo ID which at a later
    -+ *     point will be linked to a specific SDP handle.
    -+ *  2) createRecord() requests the BTU task(thread) to call a callback in SDP
    -+ *     which creates the actual record, and updates the ID<->SDPHandle map
    -+ *     based on the ID beeing passed to BTA as user_data.
    -+ *****************************************************************************/
    -+
    -+static void init_sdp_slots() {
    -+  int i;
    -+  memset(sdp_slots, 0, sizeof(sdp_slot_t) * MAX_SDP_SLOTS);
    -+  /* if SDP_RECORD_FREE is zero - no need to set the value */
    -+  if (SDP_RECORD_FREE != 0) {
    -+    for (i = 0; i < MAX_SDP_SLOTS; i++) {
    -+      sdp_slots[i].state = SDP_RECORD_FREE;
    -+    }
    -+  }
    -+}
    -+
    -+bt_status_t sdp_server_init() {
    -+  BTIF_TRACE_DEBUG("Sdp Server %s", __func__);
    -+  init_sdp_slots();
    -+  return BT_STATUS_SUCCESS;
    -+}
    -+
    -+void sdp_server_cleanup() {
    -+  BTIF_TRACE_DEBUG("Sdp Server %s", __func__);
    -+  std::unique_lock<std::recursive_mutex> lock(sdp_lock);
    -+  int i;
    -+  for (i = 0; i < MAX_SDP_SLOTS; i++) {
    -+    /*remove_sdp_record(i); we cannot send messages to the other threads, since
    -+    * they might
    -+    *                       have been shut down already. Just do local cleanup.
    -+    */
    -+    free_sdp_slot(i);
    -+  }
    -+}
    -+
    -+int get_sdp_records_size(bluetooth_sdp_record* in_record, int count) {
    -+  bluetooth_sdp_record* record = in_record;
    -+  int records_size = 0;
    -+  int i;
    -+  for (i = 0; i < count; i++) {
    -+    record = &in_record[i];
    -+    records_size += sizeof(bluetooth_sdp_record);
    -+    records_size += record->hdr.service_name_length;
    -+    if (record->hdr.service_name_length > 0) {
    -+      records_size++; /* + '\0' termination of string */
    -+    }
    -+    records_size += record->hdr.user1_ptr_len;
    -+    records_size += record->hdr.user2_ptr_len;
    -+  }
    -+  return records_size;
    -+}
    -+
    -+/* Deep copy all content of in_records into out_records.
    -+ * out_records must point to a chunk of memory large enough to contain all
    -+ * the data. Use getSdpRecordsSize() to calculate the needed size. */
    -+void copy_sdp_records(bluetooth_sdp_record* in_records,
    -+                      bluetooth_sdp_record* out_records, int count) {
    -+  int i;
    -+  bluetooth_sdp_record* in_record;
    -+  bluetooth_sdp_record* out_record;
    -+  char* free_ptr =
    -+      (char*)(&out_records[count]); /* set pointer to after the last entry */
    -+
    -+  for (i = 0; i < count; i++) {
    -+    in_record = &in_records[i];
    -+    out_record = &out_records[i];
    -+    *out_record = *in_record;
    -+
    -+    if (in_record->hdr.service_name == NULL ||
    -+        in_record->hdr.service_name_length == 0) {
    -+      out_record->hdr.service_name = NULL;
    -+      out_record->hdr.service_name_length = 0;
    -+    } else {
    -+      out_record->hdr.service_name = free_ptr;  // Update service_name pointer
    -+      // Copy string
    -+      memcpy(free_ptr, in_record->hdr.service_name,
    -+             in_record->hdr.service_name_length);
    -+      free_ptr += in_record->hdr.service_name_length;
    -+      *(free_ptr) = '\0';  // Set '\0' termination of string
    -+      free_ptr++;
    -+    }
    -+    if (in_record->hdr.user1_ptr != NULL) {
    -+      out_record->hdr.user1_ptr = (uint8_t*)free_ptr;  // Update pointer
    -+      memcpy(free_ptr, in_record->hdr.user1_ptr,
    -+             in_record->hdr.user1_ptr_len);  // Copy content
    -+      free_ptr += in_record->hdr.user1_ptr_len;
    -+    }
    -+    if (in_record->hdr.user2_ptr != NULL) {
    -+      out_record->hdr.user2_ptr = (uint8_t*)free_ptr;  // Update pointer
    -+      memcpy(free_ptr, in_record->hdr.user2_ptr,
    -+             in_record->hdr.user2_ptr_len);  // Copy content
    -+      free_ptr += in_record->hdr.user2_ptr_len;
    -+    }
    -+  }
    -+  return;
    -+}
    -+
    -+/* Reserve a slot in sdp_slots, copy data and set a reference to the copy.
    -+ * The record_data will contain both the record and any data pointed to by
    -+ * the record.
    -+ * Currently this covers:
    -+ *   service_name string,
    -+ *   user1_ptr and
    -+ *   user2_ptr. */
    -+static int alloc_sdp_slot(bluetooth_sdp_record* in_record) {
    -+  int record_size = get_sdp_records_size(in_record, 1);
    -+  /* We are optimists here, and preallocate the record.
    -+   * This is to reduce the time we hold the sdp_lock. */
    -+  bluetooth_sdp_record* record = (bluetooth_sdp_record*)osi_malloc(record_size);
    -+
    -+  copy_sdp_records(in_record, record, 1);
    -+  {
    -+    std::unique_lock<std::recursive_mutex> lock(sdp_lock);
    -+    for (int i = 0; i < MAX_SDP_SLOTS; i++) {
    -+      if (sdp_slots[i].state == SDP_RECORD_FREE) {
    -+        sdp_slots[i].state = SDP_RECORD_ALLOCED;
    -+        sdp_slots[i].record_data = record;
    -+        return i;
    -+      }
    -+    }
    -+  }
    -+  APPL_TRACE_ERROR("%s() failed - no more free slots!", __func__);
    -+  /* Rearly the optimist is too optimistic, and cleanup is needed...*/
    -+  osi_free(record);
    -+  return -1;
    -+}
    -+
    -+static int free_sdp_slot(int id) {
    -+  int handle = -1;
    -+  bluetooth_sdp_record* record = NULL;
    -+  if (id < 0 || id >= MAX_SDP_SLOTS) {
    -+    android_errorWriteLog(0x534e4554, "37502513");
    -+    APPL_TRACE_ERROR("%s() failed - id %d is invalid", __func__, id);
    -+    return handle;
    -+  }
    -+
    -+  {
    -+    std::unique_lock<std::recursive_mutex> lock(sdp_lock);
    -+    handle = sdp_slots[id].sdp_handle;
    -+    sdp_slots[id].sdp_handle = 0;
    -+    if (sdp_slots[id].state != SDP_RECORD_FREE) {
    -+      /* safe a copy of the pointer, and free after unlock() */
    -+      record = sdp_slots[id].record_data;
    -+    }
    -+    sdp_slots[id].state = SDP_RECORD_FREE;
    -+  }
    -+
    -+  if (record != NULL) {
    -+    osi_free(record);
    -+  } else {
    -+    // Record have already been freed
    -+    handle = -1;
    -+  }
    -+  return handle;
    -+}
    -+
    -+/***
    -+ * Use this to get a reference to a SDP slot AND change the state to
    -+ * SDP_RECORD_CREATE_INITIATED.
    -+ */
    -+static const sdp_slot_t* start_create_sdp(int id) {
    -+  if (id >= MAX_SDP_SLOTS) {
    -+    APPL_TRACE_ERROR("%s() failed - id %d is invalid", __func__, id);
    -+    return NULL;
    -+  }
    -+
    -+  std::unique_lock<std::recursive_mutex> lock(sdp_lock);
    -+  if (sdp_slots[id].state != SDP_RECORD_ALLOCED) {
    -+    /* The record have been removed before this event occurred - e.g. deinit */
    -+    APPL_TRACE_ERROR(
    -+        "%s() failed - state for id %d is "
    -+        "sdp_slots[id].state = %d expected %d",
    -+        __func__, id, sdp_slots[id].state, SDP_RECORD_ALLOCED);
    -+    return NULL;
    -+  }
    -+
    -+  return &(sdp_slots[id]);
    -+}
    -+
    -+static void set_sdp_handle(int id, int handle) {
    -+  std::unique_lock<std::recursive_mutex> lock(sdp_lock);
    -+  sdp_slots[id].sdp_handle = handle;
    -+  BTIF_TRACE_DEBUG("%s() id=%d to handle=0x%08x", __func__, id, handle);
    -+}
    -+
    -+bt_status_t create_sdp_record(bluetooth_sdp_record* record,
    -+                              int* record_handle) {
    -+  int handle;
    -+
    -+  handle = alloc_sdp_slot(record);
    -+  BTIF_TRACE_DEBUG("%s() handle = 0x%08x", __func__, handle);
    -+
    -+  if (handle < 0) return BT_STATUS_FAIL;
    -+
    -+  BTA_SdpCreateRecordByUser(INT_TO_PTR(handle));
    -+
    -+  *record_handle = handle;
    -+
    -+  return BT_STATUS_SUCCESS;
    -+}
    -+
    -+bt_status_t remove_sdp_record(int record_id) {
    -+  int handle;
    -+
    -+  /* Get the Record handle, and free the slot */
    -+  handle = free_sdp_slot(record_id);
    -+  BTIF_TRACE_DEBUG("Sdp Server %s id=%d to handle=0x%08x", __func__, record_id,
    -+                   handle);
    -+
    -+  /* Pass the actual record handle */
    -+  if (handle > 0) {
    -+    BTA_SdpRemoveRecordByUser(INT_TO_PTR(handle));
    -+    return BT_STATUS_SUCCESS;
    -+  }
    -+  BTIF_TRACE_DEBUG("Sdp Server %s - record already removed - or never created",
    -+                   __func__);
    -+  return BT_STATUS_FAIL;
    -+}
    -+
    -+/******************************************************************************
    -+ * CALLBACK FUNCTIONS
    -+ * Called in BTA context to create/remove SDP records.
    -+ ******************************************************************************/
    -+
    -+void on_create_record_event(int id) {
    -+  /*
    -+   * 1) Fetch the record pointer, and change its state?
    -+   * 2) switch on the type to create the correct record
    -+   * 3) Update state on completion
    -+   * 4) What to do at fail?
    -+   * */
    -+  BTIF_TRACE_DEBUG("Sdp Server %s", __func__);
    -+  const sdp_slot_t* sdp_slot = start_create_sdp(id);
    -+  /* In the case we are shutting down, sdp_slot is NULL */
    -+  if (sdp_slot != NULL) {
    -+    bluetooth_sdp_record* record = sdp_slot->record_data;
    -+    int handle = -1;
    -+    switch (record->hdr.type) {
    -+      case SDP_TYPE_MAP_MAS:
    -+        handle = add_maps_sdp(&record->mas);
    -+        break;
    -+      case SDP_TYPE_MAP_MNS:
    -+        handle = add_mapc_sdp(&record->mns);
    -+        break;
    -+      case SDP_TYPE_PBAP_PSE:
    -+        handle = add_pbaps_sdp(&record->pse);
    -+        break;
    -+      case SDP_TYPE_OPP_SERVER:
    -+        handle = add_opps_sdp(&record->ops);
    -+        break;
    -+      case SDP_TYPE_SAP_SERVER:
    -+        handle = add_saps_sdp(&record->sap);
    -+        break;
    -+      case SDP_TYPE_PBAP_PCE:
    -+      //        break; not yet supported
    -+      default:
    -+        BTIF_TRACE_DEBUG("Record type %d is not supported", record->hdr.type);
    -+        break;
    -+    }
    -+    if (handle != -1) {
    -+      set_sdp_handle(id, handle);
    -+    }
    -+  }
    -+}
    -+
    -+void on_remove_record_event(int handle) {
    -+  BTIF_TRACE_DEBUG("Sdp Server %s", __func__);
    -+
    -+  // User data carries the actual SDP handle, not the ID.
    -+  if (handle != -1 && handle != 0) {
    -+    bool result;
    -+    result = SDP_DeleteRecord(handle);
    -+    if (result == false) {
    -+      BTIF_TRACE_ERROR("  Unable to remove handle 0x%08x", handle);
    -+    }
    -+  }
    -+}
    -+
    -+/****
    -+ * Below the actual functions accessing BTA context data - hence only call from
    -+ * BTA context!
    -+ */
    -+
    -+/* Create a MAP MAS SDP record based on information stored in a
    -+ * bluetooth_sdp_mas_record */
    -+static int add_maps_sdp(const bluetooth_sdp_mas_record* rec) {
    -+  tSDP_PROTOCOL_ELEM protoList[3];
    -+  uint16_t service = UUID_SERVCLASS_MESSAGE_ACCESS;
    -+  uint16_t browse = UUID_SERVCLASS_PUBLIC_BROWSE_GROUP;
    -+  bool status = true;
    -+  uint32_t sdp_handle = 0;
    -+  uint8_t temp[4];
    -+  uint8_t* p_temp = temp;
    -+
    -+  APPL_TRACE_DEBUG(
    -+      "%s(): MASID = 0x%02x, scn 0x%02x, psm = 0x%04x\n  service name %s",
    -+      __func__, rec->mas_instance_id, rec->hdr.rfcomm_channel_number,
    -+      rec->hdr.l2cap_psm, rec->hdr.service_name);
    -+
    -+  APPL_TRACE_DEBUG("  msg_types: 0x%02x, feature_bits: 0x%08x",
    -+                   rec->supported_message_types, rec->supported_features);
    -+
    -+  sdp_handle = SDP_CreateRecord();
    -+  if (sdp_handle == 0) {
    -+    APPL_TRACE_ERROR("%s() - Unable to register MAPS Service", __func__);
    -+    return sdp_handle;
    -+  }
    -+
    -+  /* add service class */
    -+  status &= SDP_AddServiceClassIdList(sdp_handle, 1, &service);
    -+  memset(protoList, 0, 3 * sizeof(tSDP_PROTOCOL_ELEM));
    -+
    -+  /* add protocol list, including RFCOMM scn */
    -+  protoList[0].protocol_uuid = UUID_PROTOCOL_L2CAP;
    -+  protoList[0].num_params = 0;
    -+  protoList[1].protocol_uuid = UUID_PROTOCOL_RFCOMM;
    -+  protoList[1].num_params = 1;
    -+  protoList[1].params[0] = rec->hdr.rfcomm_channel_number;
    -+  protoList[2].protocol_uuid = UUID_PROTOCOL_OBEX;
    -+  protoList[2].num_params = 0;
    -+  status &= SDP_AddProtocolList(sdp_handle, 3, protoList);
    -+
    -+  /* Add a name entry */
    -+  status &= SDP_AddAttribute(sdp_handle, (uint16_t)ATTR_ID_SERVICE_NAME,
    -+                             (uint8_t)TEXT_STR_DESC_TYPE,
    -+                             (uint32_t)(rec->hdr.service_name_length + 1),
    -+                             (uint8_t*)rec->hdr.service_name);
    -+
    -+  /* Add in the Bluetooth Profile Descriptor List */
    -+  status &= SDP_AddProfileDescriptorList(sdp_handle, UUID_SERVCLASS_MAP_PROFILE,
    -+                                         rec->hdr.profile_version);
    -+
    -+  /* Add MAS instance ID */
    -+  status &=
    -+      SDP_AddAttribute(sdp_handle, ATTR_ID_MAS_INSTANCE_ID, UINT_DESC_TYPE,
    -+                       (uint32_t)1, (uint8_t*)&rec->mas_instance_id);
    -+
    -+  /* Add supported message types */
    -+  status &=
    -+      SDP_AddAttribute(sdp_handle, ATTR_ID_SUPPORTED_MSG_TYPE, UINT_DESC_TYPE,
    -+                       (uint32_t)1, (uint8_t*)&rec->supported_message_types);
    -+
    -+  /* Add supported feature */
    -+  UINT32_TO_BE_STREAM(p_temp, rec->supported_features);
    -+  status &= SDP_AddAttribute(sdp_handle, ATTR_ID_MAP_SUPPORTED_FEATURES,
    -+                             UINT_DESC_TYPE, (uint32_t)4, temp);
    -+
    -+  /* Add the L2CAP PSM if present */
    -+  if (rec->hdr.l2cap_psm != -1) {
    -+    p_temp = temp;  // The macro modifies p_temp, hence rewind.
    -+    UINT16_TO_BE_STREAM(p_temp, rec->hdr.l2cap_psm);
    -+    status &= SDP_AddAttribute(sdp_handle, ATTR_ID_GOEP_L2CAP_PSM,
    -+                               UINT_DESC_TYPE, (uint32_t)2, temp);
    -+  }
    -+
    -+  /* Make the service browseable */
    -+  status &=
    -+      SDP_AddUuidSequence(sdp_handle, ATTR_ID_BROWSE_GROUP_LIST, 1, &browse);
    -+
    -+  if (!status) {
    -+    SDP_DeleteRecord(sdp_handle);
    -+    sdp_handle = 0;
    -+    APPL_TRACE_ERROR("%s() FAILED", __func__);
    -+  } else {
    -+    bta_sys_add_uuid(service); /* UUID_SERVCLASS_MESSAGE_ACCESS */
    -+    APPL_TRACE_DEBUG("%s():  SDP Registered (handle 0x%08x)", __func__,
    -+                     sdp_handle);
    -+  }
    -+  return sdp_handle;
    -+}
    -+
    -+/* Create a MAP MNS SDP record based on information stored in a
    -+ * bluetooth_sdp_mns_record */
    -+static int add_mapc_sdp(const bluetooth_sdp_mns_record* rec) {
    -+  tSDP_PROTOCOL_ELEM protoList[3];
    -+  uint16_t service = UUID_SERVCLASS_MESSAGE_NOTIFICATION;
    -+  uint16_t browse = UUID_SERVCLASS_PUBLIC_BROWSE_GROUP;
    -+  bool status = true;
    -+  uint32_t sdp_handle = 0;
    -+  uint8_t temp[4];
    -+  uint8_t* p_temp = temp;
    -+
    -+  APPL_TRACE_DEBUG("%s(): scn 0x%02x, psm = 0x%04x\n  service name %s",
    -+                   __func__, rec->hdr.rfcomm_channel_number, rec->hdr.l2cap_psm,
    -+                   rec->hdr.service_name);
    -+
    -+  APPL_TRACE_DEBUG("  feature_bits: 0x%08x", rec->supported_features);
    -+
    -+  sdp_handle = SDP_CreateRecord();
    -+  if (sdp_handle == 0) {
    -+    APPL_TRACE_ERROR("%s(): Unable to register MAP Notification Service",
    -+                     __func__);
    -+    return sdp_handle;
    -+  }
    -+
    -+  /* add service class */
    -+  status &= SDP_AddServiceClassIdList(sdp_handle, 1, &service);
    -+  memset(protoList, 0, 3 * sizeof(tSDP_PROTOCOL_ELEM));
    -+
    -+  /* add protocol list, including RFCOMM scn */
    -+  protoList[0].protocol_uuid = UUID_PROTOCOL_L2CAP;
    -+  protoList[0].num_params = 0;
    -+  protoList[1].protocol_uuid = UUID_PROTOCOL_RFCOMM;
    -+  protoList[1].num_params = 1;
    -+  protoList[1].params[0] = rec->hdr.rfcomm_channel_number;
    -+  protoList[2].protocol_uuid = UUID_PROTOCOL_OBEX;
    -+  protoList[2].num_params = 0;
    -+  status &= SDP_AddProtocolList(sdp_handle, 3, protoList);
    -+
    -+  /* Add a name entry */
    -+  status &= SDP_AddAttribute(sdp_handle, (uint16_t)ATTR_ID_SERVICE_NAME,
    -+                             (uint8_t)TEXT_STR_DESC_TYPE,
    -+                             (uint32_t)(rec->hdr.service_name_length + 1),
    -+                             (uint8_t*)rec->hdr.service_name);
    -+
    -+  /* Add in the Bluetooth Profile Descriptor List */
    -+  status &= SDP_AddProfileDescriptorList(sdp_handle, UUID_SERVCLASS_MAP_PROFILE,
    -+                                         rec->hdr.profile_version);
    -+
    -+  /* Add supported feature */
    -+  UINT32_TO_BE_STREAM(p_temp, rec->supported_features);
    -+  status &= SDP_AddAttribute(sdp_handle, ATTR_ID_MAP_SUPPORTED_FEATURES,
    -+                             UINT_DESC_TYPE, (uint32_t)4, temp);
    -+
    -+  /* Add the L2CAP PSM if present */
    -+  if (rec->hdr.l2cap_psm != -1) {
    -+    p_temp = temp;  // The macro modifies p_temp, hence rewind.
    -+    UINT16_TO_BE_STREAM(p_temp, rec->hdr.l2cap_psm);
    -+    status &= SDP_AddAttribute(sdp_handle, ATTR_ID_GOEP_L2CAP_PSM,
    -+                               UINT_DESC_TYPE, (uint32_t)2, temp);
    -+  }
    -+
    -+  /* Make the service browseable */
    -+  status &=
    -+      SDP_AddUuidSequence(sdp_handle, ATTR_ID_BROWSE_GROUP_LIST, 1, &browse);
    -+
    -+  if (!status) {
    -+    SDP_DeleteRecord(sdp_handle);
    -+    sdp_handle = 0;
    -+    APPL_TRACE_ERROR("%s() FAILED", __func__);
    -+  } else {
    -+    bta_sys_add_uuid(service); /* UUID_SERVCLASS_MESSAGE_ACCESS */
    -+    APPL_TRACE_DEBUG("%s():  SDP Registered (handle 0x%08x)", __func__,
    -+                     sdp_handle);
    -+  }
    -+  return sdp_handle;
    -+}
    -+
    -+/* Create a PBAP Server SDP record based on information stored in a
    -+ * bluetooth_sdp_pse_record */
    -+static int add_pbaps_sdp(const bluetooth_sdp_pse_record* rec) {
    -+  tSDP_PROTOCOL_ELEM protoList[3];
    -+  uint16_t service = UUID_SERVCLASS_PBAP_PSE;
    -+  uint16_t browse = UUID_SERVCLASS_PUBLIC_BROWSE_GROUP;
    -+  bool status = true;
    -+  uint32_t sdp_handle = 0;
    -+  uint8_t temp[4];
    -+  uint8_t* p_temp = temp;
    -+
    -+  APPL_TRACE_DEBUG("%s(): scn 0x%02x, psm = 0x%04x\n  service name %s",
    -+                   __func__, rec->hdr.rfcomm_channel_number, rec->hdr.l2cap_psm,
    -+                   rec->hdr.service_name);
    -+
    -+  APPL_TRACE_DEBUG("  supported_repositories: 0x%08x, feature_bits: 0x%08x",
    -+                   rec->supported_repositories, rec->supported_features);
    -+
    -+  sdp_handle = SDP_CreateRecord();
    -+  if (sdp_handle == 0) {
    -+    APPL_TRACE_ERROR("%s(): Unable to register PBAP Server Service", __func__);
    -+    return sdp_handle;
    -+  }
    -+
    -+  /* add service class */
    -+  status &= SDP_AddServiceClassIdList(sdp_handle, 1, &service);
    -+  memset(protoList, 0, 3 * sizeof(tSDP_PROTOCOL_ELEM));
    -+
    -+  /* add protocol list, including RFCOMM scn */
    -+  protoList[0].protocol_uuid = UUID_PROTOCOL_L2CAP;
    -+  protoList[0].num_params = 0;
    -+  protoList[1].protocol_uuid = UUID_PROTOCOL_RFCOMM;
    -+  protoList[1].num_params = 1;
    -+  protoList[1].params[0] = rec->hdr.rfcomm_channel_number;
    -+  protoList[2].protocol_uuid = UUID_PROTOCOL_OBEX;
    -+  protoList[2].num_params = 0;
    -+  status &= SDP_AddProtocolList(sdp_handle, 3, protoList);
    -+
    -+  /* Add a name entry */
    -+  status &= SDP_AddAttribute(sdp_handle, (uint16_t)ATTR_ID_SERVICE_NAME,
    -+                             (uint8_t)TEXT_STR_DESC_TYPE,
    -+                             (uint32_t)(rec->hdr.service_name_length + 1),
    -+                             (uint8_t*)rec->hdr.service_name);
    -+
    -+  /* Add in the Bluetooth Profile Descriptor List */
    -+  status &= SDP_AddProfileDescriptorList(
    -+      sdp_handle, UUID_SERVCLASS_PHONE_ACCESS, rec->hdr.profile_version);
    -+
    -+  /* Add supported repositories 1 byte */
    -+  status &= SDP_AddAttribute(sdp_handle, ATTR_ID_SUPPORTED_REPOSITORIES,
    -+                             UINT_DESC_TYPE, (uint32_t)1,
    -+                             (uint8_t*)&rec->supported_repositories);
    -+
    -+  /* Add supported feature 4 bytes*/
    -+  UINT32_TO_BE_STREAM(p_temp, rec->supported_features);
    -+  status &= SDP_AddAttribute(sdp_handle, ATTR_ID_PBAP_SUPPORTED_FEATURES,
    -+                             UINT_DESC_TYPE, (uint32_t)4, temp);
    -+
    -+  /* Add the L2CAP PSM if present */
    -+  if (rec->hdr.l2cap_psm != -1) {
    -+    p_temp = temp;  // The macro modifies p_temp, hence rewind.
    -+    UINT16_TO_BE_STREAM(p_temp, rec->hdr.l2cap_psm);
    -+    status &= SDP_AddAttribute(sdp_handle, ATTR_ID_GOEP_L2CAP_PSM,
    -+                               UINT_DESC_TYPE, (uint32_t)2, temp);
    -+  }
    -+
    -+  /* Make the service browseable */
    -+  status &=
    -+      SDP_AddUuidSequence(sdp_handle, ATTR_ID_BROWSE_GROUP_LIST, 1, &browse);
    -+
    -+  if (!status) {
    -+    SDP_DeleteRecord(sdp_handle);
    -+    sdp_handle = 0;
    -+    APPL_TRACE_ERROR("%s() FAILED", __func__);
    -+  } else {
    -+    bta_sys_add_uuid(service); /* UUID_SERVCLASS_MESSAGE_ACCESS */
    -+    APPL_TRACE_DEBUG("%s():  SDP Registered (handle 0x%08x)", __func__,
    -+                     sdp_handle);
    -+  }
    -+  return sdp_handle;
    -+}
    -+
    -+/* Create a OPP Server SDP record based on information stored in a
    -+ * bluetooth_sdp_ops_record */
    -+static int add_opps_sdp(const bluetooth_sdp_ops_record* rec) {
    -+  tSDP_PROTOCOL_ELEM protoList[3];
    -+  uint16_t service = UUID_SERVCLASS_OBEX_OBJECT_PUSH;
    -+  uint16_t browse = UUID_SERVCLASS_PUBLIC_BROWSE_GROUP;
    -+  uint8_t type_len[rec->supported_formats_list_len];
    -+  uint8_t desc_type[rec->supported_formats_list_len];
    -+  uint8_t* type_value[rec->supported_formats_list_len];
    -+  bool status = true;
    -+  uint32_t sdp_handle = 0;
    -+  uint8_t temp[4];
    -+  uint8_t* p_temp = temp;
    -+  tBTA_UTL_COD cod;
    -+  int i, j;
    -+
    -+  APPL_TRACE_DEBUG("%s(): scn 0x%02x, psm = 0x%04x\n  service name %s",
    -+                   __func__, rec->hdr.rfcomm_channel_number, rec->hdr.l2cap_psm,
    -+                   rec->hdr.service_name);
    -+
    -+  APPL_TRACE_DEBUG("  supported formats count: %d",
    -+                   rec->supported_formats_list_len);
    -+
    -+  sdp_handle = SDP_CreateRecord();
    -+  if (sdp_handle == 0) {
    -+    APPL_TRACE_ERROR("%s(): Unable to register Object Push Server Service",
    -+                     __func__);
    -+    return sdp_handle;
    -+  }
    -+
    -+  /* add service class */
    -+  status &= SDP_AddServiceClassIdList(sdp_handle, 1, &service);
    -+  memset(protoList, 0, 3 * sizeof(tSDP_PROTOCOL_ELEM));
    -+
    -+  /* add protocol list, including RFCOMM scn */
    -+  protoList[0].protocol_uuid = UUID_PROTOCOL_L2CAP;
    -+  protoList[0].num_params = 0;
    -+  protoList[1].protocol_uuid = UUID_PROTOCOL_RFCOMM;
    -+  protoList[1].num_params = 1;
    -+  protoList[1].params[0] = rec->hdr.rfcomm_channel_number;
    -+  protoList[2].protocol_uuid = UUID_PROTOCOL_OBEX;
    -+  protoList[2].num_params = 0;
    -+  status &= SDP_AddProtocolList(sdp_handle, 3, protoList);
    -+
    -+  /* Add a name entry */
    -+  status &= SDP_AddAttribute(sdp_handle, (uint16_t)ATTR_ID_SERVICE_NAME,
    -+                             (uint8_t)TEXT_STR_DESC_TYPE,
    -+                             (uint32_t)(rec->hdr.service_name_length + 1),
    -+                             (uint8_t*)rec->hdr.service_name);
    -+
    -+  /* Add in the Bluetooth Profile Descriptor List */
    -+  status &= SDP_AddProfileDescriptorList(
    -+      sdp_handle, UUID_SERVCLASS_OBEX_OBJECT_PUSH, rec->hdr.profile_version);
    -+
    -+  /* add sequence for supported types */
    -+  for (i = 0, j = 0; i < rec->supported_formats_list_len; i++) {
    -+    type_value[j] = (uint8_t*)&rec->supported_formats_list[i];
    -+    desc_type[j] = UINT_DESC_TYPE;
    -+    type_len[j++] = 1;
    -+  }
    -+
    -+  status &=
    -+      SDP_AddSequence(sdp_handle, (uint16_t)ATTR_ID_SUPPORTED_FORMATS_LIST,
    -+                      (uint8_t)rec->supported_formats_list_len, desc_type,
    -+                      type_len, type_value);
    -+
    -+  /* Add the L2CAP PSM if present */
    -+  if (rec->hdr.l2cap_psm != -1) {
    -+    p_temp = temp;  // The macro modifies p_temp, hence rewind.
    -+    UINT16_TO_BE_STREAM(p_temp, rec->hdr.l2cap_psm);
    -+    status &= SDP_AddAttribute(sdp_handle, ATTR_ID_GOEP_L2CAP_PSM,
    -+                               UINT_DESC_TYPE, (uint32_t)2, temp);
    -+  }
    -+
    -+  /* Make the service browseable */
    -+  status &=
    -+      SDP_AddUuidSequence(sdp_handle, ATTR_ID_BROWSE_GROUP_LIST, 1, &browse);
    -+
    -+  if (!status) {
    -+    SDP_DeleteRecord(sdp_handle);
    -+    sdp_handle = 0;
    -+    APPL_TRACE_ERROR("%s() FAILED", __func__);
    -+  } else {
    -+    /* set class of device */
    -+    cod.service = BTM_COD_SERVICE_OBJ_TRANSFER;
    -+    utl_set_device_class(&cod, BTA_UTL_SET_COD_SERVICE_CLASS);
    -+
    -+    bta_sys_add_uuid(service); /* UUID_SERVCLASS_OBEX_OBJECT_PUSH */
    -+    APPL_TRACE_DEBUG("%s():  SDP Registered (handle 0x%08x)", __func__,
    -+                     sdp_handle);
    -+  }
    -+  return sdp_handle;
    -+}
    -+
    -+// Create a Sim Access Profile SDP record based on information stored in a
    -+// bluetooth_sdp_sap_record.
    -+static int add_saps_sdp(const bluetooth_sdp_sap_record* rec) {
    -+  tSDP_PROTOCOL_ELEM protoList[2];
    -+  uint16_t services[2];
    -+  uint16_t browse = UUID_SERVCLASS_PUBLIC_BROWSE_GROUP;
    -+  bool status = true;
    -+  uint32_t sdp_handle = 0;
    -+
    -+  APPL_TRACE_DEBUG("%s(): scn 0x%02x, service name %s", __func__,
    -+                   rec->hdr.rfcomm_channel_number, rec->hdr.service_name);
    -+
    -+  sdp_handle = SDP_CreateRecord();
    -+  if (sdp_handle == 0) {
    -+    APPL_TRACE_ERROR("%s(): Unable to register SAPS Service", __func__);
    -+    return sdp_handle;
    -+  }
    -+
    -+  services[0] = UUID_SERVCLASS_SAP;
    -+  services[1] = UUID_SERVCLASS_GENERIC_TELEPHONY;
    -+
    -+  // add service class
    -+  status &= SDP_AddServiceClassIdList(sdp_handle, 2, services);
    -+  memset(protoList, 0, 2 * sizeof(tSDP_PROTOCOL_ELEM));
    -+
    -+  // add protocol list, including RFCOMM scn
    -+  protoList[0].protocol_uuid = UUID_PROTOCOL_L2CAP;
    -+  protoList[0].num_params = 0;
    -+  protoList[1].protocol_uuid = UUID_PROTOCOL_RFCOMM;
    -+  protoList[1].num_params = 1;
    -+  protoList[1].params[0] = rec->hdr.rfcomm_channel_number;
    -+  status &= SDP_AddProtocolList(sdp_handle, 2, protoList);
    -+
    -+  // Add a name entry
    -+  status &= SDP_AddAttribute(sdp_handle, (uint16_t)ATTR_ID_SERVICE_NAME,
    -+                             (uint8_t)TEXT_STR_DESC_TYPE,
    -+                             (uint32_t)(rec->hdr.service_name_length + 1),
    -+                             (uint8_t*)rec->hdr.service_name);
    -+
    -+  // Add in the Bluetooth Profile Descriptor List
    -+  status &= SDP_AddProfileDescriptorList(sdp_handle, UUID_SERVCLASS_SAP,
    -+                                         rec->hdr.profile_version);
    -+
    -+  // Make the service browseable
    -+  status &=
    -+      SDP_AddUuidSequence(sdp_handle, ATTR_ID_BROWSE_GROUP_LIST, 1, &browse);
    -+
    -+  if (!status) {
    -+    SDP_DeleteRecord(sdp_handle);
    -+    sdp_handle = 0;
    -+    APPL_TRACE_ERROR("%s(): FAILED deleting record", __func__);
    -+  } else {
    -+    bta_sys_add_uuid(UUID_SERVCLASS_SAP);
    -+    APPL_TRACE_DEBUG("%s(): SDP Registered (handle 0x%08x)", __func__,
    -+                     sdp_handle);
    -+  }
    -+  return sdp_handle;
    -+}
    +diff --git a/btif/src/btif_sdp_server.c b/btif/src/btif_sdp_server.c
    +index d02dfa0..90d74cf 100644
    +--- a/btif/src/btif_sdp_server.c
    ++++ b/btif/src/btif_sdp_server.c
    +@@ -215,7 +215,8 @@ static int alloc_sdp_slot(bluetooth_sdp_record* in_record) {
    + static int free_sdp_slot(int id) {
    +     int handle = -1;
    +     bluetooth_sdp_record* record = NULL;
    +-    if(id >= MAX_SDP_SLOTS) {
    ++    if(id < 0 || id >= MAX_SDP_SLOTS) {
    ++        android_errorWriteLog(0x534e4554, "37502513");
    +         APPL_TRACE_ERROR("%s() failed - id %d is invalid", __func__, id);
    +         return handle;
    +     }
     diff --git a/stack/avdt/avdt_api.c b/stack/avdt/avdt_api.c
    -index 98ef5f7..258f424 100644
    +index 98ef5f7..5201054 100644
     --- a/stack/avdt/avdt_api.c
     +++ b/stack/avdt/avdt_api.c
     @@ -1208,7 +1208,7 @@ UINT16 AVDT_SendReport(UINT8 handle, AVDT_REPORT_TYPE type,
    @@ -809,12 +62,12 @@ index 98ef5f7..258f424 100644
              p_tbl = avdt_ad_tc_tbl_by_type(AVDT_CHAN_REPORT, p_scb->p_ccb, p_scb);
              if (p_tbl->state == AVDT_AD_ST_OPEN) {
     -            BT_HDR *p_pkt = (BT_HDR *)osi_malloc(p_tbl->peer_mtu);
    -+            BT_HDR* p_pkt = (BT_HDR*)osi_malloc(p_tbl->peer_mtu + sizeof(BT_HDR));
    ++            BT_HDR *p_pkt = (BT_HDR *)osi_malloc(p_tbl->peer_mtu + sizeof(BT_HDR));
      
                  p_pkt->offset = L2CAP_MIN_OFFSET;
                  p = (UINT8 *)(p_pkt + 1) + p_pkt->offset;
     diff --git a/stack/bnep/bnep_main.c b/stack/bnep/bnep_main.c
    -index 078a72e..9b01472 100644
    +index 078a72e..36b76a1 100644
     --- a/stack/bnep/bnep_main.c
     +++ b/stack/bnep/bnep_main.c
     @@ -575,7 +575,8 @@ static void bnep_data_ind (UINT16 l2cap_cid, BT_HDR *p_buf)
    @@ -823,24 +76,23 @@ index 078a72e..9b01472 100644
              {
     -            p_bcb->p_pending_data = (BT_HDR *)osi_malloc(rem_len);
     +            osi_free(p_bcb->p_pending_data);
    -+            p_bcb->p_pending_data = (BT_HDR*)osi_malloc(rem_len + sizeof(BT_HDR));
    ++            p_bcb->p_pending_data = (BT_HDR *)osi_malloc(rem_len + sizeof(BT_HDR));
                  memcpy((UINT8 *)(p_bcb->p_pending_data + 1), p, rem_len);
                  p_bcb->p_pending_data->len    = rem_len;
                  p_bcb->p_pending_data->offset = 0;
     diff --git a/stack/bnep/bnep_utils.c b/stack/bnep/bnep_utils.c
    -index 13fb189..2250634 100644
    +index 13fb189..e16ffca 100644
     --- a/stack/bnep/bnep_utils.c
     +++ b/stack/bnep/bnep_utils.c
    -@@ -154,7 +154,7 @@ void bnepu_release_bcb (tBNEP_CONN *p_bcb)
    +@@ -154,6 +154,7 @@ void bnepu_release_bcb (tBNEP_CONN *p_bcb)
      
          /* Drop any response pointer we may be holding */
          p_bcb->con_state        = BNEP_STATE_IDLE;
    --    p_bcb->p_pending_data   = NULL;
    -+    osi_free_and_reset((void**)&p_bcb->p_pending_data);
    ++    osi_free(p_bcb->p_pending_data);
    +     p_bcb->p_pending_data   = NULL;
      
          /* Free transmit queue */
    -     while (!fixed_queue_is_empty(p_bcb->xmit_q))
    -@@ -762,24 +762,43 @@ void bnep_process_setup_conn_responce (tBNEP_CONN *p_bcb, UINT8 *p_setup)
    +@@ -762,35 +763,53 @@ void bnep_process_setup_conn_responce (tBNEP_CONN *p_bcb, UINT8 *p_setup)
      UINT8 *bnep_process_control_packet (tBNEP_CONN *p_bcb, UINT8 *p, UINT16 *rem_len, BOOLEAN is_ext)
      {
          UINT8       control_type;
    @@ -848,10 +100,10 @@ index 13fb189..2250634 100644
          UINT16      len, ext_len = 0;
      
     +    if (p == NULL || rem_len == NULL) {
    -+       if (rem_len != NULL) *rem_len = 0;
    -+       BNEP_TRACE_DEBUG("%s: invalid packet: p = %p rem_len = %p", __func__, p,
    -+                        rem_len);
    -+       return NULL;
    ++        if (rem_len != NULL) *rem_len = 0;
    ++        BNEP_TRACE_DEBUG("%s: invalid packet: p = %p rem_len = %p", __func__, p,
    ++                         rem_len);
    ++        return NULL;
     +    }
     +    UINT16 rem_len_orig = *rem_len;
     +
    @@ -867,103 +119,104 @@ index 13fb189..2250634 100644
          *rem_len = *rem_len - 1;
      
     -    BNEP_TRACE_EVENT ("BNEP processing control packet rem_len %d, is_ext %d, ctrl_type %d", *rem_len, is_ext, control_type);
    -+    BNEP_TRACE_EVENT (
    -+       "%s: BNEP processing control packet rem_len %d, is_ext %d, ctrl_type %d",
    -+       __func__, *rem_len, is_ext, control_type);
    ++    BNEP_TRACE_EVENT("%s: BNEP processing control packet rem_len %d, is_ext %d, ctrl_type %d",
    ++                     __func__, *rem_len, is_ext, control_type);
      
          switch (control_type)
          {
          case BNEP_CONTROL_COMMAND_NOT_UNDERSTOOD:
     -        BNEP_TRACE_ERROR ("BNEP Received Cmd not understood for ctl pkt type: %d", *p);
    -+       if (*rem_len < 1) {
    -+         BNEP_TRACE_ERROR(
    -+             "%s: Received BNEP_CONTROL_COMMAND_NOT_UNDERSTOOD with bad length",
    -+             __func__);
    -+         goto bad_packet_length;
    -+       }
    -+       BNEP_TRACE_ERROR(
    -+           "%s: Received BNEP_CONTROL_COMMAND_NOT_UNDERSTOOD for pkt type: %d",
    -+           __func__, *p);
    ++        if (*rem_len < 1) {
    ++            BNEP_TRACE_ERROR(
    ++              "%s: Received BNEP_CONTROL_COMMAND_NOT_UNDERSTOOD with bad length",
    ++              __func__);
    ++            goto bad_packet_length;
    ++        }
    ++        BNEP_TRACE_ERROR(
    ++          "%s: Received BNEP_CONTROL_COMMAND_NOT_UNDERSTOOD for pkt type: %d",
    ++          __func__, *p);
              p++;
              *rem_len = *rem_len - 1;
              break;
    -@@ -788,9 +807,10 @@ UINT8 *bnep_process_control_packet (tBNEP_CONN *p_bcb, UINT8 *p, UINT16 *rem_len
    + 
    +     case BNEP_SETUP_CONNECTION_REQUEST_MSG:
              len = *p++;
    -         if (*rem_len < ((2 * len) + 1))
    -         {
    +-        if (*rem_len < ((2 * len) + 1))
    +-        {
     -            bad_pkt = TRUE;
     -            BNEP_TRACE_ERROR ("BNEP Received Setup message with bad length");
     -            break;
    ++        if (*rem_len < ((2 * len) + 1)) {
     +            BNEP_TRACE_ERROR(
    -+                "%s: Received BNEP_SETUP_CONNECTION_REQUEST_MSG with bad length",
    -+                __func__);
    ++              "%s: Received BNEP_SETUP_CONNECTION_REQUEST_MSG with bad length",
    ++              __func__);
     +            goto bad_packet_length;
              }
              if (!is_ext)
                  bnep_process_setup_conn_req (p_bcb, p, (UINT8)len);
    -@@ -799,6 +819,12 @@ UINT8 *bnep_process_control_packet (tBNEP_CONN *p_bcb, UINT8 *p, UINT16 *rem_len
    +@@ -799,6 +818,12 @@ UINT8 *bnep_process_control_packet (tBNEP_CONN *p_bcb, UINT8 *p, UINT16 *rem_len
              break;
      
          case BNEP_SETUP_CONNECTION_RESPONSE_MSG:
     +        if (*rem_len < 2) {
    -+          BNEP_TRACE_ERROR(
    ++            BNEP_TRACE_ERROR(
     +              "%s: Received BNEP_SETUP_CONNECTION_RESPONSE_MSG with bad length",
     +              __func__);
    -+          goto bad_packet_length;
    ++            goto bad_packet_length;
     +        }
              if (!is_ext)
                  bnep_process_setup_conn_responce (p_bcb, p);
              p += 2;
    -@@ -809,9 +835,10 @@ UINT8 *bnep_process_control_packet (tBNEP_CONN *p_bcb, UINT8 *p, UINT16 *rem_len
    +@@ -809,9 +834,10 @@ UINT8 *bnep_process_control_packet (tBNEP_CONN *p_bcb, UINT8 *p, UINT16 *rem_len
              BE_STREAM_TO_UINT16 (len, p);
              if (*rem_len < (len + 2))
              {
     -            bad_pkt = TRUE;
     -            BNEP_TRACE_ERROR ("BNEP Received Filter set message with bad length");
     -            break;
    -+           BNEP_TRACE_ERROR(
    -+               "%s: Received BNEP_FILTER_NET_TYPE_SET_MSG with bad length",
    -+               __func__);
    -+           goto bad_packet_length;
    ++            BNEP_TRACE_ERROR(
    ++              "%s: Received BNEP_FILTER_NET_TYPE_SET_MSG with bad length",
    ++              __func__);
    ++            goto bad_packet_length;
              }
              bnepu_process_peer_filter_set (p_bcb, p, len);
              p += len;
    -@@ -819,6 +846,12 @@ UINT8 *bnep_process_control_packet (tBNEP_CONN *p_bcb, UINT8 *p, UINT16 *rem_len
    +@@ -819,6 +845,12 @@ UINT8 *bnep_process_control_packet (tBNEP_CONN *p_bcb, UINT8 *p, UINT16 *rem_len
              break;
      
          case BNEP_FILTER_NET_TYPE_RESPONSE_MSG:
     +        if (*rem_len < 2) {
    -+          BNEP_TRACE_ERROR(
    ++            BNEP_TRACE_ERROR(
     +              "%s: Received BNEP_FILTER_NET_TYPE_RESPONSE_MSG with bad length",
     +              __func__);
    -+          goto bad_packet_length;
    ++            goto bad_packet_length;
     +        }
              bnepu_process_peer_filter_rsp (p_bcb, p);
              p += 2;
              *rem_len = *rem_len - 2;
    -@@ -828,9 +861,10 @@ UINT8 *bnep_process_control_packet (tBNEP_CONN *p_bcb, UINT8 *p, UINT16 *rem_len
    +@@ -828,9 +860,10 @@ UINT8 *bnep_process_control_packet (tBNEP_CONN *p_bcb, UINT8 *p, UINT16 *rem_len
              BE_STREAM_TO_UINT16 (len, p);
              if (*rem_len < (len + 2))
              {
     -            bad_pkt = TRUE;
     -            BNEP_TRACE_ERROR ("BNEP Received Multicast Filter Set message with bad length");
     -            break;
    -+           BNEP_TRACE_ERROR (
    -+               "%s: Received BNEP_FILTER_MULTI_ADDR_SET_MSG with bad length",
    -+               __func__);
    -+           goto bad_packet_length;
    ++            BNEP_TRACE_ERROR(
    ++              "%s: Received BNEP_FILTER_MULTI_ADDR_SET_MSG with bad length",
    ++              __func__);
    ++            goto bad_packet_length;
              }
              bnepu_process_peer_multicast_filter_set (p_bcb, p, len);
              p += len;
    -@@ -838,30 +872,38 @@ UINT8 *bnep_process_control_packet (tBNEP_CONN *p_bcb, UINT8 *p, UINT16 *rem_len
    +@@ -838,30 +871,38 @@ UINT8 *bnep_process_control_packet (tBNEP_CONN *p_bcb, UINT8 *p, UINT16 *rem_len
              break;
      
          case BNEP_FILTER_MULTI_ADDR_RESPONSE_MSG:
     +        if (*rem_len < 2) {
    -+          BNEP_TRACE_ERROR(
    ++            BNEP_TRACE_ERROR(
     +              "%s: Received BNEP_FILTER_MULTI_ADDR_RESPONSE_MSG with bad length",
     +              __func__);
    -+          goto bad_packet_length;
    ++            goto bad_packet_length;
     +        }
              bnepu_process_multicast_filter_rsp (p_bcb, p);
              p += 2;
    @@ -976,17 +229,17 @@ index 13fb189..2250634 100644
     +                         control_type);
              bnep_send_command_not_understood (p_bcb, control_type);
     -        if (is_ext)
    --        {
    -+        if (is_ext && (ext_len > 0)) {
    ++        if (is_ext && (ext_len > 0))
    +         {
     +            if (*rem_len < (ext_len - 1)) {
    -+               goto bad_packet_length;
    ++                goto bad_packet_length;
     +            }
                  p += (ext_len - 1);
                  *rem_len -= (ext_len - 1);
              }
              break;
          }
    - 
    +-
     -    if (bad_pkt)
     -    {
     -        BNEP_TRACE_ERROR ("BNEP - bad ctl pkt length: %d", *rem_len);
    @@ -997,32 +250,34 @@ index 13fb189..2250634 100644
          return p;
     +
     +bad_packet_length:
    -+  BNEP_TRACE_ERROR("%s: bad control packet length: original=%d remaining=%d",
    -+                   __func__, rem_len_orig, *rem_len);
    -+  *rem_len = 0;
    -+  return NULL;
    ++    BNEP_TRACE_ERROR("%s: bad control packet length: original=%d remaining=%d",
    ++                     __func__, rem_len_orig, *rem_len);
    ++    *rem_len = 0;
    ++    return NULL;
      }
      
      
     diff --git a/stack/l2cap/l2cap_client.c b/stack/l2cap/l2cap_client.c
    -index 7e8b3cb..ce58cdc 100644
    +index 7e8b3cb..cd7edfe 100644
     --- a/stack/l2cap/l2cap_client.c
     +++ b/stack/l2cap/l2cap_client.c
    -@@ -370,7 +370,7 @@ static void fragment_packet(l2cap_client_t *client, buffer_t *packet) {
    +@@ -370,7 +370,8 @@ static void fragment_packet(l2cap_client_t *client, buffer_t *packet) {
        assert(packet != NULL);
      
        // TODO(sharvil): eliminate copy into BT_HDR.
     -  BT_HDR *bt_packet = osi_malloc(buffer_length(packet) + L2CAP_MIN_OFFSET);
    -+  BT_HDR *bt_packet = osi_malloc(buffer_length(packet) + L2CAP_MIN_OFFSET + sizeof(BT_HDR));
    ++  BT_HDR *bt_packet = osi_malloc(buffer_length(packet) + L2CAP_MIN_OFFSET +
    ++                                 sizeof(BT_HDR));
        bt_packet->offset = L2CAP_MIN_OFFSET;
        bt_packet->len = buffer_length(packet);
        memcpy(bt_packet->data + bt_packet->offset, buffer_ptr(packet), buffer_length(packet));
    -@@ -384,7 +384,7 @@ static void fragment_packet(l2cap_client_t *client, buffer_t *packet) {
    +@@ -384,7 +385,8 @@ static void fragment_packet(l2cap_client_t *client, buffer_t *packet) {
            break;
          }
      
     -    BT_HDR *fragment = osi_malloc(client->remote_mtu + L2CAP_MIN_OFFSET);
    -+    BT_HDR *fragment = osi_malloc(client->remote_mtu + L2CAP_MIN_OFFSET + sizeof(BT_HDR));
    ++    BT_HDR *fragment = osi_malloc(client->remote_mtu + L2CAP_MIN_OFFSET +
    ++                                  sizeof(BT_HDR));
          fragment->offset = L2CAP_MIN_OFFSET;
          fragment->len = client->remote_mtu;
          memcpy(fragment->data + fragment->offset, bt_packet->data + bt_packet->offset, client->remote_mtu);
    @@ -1058,7 +313,7 @@ index 583a342..6694ff7 100644
              p = p_start = (UINT8*)(p_buf + 1) + L2CAP_MIN_OFFSET;
              *p++ = reject_opcode;
     diff --git a/stack/pan/pan_main.c b/stack/pan/pan_main.c
    -index 5c3a367..044469d 100644
    +index 5c3a367..9268ff9 100644
     --- a/stack/pan/pan_main.c
     +++ b/stack/pan/pan_main.c
     @@ -221,6 +221,38 @@ void pan_conn_ind_cb (UINT16 handle,
    @@ -1087,15 +342,15 @@ index 5c3a367..044469d 100644
     +     */
     +    if ((local_uuid->uu.uuid16 == UUID_SERVCLASS_PANU) &&
     +        (remote_uuid->uu.uuid16 != UUID_SERVCLASS_PANU)) {
    -+      is_valid_interaction = false;
    ++        is_valid_interaction = FALSE;
     +    }
     +    if (!is_valid_interaction) {
    -+      PAN_TRACE_ERROR(
    ++        PAN_TRACE_ERROR(
     +          "PAN Connection failed because of invalid PAN profile roles "
     +          "interaction: Remote UUID 0x%x Local UUID 0x%x",
     +          remote_uuid->uu.uuid16, local_uuid->uu.uuid16);
    -+      BNEP_ConnectResp(handle, BNEP_CONN_FAILED_SRC_UUID);
    -+      return;
    ++        BNEP_ConnectResp(handle, BNEP_CONN_FAILED_SRC_UUID);
    ++        return;
     +    }
      
          /* Requested destination role is */
    diff --git a/system_core.patch b/system_core.patch
    index 1138952..2787712 100644
    --- a/system_core.patch
    +++ b/system_core.patch
    @@ -197,10 +197,18 @@ index cd2d2e6..81628a1 100644
          am.QueueBuiltinAction(console_init_action, "console_init");
      
     diff --git a/libutils/Unicode.cpp b/libutils/Unicode.cpp
    -index ba084f6..22c5b29 100644
    +index ba084f6..bfacf1e 100644
     --- a/libutils/Unicode.cpp
     +++ b/libutils/Unicode.cpp
    -@@ -178,7 +178,15 @@ ssize_t utf32_to_utf8_length(const char32_t *src, size_t src_len)
    +@@ -18,6 +18,7 @@
    + #include <utils/Unicode.h>
    + 
    + #include <stddef.h>
    ++#include <limits.h>
    + 
    + #if defined(_WIN32)
    + # undef  nhtol
    +@@ -178,7 +179,15 @@ ssize_t utf32_to_utf8_length(const char32_t *src, size_t src_len)
          size_t ret = 0;
          const char32_t *end = src + src_len;
          while (src < end) {
    @@ -217,7 +225,7 @@ index ba084f6..22c5b29 100644
          }
          return ret;
      }
    -@@ -438,14 +446,23 @@ ssize_t utf16_to_utf8_length(const char16_t *src, size_t src_len)
    +@@ -438,14 +447,23 @@ ssize_t utf16_to_utf8_length(const char16_t *src, size_t src_len)
          size_t ret = 0;
          const char16_t* const end = src + src_len;
          while (src < end) {
    @@ -243,6 +251,102 @@ index ba084f6..22c5b29 100644
          }
          return ret;
      }
    +diff --git a/libziparchive/zip_archive.cc b/libziparchive/zip_archive.cc
    +index 49097ce..89cfe77 100644
    +--- a/libziparchive/zip_archive.cc
    ++++ b/libziparchive/zip_archive.cc
    +@@ -358,6 +358,8 @@ static int32_t MapCentralDirectory(int fd, const char* debug_file_name,
    +   return result;
    + }
    + 
    ++static inline bool ReadAtOffset(int fd, uint8_t* buf, size_t len, off64_t off);
    ++
    + /*
    +  * Parses the Zip archive's Central Directory.  Allocates and populates the
    +  * hash table.
    +@@ -436,6 +438,22 @@ static int32_t ParseZipArchive(ZipArchive* archive) {
    +       return -1;
    +     }
    +   }
    ++
    ++  uint32_t lfh_start_bytes;
    ++  if (!ReadAtOffset(archive->fd, reinterpret_cast<uint8_t*>(&lfh_start_bytes),
    ++                    sizeof(uint32_t), 0)) {
    ++    ALOGW("Zip: Unable to read header for entry at offset == 0.");
    ++    return -1;
    ++  }
    ++
    ++  if (lfh_start_bytes != LocalFileHeader::kSignature) {
    ++    ALOGW("Zip: Entry at offset zero has invalid LFH signature %" PRIx32, lfh_start_bytes);
    ++#if defined(__ANDROID__)
    ++    android_errorWriteLog(0x534e4554, "64211847");
    ++#endif
    ++    return -1;
    ++  }
    ++
    +   ALOGV("+++ zip good scan %" PRIu16 " entries", num_entries);
    + 
    +   return 0;
    +diff --git a/libziparchive/zip_archive_test.cc b/libziparchive/zip_archive_test.cc
    +index 6aee1bb..b8db6a4 100644
    +--- a/libziparchive/zip_archive_test.cc
    ++++ b/libziparchive/zip_archive_test.cc
    +@@ -603,6 +603,55 @@ TEST(ziparchive, StreamUncompressedBadCrc) {
    +   CloseArchive(handle);
    + }
    + 
    ++// A zip file whose local file header at offset zero is corrupted.
    ++//
    ++// ---------------
    ++// cat foo > a.txt
    ++// zip a.zip a.txt
    ++// cat a.zip | xxd -i
    ++//
    ++// Manual changes :
    ++// [2] = 0xff  // Corrupt the LFH signature of entry 0.
    ++// [3] = 0xff  // Corrupt the LFH signature of entry 0.
    ++static const std::vector<uint8_t> kZipFileWithBrokenLfhSignature{
    ++    //[lfh-sig-----------], [lfh contents---------------------------------
    ++    0x50, 0x4b, 0xff, 0xff, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x77, 0x80,
    ++    //--------------------------------------------------------------------
    ++    0x09, 0x4b, 0xa8, 0x65, 0x32, 0x7e, 0x04, 0x00, 0x00, 0x00, 0x04, 0x00,
    ++    //-------------------------------]  [file-name-----------------], [---
    ++    0x00, 0x00, 0x05, 0x00, 0x1c, 0x00, 0x61, 0x2e, 0x74, 0x78, 0x74, 0x55,
    ++    // entry-contents------------------------------------------------------
    ++    0x54, 0x09, 0x00, 0x03, 0x51, 0x24, 0x8b, 0x59, 0x51, 0x24, 0x8b, 0x59,
    ++    //--------------------------------------------------------------------
    ++    0x75, 0x78, 0x0b, 0x00, 0x01, 0x04, 0x89, 0x42, 0x00, 0x00, 0x04, 0x88,
    ++    //-------------------------------------], [cd-record-sig-------], [---
    ++    0x13, 0x00, 0x00, 0x66, 0x6f, 0x6f, 0x0a, 0x50, 0x4b, 0x01, 0x02, 0x1e,
    ++    // cd-record-----------------------------------------------------------
    ++    0x03, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x77, 0x80, 0x09, 0x4b, 0xa8,
    ++    //--------------------------------------------------------------------
    ++    0x65, 0x32, 0x7e, 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x05,
    ++    //--------------------------------------------------------------------
    ++    0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0xa0,
    ++    //-]  [lfh-file-header-off-], [file-name-----------------], [extra----
    ++    0x81, 0x00, 0x00, 0x00, 0x00, 0x61, 0x2e, 0x74, 0x78, 0x74, 0x55, 0x54,
    ++    //--------------------------------------------------------------------
    ++    0x05, 0x00, 0x03, 0x51, 0x24, 0x8b, 0x59, 0x75, 0x78, 0x0b, 0x00, 0x01,
    ++    //-------------------------------------------------------], [eocd-sig-
    ++    0x04, 0x89, 0x42, 0x00, 0x00, 0x04, 0x88, 0x13, 0x00, 0x00, 0x50, 0x4b,
    ++    //-------], [---------------------------------------------------------
    ++    0x05, 0x06, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x4b, 0x00,
    ++    //-------------------------------------------]
    ++    0x00, 0x00, 0x43, 0x00, 0x00, 0x00, 0x00, 0x00};
    ++
    ++TEST(ziparchive, BrokenLfhSignature) {
    ++  TemporaryFile tmp_file;
    ++  ASSERT_NE(-1, tmp_file.fd);
    ++  ASSERT_TRUE(android::base::WriteFully(tmp_file.fd, &kZipFileWithBrokenLfhSignature[0],
    ++                                        kZipFileWithBrokenLfhSignature.size()));
    ++  ZipArchiveHandle handle;
    ++  ASSERT_EQ(-1, OpenArchiveFd(tmp_file.fd, "LeadingNonZipBytes", &handle));
    ++}
    ++
    + int main(int argc, char** argv) {
    +   ::testing::InitGoogleTest(&argc, argv);
    + 
     diff --git a/rootdir/init.rc b/rootdir/init.rc
     index 7dc9e55..adc062b 100644
     --- a/rootdir/init.rc
    
    From 4c2248ab23b79777940f5ec87fedaf349dcceae3 Mon Sep 17 00:00:00 2001
    From: AndDiSa <anddisa@googlemail.com>
    Date: Sat, 13 Jan 2018 16:48:27 +0100
    Subject: [PATCH 090/159] update patches
    
    Change-Id: I7efc95d46caa67a93c3fbb2c1960ffa8f4593f3e
    ---
     build.patch             |    4 +-
     external_libhevc.patch  | 4160 ++++++++++++++++++++++++++++++++++++++-
     external_libmpeg2.patch | 4160 ++++++++++++++++++++++++++++++++++++++-
     frameworks_av.patch     |  101 +-
     frameworks_base.patch   |  160 +-
     frameworks_native.patch |  186 +-
     system_core.patch       |  202 ++
     system_media.patch      |   17 +
     system_sepolicy.patch   |   89 +-
     9 files changed, 8993 insertions(+), 86 deletions(-)
     create mode 100644 system_media.patch
    
    diff --git a/build.patch b/build.patch
    index 0190f84..02d2ea7 100644
    --- a/build.patch
    +++ b/build.patch
    @@ -323,7 +323,7 @@ index 0000000..ee76dc2
     +ALL_PREBUILT += $(INSTALLED_KERNEL_TARGET)
     +endif
     diff --git a/core/version_defaults.mk b/core/version_defaults.mk
    -index 7c96344..e4077cf 100644
    +index 7c96344..68fcba2 100644
     --- a/core/version_defaults.mk
     +++ b/core/version_defaults.mk
     @@ -131,7 +131,7 @@ ifeq "" "$(PLATFORM_SECURITY_PATCH)"
    @@ -331,7 +331,7 @@ index 7c96344..e4077cf 100644
          #  It must match one of the Android Security Patch Level strings of the Public Security Bulletins.
          #  If there is no $PLATFORM_SECURITY_PATCH set, keep it empty.
     -    PLATFORM_SECURITY_PATCH := 2017-08-05
    -+    PLATFORM_SECURITY_PATCH := 2017-12-05
    ++    PLATFORM_SECURITY_PATCH := 2018-01-05
      endif
      
      ifeq "" "$(PLATFORM_BASE_OS)"
    diff --git a/external_libhevc.patch b/external_libhevc.patch
    index dee93db..467feca 100644
    --- a/external_libhevc.patch
    +++ b/external_libhevc.patch
    @@ -1,3 +1,3959 @@
    +diff --git a/common/arm/ihevc_deblk_chroma_horz.s b/common/arm/ihevc_deblk_chroma_horz.s
    +index 34422ff..b0a79eb 100644
    +--- a/common/arm/ihevc_deblk_chroma_horz.s
    ++++ b/common/arm/ihevc_deblk_chroma_horz.s
    +@@ -36,6 +36,12 @@
    + @*
    + @*******************************************************************************/
    + 
    ++.equ    qp_offset_u_offset,     40
    ++.equ    qp_offset_v_offset,     44
    ++.equ    tc_offset_div2_offset,  48
    ++.equ    filter_p_offset,        52
    ++.equ    filter_q_offset,        56
    ++
    + .text
    + .align 4
    + 
    +@@ -62,17 +68,17 @@ ihevc_deblk_chroma_horz_a9q:
    +     add         r6,r0,r1
    +     add         r1,r2,r3
    +     vmovl.u8    q0,d0
    +-    ldr         r10,[sp,#0x28]
    ++    ldr         r10,[sp,#qp_offset_u_offset]
    +     vld1.8      {d2},[r12]
    +     add         r2,r1,#1
    +-    ldr         r4,[sp,#0x30]
    ++    ldr         r4,[sp,#tc_offset_div2_offset]
    +     vld1.8      {d4},[r5]
    +-    ldr         r8,[sp,#0x34]
    ++    ldr         r8,[sp,#filter_p_offset]
    +     vld1.8      {d16},[r6]
    +-    ldr         r9,[sp,#0x38]
    ++    ldr         r9,[sp,#filter_q_offset]
    +     adds        r1,r10,r2,asr #1
    +     vmovl.u8    q1,d2
    +-    ldr         r7,[sp,#0x2c]
    ++    ldr         r7,[sp,#qp_offset_v_offset]
    +     ldr         r3,gai4_ihevc_qp_table_addr
    + ulbl1:
    +     add         r3, r3, pc
    +diff --git a/common/arm/ihevc_deblk_chroma_vert.s b/common/arm/ihevc_deblk_chroma_vert.s
    +index 4cb305f..3962b28 100644
    +--- a/common/arm/ihevc_deblk_chroma_vert.s
    ++++ b/common/arm/ihevc_deblk_chroma_vert.s
    +@@ -37,6 +37,12 @@
    + @*
    + @*******************************************************************************/
    + 
    ++.equ    qp_offset_u_offset,     40
    ++.equ    qp_offset_v_offset,     44
    ++.equ    tc_offset_div2_offset,  48
    ++.equ    filter_p_offset,        52
    ++.equ    filter_q_offset,        56
    ++
    + .text
    + .align 4
    + 
    +@@ -63,19 +69,19 @@ ihevc_deblk_chroma_vert_a9q:
    +     vld1.8      {d5},[r8],r1
    +     add         r2,r2,#1
    +     vld1.8      {d17},[r8],r1
    +-    ldr         r7,[sp,#0x28]
    ++    ldr         r7,[sp,#qp_offset_u_offset]
    +     vld1.8      {d16},[r8],r1
    +-    ldr         r4,[sp,#0x38]
    ++    ldr         r4,[sp,#filter_q_offset]
    +     vld1.8      {d4},[r8]
    +-    ldr         r5,[sp,#0x30]
    ++    ldr         r5,[sp,#tc_offset_div2_offset]
    +     vtrn.8      d5,d17
    +     adds        r3,r7,r2,asr #1
    +     vtrn.8      d16,d4
    +     ldr         r7,gai4_ihevc_qp_table_addr
    + ulbl1:
    +     add         r7,r7,pc
    +-    ldr         r12,[sp,#0x34]
    +-    ldr         r6,[sp,#0x2c]
    ++    ldr         r12,[sp,#filter_p_offset]
    ++    ldr         r6,[sp,#qp_offset_v_offset]
    +     bmi         l1.2944
    +     cmp         r3,#0x39
    +     ldrle       r3,[r7,r3,lsl #2]
    +diff --git a/common/arm/ihevc_deblk_luma_horz.s b/common/arm/ihevc_deblk_luma_horz.s
    +index b12ceb9..76660b3 100644
    +--- a/common/arm/ihevc_deblk_luma_horz.s
    ++++ b/common/arm/ihevc_deblk_luma_horz.s
    +@@ -36,6 +36,12 @@
    + @*
    + @*******************************************************************************/
    + 
    ++.equ    qp_q_offset,                108
    ++.equ    beta_offset_div2_offset,    112
    ++.equ    tc_offset_div2_offset,      116
    ++.equ    filter_p_offset,            120
    ++.equ    filter_q_offset,            124
    ++
    + .text
    + .align 4
    + 
    +@@ -57,12 +63,14 @@ gai4_ihevc_beta_table_addr:
    + 
    + ihevc_deblk_luma_horz_a9q:
    +     stmfd       sp!, {r3-r12,lr}
    +-    ldr         r4,[sp,#0x2c]
    +-    ldr         r5,[sp,#0x30]
    ++    vpush       {d8  -  d15}
    ++
    ++    ldr         r4,[sp,#qp_q_offset]
    ++    ldr         r5,[sp,#beta_offset_div2_offset]
    + 
    +     add         r3,r3,r4
    +     add         r3,r3,#1
    +-    ldr         r6, [sp,#0x34]
    ++    ldr         r6, [sp,#tc_offset_div2_offset]
    +     asr         r3,r3,#1
    +     add         r7,r3,r5,lsl #1
    +     add         r3,r3,r6,lsl #1
    +@@ -291,9 +299,9 @@ ulbl1:
    +     vmin.u8     d18,d20,d30
    +     mov         r2,#2
    +     vqadd.u8    d30,d23,d1
    +-    ldr         r4,[sp,#0x38]               @ loading the filter_flag_p
    ++    ldr         r4,[sp,#filter_p_offset]         @ loading the filter_flag_p
    +     vmax.u8     d2,d18,d31
    +-    ldr         r5,[sp,#0x3c]               @ loading the filter_flag_q
    ++    ldr         r5,[sp,#filter_q_offset]         @ loading the filter_flag_q
    +     vrshrn.i16  d21,q7,#2
    +     b           end_dep_deq_decision_horz
    +     @ r2 has the value of de
    +@@ -308,8 +316,8 @@ l1.1840:
    +     mov         r2,#1
    + 
    +     mov         r11,r5
    +-    ldr         r4,[sp,#0x38]               @ loading the filter_flag_p
    +-    ldr         r5,[sp,#0x3c]               @ loading the filter_flag_q
    ++    ldr         r4,[sp,#filter_p_offset]         @ loading the filter_flag_p
    ++    ldr         r5,[sp,#filter_q_offset]         @ loading the filter_flag_q
    + 
    +     cmp         r6,#1
    +     moveq       r9,#0
    +@@ -397,6 +405,7 @@ strong_filtering_p:
    +     vst1.32     d3[0],[r12]
    + 
    + l1.2404:
    ++    vpop        {d8  -  d15}
    +     ldmfd       sp!, {r3-r12,pc}
    + 
    +     @ r4=flag p
    +@@ -537,6 +546,8 @@ l1.2852:
    +     vbsl        d19,d26,d13
    +     vst1.32     {d19[0]},[r12],r1
    +     vst1.32     {d18[0]},[r12]
    ++
    ++    vpop        {d8  -  d15}
    +     ldmfd       sp!, {r3-r12,r15}
    + 
    + 
    +diff --git a/common/arm/ihevc_deblk_luma_vert.s b/common/arm/ihevc_deblk_luma_vert.s
    +index ee247cc..91662c9 100644
    +--- a/common/arm/ihevc_deblk_luma_vert.s
    ++++ b/common/arm/ihevc_deblk_luma_vert.s
    +@@ -37,6 +37,12 @@
    + @*
    + @*******************************************************************************/
    + 
    ++.equ    qp_q_offset,                44
    ++.equ    beta_offset_div2_offset,    48
    ++.equ    tc_offset_div2_offset,      52
    ++.equ    filter_p_offset,            56
    ++.equ    filter_q_offset,            60
    ++
    + .text
    + .align 4
    + 
    +@@ -60,12 +66,12 @@ gai4_ihevc_beta_table_addr:
    + ihevc_deblk_luma_vert_a9q:
    + 
    +     push        {r3-r12,lr}
    +-    ldr         r4,[sp,#0x2c]
    +-    ldr         r5,[sp,#0x30]
    ++    ldr         r4,[sp,#qp_q_offset]
    ++    ldr         r5,[sp,#beta_offset_div2_offset]
    + 
    +     add         r3,r3,r4
    +     add         r3,r3,#1
    +-    ldr         r6, [sp,#0x34]
    ++    ldr         r6, [sp,#tc_offset_div2_offset]
    +     asr         r3,r3,#1
    +     add         r7,r3,r5,lsl #1
    +     add         r3,r3,r6,lsl #1
    +@@ -291,9 +297,9 @@ ulbl1:
    +     vqadd.u8    d30,d6,d19
    + 
    +     mov         r2,#2
    +-    ldr         r4,[sp,#0x38]               @ loading the filter_flag_p
    ++    ldr         r4,[sp,#filter_p_offset]        @ loading the filter_flag_p
    +     vqsub.u8    d31,d6,d19
    +-    ldr         r5,[sp,#0x3c]               @ loading the filter_flag_q
    ++    ldr         r5,[sp,#filter_q_offset]        @ loading the filter_flag_q
    +     b           end_dep_deq_decision
    + @ r2 has the value of de
    + @ r6 has teh value of tc
    +@@ -307,8 +313,8 @@ l1.336:
    +     mov         r2,#1
    + l1.424:
    +     mov         r11,r5
    +-    ldr         r4,[sp,#0x38]               @ loading the filter_flag_p
    +-    ldr         r5,[sp,#0x3c]               @ loading the filter_flag_q
    ++    ldr         r4,[sp,#filter_p_offset]        @ loading the filter_flag_p
    ++    ldr         r5,[sp,#filter_q_offset]        @ loading the filter_flag_q
    + 
    +     cmp         r6,#1
    +     moveq       r9,#0
    +@@ -532,7 +538,6 @@ l1.1212:
    +     vst1.16     {d3[1]},[r12]
    +     vst1.8      {d16[3]},[r3]
    + l1.1272:
    +-    @   ldr      r3,[sp,#0x38]
    +     cmp         r5,#0
    +     beq         l1.964
    +     @ checks for the flag q
    +diff --git a/common/arm/ihevc_inter_pred_chroma_copy.s b/common/arm/ihevc_inter_pred_chroma_copy.s
    +index 0da34cc..1b38dbb 100644
    +--- a/common/arm/ihevc_inter_pred_chroma_copy.s
    ++++ b/common/arm/ihevc_inter_pred_chroma_copy.s
    +@@ -92,6 +92,9 @@
    + @               r5 =>  ht
    + @               r6 =>  wd
    + 
    ++.equ    ht_offset,      44
    ++.equ    wd_offset,      48
    ++
    + .text
    + .align 4
    + 
    +@@ -104,9 +107,9 @@
    + 
    + ihevc_inter_pred_chroma_copy_a9q:
    +     stmfd       sp!, {r4-r12, r14}          @stack stores the values of the arguments
    +-    ldr         r12,[sp,#48]                @loads wd
    ++    ldr         r12,[sp,#wd_offset]         @loads wd
    +     lsl         r12,r12,#1
    +-    ldr         r7,[sp,#44]                 @loads ht
    ++    ldr         r7,[sp,#ht_offset]          @loads ht
    +     cmp         r7,#0                       @checks ht == 0
    +     ble         end_loops
    +     and         r8,r7,#3                    @check ht for mul of 2
    +diff --git a/common/arm/ihevc_inter_pred_chroma_copy_w16out.s b/common/arm/ihevc_inter_pred_chroma_copy_w16out.s
    +index a927fa7..4997b84 100644
    +--- a/common/arm/ihevc_inter_pred_chroma_copy_w16out.s
    ++++ b/common/arm/ihevc_inter_pred_chroma_copy_w16out.s
    +@@ -92,6 +92,11 @@
    + @r5 =>  ht
    + @r6 =>  wd
    + 
    ++.equ    coeff_offset,   104
    ++.equ    ht_offset,      108
    ++.equ    wd_offset,      112
    ++
    ++
    + .text
    + .align 4
    + 
    +@@ -105,9 +110,11 @@
    + ihevc_inter_pred_chroma_copy_w16out_a9q:
    + 
    +     stmfd       sp!, {r4-r12, r14}          @stack stores the values of the arguments
    +-    ldr         r12,[sp,#48]                @loads wd
    ++    vpush        {d8 - d15}
    ++
    ++    ldr         r12,[sp,#wd_offset]                @loads wd
    +     lsl         r12,r12,#1                  @2*wd
    +-    ldr         r7,[sp,#44]                 @loads ht
    ++    ldr         r7,[sp,#ht_offset]                 @loads ht
    +     cmp         r7,#0                       @ht condition(ht == 0)
    +     ble         end_loops                   @loop
    +     and         r8,r7,#3                    @check ht for mul of 2
    +@@ -162,6 +169,7 @@ end_inner_loop_wd_4:
    + 
    + 
    + end_loops:
    ++    vpop         {d8 - d15}
    +     ldmfd       sp!,{r4-r12,r15}            @reload the registers from sp
    + 
    + 
    +@@ -316,6 +324,7 @@ core_loop_wd_8_ht_2:
    +     vst1.16     {d2,d3},[r10],r5            @vst1q_s16(pi2_dst_tmp, tmp)
    +     bgt         core_loop_wd_8_ht_2
    + 
    ++    vpop         {d8 - d15}
    +     ldmfd       sp!,{r4-r12,r15}            @reload the registers from sp
    + 
    + 
    +diff --git a/common/arm/ihevc_inter_pred_chroma_horz.s b/common/arm/ihevc_inter_pred_chroma_horz.s
    +index 4781d3e..c69b417 100644
    +--- a/common/arm/ihevc_inter_pred_chroma_horz.s
    ++++ b/common/arm/ihevc_inter_pred_chroma_horz.s
    +@@ -93,6 +93,10 @@
    + @r2 =>  src_strd
    + @r3 =>  dst_strd
    + 
    ++.equ    coeff_offset,   104
    ++.equ    ht_offset,      108
    ++.equ    wd_offset,      112
    ++
    + .text
    + .align 4
    + 
    +@@ -106,10 +110,11 @@
    + ihevc_inter_pred_chroma_horz_a9q:
    + 
    +     stmfd       sp!, {r4-r12, r14}          @stack stores the values of the arguments
    ++    vpush        {d8 - d15}
    + 
    +-    ldr         r4,[sp,#40]                 @loads pi1_coeff
    +-    ldr         r7,[sp,#44]                 @loads ht
    +-    ldr         r10,[sp,#48]                @loads wd
    ++    ldr         r4,[sp,#coeff_offset]                 @loads pi1_coeff
    ++    ldr         r7,[sp,#ht_offset]                 @loads ht
    ++    ldr         r10,[sp,#wd_offset]                @loads wd
    + 
    +     vld1.8      {d0},[r4]                   @coeff = vld1_s8(pi1_coeff)
    +     subs        r14,r7,#0                   @checks for ht == 0
    +@@ -672,6 +677,7 @@ inner_loop_4:
    + 
    + end_loops:
    + 
    ++    vpop         {d8 - d15}
    +     ldmfd       sp!,{r4-r12,r15}            @reload the registers from sp
    + 
    + 
    +diff --git a/common/arm/ihevc_inter_pred_chroma_horz_w16out.s b/common/arm/ihevc_inter_pred_chroma_horz_w16out.s
    +index f95937c..9c498e8 100644
    +--- a/common/arm/ihevc_inter_pred_chroma_horz_w16out.s
    ++++ b/common/arm/ihevc_inter_pred_chroma_horz_w16out.s
    +@@ -90,6 +90,9 @@
    + @r2 =>  src_strd
    + @r3 =>  dst_strd
    + 
    ++.equ    coeff_offset,   104
    ++.equ    ht_offset,      108
    ++.equ    wd_offset,      112
    + 
    + .text
    + .align 4
    +@@ -105,10 +108,11 @@
    + ihevc_inter_pred_chroma_horz_w16out_a9q:
    + 
    +     stmfd       sp!, {r4-r12, r14}          @stack stores the values of the arguments
    ++    vpush        {d8 - d15}
    + 
    +-    ldr         r4,[sp,#40]                 @loads pi1_coeff
    +-    ldr         r6,[sp,#44]                 @loads ht
    +-    ldr         r10,[sp,#48]                @loads wd
    ++    ldr         r4,[sp,#coeff_offset]                 @loads pi1_coeff
    ++    ldr         r6,[sp,#ht_offset]                 @loads ht
    ++    ldr         r10,[sp,#wd_offset]                @loads wd
    + 
    +     vld1.8      {d0},[r4]                   @coeff = vld1_s8(pi1_coeff)
    +     subs        r14,r6,#0                   @checks for ht == 0
    +@@ -362,7 +366,7 @@ epilog_end:
    +     vst1.16     {q10},[r1],r6               @store the result pu1_dst
    + 
    + 
    +-    ldr         r6,[sp,#44]                 @loads ht
    ++    ldr         r6,[sp,#ht_offset]                 @loads ht
    + 
    +     and         r7,r6,#1
    + 
    +@@ -710,6 +714,7 @@ loop_residue:
    + 
    + end_loops:
    + 
    ++    vpop         {d8 - d15}
    +     ldmfd       sp!,{r4-r12,r15}            @reload the registers from sp
    + 
    + 
    +diff --git a/common/arm/ihevc_inter_pred_chroma_vert.s b/common/arm/ihevc_inter_pred_chroma_vert.s
    +index e786497..8b4e48b 100644
    +--- a/common/arm/ihevc_inter_pred_chroma_vert.s
    ++++ b/common/arm/ihevc_inter_pred_chroma_vert.s
    +@@ -92,6 +92,11 @@
    + @r1 => *pi2_dst
    + @r2 =>  src_strd
    + @r3 =>  dst_strd
    ++
    ++.equ    coeff_offset,   104
    ++.equ    ht_offset,      108
    ++.equ    wd_offset,      112
    ++
    + .text
    + .align 4
    + 
    +@@ -105,11 +110,12 @@
    + ihevc_inter_pred_chroma_vert_a9q:
    + 
    +     stmfd       sp!,{r4-r12,r14}            @stack stores the values of the arguments
    ++    vpush        {d8 - d15}
    + 
    +-    ldr         r4,[sp,#44]                 @loads ht
    +-    ldr         r12,[sp,#40]                @loads pi1_coeff
    ++    ldr         r4,[sp,#ht_offset]                 @loads ht
    ++    ldr         r12,[sp,#coeff_offset]                @loads pi1_coeff
    +     cmp         r4,#0                       @checks ht == 0
    +-    ldr         r6,[sp,#48]                 @loads wd
    ++    ldr         r6,[sp,#wd_offset]                 @loads wd
    +     sub         r0,r0,r2                    @pu1_src - src_strd
    +     vld1.8      {d0},[r12]                  @loads pi1_coeff
    + 
    +@@ -377,6 +383,7 @@ epilog:
    +     vqrshrun.s16 d24,q12,#6
    +     vst1.8      {d24},[r7],r3               @stores the loaded value
    + end_loops:
    ++    vpop         {d8 - d15}
    +     ldmfd       sp!,{r4-r12,r15}            @reload the registers from sp
    + 
    + 
    +diff --git a/common/arm/ihevc_inter_pred_chroma_vert_w16inp.s b/common/arm/ihevc_inter_pred_chroma_vert_w16inp.s
    +index ba2ea8e..f9e513a 100644
    +--- a/common/arm/ihevc_inter_pred_chroma_vert_w16inp.s
    ++++ b/common/arm/ihevc_inter_pred_chroma_vert_w16inp.s
    +@@ -92,6 +92,11 @@
    + @r2 =>  src_strd
    + @r3 =>  dst_strd
    + 
    ++.equ    coeff_offset,   104
    ++.equ    ht_offset,      108
    ++.equ    wd_offset,      112
    ++
    ++
    + .text
    + .align 4
    + 
    +@@ -105,11 +110,12 @@
    + ihevc_inter_pred_chroma_vert_w16inp_a9q:
    + 
    +     stmfd       sp!, {r4-r12, r14}          @stack stores the values of the arguments
    ++    vpush        {d8 - d15}
    + 
    +-    ldr         r4, [sp,#40]                @loads pi1_coeff
    +-    ldr         r6, [sp,#48]                @wd
    ++    ldr         r4, [sp,#coeff_offset]                @loads pi1_coeff
    ++    ldr         r6, [sp,#wd_offset]                @wd
    +     lsl         r2,r2,#1                    @src_strd = 2* src_strd
    +-    ldr         r5,[sp,#44]                 @loads ht
    ++    ldr         r5,[sp,#ht_offset]                 @loads ht
    +     vld1.8      {d0},[r4]                   @loads pi1_coeff
    +     sub         r4,r0,r2                    @pu1_src - src_strd
    +     vmovl.s8    q0,d0                       @long the value
    +@@ -335,6 +341,7 @@ epilog:
    +     vst1.32     {d24[0]},[r9]               @stores the loaded value
    + 
    + end_loops:
    ++    vpop         {d8 - d15}
    +     ldmfd       sp!,{r4-r12,r15}            @reload the registers from sp
    + 
    + 
    +diff --git a/common/arm/ihevc_inter_pred_chroma_vert_w16inp_w16out.s b/common/arm/ihevc_inter_pred_chroma_vert_w16inp_w16out.s
    +index 00b3011..0c2ffbd 100644
    +--- a/common/arm/ihevc_inter_pred_chroma_vert_w16inp_w16out.s
    ++++ b/common/arm/ihevc_inter_pred_chroma_vert_w16inp_w16out.s
    +@@ -92,6 +92,11 @@
    + @r1 => *pi2_dst
    + @r2 =>  src_strd
    + @r3 =>  dst_strd
    ++
    ++.equ    coeff_offset,   104
    ++.equ    ht_offset,      108
    ++.equ    wd_offset,      112
    ++
    + .text
    + .align 4
    + 
    +@@ -105,11 +110,12 @@
    + ihevc_inter_pred_chroma_vert_w16inp_w16out_a9q:
    + 
    +     stmfd       sp!, {r4-r12, r14}          @stack stores the values of the arguments
    ++    vpush        {d8 - d15}
    + 
    +-    ldr         r4, [sp,#40]                @loads pi1_coeff
    +-    ldr         r6, [sp,#48]                @wd
    ++    ldr         r4, [sp,#coeff_offset]                @loads pi1_coeff
    ++    ldr         r6, [sp,#wd_offset]                @wd
    +     lsl         r2,r2,#1                    @src_strd = 2* src_strd
    +-    ldr         r5,[sp,#44]                 @loads ht
    ++    ldr         r5,[sp,#ht_offset]                 @loads ht
    +     vld1.8      {d0},[r4]                   @loads pi1_coeff
    +     sub         r4,r0,r2                    @pu1_src - src_strd
    +     vmovl.s8    q0,d0                       @long the value
    +@@ -322,6 +328,7 @@ epilog:
    +     vst1.32     {d24},[r9]                  @stores the loaded value
    + 
    + end_loops:
    ++    vpop         {d8 - d15}
    +     ldmfd       sp!,{r4-r12,r15}            @reload the registers from sp
    + 
    + 
    +diff --git a/common/arm/ihevc_inter_pred_chroma_vert_w16out.s b/common/arm/ihevc_inter_pred_chroma_vert_w16out.s
    +index 6e6776c..84b0792 100644
    +--- a/common/arm/ihevc_inter_pred_chroma_vert_w16out.s
    ++++ b/common/arm/ihevc_inter_pred_chroma_vert_w16out.s
    +@@ -93,6 +93,10 @@
    + @r2 =>  src_strd
    + @r3 =>  dst_strd
    + 
    ++.equ    coeff_offset,   104
    ++.equ    ht_offset,      108
    ++.equ    wd_offset,      112
    ++
    + .text
    + .align 4
    + 
    +@@ -106,11 +110,12 @@
    + ihevc_inter_pred_chroma_vert_w16out_a9q:
    + 
    +     stmfd       sp!,{r4-r12,r14}            @stack stores the values of the arguments
    ++    vpush        {d8 - d15}
    + 
    +-    ldr         r4,[sp,#44]                 @loads ht
    +-    ldr         r12,[sp,#40]                @loads pi1_coeff
    ++    ldr         r4,[sp,#ht_offset]                 @loads ht
    ++    ldr         r12,[sp,#coeff_offset]                @loads pi1_coeff
    +     cmp         r4,#0                       @checks ht == 0
    +-    ldr         r6,[sp,#48]                 @loads wd
    ++    ldr         r6,[sp,#wd_offset]                 @loads wd
    +     sub         r0,r0,r2                    @pu1_src - src_strd
    +     vld1.8      {d0},[r12]                  @loads pi1_coeff
    + 
    +@@ -361,6 +366,7 @@ epilog:
    +     vst1.8      {q12},[r7],r3               @stores the loaded value
    + 
    + end_loops:
    ++    vpop         {d8 - d15}
    +     ldmfd       sp!,{r4-r12,r15}            @reload the registers from sp
    + 
    + 
    +diff --git a/common/arm/ihevc_inter_pred_filters_luma_horz.s b/common/arm/ihevc_inter_pred_filters_luma_horz.s
    +index 215f8fd..5559aa7 100644
    +--- a/common/arm/ihevc_inter_pred_filters_luma_horz.s
    ++++ b/common/arm/ihevc_inter_pred_filters_luma_horz.s
    +@@ -103,6 +103,11 @@
    + @   r5 =>  ht
    + @   r6 =>  wd
    + 
    ++
    ++.equ    coeff_offset,   104
    ++.equ    ht_offset,      108
    ++.equ    wd_offset,      112
    ++
    + .text
    + .align 4
    + 
    +@@ -116,15 +121,15 @@
    + ihevc_inter_pred_luma_horz_a9q:
    + 
    +     stmfd       sp!, {r4-r12, r14}          @stack stores the values of the arguments
    +-    @str        r1,[sp,#-4]
    +-    @ mov       r7,#8192
    ++    vpush        {d8 - d15}
    ++
    ++
    + start_loop_count:
    +-    @ ldr       r1,[sp,#-4]
    + 
    + 
    +-    ldr         r4,[sp,#40]                 @loads pi1_coeff
    +-    ldr         r8,[sp,#44]                 @loads ht
    +-    ldr         r10,[sp,#48]                @loads wd
    ++    ldr         r4,[sp,#coeff_offset]                 @loads pi1_coeff
    ++    ldr         r8,[sp,#ht_offset]                 @loads ht
    ++    ldr         r10,[sp,#wd_offset]                @loads wd
    + 
    +     vld1.8      {d0},[r4]                   @coeff = vld1_s8(pi1_coeff)
    +     mov         r11,#1
    +@@ -262,7 +267,8 @@ end_inner_loop_8:
    + 
    + 
    + 
    +-    ldr         r10,[sp,#48]                @loads wd
    ++    ldr         r10,[sp,#wd_offset]                @loads wd
    ++
    +     cmp         r10,#12
    + 
    +     beq         outer_loop4_residual
    +@@ -270,6 +276,7 @@ end_inner_loop_8:
    + 
    + end_loops:
    + 
    ++    vpop         {d8 - d15}
    +     ldmfd       sp!,{r4-r12,r15}            @reload the registers from sp
    + 
    + 
    +@@ -417,7 +424,7 @@ epilog_16:
    + 
    +     ldr         r7, [sp], #4
    +     ldr         r0, [sp], #4
    +-    ldr         r10,[sp,#48]
    ++    ldr         r10,[sp,#wd_offset]
    +     cmp         r10,#24
    + 
    +     beq         outer_loop8_residual
    +@@ -426,6 +433,7 @@ epilog_16:
    + 
    + end_loops1:
    + 
    ++    vpop         {d8 - d15}
    +     ldmfd       sp!,{r4-r12,r15}            @reload the registers from sp
    + 
    + 
    +@@ -527,6 +535,7 @@ end_inner_loop_4:
    +     @subs   r7,r7,#1
    +     @ bgt   start_loop_count
    + 
    ++    vpop         {d8 - d15}
    +     ldmfd       sp!,{r4-r12,r15}            @reload the registers from sp
    + 
    + 
    +diff --git a/common/arm/ihevc_inter_pred_filters_luma_vert.s b/common/arm/ihevc_inter_pred_filters_luma_vert.s
    +index f51d68c..3d9ab1c 100644
    +--- a/common/arm/ihevc_inter_pred_filters_luma_vert.s
    ++++ b/common/arm/ihevc_inter_pred_filters_luma_vert.s
    +@@ -103,6 +103,11 @@
    + @   r12 => *pi1_coeff
    + @   r5 =>  ht
    + @   r3 =>  wd
    ++
    ++.equ    coeff_offset,   104
    ++.equ    ht_offset,      108
    ++.equ    wd_offset,      112
    ++
    + .text
    + .align 4
    + .syntax unified
    +@@ -116,15 +121,16 @@
    + ihevc_inter_pred_luma_vert_a9q:
    + 
    +     stmfd       sp!, {r4-r12, r14}          @stack stores the values of the arguments
    ++    vpush        {d8 - d15}
    + 
    +-    ldr         r12,[sp,#40]                @load pi1_coeff
    ++    ldr         r12,[sp,#coeff_offset]                @load pi1_coeff
    +     mov         r6,r3
    +-    ldr         r5,[sp,#48]                 @load wd
    ++    ldr         r5,[sp,#wd_offset]                 @load wd
    +     vld1.u8     {d0},[r12]                  @coeff = vld1_s8(pi1_coeff)
    +     sub         r12,r2,r2,lsl #2            @src_ctrd & pi1_coeff
    +     vabs.s8     d0,d0                       @vabs_s8(coeff)
    +     add         r0,r0,r12                   @r0->pu1_src    r12->pi1_coeff
    +-    ldr         r3,[sp,#44]                 @load ht
    ++    ldr         r3,[sp,#ht_offset]                 @load ht
    +     subs        r7,r3,#0                    @r3->ht
    +     @ble        end_loops           @end loop jump
    +     vdup.u8     d22,d0[0]                   @coeffabs_0 = vdup_lane_u8(coeffabs, 0)@
    +@@ -407,7 +413,8 @@ end_loops:
    +     ldr         r1, [sp], #4
    +     ldr         r0, [sp], #4
    + 
    +-    ldmfdeq     sp!,{r4-r12,r15}            @reload the registers from sp
    ++    beq         end1
    ++
    +     mov         r5, #4
    +     add         r0, r0, #8
    +     add         r1, r1, #8
    +@@ -491,6 +498,8 @@ end_inner_loop_wd_4:
    +     add         r0,r0,r8
    +     bgt         outer_loop_wd_4
    + 
    ++end1:
    ++    vpop         {d8 - d15}
    +     ldmfd       sp!, {r4-r12, r15}          @reload the registers from sp
    + 
    + 
    +@@ -564,15 +573,16 @@ end_inner_loop_wd_4:
    + ihevc_inter_pred_luma_vert_w16out_a9q:
    + 
    +     stmfd       sp!, {r4-r12, r14}          @stack stores the values of the arguments
    ++    vpush        {d8 - d15}
    + 
    +-    ldr         r12,[sp,#40]                @load pi1_coeff
    ++    ldr         r12,[sp,#coeff_offset]                @load pi1_coeff
    +     mov         r6,r3
    +-    ldr         r5,[sp,#48]                 @load wd
    ++    ldr         r5,[sp,#wd_offset]                 @load wd
    +     vld1.u8     {d0},[r12]                  @coeff = vld1_s8(pi1_coeff)
    +     sub         r12,r2,r2,lsl #2            @src_ctrd & pi1_coeff
    +     vabs.s8     d0,d0                       @vabs_s8(coeff)
    +     add         r0,r0,r12                   @r0->pu1_src    r12->pi1_coeff
    +-    ldr         r3,[sp,#44]                 @load ht
    ++    ldr         r3,[sp,#ht_offset]                 @load ht
    +     subs        r7,r3,#0                    @r3->ht
    +     @ble        end_loops_16out         @end loop jump
    +     vdup.u8     d22,d0[0]                   @coeffabs_0 = vdup_lane_u8(coeffabs, 0)@
    +@@ -848,7 +858,8 @@ end_loops_16out:
    +     ldr         r1, [sp], #4
    +     ldr         r0, [sp], #4
    + 
    +-    ldmfdeq     sp!,{r4-r12,r15}            @reload the registers from sp
    ++    beq         end2
    ++
    +     mov         r5, #4
    +     add         r0, r0, #8
    +     add         r1, r1, #16
    +@@ -934,7 +945,8 @@ end_inner_loop_wd_4_16out:
    +     add         r1,r1,r9,lsl #1
    +     add         r0,r0,r8
    +     bgt         outer_loop_wd_4_16out
    +-
    ++end2:
    ++    vpop         {d8 - d15}
    +     ldmfd       sp!, {r4-r12, r15}          @reload the registers from sp
    + 
    + 
    +diff --git a/common/arm/ihevc_inter_pred_filters_luma_vert_w16inp.s b/common/arm/ihevc_inter_pred_filters_luma_vert_w16inp.s
    +index 4fbc5d1..9726710 100644
    +--- a/common/arm/ihevc_inter_pred_filters_luma_vert_w16inp.s
    ++++ b/common/arm/ihevc_inter_pred_filters_luma_vert_w16inp.s
    +@@ -94,6 +94,10 @@
    + @                                    word32 ht,
    + @                                    word32 wd   )
    + 
    ++.equ    coeff_offset,   104
    ++.equ    ht_offset,      108
    ++.equ    wd_offset,      112
    ++
    + .text
    + .align 4
    + 
    +@@ -107,16 +111,17 @@
    + ihevc_inter_pred_luma_vert_w16inp_a9q:
    + 
    +     stmfd       sp!, {r4-r12, r14}          @stack stores the values of the arguments
    ++    vpush        {d8 - d15}
    + 
    +-    ldr         r12,[sp,#40]                @load pi1_coeff
    ++    ldr         r12,[sp,#coeff_offset]                @load pi1_coeff
    +     mov         r6,r3
    +-    ldr         r5,[sp,#48]                 @load wd
    ++    ldr         r5,[sp,#wd_offset]                 @load wd
    +     vld1.8      {d0},[r12]                  @coeff = vld1_s8(pi1_coeff)
    +     mov         r2, r2, lsl #1
    +     sub         r12,r2,r2,lsl #2            @src_ctrd & pi1_coeff
    +     @vabs.s8    d0,d0               @vabs_s8(coeff)
    +     add         r0,r0,r12                   @r0->pu1_src    r12->pi1_coeff
    +-    ldr         r3,[sp,#44]                 @load ht
    ++    ldr         r3,[sp,#ht_offset]                 @load ht
    +     subs        r7,r3,#0                    @r3->ht
    +     @ble        end_loops           @end loop jump
    +     vmovl.s8    q0,d0
    +@@ -370,6 +375,7 @@ epilog_end:
    + 
    + end_loops:
    + 
    ++    vpop         {d8 - d15}
    +     ldmfd       sp!,{r4-r12,r15}            @reload the registers from sp
    + 
    + 
    +diff --git a/common/arm/ihevc_inter_pred_luma_copy.s b/common/arm/ihevc_inter_pred_luma_copy.s
    +index 8a61369..e4f5573 100644
    +--- a/common/arm/ihevc_inter_pred_luma_copy.s
    ++++ b/common/arm/ihevc_inter_pred_luma_copy.s
    +@@ -71,6 +71,10 @@
    + @   r7 =>  ht
    + @   r12 => wd
    + 
    ++.equ    coeff_offset,   104
    ++.equ    ht_offset,      108
    ++.equ    wd_offset,      112
    ++
    + .text
    + .align 4
    + 
    +@@ -83,8 +87,9 @@
    + 
    + ihevc_inter_pred_luma_copy_a9q:
    +     stmfd       sp!, {r4-r12, r14}          @stack stores the values of the arguments
    +-    ldr         r12,[sp,#48]                @loads wd
    +-    ldr         r7,[sp,#44]                 @loads ht
    ++    vpush        {d8 - d15}
    ++    ldr         r12,[sp,#wd_offset]                @loads wd
    ++    ldr         r7,[sp,#ht_offset]                 @loads ht
    +     cmp         r7,#0                       @checks ht == 0
    +     ble         end_loops
    +     tst         r12,#15                     @checks wd for multiples for 4 & 8
    +@@ -121,6 +126,7 @@ end_inner_loop_wd_4:
    +     bgt         outer_loop_wd_4
    + 
    + end_loops:
    ++    vpop         {d8 - d15}
    +     ldmfd       sp!,{r4-r12,r15}            @reload the registers from sp
    + 
    + 
    +@@ -151,6 +157,7 @@ end_inner_loop_wd_8:
    +     sub         r1,r6,r11                   @pu1_dst = pu1_dst_tmp
    +     bgt         outer_loop_wd_8
    + 
    ++    vpop         {d8 - d15}
    +     ldmfd       sp!,{r4-r12,r15}            @reload the registers from sp
    + 
    + core_loop_wd_16:
    +@@ -180,6 +187,7 @@ end_inner_loop_wd_16:
    +     sub         r1,r6,r11                   @pu1_dst = pu1_dst_tmp
    +     bgt         outer_loop_wd_16
    + 
    ++    vpop         {d8 - d15}
    +     ldmfd       sp!,{r4-r12,r15}            @reload the registers from sp
    + 
    + 
    +diff --git a/common/arm/ihevc_inter_pred_luma_copy_w16out.s b/common/arm/ihevc_inter_pred_luma_copy_w16out.s
    +index 771bcb3..84dbbad 100644
    +--- a/common/arm/ihevc_inter_pred_luma_copy_w16out.s
    ++++ b/common/arm/ihevc_inter_pred_luma_copy_w16out.s
    +@@ -72,6 +72,10 @@
    + @   r7 =>  ht
    + @   r12 => wd
    + 
    ++.equ    coeff_offset,   104
    ++.equ    ht_offset,      108
    ++.equ    wd_offset,      112
    ++
    + .text
    + .align 4
    + 
    +@@ -85,8 +89,9 @@
    + ihevc_inter_pred_luma_copy_w16out_a9q:
    + 
    +     stmfd       sp!, {r4-r12, r14}          @stack stores the values of the arguments
    +-    ldr         r12,[sp,#48]                @loads wd
    +-    ldr         r7,[sp,#44]                 @loads ht
    ++    vpush        {d8 - d15}
    ++    ldr         r12,[sp,#wd_offset]                @loads wd
    ++    ldr         r7,[sp,#ht_offset]                 @loads ht
    +     cmp         r7,#0                       @ht condition(ht == 0)
    +     ble         end_loops                   @loop
    +     tst         r12,#7                      @conditional check for wd (multiples)
    +@@ -129,6 +134,7 @@ end_inner_loop_wd_4:
    +     bgt         outer_loop_wd_4
    + 
    + end_loops:
    ++    vpop         {d8 - d15}
    +     ldmfd       sp!,{r4-r12,r15}            @reload the registers from sp
    + 
    + 
    +@@ -242,6 +248,7 @@ epilog_end:
    +     vst1.16     {d6,d7},[r10],r5            @vst1q_s16(pi2_dst_tmp, tmp)
    + 
    + 
    ++    vpop         {d8 - d15}
    +     ldmfd       sp!,{r4-r12,r15}            @reload the registers from sp
    + 
    + 
    +diff --git a/common/arm/ihevc_inter_pred_luma_horz_w16out.s b/common/arm/ihevc_inter_pred_luma_horz_w16out.s
    +index e8800e0..a60bb08 100644
    +--- a/common/arm/ihevc_inter_pred_luma_horz_w16out.s
    ++++ b/common/arm/ihevc_inter_pred_luma_horz_w16out.s
    +@@ -107,6 +107,11 @@
    + @r11 - #1
    + @r12 - src_ptr1
    + @r14 - loop_counter
    ++
    ++.equ    coeff_offset,   104
    ++.equ    ht_offset,      108
    ++.equ    wd_offset,      112
    ++
    + .text
    + .align 4
    + .syntax unified
    +@@ -122,16 +127,16 @@ ihevc_inter_pred_luma_horz_w16out_a9q:
    + 
    +     bic         r14, #1                     @ clearing bit[0], so that it goes back to mode
    +     stmfd       sp!, {r4-r12, r14}          @stack stores the values of the arguments
    +-    ldr         r4,[sp,#40]                 @loads pi1_coeff
    +-    ldr         r7,[sp,#44]                 @loads ht
    ++    vpush       {d8 - d15}
    ++    ldr         r4,[sp,#coeff_offset]                 @loads pi1_coeff
    ++    ldr         r7,[sp,#ht_offset]                 @loads ht
    + 
    + 
    +     vld1.8      {d0},[r4]                   @coeff = vld1_s8(pi1_coeff)
    +     sub         r14,r7,#0                   @checks for ht == 0
    +     vabs.s8     d2,d0                       @vabs_s8(coeff)
    +     mov         r11,#1
    +-    @ble       end_loops
    +-    ldr         r10,[sp,#48]                @loads wd
    ++    ldr         r10,[sp,#wd_offset]                @loads wd
    +     vdup.8      d24,d2[0]                   @coeffabs_0 = vdup_lane_u8(coeffabs, 0)
    +     sub         r12,r0,#3                   @pu1_src - 3
    +     vdup.8      d25,d2[1]                   @coeffabs_1 = vdup_lane_u8(coeffabs, 1)
    +@@ -274,11 +279,10 @@ end_inner_loop_4:
    + 
    + height_residue_4:
    + 
    +-    ldr         r7,[sp,#44]                 @loads ht
    ++    ldr         r7,[sp,#ht_offset]                 @loads ht
    +     and         r7,r7,#1                    @calculating ht_residue ht_residue = (ht & 1)
    +     cmp         r7,#0
    +-    @beq        end_loops
    +-    ldmfdeq     sp!,{r4-r12,r15}            @reload the registers from sp
    ++    beq         end_loops
    + 
    + outer_loop_height_residue_4:
    + 
    +@@ -331,7 +335,7 @@ end_inner_loop_height_residue_4:
    +     add         r12,r12,r9                  @increment the input pointer src_strd-wd
    +     add         r1,r1,r8                    @increment the output pointer dst_strd-wd
    +     bgt         outer_loop_height_residue_4
    +-
    ++    vpop        {d8 - d15}
    +     ldmfd       sp!,{r4-r12,r15}            @reload the registers from sp
    + 
    + outer_loop8_residual:
    +@@ -427,18 +431,18 @@ end_inner_loop_8:
    + 
    + 
    + 
    +-    ldr         r10,[sp,#48]                @loads wd
    ++    ldr         r10,[sp,#wd_offset]                @loads wd
    +     cmp         r10,#12
    + 
    +     beq         outer_loop4_residual
    + 
    +-    ldr         r7,[sp,#44]                 @loads ht
    ++    ldr         r7,[sp,#ht_offset]                 @loads ht
    +     and         r7,r7,#1
    +     cmp         r7,#1
    +     beq         height_residue_4
    + 
    +-@end_loops
    + 
    ++    vpop        {d8 - d15}
    +     ldmfd       sp!,{r4-r12,r15}            @reload the registers from sp
    + 
    + 
    +@@ -452,7 +456,6 @@ outer_loop_16:
    +     add         r4,r12,r2                   @pu1_src + src_strd
    +     and         r0, r12, #31
    +     sub         r5,r10,#0                   @checks wd
    +-    @ble       end_loops1
    +     pld         [r12, r2, lsl #1]
    +     vld1.u32    {q0},[r12],r11              @vector load pu1_src
    +     pld         [r4, r2, lsl #1]
    +@@ -580,17 +583,17 @@ epilog_16:
    + 
    +     ldr         r7, [sp], #4
    +     ldr         r0, [sp], #4
    +-    ldr         r10,[sp,#48]
    ++    ldr         r10,[sp,#wd_offset]
    +     cmp         r10,#24
    +     beq         outer_loop8_residual
    +     add         r1,r6,r8,lsl #1
    +-    ldr         r7,[sp,#44]                 @loads ht
    ++    ldr         r7,[sp,#ht_offset]                 @loads ht
    +     and         r7,r7,#1
    +     cmp         r7,#1
    +     beq         height_residue_4
    + 
    +-end_loops1:
    +-
    ++end_loops:
    ++    vpop        {d8 - d15}
    +     ldmfd       sp!,{r4-r12,r15}            @reload the registers from sp
    + 
    + 
    +diff --git a/common/arm/ihevc_inter_pred_luma_vert_w16inp_w16out.s b/common/arm/ihevc_inter_pred_luma_vert_w16inp_w16out.s
    +index c6716fe..6e0f1ed 100644
    +--- a/common/arm/ihevc_inter_pred_luma_vert_w16inp_w16out.s
    ++++ b/common/arm/ihevc_inter_pred_luma_vert_w16inp_w16out.s
    +@@ -102,6 +102,10 @@
    + @   r5 =>  ht
    + @   r6 =>  wd
    + 
    ++.equ    coeff_offset,   104
    ++.equ    ht_offset,      108
    ++.equ    wd_offset,      112
    ++
    + .text
    + .align 4
    + 
    +@@ -115,16 +119,17 @@
    + ihevc_inter_pred_luma_vert_w16inp_w16out_a9q:
    + 
    +     stmfd       sp!, {r4-r12, r14}          @stack stores the values of the arguments
    ++    vpush        {d8 - d15}
    + 
    +-    ldr         r12,[sp,#40]                @load pi1_coeff
    ++    ldr         r12,[sp,#coeff_offset]                @load pi1_coeff
    +     mov         r6,r3,lsl #1
    +-    ldr         r5,[sp,#48]                 @load wd
    ++    ldr         r5,[sp,#wd_offset]                 @load wd
    +     vld1.8      {d0},[r12]                  @coeff = vld1_s8(pi1_coeff)
    +     mov         r2, r2, lsl #1
    +     sub         r12,r2,r2,lsl #2            @src_ctrd & pi1_coeff
    +     @vabs.s8    d0,d0               @vabs_s8(coeff)
    +     add         r0,r0,r12                   @r0->pu1_src    r12->pi1_coeff
    +-    ldr         r3,[sp,#44]                 @load ht
    ++    ldr         r3,[sp,#ht_offset]                 @load ht
    +     subs        r7,r3,#0                    @r3->ht
    +     @ble        end_loops           @end loop jump
    +     vmovl.s8    q0,d0
    +@@ -393,6 +398,7 @@ epilog_end:
    + 
    + end_loops:
    + 
    ++    vpop         {d8 - d15}
    +     ldmfd       sp!,{r4-r12,r15}            @reload the registers from sp
    + 
    + 
    +diff --git a/common/arm/ihevc_intra_pred_chroma_dc.s b/common/arm/ihevc_intra_pred_chroma_dc.s
    +index 72d9730..6e5900a 100644
    +--- a/common/arm/ihevc_intra_pred_chroma_dc.s
    ++++ b/common/arm/ihevc_intra_pred_chroma_dc.s
    +@@ -92,6 +92,8 @@
    + @   mode
    + @   pi1_coeff
    + 
    ++.equ    nt_offset,      40
    ++
    + .text
    + .align 4
    + 
    +@@ -106,7 +108,7 @@ ihevc_intra_pred_chroma_dc_a9q:
    + 
    +     stmfd       sp!, {r4-r12, r14}          @stack stores the values of the arguments
    + 
    +-    ldr         r4,[sp,#40]                 @loads nt
    ++    ldr         r4,[sp,#nt_offset]          @loads nt
    +     mov         r9, #0
    +     vmov        d17, r9, r9
    + 
    +diff --git a/common/arm/ihevc_intra_pred_chroma_horz.s b/common/arm/ihevc_intra_pred_chroma_horz.s
    +index 6089fd8..4512d72 100644
    +--- a/common/arm/ihevc_intra_pred_chroma_horz.s
    ++++ b/common/arm/ihevc_intra_pred_chroma_horz.s
    +@@ -84,6 +84,8 @@
    + @r2 => *pu1_dst
    + @r3 =>  dst_strd
    + 
    ++.equ    nt_offset,      104
    ++
    + .text
    + .align 4
    + 
    +@@ -97,8 +99,9 @@
    + ihevc_intra_pred_chroma_horz_a9q:
    + 
    +     stmfd       sp!, {r4-r12, r14}          @stack stores the values of the arguments
    ++    vpush       {d8 - d15}
    + 
    +-    ldr         r4,[sp,#40]                 @loads nt
    ++    ldr         r4,[sp,#nt_offset]          @loads nt
    + 
    +     lsl         r6,r4,#2                    @four_nt
    + 
    +@@ -187,6 +190,7 @@ core_loop_16:
    +     vst1.16     {q4},[r2],r3
    +     vst1.16     {q4},[r9],r3
    +     bgt         core_loop_16
    ++    vpop        {d8 - d15}
    +     ldmfd       sp!,{r4-r12,r15}            @reload the registers from sp
    +     b           endloop
    + 
    +@@ -263,6 +267,7 @@ core_loop_8:
    +     @vst1.8     {q5},[r2],r3
    +     @vst1.8     {q6},[r2],r3
    +     @vst1.8     {q7},[r2],r3
    ++    vpop        {d8 - d15}
    + 
    +     ldmfd       sp!,{r4-r12,r15}            @reload the registers from sp
    +     b           endloop
    +@@ -308,6 +313,7 @@ core_loop_4:
    + 
    +     @vst1.8     {d8},[r2],r3
    +     @vst1.8     {d9},[r2],r3
    ++    vpop        {d8 - d15}
    +     ldmfd       sp!,{r4-r12,r15}            @reload the registers from sp
    +     b           endloop
    + 
    +@@ -339,6 +345,7 @@ core_loop_4:
    +     vst1.32     {d4[0]},[r2],r3
    +     vst1.32     {d5[0]},[r2],r3
    + 
    ++    vpop        {d8 - d15}
    +     ldmfd       sp!,{r4-r12,r15}            @reload the registers from sp
    + 
    + endloop:
    +diff --git a/common/arm/ihevc_intra_pred_chroma_mode2.s b/common/arm/ihevc_intra_pred_chroma_mode2.s
    +index cfa2ddb..013700d 100644
    +--- a/common/arm/ihevc_intra_pred_chroma_mode2.s
    ++++ b/common/arm/ihevc_intra_pred_chroma_mode2.s
    +@@ -87,11 +87,13 @@
    + @r2 => *pu1_dst
    + @r3 => dst_strd
    + 
    +-@stack contents from #40
    ++@stack contents from #104
    + @   nt
    + @   mode
    + @   pi1_coeff
    + 
    ++.equ    nt_offset,      104
    ++
    + .text
    + .align 4
    + 
    +@@ -105,8 +107,9 @@
    + ihevc_intra_pred_chroma_mode2_a9q:
    + 
    +     stmfd       sp!, {r4-r12, r14}          @stack stores the values of the arguments
    ++    vpush       {d8 - d15}
    + 
    +-    ldr         r4,[sp,#40]                 @loads nt
    ++    ldr         r4,[sp,#nt_offset]          @loads nt
    +     mov         r8,#-4
    + 
    +     cmp         r4,#4
    +@@ -290,6 +293,7 @@ mode2_4:
    +     vst1.8      {d6},[r2],r3
    + 
    + end_func:
    ++    vpop        {d8 - d15}
    +     ldmfd       sp!,{r4-r12,r15}            @reload the registers from sp
    + 
    + 
    +diff --git a/common/arm/ihevc_intra_pred_chroma_mode_18_34.s b/common/arm/ihevc_intra_pred_chroma_mode_18_34.s
    +index b0dd1fa..6af6450 100644
    +--- a/common/arm/ihevc_intra_pred_chroma_mode_18_34.s
    ++++ b/common/arm/ihevc_intra_pred_chroma_mode_18_34.s
    +@@ -87,11 +87,14 @@
    + @r2 => *pu1_dst
    + @r3 => dst_strd
    + 
    +-@stack contents from #40
    ++@stack contents from #104
    + @   nt
    + @   mode
    + @   pi1_coeff
    + 
    ++.equ    nt_offset,          104
    ++.equ    mode_offset,        108
    ++
    + .text
    + .align 4
    + 
    +@@ -105,10 +108,10 @@
    + ihevc_intra_pred_chroma_mode_18_34_a9q:
    + 
    +     stmfd       sp!, {r4-r12, r14}          @stack stores the values of the arguments
    ++    vpush       {d8 - d15}
    + 
    +-
    +-    ldr         r4,[sp,#40]
    +-    ldr         r5,[sp,#44]
    ++    ldr         r4,[sp,#nt_offset]
    ++    ldr         r5,[sp,#mode_offset]
    + 
    +     cmp         r4,#4
    +     beq         mode2_4
    +@@ -181,6 +184,7 @@ mode2_4:
    +     vst1.32     {d0},[r2],r3
    + 
    + end_func:
    ++    vpop        {d8 - d15}
    +     ldmfd       sp!,{r4-r12,r15}            @reload the registers from sp
    + 
    + 
    +diff --git a/common/arm/ihevc_intra_pred_chroma_mode_27_to_33.s b/common/arm/ihevc_intra_pred_chroma_mode_27_to_33.s
    +index fb75e96..21b54da 100644
    +--- a/common/arm/ihevc_intra_pred_chroma_mode_27_to_33.s
    ++++ b/common/arm/ihevc_intra_pred_chroma_mode_27_to_33.s
    +@@ -81,6 +81,9 @@
    + @                                         word32 nt,
    + @                                         word32 mode)
    + 
    ++.equ    nt_offset,          104
    ++.equ    mode_offset,        108
    ++
    + .text
    + .align 4
    + 
    +@@ -103,9 +106,10 @@ gau1_ihevc_planar_factor_addr:
    + ihevc_intra_pred_chroma_mode_27_to_33_a9q:
    + 
    +     stmfd       sp!, {r4-r12, r14}          @stack stores the values of the arguments
    ++    vpush        {d8 - d15}
    + 
    +-    ldr         r4,[sp,#40]                 @loads nt
    +-    ldr         r5,[sp,#44]                 @loads mode
    ++    ldr         r4,[sp,#nt_offset]                 @loads nt
    ++    ldr         r5,[sp,#mode_offset]                 @loads mode
    +     ldr         r6,gai4_ihevc_ang_table_addr @loads word32 gai4_ihevc_ang_table[35]
    + ulbl1:
    +     add         r6,r6,pc
    +@@ -535,6 +539,7 @@ core_loop_4:
    +     vst1.8      {d22},[r2],r3
    + 
    + end_loops:
    ++    vpop         {d8 - d15}
    +     ldmfd       sp!,{r4-r12,r15}            @reload the registers from sp
    + 
    + 
    +diff --git a/common/arm/ihevc_intra_pred_chroma_mode_3_to_9.s b/common/arm/ihevc_intra_pred_chroma_mode_3_to_9.s
    +index a5eb3ca..b7dcbfb 100644
    +--- a/common/arm/ihevc_intra_pred_chroma_mode_3_to_9.s
    ++++ b/common/arm/ihevc_intra_pred_chroma_mode_3_to_9.s
    +@@ -82,10 +82,13 @@
    + @r2 => *pu1_dst
    + @r3 => dst_strd
    + 
    +-@stack contents from #40
    ++@stack contents from #104
    + @   nt
    + @   mode
    + 
    ++.equ    nt_offset,          104
    ++.equ    mode_offset,        108
    ++
    + .text
    + .align 4
    + 
    +@@ -123,13 +126,14 @@ col_for_intra_chroma_addr_3:
    + ihevc_intra_pred_chroma_mode_3_to_9_a9q:
    + 
    +     stmfd       sp!, {r4-r12, r14}          @stack stores the values of the arguments
    ++    vpush       {d8 - d15}
    + 
    +-    ldr         r4,[sp,#40]                 @loads nt
    ++    ldr         r4,[sp,#nt_offset]          @loads nt
    +     ldr         r7, gai4_ihevc_ang_table_addr
    + ulbl1:
    +     add         r7,r7,pc
    + 
    +-    ldr         r5,[sp,#44]                 @mode (3 to 9)
    ++    ldr         r5,[sp,#mode_offset]        @mode (3 to 9)
    +     ldr         r8, gai4_ihevc_inv_ang_table_addr
    + ulbl2:
    +     add         r8,r8,pc
    +@@ -486,6 +490,7 @@ epil_8_16_32:
    +     vst1.8      d18, [r5], r3               @st (row 7)
    + 
    + end_func:
    ++    vpop        {d8 - d15}
    +     ldmfd       sp!,{r4-r12,r15}            @reload the registers from sp
    + 
    + 
    +diff --git a/common/arm/ihevc_intra_pred_chroma_planar.s b/common/arm/ihevc_intra_pred_chroma_planar.s
    +index 30b3144..7d03d55 100644
    +--- a/common/arm/ihevc_intra_pred_chroma_planar.s
    ++++ b/common/arm/ihevc_intra_pred_chroma_planar.s
    +@@ -87,11 +87,13 @@
    + @r2 => *pu1_dst
    + @r3 => dst_strd
    + 
    +-@stack contents from #40
    ++@stack contents from #104
    + @   nt
    + @   mode
    + @   pi1_coeff
    + 
    ++.equ    nt_offset,      104
    ++
    + .text
    + .align 4
    + 
    +@@ -109,8 +111,9 @@ gau1_ihevc_planar_factor_addr:
    + ihevc_intra_pred_chroma_planar_a9q:
    + 
    +     stmfd       sp!, {r4-r12, r14}          @stack stores the values of the arguments
    ++    vpush       {d8 - d15}
    + 
    +-    ldr         r4,[sp,#40]                 @loads nt
    ++    ldr         r4,[sp,#nt_offset]          @loads nt
    +     ldr         r11, gau1_ihevc_planar_factor_addr @loads table of coeffs
    + ulbl1:
    +     add         r11,r11,pc
    +@@ -353,6 +356,7 @@ loop_sz_4:
    +     bne         loop_sz_4
    + 
    + end_loop:
    ++    vpop        {d8 - d15}
    +     ldmfd       sp!,{r4-r12,r15}            @reload the registers from sp
    + 
    + 
    +diff --git a/common/arm/ihevc_intra_pred_chroma_ver.s b/common/arm/ihevc_intra_pred_chroma_ver.s
    +index b68a045..ce2ad73 100644
    +--- a/common/arm/ihevc_intra_pred_chroma_ver.s
    ++++ b/common/arm/ihevc_intra_pred_chroma_ver.s
    +@@ -87,6 +87,8 @@
    + @   nt
    + @   mode
    + 
    ++.equ    nt_offset,      40
    ++
    + .text
    + .align 4
    + 
    +@@ -101,7 +103,7 @@ ihevc_intra_pred_chroma_ver_a9q:
    + 
    +     stmfd       sp!, {r4-r12, r14}          @stack stores the values of the arguments
    + 
    +-    ldr         r4,[sp,#40]                 @loads nt
    ++    ldr         r4,[sp,#nt_offset]          @loads nt
    +     lsl         r5, r4, #2                  @4nt
    + 
    + 
    +diff --git a/common/arm/ihevc_intra_pred_filters_chroma_mode_11_to_17.s b/common/arm/ihevc_intra_pred_filters_chroma_mode_11_to_17.s
    +index 6c882cf..8644cc8 100644
    +--- a/common/arm/ihevc_intra_pred_filters_chroma_mode_11_to_17.s
    ++++ b/common/arm/ihevc_intra_pred_filters_chroma_mode_11_to_17.s
    +@@ -84,10 +84,13 @@
    + @r2 => *pu1_dst
    + @r3 => dst_strd
    + 
    +-@stack contents from #40
    ++@stack contents from #236
    + @   nt
    + @   mode
    + 
    ++.equ    nt_offset,      236
    ++.equ    mode_offset,    240
    ++
    + .text
    + .align 4
    + 
    +@@ -123,13 +126,15 @@ col_for_intra_chroma_addr_3:
    + ihevc_intra_pred_chroma_mode_11_to_17_a9q:
    + 
    +     stmfd       sp!, {r4-r12, r14}          @stack stores the values of the arguments
    ++    vpush        {d8 - d15}
    ++    sub         sp, sp, #132                @ref_temp[2 * max_cu_size + 2]
    + 
    +-    ldr         r4,[sp,#40]                 @loads nt
    ++    ldr         r4,[sp,#nt_offset]          @loads wd
    +     ldr         r7, gai4_ihevc_ang_table_addr
    + ulbl1:
    +     add         r7,r7,pc
    + 
    +-    ldr         r5,[sp,#44]                 @mode (11 to 17)
    ++    ldr         r5,[sp,#mode_offset]        @mode (11 to 17)
    +     ldr         r8, gai4_ihevc_inv_ang_table_addr
    + ulbl2:
    +     add         r8,r8,pc
    +@@ -139,7 +144,6 @@ ulbl2:
    +     sub         r8, r8, #44
    + 
    +     ldr         r7, [r7]                    @intra_pred_ang
    +-    sub         sp, sp, #132                @ref_temp[2 * max_cu_size + 2]
    + 
    +     ldr         r8, [r8]                    @inv_ang
    +     add         r6, sp, r4, lsl #1          @ref_temp + 2 * nt
    +@@ -607,6 +611,7 @@ epil_8_16_32:
    + 
    + end_func:
    +     add         sp, sp, #132
    ++    vpop        {d8 - d15}
    +     ldmfd       sp!,{r4-r12,r15}            @reload the registers from sp
    + 
    + 
    +diff --git a/common/arm/ihevc_intra_pred_filters_chroma_mode_19_to_25.s b/common/arm/ihevc_intra_pred_filters_chroma_mode_19_to_25.s
    +index 2ede914..a555646 100644
    +--- a/common/arm/ihevc_intra_pred_filters_chroma_mode_19_to_25.s
    ++++ b/common/arm/ihevc_intra_pred_filters_chroma_mode_19_to_25.s
    +@@ -84,10 +84,13 @@
    + @r2 => *pu1_dst
    + @r3 => dst_strd
    + 
    +-@stack contents from #40
    ++@stack contents from #236
    + @   nt
    + @   mode
    + 
    ++.equ    nt_offset,      236
    ++.equ    mode_offset,    240
    ++
    + .text
    + .align 4
    + 
    +@@ -116,13 +119,15 @@ gai4_ihevc_ang_table_addr_2:
    + ihevc_intra_pred_chroma_mode_19_to_25_a9q:
    + 
    +     stmfd       sp!, {r4-r12, r14}          @stack stores the values of the arguments
    ++    vpush       {d8 - d15}
    ++    sub         sp, sp, #132                @ref_temp[2 * max_cu_size + 2]
    + 
    +-    ldr         r4,[sp,#40]                 @loads nt
    ++    ldr         r4,[sp,#nt_offset]          @loads nt
    +     ldr         r7, gai4_ihevc_ang_table_addr_1
    + ulbl3:
    +     add         r7,r7,pc
    + 
    +-    ldr         r5,[sp,#44]                 @mode (19 to 25)
    ++    ldr         r5,[sp,#mode_offset]        @mode (19 to 25)
    +     ldr         r8, gai4_ihevc_inv_ang_table_addr
    + ulbl1:
    +     add         r8,r8,pc
    +@@ -132,7 +137,6 @@ ulbl1:
    +     sub         r8, r8, #48                 @gai4_ihevc_inv_ang_table[mode - 12]
    + 
    +     ldr         r7, [r7]                    @intra_pred_ang
    +-    sub         sp, sp, #132                @ref_temp[2 * max_cu_size + 2]
    + 
    +     ldr         r8, [r8]                    @inv_ang
    +     add         r6, sp, r4 , lsl #1         @ref_temp + 2 * nt
    +@@ -562,6 +566,7 @@ core_loop_4:
    + 
    + end_loops:
    +     add         sp, sp, #132
    ++    vpop        {d8 - d15}
    +     ldmfd       sp!,{r4-r12,r15}            @reload the registers from sp
    + 
    + 
    +diff --git a/common/arm/ihevc_intra_pred_filters_luma_mode_11_to_17.s b/common/arm/ihevc_intra_pred_filters_luma_mode_11_to_17.s
    +index ec38786..336af06 100644
    +--- a/common/arm/ihevc_intra_pred_filters_luma_mode_11_to_17.s
    ++++ b/common/arm/ihevc_intra_pred_filters_luma_mode_11_to_17.s
    +@@ -84,10 +84,13 @@
    + @r2 => *pu1_dst
    + @r3 => dst_strd
    + 
    +-@stack contents from #40
    ++@stack contents from #236
    + @   nt
    + @   mode
    + 
    ++.equ    nt_offset,      236
    ++.equ    mode_offset,    240
    ++
    + .text
    + .align 4
    + 
    +@@ -129,13 +132,14 @@ col_for_intra_luma_addr_4:
    + ihevc_intra_pred_luma_mode_11_to_17_a9q:
    + 
    +     stmfd       sp!, {r4-r12, r14}          @stack stores the values of the arguments
    +-
    +-    ldr         r4,[sp,#40]                 @loads nt
    ++    vpush       {d8 - d15}
    ++    sub         sp, sp, #132                @ref_temp[2 * max_cu_size + 1]
    ++    ldr         r4,[sp,#nt_offset]          @loads nt
    +     ldr         r7, gai4_ihevc_ang_table_addr
    + ulbl1:
    +     add         r7,r7,pc
    + 
    +-    ldr         r5,[sp,#44]                 @mode (11 to 17)
    ++    ldr         r5,[sp,#mode_offset]        @mode (11 to 17)
    +     ldr         r8, gai4_ihevc_inv_ang_table_addr
    + ulbl2:
    +     add         r8,r8,pc
    +@@ -145,7 +149,6 @@ ulbl2:
    +     sub         r8, r8, #44
    + 
    +     ldr         r7, [r7]                    @intra_pred_ang
    +-    sub         sp, sp, #132                @ref_temp[2 * max_cu_size + 1]
    + 
    +     ldr         r8, [r8]                    @inv_ang
    +     add         r6, sp, r4                  @ref_temp + nt
    +@@ -684,6 +687,7 @@ ulbl4:
    + 
    + end_func:
    +     add         sp, sp, #132
    ++    vpop        {d8 - d15}
    +     ldmfd       sp!,{r4-r12,r15}            @reload the registers from sp
    + 
    + 
    +diff --git a/common/arm/ihevc_intra_pred_filters_luma_mode_19_to_25.s b/common/arm/ihevc_intra_pred_filters_luma_mode_19_to_25.s
    +index af342bf..32268a2 100644
    +--- a/common/arm/ihevc_intra_pred_filters_luma_mode_19_to_25.s
    ++++ b/common/arm/ihevc_intra_pred_filters_luma_mode_19_to_25.s
    +@@ -84,10 +84,13 @@
    + @r2 => *pu1_dst
    + @r3 => dst_strd
    + 
    +-@stack contents from #40
    ++@stack contents from #236
    + @   nt
    + @   mode
    + 
    ++.equ    nt_offset,      236
    ++.equ    mode_offset,    240
    ++
    + .text
    + .align 4
    + 
    +@@ -116,13 +119,15 @@ gai4_ihevc_ang_table_addr_2:
    + ihevc_intra_pred_luma_mode_19_to_25_a9q:
    + 
    +     stmfd       sp!, {r4-r12, r14}          @stack stores the values of the arguments
    ++    vpush       {d8 - d15}
    ++    sub         sp, sp, #132                @ref_temp[2 * max_cu_size + 1]
    + 
    +-    ldr         r4,[sp,#40]                 @loads nt
    ++    ldr         r4,[sp,#nt_offset]          @loads nt
    +     ldr         r7, gai4_ihevc_ang_table_addr_1
    + ulbl_1:
    +     add         r7,r7,pc
    + 
    +-    ldr         r5,[sp,#44]                 @mode (19 to 25)
    ++    ldr         r5,[sp,#mode_offset]        @mode (19 to 25)
    +     ldr         r8, gai4_ihevc_inv_ang_table_addr
    + ulbl1:
    +     add         r8,r8,pc
    +@@ -132,7 +137,6 @@ ulbl1:
    +     sub         r8, r8, #48                 @gai4_ihevc_inv_ang_table[mode - 12]
    + 
    +     ldr         r7, [r7]                    @intra_pred_ang
    +-    sub         sp, sp, #132                @ref_temp[2 * max_cu_size + 1]
    + 
    +     ldr         r8, [r8]                    @inv_ang
    +     add         r6, sp, r4                  @ref_temp + nt
    +@@ -644,6 +648,7 @@ core_loop_4:
    + 
    + end_loops:
    +     add         sp, sp, #132
    ++    vpop        {d8 - d15}
    +     ldmfd       sp!,{r4-r12,r15}            @reload the registers from sp
    + 
    + 
    +diff --git a/common/arm/ihevc_intra_pred_luma_dc.s b/common/arm/ihevc_intra_pred_luma_dc.s
    +index f380d94..7d8cb91 100644
    +--- a/common/arm/ihevc_intra_pred_luma_dc.s
    ++++ b/common/arm/ihevc_intra_pred_luma_dc.s
    +@@ -87,11 +87,13 @@
    + @r2 => *pu1_dst
    + @r3 => dst_strd
    + 
    +-@stack contents from #40
    ++@stack contents from #104
    + @   nt
    + @   mode
    + @   pi1_coeff
    + 
    ++.equ    nt_offset,      104
    ++
    + .text
    + .align 4
    + 
    +@@ -105,8 +107,8 @@
    + ihevc_intra_pred_luma_dc_a9q:
    + 
    +     stmfd       sp!, {r4-r12, r14}          @stack stores the values of the arguments
    +-
    +-    ldr         r4,[sp,#40]                 @loads nt
    ++    vpush       {d8 - d15}
    ++    ldr         r4,[sp,#nt_offset]          @loads nt
    + 
    + @********** testing
    +     @mov        r6, #128
    +@@ -498,6 +500,7 @@ dc_4:
    + 
    + epilogue_end:
    + end_func:
    ++    vpop        {d8 - d15}
    +     ldmfd       sp!,{r4-r12,r15}            @reload the registers from sp
    + 
    + 
    +diff --git a/common/arm/ihevc_intra_pred_luma_horz.s b/common/arm/ihevc_intra_pred_luma_horz.s
    +index 581b673..2a44404 100644
    +--- a/common/arm/ihevc_intra_pred_luma_horz.s
    ++++ b/common/arm/ihevc_intra_pred_luma_horz.s
    +@@ -84,6 +84,8 @@
    + @r2 => *pu1_dst
    + @r3 =>  dst_strd
    + 
    ++.equ    nt_offset,      104
    ++
    + .text
    + .align 4
    + 
    +@@ -97,9 +99,8 @@
    + ihevc_intra_pred_luma_horz_a9q:
    + 
    +     stmfd       sp!, {r4-r12, r14}          @stack stores the values of the arguments
    +-
    +-    ldr         r4,[sp,#40]                 @loads nt
    +-    @ldr        r5,[sp,#44]                     @loads mode
    ++    vpush       {d8 - d15}
    ++    ldr         r4,[sp,#nt_offset]          @loads nt
    + 
    +     lsl         r6,r4,#1                    @two_nt
    + 
    +@@ -185,6 +186,7 @@ core_loop_32:
    +     vst1.8      {q4},[r2],r3
    +     vst1.8      {q4},[r9],r3
    +     bgt         core_loop_32
    ++    vpop        {d8 - d15}
    +     ldmfd       sp!,{r4-r12,r15}            @reload the registers from sp
    +     b           end_func
    + 
    +@@ -258,7 +260,7 @@ core_loop_16:
    +     vst1.8      {q5},[r2],r3
    +     vst1.8      {q6},[r2],r3
    +     vst1.8      {q7},[r2],r3
    +-
    ++    vpop        {d8 - d15}
    +     ldmfd       sp!,{r4-r12,r15}            @reload the registers from sp
    +     b           end_func
    + 
    +@@ -301,6 +303,7 @@ core_loop_8:
    + 
    +     vst1.8      {d8},[r2],r3
    +     vst1.8      {d9},[r2],r3
    ++    vpop        {d8 - d15}
    +     ldmfd       sp!,{r4-r12,r15}            @reload the registers from sp
    +     b           end_func
    + 
    +@@ -331,7 +334,7 @@ core_loop_4:
    +     vst1.32     {d3[0]},[r2],r3
    +     vst1.32     {d4[0]},[r2],r3
    +     vst1.32     {d5[0]},[r2],r3
    +-
    ++    vpop        {d8 - d15}
    +     ldmfd       sp!,{r4-r12,r15}            @reload the registers from sp
    + end_func:
    + 
    +diff --git a/common/arm/ihevc_intra_pred_luma_mode2.s b/common/arm/ihevc_intra_pred_luma_mode2.s
    +index cf7999b..935f02d 100644
    +--- a/common/arm/ihevc_intra_pred_luma_mode2.s
    ++++ b/common/arm/ihevc_intra_pred_luma_mode2.s
    +@@ -87,11 +87,13 @@
    + @r2 => *pu1_dst
    + @r3 => dst_strd
    + 
    +-@stack contents from #40
    ++@stack contents from #104
    + @   nt
    + @   mode
    + @   pi1_coeff
    + 
    ++.equ    nt_offset,      104
    ++
    + .text
    + .align 4
    + 
    +@@ -105,8 +107,8 @@
    + ihevc_intra_pred_luma_mode2_a9q:
    + 
    +     stmfd       sp!, {r4-r12, r14}          @stack stores the values of the arguments
    +-
    +-    ldr         r4,[sp,#40]                 @loads nt
    ++    vpush       {d8 - d15}
    ++    ldr         r4,[sp,#nt_offset]          @loads nt
    +     mov         r8,#-2
    + 
    +     cmp         r4,#4
    +@@ -260,6 +262,7 @@ mode2_4:
    +     vst1.32     {d7[0]},[r7]
    + 
    + end_func:
    ++    vpop        {d8 - d15}
    +     ldmfd       sp!,{r4-r12,r15}            @reload the registers from sp
    + 
    + 
    +diff --git a/common/arm/ihevc_intra_pred_luma_mode_18_34.s b/common/arm/ihevc_intra_pred_luma_mode_18_34.s
    +index 438c0f5..9287371 100644
    +--- a/common/arm/ihevc_intra_pred_luma_mode_18_34.s
    ++++ b/common/arm/ihevc_intra_pred_luma_mode_18_34.s
    +@@ -92,6 +92,9 @@
    + @   mode
    + @   pi1_coeff
    + 
    ++.equ    nt_offset,      40
    ++.equ    mode_offset,    44
    ++
    + .text
    + .align 4
    + 
    +@@ -107,8 +110,8 @@ ihevc_intra_pred_luma_mode_18_34_a9q:
    +     stmfd       sp!, {r4-r12, r14}          @stack stores the values of the arguments
    + 
    + 
    +-    ldr         r4,[sp,#40]
    +-    ldr         r5,[sp,#44]
    ++    ldr         r4,[sp,#nt_offset]
    ++    ldr         r5,[sp,#mode_offset]
    + 
    +     cmp         r4,#4
    +     beq         mode2_4
    +diff --git a/common/arm/ihevc_intra_pred_luma_mode_27_to_33.s b/common/arm/ihevc_intra_pred_luma_mode_27_to_33.s
    +index 595d82a..9d95719 100644
    +--- a/common/arm/ihevc_intra_pred_luma_mode_27_to_33.s
    ++++ b/common/arm/ihevc_intra_pred_luma_mode_27_to_33.s
    +@@ -85,6 +85,9 @@
    + @r2 => *pu1_dst
    + @r3 =>  dst_strd
    + 
    ++.equ    nt_offset,      104
    ++.equ    mode_offset,    108
    ++
    + .text
    + .align 4
    + 
    +@@ -107,9 +110,9 @@ gau1_ihevc_planar_factor_addr:
    + ihevc_intra_pred_luma_mode_27_to_33_a9q:
    + 
    +     stmfd       sp!, {r4-r12, r14}          @stack stores the values of the arguments
    +-
    +-    ldr         r4,[sp,#40]                 @loads nt
    +-    ldr         r5,[sp,#44]                 @loads mode
    ++    vpush       {d8 - d15}
    ++    ldr         r4,[sp,#nt_offset]          @loads nt
    ++    ldr         r5,[sp,#mode_offset]        @loads mode
    +     ldr         r6,gai4_ihevc_ang_table_addr @loads word32 gai4_ihevc_ang_table[35]
    + ulbl1:
    +     add         r6,r6,pc
    +@@ -534,6 +537,7 @@ core_loop_4:
    +     vst1.32     {d22[0]},[r2],r3
    + 
    + end_loops:
    ++    vpop        {d8 - d15}
    +     ldmfd       sp!,{r4-r12,r15}            @reload the registers from sp
    + 
    + 
    +diff --git a/common/arm/ihevc_intra_pred_luma_mode_3_to_9.s b/common/arm/ihevc_intra_pred_luma_mode_3_to_9.s
    +index a8e93c8..e9c871c 100644
    +--- a/common/arm/ihevc_intra_pred_luma_mode_3_to_9.s
    ++++ b/common/arm/ihevc_intra_pred_luma_mode_3_to_9.s
    +@@ -84,10 +84,13 @@
    + @r2 => *pu1_dst
    + @r3 => dst_strd
    + 
    +-@stack contents from #40
    ++@stack contents from #104
    + @   nt
    + @   mode
    + 
    ++.equ    nt_offset,      104
    ++.equ    mode_offset,    108
    ++
    + .text
    + .align 4
    + 
    +@@ -126,13 +129,13 @@ col_for_intra_luma_addr_3:
    + ihevc_intra_pred_luma_mode_3_to_9_a9q:
    + 
    +     stmfd       sp!, {r4-r12, r14}          @stack stores the values of the arguments
    +-
    +-    ldr         r4,[sp,#40]                 @loads nt
    ++    vpush       {d8 - d15}
    ++    ldr         r4,[sp,#nt_offset]          @loads nt
    +     ldr         r7, gai4_ihevc_ang_table_addr
    + ulbl1:
    +     add         r7,r7,pc
    + 
    +-    ldr         r5,[sp,#44]                 @mode (3 to 9)
    ++    ldr         r5,[sp,#mode_offset]        @mode (3 to 9)
    +     ldr         r8, gai4_ihevc_inv_ang_table_addr
    + ulbl2:
    +     add         r8,r8,pc
    +@@ -566,6 +569,7 @@ ulbl3_2:
    +     vst1.32     d18[0], [r2], r3            @st (row 3)
    + 
    + end_func:
    ++    vpop        {d8 - d15}
    +     ldmfd       sp!,{r4-r12,r15}            @reload the registers from sp
    + 
    + 
    +diff --git a/common/arm/ihevc_intra_pred_luma_planar.s b/common/arm/ihevc_intra_pred_luma_planar.s
    +index 666798e..50b6b1b 100644
    +--- a/common/arm/ihevc_intra_pred_luma_planar.s
    ++++ b/common/arm/ihevc_intra_pred_luma_planar.s
    +@@ -87,11 +87,13 @@
    + @r2 => *pu1_dst
    + @r3 => dst_strd
    + 
    +-@stack contents from #40
    ++@stack contents from #104
    + @   nt
    + @   mode
    + @   pi1_coeff
    + 
    ++.equ    nt_offset,      104
    ++
    + .text
    + .align 4
    + 
    +@@ -114,8 +116,8 @@ gau1_ihevc_planar_factor_1_addr:
    + ihevc_intra_pred_luma_planar_a9q:
    + 
    +     stmfd       sp!, {r4-r12, r14}          @stack stores the values of the arguments
    +-
    +-    ldr         r4,[sp,#40]                 @loads nt
    ++    vpush       {d8 - d15}
    ++    ldr         r4,[sp,#nt_offset]          @loads nt
    +     ldr         r11, gau1_ihevc_planar_factor_addr @loads table of coeffs
    + ulbl1:
    +     add         r11,r11,pc
    +@@ -546,6 +548,7 @@ loop_sz_4:
    +     bne         loop_sz_4
    + 
    + end_loop:
    ++    vpop        {d8 - d15}
    +     ldmfd       sp!,{r4-r12,r15}            @reload the registers from sp
    + 
    + 
    +diff --git a/common/arm/ihevc_intra_pred_luma_vert.s b/common/arm/ihevc_intra_pred_luma_vert.s
    +index 5eeaeb3..9610773 100644
    +--- a/common/arm/ihevc_intra_pred_luma_vert.s
    ++++ b/common/arm/ihevc_intra_pred_luma_vert.s
    +@@ -84,10 +84,12 @@
    + @r2 => *pu1_dst
    + @r3 => dst_strd
    + 
    +-@stack contents from #40
    ++@stack contents from #104
    + @   nt
    + @   mode
    + 
    ++.equ    nt_offset,      104
    ++
    + .text
    + .align 4
    + 
    +@@ -101,8 +103,8 @@
    + ihevc_intra_pred_luma_ver_a9q:
    + 
    +     stmfd       sp!, {r4-r12, r14}          @stack stores the values of the arguments
    +-
    +-    ldr         r4,[sp,#40]                 @loads nt
    ++    vpush       {d8 - d15}
    ++    ldr         r4,[sp,#nt_offset]          @loads nt
    + 
    +     lsl         r5, r4, #1                  @2nt
    + 
    +@@ -417,5 +419,6 @@ blk_4:
    + 
    + 
    + end_func:
    ++    vpop        {d8 - d15}
    +     ldmfd       sp!,{r4-r12,r15}            @reload the registers from sp
    + 
    +diff --git a/common/arm/ihevc_itrans_recon_16x16.s b/common/arm/ihevc_itrans_recon_16x16.s
    +index 82055ad..198fd52 100644
    +--- a/common/arm/ihevc_itrans_recon_16x16.s
    ++++ b/common/arm/ihevc_itrans_recon_16x16.s
    +@@ -105,6 +105,12 @@
    + @   r12
    + @   r11
    + 
    ++.equ    src_stride_offset,     104
    ++.equ    pred_stride_offset,    108
    ++.equ    out_stride_offset,     112
    ++.equ    zero_cols_offset,      116
    ++.equ    zero_rows_offset,      120
    ++
    + .text
    + .align 4
    + 
    +@@ -129,15 +135,10 @@ g_ai2_ihevc_trans_16_transpose_addr:
    + ihevc_itrans_recon_16x16_a9q:
    + 
    +     stmfd       sp!,{r4-r12,lr}
    +-@   add             sp,sp,#40
    +-
    +-
    +-
    +-@   ldr         r8,[sp,#4]  @ prediction stride
    +-@   ldr         r7,[sp,#8]  @ destination stride
    +-    ldr         r6,[sp,#40]                 @ src stride
    +-    ldr         r12,[sp,#52]
    +-    ldr         r11,[sp,#56]
    ++    vpush       {d8  -  d15}
    ++    ldr         r6,[sp,#src_stride_offset]  @ src stride
    ++    ldr         r12,[sp,#zero_cols_offset]
    ++    ldr         r11,[sp,#zero_rows_offset]
    + 
    + 
    + 
    +@@ -661,8 +662,8 @@ skip_last12rows_kernel2:
    + 
    +     mov         r6,r7
    + 
    +-    ldr         r8,[sp,#44]                 @ prediction stride
    +-    ldr         r7,[sp,#48]                 @ destination stride
    ++    ldr         r8,[sp,#pred_stride_offset] @ prediction stride
    ++    ldr         r7,[sp,#out_stride_offset]  @ destination stride
    + 
    +     mov         r10,#16
    + 
    +@@ -1126,7 +1127,7 @@ skip_last8rows_stage2_kernel2:
    +     bne         second_stage
    + 
    + 
    +-@   sub         sp,sp,#40
    ++    vpop        {d8  -  d15}
    +     ldmfd       sp!,{r4-r12,pc}
    + 
    + 
    +diff --git a/common/arm/ihevc_itrans_recon_32x32.s b/common/arm/ihevc_itrans_recon_32x32.s
    +index eeb1d66..65b6ffd 100644
    +--- a/common/arm/ihevc_itrans_recon_32x32.s
    ++++ b/common/arm/ihevc_itrans_recon_32x32.s
    +@@ -124,6 +124,14 @@
    + @d5[2]= 43      d7[2]=9
    + @d5[3]= 38      d7[3]=4
    + 
    ++.equ    pi2_src_offset,     64
    ++.equ    pi2_tmp_offset,     68
    ++.equ    src_strd_offset,    120
    ++.equ    pred_strd_offset,   124
    ++.equ    dst_strd_offset,    128
    ++.equ    zero_cols_offset,   132
    ++.equ    zero_rows_offset,   136
    ++
    + .text
    + .align 4
    + 
    +@@ -152,13 +160,11 @@ r9_addr: .word 0xffff0000
    + ihevc_itrans_recon_32x32_a9q:
    + 
    +     stmfd       sp!,{r0-r12,lr}
    ++    vpush       {d8  -  d15}
    + 
    +-
    +-@ldr            r8,[sp,#56]     @ prediction stride
    +-@ldr            r7,[sp,#64]     @ destination stride
    +-    ldr         r6,[sp,#56]                 @ src stride
    +-    ldr         r12,[sp,#68]
    +-    ldr         r11,[sp,#72]
    ++    ldr         r6,[sp,#src_strd_offset]    @ src stride
    ++    ldr         r12,[sp,#zero_cols_offset]
    ++    ldr         r11,[sp,#zero_rows_offset]
    +     mov         r6,r6,lsl #1                @ x sizeof(word16)
    +     add         r10,r6,r6, lsl #1           @ 3 rows
    + 
    +@@ -1493,10 +1499,10 @@ shift4:
    +     bne         dct_stage1
    + second_stage_dct:
    + @   mov     r0,r1
    +-    ldr         r0,[sp]
    +-    ldr         r1,[sp,#4]
    +-    ldr         r8,[sp,#60]                 @ prediction stride
    +-    ldr         r7,[sp,#64]                 @ destination stride
    ++    ldr         r0,[sp,#pi2_src_offset]
    ++    ldr         r1,[sp,#pi2_tmp_offset]
    ++    ldr         r8,[sp,#pred_strd_offset]   @ prediction stride
    ++    ldr         r7,[sp,#dst_strd_offset]    @ destination stride
    + 
    + @   add r4,r2,r8, lsl #1    @ r4 = r2 + pred_strd * 2    => r4 points to 3rd row of pred data
    + @   add r5,r8,r8, lsl #1    @
    +@@ -2855,6 +2861,7 @@ prediction_buffer:
    + 
    +     subs        r14,r14,#1
    +     bne         dct_stage2
    ++    vpop        {d8  -  d15}
    +     ldmfd       sp!,{r0-r12,pc}
    + 
    + 
    +diff --git a/common/arm/ihevc_itrans_recon_4x4.s b/common/arm/ihevc_itrans_recon_4x4.s
    +index c955502..fb5796c 100644
    +--- a/common/arm/ihevc_itrans_recon_4x4.s
    ++++ b/common/arm/ihevc_itrans_recon_4x4.s
    +@@ -100,6 +100,10 @@
    + @   r6 => dst_strd
    + @   r7 => zero_cols
    + 
    ++.equ    src_strd_offset,    104
    ++.equ    pred_strd_offset,   108
    ++.equ    dst_strd_offset,    112
    ++.equ    zero_cols_offset,   116
    + 
    + .text
    + .align 4
    +@@ -122,17 +126,18 @@ g_ai2_ihevc_trans_4_transpose_addr:
    + ihevc_itrans_recon_4x4_a9q:
    + 
    +     stmfd       sp!, {r4-r12, r14}          @stack stores the values of the arguments
    ++    vpush       {d8  -  d15}
    + 
    +     ldr         r8,g_ai2_ihevc_trans_4_transpose_addr
    + ulbl1:
    +     add         r8,r8,pc
    + 
    +-    ldr         r4,[sp,#40]                 @loading src_strd
    +-    ldr         r5,[sp,#44]                 @loading pred_strd
    ++    ldr         r4,[sp,#src_strd_offset]    @loading src_strd
    ++    ldr         r5,[sp,#pred_strd_offset]   @loading pred_strd
    +     add         r4,r4,r4                    @ src_strd in terms of word16
    + 
    +-    ldr         r6,[sp,#48]                 @loading dst_strd
    +-    ldr         r7,[sp,#52]                 @loading zero_cols
    ++    ldr         r6,[sp,#dst_strd_offset]    @loading dst_strd
    ++    ldr         r7,[sp,#zero_cols_offset]   @loading zero_cols
    +     add         r9,r0,r4                    @ pi2_src[0] + src_strd
    + 
    + 
    +@@ -223,7 +228,7 @@ ulbl1:
    +     vst1.32     {d1[0]},[r3],r6
    +     vst1.32     {d1[1]},[r3],r6
    + 
    +-
    ++    vpop        {d8  -  d15}
    +     ldmfd       sp!,{r4-r12,r15}            @reload the registers from sp
    + 
    + 
    +diff --git a/common/arm/ihevc_itrans_recon_4x4_ttype1.s b/common/arm/ihevc_itrans_recon_4x4_ttype1.s
    +index ab65dae..82ed8a0 100644
    +--- a/common/arm/ihevc_itrans_recon_4x4_ttype1.s
    ++++ b/common/arm/ihevc_itrans_recon_4x4_ttype1.s
    +@@ -103,6 +103,11 @@
    + @   r6 => dst_strd
    + @   r7 => zero_cols
    + 
    ++.equ    src_strd_offset,    104
    ++.equ    pred_strd_offset,   108
    ++.equ    dst_strd_offset,    112
    ++.equ    zero_cols_offset,   116
    ++
    + .text
    + .align 4
    + 
    +@@ -119,10 +124,12 @@
    + ihevc_itrans_recon_4x4_ttype1_a9q:
    + 
    +     stmfd       sp!, {r4-r12, r14}          @stack stores the values of the arguments
    +-    ldr         r4,[sp,#40]                 @loading src_strd
    +-    ldr         r5,[sp,#44]                 @loading pred_strd
    +-    ldr         r6,[sp,#48]                 @loading dst_strd
    +-    ldr         r7,[sp,#52]                 @loading zero_cols
    ++    vpush       {d8  -  d15}
    ++
    ++    ldr         r4,[sp,#src_strd_offset]    @loading src_strd
    ++    ldr         r5,[sp,#pred_strd_offset]   @loading pred_strd
    ++    ldr         r6,[sp,#dst_strd_offset]    @loading dst_strd
    ++    ldr         r7,[sp,#zero_cols_offset]   @loading zero_cols
    + 
    +     add         r4,r4,r4                    @ src_strd in terms of word16
    + 
    +@@ -224,6 +231,7 @@ ihevc_itrans_recon_4x4_ttype1_a9q:
    +     vst1.32     {d1[0]},[r3],r6
    +     vst1.32     {d1[1]},[r3],r6
    + 
    ++    vpop        {d8  -  d15}
    +     ldmfd       sp!,{r4-r12,r15}            @reload the registers from sp
    + 
    + 
    +diff --git a/common/arm/ihevc_itrans_recon_8x8.s b/common/arm/ihevc_itrans_recon_8x8.s
    +index e9b53b4..94113d8 100644
    +--- a/common/arm/ihevc_itrans_recon_8x8.s
    ++++ b/common/arm/ihevc_itrans_recon_8x8.s
    +@@ -104,6 +104,11 @@
    + @   dst_strd
    + @   zero_cols
    + 
    ++.equ    src_stride_offset,     104
    ++.equ    pred_stride_offset,    108
    ++.equ    out_stride_offset,     112
    ++.equ    zero_cols_offset,      116
    ++.equ    zero_rows_offset,      120
    + 
    + 
    + .text
    +@@ -151,12 +156,13 @@ ihevc_itrans_recon_8x8_a9q:
    +     @// copy the input pointer to another register
    +     @// step 1 : load all constants
    +     stmfd       sp!,{r4-r12,lr}
    ++    vpush       {d8  -  d15}
    + 
    +-    ldr         r8,[sp,#44]                  @ prediction stride
    +-    ldr         r7,[sp,#48]                  @ destination stride
    +-    ldr         r6,[sp, #40]                     @ src stride
    +-    ldr         r12,[sp,#52]
    +-    ldr         r11,[sp,#56]
    ++    ldr         r8, [sp, #pred_stride_offset]    @ prediction stride
    ++    ldr         r7, [sp, #out_stride_offset]     @ destination stride
    ++    ldr         r6, [sp, #src_stride_offset]     @ src stride
    ++    ldr         r12, [sp, #zero_cols_offset]
    ++    ldr         r11, [sp, #zero_rows_offset]
    +     mov         r6,r6,lsl #1                @ x sizeof(word16)
    +     add         r9,r0,r6, lsl #1            @ 2 rows
    + 
    +@@ -925,7 +931,7 @@ pred_buff_addition:
    + 
    + 
    + 
    +-
    ++    vpop        {d8  -  d15}
    +     ldmfd       sp!,{r4-r12,pc}
    + 
    + 
    +diff --git a/common/arm/ihevc_sao_band_offset_chroma.s b/common/arm/ihevc_sao_band_offset_chroma.s
    +index 32e149d..a9da725 100644
    +--- a/common/arm/ihevc_sao_band_offset_chroma.s
    ++++ b/common/arm/ihevc_sao_band_offset_chroma.s
    +@@ -61,6 +61,14 @@
    + @r9 =>  wd
    + @r10=>  ht
    + 
    ++.equ    pu1_src_top_left_offset,    104
    ++.equ    sao_band_pos_u_offset,      108
    ++.equ    sao_band_pos_v_offset,      112
    ++.equ    pi1_sao_u_offset,           116
    ++.equ    pi1_sao_v_offset,           120
    ++.equ    wd_offset,                  124
    ++.equ    ht_offset,                  128
    ++
    + .text
    + .p2align 2
    + 
    +@@ -76,10 +84,11 @@ gu1_table_band_idx_addr_2:
    + ihevc_sao_band_offset_chroma_a9q:
    + 
    +     STMFD       sp!, {r4-r12, r14}          @stack stores the values of the arguments
    +-    LDR         r4,[sp,#40]                 @Loads pu1_src_top_left
    +-    LDR         r10,[sp,#64]                @Loads ht
    ++    vpush       {d8  -  d15}
    ++    LDR         r4,[sp,#pu1_src_top_left_offset]    @Loads pu1_src_top_left
    ++    LDR         r10,[sp,#ht_offset]         @Loads ht
    + 
    +-    LDR         r9,[sp,#60]                 @Loads wd
    ++    LDR         r9,[sp,#wd_offset]          @Loads wd
    +     MOV         r11,r10                     @Move the ht to r9 for loop counter
    + 
    +     ADD         r12,r0,r9                   @pu1_src[row * src_strd + (wd)]
    +@@ -94,7 +103,7 @@ SRC_LEFT_LOOP:
    +     STRH        r5,[r2],#2                  @Store the value in pu1_src_left pointer
    +     BNE         SRC_LEFT_LOOP
    + 
    +-    LDR         r5,[sp,#44]                 @Loads sao_band_pos_u
    ++    LDR         r5,[sp,#sao_band_pos_u_offset]  @Loads sao_band_pos_u
    +     VLD1.8      D1,[r14]!                   @band_table_u.val[0]
    +     ADD         r12,r3,r9                   @pu1_src_top[wd]
    + 
    +@@ -104,7 +113,7 @@ SRC_LEFT_LOOP:
    + 
    +     STRH        r11,[r4]                    @store to pu1_src_top_left[0]
    +     VLD1.8      D3,[r14]!                   @band_table_u.val[2]
    +-    LDR         r7,[sp,#52]                 @Loads pi1_sao_offset_u
    ++    LDR         r7,[sp,#pi1_sao_u_offset]   @Loads pi1_sao_offset_u
    + 
    +     SUB         r4,r10,#1                   @ht-1
    +     VDUP.8      D31,r6                      @band_pos_u
    +@@ -147,7 +156,7 @@ ulbl2:
    +     VLD1.8      D10,[r14]!                  @band_table_v.val[1]
    +     VADD.I8     D3,D7,D27                   @band_table_u.val[2] = vadd_u8(band_table_u.val[2], vdup_n_u8(pi1_sao_offset_u[3]))
    + 
    +-    LDR         r6,[sp,#48]                 @Loads sao_band_pos_v
    ++    LDR         r6,[sp,#sao_band_pos_v_offset]  @Loads sao_band_pos_v
    +     VADD.I8     D4,D8,D26                   @band_table_u.val[3] = vadd_u8(band_table_u.val[3], vdup_n_u8(pi1_sao_offset_u[4]))
    +     LSL         r11,r6,#3                   @sao_band_pos_v
    + 
    +@@ -198,7 +207,7 @@ SAO_BAND_POS_U_0:
    + 
    + SWITCH_BREAK_U:
    +     VDUP.8      D30,r11                     @band_pos_v
    +-    LDR         r8,[sp,#56]                 @Loads pi1_sao_offset_v
    ++    LDR         r8,[sp,#pi1_sao_v_offset]   @Loads pi1_sao_offset_v
    + 
    +     VLD1.8      D11,[r14]!                  @band_table_v.val[2]
    +     VADD.I8     D13,D9,D30                  @band_table_v.val[0] = vadd_u8(band_table_v.val[0], band_pos_v)
    +@@ -387,6 +396,7 @@ WIDTH_RESIDUE:                              @If width is not multiple of 16
    +     BNE         WIDTH_RESIDUE
    + 
    + END_LOOP:
    ++    vpop        {d8  -  d15}
    +     LDMFD       sp!,{r4-r12,r15}            @Reload the registers from SP
    + 
    + 
    +diff --git a/common/arm/ihevc_sao_band_offset_luma.s b/common/arm/ihevc_sao_band_offset_luma.s
    +index 3875377..66f2968 100644
    +--- a/common/arm/ihevc_sao_band_offset_luma.s
    ++++ b/common/arm/ihevc_sao_band_offset_luma.s
    +@@ -57,6 +57,12 @@
    + @r7 =>  wd
    + @r8 =>  ht
    + 
    ++.equ    pu1_src_top_left_offset,    104
    ++.equ    sao_band_pos_offset,        108
    ++.equ    pi1_sao_offset,             112
    ++.equ    wd_offset,                  116
    ++.equ    ht_offset,                  120
    ++
    + .text
    + .p2align 2
    + 
    +@@ -69,15 +75,16 @@ gu1_table_band_idx_addr:
    + ihevc_sao_band_offset_luma_a9q:
    + 
    +     STMFD       sp!, {r4-r12, r14}          @stack stores the values of the arguments
    ++    vpush       {d8  -  d15}
    + 
    +-    LDR         r8,[sp,#56]                 @Loads ht
    +-    LDR         r7,[sp,#52]                 @Loads wd
    ++    LDR         r8,[sp,#ht_offset]          @Loads ht
    ++    LDR         r7,[sp,#wd_offset]          @Loads wd
    + 
    +     MOV         r9,r8                       @Move the ht to r9 for loop counter
    +-    LDR         r5,[sp,#44]                 @Loads sao_band_pos
    ++    LDR         r5,[sp,#sao_band_pos_offset]    @Loads sao_band_pos
    +     ADD         r10,r0,r7                   @pu1_src[row * src_strd + (wd)]
    + 
    +-    LDR         r4,[sp,#40]                 @Loads pu1_src_top_left
    ++    LDR         r4,[sp,#pu1_src_top_left_offset]    @Loads pu1_src_top_left
    +     SUB         r10,r10,#1                  @wd-1
    +     LDR         r14, gu1_table_band_idx_addr
    + ulbl1:
    +@@ -91,7 +98,7 @@ SRC_LEFT_LOOP:
    + 
    +     ADD         r9,r3,r7                    @pu1_src_top[wd]
    +     VLD1.8      D1,[r14]!                   @band_table.val[0]
    +-    LDR         r6,[sp,#48]                 @Loads pi1_sao_offset
    ++    LDR         r6,[sp,#pi1_sao_offset]     @Loads pi1_sao_offset
    + 
    +     LSL         r11,r5,#3
    +     VLD1.8      D2,[r14]!                   @band_table.val[1]
    +@@ -226,6 +233,7 @@ HEIGHT_LOOP:
    +     ADD         r0,r0,#8
    +     BNE         SWITCH_BREAK
    + 
    ++    vpop        {d8  -  d15}
    +     LDMFD       sp!,{r4-r12,r15}            @Reload the registers from SP
    + 
    + 
    +diff --git a/common/arm/ihevc_sao_edge_offset_class0.s b/common/arm/ihevc_sao_edge_offset_class0.s
    +index a9fe046..e4bb455 100644
    +--- a/common/arm/ihevc_sao_edge_offset_class0.s
    ++++ b/common/arm/ihevc_sao_edge_offset_class0.s
    +@@ -59,6 +59,14 @@
    + @r9 =>  wd
    + @r10=>  ht
    + 
    ++.equ    pu1_src_top_left_offset,    104
    ++.equ    pu1_src_top_right_offset,   108
    ++.equ    pu1_src_bot_left_offset,    112
    ++.equ    pu1_avail_offset,           116
    ++.equ    pi1_sao_offset,             120
    ++.equ    wd_offset,                  124
    ++.equ    ht_offset,                  128
    ++
    + .text
    + .p2align 2
    + 
    +@@ -72,23 +80,25 @@ ihevc_sao_edge_offset_class0_a9q:
    + 
    + 
    +     STMFD       sp!, {r4-r12, r14}          @stack stores the values of the arguments
    +-    LDR         r9,[sp,#60]                 @Loads wd
    ++    vpush       {d8  -  d15}
    ++
    ++    LDR         r9,[sp,#wd_offset]          @Loads wd
    + 
    +-    LDR         r4,[sp,#40]                 @Loads pu1_src_top_left
    ++    LDR         r4,[sp,#pu1_src_top_left_offset]    @Loads pu1_src_top_left
    +     VMOV.I8     Q1,#2                       @const_2 = vdupq_n_s8(2)
    +     ADD         r11,r3,r9                   @pu1_src_top[wd]
    + 
    +-    LDR         r10,[sp,#64]                @Loads ht
    ++    LDR         r10,[sp,#ht_offset]         @Loads ht
    +     VMOV.I16    Q2,#0                       @const_min_clip = vdupq_n_s16(0)
    +     LDRB        r12,[r11,#-1]               @pu1_src_top[wd - 1]
    + 
    +-    LDR         r7,[sp,#52]                 @Loads pu1_avail
    ++    LDR         r7,[sp,#pu1_avail_offset]   @Loads pu1_avail
    +     VMOV.I16    Q3,#255                     @const_max_clip = vdupq_n_u16((1 << bit_depth) - 1)
    +     LDR         r14, gi1_table_edge_idx_addr @table pointer
    + ulbl1:
    +     add         r14,r14,pc
    + 
    +-    LDR         r8,[sp,#56]                 @Loads pi1_sao_offset
    ++    LDR         r8,[sp,#pi1_sao_offset]     @Loads pi1_sao_offset
    +     VMOV.S8     Q4,#0xFF                    @au1_mask = vdupq_n_s8(-1)
    +     STRB        r12,[r4]                    @*pu1_src_top_left = pu1_src_top[wd - 1]
    + 
    +@@ -337,6 +347,7 @@ PU1_SRC_LOOP_RESIDUE:
    +     BNE         PU1_SRC_LOOP_RESIDUE        @If not equal jump to the pu1_src loop
    + 
    + END_LOOPS:
    ++    vpop        {d8  -  d15}
    +     LDMFD       sp!,{r4-r12,r15}            @Reload the registers from SP
    + 
    + 
    +diff --git a/common/arm/ihevc_sao_edge_offset_class0_chroma.s b/common/arm/ihevc_sao_edge_offset_class0_chroma.s
    +index 1dd56f6..e11cd4f 100644
    +--- a/common/arm/ihevc_sao_edge_offset_class0_chroma.s
    ++++ b/common/arm/ihevc_sao_edge_offset_class0_chroma.s
    +@@ -60,6 +60,15 @@
    + @r9 =>  wd
    + @r10=>  ht
    + 
    ++.equ    pu1_src_top_left_offset,    104
    ++.equ    pu1_src_top_right_offset,   108
    ++.equ    pu1_src_bot_left_offset,    112
    ++.equ    pu1_avail_offset,           116
    ++.equ    pi1_sao_u_offset,           120
    ++.equ    pi1_sao_v_offset,           124
    ++.equ    wd_offset,                  128
    ++.equ    ht_offset,                  132
    ++
    + .text
    + .p2align 2
    + 
    +@@ -73,20 +82,22 @@ ihevc_sao_edge_offset_class0_chroma_a9q:
    + 
    + 
    +     STMFD       sp!, {r4-r12, r14}          @stack stores the values of the arguments
    +-    LDR         r9,[sp,#64]                 @Loads wd
    ++    vpush       {d8  -  d15}
    ++
    ++    LDR         r9,[sp,#wd_offset]          @Loads wd
    + 
    +-    LDR         r4,[sp,#40]                 @Loads pu1_src_top_left
    ++    LDR         r4,[sp,#pu1_src_top_left_offset]    @Loads pu1_src_top_left
    +     ADD         r11,r3,r9                   @pu1_src_top[wd]
    + 
    +-    LDR         r10,[sp,#68]                @Loads ht
    ++    LDR         r10,[sp,#ht_offset]         @Loads ht
    +     VMOV.I8     Q1,#2                       @const_2 = vdupq_n_s8(2)
    +     LDRH        r12,[r11,#-2]               @pu1_src_top[wd - 1]
    + 
    +-    LDR         r7,[sp,#52]                 @Loads pu1_avail
    ++    LDR         r7,[sp,#pu1_avail_offset]   @Loads pu1_avail
    +     VMOV.I16    Q2,#0                       @const_min_clip = vdupq_n_s16(0)
    +     STRH        r12,[r4]                    @*pu1_src_top_left = pu1_src_top[wd - 1]
    + 
    +-    LDR         r8,[sp,#56]                 @Loads pi1_sao_offset_u
    ++    LDR         r8,[sp,#pi1_sao_u_offset]   @Loads pi1_sao_offset_u
    +     VMOV.I16    Q3,#255                     @const_max_clip = vdupq_n_u16((1 << bit_depth) - 1)
    +     SUB         r4,r10,#1                   @(ht - 1)
    + 
    +@@ -96,7 +107,7 @@ ulbl1:
    +     VMOV.S8     Q4,#0xFF                    @au1_mask = vdupq_n_s8(-1)
    +     MUL         r4,r4,r1                    @(ht - 1) * src_strd
    + 
    +-    LDR         r5,[sp,#60]                 @Loads pi1_sao_offset_v
    ++    LDR         r5,[sp,#pi1_sao_v_offset]   @Loads pi1_sao_offset_v
    +     VLD1.8      D11,[r8]                    @offset_tbl = vld1_s8(pi1_sao_offset_u)
    +     ADD         r4,r4,r0                    @pu1_src[(ht - 1) * src_strd]
    + 
    +@@ -423,6 +434,7 @@ PU1_SRC_LOOP_RESIDUE:
    +     BNE         PU1_SRC_LOOP_RESIDUE        @If not equal jump to the pu1_src loop
    + 
    + END_LOOPS:
    ++    vpop        {d8  -  d15}
    +     LDMFD       sp!,{r4-r12,r15}            @Reload the registers from SP
    + 
    + 
    +diff --git a/common/arm/ihevc_sao_edge_offset_class1.s b/common/arm/ihevc_sao_edge_offset_class1.s
    +index aa1337f..029ac46 100644
    +--- a/common/arm/ihevc_sao_edge_offset_class1.s
    ++++ b/common/arm/ihevc_sao_edge_offset_class1.s
    +@@ -58,6 +58,14 @@
    + @r7 =>  wd
    + @r8 =>  ht
    + 
    ++.equ    pu1_src_top_left_offset,    104
    ++.equ    pu1_src_top_right_offset,   108
    ++.equ    pu1_src_bot_left_offset,    112
    ++.equ    pu1_avail_offset,           116
    ++.equ    pi1_sao_offset,             120
    ++.equ    wd_offset,                  124
    ++.equ    ht_offset,                  128
    ++
    + .text
    + .p2align 2
    + 
    +@@ -71,11 +79,13 @@ ihevc_sao_edge_offset_class1_a9q:
    + 
    + 
    +     STMFD       sp!, {r4-r12, r14}          @stack stores the values of the arguments
    +-    LDR         r7,[sp,#60]                 @Loads wd
    +-    LDR         r4,[sp,#40]                 @Loads pu1_src_top_left
    +-    LDR         r5,[sp,#52]                 @Loads pu1_avail
    +-    LDR         r6,[sp,#56]                 @Loads pi1_sao_offset
    +-    LDR         r8,[sp,#64]                 @Loads ht
    ++    vpush       {d8  -  d15}
    ++
    ++    LDR         r7,[sp,#wd_offset]               @Loads wd
    ++    LDR         r4,[sp,#pu1_src_top_left_offset] @Loads pu1_src_top_left
    ++    LDR         r5,[sp,#pu1_avail_offset]        @Loads pu1_avail
    ++    LDR         r6,[sp,#pi1_sao_offset]          @Loads pi1_sao_offset
    ++    LDR         r8,[sp,#ht_offset]               @Loads ht
    + 
    +     SUB         r9,r7,#1                    @wd - 1
    +     LDRB        r10,[r3,r9]                 @pu1_src_top[wd - 1]
    +@@ -362,6 +372,7 @@ PU1_SRC_LOOP_RESIDUE:
    +     VST1.8      {D30},[r10],r1              @vst1q_u8(pu1_src_cpy, pu1_cur_row)
    + 
    + END_LOOPS:
    ++    vpop        {d8  -  d15}
    +     LDMFD       sp!,{r4-r12,r15}            @Reload the registers from SP
    + 
    + 
    +diff --git a/common/arm/ihevc_sao_edge_offset_class1_chroma.s b/common/arm/ihevc_sao_edge_offset_class1_chroma.s
    +index 09d925f..b377220 100644
    +--- a/common/arm/ihevc_sao_edge_offset_class1_chroma.s
    ++++ b/common/arm/ihevc_sao_edge_offset_class1_chroma.s
    +@@ -60,6 +60,15 @@
    + @r8 =>  wd
    + @r9 =>  ht
    + 
    ++.equ    pu1_src_top_left_offset,    104
    ++.equ    pu1_src_top_right_offset,   108
    ++.equ    pu1_src_bot_left_offset,    112
    ++.equ    pu1_avail_offset,           116
    ++.equ    pi1_sao_u_offset,           120
    ++.equ    pi1_sao_v_offset,           124
    ++.equ    wd_offset,                  128
    ++.equ    ht_offset,                  132
    ++
    + .text
    + .p2align 2
    + 
    +@@ -73,13 +82,13 @@ ihevc_sao_edge_offset_class1_chroma_a9q:
    + 
    + 
    +     STMFD       sp!, {r4-r12, r14}          @stack stores the values of the arguments
    +-    LDR         r7,[sp,#60]                 @Loads wd
    +-    LDR         r4,[sp,#40]                 @Loads pu1_src_top_left
    +-    LDR         r5,[sp,#52]                 @Loads pu1_avail
    +-    LDR         r6,[sp,#56]                 @Loads pi1_sao_offset_u
    +-    LDR         r7,[sp,#60]                 @Loads pi1_sao_offset_v
    +-    LDR         r8,[sp,#64]                 @Loads wd
    +-    LDR         r9,[sp,#68]                 @Loads ht
    ++    vpush       {d8  -  d15}
    ++    LDR         r4,[sp,#pu1_src_top_left_offset]    @Loads pu1_src_top_left
    ++    LDR         r5,[sp,#pu1_avail_offset]   @Loads pu1_avail
    ++    LDR         r6,[sp,#pi1_sao_u_offset]   @Loads pi1_sao_offset_u
    ++    LDR         r7,[sp,#pi1_sao_v_offset]   @Loads pi1_sao_offset_v
    ++    LDR         r8,[sp,#wd_offset]          @Loads wd
    ++    LDR         r9,[sp,#ht_offset]          @Loads ht
    + 
    +     SUB         r10,r8,#2                   @wd - 2
    +     LDRH        r11,[r3,r10]                @pu1_src_top[wd - 2]
    +@@ -398,6 +407,7 @@ PU1_SRC_LOOP_RESIDUE:
    +     VST1.8      {D30},[r10],r1              @vst1q_u8(pu1_src_cpy, pu1_cur_row)
    + 
    + END_LOOPS:
    ++    vpop        {d8  -  d15}
    +     LDMFD       sp!,{r4-r12,r15}            @Reload the registers from SP
    + 
    + 
    +diff --git a/common/arm/ihevc_sao_edge_offset_class2.s b/common/arm/ihevc_sao_edge_offset_class2.s
    +index 536f941..15d6efa 100644
    +--- a/common/arm/ihevc_sao_edge_offset_class2.s
    ++++ b/common/arm/ihevc_sao_edge_offset_class2.s
    +@@ -58,6 +58,14 @@
    + @r7 =>  wd
    + @r8=>   ht
    + 
    ++.equ    pu1_src_top_left_offset,    264
    ++.equ    pu1_src_top_right_offset,   268
    ++.equ    pu1_src_bot_left_offset,    272
    ++.equ    pu1_avail_offset,           276
    ++.equ    pi1_sao_offset,             280
    ++.equ    wd_offset,                  284
    ++.equ    ht_offset,                  288
    ++
    + .text
    + .syntax unified
    + .p2align 2
    +@@ -78,28 +86,29 @@ ihevc_sao_edge_offset_class2_a9q:
    + 
    + 
    +     STMFD       sp!,{r4-r12,r14}            @stack stores the values of the arguments
    +-    LDR         r7,[sp,#0x3C]               @Loads wd
    ++    vpush       {d8  -  d15}
    ++    SUB         sp,sp,#160                  @Decrement the stack pointer to store some temp arr values
    + 
    +-    LDR         r8,[sp,#0x40]               @Loads ht
    ++    LDR         r7,[sp,#wd_offset]          @Loads wd
    ++    LDR         r8,[sp,#ht_offset]          @Loads ht
    +     SUB         r9,r7,#1                    @wd - 1
    + 
    +-    LDR         r4,[sp,#0x28]               @Loads pu1_src_top_left
    ++    LDR         r4,[sp,#pu1_src_top_left_offset]    @Loads pu1_src_top_left
    +     LDRB        r10,[r3,r9]                 @pu1_src_top[wd - 1]
    + 
    +-    STR         r0,[sp,#0x2C]               @Store pu1_src in sp
    ++    STR         r0,[sp,#152]                @Store pu1_src in sp
    +     MOV         r9,r7                       @Move width to r9 for loop count
    + 
    +-    STR         r2,[sp,#0x30]               @Store pu1_src_left in sp
    +-    LDR         r5,[sp,#0x34]               @Loads pu1_avail
    +-    LDR         r6,[sp,#0x38]               @Loads pi1_sao_offset
    +-    STR         r3,[sp,#0x38]               @Store pu1_src_top in sp
    ++    STR         r2,[sp,#156]                @Store pu1_src_left in sp
    ++    LDR         r5,[sp,#pu1_avail_offset]   @Loads pu1_avail
    ++    LDR         r6,[sp,#pi1_sao_offset]     @Loads pi1_sao_offset
    ++    STR         r3,[sp,#148]                @Store pu1_src_top in sp
    + 
    +-    SUB         sp,sp,#0x94                 @Decrement the stack pointer to store some temp arr values
    + 
    +     STRB        r10,[sp]                    @u1_src_top_left_tmp = pu1_src_top[wd - 1]
    +     SUB         r10,r8,#1                   @ht-1
    +     MLA         r11,r10,r1,r0               @pu1_src[(ht - 1) * src_strd + col]
    +-    ADD         r12,sp,#0x02                @temp array
    ++    ADD         r12,sp,#2                   @temp array
    + 
    + AU1_SRC_TOP_LOOP:
    +     VLD1.8      D0,[r11]!                   @pu1_src[(ht - 1) * src_strd + col]
    +@@ -203,7 +212,7 @@ ulbl3:
    +     VMOV.S8     Q4,#0xFF                    @au1_mask = vdupq_n_s8(-1)
    +     ADDEQ       r14,r14,#1                  @pu1_src_left_cpy += 1
    + 
    +-    STR         r0,[sp,#0x90]               @Store pu1_src in sp
    ++    STR         r0,[sp,#144]                @Store pu1_src in sp
    +     CMP         r7,#16                      @Compare wd with 16
    + 
    +     BLT         WIDTH_RESIDUE               @If not jump to WIDTH_RESIDUE where loop is unrolled for 8 case
    +@@ -211,9 +220,9 @@ ulbl3:
    +     BLE         WD_16_HT_4_LOOP             @If jump to WD_16_HT_4_LOOP
    + 
    + WIDTH_LOOP_16:
    +-    LDR         r7,[sp,#0xD0]               @Loads wd
    ++    LDR         r7,[sp,#wd_offset]          @Loads wd
    + 
    +-    LDR         r5,[sp,#0xC8]               @Loads pu1_avail
    ++    LDR         r5,[sp,#pu1_avail_offset]   @Loads pu1_avail
    +     CMP         r6,r7                       @col == wd
    +     LDRBEQ      r8,[r5]                     @pu1_avail[0]
    +     MOVNE       r8,#-1                      @au1_mask = vsetq_lane_s8(-1, au1_mask, 0)
    +@@ -232,21 +241,21 @@ SKIP_AU1_MASK_VAL:
    +     MOVNE       r8,r3                       @pu1_src_top_cpy
    +     SUB         r8,r8,#1                    @pu1_src_top_cpy - 1 || pu1_src - src_strd - 1
    + 
    +-    LDR         r7,[sp,#0xD0]               @Loads wd
    ++    LDR         r7,[sp,#wd_offset]          @Loads wd
    +     VLD1.8      D10,[r8]!                   @pu1_top_row = vld1q_u8(pu1_src - src_strd - 1) || vld1q_u8(pu1_src_top_cpy - 1)
    +     VLD1.8      D11,[r8]                    @pu1_top_row = vld1q_u8(pu1_src - src_strd - 1) || vld1q_u8(pu1_src_top_cpy - 1)
    +     SUB         r8,#8
    +     ADD         r3,r3,#16
    + 
    +-    ADD         r5,sp,#0x42                 @*au1_src_left_tmp
    ++    ADD         r5,sp,#66                   @*au1_src_left_tmp
    +     VLD1.8      D12,[r0]!                   @pu1_cur_row = vld1q_u8(pu1_src)
    +     VLD1.8      D13,[r0]                    @pu1_cur_row = vld1q_u8(pu1_src)
    +     SUB         r0,#8
    +-    LDR         r4,[sp,#0xD4]               @Loads ht
    ++    LDR         r4,[sp,#ht_offset]          @Loads ht
    + 
    +     SUB         r7,r7,r6                    @(wd - col)
    +     VCGT.U8     Q7,Q6,Q5                    @vcgtq_u8(pu1_cur_row, pu1_top_row)
    +-    LDR         r8,[sp,#0xC0]               @Loads *pu1_src
    ++    LDR         r8,[sp,#152]                @Loads *pu1_src
    + 
    +     ADD         r7,r7,#15                   @15 + (wd - col)
    +     VCLT.U8     Q8,Q6,Q5                    @vcltq_u8(pu1_cur_row, pu1_top_row)
    +@@ -263,7 +272,7 @@ AU1_SRC_LEFT_LOOP:
    + 
    +     ADD         r8,r0,r1                    @I Iteration *pu1_src + src_strd
    +     VMOV.I8     Q9,#0
    +-    LDR         r4,[sp,#0xC8]               @I Loads pu1_avail
    ++    LDR         r4,[sp,#pu1_avail_offset]   @I Loads pu1_avail
    + 
    +     MOV         r7,r12                      @row count, move ht_tmp to r7
    +     VLD1.8      D16,[r8]!                   @I pu1_next_row = vld1q_u8(pu1_src_cpy + src_strd)
    +@@ -498,11 +507,11 @@ PU1_SRC_LOOP:
    + 
    + 
    + INNER_LOOP_DONE:
    +-    ADD         r5,sp,#0x42                 @*au1_src_left_tmp
    ++    ADD         r5,sp,#66                   @*au1_src_left_tmp
    +     VST1.8      {Q10},[r0],r1               @vst1q_u8(pu1_src_cpy, pu1_cur_row)
    +-    LDR         r2,[sp,#0xC4]               @Loads *pu1_src_left
    ++    LDR         r2,[sp,#156]                @Loads *pu1_src_left
    + 
    +-    LDR         r8,[sp,#0xD4]               @Loads ht
    ++    LDR         r8,[sp,#ht_offset]          @Loads ht
    +     SUB         r5,r5,#1
    + 
    +     SUB         r2,r2,#1
    +@@ -515,8 +524,8 @@ SRC_LEFT_LOOP:
    +     SUB         r6,r6,#16                   @Decrement the wd loop count by 16
    +     CMP         r6,#8                       @Check whether residue remains
    +     BLT         RE_ASSINING_LOOP            @Jump to re-assigning loop
    +-    LDR         r7,[sp,#0xD0]               @Loads wd
    +-    LDR         r0,[sp,#0x90]               @Loads *pu1_src
    ++    LDR         r7,[sp,#wd_offset]          @Loads wd
    ++    LDR         r0,[sp,#144]                @Loads *pu1_src
    +     SUB         r7,r7,r6
    +     ADD         r0,r0,r7
    +     BGT         WIDTH_LOOP_16               @If not equal jump to width_loop
    +@@ -524,8 +533,8 @@ SRC_LEFT_LOOP:
    + 
    + 
    + WD_16_HT_4_LOOP:
    +-    LDR         r7,[sp,#0xD0]               @Loads wd
    +-    LDR         r5,[sp,#0xC8]               @Loads pu1_avail
    ++    LDR         r7,[sp,#wd_offset]          @Loads wd
    ++    LDR         r5,[sp,#pu1_avail_offset]   @Loads pu1_avail
    +     CMP         r6,r7                       @col == wd
    +     LDRBEQ      r8,[r5]                     @pu1_avail[0]
    +     MOVNE       r8,#-1                      @au1_mask = vsetq_lane_s8(-1, au1_mask, 0)
    +@@ -544,21 +553,21 @@ SKIP_AU1_MASK_VAL_WD_16_HT_4:
    +     MOVNE       r8,r3
    +     SUB         r8,r8,#1                    @pu1_src_top_cpy - 1 || pu1_src - src_strd - 1
    + 
    +-    LDR         r7,[sp,#0xD0]               @Loads wd
    ++    LDR         r7,[sp,#wd_offset]          @Loads wd
    +     VLD1.8      D10,[r8]!                   @pu1_top_row = vld1q_u8(pu1_src - src_strd - 1) || vld1q_u8(pu1_src_top_cpy - 1)
    +     VLD1.8      D11,[r8]                    @pu1_top_row = vld1q_u8(pu1_src - src_strd - 1) || vld1q_u8(pu1_src_top_cpy - 1)
    +     SUB         r8,#8
    +     ADD         r3,r3,#16
    + 
    +-    ADD         r5,sp,#0x42                 @*au1_src_left_tmp
    ++    ADD         r5,sp,#66                   @*au1_src_left_tmp
    +     VLD1.8      D12,[r0]!                   @pu1_cur_row = vld1q_u8(pu1_src)
    +     VLD1.8      D13,[r0]                    @pu1_cur_row = vld1q_u8(pu1_src)
    +     SUB         r0,#8
    +-    LDR         r4,[sp,#0xD4]               @Loads ht
    ++    LDR         r4,[sp,#ht_offset]          @Loads ht
    + 
    +     SUB         r7,r7,r6                    @(wd - col)
    +     VCGT.U8     Q7,Q6,Q5                    @vcgtq_u8(pu1_cur_row, pu1_top_row)
    +-    LDR         r8,[sp,#0xC0]               @Loads *pu1_src
    ++    LDR         r8,[sp,#152]                @Loads *pu1_src
    + 
    +     ADD         r7,r7,#15                   @15 + (wd - col)
    +     VCLT.U8     Q8,Q6,Q5                    @vcltq_u8(pu1_cur_row, pu1_top_row)
    +@@ -588,7 +597,7 @@ PU1_SRC_LOOP_WD_16_HT_4:
    + 
    +     CMP         r7,r12
    +     BLT         SIGN_UP_CHANGE_WD_16_HT_4
    +-    LDR         r5,[sp,#0xC8]               @Loads pu1_avail
    ++    LDR         r5,[sp,#pu1_avail_offset]   @Loads pu1_avail
    +     LDRB        r5,[r5,#2]                  @pu1_avail[2]
    +     CMP         r5,#0
    +     BNE         SIGN_UP_CHANGE_DONE_WD_16_HT_4
    +@@ -639,9 +648,9 @@ SIGN_UP_CHANGE_DONE_WD_16_HT_4:
    +     SUBS        r7,r7,#1                    @Decrement the ht_tmp loop count by 1
    +     BNE         PU1_SRC_LOOP_WD_16_HT_4     @If not equal jump to PU1_SRC_LOOP_WD_16_HT_4
    + 
    +-    LDR         r8,[sp,#0xD4]               @Loads ht
    +-    ADD         r5,sp,#0x42                 @*au1_src_left_tmp
    +-    LDR         r2,[sp,#0xC4]               @Loads *pu1_src_left
    ++    LDR         r8,[sp,#ht_offset]          @Loads ht
    ++    ADD         r5,sp,#66                   @*au1_src_left_tmp
    ++    LDR         r2,[sp,#156]                @Loads *pu1_src_left
    +     SUB         r5,r5,#1
    +     SUB         r2,r2,#1
    + 
    +@@ -656,8 +665,8 @@ SRC_LEFT_LOOP_WD_16_HT_4:
    + 
    + 
    + WIDTH_RESIDUE:
    +-    LDR         r7,[sp,#0xD0]               @Loads wd
    +-    LDR         r5,[sp,#0xC8]               @Loads pu1_avail
    ++    LDR         r7,[sp,#wd_offset]          @Loads wd
    ++    LDR         r5,[sp,#pu1_avail_offset]   @Loads pu1_avail
    +     CMP         r6,r7                       @wd_residue == wd
    +     LDRBEQ      r8,[r5]                     @pu1_avail[0]
    + 
    +@@ -679,16 +688,16 @@ PU1_AVAIL_2_RESIDUE:
    + 
    +     SUB         r8,r8,#1
    + 
    +-    ADD         r5,sp,#0x42                 @*au1_src_left_tmp
    ++    ADD         r5,sp,#66                   @*au1_src_left_tmp
    +     VLD1.8      D10,[r8]!                   @pu1_top_row = vld1q_u8(pu1_src_top_cpy - 1)
    +     VLD1.8      D11,[r8]!                   @pu1_top_row = vld1q_u8(pu1_src_top_cpy - 1)
    +-    LDR         r7,[sp,#0xD0]               @Loads wd
    ++    LDR         r7,[sp,#wd_offset]          @Loads wd
    + 
    +-    LDR         r4,[sp,#0xD4]               @Loads ht
    ++    LDR         r4,[sp,#ht_offset]          @Loads ht
    +     VCGT.U8     Q7,Q6,Q5                    @vcgtq_u8(pu1_cur_row, pu1_top_row)
    +     SUB         r7,r7,#1                    @(wd - 1)
    + 
    +-    LDR         r8,[sp,#0xC0]               @Loads *pu1_src
    ++    LDR         r8,[sp,#152]                @Loads *pu1_src
    +     VCLT.U8     Q8,Q6,Q5                    @vcltq_u8(pu1_cur_row, pu1_top_row)
    +     SUB         r5,r5,#1
    + 
    +@@ -718,7 +727,7 @@ PU1_SRC_LOOP_RESIDUE:
    + 
    +     CMP         r7,r12
    +     BLT         SIGN_UP_CHANGE_RESIDUE
    +-    LDR         r5,[sp,#0xC8]               @Loads pu1_avail
    ++    LDR         r5,[sp,#pu1_avail_offset]   @Loads pu1_avail
    +     LDRB        r5,[r5,#2]                  @pu1_avail[2]
    +     CMP         r5,#0
    +     BNE         SIGN_UP_CHANGE_DONE_RESIDUE
    +@@ -762,10 +771,10 @@ SIGN_UP_CHANGE_DONE_RESIDUE:
    +     SUBS        r7,r7,#1
    +     BNE         PU1_SRC_LOOP_RESIDUE
    + 
    +-    LDR         r8,[sp,#0xD4]               @Loads ht
    +-    ADD         r5,sp,#0x42                 @*au1_src_left_tmp
    ++    LDR         r8,[sp,#ht_offset]          @Loads ht
    ++    ADD         r5,sp,#66                   @*au1_src_left_tmp
    + 
    +-    LDR         r2,[sp,#0xC4]               @Loads *pu1_src_left
    ++    LDR         r2,[sp,#156]                @Loads *pu1_src_left
    +     SUB         r5,r5,#1
    + 
    +     SUB         r2,r2,#1
    +@@ -778,23 +787,23 @@ SRC_LEFT_LOOP_RESIDUE:
    + 
    + 
    + RE_ASSINING_LOOP:
    +-    LDR         r8,[sp,#0xD4]               @Loads ht
    +-    LDR         r7,[sp,#0xD0]               @Loads wd
    ++    LDR         r8,[sp,#ht_offset]          @Loads ht
    ++    LDR         r7,[sp,#wd_offset]          @Loads wd
    + 
    +-    LDR         r0,[sp,#0xC0]               @Loads *pu1_src
    ++    LDR         r0,[sp,#152]                @Loads *pu1_src
    +     SUB         r8,r8,#1                    @ht - 1
    + 
    +     MLA         r6,r8,r1,r7                 @wd - 1 + (ht - 1) * src_strd
    +     STRB        r9,[r0]                     @pu1_src_org[0] = u1_pos_0_0_tmp
    + 
    +-    LDR         r4,[sp,#0xBC]               @Loads pu1_src_top_left
    ++    LDR         r4,[sp,#pu1_src_top_left_offset] @Loads pu1_src_top_left
    +     ADD         r6,r0,r6                    @pu1_src[wd - 1 + (ht - 1) * src_strd]
    + 
    +-    ADD         r12,sp,#0x02
    ++    ADD         r12,sp,#2
    +     STRB        r10,[r6,#-1]                @pu1_src_org[wd - 1 + (ht - 1) * src_strd] = u1_pos_wd_ht_tmp
    + 
    +     LDRB        r11,[sp]                    @load u1_src_top_left_tmp from stack pointer
    +-    LDR         r3,[sp,#0xCC]               @Loads pu1_src_top
    ++    LDR         r3,[sp,#148]                @Loads pu1_src_top
    + 
    +     STRB        r11,[r4]                    @*pu1_src_top_left = u1_src_top_left_tmp
    + 
    +@@ -805,7 +814,8 @@ SRC_TOP_LOOP:
    +     BNE         SRC_TOP_LOOP
    + 
    + END_LOOPS:
    +-    ADD         sp,sp,#0x94
    ++    ADD         sp,sp,#160
    ++    vpop        {d8  -  d15}
    +     LDMFD       sp!,{r4-r12,r15}            @Reload the registers from SP
    + 
    + 
    +diff --git a/common/arm/ihevc_sao_edge_offset_class2_chroma.s b/common/arm/ihevc_sao_edge_offset_class2_chroma.s
    +index b74a8f6..f7ab3f8 100644
    +--- a/common/arm/ihevc_sao_edge_offset_class2_chroma.s
    ++++ b/common/arm/ihevc_sao_edge_offset_class2_chroma.s
    +@@ -60,6 +60,15 @@
    + @r7 =>  wd
    + @r8=>   ht
    + 
    ++.equ    pu1_src_top_left_offset,    328
    ++.equ    pu1_src_top_right_offset,   332
    ++.equ    pu1_src_bot_left_offset,    336
    ++.equ    pu1_avail_offset,           340
    ++.equ    pi1_sao_u_offset,           344
    ++.equ    pi1_sao_v_offset,           348
    ++.equ    wd_offset,                  352
    ++.equ    ht_offset,                  356
    ++
    + .text
    + .syntax unified
    + .p2align 2
    +@@ -86,23 +95,24 @@ ihevc_sao_edge_offset_class2_chroma_a9q:
    + 
    + 
    +     STMFD       sp!,{r4-r12,r14}            @stack stores the values of the arguments
    ++    vpush       {d8  -  d15}
    ++    SUB         sp,sp,#224                  @Decrement the stack pointer to store some temp arr values
    + 
    +-    LDR         r7,[sp,#0x40]               @Loads wd
    +-    LDR         r8,[sp,#0x44]               @Loads ht
    ++    LDR         r7,[sp,#wd_offset]          @Loads wd
    ++    LDR         r8,[sp,#ht_offset]          @Loads ht
    +     SUB         r9,r7,#2                    @wd - 2
    + 
    +-    LDR         r4,[sp,#0x28]               @Loads pu1_src_top_left
    ++    LDR         r4,[sp,#pu1_src_top_left_offset]    @Loads pu1_src_top_left
    +     LDRH        r10,[r3,r9]                 @pu1_src_top[wd - 2]
    + 
    +-    STR         r0,[sp,#0x2C]               @Store pu1_src in sp
    ++    STR         r0,[sp,#212]                @Store pu1_src in sp
    +     MOV         r9,r7                       @Move width to r9 for loop count
    + 
    +-    STR         r2,[sp,#0x30]               @Store pu1_src_left in sp
    +-    LDR         r5,[sp,#0x34]               @Loads pu1_avail
    +-    LDR         r6,[sp,#0x38]               @Loads pi1_sao_offset_u
    ++    STR         r2,[sp,#216]                @Store pu1_src_left in sp
    ++    LDR         r5,[sp,#pu1_avail_offset]   @Loads pu1_avail
    ++    LDR         r6,[sp,#pi1_sao_u_offset]   @Loads pi1_sao_offset_u
    + 
    +-    STR         r3,[sp,#0x38]               @Store pu1_src_top in sp
    +-    SUB         sp,sp,#0xD4                 @Decrement the stack pointer to store some temp arr values
    ++    STR         r3,[sp,#220]                @Store pu1_src_top in sp
    + 
    +     STRH        r10,[sp]                    @u1_src_top_left_tmp = pu1_src_top[wd - 2]
    +     SUB         r10,r8,#1                   @ht-1
    +@@ -178,7 +188,7 @@ ulbl2:
    +     LDRSB       r12,[r14,r11]               @edge_idx = gi1_table_edge_idx[edge_idx]
    +     CMP         r12,#0                      @0 != edge_idx
    +     BEQ         PU1_AVAIL_7_LOOP_U
    +-    LDR         r11,[sp,#0x110]             @Loads pi1_sao_offset_v
    ++    LDR         r11,[sp,#pi1_sao_v_offset]  @Loads pi1_sao_offset_v
    +     LDRSB       r11,[r11,r12]               @pi1_sao_offset_v[edge_idx]
    +     ADD         r10,r10,r11                 @pu1_src[0] + pi1_sao_offset_v[edge_idx]
    +     USAT        r10,#8,r10                  @u1_pos_0_0_tmp_v = CLIP3(pu1_src[0] + pi1_sao_offset_v[edge_idx], 0, (1 << bit_depth) - 1)
    +@@ -253,7 +263,7 @@ ulbl4:
    +     LDRSB       r12,[r14,r11]               @edge_idx = gi1_table_edge_idx[edge_idx]
    +     CMP         r12,#0
    +     BEQ         PU1_AVAIL_3_LOOP
    +-    LDR         r14,[sp,#0x110]             @Loads pi1_sao_offset_v
    ++    LDR         r14,[sp,#pi1_sao_v_offset]  @Loads pi1_sao_offset_v
    +     LDRSB       r11,[r14,r12]               @pi1_sao_offset_v[edge_idx]
    +     ADD         r9,r9,r11                   @pu1_src[wd - 1 + (ht - 1) * src_strd] + pi1_sao_offset[edge_idx]
    +     USAT        r9,#8,r9                    @u1_pos_wd_ht_tmp_v = CLIP3(pu1_src[wd - 1 + (ht - 1) * src_strd] + pi1_sao_offset[edge_idx], 0, (1 << bit_depth) - 1)
    +@@ -280,7 +290,7 @@ PU1_AVAIL_3_LOOP:
    +     VLD1.8      D6,[r6]                     @offset_tbl_u = vld1_s8(pi1_sao_offset_u)
    +     SUBEQ       r12,r12,#1                  @ht_tmp--
    + 
    +-    LDR         r6,[sp,#0x110]              @Loads pi1_sao_offset_v
    ++    LDR         r6,[sp,#pi1_sao_v_offset]   @Loads pi1_sao_offset_v
    +     ADDEQ       r14,r14,#2                  @pu1_src_left_cpy += 2
    + 
    +     STR         r0,[sp,#2]                  @Store pu1_src in sp
    +@@ -298,8 +308,8 @@ ulbl5:
    +     BLE         WD_16_HT_4_LOOP             @If jump to WD_16_HT_4_LOOP
    + 
    + WIDTH_LOOP_16:
    +-    LDR         r5,[sp,#0x108]              @Loads pu1_avail
    +-    LDR         r7,[sp,#0x114]              @Loads wd
    ++    LDR         r5,[sp,#pu1_avail_offset]   @Loads pu1_avail
    ++    LDR         r7,[sp,#wd_offset]          @Loads wd
    +     CMP         r6,r7                       @col == wd
    +     LDRBEQ      r8,[r5]                     @pu1_avail[0]
    + 
    +@@ -321,16 +331,16 @@ SKIP_AU1_MASK_VAL:
    +     SUB         r0,#8
    +     CMP         r9,#0
    + 
    +-    LDR         r4,[sp,#0x118]              @Loads ht
    ++    LDR         r4,[sp,#ht_offset]          @Loads ht
    +     SUBEQ       r8,r0,r1                    @pu1_src - src_strd
    + 
    +-    LDR         r7,[sp,#0x114]              @Loads wd
    ++    LDR         r7,[sp,#wd_offset]          @Loads wd
    +     MOVNE       r8,r3                       @pu1_src_top_cpy
    + 
    +     SUB         r8,r8,#2                    @pu1_src - src_strd - 2
    +     ADD         r3,r3,#16
    + 
    +-    ADD         r5,sp,#0x4B                 @*au1_src_left_tmp
    ++    ADD         r5,sp,#75                   @*au1_src_left_tmp
    +     VLD1.8      D10,[r8]!                   @pu1_top_row = vld1q_u8(pu1_src - src_strd - 2) || vld1q_u8(pu1_src_top_cpy - 2)
    +     VLD1.8      D11,[r8]                    @pu1_top_row = vld1q_u8(pu1_src - src_strd - 2) || vld1q_u8(pu1_src_top_cpy - 2)
    +     SUB         r8,#8
    +@@ -338,7 +348,7 @@ SKIP_AU1_MASK_VAL:
    + 
    +     ADD         r7,r7,#14                   @15 + (wd - col)
    +     VCGT.U8     Q7,Q6,Q5                    @vcgtq_u8(pu1_cur_row, pu1_top_row)
    +-    LDR         r8,[sp,#0x100]              @Loads *pu1_src
    ++    LDR         r8,[sp,#212]                @Loads *pu1_src
    + 
    +     ADD         r7,r8,r7                    @pu1_src[0 * src_strd + 15 + (wd - col)]
    +     VCLT.U8     Q8,Q6,Q5                    @vcltq_u8(pu1_cur_row, pu1_top_row)
    +@@ -364,7 +374,7 @@ AU1_SRC_LEFT_LOOP:
    +     VMOV.I8     Q9,#0
    +     LDRH        r5,[r8]                     @I pu1_src_cpy[src_strd + 16]
    + 
    +-    LDR         r10,[sp,#0x108]             @I Loads pu1_avail
    ++    LDR         r10,[sp,#pu1_avail_offset]  @I Loads pu1_avail
    +     VMOV.16     D18[0],r5                   @I pu1_next_row_tmp = vsetq_lane_u8(pu1_src_cpy[src_strd + 16], pu1_next_row_tmp, 0)
    +     LDRB        r10,[r10,#2]                @I pu1_avail[2]
    + 
    +@@ -654,11 +664,11 @@ PU1_SRC_LOOP:
    + 
    + 
    + INNER_LOOP_DONE:
    +-    LDR         r8,[sp,#0x118]              @Loads ht
    ++    LDR         r8,[sp,#ht_offset]          @Loads ht
    +     VMOVN.I16   D20,Q10                     @vmovn_s16(pi2_tmp_cur_row.val[0])
    +-    ADD         r5,sp,#0x4B                 @*au1_src_left_tmp
    ++    ADD         r5,sp,#75                   @*au1_src_left_tmp
    + 
    +-    LDR         r11,[sp,#0x104]             @Loads *pu1_src_left
    ++    LDR         r11,[sp,#216]               @Loads *pu1_src_left
    +     VMOVN.I16   D21,Q9                      @vmovn_s16(pi2_tmp_cur_row.val[1])
    + 
    + 
    +@@ -673,8 +683,8 @@ SRC_LEFT_LOOP:
    +     CMP         r6,#8                       @Check whether residue remains
    + 
    +     BLT         RE_ASSINING_LOOP            @Jump to re-assigning loop
    +-    LDR         r7,[sp,#0x114]              @Loads wd
    +-    LDR         r0,[sp,#0x02]               @Loads *pu1_src
    ++    LDR         r7,[sp,#wd_offset]          @Loads wd
    ++    LDR         r0,[sp,#2]                  @Loads *pu1_src
    +     SUB         r7,r7,r6
    +     ADD         r0,r0,r7
    +     BGT         WIDTH_LOOP_16               @If not equal jump to width_loop
    +@@ -682,8 +692,8 @@ SRC_LEFT_LOOP:
    + 
    + 
    + WD_16_HT_4_LOOP:
    +-    LDR         r5,[sp,#0x108]              @Loads pu1_avail
    +-    LDR         r7,[sp,#0x114]              @Loads wd
    ++    LDR         r5,[sp,#pu1_avail_offset]   @Loads pu1_avail
    ++    LDR         r7,[sp,#wd_offset]          @Loads wd
    +     CMP         r6,r7                       @col == wd
    +     LDRBEQ      r8,[r5]                     @pu1_avail[0]
    + 
    +@@ -709,12 +719,12 @@ SKIP_AU1_MASK_VAL_WD_16_HT_4:
    +     SUB         r8,#8
    + 
    +     ADD         r3,r3,#16
    +-    ADD         r5,sp,#0x4B                 @*au1_src_left_tmp
    +-    LDR         r4,[sp,#0x118]              @Loads ht
    +-    LDR         r7,[sp,#0x114]              @Loads wd
    ++    ADD         r5,sp,#75                   @*au1_src_left_tmp
    ++    LDR         r4,[sp,#ht_offset]          @Loads ht
    ++    LDR         r7,[sp,#wd_offset]          @Loads wd
    +     SUB         r7,r7,r6                    @(wd - col)
    +     ADD         r7,r7,#14                   @15 + (wd - col)
    +-    LDR         r8,[sp,#0x100]              @Loads *pu1_src
    ++    LDR         r8,[sp,#212]                @Loads *pu1_src
    +     ADD         r7,r8,r7                    @pu1_src[0 * src_strd + 15 + (wd - col)]
    + 
    + AU1_SRC_LEFT_LOOP_WD_16_HT_4:
    +@@ -749,7 +759,7 @@ PU1_SRC_LOOP_WD_16_HT_4:
    + 
    +     CMP         r7,r12
    +     BLT         SIGN_UP_CHANGE_WD_16_HT_4
    +-    LDR         r5,[sp,#0x108]              @Loads pu1_avail
    ++    LDR         r5,[sp,#pu1_avail_offset]   @Loads pu1_avail
    +     LDRB        r5,[r5,#2]                  @pu1_avail[2]
    +     CMP         r5,#0
    +     BNE         SIGN_UP_CHANGE_DONE_WD_16_HT_4
    +@@ -815,9 +825,9 @@ SIGN_UP_CHANGE_DONE_WD_16_HT_4:
    +     SUBS        r7,r7,#1                    @Decrement the ht_tmp loop count by 1
    +     BNE         PU1_SRC_LOOP_WD_16_HT_4     @If not equal jump to PU1_SRC_LOOP_WD_16_HT_4
    + 
    +-    LDR         r8,[sp,#0x118]              @Loads ht
    +-    ADD         r5,sp,#0x4B                 @*au1_src_left_tmp
    +-    LDR         r11,[sp,#0x104]             @Loads *pu1_src_left
    ++    LDR         r8,[sp,#ht_offset]          @Loads ht
    ++    ADD         r5,sp,#75                   @*au1_src_left_tmp
    ++    LDR         r11,[sp,#216]               @Loads *pu1_src_left
    + 
    + SRC_LEFT_LOOP_WD_16_HT_4:
    +     LDR         r7,[r5],#4                  @au1_src_left_tmp[row]
    +@@ -829,12 +839,16 @@ SRC_LEFT_LOOP_WD_16_HT_4:
    + 
    +     SUBS        r6,r6,#16                   @Decrement the wd loop count by 16
    +     BLE         RE_ASSINING_LOOP            @Jump to re-assigning loop
    ++    LDR         r7,[sp,#wd_offset]          @Loads wd
    ++    LDR         r0,[sp,#2]                  @Loads *pu1_src
    ++    SUB         r7,r7,r6
    ++    ADD         r0,r0,r7
    +     BGT         WD_16_HT_4_LOOP
    + 
    + 
    + WIDTH_RESIDUE:
    +-    LDR         r7,[sp,#0x114]              @Loads wd
    +-    LDR         r5,[sp,#0x108]              @Loads pu1_avail
    ++    LDR         r7,[sp,#wd_offset]          @Loads wd
    ++    LDR         r5,[sp,#pu1_avail_offset]   @Loads pu1_avail
    +     CMP         r6,r7                       @wd_residue == wd
    +     LDRBEQ      r8,[r5]                     @pu1_avail[0]
    + 
    +@@ -856,10 +870,10 @@ WIDTH_RESIDUE:
    +     VLD1.8      D11,[r8]                    @pu1_top_row = vld1q_u8(pu1_src - src_strd - 2)
    +     SUB         r8,#8
    + 
    +-    ADD         r5,sp,#0x4B                 @*au1_src_left_tmp
    +-    LDR         r4,[sp,#0x118]              @Loads ht
    +-    LDR         r7,[sp,#0x114]              @Loads wd
    +-    LDR         r8,[sp,#0x100]              @Loads *pu1_src
    ++    ADD         r5,sp,#75                   @*au1_src_left_tmp
    ++    LDR         r4,[sp,#ht_offset]          @Loads ht
    ++    LDR         r7,[sp,#wd_offset]          @Loads wd
    ++    LDR         r8,[sp,#212]                @Loads *pu1_src
    +     SUB         r7,r7,#2                    @(wd - 2)
    +     ADD         r7,r8,r7                    @pu1_src[0 * src_strd + (wd - 2)]
    + 
    +@@ -893,7 +907,7 @@ PU1_SRC_LOOP_RESIDUE:
    + 
    +     CMP         r7,r12
    +     BLT         SIGN_UP_CHANGE_RESIDUE
    +-    LDR         r5,[sp,#0x108]              @Loads pu1_avail
    ++    LDR         r5,[sp,#pu1_avail_offset]   @Loads pu1_avail
    +     LDRB        r5,[r5,#2]                  @pu1_avail[2]
    +     CMP         r5,#0
    +     BNE         SIGN_UP_CHANGE_DONE_RESIDUE
    +@@ -953,9 +967,9 @@ SIGN_UP_CHANGE_DONE_RESIDUE:
    +     SUBS        r7,r7,#1                    @Decrement the ht_tmp loop count by 1
    +     BNE         PU1_SRC_LOOP_RESIDUE        @If not equal jump to PU1_SRC_LOOP
    + 
    +-    LDR         r8,[sp,#0x118]              @Loads ht
    +-    LDR         r11,[sp,#0x104]             @Loads *pu1_src_left
    +-    ADD         r5,sp,#0x4B                 @*au1_src_left_tmp
    ++    LDR         r8,[sp,#ht_offset]          @Loads ht
    ++    LDR         r11,[sp,#216]               @Loads *pu1_src_left
    ++    ADD         r5,sp,#75                   @*au1_src_left_tmp
    + 
    + SRC_LEFT_LOOP_RESIDUE:
    +     LDR         r7,[r5],#4                  @au1_src_left_tmp[row]
    +@@ -966,12 +980,12 @@ SRC_LEFT_LOOP_RESIDUE:
    + 
    + 
    + RE_ASSINING_LOOP:
    +-    LDR         r8,[sp,#0x118]              @Loads ht
    ++    LDR         r8,[sp,#ht_offset]          @Loads ht
    + 
    +-    LDR         r0,[sp,#0x100]              @Loads *pu1_src
    ++    LDR         r0,[sp,#212]                @Loads *pu1_src
    +     SUB         r8,r8,#1                    @ht - 1
    + 
    +-    LDR         r7,[sp,#0x114]              @Loads wd
    ++    LDR         r7,[sp,#wd_offset]          @Loads wd
    + 
    +     LDRH        r9,[sp,#6]
    +     MLA         r6,r8,r1,r7                 @wd - 2 + (ht - 1) * src_strd
    +@@ -983,10 +997,10 @@ RE_ASSINING_LOOP:
    +     ADD         r12,sp,#10
    +     STRH        r9,[r6,#-2]                 @pu1_src_org[wd - 1 + (ht - 1) * src_strd] = u1_pos_wd_ht_tmp_u
    + 
    +-    LDR         r4,[sp,#0xFC]               @Loads pu1_src_top_left
    ++    LDR         r4,[sp,#pu1_src_top_left_offset]               @Loads pu1_src_top_left
    +     LDRH        r10,[sp]                    @load u1_src_top_left_tmp from stack pointer
    +     STRH        r10,[r4]                    @*pu1_src_top_left = u1_src_top_left_tmp
    +-    LDR         r3,[sp,#0x10C]              @Loads pu1_src_top
    ++    LDR         r3,[sp,#220]                @Loads pu1_src_top
    + 
    + SRC_TOP_LOOP:
    +     VLD1.8      D0,[r12]!                   @pu1_src_top[col] = au1_src_top_tmp[col]
    +@@ -995,7 +1009,9 @@ SRC_TOP_LOOP:
    +     BNE         SRC_TOP_LOOP
    + 
    + END_LOOPS:
    +-    ADD         sp,sp,#0xD4
    ++    ADD         sp,sp,#224
    ++
    ++    vpop        {d8  -  d15}
    +     LDMFD       sp!,{r4-r12,r15}            @Reload the registers from SP
    + 
    + 
    +diff --git a/common/arm/ihevc_sao_edge_offset_class3.s b/common/arm/ihevc_sao_edge_offset_class3.s
    +index de09d6c..fb3b05c 100644
    +--- a/common/arm/ihevc_sao_edge_offset_class3.s
    ++++ b/common/arm/ihevc_sao_edge_offset_class3.s
    +@@ -58,6 +58,14 @@
    + @r7 =>  wd
    + @r8=>   ht
    + 
    ++.equ    pu1_src_top_left_offset,    264
    ++.equ    pu1_src_top_right_offset,   268
    ++.equ    pu1_src_bot_left_offset,    272
    ++.equ    pu1_avail_offset,           276
    ++.equ    pi1_sao_offset,             280
    ++.equ    wd_offset,                  284
    ++.equ    ht_offset,                  288
    ++
    + .text
    + .syntax unified
    + .p2align 2
    +@@ -78,26 +86,27 @@ ihevc_sao_edge_offset_class3_a9q:
    + 
    + 
    +     STMFD       sp!,{r4-r12,r14}            @stack stores the values of the arguments
    +-    LDR         r7,[sp,#0x3C]               @Loads wd
    ++    vpush       {d8  -  d15}
    ++    SUB         sp,sp,#160                  @Decrement the stack pointer to store some temp arr values
    ++    LDR         r7,[sp,#wd_offset]          @Loads wd
    + 
    +-    LDR         r8,[sp,#0x40]               @Loads ht
    ++    LDR         r8,[sp,#ht_offset]          @Loads ht
    +     SUB         r9,r7,#1                    @wd - 1
    + 
    +-    LDR         r4,[sp,#0x28]               @Loads pu1_src_top_left
    ++    LDR         r4,[sp,#pu1_src_top_left_offset]               @Loads pu1_src_top_left
    +     LDRB        r10,[r3,r9]                 @pu1_src_top[wd - 1]
    + 
    +     MOV         r9,r7                       @Move width to r9 for loop count
    + 
    +-    LDR         r5,[sp,#0x34]               @Loads pu1_avail
    +-    LDR         r6,[sp,#0x38]               @Loads pi1_sao_offset
    +-    STR         r3,[sp,#0x38]               @Store pu1_src_top in sp
    ++    LDR         r5,[sp,#pu1_avail_offset]   @Loads pu1_avail
    ++    LDR         r6,[sp,#pi1_sao_offset]     @Loads pi1_sao_offset
    ++    STR         r3,[sp,#156]                @Store pu1_src_top in sp
    + 
    +-    SUB         sp,sp,#0x94                 @Decrement the stack pointer to store some temp arr values
    + 
    +     STRB        r10,[sp]                    @u1_src_top_left_tmp = pu1_src_top[wd - 1]
    +     SUB         r10,r8,#1                   @ht-1
    +     MLA         r11,r10,r1,r0               @pu1_src[(ht - 1) * src_strd + col]
    +-    ADD         r12,sp,#0x02                @temp array
    ++    ADD         r12,sp,#2                   @temp array
    + 
    + AU1_SRC_TOP_LOOP:
    +     VLD1.8      D0,[r11]!                   @pu1_src[(ht - 1) * src_strd + col]
    +@@ -112,7 +121,7 @@ PU1_AVAIL_5_LOOP:
    +     LDRB        r9,[r0,r10]                 @u1_pos_0_0_tmp = pu1_src[wd - 1]
    +     BEQ         PU1_AVAIL_6_LOOP
    + 
    +-    LDR         r11,[sp,#0xC0]              @Load pu1_src_top_right from sp
    ++    LDR         r11,[sp,#pu1_src_top_right_offset]  @Load pu1_src_top_right from sp
    +     SUB         r10,r10,#1                  @[wd - 1 - 1]
    + 
    +     LDRB        r11,[r11]                   @pu1_src_top_right[0]
    +@@ -147,13 +156,13 @@ PU1_AVAIL_6_LOOP:
    +     SUB         r11,r8,#1                   @ht - 1
    + 
    +     CMP         r10,#0
    +-    STR         r0,[sp,#0xC0]               @Store pu1_src in sp
    ++    STR         r0,[sp,#148]                @Store pu1_src in sp
    +     MLA         r12,r11,r1,r0               @pu1_src[(ht - 1) * src_strd]
    + 
    +     LDRB        r10,[r12]                   @u1_pos_wd_ht_tmp = pu1_src[(ht - 1) * src_strd]
    +     BEQ         PU1_AVAIL_3_LOOP
    + 
    +-    LDR         r14,[sp,#0xC4]              @Load pu1_src_bot_left from sp
    ++    LDR         r14,[sp,#pu1_src_bot_left_offset]   @Load pu1_src_bot_left from sp
    +     SUB         r11,r12,r1                  @pu1_src[(ht - 1) * src_strd) - src_strd]
    + 
    +     LDRB        r14,[r14]                   @Load pu1_src_bot_left[0]
    +@@ -186,7 +195,7 @@ ulbl2:
    +     USAT        r10,#8,r10                  @u1_pos_wd_ht_tmp = CLIP3(pu1_src[(ht - 1) * src_strd] + pi1_sao_offset[edge_idx], 0, (1 << bit_depth) - 1)
    + 
    + PU1_AVAIL_3_LOOP:
    +-    STR         r2,[sp,#0xC4]               @Store pu1_src_left in sp
    ++    STR         r2,[sp,#152]                @Store pu1_src_left in sp
    +     MOV         r12,r8                      @Move ht
    + 
    +     MOV         r14,r2                      @Move pu1_src_left to pu1_src_left_cpy
    +@@ -211,7 +220,7 @@ ulbl3:
    +     VMOV.S8     Q4,#0xFF                    @au1_mask = vdupq_n_s8(-1)
    +     ADDEQ       r14,r14,#1                  @pu1_src_left_cpy += 1
    + 
    +-    STR         r0,[sp,#0x90]               @Store pu1_src in sp
    ++    STR         r0,[sp,#144]                @Store pu1_src in sp
    +     VLD1.8      D6,[r6]                     @edge_idx_tbl = vld1_s8(gi1_table_edge_idx)
    +     MOV         r6,r7                       @move wd to r6 loop_count
    + 
    +@@ -221,9 +230,9 @@ ulbl3:
    +     BLE         WD_16_HT_4_LOOP             @If jump to WD_16_HT_4_LOOP
    + 
    + WIDTH_LOOP_16:
    +-    LDR         r7,[sp,#0xD0]               @Loads wd
    ++    LDR         r7,[sp,#wd_offset]          @Loads wd
    + 
    +-    LDR         r5,[sp,#0xC8]               @Loads pu1_avail
    ++    LDR         r5,[sp,#pu1_avail_offset]   @Loads pu1_avail
    +     CMP         r6,r7                       @col == wd
    +     LDRBEQ      r8,[r5]                     @pu1_avail[0]
    +     MOVNE       r8,#-1
    +@@ -238,13 +247,13 @@ SKIP_AU1_MASK_VAL:
    +     LDRB        r8,[r5,#2]                  @pu1_avail[2]
    +     CMP         r8,#0
    + 
    +-    LDR         r4,[sp,#0xD4]               @Loads ht
    ++    LDR         r4,[sp,#ht_offset]          @Loads ht
    +     SUBEQ       r8,r0,r1                    @pu1_src - src_strd
    + 
    +     MOVNE       r8,r3
    +-    ADD         r5,sp,#0x42                 @*au1_src_left_tmp
    ++    ADD         r5,sp,#66                   @*au1_src_left_tmp
    + 
    +-    LDR         r7,[sp,#0xD0]               @Loads wd
    ++    LDR         r7,[sp,#wd_offset]          @Loads wd
    +     ADD         r8,r8,#1                    @pu1_src - src_strd + 1
    + 
    +     SUB         r7,r7,r6                    @(wd - col)
    +@@ -253,7 +262,7 @@ SKIP_AU1_MASK_VAL:
    +     SUB         r8,#8
    +     ADD         r3,r3,#16
    + 
    +-    LDR         r8,[sp,#0xC0]               @Loads *pu1_src
    ++    LDR         r8,[sp,#148]                @Loads *pu1_src
    +     VLD1.8      D12,[r0]!                   @pu1_cur_row = vld1q_u8(pu1_src)
    +     VLD1.8      D13,[r0]                    @pu1_cur_row = vld1q_u8(pu1_src)
    +     SUB         r0,#8
    +@@ -285,7 +294,7 @@ AU1_SRC_LEFT_LOOP:
    +     ADD         r8,r8,#1                    @I pu1_src_left_cpy[ht_tmp - row + 1]
    +     LDRB        r8,[r8]
    + 
    +-    LDR         r5,[sp,#0xC8]               @I Loads pu1_avail
    ++    LDR         r5,[sp,#pu1_avail_offset]   @I Loads pu1_avail
    +     VMOV.8      D19[7],r8                   @I vsetq_lane_u8
    +     LDRB        r5,[r5,#2]                  @I pu1_avail[2]
    + 
    +@@ -375,7 +384,7 @@ PU1_SRC_LOOP:
    +     CMP         r7,#1                       @III
    + 
    +     BNE         NEXT_ROW_ELSE_2             @III
    +-    LDR         r5,[sp,#0xC8]               @III Loads pu1_avail
    ++    LDR         r5,[sp,#pu1_avail_offset]   @III Loads pu1_avail
    +     LDRB        r5,[r5,#3]                  @III pu1_avail[3]
    +     CMP         r5,#0                       @III
    +     SUBNE       r8,r2,#2                    @III pu1_src_cpy[src_strd - 1]
    +@@ -465,7 +474,7 @@ NEXT_ROW_ELSE_2:
    + 
    +     ADD         r8,r0,r1,LSL #1             @*pu1_src + src_strd
    +     VMOVN.I16   D20,Q10                     @III vmovn_s16(pi2_tmp_cur_row.val[0])
    +-    LDR         r5,[sp,#0xC8]               @Loads pu1_avail
    ++    LDR         r5,[sp,#pu1_avail_offset]   @Loads pu1_avail
    + 
    +     LDRB        r5,[r5,#3]                  @pu1_avail[3]
    +     VMOVN.I16   D21,Q11                     @III vmovn_s16(pi2_tmp_cur_row.val[1])
    +@@ -529,13 +538,13 @@ NEXT_ROW_POINTER_ASSIGNED_3:
    + 
    + INNER_LOOP_DONE:
    +     VMOVN.I16   D20,Q10                     @vmovn_s16(pi2_tmp_cur_row.val[0])
    +-    LDR         r8,[sp,#0xD4]               @Loads ht
    ++    LDR         r8,[sp,#ht_offset]          @Loads ht
    + 
    +     VMOVN.I16   D21,Q11                     @vmovn_s16(pi2_tmp_cur_row.val[1])
    +-    ADD         r5,sp,#0x42                 @*au1_src_left_tmp
    ++    ADD         r5,sp,#66                   @*au1_src_left_tmp
    + 
    +     VST1.8      {Q10},[r0],r1               @vst1q_u8(pu1_src_cpy, pu1_cur_row)
    +-    LDR         r2,[sp,#0xC4]               @Loads *pu1_src_left
    ++    LDR         r2,[sp,#152]                @Loads *pu1_src_left
    + SRC_LEFT_LOOP:
    +     LDR         r7,[r5],#4                  @au1_src_left_tmp[row]
    +     SUBS        r8,r8,#4
    +@@ -545,8 +554,8 @@ SRC_LEFT_LOOP:
    +     SUBS        r6,r6,#16                   @Decrement the wd loop count by 16
    +     CMP         r6,#8                       @Check whether residue remains
    +     BLT         RE_ASSINING_LOOP            @Jump to re-assigning loop
    +-    LDR         r7,[sp,#0xD0]               @Loads wd
    +-    LDR         r0,[sp,#0x90]               @Loads *pu1_src
    ++    LDR         r7,[sp,#wd_offset]          @Loads wd
    ++    LDR         r0,[sp,#144]                @Loads *pu1_src
    +     SUB         r7,r7,r6
    +     ADD         r0,r0,r7
    +     BGT         WIDTH_LOOP_16               @If not equal jump to width_loop
    +@@ -555,8 +564,8 @@ SRC_LEFT_LOOP:
    + 
    + 
    + WD_16_HT_4_LOOP:
    +-    LDR         r5,[sp,#0xC8]               @Loads pu1_avail
    +-    LDR         r7,[sp,#0xD0]               @Loads wd
    ++    LDR         r5,[sp,#pu1_avail_offset]   @Loads pu1_avail
    ++    LDR         r7,[sp,#wd_offset]          @Loads wd
    +     CMP         r6,r7                       @col == wd
    +     LDRBEQ      r8,[r5]                     @pu1_avail[0]
    +     MOVNE       r8,#-1
    +@@ -579,12 +588,12 @@ SKIP_AU1_MASK_VAL_WD_16_HT_4:
    +     SUB         r8,#8
    + 
    +     ADD         r3,r3,#16
    +-    ADD         r5,sp,#0x42                 @*au1_src_left_tmp
    +-    LDR         r4,[sp,#0xD4]               @Loads ht
    +-    LDR         r7,[sp,#0xD0]               @Loads wd
    ++    ADD         r5,sp,#66                   @*au1_src_left_tmp
    ++    LDR         r4,[sp,#ht_offset]          @Loads ht
    ++    LDR         r7,[sp,#wd_offset]          @Loads wd
    +     SUB         r7,r7,r6                    @(wd - col)
    +     ADD         r7,r7,#15                   @15 + (wd - col)
    +-    LDR         r8,[sp,#0xC0]               @Loads *pu1_src
    ++    LDR         r8,[sp,#148]                @Loads *pu1_src
    +     ADD         r7,r8,r7                    @pu1_src[0 * src_strd + 15 + (wd - col)]
    +     SUB         r5,r5,#1
    + 
    +@@ -609,7 +618,7 @@ PU1_SRC_LOOP_WD_16_HT_4:
    +     VLD1.8      D16,[r8]!                   @pu1_next_row = vld1q_u8(pu1_src_cpy + src_strd)
    +     VLD1.8      D17,[r8]                    @pu1_next_row = vld1q_u8(pu1_src_cpy + src_strd)
    +     SUB         r8,#8
    +-    LDR         r5,[sp,#0xC8]               @Loads pu1_avail
    ++    LDR         r5,[sp,#pu1_avail_offset]   @Loads pu1_avail
    +     LDRB        r5,[r5,#3]                  @pu1_avail[3]
    +     CMP         r5,#0
    +     BEQ         NEXT_ROW_ELSE_WD_16_HT_4
    +@@ -628,7 +637,7 @@ NEXT_ROW_POINTER_ASSIGNED_WD_16_HT_4:
    + 
    +     CMP         r7,r12
    +     BNE         SIGN_UP_CHANGE_WD_16_HT_4
    +-    LDR         r5,[sp,#0xC8]               @Loads pu1_avail
    ++    LDR         r5,[sp,#pu1_avail_offset]   @Loads pu1_avail
    +     LDRB        r5,[r5,#2]                  @pu1_avail[2]
    +     CMP         r5,#0
    +     BNE         SIGN_UP_CHANGE_DONE_WD_16_HT_4
    +@@ -680,9 +689,9 @@ SIGN_UP_CHANGE_DONE_WD_16_HT_4:
    +     SUBS        r7,r7,#1                    @Decrement the ht_tmp loop count by 1
    +     BNE         PU1_SRC_LOOP_WD_16_HT_4     @If not equal jump to PU1_SRC_LOOP_WD_16_HT_4
    + 
    +-    LDR         r8,[sp,#0xD4]               @Loads ht
    +-    ADD         r5,sp,#0x42                 @*au1_src_left_tmp
    +-    LDR         r2,[sp,#0xC4]               @Loads *pu1_src_left
    ++    LDR         r8,[sp,#ht_offset]          @Loads ht
    ++    ADD         r5,sp,#66                   @*au1_src_left_tmp
    ++    LDR         r2,[sp,#152]                @Loads *pu1_src_left
    + SRC_LEFT_LOOP_WD_16_HT_4:
    +     LDR         r7,[r5],#4                  @au1_src_left_tmp[row]
    +     STR         r7,[r2],#4                  @pu1_src_left[row] = au1_src_left_tmp[row]
    +@@ -691,12 +700,16 @@ SRC_LEFT_LOOP_WD_16_HT_4:
    + 
    +     SUBS        r6,r6,#16                   @Decrement the wd loop count by 16
    +     BLE         RE_ASSINING_LOOP            @Jump to re-assigning loop
    ++    LDR         r7,[sp,#wd_offset]          @Loads wd
    ++    LDR         r0,[sp,#144]                @Loads *pu1_src
    ++    SUB         r7,r7,r6
    ++    ADD         r0,r0,r7
    +     BGT         WD_16_HT_4_LOOP             @If not equal jump to width_loop
    + 
    + 
    + WIDTH_RESIDUE:
    +-    LDR         r7,[sp,#0xD0]               @Loads wd
    +-    LDR         r5,[sp,#0xC8]               @Loads pu1_avail
    ++    LDR         r7,[sp,#wd_offset]          @Loads wd
    ++    LDR         r5,[sp,#pu1_avail_offset]   @Loads pu1_avail
    +     CMP         r6,r7                       @wd_residue == wd
    +     LDRBEQ      r8,[r5]                     @pu1_avail[0]
    + 
    +@@ -718,10 +731,10 @@ PU1_AVAIL_2_RESIDUE:
    +     SUB         r8,#8
    + 
    + 
    +-    ADD         r5,sp,#0x42                 @*au1_src_left_tmp
    +-    LDR         r4,[sp,#0xD4]               @Loads ht
    +-    LDR         r7,[sp,#0xD0]               @Loads wd
    +-    LDR         r8,[sp,#0xC0]               @Loads *pu1_src
    ++    ADD         r5,sp,#66                   @*au1_src_left_tmp
    ++    LDR         r4,[sp,#ht_offset]          @Loads ht
    ++    LDR         r7,[sp,#wd_offset]          @Loads wd
    ++    LDR         r8,[sp,#148]                @Loads *pu1_src
    +     SUB         r7,r7,#1                    @(wd - 1)
    +     ADD         r7,r8,r7                    @pu1_src[0 * src_strd + (wd - 1)]
    +     SUB         r5,r5,#1
    +@@ -747,7 +760,7 @@ PU1_SRC_LOOP_RESIDUE:
    +     VLD1.8      D16,[r8]!                   @pu1_next_row = vld1q_u8(pu1_src_cpy + src_strd)
    +     VLD1.8      D17,[r8]                    @pu1_next_row = vld1q_u8(pu1_src_cpy + src_strd)
    +     SUB         r8,#8
    +-    LDR         r5,[sp,#0xC8]               @Loads pu1_avail
    ++    LDR         r5,[sp,#pu1_avail_offset]   @Loads pu1_avail
    +     LDRB        r5,[r5,#3]                  @pu1_avail[3]
    +     CMP         r5,#0
    +     BEQ         NEXT_ROW_ELSE_RESIDUE
    +@@ -766,7 +779,7 @@ NEXT_ROW_POINTER_ASSIGNED_RESIDUE:
    + 
    +     CMP         r7,r12
    +     BNE         SIGN_UP_CHANGE_RESIDUE
    +-    LDR         r5,[sp,#0xC8]               @Loads pu1_avail
    ++    LDR         r5,[sp,#pu1_avail_offset]   @Loads pu1_avail
    +     LDRB        r5,[r5,#2]                  @pu1_avail[2]
    +     CMP         r5,#0
    +     BNE         SIGN_UP_CHANGE_DONE_RESIDUE
    +@@ -810,9 +823,9 @@ SIGN_UP_CHANGE_DONE_RESIDUE:
    +     SUBS        r7,r7,#1
    +     BNE         PU1_SRC_LOOP_RESIDUE
    + 
    +-    LDR         r8,[sp,#0xD4]               @Loads ht
    +-    LDR         r2,[sp,#0xC4]               @Loads *pu1_src_left
    +-    ADD         r5,sp,#0x42                 @*au1_src_left_tmp
    ++    LDR         r8,[sp,#ht_offset]          @Loads ht
    ++    LDR         r2,[sp,#152]                @Loads *pu1_src_left
    ++    ADD         r5,sp,#66                   @*au1_src_left_tmp
    + 
    + SRC_LEFT_LOOP_RESIDUE:
    +     LDR         r7,[r5],#4                  @au1_src_left_tmp[row]
    +@@ -822,24 +835,24 @@ SRC_LEFT_LOOP_RESIDUE:
    + 
    + 
    + RE_ASSINING_LOOP:
    +-    LDR         r7,[sp,#0xD0]               @Loads wd
    +-    LDR         r0,[sp,#0xC0]               @Loads *pu1_src
    ++    LDR         r7,[sp,#wd_offset]          @Loads wd
    ++    LDR         r0,[sp,#148]                @Loads *pu1_src
    + 
    +-    LDR         r11,[sp,#0xD4]              @Loads ht
    ++    LDR         r11,[sp,#ht_offset]         @Loads ht
    +     ADD         r8,r0,r7                    @pu1_src[wd]
    + 
    +-    LDR         r4,[sp,#0xBC]               @Loads pu1_src_top_left
    ++    LDR         r4,[sp,#pu1_src_top_left_offset]    @Loads pu1_src_top_left
    +     SUB         r11,r11,#1                  @ht - 1
    + 
    +     STRB        r9,[r8,#-1]                 @pu1_src_org[wd - 1] = u1_pos_wd_0_tmp
    +     MLA         r6,r11,r1,r0                @pu1_src_org[(ht - 1) * src_strd]
    + 
    +     LDRB        r8,[sp]                     @load u1_src_top_left_tmp from stack pointer
    +-    ADD         r12,sp,#0x02
    ++    ADD         r12,sp,#2
    + 
    +     STRB        r10,[r6]                    @pu1_src_org[wd - 1 + (ht - 1) * src_strd] = u1_pos_wd_ht_tmp
    +     STRB        r8,[r4]                     @*pu1_src_top_left = u1_src_top_left_tmp
    +-    LDR         r3,[sp,#0xCC]               @Loads pu1_src_top
    ++    LDR         r3,[sp,#156]                @Loads pu1_src_top
    + 
    + SRC_TOP_LOOP:
    +     VLD1.8      D0,[r12]!                   @pu1_src_top[col] = au1_src_top_tmp[col]
    +@@ -848,7 +861,8 @@ SRC_TOP_LOOP:
    +     BNE         SRC_TOP_LOOP
    + 
    + END_LOOPS:
    +-    ADD         sp,sp,#0x94
    ++    ADD         sp,sp,#160
    ++    vpop        {d8  -  d15}
    +     LDMFD       sp!,{r4-r12,r15}            @Reload the registers from SP
    + 
    + 
    +diff --git a/common/arm/ihevc_sao_edge_offset_class3_chroma.s b/common/arm/ihevc_sao_edge_offset_class3_chroma.s
    +index 62f40d1..9f4eb62 100644
    +--- a/common/arm/ihevc_sao_edge_offset_class3_chroma.s
    ++++ b/common/arm/ihevc_sao_edge_offset_class3_chroma.s
    +@@ -60,6 +60,15 @@
    + @r7 =>  wd
    + @r8=>   ht
    + 
    ++.equ    pu1_src_top_left_offset,    328
    ++.equ    pu1_src_top_right_offset,   332
    ++.equ    pu1_src_bot_left_offset,    336
    ++.equ    pu1_avail_offset,           340
    ++.equ    pi1_sao_u_offset,           344
    ++.equ    pi1_sao_v_offset,           348
    ++.equ    wd_offset,                  352
    ++.equ    ht_offset,                  356
    ++
    + .text
    + .syntax unified
    + .p2align 2
    +@@ -86,21 +95,22 @@ ihevc_sao_edge_offset_class3_chroma_a9q:
    + 
    + 
    +     STMFD       sp!,{r4-r12,r14}            @stack stores the values of the arguments
    ++    vpush       {d8  -  d15}
    ++    SUB         sp,sp,#224                  @Decrement the stack pointer to store some temp arr values
    + 
    +-    LDR         r7,[sp,#0x40]               @Loads wd
    +-    LDR         r8,[sp,#0x44]               @Loads ht
    ++    LDR         r7,[sp,#wd_offset]          @Loads wd
    ++    LDR         r8,[sp,#ht_offset]          @Loads ht
    +     SUB         r9,r7,#2                    @wd - 2
    + 
    +-    LDR         r4,[sp,#0x28]               @Loads pu1_src_top_left
    ++    LDR         r4,[sp,#pu1_src_top_left_offset]    @Loads pu1_src_top_left
    +     LDRH        r10,[r3,r9]                 @pu1_src_top[wd - 2]
    + 
    +     MOV         r9,r7                       @Move width to r9 for loop count
    + 
    +-    LDR         r5,[sp,#0x34]               @Loads pu1_avail
    +-    LDR         r6,[sp,#0x38]               @Loads pi1_sao_offset_u
    ++    LDR         r5,[sp,#pu1_avail_offset]   @Loads pu1_avail
    ++    LDR         r6,[sp,#pi1_sao_u_offset]   @Loads pi1_sao_offset_u
    + 
    +-    STR         r3,[sp,#0x38]               @Store pu1_src_top in sp
    +-    SUB         sp,sp,#0xD4                 @Decrement the stack pointer to store some temp arr values
    ++    STR         r3,[sp,#220]                @Store pu1_src_top in sp
    + 
    +     STRH        r10,[sp]                    @u1_src_top_left_tmp = pu1_src_top[wd - 2]
    +     SUB         r10,r8,#1                   @ht-1
    +@@ -122,7 +132,7 @@ PU1_AVAIL_5_LOOP_U:
    +     LDRB        r10,[r0,r11]                @u1_pos_0_0_tmp_v = pu1_src[wd - 1]
    +     BEQ         PU1_AVAIL_6_LOOP_U
    + 
    +-    LDR         r11,[sp,#0x100]             @Load pu1_src_top_right from sp
    ++    LDR         r11,[sp,#pu1_src_top_right_offset]  @Load pu1_src_top_right from sp
    +     LDRB        r11,[r11]                   @pu1_src_top_right[0]
    +     SUB         r12,r9,r11                  @pu1_src[wd - 2] - pu1_src_top_right[0]
    +     CMP         r12,#0
    +@@ -150,7 +160,7 @@ ulbl1:
    + 
    + PU1_AVAIL_5_LOOP_V:
    + 
    +-    LDR         r11,[sp,#0x100]             @Load pu1_src_top_right from sp
    ++    LDR         r11,[sp,#pu1_src_top_right_offset]  @Load pu1_src_top_right from sp
    +     LDRB        r11,[r11,#1]                @pu1_src_top_right[1]
    +     SUB         r12,r10,r11                 @pu1_src[wd - 1] - pu1_src_top_right[1]
    +     CMP         r12,#0
    +@@ -172,7 +182,7 @@ ulbl2:
    +     LDRSB       r12,[r14,r11]               @edge_idx = gi1_table_edge_idx[edge_idx]
    +     CMP         r12,#0                      @0 != edge_idx
    +     BEQ         PU1_AVAIL_6_LOOP_U
    +-    LDR         r11,[sp,#0x110]             @Loads pi1_sao_offset_v
    ++    LDR         r11,[sp,#pi1_sao_v_offset]  @Loads pi1_sao_offset_v
    +     LDRSB       r11,[r11,r12]               @pi1_sao_offset_v[edge_idx]
    +     ADD         r10,r10,r11                 @pu1_src[wd - 1] + pi1_sao_offset_v[edge_idx]
    +     USAT        r10,#8,r10                  @u1_pos_0_0_tmp_v = CLIP3(pu1_src[wd - 1] + pi1_sao_offset_v[edge_idx], 0, (1 << bit_depth) - 1)
    +@@ -180,7 +190,7 @@ ulbl2:
    + PU1_AVAIL_6_LOOP_U:
    +     STRB        r9,[sp,#6]
    +     STRB        r10,[sp,#7]
    +-    STR         r0,[sp,#0x100]              @Store pu1_src in sp
    ++    STR         r0,[sp,#212]                @Store pu1_src in sp
    + 
    +     LDRB        r10,[r5,#6]                 @pu1_avail[6]
    +     CMP         r10,#0
    +@@ -198,7 +208,7 @@ PU1_AVAIL_6_LOOP_U:
    +     MVNLT       r11,#0
    +     MOVGT       r11,#1                      @SIGN(pu1_src[(ht - 1) * src_strd] - pu1_src[(ht - 1) * src_strd +  2 - src_strd])
    + 
    +-    LDR         r14,[sp,#0x104]             @Load pu1_src_bot_left from sp
    ++    LDR         r14,[sp,#pu1_src_bot_left_offset]   @Load pu1_src_bot_left from sp
    +     LDRB        r14,[r14]                   @Load pu1_src_bot_left[0]
    +     SUB         r14,r10,r14                 @pu1_src[(ht - 1) * src_strd] - pu1_src_bot_left[0]
    +     CMP         r14,#0
    +@@ -228,7 +238,7 @@ PU1_AVAIL_6_LOOP_V:
    +     MVNLT       r11,#0
    +     MOVGT       r11,#1                      @SIGN(pu1_src[(ht - 1) * src_strd + 1] - pu1_src[(ht - 1) * src_strd + 1 + 2 - src_strd])
    + 
    +-    LDR         r14,[sp,#0x104]             @Load pu1_src_bot_left from sp
    ++    LDR         r14,[sp,#pu1_src_bot_left_offset]   @Load pu1_src_bot_left from sp
    +     LDRB        r14,[r14,#1]                @Load pu1_src_bot_left[1]
    +     SUB         r14,r9,r14                  @pu1_src[(ht - 1) * src_strd + 1] - pu1_src_bot_left[1]
    +     CMP         r14,#0
    +@@ -244,7 +254,7 @@ ulbl4:
    +     LDRSB       r12,[r14,r11]               @edge_idx = gi1_table_edge_idx[edge_idx]
    +     CMP         r12,#0
    +     BEQ         PU1_AVAIL_3_LOOP
    +-    LDR         r14,[sp,#0x110]             @Loads pi1_sao_offset_v
    ++    LDR         r14,[sp,#pi1_sao_v_offset]  @Loads pi1_sao_offset_v
    +     LDRSB       r11,[r14,r12]               @pi1_sao_offset_v[edge_idx]
    +     ADD         r9,r9,r11                   @pu1_src[(ht - 1) * src_strd] + pi1_sao_offset[edge_idx]
    +     USAT        r9,#8,r9                    @u1_pos_wd_ht_tmp_v = CLIP3(pu1_src[(ht - 1) * src_strd] + pi1_sao_offset[edge_idx], 0, (1 << bit_depth) - 1)
    +@@ -252,7 +262,7 @@ ulbl4:
    + PU1_AVAIL_3_LOOP:
    +     STRB        r10,[sp,#8]
    +     STRB        r9,[sp,#9]
    +-    STR         r2,[sp,#0x104]              @Store pu1_src_left in sp
    ++    STR         r2,[sp,#216]                @Store pu1_src_left in sp
    + 
    +     MOV         r12,r8                      @Move ht
    +     MOV         r14,r2                      @Move pu1_src_left to pu1_src_left_cpy
    +@@ -276,7 +286,7 @@ PU1_AVAIL_2_LOOP_END:
    +     VMOV.I16    Q1,#0                       @const_min_clip = vdupq_n_s16(0)
    +     VMOV.I16    Q2,#255                     @const_max_clip = vdupq_n_u16((1 << bit_depth) - 1)
    +     VLD1.8      D6,[r6]                     @offset_tbl_u = vld1_s8(pi1_sao_offset_u)
    +-    LDR         r6,[sp,#0x110]              @Loads pi1_sao_offset_v
    ++    LDR         r6,[sp,#pi1_sao_v_offset]   @Loads pi1_sao_offset_v
    +     VLD1.8      D7,[r6]                     @offset_tbl_v = vld1_s8(pi1_sao_offset_v)
    +     LDR         r2, gi1_table_edge_idx_addr_5 @table pointer
    + ulbl5:
    +@@ -291,9 +301,9 @@ ulbl5:
    +     BLE         WD_16_HT_4_LOOP             @If jump to WD_16_HT_4_LOOP
    + 
    + WIDTH_LOOP_16:
    +-    LDR         r7,[sp,#0x114]              @Loads wd
    ++    LDR         r7,[sp,#wd_offset]          @Loads wd
    +     CMP         r6,r7                       @col == wd
    +-    LDR         r5,[sp,#0x108]              @Loads pu1_avail
    ++    LDR         r5,[sp,#pu1_avail_offset]   @Loads pu1_avail
    + 
    +     LDRBEQ      r8,[r5]                     @pu1_avail[0]
    +     MOVNE       r8,#-1
    +@@ -314,7 +324,7 @@ SKIP_AU1_MASK_VAL:
    +     VLD1.8      D12,[r0]!                   @pu1_cur_row = vld1q_u8(pu1_src)
    +     VLD1.8      D13,[r0]                    @pu1_cur_row = vld1q_u8(pu1_src)
    +     SUB         r0,#8
    +-    ADD         r5,sp,#0x4B                 @*au1_src_left_tmp
    ++    ADD         r5,sp,#75                   @*au1_src_left_tmp
    + 
    +     SUBEQ       r8,r0,r1                    @pu1_src - src_strd
    +     VMOV.I8     Q9,#0
    +@@ -326,15 +336,15 @@ SKIP_AU1_MASK_VAL:
    +     SUB         r8,#8
    +     ADD         r3,r3,#16
    + 
    +-    LDR         r4,[sp,#0x118]              @Loads ht
    ++    LDR         r4,[sp,#ht_offset]          @Loads ht
    +     VCGT.U8     Q7,Q6,Q5                    @vcgtq_u8(pu1_cur_row, pu1_top_row)
    +-    LDR         r7,[sp,#0x114]              @Loads wd
    ++    LDR         r7,[sp,#wd_offset]          @Loads wd
    + 
    +     SUB         r7,r7,r6                    @(wd - col)
    +     VCLT.U8     Q8,Q6,Q5                    @vcltq_u8(pu1_cur_row, pu1_top_row)
    +     ADD         r7,r7,#14                   @15 + (wd - col)
    + 
    +-    LDR         r8,[sp,#0x100]              @Loads *pu1_src
    ++    LDR         r8,[sp,#212]                @Loads *pu1_src
    +     VSUB.U8     Q7,Q8,Q7                    @sign_up = vreinterpretq_s8_u8(vsubq_u8(cmp_lt, cmp_gt))
    +     ADD         r7,r8,r7                    @pu1_src[0 * src_strd + 15 + (wd - col)]
    + 
    +@@ -359,7 +369,7 @@ AU1_SRC_LEFT_LOOP:
    + 
    +     LDRH        r5,[r8,#2]                  @I
    +     VMOV.16     D19[3],r5                   @I vsetq_lane_u8
    +-    LDR         r11,[sp,#0x108]             @I Loads pu1_avail
    ++    LDR         r11,[sp,#pu1_avail_offset]  @I Loads pu1_avail
    + 
    +     LDRB        r11,[r11,#2]                @I pu1_avail[2]
    +     VEXT.8      Q9,Q9,Q8,#14                @I pu1_next_row_tmp = vextq_u8(pu1_next_row_tmp, pu1_next_row, 14)
    +@@ -477,7 +487,7 @@ PU1_SRC_LOOP:
    +     VCGT.U8     Q11,Q6,Q14                  @II vcgtq_u8(pu1_cur_row, pu1_next_row_tmp)
    +     BNE         NEXT_ROW_POINTER_ASSIGNED_2 @III
    + 
    +-    LDR         r5,[sp,#0x108]              @III Loads pu1_avail
    ++    LDR         r5,[sp,#pu1_avail_offset]   @III Loads pu1_avail
    +     LDRB        r5,[r5,#3]                  @III pu1_avail[3]
    +     CMP         r5,#0                       @III
    +     SUBNE       r11,r4,#4                   @III pu1_src[src_strd - 2]
    +@@ -597,7 +607,7 @@ NEXT_ROW_POINTER_ASSIGNED_2:
    +     LDRB        r9,[r0,#17]                 @load the value pu1_src_cpy[17 - src_strd]
    + 
    +     BNE         NEXT_ROW_POINTER_ASSIGNED_3
    +-    LDR         r5,[sp,#0x108]              @Loads pu1_avail
    ++    LDR         r5,[sp,#pu1_avail_offset]   @Loads pu1_avail
    +     LDRB        r5,[r5,#3]                  @pu1_avail[3]
    +     CMP         r5,#0
    +     SUBNE       r8,r11,#4                   @pu1_src[src_strd - 2]
    +@@ -657,13 +667,13 @@ NEXT_ROW_POINTER_ASSIGNED_3:
    + 
    + INNER_LOOP_DONE:
    + 
    +-    LDR         r8,[sp,#0x118]              @Loads ht
    ++    LDR         r8,[sp,#ht_offset]          @Loads ht
    +     VMOVN.I16   D20,Q10                     @III vmovn_s16(pi2_tmp_cur_row.val[0])
    +-    ADD         r5,sp,#0x4B                 @*au1_src_left_tmp
    ++    ADD         r5,sp,#75                   @*au1_src_left_tmp
    + 
    +     LSL         r8,r8,#1
    +     VMOVN.I16   D21,Q9                      @III vmovn_s16(pi2_tmp_cur_row.val[1])
    +-    LDR         r11,[sp,#0x104]             @Loads *pu1_src_left
    ++    LDR         r11,[sp,#216]               @Loads *pu1_src_left
    + 
    + SRC_LEFT_LOOP:
    +     LDR         r7,[r5],#4                  @au1_src_left_tmp[row]
    +@@ -676,7 +686,7 @@ SRC_LEFT_LOOP:
    +     CMP         r6,#8                       @Check whether residue remains
    + 
    +     BLT         RE_ASSINING_LOOP            @Jump to re-assigning loop
    +-    LDR         r7,[sp,#0x114]              @Loads wd
    ++    LDR         r7,[sp,#wd_offset]          @Loads wd
    +     LDR         r0,[sp,#0x02]               @Loads *pu1_src
    +     SUB         r7,r7,r6
    +     ADD         r0,r0,r7
    +@@ -684,9 +694,9 @@ SRC_LEFT_LOOP:
    +     BEQ         WIDTH_RESIDUE               @If residue remains jump to residue loop
    + 
    + WD_16_HT_4_LOOP:
    +-    LDR         r7,[sp,#0x114]              @Loads wd
    ++    LDR         r7,[sp,#wd_offset]          @Loads wd
    + 
    +-    LDR         r5,[sp,#0x108]              @Loads pu1_avail
    ++    LDR         r5,[sp,#pu1_avail_offset]   @Loads pu1_avail
    +     CMP         r6,r7                       @col == wd
    + 
    +     LDRBEQ      r8,[r5]                     @pu1_avail[0]
    +@@ -716,17 +726,17 @@ SKIP_AU1_MASK_VAL_WD_16_HT_4:
    +     VLD1.8      D10,[r8]!                   @pu1_top_row = vld1q_u8(pu1_src - src_strd + 2)
    +     VLD1.8      D11,[r8]                    @pu1_top_row = vld1q_u8(pu1_src - src_strd + 2)
    +     SUB         r8,#8
    +-    ADD         r5,sp,#0x4B                 @*au1_src_left_tmp
    ++    ADD         r5,sp,#75                   @*au1_src_left_tmp
    + 
    +-    LDR         r4,[sp,#0x118]              @Loads ht
    ++    LDR         r4,[sp,#ht_offset]          @Loads ht
    +     VCGT.U8     Q7,Q6,Q5                    @vcgtq_u8(pu1_cur_row, pu1_top_row)
    +-    LDR         r7,[sp,#0x114]              @Loads wd
    ++    LDR         r7,[sp,#wd_offset]          @Loads wd
    + 
    +     SUB         r7,r7,r6                    @(wd - col)
    +     VCLT.U8     Q8,Q6,Q5                    @vcltq_u8(pu1_cur_row, pu1_top_row)
    +     ADD         r7,r7,#14                   @15 + (wd - col)
    + 
    +-    LDR         r8,[sp,#0x100]              @Loads *pu1_src
    ++    LDR         r8,[sp,#212]                @Loads *pu1_src
    +     VSUB.U8     Q7,Q8,Q7                    @sign_up = vreinterpretq_s8_u8(vsubq_u8(cmp_lt, cmp_gt))
    +     ADD         r7,r8,r7                    @pu1_src[0 * src_strd + 15 + (wd - col)]
    + 
    +@@ -744,7 +754,7 @@ AU1_SRC_LEFT_LOOP_WD_16_HT_4:
    + PU1_SRC_LOOP_WD_16_HT_4:
    +     ADD         r9,r0,r1                    @*pu1_src + src_strd
    + 
    +-    LDR         r5,[sp,#0x108]              @Loads pu1_avail
    ++    LDR         r5,[sp,#pu1_avail_offset]   @Loads pu1_avail
    +     VLD1.8      D16,[r9]!                   @pu1_next_row = vld1q_u8(pu1_src_cpy + src_strd)
    +     VLD1.8      D17,[r9]                    @pu1_next_row = vld1q_u8(pu1_src_cpy + src_strd)
    +     SUB         r9,#8
    +@@ -766,7 +776,7 @@ NEXT_ROW_POINTER_ASSIGNED_WD_16_HT_4:
    + 
    +     CMP         r7,r12
    +     BLT         SIGN_UP_CHANGE_WD_16_HT_4
    +-    LDR         r5,[sp,#0x108]              @Loads pu1_avail
    ++    LDR         r5,[sp,#pu1_avail_offset]   @Loads pu1_avail
    +     LDRB        r5,[r5,#2]                  @pu1_avail[2]
    +     CMP         r5,#0
    +     BNE         SIGN_UP_CHANGE_DONE_WD_16_HT_4
    +@@ -839,9 +849,9 @@ SIGN_UP_CHANGE_DONE_WD_16_HT_4:
    +     VST1.8      {Q14},[r0],r1               @vst1q_u8(pu1_src_cpy, pu1_cur_row)
    +     BNE         PU1_SRC_LOOP_WD_16_HT_4     @If not equal jump to PU1_SRC_LOOP_WD_16_HT_4
    + 
    +-    LDR         r8,[sp,#0x118]              @Loads ht
    +-    ADD         r5,sp,#0x4B                 @*au1_src_left_tmp
    +-    LDR         r11,[sp,#0x104]             @Loads *pu1_src_left
    ++    LDR         r8,[sp,#ht_offset]          @Loads ht
    ++    ADD         r5,sp,#75                   @*au1_src_left_tmp
    ++    LDR         r11,[sp,#216]               @Loads *pu1_src_left
    + 
    + SRC_LEFT_LOOP_WD_16_HT_4:
    +     LDR         r7,[r5],#4                  @au1_src_left_tmp[row]
    +@@ -851,12 +861,16 @@ SRC_LEFT_LOOP_WD_16_HT_4:
    + 
    +     SUBS        r6,r6,#16                   @Decrement the wd loop count by 16
    +     BLE         RE_ASSINING_LOOP            @Jump to re-assigning loop
    ++    LDR         r7,[sp,#wd_offset]          @Loads wd
    ++    LDR         r0,[sp,#0x02]               @Loads *pu1_src
    ++    SUB         r7,r7,r6
    ++    ADD         r0,r0,r7
    +     BGT         WD_16_HT_4_LOOP             @If not equal jump to width_loop
    + 
    + WIDTH_RESIDUE:
    +-    LDR         r7,[sp,#0x114]              @Loads wd
    ++    LDR         r7,[sp,#wd_offset]          @Loads wd
    + 
    +-    LDR         r5,[sp,#0x108]              @Loads pu1_avail
    ++    LDR         r5,[sp,#pu1_avail_offset]   @Loads pu1_avail
    +     CMP         r6,r7                       @wd_residue == wd
    + 
    +     LDRBEQ      r8,[r5]                     @pu1_avail[0]
    +@@ -874,13 +888,13 @@ WIDTH_RESIDUE:
    + 
    +     ADD         r10,r10,#2                  @pu1_src - src_strd + 2
    +     VMOV.8      d8[6],r11                   @au1_mask = vsetq_lane_s8(pu1_avail[1], au1_mask, 15)
    +-    ADD         r5,sp,#0x4B                 @*au1_src_left_tmp
    ++    ADD         r5,sp,#75                   @*au1_src_left_tmp
    + 
    +-    LDR         r4,[sp,#0x118]              @Loads ht
    ++    LDR         r4,[sp,#ht_offset]          @Loads ht
    +     VMOV.8      d8[7],r11                   @au1_mask = vsetq_lane_s8(pu1_avail[1], au1_mask, 15)
    +-    LDR         r7,[sp,#0x114]              @Loads wd
    ++    LDR         r7,[sp,#wd_offset]          @Loads wd
    + 
    +-    LDR         r8,[sp,#0x100]              @Loads *pu1_src
    ++    LDR         r8,[sp,#212]                @Loads *pu1_src
    +     VLD1.8      D10,[r10]!                  @pu1_top_row = vld1q_u8(pu1_src - src_strd + 2)
    +     VLD1.8      D11,[r10]                   @pu1_top_row = vld1q_u8(pu1_src - src_strd + 2)
    +     SUB         r10,#8
    +@@ -913,7 +927,7 @@ PU1_SRC_LOOP_RESIDUE:
    +     VLD1.8      D16,[r9]!                   @pu1_next_row = vld1q_u8(pu1_src_cpy + src_strd)
    +     VLD1.8      D17,[r9]                    @pu1_next_row = vld1q_u8(pu1_src_cpy + src_strd)
    +     SUB         r9,#8
    +-    LDR         r5,[sp,#0x108]              @Loads pu1_avail
    ++    LDR         r5,[sp,#pu1_avail_offset]   @Loads pu1_avail
    + 
    +     LDRB        r5,[r5,#3]                  @pu1_avail[3]
    +     ADD         r8,r14,r11,LSL #1           @pu1_src_left_cpy[(ht_tmp - row) * 2]
    +@@ -936,7 +950,7 @@ NEXT_ROW_POINTER_ASSIGNED_RESIDUE:
    +     VEXT.8      Q9,Q9,Q8,#14                @pu1_next_row_tmp = vextq_u8(pu1_next_row_tmp, pu1_next_row, 14)
    + 
    +     BLT         SIGN_UP_CHANGE_RESIDUE
    +-    LDR         r5,[sp,#0x108]              @Loads pu1_avail
    ++    LDR         r5,[sp,#pu1_avail_offset]   @Loads pu1_avail
    +     LDRB        r5,[r5,#2]                  @pu1_avail[2]
    +     CMP         r5,#0
    +     BNE         SIGN_UP_CHANGE_DONE_RESIDUE
    +@@ -1003,10 +1017,10 @@ SIGN_UP_CHANGE_DONE_RESIDUE:
    + 
    +     BNE         PU1_SRC_LOOP_RESIDUE        @If not equal jump to PU1_SRC_LOOP
    + 
    +-    LDR         r8,[sp,#0x118]              @Loads ht
    +-    ADD         r5,sp,#0x4B                 @*au1_src_left_tmp
    ++    LDR         r8,[sp,#ht_offset]          @Loads ht
    ++    ADD         r5,sp,#75                   @*au1_src_left_tmp
    + 
    +-    LDR         r11,[sp,#0x104]             @Loads *pu1_src_left
    ++    LDR         r11,[sp,#216]               @Loads *pu1_src_left
    + 
    + SRC_LEFT_LOOP_RESIDUE:
    +     LDR         r7,[r5],#4                  @au1_src_left_tmp[row]
    +@@ -1016,10 +1030,10 @@ SRC_LEFT_LOOP_RESIDUE:
    + 
    + 
    + RE_ASSINING_LOOP:
    +-    LDR         r7,[sp,#0x114]              @Loads wd
    +-    LDR         r8,[sp,#0x118]              @Loads ht
    ++    LDR         r7,[sp,#wd_offset]          @Loads wd
    ++    LDR         r8,[sp,#ht_offset]          @Loads ht
    + 
    +-    LDR         r0,[sp,#0x100]              @Loads *pu1_src
    ++    LDR         r0,[sp,#212]                @Loads *pu1_src
    +     SUB         r10,r7,#2                   @wd - 2
    + 
    +     LDRH        r9,[sp,#6]
    +@@ -1028,7 +1042,7 @@ RE_ASSINING_LOOP:
    +     STRH        r9,[r0,r10]                 @pu1_src_org[0] = u1_pos_0_0_tmp
    +     MLA         r6,r8,r1,r0                 @pu1_src[(ht - 1) * src_strd]
    + 
    +-    LDR         r4,[sp,#0xFC]               @Loads pu1_src_top_left
    ++    LDR         r4,[sp,#pu1_src_top_left_offset]               @Loads pu1_src_top_left
    + 
    +     LDRH        r9,[sp,#8]
    +     ADD         r12,sp,#10
    +@@ -1037,7 +1051,7 @@ RE_ASSINING_LOOP:
    + 
    +     LDRH        r10,[sp]                    @load u1_src_top_left_tmp from stack pointer
    +     STRH        r10,[r4]                    @*pu1_src_top_left = u1_src_top_left_tmp
    +-    LDR         r3,[sp,#0x10C]              @Loads pu1_src_top
    ++    LDR         r3,[sp,#220]                @Loads pu1_src_top
    + 
    + SRC_TOP_LOOP:
    +     VLD1.8      D0,[r12]!                   @pu1_src_top[col] = au1_src_top_tmp[col]
    +@@ -1046,7 +1060,8 @@ SRC_TOP_LOOP:
    +     BNE         SRC_TOP_LOOP
    + 
    + END_LOOPS:
    +-    ADD         sp,sp,#0xD4
    ++    ADD         sp,sp,#224
    ++    vpop        {d8  -  d15}
    +     LDMFD       sp!,{r4-r12,r15}            @Reload the registers from SP
    + 
    + 
    +diff --git a/common/arm/ihevc_weighted_pred_bi.s b/common/arm/ihevc_weighted_pred_bi.s
    +index 5308423..8845b8b 100644
    +--- a/common/arm/ihevc_weighted_pred_bi.s
    ++++ b/common/arm/ihevc_weighted_pred_bi.s
    +@@ -134,6 +134,18 @@
    + @   r14 =>  ht
    + @   r7  =>  wd
    + 
    ++.equ    src_strd2_offset,       104
    ++.equ    dst_strd_offset,        108
    ++.equ    wgt0_offset,            112
    ++.equ    off0_offset,            116
    ++.equ    wgt1_offset,            120
    ++.equ    off1_offset,            124
    ++.equ    shift_offset,           128
    ++.equ    lvl_shift1_offset,      132
    ++.equ    lvl_shift2_offset,      136
    ++.equ    ht_offset,              140
    ++.equ    wd_offset,              144
    ++
    + .text
    + .align 4
    + 
    +@@ -147,32 +159,33 @@
    + ihevc_weighted_pred_bi_a9q:
    + 
    +     stmfd       sp!, {r4-r12, r14}          @stack stores the values of the arguments
    ++    vpush       {d8  -  d15}
    + 
    +-    ldr         r6,[sp,#48]                 @load wgt0
    +-    ldr         r11,[sp,#68]                @load lvl_shift1
    +-    ldr         r12,[sp,#72]                @load lvl_shift2
    ++    ldr         r6,[sp,#wgt0_offset]        @load wgt0
    ++    ldr         r11,[sp,#lvl_shift1_offset] @load lvl_shift1
    ++    ldr         r12,[sp,#lvl_shift2_offset] @load lvl_shift2
    +     vmov.s16    d7[0],r6                    @moved for scalar multiplication
    +     mul         r4,r11,r6                   @lvl_shift1 * wgt0
    +-    ldr         r8,[sp,#56]                 @load wgt1
    +-    ldr         r7,[sp,#52]                 @load off0
    ++    ldr         r8,[sp,#wgt1_offset]        @load wgt1
    ++    ldr         r7,[sp,#off0_offset]        @load off0
    +     vmov.s16    d7[1],r8                    @moved for scalar multiplication
    +     mla         r4,r12,r8,r4                @(lvl_shift1 * wgt0) + (lvl_shift2 * wgt1)
    +-    ldr         r9,[sp,#60]                 @load off1
    ++    ldr         r9,[sp,#off1_offset]        @load off1
    +     add         r5,r7,r9                    @off0 + off1
    +-    ldr         r10,[sp,#64]                @load shift
    ++    ldr         r10,[sp,#shift_offset]      @load shift
    +     add         r5,r5,#1                    @off0 + off1 + 1
    +     sub         r14,r10,#1                  @shift - 1
    +-    ldr         r7,[sp,#80]                 @load wd
    ++    ldr         r7,[sp,#wd_offset]          @load wd
    +     lsl         r5,r5,r14                   @((off0 + off1 + 1) << (shift - 1))
    +     vdup.u32    q14,r10                     @vmovq_n_s32(0-shift)
    +     add         r4,r4,r5                    @tmp_lvl_shift += ((off0 + off1 + 1) << (shift - 1))
    +     vdup.u32    q15,r4                      @vmovq_n_s32(tmp_lvl_shift)
    +     vneg.s32    q14,q14
    +-    ldr         r4,[sp,#40]                 @load src_strd2
    ++    ldr         r4,[sp,#src_strd2_offset]   @load src_strd2
    +     lsl         r9,r7,#1
    +-    ldr         r5,[sp,#44]                 @load dst_strd
    ++    ldr         r5,[sp,#dst_strd_offset]    @load dst_strd
    +     lsl         r3,r3,#1
    +-    ldr         r14,[sp,#76]                @load ht
    ++    ldr         r14,[sp,#ht_offset]         @load ht
    +     lsl         r4,r4,#1
    + 
    +     cmp         r14,#0                      @check ht == 0
    +@@ -260,6 +273,7 @@ end_core_loop:
    +     bgt         core_loop                   @if ht is greater than 0 goto outer_loop
    + 
    + end_loops:
    ++    vpop        {d8  -  d15}
    +     ldmfd       sp!,{r4-r12,r15}            @reload the registers from sp
    + 
    + 
    +diff --git a/common/arm/ihevc_weighted_pred_bi_default.s b/common/arm/ihevc_weighted_pred_bi_default.s
    +index 6bdb8cc..5b369be 100644
    +--- a/common/arm/ihevc_weighted_pred_bi_default.s
    ++++ b/common/arm/ihevc_weighted_pred_bi_default.s
    +@@ -107,6 +107,14 @@
    + @   r7 =>  lvl_shift2
    + @   r8 =>  ht
    + @   r9 =>  wd
    ++
    ++.equ    src_strd2_offset,       104
    ++.equ    dst_strd_offset,        108
    ++.equ    lvl_shift1_offset,      112
    ++.equ    lvl_shift2_offset,      116
    ++.equ    ht_offset,              120
    ++.equ    wd_offset,              124
    ++
    + .text
    + .syntax unified
    + .align 4
    +@@ -121,14 +129,15 @@
    + ihevc_weighted_pred_bi_default_a9q:
    + 
    +     stmfd       sp!, {r4-r12, r14}          @stack stores the values of the arguments
    +-    ldr         r4,[sp,#40]                 @load src_strd2
    ++    vpush       {d8  -  d15}
    ++    ldr         r4,[sp,#src_strd2_offset]   @load src_strd2
    +     lsl         r3,r3,#1
    +-    ldr         r5,[sp,#44]                 @load dst_strd
    +-    ldr         r6,[sp,#48]                 @load lvl_shift1
    ++    ldr         r5,[sp,#dst_strd_offset]    @load dst_strd
    ++    ldr         r6,[sp,#lvl_shift1_offset]  @load lvl_shift1
    +     lsl         r4,r4,#1
    +-    ldr         r7,[sp,#52]                 @load lvl_shift2
    +-    ldr         r8,[sp,#56]                 @load ht
    +-    ldr         r9,[sp,#60]                 @load wd
    ++    ldr         r7,[sp,#lvl_shift2_offset]  @load lvl_shift2
    ++    ldr         r8,[sp,#ht_offset]          @load ht
    ++    ldr         r9,[sp,#wd_offset]          @load wd
    +     vdup.16     q2,r6                       @lvl_shift1_t = vmov_n_s16((int16_t)lvl_shift1)
    +     vdup.16     q3,r7                       @lvl_shift2_t = vmov_n_s16((int16_t)lvl_shift2)
    +     vmov.i16    q0,#0x40                    @tmp_lvl_shift = 1 << (shift - 1)
    +@@ -488,6 +497,7 @@ end_core_loop_16:
    + 
    + 
    + end_loops:
    ++    vpop        {d8  -  d15}
    +     ldmfd       sp!,{r4-r12,r15}            @reload the registers from sp
    + 
    + 
    +diff --git a/common/arm/ihevc_weighted_pred_uni.s b/common/arm/ihevc_weighted_pred_uni.s
    +index e9b69c1..1f99ff8 100644
    +--- a/common/arm/ihevc_weighted_pred_uni.s
    ++++ b/common/arm/ihevc_weighted_pred_uni.s
    +@@ -112,6 +112,13 @@
    + @   r8 =>   ht
    + @   r9  =>  wd
    + 
    ++.equ    wgt0_offset,        104
    ++.equ    off0_offset,        108
    ++.equ    shift_offset,       112
    ++.equ    lvl_shift_offset,   116
    ++.equ    ht_offset,          120
    ++.equ    wd_offset,          124
    ++
    + .text
    + .align 4
    + 
    +@@ -125,16 +132,17 @@
    + ihevc_weighted_pred_uni_a9q:
    + 
    +     stmfd       sp!, {r4-r12, r14}          @stack stores the values of the arguments
    ++    vpush       {d8  -  d15}
    + 
    +-    ldr         r4,[sp,#40]                 @load wgt0
    +-    ldr         r7,[sp,#52]                 @load lvl_shift
    ++    ldr         r4,[sp,#wgt0_offset]        @load wgt0
    ++    ldr         r7,[sp,#lvl_shift_offset]   @load lvl_shift
    +     mov         r11,#1
    +-    ldr         r5,[sp,#44]                 @load off0
    ++    ldr         r5,[sp,#off0_offset]        @load off0
    +     mul         r10,r7,r4                   @lvl_shift * wgt0
    +-    ldr         r6,[sp,#48]                 @load shift
    +-    ldr         r8,[sp,#56]                 @load ht
    ++    ldr         r6,[sp,#shift_offset]       @load shift
    ++    ldr         r8,[sp,#ht_offset]          @load ht
    +     add         r10,r10,r5,lsl r6           @lvl_shift * wgt0 + (off0 << shift)
    +-    ldr         r9,[sp,#60]                 @load wt
    ++    ldr         r9,[sp,#wd_offset]          @load wt
    +     sub         r12,r6,#1
    +     vmov.s16    d0[0],r4                    @moved for scalar multiplication
    +     lsl         r2,r2,#1
    +@@ -214,6 +222,7 @@ end_core_loop:
    +     bgt         core_loop                   @if ht is greater than 0 goto outer_loop
    + 
    + end_loops:
    ++    vpop        {d8  -  d15}
    +     ldmfd       sp!,{r4-r12,r15}            @reload the registers from sp
    + 
    + 
     diff --git a/common/ihevc_structs.h b/common/ihevc_structs.h
     index 93d2ad4..baa6375 100644
     --- a/common/ihevc_structs.h
    @@ -79,10 +4035,18 @@ index c661083..2ae90b0 100644
              ps_codec->pu1_bitsbuf_dynamic = pv_buf;
              ps_codec->u4_bitsbuf_size_dynamic = size;
     diff --git a/decoder/ihevcd_decode.c b/decoder/ihevcd_decode.c
    -index d656519..04ad8f5 100644
    +index d656519..d2ea7a5 100644
     --- a/decoder/ihevcd_decode.c
     +++ b/decoder/ihevcd_decode.c
    -@@ -81,6 +81,7 @@
    +@@ -69,6 +69,7 @@
    + #include "ihevcd_fmt_conv.h"
    + #include "ihevcd_job_queue.h"
    + #include "ihevcd_debug.h"
    ++#include "ihevcd_parse_slice.h"
    + #include "ihevcd_process_slice.h"
    + #include "ihevcd_ittiam_logo.h"
    + #include "ihevcd_profile.h"
    +@@ -81,6 +82,7 @@
      #define NUM_FRAMES_LIMIT 0x7FFFFFFF
      #endif
      
    @@ -90,7 +4054,57 @@ index d656519..04ad8f5 100644
      IHEVCD_ERROR_T ihevcd_fmt_conv(codec_t *ps_codec,
                                     process_ctxt_t *ps_proc,
                                     UWORD8 *pu1_y_dst,
    -@@ -420,7 +421,8 @@ WORD32 ihevcd_decode(iv_obj_t *ps_codec_obj, void *pv_api_ip, void *pv_api_op)
    +@@ -203,6 +205,18 @@ static void ihevcd_fill_outargs(codec_t *ps_codec,
    + 
    +     ps_dec_op->u4_output_present = 0;
    +     ps_dec_op->u4_progressive_frame_flag = 1;
    ++    if(ps_codec->i4_sps_done)
    ++    {
    ++        sps_t *ps_sps = (ps_codec->s_parse.ps_sps_base + ps_codec->i4_sps_id);
    ++        profile_tier_lvl_info_t *ps_ptl;
    ++        ps_ptl = &ps_sps->s_ptl;
    ++        if((0 == ps_ptl->s_ptl_gen.i1_general_progressive_source_flag) &&
    ++           (1 == ps_ptl->s_ptl_gen.i1_general_interlaced_source_flag))
    ++        {
    ++            ps_dec_op->u4_progressive_frame_flag = 0;
    ++        }
    ++    }
    ++
    +     ps_dec_op->u4_is_ref_flag = 1;
    +     ps_dec_op->e_output_format = ps_codec->e_chroma_fmt;
    +     ps_dec_op->u4_is_ref_flag = 1;
    +@@ -224,7 +238,30 @@ static void ihevcd_fill_outargs(codec_t *ps_codec,
    +     if(ps_codec->ps_disp_buf)
    +     {
    +         pic_buf_t *ps_disp_buf = ps_codec->ps_disp_buf;
    ++        sei_params_t *ps_sei = &ps_disp_buf->s_sei_params;
    + 
    ++        if(ps_sei->i1_sei_parameters_present_flag &&
    ++           ps_sei->i1_pic_timing_params_present_flag)
    ++        {
    ++            UWORD32 u4_pic_struct;
    ++            u4_pic_struct = ps_sei->s_pic_timing_sei_params.u4_pic_struct;
    ++            switch(u4_pic_struct)
    ++            {
    ++                case 1:
    ++                    ps_dec_op->e4_fld_type = IV_TOP_FLD;
    ++                    ps_dec_op->u4_progressive_frame_flag = 0;
    ++                    break;
    ++                case 2:
    ++                    ps_dec_op->e4_fld_type = IV_BOT_FLD;
    ++                    ps_dec_op->u4_progressive_frame_flag = 0;
    ++                    break;
    ++                case 0:
    ++                default:
    ++                    ps_dec_op->e4_fld_type = IV_FLD_TYPE_DEFAULT;
    ++                    ps_dec_op->u4_progressive_frame_flag = 1;
    ++                    break;
    ++            }
    ++        }
    +         ps_dec_op->u4_output_present = 1;
    +         ps_dec_op->u4_ts = ps_disp_buf->u4_ts;
    +         if((ps_codec->i4_flush_mode == 0) && (ps_codec->s_parse.i4_end_of_frame == 0))
    +@@ -420,7 +457,8 @@ WORD32 ihevcd_decode(iv_obj_t *ps_codec_obj, void *pv_api_ip, void *pv_api_op)
          if(0 == ps_codec->i4_share_disp_buf && ps_codec->i4_header_mode == 0)
          {
              UWORD32 i;
    @@ -100,7 +4114,7 @@ index d656519..04ad8f5 100644
              {
                  ps_dec_op->u4_error_code |= 1 << IVD_UNSUPPORTEDPARAM;
                  ps_dec_op->u4_error_code |= IVD_DISP_FRM_ZERO_OP_BUFS;
    -@@ -471,6 +473,10 @@ WORD32 ihevcd_decode(iv_obj_t *ps_codec_obj, void *pv_api_ip, void *pv_api_op)
    +@@ -471,6 +509,10 @@ WORD32 ihevcd_decode(iv_obj_t *ps_codec_obj, void *pv_api_ip, void *pv_api_op)
                      ihevcd_init_proc_ctxt(ps_proc, 0);
                  }
      
    @@ -111,7 +4125,7 @@ index d656519..04ad8f5 100644
                  /* Set remaining number of rows to be processed */
                  ret = ihevcd_fmt_conv(ps_codec, &ps_codec->as_process[prev_proc_idx],
                                        ps_dec_ip->s_out_buffer.pu1_bufs[0],
    -@@ -628,7 +634,6 @@ WORD32 ihevcd_decode(iv_obj_t *ps_codec_obj, void *pv_api_ip, void *pv_api_op)
    +@@ -628,15 +670,13 @@ WORD32 ihevcd_decode(iv_obj_t *ps_codec_obj, void *pv_api_ip, void *pv_api_op)
      
              if(IHEVCD_IGNORE_SLICE == ret)
              {
    @@ -119,36 +4133,71 @@ index d656519..04ad8f5 100644
                  ps_codec->pu1_inp_bitsbuf += (nal_ofst + nal_len);
                  ps_codec->i4_bytes_remaining -= (nal_ofst + nal_len);
      
    +             continue;
    +         }
    + 
    +-        if((IVD_RES_CHANGED == ret) ||
    +-           (IHEVCD_UNSUPPORTED_DIMENSIONS == ret))
    ++        if(IVD_RES_CHANGED == ret)
    +         {
    +             break;
    +         }
    +@@ -685,12 +725,20 @@ WORD32 ihevcd_decode(iv_obj_t *ps_codec_obj, void *pv_api_ip, void *pv_api_op)
    +         BREAK_AFTER_SLICE_NAL();
    +     }
    + 
    +-    if((ps_codec->u4_pic_cnt == 0) && (ret != IHEVCD_SUCCESS))
    ++    if(1 == ps_codec->i4_pic_present && 0 == ps_codec->s_parse.i4_end_of_frame)
    +     {
    +-        ps_codec->i4_error_code = ret;
    +-
    +-        ihevcd_fill_outargs(ps_codec, ps_dec_ip, ps_dec_op);
    +-        return IV_FAIL;
    ++        slice_header_t *ps_slice_hdr_next;
    ++        ps_codec->i4_slice_error = 1;
    ++        ps_codec->s_parse.i4_cur_slice_idx--;
    ++        if(ps_codec->s_parse.i4_cur_slice_idx < 0)
    ++            ps_codec->s_parse.i4_cur_slice_idx = 0;
    ++
    ++        ps_slice_hdr_next = ps_codec->s_parse.ps_slice_hdr_base + ((ps_codec->s_parse.i4_cur_slice_idx + 1) & (MAX_SLICE_HDR_CNT - 1));
    ++        ps_slice_hdr_next->i2_ctb_x = -1;
    ++        ps_slice_hdr_next->i2_ctb_y = -1;
    ++
    ++        ihevcd_parse_slice_data(ps_codec);
    ++        ASSERT(ps_codec->s_parse.i4_end_of_frame != 0);
    +     }
    + 
    +     if(1 == ps_codec->i4_pic_present)
     diff --git a/decoder/ihevcd_parse_headers.c b/decoder/ihevcd_parse_headers.c
    -index c0f1564..06f35a3 100644
    +index c0f1564..6a9fe5e 100644
     --- a/decoder/ihevcd_parse_headers.c
     +++ b/decoder/ihevcd_parse_headers.c
     @@ -1285,15 +1285,31 @@ IHEVCD_ERROR_T ihevcd_parse_sps(codec_t *ps_codec)
          {
      
              UEV_PARSE("pic_crop_left_offset", value, ps_bitstrm);
    -+        if (value >= ps_sps->i2_pic_width_in_luma_samples)
    ++        if (value < 0 || value >= ps_sps->i2_pic_width_in_luma_samples)
     +        {
     +            return IHEVCD_INVALID_PARAMETER;
     +        }
              ps_sps->i2_pic_crop_left_offset = value;
      
              UEV_PARSE("pic_crop_right_offset", value, ps_bitstrm);
    -+        if (value >= ps_sps->i2_pic_width_in_luma_samples)
    ++        if (value < 0 || value >= ps_sps->i2_pic_width_in_luma_samples)
     +        {
     +            return IHEVCD_INVALID_PARAMETER;
     +        }
              ps_sps->i2_pic_crop_right_offset = value;
      
              UEV_PARSE("pic_crop_top_offset", value, ps_bitstrm);
    -+        if (value >= ps_sps->i2_pic_height_in_luma_samples)
    ++        if (value < 0 || value >= ps_sps->i2_pic_height_in_luma_samples)
     +        {
     +            return IHEVCD_INVALID_PARAMETER;
     +        }
              ps_sps->i2_pic_crop_top_offset = value;
      
              UEV_PARSE("pic_crop_bottom_offset", value, ps_bitstrm);
    -+        if (value >= ps_sps->i2_pic_height_in_luma_samples)
    ++        if (value < 0 || value >= ps_sps->i2_pic_height_in_luma_samples)
     +        {
     +            return IHEVCD_INVALID_PARAMETER;
     +        }
    @@ -176,10 +4225,73 @@ index c0f1564..06f35a3 100644
          ps_pps->i1_entropy_coding_sync_enabled_flag = value;
      
     diff --git a/decoder/ihevcd_parse_slice.c b/decoder/ihevcd_parse_slice.c
    -index 126b14c..9f92a0d 100644
    +index 126b14c..70c2e88 100644
     --- a/decoder/ihevcd_parse_slice.c
     +++ b/decoder/ihevcd_parse_slice.c
    -@@ -2708,6 +2708,17 @@ IHEVCD_ERROR_T ihevcd_parse_slice_data(codec_t *ps_codec)
    +@@ -2376,26 +2376,29 @@ IHEVCD_ERROR_T ihevcd_parse_slice_data(codec_t *ps_codec)
    + 
    +     /*Cabac init at the beginning of a slice*/
    +     //If the slice is a dependent slice, not present at the start of a tile
    +-    if((1 == ps_slice_hdr->i1_dependent_slice_flag) && (!((ps_codec->s_parse.i4_ctb_tile_x == 0) && (ps_codec->s_parse.i4_ctb_tile_y == 0))))
    ++    if(0 == ps_codec->i4_slice_error)
    +     {
    +-        if((0 == ps_pps->i1_entropy_coding_sync_enabled_flag) || (ps_pps->i1_entropy_coding_sync_enabled_flag && (0 != ps_codec->s_parse.i4_ctb_x)))
    ++        if((1 == ps_slice_hdr->i1_dependent_slice_flag) && (!((ps_codec->s_parse.i4_ctb_tile_x == 0) && (ps_codec->s_parse.i4_ctb_tile_y == 0))))
    +         {
    +-            ihevcd_cabac_reset(&ps_codec->s_parse.s_cabac,
    +-                               &ps_codec->s_parse.s_bitstrm);
    ++            if((0 == ps_pps->i1_entropy_coding_sync_enabled_flag) || (ps_pps->i1_entropy_coding_sync_enabled_flag && (0 != ps_codec->s_parse.i4_ctb_x)))
    ++            {
    ++                ihevcd_cabac_reset(&ps_codec->s_parse.s_cabac,
    ++                                   &ps_codec->s_parse.s_bitstrm);
    ++            }
    +         }
    +-    }
    +-    else if((0 == ps_pps->i1_entropy_coding_sync_enabled_flag) || (ps_pps->i1_entropy_coding_sync_enabled_flag && (0 != ps_codec->s_parse.i4_ctb_x)))
    +-    {
    +-        ret = ihevcd_cabac_init(&ps_codec->s_parse.s_cabac,
    +-                                &ps_codec->s_parse.s_bitstrm,
    +-                                slice_qp,
    +-                                cabac_init_idc,
    +-                                &gau1_ihevc_cab_ctxts[cabac_init_idc][slice_qp][0]);
    +-        if(ret != (IHEVCD_ERROR_T)IHEVCD_SUCCESS)
    ++        else if((0 == ps_pps->i1_entropy_coding_sync_enabled_flag) || (ps_pps->i1_entropy_coding_sync_enabled_flag && (0 != ps_codec->s_parse.i4_ctb_x)))
    +         {
    +-            ps_codec->i4_slice_error = 1;
    +-            end_of_slice_flag = 1;
    +-            ret = (IHEVCD_ERROR_T)IHEVCD_SUCCESS;
    ++            ret = ihevcd_cabac_init(&ps_codec->s_parse.s_cabac,
    ++                                    &ps_codec->s_parse.s_bitstrm,
    ++                                    slice_qp,
    ++                                    cabac_init_idc,
    ++                                    &gau1_ihevc_cab_ctxts[cabac_init_idc][slice_qp][0]);
    ++            if(ret != (IHEVCD_ERROR_T)IHEVCD_SUCCESS)
    ++            {
    ++                ps_codec->i4_slice_error = 1;
    ++                end_of_slice_flag = 1;
    ++                ret = (IHEVCD_ERROR_T)IHEVCD_SUCCESS;
    ++            }
    +         }
    +     }
    + 
    +@@ -2479,6 +2482,7 @@ IHEVCD_ERROR_T ihevcd_parse_slice_data(codec_t *ps_codec)
    + 
    +             /* Cabac init is done unconditionally at the start of the tile irrespective
    +              * of whether it is a dependent or an independent slice */
    ++            if(0 == ps_codec->i4_slice_error)
    +             {
    +                 ret = ihevcd_cabac_init(&ps_codec->s_parse.s_cabac,
    +                                         &ps_codec->s_parse.s_bitstrm,
    +@@ -2542,7 +2546,7 @@ IHEVCD_ERROR_T ihevcd_parse_slice_data(codec_t *ps_codec)
    +         if(ps_pps->i1_entropy_coding_sync_enabled_flag)
    +         {
    +             /*TODO Handle single CTB and top-right belonging to a different slice */
    +-            if(0 == ps_codec->s_parse.i4_ctb_x)
    ++            if(0 == ps_codec->s_parse.i4_ctb_x && 0 == ps_codec->i4_slice_error)
    +             {
    +                 //WORD32 size = sizeof(ps_codec->s_parse.s_cabac.au1_ctxt_models);
    +                 WORD32 default_ctxt = 0;
    +@@ -2708,6 +2712,17 @@ IHEVCD_ERROR_T ihevcd_parse_slice_data(codec_t *ps_codec)
              {
                  tu_t *ps_tu = ps_codec->s_parse.ps_tu;
                  pu_t *ps_pu = ps_codec->s_parse.ps_pu;
    @@ -197,7 +4309,7 @@ index 126b14c..9f92a0d 100644
      
                  ps_tu->b1_cb_cbf = 0;
                  ps_tu->b1_cr_cbf = 0;
    -@@ -2731,8 +2742,8 @@ IHEVCD_ERROR_T ihevcd_parse_slice_data(codec_t *ps_codec)
    +@@ -2731,8 +2746,8 @@ IHEVCD_ERROR_T ihevcd_parse_slice_data(codec_t *ps_codec)
                  ps_pu->b2_part_idx = 0;
                  ps_pu->b4_pos_x = 0;
                  ps_pu->b4_pos_y = 0;
    @@ -208,6 +4320,28 @@ index 126b14c..9f92a0d 100644
                  ps_pu->b1_intra_flag = 0;
                  ps_pu->b3_part_mode = ps_codec->s_parse.s_cu.i4_part_mode;
                  ps_pu->b1_merge_flag = 1;
    +@@ -2772,7 +2787,7 @@ IHEVCD_ERROR_T ihevcd_parse_slice_data(codec_t *ps_codec)
    +                 if((ps_codec->s_parse.i4_ctb_tile_y + 1) == ps_tile->u2_ht)
    +                     end_of_tile = 1;
    +             }
    +-            if((0 == end_of_slice_flag) &&
    ++            if((0 == end_of_slice_flag) && (0 == ps_codec->i4_slice_error) &&
    +                             ((ps_pps->i1_tiles_enabled_flag && end_of_tile) ||
    +                                             (ps_pps->i1_entropy_coding_sync_enabled_flag && end_of_tile_row)))
    +             {
    +diff --git a/decoder/ihevcd_parse_slice_header.c b/decoder/ihevcd_parse_slice_header.c
    +index e1b50b7..ae19328 100644
    +--- a/decoder/ihevcd_parse_slice_header.c
    ++++ b/decoder/ihevcd_parse_slice_header.c
    +@@ -356,7 +356,7 @@ IHEVCD_ERROR_T ihevcd_parse_slice_header(codec_t *ps_codec,
    +         slice_address = value;
    +         /* If slice address is greater than the number of CTBs in a picture,
    +          * ignore the slice */
    +-        if(value >= ps_sps->i4_pic_size_in_ctb)
    ++        if(value >= ps_sps->i4_pic_size_in_ctb || value <= 0)
    +             return IHEVCD_IGNORE_SLICE;
    +     }
    +     else
     diff --git a/decoder/ihevcd_utils.c b/decoder/ihevcd_utils.c
     index 7d76577..14cdd2b 100755
     --- a/decoder/ihevcd_utils.c
    diff --git a/external_libmpeg2.patch b/external_libmpeg2.patch
    index dee93db..467feca 100644
    --- a/external_libmpeg2.patch
    +++ b/external_libmpeg2.patch
    @@ -1,3 +1,3959 @@
    +diff --git a/common/arm/ihevc_deblk_chroma_horz.s b/common/arm/ihevc_deblk_chroma_horz.s
    +index 34422ff..b0a79eb 100644
    +--- a/common/arm/ihevc_deblk_chroma_horz.s
    ++++ b/common/arm/ihevc_deblk_chroma_horz.s
    +@@ -36,6 +36,12 @@
    + @*
    + @*******************************************************************************/
    + 
    ++.equ    qp_offset_u_offset,     40
    ++.equ    qp_offset_v_offset,     44
    ++.equ    tc_offset_div2_offset,  48
    ++.equ    filter_p_offset,        52
    ++.equ    filter_q_offset,        56
    ++
    + .text
    + .align 4
    + 
    +@@ -62,17 +68,17 @@ ihevc_deblk_chroma_horz_a9q:
    +     add         r6,r0,r1
    +     add         r1,r2,r3
    +     vmovl.u8    q0,d0
    +-    ldr         r10,[sp,#0x28]
    ++    ldr         r10,[sp,#qp_offset_u_offset]
    +     vld1.8      {d2},[r12]
    +     add         r2,r1,#1
    +-    ldr         r4,[sp,#0x30]
    ++    ldr         r4,[sp,#tc_offset_div2_offset]
    +     vld1.8      {d4},[r5]
    +-    ldr         r8,[sp,#0x34]
    ++    ldr         r8,[sp,#filter_p_offset]
    +     vld1.8      {d16},[r6]
    +-    ldr         r9,[sp,#0x38]
    ++    ldr         r9,[sp,#filter_q_offset]
    +     adds        r1,r10,r2,asr #1
    +     vmovl.u8    q1,d2
    +-    ldr         r7,[sp,#0x2c]
    ++    ldr         r7,[sp,#qp_offset_v_offset]
    +     ldr         r3,gai4_ihevc_qp_table_addr
    + ulbl1:
    +     add         r3, r3, pc
    +diff --git a/common/arm/ihevc_deblk_chroma_vert.s b/common/arm/ihevc_deblk_chroma_vert.s
    +index 4cb305f..3962b28 100644
    +--- a/common/arm/ihevc_deblk_chroma_vert.s
    ++++ b/common/arm/ihevc_deblk_chroma_vert.s
    +@@ -37,6 +37,12 @@
    + @*
    + @*******************************************************************************/
    + 
    ++.equ    qp_offset_u_offset,     40
    ++.equ    qp_offset_v_offset,     44
    ++.equ    tc_offset_div2_offset,  48
    ++.equ    filter_p_offset,        52
    ++.equ    filter_q_offset,        56
    ++
    + .text
    + .align 4
    + 
    +@@ -63,19 +69,19 @@ ihevc_deblk_chroma_vert_a9q:
    +     vld1.8      {d5},[r8],r1
    +     add         r2,r2,#1
    +     vld1.8      {d17},[r8],r1
    +-    ldr         r7,[sp,#0x28]
    ++    ldr         r7,[sp,#qp_offset_u_offset]
    +     vld1.8      {d16},[r8],r1
    +-    ldr         r4,[sp,#0x38]
    ++    ldr         r4,[sp,#filter_q_offset]
    +     vld1.8      {d4},[r8]
    +-    ldr         r5,[sp,#0x30]
    ++    ldr         r5,[sp,#tc_offset_div2_offset]
    +     vtrn.8      d5,d17
    +     adds        r3,r7,r2,asr #1
    +     vtrn.8      d16,d4
    +     ldr         r7,gai4_ihevc_qp_table_addr
    + ulbl1:
    +     add         r7,r7,pc
    +-    ldr         r12,[sp,#0x34]
    +-    ldr         r6,[sp,#0x2c]
    ++    ldr         r12,[sp,#filter_p_offset]
    ++    ldr         r6,[sp,#qp_offset_v_offset]
    +     bmi         l1.2944
    +     cmp         r3,#0x39
    +     ldrle       r3,[r7,r3,lsl #2]
    +diff --git a/common/arm/ihevc_deblk_luma_horz.s b/common/arm/ihevc_deblk_luma_horz.s
    +index b12ceb9..76660b3 100644
    +--- a/common/arm/ihevc_deblk_luma_horz.s
    ++++ b/common/arm/ihevc_deblk_luma_horz.s
    +@@ -36,6 +36,12 @@
    + @*
    + @*******************************************************************************/
    + 
    ++.equ    qp_q_offset,                108
    ++.equ    beta_offset_div2_offset,    112
    ++.equ    tc_offset_div2_offset,      116
    ++.equ    filter_p_offset,            120
    ++.equ    filter_q_offset,            124
    ++
    + .text
    + .align 4
    + 
    +@@ -57,12 +63,14 @@ gai4_ihevc_beta_table_addr:
    + 
    + ihevc_deblk_luma_horz_a9q:
    +     stmfd       sp!, {r3-r12,lr}
    +-    ldr         r4,[sp,#0x2c]
    +-    ldr         r5,[sp,#0x30]
    ++    vpush       {d8  -  d15}
    ++
    ++    ldr         r4,[sp,#qp_q_offset]
    ++    ldr         r5,[sp,#beta_offset_div2_offset]
    + 
    +     add         r3,r3,r4
    +     add         r3,r3,#1
    +-    ldr         r6, [sp,#0x34]
    ++    ldr         r6, [sp,#tc_offset_div2_offset]
    +     asr         r3,r3,#1
    +     add         r7,r3,r5,lsl #1
    +     add         r3,r3,r6,lsl #1
    +@@ -291,9 +299,9 @@ ulbl1:
    +     vmin.u8     d18,d20,d30
    +     mov         r2,#2
    +     vqadd.u8    d30,d23,d1
    +-    ldr         r4,[sp,#0x38]               @ loading the filter_flag_p
    ++    ldr         r4,[sp,#filter_p_offset]         @ loading the filter_flag_p
    +     vmax.u8     d2,d18,d31
    +-    ldr         r5,[sp,#0x3c]               @ loading the filter_flag_q
    ++    ldr         r5,[sp,#filter_q_offset]         @ loading the filter_flag_q
    +     vrshrn.i16  d21,q7,#2
    +     b           end_dep_deq_decision_horz
    +     @ r2 has the value of de
    +@@ -308,8 +316,8 @@ l1.1840:
    +     mov         r2,#1
    + 
    +     mov         r11,r5
    +-    ldr         r4,[sp,#0x38]               @ loading the filter_flag_p
    +-    ldr         r5,[sp,#0x3c]               @ loading the filter_flag_q
    ++    ldr         r4,[sp,#filter_p_offset]         @ loading the filter_flag_p
    ++    ldr         r5,[sp,#filter_q_offset]         @ loading the filter_flag_q
    + 
    +     cmp         r6,#1
    +     moveq       r9,#0
    +@@ -397,6 +405,7 @@ strong_filtering_p:
    +     vst1.32     d3[0],[r12]
    + 
    + l1.2404:
    ++    vpop        {d8  -  d15}
    +     ldmfd       sp!, {r3-r12,pc}
    + 
    +     @ r4=flag p
    +@@ -537,6 +546,8 @@ l1.2852:
    +     vbsl        d19,d26,d13
    +     vst1.32     {d19[0]},[r12],r1
    +     vst1.32     {d18[0]},[r12]
    ++
    ++    vpop        {d8  -  d15}
    +     ldmfd       sp!, {r3-r12,r15}
    + 
    + 
    +diff --git a/common/arm/ihevc_deblk_luma_vert.s b/common/arm/ihevc_deblk_luma_vert.s
    +index ee247cc..91662c9 100644
    +--- a/common/arm/ihevc_deblk_luma_vert.s
    ++++ b/common/arm/ihevc_deblk_luma_vert.s
    +@@ -37,6 +37,12 @@
    + @*
    + @*******************************************************************************/
    + 
    ++.equ    qp_q_offset,                44
    ++.equ    beta_offset_div2_offset,    48
    ++.equ    tc_offset_div2_offset,      52
    ++.equ    filter_p_offset,            56
    ++.equ    filter_q_offset,            60
    ++
    + .text
    + .align 4
    + 
    +@@ -60,12 +66,12 @@ gai4_ihevc_beta_table_addr:
    + ihevc_deblk_luma_vert_a9q:
    + 
    +     push        {r3-r12,lr}
    +-    ldr         r4,[sp,#0x2c]
    +-    ldr         r5,[sp,#0x30]
    ++    ldr         r4,[sp,#qp_q_offset]
    ++    ldr         r5,[sp,#beta_offset_div2_offset]
    + 
    +     add         r3,r3,r4
    +     add         r3,r3,#1
    +-    ldr         r6, [sp,#0x34]
    ++    ldr         r6, [sp,#tc_offset_div2_offset]
    +     asr         r3,r3,#1
    +     add         r7,r3,r5,lsl #1
    +     add         r3,r3,r6,lsl #1
    +@@ -291,9 +297,9 @@ ulbl1:
    +     vqadd.u8    d30,d6,d19
    + 
    +     mov         r2,#2
    +-    ldr         r4,[sp,#0x38]               @ loading the filter_flag_p
    ++    ldr         r4,[sp,#filter_p_offset]        @ loading the filter_flag_p
    +     vqsub.u8    d31,d6,d19
    +-    ldr         r5,[sp,#0x3c]               @ loading the filter_flag_q
    ++    ldr         r5,[sp,#filter_q_offset]        @ loading the filter_flag_q
    +     b           end_dep_deq_decision
    + @ r2 has the value of de
    + @ r6 has teh value of tc
    +@@ -307,8 +313,8 @@ l1.336:
    +     mov         r2,#1
    + l1.424:
    +     mov         r11,r5
    +-    ldr         r4,[sp,#0x38]               @ loading the filter_flag_p
    +-    ldr         r5,[sp,#0x3c]               @ loading the filter_flag_q
    ++    ldr         r4,[sp,#filter_p_offset]        @ loading the filter_flag_p
    ++    ldr         r5,[sp,#filter_q_offset]        @ loading the filter_flag_q
    + 
    +     cmp         r6,#1
    +     moveq       r9,#0
    +@@ -532,7 +538,6 @@ l1.1212:
    +     vst1.16     {d3[1]},[r12]
    +     vst1.8      {d16[3]},[r3]
    + l1.1272:
    +-    @   ldr      r3,[sp,#0x38]
    +     cmp         r5,#0
    +     beq         l1.964
    +     @ checks for the flag q
    +diff --git a/common/arm/ihevc_inter_pred_chroma_copy.s b/common/arm/ihevc_inter_pred_chroma_copy.s
    +index 0da34cc..1b38dbb 100644
    +--- a/common/arm/ihevc_inter_pred_chroma_copy.s
    ++++ b/common/arm/ihevc_inter_pred_chroma_copy.s
    +@@ -92,6 +92,9 @@
    + @               r5 =>  ht
    + @               r6 =>  wd
    + 
    ++.equ    ht_offset,      44
    ++.equ    wd_offset,      48
    ++
    + .text
    + .align 4
    + 
    +@@ -104,9 +107,9 @@
    + 
    + ihevc_inter_pred_chroma_copy_a9q:
    +     stmfd       sp!, {r4-r12, r14}          @stack stores the values of the arguments
    +-    ldr         r12,[sp,#48]                @loads wd
    ++    ldr         r12,[sp,#wd_offset]         @loads wd
    +     lsl         r12,r12,#1
    +-    ldr         r7,[sp,#44]                 @loads ht
    ++    ldr         r7,[sp,#ht_offset]          @loads ht
    +     cmp         r7,#0                       @checks ht == 0
    +     ble         end_loops
    +     and         r8,r7,#3                    @check ht for mul of 2
    +diff --git a/common/arm/ihevc_inter_pred_chroma_copy_w16out.s b/common/arm/ihevc_inter_pred_chroma_copy_w16out.s
    +index a927fa7..4997b84 100644
    +--- a/common/arm/ihevc_inter_pred_chroma_copy_w16out.s
    ++++ b/common/arm/ihevc_inter_pred_chroma_copy_w16out.s
    +@@ -92,6 +92,11 @@
    + @r5 =>  ht
    + @r6 =>  wd
    + 
    ++.equ    coeff_offset,   104
    ++.equ    ht_offset,      108
    ++.equ    wd_offset,      112
    ++
    ++
    + .text
    + .align 4
    + 
    +@@ -105,9 +110,11 @@
    + ihevc_inter_pred_chroma_copy_w16out_a9q:
    + 
    +     stmfd       sp!, {r4-r12, r14}          @stack stores the values of the arguments
    +-    ldr         r12,[sp,#48]                @loads wd
    ++    vpush        {d8 - d15}
    ++
    ++    ldr         r12,[sp,#wd_offset]                @loads wd
    +     lsl         r12,r12,#1                  @2*wd
    +-    ldr         r7,[sp,#44]                 @loads ht
    ++    ldr         r7,[sp,#ht_offset]                 @loads ht
    +     cmp         r7,#0                       @ht condition(ht == 0)
    +     ble         end_loops                   @loop
    +     and         r8,r7,#3                    @check ht for mul of 2
    +@@ -162,6 +169,7 @@ end_inner_loop_wd_4:
    + 
    + 
    + end_loops:
    ++    vpop         {d8 - d15}
    +     ldmfd       sp!,{r4-r12,r15}            @reload the registers from sp
    + 
    + 
    +@@ -316,6 +324,7 @@ core_loop_wd_8_ht_2:
    +     vst1.16     {d2,d3},[r10],r5            @vst1q_s16(pi2_dst_tmp, tmp)
    +     bgt         core_loop_wd_8_ht_2
    + 
    ++    vpop         {d8 - d15}
    +     ldmfd       sp!,{r4-r12,r15}            @reload the registers from sp
    + 
    + 
    +diff --git a/common/arm/ihevc_inter_pred_chroma_horz.s b/common/arm/ihevc_inter_pred_chroma_horz.s
    +index 4781d3e..c69b417 100644
    +--- a/common/arm/ihevc_inter_pred_chroma_horz.s
    ++++ b/common/arm/ihevc_inter_pred_chroma_horz.s
    +@@ -93,6 +93,10 @@
    + @r2 =>  src_strd
    + @r3 =>  dst_strd
    + 
    ++.equ    coeff_offset,   104
    ++.equ    ht_offset,      108
    ++.equ    wd_offset,      112
    ++
    + .text
    + .align 4
    + 
    +@@ -106,10 +110,11 @@
    + ihevc_inter_pred_chroma_horz_a9q:
    + 
    +     stmfd       sp!, {r4-r12, r14}          @stack stores the values of the arguments
    ++    vpush        {d8 - d15}
    + 
    +-    ldr         r4,[sp,#40]                 @loads pi1_coeff
    +-    ldr         r7,[sp,#44]                 @loads ht
    +-    ldr         r10,[sp,#48]                @loads wd
    ++    ldr         r4,[sp,#coeff_offset]                 @loads pi1_coeff
    ++    ldr         r7,[sp,#ht_offset]                 @loads ht
    ++    ldr         r10,[sp,#wd_offset]                @loads wd
    + 
    +     vld1.8      {d0},[r4]                   @coeff = vld1_s8(pi1_coeff)
    +     subs        r14,r7,#0                   @checks for ht == 0
    +@@ -672,6 +677,7 @@ inner_loop_4:
    + 
    + end_loops:
    + 
    ++    vpop         {d8 - d15}
    +     ldmfd       sp!,{r4-r12,r15}            @reload the registers from sp
    + 
    + 
    +diff --git a/common/arm/ihevc_inter_pred_chroma_horz_w16out.s b/common/arm/ihevc_inter_pred_chroma_horz_w16out.s
    +index f95937c..9c498e8 100644
    +--- a/common/arm/ihevc_inter_pred_chroma_horz_w16out.s
    ++++ b/common/arm/ihevc_inter_pred_chroma_horz_w16out.s
    +@@ -90,6 +90,9 @@
    + @r2 =>  src_strd
    + @r3 =>  dst_strd
    + 
    ++.equ    coeff_offset,   104
    ++.equ    ht_offset,      108
    ++.equ    wd_offset,      112
    + 
    + .text
    + .align 4
    +@@ -105,10 +108,11 @@
    + ihevc_inter_pred_chroma_horz_w16out_a9q:
    + 
    +     stmfd       sp!, {r4-r12, r14}          @stack stores the values of the arguments
    ++    vpush        {d8 - d15}
    + 
    +-    ldr         r4,[sp,#40]                 @loads pi1_coeff
    +-    ldr         r6,[sp,#44]                 @loads ht
    +-    ldr         r10,[sp,#48]                @loads wd
    ++    ldr         r4,[sp,#coeff_offset]                 @loads pi1_coeff
    ++    ldr         r6,[sp,#ht_offset]                 @loads ht
    ++    ldr         r10,[sp,#wd_offset]                @loads wd
    + 
    +     vld1.8      {d0},[r4]                   @coeff = vld1_s8(pi1_coeff)
    +     subs        r14,r6,#0                   @checks for ht == 0
    +@@ -362,7 +366,7 @@ epilog_end:
    +     vst1.16     {q10},[r1],r6               @store the result pu1_dst
    + 
    + 
    +-    ldr         r6,[sp,#44]                 @loads ht
    ++    ldr         r6,[sp,#ht_offset]                 @loads ht
    + 
    +     and         r7,r6,#1
    + 
    +@@ -710,6 +714,7 @@ loop_residue:
    + 
    + end_loops:
    + 
    ++    vpop         {d8 - d15}
    +     ldmfd       sp!,{r4-r12,r15}            @reload the registers from sp
    + 
    + 
    +diff --git a/common/arm/ihevc_inter_pred_chroma_vert.s b/common/arm/ihevc_inter_pred_chroma_vert.s
    +index e786497..8b4e48b 100644
    +--- a/common/arm/ihevc_inter_pred_chroma_vert.s
    ++++ b/common/arm/ihevc_inter_pred_chroma_vert.s
    +@@ -92,6 +92,11 @@
    + @r1 => *pi2_dst
    + @r2 =>  src_strd
    + @r3 =>  dst_strd
    ++
    ++.equ    coeff_offset,   104
    ++.equ    ht_offset,      108
    ++.equ    wd_offset,      112
    ++
    + .text
    + .align 4
    + 
    +@@ -105,11 +110,12 @@
    + ihevc_inter_pred_chroma_vert_a9q:
    + 
    +     stmfd       sp!,{r4-r12,r14}            @stack stores the values of the arguments
    ++    vpush        {d8 - d15}
    + 
    +-    ldr         r4,[sp,#44]                 @loads ht
    +-    ldr         r12,[sp,#40]                @loads pi1_coeff
    ++    ldr         r4,[sp,#ht_offset]                 @loads ht
    ++    ldr         r12,[sp,#coeff_offset]                @loads pi1_coeff
    +     cmp         r4,#0                       @checks ht == 0
    +-    ldr         r6,[sp,#48]                 @loads wd
    ++    ldr         r6,[sp,#wd_offset]                 @loads wd
    +     sub         r0,r0,r2                    @pu1_src - src_strd
    +     vld1.8      {d0},[r12]                  @loads pi1_coeff
    + 
    +@@ -377,6 +383,7 @@ epilog:
    +     vqrshrun.s16 d24,q12,#6
    +     vst1.8      {d24},[r7],r3               @stores the loaded value
    + end_loops:
    ++    vpop         {d8 - d15}
    +     ldmfd       sp!,{r4-r12,r15}            @reload the registers from sp
    + 
    + 
    +diff --git a/common/arm/ihevc_inter_pred_chroma_vert_w16inp.s b/common/arm/ihevc_inter_pred_chroma_vert_w16inp.s
    +index ba2ea8e..f9e513a 100644
    +--- a/common/arm/ihevc_inter_pred_chroma_vert_w16inp.s
    ++++ b/common/arm/ihevc_inter_pred_chroma_vert_w16inp.s
    +@@ -92,6 +92,11 @@
    + @r2 =>  src_strd
    + @r3 =>  dst_strd
    + 
    ++.equ    coeff_offset,   104
    ++.equ    ht_offset,      108
    ++.equ    wd_offset,      112
    ++
    ++
    + .text
    + .align 4
    + 
    +@@ -105,11 +110,12 @@
    + ihevc_inter_pred_chroma_vert_w16inp_a9q:
    + 
    +     stmfd       sp!, {r4-r12, r14}          @stack stores the values of the arguments
    ++    vpush        {d8 - d15}
    + 
    +-    ldr         r4, [sp,#40]                @loads pi1_coeff
    +-    ldr         r6, [sp,#48]                @wd
    ++    ldr         r4, [sp,#coeff_offset]                @loads pi1_coeff
    ++    ldr         r6, [sp,#wd_offset]                @wd
    +     lsl         r2,r2,#1                    @src_strd = 2* src_strd
    +-    ldr         r5,[sp,#44]                 @loads ht
    ++    ldr         r5,[sp,#ht_offset]                 @loads ht
    +     vld1.8      {d0},[r4]                   @loads pi1_coeff
    +     sub         r4,r0,r2                    @pu1_src - src_strd
    +     vmovl.s8    q0,d0                       @long the value
    +@@ -335,6 +341,7 @@ epilog:
    +     vst1.32     {d24[0]},[r9]               @stores the loaded value
    + 
    + end_loops:
    ++    vpop         {d8 - d15}
    +     ldmfd       sp!,{r4-r12,r15}            @reload the registers from sp
    + 
    + 
    +diff --git a/common/arm/ihevc_inter_pred_chroma_vert_w16inp_w16out.s b/common/arm/ihevc_inter_pred_chroma_vert_w16inp_w16out.s
    +index 00b3011..0c2ffbd 100644
    +--- a/common/arm/ihevc_inter_pred_chroma_vert_w16inp_w16out.s
    ++++ b/common/arm/ihevc_inter_pred_chroma_vert_w16inp_w16out.s
    +@@ -92,6 +92,11 @@
    + @r1 => *pi2_dst
    + @r2 =>  src_strd
    + @r3 =>  dst_strd
    ++
    ++.equ    coeff_offset,   104
    ++.equ    ht_offset,      108
    ++.equ    wd_offset,      112
    ++
    + .text
    + .align 4
    + 
    +@@ -105,11 +110,12 @@
    + ihevc_inter_pred_chroma_vert_w16inp_w16out_a9q:
    + 
    +     stmfd       sp!, {r4-r12, r14}          @stack stores the values of the arguments
    ++    vpush        {d8 - d15}
    + 
    +-    ldr         r4, [sp,#40]                @loads pi1_coeff
    +-    ldr         r6, [sp,#48]                @wd
    ++    ldr         r4, [sp,#coeff_offset]                @loads pi1_coeff
    ++    ldr         r6, [sp,#wd_offset]                @wd
    +     lsl         r2,r2,#1                    @src_strd = 2* src_strd
    +-    ldr         r5,[sp,#44]                 @loads ht
    ++    ldr         r5,[sp,#ht_offset]                 @loads ht
    +     vld1.8      {d0},[r4]                   @loads pi1_coeff
    +     sub         r4,r0,r2                    @pu1_src - src_strd
    +     vmovl.s8    q0,d0                       @long the value
    +@@ -322,6 +328,7 @@ epilog:
    +     vst1.32     {d24},[r9]                  @stores the loaded value
    + 
    + end_loops:
    ++    vpop         {d8 - d15}
    +     ldmfd       sp!,{r4-r12,r15}            @reload the registers from sp
    + 
    + 
    +diff --git a/common/arm/ihevc_inter_pred_chroma_vert_w16out.s b/common/arm/ihevc_inter_pred_chroma_vert_w16out.s
    +index 6e6776c..84b0792 100644
    +--- a/common/arm/ihevc_inter_pred_chroma_vert_w16out.s
    ++++ b/common/arm/ihevc_inter_pred_chroma_vert_w16out.s
    +@@ -93,6 +93,10 @@
    + @r2 =>  src_strd
    + @r3 =>  dst_strd
    + 
    ++.equ    coeff_offset,   104
    ++.equ    ht_offset,      108
    ++.equ    wd_offset,      112
    ++
    + .text
    + .align 4
    + 
    +@@ -106,11 +110,12 @@
    + ihevc_inter_pred_chroma_vert_w16out_a9q:
    + 
    +     stmfd       sp!,{r4-r12,r14}            @stack stores the values of the arguments
    ++    vpush        {d8 - d15}
    + 
    +-    ldr         r4,[sp,#44]                 @loads ht
    +-    ldr         r12,[sp,#40]                @loads pi1_coeff
    ++    ldr         r4,[sp,#ht_offset]                 @loads ht
    ++    ldr         r12,[sp,#coeff_offset]                @loads pi1_coeff
    +     cmp         r4,#0                       @checks ht == 0
    +-    ldr         r6,[sp,#48]                 @loads wd
    ++    ldr         r6,[sp,#wd_offset]                 @loads wd
    +     sub         r0,r0,r2                    @pu1_src - src_strd
    +     vld1.8      {d0},[r12]                  @loads pi1_coeff
    + 
    +@@ -361,6 +366,7 @@ epilog:
    +     vst1.8      {q12},[r7],r3               @stores the loaded value
    + 
    + end_loops:
    ++    vpop         {d8 - d15}
    +     ldmfd       sp!,{r4-r12,r15}            @reload the registers from sp
    + 
    + 
    +diff --git a/common/arm/ihevc_inter_pred_filters_luma_horz.s b/common/arm/ihevc_inter_pred_filters_luma_horz.s
    +index 215f8fd..5559aa7 100644
    +--- a/common/arm/ihevc_inter_pred_filters_luma_horz.s
    ++++ b/common/arm/ihevc_inter_pred_filters_luma_horz.s
    +@@ -103,6 +103,11 @@
    + @   r5 =>  ht
    + @   r6 =>  wd
    + 
    ++
    ++.equ    coeff_offset,   104
    ++.equ    ht_offset,      108
    ++.equ    wd_offset,      112
    ++
    + .text
    + .align 4
    + 
    +@@ -116,15 +121,15 @@
    + ihevc_inter_pred_luma_horz_a9q:
    + 
    +     stmfd       sp!, {r4-r12, r14}          @stack stores the values of the arguments
    +-    @str        r1,[sp,#-4]
    +-    @ mov       r7,#8192
    ++    vpush        {d8 - d15}
    ++
    ++
    + start_loop_count:
    +-    @ ldr       r1,[sp,#-4]
    + 
    + 
    +-    ldr         r4,[sp,#40]                 @loads pi1_coeff
    +-    ldr         r8,[sp,#44]                 @loads ht
    +-    ldr         r10,[sp,#48]                @loads wd
    ++    ldr         r4,[sp,#coeff_offset]                 @loads pi1_coeff
    ++    ldr         r8,[sp,#ht_offset]                 @loads ht
    ++    ldr         r10,[sp,#wd_offset]                @loads wd
    + 
    +     vld1.8      {d0},[r4]                   @coeff = vld1_s8(pi1_coeff)
    +     mov         r11,#1
    +@@ -262,7 +267,8 @@ end_inner_loop_8:
    + 
    + 
    + 
    +-    ldr         r10,[sp,#48]                @loads wd
    ++    ldr         r10,[sp,#wd_offset]                @loads wd
    ++
    +     cmp         r10,#12
    + 
    +     beq         outer_loop4_residual
    +@@ -270,6 +276,7 @@ end_inner_loop_8:
    + 
    + end_loops:
    + 
    ++    vpop         {d8 - d15}
    +     ldmfd       sp!,{r4-r12,r15}            @reload the registers from sp
    + 
    + 
    +@@ -417,7 +424,7 @@ epilog_16:
    + 
    +     ldr         r7, [sp], #4
    +     ldr         r0, [sp], #4
    +-    ldr         r10,[sp,#48]
    ++    ldr         r10,[sp,#wd_offset]
    +     cmp         r10,#24
    + 
    +     beq         outer_loop8_residual
    +@@ -426,6 +433,7 @@ epilog_16:
    + 
    + end_loops1:
    + 
    ++    vpop         {d8 - d15}
    +     ldmfd       sp!,{r4-r12,r15}            @reload the registers from sp
    + 
    + 
    +@@ -527,6 +535,7 @@ end_inner_loop_4:
    +     @subs   r7,r7,#1
    +     @ bgt   start_loop_count
    + 
    ++    vpop         {d8 - d15}
    +     ldmfd       sp!,{r4-r12,r15}            @reload the registers from sp
    + 
    + 
    +diff --git a/common/arm/ihevc_inter_pred_filters_luma_vert.s b/common/arm/ihevc_inter_pred_filters_luma_vert.s
    +index f51d68c..3d9ab1c 100644
    +--- a/common/arm/ihevc_inter_pred_filters_luma_vert.s
    ++++ b/common/arm/ihevc_inter_pred_filters_luma_vert.s
    +@@ -103,6 +103,11 @@
    + @   r12 => *pi1_coeff
    + @   r5 =>  ht
    + @   r3 =>  wd
    ++
    ++.equ    coeff_offset,   104
    ++.equ    ht_offset,      108
    ++.equ    wd_offset,      112
    ++
    + .text
    + .align 4
    + .syntax unified
    +@@ -116,15 +121,16 @@
    + ihevc_inter_pred_luma_vert_a9q:
    + 
    +     stmfd       sp!, {r4-r12, r14}          @stack stores the values of the arguments
    ++    vpush        {d8 - d15}
    + 
    +-    ldr         r12,[sp,#40]                @load pi1_coeff
    ++    ldr         r12,[sp,#coeff_offset]                @load pi1_coeff
    +     mov         r6,r3
    +-    ldr         r5,[sp,#48]                 @load wd
    ++    ldr         r5,[sp,#wd_offset]                 @load wd
    +     vld1.u8     {d0},[r12]                  @coeff = vld1_s8(pi1_coeff)
    +     sub         r12,r2,r2,lsl #2            @src_ctrd & pi1_coeff
    +     vabs.s8     d0,d0                       @vabs_s8(coeff)
    +     add         r0,r0,r12                   @r0->pu1_src    r12->pi1_coeff
    +-    ldr         r3,[sp,#44]                 @load ht
    ++    ldr         r3,[sp,#ht_offset]                 @load ht
    +     subs        r7,r3,#0                    @r3->ht
    +     @ble        end_loops           @end loop jump
    +     vdup.u8     d22,d0[0]                   @coeffabs_0 = vdup_lane_u8(coeffabs, 0)@
    +@@ -407,7 +413,8 @@ end_loops:
    +     ldr         r1, [sp], #4
    +     ldr         r0, [sp], #4
    + 
    +-    ldmfdeq     sp!,{r4-r12,r15}            @reload the registers from sp
    ++    beq         end1
    ++
    +     mov         r5, #4
    +     add         r0, r0, #8
    +     add         r1, r1, #8
    +@@ -491,6 +498,8 @@ end_inner_loop_wd_4:
    +     add         r0,r0,r8
    +     bgt         outer_loop_wd_4
    + 
    ++end1:
    ++    vpop         {d8 - d15}
    +     ldmfd       sp!, {r4-r12, r15}          @reload the registers from sp
    + 
    + 
    +@@ -564,15 +573,16 @@ end_inner_loop_wd_4:
    + ihevc_inter_pred_luma_vert_w16out_a9q:
    + 
    +     stmfd       sp!, {r4-r12, r14}          @stack stores the values of the arguments
    ++    vpush        {d8 - d15}
    + 
    +-    ldr         r12,[sp,#40]                @load pi1_coeff
    ++    ldr         r12,[sp,#coeff_offset]                @load pi1_coeff
    +     mov         r6,r3
    +-    ldr         r5,[sp,#48]                 @load wd
    ++    ldr         r5,[sp,#wd_offset]                 @load wd
    +     vld1.u8     {d0},[r12]                  @coeff = vld1_s8(pi1_coeff)
    +     sub         r12,r2,r2,lsl #2            @src_ctrd & pi1_coeff
    +     vabs.s8     d0,d0                       @vabs_s8(coeff)
    +     add         r0,r0,r12                   @r0->pu1_src    r12->pi1_coeff
    +-    ldr         r3,[sp,#44]                 @load ht
    ++    ldr         r3,[sp,#ht_offset]                 @load ht
    +     subs        r7,r3,#0                    @r3->ht
    +     @ble        end_loops_16out         @end loop jump
    +     vdup.u8     d22,d0[0]                   @coeffabs_0 = vdup_lane_u8(coeffabs, 0)@
    +@@ -848,7 +858,8 @@ end_loops_16out:
    +     ldr         r1, [sp], #4
    +     ldr         r0, [sp], #4
    + 
    +-    ldmfdeq     sp!,{r4-r12,r15}            @reload the registers from sp
    ++    beq         end2
    ++
    +     mov         r5, #4
    +     add         r0, r0, #8
    +     add         r1, r1, #16
    +@@ -934,7 +945,8 @@ end_inner_loop_wd_4_16out:
    +     add         r1,r1,r9,lsl #1
    +     add         r0,r0,r8
    +     bgt         outer_loop_wd_4_16out
    +-
    ++end2:
    ++    vpop         {d8 - d15}
    +     ldmfd       sp!, {r4-r12, r15}          @reload the registers from sp
    + 
    + 
    +diff --git a/common/arm/ihevc_inter_pred_filters_luma_vert_w16inp.s b/common/arm/ihevc_inter_pred_filters_luma_vert_w16inp.s
    +index 4fbc5d1..9726710 100644
    +--- a/common/arm/ihevc_inter_pred_filters_luma_vert_w16inp.s
    ++++ b/common/arm/ihevc_inter_pred_filters_luma_vert_w16inp.s
    +@@ -94,6 +94,10 @@
    + @                                    word32 ht,
    + @                                    word32 wd   )
    + 
    ++.equ    coeff_offset,   104
    ++.equ    ht_offset,      108
    ++.equ    wd_offset,      112
    ++
    + .text
    + .align 4
    + 
    +@@ -107,16 +111,17 @@
    + ihevc_inter_pred_luma_vert_w16inp_a9q:
    + 
    +     stmfd       sp!, {r4-r12, r14}          @stack stores the values of the arguments
    ++    vpush        {d8 - d15}
    + 
    +-    ldr         r12,[sp,#40]                @load pi1_coeff
    ++    ldr         r12,[sp,#coeff_offset]                @load pi1_coeff
    +     mov         r6,r3
    +-    ldr         r5,[sp,#48]                 @load wd
    ++    ldr         r5,[sp,#wd_offset]                 @load wd
    +     vld1.8      {d0},[r12]                  @coeff = vld1_s8(pi1_coeff)
    +     mov         r2, r2, lsl #1
    +     sub         r12,r2,r2,lsl #2            @src_ctrd & pi1_coeff
    +     @vabs.s8    d0,d0               @vabs_s8(coeff)
    +     add         r0,r0,r12                   @r0->pu1_src    r12->pi1_coeff
    +-    ldr         r3,[sp,#44]                 @load ht
    ++    ldr         r3,[sp,#ht_offset]                 @load ht
    +     subs        r7,r3,#0                    @r3->ht
    +     @ble        end_loops           @end loop jump
    +     vmovl.s8    q0,d0
    +@@ -370,6 +375,7 @@ epilog_end:
    + 
    + end_loops:
    + 
    ++    vpop         {d8 - d15}
    +     ldmfd       sp!,{r4-r12,r15}            @reload the registers from sp
    + 
    + 
    +diff --git a/common/arm/ihevc_inter_pred_luma_copy.s b/common/arm/ihevc_inter_pred_luma_copy.s
    +index 8a61369..e4f5573 100644
    +--- a/common/arm/ihevc_inter_pred_luma_copy.s
    ++++ b/common/arm/ihevc_inter_pred_luma_copy.s
    +@@ -71,6 +71,10 @@
    + @   r7 =>  ht
    + @   r12 => wd
    + 
    ++.equ    coeff_offset,   104
    ++.equ    ht_offset,      108
    ++.equ    wd_offset,      112
    ++
    + .text
    + .align 4
    + 
    +@@ -83,8 +87,9 @@
    + 
    + ihevc_inter_pred_luma_copy_a9q:
    +     stmfd       sp!, {r4-r12, r14}          @stack stores the values of the arguments
    +-    ldr         r12,[sp,#48]                @loads wd
    +-    ldr         r7,[sp,#44]                 @loads ht
    ++    vpush        {d8 - d15}
    ++    ldr         r12,[sp,#wd_offset]                @loads wd
    ++    ldr         r7,[sp,#ht_offset]                 @loads ht
    +     cmp         r7,#0                       @checks ht == 0
    +     ble         end_loops
    +     tst         r12,#15                     @checks wd for multiples for 4 & 8
    +@@ -121,6 +126,7 @@ end_inner_loop_wd_4:
    +     bgt         outer_loop_wd_4
    + 
    + end_loops:
    ++    vpop         {d8 - d15}
    +     ldmfd       sp!,{r4-r12,r15}            @reload the registers from sp
    + 
    + 
    +@@ -151,6 +157,7 @@ end_inner_loop_wd_8:
    +     sub         r1,r6,r11                   @pu1_dst = pu1_dst_tmp
    +     bgt         outer_loop_wd_8
    + 
    ++    vpop         {d8 - d15}
    +     ldmfd       sp!,{r4-r12,r15}            @reload the registers from sp
    + 
    + core_loop_wd_16:
    +@@ -180,6 +187,7 @@ end_inner_loop_wd_16:
    +     sub         r1,r6,r11                   @pu1_dst = pu1_dst_tmp
    +     bgt         outer_loop_wd_16
    + 
    ++    vpop         {d8 - d15}
    +     ldmfd       sp!,{r4-r12,r15}            @reload the registers from sp
    + 
    + 
    +diff --git a/common/arm/ihevc_inter_pred_luma_copy_w16out.s b/common/arm/ihevc_inter_pred_luma_copy_w16out.s
    +index 771bcb3..84dbbad 100644
    +--- a/common/arm/ihevc_inter_pred_luma_copy_w16out.s
    ++++ b/common/arm/ihevc_inter_pred_luma_copy_w16out.s
    +@@ -72,6 +72,10 @@
    + @   r7 =>  ht
    + @   r12 => wd
    + 
    ++.equ    coeff_offset,   104
    ++.equ    ht_offset,      108
    ++.equ    wd_offset,      112
    ++
    + .text
    + .align 4
    + 
    +@@ -85,8 +89,9 @@
    + ihevc_inter_pred_luma_copy_w16out_a9q:
    + 
    +     stmfd       sp!, {r4-r12, r14}          @stack stores the values of the arguments
    +-    ldr         r12,[sp,#48]                @loads wd
    +-    ldr         r7,[sp,#44]                 @loads ht
    ++    vpush        {d8 - d15}
    ++    ldr         r12,[sp,#wd_offset]                @loads wd
    ++    ldr         r7,[sp,#ht_offset]                 @loads ht
    +     cmp         r7,#0                       @ht condition(ht == 0)
    +     ble         end_loops                   @loop
    +     tst         r12,#7                      @conditional check for wd (multiples)
    +@@ -129,6 +134,7 @@ end_inner_loop_wd_4:
    +     bgt         outer_loop_wd_4
    + 
    + end_loops:
    ++    vpop         {d8 - d15}
    +     ldmfd       sp!,{r4-r12,r15}            @reload the registers from sp
    + 
    + 
    +@@ -242,6 +248,7 @@ epilog_end:
    +     vst1.16     {d6,d7},[r10],r5            @vst1q_s16(pi2_dst_tmp, tmp)
    + 
    + 
    ++    vpop         {d8 - d15}
    +     ldmfd       sp!,{r4-r12,r15}            @reload the registers from sp
    + 
    + 
    +diff --git a/common/arm/ihevc_inter_pred_luma_horz_w16out.s b/common/arm/ihevc_inter_pred_luma_horz_w16out.s
    +index e8800e0..a60bb08 100644
    +--- a/common/arm/ihevc_inter_pred_luma_horz_w16out.s
    ++++ b/common/arm/ihevc_inter_pred_luma_horz_w16out.s
    +@@ -107,6 +107,11 @@
    + @r11 - #1
    + @r12 - src_ptr1
    + @r14 - loop_counter
    ++
    ++.equ    coeff_offset,   104
    ++.equ    ht_offset,      108
    ++.equ    wd_offset,      112
    ++
    + .text
    + .align 4
    + .syntax unified
    +@@ -122,16 +127,16 @@ ihevc_inter_pred_luma_horz_w16out_a9q:
    + 
    +     bic         r14, #1                     @ clearing bit[0], so that it goes back to mode
    +     stmfd       sp!, {r4-r12, r14}          @stack stores the values of the arguments
    +-    ldr         r4,[sp,#40]                 @loads pi1_coeff
    +-    ldr         r7,[sp,#44]                 @loads ht
    ++    vpush       {d8 - d15}
    ++    ldr         r4,[sp,#coeff_offset]                 @loads pi1_coeff
    ++    ldr         r7,[sp,#ht_offset]                 @loads ht
    + 
    + 
    +     vld1.8      {d0},[r4]                   @coeff = vld1_s8(pi1_coeff)
    +     sub         r14,r7,#0                   @checks for ht == 0
    +     vabs.s8     d2,d0                       @vabs_s8(coeff)
    +     mov         r11,#1
    +-    @ble       end_loops
    +-    ldr         r10,[sp,#48]                @loads wd
    ++    ldr         r10,[sp,#wd_offset]                @loads wd
    +     vdup.8      d24,d2[0]                   @coeffabs_0 = vdup_lane_u8(coeffabs, 0)
    +     sub         r12,r0,#3                   @pu1_src - 3
    +     vdup.8      d25,d2[1]                   @coeffabs_1 = vdup_lane_u8(coeffabs, 1)
    +@@ -274,11 +279,10 @@ end_inner_loop_4:
    + 
    + height_residue_4:
    + 
    +-    ldr         r7,[sp,#44]                 @loads ht
    ++    ldr         r7,[sp,#ht_offset]                 @loads ht
    +     and         r7,r7,#1                    @calculating ht_residue ht_residue = (ht & 1)
    +     cmp         r7,#0
    +-    @beq        end_loops
    +-    ldmfdeq     sp!,{r4-r12,r15}            @reload the registers from sp
    ++    beq         end_loops
    + 
    + outer_loop_height_residue_4:
    + 
    +@@ -331,7 +335,7 @@ end_inner_loop_height_residue_4:
    +     add         r12,r12,r9                  @increment the input pointer src_strd-wd
    +     add         r1,r1,r8                    @increment the output pointer dst_strd-wd
    +     bgt         outer_loop_height_residue_4
    +-
    ++    vpop        {d8 - d15}
    +     ldmfd       sp!,{r4-r12,r15}            @reload the registers from sp
    + 
    + outer_loop8_residual:
    +@@ -427,18 +431,18 @@ end_inner_loop_8:
    + 
    + 
    + 
    +-    ldr         r10,[sp,#48]                @loads wd
    ++    ldr         r10,[sp,#wd_offset]                @loads wd
    +     cmp         r10,#12
    + 
    +     beq         outer_loop4_residual
    + 
    +-    ldr         r7,[sp,#44]                 @loads ht
    ++    ldr         r7,[sp,#ht_offset]                 @loads ht
    +     and         r7,r7,#1
    +     cmp         r7,#1
    +     beq         height_residue_4
    + 
    +-@end_loops
    + 
    ++    vpop        {d8 - d15}
    +     ldmfd       sp!,{r4-r12,r15}            @reload the registers from sp
    + 
    + 
    +@@ -452,7 +456,6 @@ outer_loop_16:
    +     add         r4,r12,r2                   @pu1_src + src_strd
    +     and         r0, r12, #31
    +     sub         r5,r10,#0                   @checks wd
    +-    @ble       end_loops1
    +     pld         [r12, r2, lsl #1]
    +     vld1.u32    {q0},[r12],r11              @vector load pu1_src
    +     pld         [r4, r2, lsl #1]
    +@@ -580,17 +583,17 @@ epilog_16:
    + 
    +     ldr         r7, [sp], #4
    +     ldr         r0, [sp], #4
    +-    ldr         r10,[sp,#48]
    ++    ldr         r10,[sp,#wd_offset]
    +     cmp         r10,#24
    +     beq         outer_loop8_residual
    +     add         r1,r6,r8,lsl #1
    +-    ldr         r7,[sp,#44]                 @loads ht
    ++    ldr         r7,[sp,#ht_offset]                 @loads ht
    +     and         r7,r7,#1
    +     cmp         r7,#1
    +     beq         height_residue_4
    + 
    +-end_loops1:
    +-
    ++end_loops:
    ++    vpop        {d8 - d15}
    +     ldmfd       sp!,{r4-r12,r15}            @reload the registers from sp
    + 
    + 
    +diff --git a/common/arm/ihevc_inter_pred_luma_vert_w16inp_w16out.s b/common/arm/ihevc_inter_pred_luma_vert_w16inp_w16out.s
    +index c6716fe..6e0f1ed 100644
    +--- a/common/arm/ihevc_inter_pred_luma_vert_w16inp_w16out.s
    ++++ b/common/arm/ihevc_inter_pred_luma_vert_w16inp_w16out.s
    +@@ -102,6 +102,10 @@
    + @   r5 =>  ht
    + @   r6 =>  wd
    + 
    ++.equ    coeff_offset,   104
    ++.equ    ht_offset,      108
    ++.equ    wd_offset,      112
    ++
    + .text
    + .align 4
    + 
    +@@ -115,16 +119,17 @@
    + ihevc_inter_pred_luma_vert_w16inp_w16out_a9q:
    + 
    +     stmfd       sp!, {r4-r12, r14}          @stack stores the values of the arguments
    ++    vpush        {d8 - d15}
    + 
    +-    ldr         r12,[sp,#40]                @load pi1_coeff
    ++    ldr         r12,[sp,#coeff_offset]                @load pi1_coeff
    +     mov         r6,r3,lsl #1
    +-    ldr         r5,[sp,#48]                 @load wd
    ++    ldr         r5,[sp,#wd_offset]                 @load wd
    +     vld1.8      {d0},[r12]                  @coeff = vld1_s8(pi1_coeff)
    +     mov         r2, r2, lsl #1
    +     sub         r12,r2,r2,lsl #2            @src_ctrd & pi1_coeff
    +     @vabs.s8    d0,d0               @vabs_s8(coeff)
    +     add         r0,r0,r12                   @r0->pu1_src    r12->pi1_coeff
    +-    ldr         r3,[sp,#44]                 @load ht
    ++    ldr         r3,[sp,#ht_offset]                 @load ht
    +     subs        r7,r3,#0                    @r3->ht
    +     @ble        end_loops           @end loop jump
    +     vmovl.s8    q0,d0
    +@@ -393,6 +398,7 @@ epilog_end:
    + 
    + end_loops:
    + 
    ++    vpop         {d8 - d15}
    +     ldmfd       sp!,{r4-r12,r15}            @reload the registers from sp
    + 
    + 
    +diff --git a/common/arm/ihevc_intra_pred_chroma_dc.s b/common/arm/ihevc_intra_pred_chroma_dc.s
    +index 72d9730..6e5900a 100644
    +--- a/common/arm/ihevc_intra_pred_chroma_dc.s
    ++++ b/common/arm/ihevc_intra_pred_chroma_dc.s
    +@@ -92,6 +92,8 @@
    + @   mode
    + @   pi1_coeff
    + 
    ++.equ    nt_offset,      40
    ++
    + .text
    + .align 4
    + 
    +@@ -106,7 +108,7 @@ ihevc_intra_pred_chroma_dc_a9q:
    + 
    +     stmfd       sp!, {r4-r12, r14}          @stack stores the values of the arguments
    + 
    +-    ldr         r4,[sp,#40]                 @loads nt
    ++    ldr         r4,[sp,#nt_offset]          @loads nt
    +     mov         r9, #0
    +     vmov        d17, r9, r9
    + 
    +diff --git a/common/arm/ihevc_intra_pred_chroma_horz.s b/common/arm/ihevc_intra_pred_chroma_horz.s
    +index 6089fd8..4512d72 100644
    +--- a/common/arm/ihevc_intra_pred_chroma_horz.s
    ++++ b/common/arm/ihevc_intra_pred_chroma_horz.s
    +@@ -84,6 +84,8 @@
    + @r2 => *pu1_dst
    + @r3 =>  dst_strd
    + 
    ++.equ    nt_offset,      104
    ++
    + .text
    + .align 4
    + 
    +@@ -97,8 +99,9 @@
    + ihevc_intra_pred_chroma_horz_a9q:
    + 
    +     stmfd       sp!, {r4-r12, r14}          @stack stores the values of the arguments
    ++    vpush       {d8 - d15}
    + 
    +-    ldr         r4,[sp,#40]                 @loads nt
    ++    ldr         r4,[sp,#nt_offset]          @loads nt
    + 
    +     lsl         r6,r4,#2                    @four_nt
    + 
    +@@ -187,6 +190,7 @@ core_loop_16:
    +     vst1.16     {q4},[r2],r3
    +     vst1.16     {q4},[r9],r3
    +     bgt         core_loop_16
    ++    vpop        {d8 - d15}
    +     ldmfd       sp!,{r4-r12,r15}            @reload the registers from sp
    +     b           endloop
    + 
    +@@ -263,6 +267,7 @@ core_loop_8:
    +     @vst1.8     {q5},[r2],r3
    +     @vst1.8     {q6},[r2],r3
    +     @vst1.8     {q7},[r2],r3
    ++    vpop        {d8 - d15}
    + 
    +     ldmfd       sp!,{r4-r12,r15}            @reload the registers from sp
    +     b           endloop
    +@@ -308,6 +313,7 @@ core_loop_4:
    + 
    +     @vst1.8     {d8},[r2],r3
    +     @vst1.8     {d9},[r2],r3
    ++    vpop        {d8 - d15}
    +     ldmfd       sp!,{r4-r12,r15}            @reload the registers from sp
    +     b           endloop
    + 
    +@@ -339,6 +345,7 @@ core_loop_4:
    +     vst1.32     {d4[0]},[r2],r3
    +     vst1.32     {d5[0]},[r2],r3
    + 
    ++    vpop        {d8 - d15}
    +     ldmfd       sp!,{r4-r12,r15}            @reload the registers from sp
    + 
    + endloop:
    +diff --git a/common/arm/ihevc_intra_pred_chroma_mode2.s b/common/arm/ihevc_intra_pred_chroma_mode2.s
    +index cfa2ddb..013700d 100644
    +--- a/common/arm/ihevc_intra_pred_chroma_mode2.s
    ++++ b/common/arm/ihevc_intra_pred_chroma_mode2.s
    +@@ -87,11 +87,13 @@
    + @r2 => *pu1_dst
    + @r3 => dst_strd
    + 
    +-@stack contents from #40
    ++@stack contents from #104
    + @   nt
    + @   mode
    + @   pi1_coeff
    + 
    ++.equ    nt_offset,      104
    ++
    + .text
    + .align 4
    + 
    +@@ -105,8 +107,9 @@
    + ihevc_intra_pred_chroma_mode2_a9q:
    + 
    +     stmfd       sp!, {r4-r12, r14}          @stack stores the values of the arguments
    ++    vpush       {d8 - d15}
    + 
    +-    ldr         r4,[sp,#40]                 @loads nt
    ++    ldr         r4,[sp,#nt_offset]          @loads nt
    +     mov         r8,#-4
    + 
    +     cmp         r4,#4
    +@@ -290,6 +293,7 @@ mode2_4:
    +     vst1.8      {d6},[r2],r3
    + 
    + end_func:
    ++    vpop        {d8 - d15}
    +     ldmfd       sp!,{r4-r12,r15}            @reload the registers from sp
    + 
    + 
    +diff --git a/common/arm/ihevc_intra_pred_chroma_mode_18_34.s b/common/arm/ihevc_intra_pred_chroma_mode_18_34.s
    +index b0dd1fa..6af6450 100644
    +--- a/common/arm/ihevc_intra_pred_chroma_mode_18_34.s
    ++++ b/common/arm/ihevc_intra_pred_chroma_mode_18_34.s
    +@@ -87,11 +87,14 @@
    + @r2 => *pu1_dst
    + @r3 => dst_strd
    + 
    +-@stack contents from #40
    ++@stack contents from #104
    + @   nt
    + @   mode
    + @   pi1_coeff
    + 
    ++.equ    nt_offset,          104
    ++.equ    mode_offset,        108
    ++
    + .text
    + .align 4
    + 
    +@@ -105,10 +108,10 @@
    + ihevc_intra_pred_chroma_mode_18_34_a9q:
    + 
    +     stmfd       sp!, {r4-r12, r14}          @stack stores the values of the arguments
    ++    vpush       {d8 - d15}
    + 
    +-
    +-    ldr         r4,[sp,#40]
    +-    ldr         r5,[sp,#44]
    ++    ldr         r4,[sp,#nt_offset]
    ++    ldr         r5,[sp,#mode_offset]
    + 
    +     cmp         r4,#4
    +     beq         mode2_4
    +@@ -181,6 +184,7 @@ mode2_4:
    +     vst1.32     {d0},[r2],r3
    + 
    + end_func:
    ++    vpop        {d8 - d15}
    +     ldmfd       sp!,{r4-r12,r15}            @reload the registers from sp
    + 
    + 
    +diff --git a/common/arm/ihevc_intra_pred_chroma_mode_27_to_33.s b/common/arm/ihevc_intra_pred_chroma_mode_27_to_33.s
    +index fb75e96..21b54da 100644
    +--- a/common/arm/ihevc_intra_pred_chroma_mode_27_to_33.s
    ++++ b/common/arm/ihevc_intra_pred_chroma_mode_27_to_33.s
    +@@ -81,6 +81,9 @@
    + @                                         word32 nt,
    + @                                         word32 mode)
    + 
    ++.equ    nt_offset,          104
    ++.equ    mode_offset,        108
    ++
    + .text
    + .align 4
    + 
    +@@ -103,9 +106,10 @@ gau1_ihevc_planar_factor_addr:
    + ihevc_intra_pred_chroma_mode_27_to_33_a9q:
    + 
    +     stmfd       sp!, {r4-r12, r14}          @stack stores the values of the arguments
    ++    vpush        {d8 - d15}
    + 
    +-    ldr         r4,[sp,#40]                 @loads nt
    +-    ldr         r5,[sp,#44]                 @loads mode
    ++    ldr         r4,[sp,#nt_offset]                 @loads nt
    ++    ldr         r5,[sp,#mode_offset]                 @loads mode
    +     ldr         r6,gai4_ihevc_ang_table_addr @loads word32 gai4_ihevc_ang_table[35]
    + ulbl1:
    +     add         r6,r6,pc
    +@@ -535,6 +539,7 @@ core_loop_4:
    +     vst1.8      {d22},[r2],r3
    + 
    + end_loops:
    ++    vpop         {d8 - d15}
    +     ldmfd       sp!,{r4-r12,r15}            @reload the registers from sp
    + 
    + 
    +diff --git a/common/arm/ihevc_intra_pred_chroma_mode_3_to_9.s b/common/arm/ihevc_intra_pred_chroma_mode_3_to_9.s
    +index a5eb3ca..b7dcbfb 100644
    +--- a/common/arm/ihevc_intra_pred_chroma_mode_3_to_9.s
    ++++ b/common/arm/ihevc_intra_pred_chroma_mode_3_to_9.s
    +@@ -82,10 +82,13 @@
    + @r2 => *pu1_dst
    + @r3 => dst_strd
    + 
    +-@stack contents from #40
    ++@stack contents from #104
    + @   nt
    + @   mode
    + 
    ++.equ    nt_offset,          104
    ++.equ    mode_offset,        108
    ++
    + .text
    + .align 4
    + 
    +@@ -123,13 +126,14 @@ col_for_intra_chroma_addr_3:
    + ihevc_intra_pred_chroma_mode_3_to_9_a9q:
    + 
    +     stmfd       sp!, {r4-r12, r14}          @stack stores the values of the arguments
    ++    vpush       {d8 - d15}
    + 
    +-    ldr         r4,[sp,#40]                 @loads nt
    ++    ldr         r4,[sp,#nt_offset]          @loads nt
    +     ldr         r7, gai4_ihevc_ang_table_addr
    + ulbl1:
    +     add         r7,r7,pc
    + 
    +-    ldr         r5,[sp,#44]                 @mode (3 to 9)
    ++    ldr         r5,[sp,#mode_offset]        @mode (3 to 9)
    +     ldr         r8, gai4_ihevc_inv_ang_table_addr
    + ulbl2:
    +     add         r8,r8,pc
    +@@ -486,6 +490,7 @@ epil_8_16_32:
    +     vst1.8      d18, [r5], r3               @st (row 7)
    + 
    + end_func:
    ++    vpop        {d8 - d15}
    +     ldmfd       sp!,{r4-r12,r15}            @reload the registers from sp
    + 
    + 
    +diff --git a/common/arm/ihevc_intra_pred_chroma_planar.s b/common/arm/ihevc_intra_pred_chroma_planar.s
    +index 30b3144..7d03d55 100644
    +--- a/common/arm/ihevc_intra_pred_chroma_planar.s
    ++++ b/common/arm/ihevc_intra_pred_chroma_planar.s
    +@@ -87,11 +87,13 @@
    + @r2 => *pu1_dst
    + @r3 => dst_strd
    + 
    +-@stack contents from #40
    ++@stack contents from #104
    + @   nt
    + @   mode
    + @   pi1_coeff
    + 
    ++.equ    nt_offset,      104
    ++
    + .text
    + .align 4
    + 
    +@@ -109,8 +111,9 @@ gau1_ihevc_planar_factor_addr:
    + ihevc_intra_pred_chroma_planar_a9q:
    + 
    +     stmfd       sp!, {r4-r12, r14}          @stack stores the values of the arguments
    ++    vpush       {d8 - d15}
    + 
    +-    ldr         r4,[sp,#40]                 @loads nt
    ++    ldr         r4,[sp,#nt_offset]          @loads nt
    +     ldr         r11, gau1_ihevc_planar_factor_addr @loads table of coeffs
    + ulbl1:
    +     add         r11,r11,pc
    +@@ -353,6 +356,7 @@ loop_sz_4:
    +     bne         loop_sz_4
    + 
    + end_loop:
    ++    vpop        {d8 - d15}
    +     ldmfd       sp!,{r4-r12,r15}            @reload the registers from sp
    + 
    + 
    +diff --git a/common/arm/ihevc_intra_pred_chroma_ver.s b/common/arm/ihevc_intra_pred_chroma_ver.s
    +index b68a045..ce2ad73 100644
    +--- a/common/arm/ihevc_intra_pred_chroma_ver.s
    ++++ b/common/arm/ihevc_intra_pred_chroma_ver.s
    +@@ -87,6 +87,8 @@
    + @   nt
    + @   mode
    + 
    ++.equ    nt_offset,      40
    ++
    + .text
    + .align 4
    + 
    +@@ -101,7 +103,7 @@ ihevc_intra_pred_chroma_ver_a9q:
    + 
    +     stmfd       sp!, {r4-r12, r14}          @stack stores the values of the arguments
    + 
    +-    ldr         r4,[sp,#40]                 @loads nt
    ++    ldr         r4,[sp,#nt_offset]          @loads nt
    +     lsl         r5, r4, #2                  @4nt
    + 
    + 
    +diff --git a/common/arm/ihevc_intra_pred_filters_chroma_mode_11_to_17.s b/common/arm/ihevc_intra_pred_filters_chroma_mode_11_to_17.s
    +index 6c882cf..8644cc8 100644
    +--- a/common/arm/ihevc_intra_pred_filters_chroma_mode_11_to_17.s
    ++++ b/common/arm/ihevc_intra_pred_filters_chroma_mode_11_to_17.s
    +@@ -84,10 +84,13 @@
    + @r2 => *pu1_dst
    + @r3 => dst_strd
    + 
    +-@stack contents from #40
    ++@stack contents from #236
    + @   nt
    + @   mode
    + 
    ++.equ    nt_offset,      236
    ++.equ    mode_offset,    240
    ++
    + .text
    + .align 4
    + 
    +@@ -123,13 +126,15 @@ col_for_intra_chroma_addr_3:
    + ihevc_intra_pred_chroma_mode_11_to_17_a9q:
    + 
    +     stmfd       sp!, {r4-r12, r14}          @stack stores the values of the arguments
    ++    vpush        {d8 - d15}
    ++    sub         sp, sp, #132                @ref_temp[2 * max_cu_size + 2]
    + 
    +-    ldr         r4,[sp,#40]                 @loads nt
    ++    ldr         r4,[sp,#nt_offset]          @loads wd
    +     ldr         r7, gai4_ihevc_ang_table_addr
    + ulbl1:
    +     add         r7,r7,pc
    + 
    +-    ldr         r5,[sp,#44]                 @mode (11 to 17)
    ++    ldr         r5,[sp,#mode_offset]        @mode (11 to 17)
    +     ldr         r8, gai4_ihevc_inv_ang_table_addr
    + ulbl2:
    +     add         r8,r8,pc
    +@@ -139,7 +144,6 @@ ulbl2:
    +     sub         r8, r8, #44
    + 
    +     ldr         r7, [r7]                    @intra_pred_ang
    +-    sub         sp, sp, #132                @ref_temp[2 * max_cu_size + 2]
    + 
    +     ldr         r8, [r8]                    @inv_ang
    +     add         r6, sp, r4, lsl #1          @ref_temp + 2 * nt
    +@@ -607,6 +611,7 @@ epil_8_16_32:
    + 
    + end_func:
    +     add         sp, sp, #132
    ++    vpop        {d8 - d15}
    +     ldmfd       sp!,{r4-r12,r15}            @reload the registers from sp
    + 
    + 
    +diff --git a/common/arm/ihevc_intra_pred_filters_chroma_mode_19_to_25.s b/common/arm/ihevc_intra_pred_filters_chroma_mode_19_to_25.s
    +index 2ede914..a555646 100644
    +--- a/common/arm/ihevc_intra_pred_filters_chroma_mode_19_to_25.s
    ++++ b/common/arm/ihevc_intra_pred_filters_chroma_mode_19_to_25.s
    +@@ -84,10 +84,13 @@
    + @r2 => *pu1_dst
    + @r3 => dst_strd
    + 
    +-@stack contents from #40
    ++@stack contents from #236
    + @   nt
    + @   mode
    + 
    ++.equ    nt_offset,      236
    ++.equ    mode_offset,    240
    ++
    + .text
    + .align 4
    + 
    +@@ -116,13 +119,15 @@ gai4_ihevc_ang_table_addr_2:
    + ihevc_intra_pred_chroma_mode_19_to_25_a9q:
    + 
    +     stmfd       sp!, {r4-r12, r14}          @stack stores the values of the arguments
    ++    vpush       {d8 - d15}
    ++    sub         sp, sp, #132                @ref_temp[2 * max_cu_size + 2]
    + 
    +-    ldr         r4,[sp,#40]                 @loads nt
    ++    ldr         r4,[sp,#nt_offset]          @loads nt
    +     ldr         r7, gai4_ihevc_ang_table_addr_1
    + ulbl3:
    +     add         r7,r7,pc
    + 
    +-    ldr         r5,[sp,#44]                 @mode (19 to 25)
    ++    ldr         r5,[sp,#mode_offset]        @mode (19 to 25)
    +     ldr         r8, gai4_ihevc_inv_ang_table_addr
    + ulbl1:
    +     add         r8,r8,pc
    +@@ -132,7 +137,6 @@ ulbl1:
    +     sub         r8, r8, #48                 @gai4_ihevc_inv_ang_table[mode - 12]
    + 
    +     ldr         r7, [r7]                    @intra_pred_ang
    +-    sub         sp, sp, #132                @ref_temp[2 * max_cu_size + 2]
    + 
    +     ldr         r8, [r8]                    @inv_ang
    +     add         r6, sp, r4 , lsl #1         @ref_temp + 2 * nt
    +@@ -562,6 +566,7 @@ core_loop_4:
    + 
    + end_loops:
    +     add         sp, sp, #132
    ++    vpop        {d8 - d15}
    +     ldmfd       sp!,{r4-r12,r15}            @reload the registers from sp
    + 
    + 
    +diff --git a/common/arm/ihevc_intra_pred_filters_luma_mode_11_to_17.s b/common/arm/ihevc_intra_pred_filters_luma_mode_11_to_17.s
    +index ec38786..336af06 100644
    +--- a/common/arm/ihevc_intra_pred_filters_luma_mode_11_to_17.s
    ++++ b/common/arm/ihevc_intra_pred_filters_luma_mode_11_to_17.s
    +@@ -84,10 +84,13 @@
    + @r2 => *pu1_dst
    + @r3 => dst_strd
    + 
    +-@stack contents from #40
    ++@stack contents from #236
    + @   nt
    + @   mode
    + 
    ++.equ    nt_offset,      236
    ++.equ    mode_offset,    240
    ++
    + .text
    + .align 4
    + 
    +@@ -129,13 +132,14 @@ col_for_intra_luma_addr_4:
    + ihevc_intra_pred_luma_mode_11_to_17_a9q:
    + 
    +     stmfd       sp!, {r4-r12, r14}          @stack stores the values of the arguments
    +-
    +-    ldr         r4,[sp,#40]                 @loads nt
    ++    vpush       {d8 - d15}
    ++    sub         sp, sp, #132                @ref_temp[2 * max_cu_size + 1]
    ++    ldr         r4,[sp,#nt_offset]          @loads nt
    +     ldr         r7, gai4_ihevc_ang_table_addr
    + ulbl1:
    +     add         r7,r7,pc
    + 
    +-    ldr         r5,[sp,#44]                 @mode (11 to 17)
    ++    ldr         r5,[sp,#mode_offset]        @mode (11 to 17)
    +     ldr         r8, gai4_ihevc_inv_ang_table_addr
    + ulbl2:
    +     add         r8,r8,pc
    +@@ -145,7 +149,6 @@ ulbl2:
    +     sub         r8, r8, #44
    + 
    +     ldr         r7, [r7]                    @intra_pred_ang
    +-    sub         sp, sp, #132                @ref_temp[2 * max_cu_size + 1]
    + 
    +     ldr         r8, [r8]                    @inv_ang
    +     add         r6, sp, r4                  @ref_temp + nt
    +@@ -684,6 +687,7 @@ ulbl4:
    + 
    + end_func:
    +     add         sp, sp, #132
    ++    vpop        {d8 - d15}
    +     ldmfd       sp!,{r4-r12,r15}            @reload the registers from sp
    + 
    + 
    +diff --git a/common/arm/ihevc_intra_pred_filters_luma_mode_19_to_25.s b/common/arm/ihevc_intra_pred_filters_luma_mode_19_to_25.s
    +index af342bf..32268a2 100644
    +--- a/common/arm/ihevc_intra_pred_filters_luma_mode_19_to_25.s
    ++++ b/common/arm/ihevc_intra_pred_filters_luma_mode_19_to_25.s
    +@@ -84,10 +84,13 @@
    + @r2 => *pu1_dst
    + @r3 => dst_strd
    + 
    +-@stack contents from #40
    ++@stack contents from #236
    + @   nt
    + @   mode
    + 
    ++.equ    nt_offset,      236
    ++.equ    mode_offset,    240
    ++
    + .text
    + .align 4
    + 
    +@@ -116,13 +119,15 @@ gai4_ihevc_ang_table_addr_2:
    + ihevc_intra_pred_luma_mode_19_to_25_a9q:
    + 
    +     stmfd       sp!, {r4-r12, r14}          @stack stores the values of the arguments
    ++    vpush       {d8 - d15}
    ++    sub         sp, sp, #132                @ref_temp[2 * max_cu_size + 1]
    + 
    +-    ldr         r4,[sp,#40]                 @loads nt
    ++    ldr         r4,[sp,#nt_offset]          @loads nt
    +     ldr         r7, gai4_ihevc_ang_table_addr_1
    + ulbl_1:
    +     add         r7,r7,pc
    + 
    +-    ldr         r5,[sp,#44]                 @mode (19 to 25)
    ++    ldr         r5,[sp,#mode_offset]        @mode (19 to 25)
    +     ldr         r8, gai4_ihevc_inv_ang_table_addr
    + ulbl1:
    +     add         r8,r8,pc
    +@@ -132,7 +137,6 @@ ulbl1:
    +     sub         r8, r8, #48                 @gai4_ihevc_inv_ang_table[mode - 12]
    + 
    +     ldr         r7, [r7]                    @intra_pred_ang
    +-    sub         sp, sp, #132                @ref_temp[2 * max_cu_size + 1]
    + 
    +     ldr         r8, [r8]                    @inv_ang
    +     add         r6, sp, r4                  @ref_temp + nt
    +@@ -644,6 +648,7 @@ core_loop_4:
    + 
    + end_loops:
    +     add         sp, sp, #132
    ++    vpop        {d8 - d15}
    +     ldmfd       sp!,{r4-r12,r15}            @reload the registers from sp
    + 
    + 
    +diff --git a/common/arm/ihevc_intra_pred_luma_dc.s b/common/arm/ihevc_intra_pred_luma_dc.s
    +index f380d94..7d8cb91 100644
    +--- a/common/arm/ihevc_intra_pred_luma_dc.s
    ++++ b/common/arm/ihevc_intra_pred_luma_dc.s
    +@@ -87,11 +87,13 @@
    + @r2 => *pu1_dst
    + @r3 => dst_strd
    + 
    +-@stack contents from #40
    ++@stack contents from #104
    + @   nt
    + @   mode
    + @   pi1_coeff
    + 
    ++.equ    nt_offset,      104
    ++
    + .text
    + .align 4
    + 
    +@@ -105,8 +107,8 @@
    + ihevc_intra_pred_luma_dc_a9q:
    + 
    +     stmfd       sp!, {r4-r12, r14}          @stack stores the values of the arguments
    +-
    +-    ldr         r4,[sp,#40]                 @loads nt
    ++    vpush       {d8 - d15}
    ++    ldr         r4,[sp,#nt_offset]          @loads nt
    + 
    + @********** testing
    +     @mov        r6, #128
    +@@ -498,6 +500,7 @@ dc_4:
    + 
    + epilogue_end:
    + end_func:
    ++    vpop        {d8 - d15}
    +     ldmfd       sp!,{r4-r12,r15}            @reload the registers from sp
    + 
    + 
    +diff --git a/common/arm/ihevc_intra_pred_luma_horz.s b/common/arm/ihevc_intra_pred_luma_horz.s
    +index 581b673..2a44404 100644
    +--- a/common/arm/ihevc_intra_pred_luma_horz.s
    ++++ b/common/arm/ihevc_intra_pred_luma_horz.s
    +@@ -84,6 +84,8 @@
    + @r2 => *pu1_dst
    + @r3 =>  dst_strd
    + 
    ++.equ    nt_offset,      104
    ++
    + .text
    + .align 4
    + 
    +@@ -97,9 +99,8 @@
    + ihevc_intra_pred_luma_horz_a9q:
    + 
    +     stmfd       sp!, {r4-r12, r14}          @stack stores the values of the arguments
    +-
    +-    ldr         r4,[sp,#40]                 @loads nt
    +-    @ldr        r5,[sp,#44]                     @loads mode
    ++    vpush       {d8 - d15}
    ++    ldr         r4,[sp,#nt_offset]          @loads nt
    + 
    +     lsl         r6,r4,#1                    @two_nt
    + 
    +@@ -185,6 +186,7 @@ core_loop_32:
    +     vst1.8      {q4},[r2],r3
    +     vst1.8      {q4},[r9],r3
    +     bgt         core_loop_32
    ++    vpop        {d8 - d15}
    +     ldmfd       sp!,{r4-r12,r15}            @reload the registers from sp
    +     b           end_func
    + 
    +@@ -258,7 +260,7 @@ core_loop_16:
    +     vst1.8      {q5},[r2],r3
    +     vst1.8      {q6},[r2],r3
    +     vst1.8      {q7},[r2],r3
    +-
    ++    vpop        {d8 - d15}
    +     ldmfd       sp!,{r4-r12,r15}            @reload the registers from sp
    +     b           end_func
    + 
    +@@ -301,6 +303,7 @@ core_loop_8:
    + 
    +     vst1.8      {d8},[r2],r3
    +     vst1.8      {d9},[r2],r3
    ++    vpop        {d8 - d15}
    +     ldmfd       sp!,{r4-r12,r15}            @reload the registers from sp
    +     b           end_func
    + 
    +@@ -331,7 +334,7 @@ core_loop_4:
    +     vst1.32     {d3[0]},[r2],r3
    +     vst1.32     {d4[0]},[r2],r3
    +     vst1.32     {d5[0]},[r2],r3
    +-
    ++    vpop        {d8 - d15}
    +     ldmfd       sp!,{r4-r12,r15}            @reload the registers from sp
    + end_func:
    + 
    +diff --git a/common/arm/ihevc_intra_pred_luma_mode2.s b/common/arm/ihevc_intra_pred_luma_mode2.s
    +index cf7999b..935f02d 100644
    +--- a/common/arm/ihevc_intra_pred_luma_mode2.s
    ++++ b/common/arm/ihevc_intra_pred_luma_mode2.s
    +@@ -87,11 +87,13 @@
    + @r2 => *pu1_dst
    + @r3 => dst_strd
    + 
    +-@stack contents from #40
    ++@stack contents from #104
    + @   nt
    + @   mode
    + @   pi1_coeff
    + 
    ++.equ    nt_offset,      104
    ++
    + .text
    + .align 4
    + 
    +@@ -105,8 +107,8 @@
    + ihevc_intra_pred_luma_mode2_a9q:
    + 
    +     stmfd       sp!, {r4-r12, r14}          @stack stores the values of the arguments
    +-
    +-    ldr         r4,[sp,#40]                 @loads nt
    ++    vpush       {d8 - d15}
    ++    ldr         r4,[sp,#nt_offset]          @loads nt
    +     mov         r8,#-2
    + 
    +     cmp         r4,#4
    +@@ -260,6 +262,7 @@ mode2_4:
    +     vst1.32     {d7[0]},[r7]
    + 
    + end_func:
    ++    vpop        {d8 - d15}
    +     ldmfd       sp!,{r4-r12,r15}            @reload the registers from sp
    + 
    + 
    +diff --git a/common/arm/ihevc_intra_pred_luma_mode_18_34.s b/common/arm/ihevc_intra_pred_luma_mode_18_34.s
    +index 438c0f5..9287371 100644
    +--- a/common/arm/ihevc_intra_pred_luma_mode_18_34.s
    ++++ b/common/arm/ihevc_intra_pred_luma_mode_18_34.s
    +@@ -92,6 +92,9 @@
    + @   mode
    + @   pi1_coeff
    + 
    ++.equ    nt_offset,      40
    ++.equ    mode_offset,    44
    ++
    + .text
    + .align 4
    + 
    +@@ -107,8 +110,8 @@ ihevc_intra_pred_luma_mode_18_34_a9q:
    +     stmfd       sp!, {r4-r12, r14}          @stack stores the values of the arguments
    + 
    + 
    +-    ldr         r4,[sp,#40]
    +-    ldr         r5,[sp,#44]
    ++    ldr         r4,[sp,#nt_offset]
    ++    ldr         r5,[sp,#mode_offset]
    + 
    +     cmp         r4,#4
    +     beq         mode2_4
    +diff --git a/common/arm/ihevc_intra_pred_luma_mode_27_to_33.s b/common/arm/ihevc_intra_pred_luma_mode_27_to_33.s
    +index 595d82a..9d95719 100644
    +--- a/common/arm/ihevc_intra_pred_luma_mode_27_to_33.s
    ++++ b/common/arm/ihevc_intra_pred_luma_mode_27_to_33.s
    +@@ -85,6 +85,9 @@
    + @r2 => *pu1_dst
    + @r3 =>  dst_strd
    + 
    ++.equ    nt_offset,      104
    ++.equ    mode_offset,    108
    ++
    + .text
    + .align 4
    + 
    +@@ -107,9 +110,9 @@ gau1_ihevc_planar_factor_addr:
    + ihevc_intra_pred_luma_mode_27_to_33_a9q:
    + 
    +     stmfd       sp!, {r4-r12, r14}          @stack stores the values of the arguments
    +-
    +-    ldr         r4,[sp,#40]                 @loads nt
    +-    ldr         r5,[sp,#44]                 @loads mode
    ++    vpush       {d8 - d15}
    ++    ldr         r4,[sp,#nt_offset]          @loads nt
    ++    ldr         r5,[sp,#mode_offset]        @loads mode
    +     ldr         r6,gai4_ihevc_ang_table_addr @loads word32 gai4_ihevc_ang_table[35]
    + ulbl1:
    +     add         r6,r6,pc
    +@@ -534,6 +537,7 @@ core_loop_4:
    +     vst1.32     {d22[0]},[r2],r3
    + 
    + end_loops:
    ++    vpop        {d8 - d15}
    +     ldmfd       sp!,{r4-r12,r15}            @reload the registers from sp
    + 
    + 
    +diff --git a/common/arm/ihevc_intra_pred_luma_mode_3_to_9.s b/common/arm/ihevc_intra_pred_luma_mode_3_to_9.s
    +index a8e93c8..e9c871c 100644
    +--- a/common/arm/ihevc_intra_pred_luma_mode_3_to_9.s
    ++++ b/common/arm/ihevc_intra_pred_luma_mode_3_to_9.s
    +@@ -84,10 +84,13 @@
    + @r2 => *pu1_dst
    + @r3 => dst_strd
    + 
    +-@stack contents from #40
    ++@stack contents from #104
    + @   nt
    + @   mode
    + 
    ++.equ    nt_offset,      104
    ++.equ    mode_offset,    108
    ++
    + .text
    + .align 4
    + 
    +@@ -126,13 +129,13 @@ col_for_intra_luma_addr_3:
    + ihevc_intra_pred_luma_mode_3_to_9_a9q:
    + 
    +     stmfd       sp!, {r4-r12, r14}          @stack stores the values of the arguments
    +-
    +-    ldr         r4,[sp,#40]                 @loads nt
    ++    vpush       {d8 - d15}
    ++    ldr         r4,[sp,#nt_offset]          @loads nt
    +     ldr         r7, gai4_ihevc_ang_table_addr
    + ulbl1:
    +     add         r7,r7,pc
    + 
    +-    ldr         r5,[sp,#44]                 @mode (3 to 9)
    ++    ldr         r5,[sp,#mode_offset]        @mode (3 to 9)
    +     ldr         r8, gai4_ihevc_inv_ang_table_addr
    + ulbl2:
    +     add         r8,r8,pc
    +@@ -566,6 +569,7 @@ ulbl3_2:
    +     vst1.32     d18[0], [r2], r3            @st (row 3)
    + 
    + end_func:
    ++    vpop        {d8 - d15}
    +     ldmfd       sp!,{r4-r12,r15}            @reload the registers from sp
    + 
    + 
    +diff --git a/common/arm/ihevc_intra_pred_luma_planar.s b/common/arm/ihevc_intra_pred_luma_planar.s
    +index 666798e..50b6b1b 100644
    +--- a/common/arm/ihevc_intra_pred_luma_planar.s
    ++++ b/common/arm/ihevc_intra_pred_luma_planar.s
    +@@ -87,11 +87,13 @@
    + @r2 => *pu1_dst
    + @r3 => dst_strd
    + 
    +-@stack contents from #40
    ++@stack contents from #104
    + @   nt
    + @   mode
    + @   pi1_coeff
    + 
    ++.equ    nt_offset,      104
    ++
    + .text
    + .align 4
    + 
    +@@ -114,8 +116,8 @@ gau1_ihevc_planar_factor_1_addr:
    + ihevc_intra_pred_luma_planar_a9q:
    + 
    +     stmfd       sp!, {r4-r12, r14}          @stack stores the values of the arguments
    +-
    +-    ldr         r4,[sp,#40]                 @loads nt
    ++    vpush       {d8 - d15}
    ++    ldr         r4,[sp,#nt_offset]          @loads nt
    +     ldr         r11, gau1_ihevc_planar_factor_addr @loads table of coeffs
    + ulbl1:
    +     add         r11,r11,pc
    +@@ -546,6 +548,7 @@ loop_sz_4:
    +     bne         loop_sz_4
    + 
    + end_loop:
    ++    vpop        {d8 - d15}
    +     ldmfd       sp!,{r4-r12,r15}            @reload the registers from sp
    + 
    + 
    +diff --git a/common/arm/ihevc_intra_pred_luma_vert.s b/common/arm/ihevc_intra_pred_luma_vert.s
    +index 5eeaeb3..9610773 100644
    +--- a/common/arm/ihevc_intra_pred_luma_vert.s
    ++++ b/common/arm/ihevc_intra_pred_luma_vert.s
    +@@ -84,10 +84,12 @@
    + @r2 => *pu1_dst
    + @r3 => dst_strd
    + 
    +-@stack contents from #40
    ++@stack contents from #104
    + @   nt
    + @   mode
    + 
    ++.equ    nt_offset,      104
    ++
    + .text
    + .align 4
    + 
    +@@ -101,8 +103,8 @@
    + ihevc_intra_pred_luma_ver_a9q:
    + 
    +     stmfd       sp!, {r4-r12, r14}          @stack stores the values of the arguments
    +-
    +-    ldr         r4,[sp,#40]                 @loads nt
    ++    vpush       {d8 - d15}
    ++    ldr         r4,[sp,#nt_offset]          @loads nt
    + 
    +     lsl         r5, r4, #1                  @2nt
    + 
    +@@ -417,5 +419,6 @@ blk_4:
    + 
    + 
    + end_func:
    ++    vpop        {d8 - d15}
    +     ldmfd       sp!,{r4-r12,r15}            @reload the registers from sp
    + 
    +diff --git a/common/arm/ihevc_itrans_recon_16x16.s b/common/arm/ihevc_itrans_recon_16x16.s
    +index 82055ad..198fd52 100644
    +--- a/common/arm/ihevc_itrans_recon_16x16.s
    ++++ b/common/arm/ihevc_itrans_recon_16x16.s
    +@@ -105,6 +105,12 @@
    + @   r12
    + @   r11
    + 
    ++.equ    src_stride_offset,     104
    ++.equ    pred_stride_offset,    108
    ++.equ    out_stride_offset,     112
    ++.equ    zero_cols_offset,      116
    ++.equ    zero_rows_offset,      120
    ++
    + .text
    + .align 4
    + 
    +@@ -129,15 +135,10 @@ g_ai2_ihevc_trans_16_transpose_addr:
    + ihevc_itrans_recon_16x16_a9q:
    + 
    +     stmfd       sp!,{r4-r12,lr}
    +-@   add             sp,sp,#40
    +-
    +-
    +-
    +-@   ldr         r8,[sp,#4]  @ prediction stride
    +-@   ldr         r7,[sp,#8]  @ destination stride
    +-    ldr         r6,[sp,#40]                 @ src stride
    +-    ldr         r12,[sp,#52]
    +-    ldr         r11,[sp,#56]
    ++    vpush       {d8  -  d15}
    ++    ldr         r6,[sp,#src_stride_offset]  @ src stride
    ++    ldr         r12,[sp,#zero_cols_offset]
    ++    ldr         r11,[sp,#zero_rows_offset]
    + 
    + 
    + 
    +@@ -661,8 +662,8 @@ skip_last12rows_kernel2:
    + 
    +     mov         r6,r7
    + 
    +-    ldr         r8,[sp,#44]                 @ prediction stride
    +-    ldr         r7,[sp,#48]                 @ destination stride
    ++    ldr         r8,[sp,#pred_stride_offset] @ prediction stride
    ++    ldr         r7,[sp,#out_stride_offset]  @ destination stride
    + 
    +     mov         r10,#16
    + 
    +@@ -1126,7 +1127,7 @@ skip_last8rows_stage2_kernel2:
    +     bne         second_stage
    + 
    + 
    +-@   sub         sp,sp,#40
    ++    vpop        {d8  -  d15}
    +     ldmfd       sp!,{r4-r12,pc}
    + 
    + 
    +diff --git a/common/arm/ihevc_itrans_recon_32x32.s b/common/arm/ihevc_itrans_recon_32x32.s
    +index eeb1d66..65b6ffd 100644
    +--- a/common/arm/ihevc_itrans_recon_32x32.s
    ++++ b/common/arm/ihevc_itrans_recon_32x32.s
    +@@ -124,6 +124,14 @@
    + @d5[2]= 43      d7[2]=9
    + @d5[3]= 38      d7[3]=4
    + 
    ++.equ    pi2_src_offset,     64
    ++.equ    pi2_tmp_offset,     68
    ++.equ    src_strd_offset,    120
    ++.equ    pred_strd_offset,   124
    ++.equ    dst_strd_offset,    128
    ++.equ    zero_cols_offset,   132
    ++.equ    zero_rows_offset,   136
    ++
    + .text
    + .align 4
    + 
    +@@ -152,13 +160,11 @@ r9_addr: .word 0xffff0000
    + ihevc_itrans_recon_32x32_a9q:
    + 
    +     stmfd       sp!,{r0-r12,lr}
    ++    vpush       {d8  -  d15}
    + 
    +-
    +-@ldr            r8,[sp,#56]     @ prediction stride
    +-@ldr            r7,[sp,#64]     @ destination stride
    +-    ldr         r6,[sp,#56]                 @ src stride
    +-    ldr         r12,[sp,#68]
    +-    ldr         r11,[sp,#72]
    ++    ldr         r6,[sp,#src_strd_offset]    @ src stride
    ++    ldr         r12,[sp,#zero_cols_offset]
    ++    ldr         r11,[sp,#zero_rows_offset]
    +     mov         r6,r6,lsl #1                @ x sizeof(word16)
    +     add         r10,r6,r6, lsl #1           @ 3 rows
    + 
    +@@ -1493,10 +1499,10 @@ shift4:
    +     bne         dct_stage1
    + second_stage_dct:
    + @   mov     r0,r1
    +-    ldr         r0,[sp]
    +-    ldr         r1,[sp,#4]
    +-    ldr         r8,[sp,#60]                 @ prediction stride
    +-    ldr         r7,[sp,#64]                 @ destination stride
    ++    ldr         r0,[sp,#pi2_src_offset]
    ++    ldr         r1,[sp,#pi2_tmp_offset]
    ++    ldr         r8,[sp,#pred_strd_offset]   @ prediction stride
    ++    ldr         r7,[sp,#dst_strd_offset]    @ destination stride
    + 
    + @   add r4,r2,r8, lsl #1    @ r4 = r2 + pred_strd * 2    => r4 points to 3rd row of pred data
    + @   add r5,r8,r8, lsl #1    @
    +@@ -2855,6 +2861,7 @@ prediction_buffer:
    + 
    +     subs        r14,r14,#1
    +     bne         dct_stage2
    ++    vpop        {d8  -  d15}
    +     ldmfd       sp!,{r0-r12,pc}
    + 
    + 
    +diff --git a/common/arm/ihevc_itrans_recon_4x4.s b/common/arm/ihevc_itrans_recon_4x4.s
    +index c955502..fb5796c 100644
    +--- a/common/arm/ihevc_itrans_recon_4x4.s
    ++++ b/common/arm/ihevc_itrans_recon_4x4.s
    +@@ -100,6 +100,10 @@
    + @   r6 => dst_strd
    + @   r7 => zero_cols
    + 
    ++.equ    src_strd_offset,    104
    ++.equ    pred_strd_offset,   108
    ++.equ    dst_strd_offset,    112
    ++.equ    zero_cols_offset,   116
    + 
    + .text
    + .align 4
    +@@ -122,17 +126,18 @@ g_ai2_ihevc_trans_4_transpose_addr:
    + ihevc_itrans_recon_4x4_a9q:
    + 
    +     stmfd       sp!, {r4-r12, r14}          @stack stores the values of the arguments
    ++    vpush       {d8  -  d15}
    + 
    +     ldr         r8,g_ai2_ihevc_trans_4_transpose_addr
    + ulbl1:
    +     add         r8,r8,pc
    + 
    +-    ldr         r4,[sp,#40]                 @loading src_strd
    +-    ldr         r5,[sp,#44]                 @loading pred_strd
    ++    ldr         r4,[sp,#src_strd_offset]    @loading src_strd
    ++    ldr         r5,[sp,#pred_strd_offset]   @loading pred_strd
    +     add         r4,r4,r4                    @ src_strd in terms of word16
    + 
    +-    ldr         r6,[sp,#48]                 @loading dst_strd
    +-    ldr         r7,[sp,#52]                 @loading zero_cols
    ++    ldr         r6,[sp,#dst_strd_offset]    @loading dst_strd
    ++    ldr         r7,[sp,#zero_cols_offset]   @loading zero_cols
    +     add         r9,r0,r4                    @ pi2_src[0] + src_strd
    + 
    + 
    +@@ -223,7 +228,7 @@ ulbl1:
    +     vst1.32     {d1[0]},[r3],r6
    +     vst1.32     {d1[1]},[r3],r6
    + 
    +-
    ++    vpop        {d8  -  d15}
    +     ldmfd       sp!,{r4-r12,r15}            @reload the registers from sp
    + 
    + 
    +diff --git a/common/arm/ihevc_itrans_recon_4x4_ttype1.s b/common/arm/ihevc_itrans_recon_4x4_ttype1.s
    +index ab65dae..82ed8a0 100644
    +--- a/common/arm/ihevc_itrans_recon_4x4_ttype1.s
    ++++ b/common/arm/ihevc_itrans_recon_4x4_ttype1.s
    +@@ -103,6 +103,11 @@
    + @   r6 => dst_strd
    + @   r7 => zero_cols
    + 
    ++.equ    src_strd_offset,    104
    ++.equ    pred_strd_offset,   108
    ++.equ    dst_strd_offset,    112
    ++.equ    zero_cols_offset,   116
    ++
    + .text
    + .align 4
    + 
    +@@ -119,10 +124,12 @@
    + ihevc_itrans_recon_4x4_ttype1_a9q:
    + 
    +     stmfd       sp!, {r4-r12, r14}          @stack stores the values of the arguments
    +-    ldr         r4,[sp,#40]                 @loading src_strd
    +-    ldr         r5,[sp,#44]                 @loading pred_strd
    +-    ldr         r6,[sp,#48]                 @loading dst_strd
    +-    ldr         r7,[sp,#52]                 @loading zero_cols
    ++    vpush       {d8  -  d15}
    ++
    ++    ldr         r4,[sp,#src_strd_offset]    @loading src_strd
    ++    ldr         r5,[sp,#pred_strd_offset]   @loading pred_strd
    ++    ldr         r6,[sp,#dst_strd_offset]    @loading dst_strd
    ++    ldr         r7,[sp,#zero_cols_offset]   @loading zero_cols
    + 
    +     add         r4,r4,r4                    @ src_strd in terms of word16
    + 
    +@@ -224,6 +231,7 @@ ihevc_itrans_recon_4x4_ttype1_a9q:
    +     vst1.32     {d1[0]},[r3],r6
    +     vst1.32     {d1[1]},[r3],r6
    + 
    ++    vpop        {d8  -  d15}
    +     ldmfd       sp!,{r4-r12,r15}            @reload the registers from sp
    + 
    + 
    +diff --git a/common/arm/ihevc_itrans_recon_8x8.s b/common/arm/ihevc_itrans_recon_8x8.s
    +index e9b53b4..94113d8 100644
    +--- a/common/arm/ihevc_itrans_recon_8x8.s
    ++++ b/common/arm/ihevc_itrans_recon_8x8.s
    +@@ -104,6 +104,11 @@
    + @   dst_strd
    + @   zero_cols
    + 
    ++.equ    src_stride_offset,     104
    ++.equ    pred_stride_offset,    108
    ++.equ    out_stride_offset,     112
    ++.equ    zero_cols_offset,      116
    ++.equ    zero_rows_offset,      120
    + 
    + 
    + .text
    +@@ -151,12 +156,13 @@ ihevc_itrans_recon_8x8_a9q:
    +     @// copy the input pointer to another register
    +     @// step 1 : load all constants
    +     stmfd       sp!,{r4-r12,lr}
    ++    vpush       {d8  -  d15}
    + 
    +-    ldr         r8,[sp,#44]                  @ prediction stride
    +-    ldr         r7,[sp,#48]                  @ destination stride
    +-    ldr         r6,[sp, #40]                     @ src stride
    +-    ldr         r12,[sp,#52]
    +-    ldr         r11,[sp,#56]
    ++    ldr         r8, [sp, #pred_stride_offset]    @ prediction stride
    ++    ldr         r7, [sp, #out_stride_offset]     @ destination stride
    ++    ldr         r6, [sp, #src_stride_offset]     @ src stride
    ++    ldr         r12, [sp, #zero_cols_offset]
    ++    ldr         r11, [sp, #zero_rows_offset]
    +     mov         r6,r6,lsl #1                @ x sizeof(word16)
    +     add         r9,r0,r6, lsl #1            @ 2 rows
    + 
    +@@ -925,7 +931,7 @@ pred_buff_addition:
    + 
    + 
    + 
    +-
    ++    vpop        {d8  -  d15}
    +     ldmfd       sp!,{r4-r12,pc}
    + 
    + 
    +diff --git a/common/arm/ihevc_sao_band_offset_chroma.s b/common/arm/ihevc_sao_band_offset_chroma.s
    +index 32e149d..a9da725 100644
    +--- a/common/arm/ihevc_sao_band_offset_chroma.s
    ++++ b/common/arm/ihevc_sao_band_offset_chroma.s
    +@@ -61,6 +61,14 @@
    + @r9 =>  wd
    + @r10=>  ht
    + 
    ++.equ    pu1_src_top_left_offset,    104
    ++.equ    sao_band_pos_u_offset,      108
    ++.equ    sao_band_pos_v_offset,      112
    ++.equ    pi1_sao_u_offset,           116
    ++.equ    pi1_sao_v_offset,           120
    ++.equ    wd_offset,                  124
    ++.equ    ht_offset,                  128
    ++
    + .text
    + .p2align 2
    + 
    +@@ -76,10 +84,11 @@ gu1_table_band_idx_addr_2:
    + ihevc_sao_band_offset_chroma_a9q:
    + 
    +     STMFD       sp!, {r4-r12, r14}          @stack stores the values of the arguments
    +-    LDR         r4,[sp,#40]                 @Loads pu1_src_top_left
    +-    LDR         r10,[sp,#64]                @Loads ht
    ++    vpush       {d8  -  d15}
    ++    LDR         r4,[sp,#pu1_src_top_left_offset]    @Loads pu1_src_top_left
    ++    LDR         r10,[sp,#ht_offset]         @Loads ht
    + 
    +-    LDR         r9,[sp,#60]                 @Loads wd
    ++    LDR         r9,[sp,#wd_offset]          @Loads wd
    +     MOV         r11,r10                     @Move the ht to r9 for loop counter
    + 
    +     ADD         r12,r0,r9                   @pu1_src[row * src_strd + (wd)]
    +@@ -94,7 +103,7 @@ SRC_LEFT_LOOP:
    +     STRH        r5,[r2],#2                  @Store the value in pu1_src_left pointer
    +     BNE         SRC_LEFT_LOOP
    + 
    +-    LDR         r5,[sp,#44]                 @Loads sao_band_pos_u
    ++    LDR         r5,[sp,#sao_band_pos_u_offset]  @Loads sao_band_pos_u
    +     VLD1.8      D1,[r14]!                   @band_table_u.val[0]
    +     ADD         r12,r3,r9                   @pu1_src_top[wd]
    + 
    +@@ -104,7 +113,7 @@ SRC_LEFT_LOOP:
    + 
    +     STRH        r11,[r4]                    @store to pu1_src_top_left[0]
    +     VLD1.8      D3,[r14]!                   @band_table_u.val[2]
    +-    LDR         r7,[sp,#52]                 @Loads pi1_sao_offset_u
    ++    LDR         r7,[sp,#pi1_sao_u_offset]   @Loads pi1_sao_offset_u
    + 
    +     SUB         r4,r10,#1                   @ht-1
    +     VDUP.8      D31,r6                      @band_pos_u
    +@@ -147,7 +156,7 @@ ulbl2:
    +     VLD1.8      D10,[r14]!                  @band_table_v.val[1]
    +     VADD.I8     D3,D7,D27                   @band_table_u.val[2] = vadd_u8(band_table_u.val[2], vdup_n_u8(pi1_sao_offset_u[3]))
    + 
    +-    LDR         r6,[sp,#48]                 @Loads sao_band_pos_v
    ++    LDR         r6,[sp,#sao_band_pos_v_offset]  @Loads sao_band_pos_v
    +     VADD.I8     D4,D8,D26                   @band_table_u.val[3] = vadd_u8(band_table_u.val[3], vdup_n_u8(pi1_sao_offset_u[4]))
    +     LSL         r11,r6,#3                   @sao_band_pos_v
    + 
    +@@ -198,7 +207,7 @@ SAO_BAND_POS_U_0:
    + 
    + SWITCH_BREAK_U:
    +     VDUP.8      D30,r11                     @band_pos_v
    +-    LDR         r8,[sp,#56]                 @Loads pi1_sao_offset_v
    ++    LDR         r8,[sp,#pi1_sao_v_offset]   @Loads pi1_sao_offset_v
    + 
    +     VLD1.8      D11,[r14]!                  @band_table_v.val[2]
    +     VADD.I8     D13,D9,D30                  @band_table_v.val[0] = vadd_u8(band_table_v.val[0], band_pos_v)
    +@@ -387,6 +396,7 @@ WIDTH_RESIDUE:                              @If width is not multiple of 16
    +     BNE         WIDTH_RESIDUE
    + 
    + END_LOOP:
    ++    vpop        {d8  -  d15}
    +     LDMFD       sp!,{r4-r12,r15}            @Reload the registers from SP
    + 
    + 
    +diff --git a/common/arm/ihevc_sao_band_offset_luma.s b/common/arm/ihevc_sao_band_offset_luma.s
    +index 3875377..66f2968 100644
    +--- a/common/arm/ihevc_sao_band_offset_luma.s
    ++++ b/common/arm/ihevc_sao_band_offset_luma.s
    +@@ -57,6 +57,12 @@
    + @r7 =>  wd
    + @r8 =>  ht
    + 
    ++.equ    pu1_src_top_left_offset,    104
    ++.equ    sao_band_pos_offset,        108
    ++.equ    pi1_sao_offset,             112
    ++.equ    wd_offset,                  116
    ++.equ    ht_offset,                  120
    ++
    + .text
    + .p2align 2
    + 
    +@@ -69,15 +75,16 @@ gu1_table_band_idx_addr:
    + ihevc_sao_band_offset_luma_a9q:
    + 
    +     STMFD       sp!, {r4-r12, r14}          @stack stores the values of the arguments
    ++    vpush       {d8  -  d15}
    + 
    +-    LDR         r8,[sp,#56]                 @Loads ht
    +-    LDR         r7,[sp,#52]                 @Loads wd
    ++    LDR         r8,[sp,#ht_offset]          @Loads ht
    ++    LDR         r7,[sp,#wd_offset]          @Loads wd
    + 
    +     MOV         r9,r8                       @Move the ht to r9 for loop counter
    +-    LDR         r5,[sp,#44]                 @Loads sao_band_pos
    ++    LDR         r5,[sp,#sao_band_pos_offset]    @Loads sao_band_pos
    +     ADD         r10,r0,r7                   @pu1_src[row * src_strd + (wd)]
    + 
    +-    LDR         r4,[sp,#40]                 @Loads pu1_src_top_left
    ++    LDR         r4,[sp,#pu1_src_top_left_offset]    @Loads pu1_src_top_left
    +     SUB         r10,r10,#1                  @wd-1
    +     LDR         r14, gu1_table_band_idx_addr
    + ulbl1:
    +@@ -91,7 +98,7 @@ SRC_LEFT_LOOP:
    + 
    +     ADD         r9,r3,r7                    @pu1_src_top[wd]
    +     VLD1.8      D1,[r14]!                   @band_table.val[0]
    +-    LDR         r6,[sp,#48]                 @Loads pi1_sao_offset
    ++    LDR         r6,[sp,#pi1_sao_offset]     @Loads pi1_sao_offset
    + 
    +     LSL         r11,r5,#3
    +     VLD1.8      D2,[r14]!                   @band_table.val[1]
    +@@ -226,6 +233,7 @@ HEIGHT_LOOP:
    +     ADD         r0,r0,#8
    +     BNE         SWITCH_BREAK
    + 
    ++    vpop        {d8  -  d15}
    +     LDMFD       sp!,{r4-r12,r15}            @Reload the registers from SP
    + 
    + 
    +diff --git a/common/arm/ihevc_sao_edge_offset_class0.s b/common/arm/ihevc_sao_edge_offset_class0.s
    +index a9fe046..e4bb455 100644
    +--- a/common/arm/ihevc_sao_edge_offset_class0.s
    ++++ b/common/arm/ihevc_sao_edge_offset_class0.s
    +@@ -59,6 +59,14 @@
    + @r9 =>  wd
    + @r10=>  ht
    + 
    ++.equ    pu1_src_top_left_offset,    104
    ++.equ    pu1_src_top_right_offset,   108
    ++.equ    pu1_src_bot_left_offset,    112
    ++.equ    pu1_avail_offset,           116
    ++.equ    pi1_sao_offset,             120
    ++.equ    wd_offset,                  124
    ++.equ    ht_offset,                  128
    ++
    + .text
    + .p2align 2
    + 
    +@@ -72,23 +80,25 @@ ihevc_sao_edge_offset_class0_a9q:
    + 
    + 
    +     STMFD       sp!, {r4-r12, r14}          @stack stores the values of the arguments
    +-    LDR         r9,[sp,#60]                 @Loads wd
    ++    vpush       {d8  -  d15}
    ++
    ++    LDR         r9,[sp,#wd_offset]          @Loads wd
    + 
    +-    LDR         r4,[sp,#40]                 @Loads pu1_src_top_left
    ++    LDR         r4,[sp,#pu1_src_top_left_offset]    @Loads pu1_src_top_left
    +     VMOV.I8     Q1,#2                       @const_2 = vdupq_n_s8(2)
    +     ADD         r11,r3,r9                   @pu1_src_top[wd]
    + 
    +-    LDR         r10,[sp,#64]                @Loads ht
    ++    LDR         r10,[sp,#ht_offset]         @Loads ht
    +     VMOV.I16    Q2,#0                       @const_min_clip = vdupq_n_s16(0)
    +     LDRB        r12,[r11,#-1]               @pu1_src_top[wd - 1]
    + 
    +-    LDR         r7,[sp,#52]                 @Loads pu1_avail
    ++    LDR         r7,[sp,#pu1_avail_offset]   @Loads pu1_avail
    +     VMOV.I16    Q3,#255                     @const_max_clip = vdupq_n_u16((1 << bit_depth) - 1)
    +     LDR         r14, gi1_table_edge_idx_addr @table pointer
    + ulbl1:
    +     add         r14,r14,pc
    + 
    +-    LDR         r8,[sp,#56]                 @Loads pi1_sao_offset
    ++    LDR         r8,[sp,#pi1_sao_offset]     @Loads pi1_sao_offset
    +     VMOV.S8     Q4,#0xFF                    @au1_mask = vdupq_n_s8(-1)
    +     STRB        r12,[r4]                    @*pu1_src_top_left = pu1_src_top[wd - 1]
    + 
    +@@ -337,6 +347,7 @@ PU1_SRC_LOOP_RESIDUE:
    +     BNE         PU1_SRC_LOOP_RESIDUE        @If not equal jump to the pu1_src loop
    + 
    + END_LOOPS:
    ++    vpop        {d8  -  d15}
    +     LDMFD       sp!,{r4-r12,r15}            @Reload the registers from SP
    + 
    + 
    +diff --git a/common/arm/ihevc_sao_edge_offset_class0_chroma.s b/common/arm/ihevc_sao_edge_offset_class0_chroma.s
    +index 1dd56f6..e11cd4f 100644
    +--- a/common/arm/ihevc_sao_edge_offset_class0_chroma.s
    ++++ b/common/arm/ihevc_sao_edge_offset_class0_chroma.s
    +@@ -60,6 +60,15 @@
    + @r9 =>  wd
    + @r10=>  ht
    + 
    ++.equ    pu1_src_top_left_offset,    104
    ++.equ    pu1_src_top_right_offset,   108
    ++.equ    pu1_src_bot_left_offset,    112
    ++.equ    pu1_avail_offset,           116
    ++.equ    pi1_sao_u_offset,           120
    ++.equ    pi1_sao_v_offset,           124
    ++.equ    wd_offset,                  128
    ++.equ    ht_offset,                  132
    ++
    + .text
    + .p2align 2
    + 
    +@@ -73,20 +82,22 @@ ihevc_sao_edge_offset_class0_chroma_a9q:
    + 
    + 
    +     STMFD       sp!, {r4-r12, r14}          @stack stores the values of the arguments
    +-    LDR         r9,[sp,#64]                 @Loads wd
    ++    vpush       {d8  -  d15}
    ++
    ++    LDR         r9,[sp,#wd_offset]          @Loads wd
    + 
    +-    LDR         r4,[sp,#40]                 @Loads pu1_src_top_left
    ++    LDR         r4,[sp,#pu1_src_top_left_offset]    @Loads pu1_src_top_left
    +     ADD         r11,r3,r9                   @pu1_src_top[wd]
    + 
    +-    LDR         r10,[sp,#68]                @Loads ht
    ++    LDR         r10,[sp,#ht_offset]         @Loads ht
    +     VMOV.I8     Q1,#2                       @const_2 = vdupq_n_s8(2)
    +     LDRH        r12,[r11,#-2]               @pu1_src_top[wd - 1]
    + 
    +-    LDR         r7,[sp,#52]                 @Loads pu1_avail
    ++    LDR         r7,[sp,#pu1_avail_offset]   @Loads pu1_avail
    +     VMOV.I16    Q2,#0                       @const_min_clip = vdupq_n_s16(0)
    +     STRH        r12,[r4]                    @*pu1_src_top_left = pu1_src_top[wd - 1]
    + 
    +-    LDR         r8,[sp,#56]                 @Loads pi1_sao_offset_u
    ++    LDR         r8,[sp,#pi1_sao_u_offset]   @Loads pi1_sao_offset_u
    +     VMOV.I16    Q3,#255                     @const_max_clip = vdupq_n_u16((1 << bit_depth) - 1)
    +     SUB         r4,r10,#1                   @(ht - 1)
    + 
    +@@ -96,7 +107,7 @@ ulbl1:
    +     VMOV.S8     Q4,#0xFF                    @au1_mask = vdupq_n_s8(-1)
    +     MUL         r4,r4,r1                    @(ht - 1) * src_strd
    + 
    +-    LDR         r5,[sp,#60]                 @Loads pi1_sao_offset_v
    ++    LDR         r5,[sp,#pi1_sao_v_offset]   @Loads pi1_sao_offset_v
    +     VLD1.8      D11,[r8]                    @offset_tbl = vld1_s8(pi1_sao_offset_u)
    +     ADD         r4,r4,r0                    @pu1_src[(ht - 1) * src_strd]
    + 
    +@@ -423,6 +434,7 @@ PU1_SRC_LOOP_RESIDUE:
    +     BNE         PU1_SRC_LOOP_RESIDUE        @If not equal jump to the pu1_src loop
    + 
    + END_LOOPS:
    ++    vpop        {d8  -  d15}
    +     LDMFD       sp!,{r4-r12,r15}            @Reload the registers from SP
    + 
    + 
    +diff --git a/common/arm/ihevc_sao_edge_offset_class1.s b/common/arm/ihevc_sao_edge_offset_class1.s
    +index aa1337f..029ac46 100644
    +--- a/common/arm/ihevc_sao_edge_offset_class1.s
    ++++ b/common/arm/ihevc_sao_edge_offset_class1.s
    +@@ -58,6 +58,14 @@
    + @r7 =>  wd
    + @r8 =>  ht
    + 
    ++.equ    pu1_src_top_left_offset,    104
    ++.equ    pu1_src_top_right_offset,   108
    ++.equ    pu1_src_bot_left_offset,    112
    ++.equ    pu1_avail_offset,           116
    ++.equ    pi1_sao_offset,             120
    ++.equ    wd_offset,                  124
    ++.equ    ht_offset,                  128
    ++
    + .text
    + .p2align 2
    + 
    +@@ -71,11 +79,13 @@ ihevc_sao_edge_offset_class1_a9q:
    + 
    + 
    +     STMFD       sp!, {r4-r12, r14}          @stack stores the values of the arguments
    +-    LDR         r7,[sp,#60]                 @Loads wd
    +-    LDR         r4,[sp,#40]                 @Loads pu1_src_top_left
    +-    LDR         r5,[sp,#52]                 @Loads pu1_avail
    +-    LDR         r6,[sp,#56]                 @Loads pi1_sao_offset
    +-    LDR         r8,[sp,#64]                 @Loads ht
    ++    vpush       {d8  -  d15}
    ++
    ++    LDR         r7,[sp,#wd_offset]               @Loads wd
    ++    LDR         r4,[sp,#pu1_src_top_left_offset] @Loads pu1_src_top_left
    ++    LDR         r5,[sp,#pu1_avail_offset]        @Loads pu1_avail
    ++    LDR         r6,[sp,#pi1_sao_offset]          @Loads pi1_sao_offset
    ++    LDR         r8,[sp,#ht_offset]               @Loads ht
    + 
    +     SUB         r9,r7,#1                    @wd - 1
    +     LDRB        r10,[r3,r9]                 @pu1_src_top[wd - 1]
    +@@ -362,6 +372,7 @@ PU1_SRC_LOOP_RESIDUE:
    +     VST1.8      {D30},[r10],r1              @vst1q_u8(pu1_src_cpy, pu1_cur_row)
    + 
    + END_LOOPS:
    ++    vpop        {d8  -  d15}
    +     LDMFD       sp!,{r4-r12,r15}            @Reload the registers from SP
    + 
    + 
    +diff --git a/common/arm/ihevc_sao_edge_offset_class1_chroma.s b/common/arm/ihevc_sao_edge_offset_class1_chroma.s
    +index 09d925f..b377220 100644
    +--- a/common/arm/ihevc_sao_edge_offset_class1_chroma.s
    ++++ b/common/arm/ihevc_sao_edge_offset_class1_chroma.s
    +@@ -60,6 +60,15 @@
    + @r8 =>  wd
    + @r9 =>  ht
    + 
    ++.equ    pu1_src_top_left_offset,    104
    ++.equ    pu1_src_top_right_offset,   108
    ++.equ    pu1_src_bot_left_offset,    112
    ++.equ    pu1_avail_offset,           116
    ++.equ    pi1_sao_u_offset,           120
    ++.equ    pi1_sao_v_offset,           124
    ++.equ    wd_offset,                  128
    ++.equ    ht_offset,                  132
    ++
    + .text
    + .p2align 2
    + 
    +@@ -73,13 +82,13 @@ ihevc_sao_edge_offset_class1_chroma_a9q:
    + 
    + 
    +     STMFD       sp!, {r4-r12, r14}          @stack stores the values of the arguments
    +-    LDR         r7,[sp,#60]                 @Loads wd
    +-    LDR         r4,[sp,#40]                 @Loads pu1_src_top_left
    +-    LDR         r5,[sp,#52]                 @Loads pu1_avail
    +-    LDR         r6,[sp,#56]                 @Loads pi1_sao_offset_u
    +-    LDR         r7,[sp,#60]                 @Loads pi1_sao_offset_v
    +-    LDR         r8,[sp,#64]                 @Loads wd
    +-    LDR         r9,[sp,#68]                 @Loads ht
    ++    vpush       {d8  -  d15}
    ++    LDR         r4,[sp,#pu1_src_top_left_offset]    @Loads pu1_src_top_left
    ++    LDR         r5,[sp,#pu1_avail_offset]   @Loads pu1_avail
    ++    LDR         r6,[sp,#pi1_sao_u_offset]   @Loads pi1_sao_offset_u
    ++    LDR         r7,[sp,#pi1_sao_v_offset]   @Loads pi1_sao_offset_v
    ++    LDR         r8,[sp,#wd_offset]          @Loads wd
    ++    LDR         r9,[sp,#ht_offset]          @Loads ht
    + 
    +     SUB         r10,r8,#2                   @wd - 2
    +     LDRH        r11,[r3,r10]                @pu1_src_top[wd - 2]
    +@@ -398,6 +407,7 @@ PU1_SRC_LOOP_RESIDUE:
    +     VST1.8      {D30},[r10],r1              @vst1q_u8(pu1_src_cpy, pu1_cur_row)
    + 
    + END_LOOPS:
    ++    vpop        {d8  -  d15}
    +     LDMFD       sp!,{r4-r12,r15}            @Reload the registers from SP
    + 
    + 
    +diff --git a/common/arm/ihevc_sao_edge_offset_class2.s b/common/arm/ihevc_sao_edge_offset_class2.s
    +index 536f941..15d6efa 100644
    +--- a/common/arm/ihevc_sao_edge_offset_class2.s
    ++++ b/common/arm/ihevc_sao_edge_offset_class2.s
    +@@ -58,6 +58,14 @@
    + @r7 =>  wd
    + @r8=>   ht
    + 
    ++.equ    pu1_src_top_left_offset,    264
    ++.equ    pu1_src_top_right_offset,   268
    ++.equ    pu1_src_bot_left_offset,    272
    ++.equ    pu1_avail_offset,           276
    ++.equ    pi1_sao_offset,             280
    ++.equ    wd_offset,                  284
    ++.equ    ht_offset,                  288
    ++
    + .text
    + .syntax unified
    + .p2align 2
    +@@ -78,28 +86,29 @@ ihevc_sao_edge_offset_class2_a9q:
    + 
    + 
    +     STMFD       sp!,{r4-r12,r14}            @stack stores the values of the arguments
    +-    LDR         r7,[sp,#0x3C]               @Loads wd
    ++    vpush       {d8  -  d15}
    ++    SUB         sp,sp,#160                  @Decrement the stack pointer to store some temp arr values
    + 
    +-    LDR         r8,[sp,#0x40]               @Loads ht
    ++    LDR         r7,[sp,#wd_offset]          @Loads wd
    ++    LDR         r8,[sp,#ht_offset]          @Loads ht
    +     SUB         r9,r7,#1                    @wd - 1
    + 
    +-    LDR         r4,[sp,#0x28]               @Loads pu1_src_top_left
    ++    LDR         r4,[sp,#pu1_src_top_left_offset]    @Loads pu1_src_top_left
    +     LDRB        r10,[r3,r9]                 @pu1_src_top[wd - 1]
    + 
    +-    STR         r0,[sp,#0x2C]               @Store pu1_src in sp
    ++    STR         r0,[sp,#152]                @Store pu1_src in sp
    +     MOV         r9,r7                       @Move width to r9 for loop count
    + 
    +-    STR         r2,[sp,#0x30]               @Store pu1_src_left in sp
    +-    LDR         r5,[sp,#0x34]               @Loads pu1_avail
    +-    LDR         r6,[sp,#0x38]               @Loads pi1_sao_offset
    +-    STR         r3,[sp,#0x38]               @Store pu1_src_top in sp
    ++    STR         r2,[sp,#156]                @Store pu1_src_left in sp
    ++    LDR         r5,[sp,#pu1_avail_offset]   @Loads pu1_avail
    ++    LDR         r6,[sp,#pi1_sao_offset]     @Loads pi1_sao_offset
    ++    STR         r3,[sp,#148]                @Store pu1_src_top in sp
    + 
    +-    SUB         sp,sp,#0x94                 @Decrement the stack pointer to store some temp arr values
    + 
    +     STRB        r10,[sp]                    @u1_src_top_left_tmp = pu1_src_top[wd - 1]
    +     SUB         r10,r8,#1                   @ht-1
    +     MLA         r11,r10,r1,r0               @pu1_src[(ht - 1) * src_strd + col]
    +-    ADD         r12,sp,#0x02                @temp array
    ++    ADD         r12,sp,#2                   @temp array
    + 
    + AU1_SRC_TOP_LOOP:
    +     VLD1.8      D0,[r11]!                   @pu1_src[(ht - 1) * src_strd + col]
    +@@ -203,7 +212,7 @@ ulbl3:
    +     VMOV.S8     Q4,#0xFF                    @au1_mask = vdupq_n_s8(-1)
    +     ADDEQ       r14,r14,#1                  @pu1_src_left_cpy += 1
    + 
    +-    STR         r0,[sp,#0x90]               @Store pu1_src in sp
    ++    STR         r0,[sp,#144]                @Store pu1_src in sp
    +     CMP         r7,#16                      @Compare wd with 16
    + 
    +     BLT         WIDTH_RESIDUE               @If not jump to WIDTH_RESIDUE where loop is unrolled for 8 case
    +@@ -211,9 +220,9 @@ ulbl3:
    +     BLE         WD_16_HT_4_LOOP             @If jump to WD_16_HT_4_LOOP
    + 
    + WIDTH_LOOP_16:
    +-    LDR         r7,[sp,#0xD0]               @Loads wd
    ++    LDR         r7,[sp,#wd_offset]          @Loads wd
    + 
    +-    LDR         r5,[sp,#0xC8]               @Loads pu1_avail
    ++    LDR         r5,[sp,#pu1_avail_offset]   @Loads pu1_avail
    +     CMP         r6,r7                       @col == wd
    +     LDRBEQ      r8,[r5]                     @pu1_avail[0]
    +     MOVNE       r8,#-1                      @au1_mask = vsetq_lane_s8(-1, au1_mask, 0)
    +@@ -232,21 +241,21 @@ SKIP_AU1_MASK_VAL:
    +     MOVNE       r8,r3                       @pu1_src_top_cpy
    +     SUB         r8,r8,#1                    @pu1_src_top_cpy - 1 || pu1_src - src_strd - 1
    + 
    +-    LDR         r7,[sp,#0xD0]               @Loads wd
    ++    LDR         r7,[sp,#wd_offset]          @Loads wd
    +     VLD1.8      D10,[r8]!                   @pu1_top_row = vld1q_u8(pu1_src - src_strd - 1) || vld1q_u8(pu1_src_top_cpy - 1)
    +     VLD1.8      D11,[r8]                    @pu1_top_row = vld1q_u8(pu1_src - src_strd - 1) || vld1q_u8(pu1_src_top_cpy - 1)
    +     SUB         r8,#8
    +     ADD         r3,r3,#16
    + 
    +-    ADD         r5,sp,#0x42                 @*au1_src_left_tmp
    ++    ADD         r5,sp,#66                   @*au1_src_left_tmp
    +     VLD1.8      D12,[r0]!                   @pu1_cur_row = vld1q_u8(pu1_src)
    +     VLD1.8      D13,[r0]                    @pu1_cur_row = vld1q_u8(pu1_src)
    +     SUB         r0,#8
    +-    LDR         r4,[sp,#0xD4]               @Loads ht
    ++    LDR         r4,[sp,#ht_offset]          @Loads ht
    + 
    +     SUB         r7,r7,r6                    @(wd - col)
    +     VCGT.U8     Q7,Q6,Q5                    @vcgtq_u8(pu1_cur_row, pu1_top_row)
    +-    LDR         r8,[sp,#0xC0]               @Loads *pu1_src
    ++    LDR         r8,[sp,#152]                @Loads *pu1_src
    + 
    +     ADD         r7,r7,#15                   @15 + (wd - col)
    +     VCLT.U8     Q8,Q6,Q5                    @vcltq_u8(pu1_cur_row, pu1_top_row)
    +@@ -263,7 +272,7 @@ AU1_SRC_LEFT_LOOP:
    + 
    +     ADD         r8,r0,r1                    @I Iteration *pu1_src + src_strd
    +     VMOV.I8     Q9,#0
    +-    LDR         r4,[sp,#0xC8]               @I Loads pu1_avail
    ++    LDR         r4,[sp,#pu1_avail_offset]   @I Loads pu1_avail
    + 
    +     MOV         r7,r12                      @row count, move ht_tmp to r7
    +     VLD1.8      D16,[r8]!                   @I pu1_next_row = vld1q_u8(pu1_src_cpy + src_strd)
    +@@ -498,11 +507,11 @@ PU1_SRC_LOOP:
    + 
    + 
    + INNER_LOOP_DONE:
    +-    ADD         r5,sp,#0x42                 @*au1_src_left_tmp
    ++    ADD         r5,sp,#66                   @*au1_src_left_tmp
    +     VST1.8      {Q10},[r0],r1               @vst1q_u8(pu1_src_cpy, pu1_cur_row)
    +-    LDR         r2,[sp,#0xC4]               @Loads *pu1_src_left
    ++    LDR         r2,[sp,#156]                @Loads *pu1_src_left
    + 
    +-    LDR         r8,[sp,#0xD4]               @Loads ht
    ++    LDR         r8,[sp,#ht_offset]          @Loads ht
    +     SUB         r5,r5,#1
    + 
    +     SUB         r2,r2,#1
    +@@ -515,8 +524,8 @@ SRC_LEFT_LOOP:
    +     SUB         r6,r6,#16                   @Decrement the wd loop count by 16
    +     CMP         r6,#8                       @Check whether residue remains
    +     BLT         RE_ASSINING_LOOP            @Jump to re-assigning loop
    +-    LDR         r7,[sp,#0xD0]               @Loads wd
    +-    LDR         r0,[sp,#0x90]               @Loads *pu1_src
    ++    LDR         r7,[sp,#wd_offset]          @Loads wd
    ++    LDR         r0,[sp,#144]                @Loads *pu1_src
    +     SUB         r7,r7,r6
    +     ADD         r0,r0,r7
    +     BGT         WIDTH_LOOP_16               @If not equal jump to width_loop
    +@@ -524,8 +533,8 @@ SRC_LEFT_LOOP:
    + 
    + 
    + WD_16_HT_4_LOOP:
    +-    LDR         r7,[sp,#0xD0]               @Loads wd
    +-    LDR         r5,[sp,#0xC8]               @Loads pu1_avail
    ++    LDR         r7,[sp,#wd_offset]          @Loads wd
    ++    LDR         r5,[sp,#pu1_avail_offset]   @Loads pu1_avail
    +     CMP         r6,r7                       @col == wd
    +     LDRBEQ      r8,[r5]                     @pu1_avail[0]
    +     MOVNE       r8,#-1                      @au1_mask = vsetq_lane_s8(-1, au1_mask, 0)
    +@@ -544,21 +553,21 @@ SKIP_AU1_MASK_VAL_WD_16_HT_4:
    +     MOVNE       r8,r3
    +     SUB         r8,r8,#1                    @pu1_src_top_cpy - 1 || pu1_src - src_strd - 1
    + 
    +-    LDR         r7,[sp,#0xD0]               @Loads wd
    ++    LDR         r7,[sp,#wd_offset]          @Loads wd
    +     VLD1.8      D10,[r8]!                   @pu1_top_row = vld1q_u8(pu1_src - src_strd - 1) || vld1q_u8(pu1_src_top_cpy - 1)
    +     VLD1.8      D11,[r8]                    @pu1_top_row = vld1q_u8(pu1_src - src_strd - 1) || vld1q_u8(pu1_src_top_cpy - 1)
    +     SUB         r8,#8
    +     ADD         r3,r3,#16
    + 
    +-    ADD         r5,sp,#0x42                 @*au1_src_left_tmp
    ++    ADD         r5,sp,#66                   @*au1_src_left_tmp
    +     VLD1.8      D12,[r0]!                   @pu1_cur_row = vld1q_u8(pu1_src)
    +     VLD1.8      D13,[r0]                    @pu1_cur_row = vld1q_u8(pu1_src)
    +     SUB         r0,#8
    +-    LDR         r4,[sp,#0xD4]               @Loads ht
    ++    LDR         r4,[sp,#ht_offset]          @Loads ht
    + 
    +     SUB         r7,r7,r6                    @(wd - col)
    +     VCGT.U8     Q7,Q6,Q5                    @vcgtq_u8(pu1_cur_row, pu1_top_row)
    +-    LDR         r8,[sp,#0xC0]               @Loads *pu1_src
    ++    LDR         r8,[sp,#152]                @Loads *pu1_src
    + 
    +     ADD         r7,r7,#15                   @15 + (wd - col)
    +     VCLT.U8     Q8,Q6,Q5                    @vcltq_u8(pu1_cur_row, pu1_top_row)
    +@@ -588,7 +597,7 @@ PU1_SRC_LOOP_WD_16_HT_4:
    + 
    +     CMP         r7,r12
    +     BLT         SIGN_UP_CHANGE_WD_16_HT_4
    +-    LDR         r5,[sp,#0xC8]               @Loads pu1_avail
    ++    LDR         r5,[sp,#pu1_avail_offset]   @Loads pu1_avail
    +     LDRB        r5,[r5,#2]                  @pu1_avail[2]
    +     CMP         r5,#0
    +     BNE         SIGN_UP_CHANGE_DONE_WD_16_HT_4
    +@@ -639,9 +648,9 @@ SIGN_UP_CHANGE_DONE_WD_16_HT_4:
    +     SUBS        r7,r7,#1                    @Decrement the ht_tmp loop count by 1
    +     BNE         PU1_SRC_LOOP_WD_16_HT_4     @If not equal jump to PU1_SRC_LOOP_WD_16_HT_4
    + 
    +-    LDR         r8,[sp,#0xD4]               @Loads ht
    +-    ADD         r5,sp,#0x42                 @*au1_src_left_tmp
    +-    LDR         r2,[sp,#0xC4]               @Loads *pu1_src_left
    ++    LDR         r8,[sp,#ht_offset]          @Loads ht
    ++    ADD         r5,sp,#66                   @*au1_src_left_tmp
    ++    LDR         r2,[sp,#156]                @Loads *pu1_src_left
    +     SUB         r5,r5,#1
    +     SUB         r2,r2,#1
    + 
    +@@ -656,8 +665,8 @@ SRC_LEFT_LOOP_WD_16_HT_4:
    + 
    + 
    + WIDTH_RESIDUE:
    +-    LDR         r7,[sp,#0xD0]               @Loads wd
    +-    LDR         r5,[sp,#0xC8]               @Loads pu1_avail
    ++    LDR         r7,[sp,#wd_offset]          @Loads wd
    ++    LDR         r5,[sp,#pu1_avail_offset]   @Loads pu1_avail
    +     CMP         r6,r7                       @wd_residue == wd
    +     LDRBEQ      r8,[r5]                     @pu1_avail[0]
    + 
    +@@ -679,16 +688,16 @@ PU1_AVAIL_2_RESIDUE:
    + 
    +     SUB         r8,r8,#1
    + 
    +-    ADD         r5,sp,#0x42                 @*au1_src_left_tmp
    ++    ADD         r5,sp,#66                   @*au1_src_left_tmp
    +     VLD1.8      D10,[r8]!                   @pu1_top_row = vld1q_u8(pu1_src_top_cpy - 1)
    +     VLD1.8      D11,[r8]!                   @pu1_top_row = vld1q_u8(pu1_src_top_cpy - 1)
    +-    LDR         r7,[sp,#0xD0]               @Loads wd
    ++    LDR         r7,[sp,#wd_offset]          @Loads wd
    + 
    +-    LDR         r4,[sp,#0xD4]               @Loads ht
    ++    LDR         r4,[sp,#ht_offset]          @Loads ht
    +     VCGT.U8     Q7,Q6,Q5                    @vcgtq_u8(pu1_cur_row, pu1_top_row)
    +     SUB         r7,r7,#1                    @(wd - 1)
    + 
    +-    LDR         r8,[sp,#0xC0]               @Loads *pu1_src
    ++    LDR         r8,[sp,#152]                @Loads *pu1_src
    +     VCLT.U8     Q8,Q6,Q5                    @vcltq_u8(pu1_cur_row, pu1_top_row)
    +     SUB         r5,r5,#1
    + 
    +@@ -718,7 +727,7 @@ PU1_SRC_LOOP_RESIDUE:
    + 
    +     CMP         r7,r12
    +     BLT         SIGN_UP_CHANGE_RESIDUE
    +-    LDR         r5,[sp,#0xC8]               @Loads pu1_avail
    ++    LDR         r5,[sp,#pu1_avail_offset]   @Loads pu1_avail
    +     LDRB        r5,[r5,#2]                  @pu1_avail[2]
    +     CMP         r5,#0
    +     BNE         SIGN_UP_CHANGE_DONE_RESIDUE
    +@@ -762,10 +771,10 @@ SIGN_UP_CHANGE_DONE_RESIDUE:
    +     SUBS        r7,r7,#1
    +     BNE         PU1_SRC_LOOP_RESIDUE
    + 
    +-    LDR         r8,[sp,#0xD4]               @Loads ht
    +-    ADD         r5,sp,#0x42                 @*au1_src_left_tmp
    ++    LDR         r8,[sp,#ht_offset]          @Loads ht
    ++    ADD         r5,sp,#66                   @*au1_src_left_tmp
    + 
    +-    LDR         r2,[sp,#0xC4]               @Loads *pu1_src_left
    ++    LDR         r2,[sp,#156]                @Loads *pu1_src_left
    +     SUB         r5,r5,#1
    + 
    +     SUB         r2,r2,#1
    +@@ -778,23 +787,23 @@ SRC_LEFT_LOOP_RESIDUE:
    + 
    + 
    + RE_ASSINING_LOOP:
    +-    LDR         r8,[sp,#0xD4]               @Loads ht
    +-    LDR         r7,[sp,#0xD0]               @Loads wd
    ++    LDR         r8,[sp,#ht_offset]          @Loads ht
    ++    LDR         r7,[sp,#wd_offset]          @Loads wd
    + 
    +-    LDR         r0,[sp,#0xC0]               @Loads *pu1_src
    ++    LDR         r0,[sp,#152]                @Loads *pu1_src
    +     SUB         r8,r8,#1                    @ht - 1
    + 
    +     MLA         r6,r8,r1,r7                 @wd - 1 + (ht - 1) * src_strd
    +     STRB        r9,[r0]                     @pu1_src_org[0] = u1_pos_0_0_tmp
    + 
    +-    LDR         r4,[sp,#0xBC]               @Loads pu1_src_top_left
    ++    LDR         r4,[sp,#pu1_src_top_left_offset] @Loads pu1_src_top_left
    +     ADD         r6,r0,r6                    @pu1_src[wd - 1 + (ht - 1) * src_strd]
    + 
    +-    ADD         r12,sp,#0x02
    ++    ADD         r12,sp,#2
    +     STRB        r10,[r6,#-1]                @pu1_src_org[wd - 1 + (ht - 1) * src_strd] = u1_pos_wd_ht_tmp
    + 
    +     LDRB        r11,[sp]                    @load u1_src_top_left_tmp from stack pointer
    +-    LDR         r3,[sp,#0xCC]               @Loads pu1_src_top
    ++    LDR         r3,[sp,#148]                @Loads pu1_src_top
    + 
    +     STRB        r11,[r4]                    @*pu1_src_top_left = u1_src_top_left_tmp
    + 
    +@@ -805,7 +814,8 @@ SRC_TOP_LOOP:
    +     BNE         SRC_TOP_LOOP
    + 
    + END_LOOPS:
    +-    ADD         sp,sp,#0x94
    ++    ADD         sp,sp,#160
    ++    vpop        {d8  -  d15}
    +     LDMFD       sp!,{r4-r12,r15}            @Reload the registers from SP
    + 
    + 
    +diff --git a/common/arm/ihevc_sao_edge_offset_class2_chroma.s b/common/arm/ihevc_sao_edge_offset_class2_chroma.s
    +index b74a8f6..f7ab3f8 100644
    +--- a/common/arm/ihevc_sao_edge_offset_class2_chroma.s
    ++++ b/common/arm/ihevc_sao_edge_offset_class2_chroma.s
    +@@ -60,6 +60,15 @@
    + @r7 =>  wd
    + @r8=>   ht
    + 
    ++.equ    pu1_src_top_left_offset,    328
    ++.equ    pu1_src_top_right_offset,   332
    ++.equ    pu1_src_bot_left_offset,    336
    ++.equ    pu1_avail_offset,           340
    ++.equ    pi1_sao_u_offset,           344
    ++.equ    pi1_sao_v_offset,           348
    ++.equ    wd_offset,                  352
    ++.equ    ht_offset,                  356
    ++
    + .text
    + .syntax unified
    + .p2align 2
    +@@ -86,23 +95,24 @@ ihevc_sao_edge_offset_class2_chroma_a9q:
    + 
    + 
    +     STMFD       sp!,{r4-r12,r14}            @stack stores the values of the arguments
    ++    vpush       {d8  -  d15}
    ++    SUB         sp,sp,#224                  @Decrement the stack pointer to store some temp arr values
    + 
    +-    LDR         r7,[sp,#0x40]               @Loads wd
    +-    LDR         r8,[sp,#0x44]               @Loads ht
    ++    LDR         r7,[sp,#wd_offset]          @Loads wd
    ++    LDR         r8,[sp,#ht_offset]          @Loads ht
    +     SUB         r9,r7,#2                    @wd - 2
    + 
    +-    LDR         r4,[sp,#0x28]               @Loads pu1_src_top_left
    ++    LDR         r4,[sp,#pu1_src_top_left_offset]    @Loads pu1_src_top_left
    +     LDRH        r10,[r3,r9]                 @pu1_src_top[wd - 2]
    + 
    +-    STR         r0,[sp,#0x2C]               @Store pu1_src in sp
    ++    STR         r0,[sp,#212]                @Store pu1_src in sp
    +     MOV         r9,r7                       @Move width to r9 for loop count
    + 
    +-    STR         r2,[sp,#0x30]               @Store pu1_src_left in sp
    +-    LDR         r5,[sp,#0x34]               @Loads pu1_avail
    +-    LDR         r6,[sp,#0x38]               @Loads pi1_sao_offset_u
    ++    STR         r2,[sp,#216]                @Store pu1_src_left in sp
    ++    LDR         r5,[sp,#pu1_avail_offset]   @Loads pu1_avail
    ++    LDR         r6,[sp,#pi1_sao_u_offset]   @Loads pi1_sao_offset_u
    + 
    +-    STR         r3,[sp,#0x38]               @Store pu1_src_top in sp
    +-    SUB         sp,sp,#0xD4                 @Decrement the stack pointer to store some temp arr values
    ++    STR         r3,[sp,#220]                @Store pu1_src_top in sp
    + 
    +     STRH        r10,[sp]                    @u1_src_top_left_tmp = pu1_src_top[wd - 2]
    +     SUB         r10,r8,#1                   @ht-1
    +@@ -178,7 +188,7 @@ ulbl2:
    +     LDRSB       r12,[r14,r11]               @edge_idx = gi1_table_edge_idx[edge_idx]
    +     CMP         r12,#0                      @0 != edge_idx
    +     BEQ         PU1_AVAIL_7_LOOP_U
    +-    LDR         r11,[sp,#0x110]             @Loads pi1_sao_offset_v
    ++    LDR         r11,[sp,#pi1_sao_v_offset]  @Loads pi1_sao_offset_v
    +     LDRSB       r11,[r11,r12]               @pi1_sao_offset_v[edge_idx]
    +     ADD         r10,r10,r11                 @pu1_src[0] + pi1_sao_offset_v[edge_idx]
    +     USAT        r10,#8,r10                  @u1_pos_0_0_tmp_v = CLIP3(pu1_src[0] + pi1_sao_offset_v[edge_idx], 0, (1 << bit_depth) - 1)
    +@@ -253,7 +263,7 @@ ulbl4:
    +     LDRSB       r12,[r14,r11]               @edge_idx = gi1_table_edge_idx[edge_idx]
    +     CMP         r12,#0
    +     BEQ         PU1_AVAIL_3_LOOP
    +-    LDR         r14,[sp,#0x110]             @Loads pi1_sao_offset_v
    ++    LDR         r14,[sp,#pi1_sao_v_offset]  @Loads pi1_sao_offset_v
    +     LDRSB       r11,[r14,r12]               @pi1_sao_offset_v[edge_idx]
    +     ADD         r9,r9,r11                   @pu1_src[wd - 1 + (ht - 1) * src_strd] + pi1_sao_offset[edge_idx]
    +     USAT        r9,#8,r9                    @u1_pos_wd_ht_tmp_v = CLIP3(pu1_src[wd - 1 + (ht - 1) * src_strd] + pi1_sao_offset[edge_idx], 0, (1 << bit_depth) - 1)
    +@@ -280,7 +290,7 @@ PU1_AVAIL_3_LOOP:
    +     VLD1.8      D6,[r6]                     @offset_tbl_u = vld1_s8(pi1_sao_offset_u)
    +     SUBEQ       r12,r12,#1                  @ht_tmp--
    + 
    +-    LDR         r6,[sp,#0x110]              @Loads pi1_sao_offset_v
    ++    LDR         r6,[sp,#pi1_sao_v_offset]   @Loads pi1_sao_offset_v
    +     ADDEQ       r14,r14,#2                  @pu1_src_left_cpy += 2
    + 
    +     STR         r0,[sp,#2]                  @Store pu1_src in sp
    +@@ -298,8 +308,8 @@ ulbl5:
    +     BLE         WD_16_HT_4_LOOP             @If jump to WD_16_HT_4_LOOP
    + 
    + WIDTH_LOOP_16:
    +-    LDR         r5,[sp,#0x108]              @Loads pu1_avail
    +-    LDR         r7,[sp,#0x114]              @Loads wd
    ++    LDR         r5,[sp,#pu1_avail_offset]   @Loads pu1_avail
    ++    LDR         r7,[sp,#wd_offset]          @Loads wd
    +     CMP         r6,r7                       @col == wd
    +     LDRBEQ      r8,[r5]                     @pu1_avail[0]
    + 
    +@@ -321,16 +331,16 @@ SKIP_AU1_MASK_VAL:
    +     SUB         r0,#8
    +     CMP         r9,#0
    + 
    +-    LDR         r4,[sp,#0x118]              @Loads ht
    ++    LDR         r4,[sp,#ht_offset]          @Loads ht
    +     SUBEQ       r8,r0,r1                    @pu1_src - src_strd
    + 
    +-    LDR         r7,[sp,#0x114]              @Loads wd
    ++    LDR         r7,[sp,#wd_offset]          @Loads wd
    +     MOVNE       r8,r3                       @pu1_src_top_cpy
    + 
    +     SUB         r8,r8,#2                    @pu1_src - src_strd - 2
    +     ADD         r3,r3,#16
    + 
    +-    ADD         r5,sp,#0x4B                 @*au1_src_left_tmp
    ++    ADD         r5,sp,#75                   @*au1_src_left_tmp
    +     VLD1.8      D10,[r8]!                   @pu1_top_row = vld1q_u8(pu1_src - src_strd - 2) || vld1q_u8(pu1_src_top_cpy - 2)
    +     VLD1.8      D11,[r8]                    @pu1_top_row = vld1q_u8(pu1_src - src_strd - 2) || vld1q_u8(pu1_src_top_cpy - 2)
    +     SUB         r8,#8
    +@@ -338,7 +348,7 @@ SKIP_AU1_MASK_VAL:
    + 
    +     ADD         r7,r7,#14                   @15 + (wd - col)
    +     VCGT.U8     Q7,Q6,Q5                    @vcgtq_u8(pu1_cur_row, pu1_top_row)
    +-    LDR         r8,[sp,#0x100]              @Loads *pu1_src
    ++    LDR         r8,[sp,#212]                @Loads *pu1_src
    + 
    +     ADD         r7,r8,r7                    @pu1_src[0 * src_strd + 15 + (wd - col)]
    +     VCLT.U8     Q8,Q6,Q5                    @vcltq_u8(pu1_cur_row, pu1_top_row)
    +@@ -364,7 +374,7 @@ AU1_SRC_LEFT_LOOP:
    +     VMOV.I8     Q9,#0
    +     LDRH        r5,[r8]                     @I pu1_src_cpy[src_strd + 16]
    + 
    +-    LDR         r10,[sp,#0x108]             @I Loads pu1_avail
    ++    LDR         r10,[sp,#pu1_avail_offset]  @I Loads pu1_avail
    +     VMOV.16     D18[0],r5                   @I pu1_next_row_tmp = vsetq_lane_u8(pu1_src_cpy[src_strd + 16], pu1_next_row_tmp, 0)
    +     LDRB        r10,[r10,#2]                @I pu1_avail[2]
    + 
    +@@ -654,11 +664,11 @@ PU1_SRC_LOOP:
    + 
    + 
    + INNER_LOOP_DONE:
    +-    LDR         r8,[sp,#0x118]              @Loads ht
    ++    LDR         r8,[sp,#ht_offset]          @Loads ht
    +     VMOVN.I16   D20,Q10                     @vmovn_s16(pi2_tmp_cur_row.val[0])
    +-    ADD         r5,sp,#0x4B                 @*au1_src_left_tmp
    ++    ADD         r5,sp,#75                   @*au1_src_left_tmp
    + 
    +-    LDR         r11,[sp,#0x104]             @Loads *pu1_src_left
    ++    LDR         r11,[sp,#216]               @Loads *pu1_src_left
    +     VMOVN.I16   D21,Q9                      @vmovn_s16(pi2_tmp_cur_row.val[1])
    + 
    + 
    +@@ -673,8 +683,8 @@ SRC_LEFT_LOOP:
    +     CMP         r6,#8                       @Check whether residue remains
    + 
    +     BLT         RE_ASSINING_LOOP            @Jump to re-assigning loop
    +-    LDR         r7,[sp,#0x114]              @Loads wd
    +-    LDR         r0,[sp,#0x02]               @Loads *pu1_src
    ++    LDR         r7,[sp,#wd_offset]          @Loads wd
    ++    LDR         r0,[sp,#2]                  @Loads *pu1_src
    +     SUB         r7,r7,r6
    +     ADD         r0,r0,r7
    +     BGT         WIDTH_LOOP_16               @If not equal jump to width_loop
    +@@ -682,8 +692,8 @@ SRC_LEFT_LOOP:
    + 
    + 
    + WD_16_HT_4_LOOP:
    +-    LDR         r5,[sp,#0x108]              @Loads pu1_avail
    +-    LDR         r7,[sp,#0x114]              @Loads wd
    ++    LDR         r5,[sp,#pu1_avail_offset]   @Loads pu1_avail
    ++    LDR         r7,[sp,#wd_offset]          @Loads wd
    +     CMP         r6,r7                       @col == wd
    +     LDRBEQ      r8,[r5]                     @pu1_avail[0]
    + 
    +@@ -709,12 +719,12 @@ SKIP_AU1_MASK_VAL_WD_16_HT_4:
    +     SUB         r8,#8
    + 
    +     ADD         r3,r3,#16
    +-    ADD         r5,sp,#0x4B                 @*au1_src_left_tmp
    +-    LDR         r4,[sp,#0x118]              @Loads ht
    +-    LDR         r7,[sp,#0x114]              @Loads wd
    ++    ADD         r5,sp,#75                   @*au1_src_left_tmp
    ++    LDR         r4,[sp,#ht_offset]          @Loads ht
    ++    LDR         r7,[sp,#wd_offset]          @Loads wd
    +     SUB         r7,r7,r6                    @(wd - col)
    +     ADD         r7,r7,#14                   @15 + (wd - col)
    +-    LDR         r8,[sp,#0x100]              @Loads *pu1_src
    ++    LDR         r8,[sp,#212]                @Loads *pu1_src
    +     ADD         r7,r8,r7                    @pu1_src[0 * src_strd + 15 + (wd - col)]
    + 
    + AU1_SRC_LEFT_LOOP_WD_16_HT_4:
    +@@ -749,7 +759,7 @@ PU1_SRC_LOOP_WD_16_HT_4:
    + 
    +     CMP         r7,r12
    +     BLT         SIGN_UP_CHANGE_WD_16_HT_4
    +-    LDR         r5,[sp,#0x108]              @Loads pu1_avail
    ++    LDR         r5,[sp,#pu1_avail_offset]   @Loads pu1_avail
    +     LDRB        r5,[r5,#2]                  @pu1_avail[2]
    +     CMP         r5,#0
    +     BNE         SIGN_UP_CHANGE_DONE_WD_16_HT_4
    +@@ -815,9 +825,9 @@ SIGN_UP_CHANGE_DONE_WD_16_HT_4:
    +     SUBS        r7,r7,#1                    @Decrement the ht_tmp loop count by 1
    +     BNE         PU1_SRC_LOOP_WD_16_HT_4     @If not equal jump to PU1_SRC_LOOP_WD_16_HT_4
    + 
    +-    LDR         r8,[sp,#0x118]              @Loads ht
    +-    ADD         r5,sp,#0x4B                 @*au1_src_left_tmp
    +-    LDR         r11,[sp,#0x104]             @Loads *pu1_src_left
    ++    LDR         r8,[sp,#ht_offset]          @Loads ht
    ++    ADD         r5,sp,#75                   @*au1_src_left_tmp
    ++    LDR         r11,[sp,#216]               @Loads *pu1_src_left
    + 
    + SRC_LEFT_LOOP_WD_16_HT_4:
    +     LDR         r7,[r5],#4                  @au1_src_left_tmp[row]
    +@@ -829,12 +839,16 @@ SRC_LEFT_LOOP_WD_16_HT_4:
    + 
    +     SUBS        r6,r6,#16                   @Decrement the wd loop count by 16
    +     BLE         RE_ASSINING_LOOP            @Jump to re-assigning loop
    ++    LDR         r7,[sp,#wd_offset]          @Loads wd
    ++    LDR         r0,[sp,#2]                  @Loads *pu1_src
    ++    SUB         r7,r7,r6
    ++    ADD         r0,r0,r7
    +     BGT         WD_16_HT_4_LOOP
    + 
    + 
    + WIDTH_RESIDUE:
    +-    LDR         r7,[sp,#0x114]              @Loads wd
    +-    LDR         r5,[sp,#0x108]              @Loads pu1_avail
    ++    LDR         r7,[sp,#wd_offset]          @Loads wd
    ++    LDR         r5,[sp,#pu1_avail_offset]   @Loads pu1_avail
    +     CMP         r6,r7                       @wd_residue == wd
    +     LDRBEQ      r8,[r5]                     @pu1_avail[0]
    + 
    +@@ -856,10 +870,10 @@ WIDTH_RESIDUE:
    +     VLD1.8      D11,[r8]                    @pu1_top_row = vld1q_u8(pu1_src - src_strd - 2)
    +     SUB         r8,#8
    + 
    +-    ADD         r5,sp,#0x4B                 @*au1_src_left_tmp
    +-    LDR         r4,[sp,#0x118]              @Loads ht
    +-    LDR         r7,[sp,#0x114]              @Loads wd
    +-    LDR         r8,[sp,#0x100]              @Loads *pu1_src
    ++    ADD         r5,sp,#75                   @*au1_src_left_tmp
    ++    LDR         r4,[sp,#ht_offset]          @Loads ht
    ++    LDR         r7,[sp,#wd_offset]          @Loads wd
    ++    LDR         r8,[sp,#212]                @Loads *pu1_src
    +     SUB         r7,r7,#2                    @(wd - 2)
    +     ADD         r7,r8,r7                    @pu1_src[0 * src_strd + (wd - 2)]
    + 
    +@@ -893,7 +907,7 @@ PU1_SRC_LOOP_RESIDUE:
    + 
    +     CMP         r7,r12
    +     BLT         SIGN_UP_CHANGE_RESIDUE
    +-    LDR         r5,[sp,#0x108]              @Loads pu1_avail
    ++    LDR         r5,[sp,#pu1_avail_offset]   @Loads pu1_avail
    +     LDRB        r5,[r5,#2]                  @pu1_avail[2]
    +     CMP         r5,#0
    +     BNE         SIGN_UP_CHANGE_DONE_RESIDUE
    +@@ -953,9 +967,9 @@ SIGN_UP_CHANGE_DONE_RESIDUE:
    +     SUBS        r7,r7,#1                    @Decrement the ht_tmp loop count by 1
    +     BNE         PU1_SRC_LOOP_RESIDUE        @If not equal jump to PU1_SRC_LOOP
    + 
    +-    LDR         r8,[sp,#0x118]              @Loads ht
    +-    LDR         r11,[sp,#0x104]             @Loads *pu1_src_left
    +-    ADD         r5,sp,#0x4B                 @*au1_src_left_tmp
    ++    LDR         r8,[sp,#ht_offset]          @Loads ht
    ++    LDR         r11,[sp,#216]               @Loads *pu1_src_left
    ++    ADD         r5,sp,#75                   @*au1_src_left_tmp
    + 
    + SRC_LEFT_LOOP_RESIDUE:
    +     LDR         r7,[r5],#4                  @au1_src_left_tmp[row]
    +@@ -966,12 +980,12 @@ SRC_LEFT_LOOP_RESIDUE:
    + 
    + 
    + RE_ASSINING_LOOP:
    +-    LDR         r8,[sp,#0x118]              @Loads ht
    ++    LDR         r8,[sp,#ht_offset]          @Loads ht
    + 
    +-    LDR         r0,[sp,#0x100]              @Loads *pu1_src
    ++    LDR         r0,[sp,#212]                @Loads *pu1_src
    +     SUB         r8,r8,#1                    @ht - 1
    + 
    +-    LDR         r7,[sp,#0x114]              @Loads wd
    ++    LDR         r7,[sp,#wd_offset]          @Loads wd
    + 
    +     LDRH        r9,[sp,#6]
    +     MLA         r6,r8,r1,r7                 @wd - 2 + (ht - 1) * src_strd
    +@@ -983,10 +997,10 @@ RE_ASSINING_LOOP:
    +     ADD         r12,sp,#10
    +     STRH        r9,[r6,#-2]                 @pu1_src_org[wd - 1 + (ht - 1) * src_strd] = u1_pos_wd_ht_tmp_u
    + 
    +-    LDR         r4,[sp,#0xFC]               @Loads pu1_src_top_left
    ++    LDR         r4,[sp,#pu1_src_top_left_offset]               @Loads pu1_src_top_left
    +     LDRH        r10,[sp]                    @load u1_src_top_left_tmp from stack pointer
    +     STRH        r10,[r4]                    @*pu1_src_top_left = u1_src_top_left_tmp
    +-    LDR         r3,[sp,#0x10C]              @Loads pu1_src_top
    ++    LDR         r3,[sp,#220]                @Loads pu1_src_top
    + 
    + SRC_TOP_LOOP:
    +     VLD1.8      D0,[r12]!                   @pu1_src_top[col] = au1_src_top_tmp[col]
    +@@ -995,7 +1009,9 @@ SRC_TOP_LOOP:
    +     BNE         SRC_TOP_LOOP
    + 
    + END_LOOPS:
    +-    ADD         sp,sp,#0xD4
    ++    ADD         sp,sp,#224
    ++
    ++    vpop        {d8  -  d15}
    +     LDMFD       sp!,{r4-r12,r15}            @Reload the registers from SP
    + 
    + 
    +diff --git a/common/arm/ihevc_sao_edge_offset_class3.s b/common/arm/ihevc_sao_edge_offset_class3.s
    +index de09d6c..fb3b05c 100644
    +--- a/common/arm/ihevc_sao_edge_offset_class3.s
    ++++ b/common/arm/ihevc_sao_edge_offset_class3.s
    +@@ -58,6 +58,14 @@
    + @r7 =>  wd
    + @r8=>   ht
    + 
    ++.equ    pu1_src_top_left_offset,    264
    ++.equ    pu1_src_top_right_offset,   268
    ++.equ    pu1_src_bot_left_offset,    272
    ++.equ    pu1_avail_offset,           276
    ++.equ    pi1_sao_offset,             280
    ++.equ    wd_offset,                  284
    ++.equ    ht_offset,                  288
    ++
    + .text
    + .syntax unified
    + .p2align 2
    +@@ -78,26 +86,27 @@ ihevc_sao_edge_offset_class3_a9q:
    + 
    + 
    +     STMFD       sp!,{r4-r12,r14}            @stack stores the values of the arguments
    +-    LDR         r7,[sp,#0x3C]               @Loads wd
    ++    vpush       {d8  -  d15}
    ++    SUB         sp,sp,#160                  @Decrement the stack pointer to store some temp arr values
    ++    LDR         r7,[sp,#wd_offset]          @Loads wd
    + 
    +-    LDR         r8,[sp,#0x40]               @Loads ht
    ++    LDR         r8,[sp,#ht_offset]          @Loads ht
    +     SUB         r9,r7,#1                    @wd - 1
    + 
    +-    LDR         r4,[sp,#0x28]               @Loads pu1_src_top_left
    ++    LDR         r4,[sp,#pu1_src_top_left_offset]               @Loads pu1_src_top_left
    +     LDRB        r10,[r3,r9]                 @pu1_src_top[wd - 1]
    + 
    +     MOV         r9,r7                       @Move width to r9 for loop count
    + 
    +-    LDR         r5,[sp,#0x34]               @Loads pu1_avail
    +-    LDR         r6,[sp,#0x38]               @Loads pi1_sao_offset
    +-    STR         r3,[sp,#0x38]               @Store pu1_src_top in sp
    ++    LDR         r5,[sp,#pu1_avail_offset]   @Loads pu1_avail
    ++    LDR         r6,[sp,#pi1_sao_offset]     @Loads pi1_sao_offset
    ++    STR         r3,[sp,#156]                @Store pu1_src_top in sp
    + 
    +-    SUB         sp,sp,#0x94                 @Decrement the stack pointer to store some temp arr values
    + 
    +     STRB        r10,[sp]                    @u1_src_top_left_tmp = pu1_src_top[wd - 1]
    +     SUB         r10,r8,#1                   @ht-1
    +     MLA         r11,r10,r1,r0               @pu1_src[(ht - 1) * src_strd + col]
    +-    ADD         r12,sp,#0x02                @temp array
    ++    ADD         r12,sp,#2                   @temp array
    + 
    + AU1_SRC_TOP_LOOP:
    +     VLD1.8      D0,[r11]!                   @pu1_src[(ht - 1) * src_strd + col]
    +@@ -112,7 +121,7 @@ PU1_AVAIL_5_LOOP:
    +     LDRB        r9,[r0,r10]                 @u1_pos_0_0_tmp = pu1_src[wd - 1]
    +     BEQ         PU1_AVAIL_6_LOOP
    + 
    +-    LDR         r11,[sp,#0xC0]              @Load pu1_src_top_right from sp
    ++    LDR         r11,[sp,#pu1_src_top_right_offset]  @Load pu1_src_top_right from sp
    +     SUB         r10,r10,#1                  @[wd - 1 - 1]
    + 
    +     LDRB        r11,[r11]                   @pu1_src_top_right[0]
    +@@ -147,13 +156,13 @@ PU1_AVAIL_6_LOOP:
    +     SUB         r11,r8,#1                   @ht - 1
    + 
    +     CMP         r10,#0
    +-    STR         r0,[sp,#0xC0]               @Store pu1_src in sp
    ++    STR         r0,[sp,#148]                @Store pu1_src in sp
    +     MLA         r12,r11,r1,r0               @pu1_src[(ht - 1) * src_strd]
    + 
    +     LDRB        r10,[r12]                   @u1_pos_wd_ht_tmp = pu1_src[(ht - 1) * src_strd]
    +     BEQ         PU1_AVAIL_3_LOOP
    + 
    +-    LDR         r14,[sp,#0xC4]              @Load pu1_src_bot_left from sp
    ++    LDR         r14,[sp,#pu1_src_bot_left_offset]   @Load pu1_src_bot_left from sp
    +     SUB         r11,r12,r1                  @pu1_src[(ht - 1) * src_strd) - src_strd]
    + 
    +     LDRB        r14,[r14]                   @Load pu1_src_bot_left[0]
    +@@ -186,7 +195,7 @@ ulbl2:
    +     USAT        r10,#8,r10                  @u1_pos_wd_ht_tmp = CLIP3(pu1_src[(ht - 1) * src_strd] + pi1_sao_offset[edge_idx], 0, (1 << bit_depth) - 1)
    + 
    + PU1_AVAIL_3_LOOP:
    +-    STR         r2,[sp,#0xC4]               @Store pu1_src_left in sp
    ++    STR         r2,[sp,#152]                @Store pu1_src_left in sp
    +     MOV         r12,r8                      @Move ht
    + 
    +     MOV         r14,r2                      @Move pu1_src_left to pu1_src_left_cpy
    +@@ -211,7 +220,7 @@ ulbl3:
    +     VMOV.S8     Q4,#0xFF                    @au1_mask = vdupq_n_s8(-1)
    +     ADDEQ       r14,r14,#1                  @pu1_src_left_cpy += 1
    + 
    +-    STR         r0,[sp,#0x90]               @Store pu1_src in sp
    ++    STR         r0,[sp,#144]                @Store pu1_src in sp
    +     VLD1.8      D6,[r6]                     @edge_idx_tbl = vld1_s8(gi1_table_edge_idx)
    +     MOV         r6,r7                       @move wd to r6 loop_count
    + 
    +@@ -221,9 +230,9 @@ ulbl3:
    +     BLE         WD_16_HT_4_LOOP             @If jump to WD_16_HT_4_LOOP
    + 
    + WIDTH_LOOP_16:
    +-    LDR         r7,[sp,#0xD0]               @Loads wd
    ++    LDR         r7,[sp,#wd_offset]          @Loads wd
    + 
    +-    LDR         r5,[sp,#0xC8]               @Loads pu1_avail
    ++    LDR         r5,[sp,#pu1_avail_offset]   @Loads pu1_avail
    +     CMP         r6,r7                       @col == wd
    +     LDRBEQ      r8,[r5]                     @pu1_avail[0]
    +     MOVNE       r8,#-1
    +@@ -238,13 +247,13 @@ SKIP_AU1_MASK_VAL:
    +     LDRB        r8,[r5,#2]                  @pu1_avail[2]
    +     CMP         r8,#0
    + 
    +-    LDR         r4,[sp,#0xD4]               @Loads ht
    ++    LDR         r4,[sp,#ht_offset]          @Loads ht
    +     SUBEQ       r8,r0,r1                    @pu1_src - src_strd
    + 
    +     MOVNE       r8,r3
    +-    ADD         r5,sp,#0x42                 @*au1_src_left_tmp
    ++    ADD         r5,sp,#66                   @*au1_src_left_tmp
    + 
    +-    LDR         r7,[sp,#0xD0]               @Loads wd
    ++    LDR         r7,[sp,#wd_offset]          @Loads wd
    +     ADD         r8,r8,#1                    @pu1_src - src_strd + 1
    + 
    +     SUB         r7,r7,r6                    @(wd - col)
    +@@ -253,7 +262,7 @@ SKIP_AU1_MASK_VAL:
    +     SUB         r8,#8
    +     ADD         r3,r3,#16
    + 
    +-    LDR         r8,[sp,#0xC0]               @Loads *pu1_src
    ++    LDR         r8,[sp,#148]                @Loads *pu1_src
    +     VLD1.8      D12,[r0]!                   @pu1_cur_row = vld1q_u8(pu1_src)
    +     VLD1.8      D13,[r0]                    @pu1_cur_row = vld1q_u8(pu1_src)
    +     SUB         r0,#8
    +@@ -285,7 +294,7 @@ AU1_SRC_LEFT_LOOP:
    +     ADD         r8,r8,#1                    @I pu1_src_left_cpy[ht_tmp - row + 1]
    +     LDRB        r8,[r8]
    + 
    +-    LDR         r5,[sp,#0xC8]               @I Loads pu1_avail
    ++    LDR         r5,[sp,#pu1_avail_offset]   @I Loads pu1_avail
    +     VMOV.8      D19[7],r8                   @I vsetq_lane_u8
    +     LDRB        r5,[r5,#2]                  @I pu1_avail[2]
    + 
    +@@ -375,7 +384,7 @@ PU1_SRC_LOOP:
    +     CMP         r7,#1                       @III
    + 
    +     BNE         NEXT_ROW_ELSE_2             @III
    +-    LDR         r5,[sp,#0xC8]               @III Loads pu1_avail
    ++    LDR         r5,[sp,#pu1_avail_offset]   @III Loads pu1_avail
    +     LDRB        r5,[r5,#3]                  @III pu1_avail[3]
    +     CMP         r5,#0                       @III
    +     SUBNE       r8,r2,#2                    @III pu1_src_cpy[src_strd - 1]
    +@@ -465,7 +474,7 @@ NEXT_ROW_ELSE_2:
    + 
    +     ADD         r8,r0,r1,LSL #1             @*pu1_src + src_strd
    +     VMOVN.I16   D20,Q10                     @III vmovn_s16(pi2_tmp_cur_row.val[0])
    +-    LDR         r5,[sp,#0xC8]               @Loads pu1_avail
    ++    LDR         r5,[sp,#pu1_avail_offset]   @Loads pu1_avail
    + 
    +     LDRB        r5,[r5,#3]                  @pu1_avail[3]
    +     VMOVN.I16   D21,Q11                     @III vmovn_s16(pi2_tmp_cur_row.val[1])
    +@@ -529,13 +538,13 @@ NEXT_ROW_POINTER_ASSIGNED_3:
    + 
    + INNER_LOOP_DONE:
    +     VMOVN.I16   D20,Q10                     @vmovn_s16(pi2_tmp_cur_row.val[0])
    +-    LDR         r8,[sp,#0xD4]               @Loads ht
    ++    LDR         r8,[sp,#ht_offset]          @Loads ht
    + 
    +     VMOVN.I16   D21,Q11                     @vmovn_s16(pi2_tmp_cur_row.val[1])
    +-    ADD         r5,sp,#0x42                 @*au1_src_left_tmp
    ++    ADD         r5,sp,#66                   @*au1_src_left_tmp
    + 
    +     VST1.8      {Q10},[r0],r1               @vst1q_u8(pu1_src_cpy, pu1_cur_row)
    +-    LDR         r2,[sp,#0xC4]               @Loads *pu1_src_left
    ++    LDR         r2,[sp,#152]                @Loads *pu1_src_left
    + SRC_LEFT_LOOP:
    +     LDR         r7,[r5],#4                  @au1_src_left_tmp[row]
    +     SUBS        r8,r8,#4
    +@@ -545,8 +554,8 @@ SRC_LEFT_LOOP:
    +     SUBS        r6,r6,#16                   @Decrement the wd loop count by 16
    +     CMP         r6,#8                       @Check whether residue remains
    +     BLT         RE_ASSINING_LOOP            @Jump to re-assigning loop
    +-    LDR         r7,[sp,#0xD0]               @Loads wd
    +-    LDR         r0,[sp,#0x90]               @Loads *pu1_src
    ++    LDR         r7,[sp,#wd_offset]          @Loads wd
    ++    LDR         r0,[sp,#144]                @Loads *pu1_src
    +     SUB         r7,r7,r6
    +     ADD         r0,r0,r7
    +     BGT         WIDTH_LOOP_16               @If not equal jump to width_loop
    +@@ -555,8 +564,8 @@ SRC_LEFT_LOOP:
    + 
    + 
    + WD_16_HT_4_LOOP:
    +-    LDR         r5,[sp,#0xC8]               @Loads pu1_avail
    +-    LDR         r7,[sp,#0xD0]               @Loads wd
    ++    LDR         r5,[sp,#pu1_avail_offset]   @Loads pu1_avail
    ++    LDR         r7,[sp,#wd_offset]          @Loads wd
    +     CMP         r6,r7                       @col == wd
    +     LDRBEQ      r8,[r5]                     @pu1_avail[0]
    +     MOVNE       r8,#-1
    +@@ -579,12 +588,12 @@ SKIP_AU1_MASK_VAL_WD_16_HT_4:
    +     SUB         r8,#8
    + 
    +     ADD         r3,r3,#16
    +-    ADD         r5,sp,#0x42                 @*au1_src_left_tmp
    +-    LDR         r4,[sp,#0xD4]               @Loads ht
    +-    LDR         r7,[sp,#0xD0]               @Loads wd
    ++    ADD         r5,sp,#66                   @*au1_src_left_tmp
    ++    LDR         r4,[sp,#ht_offset]          @Loads ht
    ++    LDR         r7,[sp,#wd_offset]          @Loads wd
    +     SUB         r7,r7,r6                    @(wd - col)
    +     ADD         r7,r7,#15                   @15 + (wd - col)
    +-    LDR         r8,[sp,#0xC0]               @Loads *pu1_src
    ++    LDR         r8,[sp,#148]                @Loads *pu1_src
    +     ADD         r7,r8,r7                    @pu1_src[0 * src_strd + 15 + (wd - col)]
    +     SUB         r5,r5,#1
    + 
    +@@ -609,7 +618,7 @@ PU1_SRC_LOOP_WD_16_HT_4:
    +     VLD1.8      D16,[r8]!                   @pu1_next_row = vld1q_u8(pu1_src_cpy + src_strd)
    +     VLD1.8      D17,[r8]                    @pu1_next_row = vld1q_u8(pu1_src_cpy + src_strd)
    +     SUB         r8,#8
    +-    LDR         r5,[sp,#0xC8]               @Loads pu1_avail
    ++    LDR         r5,[sp,#pu1_avail_offset]   @Loads pu1_avail
    +     LDRB        r5,[r5,#3]                  @pu1_avail[3]
    +     CMP         r5,#0
    +     BEQ         NEXT_ROW_ELSE_WD_16_HT_4
    +@@ -628,7 +637,7 @@ NEXT_ROW_POINTER_ASSIGNED_WD_16_HT_4:
    + 
    +     CMP         r7,r12
    +     BNE         SIGN_UP_CHANGE_WD_16_HT_4
    +-    LDR         r5,[sp,#0xC8]               @Loads pu1_avail
    ++    LDR         r5,[sp,#pu1_avail_offset]   @Loads pu1_avail
    +     LDRB        r5,[r5,#2]                  @pu1_avail[2]
    +     CMP         r5,#0
    +     BNE         SIGN_UP_CHANGE_DONE_WD_16_HT_4
    +@@ -680,9 +689,9 @@ SIGN_UP_CHANGE_DONE_WD_16_HT_4:
    +     SUBS        r7,r7,#1                    @Decrement the ht_tmp loop count by 1
    +     BNE         PU1_SRC_LOOP_WD_16_HT_4     @If not equal jump to PU1_SRC_LOOP_WD_16_HT_4
    + 
    +-    LDR         r8,[sp,#0xD4]               @Loads ht
    +-    ADD         r5,sp,#0x42                 @*au1_src_left_tmp
    +-    LDR         r2,[sp,#0xC4]               @Loads *pu1_src_left
    ++    LDR         r8,[sp,#ht_offset]          @Loads ht
    ++    ADD         r5,sp,#66                   @*au1_src_left_tmp
    ++    LDR         r2,[sp,#152]                @Loads *pu1_src_left
    + SRC_LEFT_LOOP_WD_16_HT_4:
    +     LDR         r7,[r5],#4                  @au1_src_left_tmp[row]
    +     STR         r7,[r2],#4                  @pu1_src_left[row] = au1_src_left_tmp[row]
    +@@ -691,12 +700,16 @@ SRC_LEFT_LOOP_WD_16_HT_4:
    + 
    +     SUBS        r6,r6,#16                   @Decrement the wd loop count by 16
    +     BLE         RE_ASSINING_LOOP            @Jump to re-assigning loop
    ++    LDR         r7,[sp,#wd_offset]          @Loads wd
    ++    LDR         r0,[sp,#144]                @Loads *pu1_src
    ++    SUB         r7,r7,r6
    ++    ADD         r0,r0,r7
    +     BGT         WD_16_HT_4_LOOP             @If not equal jump to width_loop
    + 
    + 
    + WIDTH_RESIDUE:
    +-    LDR         r7,[sp,#0xD0]               @Loads wd
    +-    LDR         r5,[sp,#0xC8]               @Loads pu1_avail
    ++    LDR         r7,[sp,#wd_offset]          @Loads wd
    ++    LDR         r5,[sp,#pu1_avail_offset]   @Loads pu1_avail
    +     CMP         r6,r7                       @wd_residue == wd
    +     LDRBEQ      r8,[r5]                     @pu1_avail[0]
    + 
    +@@ -718,10 +731,10 @@ PU1_AVAIL_2_RESIDUE:
    +     SUB         r8,#8
    + 
    + 
    +-    ADD         r5,sp,#0x42                 @*au1_src_left_tmp
    +-    LDR         r4,[sp,#0xD4]               @Loads ht
    +-    LDR         r7,[sp,#0xD0]               @Loads wd
    +-    LDR         r8,[sp,#0xC0]               @Loads *pu1_src
    ++    ADD         r5,sp,#66                   @*au1_src_left_tmp
    ++    LDR         r4,[sp,#ht_offset]          @Loads ht
    ++    LDR         r7,[sp,#wd_offset]          @Loads wd
    ++    LDR         r8,[sp,#148]                @Loads *pu1_src
    +     SUB         r7,r7,#1                    @(wd - 1)
    +     ADD         r7,r8,r7                    @pu1_src[0 * src_strd + (wd - 1)]
    +     SUB         r5,r5,#1
    +@@ -747,7 +760,7 @@ PU1_SRC_LOOP_RESIDUE:
    +     VLD1.8      D16,[r8]!                   @pu1_next_row = vld1q_u8(pu1_src_cpy + src_strd)
    +     VLD1.8      D17,[r8]                    @pu1_next_row = vld1q_u8(pu1_src_cpy + src_strd)
    +     SUB         r8,#8
    +-    LDR         r5,[sp,#0xC8]               @Loads pu1_avail
    ++    LDR         r5,[sp,#pu1_avail_offset]   @Loads pu1_avail
    +     LDRB        r5,[r5,#3]                  @pu1_avail[3]
    +     CMP         r5,#0
    +     BEQ         NEXT_ROW_ELSE_RESIDUE
    +@@ -766,7 +779,7 @@ NEXT_ROW_POINTER_ASSIGNED_RESIDUE:
    + 
    +     CMP         r7,r12
    +     BNE         SIGN_UP_CHANGE_RESIDUE
    +-    LDR         r5,[sp,#0xC8]               @Loads pu1_avail
    ++    LDR         r5,[sp,#pu1_avail_offset]   @Loads pu1_avail
    +     LDRB        r5,[r5,#2]                  @pu1_avail[2]
    +     CMP         r5,#0
    +     BNE         SIGN_UP_CHANGE_DONE_RESIDUE
    +@@ -810,9 +823,9 @@ SIGN_UP_CHANGE_DONE_RESIDUE:
    +     SUBS        r7,r7,#1
    +     BNE         PU1_SRC_LOOP_RESIDUE
    + 
    +-    LDR         r8,[sp,#0xD4]               @Loads ht
    +-    LDR         r2,[sp,#0xC4]               @Loads *pu1_src_left
    +-    ADD         r5,sp,#0x42                 @*au1_src_left_tmp
    ++    LDR         r8,[sp,#ht_offset]          @Loads ht
    ++    LDR         r2,[sp,#152]                @Loads *pu1_src_left
    ++    ADD         r5,sp,#66                   @*au1_src_left_tmp
    + 
    + SRC_LEFT_LOOP_RESIDUE:
    +     LDR         r7,[r5],#4                  @au1_src_left_tmp[row]
    +@@ -822,24 +835,24 @@ SRC_LEFT_LOOP_RESIDUE:
    + 
    + 
    + RE_ASSINING_LOOP:
    +-    LDR         r7,[sp,#0xD0]               @Loads wd
    +-    LDR         r0,[sp,#0xC0]               @Loads *pu1_src
    ++    LDR         r7,[sp,#wd_offset]          @Loads wd
    ++    LDR         r0,[sp,#148]                @Loads *pu1_src
    + 
    +-    LDR         r11,[sp,#0xD4]              @Loads ht
    ++    LDR         r11,[sp,#ht_offset]         @Loads ht
    +     ADD         r8,r0,r7                    @pu1_src[wd]
    + 
    +-    LDR         r4,[sp,#0xBC]               @Loads pu1_src_top_left
    ++    LDR         r4,[sp,#pu1_src_top_left_offset]    @Loads pu1_src_top_left
    +     SUB         r11,r11,#1                  @ht - 1
    + 
    +     STRB        r9,[r8,#-1]                 @pu1_src_org[wd - 1] = u1_pos_wd_0_tmp
    +     MLA         r6,r11,r1,r0                @pu1_src_org[(ht - 1) * src_strd]
    + 
    +     LDRB        r8,[sp]                     @load u1_src_top_left_tmp from stack pointer
    +-    ADD         r12,sp,#0x02
    ++    ADD         r12,sp,#2
    + 
    +     STRB        r10,[r6]                    @pu1_src_org[wd - 1 + (ht - 1) * src_strd] = u1_pos_wd_ht_tmp
    +     STRB        r8,[r4]                     @*pu1_src_top_left = u1_src_top_left_tmp
    +-    LDR         r3,[sp,#0xCC]               @Loads pu1_src_top
    ++    LDR         r3,[sp,#156]                @Loads pu1_src_top
    + 
    + SRC_TOP_LOOP:
    +     VLD1.8      D0,[r12]!                   @pu1_src_top[col] = au1_src_top_tmp[col]
    +@@ -848,7 +861,8 @@ SRC_TOP_LOOP:
    +     BNE         SRC_TOP_LOOP
    + 
    + END_LOOPS:
    +-    ADD         sp,sp,#0x94
    ++    ADD         sp,sp,#160
    ++    vpop        {d8  -  d15}
    +     LDMFD       sp!,{r4-r12,r15}            @Reload the registers from SP
    + 
    + 
    +diff --git a/common/arm/ihevc_sao_edge_offset_class3_chroma.s b/common/arm/ihevc_sao_edge_offset_class3_chroma.s
    +index 62f40d1..9f4eb62 100644
    +--- a/common/arm/ihevc_sao_edge_offset_class3_chroma.s
    ++++ b/common/arm/ihevc_sao_edge_offset_class3_chroma.s
    +@@ -60,6 +60,15 @@
    + @r7 =>  wd
    + @r8=>   ht
    + 
    ++.equ    pu1_src_top_left_offset,    328
    ++.equ    pu1_src_top_right_offset,   332
    ++.equ    pu1_src_bot_left_offset,    336
    ++.equ    pu1_avail_offset,           340
    ++.equ    pi1_sao_u_offset,           344
    ++.equ    pi1_sao_v_offset,           348
    ++.equ    wd_offset,                  352
    ++.equ    ht_offset,                  356
    ++
    + .text
    + .syntax unified
    + .p2align 2
    +@@ -86,21 +95,22 @@ ihevc_sao_edge_offset_class3_chroma_a9q:
    + 
    + 
    +     STMFD       sp!,{r4-r12,r14}            @stack stores the values of the arguments
    ++    vpush       {d8  -  d15}
    ++    SUB         sp,sp,#224                  @Decrement the stack pointer to store some temp arr values
    + 
    +-    LDR         r7,[sp,#0x40]               @Loads wd
    +-    LDR         r8,[sp,#0x44]               @Loads ht
    ++    LDR         r7,[sp,#wd_offset]          @Loads wd
    ++    LDR         r8,[sp,#ht_offset]          @Loads ht
    +     SUB         r9,r7,#2                    @wd - 2
    + 
    +-    LDR         r4,[sp,#0x28]               @Loads pu1_src_top_left
    ++    LDR         r4,[sp,#pu1_src_top_left_offset]    @Loads pu1_src_top_left
    +     LDRH        r10,[r3,r9]                 @pu1_src_top[wd - 2]
    + 
    +     MOV         r9,r7                       @Move width to r9 for loop count
    + 
    +-    LDR         r5,[sp,#0x34]               @Loads pu1_avail
    +-    LDR         r6,[sp,#0x38]               @Loads pi1_sao_offset_u
    ++    LDR         r5,[sp,#pu1_avail_offset]   @Loads pu1_avail
    ++    LDR         r6,[sp,#pi1_sao_u_offset]   @Loads pi1_sao_offset_u
    + 
    +-    STR         r3,[sp,#0x38]               @Store pu1_src_top in sp
    +-    SUB         sp,sp,#0xD4                 @Decrement the stack pointer to store some temp arr values
    ++    STR         r3,[sp,#220]                @Store pu1_src_top in sp
    + 
    +     STRH        r10,[sp]                    @u1_src_top_left_tmp = pu1_src_top[wd - 2]
    +     SUB         r10,r8,#1                   @ht-1
    +@@ -122,7 +132,7 @@ PU1_AVAIL_5_LOOP_U:
    +     LDRB        r10,[r0,r11]                @u1_pos_0_0_tmp_v = pu1_src[wd - 1]
    +     BEQ         PU1_AVAIL_6_LOOP_U
    + 
    +-    LDR         r11,[sp,#0x100]             @Load pu1_src_top_right from sp
    ++    LDR         r11,[sp,#pu1_src_top_right_offset]  @Load pu1_src_top_right from sp
    +     LDRB        r11,[r11]                   @pu1_src_top_right[0]
    +     SUB         r12,r9,r11                  @pu1_src[wd - 2] - pu1_src_top_right[0]
    +     CMP         r12,#0
    +@@ -150,7 +160,7 @@ ulbl1:
    + 
    + PU1_AVAIL_5_LOOP_V:
    + 
    +-    LDR         r11,[sp,#0x100]             @Load pu1_src_top_right from sp
    ++    LDR         r11,[sp,#pu1_src_top_right_offset]  @Load pu1_src_top_right from sp
    +     LDRB        r11,[r11,#1]                @pu1_src_top_right[1]
    +     SUB         r12,r10,r11                 @pu1_src[wd - 1] - pu1_src_top_right[1]
    +     CMP         r12,#0
    +@@ -172,7 +182,7 @@ ulbl2:
    +     LDRSB       r12,[r14,r11]               @edge_idx = gi1_table_edge_idx[edge_idx]
    +     CMP         r12,#0                      @0 != edge_idx
    +     BEQ         PU1_AVAIL_6_LOOP_U
    +-    LDR         r11,[sp,#0x110]             @Loads pi1_sao_offset_v
    ++    LDR         r11,[sp,#pi1_sao_v_offset]  @Loads pi1_sao_offset_v
    +     LDRSB       r11,[r11,r12]               @pi1_sao_offset_v[edge_idx]
    +     ADD         r10,r10,r11                 @pu1_src[wd - 1] + pi1_sao_offset_v[edge_idx]
    +     USAT        r10,#8,r10                  @u1_pos_0_0_tmp_v = CLIP3(pu1_src[wd - 1] + pi1_sao_offset_v[edge_idx], 0, (1 << bit_depth) - 1)
    +@@ -180,7 +190,7 @@ ulbl2:
    + PU1_AVAIL_6_LOOP_U:
    +     STRB        r9,[sp,#6]
    +     STRB        r10,[sp,#7]
    +-    STR         r0,[sp,#0x100]              @Store pu1_src in sp
    ++    STR         r0,[sp,#212]                @Store pu1_src in sp
    + 
    +     LDRB        r10,[r5,#6]                 @pu1_avail[6]
    +     CMP         r10,#0
    +@@ -198,7 +208,7 @@ PU1_AVAIL_6_LOOP_U:
    +     MVNLT       r11,#0
    +     MOVGT       r11,#1                      @SIGN(pu1_src[(ht - 1) * src_strd] - pu1_src[(ht - 1) * src_strd +  2 - src_strd])
    + 
    +-    LDR         r14,[sp,#0x104]             @Load pu1_src_bot_left from sp
    ++    LDR         r14,[sp,#pu1_src_bot_left_offset]   @Load pu1_src_bot_left from sp
    +     LDRB        r14,[r14]                   @Load pu1_src_bot_left[0]
    +     SUB         r14,r10,r14                 @pu1_src[(ht - 1) * src_strd] - pu1_src_bot_left[0]
    +     CMP         r14,#0
    +@@ -228,7 +238,7 @@ PU1_AVAIL_6_LOOP_V:
    +     MVNLT       r11,#0
    +     MOVGT       r11,#1                      @SIGN(pu1_src[(ht - 1) * src_strd + 1] - pu1_src[(ht - 1) * src_strd + 1 + 2 - src_strd])
    + 
    +-    LDR         r14,[sp,#0x104]             @Load pu1_src_bot_left from sp
    ++    LDR         r14,[sp,#pu1_src_bot_left_offset]   @Load pu1_src_bot_left from sp
    +     LDRB        r14,[r14,#1]                @Load pu1_src_bot_left[1]
    +     SUB         r14,r9,r14                  @pu1_src[(ht - 1) * src_strd + 1] - pu1_src_bot_left[1]
    +     CMP         r14,#0
    +@@ -244,7 +254,7 @@ ulbl4:
    +     LDRSB       r12,[r14,r11]               @edge_idx = gi1_table_edge_idx[edge_idx]
    +     CMP         r12,#0
    +     BEQ         PU1_AVAIL_3_LOOP
    +-    LDR         r14,[sp,#0x110]             @Loads pi1_sao_offset_v
    ++    LDR         r14,[sp,#pi1_sao_v_offset]  @Loads pi1_sao_offset_v
    +     LDRSB       r11,[r14,r12]               @pi1_sao_offset_v[edge_idx]
    +     ADD         r9,r9,r11                   @pu1_src[(ht - 1) * src_strd] + pi1_sao_offset[edge_idx]
    +     USAT        r9,#8,r9                    @u1_pos_wd_ht_tmp_v = CLIP3(pu1_src[(ht - 1) * src_strd] + pi1_sao_offset[edge_idx], 0, (1 << bit_depth) - 1)
    +@@ -252,7 +262,7 @@ ulbl4:
    + PU1_AVAIL_3_LOOP:
    +     STRB        r10,[sp,#8]
    +     STRB        r9,[sp,#9]
    +-    STR         r2,[sp,#0x104]              @Store pu1_src_left in sp
    ++    STR         r2,[sp,#216]                @Store pu1_src_left in sp
    + 
    +     MOV         r12,r8                      @Move ht
    +     MOV         r14,r2                      @Move pu1_src_left to pu1_src_left_cpy
    +@@ -276,7 +286,7 @@ PU1_AVAIL_2_LOOP_END:
    +     VMOV.I16    Q1,#0                       @const_min_clip = vdupq_n_s16(0)
    +     VMOV.I16    Q2,#255                     @const_max_clip = vdupq_n_u16((1 << bit_depth) - 1)
    +     VLD1.8      D6,[r6]                     @offset_tbl_u = vld1_s8(pi1_sao_offset_u)
    +-    LDR         r6,[sp,#0x110]              @Loads pi1_sao_offset_v
    ++    LDR         r6,[sp,#pi1_sao_v_offset]   @Loads pi1_sao_offset_v
    +     VLD1.8      D7,[r6]                     @offset_tbl_v = vld1_s8(pi1_sao_offset_v)
    +     LDR         r2, gi1_table_edge_idx_addr_5 @table pointer
    + ulbl5:
    +@@ -291,9 +301,9 @@ ulbl5:
    +     BLE         WD_16_HT_4_LOOP             @If jump to WD_16_HT_4_LOOP
    + 
    + WIDTH_LOOP_16:
    +-    LDR         r7,[sp,#0x114]              @Loads wd
    ++    LDR         r7,[sp,#wd_offset]          @Loads wd
    +     CMP         r6,r7                       @col == wd
    +-    LDR         r5,[sp,#0x108]              @Loads pu1_avail
    ++    LDR         r5,[sp,#pu1_avail_offset]   @Loads pu1_avail
    + 
    +     LDRBEQ      r8,[r5]                     @pu1_avail[0]
    +     MOVNE       r8,#-1
    +@@ -314,7 +324,7 @@ SKIP_AU1_MASK_VAL:
    +     VLD1.8      D12,[r0]!                   @pu1_cur_row = vld1q_u8(pu1_src)
    +     VLD1.8      D13,[r0]                    @pu1_cur_row = vld1q_u8(pu1_src)
    +     SUB         r0,#8
    +-    ADD         r5,sp,#0x4B                 @*au1_src_left_tmp
    ++    ADD         r5,sp,#75                   @*au1_src_left_tmp
    + 
    +     SUBEQ       r8,r0,r1                    @pu1_src - src_strd
    +     VMOV.I8     Q9,#0
    +@@ -326,15 +336,15 @@ SKIP_AU1_MASK_VAL:
    +     SUB         r8,#8
    +     ADD         r3,r3,#16
    + 
    +-    LDR         r4,[sp,#0x118]              @Loads ht
    ++    LDR         r4,[sp,#ht_offset]          @Loads ht
    +     VCGT.U8     Q7,Q6,Q5                    @vcgtq_u8(pu1_cur_row, pu1_top_row)
    +-    LDR         r7,[sp,#0x114]              @Loads wd
    ++    LDR         r7,[sp,#wd_offset]          @Loads wd
    + 
    +     SUB         r7,r7,r6                    @(wd - col)
    +     VCLT.U8     Q8,Q6,Q5                    @vcltq_u8(pu1_cur_row, pu1_top_row)
    +     ADD         r7,r7,#14                   @15 + (wd - col)
    + 
    +-    LDR         r8,[sp,#0x100]              @Loads *pu1_src
    ++    LDR         r8,[sp,#212]                @Loads *pu1_src
    +     VSUB.U8     Q7,Q8,Q7                    @sign_up = vreinterpretq_s8_u8(vsubq_u8(cmp_lt, cmp_gt))
    +     ADD         r7,r8,r7                    @pu1_src[0 * src_strd + 15 + (wd - col)]
    + 
    +@@ -359,7 +369,7 @@ AU1_SRC_LEFT_LOOP:
    + 
    +     LDRH        r5,[r8,#2]                  @I
    +     VMOV.16     D19[3],r5                   @I vsetq_lane_u8
    +-    LDR         r11,[sp,#0x108]             @I Loads pu1_avail
    ++    LDR         r11,[sp,#pu1_avail_offset]  @I Loads pu1_avail
    + 
    +     LDRB        r11,[r11,#2]                @I pu1_avail[2]
    +     VEXT.8      Q9,Q9,Q8,#14                @I pu1_next_row_tmp = vextq_u8(pu1_next_row_tmp, pu1_next_row, 14)
    +@@ -477,7 +487,7 @@ PU1_SRC_LOOP:
    +     VCGT.U8     Q11,Q6,Q14                  @II vcgtq_u8(pu1_cur_row, pu1_next_row_tmp)
    +     BNE         NEXT_ROW_POINTER_ASSIGNED_2 @III
    + 
    +-    LDR         r5,[sp,#0x108]              @III Loads pu1_avail
    ++    LDR         r5,[sp,#pu1_avail_offset]   @III Loads pu1_avail
    +     LDRB        r5,[r5,#3]                  @III pu1_avail[3]
    +     CMP         r5,#0                       @III
    +     SUBNE       r11,r4,#4                   @III pu1_src[src_strd - 2]
    +@@ -597,7 +607,7 @@ NEXT_ROW_POINTER_ASSIGNED_2:
    +     LDRB        r9,[r0,#17]                 @load the value pu1_src_cpy[17 - src_strd]
    + 
    +     BNE         NEXT_ROW_POINTER_ASSIGNED_3
    +-    LDR         r5,[sp,#0x108]              @Loads pu1_avail
    ++    LDR         r5,[sp,#pu1_avail_offset]   @Loads pu1_avail
    +     LDRB        r5,[r5,#3]                  @pu1_avail[3]
    +     CMP         r5,#0
    +     SUBNE       r8,r11,#4                   @pu1_src[src_strd - 2]
    +@@ -657,13 +667,13 @@ NEXT_ROW_POINTER_ASSIGNED_3:
    + 
    + INNER_LOOP_DONE:
    + 
    +-    LDR         r8,[sp,#0x118]              @Loads ht
    ++    LDR         r8,[sp,#ht_offset]          @Loads ht
    +     VMOVN.I16   D20,Q10                     @III vmovn_s16(pi2_tmp_cur_row.val[0])
    +-    ADD         r5,sp,#0x4B                 @*au1_src_left_tmp
    ++    ADD         r5,sp,#75                   @*au1_src_left_tmp
    + 
    +     LSL         r8,r8,#1
    +     VMOVN.I16   D21,Q9                      @III vmovn_s16(pi2_tmp_cur_row.val[1])
    +-    LDR         r11,[sp,#0x104]             @Loads *pu1_src_left
    ++    LDR         r11,[sp,#216]               @Loads *pu1_src_left
    + 
    + SRC_LEFT_LOOP:
    +     LDR         r7,[r5],#4                  @au1_src_left_tmp[row]
    +@@ -676,7 +686,7 @@ SRC_LEFT_LOOP:
    +     CMP         r6,#8                       @Check whether residue remains
    + 
    +     BLT         RE_ASSINING_LOOP            @Jump to re-assigning loop
    +-    LDR         r7,[sp,#0x114]              @Loads wd
    ++    LDR         r7,[sp,#wd_offset]          @Loads wd
    +     LDR         r0,[sp,#0x02]               @Loads *pu1_src
    +     SUB         r7,r7,r6
    +     ADD         r0,r0,r7
    +@@ -684,9 +694,9 @@ SRC_LEFT_LOOP:
    +     BEQ         WIDTH_RESIDUE               @If residue remains jump to residue loop
    + 
    + WD_16_HT_4_LOOP:
    +-    LDR         r7,[sp,#0x114]              @Loads wd
    ++    LDR         r7,[sp,#wd_offset]          @Loads wd
    + 
    +-    LDR         r5,[sp,#0x108]              @Loads pu1_avail
    ++    LDR         r5,[sp,#pu1_avail_offset]   @Loads pu1_avail
    +     CMP         r6,r7                       @col == wd
    + 
    +     LDRBEQ      r8,[r5]                     @pu1_avail[0]
    +@@ -716,17 +726,17 @@ SKIP_AU1_MASK_VAL_WD_16_HT_4:
    +     VLD1.8      D10,[r8]!                   @pu1_top_row = vld1q_u8(pu1_src - src_strd + 2)
    +     VLD1.8      D11,[r8]                    @pu1_top_row = vld1q_u8(pu1_src - src_strd + 2)
    +     SUB         r8,#8
    +-    ADD         r5,sp,#0x4B                 @*au1_src_left_tmp
    ++    ADD         r5,sp,#75                   @*au1_src_left_tmp
    + 
    +-    LDR         r4,[sp,#0x118]              @Loads ht
    ++    LDR         r4,[sp,#ht_offset]          @Loads ht
    +     VCGT.U8     Q7,Q6,Q5                    @vcgtq_u8(pu1_cur_row, pu1_top_row)
    +-    LDR         r7,[sp,#0x114]              @Loads wd
    ++    LDR         r7,[sp,#wd_offset]          @Loads wd
    + 
    +     SUB         r7,r7,r6                    @(wd - col)
    +     VCLT.U8     Q8,Q6,Q5                    @vcltq_u8(pu1_cur_row, pu1_top_row)
    +     ADD         r7,r7,#14                   @15 + (wd - col)
    + 
    +-    LDR         r8,[sp,#0x100]              @Loads *pu1_src
    ++    LDR         r8,[sp,#212]                @Loads *pu1_src
    +     VSUB.U8     Q7,Q8,Q7                    @sign_up = vreinterpretq_s8_u8(vsubq_u8(cmp_lt, cmp_gt))
    +     ADD         r7,r8,r7                    @pu1_src[0 * src_strd + 15 + (wd - col)]
    + 
    +@@ -744,7 +754,7 @@ AU1_SRC_LEFT_LOOP_WD_16_HT_4:
    + PU1_SRC_LOOP_WD_16_HT_4:
    +     ADD         r9,r0,r1                    @*pu1_src + src_strd
    + 
    +-    LDR         r5,[sp,#0x108]              @Loads pu1_avail
    ++    LDR         r5,[sp,#pu1_avail_offset]   @Loads pu1_avail
    +     VLD1.8      D16,[r9]!                   @pu1_next_row = vld1q_u8(pu1_src_cpy + src_strd)
    +     VLD1.8      D17,[r9]                    @pu1_next_row = vld1q_u8(pu1_src_cpy + src_strd)
    +     SUB         r9,#8
    +@@ -766,7 +776,7 @@ NEXT_ROW_POINTER_ASSIGNED_WD_16_HT_4:
    + 
    +     CMP         r7,r12
    +     BLT         SIGN_UP_CHANGE_WD_16_HT_4
    +-    LDR         r5,[sp,#0x108]              @Loads pu1_avail
    ++    LDR         r5,[sp,#pu1_avail_offset]   @Loads pu1_avail
    +     LDRB        r5,[r5,#2]                  @pu1_avail[2]
    +     CMP         r5,#0
    +     BNE         SIGN_UP_CHANGE_DONE_WD_16_HT_4
    +@@ -839,9 +849,9 @@ SIGN_UP_CHANGE_DONE_WD_16_HT_4:
    +     VST1.8      {Q14},[r0],r1               @vst1q_u8(pu1_src_cpy, pu1_cur_row)
    +     BNE         PU1_SRC_LOOP_WD_16_HT_4     @If not equal jump to PU1_SRC_LOOP_WD_16_HT_4
    + 
    +-    LDR         r8,[sp,#0x118]              @Loads ht
    +-    ADD         r5,sp,#0x4B                 @*au1_src_left_tmp
    +-    LDR         r11,[sp,#0x104]             @Loads *pu1_src_left
    ++    LDR         r8,[sp,#ht_offset]          @Loads ht
    ++    ADD         r5,sp,#75                   @*au1_src_left_tmp
    ++    LDR         r11,[sp,#216]               @Loads *pu1_src_left
    + 
    + SRC_LEFT_LOOP_WD_16_HT_4:
    +     LDR         r7,[r5],#4                  @au1_src_left_tmp[row]
    +@@ -851,12 +861,16 @@ SRC_LEFT_LOOP_WD_16_HT_4:
    + 
    +     SUBS        r6,r6,#16                   @Decrement the wd loop count by 16
    +     BLE         RE_ASSINING_LOOP            @Jump to re-assigning loop
    ++    LDR         r7,[sp,#wd_offset]          @Loads wd
    ++    LDR         r0,[sp,#0x02]               @Loads *pu1_src
    ++    SUB         r7,r7,r6
    ++    ADD         r0,r0,r7
    +     BGT         WD_16_HT_4_LOOP             @If not equal jump to width_loop
    + 
    + WIDTH_RESIDUE:
    +-    LDR         r7,[sp,#0x114]              @Loads wd
    ++    LDR         r7,[sp,#wd_offset]          @Loads wd
    + 
    +-    LDR         r5,[sp,#0x108]              @Loads pu1_avail
    ++    LDR         r5,[sp,#pu1_avail_offset]   @Loads pu1_avail
    +     CMP         r6,r7                       @wd_residue == wd
    + 
    +     LDRBEQ      r8,[r5]                     @pu1_avail[0]
    +@@ -874,13 +888,13 @@ WIDTH_RESIDUE:
    + 
    +     ADD         r10,r10,#2                  @pu1_src - src_strd + 2
    +     VMOV.8      d8[6],r11                   @au1_mask = vsetq_lane_s8(pu1_avail[1], au1_mask, 15)
    +-    ADD         r5,sp,#0x4B                 @*au1_src_left_tmp
    ++    ADD         r5,sp,#75                   @*au1_src_left_tmp
    + 
    +-    LDR         r4,[sp,#0x118]              @Loads ht
    ++    LDR         r4,[sp,#ht_offset]          @Loads ht
    +     VMOV.8      d8[7],r11                   @au1_mask = vsetq_lane_s8(pu1_avail[1], au1_mask, 15)
    +-    LDR         r7,[sp,#0x114]              @Loads wd
    ++    LDR         r7,[sp,#wd_offset]          @Loads wd
    + 
    +-    LDR         r8,[sp,#0x100]              @Loads *pu1_src
    ++    LDR         r8,[sp,#212]                @Loads *pu1_src
    +     VLD1.8      D10,[r10]!                  @pu1_top_row = vld1q_u8(pu1_src - src_strd + 2)
    +     VLD1.8      D11,[r10]                   @pu1_top_row = vld1q_u8(pu1_src - src_strd + 2)
    +     SUB         r10,#8
    +@@ -913,7 +927,7 @@ PU1_SRC_LOOP_RESIDUE:
    +     VLD1.8      D16,[r9]!                   @pu1_next_row = vld1q_u8(pu1_src_cpy + src_strd)
    +     VLD1.8      D17,[r9]                    @pu1_next_row = vld1q_u8(pu1_src_cpy + src_strd)
    +     SUB         r9,#8
    +-    LDR         r5,[sp,#0x108]              @Loads pu1_avail
    ++    LDR         r5,[sp,#pu1_avail_offset]   @Loads pu1_avail
    + 
    +     LDRB        r5,[r5,#3]                  @pu1_avail[3]
    +     ADD         r8,r14,r11,LSL #1           @pu1_src_left_cpy[(ht_tmp - row) * 2]
    +@@ -936,7 +950,7 @@ NEXT_ROW_POINTER_ASSIGNED_RESIDUE:
    +     VEXT.8      Q9,Q9,Q8,#14                @pu1_next_row_tmp = vextq_u8(pu1_next_row_tmp, pu1_next_row, 14)
    + 
    +     BLT         SIGN_UP_CHANGE_RESIDUE
    +-    LDR         r5,[sp,#0x108]              @Loads pu1_avail
    ++    LDR         r5,[sp,#pu1_avail_offset]   @Loads pu1_avail
    +     LDRB        r5,[r5,#2]                  @pu1_avail[2]
    +     CMP         r5,#0
    +     BNE         SIGN_UP_CHANGE_DONE_RESIDUE
    +@@ -1003,10 +1017,10 @@ SIGN_UP_CHANGE_DONE_RESIDUE:
    + 
    +     BNE         PU1_SRC_LOOP_RESIDUE        @If not equal jump to PU1_SRC_LOOP
    + 
    +-    LDR         r8,[sp,#0x118]              @Loads ht
    +-    ADD         r5,sp,#0x4B                 @*au1_src_left_tmp
    ++    LDR         r8,[sp,#ht_offset]          @Loads ht
    ++    ADD         r5,sp,#75                   @*au1_src_left_tmp
    + 
    +-    LDR         r11,[sp,#0x104]             @Loads *pu1_src_left
    ++    LDR         r11,[sp,#216]               @Loads *pu1_src_left
    + 
    + SRC_LEFT_LOOP_RESIDUE:
    +     LDR         r7,[r5],#4                  @au1_src_left_tmp[row]
    +@@ -1016,10 +1030,10 @@ SRC_LEFT_LOOP_RESIDUE:
    + 
    + 
    + RE_ASSINING_LOOP:
    +-    LDR         r7,[sp,#0x114]              @Loads wd
    +-    LDR         r8,[sp,#0x118]              @Loads ht
    ++    LDR         r7,[sp,#wd_offset]          @Loads wd
    ++    LDR         r8,[sp,#ht_offset]          @Loads ht
    + 
    +-    LDR         r0,[sp,#0x100]              @Loads *pu1_src
    ++    LDR         r0,[sp,#212]                @Loads *pu1_src
    +     SUB         r10,r7,#2                   @wd - 2
    + 
    +     LDRH        r9,[sp,#6]
    +@@ -1028,7 +1042,7 @@ RE_ASSINING_LOOP:
    +     STRH        r9,[r0,r10]                 @pu1_src_org[0] = u1_pos_0_0_tmp
    +     MLA         r6,r8,r1,r0                 @pu1_src[(ht - 1) * src_strd]
    + 
    +-    LDR         r4,[sp,#0xFC]               @Loads pu1_src_top_left
    ++    LDR         r4,[sp,#pu1_src_top_left_offset]               @Loads pu1_src_top_left
    + 
    +     LDRH        r9,[sp,#8]
    +     ADD         r12,sp,#10
    +@@ -1037,7 +1051,7 @@ RE_ASSINING_LOOP:
    + 
    +     LDRH        r10,[sp]                    @load u1_src_top_left_tmp from stack pointer
    +     STRH        r10,[r4]                    @*pu1_src_top_left = u1_src_top_left_tmp
    +-    LDR         r3,[sp,#0x10C]              @Loads pu1_src_top
    ++    LDR         r3,[sp,#220]                @Loads pu1_src_top
    + 
    + SRC_TOP_LOOP:
    +     VLD1.8      D0,[r12]!                   @pu1_src_top[col] = au1_src_top_tmp[col]
    +@@ -1046,7 +1060,8 @@ SRC_TOP_LOOP:
    +     BNE         SRC_TOP_LOOP
    + 
    + END_LOOPS:
    +-    ADD         sp,sp,#0xD4
    ++    ADD         sp,sp,#224
    ++    vpop        {d8  -  d15}
    +     LDMFD       sp!,{r4-r12,r15}            @Reload the registers from SP
    + 
    + 
    +diff --git a/common/arm/ihevc_weighted_pred_bi.s b/common/arm/ihevc_weighted_pred_bi.s
    +index 5308423..8845b8b 100644
    +--- a/common/arm/ihevc_weighted_pred_bi.s
    ++++ b/common/arm/ihevc_weighted_pred_bi.s
    +@@ -134,6 +134,18 @@
    + @   r14 =>  ht
    + @   r7  =>  wd
    + 
    ++.equ    src_strd2_offset,       104
    ++.equ    dst_strd_offset,        108
    ++.equ    wgt0_offset,            112
    ++.equ    off0_offset,            116
    ++.equ    wgt1_offset,            120
    ++.equ    off1_offset,            124
    ++.equ    shift_offset,           128
    ++.equ    lvl_shift1_offset,      132
    ++.equ    lvl_shift2_offset,      136
    ++.equ    ht_offset,              140
    ++.equ    wd_offset,              144
    ++
    + .text
    + .align 4
    + 
    +@@ -147,32 +159,33 @@
    + ihevc_weighted_pred_bi_a9q:
    + 
    +     stmfd       sp!, {r4-r12, r14}          @stack stores the values of the arguments
    ++    vpush       {d8  -  d15}
    + 
    +-    ldr         r6,[sp,#48]                 @load wgt0
    +-    ldr         r11,[sp,#68]                @load lvl_shift1
    +-    ldr         r12,[sp,#72]                @load lvl_shift2
    ++    ldr         r6,[sp,#wgt0_offset]        @load wgt0
    ++    ldr         r11,[sp,#lvl_shift1_offset] @load lvl_shift1
    ++    ldr         r12,[sp,#lvl_shift2_offset] @load lvl_shift2
    +     vmov.s16    d7[0],r6                    @moved for scalar multiplication
    +     mul         r4,r11,r6                   @lvl_shift1 * wgt0
    +-    ldr         r8,[sp,#56]                 @load wgt1
    +-    ldr         r7,[sp,#52]                 @load off0
    ++    ldr         r8,[sp,#wgt1_offset]        @load wgt1
    ++    ldr         r7,[sp,#off0_offset]        @load off0
    +     vmov.s16    d7[1],r8                    @moved for scalar multiplication
    +     mla         r4,r12,r8,r4                @(lvl_shift1 * wgt0) + (lvl_shift2 * wgt1)
    +-    ldr         r9,[sp,#60]                 @load off1
    ++    ldr         r9,[sp,#off1_offset]        @load off1
    +     add         r5,r7,r9                    @off0 + off1
    +-    ldr         r10,[sp,#64]                @load shift
    ++    ldr         r10,[sp,#shift_offset]      @load shift
    +     add         r5,r5,#1                    @off0 + off1 + 1
    +     sub         r14,r10,#1                  @shift - 1
    +-    ldr         r7,[sp,#80]                 @load wd
    ++    ldr         r7,[sp,#wd_offset]          @load wd
    +     lsl         r5,r5,r14                   @((off0 + off1 + 1) << (shift - 1))
    +     vdup.u32    q14,r10                     @vmovq_n_s32(0-shift)
    +     add         r4,r4,r5                    @tmp_lvl_shift += ((off0 + off1 + 1) << (shift - 1))
    +     vdup.u32    q15,r4                      @vmovq_n_s32(tmp_lvl_shift)
    +     vneg.s32    q14,q14
    +-    ldr         r4,[sp,#40]                 @load src_strd2
    ++    ldr         r4,[sp,#src_strd2_offset]   @load src_strd2
    +     lsl         r9,r7,#1
    +-    ldr         r5,[sp,#44]                 @load dst_strd
    ++    ldr         r5,[sp,#dst_strd_offset]    @load dst_strd
    +     lsl         r3,r3,#1
    +-    ldr         r14,[sp,#76]                @load ht
    ++    ldr         r14,[sp,#ht_offset]         @load ht
    +     lsl         r4,r4,#1
    + 
    +     cmp         r14,#0                      @check ht == 0
    +@@ -260,6 +273,7 @@ end_core_loop:
    +     bgt         core_loop                   @if ht is greater than 0 goto outer_loop
    + 
    + end_loops:
    ++    vpop        {d8  -  d15}
    +     ldmfd       sp!,{r4-r12,r15}            @reload the registers from sp
    + 
    + 
    +diff --git a/common/arm/ihevc_weighted_pred_bi_default.s b/common/arm/ihevc_weighted_pred_bi_default.s
    +index 6bdb8cc..5b369be 100644
    +--- a/common/arm/ihevc_weighted_pred_bi_default.s
    ++++ b/common/arm/ihevc_weighted_pred_bi_default.s
    +@@ -107,6 +107,14 @@
    + @   r7 =>  lvl_shift2
    + @   r8 =>  ht
    + @   r9 =>  wd
    ++
    ++.equ    src_strd2_offset,       104
    ++.equ    dst_strd_offset,        108
    ++.equ    lvl_shift1_offset,      112
    ++.equ    lvl_shift2_offset,      116
    ++.equ    ht_offset,              120
    ++.equ    wd_offset,              124
    ++
    + .text
    + .syntax unified
    + .align 4
    +@@ -121,14 +129,15 @@
    + ihevc_weighted_pred_bi_default_a9q:
    + 
    +     stmfd       sp!, {r4-r12, r14}          @stack stores the values of the arguments
    +-    ldr         r4,[sp,#40]                 @load src_strd2
    ++    vpush       {d8  -  d15}
    ++    ldr         r4,[sp,#src_strd2_offset]   @load src_strd2
    +     lsl         r3,r3,#1
    +-    ldr         r5,[sp,#44]                 @load dst_strd
    +-    ldr         r6,[sp,#48]                 @load lvl_shift1
    ++    ldr         r5,[sp,#dst_strd_offset]    @load dst_strd
    ++    ldr         r6,[sp,#lvl_shift1_offset]  @load lvl_shift1
    +     lsl         r4,r4,#1
    +-    ldr         r7,[sp,#52]                 @load lvl_shift2
    +-    ldr         r8,[sp,#56]                 @load ht
    +-    ldr         r9,[sp,#60]                 @load wd
    ++    ldr         r7,[sp,#lvl_shift2_offset]  @load lvl_shift2
    ++    ldr         r8,[sp,#ht_offset]          @load ht
    ++    ldr         r9,[sp,#wd_offset]          @load wd
    +     vdup.16     q2,r6                       @lvl_shift1_t = vmov_n_s16((int16_t)lvl_shift1)
    +     vdup.16     q3,r7                       @lvl_shift2_t = vmov_n_s16((int16_t)lvl_shift2)
    +     vmov.i16    q0,#0x40                    @tmp_lvl_shift = 1 << (shift - 1)
    +@@ -488,6 +497,7 @@ end_core_loop_16:
    + 
    + 
    + end_loops:
    ++    vpop        {d8  -  d15}
    +     ldmfd       sp!,{r4-r12,r15}            @reload the registers from sp
    + 
    + 
    +diff --git a/common/arm/ihevc_weighted_pred_uni.s b/common/arm/ihevc_weighted_pred_uni.s
    +index e9b69c1..1f99ff8 100644
    +--- a/common/arm/ihevc_weighted_pred_uni.s
    ++++ b/common/arm/ihevc_weighted_pred_uni.s
    +@@ -112,6 +112,13 @@
    + @   r8 =>   ht
    + @   r9  =>  wd
    + 
    ++.equ    wgt0_offset,        104
    ++.equ    off0_offset,        108
    ++.equ    shift_offset,       112
    ++.equ    lvl_shift_offset,   116
    ++.equ    ht_offset,          120
    ++.equ    wd_offset,          124
    ++
    + .text
    + .align 4
    + 
    +@@ -125,16 +132,17 @@
    + ihevc_weighted_pred_uni_a9q:
    + 
    +     stmfd       sp!, {r4-r12, r14}          @stack stores the values of the arguments
    ++    vpush       {d8  -  d15}
    + 
    +-    ldr         r4,[sp,#40]                 @load wgt0
    +-    ldr         r7,[sp,#52]                 @load lvl_shift
    ++    ldr         r4,[sp,#wgt0_offset]        @load wgt0
    ++    ldr         r7,[sp,#lvl_shift_offset]   @load lvl_shift
    +     mov         r11,#1
    +-    ldr         r5,[sp,#44]                 @load off0
    ++    ldr         r5,[sp,#off0_offset]        @load off0
    +     mul         r10,r7,r4                   @lvl_shift * wgt0
    +-    ldr         r6,[sp,#48]                 @load shift
    +-    ldr         r8,[sp,#56]                 @load ht
    ++    ldr         r6,[sp,#shift_offset]       @load shift
    ++    ldr         r8,[sp,#ht_offset]          @load ht
    +     add         r10,r10,r5,lsl r6           @lvl_shift * wgt0 + (off0 << shift)
    +-    ldr         r9,[sp,#60]                 @load wt
    ++    ldr         r9,[sp,#wd_offset]          @load wt
    +     sub         r12,r6,#1
    +     vmov.s16    d0[0],r4                    @moved for scalar multiplication
    +     lsl         r2,r2,#1
    +@@ -214,6 +222,7 @@ end_core_loop:
    +     bgt         core_loop                   @if ht is greater than 0 goto outer_loop
    + 
    + end_loops:
    ++    vpop        {d8  -  d15}
    +     ldmfd       sp!,{r4-r12,r15}            @reload the registers from sp
    + 
    + 
     diff --git a/common/ihevc_structs.h b/common/ihevc_structs.h
     index 93d2ad4..baa6375 100644
     --- a/common/ihevc_structs.h
    @@ -79,10 +4035,18 @@ index c661083..2ae90b0 100644
              ps_codec->pu1_bitsbuf_dynamic = pv_buf;
              ps_codec->u4_bitsbuf_size_dynamic = size;
     diff --git a/decoder/ihevcd_decode.c b/decoder/ihevcd_decode.c
    -index d656519..04ad8f5 100644
    +index d656519..d2ea7a5 100644
     --- a/decoder/ihevcd_decode.c
     +++ b/decoder/ihevcd_decode.c
    -@@ -81,6 +81,7 @@
    +@@ -69,6 +69,7 @@
    + #include "ihevcd_fmt_conv.h"
    + #include "ihevcd_job_queue.h"
    + #include "ihevcd_debug.h"
    ++#include "ihevcd_parse_slice.h"
    + #include "ihevcd_process_slice.h"
    + #include "ihevcd_ittiam_logo.h"
    + #include "ihevcd_profile.h"
    +@@ -81,6 +82,7 @@
      #define NUM_FRAMES_LIMIT 0x7FFFFFFF
      #endif
      
    @@ -90,7 +4054,57 @@ index d656519..04ad8f5 100644
      IHEVCD_ERROR_T ihevcd_fmt_conv(codec_t *ps_codec,
                                     process_ctxt_t *ps_proc,
                                     UWORD8 *pu1_y_dst,
    -@@ -420,7 +421,8 @@ WORD32 ihevcd_decode(iv_obj_t *ps_codec_obj, void *pv_api_ip, void *pv_api_op)
    +@@ -203,6 +205,18 @@ static void ihevcd_fill_outargs(codec_t *ps_codec,
    + 
    +     ps_dec_op->u4_output_present = 0;
    +     ps_dec_op->u4_progressive_frame_flag = 1;
    ++    if(ps_codec->i4_sps_done)
    ++    {
    ++        sps_t *ps_sps = (ps_codec->s_parse.ps_sps_base + ps_codec->i4_sps_id);
    ++        profile_tier_lvl_info_t *ps_ptl;
    ++        ps_ptl = &ps_sps->s_ptl;
    ++        if((0 == ps_ptl->s_ptl_gen.i1_general_progressive_source_flag) &&
    ++           (1 == ps_ptl->s_ptl_gen.i1_general_interlaced_source_flag))
    ++        {
    ++            ps_dec_op->u4_progressive_frame_flag = 0;
    ++        }
    ++    }
    ++
    +     ps_dec_op->u4_is_ref_flag = 1;
    +     ps_dec_op->e_output_format = ps_codec->e_chroma_fmt;
    +     ps_dec_op->u4_is_ref_flag = 1;
    +@@ -224,7 +238,30 @@ static void ihevcd_fill_outargs(codec_t *ps_codec,
    +     if(ps_codec->ps_disp_buf)
    +     {
    +         pic_buf_t *ps_disp_buf = ps_codec->ps_disp_buf;
    ++        sei_params_t *ps_sei = &ps_disp_buf->s_sei_params;
    + 
    ++        if(ps_sei->i1_sei_parameters_present_flag &&
    ++           ps_sei->i1_pic_timing_params_present_flag)
    ++        {
    ++            UWORD32 u4_pic_struct;
    ++            u4_pic_struct = ps_sei->s_pic_timing_sei_params.u4_pic_struct;
    ++            switch(u4_pic_struct)
    ++            {
    ++                case 1:
    ++                    ps_dec_op->e4_fld_type = IV_TOP_FLD;
    ++                    ps_dec_op->u4_progressive_frame_flag = 0;
    ++                    break;
    ++                case 2:
    ++                    ps_dec_op->e4_fld_type = IV_BOT_FLD;
    ++                    ps_dec_op->u4_progressive_frame_flag = 0;
    ++                    break;
    ++                case 0:
    ++                default:
    ++                    ps_dec_op->e4_fld_type = IV_FLD_TYPE_DEFAULT;
    ++                    ps_dec_op->u4_progressive_frame_flag = 1;
    ++                    break;
    ++            }
    ++        }
    +         ps_dec_op->u4_output_present = 1;
    +         ps_dec_op->u4_ts = ps_disp_buf->u4_ts;
    +         if((ps_codec->i4_flush_mode == 0) && (ps_codec->s_parse.i4_end_of_frame == 0))
    +@@ -420,7 +457,8 @@ WORD32 ihevcd_decode(iv_obj_t *ps_codec_obj, void *pv_api_ip, void *pv_api_op)
          if(0 == ps_codec->i4_share_disp_buf && ps_codec->i4_header_mode == 0)
          {
              UWORD32 i;
    @@ -100,7 +4114,7 @@ index d656519..04ad8f5 100644
              {
                  ps_dec_op->u4_error_code |= 1 << IVD_UNSUPPORTEDPARAM;
                  ps_dec_op->u4_error_code |= IVD_DISP_FRM_ZERO_OP_BUFS;
    -@@ -471,6 +473,10 @@ WORD32 ihevcd_decode(iv_obj_t *ps_codec_obj, void *pv_api_ip, void *pv_api_op)
    +@@ -471,6 +509,10 @@ WORD32 ihevcd_decode(iv_obj_t *ps_codec_obj, void *pv_api_ip, void *pv_api_op)
                      ihevcd_init_proc_ctxt(ps_proc, 0);
                  }
      
    @@ -111,7 +4125,7 @@ index d656519..04ad8f5 100644
                  /* Set remaining number of rows to be processed */
                  ret = ihevcd_fmt_conv(ps_codec, &ps_codec->as_process[prev_proc_idx],
                                        ps_dec_ip->s_out_buffer.pu1_bufs[0],
    -@@ -628,7 +634,6 @@ WORD32 ihevcd_decode(iv_obj_t *ps_codec_obj, void *pv_api_ip, void *pv_api_op)
    +@@ -628,15 +670,13 @@ WORD32 ihevcd_decode(iv_obj_t *ps_codec_obj, void *pv_api_ip, void *pv_api_op)
      
              if(IHEVCD_IGNORE_SLICE == ret)
              {
    @@ -119,36 +4133,71 @@ index d656519..04ad8f5 100644
                  ps_codec->pu1_inp_bitsbuf += (nal_ofst + nal_len);
                  ps_codec->i4_bytes_remaining -= (nal_ofst + nal_len);
      
    +             continue;
    +         }
    + 
    +-        if((IVD_RES_CHANGED == ret) ||
    +-           (IHEVCD_UNSUPPORTED_DIMENSIONS == ret))
    ++        if(IVD_RES_CHANGED == ret)
    +         {
    +             break;
    +         }
    +@@ -685,12 +725,20 @@ WORD32 ihevcd_decode(iv_obj_t *ps_codec_obj, void *pv_api_ip, void *pv_api_op)
    +         BREAK_AFTER_SLICE_NAL();
    +     }
    + 
    +-    if((ps_codec->u4_pic_cnt == 0) && (ret != IHEVCD_SUCCESS))
    ++    if(1 == ps_codec->i4_pic_present && 0 == ps_codec->s_parse.i4_end_of_frame)
    +     {
    +-        ps_codec->i4_error_code = ret;
    +-
    +-        ihevcd_fill_outargs(ps_codec, ps_dec_ip, ps_dec_op);
    +-        return IV_FAIL;
    ++        slice_header_t *ps_slice_hdr_next;
    ++        ps_codec->i4_slice_error = 1;
    ++        ps_codec->s_parse.i4_cur_slice_idx--;
    ++        if(ps_codec->s_parse.i4_cur_slice_idx < 0)
    ++            ps_codec->s_parse.i4_cur_slice_idx = 0;
    ++
    ++        ps_slice_hdr_next = ps_codec->s_parse.ps_slice_hdr_base + ((ps_codec->s_parse.i4_cur_slice_idx + 1) & (MAX_SLICE_HDR_CNT - 1));
    ++        ps_slice_hdr_next->i2_ctb_x = -1;
    ++        ps_slice_hdr_next->i2_ctb_y = -1;
    ++
    ++        ihevcd_parse_slice_data(ps_codec);
    ++        ASSERT(ps_codec->s_parse.i4_end_of_frame != 0);
    +     }
    + 
    +     if(1 == ps_codec->i4_pic_present)
     diff --git a/decoder/ihevcd_parse_headers.c b/decoder/ihevcd_parse_headers.c
    -index c0f1564..06f35a3 100644
    +index c0f1564..6a9fe5e 100644
     --- a/decoder/ihevcd_parse_headers.c
     +++ b/decoder/ihevcd_parse_headers.c
     @@ -1285,15 +1285,31 @@ IHEVCD_ERROR_T ihevcd_parse_sps(codec_t *ps_codec)
          {
      
              UEV_PARSE("pic_crop_left_offset", value, ps_bitstrm);
    -+        if (value >= ps_sps->i2_pic_width_in_luma_samples)
    ++        if (value < 0 || value >= ps_sps->i2_pic_width_in_luma_samples)
     +        {
     +            return IHEVCD_INVALID_PARAMETER;
     +        }
              ps_sps->i2_pic_crop_left_offset = value;
      
              UEV_PARSE("pic_crop_right_offset", value, ps_bitstrm);
    -+        if (value >= ps_sps->i2_pic_width_in_luma_samples)
    ++        if (value < 0 || value >= ps_sps->i2_pic_width_in_luma_samples)
     +        {
     +            return IHEVCD_INVALID_PARAMETER;
     +        }
              ps_sps->i2_pic_crop_right_offset = value;
      
              UEV_PARSE("pic_crop_top_offset", value, ps_bitstrm);
    -+        if (value >= ps_sps->i2_pic_height_in_luma_samples)
    ++        if (value < 0 || value >= ps_sps->i2_pic_height_in_luma_samples)
     +        {
     +            return IHEVCD_INVALID_PARAMETER;
     +        }
              ps_sps->i2_pic_crop_top_offset = value;
      
              UEV_PARSE("pic_crop_bottom_offset", value, ps_bitstrm);
    -+        if (value >= ps_sps->i2_pic_height_in_luma_samples)
    ++        if (value < 0 || value >= ps_sps->i2_pic_height_in_luma_samples)
     +        {
     +            return IHEVCD_INVALID_PARAMETER;
     +        }
    @@ -176,10 +4225,73 @@ index c0f1564..06f35a3 100644
          ps_pps->i1_entropy_coding_sync_enabled_flag = value;
      
     diff --git a/decoder/ihevcd_parse_slice.c b/decoder/ihevcd_parse_slice.c
    -index 126b14c..9f92a0d 100644
    +index 126b14c..70c2e88 100644
     --- a/decoder/ihevcd_parse_slice.c
     +++ b/decoder/ihevcd_parse_slice.c
    -@@ -2708,6 +2708,17 @@ IHEVCD_ERROR_T ihevcd_parse_slice_data(codec_t *ps_codec)
    +@@ -2376,26 +2376,29 @@ IHEVCD_ERROR_T ihevcd_parse_slice_data(codec_t *ps_codec)
    + 
    +     /*Cabac init at the beginning of a slice*/
    +     //If the slice is a dependent slice, not present at the start of a tile
    +-    if((1 == ps_slice_hdr->i1_dependent_slice_flag) && (!((ps_codec->s_parse.i4_ctb_tile_x == 0) && (ps_codec->s_parse.i4_ctb_tile_y == 0))))
    ++    if(0 == ps_codec->i4_slice_error)
    +     {
    +-        if((0 == ps_pps->i1_entropy_coding_sync_enabled_flag) || (ps_pps->i1_entropy_coding_sync_enabled_flag && (0 != ps_codec->s_parse.i4_ctb_x)))
    ++        if((1 == ps_slice_hdr->i1_dependent_slice_flag) && (!((ps_codec->s_parse.i4_ctb_tile_x == 0) && (ps_codec->s_parse.i4_ctb_tile_y == 0))))
    +         {
    +-            ihevcd_cabac_reset(&ps_codec->s_parse.s_cabac,
    +-                               &ps_codec->s_parse.s_bitstrm);
    ++            if((0 == ps_pps->i1_entropy_coding_sync_enabled_flag) || (ps_pps->i1_entropy_coding_sync_enabled_flag && (0 != ps_codec->s_parse.i4_ctb_x)))
    ++            {
    ++                ihevcd_cabac_reset(&ps_codec->s_parse.s_cabac,
    ++                                   &ps_codec->s_parse.s_bitstrm);
    ++            }
    +         }
    +-    }
    +-    else if((0 == ps_pps->i1_entropy_coding_sync_enabled_flag) || (ps_pps->i1_entropy_coding_sync_enabled_flag && (0 != ps_codec->s_parse.i4_ctb_x)))
    +-    {
    +-        ret = ihevcd_cabac_init(&ps_codec->s_parse.s_cabac,
    +-                                &ps_codec->s_parse.s_bitstrm,
    +-                                slice_qp,
    +-                                cabac_init_idc,
    +-                                &gau1_ihevc_cab_ctxts[cabac_init_idc][slice_qp][0]);
    +-        if(ret != (IHEVCD_ERROR_T)IHEVCD_SUCCESS)
    ++        else if((0 == ps_pps->i1_entropy_coding_sync_enabled_flag) || (ps_pps->i1_entropy_coding_sync_enabled_flag && (0 != ps_codec->s_parse.i4_ctb_x)))
    +         {
    +-            ps_codec->i4_slice_error = 1;
    +-            end_of_slice_flag = 1;
    +-            ret = (IHEVCD_ERROR_T)IHEVCD_SUCCESS;
    ++            ret = ihevcd_cabac_init(&ps_codec->s_parse.s_cabac,
    ++                                    &ps_codec->s_parse.s_bitstrm,
    ++                                    slice_qp,
    ++                                    cabac_init_idc,
    ++                                    &gau1_ihevc_cab_ctxts[cabac_init_idc][slice_qp][0]);
    ++            if(ret != (IHEVCD_ERROR_T)IHEVCD_SUCCESS)
    ++            {
    ++                ps_codec->i4_slice_error = 1;
    ++                end_of_slice_flag = 1;
    ++                ret = (IHEVCD_ERROR_T)IHEVCD_SUCCESS;
    ++            }
    +         }
    +     }
    + 
    +@@ -2479,6 +2482,7 @@ IHEVCD_ERROR_T ihevcd_parse_slice_data(codec_t *ps_codec)
    + 
    +             /* Cabac init is done unconditionally at the start of the tile irrespective
    +              * of whether it is a dependent or an independent slice */
    ++            if(0 == ps_codec->i4_slice_error)
    +             {
    +                 ret = ihevcd_cabac_init(&ps_codec->s_parse.s_cabac,
    +                                         &ps_codec->s_parse.s_bitstrm,
    +@@ -2542,7 +2546,7 @@ IHEVCD_ERROR_T ihevcd_parse_slice_data(codec_t *ps_codec)
    +         if(ps_pps->i1_entropy_coding_sync_enabled_flag)
    +         {
    +             /*TODO Handle single CTB and top-right belonging to a different slice */
    +-            if(0 == ps_codec->s_parse.i4_ctb_x)
    ++            if(0 == ps_codec->s_parse.i4_ctb_x && 0 == ps_codec->i4_slice_error)
    +             {
    +                 //WORD32 size = sizeof(ps_codec->s_parse.s_cabac.au1_ctxt_models);
    +                 WORD32 default_ctxt = 0;
    +@@ -2708,6 +2712,17 @@ IHEVCD_ERROR_T ihevcd_parse_slice_data(codec_t *ps_codec)
              {
                  tu_t *ps_tu = ps_codec->s_parse.ps_tu;
                  pu_t *ps_pu = ps_codec->s_parse.ps_pu;
    @@ -197,7 +4309,7 @@ index 126b14c..9f92a0d 100644
      
                  ps_tu->b1_cb_cbf = 0;
                  ps_tu->b1_cr_cbf = 0;
    -@@ -2731,8 +2742,8 @@ IHEVCD_ERROR_T ihevcd_parse_slice_data(codec_t *ps_codec)
    +@@ -2731,8 +2746,8 @@ IHEVCD_ERROR_T ihevcd_parse_slice_data(codec_t *ps_codec)
                  ps_pu->b2_part_idx = 0;
                  ps_pu->b4_pos_x = 0;
                  ps_pu->b4_pos_y = 0;
    @@ -208,6 +4320,28 @@ index 126b14c..9f92a0d 100644
                  ps_pu->b1_intra_flag = 0;
                  ps_pu->b3_part_mode = ps_codec->s_parse.s_cu.i4_part_mode;
                  ps_pu->b1_merge_flag = 1;
    +@@ -2772,7 +2787,7 @@ IHEVCD_ERROR_T ihevcd_parse_slice_data(codec_t *ps_codec)
    +                 if((ps_codec->s_parse.i4_ctb_tile_y + 1) == ps_tile->u2_ht)
    +                     end_of_tile = 1;
    +             }
    +-            if((0 == end_of_slice_flag) &&
    ++            if((0 == end_of_slice_flag) && (0 == ps_codec->i4_slice_error) &&
    +                             ((ps_pps->i1_tiles_enabled_flag && end_of_tile) ||
    +                                             (ps_pps->i1_entropy_coding_sync_enabled_flag && end_of_tile_row)))
    +             {
    +diff --git a/decoder/ihevcd_parse_slice_header.c b/decoder/ihevcd_parse_slice_header.c
    +index e1b50b7..ae19328 100644
    +--- a/decoder/ihevcd_parse_slice_header.c
    ++++ b/decoder/ihevcd_parse_slice_header.c
    +@@ -356,7 +356,7 @@ IHEVCD_ERROR_T ihevcd_parse_slice_header(codec_t *ps_codec,
    +         slice_address = value;
    +         /* If slice address is greater than the number of CTBs in a picture,
    +          * ignore the slice */
    +-        if(value >= ps_sps->i4_pic_size_in_ctb)
    ++        if(value >= ps_sps->i4_pic_size_in_ctb || value <= 0)
    +             return IHEVCD_IGNORE_SLICE;
    +     }
    +     else
     diff --git a/decoder/ihevcd_utils.c b/decoder/ihevcd_utils.c
     index 7d76577..14cdd2b 100755
     --- a/decoder/ihevcd_utils.c
    diff --git a/frameworks_av.patch b/frameworks_av.patch
    index 78f16d8..27d5275 100644
    --- a/frameworks_av.patch
    +++ b/frameworks_av.patch
    @@ -754,7 +754,7 @@ index 893da89..2152454 100644
          // buffer queue.
          switch (mVideoBufferMode) {
     diff --git a/media/libstagefright/MPEG4Extractor.cpp b/media/libstagefright/MPEG4Extractor.cpp
    -index 5441714..2037923 100644
    +index 5441714..d1603c1 100644
     --- a/media/libstagefright/MPEG4Extractor.cpp
     +++ b/media/libstagefright/MPEG4Extractor.cpp
     @@ -72,6 +72,7 @@ public:
    @@ -804,7 +804,17 @@ index 5441714..2037923 100644
                  } else if (chunk_type == FOURCC('m', 'o', 'o', 'v')) {
                      mInitCheck = OK;
      
    -@@ -2148,7 +2155,10 @@ status_t MPEG4Extractor::parseChunk(off64_t *offset, int depth) {
    +@@ -1642,6 +1649,9 @@ status_t MPEG4Extractor::parseChunk(off64_t *offset, int depth) {
    +                     // ratio. Use compression ratio of 1.
    +                     max_size = width * height * 3 / 2;
    +                 }
    ++                // HACK: allow 10% overhead
    ++                // TODO: read sample size from traf atom for fragmented MPEG4.
    ++                max_size += max_size / 10;
    +                 mLastTrack->meta->setInt32(kKeyMaxInputSize, max_size);
    +             }
    + 
    +@@ -2148,7 +2158,10 @@ status_t MPEG4Extractor::parseChunk(off64_t *offset, int depth) {
                  *offset += chunk_size;
      
                  if (underQTMetaPath(mPath, 3)) {
    @@ -816,7 +826,7 @@ index 5441714..2037923 100644
                  }
                  break;
              }
    -@@ -2307,7 +2317,10 @@ status_t MPEG4Extractor::parseChunk(off64_t *offset, int depth) {
    +@@ -2307,7 +2320,10 @@ status_t MPEG4Extractor::parseChunk(off64_t *offset, int depth) {
      
              case FOURCC('s', 'i', 'd', 'x'):
              {
    @@ -828,7 +838,7 @@ index 5441714..2037923 100644
                  *offset += chunk_size;
                  return UNKNOWN_ERROR; // stop parsing after sidx
              }
    -@@ -2349,7 +2362,10 @@ status_t MPEG4Extractor::parseChunk(off64_t *offset, int depth) {
    +@@ -2349,7 +2365,10 @@ status_t MPEG4Extractor::parseChunk(off64_t *offset, int depth) {
                  // check if we're parsing 'ilst' for meta keys
                  // if so, treat type as a number (key-id).
                  if (underQTMetaPath(mPath, 3)) {
    @@ -840,7 +850,7 @@ index 5441714..2037923 100644
                  }
      
                  *offset += chunk_size;
    -@@ -2906,7 +2922,7 @@ status_t MPEG4Extractor::parseColorInfo(off64_t offset, size_t size) {
    +@@ -2906,7 +2925,7 @@ status_t MPEG4Extractor::parseColorInfo(off64_t offset, size_t size) {
      
          int32_t type = U32_AT(&buffer[0]);
          if ((type == FOURCC('n', 'c', 'l', 'x') && size >= 11)
    @@ -849,7 +859,7 @@ index 5441714..2037923 100644
              int32_t primaries = U16_AT(&buffer[4]);
              int32_t transfer = U16_AT(&buffer[6]);
              int32_t coeffs = U16_AT(&buffer[8]);
    -@@ -2984,6 +3000,13 @@ status_t MPEG4Extractor::parse3GPPMetaData(off64_t offset, size_t size, int dept
    +@@ -2984,6 +3003,13 @@ status_t MPEG4Extractor::parse3GPPMetaData(off64_t offset, size_t size, int dept
              }
              case FOURCC('y', 'r', 'r', 'c'):
              {
    @@ -863,7 +873,7 @@ index 5441714..2037923 100644
                  char tmp[5];
                  uint16_t year = U16_AT(&buffer[4]);
      
    -@@ -3006,6 +3029,8 @@ status_t MPEG4Extractor::parse3GPPMetaData(off64_t offset, size_t size, int dept
    +@@ -3006,6 +3032,8 @@ status_t MPEG4Extractor::parse3GPPMetaData(off64_t offset, size_t size, int dept
      
              // smallest possible valid UTF-16 string w BOM: 0xfe 0xff 0x00 0x00
              if (size < 6) {
    @@ -872,7 +882,7 @@ index 5441714..2037923 100644
                  return ERROR_MALFORMED;
              }
      
    -@@ -3174,9 +3199,13 @@ sp<IMediaSource> MPEG4Extractor::getTrack(size_t index) {
    +@@ -3174,9 +3202,13 @@ sp<IMediaSource> MPEG4Extractor::getTrack(size_t index) {
              }
          }
      
    @@ -887,7 +897,7 @@ index 5441714..2037923 100644
      }
      
      // static
    -@@ -3573,6 +3602,7 @@ MPEG4Source::MPEG4Source(
    +@@ -3573,6 +3605,7 @@ MPEG4Source::MPEG4Source(
            mTrex(trex),
            mFirstMoofOffset(firstMoofOffset),
            mCurrentMoofOffset(firstMoofOffset),
    @@ -895,7 +905,7 @@ index 5441714..2037923 100644
            mCurrentTime(0),
            mCurrentSampleInfoAllocSize(0),
            mCurrentSampleInfoSizes(NULL),
    -@@ -3637,10 +3667,14 @@ MPEG4Source::MPEG4Source(
    +@@ -3637,10 +3670,14 @@ MPEG4Source::MPEG4Source(
      
          CHECK(format->findInt32(kKeyTrackID, &mTrackId));
      
    @@ -911,7 +921,7 @@ index 5441714..2037923 100644
      }
      
      MPEG4Source::~MPEG4Source() {
    -@@ -3767,13 +3801,35 @@ status_t MPEG4Source::parseChunk(off64_t *offset) {
    +@@ -3767,13 +3804,35 @@ status_t MPEG4Source::parseChunk(off64_t *offset) {
      
                      while (true) {
                          if (mDataSource->readAt(*offset, hdr, 8) < 8) {
    @@ -948,7 +958,7 @@ index 5441714..2037923 100644
                          }
                          *offset += chunk_size;
                      }
    -@@ -4431,6 +4487,8 @@ status_t MPEG4Source::read(
    +@@ -4431,6 +4490,8 @@ status_t MPEG4Source::read(
              }
              if (size > mBuffer->size()) {
                  ALOGE("buffer too small: %zu > %zu", size, mBuffer->size());
    @@ -957,7 +967,7 @@ index 5441714..2037923 100644
                  return ERROR_BUFFER_TOO_SMALL;
              }
          }
    -@@ -4651,17 +4709,25 @@ status_t MPEG4Source::fragmentedRead(
    +@@ -4651,17 +4712,25 @@ status_t MPEG4Source::fragmentedRead(
                      totalOffset += se->mSize;
                  }
                  mCurrentMoofOffset = totalOffset;
    @@ -985,7 +995,7 @@ index 5441714..2037923 100644
                  mCurrentTime = 0;
              }
      
    -@@ -4690,7 +4756,10 @@ status_t MPEG4Source::fragmentedRead(
    +@@ -4690,7 +4759,10 @@ status_t MPEG4Source::fragmentedRead(
                  mCurrentMoofOffset = nextMoof;
                  mCurrentSamples.clear();
                  mCurrentSampleIndex = 0;
    @@ -997,7 +1007,7 @@ index 5441714..2037923 100644
                  if (mCurrentSampleIndex >= mCurrentSamples.size()) {
                      return ERROR_END_OF_STREAM;
                  }
    -@@ -4712,6 +4781,8 @@ status_t MPEG4Source::fragmentedRead(
    +@@ -4712,6 +4784,8 @@ status_t MPEG4Source::fragmentedRead(
              }
              if (size > mBuffer->size()) {
                  ALOGE("buffer too small: %zu > %zu", size, mBuffer->size());
    @@ -1291,6 +1301,67 @@ index f1b81e1..123fd25 100644
          int64_t mInputTimeUs;
      
          bool mSawInputEOS;
    +diff --git a/media/libstagefright/codecs/avcdec/SoftAVCDec.cpp b/media/libstagefright/codecs/avcdec/SoftAVCDec.cpp
    +index cecc52b..43ef4a4 100644
    +--- a/media/libstagefright/codecs/avcdec/SoftAVCDec.cpp
    ++++ b/media/libstagefright/codecs/avcdec/SoftAVCDec.cpp
    +@@ -318,10 +318,6 @@ status_t SoftAVC::initDecoder() {
    + 
    +         status = ivdec_api_function(mCodecCtx, (void *)&s_create_ip, (void *)&s_create_op);
    + 
    +-        mCodecCtx = (iv_obj_t*)s_create_op.s_ivd_create_op_t.pv_handle;
    +-        mCodecCtx->pv_fxns = dec_fxns;
    +-        mCodecCtx->u4_size = sizeof(iv_obj_t);
    +-
    +         if (status != IV_SUCCESS) {
    +             ALOGE("Error in create: 0x%x",
    +                     s_create_op.s_ivd_create_op_t.u4_error_code);
    +@@ -329,6 +325,10 @@ status_t SoftAVC::initDecoder() {
    +             mCodecCtx = NULL;
    +             return UNKNOWN_ERROR;
    +         }
    ++
    ++        mCodecCtx = (iv_obj_t*)s_create_op.s_ivd_create_op_t.pv_handle;
    ++        mCodecCtx->pv_fxns = dec_fxns;
    ++        mCodecCtx->u4_size = sizeof(iv_obj_t);
    +     }
    + 
    +     /* Reset the plugin state */
    +@@ -578,7 +578,7 @@ void SoftAVC::onQueueFilled(OMX_U32 portIndex) {
    +                 notifyEmptyBufferDone(inHeader);
    + 
    +                 if (!(inHeader->nFlags & OMX_BUFFERFLAG_EOS)) {
    +-                    continue;
    ++                    return;
    +                 }
    + 
    +                 mReceivedEOS = true;
    +diff --git a/media/libstagefright/codecs/hevcdec/SoftHEVC.cpp b/media/libstagefright/codecs/hevcdec/SoftHEVC.cpp
    +index 5c70387..194a078 100644
    +--- a/media/libstagefright/codecs/hevcdec/SoftHEVC.cpp
    ++++ b/media/libstagefright/codecs/hevcdec/SoftHEVC.cpp
    +@@ -320,10 +320,6 @@ status_t SoftHEVC::initDecoder() {
    + 
    +         status = ivdec_api_function(mCodecCtx, (void *)&s_create_ip, (void *)&s_create_op);
    + 
    +-        mCodecCtx = (iv_obj_t*)s_create_op.s_ivd_create_op_t.pv_handle;
    +-        mCodecCtx->pv_fxns = dec_fxns;
    +-        mCodecCtx->u4_size = sizeof(iv_obj_t);
    +-
    +         if (status != IV_SUCCESS) {
    +             ALOGE("Error in create: 0x%x",
    +                     s_create_op.s_ivd_create_op_t.u4_error_code);
    +@@ -331,6 +327,10 @@ status_t SoftHEVC::initDecoder() {
    +             mCodecCtx = NULL;
    +             return UNKNOWN_ERROR;
    +         }
    ++
    ++        mCodecCtx = (iv_obj_t*)s_create_op.s_ivd_create_op_t.pv_handle;
    ++        mCodecCtx->pv_fxns = dec_fxns;
    ++        mCodecCtx->u4_size = sizeof(iv_obj_t);
    +     }
    + 
    +     /* Reset the plugin state */
     diff --git a/media/libstagefright/codecs/m4v_h263/dec/src/vlc_decode.cpp b/media/libstagefright/codecs/m4v_h263/dec/src/vlc_decode.cpp
     index f7192b1c..7202f98 100644
     --- a/media/libstagefright/codecs/m4v_h263/dec/src/vlc_decode.cpp
    diff --git a/frameworks_base.patch b/frameworks_base.patch
    index cfb7f28..ce7d836 100644
    --- a/frameworks_base.patch
    +++ b/frameworks_base.patch
    @@ -128,6 +128,37 @@ index a110383..aea843a 100644
                  }
              }
              return false;
    +diff --git a/core/java/android/net/Uri.java b/core/java/android/net/Uri.java
    +index 09af05c..a84f74a 100644
    +--- a/core/java/android/net/Uri.java
    ++++ b/core/java/android/net/Uri.java
    +@@ -1065,7 +1065,7 @@ public abstract class Uri implements Parcelable, Comparable<Uri> {
    +                 return null;
    +             }
    + 
    +-            int end = authority.indexOf('@');
    ++            int end = authority.lastIndexOf('@');
    +             return end == NOT_FOUND ? null : authority.substring(0, end);
    +         }
    + 
    +@@ -1089,7 +1089,7 @@ public abstract class Uri implements Parcelable, Comparable<Uri> {
    +             }
    + 
    +             // Parse out user info and then port.
    +-            int userInfoSeparator = authority.indexOf('@');
    ++            int userInfoSeparator = authority.lastIndexOf('@');
    +             int portSeparator = authority.indexOf(':', userInfoSeparator);
    + 
    +             String encodedHost = portSeparator == NOT_FOUND
    +@@ -1115,7 +1115,7 @@ public abstract class Uri implements Parcelable, Comparable<Uri> {
    + 
    +             // Make sure we look for the port separtor *after* the user info
    +             // separator. We have URLs with a ':' in the user info.
    +-            int userInfoSeparator = authority.indexOf('@');
    ++            int userInfoSeparator = authority.lastIndexOf('@');
    +             int portSeparator = authority.indexOf(':', userInfoSeparator);
    + 
    +             if (portSeparator == NOT_FOUND) {
     diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
     index a8209af..4766d33 100755
     --- a/core/java/android/provider/Settings.java
    @@ -204,6 +235,24 @@ index 395f738..169f7e1 100644
               * Control flags that are private to the platform.
               * @hide
               */
    +diff --git a/core/java/android/view/WindowManagerPolicy.java b/core/java/android/view/WindowManagerPolicy.java
    +index 46a0194..ecc9025 100644
    +--- a/core/java/android/view/WindowManagerPolicy.java
    ++++ b/core/java/android/view/WindowManagerPolicy.java
    +@@ -1100,6 +1100,13 @@ public interface WindowManagerPolicy {
    +     public void notifyCameraLensCoverSwitchChanged(long whenNanos, boolean lensCovered);
    + 
    +     /**
    ++     * Tell the policy that the rotation lock switch has changed state.
    ++     * @param whenNanos The time when the change occurred in uptime nanoseconds.
    ++     * @param isLocked True if the rotation is now locked.
    ++     */
    ++    public void notifyRotateLockSwitchChanged(long whenNanos, boolean isLocked);
    ++
    ++    /**
    +      * Tell the policy if anyone is requesting that keyguard not come on.
    +      *
    +      * @param enabled Whether keyguard can be on or not.  does not actually
     diff --git a/core/java/com/android/internal/app/procstats/ProcessState.java b/core/java/com/android/internal/app/procstats/ProcessState.java
     index 8c5df08..8c2c236 100644
     --- a/core/java/com/android/internal/app/procstats/ProcessState.java
    @@ -362,6 +411,22 @@ index f062b59..574f7c1 100644
     +  <!-- The default WebView implementation -->
     +    <webviewprovider description="AOSP WebView" packageName="com.android.webview" availableByDefault="true" isFallback="true" />
      </webviewproviders>
    +diff --git a/core/tests/coretests/src/android/net/UriTest.java b/core/tests/coretests/src/android/net/UriTest.java
    +index 6fa28b1..27b7f9e 100644
    +--- a/core/tests/coretests/src/android/net/UriTest.java
    ++++ b/core/tests/coretests/src/android/net/UriTest.java
    +@@ -187,6 +187,11 @@ public class UriTest extends TestCase {
    +         uri = Uri.parse("http://localhost");
    +         assertEquals("localhost", uri.getHost());
    +         assertEquals(-1, uri.getPort());
    ++
    ++        uri = Uri.parse("http://a:a@example.com:a@example2.com/path");
    ++        assertEquals("a:a@example.com:a@example2.com", uri.getAuthority());
    ++        assertEquals("example2.com", uri.getHost());
    ++        assertEquals(-1, uri.getPort());
    +     }
    + 
    +     @SmallTest
     diff --git a/libs/hwui/Android.mk b/libs/hwui/Android.mk
     index cacfce1..0b177b9 100644
     --- a/libs/hwui/Android.mk
    @@ -401,6 +466,18 @@ index 731deae..20f9ef6 100644
          return getRawAttributes(env, fileStream.get(), false);
      }
      
    +diff --git a/media/jni/android_mtp_MtpDatabase.cpp b/media/jni/android_mtp_MtpDatabase.cpp
    +index 7217832..feff102 100644
    +--- a/media/jni/android_mtp_MtpDatabase.cpp
    ++++ b/media/jni/android_mtp_MtpDatabase.cpp
    +@@ -948,6 +948,7 @@ void* MyMtpDatabase::getThumbnail(MtpObjectHandle handle, size_t& outThumbSize)
    +                         outThumbSize = image_data.thumbnail.length;
    +                     } else {
    +                         free(result);
    ++                        result = NULL;
    +                     }
    +                 }
    +                 break;
     diff --git a/packages/SystemUI/res/values/config.xml b/packages/SystemUI/res/values/config.xml
     index 0fa9a85..925f368 100644
     --- a/packages/SystemUI/res/values/config.xml
    @@ -1102,6 +1179,49 @@ index 069ae73..f804fa1 100644
                          }
                      }
                  }
    +diff --git a/services/core/java/com/android/server/input/InputManagerService.java b/services/core/java/com/android/server/input/InputManagerService.java
    +index 719ce76..df2c00b 100644
    +--- a/services/core/java/com/android/server/input/InputManagerService.java
    ++++ b/services/core/java/com/android/server/input/InputManagerService.java
    +@@ -286,6 +286,9 @@ public class InputManagerService extends IInputManager.Stub
    +     /** Switch code: Camera lens cover. When set the lens is covered. */
    +     public static final int SW_CAMERA_LENS_COVER = 0x09;
    + 
    ++    /** Switch code: Rotation Lock.  When set, rotation is locked. */
    ++    public static final int SW_ROTATE_LOCK = 0x0c;
    ++
    +     public static final int SW_LID_BIT = 1 << SW_LID;
    +     public static final int SW_TABLET_MODE_BIT = 1 << SW_TABLET_MODE;
    +     public static final int SW_KEYPAD_SLIDE_BIT = 1 << SW_KEYPAD_SLIDE;
    +@@ -296,6 +299,7 @@ public class InputManagerService extends IInputManager.Stub
    +     public static final int SW_JACK_BITS =
    +             SW_HEADPHONE_INSERT_BIT | SW_MICROPHONE_INSERT_BIT | SW_JACK_PHYSICAL_INSERT_BIT | SW_LINEOUT_INSERT_BIT;
    +     public static final int SW_CAMERA_LENS_COVER_BIT = 1 << SW_CAMERA_LENS_COVER;
    ++    public static final int SW_ROTATE_LOCK_BIT = 1 << SW_ROTATE_LOCK;
    + 
    +     /** Whether to use the dev/input/event or uevent subsystem for the audio jack. */
    +     final boolean mUseDevInputEventForAudioJack;
    +@@ -1831,6 +1835,11 @@ public class InputManagerService extends IInputManager.Stub
    +                     switchMask);
    +         }
    + 
    ++        if ((switchMask & SW_ROTATE_LOCK_BIT) != 0) {
    ++            final boolean isLocked = ((switchValues & SW_ROTATE_LOCK_BIT) != 0);
    ++            mWindowManagerCallbacks.notifyRotateLockSwitchChanged(whenNanos, isLocked);
    ++        }
    ++
    +         if ((switchMask & SW_TABLET_MODE_BIT) != 0) {
    +             SomeArgs args = SomeArgs.obtain();
    +             args.argi1 = (int) (whenNanos & 0xFFFFFFFF);
    +@@ -2032,6 +2041,8 @@ public class InputManagerService extends IInputManager.Stub
    + 
    +         public void notifyCameraLensCoverSwitchChanged(long whenNanos, boolean lensCovered);
    + 
    ++        public void notifyRotateLockSwitchChanged(long whenNanos, boolean isLocked);
    ++
    +         public void notifyInputChannelBroken(InputWindowHandle inputWindowHandle);
    + 
    +         public long notifyANR(InputApplicationHandle inputApplicationHandle,
     diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
     index b6a9940..11b5832a 100644
     --- a/services/core/java/com/android/server/pm/PackageManagerService.java
    @@ -1116,7 +1236,7 @@ index b6a9940..11b5832a 100644
          /**
           * Whether verification is enabled by default.
     diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java
    -index 889c52a..11585b4 100644
    +index 889c52a..872b03d 100644
     --- a/services/core/java/com/android/server/policy/PhoneWindowManager.java
     +++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java
     @@ -491,6 +491,9 @@ public class PhoneWindowManager implements WindowManagerPolicy {
    @@ -1161,7 +1281,26 @@ index 889c52a..11585b4 100644
                  sendCloseSystemWindows(SYSTEM_DIALOG_REASON_HOME_KEY);
                  startDockOrHome(true /*fromHomeKey*/, awakenFromDreams);
              }
    -@@ -5884,6 +5894,12 @@ public class PhoneWindowManager implements WindowManagerPolicy {
    +@@ -5567,6 +5577,18 @@ public class PhoneWindowManager implements WindowManagerPolicy {
    +         mCameraLensCoverState = lensCoverState;
    +     }
    + 
    ++    /** {@inheritDoc} */
    ++    public void notifyRotateLockSwitchChanged(long whenNanos, boolean isLocked) {
    ++        try {
    ++            if (isLocked)
    ++                mWindowManager.freezeRotation(-1);
    ++            else
    ++                mWindowManager.thawRotation();
    ++        } catch (RemoteException e) {
    ++            // Ignore
    ++        }
    ++    }
    ++
    +     void setHdmiPlugged(boolean plugged) {
    +         if (mHdmiPlugged != plugged) {
    +             mHdmiPlugged = plugged;
    +@@ -5884,6 +5906,12 @@ public class PhoneWindowManager implements WindowManagerPolicy {
                      break;
                  }
      
    @@ -1174,6 +1313,23 @@ index 889c52a..11585b4 100644
                  case KeyEvent.KEYCODE_ENDCALL: {
                      result &= ~ACTION_PASS_TO_USER;
                      if (down) {
    +diff --git a/services/core/java/com/android/server/wm/InputMonitor.java b/services/core/java/com/android/server/wm/InputMonitor.java
    +index be9fb26..d835e88 100644
    +--- a/services/core/java/com/android/server/wm/InputMonitor.java
    ++++ b/services/core/java/com/android/server/wm/InputMonitor.java
    +@@ -392,6 +392,12 @@ final class InputMonitor implements InputManagerService.WindowManagerCallbacks {
    +         mService.mPolicy.notifyCameraLensCoverSwitchChanged(whenNanos, lensCovered);
    +     }
    + 
    ++    /* Notifies that the rotation lock switch changed state. */
    ++    @Override
    ++    public void notifyRotateLockSwitchChanged(long whenNanos, boolean isLocked) {
    ++        mService.mPolicy.notifyRotateLockSwitchChanged(whenNanos, isLocked);
    ++    }
    ++
    +     /* Provides an opportunity for the window manager policy to intercept early key
    +      * processing as soon as the key has been read from the device. */
    +     @Override
     diff --git a/services/core/java/com/android/server/wm/Session.java b/services/core/java/com/android/server/wm/Session.java
     index 08c0a4b..b5c4202 100644
     --- a/services/core/java/com/android/server/wm/Session.java
    diff --git a/frameworks_native.patch b/frameworks_native.patch
    index a5e2a4b..8bd2209 100644
    --- a/frameworks_native.patch
    +++ b/frameworks_native.patch
    @@ -859,10 +859,20 @@ index ee152bf..9c82295 100644
          result.mStorage.clear();
          for (size_t r = 0; r < numRects; ++r) {
     diff --git a/opengl/libs/Android.mk b/opengl/libs/Android.mk
    -index 24e4c19..ffd0dbc 100644
    +index 24e4c19..afbfb66 100644
     --- a/opengl/libs/Android.mk
     +++ b/opengl/libs/Android.mk
    -@@ -77,7 +77,6 @@ LOCAL_SRC_FILES:= 		\
    +@@ -45,6 +45,9 @@ LOCAL_CFLAGS += -fvisibility=hidden
    + ifeq ($(BOARD_ALLOW_EGL_HIBERNATION),true)
    +   LOCAL_CFLAGS += -DBOARD_ALLOW_EGL_HIBERNATION
    + endif
    ++ifeq ($(BOARD_EGL_WORKAROUND_BUG_10194508),true)
    ++  LOCAL_CFLAGS += -DWORKAROUND_BUG_10194508
    ++endif
    + ifneq ($(MAX_EGL_CACHE_ENTRY_SIZE),)
    +   LOCAL_CFLAGS += -DMAX_EGL_CACHE_ENTRY_SIZE=$(MAX_EGL_CACHE_ENTRY_SIZE)
    + endif
    +@@ -77,7 +80,6 @@ LOCAL_SRC_FILES:= 		\
      	GLES_CM/gl.cpp.arm 	\
      #
      
    @@ -870,7 +880,7 @@ index 24e4c19..ffd0dbc 100644
      LOCAL_SHARED_LIBRARIES += libcutils liblog libEGL
      LOCAL_MODULE:= libGLESv1_CM
      
    -@@ -105,7 +104,6 @@ LOCAL_SRC_FILES:= \
    +@@ -105,7 +107,6 @@ LOCAL_SRC_FILES:= \
      	GLES2/gl2.cpp   \
      #
      
    @@ -878,7 +888,7 @@ index 24e4c19..ffd0dbc 100644
      LOCAL_ARM_MODE := arm
      LOCAL_SHARED_LIBRARIES += libcutils libutils liblog libEGL
      LOCAL_MODULE:= libGLESv2
    -@@ -133,7 +131,6 @@ LOCAL_SRC_FILES:= \
    +@@ -133,7 +134,6 @@ LOCAL_SRC_FILES:= \
      	GLES2/gl2.cpp   \
      #
      
    @@ -1575,6 +1585,46 @@ index b1b31f8..8bde4e5 100644
      #undef CALL_GL_API_RETURN
      
      /*
    +diff --git a/services/inputflinger/InputManager.cpp b/services/inputflinger/InputManager.cpp
    +index 6a6547b..2ef25f3 100644
    +--- a/services/inputflinger/InputManager.cpp
    ++++ b/services/inputflinger/InputManager.cpp
    +@@ -20,6 +20,7 @@
    + 
    + #include "InputManager.h"
    + 
    ++#include <cutils/iosched_policy.h>
    + #include <cutils/log.h>
    + 
    + namespace android {
    +@@ -51,13 +52,15 @@ void InputManager::initialize() {
    + }
    + 
    + status_t InputManager::start() {
    +-    status_t result = mDispatcherThread->run("InputDispatcher", PRIORITY_URGENT_DISPLAY);
    ++    status_t result = mDispatcherThread->run("InputDispatcher",
    ++            PRIORITY_URGENT_DISPLAY + PRIORITY_MORE_FAVORABLE);
    +     if (result) {
    +         ALOGE("Could not start InputDispatcher thread due to error %d.", result);
    +         return result;
    +     }
    + 
    +-    result = mReaderThread->run("InputReader", PRIORITY_URGENT_DISPLAY);
    ++    result = mReaderThread->run("InputReader",
    ++            PRIORITY_URGENT_DISPLAY + PRIORITY_MORE_FAVORABLE);
    +     if (result) {
    +         ALOGE("Could not start InputReader thread due to error %d.", result);
    + 
    +@@ -65,6 +68,9 @@ status_t InputManager::start() {
    +         return result;
    +     }
    + 
    ++    android_set_rt_ioprio(mDispatcherThread->getTid(), 1);
    ++    android_set_rt_ioprio(mReaderThread->getTid(), 1);
    ++
    +     return OK;
    + }
    + 
     diff --git a/services/inputflinger/InputReader.cpp b/services/inputflinger/InputReader.cpp
     index b9be675..eff3deb 100644
     --- a/services/inputflinger/InputReader.cpp
    @@ -1794,6 +1844,26 @@ index ffda035..3f96b35 100644
      endif
      
      ifneq ($(PRESENT_TIME_OFFSET_FROM_VSYNC_NS),)
    +diff --git a/services/surfaceflinger/DispSync.cpp b/services/surfaceflinger/DispSync.cpp
    +index 1a9820d..b45e00a 100644
    +--- a/services/surfaceflinger/DispSync.cpp
    ++++ b/services/surfaceflinger/DispSync.cpp
    +@@ -22,6 +22,7 @@
    + 
    + #include <math.h>
    + 
    ++#include <cutils/iosched_policy.h>
    + #include <cutils/log.h>
    + 
    + #include <ui/Fence.h>
    +@@ -390,6 +391,7 @@ DispSync::DispSync(const char* name) :
    +         ALOGE("Couldn't set SCHED_FIFO for DispSyncThread");
    +     }
    + 
    ++    android_set_rt_ioprio(mThread->getTid(), 1);
    + 
    +     reset();
    +     beginResync();
     diff --git a/services/surfaceflinger/DisplayDevice.cpp b/services/surfaceflinger/DisplayDevice.cpp
     index 5c2c0ad..1f2e554 100644
     --- a/services/surfaceflinger/DisplayDevice.cpp
    @@ -1852,6 +1922,26 @@ index 2190466..8c36d85 100644
          status_t result = mSource[source]->dequeueBuffer(sslot, fence,
                  mSinkBufferWidth, mSinkBufferHeight, format, usage);
          if (result < 0)
    +diff --git a/services/surfaceflinger/EventThread.cpp b/services/surfaceflinger/EventThread.cpp
    +index dd88adb..2dacd87 100644
    +--- a/services/surfaceflinger/EventThread.cpp
    ++++ b/services/surfaceflinger/EventThread.cpp
    +@@ -20,6 +20,7 @@
    + #include <sys/types.h>
    + 
    + #include <cutils/compiler.h>
    ++#include <cutils/iosched_policy.h>
    + 
    + #include <gui/BitTube.h>
    + #include <gui/IDisplayEventConnection.h>
    +@@ -92,6 +93,7 @@ void EventThread::sendVsyncHintOnLocked() {
    + 
    + void EventThread::onFirstRef() {
    +     run("EventThread", PRIORITY_URGENT_DISPLAY + PRIORITY_MORE_FAVORABLE);
    ++    android_set_rt_ioprio(getTid(), 1);
    + }
    + 
    + sp<EventThread::Connection> EventThread::createEventConnection() const {
     diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
     index 3ffa655..f8de24d 100644
     --- a/services/surfaceflinger/Layer.cpp
    @@ -2082,10 +2172,18 @@ index 7c3f9b5..b268119 100644
      public:
          GLES20RenderEngine();
     diff --git a/services/surfaceflinger/RenderEngine/RenderEngine.cpp b/services/surfaceflinger/RenderEngine/RenderEngine.cpp
    -index d6a032f..d0df8ab 100644
    +index d6a032f..28b3319 100644
     --- a/services/surfaceflinger/RenderEngine/RenderEngine.cpp
     +++ b/services/surfaceflinger/RenderEngine/RenderEngine.cpp
    -@@ -262,9 +262,11 @@ void RenderEngine::dump(String8& result) {
    +@@ -83,7 +83,6 @@ RenderEngine* RenderEngine::create(EGLDisplay display, int hwcFormat) {
    +             EGL_CONTEXT_CLIENT_VERSION, contextClientVersion,      // MUST be first
    + #ifdef EGL_IMG_context_priority
    + #ifdef HAS_CONTEXT_PRIORITY
    +-#warning "using EGL_IMG_context_priority"
    +             EGL_CONTEXT_PRIORITY_LEVEL_IMG, EGL_CONTEXT_PRIORITY_HIGH_IMG,
    + #endif
    + #endif
    +@@ -262,9 +261,11 @@ void RenderEngine::dump(String8& result) {
      // ---------------------------------------------------------------------------
      
      RenderEngine::BindImageAsFramebuffer::BindImageAsFramebuffer(
    @@ -2099,7 +2197,7 @@ index d6a032f..d0df8ab 100644
      
          ALOGE_IF(mStatus != GL_FRAMEBUFFER_COMPLETE_OES,
                  "glCheckFramebufferStatusOES error %d", mStatus);
    -@@ -272,7 +274,7 @@ RenderEngine::BindImageAsFramebuffer::BindImageAsFramebuffer(
    +@@ -272,7 +273,7 @@ RenderEngine::BindImageAsFramebuffer::BindImageAsFramebuffer(
      
      RenderEngine::BindImageAsFramebuffer::~BindImageAsFramebuffer() {
          // back to main framebuffer
    @@ -2135,10 +2233,26 @@ index 0259881..5a5910a 100644
              int getStatus() const;
          };
     diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
    -index 8e7e577..a04684c 100644
    +index 8e7e577..f1104a0 100644
     --- a/services/surfaceflinger/SurfaceFlinger.cpp
     +++ b/services/surfaceflinger/SurfaceFlinger.cpp
    -@@ -3437,7 +3437,8 @@ status_t SurfaceFlinger::captureScreen(const sp<IBinder>& display,
    +@@ -27,6 +27,7 @@
    + 
    + #include <EGL/egl.h>
    + 
    ++#include <cutils/iosched_policy.h>
    + #include <cutils/log.h>
    + #include <cutils/properties.h>
    + 
    +@@ -501,6 +502,7 @@ void SurfaceFlinger::init() {
    + 
    +     mEventControlThread = new EventControlThread(this);
    +     mEventControlThread->run("EventControl", PRIORITY_URGENT_DISPLAY);
    ++    android_set_rt_ioprio(mEventControlThread->getTid(), 1);
    + 
    +     // initialize our drawing state
    +     mDrawingState = mCurrentState;
    +@@ -3437,7 +3439,8 @@ status_t SurfaceFlinger::captureScreen(const sp<IBinder>& display,
              const sp<IGraphicBufferProducer>& producer,
              Rect sourceCrop, uint32_t reqWidth, uint32_t reqHeight,
              uint32_t minLayerZ, uint32_t maxLayerZ,
    @@ -2148,7 +2262,7 @@ index 8e7e577..a04684c 100644
      
          if (CC_UNLIKELY(display == 0))
              return BAD_VALUE;
    -@@ -3481,6 +3482,7 @@ status_t SurfaceFlinger::captureScreen(const sp<IBinder>& display,
    +@@ -3481,6 +3484,7 @@ status_t SurfaceFlinger::captureScreen(const sp<IBinder>& display,
              bool useIdentityTransform;
              Transform::orientation_flags rotation;
              status_t result;
    @@ -2156,7 +2270,7 @@ index 8e7e577..a04684c 100644
              bool isLocalScreenshot;
          public:
              MessageCaptureScreen(SurfaceFlinger* flinger,
    -@@ -3490,12 +3492,13 @@ status_t SurfaceFlinger::captureScreen(const sp<IBinder>& display,
    +@@ -3490,12 +3494,13 @@ status_t SurfaceFlinger::captureScreen(const sp<IBinder>& display,
                      uint32_t minLayerZ, uint32_t maxLayerZ,
                      bool useIdentityTransform,
                      Transform::orientation_flags rotation,
    @@ -2171,7 +2285,7 @@ index 8e7e577..a04684c 100644
                    isLocalScreenshot(isLocalScreenshot)
              {
              }
    -@@ -3505,9 +3508,10 @@ status_t SurfaceFlinger::captureScreen(const sp<IBinder>& display,
    +@@ -3505,9 +3510,10 @@ status_t SurfaceFlinger::captureScreen(const sp<IBinder>& display,
              virtual bool handler() {
                  Mutex::Autolock _l(flinger->mStateLock);
                  sp<const DisplayDevice> hw(flinger->getDisplayDevice(display));
    @@ -2183,7 +2297,7 @@ index 8e7e577..a04684c 100644
                  static_cast<GraphicProducerWrapper*>(IInterface::asBinder(producer).get())->exit(result);
                  return true;
              }
    -@@ -3523,7 +3527,7 @@ status_t SurfaceFlinger::captureScreen(const sp<IBinder>& display,
    +@@ -3523,7 +3529,7 @@ status_t SurfaceFlinger::captureScreen(const sp<IBinder>& display,
          sp<MessageBase> msg = new MessageCaptureScreen(this,
                  display, IGraphicBufferProducer::asInterface( wrapper ),
                  sourceCrop, reqWidth, reqHeight, minLayerZ, maxLayerZ,
    @@ -2192,7 +2306,7 @@ index 8e7e577..a04684c 100644
      
          status_t res = postMessageAsync(msg);
          if (res == NO_ERROR) {
    -@@ -3606,7 +3610,7 @@ status_t SurfaceFlinger::captureScreenImplLocked(
    +@@ -3606,7 +3612,7 @@ status_t SurfaceFlinger::captureScreenImplLocked(
              Rect sourceCrop, uint32_t reqWidth, uint32_t reqHeight,
              uint32_t minLayerZ, uint32_t maxLayerZ,
              bool useIdentityTransform, Transform::orientation_flags rotation,
    @@ -2201,7 +2315,7 @@ index 8e7e577..a04684c 100644
      {
          ATRACE_CALL();
      
    -@@ -3684,7 +3688,7 @@ status_t SurfaceFlinger::captureScreenImplLocked(
    +@@ -3684,7 +3690,7 @@ status_t SurfaceFlinger::captureScreenImplLocked(
                      if (image != EGL_NO_IMAGE_KHR) {
                          // this binds the given EGLImage as a framebuffer for the
                          // duration of this scope.
    @@ -2210,7 +2324,7 @@ index 8e7e577..a04684c 100644
                          if (imageBond.getStatus() == NO_ERROR) {
                              // this will in fact render into our dequeued buffer
                              // via an FBO, which means we didn't have to create
    -@@ -3731,6 +3735,16 @@ status_t SurfaceFlinger::captureScreenImplLocked(
    +@@ -3731,6 +3737,16 @@ status_t SurfaceFlinger::captureScreenImplLocked(
                                      ALOGW("captureScreen: error creating EGL fence: %#x", eglGetError());
                                  }
                              }
    @@ -2285,10 +2399,18 @@ index e0e4c61..6f2520b 100644
      #ifdef USE_HWC2
          err = updateAndReleaseLocked(item, &mPendingRelease);
     diff --git a/services/surfaceflinger/SurfaceFlinger_hwc1.cpp b/services/surfaceflinger/SurfaceFlinger_hwc1.cpp
    -index b32f652..512f63d 100644
    +index b32f652..c9ac4d7 100644
     --- a/services/surfaceflinger/SurfaceFlinger_hwc1.cpp
     +++ b/services/surfaceflinger/SurfaceFlinger_hwc1.cpp
    -@@ -457,19 +457,28 @@ void SurfaceFlinger::init() {
    +@@ -26,6 +26,7 @@
    + 
    + #include <EGL/egl.h>
    + 
    ++#include <cutils/iosched_policy.h>
    + #include <cutils/log.h>
    + #include <cutils/properties.h>
    + 
    +@@ -457,19 +458,28 @@ void SurfaceFlinger::init() {
          eglInitialize(mEGLDisplay, NULL, NULL);
      
          // start the EventThread
    @@ -2328,7 +2450,15 @@ index b32f652..512f63d 100644
          }
      
      
    -@@ -635,10 +644,21 @@ status_t SurfaceFlinger::getDisplayConfigs(const sp<IBinder>& display,
    +@@ -526,6 +536,7 @@ void SurfaceFlinger::init() {
    + 
    +     mEventControlThread = new EventControlThread(this);
    +     mEventControlThread->run("EventControl", PRIORITY_URGENT_DISPLAY);
    ++    android_set_rt_ioprio(mEventControlThread->getTid(), 1);
    + 
    +     // set a fake vsync period if there is no HWComposer
    +     if (mHwc->initCheck() != NO_ERROR) {
    +@@ -635,10 +646,21 @@ status_t SurfaceFlinger::getDisplayConfigs(const sp<IBinder>& display,
                  info.orientation = 0;
              }
      
    @@ -2354,7 +2484,7 @@ index b32f652..512f63d 100644
              info.fps = float(1e9 / hwConfig.refresh);
              info.appVsyncOffset = VSYNC_EVENT_PHASE_OFFSET_NS;
      
    -@@ -3186,12 +3206,14 @@ status_t SurfaceFlinger::onTransact(
    +@@ -3186,12 +3208,14 @@ status_t SurfaceFlinger::onTransact(
                  }
                  case 1018: { // Modify Choreographer's phase offset
                      n = data.readInt32();
    @@ -2371,7 +2501,7 @@ index b32f652..512f63d 100644
                      return NO_ERROR;
                  }
                  case 1021: { // Disable HWC virtual displays
    -@@ -3330,7 +3352,8 @@ status_t SurfaceFlinger::captureScreen(const sp<IBinder>& display,
    +@@ -3330,7 +3354,8 @@ status_t SurfaceFlinger::captureScreen(const sp<IBinder>& display,
              const sp<IGraphicBufferProducer>& producer,
              Rect sourceCrop, uint32_t reqWidth, uint32_t reqHeight,
              uint32_t minLayerZ, uint32_t maxLayerZ,
    @@ -2381,7 +2511,7 @@ index b32f652..512f63d 100644
      
          if (CC_UNLIKELY(display == 0))
              return BAD_VALUE;
    -@@ -3374,6 +3397,7 @@ status_t SurfaceFlinger::captureScreen(const sp<IBinder>& display,
    +@@ -3374,6 +3399,7 @@ status_t SurfaceFlinger::captureScreen(const sp<IBinder>& display,
              bool useIdentityTransform;
              Transform::orientation_flags rotation;
              status_t result;
    @@ -2389,7 +2519,7 @@ index b32f652..512f63d 100644
              bool isLocalScreenshot;
          public:
              MessageCaptureScreen(SurfaceFlinger* flinger,
    -@@ -3383,12 +3407,13 @@ status_t SurfaceFlinger::captureScreen(const sp<IBinder>& display,
    +@@ -3383,12 +3409,13 @@ status_t SurfaceFlinger::captureScreen(const sp<IBinder>& display,
                      uint32_t minLayerZ, uint32_t maxLayerZ,
                      bool useIdentityTransform,
                      Transform::orientation_flags rotation,
    @@ -2404,7 +2534,7 @@ index b32f652..512f63d 100644
                    isLocalScreenshot(isLocalScreenshot)
              {
              }
    -@@ -3398,9 +3423,10 @@ status_t SurfaceFlinger::captureScreen(const sp<IBinder>& display,
    +@@ -3398,9 +3425,10 @@ status_t SurfaceFlinger::captureScreen(const sp<IBinder>& display,
              virtual bool handler() {
                  Mutex::Autolock _l(flinger->mStateLock);
                  sp<const DisplayDevice> hw(flinger->getDisplayDevice(display));
    @@ -2416,7 +2546,7 @@ index b32f652..512f63d 100644
                  static_cast<GraphicProducerWrapper*>(IInterface::asBinder(producer).get())->exit(result);
                  return true;
              }
    -@@ -3416,7 +3442,7 @@ status_t SurfaceFlinger::captureScreen(const sp<IBinder>& display,
    +@@ -3416,7 +3444,7 @@ status_t SurfaceFlinger::captureScreen(const sp<IBinder>& display,
          sp<MessageBase> msg = new MessageCaptureScreen(this,
                  display, IGraphicBufferProducer::asInterface( wrapper ),
                  sourceCrop, reqWidth, reqHeight, minLayerZ, maxLayerZ,
    @@ -2425,7 +2555,7 @@ index b32f652..512f63d 100644
      
          status_t res = postMessageAsync(msg);
          if (res == NO_ERROR) {
    -@@ -3501,7 +3527,7 @@ status_t SurfaceFlinger::captureScreenImplLocked(
    +@@ -3501,7 +3529,7 @@ status_t SurfaceFlinger::captureScreenImplLocked(
              Rect sourceCrop, uint32_t reqWidth, uint32_t reqHeight,
              uint32_t minLayerZ, uint32_t maxLayerZ,
              bool useIdentityTransform, Transform::orientation_flags rotation,
    @@ -2434,7 +2564,7 @@ index b32f652..512f63d 100644
      {
          ATRACE_CALL();
      
    -@@ -3571,7 +3597,7 @@ status_t SurfaceFlinger::captureScreenImplLocked(
    +@@ -3571,7 +3599,7 @@ status_t SurfaceFlinger::captureScreenImplLocked(
                      if (image != EGL_NO_IMAGE_KHR) {
                          // this binds the given EGLImage as a framebuffer for the
                          // duration of this scope.
    @@ -2443,7 +2573,7 @@ index b32f652..512f63d 100644
                          if (imageBond.getStatus() == NO_ERROR) {
                              // this will in fact render into our dequeued buffer
                              // via an FBO, which means we didn't have to create
    -@@ -3618,6 +3644,16 @@ status_t SurfaceFlinger::captureScreenImplLocked(
    +@@ -3618,6 +3646,16 @@ status_t SurfaceFlinger::captureScreenImplLocked(
                                      ALOGW("captureScreen: error creating EGL fence: %#x", eglGetError());
                                  }
                              }
    diff --git a/system_core.patch b/system_core.patch
    index 2787712..2ab3421 100644
    --- a/system_core.patch
    +++ b/system_core.patch
    @@ -1,3 +1,37 @@
    +diff --git a/include/cutils/iosched_policy.h b/include/cutils/iosched_policy.h
    +index 07c5d1f..25b87ba 100644
    +--- a/include/cutils/iosched_policy.h
    ++++ b/include/cutils/iosched_policy.h
    +@@ -31,6 +31,8 @@ typedef enum {
    + extern int android_set_ioprio(int pid, IoSchedClass clazz, int ioprio);
    + extern int android_get_ioprio(int pid, IoSchedClass *clazz, int *ioprio);
    + 
    ++extern int android_set_rt_ioprio(int pid, int rt);
    ++
    + #ifdef __cplusplus
    + }
    + #endif
    +diff --git a/include/private/android_filesystem_config.h b/include/private/android_filesystem_config.h
    +index 5ccd80e..ed8ae35 100644
    +--- a/include/private/android_filesystem_config.h
    ++++ b/include/private/android_filesystem_config.h
    +@@ -121,6 +121,8 @@
    + /* The range 5000-5999 is also reserved for OEM, and must never be used here. */
    + #define AID_OEM_RESERVED_2_START 5000
    + #define AID_OEM_RESERVED_2_END   5999
    ++#define AID_SENSORS       3011 /* access to /dev/socket/sensor_ctl_socket & QCCI/QCSI */
    ++
    + 
    + #define AID_EVERYBODY     9997  /* shared between all apps in the same profile */
    + #define AID_MISC          9998  /* access to misc storage */
    +@@ -222,6 +224,7 @@ static const struct android_id_info android_ids[] = {
    +     { "net_bt_stack",  AID_NET_BT_STACK, },
    +     { "readproc",      AID_READPROC, },
    +     { "wakelock",      AID_WAKELOCK, },
    ++    { "sensors",       AID_SENSORS, },
    + 
    +     { "everybody",     AID_EVERYBODY, },
    +     { "misc",          AID_MISC, },
     diff --git a/include/system/camera.h b/include/system/camera.h
     index 5d0873a..e4c0a47 100644
     --- a/include/system/camera.h
    @@ -196,6 +230,174 @@ index cd2d2e6..81628a1 100644
          am.QueueBuiltinAction(keychord_init_action, "keychord_init");
          am.QueueBuiltinAction(console_init_action, "console_init");
      
    +diff --git a/libcutils/iosched_policy.c b/libcutils/iosched_policy.c
    +index 71bc94b..8a21b8b 100644
    +--- a/libcutils/iosched_policy.c
    ++++ b/libcutils/iosched_policy.c
    +@@ -1,9 +1,10 @@
    + /*
    +-** Copyright 2007, The Android Open Source Project
    ++** Copyright 2007-2014, The Android Open Source Project
    ++** Copyright 2015, The CyanogenMod 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 
    ++** 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 
    + **
    +@@ -20,28 +21,30 @@
    + #include <stdlib.h>
    + #include <string.h>
    + #include <unistd.h>
    ++#include <pthread.h>
    + 
    + #include <cutils/iosched_policy.h>
    ++#define LOG_TAG "iosched_policy"
    ++#include <cutils/log.h>
    ++
    ++#define __android_unused __attribute__((__unused__))
    + 
    + #if defined(__ANDROID__)
    + #include <linux/ioprio.h>
    + #include <sys/syscall.h>
    +-#define __android_unused
    +-#else
    +-#define __android_unused __attribute__((__unused__))
    +-#endif
    ++#include <sys/stat.h>
    ++
    ++static int __rtio_cgroup_supported = -1;
    ++static pthread_once_t __rtio_init_once = PTHREAD_ONCE_INIT;
    + 
    + int android_set_ioprio(int pid __android_unused, IoSchedClass clazz __android_unused, int ioprio __android_unused) {
    +-#if defined(__ANDROID__)
    +     if (syscall(SYS_ioprio_set, IOPRIO_WHO_PROCESS, pid, ioprio | (clazz << IOPRIO_CLASS_SHIFT))) {
    +         return -1;
    +     }
    +-#endif
    +     return 0;
    + }
    + 
    + int android_get_ioprio(int pid __android_unused, IoSchedClass *clazz, int *ioprio) {
    +-#if defined(__ANDROID__)
    +     int rc;
    + 
    +     if ((rc = syscall(SYS_ioprio_get, IOPRIO_WHO_PROCESS, pid)) < 0) {
    +@@ -50,9 +53,84 @@ int android_get_ioprio(int pid __android_unused, IoSchedClass *clazz, int *iopri
    + 
    +     *clazz = (rc >> IOPRIO_CLASS_SHIFT);
    +     *ioprio = (rc & 0xff);
    ++    return 0;
    ++}
    ++
    ++static void __initialize_rtio(void) {
    ++    if (!access("/dev/bfqio/tasks", W_OK) ||
    ++        !access("/dev/bfqio/rt-display/tasks", W_OK)) {
    ++        __rtio_cgroup_supported = 1;
    ++    } else {
    ++        __rtio_cgroup_supported = 0;
    ++    }
    ++}
    ++
    ++int android_set_rt_ioprio(int tid, int rt) {
    ++    int fd = -1, rc = -1;
    ++
    ++    pthread_once(&__rtio_init_once, __initialize_rtio);
    ++    if (__rtio_cgroup_supported != 1) {
    ++        return -1;
    ++    }
    ++
    ++    if (rt) {
    ++        fd = open("/dev/bfqio/rt-display/tasks", O_WRONLY | O_CLOEXEC);
    ++    } else {
    ++        fd = open("/dev/bfqio/tasks", O_WRONLY | O_CLOEXEC);
    ++    }
    ++
    ++    if (fd < 0) {
    ++        return -1;
    ++    }
    ++
    ++#ifdef HAVE_GETTID
    ++    if (tid == 0) {
    ++        tid = gettid();
    ++    }
    ++#endif
    ++
    ++    // specialized itoa -- works for tid > 0
    ++    char text[22];
    ++    char *end = text + sizeof(text) - 1;
    ++    char *ptr = end;
    ++    *ptr = '\0';
    ++    while (tid > 0) {
    ++        *--ptr = '0' + (tid % 10);
    ++        tid = tid / 10;
    ++    }
    ++
    ++    rc = write(fd, ptr, end - ptr);
    ++    if (rc < 0) {
    ++        /*
    ++         * If the thread is in the process of exiting,
    ++         * don't flag an error
    ++         */
    ++        if (errno == ESRCH) {
    ++            rc = 0;
    ++        } else {
    ++            SLOGV("android_set_rt_ioprio failed to write '%s' (%s); fd=%d\n",
    ++                  ptr, strerror(errno), fd);
    ++        }
    ++    }
    ++
    ++    close(fd);
    ++    return rc;
    ++}
    ++
    + #else
    ++int android_set_ioprio(int pid __android_unused, IoSchedClass clazz __android_unused, int ioprio __android_unused) {
    ++    return 0;
    ++}
    ++
    ++int android_get_ioprio(int pid __android_unused, IoSchedClass *clazz, int *ioprio) {
    +     *clazz = IoSchedClass_NONE;
    +     *ioprio = 0;
    +-#endif
    +     return 0;
    + }
    ++
    ++int android_set_rt_ioprio(int tid __android_unused, int rt __android_unused)
    ++{
    ++    return 0;
    ++}
    ++#endif
    ++
    +diff --git a/libnetutils/packet.c b/libnetutils/packet.c
    +index cd26d05..bfc5f4d 100644
    +--- a/libnetutils/packet.c
    ++++ b/libnetutils/packet.c
    +@@ -219,6 +219,20 @@ int receive_packet(int s, struct dhcp_msg *msg)
    +      * to construct the pseudo header used in the checksum calculation.
    +      */
    +     dhcp_size = ntohs(packet.udp.len) - sizeof(packet.udp);
    ++    /*
    ++     * check validity of dhcp_size.
    ++     * 1) cannot be negative or zero.
    ++     * 2) src buffer contains enough bytes to copy
    ++     * 3) cannot exceed destination buffer
    ++     */
    ++    if ((dhcp_size <= 0) ||
    ++        ((int)(nread - sizeof(struct iphdr) - sizeof(struct udphdr)) < dhcp_size) ||
    ++        ((int)sizeof(struct dhcp_msg) < dhcp_size)) {
    ++#if VERBOSE
    ++        ALOGD("Malformed Packet");
    ++#endif
    ++        return -1;
    ++    }
    +     saddr = packet.ip.saddr;
    +     daddr = packet.ip.daddr;
    +     nread = ntohs(packet.ip.tot_len);
     diff --git a/libutils/Unicode.cpp b/libutils/Unicode.cpp
     index ba084f6..bfacf1e 100644
     --- a/libutils/Unicode.cpp
    diff --git a/system_media.patch b/system_media.patch
    new file mode 100644
    index 0000000..1f7ebca
    --- /dev/null
    +++ b/system_media.patch
    @@ -0,0 +1,17 @@
    +diff --git a/camera/src/camera_metadata.c b/camera/src/camera_metadata.c
    +index e369c64..f76c99e 100644
    +--- a/camera/src/camera_metadata.c
    ++++ b/camera/src/camera_metadata.c
    +@@ -182,6 +182,12 @@ camera_metadata_t *allocate_copy_camera_metadata_checked(
    +         return NULL;
    +     }
    + 
    ++    if (src_size < sizeof(camera_metadata_t)) {
    ++        ALOGE("%s: Source size too small!", __FUNCTION__);
    ++        android_errorWriteLog(0x534e4554, "67782345");
    ++        return NULL;
    ++    }
    ++
    +     void *buffer = malloc(src_size);
    +     memcpy(buffer, src, src_size);
    + 
    diff --git a/system_sepolicy.patch b/system_sepolicy.patch
    index 1d9a08e..346762d 100644
    --- a/system_sepolicy.patch
    +++ b/system_sepolicy.patch
    @@ -1,3 +1,26 @@
    +diff --git a/Android.mk b/Android.mk
    +index 0bfa54d..a8b7ff7 100644
    +--- a/Android.mk
    ++++ b/Android.mk
    +@@ -95,7 +95,10 @@ $(sepolicy_policy.conf): $(call build_policy, $(sepolicy_build_files))
    + 	$(hide) m4 $(PRIVATE_ADDITIONAL_M4DEFS) \
    + 		-D mls_num_sens=$(PRIVATE_MLS_SENS) -D mls_num_cats=$(PRIVATE_MLS_CATS) \
    + 		-D target_build_variant=$(TARGET_BUILD_VARIANT) \
    ++		-D target_has_legacy_camera_hal1=$(TARGET_HAS_LEGACY_CAMERA_HAL1) \
    ++		-D target_needs_platform_text_relocations=$(TARGET_NEEDS_PLATFORM_TEXTRELS) \
    + 		-s $^ > $@
    ++
    + 	$(hide) sed '/dontaudit/d' $@ > $@.dontaudit
    + 
    + $(LOCAL_BUILT_MODULE): $(sepolicy_policy.conf) $(HOST_OUT_EXECUTABLES)/checkpolicy $(HOST_OUT_EXECUTABLES)/sepolicy-analyze
    +@@ -134,6 +137,7 @@ $(sepolicy_policy_recovery.conf): $(call build_policy, $(sepolicy_build_files))
    + 		-D mls_num_sens=$(PRIVATE_MLS_SENS) -D mls_num_cats=$(PRIVATE_MLS_CATS) \
    + 		-D target_build_variant=$(TARGET_BUILD_VARIANT) \
    + 		-D target_recovery=true \
    ++		-D target_needs_platform_text_relocations=$(TARGET_NEEDS_PLATFORM_TEXTRELS) \
    + 		-s $^ > $@
    + 
    + $(LOCAL_BUILT_MODULE): $(sepolicy_policy_recovery.conf) $(HOST_OUT_EXECUTABLES)/checkpolicy $(HOST_OUT_EXECUTABLES)/sepolicy-analyze
     diff --git a/app.te b/app.te
     index e9dd7b3..ef2bd9d 100644
     --- a/app.te
    @@ -12,9 +35,18 @@ index e9dd7b3..ef2bd9d 100644
      
      # Block device access.
     diff --git a/domain.te b/domain.te
    -index 45569de..21c9df2 100644
    +index 45569de..5013ad3 100644
     --- a/domain.te
     +++ b/domain.te
    +@@ -62,7 +62,7 @@ allow domain debuggerd:unix_stream_socket connectto;
    + 
    + # Root fs.
    + allow domain rootfs:dir search;
    +-allow domain rootfs:lnk_file read;
    ++allow domain rootfs:lnk_file { read getattr };
    + 
    + # Device accesses.
    + allow domain device:dir search;
     @@ -159,6 +159,7 @@ neverallow {
        -dumpstate
        -system_server
    @@ -59,7 +91,7 @@ index 45569de..21c9df2 100644
      } dalvikcache_data_file:dir no_w_dir_perms;
      
      # Only system_server should be able to send commands via the zygote socket
    -@@ -428,13 +435,13 @@ neverallow { domain userdebug_or_eng(`-dumpstate -shell -su') } su_exec:file no_
    +@@ -428,14 +435,24 @@ neverallow { domain userdebug_or_eng(`-dumpstate -shell -su') } su_exec:file no_
      # The only exceptions are for NDK text relocations associated with
      # https://code.google.com/p/android/issues/detail?id=23203
      # which, long term, need to go away.
    @@ -70,26 +102,40 @@ index 45569de..21c9df2 100644
     -  -app_data_file
     -  -asec_public_file
     -}:file execmod;
    -+#neverallow * {
    -+#  file_type
    -+#  -system_data_file
    -+#  -apk_data_file
    -+#  -app_data_file
    -+#  -asec_public_file
    -+#}:file execmod;
    - 
    +-
    ++#ifelse(target_needs_platform_text_relocations, `true',
    ++#  `neverallow * {
    ++#    file_type
    ++#    -system_file
    ++#    -system_data_file
    ++#    -apk_data_file
    ++#    -app_data_file
    ++#    -asec_public_file
    ++#  }:file execmod;'
    ++#,
    ++#  `neverallow * {
    ++#    file_type
    ++#    -system_data_file
    ++#    -apk_data_file
    ++#    -app_data_file
    ++#    -asec_public_file
    ++#  }:file execmod;'
    ++#)
      # Do not allow making the stack or heap executable.
      # We would also like to minimize execmem but it seems to be
    -@@ -443,7 +450,7 @@ neverallow * self:process { execstack execheap };
    + # required by some device-specific service domains.
    +@@ -443,7 +460,9 @@ neverallow * self:process { execstack execheap };
      
      # prohibit non-zygote spawned processes from using shared libraries
      # with text relocations. b/20013628 .
     -neverallow { domain -appdomain } file_type:file execmod;
    -+#neverallow { domain -appdomain } file_type:file execmod;
    ++#ifelse(target_needs_platform_text_relocations, `true', ,
    ++#  `neverallow { domain -appdomain } file_type:file execmod;'
    ++#)
      
      neverallow { domain -init } proc:{ file dir } mounton;
      
    -@@ -570,7 +577,7 @@ neverallow * domain:file { execute execute_no_trans entrypoint };
    +@@ -570,7 +589,7 @@ neverallow * domain:file { execute execute_no_trans entrypoint };
      # Instead, if access to part of debugfs is desired, it should have a
      # more specific label.
      # TODO: fix system_server and dumpstate
    @@ -111,6 +157,23 @@ index 87cec82..bdc7cbe 100644
      type fuse, sdcard_type, fs_type, mlstrustedobject;
      type sdcardfs, sdcard_type, fs_type, mlstrustedobject;
      type vfat, sdcard_type, fs_type, mlstrustedobject;
    +diff --git a/mediaserver.te b/mediaserver.te
    +index 5fbaa30..dc05e14 100644
    +--- a/mediaserver.te
    ++++ b/mediaserver.te
    +@@ -94,6 +94,12 @@ allow mediaserver processinfo_service:service_manager find;
    + allow mediaserver scheduling_policy_service:service_manager find;
    + allow mediaserver surfaceflinger_service:service_manager find;
    + 
    ++ifelse(target_has_legacy_camera_hal1, `true',
    ++  allow mediaserver cameraproxy_service:service_manager find;
    ++  allow mediaserver cameraserver_service:service_manager add;
    ++,
    ++)
    ++
    + # /oem access
    + allow mediaserver oemfs:dir search;
    + allow mediaserver oemfs:file r_file_perms;
     diff --git a/priv_app.te b/priv_app.te
     index 85516a6..e1f96d5 100644
     --- a/priv_app.te
    
    From 08b1f994bcee773ed528935bd8b345dde1d5823d Mon Sep 17 00:00:00 2001
    From: AndDiSa <anddisa@googlemail.com>
    Date: Fri, 26 Jan 2018 16:03:02 +0100
    Subject: [PATCH 091/159] move from millosr to own repo
    
    Change-Id: I5facff1cff52d03139d21bd32ac95d1bcd6d8163
    ---
     default.xml | 4 +---
     1 file changed, 1 insertion(+), 3 deletions(-)
    
    diff --git a/default.xml b/default.xml
    index 6c1e78a..c9fb020 100644
    --- a/default.xml
    +++ b/default.xml
    @@ -5,8 +5,6 @@
                fetch="https://android.googlesource.com/" />
       <remote  name="ads"
                fetch="https://github.com/AndDiSa/" />
    -  <remote  name="millosr"
    -           fetch="https://github.com/millosr/" />
       <remote  name="unlegacy"
                fetch="https://github.com/Unlegacy-Android/" />
       <default revision="refs/tags/android-7.1.2_r33"
    @@ -31,7 +29,7 @@
       <project path="developers/samples/android" name="platform/developers/samples/android" />
       <project path="development" name="platform/development" groups="pdk-cw-fs,pdk-fs" />
       <project path="device/asus/grouper" name="android_device_asus_grouper" remote="ads" revision="ads-7.1.0" groups="device,grouper" />
    -  <project path="device/asus/tilapia" name="device_asus_tilapia" remote="millosr" revision="nAOSP-7.1.2" groups="device,grouper" />
    +  <project path="device/asus/tilapia" name="device_asus_tilapia" remote="ads" revision="ads-7.1.0" groups="device,grouper" />
       <project path="device/common" name="device/common" groups="pdk-cw-fs,pdk-fs" />
       <project path="device/generic/arm64" name="device/generic/arm64" groups="pdk" />
       <project path="device/generic/armv7-a-neon" name="device/generic/armv7-a-neon" groups="pdk" />
    
    From 1178aff6cb8e0c70ad9f2752a20b91d3613b72b9 Mon Sep 17 00:00:00 2001
    From: AndDiSa <anddisa@googlemail.com>
    Date: Fri, 9 Feb 2018 17:05:23 +0100
    Subject: [PATCH 092/159] update patches
    
    Change-Id: I89f3181ef1ed03efcba76f6e7b4799dad91ce3f2
    ---
     build.patch                  |  10 +-
     external_libavc.patch        |  31 ++++++
     external_libhevc.patch       | 125 ++++++++++++++++++++++++-
     external_libmpeg2.patch      | 125 ++++++++++++++++++++++++-
     external_sonivox.patch       | 103 ++++++++++++++++++++
     frameworks_av.patch          | 177 +++++++++++++++++++++++++++++++++++
     frameworks_base.patch        |  50 ++++++++++
     packages_apps_settings.patch |  13 +++
     8 files changed, 621 insertions(+), 13 deletions(-)
    
    diff --git a/build.patch b/build.patch
    index 02d2ea7..89e29a2 100644
    --- a/build.patch
    +++ b/build.patch
    @@ -122,7 +122,7 @@ index 6438d51..2204f78 100644
          $(strip $(PRODUCTS.$(INTERNAL_PRODUCT).PRODUCT_PACKAGE_OVERLAYS))
     diff --git a/core/tasks/kernel.mk b/core/tasks/kernel.mk
     new file mode 100644
    -index 0000000..ee76dc2
    +index 0000000..80664fa
     --- /dev/null
     +++ b/core/tasks/kernel.mk
     @@ -0,0 +1,196 @@
    @@ -265,9 +265,9 @@ index 0000000..ee76dc2
     +    endif
     +    ifneq ($(TARGET_KERNEL_CUSTOM_TOOLCHAIN),)
     +        ifeq ($(HOST_OS),darwin)
    -+            ARM_CROSS_COMPILE:=CROSS_COMPILE="$(ccache) $(ANDROID_BUILD_TOP)/prebuilts/gcc/darwin-x86/arm/$(TARGET_KERNEL_CUSTOM_TOOLCHAIN)/bin/arm-eabi-"
    ++            ARM_CROSS_COMPILE:=CROSS_COMPILE="$(ccache) $(ANDROID_BUILD_TOP)/prebuilts/gcc/darwin-x86/arm/$(TARGET_KERNEL_CUSTOM_TOOLCHAIN)/bin/$(KERNEL_TOOLCHAIN_PREFIX)"
     +        else
    -+            ARM_CROSS_COMPILE:=CROSS_COMPILE="$(ccache) $(ANDROID_BUILD_TOP)/prebuilts/gcc/linux-x86/arm/$(TARGET_KERNEL_CUSTOM_TOOLCHAIN)/bin/arm-eabi-"
    ++            ARM_CROSS_COMPILE:=CROSS_COMPILE="$(ccache) $(ANDROID_BUILD_TOP)/prebuilts/gcc/linux-x86/arm/$(TARGET_KERNEL_CUSTOM_TOOLCHAIN)/bin/$(KERNEL_TOOLCHAIN_PREFIX)"
     +        endif
     +    else
     +        ARM_CROSS_COMPILE:=CROSS_COMPILE="$(ccache) $(ARM_EABI_TOOLCHAIN)/arm-eabi-"
    @@ -323,7 +323,7 @@ index 0000000..ee76dc2
     +ALL_PREBUILT += $(INSTALLED_KERNEL_TARGET)
     +endif
     diff --git a/core/version_defaults.mk b/core/version_defaults.mk
    -index 7c96344..68fcba2 100644
    +index 7c96344..42fa3a8 100644
     --- a/core/version_defaults.mk
     +++ b/core/version_defaults.mk
     @@ -131,7 +131,7 @@ ifeq "" "$(PLATFORM_SECURITY_PATCH)"
    @@ -331,7 +331,7 @@ index 7c96344..68fcba2 100644
          #  It must match one of the Android Security Patch Level strings of the Public Security Bulletins.
          #  If there is no $PLATFORM_SECURITY_PATCH set, keep it empty.
     -    PLATFORM_SECURITY_PATCH := 2017-08-05
    -+    PLATFORM_SECURITY_PATCH := 2018-01-05
    ++    PLATFORM_SECURITY_PATCH := 2018-02-05
      endif
      
      ifeq "" "$(PLATFORM_BASE_OS)"
    diff --git a/external_libavc.patch b/external_libavc.patch
    index aa6f727..7b74c3f 100644
    --- a/external_libavc.patch
    +++ b/external_libavc.patch
    @@ -229,6 +229,37 @@ index 2cde456..5ef49b1 100644
          ps_dec->u4_num_disp_bufs_requested = ps_ctl_op->u4_num_disp_bufs;
      
          return IV_SUCCESS;
    +diff --git a/decoder/ih264d_dpb_mgr.c b/decoder/ih264d_dpb_mgr.c
    +index 0a61ffd..7e0db74 100644
    +--- a/decoder/ih264d_dpb_mgr.c
    ++++ b/decoder/ih264d_dpb_mgr.c
    +@@ -721,7 +721,7 @@ WORD32 ih264d_ref_idx_reordering(dec_struct_t *ps_dec, UWORD8 uc_lx)
    +     UWORD16 ui_max_frame_num =
    +                     ps_dec->ps_cur_sps->u2_u4_max_pic_num_minus1 + 1;
    + 
    +-    WORD32 i;
    ++    WORD32 i, count = 0;
    +     UWORD32 ui_remapIdc, ui_nextUev;
    +     WORD16 u2_pred_frame_num = u4_cur_pic_num;
    +     WORD32 i_temp;
    +@@ -742,7 +742,8 @@ WORD32 ih264d_ref_idx_reordering(dec_struct_t *ps_dec, UWORD8 uc_lx)
    + 
    +     ui_remapIdc = ih264d_uev(pu4_bitstrm_ofst, pu4_bitstrm_buf);
    + 
    +-    while(ui_remapIdc != 3)
    ++    while((ui_remapIdc != 3)
    ++                    && (count < ps_cur_slice->u1_num_ref_idx_lx_active[uc_lx]))
    +     {
    +         ui_nextUev = ih264d_uev(pu4_bitstrm_ofst, pu4_bitstrm_buf);
    +         if(ui_remapIdc != 2)
    +@@ -811,6 +812,7 @@ WORD32 ih264d_ref_idx_reordering(dec_struct_t *ps_dec, UWORD8 uc_lx)
    + 
    +         ui_remapIdc = ih264d_uev(pu4_bitstrm_ofst, pu4_bitstrm_buf);
    +         /* Get the remapping_idc - 0/1/2/3 */
    ++        count++;
    +     }
    + 
    +     //Handle the ref indices that were not remapped
     diff --git a/decoder/ih264d_parse_bslice.c b/decoder/ih264d_parse_bslice.c
     index 772964a..f087f8d 100644
     --- a/decoder/ih264d_parse_bslice.c
    diff --git a/external_libhevc.patch b/external_libhevc.patch
    index 467feca..87f6034 100644
    --- a/external_libhevc.patch
    +++ b/external_libhevc.patch
    @@ -4169,10 +4169,23 @@ index d656519..d2ea7a5 100644
      
          if(1 == ps_codec->i4_pic_present)
     diff --git a/decoder/ihevcd_parse_headers.c b/decoder/ihevcd_parse_headers.c
    -index c0f1564..6a9fe5e 100644
    +index c0f1564..8348fc6 100644
     --- a/decoder/ihevcd_parse_headers.c
     +++ b/decoder/ihevcd_parse_headers.c
    -@@ -1285,15 +1285,31 @@ IHEVCD_ERROR_T ihevcd_parse_sps(codec_t *ps_codec)
    +@@ -1272,12 +1272,6 @@ IHEVCD_ERROR_T ihevcd_parse_sps(codec_t *ps_codec)
    +     if((0 >= ps_sps->i2_pic_width_in_luma_samples) || (0 >= ps_sps->i2_pic_height_in_luma_samples))
    +         return IHEVCD_INVALID_PARAMETER;
    + 
    +-    /* i2_pic_width_in_luma_samples and i2_pic_height_in_luma_samples
    +-       should be multiples of min_cb_size. Here these are aligned to 8,
    +-       i.e. smallest CB size */
    +-    ps_sps->i2_pic_width_in_luma_samples = ALIGN8(ps_sps->i2_pic_width_in_luma_samples);
    +-    ps_sps->i2_pic_height_in_luma_samples = ALIGN8(ps_sps->i2_pic_height_in_luma_samples);
    +-
    +     BITS_PARSE("pic_cropping_flag", value, ps_bitstrm, 1);
    +     ps_sps->i1_pic_cropping_flag = value;
    + 
    +@@ -1285,15 +1279,31 @@ IHEVCD_ERROR_T ihevcd_parse_sps(codec_t *ps_codec)
          {
      
              UEV_PARSE("pic_crop_left_offset", value, ps_bitstrm);
    @@ -4204,7 +4217,18 @@ index c0f1564..6a9fe5e 100644
              ps_sps->i2_pic_crop_bottom_offset = value;
          }
          else
    -@@ -1797,6 +1813,19 @@ IHEVCD_ERROR_T ihevcd_parse_pps(codec_t *ps_codec)
    +@@ -1402,7 +1412,9 @@ IHEVCD_ERROR_T ihevcd_parse_sps(codec_t *ps_codec)
    +                     (ps_sps->i1_log2_diff_max_min_transform_block_size < 0) ||
    +                     (ps_sps->i1_log2_max_transform_block_size > ps_sps->i1_log2_ctb_size) ||
    +                     (ps_sps->i1_log2_ctb_size < 4) ||
    +-                    (ps_sps->i1_log2_ctb_size > 6))
    ++                    (ps_sps->i1_log2_ctb_size > 6) ||
    ++                    (ps_sps->i2_pic_width_in_luma_samples % (1 << ps_sps->i1_log2_min_coding_block_size) != 0) ||
    ++                    (ps_sps->i2_pic_height_in_luma_samples % (1 << ps_sps->i1_log2_min_coding_block_size) != 0))
    +     {
    +         return IHEVCD_INVALID_PARAMETER;
    +     }
    +@@ -1797,6 +1809,19 @@ IHEVCD_ERROR_T ihevcd_parse_pps(codec_t *ps_codec)
          BITS_PARSE("tiles_enabled_flag", value, ps_bitstrm, 1);
          ps_pps->i1_tiles_enabled_flag = value;
      
    @@ -4225,7 +4249,7 @@ index c0f1564..6a9fe5e 100644
          ps_pps->i1_entropy_coding_sync_enabled_flag = value;
      
     diff --git a/decoder/ihevcd_parse_slice.c b/decoder/ihevcd_parse_slice.c
    -index 126b14c..70c2e88 100644
    +index 126b14c..e394a4e 100644
     --- a/decoder/ihevcd_parse_slice.c
     +++ b/decoder/ihevcd_parse_slice.c
     @@ -2376,26 +2376,29 @@ IHEVCD_ERROR_T ihevcd_parse_slice_data(codec_t *ps_codec)
    @@ -4329,6 +4353,51 @@ index 126b14c..70c2e88 100644
                                  ((ps_pps->i1_tiles_enabled_flag && end_of_tile) ||
                                                  (ps_pps->i1_entropy_coding_sync_enabled_flag && end_of_tile_row)))
                  {
    +@@ -3090,15 +3105,7 @@ IHEVCD_ERROR_T ihevcd_parse_slice_data(codec_t *ps_codec)
    +                 UWORD32 *pu4_nbr_pu_idx = ps_proc->pu4_pic_pu_idx_map;
    +                 WORD32 nbr_pu_idx_strd = MAX_CTB_SIZE / MIN_PU_SIZE + 2;
    +                 pu_t *ps_pu;
    +-
    +-                for(row = 0; row < ctb_size / MIN_PU_SIZE; row++)
    +-                {
    +-                    for(col = 0; col < ctb_size / MIN_PU_SIZE; col++)
    +-                    {
    +-                        pu1_pic_pu_map_ctb[row * ctb_size / MIN_PU_SIZE + col] = 0;
    +-                    }
    +-                }
    +-
    ++                WORD32 ctb_size_in_min_pu = (ctb_size / MIN_PU_SIZE);
    + 
    +                 /* Neighbor PU idx update inside CTB */
    +                 /* 1byte per 4x4. Indicates the PU idx that 4x4 block belongs to */
    +@@ -3149,6 +3156,27 @@ IHEVCD_ERROR_T ihevcd_parse_slice_data(codec_t *ps_codec)
    + 
    +                     }
    +                 }
    ++
    ++                /* Updating the CTB level PU idx (Used for collocated MV pred)*/
    ++                {
    ++                    WORD32 ctb_row, ctb_col, index_pic_map, index_nbr_map;
    ++                    WORD32 first_pu_of_ctb;
    ++                    first_pu_of_ctb = pu4_nbr_pu_idx[1 + nbr_pu_idx_strd];
    ++
    ++                    index_pic_map = 0 * ctb_size_in_min_pu + 0;
    ++                    index_nbr_map = (0 + 1) * nbr_pu_idx_strd + (0 + 1);
    ++
    ++                    for(ctb_row = 0; ctb_row < ctb_size_in_min_pu; ctb_row++)
    ++                    {
    ++                        for(ctb_col = 0; ctb_col < ctb_size_in_min_pu; ctb_col++)
    ++                        {
    ++                            pu1_pic_pu_map_ctb[index_pic_map + ctb_col] = pu4_nbr_pu_idx[index_nbr_map + ctb_col]
    ++                                            - first_pu_of_ctb;
    ++                        }
    ++                        index_pic_map += ctb_size_in_min_pu;
    ++                        index_nbr_map += nbr_pu_idx_strd;
    ++                    }
    ++                }
    +             }
    + 
    +             /*************************************************/
     diff --git a/decoder/ihevcd_parse_slice_header.c b/decoder/ihevcd_parse_slice_header.c
     index e1b50b7..ae19328 100644
     --- a/decoder/ihevcd_parse_slice_header.c
    @@ -4342,6 +4411,54 @@ index e1b50b7..ae19328 100644
                  return IHEVCD_IGNORE_SLICE;
          }
          else
    +diff --git a/decoder/ihevcd_process_slice.c b/decoder/ihevcd_process_slice.c
    +index f57cc31..72db2cc 100644
    +--- a/decoder/ihevcd_process_slice.c
    ++++ b/decoder/ihevcd_process_slice.c
    +@@ -704,14 +704,8 @@ IHEVCD_ERROR_T ihevcd_process(process_ctxt_t *ps_proc)
    +                     WORD32 row, col;
    +                     UWORD32 *pu4_nbr_pu_idx = ps_proc->pu4_pic_pu_idx_map;
    +                     WORD32 nbr_pu_idx_strd = MAX_CTB_SIZE / MIN_PU_SIZE + 2;
    ++                    WORD32 ctb_size_in_min_pu = (ctb_size / MIN_PU_SIZE);
    + 
    +-                    for(row = 0; row < ctb_size / MIN_PU_SIZE; row++)
    +-                    {
    +-                        for(col = 0; col < ctb_size / MIN_PU_SIZE; col++)
    +-                        {
    +-                            pu1_pic_pu_map_ctb[row * ctb_size / MIN_PU_SIZE + col] = 0;
    +-                        }
    +-                    }
    +                     /* Neighbor PU idx update inside CTB */
    +                     /* 1byte per 4x4. Indicates the PU idx that 4x4 block belongs to */
    + 
    +@@ -760,6 +754,27 @@ IHEVCD_ERROR_T ihevcd_process(process_ctxt_t *ps_proc)
    +                                             pu4_nbr_pu_idx[(ctb_size_left / MIN_PU_SIZE) * nbr_pu_idx_strd + i + 1];
    + 
    +                         }
    ++
    ++                        /* Updating the CTB level PU idx (Used for collocated MV pred)*/
    ++                        {
    ++                            WORD32 ctb_row, ctb_col, index_pic_map, index_nbr_map;
    ++                            WORD32 first_pu_of_ctb;
    ++                            first_pu_of_ctb = pu4_nbr_pu_idx[1 + nbr_pu_idx_strd];
    ++
    ++                            index_pic_map = 0 * ctb_size_in_min_pu + 0;
    ++                            index_nbr_map = (0 + 1) * nbr_pu_idx_strd + (0 + 1);
    ++
    ++                            for(ctb_row = 0; ctb_row < ctb_size_in_min_pu; ctb_row++)
    ++                            {
    ++                                for(ctb_col = 0; ctb_col < ctb_size_in_min_pu; ctb_col++)
    ++                                {
    ++                                    pu1_pic_pu_map_ctb[index_pic_map + ctb_col] = pu4_nbr_pu_idx[index_nbr_map + ctb_col]
    ++                                                    - first_pu_of_ctb;
    ++                                }
    ++                                index_pic_map += ctb_size_in_min_pu;
    ++                                index_nbr_map += nbr_pu_idx_strd;
    ++                            }
    ++                        }
    +                     }
    +                 }
    +             }
     diff --git a/decoder/ihevcd_utils.c b/decoder/ihevcd_utils.c
     index 7d76577..14cdd2b 100755
     --- a/decoder/ihevcd_utils.c
    diff --git a/external_libmpeg2.patch b/external_libmpeg2.patch
    index 467feca..87f6034 100644
    --- a/external_libmpeg2.patch
    +++ b/external_libmpeg2.patch
    @@ -4169,10 +4169,23 @@ index d656519..d2ea7a5 100644
      
          if(1 == ps_codec->i4_pic_present)
     diff --git a/decoder/ihevcd_parse_headers.c b/decoder/ihevcd_parse_headers.c
    -index c0f1564..6a9fe5e 100644
    +index c0f1564..8348fc6 100644
     --- a/decoder/ihevcd_parse_headers.c
     +++ b/decoder/ihevcd_parse_headers.c
    -@@ -1285,15 +1285,31 @@ IHEVCD_ERROR_T ihevcd_parse_sps(codec_t *ps_codec)
    +@@ -1272,12 +1272,6 @@ IHEVCD_ERROR_T ihevcd_parse_sps(codec_t *ps_codec)
    +     if((0 >= ps_sps->i2_pic_width_in_luma_samples) || (0 >= ps_sps->i2_pic_height_in_luma_samples))
    +         return IHEVCD_INVALID_PARAMETER;
    + 
    +-    /* i2_pic_width_in_luma_samples and i2_pic_height_in_luma_samples
    +-       should be multiples of min_cb_size. Here these are aligned to 8,
    +-       i.e. smallest CB size */
    +-    ps_sps->i2_pic_width_in_luma_samples = ALIGN8(ps_sps->i2_pic_width_in_luma_samples);
    +-    ps_sps->i2_pic_height_in_luma_samples = ALIGN8(ps_sps->i2_pic_height_in_luma_samples);
    +-
    +     BITS_PARSE("pic_cropping_flag", value, ps_bitstrm, 1);
    +     ps_sps->i1_pic_cropping_flag = value;
    + 
    +@@ -1285,15 +1279,31 @@ IHEVCD_ERROR_T ihevcd_parse_sps(codec_t *ps_codec)
          {
      
              UEV_PARSE("pic_crop_left_offset", value, ps_bitstrm);
    @@ -4204,7 +4217,18 @@ index c0f1564..6a9fe5e 100644
              ps_sps->i2_pic_crop_bottom_offset = value;
          }
          else
    -@@ -1797,6 +1813,19 @@ IHEVCD_ERROR_T ihevcd_parse_pps(codec_t *ps_codec)
    +@@ -1402,7 +1412,9 @@ IHEVCD_ERROR_T ihevcd_parse_sps(codec_t *ps_codec)
    +                     (ps_sps->i1_log2_diff_max_min_transform_block_size < 0) ||
    +                     (ps_sps->i1_log2_max_transform_block_size > ps_sps->i1_log2_ctb_size) ||
    +                     (ps_sps->i1_log2_ctb_size < 4) ||
    +-                    (ps_sps->i1_log2_ctb_size > 6))
    ++                    (ps_sps->i1_log2_ctb_size > 6) ||
    ++                    (ps_sps->i2_pic_width_in_luma_samples % (1 << ps_sps->i1_log2_min_coding_block_size) != 0) ||
    ++                    (ps_sps->i2_pic_height_in_luma_samples % (1 << ps_sps->i1_log2_min_coding_block_size) != 0))
    +     {
    +         return IHEVCD_INVALID_PARAMETER;
    +     }
    +@@ -1797,6 +1809,19 @@ IHEVCD_ERROR_T ihevcd_parse_pps(codec_t *ps_codec)
          BITS_PARSE("tiles_enabled_flag", value, ps_bitstrm, 1);
          ps_pps->i1_tiles_enabled_flag = value;
      
    @@ -4225,7 +4249,7 @@ index c0f1564..6a9fe5e 100644
          ps_pps->i1_entropy_coding_sync_enabled_flag = value;
      
     diff --git a/decoder/ihevcd_parse_slice.c b/decoder/ihevcd_parse_slice.c
    -index 126b14c..70c2e88 100644
    +index 126b14c..e394a4e 100644
     --- a/decoder/ihevcd_parse_slice.c
     +++ b/decoder/ihevcd_parse_slice.c
     @@ -2376,26 +2376,29 @@ IHEVCD_ERROR_T ihevcd_parse_slice_data(codec_t *ps_codec)
    @@ -4329,6 +4353,51 @@ index 126b14c..70c2e88 100644
                                  ((ps_pps->i1_tiles_enabled_flag && end_of_tile) ||
                                                  (ps_pps->i1_entropy_coding_sync_enabled_flag && end_of_tile_row)))
                  {
    +@@ -3090,15 +3105,7 @@ IHEVCD_ERROR_T ihevcd_parse_slice_data(codec_t *ps_codec)
    +                 UWORD32 *pu4_nbr_pu_idx = ps_proc->pu4_pic_pu_idx_map;
    +                 WORD32 nbr_pu_idx_strd = MAX_CTB_SIZE / MIN_PU_SIZE + 2;
    +                 pu_t *ps_pu;
    +-
    +-                for(row = 0; row < ctb_size / MIN_PU_SIZE; row++)
    +-                {
    +-                    for(col = 0; col < ctb_size / MIN_PU_SIZE; col++)
    +-                    {
    +-                        pu1_pic_pu_map_ctb[row * ctb_size / MIN_PU_SIZE + col] = 0;
    +-                    }
    +-                }
    +-
    ++                WORD32 ctb_size_in_min_pu = (ctb_size / MIN_PU_SIZE);
    + 
    +                 /* Neighbor PU idx update inside CTB */
    +                 /* 1byte per 4x4. Indicates the PU idx that 4x4 block belongs to */
    +@@ -3149,6 +3156,27 @@ IHEVCD_ERROR_T ihevcd_parse_slice_data(codec_t *ps_codec)
    + 
    +                     }
    +                 }
    ++
    ++                /* Updating the CTB level PU idx (Used for collocated MV pred)*/
    ++                {
    ++                    WORD32 ctb_row, ctb_col, index_pic_map, index_nbr_map;
    ++                    WORD32 first_pu_of_ctb;
    ++                    first_pu_of_ctb = pu4_nbr_pu_idx[1 + nbr_pu_idx_strd];
    ++
    ++                    index_pic_map = 0 * ctb_size_in_min_pu + 0;
    ++                    index_nbr_map = (0 + 1) * nbr_pu_idx_strd + (0 + 1);
    ++
    ++                    for(ctb_row = 0; ctb_row < ctb_size_in_min_pu; ctb_row++)
    ++                    {
    ++                        for(ctb_col = 0; ctb_col < ctb_size_in_min_pu; ctb_col++)
    ++                        {
    ++                            pu1_pic_pu_map_ctb[index_pic_map + ctb_col] = pu4_nbr_pu_idx[index_nbr_map + ctb_col]
    ++                                            - first_pu_of_ctb;
    ++                        }
    ++                        index_pic_map += ctb_size_in_min_pu;
    ++                        index_nbr_map += nbr_pu_idx_strd;
    ++                    }
    ++                }
    +             }
    + 
    +             /*************************************************/
     diff --git a/decoder/ihevcd_parse_slice_header.c b/decoder/ihevcd_parse_slice_header.c
     index e1b50b7..ae19328 100644
     --- a/decoder/ihevcd_parse_slice_header.c
    @@ -4342,6 +4411,54 @@ index e1b50b7..ae19328 100644
                  return IHEVCD_IGNORE_SLICE;
          }
          else
    +diff --git a/decoder/ihevcd_process_slice.c b/decoder/ihevcd_process_slice.c
    +index f57cc31..72db2cc 100644
    +--- a/decoder/ihevcd_process_slice.c
    ++++ b/decoder/ihevcd_process_slice.c
    +@@ -704,14 +704,8 @@ IHEVCD_ERROR_T ihevcd_process(process_ctxt_t *ps_proc)
    +                     WORD32 row, col;
    +                     UWORD32 *pu4_nbr_pu_idx = ps_proc->pu4_pic_pu_idx_map;
    +                     WORD32 nbr_pu_idx_strd = MAX_CTB_SIZE / MIN_PU_SIZE + 2;
    ++                    WORD32 ctb_size_in_min_pu = (ctb_size / MIN_PU_SIZE);
    + 
    +-                    for(row = 0; row < ctb_size / MIN_PU_SIZE; row++)
    +-                    {
    +-                        for(col = 0; col < ctb_size / MIN_PU_SIZE; col++)
    +-                        {
    +-                            pu1_pic_pu_map_ctb[row * ctb_size / MIN_PU_SIZE + col] = 0;
    +-                        }
    +-                    }
    +                     /* Neighbor PU idx update inside CTB */
    +                     /* 1byte per 4x4. Indicates the PU idx that 4x4 block belongs to */
    + 
    +@@ -760,6 +754,27 @@ IHEVCD_ERROR_T ihevcd_process(process_ctxt_t *ps_proc)
    +                                             pu4_nbr_pu_idx[(ctb_size_left / MIN_PU_SIZE) * nbr_pu_idx_strd + i + 1];
    + 
    +                         }
    ++
    ++                        /* Updating the CTB level PU idx (Used for collocated MV pred)*/
    ++                        {
    ++                            WORD32 ctb_row, ctb_col, index_pic_map, index_nbr_map;
    ++                            WORD32 first_pu_of_ctb;
    ++                            first_pu_of_ctb = pu4_nbr_pu_idx[1 + nbr_pu_idx_strd];
    ++
    ++                            index_pic_map = 0 * ctb_size_in_min_pu + 0;
    ++                            index_nbr_map = (0 + 1) * nbr_pu_idx_strd + (0 + 1);
    ++
    ++                            for(ctb_row = 0; ctb_row < ctb_size_in_min_pu; ctb_row++)
    ++                            {
    ++                                for(ctb_col = 0; ctb_col < ctb_size_in_min_pu; ctb_col++)
    ++                                {
    ++                                    pu1_pic_pu_map_ctb[index_pic_map + ctb_col] = pu4_nbr_pu_idx[index_nbr_map + ctb_col]
    ++                                                    - first_pu_of_ctb;
    ++                                }
    ++                                index_pic_map += ctb_size_in_min_pu;
    ++                                index_nbr_map += nbr_pu_idx_strd;
    ++                            }
    ++                        }
    +                     }
    +                 }
    +             }
     diff --git a/decoder/ihevcd_utils.c b/decoder/ihevcd_utils.c
     index 7d76577..14cdd2b 100755
     --- a/decoder/ihevcd_utils.c
    diff --git a/external_sonivox.patch b/external_sonivox.patch
    index a3a99fa..53ad015 100644
    --- a/external_sonivox.patch
    +++ b/external_sonivox.patch
    @@ -1,3 +1,47 @@
    +diff --git a/arm-wt-22k/lib_src/eas_mdls.c b/arm-wt-22k/lib_src/eas_mdls.c
    +index 8097ba4..3ec24a0 100644
    +--- a/arm-wt-22k/lib_src/eas_mdls.c
    ++++ b/arm-wt-22k/lib_src/eas_mdls.c
    +@@ -602,6 +602,7 @@ EAS_RESULT DLSParser (EAS_HW_DATA_HANDLE hwInstData, EAS_FILE_HANDLE fileHandle,
    +         if ((dls.regionCount == 0) || (dls.regionCount > DLS_MAX_REGION_COUNT))
    +         {
    +             { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "DLS file contains invalid #regions [%u]\n", dls.regionCount); */ }
    ++            EAS_HWFree(dls.hwInstData, dls.wsmpData);
    +             return EAS_ERROR_FILE_FORMAT;
    +         }
    + 
    +@@ -609,6 +610,7 @@ EAS_RESULT DLSParser (EAS_HW_DATA_HANDLE hwInstData, EAS_FILE_HANDLE fileHandle,
    +         if ((dls.artCount == 0) || (dls.artCount > DLS_MAX_ART_COUNT))
    +         {
    +             { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "DLS file contains invalid #articulations [%u]\n", dls.regionCount); */ }
    ++            EAS_HWFree(dls.hwInstData, dls.wsmpData);
    +             return EAS_ERROR_FILE_FORMAT;
    +         }
    + 
    +@@ -616,6 +618,7 @@ EAS_RESULT DLSParser (EAS_HW_DATA_HANDLE hwInstData, EAS_FILE_HANDLE fileHandle,
    +         if ((dls.instCount == 0) || (dls.instCount > DLS_MAX_INST_COUNT))
    +         {
    +             { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "DLS file contains invalid #instruments [%u]\n", dls.instCount); */ }
    ++            EAS_HWFree(dls.hwInstData, dls.wsmpData);
    +             return EAS_ERROR_FILE_FORMAT;
    +         }
    + 
    +@@ -636,6 +639,7 @@ EAS_RESULT DLSParser (EAS_HW_DATA_HANDLE hwInstData, EAS_FILE_HANDLE fileHandle,
    +         /* calculate final memory size */
    +         size = (EAS_I32) sizeof(S_EAS) + instSize + rgnPoolSize + artPoolSize + (2 * waveLenSize) + (EAS_I32) dls.wavePoolSize;
    +         if (size <= 0) {
    ++            EAS_HWFree(dls.hwInstData, dls.wsmpData);
    +             return EAS_ERROR_FILE_FORMAT;
    +         }
    + 
    +@@ -644,6 +648,7 @@ EAS_RESULT DLSParser (EAS_HW_DATA_HANDLE hwInstData, EAS_FILE_HANDLE fileHandle,
    +         if (dls.pDLS == NULL)
    +         {
    +             { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "EAS_HWMalloc failed for DLS memory allocation size %ld\n", size); */ }
    ++            EAS_HWFree(dls.hwInstData, dls.wsmpData);
    +             return EAS_ERROR_MALLOC_FAILED;
    +         }
    +         EAS_HWMemSet(dls.pDLS, 0, size);
     diff --git a/arm-wt-22k/lib_src/eas_wtsynth.c b/arm-wt-22k/lib_src/eas_wtsynth.c
     index 9fcda7b..8488fe2 100644
     --- a/arm-wt-22k/lib_src/eas_wtsynth.c
    @@ -25,3 +69,62 @@ index 9fcda7b..8488fe2 100644
      
          /* call into engine to generate samples */
          intFrame.pAudioBuffer = pVoiceMgr->voiceBuffer;
    +diff --git a/arm-wt-22k/lib_src/eas_xmf.c b/arm-wt-22k/lib_src/eas_xmf.c
    +index 169eb7e..07ee8f7 100644
    +--- a/arm-wt-22k/lib_src/eas_xmf.c
    ++++ b/arm-wt-22k/lib_src/eas_xmf.c
    +@@ -67,7 +67,7 @@ static EAS_RESULT XMF_Resume (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData);
    + static EAS_RESULT XMF_SetData (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData, EAS_I32 param, EAS_I32 value);
    + static EAS_RESULT XMF_GetData (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData, EAS_I32 param, EAS_I32 *pValue);
    + static EAS_RESULT XMF_FindFileContents (EAS_HW_DATA_HANDLE hwInstData, S_XMF_DATA *pXMFData);
    +-static EAS_RESULT XMF_ReadNode (EAS_HW_DATA_HANDLE hwInstData, S_XMF_DATA *pXMFData, EAS_I32 nodeOffset, EAS_I32 *pLength);
    ++static EAS_RESULT XMF_ReadNode (EAS_HW_DATA_HANDLE hwInstData, S_XMF_DATA *pXMFData, EAS_I32 nodeOffset, EAS_I32 *pLength, EAS_I32 depth);
    + static EAS_RESULT XMF_ReadVLQ (EAS_HW_DATA_HANDLE hwInstData, EAS_FILE_HANDLE fileHandle, EAS_I32 *value);
    + 
    + 
    +@@ -504,6 +504,7 @@ static EAS_RESULT XMF_FindFileContents (EAS_HW_DATA_HANDLE hwInstData, S_XMF_DAT
    +     EAS_RESULT result;
    +     EAS_I32 value;
    +     EAS_I32 length;
    ++    EAS_I32 node_depth = 0 ;
    + 
    +     /* initialize offsets */
    +     pXMFData->dlsOffset = pXMFData->midiOffset = 0;
    +@@ -521,7 +522,7 @@ static EAS_RESULT XMF_FindFileContents (EAS_HW_DATA_HANDLE hwInstData, S_XMF_DAT
    +     /* get TreeStart offset and jump to it */
    +     if ((result = XMF_ReadVLQ(hwInstData, pXMFData->fileHandle, &value)) != EAS_SUCCESS)
    +         return result;
    +-    if ((result = XMF_ReadNode(hwInstData, pXMFData, value, &length)) != EAS_SUCCESS)
    ++    if ((result = XMF_ReadNode(hwInstData, pXMFData, value, &length, node_depth)) != EAS_SUCCESS)
    +         return result;
    + 
    +     /* check for SMF data */
    +@@ -552,7 +553,7 @@ static EAS_RESULT XMF_FindFileContents (EAS_HW_DATA_HANDLE hwInstData, S_XMF_DAT
    +  *
    +  *----------------------------------------------------------------------------
    + */
    +-static EAS_RESULT XMF_ReadNode (EAS_HW_DATA_HANDLE hwInstData, S_XMF_DATA *pXMFData, EAS_I32 nodeOffset, EAS_I32 *pLength)
    ++static EAS_RESULT XMF_ReadNode (EAS_HW_DATA_HANDLE hwInstData, S_XMF_DATA *pXMFData, EAS_I32 nodeOffset, EAS_I32 *pLength, EAS_I32 depth)
    + {
    +     EAS_RESULT result;
    +     EAS_I32 refType;
    +@@ -562,6 +563,10 @@ static EAS_RESULT XMF_ReadNode (EAS_HW_DATA_HANDLE hwInstData, S_XMF_DATA *pXMFD
    +     EAS_I32 headerLength;
    +     EAS_U32 chunkType;
    + 
    ++    /* check the depth of current node*/
    ++    if ( depth > 100 )
    ++        return EAS_ERROR_FILE_FORMAT;
    ++
    +     /* seek to start of node */
    +     if ((result = EAS_HWFileSeek(hwInstData, pXMFData->fileHandle, nodeOffset)) != EAS_SUCCESS)
    +         return result;
    +@@ -656,7 +661,7 @@ static EAS_RESULT XMF_ReadNode (EAS_HW_DATA_HANDLE hwInstData, S_XMF_DATA *pXMFD
    +                 return EAS_ERROR_FILE_FORMAT;
    +             }
    + 
    +-            if ((result = XMF_ReadNode(hwInstData, pXMFData, offset, &length)) != EAS_SUCCESS)
    ++            if ((result = XMF_ReadNode(hwInstData, pXMFData, offset, &length, depth+1)) != EAS_SUCCESS)
    +                 return result;
    + 
    +             /* seek to start of next item */
    diff --git a/frameworks_av.patch b/frameworks_av.patch
    index 27d5275..e713e5e 100644
    --- a/frameworks_av.patch
    +++ b/frameworks_av.patch
    @@ -151,6 +151,19 @@ index bca3832..cf59357 100644
          }
      
          CHECK_EQ(mWriter->start(), (status_t)OK);
    +diff --git a/include/media/IAudioPolicyService.h b/include/media/IAudioPolicyService.h
    +index 0e9e3bc..de6e5ce 100644
    +--- a/include/media/IAudioPolicyService.h
    ++++ b/include/media/IAudioPolicyService.h
    +@@ -181,6 +181,8 @@ public:
    +                                     const Parcel& data,
    +                                     Parcel* reply,
    +                                     uint32_t flags = 0);
    ++private:
    ++    void sanetizeAudioAttributes(audio_attributes_t* attr);
    + };
    + 
    + // ----------------------------------------------------------------------------
     diff --git a/include/media/IMediaExtractor.h b/include/media/IMediaExtractor.h
     index 34b15e9..743ef7f 100644
     --- a/include/media/IMediaExtractor.h
    @@ -302,6 +315,52 @@ index 4dc8b45..19892dd 100644
              } break;
      
              case EFFECT_CMD_ENABLE:
    +diff --git a/media/libmedia/IAudioPolicyService.cpp b/media/libmedia/IAudioPolicyService.cpp
    +index 6405d6d..09bacc0 100644
    +--- a/media/libmedia/IAudioPolicyService.cpp
    ++++ b/media/libmedia/IAudioPolicyService.cpp
    +@@ -893,6 +893,7 @@ status_t BnAudioPolicyService::onTransact(
    +             bool hasAttributes = data.readInt32() != 0;
    +             if (hasAttributes) {
    +                 data.read(&attr, sizeof(audio_attributes_t));
    ++		sanetizeAudioAttributes(&attr);
    +             }
    +             audio_session_t session = (audio_session_t)data.readInt32();
    +             audio_stream_type_t stream = AUDIO_STREAM_DEFAULT;
    +@@ -960,6 +961,7 @@ status_t BnAudioPolicyService::onTransact(
    +             CHECK_INTERFACE(IAudioPolicyService, data, reply);
    +             audio_attributes_t attr;
    +             data.read(&attr, sizeof(audio_attributes_t));
    ++            sanetizeAudioAttributes(&attr);
    +             audio_session_t session = (audio_session_t)data.readInt32();
    +             pid_t pid = (pid_t)data.readInt32();
    +             uid_t uid = (uid_t)data.readInt32();
    +@@ -1332,6 +1334,7 @@ status_t BnAudioPolicyService::onTransact(
    +             data.read(&source, sizeof(struct audio_port_config));
    +             audio_attributes_t attributes;
    +             data.read(&attributes, sizeof(audio_attributes_t));
    ++            sanetizeAudioAttributes(&attributes);
    +             audio_io_handle_t handle = {};
    +             status_t status = startAudioSource(&source, &attributes, &handle);
    +             reply->writeInt32(status);
    +@@ -1371,6 +1374,16 @@ status_t BnAudioPolicyService::onTransact(
    +     }
    + }
    + 
    ++void BnAudioPolicyService::sanetizeAudioAttributes(audio_attributes_t* attr)
    ++{
    ++    const size_t tagsMaxSize = AUDIO_ATTRIBUTES_TAGS_MAX_SIZE;
    ++    if (strnlen(attr->tags, tagsMaxSize) >= tagsMaxSize) {
    ++        android_errorWriteLog(0x534e4554, "68953950"); // SafetyNet logging
    ++    }
    ++    attr->tags[tagsMaxSize - 1] = '\0';
    ++}
    ++
    + // ----------------------------------------------------------------------------
    + 
    +-} // namespace android
    ++ 
    ++ } // namespace android
     diff --git a/media/libmedia/IDataSource.cpp b/media/libmedia/IDataSource.cpp
     index 51c9938..5ad39fe 100644
     --- a/media/libmedia/IDataSource.cpp
    @@ -1336,6 +1395,23 @@ index cecc52b..43ef4a4 100644
                      }
      
                      mReceivedEOS = true;
    +diff --git a/media/libstagefright/codecs/avcenc/SoftAVCEnc.cpp b/media/libstagefright/codecs/avcenc/SoftAVCEnc.cpp
    +index 5b06722..7bfa051 100644
    +--- a/media/libstagefright/codecs/avcenc/SoftAVCEnc.cpp
    ++++ b/media/libstagefright/codecs/avcenc/SoftAVCEnc.cpp
    +@@ -1191,6 +1191,12 @@ OMX_ERRORTYPE SoftAVC::setEncodeArgs(
    +     ps_inp_raw_buf->e_color_fmt = mIvVideoColorFormat;
    +     source = NULL;
    +     if ((inputBufferHeader != NULL) && inputBufferHeader->nFilledLen) {
    ++        OMX_ERRORTYPE error = validateInputBuffer(inputBufferHeader);
    ++        if (error != OMX_ErrorNone) {
    ++            ALOGE("b/69065651");
    ++            android_errorWriteLog(0x534e4554, "69065651");
    ++            return error;
    ++        }
    +         source = inputBufferHeader->pBuffer + inputBufferHeader->nOffset;
    + 
    +         if (mInputDataIsMeta) {
     diff --git a/media/libstagefright/codecs/hevcdec/SoftHEVC.cpp b/media/libstagefright/codecs/hevcdec/SoftHEVC.cpp
     index 5c70387..194a078 100644
     --- a/media/libstagefright/codecs/hevcdec/SoftHEVC.cpp
    @@ -1375,6 +1451,25 @@ index f7192b1c..7202f98 100644
          {
              return VLC_CODE_ERROR;
          }
    +diff --git a/media/libstagefright/codecs/m4v_h263/enc/SoftMPEG4Encoder.cpp b/media/libstagefright/codecs/m4v_h263/enc/SoftMPEG4Encoder.cpp
    +index d5a26d3..7d2131d 100644
    +--- a/media/libstagefright/codecs/m4v_h263/enc/SoftMPEG4Encoder.cpp
    ++++ b/media/libstagefright/codecs/m4v_h263/enc/SoftMPEG4Encoder.cpp
    +@@ -437,6 +437,14 @@ void SoftMPEG4Encoder::onQueueFilled(OMX_U32 /* portIndex */) {
    +         }
    + 
    +         if (inHeader->nFilledLen > 0) {
    ++            OMX_ERRORTYPE error = validateInputBuffer(inHeader);
    ++            if (error != OMX_ErrorNone) {
    ++                ALOGE("b/69065651");
    ++                android_errorWriteLog(0x534e4554, "69065651");
    ++                mSignalledError = true;
    ++                notify(OMX_EventError, error, 0, 0);
    ++                return;
    ++            }
    +             const uint8_t *inputData = NULL;
    +             if (mInputDataIsMeta) {
    +                 inputData =
     diff --git a/media/libstagefright/codecs/mpeg2dec/SoftMPEG2.cpp b/media/libstagefright/codecs/mpeg2dec/SoftMPEG2.cpp
     index 5ed037a..7297f40 100644
     --- a/media/libstagefright/codecs/mpeg2dec/SoftMPEG2.cpp
    @@ -1528,6 +1623,39 @@ index 700ef5f..1285c5b 100644
          bool mWaitForI;
          size_t mStride;
      
    +diff --git a/media/libstagefright/codecs/on2/enc/SoftVPXEncoder.cpp b/media/libstagefright/codecs/on2/enc/SoftVPXEncoder.cpp
    +index 56e1f77..04d8dda 100644
    +--- a/media/libstagefright/codecs/on2/enc/SoftVPXEncoder.cpp
    ++++ b/media/libstagefright/codecs/on2/enc/SoftVPXEncoder.cpp
    +@@ -731,6 +731,13 @@ void SoftVPXEncoder::onQueueFilled(OMX_U32 /* portIndex */) {
    +             return;
    +         }
    + 
    ++        OMX_ERRORTYPE error = validateInputBuffer(inputBufferHeader);
    ++        if (error != OMX_ErrorNone) {
    ++            ALOGE("b/27569635");
    ++            android_errorWriteLog(0x534e4554, "27569635");
    ++            notify(OMX_EventError, error, 0, 0);
    ++            return;
    ++        }
    +         const uint8_t *source =
    +             inputBufferHeader->pBuffer + inputBufferHeader->nOffset;
    + 
    +@@ -746,14 +753,6 @@ void SoftVPXEncoder::onQueueFilled(OMX_U32 /* portIndex */) {
    +                 return;
    +             }
    +         } else {
    +-            if (inputBufferHeader->nFilledLen < frameSize) {
    +-                android_errorWriteLog(0x534e4554, "27569635");
    +-                notify(OMX_EventError, OMX_ErrorUndefined, 0, 0);
    +-                return;
    +-            } else if (inputBufferHeader->nFilledLen > frameSize) {
    +-                ALOGW("Input buffer contains too many pixels");
    +-            }
    +-
    +             if (mColorFormat == OMX_COLOR_FormatYUV420SemiPlanar) {
    +                 ConvertYUV420SemiPlanarToYUV420Planar(
    +                         source, mConversionBuffer, mWidth, mHeight);
     diff --git a/media/libstagefright/foundation/MediaBufferGroup.cpp b/media/libstagefright/foundation/MediaBufferGroup.cpp
     index 8e4d064..66992d7 100644
     --- a/media/libstagefright/foundation/MediaBufferGroup.cpp
    @@ -1591,6 +1719,20 @@ index 7abc019..590146d 100644
          mPrevEstimates.push_back(*bandwidthBps);
          while (mPrevEstimates.size() > 3) {
              mPrevEstimates.erase(mPrevEstimates.begin());
    +diff --git a/media/libstagefright/httplive/M3UParser.cpp b/media/libstagefright/httplive/M3UParser.cpp
    +index c04549a..78a2dd0 100644
    +--- a/media/libstagefright/httplive/M3UParser.cpp
    ++++ b/media/libstagefright/httplive/M3UParser.cpp
    +@@ -897,6 +897,9 @@ status_t M3UParser::parseStreamInf(
    +         }
    +     }
    + 
    ++    if (meta->get() == NULL) {
    ++        return ERROR_MALFORMED;
    ++    }
    +     return OK;
    + }
    + 
     diff --git a/media/libstagefright/include/OMXNodeInstance.h b/media/libstagefright/include/OMXNodeInstance.h
     index 94cf15a..dd396e8 100644
     --- a/media/libstagefright/include/OMXNodeInstance.h
    @@ -1900,6 +2042,19 @@ index 0000000..f65a409
     +}  // namespace android
     +
     +#endif  // OMX_NODE_INSTANCE_H_
    +diff --git a/media/libstagefright/include/SoftVideoEncoderOMXComponent.h b/media/libstagefright/include/SoftVideoEncoderOMXComponent.h
    +index b43635d..02555a2 100644
    +--- a/media/libstagefright/include/SoftVideoEncoderOMXComponent.h
    ++++ b/media/libstagefright/include/SoftVideoEncoderOMXComponent.h
    +@@ -68,6 +68,8 @@ protected:
    + 
    +     virtual OMX_ERRORTYPE getExtensionIndex(const char *name, OMX_INDEXTYPE *index);
    + 
    ++    OMX_ERRORTYPE validateInputBuffer(const OMX_BUFFERHEADERTYPE *inputBufferHeader);
    ++
    +     enum {
    +         kInputPortIndex = 0,
    +         kOutputPortIndex = 1,
     diff --git a/media/libstagefright/mpeg2ts/ESQueue.cpp b/media/libstagefright/mpeg2ts/ESQueue.cpp
     index 96ca405..7599c13 100644
     --- a/media/libstagefright/mpeg2ts/ESQueue.cpp
    @@ -4256,6 +4411,28 @@ index 7c975f7..76cbbc4 100644
          CHECK(mState == OMX_StateLoaded || port->mDef.bEnabled == OMX_FALSE);
      
          CHECK_LT(port->mBuffers.size(), port->mDef.nBufferCountActual);
    +diff --git a/media/libstagefright/omx/SoftVideoEncoderOMXComponent.cpp b/media/libstagefright/omx/SoftVideoEncoderOMXComponent.cpp
    +index 0f9c118..9d302dd 100644
    +--- a/media/libstagefright/omx/SoftVideoEncoderOMXComponent.cpp
    ++++ b/media/libstagefright/omx/SoftVideoEncoderOMXComponent.cpp
    +@@ -656,4 +656,17 @@ OMX_ERRORTYPE SoftVideoEncoderOMXComponent::getExtensionIndex(
    +     return SimpleSoftOMXComponent::getExtensionIndex(name, index);
    + }
    + 
    ++OMX_ERRORTYPE SoftVideoEncoderOMXComponent::validateInputBuffer(
    ++        const OMX_BUFFERHEADERTYPE *inputBufferHeader) {
    ++    size_t frameSize = mInputDataIsMeta ?
    ++            max(sizeof(VideoNativeMetadata), sizeof(VideoGrallocMetadata))
    ++            : mWidth * mHeight * 3 / 2;
    ++    if (inputBufferHeader->nFilledLen < frameSize) {
    ++        return OMX_ErrorUndefined;
    ++    } else if (inputBufferHeader->nFilledLen > frameSize) {
    ++        ALOGW("Input buffer contains more data than expected.");
    ++    }
    ++    return OMX_ErrorNone;
    ++}
    ++
    + }  // namespace android
     diff --git a/media/mediaserver/Android.mk b/media/mediaserver/Android.mk
     index 1738df8..c2b9c1f 100644
     --- a/media/mediaserver/Android.mk
    diff --git a/frameworks_base.patch b/frameworks_base.patch
    index ce7d836..4a84543 100644
    --- a/frameworks_base.patch
    +++ b/frameworks_base.patch
    @@ -382,6 +382,29 @@ index 011884c..a5035ee 100644
          <!-- @SystemApi Allows an application to manage (create, destroy,
               Z-order) application tokens in the window manager.
               <p>Not for use by third-party applications.
    +diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
    +index 7baed78..a0fbdac 100644
    +--- a/core/res/res/values/config.xml
    ++++ b/core/res/res/values/config.xml
    +@@ -2710,4 +2710,6 @@
    +          is installed. -->
    +     <bool name="config_permissionReviewRequired">false</bool>
    + 
    ++    <!-- Whether to enable HumanInteractionController by default -->
    ++    <bool name="config_HICEnabledDefault">true</bool>
    + </resources>
    +diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
    +index 08ac043..9e6f3b8 100644
    +--- a/core/res/res/values/symbols.xml
    ++++ b/core/res/res/values/symbols.xml
    +@@ -2749,4 +2749,7 @@
    +   <java-symbol type="bool" name="use_lock_pattern_drawable" />
    +   <java-symbol type="drawable" name="lockscreen_notselected" />
    +   <java-symbol type="drawable" name="lockscreen_selected" />
    ++
    ++  <!-- Whether to enable HumanInteractionController by default -->
    ++  <java-symbol type="bool" name="config_HICEnabledDefault" />
    + </resources>
     diff --git a/core/res/res/xml/config_webview_packages.xml b/core/res/res/xml/config_webview_packages.xml
     index f062b59..574f7c1 100644
     --- a/core/res/res/xml/config_webview_packages.xml
    @@ -491,6 +514,33 @@ index 0fa9a85..925f368 100644
          </string>
      
          <!-- The tiles to display in QuickSettings -->
    +diff --git a/packages/SystemUI/src/com/android/systemui/classifier/HumanInteractionClassifier.java b/packages/SystemUI/src/com/android/systemui/classifier/HumanInteractionClassifier.java
    +index 851ab77..a384641 100644
    +--- a/packages/SystemUI/src/com/android/systemui/classifier/HumanInteractionClassifier.java
    ++++ b/packages/SystemUI/src/com/android/systemui/classifier/HumanInteractionClassifier.java
    +@@ -36,9 +36,6 @@ public class HumanInteractionClassifier extends Classifier {
    +     private static final String HIC_ENABLE = "HIC_enable";
    +     private static final float FINGER_DISTANCE = 0.1f;
    + 
    +-    /** Default value for the HIC_ENABLE setting: 1 - enabled, 0 - disabled */
    +-    private static final int HIC_ENABLE_DEFAULT = 1;
    +-
    +     private static HumanInteractionClassifier sInstance = null;
    + 
    +     private final Handler mHandler = new Handler();
    +@@ -105,9 +102,11 @@ public class HumanInteractionClassifier extends Classifier {
    +     }
    + 
    +     private void updateConfiguration() {
    ++        boolean enabledDefault = mContext.getResources()
    ++                .getBoolean(com.android.internal.R.bool.config_HICEnabledDefault);
    +         mEnableClassifier = 0 != Settings.Global.getInt(
    +                 mContext.getContentResolver(),
    +-                HIC_ENABLE, HIC_ENABLE_DEFAULT);
    ++ 		HIC_ENABLE, enabledDefault ? 1 : 0);
    +     }
    + 
    +     public void setType(int type) {
     diff --git a/packages/SystemUI/src/com/android/systemui/settings/CurrentUserTracker.java b/packages/SystemUI/src/com/android/systemui/settings/CurrentUserTracker.java
     index dd80750..005206f 100644
     --- a/packages/SystemUI/src/com/android/systemui/settings/CurrentUserTracker.java
    diff --git a/packages_apps_settings.patch b/packages_apps_settings.patch
    index f64357e..75a2bdc 100644
    --- a/packages_apps_settings.patch
    +++ b/packages_apps_settings.patch
    @@ -10,6 +10,19 @@ index 2ec976d..c155cf7 100644
      
          <application android:label="@string/settings_label"
                  android:icon="@mipmap/ic_launcher_settings"
    +diff --git a/res/values/strings.xml b/res/values/strings.xml
    +index c731267..9ec0584 100644
    +--- a/res/values/strings.xml
    ++++ b/res/values/strings.xml
    +@@ -1348,7 +1348,7 @@
    +     <string name="bluetooth_display_passkey_pin_msg">To pair with:<xliff:g id="bold1">&lt;br>&lt;b></xliff:g><xliff:g id="device_name">%1$s</xliff:g><xliff:g id="end_bold1">&lt;/b>&lt;br>&lt;br></xliff:g>Type on it:<xliff:g id="bold2">&lt;br>&lt;b></xliff:g><xliff:g id="passkey">%2$s</xliff:g><xliff:g id="end_bold2">&lt;/b></xliff:g>, then press Return or Enter.</string>
    + 
    +     <!-- Checkbox message in pairing dialogs.  [CHAR LIMIT=NONE] -->
    +-    <string name="bluetooth_pairing_shares_phonebook">Allow <xliff:g id="device_name">%1$s</xliff:g> to access your contacts and call history</string>
    ++    <string name="bluetooth_pairing_shares_phonebook">Allow access to your contacts and call history</string>
    + 
    +     <!-- Title for BT error dialogs. -->
    +     <string name="bluetooth_error_title"></string>
     diff --git a/src/com/android/settings/ActivityPicker.java b/src/com/android/settings/ActivityPicker.java
     index 2c3436f..ae61944 100644
     --- a/src/com/android/settings/ActivityPicker.java
    
    From e56108de3ef171dfcfc36bbd61ada76119f400cf Mon Sep 17 00:00:00 2001
    From: AndDiSa <anddisa@googlemail.com>
    Date: Sat, 7 Apr 2018 14:52:24 +0200
    Subject: [PATCH 093/159] update patches
    
    Change-Id: Ib39e542e29f5289415f7f8ca88e5f8c4aea502eb
    ---
     build.patch                     |   20 +-
     default.xml                     |    3 +-
     external_aac.patch              |   54 +
     external_apache-http.patch      |   56 +
     external_libavc.patch           |  123 +-
     external_libhevc.patch          |    9 +-
     external_libmpeg2.patch         | 5150 ++++---------------------------
     external_svox.patch             |   27 +
     external_wpa_supplicant_8.patch |   10 +
     frameworks_av.patch             |   35 +-
     frameworks_base.patch           |   68 +-
     frameworks_op_net_wifi.patch    |   48 -
     system_bt.patch                 |  420 ++-
     system_security.patch           |    0
     update_engine.patch             |  554 ++++
     15 files changed, 1963 insertions(+), 4614 deletions(-)
     create mode 100644 external_aac.patch
     create mode 100644 external_apache-http.patch
     create mode 100644 external_svox.patch
     create mode 100644 system_security.patch
     create mode 100644 update_engine.patch
    
    diff --git a/build.patch b/build.patch
    index 89e29a2..633eadf 100644
    --- a/build.patch
    +++ b/build.patch
    @@ -323,7 +323,7 @@ index 0000000..80664fa
     +ALL_PREBUILT += $(INSTALLED_KERNEL_TARGET)
     +endif
     diff --git a/core/version_defaults.mk b/core/version_defaults.mk
    -index 7c96344..42fa3a8 100644
    +index 7c96344..d9e7159 100644
     --- a/core/version_defaults.mk
     +++ b/core/version_defaults.mk
     @@ -131,7 +131,7 @@ ifeq "" "$(PLATFORM_SECURITY_PATCH)"
    @@ -331,7 +331,7 @@ index 7c96344..42fa3a8 100644
          #  It must match one of the Android Security Patch Level strings of the Public Security Bulletins.
          #  If there is no $PLATFORM_SECURITY_PATCH set, keep it empty.
     -    PLATFORM_SECURITY_PATCH := 2017-08-05
    -+    PLATFORM_SECURITY_PATCH := 2018-02-05
    ++    PLATFORM_SECURITY_PATCH := 2018-04-05
      endif
      
      ifeq "" "$(PLATFORM_BASE_OS)"
    @@ -352,3 +352,19 @@ index 0a4e0fd..5508c12 100644
          VpnDialogs \
          MmsService
      
    +diff --git a/tools/releasetools/ota_from_target_files.py b/tools/releasetools/ota_from_target_files.py
    +index d409d94..6aa14d2 100755
    +--- a/tools/releasetools/ota_from_target_files.py
    ++++ b/tools/releasetools/ota_from_target_files.py
    +@@ -1284,6 +1284,11 @@ def WriteABOTAPackageWithBrilloScript(target_file, output_file,
    +          "--target_image", target_file]
    +   if source_file is not None:
    +     cmd.extend(["--source_image", source_file])
    ++  if OPTIONS.downgrade:
    ++    max_timestamp = GetBuildProp("ro.build.date.utc", OPTIONS.source_info_dict)
    ++  else:
    ++    max_timestamp = metadata["post-timestamp"]
    ++  cmd.extend(["--max_timestamp", max_timestamp])
    +   p1 = common.Run(cmd, stdout=subprocess.PIPE)
    +   p1.wait()
    +   assert p1.returncode == 0, "brillo_update_payload generate failed"
    diff --git a/default.xml b/default.xml
    index c9fb020..ff75ab2 100644
    --- a/default.xml
    +++ b/default.xml
    @@ -377,7 +377,6 @@
       <project path="packages/apps/Browser2" name="platform/packages/apps/Browser2" />
       <project path="packages/apps/Calculator" name="platform/packages/apps/Calculator" groups="pdk-fs" />
       <project path="packages/apps/Calendar" name="platform/packages/apps/Calendar" groups="pdk-fs" />
    -  <project path="packages/apps/Camera2" name="platform/packages/apps/Camera2" groups="pdk-fs" />
       <project path="packages/apps/CarrierConfig" name="platform/packages/apps/CarrierConfig" groups="pdk-fs" />
       <project path="packages/apps/CellBroadcastReceiver" name="platform/packages/apps/CellBroadcastReceiver" groups="pdk-fs" />
       <project path="packages/apps/CertInstaller" name="platform/packages/apps/CertInstaller" groups="pdk-cw-fs,pdk-fs" />
    @@ -403,7 +402,7 @@
       <project path="packages/apps/Nfc" name="platform/packages/apps/Nfc" groups="apps_nfc,pdk-fs" />
       <project path="packages/apps/OneTimeInitializer" name="platform/packages/apps/OneTimeInitializer" groups="pdk-fs" />
       <project path="packages/apps/PackageInstaller" name="platform/packages/apps/PackageInstaller" groups="pdk-fs" />
    -  <project path="packages/apps/PerformanceControl" name="android_packages_apps_PerformanceControl" remote="ads" revision="cm-13.0" />
    +<!--  <project path="packages/apps/PerformanceControl" name="android_packages_apps_PerformanceControl" remote="ads" revision="cm-13.0" /> -->
       <project path="packages/apps/Phone" name="platform/packages/apps/Phone" groups="pdk-fs" />
       <project path="packages/apps/PhoneCommon" name="platform/packages/apps/PhoneCommon" groups="pdk-cw-fs,pdk-fs"/>
       <project path="packages/apps/Protips" name="platform/packages/apps/Protips" groups="pdk-fs" />
    diff --git a/external_aac.patch b/external_aac.patch
    new file mode 100644
    index 0000000..5432769
    --- /dev/null
    +++ b/external_aac.patch
    @@ -0,0 +1,54 @@
    +diff --git a/libMpegTPDec/src/tpdec_asc.cpp b/libMpegTPDec/src/tpdec_asc.cpp
    +index 96a1b35..e80d0e5 100644
    +--- a/libMpegTPDec/src/tpdec_asc.cpp
    ++++ b/libMpegTPDec/src/tpdec_asc.cpp
    +@@ -118,7 +118,9 @@ int  CProgramConfig_IsValid ( const CProgramConfig *pPce )
    + 
    + /*
    +  * Read the extension for height info.
    +- * return 0 if successfull or -1 if the CRC failed.
    ++ * return 0 if successfull,
    ++ *       -1 if the CRC failed,
    ++ *       -2 if invalid HeightInfo.
    +  */
    + static
    + int CProgramConfig_ReadHeightExt(
    +@@ -146,15 +148,21 @@ int CProgramConfig_ReadHeightExt(
    + 
    +     for (i=0; i < pPce->NumFrontChannelElements; i++)
    +     {
    +-      pPce->FrontElementHeightInfo[i] = (UCHAR) FDKreadBits(bs,2);
    ++      if ((pPce->FrontElementHeightInfo[i] = (UCHAR) FDKreadBits(bs,2)) >= PC_NUM_HEIGHT_LAYER) {
    ++        err = -2; /* height information is out of the valid range */
    ++      }
    +     }
    +     for (i=0; i < pPce->NumSideChannelElements; i++)
    +     {
    +-      pPce->SideElementHeightInfo[i] = (UCHAR) FDKreadBits(bs,2);
    ++      if ((pPce->SideElementHeightInfo[i] = (UCHAR) FDKreadBits(bs,2)) >= PC_NUM_HEIGHT_LAYER) {
    ++        err = -2; /* height information is out of the valid range */
    ++      }
    +     }
    +     for (i=0; i < pPce->NumBackChannelElements; i++)
    +     {
    +-      pPce->BackElementHeightInfo[i] = (UCHAR) FDKreadBits(bs,2);
    ++      if ((pPce->BackElementHeightInfo[i] = (UCHAR) FDKreadBits(bs,2)) >= PC_NUM_HEIGHT_LAYER) {
    ++        err = -2; /* height information is out of the valid range */
    ++      }
    +     }
    +     FDKbyteAlign(bs, alignmentAnchor);
    + 
    +@@ -163,6 +171,13 @@ int CProgramConfig_ReadHeightExt(
    +       /* CRC failed */
    +       err = -1;
    +     }
    ++    if (err!=0) {
    ++      /* Reset whole height information in case an error occured during parsing. The return
    ++         value ensures that pPce->isValid is set to 0 and implicit channel mapping is used. */
    ++      FDKmemclear(pPce->FrontElementHeightInfo, sizeof(pPce->FrontElementHeightInfo));
    ++      FDKmemclear(pPce->SideElementHeightInfo, sizeof(pPce->SideElementHeightInfo));
    ++      FDKmemclear(pPce->BackElementHeightInfo, sizeof(pPce->BackElementHeightInfo));
    ++    }
    +   }
    +   else {
    +     /* No valid extension data found -> restore the initial bitbuffer state */
    diff --git a/external_apache-http.patch b/external_apache-http.patch
    new file mode 100644
    index 0000000..485da54
    --- /dev/null
    +++ b/external_apache-http.patch
    @@ -0,0 +1,56 @@
    +diff --git a/Android.mk b/Android.mk
    +index f44b4d4..f0061b9 100644
    +--- a/Android.mk
    ++++ b/Android.mk
    +@@ -13,13 +13,10 @@
    + # limitations under the License.
    + #
    + LOCAL_PATH:= $(call my-dir)
    +-
    + apache_http_src_files := \
    +     $(call all-java-files-under,src) \
    +     $(call all-java-files-under,android)
    +-
    + apache_http_java_libs := conscrypt
    +-
    + apache_http_packages := $(strip \
    +   com.android.internal.http.multipart \
    +   org.apache.commons.logging \
    +@@ -93,9 +90,9 @@ LOCAL_SRC_FILES += \
    +     ../../frameworks/base/core/java/android/net/http/HttpResponseCache.java \
    +     ../../frameworks/base/core/java/android/net/http/SslCertificate.java \
    +     ../../frameworks/base/core/java/android/net/http/SslError.java \
    ++    ../../frameworks/base/core/java/com/android/internal/util/HexDump.java \
    + 
    +-
    +-LOCAL_JAVA_LIBRARIES := $(apache_http_java_libs)
    ++LOCAL_JAVA_LIBRARIES := bouncycastle okhttp $(apache_http_java_libs)
    + LOCAL_MODULE_CLASS := JAVA_LIBRARIES
    + LOCAL_DROIDDOC_SOURCE_PATH := $(LOCAL_PATH)/src \
    +   $(LOCAL_PATH)/android \
    +@@ -109,8 +106,8 @@ LOCAL_DROIDDOC_OPTIONS:= \
    + LOCAL_SDK_VERSION := 21
    + LOCAL_UNINSTALLABLE_MODULE := true
    + LOCAL_MODULE := apache-http-stubs-gen
    +-
    + include $(BUILD_DROIDDOC)
    ++
    + apache_http_stubs_gen_stamp := $(full_target)
    + 
    + # For unbundled build we'll use the prebuilt jar from prebuilts/sdk.
    +@@ -122,7 +119,6 @@ LOCAL_MODULE := org.apache.http.legacy
    + LOCAL_SOURCE_FILES_ALL_GENERATED := true
    + LOCAL_SDK_VERSION := 21
    + include $(BUILD_STATIC_JAVA_LIBRARY)
    +-
    + # Make sure to run droiddoc first to generate the stub source files.
    + $(full_classes_compiled_jar) : $(apache_http_stubs_gen_stamp)
    + $(full_classes_jack) : $(apache_http_stubs_gen_stamp)
    +@@ -130,7 +126,6 @@ $(full_classes_jack) : $(apache_http_stubs_gen_stamp)
    + # Archive a copy of the classes.jar in SDK build.
    + $(call dist-for-goals,sdk win_sdk,$(full_classes_jar):org.apache.http.legacy.jar)
    + endif  # not TARGET_BUILD_APPS
    +-
    + apache_http_src_files :=
    + apache_http_java_libs :=
    + apache_http_packages :=
    diff --git a/external_libavc.patch b/external_libavc.patch
    index 7b74c3f..d964acb 100644
    --- a/external_libavc.patch
    +++ b/external_libavc.patch
    @@ -1,8 +1,8 @@
     diff --git a/decoder/ih264d_api.c b/decoder/ih264d_api.c
    -index 2cde456..5ef49b1 100644
    +index 2cde456..70e19aa 100644
     --- a/decoder/ih264d_api.c
     +++ b/decoder/ih264d_api.c
    -@@ -1623,6 +1623,89 @@ UWORD32 ih264d_map_error(UWORD32 i4_err_status)
    +@@ -1623,6 +1623,109 @@ UWORD32 ih264d_map_error(UWORD32 i4_err_status)
      
      }
      
    @@ -64,8 +64,8 @@ index 2cde456..5ef49b1 100644
     +    }
     +    else
     +    {
    -+        /* In case of shared mode, do not check validity of ps_dec->ps_out_buffer */
    -+        return (IV_SUCCESS);
    ++        pic_wd = ps_dec->u2_frm_wd_y;
    ++        pic_ht = ps_dec->u2_frm_ht_y;
     +    }
     +
     +    if(ps_dec->u4_app_disp_width > pic_wd)
    @@ -75,14 +75,34 @@ index 2cde456..5ef49b1 100644
     +                                                 ps_dec->u1_chroma_format,
     +                                                 &au4_min_out_buf_size[0]);
     +
    -+    if(ps_dec->ps_out_buffer->u4_num_bufs < u4_min_num_out_bufs)
    -+        return IV_FAIL;
     +
    -+    for(i = 0; i < u4_min_num_out_bufs; i++)
    ++    if(0 == ps_dec->u4_share_disp_buf)
     +    {
    -+        if(ps_dec->ps_out_buffer->u4_min_out_buf_size[i]
    -+                        < au4_min_out_buf_size[i])
    -+            return (IV_FAIL);
    ++        if(ps_dec->ps_out_buffer->u4_num_bufs < u4_min_num_out_bufs)
    ++            return IV_FAIL;
    ++
    ++        for(i = 0; i < u4_min_num_out_bufs; i++)
    ++        {
    ++            if(ps_dec->ps_out_buffer->u4_min_out_buf_size[i]
    ++                            < au4_min_out_buf_size[i])
    ++                return (IV_FAIL);
    ++        }
    ++    }
    ++    else
    ++    {
    ++        if(ps_dec->disp_bufs[0].u4_num_bufs < u4_min_num_out_bufs)
    ++            return IV_FAIL;
    ++
    ++        for(i = 0; i < u4_min_num_out_bufs; i++)
    ++        {
    ++            /* We need to check only with the disp_buffer[0], because we have
    ++             * already ensured that all the buffers are of the same size in
    ++             * ih264d_set_display_frame.
    ++             */
    ++            if(ps_dec->disp_bufs[0].u4_bufsize[i] < au4_min_out_buf_size[i])
    ++                return (IV_FAIL);
    ++        }
    ++
     +    }
     +
     +    return (IV_SUCCESS);
    @@ -92,7 +112,7 @@ index 2cde456..5ef49b1 100644
      /*****************************************************************************/
      /*                                                                           */
      /*  Function Name :  ih264d_video_decode                                     */
    -@@ -1721,7 +1804,8 @@ WORD32 ih264d_video_decode(iv_obj_t *dec_hdl, void *pv_api_ip, void *pv_api_op)
    +@@ -1721,7 +1824,8 @@ WORD32 ih264d_video_decode(iv_obj_t *dec_hdl, void *pv_api_ip, void *pv_api_op)
                          && ps_dec->i4_decode_header == 0)
          {
              UWORD32 i;
    @@ -102,7 +122,7 @@ index 2cde456..5ef49b1 100644
              {
                  ps_dec_op->u4_error_code |= 1 << IVD_UNSUPPORTEDPARAM;
                  ps_dec_op->u4_error_code |= IVD_DISP_FRM_ZERO_OP_BUFS;
    -@@ -1865,6 +1949,13 @@ WORD32 ih264d_video_decode(iv_obj_t *dec_hdl, void *pv_api_ip, void *pv_api_op)
    +@@ -1865,6 +1969,13 @@ WORD32 ih264d_video_decode(iv_obj_t *dec_hdl, void *pv_api_ip, void *pv_api_op)
                                            &(ps_dec->s_disp_op));
              if(0 == ps_dec->s_disp_op.u4_error_code)
              {
    @@ -116,7 +136,7 @@ index 2cde456..5ef49b1 100644
                  ps_dec->u4_fmt_conv_cur_row = 0;
                  ps_dec->u4_fmt_conv_num_rows = ps_dec->s_disp_frame_info.u4_y_ht;
                  ih264d_format_convert(ps_dec, &(ps_dec->s_disp_op),
    -@@ -2094,7 +2185,8 @@ WORD32 ih264d_video_decode(iv_obj_t *dec_hdl, void *pv_api_ip, void *pv_api_op)
    +@@ -2094,7 +2205,8 @@ WORD32 ih264d_video_decode(iv_obj_t *dec_hdl, void *pv_api_ip, void *pv_api_op)
                                  || (ret == IVD_MEM_ALLOC_FAILED)
                                  || (ret == ERROR_UNAVAIL_PICBUF_T)
                                  || (ret == ERROR_UNAVAIL_MVBUF_T)
    @@ -126,7 +146,7 @@ index 2cde456..5ef49b1 100644
                  {
                      ps_dec->u4_slice_start_code_found = 0;
                      break;
    -@@ -2148,7 +2240,7 @@ WORD32 ih264d_video_decode(iv_obj_t *dec_hdl, void *pv_api_ip, void *pv_api_op)
    +@@ -2148,7 +2260,7 @@ WORD32 ih264d_video_decode(iv_obj_t *dec_hdl, void *pv_api_ip, void *pv_api_op)
          }
          while(( header_data_left == 1)||(frame_data_left == 1));
      
    @@ -135,7 +155,7 @@ index 2cde456..5ef49b1 100644
                  && (ret != IVD_MEM_ALLOC_FAILED)
                  && ps_dec->u2_total_mbs_coded < ps_dec->u2_frm_ht_in_mbs * ps_dec->u2_frm_wd_in_mbs)
          {
    -@@ -2290,7 +2382,7 @@ WORD32 ih264d_video_decode(iv_obj_t *dec_hdl, void *pv_api_ip, void *pv_api_op)
    +@@ -2290,7 +2402,7 @@ WORD32 ih264d_video_decode(iv_obj_t *dec_hdl, void *pv_api_ip, void *pv_api_op)
      
          }
      
    @@ -144,7 +164,7 @@ index 2cde456..5ef49b1 100644
                          && (ERROR_DANGLING_FIELD_IN_PIC != i4_err_status))
          {
              /*
    -@@ -2316,8 +2408,7 @@ WORD32 ih264d_video_decode(iv_obj_t *dec_hdl, void *pv_api_ip, void *pv_api_op)
    +@@ -2316,8 +2428,7 @@ WORD32 ih264d_video_decode(iv_obj_t *dec_hdl, void *pv_api_ip, void *pv_api_op)
              /* if new frame in not found (if we are still getting slices from previous frame)
               * ih264d_deblock_display is not called. Such frames will not be added to reference /display
               */
    @@ -154,7 +174,52 @@ index 2cde456..5ef49b1 100644
              {
                  /* Calling Function to deblock Picture and Display */
                  ret = ih264d_deblock_display(ps_dec);
    -@@ -2843,27 +2934,15 @@ WORD32 ih264d_get_buf_info(iv_obj_t *dec_hdl, void *pv_api_ip, void *pv_api_op)
    +@@ -2549,6 +2660,7 @@ WORD32 ih264d_set_display_frame(iv_obj_t *dec_hdl,
    +                                 void *pv_api_op)
    + {
    + 
    ++    UWORD32 u4_disp_buf_size[3], u4_num_disp_bufs;
    +     ivd_set_display_frame_ip_t *dec_disp_ip;
    +     ivd_set_display_frame_op_t *dec_disp_op;
    + 
    +@@ -2568,8 +2680,36 @@ WORD32 ih264d_set_display_frame(iv_obj_t *dec_hdl,
    +         u4_num_bufs = MIN(u4_num_bufs, MAX_DISP_BUFS_NEW);
    + 
    +         ps_dec->u4_num_disp_bufs = u4_num_bufs;
    ++
    ++        /* Get the number and sizes of the first buffer. Compare this with the
    ++         * rest to make sure all the buffers are of the same size.
    ++         */
    ++        u4_num_disp_bufs = dec_disp_ip->s_disp_buffer[0].u4_num_bufs;
    ++
    ++        u4_disp_buf_size[0] =
    ++          dec_disp_ip->s_disp_buffer[0].u4_min_out_buf_size[0];
    ++        u4_disp_buf_size[1] =
    ++          dec_disp_ip->s_disp_buffer[0].u4_min_out_buf_size[1];
    ++        u4_disp_buf_size[2] =
    ++          dec_disp_ip->s_disp_buffer[0].u4_min_out_buf_size[2];
    ++
    +         for(i = 0; i < u4_num_bufs; i++)
    +         {
    ++            if(dec_disp_ip->s_disp_buffer[i].u4_num_bufs != u4_num_disp_bufs)
    ++            {
    ++                return IV_FAIL;
    ++            }
    ++
    ++            if((dec_disp_ip->s_disp_buffer[i].u4_min_out_buf_size[0]
    ++                != u4_disp_buf_size[0])
    ++                || (dec_disp_ip->s_disp_buffer[i].u4_min_out_buf_size[1]
    ++                    != u4_disp_buf_size[1])
    ++                || (dec_disp_ip->s_disp_buffer[i].u4_min_out_buf_size[2]
    ++                    != u4_disp_buf_size[2]))
    ++            {
    ++                return IV_FAIL;
    ++            }
    ++
    +             ps_dec->disp_bufs[i].u4_num_bufs =
    +                             dec_disp_ip->s_disp_buffer[i].u4_num_bufs;
    + 
    +@@ -2843,27 +2983,15 @@ WORD32 ih264d_get_buf_info(iv_obj_t *dec_hdl, void *pv_api_ip, void *pv_api_op)
          UWORD16 pic_wd, pic_ht;
          ivd_ctl_getbufinfo_op_t *ps_ctl_op =
                          (ivd_ctl_getbufinfo_op_t*)pv_api_op;
    @@ -184,7 +249,7 @@ index 2cde456..5ef49b1 100644
      
          ps_ctl_op->u4_num_disp_bufs = 1;
      
    -@@ -2930,37 +3009,15 @@ WORD32 ih264d_get_buf_info(iv_obj_t *dec_hdl, void *pv_api_ip, void *pv_api_op)
    +@@ -2930,37 +3058,15 @@ WORD32 ih264d_get_buf_info(iv_obj_t *dec_hdl, void *pv_api_ip, void *pv_api_op)
                              ps_ctl_op->u4_num_disp_bufs, 32);
          }
      
    @@ -565,10 +630,28 @@ index 95ac557..efda5cf 100644
                      ih264d_insert_pic_in_ref_pic_listx(ps_ref_pic_buf_lx,
                                                         ps_next_dpb->ps_pic_buf);
     diff --git a/decoder/ih264d_utils.c b/decoder/ih264d_utils.c
    -index 4f6deca..7d7475d 100644
    +index 4f6deca..b37acec 100644
     --- a/decoder/ih264d_utils.c
     +++ b/decoder/ih264d_utils.c
    -@@ -1979,10 +1979,7 @@ WORD16 ih264d_allocate_dynamic_bufs(dec_struct_t * ps_dec)
    +@@ -1042,12 +1042,15 @@ WORD32 ih264d_get_next_display_field(dec_struct_t * ps_dec,
    +                         buf = ps_dec->disp_bufs[i].buf[1];
    +                         buf += ps_dec->disp_bufs[i].u4_ofst[1];
    +                         pv_disp_op->s_disp_frm_buf.pv_u_buf = buf
    +-                                        + pic_buf->u2_crop_offset_uv;
    ++                                        + (pic_buf->u2_crop_offset_uv
    ++                                           / YUV420SP_FACTOR);
    + 
    +                         buf = ps_dec->disp_bufs[i].buf[2];
    +                         buf += ps_dec->disp_bufs[i].u4_ofst[2];
    +                         pv_disp_op->s_disp_frm_buf.pv_v_buf = buf
    +-                                        + pic_buf->u2_crop_offset_uv;
    ++                                        + (pic_buf->u2_crop_offset_uv
    ++                                           / YUV420SP_FACTOR);
    ++
    +                     }
    +                 }
    +             }
    +@@ -1979,10 +1982,7 @@ WORD16 ih264d_allocate_dynamic_bufs(dec_struct_t * ps_dec)
              num_entries = 1;
          }
          num_entries = ((2 * num_entries) + 1);
    diff --git a/external_libhevc.patch b/external_libhevc.patch
    index 87f6034..bff0753 100644
    --- a/external_libhevc.patch
    +++ b/external_libhevc.patch
    @@ -4460,10 +4460,10 @@ index f57cc31..72db2cc 100644
                      }
                  }
     diff --git a/decoder/ihevcd_utils.c b/decoder/ihevcd_utils.c
    -index 7d76577..14cdd2b 100755
    +index 7d76577..14c36ba 100755
     --- a/decoder/ihevcd_utils.c
     +++ b/decoder/ihevcd_utils.c
    -@@ -662,6 +662,103 @@ IHEVCD_ERROR_T ihevcd_mv_buf_mgr_add_bufs(codec_t *ps_codec)
    +@@ -662,6 +662,106 @@ IHEVCD_ERROR_T ihevcd_mv_buf_mgr_add_bufs(codec_t *ps_codec)
      *******************************************************************************
      *
      * @brief
    @@ -4500,6 +4500,9 @@ index 7d76577..14cdd2b 100755
     +        return (IHEVCD_ERROR_T)IHEVCD_SUCCESS;
     +    }
     +
    ++    if(ps_codec->i4_disp_strd > (WORD32)wd)
    ++        wd = ps_codec->i4_disp_strd;
    ++
     +    if(ps_codec->e_chroma_fmt == IV_YUV_420P)
     +        u4_min_num_out_bufs = MIN_OUT_BUFS_420;
     +    else if(ps_codec->e_chroma_fmt == IV_YUV_422ILE)
    @@ -4567,7 +4570,7 @@ index 7d76577..14cdd2b 100755
      *  Picture level initializations required during parsing
      *
      * @par Description:
    -@@ -713,6 +810,10 @@ IHEVCD_ERROR_T ihevcd_parse_pic_init(codec_t *ps_codec)
    +@@ -713,6 +813,10 @@ IHEVCD_ERROR_T ihevcd_parse_pic_init(codec_t *ps_codec)
              ps_codec->s_parse.i4_first_pic_init = 1;
          }
      
    diff --git a/external_libmpeg2.patch b/external_libmpeg2.patch
    index 87f6034..eb419b3 100644
    --- a/external_libmpeg2.patch
    +++ b/external_libmpeg2.patch
    @@ -1,4580 +1,696 @@
    -diff --git a/common/arm/ihevc_deblk_chroma_horz.s b/common/arm/ihevc_deblk_chroma_horz.s
    -index 34422ff..b0a79eb 100644
    ---- a/common/arm/ihevc_deblk_chroma_horz.s
    -+++ b/common/arm/ihevc_deblk_chroma_horz.s
    -@@ -36,6 +36,12 @@
    - @*
    - @*******************************************************************************/
    - 
    -+.equ    qp_offset_u_offset,     40
    -+.equ    qp_offset_v_offset,     44
    -+.equ    tc_offset_div2_offset,  48
    -+.equ    filter_p_offset,        52
    -+.equ    filter_q_offset,        56
    -+
    - .text
    - .align 4
    - 
    -@@ -62,17 +68,17 @@ ihevc_deblk_chroma_horz_a9q:
    -     add         r6,r0,r1
    -     add         r1,r2,r3
    -     vmovl.u8    q0,d0
    --    ldr         r10,[sp,#0x28]
    -+    ldr         r10,[sp,#qp_offset_u_offset]
    -     vld1.8      {d2},[r12]
    -     add         r2,r1,#1
    --    ldr         r4,[sp,#0x30]
    -+    ldr         r4,[sp,#tc_offset_div2_offset]
    -     vld1.8      {d4},[r5]
    --    ldr         r8,[sp,#0x34]
    -+    ldr         r8,[sp,#filter_p_offset]
    -     vld1.8      {d16},[r6]
    --    ldr         r9,[sp,#0x38]
    -+    ldr         r9,[sp,#filter_q_offset]
    -     adds        r1,r10,r2,asr #1
    -     vmovl.u8    q1,d2
    --    ldr         r7,[sp,#0x2c]
    -+    ldr         r7,[sp,#qp_offset_v_offset]
    -     ldr         r3,gai4_ihevc_qp_table_addr
    - ulbl1:
    -     add         r3, r3, pc
    -diff --git a/common/arm/ihevc_deblk_chroma_vert.s b/common/arm/ihevc_deblk_chroma_vert.s
    -index 4cb305f..3962b28 100644
    ---- a/common/arm/ihevc_deblk_chroma_vert.s
    -+++ b/common/arm/ihevc_deblk_chroma_vert.s
    -@@ -37,6 +37,12 @@
    - @*
    - @*******************************************************************************/
    - 
    -+.equ    qp_offset_u_offset,     40
    -+.equ    qp_offset_v_offset,     44
    -+.equ    tc_offset_div2_offset,  48
    -+.equ    filter_p_offset,        52
    -+.equ    filter_q_offset,        56
    -+
    - .text
    - .align 4
    - 
    -@@ -63,19 +69,19 @@ ihevc_deblk_chroma_vert_a9q:
    -     vld1.8      {d5},[r8],r1
    -     add         r2,r2,#1
    -     vld1.8      {d17},[r8],r1
    --    ldr         r7,[sp,#0x28]
    -+    ldr         r7,[sp,#qp_offset_u_offset]
    -     vld1.8      {d16},[r8],r1
    --    ldr         r4,[sp,#0x38]
    -+    ldr         r4,[sp,#filter_q_offset]
    -     vld1.8      {d4},[r8]
    --    ldr         r5,[sp,#0x30]
    -+    ldr         r5,[sp,#tc_offset_div2_offset]
    -     vtrn.8      d5,d17
    -     adds        r3,r7,r2,asr #1
    -     vtrn.8      d16,d4
    -     ldr         r7,gai4_ihevc_qp_table_addr
    - ulbl1:
    -     add         r7,r7,pc
    --    ldr         r12,[sp,#0x34]
    --    ldr         r6,[sp,#0x2c]
    -+    ldr         r12,[sp,#filter_p_offset]
    -+    ldr         r6,[sp,#qp_offset_v_offset]
    -     bmi         l1.2944
    -     cmp         r3,#0x39
    -     ldrle       r3,[r7,r3,lsl #2]
    -diff --git a/common/arm/ihevc_deblk_luma_horz.s b/common/arm/ihevc_deblk_luma_horz.s
    -index b12ceb9..76660b3 100644
    ---- a/common/arm/ihevc_deblk_luma_horz.s
    -+++ b/common/arm/ihevc_deblk_luma_horz.s
    -@@ -36,6 +36,12 @@
    - @*
    - @*******************************************************************************/
    - 
    -+.equ    qp_q_offset,                108
    -+.equ    beta_offset_div2_offset,    112
    -+.equ    tc_offset_div2_offset,      116
    -+.equ    filter_p_offset,            120
    -+.equ    filter_q_offset,            124
    -+
    - .text
    - .align 4
    - 
    -@@ -57,12 +63,14 @@ gai4_ihevc_beta_table_addr:
    - 
    - ihevc_deblk_luma_horz_a9q:
    -     stmfd       sp!, {r3-r12,lr}
    --    ldr         r4,[sp,#0x2c]
    --    ldr         r5,[sp,#0x30]
    -+    vpush       {d8  -  d15}
    -+
    -+    ldr         r4,[sp,#qp_q_offset]
    -+    ldr         r5,[sp,#beta_offset_div2_offset]
    - 
    -     add         r3,r3,r4
    -     add         r3,r3,#1
    --    ldr         r6, [sp,#0x34]
    -+    ldr         r6, [sp,#tc_offset_div2_offset]
    -     asr         r3,r3,#1
    -     add         r7,r3,r5,lsl #1
    -     add         r3,r3,r6,lsl #1
    -@@ -291,9 +299,9 @@ ulbl1:
    -     vmin.u8     d18,d20,d30
    -     mov         r2,#2
    -     vqadd.u8    d30,d23,d1
    --    ldr         r4,[sp,#0x38]               @ loading the filter_flag_p
    -+    ldr         r4,[sp,#filter_p_offset]         @ loading the filter_flag_p
    -     vmax.u8     d2,d18,d31
    --    ldr         r5,[sp,#0x3c]               @ loading the filter_flag_q
    -+    ldr         r5,[sp,#filter_q_offset]         @ loading the filter_flag_q
    -     vrshrn.i16  d21,q7,#2
    -     b           end_dep_deq_decision_horz
    -     @ r2 has the value of de
    -@@ -308,8 +316,8 @@ l1.1840:
    -     mov         r2,#1
    - 
    -     mov         r11,r5
    --    ldr         r4,[sp,#0x38]               @ loading the filter_flag_p
    --    ldr         r5,[sp,#0x3c]               @ loading the filter_flag_q
    -+    ldr         r4,[sp,#filter_p_offset]         @ loading the filter_flag_p
    -+    ldr         r5,[sp,#filter_q_offset]         @ loading the filter_flag_q
    - 
    -     cmp         r6,#1
    -     moveq       r9,#0
    -@@ -397,6 +405,7 @@ strong_filtering_p:
    -     vst1.32     d3[0],[r12]
    - 
    - l1.2404:
    -+    vpop        {d8  -  d15}
    -     ldmfd       sp!, {r3-r12,pc}
    - 
    -     @ r4=flag p
    -@@ -537,6 +546,8 @@ l1.2852:
    -     vbsl        d19,d26,d13
    -     vst1.32     {d19[0]},[r12],r1
    -     vst1.32     {d18[0]},[r12]
    -+
    -+    vpop        {d8  -  d15}
    -     ldmfd       sp!, {r3-r12,r15}
    - 
    - 
    -diff --git a/common/arm/ihevc_deblk_luma_vert.s b/common/arm/ihevc_deblk_luma_vert.s
    -index ee247cc..91662c9 100644
    ---- a/common/arm/ihevc_deblk_luma_vert.s
    -+++ b/common/arm/ihevc_deblk_luma_vert.s
    -@@ -37,6 +37,12 @@
    - @*
    - @*******************************************************************************/
    - 
    -+.equ    qp_q_offset,                44
    -+.equ    beta_offset_div2_offset,    48
    -+.equ    tc_offset_div2_offset,      52
    -+.equ    filter_p_offset,            56
    -+.equ    filter_q_offset,            60
    -+
    - .text
    - .align 4
    - 
    -@@ -60,12 +66,12 @@ gai4_ihevc_beta_table_addr:
    - ihevc_deblk_luma_vert_a9q:
    - 
    -     push        {r3-r12,lr}
    --    ldr         r4,[sp,#0x2c]
    --    ldr         r5,[sp,#0x30]
    -+    ldr         r4,[sp,#qp_q_offset]
    -+    ldr         r5,[sp,#beta_offset_div2_offset]
    - 
    -     add         r3,r3,r4
    -     add         r3,r3,#1
    --    ldr         r6, [sp,#0x34]
    -+    ldr         r6, [sp,#tc_offset_div2_offset]
    -     asr         r3,r3,#1
    -     add         r7,r3,r5,lsl #1
    -     add         r3,r3,r6,lsl #1
    -@@ -291,9 +297,9 @@ ulbl1:
    -     vqadd.u8    d30,d6,d19
    - 
    -     mov         r2,#2
    --    ldr         r4,[sp,#0x38]               @ loading the filter_flag_p
    -+    ldr         r4,[sp,#filter_p_offset]        @ loading the filter_flag_p
    -     vqsub.u8    d31,d6,d19
    --    ldr         r5,[sp,#0x3c]               @ loading the filter_flag_q
    -+    ldr         r5,[sp,#filter_q_offset]        @ loading the filter_flag_q
    -     b           end_dep_deq_decision
    - @ r2 has the value of de
    - @ r6 has teh value of tc
    -@@ -307,8 +313,8 @@ l1.336:
    -     mov         r2,#1
    - l1.424:
    -     mov         r11,r5
    --    ldr         r4,[sp,#0x38]               @ loading the filter_flag_p
    --    ldr         r5,[sp,#0x3c]               @ loading the filter_flag_q
    -+    ldr         r4,[sp,#filter_p_offset]        @ loading the filter_flag_p
    -+    ldr         r5,[sp,#filter_q_offset]        @ loading the filter_flag_q
    - 
    -     cmp         r6,#1
    -     moveq       r9,#0
    -@@ -532,7 +538,6 @@ l1.1212:
    -     vst1.16     {d3[1]},[r12]
    -     vst1.8      {d16[3]},[r3]
    - l1.1272:
    --    @   ldr      r3,[sp,#0x38]
    -     cmp         r5,#0
    -     beq         l1.964
    -     @ checks for the flag q
    -diff --git a/common/arm/ihevc_inter_pred_chroma_copy.s b/common/arm/ihevc_inter_pred_chroma_copy.s
    -index 0da34cc..1b38dbb 100644
    ---- a/common/arm/ihevc_inter_pred_chroma_copy.s
    -+++ b/common/arm/ihevc_inter_pred_chroma_copy.s
    -@@ -92,6 +92,9 @@
    - @               r5 =>  ht
    - @               r6 =>  wd
    - 
    -+.equ    ht_offset,      44
    -+.equ    wd_offset,      48
    -+
    - .text
    - .align 4
    - 
    -@@ -104,9 +107,9 @@
    - 
    - ihevc_inter_pred_chroma_copy_a9q:
    -     stmfd       sp!, {r4-r12, r14}          @stack stores the values of the arguments
    --    ldr         r12,[sp,#48]                @loads wd
    -+    ldr         r12,[sp,#wd_offset]         @loads wd
    -     lsl         r12,r12,#1
    --    ldr         r7,[sp,#44]                 @loads ht
    -+    ldr         r7,[sp,#ht_offset]          @loads ht
    -     cmp         r7,#0                       @checks ht == 0
    -     ble         end_loops
    -     and         r8,r7,#3                    @check ht for mul of 2
    -diff --git a/common/arm/ihevc_inter_pred_chroma_copy_w16out.s b/common/arm/ihevc_inter_pred_chroma_copy_w16out.s
    -index a927fa7..4997b84 100644
    ---- a/common/arm/ihevc_inter_pred_chroma_copy_w16out.s
    -+++ b/common/arm/ihevc_inter_pred_chroma_copy_w16out.s
    -@@ -92,6 +92,11 @@
    - @r5 =>  ht
    - @r6 =>  wd
    - 
    -+.equ    coeff_offset,   104
    -+.equ    ht_offset,      108
    -+.equ    wd_offset,      112
    -+
    -+
    - .text
    - .align 4
    - 
    -@@ -105,9 +110,11 @@
    - ihevc_inter_pred_chroma_copy_w16out_a9q:
    - 
    -     stmfd       sp!, {r4-r12, r14}          @stack stores the values of the arguments
    --    ldr         r12,[sp,#48]                @loads wd
    -+    vpush        {d8 - d15}
    -+
    -+    ldr         r12,[sp,#wd_offset]                @loads wd
    -     lsl         r12,r12,#1                  @2*wd
    --    ldr         r7,[sp,#44]                 @loads ht
    -+    ldr         r7,[sp,#ht_offset]                 @loads ht
    -     cmp         r7,#0                       @ht condition(ht == 0)
    -     ble         end_loops                   @loop
    -     and         r8,r7,#3                    @check ht for mul of 2
    -@@ -162,6 +169,7 @@ end_inner_loop_wd_4:
    - 
    - 
    - end_loops:
    -+    vpop         {d8 - d15}
    -     ldmfd       sp!,{r4-r12,r15}            @reload the registers from sp
    - 
    - 
    -@@ -316,6 +324,7 @@ core_loop_wd_8_ht_2:
    -     vst1.16     {d2,d3},[r10],r5            @vst1q_s16(pi2_dst_tmp, tmp)
    -     bgt         core_loop_wd_8_ht_2
    - 
    -+    vpop         {d8 - d15}
    -     ldmfd       sp!,{r4-r12,r15}            @reload the registers from sp
    - 
    - 
    -diff --git a/common/arm/ihevc_inter_pred_chroma_horz.s b/common/arm/ihevc_inter_pred_chroma_horz.s
    -index 4781d3e..c69b417 100644
    ---- a/common/arm/ihevc_inter_pred_chroma_horz.s
    -+++ b/common/arm/ihevc_inter_pred_chroma_horz.s
    -@@ -93,6 +93,10 @@
    - @r2 =>  src_strd
    - @r3 =>  dst_strd
    - 
    -+.equ    coeff_offset,   104
    -+.equ    ht_offset,      108
    -+.equ    wd_offset,      112
    -+
    - .text
    - .align 4
    - 
    -@@ -106,10 +110,11 @@
    - ihevc_inter_pred_chroma_horz_a9q:
    - 
    -     stmfd       sp!, {r4-r12, r14}          @stack stores the values of the arguments
    -+    vpush        {d8 - d15}
    - 
    --    ldr         r4,[sp,#40]                 @loads pi1_coeff
    --    ldr         r7,[sp,#44]                 @loads ht
    --    ldr         r10,[sp,#48]                @loads wd
    -+    ldr         r4,[sp,#coeff_offset]                 @loads pi1_coeff
    -+    ldr         r7,[sp,#ht_offset]                 @loads ht
    -+    ldr         r10,[sp,#wd_offset]                @loads wd
    - 
    -     vld1.8      {d0},[r4]                   @coeff = vld1_s8(pi1_coeff)
    -     subs        r14,r7,#0                   @checks for ht == 0
    -@@ -672,6 +677,7 @@ inner_loop_4:
    - 
    - end_loops:
    - 
    -+    vpop         {d8 - d15}
    -     ldmfd       sp!,{r4-r12,r15}            @reload the registers from sp
    - 
    - 
    -diff --git a/common/arm/ihevc_inter_pred_chroma_horz_w16out.s b/common/arm/ihevc_inter_pred_chroma_horz_w16out.s
    -index f95937c..9c498e8 100644
    ---- a/common/arm/ihevc_inter_pred_chroma_horz_w16out.s
    -+++ b/common/arm/ihevc_inter_pred_chroma_horz_w16out.s
    -@@ -90,6 +90,9 @@
    - @r2 =>  src_strd
    - @r3 =>  dst_strd
    - 
    -+.equ    coeff_offset,   104
    -+.equ    ht_offset,      108
    -+.equ    wd_offset,      112
    - 
    - .text
    - .align 4
    -@@ -105,10 +108,11 @@
    - ihevc_inter_pred_chroma_horz_w16out_a9q:
    - 
    -     stmfd       sp!, {r4-r12, r14}          @stack stores the values of the arguments
    -+    vpush        {d8 - d15}
    - 
    --    ldr         r4,[sp,#40]                 @loads pi1_coeff
    --    ldr         r6,[sp,#44]                 @loads ht
    --    ldr         r10,[sp,#48]                @loads wd
    -+    ldr         r4,[sp,#coeff_offset]                 @loads pi1_coeff
    -+    ldr         r6,[sp,#ht_offset]                 @loads ht
    -+    ldr         r10,[sp,#wd_offset]                @loads wd
    - 
    -     vld1.8      {d0},[r4]                   @coeff = vld1_s8(pi1_coeff)
    -     subs        r14,r6,#0                   @checks for ht == 0
    -@@ -362,7 +366,7 @@ epilog_end:
    -     vst1.16     {q10},[r1],r6               @store the result pu1_dst
    - 
    - 
    --    ldr         r6,[sp,#44]                 @loads ht
    -+    ldr         r6,[sp,#ht_offset]                 @loads ht
    - 
    -     and         r7,r6,#1
    - 
    -@@ -710,6 +714,7 @@ loop_residue:
    - 
    - end_loops:
    - 
    -+    vpop         {d8 - d15}
    -     ldmfd       sp!,{r4-r12,r15}            @reload the registers from sp
    - 
    - 
    -diff --git a/common/arm/ihevc_inter_pred_chroma_vert.s b/common/arm/ihevc_inter_pred_chroma_vert.s
    -index e786497..8b4e48b 100644
    ---- a/common/arm/ihevc_inter_pred_chroma_vert.s
    -+++ b/common/arm/ihevc_inter_pred_chroma_vert.s
    -@@ -92,6 +92,11 @@
    - @r1 => *pi2_dst
    - @r2 =>  src_strd
    - @r3 =>  dst_strd
    -+
    -+.equ    coeff_offset,   104
    -+.equ    ht_offset,      108
    -+.equ    wd_offset,      112
    -+
    - .text
    - .align 4
    - 
    -@@ -105,11 +110,12 @@
    - ihevc_inter_pred_chroma_vert_a9q:
    - 
    -     stmfd       sp!,{r4-r12,r14}            @stack stores the values of the arguments
    -+    vpush        {d8 - d15}
    - 
    --    ldr         r4,[sp,#44]                 @loads ht
    --    ldr         r12,[sp,#40]                @loads pi1_coeff
    -+    ldr         r4,[sp,#ht_offset]                 @loads ht
    -+    ldr         r12,[sp,#coeff_offset]                @loads pi1_coeff
    -     cmp         r4,#0                       @checks ht == 0
    --    ldr         r6,[sp,#48]                 @loads wd
    -+    ldr         r6,[sp,#wd_offset]                 @loads wd
    -     sub         r0,r0,r2                    @pu1_src - src_strd
    -     vld1.8      {d0},[r12]                  @loads pi1_coeff
    - 
    -@@ -377,6 +383,7 @@ epilog:
    -     vqrshrun.s16 d24,q12,#6
    -     vst1.8      {d24},[r7],r3               @stores the loaded value
    - end_loops:
    -+    vpop         {d8 - d15}
    -     ldmfd       sp!,{r4-r12,r15}            @reload the registers from sp
    - 
    - 
    -diff --git a/common/arm/ihevc_inter_pred_chroma_vert_w16inp.s b/common/arm/ihevc_inter_pred_chroma_vert_w16inp.s
    -index ba2ea8e..f9e513a 100644
    ---- a/common/arm/ihevc_inter_pred_chroma_vert_w16inp.s
    -+++ b/common/arm/ihevc_inter_pred_chroma_vert_w16inp.s
    -@@ -92,6 +92,11 @@
    - @r2 =>  src_strd
    - @r3 =>  dst_strd
    - 
    -+.equ    coeff_offset,   104
    -+.equ    ht_offset,      108
    -+.equ    wd_offset,      112
    -+
    -+
    - .text
    - .align 4
    - 
    -@@ -105,11 +110,12 @@
    - ihevc_inter_pred_chroma_vert_w16inp_a9q:
    - 
    -     stmfd       sp!, {r4-r12, r14}          @stack stores the values of the arguments
    -+    vpush        {d8 - d15}
    - 
    --    ldr         r4, [sp,#40]                @loads pi1_coeff
    --    ldr         r6, [sp,#48]                @wd
    -+    ldr         r4, [sp,#coeff_offset]                @loads pi1_coeff
    -+    ldr         r6, [sp,#wd_offset]                @wd
    -     lsl         r2,r2,#1                    @src_strd = 2* src_strd
    --    ldr         r5,[sp,#44]                 @loads ht
    -+    ldr         r5,[sp,#ht_offset]                 @loads ht
    -     vld1.8      {d0},[r4]                   @loads pi1_coeff
    -     sub         r4,r0,r2                    @pu1_src - src_strd
    -     vmovl.s8    q0,d0                       @long the value
    -@@ -335,6 +341,7 @@ epilog:
    -     vst1.32     {d24[0]},[r9]               @stores the loaded value
    - 
    - end_loops:
    -+    vpop         {d8 - d15}
    -     ldmfd       sp!,{r4-r12,r15}            @reload the registers from sp
    - 
    - 
    -diff --git a/common/arm/ihevc_inter_pred_chroma_vert_w16inp_w16out.s b/common/arm/ihevc_inter_pred_chroma_vert_w16inp_w16out.s
    -index 00b3011..0c2ffbd 100644
    ---- a/common/arm/ihevc_inter_pred_chroma_vert_w16inp_w16out.s
    -+++ b/common/arm/ihevc_inter_pred_chroma_vert_w16inp_w16out.s
    -@@ -92,6 +92,11 @@
    - @r1 => *pi2_dst
    - @r2 =>  src_strd
    - @r3 =>  dst_strd
    -+
    -+.equ    coeff_offset,   104
    -+.equ    ht_offset,      108
    -+.equ    wd_offset,      112
    -+
    - .text
    - .align 4
    - 
    -@@ -105,11 +110,12 @@
    - ihevc_inter_pred_chroma_vert_w16inp_w16out_a9q:
    - 
    -     stmfd       sp!, {r4-r12, r14}          @stack stores the values of the arguments
    -+    vpush        {d8 - d15}
    - 
    --    ldr         r4, [sp,#40]                @loads pi1_coeff
    --    ldr         r6, [sp,#48]                @wd
    -+    ldr         r4, [sp,#coeff_offset]                @loads pi1_coeff
    -+    ldr         r6, [sp,#wd_offset]                @wd
    -     lsl         r2,r2,#1                    @src_strd = 2* src_strd
    --    ldr         r5,[sp,#44]                 @loads ht
    -+    ldr         r5,[sp,#ht_offset]                 @loads ht
    -     vld1.8      {d0},[r4]                   @loads pi1_coeff
    -     sub         r4,r0,r2                    @pu1_src - src_strd
    -     vmovl.s8    q0,d0                       @long the value
    -@@ -322,6 +328,7 @@ epilog:
    -     vst1.32     {d24},[r9]                  @stores the loaded value
    - 
    - end_loops:
    -+    vpop         {d8 - d15}
    -     ldmfd       sp!,{r4-r12,r15}            @reload the registers from sp
    - 
    - 
    -diff --git a/common/arm/ihevc_inter_pred_chroma_vert_w16out.s b/common/arm/ihevc_inter_pred_chroma_vert_w16out.s
    -index 6e6776c..84b0792 100644
    ---- a/common/arm/ihevc_inter_pred_chroma_vert_w16out.s
    -+++ b/common/arm/ihevc_inter_pred_chroma_vert_w16out.s
    -@@ -93,6 +93,10 @@
    - @r2 =>  src_strd
    - @r3 =>  dst_strd
    - 
    -+.equ    coeff_offset,   104
    -+.equ    ht_offset,      108
    -+.equ    wd_offset,      112
    -+
    - .text
    - .align 4
    - 
    -@@ -106,11 +110,12 @@
    - ihevc_inter_pred_chroma_vert_w16out_a9q:
    - 
    -     stmfd       sp!,{r4-r12,r14}            @stack stores the values of the arguments
    -+    vpush        {d8 - d15}
    - 
    --    ldr         r4,[sp,#44]                 @loads ht
    --    ldr         r12,[sp,#40]                @loads pi1_coeff
    -+    ldr         r4,[sp,#ht_offset]                 @loads ht
    -+    ldr         r12,[sp,#coeff_offset]                @loads pi1_coeff
    -     cmp         r4,#0                       @checks ht == 0
    --    ldr         r6,[sp,#48]                 @loads wd
    -+    ldr         r6,[sp,#wd_offset]                 @loads wd
    -     sub         r0,r0,r2                    @pu1_src - src_strd
    -     vld1.8      {d0},[r12]                  @loads pi1_coeff
    - 
    -@@ -361,6 +366,7 @@ epilog:
    -     vst1.8      {q12},[r7],r3               @stores the loaded value
    - 
    - end_loops:
    -+    vpop         {d8 - d15}
    -     ldmfd       sp!,{r4-r12,r15}            @reload the registers from sp
    - 
    - 
    -diff --git a/common/arm/ihevc_inter_pred_filters_luma_horz.s b/common/arm/ihevc_inter_pred_filters_luma_horz.s
    -index 215f8fd..5559aa7 100644
    ---- a/common/arm/ihevc_inter_pred_filters_luma_horz.s
    -+++ b/common/arm/ihevc_inter_pred_filters_luma_horz.s
    -@@ -103,6 +103,11 @@
    - @   r5 =>  ht
    - @   r6 =>  wd
    - 
    -+
    -+.equ    coeff_offset,   104
    -+.equ    ht_offset,      108
    -+.equ    wd_offset,      112
    -+
    - .text
    - .align 4
    - 
    -@@ -116,15 +121,15 @@
    - ihevc_inter_pred_luma_horz_a9q:
    - 
    -     stmfd       sp!, {r4-r12, r14}          @stack stores the values of the arguments
    --    @str        r1,[sp,#-4]
    --    @ mov       r7,#8192
    -+    vpush        {d8 - d15}
    -+
    -+
    - start_loop_count:
    --    @ ldr       r1,[sp,#-4]
    - 
    - 
    --    ldr         r4,[sp,#40]                 @loads pi1_coeff
    --    ldr         r8,[sp,#44]                 @loads ht
    --    ldr         r10,[sp,#48]                @loads wd
    -+    ldr         r4,[sp,#coeff_offset]                 @loads pi1_coeff
    -+    ldr         r8,[sp,#ht_offset]                 @loads ht
    -+    ldr         r10,[sp,#wd_offset]                @loads wd
    - 
    -     vld1.8      {d0},[r4]                   @coeff = vld1_s8(pi1_coeff)
    -     mov         r11,#1
    -@@ -262,7 +267,8 @@ end_inner_loop_8:
    - 
    - 
    - 
    --    ldr         r10,[sp,#48]                @loads wd
    -+    ldr         r10,[sp,#wd_offset]                @loads wd
    -+
    -     cmp         r10,#12
    - 
    -     beq         outer_loop4_residual
    -@@ -270,6 +276,7 @@ end_inner_loop_8:
    - 
    - end_loops:
    - 
    -+    vpop         {d8 - d15}
    -     ldmfd       sp!,{r4-r12,r15}            @reload the registers from sp
    - 
    - 
    -@@ -417,7 +424,7 @@ epilog_16:
    - 
    -     ldr         r7, [sp], #4
    -     ldr         r0, [sp], #4
    --    ldr         r10,[sp,#48]
    -+    ldr         r10,[sp,#wd_offset]
    -     cmp         r10,#24
    - 
    -     beq         outer_loop8_residual
    -@@ -426,6 +433,7 @@ epilog_16:
    - 
    - end_loops1:
    - 
    -+    vpop         {d8 - d15}
    -     ldmfd       sp!,{r4-r12,r15}            @reload the registers from sp
    - 
    - 
    -@@ -527,6 +535,7 @@ end_inner_loop_4:
    -     @subs   r7,r7,#1
    -     @ bgt   start_loop_count
    - 
    -+    vpop         {d8 - d15}
    -     ldmfd       sp!,{r4-r12,r15}            @reload the registers from sp
    - 
    - 
    -diff --git a/common/arm/ihevc_inter_pred_filters_luma_vert.s b/common/arm/ihevc_inter_pred_filters_luma_vert.s
    -index f51d68c..3d9ab1c 100644
    ---- a/common/arm/ihevc_inter_pred_filters_luma_vert.s
    -+++ b/common/arm/ihevc_inter_pred_filters_luma_vert.s
    -@@ -103,6 +103,11 @@
    - @   r12 => *pi1_coeff
    - @   r5 =>  ht
    - @   r3 =>  wd
    -+
    -+.equ    coeff_offset,   104
    -+.equ    ht_offset,      108
    -+.equ    wd_offset,      112
    -+
    - .text
    - .align 4
    - .syntax unified
    -@@ -116,15 +121,16 @@
    - ihevc_inter_pred_luma_vert_a9q:
    - 
    -     stmfd       sp!, {r4-r12, r14}          @stack stores the values of the arguments
    -+    vpush        {d8 - d15}
    - 
    --    ldr         r12,[sp,#40]                @load pi1_coeff
    -+    ldr         r12,[sp,#coeff_offset]                @load pi1_coeff
    -     mov         r6,r3
    --    ldr         r5,[sp,#48]                 @load wd
    -+    ldr         r5,[sp,#wd_offset]                 @load wd
    -     vld1.u8     {d0},[r12]                  @coeff = vld1_s8(pi1_coeff)
    -     sub         r12,r2,r2,lsl #2            @src_ctrd & pi1_coeff
    -     vabs.s8     d0,d0                       @vabs_s8(coeff)
    -     add         r0,r0,r12                   @r0->pu1_src    r12->pi1_coeff
    --    ldr         r3,[sp,#44]                 @load ht
    -+    ldr         r3,[sp,#ht_offset]                 @load ht
    -     subs        r7,r3,#0                    @r3->ht
    -     @ble        end_loops           @end loop jump
    -     vdup.u8     d22,d0[0]                   @coeffabs_0 = vdup_lane_u8(coeffabs, 0)@
    -@@ -407,7 +413,8 @@ end_loops:
    -     ldr         r1, [sp], #4
    -     ldr         r0, [sp], #4
    - 
    --    ldmfdeq     sp!,{r4-r12,r15}            @reload the registers from sp
    -+    beq         end1
    -+
    -     mov         r5, #4
    -     add         r0, r0, #8
    -     add         r1, r1, #8
    -@@ -491,6 +498,8 @@ end_inner_loop_wd_4:
    -     add         r0,r0,r8
    -     bgt         outer_loop_wd_4
    - 
    -+end1:
    -+    vpop         {d8 - d15}
    -     ldmfd       sp!, {r4-r12, r15}          @reload the registers from sp
    - 
    - 
    -@@ -564,15 +573,16 @@ end_inner_loop_wd_4:
    - ihevc_inter_pred_luma_vert_w16out_a9q:
    - 
    -     stmfd       sp!, {r4-r12, r14}          @stack stores the values of the arguments
    -+    vpush        {d8 - d15}
    - 
    --    ldr         r12,[sp,#40]                @load pi1_coeff
    -+    ldr         r12,[sp,#coeff_offset]                @load pi1_coeff
    -     mov         r6,r3
    --    ldr         r5,[sp,#48]                 @load wd
    -+    ldr         r5,[sp,#wd_offset]                 @load wd
    -     vld1.u8     {d0},[r12]                  @coeff = vld1_s8(pi1_coeff)
    -     sub         r12,r2,r2,lsl #2            @src_ctrd & pi1_coeff
    -     vabs.s8     d0,d0                       @vabs_s8(coeff)
    -     add         r0,r0,r12                   @r0->pu1_src    r12->pi1_coeff
    --    ldr         r3,[sp,#44]                 @load ht
    -+    ldr         r3,[sp,#ht_offset]                 @load ht
    -     subs        r7,r3,#0                    @r3->ht
    -     @ble        end_loops_16out         @end loop jump
    -     vdup.u8     d22,d0[0]                   @coeffabs_0 = vdup_lane_u8(coeffabs, 0)@
    -@@ -848,7 +858,8 @@ end_loops_16out:
    -     ldr         r1, [sp], #4
    -     ldr         r0, [sp], #4
    - 
    --    ldmfdeq     sp!,{r4-r12,r15}            @reload the registers from sp
    -+    beq         end2
    -+
    -     mov         r5, #4
    -     add         r0, r0, #8
    -     add         r1, r1, #16
    -@@ -934,7 +945,8 @@ end_inner_loop_wd_4_16out:
    -     add         r1,r1,r9,lsl #1
    -     add         r0,r0,r8
    -     bgt         outer_loop_wd_4_16out
    --
    -+end2:
    -+    vpop         {d8 - d15}
    -     ldmfd       sp!, {r4-r12, r15}          @reload the registers from sp
    - 
    - 
    -diff --git a/common/arm/ihevc_inter_pred_filters_luma_vert_w16inp.s b/common/arm/ihevc_inter_pred_filters_luma_vert_w16inp.s
    -index 4fbc5d1..9726710 100644
    ---- a/common/arm/ihevc_inter_pred_filters_luma_vert_w16inp.s
    -+++ b/common/arm/ihevc_inter_pred_filters_luma_vert_w16inp.s
    -@@ -94,6 +94,10 @@
    - @                                    word32 ht,
    - @                                    word32 wd   )
    - 
    -+.equ    coeff_offset,   104
    -+.equ    ht_offset,      108
    -+.equ    wd_offset,      112
    -+
    - .text
    - .align 4
    - 
    -@@ -107,16 +111,17 @@
    - ihevc_inter_pred_luma_vert_w16inp_a9q:
    - 
    -     stmfd       sp!, {r4-r12, r14}          @stack stores the values of the arguments
    -+    vpush        {d8 - d15}
    - 
    --    ldr         r12,[sp,#40]                @load pi1_coeff
    -+    ldr         r12,[sp,#coeff_offset]                @load pi1_coeff
    -     mov         r6,r3
    --    ldr         r5,[sp,#48]                 @load wd
    -+    ldr         r5,[sp,#wd_offset]                 @load wd
    -     vld1.8      {d0},[r12]                  @coeff = vld1_s8(pi1_coeff)
    -     mov         r2, r2, lsl #1
    -     sub         r12,r2,r2,lsl #2            @src_ctrd & pi1_coeff
    -     @vabs.s8    d0,d0               @vabs_s8(coeff)
    -     add         r0,r0,r12                   @r0->pu1_src    r12->pi1_coeff
    --    ldr         r3,[sp,#44]                 @load ht
    -+    ldr         r3,[sp,#ht_offset]                 @load ht
    -     subs        r7,r3,#0                    @r3->ht
    -     @ble        end_loops           @end loop jump
    -     vmovl.s8    q0,d0
    -@@ -370,6 +375,7 @@ epilog_end:
    - 
    - end_loops:
    - 
    -+    vpop         {d8 - d15}
    -     ldmfd       sp!,{r4-r12,r15}            @reload the registers from sp
    - 
    - 
    -diff --git a/common/arm/ihevc_inter_pred_luma_copy.s b/common/arm/ihevc_inter_pred_luma_copy.s
    -index 8a61369..e4f5573 100644
    ---- a/common/arm/ihevc_inter_pred_luma_copy.s
    -+++ b/common/arm/ihevc_inter_pred_luma_copy.s
    -@@ -71,6 +71,10 @@
    - @   r7 =>  ht
    - @   r12 => wd
    - 
    -+.equ    coeff_offset,   104
    -+.equ    ht_offset,      108
    -+.equ    wd_offset,      112
    -+
    - .text
    - .align 4
    - 
    -@@ -83,8 +87,9 @@
    - 
    - ihevc_inter_pred_luma_copy_a9q:
    -     stmfd       sp!, {r4-r12, r14}          @stack stores the values of the arguments
    --    ldr         r12,[sp,#48]                @loads wd
    --    ldr         r7,[sp,#44]                 @loads ht
    -+    vpush        {d8 - d15}
    -+    ldr         r12,[sp,#wd_offset]                @loads wd
    -+    ldr         r7,[sp,#ht_offset]                 @loads ht
    -     cmp         r7,#0                       @checks ht == 0
    -     ble         end_loops
    -     tst         r12,#15                     @checks wd for multiples for 4 & 8
    -@@ -121,6 +126,7 @@ end_inner_loop_wd_4:
    -     bgt         outer_loop_wd_4
    - 
    - end_loops:
    -+    vpop         {d8 - d15}
    -     ldmfd       sp!,{r4-r12,r15}            @reload the registers from sp
    - 
    - 
    -@@ -151,6 +157,7 @@ end_inner_loop_wd_8:
    -     sub         r1,r6,r11                   @pu1_dst = pu1_dst_tmp
    -     bgt         outer_loop_wd_8
    - 
    -+    vpop         {d8 - d15}
    -     ldmfd       sp!,{r4-r12,r15}            @reload the registers from sp
    - 
    - core_loop_wd_16:
    -@@ -180,6 +187,7 @@ end_inner_loop_wd_16:
    -     sub         r1,r6,r11                   @pu1_dst = pu1_dst_tmp
    -     bgt         outer_loop_wd_16
    - 
    -+    vpop         {d8 - d15}
    -     ldmfd       sp!,{r4-r12,r15}            @reload the registers from sp
    - 
    - 
    -diff --git a/common/arm/ihevc_inter_pred_luma_copy_w16out.s b/common/arm/ihevc_inter_pred_luma_copy_w16out.s
    -index 771bcb3..84dbbad 100644
    ---- a/common/arm/ihevc_inter_pred_luma_copy_w16out.s
    -+++ b/common/arm/ihevc_inter_pred_luma_copy_w16out.s
    -@@ -72,6 +72,10 @@
    - @   r7 =>  ht
    - @   r12 => wd
    - 
    -+.equ    coeff_offset,   104
    -+.equ    ht_offset,      108
    -+.equ    wd_offset,      112
    -+
    - .text
    - .align 4
    - 
    -@@ -85,8 +89,9 @@
    - ihevc_inter_pred_luma_copy_w16out_a9q:
    - 
    -     stmfd       sp!, {r4-r12, r14}          @stack stores the values of the arguments
    --    ldr         r12,[sp,#48]                @loads wd
    --    ldr         r7,[sp,#44]                 @loads ht
    -+    vpush        {d8 - d15}
    -+    ldr         r12,[sp,#wd_offset]                @loads wd
    -+    ldr         r7,[sp,#ht_offset]                 @loads ht
    -     cmp         r7,#0                       @ht condition(ht == 0)
    -     ble         end_loops                   @loop
    -     tst         r12,#7                      @conditional check for wd (multiples)
    -@@ -129,6 +134,7 @@ end_inner_loop_wd_4:
    -     bgt         outer_loop_wd_4
    - 
    - end_loops:
    -+    vpop         {d8 - d15}
    -     ldmfd       sp!,{r4-r12,r15}            @reload the registers from sp
    - 
    - 
    -@@ -242,6 +248,7 @@ epilog_end:
    -     vst1.16     {d6,d7},[r10],r5            @vst1q_s16(pi2_dst_tmp, tmp)
    - 
    - 
    -+    vpop         {d8 - d15}
    -     ldmfd       sp!,{r4-r12,r15}            @reload the registers from sp
    - 
    - 
    -diff --git a/common/arm/ihevc_inter_pred_luma_horz_w16out.s b/common/arm/ihevc_inter_pred_luma_horz_w16out.s
    -index e8800e0..a60bb08 100644
    ---- a/common/arm/ihevc_inter_pred_luma_horz_w16out.s
    -+++ b/common/arm/ihevc_inter_pred_luma_horz_w16out.s
    -@@ -107,6 +107,11 @@
    - @r11 - #1
    - @r12 - src_ptr1
    - @r14 - loop_counter
    -+
    -+.equ    coeff_offset,   104
    -+.equ    ht_offset,      108
    -+.equ    wd_offset,      112
    -+
    - .text
    - .align 4
    - .syntax unified
    -@@ -122,16 +127,16 @@ ihevc_inter_pred_luma_horz_w16out_a9q:
    - 
    -     bic         r14, #1                     @ clearing bit[0], so that it goes back to mode
    -     stmfd       sp!, {r4-r12, r14}          @stack stores the values of the arguments
    --    ldr         r4,[sp,#40]                 @loads pi1_coeff
    --    ldr         r7,[sp,#44]                 @loads ht
    -+    vpush       {d8 - d15}
    -+    ldr         r4,[sp,#coeff_offset]                 @loads pi1_coeff
    -+    ldr         r7,[sp,#ht_offset]                 @loads ht
    - 
    - 
    -     vld1.8      {d0},[r4]                   @coeff = vld1_s8(pi1_coeff)
    -     sub         r14,r7,#0                   @checks for ht == 0
    -     vabs.s8     d2,d0                       @vabs_s8(coeff)
    -     mov         r11,#1
    --    @ble       end_loops
    --    ldr         r10,[sp,#48]                @loads wd
    -+    ldr         r10,[sp,#wd_offset]                @loads wd
    -     vdup.8      d24,d2[0]                   @coeffabs_0 = vdup_lane_u8(coeffabs, 0)
    -     sub         r12,r0,#3                   @pu1_src - 3
    -     vdup.8      d25,d2[1]                   @coeffabs_1 = vdup_lane_u8(coeffabs, 1)
    -@@ -274,11 +279,10 @@ end_inner_loop_4:
    - 
    - height_residue_4:
    - 
    --    ldr         r7,[sp,#44]                 @loads ht
    -+    ldr         r7,[sp,#ht_offset]                 @loads ht
    -     and         r7,r7,#1                    @calculating ht_residue ht_residue = (ht & 1)
    -     cmp         r7,#0
    --    @beq        end_loops
    --    ldmfdeq     sp!,{r4-r12,r15}            @reload the registers from sp
    -+    beq         end_loops
    - 
    - outer_loop_height_residue_4:
    - 
    -@@ -331,7 +335,7 @@ end_inner_loop_height_residue_4:
    -     add         r12,r12,r9                  @increment the input pointer src_strd-wd
    -     add         r1,r1,r8                    @increment the output pointer dst_strd-wd
    -     bgt         outer_loop_height_residue_4
    --
    -+    vpop        {d8 - d15}
    -     ldmfd       sp!,{r4-r12,r15}            @reload the registers from sp
    - 
    - outer_loop8_residual:
    -@@ -427,18 +431,18 @@ end_inner_loop_8:
    - 
    - 
    - 
    --    ldr         r10,[sp,#48]                @loads wd
    -+    ldr         r10,[sp,#wd_offset]                @loads wd
    -     cmp         r10,#12
    - 
    -     beq         outer_loop4_residual
    - 
    --    ldr         r7,[sp,#44]                 @loads ht
    -+    ldr         r7,[sp,#ht_offset]                 @loads ht
    -     and         r7,r7,#1
    -     cmp         r7,#1
    -     beq         height_residue_4
    - 
    --@end_loops
    - 
    -+    vpop        {d8 - d15}
    -     ldmfd       sp!,{r4-r12,r15}            @reload the registers from sp
    - 
    - 
    -@@ -452,7 +456,6 @@ outer_loop_16:
    -     add         r4,r12,r2                   @pu1_src + src_strd
    -     and         r0, r12, #31
    -     sub         r5,r10,#0                   @checks wd
    --    @ble       end_loops1
    -     pld         [r12, r2, lsl #1]
    -     vld1.u32    {q0},[r12],r11              @vector load pu1_src
    -     pld         [r4, r2, lsl #1]
    -@@ -580,17 +583,17 @@ epilog_16:
    - 
    -     ldr         r7, [sp], #4
    -     ldr         r0, [sp], #4
    --    ldr         r10,[sp,#48]
    -+    ldr         r10,[sp,#wd_offset]
    -     cmp         r10,#24
    -     beq         outer_loop8_residual
    -     add         r1,r6,r8,lsl #1
    --    ldr         r7,[sp,#44]                 @loads ht
    -+    ldr         r7,[sp,#ht_offset]                 @loads ht
    -     and         r7,r7,#1
    -     cmp         r7,#1
    -     beq         height_residue_4
    - 
    --end_loops1:
    --
    -+end_loops:
    -+    vpop        {d8 - d15}
    -     ldmfd       sp!,{r4-r12,r15}            @reload the registers from sp
    - 
    - 
    -diff --git a/common/arm/ihevc_inter_pred_luma_vert_w16inp_w16out.s b/common/arm/ihevc_inter_pred_luma_vert_w16inp_w16out.s
    -index c6716fe..6e0f1ed 100644
    ---- a/common/arm/ihevc_inter_pred_luma_vert_w16inp_w16out.s
    -+++ b/common/arm/ihevc_inter_pred_luma_vert_w16inp_w16out.s
    -@@ -102,6 +102,10 @@
    - @   r5 =>  ht
    - @   r6 =>  wd
    - 
    -+.equ    coeff_offset,   104
    -+.equ    ht_offset,      108
    -+.equ    wd_offset,      112
    -+
    - .text
    - .align 4
    - 
    -@@ -115,16 +119,17 @@
    - ihevc_inter_pred_luma_vert_w16inp_w16out_a9q:
    - 
    -     stmfd       sp!, {r4-r12, r14}          @stack stores the values of the arguments
    -+    vpush        {d8 - d15}
    - 
    --    ldr         r12,[sp,#40]                @load pi1_coeff
    -+    ldr         r12,[sp,#coeff_offset]                @load pi1_coeff
    -     mov         r6,r3,lsl #1
    --    ldr         r5,[sp,#48]                 @load wd
    -+    ldr         r5,[sp,#wd_offset]                 @load wd
    -     vld1.8      {d0},[r12]                  @coeff = vld1_s8(pi1_coeff)
    -     mov         r2, r2, lsl #1
    -     sub         r12,r2,r2,lsl #2            @src_ctrd & pi1_coeff
    -     @vabs.s8    d0,d0               @vabs_s8(coeff)
    -     add         r0,r0,r12                   @r0->pu1_src    r12->pi1_coeff
    --    ldr         r3,[sp,#44]                 @load ht
    -+    ldr         r3,[sp,#ht_offset]                 @load ht
    -     subs        r7,r3,#0                    @r3->ht
    -     @ble        end_loops           @end loop jump
    -     vmovl.s8    q0,d0
    -@@ -393,6 +398,7 @@ epilog_end:
    - 
    - end_loops:
    - 
    -+    vpop         {d8 - d15}
    -     ldmfd       sp!,{r4-r12,r15}            @reload the registers from sp
    - 
    - 
    -diff --git a/common/arm/ihevc_intra_pred_chroma_dc.s b/common/arm/ihevc_intra_pred_chroma_dc.s
    -index 72d9730..6e5900a 100644
    ---- a/common/arm/ihevc_intra_pred_chroma_dc.s
    -+++ b/common/arm/ihevc_intra_pred_chroma_dc.s
    -@@ -92,6 +92,8 @@
    - @   mode
    - @   pi1_coeff
    - 
    -+.equ    nt_offset,      40
    -+
    - .text
    - .align 4
    - 
    -@@ -106,7 +108,7 @@ ihevc_intra_pred_chroma_dc_a9q:
    - 
    -     stmfd       sp!, {r4-r12, r14}          @stack stores the values of the arguments
    - 
    --    ldr         r4,[sp,#40]                 @loads nt
    -+    ldr         r4,[sp,#nt_offset]          @loads nt
    -     mov         r9, #0
    -     vmov        d17, r9, r9
    - 
    -diff --git a/common/arm/ihevc_intra_pred_chroma_horz.s b/common/arm/ihevc_intra_pred_chroma_horz.s
    -index 6089fd8..4512d72 100644
    ---- a/common/arm/ihevc_intra_pred_chroma_horz.s
    -+++ b/common/arm/ihevc_intra_pred_chroma_horz.s
    -@@ -84,6 +84,8 @@
    - @r2 => *pu1_dst
    - @r3 =>  dst_strd
    - 
    -+.equ    nt_offset,      104
    -+
    - .text
    - .align 4
    - 
    -@@ -97,8 +99,9 @@
    - ihevc_intra_pred_chroma_horz_a9q:
    - 
    -     stmfd       sp!, {r4-r12, r14}          @stack stores the values of the arguments
    -+    vpush       {d8 - d15}
    - 
    --    ldr         r4,[sp,#40]                 @loads nt
    -+    ldr         r4,[sp,#nt_offset]          @loads nt
    - 
    -     lsl         r6,r4,#2                    @four_nt
    - 
    -@@ -187,6 +190,7 @@ core_loop_16:
    -     vst1.16     {q4},[r2],r3
    -     vst1.16     {q4},[r9],r3
    -     bgt         core_loop_16
    -+    vpop        {d8 - d15}
    -     ldmfd       sp!,{r4-r12,r15}            @reload the registers from sp
    -     b           endloop
    - 
    -@@ -263,6 +267,7 @@ core_loop_8:
    -     @vst1.8     {q5},[r2],r3
    -     @vst1.8     {q6},[r2],r3
    -     @vst1.8     {q7},[r2],r3
    -+    vpop        {d8 - d15}
    - 
    -     ldmfd       sp!,{r4-r12,r15}            @reload the registers from sp
    -     b           endloop
    -@@ -308,6 +313,7 @@ core_loop_4:
    - 
    -     @vst1.8     {d8},[r2],r3
    -     @vst1.8     {d9},[r2],r3
    -+    vpop        {d8 - d15}
    -     ldmfd       sp!,{r4-r12,r15}            @reload the registers from sp
    -     b           endloop
    - 
    -@@ -339,6 +345,7 @@ core_loop_4:
    -     vst1.32     {d4[0]},[r2],r3
    -     vst1.32     {d5[0]},[r2],r3
    - 
    -+    vpop        {d8 - d15}
    -     ldmfd       sp!,{r4-r12,r15}            @reload the registers from sp
    - 
    - endloop:
    -diff --git a/common/arm/ihevc_intra_pred_chroma_mode2.s b/common/arm/ihevc_intra_pred_chroma_mode2.s
    -index cfa2ddb..013700d 100644
    ---- a/common/arm/ihevc_intra_pred_chroma_mode2.s
    -+++ b/common/arm/ihevc_intra_pred_chroma_mode2.s
    -@@ -87,11 +87,13 @@
    - @r2 => *pu1_dst
    - @r3 => dst_strd
    - 
    --@stack contents from #40
    -+@stack contents from #104
    - @   nt
    - @   mode
    - @   pi1_coeff
    - 
    -+.equ    nt_offset,      104
    -+
    - .text
    - .align 4
    - 
    -@@ -105,8 +107,9 @@
    - ihevc_intra_pred_chroma_mode2_a9q:
    - 
    -     stmfd       sp!, {r4-r12, r14}          @stack stores the values of the arguments
    -+    vpush       {d8 - d15}
    - 
    --    ldr         r4,[sp,#40]                 @loads nt
    -+    ldr         r4,[sp,#nt_offset]          @loads nt
    -     mov         r8,#-4
    - 
    -     cmp         r4,#4
    -@@ -290,6 +293,7 @@ mode2_4:
    -     vst1.8      {d6},[r2],r3
    - 
    - end_func:
    -+    vpop        {d8 - d15}
    -     ldmfd       sp!,{r4-r12,r15}            @reload the registers from sp
    - 
    - 
    -diff --git a/common/arm/ihevc_intra_pred_chroma_mode_18_34.s b/common/arm/ihevc_intra_pred_chroma_mode_18_34.s
    -index b0dd1fa..6af6450 100644
    ---- a/common/arm/ihevc_intra_pred_chroma_mode_18_34.s
    -+++ b/common/arm/ihevc_intra_pred_chroma_mode_18_34.s
    -@@ -87,11 +87,14 @@
    - @r2 => *pu1_dst
    - @r3 => dst_strd
    - 
    --@stack contents from #40
    -+@stack contents from #104
    - @   nt
    - @   mode
    - @   pi1_coeff
    - 
    -+.equ    nt_offset,          104
    -+.equ    mode_offset,        108
    -+
    - .text
    - .align 4
    - 
    -@@ -105,10 +108,10 @@
    - ihevc_intra_pred_chroma_mode_18_34_a9q:
    - 
    -     stmfd       sp!, {r4-r12, r14}          @stack stores the values of the arguments
    -+    vpush       {d8 - d15}
    - 
    --
    --    ldr         r4,[sp,#40]
    --    ldr         r5,[sp,#44]
    -+    ldr         r4,[sp,#nt_offset]
    -+    ldr         r5,[sp,#mode_offset]
    - 
    -     cmp         r4,#4
    -     beq         mode2_4
    -@@ -181,6 +184,7 @@ mode2_4:
    -     vst1.32     {d0},[r2],r3
    - 
    - end_func:
    -+    vpop        {d8 - d15}
    -     ldmfd       sp!,{r4-r12,r15}            @reload the registers from sp
    - 
    - 
    -diff --git a/common/arm/ihevc_intra_pred_chroma_mode_27_to_33.s b/common/arm/ihevc_intra_pred_chroma_mode_27_to_33.s
    -index fb75e96..21b54da 100644
    ---- a/common/arm/ihevc_intra_pred_chroma_mode_27_to_33.s
    -+++ b/common/arm/ihevc_intra_pred_chroma_mode_27_to_33.s
    -@@ -81,6 +81,9 @@
    - @                                         word32 nt,
    - @                                         word32 mode)
    - 
    -+.equ    nt_offset,          104
    -+.equ    mode_offset,        108
    -+
    - .text
    - .align 4
    - 
    -@@ -103,9 +106,10 @@ gau1_ihevc_planar_factor_addr:
    - ihevc_intra_pred_chroma_mode_27_to_33_a9q:
    - 
    -     stmfd       sp!, {r4-r12, r14}          @stack stores the values of the arguments
    -+    vpush        {d8 - d15}
    - 
    --    ldr         r4,[sp,#40]                 @loads nt
    --    ldr         r5,[sp,#44]                 @loads mode
    -+    ldr         r4,[sp,#nt_offset]                 @loads nt
    -+    ldr         r5,[sp,#mode_offset]                 @loads mode
    -     ldr         r6,gai4_ihevc_ang_table_addr @loads word32 gai4_ihevc_ang_table[35]
    - ulbl1:
    -     add         r6,r6,pc
    -@@ -535,6 +539,7 @@ core_loop_4:
    -     vst1.8      {d22},[r2],r3
    - 
    - end_loops:
    -+    vpop         {d8 - d15}
    -     ldmfd       sp!,{r4-r12,r15}            @reload the registers from sp
    - 
    - 
    -diff --git a/common/arm/ihevc_intra_pred_chroma_mode_3_to_9.s b/common/arm/ihevc_intra_pred_chroma_mode_3_to_9.s
    -index a5eb3ca..b7dcbfb 100644
    ---- a/common/arm/ihevc_intra_pred_chroma_mode_3_to_9.s
    -+++ b/common/arm/ihevc_intra_pred_chroma_mode_3_to_9.s
    -@@ -82,10 +82,13 @@
    - @r2 => *pu1_dst
    - @r3 => dst_strd
    - 
    --@stack contents from #40
    -+@stack contents from #104
    - @   nt
    - @   mode
    - 
    -+.equ    nt_offset,          104
    -+.equ    mode_offset,        108
    -+
    - .text
    - .align 4
    - 
    -@@ -123,13 +126,14 @@ col_for_intra_chroma_addr_3:
    - ihevc_intra_pred_chroma_mode_3_to_9_a9q:
    - 
    -     stmfd       sp!, {r4-r12, r14}          @stack stores the values of the arguments
    -+    vpush       {d8 - d15}
    - 
    --    ldr         r4,[sp,#40]                 @loads nt
    -+    ldr         r4,[sp,#nt_offset]          @loads nt
    -     ldr         r7, gai4_ihevc_ang_table_addr
    - ulbl1:
    -     add         r7,r7,pc
    - 
    --    ldr         r5,[sp,#44]                 @mode (3 to 9)
    -+    ldr         r5,[sp,#mode_offset]        @mode (3 to 9)
    -     ldr         r8, gai4_ihevc_inv_ang_table_addr
    - ulbl2:
    -     add         r8,r8,pc
    -@@ -486,6 +490,7 @@ epil_8_16_32:
    -     vst1.8      d18, [r5], r3               @st (row 7)
    - 
    - end_func:
    -+    vpop        {d8 - d15}
    -     ldmfd       sp!,{r4-r12,r15}            @reload the registers from sp
    - 
    - 
    -diff --git a/common/arm/ihevc_intra_pred_chroma_planar.s b/common/arm/ihevc_intra_pred_chroma_planar.s
    -index 30b3144..7d03d55 100644
    ---- a/common/arm/ihevc_intra_pred_chroma_planar.s
    -+++ b/common/arm/ihevc_intra_pred_chroma_planar.s
    -@@ -87,11 +87,13 @@
    - @r2 => *pu1_dst
    - @r3 => dst_strd
    - 
    --@stack contents from #40
    -+@stack contents from #104
    - @   nt
    - @   mode
    - @   pi1_coeff
    - 
    -+.equ    nt_offset,      104
    -+
    - .text
    - .align 4
    - 
    -@@ -109,8 +111,9 @@ gau1_ihevc_planar_factor_addr:
    - ihevc_intra_pred_chroma_planar_a9q:
    - 
    -     stmfd       sp!, {r4-r12, r14}          @stack stores the values of the arguments
    -+    vpush       {d8 - d15}
    - 
    --    ldr         r4,[sp,#40]                 @loads nt
    -+    ldr         r4,[sp,#nt_offset]          @loads nt
    -     ldr         r11, gau1_ihevc_planar_factor_addr @loads table of coeffs
    - ulbl1:
    -     add         r11,r11,pc
    -@@ -353,6 +356,7 @@ loop_sz_4:
    -     bne         loop_sz_4
    - 
    - end_loop:
    -+    vpop        {d8 - d15}
    -     ldmfd       sp!,{r4-r12,r15}            @reload the registers from sp
    - 
    - 
    -diff --git a/common/arm/ihevc_intra_pred_chroma_ver.s b/common/arm/ihevc_intra_pred_chroma_ver.s
    -index b68a045..ce2ad73 100644
    ---- a/common/arm/ihevc_intra_pred_chroma_ver.s
    -+++ b/common/arm/ihevc_intra_pred_chroma_ver.s
    -@@ -87,6 +87,8 @@
    - @   nt
    - @   mode
    - 
    -+.equ    nt_offset,      40
    -+
    - .text
    - .align 4
    - 
    -@@ -101,7 +103,7 @@ ihevc_intra_pred_chroma_ver_a9q:
    - 
    -     stmfd       sp!, {r4-r12, r14}          @stack stores the values of the arguments
    - 
    --    ldr         r4,[sp,#40]                 @loads nt
    -+    ldr         r4,[sp,#nt_offset]          @loads nt
    -     lsl         r5, r4, #2                  @4nt
    - 
    - 
    -diff --git a/common/arm/ihevc_intra_pred_filters_chroma_mode_11_to_17.s b/common/arm/ihevc_intra_pred_filters_chroma_mode_11_to_17.s
    -index 6c882cf..8644cc8 100644
    ---- a/common/arm/ihevc_intra_pred_filters_chroma_mode_11_to_17.s
    -+++ b/common/arm/ihevc_intra_pred_filters_chroma_mode_11_to_17.s
    -@@ -84,10 +84,13 @@
    - @r2 => *pu1_dst
    - @r3 => dst_strd
    - 
    --@stack contents from #40
    -+@stack contents from #236
    - @   nt
    - @   mode
    - 
    -+.equ    nt_offset,      236
    -+.equ    mode_offset,    240
    -+
    - .text
    - .align 4
    - 
    -@@ -123,13 +126,15 @@ col_for_intra_chroma_addr_3:
    - ihevc_intra_pred_chroma_mode_11_to_17_a9q:
    - 
    -     stmfd       sp!, {r4-r12, r14}          @stack stores the values of the arguments
    -+    vpush        {d8 - d15}
    -+    sub         sp, sp, #132                @ref_temp[2 * max_cu_size + 2]
    - 
    --    ldr         r4,[sp,#40]                 @loads nt
    -+    ldr         r4,[sp,#nt_offset]          @loads wd
    -     ldr         r7, gai4_ihevc_ang_table_addr
    - ulbl1:
    -     add         r7,r7,pc
    - 
    --    ldr         r5,[sp,#44]                 @mode (11 to 17)
    -+    ldr         r5,[sp,#mode_offset]        @mode (11 to 17)
    -     ldr         r8, gai4_ihevc_inv_ang_table_addr
    - ulbl2:
    -     add         r8,r8,pc
    -@@ -139,7 +144,6 @@ ulbl2:
    -     sub         r8, r8, #44
    - 
    -     ldr         r7, [r7]                    @intra_pred_ang
    --    sub         sp, sp, #132                @ref_temp[2 * max_cu_size + 2]
    - 
    -     ldr         r8, [r8]                    @inv_ang
    -     add         r6, sp, r4, lsl #1          @ref_temp + 2 * nt
    -@@ -607,6 +611,7 @@ epil_8_16_32:
    - 
    - end_func:
    -     add         sp, sp, #132
    -+    vpop        {d8 - d15}
    -     ldmfd       sp!,{r4-r12,r15}            @reload the registers from sp
    - 
    - 
    -diff --git a/common/arm/ihevc_intra_pred_filters_chroma_mode_19_to_25.s b/common/arm/ihevc_intra_pred_filters_chroma_mode_19_to_25.s
    -index 2ede914..a555646 100644
    ---- a/common/arm/ihevc_intra_pred_filters_chroma_mode_19_to_25.s
    -+++ b/common/arm/ihevc_intra_pred_filters_chroma_mode_19_to_25.s
    -@@ -84,10 +84,13 @@
    - @r2 => *pu1_dst
    - @r3 => dst_strd
    - 
    --@stack contents from #40
    -+@stack contents from #236
    - @   nt
    - @   mode
    - 
    -+.equ    nt_offset,      236
    -+.equ    mode_offset,    240
    -+
    - .text
    - .align 4
    - 
    -@@ -116,13 +119,15 @@ gai4_ihevc_ang_table_addr_2:
    - ihevc_intra_pred_chroma_mode_19_to_25_a9q:
    - 
    -     stmfd       sp!, {r4-r12, r14}          @stack stores the values of the arguments
    -+    vpush       {d8 - d15}
    -+    sub         sp, sp, #132                @ref_temp[2 * max_cu_size + 2]
    - 
    --    ldr         r4,[sp,#40]                 @loads nt
    -+    ldr         r4,[sp,#nt_offset]          @loads nt
    -     ldr         r7, gai4_ihevc_ang_table_addr_1
    - ulbl3:
    -     add         r7,r7,pc
    - 
    --    ldr         r5,[sp,#44]                 @mode (19 to 25)
    -+    ldr         r5,[sp,#mode_offset]        @mode (19 to 25)
    -     ldr         r8, gai4_ihevc_inv_ang_table_addr
    - ulbl1:
    -     add         r8,r8,pc
    -@@ -132,7 +137,6 @@ ulbl1:
    -     sub         r8, r8, #48                 @gai4_ihevc_inv_ang_table[mode - 12]
    - 
    -     ldr         r7, [r7]                    @intra_pred_ang
    --    sub         sp, sp, #132                @ref_temp[2 * max_cu_size + 2]
    - 
    -     ldr         r8, [r8]                    @inv_ang
    -     add         r6, sp, r4 , lsl #1         @ref_temp + 2 * nt
    -@@ -562,6 +566,7 @@ core_loop_4:
    - 
    - end_loops:
    -     add         sp, sp, #132
    -+    vpop        {d8 - d15}
    -     ldmfd       sp!,{r4-r12,r15}            @reload the registers from sp
    - 
    - 
    -diff --git a/common/arm/ihevc_intra_pred_filters_luma_mode_11_to_17.s b/common/arm/ihevc_intra_pred_filters_luma_mode_11_to_17.s
    -index ec38786..336af06 100644
    ---- a/common/arm/ihevc_intra_pred_filters_luma_mode_11_to_17.s
    -+++ b/common/arm/ihevc_intra_pred_filters_luma_mode_11_to_17.s
    -@@ -84,10 +84,13 @@
    - @r2 => *pu1_dst
    - @r3 => dst_strd
    - 
    --@stack contents from #40
    -+@stack contents from #236
    - @   nt
    - @   mode
    - 
    -+.equ    nt_offset,      236
    -+.equ    mode_offset,    240
    -+
    - .text
    - .align 4
    - 
    -@@ -129,13 +132,14 @@ col_for_intra_luma_addr_4:
    - ihevc_intra_pred_luma_mode_11_to_17_a9q:
    - 
    -     stmfd       sp!, {r4-r12, r14}          @stack stores the values of the arguments
    --
    --    ldr         r4,[sp,#40]                 @loads nt
    -+    vpush       {d8 - d15}
    -+    sub         sp, sp, #132                @ref_temp[2 * max_cu_size + 1]
    -+    ldr         r4,[sp,#nt_offset]          @loads nt
    -     ldr         r7, gai4_ihevc_ang_table_addr
    - ulbl1:
    -     add         r7,r7,pc
    - 
    --    ldr         r5,[sp,#44]                 @mode (11 to 17)
    -+    ldr         r5,[sp,#mode_offset]        @mode (11 to 17)
    -     ldr         r8, gai4_ihevc_inv_ang_table_addr
    - ulbl2:
    -     add         r8,r8,pc
    -@@ -145,7 +149,6 @@ ulbl2:
    -     sub         r8, r8, #44
    - 
    -     ldr         r7, [r7]                    @intra_pred_ang
    --    sub         sp, sp, #132                @ref_temp[2 * max_cu_size + 1]
    - 
    -     ldr         r8, [r8]                    @inv_ang
    -     add         r6, sp, r4                  @ref_temp + nt
    -@@ -684,6 +687,7 @@ ulbl4:
    - 
    - end_func:
    -     add         sp, sp, #132
    -+    vpop        {d8 - d15}
    -     ldmfd       sp!,{r4-r12,r15}            @reload the registers from sp
    - 
    - 
    -diff --git a/common/arm/ihevc_intra_pred_filters_luma_mode_19_to_25.s b/common/arm/ihevc_intra_pred_filters_luma_mode_19_to_25.s
    -index af342bf..32268a2 100644
    ---- a/common/arm/ihevc_intra_pred_filters_luma_mode_19_to_25.s
    -+++ b/common/arm/ihevc_intra_pred_filters_luma_mode_19_to_25.s
    -@@ -84,10 +84,13 @@
    - @r2 => *pu1_dst
    - @r3 => dst_strd
    - 
    --@stack contents from #40
    -+@stack contents from #236
    - @   nt
    - @   mode
    - 
    -+.equ    nt_offset,      236
    -+.equ    mode_offset,    240
    -+
    - .text
    - .align 4
    - 
    -@@ -116,13 +119,15 @@ gai4_ihevc_ang_table_addr_2:
    - ihevc_intra_pred_luma_mode_19_to_25_a9q:
    - 
    -     stmfd       sp!, {r4-r12, r14}          @stack stores the values of the arguments
    -+    vpush       {d8 - d15}
    -+    sub         sp, sp, #132                @ref_temp[2 * max_cu_size + 1]
    - 
    --    ldr         r4,[sp,#40]                 @loads nt
    -+    ldr         r4,[sp,#nt_offset]          @loads nt
    -     ldr         r7, gai4_ihevc_ang_table_addr_1
    - ulbl_1:
    -     add         r7,r7,pc
    - 
    --    ldr         r5,[sp,#44]                 @mode (19 to 25)
    -+    ldr         r5,[sp,#mode_offset]        @mode (19 to 25)
    -     ldr         r8, gai4_ihevc_inv_ang_table_addr
    - ulbl1:
    -     add         r8,r8,pc
    -@@ -132,7 +137,6 @@ ulbl1:
    -     sub         r8, r8, #48                 @gai4_ihevc_inv_ang_table[mode - 12]
    - 
    -     ldr         r7, [r7]                    @intra_pred_ang
    --    sub         sp, sp, #132                @ref_temp[2 * max_cu_size + 1]
    - 
    -     ldr         r8, [r8]                    @inv_ang
    -     add         r6, sp, r4                  @ref_temp + nt
    -@@ -644,6 +648,7 @@ core_loop_4:
    - 
    - end_loops:
    -     add         sp, sp, #132
    -+    vpop        {d8 - d15}
    -     ldmfd       sp!,{r4-r12,r15}            @reload the registers from sp
    - 
    - 
    -diff --git a/common/arm/ihevc_intra_pred_luma_dc.s b/common/arm/ihevc_intra_pred_luma_dc.s
    -index f380d94..7d8cb91 100644
    ---- a/common/arm/ihevc_intra_pred_luma_dc.s
    -+++ b/common/arm/ihevc_intra_pred_luma_dc.s
    -@@ -87,11 +87,13 @@
    - @r2 => *pu1_dst
    - @r3 => dst_strd
    - 
    --@stack contents from #40
    -+@stack contents from #104
    - @   nt
    - @   mode
    - @   pi1_coeff
    - 
    -+.equ    nt_offset,      104
    -+
    - .text
    - .align 4
    - 
    -@@ -105,8 +107,8 @@
    - ihevc_intra_pred_luma_dc_a9q:
    - 
    -     stmfd       sp!, {r4-r12, r14}          @stack stores the values of the arguments
    --
    --    ldr         r4,[sp,#40]                 @loads nt
    -+    vpush       {d8 - d15}
    -+    ldr         r4,[sp,#nt_offset]          @loads nt
    - 
    - @********** testing
    -     @mov        r6, #128
    -@@ -498,6 +500,7 @@ dc_4:
    - 
    - epilogue_end:
    - end_func:
    -+    vpop        {d8 - d15}
    -     ldmfd       sp!,{r4-r12,r15}            @reload the registers from sp
    - 
    - 
    -diff --git a/common/arm/ihevc_intra_pred_luma_horz.s b/common/arm/ihevc_intra_pred_luma_horz.s
    -index 581b673..2a44404 100644
    ---- a/common/arm/ihevc_intra_pred_luma_horz.s
    -+++ b/common/arm/ihevc_intra_pred_luma_horz.s
    -@@ -84,6 +84,8 @@
    - @r2 => *pu1_dst
    - @r3 =>  dst_strd
    - 
    -+.equ    nt_offset,      104
    -+
    - .text
    - .align 4
    - 
    -@@ -97,9 +99,8 @@
    - ihevc_intra_pred_luma_horz_a9q:
    - 
    -     stmfd       sp!, {r4-r12, r14}          @stack stores the values of the arguments
    --
    --    ldr         r4,[sp,#40]                 @loads nt
    --    @ldr        r5,[sp,#44]                     @loads mode
    -+    vpush       {d8 - d15}
    -+    ldr         r4,[sp,#nt_offset]          @loads nt
    - 
    -     lsl         r6,r4,#1                    @two_nt
    - 
    -@@ -185,6 +186,7 @@ core_loop_32:
    -     vst1.8      {q4},[r2],r3
    -     vst1.8      {q4},[r9],r3
    -     bgt         core_loop_32
    -+    vpop        {d8 - d15}
    -     ldmfd       sp!,{r4-r12,r15}            @reload the registers from sp
    -     b           end_func
    - 
    -@@ -258,7 +260,7 @@ core_loop_16:
    -     vst1.8      {q5},[r2],r3
    -     vst1.8      {q6},[r2],r3
    -     vst1.8      {q7},[r2],r3
    --
    -+    vpop        {d8 - d15}
    -     ldmfd       sp!,{r4-r12,r15}            @reload the registers from sp
    -     b           end_func
    - 
    -@@ -301,6 +303,7 @@ core_loop_8:
    - 
    -     vst1.8      {d8},[r2],r3
    -     vst1.8      {d9},[r2],r3
    -+    vpop        {d8 - d15}
    -     ldmfd       sp!,{r4-r12,r15}            @reload the registers from sp
    -     b           end_func
    - 
    -@@ -331,7 +334,7 @@ core_loop_4:
    -     vst1.32     {d3[0]},[r2],r3
    -     vst1.32     {d4[0]},[r2],r3
    -     vst1.32     {d5[0]},[r2],r3
    --
    -+    vpop        {d8 - d15}
    -     ldmfd       sp!,{r4-r12,r15}            @reload the registers from sp
    - end_func:
    - 
    -diff --git a/common/arm/ihevc_intra_pred_luma_mode2.s b/common/arm/ihevc_intra_pred_luma_mode2.s
    -index cf7999b..935f02d 100644
    ---- a/common/arm/ihevc_intra_pred_luma_mode2.s
    -+++ b/common/arm/ihevc_intra_pred_luma_mode2.s
    -@@ -87,11 +87,13 @@
    - @r2 => *pu1_dst
    - @r3 => dst_strd
    - 
    --@stack contents from #40
    -+@stack contents from #104
    - @   nt
    - @   mode
    - @   pi1_coeff
    - 
    -+.equ    nt_offset,      104
    -+
    - .text
    - .align 4
    - 
    -@@ -105,8 +107,8 @@
    - ihevc_intra_pred_luma_mode2_a9q:
    - 
    -     stmfd       sp!, {r4-r12, r14}          @stack stores the values of the arguments
    --
    --    ldr         r4,[sp,#40]                 @loads nt
    -+    vpush       {d8 - d15}
    -+    ldr         r4,[sp,#nt_offset]          @loads nt
    -     mov         r8,#-2
    - 
    -     cmp         r4,#4
    -@@ -260,6 +262,7 @@ mode2_4:
    -     vst1.32     {d7[0]},[r7]
    - 
    - end_func:
    -+    vpop        {d8 - d15}
    -     ldmfd       sp!,{r4-r12,r15}            @reload the registers from sp
    - 
    - 
    -diff --git a/common/arm/ihevc_intra_pred_luma_mode_18_34.s b/common/arm/ihevc_intra_pred_luma_mode_18_34.s
    -index 438c0f5..9287371 100644
    ---- a/common/arm/ihevc_intra_pred_luma_mode_18_34.s
    -+++ b/common/arm/ihevc_intra_pred_luma_mode_18_34.s
    -@@ -92,6 +92,9 @@
    - @   mode
    - @   pi1_coeff
    - 
    -+.equ    nt_offset,      40
    -+.equ    mode_offset,    44
    -+
    - .text
    - .align 4
    - 
    -@@ -107,8 +110,8 @@ ihevc_intra_pred_luma_mode_18_34_a9q:
    -     stmfd       sp!, {r4-r12, r14}          @stack stores the values of the arguments
    - 
    - 
    --    ldr         r4,[sp,#40]
    --    ldr         r5,[sp,#44]
    -+    ldr         r4,[sp,#nt_offset]
    -+    ldr         r5,[sp,#mode_offset]
    - 
    -     cmp         r4,#4
    -     beq         mode2_4
    -diff --git a/common/arm/ihevc_intra_pred_luma_mode_27_to_33.s b/common/arm/ihevc_intra_pred_luma_mode_27_to_33.s
    -index 595d82a..9d95719 100644
    ---- a/common/arm/ihevc_intra_pred_luma_mode_27_to_33.s
    -+++ b/common/arm/ihevc_intra_pred_luma_mode_27_to_33.s
    -@@ -85,6 +85,9 @@
    - @r2 => *pu1_dst
    - @r3 =>  dst_strd
    - 
    -+.equ    nt_offset,      104
    -+.equ    mode_offset,    108
    -+
    - .text
    - .align 4
    - 
    -@@ -107,9 +110,9 @@ gau1_ihevc_planar_factor_addr:
    - ihevc_intra_pred_luma_mode_27_to_33_a9q:
    - 
    -     stmfd       sp!, {r4-r12, r14}          @stack stores the values of the arguments
    --
    --    ldr         r4,[sp,#40]                 @loads nt
    --    ldr         r5,[sp,#44]                 @loads mode
    -+    vpush       {d8 - d15}
    -+    ldr         r4,[sp,#nt_offset]          @loads nt
    -+    ldr         r5,[sp,#mode_offset]        @loads mode
    -     ldr         r6,gai4_ihevc_ang_table_addr @loads word32 gai4_ihevc_ang_table[35]
    - ulbl1:
    -     add         r6,r6,pc
    -@@ -534,6 +537,7 @@ core_loop_4:
    -     vst1.32     {d22[0]},[r2],r3
    - 
    - end_loops:
    -+    vpop        {d8 - d15}
    -     ldmfd       sp!,{r4-r12,r15}            @reload the registers from sp
    - 
    - 
    -diff --git a/common/arm/ihevc_intra_pred_luma_mode_3_to_9.s b/common/arm/ihevc_intra_pred_luma_mode_3_to_9.s
    -index a8e93c8..e9c871c 100644
    ---- a/common/arm/ihevc_intra_pred_luma_mode_3_to_9.s
    -+++ b/common/arm/ihevc_intra_pred_luma_mode_3_to_9.s
    -@@ -84,10 +84,13 @@
    - @r2 => *pu1_dst
    - @r3 => dst_strd
    - 
    --@stack contents from #40
    -+@stack contents from #104
    - @   nt
    - @   mode
    - 
    -+.equ    nt_offset,      104
    -+.equ    mode_offset,    108
    -+
    - .text
    - .align 4
    - 
    -@@ -126,13 +129,13 @@ col_for_intra_luma_addr_3:
    - ihevc_intra_pred_luma_mode_3_to_9_a9q:
    - 
    -     stmfd       sp!, {r4-r12, r14}          @stack stores the values of the arguments
    --
    --    ldr         r4,[sp,#40]                 @loads nt
    -+    vpush       {d8 - d15}
    -+    ldr         r4,[sp,#nt_offset]          @loads nt
    -     ldr         r7, gai4_ihevc_ang_table_addr
    - ulbl1:
    -     add         r7,r7,pc
    - 
    --    ldr         r5,[sp,#44]                 @mode (3 to 9)
    -+    ldr         r5,[sp,#mode_offset]        @mode (3 to 9)
    -     ldr         r8, gai4_ihevc_inv_ang_table_addr
    - ulbl2:
    -     add         r8,r8,pc
    -@@ -566,6 +569,7 @@ ulbl3_2:
    -     vst1.32     d18[0], [r2], r3            @st (row 3)
    - 
    - end_func:
    -+    vpop        {d8 - d15}
    -     ldmfd       sp!,{r4-r12,r15}            @reload the registers from sp
    - 
    - 
    -diff --git a/common/arm/ihevc_intra_pred_luma_planar.s b/common/arm/ihevc_intra_pred_luma_planar.s
    -index 666798e..50b6b1b 100644
    ---- a/common/arm/ihevc_intra_pred_luma_planar.s
    -+++ b/common/arm/ihevc_intra_pred_luma_planar.s
    -@@ -87,11 +87,13 @@
    - @r2 => *pu1_dst
    - @r3 => dst_strd
    - 
    --@stack contents from #40
    -+@stack contents from #104
    - @   nt
    - @   mode
    - @   pi1_coeff
    - 
    -+.equ    nt_offset,      104
    -+
    - .text
    - .align 4
    - 
    -@@ -114,8 +116,8 @@ gau1_ihevc_planar_factor_1_addr:
    - ihevc_intra_pred_luma_planar_a9q:
    - 
    -     stmfd       sp!, {r4-r12, r14}          @stack stores the values of the arguments
    --
    --    ldr         r4,[sp,#40]                 @loads nt
    -+    vpush       {d8 - d15}
    -+    ldr         r4,[sp,#nt_offset]          @loads nt
    -     ldr         r11, gau1_ihevc_planar_factor_addr @loads table of coeffs
    - ulbl1:
    -     add         r11,r11,pc
    -@@ -546,6 +548,7 @@ loop_sz_4:
    -     bne         loop_sz_4
    - 
    - end_loop:
    -+    vpop        {d8 - d15}
    -     ldmfd       sp!,{r4-r12,r15}            @reload the registers from sp
    - 
    - 
    -diff --git a/common/arm/ihevc_intra_pred_luma_vert.s b/common/arm/ihevc_intra_pred_luma_vert.s
    -index 5eeaeb3..9610773 100644
    ---- a/common/arm/ihevc_intra_pred_luma_vert.s
    -+++ b/common/arm/ihevc_intra_pred_luma_vert.s
    -@@ -84,10 +84,12 @@
    - @r2 => *pu1_dst
    - @r3 => dst_strd
    - 
    --@stack contents from #40
    -+@stack contents from #104
    - @   nt
    - @   mode
    - 
    -+.equ    nt_offset,      104
    -+
    - .text
    - .align 4
    - 
    -@@ -101,8 +103,8 @@
    - ihevc_intra_pred_luma_ver_a9q:
    - 
    -     stmfd       sp!, {r4-r12, r14}          @stack stores the values of the arguments
    --
    --    ldr         r4,[sp,#40]                 @loads nt
    -+    vpush       {d8 - d15}
    -+    ldr         r4,[sp,#nt_offset]          @loads nt
    - 
    -     lsl         r5, r4, #1                  @2nt
    - 
    -@@ -417,5 +419,6 @@ blk_4:
    - 
    - 
    - end_func:
    -+    vpop        {d8 - d15}
    -     ldmfd       sp!,{r4-r12,r15}            @reload the registers from sp
    - 
    -diff --git a/common/arm/ihevc_itrans_recon_16x16.s b/common/arm/ihevc_itrans_recon_16x16.s
    -index 82055ad..198fd52 100644
    ---- a/common/arm/ihevc_itrans_recon_16x16.s
    -+++ b/common/arm/ihevc_itrans_recon_16x16.s
    -@@ -105,6 +105,12 @@
    - @   r12
    - @   r11
    - 
    -+.equ    src_stride_offset,     104
    -+.equ    pred_stride_offset,    108
    -+.equ    out_stride_offset,     112
    -+.equ    zero_cols_offset,      116
    -+.equ    zero_rows_offset,      120
    -+
    - .text
    - .align 4
    - 
    -@@ -129,15 +135,10 @@ g_ai2_ihevc_trans_16_transpose_addr:
    - ihevc_itrans_recon_16x16_a9q:
    - 
    -     stmfd       sp!,{r4-r12,lr}
    --@   add             sp,sp,#40
    --
    --
    --
    --@   ldr         r8,[sp,#4]  @ prediction stride
    --@   ldr         r7,[sp,#8]  @ destination stride
    --    ldr         r6,[sp,#40]                 @ src stride
    --    ldr         r12,[sp,#52]
    --    ldr         r11,[sp,#56]
    -+    vpush       {d8  -  d15}
    -+    ldr         r6,[sp,#src_stride_offset]  @ src stride
    -+    ldr         r12,[sp,#zero_cols_offset]
    -+    ldr         r11,[sp,#zero_rows_offset]
    - 
    - 
    - 
    -@@ -661,8 +662,8 @@ skip_last12rows_kernel2:
    - 
    -     mov         r6,r7
    - 
    --    ldr         r8,[sp,#44]                 @ prediction stride
    --    ldr         r7,[sp,#48]                 @ destination stride
    -+    ldr         r8,[sp,#pred_stride_offset] @ prediction stride
    -+    ldr         r7,[sp,#out_stride_offset]  @ destination stride
    - 
    -     mov         r10,#16
    - 
    -@@ -1126,7 +1127,7 @@ skip_last8rows_stage2_kernel2:
    -     bne         second_stage
    - 
    - 
    --@   sub         sp,sp,#40
    -+    vpop        {d8  -  d15}
    -     ldmfd       sp!,{r4-r12,pc}
    - 
    - 
    -diff --git a/common/arm/ihevc_itrans_recon_32x32.s b/common/arm/ihevc_itrans_recon_32x32.s
    -index eeb1d66..65b6ffd 100644
    ---- a/common/arm/ihevc_itrans_recon_32x32.s
    -+++ b/common/arm/ihevc_itrans_recon_32x32.s
    -@@ -124,6 +124,14 @@
    - @d5[2]= 43      d7[2]=9
    - @d5[3]= 38      d7[3]=4
    - 
    -+.equ    pi2_src_offset,     64
    -+.equ    pi2_tmp_offset,     68
    -+.equ    src_strd_offset,    120
    -+.equ    pred_strd_offset,   124
    -+.equ    dst_strd_offset,    128
    -+.equ    zero_cols_offset,   132
    -+.equ    zero_rows_offset,   136
    -+
    - .text
    - .align 4
    - 
    -@@ -152,13 +160,11 @@ r9_addr: .word 0xffff0000
    - ihevc_itrans_recon_32x32_a9q:
    - 
    -     stmfd       sp!,{r0-r12,lr}
    -+    vpush       {d8  -  d15}
    - 
    --
    --@ldr            r8,[sp,#56]     @ prediction stride
    --@ldr            r7,[sp,#64]     @ destination stride
    --    ldr         r6,[sp,#56]                 @ src stride
    --    ldr         r12,[sp,#68]
    --    ldr         r11,[sp,#72]
    -+    ldr         r6,[sp,#src_strd_offset]    @ src stride
    -+    ldr         r12,[sp,#zero_cols_offset]
    -+    ldr         r11,[sp,#zero_rows_offset]
    -     mov         r6,r6,lsl #1                @ x sizeof(word16)
    -     add         r10,r6,r6, lsl #1           @ 3 rows
    - 
    -@@ -1493,10 +1499,10 @@ shift4:
    -     bne         dct_stage1
    - second_stage_dct:
    - @   mov     r0,r1
    --    ldr         r0,[sp]
    --    ldr         r1,[sp,#4]
    --    ldr         r8,[sp,#60]                 @ prediction stride
    --    ldr         r7,[sp,#64]                 @ destination stride
    -+    ldr         r0,[sp,#pi2_src_offset]
    -+    ldr         r1,[sp,#pi2_tmp_offset]
    -+    ldr         r8,[sp,#pred_strd_offset]   @ prediction stride
    -+    ldr         r7,[sp,#dst_strd_offset]    @ destination stride
    - 
    - @   add r4,r2,r8, lsl #1    @ r4 = r2 + pred_strd * 2    => r4 points to 3rd row of pred data
    - @   add r5,r8,r8, lsl #1    @
    -@@ -2855,6 +2861,7 @@ prediction_buffer:
    - 
    -     subs        r14,r14,#1
    -     bne         dct_stage2
    -+    vpop        {d8  -  d15}
    -     ldmfd       sp!,{r0-r12,pc}
    - 
    - 
    -diff --git a/common/arm/ihevc_itrans_recon_4x4.s b/common/arm/ihevc_itrans_recon_4x4.s
    -index c955502..fb5796c 100644
    ---- a/common/arm/ihevc_itrans_recon_4x4.s
    -+++ b/common/arm/ihevc_itrans_recon_4x4.s
    -@@ -100,6 +100,10 @@
    - @   r6 => dst_strd
    - @   r7 => zero_cols
    - 
    -+.equ    src_strd_offset,    104
    -+.equ    pred_strd_offset,   108
    -+.equ    dst_strd_offset,    112
    -+.equ    zero_cols_offset,   116
    - 
    - .text
    - .align 4
    -@@ -122,17 +126,18 @@ g_ai2_ihevc_trans_4_transpose_addr:
    - ihevc_itrans_recon_4x4_a9q:
    - 
    -     stmfd       sp!, {r4-r12, r14}          @stack stores the values of the arguments
    -+    vpush       {d8  -  d15}
    - 
    -     ldr         r8,g_ai2_ihevc_trans_4_transpose_addr
    - ulbl1:
    -     add         r8,r8,pc
    - 
    --    ldr         r4,[sp,#40]                 @loading src_strd
    --    ldr         r5,[sp,#44]                 @loading pred_strd
    -+    ldr         r4,[sp,#src_strd_offset]    @loading src_strd
    -+    ldr         r5,[sp,#pred_strd_offset]   @loading pred_strd
    -     add         r4,r4,r4                    @ src_strd in terms of word16
    - 
    --    ldr         r6,[sp,#48]                 @loading dst_strd
    --    ldr         r7,[sp,#52]                 @loading zero_cols
    -+    ldr         r6,[sp,#dst_strd_offset]    @loading dst_strd
    -+    ldr         r7,[sp,#zero_cols_offset]   @loading zero_cols
    -     add         r9,r0,r4                    @ pi2_src[0] + src_strd
    - 
    - 
    -@@ -223,7 +228,7 @@ ulbl1:
    -     vst1.32     {d1[0]},[r3],r6
    -     vst1.32     {d1[1]},[r3],r6
    - 
    --
    -+    vpop        {d8  -  d15}
    -     ldmfd       sp!,{r4-r12,r15}            @reload the registers from sp
    - 
    - 
    -diff --git a/common/arm/ihevc_itrans_recon_4x4_ttype1.s b/common/arm/ihevc_itrans_recon_4x4_ttype1.s
    -index ab65dae..82ed8a0 100644
    ---- a/common/arm/ihevc_itrans_recon_4x4_ttype1.s
    -+++ b/common/arm/ihevc_itrans_recon_4x4_ttype1.s
    -@@ -103,6 +103,11 @@
    - @   r6 => dst_strd
    - @   r7 => zero_cols
    - 
    -+.equ    src_strd_offset,    104
    -+.equ    pred_strd_offset,   108
    -+.equ    dst_strd_offset,    112
    -+.equ    zero_cols_offset,   116
    -+
    - .text
    - .align 4
    - 
    -@@ -119,10 +124,12 @@
    - ihevc_itrans_recon_4x4_ttype1_a9q:
    - 
    -     stmfd       sp!, {r4-r12, r14}          @stack stores the values of the arguments
    --    ldr         r4,[sp,#40]                 @loading src_strd
    --    ldr         r5,[sp,#44]                 @loading pred_strd
    --    ldr         r6,[sp,#48]                 @loading dst_strd
    --    ldr         r7,[sp,#52]                 @loading zero_cols
    -+    vpush       {d8  -  d15}
    -+
    -+    ldr         r4,[sp,#src_strd_offset]    @loading src_strd
    -+    ldr         r5,[sp,#pred_strd_offset]   @loading pred_strd
    -+    ldr         r6,[sp,#dst_strd_offset]    @loading dst_strd
    -+    ldr         r7,[sp,#zero_cols_offset]   @loading zero_cols
    - 
    -     add         r4,r4,r4                    @ src_strd in terms of word16
    - 
    -@@ -224,6 +231,7 @@ ihevc_itrans_recon_4x4_ttype1_a9q:
    -     vst1.32     {d1[0]},[r3],r6
    -     vst1.32     {d1[1]},[r3],r6
    - 
    -+    vpop        {d8  -  d15}
    -     ldmfd       sp!,{r4-r12,r15}            @reload the registers from sp
    - 
    - 
    -diff --git a/common/arm/ihevc_itrans_recon_8x8.s b/common/arm/ihevc_itrans_recon_8x8.s
    -index e9b53b4..94113d8 100644
    ---- a/common/arm/ihevc_itrans_recon_8x8.s
    -+++ b/common/arm/ihevc_itrans_recon_8x8.s
    -@@ -104,6 +104,11 @@
    - @   dst_strd
    - @   zero_cols
    - 
    -+.equ    src_stride_offset,     104
    -+.equ    pred_stride_offset,    108
    -+.equ    out_stride_offset,     112
    -+.equ    zero_cols_offset,      116
    -+.equ    zero_rows_offset,      120
    - 
    - 
    - .text
    -@@ -151,12 +156,13 @@ ihevc_itrans_recon_8x8_a9q:
    -     @// copy the input pointer to another register
    -     @// step 1 : load all constants
    -     stmfd       sp!,{r4-r12,lr}
    -+    vpush       {d8  -  d15}
    - 
    --    ldr         r8,[sp,#44]                  @ prediction stride
    --    ldr         r7,[sp,#48]                  @ destination stride
    --    ldr         r6,[sp, #40]                     @ src stride
    --    ldr         r12,[sp,#52]
    --    ldr         r11,[sp,#56]
    -+    ldr         r8, [sp, #pred_stride_offset]    @ prediction stride
    -+    ldr         r7, [sp, #out_stride_offset]     @ destination stride
    -+    ldr         r6, [sp, #src_stride_offset]     @ src stride
    -+    ldr         r12, [sp, #zero_cols_offset]
    -+    ldr         r11, [sp, #zero_rows_offset]
    -     mov         r6,r6,lsl #1                @ x sizeof(word16)
    -     add         r9,r0,r6, lsl #1            @ 2 rows
    - 
    -@@ -925,7 +931,7 @@ pred_buff_addition:
    - 
    - 
    - 
    --
    -+    vpop        {d8  -  d15}
    -     ldmfd       sp!,{r4-r12,pc}
    - 
    - 
    -diff --git a/common/arm/ihevc_sao_band_offset_chroma.s b/common/arm/ihevc_sao_band_offset_chroma.s
    -index 32e149d..a9da725 100644
    ---- a/common/arm/ihevc_sao_band_offset_chroma.s
    -+++ b/common/arm/ihevc_sao_band_offset_chroma.s
    -@@ -61,6 +61,14 @@
    - @r9 =>  wd
    - @r10=>  ht
    - 
    -+.equ    pu1_src_top_left_offset,    104
    -+.equ    sao_band_pos_u_offset,      108
    -+.equ    sao_band_pos_v_offset,      112
    -+.equ    pi1_sao_u_offset,           116
    -+.equ    pi1_sao_v_offset,           120
    -+.equ    wd_offset,                  124
    -+.equ    ht_offset,                  128
    -+
    - .text
    - .p2align 2
    - 
    -@@ -76,10 +84,11 @@ gu1_table_band_idx_addr_2:
    - ihevc_sao_band_offset_chroma_a9q:
    - 
    -     STMFD       sp!, {r4-r12, r14}          @stack stores the values of the arguments
    --    LDR         r4,[sp,#40]                 @Loads pu1_src_top_left
    --    LDR         r10,[sp,#64]                @Loads ht
    -+    vpush       {d8  -  d15}
    -+    LDR         r4,[sp,#pu1_src_top_left_offset]    @Loads pu1_src_top_left
    -+    LDR         r10,[sp,#ht_offset]         @Loads ht
    - 
    --    LDR         r9,[sp,#60]                 @Loads wd
    -+    LDR         r9,[sp,#wd_offset]          @Loads wd
    -     MOV         r11,r10                     @Move the ht to r9 for loop counter
    - 
    -     ADD         r12,r0,r9                   @pu1_src[row * src_strd + (wd)]
    -@@ -94,7 +103,7 @@ SRC_LEFT_LOOP:
    -     STRH        r5,[r2],#2                  @Store the value in pu1_src_left pointer
    -     BNE         SRC_LEFT_LOOP
    - 
    --    LDR         r5,[sp,#44]                 @Loads sao_band_pos_u
    -+    LDR         r5,[sp,#sao_band_pos_u_offset]  @Loads sao_band_pos_u
    -     VLD1.8      D1,[r14]!                   @band_table_u.val[0]
    -     ADD         r12,r3,r9                   @pu1_src_top[wd]
    - 
    -@@ -104,7 +113,7 @@ SRC_LEFT_LOOP:
    - 
    -     STRH        r11,[r4]                    @store to pu1_src_top_left[0]
    -     VLD1.8      D3,[r14]!                   @band_table_u.val[2]
    --    LDR         r7,[sp,#52]                 @Loads pi1_sao_offset_u
    -+    LDR         r7,[sp,#pi1_sao_u_offset]   @Loads pi1_sao_offset_u
    - 
    -     SUB         r4,r10,#1                   @ht-1
    -     VDUP.8      D31,r6                      @band_pos_u
    -@@ -147,7 +156,7 @@ ulbl2:
    -     VLD1.8      D10,[r14]!                  @band_table_v.val[1]
    -     VADD.I8     D3,D7,D27                   @band_table_u.val[2] = vadd_u8(band_table_u.val[2], vdup_n_u8(pi1_sao_offset_u[3]))
    - 
    --    LDR         r6,[sp,#48]                 @Loads sao_band_pos_v
    -+    LDR         r6,[sp,#sao_band_pos_v_offset]  @Loads sao_band_pos_v
    -     VADD.I8     D4,D8,D26                   @band_table_u.val[3] = vadd_u8(band_table_u.val[3], vdup_n_u8(pi1_sao_offset_u[4]))
    -     LSL         r11,r6,#3                   @sao_band_pos_v
    - 
    -@@ -198,7 +207,7 @@ SAO_BAND_POS_U_0:
    - 
    - SWITCH_BREAK_U:
    -     VDUP.8      D30,r11                     @band_pos_v
    --    LDR         r8,[sp,#56]                 @Loads pi1_sao_offset_v
    -+    LDR         r8,[sp,#pi1_sao_v_offset]   @Loads pi1_sao_offset_v
    - 
    -     VLD1.8      D11,[r14]!                  @band_table_v.val[2]
    -     VADD.I8     D13,D9,D30                  @band_table_v.val[0] = vadd_u8(band_table_v.val[0], band_pos_v)
    -@@ -387,6 +396,7 @@ WIDTH_RESIDUE:                              @If width is not multiple of 16
    -     BNE         WIDTH_RESIDUE
    - 
    - END_LOOP:
    -+    vpop        {d8  -  d15}
    -     LDMFD       sp!,{r4-r12,r15}            @Reload the registers from SP
    - 
    - 
    -diff --git a/common/arm/ihevc_sao_band_offset_luma.s b/common/arm/ihevc_sao_band_offset_luma.s
    -index 3875377..66f2968 100644
    ---- a/common/arm/ihevc_sao_band_offset_luma.s
    -+++ b/common/arm/ihevc_sao_band_offset_luma.s
    -@@ -57,6 +57,12 @@
    - @r7 =>  wd
    - @r8 =>  ht
    - 
    -+.equ    pu1_src_top_left_offset,    104
    -+.equ    sao_band_pos_offset,        108
    -+.equ    pi1_sao_offset,             112
    -+.equ    wd_offset,                  116
    -+.equ    ht_offset,                  120
    -+
    - .text
    - .p2align 2
    - 
    -@@ -69,15 +75,16 @@ gu1_table_band_idx_addr:
    - ihevc_sao_band_offset_luma_a9q:
    - 
    -     STMFD       sp!, {r4-r12, r14}          @stack stores the values of the arguments
    -+    vpush       {d8  -  d15}
    - 
    --    LDR         r8,[sp,#56]                 @Loads ht
    --    LDR         r7,[sp,#52]                 @Loads wd
    -+    LDR         r8,[sp,#ht_offset]          @Loads ht
    -+    LDR         r7,[sp,#wd_offset]          @Loads wd
    - 
    -     MOV         r9,r8                       @Move the ht to r9 for loop counter
    --    LDR         r5,[sp,#44]                 @Loads sao_band_pos
    -+    LDR         r5,[sp,#sao_band_pos_offset]    @Loads sao_band_pos
    -     ADD         r10,r0,r7                   @pu1_src[row * src_strd + (wd)]
    - 
    --    LDR         r4,[sp,#40]                 @Loads pu1_src_top_left
    -+    LDR         r4,[sp,#pu1_src_top_left_offset]    @Loads pu1_src_top_left
    -     SUB         r10,r10,#1                  @wd-1
    -     LDR         r14, gu1_table_band_idx_addr
    - ulbl1:
    -@@ -91,7 +98,7 @@ SRC_LEFT_LOOP:
    - 
    -     ADD         r9,r3,r7                    @pu1_src_top[wd]
    -     VLD1.8      D1,[r14]!                   @band_table.val[0]
    --    LDR         r6,[sp,#48]                 @Loads pi1_sao_offset
    -+    LDR         r6,[sp,#pi1_sao_offset]     @Loads pi1_sao_offset
    - 
    -     LSL         r11,r5,#3
    -     VLD1.8      D2,[r14]!                   @band_table.val[1]
    -@@ -226,6 +233,7 @@ HEIGHT_LOOP:
    -     ADD         r0,r0,#8
    -     BNE         SWITCH_BREAK
    - 
    -+    vpop        {d8  -  d15}
    -     LDMFD       sp!,{r4-r12,r15}            @Reload the registers from SP
    - 
    - 
    -diff --git a/common/arm/ihevc_sao_edge_offset_class0.s b/common/arm/ihevc_sao_edge_offset_class0.s
    -index a9fe046..e4bb455 100644
    ---- a/common/arm/ihevc_sao_edge_offset_class0.s
    -+++ b/common/arm/ihevc_sao_edge_offset_class0.s
    -@@ -59,6 +59,14 @@
    - @r9 =>  wd
    - @r10=>  ht
    - 
    -+.equ    pu1_src_top_left_offset,    104
    -+.equ    pu1_src_top_right_offset,   108
    -+.equ    pu1_src_bot_left_offset,    112
    -+.equ    pu1_avail_offset,           116
    -+.equ    pi1_sao_offset,             120
    -+.equ    wd_offset,                  124
    -+.equ    ht_offset,                  128
    -+
    - .text
    - .p2align 2
    - 
    -@@ -72,23 +80,25 @@ ihevc_sao_edge_offset_class0_a9q:
    - 
    - 
    -     STMFD       sp!, {r4-r12, r14}          @stack stores the values of the arguments
    --    LDR         r9,[sp,#60]                 @Loads wd
    -+    vpush       {d8  -  d15}
    -+
    -+    LDR         r9,[sp,#wd_offset]          @Loads wd
    - 
    --    LDR         r4,[sp,#40]                 @Loads pu1_src_top_left
    -+    LDR         r4,[sp,#pu1_src_top_left_offset]    @Loads pu1_src_top_left
    -     VMOV.I8     Q1,#2                       @const_2 = vdupq_n_s8(2)
    -     ADD         r11,r3,r9                   @pu1_src_top[wd]
    - 
    --    LDR         r10,[sp,#64]                @Loads ht
    -+    LDR         r10,[sp,#ht_offset]         @Loads ht
    -     VMOV.I16    Q2,#0                       @const_min_clip = vdupq_n_s16(0)
    -     LDRB        r12,[r11,#-1]               @pu1_src_top[wd - 1]
    - 
    --    LDR         r7,[sp,#52]                 @Loads pu1_avail
    -+    LDR         r7,[sp,#pu1_avail_offset]   @Loads pu1_avail
    -     VMOV.I16    Q3,#255                     @const_max_clip = vdupq_n_u16((1 << bit_depth) - 1)
    -     LDR         r14, gi1_table_edge_idx_addr @table pointer
    - ulbl1:
    -     add         r14,r14,pc
    - 
    --    LDR         r8,[sp,#56]                 @Loads pi1_sao_offset
    -+    LDR         r8,[sp,#pi1_sao_offset]     @Loads pi1_sao_offset
    -     VMOV.S8     Q4,#0xFF                    @au1_mask = vdupq_n_s8(-1)
    -     STRB        r12,[r4]                    @*pu1_src_top_left = pu1_src_top[wd - 1]
    - 
    -@@ -337,6 +347,7 @@ PU1_SRC_LOOP_RESIDUE:
    -     BNE         PU1_SRC_LOOP_RESIDUE        @If not equal jump to the pu1_src loop
    - 
    - END_LOOPS:
    -+    vpop        {d8  -  d15}
    -     LDMFD       sp!,{r4-r12,r15}            @Reload the registers from SP
    - 
    - 
    -diff --git a/common/arm/ihevc_sao_edge_offset_class0_chroma.s b/common/arm/ihevc_sao_edge_offset_class0_chroma.s
    -index 1dd56f6..e11cd4f 100644
    ---- a/common/arm/ihevc_sao_edge_offset_class0_chroma.s
    -+++ b/common/arm/ihevc_sao_edge_offset_class0_chroma.s
    -@@ -60,6 +60,15 @@
    - @r9 =>  wd
    - @r10=>  ht
    - 
    -+.equ    pu1_src_top_left_offset,    104
    -+.equ    pu1_src_top_right_offset,   108
    -+.equ    pu1_src_bot_left_offset,    112
    -+.equ    pu1_avail_offset,           116
    -+.equ    pi1_sao_u_offset,           120
    -+.equ    pi1_sao_v_offset,           124
    -+.equ    wd_offset,                  128
    -+.equ    ht_offset,                  132
    -+
    - .text
    - .p2align 2
    - 
    -@@ -73,20 +82,22 @@ ihevc_sao_edge_offset_class0_chroma_a9q:
    - 
    - 
    -     STMFD       sp!, {r4-r12, r14}          @stack stores the values of the arguments
    --    LDR         r9,[sp,#64]                 @Loads wd
    -+    vpush       {d8  -  d15}
    -+
    -+    LDR         r9,[sp,#wd_offset]          @Loads wd
    - 
    --    LDR         r4,[sp,#40]                 @Loads pu1_src_top_left
    -+    LDR         r4,[sp,#pu1_src_top_left_offset]    @Loads pu1_src_top_left
    -     ADD         r11,r3,r9                   @pu1_src_top[wd]
    - 
    --    LDR         r10,[sp,#68]                @Loads ht
    -+    LDR         r10,[sp,#ht_offset]         @Loads ht
    -     VMOV.I8     Q1,#2                       @const_2 = vdupq_n_s8(2)
    -     LDRH        r12,[r11,#-2]               @pu1_src_top[wd - 1]
    - 
    --    LDR         r7,[sp,#52]                 @Loads pu1_avail
    -+    LDR         r7,[sp,#pu1_avail_offset]   @Loads pu1_avail
    -     VMOV.I16    Q2,#0                       @const_min_clip = vdupq_n_s16(0)
    -     STRH        r12,[r4]                    @*pu1_src_top_left = pu1_src_top[wd - 1]
    - 
    --    LDR         r8,[sp,#56]                 @Loads pi1_sao_offset_u
    -+    LDR         r8,[sp,#pi1_sao_u_offset]   @Loads pi1_sao_offset_u
    -     VMOV.I16    Q3,#255                     @const_max_clip = vdupq_n_u16((1 << bit_depth) - 1)
    -     SUB         r4,r10,#1                   @(ht - 1)
    - 
    -@@ -96,7 +107,7 @@ ulbl1:
    -     VMOV.S8     Q4,#0xFF                    @au1_mask = vdupq_n_s8(-1)
    -     MUL         r4,r4,r1                    @(ht - 1) * src_strd
    - 
    --    LDR         r5,[sp,#60]                 @Loads pi1_sao_offset_v
    -+    LDR         r5,[sp,#pi1_sao_v_offset]   @Loads pi1_sao_offset_v
    -     VLD1.8      D11,[r8]                    @offset_tbl = vld1_s8(pi1_sao_offset_u)
    -     ADD         r4,r4,r0                    @pu1_src[(ht - 1) * src_strd]
    - 
    -@@ -423,6 +434,7 @@ PU1_SRC_LOOP_RESIDUE:
    -     BNE         PU1_SRC_LOOP_RESIDUE        @If not equal jump to the pu1_src loop
    - 
    - END_LOOPS:
    -+    vpop        {d8  -  d15}
    -     LDMFD       sp!,{r4-r12,r15}            @Reload the registers from SP
    - 
    - 
    -diff --git a/common/arm/ihevc_sao_edge_offset_class1.s b/common/arm/ihevc_sao_edge_offset_class1.s
    -index aa1337f..029ac46 100644
    ---- a/common/arm/ihevc_sao_edge_offset_class1.s
    -+++ b/common/arm/ihevc_sao_edge_offset_class1.s
    -@@ -58,6 +58,14 @@
    - @r7 =>  wd
    - @r8 =>  ht
    - 
    -+.equ    pu1_src_top_left_offset,    104
    -+.equ    pu1_src_top_right_offset,   108
    -+.equ    pu1_src_bot_left_offset,    112
    -+.equ    pu1_avail_offset,           116
    -+.equ    pi1_sao_offset,             120
    -+.equ    wd_offset,                  124
    -+.equ    ht_offset,                  128
    -+
    - .text
    - .p2align 2
    - 
    -@@ -71,11 +79,13 @@ ihevc_sao_edge_offset_class1_a9q:
    - 
    - 
    -     STMFD       sp!, {r4-r12, r14}          @stack stores the values of the arguments
    --    LDR         r7,[sp,#60]                 @Loads wd
    --    LDR         r4,[sp,#40]                 @Loads pu1_src_top_left
    --    LDR         r5,[sp,#52]                 @Loads pu1_avail
    --    LDR         r6,[sp,#56]                 @Loads pi1_sao_offset
    --    LDR         r8,[sp,#64]                 @Loads ht
    -+    vpush       {d8  -  d15}
    -+
    -+    LDR         r7,[sp,#wd_offset]               @Loads wd
    -+    LDR         r4,[sp,#pu1_src_top_left_offset] @Loads pu1_src_top_left
    -+    LDR         r5,[sp,#pu1_avail_offset]        @Loads pu1_avail
    -+    LDR         r6,[sp,#pi1_sao_offset]          @Loads pi1_sao_offset
    -+    LDR         r8,[sp,#ht_offset]               @Loads ht
    - 
    -     SUB         r9,r7,#1                    @wd - 1
    -     LDRB        r10,[r3,r9]                 @pu1_src_top[wd - 1]
    -@@ -362,6 +372,7 @@ PU1_SRC_LOOP_RESIDUE:
    -     VST1.8      {D30},[r10],r1              @vst1q_u8(pu1_src_cpy, pu1_cur_row)
    - 
    - END_LOOPS:
    -+    vpop        {d8  -  d15}
    -     LDMFD       sp!,{r4-r12,r15}            @Reload the registers from SP
    - 
    - 
    -diff --git a/common/arm/ihevc_sao_edge_offset_class1_chroma.s b/common/arm/ihevc_sao_edge_offset_class1_chroma.s
    -index 09d925f..b377220 100644
    ---- a/common/arm/ihevc_sao_edge_offset_class1_chroma.s
    -+++ b/common/arm/ihevc_sao_edge_offset_class1_chroma.s
    -@@ -60,6 +60,15 @@
    - @r8 =>  wd
    - @r9 =>  ht
    - 
    -+.equ    pu1_src_top_left_offset,    104
    -+.equ    pu1_src_top_right_offset,   108
    -+.equ    pu1_src_bot_left_offset,    112
    -+.equ    pu1_avail_offset,           116
    -+.equ    pi1_sao_u_offset,           120
    -+.equ    pi1_sao_v_offset,           124
    -+.equ    wd_offset,                  128
    -+.equ    ht_offset,                  132
    -+
    - .text
    - .p2align 2
    - 
    -@@ -73,13 +82,13 @@ ihevc_sao_edge_offset_class1_chroma_a9q:
    - 
    - 
    -     STMFD       sp!, {r4-r12, r14}          @stack stores the values of the arguments
    --    LDR         r7,[sp,#60]                 @Loads wd
    --    LDR         r4,[sp,#40]                 @Loads pu1_src_top_left
    --    LDR         r5,[sp,#52]                 @Loads pu1_avail
    --    LDR         r6,[sp,#56]                 @Loads pi1_sao_offset_u
    --    LDR         r7,[sp,#60]                 @Loads pi1_sao_offset_v
    --    LDR         r8,[sp,#64]                 @Loads wd
    --    LDR         r9,[sp,#68]                 @Loads ht
    -+    vpush       {d8  -  d15}
    -+    LDR         r4,[sp,#pu1_src_top_left_offset]    @Loads pu1_src_top_left
    -+    LDR         r5,[sp,#pu1_avail_offset]   @Loads pu1_avail
    -+    LDR         r6,[sp,#pi1_sao_u_offset]   @Loads pi1_sao_offset_u
    -+    LDR         r7,[sp,#pi1_sao_v_offset]   @Loads pi1_sao_offset_v
    -+    LDR         r8,[sp,#wd_offset]          @Loads wd
    -+    LDR         r9,[sp,#ht_offset]          @Loads ht
    - 
    -     SUB         r10,r8,#2                   @wd - 2
    -     LDRH        r11,[r3,r10]                @pu1_src_top[wd - 2]
    -@@ -398,6 +407,7 @@ PU1_SRC_LOOP_RESIDUE:
    -     VST1.8      {D30},[r10],r1              @vst1q_u8(pu1_src_cpy, pu1_cur_row)
    - 
    - END_LOOPS:
    -+    vpop        {d8  -  d15}
    -     LDMFD       sp!,{r4-r12,r15}            @Reload the registers from SP
    - 
    - 
    -diff --git a/common/arm/ihevc_sao_edge_offset_class2.s b/common/arm/ihevc_sao_edge_offset_class2.s
    -index 536f941..15d6efa 100644
    ---- a/common/arm/ihevc_sao_edge_offset_class2.s
    -+++ b/common/arm/ihevc_sao_edge_offset_class2.s
    -@@ -58,6 +58,14 @@
    - @r7 =>  wd
    - @r8=>   ht
    - 
    -+.equ    pu1_src_top_left_offset,    264
    -+.equ    pu1_src_top_right_offset,   268
    -+.equ    pu1_src_bot_left_offset,    272
    -+.equ    pu1_avail_offset,           276
    -+.equ    pi1_sao_offset,             280
    -+.equ    wd_offset,                  284
    -+.equ    ht_offset,                  288
    -+
    - .text
    - .syntax unified
    - .p2align 2
    -@@ -78,28 +86,29 @@ ihevc_sao_edge_offset_class2_a9q:
    - 
    - 
    -     STMFD       sp!,{r4-r12,r14}            @stack stores the values of the arguments
    --    LDR         r7,[sp,#0x3C]               @Loads wd
    -+    vpush       {d8  -  d15}
    -+    SUB         sp,sp,#160                  @Decrement the stack pointer to store some temp arr values
    - 
    --    LDR         r8,[sp,#0x40]               @Loads ht
    -+    LDR         r7,[sp,#wd_offset]          @Loads wd
    -+    LDR         r8,[sp,#ht_offset]          @Loads ht
    -     SUB         r9,r7,#1                    @wd - 1
    - 
    --    LDR         r4,[sp,#0x28]               @Loads pu1_src_top_left
    -+    LDR         r4,[sp,#pu1_src_top_left_offset]    @Loads pu1_src_top_left
    -     LDRB        r10,[r3,r9]                 @pu1_src_top[wd - 1]
    - 
    --    STR         r0,[sp,#0x2C]               @Store pu1_src in sp
    -+    STR         r0,[sp,#152]                @Store pu1_src in sp
    -     MOV         r9,r7                       @Move width to r9 for loop count
    - 
    --    STR         r2,[sp,#0x30]               @Store pu1_src_left in sp
    --    LDR         r5,[sp,#0x34]               @Loads pu1_avail
    --    LDR         r6,[sp,#0x38]               @Loads pi1_sao_offset
    --    STR         r3,[sp,#0x38]               @Store pu1_src_top in sp
    -+    STR         r2,[sp,#156]                @Store pu1_src_left in sp
    -+    LDR         r5,[sp,#pu1_avail_offset]   @Loads pu1_avail
    -+    LDR         r6,[sp,#pi1_sao_offset]     @Loads pi1_sao_offset
    -+    STR         r3,[sp,#148]                @Store pu1_src_top in sp
    - 
    --    SUB         sp,sp,#0x94                 @Decrement the stack pointer to store some temp arr values
    - 
    -     STRB        r10,[sp]                    @u1_src_top_left_tmp = pu1_src_top[wd - 1]
    -     SUB         r10,r8,#1                   @ht-1
    -     MLA         r11,r10,r1,r0               @pu1_src[(ht - 1) * src_strd + col]
    --    ADD         r12,sp,#0x02                @temp array
    -+    ADD         r12,sp,#2                   @temp array
    - 
    - AU1_SRC_TOP_LOOP:
    -     VLD1.8      D0,[r11]!                   @pu1_src[(ht - 1) * src_strd + col]
    -@@ -203,7 +212,7 @@ ulbl3:
    -     VMOV.S8     Q4,#0xFF                    @au1_mask = vdupq_n_s8(-1)
    -     ADDEQ       r14,r14,#1                  @pu1_src_left_cpy += 1
    - 
    --    STR         r0,[sp,#0x90]               @Store pu1_src in sp
    -+    STR         r0,[sp,#144]                @Store pu1_src in sp
    -     CMP         r7,#16                      @Compare wd with 16
    - 
    -     BLT         WIDTH_RESIDUE               @If not jump to WIDTH_RESIDUE where loop is unrolled for 8 case
    -@@ -211,9 +220,9 @@ ulbl3:
    -     BLE         WD_16_HT_4_LOOP             @If jump to WD_16_HT_4_LOOP
    - 
    - WIDTH_LOOP_16:
    --    LDR         r7,[sp,#0xD0]               @Loads wd
    -+    LDR         r7,[sp,#wd_offset]          @Loads wd
    - 
    --    LDR         r5,[sp,#0xC8]               @Loads pu1_avail
    -+    LDR         r5,[sp,#pu1_avail_offset]   @Loads pu1_avail
    -     CMP         r6,r7                       @col == wd
    -     LDRBEQ      r8,[r5]                     @pu1_avail[0]
    -     MOVNE       r8,#-1                      @au1_mask = vsetq_lane_s8(-1, au1_mask, 0)
    -@@ -232,21 +241,21 @@ SKIP_AU1_MASK_VAL:
    -     MOVNE       r8,r3                       @pu1_src_top_cpy
    -     SUB         r8,r8,#1                    @pu1_src_top_cpy - 1 || pu1_src - src_strd - 1
    - 
    --    LDR         r7,[sp,#0xD0]               @Loads wd
    -+    LDR         r7,[sp,#wd_offset]          @Loads wd
    -     VLD1.8      D10,[r8]!                   @pu1_top_row = vld1q_u8(pu1_src - src_strd - 1) || vld1q_u8(pu1_src_top_cpy - 1)
    -     VLD1.8      D11,[r8]                    @pu1_top_row = vld1q_u8(pu1_src - src_strd - 1) || vld1q_u8(pu1_src_top_cpy - 1)
    -     SUB         r8,#8
    -     ADD         r3,r3,#16
    - 
    --    ADD         r5,sp,#0x42                 @*au1_src_left_tmp
    -+    ADD         r5,sp,#66                   @*au1_src_left_tmp
    -     VLD1.8      D12,[r0]!                   @pu1_cur_row = vld1q_u8(pu1_src)
    -     VLD1.8      D13,[r0]                    @pu1_cur_row = vld1q_u8(pu1_src)
    -     SUB         r0,#8
    --    LDR         r4,[sp,#0xD4]               @Loads ht
    -+    LDR         r4,[sp,#ht_offset]          @Loads ht
    - 
    -     SUB         r7,r7,r6                    @(wd - col)
    -     VCGT.U8     Q7,Q6,Q5                    @vcgtq_u8(pu1_cur_row, pu1_top_row)
    --    LDR         r8,[sp,#0xC0]               @Loads *pu1_src
    -+    LDR         r8,[sp,#152]                @Loads *pu1_src
    - 
    -     ADD         r7,r7,#15                   @15 + (wd - col)
    -     VCLT.U8     Q8,Q6,Q5                    @vcltq_u8(pu1_cur_row, pu1_top_row)
    -@@ -263,7 +272,7 @@ AU1_SRC_LEFT_LOOP:
    - 
    -     ADD         r8,r0,r1                    @I Iteration *pu1_src + src_strd
    -     VMOV.I8     Q9,#0
    --    LDR         r4,[sp,#0xC8]               @I Loads pu1_avail
    -+    LDR         r4,[sp,#pu1_avail_offset]   @I Loads pu1_avail
    - 
    -     MOV         r7,r12                      @row count, move ht_tmp to r7
    -     VLD1.8      D16,[r8]!                   @I pu1_next_row = vld1q_u8(pu1_src_cpy + src_strd)
    -@@ -498,11 +507,11 @@ PU1_SRC_LOOP:
    - 
    - 
    - INNER_LOOP_DONE:
    --    ADD         r5,sp,#0x42                 @*au1_src_left_tmp
    -+    ADD         r5,sp,#66                   @*au1_src_left_tmp
    -     VST1.8      {Q10},[r0],r1               @vst1q_u8(pu1_src_cpy, pu1_cur_row)
    --    LDR         r2,[sp,#0xC4]               @Loads *pu1_src_left
    -+    LDR         r2,[sp,#156]                @Loads *pu1_src_left
    - 
    --    LDR         r8,[sp,#0xD4]               @Loads ht
    -+    LDR         r8,[sp,#ht_offset]          @Loads ht
    -     SUB         r5,r5,#1
    - 
    -     SUB         r2,r2,#1
    -@@ -515,8 +524,8 @@ SRC_LEFT_LOOP:
    -     SUB         r6,r6,#16                   @Decrement the wd loop count by 16
    -     CMP         r6,#8                       @Check whether residue remains
    -     BLT         RE_ASSINING_LOOP            @Jump to re-assigning loop
    --    LDR         r7,[sp,#0xD0]               @Loads wd
    --    LDR         r0,[sp,#0x90]               @Loads *pu1_src
    -+    LDR         r7,[sp,#wd_offset]          @Loads wd
    -+    LDR         r0,[sp,#144]                @Loads *pu1_src
    -     SUB         r7,r7,r6
    -     ADD         r0,r0,r7
    -     BGT         WIDTH_LOOP_16               @If not equal jump to width_loop
    -@@ -524,8 +533,8 @@ SRC_LEFT_LOOP:
    - 
    - 
    - WD_16_HT_4_LOOP:
    --    LDR         r7,[sp,#0xD0]               @Loads wd
    --    LDR         r5,[sp,#0xC8]               @Loads pu1_avail
    -+    LDR         r7,[sp,#wd_offset]          @Loads wd
    -+    LDR         r5,[sp,#pu1_avail_offset]   @Loads pu1_avail
    -     CMP         r6,r7                       @col == wd
    -     LDRBEQ      r8,[r5]                     @pu1_avail[0]
    -     MOVNE       r8,#-1                      @au1_mask = vsetq_lane_s8(-1, au1_mask, 0)
    -@@ -544,21 +553,21 @@ SKIP_AU1_MASK_VAL_WD_16_HT_4:
    -     MOVNE       r8,r3
    -     SUB         r8,r8,#1                    @pu1_src_top_cpy - 1 || pu1_src - src_strd - 1
    - 
    --    LDR         r7,[sp,#0xD0]               @Loads wd
    -+    LDR         r7,[sp,#wd_offset]          @Loads wd
    -     VLD1.8      D10,[r8]!                   @pu1_top_row = vld1q_u8(pu1_src - src_strd - 1) || vld1q_u8(pu1_src_top_cpy - 1)
    -     VLD1.8      D11,[r8]                    @pu1_top_row = vld1q_u8(pu1_src - src_strd - 1) || vld1q_u8(pu1_src_top_cpy - 1)
    -     SUB         r8,#8
    -     ADD         r3,r3,#16
    - 
    --    ADD         r5,sp,#0x42                 @*au1_src_left_tmp
    -+    ADD         r5,sp,#66                   @*au1_src_left_tmp
    -     VLD1.8      D12,[r0]!                   @pu1_cur_row = vld1q_u8(pu1_src)
    -     VLD1.8      D13,[r0]                    @pu1_cur_row = vld1q_u8(pu1_src)
    -     SUB         r0,#8
    --    LDR         r4,[sp,#0xD4]               @Loads ht
    -+    LDR         r4,[sp,#ht_offset]          @Loads ht
    - 
    -     SUB         r7,r7,r6                    @(wd - col)
    -     VCGT.U8     Q7,Q6,Q5                    @vcgtq_u8(pu1_cur_row, pu1_top_row)
    --    LDR         r8,[sp,#0xC0]               @Loads *pu1_src
    -+    LDR         r8,[sp,#152]                @Loads *pu1_src
    - 
    -     ADD         r7,r7,#15                   @15 + (wd - col)
    -     VCLT.U8     Q8,Q6,Q5                    @vcltq_u8(pu1_cur_row, pu1_top_row)
    -@@ -588,7 +597,7 @@ PU1_SRC_LOOP_WD_16_HT_4:
    - 
    -     CMP         r7,r12
    -     BLT         SIGN_UP_CHANGE_WD_16_HT_4
    --    LDR         r5,[sp,#0xC8]               @Loads pu1_avail
    -+    LDR         r5,[sp,#pu1_avail_offset]   @Loads pu1_avail
    -     LDRB        r5,[r5,#2]                  @pu1_avail[2]
    -     CMP         r5,#0
    -     BNE         SIGN_UP_CHANGE_DONE_WD_16_HT_4
    -@@ -639,9 +648,9 @@ SIGN_UP_CHANGE_DONE_WD_16_HT_4:
    -     SUBS        r7,r7,#1                    @Decrement the ht_tmp loop count by 1
    -     BNE         PU1_SRC_LOOP_WD_16_HT_4     @If not equal jump to PU1_SRC_LOOP_WD_16_HT_4
    - 
    --    LDR         r8,[sp,#0xD4]               @Loads ht
    --    ADD         r5,sp,#0x42                 @*au1_src_left_tmp
    --    LDR         r2,[sp,#0xC4]               @Loads *pu1_src_left
    -+    LDR         r8,[sp,#ht_offset]          @Loads ht
    -+    ADD         r5,sp,#66                   @*au1_src_left_tmp
    -+    LDR         r2,[sp,#156]                @Loads *pu1_src_left
    -     SUB         r5,r5,#1
    -     SUB         r2,r2,#1
    - 
    -@@ -656,8 +665,8 @@ SRC_LEFT_LOOP_WD_16_HT_4:
    - 
    - 
    - WIDTH_RESIDUE:
    --    LDR         r7,[sp,#0xD0]               @Loads wd
    --    LDR         r5,[sp,#0xC8]               @Loads pu1_avail
    -+    LDR         r7,[sp,#wd_offset]          @Loads wd
    -+    LDR         r5,[sp,#pu1_avail_offset]   @Loads pu1_avail
    -     CMP         r6,r7                       @wd_residue == wd
    -     LDRBEQ      r8,[r5]                     @pu1_avail[0]
    - 
    -@@ -679,16 +688,16 @@ PU1_AVAIL_2_RESIDUE:
    - 
    -     SUB         r8,r8,#1
    - 
    --    ADD         r5,sp,#0x42                 @*au1_src_left_tmp
    -+    ADD         r5,sp,#66                   @*au1_src_left_tmp
    -     VLD1.8      D10,[r8]!                   @pu1_top_row = vld1q_u8(pu1_src_top_cpy - 1)
    -     VLD1.8      D11,[r8]!                   @pu1_top_row = vld1q_u8(pu1_src_top_cpy - 1)
    --    LDR         r7,[sp,#0xD0]               @Loads wd
    -+    LDR         r7,[sp,#wd_offset]          @Loads wd
    - 
    --    LDR         r4,[sp,#0xD4]               @Loads ht
    -+    LDR         r4,[sp,#ht_offset]          @Loads ht
    -     VCGT.U8     Q7,Q6,Q5                    @vcgtq_u8(pu1_cur_row, pu1_top_row)
    -     SUB         r7,r7,#1                    @(wd - 1)
    - 
    --    LDR         r8,[sp,#0xC0]               @Loads *pu1_src
    -+    LDR         r8,[sp,#152]                @Loads *pu1_src
    -     VCLT.U8     Q8,Q6,Q5                    @vcltq_u8(pu1_cur_row, pu1_top_row)
    -     SUB         r5,r5,#1
    - 
    -@@ -718,7 +727,7 @@ PU1_SRC_LOOP_RESIDUE:
    - 
    -     CMP         r7,r12
    -     BLT         SIGN_UP_CHANGE_RESIDUE
    --    LDR         r5,[sp,#0xC8]               @Loads pu1_avail
    -+    LDR         r5,[sp,#pu1_avail_offset]   @Loads pu1_avail
    -     LDRB        r5,[r5,#2]                  @pu1_avail[2]
    -     CMP         r5,#0
    -     BNE         SIGN_UP_CHANGE_DONE_RESIDUE
    -@@ -762,10 +771,10 @@ SIGN_UP_CHANGE_DONE_RESIDUE:
    -     SUBS        r7,r7,#1
    -     BNE         PU1_SRC_LOOP_RESIDUE
    - 
    --    LDR         r8,[sp,#0xD4]               @Loads ht
    --    ADD         r5,sp,#0x42                 @*au1_src_left_tmp
    -+    LDR         r8,[sp,#ht_offset]          @Loads ht
    -+    ADD         r5,sp,#66                   @*au1_src_left_tmp
    - 
    --    LDR         r2,[sp,#0xC4]               @Loads *pu1_src_left
    -+    LDR         r2,[sp,#156]                @Loads *pu1_src_left
    -     SUB         r5,r5,#1
    - 
    -     SUB         r2,r2,#1
    -@@ -778,23 +787,23 @@ SRC_LEFT_LOOP_RESIDUE:
    - 
    - 
    - RE_ASSINING_LOOP:
    --    LDR         r8,[sp,#0xD4]               @Loads ht
    --    LDR         r7,[sp,#0xD0]               @Loads wd
    -+    LDR         r8,[sp,#ht_offset]          @Loads ht
    -+    LDR         r7,[sp,#wd_offset]          @Loads wd
    - 
    --    LDR         r0,[sp,#0xC0]               @Loads *pu1_src
    -+    LDR         r0,[sp,#152]                @Loads *pu1_src
    -     SUB         r8,r8,#1                    @ht - 1
    - 
    -     MLA         r6,r8,r1,r7                 @wd - 1 + (ht - 1) * src_strd
    -     STRB        r9,[r0]                     @pu1_src_org[0] = u1_pos_0_0_tmp
    - 
    --    LDR         r4,[sp,#0xBC]               @Loads pu1_src_top_left
    -+    LDR         r4,[sp,#pu1_src_top_left_offset] @Loads pu1_src_top_left
    -     ADD         r6,r0,r6                    @pu1_src[wd - 1 + (ht - 1) * src_strd]
    - 
    --    ADD         r12,sp,#0x02
    -+    ADD         r12,sp,#2
    -     STRB        r10,[r6,#-1]                @pu1_src_org[wd - 1 + (ht - 1) * src_strd] = u1_pos_wd_ht_tmp
    - 
    -     LDRB        r11,[sp]                    @load u1_src_top_left_tmp from stack pointer
    --    LDR         r3,[sp,#0xCC]               @Loads pu1_src_top
    -+    LDR         r3,[sp,#148]                @Loads pu1_src_top
    - 
    -     STRB        r11,[r4]                    @*pu1_src_top_left = u1_src_top_left_tmp
    - 
    -@@ -805,7 +814,8 @@ SRC_TOP_LOOP:
    -     BNE         SRC_TOP_LOOP
    - 
    - END_LOOPS:
    --    ADD         sp,sp,#0x94
    -+    ADD         sp,sp,#160
    -+    vpop        {d8  -  d15}
    -     LDMFD       sp!,{r4-r12,r15}            @Reload the registers from SP
    - 
    - 
    -diff --git a/common/arm/ihevc_sao_edge_offset_class2_chroma.s b/common/arm/ihevc_sao_edge_offset_class2_chroma.s
    -index b74a8f6..f7ab3f8 100644
    ---- a/common/arm/ihevc_sao_edge_offset_class2_chroma.s
    -+++ b/common/arm/ihevc_sao_edge_offset_class2_chroma.s
    -@@ -60,6 +60,15 @@
    - @r7 =>  wd
    - @r8=>   ht
    - 
    -+.equ    pu1_src_top_left_offset,    328
    -+.equ    pu1_src_top_right_offset,   332
    -+.equ    pu1_src_bot_left_offset,    336
    -+.equ    pu1_avail_offset,           340
    -+.equ    pi1_sao_u_offset,           344
    -+.equ    pi1_sao_v_offset,           348
    -+.equ    wd_offset,                  352
    -+.equ    ht_offset,                  356
    -+
    - .text
    - .syntax unified
    - .p2align 2
    -@@ -86,23 +95,24 @@ ihevc_sao_edge_offset_class2_chroma_a9q:
    - 
    - 
    -     STMFD       sp!,{r4-r12,r14}            @stack stores the values of the arguments
    -+    vpush       {d8  -  d15}
    -+    SUB         sp,sp,#224                  @Decrement the stack pointer to store some temp arr values
    - 
    --    LDR         r7,[sp,#0x40]               @Loads wd
    --    LDR         r8,[sp,#0x44]               @Loads ht
    -+    LDR         r7,[sp,#wd_offset]          @Loads wd
    -+    LDR         r8,[sp,#ht_offset]          @Loads ht
    -     SUB         r9,r7,#2                    @wd - 2
    - 
    --    LDR         r4,[sp,#0x28]               @Loads pu1_src_top_left
    -+    LDR         r4,[sp,#pu1_src_top_left_offset]    @Loads pu1_src_top_left
    -     LDRH        r10,[r3,r9]                 @pu1_src_top[wd - 2]
    - 
    --    STR         r0,[sp,#0x2C]               @Store pu1_src in sp
    -+    STR         r0,[sp,#212]                @Store pu1_src in sp
    -     MOV         r9,r7                       @Move width to r9 for loop count
    - 
    --    STR         r2,[sp,#0x30]               @Store pu1_src_left in sp
    --    LDR         r5,[sp,#0x34]               @Loads pu1_avail
    --    LDR         r6,[sp,#0x38]               @Loads pi1_sao_offset_u
    -+    STR         r2,[sp,#216]                @Store pu1_src_left in sp
    -+    LDR         r5,[sp,#pu1_avail_offset]   @Loads pu1_avail
    -+    LDR         r6,[sp,#pi1_sao_u_offset]   @Loads pi1_sao_offset_u
    - 
    --    STR         r3,[sp,#0x38]               @Store pu1_src_top in sp
    --    SUB         sp,sp,#0xD4                 @Decrement the stack pointer to store some temp arr values
    -+    STR         r3,[sp,#220]                @Store pu1_src_top in sp
    - 
    -     STRH        r10,[sp]                    @u1_src_top_left_tmp = pu1_src_top[wd - 2]
    -     SUB         r10,r8,#1                   @ht-1
    -@@ -178,7 +188,7 @@ ulbl2:
    -     LDRSB       r12,[r14,r11]               @edge_idx = gi1_table_edge_idx[edge_idx]
    -     CMP         r12,#0                      @0 != edge_idx
    -     BEQ         PU1_AVAIL_7_LOOP_U
    --    LDR         r11,[sp,#0x110]             @Loads pi1_sao_offset_v
    -+    LDR         r11,[sp,#pi1_sao_v_offset]  @Loads pi1_sao_offset_v
    -     LDRSB       r11,[r11,r12]               @pi1_sao_offset_v[edge_idx]
    -     ADD         r10,r10,r11                 @pu1_src[0] + pi1_sao_offset_v[edge_idx]
    -     USAT        r10,#8,r10                  @u1_pos_0_0_tmp_v = CLIP3(pu1_src[0] + pi1_sao_offset_v[edge_idx], 0, (1 << bit_depth) - 1)
    -@@ -253,7 +263,7 @@ ulbl4:
    -     LDRSB       r12,[r14,r11]               @edge_idx = gi1_table_edge_idx[edge_idx]
    -     CMP         r12,#0
    -     BEQ         PU1_AVAIL_3_LOOP
    --    LDR         r14,[sp,#0x110]             @Loads pi1_sao_offset_v
    -+    LDR         r14,[sp,#pi1_sao_v_offset]  @Loads pi1_sao_offset_v
    -     LDRSB       r11,[r14,r12]               @pi1_sao_offset_v[edge_idx]
    -     ADD         r9,r9,r11                   @pu1_src[wd - 1 + (ht - 1) * src_strd] + pi1_sao_offset[edge_idx]
    -     USAT        r9,#8,r9                    @u1_pos_wd_ht_tmp_v = CLIP3(pu1_src[wd - 1 + (ht - 1) * src_strd] + pi1_sao_offset[edge_idx], 0, (1 << bit_depth) - 1)
    -@@ -280,7 +290,7 @@ PU1_AVAIL_3_LOOP:
    -     VLD1.8      D6,[r6]                     @offset_tbl_u = vld1_s8(pi1_sao_offset_u)
    -     SUBEQ       r12,r12,#1                  @ht_tmp--
    - 
    --    LDR         r6,[sp,#0x110]              @Loads pi1_sao_offset_v
    -+    LDR         r6,[sp,#pi1_sao_v_offset]   @Loads pi1_sao_offset_v
    -     ADDEQ       r14,r14,#2                  @pu1_src_left_cpy += 2
    - 
    -     STR         r0,[sp,#2]                  @Store pu1_src in sp
    -@@ -298,8 +308,8 @@ ulbl5:
    -     BLE         WD_16_HT_4_LOOP             @If jump to WD_16_HT_4_LOOP
    - 
    - WIDTH_LOOP_16:
    --    LDR         r5,[sp,#0x108]              @Loads pu1_avail
    --    LDR         r7,[sp,#0x114]              @Loads wd
    -+    LDR         r5,[sp,#pu1_avail_offset]   @Loads pu1_avail
    -+    LDR         r7,[sp,#wd_offset]          @Loads wd
    -     CMP         r6,r7                       @col == wd
    -     LDRBEQ      r8,[r5]                     @pu1_avail[0]
    - 
    -@@ -321,16 +331,16 @@ SKIP_AU1_MASK_VAL:
    -     SUB         r0,#8
    -     CMP         r9,#0
    - 
    --    LDR         r4,[sp,#0x118]              @Loads ht
    -+    LDR         r4,[sp,#ht_offset]          @Loads ht
    -     SUBEQ       r8,r0,r1                    @pu1_src - src_strd
    - 
    --    LDR         r7,[sp,#0x114]              @Loads wd
    -+    LDR         r7,[sp,#wd_offset]          @Loads wd
    -     MOVNE       r8,r3                       @pu1_src_top_cpy
    - 
    -     SUB         r8,r8,#2                    @pu1_src - src_strd - 2
    -     ADD         r3,r3,#16
    - 
    --    ADD         r5,sp,#0x4B                 @*au1_src_left_tmp
    -+    ADD         r5,sp,#75                   @*au1_src_left_tmp
    -     VLD1.8      D10,[r8]!                   @pu1_top_row = vld1q_u8(pu1_src - src_strd - 2) || vld1q_u8(pu1_src_top_cpy - 2)
    -     VLD1.8      D11,[r8]                    @pu1_top_row = vld1q_u8(pu1_src - src_strd - 2) || vld1q_u8(pu1_src_top_cpy - 2)
    -     SUB         r8,#8
    -@@ -338,7 +348,7 @@ SKIP_AU1_MASK_VAL:
    - 
    -     ADD         r7,r7,#14                   @15 + (wd - col)
    -     VCGT.U8     Q7,Q6,Q5                    @vcgtq_u8(pu1_cur_row, pu1_top_row)
    --    LDR         r8,[sp,#0x100]              @Loads *pu1_src
    -+    LDR         r8,[sp,#212]                @Loads *pu1_src
    - 
    -     ADD         r7,r8,r7                    @pu1_src[0 * src_strd + 15 + (wd - col)]
    -     VCLT.U8     Q8,Q6,Q5                    @vcltq_u8(pu1_cur_row, pu1_top_row)
    -@@ -364,7 +374,7 @@ AU1_SRC_LEFT_LOOP:
    -     VMOV.I8     Q9,#0
    -     LDRH        r5,[r8]                     @I pu1_src_cpy[src_strd + 16]
    - 
    --    LDR         r10,[sp,#0x108]             @I Loads pu1_avail
    -+    LDR         r10,[sp,#pu1_avail_offset]  @I Loads pu1_avail
    -     VMOV.16     D18[0],r5                   @I pu1_next_row_tmp = vsetq_lane_u8(pu1_src_cpy[src_strd + 16], pu1_next_row_tmp, 0)
    -     LDRB        r10,[r10,#2]                @I pu1_avail[2]
    - 
    -@@ -654,11 +664,11 @@ PU1_SRC_LOOP:
    - 
    - 
    - INNER_LOOP_DONE:
    --    LDR         r8,[sp,#0x118]              @Loads ht
    -+    LDR         r8,[sp,#ht_offset]          @Loads ht
    -     VMOVN.I16   D20,Q10                     @vmovn_s16(pi2_tmp_cur_row.val[0])
    --    ADD         r5,sp,#0x4B                 @*au1_src_left_tmp
    -+    ADD         r5,sp,#75                   @*au1_src_left_tmp
    - 
    --    LDR         r11,[sp,#0x104]             @Loads *pu1_src_left
    -+    LDR         r11,[sp,#216]               @Loads *pu1_src_left
    -     VMOVN.I16   D21,Q9                      @vmovn_s16(pi2_tmp_cur_row.val[1])
    - 
    - 
    -@@ -673,8 +683,8 @@ SRC_LEFT_LOOP:
    -     CMP         r6,#8                       @Check whether residue remains
    - 
    -     BLT         RE_ASSINING_LOOP            @Jump to re-assigning loop
    --    LDR         r7,[sp,#0x114]              @Loads wd
    --    LDR         r0,[sp,#0x02]               @Loads *pu1_src
    -+    LDR         r7,[sp,#wd_offset]          @Loads wd
    -+    LDR         r0,[sp,#2]                  @Loads *pu1_src
    -     SUB         r7,r7,r6
    -     ADD         r0,r0,r7
    -     BGT         WIDTH_LOOP_16               @If not equal jump to width_loop
    -@@ -682,8 +692,8 @@ SRC_LEFT_LOOP:
    - 
    - 
    - WD_16_HT_4_LOOP:
    --    LDR         r5,[sp,#0x108]              @Loads pu1_avail
    --    LDR         r7,[sp,#0x114]              @Loads wd
    -+    LDR         r5,[sp,#pu1_avail_offset]   @Loads pu1_avail
    -+    LDR         r7,[sp,#wd_offset]          @Loads wd
    -     CMP         r6,r7                       @col == wd
    -     LDRBEQ      r8,[r5]                     @pu1_avail[0]
    - 
    -@@ -709,12 +719,12 @@ SKIP_AU1_MASK_VAL_WD_16_HT_4:
    -     SUB         r8,#8
    - 
    -     ADD         r3,r3,#16
    --    ADD         r5,sp,#0x4B                 @*au1_src_left_tmp
    --    LDR         r4,[sp,#0x118]              @Loads ht
    --    LDR         r7,[sp,#0x114]              @Loads wd
    -+    ADD         r5,sp,#75                   @*au1_src_left_tmp
    -+    LDR         r4,[sp,#ht_offset]          @Loads ht
    -+    LDR         r7,[sp,#wd_offset]          @Loads wd
    -     SUB         r7,r7,r6                    @(wd - col)
    -     ADD         r7,r7,#14                   @15 + (wd - col)
    --    LDR         r8,[sp,#0x100]              @Loads *pu1_src
    -+    LDR         r8,[sp,#212]                @Loads *pu1_src
    -     ADD         r7,r8,r7                    @pu1_src[0 * src_strd + 15 + (wd - col)]
    - 
    - AU1_SRC_LEFT_LOOP_WD_16_HT_4:
    -@@ -749,7 +759,7 @@ PU1_SRC_LOOP_WD_16_HT_4:
    - 
    -     CMP         r7,r12
    -     BLT         SIGN_UP_CHANGE_WD_16_HT_4
    --    LDR         r5,[sp,#0x108]              @Loads pu1_avail
    -+    LDR         r5,[sp,#pu1_avail_offset]   @Loads pu1_avail
    -     LDRB        r5,[r5,#2]                  @pu1_avail[2]
    -     CMP         r5,#0
    -     BNE         SIGN_UP_CHANGE_DONE_WD_16_HT_4
    -@@ -815,9 +825,9 @@ SIGN_UP_CHANGE_DONE_WD_16_HT_4:
    -     SUBS        r7,r7,#1                    @Decrement the ht_tmp loop count by 1
    -     BNE         PU1_SRC_LOOP_WD_16_HT_4     @If not equal jump to PU1_SRC_LOOP_WD_16_HT_4
    - 
    --    LDR         r8,[sp,#0x118]              @Loads ht
    --    ADD         r5,sp,#0x4B                 @*au1_src_left_tmp
    --    LDR         r11,[sp,#0x104]             @Loads *pu1_src_left
    -+    LDR         r8,[sp,#ht_offset]          @Loads ht
    -+    ADD         r5,sp,#75                   @*au1_src_left_tmp
    -+    LDR         r11,[sp,#216]               @Loads *pu1_src_left
    - 
    - SRC_LEFT_LOOP_WD_16_HT_4:
    -     LDR         r7,[r5],#4                  @au1_src_left_tmp[row]
    -@@ -829,12 +839,16 @@ SRC_LEFT_LOOP_WD_16_HT_4:
    - 
    -     SUBS        r6,r6,#16                   @Decrement the wd loop count by 16
    -     BLE         RE_ASSINING_LOOP            @Jump to re-assigning loop
    -+    LDR         r7,[sp,#wd_offset]          @Loads wd
    -+    LDR         r0,[sp,#2]                  @Loads *pu1_src
    -+    SUB         r7,r7,r6
    -+    ADD         r0,r0,r7
    -     BGT         WD_16_HT_4_LOOP
    - 
    - 
    - WIDTH_RESIDUE:
    --    LDR         r7,[sp,#0x114]              @Loads wd
    --    LDR         r5,[sp,#0x108]              @Loads pu1_avail
    -+    LDR         r7,[sp,#wd_offset]          @Loads wd
    -+    LDR         r5,[sp,#pu1_avail_offset]   @Loads pu1_avail
    -     CMP         r6,r7                       @wd_residue == wd
    -     LDRBEQ      r8,[r5]                     @pu1_avail[0]
    - 
    -@@ -856,10 +870,10 @@ WIDTH_RESIDUE:
    -     VLD1.8      D11,[r8]                    @pu1_top_row = vld1q_u8(pu1_src - src_strd - 2)
    -     SUB         r8,#8
    - 
    --    ADD         r5,sp,#0x4B                 @*au1_src_left_tmp
    --    LDR         r4,[sp,#0x118]              @Loads ht
    --    LDR         r7,[sp,#0x114]              @Loads wd
    --    LDR         r8,[sp,#0x100]              @Loads *pu1_src
    -+    ADD         r5,sp,#75                   @*au1_src_left_tmp
    -+    LDR         r4,[sp,#ht_offset]          @Loads ht
    -+    LDR         r7,[sp,#wd_offset]          @Loads wd
    -+    LDR         r8,[sp,#212]                @Loads *pu1_src
    -     SUB         r7,r7,#2                    @(wd - 2)
    -     ADD         r7,r8,r7                    @pu1_src[0 * src_strd + (wd - 2)]
    - 
    -@@ -893,7 +907,7 @@ PU1_SRC_LOOP_RESIDUE:
    - 
    -     CMP         r7,r12
    -     BLT         SIGN_UP_CHANGE_RESIDUE
    --    LDR         r5,[sp,#0x108]              @Loads pu1_avail
    -+    LDR         r5,[sp,#pu1_avail_offset]   @Loads pu1_avail
    -     LDRB        r5,[r5,#2]                  @pu1_avail[2]
    -     CMP         r5,#0
    -     BNE         SIGN_UP_CHANGE_DONE_RESIDUE
    -@@ -953,9 +967,9 @@ SIGN_UP_CHANGE_DONE_RESIDUE:
    -     SUBS        r7,r7,#1                    @Decrement the ht_tmp loop count by 1
    -     BNE         PU1_SRC_LOOP_RESIDUE        @If not equal jump to PU1_SRC_LOOP
    - 
    --    LDR         r8,[sp,#0x118]              @Loads ht
    --    LDR         r11,[sp,#0x104]             @Loads *pu1_src_left
    --    ADD         r5,sp,#0x4B                 @*au1_src_left_tmp
    -+    LDR         r8,[sp,#ht_offset]          @Loads ht
    -+    LDR         r11,[sp,#216]               @Loads *pu1_src_left
    -+    ADD         r5,sp,#75                   @*au1_src_left_tmp
    - 
    - SRC_LEFT_LOOP_RESIDUE:
    -     LDR         r7,[r5],#4                  @au1_src_left_tmp[row]
    -@@ -966,12 +980,12 @@ SRC_LEFT_LOOP_RESIDUE:
    - 
    - 
    - RE_ASSINING_LOOP:
    --    LDR         r8,[sp,#0x118]              @Loads ht
    -+    LDR         r8,[sp,#ht_offset]          @Loads ht
    - 
    --    LDR         r0,[sp,#0x100]              @Loads *pu1_src
    -+    LDR         r0,[sp,#212]                @Loads *pu1_src
    -     SUB         r8,r8,#1                    @ht - 1
    - 
    --    LDR         r7,[sp,#0x114]              @Loads wd
    -+    LDR         r7,[sp,#wd_offset]          @Loads wd
    - 
    -     LDRH        r9,[sp,#6]
    -     MLA         r6,r8,r1,r7                 @wd - 2 + (ht - 1) * src_strd
    -@@ -983,10 +997,10 @@ RE_ASSINING_LOOP:
    -     ADD         r12,sp,#10
    -     STRH        r9,[r6,#-2]                 @pu1_src_org[wd - 1 + (ht - 1) * src_strd] = u1_pos_wd_ht_tmp_u
    - 
    --    LDR         r4,[sp,#0xFC]               @Loads pu1_src_top_left
    -+    LDR         r4,[sp,#pu1_src_top_left_offset]               @Loads pu1_src_top_left
    -     LDRH        r10,[sp]                    @load u1_src_top_left_tmp from stack pointer
    -     STRH        r10,[r4]                    @*pu1_src_top_left = u1_src_top_left_tmp
    --    LDR         r3,[sp,#0x10C]              @Loads pu1_src_top
    -+    LDR         r3,[sp,#220]                @Loads pu1_src_top
    - 
    - SRC_TOP_LOOP:
    -     VLD1.8      D0,[r12]!                   @pu1_src_top[col] = au1_src_top_tmp[col]
    -@@ -995,7 +1009,9 @@ SRC_TOP_LOOP:
    -     BNE         SRC_TOP_LOOP
    - 
    - END_LOOPS:
    --    ADD         sp,sp,#0xD4
    -+    ADD         sp,sp,#224
    -+
    -+    vpop        {d8  -  d15}
    -     LDMFD       sp!,{r4-r12,r15}            @Reload the registers from SP
    - 
    - 
    -diff --git a/common/arm/ihevc_sao_edge_offset_class3.s b/common/arm/ihevc_sao_edge_offset_class3.s
    -index de09d6c..fb3b05c 100644
    ---- a/common/arm/ihevc_sao_edge_offset_class3.s
    -+++ b/common/arm/ihevc_sao_edge_offset_class3.s
    -@@ -58,6 +58,14 @@
    - @r7 =>  wd
    - @r8=>   ht
    - 
    -+.equ    pu1_src_top_left_offset,    264
    -+.equ    pu1_src_top_right_offset,   268
    -+.equ    pu1_src_bot_left_offset,    272
    -+.equ    pu1_avail_offset,           276
    -+.equ    pi1_sao_offset,             280
    -+.equ    wd_offset,                  284
    -+.equ    ht_offset,                  288
    -+
    - .text
    - .syntax unified
    - .p2align 2
    -@@ -78,26 +86,27 @@ ihevc_sao_edge_offset_class3_a9q:
    - 
    - 
    -     STMFD       sp!,{r4-r12,r14}            @stack stores the values of the arguments
    --    LDR         r7,[sp,#0x3C]               @Loads wd
    -+    vpush       {d8  -  d15}
    -+    SUB         sp,sp,#160                  @Decrement the stack pointer to store some temp arr values
    -+    LDR         r7,[sp,#wd_offset]          @Loads wd
    - 
    --    LDR         r8,[sp,#0x40]               @Loads ht
    -+    LDR         r8,[sp,#ht_offset]          @Loads ht
    -     SUB         r9,r7,#1                    @wd - 1
    - 
    --    LDR         r4,[sp,#0x28]               @Loads pu1_src_top_left
    -+    LDR         r4,[sp,#pu1_src_top_left_offset]               @Loads pu1_src_top_left
    -     LDRB        r10,[r3,r9]                 @pu1_src_top[wd - 1]
    - 
    -     MOV         r9,r7                       @Move width to r9 for loop count
    - 
    --    LDR         r5,[sp,#0x34]               @Loads pu1_avail
    --    LDR         r6,[sp,#0x38]               @Loads pi1_sao_offset
    --    STR         r3,[sp,#0x38]               @Store pu1_src_top in sp
    -+    LDR         r5,[sp,#pu1_avail_offset]   @Loads pu1_avail
    -+    LDR         r6,[sp,#pi1_sao_offset]     @Loads pi1_sao_offset
    -+    STR         r3,[sp,#156]                @Store pu1_src_top in sp
    - 
    --    SUB         sp,sp,#0x94                 @Decrement the stack pointer to store some temp arr values
    - 
    -     STRB        r10,[sp]                    @u1_src_top_left_tmp = pu1_src_top[wd - 1]
    -     SUB         r10,r8,#1                   @ht-1
    -     MLA         r11,r10,r1,r0               @pu1_src[(ht - 1) * src_strd + col]
    --    ADD         r12,sp,#0x02                @temp array
    -+    ADD         r12,sp,#2                   @temp array
    - 
    - AU1_SRC_TOP_LOOP:
    -     VLD1.8      D0,[r11]!                   @pu1_src[(ht - 1) * src_strd + col]
    -@@ -112,7 +121,7 @@ PU1_AVAIL_5_LOOP:
    -     LDRB        r9,[r0,r10]                 @u1_pos_0_0_tmp = pu1_src[wd - 1]
    -     BEQ         PU1_AVAIL_6_LOOP
    - 
    --    LDR         r11,[sp,#0xC0]              @Load pu1_src_top_right from sp
    -+    LDR         r11,[sp,#pu1_src_top_right_offset]  @Load pu1_src_top_right from sp
    -     SUB         r10,r10,#1                  @[wd - 1 - 1]
    - 
    -     LDRB        r11,[r11]                   @pu1_src_top_right[0]
    -@@ -147,13 +156,13 @@ PU1_AVAIL_6_LOOP:
    -     SUB         r11,r8,#1                   @ht - 1
    - 
    -     CMP         r10,#0
    --    STR         r0,[sp,#0xC0]               @Store pu1_src in sp
    -+    STR         r0,[sp,#148]                @Store pu1_src in sp
    -     MLA         r12,r11,r1,r0               @pu1_src[(ht - 1) * src_strd]
    - 
    -     LDRB        r10,[r12]                   @u1_pos_wd_ht_tmp = pu1_src[(ht - 1) * src_strd]
    -     BEQ         PU1_AVAIL_3_LOOP
    - 
    --    LDR         r14,[sp,#0xC4]              @Load pu1_src_bot_left from sp
    -+    LDR         r14,[sp,#pu1_src_bot_left_offset]   @Load pu1_src_bot_left from sp
    -     SUB         r11,r12,r1                  @pu1_src[(ht - 1) * src_strd) - src_strd]
    - 
    -     LDRB        r14,[r14]                   @Load pu1_src_bot_left[0]
    -@@ -186,7 +195,7 @@ ulbl2:
    -     USAT        r10,#8,r10                  @u1_pos_wd_ht_tmp = CLIP3(pu1_src[(ht - 1) * src_strd] + pi1_sao_offset[edge_idx], 0, (1 << bit_depth) - 1)
    - 
    - PU1_AVAIL_3_LOOP:
    --    STR         r2,[sp,#0xC4]               @Store pu1_src_left in sp
    -+    STR         r2,[sp,#152]                @Store pu1_src_left in sp
    -     MOV         r12,r8                      @Move ht
    - 
    -     MOV         r14,r2                      @Move pu1_src_left to pu1_src_left_cpy
    -@@ -211,7 +220,7 @@ ulbl3:
    -     VMOV.S8     Q4,#0xFF                    @au1_mask = vdupq_n_s8(-1)
    -     ADDEQ       r14,r14,#1                  @pu1_src_left_cpy += 1
    - 
    --    STR         r0,[sp,#0x90]               @Store pu1_src in sp
    -+    STR         r0,[sp,#144]                @Store pu1_src in sp
    -     VLD1.8      D6,[r6]                     @edge_idx_tbl = vld1_s8(gi1_table_edge_idx)
    -     MOV         r6,r7                       @move wd to r6 loop_count
    - 
    -@@ -221,9 +230,9 @@ ulbl3:
    -     BLE         WD_16_HT_4_LOOP             @If jump to WD_16_HT_4_LOOP
    - 
    - WIDTH_LOOP_16:
    --    LDR         r7,[sp,#0xD0]               @Loads wd
    -+    LDR         r7,[sp,#wd_offset]          @Loads wd
    - 
    --    LDR         r5,[sp,#0xC8]               @Loads pu1_avail
    -+    LDR         r5,[sp,#pu1_avail_offset]   @Loads pu1_avail
    -     CMP         r6,r7                       @col == wd
    -     LDRBEQ      r8,[r5]                     @pu1_avail[0]
    -     MOVNE       r8,#-1
    -@@ -238,13 +247,13 @@ SKIP_AU1_MASK_VAL:
    -     LDRB        r8,[r5,#2]                  @pu1_avail[2]
    -     CMP         r8,#0
    - 
    --    LDR         r4,[sp,#0xD4]               @Loads ht
    -+    LDR         r4,[sp,#ht_offset]          @Loads ht
    -     SUBEQ       r8,r0,r1                    @pu1_src - src_strd
    - 
    -     MOVNE       r8,r3
    --    ADD         r5,sp,#0x42                 @*au1_src_left_tmp
    -+    ADD         r5,sp,#66                   @*au1_src_left_tmp
    - 
    --    LDR         r7,[sp,#0xD0]               @Loads wd
    -+    LDR         r7,[sp,#wd_offset]          @Loads wd
    -     ADD         r8,r8,#1                    @pu1_src - src_strd + 1
    - 
    -     SUB         r7,r7,r6                    @(wd - col)
    -@@ -253,7 +262,7 @@ SKIP_AU1_MASK_VAL:
    -     SUB         r8,#8
    -     ADD         r3,r3,#16
    - 
    --    LDR         r8,[sp,#0xC0]               @Loads *pu1_src
    -+    LDR         r8,[sp,#148]                @Loads *pu1_src
    -     VLD1.8      D12,[r0]!                   @pu1_cur_row = vld1q_u8(pu1_src)
    -     VLD1.8      D13,[r0]                    @pu1_cur_row = vld1q_u8(pu1_src)
    -     SUB         r0,#8
    -@@ -285,7 +294,7 @@ AU1_SRC_LEFT_LOOP:
    -     ADD         r8,r8,#1                    @I pu1_src_left_cpy[ht_tmp - row + 1]
    -     LDRB        r8,[r8]
    - 
    --    LDR         r5,[sp,#0xC8]               @I Loads pu1_avail
    -+    LDR         r5,[sp,#pu1_avail_offset]   @I Loads pu1_avail
    -     VMOV.8      D19[7],r8                   @I vsetq_lane_u8
    -     LDRB        r5,[r5,#2]                  @I pu1_avail[2]
    - 
    -@@ -375,7 +384,7 @@ PU1_SRC_LOOP:
    -     CMP         r7,#1                       @III
    - 
    -     BNE         NEXT_ROW_ELSE_2             @III
    --    LDR         r5,[sp,#0xC8]               @III Loads pu1_avail
    -+    LDR         r5,[sp,#pu1_avail_offset]   @III Loads pu1_avail
    -     LDRB        r5,[r5,#3]                  @III pu1_avail[3]
    -     CMP         r5,#0                       @III
    -     SUBNE       r8,r2,#2                    @III pu1_src_cpy[src_strd - 1]
    -@@ -465,7 +474,7 @@ NEXT_ROW_ELSE_2:
    - 
    -     ADD         r8,r0,r1,LSL #1             @*pu1_src + src_strd
    -     VMOVN.I16   D20,Q10                     @III vmovn_s16(pi2_tmp_cur_row.val[0])
    --    LDR         r5,[sp,#0xC8]               @Loads pu1_avail
    -+    LDR         r5,[sp,#pu1_avail_offset]   @Loads pu1_avail
    - 
    -     LDRB        r5,[r5,#3]                  @pu1_avail[3]
    -     VMOVN.I16   D21,Q11                     @III vmovn_s16(pi2_tmp_cur_row.val[1])
    -@@ -529,13 +538,13 @@ NEXT_ROW_POINTER_ASSIGNED_3:
    - 
    - INNER_LOOP_DONE:
    -     VMOVN.I16   D20,Q10                     @vmovn_s16(pi2_tmp_cur_row.val[0])
    --    LDR         r8,[sp,#0xD4]               @Loads ht
    -+    LDR         r8,[sp,#ht_offset]          @Loads ht
    - 
    -     VMOVN.I16   D21,Q11                     @vmovn_s16(pi2_tmp_cur_row.val[1])
    --    ADD         r5,sp,#0x42                 @*au1_src_left_tmp
    -+    ADD         r5,sp,#66                   @*au1_src_left_tmp
    - 
    -     VST1.8      {Q10},[r0],r1               @vst1q_u8(pu1_src_cpy, pu1_cur_row)
    --    LDR         r2,[sp,#0xC4]               @Loads *pu1_src_left
    -+    LDR         r2,[sp,#152]                @Loads *pu1_src_left
    - SRC_LEFT_LOOP:
    -     LDR         r7,[r5],#4                  @au1_src_left_tmp[row]
    -     SUBS        r8,r8,#4
    -@@ -545,8 +554,8 @@ SRC_LEFT_LOOP:
    -     SUBS        r6,r6,#16                   @Decrement the wd loop count by 16
    -     CMP         r6,#8                       @Check whether residue remains
    -     BLT         RE_ASSINING_LOOP            @Jump to re-assigning loop
    --    LDR         r7,[sp,#0xD0]               @Loads wd
    --    LDR         r0,[sp,#0x90]               @Loads *pu1_src
    -+    LDR         r7,[sp,#wd_offset]          @Loads wd
    -+    LDR         r0,[sp,#144]                @Loads *pu1_src
    -     SUB         r7,r7,r6
    -     ADD         r0,r0,r7
    -     BGT         WIDTH_LOOP_16               @If not equal jump to width_loop
    -@@ -555,8 +564,8 @@ SRC_LEFT_LOOP:
    - 
    - 
    - WD_16_HT_4_LOOP:
    --    LDR         r5,[sp,#0xC8]               @Loads pu1_avail
    --    LDR         r7,[sp,#0xD0]               @Loads wd
    -+    LDR         r5,[sp,#pu1_avail_offset]   @Loads pu1_avail
    -+    LDR         r7,[sp,#wd_offset]          @Loads wd
    -     CMP         r6,r7                       @col == wd
    -     LDRBEQ      r8,[r5]                     @pu1_avail[0]
    -     MOVNE       r8,#-1
    -@@ -579,12 +588,12 @@ SKIP_AU1_MASK_VAL_WD_16_HT_4:
    -     SUB         r8,#8
    - 
    -     ADD         r3,r3,#16
    --    ADD         r5,sp,#0x42                 @*au1_src_left_tmp
    --    LDR         r4,[sp,#0xD4]               @Loads ht
    --    LDR         r7,[sp,#0xD0]               @Loads wd
    -+    ADD         r5,sp,#66                   @*au1_src_left_tmp
    -+    LDR         r4,[sp,#ht_offset]          @Loads ht
    -+    LDR         r7,[sp,#wd_offset]          @Loads wd
    -     SUB         r7,r7,r6                    @(wd - col)
    -     ADD         r7,r7,#15                   @15 + (wd - col)
    --    LDR         r8,[sp,#0xC0]               @Loads *pu1_src
    -+    LDR         r8,[sp,#148]                @Loads *pu1_src
    -     ADD         r7,r8,r7                    @pu1_src[0 * src_strd + 15 + (wd - col)]
    -     SUB         r5,r5,#1
    - 
    -@@ -609,7 +618,7 @@ PU1_SRC_LOOP_WD_16_HT_4:
    -     VLD1.8      D16,[r8]!                   @pu1_next_row = vld1q_u8(pu1_src_cpy + src_strd)
    -     VLD1.8      D17,[r8]                    @pu1_next_row = vld1q_u8(pu1_src_cpy + src_strd)
    -     SUB         r8,#8
    --    LDR         r5,[sp,#0xC8]               @Loads pu1_avail
    -+    LDR         r5,[sp,#pu1_avail_offset]   @Loads pu1_avail
    -     LDRB        r5,[r5,#3]                  @pu1_avail[3]
    -     CMP         r5,#0
    -     BEQ         NEXT_ROW_ELSE_WD_16_HT_4
    -@@ -628,7 +637,7 @@ NEXT_ROW_POINTER_ASSIGNED_WD_16_HT_4:
    - 
    -     CMP         r7,r12
    -     BNE         SIGN_UP_CHANGE_WD_16_HT_4
    --    LDR         r5,[sp,#0xC8]               @Loads pu1_avail
    -+    LDR         r5,[sp,#pu1_avail_offset]   @Loads pu1_avail
    -     LDRB        r5,[r5,#2]                  @pu1_avail[2]
    -     CMP         r5,#0
    -     BNE         SIGN_UP_CHANGE_DONE_WD_16_HT_4
    -@@ -680,9 +689,9 @@ SIGN_UP_CHANGE_DONE_WD_16_HT_4:
    -     SUBS        r7,r7,#1                    @Decrement the ht_tmp loop count by 1
    -     BNE         PU1_SRC_LOOP_WD_16_HT_4     @If not equal jump to PU1_SRC_LOOP_WD_16_HT_4
    - 
    --    LDR         r8,[sp,#0xD4]               @Loads ht
    --    ADD         r5,sp,#0x42                 @*au1_src_left_tmp
    --    LDR         r2,[sp,#0xC4]               @Loads *pu1_src_left
    -+    LDR         r8,[sp,#ht_offset]          @Loads ht
    -+    ADD         r5,sp,#66                   @*au1_src_left_tmp
    -+    LDR         r2,[sp,#152]                @Loads *pu1_src_left
    - SRC_LEFT_LOOP_WD_16_HT_4:
    -     LDR         r7,[r5],#4                  @au1_src_left_tmp[row]
    -     STR         r7,[r2],#4                  @pu1_src_left[row] = au1_src_left_tmp[row]
    -@@ -691,12 +700,16 @@ SRC_LEFT_LOOP_WD_16_HT_4:
    - 
    -     SUBS        r6,r6,#16                   @Decrement the wd loop count by 16
    -     BLE         RE_ASSINING_LOOP            @Jump to re-assigning loop
    -+    LDR         r7,[sp,#wd_offset]          @Loads wd
    -+    LDR         r0,[sp,#144]                @Loads *pu1_src
    -+    SUB         r7,r7,r6
    -+    ADD         r0,r0,r7
    -     BGT         WD_16_HT_4_LOOP             @If not equal jump to width_loop
    - 
    - 
    - WIDTH_RESIDUE:
    --    LDR         r7,[sp,#0xD0]               @Loads wd
    --    LDR         r5,[sp,#0xC8]               @Loads pu1_avail
    -+    LDR         r7,[sp,#wd_offset]          @Loads wd
    -+    LDR         r5,[sp,#pu1_avail_offset]   @Loads pu1_avail
    -     CMP         r6,r7                       @wd_residue == wd
    -     LDRBEQ      r8,[r5]                     @pu1_avail[0]
    - 
    -@@ -718,10 +731,10 @@ PU1_AVAIL_2_RESIDUE:
    -     SUB         r8,#8
    - 
    - 
    --    ADD         r5,sp,#0x42                 @*au1_src_left_tmp
    --    LDR         r4,[sp,#0xD4]               @Loads ht
    --    LDR         r7,[sp,#0xD0]               @Loads wd
    --    LDR         r8,[sp,#0xC0]               @Loads *pu1_src
    -+    ADD         r5,sp,#66                   @*au1_src_left_tmp
    -+    LDR         r4,[sp,#ht_offset]          @Loads ht
    -+    LDR         r7,[sp,#wd_offset]          @Loads wd
    -+    LDR         r8,[sp,#148]                @Loads *pu1_src
    -     SUB         r7,r7,#1                    @(wd - 1)
    -     ADD         r7,r8,r7                    @pu1_src[0 * src_strd + (wd - 1)]
    -     SUB         r5,r5,#1
    -@@ -747,7 +760,7 @@ PU1_SRC_LOOP_RESIDUE:
    -     VLD1.8      D16,[r8]!                   @pu1_next_row = vld1q_u8(pu1_src_cpy + src_strd)
    -     VLD1.8      D17,[r8]                    @pu1_next_row = vld1q_u8(pu1_src_cpy + src_strd)
    -     SUB         r8,#8
    --    LDR         r5,[sp,#0xC8]               @Loads pu1_avail
    -+    LDR         r5,[sp,#pu1_avail_offset]   @Loads pu1_avail
    -     LDRB        r5,[r5,#3]                  @pu1_avail[3]
    -     CMP         r5,#0
    -     BEQ         NEXT_ROW_ELSE_RESIDUE
    -@@ -766,7 +779,7 @@ NEXT_ROW_POINTER_ASSIGNED_RESIDUE:
    - 
    -     CMP         r7,r12
    -     BNE         SIGN_UP_CHANGE_RESIDUE
    --    LDR         r5,[sp,#0xC8]               @Loads pu1_avail
    -+    LDR         r5,[sp,#pu1_avail_offset]   @Loads pu1_avail
    -     LDRB        r5,[r5,#2]                  @pu1_avail[2]
    -     CMP         r5,#0
    -     BNE         SIGN_UP_CHANGE_DONE_RESIDUE
    -@@ -810,9 +823,9 @@ SIGN_UP_CHANGE_DONE_RESIDUE:
    -     SUBS        r7,r7,#1
    -     BNE         PU1_SRC_LOOP_RESIDUE
    - 
    --    LDR         r8,[sp,#0xD4]               @Loads ht
    --    LDR         r2,[sp,#0xC4]               @Loads *pu1_src_left
    --    ADD         r5,sp,#0x42                 @*au1_src_left_tmp
    -+    LDR         r8,[sp,#ht_offset]          @Loads ht
    -+    LDR         r2,[sp,#152]                @Loads *pu1_src_left
    -+    ADD         r5,sp,#66                   @*au1_src_left_tmp
    - 
    - SRC_LEFT_LOOP_RESIDUE:
    -     LDR         r7,[r5],#4                  @au1_src_left_tmp[row]
    -@@ -822,24 +835,24 @@ SRC_LEFT_LOOP_RESIDUE:
    - 
    - 
    - RE_ASSINING_LOOP:
    --    LDR         r7,[sp,#0xD0]               @Loads wd
    --    LDR         r0,[sp,#0xC0]               @Loads *pu1_src
    -+    LDR         r7,[sp,#wd_offset]          @Loads wd
    -+    LDR         r0,[sp,#148]                @Loads *pu1_src
    - 
    --    LDR         r11,[sp,#0xD4]              @Loads ht
    -+    LDR         r11,[sp,#ht_offset]         @Loads ht
    -     ADD         r8,r0,r7                    @pu1_src[wd]
    - 
    --    LDR         r4,[sp,#0xBC]               @Loads pu1_src_top_left
    -+    LDR         r4,[sp,#pu1_src_top_left_offset]    @Loads pu1_src_top_left
    -     SUB         r11,r11,#1                  @ht - 1
    - 
    -     STRB        r9,[r8,#-1]                 @pu1_src_org[wd - 1] = u1_pos_wd_0_tmp
    -     MLA         r6,r11,r1,r0                @pu1_src_org[(ht - 1) * src_strd]
    - 
    -     LDRB        r8,[sp]                     @load u1_src_top_left_tmp from stack pointer
    --    ADD         r12,sp,#0x02
    -+    ADD         r12,sp,#2
    - 
    -     STRB        r10,[r6]                    @pu1_src_org[wd - 1 + (ht - 1) * src_strd] = u1_pos_wd_ht_tmp
    -     STRB        r8,[r4]                     @*pu1_src_top_left = u1_src_top_left_tmp
    --    LDR         r3,[sp,#0xCC]               @Loads pu1_src_top
    -+    LDR         r3,[sp,#156]                @Loads pu1_src_top
    - 
    - SRC_TOP_LOOP:
    -     VLD1.8      D0,[r12]!                   @pu1_src_top[col] = au1_src_top_tmp[col]
    -@@ -848,7 +861,8 @@ SRC_TOP_LOOP:
    -     BNE         SRC_TOP_LOOP
    - 
    - END_LOOPS:
    --    ADD         sp,sp,#0x94
    -+    ADD         sp,sp,#160
    -+    vpop        {d8  -  d15}
    -     LDMFD       sp!,{r4-r12,r15}            @Reload the registers from SP
    - 
    - 
    -diff --git a/common/arm/ihevc_sao_edge_offset_class3_chroma.s b/common/arm/ihevc_sao_edge_offset_class3_chroma.s
    -index 62f40d1..9f4eb62 100644
    ---- a/common/arm/ihevc_sao_edge_offset_class3_chroma.s
    -+++ b/common/arm/ihevc_sao_edge_offset_class3_chroma.s
    -@@ -60,6 +60,15 @@
    - @r7 =>  wd
    - @r8=>   ht
    - 
    -+.equ    pu1_src_top_left_offset,    328
    -+.equ    pu1_src_top_right_offset,   332
    -+.equ    pu1_src_bot_left_offset,    336
    -+.equ    pu1_avail_offset,           340
    -+.equ    pi1_sao_u_offset,           344
    -+.equ    pi1_sao_v_offset,           348
    -+.equ    wd_offset,                  352
    -+.equ    ht_offset,                  356
    -+
    - .text
    - .syntax unified
    - .p2align 2
    -@@ -86,21 +95,22 @@ ihevc_sao_edge_offset_class3_chroma_a9q:
    - 
    - 
    -     STMFD       sp!,{r4-r12,r14}            @stack stores the values of the arguments
    -+    vpush       {d8  -  d15}
    -+    SUB         sp,sp,#224                  @Decrement the stack pointer to store some temp arr values
    - 
    --    LDR         r7,[sp,#0x40]               @Loads wd
    --    LDR         r8,[sp,#0x44]               @Loads ht
    -+    LDR         r7,[sp,#wd_offset]          @Loads wd
    -+    LDR         r8,[sp,#ht_offset]          @Loads ht
    -     SUB         r9,r7,#2                    @wd - 2
    - 
    --    LDR         r4,[sp,#0x28]               @Loads pu1_src_top_left
    -+    LDR         r4,[sp,#pu1_src_top_left_offset]    @Loads pu1_src_top_left
    -     LDRH        r10,[r3,r9]                 @pu1_src_top[wd - 2]
    - 
    -     MOV         r9,r7                       @Move width to r9 for loop count
    - 
    --    LDR         r5,[sp,#0x34]               @Loads pu1_avail
    --    LDR         r6,[sp,#0x38]               @Loads pi1_sao_offset_u
    -+    LDR         r5,[sp,#pu1_avail_offset]   @Loads pu1_avail
    -+    LDR         r6,[sp,#pi1_sao_u_offset]   @Loads pi1_sao_offset_u
    - 
    --    STR         r3,[sp,#0x38]               @Store pu1_src_top in sp
    --    SUB         sp,sp,#0xD4                 @Decrement the stack pointer to store some temp arr values
    -+    STR         r3,[sp,#220]                @Store pu1_src_top in sp
    - 
    -     STRH        r10,[sp]                    @u1_src_top_left_tmp = pu1_src_top[wd - 2]
    -     SUB         r10,r8,#1                   @ht-1
    -@@ -122,7 +132,7 @@ PU1_AVAIL_5_LOOP_U:
    -     LDRB        r10,[r0,r11]                @u1_pos_0_0_tmp_v = pu1_src[wd - 1]
    -     BEQ         PU1_AVAIL_6_LOOP_U
    - 
    --    LDR         r11,[sp,#0x100]             @Load pu1_src_top_right from sp
    -+    LDR         r11,[sp,#pu1_src_top_right_offset]  @Load pu1_src_top_right from sp
    -     LDRB        r11,[r11]                   @pu1_src_top_right[0]
    -     SUB         r12,r9,r11                  @pu1_src[wd - 2] - pu1_src_top_right[0]
    -     CMP         r12,#0
    -@@ -150,7 +160,7 @@ ulbl1:
    - 
    - PU1_AVAIL_5_LOOP_V:
    - 
    --    LDR         r11,[sp,#0x100]             @Load pu1_src_top_right from sp
    -+    LDR         r11,[sp,#pu1_src_top_right_offset]  @Load pu1_src_top_right from sp
    -     LDRB        r11,[r11,#1]                @pu1_src_top_right[1]
    -     SUB         r12,r10,r11                 @pu1_src[wd - 1] - pu1_src_top_right[1]
    -     CMP         r12,#0
    -@@ -172,7 +182,7 @@ ulbl2:
    -     LDRSB       r12,[r14,r11]               @edge_idx = gi1_table_edge_idx[edge_idx]
    -     CMP         r12,#0                      @0 != edge_idx
    -     BEQ         PU1_AVAIL_6_LOOP_U
    --    LDR         r11,[sp,#0x110]             @Loads pi1_sao_offset_v
    -+    LDR         r11,[sp,#pi1_sao_v_offset]  @Loads pi1_sao_offset_v
    -     LDRSB       r11,[r11,r12]               @pi1_sao_offset_v[edge_idx]
    -     ADD         r10,r10,r11                 @pu1_src[wd - 1] + pi1_sao_offset_v[edge_idx]
    -     USAT        r10,#8,r10                  @u1_pos_0_0_tmp_v = CLIP3(pu1_src[wd - 1] + pi1_sao_offset_v[edge_idx], 0, (1 << bit_depth) - 1)
    -@@ -180,7 +190,7 @@ ulbl2:
    - PU1_AVAIL_6_LOOP_U:
    -     STRB        r9,[sp,#6]
    -     STRB        r10,[sp,#7]
    --    STR         r0,[sp,#0x100]              @Store pu1_src in sp
    -+    STR         r0,[sp,#212]                @Store pu1_src in sp
    - 
    -     LDRB        r10,[r5,#6]                 @pu1_avail[6]
    -     CMP         r10,#0
    -@@ -198,7 +208,7 @@ PU1_AVAIL_6_LOOP_U:
    -     MVNLT       r11,#0
    -     MOVGT       r11,#1                      @SIGN(pu1_src[(ht - 1) * src_strd] - pu1_src[(ht - 1) * src_strd +  2 - src_strd])
    - 
    --    LDR         r14,[sp,#0x104]             @Load pu1_src_bot_left from sp
    -+    LDR         r14,[sp,#pu1_src_bot_left_offset]   @Load pu1_src_bot_left from sp
    -     LDRB        r14,[r14]                   @Load pu1_src_bot_left[0]
    -     SUB         r14,r10,r14                 @pu1_src[(ht - 1) * src_strd] - pu1_src_bot_left[0]
    -     CMP         r14,#0
    -@@ -228,7 +238,7 @@ PU1_AVAIL_6_LOOP_V:
    -     MVNLT       r11,#0
    -     MOVGT       r11,#1                      @SIGN(pu1_src[(ht - 1) * src_strd + 1] - pu1_src[(ht - 1) * src_strd + 1 + 2 - src_strd])
    - 
    --    LDR         r14,[sp,#0x104]             @Load pu1_src_bot_left from sp
    -+    LDR         r14,[sp,#pu1_src_bot_left_offset]   @Load pu1_src_bot_left from sp
    -     LDRB        r14,[r14,#1]                @Load pu1_src_bot_left[1]
    -     SUB         r14,r9,r14                  @pu1_src[(ht - 1) * src_strd + 1] - pu1_src_bot_left[1]
    -     CMP         r14,#0
    -@@ -244,7 +254,7 @@ ulbl4:
    -     LDRSB       r12,[r14,r11]               @edge_idx = gi1_table_edge_idx[edge_idx]
    -     CMP         r12,#0
    -     BEQ         PU1_AVAIL_3_LOOP
    --    LDR         r14,[sp,#0x110]             @Loads pi1_sao_offset_v
    -+    LDR         r14,[sp,#pi1_sao_v_offset]  @Loads pi1_sao_offset_v
    -     LDRSB       r11,[r14,r12]               @pi1_sao_offset_v[edge_idx]
    -     ADD         r9,r9,r11                   @pu1_src[(ht - 1) * src_strd] + pi1_sao_offset[edge_idx]
    -     USAT        r9,#8,r9                    @u1_pos_wd_ht_tmp_v = CLIP3(pu1_src[(ht - 1) * src_strd] + pi1_sao_offset[edge_idx], 0, (1 << bit_depth) - 1)
    -@@ -252,7 +262,7 @@ ulbl4:
    - PU1_AVAIL_3_LOOP:
    -     STRB        r10,[sp,#8]
    -     STRB        r9,[sp,#9]
    --    STR         r2,[sp,#0x104]              @Store pu1_src_left in sp
    -+    STR         r2,[sp,#216]                @Store pu1_src_left in sp
    - 
    -     MOV         r12,r8                      @Move ht
    -     MOV         r14,r2                      @Move pu1_src_left to pu1_src_left_cpy
    -@@ -276,7 +286,7 @@ PU1_AVAIL_2_LOOP_END:
    -     VMOV.I16    Q1,#0                       @const_min_clip = vdupq_n_s16(0)
    -     VMOV.I16    Q2,#255                     @const_max_clip = vdupq_n_u16((1 << bit_depth) - 1)
    -     VLD1.8      D6,[r6]                     @offset_tbl_u = vld1_s8(pi1_sao_offset_u)
    --    LDR         r6,[sp,#0x110]              @Loads pi1_sao_offset_v
    -+    LDR         r6,[sp,#pi1_sao_v_offset]   @Loads pi1_sao_offset_v
    -     VLD1.8      D7,[r6]                     @offset_tbl_v = vld1_s8(pi1_sao_offset_v)
    -     LDR         r2, gi1_table_edge_idx_addr_5 @table pointer
    - ulbl5:
    -@@ -291,9 +301,9 @@ ulbl5:
    -     BLE         WD_16_HT_4_LOOP             @If jump to WD_16_HT_4_LOOP
    - 
    - WIDTH_LOOP_16:
    --    LDR         r7,[sp,#0x114]              @Loads wd
    -+    LDR         r7,[sp,#wd_offset]          @Loads wd
    -     CMP         r6,r7                       @col == wd
    --    LDR         r5,[sp,#0x108]              @Loads pu1_avail
    -+    LDR         r5,[sp,#pu1_avail_offset]   @Loads pu1_avail
    - 
    -     LDRBEQ      r8,[r5]                     @pu1_avail[0]
    -     MOVNE       r8,#-1
    -@@ -314,7 +324,7 @@ SKIP_AU1_MASK_VAL:
    -     VLD1.8      D12,[r0]!                   @pu1_cur_row = vld1q_u8(pu1_src)
    -     VLD1.8      D13,[r0]                    @pu1_cur_row = vld1q_u8(pu1_src)
    -     SUB         r0,#8
    --    ADD         r5,sp,#0x4B                 @*au1_src_left_tmp
    -+    ADD         r5,sp,#75                   @*au1_src_left_tmp
    - 
    -     SUBEQ       r8,r0,r1                    @pu1_src - src_strd
    -     VMOV.I8     Q9,#0
    -@@ -326,15 +336,15 @@ SKIP_AU1_MASK_VAL:
    -     SUB         r8,#8
    -     ADD         r3,r3,#16
    - 
    --    LDR         r4,[sp,#0x118]              @Loads ht
    -+    LDR         r4,[sp,#ht_offset]          @Loads ht
    -     VCGT.U8     Q7,Q6,Q5                    @vcgtq_u8(pu1_cur_row, pu1_top_row)
    --    LDR         r7,[sp,#0x114]              @Loads wd
    -+    LDR         r7,[sp,#wd_offset]          @Loads wd
    - 
    -     SUB         r7,r7,r6                    @(wd - col)
    -     VCLT.U8     Q8,Q6,Q5                    @vcltq_u8(pu1_cur_row, pu1_top_row)
    -     ADD         r7,r7,#14                   @15 + (wd - col)
    - 
    --    LDR         r8,[sp,#0x100]              @Loads *pu1_src
    -+    LDR         r8,[sp,#212]                @Loads *pu1_src
    -     VSUB.U8     Q7,Q8,Q7                    @sign_up = vreinterpretq_s8_u8(vsubq_u8(cmp_lt, cmp_gt))
    -     ADD         r7,r8,r7                    @pu1_src[0 * src_strd + 15 + (wd - col)]
    - 
    -@@ -359,7 +369,7 @@ AU1_SRC_LEFT_LOOP:
    - 
    -     LDRH        r5,[r8,#2]                  @I
    -     VMOV.16     D19[3],r5                   @I vsetq_lane_u8
    --    LDR         r11,[sp,#0x108]             @I Loads pu1_avail
    -+    LDR         r11,[sp,#pu1_avail_offset]  @I Loads pu1_avail
    - 
    -     LDRB        r11,[r11,#2]                @I pu1_avail[2]
    -     VEXT.8      Q9,Q9,Q8,#14                @I pu1_next_row_tmp = vextq_u8(pu1_next_row_tmp, pu1_next_row, 14)
    -@@ -477,7 +487,7 @@ PU1_SRC_LOOP:
    -     VCGT.U8     Q11,Q6,Q14                  @II vcgtq_u8(pu1_cur_row, pu1_next_row_tmp)
    -     BNE         NEXT_ROW_POINTER_ASSIGNED_2 @III
    - 
    --    LDR         r5,[sp,#0x108]              @III Loads pu1_avail
    -+    LDR         r5,[sp,#pu1_avail_offset]   @III Loads pu1_avail
    -     LDRB        r5,[r5,#3]                  @III pu1_avail[3]
    -     CMP         r5,#0                       @III
    -     SUBNE       r11,r4,#4                   @III pu1_src[src_strd - 2]
    -@@ -597,7 +607,7 @@ NEXT_ROW_POINTER_ASSIGNED_2:
    -     LDRB        r9,[r0,#17]                 @load the value pu1_src_cpy[17 - src_strd]
    - 
    -     BNE         NEXT_ROW_POINTER_ASSIGNED_3
    --    LDR         r5,[sp,#0x108]              @Loads pu1_avail
    -+    LDR         r5,[sp,#pu1_avail_offset]   @Loads pu1_avail
    -     LDRB        r5,[r5,#3]                  @pu1_avail[3]
    -     CMP         r5,#0
    -     SUBNE       r8,r11,#4                   @pu1_src[src_strd - 2]
    -@@ -657,13 +667,13 @@ NEXT_ROW_POINTER_ASSIGNED_3:
    - 
    - INNER_LOOP_DONE:
    - 
    --    LDR         r8,[sp,#0x118]              @Loads ht
    -+    LDR         r8,[sp,#ht_offset]          @Loads ht
    -     VMOVN.I16   D20,Q10                     @III vmovn_s16(pi2_tmp_cur_row.val[0])
    --    ADD         r5,sp,#0x4B                 @*au1_src_left_tmp
    -+    ADD         r5,sp,#75                   @*au1_src_left_tmp
    - 
    -     LSL         r8,r8,#1
    -     VMOVN.I16   D21,Q9                      @III vmovn_s16(pi2_tmp_cur_row.val[1])
    --    LDR         r11,[sp,#0x104]             @Loads *pu1_src_left
    -+    LDR         r11,[sp,#216]               @Loads *pu1_src_left
    - 
    - SRC_LEFT_LOOP:
    -     LDR         r7,[r5],#4                  @au1_src_left_tmp[row]
    -@@ -676,7 +686,7 @@ SRC_LEFT_LOOP:
    -     CMP         r6,#8                       @Check whether residue remains
    - 
    -     BLT         RE_ASSINING_LOOP            @Jump to re-assigning loop
    --    LDR         r7,[sp,#0x114]              @Loads wd
    -+    LDR         r7,[sp,#wd_offset]          @Loads wd
    -     LDR         r0,[sp,#0x02]               @Loads *pu1_src
    -     SUB         r7,r7,r6
    -     ADD         r0,r0,r7
    -@@ -684,9 +694,9 @@ SRC_LEFT_LOOP:
    -     BEQ         WIDTH_RESIDUE               @If residue remains jump to residue loop
    - 
    - WD_16_HT_4_LOOP:
    --    LDR         r7,[sp,#0x114]              @Loads wd
    -+    LDR         r7,[sp,#wd_offset]          @Loads wd
    - 
    --    LDR         r5,[sp,#0x108]              @Loads pu1_avail
    -+    LDR         r5,[sp,#pu1_avail_offset]   @Loads pu1_avail
    -     CMP         r6,r7                       @col == wd
    - 
    -     LDRBEQ      r8,[r5]                     @pu1_avail[0]
    -@@ -716,17 +726,17 @@ SKIP_AU1_MASK_VAL_WD_16_HT_4:
    -     VLD1.8      D10,[r8]!                   @pu1_top_row = vld1q_u8(pu1_src - src_strd + 2)
    -     VLD1.8      D11,[r8]                    @pu1_top_row = vld1q_u8(pu1_src - src_strd + 2)
    -     SUB         r8,#8
    --    ADD         r5,sp,#0x4B                 @*au1_src_left_tmp
    -+    ADD         r5,sp,#75                   @*au1_src_left_tmp
    - 
    --    LDR         r4,[sp,#0x118]              @Loads ht
    -+    LDR         r4,[sp,#ht_offset]          @Loads ht
    -     VCGT.U8     Q7,Q6,Q5                    @vcgtq_u8(pu1_cur_row, pu1_top_row)
    --    LDR         r7,[sp,#0x114]              @Loads wd
    -+    LDR         r7,[sp,#wd_offset]          @Loads wd
    - 
    -     SUB         r7,r7,r6                    @(wd - col)
    -     VCLT.U8     Q8,Q6,Q5                    @vcltq_u8(pu1_cur_row, pu1_top_row)
    -     ADD         r7,r7,#14                   @15 + (wd - col)
    - 
    --    LDR         r8,[sp,#0x100]              @Loads *pu1_src
    -+    LDR         r8,[sp,#212]                @Loads *pu1_src
    -     VSUB.U8     Q7,Q8,Q7                    @sign_up = vreinterpretq_s8_u8(vsubq_u8(cmp_lt, cmp_gt))
    -     ADD         r7,r8,r7                    @pu1_src[0 * src_strd + 15 + (wd - col)]
    - 
    -@@ -744,7 +754,7 @@ AU1_SRC_LEFT_LOOP_WD_16_HT_4:
    - PU1_SRC_LOOP_WD_16_HT_4:
    -     ADD         r9,r0,r1                    @*pu1_src + src_strd
    - 
    --    LDR         r5,[sp,#0x108]              @Loads pu1_avail
    -+    LDR         r5,[sp,#pu1_avail_offset]   @Loads pu1_avail
    -     VLD1.8      D16,[r9]!                   @pu1_next_row = vld1q_u8(pu1_src_cpy + src_strd)
    -     VLD1.8      D17,[r9]                    @pu1_next_row = vld1q_u8(pu1_src_cpy + src_strd)
    -     SUB         r9,#8
    -@@ -766,7 +776,7 @@ NEXT_ROW_POINTER_ASSIGNED_WD_16_HT_4:
    - 
    -     CMP         r7,r12
    -     BLT         SIGN_UP_CHANGE_WD_16_HT_4
    --    LDR         r5,[sp,#0x108]              @Loads pu1_avail
    -+    LDR         r5,[sp,#pu1_avail_offset]   @Loads pu1_avail
    -     LDRB        r5,[r5,#2]                  @pu1_avail[2]
    -     CMP         r5,#0
    -     BNE         SIGN_UP_CHANGE_DONE_WD_16_HT_4
    -@@ -839,9 +849,9 @@ SIGN_UP_CHANGE_DONE_WD_16_HT_4:
    -     VST1.8      {Q14},[r0],r1               @vst1q_u8(pu1_src_cpy, pu1_cur_row)
    -     BNE         PU1_SRC_LOOP_WD_16_HT_4     @If not equal jump to PU1_SRC_LOOP_WD_16_HT_4
    - 
    --    LDR         r8,[sp,#0x118]              @Loads ht
    --    ADD         r5,sp,#0x4B                 @*au1_src_left_tmp
    --    LDR         r11,[sp,#0x104]             @Loads *pu1_src_left
    -+    LDR         r8,[sp,#ht_offset]          @Loads ht
    -+    ADD         r5,sp,#75                   @*au1_src_left_tmp
    -+    LDR         r11,[sp,#216]               @Loads *pu1_src_left
    - 
    - SRC_LEFT_LOOP_WD_16_HT_4:
    -     LDR         r7,[r5],#4                  @au1_src_left_tmp[row]
    -@@ -851,12 +861,16 @@ SRC_LEFT_LOOP_WD_16_HT_4:
    - 
    -     SUBS        r6,r6,#16                   @Decrement the wd loop count by 16
    -     BLE         RE_ASSINING_LOOP            @Jump to re-assigning loop
    -+    LDR         r7,[sp,#wd_offset]          @Loads wd
    -+    LDR         r0,[sp,#0x02]               @Loads *pu1_src
    -+    SUB         r7,r7,r6
    -+    ADD         r0,r0,r7
    -     BGT         WD_16_HT_4_LOOP             @If not equal jump to width_loop
    - 
    - WIDTH_RESIDUE:
    --    LDR         r7,[sp,#0x114]              @Loads wd
    -+    LDR         r7,[sp,#wd_offset]          @Loads wd
    - 
    --    LDR         r5,[sp,#0x108]              @Loads pu1_avail
    -+    LDR         r5,[sp,#pu1_avail_offset]   @Loads pu1_avail
    -     CMP         r6,r7                       @wd_residue == wd
    - 
    -     LDRBEQ      r8,[r5]                     @pu1_avail[0]
    -@@ -874,13 +888,13 @@ WIDTH_RESIDUE:
    - 
    -     ADD         r10,r10,#2                  @pu1_src - src_strd + 2
    -     VMOV.8      d8[6],r11                   @au1_mask = vsetq_lane_s8(pu1_avail[1], au1_mask, 15)
    --    ADD         r5,sp,#0x4B                 @*au1_src_left_tmp
    -+    ADD         r5,sp,#75                   @*au1_src_left_tmp
    - 
    --    LDR         r4,[sp,#0x118]              @Loads ht
    -+    LDR         r4,[sp,#ht_offset]          @Loads ht
    -     VMOV.8      d8[7],r11                   @au1_mask = vsetq_lane_s8(pu1_avail[1], au1_mask, 15)
    --    LDR         r7,[sp,#0x114]              @Loads wd
    -+    LDR         r7,[sp,#wd_offset]          @Loads wd
    - 
    --    LDR         r8,[sp,#0x100]              @Loads *pu1_src
    -+    LDR         r8,[sp,#212]                @Loads *pu1_src
    -     VLD1.8      D10,[r10]!                  @pu1_top_row = vld1q_u8(pu1_src - src_strd + 2)
    -     VLD1.8      D11,[r10]                   @pu1_top_row = vld1q_u8(pu1_src - src_strd + 2)
    -     SUB         r10,#8
    -@@ -913,7 +927,7 @@ PU1_SRC_LOOP_RESIDUE:
    -     VLD1.8      D16,[r9]!                   @pu1_next_row = vld1q_u8(pu1_src_cpy + src_strd)
    -     VLD1.8      D17,[r9]                    @pu1_next_row = vld1q_u8(pu1_src_cpy + src_strd)
    -     SUB         r9,#8
    --    LDR         r5,[sp,#0x108]              @Loads pu1_avail
    -+    LDR         r5,[sp,#pu1_avail_offset]   @Loads pu1_avail
    - 
    -     LDRB        r5,[r5,#3]                  @pu1_avail[3]
    -     ADD         r8,r14,r11,LSL #1           @pu1_src_left_cpy[(ht_tmp - row) * 2]
    -@@ -936,7 +950,7 @@ NEXT_ROW_POINTER_ASSIGNED_RESIDUE:
    -     VEXT.8      Q9,Q9,Q8,#14                @pu1_next_row_tmp = vextq_u8(pu1_next_row_tmp, pu1_next_row, 14)
    - 
    -     BLT         SIGN_UP_CHANGE_RESIDUE
    --    LDR         r5,[sp,#0x108]              @Loads pu1_avail
    -+    LDR         r5,[sp,#pu1_avail_offset]   @Loads pu1_avail
    -     LDRB        r5,[r5,#2]                  @pu1_avail[2]
    -     CMP         r5,#0
    -     BNE         SIGN_UP_CHANGE_DONE_RESIDUE
    -@@ -1003,10 +1017,10 @@ SIGN_UP_CHANGE_DONE_RESIDUE:
    - 
    -     BNE         PU1_SRC_LOOP_RESIDUE        @If not equal jump to PU1_SRC_LOOP
    - 
    --    LDR         r8,[sp,#0x118]              @Loads ht
    --    ADD         r5,sp,#0x4B                 @*au1_src_left_tmp
    -+    LDR         r8,[sp,#ht_offset]          @Loads ht
    -+    ADD         r5,sp,#75                   @*au1_src_left_tmp
    - 
    --    LDR         r11,[sp,#0x104]             @Loads *pu1_src_left
    -+    LDR         r11,[sp,#216]               @Loads *pu1_src_left
    - 
    - SRC_LEFT_LOOP_RESIDUE:
    -     LDR         r7,[r5],#4                  @au1_src_left_tmp[row]
    -@@ -1016,10 +1030,10 @@ SRC_LEFT_LOOP_RESIDUE:
    - 
    - 
    - RE_ASSINING_LOOP:
    --    LDR         r7,[sp,#0x114]              @Loads wd
    --    LDR         r8,[sp,#0x118]              @Loads ht
    -+    LDR         r7,[sp,#wd_offset]          @Loads wd
    -+    LDR         r8,[sp,#ht_offset]          @Loads ht
    - 
    --    LDR         r0,[sp,#0x100]              @Loads *pu1_src
    -+    LDR         r0,[sp,#212]                @Loads *pu1_src
    -     SUB         r10,r7,#2                   @wd - 2
    - 
    -     LDRH        r9,[sp,#6]
    -@@ -1028,7 +1042,7 @@ RE_ASSINING_LOOP:
    -     STRH        r9,[r0,r10]                 @pu1_src_org[0] = u1_pos_0_0_tmp
    -     MLA         r6,r8,r1,r0                 @pu1_src[(ht - 1) * src_strd]
    - 
    --    LDR         r4,[sp,#0xFC]               @Loads pu1_src_top_left
    -+    LDR         r4,[sp,#pu1_src_top_left_offset]               @Loads pu1_src_top_left
    - 
    -     LDRH        r9,[sp,#8]
    -     ADD         r12,sp,#10
    -@@ -1037,7 +1051,7 @@ RE_ASSINING_LOOP:
    +diff --git a/decoder/impeg2d_api_main.c b/decoder/impeg2d_api_main.c
    +index c0813c4..847c4f7 100644
    +--- a/decoder/impeg2d_api_main.c
    ++++ b/decoder/impeg2d_api_main.c
    +@@ -125,6 +125,7 @@
    + 
    + void impeg2d_init_arch(void *pv_codec);
    + void impeg2d_init_function_ptr(void *pv_codec);
    ++UWORD32 impeg2d_get_outbuf_size(WORD32 pic_wd,UWORD32 pic_ht, WORD32 u1_chroma_format,UWORD32 *p_buf_size);
    + 
    + /*****************************************************************************/
    + /*                                                                           */
    +@@ -211,6 +212,8 @@ IV_API_CALL_STATUS_T impeg2d_api_set_display_frame(iv_obj_t *ps_dechdl,
    +     dec_state_t *ps_dec_state;
    +     dec_state_multi_core_t *ps_dec_state_multi_core;
    +     UWORD32 u4_num_disp_bufs;
    ++    UWORD32 u4_disp_buf_size[3];
    ++    UWORD32 num_bufs;
    + 
    + 
    +     dec_disp_ip = (ivd_set_display_frame_ip_t  *)pv_api_ip;
    +@@ -224,12 +227,41 @@ IV_API_CALL_STATUS_T impeg2d_api_set_display_frame(iv_obj_t *ps_dechdl,
    +     ps_dec_state_multi_core = (dec_state_multi_core_t *) (ps_dechdl->pv_codec_handle);
    +     ps_dec_state = ps_dec_state_multi_core->ps_dec_state[0];
    + 
    ++    num_bufs = dec_disp_ip->s_disp_buffer[0].u4_num_bufs;
    ++
    +     if(ps_dec_state->u4_share_disp_buf)
    +     {
    +         pic_buf_t *ps_pic_buf;
    +         ps_pic_buf = (pic_buf_t *)ps_dec_state->pv_pic_buf_base;
    ++
    ++        /* Get the sizes of the first buffer structure. Compare this with the
    ++         * rest to make sure all the buffers are of the same size.
    ++         */
    ++        u4_disp_buf_size[0] =
    ++            dec_disp_ip->s_disp_buffer[0].u4_min_out_buf_size[0];
    ++        u4_disp_buf_size[1] =
    ++            dec_disp_ip->s_disp_buffer[0].u4_min_out_buf_size[1];
    ++        u4_disp_buf_size[2] =
    ++            dec_disp_ip->s_disp_buffer[0].u4_min_out_buf_size[2];
    +         for(i = 0; i < u4_num_disp_bufs; i++)
    +         {
    ++            /* Verify all buffer structures have the same sized buffers as the
    ++             * first buffer structure*/
    ++            if ((dec_disp_ip->s_disp_buffer[i].u4_min_out_buf_size[0]
    ++                 != u4_disp_buf_size[0])
    ++                 || (dec_disp_ip->s_disp_buffer[i].u4_min_out_buf_size[1]
    ++                     != u4_disp_buf_size[1])
    ++                 || (dec_disp_ip->s_disp_buffer[i].u4_min_out_buf_size[2]
    ++                     != u4_disp_buf_size[2]))
    ++            {
    ++              return IV_FAIL;
    ++            }
    ++            /* Verify all buffer structures have the same number of
    ++             * buffers (e.g. y, u, v) */
    ++            if (dec_disp_ip->s_disp_buffer[i].u4_num_bufs != num_bufs)
    ++            {
    ++                return IV_FAIL;
    ++            }
      
    -     LDRH        r10,[sp]                    @load u1_src_top_left_tmp from stack pointer
    -     STRH        r10,[r4]                    @*pu1_src_top_left = u1_src_top_left_tmp
    --    LDR         r3,[sp,#0x10C]              @Loads pu1_src_top
    -+    LDR         r3,[sp,#220]                @Loads pu1_src_top
    +             ps_pic_buf->pu1_y = dec_disp_ip->s_disp_buffer[i].pu1_bufs[0];
    +             if(IV_YUV_420P == ps_dec_state->i4_chromaFormat)
    +@@ -428,7 +460,11 @@ void impeg2d_fill_mem_rec(impeg2d_fill_mem_rec_ip_t *ps_ip,
    +     UWORD32 u4_deinterlace;
    +     UNUSED(u4_deinterlace);
    +     max_frm_width = ALIGN16(ps_ip->s_ivd_fill_mem_rec_ip_t.u4_max_frm_wd);
    +-    max_frm_height = ALIGN16(ps_ip->s_ivd_fill_mem_rec_ip_t.u4_max_frm_ht);
    ++    /* In error clips with field prediction, the mv may incorrectly refer to
    ++    * the last MB row, causing an out of bounds read access. Allocating 8 extra
    ++    * rows to handle this. Adding another extra row to handle half_y prediction.
    ++    */
    ++    max_frm_height = ALIGN32(ps_ip->s_ivd_fill_mem_rec_ip_t.u4_max_frm_ht) + 9;
    + 
    +     max_frm_size = (max_frm_width * max_frm_height * 3) >> 1;/* 420 P */
    + 
    +@@ -760,35 +796,6 @@ IV_API_CALL_STATUS_T impeg2d_api_get_buf_info(iv_obj_t *ps_dechdl,
    +     ps_ctl_bufinfo_op->s_ivd_ctl_getbufinfo_op_t.u4_min_num_in_bufs = 1;
    +     ps_ctl_bufinfo_op->s_ivd_ctl_getbufinfo_op_t.u4_min_num_out_bufs = 1;
    + 
    +-    if(ps_dec_state->i4_chromaFormat == IV_YUV_420P)
    +-    {
    +-        ps_ctl_bufinfo_op->s_ivd_ctl_getbufinfo_op_t.u4_min_num_out_bufs =
    +-                        MIN_OUT_BUFS_420;
    +-    }
    +-    else if((ps_dec_state->i4_chromaFormat == IV_YUV_420SP_UV)
    +-                    || (ps_dec_state->i4_chromaFormat == IV_YUV_420SP_VU))
    +-    {
    +-        ps_ctl_bufinfo_op->s_ivd_ctl_getbufinfo_op_t.u4_min_num_out_bufs =
    +-                        MIN_OUT_BUFS_420SP;
    +-    }
    +-    else if(ps_dec_state->i4_chromaFormat == IV_YUV_422ILE)
    +-    {
    +-        ps_ctl_bufinfo_op->s_ivd_ctl_getbufinfo_op_t.u4_min_num_out_bufs =
    +-                        MIN_OUT_BUFS_422ILE;
    +-    }
    +-    else if(ps_dec_state->i4_chromaFormat == IV_RGB_565)
    +-    {
    +-        ps_ctl_bufinfo_op->s_ivd_ctl_getbufinfo_op_t.u4_min_num_out_bufs =
    +-                        MIN_OUT_BUFS_RGB565;
    +-    }
    +-    else
    +-    {
    +-        //Invalid chroma format; Error code may be updated, verify in testing if needed
    +-        ps_ctl_bufinfo_op->s_ivd_ctl_getbufinfo_op_t.u4_error_code =
    +-                        IVD_INIT_DEC_COL_FMT_NOT_SUPPORTED;
    +-        return IV_FAIL;
    +-    }
    +-
    +     for(u4_i = 0; u4_i < IVD_VIDDEC_MAX_IO_BUFFERS; u4_i++)
    +     {
    +         ps_ctl_bufinfo_op->s_ivd_ctl_getbufinfo_op_t.u4_min_in_buf_size[u4_i] =
    +@@ -820,33 +827,22 @@ IV_API_CALL_STATUS_T impeg2d_api_get_buf_info(iv_obj_t *ps_dechdl,
    +     {
    +         u4_stride = ps_dec_state->u4_frm_buf_stride;
    +     }
    +-    u4_height = ((ps_dec_state->u2_frame_height + 15) >> 4) << 4;
    ++    u4_stride = ALIGN16(u4_stride);
    ++    u4_height = ALIGN32(ps_dec_state->u2_frame_height) + 9;
      
    - SRC_TOP_LOOP:
    -     VLD1.8      D0,[r12]!                   @pu1_src_top[col] = au1_src_top_tmp[col]
    -@@ -1046,7 +1060,8 @@ SRC_TOP_LOOP:
    -     BNE         SRC_TOP_LOOP
    +-    if(ps_dec_state->i4_chromaFormat == IV_YUV_420P)
    +-    {
    +-        ps_ctl_bufinfo_op->s_ivd_ctl_getbufinfo_op_t.u4_min_out_buf_size[0] =
    +-                        (u4_stride * u4_height);
    +-        ps_ctl_bufinfo_op->s_ivd_ctl_getbufinfo_op_t.u4_min_out_buf_size[1] =
    +-                        (u4_stride * u4_height) >> 2;
    +-        ps_ctl_bufinfo_op->s_ivd_ctl_getbufinfo_op_t.u4_min_out_buf_size[2] =
    +-                        (u4_stride * u4_height) >> 2;
    +-    }
    +-    else if((ps_dec_state->i4_chromaFormat == IV_YUV_420SP_UV)
    +-                    || (ps_dec_state->i4_chromaFormat == IV_YUV_420SP_VU))
    +-    {
    +-        ps_ctl_bufinfo_op->s_ivd_ctl_getbufinfo_op_t.u4_min_out_buf_size[0] =
    +-                        (u4_stride * u4_height);
    +-        ps_ctl_bufinfo_op->s_ivd_ctl_getbufinfo_op_t.u4_min_out_buf_size[1] =
    +-                        (u4_stride * u4_height) >> 1;
    +-        ps_ctl_bufinfo_op->s_ivd_ctl_getbufinfo_op_t.u4_min_out_buf_size[2] = 0;
    +-    }
    +-    else if(ps_dec_state->i4_chromaFormat == IV_YUV_422ILE)
    ++    ps_ctl_bufinfo_op->s_ivd_ctl_getbufinfo_op_t.u4_min_num_out_bufs =
    ++                    impeg2d_get_outbuf_size(
    ++                                    u4_stride,
    ++                                    u4_height,
    ++                                    ps_dec_state->i4_chromaFormat,
    ++                                    &ps_ctl_bufinfo_op->s_ivd_ctl_getbufinfo_op_t.u4_min_out_buf_size[0]);
    ++
    ++    if (0 == ps_ctl_bufinfo_op->s_ivd_ctl_getbufinfo_op_t.u4_min_num_out_bufs)
    +     {
    +-        ps_ctl_bufinfo_op->s_ivd_ctl_getbufinfo_op_t.u4_min_out_buf_size[0] =
    +-                        (u4_stride * u4_height) * 2;
    +-        ps_ctl_bufinfo_op->s_ivd_ctl_getbufinfo_op_t.u4_min_out_buf_size[1] =
    +-                        ps_ctl_bufinfo_op->s_ivd_ctl_getbufinfo_op_t.u4_min_out_buf_size[2] =
    +-                                        0;
    ++        //Invalid chroma format; Error code may be updated, verify in testing if needed
    ++        ps_ctl_bufinfo_op->s_ivd_ctl_getbufinfo_op_t.u4_error_code =
    ++                        IVD_INIT_DEC_COL_FMT_NOT_SUPPORTED;
    ++        return IV_FAIL;
    +     }
      
    - END_LOOPS:
    --    ADD         sp,sp,#0xD4
    -+    ADD         sp,sp,#224
    -+    vpop        {d8  -  d15}
    -     LDMFD       sp!,{r4-r12,r15}            @Reload the registers from SP
    +     /* Adding initialization for 2 uninitialized values */
    +@@ -1022,6 +1018,7 @@ IV_API_CALL_STATUS_T impeg2d_api_reset(iv_obj_t *ps_dechdl,
      
    +             ps_dec_state->u2_header_done    = 0;  /* Header decoding not done */
    +             ps_dec_state->u4_frm_buf_stride = 0;
    ++            ps_dec_state->i4_pic_count      = 0;
    +             ps_dec_state->u2_is_mpeg2       = 0;
    +             ps_dec_state->aps_ref_pics[0] = NULL;
    +             ps_dec_state->aps_ref_pics[1] = NULL;
    +@@ -1508,6 +1505,100 @@ IV_API_CALL_STATUS_T impeg2d_api_fill_mem_rec(void *pv_api_ip,void *pv_api_op)
      
    -diff --git a/common/arm/ihevc_weighted_pred_bi.s b/common/arm/ihevc_weighted_pred_bi.s
    -index 5308423..8845b8b 100644
    ---- a/common/arm/ihevc_weighted_pred_bi.s
    -+++ b/common/arm/ihevc_weighted_pred_bi.s
    -@@ -134,6 +134,18 @@
    - @   r14 =>  ht
    - @   r7  =>  wd
    + }
      
    -+.equ    src_strd2_offset,       104
    -+.equ    dst_strd_offset,        108
    -+.equ    wgt0_offset,            112
    -+.equ    off0_offset,            116
    -+.equ    wgt1_offset,            120
    -+.equ    off1_offset,            124
    -+.equ    shift_offset,           128
    -+.equ    lvl_shift1_offset,      132
    -+.equ    lvl_shift2_offset,      136
    -+.equ    ht_offset,              140
    -+.equ    wd_offset,              144
    ++UWORD32 impeg2d_get_outbuf_size(WORD32 pic_wd,UWORD32 pic_ht, WORD32 u1_chroma_format,UWORD32 *p_buf_size)
    ++{
    ++    UWORD32 u4_min_num_out_bufs = 0;
    ++    if(u1_chroma_format == IV_YUV_420P)
    ++        u4_min_num_out_bufs = MIN_OUT_BUFS_420;
    ++    else if(u1_chroma_format == IV_YUV_422ILE)
    ++        u4_min_num_out_bufs = MIN_OUT_BUFS_422ILE;
    ++    else if(u1_chroma_format == IV_RGB_565)
    ++        u4_min_num_out_bufs = MIN_OUT_BUFS_RGB565;
    ++    else if((u1_chroma_format == IV_YUV_420SP_UV)
    ++                    || (u1_chroma_format == IV_YUV_420SP_VU))
    ++        u4_min_num_out_bufs = MIN_OUT_BUFS_420SP;
     +
    - .text
    - .align 4
    - 
    -@@ -147,32 +159,33 @@
    - ihevc_weighted_pred_bi_a9q:
    - 
    -     stmfd       sp!, {r4-r12, r14}          @stack stores the values of the arguments
    -+    vpush       {d8  -  d15}
    - 
    --    ldr         r6,[sp,#48]                 @load wgt0
    --    ldr         r11,[sp,#68]                @load lvl_shift1
    --    ldr         r12,[sp,#72]                @load lvl_shift2
    -+    ldr         r6,[sp,#wgt0_offset]        @load wgt0
    -+    ldr         r11,[sp,#lvl_shift1_offset] @load lvl_shift1
    -+    ldr         r12,[sp,#lvl_shift2_offset] @load lvl_shift2
    -     vmov.s16    d7[0],r6                    @moved for scalar multiplication
    -     mul         r4,r11,r6                   @lvl_shift1 * wgt0
    --    ldr         r8,[sp,#56]                 @load wgt1
    --    ldr         r7,[sp,#52]                 @load off0
    -+    ldr         r8,[sp,#wgt1_offset]        @load wgt1
    -+    ldr         r7,[sp,#off0_offset]        @load off0
    -     vmov.s16    d7[1],r8                    @moved for scalar multiplication
    -     mla         r4,r12,r8,r4                @(lvl_shift1 * wgt0) + (lvl_shift2 * wgt1)
    --    ldr         r9,[sp,#60]                 @load off1
    -+    ldr         r9,[sp,#off1_offset]        @load off1
    -     add         r5,r7,r9                    @off0 + off1
    --    ldr         r10,[sp,#64]                @load shift
    -+    ldr         r10,[sp,#shift_offset]      @load shift
    -     add         r5,r5,#1                    @off0 + off1 + 1
    -     sub         r14,r10,#1                  @shift - 1
    --    ldr         r7,[sp,#80]                 @load wd
    -+    ldr         r7,[sp,#wd_offset]          @load wd
    -     lsl         r5,r5,r14                   @((off0 + off1 + 1) << (shift - 1))
    -     vdup.u32    q14,r10                     @vmovq_n_s32(0-shift)
    -     add         r4,r4,r5                    @tmp_lvl_shift += ((off0 + off1 + 1) << (shift - 1))
    -     vdup.u32    q15,r4                      @vmovq_n_s32(tmp_lvl_shift)
    -     vneg.s32    q14,q14
    --    ldr         r4,[sp,#40]                 @load src_strd2
    -+    ldr         r4,[sp,#src_strd2_offset]   @load src_strd2
    -     lsl         r9,r7,#1
    --    ldr         r5,[sp,#44]                 @load dst_strd
    -+    ldr         r5,[sp,#dst_strd_offset]    @load dst_strd
    -     lsl         r3,r3,#1
    --    ldr         r14,[sp,#76]                @load ht
    -+    ldr         r14,[sp,#ht_offset]         @load ht
    -     lsl         r4,r4,#1
    - 
    -     cmp         r14,#0                      @check ht == 0
    -@@ -260,6 +273,7 @@ end_core_loop:
    -     bgt         core_loop                   @if ht is greater than 0 goto outer_loop
    - 
    - end_loops:
    -+    vpop        {d8  -  d15}
    -     ldmfd       sp!,{r4-r12,r15}            @reload the registers from sp
    - 
    - 
    -diff --git a/common/arm/ihevc_weighted_pred_bi_default.s b/common/arm/ihevc_weighted_pred_bi_default.s
    -index 6bdb8cc..5b369be 100644
    ---- a/common/arm/ihevc_weighted_pred_bi_default.s
    -+++ b/common/arm/ihevc_weighted_pred_bi_default.s
    -@@ -107,6 +107,14 @@
    - @   r7 =>  lvl_shift2
    - @   r8 =>  ht
    - @   r9 =>  wd
    ++    if(u1_chroma_format == IV_YUV_420P)
    ++    {
    ++        p_buf_size[0] = (pic_wd * pic_ht);
    ++        p_buf_size[1] = (pic_wd * pic_ht)
    ++                        >> 2;
    ++        p_buf_size[2] = (pic_wd * pic_ht)
    ++                        >> 2;
    ++    }
    ++    else if(u1_chroma_format == IV_YUV_422ILE)
    ++    {
    ++        p_buf_size[0] = (pic_wd * pic_ht)
    ++                        * 2;
    ++        p_buf_size[1] =
    ++                        p_buf_size[2] = 0;
    ++    }
    ++    else if(u1_chroma_format == IV_RGB_565)
    ++    {
    ++        p_buf_size[0] = (pic_wd * pic_ht)
    ++                        * 2;
    ++        p_buf_size[1] =
    ++                        p_buf_size[2] = 0;
    ++    }
    ++    else if((u1_chroma_format == IV_YUV_420SP_UV)
    ++                    || (u1_chroma_format == IV_YUV_420SP_VU))
    ++    {
    ++        p_buf_size[0] = (pic_wd * pic_ht);
    ++        p_buf_size[1] = (pic_wd * pic_ht)
    ++                        >> 1;
    ++        p_buf_size[2] = 0;
    ++    }
     +
    -+.equ    src_strd2_offset,       104
    -+.equ    dst_strd_offset,        108
    -+.equ    lvl_shift1_offset,      112
    -+.equ    lvl_shift2_offset,      116
    -+.equ    ht_offset,              120
    -+.equ    wd_offset,              124
    ++    return u4_min_num_out_bufs;
    ++}
     +
    - .text
    - .syntax unified
    - .align 4
    -@@ -121,14 +129,15 @@
    - ihevc_weighted_pred_bi_default_a9q:
    - 
    -     stmfd       sp!, {r4-r12, r14}          @stack stores the values of the arguments
    --    ldr         r4,[sp,#40]                 @load src_strd2
    -+    vpush       {d8  -  d15}
    -+    ldr         r4,[sp,#src_strd2_offset]   @load src_strd2
    -     lsl         r3,r3,#1
    --    ldr         r5,[sp,#44]                 @load dst_strd
    --    ldr         r6,[sp,#48]                 @load lvl_shift1
    -+    ldr         r5,[sp,#dst_strd_offset]    @load dst_strd
    -+    ldr         r6,[sp,#lvl_shift1_offset]  @load lvl_shift1
    -     lsl         r4,r4,#1
    --    ldr         r7,[sp,#52]                 @load lvl_shift2
    --    ldr         r8,[sp,#56]                 @load ht
    --    ldr         r9,[sp,#60]                 @load wd
    -+    ldr         r7,[sp,#lvl_shift2_offset]  @load lvl_shift2
    -+    ldr         r8,[sp,#ht_offset]          @load ht
    -+    ldr         r9,[sp,#wd_offset]          @load wd
    -     vdup.16     q2,r6                       @lvl_shift1_t = vmov_n_s16((int16_t)lvl_shift1)
    -     vdup.16     q3,r7                       @lvl_shift2_t = vmov_n_s16((int16_t)lvl_shift2)
    -     vmov.i16    q0,#0x40                    @tmp_lvl_shift = 1 << (shift - 1)
    -@@ -488,6 +497,7 @@ end_core_loop_16:
    - 
    - 
    - end_loops:
    -+    vpop        {d8  -  d15}
    -     ldmfd       sp!,{r4-r12,r15}            @reload the registers from sp
    - 
    - 
    -diff --git a/common/arm/ihevc_weighted_pred_uni.s b/common/arm/ihevc_weighted_pred_uni.s
    -index e9b69c1..1f99ff8 100644
    ---- a/common/arm/ihevc_weighted_pred_uni.s
    -+++ b/common/arm/ihevc_weighted_pred_uni.s
    -@@ -112,6 +112,13 @@
    - @   r8 =>   ht
    - @   r9  =>  wd
    - 
    -+.equ    wgt0_offset,        104
    -+.equ    off0_offset,        108
    -+.equ    shift_offset,       112
    -+.equ    lvl_shift_offset,   116
    -+.equ    ht_offset,          120
    -+.equ    wd_offset,          124
    ++WORD32 check_app_out_buf_size(dec_state_t *ps_dec)
    ++{
    ++    UWORD32 au4_min_out_buf_size[IVD_VIDDEC_MAX_IO_BUFFERS];
    ++    UWORD32 u4_min_num_out_bufs, i;
    ++    UWORD32 pic_wd, pic_ht;
     +
    - .text
    - .align 4
    - 
    -@@ -125,16 +132,17 @@
    - ihevc_weighted_pred_uni_a9q:
    - 
    -     stmfd       sp!, {r4-r12, r14}          @stack stores the values of the arguments
    -+    vpush       {d8  -  d15}
    - 
    --    ldr         r4,[sp,#40]                 @load wgt0
    --    ldr         r7,[sp,#52]                 @load lvl_shift
    -+    ldr         r4,[sp,#wgt0_offset]        @load wgt0
    -+    ldr         r7,[sp,#lvl_shift_offset]   @load lvl_shift
    -     mov         r11,#1
    --    ldr         r5,[sp,#44]                 @load off0
    -+    ldr         r5,[sp,#off0_offset]        @load off0
    -     mul         r10,r7,r4                   @lvl_shift * wgt0
    --    ldr         r6,[sp,#48]                 @load shift
    --    ldr         r8,[sp,#56]                 @load ht
    -+    ldr         r6,[sp,#shift_offset]       @load shift
    -+    ldr         r8,[sp,#ht_offset]          @load ht
    -     add         r10,r10,r5,lsl r6           @lvl_shift * wgt0 + (off0 << shift)
    --    ldr         r9,[sp,#60]                 @load wt
    -+    ldr         r9,[sp,#wd_offset]          @load wt
    -     sub         r12,r6,#1
    -     vmov.s16    d0[0],r4                    @moved for scalar multiplication
    -     lsl         r2,r2,#1
    -@@ -214,6 +222,7 @@ end_core_loop:
    -     bgt         core_loop                   @if ht is greater than 0 goto outer_loop
    - 
    - end_loops:
    -+    vpop        {d8  -  d15}
    -     ldmfd       sp!,{r4-r12,r15}            @reload the registers from sp
    - 
    - 
    -diff --git a/common/ihevc_structs.h b/common/ihevc_structs.h
    -index 93d2ad4..baa6375 100644
    ---- a/common/ihevc_structs.h
    -+++ b/common/ihevc_structs.h
    -@@ -644,33 +644,33 @@ typedef struct
    -      * if 1, , for the highest temporal sub-layers, the temporal distance between the HRD output times
    -      * of consecutive pictures in output order is constrained refer to Table E-6
    -      */
    --    UWORD8 au1_fixed_pic_rate_general_flag[6];
    -+    UWORD8 au1_fixed_pic_rate_general_flag[VPS_MAX_SUB_LAYERS];
    - 
    --    UWORD8 au1_fixed_pic_rate_within_cvs_flag[6];
    -+    UWORD8 au1_fixed_pic_rate_within_cvs_flag[VPS_MAX_SUB_LAYERS];
    - 
    -     /**
    -      * if 1, , for the highest temporal sub-layers, the temporal distance (in clock ticks) between the
    -      * element units that specify HRD output times of consecutive pictures in output order is constrained
    -      * refer to Table E-6
    -      */
    --    UWORD8 au1_elemental_duration_in_tc_minus1[6];
    -+    UWORD8 au1_elemental_duration_in_tc_minus1[VPS_MAX_SUB_LAYERS];
    - 
    -     /**
    -      * specifies the HRD operational mode
    -      */
    --    UWORD8 au1_low_delay_hrd_flag[6];
    -+    UWORD8 au1_low_delay_hrd_flag[VPS_MAX_SUB_LAYERS];
    - 
    -     /**
    -      * 1 specifies the number of alternative CPB specifications in the
    -      * bitstream of the cvs when HighestTid is equal to i
    -      */
    --    UWORD8 au1_cpb_cnt_minus1[6];
    -+    UWORD8 au1_cpb_cnt_minus1[VPS_MAX_SUB_LAYERS];
    - 
    - 
    -     /**
    -      * VUI level Sub-layer HRD parameters
    -      */
    --    sub_lyr_hrd_params_t as_sub_layer_hrd_params[6];
    -+    sub_lyr_hrd_params_t as_sub_layer_hrd_params[VPS_MAX_SUB_LAYERS];
    - 
    - }hrd_params_t;
    - 
    -diff --git a/decoder/ihevcd_api.c b/decoder/ihevcd_api.c
    -index c661083..2ae90b0 100644
    ---- a/decoder/ihevcd_api.c
    -+++ b/decoder/ihevcd_api.c
    -@@ -1215,7 +1215,7 @@ WORD32 ihevcd_allocate_static_bufs(iv_obj_t **pps_codec_obj,
    - 
    -     /* Request memory for static bitstream buffer which holds bitstream after emulation prevention */
    -     size = MIN_BITSBUF_SIZE;
    --    pv_buf = pf_aligned_alloc(pv_mem_ctxt, 128, size);
    -+    pv_buf = pf_aligned_alloc(pv_mem_ctxt, 128, size + 16); //Alloc extra for parse optimization
    -     RETURN_IF((NULL == pv_buf), IV_FAIL);
    -     ps_codec->pu1_bitsbuf_static = pv_buf;
    -     ps_codec->u4_bitsbuf_size_static = size;
    -@@ -1867,10 +1867,10 @@ WORD32 ihevcd_allocate_dynamic_bufs(codec_t *ps_codec)
    -     }
    - 
    -     /* Max CTBs in a row */
    --    size  = wd / MIN_CTB_SIZE + 2 /* Top row and bottom row extra. This ensures accessing left,top in first row
    --                                              and right in last row will not result in invalid access*/;
    -+    size  = wd / MIN_CTB_SIZE;
    -     /* Max CTBs in a column */
    --    size *= ht / MIN_CTB_SIZE;
    -+    size *= (ht / MIN_CTB_SIZE + 2) /* Top row and bottom row extra. This ensures accessing left,top in first row
    -+                                              and right in last row will not result in invalid access*/;
    - 
    -     size *= sizeof(UWORD16);
    -     pv_buf = ps_codec->pf_aligned_alloc(pv_mem_ctxt, 128, size);
    -@@ -1908,7 +1908,7 @@ WORD32 ihevcd_allocate_dynamic_bufs(codec_t *ps_codec)
    -     size = wd * ht;
    -     if(size > MIN_BITSBUF_SIZE)
    -     {
    --        pv_buf = ps_codec->pf_aligned_alloc(pv_mem_ctxt, 128, size);
    -+        pv_buf = ps_codec->pf_aligned_alloc(pv_mem_ctxt, 128, size + 16); //Alloc extra for parse optimization
    -         RETURN_IF((NULL == pv_buf), IV_FAIL);
    -         ps_codec->pu1_bitsbuf_dynamic = pv_buf;
    -         ps_codec->u4_bitsbuf_size_dynamic = size;
    -diff --git a/decoder/ihevcd_decode.c b/decoder/ihevcd_decode.c
    -index d656519..d2ea7a5 100644
    ---- a/decoder/ihevcd_decode.c
    -+++ b/decoder/ihevcd_decode.c
    -@@ -69,6 +69,7 @@
    - #include "ihevcd_fmt_conv.h"
    - #include "ihevcd_job_queue.h"
    - #include "ihevcd_debug.h"
    -+#include "ihevcd_parse_slice.h"
    - #include "ihevcd_process_slice.h"
    - #include "ihevcd_ittiam_logo.h"
    - #include "ihevcd_profile.h"
    -@@ -81,6 +82,7 @@
    - #define NUM_FRAMES_LIMIT 0x7FFFFFFF
    - #endif
    - 
    -+IHEVCD_ERROR_T ihevcd_check_out_buf_size(codec_t *ps_codec);
    - IHEVCD_ERROR_T ihevcd_fmt_conv(codec_t *ps_codec,
    -                                process_ctxt_t *ps_proc,
    -                                UWORD8 *pu1_y_dst,
    -@@ -203,6 +205,18 @@ static void ihevcd_fill_outargs(codec_t *ps_codec,
    - 
    -     ps_dec_op->u4_output_present = 0;
    -     ps_dec_op->u4_progressive_frame_flag = 1;
    -+    if(ps_codec->i4_sps_done)
    ++    pic_wd = ps_dec->u2_horizontal_size;
    ++    pic_ht = ps_dec->u2_vertical_size;
    ++
    ++    if(ps_dec->u4_frm_buf_stride > pic_wd)
    ++        pic_wd = ps_dec->u4_frm_buf_stride;
    ++
    ++    u4_min_num_out_bufs = impeg2d_get_outbuf_size(pic_wd, pic_ht, ps_dec->i4_chromaFormat, &au4_min_out_buf_size[0]);
    ++
    ++    if (0 == ps_dec->u4_share_disp_buf)
     +    {
    -+        sps_t *ps_sps = (ps_codec->s_parse.ps_sps_base + ps_codec->i4_sps_id);
    -+        profile_tier_lvl_info_t *ps_ptl;
    -+        ps_ptl = &ps_sps->s_ptl;
    -+        if((0 == ps_ptl->s_ptl_gen.i1_general_progressive_source_flag) &&
    -+           (1 == ps_ptl->s_ptl_gen.i1_general_interlaced_source_flag))
    ++        if(ps_dec->ps_out_buf->u4_num_bufs < u4_min_num_out_bufs)
    ++        {
    ++            return IV_FAIL;
    ++        }
    ++
    ++        for (i = 0 ; i < u4_min_num_out_bufs; i++)
     +        {
    -+            ps_dec_op->u4_progressive_frame_flag = 0;
    ++            if(ps_dec->ps_out_buf->u4_min_out_buf_size[i] < au4_min_out_buf_size[i])
    ++                return (IV_FAIL);
     +        }
     +    }
    ++    else
    ++    {
    ++        if(ps_dec->as_disp_buffers[0].u4_num_bufs < u4_min_num_out_bufs)
    ++            return IV_FAIL;
     +
    -     ps_dec_op->u4_is_ref_flag = 1;
    -     ps_dec_op->e_output_format = ps_codec->e_chroma_fmt;
    -     ps_dec_op->u4_is_ref_flag = 1;
    -@@ -224,7 +238,30 @@ static void ihevcd_fill_outargs(codec_t *ps_codec,
    -     if(ps_codec->ps_disp_buf)
    -     {
    -         pic_buf_t *ps_disp_buf = ps_codec->ps_disp_buf;
    -+        sei_params_t *ps_sei = &ps_disp_buf->s_sei_params;
    - 
    -+        if(ps_sei->i1_sei_parameters_present_flag &&
    -+           ps_sei->i1_pic_timing_params_present_flag)
    ++        for (i = 0 ; i < u4_min_num_out_bufs; i++)
     +        {
    -+            UWORD32 u4_pic_struct;
    -+            u4_pic_struct = ps_sei->s_pic_timing_sei_params.u4_pic_struct;
    -+            switch(u4_pic_struct)
    -+            {
    -+                case 1:
    -+                    ps_dec_op->e4_fld_type = IV_TOP_FLD;
    -+                    ps_dec_op->u4_progressive_frame_flag = 0;
    -+                    break;
    -+                case 2:
    -+                    ps_dec_op->e4_fld_type = IV_BOT_FLD;
    -+                    ps_dec_op->u4_progressive_frame_flag = 0;
    -+                    break;
    -+                case 0:
    -+                default:
    -+                    ps_dec_op->e4_fld_type = IV_FLD_TYPE_DEFAULT;
    -+                    ps_dec_op->u4_progressive_frame_flag = 1;
    -+                    break;
    -+            }
    ++            /* We need to check only with the disp_buffer[0], because we have
    ++            * already ensured that all the buffers are of the same size in
    ++            * impeg2d_api_set_display_frame.
    ++            */
    ++            if(ps_dec->as_disp_buffers[0].u4_min_out_buf_size[i] <
    ++                   au4_min_out_buf_size[i])
    ++                return (IV_FAIL);
     +        }
    -         ps_dec_op->u4_output_present = 1;
    -         ps_dec_op->u4_ts = ps_disp_buf->u4_ts;
    -         if((ps_codec->i4_flush_mode == 0) && (ps_codec->s_parse.i4_end_of_frame == 0))
    -@@ -420,7 +457,8 @@ WORD32 ihevcd_decode(iv_obj_t *ps_codec_obj, void *pv_api_ip, void *pv_api_op)
    -     if(0 == ps_codec->i4_share_disp_buf && ps_codec->i4_header_mode == 0)
    -     {
    -         UWORD32 i;
    --        if(ps_dec_ip->s_out_buffer.u4_num_bufs == 0)
    -+        if((ps_dec_ip->s_out_buffer.u4_num_bufs <= 0) ||
    -+           (ps_dec_ip->s_out_buffer.u4_num_bufs > IVD_VIDDEC_MAX_IO_BUFFERS))
    -         {
    -             ps_dec_op->u4_error_code |= 1 << IVD_UNSUPPORTEDPARAM;
    -             ps_dec_op->u4_error_code |= IVD_DISP_FRM_ZERO_OP_BUFS;
    -@@ -471,6 +509,10 @@ WORD32 ihevcd_decode(iv_obj_t *ps_codec_obj, void *pv_api_ip, void *pv_api_op)
    -                 ihevcd_init_proc_ctxt(ps_proc, 0);
    -             }
    - 
    -+            /* Output buffer check */
    -+            ret = ihevcd_check_out_buf_size(ps_codec);
    -+            RETURN_IF((ret != (IHEVCD_ERROR_T)IHEVCD_SUCCESS), ret);
    ++    }
    ++
    ++    return(IV_SUCCESS);
    ++}
     +
    -             /* Set remaining number of rows to be processed */
    -             ret = ihevcd_fmt_conv(ps_codec, &ps_codec->as_process[prev_proc_idx],
    -                                   ps_dec_ip->s_out_buffer.pu1_bufs[0],
    -@@ -628,15 +670,13 @@ WORD32 ihevcd_decode(iv_obj_t *ps_codec_obj, void *pv_api_ip, void *pv_api_op)
    - 
    -         if(IHEVCD_IGNORE_SLICE == ret)
    -         {
    --            ps_codec->s_parse.i4_cur_slice_idx = MAX(0, (ps_codec->s_parse.i4_cur_slice_idx - 1));
    -             ps_codec->pu1_inp_bitsbuf += (nal_ofst + nal_len);
    -             ps_codec->i4_bytes_remaining -= (nal_ofst + nal_len);
      
    -             continue;
    -         }
      
    --        if((IVD_RES_CHANGED == ret) ||
    --           (IHEVCD_UNSUPPORTED_DIMENSIONS == ret))
    -+        if(IVD_RES_CHANGED == ret)
    -         {
    -             break;
    + /*****************************************************************************/
    +@@ -1791,7 +1882,6 @@ IV_API_CALL_STATUS_T impeg2d_api_init(iv_obj_t *ps_dechdl,
              }
    -@@ -685,12 +725,20 @@ WORD32 ihevcd_decode(iv_obj_t *ps_codec_obj, void *pv_api_ip, void *pv_api_op)
    -         BREAK_AFTER_SLICE_NAL();
    -     }
    - 
    --    if((ps_codec->u4_pic_cnt == 0) && (ret != IHEVCD_SUCCESS))
    -+    if(1 == ps_codec->i4_pic_present && 0 == ps_codec->s_parse.i4_end_of_frame)
    -     {
    --        ps_codec->i4_error_code = ret;
    --
    --        ihevcd_fill_outargs(ps_codec, ps_dec_ip, ps_dec_op);
    --        return IV_FAIL;
    -+        slice_header_t *ps_slice_hdr_next;
    -+        ps_codec->i4_slice_error = 1;
    -+        ps_codec->s_parse.i4_cur_slice_idx--;
    -+        if(ps_codec->s_parse.i4_cur_slice_idx < 0)
    -+            ps_codec->s_parse.i4_cur_slice_idx = 0;
    -+
    -+        ps_slice_hdr_next = ps_codec->s_parse.ps_slice_hdr_base + ((ps_codec->s_parse.i4_cur_slice_idx + 1) & (MAX_SLICE_HDR_CNT - 1));
    -+        ps_slice_hdr_next->i2_ctb_x = -1;
    -+        ps_slice_hdr_next->i2_ctb_y = -1;
    -+
    -+        ihevcd_parse_slice_data(ps_codec);
    -+        ASSERT(ps_codec->s_parse.i4_end_of_frame != 0);
          }
      
    -     if(1 == ps_codec->i4_pic_present)
    -diff --git a/decoder/ihevcd_parse_headers.c b/decoder/ihevcd_parse_headers.c
    -index c0f1564..8348fc6 100644
    ---- a/decoder/ihevcd_parse_headers.c
    -+++ b/decoder/ihevcd_parse_headers.c
    -@@ -1272,12 +1272,6 @@ IHEVCD_ERROR_T ihevcd_parse_sps(codec_t *ps_codec)
    -     if((0 >= ps_sps->i2_pic_width_in_luma_samples) || (0 >= ps_sps->i2_pic_height_in_luma_samples))
    -         return IHEVCD_INVALID_PARAMETER;
    - 
    --    /* i2_pic_width_in_luma_samples and i2_pic_height_in_luma_samples
    --       should be multiples of min_cb_size. Here these are aligned to 8,
    --       i.e. smallest CB size */
    --    ps_sps->i2_pic_width_in_luma_samples = ALIGN8(ps_sps->i2_pic_width_in_luma_samples);
    --    ps_sps->i2_pic_height_in_luma_samples = ALIGN8(ps_sps->i2_pic_height_in_luma_samples);
     -
    -     BITS_PARSE("pic_cropping_flag", value, ps_bitstrm, 1);
    -     ps_sps->i1_pic_cropping_flag = value;
    - 
    -@@ -1285,15 +1279,31 @@ IHEVCD_ERROR_T ihevcd_parse_sps(codec_t *ps_codec)
    -     {
    +     ps_dec_state = ps_dec_state_multi_core->ps_dec_state[0];
      
    -         UEV_PARSE("pic_crop_left_offset", value, ps_bitstrm);
    -+        if (value < 0 || value >= ps_sps->i2_pic_width_in_luma_samples)
    -+        {
    -+            return IHEVCD_INVALID_PARAMETER;
    -+        }
    -         ps_sps->i2_pic_crop_left_offset = value;
    - 
    -         UEV_PARSE("pic_crop_right_offset", value, ps_bitstrm);
    -+        if (value < 0 || value >= ps_sps->i2_pic_width_in_luma_samples)
    -+        {
    -+            return IHEVCD_INVALID_PARAMETER;
    -+        }
    -         ps_sps->i2_pic_crop_right_offset = value;
    - 
    -         UEV_PARSE("pic_crop_top_offset", value, ps_bitstrm);
    -+        if (value < 0 || value >= ps_sps->i2_pic_height_in_luma_samples)
    -+        {
    -+            return IHEVCD_INVALID_PARAMETER;
    -+        }
    -         ps_sps->i2_pic_crop_top_offset = value;
    - 
    -         UEV_PARSE("pic_crop_bottom_offset", value, ps_bitstrm);
    -+        if (value < 0 || value >= ps_sps->i2_pic_height_in_luma_samples)
    -+        {
    -+            return IHEVCD_INVALID_PARAMETER;
    -+        }
    -         ps_sps->i2_pic_crop_bottom_offset = value;
    -     }
    -     else
    -@@ -1402,7 +1412,9 @@ IHEVCD_ERROR_T ihevcd_parse_sps(codec_t *ps_codec)
    -                     (ps_sps->i1_log2_diff_max_min_transform_block_size < 0) ||
    -                     (ps_sps->i1_log2_max_transform_block_size > ps_sps->i1_log2_ctb_size) ||
    -                     (ps_sps->i1_log2_ctb_size < 4) ||
    --                    (ps_sps->i1_log2_ctb_size > 6))
    -+                    (ps_sps->i1_log2_ctb_size > 6) ||
    -+                    (ps_sps->i2_pic_width_in_luma_samples % (1 << ps_sps->i1_log2_min_coding_block_size) != 0) ||
    -+                    (ps_sps->i2_pic_height_in_luma_samples % (1 << ps_sps->i1_log2_min_coding_block_size) != 0))
    -     {
    -         return IHEVCD_INVALID_PARAMETER;
    -     }
    -@@ -1797,6 +1809,19 @@ IHEVCD_ERROR_T ihevcd_parse_pps(codec_t *ps_codec)
    -     BITS_PARSE("tiles_enabled_flag", value, ps_bitstrm, 1);
    -     ps_pps->i1_tiles_enabled_flag = value;
    +     if((ps_dec_state->i4_chromaFormat  == IV_YUV_422ILE)
    +@@ -3373,6 +3463,13 @@ IV_API_CALL_STATUS_T impeg2d_api_entity(iv_obj_t *ps_dechdl,
    +             {
    +                 ps_dec_state->u1_flushcnt    = 0;
      
    -+    /* When tiles are enabled and width or height is >= 4096,
    -+     * CTB Size should at least be 32. 16x16 CTBs can result
    -+     * in tile position greater than 255 for 4096,
    -+     * which decoder does not support.
    -+     */
    -+    if((ps_pps->i1_tiles_enabled_flag) &&
    -+                    (ps_sps->i1_log2_ctb_size == 4) &&
    -+                    ((ps_sps->i2_pic_width_in_luma_samples >= 4096) ||
    -+                    (ps_sps->i2_pic_height_in_luma_samples >= 4096)))
    -+    {
    -+        return IHEVCD_INVALID_HEADER;
    -+    }
    ++                ps_dec_state->ps_out_buf = &ps_dec_ip->s_ivd_video_decode_ip_t.s_out_buffer;
    ++                if (IV_SUCCESS != check_app_out_buf_size(ps_dec_state))
    ++                {
    ++                    ps_dec_op->s_ivd_video_decode_op_t.u4_error_code = IVD_DISP_FRM_ZERO_OP_BUF_SIZE;
    ++                    return IV_FAIL;
    ++                }
     +
    -     BITS_PARSE("entropy_coding_sync_enabled_flag", value, ps_bitstrm, 1);
    -     ps_pps->i1_entropy_coding_sync_enabled_flag = value;
    - 
    -diff --git a/decoder/ihevcd_parse_slice.c b/decoder/ihevcd_parse_slice.c
    -index 126b14c..e394a4e 100644
    ---- a/decoder/ihevcd_parse_slice.c
    -+++ b/decoder/ihevcd_parse_slice.c
    -@@ -2376,26 +2376,29 @@ IHEVCD_ERROR_T ihevcd_parse_slice_data(codec_t *ps_codec)
    - 
    -     /*Cabac init at the beginning of a slice*/
    -     //If the slice is a dependent slice, not present at the start of a tile
    --    if((1 == ps_slice_hdr->i1_dependent_slice_flag) && (!((ps_codec->s_parse.i4_ctb_tile_x == 0) && (ps_codec->s_parse.i4_ctb_tile_y == 0))))
    -+    if(0 == ps_codec->i4_slice_error)
    +                 /*************************************************************************/
    +                 /*                              Frame Decode                             */
    +                 /*************************************************************************/
    +diff --git a/decoder/impeg2d_bitstream.c b/decoder/impeg2d_bitstream.c
    +index 36092e5..57a9e2f 100644
    +--- a/decoder/impeg2d_bitstream.c
    ++++ b/decoder/impeg2d_bitstream.c
    +@@ -191,21 +191,17 @@ INLINE UWORD8 impeg2d_bit_stream_get_bit(stream_t *ps_stream)
    + INLINE void impeg2d_bit_stream_flush(void* pv_ctxt, UWORD32 u4_no_of_bits)
    + {
    +     stream_t *ps_stream = (stream_t *)pv_ctxt;
    +-    if ((ps_stream->u4_offset + 64) < ps_stream->u4_max_offset)
    ++
    ++
    ++    if (ps_stream->u4_offset <= ps_stream->u4_max_offset)
          {
    --        if((0 == ps_pps->i1_entropy_coding_sync_enabled_flag) || (ps_pps->i1_entropy_coding_sync_enabled_flag && (0 != ps_codec->s_parse.i4_ctb_x)))
    -+        if((1 == ps_slice_hdr->i1_dependent_slice_flag) && (!((ps_codec->s_parse.i4_ctb_tile_x == 0) && (ps_codec->s_parse.i4_ctb_tile_y == 0))))
    -         {
    --            ihevcd_cabac_reset(&ps_codec->s_parse.s_cabac,
    --                               &ps_codec->s_parse.s_bitstrm);
    -+            if((0 == ps_pps->i1_entropy_coding_sync_enabled_flag) || (ps_pps->i1_entropy_coding_sync_enabled_flag && (0 != ps_codec->s_parse.i4_ctb_x)))
    -+            {
    -+                ihevcd_cabac_reset(&ps_codec->s_parse.s_cabac,
    -+                                   &ps_codec->s_parse.s_bitstrm);
    -+            }
    -         }
    --    }
    --    else if((0 == ps_pps->i1_entropy_coding_sync_enabled_flag) || (ps_pps->i1_entropy_coding_sync_enabled_flag && (0 != ps_codec->s_parse.i4_ctb_x)))
    ++        /* We have to flush the bytes even if the offset is equal to the maximum
    ++         * offset. This will ensure that a stream with an error exactly at the
    ++         * offset will not get stuck in an infinite loop - If we do not flush
    ++         * these bytes, then we keep feeding the erroneous bits.
    ++         */
    +         FLUSH_BITS(ps_stream->u4_offset,ps_stream->u4_buf,ps_stream->u4_buf_nxt,u4_no_of_bits,ps_stream->pu4_buf_aligned)
    +     }
    +-    else
     -    {
    --        ret = ihevcd_cabac_init(&ps_codec->s_parse.s_cabac,
    --                                &ps_codec->s_parse.s_bitstrm,
    --                                slice_qp,
    --                                cabac_init_idc,
    --                                &gau1_ihevc_cab_ctxts[cabac_init_idc][slice_qp][0]);
    --        if(ret != (IHEVCD_ERROR_T)IHEVCD_SUCCESS)
    -+        else if((0 == ps_pps->i1_entropy_coding_sync_enabled_flag) || (ps_pps->i1_entropy_coding_sync_enabled_flag && (0 != ps_codec->s_parse.i4_ctb_x)))
    +-        UWORD32     u4_temp;
    +-
    +-        if (((ps_stream->u4_offset & 0x1f) + u4_no_of_bits) >= 32)
    +-        {
    +-            ps_stream->u4_buf              = ps_stream->u4_buf_nxt;
    +-            ps_stream->u4_buf_nxt          = 0;
    +-        }
    +-        ps_stream->u4_offset += u4_no_of_bits;
    +-    }
    +     return;
    + }
    + /******************************************************************************
    +diff --git a/decoder/impeg2d_dec_hdr.c b/decoder/impeg2d_dec_hdr.c
    +index 4a84086..5a8b996 100644
    +--- a/decoder/impeg2d_dec_hdr.c
    ++++ b/decoder/impeg2d_dec_hdr.c
    +@@ -173,7 +173,16 @@ IMPEG2D_ERROR_CODES_T impeg2d_dec_seq_hdr(dec_state_t *ps_dec)
    +         }
    +         else
              {
    --            ps_codec->i4_slice_error = 1;
    --            end_of_slice_flag = 1;
    --            ret = (IHEVCD_ERROR_T)IHEVCD_SUCCESS;
    -+            ret = ihevcd_cabac_init(&ps_codec->s_parse.s_cabac,
    -+                                    &ps_codec->s_parse.s_bitstrm,
    -+                                    slice_qp,
    -+                                    cabac_init_idc,
    -+                                    &gau1_ihevc_cab_ctxts[cabac_init_idc][slice_qp][0]);
    -+            if(ret != (IHEVCD_ERROR_T)IHEVCD_SUCCESS)
    +-            if((u2_width > ps_dec->u2_create_max_width)
    ++            if (0 == ps_dec->i4_pic_count)
     +            {
    -+                ps_codec->i4_slice_error = 1;
    -+                end_of_slice_flag = 1;
    -+                ret = (IHEVCD_ERROR_T)IHEVCD_SUCCESS;
    ++                /* Decoder has not decoded a single frame since the last
    ++                 * reset/init. This implies that we have two headers in the
    ++                 * input stream. So, do not indicate a resolution change, since
    ++                 * this can take the decoder into an infinite loop.
    ++                 */
    ++                return (IMPEG2D_ERROR_CODES_T) IMPEG2D_FRM_HDR_DECODE_ERR;
     +            }
    -         }
    -     }
    ++            else if((u2_width > ps_dec->u2_create_max_width)
    +                             || (u2_height > ps_dec->u2_create_max_height))
    +             {
    +                 IMPEG2D_ERROR_CODES_T e_error = IMPEG2D_UNSUPPORTED_DIMENSIONS;
    +@@ -280,6 +289,8 @@ IMPEG2D_ERROR_CODES_T impeg2d_dec_seq_hdr(dec_state_t *ps_dec)
    + IMPEG2D_ERROR_CODES_T impeg2d_dec_seq_ext(dec_state_t *ps_dec)
    + {
    +     stream_t *ps_stream;
    ++    UWORD16 horizontal_value;
    ++    UWORD16 vertical_value;
      
    -@@ -2479,6 +2482,7 @@ IHEVCD_ERROR_T ihevcd_parse_slice_data(codec_t *ps_codec)
    +     ps_stream = &ps_dec->s_bit_stream;
      
    -             /* Cabac init is done unconditionally at the start of the tile irrespective
    -              * of whether it is a dependent or an independent slice */
    -+            if(0 == ps_codec->i4_slice_error)
    -             {
    -                 ret = ihevcd_cabac_init(&ps_codec->s_parse.s_cabac,
    -                                         &ps_codec->s_parse.s_bitstrm,
    -@@ -2542,7 +2546,7 @@ IHEVCD_ERROR_T ihevcd_parse_slice_data(codec_t *ps_codec)
    -         if(ps_pps->i1_entropy_coding_sync_enabled_flag)
    -         {
    -             /*TODO Handle single CTB and top-right belonging to a different slice */
    --            if(0 == ps_codec->s_parse.i4_ctb_x)
    -+            if(0 == ps_codec->s_parse.i4_ctb_x && 0 == ps_codec->i4_slice_error)
    -             {
    -                 //WORD32 size = sizeof(ps_codec->s_parse.s_cabac.au1_ctxt_models);
    -                 WORD32 default_ctxt = 0;
    -@@ -2708,6 +2712,17 @@ IHEVCD_ERROR_T ihevcd_parse_slice_data(codec_t *ps_codec)
    -         {
    -             tu_t *ps_tu = ps_codec->s_parse.ps_tu;
    -             pu_t *ps_pu = ps_codec->s_parse.ps_pu;
    -+            WORD32 pu_skip_wd, pu_skip_ht;
    -+            WORD32 rows_remaining, cols_remaining;
    +@@ -329,11 +340,30 @@ IMPEG2D_ERROR_CODES_T impeg2d_dec_seq_ext(dec_state_t *ps_dec)
    +     if(impeg2d_bit_stream_get(ps_stream,2) != 0x1)
    +         return IMPEG2D_CHROMA_FMT_NOT_SUP;
    + 
    ++    /* Error resilience: store the 2 most significant bit in horizontal and vertical   */
    ++    /* variables.Use it only if adding them to the vertical and horizontal sizes       */
    ++    /* respectively, doesn't exceed the MAX_WD and MAX_HT supported by the application.*/
     +
    -+            /* Set pu wd and ht based on whether the ctb is complete or not */
    -+            rows_remaining = ps_sps->i2_pic_height_in_luma_samples
    -+                            - (ps_codec->s_parse.i4_ctb_y << ps_sps->i1_log2_ctb_size);
    -+            pu_skip_ht = MIN(ctb_size, rows_remaining);
     +
    -+            cols_remaining = ps_sps->i2_pic_width_in_luma_samples
    -+                            - (ps_codec->s_parse.i4_ctb_x << ps_sps->i1_log2_ctb_size);
    -+            pu_skip_wd = MIN(ctb_size, cols_remaining);
    +     /* Read the 2 most significant bits from horizontal_size */
    +-    ps_dec->u2_horizontal_size    += (impeg2d_bit_stream_get(ps_stream,2) << 12);
    ++    horizontal_value               = (impeg2d_bit_stream_get(ps_stream,2) << 12);
      
    -             ps_tu->b1_cb_cbf = 0;
    -             ps_tu->b1_cr_cbf = 0;
    -@@ -2731,8 +2746,8 @@ IHEVCD_ERROR_T ihevcd_parse_slice_data(codec_t *ps_codec)
    -             ps_pu->b2_part_idx = 0;
    -             ps_pu->b4_pos_x = 0;
    -             ps_pu->b4_pos_y = 0;
    --            ps_pu->b4_wd = (ctb_size >> 2) - 1;
    --            ps_pu->b4_ht = (ctb_size >> 2) - 1;
    -+            ps_pu->b4_wd = (pu_skip_wd >> 2) - 1;
    -+            ps_pu->b4_ht = (pu_skip_ht >> 2) - 1;
    -             ps_pu->b1_intra_flag = 0;
    -             ps_pu->b3_part_mode = ps_codec->s_parse.s_cu.i4_part_mode;
    -             ps_pu->b1_merge_flag = 1;
    -@@ -2772,7 +2787,7 @@ IHEVCD_ERROR_T ihevcd_parse_slice_data(codec_t *ps_codec)
    -                 if((ps_codec->s_parse.i4_ctb_tile_y + 1) == ps_tile->u2_ht)
    -                     end_of_tile = 1;
    +     /* Read the 2 most significant bits from vertical_size */
    +-    ps_dec->u2_vertical_size      += (impeg2d_bit_stream_get(ps_stream,2) << 12);
    ++    vertical_value                 = (impeg2d_bit_stream_get(ps_stream,2) << 12);
    ++
    ++    /* Error resilience: The height and width should not be more than the*/
    ++    /*max height and width the application can support*/
    ++    if(ps_dec->u2_create_max_height < (ps_dec->u2_vertical_size + vertical_value))
    ++    {
    ++        return (IMPEG2D_ERROR_CODES_T) IVD_STREAM_WIDTH_HEIGHT_NOT_SUPPORTED;
    ++    }
    ++
    ++    if(ps_dec->u2_create_max_width < (ps_dec->u2_horizontal_size + horizontal_value))
    ++    {
    ++        return (IMPEG2D_ERROR_CODES_T) IVD_STREAM_WIDTH_HEIGHT_NOT_SUPPORTED;
    ++    }
    ++    ps_dec->u2_vertical_size       += vertical_value;
    ++    ps_dec->u2_horizontal_size     += horizontal_value;
    + 
    +     /*-----------------------------------------------------------------------*/
    +     /* Flush the following as they are not used now                          */
    +@@ -914,7 +944,7 @@ void impeg2d_dec_pic_data_thread(dec_state_t *ps_dec)
    +                 {
    +                     pu1_buf = ps_dec->pu1_inp_bits_buf + s_job.i4_bistream_ofst;
    +                     impeg2d_bit_stream_init(&(ps_dec->s_bit_stream), pu1_buf,
    +-                            (ps_dec->u4_num_inp_bytes - s_job.i4_bistream_ofst) + 8);
    ++                            (ps_dec->u4_num_inp_bytes - s_job.i4_bistream_ofst));
    +                     i4_cur_row      = s_job.i2_start_mb_y;
    +                     ps_dec->i4_start_mb_y = s_job.i2_start_mb_y;
    +                     ps_dec->i4_end_mb_y = s_job.i2_end_mb_y;
    +@@ -956,6 +986,11 @@ void impeg2d_dec_pic_data_thread(dec_state_t *ps_dec)
    +             if ((IMPEG2D_ERROR_CODES_T)IVD_ERROR_NONE != e_error)
    +             {
    +                 impeg2d_next_start_code(ps_dec);
    ++                if(ps_dec->s_bit_stream.u4_offset >= ps_dec->s_bit_stream.u4_max_offset)
    ++                {
    ++                    ps_dec->u4_error_code = IMPEG2D_BITSTREAM_BUFF_EXCEEDED_ERR;
    ++                    return;
    ++                }
                  }
    --            if((0 == end_of_slice_flag) &&
    -+            if((0 == end_of_slice_flag) && (0 == ps_codec->i4_slice_error) &&
    -                             ((ps_pps->i1_tiles_enabled_flag && end_of_tile) ||
    -                                             (ps_pps->i1_entropy_coding_sync_enabled_flag && end_of_tile_row)))
    +         }
    + 
    +@@ -975,23 +1010,30 @@ void impeg2d_dec_pic_data_thread(dec_state_t *ps_dec)
    + 
    +             if(i4_continue_decode)
                  {
    -@@ -3090,15 +3105,7 @@ IHEVCD_ERROR_T ihevcd_parse_slice_data(codec_t *ps_codec)
    -                 UWORD32 *pu4_nbr_pu_idx = ps_proc->pu4_pic_pu_idx_map;
    -                 WORD32 nbr_pu_idx_strd = MAX_CTB_SIZE / MIN_PU_SIZE + 2;
    -                 pu_t *ps_pu;
    --
    --                for(row = 0; row < ctb_size / MIN_PU_SIZE; row++)
    --                {
    --                    for(col = 0; col < ctb_size / MIN_PU_SIZE; col++)
    --                    {
    --                        pu1_pic_pu_map_ctb[row * ctb_size / MIN_PU_SIZE + col] = 0;
    --                    }
    +-                /* If the slice is from the same row, then continue decoding without dequeue */
    +-                if((temp - 1) == i4_cur_row)
    ++                if (0 != ps_dec->u2_num_mbs_left)
    +                 {
    +-                    i4_dequeue_job = 0;
    +-                    break;
     -                }
     -
    -+                WORD32 ctb_size_in_min_pu = (ctb_size / MIN_PU_SIZE);
    - 
    -                 /* Neighbor PU idx update inside CTB */
    -                 /* 1byte per 4x4. Indicates the PU idx that 4x4 block belongs to */
    -@@ -3149,6 +3156,27 @@ IHEVCD_ERROR_T ihevcd_parse_slice_data(codec_t *ps_codec)
    - 
    -                     }
    -                 }
    -+
    -+                /* Updating the CTB level PU idx (Used for collocated MV pred)*/
    -+                {
    -+                    WORD32 ctb_row, ctb_col, index_pic_map, index_nbr_map;
    -+                    WORD32 first_pu_of_ctb;
    -+                    first_pu_of_ctb = pu4_nbr_pu_idx[1 + nbr_pu_idx_strd];
    -+
    -+                    index_pic_map = 0 * ctb_size_in_min_pu + 0;
    -+                    index_nbr_map = (0 + 1) * nbr_pu_idx_strd + (0 + 1);
    -+
    -+                    for(ctb_row = 0; ctb_row < ctb_size_in_min_pu; ctb_row++)
    +-                if(temp < ps_dec->i4_end_mb_y)
    +-                {
    +-                    i4_cur_row = ps_dec->u2_mb_y;
    ++                    /* If the slice is from the same row, then continue decoding without dequeue */
    ++                    if((temp - 1) == i4_cur_row)
    ++                    {
    ++                        i4_dequeue_job = 0;
    ++                    }
    ++                    else
     +                    {
    -+                        for(ctb_col = 0; ctb_col < ctb_size_in_min_pu; ctb_col++)
    ++                        if(temp < ps_dec->i4_end_mb_y)
    ++                        {
    ++                            i4_cur_row = ps_dec->u2_mb_y;
    ++                        }
    ++                        else
     +                        {
    -+                            pu1_pic_pu_map_ctb[index_pic_map + ctb_col] = pu4_nbr_pu_idx[index_nbr_map + ctb_col]
    -+                                            - first_pu_of_ctb;
    ++                            i4_dequeue_job = 1;
     +                        }
    -+                        index_pic_map += ctb_size_in_min_pu;
    -+                        index_nbr_map += nbr_pu_idx_strd;
     +                    }
    -+                }
    +                 }
    +                 else
    +                 {
    +                     i4_dequeue_job = 1;
    +                 }
    +                 break;
    +-
                  }
    - 
    -             /*************************************************/
    -diff --git a/decoder/ihevcd_parse_slice_header.c b/decoder/ihevcd_parse_slice_header.c
    -index e1b50b7..ae19328 100644
    ---- a/decoder/ihevcd_parse_slice_header.c
    -+++ b/decoder/ihevcd_parse_slice_header.c
    -@@ -356,7 +356,7 @@ IHEVCD_ERROR_T ihevcd_parse_slice_header(codec_t *ps_codec,
    -         slice_address = value;
    -         /* If slice address is greater than the number of CTBs in a picture,
    -          * ignore the slice */
    --        if(value >= ps_sps->i4_pic_size_in_ctb)
    -+        if(value >= ps_sps->i4_pic_size_in_ctb || value <= 0)
    -             return IHEVCD_IGNORE_SLICE;
    +             else
    +                 break;
    +@@ -1068,6 +1110,7 @@ static WORD32 impeg2d_init_thread_dec_ctxt(dec_state_t *ps_dec,
    +     ps_dec_thd->u2_mb_x = 0;
    +     ps_dec_thd->u2_mb_y = 0;
    +     ps_dec_thd->u2_is_mpeg2 = ps_dec->u2_is_mpeg2;
    ++    ps_dec_thd->i4_pic_count = ps_dec->i4_pic_count;
    +     ps_dec_thd->u2_frame_width = ps_dec->u2_frame_width;
    +     ps_dec_thd->u2_frame_height = ps_dec->u2_frame_height;
    +     ps_dec_thd->u2_picture_width = ps_dec->u2_picture_width;
    +@@ -1337,8 +1380,6 @@ void impeg2d_dec_pic_data(dec_state_t *ps_dec)
    +     WORD32 i;
    +     dec_state_multi_core_t *ps_dec_state_multi_core;
    + 
    +-    UWORD32  u4_error_code;
    +-
    +     dec_state_t *ps_dec_thd;
    +     WORD32 i4_status;
    +     WORD32 i4_min_mb_y;
    +@@ -1346,7 +1387,6 @@ void impeg2d_dec_pic_data(dec_state_t *ps_dec)
    + 
    +     /* Resetting the MB address and MB coordinates at the start of the Frame */
    +     ps_dec->u2_mb_x = ps_dec->u2_mb_y = 0;
    +-    u4_error_code = 0;
    + 
    +     ps_dec_state_multi_core = ps_dec->ps_dec_state_multi_core;
    +     impeg2d_get_slice_pos(ps_dec_state_multi_core);
    +@@ -1390,8 +1430,6 @@ void impeg2d_dec_pic_data(dec_state_t *ps_dec)
    +         }
          }
    -     else
    -diff --git a/decoder/ihevcd_process_slice.c b/decoder/ihevcd_process_slice.c
    -index f57cc31..72db2cc 100644
    ---- a/decoder/ihevcd_process_slice.c
    -+++ b/decoder/ihevcd_process_slice.c
    -@@ -704,14 +704,8 @@ IHEVCD_ERROR_T ihevcd_process(process_ctxt_t *ps_proc)
    -                     WORD32 row, col;
    -                     UWORD32 *pu4_nbr_pu_idx = ps_proc->pu4_pic_pu_idx_map;
    -                     WORD32 nbr_pu_idx_strd = MAX_CTB_SIZE / MIN_PU_SIZE + 2;
    -+                    WORD32 ctb_size_in_min_pu = (ctb_size / MIN_PU_SIZE);
    - 
    --                    for(row = 0; row < ctb_size / MIN_PU_SIZE; row++)
    --                    {
    --                        for(col = 0; col < ctb_size / MIN_PU_SIZE; col++)
    --                        {
    --                            pu1_pic_pu_map_ctb[row * ctb_size / MIN_PU_SIZE + col] = 0;
    --                        }
    --                    }
    -                     /* Neighbor PU idx update inside CTB */
    -                     /* 1byte per 4x4. Indicates the PU idx that 4x4 block belongs to */
      
    -@@ -760,6 +754,27 @@ IHEVCD_ERROR_T ihevcd_process(process_ctxt_t *ps_proc)
    -                                             pu4_nbr_pu_idx[(ctb_size_left / MIN_PU_SIZE) * nbr_pu_idx_strd + i + 1];
    +-    ps_dec->u4_error_code = u4_error_code;
    +-
    + }
    + /*******************************************************************************
    + *
    +@@ -1725,6 +1763,7 @@ IMPEG2D_ERROR_CODES_T impeg2d_process_video_bit_stream(dec_state_t *ps_dec)
    +             else if((ps_dec->s_bit_stream.u4_offset < ps_dec->s_bit_stream.u4_max_offset)
    +                     && (u4_next_bits == PICTURE_START_CODE))
    +             {
    ++                ps_dec->i4_pic_count++;
      
    -                         }
    -+
    -+                        /* Updating the CTB level PU idx (Used for collocated MV pred)*/
    -+                        {
    -+                            WORD32 ctb_row, ctb_col, index_pic_map, index_nbr_map;
    -+                            WORD32 first_pu_of_ctb;
    -+                            first_pu_of_ctb = pu4_nbr_pu_idx[1 + nbr_pu_idx_strd];
    -+
    -+                            index_pic_map = 0 * ctb_size_in_min_pu + 0;
    -+                            index_nbr_map = (0 + 1) * nbr_pu_idx_strd + (0 + 1);
    -+
    -+                            for(ctb_row = 0; ctb_row < ctb_size_in_min_pu; ctb_row++)
    -+                            {
    -+                                for(ctb_col = 0; ctb_col < ctb_size_in_min_pu; ctb_col++)
    -+                                {
    -+                                    pu1_pic_pu_map_ctb[index_pic_map + ctb_col] = pu4_nbr_pu_idx[index_nbr_map + ctb_col]
    -+                                                    - first_pu_of_ctb;
    -+                                }
    -+                                index_pic_map += ctb_size_in_min_pu;
    -+                                index_nbr_map += nbr_pu_idx_strd;
    -+                            }
    -+                        }
    -                     }
    +                 e_error = impeg2d_dec_pic_hdr(ps_dec);
    +                 if ((IMPEG2D_ERROR_CODES_T)IVD_ERROR_NONE != e_error)
    +@@ -1741,7 +1780,11 @@ IMPEG2D_ERROR_CODES_T impeg2d_process_video_bit_stream(dec_state_t *ps_dec)
    +                 {
    +                     return e_error;
                      }
    -             }
    -diff --git a/decoder/ihevcd_utils.c b/decoder/ihevcd_utils.c
    -index 7d76577..14cdd2b 100755
    ---- a/decoder/ihevcd_utils.c
    -+++ b/decoder/ihevcd_utils.c
    -@@ -662,6 +662,103 @@ IHEVCD_ERROR_T ihevcd_mv_buf_mgr_add_bufs(codec_t *ps_codec)
    - *******************************************************************************
    - *
    - * @brief
    -+*  Output buffer check
    -+*
    -+* @par Description:
    -+*  Check for the number of buffers and buffer sizes of output buffer
    -+*
    -+* @param[in] ps_codec
    -+*  Pointer to codec context
    -+*
    -+* @returns  Error from IHEVCD_ERROR_T
    -+*
    -+* @remarks
    -+*
    -+*
    -+*******************************************************************************
    -+*/
    -+IHEVCD_ERROR_T ihevcd_check_out_buf_size(codec_t *ps_codec)
    -+{
    -+    ivd_out_bufdesc_t *ps_out_buffer = ps_codec->ps_out_buffer;
    -+    UWORD32 au4_min_out_buf_size[IVD_VIDDEC_MAX_IO_BUFFERS];
    -+    UWORD32 u4_min_num_out_bufs = 0, i;
    -+    UWORD32 wd, ht;
    -+
    -+    if(0 == ps_codec->i4_share_disp_buf)
    +-                impeg2d_pre_pic_dec_proc(ps_dec);
    ++                e_error = impeg2d_pre_pic_dec_proc(ps_dec);
    ++                if ((IMPEG2D_ERROR_CODES_T) IVD_ERROR_NONE != e_error)
    ++                {
    ++                    return e_error;
    ++                }
    +                 impeg2d_dec_pic_data(ps_dec);
    +                 impeg2d_post_pic_dec_proc(ps_dec);
    +                 u4_start_code_found = 1;
    +@@ -1813,6 +1856,7 @@ IMPEG2D_ERROR_CODES_T impeg2d_process_video_bit_stream(dec_state_t *ps_dec)
    +             else if ((impeg2d_bit_stream_nxt(ps_stream,START_CODE_LEN) == PICTURE_START_CODE)
    +                     && (ps_dec->s_bit_stream.u4_offset < ps_dec->s_bit_stream.u4_max_offset))
    +             {
    ++                ps_dec->i4_pic_count++;
    + 
    +                 e_error = impeg2d_dec_pic_hdr(ps_dec);
    +                 if ((IMPEG2D_ERROR_CODES_T)IVD_ERROR_NONE != e_error)
    +diff --git a/decoder/impeg2d_decoder.c b/decoder/impeg2d_decoder.c
    +index fa88bb5..e4ff79c 100644
    +--- a/decoder/impeg2d_decoder.c
    ++++ b/decoder/impeg2d_decoder.c
    +@@ -98,12 +98,17 @@ void impeg2d_dec_hdr(void *pv_dec,impeg2d_video_decode_ip_t *ps_ip,
    + 
    +     UWORD32 u4_bits_read;
    +     dec_state_t *ps_dec;
    ++    UWORD32 u4_size = ps_ip->s_ivd_video_decode_ip_t.u4_num_Bytes;
    + 
    +     ps_dec = (dec_state_t *)pv_dec;
    +     ps_op->s_ivd_video_decode_op_t.u4_error_code = 0;
    ++    if (u4_size >= MAX_BITSTREAM_BUFFER_SIZE)
     +    {
    -+        wd = ps_codec->i4_disp_wd;
    -+        ht = ps_codec->i4_disp_ht;
    ++        u4_size = MAX_BITSTREAM_BUFFER_SIZE - MIN_BUFFER_BYTES_AT_EOS;
     +    }
    -+    else
    + 
    +     impeg2d_bit_stream_init(&(ps_dec->s_bit_stream),ps_ip->s_ivd_video_decode_ip_t.pv_stream_buffer,
    +-        ps_ip->s_ivd_video_decode_ip_t.u4_num_Bytes);
    ++        u4_size);
    + 
    +     {
    +         {
    +@@ -189,12 +194,15 @@ void impeg2d_dec_frm(void *pv_dec,impeg2d_video_decode_ip_t *ps_ip,
    +     ps_op->s_ivd_video_decode_op_t.u4_num_bytes_consumed = 0;
    + 
    +     IMPEG2D_FRM_NUM_SET();
    ++    if (u4_size >= MAX_BITSTREAM_BUFFER_SIZE)
     +    {
    -+        /* In case of shared mode, do not check validity of ps_codec->ps_out_buffer */
    -+        return (IHEVCD_ERROR_T)IHEVCD_SUCCESS;
    ++        u4_size = MAX_BITSTREAM_BUFFER_SIZE - MIN_BUFFER_BYTES_AT_EOS;
     +    }
    + 
    +     ps_dec->pu1_inp_bits_buf = ps_ip->s_ivd_video_decode_ip_t.pv_stream_buffer;
    +     ps_dec->u4_num_inp_bytes = u4_size;
    +     ps_stream  = &ps_dec->s_bit_stream;
    + 
    +-
    +     impeg2d_bit_stream_init(ps_stream,ps_ip->s_ivd_video_decode_ip_t.pv_stream_buffer,u4_size);
    + 
    +     /* @ */ /* Updating the bufferID */
    +diff --git a/decoder/impeg2d_mc.c b/decoder/impeg2d_mc.c
    +index 79c5ef6..229579c 100644
    +--- a/decoder/impeg2d_mc.c
    ++++ b/decoder/impeg2d_mc.c
    +@@ -1260,7 +1260,7 @@ void impeg2d_mc_fullx_fully(void *pv_dec,
    + 
    +         for(i = 0; i < u4_blk_height; i++)
    +         {
    +-            memcpy(pu1_out, pu1_ref, u4_blk_width);
    ++            memmove(pu1_out, pu1_ref, u4_blk_width);
    +             pu1_ref += u4_ref_wid;
    +             pu1_out += u4_out_wid;
    +         }
    +diff --git a/decoder/impeg2d_pnb_pic.c b/decoder/impeg2d_pnb_pic.c
    +index 5540044..a3ae436 100644
    +--- a/decoder/impeg2d_pnb_pic.c
    ++++ b/decoder/impeg2d_pnb_pic.c
    +@@ -77,6 +77,12 @@ WORD32  impeg2d_dec_p_mb_params(dec_state_t *ps_dec)
    +     else
    +     {
    +         u2_mb_addr_incr = impeg2d_get_mb_addr_incr(ps_stream);
     +
    -+    if(ps_codec->e_chroma_fmt == IV_YUV_420P)
    -+        u4_min_num_out_bufs = MIN_OUT_BUFS_420;
    -+    else if(ps_codec->e_chroma_fmt == IV_YUV_422ILE)
    -+        u4_min_num_out_bufs = MIN_OUT_BUFS_422ILE;
    -+    else if(ps_codec->e_chroma_fmt == IV_RGB_565)
    -+        u4_min_num_out_bufs = MIN_OUT_BUFS_RGB565;
    -+    else if(ps_codec->e_chroma_fmt == IV_RGBA_8888)
    -+        u4_min_num_out_bufs = MIN_OUT_BUFS_RGBA8888;
    -+    else if((ps_codec->e_chroma_fmt == IV_YUV_420SP_UV)
    -+                    || (ps_codec->e_chroma_fmt == IV_YUV_420SP_VU))
    -+        u4_min_num_out_bufs = MIN_OUT_BUFS_420SP;
    ++        if(!u2_mb_addr_incr)
    ++        {
    ++            return IV_FAIL;
    ++        }
     +
    -+    if(ps_codec->e_chroma_fmt == IV_YUV_420P)
    -+    {
    -+        au4_min_out_buf_size[0] = (wd * ht);
    -+        au4_min_out_buf_size[1] = (wd * ht) >> 2;
    -+        au4_min_out_buf_size[2] = (wd * ht) >> 2;
    -+    }
    -+    else if(ps_codec->e_chroma_fmt == IV_YUV_422ILE)
    -+    {
    -+        au4_min_out_buf_size[0] = (wd * ht) * 2;
    -+        au4_min_out_buf_size[1] =
    -+                        au4_min_out_buf_size[2] = 0;
    -+    }
    -+    else if(ps_codec->e_chroma_fmt == IV_RGB_565)
    -+    {
    -+        au4_min_out_buf_size[0] = (wd * ht) * 2;
    -+        au4_min_out_buf_size[1] =
    -+                        au4_min_out_buf_size[2] = 0;
    -+    }
    -+    else if(ps_codec->e_chroma_fmt == IV_RGBA_8888)
    -+    {
    -+        au4_min_out_buf_size[0] = (wd * ht) * 4;
    -+        au4_min_out_buf_size[1] =
    -+                        au4_min_out_buf_size[2] = 0;
    -+    }
    -+    else if((ps_codec->e_chroma_fmt == IV_YUV_420SP_UV)
    -+                    || (ps_codec->e_chroma_fmt == IV_YUV_420SP_VU))
    -+    {
    -+        au4_min_out_buf_size[0] = (wd * ht);
    -+        au4_min_out_buf_size[1] = (wd * ht) >> 1;
    -+        au4_min_out_buf_size[2] = 0;
    -+    }
    +         if(0 == ps_dec->u2_first_mb)
    +         {
    +             /****************************************************************/
    +@@ -116,6 +122,33 @@ WORD32  impeg2d_dec_p_mb_params(dec_state_t *ps_dec)
    + 
    +             impeg2d_dec_skip_mbs(ps_dec, (UWORD16)(u2_mb_addr_incr - 1));
    +         }
    ++        else
    ++        {
     +
    -+    if(ps_out_buffer->u4_num_bufs < u4_min_num_out_bufs)
    -+    {
    -+        return (IHEVCD_ERROR_T)IV_FAIL;
    -+    }
    ++            /****************************************************************/
    ++            /* Section 6.3.17                                               */
    ++            /* The first MB of a slice cannot be skipped                    */
    ++            /* But the mb_addr_incr can be > 1, because at the beginning of */
    ++            /* a slice, it indicates the offset from the last MB in the     */
    ++            /* previous row. Hence for the first slice in a row, the        */
    ++            /* mb_addr_incr needs to be 1.                                  */
    ++            /****************************************************************/
    ++            /* MB_x is set to zero whenever MB_y changes.                   */
    ++            ps_dec->u2_mb_x = u2_mb_addr_incr - 1;
    ++            /* For error resilience */
    ++            ps_dec->u2_mb_x = MIN(ps_dec->u2_mb_x, (ps_dec->u2_num_horiz_mb - 1));
    ++            ps_dec->u2_num_mbs_left = ((ps_dec->u2_num_vert_mb - ps_dec->u2_mb_y)
    ++                            * ps_dec->u2_num_horiz_mb) - ps_dec->u2_mb_x;
    ++
    ++            /****************************************************************/
    ++            /* mb_addr_incr is forced to 1 because in this decoder it is used */
    ++            /* more as an indicator of the number of MBs skipped than the   */
    ++            /* as defined by the standard (Section 6.3.17)                  */
    ++            /****************************************************************/
    ++            u2_mb_addr_incr = 1;
    ++            ps_dec->u2_first_mb = 0;
     +
    -+    for (i = 0 ; i < u4_min_num_out_bufs; i++)
    -+    {
    -+        if(ps_out_buffer->u4_min_out_buf_size[i] < au4_min_out_buf_size[i])
    ++        }
    + 
    +     }
    +     u4_next_word = (UWORD16)impeg2d_bit_stream_nxt(ps_stream,16);
    +@@ -280,6 +313,8 @@ WORD32 impeg2d_dec_pnb_mb_params(dec_state_t *ps_dec)
    +             ps_dec->u2_mb_x = u2_mb_addr_incr - 1;
    +             /* For error resilience */
    +             ps_dec->u2_mb_x = MIN(ps_dec->u2_mb_x, (ps_dec->u2_num_horiz_mb - 1));
    ++            ps_dec->u2_num_mbs_left = ((ps_dec->u2_num_vert_mb - ps_dec->u2_mb_y)
    ++                            * ps_dec->u2_num_horiz_mb) - ps_dec->u2_mb_x;
    + 
    +             /****************************************************************/
    +             /* mb_addr_incr is forced to 1 because in this decoder it is used */
    +@@ -510,6 +545,12 @@ IMPEG2D_ERROR_CODES_T impeg2d_dec_p_b_slice(dec_state_t *ps_dec)
    + 
    +         if(ret)
    +             return IMPEG2D_MB_TEX_DECODE_ERR;
    ++
    ++        if(0 >= ps_dec->u2_num_mbs_left)
     +        {
    -+            return (IHEVCD_ERROR_T)IV_FAIL;
    ++            break;
     +        }
    -+    }
     +
    -+    return (IHEVCD_ERROR_T)IHEVCD_SUCCESS;
    -+}
    +         IMPEG2D_TRACE_MB_START(ps_dec->u2_mb_x, ps_dec->u2_mb_y);
    + 
    +         u4_x_dst_offset = u4_frm_offset + (ps_dec->u2_mb_x << 4);
    +diff --git a/decoder/impeg2d_structs.h b/decoder/impeg2d_structs.h
    +index 03cd54c..bdda8b8 100644
    +--- a/decoder/impeg2d_structs.h
    ++++ b/decoder/impeg2d_structs.h
    +@@ -40,6 +40,7 @@ Because of temporal dependency in deinterlacer one additional buffer is also nee
    + #define DEC_ORDER               0
    + 
    + #define MAX_BITSTREAM_BUFFER_SIZE       2000 * 1024
    ++#define MIN_BUFFER_BYTES_AT_EOS 8
    + 
    + /* Flag to signal that buffer is held by deinterlacing */
    + #define MPEG2_BUF_MGR_DEINT (BUF_MGR_DISP << 1)
    +@@ -331,6 +332,9 @@ typedef struct dec_state_struct_t
    +     UWORD8          *pu1_chroma_ref_buf[BUF_MGR_MAX_CNT];
    +     ivd_out_bufdesc_t as_disp_buffers[BUF_MGR_MAX_CNT];
    + 
    ++    /* Count the number of pictures decoded after init/reset */
    ++    WORD32          i4_pic_count;
    ++
    +     /* Flag to signal last coeff in a 8x8 block is one
    +     after mismatch contol */
    +     WORD32          i4_last_value_one;
    +@@ -359,6 +363,8 @@ typedef struct dec_state_struct_t
    +     /* Number of bytes in the input bitstream */
    +     UWORD32         u4_num_inp_bytes;
    + 
    ++    ivd_out_bufdesc_t *ps_out_buf;
    ++
    +     /* Bytes consumed */
    +     WORD32          i4_bytes_consumed;
    + 
    +diff --git a/test/decoder/main.c b/test/decoder/main.c
    +index 7a6db46..6229f50 100644
    +--- a/test/decoder/main.c
    ++++ b/test/decoder/main.c
    +@@ -2246,6 +2246,7 @@ int main(WORD32 argc, CHAR *argv[])
    +                             u4_ip_buf_len);
    +                     codec_exit(ac_error_str);
    +                 }
     +
    -+/**
    -+*******************************************************************************
    -+*
    -+* @brief
    - *  Picture level initializations required during parsing
    - *
    - * @par Description:
    -@@ -713,6 +810,10 @@ IHEVCD_ERROR_T ihevcd_parse_pic_init(codec_t *ps_codec)
    -         ps_codec->s_parse.i4_first_pic_init = 1;
    -     }
    +                 s_app_ctx.num_disp_buf = s_ctl_op.u4_num_disp_bufs;
    +                 /* Allocate output buffer only if display buffers are not shared */
    +                 /* Or if shared and output is 420P */
    +@@ -3012,6 +3013,12 @@ int main(WORD32 argc, CHAR *argv[])
      
    -+    /* Output buffer check */
    -+    ret = ihevcd_check_out_buf_size(ps_codec);
    -+    RETURN_IF((ret != (IHEVCD_ERROR_T)IHEVCD_SUCCESS), ret);
    -+
    -     /* Initialize all the slice headers' slice addresses to zero */
    -     {
    -         WORD32 slice_idx;
    +                     break;
    +                 }
    ++                else if (IVD_DISP_FRM_ZERO_OP_BUF_SIZE ==
    ++                                (IMPEG2D_ERROR_CODES_T)s_video_decode_op.u4_error_code)
    ++                {
    ++                    printf("Output buffer is not large enough!\n");
    ++                    break;
    ++                }
    +             }
    + 
    +             if((1 == s_app_ctx.display) &&
    diff --git a/external_svox.patch b/external_svox.patch
    new file mode 100644
    index 0000000..c5ecb05
    --- /dev/null
    +++ b/external_svox.patch
    @@ -0,0 +1,27 @@
    +diff --git a/pico/tts/svox_ssml_parser.cpp b/pico/tts/svox_ssml_parser.cpp
    +index 1e86940..94cd25a 100755
    +--- a/pico/tts/svox_ssml_parser.cpp
    ++++ b/pico/tts/svox_ssml_parser.cpp
    +@@ -57,7 +57,12 @@ SvoxSsmlParser::SvoxSsmlParser() : m_isInBreak(0), m_appendix(NULL), m_docLangua
    +         XML_SetUserData(mParser, (void*)this);
    +         m_datasize = 512;
    +         m_data = new char[m_datasize];
    +-        m_data[0] = '\0';
    ++        if (!m_data)
    ++        {
    ++            ALOGE("Error: failed to allocate memory for string!\n");
    ++        } else {
    ++            memset(m_data, 0, m_datasize);
    ++        }
    +     }
    + }
    + 
    +@@ -120,6 +125,8 @@ void SvoxSsmlParser::startElement(const XML_Char* element, const XML_Char** attr
    +             {
    +                 ALOGE("Error: failed to allocate memory for string!\n");
    +                 return;
    ++            } else {
    ++                memset(m_data, 0, m_datasize);
    +             }
    +         }
    + 
    diff --git a/external_wpa_supplicant_8.patch b/external_wpa_supplicant_8.patch
    index 41d8d87..47099b7 100644
    --- a/external_wpa_supplicant_8.patch
    +++ b/external_wpa_supplicant_8.patch
    @@ -3708,6 +3708,16 @@ index e55b380..512116a 100644
      # wpa_ptk_rekey: Maximum lifetime for PTK in seconds. This can be used to
      # enforce rekeying of PTK to mitigate some attacks against TKIP deficiencies.
      #
    +diff --git a/wpa_supplicant/wpa_supplicant_template.conf b/wpa_supplicant/wpa_supplicant_template.conf
    +index f3f2a64..d511029 100644
    +--- a/wpa_supplicant/wpa_supplicant_template.conf
    ++++ b/wpa_supplicant/wpa_supplicant_template.conf
    +@@ -3,4 +3,4 @@ update_config=1
    + eapol_version=1
    + ap_scan=1
    + fast_reauth=1
    +-pmf=1
    ++pmf=0
     diff --git a/wpa_supplicant/wpas_glue.c b/wpa_supplicant/wpas_glue.c
     index f84c8b9..8c1d4fc 100644
     --- a/wpa_supplicant/wpas_glue.c
    diff --git a/frameworks_av.patch b/frameworks_av.patch
    index e713e5e..2945cf5 100644
    --- a/frameworks_av.patch
    +++ b/frameworks_av.patch
    @@ -576,6 +576,21 @@ index 594128c..caaa735 100644
          if (index >= mOutputBuffers.size()) {
              for (size_t i = mOutputBuffers.size(); i <= index; ++i) {
                  mOutputBuffers.add();
    +diff --git a/media/libstagefright/AACExtractor.cpp b/media/libstagefright/AACExtractor.cpp
    +index 7449aa7..3ba1858 100644
    +--- a/media/libstagefright/AACExtractor.cpp
    ++++ b/media/libstagefright/AACExtractor.cpp
    +@@ -294,6 +294,10 @@ status_t AACSource::read(
    +     if (options && options->getSeekTo(&seekTimeUs, &mode)) {
    +         if (mFrameDurationUs > 0) {
    +             int64_t seekFrame = seekTimeUs / mFrameDurationUs;
    ++            if (seekFrame < 0 || seekFrame >= (int64_t)mOffsetVector.size()) {
    ++                android_errorWriteLog(0x534e4554, "70239507");
    ++                return ERROR_MALFORMED;
    ++            }
    +             mCurrentTimeUs = seekFrame * mFrameDurationUs;
    + 
    +             mOffset = mOffsetVector.itemAt(seekFrame);
     diff --git a/media/libstagefright/ACodec.cpp b/media/libstagefright/ACodec.cpp
     index 37fd5a5..337fb2d 100644
     --- a/media/libstagefright/ACodec.cpp
    @@ -1720,10 +1735,26 @@ index 7abc019..590146d 100644
          while (mPrevEstimates.size() > 3) {
              mPrevEstimates.erase(mPrevEstimates.begin());
     diff --git a/media/libstagefright/httplive/M3UParser.cpp b/media/libstagefright/httplive/M3UParser.cpp
    -index c04549a..78a2dd0 100644
    +index c04549a..1242c95 100644
     --- a/media/libstagefright/httplive/M3UParser.cpp
     +++ b/media/libstagefright/httplive/M3UParser.cpp
    -@@ -897,6 +897,9 @@ status_t M3UParser::parseStreamInf(
    +@@ -658,10 +658,13 @@ status_t M3UParser::parse(const void *_data, size_t size) {
    +         }
    + 
    +         if (!line.startsWith("#")) {
    ++            if (itemMeta == NULL) {
    ++                ALOGV("itemMeta == NULL");
    ++                return ERROR_MALFORMED;
    ++            }
    +             if (!mIsVariantPlaylist) {
    +                 int64_t durationUs;
    +-                if (itemMeta == NULL
    +-                        || !itemMeta->findInt64("durationUs", &durationUs)) {
    ++                if (!itemMeta->findInt64("durationUs", &durationUs)) {
    +                     return ERROR_MALFORMED;
    +                 }
    +                 itemMeta->setInt32("discontinuity-sequence",
    +@@ -897,6 +900,9 @@ status_t M3UParser::parseStreamInf(
              }
          }
      
    diff --git a/frameworks_base.patch b/frameworks_base.patch
    index 4a84543..e2538fe 100644
    --- a/frameworks_base.patch
    +++ b/frameworks_base.patch
    @@ -129,10 +129,32 @@ index a110383..aea843a 100644
              }
              return false;
     diff --git a/core/java/android/net/Uri.java b/core/java/android/net/Uri.java
    -index 09af05c..a84f74a 100644
    +index 09af05c..6c069be 100644
     --- a/core/java/android/net/Uri.java
     +++ b/core/java/android/net/Uri.java
    -@@ -1065,7 +1065,7 @@ public abstract class Uri implements Parcelable, Comparable<Uri> {
    +@@ -719,6 +719,10 @@ public abstract class Uri implements Parcelable, Comparable<Uri> {
    +                 LOOP: while (end < length) {
    +                     switch (uriString.charAt(end)) {
    +                         case '/': // Start of path
    ++                        case '\\':// Start of path
    ++                          // Per http://url.spec.whatwg.org/#host-state, the \ character
    ++                          // is treated as if it were a / character when encountered in a
    ++                          // host
    +                         case '?': // Start of query
    +                         case '#': // Start of fragment
    +                             break LOOP;
    +@@ -757,6 +761,10 @@ public abstract class Uri implements Parcelable, Comparable<Uri> {
    +                         case '#': // Start of fragment
    +                             return ""; // Empty path.
    +                         case '/': // Start of path!
    ++                        case '\\':// Start of path!
    ++                          // Per http://url.spec.whatwg.org/#host-state, the \ character
    ++                          // is treated as if it were a / character when encountered in a
    ++                          // host
    +                             break LOOP;
    +                     }
    +                     pathStart++;
    +@@ -1065,7 +1073,7 @@ public abstract class Uri implements Parcelable, Comparable<Uri> {
                      return null;
                  }
      
    @@ -141,7 +163,7 @@ index 09af05c..a84f74a 100644
                  return end == NOT_FOUND ? null : authority.substring(0, end);
              }
      
    -@@ -1089,7 +1089,7 @@ public abstract class Uri implements Parcelable, Comparable<Uri> {
    +@@ -1089,7 +1097,7 @@ public abstract class Uri implements Parcelable, Comparable<Uri> {
                  }
      
                  // Parse out user info and then port.
    @@ -150,7 +172,7 @@ index 09af05c..a84f74a 100644
                  int portSeparator = authority.indexOf(':', userInfoSeparator);
      
                  String encodedHost = portSeparator == NOT_FOUND
    -@@ -1115,7 +1115,7 @@ public abstract class Uri implements Parcelable, Comparable<Uri> {
    +@@ -1115,7 +1123,7 @@ public abstract class Uri implements Parcelable, Comparable<Uri> {
      
                  // Make sure we look for the port separtor *after* the user info
                  // separator. We have URLs with a ':' in the user info.
    @@ -281,6 +303,19 @@ index e4f573b..0d3f50c 100644
                  EGL14.eglGetDisplay(EGL14.EGL_DEFAULT_DISPLAY);
              }
          }
    +diff --git a/core/java/com/android/internal/widget/VerifyCredentialResponse.java b/core/java/com/android/internal/widget/VerifyCredentialResponse.java
    +index 48109ca..c4d91e0 100644
    +--- a/core/java/com/android/internal/widget/VerifyCredentialResponse.java
    ++++ b/core/java/com/android/internal/widget/VerifyCredentialResponse.java
    +@@ -95,6 +95,8 @@ public final class VerifyCredentialResponse implements Parcelable {
    +             if (mPayload != null) {
    +                 dest.writeInt(mPayload.length);
    +                 dest.writeByteArray(mPayload);
    ++            } else {
    ++                dest.writeInt(0);
    +             }
    +         }
    +     }
     diff --git a/core/jni/android/graphics/BitmapFactory.cpp b/core/jni/android/graphics/BitmapFactory.cpp
     index 4001283..0a14361 100644
     --- a/core/jni/android/graphics/BitmapFactory.cpp
    @@ -435,10 +470,10 @@ index f062b59..574f7c1 100644
     +    <webviewprovider description="AOSP WebView" packageName="com.android.webview" availableByDefault="true" isFallback="true" />
      </webviewproviders>
     diff --git a/core/tests/coretests/src/android/net/UriTest.java b/core/tests/coretests/src/android/net/UriTest.java
    -index 6fa28b1..27b7f9e 100644
    +index 6fa28b1..ea0347d 100644
     --- a/core/tests/coretests/src/android/net/UriTest.java
     +++ b/core/tests/coretests/src/android/net/UriTest.java
    -@@ -187,6 +187,11 @@ public class UriTest extends TestCase {
    +@@ -187,6 +187,17 @@ public class UriTest extends TestCase {
              uri = Uri.parse("http://localhost");
              assertEquals("localhost", uri.getHost());
              assertEquals(-1, uri.getPort());
    @@ -447,6 +482,12 @@ index 6fa28b1..27b7f9e 100644
     +        assertEquals("a:a@example.com:a@example2.com", uri.getAuthority());
     +        assertEquals("example2.com", uri.getHost());
     +        assertEquals(-1, uri.getPort());
    ++        assertEquals("/path", uri.getPath());
    ++
    ++        uri = Uri.parse("http://a.foo.com\\.example.com/path");
    ++        assertEquals("a.foo.com", uri.getHost());
    ++        assertEquals(-1, uri.getPort());
    ++        assertEquals("\\.example.com/path", uri.getPath());
          }
      
          @SmallTest
    @@ -42649,3 +42690,18 @@ index 1fe5cb7..0000000
     -        assertTrue(message, checker.getAsBoolean());
     -    }
     -}
    +diff --git a/wifi/java/android/net/wifi/RttManager.java b/wifi/java/android/net/wifi/RttManager.java
    +index 590ff1b..8c96774 100644
    +--- a/wifi/java/android/net/wifi/RttManager.java
    ++++ b/wifi/java/android/net/wifi/RttManager.java
    +@@ -766,8 +766,8 @@ public class RttManager {
    +                     }
    +                     dest.writeByte(result.LCR.id);
    +                     if (result.LCR.id != (byte) 0xFF) {
    +-                        dest.writeInt((byte) result.LCR.data.length);
    +-                        dest.writeByte(result.LCR.id);
    ++                        dest.writeByte((byte) result.LCR.data.length);
    ++                        dest.writeByteArray(result.LCR.data);
    +                     }
    +                     dest.writeByte(result.secure ? (byte) 1 : 0);
    +                 }
    diff --git a/frameworks_op_net_wifi.patch b/frameworks_op_net_wifi.patch
    index ee4bdc8..e69de29 100644
    --- a/frameworks_op_net_wifi.patch
    +++ b/frameworks_op_net_wifi.patch
    @@ -1,48 +0,0 @@
    -diff --git a/service/java/com/android/server/wifi/WifiStateMachine.java b/service/java/com/android/server/wifi/WifiStateMachine.java
    -index 89aabcf..7802b3d 100644
    ---- a/service/java/com/android/server/wifi/WifiStateMachine.java
    -+++ b/service/java/com/android/server/wifi/WifiStateMachine.java
    -@@ -2329,7 +2329,7 @@ public class WifiStateMachine extends StateMachine implements WifiNative.WifiRss
    - 
    -     @Override
    -     public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
    --        if (args.length > 1 && WifiMetrics.PROTO_DUMP_ARG.equals(args[0])
    -+        if (args != null && args.length > 1 && WifiMetrics.PROTO_DUMP_ARG.equals(args[0])
    -                 && WifiMetrics.CLEAN_DUMP_ARG.equals(args[1])) {
    -             // Dump only wifi metrics serialized proto bytes (base64)
    -             updateWifiMetrics();
    -@@ -4340,6 +4340,12 @@ public class WifiStateMachine extends StateMachine implements WifiNative.WifiRss
    -             logStateAndMessage(message, this);
    -             switch (message.what) {
    -                 case CMD_START_SUPPLICANT:
    -+                   /* Stop a running supplicant after a runtime restart
    -+                    * Avoids issues with drivers that do not handle interface down
    -+                    * on a running supplicant properly.
    -+                    */
    -+                    mWifiMonitor.killSupplicant(mP2pSupported);
    -+
    -                     if (mWifiNative.loadDriver()) {
    -                         try {
    -                             mNwService.wifiFirmwareReload(mInterfaceName, "STA");
    -@@ -4372,12 +4378,6 @@ public class WifiStateMachine extends StateMachine implements WifiNative.WifiRss
    -                             loge("Unable to change interface settings: " + ie);
    -                         }
    - 
    --                       /* Stop a running supplicant after a runtime restart
    --                        * Avoids issues with drivers that do not handle interface down
    --                        * on a running supplicant properly.
    --                        */
    --                        mWifiMonitor.killSupplicant(mP2pSupported);
    --
    -                         if (mWifiNative.startHal() == false) {
    -                             /* starting HAL is optional */
    -                             loge("Failed to start HAL");
    -@@ -5527,7 +5527,7 @@ public class WifiStateMachine extends StateMachine implements WifiNative.WifiRss
    -                     // If we have COMPLETED a connection to a BSSID, start doing
    -                     // DNAv4/DNAv6 -style probing for on-link neighbors of
    -                     // interest (e.g. routers); harmless if none are configured.
    --                    if (state == SupplicantState.COMPLETED) {
    -+                    if (isRoaming() && state == SupplicantState.COMPLETED) {
    -                         mIpManager.confirmConfiguration();
    -                     }
    -                     break;
    diff --git a/system_bt.patch b/system_bt.patch
    index cb27095..eb844f2 100644
    --- a/system_bt.patch
    +++ b/system_bt.patch
    @@ -12,7 +12,7 @@ index 63c4246..45d2588 100644
              goto done;
          }
     diff --git a/bta/pan/bta_pan_act.c b/bta/pan/bta_pan_act.c
    -index 1995478..f80dca1 100644
    +index 1995478..82095fb 100644
     --- a/bta/pan/bta_pan_act.c
     +++ b/bta/pan/bta_pan_act.c
     @@ -26,6 +26,8 @@
    @@ -24,8 +24,15 @@ index 1995478..f80dca1 100644
      #include "bta_api.h"
      #include "bta_sys.h"
      #include "bt_common.h"
    -@@ -176,6 +178,14 @@ static void bta_pan_data_buf_ind_cback(UINT16 handle, BD_ADDR src, BD_ADDR dst,
    +@@ -174,14 +176,25 @@ static void bta_pan_data_buf_ind_cback(UINT16 handle, BD_ADDR src, BD_ADDR dst,
    +     tBTA_PAN_SCB *p_scb;
    +     BT_HDR *p_new_buf;
      
    ++    p_scb = bta_pan_scb_by_handle(handle);
    ++    if (p_scb == NULL) {
    ++        return;
    ++    }
    ++
          if (sizeof(tBTA_PAN_DATA_PARAMS) > p_buf->offset) {
              /* offset smaller than data structure in front of actual data */
     +        if (sizeof(BT_HDR) + sizeof(tBTA_PAN_DATA_PARAMS) + p_buf->len >
    @@ -33,12 +40,29 @@ index 1995478..f80dca1 100644
     +            android_errorWriteLog(0x534e4554, "63146237");
     +            APPL_TRACE_ERROR("%s: received buffer length too large: %d", __func__,
     +                             p_buf->len);
    -+            osi_free(p_buf);
     +            return;
     +        }
              p_new_buf = (BT_HDR *)osi_malloc(PAN_BUF_SIZE);
              memcpy((UINT8 *)(p_new_buf + 1) + sizeof(tBTA_PAN_DATA_PARAMS),
                     (UINT8 *)(p_buf + 1) + p_buf->offset, p_buf->len);
    +         p_new_buf->len    = p_buf->len;
    +         p_new_buf->offset = sizeof(tBTA_PAN_DATA_PARAMS);
    +-        osi_free(p_buf);
    +     } else {
    +         p_new_buf = p_buf;
    +     }
    +@@ -192,11 +205,6 @@ static void bta_pan_data_buf_ind_cback(UINT16 handle, BD_ADDR src, BD_ADDR dst,
    +     ((tBTA_PAN_DATA_PARAMS *)p_new_buf)->ext = ext;
    +     ((tBTA_PAN_DATA_PARAMS *)p_new_buf)->forward = forward;
    + 
    +-    if ((p_scb = bta_pan_scb_by_handle(handle)) == NULL) {
    +-        osi_free(p_new_buf);
    +-        return;
    +-    }
    +-
    +     fixed_queue_enqueue(p_scb->data_queue, p_new_buf);
    +     BT_HDR *p_event = (BT_HDR *)osi_malloc(sizeof(BT_HDR));
    +     p_event->layer_specific = handle;
     diff --git a/btif/src/btif_sdp_server.c b/btif/src/btif_sdp_server.c
     index d02dfa0..90d74cf 100644
     --- a/btif/src/btif_sdp_server.c
    @@ -53,6 +77,83 @@ index d02dfa0..90d74cf 100644
              APPL_TRACE_ERROR("%s() failed - id %d is invalid", __func__, id);
              return handle;
          }
    +diff --git a/osi/src/alarm.c b/osi/src/alarm.c
    +index 69ded69..5f9e42c 100644
    +--- a/osi/src/alarm.c
    ++++ b/osi/src/alarm.c
    +@@ -64,7 +64,6 @@ typedef struct {
    +   size_t rescheduled_count;
    +   size_t total_updates;
    +   period_ms_t last_update_ms;
    +-  stat_t callback_execution;
    +   stat_t overdue_scheduling;
    +   stat_t premature_scheduling;
    + } alarm_stats_t;
    +@@ -136,8 +135,7 @@ static void callback_dispatch(void *context);
    + static bool timer_create_internal(const clockid_t clock_id, timer_t *timer);
    + static void update_scheduling_stats(alarm_stats_t *stats,
    +                                     period_ms_t now_ms,
    +-                                    period_ms_t deadline_ms,
    +-                                    period_ms_t execution_delta_ms);
    ++                                    period_ms_t deadline_ms);
    + 
    + static void update_stat(stat_t *stat, period_ms_t delta)
    + {
    +@@ -614,14 +612,12 @@ static void alarm_queue_ready(fixed_queue_t *queue,
    +   pthread_mutex_lock(&alarm->callback_lock);
    +   pthread_mutex_unlock(&monitor);
    + 
    +-  period_ms_t t0 = now();
    +-  callback(data);
    +-  period_ms_t t1 = now();
    +-
    +   // Update the statistics
    +-  assert(t1 >= t0);
    +-  period_ms_t delta = t1 - t0;
    +-  update_scheduling_stats(&alarm->stats, t0, deadline, delta);
    ++  update_scheduling_stats(&alarm->stats, now(), deadline);
    ++
    ++  // NOTE: Do NOT access "alarm" after the callback, as a safety precaution
    ++  // in case the callback itself deleted the alarm.
    ++  callback(data);
    + 
    +   pthread_mutex_unlock(&alarm->callback_lock);
    + }
    +@@ -695,14 +691,11 @@ static bool timer_create_internal(const clockid_t clock_id, timer_t *timer) {
    + 
    + static void update_scheduling_stats(alarm_stats_t *stats,
    +                                     period_ms_t now_ms,
    +-                                    period_ms_t deadline_ms,
    +-                                    period_ms_t execution_delta_ms)
    ++                                    period_ms_t deadline_ms)
    + {
    +   stats->total_updates++;
    +   stats->last_update_ms = now_ms;
    + 
    +-  update_stat(&stats->callback_execution, execution_delta_ms);
    +-
    +   if (deadline_ms < now_ms) {
    +     // Overdue scheduling
    +     period_ms_t delta_ms = now_ms - deadline_ms;
    +@@ -755,7 +748,7 @@ void alarm_debug_dump(int fd)
    +     dprintf(fd, "%-51s: %zu / %zu / %zu / %zu\n",
    +             "    Action counts (sched/resched/exec/cancel)",
    +             stats->scheduled_count, stats->rescheduled_count,
    +-            stats->callback_execution.count, stats->canceled_count);
    ++            stats->total_updates, stats->canceled_count);
    + 
    +     dprintf(fd, "%-51s: %zu / %zu\n",
    +             "    Deviation counts (overdue/premature)",
    +@@ -768,9 +761,6 @@ void alarm_debug_dump(int fd)
    +             (unsigned long long) alarm->period,
    +             (long long)(alarm->deadline - just_now));
    + 
    +-    dump_stat(fd, &stats->callback_execution,
    +-              "    Callback execution time in ms (total/max/avg)");
    +-
    +     dump_stat(fd, &stats->overdue_scheduling,
    +               "    Overdue scheduling time in ms (total/max/avg)");
    + 
     diff --git a/stack/avdt/avdt_api.c b/stack/avdt/avdt_api.c
     index 98ef5f7..5201054 100644
     --- a/stack/avdt/avdt_api.c
    @@ -66,11 +167,134 @@ index 98ef5f7..5201054 100644
      
                  p_pkt->offset = L2CAP_MIN_OFFSET;
                  p = (UINT8 *)(p_pkt + 1) + p_pkt->offset;
    +diff --git a/stack/avrc/avrc_pars_ct.c b/stack/avrc/avrc_pars_ct.c
    +index 63cc384..0e67dd5 100644
    +--- a/stack/avrc/avrc_pars_ct.c
    ++++ b/stack/avrc/avrc_pars_ct.c
    +@@ -22,6 +22,7 @@
    + #include "avrc_defs.h"
    + #include "avrc_int.h"
    + #include "bt_utils.h"
    ++#include "log/log.h"
    + 
    + /*****************************************************************************
    + **  Global data
    +@@ -241,6 +242,12 @@ static tAVRC_STS avrc_ctrl_pars_vendor_rsp(
    +         }
    +         BE_STREAM_TO_UINT8(p_result->list_app_values.num_val, p);
    +         AVRC_TRACE_DEBUG("%s value count = %d ", __func__, p_result->list_app_values.num_val);
    ++
    ++        if (p_result->list_app_attr.num_attr > AVRC_MAX_APP_ATTR_SIZE) {
    ++          android_errorWriteLog(0x534e4554, "63146237");
    ++          p_result->list_app_attr.num_attr = AVRC_MAX_APP_ATTR_SIZE;
    ++        }
    ++ 
    +         for(int xx = 0; xx < p_result->list_app_values.num_val; xx++)
    +         {
    +             BE_STREAM_TO_UINT8(p_result->list_app_values.vals[xx], p);
    +@@ -258,6 +265,12 @@ static tAVRC_STS avrc_ctrl_pars_vendor_rsp(
    +         tAVRC_APP_SETTING *app_sett =
    +             (tAVRC_APP_SETTING*)osi_malloc(p_result->get_cur_app_val.num_val*sizeof(tAVRC_APP_SETTING));
    +         AVRC_TRACE_DEBUG("%s attr count = %d ", __func__, p_result->get_cur_app_val.num_val);
    ++ 
    ++        if (p_result->get_cur_app_val.num_val > AVRC_MAX_APP_ATTR_SIZE) {
    ++          android_errorWriteLog(0x534e4554, "63146237");
    ++          p_result->get_cur_app_val.num_val = AVRC_MAX_APP_ATTR_SIZE;
    ++        }
    ++
    +         for (int xx = 0; xx < p_result->get_cur_app_val.num_val; xx++)
    +         {
    +             BE_STREAM_TO_UINT8(app_sett[xx].attr_id, p);
    +diff --git a/stack/avrc/avrc_pars_tg.c b/stack/avrc/avrc_pars_tg.c
    +index 3f3fe93..63f74b6 100644
    +--- a/stack/avrc/avrc_pars_tg.c
    ++++ b/stack/avrc/avrc_pars_tg.c
    +@@ -21,6 +21,7 @@
    + #include "avrc_api.h"
    + #include "avrc_defs.h"
    + #include "avrc_int.h"
    ++#include "log/log.h"
    + 
    + /*****************************************************************************
    + **  Global data
    +@@ -169,6 +170,12 @@ static tAVRC_STS avrc_pars_vendor_cmd(tAVRC_MSG_VENDOR *p_msg, tAVRC_COMMAND *p_
    +             status = AVRC_STS_INTERNAL_ERR;
    +             break;
    +         }
    ++
    ++        if (p_result->get_cur_app_val.num_attr > AVRC_MAX_APP_ATTR_SIZE) {
    ++            android_errorWriteLog(0x534e4554, "63146237");
    ++            p_result->get_cur_app_val.num_attr = AVRC_MAX_APP_ATTR_SIZE;
    ++        }
    ++
    +         p_u8 = p_result->get_cur_app_val.attrs;
    +         for (xx=0, yy=0; xx< p_result->get_cur_app_val.num_attr; xx++)
    +         {
    +@@ -229,6 +236,11 @@ static tAVRC_STS avrc_pars_vendor_cmd(tAVRC_MSG_VENDOR *p_msg, tAVRC_COMMAND *p_
    +                     status = AVRC_STS_INTERNAL_ERR;
    +                 else
    +                 {
    ++                    if (p_result->get_app_val_txt.num_val > AVRC_MAX_APP_ATTR_SIZE) {
    ++                      android_errorWriteLog(0x534e4554, "63146237");
    ++                      p_result->get_app_val_txt.num_val = AVRC_MAX_APP_ATTR_SIZE;
    ++                    }
    ++       
    +                     p_u8 = p_result->get_app_val_txt.vals;
    +                     for (xx=0; xx< p_result->get_app_val_txt.num_val; xx++)
    +                     {
     diff --git a/stack/bnep/bnep_main.c b/stack/bnep/bnep_main.c
    -index 078a72e..36b76a1 100644
    +index 078a72e..3560d46 100644
     --- a/stack/bnep/bnep_main.c
     +++ b/stack/bnep/bnep_main.c
    -@@ -575,7 +575,8 @@ static void bnep_data_ind (UINT16 l2cap_cid, BT_HDR *p_buf)
    +@@ -35,6 +35,7 @@
    + 
    + #include "l2c_api.h"
    + #include "l2cdefs.h"
    ++#include "log/log.h"
    + 
    + #include "btu.h"
    + #include "btm_api.h"
    +@@ -495,6 +496,12 @@ static void bnep_data_ind (UINT16 l2cap_cid, BT_HDR *p_buf)
    +     type = *p++;
    +     extension_present = type >> 7;
    +     type &= 0x7f;
    ++    if (type >= sizeof(bnep_frame_hdr_sizes) / sizeof(bnep_frame_hdr_sizes[0])) {
    ++        BNEP_TRACE_EVENT("BNEP - rcvd frame, bad type: 0x%02x", type);
    ++        android_errorWriteLog(0x534e4554, "68818034");
    ++        osi_free(p_buf);
    ++        return;
    ++    }
    +     if ((rem_len <= bnep_frame_hdr_sizes[type]) || (rem_len > BNEP_MTU_SIZE))
    +     {
    +         BNEP_TRACE_EVENT ("BNEP - rcvd frame, bad len: %d  type: 0x%02x", p_buf->len, type);
    +@@ -524,20 +531,21 @@ static void bnep_data_ind (UINT16 l2cap_cid, BT_HDR *p_buf)
    +             org_len = rem_len;
    +             new_len = 0;
    +             do {
    +-
    ++		if (org_len < 2) break;
    +                 ext     = *p++;
    +                 length  = *p++;
    +                 p += length;
    + 
    ++                new_len = (length + 2);
    ++                if (new_len > org_len) break;
    ++
    +                 if ((!(ext & 0x7F)) && (*p > BNEP_FILTER_MULTI_ADDR_RESPONSE_MSG))
    +                     bnep_send_command_not_understood (p_bcb, *p);
    + 
    +-                new_len += (length + 2);
    +-
    +-                if (new_len > org_len)
    +-                    break;
    ++		org_len -= new_len;
    + 
    +             } while (ext & 0x80);
    ++            android_errorWriteLog(0x534e4554, "67863755");
    +         }
    + 
    +         osi_free(p_buf);
    +@@ -575,7 +583,8 @@ static void bnep_data_ind (UINT16 l2cap_cid, BT_HDR *p_buf)
                  p_bcb->con_state != BNEP_STATE_CONNECTED &&
                  extension_present && p && rem_len)
              {
    @@ -80,11 +304,36 @@ index 078a72e..36b76a1 100644
                  memcpy((UINT8 *)(p_bcb->p_pending_data + 1), p, rem_len);
                  p_bcb->p_pending_data->len    = rem_len;
                  p_bcb->p_pending_data->offset = 0;
    +@@ -585,6 +594,8 @@ static void bnep_data_ind (UINT16 l2cap_cid, BT_HDR *p_buf)
    +             while (extension_present && p && rem_len)
    +             {
    +                 ext_type = *p++;
    ++                rem_len--;
    ++                android_errorWriteLog(0x534e4554, "69271284");
    +                 extension_present = ext_type >> 7;
    +                 ext_type &= 0x7F;
    + 
    +@@ -656,6 +667,7 @@ static void bnep_data_ind (UINT16 l2cap_cid, BT_HDR *p_buf)
    +     if (bnep_cb.p_data_buf_cb)
    +     {
    +         (*bnep_cb.p_data_buf_cb)(p_bcb->handle, p_src_addr, p_dst_addr, protocol, p_buf, fw_ext_present);
    ++	osi_free(p_buf);
    +     }
    +     else if (bnep_cb.p_data_ind_cb)
    +     {
     diff --git a/stack/bnep/bnep_utils.c b/stack/bnep/bnep_utils.c
    -index 13fb189..e16ffca 100644
    +index 13fb189..05bcdda 100644
     --- a/stack/bnep/bnep_utils.c
     +++ b/stack/bnep/bnep_utils.c
    -@@ -154,6 +154,7 @@ void bnepu_release_bcb (tBNEP_CONN *p_bcb)
    +@@ -22,6 +22,7 @@
    +  *
    +  ******************************************************************************/
    + 
    ++#include <cutils/log.h>
    + #include <stdio.h>
    + #include <string.h>
    + #include "bt_common.h"
    +@@ -154,6 +155,7 @@ void bnepu_release_bcb (tBNEP_CONN *p_bcb)
      
          /* Drop any response pointer we may be holding */
          p_bcb->con_state        = BNEP_STATE_IDLE;
    @@ -92,7 +341,7 @@ index 13fb189..e16ffca 100644
          p_bcb->p_pending_data   = NULL;
      
          /* Free transmit queue */
    -@@ -762,35 +763,53 @@ void bnep_process_setup_conn_responce (tBNEP_CONN *p_bcb, UINT8 *p_setup)
    +@@ -762,35 +764,60 @@ void bnep_process_setup_conn_responce (tBNEP_CONN *p_bcb, UINT8 *p_setup)
      UINT8 *bnep_process_control_packet (tBNEP_CONN *p_bcb, UINT8 *p, UINT16 *rem_len, BOOLEAN is_ext)
      {
          UINT8       control_type;
    @@ -140,6 +389,13 @@ index 13fb189..e16ffca 100644
              break;
      
          case BNEP_SETUP_CONNECTION_REQUEST_MSG:
    ++        if (*rem_len < 1) {
    ++            BNEP_TRACE_ERROR(
    ++                "%s: Received BNEP_SETUP_CONNECTION_REQUEST_MSG with bad length",
    ++                __func__);
    ++            android_errorWriteLog(0x534e4554, "69177292");
    ++            goto bad_packet_length;
    ++        }
              len = *p++;
     -        if (*rem_len < ((2 * len) + 1))
     -        {
    @@ -154,7 +410,7 @@ index 13fb189..e16ffca 100644
              }
              if (!is_ext)
                  bnep_process_setup_conn_req (p_bcb, p, (UINT8)len);
    -@@ -799,6 +818,12 @@ UINT8 *bnep_process_control_packet (tBNEP_CONN *p_bcb, UINT8 *p, UINT16 *rem_len
    +@@ -799,6 +826,12 @@ UINT8 *bnep_process_control_packet (tBNEP_CONN *p_bcb, UINT8 *p, UINT16 *rem_len
              break;
      
          case BNEP_SETUP_CONNECTION_RESPONSE_MSG:
    @@ -167,7 +423,17 @@ index 13fb189..e16ffca 100644
              if (!is_ext)
                  bnep_process_setup_conn_responce (p_bcb, p);
              p += 2;
    -@@ -809,9 +834,10 @@ UINT8 *bnep_process_control_packet (tBNEP_CONN *p_bcb, UINT8 *p, UINT16 *rem_len
    +@@ -806,12 +839,20 @@ UINT8 *bnep_process_control_packet (tBNEP_CONN *p_bcb, UINT8 *p, UINT16 *rem_len
    +         break;
    + 
    +     case BNEP_FILTER_NET_TYPE_SET_MSG:
    ++        if (*rem_len < 2) {
    ++            BNEP_TRACE_ERROR(
    ++                "%s: Received BNEP_FILTER_NET_TYPE_SET_MSG with bad length",
    ++                __func__);
    ++            android_errorWriteLog(0x534e4554, "69177292");
    ++            goto bad_packet_length;
    ++        }
              BE_STREAM_TO_UINT16 (len, p);
              if (*rem_len < (len + 2))
              {
    @@ -181,7 +447,7 @@ index 13fb189..e16ffca 100644
              }
              bnepu_process_peer_filter_set (p_bcb, p, len);
              p += len;
    -@@ -819,6 +845,12 @@ UINT8 *bnep_process_control_packet (tBNEP_CONN *p_bcb, UINT8 *p, UINT16 *rem_len
    +@@ -819,18 +860,32 @@ UINT8 *bnep_process_control_packet (tBNEP_CONN *p_bcb, UINT8 *p, UINT16 *rem_len
              break;
      
          case BNEP_FILTER_NET_TYPE_RESPONSE_MSG:
    @@ -194,7 +460,16 @@ index 13fb189..e16ffca 100644
              bnepu_process_peer_filter_rsp (p_bcb, p);
              p += 2;
              *rem_len = *rem_len - 2;
    -@@ -828,9 +860,10 @@ UINT8 *bnep_process_control_packet (tBNEP_CONN *p_bcb, UINT8 *p, UINT16 *rem_len
    +         break;
    + 
    +     case BNEP_FILTER_MULTI_ADDR_SET_MSG:
    ++        if (*rem_len < 2) {
    ++            BNEP_TRACE_ERROR(
    ++                "%s: Received BNEP_FILTER_MULTI_ADDR_SET_MSG with bad length",
    ++                __func__);
    ++            android_errorWriteLog(0x534e4554, "69177292");
    ++            goto bad_packet_length;
    ++        }
              BE_STREAM_TO_UINT16 (len, p);
              if (*rem_len < (len + 2))
              {
    @@ -208,7 +483,7 @@ index 13fb189..e16ffca 100644
              }
              bnepu_process_peer_multicast_filter_set (p_bcb, p, len);
              p += len;
    -@@ -838,30 +871,38 @@ UINT8 *bnep_process_control_packet (tBNEP_CONN *p_bcb, UINT8 *p, UINT16 *rem_len
    +@@ -838,30 +893,38 @@ UINT8 *bnep_process_control_packet (tBNEP_CONN *p_bcb, UINT8 *p, UINT16 *rem_len
              break;
      
          case BNEP_FILTER_MULTI_ADDR_RESPONSE_MSG:
    @@ -257,6 +532,19 @@ index 13fb189..e16ffca 100644
      }
      
      
    +diff --git a/stack/btu/btu_init.c b/stack/btu/btu_init.c
    +index 688ed88..9f9ed0a 100644
    +--- a/stack/btu/btu_init.c
    ++++ b/stack/btu/btu_init.c
    +@@ -115,6 +115,8 @@ void btu_free_core(void)
    +       /* Free the mandatory core stack components */
    +       l2c_free();
    + 
    ++      sdp_free();
    ++
    + #if BLE_INCLUDED == TRUE
    +       gatt_free();
    + #endif
     diff --git a/stack/l2cap/l2cap_client.c b/stack/l2cap/l2cap_client.c
     index 7e8b3cb..cd7edfe 100644
     --- a/stack/l2cap/l2cap_client.c
    @@ -355,8 +643,37 @@ index 5c3a367..9268ff9 100644
      
          /* Requested destination role is */
          if (local_uuid->uu.uuid16 == UUID_SERVCLASS_PANU)
    +diff --git a/stack/sdp/sdp_main.c b/stack/sdp/sdp_main.c
    +index c888817..7cbe2d3 100644
    +--- a/stack/sdp/sdp_main.c
    ++++ b/stack/sdp/sdp_main.c
    +@@ -85,6 +85,10 @@ void sdp_init (void)
    +     /* Clears all structures and local SDP database (if Server is enabled) */
    +     memset (&sdp_cb, 0, sizeof (tSDP_CB));
    + 
    ++    for (int i = 0; i < SDP_MAX_CONNECTIONS; i++) {
    ++        sdp_cb.ccb[i].sdp_conn_timer = alarm_new("sdp.sdp_conn_timer");
    ++    }
    ++
    +     /* Initialize the L2CAP configuration. We only care about MTU and flush */
    +     sdp_cb.l2cap_my_cfg.mtu_present       = TRUE;
    +     sdp_cb.l2cap_my_cfg.mtu               = SDP_MTU_SIZE;
    +@@ -139,6 +143,13 @@ void sdp_init (void)
    +     }
    + }
    + 
    ++void sdp_free(void) {
    ++    for (int i = 0; i < SDP_MAX_CONNECTIONS; i++) {
    ++        alarm_free(sdp_cb.ccb[i].sdp_conn_timer);
    ++        sdp_cb.ccb[i].sdp_conn_timer = NULL;
    ++    }
    ++}
    ++
    + #if (defined(SDP_DEBUG) && SDP_DEBUG == TRUE)
    + /*******************************************************************************
    + **
     diff --git a/stack/sdp/sdp_server.c b/stack/sdp/sdp_server.c
    -index 627f4cf..5b0bde4 100644
    +index 627f4cf..43ea76e 100644
     --- a/stack/sdp/sdp_server.c
     +++ b/stack/sdp/sdp_server.c
     @@ -230,7 +230,7 @@ static void process_service_search (tCONN_CB *p_ccb, UINT16 trans_num,
    @@ -368,3 +685,78 @@ index 627f4cf..5b0bde4 100644
              {
                  sdpu_build_n_send_error (p_ccb, trans_num, SDP_INVALID_CONT_STATE,
                                           SDP_TEXT_BAD_CONT_INX);
    +@@ -360,6 +360,11 @@ static void process_service_attr_req (tCONN_CB *p_ccb, UINT16 trans_num,
    +         return;
    +     }
    + 
    ++    if (max_list_len < 4) {
    ++        sdpu_build_n_send_error(p_ccb, trans_num, SDP_ILLEGAL_PARAMETER, NULL);
    ++        return;
    ++    }
    ++
    +     /* Free and reallocate buffer */
    +     osi_free(p_ccb->rsp_list);
    +     p_ccb->rsp_list = (UINT8 *)osi_malloc(max_list_len);
    +@@ -584,6 +589,11 @@ static void process_service_search_attr_req (tCONN_CB *p_ccb, UINT16 trans_num,
    + 
    +     memcpy(&attr_seq_sav, &attr_seq, sizeof(tSDP_ATTR_SEQ)) ;
    + 
    ++    if (max_list_len < 4) {
    ++        sdpu_build_n_send_error(p_ccb, trans_num, SDP_ILLEGAL_PARAMETER, NULL);
    ++        return;
    ++    }
    ++
    +     /* Free and reallocate buffer */
    +     osi_free(p_ccb->rsp_list);
    +     p_ccb->rsp_list = (UINT8 *)osi_malloc(max_list_len);
    +diff --git a/stack/sdp/sdp_utils.c b/stack/sdp/sdp_utils.c
    +index a6f0ba6..aa1bfb5 100644
    +--- a/stack/sdp/sdp_utils.c
    ++++ b/stack/sdp/sdp_utils.c
    +@@ -120,8 +120,9 @@ tCONN_CB *sdpu_allocate_ccb (void)
    +     {
    +         if (p_ccb->con_state == SDP_STATE_IDLE)
    +         {
    ++            alarm_t* alarm = p_ccb->sdp_conn_timer;
    +             memset(p_ccb, 0, sizeof(tCONN_CB));
    +-            p_ccb->sdp_conn_timer = alarm_new("sdp.sdp_conn_timer");
    ++            p_ccb->sdp_conn_timer = alarm;
    +             return (p_ccb);
    +         }
    +     }
    +@@ -143,8 +144,7 @@ tCONN_CB *sdpu_allocate_ccb (void)
    + void sdpu_release_ccb (tCONN_CB *p_ccb)
    + {
    +     /* Ensure timer is stopped */
    +-    alarm_free(p_ccb->sdp_conn_timer);
    +-    p_ccb->sdp_conn_timer = NULL;
    ++    alarm_cancel(p_ccb->sdp_conn_timer);
    + 
    +     /* Drop any response pointer we may be holding */
    +     p_ccb->con_state = SDP_STATE_IDLE;
    +diff --git a/stack/sdp/sdpint.h b/stack/sdp/sdpint.h
    +index 05414cd..71dab92 100644
    +--- a/stack/sdp/sdpint.h
    ++++ b/stack/sdp/sdpint.h
    +@@ -246,6 +246,7 @@ extern tSDP_CB *sdp_cb_ptr;
    + 
    + /* Functions provided by sdp_main.c */
    + extern void     sdp_init (void);
    ++extern void     sdp_free(void);
    + extern void     sdp_disconnect (tCONN_CB*p_ccb, UINT16 reason);
    + 
    + #if (defined(SDP_DEBUG) && SDP_DEBUG == TRUE)
    +diff --git a/stack/smp/smp_utils.c b/stack/smp/smp_utils.c
    +index a7357db..93c9a23 100644
    +--- a/stack/smp/smp_utils.c
    ++++ b/stack/smp/smp_utils.c
    +@@ -297,8 +297,7 @@ BOOLEAN  smp_send_msg_to_L2CAP(BD_ADDR rem_bda, BT_HDR *p_toL2CAP)
    +     if ((l2cap_ret = L2CA_SendFixedChnlData (fixed_cid, rem_bda, p_toL2CAP)) == L2CAP_DW_FAILED)
    +     {
    +         smp_cb.total_tx_unacked -= 1;
    +-        SMP_TRACE_ERROR("SMP   failed to pass msg:0x%0x to L2CAP",
    +-                         *((UINT8 *)(p_toL2CAP + 1) + p_toL2CAP->offset));
    ++	SMP_TRACE_ERROR("SMP failed to pass msg to L2CAP");
    +         return FALSE;
    +     }
    +     else
    diff --git a/system_security.patch b/system_security.patch
    new file mode 100644
    index 0000000..e69de29
    diff --git a/update_engine.patch b/update_engine.patch
    new file mode 100644
    index 0000000..d6b0205
    --- /dev/null
    +++ b/update_engine.patch
    @@ -0,0 +1,554 @@
    +diff --git a/common/error_code.h b/common/error_code.h
    +index 32155f2..3800bf0 100644
    +--- a/common/error_code.h
    ++++ b/common/error_code.h
    +@@ -72,6 +72,9 @@ enum class ErrorCode : int {
    +   kOmahaRequestXMLHasEntityDecl = 46,
    +   kFilesystemVerifierError = 47,
    +   kUserCanceled = 48,
    ++  kNonCriticalUpdateInOOBE = 49,
    ++  // kOmahaUpdateIgnoredOverCellular = 50,
    ++  kPayloadTimestampError = 51,
    + 
    +   // VERY IMPORTANT! When adding new error codes:
    +   //
    +diff --git a/common/error_code_utils.cc b/common/error_code_utils.cc
    +index dc9eaf4..0a015eb 100644
    +--- a/common/error_code_utils.cc
    ++++ b/common/error_code_utils.cc
    +@@ -142,6 +142,10 @@ string ErrorCodeToString(ErrorCode code) {
    +       return "ErrorCode::kFilesystemVerifierError";
    +     case ErrorCode::kUserCanceled:
    +       return "ErrorCode::kUserCanceled";
    ++    case ErrorCode::kNonCriticalUpdateInOOBE:
    ++      return "ErrorCode::kNonCriticalUpdateInOOBE";
    ++    case ErrorCode::kPayloadTimestampError:
    ++      return "ErrorCode::kPayloadTimestampError";
    +     // Don't add a default case to let the compiler warn about newly added
    +     // error codes which should be added here.
    +   }
    +diff --git a/common/fake_hardware.h b/common/fake_hardware.h
    +index 0bd297b..25324ae 100644
    +--- a/common/fake_hardware.h
    ++++ b/common/fake_hardware.h
    +@@ -82,6 +82,8 @@ class FakeHardware : public HardwareInterface {
    +     return false;
    +   }
    + 
    ++  int64_t GetBuildTimestamp() const override { return build_timestamp_; }
    ++
    +   // Setters
    +   void SetIsOfficialBuild(bool is_official_build) {
    +     is_official_build_ = is_official_build;
    +@@ -118,6 +120,10 @@ class FakeHardware : public HardwareInterface {
    +     powerwash_count_ = powerwash_count;
    +   }
    + 
    ++  void SetBuildTimestamp(int64_t build_timestamp) {
    ++    build_timestamp_ = build_timestamp;
    ++  }
    ++
    +  private:
    +   bool is_official_build_;
    +   bool is_normal_boot_mode_;
    +@@ -128,6 +134,7 @@ class FakeHardware : public HardwareInterface {
    +   std::string ec_version_;
    +   int powerwash_count_;
    +   bool powerwash_scheduled_{false};
    ++  int64_t build_timestamp_{0};
    + 
    +   DISALLOW_COPY_AND_ASSIGN(FakeHardware);
    + };
    +diff --git a/common/hardware_interface.h b/common/hardware_interface.h
    +index c2d4296..d5f73f7 100644
    +--- a/common/hardware_interface.h
    ++++ b/common/hardware_interface.h
    +@@ -17,6 +17,8 @@
    + #ifndef UPDATE_ENGINE_COMMON_HARDWARE_INTERFACE_H_
    + #define UPDATE_ENGINE_COMMON_HARDWARE_INTERFACE_H_
    + 
    ++#include <stdint.h>
    ++
    + #include <string>
    + #include <vector>
    + 
    +@@ -81,6 +83,9 @@ class HardwareInterface {
    +   // powerwash cycles. In case of an error, such as no directory available,
    +   // returns false.
    +   virtual bool GetPowerwashSafeDirectory(base::FilePath* path) const = 0;
    ++
    ++  // Returns the timestamp of the current OS build.
    ++  virtual int64_t GetBuildTimestamp() const = 0;
    + };
    + 
    + }  // namespace chromeos_update_engine
    +diff --git a/hardware_android.cc b/hardware_android.cc
    +index 778f8ad..9490c24 100644
    +--- a/hardware_android.cc
    ++++ b/hardware_android.cc
    +@@ -25,6 +25,7 @@
    + #include <bootloader.h>
    + 
    + #include <base/files/file_util.h>
    ++#include <base/strings/stringprintf.h>
    + #include <brillo/make_unique_ptr.h>
    + #include <cutils/properties.h>
    + 
    +@@ -45,6 +46,16 @@ const char kAndroidRecoveryPowerwashCommand[] =
    +     "--wipe_data\n"
    +     "--reason=wipe_data_from_ota\n";
    + 
    ++// Android properties that identify the hardware and potentially non-updatable
    ++// parts of the bootloader (such as the bootloader version and the baseband
    ++// version).
    ++const char kPropBootBootloader[] = "ro.boot.bootloader";
    ++const char kPropBootBaseband[] = "ro.boot.baseband";
    ++const char kPropProductManufacturer[] = "ro.product.manufacturer";
    ++const char kPropBootHardwareSKU[] = "ro.boot.hardware.sku";
    ++const char kPropBootRevision[] = "ro.boot.revision";
    ++const char kPropBuildDateUTC[] = "ro.build.date.utc";
    ++
    + // Write a recovery command line |message| to the BCB. The arguments to recovery
    + // must be separated by '\n'. An empty string will erase the BCB.
    + bool WriteBootloaderRecoveryMessage(const string& message) {
    +@@ -122,26 +133,43 @@ bool HardwareAndroid::IsNormalBootMode() const {
    +   return property_get_bool("ro.debuggable", 0) != 1;
    + }
    + 
    ++bool HardwareAndroid::AreDevFeaturesEnabled() const {
    ++  return !IsNormalBootMode();
    ++}
    ++
    ++bool HardwareAndroid::IsOOBEEnabled() const {
    ++  // No OOBE flow blocking updates for Android-based boards.
    ++  return false;
    ++}
    ++
    + bool HardwareAndroid::IsOOBEComplete(base::Time* out_time_of_oobe) const {
    +-  LOG(WARNING) << "STUB: Assuming OOBE is complete.";
    ++  LOG(WARNING) << "OOBE is not enabled but IsOOBEComplete() called.";
    +   if (out_time_of_oobe)
    +     *out_time_of_oobe = base::Time();
    +   return true;
    + }
    + 
    + string HardwareAndroid::GetHardwareClass() const {
    +-  LOG(WARNING) << "STUB: GetHardwareClass().";
    +-  return "ANDROID";
    ++  char manufacturer[PROPERTY_VALUE_MAX];
    ++  char sku[PROPERTY_VALUE_MAX];
    ++  char revision[PROPERTY_VALUE_MAX];
    ++  property_get(kPropBootHardwareSKU, sku, "");
    ++  property_get(kPropProductManufacturer, manufacturer, "");
    ++  property_get(kPropBootRevision, revision, "");
    ++
    ++  return base::StringPrintf("%s:%s:%s", manufacturer, sku, revision);
    + }
    + 
    + string HardwareAndroid::GetFirmwareVersion() const {
    +-  LOG(WARNING) << "STUB: GetFirmwareVersion().";
    +-  return "0";
    ++  char bootloader[PROPERTY_VALUE_MAX];
    ++  property_get(kPropBootBootloader, bootloader, "");
    ++  return bootloader;
    + }
    + 
    + string HardwareAndroid::GetECVersion() const {
    +-  LOG(WARNING) << "STUB: GetECVersion().";
    +-  return "0";
    ++  char baseband[PROPERTY_VALUE_MAX];
    ++  property_get(kPropBootBaseband, baseband, "");
    ++  return baseband;
    + }
    + 
    + int HardwareAndroid::GetPowerwashCount() const {
    +@@ -173,4 +201,8 @@ bool HardwareAndroid::GetPowerwashSafeDirectory(base::FilePath* path) const {
    +   return false;
    + }
    + 
    ++int64_t HardwareAndroid::GetBuildTimestamp() const {
    ++  return property_get_int64(kPropBuildDateUTC, 0);
    ++}
    ++
    + }  // namespace chromeos_update_engine
    +diff --git a/hardware_android.h b/hardware_android.h
    +index 4ea3404..6561377 100644
    +--- a/hardware_android.h
    ++++ b/hardware_android.h
    +@@ -45,6 +45,7 @@ class HardwareAndroid final : public HardwareInterface {
    +   bool CancelPowerwash() override;
    +   bool GetNonVolatileDirectory(base::FilePath* path) const override;
    +   bool GetPowerwashSafeDirectory(base::FilePath* path) const override;
    ++  int64_t GetBuildTimestamp() const override;
    + 
    +  private:
    +   DISALLOW_COPY_AND_ASSIGN(HardwareAndroid);
    +diff --git a/hardware_chromeos.cc b/hardware_chromeos.cc
    +index 85131fc..f0f3ea9 100644
    +--- a/hardware_chromeos.cc
    ++++ b/hardware_chromeos.cc
    +@@ -16,22 +16,27 @@
    + 
    + #include "update_engine/hardware_chromeos.h"
    + 
    ++#include <base/files/file_path.h>
    + #include <base/files/file_util.h>
    + #include <base/logging.h>
    + #include <base/strings/string_number_conversions.h>
    + #include <base/strings/string_util.h>
    ++#include <brillo/key_value_store.h>
    + #include <brillo/make_unique_ptr.h>
    ++#include <debugd/dbus-constants.h>
    + #include <vboot/crossystem.h>
    + 
    + extern "C" {
    + #include "vboot/vboot_host.h"
    + }
    + 
    ++#include "update_engine/common/constants.h"
    + #include "update_engine/common/hardware.h"
    + #include "update_engine/common/hwid_override.h"
    + #include "update_engine/common/platform_constants.h"
    + #include "update_engine/common/subprocess.h"
    + #include "update_engine/common/utils.h"
    ++#include "update_engine/dbus_connection.h"
    + 
    + using std::string;
    + using std::vector;
    +@@ -50,6 +55,14 @@ const char kPowerwashSafeDirectory[] =
    + // a powerwash is performed.
    + const char kPowerwashCountMarker[] = "powerwash_count";
    + 
    ++// The name of the marker file used to trigger powerwash when post-install
    ++// completes successfully so that the device is powerwashed on next reboot.
    ++const char kPowerwashMarkerFile[] =
    ++    "/mnt/stateful_partition/factory_install_reset";
    ++
    ++// The contents of the powerwash marker file.
    ++const char kPowerwashCommand[] = "safe fast keepimg reason=update_engine\n";
    ++
    + // UpdateManager config path.
    + const char* kConfigFilePath = "/etc/update_manager.conf";
    + 
    +@@ -64,11 +77,19 @@ namespace hardware {
    + 
    + // Factory defined in hardware.h.
    + std::unique_ptr<HardwareInterface> CreateHardware() {
    +-  return brillo::make_unique_ptr(new HardwareChromeOS());
    ++  std::unique_ptr<HardwareChromeOS> hardware(new HardwareChromeOS());
    ++  hardware->Init();
    ++  return std::move(hardware);
    + }
    + 
    + }  // namespace hardware
    + 
    ++void HardwareChromeOS::Init() {
    ++  LoadConfig("" /* root_prefix */, IsNormalBootMode());
    ++  debugd_proxy_.reset(
    ++      new org::chromium::debugdProxy(DBusConnection::Get()->GetDBus()));
    ++}
    ++
    + bool HardwareChromeOS::IsOfficialBuild() const {
    +   return VbGetSystemPropertyInt("debug_build") == 0;
    + }
    +@@ -78,7 +99,32 @@ bool HardwareChromeOS::IsNormalBootMode() const {
    +   return !dev_mode;
    + }
    + 
    ++bool HardwareChromeOS::AreDevFeaturesEnabled() const {
    ++  // Even though the debugd tools are also gated on devmode, checking here can
    ++  // save us a D-Bus call so it's worth doing explicitly.
    ++  if (IsNormalBootMode())
    ++    return false;
    ++
    ++  int32_t dev_features = debugd::DEV_FEATURES_DISABLED;
    ++  brillo::ErrorPtr error;
    ++  // Some boards may not include debugd so it's expected that this may fail,
    ++  // in which case we treat it as disabled.
    ++  if (debugd_proxy_ && debugd_proxy_->QueryDevFeatures(&dev_features, &error) &&
    ++      !(dev_features & debugd::DEV_FEATURES_DISABLED)) {
    ++    LOG(INFO) << "Debugd dev tools enabled.";
    ++    return true;
    ++  }
    ++  return false;
    ++}
    ++
    ++bool HardwareChromeOS::IsOOBEEnabled() const {
    ++  return is_oobe_enabled_;
    ++}
    ++
    + bool HardwareChromeOS::IsOOBEComplete(base::Time* out_time_of_oobe) const {
    ++  if (!is_oobe_enabled_) {
    ++    LOG(WARNING) << "OOBE is not enabled but IsOOBEComplete() was called";
    ++  }
    +   struct stat statbuf;
    +   if (stat(kOOBECompletedMarker, &statbuf) != 0) {
    +     if (errno != ENOENT) {
    +@@ -150,9 +196,11 @@ bool HardwareChromeOS::SchedulePowerwash() {
    +   bool result = utils::WriteFile(
    +       kPowerwashMarkerFile, kPowerwashCommand, strlen(kPowerwashCommand));
    +   if (result) {
    +-    LOG(INFO) << "Created " << marker_file << " to powerwash on next reboot";
    ++    LOG(INFO) << "Created " << kPowerwashMarkerFile
    ++              << " to powerwash on next reboot";
    +   } else {
    +-    PLOG(ERROR) << "Error in creating powerwash marker file: " << marker_file;
    ++    PLOG(ERROR) << "Error in creating powerwash marker file: "
    ++                << kPowerwashMarkerFile;
    +   }
    + 
    +   return result;
    +@@ -163,10 +211,10 @@ bool HardwareChromeOS::CancelPowerwash() {
    + 
    +   if (result) {
    +     LOG(INFO) << "Successfully deleted the powerwash marker file : "
    +-              << marker_file;
    ++              << kPowerwashMarkerFile;
    +   } else {
    +     PLOG(ERROR) << "Could not delete the powerwash marker file : "
    +-                << marker_file;
    ++                << kPowerwashMarkerFile;
    +   }
    + 
    +   return result;
    +@@ -182,4 +230,27 @@ bool HardwareChromeOS::GetPowerwashSafeDirectory(base::FilePath* path) const {
    +   return true;
    + }
    + 
    ++int64_t HardwareChromeOS::GetBuildTimestamp() const {
    ++  // TODO(senj): implement this in Chrome OS.
    ++  return 0;
    ++}
    ++
    ++void HardwareChromeOS::LoadConfig(const string& root_prefix, bool normal_mode) {
    ++  brillo::KeyValueStore store;
    ++
    ++  if (normal_mode) {
    ++    store.Load(base::FilePath(root_prefix + kConfigFilePath));
    ++  } else {
    ++    if (store.Load(base::FilePath(root_prefix + kStatefulPartition +
    ++                                  kConfigFilePath))) {
    ++      LOG(INFO) << "UpdateManager Config loaded from stateful partition.";
    ++    } else {
    ++      store.Load(base::FilePath(root_prefix + kConfigFilePath));
    ++    }
    ++  }
    ++
    ++  if (!store.GetBoolean(kConfigOptsIsOOBEEnabled, &is_oobe_enabled_))
    ++    is_oobe_enabled_ = true;  // Default value.
    ++}
    ++
    + }  // namespace chromeos_update_engine
    +diff --git a/hardware_chromeos.h b/hardware_chromeos.h
    +index 221f12c..e3f086f 100644
    +--- a/hardware_chromeos.h
    ++++ b/hardware_chromeos.h
    +@@ -46,6 +46,7 @@ class HardwareChromeOS final : public HardwareInterface {
    +   bool CancelPowerwash() override;
    +   bool GetNonVolatileDirectory(base::FilePath* path) const override;
    +   bool GetPowerwashSafeDirectory(base::FilePath* path) const override;
    ++  int64_t GetBuildTimestamp() const override;
    + 
    +  private:
    +   DISALLOW_COPY_AND_ASSIGN(HardwareChromeOS);
    +diff --git a/metrics_utils.cc b/metrics_utils.cc
    +index 11260fc..433ca1e 100644
    +--- a/metrics_utils.cc
    ++++ b/metrics_utils.cc
    +@@ -74,6 +74,7 @@ metrics::AttemptResult GetAttemptResult(ErrorCode code) {
    +     case ErrorCode::kDownloadPayloadVerificationError:
    +     case ErrorCode::kSignedDeltaPayloadExpectedError:
    +     case ErrorCode::kDownloadPayloadPubKeyVerificationError:
    ++    case ErrorCode::kPayloadTimestampError:
    +       return metrics::AttemptResult::kPayloadVerificationFailed;
    + 
    +     case ErrorCode::kNewRootfsVerificationError:
    +@@ -205,6 +206,7 @@ metrics::DownloadErrorCode GetDownloadErrorCode(ErrorCode code) {
    +     case ErrorCode::kOmahaRequestXMLHasEntityDecl:
    +     case ErrorCode::kFilesystemVerifierError:
    +     case ErrorCode::kUserCanceled:
    ++    case ErrorCode::kPayloadTimestampError:
    +       break;
    + 
    +     // Special flags. These can't happen (we mask them out above) but
    +diff --git a/payload_consumer/delta_performer.cc b/payload_consumer/delta_performer.cc
    +index a156132..b338d34 100644
    +--- a/payload_consumer/delta_performer.cc
    ++++ b/payload_consumer/delta_performer.cc
    +@@ -1502,6 +1502,14 @@ ErrorCode DeltaPerformer::ValidateManifest() {
    +     }
    +   }
    + 
    ++  if (manifest_.max_timestamp() < hardware_->GetBuildTimestamp()) {
    ++    LOG(ERROR) << "The current OS build timestamp ("
    ++               << hardware_->GetBuildTimestamp()
    ++               << ") is newer than the maximum timestamp in the manifest ("
    ++               << manifest_.max_timestamp() << ")";
    ++    return ErrorCode::kPayloadTimestampError;
    ++  }
    ++
    +   // TODO(garnold) we should be adding more and more manifest checks, such as
    +   // partition boundaries etc (see chromium-os:37661).
    + 
    +diff --git a/payload_consumer/delta_performer_unittest.cc b/payload_consumer/delta_performer_unittest.cc
    +index d1918b7..2ee4516 100644
    +--- a/payload_consumer/delta_performer_unittest.cc
    ++++ b/payload_consumer/delta_performer_unittest.cc
    +@@ -638,6 +638,20 @@ TEST_F(DeltaPerformerTest, ValidateManifestBadMinorVersion) {
    +                         ErrorCode::kUnsupportedMinorPayloadVersion);
    + }
    + 
    ++TEST_F(DeltaPerformerTest, ValidateManifestDowngrade) {
    ++  // The Manifest we are validating.
    ++  DeltaArchiveManifest manifest;
    ++
    ++  manifest.set_minor_version(kFullPayloadMinorVersion);
    ++  manifest.set_max_timestamp(1);
    ++  fake_hardware_.SetBuildTimestamp(2);
    ++
    ++  RunManifestValidation(manifest,
    ++                        DeltaPerformer::kSupportedMajorPayloadVersion,
    ++                        InstallPayloadType::kFull,
    ++                        ErrorCode::kPayloadTimestampError);
    ++}
    ++
    + TEST_F(DeltaPerformerTest, BrilloMetadataSignatureSizeTest) {
    +   EXPECT_TRUE(performer_.Write(kDeltaMagic, sizeof(kDeltaMagic)));
    + 
    +diff --git a/payload_generator/generate_delta_main.cc b/payload_generator/generate_delta_main.cc
    +index 0716c1f..85785c5 100644
    +--- a/payload_generator/generate_delta_main.cc
    ++++ b/payload_generator/generate_delta_main.cc
    +@@ -322,6 +322,10 @@ int Main(int argc, char** argv) {
    +   DEFINE_string(zlib_fingerprint, "",
    +                 "The fingerprint of zlib in the source image in hash string "
    +                 "format, used to check imgdiff compatibility.");
    ++  DEFINE_int64(max_timestamp,
    ++               0,
    ++               "The maximum timestamp of the OS allowed to apply this "
    ++               "payload.");
    + 
    +   DEFINE_string(old_channel, "",
    +                 "The channel for the old image. 'dev-channel', 'npo-channel', "
    +@@ -573,6 +577,8 @@ int Main(int argc, char** argv) {
    +     }
    +   }
    + 
    ++  payload_config.max_timestamp = FLAGS_max_timestamp;
    ++
    +   if (payload_config.is_delta) {
    +     LOG(INFO) << "Generating delta update";
    +   } else {
    +diff --git a/payload_generator/payload_file.cc b/payload_generator/payload_file.cc
    +index 2f95b21..d2ae706 100644
    +--- a/payload_generator/payload_file.cc
    ++++ b/payload_generator/payload_file.cc
    +@@ -70,6 +70,7 @@ bool PayloadFile::Init(const PayloadGenerationConfig& config) {
    +     *(manifest_.mutable_new_image_info()) = config.target.image_info;
    + 
    +   manifest_.set_block_size(config.block_size);
    ++  manifest_.set_max_timestamp(config.max_timestamp);
    +   return true;
    + }
    + 
    +diff --git a/payload_generator/payload_generation_config.h b/payload_generator/payload_generation_config.h
    +index 8617d14..dd3242a 100644
    +--- a/payload_generator/payload_generation_config.h
    ++++ b/payload_generator/payload_generation_config.h
    +@@ -190,6 +190,9 @@ struct PayloadGenerationConfig {
    + 
    +   // The block size used for all the operations in the manifest.
    +   size_t block_size = 4096;
    ++
    ++  // The maximum timestamp of the OS allowed to apply this payload.
    ++  int64_t max_timestamp = 0;
    + };
    + 
    + }  // namespace chromeos_update_engine
    +diff --git a/payload_state.cc b/payload_state.cc
    +index 04b6579..7859420 100644
    +--- a/payload_state.cc
    ++++ b/payload_state.cc
    +@@ -295,6 +295,7 @@ void PayloadState::UpdateFailed(ErrorCode error) {
    +     case ErrorCode::kPayloadMismatchedType:
    +     case ErrorCode::kUnsupportedMajorPayloadVersion:
    +     case ErrorCode::kUnsupportedMinorPayloadVersion:
    ++    case ErrorCode::kPayloadTimestampError:
    +       IncrementUrlIndex();
    +       break;
    + 
    +diff --git a/scripts/brillo_update_payload b/scripts/brillo_update_payload
    +index 8d51118..9b599d4 100755
    +--- a/scripts/brillo_update_payload
    ++++ b/scripts/brillo_update_payload
    +@@ -143,6 +143,10 @@ if [[ "${COMMAND}" == "generate" ]]; then
    +     "Optional: Path to a source image. If specified, this makes a delta update."
    +   DEFINE_string metadata_size_file "" \
    +     "Optional: Path to output metadata size."
    ++  DEFINE_string max_timestamp "" \
    ++    "Optional: The maximum unix timestamp of the OS allowed to apply this \
    ++payload, should be set to a number higher than the build timestamp of the \
    ++system running on the device, 0 if not specified."
    + fi
    + if [[ "${COMMAND}" == "hash" || "${COMMAND}" == "sign" ]]; then
    +   DEFINE_string unsigned_payload "" "Path to the input unsigned payload."
    +@@ -524,6 +528,10 @@ cmd_generate() {
    +     GENERATOR_ARGS+=( --out_metadata_size_file="${FLAGS_metadata_size_file}" )
    +   fi
    + 
    ++  if [[ -n "${FLAGS_max_timestamp}" ]]; then
    ++    GENERATOR_ARGS+=( --max_timestamp="${FLAGS_max_timestamp}" )
    ++  fi
    ++
    +   if [[ -n "${POSTINSTALL_CONFIG_FILE}" ]]; then
    +     GENERATOR_ARGS+=(
    +       --new_postinstall_config_file="${POSTINSTALL_CONFIG_FILE}"
    +diff --git a/update_attempter_android.cc b/update_attempter_android.cc
    +index 1269cef..0fa1fa1 100644
    +--- a/update_attempter_android.cc
    ++++ b/update_attempter_android.cc
    +@@ -26,6 +26,7 @@
    + #include <brillo/bind_lambda.h>
    + #include <brillo/message_loops/message_loop.h>
    + #include <brillo/strings/string_utils.h>
    ++#include <log/log.h>
    + 
    + #include "update_engine/common/constants.h"
    + #include "update_engine/common/file_fetcher.h"
    +@@ -308,6 +309,11 @@ void UpdateAttempterAndroid::ProcessingDone(const ActionProcessor* processor,
    +       LOG(INFO) << "Resetting update progress.";
    +       break;
    + 
    ++    case ErrorCode::kPayloadTimestampError:
    ++      // SafetyNet logging, b/36232423
    ++      android_errorWriteLog(0x534e4554, "36232423");
    ++      break;
    ++
    +     default:
    +       // Ignore all other error codes.
    +       break;
    +diff --git a/update_manager/chromeos_policy.cc b/update_manager/chromeos_policy.cc
    +index aed2aaa..02ec19f 100644
    +--- a/update_manager/chromeos_policy.cc
    ++++ b/update_manager/chromeos_policy.cc
    +@@ -76,6 +76,7 @@ bool HandleErrorCode(ErrorCode err_code, int* url_num_error_p) {
    +     case ErrorCode::kPayloadMismatchedType:
    +     case ErrorCode::kUnsupportedMajorPayloadVersion:
    +     case ErrorCode::kUnsupportedMinorPayloadVersion:
    ++    case ErrorCode::kPayloadTimestampError:
    +       LOG(INFO) << "Advancing download URL due to error "
    +                 << chromeos_update_engine::utils::ErrorCodeToString(err_code)
    +                 << " (" << static_cast<int>(err_code) << ")";
    +diff --git a/update_metadata.proto b/update_metadata.proto
    +index 454c736..596a04e 100644
    +--- a/update_metadata.proto
    ++++ b/update_metadata.proto
    +@@ -281,4 +281,8 @@ message DeltaArchiveManifest {
    +   // array can have more than two partitions if needed, and they are identified
    +   // by the partition name.
    +   repeated PartitionUpdate partitions = 13;
    ++
    ++  // The maximum timestamp of the OS allowed to apply this payload.
    ++  // Can be used to prevent downgrading the OS.
    ++  optional int64 max_timestamp = 14;
    + }
    
    From 64b0de91f541d5beb540bcccfe4077e171986ada Mon Sep 17 00:00:00 2001
    From: AndDiSa <anddisa@googlemail.com>
    Date: Sun, 13 May 2018 14:31:47 +0200
    Subject: [PATCH 094/159] update patches
    
    Change-Id: I15c28a63a5356358e9633e0a2feb277c40c19ecc
    ---
     build.patch                  |  4 +-
     frameworks_av.patch          | 32 +++++++++++-
     frameworks_base.patch        | 94 ++++++++++++++++++++++++++++++++++++
     frameworks_op_net_wifi.patch | 48 ++++++++++++++++++
     system_sepolicy.patch        | 16 ++++--
     5 files changed, 188 insertions(+), 6 deletions(-)
    
    diff --git a/build.patch b/build.patch
    index 633eadf..d33eee3 100644
    --- a/build.patch
    +++ b/build.patch
    @@ -323,7 +323,7 @@ index 0000000..80664fa
     +ALL_PREBUILT += $(INSTALLED_KERNEL_TARGET)
     +endif
     diff --git a/core/version_defaults.mk b/core/version_defaults.mk
    -index 7c96344..d9e7159 100644
    +index 7c96344..14048ef 100644
     --- a/core/version_defaults.mk
     +++ b/core/version_defaults.mk
     @@ -131,7 +131,7 @@ ifeq "" "$(PLATFORM_SECURITY_PATCH)"
    @@ -331,7 +331,7 @@ index 7c96344..d9e7159 100644
          #  It must match one of the Android Security Patch Level strings of the Public Security Bulletins.
          #  If there is no $PLATFORM_SECURITY_PATCH set, keep it empty.
     -    PLATFORM_SECURITY_PATCH := 2017-08-05
    -+    PLATFORM_SECURITY_PATCH := 2018-04-05
    ++    PLATFORM_SECURITY_PATCH := 2018-05-05
      endif
      
      ifeq "" "$(PLATFORM_BASE_OS)"
    diff --git a/frameworks_av.patch b/frameworks_av.patch
    index 2945cf5..647ae82 100644
    --- a/frameworks_av.patch
    +++ b/frameworks_av.patch
    @@ -2087,7 +2087,7 @@ index b43635d..02555a2 100644
              kInputPortIndex = 0,
              kOutputPortIndex = 1,
     diff --git a/media/libstagefright/mpeg2ts/ESQueue.cpp b/media/libstagefright/mpeg2ts/ESQueue.cpp
    -index 96ca405..7599c13 100644
    +index 96ca405..c454a0e 100644
     --- a/media/libstagefright/mpeg2ts/ESQueue.cpp
     +++ b/media/libstagefright/mpeg2ts/ESQueue.cpp
     @@ -716,6 +716,11 @@ sp<ABuffer> ElementaryStreamQueue::dequeueAccessUnitAAC() {
    @@ -2102,6 +2102,36 @@ index 96ca405..7599c13 100644
      
              bits.skipBits(11);  // adts_buffer_fullness
      
    +@@ -1197,7 +1202,9 @@ static ssize_t getNextChunkSize(
    +         const uint8_t *data, size_t size) {
    +     static const char kStartCode[] = "\x00\x00\x01";
    + 
    +-    if (size < 3) {
    ++    // per ISO/IEC 14496-2 6.2.1, a chunk has a 3-byte prefix + 1-byte start code
    ++    // we need at least <prefix><start><next prefix> to successfully scan
    ++    if (size < 3 + 1 + 3) {
    +         return -EAGAIN;
    +     }
    + 
    +@@ -1205,7 +1212,7 @@ static ssize_t getNextChunkSize(
    +         return -EAGAIN;
    +     }
    + 
    +-    size_t offset = 3;
    ++    size_t offset = 4;
    +     while (offset + 2 < size) {
    +         if (!memcmp(&data[offset], kStartCode, 3)) {
    +             return offset;
    +@@ -1256,6 +1263,9 @@ sp<ABuffer> ElementaryStreamQueue::dequeueAccessUnitMPEG4Video() {
    +                     state = EXPECT_VISUAL_OBJECT_START;
    +                 } else {
    +                     discard = true;
    ++                    offset += chunkSize;
    ++                    ALOGW("b/74114680, advance to next chunk");
    ++                    android_errorWriteLog(0x534e4554, "74114680");
    +                 }
    +                 break;
    +             }
     diff --git a/media/libstagefright/omx/Android.mk b/media/libstagefright/omx/Android.mk
     index e4fbd81..8fc788f 100644
     --- a/media/libstagefright/omx/Android.mk
    diff --git a/frameworks_base.patch b/frameworks_base.patch
    index e2538fe..9a23344 100644
    --- a/frameworks_base.patch
    +++ b/frameworks_base.patch
    @@ -288,6 +288,31 @@ index 8c5df08..8c2c236 100644
                  //Slog.i(TAG, "Setting state in " + mName + "/" + mPackage + ": " + state);
                  commitStateTime(now);
                  mCurState = state;
    +diff --git a/core/java/com/android/internal/app/procstats/SparseMappingTable.java b/core/java/com/android/internal/app/procstats/SparseMappingTable.java
    +index f941836..6d79d3b 100644
    +--- a/core/java/com/android/internal/app/procstats/SparseMappingTable.java
    ++++ b/core/java/com/android/internal/app/procstats/SparseMappingTable.java
    +@@ -18,6 +18,7 @@ package com.android.internal.app.procstats;
    + 
    + import android.os.Build;
    + import android.os.Parcel;
    ++import android.util.EventLog;
    + import android.util.Slog;
    + import libcore.util.EmptyArray;
    + 
    +@@ -529,6 +530,12 @@ public class SparseMappingTable {
    +             readCompactedLongArray(in, array, size);
    +             mLongs.add(array);
    +         }
    ++        // Verify that last array's length is consistent with writeToParcel
    ++        if (N > 0 && mLongs.get(N - 1).length != mNextIndex) {
    ++            EventLog.writeEvent(0x534e4554, "73252178", -1, "");
    ++            throw new IllegalStateException("Expected array of length " + mNextIndex + " but was "
    ++                    + mLongs.get(N - 1).length);
    ++        }
    +     }
    + 
    +     /**
     diff --git a/core/java/com/android/internal/os/ZygoteInit.java b/core/java/com/android/internal/os/ZygoteInit.java
     index e4f573b..0d3f50c 100644
     --- a/core/java/com/android/internal/os/ZygoteInit.java
    @@ -316,6 +341,62 @@ index 48109ca..c4d91e0 100644
                  }
              }
          }
    +diff --git a/core/java/com/android/internal/widget/ViewPager.java b/core/java/com/android/internal/widget/ViewPager.java
    +index d5b6def..df1ed7d 100644
    +--- a/core/java/com/android/internal/widget/ViewPager.java
    ++++ b/core/java/com/android/internal/widget/ViewPager.java
    +@@ -31,6 +31,7 @@ import android.os.Parcelable;
    + import android.util.AttributeSet;
    + import android.util.Log;
    + import android.util.MathUtils;
    ++import android.view.AbsSavedState;
    + import android.view.FocusFinder;
    + import android.view.Gravity;
    + import android.view.KeyEvent;
    +@@ -1198,15 +1199,11 @@ public class ViewPager extends ViewGroup {
    +      * state, in which case it should implement a subclass of this which
    +      * contains that state.
    +      */
    +-    public static class SavedState extends BaseSavedState {
    ++    public static class SavedState extends AbsSavedState {
    +         int position;
    +         Parcelable adapterState;
    +         ClassLoader loader;
    + 
    +-        public SavedState(Parcel source) {
    +-            super(source);
    +-        }
    +-
    +         public SavedState(Parcelable superState) {
    +             super(superState);
    +         }
    +@@ -1225,10 +1222,15 @@ public class ViewPager extends ViewGroup {
    +                     + " position=" + position + "}";
    +         }
    + 
    +-        public static final Creator<SavedState> CREATOR = new Creator<SavedState>() {
    ++        public static final Creator<SavedState> CREATOR = new ClassLoaderCreator<SavedState>() {
    ++            @Override
    ++            public SavedState createFromParcel(Parcel in, ClassLoader loader) {
    ++                return new SavedState(in, loader);
    ++            }
    ++
    +             @Override
    +             public SavedState createFromParcel(Parcel in) {
    +-                return new SavedState(in);
    ++                return new SavedState(in, null);
    +             }
    +             @Override
    +             public SavedState[] newArray(int size) {
    +@@ -1237,7 +1239,7 @@ public class ViewPager extends ViewGroup {
    +         };
    + 
    +         SavedState(Parcel in, ClassLoader loader) {
    +-            super(in);
    ++            super(in, loader);
    +             if (loader == null) {
    +                 loader = getClass().getClassLoader();
    +             }
     diff --git a/core/jni/android/graphics/BitmapFactory.cpp b/core/jni/android/graphics/BitmapFactory.cpp
     index 4001283..0a14361 100644
     --- a/core/jni/android/graphics/BitmapFactory.cpp
    @@ -42690,6 +42771,19 @@ index 1fe5cb7..0000000
     -        assertTrue(message, checker.getAsBoolean());
     -    }
     -}
    +diff --git a/telephony/java/com/android/internal/telephony/DcParamObject.java b/telephony/java/com/android/internal/telephony/DcParamObject.java
    +index 139939c..fc6b610 100644
    +--- a/telephony/java/com/android/internal/telephony/DcParamObject.java
    ++++ b/telephony/java/com/android/internal/telephony/DcParamObject.java
    +@@ -36,7 +36,7 @@ public class DcParamObject implements Parcelable {
    +     }
    + 
    +     public void writeToParcel(Parcel dest, int flags) {
    +-        dest.writeLong(mSubId);
    ++        dest.writeInt(mSubId);
    +     }
    + 
    +     private void readFromParcel(Parcel in) {
     diff --git a/wifi/java/android/net/wifi/RttManager.java b/wifi/java/android/net/wifi/RttManager.java
     index 590ff1b..8c96774 100644
     --- a/wifi/java/android/net/wifi/RttManager.java
    diff --git a/frameworks_op_net_wifi.patch b/frameworks_op_net_wifi.patch
    index e69de29..ee4bdc8 100644
    --- a/frameworks_op_net_wifi.patch
    +++ b/frameworks_op_net_wifi.patch
    @@ -0,0 +1,48 @@
    +diff --git a/service/java/com/android/server/wifi/WifiStateMachine.java b/service/java/com/android/server/wifi/WifiStateMachine.java
    +index 89aabcf..7802b3d 100644
    +--- a/service/java/com/android/server/wifi/WifiStateMachine.java
    ++++ b/service/java/com/android/server/wifi/WifiStateMachine.java
    +@@ -2329,7 +2329,7 @@ public class WifiStateMachine extends StateMachine implements WifiNative.WifiRss
    + 
    +     @Override
    +     public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
    +-        if (args.length > 1 && WifiMetrics.PROTO_DUMP_ARG.equals(args[0])
    ++        if (args != null && args.length > 1 && WifiMetrics.PROTO_DUMP_ARG.equals(args[0])
    +                 && WifiMetrics.CLEAN_DUMP_ARG.equals(args[1])) {
    +             // Dump only wifi metrics serialized proto bytes (base64)
    +             updateWifiMetrics();
    +@@ -4340,6 +4340,12 @@ public class WifiStateMachine extends StateMachine implements WifiNative.WifiRss
    +             logStateAndMessage(message, this);
    +             switch (message.what) {
    +                 case CMD_START_SUPPLICANT:
    ++                   /* Stop a running supplicant after a runtime restart
    ++                    * Avoids issues with drivers that do not handle interface down
    ++                    * on a running supplicant properly.
    ++                    */
    ++                    mWifiMonitor.killSupplicant(mP2pSupported);
    ++
    +                     if (mWifiNative.loadDriver()) {
    +                         try {
    +                             mNwService.wifiFirmwareReload(mInterfaceName, "STA");
    +@@ -4372,12 +4378,6 @@ public class WifiStateMachine extends StateMachine implements WifiNative.WifiRss
    +                             loge("Unable to change interface settings: " + ie);
    +                         }
    + 
    +-                       /* Stop a running supplicant after a runtime restart
    +-                        * Avoids issues with drivers that do not handle interface down
    +-                        * on a running supplicant properly.
    +-                        */
    +-                        mWifiMonitor.killSupplicant(mP2pSupported);
    +-
    +                         if (mWifiNative.startHal() == false) {
    +                             /* starting HAL is optional */
    +                             loge("Failed to start HAL");
    +@@ -5527,7 +5527,7 @@ public class WifiStateMachine extends StateMachine implements WifiNative.WifiRss
    +                     // If we have COMPLETED a connection to a BSSID, start doing
    +                     // DNAv4/DNAv6 -style probing for on-link neighbors of
    +                     // interest (e.g. routers); harmless if none are configured.
    +-                    if (state == SupplicantState.COMPLETED) {
    ++                    if (isRoaming() && state == SupplicantState.COMPLETED) {
    +                         mIpManager.confirmConfiguration();
    +                     }
    +                     break;
    diff --git a/system_sepolicy.patch b/system_sepolicy.patch
    index 346762d..623b327 100644
    --- a/system_sepolicy.patch
    +++ b/system_sepolicy.patch
    @@ -1,5 +1,5 @@
     diff --git a/Android.mk b/Android.mk
    -index 0bfa54d..a8b7ff7 100644
    +index 0bfa54d..886e081 100644
     --- a/Android.mk
     +++ b/Android.mk
     @@ -95,7 +95,10 @@ $(sepolicy_policy.conf): $(call build_policy, $(sepolicy_build_files))
    @@ -7,7 +7,7 @@ index 0bfa54d..a8b7ff7 100644
      		-D mls_num_sens=$(PRIVATE_MLS_SENS) -D mls_num_cats=$(PRIVATE_MLS_CATS) \
      		-D target_build_variant=$(TARGET_BUILD_VARIANT) \
     +		-D target_has_legacy_camera_hal1=$(TARGET_HAS_LEGACY_CAMERA_HAL1) \
    -+		-D target_needs_platform_text_relocations=$(TARGET_NEEDS_PLATFORM_TEXTRELS) \
    ++		-D target_needs_platform_text_relocations=$(TARGET_NEEDS_PLATFORM_TEXT_RELOCATIONS) \
      		-s $^ > $@
     +
      	$(hide) sed '/dontaudit/d' $@ > $@.dontaudit
    @@ -17,7 +17,7 @@ index 0bfa54d..a8b7ff7 100644
      		-D mls_num_sens=$(PRIVATE_MLS_SENS) -D mls_num_cats=$(PRIVATE_MLS_CATS) \
      		-D target_build_variant=$(TARGET_BUILD_VARIANT) \
      		-D target_recovery=true \
    -+		-D target_needs_platform_text_relocations=$(TARGET_NEEDS_PLATFORM_TEXTRELS) \
    ++		-D target_needs_platform_text_relocations=$(TARGET_NEEDS_PLATFORM_TEXT_RELOCATIONS) \
      		-s $^ > $@
      
      $(LOCAL_BUILT_MODULE): $(sepolicy_policy_recovery.conf) $(HOST_OUT_EXECUTABLES)/checkpolicy $(HOST_OUT_EXECUTABLES)/sepolicy-analyze
    @@ -34,6 +34,16 @@ index e9dd7b3..ef2bd9d 100644
      neverallow { appdomain -bluetooth } self:capability2 *;
      
      # Block device access.
    +diff --git a/attributes b/attributes
    +index a846c34..e8fe3ae 100644
    +--- a/attributes
    ++++ b/attributes
    +@@ -113,3 +113,5 @@ attribute boot_control_hal;
    + # postinstall. This includes the background daemon and the sideload tool from
    + # recovery for A/B devices.
    + attribute update_engine_common;
    ++
    ++attribute tracefs_type;
     diff --git a/domain.te b/domain.te
     index 45569de..5013ad3 100644
     --- a/domain.te
    
    From 13466671997be3edebc58c989fcc2b785cc919c5 Mon Sep 17 00:00:00 2001
    From: AndDiSa <anddisa@googlemail.com>
    Date: Fri, 8 Jun 2018 17:14:26 +0200
    Subject: [PATCH 095/159] update patches
    
    Change-Id: Ied3a8e9075c1f13341e32db673d7e93931b41935
    ---
     build.patch             |   4 +-
     external_libmpeg2.patch |  18 ++-
     external_sonivox.patch  |  34 ++++
     frameworks_av.patch     |  12 ++
     frameworks_base.patch   |  67 +++++++-
     frameworks_native.patch | 186 ++++-----------------
     system_bt.patch         | 350 +++++++++++++++++++++++++++++++++++++++-
     7 files changed, 500 insertions(+), 171 deletions(-)
    
    diff --git a/build.patch b/build.patch
    index d33eee3..f578613 100644
    --- a/build.patch
    +++ b/build.patch
    @@ -323,7 +323,7 @@ index 0000000..80664fa
     +ALL_PREBUILT += $(INSTALLED_KERNEL_TARGET)
     +endif
     diff --git a/core/version_defaults.mk b/core/version_defaults.mk
    -index 7c96344..14048ef 100644
    +index 7c96344..b6b44e1 100644
     --- a/core/version_defaults.mk
     +++ b/core/version_defaults.mk
     @@ -131,7 +131,7 @@ ifeq "" "$(PLATFORM_SECURITY_PATCH)"
    @@ -331,7 +331,7 @@ index 7c96344..14048ef 100644
          #  It must match one of the Android Security Patch Level strings of the Public Security Bulletins.
          #  If there is no $PLATFORM_SECURITY_PATCH set, keep it empty.
     -    PLATFORM_SECURITY_PATCH := 2017-08-05
    -+    PLATFORM_SECURITY_PATCH := 2018-05-05
    ++    PLATFORM_SECURITY_PATCH := 2018-06-05
      endif
      
      ifeq "" "$(PLATFORM_BASE_OS)"
    diff --git a/external_libmpeg2.patch b/external_libmpeg2.patch
    index eb419b3..eb254a1 100644
    --- a/external_libmpeg2.patch
    +++ b/external_libmpeg2.patch
    @@ -566,7 +566,7 @@ index 79c5ef6..229579c 100644
                  pu1_out += u4_out_wid;
              }
     diff --git a/decoder/impeg2d_pnb_pic.c b/decoder/impeg2d_pnb_pic.c
    -index 5540044..a3ae436 100644
    +index 5540044..f7937a8 100644
     --- a/decoder/impeg2d_pnb_pic.c
     +++ b/decoder/impeg2d_pnb_pic.c
     @@ -77,6 +77,12 @@ WORD32  impeg2d_dec_p_mb_params(dec_state_t *ps_dec)
    @@ -616,7 +616,19 @@ index 5540044..a3ae436 100644
      
          }
          u4_next_word = (UWORD16)impeg2d_bit_stream_nxt(ps_stream,16);
    -@@ -280,6 +313,8 @@ WORD32 impeg2d_dec_pnb_mb_params(dec_state_t *ps_dec)
    +@@ -266,6 +299,11 @@ WORD32 impeg2d_dec_pnb_mb_params(dec_state_t *ps_dec)
    +     {
    +         u2_mb_addr_incr = impeg2d_get_mb_addr_incr(ps_stream);
    + 
    ++        if(0 == u2_mb_addr_incr)
    ++        {
    ++            return IV_FAIL;
    ++        }
    ++
    +         if(ps_dec->u2_first_mb)
    +         {
    +             /****************************************************************/
    +@@ -280,6 +318,8 @@ WORD32 impeg2d_dec_pnb_mb_params(dec_state_t *ps_dec)
                  ps_dec->u2_mb_x = u2_mb_addr_incr - 1;
                  /* For error resilience */
                  ps_dec->u2_mb_x = MIN(ps_dec->u2_mb_x, (ps_dec->u2_num_horiz_mb - 1));
    @@ -625,7 +637,7 @@ index 5540044..a3ae436 100644
      
                  /****************************************************************/
                  /* mb_addr_incr is forced to 1 because in this decoder it is used */
    -@@ -510,6 +545,12 @@ IMPEG2D_ERROR_CODES_T impeg2d_dec_p_b_slice(dec_state_t *ps_dec)
    +@@ -510,6 +550,12 @@ IMPEG2D_ERROR_CODES_T impeg2d_dec_p_b_slice(dec_state_t *ps_dec)
      
              if(ret)
                  return IMPEG2D_MB_TEX_DECODE_ERR;
    diff --git a/external_sonivox.patch b/external_sonivox.patch
    index 53ad015..2da5e2b 100644
    --- a/external_sonivox.patch
    +++ b/external_sonivox.patch
    @@ -42,6 +42,40 @@ index 8097ba4..3ec24a0 100644
                  return EAS_ERROR_MALLOC_FAILED;
              }
              EAS_HWMemSet(dls.pDLS, 0, size);
    +diff --git a/arm-wt-22k/lib_src/eas_smf.c b/arm-wt-22k/lib_src/eas_smf.c
    +index 8b54b8e..3c284eb 100644
    +--- a/arm-wt-22k/lib_src/eas_smf.c
    ++++ b/arm-wt-22k/lib_src/eas_smf.c
    +@@ -29,6 +29,8 @@
    +  *----------------------------------------------------------------------------
    + */
    + 
    ++#include "log/log.h"
    ++
    + #include "eas_data.h"
    + #include "eas_miditypes.h"
    + #include "eas_parser.h"
    +@@ -833,6 +835,20 @@ static EAS_RESULT SMF_ParseMetaEvent (S_EAS_DATA *pEASData, S_SMF_DATA *pSMFData
    +     /* get the current file position so we can skip the event */
    +     if ((result = EAS_HWFilePos(pEASData->hwInstData, pSMFStream->fileHandle, &pos)) != EAS_SUCCESS)
    +         return result;
    ++
    ++    /* prevent a large unsigned length from being treated as a negative length */
    ++    if ((EAS_I32) len < 0) {
    ++        /* note that EAS_I32 is a long, which can be 64-bits on some computers */
    ++        ALOGE("b/68953854 SMF_ParseMetaEvent, negative len = %ld\n", (EAS_I32) len);
    ++        return EAS_ERROR_FILE_FORMAT;
    ++    }
    ++    /* prevent numeric overflow caused by a very large len, assume pos > 0 */
    ++    const EAS_I32 EAS_I32_MAX = 0x7FFFFFFF;
    ++    if ((EAS_I32) len > (EAS_I32_MAX - pos)) {
    ++        ALOGE("b/68953854 SMF_ParseMetaEvent, too large len = %ld\n", (EAS_I32) len);
    ++        return EAS_ERROR_FILE_FORMAT;
    ++    }
    ++
    +     pos += (EAS_I32) len;
    + 
    +     /* end of track? */
     diff --git a/arm-wt-22k/lib_src/eas_wtsynth.c b/arm-wt-22k/lib_src/eas_wtsynth.c
     index 9fcda7b..8488fe2 100644
     --- a/arm-wt-22k/lib_src/eas_wtsynth.c
    diff --git a/frameworks_av.patch b/frameworks_av.patch
    index 647ae82..dae7688 100644
    --- a/frameworks_av.patch
    +++ b/frameworks_av.patch
    @@ -4721,6 +4721,18 @@ index f18b88d..a3f3ea5 100644
              mAudioTrackServerProxy = new StaticAudioTrackServerProxy(mCblk, mBuffer, frameCount,
                      mFrameSize);
          }
    +diff --git a/services/audiopolicy/common/managerdefinitions/src/AudioPort.cpp b/services/audiopolicy/common/managerdefinitions/src/AudioPort.cpp
    +index 17ed537..ce9bdc2 100644
    +--- a/services/audiopolicy/common/managerdefinitions/src/AudioPort.cpp
    ++++ b/services/audiopolicy/common/managerdefinitions/src/AudioPort.cpp
    +@@ -384,6 +384,7 @@ AudioPortConfig::AudioPortConfig()
    +     mSamplingRate = 0;
    +     mChannelMask = AUDIO_CHANNEL_NONE;
    +     mFormat = AUDIO_FORMAT_INVALID;
    ++    memset(&mGain, 0, sizeof(struct audio_gain_config));
    +     mGain.index = -1;
    + }
    + 
     diff --git a/services/audiopolicy/common/managerdefinitions/src/Serializer.cpp b/services/audiopolicy/common/managerdefinitions/src/Serializer.cpp
     index 3e5bb7d..2ecd6b1 100644
     --- a/services/audiopolicy/common/managerdefinitions/src/Serializer.cpp
    diff --git a/frameworks_base.patch b/frameworks_base.patch
    index 9a23344..f1f2388 100644
    --- a/frameworks_base.patch
    +++ b/frameworks_base.patch
    @@ -479,10 +479,24 @@ index 5559d48..bee11db 100644
          return 0;
      }
     diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
    -index 011884c..a5035ee 100644
    +index 011884c..8403e80 100644
     --- a/core/res/AndroidManifest.xml
     +++ b/core/res/AndroidManifest.xml
    -@@ -2154,6 +2154,15 @@
    +@@ -1223,6 +1223,13 @@
    +     <permission android:name="android.permission.SCORE_NETWORKS"
    +         android:protectionLevel="signature|privileged" />
    + 
    ++    <!-- Allows network stack services (Connectivity and Wifi) to coordinate
    ++         <p>Not for use by third-party or privileged applications.
    ++         @hide This should only be used by Connectivity and Wifi Services.
    ++    -->
    ++    <permission android:name="android.permission.NETWORK_STACK"
    ++        android:protectionLevel="signature" />
    ++
    +     <!-- ======================================= -->
    +     <!-- Permissions for short range, peripheral networks -->
    +     <!-- ======================================= -->
    +@@ -2154,6 +2161,15 @@
          <permission android:name="android.permission.INTERNAL_SYSTEM_WINDOW"
              android:protectionLevel="signature" />
      
    @@ -572,6 +586,42 @@ index 6fa28b1..ea0347d 100644
          }
      
          @SmallTest
    +diff --git a/libs/androidfw/ResourceTypes.cpp b/libs/androidfw/ResourceTypes.cpp
    +index ceeb12b..803f635 100644
    +--- a/libs/androidfw/ResourceTypes.cpp
    ++++ b/libs/androidfw/ResourceTypes.cpp
    +@@ -457,6 +457,22 @@ status_t ResStringPool::setTo(const void* data, size_t size, bool copyData)
    + 
    +     uninit();
    + 
    ++    // The chunk must be at least the size of the string pool header.
    ++    if (size < sizeof(ResStringPool_header)) {
    ++        LOG_ALWAYS_FATAL("Bad string block: data size %zu is too small to be a string block", size);
    ++        return (mError=BAD_TYPE);
    ++    }
    ++
    ++    // The data is at least as big as a ResChunk_header, so we can safely validate the other
    ++    // header fields.
    ++    // `data + size` is safe because the source of `size` comes from the kernel/filesystem.
    ++    if (validate_chunk(reinterpret_cast<const ResChunk_header*>(data), sizeof(ResStringPool_header),
    ++                       reinterpret_cast<const uint8_t*>(data) + size,
    ++                       "ResStringPool_header") != NO_ERROR) {
    ++        LOG_ALWAYS_FATAL("Bad string block: malformed block dimensions");
    ++        return (mError=BAD_TYPE);
    ++    }
    ++
    +     const bool notDeviceEndian = htods(0xf0) != 0xf0;
    + 
    +     if (copyData || notDeviceEndian) {
    +@@ -468,6 +484,8 @@ status_t ResStringPool::setTo(const void* data, size_t size, bool copyData)
    +         data = mOwnedData;
    +     }
    + 
    ++    // The size has been checked, so it is safe to read the data in the ResStringPool_header
    ++    // data structure.
    +     mHeader = (const ResStringPool_header*)data;
    + 
    +     if (notDeviceEndian) {
     diff --git a/libs/hwui/Android.mk b/libs/hwui/Android.mk
     index cacfce1..0b177b9 100644
     --- a/libs/hwui/Android.mk
    @@ -1117,6 +1167,19 @@ index 2693272..f2368ed 100644
                      // next check if it's better than any current network we're using for
                      // this request
                      if (VDBG) {
    +diff --git a/services/core/java/com/android/server/NetworkManagementService.java b/services/core/java/com/android/server/NetworkManagementService.java
    +index bdbd066..aebe77a 100644
    +--- a/services/core/java/com/android/server/NetworkManagementService.java
    ++++ b/services/core/java/com/android/server/NetworkManagementService.java
    +@@ -1864,6 +1864,8 @@ public class NetworkManagementService extends INetworkManagementService.Stub
    +     @Override
    +     public void setAllowOnlyVpnForUids(boolean add, UidRange[] uidRanges)
    +             throws ServiceSpecificException {
    ++        mContext.enforceCallingOrSelfPermission(android.Manifest.permission.NETWORK_STACK, TAG);
    ++
    +         try {
    +             mNetdService.networkRejectNonSecureVpn(add, uidRanges);
    +         } catch (ServiceSpecificException e) {
     diff --git a/services/core/java/com/android/server/accounts/AccountManagerService.java b/services/core/java/com/android/server/accounts/AccountManagerService.java
     index a7a79cd..a085b71 100644
     --- a/services/core/java/com/android/server/accounts/AccountManagerService.java
    diff --git a/frameworks_native.patch b/frameworks_native.patch
    index 8bd2209..a5e2a4b 100644
    --- a/frameworks_native.patch
    +++ b/frameworks_native.patch
    @@ -859,20 +859,10 @@ index ee152bf..9c82295 100644
          result.mStorage.clear();
          for (size_t r = 0; r < numRects; ++r) {
     diff --git a/opengl/libs/Android.mk b/opengl/libs/Android.mk
    -index 24e4c19..afbfb66 100644
    +index 24e4c19..ffd0dbc 100644
     --- a/opengl/libs/Android.mk
     +++ b/opengl/libs/Android.mk
    -@@ -45,6 +45,9 @@ LOCAL_CFLAGS += -fvisibility=hidden
    - ifeq ($(BOARD_ALLOW_EGL_HIBERNATION),true)
    -   LOCAL_CFLAGS += -DBOARD_ALLOW_EGL_HIBERNATION
    - endif
    -+ifeq ($(BOARD_EGL_WORKAROUND_BUG_10194508),true)
    -+  LOCAL_CFLAGS += -DWORKAROUND_BUG_10194508
    -+endif
    - ifneq ($(MAX_EGL_CACHE_ENTRY_SIZE),)
    -   LOCAL_CFLAGS += -DMAX_EGL_CACHE_ENTRY_SIZE=$(MAX_EGL_CACHE_ENTRY_SIZE)
    - endif
    -@@ -77,7 +80,6 @@ LOCAL_SRC_FILES:= 		\
    +@@ -77,7 +77,6 @@ LOCAL_SRC_FILES:= 		\
      	GLES_CM/gl.cpp.arm 	\
      #
      
    @@ -880,7 +870,7 @@ index 24e4c19..afbfb66 100644
      LOCAL_SHARED_LIBRARIES += libcutils liblog libEGL
      LOCAL_MODULE:= libGLESv1_CM
      
    -@@ -105,7 +107,6 @@ LOCAL_SRC_FILES:= \
    +@@ -105,7 +104,6 @@ LOCAL_SRC_FILES:= \
      	GLES2/gl2.cpp   \
      #
      
    @@ -888,7 +878,7 @@ index 24e4c19..afbfb66 100644
      LOCAL_ARM_MODE := arm
      LOCAL_SHARED_LIBRARIES += libcutils libutils liblog libEGL
      LOCAL_MODULE:= libGLESv2
    -@@ -133,7 +134,6 @@ LOCAL_SRC_FILES:= \
    +@@ -133,7 +131,6 @@ LOCAL_SRC_FILES:= \
      	GLES2/gl2.cpp   \
      #
      
    @@ -1585,46 +1575,6 @@ index b1b31f8..8bde4e5 100644
      #undef CALL_GL_API_RETURN
      
      /*
    -diff --git a/services/inputflinger/InputManager.cpp b/services/inputflinger/InputManager.cpp
    -index 6a6547b..2ef25f3 100644
    ---- a/services/inputflinger/InputManager.cpp
    -+++ b/services/inputflinger/InputManager.cpp
    -@@ -20,6 +20,7 @@
    - 
    - #include "InputManager.h"
    - 
    -+#include <cutils/iosched_policy.h>
    - #include <cutils/log.h>
    - 
    - namespace android {
    -@@ -51,13 +52,15 @@ void InputManager::initialize() {
    - }
    - 
    - status_t InputManager::start() {
    --    status_t result = mDispatcherThread->run("InputDispatcher", PRIORITY_URGENT_DISPLAY);
    -+    status_t result = mDispatcherThread->run("InputDispatcher",
    -+            PRIORITY_URGENT_DISPLAY + PRIORITY_MORE_FAVORABLE);
    -     if (result) {
    -         ALOGE("Could not start InputDispatcher thread due to error %d.", result);
    -         return result;
    -     }
    - 
    --    result = mReaderThread->run("InputReader", PRIORITY_URGENT_DISPLAY);
    -+    result = mReaderThread->run("InputReader",
    -+            PRIORITY_URGENT_DISPLAY + PRIORITY_MORE_FAVORABLE);
    -     if (result) {
    -         ALOGE("Could not start InputReader thread due to error %d.", result);
    - 
    -@@ -65,6 +68,9 @@ status_t InputManager::start() {
    -         return result;
    -     }
    - 
    -+    android_set_rt_ioprio(mDispatcherThread->getTid(), 1);
    -+    android_set_rt_ioprio(mReaderThread->getTid(), 1);
    -+
    -     return OK;
    - }
    - 
     diff --git a/services/inputflinger/InputReader.cpp b/services/inputflinger/InputReader.cpp
     index b9be675..eff3deb 100644
     --- a/services/inputflinger/InputReader.cpp
    @@ -1844,26 +1794,6 @@ index ffda035..3f96b35 100644
      endif
      
      ifneq ($(PRESENT_TIME_OFFSET_FROM_VSYNC_NS),)
    -diff --git a/services/surfaceflinger/DispSync.cpp b/services/surfaceflinger/DispSync.cpp
    -index 1a9820d..b45e00a 100644
    ---- a/services/surfaceflinger/DispSync.cpp
    -+++ b/services/surfaceflinger/DispSync.cpp
    -@@ -22,6 +22,7 @@
    - 
    - #include <math.h>
    - 
    -+#include <cutils/iosched_policy.h>
    - #include <cutils/log.h>
    - 
    - #include <ui/Fence.h>
    -@@ -390,6 +391,7 @@ DispSync::DispSync(const char* name) :
    -         ALOGE("Couldn't set SCHED_FIFO for DispSyncThread");
    -     }
    - 
    -+    android_set_rt_ioprio(mThread->getTid(), 1);
    - 
    -     reset();
    -     beginResync();
     diff --git a/services/surfaceflinger/DisplayDevice.cpp b/services/surfaceflinger/DisplayDevice.cpp
     index 5c2c0ad..1f2e554 100644
     --- a/services/surfaceflinger/DisplayDevice.cpp
    @@ -1922,26 +1852,6 @@ index 2190466..8c36d85 100644
          status_t result = mSource[source]->dequeueBuffer(sslot, fence,
                  mSinkBufferWidth, mSinkBufferHeight, format, usage);
          if (result < 0)
    -diff --git a/services/surfaceflinger/EventThread.cpp b/services/surfaceflinger/EventThread.cpp
    -index dd88adb..2dacd87 100644
    ---- a/services/surfaceflinger/EventThread.cpp
    -+++ b/services/surfaceflinger/EventThread.cpp
    -@@ -20,6 +20,7 @@
    - #include <sys/types.h>
    - 
    - #include <cutils/compiler.h>
    -+#include <cutils/iosched_policy.h>
    - 
    - #include <gui/BitTube.h>
    - #include <gui/IDisplayEventConnection.h>
    -@@ -92,6 +93,7 @@ void EventThread::sendVsyncHintOnLocked() {
    - 
    - void EventThread::onFirstRef() {
    -     run("EventThread", PRIORITY_URGENT_DISPLAY + PRIORITY_MORE_FAVORABLE);
    -+    android_set_rt_ioprio(getTid(), 1);
    - }
    - 
    - sp<EventThread::Connection> EventThread::createEventConnection() const {
     diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
     index 3ffa655..f8de24d 100644
     --- a/services/surfaceflinger/Layer.cpp
    @@ -2172,18 +2082,10 @@ index 7c3f9b5..b268119 100644
      public:
          GLES20RenderEngine();
     diff --git a/services/surfaceflinger/RenderEngine/RenderEngine.cpp b/services/surfaceflinger/RenderEngine/RenderEngine.cpp
    -index d6a032f..28b3319 100644
    +index d6a032f..d0df8ab 100644
     --- a/services/surfaceflinger/RenderEngine/RenderEngine.cpp
     +++ b/services/surfaceflinger/RenderEngine/RenderEngine.cpp
    -@@ -83,7 +83,6 @@ RenderEngine* RenderEngine::create(EGLDisplay display, int hwcFormat) {
    -             EGL_CONTEXT_CLIENT_VERSION, contextClientVersion,      // MUST be first
    - #ifdef EGL_IMG_context_priority
    - #ifdef HAS_CONTEXT_PRIORITY
    --#warning "using EGL_IMG_context_priority"
    -             EGL_CONTEXT_PRIORITY_LEVEL_IMG, EGL_CONTEXT_PRIORITY_HIGH_IMG,
    - #endif
    - #endif
    -@@ -262,9 +261,11 @@ void RenderEngine::dump(String8& result) {
    +@@ -262,9 +262,11 @@ void RenderEngine::dump(String8& result) {
      // ---------------------------------------------------------------------------
      
      RenderEngine::BindImageAsFramebuffer::BindImageAsFramebuffer(
    @@ -2197,7 +2099,7 @@ index d6a032f..28b3319 100644
      
          ALOGE_IF(mStatus != GL_FRAMEBUFFER_COMPLETE_OES,
                  "glCheckFramebufferStatusOES error %d", mStatus);
    -@@ -272,7 +273,7 @@ RenderEngine::BindImageAsFramebuffer::BindImageAsFramebuffer(
    +@@ -272,7 +274,7 @@ RenderEngine::BindImageAsFramebuffer::BindImageAsFramebuffer(
      
      RenderEngine::BindImageAsFramebuffer::~BindImageAsFramebuffer() {
          // back to main framebuffer
    @@ -2233,26 +2135,10 @@ index 0259881..5a5910a 100644
              int getStatus() const;
          };
     diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
    -index 8e7e577..f1104a0 100644
    +index 8e7e577..a04684c 100644
     --- a/services/surfaceflinger/SurfaceFlinger.cpp
     +++ b/services/surfaceflinger/SurfaceFlinger.cpp
    -@@ -27,6 +27,7 @@
    - 
    - #include <EGL/egl.h>
    - 
    -+#include <cutils/iosched_policy.h>
    - #include <cutils/log.h>
    - #include <cutils/properties.h>
    - 
    -@@ -501,6 +502,7 @@ void SurfaceFlinger::init() {
    - 
    -     mEventControlThread = new EventControlThread(this);
    -     mEventControlThread->run("EventControl", PRIORITY_URGENT_DISPLAY);
    -+    android_set_rt_ioprio(mEventControlThread->getTid(), 1);
    - 
    -     // initialize our drawing state
    -     mDrawingState = mCurrentState;
    -@@ -3437,7 +3439,8 @@ status_t SurfaceFlinger::captureScreen(const sp<IBinder>& display,
    +@@ -3437,7 +3437,8 @@ status_t SurfaceFlinger::captureScreen(const sp<IBinder>& display,
              const sp<IGraphicBufferProducer>& producer,
              Rect sourceCrop, uint32_t reqWidth, uint32_t reqHeight,
              uint32_t minLayerZ, uint32_t maxLayerZ,
    @@ -2262,7 +2148,7 @@ index 8e7e577..f1104a0 100644
      
          if (CC_UNLIKELY(display == 0))
              return BAD_VALUE;
    -@@ -3481,6 +3484,7 @@ status_t SurfaceFlinger::captureScreen(const sp<IBinder>& display,
    +@@ -3481,6 +3482,7 @@ status_t SurfaceFlinger::captureScreen(const sp<IBinder>& display,
              bool useIdentityTransform;
              Transform::orientation_flags rotation;
              status_t result;
    @@ -2270,7 +2156,7 @@ index 8e7e577..f1104a0 100644
              bool isLocalScreenshot;
          public:
              MessageCaptureScreen(SurfaceFlinger* flinger,
    -@@ -3490,12 +3494,13 @@ status_t SurfaceFlinger::captureScreen(const sp<IBinder>& display,
    +@@ -3490,12 +3492,13 @@ status_t SurfaceFlinger::captureScreen(const sp<IBinder>& display,
                      uint32_t minLayerZ, uint32_t maxLayerZ,
                      bool useIdentityTransform,
                      Transform::orientation_flags rotation,
    @@ -2285,7 +2171,7 @@ index 8e7e577..f1104a0 100644
                    isLocalScreenshot(isLocalScreenshot)
              {
              }
    -@@ -3505,9 +3510,10 @@ status_t SurfaceFlinger::captureScreen(const sp<IBinder>& display,
    +@@ -3505,9 +3508,10 @@ status_t SurfaceFlinger::captureScreen(const sp<IBinder>& display,
              virtual bool handler() {
                  Mutex::Autolock _l(flinger->mStateLock);
                  sp<const DisplayDevice> hw(flinger->getDisplayDevice(display));
    @@ -2297,7 +2183,7 @@ index 8e7e577..f1104a0 100644
                  static_cast<GraphicProducerWrapper*>(IInterface::asBinder(producer).get())->exit(result);
                  return true;
              }
    -@@ -3523,7 +3529,7 @@ status_t SurfaceFlinger::captureScreen(const sp<IBinder>& display,
    +@@ -3523,7 +3527,7 @@ status_t SurfaceFlinger::captureScreen(const sp<IBinder>& display,
          sp<MessageBase> msg = new MessageCaptureScreen(this,
                  display, IGraphicBufferProducer::asInterface( wrapper ),
                  sourceCrop, reqWidth, reqHeight, minLayerZ, maxLayerZ,
    @@ -2306,7 +2192,7 @@ index 8e7e577..f1104a0 100644
      
          status_t res = postMessageAsync(msg);
          if (res == NO_ERROR) {
    -@@ -3606,7 +3612,7 @@ status_t SurfaceFlinger::captureScreenImplLocked(
    +@@ -3606,7 +3610,7 @@ status_t SurfaceFlinger::captureScreenImplLocked(
              Rect sourceCrop, uint32_t reqWidth, uint32_t reqHeight,
              uint32_t minLayerZ, uint32_t maxLayerZ,
              bool useIdentityTransform, Transform::orientation_flags rotation,
    @@ -2315,7 +2201,7 @@ index 8e7e577..f1104a0 100644
      {
          ATRACE_CALL();
      
    -@@ -3684,7 +3690,7 @@ status_t SurfaceFlinger::captureScreenImplLocked(
    +@@ -3684,7 +3688,7 @@ status_t SurfaceFlinger::captureScreenImplLocked(
                      if (image != EGL_NO_IMAGE_KHR) {
                          // this binds the given EGLImage as a framebuffer for the
                          // duration of this scope.
    @@ -2324,7 +2210,7 @@ index 8e7e577..f1104a0 100644
                          if (imageBond.getStatus() == NO_ERROR) {
                              // this will in fact render into our dequeued buffer
                              // via an FBO, which means we didn't have to create
    -@@ -3731,6 +3737,16 @@ status_t SurfaceFlinger::captureScreenImplLocked(
    +@@ -3731,6 +3735,16 @@ status_t SurfaceFlinger::captureScreenImplLocked(
                                      ALOGW("captureScreen: error creating EGL fence: %#x", eglGetError());
                                  }
                              }
    @@ -2399,18 +2285,10 @@ index e0e4c61..6f2520b 100644
      #ifdef USE_HWC2
          err = updateAndReleaseLocked(item, &mPendingRelease);
     diff --git a/services/surfaceflinger/SurfaceFlinger_hwc1.cpp b/services/surfaceflinger/SurfaceFlinger_hwc1.cpp
    -index b32f652..c9ac4d7 100644
    +index b32f652..512f63d 100644
     --- a/services/surfaceflinger/SurfaceFlinger_hwc1.cpp
     +++ b/services/surfaceflinger/SurfaceFlinger_hwc1.cpp
    -@@ -26,6 +26,7 @@
    - 
    - #include <EGL/egl.h>
    - 
    -+#include <cutils/iosched_policy.h>
    - #include <cutils/log.h>
    - #include <cutils/properties.h>
    - 
    -@@ -457,19 +458,28 @@ void SurfaceFlinger::init() {
    +@@ -457,19 +457,28 @@ void SurfaceFlinger::init() {
          eglInitialize(mEGLDisplay, NULL, NULL);
      
          // start the EventThread
    @@ -2450,15 +2328,7 @@ index b32f652..c9ac4d7 100644
          }
      
      
    -@@ -526,6 +536,7 @@ void SurfaceFlinger::init() {
    - 
    -     mEventControlThread = new EventControlThread(this);
    -     mEventControlThread->run("EventControl", PRIORITY_URGENT_DISPLAY);
    -+    android_set_rt_ioprio(mEventControlThread->getTid(), 1);
    - 
    -     // set a fake vsync period if there is no HWComposer
    -     if (mHwc->initCheck() != NO_ERROR) {
    -@@ -635,10 +646,21 @@ status_t SurfaceFlinger::getDisplayConfigs(const sp<IBinder>& display,
    +@@ -635,10 +644,21 @@ status_t SurfaceFlinger::getDisplayConfigs(const sp<IBinder>& display,
                  info.orientation = 0;
              }
      
    @@ -2484,7 +2354,7 @@ index b32f652..c9ac4d7 100644
              info.fps = float(1e9 / hwConfig.refresh);
              info.appVsyncOffset = VSYNC_EVENT_PHASE_OFFSET_NS;
      
    -@@ -3186,12 +3208,14 @@ status_t SurfaceFlinger::onTransact(
    +@@ -3186,12 +3206,14 @@ status_t SurfaceFlinger::onTransact(
                  }
                  case 1018: { // Modify Choreographer's phase offset
                      n = data.readInt32();
    @@ -2501,7 +2371,7 @@ index b32f652..c9ac4d7 100644
                      return NO_ERROR;
                  }
                  case 1021: { // Disable HWC virtual displays
    -@@ -3330,7 +3354,8 @@ status_t SurfaceFlinger::captureScreen(const sp<IBinder>& display,
    +@@ -3330,7 +3352,8 @@ status_t SurfaceFlinger::captureScreen(const sp<IBinder>& display,
              const sp<IGraphicBufferProducer>& producer,
              Rect sourceCrop, uint32_t reqWidth, uint32_t reqHeight,
              uint32_t minLayerZ, uint32_t maxLayerZ,
    @@ -2511,7 +2381,7 @@ index b32f652..c9ac4d7 100644
      
          if (CC_UNLIKELY(display == 0))
              return BAD_VALUE;
    -@@ -3374,6 +3399,7 @@ status_t SurfaceFlinger::captureScreen(const sp<IBinder>& display,
    +@@ -3374,6 +3397,7 @@ status_t SurfaceFlinger::captureScreen(const sp<IBinder>& display,
              bool useIdentityTransform;
              Transform::orientation_flags rotation;
              status_t result;
    @@ -2519,7 +2389,7 @@ index b32f652..c9ac4d7 100644
              bool isLocalScreenshot;
          public:
              MessageCaptureScreen(SurfaceFlinger* flinger,
    -@@ -3383,12 +3409,13 @@ status_t SurfaceFlinger::captureScreen(const sp<IBinder>& display,
    +@@ -3383,12 +3407,13 @@ status_t SurfaceFlinger::captureScreen(const sp<IBinder>& display,
                      uint32_t minLayerZ, uint32_t maxLayerZ,
                      bool useIdentityTransform,
                      Transform::orientation_flags rotation,
    @@ -2534,7 +2404,7 @@ index b32f652..c9ac4d7 100644
                    isLocalScreenshot(isLocalScreenshot)
              {
              }
    -@@ -3398,9 +3425,10 @@ status_t SurfaceFlinger::captureScreen(const sp<IBinder>& display,
    +@@ -3398,9 +3423,10 @@ status_t SurfaceFlinger::captureScreen(const sp<IBinder>& display,
              virtual bool handler() {
                  Mutex::Autolock _l(flinger->mStateLock);
                  sp<const DisplayDevice> hw(flinger->getDisplayDevice(display));
    @@ -2546,7 +2416,7 @@ index b32f652..c9ac4d7 100644
                  static_cast<GraphicProducerWrapper*>(IInterface::asBinder(producer).get())->exit(result);
                  return true;
              }
    -@@ -3416,7 +3444,7 @@ status_t SurfaceFlinger::captureScreen(const sp<IBinder>& display,
    +@@ -3416,7 +3442,7 @@ status_t SurfaceFlinger::captureScreen(const sp<IBinder>& display,
          sp<MessageBase> msg = new MessageCaptureScreen(this,
                  display, IGraphicBufferProducer::asInterface( wrapper ),
                  sourceCrop, reqWidth, reqHeight, minLayerZ, maxLayerZ,
    @@ -2555,7 +2425,7 @@ index b32f652..c9ac4d7 100644
      
          status_t res = postMessageAsync(msg);
          if (res == NO_ERROR) {
    -@@ -3501,7 +3529,7 @@ status_t SurfaceFlinger::captureScreenImplLocked(
    +@@ -3501,7 +3527,7 @@ status_t SurfaceFlinger::captureScreenImplLocked(
              Rect sourceCrop, uint32_t reqWidth, uint32_t reqHeight,
              uint32_t minLayerZ, uint32_t maxLayerZ,
              bool useIdentityTransform, Transform::orientation_flags rotation,
    @@ -2564,7 +2434,7 @@ index b32f652..c9ac4d7 100644
      {
          ATRACE_CALL();
      
    -@@ -3571,7 +3599,7 @@ status_t SurfaceFlinger::captureScreenImplLocked(
    +@@ -3571,7 +3597,7 @@ status_t SurfaceFlinger::captureScreenImplLocked(
                      if (image != EGL_NO_IMAGE_KHR) {
                          // this binds the given EGLImage as a framebuffer for the
                          // duration of this scope.
    @@ -2573,7 +2443,7 @@ index b32f652..c9ac4d7 100644
                          if (imageBond.getStatus() == NO_ERROR) {
                              // this will in fact render into our dequeued buffer
                              // via an FBO, which means we didn't have to create
    -@@ -3618,6 +3646,16 @@ status_t SurfaceFlinger::captureScreenImplLocked(
    +@@ -3618,6 +3644,16 @@ status_t SurfaceFlinger::captureScreenImplLocked(
                                      ALOGW("captureScreen: error creating EGL fence: %#x", eglGetError());
                                  }
                              }
    diff --git a/system_bt.patch b/system_bt.patch
    index eb844f2..7173339 100644
    --- a/system_bt.patch
    +++ b/system_bt.patch
    @@ -154,6 +154,18 @@ index 69ded69..5f9e42c 100644
          dump_stat(fd, &stats->overdue_scheduling,
                    "    Overdue scheduling time in ms (total/max/avg)");
      
    +diff --git a/osi/src/config.c b/osi/src/config.c
    +index 345f907..0e8c421 100644
    +--- a/osi/src/config.c
    ++++ b/osi/src/config.c
    +@@ -34,6 +34,7 @@
    + #include "osi/include/allocator.h"
    + #include "osi/include/list.h"
    + #include "osi/include/log.h"
    ++#include "log/log.h"
    + 
    + typedef struct {
    +   char *key;
     diff --git a/stack/avdt/avdt_api.c b/stack/avdt/avdt_api.c
     index 98ef5f7..5201054 100644
     --- a/stack/avdt/avdt_api.c
    @@ -168,7 +180,7 @@ index 98ef5f7..5201054 100644
                  p_pkt->offset = L2CAP_MIN_OFFSET;
                  p = (UINT8 *)(p_pkt + 1) + p_pkt->offset;
     diff --git a/stack/avrc/avrc_pars_ct.c b/stack/avrc/avrc_pars_ct.c
    -index 63cc384..0e67dd5 100644
    +index 63cc384..bd96d6c 100644
     --- a/stack/avrc/avrc_pars_ct.c
     +++ b/stack/avrc/avrc_pars_ct.c
     @@ -22,6 +22,7 @@
    @@ -205,6 +217,51 @@ index 63cc384..0e67dd5 100644
              for (int xx = 0; xx < p_result->get_cur_app_val.num_val; xx++)
              {
                  BE_STREAM_TO_UINT8(app_sett[xx].attr_id, p);
    +@@ -269,7 +282,6 @@ static tAVRC_STS avrc_ctrl_pars_vendor_rsp(
    + 
    +     case AVRC_PDU_GET_PLAYER_APP_ATTR_TEXT:
    +     {
    +-        tAVRC_APP_SETTING_TEXT   *p_setting_text;
    +         UINT8                    num_attrs;
    + 
    +         if (len == 0)
    +@@ -278,9 +290,12 @@ static tAVRC_STS avrc_ctrl_pars_vendor_rsp(
    +             break;
    +         }
    +         BE_STREAM_TO_UINT8(num_attrs, p);
    ++        if (num_attrs > AVRC_MAX_APP_ATTR_SIZE) {
    ++            num_attrs = AVRC_MAX_APP_ATTR_SIZE;
    ++        }
    +         AVRC_TRACE_DEBUG("%s attr count = %d ", __func__, p_result->get_app_attr_txt.num_attr);
    +         p_result->get_app_attr_txt.num_attr = num_attrs;
    +-        p_setting_text = (tAVRC_APP_SETTING_TEXT*)osi_malloc(num_attrs * sizeof(tAVRC_APP_SETTING_TEXT));
    ++        p_result->get_app_attr_txt.p_attrs = (tAVRC_APP_SETTING_TEXT*)osi_malloc(num_attrs * sizeof(tAVRC_APP_SETTING_TEXT));
    +         for (int xx = 0; xx < num_attrs; xx++)
    +         {
    +             BE_STREAM_TO_UINT8(p_result->get_app_attr_txt.p_attrs[xx].attr_id, p);
    +@@ -300,7 +315,6 @@ static tAVRC_STS avrc_ctrl_pars_vendor_rsp(
    + 
    +     case AVRC_PDU_GET_PLAYER_APP_VALUE_TEXT:
    +     {
    +-        tAVRC_APP_SETTING_TEXT   *p_setting_text;
    +         UINT8                    num_vals;
    + 
    +         if (len == 0)
    +@@ -309,10 +323,13 @@ static tAVRC_STS avrc_ctrl_pars_vendor_rsp(
    +             break;
    +         }
    +         BE_STREAM_TO_UINT8(num_vals, p);
    ++        if (num_vals > AVRC_MAX_APP_ATTR_SIZE) {
    ++            num_vals = AVRC_MAX_APP_ATTR_SIZE;
    ++        }
    +         p_result->get_app_val_txt.num_attr = num_vals;
    +         AVRC_TRACE_DEBUG("%s value count = %d ", __func__, p_result->get_app_val_txt.num_attr);
    + 
    +-        p_setting_text = (tAVRC_APP_SETTING_TEXT *)osi_malloc(num_vals * sizeof(tAVRC_APP_SETTING_TEXT));
    ++        p_result->get_app_val_txt.p_attrs = (tAVRC_APP_SETTING_TEXT *)osi_malloc(num_vals * sizeof(tAVRC_APP_SETTING_TEXT));
    +         for (int i = 0; i < num_vals; i++) {
    +             BE_STREAM_TO_UINT8(p_result->get_app_val_txt.p_attrs[i].attr_id, p);
    +             BE_STREAM_TO_UINT16(p_result->get_app_val_txt.p_attrs[i].charset_id, p);
     diff --git a/stack/avrc/avrc_pars_tg.c b/stack/avrc/avrc_pars_tg.c
     index 3f3fe93..63f74b6 100644
     --- a/stack/avrc/avrc_pars_tg.c
    @@ -673,10 +730,77 @@ index c888817..7cbe2d3 100644
      /*******************************************************************************
      **
     diff --git a/stack/sdp/sdp_server.c b/stack/sdp/sdp_server.c
    -index 627f4cf..43ea76e 100644
    +index 627f4cf..ba9e8fd 100644
     --- a/stack/sdp/sdp_server.c
     +++ b/stack/sdp/sdp_server.c
    -@@ -230,7 +230,7 @@ static void process_service_search (tCONN_CB *p_ccb, UINT16 trans_num,
    +@@ -23,6 +23,7 @@
    +  *
    +  ******************************************************************************/
    + 
    ++#include <cutils/log.h>
    + #include <stdlib.h>
    + #include <string.h>
    + #include <stdio.h>
    +@@ -126,11 +127,25 @@ void sdp_server_handle_client_req (tCONN_CB *p_ccb, BT_HDR *p_msg)
    +     alarm_set_on_queue(p_ccb->sdp_conn_timer, SDP_INACT_TIMEOUT_MS,
    +                        sdp_conn_timer_timeout, p_ccb, btu_general_alarm_queue);
    + 
    ++    if (p_req + sizeof(pdu_id) + sizeof(trans_num) > p_req_end) {
    ++        android_errorWriteLog(0x534e4554, "69384124");
    ++        trans_num = 0;
    ++        sdpu_build_n_send_error(p_ccb, trans_num, SDP_INVALID_REQ_SYNTAX,
    ++                                SDP_TEXT_BAD_HEADER);
    ++    }
    ++
    +     /* The first byte in the message is the pdu type */
    +     pdu_id = *p_req++;
    + 
    +     /* Extract the transaction number and parameter length */
    +     BE_STREAM_TO_UINT16 (trans_num, p_req);
    ++
    ++    if (p_req + sizeof(param_len) > p_req_end) {
    ++        android_errorWriteLog(0x534e4554, "69384124");
    ++        sdpu_build_n_send_error(p_ccb, trans_num, SDP_INVALID_REQ_SYNTAX,
    ++                                SDP_TEXT_BAD_HEADER);
    ++    }
    ++
    +     BE_STREAM_TO_UINT16 (param_len, p_req);
    + 
    +     if ((p_req + param_len) != p_req_end)
    +@@ -195,17 +210,14 @@ static void process_service_search (tCONN_CB *p_ccb, UINT16 trans_num,
    +     }
    + 
    +     /* Get the max replies we can send. Cap it at our max anyways. */
    +-    BE_STREAM_TO_UINT16 (max_replies, p_req);
    +-
    +-    if (max_replies > SDP_MAX_RECORDS)
    +-        max_replies = SDP_MAX_RECORDS;
    +-
    +-
    +-    if ((!p_req) || (p_req > p_req_end))
    +-    {
    ++    if (p_req + sizeof(max_replies) + sizeof(uint8_t) > p_req_end) {
    ++        android_errorWriteLog(0x534e4554, "69384124");
    +         sdpu_build_n_send_error (p_ccb, trans_num, SDP_INVALID_REQ_SYNTAX, SDP_TEXT_BAD_MAX_RECORDS_LIST);
    +         return;
    +     }
    ++    BE_STREAM_TO_UINT16(max_replies, p_req);
    ++
    ++    if (max_replies > SDP_MAX_RECORDS) max_replies = SDP_MAX_RECORDS;
    + 
    + 
    +     /* Get a list of handles that match the UUIDs given to us */
    +@@ -222,15 +234,15 @@ static void process_service_search (tCONN_CB *p_ccb, UINT16 trans_num,
    +     /* Check if this is a continuation request */
    +     if (*p_req)
    +     {
    +-        if (*p_req++ != SDP_CONTINUATION_LEN || (p_req >= p_req_end))
    +-        {
    ++        if (*p_req++ != SDP_CONTINUATION_LEN ||
    ++            (p_req + sizeof(cont_offset) > p_req_end)) {
    +             sdpu_build_n_send_error (p_ccb, trans_num, SDP_INVALID_CONT_STATE,
    +                                      SDP_TEXT_BAD_CONT_LEN);
    +             return;
              }
              BE_STREAM_TO_UINT16 (cont_offset, p_req);
      
    @@ -685,7 +809,39 @@ index 627f4cf..43ea76e 100644
              {
                  sdpu_build_n_send_error (p_ccb, trans_num, SDP_INVALID_CONT_STATE,
                                           SDP_TEXT_BAD_CONT_INX);
    -@@ -360,6 +360,11 @@ static void process_service_attr_req (tCONN_CB *p_ccb, UINT16 trans_num,
    +@@ -327,15 +339,15 @@ static void process_service_attr_req (tCONN_CB *p_ccb, UINT16 trans_num,
    +     BOOLEAN         is_cont = FALSE;
    +     UINT16          attr_len;
    + 
    +-    /* Extract the record handle */
    +-    BE_STREAM_TO_UINT32 (rec_handle, p_req);
    +-
    +-    if (p_req > p_req_end)
    +-    {
    ++    if (p_req + sizeof(rec_handle) + sizeof(max_list_len) > p_req_end) {
    ++        android_errorWriteLog(0x534e4554, "69384124");
    +         sdpu_build_n_send_error (p_ccb, trans_num, SDP_INVALID_SERV_REC_HDL, SDP_TEXT_BAD_HANDLE);
    +         return;
    +     }
    + 
    ++    /* Extract the record handle */
    ++    BE_STREAM_TO_UINT32(rec_handle, p_req);
    ++
    +     /* Get the max list length we can send. Cap it at MTU size minus overhead */
    +     BE_STREAM_TO_UINT16 (max_list_len, p_req);
    + 
    +@@ -344,8 +356,8 @@ static void process_service_attr_req (tCONN_CB *p_ccb, UINT16 trans_num,
    + 
    +     p_req = sdpu_extract_attr_seq (p_req, param_len, &attr_seq);
    + 
    +-    if ((!p_req) || (!attr_seq.num_attr) || (p_req > p_req_end))
    +-    {
    ++    if ((!p_req) || (!attr_seq.num_attr) ||
    ++        (p_req + sizeof(uint8_t) > p_req_end)) {
    +         sdpu_build_n_send_error (p_ccb, trans_num, SDP_INVALID_REQ_SYNTAX, SDP_TEXT_BAD_ATTR_LIST);
    +         return;
    +     }
    +@@ -360,13 +372,19 @@ static void process_service_attr_req (tCONN_CB *p_ccb, UINT16 trans_num,
              return;
          }
      
    @@ -697,7 +853,37 @@ index 627f4cf..43ea76e 100644
          /* Free and reallocate buffer */
          osi_free(p_ccb->rsp_list);
          p_ccb->rsp_list = (UINT8 *)osi_malloc(max_list_len);
    -@@ -584,6 +589,11 @@ static void process_service_search_attr_req (tCONN_CB *p_ccb, UINT16 trans_num,
    + 
    +     /* Check if this is a continuation request */
    +     if (*p_req) {
    +-        if (*p_req++ != SDP_CONTINUATION_LEN) {
    ++        if (*p_req++ != SDP_CONTINUATION_LEN ||
    ++            (p_req + sizeof(cont_offset) > p_req_end)) {
    +             sdpu_build_n_send_error(p_ccb, trans_num, SDP_INVALID_CONT_STATE,
    +                                     SDP_TEXT_BAD_CONT_LEN);
    +             return;
    +@@ -562,8 +580,8 @@ static void process_service_search_attr_req (tCONN_CB *p_ccb, UINT16 trans_num,
    +     /* Extract the UUID sequence to search for */
    +     p_req = sdpu_extract_uid_seq (p_req, param_len, &uid_seq);
    + 
    +-    if ((!p_req) || (!uid_seq.num_uids))
    +-    {
    ++    if ((!p_req) || (!uid_seq.num_uids) ||
    ++        (p_req + sizeof(uint16_t) > p_req_end)) {
    +         sdpu_build_n_send_error (p_ccb, trans_num, SDP_INVALID_REQ_SYNTAX, SDP_TEXT_BAD_UUID_LIST);
    +         return;
    +     }
    +@@ -576,21 +594,27 @@ static void process_service_search_attr_req (tCONN_CB *p_ccb, UINT16 trans_num,
    + 
    +     p_req = sdpu_extract_attr_seq (p_req, param_len, &attr_seq);
    + 
    +-    if ((!p_req) || (!attr_seq.num_attr))
    +-    {
    ++    if ((!p_req) || (!attr_seq.num_attr) ||
    ++        (p_req + sizeof(uint8_t) > p_req_end)) {
    +         sdpu_build_n_send_error (p_ccb, trans_num, SDP_INVALID_REQ_SYNTAX, SDP_TEXT_BAD_ATTR_LIST);
    +         return;
    +     }
      
          memcpy(&attr_seq_sav, &attr_seq, sizeof(tSDP_ATTR_SEQ)) ;
      
    @@ -709,8 +895,17 @@ index 627f4cf..43ea76e 100644
          /* Free and reallocate buffer */
          osi_free(p_ccb->rsp_list);
          p_ccb->rsp_list = (UINT8 *)osi_malloc(max_list_len);
    + 
    +     /* Check if this is a continuation request */
    +     if (*p_req) {
    +-        if (*p_req++ != SDP_CONTINUATION_LEN) {
    ++        if (*p_req++ != SDP_CONTINUATION_LEN ||
    ++            (p_req + sizeof(uint16_t) > p_req_end)) {
    +             sdpu_build_n_send_error(p_ccb, trans_num, SDP_INVALID_CONT_STATE,
    +                                     SDP_TEXT_BAD_CONT_LEN);
    +             return;
     diff --git a/stack/sdp/sdp_utils.c b/stack/sdp/sdp_utils.c
    -index a6f0ba6..aa1bfb5 100644
    +index a6f0ba6..6b503cb 100644
     --- a/stack/sdp/sdp_utils.c
     +++ b/stack/sdp/sdp_utils.c
     @@ -120,8 +120,9 @@ tCONN_CB *sdpu_allocate_ccb (void)
    @@ -734,6 +929,149 @@ index a6f0ba6..aa1bfb5 100644
      
          /* Drop any response pointer we may be holding */
          p_ccb->con_state = SDP_STATE_IDLE;
    +@@ -369,6 +369,8 @@ UINT8 *sdpu_extract_uid_seq (UINT8 *p, UINT16 param_len, tSDP_UUID_SEQ *p_seq)
    +     p_seq->num_uids = 0;
    + 
    +     /* A UID sequence is composed of a bunch of UIDs. */
    ++    if (sizeof(descr) > param_len) return (NULL);
    ++    param_len -= sizeof(descr);
    + 
    +     BE_STREAM_TO_UINT8 (descr, p);
    +     type = descr >> 3;
    +@@ -389,19 +391,25 @@ UINT8 *sdpu_extract_uid_seq (UINT8 *p, UINT16 param_len, tSDP_UUID_SEQ *p_seq)
    +         seq_len = 16;
    +         break;
    +     case SIZE_IN_NEXT_BYTE:
    ++        if (sizeof(uint8_t) > param_len) return (NULL);
    ++        param_len -= sizeof(uint8_t);
    +         BE_STREAM_TO_UINT8 (seq_len, p);
    +         break;
    +     case SIZE_IN_NEXT_WORD:
    ++        if (sizeof(uint16_t) > param_len) return (NULL);
    ++        param_len -= sizeof(uint16_t);
    +         BE_STREAM_TO_UINT16 (seq_len, p);
    +         break;
    +     case SIZE_IN_NEXT_LONG:
    ++        if (sizeof(uint32_t) > param_len) return (NULL);
    ++        param_len -= sizeof(uint32_t);
    +         BE_STREAM_TO_UINT32 (seq_len, p);
    +         break;
    +     default:
    +         return (NULL);
    +     }
    + 
    +-    if (seq_len >= param_len)
    ++    if (seq_len > param_len)
    +         return (NULL);
    + 
    +     p_seq_end = p + seq_len;
    +@@ -428,12 +436,15 @@ UINT8 *sdpu_extract_uid_seq (UINT8 *p, UINT16 param_len, tSDP_UUID_SEQ *p_seq)
    +             uuid_len = 16;
    +             break;
    +         case SIZE_IN_NEXT_BYTE:
    ++            if (p + sizeof(uint8_t) > p_seq_end) return NULL;
    +             BE_STREAM_TO_UINT8 (uuid_len, p);
    +             break;
    +         case SIZE_IN_NEXT_WORD:
    ++            if (p + sizeof(uint16_t) > p_seq_end) return NULL;
    +             BE_STREAM_TO_UINT16 (uuid_len, p);
    +             break;
    +         case SIZE_IN_NEXT_LONG:
    ++            if (p + sizeof(uint32_t) > p_seq_end) return NULL;
    +             BE_STREAM_TO_UINT32 (uuid_len, p);
    +             break;
    +         default:
    +@@ -441,8 +452,8 @@ UINT8 *sdpu_extract_uid_seq (UINT8 *p, UINT16 param_len, tSDP_UUID_SEQ *p_seq)
    +         }
    + 
    +         /* If UUID length is valid, copy it across */
    +-        if ((uuid_len == 2) || (uuid_len == 4) || (uuid_len == 16))
    +-        {
    ++        if (((uuid_len == 2) || (uuid_len == 4) || (uuid_len == 16)) &&
    ++            (p + uuid_len <= p_seq_end)) {
    +             p_seq->uuid_entry[p_seq->num_uids].len = (UINT16) uuid_len;
    +             BE_STREAM_TO_ARRAY (p, p_seq->uuid_entry[p_seq->num_uids].value, (int)uuid_len);
    +             p_seq->num_uids++;
    +@@ -483,33 +494,41 @@ UINT8 *sdpu_extract_attr_seq (UINT8 *p, UINT16 param_len, tSDP_ATTR_SEQ *p_seq)
    +     p_seq->num_attr = 0;
    + 
    +     /* Get attribute sequence info */
    ++    if (param_len < sizeof(descr)) return NULL;
    ++    param_len -= sizeof(descr);
    +     BE_STREAM_TO_UINT8 (descr, p);
    +     type = descr >> 3;
    +     size = descr & 7;
    + 
    +     if (type != DATA_ELE_SEQ_DESC_TYPE)
    +-        return (p);
    ++        return NULL;
    + 
    +     switch (size)
    +     {
    +     case SIZE_IN_NEXT_BYTE:
    ++        if (param_len < sizeof(uint8_t)) return NULL;
    ++        param_len -= sizeof(uint8_t);
    +         BE_STREAM_TO_UINT8 (list_len, p);
    +         break;
    + 
    +     case SIZE_IN_NEXT_WORD:
    ++        if (param_len < sizeof(uint16_t)) return NULL;
    ++        param_len -= sizeof(uint16_t);
    +         BE_STREAM_TO_UINT16 (list_len, p);
    +         break;
    + 
    +     case SIZE_IN_NEXT_LONG:
    ++        if (param_len < sizeof(uint32_t)) return NULL;
    ++        param_len -= sizeof(uint32_t);
    +         BE_STREAM_TO_UINT32 (list_len, p);
    +         break;
    + 
    +     default:
    +-        return (p);
    ++        return NULL;
    +     }
    + 
    +     if (list_len > param_len)
    +-        return (p);
    ++        return NULL;
    + 
    +     p_end_list = p + list_len;
    + 
    +@@ -521,7 +540,7 @@ UINT8 *sdpu_extract_attr_seq (UINT8 *p, UINT16 param_len, tSDP_ATTR_SEQ *p_seq)
    +         size = descr & 7;
    + 
    +         if (type != UINT_DESC_TYPE)
    +-            return (p);
    ++            return NULL;
    + 
    +         switch (size)
    +         {
    +@@ -532,20 +551,24 @@ UINT8 *sdpu_extract_attr_seq (UINT8 *p, UINT16 param_len, tSDP_ATTR_SEQ *p_seq)
    +             attr_len = 4;
    +             break;
    +         case SIZE_IN_NEXT_BYTE:
    ++            if (p + sizeof(uint8_t) > p_end_list) return NULL;
    +             BE_STREAM_TO_UINT8 (attr_len, p);
    +             break;
    +         case SIZE_IN_NEXT_WORD:
    ++            if (p + sizeof(uint16_t) > p_end_list) return NULL;
    +             BE_STREAM_TO_UINT16 (attr_len, p);
    +             break;
    +         case SIZE_IN_NEXT_LONG:
    ++            if (p + sizeof(uint32_t) > p_end_list) return NULL;
    +             BE_STREAM_TO_UINT32 (attr_len, p);
    +             break;
    +         default:
    +-            return (NULL);
    ++            return NULL;
    +             break;
    +         }
    + 
    +         /* Attribute length must be 2-bytes or 4-bytes for a paired entry. */
    ++        if (p + attr_len > p_end_list) return NULL;
    +         if (attr_len == 2)
    +         {
    +             BE_STREAM_TO_UINT16 (p_seq->attr_entry[p_seq->num_attr].start, p);
     diff --git a/stack/sdp/sdpint.h b/stack/sdp/sdpint.h
     index 05414cd..71dab92 100644
     --- a/stack/sdp/sdpint.h
    
    From 30da9d76244180c1d4537fe4cc5375e05d3549eb Mon Sep 17 00:00:00 2001
    From: AndDiSa <anddisa@googlemail.com>
    Date: Thu, 21 Jun 2018 18:11:00 +0200
    Subject: [PATCH 096/159] update patches
    
    Change-Id: Ib938429983975586f881cf2816e5cb5c178af533
    ---
     frameworks_av.patch     | 760 ++++++++++++++++++++++++++++++++++++++--
     frameworks_base.patch   | 403 +++++++++++++++++++++
     frameworks_native.patch | 337 ++++++++++++++++--
     system_bt.patch         | 558 +++++++++++++++++++++++++++--
     system_core.patch       | 107 ++++++
     5 files changed, 2083 insertions(+), 82 deletions(-)
    
    diff --git a/frameworks_av.patch b/frameworks_av.patch
    index dae7688..caeba98 100644
    --- a/frameworks_av.patch
    +++ b/frameworks_av.patch
    @@ -151,16 +151,127 @@ index bca3832..cf59357 100644
          }
      
          CHECK_EQ(mWriter->start(), (status_t)OK);
    +diff --git a/drm/mediadrm/plugins/clearkey/AesCtrDecryptor.cpp b/drm/mediadrm/plugins/clearkey/AesCtrDecryptor.cpp
    +index 01f8d65..f7106b2 100644
    +--- a/drm/mediadrm/plugins/clearkey/AesCtrDecryptor.cpp
    ++++ b/drm/mediadrm/plugins/clearkey/AesCtrDecryptor.cpp
    +@@ -36,6 +36,11 @@ android::status_t AesCtrDecryptor::decrypt(const android::Vector<uint8_t>& key,
    +     uint8_t previousEncryptedCounter[kBlockSize];
    +     memset(previousEncryptedCounter, 0, kBlockSize);
    + 
    ++    if (key.size() != kBlockSize || (sizeof(Iv) / sizeof(uint8_t)) != kBlockSize) {
    ++        android_errorWriteLog(0x534e4554, "63982768");
    ++        return android::ERROR_DRM_DECRYPT;
    ++    }
    ++
    +     size_t offset = 0;
    +     AES_KEY opensslKey;
    +     AES_set_encrypt_key(key.array(), kBlockBitCount, &opensslKey);
    +diff --git a/drm/mediadrm/plugins/clearkey/AesCtrDecryptor.h b/drm/mediadrm/plugins/clearkey/AesCtrDecryptor.h
    +index b416266..edb8445 100644
    +--- a/drm/mediadrm/plugins/clearkey/AesCtrDecryptor.h
    ++++ b/drm/mediadrm/plugins/clearkey/AesCtrDecryptor.h
    +@@ -18,6 +18,7 @@
    + #define CLEARKEY_AES_CTR_DECRYPTOR_H_
    + 
    + #include <media/stagefright/foundation/ABase.h>
    ++#include <media/stagefright/MediaErrors.h>
    + #include <Utils.h>
    + #include <utils/Errors.h>
    + #include <utils/Vector.h>
    +diff --git a/drm/mediadrm/plugins/clearkey/tests/AesCtrDecryptorUnittest.cpp b/drm/mediadrm/plugins/clearkey/tests/AesCtrDecryptorUnittest.cpp
    +index 039e402..5db8290 100644
    +--- a/drm/mediadrm/plugins/clearkey/tests/AesCtrDecryptorUnittest.cpp
    ++++ b/drm/mediadrm/plugins/clearkey/tests/AesCtrDecryptorUnittest.cpp
    +@@ -34,7 +34,7 @@ class AesCtrDecryptorTest : public ::testing::Test {
    +                             uint8_t* destination, const SubSample* subSamples,
    +                             size_t numSubSamples, size_t* bytesDecryptedOut) {
    +         Vector<uint8_t> keyVector;
    +-        keyVector.appendArray(key, kBlockSize);
    ++        keyVector.appendArray(key, sizeof(key) / sizeof(uint8_t));
    + 
    +         AesCtrDecryptor decryptor;
    +         return decryptor.decrypt(keyVector, iv, source, destination, subSamples,
    +@@ -57,6 +57,67 @@ class AesCtrDecryptorTest : public ::testing::Test {
    +     }
    + };
    + 
    ++TEST_F(AesCtrDecryptorTest, DecryptsWithEmptyKey) {
    ++    const size_t kTotalSize = 64;
    ++    const size_t kNumSubsamples = 1;
    ++
    ++    // Test vectors from NIST-800-38A
    ++    Iv iv = {
    ++        0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7,
    ++        0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff
    ++    };
    ++
    ++    uint8_t source[kTotalSize] = { 0 };
    ++    uint8_t destination[kTotalSize] = { 0 };
    ++    SubSample subSamples[kNumSubsamples] = {
    ++        {0, 64}
    ++    };
    ++
    ++    size_t bytesDecrypted = 0;
    ++    Vector<uint8_t> keyVector;
    ++    keyVector.clear();
    ++
    ++    AesCtrDecryptor decryptor;
    ++    ASSERT_EQ(android::ERROR_DRM_DECRYPT, decryptor.decrypt(keyVector, iv,
    ++              &source[0], &destination[0],
    ++              &subSamples[0], kNumSubsamples, &bytesDecrypted));
    ++    ASSERT_EQ(0u, bytesDecrypted);
    ++}
    ++
    ++TEST_F(AesCtrDecryptorTest, DecryptsWithKeyTooLong) {
    ++    const size_t kTotalSize = 64;
    ++    const size_t kNumSubsamples = 1;
    ++
    ++    // Test vectors from NIST-800-38A
    ++    uint8_t key[kBlockSize * 2] = {
    ++        0x2b, 0x7e, 0x15, 0x16, 0x28, 0xae, 0xd2, 0xa6,
    ++        0xab, 0xf7, 0x15, 0x88, 0x09, 0xcf, 0x4f, 0x3c,
    ++        0x2b, 0x7e, 0x15, 0x16, 0x28, 0xae, 0xd2, 0xa6,
    ++        0xab, 0xf7, 0x15, 0x88, 0x09, 0xcf, 0x4f, 0x3c
    ++    };
    ++
    ++    Iv iv = {
    ++        0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7,
    ++        0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff
    ++    };
    ++
    ++    uint8_t source[kTotalSize] = { 0 };
    ++    uint8_t destination[kTotalSize] = { 0 };
    ++    SubSample subSamples[kNumSubsamples] = {
    ++        {0, 64}
    ++    };
    ++
    ++    size_t bytesDecrypted = 0;
    ++    Vector<uint8_t> keyVector;
    ++    keyVector.appendArray(key, sizeof(key) / sizeof(uint8_t));
    ++
    ++    AesCtrDecryptor decryptor;
    ++    ASSERT_EQ(android::ERROR_DRM_DECRYPT, decryptor.decrypt(keyVector, iv,
    ++              &source[0], &destination[0],
    ++              &subSamples[0], kNumSubsamples, &bytesDecrypted));
    ++    ASSERT_EQ(0u, bytesDecrypted);
    ++}
    ++
    + TEST_F(AesCtrDecryptorTest, DecryptsContiguousEncryptedBlock) {
    +     const size_t kTotalSize = 64;
    +     const size_t kNumSubsamples = 1;
     diff --git a/include/media/IAudioPolicyService.h b/include/media/IAudioPolicyService.h
    -index 0e9e3bc..de6e5ce 100644
    +index 0e9e3bc..9ffcc77 100644
     --- a/include/media/IAudioPolicyService.h
     +++ b/include/media/IAudioPolicyService.h
    -@@ -181,6 +181,8 @@ public:
    +@@ -181,6 +181,10 @@ public:
                                          const Parcel& data,
                                          Parcel* reply,
                                          uint32_t flags = 0);
     +private:
     +    void sanetizeAudioAttributes(audio_attributes_t* attr);
    ++    status_t sanitizeEffectDescriptor(effect_descriptor_t* desc);
    ++    status_t sanitizeAudioPortConfig(struct audio_port_config* config);
      };
      
      // ----------------------------------------------------------------------------
    @@ -178,6 +289,81 @@ index 34b15e9..743ef7f 100644
          virtual sp<IMediaSource> getTrack(size_t index) = 0;
      
          enum GetTrackMetaDataFlags {
    +diff --git a/include/media/MediaPlayerInterface.h b/include/media/MediaPlayerInterface.h
    +index 4977efd..c1bd8eb 100644
    +--- a/include/media/MediaPlayerInterface.h
    ++++ b/include/media/MediaPlayerInterface.h
    +@@ -65,14 +65,17 @@ enum player_type {
    + // duration below which we do not allow deep audio buffering
    + #define AUDIO_SINK_MIN_DEEP_BUFFER_DURATION_US 5000000
    + 
    +-// callback mechanism for passing messages to MediaPlayer object
    +-typedef void (*notify_callback_f)(void* cookie,
    +-        int msg, int ext1, int ext2, const Parcel *obj);
    +-
    + // abstract base class - use MediaPlayerInterface
    + class MediaPlayerBase : public RefBase
    + {
    + public:
    ++    // callback mechanism for passing messages to MediaPlayer object
    ++    class Listener : public RefBase {
    ++    public:
    ++        virtual void notify(int msg, int ext1, int ext2, const Parcel *obj) = 0;
    ++        virtual ~Listener() {}
    ++    };
    ++
    +     // AudioSink: abstraction layer for audio output
    +     class AudioSink : public RefBase {
    +     public:
    +@@ -146,7 +149,7 @@ public:
    +         virtual String8     getParameters(const String8& /* keys */) { return String8::empty(); }
    +     };
    + 
    +-                        MediaPlayerBase() : mCookie(0), mNotify(0) {}
    ++                        MediaPlayerBase() {}
    +     virtual             ~MediaPlayerBase() {}
    +     virtual status_t    initCheck() = 0;
    +     virtual bool        hardwareOutput() = 0;
    +@@ -247,22 +250,22 @@ public:
    +     };
    + 
    +     void        setNotifyCallback(
    +-            void* cookie, notify_callback_f notifyFunc) {
    ++            const sp<Listener> &listener) {
    +         Mutex::Autolock autoLock(mNotifyLock);
    +-        mCookie = cookie; mNotify = notifyFunc;
    ++        mListener = listener;
    +     }
    + 
    +     void        sendEvent(int msg, int ext1=0, int ext2=0,
    +                           const Parcel *obj=NULL) {
    +-        notify_callback_f notifyCB;
    +-        void* cookie;
    ++        sp<Listener> listener;
    +         {
    +             Mutex::Autolock autoLock(mNotifyLock);
    +-            notifyCB = mNotify;
    +-            cookie = mCookie;
    ++            listener = mListener;
    +         }
    + 
    +-        if (notifyCB) notifyCB(cookie, msg, ext1, ext2, obj);
    ++        if (listener != NULL) {
    ++            listener->notify(msg, ext1, ext2, obj);
    ++        }
    +     }
    + 
    +     virtual status_t dump(int /* fd */, const Vector<String16>& /* args */) const {
    +@@ -273,8 +276,7 @@ private:
    +     friend class MediaPlayerService;
    + 
    +     Mutex               mNotifyLock;
    +-    void*               mCookie;
    +-    notify_callback_f   mNotify;
    ++    sp<Listener>        mListener;
    + };
    + 
    + // Implement this class for media players that use the AudioFlinger software mixer
     diff --git a/include/media/stagefright/MediaBufferGroup.h b/include/media/stagefright/MediaBufferGroup.h
     index 3051406..870bb9b 100644
     --- a/include/media/stagefright/MediaBufferGroup.h
    @@ -228,7 +414,7 @@ index dcf3fa0..07ea818 100644
              strncpy(name, EqualizerGetPresetName(param2), *pValueSize - 1);
              name[*pValueSize - 1] = 0;
     diff --git a/media/libeffects/lvm/wrapper/Reverb/EffectReverb.cpp b/media/libeffects/lvm/wrapper/Reverb/EffectReverb.cpp
    -index 4dc8b45..19892dd 100644
    +index 4dc8b45..80c8a38 100644
     --- a/media/libeffects/lvm/wrapper/Reverb/EffectReverb.cpp
     +++ b/media/libeffects/lvm/wrapper/Reverb/EffectReverb.cpp
     @@ -180,12 +180,13 @@ int  Reverb_init            (ReverbContext *pContext);
    @@ -261,7 +447,18 @@ index 4dc8b45..19892dd 100644
          int status = 0;
          int16_t level;
          int16_t ratio;
    -@@ -1776,6 +1778,11 @@ int Reverb_setParameter (ReverbContext *pContext, void *pParam, void *pValue){
    +@@ -1766,6 +1768,10 @@ int Reverb_setParameter (ReverbContext *pContext, void *pParam, void *pValue){
    +         if (param != REVERB_PARAM_PRESET) {
    +             return -EINVAL;
    +         }
    ++        if (vsize < (int)sizeof(uint16_t)) {
    ++            android_errorWriteLog(0x534e4554, "67647856");
    ++            return -EINVAL;
    ++        }
    + 
    +         uint16_t preset = *(uint16_t *)pValue;
    +         ALOGV("set REVERB_PARAM_PRESET, preset %d", preset);
    +@@ -1776,6 +1782,11 @@ int Reverb_setParameter (ReverbContext *pContext, void *pParam, void *pValue){
              return 0;
          }
      
    @@ -273,7 +470,7 @@ index 4dc8b45..19892dd 100644
          switch (param){
              case REVERB_PARAM_PROPERTIES:
                  ALOGV("\tReverb_setParameter() REVERB_PARAM_PROPERTIES");
    -@@ -1851,6 +1858,31 @@ int Reverb_setParameter (ReverbContext *pContext, void *pParam, void *pValue){
    +@@ -1851,6 +1862,31 @@ int Reverb_setParameter (ReverbContext *pContext, void *pParam, void *pValue){
          return status;
      } /* end Reverb_setParameter */
      
    @@ -305,7 +502,7 @@ index 4dc8b45..19892dd 100644
      } // namespace
      } // namespace
      
    -@@ -2022,7 +2054,8 @@ int Reverb_command(effect_handle_t  self,
    +@@ -2022,7 +2058,8 @@ int Reverb_command(effect_handle_t  self,
      
                  *(int *)pReplyData = android::Reverb_setParameter(pContext,
                                                                   (void *)p->data,
    @@ -316,37 +513,144 @@ index 4dc8b45..19892dd 100644
      
              case EFFECT_CMD_ENABLE:
     diff --git a/media/libmedia/IAudioPolicyService.cpp b/media/libmedia/IAudioPolicyService.cpp
    -index 6405d6d..09bacc0 100644
    +index 6405d6d..be826ab 100644
     --- a/media/libmedia/IAudioPolicyService.cpp
     +++ b/media/libmedia/IAudioPolicyService.cpp
    -@@ -893,6 +893,7 @@ status_t BnAudioPolicyService::onTransact(
    +@@ -873,7 +873,7 @@ status_t BnAudioPolicyService::onTransact(
    +             audio_output_flags_t flags =
    +                     static_cast <audio_output_flags_t>(data.readInt32());
    +             bool hasOffloadInfo = data.readInt32() != 0;
    +-            audio_offload_info_t offloadInfo;
    ++            audio_offload_info_t offloadInfo = {};
    +             if (hasOffloadInfo) {
    +                 data.read(&offloadInfo, sizeof(audio_offload_info_t));
    +             }
    +@@ -889,10 +889,11 @@ status_t BnAudioPolicyService::onTransact(
    + 
    +         case GET_OUTPUT_FOR_ATTR: {
    +             CHECK_INTERFACE(IAudioPolicyService, data, reply);
    +-            audio_attributes_t attr;
    ++            audio_attributes_t attr = {};
                  bool hasAttributes = data.readInt32() != 0;
                  if (hasAttributes) {
                      data.read(&attr, sizeof(audio_attributes_t));
    -+		sanetizeAudioAttributes(&attr);
    ++                sanetizeAudioAttributes(&attr);
                  }
                  audio_session_t session = (audio_session_t)data.readInt32();
                  audio_stream_type_t stream = AUDIO_STREAM_DEFAULT;
    -@@ -960,6 +961,7 @@ status_t BnAudioPolicyService::onTransact(
    +@@ -958,8 +959,9 @@ status_t BnAudioPolicyService::onTransact(
    + 
    +         case GET_INPUT_FOR_ATTR: {
                  CHECK_INTERFACE(IAudioPolicyService, data, reply);
    -             audio_attributes_t attr;
    +-            audio_attributes_t attr;
    ++            audio_attributes_t attr = {};
                  data.read(&attr, sizeof(audio_attributes_t));
     +            sanetizeAudioAttributes(&attr);
                  audio_session_t session = (audio_session_t)data.readInt32();
                  pid_t pid = (pid_t)data.readInt32();
                  uid_t uid = (uid_t)data.readInt32();
    -@@ -1332,6 +1334,7 @@ status_t BnAudioPolicyService::onTransact(
    +@@ -1055,8 +1057,11 @@ status_t BnAudioPolicyService::onTransact(
    + 
    +         case GET_OUTPUT_FOR_EFFECT: {
    +             CHECK_INTERFACE(IAudioPolicyService, data, reply);
    +-            effect_descriptor_t desc;
    +-            data.read(&desc, sizeof(effect_descriptor_t));
    ++            effect_descriptor_t desc = {};
    ++            if (data.read(&desc, sizeof(desc)) != NO_ERROR) {
    ++                android_errorWriteLog(0x534e4554, "73126106");
    ++            }
    ++            (void)sanitizeEffectDescriptor(&desc);
    +             audio_io_handle_t output = getOutputForEffect(&desc);
    +             reply->writeInt32(static_cast <int>(output));
    +             return NO_ERROR;
    +@@ -1064,8 +1069,11 @@ status_t BnAudioPolicyService::onTransact(
    + 
    +         case REGISTER_EFFECT: {
    +             CHECK_INTERFACE(IAudioPolicyService, data, reply);
    +-            effect_descriptor_t desc;
    +-            data.read(&desc, sizeof(effect_descriptor_t));
    ++            effect_descriptor_t desc = {};
    ++            if (data.read(&desc, sizeof(desc)) != NO_ERROR) {
    ++                android_errorWriteLog(0x534e4554, "73126106");
    ++            }
    ++            (void)sanitizeEffectDescriptor(&desc);
    +             audio_io_handle_t io = data.readInt32();
    +             uint32_t strategy = data.readInt32();
    +             audio_session_t session = (audio_session_t) data.readInt32();
    +@@ -1124,7 +1132,7 @@ status_t BnAudioPolicyService::onTransact(
    +                 count = AudioEffect::kMaxPreProcessing;
    +             }
    +             uint32_t retCount = count;
    +-            effect_descriptor_t *descriptors = new effect_descriptor_t[count];
    ++            effect_descriptor_t *descriptors = new effect_descriptor_t[count]{};
    +             status_t status = queryDefaultPreProcessing(audioSession, descriptors, &retCount);
    +             reply->writeInt32(status);
    +             if (status != NO_ERROR && status != NO_MEMORY) {
    +@@ -1143,7 +1151,7 @@ status_t BnAudioPolicyService::onTransact(
    + 
    +         case IS_OFFLOAD_SUPPORTED: {
    +             CHECK_INTERFACE(IAudioPolicyService, data, reply);
    +-            audio_offload_info_t info;
    ++            audio_offload_info_t info = {};
    +             data.read(&info, sizeof(audio_offload_info_t));
    +             bool isSupported = isOffloadSupported(info);
    +             reply->writeInt32(isSupported);
    +@@ -1198,7 +1206,7 @@ status_t BnAudioPolicyService::onTransact(
    + 
    +         case CREATE_AUDIO_PATCH: {
    +             CHECK_INTERFACE(IAudioPolicyService, data, reply);
    +-            struct audio_patch patch;
    ++            struct audio_patch patch = {};
    +             data.read(&patch, sizeof(struct audio_patch));
    +             audio_patch_handle_t handle = AUDIO_PATCH_HANDLE_NONE;
    +             if (data.read(&handle, sizeof(audio_patch_handle_t)) != NO_ERROR) {
    +@@ -1214,7 +1222,7 @@ status_t BnAudioPolicyService::onTransact(
    + 
    +         case RELEASE_AUDIO_PATCH: {
    +             CHECK_INTERFACE(IAudioPolicyService, data, reply);
    +-            audio_patch_handle_t handle;
    ++            audio_patch_handle_t handle = AUDIO_PATCH_HANDLE_NONE;
    +             data.read(&handle, sizeof(audio_patch_handle_t));
    +             status_t status = releaseAudioPatch(handle);
    +             reply->writeInt32(status);
    +@@ -1253,8 +1261,9 @@ status_t BnAudioPolicyService::onTransact(
    + 
    +         case SET_AUDIO_PORT_CONFIG: {
    +             CHECK_INTERFACE(IAudioPolicyService, data, reply);
    +-            struct audio_port_config config;
    ++            struct audio_port_config config = {};
    +             data.read(&config, sizeof(struct audio_port_config));
    ++            (void)sanitizeAudioPortConfig(&config);
    +             status_t status = setAudioPortConfig(&config);
    +             reply->writeInt32(status);
    +             return NO_ERROR;
    +@@ -1328,10 +1337,12 @@ status_t BnAudioPolicyService::onTransact(
    + 
    +         case START_AUDIO_SOURCE: {
    +             CHECK_INTERFACE(IAudioPolicyService, data, reply);
    +-            struct audio_port_config source;
    ++            struct audio_port_config source = {};
                  data.read(&source, sizeof(struct audio_port_config));
    -             audio_attributes_t attributes;
    +-            audio_attributes_t attributes;
    ++            (void)sanitizeAudioPortConfig(&source);
    ++            audio_attributes_t attributes = {};
                  data.read(&attributes, sizeof(audio_attributes_t));
     +            sanetizeAudioAttributes(&attributes);
                  audio_io_handle_t handle = {};
                  status_t status = startAudioSource(&source, &attributes, &handle);
                  reply->writeInt32(status);
    -@@ -1371,6 +1374,16 @@ status_t BnAudioPolicyService::onTransact(
    +@@ -1371,6 +1382,44 @@ status_t BnAudioPolicyService::onTransact(
          }
      }
      
    ++/** returns true if string overflow was prevented by zero termination */
    ++template <size_t size>
    ++static bool preventStringOverflow(char (&s)[size]) {
    ++    if (strnlen(s, size) < size) return false;
    ++    s[size - 1] = '\0';
    ++    return true;
    ++}
    ++
     +void BnAudioPolicyService::sanetizeAudioAttributes(audio_attributes_t* attr)
     +{
     +    const size_t tagsMaxSize = AUDIO_ATTRIBUTES_TAGS_MAX_SIZE;
    @@ -355,12 +659,31 @@ index 6405d6d..09bacc0 100644
     +    }
     +    attr->tags[tagsMaxSize - 1] = '\0';
     +}
    ++
    ++/** returns BAD_VALUE if sanitization was required. */
    ++status_t BnAudioPolicyService::sanitizeEffectDescriptor(effect_descriptor_t* desc)
    ++{
    ++    if (preventStringOverflow(desc->name)
    ++        | /* always */ preventStringOverflow(desc->implementor)) {
    ++        android_errorWriteLog(0x534e4554, "73126106"); // SafetyNet logging
    ++        return BAD_VALUE;
    ++    }
    ++    return NO_ERROR;
    ++}
    ++
    ++/** returns BAD_VALUE if sanitization was required. */
    ++status_t BnAudioPolicyService::sanitizeAudioPortConfig(struct audio_port_config* config)
    ++{
    ++    if (config->type == AUDIO_PORT_TYPE_DEVICE &&
    ++        preventStringOverflow(config->ext.device.address)) {
    ++        return BAD_VALUE;
    ++    }
    ++    return NO_ERROR;
    ++}
     +
      // ----------------------------------------------------------------------------
      
    --} // namespace android
    -+ 
    -+ } // namespace android
    + } // namespace android
     diff --git a/media/libmedia/IDataSource.cpp b/media/libmedia/IDataSource.cpp
     index 51c9938..5ad39fe 100644
     --- a/media/libmedia/IDataSource.cpp
    @@ -445,8 +768,45 @@ index 72d1d7c..4be1118 100644
                  break;
              }
          }
    +diff --git a/media/libmediaplayerservice/MediaPlayerFactory.cpp b/media/libmediaplayerservice/MediaPlayerFactory.cpp
    +index 605c710..f5ec20c 100644
    +--- a/media/libmediaplayerservice/MediaPlayerFactory.cpp
    ++++ b/media/libmediaplayerservice/MediaPlayerFactory.cpp
    +@@ -127,8 +127,7 @@ player_type MediaPlayerFactory::getPlayerType(const sp<IMediaPlayer>& client,
    + 
    + sp<MediaPlayerBase> MediaPlayerFactory::createPlayer(
    +         player_type playerType,
    +-        void* cookie,
    +-        notify_callback_f notifyFunc,
    ++        const sp<MediaPlayerBase::Listener> &listener,
    +         pid_t pid) {
    +     sp<MediaPlayerBase> p;
    +     IFactory* factory;
    +@@ -153,7 +152,7 @@ sp<MediaPlayerBase> MediaPlayerFactory::createPlayer(
    + 
    +     init_result = p->initCheck();
    +     if (init_result == NO_ERROR) {
    +-        p->setNotifyCallback(cookie, notifyFunc);
    ++        p->setNotifyCallback(listener);
    +     } else {
    +         ALOGE("Failed to create player object of type %d, initCheck failed"
    +               " (res = %d)", playerType, init_result);
    +diff --git a/media/libmediaplayerservice/MediaPlayerFactory.h b/media/libmediaplayerservice/MediaPlayerFactory.h
    +index e22a56f..e88700c 100644
    +--- a/media/libmediaplayerservice/MediaPlayerFactory.h
    ++++ b/media/libmediaplayerservice/MediaPlayerFactory.h
    +@@ -65,8 +65,7 @@ class MediaPlayerFactory {
    +                                      const sp<DataSource> &source);
    + 
    +     static sp<MediaPlayerBase> createPlayer(player_type playerType,
    +-                                            void* cookie,
    +-                                            notify_callback_f notifyFunc,
    ++                                            const sp<MediaPlayerBase::Listener> &listener,
    +                                             pid_t pid);
    + 
    +     static void registerBuiltinFactories();
     diff --git a/media/libmediaplayerservice/MediaPlayerService.cpp b/media/libmediaplayerservice/MediaPlayerService.cpp
    -index bd16e91..6e689e6 100644
    +index bd16e91..7196f42 100644
     --- a/media/libmediaplayerservice/MediaPlayerService.cpp
     +++ b/media/libmediaplayerservice/MediaPlayerService.cpp
     @@ -82,6 +82,9 @@
    @@ -496,7 +856,19 @@ index bd16e91..6e689e6 100644
          }
          write(fd, "\n", 1);
          return NO_ERROR;
    -@@ -590,7 +613,10 @@ MediaPlayerService::Client::Client(
    +@@ -580,17 +603,21 @@ MediaPlayerService::Client::Client(
    +     mUID = uid;
    +     mRetransmitEndpointValid = false;
    +     mAudioAttributes = NULL;
    ++    mListener = new Listener(this);
    + 
    + #if CALLBACK_ANTAGONIZER
    +     ALOGD("create Antagonizer");
    +-    mAntagonizer = new Antagonizer(notify, this);
    ++    mAntagonizer = new Antagonizer(mListener);
    + #endif
    + }
    + 
      MediaPlayerService::Client::~Client()
      {
          ALOGV("Client(%d) destructor pid = %d", mConnId, mPid);
    @@ -508,7 +880,7 @@ index bd16e91..6e689e6 100644
          wp<Client> client(this);
          disconnect();
          mService->removeClient(client);
    -@@ -609,10 +635,9 @@ void MediaPlayerService::Client::disconnect()
    +@@ -609,15 +636,14 @@ void MediaPlayerService::Client::disconnect()
              Mutex::Autolock l(mLock);
              p = mPlayer;
              mClient.clear();
    @@ -520,7 +892,13 @@ index bd16e91..6e689e6 100644
          // clear the notification to prevent callbacks to dead client
          // and reset the player. We assume the player will serialize
          // access to itself if necessary.
    -@@ -633,7 +658,7 @@ void MediaPlayerService::Client::disconnect()
    +     if (p != 0) {
    +-        p->setNotifyCallback(0, 0);
    ++        p->setNotifyCallback(0);
    + #if CALLBACK_ANTAGONIZER
    +         ALOGD("kill Antagonizer");
    +         mAntagonizer->kill();
    +@@ -633,13 +659,13 @@ void MediaPlayerService::Client::disconnect()
      sp<MediaPlayerBase> MediaPlayerService::Client::createPlayer(player_type playerType)
      {
          // determine if we have the right player type
    @@ -529,7 +907,14 @@ index bd16e91..6e689e6 100644
          if ((p != NULL) && (p->playerType() != playerType)) {
              ALOGV("delete player");
              p.clear();
    -@@ -721,6 +746,7 @@ void MediaPlayerService::Client::setDataSource_post(
    +     }
    +     if (p == NULL) {
    +-        p = MediaPlayerFactory::createPlayer(playerType, this, notify, mPid);
    ++        p = MediaPlayerFactory::createPlayer(playerType, mListener, mPid);
    +     }
    + 
    +     if (p != NULL) {
    +@@ -721,6 +747,7 @@ void MediaPlayerService::Client::setDataSource_post(
          }
      
          if (mStatus == OK) {
    @@ -537,6 +922,213 @@ index bd16e91..6e689e6 100644
              mPlayer = p;
          }
      }
    +@@ -1276,24 +1303,36 @@ status_t MediaPlayerService::Client::getRetransmitEndpoint(
    + }
    + 
    + void MediaPlayerService::Client::notify(
    +-        void* cookie, int msg, int ext1, int ext2, const Parcel *obj)
    ++        int msg, int ext1, int ext2, const Parcel *obj)
    + {
    +-    Client* client = static_cast<Client*>(cookie);
    +-    if (client == NULL) {
    +-        return;
    +-    }
    +-
    +     sp<IMediaPlayerClient> c;
    ++    sp<Client> nextClient;
    ++    status_t errStartNext = NO_ERROR;
    +     {
    +-        Mutex::Autolock l(client->mLock);
    +-        c = client->mClient;
    +-        if (msg == MEDIA_PLAYBACK_COMPLETE && client->mNextClient != NULL) {
    +-            if (client->mAudioOutput != NULL)
    +-                client->mAudioOutput->switchToNextOutput();
    +-            client->mNextClient->start();
    +-            if (client->mNextClient->mClient != NULL) {
    +-                client->mNextClient->mClient->notify(
    +-                        MEDIA_INFO, MEDIA_INFO_STARTED_AS_NEXT, 0, obj);
    ++        Mutex::Autolock l(mLock);
    ++        c = mClient;
    ++        if (msg == MEDIA_PLAYBACK_COMPLETE && mNextClient != NULL) {
    ++            nextClient = mNextClient;
    ++
    ++            if (mAudioOutput != NULL)
    ++                mAudioOutput->switchToNextOutput();
    ++
    ++            errStartNext = nextClient->start();
    ++        }
    ++    }
    ++
    ++    if (nextClient != NULL) {
    ++        sp<IMediaPlayerClient> nc;
    ++        {
    ++            Mutex::Autolock l(nextClient->mLock);
    ++            nc = nextClient->mClient;
    ++        }
    ++        if (nc != NULL) {
    ++            if (errStartNext == NO_ERROR) {
    ++                nc->notify(MEDIA_INFO, MEDIA_INFO_STARTED_AS_NEXT, 0, obj);
    ++            } else {
    ++                nc->notify(MEDIA_ERROR, MEDIA_ERROR_UNKNOWN , 0, obj);
    ++                ALOGE("gapless:start playback for next track failed, err(%d)", errStartNext);
    +             }
    +         }
    +     }
    +@@ -1302,17 +1341,17 @@ void MediaPlayerService::Client::notify(
    +         MEDIA_INFO_METADATA_UPDATE == ext1) {
    +         const media::Metadata::Type metadata_type = ext2;
    + 
    +-        if(client->shouldDropMetadata(metadata_type)) {
    ++        if(shouldDropMetadata(metadata_type)) {
    +             return;
    +         }
    + 
    +         // Update the list of metadata that have changed. getMetadata
    +         // also access mMetadataUpdated and clears it.
    +-        client->addNewMetadataUpdate(metadata_type);
    ++        addNewMetadataUpdate(metadata_type);
    +     }
    + 
    +     if (c != NULL) {
    +-        ALOGV("[%d] notify (%p, %d, %d, %d)", client->mConnId, cookie, msg, ext1, ext2);
    ++        ALOGV("[%d] notify (%d, %d, %d)", mConnId, msg, ext1, ext2);
    +         c->notify(msg, ext1, ext2, obj);
    +     }
    + }
    +@@ -1344,8 +1383,8 @@ void MediaPlayerService::Client::addNewMetadataUpdate(media::Metadata::Type meta
    + #if CALLBACK_ANTAGONIZER
    + const int Antagonizer::interval = 10000; // 10 msecs
    + 
    +-Antagonizer::Antagonizer(notify_callback_f cb, void* client) :
    +-    mExit(false), mActive(false), mClient(client), mCb(cb)
    ++Antagonizer::Antagonizer(const sp<MediaPlayerBase::Listener> &listener) :
    ++    mExit(false), mActive(false), mListener(listener)
    + {
    +     createThread(callbackThread, this);
    + }
    +@@ -1365,7 +1404,7 @@ int Antagonizer::callbackThread(void* user)
    +     while (!p->mExit) {
    +         if (p->mActive) {
    +             ALOGV("send event");
    +-            p->mCb(p->mClient, 0, 0, 0);
    ++            p->mListener->notify(0, 0, 0, 0);
    +         }
    +         usleep(interval);
    +     }
    +diff --git a/media/libmediaplayerservice/MediaPlayerService.h b/media/libmediaplayerservice/MediaPlayerService.h
    +index 7a41d9c..99b1d4d 100644
    +--- a/media/libmediaplayerservice/MediaPlayerService.h
    ++++ b/media/libmediaplayerservice/MediaPlayerService.h
    +@@ -49,7 +49,7 @@ class MediaRecorderClient;
    + #if CALLBACK_ANTAGONIZER
    + class Antagonizer {
    + public:
    +-    Antagonizer(notify_callback_f cb, void* client);
    ++    Antagonizer(const sp<MediaPlayerBase::Listener> &listener);
    +     void start() { mActive = true; }
    +     void stop() { mActive = false; }
    +     void kill();
    +@@ -57,12 +57,11 @@ private:
    +     static const int interval;
    +     Antagonizer();
    +     static int callbackThread(void* cookie);
    +-    Mutex               mLock;
    +-    Condition           mCondition;
    +-    bool                mExit;
    +-    bool                mActive;
    +-    void*               mClient;
    +-    notify_callback_f   mCb;
    ++    Mutex                         mLock;
    ++    Condition                     mCondition;
    ++    bool                          mExit;
    ++    bool                          mActive;
    ++    sp<MediaPlayerBase::Listener> mListener;
    + };
    + #endif
    + 
    +@@ -206,7 +205,6 @@ class MediaPlayerService : public BnMediaPlayerService
    + 
    +     }; // AudioOutput
    + 
    +-
    + public:
    +     static  void                instantiate();
    + 
    +@@ -335,8 +333,7 @@ private:
    +         void                    setDataSource_post(const sp<MediaPlayerBase>& p,
    +                                                    status_t status);
    + 
    +-        static  void            notify(void* cookie, int msg,
    +-                                       int ext1, int ext2, const Parcel *obj);
    ++                void            notify(int msg, int ext1, int ext2, const Parcel *obj);
    + 
    +                 pid_t           pid() const { return mPid; }
    +         virtual status_t        dump(int fd, const Vector<String16>& args);
    +@@ -391,23 +388,38 @@ private:
    + 
    +         status_t setAudioAttributes_l(const Parcel &request);
    + 
    +-        mutable     Mutex                       mLock;
    +-                    sp<MediaPlayerBase>         mPlayer;
    +-                    sp<MediaPlayerService>      mService;
    +-                    sp<IMediaPlayerClient>      mClient;
    +-                    sp<AudioOutput>             mAudioOutput;
    +-                    pid_t                       mPid;
    +-                    status_t                    mStatus;
    +-                    bool                        mLoop;
    +-                    int32_t                     mConnId;
    +-                    audio_session_t             mAudioSessionId;
    +-                    audio_attributes_t *        mAudioAttributes;
    +-                    uid_t                       mUID;
    +-                    sp<ANativeWindow>           mConnectedWindow;
    +-                    sp<IBinder>                 mConnectedWindowBinder;
    +-                    struct sockaddr_in          mRetransmitEndpoint;
    +-                    bool                        mRetransmitEndpointValid;
    +-                    sp<Client>                  mNextClient;
    ++        class Listener : public MediaPlayerBase::Listener {
    ++        public:
    ++            Listener(const wp<Client> &client) : mClient(client) {}
    ++            virtual ~Listener() {}
    ++            virtual void notify(int msg, int ext1, int ext2, const Parcel *obj) {
    ++                sp<Client> client = mClient.promote();
    ++                if (client != NULL) {
    ++                    client->notify(msg, ext1, ext2, obj);
    ++                }
    ++            }
    ++        private:
    ++            wp<Client> mClient;
    ++        };
    ++
    ++        mutable     Mutex                         mLock;
    ++                    sp<MediaPlayerBase>           mPlayer;
    ++                    sp<MediaPlayerService>        mService;
    ++                    sp<IMediaPlayerClient>        mClient;
    ++                    sp<AudioOutput>               mAudioOutput;
    ++                    pid_t                         mPid;
    ++                    status_t                      mStatus;
    ++                    bool                          mLoop;
    ++                    int32_t                       mConnId;
    ++                    audio_session_t               mAudioSessionId;
    ++                    audio_attributes_t *          mAudioAttributes;
    ++                    uid_t                         mUID;
    ++                    sp<ANativeWindow>             mConnectedWindow;
    ++                    sp<IBinder>                   mConnectedWindowBinder;
    ++                    struct sockaddr_in            mRetransmitEndpoint;
    ++                    bool                          mRetransmitEndpointValid;
    ++                    sp<Client>                    mNextClient;
    ++                    sp<MediaPlayerBase::Listener> mListener;
    + 
    +         // Metadata filters.
    +         media::Metadata::Filter mMetadataAllow;  // protected by mLock
    +@@ -422,7 +434,7 @@ private:
    +         sp<IBinder::DeathRecipient> mExtractorDeathListener;
    +         sp<IBinder::DeathRecipient> mCodecDeathListener;
    + #if CALLBACK_ANTAGONIZER
    +-                    Antagonizer*                mAntagonizer;
    ++                    Antagonizer*                  mAntagonizer;
    + #endif
    +     }; // Client
    + 
     diff --git a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp
     index dc4e5d4..b64d899 100644
     --- a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp
    @@ -1090,6 +1682,26 @@ index 5441714..d1603c1 100644
                  return ERROR_BUFFER_TOO_SMALL;
              }
          }
    +diff --git a/media/libstagefright/MPEG4Writer.cpp b/media/libstagefright/MPEG4Writer.cpp
    +index 5e96c2b..6ca2abb 100644
    +--- a/media/libstagefright/MPEG4Writer.cpp
    ++++ b/media/libstagefright/MPEG4Writer.cpp
    +@@ -1674,10 +1674,12 @@ void MPEG4Writer::Track::getCodecSpecificDataFromInputFormatIfPossible() {
    +             || !strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_AAC)) {
    +         if (mMeta->findData(kKeyESDS, &type, &data, &size)) {
    +             ESDS esds(data, size);
    +-            if (esds.getCodecSpecificInfo(&data, &size) != OK) {
    +-                data = NULL;
    +-                size = 0;
    ++            if (esds.getCodecSpecificInfo(&data, &size) == OK &&
    ++                    data != NULL &&
    ++                    copyCodecSpecificData((uint8_t*)data, size) == OK) {
    ++                mGotAllCodecSpecificData = true;
    +             }
    ++            return;
    +         }
    +     }
    +     if (data != NULL && copyCodecSpecificData((uint8_t *)data, size) == OK) {
     diff --git a/media/libstagefright/MediaCodecList.cpp b/media/libstagefright/MediaCodecList.cpp
     index 0fb5072..a25c47d 100644
     --- a/media/libstagefright/MediaCodecList.cpp
    @@ -1303,10 +1915,35 @@ index 15ff569..547267c 100644
                  ALOGV("Slot %d returned, matches handle = %p", id,
                          mSlots[id].mGraphicBuffer->handle);
      
    +diff --git a/media/libstagefright/VideoFrameScheduler.cpp b/media/libstagefright/VideoFrameScheduler.cpp
    +index 03226c7..6819bba 100644
    +--- a/media/libstagefright/VideoFrameScheduler.cpp
    ++++ b/media/libstagefright/VideoFrameScheduler.cpp
    +@@ -129,6 +129,11 @@ bool VideoFrameScheduler::PLL::fit(
    +         numSamplesToUse = mNumSamples;
    +     }
    + 
    ++    if ((period >> kPrecision) == 0 ) {
    ++        ALOGW("Period is 0, or after including precision is 0 - would cause div0, returning");
    ++        return false;
    ++    }
    ++
    +     int64_t sumX = 0;
    +     int64_t sumXX = 0;
    +     int64_t sumXY = 0;
     diff --git a/media/libstagefright/avc_utils.cpp b/media/libstagefright/avc_utils.cpp
    -index 763381e..e5819ed 100644
    +index 763381e..78aae8c 100644
     --- a/media/libstagefright/avc_utils.cpp
     +++ b/media/libstagefright/avc_utils.cpp
    +@@ -330,7 +330,7 @@ static sp<ABuffer> FindNAL(const uint8_t *data, size_t size, unsigned nalType) {
    +     const uint8_t *nalStart;
    +     size_t nalSize;
    +     while (getNextNALUnit(&data, &size, &nalStart, &nalSize, true) == OK) {
    +-        if ((nalStart[0] & 0x1f) == nalType) {
    ++        if (nalSize > 0 && (nalStart[0] & 0x1f) == nalType) {
    +             sp<ABuffer> buffer = new ABuffer(nalSize);
    +             memcpy(buffer->data(), nalStart, nalSize);
    +             return buffer;
     @@ -479,7 +479,10 @@ bool IsAVCReferenceFrame(const sp<ABuffer> &accessUnit) {
          const uint8_t *nalStart;
          size_t nalSize;
    @@ -1485,6 +2122,19 @@ index d5a26d3..7d2131d 100644
                  const uint8_t *inputData = NULL;
                  if (mInputDataIsMeta) {
                      inputData =
    +diff --git a/media/libstagefright/codecs/mp3dec/src/pvmp3_decode_header.cpp b/media/libstagefright/codecs/mp3dec/src/pvmp3_decode_header.cpp
    +index d443b7c..bc5fd79 100644
    +--- a/media/libstagefright/codecs/mp3dec/src/pvmp3_decode_header.cpp
    ++++ b/media/libstagefright/codecs/mp3dec/src/pvmp3_decode_header.cpp
    +@@ -184,7 +184,7 @@ ERROR_CODE pvmp3_decode_header(tmp3Bits  *inputStream,
    +     info->emphasis           = (temp << 30) >> 30;  /* 2 */
    + 
    + 
    +-    if (!info->bitrate_index || info->sampling_frequency == 3)
    ++    if (!info->bitrate_index || info->bitrate_index == 15 || info->sampling_frequency == 3)
    +     {
    +         err = UNSUPPORTED_FREE_BITRATE;
    +     }
     diff --git a/media/libstagefright/codecs/mpeg2dec/SoftMPEG2.cpp b/media/libstagefright/codecs/mpeg2dec/SoftMPEG2.cpp
     index 5ed037a..7297f40 100644
     --- a/media/libstagefright/codecs/mpeg2dec/SoftMPEG2.cpp
    @@ -1764,6 +2414,24 @@ index c04549a..1242c95 100644
          return OK;
      }
      
    +diff --git a/media/libstagefright/id3/ID3.cpp b/media/libstagefright/id3/ID3.cpp
    +index 8b80ae9..c21097b 100644
    +--- a/media/libstagefright/id3/ID3.cpp
    ++++ b/media/libstagefright/id3/ID3.cpp
    +@@ -392,7 +392,12 @@ bool ID3::removeUnsynchronizationV2_4(bool iTunesHack) {
    +                     --mSize;
    +                     --dataSize;
    +                 }
    +-                mData[writeOffset++] = mData[readOffset++];
    ++                if (i + 1 < dataSize) {
    ++                    // Only move data if there's actually something to move.
    ++                    // This handles the special case of the data being only [0xff, 0x00]
    ++                    // which should be converted to just 0xff if unsynchronization is on.
    ++                    mData[writeOffset++] = mData[readOffset++];
    ++                }
    +             }
    +             // move the remaining data following this frame
    +             if (readOffset <= oldSize) {
     diff --git a/media/libstagefright/include/OMXNodeInstance.h b/media/libstagefright/include/OMXNodeInstance.h
     index 94cf15a..dd396e8 100644
     --- a/media/libstagefright/include/OMXNodeInstance.h
    @@ -4625,7 +5293,7 @@ index b3a11e0..cd543c8 100644
          void                sendStoreRemoved(MtpStorageID id);
          void                sendEvent(MtpEventCode code, uint32_t param1);
     diff --git a/services/audioflinger/AudioFlinger.cpp b/services/audioflinger/AudioFlinger.cpp
    -index fec3a57..a0ef28c 100644
    +index fec3a57..4aad2c2 100644
     --- a/services/audioflinger/AudioFlinger.cpp
     +++ b/services/audioflinger/AudioFlinger.cpp
     @@ -1509,7 +1509,8 @@ sp<IAudioRecord> AudioFlinger::openRecord(
    @@ -4634,7 +5302,7 @@ index fec3a57..a0ef28c 100644
          // check calling permissions
     -    if (!recordingAllowed(opPackageName, tid, clientUid)) {
     +    if (!isTrustedCallingUid(callingUid) &&
    -+		!recordingAllowed(opPackageName, tid, clientUid)) {
    ++                 !recordingAllowed(opPackageName, tid, callingUid)) {
              ALOGE("openRecord() permission denied: recording not allowed");
              lStatus = PERMISSION_DENIED;
              goto Exit;
    @@ -4667,6 +5335,48 @@ index f908d6d..b588685 100644
          if (cmdCode == EFFECT_CMD_ENABLE) {
              if (*replySize < sizeof(int)) {
                  android_errorWriteLog(0x534e4554, "32095713");
    +diff --git a/services/audioflinger/Threads.cpp b/services/audioflinger/Threads.cpp
    +index 7423ea9..1bc9516 100644
    +--- a/services/audioflinger/Threads.cpp
    ++++ b/services/audioflinger/Threads.cpp
    +@@ -1412,6 +1412,7 @@ sp<AudioFlinger::EffectHandle> AudioFlinger::ThreadBase::createEffect_l(
    +     bool chainCreated = false;
    +     bool effectCreated = false;
    +     bool effectRegistered = false;
    ++    audio_unique_id_t effectId = AUDIO_UNIQUE_ID_USE_UNSPECIFIED;
    + 
    +     lStatus = initCheck();
    +     if (lStatus != NO_ERROR) {
    +@@ -1445,15 +1446,17 @@ sp<AudioFlinger::EffectHandle> AudioFlinger::ThreadBase::createEffect_l(
    +         ALOGV("createEffect_l() got effect %p on chain %p", effect.get(), chain.get());
    + 
    +         if (effect == 0) {
    +-            audio_unique_id_t id = mAudioFlinger->nextUniqueId(AUDIO_UNIQUE_ID_USE_EFFECT);
    ++            effectId = mAudioFlinger->nextUniqueId(AUDIO_UNIQUE_ID_USE_EFFECT);
    +             // Check CPU and memory usage
    +-            lStatus = AudioSystem::registerEffect(desc, mId, chain->strategy(), sessionId, id);
    ++            lStatus = AudioSystem::registerEffect(
    ++                    desc, mId, chain->strategy(), sessionId, effectId);
    +             if (lStatus != NO_ERROR) {
    +                 goto Exit;
    +             }
    +             effectRegistered = true;
    +             // create a new effect module if none present in the chain
    +-            lStatus = chain->createEffect_l(effect, this, desc, id, sessionId, pinned);
    ++            lStatus = chain->createEffect_l(
    ++                    effect, this, desc, effectId, sessionId, pinned);
    +             if (lStatus != NO_ERROR) {
    +                 goto Exit;
    +             }
    +@@ -1482,7 +1485,7 @@ Exit:
    +             chain->removeEffect_l(effect);
    +         }
    +         if (effectRegistered) {
    +-            AudioSystem::unregisterEffect(effect->id());
    ++            AudioSystem::unregisterEffect(effectId);
    +         }
    +         if (chainCreated) {
    +             removeEffectChain_l(chain);
     diff --git a/services/audioflinger/Tracks.cpp b/services/audioflinger/Tracks.cpp
     index f18b88d..a3f3ea5 100644
     --- a/services/audioflinger/Tracks.cpp
    diff --git a/frameworks_base.patch b/frameworks_base.patch
    index f1f2388..08e551c 100644
    --- a/frameworks_base.patch
    +++ b/frameworks_base.patch
    @@ -98,6 +98,169 @@ index 5cc064e..4916c1c 100644
                      if (impl != null && key.mResDir.equals(assetPath)) {
                          if (!ArrayUtils.contains(key.mLibDirs, libAsset)) {
                              final int newLibAssetCount = 1 +
    +diff --git a/core/java/android/content/PermissionChecker.java b/core/java/android/content/PermissionChecker.java
    +new file mode 100644
    +index 0000000..a4b2fe0
    +--- /dev/null
    ++++ b/core/java/android/content/PermissionChecker.java
    +@@ -0,0 +1,157 @@
    ++/*
    ++ * Copyright (C) 2018 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 android.content;
    ++import android.annotation.IntDef;
    ++import android.annotation.NonNull;
    ++import android.annotation.Nullable;
    ++import android.app.AppOpsManager;
    ++import android.content.pm.PackageManager;
    ++import android.os.Binder;
    ++import android.os.Process;
    ++import java.lang.annotation.Retention;
    ++import java.lang.annotation.RetentionPolicy;
    ++/**
    ++ * This class provides permission check APIs that verify both the
    ++ * permission and the associated app op for this permission if
    ++ * such is defined.
    ++ * <p>
    ++ * In the new permission model permissions with protection level
    ++ * dangerous are runtime permissions. For apps targeting {@link android.os.Build.VERSION_CODES#M}
    ++ * and above the user may not grant such permissions or revoke
    ++ * them at any time. For apps targeting API lower than {@link android.os.Build.VERSION_CODES#M}
    ++ * these permissions are always granted as such apps do not expect
    ++ * permission revocations and would crash. Therefore, when the
    ++ * user disables a permission for a legacy app in the UI the
    ++ * platform disables the APIs guarded by this permission making
    ++ * them a no-op which is doing nothing or returning an empty
    ++ * result or default error.
    ++ * </p>
    ++ * <p>
    ++ * It is important that when you perform an operation on behalf of
    ++ * another app you use these APIs to check for permissions as the
    ++ * app may be a legacy app that does not participate in the new
    ++ * permission model for which the user had disabled the "permission"
    ++ * which is achieved by disallowing the corresponding app op.
    ++ * </p>
    ++ *
    ++ * @hide
    ++ */
    ++public final class PermissionChecker {
    ++    /** Permission result: The permission is granted. */
    ++    public static final int PERMISSION_GRANTED =  PackageManager.PERMISSION_GRANTED;
    ++    /** Permission result: The permission is denied. */
    ++    public static final int PERMISSION_DENIED =  PackageManager.PERMISSION_DENIED;
    ++    /** Permission result: The permission is denied because the app op is not allowed. */
    ++    public static final int PERMISSION_DENIED_APP_OP =  PackageManager.PERMISSION_DENIED  - 1;
    ++    /** @hide */
    ++    @IntDef({PERMISSION_GRANTED,
    ++            PERMISSION_DENIED,
    ++            PERMISSION_DENIED_APP_OP})
    ++    @Retention(RetentionPolicy.SOURCE)
    ++    public @interface PermissionResult {}
    ++    private PermissionChecker() {
    ++        /* do nothing */
    ++    }
    ++    /**
    ++     * Checks whether a given package in a UID and PID has a given permission
    ++     * and whether the app op that corresponds to this permission is allowed.
    ++     *
    ++     * @param context Context for accessing resources.
    ++     * @param permission The permission to check.
    ++     * @param pid The process id for which to check.
    ++     * @param uid The uid for which to check.
    ++     * @param packageName The package name for which to check. If null the
    ++     *     the first package for the calling UID will be used.
    ++     * @return The permission check result which is either {@link #PERMISSION_GRANTED}
    ++     *     or {@link #PERMISSION_DENIED} or {@link #PERMISSION_DENIED_APP_OP}.
    ++     */
    ++    @PermissionResult
    ++    public static int checkPermission(@NonNull Context context, @NonNull String permission,
    ++            int pid, int uid, @Nullable String packageName) {
    ++        if (context.checkPermission(permission, pid, uid) == PackageManager.PERMISSION_DENIED) {
    ++            return PERMISSION_DENIED;
    ++        }
    ++        AppOpsManager appOpsManager = context.getSystemService(AppOpsManager.class);
    ++        String op = appOpsManager.permissionToOp(permission);
    ++        if (op == null) {
    ++            return PERMISSION_GRANTED;
    ++        }
    ++        if (packageName == null) {
    ++            String[] packageNames = context.getPackageManager().getPackagesForUid(uid);
    ++            if (packageNames == null || packageNames.length <= 0) {
    ++                return PERMISSION_DENIED;
    ++            }
    ++            packageName = packageNames[0];
    ++        }
    ++        if (appOpsManager.noteProxyOpNoThrow(op, packageName)
    ++                != AppOpsManager.MODE_ALLOWED) {
    ++            return PERMISSION_DENIED_APP_OP;
    ++        }
    ++        return PERMISSION_GRANTED;
    ++    }
    ++    /**
    ++     * Checks whether your app has a given permission and whether the app op
    ++     * that corresponds to this permission is allowed.
    ++     *
    ++     * @param context Context for accessing resources.
    ++     * @param permission The permission to check.
    ++     * @return The permission check result which is either {@link #PERMISSION_GRANTED}
    ++     *     or {@link #PERMISSION_DENIED} or {@link #PERMISSION_DENIED_APP_OP}.
    ++     */
    ++    @PermissionResult
    ++    public static int checkSelfPermission(@NonNull Context context,
    ++            @NonNull String permission) {
    ++        return checkPermission(context, permission, Process.myPid(),
    ++                Process.myUid(), context.getPackageName());
    ++    }
    ++    /**
    ++     * Checks whether the IPC you are handling has a given permission and whether
    ++     * the app op that corresponds to this permission is allowed.
    ++     *
    ++     * @param context Context for accessing resources.
    ++     * @param permission The permission to check.
    ++     * @param packageName The package name making the IPC. If null the
    ++     *     the first package for the calling UID will be used.
    ++     * @return The permission check result which is either {@link #PERMISSION_GRANTED}
    ++     *     or {@link #PERMISSION_DENIED} or {@link #PERMISSION_DENIED_APP_OP}.
    ++     */
    ++    @PermissionResult
    ++    public static int checkCallingPermission(@NonNull Context context,
    ++            @NonNull String permission, @Nullable String packageName) {
    ++        if (Binder.getCallingPid() == Process.myPid()) {
    ++            return PERMISSION_DENIED;
    ++        }
    ++        return checkPermission(context, permission, Binder.getCallingPid(),
    ++                Binder.getCallingUid(), packageName);
    ++    }
    ++    /**
    ++     * Checks whether the IPC you are handling or your app has a given permission
    ++     * and whether the app op that corresponds to this permission is allowed.
    ++     *
    ++     * @param context Context for accessing resources.
    ++     * @param permission The permission to check.
    ++     * @return The permission check result which is either {@link #PERMISSION_GRANTED}
    ++     *     or {@link #PERMISSION_DENIED} or {@link #PERMISSION_DENIED_APP_OP}.
    ++     */
    ++    @PermissionResult
    ++    public static int checkCallingOrSelfPermission(@NonNull Context context,
    ++            @NonNull String permission) {
    ++        String packageName = (Binder.getCallingPid() == Process.myPid())
    ++                ? context.getPackageName() : null;
    ++        return checkPermission(context, permission, Binder.getCallingPid(),
    ++                Binder.getCallingUid(), packageName);
    ++    }
    ++}
     diff --git a/core/java/android/content/pm/RegisteredServicesCache.java b/core/java/android/content/pm/RegisteredServicesCache.java
     index a110383..aea843a 100644
     --- a/core/java/android/content/pm/RegisteredServicesCache.java
    @@ -181,6 +344,21 @@ index 09af05c..6c069be 100644
                  int portSeparator = authority.indexOf(':', userInfoSeparator);
      
                  if (portSeparator == NOT_FOUND) {
    +diff --git a/core/java/android/provider/MediaStore.java b/core/java/android/provider/MediaStore.java
    +index de19f81..b17657b 100644
    +--- a/core/java/android/provider/MediaStore.java
    ++++ b/core/java/android/provider/MediaStore.java
    +@@ -678,8 +678,8 @@ public final class MediaStore {
    +             // Log.v(TAG, "getThumbnail: origId="+origId+", kind="+kind+", isVideo="+isVideo);
    +             // If the magic is non-zero, we simply return thumbnail if it does exist.
    +             // querying MediaProvider and simply return thumbnail.
    +-            MiniThumbFile thumbFile = new MiniThumbFile(isVideo ? Video.Media.EXTERNAL_CONTENT_URI
    +-                    : Images.Media.EXTERNAL_CONTENT_URI);
    ++            MiniThumbFile thumbFile = MiniThumbFile.instance(
    ++                    isVideo ? Video.Media.EXTERNAL_CONTENT_URI : Images.Media.EXTERNAL_CONTENT_URI);
    +             Cursor c = null;
    +             try {
    +                 long magic = thumbFile.getMagic(origId);
     diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
     index a8209af..4766d33 100755
     --- a/core/java/android/provider/Settings.java
    @@ -211,6 +389,30 @@ index a512957..6ca6d8a 100644
                  }
              }
          }
    +diff --git a/core/java/android/speech/RecognitionService.java b/core/java/android/speech/RecognitionService.java
    +index 674f809..70dfef5 100644
    +--- a/core/java/android/speech/RecognitionService.java
    ++++ b/core/java/android/speech/RecognitionService.java
    +@@ -20,7 +20,7 @@ import android.annotation.SdkConstant;
    + import android.annotation.SdkConstant.SdkConstantType;
    + import android.app.Service;
    + import android.content.Intent;
    +-import android.content.pm.PackageManager;
    ++import android.content.PermissionChecker;
    + import android.os.Binder;
    + import android.os.Bundle;
    + import android.os.Handler;
    +@@ -174,8 +174,8 @@ public abstract class RecognitionService extends Service {
    +      */
    +     private boolean checkPermissions(IRecognitionListener listener) {
    +         if (DBG) Log.d(TAG, "checkPermissions");
    +-        if (RecognitionService.this.checkCallingOrSelfPermission(android.Manifest.permission.
    +-                RECORD_AUDIO) == PackageManager.PERMISSION_GRANTED) {
    ++        if (PermissionChecker.checkCallingOrSelfPermission(this,
    ++                android.Manifest.permission.RECORD_AUDIO) == PermissionChecker.PERMISSION_GRANTED) {
    +             return true;
    +         }
    +         try {
     diff --git a/core/java/android/view/WindowManager.java b/core/java/android/view/WindowManager.java
     index 395f738..169f7e1 100644
     --- a/core/java/android/view/WindowManager.java
    @@ -512,6 +714,44 @@ index 011884c..8403e80 100644
          <!-- @SystemApi Allows an application to manage (create, destroy,
               Z-order) application tokens in the window manager.
               <p>Not for use by third-party applications.
    +diff --git a/core/res/res/values-mcc310-mnc490-fr/strings.xml b/core/res/res/values-mcc310-mnc490-fr/strings.xml
    +deleted file mode 100644
    +index 33e0c97..0000000
    +--- a/core/res/res/values-mcc310-mnc490-fr/strings.xml
    ++++ /dev/null
    +@@ -1,32 +0,0 @@
    +-<?xml version="1.0" encoding="UTF-8"?>
    +-<!-- 
    +-/*
    +-** Copyright 2016, 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 my 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.
    +-*/
    +- -->
    +-
    +-<!--  These resources are around just to allow their values to be customized
    +-     for different hardware and product builds.  -->
    +-
    +-<resources xmlns:android="http://schemas.android.com/apk/res/android"
    +-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
    +-  <string-array name="wfcOperatorErrorAlertMessages">
    +-    <item msgid="2780619740658228275">"Pour passer des appels et envoyer des messages via le Wi-Fi, demandez d\'abord à votre opérateur de configurer ce service. Ensuite, réactivez les appels Wi-Fi dans les paramètres."</item>
    +-  </string-array>
    +-  <string-array name="wfcOperatorErrorNotificationMessages">
    +-    <item msgid="4633656294483906293">"Inscrivez-vous auprès de votre opérateur."</item>
    +-  </string-array>
    +-    <string name="wfcSpnFormat" msgid="1518868466785799436">"Appels Wi-Fi %s"</string>
    +-</resources>
     diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
     index 7baed78..a0fbdac 100644
     --- a/core/res/res/values/config.xml
    @@ -647,6 +887,169 @@ index 2c9c9d9..7c187fb 100644
      }
      
      /**
    +diff --git a/media/java/android/media/MediaScanner.java b/media/java/android/media/MediaScanner.java
    +index 0fafe4b..4c113d9 100644
    +--- a/media/java/android/media/MediaScanner.java
    ++++ b/media/java/android/media/MediaScanner.java
    +@@ -323,7 +323,6 @@ public class MediaScanner implements AutoCloseable {
    +     private final Uri mAudioUri;
    +     private final Uri mVideoUri;
    +     private final Uri mImagesUri;
    +-    private final Uri mThumbsUri;
    +     private final Uri mPlaylistsUri;
    +     private final Uri mFilesUri;
    +     private final Uri mFilesUriNoNotify;
    +@@ -419,7 +418,6 @@ public class MediaScanner implements AutoCloseable {
    +         mAudioUri = Audio.Media.getContentUri(volumeName);
    +         mVideoUri = Video.Media.getContentUri(volumeName);
    +         mImagesUri = Images.Media.getContentUri(volumeName);
    +-        mThumbsUri = Images.Thumbnails.getContentUri(volumeName);
    +         mFilesUri = Files.getContentUri(volumeName);
    +         mFilesUriNoNotify = mFilesUri.buildUpon().appendQueryParameter("nonotify", "1").build();
    + 
    +@@ -1283,53 +1281,6 @@ public class MediaScanner implements AutoCloseable {
    +         }
    +     }
    + 
    +-    private void pruneDeadThumbnailFiles() {
    +-        HashSet<String> existingFiles = new HashSet<String>();
    +-        String directory = "/sdcard/DCIM/.thumbnails";
    +-        String [] files = (new File(directory)).list();
    +-        Cursor c = null;
    +-        if (files == null)
    +-            files = new String[0];
    +-
    +-        for (int i = 0; i < files.length; i++) {
    +-            String fullPathString = directory + "/" + files[i];
    +-            existingFiles.add(fullPathString);
    +-        }
    +-
    +-        try {
    +-            c = mMediaProvider.query(
    +-                    mThumbsUri,
    +-                    new String [] { "_data" },
    +-                    null,
    +-                    null,
    +-                    null, null);
    +-            Log.v(TAG, "pruneDeadThumbnailFiles... " + c);
    +-            if (c != null && c.moveToFirst()) {
    +-                do {
    +-                    String fullPathString = c.getString(0);
    +-                    existingFiles.remove(fullPathString);
    +-                } while (c.moveToNext());
    +-            }
    +-
    +-            for (String fileToDelete : existingFiles) {
    +-                if (false)
    +-                    Log.v(TAG, "fileToDelete is " + fileToDelete);
    +-                try {
    +-                    (new File(fileToDelete)).delete();
    +-                } catch (SecurityException ex) {
    +-                }
    +-            }
    +-
    +-            Log.v(TAG, "/pruneDeadThumbnailFiles... " + c);
    +-        } catch (RemoteException e) {
    +-            // We will soon be killed...
    +-        } finally {
    +-            if (c != null) {
    +-                c.close();
    +-            }
    +-        }
    +-    }
    +-
    +     static class MediaBulkDeleter {
    +         StringBuilder whereClause = new StringBuilder();
    +         ArrayList<String> whereArgs = new ArrayList<String>(100);
    +@@ -1373,9 +1324,6 @@ public class MediaScanner implements AutoCloseable {
    +             processPlayLists();
    +         }
    + 
    +-        if (mOriginalCount == 0 && mImagesUri.equals(Images.Media.getContentUri("external")))
    +-            pruneDeadThumbnailFiles();
    +-
    +         // allow GC to clean up
    +         mPlayLists.clear();
    +     }
    +diff --git a/media/java/android/media/MiniThumbFile.java b/media/java/android/media/MiniThumbFile.java
    +index 664308c..4f9dc68 100644
    +--- a/media/java/android/media/MiniThumbFile.java
    ++++ b/media/java/android/media/MiniThumbFile.java
    +@@ -51,6 +51,7 @@ public class MiniThumbFile {
    +     private RandomAccessFile mMiniThumbFile;
    +     private FileChannel mChannel;
    +     private ByteBuffer mBuffer;
    ++    private ByteBuffer mEmptyBuffer;
    +     private static final Hashtable<String, MiniThumbFile> sThumbFiles =
    +         new Hashtable<String, MiniThumbFile>();
    + 
    +@@ -127,9 +128,10 @@ public class MiniThumbFile {
    +         return mMiniThumbFile;
    +     }
    + 
    +-    public MiniThumbFile(Uri uri) {
    ++    private MiniThumbFile(Uri uri) {
    +         mUri = uri;
    +         mBuffer = ByteBuffer.allocateDirect(BYTES_PER_MINTHUMB);
    ++        mEmptyBuffer = ByteBuffer.allocateDirect(BYTES_PER_MINTHUMB);
    +     }
    + 
    +     public synchronized void deactivate() {
    +@@ -184,6 +186,54 @@ public class MiniThumbFile {
    +         return 0;
    +     }
    + 
    ++    public synchronized void eraseMiniThumb(long id) {
    ++        RandomAccessFile r = miniThumbDataFile();
    ++        if (r != null) {
    ++            long pos = id * BYTES_PER_MINTHUMB;
    ++            FileLock lock = null;
    ++            try {
    ++                mBuffer.clear();
    ++                mBuffer.limit(1 + 8);
    ++
    ++                lock = mChannel.lock(pos, BYTES_PER_MINTHUMB, false);
    ++                // check that we can read the following 9 bytes
    ++                // (1 for the "status" and 8 for the long)
    ++                if (mChannel.read(mBuffer, pos) == 9) {
    ++                    mBuffer.position(0);
    ++                    if (mBuffer.get() == 1) {
    ++                        long currentMagic = mBuffer.getLong();
    ++                        if (currentMagic == 0) {
    ++                            // there is no thumbnail stored here
    ++                            Log.i(TAG, "no thumbnail for id " + id);
    ++                            return;
    ++                        }
    ++                        // zero out the thumbnail slot
    ++                        // Log.v(TAG, "clearing slot " + id + ", magic " + currentMagic
    ++                        //         + " at offset " + pos);
    ++                        mChannel.write(mEmptyBuffer, pos);
    ++                    }
    ++                } else {
    ++                    // Log.v(TAG, "No slot");
    ++                }
    ++            } catch (IOException ex) {
    ++                Log.v(TAG, "Got exception checking file magic: ", ex);
    ++            } catch (RuntimeException ex) {
    ++                // Other NIO related exception like disk full, read only channel..etc
    ++                Log.e(TAG, "Got exception when reading magic, id = " + id +
    ++                        ", disk full or mount read-only? " + ex.getClass());
    ++            } finally {
    ++                try {
    ++                    if (lock != null) lock.release();
    ++                }
    ++                catch (IOException ex) {
    ++                    // ignore it.
    ++                }
    ++            }
    ++        } else {
    ++            // Log.v(TAG, "No data file");
    ++        }
    ++    }
    ++
    +     public synchronized void saveMiniThumbToFile(byte[] data, long id, long magic)
    +             throws IOException {
    +         RandomAccessFile r = miniThumbDataFile();
     diff --git a/media/jni/android_media_ExifInterface.cpp b/media/jni/android_media_ExifInterface.cpp
     index 731deae..20f9ef6 100644
     --- a/media/jni/android_media_ExifInterface.cpp
    diff --git a/frameworks_native.patch b/frameworks_native.patch
    index a5e2a4b..2f6d1ce 100644
    --- a/frameworks_native.patch
    +++ b/frameworks_native.patch
    @@ -1,3 +1,29 @@
    +diff --git a/build/phone-xhdpi-1024-dalvik-heap.mk b/build/phone-xhdpi-1024-dalvik-heap.mk
    +index 221227d..5707b1d 100644
    +--- a/build/phone-xhdpi-1024-dalvik-heap.mk
    ++++ b/build/phone-xhdpi-1024-dalvik-heap.mk
    +@@ -18,7 +18,7 @@
    + 
    + PRODUCT_PROPERTY_OVERRIDES += \
    +     dalvik.vm.heapstartsize=8m \
    +-    dalvik.vm.heapgrowthlimit=96m \
    ++    dalvik.vm.heapgrowthlimit=192m \
    +     dalvik.vm.heapsize=256m \
    +     dalvik.vm.heaptargetutilization=0.75 \
    +     dalvik.vm.heapminfree=512k \
    +diff --git a/build/tablet-7in-hdpi-1024-dalvik-heap.mk b/build/tablet-7in-hdpi-1024-dalvik-heap.mk
    +index 7fd34b5..e61c40b 100644
    +--- a/build/tablet-7in-hdpi-1024-dalvik-heap.mk
    ++++ b/build/tablet-7in-hdpi-1024-dalvik-heap.mk
    +@@ -18,7 +18,7 @@
    + 
    + PRODUCT_PROPERTY_OVERRIDES += \
    +     dalvik.vm.heapstartsize=8m \
    +-    dalvik.vm.heapgrowthlimit=80m \
    ++    dalvik.vm.heapgrowthlimit=192m \
    +     dalvik.vm.heapsize=384m \
    +     dalvik.vm.heaptargetutilization=0.75 \
    +     dalvik.vm.heapminfree=512k \
     diff --git a/cmds/atrace/atrace.cpp b/cmds/atrace/atrace.cpp
     index 5885738..86c315c 100644
     --- a/cmds/atrace/atrace.cpp
    @@ -859,10 +885,20 @@ index ee152bf..9c82295 100644
          result.mStorage.clear();
          for (size_t r = 0; r < numRects; ++r) {
     diff --git a/opengl/libs/Android.mk b/opengl/libs/Android.mk
    -index 24e4c19..ffd0dbc 100644
    +index 24e4c19..f56a346 100644
     --- a/opengl/libs/Android.mk
     +++ b/opengl/libs/Android.mk
    -@@ -77,7 +77,6 @@ LOCAL_SRC_FILES:= 		\
    +@@ -42,6 +42,9 @@ LOCAL_CFLAGS += -DLOG_TAG=\"libEGL\"
    + LOCAL_CFLAGS += -DGL_GLEXT_PROTOTYPES -DEGL_EGLEXT_PROTOTYPES
    + LOCAL_CFLAGS += -fvisibility=hidden
    + 
    ++ifeq ($(NV_ANDROID_FRAMEWORK_ENHANCEMENTS),TRUE)
    ++  LOCAL_CFLAGS += -DNV_ANDROID_FRAMEWORK_ENHANCEMENTS
    ++endif
    + ifeq ($(BOARD_ALLOW_EGL_HIBERNATION),true)
    +   LOCAL_CFLAGS += -DBOARD_ALLOW_EGL_HIBERNATION
    + endif
    +@@ -77,7 +80,6 @@ LOCAL_SRC_FILES:= 		\
      	GLES_CM/gl.cpp.arm 	\
      #
      
    @@ -870,7 +906,7 @@ index 24e4c19..ffd0dbc 100644
      LOCAL_SHARED_LIBRARIES += libcutils liblog libEGL
      LOCAL_MODULE:= libGLESv1_CM
      
    -@@ -105,7 +104,6 @@ LOCAL_SRC_FILES:= \
    +@@ -105,7 +107,6 @@ LOCAL_SRC_FILES:= \
      	GLES2/gl2.cpp   \
      #
      
    @@ -878,7 +914,7 @@ index 24e4c19..ffd0dbc 100644
      LOCAL_ARM_MODE := arm
      LOCAL_SHARED_LIBRARIES += libcutils libutils liblog libEGL
      LOCAL_MODULE:= libGLESv2
    -@@ -133,7 +131,6 @@ LOCAL_SRC_FILES:= \
    +@@ -133,7 +134,6 @@ LOCAL_SRC_FILES:= \
      	GLES2/gl2.cpp   \
      #
      
    @@ -886,6 +922,206 @@ index 24e4c19..ffd0dbc 100644
      LOCAL_ARM_MODE := arm
      LOCAL_SHARED_LIBRARIES += libcutils libutils liblog libEGL
      LOCAL_MODULE:= libGLESv3
    +diff --git a/opengl/libs/EGL/egl_object.cpp b/opengl/libs/EGL/egl_object.cpp
    +index cfecf77..4d9f77f 100644
    +--- a/opengl/libs/EGL/egl_object.cpp
    ++++ b/opengl/libs/EGL/egl_object.cpp
    +@@ -124,19 +124,25 @@ void egl_context_t::onMakeCurrent(EGLSurface draw, EGLSurface read) {
    +     if (gl_extensions.isEmpty()) {
    +         // call the implementation's glGetString(GL_EXTENSIONS)
    +         const char* exts = (const char *)gEGLImpl.hooks[version]->gl.glGetString(GL_EXTENSIONS);
    +-        gl_extensions.setTo(exts);
    +-        if (gl_extensions.find("GL_EXT_debug_marker") < 0) {
    +-            String8 temp("GL_EXT_debug_marker ");
    +-            temp.append(gl_extensions);
    +-            gl_extensions.setTo(temp);
    +-        }
    + 
    +-        // tokenize the supported extensions for the glGetStringi() wrapper
    +-        std::stringstream ss;
    +-        std::string str;
    +-        ss << gl_extensions.string();
    +-        while (ss >> str) {
    +-            tokenized_gl_extensions.push(String8(str.c_str()));
    ++        // If this context is sharing with another context, and the other context was reset
    ++        // e.g. due to robustness failure, this context might also be reset and glGetString can
    ++        // return NULL.
    ++        if (exts) {
    ++            gl_extensions.setTo(exts);
    ++            if (gl_extensions.find("GL_EXT_debug_marker") < 0) {
    ++                String8 temp("GL_EXT_debug_marker ");
    ++                temp.append(gl_extensions);
    ++                gl_extensions.setTo(temp);
    ++            }
    ++
    ++            // tokenize the supported extensions for the glGetStringi() wrapper
    ++            std::stringstream ss;
    ++            std::string str;
    ++            ss << gl_extensions.string();
    ++            while (ss >> str) {
    ++                tokenized_gl_extensions.push(String8(str.c_str()));
    ++            }
    +         }
    +     }
    + }
    +diff --git a/opengl/libs/EGL/getProcAddress.cpp b/opengl/libs/EGL/getProcAddress.cpp
    +index 336c264..bb72e79 100644
    +--- a/opengl/libs/EGL/getProcAddress.cpp
    ++++ b/opengl/libs/EGL/getProcAddress.cpp
    +@@ -40,6 +40,27 @@ namespace android {
    + 
    +     #define API_ENTRY(_api) __attribute__((naked)) _api
    + 
    ++#ifdef NV_ANDROID_FRAMEWORK_ENHANCEMENTS
    ++    #define CALL_GL_EXTENSION_API(_api)                         \
    ++         asm volatile(                                          \
    ++            GET_TLS(r12)                                        \
    ++            "ldr   r12, [r12, %[tls]] \n"                       \
    ++            "cmp   r12, #0            \n"                       \
    ++            "addne r12, %[api]        \n"                       \
    ++            "addne r12, %[spl]        \n"                       \
    ++            "ldrne r12, [r12, %[ext]] \n"                       \
    ++            "cmpne r12, #0            \n"                       \
    ++            "bxne  r12                \n"                       \
    ++            "bx    lr                 \n"                       \
    ++            :                                                   \
    ++            : [tls] "J"(TLS_SLOT_OPENGL_API*4),                 \
    ++              [ext] "J"(__builtin_offsetof(gl_hooks_t,          \
    ++                                      ext.extensions[0])),      \
    ++              [api] "J"(((_api*sizeof(void*))/1024)*1024),      \
    ++              [spl] "J"((_api*sizeof(void*))%1024)              \
    ++            : "r12"                                             \
    ++            );
    ++#else
    +     #define CALL_GL_EXTENSION_API(_api)                         \
    +          asm volatile(                                          \
    +             GET_TLS(r12)                                        \
    +@@ -57,6 +78,7 @@ namespace android {
    +               [api] "J"(_api*sizeof(void*))                     \
    +             : "r12"                                             \
    +             );
    ++#endif
    + 
    + #elif defined(__aarch64__)
    + 
    +@@ -205,6 +227,109 @@ namespace android {
    + #endif
    + 
    + 
    ++#ifdef NV_ANDROID_FRAMEWORK_ENHANCEMENTS
    ++#define GL_EXTENSION_LIST(name) \
    ++    name(0)   name(1)   name(2)   name(3)   name(4)   name(5)   name(6)   name(7)  \
    ++    name(8)   name(9)   name(10)  name(11)  name(12)  name(13)  name(14)  name(15) \
    ++    name(16)  name(17)  name(18)  name(19)  name(20)  name(21)  name(22)  name(23) \
    ++    name(24)  name(25)  name(26)  name(27)  name(28)  name(29)  name(30)  name(31) \
    ++    name(32)  name(33)  name(34)  name(35)  name(36)  name(37)  name(38)  name(39) \
    ++    name(40)  name(41)  name(42)  name(43)  name(44)  name(45)  name(46)  name(47) \
    ++    name(48)  name(49)  name(50)  name(51)  name(52)  name(53)  name(54)  name(55) \
    ++    name(56)  name(57)  name(58)  name(59)  name(60)  name(61)  name(62)  name(63) \
    ++    name(64)  name(65)  name(66)  name(67)  name(68)  name(69)  name(70)  name(71) \
    ++    name(72)  name(73)  name(74)  name(75)  name(76)  name(77)  name(78)  name(79) \
    ++    name(80)  name(81)  name(82)  name(83)  name(84)  name(85)  name(86)  name(87) \
    ++    name(88)  name(89)  name(90)  name(91)  name(92)  name(93)  name(94)  name(95) \
    ++    name(96)  name(97)  name(98)  name(99)  \
    ++    name(100) name(101) name(102) name(103) name(104) name(105) name(106) name(107) \
    ++    name(108) name(109) name(110) name(111) name(112) name(113) name(114) name(115) \
    ++    name(116) name(117) name(118) name(119) name(120) name(121) name(122) name(123) \
    ++    name(124) name(125) name(126) name(127) name(128) name(129) name(130) name(131) \
    ++    name(132) name(133) name(134) name(135) name(136) name(137) name(138) name(139) \
    ++    name(140) name(141) name(142) name(143) name(144) name(145) name(146) name(147) \
    ++    name(148) name(149) name(150) name(151) name(152) name(153) name(154) name(155) \
    ++    name(156) name(157) name(158) name(159) name(160) name(161) name(162) name(163) \
    ++    name(164) name(165) name(166) name(167) name(168) name(169) name(170) name(171) \
    ++    name(172) name(173) name(174) name(175) name(176) name(177) name(178) name(179) \
    ++    name(180) name(181) name(182) name(183) name(184) name(185) name(186) name(187) \
    ++    name(188) name(189) name(190) name(191) name(192) name(193) name(194) name(195) \
    ++    name(196) name(197) name(198) name(199) \
    ++    name(200) name(201) name(202) name(203) name(204) name(205) name(206) name(207) \
    ++    name(208) name(209) name(210) name(211) name(212) name(213) name(214) name(215) \
    ++    name(216) name(217) name(218) name(219) name(220) name(221) name(222) name(223) \
    ++    name(224) name(225) name(226) name(227) name(228) name(229) name(230) name(231) \
    ++    name(232) name(233) name(234) name(235) name(236) name(237) name(238) name(239) \
    ++    name(240) name(241) name(242) name(243) name(244) name(245) name(246) name(247) \
    ++    name(248) name(249) name(250) name(251) name(252) name(253) name(254) name(255) \
    ++    name(256) name(257) name(258) name(259) name(260) name(261) name(262) name(263) \
    ++    name(264) name(265) name(266) name(267) name(268) name(269) name(270) name(271) \
    ++    name(272) name(273) name(274) name(275) name(276) name(277) name(278) name(279) \
    ++    name(280) name(281) name(282) name(283) name(284) name(285) name(286) name(287) \
    ++    name(288) name(289) name(290) name(291) name(292) name(293) name(294) name(295) \
    ++    name(296) name(297) name(298) name(299) \
    ++    name(300) name(301) name(302) name(303) name(304) name(305) name(306) name(307) \
    ++    name(308) name(309) name(310) name(311) name(312) name(313) name(314) name(315) \
    ++    name(316) name(317) name(318) name(319) name(320) name(321) name(322) name(323) \
    ++    name(324) name(325) name(326) name(327) name(328) name(329) name(330) name(331) \
    ++    name(332) name(333) name(334) name(335) name(336) name(337) name(338) name(339) \
    ++    name(340) name(341) name(342) name(343) name(344) name(345) name(346) name(347) \
    ++    name(348) name(349) name(350) name(351) name(352) name(353) name(354) name(355) \
    ++    name(356) name(357) name(358) name(359) name(360) name(361) name(362) name(363) \
    ++    name(364) name(365) name(366) name(367) name(368) name(369) name(370) name(371) \
    ++    name(372) name(373) name(374) name(375) name(376) name(377) name(378) name(379) \
    ++    name(380) name(381) name(382) name(383) name(384) name(385) name(386) name(387) \
    ++    name(388) name(389) name(390) name(391) name(392) name(393) name(394) name(395) \
    ++    name(396) name(397) name(398) name(399) \
    ++    name(400) name(401) name(402) name(403) name(404) name(405) name(406) name(407) \
    ++    name(408) name(409) name(410) name(411) name(412) name(413) name(414) name(415) \
    ++    name(416) name(417) name(418) name(419) name(420) name(421) name(422) name(423) \
    ++    name(424) name(425) name(426) name(427) name(428) name(429) name(430) name(431) \
    ++    name(432) name(433) name(434) name(435) name(436) name(437) name(438) name(439) \
    ++    name(440) name(441) name(442) name(443) name(444) name(445) name(446) name(447) \
    ++    name(448) name(449) name(450) name(451) name(452) name(453) name(454) name(455) \
    ++    name(456) name(457) name(458) name(459) name(460) name(461) name(462) name(463) \
    ++    name(464) name(465) name(466) name(467) name(468) name(469) name(470) name(471) \
    ++    name(472) name(473) name(474) name(475) name(476) name(477) name(478) name(479) \
    ++    name(480) name(481) name(482) name(483) name(484) name(485) name(486) name(487) \
    ++    name(488) name(489) name(490) name(491) name(492) name(493) name(494) name(495) \
    ++    name(496) name(497) name(498) name(499) \
    ++    name(500) name(501) name(502) name(503) name(504) name(505) name(506) name(507) \
    ++    name(508) name(509) name(510) name(511) name(512) name(513) name(514) name(515) \
    ++    name(516) name(517) name(518) name(519) name(520) name(521) name(522) name(523) \
    ++    name(524) name(525) name(526) name(527) name(528) name(529) name(530) name(531) \
    ++    name(532) name(533) name(534) name(535) name(536) name(537) name(538) name(539) \
    ++    name(540) name(541) name(542) name(543) name(544) name(545) name(546) name(547) \
    ++    name(548) name(549) name(550) name(551) name(552) name(553) name(554) name(555) \
    ++    name(556) name(557) name(558) name(559) name(560) name(561) name(562) name(563) \
    ++    name(564) name(565) name(566) name(567) name(568) name(569) name(570) name(571) \
    ++    name(572) name(573) name(574) name(575) name(576) name(577) name(578) name(579) \
    ++    name(580) name(581) name(582) name(583) name(584) name(585) name(586) name(587) \
    ++    name(588) name(589) name(590) name(591) name(592) name(593) name(594) name(595) \
    ++    name(596) name(597) name(598) name(599) \
    ++    name(600) name(601) name(602) name(603) name(604) name(605) name(606) name(607) \
    ++    name(608) name(609) name(610) name(611) name(612) name(613) name(614) name(615) \
    ++    name(616) name(617) name(618) name(619) name(620) name(621) name(622) name(623) \
    ++    name(624) name(625) name(626) name(627) name(628) name(629) name(630) name(631) \
    ++    name(632) name(633) name(634) name(635) name(636) name(637) name(638) name(639) \
    ++    name(640) name(641) name(642) name(643) name(644) name(645) name(646) name(647) \
    ++    name(648) name(649) name(650) name(651) name(652) name(653) name(654) name(655) \
    ++    name(656) name(657) name(658) name(659) name(660) name(661) name(662) name(663) \
    ++    name(664) name(665) name(666) name(667) name(668) name(669) name(670) name(671) \
    ++    name(672) name(673) name(674) name(675) name(676) name(677) name(678) name(679) \
    ++    name(680) name(681) name(682) name(683) name(684) name(685) name(686) name(687) \
    ++    name(688) name(689) name(690) name(691) name(692) name(693) name(694) name(695) \
    ++    name(696) name(697) name(698) name(699) \
    ++    name(700) name(701) name(702) name(703) name(704) name(705) name(706) name(707) \
    ++    name(708) name(709) name(710) name(711) name(712) name(713) name(714) name(715) \
    ++    name(716) name(717) name(718) name(719) name(720) name(721) name(722) name(723) \
    ++    name(724) name(725) name(726) name(727) name(728) name(729) name(730) name(731) \
    ++    name(732) name(733) name(734) name(735) name(736) name(737) name(738) name(739) \
    ++    name(740) name(741) name(742) name(743) name(744) name(745) name(746) name(747) \
    ++    name(748) name(749) name(750) name(751) name(752) name(753) name(754) name(755) \
    ++    name(756) name(757) name(758) name(759) name(760) name(761) name(762) name(763) \
    ++    name(764) name(765) name(766) name(767)
    ++#else
    + #define GL_EXTENSION_LIST(name) \
    +     name(0)   name(1)   name(2)   name(3)   name(4)   name(5)   name(6)   name(7)  \
    +     name(8)   name(9)   name(10)  name(11)  name(12)  name(13)  name(14)  name(15) \
    +@@ -239,6 +364,7 @@ namespace android {
    +     name(232) name(233) name(234) name(235) name(236) name(237) name(238) name(239) \
    +     name(240) name(241) name(242) name(243) name(244) name(245) name(246) name(247) \
    +     name(248) name(249) name(250) name(251) name(252) name(253) name(254) name(255)
    ++#endif
    + 
    + 
    + GL_EXTENSION_LIST( GL_EXTENSION )
     diff --git a/opengl/libs/GLES2/gl2.cpp b/opengl/libs/GLES2/gl2.cpp
     index 6034a8e..6dd87c2 100644
     --- a/opengl/libs/GLES2/gl2.cpp
    @@ -1575,6 +1811,43 @@ index b1b31f8..8bde4e5 100644
      #undef CALL_GL_API_RETURN
      
      /*
    +diff --git a/opengl/libs/hooks.h b/opengl/libs/hooks.h
    +index e14075c..18b1b76 100644
    +--- a/opengl/libs/hooks.h
    ++++ b/opengl/libs/hooks.h
    +@@ -43,7 +43,11 @@
    + // a given process. this limitation exists because we need to have
    + // a static function for each extension and currently these static functions
    + // are generated at compile time.
    ++#ifdef NV_ANDROID_FRAMEWORK_ENHANCEMENTS
    ++#define MAX_NUMBER_OF_GL_EXTENSIONS 768
    ++#else
    + #define MAX_NUMBER_OF_GL_EXTENSIONS 256
    ++#endif
    + 
    + 
    + #include <bionic_tls.h>  /* special private C library header */
    +diff --git a/services/inputflinger/InputDispatcher.cpp b/services/inputflinger/InputDispatcher.cpp
    +index 3f69d49..e48c53a 100644
    +--- a/services/inputflinger/InputDispatcher.cpp
    ++++ b/services/inputflinger/InputDispatcher.cpp
    +@@ -1224,15 +1224,8 @@ int32_t InputDispatcher::findTouchedWindowTargetsLocked(nsecs_t currentTime,
    + 
    +                 if (maskedAction == AMOTION_EVENT_ACTION_DOWN
    +                         && (flags & InputWindowInfo::FLAG_WATCH_OUTSIDE_TOUCH)) {
    +-                    int32_t outsideTargetFlags = InputTarget::FLAG_DISPATCH_AS_OUTSIDE;
    +-                    if (isWindowObscuredAtPointLocked(windowHandle, x, y)) {
    +-                        outsideTargetFlags |= InputTarget::FLAG_WINDOW_IS_OBSCURED;
    +-                    } else if (isWindowObscuredLocked(windowHandle)) {
    +-                        outsideTargetFlags |= InputTarget::FLAG_WINDOW_IS_PARTIALLY_OBSCURED;
    +-                    }
    +-
    +                     mTempTouchState.addOrUpdateWindow(
    +-                            windowHandle, outsideTargetFlags, BitSet32(0));
    ++                            windowHandle, InputTarget::FLAG_DISPATCH_AS_OUTSIDE, BitSet32(0));
    +                 }
    +             }
    +         }
     diff --git a/services/inputflinger/InputReader.cpp b/services/inputflinger/InputReader.cpp
     index b9be675..eff3deb 100644
     --- a/services/inputflinger/InputReader.cpp
    @@ -2228,7 +2501,7 @@ index 8e7e577..a04684c 100644
                                  uint32_t* pixels = new uint32_t[reqWidth*reqHeight];
                                  getRenderEngine().readPixels(0, 0, reqWidth, reqHeight, pixels);
     diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
    -index b98924b..2c3bd19 100644
    +index b98924b..f23ba41 100644
     --- a/services/surfaceflinger/SurfaceFlinger.h
     +++ b/services/surfaceflinger/SurfaceFlinger.h
     @@ -218,7 +218,8 @@ private:
    @@ -2250,6 +2523,16 @@ index b98924b..2c3bd19 100644
      
          /* ------------------------------------------------------------------------
           * EGL
    +@@ -545,6 +546,9 @@ private:
    +     bool mPrimaryHWVsyncEnabled;
    +     bool mHWVsyncAvailable;
    + 
    ++    // Panel hardware rotation
    ++    int32_t mHardwareRotation;
    ++
    +     /* ------------------------------------------------------------------------
    +      * Feature prototyping
    +      */
     diff --git a/services/surfaceflinger/SurfaceFlingerConsumer.cpp b/services/surfaceflinger/SurfaceFlingerConsumer.cpp
     index e0e4c61..6f2520b 100644
     --- a/services/surfaceflinger/SurfaceFlingerConsumer.cpp
    @@ -2285,10 +2568,21 @@ index e0e4c61..6f2520b 100644
      #ifdef USE_HWC2
          err = updateAndReleaseLocked(item, &mPendingRelease);
     diff --git a/services/surfaceflinger/SurfaceFlinger_hwc1.cpp b/services/surfaceflinger/SurfaceFlinger_hwc1.cpp
    -index b32f652..512f63d 100644
    +index b32f652..b5b9697 100644
     --- a/services/surfaceflinger/SurfaceFlinger_hwc1.cpp
     +++ b/services/surfaceflinger/SurfaceFlinger_hwc1.cpp
    -@@ -457,19 +457,28 @@ void SurfaceFlinger::init() {
    +@@ -185,6 +185,10 @@ SurfaceFlinger::SurfaceFlinger()
    +     property_get("debug.sf.disable_hwc_vds", value, "0");
    +     mUseHwcVirtualDisplays = !atoi(value);
    +     ALOGI_IF(!mUseHwcVirtualDisplays, "Disabling HWC virtual displays");
    ++
    ++    // we store the value as orientation:
    ++    // 90 -> 1, 180 -> 2, 270 -> 3
    ++    mHardwareRotation = property_get_int32("ro.sf.hwrotation", 0) / 90;
    + }
    + 
    + void SurfaceFlinger::onFirstRef()
    +@@ -457,19 +461,28 @@ void SurfaceFlinger::init() {
          eglInitialize(mEGLDisplay, NULL, NULL);
      
          // start the EventThread
    @@ -2328,7 +2622,7 @@ index b32f652..512f63d 100644
          }
      
      
    -@@ -635,10 +644,21 @@ status_t SurfaceFlinger::getDisplayConfigs(const sp<IBinder>& display,
    +@@ -635,10 +648,18 @@ status_t SurfaceFlinger::getDisplayConfigs(const sp<IBinder>& display,
                  info.orientation = 0;
              }
      
    @@ -2336,16 +2630,13 @@ index b32f652..512f63d 100644
     -        info.h = hwConfig.height;
     -        info.xdpi = xdpi;
     -        info.ydpi = ydpi;
    -+        char value[PROPERTY_VALUE_MAX];
    -+        property_get("ro.sf.hwrotation", value, "0");
    -+        int additionalRot = atoi(value) / 90;
    -+        if ((type == DisplayDevice::DISPLAY_PRIMARY) && (additionalRot & DisplayState::eOrientationSwapMask)) {
    ++        if ((type == DisplayDevice::DISPLAY_PRIMARY) &&
    ++                (mHardwareRotation & DisplayState::eOrientationSwapMask)) {
     +            info.h = hwConfig.width;
     +            info.w = hwConfig.height;
     +            info.xdpi = ydpi;
     +            info.ydpi = xdpi;
    -+        }
    -+        else {
    ++        } else {
     +            info.w = hwConfig.width;
     +            info.h = hwConfig.height;
     +            info.xdpi = xdpi;
    @@ -2354,7 +2645,7 @@ index b32f652..512f63d 100644
              info.fps = float(1e9 / hwConfig.refresh);
              info.appVsyncOffset = VSYNC_EVENT_PHASE_OFFSET_NS;
      
    -@@ -3186,12 +3206,14 @@ status_t SurfaceFlinger::onTransact(
    +@@ -3186,12 +3207,14 @@ status_t SurfaceFlinger::onTransact(
                  }
                  case 1018: { // Modify Choreographer's phase offset
                      n = data.readInt32();
    @@ -2371,7 +2662,7 @@ index b32f652..512f63d 100644
                      return NO_ERROR;
                  }
                  case 1021: { // Disable HWC virtual displays
    -@@ -3330,7 +3352,8 @@ status_t SurfaceFlinger::captureScreen(const sp<IBinder>& display,
    +@@ -3330,7 +3353,8 @@ status_t SurfaceFlinger::captureScreen(const sp<IBinder>& display,
              const sp<IGraphicBufferProducer>& producer,
              Rect sourceCrop, uint32_t reqWidth, uint32_t reqHeight,
              uint32_t minLayerZ, uint32_t maxLayerZ,
    @@ -2381,7 +2672,7 @@ index b32f652..512f63d 100644
      
          if (CC_UNLIKELY(display == 0))
              return BAD_VALUE;
    -@@ -3374,6 +3397,7 @@ status_t SurfaceFlinger::captureScreen(const sp<IBinder>& display,
    +@@ -3374,6 +3398,7 @@ status_t SurfaceFlinger::captureScreen(const sp<IBinder>& display,
              bool useIdentityTransform;
              Transform::orientation_flags rotation;
              status_t result;
    @@ -2389,7 +2680,7 @@ index b32f652..512f63d 100644
              bool isLocalScreenshot;
          public:
              MessageCaptureScreen(SurfaceFlinger* flinger,
    -@@ -3383,12 +3407,13 @@ status_t SurfaceFlinger::captureScreen(const sp<IBinder>& display,
    +@@ -3383,12 +3408,13 @@ status_t SurfaceFlinger::captureScreen(const sp<IBinder>& display,
                      uint32_t minLayerZ, uint32_t maxLayerZ,
                      bool useIdentityTransform,
                      Transform::orientation_flags rotation,
    @@ -2404,7 +2695,7 @@ index b32f652..512f63d 100644
                    isLocalScreenshot(isLocalScreenshot)
              {
              }
    -@@ -3398,9 +3423,10 @@ status_t SurfaceFlinger::captureScreen(const sp<IBinder>& display,
    +@@ -3398,9 +3424,10 @@ status_t SurfaceFlinger::captureScreen(const sp<IBinder>& display,
              virtual bool handler() {
                  Mutex::Autolock _l(flinger->mStateLock);
                  sp<const DisplayDevice> hw(flinger->getDisplayDevice(display));
    @@ -2416,7 +2707,7 @@ index b32f652..512f63d 100644
                  static_cast<GraphicProducerWrapper*>(IInterface::asBinder(producer).get())->exit(result);
                  return true;
              }
    -@@ -3416,7 +3442,7 @@ status_t SurfaceFlinger::captureScreen(const sp<IBinder>& display,
    +@@ -3416,7 +3443,7 @@ status_t SurfaceFlinger::captureScreen(const sp<IBinder>& display,
          sp<MessageBase> msg = new MessageCaptureScreen(this,
                  display, IGraphicBufferProducer::asInterface( wrapper ),
                  sourceCrop, reqWidth, reqHeight, minLayerZ, maxLayerZ,
    @@ -2425,7 +2716,7 @@ index b32f652..512f63d 100644
      
          status_t res = postMessageAsync(msg);
          if (res == NO_ERROR) {
    -@@ -3501,7 +3527,7 @@ status_t SurfaceFlinger::captureScreenImplLocked(
    +@@ -3501,7 +3528,7 @@ status_t SurfaceFlinger::captureScreenImplLocked(
              Rect sourceCrop, uint32_t reqWidth, uint32_t reqHeight,
              uint32_t minLayerZ, uint32_t maxLayerZ,
              bool useIdentityTransform, Transform::orientation_flags rotation,
    @@ -2434,7 +2725,7 @@ index b32f652..512f63d 100644
      {
          ATRACE_CALL();
      
    -@@ -3571,7 +3597,7 @@ status_t SurfaceFlinger::captureScreenImplLocked(
    +@@ -3571,7 +3598,7 @@ status_t SurfaceFlinger::captureScreenImplLocked(
                      if (image != EGL_NO_IMAGE_KHR) {
                          // this binds the given EGLImage as a framebuffer for the
                          // duration of this scope.
    @@ -2443,7 +2734,7 @@ index b32f652..512f63d 100644
                          if (imageBond.getStatus() == NO_ERROR) {
                              // this will in fact render into our dequeued buffer
                              // via an FBO, which means we didn't have to create
    -@@ -3618,6 +3644,16 @@ status_t SurfaceFlinger::captureScreenImplLocked(
    +@@ -3618,6 +3645,16 @@ status_t SurfaceFlinger::captureScreenImplLocked(
                                      ALOGW("captureScreen: error creating EGL fence: %#x", eglGetError());
                                  }
                              }
    diff --git a/system_bt.patch b/system_bt.patch
    index 7173339..c22a42a 100644
    --- a/system_bt.patch
    +++ b/system_bt.patch
    @@ -1,3 +1,63 @@
    +diff --git a/bta/dm/bta_dm_act.c b/bta/dm/bta_dm_act.c
    +index 1bf741d..a8d92e0 100644
    +--- a/bta/dm/bta_dm_act.c
    ++++ b/bta/dm/bta_dm_act.c
    +@@ -26,6 +26,7 @@
    + #define LOG_TAG "bt_bta_dm"
    + 
    + #include <assert.h>
    ++#include <cutils/log.h>
    + #include <string.h>
    + 
    + #include "bt_target.h"
    +@@ -49,6 +50,8 @@
    + #include "gap_api.h"
    + #endif
    + 
    ++#define BTA_MAX_SERVICES 32
    ++
    + static void bta_dm_inq_results_cb (tBTM_INQ_RESULTS *p_inq, UINT8 *p_eir);
    + static void bta_dm_inq_cmpl_cb (void * p_result);
    + static void bta_dm_service_search_remname_cback (BD_ADDR bd_addr, DEV_CLASS dc, BD_NAME bd_name);
    +@@ -1601,7 +1604,7 @@ void bta_dm_sdp_result (tBTA_DM_MSG *p_data)
    + #endif
    + 
    +     UINT32 num_uuids = 0;
    +-    UINT8  uuid_list[32][MAX_UUID_SIZE]; // assuming a max of 32 services
    ++    UINT8  uuid_list[BTA_MAX_SERVICES][MAX_UUID_SIZE]; // assuming a max of 32 services
    + 
    +     if((p_data->sdp_event.sdp_result == SDP_SUCCESS)
    +         || (p_data->sdp_event.sdp_result == SDP_NO_RECS_MATCH)
    +@@ -1679,8 +1682,12 @@ void bta_dm_sdp_result (tBTA_DM_MSG *p_data)
    +                             (tBTA_SERVICE_MASK)(BTA_SERVICE_ID_TO_SERVICE_MASK(bta_dm_search_cb.service_index-1));
    +                         tmp_svc = bta_service_id_to_uuid_lkup_tbl[bta_dm_search_cb.service_index-1];
    +                         /* Add to the list of UUIDs */
    +-                        sdpu_uuid16_to_uuid128(tmp_svc, uuid_list[num_uuids]);
    +-                        num_uuids++;
    ++                        if (num_uuids < BTA_MAX_SERVICES) {
    ++                          sdpu_uuid16_to_uuid128(tmp_svc, uuid_list[num_uuids]);
    ++                          num_uuids++;
    ++                        } else {
    ++                          android_errorWriteLog(0x534e4554, "74016921");
    ++                        }
    +                     }
    +                 }
    +             }
    +@@ -1719,8 +1726,12 @@ void bta_dm_sdp_result (tBTA_DM_MSG *p_data)
    +                 {
    +                     if (SDP_FindServiceUUIDInRec_128bit(p_sdp_rec, &temp_uuid))
    +                     {
    +-                        memcpy(uuid_list[num_uuids], temp_uuid.uu.uuid128, MAX_UUID_SIZE);
    +-                        num_uuids++;
    ++                        if (num_uuids < BTA_MAX_SERVICES) {
    ++                          memcpy(uuid_list[num_uuids], temp_uuid.uu.uuid128, MAX_UUID_SIZE);
    ++                          num_uuids++;
    ++                        } else {
    ++                          android_errorWriteLog(0x534e4554, "74016921");
    ++                        }
    +                     }
    +                 }
    +             } while (p_sdp_rec);
     diff --git a/bta/gatt/bta_gattc_cache.c b/bta/gatt/bta_gattc_cache.c
     index 63c4246..45d2588 100644
     --- a/bta/gatt/bta_gattc_cache.c
    @@ -12,7 +72,7 @@ index 63c4246..45d2588 100644
              goto done;
          }
     diff --git a/bta/pan/bta_pan_act.c b/bta/pan/bta_pan_act.c
    -index 1995478..82095fb 100644
    +index 1995478..4367fce 100644
     --- a/bta/pan/bta_pan_act.c
     +++ b/bta/pan/bta_pan_act.c
     @@ -26,6 +26,8 @@
    @@ -24,34 +84,46 @@ index 1995478..82095fb 100644
      #include "bta_api.h"
      #include "bta_sys.h"
      #include "bt_common.h"
    -@@ -174,14 +176,25 @@ static void bta_pan_data_buf_ind_cback(UINT16 handle, BD_ADDR src, BD_ADDR dst,
    -     tBTA_PAN_SCB *p_scb;
    -     BT_HDR *p_new_buf;
    - 
    -+    p_scb = bta_pan_scb_by_handle(handle);
    +@@ -171,20 +173,25 @@ static void bta_pan_data_flow_cb(UINT16 handle, tPAN_RESULT result)
    + static void bta_pan_data_buf_ind_cback(UINT16 handle, BD_ADDR src, BD_ADDR dst, UINT16 protocol, BT_HDR *p_buf,
    +                                    BOOLEAN ext, BOOLEAN forward)
    + {
    +-    tBTA_PAN_SCB *p_scb;
    +-    BT_HDR *p_new_buf;
    +-
    +-    if (sizeof(tBTA_PAN_DATA_PARAMS) > p_buf->offset) {
    +-        /* offset smaller than data structure in front of actual data */
    +-        p_new_buf = (BT_HDR *)osi_malloc(PAN_BUF_SIZE);
    +-        memcpy((UINT8 *)(p_new_buf + 1) + sizeof(tBTA_PAN_DATA_PARAMS),
    +-               (UINT8 *)(p_buf + 1) + p_buf->offset, p_buf->len);
    +-        p_new_buf->len    = p_buf->len;
    +-        p_new_buf->offset = sizeof(tBTA_PAN_DATA_PARAMS);
    +-        osi_free(p_buf);
    +-    } else {
    +-        p_new_buf = p_buf;
    ++    tBTA_PAN_SCB* p_scb = bta_pan_scb_by_handle(handle);
     +    if (p_scb == NULL) {
     +        return;
     +    }
     +
    -     if (sizeof(tBTA_PAN_DATA_PARAMS) > p_buf->offset) {
    -         /* offset smaller than data structure in front of actual data */
    -+        if (sizeof(BT_HDR) + sizeof(tBTA_PAN_DATA_PARAMS) + p_buf->len >
    -+            PAN_BUF_SIZE) {
    -+            android_errorWriteLog(0x534e4554, "63146237");
    -+            APPL_TRACE_ERROR("%s: received buffer length too large: %d", __func__,
    -+                             p_buf->len);
    -+            return;
    -+        }
    -         p_new_buf = (BT_HDR *)osi_malloc(PAN_BUF_SIZE);
    -         memcpy((UINT8 *)(p_new_buf + 1) + sizeof(tBTA_PAN_DATA_PARAMS),
    -                (UINT8 *)(p_buf + 1) + p_buf->offset, p_buf->len);
    -         p_new_buf->len    = p_buf->len;
    -         p_new_buf->offset = sizeof(tBTA_PAN_DATA_PARAMS);
    --        osi_free(p_buf);
    -     } else {
    -         p_new_buf = p_buf;
    ++    if (sizeof(BT_HDR) + sizeof(tBTA_PAN_DATA_PARAMS) + p_buf->len >
    ++        PAN_BUF_SIZE) {
    ++      android_errorWriteLog(0x534e4554, "63146237");
    ++      APPL_TRACE_ERROR("%s: received buffer length too large: %d", __func__,
    ++                       p_buf->len);
    ++      return;
          }
    -@@ -192,11 +205,6 @@ static void bta_pan_data_buf_ind_cback(UINT16 handle, BD_ADDR src, BD_ADDR dst,
    ++
    ++    BT_HDR* p_new_buf = (BT_HDR*)osi_malloc(PAN_BUF_SIZE);
    ++    memcpy((uint8_t*)(p_new_buf + 1) + sizeof(tBTA_PAN_DATA_PARAMS),
    ++           (uint8_t*)(p_buf + 1) + p_buf->offset, p_buf->len);
    ++    p_new_buf->len = p_buf->len;
    ++    p_new_buf->offset = sizeof(tBTA_PAN_DATA_PARAMS);
    ++
    +     /* copy params into the space before the data */
    +     bdcpy(((tBTA_PAN_DATA_PARAMS *)p_new_buf)->src, src);
    +     bdcpy(((tBTA_PAN_DATA_PARAMS *)p_new_buf)->dst, dst);
    +@@ -192,11 +199,6 @@ static void bta_pan_data_buf_ind_cback(UINT16 handle, BD_ADDR src, BD_ADDR dst,
          ((tBTA_PAN_DATA_PARAMS *)p_new_buf)->ext = ext;
          ((tBTA_PAN_DATA_PARAMS *)p_new_buf)->forward = forward;
      
    @@ -299,8 +371,42 @@ index 3f3fe93..63f74b6 100644
                          p_u8 = p_result->get_app_val_txt.vals;
                          for (xx=0; xx< p_result->get_app_val_txt.num_val; xx++)
                          {
    +diff --git a/stack/bnep/bnep_api.c b/stack/bnep/bnep_api.c
    +index 9a7b5d9..3e866d1 100644
    +--- a/stack/bnep/bnep_api.c
    ++++ b/stack/bnep/bnep_api.c
    +@@ -24,6 +24,7 @@
    + 
    + #include <string.h>
    + #include "bnep_api.h"
    ++#include <log/log.h>
    + #include "bnep_int.h"
    + 
    + 
    +@@ -414,6 +415,10 @@ tBNEP_RESULT BNEP_WriteBuf (UINT16 handle,
    +             else
    +             {
    +                 new_len += 4;
    ++                if (new_len > org_len) {
    ++                  android_errorWriteLog(0x534e4554, "74947856");
    ++                  return BNEP_IGNORE_CMD;
    ++                }
    +                 p_data[2] = 0;
    +                 p_data[3] = 0;
    +             }
    +@@ -521,6 +526,10 @@ tBNEP_RESULT  BNEP_Write (UINT16 handle,
    +             else
    +             {
    +                 new_len += 4;
    ++                if (new_len > org_len) {
    ++                  android_errorWriteLog(0x534e4554, "74947856");
    ++                  return BNEP_IGNORE_CMD;
    ++                }
    +                 p_data[2] = 0;
    +                 p_data[3] = 0;
    +             }
     diff --git a/stack/bnep/bnep_main.c b/stack/bnep/bnep_main.c
    -index 078a72e..3560d46 100644
    +index 078a72e..534c470 100644
     --- a/stack/bnep/bnep_main.c
     +++ b/stack/bnep/bnep_main.c
     @@ -35,6 +35,7 @@
    @@ -370,14 +476,6 @@ index 078a72e..3560d46 100644
                      extension_present = ext_type >> 7;
                      ext_type &= 0x7F;
      
    -@@ -656,6 +667,7 @@ static void bnep_data_ind (UINT16 l2cap_cid, BT_HDR *p_buf)
    -     if (bnep_cb.p_data_buf_cb)
    -     {
    -         (*bnep_cb.p_data_buf_cb)(p_bcb->handle, p_src_addr, p_dst_addr, protocol, p_buf, fw_ext_present);
    -+	osi_free(p_buf);
    -     }
    -     else if (bnep_cb.p_data_ind_cb)
    -     {
     diff --git a/stack/bnep/bnep_utils.c b/stack/bnep/bnep_utils.c
     index 13fb189..05bcdda 100644
     --- a/stack/bnep/bnep_utils.c
    @@ -602,6 +700,370 @@ index 688ed88..9f9ed0a 100644
      #if BLE_INCLUDED == TRUE
            gatt_free();
      #endif
    +diff --git a/stack/gatt/gatt_sr.c b/stack/gatt/gatt_sr.c
    +index 11ef79c..c2cdb88 100644
    +--- a/stack/gatt/gatt_sr.c
    ++++ b/stack/gatt/gatt_sr.c
    +@@ -22,6 +22,7 @@
    +  *
    +  ******************************************************************************/
    + 
    ++#include <log/log.h>
    + #include "bt_target.h"
    + #include "bt_utils.h"
    + 
    +@@ -344,6 +345,13 @@ void gatt_process_exec_write_req (tGATT_TCB *p_tcb, UINT8 op_code, UINT16 len, U
    +     }
    + #endif
    + 
    ++    if (len < sizeof(flag)) {
    ++      android_errorWriteLog(0x534e4554, "73172115");
    ++      GATT_TRACE_ERROR("%s invalid length", __func__);
    ++      gatt_send_error_rsp(p_tcb, GATT_INVALID_PDU, GATT_REQ_EXEC_WRITE, 0, false);
    ++      return;
    ++    }
    ++
    +     STREAM_TO_UINT8(flag, p);
    + 
    +     /* mask the flag */
    +@@ -1143,6 +1151,14 @@ static void gatts_process_read_req(tGATT_TCB *p_tcb, tGATT_SR_REG *p_rcb, UINT8
    +     UINT16          offset = 0, value_len = 0;
    +     BT_HDR          *p_msg = (BT_HDR *)osi_calloc(buf_len);
    + 
    ++    if (op_code == GATT_REQ_READ_BLOB && len < sizeof(UINT16)) {
    ++      /* Error: packet length is too short */
    ++      GATT_TRACE_ERROR("%s: packet length=%d too short. min=%d", __func__, len, sizeof(UINT16));
    ++      android_errorWriteWithInfoLog(0x534e4554, "73172115", -1, NULL, 0);
    ++      gatt_send_error_rsp(p_tcb, GATT_INVALID_PDU, op_code, 0, false);
    ++      return;
    ++    }
    ++
    +     UNUSED(len);
    + 
    +     if (op_code == GATT_REQ_READ_BLOB)
    +diff --git a/stack/l2cap/l2c_fcr.c b/stack/l2cap/l2c_fcr.c
    +index 5ba8b56..282b171 100644
    +--- a/stack/l2cap/l2c_fcr.c
    ++++ b/stack/l2cap/l2c_fcr.c
    +@@ -24,6 +24,7 @@
    +  ******************************************************************************/
    + 
    + #include <assert.h>
    ++#include <log/log.h>
    + #include <stdio.h>
    + #include <stdlib.h>
    + #include <string.h>
    +@@ -865,7 +866,24 @@ void l2c_lcc_proc_pdu(tL2C_CCB *p_ccb, BT_HDR *p_buf)
    + 
    +     }
    +     else
    ++    {
    +         p_data = p_ccb->ble_sdu;
    ++        if (p_buf->len > (p_ccb->ble_sdu_length - p_data->len)) {
    ++          L2CAP_TRACE_ERROR("%s: buffer length=%d too big. max=%d. Dropped",
    ++                            __func__, p_data->len,
    ++                            (p_ccb->ble_sdu_length - p_data->len));
    ++          android_errorWriteWithInfoLog(0x534e4554, "75298652", -1, NULL, 0);
    ++          osi_free(p_buf);
    ++
    ++          /* Throw away all pending fragments and disconnects */
    ++          p_ccb->is_first_seg = true;
    ++          osi_free(p_ccb->ble_sdu);
    ++          p_ccb->ble_sdu = NULL;
    ++          p_ccb->ble_sdu_length = 0;
    ++          l2cu_disconnect_chnl(p_ccb);
    ++          return;
    ++          }
    ++    }
    + 
    +     memcpy((UINT8*)(p_data + 1) + p_data->offset + p_data->len, (UINT8*)(p_buf + 1) + p_buf->offset, p_buf->len);
    +     p_data->len += p_buf->len;
    +@@ -881,11 +899,6 @@ void l2c_lcc_proc_pdu(tL2C_CCB *p_ccb, BT_HDR *p_buf)
    +     {
    +         p_ccb->is_first_seg = FALSE;
    +     }
    +-    else
    +-    {
    +-        L2CAP_TRACE_ERROR ("%s Length in the SDU messed up",__func__);
    +-        // TODO: reset every thing may be???
    +-    }
    + 
    +     osi_free(p_buf);
    +     return;
    +diff --git a/stack/l2cap/l2c_main.c b/stack/l2cap/l2c_main.c
    +index 3c48d69..cef488c 100644
    +--- a/stack/l2cap/l2c_main.c
    ++++ b/stack/l2cap/l2c_main.c
    +@@ -339,9 +339,17 @@ static void process_l2cap_cmd (tL2C_LCB *p_lcb, UINT8 *p, UINT16 pkt_len)
    +         switch (cmd_code)
    +         {
    +         case L2CAP_CMD_REJECT:
    ++            if (p + 2 > p_next_cmd) {
    ++              android_errorWriteLog(0x534e4554, "74202041");
    ++              return;
    ++            }
    +             STREAM_TO_UINT16 (rej_reason, p);
    +             if (rej_reason == L2CAP_CMD_REJ_MTU_EXCEEDED)
    +             {
    ++                if (p + 2 > p_next_cmd) {
    ++                  android_errorWriteLog(0x534e4554, "74202041");
    ++                  return;
    ++                }
    +                 STREAM_TO_UINT16 (rej_mtu, p);
    +                 /* What to do with the MTU reject ? We have negotiated an MTU. For now */
    +                 /* we will ignore it and let a higher protocol timeout take care of it */
    +@@ -350,6 +358,10 @@ static void process_l2cap_cmd (tL2C_LCB *p_lcb, UINT8 *p, UINT16 pkt_len)
    +             }
    +             if (rej_reason == L2CAP_CMD_REJ_INVALID_CID)
    +             {
    ++                if (p + 4 > p_next_cmd) {
    ++                  android_errorWriteLog(0x534e4554, "74202041");
    ++                  return;
    ++                }
    +                 STREAM_TO_UINT16 (rcid, p);
    +                 STREAM_TO_UINT16 (lcid, p);
    + 
    +@@ -382,6 +394,10 @@ static void process_l2cap_cmd (tL2C_LCB *p_lcb, UINT8 *p, UINT16 pkt_len)
    +             break;
    + 
    +         case L2CAP_CMD_CONN_REQ:
    ++            if (p + 4 > p_next_cmd) {
    ++              android_errorWriteLog(0x534e4554, "74202041");
    ++              return;
    ++            }
    +             STREAM_TO_UINT16 (con_info.psm, p);
    +             STREAM_TO_UINT16 (rcid, p);
    +             if ((p_rcb = l2cu_find_rcb_by_psm (con_info.psm)) == NULL)
    +@@ -413,6 +429,10 @@ static void process_l2cap_cmd (tL2C_LCB *p_lcb, UINT8 *p, UINT16 pkt_len)
    +             break;
    + 
    +         case L2CAP_CMD_CONN_RSP:
    ++            if (p + 8 > p_next_cmd) {
    ++              android_errorWriteLog(0x534e4554, "74202041");
    ++              return;
    ++            }
    +             STREAM_TO_UINT16 (con_info.remote_cid, p);
    +             STREAM_TO_UINT16 (lcid, p);
    +             STREAM_TO_UINT16 (con_info.l2cap_result, p);
    +@@ -445,6 +465,10 @@ static void process_l2cap_cmd (tL2C_LCB *p_lcb, UINT8 *p, UINT16 pkt_len)
    +             cfg_rej = FALSE;
    +             cfg_rej_len = 0;
    + 
    ++            if (p + 4 > p_next_cmd) {
    ++              android_errorWriteLog(0x534e4554, "74202041");
    ++              return;
    ++            }
    +             STREAM_TO_UINT16 (lcid, p);
    +             STREAM_TO_UINT16 (cfg_info.flags, p);
    + 
    +@@ -455,6 +479,10 @@ static void process_l2cap_cmd (tL2C_LCB *p_lcb, UINT8 *p, UINT16 pkt_len)
    + 
    +             while (p < p_cfg_end)
    +             {
    ++                if (p + 2 > p_next_cmd) {
    ++                  android_errorWriteLog(0x534e4554, "74202041");
    ++                  return;
    ++                }
    +                 STREAM_TO_UINT8 (cfg_code, p);
    +                 STREAM_TO_UINT8 (cfg_len, p);
    + 
    +@@ -462,16 +490,28 @@ static void process_l2cap_cmd (tL2C_LCB *p_lcb, UINT8 *p, UINT16 pkt_len)
    +                 {
    +                 case L2CAP_CFG_TYPE_MTU:
    +                     cfg_info.mtu_present = TRUE;
    ++                    if (p + 2 > p_next_cmd) {
    ++                      android_errorWriteLog(0x534e4554, "74202041");
    ++                      return;
    ++                    }
    +                     STREAM_TO_UINT16 (cfg_info.mtu, p);
    +                     break;
    + 
    +                 case L2CAP_CFG_TYPE_FLUSH_TOUT:
    +                     cfg_info.flush_to_present = TRUE;
    ++                    if (p + 2 > p_next_cmd) {
    ++                      android_errorWriteLog(0x534e4554, "74202041");
    ++                      return;
    ++                    }
    +                     STREAM_TO_UINT16 (cfg_info.flush_to, p);
    +                     break;
    + 
    +                 case L2CAP_CFG_TYPE_QOS:
    +                     cfg_info.qos_present = TRUE;
    ++                    if (p + 2 + 5 * 4 > p_next_cmd) {
    ++                      android_errorWriteLog(0x534e4554, "74202041");
    ++                      return;
    ++                    }
    +                     STREAM_TO_UINT8  (cfg_info.qos.qos_flags, p);
    +                     STREAM_TO_UINT8  (cfg_info.qos.service_type, p);
    +                     STREAM_TO_UINT32 (cfg_info.qos.token_rate, p);
    +@@ -483,6 +523,10 @@ static void process_l2cap_cmd (tL2C_LCB *p_lcb, UINT8 *p, UINT16 pkt_len)
    + 
    +                 case L2CAP_CFG_TYPE_FCR:
    +                     cfg_info.fcr_present = TRUE;
    ++                    if (p + 3 + 3 * 2 > p_next_cmd) {
    ++                      android_errorWriteLog(0x534e4554, "74202041");
    ++                      return;
    ++                    }
    +                     STREAM_TO_UINT8 (cfg_info.fcr.mode, p);
    +                     STREAM_TO_UINT8 (cfg_info.fcr.tx_win_sz, p);
    +                     STREAM_TO_UINT8 (cfg_info.fcr.max_transmit, p);
    +@@ -493,11 +537,19 @@ static void process_l2cap_cmd (tL2C_LCB *p_lcb, UINT8 *p, UINT16 pkt_len)
    + 
    +                 case L2CAP_CFG_TYPE_FCS:
    +                     cfg_info.fcs_present = TRUE;
    ++                    if (p + 1 > p_next_cmd) {
    ++                      android_errorWriteLog(0x534e4554, "74202041");
    ++                      return;
    ++                    }
    +                     STREAM_TO_UINT8 (cfg_info.fcs, p);
    +                     break;
    + 
    +                 case L2CAP_CFG_TYPE_EXT_FLOW:
    +                     cfg_info.ext_flow_spec_present = TRUE;
    ++                    if (p + 2 + 2 + 3 * 4 > p_next_cmd) {
    ++                      android_errorWriteLog(0x534e4554, "74202041");
    ++                      return;
    ++                    }
    +                     STREAM_TO_UINT8  (cfg_info.ext_flow_spec.id, p);
    +                     STREAM_TO_UINT8  (cfg_info.ext_flow_spec.stype, p);
    +                     STREAM_TO_UINT16 (cfg_info.ext_flow_spec.max_sdu_size, p);
    +@@ -548,6 +600,10 @@ static void process_l2cap_cmd (tL2C_LCB *p_lcb, UINT8 *p, UINT16 pkt_len)
    + 
    +         case L2CAP_CMD_CONFIG_RSP:
    +             p_cfg_end = p + cmd_len;
    ++            if (p + 6 > p_next_cmd) {
    ++              android_errorWriteLog(0x534e4554, "74202041");
    ++              return;
    ++            }
    +             STREAM_TO_UINT16 (lcid, p);
    +             STREAM_TO_UINT16 (cfg_info.flags, p);
    +             STREAM_TO_UINT16 (cfg_info.result, p);
    +@@ -557,6 +613,10 @@ static void process_l2cap_cmd (tL2C_LCB *p_lcb, UINT8 *p, UINT16 pkt_len)
    + 
    +             while (p < p_cfg_end)
    +             {
    ++                if (p + 2 > p_next_cmd) {
    ++                  android_errorWriteLog(0x534e4554, "74202041");
    ++                  return;
    ++                }
    +                 STREAM_TO_UINT8 (cfg_code, p);
    +                 STREAM_TO_UINT8 (cfg_len, p);
    + 
    +@@ -564,16 +624,28 @@ static void process_l2cap_cmd (tL2C_LCB *p_lcb, UINT8 *p, UINT16 pkt_len)
    +                 {
    +                 case L2CAP_CFG_TYPE_MTU:
    +                     cfg_info.mtu_present = TRUE;
    ++                    if (p + 2 > p_next_cmd) {
    ++                      android_errorWriteLog(0x534e4554, "74202041");
    ++                      return;
    ++                    }
    +                     STREAM_TO_UINT16 (cfg_info.mtu, p);
    +                     break;
    + 
    +                 case L2CAP_CFG_TYPE_FLUSH_TOUT:
    +                     cfg_info.flush_to_present = TRUE;
    ++                    if (p + 2 > p_next_cmd) {
    ++                      android_errorWriteLog(0x534e4554, "74202041");
    ++                      return;
    ++                    }
    +                     STREAM_TO_UINT16 (cfg_info.flush_to, p);
    +                     break;
    + 
    +                 case L2CAP_CFG_TYPE_QOS:
    +                     cfg_info.qos_present = TRUE;
    ++                    if (p + 2 + 5 * 4 > p_next_cmd) {
    ++                      android_errorWriteLog(0x534e4554, "74202041");
    ++                      return;
    ++                    }
    +                     STREAM_TO_UINT8  (cfg_info.qos.qos_flags, p);
    +                     STREAM_TO_UINT8  (cfg_info.qos.service_type, p);
    +                     STREAM_TO_UINT32 (cfg_info.qos.token_rate, p);
    +@@ -585,6 +657,10 @@ static void process_l2cap_cmd (tL2C_LCB *p_lcb, UINT8 *p, UINT16 pkt_len)
    + 
    +                 case L2CAP_CFG_TYPE_FCR:
    +                     cfg_info.fcr_present = TRUE;
    ++                    if (p + 3 + 3 * 2 > p_next_cmd) {
    ++                      android_errorWriteLog(0x534e4554, "74202041");
    ++                      return;
    ++                    }
    +                     STREAM_TO_UINT8 (cfg_info.fcr.mode, p);
    +                     STREAM_TO_UINT8 (cfg_info.fcr.tx_win_sz, p);
    +                     STREAM_TO_UINT8 (cfg_info.fcr.max_transmit, p);
    +@@ -595,11 +671,19 @@ static void process_l2cap_cmd (tL2C_LCB *p_lcb, UINT8 *p, UINT16 pkt_len)
    + 
    +                 case L2CAP_CFG_TYPE_FCS:
    +                     cfg_info.fcs_present = TRUE;
    ++                    if (p + 1 > p_next_cmd) {
    ++                      android_errorWriteLog(0x534e4554, "74202041");
    ++                      return;
    ++                    }
    +                     STREAM_TO_UINT8 (cfg_info.fcs, p);
    +                     break;
    + 
    +                 case L2CAP_CFG_TYPE_EXT_FLOW:
    +                     cfg_info.ext_flow_spec_present = TRUE;
    ++                    if (p + 2 + 2 + 3 * 4 > p_next_cmd) {
    ++                      android_errorWriteLog(0x534e4554, "74202041");
    ++                      return;
    ++                    }
    +                     STREAM_TO_UINT8  (cfg_info.ext_flow_spec.id, p);
    +                     STREAM_TO_UINT8  (cfg_info.ext_flow_spec.stype, p);
    +                     STREAM_TO_UINT16 (cfg_info.ext_flow_spec.max_sdu_size, p);
    +@@ -630,6 +714,10 @@ static void process_l2cap_cmd (tL2C_LCB *p_lcb, UINT8 *p, UINT16 pkt_len)
    +             break;
    + 
    +         case L2CAP_CMD_DISC_REQ:
    ++            if (p + 4 > p_next_cmd) {
    ++              android_errorWriteLog(0x534e4554, "74202041");
    ++              return;
    ++            }
    +             STREAM_TO_UINT16 (lcid, p);
    +             STREAM_TO_UINT16 (rcid, p);
    + 
    +@@ -647,6 +735,10 @@ static void process_l2cap_cmd (tL2C_LCB *p_lcb, UINT8 *p, UINT16 pkt_len)
    +             break;
    + 
    +         case L2CAP_CMD_DISC_RSP:
    ++            if (p + 4 > p_next_cmd) {
    ++              android_errorWriteLog(0x534e4554, "74202041");
    ++              return;
    ++            }
    +             STREAM_TO_UINT16 (rcid, p);
    +             STREAM_TO_UINT16 (lcid, p);
    + 
    +@@ -676,6 +768,10 @@ static void process_l2cap_cmd (tL2C_LCB *p_lcb, UINT8 *p, UINT16 pkt_len)
    +             break;
    + 
    +         case L2CAP_CMD_INFO_REQ:
    ++            if (p + 2 > p_next_cmd) {
    ++              android_errorWriteLog(0x534e4554, "74202041");
    ++              return;
    ++            }
    +             STREAM_TO_UINT16 (info_type, p);
    +             l2cu_send_peer_info_rsp (p_lcb, id, info_type);
    +             break;
    +@@ -688,6 +784,10 @@ static void process_l2cap_cmd (tL2C_LCB *p_lcb, UINT8 *p, UINT16 pkt_len)
    +                 p_lcb->w4_info_rsp = FALSE;
    +             }
    + 
    ++            if (p + 4 > p_next_cmd) {
    ++              android_errorWriteLog(0x534e4554, "74202041");
    ++              return;
    ++            }
    +             STREAM_TO_UINT16 (info_type, p);
    +             STREAM_TO_UINT16 (result, p);
    + 
    +@@ -696,6 +796,10 @@ static void process_l2cap_cmd (tL2C_LCB *p_lcb, UINT8 *p, UINT16 pkt_len)
    +             if ( (info_type == L2CAP_EXTENDED_FEATURES_INFO_TYPE)
    +               && (result == L2CAP_INFO_RESP_RESULT_SUCCESS) )
    +             {
    ++                if (p + 4 > p_next_cmd) {
    ++                  android_errorWriteLog(0x534e4554, "74202041");
    ++                  return;
    ++                }
    +                 STREAM_TO_UINT32( p_lcb->peer_ext_fea, p );
    + 
    + #if (L2CAP_NUM_FIXED_CHNLS > 0)
     diff --git a/stack/l2cap/l2cap_client.c b/stack/l2cap/l2cap_client.c
     index 7e8b3cb..cd7edfe 100644
     --- a/stack/l2cap/l2cap_client.c
    @@ -658,7 +1120,7 @@ index 583a342..6694ff7 100644
              p = p_start = (UINT8*)(p_buf + 1) + L2CAP_MIN_OFFSET;
              *p++ = reject_opcode;
     diff --git a/stack/pan/pan_main.c b/stack/pan/pan_main.c
    -index 5c3a367..9268ff9 100644
    +index 5c3a367..7d56ee7 100644
     --- a/stack/pan/pan_main.c
     +++ b/stack/pan/pan_main.c
     @@ -221,6 +221,38 @@ void pan_conn_ind_cb (UINT16 handle,
    @@ -700,6 +1162,34 @@ index 5c3a367..9268ff9 100644
      
          /* Requested destination role is */
          if (local_uuid->uu.uuid16 == UUID_SERVCLASS_PANU)
    +@@ -596,11 +628,9 @@ void pan_data_buf_ind_cb (UINT16 handle,
    +             if (pan_cb.pan_data_buf_ind_cb)
    +                 (*pan_cb.pan_data_buf_ind_cb) (pcb->handle, src, dst, protocol, p_buf, ext, forward);
    +             else if (pan_cb.pan_data_ind_cb)
    +-            {
    +                 (*pan_cb.pan_data_ind_cb) (pcb->handle, src, dst, protocol, p_data, len, ext, forward);
    +-                osi_free(p_buf);
    +-            }
    + 
    ++            osi_free(p_buf);
    +             return;
    +         }
    + 
    +@@ -623,13 +653,9 @@ void pan_data_buf_ind_cb (UINT16 handle,
    +     if (pan_cb.pan_data_buf_ind_cb)
    +         (*pan_cb.pan_data_buf_ind_cb) (pcb->handle, src, dst, protocol, p_buf, ext, forward);
    +     else if (pan_cb.pan_data_ind_cb)
    +-    {
    +         (*pan_cb.pan_data_ind_cb) (pcb->handle, src, dst, protocol, p_data, len, ext, forward);
    +-        osi_free(p_buf);
    +-    }
    +-    else
    +-        osi_free(p_buf);
    + 
    ++    osi_free(p_buf);
    +     return;
    + }
    + 
     diff --git a/stack/sdp/sdp_main.c b/stack/sdp/sdp_main.c
     index c888817..7cbe2d3 100644
     --- a/stack/sdp/sdp_main.c
    diff --git a/system_core.patch b/system_core.patch
    index 2ab3421..4faa581 100644
    --- a/system_core.patch
    +++ b/system_core.patch
    @@ -398,6 +398,113 @@ index cd26d05..bfc5f4d 100644
          saddr = packet.ip.saddr;
          daddr = packet.ip.daddr;
          nread = ntohs(packet.ip.tot_len);
    +diff --git a/libutils/String16.cpp b/libutils/String16.cpp
    +index 65396ca..32e026b 100644
    +--- a/libutils/String16.cpp
    ++++ b/libutils/String16.cpp
    +@@ -84,6 +84,24 @@ static char16_t* allocFromUTF8(const char* u8str, size_t u8len)
    +     return getEmptyString();
    + }
    + 
    ++static char16_t* allocFromUTF16(const char16_t* u16str, size_t u16len) {
    ++    if (u16len >= SIZE_MAX / sizeof(char16_t)) {
    ++        android_errorWriteLog(0x534e4554, "73826242");
    ++        abort();
    ++    }
    ++
    ++    SharedBuffer* buf = SharedBuffer::alloc((u16len + 1) * sizeof(char16_t));
    ++    ALOG_ASSERT(buf, "Unable to allocate shared buffer");
    ++    if (buf) {
    ++        char16_t* str = (char16_t*)buf->data();
    ++        memcpy(str, u16str, u16len * sizeof(char16_t));
    ++        str[u16len] = 0;
    ++        return str;
    ++    }
    ++    return getEmptyString();
    ++}
    ++
    ++
    + // ---------------------------------------------------------------------------
    + 
    + String16::String16()
    +@@ -116,35 +134,9 @@ String16::String16(const String16& o, size_t len, size_t begin)
    +     setTo(o, len, begin);
    + }
    + 
    +-String16::String16(const char16_t* o)
    +-{
    +-    size_t len = strlen16(o);
    +-    SharedBuffer* buf = SharedBuffer::alloc((len+1)*sizeof(char16_t));
    +-    ALOG_ASSERT(buf, "Unable to allocate shared buffer");
    +-    if (buf) {
    +-        char16_t* str = (char16_t*)buf->data();
    +-        strcpy16(str, o);
    +-        mString = str;
    +-        return;
    +-    }
    +-    
    +-    mString = getEmptyString();
    +-}
    ++String16::String16(const char16_t* o) : mString(allocFromUTF16(o, strlen16(o))) {}
    + 
    +-String16::String16(const char16_t* o, size_t len)
    +-{
    +-    SharedBuffer* buf = SharedBuffer::alloc((len+1)*sizeof(char16_t));
    +-    ALOG_ASSERT(buf, "Unable to allocate shared buffer");
    +-    if (buf) {
    +-        char16_t* str = (char16_t*)buf->data();
    +-        memcpy(str, o, len*sizeof(char16_t));
    +-        str[len] = 0;
    +-        mString = str;
    +-        return;
    +-    }
    +-    
    +-    mString = getEmptyString();
    +-}
    ++String16::String16(const char16_t* o, size_t len) : mString(allocFromUTF16(o, len)) {}
    + 
    + String16::String16(const String8& o)
    +     : mString(allocFromUTF8(o.string(), o.size()))
    +@@ -206,6 +198,11 @@ status_t String16::setTo(const char16_t* other)
    + 
    + status_t String16::setTo(const char16_t* other, size_t len)
    + {
    ++    if (len >= SIZE_MAX / sizeof(char16_t)) {
    ++        android_errorWriteLog(0x534e4554, "73826242");
    ++        abort();
    ++    }
    ++
    +     SharedBuffer* buf = SharedBuffer::bufferFromData(mString)
    +         ->editResize((len+1)*sizeof(char16_t));
    +     if (buf) {
    +@@ -228,7 +225,12 @@ status_t String16::append(const String16& other)
    +     } else if (otherLen == 0) {
    +         return NO_ERROR;
    +     }
    +-    
    ++
    ++    if (myLen >= SIZE_MAX / sizeof(char16_t) - otherLen) {
    ++        android_errorWriteLog(0x534e4554, "73826242");
    ++        abort();
    ++    }
    ++
    +     SharedBuffer* buf = SharedBuffer::bufferFromData(mString)
    +         ->editResize((myLen+otherLen+1)*sizeof(char16_t));
    +     if (buf) {
    +@@ -249,7 +251,12 @@ status_t String16::append(const char16_t* chrs, size_t otherLen)
    +     } else if (otherLen == 0) {
    +         return NO_ERROR;
    +     }
    +-    
    ++
    ++    if (myLen >= SIZE_MAX / sizeof(char16_t) - otherLen) {
    ++        android_errorWriteLog(0x534e4554, "73826242");
    ++        abort();
    ++    }
    ++
    +     SharedBuffer* buf = SharedBuffer::bufferFromData(mString)
    +         ->editResize((myLen+otherLen+1)*sizeof(char16_t));
    +     if (buf) {
     diff --git a/libutils/Unicode.cpp b/libutils/Unicode.cpp
     index ba084f6..bfacf1e 100644
     --- a/libutils/Unicode.cpp
    
    From 2b69defe83c31a0bc246f7d38e829ee36d3151b6 Mon Sep 17 00:00:00 2001
    From: AndDiSa <anddisa@googlemail.com>
    Date: Sat, 14 Jul 2018 16:54:31 +0200
    Subject: [PATCH 097/159] update patches
    
    Change-Id: Ibb641e20c1659dee808f90bff29a249fc3b185ce
    ---
     build.patch                  |    4 +-
     default.xml                  |    2 +-
     external_android_clat.patch  |   39 +
     external_libhevc.patch       |   43 +-
     frameworks_av.patch          | 2506 +---------------------------------
     frameworks_base.patch        |  129 +-
     frameworks_native.patch      |  489 ++++++-
     frameworks_op_net_wifi.patch |   13 +
     hardware_broadcom_wlan.patch |   32 +
     system_bt.patch              |  116 +-
     system_media.patch           |   17 +-
     11 files changed, 884 insertions(+), 2506 deletions(-)
     create mode 100644 external_android_clat.patch
    
    diff --git a/build.patch b/build.patch
    index f578613..e3617ec 100644
    --- a/build.patch
    +++ b/build.patch
    @@ -323,7 +323,7 @@ index 0000000..80664fa
     +ALL_PREBUILT += $(INSTALLED_KERNEL_TARGET)
     +endif
     diff --git a/core/version_defaults.mk b/core/version_defaults.mk
    -index 7c96344..b6b44e1 100644
    +index 7c96344..4470fa4 100644
     --- a/core/version_defaults.mk
     +++ b/core/version_defaults.mk
     @@ -131,7 +131,7 @@ ifeq "" "$(PLATFORM_SECURITY_PATCH)"
    @@ -331,7 +331,7 @@ index 7c96344..b6b44e1 100644
          #  It must match one of the Android Security Patch Level strings of the Public Security Bulletins.
          #  If there is no $PLATFORM_SECURITY_PATCH set, keep it empty.
     -    PLATFORM_SECURITY_PATCH := 2017-08-05
    -+    PLATFORM_SECURITY_PATCH := 2018-06-05
    ++    PLATFORM_SECURITY_PATCH := 2018-07-05
      endif
      
      ifeq "" "$(PLATFORM_BASE_OS)"
    diff --git a/default.xml b/default.xml
    index ff75ab2..34f5ebc 100644
    --- a/default.xml
    +++ b/default.xml
    @@ -329,7 +329,7 @@
       <project path="frameworks/wilhelm" name="platform/frameworks/wilhelm" groups="pdk-cw-fs,pdk-fs" />
       <project path="hardware/akm" name="platform/hardware/akm" />
       <project path="hardware/broadcom/libbt" name="platform/hardware/broadcom/libbt" groups="pdk" />
    -  <project path="hardware/broadcom/wlan" name="platform/hardware/broadcom/wlan" groups="pdk,broadcom_wlan" />
    +  <project path="hardware/broadcom/wlan" name="platform/hardware/broadcom/wlan" remote="unlegacy" revision="aosp-7.1" groups="pdk,broadcom_wlan" />
       <project path="hardware/google/apf" name="platform/hardware/google/apf" groups="pdk" />
       <project path="hardware/intel/audio_media" name="platform/hardware/intel/audio_media" groups="intel" />
       <project path="hardware/intel/bootstub" name="platform/hardware/intel/bootstub" groups="intel" />
    diff --git a/external_android_clat.patch b/external_android_clat.patch
    new file mode 100644
    index 0000000..f743e3d
    --- /dev/null
    +++ b/external_android_clat.patch
    @@ -0,0 +1,39 @@
    +diff --git a/clatd.c b/clatd.c
    +index d57ea59..fd89e0a 100644
    +--- a/clatd.c
    ++++ b/clatd.c
    +@@ -382,19 +382,28 @@ void event_loop(struct tun_data *tunnel) {
    +   last_interface_poll = time(NULL);
    + 
    +   while(running) {
    +-    if(poll(wait_fd, 2, NO_TRAFFIC_INTERFACE_POLL_FREQUENCY*1000) == -1) {
    +-      if(errno != EINTR) {
    +-        logmsg(ANDROID_LOG_WARN,"event_loop/poll returned an error: %s",strerror(errno));
    ++    if (poll(wait_fd, ARRAY_SIZE(wait_fd),
    ++             NO_TRAFFIC_INTERFACE_POLL_FREQUENCY * 1000) == -1) {
    ++      if (errno != EINTR) {
    ++        logmsg(ANDROID_LOG_WARN,"event_loop/poll returned an error: %s", strerror(errno));
    +       }
    +     } else {
    ++      if (wait_fd[0].revents & POLLIN) {
    ++        ring_read(&tunnel->ring, tunnel->fd4, 0 /* to_ipv6 */);
    ++      }
    ++      // If any other bit is set, assume it's due to an error (i.e. POLLERR).
    ++      if (wait_fd[0].revents & ~POLLIN) {
    ++        // ring_read doesn't clear the error indication on the socket.
    ++        recv(tunnel->read_fd6, NULL, 0, MSG_PEEK);
    ++        logmsg(ANDROID_LOG_WARN, "event_loop: clearing error on read_fd6: %s",
    ++               strerror(errno));
    ++      }
    ++
    +       // Call read_packet if the socket has data to be read, but also if an
    +       // error is waiting. If we don't call read() after getting POLLERR, a
    +       // subsequent poll() will return immediately with POLLERR again,
    +       // causing this code to spin in a loop. Calling read() will clear the
    +       // socket error flag instead.
    +-      if (wait_fd[0].revents) {
    +-        ring_read(&tunnel->ring, tunnel->fd4, 0 /* to_ipv6 */);
    +-      }
    +       if (wait_fd[1].revents) {
    +         read_packet(tunnel->fd4, tunnel->write_fd6, 1 /* to_ipv6 */);
    +       }
    diff --git a/external_libhevc.patch b/external_libhevc.patch
    index bff0753..5758933 100644
    --- a/external_libhevc.patch
    +++ b/external_libhevc.patch
    @@ -3954,6 +3954,19 @@ index e9b69c1..1f99ff8 100644
          ldmfd       sp!,{r4-r12,r15}            @reload the registers from sp
      
      
    +diff --git a/common/ihevc_defs.h b/common/ihevc_defs.h
    +index a2b7eda..c4e34ba 100644
    +--- a/common/ihevc_defs.h
    ++++ b/common/ihevc_defs.h
    +@@ -274,7 +274,7 @@ typedef enum {
    + #define SPS_MAX_SUB_LAYERS  7
    + 
    + /* Maximum long term reference pics */
    +-#define MAX_LTREF_PICS_SPS 16
    ++#define MAX_LTREF_PICS_SPS 32
    + 
    + #define MAX_STREF_PICS_SPS 64
    + 
     diff --git a/common/ihevc_structs.h b/common/ihevc_structs.h
     index 93d2ad4..baa6375 100644
     --- a/common/ihevc_structs.h
    @@ -4169,7 +4182,7 @@ index d656519..d2ea7a5 100644
      
          if(1 == ps_codec->i4_pic_present)
     diff --git a/decoder/ihevcd_parse_headers.c b/decoder/ihevcd_parse_headers.c
    -index c0f1564..8348fc6 100644
    +index c0f1564..90b341a 100644
     --- a/decoder/ihevcd_parse_headers.c
     +++ b/decoder/ihevcd_parse_headers.c
     @@ -1272,12 +1272,6 @@ IHEVCD_ERROR_T ihevcd_parse_sps(codec_t *ps_codec)
    @@ -4228,7 +4241,33 @@ index c0f1564..8348fc6 100644
          {
              return IHEVCD_INVALID_PARAMETER;
          }
    -@@ -1797,6 +1809,19 @@ IHEVCD_ERROR_T ihevcd_parse_pps(codec_t *ps_codec)
    +@@ -1461,10 +1473,12 @@ IHEVCD_ERROR_T ihevcd_parse_sps(codec_t *ps_codec)
    + 
    +     }
    +     UEV_PARSE("num_short_term_ref_pic_sets", value, ps_bitstrm);
    ++    if(value < 0 || value > MAX_STREF_PICS_SPS)
    ++    {
    ++        return IHEVCD_INVALID_PARAMETER;
    ++    }
    +     ps_sps->i1_num_short_term_ref_pic_sets = value;
    + 
    +-    ps_sps->i1_num_short_term_ref_pic_sets = CLIP3(ps_sps->i1_num_short_term_ref_pic_sets, 0, MAX_STREF_PICS_SPS);
    +-
    +     for(i = 0; i < ps_sps->i1_num_short_term_ref_pic_sets; i++)
    +         ihevcd_short_term_ref_pic_set(ps_bitstrm, &ps_sps->as_stref_picset[0], ps_sps->i1_num_short_term_ref_pic_sets, i, &ps_sps->as_stref_picset[i]);
    + 
    +@@ -1474,6 +1488,10 @@ IHEVCD_ERROR_T ihevcd_parse_sps(codec_t *ps_codec)
    +     if(ps_sps->i1_long_term_ref_pics_present_flag)
    +     {
    +         UEV_PARSE("num_long_term_ref_pics_sps", value, ps_bitstrm);
    ++        if(value < 0 || value > MAX_LTREF_PICS_SPS)
    ++        {
    ++            return IHEVCD_INVALID_PARAMETER;
    ++        }
    +         ps_sps->i1_num_long_term_ref_pics_sps = value;
    + 
    +         for(i = 0; i < ps_sps->i1_num_long_term_ref_pics_sps; i++)
    +@@ -1797,6 +1815,19 @@ IHEVCD_ERROR_T ihevcd_parse_pps(codec_t *ps_codec)
          BITS_PARSE("tiles_enabled_flag", value, ps_bitstrm, 1);
          ps_pps->i1_tiles_enabled_flag = value;
      
    diff --git a/frameworks_av.patch b/frameworks_av.patch
    index caeba98..f2a6c17 100644
    --- a/frameworks_av.patch
    +++ b/frameworks_av.patch
    @@ -2415,10 +2415,39 @@ index c04549a..1242c95 100644
      }
      
     diff --git a/media/libstagefright/id3/ID3.cpp b/media/libstagefright/id3/ID3.cpp
    -index 8b80ae9..c21097b 100644
    +index 8b80ae9..0791ee9 100644
     --- a/media/libstagefright/id3/ID3.cpp
     +++ b/media/libstagefright/id3/ID3.cpp
    -@@ -392,7 +392,12 @@ bool ID3::removeUnsynchronizationV2_4(bool iTunesHack) {
    +@@ -328,12 +328,24 @@ struct id3_header {
    + }
    + 
    + void ID3::removeUnsynchronization() {
    +-    for (size_t i = 0; i + 1 < mSize; ++i) {
    +-        if (mData[i] == 0xff && mData[i + 1] == 0x00) {
    +-            memmove(&mData[i + 1], &mData[i + 2], mSize - i - 2);
    +-            --mSize;
    ++    // This file has "unsynchronization", so we have to replace occurrences
    ++    // of 0xff 0x00 with just 0xff in order to get the real data.
    ++
    ++    size_t writeOffset = 1;
    ++    for (size_t readOffset = 1; readOffset < mSize; ++readOffset) {
    ++        if (mData[readOffset - 1] == 0xff && mData[readOffset] == 0x00) {
    ++            continue;
    +         }
    ++        // Only move data if there's actually something to move.
    ++        // This handles the special case of the data being only [0xff, 0x00]
    ++        // which should be converted to just 0xff if unsynchronization is on.
    ++        mData[writeOffset++] = mData[readOffset];
    ++    }
    ++
    ++    if (writeOffset < mSize) {
    ++        mSize = writeOffset;
    +     }
    ++
    + }
    + 
    + static void WriteSyncsafeInteger(uint8_t *dst, size_t x) {
    +@@ -392,7 +404,12 @@ bool ID3::removeUnsynchronizationV2_4(bool iTunesHack) {
                          --mSize;
                          --dataSize;
                      }
    @@ -2453,294 +2482,6 @@ index 94cf15a..dd396e8 100644
      
          // For debug support
          char *mName;
    -diff --git a/media/libstagefright/include/OMXNodeInstance.h.orig b/media/libstagefright/include/OMXNodeInstance.h.orig
    -new file mode 100644
    -index 0000000..f65a409
    ---- /dev/null
    -+++ b/media/libstagefright/include/OMXNodeInstance.h.orig
    -@@ -0,0 +1,282 @@
    -+/*
    -+ * Copyright (C) 2009 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.
    -+ */
    -+
    -+#ifndef OMX_NODE_INSTANCE_H_
    -+
    -+#define OMX_NODE_INSTANCE_H_
    -+
    -+#include "OMX.h"
    -+
    -+#include <utils/RefBase.h>
    -+#include <utils/SortedVector.h>
    -+#include <utils/threads.h>
    -+
    -+namespace android {
    -+
    -+class IOMXObserver;
    -+struct OMXMaster;
    -+class GraphicBufferSource;
    -+
    -+struct OMXNodeInstance {
    -+    OMXNodeInstance(
    -+            OMX *owner, const sp<IOMXObserver> &observer, const char *name);
    -+
    -+    void setHandle(OMX::node_id node_id, OMX_HANDLETYPE handle);
    -+
    -+    OMX *owner();
    -+    sp<IOMXObserver> observer();
    -+    OMX::node_id nodeID();
    -+
    -+    status_t freeNode(OMXMaster *master);
    -+
    -+    status_t sendCommand(OMX_COMMANDTYPE cmd, OMX_S32 param);
    -+    status_t getParameter(OMX_INDEXTYPE index, void *params, size_t size);
    -+
    -+    status_t setParameter(
    -+            OMX_INDEXTYPE index, const void *params, size_t size);
    -+
    -+    status_t getConfig(OMX_INDEXTYPE index, void *params, size_t size);
    -+    status_t setConfig(OMX_INDEXTYPE index, const void *params, size_t size);
    -+
    -+    status_t getState(OMX_STATETYPE* state);
    -+
    -+    status_t enableNativeBuffers(OMX_U32 portIndex, OMX_BOOL graphic, OMX_BOOL enable);
    -+
    -+    status_t getGraphicBufferUsage(OMX_U32 portIndex, OMX_U32* usage);
    -+
    -+    status_t storeMetaDataInBuffers(
    -+            OMX_U32 portIndex, OMX_BOOL enable, MetadataBufferType *type);
    -+
    -+    status_t prepareForAdaptivePlayback(
    -+            OMX_U32 portIndex, OMX_BOOL enable,
    -+            OMX_U32 maxFrameWidth, OMX_U32 maxFrameHeight);
    -+
    -+    status_t configureVideoTunnelMode(
    -+            OMX_U32 portIndex, OMX_BOOL tunneled,
    -+            OMX_U32 audioHwSync, native_handle_t **sidebandHandle);
    -+
    -+    status_t useBuffer(
    -+            OMX_U32 portIndex, const sp<IMemory> &params,
    -+            OMX::buffer_id *buffer, OMX_U32 allottedSize);
    -+
    -+    status_t useGraphicBuffer(
    -+            OMX_U32 portIndex, const sp<GraphicBuffer> &graphicBuffer,
    -+            OMX::buffer_id *buffer);
    -+
    -+    status_t updateGraphicBufferInMeta(
    -+            OMX_U32 portIndex, const sp<GraphicBuffer> &graphicBuffer,
    -+            OMX::buffer_id buffer);
    -+
    -+    status_t updateNativeHandleInMeta(
    -+            OMX_U32 portIndex, const sp<NativeHandle> &nativeHandle,
    -+            OMX::buffer_id buffer);
    -+
    -+    status_t createInputSurface(
    -+            OMX_U32 portIndex, android_dataspace dataSpace,
    -+            sp<IGraphicBufferProducer> *bufferProducer,
    -+            MetadataBufferType *type);
    -+
    -+    static status_t createPersistentInputSurface(
    -+            sp<IGraphicBufferProducer> *bufferProducer,
    -+            sp<IGraphicBufferConsumer> *bufferConsumer);
    -+
    -+    status_t setInputSurface(
    -+            OMX_U32 portIndex, const sp<IGraphicBufferConsumer> &bufferConsumer,
    -+            MetadataBufferType *type);
    -+
    -+    status_t signalEndOfInputStream();
    -+
    -+    void signalEvent(OMX_EVENTTYPE event, OMX_U32 arg1, OMX_U32 arg2);
    -+
    -+    status_t allocateSecureBuffer(
    -+            OMX_U32 portIndex, size_t size, OMX::buffer_id *buffer,
    -+            void **buffer_data, sp<NativeHandle> *native_handle);
    -+
    -+    status_t allocateBufferWithBackup(
    -+            OMX_U32 portIndex, const sp<IMemory> &params,
    -+            OMX::buffer_id *buffer, OMX_U32 allottedSize);
    -+
    -+    status_t freeBuffer(OMX_U32 portIndex, OMX::buffer_id buffer);
    -+
    -+    status_t fillBuffer(OMX::buffer_id buffer, int fenceFd);
    -+
    -+    status_t emptyBuffer(
    -+            OMX::buffer_id buffer,
    -+            OMX_U32 rangeOffset, OMX_U32 rangeLength,
    -+            OMX_U32 flags, OMX_TICKS timestamp, int fenceFd);
    -+
    -+    status_t emptyGraphicBuffer(
    -+            OMX_BUFFERHEADERTYPE *header, const sp<GraphicBuffer> &buffer,
    -+            OMX_U32 flags, OMX_TICKS timestamp, int fenceFd);
    -+
    -+    status_t getExtensionIndex(
    -+            const char *parameterName, OMX_INDEXTYPE *index);
    -+
    -+    status_t setInternalOption(
    -+            OMX_U32 portIndex,
    -+            IOMX::InternalOptionType type,
    -+            const void *data,
    -+            size_t size);
    -+
    -+    bool isSecure() const {
    -+        return mIsSecure;
    -+    }
    -+
    -+    // handles messages and removes them from the list
    -+    void onMessages(std::list<omx_message> &messages);
    -+    void onMessage(const omx_message &msg);
    -+    void onObserverDied(OMXMaster *master);
    -+    void onGetHandleFailed();
    -+    void onEvent(OMX_EVENTTYPE event, OMX_U32 arg1, OMX_U32 arg2);
    -+
    -+    static OMX_CALLBACKTYPE kCallbacks;
    -+
    -+private:
    -+    Mutex mLock;
    -+
    -+    OMX *mOwner;
    -+    OMX::node_id mNodeID;
    -+    OMX_HANDLETYPE mHandle;
    -+    sp<IOMXObserver> mObserver;
    -+    bool mDying;
    -+    bool mSailed;  // configuration is set (no more meta-mode changes)
    -+    bool mQueriedProhibitedExtensions;
    -+    SortedVector<OMX_INDEXTYPE> mProhibitedExtensions;
    -+    bool mIsSecure;
    -+
    -+    // Lock only covers mGraphicBufferSource.  We can't always use mLock
    -+    // because of rare instances where we'd end up locking it recursively.
    -+    Mutex mGraphicBufferSourceLock;
    -+    // Access this through getGraphicBufferSource().
    -+    sp<GraphicBufferSource> mGraphicBufferSource;
    -+
    -+
    -+    struct ActiveBuffer {
    -+        OMX_U32 mPortIndex;
    -+        OMX::buffer_id mID;
    -+    };
    -+    Vector<ActiveBuffer> mActiveBuffers;
    -+    // for buffer ptr to buffer id translation
    -+    Mutex mBufferIDLock;
    -+    uint32_t mBufferIDCount;
    -+    KeyedVector<OMX::buffer_id, OMX_BUFFERHEADERTYPE *> mBufferIDToBufferHeader;
    -+    KeyedVector<OMX_BUFFERHEADERTYPE *, OMX::buffer_id> mBufferHeaderToBufferID;
    -+
    -+<<<<<<< HEAD
    -+    // metadata and secure buffer type tracking
    -+=======
    -+    bool mLegacyAdaptiveExperiment;
    -+    IOMX::PortMode mPortMode[2];
    -+    // metadata and secure buffer types and graphic buffer mode tracking
    -+>>>>>>> f630233... Track graphic buffer mode in OMXNodeInstance
    -+    MetadataBufferType mMetadataType[2];
    -+    enum SecureBufferType {
    -+        kSecureBufferTypeUnknown,
    -+        kSecureBufferTypeOpaque,
    -+        kSecureBufferTypeNativeHandle,
    -+    };
    -+    SecureBufferType mSecureBufferType[2];
    -+    bool mGraphicBufferEnabled[2];
    -+
    -+    // For debug support
    -+    char *mName;
    -+    int DEBUG;
    -+    size_t mNumPortBuffers[2];  // modified under mLock, read outside for debug
    -+    Mutex mDebugLock;
    -+    // following are modified and read under mDebugLock
    -+    int DEBUG_BUMP;
    -+    SortedVector<OMX_BUFFERHEADERTYPE *> mInputBuffersWithCodec, mOutputBuffersWithCodec;
    -+    size_t mDebugLevelBumpPendingBuffers[2];
    -+    void bumpDebugLevel_l(size_t numInputBuffers, size_t numOutputBuffers);
    -+    void unbumpDebugLevel_l(size_t portIndex);
    -+
    -+    ~OMXNodeInstance();
    -+
    -+    void addActiveBuffer(OMX_U32 portIndex, OMX::buffer_id id);
    -+    void removeActiveBuffer(OMX_U32 portIndex, OMX::buffer_id id);
    -+    void freeActiveBuffers();
    -+
    -+    // For buffer id management
    -+    OMX::buffer_id makeBufferID(OMX_BUFFERHEADERTYPE *bufferHeader);
    -+    OMX_BUFFERHEADERTYPE *findBufferHeader(OMX::buffer_id buffer, OMX_U32 portIndex);
    -+    OMX::buffer_id findBufferID(OMX_BUFFERHEADERTYPE *bufferHeader);
    -+    void invalidateBufferID(OMX::buffer_id buffer);
    -+
    -+    bool isProhibitedIndex_l(OMX_INDEXTYPE index);
    -+
    -+    status_t useGraphicBuffer2_l(
    -+            OMX_U32 portIndex, const sp<GraphicBuffer> &graphicBuffer,
    -+            OMX::buffer_id *buffer);
    -+    static OMX_ERRORTYPE OnEvent(
    -+            OMX_IN OMX_HANDLETYPE hComponent,
    -+            OMX_IN OMX_PTR pAppData,
    -+            OMX_IN OMX_EVENTTYPE eEvent,
    -+            OMX_IN OMX_U32 nData1,
    -+            OMX_IN OMX_U32 nData2,
    -+            OMX_IN OMX_PTR pEventData);
    -+
    -+    static OMX_ERRORTYPE OnEmptyBufferDone(
    -+            OMX_IN OMX_HANDLETYPE hComponent,
    -+            OMX_IN OMX_PTR pAppData,
    -+            OMX_IN OMX_BUFFERHEADERTYPE *pBuffer);
    -+
    -+    static OMX_ERRORTYPE OnFillBufferDone(
    -+            OMX_IN OMX_HANDLETYPE hComponent,
    -+            OMX_IN OMX_PTR pAppData,
    -+            OMX_IN OMX_BUFFERHEADERTYPE *pBuffer);
    -+
    -+    status_t storeMetaDataInBuffers_l(
    -+            OMX_U32 portIndex, OMX_BOOL enable, MetadataBufferType *type);
    -+
    -+    // Stores fence into buffer if it is ANWBuffer type and has enough space.
    -+    // otherwise, waits for the fence to signal.  Takes ownership of |fenceFd|.
    -+    status_t storeFenceInMeta_l(
    -+            OMX_BUFFERHEADERTYPE *header, int fenceFd, OMX_U32 portIndex);
    -+
    -+    // Retrieves the fence from buffer if ANWBuffer type and has enough space. Otherwise, returns -1
    -+    int retrieveFenceFromMeta_l(
    -+            OMX_BUFFERHEADERTYPE *header, OMX_U32 portIndex);
    -+
    -+    status_t emptyBuffer_l(
    -+            OMX_BUFFERHEADERTYPE *header,
    -+            OMX_U32 flags, OMX_TICKS timestamp, intptr_t debugAddr, int fenceFd);
    -+
    -+    // Updates the graphic buffer handle in the metadata buffer for |buffer| and |header| to
    -+    // |graphicBuffer|'s handle. If |updateCodecBuffer| is true, the update will happen in
    -+    // the actual codec buffer (use this if not using emptyBuffer (with no _l) later to
    -+    // pass the buffer to the codec, as only emptyBuffer copies the backup buffer to the codec
    -+    // buffer.)
    -+    status_t updateGraphicBufferInMeta_l(
    -+            OMX_U32 portIndex, const sp<GraphicBuffer> &graphicBuffer,
    -+            OMX::buffer_id buffer, OMX_BUFFERHEADERTYPE *header, bool updateCodecBuffer);
    -+
    -+    status_t createGraphicBufferSource(
    -+            OMX_U32 portIndex, sp<IGraphicBufferConsumer> consumer /* nullable */,
    -+            MetadataBufferType *type);
    -+    sp<GraphicBufferSource> getGraphicBufferSource();
    -+    void setGraphicBufferSource(const sp<GraphicBufferSource>& bufferSource);
    -+
    -+    // Handles |msg|, and may modify it. Returns true iff completely handled it and
    -+    // |msg| does not need to be sent to the event listener.
    -+    bool handleMessage(omx_message &msg);
    -+
    -+    OMXNodeInstance(const OMXNodeInstance &);
    -+    OMXNodeInstance &operator=(const OMXNodeInstance &);
    -+};
    -+
    -+}  // namespace android
    -+
    -+#endif  // OMX_NODE_INSTANCE_H_
     diff --git a/media/libstagefright/include/SoftVideoEncoderOMXComponent.h b/media/libstagefright/include/SoftVideoEncoderOMXComponent.h
     index b43635d..02555a2 100644
     --- a/media/libstagefright/include/SoftVideoEncoderOMXComponent.h
    @@ -2843,7 +2584,7 @@ index 6132a2c..7f0d270 100644
      
      void OMXMaster::addPlugin(const char *libname) {
     diff --git a/media/libstagefright/omx/OMXNodeInstance.cpp b/media/libstagefright/omx/OMXNodeInstance.cpp
    -index e7aaead..f60a79c 100644
    +index e7aaead..18778f7 100644
     --- a/media/libstagefright/omx/OMXNodeInstance.cpp
     +++ b/media/libstagefright/omx/OMXNodeInstance.cpp
     @@ -226,6 +226,8 @@ OMXNodeInstance::OMXNodeInstance(
    @@ -2877,7 +2618,7 @@ index e7aaead..f60a79c 100644
              }
          } else {
              CLOG_ERROR_IF(enable, getExtensionIndex, err, "%s", name);
    -@@ -798,10 +808,21 @@ status_t OMXNodeInstance::useBuffer(
    +@@ -798,10 +808,33 @@ status_t OMXNodeInstance::useBuffer(
              return BAD_VALUE;
          }
      
    @@ -2887,6 +2628,18 @@ index e7aaead..f60a79c 100644
     +        android_errorWriteLog(0x534e4554, "62948670");
     +        return INVALID_OPERATION;
     +    }
    ++
    ++    if (!mSailed) {
    ++        ALOGE("b/35467458");
    ++        android_errorWriteLog(0x534e4554, "35467458");
    ++        return BAD_VALUE;
    ++    }
    ++
    ++    if (!mSailed) {
    ++        ALOGE("b/35467458");
    ++        android_errorWriteLog(0x534e4554, "35467458");
    ++        return BAD_VALUE;
    ++    }
     +
          // metadata buffers are not connected cross process
          // use a backup buffer instead of the actual buffer
    @@ -2899,7 +2652,7 @@ index e7aaead..f60a79c 100644
          OMX_U8 *data = static_cast<OMX_U8 *>(params->pointer());
          // allocate backup buffer
          if (useBackup) {
    -@@ -916,6 +937,13 @@ status_t OMXNodeInstance::useGraphicBuffer(
    +@@ -916,6 +949,13 @@ status_t OMXNodeInstance::useGraphicBuffer(
              return BAD_VALUE;
          }
          Mutex::Autolock autoLock(mLock);
    @@ -2913,7 +2666,7 @@ index e7aaead..f60a79c 100644
      
          // See if the newer version of the extension is present.
          OMX_INDEXTYPE index;
    -@@ -1235,6 +1263,12 @@ status_t OMXNodeInstance::allocateSecureBuffer(
    +@@ -1235,6 +1275,24 @@ status_t OMXNodeInstance::allocateSecureBuffer(
              return BAD_VALUE;
          }
      
    @@ -2922,11 +2675,23 @@ index e7aaead..f60a79c 100644
     +        android_errorWriteLog(0x534e4554, "63522818");
     +        return ERROR_UNSUPPORTED;
     +    }
    ++
    ++    if (!mSailed) {
    ++        ALOGE("b/35467458");
    ++        android_errorWriteLog(0x534e4554, "35467458");
    ++        return BAD_VALUE;
    ++    }
    ++
    ++    if (!mSailed) {
    ++        ALOGE("b/35467458");
    ++        android_errorWriteLog(0x534e4554, "35467458");
    ++        return BAD_VALUE;
    ++    }
     +
          BufferMeta *buffer_meta = new BufferMeta(size, portIndex);
      
          OMX_BUFFERHEADERTYPE *header;
    -@@ -1296,8 +1330,18 @@ status_t OMXNodeInstance::allocateBufferWithBackup(
    +@@ -1296,8 +1354,30 @@ status_t OMXNodeInstance::allocateBufferWithBackup(
              return BAD_VALUE;
          }
      
    @@ -2935,6 +2700,18 @@ index e7aaead..f60a79c 100644
     +        android_errorWriteLog(0x534e4554, "63522818");
     +        return ERROR_UNSUPPORTED;
     +    }
    ++
    ++    if (!mSailed) {
    ++        ALOGE("b/35467458");
    ++        android_errorWriteLog(0x534e4554, "35467458");
    ++        return BAD_VALUE;
    ++    }
    ++
    ++    if (!mSailed) {
    ++        ALOGE("b/35467458");
    ++        android_errorWriteLog(0x534e4554, "35467458");
    ++        return BAD_VALUE;
    ++    }
     +
          // metadata buffers are not connected cross process; only copy if not meta
     +#ifdef CAMCORDER_GRALLOC_SOURCE
    @@ -2945,7 +2722,7 @@ index e7aaead..f60a79c 100644
      
          BufferMeta *buffer_meta = new BufferMeta(
                  params, portIndex,
    -@@ -1415,10 +1459,30 @@ status_t OMXNodeInstance::emptyBuffer(
    +@@ -1415,10 +1495,30 @@ status_t OMXNodeInstance::emptyBuffer(
          BufferMeta *buffer_meta =
              static_cast<BufferMeta *>(header->pAppPrivate);
      
    @@ -2976,2143 +2753,6 @@ index e7aaead..f60a79c 100644
              header->nOffset = 0;
          } else {
              // rangeLength and rangeOffset must be a subset of the allocated data in the buffer.
    -diff --git a/media/libstagefright/omx/OMXNodeInstance.cpp.orig b/media/libstagefright/omx/OMXNodeInstance.cpp.orig
    -new file mode 100644
    -index 0000000..968cc1b
    ---- /dev/null
    -+++ b/media/libstagefright/omx/OMXNodeInstance.cpp.orig
    -@@ -0,0 +1,2131 @@
    -+/*
    -+ * Copyright (C) 2009 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.
    -+ */
    -+
    -+//#define LOG_NDEBUG 0
    -+#define LOG_TAG "OMXNodeInstance"
    -+#include <utils/Log.h>
    -+
    -+#include <inttypes.h>
    -+
    -+#include "../include/OMXNodeInstance.h"
    -+#include "OMXMaster.h"
    -+#include "OMXUtils.h"
    -+#include "GraphicBufferSource.h"
    -+
    -+#include <OMX_Component.h>
    -+#include <OMX_IndexExt.h>
    -+#include <OMX_AsString.h>
    -+
    -+#include <binder/IMemory.h>
    -+#include <cutils/properties.h>
    -+#include <gui/BufferQueue.h>
    -+#include <HardwareAPI.h>
    -+#include <media/stagefright/foundation/ADebug.h>
    -+#include <media/stagefright/foundation/ABuffer.h>
    -+#include <media/stagefright/MediaErrors.h>
    -+#include <utils/misc.h>
    -+#include <utils/NativeHandle.h>
    -+
    -+static const OMX_U32 kPortIndexInput = 0;
    -+static const OMX_U32 kPortIndexOutput = 1;
    -+
    -+#define CLOGW(fmt, ...) ALOGW("[%x:%s] " fmt, mNodeID, mName, ##__VA_ARGS__)
    -+
    -+#define CLOG_ERROR_IF(cond, fn, err, fmt, ...) \
    -+    ALOGE_IF(cond, #fn "(%x:%s, " fmt ") ERROR: %s(%#x)", \
    -+    mNodeID, mName, ##__VA_ARGS__, asString(err), err)
    -+#define CLOG_ERROR(fn, err, fmt, ...) CLOG_ERROR_IF(true, fn, err, fmt, ##__VA_ARGS__)
    -+#define CLOG_IF_ERROR(fn, err, fmt, ...) \
    -+    CLOG_ERROR_IF((err) != OMX_ErrorNone, fn, err, fmt, ##__VA_ARGS__)
    -+
    -+#define CLOGI_(level, fn, fmt, ...) \
    -+    ALOGI_IF(DEBUG >= (level), #fn "(%x:%s, " fmt ")", mNodeID, mName, ##__VA_ARGS__)
    -+#define CLOGD_(level, fn, fmt, ...) \
    -+    ALOGD_IF(DEBUG >= (level), #fn "(%x:%s, " fmt ")", mNodeID, mName, ##__VA_ARGS__)
    -+
    -+#define CLOG_LIFE(fn, fmt, ...)     CLOGI_(ADebug::kDebugLifeCycle,     fn, fmt, ##__VA_ARGS__)
    -+#define CLOG_STATE(fn, fmt, ...)    CLOGI_(ADebug::kDebugState,         fn, fmt, ##__VA_ARGS__)
    -+#define CLOG_CONFIG(fn, fmt, ...)   CLOGI_(ADebug::kDebugConfig,        fn, fmt, ##__VA_ARGS__)
    -+#define CLOG_INTERNAL(fn, fmt, ...) CLOGD_(ADebug::kDebugInternalState, fn, fmt, ##__VA_ARGS__)
    -+
    -+#define CLOG_DEBUG_IF(cond, fn, fmt, ...) \
    -+    ALOGD_IF(cond, #fn "(%x, " fmt ")", mNodeID, ##__VA_ARGS__)
    -+
    -+#define CLOG_BUFFER(fn, fmt, ...) \
    -+    CLOG_DEBUG_IF(DEBUG >= ADebug::kDebugAll, fn, fmt, ##__VA_ARGS__)
    -+#define CLOG_BUMPED_BUFFER(fn, fmt, ...) \
    -+    CLOG_DEBUG_IF(DEBUG_BUMP >= ADebug::kDebugAll, fn, fmt, ##__VA_ARGS__)
    -+
    -+/* buffer formatting */
    -+#define BUFFER_FMT(port, fmt, ...) "%s:%u " fmt, portString(port), (port), ##__VA_ARGS__
    -+#define NEW_BUFFER_FMT(buffer_id, port, fmt, ...) \
    -+    BUFFER_FMT(port, fmt ") (#%zu => %#x", ##__VA_ARGS__, mActiveBuffers.size(), (buffer_id))
    -+
    -+#define SIMPLE_BUFFER(port, size, data) BUFFER_FMT(port, "%zu@%p", (size), (data))
    -+#define SIMPLE_NEW_BUFFER(buffer_id, port, size, data) \
    -+    NEW_BUFFER_FMT(buffer_id, port, "%zu@%p", (size), (data))
    -+
    -+#define EMPTY_BUFFER(addr, header, fenceFd) "%#x [%u@%p fc=%d]", \
    -+    (addr), (header)->nAllocLen, (header)->pBuffer, (fenceFd)
    -+#define FULL_BUFFER(addr, header, fenceFd) "%#" PRIxPTR " [%u@%p (%u..+%u) f=%x ts=%lld fc=%d]", \
    -+    (intptr_t)(addr), (header)->nAllocLen, (header)->pBuffer, \
    -+    (header)->nOffset, (header)->nFilledLen, (header)->nFlags, (header)->nTimeStamp, (fenceFd)
    -+
    -+#define WITH_STATS_WRAPPER(fmt, ...) fmt " { IN=%zu/%zu OUT=%zu/%zu }", ##__VA_ARGS__, \
    -+    mInputBuffersWithCodec.size(), mNumPortBuffers[kPortIndexInput], \
    -+    mOutputBuffersWithCodec.size(), mNumPortBuffers[kPortIndexOutput]
    -+// TRICKY: this is needed so formatting macros expand before substitution
    -+#define WITH_STATS(fmt, ...) WITH_STATS_WRAPPER(fmt, ##__VA_ARGS__)
    -+
    -+namespace android {
    -+
    -+struct BufferMeta {
    -+    BufferMeta(
    -+            const sp<IMemory> &mem, OMX_U32 portIndex, bool copyToOmx,
    -+            bool copyFromOmx, OMX_U8 *backup)
    -+        : mMem(mem),
    -+          mCopyFromOmx(copyFromOmx),
    -+          mCopyToOmx(copyToOmx),
    -+          mPortIndex(portIndex),
    -+          mBackup(backup) {
    -+    }
    -+
    -+    BufferMeta(size_t size, OMX_U32 portIndex)
    -+        : mSize(size),
    -+          mCopyFromOmx(false),
    -+          mCopyToOmx(false),
    -+          mPortIndex(portIndex),
    -+          mBackup(NULL) {
    -+    }
    -+
    -+    BufferMeta(const sp<GraphicBuffer> &graphicBuffer, OMX_U32 portIndex)
    -+        : mGraphicBuffer(graphicBuffer),
    -+          mCopyFromOmx(false),
    -+          mCopyToOmx(false),
    -+          mPortIndex(portIndex),
    -+          mBackup(NULL) {
    -+    }
    -+
    -+    void CopyFromOMX(const OMX_BUFFERHEADERTYPE *header) {
    -+        if (!mCopyFromOmx) {
    -+            return;
    -+        }
    -+
    -+        // check component returns proper range
    -+        sp<ABuffer> codec = getBuffer(header, false /* backup */, true /* limit */);
    -+
    -+        memcpy((OMX_U8 *)mMem->pointer() + header->nOffset, codec->data(), codec->size());
    -+    }
    -+
    -+    void CopyToOMX(const OMX_BUFFERHEADERTYPE *header) {
    -+        if (!mCopyToOmx) {
    -+            return;
    -+        }
    -+
    -+        memcpy(header->pBuffer + header->nOffset,
    -+                (const OMX_U8 *)mMem->pointer() + header->nOffset,
    -+                header->nFilledLen);
    -+    }
    -+
    -+    // return either the codec or the backup buffer
    -+    sp<ABuffer> getBuffer(const OMX_BUFFERHEADERTYPE *header, bool backup, bool limit) {
    -+        sp<ABuffer> buf;
    -+        if (backup && mMem != NULL) {
    -+            buf = new ABuffer(mMem->pointer(), mMem->size());
    -+        } else {
    -+            buf = new ABuffer(header->pBuffer, header->nAllocLen);
    -+        }
    -+        if (limit) {
    -+            if (header->nOffset + header->nFilledLen > header->nOffset
    -+                    && header->nOffset + header->nFilledLen <= header->nAllocLen) {
    -+                buf->setRange(header->nOffset, header->nFilledLen);
    -+            } else {
    -+                buf->setRange(0, 0);
    -+            }
    -+        }
    -+        return buf;
    -+    }
    -+
    -+    void setGraphicBuffer(const sp<GraphicBuffer> &graphicBuffer) {
    -+        mGraphicBuffer = graphicBuffer;
    -+    }
    -+
    -+    void setNativeHandle(const sp<NativeHandle> &nativeHandle) {
    -+        mNativeHandle = nativeHandle;
    -+    }
    -+
    -+    OMX_U32 getPortIndex() {
    -+        return mPortIndex;
    -+    }
    -+
    -+    ~BufferMeta() {
    -+        delete[] mBackup;
    -+    }
    -+
    -+private:
    -+    sp<GraphicBuffer> mGraphicBuffer;
    -+    sp<NativeHandle> mNativeHandle;
    -+    sp<IMemory> mMem;
    -+    size_t mSize;
    -+    bool mCopyFromOmx;
    -+    bool mCopyToOmx;
    -+    OMX_U32 mPortIndex;
    -+    OMX_U8 *mBackup;
    -+
    -+    BufferMeta(const BufferMeta &);
    -+    BufferMeta &operator=(const BufferMeta &);
    -+};
    -+
    -+// static
    -+OMX_CALLBACKTYPE OMXNodeInstance::kCallbacks = {
    -+    &OnEvent, &OnEmptyBufferDone, &OnFillBufferDone
    -+};
    -+
    -+static inline const char *portString(OMX_U32 portIndex) {
    -+    switch (portIndex) {
    -+        case kPortIndexInput:  return "Input";
    -+        case kPortIndexOutput: return "Output";
    -+        case ~0U:              return "All";
    -+        default:               return "port";
    -+    }
    -+}
    -+
    -+OMXNodeInstance::OMXNodeInstance(
    -+        OMX *owner, const sp<IOMXObserver> &observer, const char *name)
    -+    : mOwner(owner),
    -+      mNodeID(0),
    -+      mHandle(NULL),
    -+      mObserver(observer),
    -+      mDying(false),
    -+      mSailed(false),
    -+      mQueriedProhibitedExtensions(false),
    -+      mBufferIDCount(0)
    -+{
    -+    mName = ADebug::GetDebugName(name);
    -+    DEBUG = ADebug::GetDebugLevelFromProperty(name, "debug.stagefright.omx-debug");
    -+    ALOGV("debug level for %s is %d", name, DEBUG);
    -+    DEBUG_BUMP = DEBUG;
    -+    mNumPortBuffers[0] = 0;
    -+    mNumPortBuffers[1] = 0;
    -+    mDebugLevelBumpPendingBuffers[0] = 0;
    -+    mDebugLevelBumpPendingBuffers[1] = 0;
    -+    mMetadataType[0] = kMetadataBufferTypeInvalid;
    -+    mMetadataType[1] = kMetadataBufferTypeInvalid;
    -+    mSecureBufferType[0] = kSecureBufferTypeUnknown;
    -+    mSecureBufferType[1] = kSecureBufferTypeUnknown;
    -+    mGraphicBufferEnabled[0] = false;
    -+    mGraphicBufferEnabled[1] = false;
    -+    mIsSecure = AString(name).endsWith(".secure");
    -+}
    -+
    -+OMXNodeInstance::~OMXNodeInstance() {
    -+    free(mName);
    -+    CHECK(mHandle == NULL);
    -+}
    -+
    -+void OMXNodeInstance::setHandle(OMX::node_id node_id, OMX_HANDLETYPE handle) {
    -+    mNodeID = node_id;
    -+    CLOG_LIFE(allocateNode, "handle=%p", handle);
    -+    CHECK(mHandle == NULL);
    -+    mHandle = handle;
    -+}
    -+
    -+sp<GraphicBufferSource> OMXNodeInstance::getGraphicBufferSource() {
    -+    Mutex::Autolock autoLock(mGraphicBufferSourceLock);
    -+    return mGraphicBufferSource;
    -+}
    -+
    -+void OMXNodeInstance::setGraphicBufferSource(
    -+        const sp<GraphicBufferSource>& bufferSource) {
    -+    Mutex::Autolock autoLock(mGraphicBufferSourceLock);
    -+    CLOG_INTERNAL(setGraphicBufferSource, "%p", bufferSource.get());
    -+    mGraphicBufferSource = bufferSource;
    -+}
    -+
    -+OMX *OMXNodeInstance::owner() {
    -+    return mOwner;
    -+}
    -+
    -+sp<IOMXObserver> OMXNodeInstance::observer() {
    -+    return mObserver;
    -+}
    -+
    -+OMX::node_id OMXNodeInstance::nodeID() {
    -+    return mNodeID;
    -+}
    -+
    -+status_t OMXNodeInstance::freeNode(OMXMaster *master) {
    -+    CLOG_LIFE(freeNode, "handle=%p", mHandle);
    -+    static int32_t kMaxNumIterations = 10;
    -+
    -+    // exit if we have already freed the node
    -+    if (mHandle == NULL) {
    -+        return OK;
    -+    }
    -+
    -+    // Transition the node from its current state all the way down
    -+    // to "Loaded".
    -+    // This ensures that all active buffers are properly freed even
    -+    // for components that don't do this themselves on a call to
    -+    // "FreeHandle".
    -+
    -+    // The code below may trigger some more events to be dispatched
    -+    // by the OMX component - we want to ignore them as our client
    -+    // does not expect them.
    -+    mDying = true;
    -+
    -+    OMX_STATETYPE state;
    -+    CHECK_EQ(OMX_GetState(mHandle, &state), OMX_ErrorNone);
    -+    switch (state) {
    -+        case OMX_StateExecuting:
    -+        {
    -+            ALOGV("forcing Executing->Idle");
    -+            sendCommand(OMX_CommandStateSet, OMX_StateIdle);
    -+            OMX_ERRORTYPE err;
    -+            int32_t iteration = 0;
    -+            while ((err = OMX_GetState(mHandle, &state)) == OMX_ErrorNone
    -+                    && state != OMX_StateIdle
    -+                    && state != OMX_StateInvalid) {
    -+                if (++iteration > kMaxNumIterations) {
    -+                    CLOGW("failed to enter Idle state (now %s(%d), aborting.",
    -+                            asString(state), state);
    -+                    state = OMX_StateInvalid;
    -+                    break;
    -+                }
    -+
    -+                usleep(100000);
    -+            }
    -+            CHECK_EQ(err, OMX_ErrorNone);
    -+
    -+            if (state == OMX_StateInvalid) {
    -+                break;
    -+            }
    -+
    -+            // fall through
    -+        }
    -+
    -+        case OMX_StateIdle:
    -+        {
    -+            ALOGV("forcing Idle->Loaded");
    -+            sendCommand(OMX_CommandStateSet, OMX_StateLoaded);
    -+
    -+            freeActiveBuffers();
    -+
    -+            OMX_ERRORTYPE err;
    -+            int32_t iteration = 0;
    -+            while ((err = OMX_GetState(mHandle, &state)) == OMX_ErrorNone
    -+                    && state != OMX_StateLoaded
    -+                    && state != OMX_StateInvalid) {
    -+                if (++iteration > kMaxNumIterations) {
    -+                    CLOGW("failed to enter Loaded state (now %s(%d), aborting.",
    -+                            asString(state), state);
    -+                    state = OMX_StateInvalid;
    -+                    break;
    -+                }
    -+
    -+                ALOGV("waiting for Loaded state...");
    -+                usleep(100000);
    -+            }
    -+            CHECK_EQ(err, OMX_ErrorNone);
    -+
    -+            // fall through
    -+        }
    -+
    -+        case OMX_StateLoaded:
    -+        case OMX_StateInvalid:
    -+            break;
    -+
    -+        default:
    -+            LOG_ALWAYS_FATAL("unknown state %s(%#x).", asString(state), state);
    -+            break;
    -+    }
    -+
    -+    ALOGV("[%x:%s] calling destroyComponentInstance", mNodeID, mName);
    -+    OMX_ERRORTYPE err = master->destroyComponentInstance(
    -+            static_cast<OMX_COMPONENTTYPE *>(mHandle));
    -+
    -+    mHandle = NULL;
    -+    CLOG_IF_ERROR(freeNode, err, "");
    -+    free(mName);
    -+    mName = NULL;
    -+
    -+    mOwner->invalidateNodeID(mNodeID);
    -+    mNodeID = 0;
    -+
    -+    ALOGV("OMXNodeInstance going away.");
    -+    delete this;
    -+
    -+    return StatusFromOMXError(err);
    -+}
    -+
    -+status_t OMXNodeInstance::sendCommand(
    -+        OMX_COMMANDTYPE cmd, OMX_S32 param) {
    -+    if (cmd == OMX_CommandStateSet) {
    -+        // There are no configurations past first StateSet command.
    -+        mSailed = true;
    -+    }
    -+    const sp<GraphicBufferSource> bufferSource(getGraphicBufferSource());
    -+    if (bufferSource != NULL && cmd == OMX_CommandStateSet) {
    -+        if (param == OMX_StateIdle) {
    -+            // Initiating transition from Executing -> Idle
    -+            // ACodec is waiting for all buffers to be returned, do NOT
    -+            // submit any more buffers to the codec.
    -+            bufferSource->omxIdle();
    -+        } else if (param == OMX_StateLoaded) {
    -+            // Initiating transition from Idle/Executing -> Loaded
    -+            // Buffers are about to be freed.
    -+            bufferSource->omxLoaded();
    -+            setGraphicBufferSource(NULL);
    -+        }
    -+
    -+        // fall through
    -+    }
    -+
    -+    Mutex::Autolock autoLock(mLock);
    -+
    -+    // bump internal-state debug level for 2 input and output frames past a command
    -+    {
    -+        Mutex::Autolock _l(mDebugLock);
    -+        bumpDebugLevel_l(2 /* numInputBuffers */, 2 /* numOutputBuffers */);
    -+    }
    -+
    -+    const char *paramString =
    -+        cmd == OMX_CommandStateSet ? asString((OMX_STATETYPE)param) : portString(param);
    -+    CLOG_STATE(sendCommand, "%s(%d), %s(%d)", asString(cmd), cmd, paramString, param);
    -+    OMX_ERRORTYPE err = OMX_SendCommand(mHandle, cmd, param, NULL);
    -+    CLOG_IF_ERROR(sendCommand, err, "%s(%d), %s(%d)", asString(cmd), cmd, paramString, param);
    -+    return StatusFromOMXError(err);
    -+}
    -+
    -+bool OMXNodeInstance::isProhibitedIndex_l(OMX_INDEXTYPE index) {
    -+    // these extensions can only be used from OMXNodeInstance, not by clients directly.
    -+    static const char *restricted_extensions[] = {
    -+        "OMX.google.android.index.storeMetaDataInBuffers",
    -+        "OMX.google.android.index.storeANWBufferInMetadata",
    -+        "OMX.google.android.index.prepareForAdaptivePlayback",
    -+        "OMX.google.android.index.configureVideoTunnelMode",
    -+        "OMX.google.android.index.useAndroidNativeBuffer2",
    -+        "OMX.google.android.index.useAndroidNativeBuffer",
    -+        "OMX.google.android.index.enableAndroidNativeBuffers",
    -+        "OMX.google.android.index.allocateNativeHandle",
    -+        "OMX.google.android.index.getAndroidNativeBufferUsage",
    -+    };
    -+
    -+    if ((index > OMX_IndexComponentStartUnused && index <= OMX_IndexParamStandardComponentRole)
    -+            || (index > OMX_IndexPortStartUnused && index <= OMX_IndexParamCompBufferSupplier)
    -+            || (index > OMX_IndexAudioStartUnused && index <= OMX_IndexConfigAudioChannelVolume)
    -+            || (index > OMX_IndexVideoStartUnused && index <= OMX_IndexConfigVideoNalSize)
    -+            || (index > OMX_IndexCommonStartUnused
    -+                    && index <= OMX_IndexConfigCommonTransitionEffect)
    -+            || (index > (OMX_INDEXTYPE)OMX_IndexExtAudioStartUnused
    -+                    && index <= (OMX_INDEXTYPE)OMX_IndexParamAudioProfileQuerySupported)
    -+            || (index > (OMX_INDEXTYPE)OMX_IndexExtVideoStartUnused
    -+                    && index <= (OMX_INDEXTYPE)OMX_IndexConfigAndroidVideoTemporalLayering)
    -+            || (index > (OMX_INDEXTYPE)OMX_IndexExtOtherStartUnused
    -+                    && index <= (OMX_INDEXTYPE)OMX_IndexParamConsumerUsageBits)) {
    -+        return false;
    -+    }
    -+
    -+    if (!mQueriedProhibitedExtensions) {
    -+        for (size_t i = 0; i < NELEM(restricted_extensions); ++i) {
    -+            OMX_INDEXTYPE ext;
    -+            if (OMX_GetExtensionIndex(mHandle, (OMX_STRING)restricted_extensions[i], &ext) == OMX_ErrorNone) {
    -+                mProhibitedExtensions.add(ext);
    -+            }
    -+        }
    -+        mQueriedProhibitedExtensions = true;
    -+    }
    -+
    -+    return mProhibitedExtensions.indexOf(index) >= 0;
    -+}
    -+
    -+status_t OMXNodeInstance::getParameter(
    -+        OMX_INDEXTYPE index, void *params, size_t /* size */) {
    -+    Mutex::Autolock autoLock(mLock);
    -+
    -+    if (isProhibitedIndex_l(index)) {
    -+        android_errorWriteLog(0x534e4554, "29422020");
    -+        return BAD_INDEX;
    -+    }
    -+
    -+    OMX_ERRORTYPE err = OMX_GetParameter(mHandle, index, params);
    -+    OMX_INDEXEXTTYPE extIndex = (OMX_INDEXEXTTYPE)index;
    -+    // some errors are expected for getParameter
    -+    if (err != OMX_ErrorNoMore) {
    -+        CLOG_IF_ERROR(getParameter, err, "%s(%#x)", asString(extIndex), index);
    -+    }
    -+    return StatusFromOMXError(err);
    -+}
    -+
    -+status_t OMXNodeInstance::setParameter(
    -+        OMX_INDEXTYPE index, const void *params, size_t size) {
    -+    Mutex::Autolock autoLock(mLock);
    -+    OMX_INDEXEXTTYPE extIndex = (OMX_INDEXEXTTYPE)index;
    -+    CLOG_CONFIG(setParameter, "%s(%#x), %zu@%p)", asString(extIndex), index, size, params);
    -+
    -+    if (isProhibitedIndex_l(index)) {
    -+        android_errorWriteLog(0x534e4554, "29422020");
    -+        return BAD_INDEX;
    -+    }
    -+
    -+    OMX_ERRORTYPE err = OMX_SetParameter(
    -+            mHandle, index, const_cast<void *>(params));
    -+    CLOG_IF_ERROR(setParameter, err, "%s(%#x)", asString(extIndex), index);
    -+    return StatusFromOMXError(err);
    -+}
    -+
    -+status_t OMXNodeInstance::getConfig(
    -+        OMX_INDEXTYPE index, void *params, size_t /* size */) {
    -+    Mutex::Autolock autoLock(mLock);
    -+
    -+    if (isProhibitedIndex_l(index)) {
    -+        android_errorWriteLog(0x534e4554, "29422020");
    -+        return BAD_INDEX;
    -+    }
    -+
    -+    OMX_ERRORTYPE err = OMX_GetConfig(mHandle, index, params);
    -+    OMX_INDEXEXTTYPE extIndex = (OMX_INDEXEXTTYPE)index;
    -+    // some errors are expected for getConfig
    -+    if (err != OMX_ErrorNoMore) {
    -+        CLOG_IF_ERROR(getConfig, err, "%s(%#x)", asString(extIndex), index);
    -+    }
    -+    return StatusFromOMXError(err);
    -+}
    -+
    -+status_t OMXNodeInstance::setConfig(
    -+        OMX_INDEXTYPE index, const void *params, size_t size) {
    -+    Mutex::Autolock autoLock(mLock);
    -+    OMX_INDEXEXTTYPE extIndex = (OMX_INDEXEXTTYPE)index;
    -+    CLOG_CONFIG(setConfig, "%s(%#x), %zu@%p)", asString(extIndex), index, size, params);
    -+
    -+    if (isProhibitedIndex_l(index)) {
    -+        android_errorWriteLog(0x534e4554, "29422020");
    -+        return BAD_INDEX;
    -+    }
    -+
    -+    OMX_ERRORTYPE err = OMX_SetConfig(
    -+            mHandle, index, const_cast<void *>(params));
    -+    CLOG_IF_ERROR(setConfig, err, "%s(%#x)", asString(extIndex), index);
    -+    return StatusFromOMXError(err);
    -+}
    -+
    -+status_t OMXNodeInstance::getState(OMX_STATETYPE* state) {
    -+    Mutex::Autolock autoLock(mLock);
    -+
    -+    OMX_ERRORTYPE err = OMX_GetState(mHandle, state);
    -+    CLOG_IF_ERROR(getState, err, "");
    -+    return StatusFromOMXError(err);
    -+}
    -+
    -+status_t OMXNodeInstance::enableNativeBuffers(
    -+        OMX_U32 portIndex, OMX_BOOL graphic, OMX_BOOL enable) {
    -+    if (portIndex >= NELEM(mSecureBufferType)) {
    -+        ALOGE("b/31385713, portIndex(%u)", portIndex);
    -+        android_errorWriteLog(0x534e4554, "31385713");
    -+        return BAD_VALUE;
    -+    }
    -+
    -+    Mutex::Autolock autoLock(mLock);
    -+    CLOG_CONFIG(enableNativeBuffers, "%s:%u%s, %d", portString(portIndex), portIndex,
    -+                graphic ? ", graphic" : "", enable);
    -+    OMX_STRING name = const_cast<OMX_STRING>(
    -+            graphic ? "OMX.google.android.index.enableAndroidNativeBuffers"
    -+                    : "OMX.google.android.index.allocateNativeHandle");
    -+
    -+    OMX_INDEXTYPE index;
    -+    OMX_ERRORTYPE err = OMX_GetExtensionIndex(mHandle, name, &index);
    -+
    -+    if (err == OMX_ErrorNone) {
    -+        EnableAndroidNativeBuffersParams params;
    -+        InitOMXParams(&params);
    -+        params.nPortIndex = portIndex;
    -+        params.enable = enable;
    -+
    -+        err = OMX_SetParameter(mHandle, index, &params);
    -+        CLOG_IF_ERROR(setParameter, err, "%s(%#x): %s:%u en=%d", name, index,
    -+                      portString(portIndex), portIndex, enable);
    -+        if (!graphic) {
    -+            if (err == OMX_ErrorNone) {
    -+                mSecureBufferType[portIndex] =
    -+                    enable ? kSecureBufferTypeNativeHandle : kSecureBufferTypeOpaque;
    -+            } else if (mSecureBufferType[portIndex] == kSecureBufferTypeUnknown) {
    -+                mSecureBufferType[portIndex] = kSecureBufferTypeOpaque;
    -+            }
    -+        } else {
    -+            if (err == OMX_ErrorNone) {
    -+                mGraphicBufferEnabled[portIndex] = enable;
    -+            } else if (enable) {
    -+                mGraphicBufferEnabled[portIndex] = false;
    -+            }
    -+        }
    -+    } else {
    -+        CLOG_ERROR_IF(enable, getExtensionIndex, err, "%s", name);
    -+        if (!graphic) {
    -+            // Extension not supported, check for manual override with system property
    -+            // This is a temporary workaround until partners support the OMX extension
    -+            char value[PROPERTY_VALUE_MAX];
    -+            if (property_get("media.mediadrmservice.enable", value, NULL)
    -+                && (!strcmp("1", value) || !strcasecmp("true", value))) {
    -+                CLOG_CONFIG(enableNativeBuffers, "system property override: using native-handles");
    -+                mSecureBufferType[portIndex] = kSecureBufferTypeNativeHandle;
    -+            } else if (mSecureBufferType[portIndex] == kSecureBufferTypeUnknown) {
    -+                mSecureBufferType[portIndex] = kSecureBufferTypeOpaque;
    -+            }
    -+            err = OMX_ErrorNone;
    -+        }
    -+    }
    -+
    -+    return StatusFromOMXError(err);
    -+}
    -+
    -+status_t OMXNodeInstance::getGraphicBufferUsage(
    -+        OMX_U32 portIndex, OMX_U32* usage) {
    -+    Mutex::Autolock autoLock(mLock);
    -+
    -+    OMX_INDEXTYPE index;
    -+    OMX_STRING name = const_cast<OMX_STRING>(
    -+            "OMX.google.android.index.getAndroidNativeBufferUsage");
    -+    OMX_ERRORTYPE err = OMX_GetExtensionIndex(mHandle, name, &index);
    -+
    -+    if (err != OMX_ErrorNone) {
    -+        CLOG_ERROR(getExtensionIndex, err, "%s", name);
    -+        return StatusFromOMXError(err);
    -+    }
    -+
    -+    GetAndroidNativeBufferUsageParams params;
    -+    InitOMXParams(&params);
    -+    params.nPortIndex = portIndex;
    -+
    -+    err = OMX_GetParameter(mHandle, index, &params);
    -+    if (err != OMX_ErrorNone) {
    -+        CLOG_ERROR(getParameter, err, "%s(%#x): %s:%u", name, index,
    -+                portString(portIndex), portIndex);
    -+        return StatusFromOMXError(err);
    -+    }
    -+
    -+    *usage = params.nUsage;
    -+
    -+    return OK;
    -+}
    -+
    -+status_t OMXNodeInstance::storeMetaDataInBuffers(
    -+        OMX_U32 portIndex, OMX_BOOL enable, MetadataBufferType *type) {
    -+    Mutex::Autolock autolock(mLock);
    -+    CLOG_CONFIG(storeMetaDataInBuffers, "%s:%u en:%d", portString(portIndex), portIndex, enable);
    -+    return storeMetaDataInBuffers_l(portIndex, enable, type);
    -+}
    -+
    -+status_t OMXNodeInstance::storeMetaDataInBuffers_l(
    -+        OMX_U32 portIndex, OMX_BOOL enable, MetadataBufferType *type) {
    -+    if (mSailed) {
    -+        android_errorWriteLog(0x534e4554, "29422020");
    -+        return INVALID_OPERATION;
    -+    }
    -+    if (portIndex != kPortIndexInput && portIndex != kPortIndexOutput) {
    -+        android_errorWriteLog(0x534e4554, "26324358");
    -+        if (type != NULL) {
    -+            *type = kMetadataBufferTypeInvalid;
    -+        }
    -+        return BAD_VALUE;
    -+    }
    -+
    -+    OMX_INDEXTYPE index;
    -+    OMX_STRING name = const_cast<OMX_STRING>(
    -+            "OMX.google.android.index.storeMetaDataInBuffers");
    -+
    -+    OMX_STRING nativeBufferName = const_cast<OMX_STRING>(
    -+            "OMX.google.android.index.storeANWBufferInMetadata");
    -+    MetadataBufferType negotiatedType;
    -+    MetadataBufferType requestedType = type != NULL ? *type : kMetadataBufferTypeANWBuffer;
    -+
    -+    StoreMetaDataInBuffersParams params;
    -+    InitOMXParams(&params);
    -+    params.nPortIndex = portIndex;
    -+    params.bStoreMetaData = enable;
    -+
    -+    OMX_ERRORTYPE err =
    -+        requestedType == kMetadataBufferTypeANWBuffer
    -+                ? OMX_GetExtensionIndex(mHandle, nativeBufferName, &index)
    -+                : OMX_ErrorUnsupportedIndex;
    -+    OMX_ERRORTYPE xerr = err;
    -+    if (err == OMX_ErrorNone) {
    -+        err = OMX_SetParameter(mHandle, index, &params);
    -+        if (err == OMX_ErrorNone) {
    -+            name = nativeBufferName; // set name for debugging
    -+            negotiatedType = requestedType;
    -+        }
    -+    }
    -+    if (err != OMX_ErrorNone) {
    -+        err = OMX_GetExtensionIndex(mHandle, name, &index);
    -+        xerr = err;
    -+        if (err == OMX_ErrorNone) {
    -+            negotiatedType =
    -+                requestedType == kMetadataBufferTypeANWBuffer
    -+                        ? kMetadataBufferTypeGrallocSource : requestedType;
    -+            err = OMX_SetParameter(mHandle, index, &params);
    -+        }
    -+    }
    -+
    -+    // don't log loud error if component does not support metadata mode on the output
    -+    if (err != OMX_ErrorNone) {
    -+        if (err == OMX_ErrorUnsupportedIndex && portIndex == kPortIndexOutput) {
    -+            CLOGW("component does not support metadata mode; using fallback");
    -+        } else if (xerr != OMX_ErrorNone) {
    -+            CLOG_ERROR(getExtensionIndex, xerr, "%s", name);
    -+        } else {
    -+            CLOG_ERROR(setParameter, err, "%s(%#x): %s:%u en=%d type=%d", name, index,
    -+                    portString(portIndex), portIndex, enable, negotiatedType);
    -+        }
    -+        negotiatedType = mMetadataType[portIndex];
    -+    } else {
    -+        if (!enable) {
    -+            negotiatedType = kMetadataBufferTypeInvalid;
    -+        }
    -+        mMetadataType[portIndex] = negotiatedType;
    -+    }
    -+    CLOG_CONFIG(storeMetaDataInBuffers, "%s:%u %srequested %s:%d negotiated %s:%d",
    -+            portString(portIndex), portIndex, enable ? "" : "UN",
    -+            asString(requestedType), requestedType, asString(negotiatedType), negotiatedType);
    -+
    -+    if (type != NULL) {
    -+        *type = negotiatedType;
    -+    }
    -+
    -+    return StatusFromOMXError(err);
    -+}
    -+
    -+status_t OMXNodeInstance::prepareForAdaptivePlayback(
    -+        OMX_U32 portIndex, OMX_BOOL enable, OMX_U32 maxFrameWidth,
    -+        OMX_U32 maxFrameHeight) {
    -+    Mutex::Autolock autolock(mLock);
    -+    if (mSailed) {
    -+        android_errorWriteLog(0x534e4554, "29422020");
    -+        return INVALID_OPERATION;
    -+    }
    -+    CLOG_CONFIG(prepareForAdaptivePlayback, "%s:%u en=%d max=%ux%u",
    -+            portString(portIndex), portIndex, enable, maxFrameWidth, maxFrameHeight);
    -+
    -+    OMX_INDEXTYPE index;
    -+    OMX_STRING name = const_cast<OMX_STRING>(
    -+            "OMX.google.android.index.prepareForAdaptivePlayback");
    -+
    -+    OMX_ERRORTYPE err = OMX_GetExtensionIndex(mHandle, name, &index);
    -+    if (err != OMX_ErrorNone) {
    -+        CLOG_ERROR_IF(enable, getExtensionIndex, err, "%s", name);
    -+        return StatusFromOMXError(err);
    -+    }
    -+
    -+    PrepareForAdaptivePlaybackParams params;
    -+    InitOMXParams(&params);
    -+    params.nPortIndex = portIndex;
    -+    params.bEnable = enable;
    -+    params.nMaxFrameWidth = maxFrameWidth;
    -+    params.nMaxFrameHeight = maxFrameHeight;
    -+
    -+    err = OMX_SetParameter(mHandle, index, &params);
    -+    CLOG_IF_ERROR(setParameter, err, "%s(%#x): %s:%u en=%d max=%ux%u", name, index,
    -+            portString(portIndex), portIndex, enable, maxFrameWidth, maxFrameHeight);
    -+    return StatusFromOMXError(err);
    -+}
    -+
    -+status_t OMXNodeInstance::configureVideoTunnelMode(
    -+        OMX_U32 portIndex, OMX_BOOL tunneled, OMX_U32 audioHwSync,
    -+        native_handle_t **sidebandHandle) {
    -+    Mutex::Autolock autolock(mLock);
    -+    if (mSailed) {
    -+        android_errorWriteLog(0x534e4554, "29422020");
    -+        return INVALID_OPERATION;
    -+    }
    -+    CLOG_CONFIG(configureVideoTunnelMode, "%s:%u tun=%d sync=%u",
    -+            portString(portIndex), portIndex, tunneled, audioHwSync);
    -+
    -+    OMX_INDEXTYPE index;
    -+    OMX_STRING name = const_cast<OMX_STRING>(
    -+            "OMX.google.android.index.configureVideoTunnelMode");
    -+
    -+    OMX_ERRORTYPE err = OMX_GetExtensionIndex(mHandle, name, &index);
    -+    if (err != OMX_ErrorNone) {
    -+        CLOG_ERROR_IF(tunneled, getExtensionIndex, err, "%s", name);
    -+        return StatusFromOMXError(err);
    -+    }
    -+
    -+    ConfigureVideoTunnelModeParams tunnelParams;
    -+    InitOMXParams(&tunnelParams);
    -+    tunnelParams.nPortIndex = portIndex;
    -+    tunnelParams.bTunneled = tunneled;
    -+    tunnelParams.nAudioHwSync = audioHwSync;
    -+    err = OMX_SetParameter(mHandle, index, &tunnelParams);
    -+    if (err != OMX_ErrorNone) {
    -+        CLOG_ERROR(setParameter, err, "%s(%#x): %s:%u tun=%d sync=%u", name, index,
    -+                portString(portIndex), portIndex, tunneled, audioHwSync);
    -+        return StatusFromOMXError(err);
    -+    }
    -+
    -+    err = OMX_GetParameter(mHandle, index, &tunnelParams);
    -+    if (err != OMX_ErrorNone) {
    -+        CLOG_ERROR(getParameter, err, "%s(%#x): %s:%u tun=%d sync=%u", name, index,
    -+                portString(portIndex), portIndex, tunneled, audioHwSync);
    -+        return StatusFromOMXError(err);
    -+    }
    -+    if (sidebandHandle) {
    -+        *sidebandHandle = (native_handle_t*)tunnelParams.pSidebandWindow;
    -+    }
    -+
    -+    return OK;
    -+}
    -+
    -+status_t OMXNodeInstance::useBuffer(
    -+        OMX_U32 portIndex, const sp<IMemory> &params,
    -+        OMX::buffer_id *buffer, OMX_U32 allottedSize) {
    -+    if (params == NULL || buffer == NULL) {
    -+        ALOGE("b/25884056");
    -+        return BAD_VALUE;
    -+    }
    -+
    -+    Mutex::Autolock autoLock(mLock);
    -+    if (allottedSize > params->size() || portIndex >= NELEM(mNumPortBuffers)) {
    -+        return BAD_VALUE;
    -+    }
    -+
    -+    if (!mSailed) {
    -+        ALOGE("b/35467458");
    -+        android_errorWriteLog(0x534e4554, "35467458");
    -+        return BAD_VALUE;
    -+    }
    -+
    -+<<<<<<< HEAD
    -+    // metadata buffers are not connected cross process
    -+    // use a backup buffer instead of the actual buffer
    -+    BufferMeta *buffer_meta;
    -+#ifdef CAMCORDER_GRALLOC_SOURCE
    -+    bool useBackup = false;
    -+#else
    -+    bool useBackup = mMetadataType[portIndex] != kMetadataBufferTypeInvalid;
    -+#endif
    -+    OMX_U8 *data = static_cast<OMX_U8 *>(params->pointer());
    -+    // allocate backup buffer
    -+    if (useBackup) {
    -+        data = new (std::nothrow) OMX_U8[allottedSize];
    -+        if (data == NULL) {
    -+            return NO_MEMORY;
    -+=======
    -+    switch (omxBuffer.mBufferType) {
    -+        case OMXBuffer::kBufferTypePreset:
    -+            return useBuffer_l(portIndex, NULL, NULL, buffer);
    -+
    -+        case OMXBuffer::kBufferTypeSharedMem:
    -+            return useBuffer_l(portIndex, omxBuffer.mMem, NULL, buffer);
    -+
    -+        case OMXBuffer::kBufferTypeANWBuffer:
    -+            return useGraphicBuffer_l(portIndex, omxBuffer.mGraphicBuffer, buffer);
    -+
    -+        case OMXBuffer::kBufferTypeHidlMemory: {
    -+                sp<IHidlMemory> hidlMemory = mapMemory(omxBuffer.mHidlMemory);
    -+                return useBuffer_l(portIndex, NULL, hidlMemory, buffer);
    -+            }
    -+        default:
    -+            break;
    -+    }
    -+
    -+    return BAD_VALUE;
    -+}
    -+
    -+status_t OMXNodeInstance::useBuffer_l(
    -+        OMX_U32 portIndex, const sp<IMemory> &params,
    -+        const sp<IHidlMemory> &hParams, IOMX::buffer_id *buffer) {
    -+
    -+    BufferMeta *buffer_meta;
    -+    OMX_BUFFERHEADERTYPE *header;
    -+    OMX_ERRORTYPE err = OMX_ErrorNone;
    -+    bool isMetadata = mMetadataType[portIndex] != kMetadataBufferTypeInvalid;
    -+
    -+    if (!isMetadata && mGraphicBufferEnabled[portIndex]) {
    -+        ALOGE("b/62948670");
    -+        android_errorWriteLog(0x534e4554, "62948670");
    -+        return INVALID_OPERATION;
    -+    }
    -+
    -+    size_t paramsSize;
    -+    void* paramsPointer;
    -+    if (params != NULL && hParams != NULL) {
    -+        return BAD_VALUE;
    -+    }
    -+    if (params != NULL) {
    -+        paramsPointer = params->pointer();
    -+        paramsSize = params->size();
    -+    } else if (hParams != NULL) {
    -+        paramsPointer = hParams->getPointer();
    -+        paramsSize = hParams->getSize();
    -+    } else {
    -+        paramsPointer = nullptr;
    -+    }
    -+
    -+    OMX_U32 allottedSize;
    -+    if (isMetadata) {
    -+        if (mMetadataType[portIndex] == kMetadataBufferTypeGrallocSource) {
    -+            allottedSize = sizeof(VideoGrallocMetadata);
    -+        } else if (mMetadataType[portIndex] == kMetadataBufferTypeANWBuffer) {
    -+            allottedSize = sizeof(VideoNativeMetadata);
    -+        } else if (mMetadataType[portIndex] == kMetadataBufferTypeNativeHandleSource) {
    -+            allottedSize = sizeof(VideoNativeHandleMetadata);
    -+        } else {
    -+            return BAD_VALUE;
    -+>>>>>>> f630233... Track graphic buffer mode in OMXNodeInstance
    -+        }
    -+        memset(data, 0, allottedSize);
    -+
    -+        buffer_meta = new BufferMeta(
    -+                params, portIndex, false /* copyToOmx */, false /* copyFromOmx */, data);
    -+    } else {
    -+        buffer_meta = new BufferMeta(
    -+                params, portIndex, false /* copyToOmx */, false /* copyFromOmx */, NULL);
    -+    }
    -+
    -+    OMX_BUFFERHEADERTYPE *header;
    -+
    -+    OMX_ERRORTYPE err = OMX_UseBuffer(
    -+            mHandle, &header, portIndex, buffer_meta,
    -+            allottedSize, data);
    -+
    -+    if (err != OMX_ErrorNone) {
    -+        CLOG_ERROR(useBuffer, err, SIMPLE_BUFFER(
    -+                portIndex, (size_t)allottedSize, data));
    -+
    -+        delete buffer_meta;
    -+        buffer_meta = NULL;
    -+
    -+        *buffer = 0;
    -+
    -+        return StatusFromOMXError(err);
    -+    }
    -+
    -+    CHECK_EQ(header->pAppPrivate, buffer_meta);
    -+
    -+    *buffer = makeBufferID(header);
    -+
    -+    addActiveBuffer(portIndex, *buffer);
    -+
    -+    sp<GraphicBufferSource> bufferSource(getGraphicBufferSource());
    -+    if (bufferSource != NULL && portIndex == kPortIndexInput) {
    -+        bufferSource->addCodecBuffer(header);
    -+    }
    -+
    -+    CLOG_BUFFER(useBuffer, NEW_BUFFER_FMT(
    -+            *buffer, portIndex, "%u(%zu)@%p", allottedSize, params->size(), params->pointer()));
    -+    return OK;
    -+}
    -+
    -+status_t OMXNodeInstance::useGraphicBuffer2_l(
    -+        OMX_U32 portIndex, const sp<GraphicBuffer>& graphicBuffer,
    -+        OMX::buffer_id *buffer) {
    -+    if (graphicBuffer == NULL || buffer == NULL) {
    -+        ALOGE("b/25884056");
    -+        return BAD_VALUE;
    -+    }
    -+
    -+    // port definition
    -+    OMX_PARAM_PORTDEFINITIONTYPE def;
    -+    InitOMXParams(&def);
    -+    def.nPortIndex = portIndex;
    -+    OMX_ERRORTYPE err = OMX_GetParameter(mHandle, OMX_IndexParamPortDefinition, &def);
    -+    if (err != OMX_ErrorNone) {
    -+        OMX_INDEXTYPE index = OMX_IndexParamPortDefinition;
    -+        CLOG_ERROR(getParameter, err, "%s(%#x): %s:%u",
    -+                asString(index), index, portString(portIndex), portIndex);
    -+        return UNKNOWN_ERROR;
    -+    }
    -+
    -+    BufferMeta *bufferMeta = new BufferMeta(graphicBuffer, portIndex);
    -+
    -+    OMX_BUFFERHEADERTYPE *header = NULL;
    -+    OMX_U8* bufferHandle = const_cast<OMX_U8*>(
    -+            reinterpret_cast<const OMX_U8*>(graphicBuffer->handle));
    -+
    -+    err = OMX_UseBuffer(
    -+            mHandle,
    -+            &header,
    -+            portIndex,
    -+            bufferMeta,
    -+            def.nBufferSize,
    -+            bufferHandle);
    -+
    -+    if (err != OMX_ErrorNone) {
    -+        CLOG_ERROR(useBuffer, err, BUFFER_FMT(portIndex, "%u@%p", def.nBufferSize, bufferHandle));
    -+        delete bufferMeta;
    -+        bufferMeta = NULL;
    -+        *buffer = 0;
    -+        return StatusFromOMXError(err);
    -+    }
    -+
    -+    CHECK_EQ(header->pBuffer, bufferHandle);
    -+    CHECK_EQ(header->pAppPrivate, bufferMeta);
    -+
    -+    *buffer = makeBufferID(header);
    -+
    -+    addActiveBuffer(portIndex, *buffer);
    -+    CLOG_BUFFER(useGraphicBuffer2, NEW_BUFFER_FMT(
    -+            *buffer, portIndex, "%u@%p", def.nBufferSize, bufferHandle));
    -+    return OK;
    -+}
    -+
    -+// XXX: This function is here for backwards compatibility.  Once the OMX
    -+// implementations have been updated this can be removed and useGraphicBuffer2
    -+// can be renamed to useGraphicBuffer.
    -+status_t OMXNodeInstance::useGraphicBuffer(
    -+        OMX_U32 portIndex, const sp<GraphicBuffer>& graphicBuffer,
    -+        OMX::buffer_id *buffer) {
    -+    if (graphicBuffer == NULL || buffer == NULL) {
    -+        ALOGE("b/25884056");
    -+        return BAD_VALUE;
    -+    }
    -+    Mutex::Autolock autoLock(mLock);
    -+
    -+    if (!mGraphicBufferEnabled[portIndex]) {
    -+        // Report error if this is not in graphic buffer mode.
    -+        ALOGE("b/62948670");
    -+        android_errorWriteLog(0x534e4554, "62948670");
    -+        return INVALID_OPERATION;
    -+    }
    -+
    -+    // See if the newer version of the extension is present.
    -+    OMX_INDEXTYPE index;
    -+    if (OMX_GetExtensionIndex(
    -+            mHandle,
    -+            const_cast<OMX_STRING>("OMX.google.android.index.useAndroidNativeBuffer2"),
    -+            &index) == OMX_ErrorNone) {
    -+        return useGraphicBuffer2_l(portIndex, graphicBuffer, buffer);
    -+    }
    -+
    -+    OMX_STRING name = const_cast<OMX_STRING>(
    -+        "OMX.google.android.index.useAndroidNativeBuffer");
    -+    OMX_ERRORTYPE err = OMX_GetExtensionIndex(mHandle, name, &index);
    -+    if (err != OMX_ErrorNone) {
    -+        CLOG_ERROR(getExtensionIndex, err, "%s", name);
    -+        return StatusFromOMXError(err);
    -+    }
    -+
    -+    BufferMeta *bufferMeta = new BufferMeta(graphicBuffer, portIndex);
    -+
    -+    OMX_BUFFERHEADERTYPE *header;
    -+
    -+    OMX_VERSIONTYPE ver;
    -+    ver.s.nVersionMajor = 1;
    -+    ver.s.nVersionMinor = 0;
    -+    ver.s.nRevision = 0;
    -+    ver.s.nStep = 0;
    -+    UseAndroidNativeBufferParams params = {
    -+        sizeof(UseAndroidNativeBufferParams), ver, portIndex, bufferMeta,
    -+        &header, graphicBuffer,
    -+    };
    -+
    -+    err = OMX_SetParameter(mHandle, index, &params);
    -+
    -+    if (err != OMX_ErrorNone) {
    -+        CLOG_ERROR(setParameter, err, "%s(%#x): %s:%u meta=%p GB=%p", name, index,
    -+                portString(portIndex), portIndex, bufferMeta, graphicBuffer->handle);
    -+
    -+        delete bufferMeta;
    -+        bufferMeta = NULL;
    -+
    -+        *buffer = 0;
    -+
    -+        return StatusFromOMXError(err);
    -+    }
    -+
    -+    CHECK_EQ(header->pAppPrivate, bufferMeta);
    -+
    -+    *buffer = makeBufferID(header);
    -+
    -+    addActiveBuffer(portIndex, *buffer);
    -+    CLOG_BUFFER(useGraphicBuffer, NEW_BUFFER_FMT(
    -+            *buffer, portIndex, "GB=%p", graphicBuffer->handle));
    -+    return OK;
    -+}
    -+
    -+status_t OMXNodeInstance::updateGraphicBufferInMeta_l(
    -+        OMX_U32 portIndex, const sp<GraphicBuffer>& graphicBuffer,
    -+        OMX::buffer_id buffer, OMX_BUFFERHEADERTYPE *header, bool updateCodecBuffer) {
    -+    // No need to check |graphicBuffer| since NULL is valid for it as below.
    -+    if (header == NULL) {
    -+        ALOGE("b/25884056");
    -+        return BAD_VALUE;
    -+    }
    -+
    -+    if (portIndex != kPortIndexInput && portIndex != kPortIndexOutput) {
    -+        return BAD_VALUE;
    -+    }
    -+
    -+    BufferMeta *bufferMeta = (BufferMeta *)(header->pAppPrivate);
    -+    sp<ABuffer> data = bufferMeta->getBuffer(
    -+            header, !updateCodecBuffer /* backup */, false /* limit */);
    -+    bufferMeta->setGraphicBuffer(graphicBuffer);
    -+    MetadataBufferType metaType = mMetadataType[portIndex];
    -+    // we use gralloc source only in the codec buffers
    -+    if (metaType == kMetadataBufferTypeGrallocSource && !updateCodecBuffer) {
    -+        metaType = kMetadataBufferTypeANWBuffer;
    -+    }
    -+    if (metaType == kMetadataBufferTypeGrallocSource
    -+            && data->capacity() >= sizeof(VideoGrallocMetadata)) {
    -+        VideoGrallocMetadata &metadata = *(VideoGrallocMetadata *)(data->data());
    -+        metadata.eType = kMetadataBufferTypeGrallocSource;
    -+        metadata.pHandle = graphicBuffer == NULL ? NULL : graphicBuffer->handle;
    -+    } else if (metaType == kMetadataBufferTypeANWBuffer
    -+            && data->capacity() >= sizeof(VideoNativeMetadata)) {
    -+        VideoNativeMetadata &metadata = *(VideoNativeMetadata *)(data->data());
    -+        metadata.eType = kMetadataBufferTypeANWBuffer;
    -+        metadata.pBuffer = graphicBuffer == NULL ? NULL : graphicBuffer->getNativeBuffer();
    -+        metadata.nFenceFd = -1;
    -+    } else {
    -+        CLOG_ERROR(updateGraphicBufferInMeta, BAD_VALUE, "%s:%u, %#x bad type (%d) or size (%u)",
    -+            portString(portIndex), portIndex, buffer, mMetadataType[portIndex], header->nAllocLen);
    -+        return BAD_VALUE;
    -+    }
    -+
    -+    CLOG_BUFFER(updateGraphicBufferInMeta, "%s:%u, %#x := %p",
    -+            portString(portIndex), portIndex, buffer,
    -+            graphicBuffer == NULL ? NULL : graphicBuffer->handle);
    -+    return OK;
    -+}
    -+
    -+status_t OMXNodeInstance::updateGraphicBufferInMeta(
    -+        OMX_U32 portIndex, const sp<GraphicBuffer>& graphicBuffer,
    -+        OMX::buffer_id buffer) {
    -+    Mutex::Autolock autoLock(mLock);
    -+    OMX_BUFFERHEADERTYPE *header = findBufferHeader(buffer, portIndex);
    -+    // update backup buffer for input, codec buffer for output
    -+    return updateGraphicBufferInMeta_l(
    -+            portIndex, graphicBuffer, buffer, header,
    -+            true /* updateCodecBuffer */);
    -+}
    -+
    -+status_t OMXNodeInstance::updateNativeHandleInMeta(
    -+        OMX_U32 portIndex, const sp<NativeHandle>& nativeHandle, OMX::buffer_id buffer) {
    -+    Mutex::Autolock autoLock(mLock);
    -+    OMX_BUFFERHEADERTYPE *header = findBufferHeader(buffer, portIndex);
    -+    // No need to check |nativeHandle| since NULL is valid for it as below.
    -+    if (header == NULL) {
    -+        ALOGE("b/25884056");
    -+        return BAD_VALUE;
    -+    }
    -+
    -+    if (portIndex != kPortIndexInput && portIndex != kPortIndexOutput) {
    -+        return BAD_VALUE;
    -+    }
    -+
    -+    BufferMeta *bufferMeta = (BufferMeta *)(header->pAppPrivate);
    -+    // update backup buffer
    -+    sp<ABuffer> data = bufferMeta->getBuffer(
    -+            header, false /* backup */, false /* limit */);
    -+    bufferMeta->setNativeHandle(nativeHandle);
    -+    if (mMetadataType[portIndex] == kMetadataBufferTypeNativeHandleSource
    -+            && data->capacity() >= sizeof(VideoNativeHandleMetadata)) {
    -+        VideoNativeHandleMetadata &metadata = *(VideoNativeHandleMetadata *)(data->data());
    -+        metadata.eType = mMetadataType[portIndex];
    -+        metadata.pHandle =
    -+            nativeHandle == NULL ? NULL : const_cast<native_handle*>(nativeHandle->handle());
    -+    } else {
    -+        CLOG_ERROR(updateNativeHandleInMeta, BAD_VALUE, "%s:%u, %#x bad type (%d) or size (%zu)",
    -+            portString(portIndex), portIndex, buffer, mMetadataType[portIndex], data->capacity());
    -+        return BAD_VALUE;
    -+    }
    -+
    -+    CLOG_BUFFER(updateNativeHandleInMeta, "%s:%u, %#x := %p",
    -+            portString(portIndex), portIndex, buffer,
    -+            nativeHandle == NULL ? NULL : nativeHandle->handle());
    -+    return OK;
    -+}
    -+
    -+status_t OMXNodeInstance::createGraphicBufferSource(
    -+        OMX_U32 portIndex, sp<IGraphicBufferConsumer> bufferConsumer, MetadataBufferType *type) {
    -+    status_t err;
    -+
    -+    // only allow graphic source on input port, when there are no allocated buffers yet
    -+    if (portIndex != kPortIndexInput) {
    -+        android_errorWriteLog(0x534e4554, "29422020");
    -+        return BAD_VALUE;
    -+    } else if (mNumPortBuffers[portIndex] > 0) {
    -+        android_errorWriteLog(0x534e4554, "29422020");
    -+        return INVALID_OPERATION;
    -+    }
    -+
    -+    const sp<GraphicBufferSource> surfaceCheck = getGraphicBufferSource();
    -+    if (surfaceCheck != NULL) {
    -+        if (portIndex < NELEM(mMetadataType) && type != NULL) {
    -+            *type = mMetadataType[portIndex];
    -+        }
    -+        return ALREADY_EXISTS;
    -+    }
    -+
    -+    // Input buffers will hold meta-data (ANativeWindowBuffer references).
    -+    if (type != NULL) {
    -+        *type = kMetadataBufferTypeANWBuffer;
    -+    }
    -+    err = storeMetaDataInBuffers_l(portIndex, OMX_TRUE, type);
    -+    if (err != OK) {
    -+        return err;
    -+    }
    -+
    -+    // Retrieve the width and height of the graphic buffer, set when the
    -+    // codec was configured.
    -+    OMX_PARAM_PORTDEFINITIONTYPE def;
    -+    InitOMXParams(&def);
    -+    def.nPortIndex = portIndex;
    -+    OMX_ERRORTYPE oerr = OMX_GetParameter(
    -+            mHandle, OMX_IndexParamPortDefinition, &def);
    -+    if (oerr != OMX_ErrorNone) {
    -+        OMX_INDEXTYPE index = OMX_IndexParamPortDefinition;
    -+        CLOG_ERROR(getParameter, oerr, "%s(%#x): %s:%u",
    -+                asString(index), index, portString(portIndex), portIndex);
    -+        return UNKNOWN_ERROR;
    -+    }
    -+
    -+    if (def.format.video.eColorFormat != OMX_COLOR_FormatAndroidOpaque) {
    -+        CLOGW("createInputSurface requires COLOR_FormatSurface "
    -+                "(AndroidOpaque) color format instead of %s(%#x)",
    -+                asString(def.format.video.eColorFormat), def.format.video.eColorFormat);
    -+        return INVALID_OPERATION;
    -+    }
    -+
    -+    uint32_t usageBits;
    -+    oerr = OMX_GetParameter(
    -+            mHandle, (OMX_INDEXTYPE)OMX_IndexParamConsumerUsageBits, &usageBits);
    -+    if (oerr != OMX_ErrorNone) {
    -+        usageBits = 0;
    -+    }
    -+
    -+    sp<GraphicBufferSource> bufferSource = new GraphicBufferSource(this,
    -+            def.format.video.nFrameWidth,
    -+            def.format.video.nFrameHeight,
    -+            def.nBufferCountActual,
    -+            usageBits,
    -+            bufferConsumer);
    -+
    -+    if ((err = bufferSource->init()) != OK) {
    -+        return err;
    -+    }
    -+    setGraphicBufferSource(bufferSource);
    -+
    -+    return OK;
    -+}
    -+
    -+status_t OMXNodeInstance::createInputSurface(
    -+        OMX_U32 portIndex, android_dataspace dataSpace,
    -+        sp<IGraphicBufferProducer> *bufferProducer, MetadataBufferType *type) {
    -+    if (bufferProducer == NULL) {
    -+        ALOGE("b/25884056");
    -+        return BAD_VALUE;
    -+    }
    -+
    -+    Mutex::Autolock autolock(mLock);
    -+    status_t err = createGraphicBufferSource(portIndex, NULL /* bufferConsumer */, type);
    -+
    -+    if (err != OK) {
    -+        return err;
    -+    }
    -+
    -+    mGraphicBufferSource->setDefaultDataSpace(dataSpace);
    -+
    -+    *bufferProducer = mGraphicBufferSource->getIGraphicBufferProducer();
    -+    return OK;
    -+}
    -+
    -+//static
    -+status_t OMXNodeInstance::createPersistentInputSurface(
    -+        sp<IGraphicBufferProducer> *bufferProducer,
    -+        sp<IGraphicBufferConsumer> *bufferConsumer) {
    -+    if (bufferProducer == NULL || bufferConsumer == NULL) {
    -+        ALOGE("b/25884056");
    -+        return BAD_VALUE;
    -+    }
    -+    String8 name("GraphicBufferSource");
    -+
    -+    sp<IGraphicBufferProducer> producer;
    -+    sp<IGraphicBufferConsumer> consumer;
    -+    BufferQueue::createBufferQueue(&producer, &consumer);
    -+    consumer->setConsumerName(name);
    -+    consumer->setConsumerUsageBits(GRALLOC_USAGE_HW_VIDEO_ENCODER);
    -+
    -+    sp<BufferQueue::ProxyConsumerListener> proxy =
    -+        new BufferQueue::ProxyConsumerListener(NULL);
    -+    status_t err = consumer->consumerConnect(proxy, false);
    -+    if (err != NO_ERROR) {
    -+        ALOGE("Error connecting to BufferQueue: %s (%d)",
    -+                strerror(-err), err);
    -+        return err;
    -+    }
    -+
    -+    *bufferProducer = producer;
    -+    *bufferConsumer = consumer;
    -+
    -+    return OK;
    -+}
    -+
    -+status_t OMXNodeInstance::setInputSurface(
    -+        OMX_U32 portIndex, const sp<IGraphicBufferConsumer> &bufferConsumer,
    -+        MetadataBufferType *type) {
    -+    Mutex::Autolock autolock(mLock);
    -+    return createGraphicBufferSource(portIndex, bufferConsumer, type);
    -+}
    -+
    -+void OMXNodeInstance::signalEvent(OMX_EVENTTYPE event, OMX_U32 arg1, OMX_U32 arg2) {
    -+    mOwner->OnEvent(mNodeID, event, arg1, arg2, NULL);
    -+}
    -+
    -+status_t OMXNodeInstance::signalEndOfInputStream() {
    -+    // For non-Surface input, the MediaCodec should convert the call to a
    -+    // pair of requests (dequeue input buffer, queue input buffer with EOS
    -+    // flag set).  Seems easier than doing the equivalent from here.
    -+    sp<GraphicBufferSource> bufferSource(getGraphicBufferSource());
    -+    if (bufferSource == NULL) {
    -+        CLOGW("signalEndOfInputStream can only be used with Surface input");
    -+        return INVALID_OPERATION;
    -+    }
    -+    return bufferSource->signalEndOfInputStream();
    -+}
    -+
    -+status_t OMXNodeInstance::allocateSecureBuffer(
    -+        OMX_U32 portIndex, size_t size, OMX::buffer_id *buffer,
    -+        void **buffer_data, sp<NativeHandle> *native_handle) {
    -+    if (buffer == NULL || buffer_data == NULL || native_handle == NULL) {
    -+        ALOGE("b/25884056");
    -+        return BAD_VALUE;
    -+    }
    -+
    -+    if (portIndex >= NELEM(mSecureBufferType)) {
    -+        ALOGE("b/31385713, portIndex(%u)", portIndex);
    -+        android_errorWriteLog(0x534e4554, "31385713");
    -+        return BAD_VALUE;
    -+    }
    -+
    -+    Mutex::Autolock autoLock(mLock);
    -+
    -+    if (!mSailed) {
    -+        ALOGE("b/35467458");
    -+        android_errorWriteLog(0x534e4554, "35467458");
    -+        return BAD_VALUE;
    -+    }
    -+
    -+    BufferMeta *buffer_meta = new BufferMeta(size, portIndex);
    -+
    -+    OMX_BUFFERHEADERTYPE *header;
    -+
    -+    OMX_ERRORTYPE err = OMX_AllocateBuffer(
    -+            mHandle, &header, portIndex, buffer_meta, size);
    -+
    -+    if (err != OMX_ErrorNone) {
    -+        CLOG_ERROR(allocateBuffer, err, BUFFER_FMT(portIndex, "%zu@", size));
    -+        delete buffer_meta;
    -+        buffer_meta = NULL;
    -+
    -+        *buffer = 0;
    -+
    -+        return StatusFromOMXError(err);
    -+    }
    -+
    -+    CHECK_EQ(header->pAppPrivate, buffer_meta);
    -+
    -+    *buffer = makeBufferID(header);
    -+    if (mSecureBufferType[portIndex] == kSecureBufferTypeNativeHandle) {
    -+        *buffer_data = NULL;
    -+        *native_handle = NativeHandle::create(
    -+                (native_handle_t *)header->pBuffer, false /* ownsHandle */);
    -+    } else {
    -+        *buffer_data = header->pBuffer;
    -+        *native_handle = NULL;
    -+    }
    -+
    -+    addActiveBuffer(portIndex, *buffer);
    -+
    -+    sp<GraphicBufferSource> bufferSource(getGraphicBufferSource());
    -+    if (bufferSource != NULL && portIndex == kPortIndexInput) {
    -+        bufferSource->addCodecBuffer(header);
    -+    }
    -+    CLOG_BUFFER(allocateSecureBuffer, NEW_BUFFER_FMT(
    -+            *buffer, portIndex, "%zu@%p:%p", size, *buffer_data,
    -+            *native_handle == NULL ? NULL : (*native_handle)->handle()));
    -+
    -+    return OK;
    -+}
    -+
    -+status_t OMXNodeInstance::allocateBufferWithBackup(
    -+        OMX_U32 portIndex, const sp<IMemory> &params,
    -+        OMX::buffer_id *buffer, OMX_U32 allottedSize) {
    -+    if (params == NULL || buffer == NULL) {
    -+        ALOGE("b/25884056");
    -+        return BAD_VALUE;
    -+    }
    -+
    -+    Mutex::Autolock autoLock(mLock);
    -+    if (allottedSize > params->size() || portIndex >= NELEM(mNumPortBuffers)) {
    -+        return BAD_VALUE;
    -+    }
    -+
    -+    if (!mSailed) {
    -+        ALOGE("b/35467458");
    -+        android_errorWriteLog(0x534e4554, "35467458");
    -+        return BAD_VALUE;
    -+    }
    -+
    -+    // metadata buffers are not connected cross process; only copy if not meta
    -+#ifdef CAMCORDER_GRALLOC_SOURCE
    -+    bool copy = true;
    -+#else
    -+    bool copy = mMetadataType[portIndex] == kMetadataBufferTypeInvalid;
    -+#endif
    -+
    -+    BufferMeta *buffer_meta = new BufferMeta(
    -+            params, portIndex,
    -+            (portIndex == kPortIndexInput) && copy /* copyToOmx */,
    -+            (portIndex == kPortIndexOutput) && copy /* copyFromOmx */,
    -+            NULL /* data */);
    -+
    -+    OMX_BUFFERHEADERTYPE *header;
    -+
    -+    OMX_ERRORTYPE err = OMX_AllocateBuffer(
    -+            mHandle, &header, portIndex, buffer_meta, allottedSize);
    -+    if (err != OMX_ErrorNone) {
    -+        CLOG_ERROR(allocateBufferWithBackup, err,
    -+                SIMPLE_BUFFER(portIndex, (size_t)allottedSize, params->pointer()));
    -+        delete buffer_meta;
    -+        buffer_meta = NULL;
    -+
    -+        *buffer = 0;
    -+
    -+        return StatusFromOMXError(err);
    -+    }
    -+
    -+    CHECK_EQ(header->pAppPrivate, buffer_meta);
    -+
    -+    *buffer = makeBufferID(header);
    -+
    -+    addActiveBuffer(portIndex, *buffer);
    -+
    -+    sp<GraphicBufferSource> bufferSource(getGraphicBufferSource());
    -+    if (bufferSource != NULL && portIndex == kPortIndexInput) {
    -+        bufferSource->addCodecBuffer(header);
    -+    }
    -+
    -+    CLOG_BUFFER(allocateBufferWithBackup, NEW_BUFFER_FMT(*buffer, portIndex, "%zu@%p :> %u@%p",
    -+            params->size(), params->pointer(), allottedSize, header->pBuffer));
    -+
    -+    return OK;
    -+}
    -+
    -+status_t OMXNodeInstance::freeBuffer(
    -+        OMX_U32 portIndex, OMX::buffer_id buffer) {
    -+    Mutex::Autolock autoLock(mLock);
    -+    CLOG_BUFFER(freeBuffer, "%s:%u %#x", portString(portIndex), portIndex, buffer);
    -+
    -+    removeActiveBuffer(portIndex, buffer);
    -+
    -+    OMX_BUFFERHEADERTYPE *header = findBufferHeader(buffer, portIndex);
    -+    if (header == NULL) {
    -+        ALOGE("b/25884056");
    -+        return BAD_VALUE;
    -+    }
    -+    BufferMeta *buffer_meta = static_cast<BufferMeta *>(header->pAppPrivate);
    -+
    -+    OMX_ERRORTYPE err = OMX_FreeBuffer(mHandle, portIndex, header);
    -+    CLOG_IF_ERROR(freeBuffer, err, "%s:%u %#x", portString(portIndex), portIndex, buffer);
    -+
    -+    delete buffer_meta;
    -+    buffer_meta = NULL;
    -+    invalidateBufferID(buffer);
    -+
    -+    return StatusFromOMXError(err);
    -+}
    -+
    -+status_t OMXNodeInstance::fillBuffer(OMX::buffer_id buffer, int fenceFd) {
    -+    Mutex::Autolock autoLock(mLock);
    -+
    -+    OMX_BUFFERHEADERTYPE *header = findBufferHeader(buffer, kPortIndexOutput);
    -+    if (header == NULL) {
    -+        ALOGE("b/25884056");
    -+        return BAD_VALUE;
    -+    }
    -+    header->nFilledLen = 0;
    -+    header->nOffset = 0;
    -+    header->nFlags = 0;
    -+
    -+    // meta now owns fenceFd
    -+    status_t res = storeFenceInMeta_l(header, fenceFd, kPortIndexOutput);
    -+    if (res != OK) {
    -+        CLOG_ERROR(fillBuffer::storeFenceInMeta, res, EMPTY_BUFFER(buffer, header, fenceFd));
    -+        return res;
    -+    }
    -+
    -+    {
    -+        Mutex::Autolock _l(mDebugLock);
    -+        mOutputBuffersWithCodec.add(header);
    -+        CLOG_BUMPED_BUFFER(fillBuffer, WITH_STATS(EMPTY_BUFFER(buffer, header, fenceFd)));
    -+    }
    -+
    -+    OMX_ERRORTYPE err = OMX_FillThisBuffer(mHandle, header);
    -+    if (err != OMX_ErrorNone) {
    -+        CLOG_ERROR(fillBuffer, err, EMPTY_BUFFER(buffer, header, fenceFd));
    -+        Mutex::Autolock _l(mDebugLock);
    -+        mOutputBuffersWithCodec.remove(header);
    -+    }
    -+    return StatusFromOMXError(err);
    -+}
    -+
    -+status_t OMXNodeInstance::emptyBuffer(
    -+        OMX::buffer_id buffer,
    -+        OMX_U32 rangeOffset, OMX_U32 rangeLength,
    -+        OMX_U32 flags, OMX_TICKS timestamp, int fenceFd) {
    -+    Mutex::Autolock autoLock(mLock);
    -+
    -+    // no emptybuffer if using input surface
    -+    if (getGraphicBufferSource() != NULL) {
    -+        android_errorWriteLog(0x534e4554, "29422020");
    -+        return INVALID_OPERATION;
    -+    }
    -+
    -+    OMX_BUFFERHEADERTYPE *header = findBufferHeader(buffer, kPortIndexInput);
    -+    if (header == NULL) {
    -+        ALOGE("b/25884056");
    -+        return BAD_VALUE;
    -+    }
    -+    BufferMeta *buffer_meta =
    -+        static_cast<BufferMeta *>(header->pAppPrivate);
    -+
    -+#ifndef CAMCORDER_GRALLOC_SOURCE
    -+    // set up proper filled length if component is configured for gralloc metadata mode
    -+    // ignore rangeOffset in this case (as client may be assuming ANW meta buffers).
    -+    if (mMetadataType[kPortIndexInput] == kMetadataBufferTypeGrallocSource) {
    -+        header->nFilledLen = rangeLength ? sizeof(VideoGrallocMetadata) : 0;
    -+#else
    -+    sp<ABuffer> backup = buffer_meta->getBuffer(header, true /* backup */, false /* limit */);
    -+    sp<ABuffer> codec = buffer_meta->getBuffer(header, false /* backup */, false /* limit */);
    -+
    -+    // convert incoming ANW meta buffers if component is configured for gralloc metadata mode
    -+    // ignore rangeOffset in this case
    -+    if (mMetadataType[kPortIndexInput] == kMetadataBufferTypeGrallocSource
    -+            && backup->capacity() >= sizeof(VideoNativeMetadata)
    -+            && codec->capacity() >= sizeof(VideoGrallocMetadata)
    -+            && ((VideoNativeMetadata *)backup->base())->eType
    -+                    == kMetadataBufferTypeANWBuffer) {
    -+        VideoNativeMetadata &backupMeta = *(VideoNativeMetadata *)backup->base();
    -+        VideoGrallocMetadata &codecMeta = *(VideoGrallocMetadata *)codec->base();
    -+        CLOG_BUFFER(emptyBuffer, "converting ANWB %p to handle %p",
    -+                backupMeta.pBuffer, backupMeta.pBuffer->handle);
    -+        codecMeta.pHandle = backupMeta.pBuffer != NULL ? backupMeta.pBuffer->handle : NULL;
    -+        codecMeta.eType = kMetadataBufferTypeGrallocSource;
    -+        header->nFilledLen = rangeLength ? sizeof(codecMeta) : 0;
    -+#endif
    -+        header->nOffset = 0;
    -+    } else {
    -+        // rangeLength and rangeOffset must be a subset of the allocated data in the buffer.
    -+        // corner case: we permit rangeOffset == end-of-buffer with rangeLength == 0.
    -+        if (rangeOffset > header->nAllocLen
    -+                || rangeLength > header->nAllocLen - rangeOffset) {
    -+            CLOG_ERROR(emptyBuffer, OMX_ErrorBadParameter, FULL_BUFFER(NULL, header, fenceFd));
    -+            if (fenceFd >= 0) {
    -+                ::close(fenceFd);
    -+            }
    -+            return BAD_VALUE;
    -+        }
    -+        header->nFilledLen = rangeLength;
    -+        header->nOffset = rangeOffset;
    -+
    -+        buffer_meta->CopyToOMX(header);
    -+    }
    -+
    -+    return emptyBuffer_l(header, flags, timestamp, (intptr_t)buffer, fenceFd);
    -+}
    -+
    -+// log queued buffer activity for the next few input and/or output frames
    -+// if logging at internal state level
    -+void OMXNodeInstance::bumpDebugLevel_l(size_t numInputBuffers, size_t numOutputBuffers) {
    -+    if (DEBUG == ADebug::kDebugInternalState) {
    -+        DEBUG_BUMP = ADebug::kDebugAll;
    -+        if (numInputBuffers > 0) {
    -+            mDebugLevelBumpPendingBuffers[kPortIndexInput] = numInputBuffers;
    -+        }
    -+        if (numOutputBuffers > 0) {
    -+            mDebugLevelBumpPendingBuffers[kPortIndexOutput] = numOutputBuffers;
    -+        }
    -+    }
    -+}
    -+
    -+void OMXNodeInstance::unbumpDebugLevel_l(size_t portIndex) {
    -+    if (mDebugLevelBumpPendingBuffers[portIndex]) {
    -+        --mDebugLevelBumpPendingBuffers[portIndex];
    -+    }
    -+    if (!mDebugLevelBumpPendingBuffers[0]
    -+            && !mDebugLevelBumpPendingBuffers[1]) {
    -+        DEBUG_BUMP = DEBUG;
    -+    }
    -+}
    -+
    -+status_t OMXNodeInstance::storeFenceInMeta_l(
    -+        OMX_BUFFERHEADERTYPE *header, int fenceFd, OMX_U32 portIndex) {
    -+    // propagate fence if component supports it; wait for it otherwise
    -+    OMX_U32 metaSize = portIndex == kPortIndexInput ? header->nFilledLen : header->nAllocLen;
    -+    if (mMetadataType[portIndex] == kMetadataBufferTypeANWBuffer
    -+            && metaSize >= sizeof(VideoNativeMetadata)) {
    -+        VideoNativeMetadata &nativeMeta = *(VideoNativeMetadata *)(header->pBuffer);
    -+        if (nativeMeta.nFenceFd >= 0) {
    -+            ALOGE("fence (%d) already exists in meta", nativeMeta.nFenceFd);
    -+            if (fenceFd >= 0) {
    -+                ::close(fenceFd);
    -+            }
    -+            return ALREADY_EXISTS;
    -+        }
    -+        nativeMeta.nFenceFd = fenceFd;
    -+    } else if (fenceFd >= 0) {
    -+        CLOG_BUFFER(storeFenceInMeta, "waiting for fence %d", fenceFd);
    -+        sp<Fence> fence = new Fence(fenceFd);
    -+        return fence->wait(IOMX::kFenceTimeoutMs);
    -+    }
    -+    return OK;
    -+}
    -+
    -+int OMXNodeInstance::retrieveFenceFromMeta_l(
    -+        OMX_BUFFERHEADERTYPE *header, OMX_U32 portIndex) {
    -+    OMX_U32 metaSize = portIndex == kPortIndexInput ? header->nAllocLen : header->nFilledLen;
    -+    int fenceFd = -1;
    -+    if (mMetadataType[portIndex] == kMetadataBufferTypeANWBuffer
    -+            && header->nAllocLen >= sizeof(VideoNativeMetadata)) {
    -+        VideoNativeMetadata &nativeMeta = *(VideoNativeMetadata *)(header->pBuffer);
    -+        if (nativeMeta.eType == kMetadataBufferTypeANWBuffer) {
    -+            fenceFd = nativeMeta.nFenceFd;
    -+            nativeMeta.nFenceFd = -1;
    -+        }
    -+        if (metaSize < sizeof(nativeMeta) && fenceFd >= 0) {
    -+            CLOG_ERROR(foundFenceInEmptyMeta, BAD_VALUE, FULL_BUFFER(
    -+                    NULL, header, nativeMeta.nFenceFd));
    -+            fenceFd = -1;
    -+        }
    -+    }
    -+    return fenceFd;
    -+}
    -+
    -+status_t OMXNodeInstance::emptyBuffer_l(
    -+        OMX_BUFFERHEADERTYPE *header, OMX_U32 flags, OMX_TICKS timestamp,
    -+        intptr_t debugAddr, int fenceFd) {
    -+    header->nFlags = flags;
    -+    header->nTimeStamp = timestamp;
    -+
    -+    status_t res = storeFenceInMeta_l(header, fenceFd, kPortIndexInput);
    -+    if (res != OK) {
    -+        CLOG_ERROR(emptyBuffer::storeFenceInMeta, res, WITH_STATS(
    -+                FULL_BUFFER(debugAddr, header, fenceFd)));
    -+        return res;
    -+    }
    -+
    -+    {
    -+        Mutex::Autolock _l(mDebugLock);
    -+        mInputBuffersWithCodec.add(header);
    -+
    -+        // bump internal-state debug level for 2 input frames past a buffer with CSD
    -+        if ((flags & OMX_BUFFERFLAG_CODECCONFIG) != 0) {
    -+            bumpDebugLevel_l(2 /* numInputBuffers */, 0 /* numOutputBuffers */);
    -+        }
    -+
    -+        CLOG_BUMPED_BUFFER(emptyBuffer, WITH_STATS(FULL_BUFFER(debugAddr, header, fenceFd)));
    -+    }
    -+
    -+    OMX_ERRORTYPE err = OMX_EmptyThisBuffer(mHandle, header);
    -+    CLOG_IF_ERROR(emptyBuffer, err, FULL_BUFFER(debugAddr, header, fenceFd));
    -+
    -+    {
    -+        Mutex::Autolock _l(mDebugLock);
    -+        if (err != OMX_ErrorNone) {
    -+            mInputBuffersWithCodec.remove(header);
    -+        } else if (!(flags & OMX_BUFFERFLAG_CODECCONFIG)) {
    -+            unbumpDebugLevel_l(kPortIndexInput);
    -+        }
    -+    }
    -+
    -+    return StatusFromOMXError(err);
    -+}
    -+
    -+// like emptyBuffer, but the data is already in header->pBuffer
    -+status_t OMXNodeInstance::emptyGraphicBuffer(
    -+        OMX_BUFFERHEADERTYPE *header, const sp<GraphicBuffer> &graphicBuffer,
    -+        OMX_U32 flags, OMX_TICKS timestamp, int fenceFd) {
    -+    if (header == NULL) {
    -+        ALOGE("b/25884056");
    -+        return BAD_VALUE;
    -+    }
    -+
    -+    Mutex::Autolock autoLock(mLock);
    -+    OMX::buffer_id buffer = findBufferID(header);
    -+    status_t err = updateGraphicBufferInMeta_l(
    -+            kPortIndexInput, graphicBuffer, buffer, header,
    -+            true /* updateCodecBuffer */);
    -+    if (err != OK) {
    -+        CLOG_ERROR(emptyGraphicBuffer, err, FULL_BUFFER(
    -+                (intptr_t)header->pBuffer, header, fenceFd));
    -+        return err;
    -+    }
    -+
    -+    header->nOffset = 0;
    -+    if (graphicBuffer == NULL) {
    -+        header->nFilledLen = 0;
    -+    } else if (mMetadataType[kPortIndexInput] == kMetadataBufferTypeGrallocSource) {
    -+        header->nFilledLen = sizeof(VideoGrallocMetadata);
    -+    } else {
    -+        header->nFilledLen = sizeof(VideoNativeMetadata);
    -+    }
    -+    return emptyBuffer_l(header, flags, timestamp, (intptr_t)header->pBuffer, fenceFd);
    -+}
    -+
    -+status_t OMXNodeInstance::getExtensionIndex(
    -+        const char *parameterName, OMX_INDEXTYPE *index) {
    -+    Mutex::Autolock autoLock(mLock);
    -+
    -+    OMX_ERRORTYPE err = OMX_GetExtensionIndex(
    -+            mHandle, const_cast<char *>(parameterName), index);
    -+
    -+    return StatusFromOMXError(err);
    -+}
    -+
    -+inline static const char *asString(IOMX::InternalOptionType i, const char *def = "??") {
    -+    switch (i) {
    -+        case IOMX::INTERNAL_OPTION_SUSPEND:           return "SUSPEND";
    -+        case IOMX::INTERNAL_OPTION_REPEAT_PREVIOUS_FRAME_DELAY:
    -+            return "REPEAT_PREVIOUS_FRAME_DELAY";
    -+        case IOMX::INTERNAL_OPTION_MAX_TIMESTAMP_GAP: return "MAX_TIMESTAMP_GAP";
    -+        case IOMX::INTERNAL_OPTION_MAX_FPS:           return "MAX_FPS";
    -+        case IOMX::INTERNAL_OPTION_START_TIME:        return "START_TIME";
    -+        case IOMX::INTERNAL_OPTION_TIME_LAPSE:        return "TIME_LAPSE";
    -+        case IOMX::INTERNAL_OPTION_TIME_OFFSET:       return "TIME_OFFSET";
    -+        default:                                      return def;
    -+    }
    -+}
    -+
    -+template<typename T>
    -+static bool getInternalOption(
    -+        const void *data, size_t size, T *out) {
    -+    if (size != sizeof(T)) {
    -+        return false;
    -+    }
    -+    *out = *(T*)data;
    -+    return true;
    -+}
    -+
    -+status_t OMXNodeInstance::setInternalOption(
    -+        OMX_U32 portIndex,
    -+        IOMX::InternalOptionType type,
    -+        const void *data,
    -+        size_t size) {
    -+    CLOG_CONFIG(setInternalOption, "%s(%d): %s:%u %zu@%p",
    -+            asString(type), type, portString(portIndex), portIndex, size, data);
    -+    switch (type) {
    -+        case IOMX::INTERNAL_OPTION_SUSPEND:
    -+        case IOMX::INTERNAL_OPTION_REPEAT_PREVIOUS_FRAME_DELAY:
    -+        case IOMX::INTERNAL_OPTION_MAX_TIMESTAMP_GAP:
    -+        case IOMX::INTERNAL_OPTION_MAX_FPS:
    -+        case IOMX::INTERNAL_OPTION_START_TIME:
    -+        case IOMX::INTERNAL_OPTION_TIME_LAPSE:
    -+        case IOMX::INTERNAL_OPTION_TIME_OFFSET:
    -+        case IOMX::INTERNAL_OPTION_COLOR_ASPECTS:
    -+        {
    -+            const sp<GraphicBufferSource> &bufferSource =
    -+                getGraphicBufferSource();
    -+
    -+            if (bufferSource == NULL || portIndex != kPortIndexInput) {
    -+                CLOGW("setInternalOption is only for Surface input");
    -+                return ERROR_UNSUPPORTED;
    -+            }
    -+
    -+            if (type == IOMX::INTERNAL_OPTION_SUSPEND) {
    -+                bool suspend;
    -+                if (!getInternalOption(data, size, &suspend)) {
    -+                    return INVALID_OPERATION;
    -+                }
    -+
    -+                CLOG_CONFIG(setInternalOption, "suspend=%d", suspend);
    -+                bufferSource->suspend(suspend);
    -+            } else if (type == IOMX::INTERNAL_OPTION_REPEAT_PREVIOUS_FRAME_DELAY) {
    -+                int64_t delayUs;
    -+                if (!getInternalOption(data, size, &delayUs)) {
    -+                    return INVALID_OPERATION;
    -+                }
    -+
    -+                CLOG_CONFIG(setInternalOption, "delayUs=%lld", (long long)delayUs);
    -+                return bufferSource->setRepeatPreviousFrameDelayUs(delayUs);
    -+            } else if (type == IOMX::INTERNAL_OPTION_TIME_OFFSET) {
    -+                int64_t timeOffsetUs;
    -+                if (!getInternalOption(data, size, &timeOffsetUs)) {
    -+                    return INVALID_OPERATION;
    -+                }
    -+                CLOG_CONFIG(setInternalOption, "bufferOffsetUs=%lld", (long long)timeOffsetUs);
    -+                return bufferSource->setInputBufferTimeOffset(timeOffsetUs);
    -+            } else if (type == IOMX::INTERNAL_OPTION_MAX_TIMESTAMP_GAP) {
    -+                int64_t maxGapUs;
    -+                if (!getInternalOption(data, size, &maxGapUs)) {
    -+                    return INVALID_OPERATION;
    -+                }
    -+
    -+                CLOG_CONFIG(setInternalOption, "gapUs=%lld", (long long)maxGapUs);
    -+                return bufferSource->setMaxTimestampGapUs(maxGapUs);
    -+            } else if (type == IOMX::INTERNAL_OPTION_MAX_FPS) {
    -+                float maxFps;
    -+                if (!getInternalOption(data, size, &maxFps)) {
    -+                    return INVALID_OPERATION;
    -+                }
    -+
    -+                CLOG_CONFIG(setInternalOption, "maxFps=%f", maxFps);
    -+                return bufferSource->setMaxFps(maxFps);
    -+            } else if (type == IOMX::INTERNAL_OPTION_START_TIME) {
    -+                int64_t skipFramesBeforeUs;
    -+                if (!getInternalOption(data, size, &skipFramesBeforeUs)) {
    -+                    return INVALID_OPERATION;
    -+                }
    -+
    -+                CLOG_CONFIG(setInternalOption, "beforeUs=%lld", (long long)skipFramesBeforeUs);
    -+                bufferSource->setSkipFramesBeforeUs(skipFramesBeforeUs);
    -+            } else if (type == IOMX::INTERNAL_OPTION_TIME_LAPSE) {
    -+                GraphicBufferSource::TimeLapseConfig config;
    -+                if (!getInternalOption(data, size, &config)) {
    -+                    return INVALID_OPERATION;
    -+                }
    -+
    -+                CLOG_CONFIG(setInternalOption, "perFrameUs=%lld perCaptureUs=%lld",
    -+                        (long long)config.mTimePerFrameUs, (long long)config.mTimePerCaptureUs);
    -+
    -+                return bufferSource->setTimeLapseConfig(config);
    -+            } else if (type == IOMX::INTERNAL_OPTION_COLOR_ASPECTS) {
    -+                ColorAspects aspects;
    -+                if (!getInternalOption(data, size, &aspects)) {
    -+                    return INVALID_OPERATION;
    -+                }
    -+
    -+                CLOG_CONFIG(setInternalOption, "setting color aspects");
    -+                bufferSource->setColorAspects(aspects);
    -+            }
    -+
    -+            return OK;
    -+        }
    -+
    -+        default:
    -+            return ERROR_UNSUPPORTED;
    -+    }
    -+}
    -+
    -+bool OMXNodeInstance::handleMessage(omx_message &msg) {
    -+    const sp<GraphicBufferSource>& bufferSource(getGraphicBufferSource());
    -+
    -+    if (msg.type == omx_message::FILL_BUFFER_DONE) {
    -+        OMX_BUFFERHEADERTYPE *buffer =
    -+            findBufferHeader(msg.u.extended_buffer_data.buffer, kPortIndexOutput);
    -+        if (buffer == NULL) {
    -+            ALOGE("b/25884056");
    -+            return false;
    -+        }
    -+
    -+        {
    -+            Mutex::Autolock _l(mDebugLock);
    -+            mOutputBuffersWithCodec.remove(buffer);
    -+
    -+            CLOG_BUMPED_BUFFER(
    -+                    FBD, WITH_STATS(FULL_BUFFER(
    -+                            msg.u.extended_buffer_data.buffer, buffer, msg.fenceFd)));
    -+
    -+            unbumpDebugLevel_l(kPortIndexOutput);
    -+        }
    -+
    -+        BufferMeta *buffer_meta =
    -+            static_cast<BufferMeta *>(buffer->pAppPrivate);
    -+
    -+        if (buffer->nOffset + buffer->nFilledLen < buffer->nOffset
    -+                || buffer->nOffset + buffer->nFilledLen > buffer->nAllocLen) {
    -+            CLOG_ERROR(onFillBufferDone, OMX_ErrorBadParameter,
    -+                    FULL_BUFFER(NULL, buffer, msg.fenceFd));
    -+        }
    -+        buffer_meta->CopyFromOMX(buffer);
    -+
    -+        if (bufferSource != NULL) {
    -+            // fix up the buffer info (especially timestamp) if needed
    -+            bufferSource->codecBufferFilled(buffer);
    -+
    -+            msg.u.extended_buffer_data.timestamp = buffer->nTimeStamp;
    -+        }
    -+    } else if (msg.type == omx_message::EMPTY_BUFFER_DONE) {
    -+        OMX_BUFFERHEADERTYPE *buffer =
    -+            findBufferHeader(msg.u.buffer_data.buffer, kPortIndexInput);
    -+        if (buffer == NULL) {
    -+            return false;
    -+        }
    -+
    -+        {
    -+            Mutex::Autolock _l(mDebugLock);
    -+            mInputBuffersWithCodec.remove(buffer);
    -+
    -+            CLOG_BUMPED_BUFFER(
    -+                    EBD, WITH_STATS(EMPTY_BUFFER(msg.u.buffer_data.buffer, buffer, msg.fenceFd)));
    -+        }
    -+
    -+        if (bufferSource != NULL) {
    -+            // This is one of the buffers used exclusively by
    -+            // GraphicBufferSource.
    -+            // Don't dispatch a message back to ACodec, since it doesn't
    -+            // know that anyone asked to have the buffer emptied and will
    -+            // be very confused.
    -+            bufferSource->codecBufferEmptied(buffer, msg.fenceFd);
    -+            return true;
    -+        }
    -+    }
    -+
    -+    return false;
    -+}
    -+
    -+void OMXNodeInstance::onMessages(std::list<omx_message> &messages) {
    -+    for (std::list<omx_message>::iterator it = messages.begin(); it != messages.end(); ) {
    -+        if (handleMessage(*it)) {
    -+            messages.erase(it++);
    -+        } else {
    -+            ++it;
    -+        }
    -+    }
    -+
    -+    if (!messages.empty()) {
    -+        mObserver->onMessages(messages);
    -+    }
    -+}
    -+
    -+void OMXNodeInstance::onObserverDied(OMXMaster *master) {
    -+    ALOGE("!!! Observer died. Quickly, do something, ... anything...");
    -+
    -+    // Try to force shutdown of the node and hope for the best.
    -+    freeNode(master);
    -+}
    -+
    -+void OMXNodeInstance::onGetHandleFailed() {
    -+    delete this;
    -+}
    -+
    -+// OMXNodeInstance::OnEvent calls OMX::OnEvent, which then calls here.
    -+// Don't try to acquire mLock here -- in rare circumstances this will hang.
    -+void OMXNodeInstance::onEvent(
    -+        OMX_EVENTTYPE event, OMX_U32 arg1, OMX_U32 arg2) {
    -+    const char *arg1String = "??";
    -+    const char *arg2String = "??";
    -+    ADebug::Level level = ADebug::kDebugInternalState;
    -+
    -+    switch (event) {
    -+        case OMX_EventCmdComplete:
    -+            arg1String = asString((OMX_COMMANDTYPE)arg1);
    -+            switch (arg1) {
    -+                case OMX_CommandStateSet:
    -+                    arg2String = asString((OMX_STATETYPE)arg2);
    -+                    level = ADebug::kDebugState;
    -+                    break;
    -+                case OMX_CommandFlush:
    -+                case OMX_CommandPortEnable:
    -+                {
    -+                    // bump internal-state debug level for 2 input and output frames
    -+                    Mutex::Autolock _l(mDebugLock);
    -+                    bumpDebugLevel_l(2 /* numInputBuffers */, 2 /* numOutputBuffers */);
    -+                }
    -+                // fall through
    -+                default:
    -+                    arg2String = portString(arg2);
    -+            }
    -+            break;
    -+        case OMX_EventError:
    -+            arg1String = asString((OMX_ERRORTYPE)arg1);
    -+            level = ADebug::kDebugLifeCycle;
    -+            break;
    -+        case OMX_EventPortSettingsChanged:
    -+            arg2String = asString((OMX_INDEXEXTTYPE)arg2);
    -+            // fall through
    -+        default:
    -+            arg1String = portString(arg1);
    -+    }
    -+
    -+    CLOGI_(level, onEvent, "%s(%x), %s(%x), %s(%x)",
    -+            asString(event), event, arg1String, arg1, arg2String, arg2);
    -+    const sp<GraphicBufferSource>& bufferSource(getGraphicBufferSource());
    -+
    -+    if (bufferSource != NULL
    -+            && event == OMX_EventCmdComplete
    -+            && arg1 == OMX_CommandStateSet
    -+            && arg2 == OMX_StateExecuting) {
    -+        bufferSource->omxExecuting();
    -+    }
    -+
    -+    // allow configuration if we return to the loaded state
    -+    if (event == OMX_EventCmdComplete
    -+            && arg1 == OMX_CommandStateSet
    -+            && arg2 == OMX_StateLoaded) {
    -+        mSailed = false;
    -+    }
    -+}
    -+
    -+// static
    -+OMX_ERRORTYPE OMXNodeInstance::OnEvent(
    -+        OMX_IN OMX_HANDLETYPE /* hComponent */,
    -+        OMX_IN OMX_PTR pAppData,
    -+        OMX_IN OMX_EVENTTYPE eEvent,
    -+        OMX_IN OMX_U32 nData1,
    -+        OMX_IN OMX_U32 nData2,
    -+        OMX_IN OMX_PTR pEventData) {
    -+    if (pAppData == NULL) {
    -+        ALOGE("b/25884056");
    -+        return OMX_ErrorBadParameter;
    -+    }
    -+    OMXNodeInstance *instance = static_cast<OMXNodeInstance *>(pAppData);
    -+    if (instance->mDying) {
    -+        return OMX_ErrorNone;
    -+    }
    -+    return instance->owner()->OnEvent(
    -+            instance->nodeID(), eEvent, nData1, nData2, pEventData);
    -+}
    -+
    -+// static
    -+OMX_ERRORTYPE OMXNodeInstance::OnEmptyBufferDone(
    -+        OMX_IN OMX_HANDLETYPE /* hComponent */,
    -+        OMX_IN OMX_PTR pAppData,
    -+        OMX_IN OMX_BUFFERHEADERTYPE* pBuffer) {
    -+    if (pAppData == NULL) {
    -+        ALOGE("b/25884056");
    -+        return OMX_ErrorBadParameter;
    -+    }
    -+    OMXNodeInstance *instance = static_cast<OMXNodeInstance *>(pAppData);
    -+    if (instance->mDying) {
    -+        return OMX_ErrorNone;
    -+    }
    -+    int fenceFd = instance->retrieveFenceFromMeta_l(pBuffer, kPortIndexOutput);
    -+    return instance->owner()->OnEmptyBufferDone(instance->nodeID(),
    -+            instance->findBufferID(pBuffer), pBuffer, fenceFd);
    -+}
    -+
    -+// static
    -+OMX_ERRORTYPE OMXNodeInstance::OnFillBufferDone(
    -+        OMX_IN OMX_HANDLETYPE /* hComponent */,
    -+        OMX_IN OMX_PTR pAppData,
    -+        OMX_IN OMX_BUFFERHEADERTYPE* pBuffer) {
    -+    if (pAppData == NULL) {
    -+        ALOGE("b/25884056");
    -+        return OMX_ErrorBadParameter;
    -+    }
    -+    OMXNodeInstance *instance = static_cast<OMXNodeInstance *>(pAppData);
    -+    if (instance->mDying) {
    -+        return OMX_ErrorNone;
    -+    }
    -+    int fenceFd = instance->retrieveFenceFromMeta_l(pBuffer, kPortIndexOutput);
    -+    return instance->owner()->OnFillBufferDone(instance->nodeID(),
    -+            instance->findBufferID(pBuffer), pBuffer, fenceFd);
    -+}
    -+
    -+void OMXNodeInstance::addActiveBuffer(OMX_U32 portIndex, OMX::buffer_id id) {
    -+    ActiveBuffer active;
    -+    active.mPortIndex = portIndex;
    -+    active.mID = id;
    -+    mActiveBuffers.push(active);
    -+
    -+    if (portIndex < NELEM(mNumPortBuffers)) {
    -+        ++mNumPortBuffers[portIndex];
    -+    }
    -+}
    -+
    -+void OMXNodeInstance::removeActiveBuffer(
    -+        OMX_U32 portIndex, OMX::buffer_id id) {
    -+    for (size_t i = 0; i < mActiveBuffers.size(); ++i) {
    -+        if (mActiveBuffers[i].mPortIndex == portIndex
    -+                && mActiveBuffers[i].mID == id) {
    -+            mActiveBuffers.removeItemsAt(i);
    -+
    -+            if (portIndex < NELEM(mNumPortBuffers)) {
    -+                --mNumPortBuffers[portIndex];
    -+            }
    -+            return;
    -+        }
    -+    }
    -+
    -+     CLOGW("Attempt to remove an active buffer [%#x] we know nothing about...", id);
    -+}
    -+
    -+void OMXNodeInstance::freeActiveBuffers() {
    -+    // Make sure to count down here, as freeBuffer will in turn remove
    -+    // the active buffer from the vector...
    -+    for (size_t i = mActiveBuffers.size(); i > 0;) {
    -+        i--;
    -+        freeBuffer(mActiveBuffers[i].mPortIndex, mActiveBuffers[i].mID);
    -+    }
    -+}
    -+
    -+OMX::buffer_id OMXNodeInstance::makeBufferID(OMX_BUFFERHEADERTYPE *bufferHeader) {
    -+    if (bufferHeader == NULL) {
    -+        return 0;
    -+    }
    -+    Mutex::Autolock autoLock(mBufferIDLock);
    -+    OMX::buffer_id buffer;
    -+    do { // handle the very unlikely case of ID overflow
    -+        if (++mBufferIDCount == 0) {
    -+            ++mBufferIDCount;
    -+        }
    -+        buffer = (OMX::buffer_id)mBufferIDCount;
    -+    } while (mBufferIDToBufferHeader.indexOfKey(buffer) >= 0);
    -+    mBufferIDToBufferHeader.add(buffer, bufferHeader);
    -+    mBufferHeaderToBufferID.add(bufferHeader, buffer);
    -+    return buffer;
    -+}
    -+
    -+OMX_BUFFERHEADERTYPE *OMXNodeInstance::findBufferHeader(
    -+        OMX::buffer_id buffer, OMX_U32 portIndex) {
    -+    if (buffer == 0) {
    -+        return NULL;
    -+    }
    -+    Mutex::Autolock autoLock(mBufferIDLock);
    -+    ssize_t index = mBufferIDToBufferHeader.indexOfKey(buffer);
    -+    if (index < 0) {
    -+        CLOGW("findBufferHeader: buffer %u not found", buffer);
    -+        return NULL;
    -+    }
    -+    OMX_BUFFERHEADERTYPE *header = mBufferIDToBufferHeader.valueAt(index);
    -+    BufferMeta *buffer_meta =
    -+        static_cast<BufferMeta *>(header->pAppPrivate);
    -+    if (buffer_meta->getPortIndex() != portIndex) {
    -+        CLOGW("findBufferHeader: buffer %u found but with incorrect port index.", buffer);
    -+        android_errorWriteLog(0x534e4554, "28816827");
    -+        return NULL;
    -+    }
    -+    return header;
    -+}
    -+
    -+OMX::buffer_id OMXNodeInstance::findBufferID(OMX_BUFFERHEADERTYPE *bufferHeader) {
    -+    if (bufferHeader == NULL) {
    -+        return 0;
    -+    }
    -+    Mutex::Autolock autoLock(mBufferIDLock);
    -+    ssize_t index = mBufferHeaderToBufferID.indexOfKey(bufferHeader);
    -+    if (index < 0) {
    -+        CLOGW("findBufferID: bufferHeader %p not found", bufferHeader);
    -+        return 0;
    -+    }
    -+    return mBufferHeaderToBufferID.valueAt(index);
    -+}
    -+
    -+void OMXNodeInstance::invalidateBufferID(OMX::buffer_id buffer) {
    -+    if (buffer == 0) {
    -+        return;
    -+    }
    -+    Mutex::Autolock autoLock(mBufferIDLock);
    -+    ssize_t index = mBufferIDToBufferHeader.indexOfKey(buffer);
    -+    if (index < 0) {
    -+        CLOGW("invalidateBufferID: buffer %u not found", buffer);
    -+        return;
    -+    }
    -+    mBufferHeaderToBufferID.removeItem(mBufferIDToBufferHeader.valueAt(index));
    -+    mBufferIDToBufferHeader.removeItemsAt(index);
    -+}
    -+
    -+}  // namespace android
     diff --git a/media/libstagefright/omx/SimpleSoftOMXComponent.cpp b/media/libstagefright/omx/SimpleSoftOMXComponent.cpp
     index 7c975f7..76cbbc4 100644
     --- a/media/libstagefright/omx/SimpleSoftOMXComponent.cpp
    diff --git a/frameworks_base.patch b/frameworks_base.patch
    index 08e551c..2d9e098 100644
    --- a/frameworks_base.patch
    +++ b/frameworks_base.patch
    @@ -36,6 +36,20 @@ index aed7a36..bf96926 100644
                  // if canceling out of addAccount and the original state caused us to skip this,
                  // finish this activity
                  if (mAccounts.isEmpty()) {
    +diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
    +index 5cfcac3..010b871 100644
    +--- a/core/java/android/app/ActivityThread.java
    ++++ b/core/java/android/app/ActivityThread.java
    +@@ -911,7 +911,8 @@ public final class ActivityThread {
    +         }
    + 
    +         public void setHttpProxy(String host, String port, String exclList, Uri pacFileUrl) {
    +-            final ConnectivityManager cm = ConnectivityManager.from(getSystemContext());
    ++            final ConnectivityManager cm = ConnectivityManager.from(
    ++                getApplication() != null ? getApplication() : getSystemContext());
    +             final Network network = cm.getBoundNetworkForProcess();
    +             if (network != null) {
    +                 Proxy.setHttpProxySystemProperty(cm.getDefaultProxy());
     diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java
     index 0dd9c63..bcdf3f4 100644
     --- a/core/java/android/app/Notification.java
    @@ -98,6 +112,23 @@ index 5cc064e..4916c1c 100644
                      if (impl != null && key.mResDir.equals(assetPath)) {
                          if (!ArrayUtils.contains(key.mLibDirs, libAsset)) {
                              final int newLibAssetCount = 1 +
    +diff --git a/core/java/android/bluetooth/BluetoothDevice.java b/core/java/android/bluetooth/BluetoothDevice.java
    +index cd5eff2..d329175 100644
    +--- a/core/java/android/bluetooth/BluetoothDevice.java
    ++++ b/core/java/android/bluetooth/BluetoothDevice.java
    +@@ -727,7 +727,11 @@ public final class BluetoothDevice implements Parcelable {
    +             return null;
    +         }
    +         try {
    +-            return sService.getRemoteName(this);
    ++            String name = sService.getRemoteName(this);
    ++            if (name != null) {
    ++                return name.replaceAll("[\\t\\n\\r]+", " ");
    ++            }
    ++            return null;
    +         } catch (RemoteException e) {Log.e(TAG, "", e);}
    +         return null;
    +     }
     diff --git a/core/java/android/content/PermissionChecker.java b/core/java/android/content/PermissionChecker.java
     new file mode 100644
     index 0000000..a4b2fe0
    @@ -477,6 +508,30 @@ index 46a0194..ecc9025 100644
           * Tell the policy if anyone is requesting that keyguard not come on.
           *
           * @param enabled Whether keyguard can be on or not.  does not actually
    +diff --git a/core/java/com/android/internal/app/ChooserActivity.java b/core/java/com/android/internal/app/ChooserActivity.java
    +index a5b2a91..cdf83d3 100644
    +--- a/core/java/com/android/internal/app/ChooserActivity.java
    ++++ b/core/java/com/android/internal/app/ChooserActivity.java
    +@@ -83,7 +83,7 @@ public class ChooserActivity extends ResolverActivity {
    + 
    +     private static final boolean DEBUG = false;
    + 
    +-    private static final int QUERY_TARGET_SERVICE_LIMIT = 5;
    ++    private static final int QUERY_TARGET_SERVICE_LIMIT = 3;
    +     private static final int WATCHDOG_TIMEOUT_MILLIS = 5000;
    + 
    +     private Bundle mReplacementExtras;
    +@@ -799,8 +799,8 @@ public class ChooserActivity extends ResolverActivity {
    +         public static final int TARGET_SERVICE = 1;
    +         public static final int TARGET_STANDARD = 2;
    + 
    +-        private static final int MAX_SERVICE_TARGETS = 8;
    +-        private static final int MAX_TARGETS_PER_SERVICE = 4;
    ++        private static final int MAX_SERVICE_TARGETS = 4;
    ++        private static final int MAX_TARGETS_PER_SERVICE = 2;
    + 
    +         private final List<ChooserTargetInfo> mServiceTargets = new ArrayList<>();
    +         private final List<TargetInfo> mCallerTargets = new ArrayList<>();
     diff --git a/core/java/com/android/internal/app/procstats/ProcessState.java b/core/java/com/android/internal/app/procstats/ProcessState.java
     index 8c5df08..8c2c236 100644
     --- a/core/java/com/android/internal/app/procstats/ProcessState.java
    @@ -1089,6 +1144,21 @@ index 0fa9a85..925f368 100644
          </string>
      
          <!-- The tiles to display in QuickSettings -->
    +diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
    +index 4a51329..aa6b3e0 100644
    +--- a/packages/SystemUI/res/values/strings.xml
    ++++ b/packages/SystemUI/res/values/strings.xml
    +@@ -1700,5 +1700,9 @@
    +     <string name="high_temp_notif_message">Some features limited while phone cools down</string>
    +     <!-- Text body for dialog alerting user that their phone has reached a certain temperature and may start to slow down in order to cool down. [CHAR LIMIT=300] -->
    +     <string name="high_temp_dialog_message">Your phone will automatically try to cool down. You can still use your phone, but it may run slower.\n\nOnce your phone has cooled down, it will run normally.</string>
    +-
    ++    <!-- Warning shown when user input has been blocked due to another app overlaying screen
    ++         content. Since we don't know what the app is showing on top of the input target, we
    ++         can't verify user consent. [CHAR LIMIT=NONE] -->
    ++    <string name="touch_filtered_warning">Because an app is obscuring a permission request, Settings
    ++        can’t verify your response.</string>
    + </resources>
     diff --git a/packages/SystemUI/src/com/android/systemui/classifier/HumanInteractionClassifier.java b/packages/SystemUI/src/com/android/systemui/classifier/HumanInteractionClassifier.java
     index 851ab77..a384641 100644
     --- a/packages/SystemUI/src/com/android/systemui/classifier/HumanInteractionClassifier.java
    @@ -1527,7 +1597,7 @@ index 2a6f9d2..7ba1fe4 100644
                      case MESSAGE_GET_NAME_AND_ADDRESS:
                          if (DBG) Slog.d(TAG, "MESSAGE_GET_NAME_AND_ADDRESS");
     diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
    -index 2693272..f2368ed 100644
    +index 2693272..903dc40 100644
     --- a/services/core/java/com/android/server/ConnectivityService.java
     +++ b/services/core/java/com/android/server/ConnectivityService.java
     @@ -3007,6 +3007,12 @@ public class ConnectivityService extends IConnectivityManager.Stub
    @@ -1556,7 +1626,26 @@ index 2693272..f2368ed 100644
                  return status;
              } else {
                  return ConnectivityManager.TETHER_ERROR_UNSUPPORTED;
    -@@ -4924,6 +4936,13 @@ public class ConnectivityService extends IConnectivityManager.Stub
    +@@ -4458,7 +4470,7 @@ public class ConnectivityService extends IConnectivityManager.Stub
    +     }
    + 
    +     private void updateLinkProperties(NetworkAgentInfo networkAgent, LinkProperties oldLp) {
    +-        LinkProperties newLp = networkAgent.linkProperties;
    ++        LinkProperties newLp = new LinkProperties(networkAgent.linkProperties);
    +         int netId = networkAgent.network.netId;
    + 
    +         // The NetworkAgentInfo does not know whether clatd is running on its network or not. Before
    +@@ -4486,6 +4498,9 @@ public class ConnectivityService extends IConnectivityManager.Stub
    +         }
    +         // TODO - move this check to cover the whole function
    +         if (!Objects.equals(newLp, oldLp)) {
    ++            synchronized (networkAgent) {
    ++                networkAgent.linkProperties = newLp;
    ++            }
    +             notifyIfacesChangedForNetworkStats();
    +             notifyNetworkCallbacks(networkAgent, ConnectivityManager.CALLBACK_IP_CHANGED);
    +         }
    +@@ -4924,6 +4939,13 @@ public class ConnectivityService extends IConnectivityManager.Stub
                  // check if it satisfies the NetworkCapabilities
                  if (VDBG) log("  checking if request is satisfied: " + nri.request);
                  if (satisfies) {
    @@ -1599,31 +1688,23 @@ index a7a79cd..a085b71 100644
                  try {
                      PackageManager pm = mContext.getPackageManager();
     diff --git a/services/core/java/com/android/server/am/ActivityStackSupervisor.java b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
    -index c6ab918..d848081 100644
    +index c6ab918..8ba368b 100644
     --- a/services/core/java/com/android/server/am/ActivityStackSupervisor.java
     +++ b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
    -@@ -2747,6 +2747,9 @@ public final class ActivityStackSupervisor implements DisplayListener {
    -             }
    +@@ -2855,10 +2855,10 @@ public final class ActivityStackSupervisor implements DisplayListener {
              }
    -         checkReadyForSleepLocked();
    -+        if (mGoingToSleep.isHeld()) {
    -+            mGoingToSleep.release();
    -+        }
    -     }
    - 
    -     boolean shutdownLocked(int timeout) {
    -@@ -2856,9 +2859,6 @@ public final class ActivityStackSupervisor implements DisplayListener {
      
              removeSleepTimeouts();
    - 
    --        if (mGoingToSleep.isHeld()) {
    --            mGoingToSleep.release();
    --        }
    +-
    +         if (mGoingToSleep.isHeld()) {
    +             mGoingToSleep.release();
    +         }
    ++
              if (mService.mShuttingDown) {
                  mService.notifyAll();
              }
     diff --git a/services/core/java/com/android/server/clipboard/ClipboardService.java b/services/core/java/com/android/server/clipboard/ClipboardService.java
    -index 66aa403..bdd2d2b 100644
    +index 66aa403..6f59e84 100644
     --- a/services/core/java/com/android/server/clipboard/ClipboardService.java
     +++ b/services/core/java/com/android/server/clipboard/ClipboardService.java
     @@ -20,6 +20,7 @@ import android.app.ActivityManagerNative;
    @@ -1670,13 +1751,19 @@ index 66aa403..bdd2d2b 100644
                      return false;
                  }
                  PerUserClipboard clipboard = getClipboard();
    -@@ -313,6 +314,11 @@ public class ClipboardService extends IClipboard.Stub {
    +@@ -313,6 +314,17 @@ public class ClipboardService extends IClipboard.Stub {
              }
          }
      
     +    private boolean isDeviceLocked() {
    -+        final KeyguardManager keyguardManager = mContext.getSystemService(KeyguardManager.class);
    -+        return keyguardManager != null && keyguardManager.isDeviceLocked();
    ++        final long token = Binder.clearCallingIdentity();
    ++        try {
    ++            final KeyguardManager keyguardManager = mContext.getSystemService(
    ++                    KeyguardManager.class);
    ++            return keyguardManager != null && keyguardManager.isDeviceLocked();
    ++        } finally {
    ++            Binder.restoreCallingIdentity(token);
    ++        }
     +    }
     +
          private final void checkUriOwnerLocked(Uri uri, int uid) {
    diff --git a/frameworks_native.patch b/frameworks_native.patch
    index 2f6d1ce..042a494 100644
    --- a/frameworks_native.patch
    +++ b/frameworks_native.patch
    @@ -113,10 +113,28 @@ index 271c75b..cadcd1e 100644
              }
          }
     diff --git a/include/binder/Parcel.h b/include/binder/Parcel.h
    -index 2490b82..1e3d02f 100644
    +index 2490b82..2b61151 100644
     --- a/include/binder/Parcel.h
     +++ b/include/binder/Parcel.h
    -@@ -476,7 +476,13 @@ private:
    +@@ -375,7 +375,8 @@ private:
    +     void                freeDataNoInit();
    +     void                initState();
    +     void                scanForFds() const;
    +-                        
    ++    status_t            validateReadData(size_t len) const;
    ++                    
    +     template<class T>
    +     status_t            readAligned(T *pArg) const;
    + 
    +@@ -421,6 +422,7 @@ private:
    +     size_t              mObjectsSize;
    +     size_t              mObjectsCapacity;
    +     mutable size_t      mNextObjectHint;
    ++    mutable bool        mObjectsSorted;
    + 
    +     mutable bool        mFdsKnown;
    +     mutable bool        mHasFds;
    +@@ -476,7 +478,13 @@ private:
                  return val.flatten(buffer, size, fds, count);
              }
              virtual status_t unflatten(void const* buffer, size_t size, int const* fds, size_t count) {
    @@ -305,6 +323,151 @@ index eccc400..3efebf7 100644
              gHaveTLS = false;
          }
      }
    +diff --git a/libs/binder/Parcel.cpp b/libs/binder/Parcel.cpp
    +index 19ce3eb..e6630d5 100644
    +--- a/libs/binder/Parcel.cpp
    ++++ b/libs/binder/Parcel.cpp
    +@@ -459,6 +459,7 @@ void Parcel::setDataPosition(size_t pos) const
    + 
    +     mDataPos = pos;
    +     mNextObjectHint = 0;
    ++    mObjectsSorted = false;
    + }
    + 
    + status_t Parcel::setDataCapacity(size_t size)
    +@@ -1363,6 +1364,59 @@ void Parcel::remove(size_t /*start*/, size_t /*amt*/)
    +     LOG_ALWAYS_FATAL("Parcel::remove() not yet implemented!");
    + }
    + 
    ++status_t Parcel::validateReadData(size_t upperBound) const
    ++{
    ++    // Don't allow non-object reads on object data
    ++    if (mObjectsSorted || mObjectsSize <= 1) {
    ++data_sorted:
    ++        // Expect to check only against the next object
    ++        if (mNextObjectHint < mObjectsSize && upperBound > mObjects[mNextObjectHint]) {
    ++            // For some reason the current read position is greater than the next object
    ++            // hint. Iterate until we find the right object
    ++            size_t nextObject = mNextObjectHint;
    ++            do {
    ++                if (mDataPos < mObjects[nextObject] + sizeof(flat_binder_object)) {
    ++                    // Requested info overlaps with an object
    ++                    ALOGE("Attempt to read from protected data in Parcel %p", this);
    ++                    return PERMISSION_DENIED;
    ++                }
    ++                nextObject++;
    ++            } while (nextObject < mObjectsSize && upperBound > mObjects[nextObject]);
    ++            mNextObjectHint = nextObject;
    ++        }
    ++        return NO_ERROR;
    ++    }
    ++    // Quickly determine if mObjects is sorted.
    ++    binder_size_t* currObj = mObjects + mObjectsSize - 1;
    ++    binder_size_t* prevObj = currObj;
    ++    while (currObj > mObjects) {
    ++        prevObj--;
    ++        if(*prevObj > *currObj) {
    ++            goto data_unsorted;
    ++        }
    ++        currObj--;
    ++    }
    ++    mObjectsSorted = true;
    ++    goto data_sorted;
    ++
    ++data_unsorted:
    ++    // Insertion Sort mObjects
    ++    // Great for mostly sorted lists. If randomly sorted or reverse ordered mObjects become common,
    ++    // switch to std::sort(mObjects, mObjects + mObjectsSize);
    ++    for (binder_size_t* iter0 = mObjects + 1; iter0 < mObjects + mObjectsSize; iter0++) {
    ++        binder_size_t temp = *iter0;
    ++        binder_size_t* iter1 = iter0 - 1;
    ++        while (iter1 >= mObjects && *iter1 > temp) {
    ++            *(iter1 + 1) = *iter1;
    ++            iter1--;
    ++        }
    ++        *(iter1 + 1) = temp;
    ++    }
    ++    mNextObjectHint = 0;
    ++    mObjectsSorted = true;
    ++    goto data_sorted;
    ++}
    ++
    + status_t Parcel::read(void* outData, size_t len) const
    + {
    +     if (len > INT32_MAX) {
    +@@ -1373,6 +1427,15 @@ status_t Parcel::read(void* outData, size_t len) const
    + 
    +     if ((mDataPos+pad_size(len)) >= mDataPos && (mDataPos+pad_size(len)) <= mDataSize
    +             && len <= pad_size(len)) {
    ++        if (mObjectsSize > 0) {
    ++            status_t err = validateReadData(mDataPos + pad_size(len));
    ++            if(err != NO_ERROR) {
    ++                // Still increment the data position by the expected length
    ++                mDataPos += pad_size(len);
    ++                ALOGV("read Setting data pos of %p to %zu", this, mDataPos);
    ++                return err;
    ++            }
    ++        }
    +         memcpy(outData, mData+mDataPos, len);
    +         mDataPos += pad_size(len);
    +         ALOGV("read Setting data pos of %p to %zu", this, mDataPos);
    +@@ -1391,6 +1454,15 @@ const void* Parcel::readInplace(size_t len) const
    + 
    +     if ((mDataPos+pad_size(len)) >= mDataPos && (mDataPos+pad_size(len)) <= mDataSize
    +             && len <= pad_size(len)) {
    ++        if (mObjectsSize > 0) {
    ++            status_t err = validateReadData(mDataPos + pad_size(len));
    ++            if(err != NO_ERROR) {
    ++                // Still increment the data position by the expected length
    ++                mDataPos += pad_size(len);
    ++                ALOGV("readInplace Setting data pos of %p to %zu", this, mDataPos);
    ++                return NULL;
    ++            }
    ++        }
    +         const void* data = mData+mDataPos;
    +         mDataPos += pad_size(len);
    +         ALOGV("readInplace Setting data pos of %p to %zu", this, mDataPos);
    +@@ -1404,6 +1476,15 @@ status_t Parcel::readAligned(T *pArg) const {
    +     COMPILE_TIME_ASSERT_FUNCTION_SCOPE(PAD_SIZE_UNSAFE(sizeof(T)) == sizeof(T));
    + 
    +     if ((mDataPos+sizeof(T)) <= mDataSize) {
    ++        if (mObjectsSize > 0) {
    ++            status_t err = validateReadData(mDataPos + sizeof(T));
    ++            if(err != NO_ERROR) {
    ++                // Still increment the data position by the expected length
    ++                mDataPos += sizeof(T);
    ++                return err;
    ++            }
    ++        }
    ++
    +         const void* data = mData+mDataPos;
    +         mDataPos += sizeof(T);
    +         *pArg =  *reinterpret_cast<const T*>(data);
    +@@ -2206,6 +2287,7 @@ void Parcel::ipcSetDataReference(const uint8_t* data, size_t dataSize,
    +     mObjects = const_cast<binder_size_t*>(objects);
    +     mObjectsSize = mObjectsCapacity = objectsCount;
    +     mNextObjectHint = 0;
    ++    mObjectsSorted = false;
    +     mOwner = relFunc;
    +     mOwnerCookie = relCookie;
    +     for (size_t i = 0; i < mObjectsSize; i++) {
    +@@ -2450,7 +2532,7 @@ status_t Parcel::continueWrite(size_t desired)
    +         mDataCapacity = desired;
    +         mObjectsSize = mObjectsCapacity = objectsSize;
    +         mNextObjectHint = 0;
    +-
    ++        mObjectsSorted = false;
    +     } else if (mData) {
    +         if (objectsSize < mObjectsSize) {
    +             // Need to release refs on any objects we are dropping.
    +@@ -2471,6 +2553,7 @@ status_t Parcel::continueWrite(size_t desired)
    +             }
    +             mObjectsSize = objectsSize;
    +             mNextObjectHint = 0;
    ++            mObjectsSorted = false;
    +         }
    + 
    +         // We own the data, so we can just do a realloc().
     diff --git a/libs/binder/ProcessState.cpp b/libs/binder/ProcessState.cpp
     index f13f49f..e45b5f1 100644
     --- a/libs/binder/ProcessState.cpp
    @@ -323,6 +486,36 @@ index f13f49f..e45b5f1 100644
      }
              
      }; // namespace android
    +diff --git a/libs/binder/tests/binderDriverInterfaceTest.cpp b/libs/binder/tests/binderDriverInterfaceTest.cpp
    +index 0277550..d8fd81c 100644
    +--- a/libs/binder/tests/binderDriverInterfaceTest.cpp
    ++++ b/libs/binder/tests/binderDriverInterfaceTest.cpp
    +@@ -77,6 +77,16 @@ class BinderDriverInterfaceTest : public ::testing::Test {
    +         virtual void TearDown() {
    +         }
    +     protected:
    ++        /* The ioctl must either return 0, or if it doesn't errno should be accepted_errno */
    ++        void binderTestIoctlSuccessOrError(int cmd, void *arg, int accepted_errno) {
    ++            int ret;
    ++
    ++            ret = ioctl(m_binderFd, cmd, arg);
    ++            if (ret != 0) {
    ++                EXPECT_EQ(errno, accepted_errno);
    ++            }
    ++        }
    ++
    +         void binderTestIoctlRetErr2(int cmd, void *arg, int expect_ret, int expect_errno, int accept_errno) {
    +             int ret;
    + 
    +@@ -248,7 +258,7 @@ TEST_F(BinderDriverInterfaceTest, Transaction) {
    + 
    +     {
    +         SCOPED_TRACE("1st WriteRead");
    +-        binderTestIoctl(BINDER_WRITE_READ, &bwr);
    ++        binderTestIoctlSuccessOrError(BINDER_WRITE_READ, &bwr, EAGAIN);
    +     }
    +     EXPECT_EQ(sizeof(bc1), bwr.write_consumed);
    +     if (bwr.read_consumed < offsetof(typeof(br), pad)) {
     diff --git a/libs/gui/Android.mk b/libs/gui/Android.mk
     index 9e2fc2b..12d2148 100644
     --- a/libs/gui/Android.mk
    @@ -885,10 +1078,10 @@ index ee152bf..9c82295 100644
          result.mStorage.clear();
          for (size_t r = 0; r < numRects; ++r) {
     diff --git a/opengl/libs/Android.mk b/opengl/libs/Android.mk
    -index 24e4c19..f56a346 100644
    +index 24e4c19..54e9d59 100644
     --- a/opengl/libs/Android.mk
     +++ b/opengl/libs/Android.mk
    -@@ -42,6 +42,9 @@ LOCAL_CFLAGS += -DLOG_TAG=\"libEGL\"
    +@@ -42,9 +42,15 @@ LOCAL_CFLAGS += -DLOG_TAG=\"libEGL\"
      LOCAL_CFLAGS += -DGL_GLEXT_PROTOTYPES -DEGL_EGLEXT_PROTOTYPES
      LOCAL_CFLAGS += -fvisibility=hidden
      
    @@ -898,7 +1091,13 @@ index 24e4c19..f56a346 100644
      ifeq ($(BOARD_ALLOW_EGL_HIBERNATION),true)
        LOCAL_CFLAGS += -DBOARD_ALLOW_EGL_HIBERNATION
      endif
    -@@ -77,7 +80,6 @@ LOCAL_SRC_FILES:= 		\
    ++ifeq ($(BOARD_EGL_WORKAROUND_BUG_10194508),true)
    ++  LOCAL_CFLAGS += -DWORKAROUND_BUG_10194508
    ++endif
    + ifneq ($(MAX_EGL_CACHE_ENTRY_SIZE),)
    +   LOCAL_CFLAGS += -DMAX_EGL_CACHE_ENTRY_SIZE=$(MAX_EGL_CACHE_ENTRY_SIZE)
    + endif
    +@@ -77,7 +83,6 @@ LOCAL_SRC_FILES:= 		\
      	GLES_CM/gl.cpp.arm 	\
      #
      
    @@ -906,7 +1105,7 @@ index 24e4c19..f56a346 100644
      LOCAL_SHARED_LIBRARIES += libcutils liblog libEGL
      LOCAL_MODULE:= libGLESv1_CM
      
    -@@ -105,7 +107,6 @@ LOCAL_SRC_FILES:= \
    +@@ -105,7 +110,6 @@ LOCAL_SRC_FILES:= \
      	GLES2/gl2.cpp   \
      #
      
    @@ -914,7 +1113,7 @@ index 24e4c19..f56a346 100644
      LOCAL_ARM_MODE := arm
      LOCAL_SHARED_LIBRARIES += libcutils libutils liblog libEGL
      LOCAL_MODULE:= libGLESv2
    -@@ -133,7 +134,6 @@ LOCAL_SRC_FILES:= \
    +@@ -133,7 +137,6 @@ LOCAL_SRC_FILES:= \
      	GLES2/gl2.cpp   \
      #
      
    @@ -922,6 +1121,39 @@ index 24e4c19..f56a346 100644
      LOCAL_ARM_MODE := arm
      LOCAL_SHARED_LIBRARIES += libcutils libutils liblog libEGL
      LOCAL_MODULE:= libGLESv3
    +diff --git a/opengl/libs/EGL/eglApi.cpp b/opengl/libs/EGL/eglApi.cpp
    +index 436ea30..58b625e 100644
    +--- a/opengl/libs/EGL/eglApi.cpp
    ++++ b/opengl/libs/EGL/eglApi.cpp
    +@@ -487,11 +487,17 @@ EGLSurface eglCreateWindowSurface(  EGLDisplay dpy, EGLConfig config,
    +         // of our native format. So if sRGB gamma is requested, we have to
    +         // modify the EGLconfig's format before setting the native window's
    +         // format.
    +-
    +-        // by default, just pick RGBA_8888
    +-        EGLint format = HAL_PIXEL_FORMAT_RGBA_8888;
    ++        EGLint format;
    +         android_dataspace dataSpace = HAL_DATASPACE_UNKNOWN;
    + 
    ++#ifdef WORKAROUND_BUG_10194508
    ++        if (!cnx->egl.eglGetConfigAttrib(iDpy, config, EGL_NATIVE_VISUAL_ID,
    ++                &format)) {
    ++            ALOGE("eglGetConfigAttrib(EGL_NATIVE_VISUAL_ID) failed: %#x",
    ++                    eglGetError());
    ++            format = 0;
    ++        }
    ++#else
    +         EGLint a = 0;
    +         cnx->egl.eglGetConfigAttrib(iDpy, config, EGL_ALPHA_SIZE, &a);
    +         if (a > 0) {
    +@@ -510,6 +516,7 @@ EGLSurface eglCreateWindowSurface(  EGLDisplay dpy, EGLConfig config,
    +                 format = HAL_PIXEL_FORMAT_RGBX_8888;
    +             }
    +         }
    ++#endif
    + 
    +         // now select a corresponding sRGB format if needed
    +         if (attrib_list && dp->haveExtension("EGL_KHR_gl_colorspace")) {
     diff --git a/opengl/libs/EGL/egl_object.cpp b/opengl/libs/EGL/egl_object.cpp
     index cfecf77..4d9f77f 100644
     --- a/opengl/libs/EGL/egl_object.cpp
    @@ -1848,6 +2080,46 @@ index 3f69d49..e48c53a 100644
                      }
                  }
              }
    +diff --git a/services/inputflinger/InputManager.cpp b/services/inputflinger/InputManager.cpp
    +index 6a6547b..2ef25f3 100644
    +--- a/services/inputflinger/InputManager.cpp
    ++++ b/services/inputflinger/InputManager.cpp
    +@@ -20,6 +20,7 @@
    + 
    + #include "InputManager.h"
    + 
    ++#include <cutils/iosched_policy.h>
    + #include <cutils/log.h>
    + 
    + namespace android {
    +@@ -51,13 +52,15 @@ void InputManager::initialize() {
    + }
    + 
    + status_t InputManager::start() {
    +-    status_t result = mDispatcherThread->run("InputDispatcher", PRIORITY_URGENT_DISPLAY);
    ++    status_t result = mDispatcherThread->run("InputDispatcher",
    ++            PRIORITY_URGENT_DISPLAY + PRIORITY_MORE_FAVORABLE);
    +     if (result) {
    +         ALOGE("Could not start InputDispatcher thread due to error %d.", result);
    +         return result;
    +     }
    + 
    +-    result = mReaderThread->run("InputReader", PRIORITY_URGENT_DISPLAY);
    ++    result = mReaderThread->run("InputReader",
    ++            PRIORITY_URGENT_DISPLAY + PRIORITY_MORE_FAVORABLE);
    +     if (result) {
    +         ALOGE("Could not start InputReader thread due to error %d.", result);
    + 
    +@@ -65,6 +68,9 @@ status_t InputManager::start() {
    +         return result;
    +     }
    + 
    ++    android_set_rt_ioprio(mDispatcherThread->getTid(), 1);
    ++    android_set_rt_ioprio(mReaderThread->getTid(), 1);
    ++
    +     return OK;
    + }
    + 
     diff --git a/services/inputflinger/InputReader.cpp b/services/inputflinger/InputReader.cpp
     index b9be675..eff3deb 100644
     --- a/services/inputflinger/InputReader.cpp
    @@ -2023,11 +2295,17 @@ index e243637..4794b47 100644
              LAST_SYSTEM_WINDOW      = 2999,
          };
     diff --git a/services/surfaceflinger/Android.mk b/services/surfaceflinger/Android.mk
    -index ffda035..3f96b35 100644
    +index ffda035..52d4a8b 100644
     --- a/services/surfaceflinger/Android.mk
     +++ b/services/surfaceflinger/Android.mk
    -@@ -56,6 +56,9 @@ else
    +@@ -54,8 +54,15 @@ else
    +     LOCAL_SRC_FILES += \
    +         SurfaceFlinger_hwc1.cpp \
              DisplayHardware/HWComposer_hwc1.cpp
    ++
    ++    ifeq ($(OMAP_ENHANCEMENT),true)
    ++        LOCAL_CFLAGS += -DOMAP_ENHANCEMENT
    ++    endif
      endif
      
     +ifeq ($(TARGET_FORCE_SCREENSHOT_CPU_PATH),true)
    @@ -2036,7 +2314,7 @@ index ffda035..3f96b35 100644
      ifeq ($(TARGET_BOARD_PLATFORM),omap4)
          LOCAL_CFLAGS += -DHAS_CONTEXT_PRIORITY
      endif
    -@@ -99,16 +102,28 @@ endif
    +@@ -99,16 +106,28 @@ endif
      # [1] https://developer.android.com/studio/profile/systrace.html
      # [2] https://developer.android.com/training/testing/performance.html
      
    @@ -2067,6 +2345,26 @@ index ffda035..3f96b35 100644
      endif
      
      ifneq ($(PRESENT_TIME_OFFSET_FROM_VSYNC_NS),)
    +diff --git a/services/surfaceflinger/DispSync.cpp b/services/surfaceflinger/DispSync.cpp
    +index 1a9820d..b45e00a 100644
    +--- a/services/surfaceflinger/DispSync.cpp
    ++++ b/services/surfaceflinger/DispSync.cpp
    +@@ -22,6 +22,7 @@
    + 
    + #include <math.h>
    + 
    ++#include <cutils/iosched_policy.h>
    + #include <cutils/log.h>
    + 
    + #include <ui/Fence.h>
    +@@ -390,6 +391,7 @@ DispSync::DispSync(const char* name) :
    +         ALOGE("Couldn't set SCHED_FIFO for DispSyncThread");
    +     }
    + 
    ++    android_set_rt_ioprio(mThread->getTid(), 1);
    + 
    +     reset();
    +     beginResync();
     diff --git a/services/surfaceflinger/DisplayDevice.cpp b/services/surfaceflinger/DisplayDevice.cpp
     index 5c2c0ad..1f2e554 100644
     --- a/services/surfaceflinger/DisplayDevice.cpp
    @@ -2081,10 +2379,67 @@ index 5c2c0ad..1f2e554 100644
      }
      
     diff --git a/services/surfaceflinger/DisplayHardware/HWComposer_hwc1.cpp b/services/surfaceflinger/DisplayHardware/HWComposer_hwc1.cpp
    -index ef41658..086acc9 100644
    +index ef41658..138d20a 100644
     --- a/services/surfaceflinger/DisplayHardware/HWComposer_hwc1.cpp
     +++ b/services/surfaceflinger/DisplayHardware/HWComposer_hwc1.cpp
    -@@ -1260,7 +1260,7 @@ void HWComposer::dump(String8& result) const {
    +@@ -111,6 +111,10 @@ HWComposer::HWComposer(
    +     int fberr = loadFbHalModule();
    +     loadHwcModule();
    + 
    ++#ifdef OMAP_ENHANCEMENT
    ++    // FB HAL must stay open independent of HWC API version. Closing FB HAL will
    ++    // result in destruction of flip chain and de-allocation of framebuffer.
    ++#else
    +     if (mFbDev && mHwc && hwcHasApiVersion(mHwc, HWC_DEVICE_API_VERSION_1_1)) {
    +         // close FB HAL if we don't needed it.
    +         // FIXME: this is temporary until we're not forced to open FB HAL
    +@@ -118,6 +122,7 @@ HWComposer::HWComposer(
    +         framebuffer_close(mFbDev);
    +         mFbDev = NULL;
    +     }
    ++#endif
    + 
    +     // If we have no HWC, or a pre-1.1 HWC, an FB dev is mandatory.
    +     if ((!mHwc || !hwcHasApiVersion(mHwc, HWC_DEVICE_API_VERSION_1_1))
    +@@ -166,7 +171,11 @@ HWComposer::HWComposer(
    +         }
    +     }
    + 
    ++#ifdef OMAP_ENHANCEMENT
    ++    if (!mHwc || !hwcHasApiVersion(mHwc, HWC_DEVICE_API_VERSION_1_1)) {
    ++#else
    +     if (mFbDev) {
    ++#endif
    +         ALOG_ASSERT(!(mHwc && hwcHasApiVersion(mHwc, HWC_DEVICE_API_VERSION_1_1)),
    +                 "should only have fbdev if no hwc or hwc is 1.0");
    + 
    +@@ -424,7 +433,12 @@ status_t HWComposer::queryDisplayProperties(int disp) {
    +     }
    + 
    +     // FIXME: what should we set the format to?
    ++#ifdef OMAP_ENHANCEMENT
    ++    // Use pixel format native to DSS HW
    ++    mDisplayData[disp].format = HAL_PIXEL_FORMAT_BGRA_8888;
    ++#else
    +     mDisplayData[disp].format = HAL_PIXEL_FORMAT_RGBA_8888;
    ++#endif
    +     mDisplayData[disp].connected = true;
    +     return NO_ERROR;
    + }
    +@@ -853,7 +867,12 @@ int HWComposer::getVisualID() const {
    +         // FIXME: temporary hack until HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED
    +         // is supported by the implementation. we can only be in this case
    +         // if we have HWC 1.1
    ++#ifdef OMAP_ENHANCEMENT
    ++        // Use pixel format native to DSS HW
    ++        return HAL_PIXEL_FORMAT_BGRA_8888;
    ++#else
    +         return HAL_PIXEL_FORMAT_RGBA_8888;
    ++#endif
    +         //return HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED;
    +     } else {
    +         return mFbDev->format;
    +@@ -1260,7 +1279,7 @@ void HWComposer::dump(String8& result) const {
          }
      
          if (mHwc && mHwc->dump) {
    @@ -2125,6 +2480,26 @@ index 2190466..8c36d85 100644
          status_t result = mSource[source]->dequeueBuffer(sslot, fence,
                  mSinkBufferWidth, mSinkBufferHeight, format, usage);
          if (result < 0)
    +diff --git a/services/surfaceflinger/EventThread.cpp b/services/surfaceflinger/EventThread.cpp
    +index dd88adb..2dacd87 100644
    +--- a/services/surfaceflinger/EventThread.cpp
    ++++ b/services/surfaceflinger/EventThread.cpp
    +@@ -20,6 +20,7 @@
    + #include <sys/types.h>
    + 
    + #include <cutils/compiler.h>
    ++#include <cutils/iosched_policy.h>
    + 
    + #include <gui/BitTube.h>
    + #include <gui/IDisplayEventConnection.h>
    +@@ -92,6 +93,7 @@ void EventThread::sendVsyncHintOnLocked() {
    + 
    + void EventThread::onFirstRef() {
    +     run("EventThread", PRIORITY_URGENT_DISPLAY + PRIORITY_MORE_FAVORABLE);
    ++    android_set_rt_ioprio(getTid(), 1);
    + }
    + 
    + sp<EventThread::Connection> EventThread::createEventConnection() const {
     diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
     index 3ffa655..f8de24d 100644
     --- a/services/surfaceflinger/Layer.cpp
    @@ -2355,10 +2730,18 @@ index 7c3f9b5..b268119 100644
      public:
          GLES20RenderEngine();
     diff --git a/services/surfaceflinger/RenderEngine/RenderEngine.cpp b/services/surfaceflinger/RenderEngine/RenderEngine.cpp
    -index d6a032f..d0df8ab 100644
    +index d6a032f..28b3319 100644
     --- a/services/surfaceflinger/RenderEngine/RenderEngine.cpp
     +++ b/services/surfaceflinger/RenderEngine/RenderEngine.cpp
    -@@ -262,9 +262,11 @@ void RenderEngine::dump(String8& result) {
    +@@ -83,7 +83,6 @@ RenderEngine* RenderEngine::create(EGLDisplay display, int hwcFormat) {
    +             EGL_CONTEXT_CLIENT_VERSION, contextClientVersion,      // MUST be first
    + #ifdef EGL_IMG_context_priority
    + #ifdef HAS_CONTEXT_PRIORITY
    +-#warning "using EGL_IMG_context_priority"
    +             EGL_CONTEXT_PRIORITY_LEVEL_IMG, EGL_CONTEXT_PRIORITY_HIGH_IMG,
    + #endif
    + #endif
    +@@ -262,9 +261,11 @@ void RenderEngine::dump(String8& result) {
      // ---------------------------------------------------------------------------
      
      RenderEngine::BindImageAsFramebuffer::BindImageAsFramebuffer(
    @@ -2372,7 +2755,7 @@ index d6a032f..d0df8ab 100644
      
          ALOGE_IF(mStatus != GL_FRAMEBUFFER_COMPLETE_OES,
                  "glCheckFramebufferStatusOES error %d", mStatus);
    -@@ -272,7 +274,7 @@ RenderEngine::BindImageAsFramebuffer::BindImageAsFramebuffer(
    +@@ -272,7 +273,7 @@ RenderEngine::BindImageAsFramebuffer::BindImageAsFramebuffer(
      
      RenderEngine::BindImageAsFramebuffer::~BindImageAsFramebuffer() {
          // back to main framebuffer
    @@ -2408,10 +2791,26 @@ index 0259881..5a5910a 100644
              int getStatus() const;
          };
     diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
    -index 8e7e577..a04684c 100644
    +index 8e7e577..f1104a0 100644
     --- a/services/surfaceflinger/SurfaceFlinger.cpp
     +++ b/services/surfaceflinger/SurfaceFlinger.cpp
    -@@ -3437,7 +3437,8 @@ status_t SurfaceFlinger::captureScreen(const sp<IBinder>& display,
    +@@ -27,6 +27,7 @@
    + 
    + #include <EGL/egl.h>
    + 
    ++#include <cutils/iosched_policy.h>
    + #include <cutils/log.h>
    + #include <cutils/properties.h>
    + 
    +@@ -501,6 +502,7 @@ void SurfaceFlinger::init() {
    + 
    +     mEventControlThread = new EventControlThread(this);
    +     mEventControlThread->run("EventControl", PRIORITY_URGENT_DISPLAY);
    ++    android_set_rt_ioprio(mEventControlThread->getTid(), 1);
    + 
    +     // initialize our drawing state
    +     mDrawingState = mCurrentState;
    +@@ -3437,7 +3439,8 @@ status_t SurfaceFlinger::captureScreen(const sp<IBinder>& display,
              const sp<IGraphicBufferProducer>& producer,
              Rect sourceCrop, uint32_t reqWidth, uint32_t reqHeight,
              uint32_t minLayerZ, uint32_t maxLayerZ,
    @@ -2421,7 +2820,7 @@ index 8e7e577..a04684c 100644
      
          if (CC_UNLIKELY(display == 0))
              return BAD_VALUE;
    -@@ -3481,6 +3482,7 @@ status_t SurfaceFlinger::captureScreen(const sp<IBinder>& display,
    +@@ -3481,6 +3484,7 @@ status_t SurfaceFlinger::captureScreen(const sp<IBinder>& display,
              bool useIdentityTransform;
              Transform::orientation_flags rotation;
              status_t result;
    @@ -2429,7 +2828,7 @@ index 8e7e577..a04684c 100644
              bool isLocalScreenshot;
          public:
              MessageCaptureScreen(SurfaceFlinger* flinger,
    -@@ -3490,12 +3492,13 @@ status_t SurfaceFlinger::captureScreen(const sp<IBinder>& display,
    +@@ -3490,12 +3494,13 @@ status_t SurfaceFlinger::captureScreen(const sp<IBinder>& display,
                      uint32_t minLayerZ, uint32_t maxLayerZ,
                      bool useIdentityTransform,
                      Transform::orientation_flags rotation,
    @@ -2444,7 +2843,7 @@ index 8e7e577..a04684c 100644
                    isLocalScreenshot(isLocalScreenshot)
              {
              }
    -@@ -3505,9 +3508,10 @@ status_t SurfaceFlinger::captureScreen(const sp<IBinder>& display,
    +@@ -3505,9 +3510,10 @@ status_t SurfaceFlinger::captureScreen(const sp<IBinder>& display,
              virtual bool handler() {
                  Mutex::Autolock _l(flinger->mStateLock);
                  sp<const DisplayDevice> hw(flinger->getDisplayDevice(display));
    @@ -2456,7 +2855,7 @@ index 8e7e577..a04684c 100644
                  static_cast<GraphicProducerWrapper*>(IInterface::asBinder(producer).get())->exit(result);
                  return true;
              }
    -@@ -3523,7 +3527,7 @@ status_t SurfaceFlinger::captureScreen(const sp<IBinder>& display,
    +@@ -3523,7 +3529,7 @@ status_t SurfaceFlinger::captureScreen(const sp<IBinder>& display,
          sp<MessageBase> msg = new MessageCaptureScreen(this,
                  display, IGraphicBufferProducer::asInterface( wrapper ),
                  sourceCrop, reqWidth, reqHeight, minLayerZ, maxLayerZ,
    @@ -2465,7 +2864,7 @@ index 8e7e577..a04684c 100644
      
          status_t res = postMessageAsync(msg);
          if (res == NO_ERROR) {
    -@@ -3606,7 +3610,7 @@ status_t SurfaceFlinger::captureScreenImplLocked(
    +@@ -3606,7 +3612,7 @@ status_t SurfaceFlinger::captureScreenImplLocked(
              Rect sourceCrop, uint32_t reqWidth, uint32_t reqHeight,
              uint32_t minLayerZ, uint32_t maxLayerZ,
              bool useIdentityTransform, Transform::orientation_flags rotation,
    @@ -2474,7 +2873,7 @@ index 8e7e577..a04684c 100644
      {
          ATRACE_CALL();
      
    -@@ -3684,7 +3688,7 @@ status_t SurfaceFlinger::captureScreenImplLocked(
    +@@ -3684,7 +3690,7 @@ status_t SurfaceFlinger::captureScreenImplLocked(
                      if (image != EGL_NO_IMAGE_KHR) {
                          // this binds the given EGLImage as a framebuffer for the
                          // duration of this scope.
    @@ -2483,7 +2882,7 @@ index 8e7e577..a04684c 100644
                          if (imageBond.getStatus() == NO_ERROR) {
                              // this will in fact render into our dequeued buffer
                              // via an FBO, which means we didn't have to create
    -@@ -3731,6 +3735,16 @@ status_t SurfaceFlinger::captureScreenImplLocked(
    +@@ -3731,6 +3737,16 @@ status_t SurfaceFlinger::captureScreenImplLocked(
                                      ALOGW("captureScreen: error creating EGL fence: %#x", eglGetError());
                                  }
                              }
    @@ -2568,10 +2967,18 @@ index e0e4c61..6f2520b 100644
      #ifdef USE_HWC2
          err = updateAndReleaseLocked(item, &mPendingRelease);
     diff --git a/services/surfaceflinger/SurfaceFlinger_hwc1.cpp b/services/surfaceflinger/SurfaceFlinger_hwc1.cpp
    -index b32f652..b5b9697 100644
    +index b32f652..3d9c80f 100644
     --- a/services/surfaceflinger/SurfaceFlinger_hwc1.cpp
     +++ b/services/surfaceflinger/SurfaceFlinger_hwc1.cpp
    -@@ -185,6 +185,10 @@ SurfaceFlinger::SurfaceFlinger()
    +@@ -26,6 +26,7 @@
    + 
    + #include <EGL/egl.h>
    + 
    ++#include <cutils/iosched_policy.h>
    + #include <cutils/log.h>
    + #include <cutils/properties.h>
    + 
    +@@ -185,6 +186,10 @@ SurfaceFlinger::SurfaceFlinger()
          property_get("debug.sf.disable_hwc_vds", value, "0");
          mUseHwcVirtualDisplays = !atoi(value);
          ALOGI_IF(!mUseHwcVirtualDisplays, "Disabling HWC virtual displays");
    @@ -2582,7 +2989,7 @@ index b32f652..b5b9697 100644
      }
      
      void SurfaceFlinger::onFirstRef()
    -@@ -457,19 +461,28 @@ void SurfaceFlinger::init() {
    +@@ -457,19 +462,28 @@ void SurfaceFlinger::init() {
          eglInitialize(mEGLDisplay, NULL, NULL);
      
          // start the EventThread
    @@ -2622,7 +3029,15 @@ index b32f652..b5b9697 100644
          }
      
      
    -@@ -635,10 +648,18 @@ status_t SurfaceFlinger::getDisplayConfigs(const sp<IBinder>& display,
    +@@ -526,6 +540,7 @@ void SurfaceFlinger::init() {
    + 
    +     mEventControlThread = new EventControlThread(this);
    +     mEventControlThread->run("EventControl", PRIORITY_URGENT_DISPLAY);
    ++    android_set_rt_ioprio(mEventControlThread->getTid(), 1);
    + 
    +     // set a fake vsync period if there is no HWComposer
    +     if (mHwc->initCheck() != NO_ERROR) {
    +@@ -635,10 +650,18 @@ status_t SurfaceFlinger::getDisplayConfigs(const sp<IBinder>& display,
                  info.orientation = 0;
              }
      
    @@ -2645,7 +3060,7 @@ index b32f652..b5b9697 100644
              info.fps = float(1e9 / hwConfig.refresh);
              info.appVsyncOffset = VSYNC_EVENT_PHASE_OFFSET_NS;
      
    -@@ -3186,12 +3207,14 @@ status_t SurfaceFlinger::onTransact(
    +@@ -3186,12 +3209,14 @@ status_t SurfaceFlinger::onTransact(
                  }
                  case 1018: { // Modify Choreographer's phase offset
                      n = data.readInt32();
    @@ -2662,7 +3077,7 @@ index b32f652..b5b9697 100644
                      return NO_ERROR;
                  }
                  case 1021: { // Disable HWC virtual displays
    -@@ -3330,7 +3353,8 @@ status_t SurfaceFlinger::captureScreen(const sp<IBinder>& display,
    +@@ -3330,7 +3355,8 @@ status_t SurfaceFlinger::captureScreen(const sp<IBinder>& display,
              const sp<IGraphicBufferProducer>& producer,
              Rect sourceCrop, uint32_t reqWidth, uint32_t reqHeight,
              uint32_t minLayerZ, uint32_t maxLayerZ,
    @@ -2672,7 +3087,7 @@ index b32f652..b5b9697 100644
      
          if (CC_UNLIKELY(display == 0))
              return BAD_VALUE;
    -@@ -3374,6 +3398,7 @@ status_t SurfaceFlinger::captureScreen(const sp<IBinder>& display,
    +@@ -3374,6 +3400,7 @@ status_t SurfaceFlinger::captureScreen(const sp<IBinder>& display,
              bool useIdentityTransform;
              Transform::orientation_flags rotation;
              status_t result;
    @@ -2680,7 +3095,7 @@ index b32f652..b5b9697 100644
              bool isLocalScreenshot;
          public:
              MessageCaptureScreen(SurfaceFlinger* flinger,
    -@@ -3383,12 +3408,13 @@ status_t SurfaceFlinger::captureScreen(const sp<IBinder>& display,
    +@@ -3383,12 +3410,13 @@ status_t SurfaceFlinger::captureScreen(const sp<IBinder>& display,
                      uint32_t minLayerZ, uint32_t maxLayerZ,
                      bool useIdentityTransform,
                      Transform::orientation_flags rotation,
    @@ -2695,7 +3110,7 @@ index b32f652..b5b9697 100644
                    isLocalScreenshot(isLocalScreenshot)
              {
              }
    -@@ -3398,9 +3424,10 @@ status_t SurfaceFlinger::captureScreen(const sp<IBinder>& display,
    +@@ -3398,9 +3426,10 @@ status_t SurfaceFlinger::captureScreen(const sp<IBinder>& display,
              virtual bool handler() {
                  Mutex::Autolock _l(flinger->mStateLock);
                  sp<const DisplayDevice> hw(flinger->getDisplayDevice(display));
    @@ -2707,7 +3122,7 @@ index b32f652..b5b9697 100644
                  static_cast<GraphicProducerWrapper*>(IInterface::asBinder(producer).get())->exit(result);
                  return true;
              }
    -@@ -3416,7 +3443,7 @@ status_t SurfaceFlinger::captureScreen(const sp<IBinder>& display,
    +@@ -3416,7 +3445,7 @@ status_t SurfaceFlinger::captureScreen(const sp<IBinder>& display,
          sp<MessageBase> msg = new MessageCaptureScreen(this,
                  display, IGraphicBufferProducer::asInterface( wrapper ),
                  sourceCrop, reqWidth, reqHeight, minLayerZ, maxLayerZ,
    @@ -2716,7 +3131,7 @@ index b32f652..b5b9697 100644
      
          status_t res = postMessageAsync(msg);
          if (res == NO_ERROR) {
    -@@ -3501,7 +3528,7 @@ status_t SurfaceFlinger::captureScreenImplLocked(
    +@@ -3501,7 +3530,7 @@ status_t SurfaceFlinger::captureScreenImplLocked(
              Rect sourceCrop, uint32_t reqWidth, uint32_t reqHeight,
              uint32_t minLayerZ, uint32_t maxLayerZ,
              bool useIdentityTransform, Transform::orientation_flags rotation,
    @@ -2725,7 +3140,7 @@ index b32f652..b5b9697 100644
      {
          ATRACE_CALL();
      
    -@@ -3571,7 +3598,7 @@ status_t SurfaceFlinger::captureScreenImplLocked(
    +@@ -3571,7 +3600,7 @@ status_t SurfaceFlinger::captureScreenImplLocked(
                      if (image != EGL_NO_IMAGE_KHR) {
                          // this binds the given EGLImage as a framebuffer for the
                          // duration of this scope.
    @@ -2734,7 +3149,7 @@ index b32f652..b5b9697 100644
                          if (imageBond.getStatus() == NO_ERROR) {
                              // this will in fact render into our dequeued buffer
                              // via an FBO, which means we didn't have to create
    -@@ -3618,6 +3645,16 @@ status_t SurfaceFlinger::captureScreenImplLocked(
    +@@ -3618,6 +3647,16 @@ status_t SurfaceFlinger::captureScreenImplLocked(
                                      ALOGW("captureScreen: error creating EGL fence: %#x", eglGetError());
                                  }
                              }
    diff --git a/frameworks_op_net_wifi.patch b/frameworks_op_net_wifi.patch
    index ee4bdc8..af065a5 100644
    --- a/frameworks_op_net_wifi.patch
    +++ b/frameworks_op_net_wifi.patch
    @@ -46,3 +46,16 @@ index 89aabcf..7802b3d 100644
                              mIpManager.confirmConfiguration();
                          }
                          break;
    +diff --git a/service/java/com/android/server/wifi/p2p/WifiP2pServiceImpl.java b/service/java/com/android/server/wifi/p2p/WifiP2pServiceImpl.java
    +index c1d9445..b19af54 100644
    +--- a/service/java/com/android/server/wifi/p2p/WifiP2pServiceImpl.java
    ++++ b/service/java/com/android/server/wifi/p2p/WifiP2pServiceImpl.java
    +@@ -2026,7 +2026,7 @@ public class WifiP2pServiceImpl extends IWifiP2pManager.Stub {
    +                         final String ifname = mGroup.getInterface();
    +                         mNwService.addInterfaceToLocalNetwork(
    +                                 ifname, mDhcpResults.getRoutes(ifname));
    +-                    } catch (RemoteException e) {
    ++                    } catch (Exception e) {
    +                         loge("Failed to add iface to local network " + e);
    +                     }
    +                     break;
    diff --git a/hardware_broadcom_wlan.patch b/hardware_broadcom_wlan.patch
    index d9fce91..da9a260 100644
    --- a/hardware_broadcom_wlan.patch
    +++ b/hardware_broadcom_wlan.patch
    @@ -1,3 +1,35 @@
    +diff --git a/bcmdhd/firmware/bcm4339/fw_bcmdhd.bin b/bcmdhd/firmware/bcm4339/fw_bcmdhd.bin
    +index bc8316d..af2c885 100644
    +Binary files a/bcmdhd/firmware/bcm4339/fw_bcmdhd.bin and b/bcmdhd/firmware/bcm4339/fw_bcmdhd.bin differ
    +diff --git a/bcmdhd/firmware/bcm4339/fw_bcmdhd_apsta.bin b/bcmdhd/firmware/bcm4339/fw_bcmdhd_apsta.bin
    +index 11cf14b..4f5f105 100644
    +Binary files a/bcmdhd/firmware/bcm4339/fw_bcmdhd_apsta.bin and b/bcmdhd/firmware/bcm4339/fw_bcmdhd_apsta.bin differ
    +diff --git a/bcmdhd/firmware/bcm4354/fw_bcm4354.bin b/bcmdhd/firmware/bcm4354/fw_bcm4354.bin
    +index 724b1fa..213fdad 100644
    +Binary files a/bcmdhd/firmware/bcm4354/fw_bcm4354.bin and b/bcmdhd/firmware/bcm4354/fw_bcm4354.bin differ
    +diff --git a/bcmdhd/firmware/bcm4354/fw_bcm4354_ap.bin b/bcmdhd/firmware/bcm4354/fw_bcm4354_ap.bin
    +index 9c95b5c..cef8fc8 100644
    +Binary files a/bcmdhd/firmware/bcm4354/fw_bcm4354_ap.bin and b/bcmdhd/firmware/bcm4354/fw_bcm4354_ap.bin differ
    +diff --git a/bcmdhd/firmware/bcm4356/fw_bcm4356_ap_pcie.bin b/bcmdhd/firmware/bcm4356/fw_bcm4356_ap_pcie.bin
    +old mode 100755
    +new mode 100644
    +index f25ff54..0462a6e
    +Binary files a/bcmdhd/firmware/bcm4356/fw_bcm4356_ap_pcie.bin and b/bcmdhd/firmware/bcm4356/fw_bcm4356_ap_pcie.bin differ
    +diff --git a/bcmdhd/firmware/bcm4356/fw_bcm4356_pcie.bin b/bcmdhd/firmware/bcm4356/fw_bcm4356_pcie.bin
    +old mode 100755
    +new mode 100644
    +index 2544f66..2b89ae8
    +Binary files a/bcmdhd/firmware/bcm4356/fw_bcm4356_pcie.bin and b/bcmdhd/firmware/bcm4356/fw_bcm4356_pcie.bin differ
    +diff --git a/bcmdhd/firmware/bcm4358/fw_bcm4358.bin b/bcmdhd/firmware/bcm4358/fw_bcm4358.bin
    +old mode 100755
    +new mode 100644
    +index 2ae8dab..1bc8bb0
    +Binary files a/bcmdhd/firmware/bcm4358/fw_bcm4358.bin and b/bcmdhd/firmware/bcm4358/fw_bcm4358.bin differ
    +diff --git a/bcmdhd/firmware/bcm4358/fw_bcm4358_ap.bin b/bcmdhd/firmware/bcm4358/fw_bcm4358_ap.bin
    +old mode 100755
    +new mode 100644
    +index 19c26a8..8f49a70
    +Binary files a/bcmdhd/firmware/bcm4358/fw_bcm4358_ap.bin and b/bcmdhd/firmware/bcm4358/fw_bcm4358_ap.bin differ
     diff --git a/bcmdhd/wifi_hal/gscan.cpp b/bcmdhd/wifi_hal/gscan.cpp
     index 07155e2..73bfe8c 100644
     --- a/bcmdhd/wifi_hal/gscan.cpp
    diff --git a/system_bt.patch b/system_bt.patch
    index c22a42a..51e97db 100644
    --- a/system_bt.patch
    +++ b/system_bt.patch
    @@ -135,6 +135,33 @@ index 1995478..4367fce 100644
          fixed_queue_enqueue(p_scb->data_queue, p_new_buf);
          BT_HDR *p_event = (BT_HDR *)osi_malloc(sizeof(BT_HDR));
          p_event->layer_specific = handle;
    +diff --git a/btif/src/btif_rc.c b/btif/src/btif_rc.c
    +index 6572fd7..1e0fce6 100644
    +--- a/btif/src/btif_rc.c
    ++++ b/btif/src/btif_rc.c
    +@@ -42,6 +42,7 @@
    + #include "btif_util.h"
    + #include "bt_common.h"
    + #include "device/include/interop.h"
    ++#include "log/log.h"
    + #include "uinput.h"
    + #include "bdaddr.h"
    + #include "osi/include/list.h"
    +@@ -2762,8 +2763,13 @@ static void handle_app_cur_val_response (tBTA_AV_META_MSG *pmeta_msg, tAVRC_GET_
    +     }
    + 
    +     bdcpy(rc_addr.address, btif_rc_cb.rc_addr);
    +-
    +     app_settings.num_attr = p_rsp->num_val;
    ++
    ++    if (app_settings.num_attr > BTRC_MAX_APP_SETTINGS) {
    ++        android_errorWriteLog(0x534e4554, "73824150");
    ++        app_settings.num_attr = BTRC_MAX_APP_SETTINGS;
    ++    }
    ++
    +     for (xx = 0; xx < app_settings.num_attr; xx++)
    +     {
    +         app_settings.attr_ids[xx] = p_rsp->p_vals[xx].attr_id;
     diff --git a/btif/src/btif_sdp_server.c b/btif/src/btif_sdp_server.c
     index d02dfa0..90d74cf 100644
     --- a/btif/src/btif_sdp_server.c
    @@ -149,6 +176,21 @@ index d02dfa0..90d74cf 100644
              APPL_TRACE_ERROR("%s() failed - id %d is invalid", __func__, id);
              return handle;
          }
    +diff --git a/btif/src/btif_storage.c b/btif/src/btif_storage.c
    +index 83dcc8c..9abfe45 100644
    +--- a/btif/src/btif_storage.c
    ++++ b/btif/src/btif_storage.c
    +@@ -229,6 +229,10 @@ static int prop2cfg(bt_bdaddr_t *remote_bd_addr, bt_property_t *prop)
    +                 bt_uuid_t *p_uuid = (bt_uuid_t*)prop->val + i;
    +                 memset(buf, 0, sizeof(buf));
    +                 uuid_to_string_legacy(p_uuid, buf);
    ++                if (strlen(value) + strlen(buf) + 1 > (int) sizeof(value) - 1) {
    ++                    android_errorWriteLog(0x534e4554, "73963551");
    ++                    return false;
    ++                }
    +                 strcat(value, buf);
    +                 //strcat(value, ";");
    +                 strcat(value, " ");
     diff --git a/osi/src/alarm.c b/osi/src/alarm.c
     index 69ded69..5f9e42c 100644
     --- a/osi/src/alarm.c
    @@ -252,7 +294,7 @@ index 98ef5f7..5201054 100644
                  p_pkt->offset = L2CAP_MIN_OFFSET;
                  p = (UINT8 *)(p_pkt + 1) + p_pkt->offset;
     diff --git a/stack/avrc/avrc_pars_ct.c b/stack/avrc/avrc_pars_ct.c
    -index 63cc384..bd96d6c 100644
    +index 63cc384..92bda6b 100644
     --- a/stack/avrc/avrc_pars_ct.c
     +++ b/stack/avrc/avrc_pars_ct.c
     @@ -22,6 +22,7 @@
    @@ -263,7 +305,18 @@ index 63cc384..bd96d6c 100644
      
      /*****************************************************************************
      **  Global data
    -@@ -241,6 +242,12 @@ static tAVRC_STS avrc_ctrl_pars_vendor_rsp(
    +@@ -121,6 +122,10 @@ void avrc_parse_notification_rsp (UINT8 *p_stream, tAVRC_REG_NOTIF_RSP *p_rsp)
    + 
    +         case AVRC_EVT_APP_SETTING_CHANGE:
    +             BE_STREAM_TO_UINT8(p_rsp->param.player_setting.num_attr, p_stream);
    ++            if (p_rsp->param.player_setting.num_attr > AVRC_MAX_APP_SETTINGS) {
    ++                android_errorWriteLog(0x534e4554, "73782082");
    ++                p_rsp->param.player_setting.num_attr = AVRC_MAX_APP_SETTINGS;
    ++            }
    +             for (int index = 0; index < p_rsp->param.player_setting.num_attr; index++)
    +             {
    +                 BE_STREAM_TO_UINT8(p_rsp->param.player_setting.attr_id[index], p_stream);
    +@@ -241,6 +246,12 @@ static tAVRC_STS avrc_ctrl_pars_vendor_rsp(
              }
              BE_STREAM_TO_UINT8(p_result->list_app_values.num_val, p);
              AVRC_TRACE_DEBUG("%s value count = %d ", __func__, p_result->list_app_values.num_val);
    @@ -276,7 +329,7 @@ index 63cc384..bd96d6c 100644
              for(int xx = 0; xx < p_result->list_app_values.num_val; xx++)
              {
                  BE_STREAM_TO_UINT8(p_result->list_app_values.vals[xx], p);
    -@@ -258,6 +265,12 @@ static tAVRC_STS avrc_ctrl_pars_vendor_rsp(
    +@@ -258,6 +269,12 @@ static tAVRC_STS avrc_ctrl_pars_vendor_rsp(
              tAVRC_APP_SETTING *app_sett =
                  (tAVRC_APP_SETTING*)osi_malloc(p_result->get_cur_app_val.num_val*sizeof(tAVRC_APP_SETTING));
              AVRC_TRACE_DEBUG("%s attr count = %d ", __func__, p_result->get_cur_app_val.num_val);
    @@ -289,7 +342,7 @@ index 63cc384..bd96d6c 100644
              for (int xx = 0; xx < p_result->get_cur_app_val.num_val; xx++)
              {
                  BE_STREAM_TO_UINT8(app_sett[xx].attr_id, p);
    -@@ -269,7 +282,6 @@ static tAVRC_STS avrc_ctrl_pars_vendor_rsp(
    +@@ -269,7 +286,6 @@ static tAVRC_STS avrc_ctrl_pars_vendor_rsp(
      
          case AVRC_PDU_GET_PLAYER_APP_ATTR_TEXT:
          {
    @@ -297,7 +350,7 @@ index 63cc384..bd96d6c 100644
              UINT8                    num_attrs;
      
              if (len == 0)
    -@@ -278,9 +290,12 @@ static tAVRC_STS avrc_ctrl_pars_vendor_rsp(
    +@@ -278,9 +294,12 @@ static tAVRC_STS avrc_ctrl_pars_vendor_rsp(
                  break;
              }
              BE_STREAM_TO_UINT8(num_attrs, p);
    @@ -311,7 +364,7 @@ index 63cc384..bd96d6c 100644
              for (int xx = 0; xx < num_attrs; xx++)
              {
                  BE_STREAM_TO_UINT8(p_result->get_app_attr_txt.p_attrs[xx].attr_id, p);
    -@@ -300,7 +315,6 @@ static tAVRC_STS avrc_ctrl_pars_vendor_rsp(
    +@@ -300,7 +319,6 @@ static tAVRC_STS avrc_ctrl_pars_vendor_rsp(
      
          case AVRC_PDU_GET_PLAYER_APP_VALUE_TEXT:
          {
    @@ -319,7 +372,7 @@ index 63cc384..bd96d6c 100644
              UINT8                    num_vals;
      
              if (len == 0)
    -@@ -309,10 +323,13 @@ static tAVRC_STS avrc_ctrl_pars_vendor_rsp(
    +@@ -309,10 +327,13 @@ static tAVRC_STS avrc_ctrl_pars_vendor_rsp(
                  break;
              }
              BE_STREAM_TO_UINT8(num_vals, p);
    @@ -741,6 +794,29 @@ index 11ef79c..c2cdb88 100644
          UNUSED(len);
      
          if (op_code == GATT_REQ_READ_BLOB)
    +diff --git a/stack/l2cap/l2c_ble.c b/stack/l2cap/l2c_ble.c
    +index 95de4e3..f61416c 100644
    +--- a/stack/l2cap/l2c_ble.c
    ++++ b/stack/l2cap/l2c_ble.c
    +@@ -27,6 +27,7 @@
    + #include "bt_utils.h"
    + #include "l2cdefs.h"
    + #include "l2c_int.h"
    ++#include "log/log.h"
    + #include "btu.h"
    + #include "btm_int.h"
    + #include "hcimsgs.h"
    +@@ -808,6 +809,10 @@ void l2cble_process_sig_cmd (tL2C_LCB *p_lcb, UINT8 *p, UINT16 pkt_len)
    +             break;
    + 
    +         case L2CAP_CMD_DISC_REQ:
    ++            if (p + 4 > p_pkt_end) {
    ++                android_errorWriteLog(0x534e4554, "74121659");
    ++                return;
    ++            }
    +             STREAM_TO_UINT16 (lcid, p);
    +             STREAM_TO_UINT16 (rcid, p);
    + 
     diff --git a/stack/l2cap/l2c_fcr.c b/stack/l2cap/l2c_fcr.c
     index 5ba8b56..282b171 100644
     --- a/stack/l2cap/l2c_fcr.c
    @@ -1574,6 +1650,32 @@ index 05414cd..71dab92 100644
      extern void     sdp_disconnect (tCONN_CB*p_ccb, UINT16 reason);
      
      #if (defined(SDP_DEBUG) && SDP_DEBUG == TRUE)
    +diff --git a/stack/smp/smp_main.c b/stack/smp/smp_main.c
    +index c3709f8..96cf555 100644
    +--- a/stack/smp/smp_main.c
    ++++ b/stack/smp/smp_main.c
    +@@ -17,6 +17,7 @@
    +  ******************************************************************************/
    + 
    + #include "bt_target.h"
    ++#include <cutils/log.h>
    + 
    + #if SMP_INCLUDED == TRUE
    + 
    +@@ -770,6 +771,13 @@ void smp_sm_event(tSMP_CB *p_cb, tSMP_EVENT event, void *p_data)
    +     UINT8           curr_state = p_cb->state;
    +     tSMP_SM_TBL     state_table;
    +     UINT8           action, entry, i;
    ++
    ++    if (p_cb->role >= 2) {
    ++      SMP_TRACE_DEBUG("Invalid role: %d", p_cb->role);
    ++      android_errorWriteLog(0x534e4554, "74121126");
    ++      return;
    ++    }
    ++
    +     tSMP_ENTRY_TBL  entry_table =  smp_entry_table[p_cb->role];
    + 
    +     SMP_TRACE_EVENT("main smp_sm_event");
     diff --git a/stack/smp/smp_utils.c b/stack/smp/smp_utils.c
     index a7357db..93c9a23 100644
     --- a/stack/smp/smp_utils.c
    diff --git a/system_media.patch b/system_media.patch
    index 1f7ebca..48fc292 100644
    --- a/system_media.patch
    +++ b/system_media.patch
    @@ -1,17 +1,28 @@
     diff --git a/camera/src/camera_metadata.c b/camera/src/camera_metadata.c
    -index e369c64..f76c99e 100644
    +index e369c64..70074c8 100644
     --- a/camera/src/camera_metadata.c
     +++ b/camera/src/camera_metadata.c
    -@@ -182,6 +182,12 @@ camera_metadata_t *allocate_copy_camera_metadata_checked(
    +@@ -182,7 +182,13 @@ camera_metadata_t *allocate_copy_camera_metadata_checked(
              return NULL;
          }
      
    +-    void *buffer = malloc(src_size);
     +    if (src_size < sizeof(camera_metadata_t)) {
     +        ALOGE("%s: Source size too small!", __FUNCTION__);
     +        android_errorWriteLog(0x534e4554, "67782345");
     +        return NULL;
     +    }
     +
    -     void *buffer = malloc(src_size);
    ++    void *buffer = calloc(1, src_size);
          memcpy(buffer, src, src_size);
      
    +     camera_metadata_t *metadata = (camera_metadata_t*) buffer;
    +@@ -199,7 +205,7 @@ camera_metadata_t *allocate_camera_metadata(size_t entry_capacity,
    + 
    +     size_t memory_needed = calculate_camera_metadata_size(entry_capacity,
    +                                                           data_capacity);
    +-    void *buffer = malloc(memory_needed);
    ++    void *buffer = calloc(1, memory_needed);
    +     return place_camera_metadata(buffer, memory_needed,
    +                                  entry_capacity,
    +                                  data_capacity);
    
    From 3bf678cc8cff7a4dc7abf11c102bffd4dba4c022 Mon Sep 17 00:00:00 2001
    From: AndDiSa <anddisa@googlemail.com>
    Date: Mon, 30 Jul 2018 16:36:08 +0200
    Subject: [PATCH 098/159] update patches
    
    Change-Id: I13a1ae0f9cb56a8e34a628fa1df19eb4e69b2d4d
    ---
     build.patch         | 12 ++++++++++++
     frameworks_av.patch | 12 ++++++++++++
     2 files changed, 24 insertions(+)
    
    diff --git a/build.patch b/build.patch
    index e3617ec..4483802 100644
    --- a/build.patch
    +++ b/build.patch
    @@ -352,6 +352,18 @@ index 0a4e0fd..5508c12 100644
          VpnDialogs \
          MmsService
      
    +diff --git a/target/product/generic_no_telephony.mk b/target/product/generic_no_telephony.mk
    +index 5c48358..c655d50 100644
    +--- a/target/product/generic_no_telephony.mk
    ++++ b/target/product/generic_no_telephony.mk
    +@@ -48,7 +48,6 @@ PRODUCT_PACKAGES += \
    +     audio.primary.default \
    +     audio_policy.default \
    +     local_time.default \
    +-    vibrator.default \
    +     power.default
    + 
    + PRODUCT_COPY_FILES := \
     diff --git a/tools/releasetools/ota_from_target_files.py b/tools/releasetools/ota_from_target_files.py
     index d409d94..6aa14d2 100755
     --- a/tools/releasetools/ota_from_target_files.py
    diff --git a/frameworks_av.patch b/frameworks_av.patch
    index f2a6c17..ffa6120 100644
    --- a/frameworks_av.patch
    +++ b/frameworks_av.patch
    @@ -2321,6 +2321,18 @@ index 56e1f77..04d8dda 100644
                  if (mColorFormat == OMX_COLOR_FormatYUV420SemiPlanar) {
                      ConvertYUV420SemiPlanarToYUV420Planar(
                              source, mConversionBuffer, mWidth, mHeight);
    +diff --git a/media/libstagefright/foundation/MediaBuffer.cpp b/media/libstagefright/foundation/MediaBuffer.cpp
    +index 16000ef..82b989c 100644
    +--- a/media/libstagefright/foundation/MediaBuffer.cpp
    ++++ b/media/libstagefright/foundation/MediaBuffer.cpp
    +@@ -155,6 +155,7 @@ size_t MediaBuffer::range_length() const {
    + void MediaBuffer::set_range(size_t offset, size_t length) {
    +     if ((mGraphicBuffer == NULL) && (offset + length > mSize)) {
    +         ALOGE("offset = %zu, length = %zu, mSize = %zu", offset, length, mSize);
    ++	offset = 0;
    +     }
    +     CHECK((mGraphicBuffer != NULL) || (offset + length <= mSize));
    + 
     diff --git a/media/libstagefright/foundation/MediaBufferGroup.cpp b/media/libstagefright/foundation/MediaBufferGroup.cpp
     index 8e4d064..66992d7 100644
     --- a/media/libstagefright/foundation/MediaBufferGroup.cpp
    
    From 6c14fc0aef9590b7062900547378f12b13c7bee2 Mon Sep 17 00:00:00 2001
    From: AndDiSa <anddisa@googlemail.com>
    Date: Thu, 9 Aug 2018 19:25:32 +0200
    Subject: [PATCH 099/159] update patches
    
    Change-Id: I4b305e117214280e002b156696fec9ae3c217f35
    ---
     build.patch                   |  16 +--
     external_curl.patch           |  63 ++++++++++
     external_e2fsprogs.patch      |  28 +++++
     external_libdrm.patch         |  15 +++
     frameworks_base.patch         |  26 +++-
     frameworks_ex.patch           |  27 +++++
     packages_apps_messaging.patch |  89 ++++++++++++++
     system_bt.patch               | 216 ++++++++++++++++++++++++++++++----
     8 files changed, 437 insertions(+), 43 deletions(-)
     create mode 100644 external_curl.patch
     create mode 100644 external_e2fsprogs.patch
     create mode 100644 external_libdrm.patch
     create mode 100644 frameworks_ex.patch
    
    diff --git a/build.patch b/build.patch
    index 4483802..eeb3a28 100644
    --- a/build.patch
    +++ b/build.patch
    @@ -323,7 +323,7 @@ index 0000000..80664fa
     +ALL_PREBUILT += $(INSTALLED_KERNEL_TARGET)
     +endif
     diff --git a/core/version_defaults.mk b/core/version_defaults.mk
    -index 7c96344..4470fa4 100644
    +index 7c96344..1829c30 100644
     --- a/core/version_defaults.mk
     +++ b/core/version_defaults.mk
     @@ -131,7 +131,7 @@ ifeq "" "$(PLATFORM_SECURITY_PATCH)"
    @@ -331,7 +331,7 @@ index 7c96344..4470fa4 100644
          #  It must match one of the Android Security Patch Level strings of the Public Security Bulletins.
          #  If there is no $PLATFORM_SECURITY_PATCH set, keep it empty.
     -    PLATFORM_SECURITY_PATCH := 2017-08-05
    -+    PLATFORM_SECURITY_PATCH := 2018-07-05
    ++    PLATFORM_SECURITY_PATCH := 2018-08-05
      endif
      
      ifeq "" "$(PLATFORM_BASE_OS)"
    @@ -352,18 +352,6 @@ index 0a4e0fd..5508c12 100644
          VpnDialogs \
          MmsService
      
    -diff --git a/target/product/generic_no_telephony.mk b/target/product/generic_no_telephony.mk
    -index 5c48358..c655d50 100644
    ---- a/target/product/generic_no_telephony.mk
    -+++ b/target/product/generic_no_telephony.mk
    -@@ -48,7 +48,6 @@ PRODUCT_PACKAGES += \
    -     audio.primary.default \
    -     audio_policy.default \
    -     local_time.default \
    --    vibrator.default \
    -     power.default
    - 
    - PRODUCT_COPY_FILES := \
     diff --git a/tools/releasetools/ota_from_target_files.py b/tools/releasetools/ota_from_target_files.py
     index d409d94..6aa14d2 100755
     --- a/tools/releasetools/ota_from_target_files.py
    diff --git a/external_curl.patch b/external_curl.patch
    new file mode 100644
    index 0000000..b1cd374
    --- /dev/null
    +++ b/external_curl.patch
    @@ -0,0 +1,63 @@
    +diff --git a/lib/curl_config.h b/lib/curl_config.h
    +index 0288018..e9b7958 100644
    +--- a/lib/curl_config.h
    ++++ b/lib/curl_config.h
    +@@ -17,22 +17,22 @@
    + /* #undef CURL_DISABLE_CRYPTO_AUTH */
    + 
    + /* to disable DICT */
    +-/* #undef CURL_DISABLE_DICT */
    ++#define CURL_DISABLE_DICT 1
    + 
    + /* to disable FILE */
    + /* #undef CURL_DISABLE_FILE */
    + 
    + /* to disable FTP */
    +-/* #undef CURL_DISABLE_FTP */
    ++#define CURL_DISABLE_FTP 1
    + 
    + /* to disable Gopher */
    +-/* #undef CURL_DISABLE_GOPHER */
    ++#define CURL_DISABLE_GOPHER 1
    + 
    + /* to disable HTTP */
    + /* #undef CURL_DISABLE_HTTP */
    + 
    + /* to disable IMAP */
    +-/* #undef CURL_DISABLE_IMAP */
    ++#define CURL_DISABLE_IMAP 1
    + 
    + /* to disable LDAP */
    + #define CURL_DISABLE_LDAP 1
    +@@ -44,25 +44,25 @@
    + /* #undef CURL_DISABLE_LIBCURL_OPTION */
    + 
    + /* to disable POP3 */
    +-/* #undef CURL_DISABLE_POP3 */
    ++#define CURL_DISABLE_POP3 1
    + 
    + /* to disable proxies */
    + /* #undef CURL_DISABLE_PROXY */
    + 
    + /* to disable RTSP */
    +-/* #undef CURL_DISABLE_RTSP */
    ++#define CURL_DISABLE_RTSP 1
    + 
    + /* to disable SMB/CIFS */
    +-/* #undef CURL_DISABLE_SMB */
    ++#define CURL_DISABLE_SMB 1
    + 
    + /* to disable SMTP */
    +-/* #undef CURL_DISABLE_SMTP */
    ++#define CURL_DISABLE_SMTP 1
    + 
    + /* to disable TELNET */
    +-/* #undef CURL_DISABLE_TELNET */
    ++#define CURL_DISABLE_TELNET 1
    + 
    + /* to disable TFTP */
    +-/* #undef CURL_DISABLE_TFTP */
    ++#define CURL_DISABLE_TFTP 1
    + 
    + /* to disable TLS-SRP authentication */
    + /* #undef CURL_DISABLE_TLS_SRP */
    diff --git a/external_e2fsprogs.patch b/external_e2fsprogs.patch
    new file mode 100644
    index 0000000..4ba54c6
    --- /dev/null
    +++ b/external_e2fsprogs.patch
    @@ -0,0 +1,28 @@
    +diff --git a/e2fsck/logfile.c b/e2fsck/logfile.c
    +index 40e5acb..3e4df8a 100644
    +--- a/e2fsck/logfile.c
    ++++ b/e2fsck/logfile.c
    +@@ -67,7 +67,7 @@ static void expand_percent_expression(e2fsck_t ctx, char ch,
    + 				      struct string *s, int *flags)
    + {
    + 	struct tm	*tm = NULL, tm_struct;
    +-	struct passwd	*pw = NULL, pw_struct;
    ++	struct passwd	*pw = NULL;
    + 	char		*cp;
    + 	char		buf[256];
    + 
    +diff --git a/misc/blkid.c b/misc/blkid.c
    +index 388abad..248cacf 100644
    +--- a/misc/blkid.c
    ++++ b/misc/blkid.c
    +@@ -86,7 +86,9 @@ static void safe_print(const char *cp, int len)
    + 			fputc('^', stdout);
    + 			ch ^= 0x40; /* ^@, ^A, ^B; ^? for DEL */
    + 		}
    +-		fputc(ch, stdout);
    ++		if (ch != '"') {
    ++			fputc(ch, stdout);
    ++		}
    + 	}
    + }
    + 
    diff --git a/external_libdrm.patch b/external_libdrm.patch
    new file mode 100644
    index 0000000..6e6503f
    --- /dev/null
    +++ b/external_libdrm.patch
    @@ -0,0 +1,15 @@
    +diff --git a/xf86drm.c b/xf86drm.c
    +index 7e28b4f..67f9f83 100644
    +--- a/xf86drm.c
    ++++ b/xf86drm.c
    +@@ -732,8 +732,8 @@ int drmOpen(const char *name, const char *busid)
    +  */
    + int drmOpenWithType(const char *name, const char *busid, int type)
    + {
    +-    if (!drmAvailable() && name != NULL && drm_server_info &&
    +-        drm_server_info->load_module) {
    ++    if (name != NULL && drm_server_info &&
    ++        drm_server_info->load_module && !drmAvailable()) {
    + 	/* try to load the kernel module */
    + 	if (!drm_server_info->load_module(name)) {
    + 	    drmMsg("[drm] failed to load kernel module \"%s\"\n", name);
    diff --git a/frameworks_base.patch b/frameworks_base.patch
    index 2d9e098..40b0aef 100644
    --- a/frameworks_base.patch
    +++ b/frameworks_base.patch
    @@ -882,7 +882,7 @@ index 6fa28b1..ea0347d 100644
      
          @SmallTest
     diff --git a/libs/androidfw/ResourceTypes.cpp b/libs/androidfw/ResourceTypes.cpp
    -index ceeb12b..803f635 100644
    +index ceeb12b..d9efe2b 100644
     --- a/libs/androidfw/ResourceTypes.cpp
     +++ b/libs/androidfw/ResourceTypes.cpp
     @@ -457,6 +457,22 @@ status_t ResStringPool::setTo(const void* data, size_t size, bool copyData)
    @@ -891,7 +891,7 @@ index ceeb12b..803f635 100644
      
     +    // The chunk must be at least the size of the string pool header.
     +    if (size < sizeof(ResStringPool_header)) {
    -+        LOG_ALWAYS_FATAL("Bad string block: data size %zu is too small to be a string block", size);
    ++        ALOGW("Bad string block: data size %zu is too small to be a string block", size);
     +        return (mError=BAD_TYPE);
     +    }
     +
    @@ -901,7 +901,7 @@ index ceeb12b..803f635 100644
     +    if (validate_chunk(reinterpret_cast<const ResChunk_header*>(data), sizeof(ResStringPool_header),
     +                       reinterpret_cast<const uint8_t*>(data) + size,
     +                       "ResStringPool_header") != NO_ERROR) {
    -+        LOG_ALWAYS_FATAL("Bad string block: malformed block dimensions");
    ++        ALOGW("Bad string block: malformed block dimensions");
     +        return (mError=BAD_TYPE);
     +    }
     +
    @@ -917,6 +917,24 @@ index ceeb12b..803f635 100644
          mHeader = (const ResStringPool_header*)data;
      
          if (notDeviceEndian) {
    +@@ -6391,8 +6409,16 @@ status_t ResTable::parsePackage(const ResTable_package* const pkg,
    +             }
    + 
    +         } else if (ctype == RES_TABLE_LIBRARY_TYPE) {
    ++
    +             if (group->dynamicRefTable.entries().size() == 0) {
    +-                status_t err = group->dynamicRefTable.load((const ResTable_lib_header*) chunk);
    ++                const ResTable_lib_header* lib = (const ResTable_lib_header*) chunk;
    ++                status_t err = validate_chunk(&lib->header, sizeof(*lib),
    ++                                              endPos, "ResTable_lib_header");
    ++                if (err != NO_ERROR) {
    ++                    return (mError=err);
    ++                }
    ++
    ++                err = group->dynamicRefTable.load(lib);
    +                 if (err != NO_ERROR) {
    +                     return (mError=err);
    +                 }
     diff --git a/libs/hwui/Android.mk b/libs/hwui/Android.mk
     index cacfce1..0b177b9 100644
     --- a/libs/hwui/Android.mk
    @@ -13756,7 +13774,7 @@ index 450653c..0000000
     -}
     diff --git a/services/tests/servicestests/src/com/android/server/connectivity/LingerMonitorTest.java b/services/tests/servicestests/src/com/android/server/connectivity/LingerMonitorTest.java
     deleted file mode 100644
    -index bce5787..0000000
    +index bce5787e..0000000
     --- a/services/tests/servicestests/src/com/android/server/connectivity/LingerMonitorTest.java
     +++ /dev/null
     @@ -1,349 +0,0 @@
    diff --git a/frameworks_ex.patch b/frameworks_ex.patch
    new file mode 100644
    index 0000000..b17a126
    --- /dev/null
    +++ b/frameworks_ex.patch
    @@ -0,0 +1,27 @@
    +diff --git a/framesequence/jni/FrameSequence_gif.cpp b/framesequence/jni/FrameSequence_gif.cpp
    +index 5118319..f6f46da 100644
    +--- a/framesequence/jni/FrameSequence_gif.cpp
    ++++ b/framesequence/jni/FrameSequence_gif.cpp
    +@@ -111,12 +111,14 @@ FrameSequence_gif::FrameSequence_gif(Stream* stream) :
    +     }
    + #endif
    + 
    +-    if (mGif->SColorMap) {
    ++    const ColorMapObject* cmap = mGif->SColorMap;
    ++    if (cmap) {
    +         // calculate bg color
    +         GraphicsControlBlock gcb;
    +         DGifSavedExtensionToGCB(mGif, 0, &gcb);
    +-        if (gcb.TransparentColor == NO_TRANSPARENT_COLOR) {
    +-            mBgColor = gifColorToColor8888(mGif->SColorMap->Colors[mGif->SBackGroundColor]);
    ++        if (gcb.TransparentColor == NO_TRANSPARENT_COLOR
    ++                && mGif->SBackGroundColor < cmap->ColorCount) {
    ++            mBgColor = gifColorToColor8888(cmap->Colors[mGif->SBackGroundColor]);
    +         }
    +     }
    + }
    +@@ -359,4 +361,3 @@ static RegistryEntry gEntry = {
    +         acceptsBuffers,
    + };
    + static Registry gRegister(gEntry);
    +-
    diff --git a/packages_apps_messaging.patch b/packages_apps_messaging.patch
    index 447d1a9..140fa4d 100644
    --- a/packages_apps_messaging.patch
    +++ b/packages_apps_messaging.patch
    @@ -26,3 +26,92 @@ index d50cf47..6801165 100644
          }
      
          @Override
    +diff --git a/src/com/android/messaging/ui/conversationlist/ShareIntentActivity.java b/src/com/android/messaging/ui/conversationlist/ShareIntentActivity.java
    +index 83b7be9..1c91e46 100644
    +--- a/src/com/android/messaging/ui/conversationlist/ShareIntentActivity.java
    ++++ b/src/com/android/messaging/ui/conversationlist/ShareIntentActivity.java
    +@@ -35,6 +35,7 @@ import com.android.messaging.util.ContentType;
    + import com.android.messaging.util.LogUtil;
    + import com.android.messaging.util.MediaMetadataRetrieverWrapper;
    + import com.android.messaging.util.FileUtil;
    ++import com.android.messaging.util.UriUtil;
    + 
    + import java.io.IOException;
    + import java.util.ArrayList;
    +@@ -75,6 +76,12 @@ public class ShareIntentActivity extends BaseBugleActivity implements
    +         final String action = intent.getAction();
    +         if (Intent.ACTION_SEND.equals(action)) {
    +             final Uri contentUri = (Uri) intent.getParcelableExtra(Intent.EXTRA_STREAM);
    ++            if (UriUtil.isFileUri(contentUri)) {
    ++                LogUtil.i(
    ++                    LogUtil.BUGLE_TAG,
    ++                    "Ignoring attachment from file URI which are no longer supported.");
    ++                return;
    ++            }
    +             final String contentType = extractContentType(contentUri, intent.getType());
    +             if (LogUtil.isLoggable(LogUtil.BUGLE_TAG, LogUtil.DEBUG)) {
    +                 LogUtil.d(LogUtil.BUGLE_TAG, String.format(
    +@@ -112,6 +119,12 @@ public class ShareIntentActivity extends BaseBugleActivity implements
    +                 if (imageUris != null && imageUris.size() > 0) {
    +                     mDraftMessage = MessageData.createSharedMessage(null);
    +                     for (final Uri imageUri : imageUris) {
    ++                        if (UriUtil.isFileUri(imageUri)) {
    ++                            LogUtil.i(
    ++                                LogUtil.BUGLE_TAG,
    ++                                "Ignoring attachment from file URI which are no longer supported.");
    ++                            continue;
    ++                        }
    +                         final String actualContentType = extractContentType(imageUri, contentType);
    +                         addSharedImagePartToDraft(actualContentType, imageUri);
    +                     }
    +diff --git a/src/com/android/messaging/util/DebugUtils.java b/src/com/android/messaging/util/DebugUtils.java
    +index f2c1d65..1362f83 100644
    +--- a/src/com/android/messaging/util/DebugUtils.java
    ++++ b/src/com/android/messaging/util/DebugUtils.java
    +@@ -22,12 +22,15 @@ import android.app.FragmentManager;
    + import android.app.FragmentTransaction;
    + import android.content.Context;
    + import android.content.DialogInterface;
    ++import android.content.Intent;
    + import android.media.MediaPlayer;
    ++import android.net.Uri;
    + import android.os.Environment;
    + import android.telephony.SmsMessage;
    + import android.text.TextUtils;
    + import android.widget.ArrayAdapter;
    + 
    ++import com.android.messaging.Factory;
    + import com.android.messaging.R;
    + import com.android.messaging.datamodel.SyncManager;
    + import com.android.messaging.datamodel.action.DumpDatabaseAction;
    +@@ -179,6 +182,13 @@ public class DebugUtils {
    +             }
    +         });
    + 
    ++        arrayAdapter.add(new DebugAction("Test sharing a file URI") {
    ++            @Override
    ++            public void run() {
    ++                shareFileUri();
    ++            }
    ++        });
    ++
    +         builder.setAdapter(arrayAdapter,
    +                 new android.content.DialogInterface.OnClickListener() {
    +             @Override
    +@@ -422,4 +432,16 @@ public class DebugUtils {
    +     public static boolean debugClassZeroSmsEnabled() {
    +         return sDebugClassZeroSms;
    +     }
    ++
    ++    /** Shares a ringtone file via file URI. */
    ++    private static void shareFileUri() {
    ++        final String packageName = "com.android.messaging";
    ++        final String fileName = "/system/media/audio/ringtones/Andromeda.ogg";
    ++
    ++        Intent intent = new Intent(Intent.ACTION_SEND);
    ++        intent.setPackage(packageName);
    ++        intent.putExtra(Intent.EXTRA_STREAM, Uri.parse("file://" + fileName));
    ++        intent.setType("image/*");
    ++        Factory.get().getApplicationContext().startActivity(intent);
    ++    }
    + }
    diff --git a/system_bt.patch b/system_bt.patch
    index 51e97db..72608d5 100644
    --- a/system_bt.patch
    +++ b/system_bt.patch
    @@ -293,6 +293,74 @@ index 98ef5f7..5201054 100644
      
                  p_pkt->offset = L2CAP_MIN_OFFSET;
                  p = (UINT8 *)(p_pkt + 1) + p_pkt->offset;
    +diff --git a/stack/avdt/avdt_msg.c b/stack/avdt/avdt_msg.c
    +index adc1ae7..9697a59 100644
    +--- a/stack/avdt/avdt_msg.c
    ++++ b/stack/avdt/avdt_msg.c
    +@@ -26,6 +26,7 @@
    +  *
    +  ******************************************************************************/
    + 
    ++#include <log/log.h>
    + #include <string.h>
    + #include "bt_types.h"
    + #include "bt_target.h"
    +@@ -673,6 +674,11 @@ static UINT8 avdt_msg_prs_cfg(tAVDT_CFG *p_cfg, UINT8 *p, UINT16 len, UINT8* p_e
    + 
    +             case AVDT_CAT_PROTECT:
    +                 p_cfg->psc_mask &= ~AVDT_PSC_PROTECT;
    ++                if (p + elem_len > p_end) {
    ++                    err = AVDT_ERR_LENGTH;
    ++                    android_errorWriteLog(0x534e4554, "78288378");
    ++                    break;
    ++                }
    +                 if ((elem_len + protect_offset) < AVDT_PROTECT_SIZE)
    +                 {
    +                     p_cfg->num_protect++;
    +@@ -747,6 +753,11 @@ static UINT8 avdt_msg_prs_cfg(tAVDT_CFG *p_cfg, UINT8 *p, UINT16 len, UINT8* p_e
    +                 {
    +                     tmp = AVDT_CODEC_SIZE - 1;
    +                 }
    ++                if (p + tmp > p_end) {
    ++                    err = AVDT_ERR_LENGTH;
    ++                    android_errorWriteLog(0x534e4554, "78288378");
    ++                    break;
    ++                }
    +                 p_cfg->num_codec++;
    +                 p_cfg->codec_info[0] = elem_len;
    +                 memcpy(&p_cfg->codec_info[1], p, tmp);
    +diff --git a/stack/avrc/avrc_api.c b/stack/avrc/avrc_api.c
    +index 77ca7d4..ffd690a 100644
    +--- a/stack/avrc/avrc_api.c
    ++++ b/stack/avrc/avrc_api.c
    +@@ -316,15 +316,15 @@ static BT_HDR * avrc_proc_vendor_command(UINT8 handle, UINT8 label,
    + 
    +     if (status != AVRC_STS_NO_ERROR)
    +     {
    +-        /* use the current GKI buffer to build/send the reject message */
    +-        p_data = (UINT8 *)(p_pkt+1) + p_pkt->offset;
    ++        p_rsp = (BT_HDR*)osi_malloc(BT_DEFAULT_BUFFER_SIZE);
    ++        p_rsp->offset = p_pkt->offset;
    ++        p_data = (uint8_t*)(p_rsp + 1) + p_pkt->offset;
    +         *p_data++ = AVRC_RSP_REJ;
    +         p_data += AVRC_VENDOR_HDR_SIZE; /* pdu */
    +         *p_data++ = 0;                  /* pkt_type */
    +         UINT16_TO_BE_STREAM(p_data, 1); /* len */
    +         *p_data++ = status;             /* error code */
    +-        p_pkt->len = AVRC_VENDOR_HDR_SIZE + 5;
    +-        p_rsp = p_pkt;
    ++        p_rsp->len = AVRC_VENDOR_HDR_SIZE + 5;
    +     }
    + 
    +     return p_rsp;
    +@@ -472,6 +472,7 @@ static UINT8 avrc_proc_far_msg(UINT8 handle, UINT8 label, UINT8 cr, BT_HDR **pp_
    +             if (p_rsp)
    +             {
    +                 AVCT_MsgReq( handle, label, AVCT_RSP, p_rsp);
    ++                osi_free_and_reset((void**)pp_pkt);
    +                 drop_code = 3;
    +             }
    +             else if (p_msg->hdr.opcode == AVRC_OP_DROP)
     diff --git a/stack/avrc/avrc_pars_ct.c b/stack/avrc/avrc_pars_ct.c
     index 63cc384..92bda6b 100644
     --- a/stack/avrc/avrc_pars_ct.c
    @@ -459,7 +527,7 @@ index 9a7b5d9..3e866d1 100644
                      p_data[3] = 0;
                  }
     diff --git a/stack/bnep/bnep_main.c b/stack/bnep/bnep_main.c
    -index 078a72e..534c470 100644
    +index 078a72e..f1ad2c9 100644
     --- a/stack/bnep/bnep_main.c
     +++ b/stack/bnep/bnep_main.c
     @@ -35,6 +35,7 @@
    @@ -470,7 +538,19 @@ index 078a72e..534c470 100644
      
      #include "btu.h"
      #include "btm_api.h"
    -@@ -495,6 +496,12 @@ static void bnep_data_ind (UINT16 l2cap_cid, BT_HDR *p_buf)
    +@@ -477,6 +478,11 @@ static void bnep_data_ind (UINT16 l2cap_cid, BT_HDR *p_buf)
    +     tBNEP_CONN    *p_bcb;
    +     UINT8         *p = (UINT8 *)(p_buf + 1) + p_buf->offset;
    +     UINT16        rem_len = p_buf->len;
    ++    if (rem_len == 0) {
    ++        android_errorWriteLog(0x534e4554, "78286118");
    ++        osi_free(p_buf);
    ++        return;
    ++    }
    +     UINT8         type, ctrl_type, ext_type = 0;
    +     BOOLEAN       extension_present, fw_ext_present;
    +     UINT16        protocol = 0;
    +@@ -495,6 +501,12 @@ static void bnep_data_ind (UINT16 l2cap_cid, BT_HDR *p_buf)
          type = *p++;
          extension_present = type >> 7;
          type &= 0x7f;
    @@ -483,34 +563,53 @@ index 078a72e..534c470 100644
          if ((rem_len <= bnep_frame_hdr_sizes[type]) || (rem_len > BNEP_MTU_SIZE))
          {
              BNEP_TRACE_EVENT ("BNEP - rcvd frame, bad len: %d  type: 0x%02x", p_buf->len, type);
    -@@ -524,20 +531,21 @@ static void bnep_data_ind (UINT16 l2cap_cid, BT_HDR *p_buf)
    +@@ -522,24 +534,36 @@ static void bnep_data_ind (UINT16 l2cap_cid, BT_HDR *p_buf)
    +             UINT16      org_len, new_len;
    +             /* parse the extension headers and process unknown control headers */
                  org_len = rem_len;
    -             new_len = 0;
    +-            new_len = 0;
                  do {
     -
    -+		if (org_len < 2) break;
    ++                if (org_len < 2) {
    ++                    android_errorWriteLog(0x534e4554, "67863755");
    ++                    break;
    ++                }
                      ext     = *p++;
                      length  = *p++;
    -                 p += length;
    +-                p += length;
    +-
    +-                if ((!(ext & 0x7F)) && (*p > BNEP_FILTER_MULTI_ADDR_RESPONSE_MSG))
    +-                    bnep_send_command_not_understood (p_bcb, *p);
      
    +-                new_len += (length + 2);
     +                new_len = (length + 2);
    -+                if (new_len > org_len) break;
    -+
    -                 if ((!(ext & 0x7F)) && (*p > BNEP_FILTER_MULTI_ADDR_RESPONSE_MSG))
    -                     bnep_send_command_not_understood (p_bcb, *p);
      
    --                new_len += (length + 2);
    --
     -                if (new_len > org_len)
    --                    break;
    -+		org_len -= new_len;
    ++                if (new_len > org_len) {
    ++                    android_errorWriteLog(0x534e4554, "67863755");
    +                     break;
    ++                }
    ++
    ++                if ((ext & 0x7F) == BNEP_EXTENSION_FILTER_CONTROL) {
    ++                    if (length == 0) {
    ++                        android_errorWriteLog(0x534e4554, "79164722");
    ++                        break;
    ++                    }
    ++                    if (*p > BNEP_FILTER_MULTI_ADDR_RESPONSE_MSG) {
    ++                        bnep_send_command_not_understood(p_bcb, *p);
    ++                    }
    ++                }
    ++
    ++                p += length;
      
    ++		org_len -= new_len;
                  } while (ext & 0x80);
    -+            android_errorWriteLog(0x534e4554, "67863755");
              }
    - 
    +-
              osi_free(p_buf);
    -@@ -575,7 +583,8 @@ static void bnep_data_ind (UINT16 l2cap_cid, BT_HDR *p_buf)
    +         return;
    +     }
    +@@ -575,7 +599,8 @@ static void bnep_data_ind (UINT16 l2cap_cid, BT_HDR *p_buf)
                  p_bcb->con_state != BNEP_STATE_CONNECTED &&
                  extension_present && p && rem_len)
              {
    @@ -520,15 +619,24 @@ index 078a72e..534c470 100644
                  memcpy((UINT8 *)(p_bcb->p_pending_data + 1), p, rem_len);
                  p_bcb->p_pending_data->len    = rem_len;
                  p_bcb->p_pending_data->offset = 0;
    -@@ -585,6 +594,8 @@ static void bnep_data_ind (UINT16 l2cap_cid, BT_HDR *p_buf)
    +@@ -585,13 +610,14 @@ static void bnep_data_ind (UINT16 l2cap_cid, BT_HDR *p_buf)
                  while (extension_present && p && rem_len)
                  {
                      ext_type = *p++;
     +                rem_len--;
    -+                android_errorWriteLog(0x534e4554, "69271284");
                      extension_present = ext_type >> 7;
                      ext_type &= 0x7F;
      
    +                 /* if unknown extension present stop processing */
    +-                if (ext_type)
    +-                    break;
    +-
    ++		if (ext_type != BNEP_EXTENSION_FILTER_CONTROL) break;
    ++ 
    ++                android_errorWriteLog(0x534e4554, "69271284");
    +                 p = bnep_process_control_packet (p_bcb, p, &rem_len, TRUE);
    +             }
    +         }
     diff --git a/stack/bnep/bnep_utils.c b/stack/bnep/bnep_utils.c
     index 13fb189..05bcdda 100644
     --- a/stack/bnep/bnep_utils.c
    @@ -1266,6 +1374,36 @@ index 5c3a367..7d56ee7 100644
          return;
      }
      
    +diff --git a/stack/sdp/sdp_discovery.c b/stack/sdp/sdp_discovery.c
    +index ec20689..de4e7ff 100644
    +--- a/stack/sdp/sdp_discovery.c
    ++++ b/stack/sdp/sdp_discovery.c
    +@@ -343,7 +343,7 @@ static void process_service_search_rsp (tCONN_CB *p_ccb, UINT8 *p_reply)
    + #if (SDP_RAW_DATA_INCLUDED == TRUE)
    + static void sdp_copy_raw_data (tCONN_CB *p_ccb, BOOLEAN offset)
    + {
    +-    unsigned int    cpy_len;
    ++    unsigned int    cpy_len, rem_len;
    +     UINT32          list_len;
    +     UINT8           *p;
    +     UINT8           type;
    +@@ -370,10 +370,15 @@ static void sdp_copy_raw_data (tCONN_CB *p_ccb, BOOLEAN offset)
    +             type = *p++;
    +             p = sdpu_get_len_from_type (p, type, &list_len);
    +         }
    +-        if(list_len && list_len < cpy_len )
    ++        if (list_len < cpy_len )
    +         {
    +             cpy_len = list_len;
    +         }
    ++        rem_len = SDP_MAX_LIST_BYTE_COUNT - (unsigned int)(p - &p_ccb->rsp_list[0]);
    ++        if (cpy_len > rem_len) {
    ++            SDP_TRACE_WARNING("rem_len :%d less than cpy_len:%d", rem_len, cpy_len);
    ++            cpy_len = rem_len;
    ++        }
    +         SDP_TRACE_WARNING(
    +           "%s: list_len:%d cpy_len:%d p:%p p_ccb:%p p_db:%p raw_size:%d "
    +           "raw_used:%d raw_data:%p",
     diff --git a/stack/sdp/sdp_main.c b/stack/sdp/sdp_main.c
     index c888817..7cbe2d3 100644
     --- a/stack/sdp/sdp_main.c
    @@ -1296,7 +1434,7 @@ index c888817..7cbe2d3 100644
      /*******************************************************************************
      **
     diff --git a/stack/sdp/sdp_server.c b/stack/sdp/sdp_server.c
    -index 627f4cf..ba9e8fd 100644
    +index 627f4cf..d680180 100644
     --- a/stack/sdp/sdp_server.c
     +++ b/stack/sdp/sdp_server.c
     @@ -23,6 +23,7 @@
    @@ -1375,7 +1513,7 @@ index 627f4cf..ba9e8fd 100644
              {
                  sdpu_build_n_send_error (p_ccb, trans_num, SDP_INVALID_CONT_STATE,
                                           SDP_TEXT_BAD_CONT_INX);
    -@@ -327,15 +339,15 @@ static void process_service_attr_req (tCONN_CB *p_ccb, UINT16 trans_num,
    +@@ -327,25 +339,27 @@ static void process_service_attr_req (tCONN_CB *p_ccb, UINT16 trans_num,
          BOOLEAN         is_cont = FALSE;
          UINT16          attr_len;
      
    @@ -1392,11 +1530,14 @@ index 627f4cf..ba9e8fd 100644
      
     +    /* Extract the record handle */
     +    BE_STREAM_TO_UINT32(rec_handle, p_req);
    ++    param_len -= sizeof(rec_handle);
     +
          /* Get the max list length we can send. Cap it at MTU size minus overhead */
          BE_STREAM_TO_UINT16 (max_list_len, p_req);
    ++    param_len -= sizeof(max_list_len);
      
    -@@ -344,8 +356,8 @@ static void process_service_attr_req (tCONN_CB *p_ccb, UINT16 trans_num,
    +     if (max_list_len > (p_ccb->rem_mtu_size - SDP_MAX_ATTR_RSPHDR_LEN))
    +         max_list_len = p_ccb->rem_mtu_size - SDP_MAX_ATTR_RSPHDR_LEN;
      
          p_req = sdpu_extract_attr_seq (p_req, param_len, &attr_seq);
      
    @@ -1407,7 +1548,7 @@ index 627f4cf..ba9e8fd 100644
              sdpu_build_n_send_error (p_ccb, trans_num, SDP_INVALID_REQ_SYNTAX, SDP_TEXT_BAD_ATTR_LIST);
              return;
          }
    -@@ -360,13 +372,19 @@ static void process_service_attr_req (tCONN_CB *p_ccb, UINT16 trans_num,
    +@@ -360,13 +374,19 @@ static void process_service_attr_req (tCONN_CB *p_ccb, UINT16 trans_num,
              return;
          }
      
    @@ -1428,7 +1569,7 @@ index 627f4cf..ba9e8fd 100644
                  sdpu_build_n_send_error(p_ccb, trans_num, SDP_INVALID_CONT_STATE,
                                          SDP_TEXT_BAD_CONT_LEN);
                  return;
    -@@ -562,8 +580,8 @@ static void process_service_search_attr_req (tCONN_CB *p_ccb, UINT16 trans_num,
    +@@ -562,8 +582,8 @@ static void process_service_search_attr_req (tCONN_CB *p_ccb, UINT16 trans_num,
          /* Extract the UUID sequence to search for */
          p_req = sdpu_extract_uid_seq (p_req, param_len, &uid_seq);
      
    @@ -1439,7 +1580,7 @@ index 627f4cf..ba9e8fd 100644
              sdpu_build_n_send_error (p_ccb, trans_num, SDP_INVALID_REQ_SYNTAX, SDP_TEXT_BAD_UUID_LIST);
              return;
          }
    -@@ -576,21 +594,27 @@ static void process_service_search_attr_req (tCONN_CB *p_ccb, UINT16 trans_num,
    +@@ -576,21 +596,27 @@ static void process_service_search_attr_req (tCONN_CB *p_ccb, UINT16 trans_num,
      
          p_req = sdpu_extract_attr_seq (p_req, param_len, &attr_seq);
      
    @@ -1650,6 +1791,31 @@ index 05414cd..71dab92 100644
      extern void     sdp_disconnect (tCONN_CB*p_ccb, UINT16 reason);
      
      #if (defined(SDP_DEBUG) && SDP_DEBUG == TRUE)
    +diff --git a/stack/smp/smp_br_main.c b/stack/smp/smp_br_main.c
    +index 11039ec..87ae24b 100644
    +--- a/stack/smp/smp_br_main.c
    ++++ b/stack/smp/smp_br_main.c
    +@@ -19,6 +19,7 @@
    + #include "bt_target.h"
    + 
    + #include <string.h>
    ++#include "log/log.h"
    + #include "smp_int.h"
    + 
    + #if BLE_INCLUDED == TRUE
    +@@ -344,6 +345,12 @@ void smp_br_state_machine_event(tSMP_CB *p_cb, tSMP_BR_EVENT event, void *p_data
    +         return;
    +     }
    + 
    ++    if (p_cb->role > HCI_ROLE_SLAVE) {
    ++        SMP_TRACE_ERROR("%s: invalid role %d", __func__, p_cb->role);
    ++        android_errorWriteLog(0x534e4554, "80145946");
    ++        return;
    ++    }
    ++
    +     SMP_TRACE_DEBUG( "SMP Role: %s State: [%s (%d)], Event: [%s (%d)]",
    +                       (p_cb->role == HCI_ROLE_SLAVE) ? "Slave" : "Master",
    +                       smp_get_br_state_name( p_cb->br_state),
     diff --git a/stack/smp/smp_main.c b/stack/smp/smp_main.c
     index c3709f8..96cf555 100644
     --- a/stack/smp/smp_main.c
    
    From a096295d561fe08d98f48dc04f18e2283505f616 Mon Sep 17 00:00:00 2001
    From: AndDiSa <anddisa@googlemail.com>
    Date: Mon, 17 Sep 2018 13:21:02 +0200
    Subject: [PATCH 100/159] switch to system/bt from unlegacy
    
    Change-Id: I783a20ec9416e6baf0e15f98b0c748acd2ccab9b
    ---
     default.xml | 2 +-
     1 file changed, 1 insertion(+), 1 deletion(-)
    
    diff --git a/default.xml b/default.xml
    index 34f5ebc..5c89b2b 100644
    --- a/default.xml
    +++ b/default.xml
    @@ -471,7 +471,7 @@
       <project path="prebuilts/sdk" name="platform/prebuilts/sdk" groups="pdk" />
       <project path="prebuilts/tools" name="platform/prebuilts/tools" groups="pdk,tools" />
       <project path="sdk" name="platform/sdk" groups="pdk-cw-fs,pdk-fs" />
    -  <project path="system/bt" name="platform/system/bt" groups="pdk" />
    +  <project path="system/bt" name="platform/system/bt" groups="pdk" remote="unlegacy" revision="aosp-7.1"/>
       <project path="system/ca-certificates" name="platform/system/ca-certificates" groups="pdk" />
       <project path="system/connectivity/apmanager" name="platform/system/connectivity/apmanager" />
       <project path="system/connectivity/dhcp_client" name="platform/system/connectivity/dhcp_client" />
    
    From 1cb65f00fbcdadb130ed14f4b69d66aa65456f08 Mon Sep 17 00:00:00 2001
    From: AndDiSa <anddisa@googlemail.com>
    Date: Tue, 18 Sep 2018 20:41:27 +0200
    Subject: [PATCH 101/159] update patches
    
    Change-Id: I42abfd233b19a4d1559c88a1b80e044fd52ab863
    ---
     build.patch           |   4 +-
     frameworks_av.patch   | 127 ++++++++-
     frameworks_base.patch |  98 +++++++
     libcore.patch         |  92 +++++++
     system_bt.patch       | 619 +++++++++++++++++++++++++-----------------
     5 files changed, 680 insertions(+), 260 deletions(-)
    
    diff --git a/build.patch b/build.patch
    index eeb3a28..f0c7554 100644
    --- a/build.patch
    +++ b/build.patch
    @@ -323,7 +323,7 @@ index 0000000..80664fa
     +ALL_PREBUILT += $(INSTALLED_KERNEL_TARGET)
     +endif
     diff --git a/core/version_defaults.mk b/core/version_defaults.mk
    -index 7c96344..1829c30 100644
    +index 7c96344..662cd08 100644
     --- a/core/version_defaults.mk
     +++ b/core/version_defaults.mk
     @@ -131,7 +131,7 @@ ifeq "" "$(PLATFORM_SECURITY_PATCH)"
    @@ -331,7 +331,7 @@ index 7c96344..1829c30 100644
          #  It must match one of the Android Security Patch Level strings of the Public Security Bulletins.
          #  If there is no $PLATFORM_SECURITY_PATCH set, keep it empty.
     -    PLATFORM_SECURITY_PATCH := 2017-08-05
    -+    PLATFORM_SECURITY_PATCH := 2018-08-05
    ++    PLATFORM_SECURITY_PATCH := 2018-09-05
      endif
      
      ifeq "" "$(PLATFORM_BASE_OS)"
    diff --git a/frameworks_av.patch b/frameworks_av.patch
    index ffa6120..498dbb3 100644
    --- a/frameworks_av.patch
    +++ b/frameworks_av.patch
    @@ -2397,10 +2397,98 @@ index 7abc019..590146d 100644
          while (mPrevEstimates.size() > 3) {
              mPrevEstimates.erase(mPrevEstimates.begin());
     diff --git a/media/libstagefright/httplive/M3UParser.cpp b/media/libstagefright/httplive/M3UParser.cpp
    -index c04549a..1242c95 100644
    +index c04549a..a092a1b 100644
     --- a/media/libstagefright/httplive/M3UParser.cpp
     +++ b/media/libstagefright/httplive/M3UParser.cpp
    -@@ -658,10 +658,13 @@ status_t M3UParser::parse(const void *_data, size_t size) {
    +@@ -56,7 +56,7 @@ struct M3UParser::MediaGroup : public RefBase {
    +             const char *language,
    +             uint32_t flags);
    + 
    +-    bool getActiveURI(AString *uri) const;
    ++    bool getActiveURI(AString *uri, const char *baseURL) const;
    + 
    +     void pickRandomMediaItems();
    +     status_t selectTrack(size_t index, bool select);
    +@@ -75,6 +75,7 @@ private:
    +         AString mURI;
    +         AString mLanguage;
    +         uint32_t mFlags;
    ++        AString makeURL(const char *baseURL) const;
    +     };
    + 
    +     Type mType;
    +@@ -227,12 +228,16 @@ sp<AMessage> M3UParser::MediaGroup::getTrackInfo(size_t index) const {
    +     return format;
    + }
    + 
    +-bool M3UParser::MediaGroup::getActiveURI(AString *uri) const {
    ++bool M3UParser::MediaGroup::getActiveURI(AString *uri, const char *baseURL) const {
    +     for (size_t i = 0; i < mMediaItems.size(); ++i) {
    +         if (mSelectedIndex >= 0 && i == (size_t)mSelectedIndex) {
    +             const Media &item = mMediaItems.itemAt(i);
    + 
    +-            *uri = item.mURI;
    ++            if (item.mURI.empty()) {
    ++                *uri = "";
    ++            } else {
    ++                *uri = item.makeURL(baseURL);
    ++            }
    +             return true;
    +         }
    +     }
    +@@ -321,7 +326,7 @@ bool M3UParser::itemAt(size_t index, AString *uri, sp<AMessage> *meta) {
    +     }
    + 
    +     if (uri) {
    +-        *uri = mItems.itemAt(index).mURI;
    ++        *uri = mItems.itemAt(index).makeURL(mBaseURI.c_str());
    +     }
    + 
    +     if (meta) {
    +@@ -427,7 +432,7 @@ bool M3UParser::getTypeURI(size_t index, const char *key, AString *uri) const {
    +     AString groupID;
    +     if (!meta->findString(key, &groupID)) {
    +         if (uri != NULL) {
    +-            *uri = mItems.itemAt(index).mURI;
    ++            *uri = mItems.itemAt(index).makeURL(mBaseURI.c_str());
    +         }
    + 
    +         AString codecs;
    +@@ -458,12 +463,12 @@ bool M3UParser::getTypeURI(size_t index, const char *key, AString *uri) const {
    +     // don't care about the active URI (or if there is an active one)
    +     if (uri != NULL) {
    +         sp<MediaGroup> group = mMediaGroups.valueFor(groupID);
    +-        if (!group->getActiveURI(uri)) {
    ++        if (!group->getActiveURI(uri, mBaseURI.c_str())) {
    +             return false;
    +         }
    + 
    +         if ((*uri).empty()) {
    +-            *uri = mItems.itemAt(index).mURI;
    ++            *uri = mItems.itemAt(index).makeURL(mBaseURI.c_str());
    +         }
    +     }
    + 
    +@@ -544,6 +549,18 @@ static bool MakeURL(const char *baseURL, const char *url, AString *out) {
    +     return true;
    + }
    + 
    ++AString M3UParser::Item::makeURL(const char *baseURL) const {
    ++    AString out;
    ++    CHECK(MakeURL(baseURL, mURI.c_str(), &out));
    ++    return out;
    ++}
    ++
    ++AString M3UParser::MediaGroup::Media::makeURL(const char *baseURL) const {
    ++    AString out;
    ++    CHECK(MakeURL(baseURL, mURI.c_str(), &out));
    ++    return out;
    ++}
    ++
    + status_t M3UParser::parse(const void *_data, size_t size) {
    +     int32_t lineNo = 0;
    + 
    +@@ -658,10 +675,13 @@ status_t M3UParser::parse(const void *_data, size_t size) {
              }
      
              if (!line.startsWith("#")) {
    @@ -2416,7 +2504,17 @@ index c04549a..1242c95 100644
                          return ERROR_MALFORMED;
                      }
                      itemMeta->setInt32("discontinuity-sequence",
    -@@ -897,6 +900,9 @@ status_t M3UParser::parseStreamInf(
    +@@ -671,8 +691,7 @@ status_t M3UParser::parse(const void *_data, size_t size) {
    +             mItems.push();
    +             Item *item = &mItems.editItemAt(mItems.size() - 1);
    + 
    +-            CHECK(MakeURL(mBaseURI.c_str(), line.c_str(), &item->mURI));
    +-
    ++            item->mURI = line;
    +             item->mMeta = itemMeta;
    + 
    +             itemMeta.clear();
    +@@ -897,6 +916,9 @@ status_t M3UParser::parseStreamInf(
              }
          }
      
    @@ -2426,6 +2524,29 @@ index c04549a..1242c95 100644
          return OK;
      }
      
    +@@ -1180,9 +1202,7 @@ status_t M3UParser::parseMedia(const AString &line) {
    + 
    +             AString tmp(val, 1, val.size() - 2);
    + 
    +-            if (!MakeURL(mBaseURI.c_str(), tmp.c_str(), &groupURI)) {
    +-                ALOGI("Failed to make absolute URI from '%s'.", tmp.c_str());
    +-            }
    ++            groupURI = tmp;
    + 
    +             haveGroupURI = true;
    +         }
    +diff --git a/media/libstagefright/httplive/M3UParser.h b/media/libstagefright/httplive/M3UParser.h
    +index fa648ed..c85335a 100644
    +--- a/media/libstagefright/httplive/M3UParser.h
    ++++ b/media/libstagefright/httplive/M3UParser.h
    +@@ -64,6 +64,7 @@ private:
    +     struct Item {
    +         AString mURI;
    +         sp<AMessage> mMeta;
    ++        AString makeURL(const char *baseURL) const;
    +     };
    + 
    +     status_t mInitCheck;
     diff --git a/media/libstagefright/id3/ID3.cpp b/media/libstagefright/id3/ID3.cpp
     index 8b80ae9..0791ee9 100644
     --- a/media/libstagefright/id3/ID3.cpp
    diff --git a/frameworks_base.patch b/frameworks_base.patch
    index 40b0aef..c371418 100644
    --- a/frameworks_base.patch
    +++ b/frameworks_base.patch
    @@ -322,6 +322,27 @@ index a110383..aea843a 100644
                  }
              }
              return false;
    +diff --git a/core/java/android/hardware/location/NanoAppFilter.java b/core/java/android/hardware/location/NanoAppFilter.java
    +index bf35a3d..c440949 100644
    +--- a/core/java/android/hardware/location/NanoAppFilter.java
    ++++ b/core/java/android/hardware/location/NanoAppFilter.java
    +@@ -83,7 +83,7 @@ public class NanoAppFilter {
    +         mAppId = in.readLong();
    +         mAppVersion = in.readInt();
    +         mVersionRestrictionMask = in.readInt();
    +-        mAppIdVendorMask = in.readInt();
    ++        mAppIdVendorMask = in.readLong();
    +     }
    + 
    +     public int describeContents() {
    +@@ -91,7 +91,6 @@ public class NanoAppFilter {
    +     }
    + 
    +     public void writeToParcel(Parcel out, int flags) {
    +-
    +         out.writeLong(mAppId);
    +         out.writeInt(mAppVersion);
    +         out.writeInt(mVersionRestrictionMask);
     diff --git a/core/java/android/net/Uri.java b/core/java/android/net/Uri.java
     index 09af05c..6c069be 100644
     --- a/core/java/android/net/Uri.java
    @@ -960,6 +981,22 @@ index 2c9c9d9..7c187fb 100644
      }
      
      /**
    +diff --git a/media/java/android/media/MediaPlayer.java b/media/java/android/media/MediaPlayer.java
    +index e5f7527..679a27e 100644
    +--- a/media/java/android/media/MediaPlayer.java
    ++++ b/media/java/android/media/MediaPlayer.java
    +@@ -2025,10 +2025,10 @@ public class MediaPlayer extends PlayerBase
    +         @Override
    +         public void writeToParcel(Parcel dest, int flags) {
    +             dest.writeInt(mTrackType);
    ++            dest.writeString(mFormat.getString(MediaFormat.KEY_MIME));
    +             dest.writeString(getLanguage());
    + 
    +             if (mTrackType == MEDIA_TRACK_TYPE_SUBTITLE) {
    +-                dest.writeString(mFormat.getString(MediaFormat.KEY_MIME));
    +                 dest.writeInt(mFormat.getInteger(MediaFormat.KEY_IS_AUTOSELECT));
    +                 dest.writeInt(mFormat.getInteger(MediaFormat.KEY_IS_DEFAULT));
    +                 dest.writeInt(mFormat.getInteger(MediaFormat.KEY_IS_FORCED_SUBTITLE));
     diff --git a/media/java/android/media/MediaScanner.java b/media/java/android/media/MediaScanner.java
     index 0fafe4b..4c113d9 100644
     --- a/media/java/android/media/MediaScanner.java
    @@ -1978,6 +2015,67 @@ index b6a9940..11b5832a 100644
      
          /**
           * Whether verification is enabled by default.
    +diff --git a/services/core/java/com/android/server/pm/ShortcutService.java b/services/core/java/com/android/server/pm/ShortcutService.java
    +index 6e8799e..b33cbfd 100644
    +--- a/services/core/java/com/android/server/pm/ShortcutService.java
    ++++ b/services/core/java/com/android/server/pm/ShortcutService.java
    +@@ -124,6 +124,7 @@ import java.nio.charset.StandardCharsets;
    + import java.util.ArrayList;
    + import java.util.Collections;
    + import java.util.List;
    ++import java.util.Objects;
    + import java.util.concurrent.atomic.AtomicBoolean;
    + import java.util.function.Consumer;
    + import java.util.function.Predicate;
    +@@ -1523,6 +1524,24 @@ public class ShortcutService extends IShortcutService.Stub {
    +         throw new SecurityException("Calling package name mismatch");
    +     }
    + 
    ++    private void verifyShortcutInfoPackage(String callerPackage, ShortcutInfo si) {
    ++        if (si == null) {
    ++            return;
    ++        }
    ++        if (!Objects.equals(callerPackage, si.getPackage())) {
    ++            android.util.EventLog.writeEvent(0x534e4554, "109824443", -1, "");
    ++            throw new SecurityException("Shortcut package name mismatch");
    ++        }
    ++    }
    ++
    ++    private void verifyShortcutInfoPackages(
    ++            String callerPackage, List<ShortcutInfo> list) {
    ++        final int size = list.size();
    ++        for (int i = 0; i < size; i++) {
    ++            verifyShortcutInfoPackage(callerPackage, list.get(i));
    ++        }
    ++    }
    ++
    +     // Overridden in unit tests to execute r synchronously.
    +     void injectPostToHandler(Runnable r) {
    +         mHandler.post(r);
    +@@ -1651,6 +1670,7 @@ public class ShortcutService extends IShortcutService.Stub {
    +         verifyCaller(packageName, userId);
    + 
    +         final List<ShortcutInfo> newShortcuts = (List<ShortcutInfo>) shortcutInfoList.getList();
    ++        verifyShortcutInfoPackages(packageName, newShortcuts);
    +         final int size = newShortcuts.size();
    + 
    +         synchronized (mLock) {
    +@@ -1702,6 +1722,7 @@ public class ShortcutService extends IShortcutService.Stub {
    +         verifyCaller(packageName, userId);
    + 
    +         final List<ShortcutInfo> newShortcuts = (List<ShortcutInfo>) shortcutInfoList.getList();
    ++        verifyShortcutInfoPackages(packageName, newShortcuts);
    +         final int size = newShortcuts.size();
    + 
    +         synchronized (mLock) {
    +@@ -1782,6 +1803,7 @@ public class ShortcutService extends IShortcutService.Stub {
    +         verifyCaller(packageName, userId);
    + 
    +         final List<ShortcutInfo> newShortcuts = (List<ShortcutInfo>) shortcutInfoList.getList();
    ++        verifyShortcutInfoPackages(packageName, newShortcuts);
    +         final int size = newShortcuts.size();
    + 
    +         synchronized (mLock) {
     diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java
     index 889c52a..872b03d 100644
     --- a/services/core/java/com/android/server/policy/PhoneWindowManager.java
    diff --git a/libcore.patch b/libcore.patch
    index a931e19..c36635b 100644
    --- a/libcore.patch
    +++ b/libcore.patch
    @@ -46,6 +46,57 @@ index 5d5317a..04de751 100644
     +        assertEquals(symlinkFile.getCanonicalPath(), f2.getCanonicalPath());
     +    }
      }
    +diff --git a/luni/src/test/java/libcore/java/net/URLTest.java b/luni/src/test/java/libcore/java/net/URLTest.java
    +index 0eee1f8..410f3fb 100644
    +--- a/luni/src/test/java/libcore/java/net/URLTest.java
    ++++ b/luni/src/test/java/libcore/java/net/URLTest.java
    +@@ -409,6 +409,46 @@ public final class URLTest extends TestCase {
    +         assertEquals("http://host/a/c", url.toString()); // RI doesn't canonicalize
    +     }
    + 
    ++    public void testPathContainsBackslash() throws Exception {
    ++        URL url = new URL("http://host\\path@foo");
    ++        assertEquals("\\path@foo", url.getPath());
    ++        assertEquals("host", url.getHost());
    ++    }
    ++
    ++    public void testQueryContainsForwardSlash() throws Exception {
    ++        URL url = new URL("http://host?query/foo");
    ++        assertEquals("", url.getPath());
    ++        assertEquals("host", url.getHost());
    ++        assertEquals("query/foo", url.getQuery());
    ++    }
    ++
    ++    public void testFragmentContainsForwardSlash() throws Exception {
    ++        URL url = new URL("http://host#fragment/foo");
    ++        assertEquals("", url.getPath());
    ++        assertEquals("host", url.getHost());
    ++        assertEquals("fragment/foo", url.getRef());
    ++    }
    ++
    ++    public void testPathContainsBackslash() throws Exception {
    ++        URL url = new URL("http://host\\path@foo");
    ++        assertEquals("\\path@foo", url.getPath());
    ++        assertEquals("host", url.getHost());
    ++    }
    ++
    ++    public void testQueryContainsForwardSlash() throws Exception {
    ++        URL url = new URL("http://host?query/foo");
    ++        assertEquals("", url.getPath());
    ++        assertEquals("host", url.getHost());
    ++        assertEquals("query/foo", url.getQuery());
    ++    }
    ++
    ++    public void testFragmentContainsForwardSlash() throws Exception {
    ++        URL url = new URL("http://host#fragment/foo");
    ++        assertEquals("", url.getPath());
    ++        assertEquals("host", url.getHost());
    ++        assertEquals("fragment/foo", url.getRef());
    ++    }
    ++
    +     public void testRelativePathAndFragment() throws Exception {
    +         URL base = new URL("http://host/file");
    +         assertEquals("http://host/another#fragment", new URL(base, "another#fragment").toString());
     diff --git a/ojluni/src/main/java/java/io/FileSystem.java b/ojluni/src/main/java/java/io/FileSystem.java
     index aa00fa9..7db1651 100755
     --- a/ojluni/src/main/java/java/io/FileSystem.java
    @@ -64,3 +115,44 @@ index aa00fa9..7db1651 100755
      
          private static boolean getBooleanProperty(String prop, boolean defaultVal) {
              String val = System.getProperty(prop);
    +diff --git a/ojluni/src/main/java/java/net/URLStreamHandler.java b/ojluni/src/main/java/java/net/URLStreamHandler.java
    +index 0892d67..49a84a9 100755
    +--- a/ojluni/src/main/java/java/net/URLStreamHandler.java
    ++++ b/ojluni/src/main/java/java/net/URLStreamHandler.java
    +@@ -168,12 +168,25 @@ public abstract class URLStreamHandler {
    +         if (!isUNCName && (start <= limit - 2) && (spec.charAt(start) == '/') &&
    +             (spec.charAt(start + 1) == '/')) {
    +             start += 2;
    ++            // BEGIN Android-changed: Check for all hostname termination chars. http://b/110955991
    ++            /*
    +             i = spec.indexOf('/', start);
    +             if (i < 0 || i > limit) {
    +                 i = spec.indexOf('?', start);
    +                 if (i < 0 || i > limit)
    +                     i = limit;
    +             }
    ++            */
    ++            LOOP: for (i = start; i < limit; i++) {
    ++                switch (spec.charAt(i)) {
    ++                    case '/':  // Start of path
    ++                    case '\\': // Start of path - see https://url.spec.whatwg.org/#host-state
    ++                    case '?':  // Start of query
    ++                    case '#':  // Start of fragment
    ++                        break LOOP;
    ++                }
    ++            }
    ++            // END Android-changed: Check for all hostname termination chars. http://b/110955991
    + 
    +             host = authority = spec.substring(start, i);
    + 
    +@@ -267,7 +280,9 @@ public abstract class URLStreamHandler {
    + 
    +         // Parse the file path if any
    +         if (start < limit) {
    +-            if (spec.charAt(start) == '/') {
    ++            // Android-changed: Check for all hostname termination chars. http://b/110955991
    ++            // if (spec.charAt(start) == '/') {
    ++            if (spec.charAt(start) == '/' || spec.charAt(start) == '\\') {
    +                 path = spec.substring(start, limit);
    +             } else if (path != null && path.length() > 0) {
    +                 isRelPath = true;
    diff --git a/system_bt.patch b/system_bt.patch
    index 72608d5..f7f82e5 100644
    --- a/system_bt.patch
    +++ b/system_bt.patch
    @@ -136,7 +136,7 @@ index 1995478..4367fce 100644
          BT_HDR *p_event = (BT_HDR *)osi_malloc(sizeof(BT_HDR));
          p_event->layer_specific = handle;
     diff --git a/btif/src/btif_rc.c b/btif/src/btif_rc.c
    -index 6572fd7..1e0fce6 100644
    +index 6572fd7..133277a 100644
     --- a/btif/src/btif_rc.c
     +++ b/btif/src/btif_rc.c
     @@ -42,6 +42,7 @@
    @@ -147,16 +147,14 @@ index 6572fd7..1e0fce6 100644
      #include "uinput.h"
      #include "bdaddr.h"
      #include "osi/include/list.h"
    -@@ -2762,8 +2763,13 @@ static void handle_app_cur_val_response (tBTA_AV_META_MSG *pmeta_msg, tAVRC_GET_
    -     }
    - 
    +@@ -2764,6 +2765,12 @@ static void handle_app_cur_val_response (tBTA_AV_META_MSG *pmeta_msg, tAVRC_GET_
          bdcpy(rc_addr.address, btif_rc_cb.rc_addr);
    --
    + 
          app_settings.num_attr = p_rsp->num_val;
     +
     +    if (app_settings.num_attr > BTRC_MAX_APP_SETTINGS) {
    -+        android_errorWriteLog(0x534e4554, "73824150");
    -+        app_settings.num_attr = BTRC_MAX_APP_SETTINGS;
    ++      android_errorWriteLog(0x534e4554, "73824150");
    ++      app_settings.num_attr = BTRC_MAX_APP_SETTINGS;
     +    }
     +
          for (xx = 0; xx < app_settings.num_attr; xx++)
    @@ -177,7 +175,7 @@ index d02dfa0..90d74cf 100644
              return handle;
          }
     diff --git a/btif/src/btif_storage.c b/btif/src/btif_storage.c
    -index 83dcc8c..9abfe45 100644
    +index 83dcc8c..d02b09a 100644
     --- a/btif/src/btif_storage.c
     +++ b/btif/src/btif_storage.c
     @@ -229,6 +229,10 @@ static int prop2cfg(bt_bdaddr_t *remote_bd_addr, bt_property_t *prop)
    @@ -185,8 +183,8 @@ index 83dcc8c..9abfe45 100644
                      memset(buf, 0, sizeof(buf));
                      uuid_to_string_legacy(p_uuid, buf);
     +                if (strlen(value) + strlen(buf) + 1 > (int) sizeof(value) - 1) {
    -+                    android_errorWriteLog(0x534e4554, "73963551");
    -+                    return false;
    ++                  android_errorWriteLog(0x534e4554, "73963551");
    ++                  return FALSE;
     +                }
                      strcat(value, buf);
                      //strcat(value, ";");
    @@ -269,7 +267,7 @@ index 69ded69..5f9e42c 100644
                    "    Overdue scheduling time in ms (total/max/avg)");
      
     diff --git a/osi/src/config.c b/osi/src/config.c
    -index 345f907..0e8c421 100644
    +index 345f907..b38977f 100644
     --- a/osi/src/config.c
     +++ b/osi/src/config.c
     @@ -34,6 +34,7 @@
    @@ -280,6 +278,46 @@ index 345f907..0e8c421 100644
      
      typedef struct {
        char *key;
    +@@ -216,16 +217,37 @@ void config_set_string(config_t *config, const char *section, const char *key, c
    +     list_append(config->sections, sec);
    +   }
    + 
    ++  char *value_string = (char *)value;
    ++  char *value_no_newline;
    ++  char *newline = strstr(value_string, "\n");
    ++  if (newline) {
    ++    android_errorWriteLog(0x534e4554, "70808273");
    ++    size_t newline_pos = newline - value_string;
    ++    value_no_newline = osi_strndup(value_string, newline_pos);
    ++    if (!value_no_newline) {
    ++      LOG_ERROR(LOG_TAG,"%s: Unable to allocate memory for value_no_newline", __func__);
    ++      return;
    ++    }
    ++  } else {
    ++    value_no_newline = value_string;
    ++  }
    ++
    +   for (const list_node_t *node = list_begin(sec->entries); node != list_end(sec->entries); node = list_next(node)) {
    +     entry_t *entry = list_node(node);
    +     if (!strcmp(entry->key, key)) {
    +       osi_free(entry->value);
    +-      entry->value = osi_strdup(value);
    ++      entry->value = osi_strdup(value_no_newline);
    ++      if (newline) {
    ++        osi_free(value_no_newline);
    ++      }
    +       return;
    +     }
    +   }
    + 
    +-  entry_t *entry = entry_new(key, value);
    ++  entry_t *entry = entry_new(key, value_no_newline);
    ++  if (newline) {
    ++    osi_free(value_no_newline);
    ++  }
    +   list_append(sec->entries, entry);
    + }
    + 
     diff --git a/stack/avdt/avdt_api.c b/stack/avdt/avdt_api.c
     index 98ef5f7..5201054 100644
     --- a/stack/avdt/avdt_api.c
    @@ -293,76 +331,8 @@ index 98ef5f7..5201054 100644
      
                  p_pkt->offset = L2CAP_MIN_OFFSET;
                  p = (UINT8 *)(p_pkt + 1) + p_pkt->offset;
    -diff --git a/stack/avdt/avdt_msg.c b/stack/avdt/avdt_msg.c
    -index adc1ae7..9697a59 100644
    ---- a/stack/avdt/avdt_msg.c
    -+++ b/stack/avdt/avdt_msg.c
    -@@ -26,6 +26,7 @@
    -  *
    -  ******************************************************************************/
    - 
    -+#include <log/log.h>
    - #include <string.h>
    - #include "bt_types.h"
    - #include "bt_target.h"
    -@@ -673,6 +674,11 @@ static UINT8 avdt_msg_prs_cfg(tAVDT_CFG *p_cfg, UINT8 *p, UINT16 len, UINT8* p_e
    - 
    -             case AVDT_CAT_PROTECT:
    -                 p_cfg->psc_mask &= ~AVDT_PSC_PROTECT;
    -+                if (p + elem_len > p_end) {
    -+                    err = AVDT_ERR_LENGTH;
    -+                    android_errorWriteLog(0x534e4554, "78288378");
    -+                    break;
    -+                }
    -                 if ((elem_len + protect_offset) < AVDT_PROTECT_SIZE)
    -                 {
    -                     p_cfg->num_protect++;
    -@@ -747,6 +753,11 @@ static UINT8 avdt_msg_prs_cfg(tAVDT_CFG *p_cfg, UINT8 *p, UINT16 len, UINT8* p_e
    -                 {
    -                     tmp = AVDT_CODEC_SIZE - 1;
    -                 }
    -+                if (p + tmp > p_end) {
    -+                    err = AVDT_ERR_LENGTH;
    -+                    android_errorWriteLog(0x534e4554, "78288378");
    -+                    break;
    -+                }
    -                 p_cfg->num_codec++;
    -                 p_cfg->codec_info[0] = elem_len;
    -                 memcpy(&p_cfg->codec_info[1], p, tmp);
    -diff --git a/stack/avrc/avrc_api.c b/stack/avrc/avrc_api.c
    -index 77ca7d4..ffd690a 100644
    ---- a/stack/avrc/avrc_api.c
    -+++ b/stack/avrc/avrc_api.c
    -@@ -316,15 +316,15 @@ static BT_HDR * avrc_proc_vendor_command(UINT8 handle, UINT8 label,
    - 
    -     if (status != AVRC_STS_NO_ERROR)
    -     {
    --        /* use the current GKI buffer to build/send the reject message */
    --        p_data = (UINT8 *)(p_pkt+1) + p_pkt->offset;
    -+        p_rsp = (BT_HDR*)osi_malloc(BT_DEFAULT_BUFFER_SIZE);
    -+        p_rsp->offset = p_pkt->offset;
    -+        p_data = (uint8_t*)(p_rsp + 1) + p_pkt->offset;
    -         *p_data++ = AVRC_RSP_REJ;
    -         p_data += AVRC_VENDOR_HDR_SIZE; /* pdu */
    -         *p_data++ = 0;                  /* pkt_type */
    -         UINT16_TO_BE_STREAM(p_data, 1); /* len */
    -         *p_data++ = status;             /* error code */
    --        p_pkt->len = AVRC_VENDOR_HDR_SIZE + 5;
    --        p_rsp = p_pkt;
    -+        p_rsp->len = AVRC_VENDOR_HDR_SIZE + 5;
    -     }
    - 
    -     return p_rsp;
    -@@ -472,6 +472,7 @@ static UINT8 avrc_proc_far_msg(UINT8 handle, UINT8 label, UINT8 cr, BT_HDR **pp_
    -             if (p_rsp)
    -             {
    -                 AVCT_MsgReq( handle, label, AVCT_RSP, p_rsp);
    -+                osi_free_and_reset((void**)pp_pkt);
    -                 drop_code = 3;
    -             }
    -             else if (p_msg->hdr.opcode == AVRC_OP_DROP)
     diff --git a/stack/avrc/avrc_pars_ct.c b/stack/avrc/avrc_pars_ct.c
    -index 63cc384..92bda6b 100644
    +index 63cc384..1818c52 100644
     --- a/stack/avrc/avrc_pars_ct.c
     +++ b/stack/avrc/avrc_pars_ct.c
     @@ -22,6 +22,7 @@
    @@ -378,33 +348,33 @@ index 63cc384..92bda6b 100644
              case AVRC_EVT_APP_SETTING_CHANGE:
                  BE_STREAM_TO_UINT8(p_rsp->param.player_setting.num_attr, p_stream);
     +            if (p_rsp->param.player_setting.num_attr > AVRC_MAX_APP_SETTINGS) {
    -+                android_errorWriteLog(0x534e4554, "73782082");
    -+                p_rsp->param.player_setting.num_attr = AVRC_MAX_APP_SETTINGS;
    ++              android_errorWriteLog(0x534e4554, "73782082");
    ++              p_rsp->param.player_setting.num_attr = AVRC_MAX_APP_SETTINGS;
     +            }
                  for (int index = 0; index < p_rsp->param.player_setting.num_attr; index++)
                  {
                      BE_STREAM_TO_UINT8(p_rsp->param.player_setting.attr_id[index], p_stream);
    -@@ -241,6 +246,12 @@ static tAVRC_STS avrc_ctrl_pars_vendor_rsp(
    +@@ -227,6 +232,12 @@ static tAVRC_STS avrc_ctrl_pars_vendor_rsp(
              }
    -         BE_STREAM_TO_UINT8(p_result->list_app_values.num_val, p);
    -         AVRC_TRACE_DEBUG("%s value count = %d ", __func__, p_result->list_app_values.num_val);
    +         BE_STREAM_TO_UINT8(p_result->list_app_attr.num_attr, p);
    +         AVRC_TRACE_DEBUG("%s attr count = %d ", __func__, p_result->list_app_attr.num_attr);
     +
     +        if (p_result->list_app_attr.num_attr > AVRC_MAX_APP_ATTR_SIZE) {
    -+          android_errorWriteLog(0x534e4554, "63146237");
    -+          p_result->list_app_attr.num_attr = AVRC_MAX_APP_ATTR_SIZE;
    ++            android_errorWriteLog(0x534e4554, "63146237");
    ++            p_result->list_app_attr.num_attr = AVRC_MAX_APP_ATTR_SIZE;
     +        }
    -+ 
    -         for(int xx = 0; xx < p_result->list_app_values.num_val; xx++)
    ++
    +         for(int xx = 0; xx < p_result->list_app_attr.num_attr; xx++)
              {
    -             BE_STREAM_TO_UINT8(p_result->list_app_values.vals[xx], p);
    +             BE_STREAM_TO_UINT8(p_result->list_app_attr.attrs[xx], p);
     @@ -258,6 +269,12 @@ static tAVRC_STS avrc_ctrl_pars_vendor_rsp(
              tAVRC_APP_SETTING *app_sett =
                  (tAVRC_APP_SETTING*)osi_malloc(p_result->get_cur_app_val.num_val*sizeof(tAVRC_APP_SETTING));
              AVRC_TRACE_DEBUG("%s attr count = %d ", __func__, p_result->get_cur_app_val.num_val);
    -+ 
    ++
     +        if (p_result->get_cur_app_val.num_val > AVRC_MAX_APP_ATTR_SIZE) {
    -+          android_errorWriteLog(0x534e4554, "63146237");
    -+          p_result->get_cur_app_val.num_val = AVRC_MAX_APP_ATTR_SIZE;
    ++            android_errorWriteLog(0x534e4554, "63146237");
    ++            p_result->get_cur_app_val.num_val = AVRC_MAX_APP_ATTR_SIZE;
     +        }
     +
              for (int xx = 0; xx < p_result->get_cur_app_val.num_val; xx++)
    @@ -456,7 +426,7 @@ index 63cc384..92bda6b 100644
                  BE_STREAM_TO_UINT8(p_result->get_app_val_txt.p_attrs[i].attr_id, p);
                  BE_STREAM_TO_UINT16(p_result->get_app_val_txt.p_attrs[i].charset_id, p);
     diff --git a/stack/avrc/avrc_pars_tg.c b/stack/avrc/avrc_pars_tg.c
    -index 3f3fe93..63f74b6 100644
    +index 3f3fe93..6d3c67e 100644
     --- a/stack/avrc/avrc_pars_tg.c
     +++ b/stack/avrc/avrc_pars_tg.c
     @@ -21,6 +21,7 @@
    @@ -485,10 +455,10 @@ index 3f3fe93..63f74b6 100644
                      else
                      {
     +                    if (p_result->get_app_val_txt.num_val > AVRC_MAX_APP_ATTR_SIZE) {
    -+                      android_errorWriteLog(0x534e4554, "63146237");
    -+                      p_result->get_app_val_txt.num_val = AVRC_MAX_APP_ATTR_SIZE;
    ++                        android_errorWriteLog(0x534e4554, "63146237");
    ++                        p_result->get_app_val_txt.num_val = AVRC_MAX_APP_ATTR_SIZE;
     +                    }
    -+       
    ++
                          p_u8 = p_result->get_app_val_txt.vals;
                          for (xx=0; xx< p_result->get_app_val_txt.num_val; xx++)
                          {
    @@ -527,7 +497,7 @@ index 9a7b5d9..3e866d1 100644
                      p_data[3] = 0;
                  }
     diff --git a/stack/bnep/bnep_main.c b/stack/bnep/bnep_main.c
    -index 078a72e..f1ad2c9 100644
    +index 078a72e..8edb712 100644
     --- a/stack/bnep/bnep_main.c
     +++ b/stack/bnep/bnep_main.c
     @@ -35,6 +35,7 @@
    @@ -538,19 +508,7 @@ index 078a72e..f1ad2c9 100644
      
      #include "btu.h"
      #include "btm_api.h"
    -@@ -477,6 +478,11 @@ static void bnep_data_ind (UINT16 l2cap_cid, BT_HDR *p_buf)
    -     tBNEP_CONN    *p_bcb;
    -     UINT8         *p = (UINT8 *)(p_buf + 1) + p_buf->offset;
    -     UINT16        rem_len = p_buf->len;
    -+    if (rem_len == 0) {
    -+        android_errorWriteLog(0x534e4554, "78286118");
    -+        osi_free(p_buf);
    -+        return;
    -+    }
    -     UINT8         type, ctrl_type, ext_type = 0;
    -     BOOLEAN       extension_present, fw_ext_present;
    -     UINT16        protocol = 0;
    -@@ -495,6 +501,12 @@ static void bnep_data_ind (UINT16 l2cap_cid, BT_HDR *p_buf)
    +@@ -495,6 +496,12 @@ static void bnep_data_ind (UINT16 l2cap_cid, BT_HDR *p_buf)
          type = *p++;
          extension_present = type >> 7;
          type &= 0x7f;
    @@ -563,53 +521,34 @@ index 078a72e..f1ad2c9 100644
          if ((rem_len <= bnep_frame_hdr_sizes[type]) || (rem_len > BNEP_MTU_SIZE))
          {
              BNEP_TRACE_EVENT ("BNEP - rcvd frame, bad len: %d  type: 0x%02x", p_buf->len, type);
    -@@ -522,24 +534,36 @@ static void bnep_data_ind (UINT16 l2cap_cid, BT_HDR *p_buf)
    -             UINT16      org_len, new_len;
    -             /* parse the extension headers and process unknown control headers */
    +@@ -524,20 +531,20 @@ static void bnep_data_ind (UINT16 l2cap_cid, BT_HDR *p_buf)
                  org_len = rem_len;
    --            new_len = 0;
    +             new_len = 0;
                  do {
     -
    -+                if (org_len < 2) {
    -+                    android_errorWriteLog(0x534e4554, "67863755");
    -+                    break;
    -+                }
    ++                if (org_len < 2) break;
                      ext     = *p++;
                      length  = *p++;
    --                p += length;
    --
    --                if ((!(ext & 0x7F)) && (*p > BNEP_FILTER_MULTI_ADDR_RESPONSE_MSG))
    --                    bnep_send_command_not_understood (p_bcb, *p);
    +                 p += length;
      
    --                new_len += (length + 2);
     +                new_len = (length + 2);
    - 
    --                if (new_len > org_len)
    -+                if (new_len > org_len) {
    -+                    android_errorWriteLog(0x534e4554, "67863755");
    -                     break;
    -+                }
    -+
    -+                if ((ext & 0x7F) == BNEP_EXTENSION_FILTER_CONTROL) {
    -+                    if (length == 0) {
    -+                        android_errorWriteLog(0x534e4554, "79164722");
    -+                        break;
    -+                    }
    -+                    if (*p > BNEP_FILTER_MULTI_ADDR_RESPONSE_MSG) {
    -+                        bnep_send_command_not_understood(p_bcb, *p);
    -+                    }
    -+                }
    ++                if (new_len > org_len) break;
     +
    -+                p += length;
    +                 if ((!(ext & 0x7F)) && (*p > BNEP_FILTER_MULTI_ADDR_RESPONSE_MSG))
    +                     bnep_send_command_not_understood (p_bcb, *p);
      
    -+		org_len -= new_len;
    +-                new_len += (length + 2);
    +-
    +-                if (new_len > org_len)
    +-                    break;
    +-
    ++                org_len -= new_len;
                  } while (ext & 0x80);
    ++            android_errorWriteLog(0x534e4554, "67863755");
              }
    --
    + 
              osi_free(p_buf);
    -         return;
    -     }
    -@@ -575,7 +599,8 @@ static void bnep_data_ind (UINT16 l2cap_cid, BT_HDR *p_buf)
    +@@ -575,7 +582,8 @@ static void bnep_data_ind (UINT16 l2cap_cid, BT_HDR *p_buf)
                  p_bcb->con_state != BNEP_STATE_CONNECTED &&
                  extension_present && p && rem_len)
              {
    @@ -619,37 +558,29 @@ index 078a72e..f1ad2c9 100644
                  memcpy((UINT8 *)(p_bcb->p_pending_data + 1), p, rem_len);
                  p_bcb->p_pending_data->len    = rem_len;
                  p_bcb->p_pending_data->offset = 0;
    -@@ -585,13 +610,14 @@ static void bnep_data_ind (UINT16 l2cap_cid, BT_HDR *p_buf)
    +@@ -585,6 +593,8 @@ static void bnep_data_ind (UINT16 l2cap_cid, BT_HDR *p_buf)
                  while (extension_present && p && rem_len)
                  {
                      ext_type = *p++;
     +                rem_len--;
    ++                android_errorWriteLog(0x534e4554, "69271284");
                      extension_present = ext_type >> 7;
                      ext_type &= 0x7F;
      
    -                 /* if unknown extension present stop processing */
    --                if (ext_type)
    --                    break;
    --
    -+		if (ext_type != BNEP_EXTENSION_FILTER_CONTROL) break;
    -+ 
    -+                android_errorWriteLog(0x534e4554, "69271284");
    -                 p = bnep_process_control_packet (p_bcb, p, &rem_len, TRUE);
    -             }
    -         }
     diff --git a/stack/bnep/bnep_utils.c b/stack/bnep/bnep_utils.c
    -index 13fb189..05bcdda 100644
    +index 13fb189..65acd33 100644
     --- a/stack/bnep/bnep_utils.c
     +++ b/stack/bnep/bnep_utils.c
    -@@ -22,6 +22,7 @@
    +@@ -22,6 +22,8 @@
       *
       ******************************************************************************/
      
     +#include <cutils/log.h>
    ++
      #include <stdio.h>
      #include <string.h>
      #include "bt_common.h"
    -@@ -154,6 +155,7 @@ void bnepu_release_bcb (tBNEP_CONN *p_bcb)
    +@@ -154,6 +156,7 @@ void bnepu_release_bcb (tBNEP_CONN *p_bcb)
      
          /* Drop any response pointer we may be holding */
          p_bcb->con_state        = BNEP_STATE_IDLE;
    @@ -657,7 +588,7 @@ index 13fb189..05bcdda 100644
          p_bcb->p_pending_data   = NULL;
      
          /* Free transmit queue */
    -@@ -762,35 +764,60 @@ void bnep_process_setup_conn_responce (tBNEP_CONN *p_bcb, UINT8 *p_setup)
    +@@ -762,35 +765,60 @@ void bnep_process_setup_conn_responce (tBNEP_CONN *p_bcb, UINT8 *p_setup)
      UINT8 *bnep_process_control_packet (tBNEP_CONN *p_bcb, UINT8 *p, UINT16 *rem_len, BOOLEAN is_ext)
      {
          UINT8       control_type;
    @@ -726,7 +657,7 @@ index 13fb189..05bcdda 100644
              }
              if (!is_ext)
                  bnep_process_setup_conn_req (p_bcb, p, (UINT8)len);
    -@@ -799,6 +826,12 @@ UINT8 *bnep_process_control_packet (tBNEP_CONN *p_bcb, UINT8 *p, UINT16 *rem_len
    +@@ -799,6 +827,12 @@ UINT8 *bnep_process_control_packet (tBNEP_CONN *p_bcb, UINT8 *p, UINT16 *rem_len
              break;
      
          case BNEP_SETUP_CONNECTION_RESPONSE_MSG:
    @@ -739,7 +670,7 @@ index 13fb189..05bcdda 100644
              if (!is_ext)
                  bnep_process_setup_conn_responce (p_bcb, p);
              p += 2;
    -@@ -806,12 +839,20 @@ UINT8 *bnep_process_control_packet (tBNEP_CONN *p_bcb, UINT8 *p, UINT16 *rem_len
    +@@ -806,12 +840,20 @@ UINT8 *bnep_process_control_packet (tBNEP_CONN *p_bcb, UINT8 *p, UINT16 *rem_len
              break;
      
          case BNEP_FILTER_NET_TYPE_SET_MSG:
    @@ -763,7 +694,7 @@ index 13fb189..05bcdda 100644
              }
              bnepu_process_peer_filter_set (p_bcb, p, len);
              p += len;
    -@@ -819,18 +860,32 @@ UINT8 *bnep_process_control_packet (tBNEP_CONN *p_bcb, UINT8 *p, UINT16 *rem_len
    +@@ -819,18 +861,32 @@ UINT8 *bnep_process_control_packet (tBNEP_CONN *p_bcb, UINT8 *p, UINT16 *rem_len
              break;
      
          case BNEP_FILTER_NET_TYPE_RESPONSE_MSG:
    @@ -799,7 +730,7 @@ index 13fb189..05bcdda 100644
              }
              bnepu_process_peer_multicast_filter_set (p_bcb, p, len);
              p += len;
    -@@ -838,30 +893,38 @@ UINT8 *bnep_process_control_packet (tBNEP_CONN *p_bcb, UINT8 *p, UINT16 *rem_len
    +@@ -838,30 +894,38 @@ UINT8 *bnep_process_control_packet (tBNEP_CONN *p_bcb, UINT8 *p, UINT16 *rem_len
              break;
      
          case BNEP_FILTER_MULTI_ADDR_RESPONSE_MSG:
    @@ -903,22 +834,23 @@ index 11ef79c..c2cdb88 100644
      
          if (op_code == GATT_REQ_READ_BLOB)
     diff --git a/stack/l2cap/l2c_ble.c b/stack/l2cap/l2c_ble.c
    -index 95de4e3..f61416c 100644
    +index 95de4e3..b2f196c 100644
     --- a/stack/l2cap/l2c_ble.c
     +++ b/stack/l2cap/l2c_ble.c
    -@@ -27,6 +27,7 @@
    - #include "bt_utils.h"
    - #include "l2cdefs.h"
    - #include "l2c_int.h"
    -+#include "log/log.h"
    - #include "btu.h"
    +@@ -31,6 +31,7 @@
      #include "btm_int.h"
      #include "hcimsgs.h"
    -@@ -808,6 +809,10 @@ void l2cble_process_sig_cmd (tL2C_LCB *p_lcb, UINT8 *p, UINT16 pkt_len)
    + #include "device/include/controller.h"
    ++#include "log/log.h"
    + #include "stack_config.h"
    + #include "btif_debug_l2c.h"
    + 
    +@@ -808,6 +809,11 @@ void l2cble_process_sig_cmd (tL2C_LCB *p_lcb, UINT8 *p, UINT16 pkt_len)
                  break;
      
              case L2CAP_CMD_DISC_REQ:
    -+            if (p + 4 > p_pkt_end) {
    ++            if (p + 4 > p_pkt_end)
    ++            {
     +                android_errorWriteLog(0x534e4554, "74121659");
     +                return;
     +            }
    @@ -1273,7 +1205,7 @@ index 7e8b3cb..cd7edfe 100644
          fragment->len = client->remote_mtu;
          memcpy(fragment->data + fragment->offset, bt_packet->data + bt_packet->offset, client->remote_mtu);
     diff --git a/stack/mcap/mca_cact.c b/stack/mcap/mca_cact.c
    -index 583a342..6694ff7 100644
    +index 583a342..483169a 100644
     --- a/stack/mcap/mca_cact.c
     +++ b/stack/mcap/mca_cact.c
     @@ -122,7 +122,7 @@ void mca_ccb_snd_req(tMCA_CCB *p_ccb, tMCA_CCB_EVT *p_data)
    @@ -1294,37 +1226,28 @@ index 583a342..6694ff7 100644
      
          MCA_TRACE_DEBUG("%s cong=%d req=%d", __func__, p_ccb->cong, p_msg->op_code);
          /* assume that API functions verified the parameters */
    -@@ -404,7 +404,7 @@ void mca_ccb_hdl_req(tMCA_CCB *p_ccb, tMCA_CCB_EVT *p_data)
    - 
    -     if (((reject_code != MCA_RSP_SUCCESS) && (evt_data.hdr.op_code != MCA_OP_SYNC_INFO_IND))
    -         || send_rsp) {
    --        BT_HDR *p_buf = (BT_HDR *)osi_malloc(MCA_CTRL_MTU);
    -+        BT_HDR *p_buf = (BT_HDR *)osi_malloc(MCA_CTRL_MTU + sizeof(BT_HDR));
    -         p_buf->offset = L2CAP_MIN_OFFSET;
    -         p = p_start = (UINT8*)(p_buf + 1) + L2CAP_MIN_OFFSET;
    -         *p++ = reject_opcode;
     diff --git a/stack/pan/pan_main.c b/stack/pan/pan_main.c
    -index 5c3a367..7d56ee7 100644
    +index 5c3a367..9c90e58 100644
     --- a/stack/pan/pan_main.c
     +++ b/stack/pan/pan_main.c
    -@@ -221,6 +221,38 @@ void pan_conn_ind_cb (UINT16 handle,
    -         BNEP_ConnectResp (handle, BNEP_CONN_FAILED_DST_UUID);
    +@@ -222,6 +222,39 @@ void pan_conn_ind_cb (UINT16 handle,
              return;
          }
    + 
     +    /* Check for valid interactions between the three PAN profile roles */
     +    /*
     +     * For reference, see Table 1 in PAN Profile v1.0 spec.
     +     * Note: the remote is the initiator.
     +     */
    -+    bool is_valid_interaction = false;
    ++    BOOLEAN is_valid_interaction = FALSE;
     +    switch (remote_uuid->uu.uuid16) {
    -+      case UUID_SERVCLASS_NAP:
    -+      case UUID_SERVCLASS_GN:
    -+         if (local_uuid->uu.uuid16 == UUID_SERVCLASS_PANU)
    -+          is_valid_interaction = true;
    ++    case UUID_SERVCLASS_NAP:
    ++    case UUID_SERVCLASS_GN:
    ++        if (local_uuid->uu.uuid16 == UUID_SERVCLASS_PANU)
    ++            is_valid_interaction = TRUE;
     +        break;
    -+      case UUID_SERVCLASS_PANU:
    -+        is_valid_interaction = true;
    ++    case UUID_SERVCLASS_PANU:
    ++        is_valid_interaction = TRUE;
     +        break;
     +    }
     +    /*
    @@ -1343,10 +1266,11 @@ index 5c3a367..7d56ee7 100644
     +        BNEP_ConnectResp(handle, BNEP_CONN_FAILED_SRC_UUID);
     +        return;
     +    }
    - 
    ++
          /* Requested destination role is */
          if (local_uuid->uu.uuid16 == UUID_SERVCLASS_PANU)
    -@@ -596,11 +628,9 @@ void pan_data_buf_ind_cb (UINT16 handle,
    +         req_role = PAN_ROLE_CLIENT;
    +@@ -596,11 +629,9 @@ void pan_data_buf_ind_cb (UINT16 handle,
                  if (pan_cb.pan_data_buf_ind_cb)
                      (*pan_cb.pan_data_buf_ind_cb) (pcb->handle, src, dst, protocol, p_buf, ext, forward);
                  else if (pan_cb.pan_data_ind_cb)
    @@ -1359,7 +1283,7 @@ index 5c3a367..7d56ee7 100644
                  return;
              }
      
    -@@ -623,13 +653,9 @@ void pan_data_buf_ind_cb (UINT16 handle,
    +@@ -623,13 +654,9 @@ void pan_data_buf_ind_cb (UINT16 handle,
          if (pan_cb.pan_data_buf_ind_cb)
              (*pan_cb.pan_data_buf_ind_cb) (pcb->handle, src, dst, protocol, p_buf, ext, forward);
          else if (pan_cb.pan_data_ind_cb)
    @@ -1375,35 +1299,158 @@ index 5c3a367..7d56ee7 100644
      }
      
     diff --git a/stack/sdp/sdp_discovery.c b/stack/sdp/sdp_discovery.c
    -index ec20689..de4e7ff 100644
    +index ec20689..7a5333e 100644
     --- a/stack/sdp/sdp_discovery.c
     +++ b/stack/sdp/sdp_discovery.c
    -@@ -343,7 +343,7 @@ static void process_service_search_rsp (tCONN_CB *p_ccb, UINT8 *p_reply)
    - #if (SDP_RAW_DATA_INCLUDED == TRUE)
    - static void sdp_copy_raw_data (tCONN_CB *p_ccb, BOOLEAN offset)
    - {
    --    unsigned int    cpy_len;
    -+    unsigned int    cpy_len, rem_len;
    -     UINT32          list_len;
    -     UINT8           *p;
    -     UINT8           type;
    -@@ -370,10 +370,15 @@ static void sdp_copy_raw_data (tCONN_CB *p_ccb, BOOLEAN offset)
    -             type = *p++;
    -             p = sdpu_get_len_from_type (p, type, &list_len);
    +@@ -29,6 +29,7 @@
    + #include "bt_target.h"
    + #include "bt_common.h"
    + #include "l2cdefs.h"
    ++#include "log/log.h"
    + #include "hcidefs.h"
    + #include "hcimsgs.h"
    + #include "sdp_api.h"
    +@@ -45,9 +46,12 @@
    + /*              L O C A L    F U N C T I O N     P R O T O T Y P E S            */
    + /********************************************************************************/
    + #if SDP_CLIENT_ENABLED == TRUE
    +-static void          process_service_search_rsp (tCONN_CB *p_ccb, UINT8 *p_reply);
    +-static void          process_service_attr_rsp (tCONN_CB *p_ccb, UINT8 *p_reply);
    +-static void          process_service_search_attr_rsp (tCONN_CB *p_ccb, UINT8 *p_reply);
    ++static void          process_service_search_rsp (tCONN_CB* p_ccb, uint8_t* p_reply,
    ++                                                 uint8_t* p_reply_end);
    ++static void          process_service_attr_rsp (tCONN_CB* p_ccb, uint8_t* p_reply,
    ++                                               uint8_t* p_reply_end);
    ++static void          process_service_search_attr_rsp (tCONN_CB* p_ccb, uint8_t* p_reply,
    ++                                                      uint8_t* p_reply_end);
    + static UINT8         *save_attr_seq (tCONN_CB *p_ccb, UINT8 *p, UINT8 *p_msg_end);
    + static tSDP_DISC_REC *add_record (tSDP_DISCOVERY_DB *p_db, BD_ADDR p_bda);
    + static UINT8         *add_attr (UINT8 *p, tSDP_DISCOVERY_DB *p_db, tSDP_DISC_REC *p_rec,
    +@@ -193,7 +197,7 @@ void sdp_disc_connected (tCONN_CB *p_ccb)
    +     {
    +         p_ccb->disc_state = SDP_DISC_WAIT_SEARCH_ATTR;
    + 
    +-        process_service_search_attr_rsp (p_ccb, NULL);
    ++        process_service_search_attr_rsp (p_ccb, NULL, NULL);
    +     }
    +     else
    +     {
    +@@ -231,6 +235,7 @@ void sdp_disc_server_rsp (tCONN_CB *p_ccb, BT_HDR *p_msg)
    + 
    +     /* Got a reply!! Check what we got back */
    +     p = (UINT8 *)(p_msg + 1) + p_msg->offset;
    ++    uint8_t* p_end = p + p_msg->len;
    + 
    +     BE_STREAM_TO_UINT8 (rsp_pdu, p);
    + 
    +@@ -241,7 +246,7 @@ void sdp_disc_server_rsp (tCONN_CB *p_ccb, BT_HDR *p_msg)
    +     case SDP_PDU_SERVICE_SEARCH_RSP:
    +         if (p_ccb->disc_state == SDP_DISC_WAIT_HANDLES)
    +         {
    +-            process_service_search_rsp (p_ccb, p);
    ++            process_service_search_rsp (p_ccb, p, p_end);
    +             invalid_pdu = FALSE;
              }
    --        if(list_len && list_len < cpy_len )
    -+        if (list_len < cpy_len )
    +         break;
    +@@ -249,7 +254,7 @@ void sdp_disc_server_rsp (tCONN_CB *p_ccb, BT_HDR *p_msg)
    +     case SDP_PDU_SERVICE_ATTR_RSP:
    +         if (p_ccb->disc_state == SDP_DISC_WAIT_ATTR)
    +         {
    +-            process_service_attr_rsp (p_ccb, p);
    ++            process_service_attr_rsp (p_ccb, p, p_end);
    +             invalid_pdu = FALSE;
    +         }
    +         break;
    +@@ -257,7 +262,7 @@ void sdp_disc_server_rsp (tCONN_CB *p_ccb, BT_HDR *p_msg)
    +     case SDP_PDU_SERVICE_SEARCH_ATTR_RSP:
    +         if (p_ccb->disc_state == SDP_DISC_WAIT_SEARCH_ATTR)
              {
    -             cpy_len = list_len;
    +-            process_service_search_attr_rsp (p_ccb, p);
    ++            process_service_search_attr_rsp (p_ccb, p, p_end);
    +             invalid_pdu = FALSE;
              }
    -+        rem_len = SDP_MAX_LIST_BYTE_COUNT - (unsigned int)(p - &p_ccb->rsp_list[0]);
    -+        if (cpy_len > rem_len) {
    -+            SDP_TRACE_WARNING("rem_len :%d less than cpy_len:%d", rem_len, cpy_len);
    -+            cpy_len = rem_len;
    +         break;
    +@@ -280,7 +285,8 @@ void sdp_disc_server_rsp (tCONN_CB *p_ccb, BT_HDR *p_msg)
    + ** Returns          void
    + **
    + *******************************************************************************/
    +-static void process_service_search_rsp (tCONN_CB *p_ccb, UINT8 *p_reply)
    ++static void process_service_search_rsp (tCONN_CB* p_ccb, uint8_t* p_reply,
    ++                                        uint8_t* p_reply_end)
    + {
    +     UINT16      xx;
    +     UINT16      total, cur_handles, orig;
    +@@ -317,6 +323,11 @@ static void process_service_search_rsp (tCONN_CB *p_ccb, UINT8 *p_reply)
    +             sdp_disconnect (p_ccb, SDP_INVALID_CONT_STATE);
    +             return;
    +         }
    ++        if (p_reply + cont_len > p_reply_end) {
    ++            android_errorWriteLog(0x534e4554, "68161546");
    ++            sdp_disconnect(p_ccb, SDP_INVALID_CONT_STATE);
    ++            return;
     +        }
    -         SDP_TRACE_WARNING(
    -           "%s: list_len:%d cpy_len:%d p:%p p_ccb:%p p_db:%p raw_size:%d "
    -           "raw_used:%d raw_data:%p",
    +         /* stay in the same state */
    +         sdp_snd_service_search_req(p_ccb, cont_len, p_reply);
    +     }
    +@@ -326,7 +337,7 @@ static void process_service_search_rsp (tCONN_CB *p_ccb, UINT8 *p_reply)
    +         p_ccb->disc_state = SDP_DISC_WAIT_ATTR;
    + 
    +         /* Kick off the first attribute request */
    +-        process_service_attr_rsp (p_ccb, NULL);
    ++        process_service_attr_rsp (p_ccb, NULL, NULL);
    +     }
    + }
    + 
    +@@ -395,7 +406,8 @@ static void sdp_copy_raw_data (tCONN_CB *p_ccb, BOOLEAN offset)
    + ** Returns          void
    + **
    + *******************************************************************************/
    +-static void process_service_attr_rsp (tCONN_CB *p_ccb, UINT8 *p_reply)
    ++static void process_service_attr_rsp (tCONN_CB* p_ccb, uint8_t* p_reply,
    ++                                      uint8_t* p_reply_end)
    + {
    +     UINT8           *p_start, *p_param_len;
    +     UINT16          param_len, list_byte_count;
    +@@ -502,8 +514,12 @@ static void process_service_attr_rsp (tCONN_CB *p_ccb, UINT8 *p_reply)
    +         /* Was this a continuation request ? */
    +         if (cont_request_needed)
    +         {
    +-            memcpy (p, p_reply, *p_reply + 1);
    +-            p += *p_reply + 1;
    ++            if ((p_reply + *p_reply + 1) <= p_reply_end) {
    ++                memcpy(p, p_reply, *p_reply + 1);
    ++                p += *p_reply + 1;
    ++            } else {
    ++                android_errorWriteLog(0x534e4554, "68161546");
    ++            }
    +         }
    +         else
    +             UINT8_TO_BE_STREAM (p, 0);
    +@@ -541,7 +557,8 @@ static void process_service_attr_rsp (tCONN_CB *p_ccb, UINT8 *p_reply)
    + ** Returns          void
    + **
    + *******************************************************************************/
    +-static void process_service_search_attr_rsp (tCONN_CB *p_ccb, UINT8 *p_reply)
    ++static void process_service_search_attr_rsp (tCONN_CB* p_ccb, uint8_t* p_reply,
    ++                                             uint8_t* p_reply_end)
    + {
    +     UINT8           *p, *p_start, *p_end, *p_param_len;
    +     UINT8           type;
    +@@ -641,8 +658,12 @@ static void process_service_search_attr_rsp (tCONN_CB *p_ccb, UINT8 *p_reply)
    +         /* No continuation for first request */
    +         if (p_reply)
    +         {
    +-            memcpy (p, p_reply, *p_reply + 1);
    +-            p += *p_reply + 1;
    ++            if ((p_reply + *p_reply + 1) <= p_reply_end) {
    ++                memcpy(p, p_reply, *p_reply + 1);
    ++                p += *p_reply + 1;
    ++            } else {
    ++                android_errorWriteLog(0x534e4554, "68161546");
    ++            }
    +         }
    +         else
    +             UINT8_TO_BE_STREAM (p, 0);
     diff --git a/stack/sdp/sdp_main.c b/stack/sdp/sdp_main.c
     index c888817..7cbe2d3 100644
     --- a/stack/sdp/sdp_main.c
    @@ -1434,7 +1481,7 @@ index c888817..7cbe2d3 100644
      /*******************************************************************************
      **
     diff --git a/stack/sdp/sdp_server.c b/stack/sdp/sdp_server.c
    -index 627f4cf..d680180 100644
    +index 627f4cf..993e0a1 100644
     --- a/stack/sdp/sdp_server.c
     +++ b/stack/sdp/sdp_server.c
     @@ -23,6 +23,7 @@
    @@ -1513,7 +1560,7 @@ index 627f4cf..d680180 100644
              {
                  sdpu_build_n_send_error (p_ccb, trans_num, SDP_INVALID_CONT_STATE,
                                           SDP_TEXT_BAD_CONT_INX);
    -@@ -327,25 +339,27 @@ static void process_service_attr_req (tCONN_CB *p_ccb, UINT16 trans_num,
    +@@ -327,15 +339,15 @@ static void process_service_attr_req (tCONN_CB *p_ccb, UINT16 trans_num,
          BOOLEAN         is_cont = FALSE;
          UINT16          attr_len;
      
    @@ -1530,14 +1577,11 @@ index 627f4cf..d680180 100644
      
     +    /* Extract the record handle */
     +    BE_STREAM_TO_UINT32(rec_handle, p_req);
    -+    param_len -= sizeof(rec_handle);
     +
          /* Get the max list length we can send. Cap it at MTU size minus overhead */
          BE_STREAM_TO_UINT16 (max_list_len, p_req);
    -+    param_len -= sizeof(max_list_len);
      
    -     if (max_list_len > (p_ccb->rem_mtu_size - SDP_MAX_ATTR_RSPHDR_LEN))
    -         max_list_len = p_ccb->rem_mtu_size - SDP_MAX_ATTR_RSPHDR_LEN;
    +@@ -344,8 +356,8 @@ static void process_service_attr_req (tCONN_CB *p_ccb, UINT16 trans_num,
      
          p_req = sdpu_extract_attr_seq (p_req, param_len, &attr_seq);
      
    @@ -1548,12 +1592,13 @@ index 627f4cf..d680180 100644
              sdpu_build_n_send_error (p_ccb, trans_num, SDP_INVALID_REQ_SYNTAX, SDP_TEXT_BAD_ATTR_LIST);
              return;
          }
    -@@ -360,13 +374,19 @@ static void process_service_attr_req (tCONN_CB *p_ccb, UINT16 trans_num,
    +@@ -360,13 +372,20 @@ static void process_service_attr_req (tCONN_CB *p_ccb, UINT16 trans_num,
              return;
          }
      
     +    if (max_list_len < 4) {
     +        sdpu_build_n_send_error(p_ccb, trans_num, SDP_ILLEGAL_PARAMETER, NULL);
    ++        android_errorWriteLog(0x534e4554, "68776054");
     +        return;
     +    }
     +
    @@ -1569,7 +1614,7 @@ index 627f4cf..d680180 100644
                  sdpu_build_n_send_error(p_ccb, trans_num, SDP_INVALID_CONT_STATE,
                                          SDP_TEXT_BAD_CONT_LEN);
                  return;
    -@@ -562,8 +582,8 @@ static void process_service_search_attr_req (tCONN_CB *p_ccb, UINT16 trans_num,
    +@@ -562,8 +581,8 @@ static void process_service_search_attr_req (tCONN_CB *p_ccb, UINT16 trans_num,
          /* Extract the UUID sequence to search for */
          p_req = sdpu_extract_uid_seq (p_req, param_len, &uid_seq);
      
    @@ -1580,7 +1625,7 @@ index 627f4cf..d680180 100644
              sdpu_build_n_send_error (p_ccb, trans_num, SDP_INVALID_REQ_SYNTAX, SDP_TEXT_BAD_UUID_LIST);
              return;
          }
    -@@ -576,21 +596,27 @@ static void process_service_search_attr_req (tCONN_CB *p_ccb, UINT16 trans_num,
    +@@ -576,21 +595,28 @@ static void process_service_search_attr_req (tCONN_CB *p_ccb, UINT16 trans_num,
      
          p_req = sdpu_extract_attr_seq (p_req, param_len, &attr_seq);
      
    @@ -1596,6 +1641,7 @@ index 627f4cf..d680180 100644
      
     +    if (max_list_len < 4) {
     +        sdpu_build_n_send_error(p_ccb, trans_num, SDP_ILLEGAL_PARAMETER, NULL);
    ++        android_errorWriteLog(0x534e4554, "68817966");
     +        return;
     +    }
     +
    @@ -1791,43 +1837,106 @@ index 05414cd..71dab92 100644
      extern void     sdp_disconnect (tCONN_CB*p_ccb, UINT16 reason);
      
      #if (defined(SDP_DEBUG) && SDP_DEBUG == TRUE)
    -diff --git a/stack/smp/smp_br_main.c b/stack/smp/smp_br_main.c
    -index 11039ec..87ae24b 100644
    ---- a/stack/smp/smp_br_main.c
    -+++ b/stack/smp/smp_br_main.c
    -@@ -19,6 +19,7 @@
    - #include "bt_target.h"
    +diff --git a/stack/smp/p_256_ecc_pp.c b/stack/smp/p_256_ecc_pp.c
    +index 2eaebd4..832ce11 100644
    +--- a/stack/smp/p_256_ecc_pp.c
    ++++ b/stack/smp/p_256_ecc_pp.c
    +@@ -259,4 +259,25 @@ void ECC_PointMult_Bin_NAF(Point *q, Point *p, DWORD *n, uint32_t keyLength)
    +     multiprecision_mersenns_mult_mod(q->y, q->y, q->z, keyLength);
    + }
      
    ++bool ECC_ValidatePoint(Point *pt)
    ++{
    ++    const size_t kl = KEY_LENGTH_DWORDS_P256;
    ++    p_256_init_curve(kl);
    ++
    ++    // Ensure y^2 = x^3 + a*x + b (mod p); a = -3
    ++
    ++    // y^2 mod p
    ++    DWORD y2_mod[KEY_LENGTH_DWORDS_P256] = {0};
    ++    multiprecision_mersenns_squa_mod(y2_mod, (DWORD*)pt->y, kl);
    + 
    ++    // Right hand side calculation
    ++    DWORD rhs[KEY_LENGTH_DWORDS_P256] = {0};
    ++    multiprecision_mersenns_squa_mod(rhs, (DWORD*)pt->x, kl);
    ++    DWORD three[KEY_LENGTH_DWORDS_P256] = {0};
    ++    three[0] = 3;
    ++    multiprecision_sub_mod(rhs, rhs, three, kl);
    ++    multiprecision_mersenns_mult_mod(rhs, rhs, (DWORD*)pt->x, kl);
    ++    multiprecision_add_mod(rhs, rhs, curve_p256.b, kl);
    ++
    ++    return multiprecision_compare(rhs, y2_mod, kl) == 0;
    ++}
    +diff --git a/stack/smp/p_256_ecc_pp.h b/stack/smp/p_256_ecc_pp.h
    +index fd3dc64..49f2d11 100644
    +--- a/stack/smp/p_256_ecc_pp.h
    ++++ b/stack/smp/p_256_ecc_pp.h
    +@@ -24,6 +24,7 @@
    + 
    + #pragma once
    + 
    ++#include <stdbool.h>
    + #include "p_256_multprecision.h"
    + 
    + typedef unsigned long  DWORD;
    +@@ -56,6 +57,8 @@ typedef struct {
    + extern elliptic_curve_t curve;
    + extern elliptic_curve_t curve_p256;
    + 
    ++bool ECC_ValidatePoint(Point *p);
    ++
    + void ECC_PointMult_Bin_NAF(Point *q, Point *p, DWORD *n, uint32_t keyLength);
    + 
    + #define ECC_PointMult(q, p, n, keyLength)  ECC_PointMult_Bin_NAF(q, p, n, keyLength)
    +diff --git a/stack/smp/smp_act.c b/stack/smp/smp_act.c
    +index e4152a4..9e0246c 100644
    +--- a/stack/smp/smp_act.c
    ++++ b/stack/smp/smp_act.c
    +@@ -16,11 +16,13 @@
    +  *
    +  ******************************************************************************/
    + 
    ++#include <cutils/log.h>
      #include <string.h>
    -+#include "log/log.h"
    - #include "smp_int.h"
    + #include "device/include/interop.h"
    + #include "include/bt_target.h"
    + #include "stack/btm/btm_int.h"
    + #include "stack/include/l2c_api.h"
    ++#include "stack/smp/p_256_ecc_pp.h"
    + #include "stack/smp/smp_int.h"
    + #include "utils/include/bt_utils.h"
      
    - #if BLE_INCLUDED == TRUE
    -@@ -344,6 +345,12 @@ void smp_br_state_machine_event(tSMP_CB *p_cb, tSMP_BR_EVENT event, void *p_data
    -         return;
    -     }
    +@@ -750,6 +752,18 @@ void smp_process_pairing_public_key(tSMP_CB *p_cb, tSMP_INT_DATA *p_data)
      
    -+    if (p_cb->role > HCI_ROLE_SLAVE) {
    -+        SMP_TRACE_ERROR("%s: invalid role %d", __func__, p_cb->role);
    -+        android_errorWriteLog(0x534e4554, "80145946");
    +     STREAM_TO_ARRAY(p_cb->peer_publ_key.x, p, BT_OCTET32_LEN);
    +     STREAM_TO_ARRAY(p_cb->peer_publ_key.y, p, BT_OCTET32_LEN);
    ++
    ++    Point pt;
    ++    memcpy(pt.x, p_cb->peer_publ_key.x, BT_OCTET32_LEN);
    ++    memcpy(pt.y, p_cb->peer_publ_key.y, BT_OCTET32_LEN);
    ++
    ++    if (!ECC_ValidatePoint(&pt))
    ++    {
    ++        android_errorWriteLog(0x534e4554, "72377774");
    ++        smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &reason);
     +        return;
     +    }
     +
    -     SMP_TRACE_DEBUG( "SMP Role: %s State: [%s (%d)], Event: [%s (%d)]",
    -                       (p_cb->role == HCI_ROLE_SLAVE) ? "Slave" : "Master",
    -                       smp_get_br_state_name( p_cb->br_state),
    +     p_cb->flags |= SMP_PAIR_FLAG_HAVE_PEER_PUBL_KEY;
    + 
    +     smp_wait_for_both_public_keys(p_cb, NULL);
     diff --git a/stack/smp/smp_main.c b/stack/smp/smp_main.c
    -index c3709f8..96cf555 100644
    +index c3709f8..67a2b39 100644
     --- a/stack/smp/smp_main.c
     +++ b/stack/smp/smp_main.c
    -@@ -17,6 +17,7 @@
    -  ******************************************************************************/
    - 
    - #include "bt_target.h"
    -+#include <cutils/log.h>
    +@@ -20,6 +20,7 @@
      
      #if SMP_INCLUDED == TRUE
      
    ++#include <cutils/log.h>
    + #include <string.h>
    + #include "smp_int.h"
    + 
     @@ -770,6 +771,13 @@ void smp_sm_event(tSMP_CB *p_cb, tSMP_EVENT event, void *p_data)
          UINT8           curr_state = p_cb->state;
          tSMP_SM_TBL     state_table;
    @@ -1843,7 +1952,7 @@ index c3709f8..96cf555 100644
      
          SMP_TRACE_EVENT("main smp_sm_event");
     diff --git a/stack/smp/smp_utils.c b/stack/smp/smp_utils.c
    -index a7357db..93c9a23 100644
    +index a7357db..675cb42 100644
     --- a/stack/smp/smp_utils.c
     +++ b/stack/smp/smp_utils.c
     @@ -297,8 +297,7 @@ BOOLEAN  smp_send_msg_to_L2CAP(BD_ADDR rem_bda, BT_HDR *p_toL2CAP)
    @@ -1852,7 +1961,7 @@ index a7357db..93c9a23 100644
              smp_cb.total_tx_unacked -= 1;
     -        SMP_TRACE_ERROR("SMP   failed to pass msg:0x%0x to L2CAP",
     -                         *((UINT8 *)(p_toL2CAP + 1) + p_toL2CAP->offset));
    -+	SMP_TRACE_ERROR("SMP failed to pass msg to L2CAP");
    ++        SMP_TRACE_ERROR("SMP failed to pass msg to L2CAP");
              return FALSE;
          }
          else
    
    From 585c841adecba4cd148475b1ee7465e9c38a72b3 Mon Sep 17 00:00:00 2001
    From: AndDiSa <anddisa@googlemail.com>
    Date: Tue, 25 Sep 2018 10:36:35 +0200
    Subject: [PATCH 102/159] update patches
    
    Change-Id: I76ac459096118f4c517a39169a145b16fa0e5531
    ---
     bionic.patch                    |  38 +--
     build.patch                     |  18 +-
     external_e2fsprogs.patch        |   4 +-
     external_libdrm.patch           |   2 +-
     external_libhevc.patch          |  20 +-
     external_skia.patch             |  36 +--
     external_wpa_supplicant_8.patch |  24 +-
     frameworks_av.patch             | 168 ++++++------
     frameworks_base.patch           | 452 ++++++++++++++++----------------
     frameworks_native.patch         | 104 ++++----
     frameworks_op_net_wifi.patch    |   4 +-
     frameworks_support.patch        |  14 +-
     hardware_libhardware.patch      |   4 +-
     libcore.patch                   |  10 +-
     packages_apps_nfc.patch         |   2 +-
     packages_apps_settings.patch    |  10 +-
     system_bt.patch                 |  64 ++---
     system_core.patch               | 232 ++++++++++++++--
     system_media.patch              |   2 +-
     system_sepolicy.patch           |  16 +-
     update_engine.patch             |  38 +--
     21 files changed, 727 insertions(+), 535 deletions(-)
    
    diff --git a/bionic.patch b/bionic.patch
    index bc655ad..9b2510f 100644
    --- a/bionic.patch
    +++ b/bionic.patch
    @@ -1,5 +1,5 @@
     diff --git a/libc/arch-arm/arm.mk b/libc/arch-arm/arm.mk
    -index 76f465e..21b6152 100644
    +index 76f465e81..21b615236 100644
     --- a/libc/arch-arm/arm.mk
     +++ b/libc/arch-arm/arm.mk
     @@ -1,6 +1,7 @@
    @@ -22,7 +22,7 @@ index 76f465e..21b6152 100644
      # Inherently architecture-specific code.
     diff --git a/libc/arch-arm/generic/bionic/memchr.S b/libc/arch-arm/generic/bionic/memchr.S
     new file mode 100644
    -index 0000000..490cdb7
    +index 000000000..490cdb7b0
     --- /dev/null
     +++ b/libc/arch-arm/generic/bionic/memchr.S
     @@ -0,0 +1,200 @@
    @@ -227,7 +227,7 @@ index 0000000..490cdb7
     +
     +END(memchr)
     diff --git a/libc/arch-arm/include/machine/cpu-features.h b/libc/arch-arm/include/machine/cpu-features.h
    -index fc8c80d..8e7f950 100644
    +index fc8c80dc7..8e7f95095 100644
     --- a/libc/arch-arm/include/machine/cpu-features.h
     +++ b/libc/arch-arm/include/machine/cpu-features.h
     @@ -33,7 +33,9 @@
    @@ -242,7 +242,7 @@ index fc8c80d..8e7f950 100644
      #    define __ARM_ARCH__ 7
      #  elif defined __ARM_ARCH_6__   || defined __ARM_ARCH_6J__ || \
     diff --git a/libc/bionic/jemalloc.h b/libc/bionic/jemalloc.h
    -index fceb323..f7e8770 100644
    +index fceb323d3..f7e877056 100644
     --- a/libc/bionic/jemalloc.h
     +++ b/libc/bionic/jemalloc.h
     @@ -26,6 +26,7 @@
    @@ -254,7 +254,7 @@ index fceb323..f7e8770 100644
      void je_malloc_disable();
      void je_malloc_enable();
     diff --git a/libc/bionic/jemalloc_wrapper.cpp b/libc/bionic/jemalloc_wrapper.cpp
    -index e33d560..266b966 100644
    +index e33d560a4..266b9660c 100644
     --- a/libc/bionic/jemalloc_wrapper.cpp
     +++ b/libc/bionic/jemalloc_wrapper.cpp
     @@ -14,6 +14,7 @@
    @@ -305,7 +305,7 @@ index e33d560..266b966 100644
     +  return 0;
     +}
     diff --git a/libc/bionic/malloc_common.cpp b/libc/bionic/malloc_common.cpp
    -index e050619..8053535 100644
    +index e05061917..8053535d9 100644
     --- a/libc/bionic/malloc_common.cpp
     +++ b/libc/bionic/malloc_common.cpp
     @@ -68,6 +68,7 @@ static constexpr MallocDispatch __libc_malloc_default_dispatch
    @@ -343,7 +343,7 @@ index e050619..8053535 100644
                                              prefix, "malloc")) {
          return false;
     diff --git a/libc/include/malloc.h b/libc/include/malloc.h
    -index 87555a9..f0cdf82 100644
    +index 87555a96b..f0cdf82f3 100644
     --- a/libc/include/malloc.h
     +++ b/libc/include/malloc.h
     @@ -70,6 +70,11 @@ extern struct mallinfo mallinfo(void);
    @@ -359,7 +359,7 @@ index 87555a9..f0cdf82 100644
      
      #endif  /* LIBC_INCLUDE_MALLOC_H_ */
     diff --git a/libc/libc.arm.map b/libc/libc.arm.map
    -index 38f8437..52698b6 100644
    +index 38f8437f4..52698b6f0 100644
     --- a/libc/libc.arm.map
     +++ b/libc/libc.arm.map
     @@ -1494,4 +1494,5 @@ LIBC_PLATFORM {
    @@ -369,7 +369,7 @@ index 38f8437..52698b6 100644
     +    mallopt;
      } LIBC_N;
     diff --git a/libc/libc.arm64.map b/libc/libc.arm64.map
    -index afbd0ee..db7368d 100644
    +index afbd0ee4b..db7368ded 100644
     --- a/libc/libc.arm64.map
     +++ b/libc/libc.arm64.map
     @@ -1209,4 +1209,5 @@ LIBC_PLATFORM {
    @@ -379,7 +379,7 @@ index afbd0ee..db7368d 100644
     +    mallopt;
      } LIBC_N;
     diff --git a/libc/libc.mips.map b/libc/libc.mips.map
    -index 46c835b..2e272f5 100644
    +index 46c835b0b..2e272f5ca 100644
     --- a/libc/libc.mips.map
     +++ b/libc/libc.mips.map
     @@ -1335,4 +1335,5 @@ LIBC_PLATFORM {
    @@ -389,7 +389,7 @@ index 46c835b..2e272f5 100644
     +    mallopt;
      } LIBC_N;
     diff --git a/libc/libc.mips64.map b/libc/libc.mips64.map
    -index afbd0ee..db7368d 100644
    +index afbd0ee4b..db7368ded 100644
     --- a/libc/libc.mips64.map
     +++ b/libc/libc.mips64.map
     @@ -1209,4 +1209,5 @@ LIBC_PLATFORM {
    @@ -399,7 +399,7 @@ index afbd0ee..db7368d 100644
     +    mallopt;
      } LIBC_N;
     diff --git a/libc/libc.x86.map b/libc/libc.x86.map
    -index 9417d56..6598e3d 100644
    +index 9417d5620..6598e3d4b 100644
     --- a/libc/libc.x86.map
     +++ b/libc/libc.x86.map
     @@ -1334,4 +1334,5 @@ LIBC_PLATFORM {
    @@ -409,7 +409,7 @@ index 9417d56..6598e3d 100644
     +    mallopt;
      } LIBC_N;
     diff --git a/libc/libc.x86_64.map b/libc/libc.x86_64.map
    -index afbd0ee..db7368d 100644
    +index afbd0ee4b..db7368ded 100644
     --- a/libc/libc.x86_64.map
     +++ b/libc/libc.x86_64.map
     @@ -1209,4 +1209,5 @@ LIBC_PLATFORM {
    @@ -419,7 +419,7 @@ index afbd0ee..db7368d 100644
     +    mallopt;
      } LIBC_N;
     diff --git a/libc/malloc_debug/malloc_debug.cpp b/libc/malloc_debug/malloc_debug.cpp
    -index 1ee7689..329e725 100644
    +index 1ee76897d..329e72505 100644
     --- a/libc/malloc_debug/malloc_debug.cpp
     +++ b/libc/malloc_debug/malloc_debug.cpp
     @@ -76,6 +76,7 @@ void* debug_memalign(size_t alignment, size_t bytes);
    @@ -442,7 +442,7 @@ index 1ee7689..329e725 100644
        if (DebugCallsDisabled()) {
          return g_dispatch->posix_memalign(memptr, alignment, size);
     diff --git a/libc/malloc_debug/tests/malloc_debug_unit_tests.cpp b/libc/malloc_debug/tests/malloc_debug_unit_tests.cpp
    -index 014b913..8014f06 100644
    +index 014b91352..8014f0652 100644
     --- a/libc/malloc_debug/tests/malloc_debug_unit_tests.cpp
     +++ b/libc/malloc_debug/tests/malloc_debug_unit_tests.cpp
     @@ -58,6 +58,7 @@ void debug_get_malloc_leak_info(uint8_t**, size_t*, size_t*, size_t*, size_t*);
    @@ -483,7 +483,7 @@ index 014b913..8014f06 100644
        Init("guard");
      
     diff --git a/libc/private/bionic_malloc_dispatch.h b/libc/private/bionic_malloc_dispatch.h
    -index 02a092f..cdae466 100644
    +index 02a092f40..cdae466c9 100644
     --- a/libc/private/bionic_malloc_dispatch.h
     +++ b/libc/private/bionic_malloc_dispatch.h
     @@ -45,6 +45,7 @@ typedef void* (*MallocRealloc)(void*, size_t);
    @@ -503,7 +503,7 @@ index 02a092f..cdae466 100644
      
      #endif
     diff --git a/linker/Android.mk b/linker/Android.mk
    -index 4a4ca5c..0d592c9 100644
    +index 4a4ca5c5a..0d592c97f 100644
     --- a/linker/Android.mk
     +++ b/linker/Android.mk
     @@ -54,6 +54,10 @@ ifeq ($(TARGET_IS_64_BIT),true)
    @@ -518,7 +518,7 @@ index 4a4ca5c..0d592c9 100644
      LOCAL_CFLAGS += -I$(LOCAL_PATH)/../libc/
      
     diff --git a/linker/linker.cpp b/linker/linker.cpp
    -index a043b85..cd1874f 100644
    +index a043b859a..cd1874fe7 100644
     --- a/linker/linker.cpp
     +++ b/linker/linker.cpp
     @@ -560,7 +560,7 @@ static bool realpath_fd(int fd, std::string* realpath) {
    @@ -562,7 +562,7 @@ index a043b85..cd1874f 100644
          // phdr_table_protect_segments() after all of them are applied.
          DL_WARN("%s has text relocations. This is wasting memory and prevents "
     diff --git a/tests/malloc_test.cpp b/tests/malloc_test.cpp
    -index 8fba1c4..a7b9d52 100644
    +index 8fba1c449..a7b9d52e5 100644
     --- a/tests/malloc_test.cpp
     +++ b/tests/malloc_test.cpp
     @@ -500,3 +500,10 @@ TEST(malloc, verify_alignment) {
    diff --git a/build.patch b/build.patch
    index f0c7554..6da1e9e 100644
    --- a/build.patch
    +++ b/build.patch
    @@ -1,5 +1,5 @@
     diff --git a/core/Makefile b/core/Makefile
    -index d8b4ef8..2f962aa 100644
    +index d8b4ef89b..2f962aa7d 100644
     --- a/core/Makefile
     +++ b/core/Makefile
     @@ -247,6 +247,7 @@ endif
    @@ -11,7 +11,7 @@ index d8b4ef8..2f962aa 100644
      	$(hide) $(foreach file,$(system_prop_file), \
      		if [ -f "$(file)" ]; then \
     diff --git a/core/combo/arch/arm/armv7-a-neon.mk b/core/combo/arch/arm/armv7-a-neon.mk
    -index 5d5b050..b0e1e25 100644
    +index 5d5b05009..b0e1e25c8 100644
     --- a/core/combo/arch/arm/armv7-a-neon.mk
     +++ b/core/combo/arch/arm/armv7-a-neon.mk
     @@ -8,36 +8,48 @@ ARCH_ARM_HAVE_NEON              := true
    @@ -82,7 +82,7 @@ index 5d5b050..b0e1e25 100644
     +	-mfpu=$(TARGET_$(combo_2nd_arch_prefix)FPU_VARIANT)
     +endif
     diff --git a/core/main.mk b/core/main.mk
    -index a612f83..921eb32 100644
    +index a612f835d..921eb3274 100644
     --- a/core/main.mk
     +++ b/core/main.mk
     @@ -215,7 +215,7 @@ endif
    @@ -95,7 +95,7 @@ index a612f83..921eb32 100644
      
      
     diff --git a/core/product.mk b/core/product.mk
    -index 332b015..447ebbc 100644
    +index 332b015fd..447ebbcfa 100644
     --- a/core/product.mk
     +++ b/core/product.mk
     @@ -73,6 +73,7 @@ endef
    @@ -107,7 +107,7 @@ index 332b015..447ebbc 100644
          PRODUCT_MODEL \
          PRODUCT_LOCALES \
     diff --git a/core/product_config.mk b/core/product_config.mk
    -index 6438d51..2204f78 100644
    +index 6438d51be..2204f7800 100644
     --- a/core/product_config.mk
     +++ b/core/product_config.mk
     @@ -363,6 +363,9 @@ endif
    @@ -122,7 +122,7 @@ index 6438d51..2204f78 100644
          $(strip $(PRODUCTS.$(INTERNAL_PRODUCT).PRODUCT_PACKAGE_OVERLAYS))
     diff --git a/core/tasks/kernel.mk b/core/tasks/kernel.mk
     new file mode 100644
    -index 0000000..80664fa
    +index 000000000..80664faf2
     --- /dev/null
     +++ b/core/tasks/kernel.mk
     @@ -0,0 +1,196 @@
    @@ -323,7 +323,7 @@ index 0000000..80664fa
     +ALL_PREBUILT += $(INSTALLED_KERNEL_TARGET)
     +endif
     diff --git a/core/version_defaults.mk b/core/version_defaults.mk
    -index 7c96344..662cd08 100644
    +index 7c9634490..662cd0807 100644
     --- a/core/version_defaults.mk
     +++ b/core/version_defaults.mk
     @@ -131,7 +131,7 @@ ifeq "" "$(PLATFORM_SECURITY_PATCH)"
    @@ -336,7 +336,7 @@ index 7c96344..662cd08 100644
      
      ifeq "" "$(PLATFORM_BASE_OS)"
     diff --git a/target/product/core.mk b/target/product/core.mk
    -index 0a4e0fd..5508c12 100644
    +index 0a4e0fdfe..5508c12e7 100644
     --- a/target/product/core.mk
     +++ b/target/product/core.mk
     @@ -1,3 +1,4 @@
    @@ -353,7 +353,7 @@ index 0a4e0fd..5508c12 100644
          MmsService
      
     diff --git a/tools/releasetools/ota_from_target_files.py b/tools/releasetools/ota_from_target_files.py
    -index d409d94..6aa14d2 100755
    +index d409d94f9..6aa14d284 100755
     --- a/tools/releasetools/ota_from_target_files.py
     +++ b/tools/releasetools/ota_from_target_files.py
     @@ -1284,6 +1284,11 @@ def WriteABOTAPackageWithBrilloScript(target_file, output_file,
    diff --git a/external_e2fsprogs.patch b/external_e2fsprogs.patch
    index 4ba54c6..0718beb 100644
    --- a/external_e2fsprogs.patch
    +++ b/external_e2fsprogs.patch
    @@ -1,5 +1,5 @@
     diff --git a/e2fsck/logfile.c b/e2fsck/logfile.c
    -index 40e5acb..3e4df8a 100644
    +index 40e5acb7..3e4df8a7 100644
     --- a/e2fsck/logfile.c
     +++ b/e2fsck/logfile.c
     @@ -67,7 +67,7 @@ static void expand_percent_expression(e2fsck_t ctx, char ch,
    @@ -12,7 +12,7 @@ index 40e5acb..3e4df8a 100644
      	char		buf[256];
      
     diff --git a/misc/blkid.c b/misc/blkid.c
    -index 388abad..248cacf 100644
    +index 388abad0..248cacf6 100644
     --- a/misc/blkid.c
     +++ b/misc/blkid.c
     @@ -86,7 +86,9 @@ static void safe_print(const char *cp, int len)
    diff --git a/external_libdrm.patch b/external_libdrm.patch
    index 6e6503f..dbc6b3d 100644
    --- a/external_libdrm.patch
    +++ b/external_libdrm.patch
    @@ -1,5 +1,5 @@
     diff --git a/xf86drm.c b/xf86drm.c
    -index 7e28b4f..67f9f83 100644
    +index 7e28b4f7..67f9f838 100644
     --- a/xf86drm.c
     +++ b/xf86drm.c
     @@ -732,8 +732,8 @@ int drmOpen(const char *name, const char *busid)
    diff --git a/external_libhevc.patch b/external_libhevc.patch
    index 5758933..a84d765 100644
    --- a/external_libhevc.patch
    +++ b/external_libhevc.patch
    @@ -4502,10 +4502,14 @@ diff --git a/decoder/ihevcd_utils.c b/decoder/ihevcd_utils.c
     index 7d76577..14c36ba 100755
     --- a/decoder/ihevcd_utils.c
     +++ b/decoder/ihevcd_utils.c
    -@@ -662,6 +662,106 @@ IHEVCD_ERROR_T ihevcd_mv_buf_mgr_add_bufs(codec_t *ps_codec)
    - *******************************************************************************
    - *
    - * @brief
    +@@ -658,6 +658,106 @@ IHEVCD_ERROR_T ihevcd_mv_buf_mgr_add_bufs(codec_t *ps_codec)
    +     }
    +     return ret;
    + }
    ++/**
    ++*******************************************************************************
    ++*
    ++* @brief
     +*  Output buffer check
     +*
     +* @par Description:
    @@ -4602,13 +4606,9 @@ index 7d76577..14c36ba 100755
     +    return (IHEVCD_ERROR_T)IHEVCD_SUCCESS;
     +}
     +
    -+/**
    -+*******************************************************************************
    -+*
    -+* @brief
    - *  Picture level initializations required during parsing
    + /**
    + *******************************************************************************
      *
    - * @par Description:
     @@ -713,6 +813,10 @@ IHEVCD_ERROR_T ihevcd_parse_pic_init(codec_t *ps_codec)
              ps_codec->s_parse.i4_first_pic_init = 1;
          }
    diff --git a/external_skia.patch b/external_skia.patch
    index 9e0708e..9bc6892 100644
    --- a/external_skia.patch
    +++ b/external_skia.patch
    @@ -1,5 +1,5 @@
     diff --git a/Android.mk b/Android.mk
    -index 77c258a..4dbd17b 100644
    +index 77c258aa06..4dbd17bb63 100644
     --- a/Android.mk
     +++ b/Android.mk
     @@ -643,7 +643,6 @@ LOCAL_SRC_FILES := \
    @@ -11,7 +11,7 @@ index 77c258a..4dbd17b 100644
      	src/utils/SkTextureCompressor.cpp \
      	src/utils/SkTextureCompressor_ASTC.cpp \
     diff --git a/dm/Android.mk b/dm/Android.mk
    -index e51da0f..f362c99 100644
    +index e51da0fc6e..f362c99aca 100644
     --- a/dm/Android.mk
     +++ b/dm/Android.mk
     @@ -213,7 +213,6 @@ LOCAL_SRC_FILES := \
    @@ -23,7 +23,7 @@ index e51da0f..f362c99 100644
      	../tests/RandomTest.cpp \
      	../tests/ReadPixelsTest.cpp \
     diff --git a/include/core/SkOSFile.h b/include/core/SkOSFile.h
    -index f977327..cb775e2 100644
    +index f977327e25..cb775e2bc1 100644
     --- a/include/core/SkOSFile.h
     +++ b/include/core/SkOSFile.h
     @@ -31,20 +31,12 @@ FILE* sk_fopen(const char path[], SkFILE_Flags);
    @@ -60,7 +60,7 @@ index f977327..cb775e2 100644
      
      // Create a new directory at this path; returns true if successful.
     diff --git a/include/core/SkStream.h b/include/core/SkStream.h
    -index 4502416..265fb64 100644
    +index 4502416fd9..265fb641c7 100644
     --- a/include/core/SkStream.h
     +++ b/include/core/SkStream.h
     @@ -11,8 +11,9 @@
    @@ -131,10 +131,10 @@ index 4502416..265fb64 100644
      };
     diff --git a/resources/invalid_images/b38116746.ico b/resources/invalid_images/b38116746.ico
     new file mode 100644
    -index 0000000..35ee5b5
    +index 0000000000..35ee5b5a28
     Binary files /dev/null and b/resources/invalid_images/b38116746.ico differ
     diff --git a/src/codec/SkIcoCodec.cpp b/src/codec/SkIcoCodec.cpp
    -index dc4222a..8b3d26d 100644
    +index dc4222a43c..8b3d26dd86 100644
     --- a/src/codec/SkIcoCodec.cpp
     +++ b/src/codec/SkIcoCodec.cpp
     @@ -14,6 +14,7 @@
    @@ -168,7 +168,7 @@ index dc4222a..8b3d26d 100644
              bytesRead += size;
      
     diff --git a/src/codec/SkIcoCodec.h b/src/codec/SkIcoCodec.h
    -index 9a3f248..5a3740d 100644
    +index 9a3f248af5..5a3740d2c0 100644
     --- a/src/codec/SkIcoCodec.h
     +++ b/src/codec/SkIcoCodec.h
     @@ -8,6 +8,7 @@
    @@ -180,7 +180,7 @@ index 9a3f248..5a3740d 100644
      
      /*
     diff --git a/src/codec/SkWebpCodec.cpp b/src/codec/SkWebpCodec.cpp
    -index 6cfb385..8acd205 100644
    +index 6cfb385294..8acd205d13 100644
     --- a/src/codec/SkWebpCodec.cpp
     +++ b/src/codec/SkWebpCodec.cpp
     @@ -235,7 +235,10 @@ SkCodec::Result SkWebpCodec::onGetPixels(const SkImageInfo& dstInfo, void* dst,
    @@ -196,7 +196,7 @@ index 6cfb385..8acd205 100644
              }
      
     diff --git a/src/core/SkPath.cpp b/src/core/SkPath.cpp
    -index 320448a..9eb5cd1 100644
    +index 320448a30e..9eb5cd184b 100644
     --- a/src/core/SkPath.cpp
     +++ b/src/core/SkPath.cpp
     @@ -2082,6 +2082,7 @@ size_t SkPath::readFromMemory(const void* storage, size_t length) {
    @@ -208,7 +208,7 @@ index 320448a..9eb5cd1 100644
      #include "SkStream.h"
      
     diff --git a/src/core/SkStream.cpp b/src/core/SkStream.cpp
    -index 9529308..4f00768 100644
    +index 9529308e86..4f00768747 100644
     --- a/src/core/SkStream.cpp
     +++ b/src/core/SkStream.cpp
     @@ -180,105 +180,95 @@ bool SkWStream::writeStream(SkStream* stream, size_t length) {
    @@ -371,7 +371,7 @@ index 9529308..4f00768 100644
      
      ///////////////////////////////////////////////////////////////////////////////
     diff --git a/src/ports/SkOSFile_posix.cpp b/src/ports/SkOSFile_posix.cpp
    -index 396de68..48b5b95 100644
    +index 396de68bbe..48b5b95ad3 100644
     --- a/src/ports/SkOSFile_posix.cpp
     +++ b/src/ports/SkOSFile_posix.cpp
     @@ -95,6 +95,18 @@ void* sk_fmmap(FILE* f, size_t* size) {
    @@ -394,7 +394,7 @@ index 396de68..48b5b95 100644
      
      struct SkOSFileIterData {
     diff --git a/src/ports/SkOSFile_stdio.cpp b/src/ports/SkOSFile_stdio.cpp
    -index 915b87b..ee997e9 100644
    +index 915b87b67b..ee997e9db9 100644
     --- a/src/ports/SkOSFile_stdio.cpp
     +++ b/src/ports/SkOSFile_stdio.cpp
     @@ -80,15 +80,6 @@ FILE* sk_fopen(const char path[], SkFILE_Flags flags) {
    @@ -476,7 +476,7 @@ index 915b87b..ee997e9 100644
      
      bool sk_isdir(const char *path) {
     diff --git a/src/ports/SkOSFile_win.cpp b/src/ports/SkOSFile_win.cpp
    -index 6bdf9ab..414393a 100644
    +index 6bdf9ab163..414393a1d4 100644
     --- a/src/ports/SkOSFile_win.cpp
     +++ b/src/ports/SkOSFile_win.cpp
     @@ -124,6 +124,33 @@ void* sk_fmmap(FILE* f, size_t* length) {
    @@ -514,7 +514,7 @@ index 6bdf9ab..414393a 100644
      
      struct SkOSFileIterData {
     diff --git a/tests/BadIcoTest.cpp b/tests/BadIcoTest.cpp
    -index c387e15..f6b1c46 100644
    +index c387e157be..f6b1c469cc 100644
     --- a/tests/BadIcoTest.cpp
     +++ b/tests/BadIcoTest.cpp
     @@ -22,6 +22,7 @@ DEF_TEST(BadImage, reporter) {
    @@ -527,7 +527,7 @@ index c387e15..f6b1c46 100644
          const char* badImagesFolder = "invalid_images";
     diff --git a/tests/CodecTest.cpp b/tests/CodecTest.cpp
     new file mode 100644
    -index 0000000..6bb0f1b
    +index 0000000000..6bb0f1b2cb
     --- /dev/null
     +++ b/tests/CodecTest.cpp
     @@ -0,0 +1,1615 @@
    @@ -2147,7 +2147,7 @@ index 0000000..6bb0f1b
     +    test_info(r, codec.get(), codec->getInfo(), SkCodec::kInvalidInput, nullptr);
     +}
     diff --git a/tests/PathOpsExtendedTest.cpp b/tests/PathOpsExtendedTest.cpp
    -index c96cbcd..9e2dfbe 100644
    +index c96cbcdae5..9e2dfbe2ae 100644
     --- a/tests/PathOpsExtendedTest.cpp
     +++ b/tests/PathOpsExtendedTest.cpp
     @@ -595,7 +595,7 @@ void initializeTests(skiatest::Reporter* reporter, const char* test) {
    @@ -2160,7 +2160,7 @@ index c96cbcd..9e2dfbe 100644
                  if (insert) {
                      insert += sizeof(marker) - 1;
     diff --git a/tests/StreamTest.cpp b/tests/StreamTest.cpp
    -index a3df8d7..031cc1a 100644
    +index a3df8d71bb..031cc1a623 100644
     --- a/tests/StreamTest.cpp
     +++ b/tests/StreamTest.cpp
     @@ -67,7 +67,7 @@ static void test_filestreams(skiatest::Reporter* reporter, const char* tmpDir) {
    @@ -2173,7 +2173,7 @@ index a3df8d7..031cc1a 100644
              test_loop_stream(reporter, &stream, s, 26, 100);
      
     diff --git a/tools/chrome_fuzz.cpp b/tools/chrome_fuzz.cpp
    -index f49e126..ff14b5b 100644
    +index f49e12693b..ff14b5b307 100644
     --- a/tools/chrome_fuzz.cpp
     +++ b/tools/chrome_fuzz.cpp
     @@ -8,6 +8,8 @@
    diff --git a/external_wpa_supplicant_8.patch b/external_wpa_supplicant_8.patch
    index 47099b7..68fc032 100644
    --- a/external_wpa_supplicant_8.patch
    +++ b/external_wpa_supplicant_8.patch
    @@ -1145,10 +1145,11 @@ diff --git a/src/drivers/driver.h b/src/drivers/driver.h
     index b7e0d16..bae4777 100644
     --- a/src/drivers/driver.h
     +++ b/src/drivers/driver.h
    -@@ -3648,17 +3648,6 @@ enum wpa_event_type {
    +@@ -3647,17 +3647,6 @@ enum wpa_event_type {
    + 	 */
      	EVENT_PMKID_CANDIDATE,
      
    - 	/**
    +-	/**
     -	 * EVENT_STKSTART - Request STK handshake (MLME-STKSTART.request)
     -	 *
     -	 * This event can be used to inform wpa_supplicant about desire to set
    @@ -1159,24 +1160,23 @@ index b7e0d16..bae4777 100644
     -	 */
     -	EVENT_STKSTART,
     -
    --	/**
    + 	/**
      	 * EVENT_TDLS - Request TDLS operation
      	 *
    - 	 * This event can be used to request a TDLS operation to be performed.
    -@@ -4298,13 +4287,6 @@ union wpa_event_data {
    +@@ -4297,13 +4286,6 @@ union wpa_event_data {
    + 		int preauth;
      	} pmkid_candidate;
      
    - 	/**
    +-	/**
     -	 * struct stkstart - Data for EVENT_STKSTART
     -	 */
     -	struct stkstart {
     -		u8 peer[ETH_ALEN];
     -	} stkstart;
     -
    --	/**
    + 	/**
      	 * struct tdls - Data for EVENT_TDLS
      	 */
    - 	struct tdls {
     diff --git a/src/drivers/driver_common.c b/src/drivers/driver_common.c
     index b32d35f..7c35277 100644
     --- a/src/drivers/driver_common.c
    @@ -3471,10 +3471,11 @@ diff --git a/wpa_supplicant/config_ssid.h b/wpa_supplicant/config_ssid.h
     index eb7b87b..5b6f426 100644
     --- a/wpa_supplicant/config_ssid.h
     +++ b/wpa_supplicant/config_ssid.h
    -@@ -388,17 +388,6 @@ struct wpa_ssid {
    +@@ -387,17 +387,6 @@ struct wpa_ssid {
    + 	 */
      	int disabled_for_connect;
      
    - 	/**
    +-	/**
     -	 * peerkey -  Whether PeerKey handshake for direct links is allowed
     -	 *
     -	 * This is only used when both RSN/WPA2 and IEEE 802.11e (QoS) are
    @@ -3485,10 +3486,9 @@ index eb7b87b..5b6f426 100644
     -	 */
     -	int peerkey;
     -
    --	/**
    + 	/**
      	 * id_str - Network identifier string for external scripts
      	 *
    - 	 * This value is passed to external ctrl_iface monitors in
     diff --git a/wpa_supplicant/config_winreg.c b/wpa_supplicant/config_winreg.c
     index 199f04f..ca70474 100644
     --- a/wpa_supplicant/config_winreg.c
    diff --git a/frameworks_av.patch b/frameworks_av.patch
    index 498dbb3..cf50e4f 100644
    --- a/frameworks_av.patch
    +++ b/frameworks_av.patch
    @@ -1,5 +1,5 @@
     diff --git a/camera/ICameraClient.cpp b/camera/ICameraClient.cpp
    -index 68cbfb8..8a7430f 100644
    +index 68cbfb8e4..8a7430fd1 100644
     --- a/camera/ICameraClient.cpp
     +++ b/camera/ICameraClient.cpp
     @@ -50,7 +50,12 @@ public:
    @@ -34,7 +34,7 @@ index 68cbfb8..8a7430f 100644
                  return NO_ERROR;
              } break;
     diff --git a/camera/cameraserver/Android.mk b/camera/cameraserver/Android.mk
    -index 7e36c5e..aca7a19 100644
    +index 7e36c5e74..aca7a190c 100644
     --- a/camera/cameraserver/Android.mk
     +++ b/camera/cameraserver/Android.mk
     @@ -14,6 +14,9 @@
    @@ -53,7 +53,7 @@ index 7e36c5e..aca7a19 100644
      include $(BUILD_EXECUTABLE)
     +endif
     diff --git a/camera/cameraserver/main_cameraserver.cpp b/camera/cameraserver/main_cameraserver.cpp
    -index f4be468..ea80ad4 100644
    +index f4be468e4..ea80ad49d 100644
     --- a/camera/cameraserver/main_cameraserver.cpp
     +++ b/camera/cameraserver/main_cameraserver.cpp
     @@ -31,5 +31,6 @@ int main(int argc __unused, char** argv __unused)
    @@ -64,7 +64,7 @@ index f4be468..ea80ad4 100644
          IPCThreadState::self()->joinThreadPool();
      }
     diff --git a/camera/ndk/NdkCaptureRequest.cpp b/camera/ndk/NdkCaptureRequest.cpp
    -index 77b9a33..7c37955 100644
    +index 77b9a3390..7c3795502 100644
     --- a/camera/ndk/NdkCaptureRequest.cpp
     +++ b/camera/ndk/NdkCaptureRequest.cpp
     @@ -51,8 +51,13 @@ camera_status_t ACaptureRequest_addTarget(
    @@ -98,7 +98,7 @@ index 77b9a33..7c37955 100644
          }
          req->targets->mOutputs.erase(*target);
     diff --git a/cmds/stagefright/stagefright.cpp b/cmds/stagefright/stagefright.cpp
    -index ca68722..cd284f6 100644
    +index ca68722c5..cd284f697 100644
     --- a/cmds/stagefright/stagefright.cpp
     +++ b/cmds/stagefright/stagefright.cpp
     @@ -1037,6 +1037,10 @@ int main(int argc, char **argv) {
    @@ -124,7 +124,7 @@ index ca68722..cd284f6 100644
              }
      
     diff --git a/cmds/stagefright/stream.cpp b/cmds/stagefright/stream.cpp
    -index bca3832..cf59357 100644
    +index bca383211..cf593577f 100644
     --- a/cmds/stagefright/stream.cpp
     +++ b/cmds/stagefright/stream.cpp
     @@ -171,7 +171,8 @@ MyConvertingStreamSource::MyConvertingStreamSource(const char *filename)
    @@ -152,7 +152,7 @@ index bca3832..cf59357 100644
      
          CHECK_EQ(mWriter->start(), (status_t)OK);
     diff --git a/drm/mediadrm/plugins/clearkey/AesCtrDecryptor.cpp b/drm/mediadrm/plugins/clearkey/AesCtrDecryptor.cpp
    -index 01f8d65..f7106b2 100644
    +index 01f8d6570..f7106b275 100644
     --- a/drm/mediadrm/plugins/clearkey/AesCtrDecryptor.cpp
     +++ b/drm/mediadrm/plugins/clearkey/AesCtrDecryptor.cpp
     @@ -36,6 +36,11 @@ android::status_t AesCtrDecryptor::decrypt(const android::Vector<uint8_t>& key,
    @@ -168,7 +168,7 @@ index 01f8d65..f7106b2 100644
          AES_KEY opensslKey;
          AES_set_encrypt_key(key.array(), kBlockBitCount, &opensslKey);
     diff --git a/drm/mediadrm/plugins/clearkey/AesCtrDecryptor.h b/drm/mediadrm/plugins/clearkey/AesCtrDecryptor.h
    -index b416266..edb8445 100644
    +index b416266dd..edb84458a 100644
     --- a/drm/mediadrm/plugins/clearkey/AesCtrDecryptor.h
     +++ b/drm/mediadrm/plugins/clearkey/AesCtrDecryptor.h
     @@ -18,6 +18,7 @@
    @@ -180,7 +180,7 @@ index b416266..edb8445 100644
      #include <utils/Errors.h>
      #include <utils/Vector.h>
     diff --git a/drm/mediadrm/plugins/clearkey/tests/AesCtrDecryptorUnittest.cpp b/drm/mediadrm/plugins/clearkey/tests/AesCtrDecryptorUnittest.cpp
    -index 039e402..5db8290 100644
    +index 039e40226..5db8290a9 100644
     --- a/drm/mediadrm/plugins/clearkey/tests/AesCtrDecryptorUnittest.cpp
     +++ b/drm/mediadrm/plugins/clearkey/tests/AesCtrDecryptorUnittest.cpp
     @@ -34,7 +34,7 @@ class AesCtrDecryptorTest : public ::testing::Test {
    @@ -261,7 +261,7 @@ index 039e402..5db8290 100644
          const size_t kTotalSize = 64;
          const size_t kNumSubsamples = 1;
     diff --git a/include/media/IAudioPolicyService.h b/include/media/IAudioPolicyService.h
    -index 0e9e3bc..9ffcc77 100644
    +index 0e9e3bc89..9ffcc77f0 100644
     --- a/include/media/IAudioPolicyService.h
     +++ b/include/media/IAudioPolicyService.h
     @@ -181,6 +181,10 @@ public:
    @@ -276,7 +276,7 @@ index 0e9e3bc..9ffcc77 100644
      
      // ----------------------------------------------------------------------------
     diff --git a/include/media/IMediaExtractor.h b/include/media/IMediaExtractor.h
    -index 34b15e9..743ef7f 100644
    +index 34b15e928..743ef7f83 100644
     --- a/include/media/IMediaExtractor.h
     +++ b/include/media/IMediaExtractor.h
     @@ -30,6 +30,9 @@ public:
    @@ -290,7 +290,7 @@ index 34b15e9..743ef7f 100644
      
          enum GetTrackMetaDataFlags {
     diff --git a/include/media/MediaPlayerInterface.h b/include/media/MediaPlayerInterface.h
    -index 4977efd..c1bd8eb 100644
    +index 4977efd65..c1bd8eb3e 100644
     --- a/include/media/MediaPlayerInterface.h
     +++ b/include/media/MediaPlayerInterface.h
     @@ -65,14 +65,17 @@ enum player_type {
    @@ -365,7 +365,7 @@ index 4977efd..c1bd8eb 100644
      
      // Implement this class for media players that use the AudioFlinger software mixer
     diff --git a/include/media/stagefright/MediaBufferGroup.h b/include/media/stagefright/MediaBufferGroup.h
    -index 3051406..870bb9b 100644
    +index 30514062d..870bb9b9d 100644
     --- a/include/media/stagefright/MediaBufferGroup.h
     +++ b/include/media/stagefright/MediaBufferGroup.h
     @@ -49,7 +49,10 @@ public:
    @@ -381,7 +381,7 @@ index 3051406..870bb9b 100644
          size_t buffers() const { return mBuffers.size(); }
      
     diff --git a/media/libeffects/downmix/EffectDownmix.c b/media/libeffects/downmix/EffectDownmix.c
    -index 9823c55..cb4be75 100644
    +index 9823c5516..cb4be7503 100644
     --- a/media/libeffects/downmix/EffectDownmix.c
     +++ b/media/libeffects/downmix/EffectDownmix.c
     @@ -445,6 +445,10 @@ static int Downmix_Command(effect_handle_t self, uint32_t cmdCode, uint32_t cmdS
    @@ -396,7 +396,7 @@ index 9823c55..cb4be75 100644
                      cmd->vsize, cmd->data + sizeof(int32_t));
              break;
     diff --git a/media/libeffects/lvm/wrapper/Bundle/EffectBundle.cpp b/media/libeffects/lvm/wrapper/Bundle/EffectBundle.cpp
    -index dcf3fa0..07ea818 100644
    +index dcf3fa0a5..07ea8187c 100644
     --- a/media/libeffects/lvm/wrapper/Bundle/EffectBundle.cpp
     +++ b/media/libeffects/lvm/wrapper/Bundle/EffectBundle.cpp
     @@ -2439,6 +2439,13 @@ int Equalizer_getParameter(EffectContext     *pContext,
    @@ -414,7 +414,7 @@ index dcf3fa0..07ea818 100644
              strncpy(name, EqualizerGetPresetName(param2), *pValueSize - 1);
              name[*pValueSize - 1] = 0;
     diff --git a/media/libeffects/lvm/wrapper/Reverb/EffectReverb.cpp b/media/libeffects/lvm/wrapper/Reverb/EffectReverb.cpp
    -index 4dc8b45..80c8a38 100644
    +index 4dc8b4592..80c8a3878 100644
     --- a/media/libeffects/lvm/wrapper/Reverb/EffectReverb.cpp
     +++ b/media/libeffects/lvm/wrapper/Reverb/EffectReverb.cpp
     @@ -180,12 +180,13 @@ int  Reverb_init            (ReverbContext *pContext);
    @@ -513,7 +513,7 @@ index 4dc8b45..80c8a38 100644
      
              case EFFECT_CMD_ENABLE:
     diff --git a/media/libmedia/IAudioPolicyService.cpp b/media/libmedia/IAudioPolicyService.cpp
    -index 6405d6d..be826ab 100644
    +index 6405d6de5..be826abda 100644
     --- a/media/libmedia/IAudioPolicyService.cpp
     +++ b/media/libmedia/IAudioPolicyService.cpp
     @@ -873,7 +873,7 @@ status_t BnAudioPolicyService::onTransact(
    @@ -685,7 +685,7 @@ index 6405d6d..be826ab 100644
      
      } // namespace android
     diff --git a/media/libmedia/IDataSource.cpp b/media/libmedia/IDataSource.cpp
    -index 51c9938..5ad39fe 100644
    +index 51c9938f6..5ad39fe81 100644
     --- a/media/libmedia/IDataSource.cpp
     +++ b/media/libmedia/IDataSource.cpp
     @@ -54,8 +54,16 @@ struct BpDataSource : public BpInterface<IDataSource> {
    @@ -708,7 +708,7 @@ index 51c9938..5ad39fe 100644
      
          virtual status_t getSize(off64_t* size) {
     diff --git a/media/libmedia/IDrm.cpp b/media/libmedia/IDrm.cpp
    -index 51a1130..393286d 100644
    +index 51a113031..393286dcf 100644
     --- a/media/libmedia/IDrm.cpp
     +++ b/media/libmedia/IDrm.cpp
     @@ -559,8 +559,13 @@ IMPLEMENT_META_INTERFACE(Drm, "android.drm.IDrm");
    @@ -728,7 +728,7 @@ index 51a1130..393286d 100644
      
      void BnDrm::writeVector(Parcel *reply, Vector<uint8_t> const &vector) const {
     diff --git a/media/libmedia/IMediaExtractor.cpp b/media/libmedia/IMediaExtractor.cpp
    -index 72d1d7c..4be1118 100644
    +index 72d1d7c57..4be111813 100644
     --- a/media/libmedia/IMediaExtractor.cpp
     +++ b/media/libmedia/IMediaExtractor.cpp
     @@ -209,11 +209,16 @@ String8 ExtractorInstance::toString() const {
    @@ -769,7 +769,7 @@ index 72d1d7c..4be1118 100644
              }
          }
     diff --git a/media/libmediaplayerservice/MediaPlayerFactory.cpp b/media/libmediaplayerservice/MediaPlayerFactory.cpp
    -index 605c710..f5ec20c 100644
    +index 605c71014..f5ec20c38 100644
     --- a/media/libmediaplayerservice/MediaPlayerFactory.cpp
     +++ b/media/libmediaplayerservice/MediaPlayerFactory.cpp
     @@ -127,8 +127,7 @@ player_type MediaPlayerFactory::getPlayerType(const sp<IMediaPlayer>& client,
    @@ -792,7 +792,7 @@ index 605c710..f5ec20c 100644
              ALOGE("Failed to create player object of type %d, initCheck failed"
                    " (res = %d)", playerType, init_result);
     diff --git a/media/libmediaplayerservice/MediaPlayerFactory.h b/media/libmediaplayerservice/MediaPlayerFactory.h
    -index e22a56f..e88700c 100644
    +index e22a56fe6..e88700cf5 100644
     --- a/media/libmediaplayerservice/MediaPlayerFactory.h
     +++ b/media/libmediaplayerservice/MediaPlayerFactory.h
     @@ -65,8 +65,7 @@ class MediaPlayerFactory {
    @@ -806,7 +806,7 @@ index e22a56f..e88700c 100644
      
          static void registerBuiltinFactories();
     diff --git a/media/libmediaplayerservice/MediaPlayerService.cpp b/media/libmediaplayerservice/MediaPlayerService.cpp
    -index bd16e91..7196f42 100644
    +index bd16e91e3..7196f420f 100644
     --- a/media/libmediaplayerservice/MediaPlayerService.cpp
     +++ b/media/libmediaplayerservice/MediaPlayerService.cpp
     @@ -82,6 +82,9 @@
    @@ -1016,7 +1016,7 @@ index bd16e91..7196f42 100644
              usleep(interval);
          }
     diff --git a/media/libmediaplayerservice/MediaPlayerService.h b/media/libmediaplayerservice/MediaPlayerService.h
    -index 7a41d9c..99b1d4d 100644
    +index 7a41d9cfe..99b1d4dfa 100644
     --- a/media/libmediaplayerservice/MediaPlayerService.h
     +++ b/media/libmediaplayerservice/MediaPlayerService.h
     @@ -49,7 +49,7 @@ class MediaRecorderClient;
    @@ -1130,7 +1130,7 @@ index 7a41d9c..99b1d4d 100644
          }; // Client
      
     diff --git a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp
    -index dc4e5d4..b64d899 100644
    +index dc4e5d4a3..b64d899b1 100644
     --- a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp
     +++ b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp
     @@ -1534,6 +1534,7 @@ void NuPlayer::restartAudio(
    @@ -1153,7 +1153,7 @@ index dc4e5d4..b64d899 100644
      
      void NuPlayer::determineAudioModeChange(const sp<AMessage> &audioFormat) {
     diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp b/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp
    -index 594128c..caaa735 100644
    +index 594128c83..caaa7356b 100644
     --- a/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp
     +++ b/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp
     @@ -631,6 +631,11 @@ bool NuPlayer::Decoder::handleAnOutputBuffer(
    @@ -1169,7 +1169,7 @@ index 594128c..caaa735 100644
              for (size_t i = mOutputBuffers.size(); i <= index; ++i) {
                  mOutputBuffers.add();
     diff --git a/media/libstagefright/AACExtractor.cpp b/media/libstagefright/AACExtractor.cpp
    -index 7449aa7..3ba1858 100644
    +index 7449aa7d9..3ba18586b 100644
     --- a/media/libstagefright/AACExtractor.cpp
     +++ b/media/libstagefright/AACExtractor.cpp
     @@ -294,6 +294,10 @@ status_t AACSource::read(
    @@ -1184,7 +1184,7 @@ index 7449aa7..3ba1858 100644
      
                  mOffset = mOffsetVector.itemAt(seekFrame);
     diff --git a/media/libstagefright/ACodec.cpp b/media/libstagefright/ACodec.cpp
    -index 37fd5a5..337fb2d 100644
    +index 37fd5a51e..337fb2de5 100644
     --- a/media/libstagefright/ACodec.cpp
     +++ b/media/libstagefright/ACodec.cpp
     @@ -804,13 +804,22 @@ status_t ACodec::allocateBuffersOnPort(OMX_U32 portIndex) {
    @@ -1344,7 +1344,7 @@ index 37fd5a5..337fb2d 100644
      
          if (err == OK) {
     diff --git a/media/libstagefright/Android.mk b/media/libstagefright/Android.mk
    -index 3848502..07f926c 100644
    +index 38485021e..07f926c77 100644
     --- a/media/libstagefright/Android.mk
     +++ b/media/libstagefright/Android.mk
     @@ -102,6 +102,10 @@ LOCAL_SHARED_LIBRARIES := \
    @@ -1381,7 +1381,7 @@ index 3848502..07f926c 100644
      LOCAL_SANITIZE := unsigned-integer-overflow signed-integer-overflow
      
     diff --git a/media/libstagefright/CameraSource.cpp b/media/libstagefright/CameraSource.cpp
    -index 893da89..2152454 100644
    +index 893da89bb..215245472 100644
     --- a/media/libstagefright/CameraSource.cpp
     +++ b/media/libstagefright/CameraSource.cpp
     @@ -950,6 +950,14 @@ void CameraSource::releaseRecordingFrame(const sp<IMemory>& frame) {
    @@ -1420,7 +1420,7 @@ index 893da89..2152454 100644
          // buffer queue.
          switch (mVideoBufferMode) {
     diff --git a/media/libstagefright/MPEG4Extractor.cpp b/media/libstagefright/MPEG4Extractor.cpp
    -index 5441714..d1603c1 100644
    +index 544171496..d1603c1ef 100644
     --- a/media/libstagefright/MPEG4Extractor.cpp
     +++ b/media/libstagefright/MPEG4Extractor.cpp
     @@ -72,6 +72,7 @@ public:
    @@ -1683,7 +1683,7 @@ index 5441714..d1603c1 100644
              }
          }
     diff --git a/media/libstagefright/MPEG4Writer.cpp b/media/libstagefright/MPEG4Writer.cpp
    -index 5e96c2b..6ca2abb 100644
    +index 5e96c2b25..6ca2abb93 100644
     --- a/media/libstagefright/MPEG4Writer.cpp
     +++ b/media/libstagefright/MPEG4Writer.cpp
     @@ -1674,10 +1674,12 @@ void MPEG4Writer::Track::getCodecSpecificDataFromInputFormatIfPossible() {
    @@ -1703,7 +1703,7 @@ index 5e96c2b..6ca2abb 100644
          }
          if (data != NULL && copyCodecSpecificData((uint8_t *)data, size) == OK) {
     diff --git a/media/libstagefright/MediaCodecList.cpp b/media/libstagefright/MediaCodecList.cpp
    -index 0fb5072..a25c47d 100644
    +index 0fb5072a4..a25c47d12 100644
     --- a/media/libstagefright/MediaCodecList.cpp
     +++ b/media/libstagefright/MediaCodecList.cpp
     @@ -1165,7 +1165,9 @@ void MediaCodecList::findMatchingCodecs(
    @@ -1718,7 +1718,7 @@ index 0fb5072..a25c47d 100644
                  ALOGV("matching '%s'", componentName.c_str());
              }
     diff --git a/media/libstagefright/MediaSource.cpp b/media/libstagefright/MediaSource.cpp
    -index a17757a..f1ad5c5 100644
    +index a17757a8e..f1ad5c573 100644
     --- a/media/libstagefright/MediaSource.cpp
     +++ b/media/libstagefright/MediaSource.cpp
     @@ -22,4 +22,10 @@ MediaSource::MediaSource() {}
    @@ -1733,7 +1733,7 @@ index a17757a..f1ad5c5 100644
     +}
      }  // namespace android
     diff --git a/media/libstagefright/NuMediaExtractor.cpp b/media/libstagefright/NuMediaExtractor.cpp
    -index 4558b3c..c3e8f20 100644
    +index 4558b3c1c..c3e8f2047 100644
     --- a/media/libstagefright/NuMediaExtractor.cpp
     +++ b/media/libstagefright/NuMediaExtractor.cpp
     @@ -305,6 +305,10 @@ status_t NuMediaExtractor::selectTrack(size_t index) {
    @@ -1748,7 +1748,7 @@ index 4558b3c..c3e8f20 100644
          if (ret != OK) {
              return ret;
     diff --git a/media/libstagefright/OggExtractor.cpp b/media/libstagefright/OggExtractor.cpp
    -index ebbe510..752f2fe 100644
    +index ebbe5102e..752f2fe20 100644
     --- a/media/libstagefright/OggExtractor.cpp
     +++ b/media/libstagefright/OggExtractor.cpp
     @@ -578,6 +578,10 @@ status_t MyOpusExtractor::readNextPacket(MediaBuffer **out) {
    @@ -1763,7 +1763,7 @@ index ebbe510..752f2fe 100644
                  }
                  curGranulePosition = mCurrentPage.mGranulePosition;
     diff --git a/media/libstagefright/SampleTable.cpp b/media/libstagefright/SampleTable.cpp
    -index ee5fdf0..597896b 100644
    +index ee5fdf041..597896b28 100644
     --- a/media/libstagefright/SampleTable.cpp
     +++ b/media/libstagefright/SampleTable.cpp
     @@ -517,6 +517,8 @@ status_t SampleTable::setSyncSampleParams(off64_t data_offset, size_t data_size)
    @@ -1790,7 +1790,7 @@ index ee5fdf0..597896b 100644
      }  // namespace android
     -
     diff --git a/media/libstagefright/StagefrightMetadataRetriever.cpp b/media/libstagefright/StagefrightMetadataRetriever.cpp
    -index be5067d..2fef7ca 100644
    +index be5067d59..2fef7caeb 100644
     --- a/media/libstagefright/StagefrightMetadataRetriever.cpp
     +++ b/media/libstagefright/StagefrightMetadataRetriever.cpp
     @@ -483,6 +483,10 @@ VideoFrame *StagefrightMetadataRetriever::getFrameAtTime(
    @@ -1826,7 +1826,7 @@ index be5067d..2fef7ca 100644
              int64_t durationUs;
              if (trackMeta->findInt64(kKeyDuration, &durationUs)) {
     diff --git a/media/libstagefright/SurfaceMediaSource.cpp b/media/libstagefright/SurfaceMediaSource.cpp
    -index 15ff569..547267c 100644
    +index 15ff5697d..547267ce0 100644
     --- a/media/libstagefright/SurfaceMediaSource.cpp
     +++ b/media/libstagefright/SurfaceMediaSource.cpp
     @@ -129,7 +129,11 @@ status_t SurfaceMediaSource::setFrameRate(int32_t fps)
    @@ -1916,7 +1916,7 @@ index 15ff569..547267c 100644
                          mSlots[id].mGraphicBuffer->handle);
      
     diff --git a/media/libstagefright/VideoFrameScheduler.cpp b/media/libstagefright/VideoFrameScheduler.cpp
    -index 03226c7..6819bba 100644
    +index 03226c753..6819bba40 100644
     --- a/media/libstagefright/VideoFrameScheduler.cpp
     +++ b/media/libstagefright/VideoFrameScheduler.cpp
     @@ -129,6 +129,11 @@ bool VideoFrameScheduler::PLL::fit(
    @@ -1932,7 +1932,7 @@ index 03226c7..6819bba 100644
          int64_t sumXX = 0;
          int64_t sumXY = 0;
     diff --git a/media/libstagefright/avc_utils.cpp b/media/libstagefright/avc_utils.cpp
    -index 763381e..78aae8c 100644
    +index 763381e1c..78aae8cc2 100644
     --- a/media/libstagefright/avc_utils.cpp
     +++ b/media/libstagefright/avc_utils.cpp
     @@ -330,7 +330,7 @@ static sp<ABuffer> FindNAL(const uint8_t *data, size_t size, unsigned nalType) {
    @@ -1957,7 +1957,7 @@ index 763381e..78aae8c 100644
              unsigned nalType = nalStart[0] & 0x1f;
      
     diff --git a/media/libstagefright/codecs/aacenc/SoftAACEncoder2.cpp b/media/libstagefright/codecs/aacenc/SoftAACEncoder2.cpp
    -index f00a5d1..44415e2 100644
    +index f00a5d1b0..44415e2e0 100644
     --- a/media/libstagefright/codecs/aacenc/SoftAACEncoder2.cpp
     +++ b/media/libstagefright/codecs/aacenc/SoftAACEncoder2.cpp
     @@ -16,6 +16,7 @@
    @@ -2001,7 +2001,7 @@ index f00a5d1..44415e2 100644
          mSentCodecSpecificData = false;
          mInputTimeUs = -1ll;
     diff --git a/media/libstagefright/codecs/aacenc/SoftAACEncoder2.h b/media/libstagefright/codecs/aacenc/SoftAACEncoder2.h
    -index f1b81e1..123fd25 100644
    +index f1b81e18f..123fd253f 100644
     --- a/media/libstagefright/codecs/aacenc/SoftAACEncoder2.h
     +++ b/media/libstagefright/codecs/aacenc/SoftAACEncoder2.h
     @@ -62,6 +62,7 @@ private:
    @@ -2013,7 +2013,7 @@ index f1b81e1..123fd25 100644
      
          bool mSawInputEOS;
     diff --git a/media/libstagefright/codecs/avcdec/SoftAVCDec.cpp b/media/libstagefright/codecs/avcdec/SoftAVCDec.cpp
    -index cecc52b..43ef4a4 100644
    +index cecc52bb1..43ef4a455 100644
     --- a/media/libstagefright/codecs/avcdec/SoftAVCDec.cpp
     +++ b/media/libstagefright/codecs/avcdec/SoftAVCDec.cpp
     @@ -318,10 +318,6 @@ status_t SoftAVC::initDecoder() {
    @@ -2048,7 +2048,7 @@ index cecc52b..43ef4a4 100644
      
                      mReceivedEOS = true;
     diff --git a/media/libstagefright/codecs/avcenc/SoftAVCEnc.cpp b/media/libstagefright/codecs/avcenc/SoftAVCEnc.cpp
    -index 5b06722..7bfa051 100644
    +index 5b06722fb..7bfa051ce 100644
     --- a/media/libstagefright/codecs/avcenc/SoftAVCEnc.cpp
     +++ b/media/libstagefright/codecs/avcenc/SoftAVCEnc.cpp
     @@ -1191,6 +1191,12 @@ OMX_ERRORTYPE SoftAVC::setEncodeArgs(
    @@ -2065,7 +2065,7 @@ index 5b06722..7bfa051 100644
      
              if (mInputDataIsMeta) {
     diff --git a/media/libstagefright/codecs/hevcdec/SoftHEVC.cpp b/media/libstagefright/codecs/hevcdec/SoftHEVC.cpp
    -index 5c70387..194a078 100644
    +index 5c70387f4..194a078e1 100644
     --- a/media/libstagefright/codecs/hevcdec/SoftHEVC.cpp
     +++ b/media/libstagefright/codecs/hevcdec/SoftHEVC.cpp
     @@ -320,10 +320,6 @@ status_t SoftHEVC::initDecoder() {
    @@ -2091,7 +2091,7 @@ index 5c70387..194a078 100644
      
          /* Reset the plugin state */
     diff --git a/media/libstagefright/codecs/m4v_h263/dec/src/vlc_decode.cpp b/media/libstagefright/codecs/m4v_h263/dec/src/vlc_decode.cpp
    -index f7192b1c..7202f98 100644
    +index f7192b1c0..7202f982e 100644
     --- a/media/libstagefright/codecs/m4v_h263/dec/src/vlc_decode.cpp
     +++ b/media/libstagefright/codecs/m4v_h263/dec/src/vlc_decode.cpp
     @@ -560,7 +560,7 @@ int PV_VlcDecMCBPC_com_inter_H263(BitstreamDecVideo *stream)
    @@ -2104,7 +2104,7 @@ index f7192b1c..7202f98 100644
              return VLC_CODE_ERROR;
          }
     diff --git a/media/libstagefright/codecs/m4v_h263/enc/SoftMPEG4Encoder.cpp b/media/libstagefright/codecs/m4v_h263/enc/SoftMPEG4Encoder.cpp
    -index d5a26d3..7d2131d 100644
    +index d5a26d372..7d2131df0 100644
     --- a/media/libstagefright/codecs/m4v_h263/enc/SoftMPEG4Encoder.cpp
     +++ b/media/libstagefright/codecs/m4v_h263/enc/SoftMPEG4Encoder.cpp
     @@ -437,6 +437,14 @@ void SoftMPEG4Encoder::onQueueFilled(OMX_U32 /* portIndex */) {
    @@ -2123,7 +2123,7 @@ index d5a26d3..7d2131d 100644
                  if (mInputDataIsMeta) {
                      inputData =
     diff --git a/media/libstagefright/codecs/mp3dec/src/pvmp3_decode_header.cpp b/media/libstagefright/codecs/mp3dec/src/pvmp3_decode_header.cpp
    -index d443b7c..bc5fd79 100644
    +index d443b7ccf..bc5fd7952 100644
     --- a/media/libstagefright/codecs/mp3dec/src/pvmp3_decode_header.cpp
     +++ b/media/libstagefright/codecs/mp3dec/src/pvmp3_decode_header.cpp
     @@ -184,7 +184,7 @@ ERROR_CODE pvmp3_decode_header(tmp3Bits  *inputStream,
    @@ -2136,7 +2136,7 @@ index d443b7c..bc5fd79 100644
              err = UNSUPPORTED_FREE_BITRATE;
          }
     diff --git a/media/libstagefright/codecs/mpeg2dec/SoftMPEG2.cpp b/media/libstagefright/codecs/mpeg2dec/SoftMPEG2.cpp
    -index 5ed037a..7297f40 100644
    +index 5ed037ac7..7297f40fe 100644
     --- a/media/libstagefright/codecs/mpeg2dec/SoftMPEG2.cpp
     +++ b/media/libstagefright/codecs/mpeg2dec/SoftMPEG2.cpp
     @@ -68,6 +68,7 @@ SoftMPEG2::SoftMPEG2(
    @@ -2277,7 +2277,7 @@ index 5ed037a..7297f40 100644
                      mTimeStampsValid[timeStampIdx] = false;
      
     diff --git a/media/libstagefright/codecs/mpeg2dec/SoftMPEG2.h b/media/libstagefright/codecs/mpeg2dec/SoftMPEG2.h
    -index 700ef5f..1285c5b 100644
    +index 700ef5f36..1285c5be4 100644
     --- a/media/libstagefright/codecs/mpeg2dec/SoftMPEG2.h
     +++ b/media/libstagefright/codecs/mpeg2dec/SoftMPEG2.h
     @@ -106,6 +106,7 @@ private:
    @@ -2289,7 +2289,7 @@ index 700ef5f..1285c5b 100644
          size_t mStride;
      
     diff --git a/media/libstagefright/codecs/on2/enc/SoftVPXEncoder.cpp b/media/libstagefright/codecs/on2/enc/SoftVPXEncoder.cpp
    -index 56e1f77..04d8dda 100644
    +index 56e1f7734..04d8dda07 100644
     --- a/media/libstagefright/codecs/on2/enc/SoftVPXEncoder.cpp
     +++ b/media/libstagefright/codecs/on2/enc/SoftVPXEncoder.cpp
     @@ -731,6 +731,13 @@ void SoftVPXEncoder::onQueueFilled(OMX_U32 /* portIndex */) {
    @@ -2322,7 +2322,7 @@ index 56e1f77..04d8dda 100644
                      ConvertYUV420SemiPlanarToYUV420Planar(
                              source, mConversionBuffer, mWidth, mHeight);
     diff --git a/media/libstagefright/foundation/MediaBuffer.cpp b/media/libstagefright/foundation/MediaBuffer.cpp
    -index 16000ef..82b989c 100644
    +index 16000ef5c..82b989c9e 100644
     --- a/media/libstagefright/foundation/MediaBuffer.cpp
     +++ b/media/libstagefright/foundation/MediaBuffer.cpp
     @@ -155,6 +155,7 @@ size_t MediaBuffer::range_length() const {
    @@ -2334,7 +2334,7 @@ index 16000ef..82b989c 100644
          CHECK((mGraphicBuffer != NULL) || (offset + length <= mSize));
      
     diff --git a/media/libstagefright/foundation/MediaBufferGroup.cpp b/media/libstagefright/foundation/MediaBufferGroup.cpp
    -index 8e4d064..66992d7 100644
    +index 8e4d0641c..66992d72b 100644
     --- a/media/libstagefright/foundation/MediaBufferGroup.cpp
     +++ b/media/libstagefright/foundation/MediaBufferGroup.cpp
     @@ -105,6 +105,11 @@ MediaBufferGroup::~MediaBufferGroup() {
    @@ -2367,7 +2367,7 @@ index 8e4d064..66992d7 100644
          mCondition.signal();
      }
     diff --git a/media/libstagefright/foundation/base64.cpp b/media/libstagefright/foundation/base64.cpp
    -index 7da7db9..cc89064 100644
    +index 7da7db941..cc8906406 100644
     --- a/media/libstagefright/foundation/base64.cpp
     +++ b/media/libstagefright/foundation/base64.cpp
     @@ -78,8 +78,7 @@ sp<ABuffer> decodeBase64(const AString &s) {
    @@ -2381,7 +2381,7 @@ index 7da7db9..cc89064 100644
                  if (j < outLen) { out[j++] = accum & 0xff; }
      
     diff --git a/media/libstagefright/httplive/LiveSession.cpp b/media/libstagefright/httplive/LiveSession.cpp
    -index 7abc019..590146d 100644
    +index 7abc0197a..590146db9 100644
     --- a/media/libstagefright/httplive/LiveSession.cpp
     +++ b/media/libstagefright/httplive/LiveSession.cpp
     @@ -157,6 +157,11 @@ bool LiveSession::BandwidthEstimator::estimateBandwidth(
    @@ -2397,7 +2397,7 @@ index 7abc019..590146d 100644
          while (mPrevEstimates.size() > 3) {
              mPrevEstimates.erase(mPrevEstimates.begin());
     diff --git a/media/libstagefright/httplive/M3UParser.cpp b/media/libstagefright/httplive/M3UParser.cpp
    -index c04549a..a092a1b 100644
    +index c04549ab0..a092a1bdc 100644
     --- a/media/libstagefright/httplive/M3UParser.cpp
     +++ b/media/libstagefright/httplive/M3UParser.cpp
     @@ -56,7 +56,7 @@ struct M3UParser::MediaGroup : public RefBase {
    @@ -2536,7 +2536,7 @@ index c04549a..a092a1b 100644
                  haveGroupURI = true;
              }
     diff --git a/media/libstagefright/httplive/M3UParser.h b/media/libstagefright/httplive/M3UParser.h
    -index fa648ed..c85335a 100644
    +index fa648ed7d..c85335abc 100644
     --- a/media/libstagefright/httplive/M3UParser.h
     +++ b/media/libstagefright/httplive/M3UParser.h
     @@ -64,6 +64,7 @@ private:
    @@ -2548,7 +2548,7 @@ index fa648ed..c85335a 100644
      
          status_t mInitCheck;
     diff --git a/media/libstagefright/id3/ID3.cpp b/media/libstagefright/id3/ID3.cpp
    -index 8b80ae9..0791ee9 100644
    +index 8b80ae949..0791ee9a2 100644
     --- a/media/libstagefright/id3/ID3.cpp
     +++ b/media/libstagefright/id3/ID3.cpp
     @@ -328,12 +328,24 @@ struct id3_header {
    @@ -2595,7 +2595,7 @@ index 8b80ae9..0791ee9 100644
                  // move the remaining data following this frame
                  if (readOffset <= oldSize) {
     diff --git a/media/libstagefright/include/OMXNodeInstance.h b/media/libstagefright/include/OMXNodeInstance.h
    -index 94cf15a..dd396e8 100644
    +index 94cf15abd..dd396e812 100644
     --- a/media/libstagefright/include/OMXNodeInstance.h
     +++ b/media/libstagefright/include/OMXNodeInstance.h
     @@ -175,7 +175,7 @@ private:
    @@ -2616,7 +2616,7 @@ index 94cf15a..dd396e8 100644
          // For debug support
          char *mName;
     diff --git a/media/libstagefright/include/SoftVideoEncoderOMXComponent.h b/media/libstagefright/include/SoftVideoEncoderOMXComponent.h
    -index b43635d..02555a2 100644
    +index b43635deb..02555a2f3 100644
     --- a/media/libstagefright/include/SoftVideoEncoderOMXComponent.h
     +++ b/media/libstagefright/include/SoftVideoEncoderOMXComponent.h
     @@ -68,6 +68,8 @@ protected:
    @@ -2629,7 +2629,7 @@ index b43635d..02555a2 100644
              kInputPortIndex = 0,
              kOutputPortIndex = 1,
     diff --git a/media/libstagefright/mpeg2ts/ESQueue.cpp b/media/libstagefright/mpeg2ts/ESQueue.cpp
    -index 96ca405..c454a0e 100644
    +index 96ca40509..c454a0e49 100644
     --- a/media/libstagefright/mpeg2ts/ESQueue.cpp
     +++ b/media/libstagefright/mpeg2ts/ESQueue.cpp
     @@ -716,6 +716,11 @@ sp<ABuffer> ElementaryStreamQueue::dequeueAccessUnitAAC() {
    @@ -2675,7 +2675,7 @@ index 96ca405..c454a0e 100644
                      break;
                  }
     diff --git a/media/libstagefright/omx/Android.mk b/media/libstagefright/omx/Android.mk
    -index e4fbd81..8fc788f 100644
    +index e4fbd815c..8fc788f4b 100644
     --- a/media/libstagefright/omx/Android.mk
     +++ b/media/libstagefright/omx/Android.mk
     @@ -31,6 +31,12 @@ LOCAL_SHARED_LIBRARIES :=               \
    @@ -2692,7 +2692,7 @@ index e4fbd81..8fc788f 100644
      LOCAL_CFLAGS += -Werror -Wall
      LOCAL_CLANG := true
     diff --git a/media/libstagefright/omx/GraphicBufferSource.cpp b/media/libstagefright/omx/GraphicBufferSource.cpp
    -index e1bcd28..5f21eac 100644
    +index e1bcd285b..5f21eacfd 100644
     --- a/media/libstagefright/omx/GraphicBufferSource.cpp
     +++ b/media/libstagefright/omx/GraphicBufferSource.cpp
     @@ -736,6 +736,8 @@ bool GraphicBufferSource::repeatLatestBuffer_l() {
    @@ -2705,7 +2705,7 @@ index e1bcd28..5f21eac 100644
              if (mBufferUseCount[mLatestBufferId] == 0) {
                  releaseBuffer(mLatestBufferId, mLatestBufferFrameNum,
     diff --git a/media/libstagefright/omx/OMXMaster.cpp b/media/libstagefright/omx/OMXMaster.cpp
    -index 6132a2c..7f0d270 100644
    +index 6132a2cf7..7f0d27008 100644
     --- a/media/libstagefright/omx/OMXMaster.cpp
     +++ b/media/libstagefright/omx/OMXMaster.cpp
     @@ -69,6 +69,7 @@ OMXMaster::~OMXMaster() {
    @@ -2717,7 +2717,7 @@ index 6132a2c..7f0d270 100644
      
      void OMXMaster::addPlugin(const char *libname) {
     diff --git a/media/libstagefright/omx/OMXNodeInstance.cpp b/media/libstagefright/omx/OMXNodeInstance.cpp
    -index e7aaead..18778f7 100644
    +index e7aaeadf9..18778f7a6 100644
     --- a/media/libstagefright/omx/OMXNodeInstance.cpp
     +++ b/media/libstagefright/omx/OMXNodeInstance.cpp
     @@ -226,6 +226,8 @@ OMXNodeInstance::OMXNodeInstance(
    @@ -2887,7 +2887,7 @@ index e7aaead..18778f7 100644
          } else {
              // rangeLength and rangeOffset must be a subset of the allocated data in the buffer.
     diff --git a/media/libstagefright/omx/SimpleSoftOMXComponent.cpp b/media/libstagefright/omx/SimpleSoftOMXComponent.cpp
    -index 7c975f7..76cbbc4 100644
    +index 7c975f7b5..76cbbc45d 100644
     --- a/media/libstagefright/omx/SimpleSoftOMXComponent.cpp
     +++ b/media/libstagefright/omx/SimpleSoftOMXComponent.cpp
     @@ -199,6 +199,13 @@ OMX_ERRORTYPE SimpleSoftOMXComponent::useBuffer(
    @@ -2914,7 +2914,7 @@ index 7c975f7..76cbbc4 100644
      
          CHECK_LT(port->mBuffers.size(), port->mDef.nBufferCountActual);
     diff --git a/media/libstagefright/omx/SoftVideoEncoderOMXComponent.cpp b/media/libstagefright/omx/SoftVideoEncoderOMXComponent.cpp
    -index 0f9c118..9d302dd 100644
    +index 0f9c11869..9d302ddbd 100644
     --- a/media/libstagefright/omx/SoftVideoEncoderOMXComponent.cpp
     +++ b/media/libstagefright/omx/SoftVideoEncoderOMXComponent.cpp
     @@ -656,4 +656,17 @@ OMX_ERRORTYPE SoftVideoEncoderOMXComponent::getExtensionIndex(
    @@ -2936,7 +2936,7 @@ index 0f9c118..9d302dd 100644
     +
      }  // namespace android
     diff --git a/media/mediaserver/Android.mk b/media/mediaserver/Android.mk
    -index 1738df8..c2b9c1f 100644
    +index 1738df80d..c2b9c1f95 100644
     --- a/media/mediaserver/Android.mk
     +++ b/media/mediaserver/Android.mk
     @@ -42,4 +42,8 @@ LOCAL_INIT_RC := mediaserver.rc
    @@ -2949,7 +2949,7 @@ index 1738df8..c2b9c1f 100644
     +
      include $(BUILD_EXECUTABLE)
     diff --git a/media/mediaserver/main_mediaserver.cpp b/media/mediaserver/main_mediaserver.cpp
    -index ecddc48..0abe6ac 100644
    +index ecddc4827..0abe6ac95 100644
     --- a/media/mediaserver/main_mediaserver.cpp
     +++ b/media/mediaserver/main_mediaserver.cpp
     @@ -25,6 +25,9 @@
    @@ -2973,7 +2973,7 @@ index ecddc48..0abe6ac 100644
          ProcessState::self()->startThreadPool();
          IPCThreadState::self()->joinThreadPool();
     diff --git a/media/mtp/MtpServer.cpp b/media/mtp/MtpServer.cpp
    -index e39dcdd..65a2415 100644
    +index e39dcddb7..65a241527 100644
     --- a/media/mtp/MtpServer.cpp
     +++ b/media/mtp/MtpServer.cpp
     @@ -136,20 +136,9 @@ void MtpServer::removeStorage(MtpStorage* storage) {
    @@ -3042,7 +3042,7 @@ index e39dcdd..65a2415 100644
          if (!storage)
              return MTP_RESPONSE_INVALID_STORAGE_ID;
     diff --git a/media/mtp/MtpServer.h b/media/mtp/MtpServer.h
    -index b3a11e0..cd543c8 100644
    +index b3a11e0a5..cd543c859 100644
     --- a/media/mtp/MtpServer.h
     +++ b/media/mtp/MtpServer.h
     @@ -95,8 +95,6 @@ public:
    @@ -3066,7 +3066,7 @@ index b3a11e0..cd543c8 100644
          void                sendStoreRemoved(MtpStorageID id);
          void                sendEvent(MtpEventCode code, uint32_t param1);
     diff --git a/services/audioflinger/AudioFlinger.cpp b/services/audioflinger/AudioFlinger.cpp
    -index fec3a57..4aad2c2 100644
    +index fec3a57c1..4aad2c219 100644
     --- a/services/audioflinger/AudioFlinger.cpp
     +++ b/services/audioflinger/AudioFlinger.cpp
     @@ -1509,7 +1509,8 @@ sp<IAudioRecord> AudioFlinger::openRecord(
    @@ -3080,7 +3080,7 @@ index fec3a57..4aad2c2 100644
              lStatus = PERMISSION_DENIED;
              goto Exit;
     diff --git a/services/audioflinger/Effects.cpp b/services/audioflinger/Effects.cpp
    -index f908d6d..b588685 100644
    +index f908d6df3..b58868598 100644
     --- a/services/audioflinger/Effects.cpp
     +++ b/services/audioflinger/Effects.cpp
     @@ -1309,6 +1309,24 @@ status_t AudioFlinger::EffectHandle::command(uint32_t cmdCode,
    @@ -3109,7 +3109,7 @@ index f908d6d..b588685 100644
              if (*replySize < sizeof(int)) {
                  android_errorWriteLog(0x534e4554, "32095713");
     diff --git a/services/audioflinger/Threads.cpp b/services/audioflinger/Threads.cpp
    -index 7423ea9..1bc9516 100644
    +index 7423ea9ae..1bc9516c4 100644
     --- a/services/audioflinger/Threads.cpp
     +++ b/services/audioflinger/Threads.cpp
     @@ -1412,6 +1412,7 @@ sp<AudioFlinger::EffectHandle> AudioFlinger::ThreadBase::createEffect_l(
    @@ -3151,7 +3151,7 @@ index 7423ea9..1bc9516 100644
              if (chainCreated) {
                  removeEffectChain_l(chain);
     diff --git a/services/audioflinger/Tracks.cpp b/services/audioflinger/Tracks.cpp
    -index f18b88d..a3f3ea5 100644
    +index f18b88d72..a3f3ea5cf 100644
     --- a/services/audioflinger/Tracks.cpp
     +++ b/services/audioflinger/Tracks.cpp
     @@ -141,9 +141,11 @@ AudioFlinger::ThreadBase::TrackBase::TrackBase(
    @@ -3205,7 +3205,7 @@ index f18b88d..a3f3ea5 100644
                      mFrameSize);
          }
     diff --git a/services/audiopolicy/common/managerdefinitions/src/AudioPort.cpp b/services/audiopolicy/common/managerdefinitions/src/AudioPort.cpp
    -index 17ed537..ce9bdc2 100644
    +index 17ed537fc..ce9bdc212 100644
     --- a/services/audiopolicy/common/managerdefinitions/src/AudioPort.cpp
     +++ b/services/audiopolicy/common/managerdefinitions/src/AudioPort.cpp
     @@ -384,6 +384,7 @@ AudioPortConfig::AudioPortConfig()
    @@ -3217,7 +3217,7 @@ index 17ed537..ce9bdc2 100644
      }
      
     diff --git a/services/audiopolicy/common/managerdefinitions/src/Serializer.cpp b/services/audiopolicy/common/managerdefinitions/src/Serializer.cpp
    -index 3e5bb7d..2ecd6b1 100644
    +index 3e5bb7d3e..2ecd6b179 100644
     --- a/services/audiopolicy/common/managerdefinitions/src/Serializer.cpp
     +++ b/services/audiopolicy/common/managerdefinitions/src/Serializer.cpp
     @@ -383,6 +383,7 @@ status_t RouteTraits::deserialize(_xmlDoc */*doc*/, const _xmlNode *root, PtrEle
    @@ -3229,7 +3229,7 @@ index 3e5bb7d..2ecd6b1 100644
                  }
                  sources.add(source);
     diff --git a/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp b/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp
    -index a75e3dd..cf81d9a 100644
    +index a75e3ddcc..cf81d9abb 100644
     --- a/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp
     +++ b/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp
     @@ -318,7 +318,7 @@ status_t AudioPolicyService::getInputForAttr(const audio_attributes_t *attr,
    @@ -3258,7 +3258,7 @@ index a75e3dd..cf81d9a 100644
              return NO_INIT;
          }
     diff --git a/services/camera/libcameraservice/Android.mk b/services/camera/libcameraservice/Android.mk
    -index 8d7f71c..d98ad47 100644
    +index 8d7f71cef..d98ad470e 100644
     --- a/services/camera/libcameraservice/Android.mk
     +++ b/services/camera/libcameraservice/Android.mk
     @@ -80,6 +80,10 @@ LOCAL_EXPORT_C_INCLUDE_DIRS := \
    @@ -3273,7 +3273,7 @@ index 8d7f71c..d98ad47 100644
      
      include $(BUILD_SHARED_LIBRARY)
     diff --git a/services/camera/libcameraservice/CameraService.cpp b/services/camera/libcameraservice/CameraService.cpp
    -index 6124fed..de7ea03 100644
    +index 6124fedde..de7ea037f 100644
     --- a/services/camera/libcameraservice/CameraService.cpp
     +++ b/services/camera/libcameraservice/CameraService.cpp
     @@ -273,7 +273,10 @@ void CameraService::onFirstRef()
    @@ -3312,7 +3312,7 @@ index 6124fed..de7ea03 100644
                  return true;
              default:
     diff --git a/services/camera/libcameraservice/api1/CameraClient.cpp b/services/camera/libcameraservice/api1/CameraClient.cpp
    -index 266fb03..3c2b98a 100644
    +index 266fb03d4..3c2b98a85 100644
     --- a/services/camera/libcameraservice/api1/CameraClient.cpp
     +++ b/services/camera/libcameraservice/api1/CameraClient.cpp
     @@ -520,6 +520,9 @@ void CameraClient::releaseRecordingFrameHandle(native_handle_t *handle) {
    @@ -3326,7 +3326,7 @@ index 266fb03..3c2b98a 100644
      
      status_t CameraClient::setVideoBufferMode(int32_t videoBufferMode) {
     diff --git a/services/soundtrigger/SoundTriggerHwService.cpp b/services/soundtrigger/SoundTriggerHwService.cpp
    -index eebc487..9d98a30 100644
    +index eebc48705..9d98a3039 100644
     --- a/services/soundtrigger/SoundTriggerHwService.cpp
     +++ b/services/soundtrigger/SoundTriggerHwService.cpp
     @@ -278,6 +278,37 @@ void SoundTriggerHwService::sendRecognitionEvent(struct sound_trigger_recognitio
    @@ -3502,7 +3502,7 @@ index eebc487..9d98a30 100644
      
      status_t SoundTriggerHwService::Module::startRecognition(sound_model_handle_t handle,
     diff --git a/services/soundtrigger/SoundTriggerHwService.h b/services/soundtrigger/SoundTriggerHwService.h
    -index 2619a5f..d05dacd 100644
    +index 2619a5fb4..d05dacdb7 100644
     --- a/services/soundtrigger/SoundTriggerHwService.h
     +++ b/services/soundtrigger/SoundTriggerHwService.h
     @@ -141,9 +141,6 @@ public:
    diff --git a/frameworks_base.patch b/frameworks_base.patch
    index c371418..d5d2baf 100644
    --- a/frameworks_base.patch
    +++ b/frameworks_base.patch
    @@ -1,5 +1,5 @@
     diff --git a/api/system-current.txt b/api/system-current.txt
    -index 0fe164a..6b6f7e9 100644
    +index 0fe164a269c..6b6f7e99e4b 100644
     --- a/api/system-current.txt
     +++ b/api/system-current.txt
     @@ -112,6 +112,7 @@ package android {
    @@ -11,7 +11,7 @@ index 0fe164a..6b6f7e9 100644
          field public static final java.lang.String INSTALL_GRANT_RUNTIME_PERMISSIONS = "android.permission.INSTALL_GRANT_RUNTIME_PERMISSIONS";
          field public static final java.lang.String INSTALL_LOCATION_PROVIDER = "android.permission.INSTALL_LOCATION_PROVIDER";
     diff --git a/core/java/android/accounts/ChooseTypeAndAccountActivity.java b/core/java/android/accounts/ChooseTypeAndAccountActivity.java
    -index aed7a36..bf96926 100644
    +index aed7a369371..bf969266257 100644
     --- a/core/java/android/accounts/ChooseTypeAndAccountActivity.java
     +++ b/core/java/android/accounts/ChooseTypeAndAccountActivity.java
     @@ -250,6 +250,10 @@ public class ChooseTypeAndAccountActivity extends Activity
    @@ -37,7 +37,7 @@ index aed7a36..bf96926 100644
                  // finish this activity
                  if (mAccounts.isEmpty()) {
     diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
    -index 5cfcac3..010b871 100644
    +index 5cfcac33050..010b871c1d4 100644
     --- a/core/java/android/app/ActivityThread.java
     +++ b/core/java/android/app/ActivityThread.java
     @@ -911,7 +911,8 @@ public final class ActivityThread {
    @@ -51,7 +51,7 @@ index 5cfcac3..010b871 100644
                  if (network != null) {
                      Proxy.setHttpProxySystemProperty(cm.getDefaultProxy());
     diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java
    -index 0dd9c63..bcdf3f4 100644
    +index 0dd9c63c40c..bcdf3f49251 100644
     --- a/core/java/android/app/Notification.java
     +++ b/core/java/android/app/Notification.java
     @@ -1761,7 +1761,9 @@ public class Notification implements Parcelable
    @@ -88,7 +88,7 @@ index 0dd9c63..bcdf3f4 100644
                  return this;
              }
     diff --git a/core/java/android/app/ResourcesManager.java b/core/java/android/app/ResourcesManager.java
    -index 5cc064e..4916c1c 100644
    +index 5cc064e5d17..4916c1c1f5c 100644
     --- a/core/java/android/app/ResourcesManager.java
     +++ b/core/java/android/app/ResourcesManager.java
     @@ -826,7 +826,8 @@ public class ResourcesManager {
    @@ -113,7 +113,7 @@ index 5cc064e..4916c1c 100644
                          if (!ArrayUtils.contains(key.mLibDirs, libAsset)) {
                              final int newLibAssetCount = 1 +
     diff --git a/core/java/android/bluetooth/BluetoothDevice.java b/core/java/android/bluetooth/BluetoothDevice.java
    -index cd5eff2..d329175 100644
    +index cd5eff29237..d329175646e 100644
     --- a/core/java/android/bluetooth/BluetoothDevice.java
     +++ b/core/java/android/bluetooth/BluetoothDevice.java
     @@ -727,7 +727,11 @@ public final class BluetoothDevice implements Parcelable {
    @@ -131,7 +131,7 @@ index cd5eff2..d329175 100644
          }
     diff --git a/core/java/android/content/PermissionChecker.java b/core/java/android/content/PermissionChecker.java
     new file mode 100644
    -index 0000000..a4b2fe0
    +index 00000000000..a4b2fe0c10e
     --- /dev/null
     +++ b/core/java/android/content/PermissionChecker.java
     @@ -0,0 +1,157 @@
    @@ -293,7 +293,7 @@ index 0000000..a4b2fe0
     +    }
     +}
     diff --git a/core/java/android/content/pm/RegisteredServicesCache.java b/core/java/android/content/pm/RegisteredServicesCache.java
    -index a110383..aea843a 100644
    +index a1103838280..aea843adbd4 100644
     --- a/core/java/android/content/pm/RegisteredServicesCache.java
     +++ b/core/java/android/content/pm/RegisteredServicesCache.java
     @@ -390,15 +390,17 @@ public abstract class RegisteredServicesCache<V> {
    @@ -323,7 +323,7 @@ index a110383..aea843a 100644
              }
              return false;
     diff --git a/core/java/android/hardware/location/NanoAppFilter.java b/core/java/android/hardware/location/NanoAppFilter.java
    -index bf35a3d..c440949 100644
    +index bf35a3d6fbd..c44094908f3 100644
     --- a/core/java/android/hardware/location/NanoAppFilter.java
     +++ b/core/java/android/hardware/location/NanoAppFilter.java
     @@ -83,7 +83,7 @@ public class NanoAppFilter {
    @@ -344,7 +344,7 @@ index bf35a3d..c440949 100644
              out.writeInt(mAppVersion);
              out.writeInt(mVersionRestrictionMask);
     diff --git a/core/java/android/net/Uri.java b/core/java/android/net/Uri.java
    -index 09af05c..6c069be 100644
    +index 09af05c0dfb..6c069be07e3 100644
     --- a/core/java/android/net/Uri.java
     +++ b/core/java/android/net/Uri.java
     @@ -719,6 +719,10 @@ public abstract class Uri implements Parcelable, Comparable<Uri> {
    @@ -397,7 +397,7 @@ index 09af05c..6c069be 100644
      
                  if (portSeparator == NOT_FOUND) {
     diff --git a/core/java/android/provider/MediaStore.java b/core/java/android/provider/MediaStore.java
    -index de19f81..b17657b 100644
    +index de19f819295..b17657b43db 100644
     --- a/core/java/android/provider/MediaStore.java
     +++ b/core/java/android/provider/MediaStore.java
     @@ -678,8 +678,8 @@ public final class MediaStore {
    @@ -412,24 +412,24 @@ index de19f81..b17657b 100644
                  try {
                      long magic = thumbFile.getMagic(origId);
     diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
    -index a8209af..4766d33 100755
    +index a8209af6aa2..4766d33846d 100755
     --- a/core/java/android/provider/Settings.java
     +++ b/core/java/android/provider/Settings.java
    -@@ -3559,6 +3559,12 @@ public final class Settings {
    +@@ -3558,6 +3558,12 @@ public final class Settings {
    +         /** @hide */
              public static final Validator LOCK_TO_APP_ENABLED_VALIDATOR = sBooleanValidator;
      
    -         /**
    ++        /**
     +         * Whether to wake the screen with the home key, the value is boolean.
     +         * @hide
     +         */
     +        public static final String HOME_WAKE_SCREEN = "home_wake_screen";
     +
    -+        /**
    +         /**
               * I am the lolrus.
               * <p>
    -          * Nonzero values indicate that the user has a bukkit.
     diff --git a/core/java/android/service/gatekeeper/GateKeeperResponse.java b/core/java/android/service/gatekeeper/GateKeeperResponse.java
    -index a512957..6ca6d8a 100644
    +index a512957d604..6ca6d8ac710 100644
     --- a/core/java/android/service/gatekeeper/GateKeeperResponse.java
     +++ b/core/java/android/service/gatekeeper/GateKeeperResponse.java
     @@ -85,6 +85,8 @@ public final class GateKeeperResponse implements Parcelable {
    @@ -442,7 +442,7 @@ index a512957..6ca6d8a 100644
              }
          }
     diff --git a/core/java/android/speech/RecognitionService.java b/core/java/android/speech/RecognitionService.java
    -index 674f809..70dfef5 100644
    +index 674f809ef0f..70dfef574ca 100644
     --- a/core/java/android/speech/RecognitionService.java
     +++ b/core/java/android/speech/RecognitionService.java
     @@ -20,7 +20,7 @@ import android.annotation.SdkConstant;
    @@ -466,7 +466,7 @@ index 674f809..70dfef5 100644
              }
              try {
     diff --git a/core/java/android/view/WindowManager.java b/core/java/android/view/WindowManager.java
    -index 395f738..169f7e1 100644
    +index 395f73844b0..169f7e170dd 100644
     --- a/core/java/android/view/WindowManager.java
     +++ b/core/java/android/view/WindowManager.java
     @@ -655,6 +655,25 @@ public interface WindowManager extends ViewManager {
    @@ -495,10 +495,11 @@ index 395f738..169f7e1 100644
              /** @deprecated this is ignored, this value is set automatically when needed. */
              @Deprecated
              public static final int MEMORY_TYPE_NORMAL = 0;
    -@@ -1263,6 +1282,15 @@ public interface WindowManager extends ViewManager {
    +@@ -1262,6 +1281,15 @@ public interface WindowManager extends ViewManager {
    +          */
              public static final int PRIVATE_FLAG_SUSTAINED_PERFORMANCE_MODE = 0x00040000;
      
    -         /**
    ++        /**
     +         * Flag to indicate that any window added by an application process that is of type
     +         * {@link #TYPE_TOAST} or that requires
     +         * {@link android.app.AppOpsManager#OP_SYSTEM_ALERT_WINDOW} permission should be hidden when
    @@ -507,30 +508,29 @@ index 395f738..169f7e1 100644
     +         */
     +        public static final int PRIVATE_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS = 0x00080000;
     +
    -+        /**
    +         /**
               * Control flags that are private to the platform.
               * @hide
    -          */
     diff --git a/core/java/android/view/WindowManagerPolicy.java b/core/java/android/view/WindowManagerPolicy.java
    -index 46a0194..ecc9025 100644
    +index 46a0194b1b0..ecc9025774a 100644
     --- a/core/java/android/view/WindowManagerPolicy.java
     +++ b/core/java/android/view/WindowManagerPolicy.java
    -@@ -1100,6 +1100,13 @@ public interface WindowManagerPolicy {
    +@@ -1099,6 +1099,13 @@ public interface WindowManagerPolicy {
    +      */
          public void notifyCameraLensCoverSwitchChanged(long whenNanos, boolean lensCovered);
      
    -     /**
    ++    /**
     +     * Tell the policy that the rotation lock switch has changed state.
     +     * @param whenNanos The time when the change occurred in uptime nanoseconds.
     +     * @param isLocked True if the rotation is now locked.
     +     */
     +    public void notifyRotateLockSwitchChanged(long whenNanos, boolean isLocked);
     +
    -+    /**
    +     /**
           * Tell the policy if anyone is requesting that keyguard not come on.
           *
    -      * @param enabled Whether keyguard can be on or not.  does not actually
     diff --git a/core/java/com/android/internal/app/ChooserActivity.java b/core/java/com/android/internal/app/ChooserActivity.java
    -index a5b2a91..cdf83d3 100644
    +index a5b2a9194fd..cdf83d3f728 100644
     --- a/core/java/com/android/internal/app/ChooserActivity.java
     +++ b/core/java/com/android/internal/app/ChooserActivity.java
     @@ -83,7 +83,7 @@ public class ChooserActivity extends ResolverActivity {
    @@ -554,7 +554,7 @@ index a5b2a91..cdf83d3 100644
              private final List<ChooserTargetInfo> mServiceTargets = new ArrayList<>();
              private final List<TargetInfo> mCallerTargets = new ArrayList<>();
     diff --git a/core/java/com/android/internal/app/procstats/ProcessState.java b/core/java/com/android/internal/app/procstats/ProcessState.java
    -index 8c5df08..8c2c236 100644
    +index 8c5df08f549..8c2c2362f99 100644
     --- a/core/java/com/android/internal/app/procstats/ProcessState.java
     +++ b/core/java/com/android/internal/app/procstats/ProcessState.java
     @@ -379,7 +379,7 @@ public final class ProcessState {
    @@ -567,7 +567,7 @@ index 8c5df08..8c2c236 100644
                  commitStateTime(now);
                  mCurState = state;
     diff --git a/core/java/com/android/internal/app/procstats/SparseMappingTable.java b/core/java/com/android/internal/app/procstats/SparseMappingTable.java
    -index f941836..6d79d3b 100644
    +index f941836d2c0..6d79d3bd32a 100644
     --- a/core/java/com/android/internal/app/procstats/SparseMappingTable.java
     +++ b/core/java/com/android/internal/app/procstats/SparseMappingTable.java
     @@ -18,6 +18,7 @@ package com.android.internal.app.procstats;
    @@ -592,7 +592,7 @@ index f941836..6d79d3b 100644
      
          /**
     diff --git a/core/java/com/android/internal/os/ZygoteInit.java b/core/java/com/android/internal/os/ZygoteInit.java
    -index e4f573b..0d3f50c 100644
    +index e4f573b7b8a..0d3f50cb93b 100644
     --- a/core/java/com/android/internal/os/ZygoteInit.java
     +++ b/core/java/com/android/internal/os/ZygoteInit.java
     @@ -245,8 +245,8 @@ public class ZygoteInit {
    @@ -607,7 +607,7 @@ index e4f573b..0d3f50c 100644
              }
          }
     diff --git a/core/java/com/android/internal/widget/VerifyCredentialResponse.java b/core/java/com/android/internal/widget/VerifyCredentialResponse.java
    -index 48109ca..c4d91e0 100644
    +index 48109ca347a..c4d91e021af 100644
     --- a/core/java/com/android/internal/widget/VerifyCredentialResponse.java
     +++ b/core/java/com/android/internal/widget/VerifyCredentialResponse.java
     @@ -95,6 +95,8 @@ public final class VerifyCredentialResponse implements Parcelable {
    @@ -620,7 +620,7 @@ index 48109ca..c4d91e0 100644
              }
          }
     diff --git a/core/java/com/android/internal/widget/ViewPager.java b/core/java/com/android/internal/widget/ViewPager.java
    -index d5b6def..df1ed7d 100644
    +index d5b6def9742..df1ed7d392b 100644
     --- a/core/java/com/android/internal/widget/ViewPager.java
     +++ b/core/java/com/android/internal/widget/ViewPager.java
     @@ -31,6 +31,7 @@ import android.os.Parcelable;
    @@ -676,7 +676,7 @@ index d5b6def..df1ed7d 100644
                      loader = getClass().getClassLoader();
                  }
     diff --git a/core/jni/android/graphics/BitmapFactory.cpp b/core/jni/android/graphics/BitmapFactory.cpp
    -index 4001283..0a14361 100644
    +index 4001283c4c6..0a143610ebd 100644
     --- a/core/jni/android/graphics/BitmapFactory.cpp
     +++ b/core/jni/android/graphics/BitmapFactory.cpp
     @@ -587,8 +587,7 @@ static jobject nativeDecodeFileDescriptor(JNIEnv* env, jobject clazz, jobject fi
    @@ -690,7 +690,7 @@ index 4001283..0a14361 100644
          // If there is no offset for the file descriptor, we use SkFILEStream directly.
          if (::lseek(descriptor, 0, SEEK_CUR) == 0) {
     diff --git a/core/jni/android_util_Binder.cpp b/core/jni/android_util_Binder.cpp
    -index 5559d48..bee11db 100644
    +index 5559d48a58b..bee11dbe600 100644
     --- a/core/jni/android_util_Binder.cpp
     +++ b/core/jni/android_util_Binder.cpp
     @@ -132,6 +132,14 @@ static struct strict_mode_callback_offsets_t
    @@ -757,7 +757,7 @@ index 5559d48..bee11db 100644
          return 0;
      }
     diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
    -index 011884c..8403e80 100644
    +index 011884cb549..8403e80ae31 100644
     --- a/core/res/AndroidManifest.xml
     +++ b/core/res/AndroidManifest.xml
     @@ -1223,6 +1223,13 @@
    @@ -792,7 +792,7 @@ index 011884c..8403e80 100644
               <p>Not for use by third-party applications.
     diff --git a/core/res/res/values-mcc310-mnc490-fr/strings.xml b/core/res/res/values-mcc310-mnc490-fr/strings.xml
     deleted file mode 100644
    -index 33e0c97..0000000
    +index 33e0c97b2fb..00000000000
     --- a/core/res/res/values-mcc310-mnc490-fr/strings.xml
     +++ /dev/null
     @@ -1,32 +0,0 @@
    @@ -829,7 +829,7 @@ index 33e0c97..0000000
     -    <string name="wfcSpnFormat" msgid="1518868466785799436">"Appels Wi-Fi %s"</string>
     -</resources>
     diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
    -index 7baed78..a0fbdac 100644
    +index 7baed78a51b..a0fbdac7360 100644
     --- a/core/res/res/values/config.xml
     +++ b/core/res/res/values/config.xml
     @@ -2710,4 +2710,6 @@
    @@ -840,7 +840,7 @@ index 7baed78..a0fbdac 100644
     +    <bool name="config_HICEnabledDefault">true</bool>
      </resources>
     diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
    -index 08ac043..9e6f3b8 100644
    +index 08ac0436d63..9e6f3b8b83f 100644
     --- a/core/res/res/values/symbols.xml
     +++ b/core/res/res/values/symbols.xml
     @@ -2749,4 +2749,7 @@
    @@ -852,7 +852,7 @@ index 08ac043..9e6f3b8 100644
     +  <java-symbol type="bool" name="config_HICEnabledDefault" />
      </resources>
     diff --git a/core/res/res/xml/config_webview_packages.xml b/core/res/res/xml/config_webview_packages.xml
    -index f062b59..574f7c1 100644
    +index f062b59a008..574f7c15fc2 100644
     --- a/core/res/res/xml/config_webview_packages.xml
     +++ b/core/res/res/xml/config_webview_packages.xml
     @@ -15,7 +15,22 @@
    @@ -881,7 +881,7 @@ index f062b59..574f7c1 100644
     +    <webviewprovider description="AOSP WebView" packageName="com.android.webview" availableByDefault="true" isFallback="true" />
      </webviewproviders>
     diff --git a/core/tests/coretests/src/android/net/UriTest.java b/core/tests/coretests/src/android/net/UriTest.java
    -index 6fa28b1..ea0347d 100644
    +index 6fa28b1ccda..ea0347d67ad 100644
     --- a/core/tests/coretests/src/android/net/UriTest.java
     +++ b/core/tests/coretests/src/android/net/UriTest.java
     @@ -187,6 +187,17 @@ public class UriTest extends TestCase {
    @@ -903,7 +903,7 @@ index 6fa28b1..ea0347d 100644
      
          @SmallTest
     diff --git a/libs/androidfw/ResourceTypes.cpp b/libs/androidfw/ResourceTypes.cpp
    -index ceeb12b..d9efe2b 100644
    +index ceeb12bab20..d9efe2b6739 100644
     --- a/libs/androidfw/ResourceTypes.cpp
     +++ b/libs/androidfw/ResourceTypes.cpp
     @@ -457,6 +457,22 @@ status_t ResStringPool::setTo(const void* data, size_t size, bool copyData)
    @@ -957,7 +957,7 @@ index ceeb12b..d9efe2b 100644
                          return (mError=err);
                      }
     diff --git a/libs/hwui/Android.mk b/libs/hwui/Android.mk
    -index cacfce1..0b177b9 100644
    +index cacfce16ab9..0b177b96430 100644
     --- a/libs/hwui/Android.mk
     +++ b/libs/hwui/Android.mk
     @@ -149,7 +149,7 @@ endif
    @@ -970,7 +970,7 @@ index cacfce1..0b177b9 100644
      
      # This has to be lazy-resolved because it depends on the LOCAL_MODULE_CLASS
     diff --git a/libs/hwui/Snapshot.cpp b/libs/hwui/Snapshot.cpp
    -index 2c9c9d9..7c187fb 100644
    +index 2c9c9d90f68..7c187fbda45 100644
     --- a/libs/hwui/Snapshot.cpp
     +++ b/libs/hwui/Snapshot.cpp
     @@ -38,6 +38,7 @@ Snapshot::Snapshot()
    @@ -982,7 +982,7 @@ index 2c9c9d9..7c187fb 100644
      
      /**
     diff --git a/media/java/android/media/MediaPlayer.java b/media/java/android/media/MediaPlayer.java
    -index e5f7527..679a27e 100644
    +index e5f7527c9db..679a27e9f42 100644
     --- a/media/java/android/media/MediaPlayer.java
     +++ b/media/java/android/media/MediaPlayer.java
     @@ -2025,10 +2025,10 @@ public class MediaPlayer extends PlayerBase
    @@ -998,7 +998,7 @@ index e5f7527..679a27e 100644
                      dest.writeInt(mFormat.getInteger(MediaFormat.KEY_IS_DEFAULT));
                      dest.writeInt(mFormat.getInteger(MediaFormat.KEY_IS_FORCED_SUBTITLE));
     diff --git a/media/java/android/media/MediaScanner.java b/media/java/android/media/MediaScanner.java
    -index 0fafe4b..4c113d9 100644
    +index 0fafe4b19a4..4c113d946d1 100644
     --- a/media/java/android/media/MediaScanner.java
     +++ b/media/java/android/media/MediaScanner.java
     @@ -323,7 +323,6 @@ public class MediaScanner implements AutoCloseable {
    @@ -1082,7 +1082,7 @@ index 0fafe4b..4c113d9 100644
              mPlayLists.clear();
          }
     diff --git a/media/java/android/media/MiniThumbFile.java b/media/java/android/media/MiniThumbFile.java
    -index 664308c..4f9dc68 100644
    +index 664308c45bf..4f9dc6817ad 100644
     --- a/media/java/android/media/MiniThumbFile.java
     +++ b/media/java/android/media/MiniThumbFile.java
     @@ -51,6 +51,7 @@ public class MiniThumbFile {
    @@ -1161,7 +1161,7 @@ index 664308c..4f9dc68 100644
                  throws IOException {
              RandomAccessFile r = miniThumbDataFile();
     diff --git a/media/jni/android_media_ExifInterface.cpp b/media/jni/android_media_ExifInterface.cpp
    -index 731deae..20f9ef6 100644
    +index 731deae1460..20f9ef6d6a4 100644
     --- a/media/jni/android_media_ExifInterface.cpp
     +++ b/media/jni/android_media_ExifInterface.cpp
     @@ -390,8 +390,7 @@ static jobject ExifInterface_getRawAttributesFromFileDescriptor(
    @@ -1175,7 +1175,7 @@ index 731deae..20f9ef6 100644
      }
      
     diff --git a/media/jni/android_mtp_MtpDatabase.cpp b/media/jni/android_mtp_MtpDatabase.cpp
    -index 7217832..feff102 100644
    +index 7217832bac6..feff102850f 100644
     --- a/media/jni/android_mtp_MtpDatabase.cpp
     +++ b/media/jni/android_mtp_MtpDatabase.cpp
     @@ -948,6 +948,7 @@ void* MyMtpDatabase::getThumbnail(MtpObjectHandle handle, size_t& outThumbSize)
    @@ -1187,7 +1187,7 @@ index 7217832..feff102 100644
                      }
                      break;
     diff --git a/packages/SystemUI/res/values/config.xml b/packages/SystemUI/res/values/config.xml
    -index 0fa9a85..925f368 100644
    +index 0fa9a85f412..925f3681c73 100644
     --- a/packages/SystemUI/res/values/config.xml
     +++ b/packages/SystemUI/res/values/config.xml
     @@ -105,7 +105,7 @@
    @@ -1200,7 +1200,7 @@ index 0fa9a85..925f368 100644
      
          <!-- The tiles to display in QuickSettings -->
     diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
    -index 4a51329..aa6b3e0 100644
    +index 4a51329215e..aa6b3e0435c 100644
     --- a/packages/SystemUI/res/values/strings.xml
     +++ b/packages/SystemUI/res/values/strings.xml
     @@ -1700,5 +1700,9 @@
    @@ -1215,7 +1215,7 @@ index 4a51329..aa6b3e0 100644
     +        can’t verify your response.</string>
      </resources>
     diff --git a/packages/SystemUI/src/com/android/systemui/classifier/HumanInteractionClassifier.java b/packages/SystemUI/src/com/android/systemui/classifier/HumanInteractionClassifier.java
    -index 851ab77..a384641 100644
    +index 851ab771882..a384641e16d 100644
     --- a/packages/SystemUI/src/com/android/systemui/classifier/HumanInteractionClassifier.java
     +++ b/packages/SystemUI/src/com/android/systemui/classifier/HumanInteractionClassifier.java
     @@ -36,9 +36,6 @@ public class HumanInteractionClassifier extends Classifier {
    @@ -1242,7 +1242,7 @@ index 851ab77..a384641 100644
      
          public void setType(int type) {
     diff --git a/packages/SystemUI/src/com/android/systemui/settings/CurrentUserTracker.java b/packages/SystemUI/src/com/android/systemui/settings/CurrentUserTracker.java
    -index dd80750..005206f 100644
    +index dd8075057e1..005206fcd14 100644
     --- a/packages/SystemUI/src/com/android/systemui/settings/CurrentUserTracker.java
     +++ b/packages/SystemUI/src/com/android/systemui/settings/CurrentUserTracker.java
     @@ -22,39 +22,93 @@ import android.content.Context;
    @@ -1360,7 +1360,7 @@ index dd80750..005206f 100644
     +    }
      }
     diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
    -index 9d22b4a..7639b3d 100644
    +index 9d22b4a9f28..7639b3d32aa 100644
     --- a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
     +++ b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
     @@ -2679,4 +2679,23 @@ public abstract class BaseStatusBar extends SystemUI implements
    @@ -1388,7 +1388,7 @@ index 9d22b4a..7639b3d 100644
     +    }
      }
     diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationGuts.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationGuts.java
    -index 63d2891..1829e59 100644
    +index 63d28910393..1829e592546 100644
     --- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationGuts.java
     +++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationGuts.java
     @@ -235,7 +235,7 @@ public class NotificationGuts extends LinearLayout implements TunerService.Tunab
    @@ -1401,7 +1401,7 @@ index 63d2891..1829e59 100644
                      return mSeekBar.getProgress();
                  } else {
     diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java
    -index 4d0e5d3..c674a82 100644
    +index 4d0e5d34761..c674a82d609 100644
     --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java
     +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java
     @@ -305,7 +305,10 @@ public class KeyguardBottomAreaView extends FrameLayout implements View.OnClickL
    @@ -1442,7 +1442,7 @@ index 4d0e5d3..c674a82 100644
              final IntentFilter filter = new IntentFilter();
              filter.addAction(DevicePolicyManager.ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED);
     diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
    -index 9c700b4..ca08ab1 100644
    +index 9c700b4280e..ca08ab15e65 100644
     --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
     +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
     @@ -31,6 +31,7 @@ import android.graphics.Paint;
    @@ -1465,7 +1465,7 @@ index 9c700b4..ca08ab1 100644
              String packageToLaunch = (resolveInfo == null || resolveInfo.activityInfo == null)
                      ? null : resolveInfo.activityInfo.packageName;
     diff --git a/packages/SystemUI/src/com/android/systemui/tuner/TunerFragment.java b/packages/SystemUI/src/com/android/systemui/tuner/TunerFragment.java
    -index 70f2fdc..ba50161 100644
    +index 70f2fdcfa8d..ba50161aae9 100644
     --- a/packages/SystemUI/src/com/android/systemui/tuner/TunerFragment.java
     +++ b/packages/SystemUI/src/com/android/systemui/tuner/TunerFragment.java
     @@ -59,7 +59,10 @@ public class TunerFragment extends PreferenceFragment {
    @@ -1481,7 +1481,7 @@ index 70f2fdc..ba50161 100644
      
          @Override
     diff --git a/services/core/java/com/android/server/AppOpsService.java b/services/core/java/com/android/server/AppOpsService.java
    -index 4caeba8..c95b9d5 100644
    +index 4caeba84b20..c95b9d52ad8 100644
     --- a/services/core/java/com/android/server/AppOpsService.java
     +++ b/services/core/java/com/android/server/AppOpsService.java
     @@ -597,7 +597,6 @@ public class AppOpsService extends IAppOpsService.Stub {
    @@ -1547,7 +1547,7 @@ index 4caeba8..c95b9d5 100644
                              out.startTag(null, "uid");
                              out.attribute(null, "n", Integer.toString(uidState.uid));
     diff --git a/services/core/java/com/android/server/BluetoothManagerService.java b/services/core/java/com/android/server/BluetoothManagerService.java
    -index 2a6f9d2..7ba1fe4 100644
    +index 2a6f9d2b856..7ba1fe40b4c 100644
     --- a/services/core/java/com/android/server/BluetoothManagerService.java
     +++ b/services/core/java/com/android/server/BluetoothManagerService.java
     @@ -55,6 +55,7 @@ import android.os.UserManager;
    @@ -1652,7 +1652,7 @@ index 2a6f9d2..7ba1fe4 100644
                      case MESSAGE_GET_NAME_AND_ADDRESS:
                          if (DBG) Slog.d(TAG, "MESSAGE_GET_NAME_AND_ADDRESS");
     diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
    -index 2693272..903dc40 100644
    +index 269327201d5..903dc400741 100644
     --- a/services/core/java/com/android/server/ConnectivityService.java
     +++ b/services/core/java/com/android/server/ConnectivityService.java
     @@ -3007,6 +3007,12 @@ public class ConnectivityService extends IConnectivityManager.Stub
    @@ -1715,7 +1715,7 @@ index 2693272..903dc40 100644
                      // this request
                      if (VDBG) {
     diff --git a/services/core/java/com/android/server/NetworkManagementService.java b/services/core/java/com/android/server/NetworkManagementService.java
    -index bdbd066..aebe77a 100644
    +index bdbd06640e4..aebe77a0849 100644
     --- a/services/core/java/com/android/server/NetworkManagementService.java
     +++ b/services/core/java/com/android/server/NetworkManagementService.java
     @@ -1864,6 +1864,8 @@ public class NetworkManagementService extends INetworkManagementService.Stub
    @@ -1728,7 +1728,7 @@ index bdbd066..aebe77a 100644
                  mNetdService.networkRejectNonSecureVpn(add, uidRanges);
              } catch (ServiceSpecificException e) {
     diff --git a/services/core/java/com/android/server/accounts/AccountManagerService.java b/services/core/java/com/android/server/accounts/AccountManagerService.java
    -index a7a79cd..a085b71 100644
    +index a7a79cd5b3e..a085b716bd8 100644
     --- a/services/core/java/com/android/server/accounts/AccountManagerService.java
     +++ b/services/core/java/com/android/server/accounts/AccountManagerService.java
     @@ -4184,6 +4184,10 @@ public class AccountManagerService
    @@ -1743,7 +1743,7 @@ index a7a79cd..a085b71 100644
                  try {
                      PackageManager pm = mContext.getPackageManager();
     diff --git a/services/core/java/com/android/server/am/ActivityStackSupervisor.java b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
    -index c6ab918..8ba368b 100644
    +index c6ab9186456..8ba368b0b00 100644
     --- a/services/core/java/com/android/server/am/ActivityStackSupervisor.java
     +++ b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
     @@ -2855,10 +2855,10 @@ public final class ActivityStackSupervisor implements DisplayListener {
    @@ -1759,7 +1759,7 @@ index c6ab918..8ba368b 100644
                  mService.notifyAll();
              }
     diff --git a/services/core/java/com/android/server/clipboard/ClipboardService.java b/services/core/java/com/android/server/clipboard/ClipboardService.java
    -index 66aa403..6f59e84 100644
    +index 66aa40325a4..6f59e845219 100644
     --- a/services/core/java/com/android/server/clipboard/ClipboardService.java
     +++ b/services/core/java/com/android/server/clipboard/ClipboardService.java
     @@ -20,6 +20,7 @@ import android.app.ActivityManagerNative;
    @@ -1825,7 +1825,7 @@ index 66aa403..6f59e84 100644
              if (!"content".equals(uri.getScheme())) {
                  return;
     diff --git a/services/core/java/com/android/server/content/SyncStorageEngine.java b/services/core/java/com/android/server/content/SyncStorageEngine.java
    -index 069ae73..f804fa1 100644
    +index 069ae739431..f804fa1cff3 100644
     --- a/services/core/java/com/android/server/content/SyncStorageEngine.java
     +++ b/services/core/java/com/android/server/content/SyncStorageEngine.java
     @@ -18,6 +18,7 @@ package com.android.server.content;
    @@ -1960,7 +1960,7 @@ index 069ae73..f804fa1 100644
                      }
                  }
     diff --git a/services/core/java/com/android/server/input/InputManagerService.java b/services/core/java/com/android/server/input/InputManagerService.java
    -index 719ce76..df2c00b 100644
    +index 719ce7618fd..df2c00be83d 100644
     --- a/services/core/java/com/android/server/input/InputManagerService.java
     +++ b/services/core/java/com/android/server/input/InputManagerService.java
     @@ -286,6 +286,9 @@ public class InputManagerService extends IInputManager.Stub
    @@ -2003,7 +2003,7 @@ index 719ce76..df2c00b 100644
      
              public long notifyANR(InputApplicationHandle inputApplicationHandle,
     diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
    -index b6a9940..11b5832a 100644
    +index b6a99408122..11b5832ad6a 100644
     --- a/services/core/java/com/android/server/pm/PackageManagerService.java
     +++ b/services/core/java/com/android/server/pm/PackageManagerService.java
     @@ -423,7 +423,7 @@ public class PackageManagerService extends IPackageManager.Stub {
    @@ -2016,7 +2016,7 @@ index b6a9940..11b5832a 100644
          /**
           * Whether verification is enabled by default.
     diff --git a/services/core/java/com/android/server/pm/ShortcutService.java b/services/core/java/com/android/server/pm/ShortcutService.java
    -index 6e8799e..b33cbfd 100644
    +index 6e8799e8132..b33cbfd6b0c 100644
     --- a/services/core/java/com/android/server/pm/ShortcutService.java
     +++ b/services/core/java/com/android/server/pm/ShortcutService.java
     @@ -124,6 +124,7 @@ import java.nio.charset.StandardCharsets;
    @@ -2077,7 +2077,7 @@ index 6e8799e..b33cbfd 100644
      
              synchronized (mLock) {
     diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java
    -index 889c52a..872b03d 100644
    +index 889c52afa37..872b03d2f09 100644
     --- a/services/core/java/com/android/server/policy/PhoneWindowManager.java
     +++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java
     @@ -491,6 +491,9 @@ public class PhoneWindowManager implements WindowManagerPolicy {
    @@ -2155,7 +2155,7 @@ index 889c52a..872b03d 100644
                      result &= ~ACTION_PASS_TO_USER;
                      if (down) {
     diff --git a/services/core/java/com/android/server/wm/InputMonitor.java b/services/core/java/com/android/server/wm/InputMonitor.java
    -index be9fb26..d835e88 100644
    +index be9fb26bb28..d835e884615 100644
     --- a/services/core/java/com/android/server/wm/InputMonitor.java
     +++ b/services/core/java/com/android/server/wm/InputMonitor.java
     @@ -392,6 +392,12 @@ final class InputMonitor implements InputManagerService.WindowManagerCallbacks {
    @@ -2172,7 +2172,7 @@ index be9fb26..d835e88 100644
           * processing as soon as the key has been read from the device. */
          @Override
     diff --git a/services/core/java/com/android/server/wm/Session.java b/services/core/java/com/android/server/wm/Session.java
    -index 08c0a4b..b5c4202 100644
    +index 08c0a4b0135..b5c4202dc10 100644
     --- a/services/core/java/com/android/server/wm/Session.java
     +++ b/services/core/java/com/android/server/wm/Session.java
     @@ -16,6 +16,9 @@
    @@ -2206,7 +2206,7 @@ index 08c0a4b..b5c4202 100644
              StringBuilder sb = new StringBuilder();
              sb.append("Session{");
     diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
    -index ca2610a..0d97059 100644
    +index ca2610af3f6..0d970591cb5 100644
     --- a/services/core/java/com/android/server/wm/WindowManagerService.java
     +++ b/services/core/java/com/android/server/wm/WindowManagerService.java
     @@ -490,6 +490,9 @@ public class WindowManagerService extends IWindowManager.Stub
    @@ -2273,7 +2273,7 @@ index ca2610a..0d97059 100644
     +    }
      }
     diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
    -index fbef2c6..228ef1a 100644
    +index fbef2c626a9..228ef1afb2a 100644
     --- a/services/core/java/com/android/server/wm/WindowState.java
     +++ b/services/core/java/com/android/server/wm/WindowState.java
     @@ -79,6 +79,7 @@ import static android.view.WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON;
    @@ -2372,7 +2372,7 @@ index fbef2c6..228ef1a 100644
              return Integer.toHexString(System.identityHashCode(this))
                  + " " + getWindowTag();
     diff --git a/services/core/java/com/android/server/wm/WindowStateAnimator.java b/services/core/java/com/android/server/wm/WindowStateAnimator.java
    -index aa8e781..ec3208b 100644
    +index aa8e781b1c0..ec3208b3cc6 100644
     --- a/services/core/java/com/android/server/wm/WindowStateAnimator.java
     +++ b/services/core/java/com/android/server/wm/WindowStateAnimator.java
     @@ -582,6 +582,7 @@ class WindowStateAnimator {
    @@ -2392,7 +2392,7 @@ index aa8e781..ec3208b 100644
                  if (DEBUG_VISIBILITY) Slog.v(TAG, "Show surface turning screen on: " + mWin);
                  mWin.mTurnOnScreen = false;
     diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
    -index e3b6ecc..ff63b08 100644
    +index e3b6ecc749c..ff63b08e96e 100644
     --- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
     +++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
     @@ -71,6 +71,7 @@ import android.content.pm.PackageManager;
    @@ -2446,7 +2446,7 @@ index e3b6ecc..ff63b08 100644
          public boolean isProvisioningAllowed(String action) {
              if (!mHasFeature) {
     diff --git a/services/net/java/android/net/dhcp/DhcpClient.java b/services/net/java/android/net/dhcp/DhcpClient.java
    -index ffbea9f..8dd05b1 100644
    +index ffbea9fce27..8dd05b19ea7 100644
     --- a/services/net/java/android/net/dhcp/DhcpClient.java
     +++ b/services/net/java/android/net/dhcp/DhcpClient.java
     @@ -40,6 +40,7 @@ import android.os.SystemClock;
    @@ -2473,7 +2473,7 @@ index ffbea9f..8dd05b1 100644
                  }
     diff --git a/services/tests/Android.mk b/services/tests/Android.mk
     deleted file mode 100644
    -index 40369ee..0000000
    +index 40369ee2ec5..00000000000
     --- a/services/tests/Android.mk
     +++ /dev/null
     @@ -1,3 +0,0 @@
    @@ -2482,7 +2482,7 @@ index 40369ee..0000000
     -include $(call all-makefiles-under, $(LOCAL_PATH))
     diff --git a/services/tests/servicestests/Android.mk b/services/tests/servicestests/Android.mk
     deleted file mode 100644
    -index 7886b5e..0000000
    +index 7886b5e9e39..00000000000
     --- a/services/tests/servicestests/Android.mk
     +++ /dev/null
     @@ -1,87 +0,0 @@
    @@ -2575,7 +2575,7 @@ index 7886b5e..0000000
     -include $(BUILD_SHARED_LIBRARY)
     diff --git a/services/tests/servicestests/AndroidManifest.xml b/services/tests/servicestests/AndroidManifest.xml
     deleted file mode 100644
    -index b8ace28..0000000
    +index b8ace28fc09..00000000000
     --- a/services/tests/servicestests/AndroidManifest.xml
     +++ /dev/null
     @@ -1,164 +0,0 @@
    @@ -2745,7 +2745,7 @@ index b8ace28..0000000
     -</manifest>
     diff --git a/services/tests/servicestests/assets/DevicePolicyManagerServiceMigrationTest/legacy_device_owner.xml b/services/tests/servicestests/assets/DevicePolicyManagerServiceMigrationTest/legacy_device_owner.xml
     deleted file mode 100644
    -index 9564969..0000000
    +index 9564969ab57..00000000000
     --- a/services/tests/servicestests/assets/DevicePolicyManagerServiceMigrationTest/legacy_device_owner.xml
     +++ /dev/null
     @@ -1,4 +0,0 @@
    @@ -2755,7 +2755,7 @@ index 9564969..0000000
     -<profile-owner package="com.android.frameworks.servicestests" name="0" userId="11" component="com.android.frameworks.servicestests/com.android.server.devicepolicy.DummyDeviceAdmins$Admin3" />
     diff --git a/services/tests/servicestests/assets/DevicePolicyManagerServiceMigrationTest/legacy_device_policies.xml b/services/tests/servicestests/assets/DevicePolicyManagerServiceMigrationTest/legacy_device_policies.xml
     deleted file mode 100644
    -index 48cb814..0000000
    +index 48cb814fa90..00000000000
     --- a/services/tests/servicestests/assets/DevicePolicyManagerServiceMigrationTest/legacy_device_policies.xml
     +++ /dev/null
     @@ -1,7 +0,0 @@
    @@ -2768,7 +2768,7 @@ index 48cb814..0000000
     -</policies>
     diff --git a/services/tests/servicestests/assets/DevicePolicyManagerServiceMigrationTest/legacy_device_policies_10.xml b/services/tests/servicestests/assets/DevicePolicyManagerServiceMigrationTest/legacy_device_policies_10.xml
     deleted file mode 100644
    -index 6b53840..0000000
    +index 6b53840434c..00000000000
     --- a/services/tests/servicestests/assets/DevicePolicyManagerServiceMigrationTest/legacy_device_policies_10.xml
     +++ /dev/null
     @@ -1,5 +0,0 @@
    @@ -2779,7 +2779,7 @@ index 6b53840..0000000
     -</policies>
     diff --git a/services/tests/servicestests/assets/DevicePolicyManagerServiceMigrationTest/legacy_device_policies_11.xml b/services/tests/servicestests/assets/DevicePolicyManagerServiceMigrationTest/legacy_device_policies_11.xml
     deleted file mode 100644
    -index 2bcc5d4..0000000
    +index 2bcc5d41a7c..00000000000
     --- a/services/tests/servicestests/assets/DevicePolicyManagerServiceMigrationTest/legacy_device_policies_11.xml
     +++ /dev/null
     @@ -1,5 +0,0 @@
    @@ -2790,7 +2790,7 @@ index 2bcc5d4..0000000
     -</policies>
     diff --git a/services/tests/servicestests/assets/DevicePolicyManagerServiceMigrationTest2/legacy_device_owner.xml b/services/tests/servicestests/assets/DevicePolicyManagerServiceMigrationTest2/legacy_device_owner.xml
     deleted file mode 100644
    -index c0977f7..0000000
    +index c0977f79127..00000000000
     --- a/services/tests/servicestests/assets/DevicePolicyManagerServiceMigrationTest2/legacy_device_owner.xml
     +++ /dev/null
     @@ -1,2 +0,0 @@
    @@ -2798,7 +2798,7 @@ index c0977f7..0000000
     -<profile-owner package="com.android.frameworks.servicestests" name="0" userId="0" component="com.android.frameworks.servicestests/com.android.server.devicepolicy.DummyDeviceAdmins$Admin2" />
     diff --git a/services/tests/servicestests/assets/DevicePolicyManagerServiceMigrationTest2/legacy_device_policies.xml b/services/tests/servicestests/assets/DevicePolicyManagerServiceMigrationTest2/legacy_device_policies.xml
     deleted file mode 100644
    -index 6b53840..0000000
    +index 6b53840434c..00000000000
     --- a/services/tests/servicestests/assets/DevicePolicyManagerServiceMigrationTest2/legacy_device_policies.xml
     +++ /dev/null
     @@ -1,5 +0,0 @@
    @@ -2809,14 +2809,14 @@ index 6b53840..0000000
     -</policies>
     diff --git a/services/tests/servicestests/assets/OwnersTest/test01/input.xml b/services/tests/servicestests/assets/OwnersTest/test01/input.xml
     deleted file mode 100644
    -index db3e974..0000000
    +index db3e974f5d0..00000000000
     --- a/services/tests/servicestests/assets/OwnersTest/test01/input.xml
     +++ /dev/null
     @@ -1 +0,0 @@
     -<?xml version='1.0' encoding='utf-8' standalone='yes' ?>
     diff --git a/services/tests/servicestests/assets/OwnersTest/test02/input.xml b/services/tests/servicestests/assets/OwnersTest/test02/input.xml
     deleted file mode 100644
    -index 321842b..0000000
    +index 321842b2745..00000000000
     --- a/services/tests/servicestests/assets/OwnersTest/test02/input.xml
     +++ /dev/null
     @@ -1,2 +0,0 @@
    @@ -2824,7 +2824,7 @@ index 321842b..0000000
     -<device-owner package="com.google.android.testdpc" />
     diff --git a/services/tests/servicestests/assets/OwnersTest/test03/input.xml b/services/tests/servicestests/assets/OwnersTest/test03/input.xml
     deleted file mode 100644
    -index 1bbfdad..0000000
    +index 1bbfdadf6eb..00000000000
     --- a/services/tests/servicestests/assets/OwnersTest/test03/input.xml
     +++ /dev/null
     @@ -1,3 +0,0 @@
    @@ -2833,7 +2833,7 @@ index 1bbfdad..0000000
     -<profile-owner package="com.google.android.testdpc1" name="1" userId="11" />
     diff --git a/services/tests/servicestests/assets/OwnersTest/test04/input.xml b/services/tests/servicestests/assets/OwnersTest/test04/input.xml
     deleted file mode 100644
    -index 8be51d9..0000000
    +index 8be51d9a45e..00000000000
     --- a/services/tests/servicestests/assets/OwnersTest/test04/input.xml
     +++ /dev/null
     @@ -1,6 +0,0 @@
    @@ -2845,7 +2845,7 @@ index 8be51d9..0000000
     -<system-update-policy policy_type="5" />
     diff --git a/services/tests/servicestests/assets/OwnersTest/test05/input.xml b/services/tests/servicestests/assets/OwnersTest/test05/input.xml
     deleted file mode 100644
    -index dbcb858..0000000
    +index dbcb8588654..00000000000
     --- a/services/tests/servicestests/assets/OwnersTest/test05/input.xml
     +++ /dev/null
     @@ -1,3 +0,0 @@
    @@ -2854,7 +2854,7 @@ index dbcb858..0000000
     -
     diff --git a/services/tests/servicestests/assets/OwnersTest/test06/input.xml b/services/tests/servicestests/assets/OwnersTest/test06/input.xml
     deleted file mode 100644
    -index 794622b..0000000
    +index 794622b0b99..00000000000
     --- a/services/tests/servicestests/assets/OwnersTest/test06/input.xml
     +++ /dev/null
     @@ -1,2 +0,0 @@
    @@ -2862,7 +2862,7 @@ index 794622b..0000000
     -<system-update-policy policy_type="5" />
     diff --git a/services/tests/servicestests/assets/shortcut/dumpsys_expected.txt b/services/tests/servicestests/assets/shortcut/dumpsys_expected.txt
     deleted file mode 100644
    -index eed2087..0000000
    +index eed2087f80e..00000000000
     --- a/services/tests/servicestests/assets/shortcut/dumpsys_expected.txt
     +++ /dev/null
     @@ -1,105 +0,0 @@
    @@ -2973,7 +2973,7 @@ index eed2087..0000000
     -}
     diff --git a/services/tests/servicestests/assets/shortcut/shortcut_legacy_file.xml b/services/tests/servicestests/assets/shortcut/shortcut_legacy_file.xml
     deleted file mode 100644
    -index f7eee91..0000000
    +index f7eee9155da..00000000000
     --- a/services/tests/servicestests/assets/shortcut/shortcut_legacy_file.xml
     +++ /dev/null
     @@ -1,25 +0,0 @@
    @@ -3004,7 +3004,7 @@ index f7eee91..0000000
     -</user>
     diff --git a/services/tests/servicestests/jni/UidRangeTest.cpp b/services/tests/servicestests/jni/UidRangeTest.cpp
     deleted file mode 100644
    -index 7941731..0000000
    +index 7941731a07f..00000000000
     --- a/services/tests/servicestests/jni/UidRangeTest.cpp
     +++ /dev/null
     @@ -1,79 +0,0 @@
    @@ -3089,7 +3089,7 @@ index 7941731..0000000
     -}
     diff --git a/services/tests/servicestests/jni/UidRangeTest.h b/services/tests/servicestests/jni/UidRangeTest.h
     deleted file mode 100644
    -index b7e7453..0000000
    +index b7e74537880..00000000000
     --- a/services/tests/servicestests/jni/UidRangeTest.h
     +++ /dev/null
     @@ -1,38 +0,0 @@
    @@ -3133,7 +3133,7 @@ index b7e7453..0000000
     -#endif  //  _ANDROID_NET_UIDRANGETEST_H_
     diff --git a/services/tests/servicestests/jni/apf_jni.cpp b/services/tests/servicestests/jni/apf_jni.cpp
     deleted file mode 100644
    -index ee43dd4..0000000
    +index ee43dd48836..00000000000
     --- a/services/tests/servicestests/jni/apf_jni.cpp
     +++ /dev/null
     @@ -1,182 +0,0 @@
    @@ -3321,83 +3321,83 @@ index ee43dd4..0000000
     -}
     diff --git a/services/tests/servicestests/res/drawable-nodpi/black_1024x4096.png b/services/tests/servicestests/res/drawable-nodpi/black_1024x4096.png
     deleted file mode 100644
    -index f700326..0000000
    +index f7003269889..00000000000
     Binary files a/services/tests/servicestests/res/drawable-nodpi/black_1024x4096.png and /dev/null differ
     diff --git a/services/tests/servicestests/res/drawable-nodpi/black_16x64.png b/services/tests/servicestests/res/drawable-nodpi/black_16x64.png
     deleted file mode 100644
    -index 315763e..0000000
    +index 315763e4560..00000000000
     Binary files a/services/tests/servicestests/res/drawable-nodpi/black_16x64.png and /dev/null differ
     diff --git a/services/tests/servicestests/res/drawable-nodpi/black_32x32.png b/services/tests/servicestests/res/drawable-nodpi/black_32x32.png
     deleted file mode 100644
    -index 8958f6b..0000000
    +index 8958f6b1eab..00000000000
     Binary files a/services/tests/servicestests/res/drawable-nodpi/black_32x32.png and /dev/null differ
     diff --git a/services/tests/servicestests/res/drawable-nodpi/black_4096x1024.png b/services/tests/servicestests/res/drawable-nodpi/black_4096x1024.png
     deleted file mode 100644
    -index f675030..0000000
    +index f6750301773..00000000000
     Binary files a/services/tests/servicestests/res/drawable-nodpi/black_4096x1024.png and /dev/null differ
     diff --git a/services/tests/servicestests/res/drawable-nodpi/black_4096x4096.png b/services/tests/servicestests/res/drawable-nodpi/black_4096x4096.png
     deleted file mode 100644
    -index 999d858..0000000
    +index 999d8585fc6..00000000000
     Binary files a/services/tests/servicestests/res/drawable-nodpi/black_4096x4096.png and /dev/null differ
     diff --git a/services/tests/servicestests/res/drawable-nodpi/black_512x512.png b/services/tests/servicestests/res/drawable-nodpi/black_512x512.png
     deleted file mode 100644
    -index 40d1c2c..0000000
    +index 40d1c2c41f1..00000000000
     Binary files a/services/tests/servicestests/res/drawable-nodpi/black_512x512.png and /dev/null differ
     diff --git a/services/tests/servicestests/res/drawable-nodpi/black_64x16.png b/services/tests/servicestests/res/drawable-nodpi/black_64x16.png
     deleted file mode 100644
    -index 5883015..0000000
    +index 58830151997..00000000000
     Binary files a/services/tests/servicestests/res/drawable-nodpi/black_64x16.png and /dev/null differ
     diff --git a/services/tests/servicestests/res/drawable-nodpi/black_64x64.png b/services/tests/servicestests/res/drawable-nodpi/black_64x64.png
     deleted file mode 100644
    -index 71cfafc..0000000
    +index 71cfafc2ad3..00000000000
     Binary files a/services/tests/servicestests/res/drawable-nodpi/black_64x64.png and /dev/null differ
     diff --git a/services/tests/servicestests/res/drawable-nodpi/icon1.png b/services/tests/servicestests/res/drawable-nodpi/icon1.png
     deleted file mode 100644
    -index 64eb294..0000000
    +index 64eb294363d..00000000000
     Binary files a/services/tests/servicestests/res/drawable-nodpi/icon1.png and /dev/null differ
     diff --git a/services/tests/servicestests/res/drawable-nodpi/icon2.png b/services/tests/servicestests/res/drawable-nodpi/icon2.png
     deleted file mode 100644
    -index 7502484..0000000
    +index 75024841d32..00000000000
     Binary files a/services/tests/servicestests/res/drawable-nodpi/icon2.png and /dev/null differ
     diff --git a/services/tests/servicestests/res/drawable/icon1.png b/services/tests/servicestests/res/drawable/icon1.png
     deleted file mode 100644
    -index 64eb294..0000000
    +index 64eb294363d..00000000000
     Binary files a/services/tests/servicestests/res/drawable/icon1.png and /dev/null differ
     diff --git a/services/tests/servicestests/res/drawable/icon2.png b/services/tests/servicestests/res/drawable/icon2.png
     deleted file mode 100644
    -index 7502484..0000000
    +index 75024841d32..00000000000
     Binary files a/services/tests/servicestests/res/drawable/icon2.png and /dev/null differ
     diff --git a/services/tests/servicestests/res/drawable/icon3.png b/services/tests/servicestests/res/drawable/icon3.png
     deleted file mode 100644
    -index 64eb294..0000000
    +index 64eb294363d..00000000000
     Binary files a/services/tests/servicestests/res/drawable/icon3.png and /dev/null differ
     diff --git a/services/tests/servicestests/res/raw/apf.pcap b/services/tests/servicestests/res/raw/apf.pcap
     deleted file mode 100644
    -index 963165f..0000000
    +index 963165f19f7..00000000000
     Binary files a/services/tests/servicestests/res/raw/apf.pcap and /dev/null differ
     diff --git a/services/tests/servicestests/res/raw/netstats_uid_v4 b/services/tests/servicestests/res/raw/netstats_uid_v4
     deleted file mode 100644
    -index e75fc1c..0000000
    +index e75fc1ca5c2..00000000000
     Binary files a/services/tests/servicestests/res/raw/netstats_uid_v4 and /dev/null differ
     diff --git a/services/tests/servicestests/res/raw/netstats_v1 b/services/tests/servicestests/res/raw/netstats_v1
     deleted file mode 100644
    -index e80860a..0000000
    +index e80860a6b95..00000000000
     Binary files a/services/tests/servicestests/res/raw/netstats_v1 and /dev/null differ
     diff --git a/services/tests/servicestests/res/raw/test1.obb b/services/tests/servicestests/res/raw/test1.obb
     deleted file mode 100644
    -index 7d2b4f6..0000000
    +index 7d2b4f6e6fb..00000000000
     Binary files a/services/tests/servicestests/res/raw/test1.obb and /dev/null differ
     diff --git a/services/tests/servicestests/res/raw/test1_nosig.obb b/services/tests/servicestests/res/raw/test1_nosig.obb
     deleted file mode 100644
    -index 5c3573f7..0000000
    +index 5c3573f72a1..00000000000
     Binary files a/services/tests/servicestests/res/raw/test1_nosig.obb and /dev/null differ
     diff --git a/services/tests/servicestests/res/raw/test1_wrongpackage.obb b/services/tests/servicestests/res/raw/test1_wrongpackage.obb
     deleted file mode 100644
    -index d0aafe1..0000000
    +index d0aafe16e1a..00000000000
     Binary files a/services/tests/servicestests/res/raw/test1_wrongpackage.obb and /dev/null differ
     diff --git a/services/tests/servicestests/res/values/strings.xml b/services/tests/servicestests/res/values/strings.xml
     deleted file mode 100644
    -index 2f9d06c..0000000
    +index 2f9d06c318c..00000000000
     --- a/services/tests/servicestests/res/values/strings.xml
     +++ /dev/null
     @@ -1,24 +0,0 @@
    @@ -3427,7 +3427,7 @@ index 2f9d06c..0000000
     -</resources>
     diff --git a/services/tests/servicestests/res/xml/device_admin_sample.xml b/services/tests/servicestests/res/xml/device_admin_sample.xml
     deleted file mode 100644
    -index 032debb..0000000
    +index 032debbb92b..00000000000
     --- a/services/tests/servicestests/res/xml/device_admin_sample.xml
     +++ /dev/null
     @@ -1,29 +0,0 @@
    @@ -3462,7 +3462,7 @@ index 032debb..0000000
     -</device-admin>
     diff --git a/services/tests/servicestests/res/xml/shortcut_0.xml b/services/tests/servicestests/res/xml/shortcut_0.xml
     deleted file mode 100644
    -index fda001e..0000000
    +index fda001ec0aa..00000000000
     --- a/services/tests/servicestests/res/xml/shortcut_0.xml
     +++ /dev/null
     @@ -1,2 +0,0 @@
    @@ -3470,7 +3470,7 @@ index fda001e..0000000
     -</shortcuts>
     diff --git a/services/tests/servicestests/res/xml/shortcut_1.xml b/services/tests/servicestests/res/xml/shortcut_1.xml
     deleted file mode 100644
    -index e3f9172..0000000
    +index e3f9172cc23..00000000000
     --- a/services/tests/servicestests/res/xml/shortcut_1.xml
     +++ /dev/null
     @@ -1,18 +0,0 @@
    @@ -3494,7 +3494,7 @@ index e3f9172..0000000
     -</shortcuts>
     diff --git a/services/tests/servicestests/res/xml/shortcut_1_alt.xml b/services/tests/servicestests/res/xml/shortcut_1_alt.xml
     deleted file mode 100644
    -index 2d5e8e7..0000000
    +index 2d5e8e7cbd7..00000000000
     --- a/services/tests/servicestests/res/xml/shortcut_1_alt.xml
     +++ /dev/null
     @@ -1,33 +0,0 @@
    @@ -3533,7 +3533,7 @@ index 2d5e8e7..0000000
     -</shortcuts>
     diff --git a/services/tests/servicestests/res/xml/shortcut_1_disable.xml b/services/tests/servicestests/res/xml/shortcut_1_disable.xml
     deleted file mode 100644
    -index e3ee3a0..0000000
    +index e3ee3a0786e..00000000000
     --- a/services/tests/servicestests/res/xml/shortcut_1_disable.xml
     +++ /dev/null
     @@ -1,25 +0,0 @@
    @@ -3564,7 +3564,7 @@ index e3ee3a0..0000000
     -</shortcuts>
     diff --git a/services/tests/servicestests/res/xml/shortcut_2.xml b/services/tests/servicestests/res/xml/shortcut_2.xml
     deleted file mode 100644
    -index f7ea803..0000000
    +index f7ea803d340..00000000000
     --- a/services/tests/servicestests/res/xml/shortcut_2.xml
     +++ /dev/null
     @@ -1,48 +0,0 @@
    @@ -3618,7 +3618,7 @@ index f7ea803..0000000
     -</shortcuts>
     diff --git a/services/tests/servicestests/res/xml/shortcut_2_duplicate.xml b/services/tests/servicestests/res/xml/shortcut_2_duplicate.xml
     deleted file mode 100644
    -index b00ec60..0000000
    +index b00ec60e0ff..00000000000
     --- a/services/tests/servicestests/res/xml/shortcut_2_duplicate.xml
     +++ /dev/null
     @@ -1,35 +0,0 @@
    @@ -3659,7 +3659,7 @@ index b00ec60..0000000
     -</shortcuts>
     diff --git a/services/tests/servicestests/res/xml/shortcut_3.xml b/services/tests/servicestests/res/xml/shortcut_3.xml
     deleted file mode 100644
    -index 432ca49..0000000
    +index 432ca4935ec..00000000000
     --- a/services/tests/servicestests/res/xml/shortcut_3.xml
     +++ /dev/null
     @@ -1,56 +0,0 @@
    @@ -3721,7 +3721,7 @@ index 432ca49..0000000
     -</shortcuts>
     diff --git a/services/tests/servicestests/res/xml/shortcut_5.xml b/services/tests/servicestests/res/xml/shortcut_5.xml
     deleted file mode 100644
    -index 9551100..0000000
    +index 9551100cefe..00000000000
     --- a/services/tests/servicestests/res/xml/shortcut_5.xml
     +++ /dev/null
     @@ -1,85 +0,0 @@
    @@ -3812,7 +3812,7 @@ index 9551100..0000000
     -</shortcuts>
     diff --git a/services/tests/servicestests/res/xml/shortcut_5_alt.xml b/services/tests/servicestests/res/xml/shortcut_5_alt.xml
     deleted file mode 100644
    -index f79cd6f..0000000
    +index f79cd6f1573..00000000000
     --- a/services/tests/servicestests/res/xml/shortcut_5_alt.xml
     +++ /dev/null
     @@ -1,74 +0,0 @@
    @@ -3892,7 +3892,7 @@ index f79cd6f..0000000
     -</shortcuts>
     diff --git a/services/tests/servicestests/res/xml/shortcut_5_reverse.xml b/services/tests/servicestests/res/xml/shortcut_5_reverse.xml
     deleted file mode 100644
    -index d5b7c8f..0000000
    +index d5b7c8fde0b..00000000000
     --- a/services/tests/servicestests/res/xml/shortcut_5_reverse.xml
     +++ /dev/null
     @@ -1,78 +0,0 @@
    @@ -3976,7 +3976,7 @@ index d5b7c8f..0000000
     -</shortcuts>
     diff --git a/services/tests/servicestests/res/xml/shortcut_error_1.xml b/services/tests/servicestests/res/xml/shortcut_error_1.xml
     deleted file mode 100644
    -index 3990d02..0000000
    +index 3990d027050..00000000000
     --- a/services/tests/servicestests/res/xml/shortcut_error_1.xml
     +++ /dev/null
     @@ -1,34 +0,0 @@
    @@ -4016,7 +4016,7 @@ index 3990d02..0000000
     -</shortcuts>
     diff --git a/services/tests/servicestests/res/xml/shortcut_error_2.xml b/services/tests/servicestests/res/xml/shortcut_error_2.xml
     deleted file mode 100644
    -index a6f7150..0000000
    +index a6f715025cc..00000000000
     --- a/services/tests/servicestests/res/xml/shortcut_error_2.xml
     +++ /dev/null
     @@ -1,34 +0,0 @@
    @@ -4056,7 +4056,7 @@ index a6f7150..0000000
     -</shortcuts>
     diff --git a/services/tests/servicestests/res/xml/shortcut_error_3.xml b/services/tests/servicestests/res/xml/shortcut_error_3.xml
     deleted file mode 100644
    -index 24ee024..0000000
    +index 24ee024f64a..00000000000
     --- a/services/tests/servicestests/res/xml/shortcut_error_3.xml
     +++ /dev/null
     @@ -1,36 +0,0 @@
    @@ -4098,7 +4098,7 @@ index 24ee024..0000000
     -</shortcuts>
     diff --git a/services/tests/servicestests/res/xml/shortcut_error_4.xml b/services/tests/servicestests/res/xml/shortcut_error_4.xml
     deleted file mode 100644
    -index f680e99..0000000
    +index f680e99f98c..00000000000
     --- a/services/tests/servicestests/res/xml/shortcut_error_4.xml
     +++ /dev/null
     @@ -1,70 +0,0 @@
    @@ -4174,7 +4174,7 @@ index f680e99..0000000
     -</shortcuts>
     diff --git a/services/tests/servicestests/src/android/net/ConnectivityMetricsLoggerTest.java b/services/tests/servicestests/src/android/net/ConnectivityMetricsLoggerTest.java
     deleted file mode 100644
    -index 6d42cce..0000000
    +index 6d42cce2e50..00000000000
     --- a/services/tests/servicestests/src/android/net/ConnectivityMetricsLoggerTest.java
     +++ /dev/null
     @@ -1,130 +0,0 @@
    @@ -4310,7 +4310,7 @@ index 6d42cce..0000000
     -}
     diff --git a/services/tests/servicestests/src/android/net/IpUtilsTest.java b/services/tests/servicestests/src/android/net/IpUtilsTest.java
     deleted file mode 100644
    -index c2d1608..0000000
    +index c2d1608c461..00000000000
     --- a/services/tests/servicestests/src/android/net/IpUtilsTest.java
     +++ /dev/null
     @@ -1,162 +0,0 @@
    @@ -4478,7 +4478,7 @@ index c2d1608..0000000
     -}
     diff --git a/services/tests/servicestests/src/android/net/UidRangeTest.java b/services/tests/servicestests/src/android/net/UidRangeTest.java
     deleted file mode 100644
    -index 221fe0f..0000000
    +index 221fe0f99f0..00000000000
     --- a/services/tests/servicestests/src/android/net/UidRangeTest.java
     +++ /dev/null
     @@ -1,112 +0,0 @@
    @@ -4596,7 +4596,7 @@ index 221fe0f..0000000
     -}
     diff --git a/services/tests/servicestests/src/android/net/apf/ApfTest.java b/services/tests/servicestests/src/android/net/apf/ApfTest.java
     deleted file mode 100644
    -index 6092fdd..0000000
    +index 6092fddc6be..00000000000
     --- a/services/tests/servicestests/src/android/net/apf/ApfTest.java
     +++ /dev/null
     @@ -1,1205 +0,0 @@
    @@ -5807,7 +5807,7 @@ index 6092fdd..0000000
     -}
     diff --git a/services/tests/servicestests/src/android/net/apf/Bpf2Apf.java b/services/tests/servicestests/src/android/net/apf/Bpf2Apf.java
     deleted file mode 100644
    -index 220e54d..0000000
    +index 220e54ddef5..00000000000
     --- a/services/tests/servicestests/src/android/net/apf/Bpf2Apf.java
     +++ /dev/null
     @@ -1,327 +0,0 @@
    @@ -6140,7 +6140,7 @@ index 220e54d..0000000
     -}
     diff --git a/services/tests/servicestests/src/android/net/dhcp/DhcpPacketTest.java b/services/tests/servicestests/src/android/net/dhcp/DhcpPacketTest.java
     deleted file mode 100644
    -index bc8baa1..0000000
    +index bc8baa12a45..00000000000
     --- a/services/tests/servicestests/src/android/net/dhcp/DhcpPacketTest.java
     +++ /dev/null
     @@ -1,939 +0,0 @@
    @@ -7085,7 +7085,7 @@ index bc8baa1..0000000
     -}
     diff --git a/services/tests/servicestests/src/android/net/netlink/NetlinkErrorMessageTest.java b/services/tests/servicestests/src/android/net/netlink/NetlinkErrorMessageTest.java
     deleted file mode 100644
    -index e677475..0000000
    +index e677475f590..00000000000
     --- a/services/tests/servicestests/src/android/net/netlink/NetlinkErrorMessageTest.java
     +++ /dev/null
     @@ -1,82 +0,0 @@
    @@ -7173,7 +7173,7 @@ index e677475..0000000
     -}
     diff --git a/services/tests/servicestests/src/android/net/netlink/NetlinkSocketTest.java b/services/tests/servicestests/src/android/net/netlink/NetlinkSocketTest.java
     deleted file mode 100644
    -index c599fe3..0000000
    +index c599fe3e5b7..00000000000
     --- a/services/tests/servicestests/src/android/net/netlink/NetlinkSocketTest.java
     +++ /dev/null
     @@ -1,116 +0,0 @@
    @@ -7295,7 +7295,7 @@ index c599fe3..0000000
     -}
     diff --git a/services/tests/servicestests/src/android/net/netlink/RtNetlinkNeighborMessageTest.java b/services/tests/servicestests/src/android/net/netlink/RtNetlinkNeighborMessageTest.java
     deleted file mode 100644
    -index 19ee000..0000000
    +index 19ee00036b6..00000000000
     --- a/services/tests/servicestests/src/android/net/netlink/RtNetlinkNeighborMessageTest.java
     +++ /dev/null
     @@ -1,257 +0,0 @@
    @@ -7558,7 +7558,7 @@ index 19ee000..0000000
     -}
     diff --git a/services/tests/servicestests/src/com/android/internal/util/FakeSettingsProvider.java b/services/tests/servicestests/src/com/android/internal/util/FakeSettingsProvider.java
     deleted file mode 100644
    -index 808f4dd..0000000
    +index 808f4dd7b84..00000000000
     --- a/services/tests/servicestests/src/com/android/internal/util/FakeSettingsProvider.java
     +++ /dev/null
     @@ -1,130 +0,0 @@
    @@ -7694,7 +7694,7 @@ index 808f4dd..0000000
     -}
     diff --git a/services/tests/servicestests/src/com/android/internal/util/FakeSettingsProviderTest.java b/services/tests/servicestests/src/com/android/internal/util/FakeSettingsProviderTest.java
     deleted file mode 100644
    -index 05de0a5..0000000
    +index 05de0a53e05..00000000000
     --- a/services/tests/servicestests/src/com/android/internal/util/FakeSettingsProviderTest.java
     +++ /dev/null
     @@ -1,59 +0,0 @@
    @@ -7759,7 +7759,7 @@ index 05de0a5..0000000
     -}
     diff --git a/services/tests/servicestests/src/com/android/server/AccessibilityManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/AccessibilityManagerServiceTest.java
     deleted file mode 100644
    -index 51e14d3..0000000
    +index 51e14d3fcb0..00000000000
     --- a/services/tests/servicestests/src/com/android/server/AccessibilityManagerServiceTest.java
     +++ /dev/null
     @@ -1,757 +0,0 @@
    @@ -8522,7 +8522,7 @@ index 51e14d3..0000000
     -}
     diff --git a/services/tests/servicestests/src/com/android/server/AccessibilityManagerTest.java b/services/tests/servicestests/src/com/android/server/AccessibilityManagerTest.java
     deleted file mode 100644
    -index 026a2ad..0000000
    +index 026a2adc1f9..00000000000
     --- a/services/tests/servicestests/src/com/android/server/AccessibilityManagerTest.java
     +++ /dev/null
     @@ -1,162 +0,0 @@
    @@ -8690,7 +8690,7 @@ index 026a2ad..0000000
     -}
     diff --git a/services/tests/servicestests/src/com/android/server/BroadcastInterceptingContext.java b/services/tests/servicestests/src/com/android/server/BroadcastInterceptingContext.java
     deleted file mode 100644
    -index 13657ab..0000000
    +index 13657ab7f02..00000000000
     --- a/services/tests/servicestests/src/com/android/server/BroadcastInterceptingContext.java
     +++ /dev/null
     @@ -1,177 +0,0 @@
    @@ -8873,7 +8873,7 @@ index 13657ab..0000000
     -}
     diff --git a/services/tests/servicestests/src/com/android/server/CertBlacklisterTest.java b/services/tests/servicestests/src/com/android/server/CertBlacklisterTest.java
     deleted file mode 100644
    -index 10b9e7c..0000000
    +index 10b9e7cf121..00000000000
     --- a/services/tests/servicestests/src/com/android/server/CertBlacklisterTest.java
     +++ /dev/null
     @@ -1,169 +0,0 @@
    @@ -9047,7 +9047,7 @@ index 10b9e7c..0000000
     -    }
     -}
     diff --git a/services/tests/servicestests/src/com/android/server/ConnectivityServiceTest.java b/services/tests/servicestests/src/com/android/server/ConnectivityServiceTest.java
    -index 65f9399..012bdd8 100644
    +index 65f9399c5a8..012bdd87b98 100644
     --- a/services/tests/servicestests/src/com/android/server/ConnectivityServiceTest.java
     +++ b/services/tests/servicestests/src/com/android/server/ConnectivityServiceTest.java
     @@ -620,6 +620,19 @@ public class ConnectivityServiceTest extends AndroidTestCase {
    @@ -9072,7 +9072,7 @@ index 65f9399..012bdd8 100644
              private WrappedNetworkMonitor mLastCreatedNetworkMonitor;
     diff --git a/services/tests/servicestests/src/com/android/server/CountryDetectorServiceTest.java b/services/tests/servicestests/src/com/android/server/CountryDetectorServiceTest.java
     deleted file mode 100644
    -index 192c50c..0000000
    +index 192c50c7dc1..00000000000
     --- a/services/tests/servicestests/src/com/android/server/CountryDetectorServiceTest.java
     +++ /dev/null
     @@ -1,109 +0,0 @@
    @@ -9187,7 +9187,7 @@ index 192c50c..0000000
     -}
     diff --git a/services/tests/servicestests/src/com/android/server/DropBoxTest.java b/services/tests/servicestests/src/com/android/server/DropBoxTest.java
     deleted file mode 100644
    -index 7f28d44..0000000
    +index 7f28d442c77..00000000000
     --- a/services/tests/servicestests/src/com/android/server/DropBoxTest.java
     +++ /dev/null
     @@ -1,775 +0,0 @@
    @@ -9968,7 +9968,7 @@ index 7f28d44..0000000
     -}
     diff --git a/services/tests/servicestests/src/com/android/server/EntropyMixerTest.java b/services/tests/servicestests/src/com/android/server/EntropyMixerTest.java
     deleted file mode 100644
    -index 50e7a03..0000000
    +index 50e7a0395a2..00000000000
     --- a/services/tests/servicestests/src/com/android/server/EntropyMixerTest.java
     +++ /dev/null
     @@ -1,41 +0,0 @@
    @@ -10015,7 +10015,7 @@ index 50e7a03..0000000
     -}
     diff --git a/services/tests/servicestests/src/com/android/server/LockSettingsStorageTests.java b/services/tests/servicestests/src/com/android/server/LockSettingsStorageTests.java
     deleted file mode 100644
    -index 7d28e39..0000000
    +index 7d28e3964f8..00000000000
     --- a/services/tests/servicestests/src/com/android/server/LockSettingsStorageTests.java
     +++ /dev/null
     @@ -1,357 +0,0 @@
    @@ -10378,7 +10378,7 @@ index 7d28e39..0000000
     -}
     diff --git a/services/tests/servicestests/src/com/android/server/MockAccessibilityService.java b/services/tests/servicestests/src/com/android/server/MockAccessibilityService.java
     deleted file mode 100644
    -index e1c5cee..0000000
    +index e1c5cee752e..00000000000
     --- a/services/tests/servicestests/src/com/android/server/MockAccessibilityService.java
     +++ /dev/null
     @@ -1,256 +0,0 @@
    @@ -10640,7 +10640,7 @@ index e1c5cee..0000000
     -}
     diff --git a/services/tests/servicestests/src/com/android/server/MountServiceTests.java b/services/tests/servicestests/src/com/android/server/MountServiceTests.java
     deleted file mode 100644
    -index ecfe0db..0000000
    +index ecfe0db103f..00000000000
     --- a/services/tests/servicestests/src/com/android/server/MountServiceTests.java
     +++ /dev/null
     @@ -1,274 +0,0 @@
    @@ -10920,7 +10920,7 @@ index ecfe0db..0000000
     -}
     diff --git a/services/tests/servicestests/src/com/android/server/NativeDaemonConnectorTest.java b/services/tests/servicestests/src/com/android/server/NativeDaemonConnectorTest.java
     deleted file mode 100644
    -index e2253a2..0000000
    +index e2253a2151b..00000000000
     --- a/services/tests/servicestests/src/com/android/server/NativeDaemonConnectorTest.java
     +++ /dev/null
     @@ -1,97 +0,0 @@
    @@ -11023,7 +11023,7 @@ index e2253a2..0000000
     -}
     diff --git a/services/tests/servicestests/src/com/android/server/NetworkManagementServiceTest.java b/services/tests/servicestests/src/com/android/server/NetworkManagementServiceTest.java
     deleted file mode 100644
    -index 0d5daa5..0000000
    +index 0d5daa5def9..00000000000
     --- a/services/tests/servicestests/src/com/android/server/NetworkManagementServiceTest.java
     +++ /dev/null
     @@ -1,226 +0,0 @@
    @@ -11255,7 +11255,7 @@ index 0d5daa5..0000000
     -}
     diff --git a/services/tests/servicestests/src/com/android/server/NetworkPolicyManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/NetworkPolicyManagerServiceTest.java
     deleted file mode 100644
    -index 541be3d..0000000
    +index 541be3dad37..00000000000
     --- a/services/tests/servicestests/src/com/android/server/NetworkPolicyManagerServiceTest.java
     +++ /dev/null
     @@ -1,1014 +0,0 @@
    @@ -12275,7 +12275,7 @@ index 541be3d..0000000
     -}
     diff --git a/services/tests/servicestests/src/com/android/server/Vector3Test.java b/services/tests/servicestests/src/com/android/server/Vector3Test.java
     deleted file mode 100644
    -index 88dbe70..0000000
    +index 88dbe70b994..00000000000
     --- a/services/tests/servicestests/src/com/android/server/Vector3Test.java
     +++ /dev/null
     @@ -1,164 +0,0 @@
    @@ -12445,7 +12445,7 @@ index 88dbe70..0000000
     -}
     diff --git a/services/tests/servicestests/src/com/android/server/accounts/AccountManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/accounts/AccountManagerServiceTest.java
     deleted file mode 100644
    -index a3d0afa..0000000
    +index a3d0afab88e..00000000000
     --- a/services/tests/servicestests/src/com/android/server/accounts/AccountManagerServiceTest.java
     +++ /dev/null
     @@ -1,466 +0,0 @@
    @@ -12917,7 +12917,7 @@ index a3d0afa..0000000
     -}
     diff --git a/services/tests/servicestests/src/com/android/server/accounts/PreNTestDatabaseHelper.java b/services/tests/servicestests/src/com/android/server/accounts/PreNTestDatabaseHelper.java
     deleted file mode 100644
    -index 97adbe6..0000000
    +index 97adbe6417b..00000000000
     --- a/services/tests/servicestests/src/com/android/server/accounts/PreNTestDatabaseHelper.java
     +++ /dev/null
     @@ -1,98 +0,0 @@
    @@ -13021,7 +13021,7 @@ index 97adbe6..0000000
     -}
     diff --git a/services/tests/servicestests/src/com/android/server/am/ActivityManagerTest.java b/services/tests/servicestests/src/com/android/server/am/ActivityManagerTest.java
     deleted file mode 100644
    -index bd9e6d1..0000000
    +index bd9e6d19269..00000000000
     --- a/services/tests/servicestests/src/com/android/server/am/ActivityManagerTest.java
     +++ /dev/null
     @@ -1,55 +0,0 @@
    @@ -13083,7 +13083,7 @@ index bd9e6d1..0000000
     \ No newline at end of file
     diff --git a/services/tests/servicestests/src/com/android/server/am/TaskPersisterTest.java b/services/tests/servicestests/src/com/android/server/am/TaskPersisterTest.java
     deleted file mode 100644
    -index 984a484..0000000
    +index 984a484dadc..00000000000
     --- a/services/tests/servicestests/src/com/android/server/am/TaskPersisterTest.java
     +++ /dev/null
     @@ -1,85 +0,0 @@
    @@ -13175,7 +13175,7 @@ index 984a484..0000000
     \ No newline at end of file
     diff --git a/services/tests/servicestests/src/com/android/server/connectivity/IpConnectivityEventBuilderTest.java b/services/tests/servicestests/src/com/android/server/connectivity/IpConnectivityEventBuilderTest.java
     deleted file mode 100644
    -index 011e505..0000000
    +index 011e505c46c..00000000000
     --- a/services/tests/servicestests/src/com/android/server/connectivity/IpConnectivityEventBuilderTest.java
     +++ /dev/null
     @@ -1,389 +0,0 @@
    @@ -13570,7 +13570,7 @@ index 011e505..0000000
     -}
     diff --git a/services/tests/servicestests/src/com/android/server/connectivity/IpConnectivityMetricsTest.java b/services/tests/servicestests/src/com/android/server/connectivity/IpConnectivityMetricsTest.java
     deleted file mode 100644
    -index 450653c..0000000
    +index 450653cdb01..00000000000
     --- a/services/tests/servicestests/src/com/android/server/connectivity/IpConnectivityMetricsTest.java
     +++ /dev/null
     @@ -1,296 +0,0 @@
    @@ -13872,7 +13872,7 @@ index 450653c..0000000
     -}
     diff --git a/services/tests/servicestests/src/com/android/server/connectivity/LingerMonitorTest.java b/services/tests/servicestests/src/com/android/server/connectivity/LingerMonitorTest.java
     deleted file mode 100644
    -index bce5787e..0000000
    +index bce5787ed9a..00000000000
     --- a/services/tests/servicestests/src/com/android/server/connectivity/LingerMonitorTest.java
     +++ /dev/null
     @@ -1,349 +0,0 @@
    @@ -14227,7 +14227,7 @@ index bce5787e..0000000
     -}
     diff --git a/services/tests/servicestests/src/com/android/server/connectivity/MetricsLoggerServiceTest.java b/services/tests/servicestests/src/com/android/server/connectivity/MetricsLoggerServiceTest.java
     deleted file mode 100644
    -index 5f84ea1..0000000
    +index 5f84ea1bfd9..00000000000
     --- a/services/tests/servicestests/src/com/android/server/connectivity/MetricsLoggerServiceTest.java
     +++ /dev/null
     @@ -1,181 +0,0 @@
    @@ -14414,7 +14414,7 @@ index 5f84ea1..0000000
     -}
     diff --git a/services/tests/servicestests/src/com/android/server/connectivity/MetricsTestUtil.java b/services/tests/servicestests/src/com/android/server/connectivity/MetricsTestUtil.java
     deleted file mode 100644
    -index e201012..0000000
    +index e2010127812..00000000000
     --- a/services/tests/servicestests/src/com/android/server/connectivity/MetricsTestUtil.java
     +++ /dev/null
     @@ -1,120 +0,0 @@
    @@ -14540,7 +14540,7 @@ index e201012..0000000
     -}
     diff --git a/services/tests/servicestests/src/com/android/server/connectivity/VpnTest.java b/services/tests/servicestests/src/com/android/server/connectivity/VpnTest.java
     deleted file mode 100644
    -index 5d8b843..0000000
    +index 5d8b843bbc1..00000000000
     --- a/services/tests/servicestests/src/com/android/server/connectivity/VpnTest.java
     +++ /dev/null
     @@ -1,310 +0,0 @@
    @@ -14856,7 +14856,7 @@ index 5d8b843..0000000
     -}
     diff --git a/services/tests/servicestests/src/com/android/server/connectivity/tethering/TetherInterfaceStateMachineTest.java b/services/tests/servicestests/src/com/android/server/connectivity/tethering/TetherInterfaceStateMachineTest.java
     deleted file mode 100644
    -index a30b362..0000000
    +index a30b3629d5c..00000000000
     --- a/services/tests/servicestests/src/com/android/server/connectivity/tethering/TetherInterfaceStateMachineTest.java
     +++ /dev/null
     @@ -1,277 +0,0 @@
    @@ -15140,7 +15140,7 @@ index a30b362..0000000
     \ No newline at end of file
     diff --git a/services/tests/servicestests/src/com/android/server/content/ObserverNodeTest.java b/services/tests/servicestests/src/com/android/server/content/ObserverNodeTest.java
     deleted file mode 100644
    -index 07280bc..0000000
    +index 07280bc881d..00000000000
     --- a/services/tests/servicestests/src/com/android/server/content/ObserverNodeTest.java
     +++ /dev/null
     @@ -1,100 +0,0 @@
    @@ -15246,7 +15246,7 @@ index 07280bc..0000000
     -}
     diff --git a/services/tests/servicestests/src/com/android/server/content/SyncManagerTest.java b/services/tests/servicestests/src/com/android/server/content/SyncManagerTest.java
     deleted file mode 100644
    -index be6861c..0000000
    +index be6861c4369..00000000000
     --- a/services/tests/servicestests/src/com/android/server/content/SyncManagerTest.java
     +++ /dev/null
     @@ -1,64 +0,0 @@
    @@ -15316,7 +15316,7 @@ index be6861c..0000000
     -}
     diff --git a/services/tests/servicestests/src/com/android/server/content/SyncOperationTest.java b/services/tests/servicestests/src/com/android/server/content/SyncOperationTest.java
     deleted file mode 100644
    -index e45b92a..0000000
    +index e45b92a1b48..00000000000
     --- a/services/tests/servicestests/src/com/android/server/content/SyncOperationTest.java
     +++ /dev/null
     @@ -1,154 +0,0 @@
    @@ -15476,7 +15476,7 @@ index e45b92a..0000000
     -}
     diff --git a/services/tests/servicestests/src/com/android/server/content/SyncStorageEngineTest.java b/services/tests/servicestests/src/com/android/server/content/SyncStorageEngineTest.java
     deleted file mode 100644
    -index 91c0de6..0000000
    +index 91c0de64cb8..00000000000
     --- a/services/tests/servicestests/src/com/android/server/content/SyncStorageEngineTest.java
     +++ /dev/null
     @@ -1,343 +0,0 @@
    @@ -15825,7 +15825,7 @@ index 91c0de6..0000000
     -}
     diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerServiceMigrationTest.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerServiceMigrationTest.java
     deleted file mode 100644
    -index 3a6b983..0000000
    +index 3a6b983854a..00000000000
     --- a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerServiceMigrationTest.java
     +++ /dev/null
     @@ -1,280 +0,0 @@
    @@ -16111,7 +16111,7 @@ index 3a6b983..0000000
     -}
     diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerServiceTestable.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerServiceTestable.java
     deleted file mode 100644
    -index 6cb4a82..0000000
    +index 6cb4a823872..00000000000
     --- a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerServiceTestable.java
     +++ /dev/null
     @@ -1,361 +0,0 @@
    @@ -16478,7 +16478,7 @@ index 6cb4a82..0000000
     -}
     diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
     deleted file mode 100644
    -index 11ec7ac..0000000
    +index 11ec7ac64ed..00000000000
     --- a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
     +++ /dev/null
     @@ -1,2186 +0,0 @@
    @@ -18670,7 +18670,7 @@ index 11ec7ac..0000000
     -}
     diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTestable.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTestable.java
     deleted file mode 100644
    -index 3da61d6..0000000
    +index 3da61d69c74..00000000000
     --- a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTestable.java
     +++ /dev/null
     @@ -1,37 +0,0 @@
    @@ -18713,7 +18713,7 @@ index 3da61d6..0000000
     -}
     diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DpmMockContext.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DpmMockContext.java
     deleted file mode 100644
    -index 956d83a..0000000
    +index 956d83a2caf..00000000000
     --- a/services/tests/servicestests/src/com/android/server/devicepolicy/DpmMockContext.java
     +++ /dev/null
     @@ -1,619 +0,0 @@
    @@ -19338,7 +19338,7 @@ index 956d83a..0000000
     -}
     diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DpmTestBase.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DpmTestBase.java
     deleted file mode 100644
    -index b4b74b3..0000000
    +index b4b74b3ec10..00000000000
     --- a/services/tests/servicestests/src/com/android/server/devicepolicy/DpmTestBase.java
     +++ /dev/null
     @@ -1,167 +0,0 @@
    @@ -19511,7 +19511,7 @@ index b4b74b3..0000000
     -}
     diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DpmTestUtils.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DpmTestUtils.java
     deleted file mode 100644
    -index cceb2d2..0000000
    +index cceb2d2761f..00000000000
     --- a/services/tests/servicestests/src/com/android/server/devicepolicy/DpmTestUtils.java
     +++ /dev/null
     @@ -1,166 +0,0 @@
    @@ -19683,7 +19683,7 @@ index cceb2d2..0000000
     -}
     diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DummyDeviceAdmins.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DummyDeviceAdmins.java
     deleted file mode 100644
    -index a0f4d97..0000000
    +index a0f4d97de1d..00000000000
     --- a/services/tests/servicestests/src/com/android/server/devicepolicy/DummyDeviceAdmins.java
     +++ /dev/null
     @@ -1,29 +0,0 @@
    @@ -19718,7 +19718,7 @@ index a0f4d97..0000000
     -}
     diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/MockUtils.java b/services/tests/servicestests/src/com/android/server/devicepolicy/MockUtils.java
     deleted file mode 100644
    -index 58db192..0000000
    +index 58db192f117..00000000000
     --- a/services/tests/servicestests/src/com/android/server/devicepolicy/MockUtils.java
     +++ /dev/null
     @@ -1,117 +0,0 @@
    @@ -19841,7 +19841,7 @@ index 58db192..0000000
     -}
     diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/OwnersTest.java b/services/tests/servicestests/src/com/android/server/devicepolicy/OwnersTest.java
     deleted file mode 100644
    -index 423c4d5..0000000
    +index 423c4d5431a..00000000000
     --- a/services/tests/servicestests/src/com/android/server/devicepolicy/OwnersTest.java
     +++ /dev/null
     @@ -1,480 +0,0 @@
    @@ -20327,7 +20327,7 @@ index 423c4d5..0000000
     -}
     diff --git a/services/tests/servicestests/src/com/android/server/job/JobStoreTest.java b/services/tests/servicestests/src/com/android/server/job/JobStoreTest.java
     deleted file mode 100644
    -index edbff83..0000000
    +index edbff83736a..00000000000
     --- a/services/tests/servicestests/src/com/android/server/job/JobStoreTest.java
     +++ /dev/null
     @@ -1,312 +0,0 @@
    @@ -20645,7 +20645,7 @@ index edbff83..0000000
     -}
     diff --git a/services/tests/servicestests/src/com/android/server/job/MockPriorityJobService.java b/services/tests/servicestests/src/com/android/server/job/MockPriorityJobService.java
     deleted file mode 100644
    -index 3ea86f2..0000000
    +index 3ea86f2e9ac..00000000000
     --- a/services/tests/servicestests/src/com/android/server/job/MockPriorityJobService.java
     +++ /dev/null
     @@ -1,106 +0,0 @@
    @@ -20757,7 +20757,7 @@ index 3ea86f2..0000000
     -}
     diff --git a/services/tests/servicestests/src/com/android/server/job/PrioritySchedulingTest.java b/services/tests/servicestests/src/com/android/server/job/PrioritySchedulingTest.java
     deleted file mode 100644
    -index 63bccfa..0000000
    +index 63bccfa0141..00000000000
     --- a/services/tests/servicestests/src/com/android/server/job/PrioritySchedulingTest.java
     +++ /dev/null
     @@ -1,119 +0,0 @@
    @@ -20882,7 +20882,7 @@ index 63bccfa..0000000
     -}
     diff --git a/services/tests/servicestests/src/com/android/server/location/ComprehensiveCountryDetectorTest.java b/services/tests/servicestests/src/com/android/server/location/ComprehensiveCountryDetectorTest.java
     deleted file mode 100644
    -index 98966c0..0000000
    +index 98966c032d1..00000000000
     --- a/services/tests/servicestests/src/com/android/server/location/ComprehensiveCountryDetectorTest.java
     +++ /dev/null
     @@ -1,299 +0,0 @@
    @@ -21187,7 +21187,7 @@ index 98966c0..0000000
     -}
     diff --git a/services/tests/servicestests/src/com/android/server/location/LocationBasedCountryDetectorTest.java b/services/tests/servicestests/src/com/android/server/location/LocationBasedCountryDetectorTest.java
     deleted file mode 100644
    -index 5f5d668..0000000
    +index 5f5d6684f38..00000000000
     --- a/services/tests/servicestests/src/com/android/server/location/LocationBasedCountryDetectorTest.java
     +++ /dev/null
     @@ -1,379 +0,0 @@
    @@ -21572,7 +21572,7 @@ index 5f5d668..0000000
     -}
     diff --git a/services/tests/servicestests/src/com/android/server/location/LocationRequestStatisticsTest.java b/services/tests/servicestests/src/com/android/server/location/LocationRequestStatisticsTest.java
     deleted file mode 100644
    -index 33f604d..0000000
    +index 33f604d9914..00000000000
     --- a/services/tests/servicestests/src/com/android/server/location/LocationRequestStatisticsTest.java
     +++ /dev/null
     @@ -1,175 +0,0 @@
    @@ -21753,7 +21753,7 @@ index 33f604d..0000000
     -}
     diff --git a/services/tests/servicestests/src/com/android/server/net/NetworkStatsAccessTest.java b/services/tests/servicestests/src/com/android/server/net/NetworkStatsAccessTest.java
     deleted file mode 100644
    -index bb8f9d1..0000000
    +index bb8f9d1a7b1..00000000000
     --- a/services/tests/servicestests/src/com/android/server/net/NetworkStatsAccessTest.java
     +++ /dev/null
     @@ -1,178 +0,0 @@
    @@ -21937,7 +21937,7 @@ index bb8f9d1..0000000
     -}
     diff --git a/services/tests/servicestests/src/com/android/server/net/NetworkStatsCollectionTest.java b/services/tests/servicestests/src/com/android/server/net/NetworkStatsCollectionTest.java
     deleted file mode 100644
    -index 9f53c87..0000000
    +index 9f53c87834e..00000000000
     --- a/services/tests/servicestests/src/com/android/server/net/NetworkStatsCollectionTest.java
     +++ /dev/null
     @@ -1,262 +0,0 @@
    @@ -22205,7 +22205,7 @@ index 9f53c87..0000000
     -}
     diff --git a/services/tests/servicestests/src/com/android/server/net/NetworkStatsObserversTest.java b/services/tests/servicestests/src/com/android/server/net/NetworkStatsObserversTest.java
     deleted file mode 100644
    -index 21560ac..0000000
    +index 21560acbf3b..00000000000
     --- a/services/tests/servicestests/src/com/android/server/net/NetworkStatsObserversTest.java
     +++ /dev/null
     @@ -1,477 +0,0 @@
    @@ -22688,7 +22688,7 @@ index 21560ac..0000000
     -}
     diff --git a/services/tests/servicestests/src/com/android/server/net/NetworkStatsServiceTest.java b/services/tests/servicestests/src/com/android/server/net/NetworkStatsServiceTest.java
     deleted file mode 100644
    -index 94c6711..0000000
    +index 94c6711da9a..00000000000
     --- a/services/tests/servicestests/src/com/android/server/net/NetworkStatsServiceTest.java
     +++ /dev/null
     @@ -1,1324 +0,0 @@
    @@ -24018,7 +24018,7 @@ index 94c6711..0000000
     -}
     diff --git a/services/tests/servicestests/src/com/android/server/notification/BuzzBeepBlinkTest.java b/services/tests/servicestests/src/com/android/server/notification/BuzzBeepBlinkTest.java
     deleted file mode 100644
    -index d51f2d8..0000000
    +index d51f2d8152a..00000000000
     --- a/services/tests/servicestests/src/com/android/server/notification/BuzzBeepBlinkTest.java
     +++ /dev/null
     @@ -1,542 +0,0 @@
    @@ -24566,7 +24566,7 @@ index d51f2d8..0000000
     -}
     diff --git a/services/tests/servicestests/src/com/android/server/notification/RankingHelperTest.java b/services/tests/servicestests/src/com/android/server/notification/RankingHelperTest.java
     deleted file mode 100644
    -index 32501ad..0000000
    +index 32501ad8878..00000000000
     --- a/services/tests/servicestests/src/com/android/server/notification/RankingHelperTest.java
     +++ /dev/null
     @@ -1,143 +0,0 @@
    @@ -24715,7 +24715,7 @@ index 32501ad..0000000
     -}
     diff --git a/services/tests/servicestests/src/com/android/server/notification/RateEstimatorTest.java b/services/tests/servicestests/src/com/android/server/notification/RateEstimatorTest.java
     deleted file mode 100644
    -index 3278cf1..0000000
    +index 3278cf1c0b7..00000000000
     --- a/services/tests/servicestests/src/com/android/server/notification/RateEstimatorTest.java
     +++ /dev/null
     @@ -1,152 +0,0 @@
    @@ -24873,7 +24873,7 @@ index 3278cf1..0000000
     -}
     diff --git a/services/tests/servicestests/src/com/android/server/notification/ValidateNotificationPeopleTest.java b/services/tests/servicestests/src/com/android/server/notification/ValidateNotificationPeopleTest.java
     deleted file mode 100644
    -index a6fdee9..0000000
    +index a6fdee9ce42..00000000000
     --- a/services/tests/servicestests/src/com/android/server/notification/ValidateNotificationPeopleTest.java
     +++ /dev/null
     @@ -1,152 +0,0 @@
    @@ -25031,7 +25031,7 @@ index a6fdee9..0000000
     -}
     diff --git a/services/tests/servicestests/src/com/android/server/pm/BaseShortcutManagerTest.java b/services/tests/servicestests/src/com/android/server/pm/BaseShortcutManagerTest.java
     deleted file mode 100644
    -index 792f300..0000000
    +index 792f3001c04..00000000000
     --- a/services/tests/servicestests/src/com/android/server/pm/BaseShortcutManagerTest.java
     +++ /dev/null
     @@ -1,1952 +0,0 @@
    @@ -26989,7 +26989,7 @@ index 792f300..0000000
     -}
     diff --git a/services/tests/servicestests/src/com/android/server/pm/KeySetManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/pm/KeySetManagerServiceTest.java
     deleted file mode 100644
    -index ba83be1..0000000
    +index ba83be19bed..00000000000
     --- a/services/tests/servicestests/src/com/android/server/pm/KeySetManagerServiceTest.java
     +++ /dev/null
     @@ -1,804 +0,0 @@
    @@ -27799,7 +27799,7 @@ index ba83be1..0000000
     -}
     diff --git a/services/tests/servicestests/src/com/android/server/pm/KeySetStrings.java b/services/tests/servicestests/src/com/android/server/pm/KeySetStrings.java
     deleted file mode 100644
    -index 89d01ae..0000000
    +index 89d01ae3cd9..00000000000
     --- a/services/tests/servicestests/src/com/android/server/pm/KeySetStrings.java
     +++ /dev/null
     @@ -1,137 +0,0 @@
    @@ -27942,7 +27942,7 @@ index 89d01ae..0000000
     -}
     diff --git a/services/tests/servicestests/src/com/android/server/pm/KeySetUtils.java b/services/tests/servicestests/src/com/android/server/pm/KeySetUtils.java
     deleted file mode 100644
    -index 9e1a366..0000000
    +index 9e1a366c8fc..00000000000
     --- a/services/tests/servicestests/src/com/android/server/pm/KeySetUtils.java
     +++ /dev/null
     @@ -1,89 +0,0 @@
    @@ -28037,7 +28037,7 @@ index 9e1a366..0000000
     -}
     diff --git a/services/tests/servicestests/src/com/android/server/pm/PackageManagerSettingsTests.java b/services/tests/servicestests/src/com/android/server/pm/PackageManagerSettingsTests.java
     deleted file mode 100644
    -index bf6343f..0000000
    +index bf6343f9c23..00000000000
     --- a/services/tests/servicestests/src/com/android/server/pm/PackageManagerSettingsTests.java
     +++ /dev/null
     @@ -1,349 +0,0 @@
    @@ -28392,7 +28392,7 @@ index bf6343f..0000000
     -}
     diff --git a/services/tests/servicestests/src/com/android/server/pm/PackageVerificationStateTest.java b/services/tests/servicestests/src/com/android/server/pm/PackageVerificationStateTest.java
     deleted file mode 100644
    -index ebd3633..0000000
    +index ebd363386fa..00000000000
     --- a/services/tests/servicestests/src/com/android/server/pm/PackageVerificationStateTest.java
     +++ /dev/null
     @@ -1,205 +0,0 @@
    @@ -28603,7 +28603,7 @@ index ebd3633..0000000
     -}
     diff --git a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest1.java b/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest1.java
     deleted file mode 100644
    -index cd48f36..0000000
    +index cd48f36ade5..00000000000
     --- a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest1.java
     +++ /dev/null
     @@ -1,7349 +0,0 @@
    @@ -35958,7 +35958,7 @@ index cd48f36..0000000
     -}
     diff --git a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest2.java b/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest2.java
     deleted file mode 100644
    -index d25923c..0000000
    +index d25923c019c..00000000000
     --- a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest2.java
     +++ /dev/null
     @@ -1,2040 +0,0 @@
    @@ -38004,7 +38004,7 @@ index d25923c..0000000
     -}
     diff --git a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest3.java b/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest3.java
     deleted file mode 100644
    -index eb4db7a..0000000
    +index eb4db7a0f4a..00000000000
     --- a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest3.java
     +++ /dev/null
     @@ -1,505 +0,0 @@
    @@ -38515,7 +38515,7 @@ index eb4db7a..0000000
     -}
     diff --git a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest4.java b/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest4.java
     deleted file mode 100644
    -index 583c3d4..0000000
    +index 583c3d41c40..00000000000
     --- a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest4.java
     +++ /dev/null
     @@ -1,126 +0,0 @@
    @@ -38648,7 +38648,7 @@ index 583c3d4..0000000
     \ No newline at end of file
     diff --git a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest5.java b/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest5.java
     deleted file mode 100644
    -index 29c98dc..0000000
    +index 29c98dcf522..00000000000
     --- a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest5.java
     +++ /dev/null
     @@ -1,202 +0,0 @@
    @@ -38856,7 +38856,7 @@ index 29c98dc..0000000
     -}
     diff --git a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest6.java b/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest6.java
     deleted file mode 100644
    -index ba4dbc1..0000000
    +index ba4dbc1d258..00000000000
     --- a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest6.java
     +++ /dev/null
     @@ -1,281 +0,0 @@
    @@ -39143,7 +39143,7 @@ index ba4dbc1..0000000
     -}
     diff --git a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest7.java b/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest7.java
     deleted file mode 100644
    -index 3c99174..0000000
    +index 3c99174142c..00000000000
     --- a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest7.java
     +++ /dev/null
     @@ -1,339 +0,0 @@
    @@ -39488,7 +39488,7 @@ index 3c99174..0000000
     -}
     diff --git a/services/tests/servicestests/src/com/android/server/pm/ShortcutTestActivity.java b/services/tests/servicestests/src/com/android/server/pm/ShortcutTestActivity.java
     deleted file mode 100644
    -index d82b0d5..0000000
    +index d82b0d55f2a..00000000000
     --- a/services/tests/servicestests/src/com/android/server/pm/ShortcutTestActivity.java
     +++ /dev/null
     @@ -1,21 +0,0 @@
    @@ -39515,7 +39515,7 @@ index d82b0d5..0000000
     -}
     diff --git a/services/tests/servicestests/src/com/android/server/pm/UserManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/pm/UserManagerServiceTest.java
     deleted file mode 100644
    -index 9f77297..0000000
    +index 9f77297b49d..00000000000
     --- a/services/tests/servicestests/src/com/android/server/pm/UserManagerServiceTest.java
     +++ /dev/null
     @@ -1,121 +0,0 @@
    @@ -39642,7 +39642,7 @@ index 9f77297..0000000
     -}
     diff --git a/services/tests/servicestests/src/com/android/server/pm/UserManagerTest.java b/services/tests/servicestests/src/com/android/server/pm/UserManagerTest.java
     deleted file mode 100644
    -index ced4980..0000000
    +index ced4980df52..00000000000
     --- a/services/tests/servicestests/src/com/android/server/pm/UserManagerTest.java
     +++ /dev/null
     @@ -1,278 +0,0 @@
    @@ -39926,7 +39926,7 @@ index ced4980..0000000
     -}
     diff --git a/services/tests/servicestests/src/com/android/server/pm/UserRestrictionsUtilsTest.java b/services/tests/servicestests/src/com/android/server/pm/UserRestrictionsUtilsTest.java
     deleted file mode 100644
    -index 11f9ebb..0000000
    +index 11f9ebb52f4..00000000000
     --- a/services/tests/servicestests/src/com/android/server/pm/UserRestrictionsUtilsTest.java
     +++ /dev/null
     @@ -1,207 +0,0 @@
    @@ -40139,7 +40139,7 @@ index 11f9ebb..0000000
     -}
     diff --git a/services/tests/servicestests/src/com/android/server/pm/backup/BackupUtilsTest.java b/services/tests/servicestests/src/com/android/server/pm/backup/BackupUtilsTest.java
     deleted file mode 100644
    -index c016e61..0000000
    +index c016e610475..00000000000
     --- a/services/tests/servicestests/src/com/android/server/pm/backup/BackupUtilsTest.java
     +++ /dev/null
     @@ -1,118 +0,0 @@
    @@ -40263,7 +40263,7 @@ index c016e61..0000000
     -}
     diff --git a/services/tests/servicestests/src/com/android/server/search/SearchablesTest.java b/services/tests/servicestests/src/com/android/server/search/SearchablesTest.java
     deleted file mode 100644
    -index 0f9bf2f..0000000
    +index 0f9bf2f6cd8..00000000000
     --- a/services/tests/servicestests/src/com/android/server/search/SearchablesTest.java
     +++ /dev/null
     @@ -1,449 +0,0 @@
    @@ -40718,7 +40718,7 @@ index 0f9bf2f..0000000
     -
     diff --git a/services/tests/servicestests/src/com/android/server/testutis/TestUtils.java b/services/tests/servicestests/src/com/android/server/testutis/TestUtils.java
     deleted file mode 100644
    -index d2a4484..0000000
    +index d2a44841ee0..00000000000
     --- a/services/tests/servicestests/src/com/android/server/testutis/TestUtils.java
     +++ /dev/null
     @@ -1,42 +0,0 @@
    @@ -40766,7 +40766,7 @@ index d2a4484..0000000
     -}
     diff --git a/services/tests/servicestests/src/com/android/server/updates/CertPinInstallReceiverTest.java b/services/tests/servicestests/src/com/android/server/updates/CertPinInstallReceiverTest.java
     deleted file mode 100644
    -index d798518..0000000
    +index d79851817f8..00000000000
     --- a/services/tests/servicestests/src/com/android/server/updates/CertPinInstallReceiverTest.java
     +++ /dev/null
     @@ -1,245 +0,0 @@
    @@ -41017,7 +41017,7 @@ index d798518..0000000
     -}
     diff --git a/services/tests/servicestests/src/com/android/server/usage/AppIdleHistoryTests.java b/services/tests/servicestests/src/com/android/server/usage/AppIdleHistoryTests.java
     deleted file mode 100644
    -index 0bd014c..0000000
    +index 0bd014c874b..00000000000
     --- a/services/tests/servicestests/src/com/android/server/usage/AppIdleHistoryTests.java
     +++ /dev/null
     @@ -1,100 +0,0 @@
    @@ -41124,7 +41124,7 @@ index 0bd014c..0000000
     \ No newline at end of file
     diff --git a/services/tests/servicestests/src/com/android/server/webkit/TestSystemImpl.java b/services/tests/servicestests/src/com/android/server/webkit/TestSystemImpl.java
     deleted file mode 100644
    -index e33be40..0000000
    +index e33be400a84..00000000000
     --- a/services/tests/servicestests/src/com/android/server/webkit/TestSystemImpl.java
     +++ /dev/null
     @@ -1,116 +0,0 @@
    @@ -41246,7 +41246,7 @@ index e33be40..0000000
     -}
     diff --git a/services/tests/servicestests/src/com/android/server/webkit/WebViewUpdateServiceTest.java b/services/tests/servicestests/src/com/android/server/webkit/WebViewUpdateServiceTest.java
     deleted file mode 100644
    -index b737033..0000000
    +index b7370331ad0..00000000000
     --- a/services/tests/servicestests/src/com/android/server/webkit/WebViewUpdateServiceTest.java
     +++ /dev/null
     @@ -1,1074 +0,0 @@
    @@ -42326,7 +42326,7 @@ index b737033..0000000
     -}
     diff --git a/services/tests/shortcutmanagerutils/Android.mk b/services/tests/shortcutmanagerutils/Android.mk
     deleted file mode 100644
    -index 2818457..0000000
    +index 2818457c9ac..00000000000
     --- a/services/tests/shortcutmanagerutils/Android.mk
     +++ /dev/null
     @@ -1,31 +0,0 @@
    @@ -42363,7 +42363,7 @@ index 2818457..0000000
     -include $(BUILD_STATIC_JAVA_LIBRARY)
     diff --git a/services/tests/shortcutmanagerutils/src/com/android/server/pm/shortcutmanagertest/ShortcutManagerTestUtils.java b/services/tests/shortcutmanagerutils/src/com/android/server/pm/shortcutmanagertest/ShortcutManagerTestUtils.java
     deleted file mode 100644
    -index 1fe5cb7..0000000
    +index 1fe5cb78231..00000000000
     --- a/services/tests/shortcutmanagerutils/src/com/android/server/pm/shortcutmanagertest/ShortcutManagerTestUtils.java
     +++ /dev/null
     @@ -1,1073 +0,0 @@
    @@ -43441,7 +43441,7 @@ index 1fe5cb7..0000000
     -    }
     -}
     diff --git a/telephony/java/com/android/internal/telephony/DcParamObject.java b/telephony/java/com/android/internal/telephony/DcParamObject.java
    -index 139939c..fc6b610 100644
    +index 139939cbd0c..fc6b6106113 100644
     --- a/telephony/java/com/android/internal/telephony/DcParamObject.java
     +++ b/telephony/java/com/android/internal/telephony/DcParamObject.java
     @@ -36,7 +36,7 @@ public class DcParamObject implements Parcelable {
    @@ -43454,7 +43454,7 @@ index 139939c..fc6b610 100644
      
          private void readFromParcel(Parcel in) {
     diff --git a/wifi/java/android/net/wifi/RttManager.java b/wifi/java/android/net/wifi/RttManager.java
    -index 590ff1b..8c96774 100644
    +index 590ff1b1bfa..8c96774eaea 100644
     --- a/wifi/java/android/net/wifi/RttManager.java
     +++ b/wifi/java/android/net/wifi/RttManager.java
     @@ -766,8 +766,8 @@ public class RttManager {
    diff --git a/frameworks_native.patch b/frameworks_native.patch
    index 042a494..6e4f90b 100644
    --- a/frameworks_native.patch
    +++ b/frameworks_native.patch
    @@ -1,5 +1,5 @@
     diff --git a/build/phone-xhdpi-1024-dalvik-heap.mk b/build/phone-xhdpi-1024-dalvik-heap.mk
    -index 221227d..5707b1d 100644
    +index 221227d4d..5707b1d1b 100644
     --- a/build/phone-xhdpi-1024-dalvik-heap.mk
     +++ b/build/phone-xhdpi-1024-dalvik-heap.mk
     @@ -18,7 +18,7 @@
    @@ -12,7 +12,7 @@ index 221227d..5707b1d 100644
          dalvik.vm.heaptargetutilization=0.75 \
          dalvik.vm.heapminfree=512k \
     diff --git a/build/tablet-7in-hdpi-1024-dalvik-heap.mk b/build/tablet-7in-hdpi-1024-dalvik-heap.mk
    -index 7fd34b5..e61c40b 100644
    +index 7fd34b5f1..e61c40ba1 100644
     --- a/build/tablet-7in-hdpi-1024-dalvik-heap.mk
     +++ b/build/tablet-7in-hdpi-1024-dalvik-heap.mk
     @@ -18,7 +18,7 @@
    @@ -25,7 +25,7 @@ index 7fd34b5..e61c40b 100644
          dalvik.vm.heaptargetutilization=0.75 \
          dalvik.vm.heapminfree=512k \
     diff --git a/cmds/atrace/atrace.cpp b/cmds/atrace/atrace.cpp
    -index 5885738..86c315c 100644
    +index 5885738e9..86c315cec 100644
     --- a/cmds/atrace/atrace.cpp
     +++ b/cmds/atrace/atrace.cpp
     @@ -594,16 +594,30 @@ static bool verifyKernelTraceFuncs(const char* funcs)
    @@ -78,7 +78,7 @@ index 5885738..86c315c 100644
      }
      
     diff --git a/cmds/flatland/GLHelper.cpp b/cmds/flatland/GLHelper.cpp
    -index ddf3aa8..5c04f6c 100644
    +index ddf3aa868..5c04f6cf1 100644
     --- a/cmds/flatland/GLHelper.cpp
     +++ b/cmds/flatland/GLHelper.cpp
     @@ -365,6 +365,7 @@ static bool compileShaderLines(GLenum shaderType, const char* const* lines,
    @@ -90,7 +90,7 @@ index ddf3aa8..5c04f6c 100644
          }
          delete[] src;
     diff --git a/cmds/installd/commands.cpp b/cmds/installd/commands.cpp
    -index 271c75b..cadcd1e 100644
    +index 271c75ba4..cadcd1ef1 100644
     --- a/cmds/installd/commands.cpp
     +++ b/cmds/installd/commands.cpp
     @@ -238,11 +238,15 @@ int migrate_app_data(const char *uuid, const char *pkgname, userid_t userid, int
    @@ -113,7 +113,7 @@ index 271c75b..cadcd1e 100644
              }
          }
     diff --git a/include/binder/Parcel.h b/include/binder/Parcel.h
    -index 2490b82..2b61151 100644
    +index 2490b82bb..2b6115121 100644
     --- a/include/binder/Parcel.h
     +++ b/include/binder/Parcel.h
     @@ -375,7 +375,8 @@ private:
    @@ -150,7 +150,7 @@ index 2490b82..2b61151 100644
          };
          status_t write(const FlattenableHelperInterface& val);
     diff --git a/include/gui/ISurfaceComposer.h b/include/gui/ISurfaceComposer.h
    -index 74a4123..8dc6f6a 100644
    +index 74a4123bb..8dc6f6a9d 100644
     --- a/include/gui/ISurfaceComposer.h
     +++ b/include/gui/ISurfaceComposer.h
     @@ -32,6 +32,12 @@
    @@ -178,7 +178,7 @@ index 74a4123..8dc6f6a 100644
           *
     diff --git a/include/ui/FramebufferNativeWindow.h b/include/ui/FramebufferNativeWindow.h
     new file mode 100644
    -index 0000000..2eb1cc1
    +index 000000000..2eb1cc16e
     --- /dev/null
     +++ b/include/ui/FramebufferNativeWindow.h
     @@ -0,0 +1,102 @@
    @@ -285,7 +285,7 @@ index 0000000..2eb1cc1
     +#endif // ANDROID_FRAMEBUFFER_NATIVE_WINDOW_H
     +
     diff --git a/libs/binder/AppOpsManager.cpp b/libs/binder/AppOpsManager.cpp
    -index 9a061a0..8f97544 100644
    +index 9a061a0ce..8f97544d5 100644
     --- a/libs/binder/AppOpsManager.cpp
     +++ b/libs/binder/AppOpsManager.cpp
     @@ -53,7 +53,8 @@ sp<IAppOpsService> AppOpsManager::getService()
    @@ -299,7 +299,7 @@ index 9a061a0..8f97544 100644
                  sleep(1);
              } else {
     diff --git a/libs/binder/Binder.cpp b/libs/binder/Binder.cpp
    -index c4d47ca..d04074e 100644
    +index c4d47caed..d04074eed 100644
     --- a/libs/binder/Binder.cpp
     +++ b/libs/binder/Binder.cpp
     @@ -240,6 +240,8 @@ status_t BBinder::onTransact(
    @@ -312,7 +312,7 @@ index c4d47ca..d04074e 100644
      
              case SYSPROPS_TRANSACTION: {
     diff --git a/libs/binder/IPCThreadState.cpp b/libs/binder/IPCThreadState.cpp
    -index eccc400..3efebf7 100644
    +index eccc400c0..3efebf7ea 100644
     --- a/libs/binder/IPCThreadState.cpp
     +++ b/libs/binder/IPCThreadState.cpp
     @@ -331,6 +331,7 @@ void IPCThreadState::shutdown()
    @@ -324,7 +324,7 @@ index eccc400..3efebf7 100644
          }
      }
     diff --git a/libs/binder/Parcel.cpp b/libs/binder/Parcel.cpp
    -index 19ce3eb..e6630d5 100644
    +index 19ce3ebae..e6630d549 100644
     --- a/libs/binder/Parcel.cpp
     +++ b/libs/binder/Parcel.cpp
     @@ -459,6 +459,7 @@ void Parcel::setDataPosition(size_t pos) const
    @@ -469,7 +469,7 @@ index 19ce3eb..e6630d5 100644
      
              // We own the data, so we can just do a realloc().
     diff --git a/libs/binder/ProcessState.cpp b/libs/binder/ProcessState.cpp
    -index f13f49f..e45b5f1 100644
    +index f13f49fe9..e45b5f1ff 100644
     --- a/libs/binder/ProcessState.cpp
     +++ b/libs/binder/ProcessState.cpp
     @@ -366,6 +366,13 @@ ProcessState::ProcessState()
    @@ -487,7 +487,7 @@ index f13f49f..e45b5f1 100644
              
      }; // namespace android
     diff --git a/libs/binder/tests/binderDriverInterfaceTest.cpp b/libs/binder/tests/binderDriverInterfaceTest.cpp
    -index 0277550..d8fd81c 100644
    +index 027755025..d8fd81c92 100644
     --- a/libs/binder/tests/binderDriverInterfaceTest.cpp
     +++ b/libs/binder/tests/binderDriverInterfaceTest.cpp
     @@ -77,6 +77,16 @@ class BinderDriverInterfaceTest : public ::testing::Test {
    @@ -517,7 +517,7 @@ index 0277550..d8fd81c 100644
          EXPECT_EQ(sizeof(bc1), bwr.write_consumed);
          if (bwr.read_consumed < offsetof(typeof(br), pad)) {
     diff --git a/libs/gui/Android.mk b/libs/gui/Android.mk
    -index 9e2fc2b..12d2148 100644
    +index 9e2fc2b04..12d21488e 100644
     --- a/libs/gui/Android.mk
     +++ b/libs/gui/Android.mk
     @@ -86,6 +86,9 @@ LOCAL_SHARED_LIBRARIES := \
    @@ -531,7 +531,7 @@ index 9e2fc2b..12d2148 100644
      LOCAL_MODULE := libgui
      
     diff --git a/libs/gui/BufferQueueProducer.cpp b/libs/gui/BufferQueueProducer.cpp
    -index ff85eb5..6dc7fec 100644
    +index ff85eb5ce..6dc7fec34 100644
     --- a/libs/gui/BufferQueueProducer.cpp
     +++ b/libs/gui/BufferQueueProducer.cpp
     @@ -721,6 +721,7 @@ status_t BufferQueueProducer::attachBuffer(int* outSlot,
    @@ -567,7 +567,7 @@ index ff85eb5..6dc7fec 100644
                          format : mCore->mDefaultBufferFormat;
                  uint32_t checkUsage = usage | mCore->mConsumerUsageBits;
     diff --git a/libs/gui/ISurfaceComposer.cpp b/libs/gui/ISurfaceComposer.cpp
    -index f0b0ada..3577a33 100644
    +index f0b0ada27..3577a331a 100644
     --- a/libs/gui/ISurfaceComposer.cpp
     +++ b/libs/gui/ISurfaceComposer.cpp
     @@ -106,7 +106,8 @@ public:
    @@ -604,7 +604,7 @@ index f0b0ada..3577a33 100644
                  return NO_ERROR;
              }
     diff --git a/libs/gui/Surface.cpp b/libs/gui/Surface.cpp
    -index 5a2ca8d..16ccbc3 100644
    +index 5a2ca8d7a..16ccbc30e 100644
     --- a/libs/gui/Surface.cpp
     +++ b/libs/gui/Surface.cpp
     @@ -1266,6 +1266,7 @@ status_t Surface::lock(
    @@ -660,7 +660,7 @@ index 5a2ca8d..16ccbc3 100644
                  *inOutDirtyBounds = newDirtyRegion.getBounds();
              }
     diff --git a/libs/ui/Android.mk b/libs/ui/Android.mk
    -index e690ede..3927031 100644
    +index e690ede19..392703167 100644
     --- a/libs/ui/Android.mk
     +++ b/libs/ui/Android.mk
     @@ -36,6 +36,7 @@ LOCAL_CPPFLAGS += -Wno-padded
    @@ -673,7 +673,7 @@ index e690ede..3927031 100644
      	Gralloc1On0Adapter.cpp \
     diff --git a/libs/ui/FramebufferNativeWindow.cpp b/libs/ui/FramebufferNativeWindow.cpp
     new file mode 100644
    -index 0000000..3ead25c
    +index 000000000..3ead25cfe
     --- /dev/null
     +++ b/libs/ui/FramebufferNativeWindow.cpp
     @@ -0,0 +1,372 @@
    @@ -1050,7 +1050,7 @@ index 0000000..3ead25c
     +    return static_cast<EGLNativeWindowType>(w);
     +}
     diff --git a/libs/ui/GraphicBuffer.cpp b/libs/ui/GraphicBuffer.cpp
    -index 97b948d..0bb0941 100644
    +index 97b948d97..0bb0941ad 100644
     --- a/libs/ui/GraphicBuffer.cpp
     +++ b/libs/ui/GraphicBuffer.cpp
     @@ -394,6 +394,7 @@ status_t GraphicBuffer::unflatten(
    @@ -1062,7 +1062,7 @@ index 97b948d..0bb0941 100644
                  ALOGE("unflatten: registerBuffer failed: %s (%d)",
                          strerror(-err), err);
     diff --git a/libs/ui/Region.cpp b/libs/ui/Region.cpp
    -index ee152bf..9c82295 100644
    +index ee152bf91..9c82295bb 100644
     --- a/libs/ui/Region.cpp
     +++ b/libs/ui/Region.cpp
     @@ -800,6 +800,11 @@ status_t Region::unflatten(void const* buffer, size_t size) {
    @@ -1078,7 +1078,7 @@ index ee152bf..9c82295 100644
          result.mStorage.clear();
          for (size_t r = 0; r < numRects; ++r) {
     diff --git a/opengl/libs/Android.mk b/opengl/libs/Android.mk
    -index 24e4c19..54e9d59 100644
    +index 24e4c19a5..54e9d59ae 100644
     --- a/opengl/libs/Android.mk
     +++ b/opengl/libs/Android.mk
     @@ -42,9 +42,15 @@ LOCAL_CFLAGS += -DLOG_TAG=\"libEGL\"
    @@ -1122,7 +1122,7 @@ index 24e4c19..54e9d59 100644
      LOCAL_SHARED_LIBRARIES += libcutils libutils liblog libEGL
      LOCAL_MODULE:= libGLESv3
     diff --git a/opengl/libs/EGL/eglApi.cpp b/opengl/libs/EGL/eglApi.cpp
    -index 436ea30..58b625e 100644
    +index 436ea3080..58b625ee9 100644
     --- a/opengl/libs/EGL/eglApi.cpp
     +++ b/opengl/libs/EGL/eglApi.cpp
     @@ -487,11 +487,17 @@ EGLSurface eglCreateWindowSurface(  EGLDisplay dpy, EGLConfig config,
    @@ -1155,7 +1155,7 @@ index 436ea30..58b625e 100644
              // now select a corresponding sRGB format if needed
              if (attrib_list && dp->haveExtension("EGL_KHR_gl_colorspace")) {
     diff --git a/opengl/libs/EGL/egl_object.cpp b/opengl/libs/EGL/egl_object.cpp
    -index cfecf77..4d9f77f 100644
    +index cfecf7702..4d9f77fbe 100644
     --- a/opengl/libs/EGL/egl_object.cpp
     +++ b/opengl/libs/EGL/egl_object.cpp
     @@ -124,19 +124,25 @@ void egl_context_t::onMakeCurrent(EGLSurface draw, EGLSurface read) {
    @@ -1197,7 +1197,7 @@ index cfecf77..4d9f77f 100644
          }
      }
     diff --git a/opengl/libs/EGL/getProcAddress.cpp b/opengl/libs/EGL/getProcAddress.cpp
    -index 336c264..bb72e79 100644
    +index 336c2642a..bb72e79f0 100644
     --- a/opengl/libs/EGL/getProcAddress.cpp
     +++ b/opengl/libs/EGL/getProcAddress.cpp
     @@ -40,6 +40,27 @@ namespace android {
    @@ -1355,7 +1355,7 @@ index 336c264..bb72e79 100644
      
      GL_EXTENSION_LIST( GL_EXTENSION )
     diff --git a/opengl/libs/GLES2/gl2.cpp b/opengl/libs/GLES2/gl2.cpp
    -index 6034a8e..6dd87c2 100644
    +index 6034a8edc..6dd87c28e 100644
     --- a/opengl/libs/GLES2/gl2.cpp
     +++ b/opengl/libs/GLES2/gl2.cpp
     @@ -34,39 +34,65 @@ using namespace android;
    @@ -1700,7 +1700,7 @@ index 6034a8e..6dd87c2 100644
      
      /*
     diff --git a/opengl/libs/GLES_CM/gl.cpp b/opengl/libs/GLES_CM/gl.cpp
    -index b1b31f8..8bde4e5 100644
    +index b1b31f829..8bde4e5f0 100644
     --- a/opengl/libs/GLES_CM/gl.cpp
     +++ b/opengl/libs/GLES_CM/gl.cpp
     @@ -90,39 +90,65 @@ GL_API void GL_APIENTRY glWeightPointerOESBounds(GLint size, GLenum type,
    @@ -2044,7 +2044,7 @@ index b1b31f8..8bde4e5 100644
      
      /*
     diff --git a/opengl/libs/hooks.h b/opengl/libs/hooks.h
    -index e14075c..18b1b76 100644
    +index e14075cdb..18b1b7601 100644
     --- a/opengl/libs/hooks.h
     +++ b/opengl/libs/hooks.h
     @@ -43,7 +43,11 @@
    @@ -2060,7 +2060,7 @@ index e14075c..18b1b76 100644
      
      #include <bionic_tls.h>  /* special private C library header */
     diff --git a/services/inputflinger/InputDispatcher.cpp b/services/inputflinger/InputDispatcher.cpp
    -index 3f69d49..e48c53a 100644
    +index 3f69d49f0..e48c53a08 100644
     --- a/services/inputflinger/InputDispatcher.cpp
     +++ b/services/inputflinger/InputDispatcher.cpp
     @@ -1224,15 +1224,8 @@ int32_t InputDispatcher::findTouchedWindowTargetsLocked(nsecs_t currentTime,
    @@ -2081,7 +2081,7 @@ index 3f69d49..e48c53a 100644
                  }
              }
     diff --git a/services/inputflinger/InputManager.cpp b/services/inputflinger/InputManager.cpp
    -index 6a6547b..2ef25f3 100644
    +index 6a6547bdf..2ef25f315 100644
     --- a/services/inputflinger/InputManager.cpp
     +++ b/services/inputflinger/InputManager.cpp
     @@ -20,6 +20,7 @@
    @@ -2121,7 +2121,7 @@ index 6a6547b..2ef25f3 100644
      }
      
     diff --git a/services/inputflinger/InputReader.cpp b/services/inputflinger/InputReader.cpp
    -index b9be675..eff3deb 100644
    +index b9be67568..eff3debc2 100644
     --- a/services/inputflinger/InputReader.cpp
     +++ b/services/inputflinger/InputReader.cpp
     @@ -2169,6 +2169,10 @@ void KeyboardInputMapper::configure(nsecs_t when,
    @@ -2230,7 +2230,7 @@ index b9be675..eff3deb 100644
          }
      
     diff --git a/services/inputflinger/InputReader.h b/services/inputflinger/InputReader.h
    -index 076f3d6..52cfb72 100644
    +index 076f3d651..52cfb727e 100644
     --- a/services/inputflinger/InputReader.h
     +++ b/services/inputflinger/InputReader.h
     @@ -144,6 +144,9 @@ struct InputReaderConfiguration {
    @@ -2282,7 +2282,7 @@ index 076f3d6..52cfb72 100644
      
          void resetLedState();
     diff --git a/services/inputflinger/InputWindow.h b/services/inputflinger/InputWindow.h
    -index e243637..4794b47 100644
    +index e243637ed..4794b47cb 100644
     --- a/services/inputflinger/InputWindow.h
     +++ b/services/inputflinger/InputWindow.h
     @@ -101,7 +101,7 @@ struct InputWindowInfo {
    @@ -2295,7 +2295,7 @@ index e243637..4794b47 100644
              LAST_SYSTEM_WINDOW      = 2999,
          };
     diff --git a/services/surfaceflinger/Android.mk b/services/surfaceflinger/Android.mk
    -index ffda035..52d4a8b 100644
    +index ffda035a9..52d4a8b39 100644
     --- a/services/surfaceflinger/Android.mk
     +++ b/services/surfaceflinger/Android.mk
     @@ -54,8 +54,15 @@ else
    @@ -2346,7 +2346,7 @@ index ffda035..52d4a8b 100644
      
      ifneq ($(PRESENT_TIME_OFFSET_FROM_VSYNC_NS),)
     diff --git a/services/surfaceflinger/DispSync.cpp b/services/surfaceflinger/DispSync.cpp
    -index 1a9820d..b45e00a 100644
    +index 1a9820d95..b45e00acd 100644
     --- a/services/surfaceflinger/DispSync.cpp
     +++ b/services/surfaceflinger/DispSync.cpp
     @@ -22,6 +22,7 @@
    @@ -2366,7 +2366,7 @@ index 1a9820d..b45e00a 100644
          reset();
          beginResync();
     diff --git a/services/surfaceflinger/DisplayDevice.cpp b/services/surfaceflinger/DisplayDevice.cpp
    -index 5c2c0ad..1f2e554 100644
    +index 5c2c0adf3..1f2e554bd 100644
     --- a/services/surfaceflinger/DisplayDevice.cpp
     +++ b/services/surfaceflinger/DisplayDevice.cpp
     @@ -166,7 +166,7 @@ DisplayDevice::DisplayDevice(
    @@ -2379,7 +2379,7 @@ index 5c2c0ad..1f2e554 100644
      }
      
     diff --git a/services/surfaceflinger/DisplayHardware/HWComposer_hwc1.cpp b/services/surfaceflinger/DisplayHardware/HWComposer_hwc1.cpp
    -index ef41658..138d20a 100644
    +index ef416581a..138d20ae5 100644
     --- a/services/surfaceflinger/DisplayHardware/HWComposer_hwc1.cpp
     +++ b/services/surfaceflinger/DisplayHardware/HWComposer_hwc1.cpp
     @@ -111,6 +111,10 @@ HWComposer::HWComposer(
    @@ -2449,7 +2449,7 @@ index ef41658..138d20a 100644
              mHwc->dump(mHwc, buffer, SIZE);
              result.append(buffer);
     diff --git a/services/surfaceflinger/DisplayHardware/HWComposer_hwc1.h b/services/surfaceflinger/DisplayHardware/HWComposer_hwc1.h
    -index 170e382..0f0c65d 100644
    +index 170e38233..0f0c65d49 100644
     --- a/services/surfaceflinger/DisplayHardware/HWComposer_hwc1.h
     +++ b/services/surfaceflinger/DisplayHardware/HWComposer_hwc1.h
     @@ -236,6 +236,9 @@ public:
    @@ -2463,7 +2463,7 @@ index 170e382..0f0c65d 100644
      
          // Returns an iterator to the beginning of the layer list
     diff --git a/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp b/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp
    -index 2190466..8c36d85 100644
    +index 2190466ad..8c36d85ee 100644
     --- a/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp
     +++ b/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp
     @@ -344,6 +344,13 @@ status_t VirtualDisplaySurface::dequeueBuffer(Source source,
    @@ -2481,7 +2481,7 @@ index 2190466..8c36d85 100644
                  mSinkBufferWidth, mSinkBufferHeight, format, usage);
          if (result < 0)
     diff --git a/services/surfaceflinger/EventThread.cpp b/services/surfaceflinger/EventThread.cpp
    -index dd88adb..2dacd87 100644
    +index dd88adb36..2dacd871a 100644
     --- a/services/surfaceflinger/EventThread.cpp
     +++ b/services/surfaceflinger/EventThread.cpp
     @@ -20,6 +20,7 @@
    @@ -2501,7 +2501,7 @@ index dd88adb..2dacd87 100644
      
      sp<EventThread::Connection> EventThread::createEventConnection() const {
     diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
    -index 3ffa655..f8de24d 100644
    +index 3ffa6554a..f8de24d97 100644
     --- a/services/surfaceflinger/Layer.cpp
     +++ b/services/surfaceflinger/Layer.cpp
     @@ -55,6 +55,7 @@
    @@ -2542,7 +2542,7 @@ index 3ffa655..f8de24d 100644
              }
      
     diff --git a/services/surfaceflinger/RenderEngine/GLES11RenderEngine.cpp b/services/surfaceflinger/RenderEngine/GLES11RenderEngine.cpp
    -index 847cdb3..b2821b7 100644
    +index 847cdb388..b2821b7d8 100644
     --- a/services/surfaceflinger/RenderEngine/GLES11RenderEngine.cpp
     +++ b/services/surfaceflinger/RenderEngine/GLES11RenderEngine.cpp
     @@ -92,14 +92,29 @@ void GLES11RenderEngine::setViewportAndProjection(
    @@ -2637,7 +2637,7 @@ index 847cdb3..b2821b7 100644
      
      void GLES11RenderEngine::setupFillWithColor(float r, float g, float b, float a) {
     diff --git a/services/surfaceflinger/RenderEngine/GLES11RenderEngine.h b/services/surfaceflinger/RenderEngine/GLES11RenderEngine.h
    -index 4cd968d..1ef6596 100644
    +index 4cd968d12..1ef659625 100644
     --- a/services/surfaceflinger/RenderEngine/GLES11RenderEngine.h
     +++ b/services/surfaceflinger/RenderEngine/GLES11RenderEngine.h
     @@ -40,8 +40,9 @@ class GLES11RenderEngine : public RenderEngine {
    @@ -2653,7 +2653,7 @@ index 4cd968d..1ef6596 100644
      public:
          GLES11RenderEngine();
     diff --git a/services/surfaceflinger/RenderEngine/GLES20RenderEngine.cpp b/services/surfaceflinger/RenderEngine/GLES20RenderEngine.cpp
    -index 406e611..e3cbc70 100644
    +index 406e611ee..e3cbc7054 100644
     --- a/services/surfaceflinger/RenderEngine/GLES20RenderEngine.cpp
     +++ b/services/surfaceflinger/RenderEngine/GLES20RenderEngine.cpp
     @@ -208,27 +208,44 @@ void GLES20RenderEngine::disableBlending() {
    @@ -2714,7 +2714,7 @@ index 406e611..e3cbc70 100644
      
      void GLES20RenderEngine::setupFillWithColor(float r, float g, float b, float a) {
     diff --git a/services/surfaceflinger/RenderEngine/GLES20RenderEngine.h b/services/surfaceflinger/RenderEngine/GLES20RenderEngine.h
    -index 7c3f9b5..b268119 100644
    +index 7c3f9b5d4..b2681198e 100644
     --- a/services/surfaceflinger/RenderEngine/GLES20RenderEngine.h
     +++ b/services/surfaceflinger/RenderEngine/GLES20RenderEngine.h
     @@ -55,8 +55,9 @@ class GLES20RenderEngine : public RenderEngine {
    @@ -2730,7 +2730,7 @@ index 7c3f9b5..b268119 100644
      public:
          GLES20RenderEngine();
     diff --git a/services/surfaceflinger/RenderEngine/RenderEngine.cpp b/services/surfaceflinger/RenderEngine/RenderEngine.cpp
    -index d6a032f..28b3319 100644
    +index d6a032fb3..28b3319ee 100644
     --- a/services/surfaceflinger/RenderEngine/RenderEngine.cpp
     +++ b/services/surfaceflinger/RenderEngine/RenderEngine.cpp
     @@ -83,7 +83,6 @@ RenderEngine* RenderEngine::create(EGLDisplay display, int hwcFormat) {
    @@ -2765,7 +2765,7 @@ index d6a032f..28b3319 100644
      
      status_t RenderEngine::BindImageAsFramebuffer::getStatus() const {
     diff --git a/services/surfaceflinger/RenderEngine/RenderEngine.h b/services/surfaceflinger/RenderEngine/RenderEngine.h
    -index 0259881..5a5910a 100644
    +index 0259881ee..5a5910ab8 100644
     --- a/services/surfaceflinger/RenderEngine/RenderEngine.h
     +++ b/services/surfaceflinger/RenderEngine/RenderEngine.h
     @@ -51,8 +51,8 @@ class RenderEngine {
    @@ -2791,7 +2791,7 @@ index 0259881..5a5910a 100644
              int getStatus() const;
          };
     diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
    -index 8e7e577..f1104a0 100644
    +index 8e7e5772b..f1104a06d 100644
     --- a/services/surfaceflinger/SurfaceFlinger.cpp
     +++ b/services/surfaceflinger/SurfaceFlinger.cpp
     @@ -27,6 +27,7 @@
    @@ -2900,7 +2900,7 @@ index 8e7e577..f1104a0 100644
                                  uint32_t* pixels = new uint32_t[reqWidth*reqHeight];
                                  getRenderEngine().readPixels(0, 0, reqWidth, reqHeight, pixels);
     diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
    -index b98924b..f23ba41 100644
    +index b98924bb2..f23ba410e 100644
     --- a/services/surfaceflinger/SurfaceFlinger.h
     +++ b/services/surfaceflinger/SurfaceFlinger.h
     @@ -218,7 +218,8 @@ private:
    @@ -2933,7 +2933,7 @@ index b98924b..f23ba41 100644
           * Feature prototyping
           */
     diff --git a/services/surfaceflinger/SurfaceFlingerConsumer.cpp b/services/surfaceflinger/SurfaceFlingerConsumer.cpp
    -index e0e4c61..6f2520b 100644
    +index e0e4c61e6..6f2520be2 100644
     --- a/services/surfaceflinger/SurfaceFlingerConsumer.cpp
     +++ b/services/surfaceflinger/SurfaceFlingerConsumer.cpp
     @@ -70,6 +70,14 @@ status_t SurfaceFlingerConsumer::updateTexImage(BufferRejecter* rejecter,
    @@ -2967,7 +2967,7 @@ index e0e4c61..6f2520b 100644
      #ifdef USE_HWC2
          err = updateAndReleaseLocked(item, &mPendingRelease);
     diff --git a/services/surfaceflinger/SurfaceFlinger_hwc1.cpp b/services/surfaceflinger/SurfaceFlinger_hwc1.cpp
    -index b32f652..3d9c80f 100644
    +index b32f652e8..3d9c80fcf 100644
     --- a/services/surfaceflinger/SurfaceFlinger_hwc1.cpp
     +++ b/services/surfaceflinger/SurfaceFlinger_hwc1.cpp
     @@ -26,6 +26,7 @@
    diff --git a/frameworks_op_net_wifi.patch b/frameworks_op_net_wifi.patch
    index af065a5..6efe67f 100644
    --- a/frameworks_op_net_wifi.patch
    +++ b/frameworks_op_net_wifi.patch
    @@ -1,5 +1,5 @@
     diff --git a/service/java/com/android/server/wifi/WifiStateMachine.java b/service/java/com/android/server/wifi/WifiStateMachine.java
    -index 89aabcf..7802b3d 100644
    +index 89aabcf3e..7802b3d00 100644
     --- a/service/java/com/android/server/wifi/WifiStateMachine.java
     +++ b/service/java/com/android/server/wifi/WifiStateMachine.java
     @@ -2329,7 +2329,7 @@ public class WifiStateMachine extends StateMachine implements WifiNative.WifiRss
    @@ -47,7 +47,7 @@ index 89aabcf..7802b3d 100644
                          }
                          break;
     diff --git a/service/java/com/android/server/wifi/p2p/WifiP2pServiceImpl.java b/service/java/com/android/server/wifi/p2p/WifiP2pServiceImpl.java
    -index c1d9445..b19af54 100644
    +index c1d9445b0..b19af5435 100644
     --- a/service/java/com/android/server/wifi/p2p/WifiP2pServiceImpl.java
     +++ b/service/java/com/android/server/wifi/p2p/WifiP2pServiceImpl.java
     @@ -2026,7 +2026,7 @@ public class WifiP2pServiceImpl extends IWifiP2pManager.Stub {
    diff --git a/frameworks_support.patch b/frameworks_support.patch
    index 46e0f3e..9dfa10c 100644
    --- a/frameworks_support.patch
    +++ b/frameworks_support.patch
    @@ -1,5 +1,5 @@
     diff --git a/compat/java/android/support/v4/view/ViewCompat.java b/compat/java/android/support/v4/view/ViewCompat.java
    -index 9637e65..cc3cc26 100644
    +index 9637e65fb9..cc3cc26058 100644
     --- a/compat/java/android/support/v4/view/ViewCompat.java
     +++ b/compat/java/android/support/v4/view/ViewCompat.java
     @@ -541,11 +541,11 @@ public class ViewCompat {
    @@ -17,7 +17,7 @@ index 9637e65..cc3cc26 100644
              @Override
              public void postOnAnimation(View view, Runnable action) {
     diff --git a/design/src/android/support/design/widget/BottomSheetBehavior.java b/design/src/android/support/design/widget/BottomSheetBehavior.java
    -index c3362a8..b913de1 100644
    +index c3362a81d1..b913de19a5 100644
     --- a/design/src/android/support/design/widget/BottomSheetBehavior.java
     +++ b/design/src/android/support/design/widget/BottomSheetBehavior.java
     @@ -385,7 +385,8 @@ public class BottomSheetBehavior<V extends View> extends CoordinatorLayout.Behav
    @@ -31,7 +31,7 @@ index c3362a8..b913de1 100644
              }
              int top;
     diff --git a/fragment/java/android/support/v4/app/FragmentHostCallback.java b/fragment/java/android/support/v4/app/FragmentHostCallback.java
    -index 75fde03..5c256d3 100644
    +index 75fde038f2..5c256d38f7 100644
     --- a/fragment/java/android/support/v4/app/FragmentHostCallback.java
     +++ b/fragment/java/android/support/v4/app/FragmentHostCallback.java
     @@ -304,13 +304,9 @@ public abstract class FragmentHostCallback<E> extends FragmentContainer {
    @@ -64,7 +64,7 @@ index 75fde03..5c256d3 100644
          }
      
     diff --git a/fragment/java/android/support/v4/app/FragmentManager.java b/fragment/java/android/support/v4/app/FragmentManager.java
    -index 3baf4f9..5996c9d 100644
    +index 3baf4f9d3a..5996c9dbc7 100644
     --- a/fragment/java/android/support/v4/app/FragmentManager.java
     +++ b/fragment/java/android/support/v4/app/FragmentManager.java
     @@ -2146,26 +2146,36 @@ final class FragmentManagerImpl extends FragmentManager implements LayoutInflate
    @@ -136,7 +136,7 @@ index 3baf4f9..5996c9d 100644
              mParent = null;
     diff --git a/fragment/tests/java/android/support/v4/app/ReentrantFragment.java b/fragment/tests/java/android/support/v4/app/ReentrantFragment.java
     new file mode 100644
    -index 0000000..472245d
    +index 0000000000..472245df2a
     --- /dev/null
     +++ b/fragment/tests/java/android/support/v4/app/ReentrantFragment.java
     @@ -0,0 +1,69 @@
    @@ -210,7 +210,7 @@ index 0000000..472245d
     +}
     +
     diff --git a/fragment/tests/java/android/support/v4/app/StrictFragment.java b/fragment/tests/java/android/support/v4/app/StrictFragment.java
    -index dfda814..d91c161 100644
    +index dfda814132..d91c161517 100644
     --- a/fragment/tests/java/android/support/v4/app/StrictFragment.java
     +++ b/fragment/tests/java/android/support/v4/app/StrictFragment.java
     @@ -51,6 +51,10 @@ public class StrictFragment extends Fragment {
    @@ -309,7 +309,7 @@ index dfda814..d91c161 100644
          }
      }
     diff --git a/v7/recyclerview/src/android/support/v7/widget/RecyclerView.java b/v7/recyclerview/src/android/support/v7/widget/RecyclerView.java
    -index b640f79..8c57dc8 100644
    +index b640f79c62..8c57dc853a 100644
     --- a/v7/recyclerview/src/android/support/v7/widget/RecyclerView.java
     +++ b/v7/recyclerview/src/android/support/v7/widget/RecyclerView.java
     @@ -11160,6 +11160,11 @@ public class RecyclerView extends ViewGroup implements ScrollingView, NestedScro
    diff --git a/hardware_libhardware.patch b/hardware_libhardware.patch
    index 9c529aa..4a2f84b 100644
    --- a/hardware_libhardware.patch
    +++ b/hardware_libhardware.patch
    @@ -1,5 +1,5 @@
     diff --git a/include/hardware/power.h b/include/hardware/power.h
    -index bd8216e..968e478 100644
    +index bd8216ef..968e478e 100644
     --- a/include/hardware/power.h
     +++ b/include/hardware/power.h
     @@ -65,7 +65,11 @@ typedef enum {
    @@ -29,7 +29,7 @@ index bd8216e..968e478 100644
           *
           * availability: version 0.2
     diff --git a/modules/sensors/multihal.cpp b/modules/sensors/multihal.cpp
    -index f38d90d..4acc93e 100644
    +index f38d90d2..4acc93e0 100644
     --- a/modules/sensors/multihal.cpp
     +++ b/modules/sensors/multihal.cpp
     @@ -527,8 +527,8 @@ static void lazy_init_modules() {
    diff --git a/libcore.patch b/libcore.patch
    index c36635b..e4a7ceb 100644
    --- a/libcore.patch
    +++ b/libcore.patch
    @@ -1,5 +1,5 @@
     diff --git a/libart/src/main/java/java/lang/AndroidHardcodedSystemProperties.java b/libart/src/main/java/java/lang/AndroidHardcodedSystemProperties.java
    -index 13e9317..7e79e28 100644
    +index 13e931786..7e79e2807 100644
     --- a/libart/src/main/java/java/lang/AndroidHardcodedSystemProperties.java
     +++ b/libart/src/main/java/java/lang/AndroidHardcodedSystemProperties.java
     @@ -87,7 +87,7 @@ public final class AndroidHardcodedSystemProperties {
    @@ -17,7 +17,7 @@ index 13e9317..7e79e28 100644
      }
     -
     diff --git a/luni/src/test/java/libcore/java/io/FileTest.java b/luni/src/test/java/libcore/java/io/FileTest.java
    -index 5d5317a..04de751 100644
    +index 5d5317a9e..04de75137 100644
     --- a/luni/src/test/java/libcore/java/io/FileTest.java
     +++ b/luni/src/test/java/libcore/java/io/FileTest.java
     @@ -368,4 +368,25 @@ public class FileTest extends junit.framework.TestCase {
    @@ -47,7 +47,7 @@ index 5d5317a..04de751 100644
     +    }
      }
     diff --git a/luni/src/test/java/libcore/java/net/URLTest.java b/luni/src/test/java/libcore/java/net/URLTest.java
    -index 0eee1f8..410f3fb 100644
    +index 0eee1f8d9..410f3fb67 100644
     --- a/luni/src/test/java/libcore/java/net/URLTest.java
     +++ b/luni/src/test/java/libcore/java/net/URLTest.java
     @@ -409,6 +409,46 @@ public final class URLTest extends TestCase {
    @@ -98,7 +98,7 @@ index 0eee1f8..410f3fb 100644
              URL base = new URL("http://host/file");
              assertEquals("http://host/another#fragment", new URL(base, "another#fragment").toString());
     diff --git a/ojluni/src/main/java/java/io/FileSystem.java b/ojluni/src/main/java/java/io/FileSystem.java
    -index aa00fa9..7db1651 100755
    +index aa00fa996..7db1651f5 100755
     --- a/ojluni/src/main/java/java/io/FileSystem.java
     +++ b/ojluni/src/main/java/java/io/FileSystem.java
     @@ -232,8 +232,11 @@ abstract class FileSystem {
    @@ -116,7 +116,7 @@ index aa00fa9..7db1651 100755
          private static boolean getBooleanProperty(String prop, boolean defaultVal) {
              String val = System.getProperty(prop);
     diff --git a/ojluni/src/main/java/java/net/URLStreamHandler.java b/ojluni/src/main/java/java/net/URLStreamHandler.java
    -index 0892d67..49a84a9 100755
    +index 0892d6741..49a84a9d6 100755
     --- a/ojluni/src/main/java/java/net/URLStreamHandler.java
     +++ b/ojluni/src/main/java/java/net/URLStreamHandler.java
     @@ -168,12 +168,25 @@ public abstract class URLStreamHandler {
    diff --git a/packages_apps_nfc.patch b/packages_apps_nfc.patch
    index ef1866e..2a7860a 100644
    --- a/packages_apps_nfc.patch
    +++ b/packages_apps_nfc.patch
    @@ -1,5 +1,5 @@
     diff --git a/src/com/android/nfc/BeamShareActivity.java b/src/com/android/nfc/BeamShareActivity.java
    -index 5b8acac..f06bfdb 100644
    +index 5b8acacd..f06bfdba 100644
     --- a/src/com/android/nfc/BeamShareActivity.java
     +++ b/src/com/android/nfc/BeamShareActivity.java
     @@ -19,6 +19,8 @@ package com.android.nfc;
    diff --git a/packages_apps_settings.patch b/packages_apps_settings.patch
    index 75a2bdc..51aa5a3 100644
    --- a/packages_apps_settings.patch
    +++ b/packages_apps_settings.patch
    @@ -1,5 +1,5 @@
     diff --git a/AndroidManifest.xml b/AndroidManifest.xml
    -index 2ec976d..c155cf7 100644
    +index 2ec976dd35..c155cf79c3 100644
     --- a/AndroidManifest.xml
     +++ b/AndroidManifest.xml
     @@ -86,6 +86,7 @@
    @@ -11,7 +11,7 @@ index 2ec976d..c155cf7 100644
          <application android:label="@string/settings_label"
                  android:icon="@mipmap/ic_launcher_settings"
     diff --git a/res/values/strings.xml b/res/values/strings.xml
    -index c731267..9ec0584 100644
    +index c731267b94..9ec0584795 100644
     --- a/res/values/strings.xml
     +++ b/res/values/strings.xml
     @@ -1348,7 +1348,7 @@
    @@ -24,7 +24,7 @@ index c731267..9ec0584 100644
          <!-- Title for BT error dialogs. -->
          <string name="bluetooth_error_title"></string>
     diff --git a/src/com/android/settings/ActivityPicker.java b/src/com/android/settings/ActivityPicker.java
    -index 2c3436f..ae61944 100644
    +index 2c3436fc70..ae61944cbe 100644
     --- a/src/com/android/settings/ActivityPicker.java
     +++ b/src/com/android/settings/ActivityPicker.java
     @@ -78,6 +78,10 @@ public class ActivityPicker extends AlertActivity implements
    @@ -39,7 +39,7 @@ index 2c3436f..ae61944 100644
                  mBaseIntent = new Intent(Intent.ACTION_MAIN, null);
                  mBaseIntent.addCategory(Intent.CATEGORY_DEFAULT);
     diff --git a/src/com/android/settings/DeviceAdminAdd.java b/src/com/android/settings/DeviceAdminAdd.java
    -index 9d4d895..2f6afd7 100644
    +index 9d4d895330..2f6afd790f 100644
     --- a/src/com/android/settings/DeviceAdminAdd.java
     +++ b/src/com/android/settings/DeviceAdminAdd.java
     @@ -16,6 +16,8 @@
    @@ -108,7 +108,7 @@ index 9d4d895..2f6afd7 100644
                  ActivityManagerNative.getDefault().resumeAppSwitches();
              } catch (RemoteException e) {
     diff --git a/src/com/android/settings/accessibility/ToggleAccessibilityServicePreferenceFragment.java b/src/com/android/settings/accessibility/ToggleAccessibilityServicePreferenceFragment.java
    -index 196a4ab..1f69768 100644
    +index 196a4ab372..1f69768c0d 100644
     --- a/src/com/android/settings/accessibility/ToggleAccessibilityServicePreferenceFragment.java
     +++ b/src/com/android/settings/accessibility/ToggleAccessibilityServicePreferenceFragment.java
     @@ -39,6 +39,8 @@ import android.view.MenuInflater;
    diff --git a/system_bt.patch b/system_bt.patch
    index f7f82e5..a932778 100644
    --- a/system_bt.patch
    +++ b/system_bt.patch
    @@ -1,5 +1,5 @@
     diff --git a/bta/dm/bta_dm_act.c b/bta/dm/bta_dm_act.c
    -index 1bf741d..a8d92e0 100644
    +index 1bf741d92..a8d92e0d3 100644
     --- a/bta/dm/bta_dm_act.c
     +++ b/bta/dm/bta_dm_act.c
     @@ -26,6 +26,7 @@
    @@ -59,7 +59,7 @@ index 1bf741d..a8d92e0 100644
                      }
                  } while (p_sdp_rec);
     diff --git a/bta/gatt/bta_gattc_cache.c b/bta/gatt/bta_gattc_cache.c
    -index 63c4246..45d2588 100644
    +index 63c424696..45d258824 100644
     --- a/bta/gatt/bta_gattc_cache.c
     +++ b/bta/gatt/bta_gattc_cache.c
     @@ -1551,7 +1551,7 @@ bool bta_gattc_cache_load(tBTA_GATTC_CLCB *p_clcb)
    @@ -72,7 +72,7 @@ index 63c4246..45d2588 100644
              goto done;
          }
     diff --git a/bta/pan/bta_pan_act.c b/bta/pan/bta_pan_act.c
    -index 1995478..4367fce 100644
    +index 199547817..4367fce68 100644
     --- a/bta/pan/bta_pan_act.c
     +++ b/bta/pan/bta_pan_act.c
     @@ -26,6 +26,8 @@
    @@ -136,7 +136,7 @@ index 1995478..4367fce 100644
          BT_HDR *p_event = (BT_HDR *)osi_malloc(sizeof(BT_HDR));
          p_event->layer_specific = handle;
     diff --git a/btif/src/btif_rc.c b/btif/src/btif_rc.c
    -index 6572fd7..133277a 100644
    +index 6572fd74e..133277a35 100644
     --- a/btif/src/btif_rc.c
     +++ b/btif/src/btif_rc.c
     @@ -42,6 +42,7 @@
    @@ -161,7 +161,7 @@ index 6572fd7..133277a 100644
          {
              app_settings.attr_ids[xx] = p_rsp->p_vals[xx].attr_id;
     diff --git a/btif/src/btif_sdp_server.c b/btif/src/btif_sdp_server.c
    -index d02dfa0..90d74cf 100644
    +index d02dfa0b8..90d74cf53 100644
     --- a/btif/src/btif_sdp_server.c
     +++ b/btif/src/btif_sdp_server.c
     @@ -215,7 +215,8 @@ static int alloc_sdp_slot(bluetooth_sdp_record* in_record) {
    @@ -175,7 +175,7 @@ index d02dfa0..90d74cf 100644
              return handle;
          }
     diff --git a/btif/src/btif_storage.c b/btif/src/btif_storage.c
    -index 83dcc8c..d02b09a 100644
    +index 83dcc8c47..d02b09a55 100644
     --- a/btif/src/btif_storage.c
     +++ b/btif/src/btif_storage.c
     @@ -229,6 +229,10 @@ static int prop2cfg(bt_bdaddr_t *remote_bd_addr, bt_property_t *prop)
    @@ -190,7 +190,7 @@ index 83dcc8c..d02b09a 100644
                      //strcat(value, ";");
                      strcat(value, " ");
     diff --git a/osi/src/alarm.c b/osi/src/alarm.c
    -index 69ded69..5f9e42c 100644
    +index 69ded69e4..5f9e42ce3 100644
     --- a/osi/src/alarm.c
     +++ b/osi/src/alarm.c
     @@ -64,7 +64,6 @@ typedef struct {
    @@ -267,7 +267,7 @@ index 69ded69..5f9e42c 100644
                    "    Overdue scheduling time in ms (total/max/avg)");
      
     diff --git a/osi/src/config.c b/osi/src/config.c
    -index 345f907..b38977f 100644
    +index 345f907d5..b38977f07 100644
     --- a/osi/src/config.c
     +++ b/osi/src/config.c
     @@ -34,6 +34,7 @@
    @@ -319,7 +319,7 @@ index 345f907..b38977f 100644
      }
      
     diff --git a/stack/avdt/avdt_api.c b/stack/avdt/avdt_api.c
    -index 98ef5f7..5201054 100644
    +index 98ef5f755..52010541d 100644
     --- a/stack/avdt/avdt_api.c
     +++ b/stack/avdt/avdt_api.c
     @@ -1208,7 +1208,7 @@ UINT16 AVDT_SendReport(UINT8 handle, AVDT_REPORT_TYPE type,
    @@ -332,7 +332,7 @@ index 98ef5f7..5201054 100644
                  p_pkt->offset = L2CAP_MIN_OFFSET;
                  p = (UINT8 *)(p_pkt + 1) + p_pkt->offset;
     diff --git a/stack/avrc/avrc_pars_ct.c b/stack/avrc/avrc_pars_ct.c
    -index 63cc384..1818c52 100644
    +index 63cc38407..1818c522f 100644
     --- a/stack/avrc/avrc_pars_ct.c
     +++ b/stack/avrc/avrc_pars_ct.c
     @@ -22,6 +22,7 @@
    @@ -426,7 +426,7 @@ index 63cc384..1818c52 100644
                  BE_STREAM_TO_UINT8(p_result->get_app_val_txt.p_attrs[i].attr_id, p);
                  BE_STREAM_TO_UINT16(p_result->get_app_val_txt.p_attrs[i].charset_id, p);
     diff --git a/stack/avrc/avrc_pars_tg.c b/stack/avrc/avrc_pars_tg.c
    -index 3f3fe93..6d3c67e 100644
    +index 3f3fe9385..6d3c67e3f 100644
     --- a/stack/avrc/avrc_pars_tg.c
     +++ b/stack/avrc/avrc_pars_tg.c
     @@ -21,6 +21,7 @@
    @@ -463,7 +463,7 @@ index 3f3fe93..6d3c67e 100644
                          for (xx=0; xx< p_result->get_app_val_txt.num_val; xx++)
                          {
     diff --git a/stack/bnep/bnep_api.c b/stack/bnep/bnep_api.c
    -index 9a7b5d9..3e866d1 100644
    +index 9a7b5d944..3e866d100 100644
     --- a/stack/bnep/bnep_api.c
     +++ b/stack/bnep/bnep_api.c
     @@ -24,6 +24,7 @@
    @@ -497,7 +497,7 @@ index 9a7b5d9..3e866d1 100644
                      p_data[3] = 0;
                  }
     diff --git a/stack/bnep/bnep_main.c b/stack/bnep/bnep_main.c
    -index 078a72e..8edb712 100644
    +index 078a72ebd..8edb712ac 100644
     --- a/stack/bnep/bnep_main.c
     +++ b/stack/bnep/bnep_main.c
     @@ -35,6 +35,7 @@
    @@ -568,7 +568,7 @@ index 078a72e..8edb712 100644
                      ext_type &= 0x7F;
      
     diff --git a/stack/bnep/bnep_utils.c b/stack/bnep/bnep_utils.c
    -index 13fb189..65acd33 100644
    +index 13fb189e7..65acd33f6 100644
     --- a/stack/bnep/bnep_utils.c
     +++ b/stack/bnep/bnep_utils.c
     @@ -22,6 +22,8 @@
    @@ -780,7 +780,7 @@ index 13fb189..65acd33 100644
      
      
     diff --git a/stack/btu/btu_init.c b/stack/btu/btu_init.c
    -index 688ed88..9f9ed0a 100644
    +index 688ed889d..9f9ed0a50 100644
     --- a/stack/btu/btu_init.c
     +++ b/stack/btu/btu_init.c
     @@ -115,6 +115,8 @@ void btu_free_core(void)
    @@ -793,7 +793,7 @@ index 688ed88..9f9ed0a 100644
            gatt_free();
      #endif
     diff --git a/stack/gatt/gatt_sr.c b/stack/gatt/gatt_sr.c
    -index 11ef79c..c2cdb88 100644
    +index 11ef79c83..c2cdb885d 100644
     --- a/stack/gatt/gatt_sr.c
     +++ b/stack/gatt/gatt_sr.c
     @@ -22,6 +22,7 @@
    @@ -834,7 +834,7 @@ index 11ef79c..c2cdb88 100644
      
          if (op_code == GATT_REQ_READ_BLOB)
     diff --git a/stack/l2cap/l2c_ble.c b/stack/l2cap/l2c_ble.c
    -index 95de4e3..b2f196c 100644
    +index 95de4e34c..b2f196c3c 100644
     --- a/stack/l2cap/l2c_ble.c
     +++ b/stack/l2cap/l2c_ble.c
     @@ -31,6 +31,7 @@
    @@ -858,7 +858,7 @@ index 95de4e3..b2f196c 100644
                  STREAM_TO_UINT16 (rcid, p);
      
     diff --git a/stack/l2cap/l2c_fcr.c b/stack/l2cap/l2c_fcr.c
    -index 5ba8b56..282b171 100644
    +index 5ba8b5619..282b1716f 100644
     --- a/stack/l2cap/l2c_fcr.c
     +++ b/stack/l2cap/l2c_fcr.c
     @@ -24,6 +24,7 @@
    @@ -907,7 +907,7 @@ index 5ba8b56..282b171 100644
          osi_free(p_buf);
          return;
     diff --git a/stack/l2cap/l2c_main.c b/stack/l2cap/l2c_main.c
    -index 3c48d69..cef488c 100644
    +index 3c48d6974..cef488cb9 100644
     --- a/stack/l2cap/l2c_main.c
     +++ b/stack/l2cap/l2c_main.c
     @@ -339,9 +339,17 @@ static void process_l2cap_cmd (tL2C_LCB *p_lcb, UINT8 *p, UINT16 pkt_len)
    @@ -1181,7 +1181,7 @@ index 3c48d69..cef488c 100644
      
      #if (L2CAP_NUM_FIXED_CHNLS > 0)
     diff --git a/stack/l2cap/l2cap_client.c b/stack/l2cap/l2cap_client.c
    -index 7e8b3cb..cd7edfe 100644
    +index 7e8b3cb6f..cd7edfe1f 100644
     --- a/stack/l2cap/l2cap_client.c
     +++ b/stack/l2cap/l2cap_client.c
     @@ -370,7 +370,8 @@ static void fragment_packet(l2cap_client_t *client, buffer_t *packet) {
    @@ -1205,7 +1205,7 @@ index 7e8b3cb..cd7edfe 100644
          fragment->len = client->remote_mtu;
          memcpy(fragment->data + fragment->offset, bt_packet->data + bt_packet->offset, client->remote_mtu);
     diff --git a/stack/mcap/mca_cact.c b/stack/mcap/mca_cact.c
    -index 583a342..483169a 100644
    +index 583a34215..483169ad6 100644
     --- a/stack/mcap/mca_cact.c
     +++ b/stack/mcap/mca_cact.c
     @@ -122,7 +122,7 @@ void mca_ccb_snd_req(tMCA_CCB *p_ccb, tMCA_CCB_EVT *p_data)
    @@ -1227,7 +1227,7 @@ index 583a342..483169a 100644
          MCA_TRACE_DEBUG("%s cong=%d req=%d", __func__, p_ccb->cong, p_msg->op_code);
          /* assume that API functions verified the parameters */
     diff --git a/stack/pan/pan_main.c b/stack/pan/pan_main.c
    -index 5c3a367..9c90e58 100644
    +index 5c3a36739..9c90e5834 100644
     --- a/stack/pan/pan_main.c
     +++ b/stack/pan/pan_main.c
     @@ -222,6 +222,39 @@ void pan_conn_ind_cb (UINT16 handle,
    @@ -1299,7 +1299,7 @@ index 5c3a367..9c90e58 100644
      }
      
     diff --git a/stack/sdp/sdp_discovery.c b/stack/sdp/sdp_discovery.c
    -index ec20689..7a5333e 100644
    +index ec20689e3..7a5333eda 100644
     --- a/stack/sdp/sdp_discovery.c
     +++ b/stack/sdp/sdp_discovery.c
     @@ -29,6 +29,7 @@
    @@ -1452,7 +1452,7 @@ index ec20689..7a5333e 100644
              else
                  UINT8_TO_BE_STREAM (p, 0);
     diff --git a/stack/sdp/sdp_main.c b/stack/sdp/sdp_main.c
    -index c888817..7cbe2d3 100644
    +index c88881799..7cbe2d37b 100644
     --- a/stack/sdp/sdp_main.c
     +++ b/stack/sdp/sdp_main.c
     @@ -85,6 +85,10 @@ void sdp_init (void)
    @@ -1481,7 +1481,7 @@ index c888817..7cbe2d3 100644
      /*******************************************************************************
      **
     diff --git a/stack/sdp/sdp_server.c b/stack/sdp/sdp_server.c
    -index 627f4cf..993e0a1 100644
    +index 627f4cf18..993e0a1f4 100644
     --- a/stack/sdp/sdp_server.c
     +++ b/stack/sdp/sdp_server.c
     @@ -23,6 +23,7 @@
    @@ -1658,7 +1658,7 @@ index 627f4cf..993e0a1 100644
                                          SDP_TEXT_BAD_CONT_LEN);
                  return;
     diff --git a/stack/sdp/sdp_utils.c b/stack/sdp/sdp_utils.c
    -index a6f0ba6..6b503cb 100644
    +index a6f0ba6a9..6b503cb70 100644
     --- a/stack/sdp/sdp_utils.c
     +++ b/stack/sdp/sdp_utils.c
     @@ -120,8 +120,9 @@ tCONN_CB *sdpu_allocate_ccb (void)
    @@ -1826,7 +1826,7 @@ index a6f0ba6..6b503cb 100644
              {
                  BE_STREAM_TO_UINT16 (p_seq->attr_entry[p_seq->num_attr].start, p);
     diff --git a/stack/sdp/sdpint.h b/stack/sdp/sdpint.h
    -index 05414cd..71dab92 100644
    +index 05414cd3c..71dab9265 100644
     --- a/stack/sdp/sdpint.h
     +++ b/stack/sdp/sdpint.h
     @@ -246,6 +246,7 @@ extern tSDP_CB *sdp_cb_ptr;
    @@ -1838,7 +1838,7 @@ index 05414cd..71dab92 100644
      
      #if (defined(SDP_DEBUG) && SDP_DEBUG == TRUE)
     diff --git a/stack/smp/p_256_ecc_pp.c b/stack/smp/p_256_ecc_pp.c
    -index 2eaebd4..832ce11 100644
    +index 2eaebd4eb..832ce11e7 100644
     --- a/stack/smp/p_256_ecc_pp.c
     +++ b/stack/smp/p_256_ecc_pp.c
     @@ -259,4 +259,25 @@ void ECC_PointMult_Bin_NAF(Point *q, Point *p, DWORD *n, uint32_t keyLength)
    @@ -1868,7 +1868,7 @@ index 2eaebd4..832ce11 100644
     +    return multiprecision_compare(rhs, y2_mod, kl) == 0;
     +}
     diff --git a/stack/smp/p_256_ecc_pp.h b/stack/smp/p_256_ecc_pp.h
    -index fd3dc64..49f2d11 100644
    +index fd3dc64fe..49f2d1104 100644
     --- a/stack/smp/p_256_ecc_pp.h
     +++ b/stack/smp/p_256_ecc_pp.h
     @@ -24,6 +24,7 @@
    @@ -1889,7 +1889,7 @@ index fd3dc64..49f2d11 100644
      
      #define ECC_PointMult(q, p, n, keyLength)  ECC_PointMult_Bin_NAF(q, p, n, keyLength)
     diff --git a/stack/smp/smp_act.c b/stack/smp/smp_act.c
    -index e4152a4..9e0246c 100644
    +index e4152a478..9e0246c97 100644
     --- a/stack/smp/smp_act.c
     +++ b/stack/smp/smp_act.c
     @@ -16,11 +16,13 @@
    @@ -1926,7 +1926,7 @@ index e4152a4..9e0246c 100644
      
          smp_wait_for_both_public_keys(p_cb, NULL);
     diff --git a/stack/smp/smp_main.c b/stack/smp/smp_main.c
    -index c3709f8..67a2b39 100644
    +index c3709f8a3..67a2b397a 100644
     --- a/stack/smp/smp_main.c
     +++ b/stack/smp/smp_main.c
     @@ -20,6 +20,7 @@
    @@ -1952,7 +1952,7 @@ index c3709f8..67a2b39 100644
      
          SMP_TRACE_EVENT("main smp_sm_event");
     diff --git a/stack/smp/smp_utils.c b/stack/smp/smp_utils.c
    -index a7357db..675cb42 100644
    +index a7357db05..675cb4251 100644
     --- a/stack/smp/smp_utils.c
     +++ b/stack/smp/smp_utils.c
     @@ -297,8 +297,7 @@ BOOLEAN  smp_send_msg_to_L2CAP(BD_ADDR rem_bda, BT_HDR *p_toL2CAP)
    diff --git a/system_core.patch b/system_core.patch
    index 4faa581..302db7f 100644
    --- a/system_core.patch
    +++ b/system_core.patch
    @@ -1,5 +1,101 @@
    +diff --git a/fs_mgr/fs_mgr.c b/fs_mgr/fs_mgr.c
    +index 387f70859..0ad35c411 100644
    +--- a/fs_mgr/fs_mgr.c
    ++++ b/fs_mgr/fs_mgr.c
    +@@ -60,6 +60,7 @@
    + #define FSCK_LOG_FILE   "/dev/fscklogs/log"
    + 
    + #define ZRAM_CONF_DEV   "/sys/block/zram0/disksize"
    ++#define ZRAM_STREAMS    "/sys/block/zram0/max_comp_streams"
    + 
    + #define ARRAY_SIZE(a) (sizeof(a) / sizeof(*(a)))
    + 
    +@@ -812,6 +813,14 @@ int fs_mgr_swapon_all(struct fstab *fstab)
    +              */
    +             FILE *zram_fp;
    + 
    ++            /* The stream count parameter is only available on new kernels.
    ++             * It must be set before the disk size. */
    ++            zram_fp = fopen(ZRAM_STREAMS, "r+");
    ++            if (zram_fp) {
    ++                fprintf(zram_fp, "%d\n", fstab->recs[i].zram_streams);
    ++                fclose(zram_fp);
    ++            }
    ++
    +             zram_fp = fopen(ZRAM_CONF_DEV, "r+");
    +             if (zram_fp == NULL) {
    +                 ERROR("Unable to open zram conf device %s\n", ZRAM_CONF_DEV);
    +diff --git a/fs_mgr/fs_mgr_fstab.c b/fs_mgr/fs_mgr_fstab.c
    +index 9225d349f..44367ed2b 100644
    +--- a/fs_mgr/fs_mgr_fstab.c
    ++++ b/fs_mgr/fs_mgr_fstab.c
    +@@ -32,6 +32,7 @@ struct fs_mgr_flag_values {
    +     int partnum;
    +     int swap_prio;
    +     unsigned int zram_size;
    ++    unsigned int zram_streams;
    +     unsigned int file_encryption_mode;
    + };
    + 
    +@@ -80,6 +81,7 @@ static struct flag_list fs_mgr_flags[] = {
    +     { "slotselect",  MF_SLOTSELECT },
    +     { "nofail",      MF_NOFAIL },
    +     { "latemount",   MF_LATEMOUNT },
    ++    { "zramstreams=",MF_ZRAMSTREAMS },
    +     { "defaults",    0 },
    +     { 0,             0 },
    + };
    +@@ -121,6 +123,7 @@ static int parse_flags(char *flags, struct flag_list *fl,
    +         memset(flag_vals, 0, sizeof(*flag_vals));
    +         flag_vals->partnum = -1;
    +         flag_vals->swap_prio = -1; /* negative means it wasn't specified. */
    ++        flag_vals->zram_streams = 1;
    +     }
    + 
    +     /* initialize fs_options to the null string */
    +@@ -213,6 +216,8 @@ static int parse_flags(char *flags, struct flag_list *fl,
    +                         flag_vals->zram_size = calculate_zram_size(val);
    +                     else
    +                         flag_vals->zram_size = val;
    ++                } else if ((fl[i].flag == MF_ZRAMSTREAMS) && flag_vals) {
    ++                    flag_vals->zram_streams = strtoll(strchr(p, '=') + 1, NULL, 0);
    +                 }
    +                 break;
    +             }
    +@@ -364,6 +369,7 @@ struct fstab *fs_mgr_read_fstab(const char *fstab_path)
    +         fstab->recs[cnt].partnum = flag_vals.partnum;
    +         fstab->recs[cnt].swap_prio = flag_vals.swap_prio;
    +         fstab->recs[cnt].zram_size = flag_vals.zram_size;
    ++        fstab->recs[cnt].zram_streams = flag_vals.zram_streams;
    +         fstab->recs[cnt].file_encryption_mode = flag_vals.file_encryption_mode;
    +         cnt++;
    +     }
    +diff --git a/fs_mgr/fs_mgr_priv.h b/fs_mgr/fs_mgr_priv.h
    +index 120ec5a68..21233b788 100644
    +--- a/fs_mgr/fs_mgr_priv.h
    ++++ b/fs_mgr/fs_mgr_priv.h
    +@@ -86,6 +86,7 @@ __BEGIN_DECLS
    + #define MF_LATEMOUNT    0x20000
    + #define MF_NOFAIL       0x40000
    + #define MF_VERIFYATBOOT 0x80000
    ++#define MF_ZRAMSTREAMS  0x100000
    + 
    + #define DM_BUF_SIZE 4096
    + 
    +diff --git a/fs_mgr/include/fs_mgr.h b/fs_mgr/include/fs_mgr.h
    +index 756596598..e796bdd50 100644
    +--- a/fs_mgr/include/fs_mgr.h
    ++++ b/fs_mgr/include/fs_mgr.h
    +@@ -72,6 +72,7 @@ struct fstab_rec {
    +     int partnum;
    +     int swap_prio;
    +     unsigned int zram_size;
    ++    unsigned int zram_streams;
    +     unsigned int file_encryption_mode;
    + };
    + 
     diff --git a/include/cutils/iosched_policy.h b/include/cutils/iosched_policy.h
    -index 07c5d1f..25b87ba 100644
    +index 07c5d1fca..25b87bac0 100644
     --- a/include/cutils/iosched_policy.h
     +++ b/include/cutils/iosched_policy.h
     @@ -31,6 +31,8 @@ typedef enum {
    @@ -12,7 +108,7 @@ index 07c5d1f..25b87ba 100644
      }
      #endif
     diff --git a/include/private/android_filesystem_config.h b/include/private/android_filesystem_config.h
    -index 5ccd80e..ed8ae35 100644
    +index 5ccd80e7a..ed8ae3578 100644
     --- a/include/private/android_filesystem_config.h
     +++ b/include/private/android_filesystem_config.h
     @@ -121,6 +121,8 @@
    @@ -33,7 +129,7 @@ index 5ccd80e..ed8ae35 100644
          { "everybody",     AID_EVERYBODY, },
          { "misc",          AID_MISC, },
     diff --git a/include/system/camera.h b/include/system/camera.h
    -index 5d0873a..e4c0a47 100644
    +index 5d0873ac4..e4c0a47a8 100644
     --- a/include/system/camera.h
     +++ b/include/system/camera.h
     @@ -88,9 +88,20 @@ enum {
    @@ -100,7 +196,7 @@ index 5d0873a..e4c0a47 100644
      };
      
      /** camera fatal errors */
    -@@ -275,10 +320,32 @@ typedef struct camera_face {
    +@@ -275,9 +320,31 @@ typedef struct camera_face {
           * -2000, -2000 if this is not supported.
           */
          int32_t mouth[2];
    @@ -119,7 +215,7 @@ index 5d0873a..e4c0a47 100644
      
      } camera_face_t;
      
    - /**
    ++/**
     + * The information of a data type received in a camera frame.
     + */
     +typedef enum {
    @@ -129,12 +225,11 @@ index 5d0873a..e4c0a47 100644
     +    CAMERA_FRAME_DATA_FD = 0x100
     +} camera_frame_data_type_t;
     +
    -+/**
    + /**
       * The metadata of the frame data.
       */
    - typedef struct camera_frame_metadata {
     diff --git a/include/utils/Unicode.h b/include/utils/Unicode.h
    -index cddbab4..b152579 100644
    +index cddbab497..b152579c7 100644
     --- a/include/utils/Unicode.h
     +++ b/include/utils/Unicode.h
     @@ -22,6 +22,10 @@
    @@ -149,7 +244,7 @@ index cddbab4..b152579 100644
      int strcmp16(const char16_t *, const char16_t *);
      int strncmp16(const char16_t *s1, const char16_t *s2, size_t n);
     diff --git a/init/Android.mk b/init/Android.mk
    -index 67541b8..ff343e9 100644
    +index 67541b81b..ff343e968 100644
     --- a/init/Android.mk
     +++ b/init/Android.mk
     @@ -10,7 +10,7 @@ else
    @@ -162,10 +257,77 @@ index 67541b8..ff343e9 100644
      init_cflags += \
          $(init_options) \
     diff --git a/init/init.cpp b/init/init.cpp
    -index cd2d2e6..81628a1 100644
    +index cd2d2e6ab..6f901a64d 100644
     --- a/init/init.cpp
     +++ b/init/init.cpp
    -@@ -296,55 +296,6 @@ static bool __attribute__((unused)) set_mmap_rnd_bits_min(int start, int min, bo
    +@@ -141,19 +141,60 @@ static void restart_processes()
    +             });
    + }
    + 
    +-void handle_control_message(const std::string& msg, const std::string& name) {
    ++static void msg_start(const std::string& name)
    ++{
    ++    Service* svc = nullptr;
    ++    std::vector<std::string> vargs;
    ++
    ++    size_t colon_pos = name.find(':');
    ++    if (colon_pos == std::string::npos) {
    ++        svc = ServiceManager::GetInstance().FindServiceByName(name);
    ++    } else {
    ++        std::string service_name(name.substr(0, colon_pos));
    ++        std::string args(name.substr(colon_pos + 1));
    ++        vargs = android::base::Split(args, " ");
    ++
    ++        svc = ServiceManager::GetInstance().FindServiceByName(service_name);
    ++    }
    ++
    ++    if (svc) {
    ++        svc->Start();
    ++    } else {
    ++        ERROR("no such service '%s'\n", name.c_str());
    ++    }
    ++}
    ++
    ++static void msg_stop(const std::string& name)
    ++{
    +     Service* svc = ServiceManager::GetInstance().FindServiceByName(name);
    +-    if (svc == nullptr) {
    ++
    ++    if (svc) {
    ++        svc->Stop();
    ++    } else {
    +         ERROR("no such service '%s'\n", name.c_str());
    +-        return;
    +     }
    ++}
    + 
    ++static void msg_restart(const std::string& name)
    ++{
    ++    Service* svc = ServiceManager::GetInstance().FindServiceByName(name);
    ++
    ++    if (svc) {
    ++        svc->Restart();
    ++    } else {
    ++        ERROR("no such service '%s'\n", name.c_str());
    ++    }
    ++}
    ++
    ++void handle_control_message(const std::string& msg, const std::string& arg)
    ++{
    +     if (msg == "start") {
    +-        svc->Start();
    ++        msg_start(arg);
    +     } else if (msg == "stop") {
    +-        svc->Stop();
    ++    } else if (msg == "stop") {
    ++        msg_stop(arg);
    +     } else if (msg == "restart") {
    +-        svc->Restart();
    ++        msg_restart(arg);
    +     } else {
    +         ERROR("unknown control msg '%s'\n", msg.c_str());
    +     }
    +@@ -296,55 +337,6 @@ static bool __attribute__((unused)) set_mmap_rnd_bits_min(int start, int min, bo
          return (start >= min);
      }
      
    @@ -221,7 +383,27 @@ index cd2d2e6..81628a1 100644
      static int keychord_init_action(const std::vector<std::string>& args)
      {
          keychord_init();
    -@@ -701,7 +652,7 @@ int main(int argc, char** argv) {
    +@@ -478,17 +470,11 @@ static void process_kernel_cmdline() {
    +     if (qemu[0]) import_kernel_cmdline(true, import_kernel_nv);
    + }
    + 
    +-static int property_enable_triggers_action(const std::vector<std::string>& args)
    +-{
    +-    /* Enable property triggers. */
    +-    property_triggers_enabled = 1;
    +-    return 0;
    +-}
    +-
    + static int queue_property_triggers_action(const std::vector<std::string>& args)
    + {
    +-    ActionManager::GetInstance().QueueBuiltinAction(property_enable_triggers_action, "enable_property_trigger");
    +     ActionManager::GetInstance().QueueAllPropertyTriggers();
    ++    /* enable property triggers */
    ++    property_triggers_enabled = 1;
    +     return 0;
    + }
    + 
    +@@ -701,7 +687,7 @@ int main(int argc, char** argv) {
          am.QueueBuiltinAction(wait_for_coldboot_done_action, "wait_for_coldboot_done");
          // ... so that we can start queuing up actions that require stuff from /dev.
          am.QueueBuiltinAction(mix_hwrng_into_linux_rng_action, "mix_hwrng_into_linux_rng");
    @@ -231,7 +413,7 @@ index cd2d2e6..81628a1 100644
          am.QueueBuiltinAction(console_init_action, "console_init");
      
     diff --git a/libcutils/iosched_policy.c b/libcutils/iosched_policy.c
    -index 71bc94b..8a21b8b 100644
    +index 71bc94b25..8a21b8bd7 100644
     --- a/libcutils/iosched_policy.c
     +++ b/libcutils/iosched_policy.c
     @@ -1,9 +1,10 @@
    @@ -374,7 +556,7 @@ index 71bc94b..8a21b8b 100644
     +#endif
     +
     diff --git a/libnetutils/packet.c b/libnetutils/packet.c
    -index cd26d05..bfc5f4d 100644
    +index cd26d058a..bfc5f4d4e 100644
     --- a/libnetutils/packet.c
     +++ b/libnetutils/packet.c
     @@ -219,6 +219,20 @@ int receive_packet(int s, struct dhcp_msg *msg)
    @@ -399,7 +581,7 @@ index cd26d05..bfc5f4d 100644
          daddr = packet.ip.daddr;
          nread = ntohs(packet.ip.tot_len);
     diff --git a/libutils/String16.cpp b/libutils/String16.cpp
    -index 65396ca..32e026b 100644
    +index 65396caca..32e026bac 100644
     --- a/libutils/String16.cpp
     +++ b/libutils/String16.cpp
     @@ -84,6 +84,24 @@ static char16_t* allocFromUTF8(const char* u8str, size_t u8len)
    @@ -506,7 +688,7 @@ index 65396ca..32e026b 100644
              ->editResize((myLen+otherLen+1)*sizeof(char16_t));
          if (buf) {
     diff --git a/libutils/Unicode.cpp b/libutils/Unicode.cpp
    -index ba084f6..bfacf1e 100644
    +index ba084f6ce..bfacf1ed7 100644
     --- a/libutils/Unicode.cpp
     +++ b/libutils/Unicode.cpp
     @@ -18,6 +18,7 @@
    @@ -561,7 +743,7 @@ index ba084f6..bfacf1e 100644
          return ret;
      }
     diff --git a/libziparchive/zip_archive.cc b/libziparchive/zip_archive.cc
    -index 49097ce..89cfe77 100644
    +index 49097ce9b..89cfe77bc 100644
     --- a/libziparchive/zip_archive.cc
     +++ b/libziparchive/zip_archive.cc
     @@ -358,6 +358,8 @@ static int32_t MapCentralDirectory(int fd, const char* debug_file_name,
    @@ -597,7 +779,7 @@ index 49097ce..89cfe77 100644
      
        return 0;
     diff --git a/libziparchive/zip_archive_test.cc b/libziparchive/zip_archive_test.cc
    -index 6aee1bb..b8db6a4 100644
    +index 6aee1bbdf..b8db6a4d3 100644
     --- a/libziparchive/zip_archive_test.cc
     +++ b/libziparchive/zip_archive_test.cc
     @@ -603,6 +603,55 @@ TEST(ziparchive, StreamUncompressedBadCrc) {
    @@ -657,10 +839,20 @@ index 6aee1bb..b8db6a4 100644
        ::testing::InitGoogleTest(&argc, argv);
      
     diff --git a/rootdir/init.rc b/rootdir/init.rc
    -index 7dc9e55..adc062b 100644
    +index 7dc9e5509..35ea5811e 100644
     --- a/rootdir/init.rc
     +++ b/rootdir/init.rc
    -@@ -656,6 +656,6 @@ on property:ro.debuggable=1
    +@@ -136,6 +136,9 @@ on init
    +     write /proc/sys/net/ipv4/conf/all/accept_redirects 0
    +     write /proc/sys/net/ipv6/conf/all/accept_redirects 0
    + 
    ++    # /proc/net/fib_trie leaks interface IP addresses
    ++    chmod 0400 /proc/net/fib_trie
    ++
    +     # Create cgroup mount points for process groups
    +     mkdir /dev/cpuctl
    +     mount cgroup none /dev/cpuctl cpu
    +@@ -656,6 +659,6 @@ on property:ro.debuggable=1
          chmod 0773 /data/misc/trace
          start console
      
    diff --git a/system_media.patch b/system_media.patch
    index 48fc292..29375c0 100644
    --- a/system_media.patch
    +++ b/system_media.patch
    @@ -1,5 +1,5 @@
     diff --git a/camera/src/camera_metadata.c b/camera/src/camera_metadata.c
    -index e369c64..70074c8 100644
    +index e369c642..70074c82 100644
     --- a/camera/src/camera_metadata.c
     +++ b/camera/src/camera_metadata.c
     @@ -182,7 +182,13 @@ camera_metadata_t *allocate_copy_camera_metadata_checked(
    diff --git a/system_sepolicy.patch b/system_sepolicy.patch
    index 623b327..fe8ec94 100644
    --- a/system_sepolicy.patch
    +++ b/system_sepolicy.patch
    @@ -1,5 +1,5 @@
     diff --git a/Android.mk b/Android.mk
    -index 0bfa54d..886e081 100644
    +index 0bfa54d3..886e0816 100644
     --- a/Android.mk
     +++ b/Android.mk
     @@ -95,7 +95,10 @@ $(sepolicy_policy.conf): $(call build_policy, $(sepolicy_build_files))
    @@ -22,7 +22,7 @@ index 0bfa54d..886e081 100644
      
      $(LOCAL_BUILT_MODULE): $(sepolicy_policy_recovery.conf) $(HOST_OUT_EXECUTABLES)/checkpolicy $(HOST_OUT_EXECUTABLES)/sepolicy-analyze
     diff --git a/app.te b/app.te
    -index e9dd7b3..ef2bd9d 100644
    +index e9dd7b39..ef2bd9d8 100644
     --- a/app.te
     +++ b/app.te
     @@ -274,7 +274,7 @@ allow appdomain cache_file:dir getattr;
    @@ -35,7 +35,7 @@ index e9dd7b3..ef2bd9d 100644
      
      # Block device access.
     diff --git a/attributes b/attributes
    -index a846c34..e8fe3ae 100644
    +index a846c347..e8fe3aea 100644
     --- a/attributes
     +++ b/attributes
     @@ -113,3 +113,5 @@ attribute boot_control_hal;
    @@ -45,7 +45,7 @@ index a846c34..e8fe3ae 100644
     +
     +attribute tracefs_type;
     diff --git a/domain.te b/domain.te
    -index 45569de..5013ad3 100644
    +index 45569de4..5013ad30 100644
     --- a/domain.te
     +++ b/domain.te
     @@ -62,7 +62,7 @@ allow domain debuggerd:unix_stream_socket connectto;
    @@ -155,7 +155,7 @@ index 45569de..5013ad3 100644
      neverallow {
        domain
     diff --git a/file.te b/file.te
    -index 87cec82..bdc7cbe 100644
    +index 87cec829..bdc7cbe6 100644
     --- a/file.te
     +++ b/file.te
     @@ -46,6 +46,8 @@ type devpts, fs_type, mlstrustedobject;
    @@ -168,7 +168,7 @@ index 87cec82..bdc7cbe 100644
      type sdcardfs, sdcard_type, fs_type, mlstrustedobject;
      type vfat, sdcard_type, fs_type, mlstrustedobject;
     diff --git a/mediaserver.te b/mediaserver.te
    -index 5fbaa30..dc05e14 100644
    +index 5fbaa303..dc05e14b 100644
     --- a/mediaserver.te
     +++ b/mediaserver.te
     @@ -94,6 +94,12 @@ allow mediaserver processinfo_service:service_manager find;
    @@ -185,7 +185,7 @@ index 5fbaa30..dc05e14 100644
      allow mediaserver oemfs:dir search;
      allow mediaserver oemfs:file r_file_perms;
     diff --git a/priv_app.te b/priv_app.te
    -index 85516a6..e1f96d5 100644
    +index 85516a6e..e1f96d5d 100644
     --- a/priv_app.te
     +++ b/priv_app.te
     @@ -112,7 +112,7 @@ neverallow priv_app domain:netlink_socket *;
    @@ -198,7 +198,7 @@ index 85516a6..e1f96d5 100644
      # Do not allow privileged apps to register services.
      # Only trusted components of Android should be registering
     diff --git a/untrusted_app.te b/untrusted_app.te
    -index 35c811c..19cfc64 100644
    +index 35c811c5..19cfc64f 100644
     --- a/untrusted_app.te
     +++ b/untrusted_app.te
     @@ -62,7 +62,7 @@ allow untrusted_app media_rw_data_file:file create_file_perms;
    diff --git a/update_engine.patch b/update_engine.patch
    index d6b0205..c555a84 100644
    --- a/update_engine.patch
    +++ b/update_engine.patch
    @@ -1,5 +1,5 @@
     diff --git a/common/error_code.h b/common/error_code.h
    -index 32155f2..3800bf0 100644
    +index 32155f27..3800bf0f 100644
     --- a/common/error_code.h
     +++ b/common/error_code.h
     @@ -72,6 +72,9 @@ enum class ErrorCode : int {
    @@ -13,7 +13,7 @@ index 32155f2..3800bf0 100644
        // VERY IMPORTANT! When adding new error codes:
        //
     diff --git a/common/error_code_utils.cc b/common/error_code_utils.cc
    -index dc9eaf4..0a015eb 100644
    +index dc9eaf4a..0a015eb2 100644
     --- a/common/error_code_utils.cc
     +++ b/common/error_code_utils.cc
     @@ -142,6 +142,10 @@ string ErrorCodeToString(ErrorCode code) {
    @@ -28,7 +28,7 @@ index dc9eaf4..0a015eb 100644
          // error codes which should be added here.
        }
     diff --git a/common/fake_hardware.h b/common/fake_hardware.h
    -index 0bd297b..25324ae 100644
    +index 0bd297bf..25324aec 100644
     --- a/common/fake_hardware.h
     +++ b/common/fake_hardware.h
     @@ -82,6 +82,8 @@ class FakeHardware : public HardwareInterface {
    @@ -60,7 +60,7 @@ index 0bd297b..25324ae 100644
        DISALLOW_COPY_AND_ASSIGN(FakeHardware);
      };
     diff --git a/common/hardware_interface.h b/common/hardware_interface.h
    -index c2d4296..d5f73f7 100644
    +index c2d42964..d5f73f78 100644
     --- a/common/hardware_interface.h
     +++ b/common/hardware_interface.h
     @@ -17,6 +17,8 @@
    @@ -83,7 +83,7 @@ index c2d4296..d5f73f7 100644
      
      }  // namespace chromeos_update_engine
     diff --git a/hardware_android.cc b/hardware_android.cc
    -index 778f8ad..9490c24 100644
    +index 778f8ad9..9490c24a 100644
     --- a/hardware_android.cc
     +++ b/hardware_android.cc
     @@ -25,6 +25,7 @@
    @@ -172,7 +172,7 @@ index 778f8ad..9490c24 100644
     +
      }  // namespace chromeos_update_engine
     diff --git a/hardware_android.h b/hardware_android.h
    -index 4ea3404..6561377 100644
    +index 4ea34042..65613774 100644
     --- a/hardware_android.h
     +++ b/hardware_android.h
     @@ -45,6 +45,7 @@ class HardwareAndroid final : public HardwareInterface {
    @@ -184,7 +184,7 @@ index 4ea3404..6561377 100644
       private:
        DISALLOW_COPY_AND_ASSIGN(HardwareAndroid);
     diff --git a/hardware_chromeos.cc b/hardware_chromeos.cc
    -index 85131fc..f0f3ea9 100644
    +index 85131fc4..f0f3ea98 100644
     --- a/hardware_chromeos.cc
     +++ b/hardware_chromeos.cc
     @@ -16,22 +16,27 @@
    @@ -340,7 +340,7 @@ index 85131fc..f0f3ea9 100644
     +
      }  // namespace chromeos_update_engine
     diff --git a/hardware_chromeos.h b/hardware_chromeos.h
    -index 221f12c..e3f086f 100644
    +index 221f12c8..e3f086f3 100644
     --- a/hardware_chromeos.h
     +++ b/hardware_chromeos.h
     @@ -46,6 +46,7 @@ class HardwareChromeOS final : public HardwareInterface {
    @@ -352,7 +352,7 @@ index 221f12c..e3f086f 100644
       private:
        DISALLOW_COPY_AND_ASSIGN(HardwareChromeOS);
     diff --git a/metrics_utils.cc b/metrics_utils.cc
    -index 11260fc..433ca1e 100644
    +index 11260fc6..433ca1e7 100644
     --- a/metrics_utils.cc
     +++ b/metrics_utils.cc
     @@ -74,6 +74,7 @@ metrics::AttemptResult GetAttemptResult(ErrorCode code) {
    @@ -372,7 +372,7 @@ index 11260fc..433ca1e 100644
      
          // Special flags. These can't happen (we mask them out above) but
     diff --git a/payload_consumer/delta_performer.cc b/payload_consumer/delta_performer.cc
    -index a156132..b338d34 100644
    +index a1561327..b338d344 100644
     --- a/payload_consumer/delta_performer.cc
     +++ b/payload_consumer/delta_performer.cc
     @@ -1502,6 +1502,14 @@ ErrorCode DeltaPerformer::ValidateManifest() {
    @@ -391,7 +391,7 @@ index a156132..b338d34 100644
        // partition boundaries etc (see chromium-os:37661).
      
     diff --git a/payload_consumer/delta_performer_unittest.cc b/payload_consumer/delta_performer_unittest.cc
    -index d1918b7..2ee4516 100644
    +index d1918b71..2ee4516d 100644
     --- a/payload_consumer/delta_performer_unittest.cc
     +++ b/payload_consumer/delta_performer_unittest.cc
     @@ -638,6 +638,20 @@ TEST_F(DeltaPerformerTest, ValidateManifestBadMinorVersion) {
    @@ -416,7 +416,7 @@ index d1918b7..2ee4516 100644
        EXPECT_TRUE(performer_.Write(kDeltaMagic, sizeof(kDeltaMagic)));
      
     diff --git a/payload_generator/generate_delta_main.cc b/payload_generator/generate_delta_main.cc
    -index 0716c1f..85785c5 100644
    +index 0716c1f1..85785c55 100644
     --- a/payload_generator/generate_delta_main.cc
     +++ b/payload_generator/generate_delta_main.cc
     @@ -322,6 +322,10 @@ int Main(int argc, char** argv) {
    @@ -440,7 +440,7 @@ index 0716c1f..85785c5 100644
          LOG(INFO) << "Generating delta update";
        } else {
     diff --git a/payload_generator/payload_file.cc b/payload_generator/payload_file.cc
    -index 2f95b21..d2ae706 100644
    +index 2f95b21c..d2ae7062 100644
     --- a/payload_generator/payload_file.cc
     +++ b/payload_generator/payload_file.cc
     @@ -70,6 +70,7 @@ bool PayloadFile::Init(const PayloadGenerationConfig& config) {
    @@ -452,7 +452,7 @@ index 2f95b21..d2ae706 100644
      }
      
     diff --git a/payload_generator/payload_generation_config.h b/payload_generator/payload_generation_config.h
    -index 8617d14..dd3242a 100644
    +index 8617d14d..dd3242ac 100644
     --- a/payload_generator/payload_generation_config.h
     +++ b/payload_generator/payload_generation_config.h
     @@ -190,6 +190,9 @@ struct PayloadGenerationConfig {
    @@ -466,7 +466,7 @@ index 8617d14..dd3242a 100644
      
      }  // namespace chromeos_update_engine
     diff --git a/payload_state.cc b/payload_state.cc
    -index 04b6579..7859420 100644
    +index 04b6579b..78594201 100644
     --- a/payload_state.cc
     +++ b/payload_state.cc
     @@ -295,6 +295,7 @@ void PayloadState::UpdateFailed(ErrorCode error) {
    @@ -478,7 +478,7 @@ index 04b6579..7859420 100644
            break;
      
     diff --git a/scripts/brillo_update_payload b/scripts/brillo_update_payload
    -index 8d51118..9b599d4 100755
    +index 8d51118b..9b599d41 100755
     --- a/scripts/brillo_update_payload
     +++ b/scripts/brillo_update_payload
     @@ -143,6 +143,10 @@ if [[ "${COMMAND}" == "generate" ]]; then
    @@ -504,7 +504,7 @@ index 8d51118..9b599d4 100755
          GENERATOR_ARGS+=(
            --new_postinstall_config_file="${POSTINSTALL_CONFIG_FILE}"
     diff --git a/update_attempter_android.cc b/update_attempter_android.cc
    -index 1269cef..0fa1fa1 100644
    +index 1269cefd..0fa1fa1b 100644
     --- a/update_attempter_android.cc
     +++ b/update_attempter_android.cc
     @@ -26,6 +26,7 @@
    @@ -528,7 +528,7 @@ index 1269cef..0fa1fa1 100644
            // Ignore all other error codes.
            break;
     diff --git a/update_manager/chromeos_policy.cc b/update_manager/chromeos_policy.cc
    -index aed2aaa..02ec19f 100644
    +index aed2aaab..02ec19f3 100644
     --- a/update_manager/chromeos_policy.cc
     +++ b/update_manager/chromeos_policy.cc
     @@ -76,6 +76,7 @@ bool HandleErrorCode(ErrorCode err_code, int* url_num_error_p) {
    @@ -540,7 +540,7 @@ index aed2aaa..02ec19f 100644
                      << chromeos_update_engine::utils::ErrorCodeToString(err_code)
                      << " (" << static_cast<int>(err_code) << ")";
     diff --git a/update_metadata.proto b/update_metadata.proto
    -index 454c736..596a04e 100644
    +index 454c7368..596a04ef 100644
     --- a/update_metadata.proto
     +++ b/update_metadata.proto
     @@ -281,4 +281,8 @@ message DeltaArchiveManifest {
    
    From ec7efee15fd89bfa5bf43c6444677c4de5c950df Mon Sep 17 00:00:00 2001
    From: AndDiSa <anddisa@googlemail.com>
    Date: Tue, 16 Oct 2018 21:21:23 +0200
    Subject: [PATCH 103/159] update patches
    
    Change-Id: I7e2a49770b6c69e8afdbc9d7cb2822887acacde0
    ---
     build.patch                              |   4 +-
     external_chromium_libpac.patch           | 116 ++++
     external_libmpeg2.patch                  |  82 ++-
     external_neven.patch                     |  13 +
     frameworks_av.patch                      |  19 +
     frameworks_base.patch                    | 695 +++++++++++++++++++++++
     packages_provider_downloadprovider.patch | 326 +++++++++++
     system_bt.patch                          | 299 +++++++++-
     system_vold.patch                        |  25 +
     9 files changed, 1545 insertions(+), 34 deletions(-)
     create mode 100644 external_chromium_libpac.patch
     create mode 100644 external_neven.patch
     create mode 100644 packages_provider_downloadprovider.patch
     create mode 100644 system_vold.patch
    
    diff --git a/build.patch b/build.patch
    index 6da1e9e..cc5de00 100644
    --- a/build.patch
    +++ b/build.patch
    @@ -323,7 +323,7 @@ index 000000000..80664faf2
     +ALL_PREBUILT += $(INSTALLED_KERNEL_TARGET)
     +endif
     diff --git a/core/version_defaults.mk b/core/version_defaults.mk
    -index 7c9634490..662cd0807 100644
    +index 7c9634490..a6f4f1aec 100644
     --- a/core/version_defaults.mk
     +++ b/core/version_defaults.mk
     @@ -131,7 +131,7 @@ ifeq "" "$(PLATFORM_SECURITY_PATCH)"
    @@ -331,7 +331,7 @@ index 7c9634490..662cd0807 100644
          #  It must match one of the Android Security Patch Level strings of the Public Security Bulletins.
          #  If there is no $PLATFORM_SECURITY_PATCH set, keep it empty.
     -    PLATFORM_SECURITY_PATCH := 2017-08-05
    -+    PLATFORM_SECURITY_PATCH := 2018-09-05
    ++    PLATFORM_SECURITY_PATCH := 2018-10-05
      endif
      
      ifeq "" "$(PLATFORM_BASE_OS)"
    diff --git a/external_chromium_libpac.patch b/external_chromium_libpac.patch
    new file mode 100644
    index 0000000..27db9a9
    --- /dev/null
    +++ b/external_chromium_libpac.patch
    @@ -0,0 +1,116 @@
    +diff --git a/Android.mk b/Android.mk
    +index e8a2b26..ae0e768 100644
    +--- a/Android.mk
    ++++ b/Android.mk
    +@@ -18,6 +18,7 @@ LOCAL_CFLAGS += \
    +   -Wno-import \
    +   -Wno-format \
    +   -Wno-unused-parameter \
    ++  -Werror
    + 
    + LOCAL_C_INCLUDES += $(LOCAL_PATH)/src $(LOCAL_PATH)/../v8
    + 
    +@@ -28,3 +29,5 @@ LOCAL_SHARED_LIBRARIES := libutils liblog libicuuc libicui18n
    + LOCAL_CXX_STL := libc++
    + 
    + include $(BUILD_SHARED_LIBRARY)
    ++
    ++include $(LOCAL_PATH)/test/Android.mk
    +diff --git a/src/net_util.cc b/src/net_util.cc
    +index 992cdd1..8eef03a 100644
    +--- a/src/net_util.cc
    ++++ b/src/net_util.cc
    +@@ -64,7 +64,7 @@ bool ParseCIDRBlock(const std::string& cidr_literal,
    +   //   <IPv6-literal> "/" <number of bits>
    + 
    +   std::vector<std::string> parts;
    +-  unsigned int split = cidr_literal.find('/');
    ++  size_t split = cidr_literal.find('/');
    +   if (split == std::string::npos)
    +     return false;
    +   parts.push_back(cidr_literal.substr(0, split));
    +diff --git a/test/Android.mk b/test/Android.mk
    +index 9c9722e..edf9107 100644
    +--- a/test/Android.mk
    ++++ b/test/Android.mk
    +@@ -18,6 +18,6 @@ LOCAL_CFLAGS += \
    + 
    + LOCAL_C_INCLUDES += $(LOCAL_PATH)/../src $(LOCAL_PATH)/ external/v8
    + 
    +-LOCAL_SHARED_LIBRARIES := libpac libutils liblog
    ++LOCAL_SHARED_LIBRARIES := libpac libutils liblog libandroid_runtime
    + 
    + include $(BUILD_NATIVE_TEST)
    +diff --git a/test/js-unittest/change_element_kind.js b/test/js-unittest/change_element_kind.js
    +new file mode 100644
    +index 0000000..335d59e
    +--- /dev/null
    ++++ b/test/js-unittest/change_element_kind.js
    +@@ -0,0 +1,15 @@
    ++// PAC script with getter that changes element kind.
    ++
    ++function FindProxyForURL(url, host) {
    ++  let arr = [];
    ++  arr[1000] = 0x1234;
    ++
    ++  arr.__defineGetter__(256, function () {
    ++    delete arr[256];
    ++    arr.unshift(1.1);
    ++  });
    ++
    ++  let results = Object.entries(arr);
    ++  let str = results.toString();
    ++  return "DIRECT";
    ++}
    +diff --git a/test/proxy_resolver_v8_unittest.cc b/test/proxy_resolver_v8_unittest.cc
    +index ad9c826..be7ecee 100644
    +--- a/test/proxy_resolver_v8_unittest.cc
    ++++ b/test/proxy_resolver_v8_unittest.cc
    +@@ -544,5 +544,19 @@ TEST(ProxyResolverV8Test, DNSResolutionOfInternationDomainName) {
    +   EXPECT_EQ("xn--bcher-kva.ch", bindings->dns_resolves_ex[0]);
    + }
    + 
    ++TEST(ProxyResolverV8Test, GetterChangesElementKind) {
    ++  ProxyResolverV8WithMockBindings resolver(new MockJSBindings());
    ++  int result = resolver.SetPacScript(String16(CHANGE_ELEMENT_KIND_JS));
    ++  EXPECT_EQ(OK, result);
    ++
    ++  // Execute FindProxyForURL().
    ++  result = resolver.GetProxyForURL(kQueryUrl, kQueryHost, &kResults);
    ++
    ++  EXPECT_EQ(OK, result);
    ++  std::vector<std::string> proxies = string16ToProxyList(kResults);
    ++  EXPECT_EQ(1U, proxies.size());
    ++  EXPECT_EQ("DIRECT", proxies[0]);
    ++}
    ++
    + }  // namespace
    + }  // namespace net
    +diff --git a/test/proxy_test_script.h b/test/proxy_test_script.h
    +index 1042366..80c96c7 100644
    +--- a/test/proxy_test_script.h
    ++++ b/test/proxy_test_script.h
    +@@ -78,6 +78,23 @@
    +   "function fn() {}\n" \
    +   "\n" \
    + 
    ++#define CHANGE_ELEMENT_KIND_JS \
    ++  "// PAC script with getter that changes element kind.\n" \
    ++  "	\n" \
    ++  "function FindProxyForURL(url, host) {\n" \
    ++  "  let arr = [];\n" \
    ++  "  arr[1000] = 0x1234;\n" \
    ++  "\n" \
    ++  "  arr.__defineGetter__(256, function () {\n" \
    ++  "    delete arr[256];\n" \
    ++  "    arr.unshift(1.1);\n" \
    ++  "  });\n" \
    ++  "\n" \
    ++  "  let results = Object.entries(arr);\n" \
    ++  "  let str = results.toString(); \n" \
    ++  "  return \"DIRECT\";\n" \
    ++  "}\n" \
    ++
    + #define DIRECT_JS \
    +   "function FindProxyForURL(url, host) {\n" \
    +   "  return \"DIRECT\";\n" \
    diff --git a/external_libmpeg2.patch b/external_libmpeg2.patch
    index eb254a1..345816c 100644
    --- a/external_libmpeg2.patch
    +++ b/external_libmpeg2.patch
    @@ -324,10 +324,17 @@ index 36092e5..57a9e2f 100644
      }
      /******************************************************************************
     diff --git a/decoder/impeg2d_dec_hdr.c b/decoder/impeg2d_dec_hdr.c
    -index 4a84086..5a8b996 100644
    +index 4a84086..f5ebafd 100644
     --- a/decoder/impeg2d_dec_hdr.c
     +++ b/decoder/impeg2d_dec_hdr.c
    -@@ -173,7 +173,16 @@ IMPEG2D_ERROR_CODES_T impeg2d_dec_seq_hdr(dec_state_t *ps_dec)
    +@@ -166,14 +166,19 @@ IMPEG2D_ERROR_CODES_T impeg2d_dec_seq_hdr(dec_state_t *ps_dec)
    +             /* This is the first time we are reading the resolution */
    +             ps_dec->u2_horizontal_size = u2_width;
    +             ps_dec->u2_vertical_size = u2_height;
    +-            if (0 == ps_dec->u4_frm_buf_stride)
    +-            {
    +-                ps_dec->u4_frm_buf_stride  = (UWORD32) (u2_width);
    +-            }
              }
              else
              {
    @@ -345,7 +352,31 @@ index 4a84086..5a8b996 100644
                                  || (u2_height > ps_dec->u2_create_max_height))
                  {
                      IMPEG2D_ERROR_CODES_T e_error = IMPEG2D_UNSUPPORTED_DIMENSIONS;
    -@@ -280,6 +289,8 @@ IMPEG2D_ERROR_CODES_T impeg2d_dec_seq_hdr(dec_state_t *ps_dec)
    +@@ -183,6 +188,11 @@ IMPEG2D_ERROR_CODES_T impeg2d_dec_seq_hdr(dec_state_t *ps_dec)
    + 
    +                 return e_error;
    +             }
    ++            else if((ps_dec->u2_horizontal_size < MIN_WIDTH)
    ++                            || (ps_dec->u2_vertical_size < MIN_HEIGHT))
    ++            {
    ++                return IMPEG2D_UNSUPPORTED_DIMENSIONS;
    ++            }
    +             else
    +             {
    +                 /* The resolution has changed */
    +@@ -200,6 +210,11 @@ IMPEG2D_ERROR_CODES_T impeg2d_dec_seq_hdr(dec_state_t *ps_dec)
    +         return e_error;
    +     }
    + 
    ++    if((ps_dec->u2_horizontal_size < MIN_WIDTH)
    ++                    || (ps_dec->u2_vertical_size < MIN_HEIGHT))
    ++    {
    ++        return IMPEG2D_UNSUPPORTED_DIMENSIONS;
    ++    }
    + 
    +     /*------------------------------------------------------------------------*/
    +     /* Flush the following as they are not being used                         */
    +@@ -280,6 +295,8 @@ IMPEG2D_ERROR_CODES_T impeg2d_dec_seq_hdr(dec_state_t *ps_dec)
      IMPEG2D_ERROR_CODES_T impeg2d_dec_seq_ext(dec_state_t *ps_dec)
      {
          stream_t *ps_stream;
    @@ -354,7 +385,7 @@ index 4a84086..5a8b996 100644
      
          ps_stream = &ps_dec->s_bit_stream;
      
    -@@ -329,11 +340,30 @@ IMPEG2D_ERROR_CODES_T impeg2d_dec_seq_ext(dec_state_t *ps_dec)
    +@@ -329,11 +346,30 @@ IMPEG2D_ERROR_CODES_T impeg2d_dec_seq_ext(dec_state_t *ps_dec)
          if(impeg2d_bit_stream_get(ps_stream,2) != 0x1)
              return IMPEG2D_CHROMA_FMT_NOT_SUP;
      
    @@ -387,7 +418,7 @@ index 4a84086..5a8b996 100644
      
          /*-----------------------------------------------------------------------*/
          /* Flush the following as they are not used now                          */
    -@@ -914,7 +944,7 @@ void impeg2d_dec_pic_data_thread(dec_state_t *ps_dec)
    +@@ -914,7 +950,7 @@ void impeg2d_dec_pic_data_thread(dec_state_t *ps_dec)
                      {
                          pu1_buf = ps_dec->pu1_inp_bits_buf + s_job.i4_bistream_ofst;
                          impeg2d_bit_stream_init(&(ps_dec->s_bit_stream), pu1_buf,
    @@ -396,7 +427,7 @@ index 4a84086..5a8b996 100644
                          i4_cur_row      = s_job.i2_start_mb_y;
                          ps_dec->i4_start_mb_y = s_job.i2_start_mb_y;
                          ps_dec->i4_end_mb_y = s_job.i2_end_mb_y;
    -@@ -956,6 +986,11 @@ void impeg2d_dec_pic_data_thread(dec_state_t *ps_dec)
    +@@ -956,6 +992,11 @@ void impeg2d_dec_pic_data_thread(dec_state_t *ps_dec)
                  if ((IMPEG2D_ERROR_CODES_T)IVD_ERROR_NONE != e_error)
                  {
                      impeg2d_next_start_code(ps_dec);
    @@ -408,20 +439,20 @@ index 4a84086..5a8b996 100644
                  }
              }
      
    -@@ -975,23 +1010,30 @@ void impeg2d_dec_pic_data_thread(dec_state_t *ps_dec)
    +@@ -975,23 +1016,30 @@ void impeg2d_dec_pic_data_thread(dec_state_t *ps_dec)
      
                  if(i4_continue_decode)
                  {
     -                /* If the slice is from the same row, then continue decoding without dequeue */
     -                if((temp - 1) == i4_cur_row)
    -+                if (0 != ps_dec->u2_num_mbs_left)
    -                 {
    +-                {
     -                    i4_dequeue_job = 0;
     -                    break;
     -                }
     -
     -                if(temp < ps_dec->i4_end_mb_y)
    --                {
    ++                if (0 != ps_dec->u2_num_mbs_left)
    +                 {
     -                    i4_cur_row = ps_dec->u2_mb_y;
     +                    /* If the slice is from the same row, then continue decoding without dequeue */
     +                    if((temp - 1) == i4_cur_row)
    @@ -449,7 +480,7 @@ index 4a84086..5a8b996 100644
                  }
                  else
                      break;
    -@@ -1068,6 +1110,7 @@ static WORD32 impeg2d_init_thread_dec_ctxt(dec_state_t *ps_dec,
    +@@ -1068,6 +1116,7 @@ static WORD32 impeg2d_init_thread_dec_ctxt(dec_state_t *ps_dec,
          ps_dec_thd->u2_mb_x = 0;
          ps_dec_thd->u2_mb_y = 0;
          ps_dec_thd->u2_is_mpeg2 = ps_dec->u2_is_mpeg2;
    @@ -457,7 +488,7 @@ index 4a84086..5a8b996 100644
          ps_dec_thd->u2_frame_width = ps_dec->u2_frame_width;
          ps_dec_thd->u2_frame_height = ps_dec->u2_frame_height;
          ps_dec_thd->u2_picture_width = ps_dec->u2_picture_width;
    -@@ -1337,8 +1380,6 @@ void impeg2d_dec_pic_data(dec_state_t *ps_dec)
    +@@ -1337,8 +1386,6 @@ void impeg2d_dec_pic_data(dec_state_t *ps_dec)
          WORD32 i;
          dec_state_multi_core_t *ps_dec_state_multi_core;
      
    @@ -466,7 +497,7 @@ index 4a84086..5a8b996 100644
          dec_state_t *ps_dec_thd;
          WORD32 i4_status;
          WORD32 i4_min_mb_y;
    -@@ -1346,7 +1387,6 @@ void impeg2d_dec_pic_data(dec_state_t *ps_dec)
    +@@ -1346,7 +1393,6 @@ void impeg2d_dec_pic_data(dec_state_t *ps_dec)
      
          /* Resetting the MB address and MB coordinates at the start of the Frame */
          ps_dec->u2_mb_x = ps_dec->u2_mb_y = 0;
    @@ -474,7 +505,7 @@ index 4a84086..5a8b996 100644
      
          ps_dec_state_multi_core = ps_dec->ps_dec_state_multi_core;
          impeg2d_get_slice_pos(ps_dec_state_multi_core);
    -@@ -1390,8 +1430,6 @@ void impeg2d_dec_pic_data(dec_state_t *ps_dec)
    +@@ -1390,8 +1436,6 @@ void impeg2d_dec_pic_data(dec_state_t *ps_dec)
              }
          }
      
    @@ -483,7 +514,7 @@ index 4a84086..5a8b996 100644
      }
      /*******************************************************************************
      *
    -@@ -1725,6 +1763,7 @@ IMPEG2D_ERROR_CODES_T impeg2d_process_video_bit_stream(dec_state_t *ps_dec)
    +@@ -1725,6 +1769,7 @@ IMPEG2D_ERROR_CODES_T impeg2d_process_video_bit_stream(dec_state_t *ps_dec)
                  else if((ps_dec->s_bit_stream.u4_offset < ps_dec->s_bit_stream.u4_max_offset)
                          && (u4_next_bits == PICTURE_START_CODE))
                  {
    @@ -491,7 +522,7 @@ index 4a84086..5a8b996 100644
      
                      e_error = impeg2d_dec_pic_hdr(ps_dec);
                      if ((IMPEG2D_ERROR_CODES_T)IVD_ERROR_NONE != e_error)
    -@@ -1741,7 +1780,11 @@ IMPEG2D_ERROR_CODES_T impeg2d_process_video_bit_stream(dec_state_t *ps_dec)
    +@@ -1741,7 +1786,11 @@ IMPEG2D_ERROR_CODES_T impeg2d_process_video_bit_stream(dec_state_t *ps_dec)
                      {
                          return e_error;
                      }
    @@ -504,7 +535,7 @@ index 4a84086..5a8b996 100644
                      impeg2d_dec_pic_data(ps_dec);
                      impeg2d_post_pic_dec_proc(ps_dec);
                      u4_start_code_found = 1;
    -@@ -1813,6 +1856,7 @@ IMPEG2D_ERROR_CODES_T impeg2d_process_video_bit_stream(dec_state_t *ps_dec)
    +@@ -1813,6 +1862,7 @@ IMPEG2D_ERROR_CODES_T impeg2d_process_video_bit_stream(dec_state_t *ps_dec)
                  else if ((impeg2d_bit_stream_nxt(ps_stream,START_CODE_LEN) == PICTURE_START_CODE)
                          && (ps_dec->s_bit_stream.u4_offset < ps_dec->s_bit_stream.u4_max_offset))
                  {
    @@ -513,7 +544,7 @@ index 4a84086..5a8b996 100644
                      e_error = impeg2d_dec_pic_hdr(ps_dec);
                      if ((IMPEG2D_ERROR_CODES_T)IVD_ERROR_NONE != e_error)
     diff --git a/decoder/impeg2d_decoder.c b/decoder/impeg2d_decoder.c
    -index fa88bb5..e4ff79c 100644
    +index fa88bb5..8846066 100644
     --- a/decoder/impeg2d_decoder.c
     +++ b/decoder/impeg2d_decoder.c
     @@ -98,12 +98,17 @@ void impeg2d_dec_hdr(void *pv_dec,impeg2d_video_decode_ip_t *ps_ip,
    @@ -535,7 +566,20 @@ index fa88bb5..e4ff79c 100644
      
          {
              {
    -@@ -189,12 +194,15 @@ void impeg2d_dec_frm(void *pv_dec,impeg2d_video_decode_ip_t *ps_ip,
    +@@ -148,6 +153,12 @@ void impeg2d_dec_hdr(void *pv_dec,impeg2d_video_decode_ip_t *ps_ip,
    +             ps_op->s_ivd_video_decode_op_t.u4_num_bytes_consumed = ps_ip->s_ivd_video_decode_ip_t.u4_num_Bytes;
    +         }
    +         ps_op->s_ivd_video_decode_op_t.u4_frame_decoded_flag = 0;
    ++
    ++        /* Set the stride */
    ++        if (0 == ps_dec->u4_frm_buf_stride)
    ++        {
    ++            ps_dec->u4_frm_buf_stride = ps_dec->u2_horizontal_size;
    ++        }
    +         /* MOD */
    +         ps_dec->u2_header_done = 1;
    + 
    +@@ -189,12 +200,15 @@ void impeg2d_dec_frm(void *pv_dec,impeg2d_video_decode_ip_t *ps_ip,
          ps_op->s_ivd_video_decode_op_t.u4_num_bytes_consumed = 0;
      
          IMPEG2D_FRM_NUM_SET();
    diff --git a/external_neven.patch b/external_neven.patch
    new file mode 100644
    index 0000000..d1869e6
    --- /dev/null
    +++ b/external_neven.patch
    @@ -0,0 +1,13 @@
    +diff --git a/Embedded/common/src/b_BitFeatureEm/Scanner.c b/Embedded/common/src/b_BitFeatureEm/Scanner.c
    +index 327e714..1a0ae2a 100644
    +--- a/Embedded/common/src/b_BitFeatureEm/Scanner.c
    ++++ b/Embedded/common/src/b_BitFeatureEm/Scanner.c
    +@@ -1064,7 +1064,7 @@ void bbf_Scanner_addOutPos( struct bbs_Context* cpA,
    + 							uint32 scaleA, 
    + 							int32 actA )
    + {
    +-	if( ( ptrA->outCountE * 4 ) < ptrA->outArrE.sizeE )
    ++	if( ( ptrA->outCountE * 4 + 3 ) < ptrA->outArrE.sizeE )
    + 	{
    +         ptrA->outArrE.arrPtrE[ ptrA->outCountE * 4 + 0 ] = xA;
    +         ptrA->outArrE.arrPtrE[ ptrA->outCountE * 4 + 1 ] = yA;
    diff --git a/frameworks_av.patch b/frameworks_av.patch
    index cf50e4f..47ebe2d 100644
    --- a/frameworks_av.patch
    +++ b/frameworks_av.patch
    @@ -3065,6 +3065,25 @@ index b3a11e0a5..cd543c859 100644
          void                sendStoreAdded(MtpStorageID id);
          void                sendStoreRemoved(MtpStorageID id);
          void                sendEvent(MtpEventCode code, uint32_t param1);
    +diff --git a/media/ndk/NdkMediaCodec.cpp b/media/ndk/NdkMediaCodec.cpp
    +index 50b490d45..73e733e77 100644
    +--- a/media/ndk/NdkMediaCodec.cpp
    ++++ b/media/ndk/NdkMediaCodec.cpp
    +@@ -447,7 +447,13 @@ AMediaCodecCryptoInfo *AMediaCodecCryptoInfo_new(
    +         size_t *encryptedbytes) {
    + 
    +     // size needed to store all the crypto data
    +-    size_t cryptosize = sizeof(AMediaCodecCryptoInfo) + sizeof(size_t) * numsubsamples * 2;
    ++    size_t cryptosize;
    ++    // = sizeof(AMediaCodecCryptoInfo) + sizeof(size_t) * numsubsamples * 2;
    ++    if (__builtin_mul_overflow(sizeof(size_t) * 2, numsubsamples, &cryptosize) ||
    ++            __builtin_add_overflow(cryptosize, sizeof(AMediaCodecCryptoInfo), &cryptosize)) {
    ++        ALOGE("crypto size overflow");
    ++        return NULL;
    ++    }
    +     AMediaCodecCryptoInfo *ret = (AMediaCodecCryptoInfo*) malloc(cryptosize);
    +     if (!ret) {
    +         ALOGE("couldn't allocate %zu bytes", cryptosize);
     diff --git a/services/audioflinger/AudioFlinger.cpp b/services/audioflinger/AudioFlinger.cpp
     index fec3a57c1..4aad2c219 100644
     --- a/services/audioflinger/AudioFlinger.cpp
    diff --git a/frameworks_base.patch b/frameworks_base.patch
    index d5d2baf..44e274a 100644
    --- a/frameworks_base.patch
    +++ b/frameworks_base.patch
    @@ -322,6 +322,369 @@ index a1103838280..aea843adbd4 100644
                  }
              }
              return false;
    +diff --git a/core/java/android/database/sqlite/SQLiteDatabase.java b/core/java/android/database/sqlite/SQLiteDatabase.java
    +index 8e178320d66..f300b5be452 100644
    +--- a/core/java/android/database/sqlite/SQLiteDatabase.java
    ++++ b/core/java/android/database/sqlite/SQLiteDatabase.java
    +@@ -1658,7 +1658,8 @@ public final class SQLiteDatabase extends SQLiteClosable {
    +         executeSql(sql, bindArgs);
    +     }
    + 
    +-    private int executeSql(String sql, Object[] bindArgs) throws SQLException {
    ++    /** {@hide} */
    ++    public int executeSql(String sql, Object[] bindArgs) throws SQLException {
    +         acquireReference();
    +         try {
    +             if (DatabaseUtils.getSqlStatementType(sql) == DatabaseUtils.STATEMENT_ATTACH) {
    +diff --git a/core/java/android/database/sqlite/SQLiteQueryBuilder.java b/core/java/android/database/sqlite/SQLiteQueryBuilder.java
    +index 56cba795355..13ab6fb0797 100644
    +--- a/core/java/android/database/sqlite/SQLiteQueryBuilder.java
    ++++ b/core/java/android/database/sqlite/SQLiteQueryBuilder.java
    +@@ -16,17 +16,25 @@
    + 
    + package android.database.sqlite;
    + 
    ++import android.annotation.NonNull;
    ++import android.annotation.Nullable;
    ++import android.content.ContentValues;
    + import android.database.Cursor;
    + import android.database.DatabaseUtils;
    ++import android.os.Build;
    + import android.os.CancellationSignal;
    + import android.os.OperationCanceledException;
    + import android.provider.BaseColumns;
    + import android.text.TextUtils;
    + import android.util.Log;
    + 
    ++import libcore.util.EmptyArray;
    ++
    ++import java.util.Arrays;
    + import java.util.Iterator;
    + import java.util.Map;
    + import java.util.Map.Entry;
    ++import java.util.Objects;
    + import java.util.Set;
    + import java.util.regex.Pattern;
    + 
    +@@ -95,9 +103,6 @@ public class SQLiteQueryBuilder
    +         if (mWhereClause == null) {
    +             mWhereClause = new StringBuilder(inWhere.length() + 16);
    +         }
    +-        if (mWhereClause.length() == 0) {
    +-            mWhereClause.append('(');
    +-        }
    +         mWhereClause.append(inWhere);
    +     }
    + 
    +@@ -115,9 +120,6 @@ public class SQLiteQueryBuilder
    +         if (mWhereClause == null) {
    +             mWhereClause = new StringBuilder(inWhere.length() + 16);
    +         }
    +-        if (mWhereClause.length() == 0) {
    +-            mWhereClause.append('(');
    +-        }
    +         DatabaseUtils.appendEscapedSQLString(mWhereClause, inWhere);
    +     }
    + 
    +@@ -376,6 +378,11 @@ public class SQLiteQueryBuilder
    +             return null;
    +         }
    + 
    ++        final String sql;
    ++        final String unwrappedSql = buildQuery(
    ++                projectionIn, selection, groupBy, having,
    ++                sortOrder, limit);
    ++
    +         if (mStrict && selection != null && selection.length() > 0) {
    +             // Validate the user-supplied selection to detect syntactic anomalies
    +             // in the selection string that could indicate a SQL injection attempt.
    +@@ -384,24 +391,166 @@ public class SQLiteQueryBuilder
    +             // originally specified. An attacker cannot create an expression that
    +             // would escape the SQL expression while maintaining balanced parentheses
    +             // in both the wrapped and original forms.
    +-            String sqlForValidation = buildQuery(projectionIn, "(" + selection + ")", groupBy,
    ++
    ++            // NOTE: The ordering of the below operations is important; we must
    ++            // execute the wrapped query to ensure the untrusted clause has been
    ++            // fully isolated.
    ++
    ++            // Validate the unwrapped query
    ++            db.validateSql(unwrappedSql, cancellationSignal); // will throw if query is invalid
    ++
    ++            // Execute wrapped query for extra protection
    ++            final String wrappedSql = buildQuery(projectionIn, wrap(selection), groupBy,
    +                     having, sortOrder, limit);
    +-            db.validateSql(sqlForValidation, cancellationSignal); // will throw if query is invalid
    ++            sql = wrappedSql;
    ++        } else {
    ++            // Execute unwrapped query
    ++            sql = unwrappedSql;
    +         }
    + 
    +-        String sql = buildQuery(
    +-                projectionIn, selection, groupBy, having,
    +-                sortOrder, limit);
    +-
    ++        final String[] sqlArgs = selectionArgs;
    +         if (Log.isLoggable(TAG, Log.DEBUG)) {
    +-            Log.d(TAG, "Performing query: " + sql);
    ++            if (Build.IS_DEBUGGABLE) {
    ++                Log.d(TAG, sql + " with args " + Arrays.toString(sqlArgs));
    ++            } else {
    ++                Log.d(TAG, sql);
    ++            }
    +         }
    +         return db.rawQueryWithFactory(
    +-                mFactory, sql, selectionArgs,
    ++                mFactory, sql, sqlArgs,
    +                 SQLiteDatabase.findEditTable(mTables),
    +                 cancellationSignal); // will throw if query is invalid
    +     }
    + 
    ++    /**
    ++     * Perform an update by combining all current settings and the
    ++     * information passed into this method.
    ++     *
    ++     * @param db the database to update on
    ++     * @param selection A filter declaring which rows to return,
    ++     *   formatted as an SQL WHERE clause (excluding the WHERE
    ++     *   itself). Passing null will return all rows for the given URL.
    ++     * @param selectionArgs You may include ?s in selection, which
    ++     *   will be replaced by the values from selectionArgs, in order
    ++     *   that they appear in the selection. The values will be bound
    ++     *   as Strings.
    ++     * @return the number of rows updated
    ++     * @hide
    ++     */
    ++    public int update(@NonNull SQLiteDatabase db, @NonNull ContentValues values,
    ++            @Nullable String selection, @Nullable String[] selectionArgs) {
    ++        Objects.requireNonNull(mTables, "No tables defined");
    ++        Objects.requireNonNull(db, "No database defined");
    ++        Objects.requireNonNull(values, "No values defined");
    ++
    ++        final String sql;
    ++        final String unwrappedSql = buildUpdate(values, selection);
    ++
    ++        if (mStrict) {
    ++            // Validate the user-supplied selection to detect syntactic anomalies
    ++            // in the selection string that could indicate a SQL injection attempt.
    ++            // The idea is to ensure that the selection clause is a valid SQL expression
    ++            // by compiling it twice: once wrapped in parentheses and once as
    ++            // originally specified. An attacker cannot create an expression that
    ++            // would escape the SQL expression while maintaining balanced parentheses
    ++            // in both the wrapped and original forms.
    ++
    ++            // NOTE: The ordering of the below operations is important; we must
    ++            // execute the wrapped query to ensure the untrusted clause has been
    ++            // fully isolated.
    ++
    ++            // Validate the unwrapped query
    ++            db.validateSql(unwrappedSql, null); // will throw if query is invalid
    ++
    ++            // Execute wrapped query for extra protection
    ++            final String wrappedSql = buildUpdate(values, wrap(selection));
    ++            sql = wrappedSql;
    ++        } else {
    ++            // Execute unwrapped query
    ++            sql = unwrappedSql;
    ++        }
    ++
    ++        if (selectionArgs == null) {
    ++            selectionArgs = EmptyArray.STRING;
    ++        }
    ++        final String[] rawKeys = values.keySet().toArray(EmptyArray.STRING);
    ++        final int valuesLength = rawKeys.length;
    ++        final Object[] sqlArgs = new Object[valuesLength + selectionArgs.length];
    ++        for (int i = 0; i < sqlArgs.length; i++) {
    ++            if (i < valuesLength) {
    ++                sqlArgs[i] = values.get(rawKeys[i]);
    ++            } else {
    ++                sqlArgs[i] = selectionArgs[i - valuesLength];
    ++            }
    ++        }
    ++        if (Log.isLoggable(TAG, Log.DEBUG)) {
    ++            if (Build.IS_DEBUGGABLE) {
    ++                Log.d(TAG, sql + " with args " + Arrays.toString(sqlArgs));
    ++            } else {
    ++                Log.d(TAG, sql);
    ++            }
    ++        }
    ++        return db.executeSql(sql, sqlArgs);
    ++    }
    ++
    ++    /**
    ++     * Perform a delete by combining all current settings and the
    ++     * information passed into this method.
    ++     *
    ++     * @param db the database to delete on
    ++     * @param selection A filter declaring which rows to return,
    ++     *   formatted as an SQL WHERE clause (excluding the WHERE
    ++     *   itself). Passing null will return all rows for the given URL.
    ++     * @param selectionArgs You may include ?s in selection, which
    ++     *   will be replaced by the values from selectionArgs, in order
    ++     *   that they appear in the selection. The values will be bound
    ++     *   as Strings.
    ++     * @return the number of rows deleted
    ++     * @hide
    ++     */
    ++    public int delete(@NonNull SQLiteDatabase db, @Nullable String selection,
    ++            @Nullable String[] selectionArgs) {
    ++        Objects.requireNonNull(mTables, "No tables defined");
    ++        Objects.requireNonNull(db, "No database defined");
    ++
    ++        final String sql;
    ++        final String unwrappedSql = buildDelete(selection);
    ++
    ++        if (mStrict) {
    ++            // Validate the user-supplied selection to detect syntactic anomalies
    ++            // in the selection string that could indicate a SQL injection attempt.
    ++            // The idea is to ensure that the selection clause is a valid SQL expression
    ++            // by compiling it twice: once wrapped in parentheses and once as
    ++            // originally specified. An attacker cannot create an expression that
    ++            // would escape the SQL expression while maintaining balanced parentheses
    ++            // in both the wrapped and original forms.
    ++
    ++            // NOTE: The ordering of the below operations is important; we must
    ++            // execute the wrapped query to ensure the untrusted clause has been
    ++            // fully isolated.
    ++
    ++            // Validate the unwrapped query
    ++            db.validateSql(unwrappedSql, null); // will throw if query is invalid
    ++
    ++            // Execute wrapped query for extra protection
    ++            final String wrappedSql = buildDelete(wrap(selection));
    ++            sql = wrappedSql;
    ++        } else {
    ++            // Execute unwrapped query
    ++            sql = unwrappedSql;
    ++        }
    ++
    ++        final String[] sqlArgs = selectionArgs;
    ++        if (Log.isLoggable(TAG, Log.DEBUG)) {
    ++            if (Build.IS_DEBUGGABLE) {
    ++                Log.d(TAG, sql + " with args " + Arrays.toString(sqlArgs));
    ++            } else {
    ++                Log.d(TAG, sql);
    ++            }
    ++        }
    ++        return db.executeSql(sql, sqlArgs);
    ++    }
    ++
    +     /**
    +      * Construct a SELECT statement suitable for use in a group of
    +      * SELECT statements that will be joined through UNION operators
    +@@ -434,28 +583,10 @@ public class SQLiteQueryBuilder
    +             String[] projectionIn, String selection, String groupBy,
    +             String having, String sortOrder, String limit) {
    +         String[] projection = computeProjection(projectionIn);
    +-
    +-        StringBuilder where = new StringBuilder();
    +-        boolean hasBaseWhereClause = mWhereClause != null && mWhereClause.length() > 0;
    +-
    +-        if (hasBaseWhereClause) {
    +-            where.append(mWhereClause.toString());
    +-            where.append(')');
    +-        }
    +-
    +-        // Tack on the user's selection, if present.
    +-        if (selection != null && selection.length() > 0) {
    +-            if (hasBaseWhereClause) {
    +-                where.append(" AND ");
    +-            }
    +-
    +-            where.append('(');
    +-            where.append(selection);
    +-            where.append(')');
    +-        }
    ++        String where = computeWhere(selection);
    + 
    +         return buildQueryString(
    +-                mDistinct, mTables, projection, where.toString(),
    ++                mDistinct, mTables, projection, where,
    +                 groupBy, having, sortOrder, limit);
    +     }
    + 
    +@@ -472,6 +603,42 @@ public class SQLiteQueryBuilder
    +         return buildQuery(projectionIn, selection, groupBy, having, sortOrder, limit);
    +     }
    + 
    ++    /** {@hide} */
    ++    public String buildUpdate(ContentValues values, String selection) {
    ++        if (values == null || values.size() == 0) {
    ++            throw new IllegalArgumentException("Empty values");
    ++        }
    ++
    ++        StringBuilder sql = new StringBuilder(120);
    ++        sql.append("UPDATE ");
    ++        sql.append(mTables);
    ++        sql.append(" SET ");
    ++
    ++        final String[] rawKeys = values.keySet().toArray(EmptyArray.STRING);
    ++        for (int i = 0; i < rawKeys.length; i++) {
    ++            if (i > 0) {
    ++                sql.append(',');
    ++            }
    ++            sql.append(rawKeys[i]);
    ++            sql.append("=?");
    ++        }
    ++
    ++        final String where = computeWhere(selection);
    ++        appendClause(sql, " WHERE ", where);
    ++        return sql.toString();
    ++    }
    ++
    ++    /** {@hide} */
    ++    public String buildDelete(String selection) {
    ++        StringBuilder sql = new StringBuilder(120);
    ++        sql.append("DELETE FROM ");
    ++        sql.append(mTables);
    ++
    ++        final String where = computeWhere(selection);
    ++        appendClause(sql, " WHERE ", where);
    ++        return sql.toString();
    ++    }
    ++
    +     /**
    +      * Construct a SELECT statement suitable for use in a group of
    +      * SELECT statements that will be joined through UNION operators
    +@@ -645,4 +812,37 @@ public class SQLiteQueryBuilder
    +         }
    +         return null;
    +     }
    ++
    ++    private @Nullable String computeWhere(@Nullable String selection) {
    ++        final boolean hasInternal = !TextUtils.isEmpty(mWhereClause);
    ++        final boolean hasExternal = !TextUtils.isEmpty(selection);
    ++
    ++        if (hasInternal || hasExternal) {
    ++            final StringBuilder where = new StringBuilder();
    ++            if (hasInternal) {
    ++                where.append('(').append(mWhereClause).append(')');
    ++            }
    ++            if (hasInternal && hasExternal) {
    ++                where.append(" AND ");
    ++            }
    ++            if (hasExternal) {
    ++                where.append('(').append(selection).append(')');
    ++            }
    ++            return where.toString();
    ++        } else {
    ++            return null;
    ++        }
    ++    }
    ++
    ++    /**
    ++     * Wrap given argument in parenthesis, unless it's {@code null} or
    ++     * {@code ()}, in which case return it verbatim.
    ++     */
    ++    private @Nullable String wrap(@Nullable String arg) {
    ++        if (TextUtils.isEmpty(arg)) {
    ++            return arg;
    ++        } else {
    ++            return "(" + arg + ")";
    ++        }
    ++    }
    + }
     diff --git a/core/java/android/hardware/location/NanoAppFilter.java b/core/java/android/hardware/location/NanoAppFilter.java
     index bf35a3d6fbd..c44094908f3 100644
     --- a/core/java/android/hardware/location/NanoAppFilter.java
    @@ -465,6 +828,338 @@ index 674f809ef0f..70dfef574ca 100644
                  return true;
              }
              try {
    +diff --git a/core/java/android/text/Layout.java b/core/java/android/text/Layout.java
    +index 0bd5071b6ea..bc55ee798e2 100644
    +--- a/core/java/android/text/Layout.java
    ++++ b/core/java/android/text/Layout.java
    +@@ -824,6 +824,32 @@ public abstract class Layout {
    +         return TextUtils.packRangeInLong(0, getLineEnd(line));
    +     }
    + 
    ++    /**
    ++     * Checks if the trailing BiDi level should be used for an offset
    ++     *
    ++     * This method is useful when the offset is at the BiDi level transition point and determine
    ++     * which run need to be used. For example, let's think about following input: (L* denotes
    ++     * Left-to-Right characters, R* denotes Right-to-Left characters.)
    ++     * Input (Logical Order): L1 L2 L3 R1 R2 R3 L4 L5 L6
    ++     * Input (Display Order): L1 L2 L3 R3 R2 R1 L4 L5 L6
    ++     *
    ++     * Then, think about selecting the range (3, 6). The offset=3 and offset=6 are ambiguous here
    ++     * since they are at the BiDi transition point.  In Android, the offset is considered to be
    ++     * associated with the trailing run if the BiDi level of the trailing run is higher than of the
    ++     * previous run.  In this case, the BiDi level of the input text is as follows:
    ++     *
    ++     * Input (Logical Order): L1 L2 L3 R1 R2 R3 L4 L5 L6
    ++     *              BiDi Run: [ Run 0 ][ Run 1 ][ Run 2 ]
    ++     *            BiDi Level:  0  0  0  1  1  1  0  0  0
    ++     *
    ++     * Thus, offset = 3 is part of Run 1 and this method returns true for offset = 3, since the BiDi
    ++     * level of Run 1 is higher than the level of Run 0.  Similarly, the offset = 6 is a part of Run
    ++     * 1 and this method returns false for the offset = 6 since the BiDi level of Run 1 is higher
    ++     * than the level of Run 2.
    ++     *
    ++     * @returns true if offset is at the BiDi level transition point and trailing BiDi level is
    ++     *          higher than previous BiDi level. See above for the detail.
    ++     */
    +     private boolean primaryIsTrailingPrevious(int offset) {
    +         int line = getLineForOffset(offset);
    +         int lineStart = getLineStart(line);
    +@@ -873,6 +899,95 @@ public abstract class Layout {
    +         return levelBefore < levelAt;
    +     }
    + 
    ++    /**
    ++     * Computes in linear time the results of calling
    ++     * #getHorizontal for all offsets on a line.
    ++     * @param line The line giving the offsets we compute information for
    ++     * @param clamped Whether to clamp the results to the width of the layout
    ++     * @param primary Whether the results should be the primary or the secondary horizontal
    ++     * @return The array of results, indexed from 0, where 0 corresponds to the line start offset
    ++     */
    ++    private float[] getLineHorizontals(int line, boolean clamped, boolean primary) {
    ++        int start = getLineStart(line);
    ++        int end = getLineEnd(line);
    ++        int dir = getParagraphDirection(line);
    ++        boolean hasTab = getLineContainsTab(line);
    ++        Directions directions = getLineDirections(line);
    ++
    ++        TabStops tabStops = null;
    ++        if (hasTab && mText instanceof Spanned) {
    ++            // Just checking this line should be good enough, tabs should be
    ++            // consistent across all lines in a paragraph.
    ++            TabStopSpan[] tabs = getParagraphSpans((Spanned) mText, start, end, TabStopSpan.class);
    ++            if (tabs.length > 0) {
    ++                tabStops = new TabStops(TAB_INCREMENT, tabs); // XXX should reuse
    ++            }
    ++        }
    ++
    ++        TextLine tl = TextLine.obtain();
    ++        tl.set(mPaint, mText, start, end, dir, directions, hasTab, tabStops);
    ++        boolean[] trailings = primaryIsTrailingPreviousAllLineOffsets(line);
    ++        if (!primary) {
    ++            for (int offset = 0; offset < trailings.length; ++offset) {
    ++                trailings[offset] = !trailings[offset];
    ++            }
    ++        }
    ++        float[] wid = tl.measureAllOffsets(trailings, null);
    ++        TextLine.recycle(tl);
    ++
    ++        if (clamped) {
    ++            for (int offset = 0; offset <= wid.length; ++offset) {
    ++                if (wid[offset] > mWidth) {
    ++                    wid[offset] = mWidth;
    ++                }
    ++            }
    ++        }
    ++        int left = getParagraphLeft(line);
    ++        int right = getParagraphRight(line);
    ++
    ++        int lineStartPos = getLineStartPos(line, left, right);
    ++        float[] horizontal = new float[end - start + 1];
    ++        for (int offset = 0; offset < horizontal.length; ++offset) {
    ++            horizontal[offset] = lineStartPos + wid[offset];
    ++        }
    ++        return horizontal;
    ++    }
    ++
    ++    /**
    ++     * Computes in linear time the results of calling
    ++     * #primaryIsTrailingPrevious for all offsets on a line.
    ++     * @param line The line giving the offsets we compute the information for
    ++     * @return The array of results, indexed from 0, where 0 corresponds to the line start offset
    ++     */
    ++    private boolean[] primaryIsTrailingPreviousAllLineOffsets(int line) {
    ++        int lineStart = getLineStart(line);
    ++        int lineEnd = getLineEnd(line);
    ++        int[] runs = getLineDirections(line).mDirections;
    ++
    ++        boolean[] trailing = new boolean[lineEnd - lineStart + 1];
    ++
    ++        byte[] level = new byte[lineEnd - lineStart + 1];
    ++        for (int i = 0; i < runs.length; i += 2) {
    ++            int start = lineStart + runs[i];
    ++            int limit = start + (runs[i + 1] & RUN_LENGTH_MASK);
    ++            if (limit > lineEnd) {
    ++                limit = lineEnd;
    ++            }
    ++            level[limit - lineStart - 1] =
    ++                    (byte) ((runs[i + 1] >>> RUN_LEVEL_SHIFT) & RUN_LEVEL_MASK);
    ++        }
    ++
    ++        for (int i = 0; i < runs.length; i += 2) {
    ++            int start = lineStart + runs[i];
    ++            byte currentLevel = (byte) ((runs[i + 1] >>> RUN_LEVEL_SHIFT) & RUN_LEVEL_MASK);
    ++            trailing[start - lineStart] = currentLevel > (start == lineStart
    ++                    ? (getParagraphDirection(line) == 1 ? 0 : 1)
    ++                    : level[start - lineStart - 1]);
    ++        }
    ++
    ++        return trailing;
    ++    }
    ++
    +     /**
    +      * Get the primary horizontal position for the specified text offset.
    +      * This is the location where a new character would be inserted in
    +@@ -1176,7 +1291,9 @@ public abstract class Layout {
    +                     !isRtlCharAt(lineEndOffset - 1)) + lineStartOffset;
    +         }
    +         int best = lineStartOffset;
    +-        float bestdist = Math.abs(getHorizontal(best, primary) - horiz);
    ++	final HorizontalMeasurementProvider horizontal =
    ++              new HorizontalMeasurementProvider(line);
    ++	float bestdist = Math.abs(horizontal.get(best) - horiz);
    + 
    +         for (int i = 0; i < dirs.mDirections.length; i += 2) {
    +             int here = lineStartOffset + dirs.mDirections[i];
    +@@ -1192,7 +1309,7 @@ public abstract class Layout {
    +                 guess = (high + low) / 2;
    +                 int adguess = getOffsetAtStartOf(guess);
    + 
    +-                if (getHorizontal(adguess, primary) * swap >= horiz * swap)
    ++                if (horizontal.get(adguess) * swap >= horiz * swap)
    +                     high = guess;
    +                 else
    +                     low = guess;
    +@@ -1205,9 +1322,9 @@ public abstract class Layout {
    +                 int aft = tl.getOffsetToLeftRightOf(low - lineStartOffset, isRtl) + lineStartOffset;
    +                 low = tl.getOffsetToLeftRightOf(aft - lineStartOffset, !isRtl) + lineStartOffset;
    +                 if (low >= here && low < there) {
    +-                    float dist = Math.abs(getHorizontal(low, primary) - horiz);
    ++                    float dist = Math.abs(horizontal.get(low) - horiz);
    +                     if (aft < there) {
    +-                        float other = Math.abs(getHorizontal(aft, primary) - horiz);
    ++                        float other = Math.abs(horizontal.get(aft) - horiz);
    + 
    +                         if (other < dist) {
    +                             dist = other;
    +@@ -1222,7 +1339,7 @@ public abstract class Layout {
    +                 }
    +             }
    + 
    +-            float dist = Math.abs(getHorizontal(here, primary) - horiz);
    ++            float dist = Math.abs(horizontal.get(here) - horiz);
    + 
    +             if (dist < bestdist) {
    +                 bestdist = dist;
    +@@ -1230,7 +1347,7 @@ public abstract class Layout {
    +             }
    +         }
    + 
    +-        float dist = Math.abs(getHorizontal(max, primary) - horiz);
    ++        float dist = Math.abs(horizontal.get(max) - horiz);
    + 
    +         if (dist <= bestdist) {
    +             bestdist = dist;
    +@@ -1241,6 +1358,45 @@ public abstract class Layout {
    +         return best;
    +     }
    + 
    ++    /**
    ++     * Responds to #getHorizontal queries, by selecting the better strategy between:
    ++     * - calling #getHorizontal explicitly for each query
    ++     * - precomputing all #getHorizontal measurements, and responding to any query in constant time
    ++     * The first strategy is used for LTR-only text, while the second is used for all other cases.
    ++     * The class is currently only used in #getOffsetForHorizontal, so reuse with care in other
    ++     * contexts.
    ++     */
    ++    private class HorizontalMeasurementProvider {
    ++        private final int mLine;
    ++
    ++        private float[] mHorizontals;
    ++        private int mLineStartOffset;
    ++
    ++        HorizontalMeasurementProvider(final int line) {
    ++            mLine = line;
    ++            init();
    ++        }
    ++
    ++        private void init() {
    ++            final Directions dirs = getLineDirections(mLine);
    ++            if (dirs == DIRS_ALL_LEFT_TO_RIGHT) {
    ++                return;
    ++            }
    ++
    ++            mHorizontals = getLineHorizontals(mLine, false, true);
    ++            mLineStartOffset = getLineStart(mLine);
    ++        }
    ++
    ++        float get(final int offset) {
    ++            if (mHorizontals == null || offset < mLineStartOffset
    ++                    || offset >= mLineStartOffset + mHorizontals.length) {
    ++                return getPrimaryHorizontal(offset);
    ++            } else {
    ++                return mHorizontals[offset - mLineStartOffset];
    ++            }
    ++        }
    ++    }
    ++
    +     /**
    +      * Return the text offset after the last character on the specified line.
    +      */
    +diff --git a/core/java/android/text/TextLine.java b/core/java/android/text/TextLine.java
    +index 2a52961984f..79333563af1 100644
    +--- a/core/java/android/text/TextLine.java
    ++++ b/core/java/android/text/TextLine.java
    +@@ -338,6 +338,98 @@ class TextLine {
    +         return h;
    +     }
    + 
    ++    /**
    ++     * @see #measure(int, boolean, FontMetricsInt)
    ++     * @return The measure results for all possible offsets
    ++     */
    ++    float[] measureAllOffsets(boolean[] trailing, FontMetricsInt fmi) {
    ++        float[] measurement = new float[mLen + 1];
    ++
    ++        int[] target = new int[mLen + 1];
    ++        for (int offset = 0; offset < target.length; ++offset) {
    ++            target[offset] = trailing[offset] ? offset - 1 : offset;
    ++        }
    ++        if (target[0] < 0) {
    ++            measurement[0] = 0;
    ++        }
    ++
    ++        float h = 0;
    ++
    ++        if (!mHasTabs) {
    ++            if (mDirections == Layout.DIRS_ALL_LEFT_TO_RIGHT) {
    ++                for (int offset = 0; offset <= mLen; ++offset) {
    ++                    measurement[offset] = measureRun(0, offset, mLen, false, fmi);
    ++                }
    ++                return measurement;
    ++            }
    ++            if (mDirections == Layout.DIRS_ALL_RIGHT_TO_LEFT) {
    ++                for (int offset = 0; offset <= mLen; ++offset) {
    ++                    measurement[offset] = measureRun(0, offset, mLen, true, fmi);
    ++                }
    ++                return measurement;
    ++            }
    ++        }
    ++
    ++        char[] chars = mChars;
    ++        int[] runs = mDirections.mDirections;
    ++        for (int i = 0; i < runs.length; i += 2) {
    ++            int runStart = runs[i];
    ++            int runLimit = runStart + (runs[i + 1] & Layout.RUN_LENGTH_MASK);
    ++            if (runLimit > mLen) {
    ++                runLimit = mLen;
    ++            }
    ++            boolean runIsRtl = (runs[i + 1] & Layout.RUN_RTL_FLAG) != 0;
    ++
    ++            int segstart = runStart;
    ++            for (int j = mHasTabs ? runStart : runLimit; j <= runLimit; ++j) {
    ++                int codept = 0;
    ++                if (mHasTabs && j < runLimit) {
    ++                    codept = chars[j];
    ++                    if (codept >= 0xD800 && codept < 0xDC00 && j + 1 < runLimit) {
    ++                        codept = Character.codePointAt(chars, j);
    ++                        if (codept > 0xFFFF) {
    ++                            ++j;
    ++                            continue;
    ++                        }
    ++                    }
    ++                }
    ++
    ++                if (j == runLimit || codept == '\t') {
    ++                    float oldh = h;
    ++                    boolean advance = (mDir == Layout.DIR_RIGHT_TO_LEFT) == runIsRtl;
    ++                    float w = measureRun(segstart, j, j, runIsRtl, fmi);
    ++                    h += advance ? w : -w;
    ++
    ++                    float baseh = advance ? oldh : h;
    ++                    FontMetricsInt crtfmi = advance ? fmi : null;
    ++                    for (int offset = segstart; offset <= j && offset <= mLen; ++offset) {
    ++                        if (target[offset] >= segstart && target[offset] < j) {
    ++                            measurement[offset] =
    ++                                    baseh + measureRun(segstart, offset, j, runIsRtl, crtfmi);
    ++                        }
    ++                    }
    ++
    ++                    if (codept == '\t') {
    ++                        if (target[j] == j) {
    ++                            measurement[j] = h;
    ++                        }
    ++                        h = mDir * nextTab(h * mDir);
    ++                        if (target[j + 1] == j) {
    ++                            measurement[j + 1] =  h;
    ++                        }
    ++                    }
    ++
    ++                    segstart = j + 1;
    ++                }
    ++            }
    ++        }
    ++        if (target[mLen] == mLen) {
    ++            measurement[mLen] = h;
    ++        }
    ++
    ++        return measurement;
    ++    }
    ++
    +     /**
    +      * Draws a unidirectional (but possibly multi-styled) run of text.
    +      *
     diff --git a/core/java/android/view/WindowManager.java b/core/java/android/view/WindowManager.java
     index 395f73844b0..169f7e170dd 100644
     --- a/core/java/android/view/WindowManager.java
    diff --git a/packages_provider_downloadprovider.patch b/packages_provider_downloadprovider.patch
    new file mode 100644
    index 0000000..c64d6f4
    --- /dev/null
    +++ b/packages_provider_downloadprovider.patch
    @@ -0,0 +1,326 @@
    +diff --git a/src/com/android/providers/downloads/DownloadProvider.java b/src/com/android/providers/downloads/DownloadProvider.java
    +index e95eb50..db016bb 100644
    +--- a/src/com/android/providers/downloads/DownloadProvider.java
    ++++ b/src/com/android/providers/downloads/DownloadProvider.java
    +@@ -20,7 +20,9 @@ import static android.provider.BaseColumns._ID;
    + import static android.provider.Downloads.Impl.COLUMN_DESTINATION;
    + import static android.provider.Downloads.Impl.COLUMN_MEDIA_SCANNED;
    + import static android.provider.Downloads.Impl.COLUMN_MIME_TYPE;
    ++import static android.provider.Downloads.Impl.COLUMN_OTHER_UID;
    + import static android.provider.Downloads.Impl.DESTINATION_NON_DOWNLOADMANAGER_DOWNLOAD;
    ++import static android.provider.Downloads.Impl.PERMISSION_ACCESS_ALL;
    + import static android.provider.Downloads.Impl._DATA;
    + 
    + import android.app.AppOpsManager;
    +@@ -42,6 +44,7 @@ import android.database.DatabaseUtils;
    + import android.database.SQLException;
    + import android.database.sqlite.SQLiteDatabase;
    + import android.database.sqlite.SQLiteOpenHelper;
    ++import android.database.sqlite.SQLiteQueryBuilder;
    + import android.net.Uri;
    + import android.os.Binder;
    + import android.os.ParcelFileDescriptor;
    +@@ -96,17 +99,13 @@ public final class DownloadProvider extends ContentProvider {
    +     private static final int MY_DOWNLOADS = 1;
    +     /** URI matcher constant for the URI of an individual download belonging to the calling UID */
    +     private static final int MY_DOWNLOADS_ID = 2;
    ++    private static final int MY_DOWNLOADS_ID_HEADERS = 3;
    +     /** URI matcher constant for the URI of all downloads in the system */
    +-    private static final int ALL_DOWNLOADS = 3;
    ++    private static final int ALL_DOWNLOADS = 4;
    +     /** URI matcher constant for the URI of an individual download */
    +-    private static final int ALL_DOWNLOADS_ID = 4;
    ++    private static final int ALL_DOWNLOADS_ID = 5;
    +     /** URI matcher constant for the URI of a download's request headers */
    +-    private static final int REQUEST_HEADERS_URI = 5;
    +-    /** URI matcher constant for the public URI returned by
    +-     * {@link DownloadManager#getUriForDownloadedFile(long)} if the given downloaded file
    +-     * is publicly accessible.
    +-     */
    +-    private static final int PUBLIC_DOWNLOAD_ID = 6;
    ++    private static final int ALL_DOWNLOADS_ID_HEADERS = 6;
    +     static {
    +         sURIMatcher.addURI("downloads", "my_downloads", MY_DOWNLOADS);
    +         sURIMatcher.addURI("downloads", "my_downloads/#", MY_DOWNLOADS_ID);
    +@@ -114,19 +113,16 @@ public final class DownloadProvider extends ContentProvider {
    +         sURIMatcher.addURI("downloads", "all_downloads/#", ALL_DOWNLOADS_ID);
    +         sURIMatcher.addURI("downloads",
    +                 "my_downloads/#/" + Downloads.Impl.RequestHeaders.URI_SEGMENT,
    +-                REQUEST_HEADERS_URI);
    ++                MY_DOWNLOADS_ID_HEADERS);
    +         sURIMatcher.addURI("downloads",
    +                 "all_downloads/#/" + Downloads.Impl.RequestHeaders.URI_SEGMENT,
    +-                REQUEST_HEADERS_URI);
    ++                MY_DOWNLOADS_ID_HEADERS);
    +         // temporary, for backwards compatibility
    +         sURIMatcher.addURI("downloads", "download", MY_DOWNLOADS);
    +         sURIMatcher.addURI("downloads", "download/#", MY_DOWNLOADS_ID);
    +         sURIMatcher.addURI("downloads",
    +                 "download/#/" + Downloads.Impl.RequestHeaders.URI_SEGMENT,
    +-                REQUEST_HEADERS_URI);
    +-        sURIMatcher.addURI("downloads",
    +-                Downloads.Impl.PUBLICLY_ACCESSIBLE_DOWNLOADS_URI_SEGMENT + "/#",
    +-                PUBLIC_DOWNLOAD_ID);
    ++                MY_DOWNLOADS_ID_HEADERS);
    +     }
    + 
    +     /** Different base URIs that could be used to access an individual download */
    +@@ -188,43 +184,6 @@ public final class DownloadProvider extends ContentProvider {
    +     private int mSystemUid = -1;
    +     private int mDefContainerUid = -1;
    + 
    +-    /**
    +-     * This class encapsulates a SQL where clause and its parameters.  It makes it possible for
    +-     * shared methods (like {@link DownloadProvider#getWhereClause(Uri, String, String[], int)})
    +-     * to return both pieces of information, and provides some utility logic to ease piece-by-piece
    +-     * construction of selections.
    +-     */
    +-    private static class SqlSelection {
    +-        public StringBuilder mWhereClause = new StringBuilder();
    +-        public List<String> mParameters = new ArrayList<String>();
    +-
    +-        public <T> void appendClause(String newClause, final T... parameters) {
    +-            if (newClause == null || newClause.isEmpty()) {
    +-                return;
    +-            }
    +-            if (mWhereClause.length() != 0) {
    +-                mWhereClause.append(" AND ");
    +-            }
    +-            mWhereClause.append("(");
    +-            mWhereClause.append(newClause);
    +-            mWhereClause.append(")");
    +-            if (parameters != null) {
    +-                for (Object parameter : parameters) {
    +-                    mParameters.add(parameter.toString());
    +-                }
    +-            }
    +-        }
    +-
    +-        public String getSelection() {
    +-            return mWhereClause.toString();
    +-        }
    +-
    +-        public String[] getParameters() {
    +-            String[] array = new String[mParameters.size()];
    +-            return mParameters.toArray(array);
    +-        }
    +-    }
    +-
    +     /**
    +      * Creates and updated database on demand when opening it.
    +      * Helper class to create database the first time the provider is
    +@@ -522,8 +481,7 @@ public final class DownloadProvider extends ContentProvider {
    +                 return DOWNLOAD_LIST_TYPE;
    +             }
    +             case MY_DOWNLOADS_ID:
    +-            case ALL_DOWNLOADS_ID:
    +-            case PUBLIC_DOWNLOAD_ID: {
    ++            case ALL_DOWNLOADS_ID: {
    +                 // return the mimetype of this id from the database
    +                 final String id = getDownloadIdFromUri(uri);
    +                 final SQLiteDatabase db = mOpenHelper.getReadableDatabase();
    +@@ -947,16 +905,22 @@ public final class DownloadProvider extends ContentProvider {
    +             throw new IllegalArgumentException("Unknown URI: " + uri);
    +         }
    + 
    +-        if (match == REQUEST_HEADERS_URI) {
    ++        if (match == MY_DOWNLOADS_ID_HEADERS || match == ALL_DOWNLOADS_ID_HEADERS) {
    +             if (projection != null || selection != null || sort != null) {
    +                 throw new UnsupportedOperationException("Request header queries do not support "
    +                                                         + "projections, selections or sorting");
    +             }
    +-            return queryRequestHeaders(db, uri);
    +-        }
    +-
    +-        SqlSelection fullSelection = getWhereClause(uri, selection, selectionArgs, match);
    ++            // Headers are only available to callers with full access.
    ++            getContext().enforceCallingOrSelfPermission(
    ++                    Downloads.Impl.PERMISSION_ACCESS_ALL, Constants.TAG);
    + 
    ++            final SQLiteQueryBuilder qb = getQueryBuilder(uri, match);
    ++            projection = new String[] {
    ++                    Downloads.Impl.RequestHeaders.COLUMN_HEADER,
    ++                    Downloads.Impl.RequestHeaders.COLUMN_VALUE
    ++            };
    ++            return qb.query(db, projection, null, null, null, null, null);
    ++        }
    +         if (shouldRestrictVisibility()) {
    +             if (projection == null) {
    +                 projection = sAppReadableColumnsArray.clone();
    +@@ -983,8 +947,8 @@ public final class DownloadProvider extends ContentProvider {
    +             logVerboseQueryInfo(projection, selection, selectionArgs, sort, db);
    +         }
    + 
    +-        Cursor ret = db.query(DB_TABLE, projection, fullSelection.getSelection(),
    +-                fullSelection.getParameters(), null, null, sort);
    ++        final SQLiteQueryBuilder qb = getQueryBuilder(uri, match);
    ++        final Cursor ret = qb.query(db, projection, selection, selectionArgs, null, null, sort);
    + 
    +         if (ret != null) {
    +             ret.setNotificationUri(getContext().getContentResolver(), uri);
    +@@ -1069,35 +1033,6 @@ public final class DownloadProvider extends ContentProvider {
    +         }
    +     }
    + 
    +-    /**
    +-     * Handle a query for the custom request headers registered for a download.
    +-     */
    +-    private Cursor queryRequestHeaders(SQLiteDatabase db, Uri uri) {
    +-        String where = Downloads.Impl.RequestHeaders.COLUMN_DOWNLOAD_ID + "="
    +-                       + getDownloadIdFromUri(uri);
    +-        String[] projection = new String[] {Downloads.Impl.RequestHeaders.COLUMN_HEADER,
    +-                                            Downloads.Impl.RequestHeaders.COLUMN_VALUE};
    +-        return db.query(Downloads.Impl.RequestHeaders.HEADERS_DB_TABLE, projection, where,
    +-                        null, null, null, null);
    +-    }
    +-
    +-    /**
    +-     * Delete request headers for downloads matching the given query.
    +-     */
    +-    private void deleteRequestHeaders(SQLiteDatabase db, String where, String[] whereArgs) {
    +-        String[] projection = new String[] {Downloads.Impl._ID};
    +-        Cursor cursor = db.query(DB_TABLE, projection, where, whereArgs, null, null, null, null);
    +-        try {
    +-            for (cursor.moveToFirst(); !cursor.isAfterLast(); cursor.moveToNext()) {
    +-                long id = cursor.getLong(0);
    +-                String idWhere = Downloads.Impl.RequestHeaders.COLUMN_DOWNLOAD_ID + "=" + id;
    +-                db.delete(Downloads.Impl.RequestHeaders.HEADERS_DB_TABLE, idWhere, null);
    +-            }
    +-        } finally {
    +-            cursor.close();
    +-        }
    +-    }
    +-
    +     /**
    +      * @return true if we should restrict the columns readable by this caller
    +      */
    +@@ -1179,13 +1114,11 @@ public final class DownloadProvider extends ContentProvider {
    +                     break;
    +                 }
    + 
    +-                final SqlSelection selection = getWhereClause(uri, where, whereArgs, match);
    +-                count = db.update(DB_TABLE, filteredValues, selection.getSelection(),
    +-                        selection.getParameters());
    ++                final SQLiteQueryBuilder qb = getQueryBuilder(uri, match);
    ++                count = qb.update(db, filteredValues, where, whereArgs);
    +                 if (updateSchedule || isCompleting) {
    +                     final long token = Binder.clearCallingIdentity();
    +-                    try (Cursor cursor = db.query(DB_TABLE, null, selection.getSelection(),
    +-                            selection.getParameters(), null, null, null)) {
    ++		    try (Cursor cursor = qb.query(db, null, where, whereArgs, null, null, null)) {
    +                         final DownloadInfo.Reader reader = new DownloadInfo.Reader(resolver,
    +                                 cursor);
    +                         final DownloadInfo info = new DownloadInfo(context);
    +@@ -1231,24 +1164,65 @@ public final class DownloadProvider extends ContentProvider {
    +         }
    +     }
    + 
    +-    private SqlSelection getWhereClause(final Uri uri, final String where, final String[] whereArgs,
    +-            int uriMatch) {
    +-        SqlSelection selection = new SqlSelection();
    +-        selection.appendClause(where, whereArgs);
    +-        if (uriMatch == MY_DOWNLOADS_ID || uriMatch == ALL_DOWNLOADS_ID ||
    +-                uriMatch == PUBLIC_DOWNLOAD_ID) {
    +-            selection.appendClause(Downloads.Impl._ID + " = ?", getDownloadIdFromUri(uri));
    +-        }
    +-        if ((uriMatch == MY_DOWNLOADS || uriMatch == MY_DOWNLOADS_ID)
    +-                && getContext().checkCallingOrSelfPermission(Downloads.Impl.PERMISSION_ACCESS_ALL)
    +-                != PackageManager.PERMISSION_GRANTED) {
    +-            selection.appendClause(
    +-                    Constants.UID + "= ? OR " + Downloads.Impl.COLUMN_OTHER_UID + "= ?",
    +-                    Binder.getCallingUid(), Binder.getCallingUid());
    +-        }
    +-        return selection;
    ++   /**
    ++     * Create a query builder that filters access to the underlying database
    ++     * based on both the requested {@link Uri} and permissions of the caller.
    ++     */
    ++    private SQLiteQueryBuilder getQueryBuilder(final Uri uri, int match) {
    ++        final String table;
    ++        final StringBuilder where = new StringBuilder();
    ++        switch (match) {
    ++            // The "my_downloads" view normally limits the caller to operating
    ++            // on downloads that they either directly own, or have been given
    ++            // indirect ownership of via OTHER_UID.
    ++            case MY_DOWNLOADS_ID:
    ++                appendWhereExpression(where, _ID + "=" + getDownloadIdFromUri(uri));
    ++                // fall-through
    ++            case MY_DOWNLOADS:
    ++                table = DB_TABLE;
    ++                if (getContext().checkCallingOrSelfPermission(
    ++                        PERMISSION_ACCESS_ALL) != PackageManager.PERMISSION_GRANTED) {
    ++                    appendWhereExpression(where, Constants.UID + "=" + Binder.getCallingUid()
    ++                            + " OR " + COLUMN_OTHER_UID + "=" + Binder.getCallingUid());
    ++                }
    ++                break;
    ++
    ++            // The "all_downloads" view is already limited via <path-permission>
    ++            // to only callers holding the ACCESS_ALL_DOWNLOADS permission, but
    ++            // access may also be delegated via Uri permission grants.
    ++            case ALL_DOWNLOADS_ID:
    ++                appendWhereExpression(where, _ID + "=" + getDownloadIdFromUri(uri));
    ++                // fall-through
    ++            case ALL_DOWNLOADS:
    ++                table = DB_TABLE;
    ++                break;
    ++
    ++            // Headers are limited to callers holding the ACCESS_ALL_DOWNLOADS
    ++            // permission, since they're only needed for executing downloads.
    ++            case MY_DOWNLOADS_ID_HEADERS:
    ++            case ALL_DOWNLOADS_ID_HEADERS:
    ++                table = Downloads.Impl.RequestHeaders.HEADERS_DB_TABLE;
    ++                appendWhereExpression(where, Downloads.Impl.RequestHeaders.COLUMN_DOWNLOAD_ID + "="
    ++                        + getDownloadIdFromUri(uri));
    ++                break;
    ++
    ++            default:
    ++                throw new UnsupportedOperationException("Unknown URI: " + uri);
    ++        }
    ++
    ++        final SQLiteQueryBuilder qb = new SQLiteQueryBuilder();
    ++        qb.setStrict(true);
    ++        qb.setTables(table);
    ++        qb.appendWhere(where);
    ++        return qb;
    +     }
    + 
    ++    private static void appendWhereExpression(StringBuilder sb, String expression) {
    ++        if (sb.length() > 0) {
    ++            sb.append(" AND ");
    ++        }
    ++        sb.append('(').append(expression).append(')');
    ++    }
    +     /**
    +      * Deletes a row in the database
    +      */
    +@@ -1270,11 +1244,8 @@ public final class DownloadProvider extends ContentProvider {
    +             case MY_DOWNLOADS_ID:
    +             case ALL_DOWNLOADS:
    +             case ALL_DOWNLOADS_ID:
    +-                final SqlSelection selection = getWhereClause(uri, where, whereArgs, match);
    +-                deleteRequestHeaders(db, selection.getSelection(), selection.getParameters());
    +-
    +-                try (Cursor cursor = db.query(DB_TABLE, null, selection.getSelection(),
    +-                        selection.getParameters(), null, null, null)) {
    ++		 final SQLiteQueryBuilder qb = getQueryBuilder(uri, match);
    ++                 try (Cursor cursor = qb.query(db, null, where, whereArgs, null, null, null)) {
    +                     final DownloadInfo.Reader reader = new DownloadInfo.Reader(resolver, cursor);
    +                     final DownloadInfo info = new DownloadInfo(context);
    +                     while (cursor.moveToNext()) {
    +@@ -1314,10 +1285,15 @@ public final class DownloadProvider extends ContentProvider {
    +                         if (!Downloads.Impl.isStatusCompleted(info.mStatus)) {
    +                             info.sendIntentIfRequested();
    +                         }
    ++			
    ++                        // Delete any headers for this download
    ++                        db.delete(Downloads.Impl.RequestHeaders.HEADERS_DB_TABLE,
    ++                                Downloads.Impl.RequestHeaders.COLUMN_DOWNLOAD_ID + "=?",
    ++                                new String[] { Long.toString(info.mId) });
    +                     }
    +                 }
    + 
    +-                count = db.delete(DB_TABLE, selection.getSelection(), selection.getParameters());
    ++		count = qb.delete(db, where, whereArgs);
    +                 break;
    + 
    +             default:
    diff --git a/system_bt.patch b/system_bt.patch
    index a932778..f38c810 100644
    --- a/system_bt.patch
    +++ b/system_bt.patch
    @@ -1,3 +1,24 @@
    +diff --git a/bta/av/bta_av_act.c b/bta/av/bta_av_act.c
    +index 9cc802f0a..5aef52823 100644
    +--- a/bta/av/bta_av_act.c
    ++++ b/bta/av/bta_av_act.c
    +@@ -800,11 +800,15 @@ tBTA_AV_EVT bta_av_proc_meta_cmd(tAVRC_RESPONSE  *p_rc_rsp, tBTA_AV_RC_MSG *p_ms
    +         case AVRC_PDU_GET_CAPABILITIES:
    +             /* process GetCapabilities command without reporting the event to app */
    +             evt = 0;
    ++            if (p_vendor->vendor_len != 5) {
    ++                p_rc_rsp->get_caps.status = AVRC_STS_INTERNAL_ERR;
    ++                break;
    ++            }
    +             u8 = *(p_vendor->p_vendor_data + 4);
    +             p = p_vendor->p_vendor_data + 2;
    +             p_rc_rsp->get_caps.capability_id = u8;
    +             BE_STREAM_TO_UINT16 (u16, p);
    +-            if ((u16 != 1) || (p_vendor->vendor_len != 5))
    ++            if (u16 != 1) 
    +             {
    +                 p_rc_rsp->get_caps.status = AVRC_STS_INTERNAL_ERR;
    +             }
     diff --git a/bta/dm/bta_dm_act.c b/bta/dm/bta_dm_act.c
     index 1bf741d92..a8d92e0d3 100644
     --- a/bta/dm/bta_dm_act.c
    @@ -331,8 +352,64 @@ index 98ef5f755..52010541d 100644
      
                  p_pkt->offset = L2CAP_MIN_OFFSET;
                  p = (UINT8 *)(p_pkt + 1) + p_pkt->offset;
    +diff --git a/stack/avrc/avrc_api.c b/stack/avrc/avrc_api.c
    +index 77ca7d45e..dc0ce4661 100644
    +--- a/stack/avrc/avrc_api.c
    ++++ b/stack/avrc/avrc_api.c
    +@@ -563,7 +563,20 @@ static void avrc_msg_cback(UINT8 handle, UINT8 label, UINT8 cr,
    + 
    +     p_data  = (UINT8 *)(p_pkt+1) + p_pkt->offset;
    +     memset(&msg, 0, sizeof(tAVRC_MSG) );
    +-    {
    ++
    ++    if (p_pkt->layer_specific == AVCT_DATA_BROWSE) {
    ++        opcode = AVRC_OP_BROWSE;
    ++        msg.browse.hdr.ctype = cr;
    ++        msg.browse.p_browse_data = p_data;
    ++        msg.browse.browse_len = p_pkt->len;
    ++        msg.browse.p_browse_pkt = p_pkt;
    ++    } else {
    ++        if (p_pkt->len < AVRC_AVC_HDR_SIZE) {
    ++            AVRC_TRACE_WARNING("%s: message length %d too short: must be at least %d",
    ++                                 __func__, p_pkt->len, AVRC_AVC_HDR_SIZE);
    ++            osi_free(p_pkt);
    ++            return;
    ++        }
    +         msg.hdr.ctype           = p_data[0] & AVRC_CTYPE_MASK;
    +         AVRC_TRACE_DEBUG("avrc_msg_cback handle:%d, ctype:%d, offset:%d, len: %d",
    +                 handle, msg.hdr.ctype, p_pkt->offset, p_pkt->len);
    +@@ -602,6 +615,14 @@ static void avrc_msg_cback(UINT8 handle, UINT8 label, UINT8 cr,
    +             else
    +             {
    +                 /* parse response */
    ++	        if (p_pkt->len < AVRC_OP_UNIT_INFO_RSP_LEN) {
    ++                    AVRC_TRACE_WARNING(
    ++                         "%s: message length %d too short: must be at least %d",
    ++                         __func__, p_pkt->len, AVRC_OP_UNIT_INFO_RSP_LEN);
    ++                    drop = true;
    ++                    p_drop_msg = "UNIT_INFO_RSP too short";
    ++                    break;
    ++                }
    +                 p_data += 4; /* 3 bytes: ctype, subunit*, opcode + octet 3 (is 7)*/
    +                 msg.unit.unit_type  = (*p_data & AVRC_SUBTYPE_MASK) >> AVRC_SUBTYPE_SHIFT;
    +                 msg.unit.unit       = *p_data & AVRC_SUBID_MASK;
    +@@ -633,6 +654,14 @@ static void avrc_msg_cback(UINT8 handle, UINT8 label, UINT8 cr,
    +             else
    +             {
    +                 /* parse response */
    ++	        if (p_pkt->len < AVRC_OP_SUB_UNIT_INFO_RSP_LEN) {
    ++                    AVRC_TRACE_WARNING(
    ++                        "%s: message length %d too short: must be at least %d",
    ++                        __func__, p_pkt->len, AVRC_OP_SUB_UNIT_INFO_RSP_LEN);
    ++                    drop = true;
    ++                    p_drop_msg = "SUB_UNIT_INFO_RSP too short";
    ++                    break;
    ++                }
    +                 p_data += AVRC_AVC_HDR_SIZE; /* 3 bytes: ctype, subunit*, opcode */
    +                 msg.sub.page    = (*p_data++ >> AVRC_SUB_PAGE_SHIFT) & AVRC_SUB_PAGE_MASK;
    +                 xx      = 0;
     diff --git a/stack/avrc/avrc_pars_ct.c b/stack/avrc/avrc_pars_ct.c
    -index 63cc38407..1818c522f 100644
    +index 63cc38407..699cd0438 100644
     --- a/stack/avrc/avrc_pars_ct.c
     +++ b/stack/avrc/avrc_pars_ct.c
     @@ -22,6 +22,7 @@
    @@ -367,7 +444,19 @@ index 63cc38407..1818c522f 100644
              for(int xx = 0; xx < p_result->list_app_attr.num_attr; xx++)
              {
                  BE_STREAM_TO_UINT8(p_result->list_app_attr.attrs[xx], p);
    -@@ -258,6 +269,12 @@ static tAVRC_STS avrc_ctrl_pars_vendor_rsp(
    +@@ -240,6 +251,11 @@ static tAVRC_STS avrc_ctrl_pars_vendor_rsp(
    +             break;
    +         }
    +         BE_STREAM_TO_UINT8(p_result->list_app_values.num_val, p);
    ++        if (p_result->list_app_values.num_val > AVRC_MAX_APP_ATTR_SIZE) {
    ++            android_errorWriteLog(0x534e4554, "78526423");
    ++            p_result->list_app_values.num_val = AVRC_MAX_APP_ATTR_SIZE;
    ++        }
    ++
    +         AVRC_TRACE_DEBUG("%s value count = %d ", __func__, p_result->list_app_values.num_val);
    +         for(int xx = 0; xx < p_result->list_app_values.num_val; xx++)
    +         {
    +@@ -258,6 +274,12 @@ static tAVRC_STS avrc_ctrl_pars_vendor_rsp(
              tAVRC_APP_SETTING *app_sett =
                  (tAVRC_APP_SETTING*)osi_malloc(p_result->get_cur_app_val.num_val*sizeof(tAVRC_APP_SETTING));
              AVRC_TRACE_DEBUG("%s attr count = %d ", __func__, p_result->get_cur_app_val.num_val);
    @@ -380,7 +469,7 @@ index 63cc38407..1818c522f 100644
              for (int xx = 0; xx < p_result->get_cur_app_val.num_val; xx++)
              {
                  BE_STREAM_TO_UINT8(app_sett[xx].attr_id, p);
    -@@ -269,7 +286,6 @@ static tAVRC_STS avrc_ctrl_pars_vendor_rsp(
    +@@ -269,7 +291,6 @@ static tAVRC_STS avrc_ctrl_pars_vendor_rsp(
      
          case AVRC_PDU_GET_PLAYER_APP_ATTR_TEXT:
          {
    @@ -388,7 +477,7 @@ index 63cc38407..1818c522f 100644
              UINT8                    num_attrs;
      
              if (len == 0)
    -@@ -278,9 +294,12 @@ static tAVRC_STS avrc_ctrl_pars_vendor_rsp(
    +@@ -278,9 +299,12 @@ static tAVRC_STS avrc_ctrl_pars_vendor_rsp(
                  break;
              }
              BE_STREAM_TO_UINT8(num_attrs, p);
    @@ -402,7 +491,7 @@ index 63cc38407..1818c522f 100644
              for (int xx = 0; xx < num_attrs; xx++)
              {
                  BE_STREAM_TO_UINT8(p_result->get_app_attr_txt.p_attrs[xx].attr_id, p);
    -@@ -300,7 +319,6 @@ static tAVRC_STS avrc_ctrl_pars_vendor_rsp(
    +@@ -300,7 +324,6 @@ static tAVRC_STS avrc_ctrl_pars_vendor_rsp(
      
          case AVRC_PDU_GET_PLAYER_APP_VALUE_TEXT:
          {
    @@ -410,7 +499,7 @@ index 63cc38407..1818c522f 100644
              UINT8                    num_vals;
      
              if (len == 0)
    -@@ -309,10 +327,13 @@ static tAVRC_STS avrc_ctrl_pars_vendor_rsp(
    +@@ -309,10 +332,13 @@ static tAVRC_STS avrc_ctrl_pars_vendor_rsp(
                  break;
              }
              BE_STREAM_TO_UINT8(num_vals, p);
    @@ -833,6 +922,24 @@ index 11ef79c83..c2cdb885d 100644
          UNUSED(len);
      
          if (op_code == GATT_REQ_READ_BLOB)
    +diff --git a/stack/include/rfcdefs.h b/stack/include/rfcdefs.h
    +index dcc37bc72..1c751f3f5 100644
    +--- a/stack/include/rfcdefs.h
    ++++ b/stack/include/rfcdefs.h
    +@@ -90,13 +90,6 @@
    +     pf   = (*p_data++ & RFCOMM_PF_MASK) >> RFCOMM_PF_OFFSET;\
    + }
    + 
    +-#define RFCOMM_PARSE_LEN_FIELD(ea, length, p_data)          \
    +-{                                                           \
    +-    ea = (*p_data & RFCOMM_EA);                             \
    +-    length = (*p_data++ >> RFCOMM_SHIFT_LENGTH1);           \
    +-    if (!ea) length += (*p_data++ << RFCOMM_SHIFT_LENGTH2); \
    +-}
    +-
    + #define RFCOMM_FRAME_IS_CMD(initiator, cr)                  \
    +     (( (initiator) && !(cr)) || (!(initiator) &&  (cr)))
    + 
     diff --git a/stack/l2cap/l2c_ble.c b/stack/l2cap/l2c_ble.c
     index 95de4e34c..b2f196c3c 100644
     --- a/stack/l2cap/l2c_ble.c
    @@ -1205,7 +1312,7 @@ index 7e8b3cb6f..cd7edfe1f 100644
          fragment->len = client->remote_mtu;
          memcpy(fragment->data + fragment->offset, bt_packet->data + bt_packet->offset, client->remote_mtu);
     diff --git a/stack/mcap/mca_cact.c b/stack/mcap/mca_cact.c
    -index 583a34215..483169ad6 100644
    +index 583a34215..f1d76be5f 100644
     --- a/stack/mcap/mca_cact.c
     +++ b/stack/mcap/mca_cact.c
     @@ -122,7 +122,7 @@ void mca_ccb_snd_req(tMCA_CCB *p_ccb, tMCA_CCB_EVT *p_data)
    @@ -1226,6 +1333,22 @@ index 583a34215..483169ad6 100644
      
          MCA_TRACE_DEBUG("%s cong=%d req=%d", __func__, p_ccb->cong, p_msg->op_code);
          /* assume that API functions verified the parameters */
    +@@ -269,9 +269,14 @@ void mca_ccb_hdl_req(tMCA_CCB *p_ccb, tMCA_CCB_EVT *p_data)
    +     p_rx_msg = (tMCA_CCB_MSG *)p_pkt;
    +     p = (UINT8 *)(p_pkt + 1) + p_pkt->offset;
    +     evt_data.hdr.op_code = *p++;
    +-    BE_STREAM_TO_UINT16 (evt_data.hdr.mdl_id, p);
    +     reject_opcode = evt_data.hdr.op_code+1;
    + 
    ++    if (p_pkt->len >= 3) {
    ++        BE_STREAM_TO_UINT16(evt_data.hdr.mdl_id, p);
    ++    } else {
    ++        evt_data.hdr.mdl_id = 0;
    ++    }
    ++
    +     MCA_TRACE_DEBUG ("received mdl id: %d ", evt_data.hdr.mdl_id);
    +     if (p_ccb->status == MCA_CCB_STAT_PENDING)
    +     {
     diff --git a/stack/pan/pan_main.c b/stack/pan/pan_main.c
     index 5c3a36739..9c90e5834 100644
     --- a/stack/pan/pan_main.c
    @@ -1298,8 +1421,70 @@ index 5c3a36739..9c90e5834 100644
          return;
      }
      
    +diff --git a/stack/rfcomm/rfc_ts_frames.c b/stack/rfcomm/rfc_ts_frames.c
    +index 739469f64..68a238414 100644
    +--- a/stack/rfcomm/rfc_ts_frames.c
    ++++ b/stack/rfcomm/rfc_ts_frames.c
    +@@ -555,7 +555,15 @@ UINT8 rfc_parse_data (tRFC_MCB *p_mcb, MX_FRAME *p_frame, BT_HDR *p_buf)
    +         return (RFC_EVENT_BAD_FRAME);
    +     }
    +     RFCOMM_PARSE_TYPE_FIELD (p_frame->type, p_frame->pf, p_data);
    +-    RFCOMM_PARSE_LEN_FIELD (eal, len, p_data);
    ++
    ++    eal = *(p_data)&RFCOMM_EA;
    ++    len = *(p_data)++ >> RFCOMM_SHIFT_LENGTH1;
    ++    if (eal == 0 && p_buf->len > RFCOMM_CTRL_FRAME_LEN) {
    ++        len += (*(p_data)++ << RFCOMM_SHIFT_LENGTH2);
    ++    } else if (eal == 0) {
    ++        RFCOMM_TRACE_ERROR("Bad Length when EAL = 0: %d", p_buf->len);
    ++        return RFC_EVENT_BAD_FRAME;
    ++    }
    + 
    +     p_buf->len      -= (3 + !ead + !eal + 1);  /* Additional 1 for FCS */
    +     p_buf->offset   += (3 + !ead + !eal);
    +@@ -670,6 +678,13 @@ void rfc_process_mx_message (tRFC_MCB *p_mcb, BT_HDR *p_buf)
    +     UINT8        ea, cr, mx_len;
    +     BOOLEAN      is_command;
    + 
    ++    if (length < 2) {
    ++        RFCOMM_TRACE_ERROR(
    ++            "%s: Illegal MX Frame len when reading EA, C/R. len:%d < 2", __func__,
    ++            length);
    ++        osi_free(p_buf);
    ++        return;
    ++    }
    +     p_rx_frame->ea   = *p_data & RFCOMM_EA;
    +     p_rx_frame->cr   = (*p_data & RFCOMM_CR_MASK) >> RFCOMM_SHIFT_CR;
    +     p_rx_frame->type = *p_data++ & ~(RFCOMM_CR_MASK | RFCOMM_EA_MASK);
    +@@ -692,6 +707,12 @@ void rfc_process_mx_message (tRFC_MCB *p_mcb, BT_HDR *p_buf)
    + 
    +     if (!ea)
    +     {
    ++       if (length < 1) {
    ++            RFCOMM_TRACE_ERROR("%s: Illegal MX Frame when EA = 0. len:%d < 1",
    ++                         __func__, length);
    ++            osi_free(p_buf);
    ++            return;
    ++        }
    +         mx_len += *p_data++ << RFCOMM_SHIFT_LENGTH2;
    +         length --;
    +     }
    +@@ -768,7 +789,12 @@ void rfc_process_mx_message (tRFC_MCB *p_mcb, BT_HDR *p_buf)
    +         return;
    + 
    +     case RFCOMM_MX_MSC:
    +-
    ++        if (length != RFCOMM_MX_MSC_LEN_WITH_BREAK &&
    ++              length != RFCOMM_MX_MSC_LEN_NO_BREAK) {
    ++            RFCOMM_TRACE_ERROR("%s: Illegal MX MSC Frame len:%d", __func__, length);
    ++            osi_free(p_buf);
    ++            return;
    ++        }
    +         ea                   = *p_data & RFCOMM_EA;
    +         cr                   = (*p_data & RFCOMM_CR_MASK) >> RFCOMM_SHIFT_CR;
    +         p_rx_frame->dlci = *p_data++ >> RFCOMM_SHIFT_DLCI;
     diff --git a/stack/sdp/sdp_discovery.c b/stack/sdp/sdp_discovery.c
    -index ec20689e3..7a5333eda 100644
    +index ec20689e3..08609a733 100644
     --- a/stack/sdp/sdp_discovery.c
     +++ b/stack/sdp/sdp_discovery.c
     @@ -29,6 +29,7 @@
    @@ -1401,7 +1586,29 @@ index ec20689e3..7a5333eda 100644
          }
      }
      
    -@@ -395,7 +406,8 @@ static void sdp_copy_raw_data (tCONN_CB *p_ccb, BOOLEAN offset)
    +@@ -365,11 +376,17 @@ static void sdp_copy_raw_data (tCONN_CB *p_ccb, BOOLEAN offset)
    +         list_len = p_ccb->list_len;
    +         p = &p_ccb->rsp_list[0];
    + 
    +-        if(offset)
    +-        {
    ++        if(offset) {
    ++            cpy_len -= 1;
    +             type = *p++;
    +-            p = sdpu_get_len_from_type (p, type, &list_len);
    +-        }
    ++            uint8_t* old_p = p;
    ++            p = sdpu_get_len_from_type(p, type, &list_len);
    ++            if ((int)cpy_len < (p - old_p)) {
    ++                SDP_TRACE_WARNING("%s: no bytes left for data", __func__);
    ++                return;
    ++            }
    ++            cpy_len -= (p - old_p);
    ++	}
    +         if(list_len && list_len < cpy_len )
    +         {
    +             cpy_len = list_len;
    +@@ -395,7 +412,8 @@ static void sdp_copy_raw_data (tCONN_CB *p_ccb, BOOLEAN offset)
      ** Returns          void
      **
      *******************************************************************************/
    @@ -1411,7 +1618,7 @@ index ec20689e3..7a5333eda 100644
      {
          UINT8           *p_start, *p_param_len;
          UINT16          param_len, list_byte_count;
    -@@ -502,8 +514,12 @@ static void process_service_attr_rsp (tCONN_CB *p_ccb, UINT8 *p_reply)
    +@@ -502,8 +520,12 @@ static void process_service_attr_rsp (tCONN_CB *p_ccb, UINT8 *p_reply)
              /* Was this a continuation request ? */
              if (cont_request_needed)
              {
    @@ -1426,7 +1633,7 @@ index ec20689e3..7a5333eda 100644
              }
              else
                  UINT8_TO_BE_STREAM (p, 0);
    -@@ -541,7 +557,8 @@ static void process_service_attr_rsp (tCONN_CB *p_ccb, UINT8 *p_reply)
    +@@ -541,7 +563,8 @@ static void process_service_attr_rsp (tCONN_CB *p_ccb, UINT8 *p_reply)
      ** Returns          void
      **
      *******************************************************************************/
    @@ -1436,7 +1643,7 @@ index ec20689e3..7a5333eda 100644
      {
          UINT8           *p, *p_start, *p_end, *p_param_len;
          UINT8           type;
    -@@ -641,8 +658,12 @@ static void process_service_search_attr_rsp (tCONN_CB *p_ccb, UINT8 *p_reply)
    +@@ -641,8 +664,12 @@ static void process_service_search_attr_rsp (tCONN_CB *p_ccb, UINT8 *p_reply)
              /* No continuation for first request */
              if (p_reply)
              {
    @@ -1889,7 +2096,7 @@ index fd3dc64fe..49f2d1104 100644
      
      #define ECC_PointMult(q, p, n, keyLength)  ECC_PointMult_Bin_NAF(q, p, n, keyLength)
     diff --git a/stack/smp/smp_act.c b/stack/smp/smp_act.c
    -index e4152a478..9e0246c97 100644
    +index e4152a478..7bef80b27 100644
     --- a/stack/smp/smp_act.c
     +++ b/stack/smp/smp_act.c
     @@ -16,11 +16,13 @@
    @@ -1925,6 +2132,72 @@ index e4152a478..9e0246c97 100644
          p_cb->flags |= SMP_PAIR_FLAG_HAVE_PEER_PUBL_KEY;
      
          smp_wait_for_both_public_keys(p_cb, NULL);
    +@@ -815,7 +829,6 @@ void smp_process_keypress_notification(tSMP_CB *p_cb, tSMP_INT_DATA *p_data)
    +     UINT8 reason = SMP_INVALID_PARAMETERS;
    + 
    +     SMP_TRACE_DEBUG("%s", __func__);
    +-    p_cb->status = *(UINT8 *)p_data;
    + 
    +     if (smp_command_has_invalid_parameters(p_cb))
    +     {
    +@@ -823,6 +836,8 @@ void smp_process_keypress_notification(tSMP_CB *p_cb, tSMP_INT_DATA *p_data)
    +         return;
    +     }
    + 
    ++    p_cb->status = *(UINT8 *)p_data;
    ++
    +     if (p != NULL)
    +     {
    +         STREAM_TO_UINT8(p_cb->peer_keypress_notification, p);
    +@@ -999,6 +1014,12 @@ void smp_proc_enc_info(tSMP_CB *p_cb, tSMP_INT_DATA *p_data)
    +     UINT8   *p = (UINT8 *)p_data;
    + 
    +     SMP_TRACE_DEBUG("%s", __func__);
    ++
    ++    if (smp_command_has_invalid_parameters(p_cb)) {
    ++        smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, NULL);
    ++        return;
    ++    }
    ++
    +     STREAM_TO_ARRAY(p_cb->ltk, p, BT_OCTET16_LEN);
    + 
    +     smp_key_distribution(p_cb, NULL);
    +@@ -1013,6 +1034,13 @@ void smp_proc_master_id(tSMP_CB *p_cb, tSMP_INT_DATA *p_data)
    +     tBTM_LE_PENC_KEYS   le_key;
    + 
    +     SMP_TRACE_DEBUG("%s", __func__);
    ++
    ++    if (p_cb->rcvd_cmd_len < 11) {  // 1(Code) + 2(EDIV) + 8(Rand)
    ++        SMP_TRACE_ERROR("%s: Invalid command length: %d, should be at least 11",
    ++                        __func__, p_cb->rcvd_cmd_len);
    ++        return;
    ++    }
    ++
    +     smp_update_key_mask (p_cb, SMP_SEC_KEY_TYPE_ENC, TRUE);
    + 
    +     STREAM_TO_UINT16(le_key.ediv, p);
    +@@ -1032,7 +1060,7 @@ void smp_proc_master_id(tSMP_CB *p_cb, tSMP_INT_DATA *p_data)
    + }
    + 
    + /*******************************************************************************
    +-** Function     smp_proc_enc_info
    ++** Function     smp_proc_id_info
    + ** Description  process identity information from peer device
    + *******************************************************************************/
    + void smp_proc_id_info(tSMP_CB *p_cb, tSMP_INT_DATA *p_data)
    +@@ -1040,6 +1068,12 @@ void smp_proc_id_info(tSMP_CB *p_cb, tSMP_INT_DATA *p_data)
    +     UINT8   *p = (UINT8 *)p_data;
    + 
    +     SMP_TRACE_DEBUG("%s", __func__);
    ++
    ++    if (smp_command_has_invalid_parameters(p_cb)) {
    ++        smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, NULL);
    ++        return;
    ++    }
    ++
    +     STREAM_TO_ARRAY (p_cb->tk, p, BT_OCTET16_LEN);   /* reuse TK for IRK */
    +     smp_key_distribution_by_transport(p_cb, NULL);
    + }
     diff --git a/stack/smp/smp_main.c b/stack/smp/smp_main.c
     index c3709f8a3..67a2b397a 100644
     --- a/stack/smp/smp_main.c
    diff --git a/system_vold.patch b/system_vold.patch
    new file mode 100644
    index 0000000..1b8de23
    --- /dev/null
    +++ b/system_vold.patch
    @@ -0,0 +1,25 @@
    +diff --git a/Utils.cpp b/Utils.cpp
    +index 014055b..43014bd 100644
    +--- a/Utils.cpp
    ++++ b/Utils.cpp
    +@@ -211,17 +211,17 @@ static status_t readMetadata(const std::string& path, std::string& fsType,
    +     for (auto line : output) {
    +         // Extract values from blkid output, if defined
    +         const char* cline = line.c_str();
    +-        char* start = strstr(cline, "TYPE=");
    ++        char* start = strstr(cline, "TYPE=\"");
    +         if (start != nullptr && sscanf(start + 5, "\"%127[^\"]\"", value) == 1) {
    +             fsType = value;
    +         }
    + 
    +-        start = strstr(cline, "UUID=");
    ++        start = strstr(cline, "UUID=\"");
    +         if (start != nullptr && sscanf(start + 5, "\"%127[^\"]\"", value) == 1) {
    +             fsUuid = value;
    +         }
    + 
    +-        start = strstr(cline, "LABEL=");
    ++        start = strstr(cline, "LABEL=\"");
    +         if (start != nullptr && sscanf(start + 6, "\"%127[^\"]\"", value) == 1) {
    +             fsLabel = value;
    +         }
    
    From 589b98d9e4f822cd276da948f01307f8990b5047 Mon Sep 17 00:00:00 2001
    From: AndDiSa <anddisa@googlemail.com>
    Date: Fri, 7 Dec 2018 13:33:10 +0100
    Subject: [PATCH 104/159] update patches
    
    Change-Id: Ic931f69265ef7eddd4fbbe193783f208f3d35dd5
    ---
     build.patch               |    4 +-
     external_aac.patch        |   81 +++
     external_libhevc.patch    |   34 +-
     external_libnfc-nci.patch |   23 +
     external_libvpx.patch     |   44 ++
     external_sonivox.patch    |  109 ++-
     external_tremolo.patch    |  212 ++++++
     frameworks_av.patch       |   59 +-
     frameworks_base.patch     |  313 ++++++++-
     system_bt.patch           | 1352 ++++++++++++++++++++++++++++++++-----
     system_vold.patch         |   36 +
     11 files changed, 2077 insertions(+), 190 deletions(-)
     create mode 100644 external_libnfc-nci.patch
     create mode 100644 external_libvpx.patch
    
    diff --git a/build.patch b/build.patch
    index cc5de00..8f144fa 100644
    --- a/build.patch
    +++ b/build.patch
    @@ -323,7 +323,7 @@ index 000000000..80664faf2
     +ALL_PREBUILT += $(INSTALLED_KERNEL_TARGET)
     +endif
     diff --git a/core/version_defaults.mk b/core/version_defaults.mk
    -index 7c9634490..a6f4f1aec 100644
    +index 7c9634490..a908f7dff 100644
     --- a/core/version_defaults.mk
     +++ b/core/version_defaults.mk
     @@ -131,7 +131,7 @@ ifeq "" "$(PLATFORM_SECURITY_PATCH)"
    @@ -331,7 +331,7 @@ index 7c9634490..a6f4f1aec 100644
          #  It must match one of the Android Security Patch Level strings of the Public Security Bulletins.
          #  If there is no $PLATFORM_SECURITY_PATCH set, keep it empty.
     -    PLATFORM_SECURITY_PATCH := 2017-08-05
    -+    PLATFORM_SECURITY_PATCH := 2018-10-05
    ++    PLATFORM_SECURITY_PATCH := 2018-12-05
      endif
      
      ifeq "" "$(PLATFORM_BASE_OS)"
    diff --git a/external_aac.patch b/external_aac.patch
    index 5432769..3475fb1 100644
    --- a/external_aac.patch
    +++ b/external_aac.patch
    @@ -1,3 +1,16 @@
    +diff --git a/Android.mk b/Android.mk
    +index 4c28670..9ffa0eb 100644
    +--- a/Android.mk
    ++++ b/Android.mk
    +@@ -55,6 +55,8 @@ LOCAL_C_INCLUDES := \
    + 
    + LOCAL_CPPFLAGS += -std=c++98
    + 
    ++LOCAL_SHARED_LIBRARIES := liblog
    ++
    + LOCAL_MODULE:= libFraunhoferAAC
    + 
    + include $(BUILD_STATIC_LIBRARY)
     diff --git a/libMpegTPDec/src/tpdec_asc.cpp b/libMpegTPDec/src/tpdec_asc.cpp
     index 96a1b35..e80d0e5 100644
     --- a/libMpegTPDec/src/tpdec_asc.cpp
    @@ -52,3 +65,71 @@ index 96a1b35..e80d0e5 100644
        }
        else {
          /* No valid extension data found -> restore the initial bitbuffer state */
    +diff --git a/libSBRdec/src/lpp_tran.cpp b/libSBRdec/src/lpp_tran.cpp
    +index 117e739..e332c25 100644
    +--- a/libSBRdec/src/lpp_tran.cpp
    ++++ b/libSBRdec/src/lpp_tran.cpp
    +@@ -96,6 +96,10 @@ amm-info@iis.fraunhofer.de
    +   \sa lppTransposer(), main_audio.cpp, sbr_scale.h, \ref documentationOverview
    + */
    + 
    ++#ifdef __ANDROID__
    ++#include "log/log.h"
    ++#endif
    ++
    + #include "lpp_tran.h"
    + 
    + #include "sbr_ram.h"
    +@@ -256,7 +260,6 @@ void lppTransposer (HANDLE_SBR_LPP_TRANS hLppTrans,    /*!< Handle of lpp transp
    +   int ovLowBandShift;
    +   int lowBandShift;
    + /*  int ovHighBandShift;*/
    +-  int targetStopBand;
    + 
    + 
    +   alphai[0] = FL2FXCONST_SGL(0.0f);
    +@@ -273,24 +276,32 @@ void lppTransposer (HANDLE_SBR_LPP_TRANS hLppTrans,    /*!< Handle of lpp transp
    + 
    +   autoCorrLength = pSettings->nCols + pSettings->overlap;
    + 
    +-  /* Set upper subbands to zero:
    +-     This is required in case that the patches do not cover the complete highband
    +-     (because the last patch would be too short).
    +-     Possible optimization: Clearing bands up to usb would be sufficient here. */
    +-  targetStopBand = patchParam[pSettings->noOfPatches-1].targetStartBand
    +-                 + patchParam[pSettings->noOfPatches-1].numBandsInPatch;
    ++  if (pSettings->noOfPatches > 0) {
    ++    /* Set upper subbands to zero:
    ++       This is required in case that the patches do not cover the complete highband
    ++       (because the last patch would be too short).
    ++       Possible optimization: Clearing bands up to usb would be sufficient here. */
    ++    int targetStopBand = patchParam[pSettings->noOfPatches-1].targetStartBand
    ++                   + patchParam[pSettings->noOfPatches-1].numBandsInPatch;
    + 
    +-  int memSize = ((64) - targetStopBand) * sizeof(FIXP_DBL);
    ++    int memSize = ((64) - targetStopBand) * sizeof(FIXP_DBL);
    + 
    +-  if (!useLP) {
    ++    if (!useLP) {
    ++      for (i = startSample; i < stopSampleClear; i++) {
    ++        FDKmemclear(&qmfBufferReal[i][targetStopBand], memSize);
    ++        FDKmemclear(&qmfBufferImag[i][targetStopBand], memSize);
    ++      }
    ++    } else
    +     for (i = startSample; i < stopSampleClear; i++) {
    +       FDKmemclear(&qmfBufferReal[i][targetStopBand], memSize);
    +-      FDKmemclear(&qmfBufferImag[i][targetStopBand], memSize);
    +     }
    +-  } else
    +-  for (i = startSample; i < stopSampleClear; i++) {
    +-    FDKmemclear(&qmfBufferReal[i][targetStopBand], memSize);
    +   }
    ++#ifdef __ANDROID__
    ++  else {
    ++    // Safetynet logging
    ++    android_errorWriteLog(0x534e4554, "112160868");
    ++  }
    ++#endif
    + 
    +   /* init bwIndex for each patch */
    +   FDKmemclear(bwIndex, pSettings->noOfPatches*sizeof(INT));
    diff --git a/external_libhevc.patch b/external_libhevc.patch
    index a84d765..91fa150 100644
    --- a/external_libhevc.patch
    +++ b/external_libhevc.patch
    @@ -4182,7 +4182,7 @@ index d656519..d2ea7a5 100644
      
          if(1 == ps_codec->i4_pic_present)
     diff --git a/decoder/ihevcd_parse_headers.c b/decoder/ihevcd_parse_headers.c
    -index c0f1564..90b341a 100644
    +index c0f1564..5fe955a 100644
     --- a/decoder/ihevcd_parse_headers.c
     +++ b/decoder/ihevcd_parse_headers.c
     @@ -1272,12 +1272,6 @@ IHEVCD_ERROR_T ihevcd_parse_sps(codec_t *ps_codec)
    @@ -4267,21 +4267,37 @@ index c0f1564..90b341a 100644
              ps_sps->i1_num_long_term_ref_pics_sps = value;
      
              for(i = 0; i < ps_sps->i1_num_long_term_ref_pics_sps; i++)
    -@@ -1797,6 +1815,19 @@ IHEVCD_ERROR_T ihevcd_parse_pps(codec_t *ps_codec)
    +@@ -1797,6 +1815,35 @@ IHEVCD_ERROR_T ihevcd_parse_pps(codec_t *ps_codec)
          BITS_PARSE("tiles_enabled_flag", value, ps_bitstrm, 1);
          ps_pps->i1_tiles_enabled_flag = value;
      
     +    /* When tiles are enabled and width or height is >= 4096,
    -+     * CTB Size should at least be 32. 16x16 CTBs can result
    -+     * in tile position greater than 255 for 4096,
    ++     * CTB Size should at least be 32 while if width or height is >= 8192,
    ++     * CTB Size should at least be 64 and so on. 16x16 CTBs can result
    ++     * in tile position greater than 255 for 4096 while 32x32 CTBs can result
    ++     * in tile position greater than 255 for 8192,
     +     * which decoder does not support.
     +     */
    -+    if((ps_pps->i1_tiles_enabled_flag) &&
    -+                    (ps_sps->i1_log2_ctb_size == 4) &&
    -+                    ((ps_sps->i2_pic_width_in_luma_samples >= 4096) ||
    -+                    (ps_sps->i2_pic_height_in_luma_samples >= 4096)))
    ++    if (ps_pps->i1_tiles_enabled_flag)
     +    {
    -+        return IHEVCD_INVALID_HEADER;
    ++        if((ps_sps->i1_log2_ctb_size == 4) &&
    ++            ((ps_sps->i2_pic_width_in_luma_samples >= 4096) ||
    ++            (ps_sps->i2_pic_height_in_luma_samples >= 4096)))
    ++        {
    ++            return IHEVCD_INVALID_HEADER;
    ++        }
    ++        if((ps_sps->i1_log2_ctb_size == 5) &&
    ++            ((ps_sps->i2_pic_width_in_luma_samples >= 8192) ||
    ++            (ps_sps->i2_pic_height_in_luma_samples >= 8192)))
    ++        {
    ++            return IHEVCD_INVALID_HEADER;
    ++        }
    ++        if((ps_sps->i1_log2_ctb_size == 6) &&
    ++            ((ps_sps->i2_pic_width_in_luma_samples >= 16384) ||
    ++            (ps_sps->i2_pic_height_in_luma_samples >= 16384)))
    ++        {
    ++            return IHEVCD_INVALID_HEADER;
    ++        }
     +    }
     +
          BITS_PARSE("entropy_coding_sync_enabled_flag", value, ps_bitstrm, 1);
    diff --git a/external_libnfc-nci.patch b/external_libnfc-nci.patch
    new file mode 100644
    index 0000000..888dacc
    --- /dev/null
    +++ b/external_libnfc-nci.patch
    @@ -0,0 +1,23 @@
    +diff --git a/src/nfc/tags/rw_t2t_ndef.c b/src/nfc/tags/rw_t2t_ndef.c
    +index 3304a90..42a558e 100644
    +--- a/src/nfc/tags/rw_t2t_ndef.c
    ++++ b/src/nfc/tags/rw_t2t_ndef.c
    +@@ -23,6 +23,7 @@
    +  *  Reader/Writer mode.
    +  *
    +  ******************************************************************************/
    ++#include <log/log.h>
    + #include <string.h>
    + #include "nfc_target.h"
    + 
    +@@ -664,6 +665,10 @@ static void rw_t2t_handle_tlv_detect_rsp (UINT8 *p_data)
    + 
    +                         /* Extract lockbytes info addressed by this Lock TLV */
    +                         xx = 0;
    ++			if (count > RW_T2T_MAX_LOCK_BYTES) {
    ++                            count = RW_T2T_MAX_LOCK_BYTES;
    ++                            android_errorWriteLog(0x534e4554, "112161557");
    ++                        }
    +                         while (xx < count)
    +                         {
    +                             p_t2t->lockbyte[p_t2t->num_lockbytes].tlv_index     = p_t2t->num_lock_tlvs;
    diff --git a/external_libvpx.patch b/external_libvpx.patch
    new file mode 100644
    index 0000000..4753aa8
    --- /dev/null
    +++ b/external_libvpx.patch
    @@ -0,0 +1,44 @@
    +diff --git a/libwebm/mkvparser/mkvparser.cc b/libwebm/mkvparser/mkvparser.cc
    +index ff13327..70c1f04 100644
    +--- a/libwebm/mkvparser/mkvparser.cc
    ++++ b/libwebm/mkvparser/mkvparser.cc
    +@@ -4983,29 +4983,27 @@ bool PrimaryChromaticity::Parse(IMkvReader* reader, long long read_pos,
    +   if (!reader)
    +     return false;
    + 
    +-  std::auto_ptr<PrimaryChromaticity> chromaticity_ptr;
    ++  if (!*chromaticity)
    ++    *chromaticity = new PrimaryChromaticity();
    + 
    +-  if (!*chromaticity) {
    +-    chromaticity_ptr.reset(new PrimaryChromaticity());
    +-  } else {
    +-    chromaticity_ptr.reset(*chromaticity);
    +-  }
    +-
    +-  if (!chromaticity_ptr.get())
    ++  if (!*chromaticity)
    +     return false;
    + 
    +-  float* value = is_x ? &chromaticity_ptr->x : &chromaticity_ptr->y;
    ++  PrimaryChromaticity* pc = *chromaticity;
    ++  float* value = is_x ? &pc->x : &pc->y;
    + 
    +   double parser_value = 0;
    +-  const long long value_parse_status =
    ++  const long long parse_status =
    +       UnserializeFloat(reader, read_pos, value_size, parser_value);
    + 
    ++  if (parse_status < 0 || parser_value < FLT_MIN || parser_value > FLT_MAX)
    ++    return false;
    ++
    +   *value = static_cast<float>(parser_value);
    + 
    +-  if (value_parse_status < 0 || *value < 0.0 || *value > 1.0)
    ++  if (*value < 0.0 || *value > 1.0)
    +     return false;
    + 
    +-  *chromaticity = chromaticity_ptr.release();
    +   return true;
    + }
    + 
    diff --git a/external_sonivox.patch b/external_sonivox.patch
    index 2da5e2b..a3671c8 100644
    --- a/external_sonivox.patch
    +++ b/external_sonivox.patch
    @@ -42,20 +42,117 @@ index 8097ba4..3ec24a0 100644
                  return EAS_ERROR_MALLOC_FAILED;
              }
              EAS_HWMemSet(dls.pDLS, 0, size);
    +diff --git a/arm-wt-22k/lib_src/eas_ota.c b/arm-wt-22k/lib_src/eas_ota.c
    +index 5bc9062..413d1d3 100644
    +--- a/arm-wt-22k/lib_src/eas_ota.c
    ++++ b/arm-wt-22k/lib_src/eas_ota.c
    +@@ -27,6 +27,9 @@
    +  *----------------------------------------------------------------------------
    + */
    + 
    ++#define LOG_TAG "Sonivox"
    ++#include <log/log.h>
    ++
    + #include "eas_data.h"
    + #include "eas_miditypes.h"
    + #include "eas_parser.h"
    +@@ -211,6 +214,7 @@ static EAS_RESULT OTA_CheckFileType (S_EAS_DATA *pEASData, EAS_FILE_HANDLE fileH
    +                 pData->fileOffset = offset;
    +                 pData->state = EAS_STATE_OPEN;
    +                 *ppHandle = pData;
    ++                ALOGD("%s() OTA file recognized", __func__);
    +                 break;
    +             }
    + 
    +@@ -360,6 +364,7 @@ static EAS_RESULT OTA_Event (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData, EAS_I
    +         /* check for loop - don't do infinite loops when locating */
    +         if (pData->loopCount && ((parserMode == eParserModePlay) || (pData->loopCount != OTA_INFINITE_LOOP)))
    +         {
    ++            ALOGV("%s() loop backwards, loopCount = %d", __func__, pData->loopCount);
    +             /* if not infinite loop, decrement loop count */
    +             if (pData->loopCount != OTA_INFINITE_LOOP)
    +                 pData->loopCount--;
    +diff --git a/arm-wt-22k/lib_src/eas_public.c b/arm-wt-22k/lib_src/eas_public.c
    +index 51ac423..952ad08 100644
    +--- a/arm-wt-22k/lib_src/eas_public.c
    ++++ b/arm-wt-22k/lib_src/eas_public.c
    +@@ -27,6 +27,9 @@
    +  *----------------------------------------------------------------------------
    + */
    + 
    ++#define LOG_TAG "Sonivox"
    ++#include "log/log.h"
    ++
    + #include "eas_synthcfg.h"
    + #include "eas.h"
    + #include "eas_config.h"
    +@@ -1245,6 +1248,13 @@ static EAS_RESULT EAS_ParseEvents (S_EAS_DATA *pEASData, EAS_HANDLE pStream, EAS
    +     EAS_BOOL done;
    +     EAS_INT yieldCount = YIELD_EVENT_COUNT;
    +     EAS_U32 time = 0;
    ++    // This constant is the maximum number of events that can be processed in a single time slice.
    ++    // A typical ringtone will contain a few events per time slice.
    ++    // Extremely dense ringtones might go up to 50 events.
    ++    // If we see this many events then the file is probably stuck in an infinite loop
    ++    // and should be aborted.
    ++    static const EAS_INT MAX_EVENT_COUNT = 100000;
    ++    EAS_INT eventCount = 0;
    + 
    +     /* does this parser have a time function? */
    +     pParserModule = pStream->pParserModule;
    +@@ -1292,9 +1302,25 @@ static EAS_RESULT EAS_ParseEvents (S_EAS_DATA *pEASData, EAS_HANDLE pStream, EAS
    +             {
    + 
    +                 /* parse the next event */
    +-                if (pParserModule->pfEvent)
    +-                    if ((result = (*pParserModule->pfEvent)(pEASData, pStream->handle, parseMode)) != EAS_SUCCESS)
    ++                if (pParserModule->pfEvent) {
    ++                    if ((result = (*pParserModule->pfEvent)(pEASData, pStream->handle, parseMode))
    ++                            != EAS_SUCCESS) {
    ++                        ALOGE("%s() pfEvent returned %ld", __func__, result);
    +                         return result;
    ++                    }
    ++                }
    ++
    ++                // An infinite loop within a ringtone file can cause this function
    ++                // to loop forever.  Try to detect that and return an error.
    ++                // Only check when playing. Otherwise a very large file could be rejected
    ++                // when scanning the entire file in a single call to this function.
    ++                // OTA files will only do infinite loops when in eParserModePlay.
    ++                if (++eventCount >= MAX_EVENT_COUNT && parseMode == eParserModePlay) {
    ++                    ALOGE("%s() aborting, %d events. Infinite loop in song file?!",
    ++                            __func__, eventCount);
    ++                    android_errorWriteLog(0x534e4554, "68664359");
    ++                    return EAS_ERROR_FILE_POS;
    ++                }
    +             }
    + 
    +             /* no more events in this frame, advance time */
     diff --git a/arm-wt-22k/lib_src/eas_smf.c b/arm-wt-22k/lib_src/eas_smf.c
    -index 8b54b8e..3c284eb 100644
    +index 8b54b8e..72e89c3 100644
     --- a/arm-wt-22k/lib_src/eas_smf.c
     +++ b/arm-wt-22k/lib_src/eas_smf.c
    -@@ -29,6 +29,8 @@
    +@@ -29,6 +29,9 @@
       *----------------------------------------------------------------------------
      */
      
    ++#define LOG_TAG "Sonivox"
     +#include "log/log.h"
     +
      #include "eas_data.h"
      #include "eas_miditypes.h"
      #include "eas_parser.h"
    -@@ -833,6 +835,20 @@ static EAS_RESULT SMF_ParseMetaEvent (S_EAS_DATA *pEASData, S_SMF_DATA *pSMFData
    +@@ -126,7 +129,8 @@ EAS_RESULT SMF_CheckFileType (S_EAS_DATA *pEASData, EAS_FILE_HANDLE fileHandle,
    +         if ((result = EAS_HWReadFile(pEASData->hwInstData, fileHandle, header, sizeof(header), &count)) != EAS_SUCCESS)
    +             return result;
    + 
    +-        /* check for 'MTrk' - return if no match */
    ++        /* check for 'MThd' - If no match then return SUCCESS with NULL handle
    ++         * to indicate not an SMF file. */
    +         if ((header[0] != 'M') || (header[1] != 'T') || (header[2] != 'h') || (header[3] != 'd'))
    +             return EAS_SUCCESS;
    +     }
    +@@ -833,6 +837,22 @@ static EAS_RESULT SMF_ParseMetaEvent (S_EAS_DATA *pEASData, S_SMF_DATA *pSMFData
          /* get the current file position so we can skip the event */
          if ((result = EAS_HWFilePos(pEASData->hwInstData, pSMFStream->fileHandle, &pos)) != EAS_SUCCESS)
              return result;
    @@ -63,13 +160,15 @@ index 8b54b8e..3c284eb 100644
     +    /* prevent a large unsigned length from being treated as a negative length */
     +    if ((EAS_I32) len < 0) {
     +        /* note that EAS_I32 is a long, which can be 64-bits on some computers */
    -+        ALOGE("b/68953854 SMF_ParseMetaEvent, negative len = %ld\n", (EAS_I32) len);
    ++        ALOGE("%s() negative len = %ld", __func__, (long) len);
    ++        android_errorWriteLog(0x534e4554, "68953854");
     +        return EAS_ERROR_FILE_FORMAT;
     +    }
     +    /* prevent numeric overflow caused by a very large len, assume pos > 0 */
     +    const EAS_I32 EAS_I32_MAX = 0x7FFFFFFF;
     +    if ((EAS_I32) len > (EAS_I32_MAX - pos)) {
    -+        ALOGE("b/68953854 SMF_ParseMetaEvent, too large len = %ld\n", (EAS_I32) len);
    ++        ALOGE("%s() too large len = %ld", __func__, (long) len);
    ++        android_errorWriteLog(0x534e4554, "68953854");
     +        return EAS_ERROR_FILE_FORMAT;
     +    }
     +
    diff --git a/external_tremolo.patch b/external_tremolo.patch
    index e6ee1e9..8fd4003 100644
    --- a/external_tremolo.patch
    +++ b/external_tremolo.patch
    @@ -706,6 +706,218 @@ index 7e4f1ed..344e41b 100644
      	LDR	r2, [r10],#4		@ r2 = a[chptr++]
      	LDR	r12,[r1], #4		@ r1 = v[j++]
      	CMP	r10,r8			@ if (chptr == ch)
    +diff --git a/Tremolo/floor0.c b/Tremolo/floor0.c
    +index 581efcb..b6ece29 100644
    +--- a/Tremolo/floor0.c
    ++++ b/Tremolo/floor0.c
    +@@ -38,6 +38,7 @@
    + #include <stdlib.h>
    + #include <string.h>
    + #include <math.h>
    ++#include <log/log.h>
    + #include "ogg.h"
    + #include "ivorbiscodec.h"
    + #include "codec_internal.h"
    +@@ -89,7 +90,7 @@ static inline ogg_int32_t vorbis_coslook_i(long a){
    +   int i=a>>COS_LOOKUP_I_SHIFT;
    +   int d=a&COS_LOOKUP_I_MASK;
    +   return COS_LOOKUP_I[i]- ((d*(COS_LOOKUP_I[i]-COS_LOOKUP_I[i+1]))>>
    +-			   COS_LOOKUP_I_SHIFT);
    ++                           COS_LOOKUP_I_SHIFT);
    + }
    + 
    + /* interpolated half-wave lookup based cos function */
    +@@ -98,7 +99,7 @@ static inline ogg_int32_t vorbis_coslook2_i(long a){
    +   int i=a>>COS_LOOKUP_I_SHIFT;
    +   int d=a&COS_LOOKUP_I_MASK;
    +   return ((COS_LOOKUP_I[i]<<COS_LOOKUP_I_SHIFT)-
    +-	  d*(COS_LOOKUP_I[i]-COS_LOOKUP_I[i+1]))>>
    ++          d*(COS_LOOKUP_I[i]-COS_LOOKUP_I[i+1]))>>
    +     (COS_LOOKUP_I_SHIFT-LSP_FRACBITS+14);
    + }
    + 
    +@@ -122,7 +123,7 @@ static inline ogg_int32_t toBARK(int n){
    +     return 54<<14;
    +   }else{
    +     return (i<<14)+(((n-barklook[i])*
    +-		     ((1UL<<31)/(barklook[i+1]-barklook[i])))>>17);
    ++                     ((1UL<<31)/(barklook[i+1]-barklook[i])))>>17);
    +   }
    + }
    + 
    +@@ -143,10 +144,10 @@ static const unsigned char MLOOP_2[64]={
    + static const unsigned char MLOOP_3[8]={0,1,2,2,3,3,3,3};
    + 
    + void vorbis_lsp_to_curve(ogg_int32_t *curve,int n,int ln,
    +-			 ogg_int32_t *lsp,int m,
    +-			 ogg_int32_t amp,
    +-			 ogg_int32_t ampoffset,
    +-			 ogg_int32_t nyq){
    ++                         ogg_int32_t *lsp,int m,
    ++                         ogg_int32_t amp,
    ++                         ogg_int32_t ampoffset,
    ++                         ogg_int32_t nyq){
    + 
    +   /* 0 <= m < 256 */
    + 
    +@@ -174,7 +175,7 @@ void vorbis_lsp_to_curve(ogg_int32_t *curve,int n,int ln,
    +   ogg_uint32_t nextbark=MULT31(imap>>1,tBnyq1);
    + #endif
    +   int nextf=barklook[nextbark>>14]+(((nextbark&0x3fff)*
    +-	    (barklook[(nextbark>>14)+1]-barklook[nextbark>>14]))>>14);
    ++            (barklook[(nextbark>>14)+1]-barklook[nextbark>>14]))>>14);
    + 
    +   /* lsp is in 8.24, range 0 to PI; coslook wants it in .16 0 to 1*/
    +   for(i=0;i<m;i++){
    +@@ -235,8 +236,8 @@ void vorbis_lsp_to_curve(ogg_int32_t *curve,int n,int ln,
    + 
    +     for(j=3;j<m;j+=2){
    +       if(!(shift=MLOOP_1[(pi|qi)>>25]))
    +-      	if(!(shift=MLOOP_2[(pi|qi)>>19]))
    +-      	  shift=MLOOP_3[(pi|qi)>>16];
    ++        if(!(shift=MLOOP_2[(pi|qi)>>19]))
    ++          shift=MLOOP_3[(pi|qi)>>16];
    + 
    +       qi=(qi>>shift)*labs(ilsp[j-1]-wi);
    +       pi=(pi>>shift)*labs(ilsp[j]-wi);
    +@@ -244,7 +245,7 @@ void vorbis_lsp_to_curve(ogg_int32_t *curve,int n,int ln,
    +     }
    +     if(!(shift=MLOOP_1[(pi|qi)>>25]))
    +       if(!(shift=MLOOP_2[(pi|qi)>>19]))
    +-	shift=MLOOP_3[(pi|qi)>>16];
    ++        shift=MLOOP_3[(pi|qi)>>16];
    + 
    +     /* pi,qi normalized collectively, both tracked using qexp */
    + 
    +@@ -256,8 +257,8 @@ void vorbis_lsp_to_curve(ogg_int32_t *curve,int n,int ln,
    +       qexp+=shift;
    + 
    +       if(!(shift=MLOOP_1[(pi|qi)>>25]))
    +-	if(!(shift=MLOOP_2[(pi|qi)>>19]))
    +-	  shift=MLOOP_3[(pi|qi)>>16];
    ++        if(!(shift=MLOOP_2[(pi|qi)>>19]))
    ++          shift=MLOOP_3[(pi|qi)>>16];
    + 
    +       pi>>=shift;
    +       qi>>=shift;
    +@@ -274,7 +275,7 @@ void vorbis_lsp_to_curve(ogg_int32_t *curve,int n,int ln,
    +       /* even order filter; still symmetric */
    + 
    +       /* p*=p(1-w), q*=q(1+w), let normalization drift because it isn't
    +-	 worth tracking step by step */
    ++         worth tracking step by step */
    + 
    +       pi>>=shift;
    +       qi>>=shift;
    +@@ -299,15 +300,15 @@ void vorbis_lsp_to_curve(ogg_int32_t *curve,int n,int ln,
    +       qi>>=1; qexp++;
    +     }else
    +       while(qi && !(qi&0x8000)){ /* checks for 0.0xxxxxxxxxxxxxxx or less*/
    +-	qi<<=1; qexp--;
    ++        qi<<=1; qexp--;
    +       }
    + 
    + #endif
    + 
    +     amp=vorbis_fromdBlook_i(ampi*                     /*  n.4         */
    +-			    vorbis_invsqlook_i(qi,qexp)-
    +-			                              /*  m.8, m+n<=8 */
    +-			    ampoffseti);              /*  8.12[0]     */
    ++                            vorbis_invsqlook_i(qi,qexp)-
    ++                                                      /*  m.8, m+n<=8 */
    ++                            ampoffseti);              /*  8.12[0]     */
    + 
    + #ifdef _LOW_ACCURACY_
    +     amp>>=9;
    +@@ -319,8 +320,8 @@ void vorbis_lsp_to_curve(ogg_int32_t *curve,int n,int ln,
    +       /* line plot to get new f */
    +       ferr+=fdy;
    +       if(ferr>=fdx){
    +-	ferr-=fdx;
    +-	f++;
    ++        ferr-=fdx;
    ++        f++;
    +       }
    +       f+=fbase;
    + 
    +@@ -335,18 +336,18 @@ void vorbis_lsp_to_curve(ogg_int32_t *curve,int n,int ln,
    +       if(map+1<ln){
    + 
    + #ifdef _LOW_ACCURACY_
    +-	nextbark=((tBnyq1<<11)/ln*(map+1))>>12;
    ++        nextbark=((tBnyq1<<11)/ln*(map+1))>>12;
    + #else
    +-	nextbark=MULT31((map+1)*(imap>>1),tBnyq1);
    ++        nextbark=MULT31((map+1)*(imap>>1),tBnyq1);
    + #endif
    +-	nextf=barklook[nextbark>>14]+
    +-	  (((nextbark&0x3fff)*
    +-	    (barklook[(nextbark>>14)+1]-barklook[nextbark>>14]))>>14);
    +-	if(f<=nextf)break;
    ++        nextf=barklook[nextbark>>14]+
    ++          (((nextbark&0x3fff)*
    ++            (barklook[(nextbark>>14)+1]-barklook[nextbark>>14]))>>14);
    ++        if(f<=nextf)break;
    + 
    +       }else{
    +-	nextf=9999999;
    +-	break;
    ++        nextf=9999999;
    ++        break;
    +       }
    +     }
    +     if(map>=ln){
    +@@ -398,7 +399,7 @@ int floor0_memosize(vorbis_info_floor *i){
    + }
    + 
    + ogg_int32_t *floor0_inverse1(vorbis_dsp_state *vd,vorbis_info_floor *i,
    +-			     ogg_int32_t *lsp){
    ++                             ogg_int32_t *lsp){
    +   vorbis_info_floor0 *info=(vorbis_info_floor0 *)i;
    +   int j,k;
    + 
    +@@ -411,13 +412,18 @@ ogg_int32_t *floor0_inverse1(vorbis_dsp_state *vd,vorbis_info_floor *i,
    +     if(booknum!=-1 && booknum<info->numbooks){ /* be paranoid */
    +       codec_setup_info  *ci=(codec_setup_info *)vd->vi->codec_setup;
    +       codebook *b=ci->book_param+info->books[booknum];
    ++      int sz = floor0_memosize(i);
    ++      if (sz < b->dim) {
    ++          ALOGE("lsp too small: %d < %ld", sz, b->dim);
    ++          return NULL;
    ++      }
    +       ogg_int32_t last=0;
    + 
    +       for(j=0;j<info->order;j+=b->dim)
    +-	if(vorbis_book_decodev_set(b,lsp+j,&vd->opb,b->dim,-24)==-1)goto eop;
    ++        if(vorbis_book_decodev_set(b,lsp+j,&vd->opb,b->dim,-24)==-1)goto eop;
    +       for(j=0;j<info->order;){
    +-	for(k=0;k<b->dim;k++,j++)lsp[j]+=last;
    +-	last=lsp[j-1];
    ++        for(k=0;k<b->dim;k++,j++)lsp[j]+=last;
    ++        last=lsp[j-1];
    +       }
    + 
    +       lsp[info->order]=amp;
    +@@ -429,7 +435,7 @@ ogg_int32_t *floor0_inverse1(vorbis_dsp_state *vd,vorbis_info_floor *i,
    + }
    + 
    + int floor0_inverse2(vorbis_dsp_state *vd,vorbis_info_floor *i,
    +-			   ogg_int32_t *lsp,ogg_int32_t *out){
    ++                           ogg_int32_t *lsp,ogg_int32_t *out){
    +   vorbis_info_floor0 *info=(vorbis_info_floor0 *)i;
    +   codec_setup_info  *ci=(codec_setup_info *)vd->vi->codec_setup;
    + 
    +@@ -438,8 +444,8 @@ int floor0_inverse2(vorbis_dsp_state *vd,vorbis_info_floor *i,
    + 
    +     /* take the coefficients back to a spectral envelope curve */
    +     vorbis_lsp_to_curve(out,ci->blocksizes[vd->W]/2,info->barkmap,
    +-			lsp,info->order,amp,info->ampdB,
    +-			info->rate>>1);
    ++                        lsp,info->order,amp,info->ampdB,
    ++                        info->rate>>1);
    +     return(1);
    +   }
    +   memset(out,0,sizeof(*out)*ci->blocksizes[vd->W]/2);
     diff --git a/Tremolo/res012.c b/Tremolo/res012.c
     index 513d9ad..ac09671 100644
     --- a/Tremolo/res012.c
    diff --git a/frameworks_av.patch b/frameworks_av.patch
    index 47ebe2d..a0b96e8 100644
    --- a/frameworks_av.patch
    +++ b/frameworks_av.patch
    @@ -728,10 +728,18 @@ index 51a113031..393286dcf 100644
      
      void BnDrm::writeVector(Parcel *reply, Vector<uint8_t> const &vector) const {
     diff --git a/media/libmedia/IMediaExtractor.cpp b/media/libmedia/IMediaExtractor.cpp
    -index 72d1d7c57..4be111813 100644
    +index 72d1d7c57..744af1be0 100644
     --- a/media/libmedia/IMediaExtractor.cpp
     +++ b/media/libmedia/IMediaExtractor.cpp
    -@@ -209,11 +209,16 @@ String8 ExtractorInstance::toString() const {
    +@@ -23,6 +23,7 @@
    + 
    + #include <binder/IPCThreadState.h>
    + #include <binder/Parcel.h>
    ++#include <binder/PermissionCache.h>
    + #include <media/IMediaExtractor.h>
    + #include <media/stagefright/MetaData.h>
    + 
    +@@ -209,11 +210,16 @@ String8 ExtractorInstance::toString() const {
          for (size_t i = 0; i < tracks.size(); i++) {
              const String8 desc = trackDescriptions.itemAt(i);
              str.appendFormat("    track {%s} ", desc.string());
    @@ -752,7 +760,7 @@ index 72d1d7c57..4be111813 100644
              }
          }
          return str;
    -@@ -232,9 +237,14 @@ void registerMediaSource(
    +@@ -232,9 +238,14 @@ void registerMediaSource(
              if (extractor != NULL && extractor == ex) {
                  if (instance.tracks.size() > 5) {
                      instance.tracks.resize(5);
    @@ -768,6 +776,35 @@ index 72d1d7c57..4be111813 100644
                  break;
              }
          }
    +@@ -262,13 +273,21 @@ void registerMediaExtractor(
    + 
    + status_t dumpExtractors(int fd, const Vector<String16>&) {
    +     String8 out;
    +-    out.append("Recent extractors, most recent first:\n");
    +-    {
    +-        Mutex::Autolock lock(sExtractorsLock);
    +-        for (size_t i = 0; i < sExtractors.size(); i++) {
    +-            const ExtractorInstance &instance = sExtractors.itemAt(i);
    +-            out.append("  ");
    +-            out.append(instance.toString());
    ++    const IPCThreadState* ipc = IPCThreadState::self();
    ++    const int pid = ipc->getCallingPid();
    ++    const int uid = ipc->getCallingUid();
    ++    if (!PermissionCache::checkPermission(String16("android.permission.DUMP"), pid, uid)) {
    ++        out.appendFormat("Permission Denial: "
    ++                "can't dump MediaExtractor from pid=%d, uid=%d\n", pid, uid);
    ++    } else {
    ++        out.append("Recent extractors, most recent first:\n");
    ++        {
    ++            Mutex::Autolock lock(sExtractorsLock);
    ++            for (size_t i = 0; i < sExtractors.size(); i++) {
    ++                const ExtractorInstance &instance = sExtractors.itemAt(i);
    ++                out.append("  ");
    ++                out.append(instance.toString());
    ++            }
    +         }
    +     }
    +     write(fd, out.string(), out.size());
     diff --git a/media/libmediaplayerservice/MediaPlayerFactory.cpp b/media/libmediaplayerservice/MediaPlayerFactory.cpp
     index 605c71014..f5ec20c38 100644
     --- a/media/libmediaplayerservice/MediaPlayerFactory.cpp
    @@ -1732,6 +1769,22 @@ index a17757a8e..f1ad5c573 100644
     +}
     +}
      }  // namespace android
    +diff --git a/media/libstagefright/MidiExtractor.cpp b/media/libstagefright/MidiExtractor.cpp
    +index 7930bbb63..214513403 100644
    +--- a/media/libstagefright/MidiExtractor.cpp
    ++++ b/media/libstagefright/MidiExtractor.cpp
    +@@ -246,8 +246,9 @@ MediaBuffer* MidiEngine::readBuffer() {
    +         EAS_I32 numRendered;
    +         EAS_RESULT result = EAS_Render(mEasData, p, mEasConfig->mixBufferSize, &numRendered);
    +         if (result != EAS_SUCCESS) {
    +-            ALOGE("EAS_Render returned %ld", result);
    +-            break;
    ++            ALOGE("EAS_Render() returned %ld, numBytesOutput = %d", result, numBytesOutput);
    ++            buffer->release();
    ++            return NULL; // Stop processing to prevent infinite loops.
    +         }
    +         p += numRendered * mEasConfig->numChannels;
    +         numBytesOutput += numRendered * mEasConfig->numChannels * sizeof(EAS_PCM);
     diff --git a/media/libstagefright/NuMediaExtractor.cpp b/media/libstagefright/NuMediaExtractor.cpp
     index 4558b3c1c..c3e8f2047 100644
     --- a/media/libstagefright/NuMediaExtractor.cpp
    diff --git a/frameworks_base.patch b/frameworks_base.patch
    index 44e274a..3ea3479 100644
    --- a/frameworks_base.patch
    +++ b/frameworks_base.patch
    @@ -129,6 +129,215 @@ index cd5eff29237..d329175646e 100644
              } catch (RemoteException e) {Log.e(TAG, "", e);}
              return null;
          }
    +diff --git a/core/java/android/content/ContentProvider.java b/core/java/android/content/ContentProvider.java
    +index bc2d788bf4c..1072b5d7902 100644
    +--- a/core/java/android/content/ContentProvider.java
    ++++ b/core/java/android/content/ContentProvider.java
    +@@ -53,6 +53,7 @@ import java.io.IOException;
    + import java.io.PrintWriter;
    + import java.util.ArrayList;
    + import java.util.Arrays;
    ++import java.util.Objects;
    + 
    + /**
    +  * Content providers are one of the primary building blocks of Android applications, providing
    +@@ -207,7 +208,7 @@ public abstract class ContentProvider implements ComponentCallbacks2 {
    +         public Cursor query(String callingPkg, Uri uri, String[] projection,
    +                 String selection, String[] selectionArgs, String sortOrder,
    +                 ICancellationSignal cancellationSignal) {
    +-            validateIncomingUri(uri);
    ++            uri = validateIncomingUri(uri);
    +             uri = getUriWithoutUserId(uri);
    +             if (enforceReadPermission(callingPkg, uri, null) != AppOpsManager.MODE_ALLOWED) {
    +                 // The caller has no access to the data, so return an empty cursor with
    +@@ -246,14 +247,14 @@ public abstract class ContentProvider implements ComponentCallbacks2 {
    + 
    +         @Override
    +         public String getType(Uri uri) {
    +-            validateIncomingUri(uri);
    ++            uri = validateIncomingUri(uri);
    +             uri = getUriWithoutUserId(uri);
    +             return ContentProvider.this.getType(uri);
    +         }
    + 
    +         @Override
    +         public Uri insert(String callingPkg, Uri uri, ContentValues initialValues) {
    +-            validateIncomingUri(uri);
    ++            uri = validateIncomingUri(uri);
    +             int userId = getUserIdFromUri(uri);
    +             uri = getUriWithoutUserId(uri);
    +             if (enforceWritePermission(callingPkg, uri, null) != AppOpsManager.MODE_ALLOWED) {
    +@@ -269,7 +270,7 @@ public abstract class ContentProvider implements ComponentCallbacks2 {
    + 
    +         @Override
    +         public int bulkInsert(String callingPkg, Uri uri, ContentValues[] initialValues) {
    +-            validateIncomingUri(uri);
    ++            uri = validateIncomingUri(uri);
    +             uri = getUriWithoutUserId(uri);
    +             if (enforceWritePermission(callingPkg, uri, null) != AppOpsManager.MODE_ALLOWED) {
    +                 return 0;
    +@@ -291,11 +292,12 @@ public abstract class ContentProvider implements ComponentCallbacks2 {
    +             for (int i = 0; i < numOperations; i++) {
    +                 ContentProviderOperation operation = operations.get(i);
    +                 Uri uri = operation.getUri();
    +-                validateIncomingUri(uri);
    +                 userIds[i] = getUserIdFromUri(uri);
    +-                if (userIds[i] != UserHandle.USER_CURRENT) {
    +-                    // Removing the user id from the uri.
    +-                    operation = new ContentProviderOperation(operation, true);
    ++                uri = validateIncomingUri(uri);
    ++                uri = getUriWithoutUserId(uri);
    ++                // Rebuild operation if we changed the Uri above
    ++                if (!Objects.equals(operation.getUri(), uri)) {
    ++                    operation = new ContentProviderOperation(operation, uri);
    +                     operations.set(i, operation);
    +                 }
    +                 if (operation.isReadOperation()) {
    +@@ -330,7 +332,7 @@ public abstract class ContentProvider implements ComponentCallbacks2 {
    + 
    +         @Override
    +         public int delete(String callingPkg, Uri uri, String selection, String[] selectionArgs) {
    +-            validateIncomingUri(uri);
    ++            uri = validateIncomingUri(uri);
    +             uri = getUriWithoutUserId(uri);
    +             if (enforceWritePermission(callingPkg, uri, null) != AppOpsManager.MODE_ALLOWED) {
    +                 return 0;
    +@@ -346,7 +348,7 @@ public abstract class ContentProvider implements ComponentCallbacks2 {
    +         @Override
    +         public int update(String callingPkg, Uri uri, ContentValues values, String selection,
    +                 String[] selectionArgs) {
    +-            validateIncomingUri(uri);
    ++            uri = validateIncomingUri(uri);
    +             uri = getUriWithoutUserId(uri);
    +             if (enforceWritePermission(callingPkg, uri, null) != AppOpsManager.MODE_ALLOWED) {
    +                 return 0;
    +@@ -363,7 +365,7 @@ public abstract class ContentProvider implements ComponentCallbacks2 {
    +         public ParcelFileDescriptor openFile(
    +                 String callingPkg, Uri uri, String mode, ICancellationSignal cancellationSignal,
    +                 IBinder callerToken) throws FileNotFoundException {
    +-            validateIncomingUri(uri);
    ++            uri = validateIncomingUri(uri);
    +             uri = getUriWithoutUserId(uri);
    +             enforceFilePermission(callingPkg, uri, mode, callerToken);
    +             final String original = setCallingPackage(callingPkg);
    +@@ -379,7 +381,7 @@ public abstract class ContentProvider implements ComponentCallbacks2 {
    +         public AssetFileDescriptor openAssetFile(
    +                 String callingPkg, Uri uri, String mode, ICancellationSignal cancellationSignal)
    +                 throws FileNotFoundException {
    +-            validateIncomingUri(uri);
    ++            uri = validateIncomingUri(uri);
    +             uri = getUriWithoutUserId(uri);
    +             enforceFilePermission(callingPkg, uri, mode, null);
    +             final String original = setCallingPackage(callingPkg);
    +@@ -405,7 +407,7 @@ public abstract class ContentProvider implements ComponentCallbacks2 {
    + 
    +         @Override
    +         public String[] getStreamTypes(Uri uri, String mimeTypeFilter) {
    +-            validateIncomingUri(uri);
    ++            uri = validateIncomingUri(uri);
    +             uri = getUriWithoutUserId(uri);
    +             return ContentProvider.this.getStreamTypes(uri, mimeTypeFilter);
    +         }
    +@@ -414,7 +416,7 @@ public abstract class ContentProvider implements ComponentCallbacks2 {
    +         public AssetFileDescriptor openTypedAssetFile(String callingPkg, Uri uri, String mimeType,
    +                 Bundle opts, ICancellationSignal cancellationSignal) throws FileNotFoundException {
    +             Bundle.setDefusable(opts, true);
    +-            validateIncomingUri(uri);
    ++            uri = validateIncomingUri(uri);
    +             uri = getUriWithoutUserId(uri);
    +             enforceFilePermission(callingPkg, uri, "r", null);
    +             final String original = setCallingPackage(callingPkg);
    +@@ -433,7 +435,7 @@ public abstract class ContentProvider implements ComponentCallbacks2 {
    + 
    +         @Override
    +         public Uri canonicalize(String callingPkg, Uri uri) {
    +-            validateIncomingUri(uri);
    ++            uri = validateIncomingUri(uri);
    +             int userId = getUserIdFromUri(uri);
    +             uri = getUriWithoutUserId(uri);
    +             if (enforceReadPermission(callingPkg, uri, null) != AppOpsManager.MODE_ALLOWED) {
    +@@ -449,7 +451,7 @@ public abstract class ContentProvider implements ComponentCallbacks2 {
    + 
    +         @Override
    +         public Uri uncanonicalize(String callingPkg, Uri uri) {
    +-            validateIncomingUri(uri);
    ++            uri = validateIncomingUri(uri);
    +             int userId = getUserIdFromUri(uri);
    +             uri = getUriWithoutUserId(uri);
    +             if (enforceReadPermission(callingPkg, uri, null) != AppOpsManager.MODE_ALLOWED) {
    +@@ -1735,7 +1737,7 @@ public abstract class ContentProvider implements ComponentCallbacks2 {
    +          */
    +         if (mContext == null) {
    +             mContext = context;
    +-            if (context != null) {
    ++            if (context != null && mTransport != null) {
    +                 mTransport.mAppOpsManager = (AppOpsManager) context.getSystemService(
    +                         Context.APP_OPS_SERVICE);
    +             }
    +@@ -1844,7 +1846,7 @@ public abstract class ContentProvider implements ComponentCallbacks2 {
    +     }
    + 
    +     /** @hide */
    +-    private void validateIncomingUri(Uri uri) throws SecurityException {
    ++    public Uri validateIncomingUri(Uri uri) throws SecurityException {
    +         String auth = uri.getAuthority();
    +         int userId = getUserIdFromAuthority(auth, UserHandle.USER_CURRENT);
    +         if (userId != UserHandle.USER_CURRENT && userId != mContext.getUserId()) {
    +@@ -1861,6 +1863,19 @@ public abstract class ContentProvider implements ComponentCallbacks2 {
    +             }
    +             throw new SecurityException(message);
    +         }
    ++
    ++        // Normalize the path by removing any empty path segments, which can be
    ++        // a source of security issues.
    ++        final String encodedPath = uri.getEncodedPath();
    ++        if (encodedPath != null && encodedPath.indexOf("//") != -1) {
    ++            final Uri normalized = uri.buildUpon()
    ++                    .encodedPath(encodedPath.replaceAll("//+", "/")).build();
    ++            Log.w(TAG, "Normalized " + uri + " to " + normalized
    ++                    + " to avoid possible security issues");
    ++            return normalized;
    ++        } else {
    ++            return uri;
    ++        }
    +     }
    + 
    +     /** @hide */
    +diff --git a/core/java/android/content/ContentProviderOperation.java b/core/java/android/content/ContentProviderOperation.java
    +index fd1e24a48da..1a03bd68cd0 100644
    +--- a/core/java/android/content/ContentProviderOperation.java
    ++++ b/core/java/android/content/ContentProviderOperation.java
    +@@ -94,13 +94,9 @@ public class ContentProviderOperation implements Parcelable {
    +     }
    + 
    +     /** @hide */
    +-    public ContentProviderOperation(ContentProviderOperation cpo, boolean removeUserIdFromUri) {
    ++    public ContentProviderOperation(ContentProviderOperation cpo, Uri withUri) {
    +         mType = cpo.mType;
    +-        if (removeUserIdFromUri) {
    +-            mUri = ContentProvider.getUriWithoutUserId(cpo.mUri);
    +-        } else {
    +-            mUri = cpo.mUri;
    +-        }
    ++        mUri = withUri;
    +         mValues = cpo.mValues;
    +         mSelection = cpo.mSelection;
    +         mSelectionArgs = cpo.mSelectionArgs;
    +@@ -110,14 +106,6 @@ public class ContentProviderOperation implements Parcelable {
    +         mYieldAllowed = cpo.mYieldAllowed;
    +     }
    + 
    +-    /** @hide */
    +-    public ContentProviderOperation getWithoutUserIdInUri() {
    +-        if (ContentProvider.uriHasUserId(mUri)) {
    +-            return new ContentProviderOperation(this, true);
    +-        }
    +-        return this;
    +-    }
    +-
    +     public void writeToParcel(Parcel dest, int flags) {
    +         dest.writeInt(mType);
    +         Uri.writeToParcel(dest, mUri);
     diff --git a/core/java/android/content/PermissionChecker.java b/core/java/android/content/PermissionChecker.java
     new file mode 100644
     index 00000000000..a4b2fe0c10e
    @@ -759,6 +968,31 @@ index 09af05c0dfb..6c069be07e3 100644
                  int portSeparator = authority.indexOf(':', userInfoSeparator);
      
                  if (portSeparator == NOT_FOUND) {
    +diff --git a/core/java/android/os/Parcel.java b/core/java/android/os/Parcel.java
    +index f6e6ad6067b..0591fa8883c 100644
    +--- a/core/java/android/os/Parcel.java
    ++++ b/core/java/android/os/Parcel.java
    +@@ -692,11 +692,19 @@ public final class Parcel {
    +             return;
    +         }
    +         Set<Map.Entry<String,Object>> entries = val.entrySet();
    +-        writeInt(entries.size());
    ++        int size = entries.size();
    ++        writeInt(size);
    ++
    +         for (Map.Entry<String,Object> e : entries) {
    +             writeValue(e.getKey());
    +             writeValue(e.getValue());
    ++            size--;
    +         }
    ++
    ++        if (size != 0) {
    ++            throw new BadParcelableException("Map size does not match number of entries!");
    ++        }
    ++
    +     }
    + 
    +     /**
     diff --git a/core/java/android/provider/MediaStore.java b/core/java/android/provider/MediaStore.java
     index de19f819295..b17657b43db 100644
     --- a/core/java/android/provider/MediaStore.java
    @@ -1881,6 +2115,20 @@ index 7217832bac6..feff102850f 100644
                          }
                      }
                      break;
    +diff --git a/packages/SystemUI/AndroidManifest.xml b/packages/SystemUI/AndroidManifest.xml
    +index 3ee844cd8ef..9e03307fa31 100644
    +--- a/packages/SystemUI/AndroidManifest.xml
    ++++ b/packages/SystemUI/AndroidManifest.xml
    +@@ -165,6 +165,9 @@
    +     <!-- shortcut manager -->
    +     <uses-permission android:name="android.permission.RESET_SHORTCUT_MANAGER_THROTTLING" />
    + 
    ++    <!-- permission necessary to hide non-system overlay windows from covering up the SystemUI -->
    ++    <uses-permission android:name="android.permission.HIDE_NON_SYSTEM_OVERLAY_WINDOWS" />
    ++
    +     <application
    +         android:name=".SystemUIApplication"
    +         android:persistent="true"
     diff --git a/packages/SystemUI/res/values/config.xml b/packages/SystemUI/res/values/config.xml
     index 0fa9a85f412..925f3681c73 100644
     --- a/packages/SystemUI/res/values/config.xml
    @@ -1936,6 +2184,38 @@ index 851ab771882..a384641e16d 100644
          }
      
          public void setType(int type) {
    +diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaProjectionPermissionActivity.java b/packages/SystemUI/src/com/android/systemui/media/MediaProjectionPermissionActivity.java
    +index b2a80f4ca52..4a6786832df 100644
    +--- a/packages/SystemUI/src/com/android/systemui/media/MediaProjectionPermissionActivity.java
    ++++ b/packages/SystemUI/src/com/android/systemui/media/MediaProjectionPermissionActivity.java
    +@@ -16,6 +16,8 @@
    + 
    + package com.android.systemui.media;
    + 
    ++import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS;
    ++
    + import android.app.Activity;
    + import android.app.AlertDialog;
    + import android.content.DialogInterface;
    +@@ -36,6 +38,7 @@ import android.text.TextPaint;
    + import android.text.TextUtils;
    + import android.text.style.StyleSpan;
    + import android.util.Log;
    ++import android.view.Window;
    + import android.view.WindowManager;
    + import android.widget.CheckBox;
    + import android.widget.CompoundButton;
    +@@ -146,7 +149,9 @@ public class MediaProjectionPermissionActivity extends Activity
    +         mDialog.getButton(DialogInterface.BUTTON_POSITIVE).setFilterTouchesWhenObscured(true);
    + 
    +         ((CheckBox) mDialog.findViewById(R.id.remember)).setOnCheckedChangeListener(this);
    +-        mDialog.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT);
    ++        final Window w = mDialog.getWindow();
    ++        w.setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT);
    ++        w.addPrivateFlags(PRIVATE_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS);
    + 
    +         mDialog.show();
    +     }
     diff --git a/packages/SystemUI/src/com/android/systemui/settings/CurrentUserTracker.java b/packages/SystemUI/src/com/android/systemui/settings/CurrentUserTracker.java
     index dd8075057e1..005206fcd14 100644
     --- a/packages/SystemUI/src/com/android/systemui/settings/CurrentUserTracker.java
    @@ -2901,10 +3181,18 @@ index 08c0a4b0135..b5c4202dc10 100644
              StringBuilder sb = new StringBuilder();
              sb.append("Session{");
     diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
    -index ca2610af3f6..0d970591cb5 100644
    +index ca2610af3f6..2203ebbee94 100644
     --- a/services/core/java/com/android/server/wm/WindowManagerService.java
     +++ b/services/core/java/com/android/server/wm/WindowManagerService.java
    -@@ -490,6 +490,9 @@ public class WindowManagerService extends IWindowManager.Stub
    +@@ -16,6 +16,7 @@
    + 
    + package com.android.server.wm;
    + 
    ++import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS;
    + import android.Manifest;
    + import android.animation.ValueAnimator;
    + import android.annotation.IntDef;
    +@@ -490,6 +491,9 @@ public class WindowManagerService extends IWindowManager.Stub
           */
          final ArrayList<WindowState> mForceRemoves = new ArrayList<>();
      
    @@ -2914,7 +3202,7 @@ index ca2610af3f6..0d970591cb5 100644
          /**
           * Windows that clients are waiting to have drawn.
           */
    -@@ -2129,6 +2132,9 @@ public class WindowManagerService extends IWindowManager.Stub
    +@@ -2129,6 +2133,9 @@ public class WindowManagerService extends IWindowManager.Stub
                      }
                  }
      
    @@ -2924,7 +3212,7 @@ index ca2610af3f6..0d970591cb5 100644
                  if (type == TYPE_APPLICATION_STARTING && token.appWindowToken != null) {
                      token.appWindowToken.startingWindow = win;
                      if (DEBUG_STARTING_WINDOW) Slog.v (TAG_WM, "addWindow: " + token.appWindowToken
    -@@ -2576,6 +2582,7 @@ public class WindowManagerService extends IWindowManager.Stub
    +@@ -2576,6 +2583,7 @@ public class WindowManagerService extends IWindowManager.Stub
      
              mPendingRemove.remove(win);
              mResizingWindows.remove(win);
    @@ -2932,13 +3220,26 @@ index ca2610af3f6..0d970591cb5 100644
              mWindowsChanged = true;
              if (DEBUG_WINDOW_MOVEMENT) Slog.v(TAG_WM, "Final remove of window: " + win);
      
    -@@ -11771,4 +11778,34 @@ public class WindowManagerService extends IWindowManager.Stub
    +@@ -2893,6 +2901,11 @@ public class WindowManagerService extends IWindowManager.Stub
    +                         | WindowManager.LayoutParams.SYSTEM_UI_VISIBILITY_CHANGED)) != 0) {
    +                     win.mLayoutNeeded = true;
    +                 }
    ++
    ++                if ((flagChanges & PRIVATE_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS) != 0) {
    ++                    updateNonSystemOverlayWindowsVisibilityIfNeeded(
    ++                            win, win.mWinAnimator.getShown());
    ++                }
    +             }
    + 
    +             if (DEBUG_LAYOUT) Slog.v(TAG_WM, "Relayout " + win + ": viewVisibility=" + viewVisibility
    +@@ -11771,4 +11784,35 @@ public class WindowManagerService extends IWindowManager.Stub
                  }
              }
          }
     +
     +    void updateNonSystemOverlayWindowsVisibilityIfNeeded(WindowState win, boolean surfaceShown) {
    -+        if (!win.hideNonSystemOverlayWindowsWhenVisible()) {
    ++        if (!win.hideNonSystemOverlayWindowsWhenVisible()
    ++                && !mHidingNonSystemOverlayWindows.contains(win)) {
     +            return;
     +        }
     +        final boolean systemAlertWindowsHidden = !mHidingNonSystemOverlayWindows.isEmpty();
    diff --git a/system_bt.patch b/system_bt.patch
    index f38c810..4936f3b 100644
    --- a/system_bt.patch
    +++ b/system_bt.patch
    @@ -1,12 +1,34 @@
    +diff --git a/Android.mk b/Android.mk
    +index 29760e4e0..43a9592be 100644
    +--- a/Android.mk
    ++++ b/Android.mk
    +@@ -38,6 +38,7 @@ bluetooth_CFLAGS += \
    +   -Wno-gnu-variable-sized-type-not-at-end \
    +   -Wno-typedef-redefinition \
    +   -Wno-unused-parameter \
    ++  -Wno-unused-variable \
    +   -UNDEBUG \
    +   -DLOG_NDEBUG=1
    + 
     diff --git a/bta/av/bta_av_act.c b/bta/av/bta_av_act.c
    -index 9cc802f0a..5aef52823 100644
    +index 9cc802f0a..7154865c6 100644
     --- a/bta/av/bta_av_act.c
     +++ b/bta/av/bta_av_act.c
    -@@ -800,11 +800,15 @@ tBTA_AV_EVT bta_av_proc_meta_cmd(tAVRC_RESPONSE  *p_rc_rsp, tBTA_AV_RC_MSG *p_ms
    +@@ -35,6 +35,7 @@
    + #include "bta_av_api.h"
    + #include "bta_av_int.h"
    + #include "l2c_api.h"
    ++#include "log/log.h"
    + #include "osi/include/list.h"
    + #include "osi/include/log.h"
    + #include "osi/include/osi.h"
    +@@ -800,11 +801,17 @@ tBTA_AV_EVT bta_av_proc_meta_cmd(tAVRC_RESPONSE  *p_rc_rsp, tBTA_AV_RC_MSG *p_ms
              case AVRC_PDU_GET_CAPABILITIES:
                  /* process GetCapabilities command without reporting the event to app */
                  evt = 0;
    -+            if (p_vendor->vendor_len != 5) {
    ++            if (p_vendor->vendor_len != 5)
    ++            {
    ++                android_errorWriteLog(0x534e4554, "111893951");
     +                p_rc_rsp->get_caps.status = AVRC_STS_INTERNAL_ERR;
     +                break;
     +            }
    @@ -15,12 +37,12 @@ index 9cc802f0a..5aef52823 100644
                  p_rc_rsp->get_caps.capability_id = u8;
                  BE_STREAM_TO_UINT16 (u16, p);
     -            if ((u16 != 1) || (p_vendor->vendor_len != 5))
    -+            if (u16 != 1) 
    ++            if (u16 != 1)
                  {
                      p_rc_rsp->get_caps.status = AVRC_STS_INTERNAL_ERR;
                  }
     diff --git a/bta/dm/bta_dm_act.c b/bta/dm/bta_dm_act.c
    -index 1bf741d92..a8d92e0d3 100644
    +index 1bf741d92..3884a5c55 100644
     --- a/bta/dm/bta_dm_act.c
     +++ b/bta/dm/bta_dm_act.c
     @@ -26,6 +26,7 @@
    @@ -40,7 +62,50 @@ index 1bf741d92..a8d92e0d3 100644
      static void bta_dm_inq_results_cb (tBTM_INQ_RESULTS *p_inq, UINT8 *p_eir);
      static void bta_dm_inq_cmpl_cb (void * p_result);
      static void bta_dm_service_search_remname_cback (BD_ADDR bd_addr, DEV_CLASS dc, BD_NAME bd_name);
    -@@ -1601,7 +1604,7 @@ void bta_dm_sdp_result (tBTA_DM_MSG *p_data)
    +@@ -132,9 +135,11 @@ static void bta_dm_ctrl_features_rd_cmpl_cback(tBTM_STATUS result);
    + 
    + static void bta_dm_reset_sec_dev_pending(BD_ADDR remote_bd_addr);
    + static void bta_dm_remove_sec_dev_entry(BD_ADDR remote_bd_addr);
    ++#if (defined(BTA_GATT_INCLUDED) && BTA_GATT_INCLUDED)
    + static void bta_dm_observe_results_cb(tBTM_INQ_RESULTS *p_inq, UINT8 *p_eir);
    + static void bta_dm_observe_cmpl_cb(void * p_result);
    + static void bta_dm_delay_role_switch_cback(void *data);
    ++#endif
    + extern void sdpu_uuid16_to_uuid128(UINT16 uuid16, UINT8* p_uuid128);
    + static void bta_dm_disable_timer_cback(void *data);
    + 
    +@@ -383,7 +388,9 @@ static void bta_dm_sys_hw_cback( tBTA_SYS_HW_EVT status )
    + 
    +         /* hw is ready, go on with BTA DM initialization */
    +         alarm_free(bta_dm_search_cb.search_timer);
    ++#if (defined(BTA_GATT_INCLUDED) && BTA_GATT_INCLUDED)
    +         alarm_free(bta_dm_search_cb.gatt_close_timer);
    ++#endif
    +         memset(&bta_dm_search_cb, 0, sizeof(bta_dm_search_cb));
    +         /*
    +          * TODO: Should alarm_free() the bta_dm_search_cb timers during
    +@@ -391,8 +398,10 @@ static void bta_dm_sys_hw_cback( tBTA_SYS_HW_EVT status )
    +          */
    +         bta_dm_search_cb.search_timer =
    +           alarm_new("bta_dm_search.search_timer");
    ++#if (defined(BTA_GATT_INCLUDED) && BTA_GATT_INCLUDED)
    +         bta_dm_search_cb.gatt_close_timer =
    +           alarm_new("bta_dm_search.gatt_close_timer");
    ++#endif
    + 
    +         memset(&bta_dm_conn_srvcs, 0, sizeof(bta_dm_conn_srvcs));
    +         memset(&bta_dm_di_cb, 0, sizeof(tBTA_DM_DI_CB));
    +@@ -710,7 +719,9 @@ void bta_dm_remove_device(tBTA_DM_MSG *p_data)
    + 
    +     /* If ACL exists for the device in the remove_bond message*/
    +     BOOLEAN continue_delete_dev = FALSE;
    ++#if (defined(BTA_GATT_INCLUDED) && BTA_GATT_INCLUDED)
    +     UINT8 other_transport = BT_TRANSPORT_INVALID;
    ++#endif
    + 
    +     if (BTM_IsAclConnectionUp(p_dev->bd_addr, BT_TRANSPORT_LE) ||
    +         BTM_IsAclConnectionUp(p_dev->bd_addr, BT_TRANSPORT_BR_EDR))
    +@@ -1601,7 +1612,7 @@ void bta_dm_sdp_result (tBTA_DM_MSG *p_data)
      #endif
      
          UINT32 num_uuids = 0;
    @@ -49,7 +114,7 @@ index 1bf741d92..a8d92e0d3 100644
      
          if((p_data->sdp_event.sdp_result == SDP_SUCCESS)
              || (p_data->sdp_event.sdp_result == SDP_NO_RECS_MATCH)
    -@@ -1679,8 +1682,12 @@ void bta_dm_sdp_result (tBTA_DM_MSG *p_data)
    +@@ -1679,8 +1690,12 @@ void bta_dm_sdp_result (tBTA_DM_MSG *p_data)
                                  (tBTA_SERVICE_MASK)(BTA_SERVICE_ID_TO_SERVICE_MASK(bta_dm_search_cb.service_index-1));
                              tmp_svc = bta_service_id_to_uuid_lkup_tbl[bta_dm_search_cb.service_index-1];
                              /* Add to the list of UUIDs */
    @@ -64,7 +129,7 @@ index 1bf741d92..a8d92e0d3 100644
                          }
                      }
                  }
    -@@ -1719,8 +1726,12 @@ void bta_dm_sdp_result (tBTA_DM_MSG *p_data)
    +@@ -1719,8 +1734,12 @@ void bta_dm_sdp_result (tBTA_DM_MSG *p_data)
                      {
                          if (SDP_FindServiceUUIDInRec_128bit(p_sdp_rec, &temp_uuid))
                          {
    @@ -79,6 +144,39 @@ index 1bf741d92..a8d92e0d3 100644
                          }
                      }
                  } while (p_sdp_rec);
    +@@ -3322,12 +3341,16 @@ void bta_dm_acl_change(tBTA_DM_MSG *p_data)
    +         }
    +         if (conn.link_down.is_removed)
    +         {
    +-            BTM_SecDeleteDevice(p_bda);
    ++            // p_bda points to security record, which is removed in
    ++            // BTM_SecDeleteDevice.
    ++            BD_ADDR addr_copy;
    ++            memcpy(addr_copy, p_bda, BD_ADDR_LEN);
    ++            BTM_SecDeleteDevice(addr_copy);
    + #if (BLE_INCLUDED == TRUE && BTA_GATT_INCLUDED == TRUE)
    +             /* need to remove all pending background connection */
    +-            BTA_GATTC_CancelOpen(0, p_bda, FALSE);
    ++            BTA_GATTC_CancelOpen(0, addr_copy, FALSE);
    +             /* remove all cached GATT information */
    +-            BTA_GATTC_Refresh(p_bda);
    ++            BTA_GATTC_Refresh(addr_copy);
    + #endif
    +          }
    + 
    +diff --git a/bta/dm/bta_dm_api.c b/bta/dm/bta_dm_api.c
    +index 82dd8b229..f7a607ee6 100644
    +--- a/bta/dm/bta_dm_api.c
    ++++ b/bta/dm/bta_dm_api.c
    +@@ -1231,6 +1231,8 @@ void BTA_DmDiscoverByTransport(BD_ADDR bd_addr, tBTA_SERVICE_MASK_EXT *p_service
    + {
    + #if BLE_INCLUDED == TRUE && BTA_GATT_INCLUDED == TRUE
    +     bta_dm_discover_send_msg(bd_addr, p_services, p_cback, sdp_search, transport);
    ++#else
    ++return;
    + #endif
    + }
    + 
     diff --git a/bta/gatt/bta_gattc_cache.c b/bta/gatt/bta_gattc_cache.c
     index 63c424696..45d258824 100644
     --- a/bta/gatt/bta_gattc_cache.c
    @@ -156,6 +254,146 @@ index 199547817..4367fce68 100644
          fixed_queue_enqueue(p_scb->data_queue, p_new_buf);
          BT_HDR *p_event = (BT_HDR *)osi_malloc(sizeof(BT_HDR));
          p_event->layer_specific = handle;
    +diff --git a/btif/src/btif_dm.c b/btif/src/btif_dm.c
    +index f54b64277..38c324c9e 100644
    +--- a/btif/src/btif_dm.c
    ++++ b/btif/src/btif_dm.c
    +@@ -52,6 +52,7 @@
    + #include "btu.h"
    + #include "bt_common.h"
    + #include "bta_gatt_api.h"
    ++#include "bta_api.h"
    + #include "device/include/interop.h"
    + #include "include/stack_config.h"
    + #include "osi/include/allocator.h"
    +@@ -234,12 +235,12 @@ static void btif_dm_ble_passkey_req_evt(tBTA_DM_PIN_REQ *p_pin_req);
    + static void btif_dm_ble_key_nc_req_evt(tBTA_DM_SP_KEY_NOTIF *p_notif_req) ;
    + static void btif_dm_ble_oob_req_evt(tBTA_DM_SP_RMT_OOB *req_oob_type);
    + static void btif_dm_ble_sc_oob_req_evt(tBTA_DM_SP_RMT_OOB *req_oob_type);
    +-#endif
    + 
    + static void bte_scan_filt_param_cfg_evt(UINT8 action_type,
    +                                            tBTA_DM_BLE_PF_AVBL_SPACE avbl_space,
    +                                            tBTA_DM_BLE_REF_VALUE ref_value,
    +                                            tBTA_STATUS status);
    ++#endif
    + 
    + static char* btif_get_default_local_name();
    + 
    +@@ -2241,7 +2242,6 @@ static void bta_energy_info_cb(tBTA_DM_BLE_TX_TIME_MS tx_time, tBTA_DM_BLE_RX_TI
    +     btif_transfer_context(btif_dm_upstreams_evt, BTA_DM_ENER_INFO_READ,
    +                           (char*) &btif_cb, sizeof(btif_activity_energy_info_cb_t), NULL);
    + }
    +-#endif
    + 
    + /*******************************************************************************
    + **
    +@@ -2269,6 +2269,7 @@ static void bte_scan_filt_param_cfg_evt(UINT8 action_type,
    +     }
    + }
    + 
    ++#endif
    + /*****************************************************************************
    + **
    + **   btif api functions (no context switch)
    +@@ -2395,6 +2396,7 @@ bt_status_t btif_dm_create_bond_out_of_band(const bt_bdaddr_t *bd_addr, int tran
    +     bdcpy(oob_cb.bdaddr, bd_addr->address);
    +     memcpy(&oob_cb.oob_data, oob_data, sizeof(bt_out_of_band_data_t));
    + 
    ++#if (defined(BLE_INCLUDED) && (BLE_INCLUDED == TRUE))
    +     uint8_t empty[] = {0, 0, 0, 0, 0, 0, 0};
    +     // If LE Bluetooth Device Address is provided, use provided address type
    +     // value.
    +@@ -2407,6 +2409,7 @@ bt_status_t btif_dm_create_bond_out_of_band(const bt_bdaddr_t *bd_addr, int tran
    +             BTM_SecAddBleDevice(bd_addr->address, NULL, BT_DEVICE_TYPE_BLE, address_type);
    +         }
    +     }
    ++#endif
    + 
    +     bdstr_t bdstr;
    +     BTIF_TRACE_EVENT("%s: bd_addr=%s, transport=%d", __FUNCTION__, bdaddr_to_string(bd_addr, bdstr, sizeof(bdstr)), transport);
    +@@ -2710,8 +2713,10 @@ bt_status_t btif_dm_get_remote_services_by_transport(bt_bdaddr_t *remote_addr, c
    +     mask_ext.p_uuid = NULL;
    +     mask_ext.srvc_mask = BTA_ALL_SERVICE_MASK;
    + 
    ++#if ((defined BLE_INCLUDED) && (BLE_INCLUDED == TRUE))
    +     BTA_DmDiscoverByTransport(remote_addr->address, &mask_ext,
    +                    bte_dm_search_services_evt, TRUE, transport);
    ++#endif
    + 
    +     return BT_STATUS_SUCCESS;
    + }
    +@@ -2957,6 +2962,7 @@ BOOLEAN btif_dm_get_smp_config(tBTE_APPL_CFG* p_cfg) {
    +     strncpy(conf, recv, 64);
    +     conf[63] = 0; // null terminate
    + 
    ++#if ((defined BLE_INCLUDED) && (BLE_INCLUDED == TRUE))
    +     if ((pch = strtok(conf, ",")) != NULL)
    +         p_cfg->ble_auth_req = (UINT8) strtoul(pch, &endptr, 16);
    +     else
    +@@ -2981,6 +2987,7 @@ BOOLEAN btif_dm_get_smp_config(tBTE_APPL_CFG* p_cfg) {
    +         p_cfg->ble_max_key_size =  (UINT8) strtoul(pch, &endptr, 16);
    +     else
    +         return FALSE;
    ++#endif
    + 
    +     return TRUE;
    + }
    +diff --git a/btif/src/btif_hf.c b/btif/src/btif_hf.c
    +index 6abf09901..9d963d1de 100644
    +--- a/btif/src/btif_hf.c
    ++++ b/btif/src/btif_hf.c
    +@@ -33,6 +33,7 @@
    + 
    + #include <hardware/bluetooth.h>
    + #include <hardware/bt_hf.h>
    ++#include <log/log.h>
    + 
    + #include "bta_ag_api.h"
    + #include "btcore/include/bdaddr.h"
    +@@ -1261,13 +1262,20 @@ static bt_status_t clcc_response(int index, bthf_call_direction_t dir,
    +                           index, dir, state, mode, number, type);
    +             xx = sprintf (ag_res.str, "%d,%d,%d,%d,%d",
    +                          index, dir, state, mode, mpty);
    ++            char number_copy[sizeof(ag_res.str)];
    ++            // 9 = [,]["][+]["][,][3_digit_type][null_terminator]
    ++            int max_number_len = sizeof(ag_res.str) - xx - 9;
    ++            int number_len = snprintf(number_copy, max_number_len, "%s", number);
    ++            if (number_len >= max_number_len) {
    ++              android_errorWriteLog(0x534e4554, "79266386");
    ++            }
    + 
    +             if (number)
    +             {
    +                 if ((type == BTHF_CALL_ADDRTYPE_INTERNATIONAL) && (*number != '+'))
    +-                    sprintf (&ag_res.str[xx], ",\"+%s\",%d", number, type);
    ++                    sprintf (&ag_res.str[xx], ",\"+%s\",%d", number_copy, type);
    +                 else
    +-                    sprintf (&ag_res.str[xx], ",\"%s\",%d", number, type);
    ++                    sprintf (&ag_res.str[xx], ",\"%s\",%d", number_copy, type);
    +             }
    +         }
    +         BTA_AgResult (btif_hf_cb[idx].handle, BTA_AG_CLCC_RES, &ag_res);
    +@@ -1420,10 +1428,17 @@ static bt_status_t phone_state_change(int num_active, int num_held, bthf_call_st
    +                 if (number)
    +                 {
    +                     int xx = 0;
    ++                    char number_copy[sizeof(ag_res.str)];
    ++                    // 8 = ["][+]["][,][3_digit_type][null_terminator]
    ++                    int max_number_len = sizeof(ag_res.str) - xx - 8;
    ++                    int number_len = snprintf(number_copy, max_number_len, "%s", number);
    ++                    if (number_len >= max_number_len) {
    ++                      android_errorWriteLog(0x534e4554, "79431031");
    ++                    }
    +                     if ((type == BTHF_CALL_ADDRTYPE_INTERNATIONAL) && (*number != '+'))
    +-                        xx = sprintf (ag_res.str, "\"+%s\"", number);
    ++                        xx = sprintf (ag_res.str, "\"+%s\"", number_copy);
    +                     else
    +-                        xx = sprintf (ag_res.str, "\"%s\"", number);
    ++                        xx = sprintf (ag_res.str, "\"%s\"", number_copy);
    +                     ag_res.num = type;
    + 
    +                     if (res == BTA_AG_CALL_WAIT_RES)
     diff --git a/btif/src/btif_rc.c b/btif/src/btif_rc.c
     index 6572fd74e..133277a35 100644
     --- a/btif/src/btif_rc.c
    @@ -196,10 +434,21 @@ index d02dfa0b8..90d74cf53 100644
              return handle;
          }
     diff --git a/btif/src/btif_storage.c b/btif/src/btif_storage.c
    -index 83dcc8c47..d02b09a55 100644
    +index 83dcc8c47..139fcdcf5 100644
     --- a/btif/src/btif_storage.c
     +++ b/btif/src/btif_storage.c
    -@@ -229,6 +229,10 @@ static int prop2cfg(bt_bdaddr_t *remote_bd_addr, bt_property_t *prop)
    +@@ -163,8 +163,10 @@ extern void btif_gatts_add_bonded_dev_from_nv(BD_ADDR bda);
    + **  Internal Functions
    + ************************************************************************************/
    + 
    ++#if (BLE_INCLUDED == TRUE)
    + static bt_status_t btif_in_fetch_bonded_ble_device(const char *remote_bd_addr,int add,
    +                                               btif_bonded_devices_t *p_bonded_devices);
    ++#endif
    + static bt_status_t btif_in_fetch_bonded_device(const char *bdstr);
    + 
    + /************************************************************************************
    +@@ -229,6 +231,10 @@ static int prop2cfg(bt_bdaddr_t *remote_bd_addr, bt_property_t *prop)
                      bt_uuid_t *p_uuid = (bt_uuid_t*)prop->val + i;
                      memset(buf, 0, sizeof(buf));
                      uuid_to_string_legacy(p_uuid, buf);
    @@ -210,6 +459,44 @@ index 83dcc8c47..d02b09a55 100644
                      strcat(value, buf);
                      //strcat(value, ";");
                      strcat(value, " ");
    +@@ -493,6 +499,7 @@ static bt_status_t btif_in_fetch_bonded_devices(btif_bonded_devices_t *p_bonded_
    +     return BT_STATUS_SUCCESS;
    + }
    + 
    ++#if (BLE_INCLUDED == TRUE)
    + static void btif_read_le_key(const uint8_t key_type, const size_t key_len, bt_bdaddr_t bd_addr,
    +                  const uint8_t addr_type, const bool add_key, bool *device_added, bool *key_found)
    + {
    +@@ -524,6 +531,7 @@ static void btif_read_le_key(const uint8_t key_type, const size_t key_len, bt_bd
    +         *key_found = true;
    +     }
    + }
    ++#endif
    + 
    + /*******************************************************************************
    +  * Functions
    +diff --git a/hci/src/hci_hal_h4.c b/hci/src/hci_hal_h4.c
    +index 9c7afe53d..0ea5dfd62 100644
    +--- a/hci/src/hci_hal_h4.c
    ++++ b/hci/src/hci_hal_h4.c
    +@@ -30,6 +30,7 @@
    + #include "osi/include/reactor.h"
    + #include "osi/include/thread.h"
    + #include "vendor.h"
    ++#include "bt_target.h"
    + 
    + #define HCI_HAL_SERIAL_BUFFER_SIZE 1026
    + #define HCI_BLE_EVENT 0x3e
    +@@ -238,7 +239,9 @@ static void event_uart_has_bytes(eager_reader_t *reader, UNUSED_ATTR void *conte
    +       LOG_ERROR(LOG_TAG, "%s Unknown HCI message type 0x%x (min=0x%x max=0x%x). Aborting...",
    +                 __func__, type_byte, DATA_TYPE_ACL, DATA_TYPE_EVENT);
    +       LOG_EVENT_INT(BT_HCI_UNKNOWN_MESSAGE_TYPE_NUM, type_byte);
    ++#if (!defined(LEGACY_BRCM_HCI) || (LEGACY_BRCM_HCI == FALSE))
    +       assert(false && "Unknown HCI message type");
    ++#endif
    +       return;
    +     }
    + 
     diff --git a/osi/src/alarm.c b/osi/src/alarm.c
     index 69ded69e4..5f9e42ce3 100644
     --- a/osi/src/alarm.c
    @@ -352,64 +639,46 @@ index 98ef5f755..52010541d 100644
      
                  p_pkt->offset = L2CAP_MIN_OFFSET;
                  p = (UINT8 *)(p_pkt + 1) + p_pkt->offset;
    -diff --git a/stack/avrc/avrc_api.c b/stack/avrc/avrc_api.c
    -index 77ca7d45e..dc0ce4661 100644
    ---- a/stack/avrc/avrc_api.c
    -+++ b/stack/avrc/avrc_api.c
    -@@ -563,7 +563,20 @@ static void avrc_msg_cback(UINT8 handle, UINT8 label, UINT8 cr,
    - 
    -     p_data  = (UINT8 *)(p_pkt+1) + p_pkt->offset;
    -     memset(&msg, 0, sizeof(tAVRC_MSG) );
    --    {
    -+
    -+    if (p_pkt->layer_specific == AVCT_DATA_BROWSE) {
    -+        opcode = AVRC_OP_BROWSE;
    -+        msg.browse.hdr.ctype = cr;
    -+        msg.browse.p_browse_data = p_data;
    -+        msg.browse.browse_len = p_pkt->len;
    -+        msg.browse.p_browse_pkt = p_pkt;
    -+    } else {
    -+        if (p_pkt->len < AVRC_AVC_HDR_SIZE) {
    -+            AVRC_TRACE_WARNING("%s: message length %d too short: must be at least %d",
    -+                                 __func__, p_pkt->len, AVRC_AVC_HDR_SIZE);
    -+            osi_free(p_pkt);
    -+            return;
    -+        }
    -         msg.hdr.ctype           = p_data[0] & AVRC_CTYPE_MASK;
    -         AVRC_TRACE_DEBUG("avrc_msg_cback handle:%d, ctype:%d, offset:%d, len: %d",
    -                 handle, msg.hdr.ctype, p_pkt->offset, p_pkt->len);
    -@@ -602,6 +615,14 @@ static void avrc_msg_cback(UINT8 handle, UINT8 label, UINT8 cr,
    -             else
    -             {
    -                 /* parse response */
    -+	        if (p_pkt->len < AVRC_OP_UNIT_INFO_RSP_LEN) {
    -+                    AVRC_TRACE_WARNING(
    -+                         "%s: message length %d too short: must be at least %d",
    -+                         __func__, p_pkt->len, AVRC_OP_UNIT_INFO_RSP_LEN);
    -+                    drop = true;
    -+                    p_drop_msg = "UNIT_INFO_RSP too short";
    +diff --git a/stack/avdt/avdt_msg.c b/stack/avdt/avdt_msg.c
    +index adc1ae731..91a58403e 100644
    +--- a/stack/avdt/avdt_msg.c
    ++++ b/stack/avdt/avdt_msg.c
    +@@ -26,6 +26,7 @@
    +  *
    +  ******************************************************************************/
    + 
    ++#include <log/log.h>
    + #include <string.h>
    + #include "bt_types.h"
    + #include "bt_target.h"
    +@@ -673,6 +674,12 @@ static UINT8 avdt_msg_prs_cfg(tAVDT_CFG *p_cfg, UINT8 *p, UINT16 len, UINT8* p_e
    + 
    +             case AVDT_CAT_PROTECT:
    +                 p_cfg->psc_mask &= ~AVDT_PSC_PROTECT;
    ++                if (p + elem_len > p_end)
    ++                {
    ++                    err = AVDT_ERR_LENGTH;
    ++                    android_errorWriteLog(0x534e4554, "78288378");
     +                    break;
     +                }
    -                 p_data += 4; /* 3 bytes: ctype, subunit*, opcode + octet 3 (is 7)*/
    -                 msg.unit.unit_type  = (*p_data & AVRC_SUBTYPE_MASK) >> AVRC_SUBTYPE_SHIFT;
    -                 msg.unit.unit       = *p_data & AVRC_SUBID_MASK;
    -@@ -633,6 +654,14 @@ static void avrc_msg_cback(UINT8 handle, UINT8 label, UINT8 cr,
    -             else
    -             {
    -                 /* parse response */
    -+	        if (p_pkt->len < AVRC_OP_SUB_UNIT_INFO_RSP_LEN) {
    -+                    AVRC_TRACE_WARNING(
    -+                        "%s: message length %d too short: must be at least %d",
    -+                        __func__, p_pkt->len, AVRC_OP_SUB_UNIT_INFO_RSP_LEN);
    -+                    drop = true;
    -+                    p_drop_msg = "SUB_UNIT_INFO_RSP too short";
    +                 if ((elem_len + protect_offset) < AVDT_PROTECT_SIZE)
    +                 {
    +                     p_cfg->num_protect++;
    +@@ -747,6 +754,12 @@ static UINT8 avdt_msg_prs_cfg(tAVDT_CFG *p_cfg, UINT8 *p, UINT16 len, UINT8* p_e
    +                 {
    +                     tmp = AVDT_CODEC_SIZE - 1;
    +                 }
    ++                if (p + tmp > p_end)
    ++                {
    ++                    err = AVDT_ERR_LENGTH;
    ++                    android_errorWriteLog(0x534e4554, "78288378");
     +                    break;
     +                }
    -                 p_data += AVRC_AVC_HDR_SIZE; /* 3 bytes: ctype, subunit*, opcode */
    -                 msg.sub.page    = (*p_data++ >> AVRC_SUB_PAGE_SHIFT) & AVRC_SUB_PAGE_MASK;
    -                 xx      = 0;
    +                 p_cfg->num_codec++;
    +                 p_cfg->codec_info[0] = elem_len;
    +                 memcpy(&p_cfg->codec_info[1], p, tmp);
     diff --git a/stack/avrc/avrc_pars_ct.c b/stack/avrc/avrc_pars_ct.c
    -index 63cc38407..699cd0438 100644
    +index 63cc38407..eb1ff99c5 100644
     --- a/stack/avrc/avrc_pars_ct.c
     +++ b/stack/avrc/avrc_pars_ct.c
     @@ -22,6 +22,7 @@
    @@ -444,11 +713,12 @@ index 63cc38407..699cd0438 100644
              for(int xx = 0; xx < p_result->list_app_attr.num_attr; xx++)
              {
                  BE_STREAM_TO_UINT8(p_result->list_app_attr.attrs[xx], p);
    -@@ -240,6 +251,11 @@ static tAVRC_STS avrc_ctrl_pars_vendor_rsp(
    +@@ -240,6 +251,12 @@ static tAVRC_STS avrc_ctrl_pars_vendor_rsp(
                  break;
              }
              BE_STREAM_TO_UINT8(p_result->list_app_values.num_val, p);
    -+        if (p_result->list_app_values.num_val > AVRC_MAX_APP_ATTR_SIZE) {
    ++        if (p_result->list_app_values.num_val > AVRC_MAX_APP_ATTR_SIZE)
    ++        {
     +            android_errorWriteLog(0x534e4554, "78526423");
     +            p_result->list_app_values.num_val = AVRC_MAX_APP_ATTR_SIZE;
     +        }
    @@ -456,7 +726,7 @@ index 63cc38407..699cd0438 100644
              AVRC_TRACE_DEBUG("%s value count = %d ", __func__, p_result->list_app_values.num_val);
              for(int xx = 0; xx < p_result->list_app_values.num_val; xx++)
              {
    -@@ -258,6 +274,12 @@ static tAVRC_STS avrc_ctrl_pars_vendor_rsp(
    +@@ -258,6 +275,12 @@ static tAVRC_STS avrc_ctrl_pars_vendor_rsp(
              tAVRC_APP_SETTING *app_sett =
                  (tAVRC_APP_SETTING*)osi_malloc(p_result->get_cur_app_val.num_val*sizeof(tAVRC_APP_SETTING));
              AVRC_TRACE_DEBUG("%s attr count = %d ", __func__, p_result->get_cur_app_val.num_val);
    @@ -469,7 +739,7 @@ index 63cc38407..699cd0438 100644
              for (int xx = 0; xx < p_result->get_cur_app_val.num_val; xx++)
              {
                  BE_STREAM_TO_UINT8(app_sett[xx].attr_id, p);
    -@@ -269,7 +291,6 @@ static tAVRC_STS avrc_ctrl_pars_vendor_rsp(
    +@@ -269,7 +292,6 @@ static tAVRC_STS avrc_ctrl_pars_vendor_rsp(
      
          case AVRC_PDU_GET_PLAYER_APP_ATTR_TEXT:
          {
    @@ -477,7 +747,7 @@ index 63cc38407..699cd0438 100644
              UINT8                    num_attrs;
      
              if (len == 0)
    -@@ -278,9 +299,12 @@ static tAVRC_STS avrc_ctrl_pars_vendor_rsp(
    +@@ -278,9 +300,12 @@ static tAVRC_STS avrc_ctrl_pars_vendor_rsp(
                  break;
              }
              BE_STREAM_TO_UINT8(num_attrs, p);
    @@ -491,7 +761,7 @@ index 63cc38407..699cd0438 100644
              for (int xx = 0; xx < num_attrs; xx++)
              {
                  BE_STREAM_TO_UINT8(p_result->get_app_attr_txt.p_attrs[xx].attr_id, p);
    -@@ -300,7 +324,6 @@ static tAVRC_STS avrc_ctrl_pars_vendor_rsp(
    +@@ -300,7 +325,6 @@ static tAVRC_STS avrc_ctrl_pars_vendor_rsp(
      
          case AVRC_PDU_GET_PLAYER_APP_VALUE_TEXT:
          {
    @@ -499,7 +769,7 @@ index 63cc38407..699cd0438 100644
              UINT8                    num_vals;
      
              if (len == 0)
    -@@ -309,10 +332,13 @@ static tAVRC_STS avrc_ctrl_pars_vendor_rsp(
    +@@ -309,10 +333,13 @@ static tAVRC_STS avrc_ctrl_pars_vendor_rsp(
                  break;
              }
              BE_STREAM_TO_UINT8(num_vals, p);
    @@ -586,7 +856,7 @@ index 9a7b5d944..3e866d100 100644
                      p_data[3] = 0;
                  }
     diff --git a/stack/bnep/bnep_main.c b/stack/bnep/bnep_main.c
    -index 078a72ebd..8edb712ac 100644
    +index 078a72ebd..2f761de68 100644
     --- a/stack/bnep/bnep_main.c
     +++ b/stack/bnep/bnep_main.c
     @@ -35,6 +35,7 @@
    @@ -597,7 +867,20 @@ index 078a72ebd..8edb712ac 100644
      
      #include "btu.h"
      #include "btm_api.h"
    -@@ -495,6 +496,12 @@ static void bnep_data_ind (UINT16 l2cap_cid, BT_HDR *p_buf)
    +@@ -482,6 +483,12 @@ static void bnep_data_ind (UINT16 l2cap_cid, BT_HDR *p_buf)
    +     UINT16        protocol = 0;
    +     UINT8         *p_src_addr, *p_dst_addr;
    + 
    ++    if (rem_len == 0)
    ++    {
    ++        android_errorWriteLog(0x534e4554, "78286118");
    ++        osi_free(p_buf);
    ++        return;
    ++    }
    + 
    +     /* Find CCB based on CID */
    +     if ((p_bcb = bnepu_find_bcb_by_cid (l2cap_cid)) == NULL)
    +@@ -495,6 +502,12 @@ static void bnep_data_ind (UINT16 l2cap_cid, BT_HDR *p_buf)
          type = *p++;
          extension_present = type >> 7;
          type &= 0x7f;
    @@ -610,34 +893,57 @@ index 078a72ebd..8edb712ac 100644
          if ((rem_len <= bnep_frame_hdr_sizes[type]) || (rem_len > BNEP_MTU_SIZE))
          {
              BNEP_TRACE_EVENT ("BNEP - rcvd frame, bad len: %d  type: 0x%02x", p_buf->len, type);
    -@@ -524,20 +531,20 @@ static void bnep_data_ind (UINT16 l2cap_cid, BT_HDR *p_buf)
    +@@ -522,24 +535,40 @@ static void bnep_data_ind (UINT16 l2cap_cid, BT_HDR *p_buf)
    +             UINT16      org_len, new_len;
    +             /* parse the extension headers and process unknown control headers */
                  org_len = rem_len;
    -             new_len = 0;
    +-            new_len = 0;
                  do {
     -
    -+                if (org_len < 2) break;
    ++                if (org_len < 2)
    ++                {
    ++                    android_errorWriteLog(0x534e4554, "67863755");
    ++                    break;
    ++                }
                      ext     = *p++;
                      length  = *p++;
    -                 p += length;
    +-                p += length;
    +-
    +-                if ((!(ext & 0x7F)) && (*p > BNEP_FILTER_MULTI_ADDR_RESPONSE_MSG))
    +-                    bnep_send_command_not_understood (p_bcb, *p);
    +-
    +-                new_len += (length + 2);
      
     +                new_len = (length + 2);
    -+                if (new_len > org_len) break;
    +                 if (new_len > org_len)
    ++                {
    ++                    android_errorWriteLog(0x534e4554, "67863755");
    +                     break;
    ++                }
     +
    -                 if ((!(ext & 0x7F)) && (*p > BNEP_FILTER_MULTI_ADDR_RESPONSE_MSG))
    -                     bnep_send_command_not_understood (p_bcb, *p);
    ++                if ((ext & 0x7F) == BNEP_EXTENSION_FILTER_CONTROL)
    ++                {
    ++                    if (length == 0)
    ++                    {
    ++                        android_errorWriteLog(0x534e4554, "79164722");
    ++                        break;
    ++                    }
    ++                    if (*p > BNEP_FILTER_MULTI_ADDR_RESPONSE_MSG)
    ++                    {
    ++                        bnep_send_command_not_understood(p_bcb, *p);
    ++                    }
    ++                }
      
    --                new_len += (length + 2);
    --
    --                if (new_len > org_len)
    --                    break;
    --
    ++                p += length;
    ++
     +                org_len -= new_len;
                  } while (ext & 0x80);
    -+            android_errorWriteLog(0x534e4554, "67863755");
              }
    - 
    +-
              osi_free(p_buf);
    -@@ -575,7 +582,8 @@ static void bnep_data_ind (UINT16 l2cap_cid, BT_HDR *p_buf)
    +         return;
    +     }
    +@@ -575,7 +604,8 @@ static void bnep_data_ind (UINT16 l2cap_cid, BT_HDR *p_buf)
                  p_bcb->con_state != BNEP_STATE_CONNECTED &&
                  extension_present && p && rem_len)
              {
    @@ -647,15 +953,23 @@ index 078a72ebd..8edb712ac 100644
                  memcpy((UINT8 *)(p_bcb->p_pending_data + 1), p, rem_len);
                  p_bcb->p_pending_data->len    = rem_len;
                  p_bcb->p_pending_data->offset = 0;
    -@@ -585,6 +593,8 @@ static void bnep_data_ind (UINT16 l2cap_cid, BT_HDR *p_buf)
    +@@ -585,13 +615,15 @@ static void bnep_data_ind (UINT16 l2cap_cid, BT_HDR *p_buf)
                  while (extension_present && p && rem_len)
                  {
                      ext_type = *p++;
     +                rem_len--;
    -+                android_errorWriteLog(0x534e4554, "69271284");
                      extension_present = ext_type >> 7;
                      ext_type &= 0x7F;
      
    +                 /* if unknown extension present stop processing */
    +-                if (ext_type)
    ++                if (ext_type != BNEP_EXTENSION_FILTER_CONTROL)
    +                     break;
    + 
    ++                android_errorWriteLog(0x534e4554, "69271284");
    +                 p = bnep_process_control_packet (p_bcb, p, &rem_len, TRUE);
    +             }
    +         }
     diff --git a/stack/bnep/bnep_utils.c b/stack/bnep/bnep_utils.c
     index 13fb189e7..65acd33f6 100644
     --- a/stack/bnep/bnep_utils.c
    @@ -868,6 +1182,71 @@ index 13fb189e7..65acd33f6 100644
      }
      
      
    +diff --git a/stack/btm/btm_acl.c b/stack/btm/btm_acl.c
    +index 4819012b8..5a1d9fdbb 100644
    +--- a/stack/btm/btm_acl.c
    ++++ b/stack/btm/btm_acl.c
    +@@ -899,6 +899,7 @@ void BTM_SetDefaultLinkPolicy (UINT16 settings)
    + }
    + 
    + 
    ++#if (defined(BLE_INCLUDED) && (BLE_INCLUDED == TRUE))
    + void btm_use_preferred_conn_params(BD_ADDR bda) {
    +     tL2C_LCB *p_lcb = l2cu_find_lcb_by_bd_addr (bda, BT_TRANSPORT_LE);
    +     tBTM_SEC_DEV_REC    *p_dev_rec = btm_find_or_alloc_dev (bda);
    +@@ -934,6 +935,7 @@ void btm_use_preferred_conn_params(BD_ADDR bda) {
    +                                            0, 0);
    +     }
    + }
    ++#endif
    + 
    + /*******************************************************************************
    + **
    +diff --git a/stack/btm/btm_dev.c b/stack/btm/btm_dev.c
    +index 8df005bf8..b278dea8f 100644
    +--- a/stack/btm/btm_dev.c
    ++++ b/stack/btm/btm_dev.c
    +@@ -157,17 +157,16 @@ BOOLEAN BTM_SecAddDevice (BD_ADDR bd_addr, DEV_CLASS dev_class, BD_NAME bd_name,
    + }
    + 
    + 
    +-/*******************************************************************************
    +-**
    +-** Function         BTM_SecDeleteDevice
    +-**
    +-** Description      Free resources associated with the device.
    +-**
    +-** Parameters:      bd_addr          - BD address of the peer
    +-**
    +-** Returns          TRUE if removed OK, FALSE if not found or ACL link is active
    +-**
    +-*******************************************************************************/
    ++/** Free resources associated with the device associated with |bd_addr| address.
    ++ *
    ++ * *** WARNING ***
    ++ * tBTM_SEC_DEV_REC associated with bd_addr becomes invalid after this function
    ++ * is called, also any of it's fields. i.e. if you use p_dev_rec->bd_addr, it is
    ++ * no longer valid!
    ++ * *** WARNING ***
    ++ *
    ++ * Returns true if removed OK, false if not found or ACL link is active.
    ++ */
    + BOOLEAN BTM_SecDeleteDevice (BD_ADDR bd_addr)
    + {
    +     if (BTM_IsAclConnectionUp(bd_addr, BT_TRANSPORT_LE) ||
    +@@ -180,9 +179,11 @@ BOOLEAN BTM_SecDeleteDevice (BD_ADDR bd_addr)
    +     tBTM_SEC_DEV_REC *p_dev_rec = btm_find_dev(bd_addr);
    +     if (p_dev_rec != NULL)
    +     {
    ++        BD_ADDR bda;
    ++        memcpy(bda, bd_addr, BD_ADDR_LEN);
    +         btm_sec_free_dev(p_dev_rec);
    +         /* Tell controller to get rid of the link key, if it has one stored */
    +-        BTM_DeleteStoredLinkKey (p_dev_rec->bd_addr, NULL);
    ++        BTM_DeleteStoredLinkKey(bda, NULL);
    +     }
    + 
    +     return TRUE;
     diff --git a/stack/btu/btu_init.c b/stack/btu/btu_init.c
     index 688ed889d..9f9ed0a50 100644
     --- a/stack/btu/btu_init.c
    @@ -881,6 +1260,96 @@ index 688ed889d..9f9ed0a50 100644
      #if BLE_INCLUDED == TRUE
            gatt_free();
      #endif
    +diff --git a/stack/gap/gap_conn.c b/stack/gap/gap_conn.c
    +index 1ee2c97b4..72861c3d7 100644
    +--- a/stack/gap/gap_conn.c
    ++++ b/stack/gap/gap_conn.c
    +@@ -203,6 +203,7 @@ UINT16 GAP_ConnOpen (char *p_serv_name, UINT8 service_id, BOOLEAN is_server,
    +         }
    +     }
    + 
    ++#if BLE_INCLUDED == TRUE
    +     if (transport == BT_TRANSPORT_LE)
    +     {
    +         p_ccb->psm = L2CA_REGISTER_COC (psm, &gap_cb.conn.reg_info,
    +@@ -215,6 +216,7 @@ UINT16 GAP_ConnOpen (char *p_serv_name, UINT8 service_id, BOOLEAN is_server,
    +         }
    +     }
    + 
    ++#endif
    +     /* Register with Security Manager for the specific security level */
    +     p_ccb->service_id = service_id;
    +     if (!BTM_SetSecurityLevel ((UINT8)!is_server, p_serv_name,
    +@@ -274,6 +276,7 @@ UINT16 GAP_ConnOpen (char *p_serv_name, UINT8 service_id, BOOLEAN is_server,
    +             }
    +         }
    + 
    ++#if BLE_INCLUDED == TRUE
    +         if (p_rem_bda && (transport == BT_TRANSPORT_LE))
    +         {
    +             cid = L2CA_CONNECT_COC_REQ (p_ccb->psm, p_rem_bda, &p_ccb->local_coc_cfg);
    +@@ -283,6 +286,7 @@ UINT16 GAP_ConnOpen (char *p_serv_name, UINT8 service_id, BOOLEAN is_server,
    +                 return (p_ccb->gap_handle);
    +             }
    +         }
    ++#endif
    + 
    +         gap_release_ccb (p_ccb);
    +         return (GAP_INVALID_HANDLE);
    +@@ -1229,8 +1233,10 @@ static void gap_release_ccb (tGAP_CCB *p_ccb)
    +     if (p_ccb->transport == BT_TRANSPORT_BR_EDR)
    +         L2CA_DEREGISTER (psm);
    + 
    ++#if BLE_INCLUDED == TRUE
    +     if(p_ccb->transport == BT_TRANSPORT_LE)
    +         L2CA_DEREGISTER_COC (psm);
    ++#endif
    + }
    + 
    + #if (GAP_CONN_POST_EVT_INCLUDED == TRUE)
    +diff --git a/stack/gatt/gatt_cl.c b/stack/gatt/gatt_cl.c
    +index 433a2f1dc..6a50d5e21 100644
    +--- a/stack/gatt/gatt_cl.c
    ++++ b/stack/gatt/gatt_cl.c
    +@@ -31,6 +31,7 @@
    + #include "bt_common.h"
    + #include "gatt_int.h"
    + #include "l2c_int.h"
    ++#include "osi/include/log.h"
    + 
    + #define GATT_WRITE_LONG_HDR_SIZE    5 /* 1 opcode + 2 handle + 2 offset */
    + #define GATT_READ_CHAR_VALUE_HDL    (GATT_READ_CHAR_VALUE | 0x80)
    +@@ -566,9 +567,27 @@ void gatt_process_error_rsp(tGATT_TCB *p_tcb, tGATT_CLCB *p_clcb, UINT8 op_code,
    +     UNUSED(len);
    + 
    +     GATT_TRACE_DEBUG("gatt_process_error_rsp ");
    +-    STREAM_TO_UINT8(opcode, p);
    +-    STREAM_TO_UINT16(handle, p);
    +-    STREAM_TO_UINT8(reason, p);
    ++
    ++    if (len < 4)
    ++    {
    ++        android_errorWriteLog(0x534e4554, "79591688");
    ++        GATT_TRACE_ERROR("Error response too short");
    ++        // Specification does not clearly define what should happen if error
    ++        // response is too short. General rule in BT Spec 5.0 Vol 3, Part F 3.4.1.1
    ++        // is: "If an error code is received in the Error Response that is not
    ++        // understood by the client, for example an error code that was reserved for
    ++        // future use that is now being used in a future version of this
    ++        // specification, then the Error Response shall still be considered to state
    ++        // that the given request cannot be performed for an unknown reason."
    ++        opcode = handle = 0;
    ++        reason = 0x7F;
    ++    }
    ++    else
    ++    {
    ++        STREAM_TO_UINT8(opcode, p);
    ++        STREAM_TO_UINT16(handle, p);
    ++        STREAM_TO_UINT8(reason, p);
    ++    }
    + 
    +     if (p_clcb->operation == GATTC_OPTYPE_DISCOVERY)
    +     {
     diff --git a/stack/gatt/gatt_sr.c b/stack/gatt/gatt_sr.c
     index 11ef79c83..c2cdb885d 100644
     --- a/stack/gatt/gatt_sr.c
    @@ -922,6 +1391,63 @@ index 11ef79c83..c2cdb885d 100644
          UNUSED(len);
      
          if (op_code == GATT_REQ_READ_BLOB)
    +diff --git a/stack/hid/hidh_conn.c b/stack/hid/hidh_conn.c
    +index ffbafe428..0e6a05d76 100644
    +--- a/stack/hid/hidh_conn.c
    ++++ b/stack/hid/hidh_conn.c
    +@@ -43,6 +43,7 @@
    + #include "hidh_int.h"
    + #include "bt_utils.h"
    + 
    ++#include "log/log.h"
    + #include "osi/include/osi.h"
    + 
    + 
    +@@ -820,6 +821,14 @@ static void hidh_l2cif_data_ind (UINT16 l2cap_cid, BT_HDR *p_msg)
    +         return;
    +     }
    + 
    ++    if (p_msg->len < 1)
    ++    {
    ++        HIDH_TRACE_WARNING("Rcvd L2CAP data, invalid length %d, should be >= 1",
    ++                           p_msg->len);
    ++        osi_free(p_msg);
    ++        android_errorWriteLog(0x534e4554, "80493272");
    ++        return;
    ++    }
    + 
    +     ttype    = HID_GET_TRANS_FROM_HDR(*p_data);
    +     param    = HID_GET_PARAM_FROM_HDR(*p_data);
    +diff --git a/stack/include/btm_api.h b/stack/include/btm_api.h
    +index 451cd6ff7..360dd48b2 100644
    +--- a/stack/include/btm_api.h
    ++++ b/stack/include/btm_api.h
    +@@ -3313,15 +3313,16 @@ extern BOOLEAN BTM_SecAddDevice (BD_ADDR bd_addr, DEV_CLASS dev_class,
    +                                  UINT8 key_type, tBTM_IO_CAP io_cap, UINT8 pin_length);
    + 
    + 
    +-/*******************************************************************************
    +-**
    +-** Function         BTM_SecDeleteDevice
    +-**
    +-** Description      Free resources associated with the device.
    +-**
    +-** Returns          TRUE if rmoved OK, FALSE if not found
    +-**
    +-*******************************************************************************/
    ++/** Free resources associated with the device associated with |bd_addr| address.
    ++ *
    ++ * *** WARNING ***
    ++ * tBTM_SEC_DEV_REC associated with bd_addr becomes invalid after this function
    ++ * is called, also any of it's fields. i.e. if you use p_dev_rec->bd_addr, it is
    ++ * no longer valid!
    ++ * *** WARNING ***
    ++ *
    ++ * Returns true if removed OK, false if not found or ACL link is active.
    ++ */
    + extern BOOLEAN BTM_SecDeleteDevice (BD_ADDR bd_addr);
    + 
    + /*******************************************************************************
     diff --git a/stack/include/rfcdefs.h b/stack/include/rfcdefs.h
     index dcc37bc72..1c751f3f5 100644
     --- a/stack/include/rfcdefs.h
    @@ -940,8 +1466,28 @@ index dcc37bc72..1c751f3f5 100644
      #define RFCOMM_FRAME_IS_CMD(initiator, cr)                  \
          (( (initiator) && !(cr)) || (!(initiator) &&  (cr)))
      
    +diff --git a/stack/l2cap/l2c_api.c b/stack/l2cap/l2c_api.c
    +index 62012c675..e4116a791 100644
    +--- a/stack/l2cap/l2c_api.c
    ++++ b/stack/l2cap/l2c_api.c
    +@@ -332,6 +332,7 @@ UINT16 L2CA_ErtmConnectReq (UINT16 psm, BD_ADDR p_bd_addr, tL2CAP_ERTM_INFO *p_e
    +     return (p_ccb->local_cid);
    + }
    + 
    ++#if (BLE_INCLUDED == TRUE)
    + /*******************************************************************************
    + **
    + ** Function         L2CA_RegisterLECoc
    +@@ -544,6 +545,7 @@ UINT16 L2CA_ConnectLECocReq(UINT16 psm, BD_ADDR p_bd_addr, tL2CAP_LE_CFG_INFO *p
    +     /* Return the local CID as our handle */
    +     return p_ccb->local_cid;
    + }
    ++#endif
    + 
    + /*******************************************************************************
    + **
     diff --git a/stack/l2cap/l2c_ble.c b/stack/l2cap/l2c_ble.c
    -index 95de4e34c..b2f196c3c 100644
    +index 95de4e34c..f5072e364 100644
     --- a/stack/l2cap/l2c_ble.c
     +++ b/stack/l2cap/l2c_ble.c
     @@ -31,6 +31,7 @@
    @@ -952,7 +1498,77 @@ index 95de4e34c..b2f196c3c 100644
      #include "stack_config.h"
      #include "btif_debug_l2c.h"
      
    -@@ -808,6 +809,11 @@ void l2cble_process_sig_cmd (tL2C_LCB *p_lcb, UINT8 *p, UINT16 pkt_len)
    +@@ -608,6 +609,13 @@ void l2cble_process_sig_cmd (tL2C_LCB *p_lcb, UINT8 *p, UINT16 pkt_len)
    +     UINT16          credit;
    +     p_pkt_end = p + pkt_len;
    + 
    ++    if (p + 4 > p_pkt_end)
    ++    {
    ++        android_errorWriteLog(0x534e4554, "80261585");
    ++        L2CAP_TRACE_ERROR("invalid read");
    ++        return;
    ++    }
    ++
    +     STREAM_TO_UINT8  (cmd_code, p);
    +     STREAM_TO_UINT8  (id, p);
    +     STREAM_TO_UINT16 (cmd_len, p);
    +@@ -633,6 +641,13 @@ void l2cble_process_sig_cmd (tL2C_LCB *p_lcb, UINT8 *p, UINT16 pkt_len)
    +             break;
    + 
    +         case L2CAP_CMD_BLE_UPDATE_REQ:
    ++            if (p + 8 > p_pkt_end)
    ++            {
    ++                android_errorWriteLog(0x534e4554, "80261585");
    ++                L2CAP_TRACE_ERROR("invalid read");
    ++                return;
    ++            }
    ++
    +             STREAM_TO_UINT16 (min_interval, p); /* 0x0006 - 0x0C80 */
    +             STREAM_TO_UINT16 (max_interval, p); /* 0x0006 - 0x0C80 */
    +             STREAM_TO_UINT16 (latency, p);  /* 0x0000 - 0x03E8 */
    +@@ -675,6 +690,13 @@ void l2cble_process_sig_cmd (tL2C_LCB *p_lcb, UINT8 *p, UINT16 pkt_len)
    +             break;
    + 
    +         case L2CAP_CMD_BLE_CREDIT_BASED_CONN_REQ:
    ++            if (p + 10 > p_pkt_end)
    ++            {
    ++                android_errorWriteLog(0x534e4554, "80261585");
    ++                L2CAP_TRACE_ERROR("invalid read");
    ++                return;
    ++            }
    ++
    +             STREAM_TO_UINT16 (con_info.psm, p);
    +             STREAM_TO_UINT16 (rcid, p);
    +             STREAM_TO_UINT16 (mtu, p);
    +@@ -749,6 +771,13 @@ void l2cble_process_sig_cmd (tL2C_LCB *p_lcb, UINT8 *p, UINT16 pkt_len)
    +             if (p_ccb)
    +             {
    +                 L2CAP_TRACE_DEBUG ("I remember the connection req");
    ++                if (p + 10 > p_pkt_end)
    ++                {
    ++                    android_errorWriteLog(0x534e4554, "80261585");
    ++                    L2CAP_TRACE_ERROR("invalid read");
    ++                    return;
    ++                }
    ++
    +                 STREAM_TO_UINT16 (p_ccb->remote_cid, p);
    +                 STREAM_TO_UINT16 (p_ccb->peer_conn_cfg.mtu, p);
    +                 STREAM_TO_UINT16 (p_ccb->peer_conn_cfg.mps, p);
    +@@ -795,6 +824,13 @@ void l2cble_process_sig_cmd (tL2C_LCB *p_lcb, UINT8 *p, UINT16 pkt_len)
    +             break;
    + 
    +         case L2CAP_CMD_BLE_FLOW_CTRL_CREDIT:
    ++            if (p + 4 > p_pkt_end)
    ++            {
    ++                android_errorWriteLog(0x534e4554, "80261585");
    ++                L2CAP_TRACE_ERROR("invalid read");
    ++                return;
    ++            }
    ++
    +             STREAM_TO_UINT16(lcid, p);
    +             if((p_ccb = l2cu_find_ccb_by_remote_cid(p_lcb, lcid)) == NULL)
    +             {
    +@@ -808,6 +844,11 @@ void l2cble_process_sig_cmd (tL2C_LCB *p_lcb, UINT8 *p, UINT16 pkt_len)
                  break;
      
              case L2CAP_CMD_DISC_REQ:
    @@ -964,8 +1580,176 @@ index 95de4e34c..b2f196c3c 100644
                  STREAM_TO_UINT16 (lcid, p);
                  STREAM_TO_UINT16 (rcid, p);
      
    +@@ -825,6 +866,12 @@ void l2cble_process_sig_cmd (tL2C_LCB *p_lcb, UINT8 *p, UINT16 pkt_len)
    +             break;
    + 
    +          case L2CAP_CMD_DISC_RSP:
    ++            if (p + 4 > p_pkt_end)
    ++            {
    ++                android_errorWriteLog(0x534e4554, "80261585");
    ++                L2CAP_TRACE_ERROR("invalid read");
    ++                return;
    ++            }
    +             STREAM_TO_UINT16 (rcid, p);
    +             STREAM_TO_UINT16 (lcid, p);
    + 
    +diff --git a/stack/l2cap/l2c_csm.c b/stack/l2cap/l2c_csm.c
    +index dedffc8a5..67bdc4049 100644
    +--- a/stack/l2cap/l2c_csm.c
    ++++ b/stack/l2cap/l2c_csm.c
    +@@ -169,6 +169,7 @@ static void l2c_csm_closed (tL2C_CCB *p_ccb, UINT16 event, void *p_data)
    +         break;
    + 
    +     case L2CEVT_LP_CONNECT_CFM:                         /* Link came up         */
    ++#if (BLE_INCLUDED == TRUE)
    +         if (p_ccb->p_lcb->transport == BT_TRANSPORT_LE)
    +         {
    +             p_ccb->chnl_state = CST_ORIG_W4_SEC_COMP;
    +@@ -176,6 +177,7 @@ static void l2c_csm_closed (tL2C_CCB *p_ccb, UINT16 event, void *p_data)
    +                     &l2c_link_sec_comp, p_ccb);
    +         }
    +         else
    ++#endif
    +         {
    +             p_ccb->chnl_state = CST_ORIG_W4_SEC_COMP;
    +             btm_sec_l2cap_access_req (p_ccb->p_lcb->remote_bd_addr, p_ccb->p_rcb->psm,
    +@@ -195,6 +197,7 @@ static void l2c_csm_closed (tL2C_CCB *p_ccb, UINT16 event, void *p_data)
    +         break;
    + 
    +     case L2CEVT_L2CA_CONNECT_REQ:                       /* API connect request  */
    ++#if (BLE_INCLUDED == TRUE)
    +         if (p_ccb->p_lcb->transport == BT_TRANSPORT_LE)
    +         {
    +             p_ccb->chnl_state = CST_ORIG_W4_SEC_COMP;
    +@@ -202,6 +205,7 @@ static void l2c_csm_closed (tL2C_CCB *p_ccb, UINT16 event, void *p_data)
    +                     &l2c_link_sec_comp, p_ccb);
    +         }
    +         else
    ++#endif
    +         {
    +             /* Cancel sniff mode if needed */
    +             {
    +@@ -258,6 +262,7 @@ Event uninit_use_in_call: Using uninitialized value "settings.min" in call to fu
    +         /* stop link timer to avoid race condition between A2MP, Security, and L2CAP */
    +         alarm_cancel(p_ccb->p_lcb->l2c_lcb_timer);
    + 
    ++#if (BLE_INCLUDED == TRUE)
    +         if (p_ccb->p_lcb->transport == BT_TRANSPORT_LE)
    +         {
    +             p_ccb->chnl_state = CST_TERM_W4_SEC_COMP;
    +@@ -265,6 +270,7 @@ Event uninit_use_in_call: Using uninitialized value "settings.min" in call to fu
    +                     &l2c_link_sec_comp, p_ccb);
    +         }
    +         else
    ++#endif
    +         {
    +             /* Cancel sniff mode if needed */
    +             {
    +@@ -358,12 +364,14 @@ static void l2c_csm_orig_w4_sec_comp (tL2C_CCB *p_ccb, UINT16 event, void *p_dat
    + 
    +     case L2CEVT_SEC_RE_SEND_CMD:                    /* BTM has enough info to proceed */
    +     case L2CEVT_LP_CONNECT_CFM:                     /* Link came up         */
    ++#if (BLE_INCLUDED == TRUE)
    +         if (p_ccb->p_lcb->transport == BT_TRANSPORT_LE)
    +         {
    +              l2ble_sec_access_req(p_ccb->p_lcb->remote_bd_addr, p_ccb->p_rcb->psm, FALSE,
    +                     &l2c_link_sec_comp, p_ccb);
    +         }
    +         else
    ++#endif
    +         {
    +             btm_sec_l2cap_access_req (p_ccb->p_lcb->remote_bd_addr, p_ccb->p_rcb->psm,
    +                                   p_ccb->p_lcb->handle, TRUE, &l2c_link_sec_comp, p_ccb);
    +@@ -373,6 +381,7 @@ static void l2c_csm_orig_w4_sec_comp (tL2C_CCB *p_ccb, UINT16 event, void *p_dat
    +     case L2CEVT_SEC_COMP:                            /* Security completed success */
    +         /* Wait for the info resp in this state before sending connect req (if needed) */
    +         p_ccb->chnl_state = CST_W4_L2CAP_CONNECT_RSP;
    ++#if (BLE_INCLUDED == TRUE)
    +         if (p_ccb->p_lcb->transport == BT_TRANSPORT_LE)
    +         {
    +             alarm_set_on_queue(p_ccb->l2c_ccb_timer,
    +@@ -382,6 +391,7 @@ static void l2c_csm_orig_w4_sec_comp (tL2C_CCB *p_ccb, UINT16 event, void *p_dat
    +             l2cble_credit_based_conn_req (p_ccb);          /* Start Connection     */
    +         }
    +         else
    ++#endif
    +         {
    +             if (!p_ccb->p_lcb->w4_info_rsp)
    +             {
    +@@ -514,9 +524,11 @@ static void l2c_csm_term_w4_sec_comp (tL2C_CCB *p_ccb, UINT16 event, void *p_dat
    +         }
    +         else
    +         {
    ++#if (BLE_INCLUDED == TRUE)
    +             if (p_ccb->p_lcb->transport == BT_TRANSPORT_LE)
    +                 l2cu_reject_ble_connection(p_ccb->p_lcb, p_ccb->remote_id, L2CAP_LE_INSUFFICIENT_AUTHENTICATION);
    +             else
    ++#endif
    +                 l2cu_send_peer_connect_rsp (p_ccb, L2CAP_CONN_SECURITY_BLOCK, 0);
    +             l2cu_release_ccb (p_ccb);
    +         }
    +@@ -721,6 +733,7 @@ static void l2c_csm_w4_l2ca_connect_rsp (tL2C_CCB *p_ccb, UINT16 event, void *p_
    + 
    +     case L2CEVT_L2CA_CONNECT_RSP:
    +         p_ci = (tL2C_CONN_INFO *)p_data;
    ++#if (BLE_INCLUDED == TRUE)
    +         if (p_ccb->p_lcb->transport == BT_TRANSPORT_LE)
    +         {
    +             /* Result should be OK or Reject */
    +@@ -737,6 +750,7 @@ static void l2c_csm_w4_l2ca_connect_rsp (tL2C_CCB *p_ccb, UINT16 event, void *p_
    +             }
    +         }
    +         else
    ++#endif
    +         {
    +             /* Result should be OK or PENDING */
    +             if ((!p_ci) || (p_ci->l2cap_result == L2CAP_CONN_OK))
    +@@ -762,9 +776,11 @@ static void l2c_csm_w4_l2ca_connect_rsp (tL2C_CCB *p_ccb, UINT16 event, void *p_
    + 
    +     case L2CEVT_L2CA_CONNECT_RSP_NEG:
    +         p_ci = (tL2C_CONN_INFO *)p_data;
    ++#if (BLE_INCLUDED == TRUE)
    +         if (p_ccb->p_lcb->transport == BT_TRANSPORT_LE)
    +             l2cble_credit_based_conn_res (p_ccb, p_ci->l2cap_result);
    +         else
    ++#endif
    +             l2cu_send_peer_connect_rsp (p_ccb, p_ci->l2cap_result, p_ci->l2cap_status);
    +         l2cu_release_ccb (p_ccb);
    +         break;
    +@@ -1185,9 +1201,11 @@ static void l2c_csm_open (tL2C_CCB *p_ccb, UINT16 event, void *p_data)
    +             }
    +         }
    + 
    ++#if (BLE_INCLUDED == TRUE)
    +         if (p_ccb->p_lcb->transport == BT_TRANSPORT_LE)
    +             l2cble_send_peer_disc_req (p_ccb);
    +         else
    ++#endif
    +             l2cu_send_peer_disc_req (p_ccb);
    + 
    +         p_ccb->chnl_state = CST_W4_L2CAP_DISCONNECT_RSP;
    +@@ -1226,7 +1244,9 @@ static void l2c_csm_open (tL2C_CCB *p_ccb, UINT16 event, void *p_data)
    +     case L2CEVT_L2CA_SEND_FLOW_CONTROL_CREDIT:
    +         L2CAP_TRACE_DEBUG("%s Sending credit",__func__);
    +         credit = (UINT16*)p_data;
    ++#if (BLE_INCLUDED == TRUE)
    +         l2cble_send_flow_control_credit(p_ccb, *credit);
    ++#endif
    +         break;
    + 
    +     case L2CEVT_L2CAP_RECV_FLOW_CONTROL_CREDIT:
    +@@ -1237,7 +1257,9 @@ static void l2c_csm_open (tL2C_CCB *p_ccb, UINT16 event, void *p_data)
    +             /* we have received credits more than max coc credits,
    +              * so disconnecting the Le Coc Channel
    +              */
    ++#if (BLE_INCLUDED == TRUE)
    +             l2cble_send_peer_disc_req (p_ccb);
    ++#endif
    +         }
    +         else
    +         {
     diff --git a/stack/l2cap/l2c_fcr.c b/stack/l2cap/l2c_fcr.c
    -index 5ba8b5619..282b1716f 100644
    +index 5ba8b5619..b6a715762 100644
     --- a/stack/l2cap/l2c_fcr.c
     +++ b/stack/l2cap/l2c_fcr.c
     @@ -24,6 +24,7 @@
    @@ -976,7 +1760,22 @@ index 5ba8b5619..282b1716f 100644
      #include <stdio.h>
      #include <stdlib.h>
      #include <string.h>
    -@@ -865,7 +866,24 @@ void l2c_lcc_proc_pdu(tL2C_CCB *p_ccb, BT_HDR *p_buf)
    +@@ -848,6 +849,14 @@ void l2c_lcc_proc_pdu(tL2C_CCB *p_ccb, BT_HDR *p_buf)
    +             return;
    +         }
    + 
    ++	if (sdu_length < p_buf->len) {
    ++		L2CAP_TRACE_ERROR("%s: Invalid sdu_length: %d", __func__, sdu_length);
    ++		android_errorWriteWithInfoLog(0x534e4554, "112321180", -1, NULL, 0);
    ++		/* Discard the buffer */
    ++		osi_free(p_buf);
    ++		return;
    ++	}
    ++
    + 
    +         if ((p_data = (BT_HDR *) osi_malloc(L2CAP_MAX_BUF_SIZE)) == NULL)
    +         {
    +@@ -865,7 +874,24 @@ void l2c_lcc_proc_pdu(tL2C_CCB *p_ccb, BT_HDR *p_buf)
      
          }
          else
    @@ -1001,7 +1800,7 @@ index 5ba8b5619..282b1716f 100644
      
          memcpy((UINT8*)(p_data + 1) + p_data->offset + p_data->len, (UINT8*)(p_buf + 1) + p_buf->offset, p_buf->len);
          p_data->len += p_buf->len;
    -@@ -881,11 +899,6 @@ void l2c_lcc_proc_pdu(tL2C_CCB *p_ccb, BT_HDR *p_buf)
    +@@ -881,11 +907,6 @@ void l2c_lcc_proc_pdu(tL2C_CCB *p_ccb, BT_HDR *p_buf)
          {
              p_ccb->is_first_seg = FALSE;
          }
    @@ -1014,7 +1813,7 @@ index 5ba8b5619..282b1716f 100644
          osi_free(p_buf);
          return;
     diff --git a/stack/l2cap/l2c_main.c b/stack/l2cap/l2c_main.c
    -index 3c48d6974..cef488cb9 100644
    +index 3c48d6974..5eced537a 100644
     --- a/stack/l2cap/l2c_main.c
     +++ b/stack/l2cap/l2c_main.c
     @@ -339,9 +339,17 @@ static void process_l2cap_cmd (tL2C_LCB *p_lcb, UINT8 *p, UINT16 pkt_len)
    @@ -1150,7 +1949,19 @@ index 3c48d6974..cef488cb9 100644
                          STREAM_TO_UINT8  (cfg_info.ext_flow_spec.id, p);
                          STREAM_TO_UINT8  (cfg_info.ext_flow_spec.stype, p);
                          STREAM_TO_UINT16 (cfg_info.ext_flow_spec.max_sdu_size, p);
    -@@ -548,6 +600,10 @@ static void process_l2cap_cmd (tL2C_LCB *p_lcb, UINT8 *p, UINT16 pkt_len)
    +@@ -510,6 +562,11 @@ static void process_l2cap_cmd (tL2C_LCB *p_lcb, UINT8 *p, UINT16 pkt_len)
    +                     /* sanity check option length */
    +                     if ((cfg_len + L2CAP_CFG_OPTION_OVERHEAD) <= cmd_len)
    +                     {
    ++                        if (p + cfg_len > p_next_cmd)
    ++                        {
    ++                            android_errorWriteLog(0x534e4554, "79488381");
    ++                            return;
    ++                        }
    +                         p += cfg_len;
    +                         if ((cfg_code & 0x80) == 0)
    +                         {
    +@@ -548,6 +605,10 @@ static void process_l2cap_cmd (tL2C_LCB *p_lcb, UINT8 *p, UINT16 pkt_len)
      
              case L2CAP_CMD_CONFIG_RSP:
                  p_cfg_end = p + cmd_len;
    @@ -1161,7 +1972,7 @@ index 3c48d6974..cef488cb9 100644
                  STREAM_TO_UINT16 (lcid, p);
                  STREAM_TO_UINT16 (cfg_info.flags, p);
                  STREAM_TO_UINT16 (cfg_info.result, p);
    -@@ -557,6 +613,10 @@ static void process_l2cap_cmd (tL2C_LCB *p_lcb, UINT8 *p, UINT16 pkt_len)
    +@@ -557,6 +618,10 @@ static void process_l2cap_cmd (tL2C_LCB *p_lcb, UINT8 *p, UINT16 pkt_len)
      
                  while (p < p_cfg_end)
                  {
    @@ -1172,7 +1983,7 @@ index 3c48d6974..cef488cb9 100644
                      STREAM_TO_UINT8 (cfg_code, p);
                      STREAM_TO_UINT8 (cfg_len, p);
      
    -@@ -564,16 +624,28 @@ static void process_l2cap_cmd (tL2C_LCB *p_lcb, UINT8 *p, UINT16 pkt_len)
    +@@ -564,16 +629,28 @@ static void process_l2cap_cmd (tL2C_LCB *p_lcb, UINT8 *p, UINT16 pkt_len)
                      {
                      case L2CAP_CFG_TYPE_MTU:
                          cfg_info.mtu_present = TRUE;
    @@ -1201,7 +2012,7 @@ index 3c48d6974..cef488cb9 100644
                          STREAM_TO_UINT8  (cfg_info.qos.qos_flags, p);
                          STREAM_TO_UINT8  (cfg_info.qos.service_type, p);
                          STREAM_TO_UINT32 (cfg_info.qos.token_rate, p);
    -@@ -585,6 +657,10 @@ static void process_l2cap_cmd (tL2C_LCB *p_lcb, UINT8 *p, UINT16 pkt_len)
    +@@ -585,6 +662,10 @@ static void process_l2cap_cmd (tL2C_LCB *p_lcb, UINT8 *p, UINT16 pkt_len)
      
                      case L2CAP_CFG_TYPE_FCR:
                          cfg_info.fcr_present = TRUE;
    @@ -1212,7 +2023,7 @@ index 3c48d6974..cef488cb9 100644
                          STREAM_TO_UINT8 (cfg_info.fcr.mode, p);
                          STREAM_TO_UINT8 (cfg_info.fcr.tx_win_sz, p);
                          STREAM_TO_UINT8 (cfg_info.fcr.max_transmit, p);
    -@@ -595,11 +671,19 @@ static void process_l2cap_cmd (tL2C_LCB *p_lcb, UINT8 *p, UINT16 pkt_len)
    +@@ -595,11 +676,19 @@ static void process_l2cap_cmd (tL2C_LCB *p_lcb, UINT8 *p, UINT16 pkt_len)
      
                      case L2CAP_CFG_TYPE_FCS:
                          cfg_info.fcs_present = TRUE;
    @@ -1232,7 +2043,7 @@ index 3c48d6974..cef488cb9 100644
                          STREAM_TO_UINT8  (cfg_info.ext_flow_spec.id, p);
                          STREAM_TO_UINT8  (cfg_info.ext_flow_spec.stype, p);
                          STREAM_TO_UINT16 (cfg_info.ext_flow_spec.max_sdu_size, p);
    -@@ -630,6 +714,10 @@ static void process_l2cap_cmd (tL2C_LCB *p_lcb, UINT8 *p, UINT16 pkt_len)
    +@@ -630,6 +719,10 @@ static void process_l2cap_cmd (tL2C_LCB *p_lcb, UINT8 *p, UINT16 pkt_len)
                  break;
      
              case L2CAP_CMD_DISC_REQ:
    @@ -1243,7 +2054,7 @@ index 3c48d6974..cef488cb9 100644
                  STREAM_TO_UINT16 (lcid, p);
                  STREAM_TO_UINT16 (rcid, p);
      
    -@@ -647,6 +735,10 @@ static void process_l2cap_cmd (tL2C_LCB *p_lcb, UINT8 *p, UINT16 pkt_len)
    +@@ -647,6 +740,10 @@ static void process_l2cap_cmd (tL2C_LCB *p_lcb, UINT8 *p, UINT16 pkt_len)
                  break;
      
              case L2CAP_CMD_DISC_RSP:
    @@ -1254,7 +2065,7 @@ index 3c48d6974..cef488cb9 100644
                  STREAM_TO_UINT16 (rcid, p);
                  STREAM_TO_UINT16 (lcid, p);
      
    -@@ -676,6 +768,10 @@ static void process_l2cap_cmd (tL2C_LCB *p_lcb, UINT8 *p, UINT16 pkt_len)
    +@@ -676,6 +773,10 @@ static void process_l2cap_cmd (tL2C_LCB *p_lcb, UINT8 *p, UINT16 pkt_len)
                  break;
      
              case L2CAP_CMD_INFO_REQ:
    @@ -1265,7 +2076,7 @@ index 3c48d6974..cef488cb9 100644
                  STREAM_TO_UINT16 (info_type, p);
                  l2cu_send_peer_info_rsp (p_lcb, id, info_type);
                  break;
    -@@ -688,6 +784,10 @@ static void process_l2cap_cmd (tL2C_LCB *p_lcb, UINT8 *p, UINT16 pkt_len)
    +@@ -688,6 +789,10 @@ static void process_l2cap_cmd (tL2C_LCB *p_lcb, UINT8 *p, UINT16 pkt_len)
                      p_lcb->w4_info_rsp = FALSE;
                  }
      
    @@ -1276,7 +2087,7 @@ index 3c48d6974..cef488cb9 100644
                  STREAM_TO_UINT16 (info_type, p);
                  STREAM_TO_UINT16 (result, p);
      
    -@@ -696,6 +796,10 @@ static void process_l2cap_cmd (tL2C_LCB *p_lcb, UINT8 *p, UINT16 pkt_len)
    +@@ -696,6 +801,10 @@ static void process_l2cap_cmd (tL2C_LCB *p_lcb, UINT8 *p, UINT16 pkt_len)
                  if ( (info_type == L2CAP_EXTENDED_FEATURES_INFO_TYPE)
                    && (result == L2CAP_INFO_RESP_RESULT_SUCCESS) )
                  {
    @@ -1287,6 +2098,58 @@ index 3c48d6974..cef488cb9 100644
                      STREAM_TO_UINT32( p_lcb->peer_ext_fea, p );
      
      #if (L2CAP_NUM_FIXED_CHNLS > 0)
    +diff --git a/stack/l2cap/l2c_utils.c b/stack/l2cap/l2c_utils.c
    +index 58ac4b06b..aeff5781c 100644
    +--- a/stack/l2cap/l2c_utils.c
    ++++ b/stack/l2cap/l2c_utils.c
    +@@ -253,6 +253,7 @@ void l2cu_release_lcb (tL2C_LCB *p_lcb)
    +         (*p_cb) (L2CAP_PING_RESULT_NO_LINK);
    +     }
    + 
    ++#if (BLE_INCLUDED == TRUE)
    +     /* Check and release all the LE COC connections waiting for security */
    +     if (p_lcb->le_sec_pending_q)
    +     {
    +@@ -266,6 +267,7 @@ void l2cu_release_lcb (tL2C_LCB *p_lcb)
    +         fixed_queue_free(p_lcb->le_sec_pending_q, NULL);
    +         p_lcb->le_sec_pending_q = NULL;
    +     }
    ++#endif
    + }
    + 
    + 
    +@@ -1817,6 +1819,7 @@ tL2C_RCB *l2cu_allocate_rcb (UINT16 psm)
    +     return (NULL);
    + }
    + 
    ++#if (BLE_INCLUDED == TRUE)
    + /*******************************************************************************
    + **
    + ** Function         l2cu_allocate_ble_rcb
    +@@ -1848,6 +1851,7 @@ tL2C_RCB *l2cu_allocate_ble_rcb (UINT16 psm)
    +     /* If here, no free RCB found */
    +     return (NULL);
    + }
    ++#endif
    + 
    + /*******************************************************************************
    + **
    +@@ -1922,6 +1926,7 @@ tL2C_RCB *l2cu_find_rcb_by_psm (UINT16 psm)
    +     return (NULL);
    + }
    + 
    ++#if (BLE_INCLUDED == TRUE)
    + /*******************************************************************************
    + **
    + ** Function         l2cu_find_ble_rcb_by_psm
    +@@ -1946,6 +1951,7 @@ tL2C_RCB *l2cu_find_ble_rcb_by_psm (UINT16 psm)
    +     /* If here, no match found */
    +     return (NULL);
    + }
    ++#endif
    + 
    + /*******************************************************************************
    + **
     diff --git a/stack/l2cap/l2cap_client.c b/stack/l2cap/l2cap_client.c
     index 7e8b3cb6f..cd7edfe1f 100644
     --- a/stack/l2cap/l2cap_client.c
    @@ -1312,10 +2175,18 @@ index 7e8b3cb6f..cd7edfe1f 100644
          fragment->len = client->remote_mtu;
          memcpy(fragment->data + fragment->offset, bt_packet->data + bt_packet->offset, client->remote_mtu);
     diff --git a/stack/mcap/mca_cact.c b/stack/mcap/mca_cact.c
    -index 583a34215..f1d76be5f 100644
    +index 583a34215..64e05f4e2 100644
     --- a/stack/mcap/mca_cact.c
     +++ b/stack/mcap/mca_cact.c
    -@@ -122,7 +122,7 @@ void mca_ccb_snd_req(tMCA_CCB *p_ccb, tMCA_CCB_EVT *p_data)
    +@@ -22,6 +22,7 @@
    +  *  Functions.
    +  *
    +  ******************************************************************************/
    ++#include <log/log.h>
    + #include <string.h>
    + #include "bt_target.h"
    + #include "bt_utils.h"
    +@@ -122,7 +123,7 @@ void mca_ccb_snd_req(tMCA_CCB *p_ccb, tMCA_CCB_EVT *p_data)
              p_ccb->p_tx_req = p_msg;
              if (!p_ccb->cong)
              {
    @@ -1324,7 +2195,7 @@ index 583a34215..f1d76be5f 100644
      
                  p_pkt->offset = L2CAP_MIN_OFFSET;
                  p = p_start = (UINT8*)(p_pkt + 1) + L2CAP_MIN_OFFSET;
    -@@ -164,7 +164,7 @@ void mca_ccb_snd_rsp(tMCA_CCB *p_ccb, tMCA_CCB_EVT *p_data)
    +@@ -164,7 +165,7 @@ void mca_ccb_snd_rsp(tMCA_CCB *p_ccb, tMCA_CCB_EVT *p_data)
          tMCA_CCB_MSG *p_msg = (tMCA_CCB_MSG *)p_data;
          UINT8   *p, *p_start;
          BOOLEAN chk_mdl = FALSE;
    @@ -1333,16 +2204,20 @@ index 583a34215..f1d76be5f 100644
      
          MCA_TRACE_DEBUG("%s cong=%d req=%d", __func__, p_ccb->cong, p_msg->op_code);
          /* assume that API functions verified the parameters */
    -@@ -269,9 +269,14 @@ void mca_ccb_hdl_req(tMCA_CCB *p_ccb, tMCA_CCB_EVT *p_data)
    +@@ -269,9 +270,18 @@ void mca_ccb_hdl_req(tMCA_CCB *p_ccb, tMCA_CCB_EVT *p_data)
          p_rx_msg = (tMCA_CCB_MSG *)p_pkt;
          p = (UINT8 *)(p_pkt + 1) + p_pkt->offset;
          evt_data.hdr.op_code = *p++;
     -    BE_STREAM_TO_UINT16 (evt_data.hdr.mdl_id, p);
          reject_opcode = evt_data.hdr.op_code+1;
      
    -+    if (p_pkt->len >= 3) {
    ++    if (p_pkt->len >= 3)
    ++    {
     +        BE_STREAM_TO_UINT16(evt_data.hdr.mdl_id, p);
    -+    } else {
    ++    }
    ++    else
    ++    {
    ++        android_errorWriteLog(0x534e4554, "110791536");
     +        evt_data.hdr.mdl_id = 0;
     +    }
     +
    @@ -1422,10 +2297,20 @@ index 5c3a36739..9c90e5834 100644
      }
      
     diff --git a/stack/rfcomm/rfc_ts_frames.c b/stack/rfcomm/rfc_ts_frames.c
    -index 739469f64..68a238414 100644
    +index 739469f64..d7fb8e5cf 100644
     --- a/stack/rfcomm/rfc_ts_frames.c
     +++ b/stack/rfcomm/rfc_ts_frames.c
    -@@ -555,7 +555,15 @@ UINT8 rfc_parse_data (tRFC_MCB *p_mcb, MX_FRAME *p_frame, BT_HDR *p_buf)
    +@@ -22,6 +22,9 @@
    +  *
    +  ******************************************************************************/
    + 
    ++#define LOG_TAG "rfc_ts_frames"
    ++#include "osi/include/log.h"
    ++
    + #include <stddef.h>
    + #include "bt_target.h"
    + #include "bt_common.h"
    +@@ -555,7 +558,19 @@ UINT8 rfc_parse_data (tRFC_MCB *p_mcb, MX_FRAME *p_frame, BT_HDR *p_buf)
              return (RFC_EVENT_BAD_FRAME);
          }
          RFCOMM_PARSE_TYPE_FIELD (p_frame->type, p_frame->pf, p_data);
    @@ -1433,58 +2318,66 @@ index 739469f64..68a238414 100644
     +
     +    eal = *(p_data)&RFCOMM_EA;
     +    len = *(p_data)++ >> RFCOMM_SHIFT_LENGTH1;
    -+    if (eal == 0 && p_buf->len > RFCOMM_CTRL_FRAME_LEN) {
    ++    if (eal == 0 && p_buf->len > RFCOMM_CTRL_FRAME_LEN)
    ++    {
     +        len += (*(p_data)++ << RFCOMM_SHIFT_LENGTH2);
    -+    } else if (eal == 0) {
    ++    }
    ++    else if (eal == 0)
    ++    {
     +        RFCOMM_TRACE_ERROR("Bad Length when EAL = 0: %d", p_buf->len);
    ++        LOG_ERROR(LOG_TAG, "78288018");
     +        return RFC_EVENT_BAD_FRAME;
     +    }
      
          p_buf->len      -= (3 + !ead + !eal + 1);  /* Additional 1 for FCS */
          p_buf->offset   += (3 + !ead + !eal);
    -@@ -670,6 +678,13 @@ void rfc_process_mx_message (tRFC_MCB *p_mcb, BT_HDR *p_buf)
    +@@ -670,6 +685,14 @@ void rfc_process_mx_message (tRFC_MCB *p_mcb, BT_HDR *p_buf)
          UINT8        ea, cr, mx_len;
          BOOLEAN      is_command;
      
    -+    if (length < 2) {
    -+        RFCOMM_TRACE_ERROR(
    -+            "%s: Illegal MX Frame len when reading EA, C/R. len:%d < 2", __func__,
    -+            length);
    ++    if (length < 2)
    ++    {
    ++        RFCOMM_TRACE_ERROR("%s: Illegal MX Frame len when reading EA, C/R. len:%d < 2",
    ++                           __func__, length);
    ++        LOG_ERROR(LOG_TAG, "111937065");
     +        osi_free(p_buf);
     +        return;
     +    }
          p_rx_frame->ea   = *p_data & RFCOMM_EA;
          p_rx_frame->cr   = (*p_data & RFCOMM_CR_MASK) >> RFCOMM_SHIFT_CR;
          p_rx_frame->type = *p_data++ & ~(RFCOMM_CR_MASK | RFCOMM_EA_MASK);
    -@@ -692,6 +707,12 @@ void rfc_process_mx_message (tRFC_MCB *p_mcb, BT_HDR *p_buf)
    +@@ -692,6 +715,14 @@ void rfc_process_mx_message (tRFC_MCB *p_mcb, BT_HDR *p_buf)
      
          if (!ea)
          {
    -+       if (length < 1) {
    ++        if (length < 1)
    ++        {
     +            RFCOMM_TRACE_ERROR("%s: Illegal MX Frame when EA = 0. len:%d < 1",
    -+                         __func__, length);
    ++                               __func__, length);
    ++            LOG_ERROR(LOG_TAG, "111937065");
     +            osi_free(p_buf);
     +            return;
     +        }
              mx_len += *p_data++ << RFCOMM_SHIFT_LENGTH2;
              length --;
          }
    -@@ -768,7 +789,12 @@ void rfc_process_mx_message (tRFC_MCB *p_mcb, BT_HDR *p_buf)
    +@@ -768,6 +799,14 @@ void rfc_process_mx_message (tRFC_MCB *p_mcb, BT_HDR *p_buf)
              return;
      
          case RFCOMM_MX_MSC:
    --
     +        if (length != RFCOMM_MX_MSC_LEN_WITH_BREAK &&
    -+              length != RFCOMM_MX_MSC_LEN_NO_BREAK) {
    ++            length != RFCOMM_MX_MSC_LEN_NO_BREAK)
    ++        {
     +            RFCOMM_TRACE_ERROR("%s: Illegal MX MSC Frame len:%d", __func__, length);
    ++            LOG_ERROR(LOG_TAG, "111937065");
     +            osi_free(p_buf);
     +            return;
     +        }
    + 
              ea                   = *p_data & RFCOMM_EA;
              cr                   = (*p_data & RFCOMM_CR_MASK) >> RFCOMM_SHIFT_CR;
    -         p_rx_frame->dlci = *p_data++ >> RFCOMM_SHIFT_DLCI;
     diff --git a/stack/sdp/sdp_discovery.c b/stack/sdp/sdp_discovery.c
    -index ec20689e3..08609a733 100644
    +index ec20689e3..5dcf9915e 100644
     --- a/stack/sdp/sdp_discovery.c
     +++ b/stack/sdp/sdp_discovery.c
     @@ -29,6 +29,7 @@
    @@ -1555,7 +2448,7 @@ index ec20689e3..08609a733 100644
                  invalid_pdu = FALSE;
              }
              break;
    -@@ -280,7 +285,8 @@ void sdp_disc_server_rsp (tCONN_CB *p_ccb, BT_HDR *p_msg)
    +@@ -280,12 +285,18 @@ void sdp_disc_server_rsp (tCONN_CB *p_ccb, BT_HDR *p_msg)
      ** Returns          void
      **
      *******************************************************************************/
    @@ -1565,7 +2458,30 @@ index ec20689e3..08609a733 100644
      {
          UINT16      xx;
          UINT16      total, cur_handles, orig;
    -@@ -317,6 +323,11 @@ static void process_service_search_rsp (tCONN_CB *p_ccb, UINT8 *p_reply)
    +     UINT8       cont_len;
    + 
    ++    if (p_reply + 8 > p_reply_end) {
    ++        android_errorWriteLog(0x534e4554, "74249842");
    ++        sdp_disconnect(p_ccb, SDP_GENERIC_ERROR);
    ++        return;
    ++    }
    +     /* Skip transaction, and param len */
    +     p_reply += 4;
    +     BE_STREAM_TO_UINT16 (total, p_reply);
    +@@ -306,6 +317,12 @@ static void process_service_search_rsp (tCONN_CB *p_ccb, UINT8 *p_reply)
    +     if (p_ccb->num_handles > sdp_cb.max_recs_per_search)
    +         p_ccb->num_handles = sdp_cb.max_recs_per_search;
    + 
    ++    if (p_reply + ((p_ccb->num_handles - orig) * 4) + 1 > p_reply_end) {
    ++        android_errorWriteLog(0x534e4554, "74249842");
    ++        sdp_disconnect(p_ccb, SDP_GENERIC_ERROR);
    ++        return;
    ++    }
    ++
    +     for (xx = orig; xx < p_ccb->num_handles; xx++)
    +         BE_STREAM_TO_UINT32 (p_ccb->handles[xx], p_reply);
    + 
    +@@ -317,6 +334,11 @@ static void process_service_search_rsp (tCONN_CB *p_ccb, UINT8 *p_reply)
                  sdp_disconnect (p_ccb, SDP_INVALID_CONT_STATE);
                  return;
              }
    @@ -1577,7 +2493,7 @@ index ec20689e3..08609a733 100644
              /* stay in the same state */
              sdp_snd_service_search_req(p_ccb, cont_len, p_reply);
          }
    -@@ -326,7 +337,7 @@ static void process_service_search_rsp (tCONN_CB *p_ccb, UINT8 *p_reply)
    +@@ -326,7 +348,7 @@ static void process_service_search_rsp (tCONN_CB *p_ccb, UINT8 *p_reply)
              p_ccb->disc_state = SDP_DISC_WAIT_ATTR;
      
              /* Kick off the first attribute request */
    @@ -1586,29 +2502,27 @@ index ec20689e3..08609a733 100644
          }
      }
      
    -@@ -365,11 +376,17 @@ static void sdp_copy_raw_data (tCONN_CB *p_ccb, BOOLEAN offset)
    -         list_len = p_ccb->list_len;
    -         p = &p_ccb->rsp_list[0];
    +@@ -367,10 +389,18 @@ static void sdp_copy_raw_data (tCONN_CB *p_ccb, BOOLEAN offset)
      
    --        if(offset)
    --        {
    -+        if(offset) {
    +         if(offset)
    +         {
     +            cpy_len -= 1;
                  type = *p++;
    --            p = sdpu_get_len_from_type (p, type, &list_len);
    --        }
     +            uint8_t* old_p = p;
    -+            p = sdpu_get_len_from_type(p, type, &list_len);
    -+            if ((int)cpy_len < (p - old_p)) {
    +             p = sdpu_get_len_from_type (p, type, &list_len);
    ++            if ((int)cpy_len < (p - old_p))
    ++            {
     +                SDP_TRACE_WARNING("%s: no bytes left for data", __func__);
     +                return;
     +            }
     +            cpy_len -= (p - old_p);
    -+	}
    -         if(list_len && list_len < cpy_len )
    +         }
    +-        if(list_len && list_len < cpy_len )
    ++        if (list_len < cpy_len)
              {
                  cpy_len = list_len;
    -@@ -395,7 +412,8 @@ static void sdp_copy_raw_data (tCONN_CB *p_ccb, BOOLEAN offset)
    +         }
    +@@ -395,7 +425,8 @@ static void sdp_copy_raw_data (tCONN_CB *p_ccb, BOOLEAN offset)
      ** Returns          void
      **
      *******************************************************************************/
    @@ -1618,7 +2532,7 @@ index ec20689e3..08609a733 100644
      {
          UINT8           *p_start, *p_param_len;
          UINT16          param_len, list_byte_count;
    -@@ -502,8 +520,12 @@ static void process_service_attr_rsp (tCONN_CB *p_ccb, UINT8 *p_reply)
    +@@ -502,8 +533,12 @@ static void process_service_attr_rsp (tCONN_CB *p_ccb, UINT8 *p_reply)
              /* Was this a continuation request ? */
              if (cont_request_needed)
              {
    @@ -1633,7 +2547,7 @@ index ec20689e3..08609a733 100644
              }
              else
                  UINT8_TO_BE_STREAM (p, 0);
    -@@ -541,7 +563,8 @@ static void process_service_attr_rsp (tCONN_CB *p_ccb, UINT8 *p_reply)
    +@@ -541,7 +576,8 @@ static void process_service_attr_rsp (tCONN_CB *p_ccb, UINT8 *p_reply)
      ** Returns          void
      **
      *******************************************************************************/
    @@ -1643,7 +2557,37 @@ index ec20689e3..08609a733 100644
      {
          UINT8           *p, *p_start, *p_end, *p_param_len;
          UINT8           type;
    -@@ -641,8 +664,12 @@ static void process_service_search_attr_rsp (tCONN_CB *p_ccb, UINT8 *p_reply)
    +@@ -555,6 +591,14 @@ static void process_service_search_attr_rsp (tCONN_CB *p_ccb, UINT8 *p_reply)
    +     /* If p_reply is NULL, we were called for the initial read */
    +     if (p_reply)
    +     {
    ++        if (p_reply + 4 /* transaction ID and length */ + sizeof(lists_byte_count) >
    ++            p_reply_end)
    ++        {
    ++            android_errorWriteLog(0x534e4554, "79884292");
    ++            sdp_disconnect(p_ccb, SDP_INVALID_PDU_SIZE);
    ++            return;
    ++        }
    ++
    + #if (SDP_DEBUG_RAW == TRUE)
    +         SDP_TRACE_WARNING("ID & len: 0x%02x-%02x-%02x-%02x",
    +             p_reply[0], p_reply[1], p_reply[2], p_reply[3]);
    +@@ -578,6 +622,14 @@ static void process_service_search_attr_rsp (tCONN_CB *p_ccb, UINT8 *p_reply)
    +         SDP_TRACE_WARNING("list_len: %d, list_byte_count: %d",
    +             p_ccb->list_len, lists_byte_count);
    + #endif
    ++
    ++        if (p_reply + lists_byte_count + 1 /* continuation */ > p_reply_end)
    ++        {
    ++            android_errorWriteLog(0x534e4554, "79884292");
    ++            sdp_disconnect(p_ccb, SDP_INVALID_PDU_SIZE);
    ++            return;
    ++        }
    ++
    +         if (p_ccb->rsp_list == NULL)
    +             p_ccb->rsp_list = (UINT8 *)osi_malloc(SDP_MAX_LIST_BYTE_COUNT);
    +         memcpy (&p_ccb->rsp_list[p_ccb->list_len], p_reply, lists_byte_count);
    +@@ -641,8 +693,12 @@ static void process_service_search_attr_rsp (tCONN_CB *p_ccb, UINT8 *p_reply)
              /* No continuation for first request */
              if (p_reply)
              {
    @@ -1688,7 +2632,7 @@ index c88881799..7cbe2d37b 100644
      /*******************************************************************************
      **
     diff --git a/stack/sdp/sdp_server.c b/stack/sdp/sdp_server.c
    -index 627f4cf18..993e0a1f4 100644
    +index 627f4cf18..64a1b9f86 100644
     --- a/stack/sdp/sdp_server.c
     +++ b/stack/sdp/sdp_server.c
     @@ -23,6 +23,7 @@
    @@ -1767,7 +2711,7 @@ index 627f4cf18..993e0a1f4 100644
              {
                  sdpu_build_n_send_error (p_ccb, trans_num, SDP_INVALID_CONT_STATE,
                                           SDP_TEXT_BAD_CONT_INX);
    -@@ -327,15 +339,15 @@ static void process_service_attr_req (tCONN_CB *p_ccb, UINT16 trans_num,
    +@@ -327,25 +339,27 @@ static void process_service_attr_req (tCONN_CB *p_ccb, UINT16 trans_num,
          BOOLEAN         is_cont = FALSE;
          UINT16          attr_len;
      
    @@ -1784,11 +2728,14 @@ index 627f4cf18..993e0a1f4 100644
      
     +    /* Extract the record handle */
     +    BE_STREAM_TO_UINT32(rec_handle, p_req);
    ++    param_len -= sizeof(rec_handle);
     +
          /* Get the max list length we can send. Cap it at MTU size minus overhead */
          BE_STREAM_TO_UINT16 (max_list_len, p_req);
    ++    param_len -= sizeof(max_list_len);
      
    -@@ -344,8 +356,8 @@ static void process_service_attr_req (tCONN_CB *p_ccb, UINT16 trans_num,
    +     if (max_list_len > (p_ccb->rem_mtu_size - SDP_MAX_ATTR_RSPHDR_LEN))
    +         max_list_len = p_ccb->rem_mtu_size - SDP_MAX_ATTR_RSPHDR_LEN;
      
          p_req = sdpu_extract_attr_seq (p_req, param_len, &attr_seq);
      
    @@ -1799,7 +2746,7 @@ index 627f4cf18..993e0a1f4 100644
              sdpu_build_n_send_error (p_ccb, trans_num, SDP_INVALID_REQ_SYNTAX, SDP_TEXT_BAD_ATTR_LIST);
              return;
          }
    -@@ -360,13 +372,20 @@ static void process_service_attr_req (tCONN_CB *p_ccb, UINT16 trans_num,
    +@@ -360,13 +374,20 @@ static void process_service_attr_req (tCONN_CB *p_ccb, UINT16 trans_num,
              return;
          }
      
    @@ -1821,7 +2768,22 @@ index 627f4cf18..993e0a1f4 100644
                  sdpu_build_n_send_error(p_ccb, trans_num, SDP_INVALID_CONT_STATE,
                                          SDP_TEXT_BAD_CONT_LEN);
                  return;
    -@@ -562,8 +581,8 @@ static void process_service_search_attr_req (tCONN_CB *p_ccb, UINT16 trans_num,
    +@@ -416,6 +437,14 @@ static void process_service_attr_req (tCONN_CB *p_ccb, UINT16 trans_num,
    +             /* if there is a partial attribute pending to be sent */
    +             if (p_ccb->cont_info.attr_offset)
    +             {
    ++                if (attr_len < p_ccb->cont_info.attr_offset)
    ++                {
    ++                    android_errorWriteLog(0x534e4554, "79217770");
    ++                    SDP_TRACE_ERROR("offset is bigger than attribute length");
    ++                    sdpu_build_n_send_error(p_ccb, trans_num, SDP_INVALID_CONT_STATE,
    ++                                            SDP_TEXT_BAD_CONT_LEN);
    ++                    return;
    ++                }
    +                 p_rsp = sdpu_build_partial_attrib_entry (p_rsp, p_attr, rem_len,
    +                                                          &p_ccb->cont_info.attr_offset);
    + 
    +@@ -562,8 +591,8 @@ static void process_service_search_attr_req (tCONN_CB *p_ccb, UINT16 trans_num,
          /* Extract the UUID sequence to search for */
          p_req = sdpu_extract_uid_seq (p_req, param_len, &uid_seq);
      
    @@ -1832,8 +2794,11 @@ index 627f4cf18..993e0a1f4 100644
              sdpu_build_n_send_error (p_ccb, trans_num, SDP_INVALID_REQ_SYNTAX, SDP_TEXT_BAD_UUID_LIST);
              return;
          }
    -@@ -576,21 +595,28 @@ static void process_service_search_attr_req (tCONN_CB *p_ccb, UINT16 trans_num,
    +@@ -574,23 +603,31 @@ static void process_service_search_attr_req (tCONN_CB *p_ccb, UINT16 trans_num,
    +     if (max_list_len > (p_ccb->rem_mtu_size - SDP_MAX_SERVATTR_RSPHDR_LEN))
    +         max_list_len = p_ccb->rem_mtu_size - SDP_MAX_SERVATTR_RSPHDR_LEN;
      
    ++    param_len = (unsigned short int)((p_req_end - p_req) & USHRT_MAX);
          p_req = sdpu_extract_attr_seq (p_req, param_len, &attr_seq);
      
     -    if ((!p_req) || (!attr_seq.num_attr))
    @@ -1864,6 +2829,21 @@ index 627f4cf18..993e0a1f4 100644
                  sdpu_build_n_send_error(p_ccb, trans_num, SDP_INVALID_CONT_STATE,
                                          SDP_TEXT_BAD_CONT_LEN);
                  return;
    +@@ -661,6 +698,14 @@ static void process_service_search_attr_req (tCONN_CB *p_ccb, UINT16 trans_num,
    +                 /* if there is a partial attribute pending to be sent */
    +                 if (p_ccb->cont_info.attr_offset)
    +                 {
    ++                    if (attr_len < p_ccb->cont_info.attr_offset)
    ++                    {
    ++                        android_errorWriteLog(0x534e4554, "79217770");
    ++                        SDP_TRACE_ERROR("offset is bigger than attribute length");
    ++                        sdpu_build_n_send_error(p_ccb, trans_num, SDP_INVALID_CONT_STATE,
    ++                                                SDP_TEXT_BAD_CONT_LEN);
    ++                        return;
    ++                    }
    +                     p_rsp = sdpu_build_partial_attrib_entry (p_rsp, p_attr, rem_len,
    +                                                              &p_ccb->cont_info.attr_offset);
    + 
     diff --git a/stack/sdp/sdp_utils.c b/stack/sdp/sdp_utils.c
     index a6f0ba6a9..6b503cb70 100644
     --- a/stack/sdp/sdp_utils.c
    @@ -2096,7 +3076,7 @@ index fd3dc64fe..49f2d1104 100644
      
      #define ECC_PointMult(q, p, n, keyLength)  ECC_PointMult_Bin_NAF(q, p, n, keyLength)
     diff --git a/stack/smp/smp_act.c b/stack/smp/smp_act.c
    -index e4152a478..7bef80b27 100644
    +index e4152a478..16d5e1a2d 100644
     --- a/stack/smp/smp_act.c
     +++ b/stack/smp/smp_act.c
     @@ -16,11 +16,13 @@
    @@ -2132,7 +3112,7 @@ index e4152a478..7bef80b27 100644
          p_cb->flags |= SMP_PAIR_FLAG_HAVE_PEER_PUBL_KEY;
      
          smp_wait_for_both_public_keys(p_cb, NULL);
    -@@ -815,7 +829,6 @@ void smp_process_keypress_notification(tSMP_CB *p_cb, tSMP_INT_DATA *p_data)
    +@@ -815,14 +829,20 @@ void smp_process_keypress_notification(tSMP_CB *p_cb, tSMP_INT_DATA *p_data)
          UINT8 reason = SMP_INVALID_PARAMETERS;
      
          SMP_TRACE_DEBUG("%s", __func__);
    @@ -2140,7 +3120,12 @@ index e4152a478..7bef80b27 100644
      
          if (smp_command_has_invalid_parameters(p_cb))
          {
    -@@ -823,6 +836,8 @@ void smp_process_keypress_notification(tSMP_CB *p_cb, tSMP_INT_DATA *p_data)
    ++        if (p_cb->rcvd_cmd_len < 2)
    ++        {
    ++            // 1 (opcode) + 1 (Notif Type) bytes
    ++            android_errorWriteLog(0x534e4554, "111936834");
    ++        }
    +         smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &reason);
              return;
          }
      
    @@ -2149,25 +3134,33 @@ index e4152a478..7bef80b27 100644
          if (p != NULL)
          {
              STREAM_TO_UINT8(p_cb->peer_keypress_notification, p);
    -@@ -999,6 +1014,12 @@ void smp_proc_enc_info(tSMP_CB *p_cb, tSMP_INT_DATA *p_data)
    +@@ -997,8 +1017,17 @@ void smp_br_select_next_key(tSMP_CB *p_cb, tSMP_INT_DATA *p_data)
    + void smp_proc_enc_info(tSMP_CB *p_cb, tSMP_INT_DATA *p_data)
    + {
          UINT8   *p = (UINT8 *)p_data;
    ++    UINT8   reason = SMP_INVALID_PARAMETERS;
      
          SMP_TRACE_DEBUG("%s", __func__);
     +
    -+    if (smp_command_has_invalid_parameters(p_cb)) {
    -+        smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, NULL);
    ++    if (smp_command_has_invalid_parameters(p_cb))
    ++    {
    ++        android_errorWriteLog(0x534e4554, "111937065");
    ++        smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &reason);
     +        return;
     +    }
     +
          STREAM_TO_ARRAY(p_cb->ltk, p, BT_OCTET16_LEN);
      
          smp_key_distribution(p_cb, NULL);
    -@@ -1013,6 +1034,13 @@ void smp_proc_master_id(tSMP_CB *p_cb, tSMP_INT_DATA *p_data)
    +@@ -1013,6 +1042,16 @@ void smp_proc_master_id(tSMP_CB *p_cb, tSMP_INT_DATA *p_data)
          tBTM_LE_PENC_KEYS   le_key;
      
          SMP_TRACE_DEBUG("%s", __func__);
     +
    -+    if (p_cb->rcvd_cmd_len < 11) {  // 1(Code) + 2(EDIV) + 8(Rand)
    ++    if (p_cb->rcvd_cmd_len < 11)
    ++    {
    ++        // 1(Code) + 2(EDIV) + 8(Rand)
    ++        android_errorWriteLog(0x534e4554, "111937027");
     +        SMP_TRACE_ERROR("%s: Invalid command length: %d, should be at least 11",
     +                        __func__, p_cb->rcvd_cmd_len);
     +        return;
    @@ -2176,7 +3169,7 @@ index e4152a478..7bef80b27 100644
          smp_update_key_mask (p_cb, SMP_SEC_KEY_TYPE_ENC, TRUE);
      
          STREAM_TO_UINT16(le_key.ediv, p);
    -@@ -1032,7 +1060,7 @@ void smp_proc_master_id(tSMP_CB *p_cb, tSMP_INT_DATA *p_data)
    +@@ -1032,14 +1071,23 @@ void smp_proc_master_id(tSMP_CB *p_cb, tSMP_INT_DATA *p_data)
      }
      
      /*******************************************************************************
    @@ -2185,19 +3178,48 @@ index e4152a478..7bef80b27 100644
      ** Description  process identity information from peer device
      *******************************************************************************/
      void smp_proc_id_info(tSMP_CB *p_cb, tSMP_INT_DATA *p_data)
    -@@ -1040,6 +1068,12 @@ void smp_proc_id_info(tSMP_CB *p_cb, tSMP_INT_DATA *p_data)
    + {
          UINT8   *p = (UINT8 *)p_data;
    ++    UINT8   reason = SMP_INVALID_PARAMETERS;
      
          SMP_TRACE_DEBUG("%s", __func__);
     +
    -+    if (smp_command_has_invalid_parameters(p_cb)) {
    -+        smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, NULL);
    ++    if (smp_command_has_invalid_parameters(p_cb))
    ++    {
    ++        android_errorWriteLog(0x534e4554, "111937065");
    ++        smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &reason);
     +        return;
     +    }
     +
          STREAM_TO_ARRAY (p_cb->tk, p, BT_OCTET16_LEN);   /* reuse TK for IRK */
          smp_key_distribution_by_transport(p_cb, NULL);
      }
    +diff --git a/stack/smp/smp_br_main.c b/stack/smp/smp_br_main.c
    +index 11039ec20..fc0d04811 100644
    +--- a/stack/smp/smp_br_main.c
    ++++ b/stack/smp/smp_br_main.c
    +@@ -19,6 +19,7 @@
    + #include "bt_target.h"
    + 
    + #include <string.h>
    ++#include "log/log.h"
    + #include "smp_int.h"
    + 
    + #if BLE_INCLUDED == TRUE
    +@@ -344,6 +345,13 @@ void smp_br_state_machine_event(tSMP_CB *p_cb, tSMP_BR_EVENT event, void *p_data
    +         return;
    +     }
    + 
    ++    if (p_cb->role > HCI_ROLE_SLAVE)
    ++    {
    ++        SMP_TRACE_ERROR("%s: invalid role %d", __func__, p_cb->role);
    ++        android_errorWriteLog(0x534e4554, "80145946");
    ++        return;
    ++    }
    ++
    +     SMP_TRACE_DEBUG( "SMP Role: %s State: [%s (%d)], Event: [%s (%d)]",
    +                       (p_cb->role == HCI_ROLE_SLAVE) ? "Slave" : "Master",
    +                       smp_get_br_state_name( p_cb->br_state),
     diff --git a/stack/smp/smp_main.c b/stack/smp/smp_main.c
     index c3709f8a3..67a2b397a 100644
     --- a/stack/smp/smp_main.c
    diff --git a/system_vold.patch b/system_vold.patch
    index 1b8de23..c98969c 100644
    --- a/system_vold.patch
    +++ b/system_vold.patch
    @@ -23,3 +23,39 @@ index 014055b..43014bd 100644
              if (start != nullptr && sscanf(start + 6, "\"%127[^\"]\"", value) == 1) {
                  fsLabel = value;
              }
    +diff --git a/cryptfs.c b/cryptfs.c
    +index 2a52336..0854f42 100644
    +--- a/cryptfs.c
    ++++ b/cryptfs.c
    +@@ -3380,24 +3380,25 @@ int cryptfs_changepw(int crypt_type, const char *newpw)
    + static unsigned int persist_get_max_entries(int encrypted) {
    +     struct crypt_mnt_ftr crypt_ftr;
    +     unsigned int dsize;
    +-    unsigned int max_persistent_entries;
    + 
    +     /* If encrypted, use the values from the crypt_ftr, otherwise
    +      * use the values for the current spec.
    +      */
    +     if (encrypted) {
    +         if (get_crypt_ftr_and_key(&crypt_ftr)) {
    +-            return -1;
    ++            /* Something is wrong, assume no space for entries */
    ++            return 0;
    +         }
    +         dsize = crypt_ftr.persist_data_size;
    +     } else {
    +         dsize = CRYPT_PERSIST_DATA_SIZE;
    +     }
    + 
    +-    max_persistent_entries = (dsize - sizeof(struct crypt_persist_data)) /
    +-        sizeof(struct crypt_persist_entry);
    +-
    +-    return max_persistent_entries;
    ++    if (dsize > sizeof(struct crypt_persist_data)) {
    ++        return (dsize - sizeof(struct crypt_persist_data)) / sizeof(struct crypt_persist_entry);
    ++    } else {
    ++        return 0;
    ++    }
    + }
    + 
    + static int persist_get_key(const char *fieldname, char *value)
    
    From d064990cc540c6ca9d8bd62c999375032ccdb393 Mon Sep 17 00:00:00 2001
    From: AndDiSa <anddisa@googlemail.com>
    Date: Sun, 9 Dec 2018 10:13:12 +0100
    Subject: [PATCH 105/159] update patches
    
    Change-Id: I0dc6ff3d221d4aeaec47c5179ae32c496de08439
    ---
     frameworks_native.patch | 13 -------------
     1 file changed, 13 deletions(-)
    
    diff --git a/frameworks_native.patch b/frameworks_native.patch
    index 6e4f90b..24f1e09 100644
    --- a/frameworks_native.patch
    +++ b/frameworks_native.patch
    @@ -2365,19 +2365,6 @@ index 1a9820d95..b45e00acd 100644
      
          reset();
          beginResync();
    -diff --git a/services/surfaceflinger/DisplayDevice.cpp b/services/surfaceflinger/DisplayDevice.cpp
    -index 5c2c0adf3..1f2e554bd 100644
    ---- a/services/surfaceflinger/DisplayDevice.cpp
    -+++ b/services/surfaceflinger/DisplayDevice.cpp
    -@@ -166,7 +166,7 @@ DisplayDevice::DisplayDevice(
    -     setProjection(DisplayState::eOrientationDefault, mViewport, mFrame);
    - 
    - #ifdef NUM_FRAMEBUFFER_SURFACE_BUFFERS
    --    surface->allocateBuffers();
    -+    mSurface->allocateBuffers();
    - #endif
    - }
    - 
     diff --git a/services/surfaceflinger/DisplayHardware/HWComposer_hwc1.cpp b/services/surfaceflinger/DisplayHardware/HWComposer_hwc1.cpp
     index ef416581a..138d20ae5 100644
     --- a/services/surfaceflinger/DisplayHardware/HWComposer_hwc1.cpp
    
    From 338eb277786985411cc289b171a19a3beea1646c Mon Sep 17 00:00:00 2001
    From: AndDiSa <anddisa@googlemail.com>
    Date: Sat, 5 Jan 2019 18:17:35 +0100
    Subject: [PATCH 106/159] debloat
    
    Change-Id: If3e867e293ac5e0cd3368db0f4f1ee9b8d6d5c9e
    ---
     default.xml | 14 +++++++-------
     1 file changed, 7 insertions(+), 7 deletions(-)
    
    diff --git a/default.xml b/default.xml
    index 5c89b2b..50a594e 100644
    --- a/default.xml
    +++ b/default.xml
    @@ -374,9 +374,9 @@
       <project path="ndk" name="platform/ndk" groups="generic_fs" />
       <project path="packages/apps/BasicSmsReceiver" name="platform/packages/apps/BasicSmsReceiver" groups="pdk-cw-fs,pdk-fs" />
       <project path="packages/apps/Bluetooth" name="platform/packages/apps/Bluetooth" groups="pdk-cw-fs,pdk-fs" />
    -  <project path="packages/apps/Browser2" name="platform/packages/apps/Browser2" />
    +  <!-- <project path="packages/apps/Browser2" name="platform/packages/apps/Browser2" /> -->
       <project path="packages/apps/Calculator" name="platform/packages/apps/Calculator" groups="pdk-fs" />
    -  <project path="packages/apps/Calendar" name="platform/packages/apps/Calendar" groups="pdk-fs" />
    +  <!--  <project path="packages/apps/Calendar" name="platform/packages/apps/Calendar" groups="pdk-fs" /> -->
       <project path="packages/apps/CarrierConfig" name="platform/packages/apps/CarrierConfig" groups="pdk-fs" />
       <project path="packages/apps/CellBroadcastReceiver" name="platform/packages/apps/CellBroadcastReceiver" groups="pdk-fs" />
       <project path="packages/apps/CertInstaller" name="platform/packages/apps/CertInstaller" groups="pdk-cw-fs,pdk-fs" />
    @@ -394,20 +394,20 @@
       <project path="packages/apps/KeyChain" name="platform/packages/apps/KeyChain" groups="pdk-fs" />
       <project path="packages/apps/Launcher2" name="platform/packages/apps/Launcher2" groups="pdk-fs" />
       <project path="packages/apps/Launcher3" name="platform/packages/apps/Launcher3" groups="pdk-fs" />
    -  <project path="packages/apps/LegacyCamera" name="platform/packages/apps/LegacyCamera" groups="pdk-fs" />
    +  <!-- <project path="packages/apps/LegacyCamera" name="platform/packages/apps/LegacyCamera" groups="pdk-fs" /> -->
       <project path="packages/apps/ManagedProvisioning" name="platform/packages/apps/ManagedProvisioning" groups="pdk-fs" />
       <project path="packages/apps/Messaging" name="platform/packages/apps/Messaging" groups="pdk-fs" />
    -  <project path="packages/apps/Music" name="platform/packages/apps/Music" groups="pdk-fs" />
    +  <!--  <project path="packages/apps/Music" name="platform/packages/apps/Music" groups="pdk-fs" /> -->
       <project path="packages/apps/MusicFX" name="platform/packages/apps/MusicFX" groups="pdk-fs" />
       <project path="packages/apps/Nfc" name="platform/packages/apps/Nfc" groups="apps_nfc,pdk-fs" />
       <project path="packages/apps/OneTimeInitializer" name="platform/packages/apps/OneTimeInitializer" groups="pdk-fs" />
       <project path="packages/apps/PackageInstaller" name="platform/packages/apps/PackageInstaller" groups="pdk-fs" />
    -<!--  <project path="packages/apps/PerformanceControl" name="android_packages_apps_PerformanceControl" remote="ads" revision="cm-13.0" /> -->
    +  <!--  <project path="packages/apps/PerformanceControl" name="android_packages_apps_PerformanceControl" remote="ads" revision="cm-13.0" /> -->
       <project path="packages/apps/Phone" name="platform/packages/apps/Phone" groups="pdk-fs" />
       <project path="packages/apps/PhoneCommon" name="platform/packages/apps/PhoneCommon" groups="pdk-cw-fs,pdk-fs"/>
       <project path="packages/apps/Protips" name="platform/packages/apps/Protips" groups="pdk-fs" />
       <project path="packages/apps/Provision" name="platform/packages/apps/Provision" groups="pdk-fs" />
    -  <project path="packages/apps/QuickSearchBox" name="platform/packages/apps/QuickSearchBox" groups="pdk-fs" />
    +  <!-- <project path="packages/apps/QuickSearchBox" name="platform/packages/apps/QuickSearchBox" groups="pdk-fs" /> -->
       <project path="packages/apps/SafetyRegulatoryInfo" name="platform/packages/apps/SafetyRegulatoryInfo" />
       <project path="packages/apps/Settings" name="platform/packages/apps/Settings" groups="pdk-fs" />
       <project path="packages/apps/SoundRecorder" name="platform/packages/apps/SoundRecorder" groups="pdk-fs" />
    @@ -420,7 +420,7 @@
       <project path="packages/apps/Test/connectivity" name="platform/packages/apps/Test/connectivity" />
       <project path="packages/apps/TvSettings" name="platform/packages/apps/TvSettings" groups="generic_fs" />
       <project path="packages/apps/UnifiedEmail" name="platform/packages/apps/UnifiedEmail" groups="pdk-fs" />
    -<!--  <project path="packages/apps/WallpaperPicker" name="platform/packages/apps/WallpaperPicker" /> -->
    +  <project path="packages/apps/WallpaperPicker" name="platform/packages/apps/WallpaperPicker" groups="pdk-fs" />
       <project path="packages/experimental" name="platform/packages/experimental" />
       <project path="packages/inputmethods/LatinIME" name="platform/packages/inputmethods/LatinIME" groups="pdk-fs" />
       <project path="packages/inputmethods/OpenWnn" name="platform/packages/inputmethods/OpenWnn" groups="pdk-fs" />
    
    From 9ba5a7a1a6fa29d588832ee61165870e69bbbad1 Mon Sep 17 00:00:00 2001
    From: AndDiSa <anddisa@googlemail.com>
    Date: Wed, 9 Jan 2019 19:10:37 +0100
    Subject: [PATCH 107/159] update patches
    
    Change-Id: Id700e8a16011e4c7e3dff5b143bde5bb2d2b02a5
    ---
     build.patch                     |    4 +-
     external_aac.patch              |  135 ----
     external_android_clat.patch     |   39 --
     external_chromium_libpac.patch  |  116 ----
     external_curl.patch             |   63 --
     external_e2fsprogs.patch        |   28 -
     external_libdrm.patch           |   15 -
     external_libnfc-nci.patch       |  161 +++++
     external_neven.patch            |   13 -
     external_svox.patch             |   27 -
     external_wpa_supplicant_8.patch |   18 +
     frameworks_ex.patch             |   27 -
     packages_apps_messaging.patch   |   89 ---
     system_bt.patch                 | 1127 ++++++++++++++++---------------
     14 files changed, 777 insertions(+), 1085 deletions(-)
    
    diff --git a/build.patch b/build.patch
    index 8f144fa..0730220 100644
    --- a/build.patch
    +++ b/build.patch
    @@ -323,7 +323,7 @@ index 000000000..80664faf2
     +ALL_PREBUILT += $(INSTALLED_KERNEL_TARGET)
     +endif
     diff --git a/core/version_defaults.mk b/core/version_defaults.mk
    -index 7c9634490..a908f7dff 100644
    +index 7c9634490..546e6fb09 100644
     --- a/core/version_defaults.mk
     +++ b/core/version_defaults.mk
     @@ -131,7 +131,7 @@ ifeq "" "$(PLATFORM_SECURITY_PATCH)"
    @@ -331,7 +331,7 @@ index 7c9634490..a908f7dff 100644
          #  It must match one of the Android Security Patch Level strings of the Public Security Bulletins.
          #  If there is no $PLATFORM_SECURITY_PATCH set, keep it empty.
     -    PLATFORM_SECURITY_PATCH := 2017-08-05
    -+    PLATFORM_SECURITY_PATCH := 2018-12-05
    ++    PLATFORM_SECURITY_PATCH := 2019-01-05
      endif
      
      ifeq "" "$(PLATFORM_BASE_OS)"
    diff --git a/external_aac.patch b/external_aac.patch
    index 3475fb1..e69de29 100644
    --- a/external_aac.patch
    +++ b/external_aac.patch
    @@ -1,135 +0,0 @@
    -diff --git a/Android.mk b/Android.mk
    -index 4c28670..9ffa0eb 100644
    ---- a/Android.mk
    -+++ b/Android.mk
    -@@ -55,6 +55,8 @@ LOCAL_C_INCLUDES := \
    - 
    - LOCAL_CPPFLAGS += -std=c++98
    - 
    -+LOCAL_SHARED_LIBRARIES := liblog
    -+
    - LOCAL_MODULE:= libFraunhoferAAC
    - 
    - include $(BUILD_STATIC_LIBRARY)
    -diff --git a/libMpegTPDec/src/tpdec_asc.cpp b/libMpegTPDec/src/tpdec_asc.cpp
    -index 96a1b35..e80d0e5 100644
    ---- a/libMpegTPDec/src/tpdec_asc.cpp
    -+++ b/libMpegTPDec/src/tpdec_asc.cpp
    -@@ -118,7 +118,9 @@ int  CProgramConfig_IsValid ( const CProgramConfig *pPce )
    - 
    - /*
    -  * Read the extension for height info.
    -- * return 0 if successfull or -1 if the CRC failed.
    -+ * return 0 if successfull,
    -+ *       -1 if the CRC failed,
    -+ *       -2 if invalid HeightInfo.
    -  */
    - static
    - int CProgramConfig_ReadHeightExt(
    -@@ -146,15 +148,21 @@ int CProgramConfig_ReadHeightExt(
    - 
    -     for (i=0; i < pPce->NumFrontChannelElements; i++)
    -     {
    --      pPce->FrontElementHeightInfo[i] = (UCHAR) FDKreadBits(bs,2);
    -+      if ((pPce->FrontElementHeightInfo[i] = (UCHAR) FDKreadBits(bs,2)) >= PC_NUM_HEIGHT_LAYER) {
    -+        err = -2; /* height information is out of the valid range */
    -+      }
    -     }
    -     for (i=0; i < pPce->NumSideChannelElements; i++)
    -     {
    --      pPce->SideElementHeightInfo[i] = (UCHAR) FDKreadBits(bs,2);
    -+      if ((pPce->SideElementHeightInfo[i] = (UCHAR) FDKreadBits(bs,2)) >= PC_NUM_HEIGHT_LAYER) {
    -+        err = -2; /* height information is out of the valid range */
    -+      }
    -     }
    -     for (i=0; i < pPce->NumBackChannelElements; i++)
    -     {
    --      pPce->BackElementHeightInfo[i] = (UCHAR) FDKreadBits(bs,2);
    -+      if ((pPce->BackElementHeightInfo[i] = (UCHAR) FDKreadBits(bs,2)) >= PC_NUM_HEIGHT_LAYER) {
    -+        err = -2; /* height information is out of the valid range */
    -+      }
    -     }
    -     FDKbyteAlign(bs, alignmentAnchor);
    - 
    -@@ -163,6 +171,13 @@ int CProgramConfig_ReadHeightExt(
    -       /* CRC failed */
    -       err = -1;
    -     }
    -+    if (err!=0) {
    -+      /* Reset whole height information in case an error occured during parsing. The return
    -+         value ensures that pPce->isValid is set to 0 and implicit channel mapping is used. */
    -+      FDKmemclear(pPce->FrontElementHeightInfo, sizeof(pPce->FrontElementHeightInfo));
    -+      FDKmemclear(pPce->SideElementHeightInfo, sizeof(pPce->SideElementHeightInfo));
    -+      FDKmemclear(pPce->BackElementHeightInfo, sizeof(pPce->BackElementHeightInfo));
    -+    }
    -   }
    -   else {
    -     /* No valid extension data found -> restore the initial bitbuffer state */
    -diff --git a/libSBRdec/src/lpp_tran.cpp b/libSBRdec/src/lpp_tran.cpp
    -index 117e739..e332c25 100644
    ---- a/libSBRdec/src/lpp_tran.cpp
    -+++ b/libSBRdec/src/lpp_tran.cpp
    -@@ -96,6 +96,10 @@ amm-info@iis.fraunhofer.de
    -   \sa lppTransposer(), main_audio.cpp, sbr_scale.h, \ref documentationOverview
    - */
    - 
    -+#ifdef __ANDROID__
    -+#include "log/log.h"
    -+#endif
    -+
    - #include "lpp_tran.h"
    - 
    - #include "sbr_ram.h"
    -@@ -256,7 +260,6 @@ void lppTransposer (HANDLE_SBR_LPP_TRANS hLppTrans,    /*!< Handle of lpp transp
    -   int ovLowBandShift;
    -   int lowBandShift;
    - /*  int ovHighBandShift;*/
    --  int targetStopBand;
    - 
    - 
    -   alphai[0] = FL2FXCONST_SGL(0.0f);
    -@@ -273,24 +276,32 @@ void lppTransposer (HANDLE_SBR_LPP_TRANS hLppTrans,    /*!< Handle of lpp transp
    - 
    -   autoCorrLength = pSettings->nCols + pSettings->overlap;
    - 
    --  /* Set upper subbands to zero:
    --     This is required in case that the patches do not cover the complete highband
    --     (because the last patch would be too short).
    --     Possible optimization: Clearing bands up to usb would be sufficient here. */
    --  targetStopBand = patchParam[pSettings->noOfPatches-1].targetStartBand
    --                 + patchParam[pSettings->noOfPatches-1].numBandsInPatch;
    -+  if (pSettings->noOfPatches > 0) {
    -+    /* Set upper subbands to zero:
    -+       This is required in case that the patches do not cover the complete highband
    -+       (because the last patch would be too short).
    -+       Possible optimization: Clearing bands up to usb would be sufficient here. */
    -+    int targetStopBand = patchParam[pSettings->noOfPatches-1].targetStartBand
    -+                   + patchParam[pSettings->noOfPatches-1].numBandsInPatch;
    - 
    --  int memSize = ((64) - targetStopBand) * sizeof(FIXP_DBL);
    -+    int memSize = ((64) - targetStopBand) * sizeof(FIXP_DBL);
    - 
    --  if (!useLP) {
    -+    if (!useLP) {
    -+      for (i = startSample; i < stopSampleClear; i++) {
    -+        FDKmemclear(&qmfBufferReal[i][targetStopBand], memSize);
    -+        FDKmemclear(&qmfBufferImag[i][targetStopBand], memSize);
    -+      }
    -+    } else
    -     for (i = startSample; i < stopSampleClear; i++) {
    -       FDKmemclear(&qmfBufferReal[i][targetStopBand], memSize);
    --      FDKmemclear(&qmfBufferImag[i][targetStopBand], memSize);
    -     }
    --  } else
    --  for (i = startSample; i < stopSampleClear; i++) {
    --    FDKmemclear(&qmfBufferReal[i][targetStopBand], memSize);
    -   }
    -+#ifdef __ANDROID__
    -+  else {
    -+    // Safetynet logging
    -+    android_errorWriteLog(0x534e4554, "112160868");
    -+  }
    -+#endif
    - 
    -   /* init bwIndex for each patch */
    -   FDKmemclear(bwIndex, pSettings->noOfPatches*sizeof(INT));
    diff --git a/external_android_clat.patch b/external_android_clat.patch
    index f743e3d..e69de29 100644
    --- a/external_android_clat.patch
    +++ b/external_android_clat.patch
    @@ -1,39 +0,0 @@
    -diff --git a/clatd.c b/clatd.c
    -index d57ea59..fd89e0a 100644
    ---- a/clatd.c
    -+++ b/clatd.c
    -@@ -382,19 +382,28 @@ void event_loop(struct tun_data *tunnel) {
    -   last_interface_poll = time(NULL);
    - 
    -   while(running) {
    --    if(poll(wait_fd, 2, NO_TRAFFIC_INTERFACE_POLL_FREQUENCY*1000) == -1) {
    --      if(errno != EINTR) {
    --        logmsg(ANDROID_LOG_WARN,"event_loop/poll returned an error: %s",strerror(errno));
    -+    if (poll(wait_fd, ARRAY_SIZE(wait_fd),
    -+             NO_TRAFFIC_INTERFACE_POLL_FREQUENCY * 1000) == -1) {
    -+      if (errno != EINTR) {
    -+        logmsg(ANDROID_LOG_WARN,"event_loop/poll returned an error: %s", strerror(errno));
    -       }
    -     } else {
    -+      if (wait_fd[0].revents & POLLIN) {
    -+        ring_read(&tunnel->ring, tunnel->fd4, 0 /* to_ipv6 */);
    -+      }
    -+      // If any other bit is set, assume it's due to an error (i.e. POLLERR).
    -+      if (wait_fd[0].revents & ~POLLIN) {
    -+        // ring_read doesn't clear the error indication on the socket.
    -+        recv(tunnel->read_fd6, NULL, 0, MSG_PEEK);
    -+        logmsg(ANDROID_LOG_WARN, "event_loop: clearing error on read_fd6: %s",
    -+               strerror(errno));
    -+      }
    -+
    -       // Call read_packet if the socket has data to be read, but also if an
    -       // error is waiting. If we don't call read() after getting POLLERR, a
    -       // subsequent poll() will return immediately with POLLERR again,
    -       // causing this code to spin in a loop. Calling read() will clear the
    -       // socket error flag instead.
    --      if (wait_fd[0].revents) {
    --        ring_read(&tunnel->ring, tunnel->fd4, 0 /* to_ipv6 */);
    --      }
    -       if (wait_fd[1].revents) {
    -         read_packet(tunnel->fd4, tunnel->write_fd6, 1 /* to_ipv6 */);
    -       }
    diff --git a/external_chromium_libpac.patch b/external_chromium_libpac.patch
    index 27db9a9..e69de29 100644
    --- a/external_chromium_libpac.patch
    +++ b/external_chromium_libpac.patch
    @@ -1,116 +0,0 @@
    -diff --git a/Android.mk b/Android.mk
    -index e8a2b26..ae0e768 100644
    ---- a/Android.mk
    -+++ b/Android.mk
    -@@ -18,6 +18,7 @@ LOCAL_CFLAGS += \
    -   -Wno-import \
    -   -Wno-format \
    -   -Wno-unused-parameter \
    -+  -Werror
    - 
    - LOCAL_C_INCLUDES += $(LOCAL_PATH)/src $(LOCAL_PATH)/../v8
    - 
    -@@ -28,3 +29,5 @@ LOCAL_SHARED_LIBRARIES := libutils liblog libicuuc libicui18n
    - LOCAL_CXX_STL := libc++
    - 
    - include $(BUILD_SHARED_LIBRARY)
    -+
    -+include $(LOCAL_PATH)/test/Android.mk
    -diff --git a/src/net_util.cc b/src/net_util.cc
    -index 992cdd1..8eef03a 100644
    ---- a/src/net_util.cc
    -+++ b/src/net_util.cc
    -@@ -64,7 +64,7 @@ bool ParseCIDRBlock(const std::string& cidr_literal,
    -   //   <IPv6-literal> "/" <number of bits>
    - 
    -   std::vector<std::string> parts;
    --  unsigned int split = cidr_literal.find('/');
    -+  size_t split = cidr_literal.find('/');
    -   if (split == std::string::npos)
    -     return false;
    -   parts.push_back(cidr_literal.substr(0, split));
    -diff --git a/test/Android.mk b/test/Android.mk
    -index 9c9722e..edf9107 100644
    ---- a/test/Android.mk
    -+++ b/test/Android.mk
    -@@ -18,6 +18,6 @@ LOCAL_CFLAGS += \
    - 
    - LOCAL_C_INCLUDES += $(LOCAL_PATH)/../src $(LOCAL_PATH)/ external/v8
    - 
    --LOCAL_SHARED_LIBRARIES := libpac libutils liblog
    -+LOCAL_SHARED_LIBRARIES := libpac libutils liblog libandroid_runtime
    - 
    - include $(BUILD_NATIVE_TEST)
    -diff --git a/test/js-unittest/change_element_kind.js b/test/js-unittest/change_element_kind.js
    -new file mode 100644
    -index 0000000..335d59e
    ---- /dev/null
    -+++ b/test/js-unittest/change_element_kind.js
    -@@ -0,0 +1,15 @@
    -+// PAC script with getter that changes element kind.
    -+
    -+function FindProxyForURL(url, host) {
    -+  let arr = [];
    -+  arr[1000] = 0x1234;
    -+
    -+  arr.__defineGetter__(256, function () {
    -+    delete arr[256];
    -+    arr.unshift(1.1);
    -+  });
    -+
    -+  let results = Object.entries(arr);
    -+  let str = results.toString();
    -+  return "DIRECT";
    -+}
    -diff --git a/test/proxy_resolver_v8_unittest.cc b/test/proxy_resolver_v8_unittest.cc
    -index ad9c826..be7ecee 100644
    ---- a/test/proxy_resolver_v8_unittest.cc
    -+++ b/test/proxy_resolver_v8_unittest.cc
    -@@ -544,5 +544,19 @@ TEST(ProxyResolverV8Test, DNSResolutionOfInternationDomainName) {
    -   EXPECT_EQ("xn--bcher-kva.ch", bindings->dns_resolves_ex[0]);
    - }
    - 
    -+TEST(ProxyResolverV8Test, GetterChangesElementKind) {
    -+  ProxyResolverV8WithMockBindings resolver(new MockJSBindings());
    -+  int result = resolver.SetPacScript(String16(CHANGE_ELEMENT_KIND_JS));
    -+  EXPECT_EQ(OK, result);
    -+
    -+  // Execute FindProxyForURL().
    -+  result = resolver.GetProxyForURL(kQueryUrl, kQueryHost, &kResults);
    -+
    -+  EXPECT_EQ(OK, result);
    -+  std::vector<std::string> proxies = string16ToProxyList(kResults);
    -+  EXPECT_EQ(1U, proxies.size());
    -+  EXPECT_EQ("DIRECT", proxies[0]);
    -+}
    -+
    - }  // namespace
    - }  // namespace net
    -diff --git a/test/proxy_test_script.h b/test/proxy_test_script.h
    -index 1042366..80c96c7 100644
    ---- a/test/proxy_test_script.h
    -+++ b/test/proxy_test_script.h
    -@@ -78,6 +78,23 @@
    -   "function fn() {}\n" \
    -   "\n" \
    - 
    -+#define CHANGE_ELEMENT_KIND_JS \
    -+  "// PAC script with getter that changes element kind.\n" \
    -+  "	\n" \
    -+  "function FindProxyForURL(url, host) {\n" \
    -+  "  let arr = [];\n" \
    -+  "  arr[1000] = 0x1234;\n" \
    -+  "\n" \
    -+  "  arr.__defineGetter__(256, function () {\n" \
    -+  "    delete arr[256];\n" \
    -+  "    arr.unshift(1.1);\n" \
    -+  "  });\n" \
    -+  "\n" \
    -+  "  let results = Object.entries(arr);\n" \
    -+  "  let str = results.toString(); \n" \
    -+  "  return \"DIRECT\";\n" \
    -+  "}\n" \
    -+
    - #define DIRECT_JS \
    -   "function FindProxyForURL(url, host) {\n" \
    -   "  return \"DIRECT\";\n" \
    diff --git a/external_curl.patch b/external_curl.patch
    index b1cd374..e69de29 100644
    --- a/external_curl.patch
    +++ b/external_curl.patch
    @@ -1,63 +0,0 @@
    -diff --git a/lib/curl_config.h b/lib/curl_config.h
    -index 0288018..e9b7958 100644
    ---- a/lib/curl_config.h
    -+++ b/lib/curl_config.h
    -@@ -17,22 +17,22 @@
    - /* #undef CURL_DISABLE_CRYPTO_AUTH */
    - 
    - /* to disable DICT */
    --/* #undef CURL_DISABLE_DICT */
    -+#define CURL_DISABLE_DICT 1
    - 
    - /* to disable FILE */
    - /* #undef CURL_DISABLE_FILE */
    - 
    - /* to disable FTP */
    --/* #undef CURL_DISABLE_FTP */
    -+#define CURL_DISABLE_FTP 1
    - 
    - /* to disable Gopher */
    --/* #undef CURL_DISABLE_GOPHER */
    -+#define CURL_DISABLE_GOPHER 1
    - 
    - /* to disable HTTP */
    - /* #undef CURL_DISABLE_HTTP */
    - 
    - /* to disable IMAP */
    --/* #undef CURL_DISABLE_IMAP */
    -+#define CURL_DISABLE_IMAP 1
    - 
    - /* to disable LDAP */
    - #define CURL_DISABLE_LDAP 1
    -@@ -44,25 +44,25 @@
    - /* #undef CURL_DISABLE_LIBCURL_OPTION */
    - 
    - /* to disable POP3 */
    --/* #undef CURL_DISABLE_POP3 */
    -+#define CURL_DISABLE_POP3 1
    - 
    - /* to disable proxies */
    - /* #undef CURL_DISABLE_PROXY */
    - 
    - /* to disable RTSP */
    --/* #undef CURL_DISABLE_RTSP */
    -+#define CURL_DISABLE_RTSP 1
    - 
    - /* to disable SMB/CIFS */
    --/* #undef CURL_DISABLE_SMB */
    -+#define CURL_DISABLE_SMB 1
    - 
    - /* to disable SMTP */
    --/* #undef CURL_DISABLE_SMTP */
    -+#define CURL_DISABLE_SMTP 1
    - 
    - /* to disable TELNET */
    --/* #undef CURL_DISABLE_TELNET */
    -+#define CURL_DISABLE_TELNET 1
    - 
    - /* to disable TFTP */
    --/* #undef CURL_DISABLE_TFTP */
    -+#define CURL_DISABLE_TFTP 1
    - 
    - /* to disable TLS-SRP authentication */
    - /* #undef CURL_DISABLE_TLS_SRP */
    diff --git a/external_e2fsprogs.patch b/external_e2fsprogs.patch
    index 0718beb..e69de29 100644
    --- a/external_e2fsprogs.patch
    +++ b/external_e2fsprogs.patch
    @@ -1,28 +0,0 @@
    -diff --git a/e2fsck/logfile.c b/e2fsck/logfile.c
    -index 40e5acb7..3e4df8a7 100644
    ---- a/e2fsck/logfile.c
    -+++ b/e2fsck/logfile.c
    -@@ -67,7 +67,7 @@ static void expand_percent_expression(e2fsck_t ctx, char ch,
    - 				      struct string *s, int *flags)
    - {
    - 	struct tm	*tm = NULL, tm_struct;
    --	struct passwd	*pw = NULL, pw_struct;
    -+	struct passwd	*pw = NULL;
    - 	char		*cp;
    - 	char		buf[256];
    - 
    -diff --git a/misc/blkid.c b/misc/blkid.c
    -index 388abad0..248cacf6 100644
    ---- a/misc/blkid.c
    -+++ b/misc/blkid.c
    -@@ -86,7 +86,9 @@ static void safe_print(const char *cp, int len)
    - 			fputc('^', stdout);
    - 			ch ^= 0x40; /* ^@, ^A, ^B; ^? for DEL */
    - 		}
    --		fputc(ch, stdout);
    -+		if (ch != '"') {
    -+			fputc(ch, stdout);
    -+		}
    - 	}
    - }
    - 
    diff --git a/external_libdrm.patch b/external_libdrm.patch
    index dbc6b3d..e69de29 100644
    --- a/external_libdrm.patch
    +++ b/external_libdrm.patch
    @@ -1,15 +0,0 @@
    -diff --git a/xf86drm.c b/xf86drm.c
    -index 7e28b4f7..67f9f838 100644
    ---- a/xf86drm.c
    -+++ b/xf86drm.c
    -@@ -732,8 +732,8 @@ int drmOpen(const char *name, const char *busid)
    -  */
    - int drmOpenWithType(const char *name, const char *busid, int type)
    - {
    --    if (!drmAvailable() && name != NULL && drm_server_info &&
    --        drm_server_info->load_module) {
    -+    if (name != NULL && drm_server_info &&
    -+        drm_server_info->load_module && !drmAvailable()) {
    - 	/* try to load the kernel module */
    - 	if (!drm_server_info->load_module(name)) {
    - 	    drmMsg("[drm] failed to load kernel module \"%s\"\n", name);
    diff --git a/external_libnfc-nci.patch b/external_libnfc-nci.patch
    index 888dacc..99a1ff8 100644
    --- a/external_libnfc-nci.patch
    +++ b/external_libnfc-nci.patch
    @@ -1,3 +1,164 @@
    +diff --git a/src/nfc/llcp/llcp_dlc.c b/src/nfc/llcp/llcp_dlc.c
    +index 95bcac5..30e1358 100644
    +--- a/src/nfc/llcp/llcp_dlc.c
    ++++ b/src/nfc/llcp/llcp_dlc.c
    +@@ -26,6 +26,7 @@
    + #include <string.h>
    + #include "gki.h"
    + #include "nfc_target.h"
    ++#include <log/log.h>
    + #include "bt_types.h"
    + #include "llcp_int.h"
    + #include "llcp_defs.h"
    +@@ -883,6 +884,15 @@ void llcp_dlc_proc_i_pdu (UINT8 dsap, UINT8 ssap, UINT16 i_pdu_length, UINT8 *p_
    +             p_i_pdu = (UINT8 *) (p_msg + 1) + p_msg->offset;
    +         }
    + 
    ++	if (i_pdu_length < LLCP_PDU_HEADER_SIZE + LLCP_SEQUENCE_SIZE) {
    ++            android_errorWriteLog(0x534e4554, "116722267");
    ++            LOG(ERROR) << StringPrintf("Insufficient I PDU length %d", i_pdu_length);
    ++            if (p_msg) {
    ++                GKI_freebuf(p_msg);
    ++            }
    ++            return;
    ++        }
    ++
    +         info_len = i_pdu_length - LLCP_PDU_HEADER_SIZE - LLCP_SEQUENCE_SIZE;
    + 
    +         if (info_len > p_dlcb->local_miu)
    +diff --git a/src/nfc/llcp/llcp_link.c b/src/nfc/llcp/llcp_link.c
    +index d70349c..9249539 100644
    +--- a/src/nfc/llcp/llcp_link.c
    ++++ b/src/nfc/llcp/llcp_link.c
    +@@ -23,6 +23,7 @@
    +  *
    +  ******************************************************************************/
    + 
    ++#include <log/log.h>
    + #include <string.h>
    + #include "gki.h"
    + #include "nfc_target.h"
    +@@ -1132,7 +1133,7 @@ static void llcp_link_proc_agf_pdu (BT_HDR *p_agf)
    + {
    +     UINT16 agf_length;
    +     UINT8 *p, *p_info, *p_pdu_length;
    +-    UINT16 pdu_hdr, pdu_length;
    ++    UINT16 pdu_hdr, pdu_length, pdu_num;
    +     UINT8  dsap, ptype, ssap;
    + 
    +     p_agf->len    -= LLCP_PDU_HEADER_SIZE;
    +@@ -1143,12 +1144,17 @@ static void llcp_link_proc_agf_pdu (BT_HDR *p_agf)
    +     */
    +     agf_length = p_agf->len;
    +     p = (UINT8 *) (p_agf + 1) + p_agf->offset;
    ++    pdu_num = 0;
    + 
    +     while (agf_length > 0)
    +     {
    +         if (agf_length > LLCP_PDU_AGF_LEN_SIZE)
    +         {
    +             BE_STREAM_TO_UINT16 (pdu_length, p);
    ++	    if (pdu_length < LLCP_PDU_HEADER_SIZE) {
    ++                LOG(ERROR) << StringPrintf("Received invalid encapsulated PDU");
    ++                break;
    ++            }
    +             agf_length -= LLCP_PDU_AGF_LEN_SIZE;
    +         }
    +         else
    +@@ -1159,6 +1165,7 @@ static void llcp_link_proc_agf_pdu (BT_HDR *p_agf)
    +         if (pdu_length <= agf_length)
    +         {
    +             p += pdu_length;
    ++	    pdu_num++;
    +             agf_length -= pdu_length;
    +         }
    +         else
    +@@ -1167,8 +1174,9 @@ static void llcp_link_proc_agf_pdu (BT_HDR *p_agf)
    +         }
    +     }
    + 
    +-    if (agf_length != 0)
    ++    if (agf_length != 0 || pdu_num < 2)
    +     {
    ++	android_errorWriteLog(0x534e4554, "116791157");
    +         LLCP_TRACE_ERROR0 ("llcp_link_proc_agf_pdu (): Received invalid AGF PDU");
    +         GKI_freebuf (p_agf);
    +         return;
    +@@ -1207,7 +1215,8 @@ static void llcp_link_proc_agf_pdu (BT_HDR *p_agf)
    +             GKI_freebuf (p_agf);
    +             llcp_link_deactivate (LLCP_LINK_REMOTE_INITIATED);
    +             return;
    +-        }
    ++	} else if (ptype == LLCP_PDU_AGF_TYPE) {
    ++            LOG(ERROR) << StringPrintf("AGF PDU shall not be in AGF");
    +         else if (ptype == LLCP_PDU_SYMM_TYPE)
    +         {
    +             LLCP_TRACE_ERROR0 ("llcp_link_proc_agf_pdu (): SYMM PDU exchange shall not be in AGF");
    +diff --git a/src/nfc/nfc/nfc_ncif.c b/src/nfc/nfc/nfc_ncif.c
    +index 2e2c14f..739bae2 100644
    +--- a/src/nfc/nfc/nfc_ncif.c
    ++++ b/src/nfc/nfc/nfc_ncif.c
    +@@ -26,6 +26,7 @@
    +  ******************************************************************************/
    + #include <stdlib.h>
    + #include <string.h>
    ++#include <log/log.h>
    + #include "nfc_target.h"
    + 
    + #if NFC_INCLUDED == TRUE
    +@@ -490,14 +491,31 @@ void nfc_ncif_set_config_status (UINT8 *p, UINT8 len)
    +     tNFC_RESPONSE   evt_data;
    +     if (nfc_cb.p_resp_cback)
    +     {
    +-        evt_data.set_config.status          = (tNFC_STATUS) *p++;
    +-        evt_data.set_config.num_param_id    = NFC_STATUS_OK;
    +-        if (evt_data.set_config.status != NFC_STATUS_OK)
    +-        {
    +-            evt_data.set_config.num_param_id    = *p++;
    +-            STREAM_TO_ARRAY (evt_data.set_config.param_ids, p, evt_data.set_config.num_param_id);
    ++        evt_data.set_config.num_param_id = 0;
    ++        if (len == 0) {
    ++            LOG(ERROR) << StringPrintf("Insufficient RSP length");
    ++            evt_data.set_config.status = NFC_STATUS_SYNTAX_ERROR;
    ++            (*nfc_cb.p_resp_cback)(NFC_SET_CONFIG_REVT, &evt_data);
    ++            return;
    +         }
    + 
    ++        evt_data.set_config.status = (tNFC_STATUS)*p++;
    ++        if (evt_data.set_config.status != NFC_STATUS_OK && len > 1) {
    ++            evt_data.set_config.num_param_id = *p++;
    ++            if (evt_data.set_config.num_param_id > NFC_MAX_NUM_IDS) {
    ++                android_errorWriteLog(0x534e4554, "114047681");
    ++                LOG(ERROR) << StringPrintf("OOB write num_param_id %d",
    ++                                       evt_data.set_config.num_param_id);
    ++                evt_data.set_config.num_param_id = 0;
    ++            } else if (evt_data.set_config.num_param_id <= len - 2) {
    ++                STREAM_TO_ARRAY(evt_data.set_config.param_ids, p,
    ++                        evt_data.set_config.num_param_id);
    ++            } else {
    ++                LOG(ERROR) << StringPrintf("Insufficient RSP length %d,num_param_id %d",
    ++                                       len, evt_data.set_config.num_param_id);
    ++                evt_data.set_config.num_param_id = 0;
    ++            }
    ++	}
    +         (*nfc_cb.p_resp_cback) (NFC_SET_CONFIG_REVT, &evt_data);
    +     }
    + }
    +@@ -1171,8 +1189,13 @@ void nfc_ncif_proc_get_routing (UINT8 *p, UINT8 len)
    +             {
    +                 tl                  = *(p+1);
    +                 tl                 += NFC_TL_SIZE;
    +-                STREAM_TO_ARRAY (pn, p, tl);
    +                 evt_data.tlv_size  += tl;
    ++		if (evt_data.tlv_size > NFC_MAX_EE_TLV_SIZE) {
    ++                    android_errorWriteLog(0x534e4554, "117554809");
    ++                    LOG(ERROR) << __func__ << "Invalid data format";
    ++                    return;
    ++                }
    ++                STREAM_TO_ARRAY(pn, p, tl);
    +                 pn                 += tl;
    +             }
    +             (*nfc_cb.p_resp_cback) (NFC_GET_ROUTING_REVT, (tNFC_RESPONSE *) &evt_data);
     diff --git a/src/nfc/tags/rw_t2t_ndef.c b/src/nfc/tags/rw_t2t_ndef.c
     index 3304a90..42a558e 100644
     --- a/src/nfc/tags/rw_t2t_ndef.c
    diff --git a/external_neven.patch b/external_neven.patch
    index d1869e6..e69de29 100644
    --- a/external_neven.patch
    +++ b/external_neven.patch
    @@ -1,13 +0,0 @@
    -diff --git a/Embedded/common/src/b_BitFeatureEm/Scanner.c b/Embedded/common/src/b_BitFeatureEm/Scanner.c
    -index 327e714..1a0ae2a 100644
    ---- a/Embedded/common/src/b_BitFeatureEm/Scanner.c
    -+++ b/Embedded/common/src/b_BitFeatureEm/Scanner.c
    -@@ -1064,7 +1064,7 @@ void bbf_Scanner_addOutPos( struct bbs_Context* cpA,
    - 							uint32 scaleA, 
    - 							int32 actA )
    - {
    --	if( ( ptrA->outCountE * 4 ) < ptrA->outArrE.sizeE )
    -+	if( ( ptrA->outCountE * 4 + 3 ) < ptrA->outArrE.sizeE )
    - 	{
    -         ptrA->outArrE.arrPtrE[ ptrA->outCountE * 4 + 0 ] = xA;
    -         ptrA->outArrE.arrPtrE[ ptrA->outCountE * 4 + 1 ] = yA;
    diff --git a/external_svox.patch b/external_svox.patch
    index c5ecb05..e69de29 100644
    --- a/external_svox.patch
    +++ b/external_svox.patch
    @@ -1,27 +0,0 @@
    -diff --git a/pico/tts/svox_ssml_parser.cpp b/pico/tts/svox_ssml_parser.cpp
    -index 1e86940..94cd25a 100755
    ---- a/pico/tts/svox_ssml_parser.cpp
    -+++ b/pico/tts/svox_ssml_parser.cpp
    -@@ -57,7 +57,12 @@ SvoxSsmlParser::SvoxSsmlParser() : m_isInBreak(0), m_appendix(NULL), m_docLangua
    -         XML_SetUserData(mParser, (void*)this);
    -         m_datasize = 512;
    -         m_data = new char[m_datasize];
    --        m_data[0] = '\0';
    -+        if (!m_data)
    -+        {
    -+            ALOGE("Error: failed to allocate memory for string!\n");
    -+        } else {
    -+            memset(m_data, 0, m_datasize);
    -+        }
    -     }
    - }
    - 
    -@@ -120,6 +125,8 @@ void SvoxSsmlParser::startElement(const XML_Char* element, const XML_Char** attr
    -             {
    -                 ALOGE("Error: failed to allocate memory for string!\n");
    -                 return;
    -+            } else {
    -+                memset(m_data, 0, m_datasize);
    -             }
    -         }
    - 
    diff --git a/external_wpa_supplicant_8.patch b/external_wpa_supplicant_8.patch
    index 68fc032..ca73422 100644
    --- a/external_wpa_supplicant_8.patch
    +++ b/external_wpa_supplicant_8.patch
    @@ -666,6 +666,24 @@ index efc1d7e..0000000
     -}
     -
     -#endif /* CONFIG_PEERKEY */
    +diff --git a/src/ap/wnm_ap.c b/src/ap/wnm_ap.c
    +index 41d50ce..02daa9b 100644
    +--- a/src/ap/wnm_ap.c
    ++++ b/src/ap/wnm_ap.c
    +@@ -202,6 +202,13 @@ static void ieee802_11_rx_wnmsleep_req(struct hostapd_data *hapd,
    + 	u8 *tfsreq_ie_end = NULL;
    + 	u16 tfsreq_ie_len = 0;
    + 
    ++	if (len < 1) {
    ++		wpa_printf(MSG_DEBUG,
    ++			   "WNM: Ignore too short WNM-Sleep Mode Request from "
    ++			   MACSTR, MAC2STR(addr));
    ++		return;
    ++	}
    ++
    + 	dialog_token = *pos++;
    + 	while (pos + 1 < frm + len) {
    + 		u8 ie_len = pos[1];
     diff --git a/src/ap/wpa_auth.c b/src/ap/wpa_auth.c
     index 3587086..e5974ff 100644
     --- a/src/ap/wpa_auth.c
    diff --git a/frameworks_ex.patch b/frameworks_ex.patch
    index b17a126..e69de29 100644
    --- a/frameworks_ex.patch
    +++ b/frameworks_ex.patch
    @@ -1,27 +0,0 @@
    -diff --git a/framesequence/jni/FrameSequence_gif.cpp b/framesequence/jni/FrameSequence_gif.cpp
    -index 5118319..f6f46da 100644
    ---- a/framesequence/jni/FrameSequence_gif.cpp
    -+++ b/framesequence/jni/FrameSequence_gif.cpp
    -@@ -111,12 +111,14 @@ FrameSequence_gif::FrameSequence_gif(Stream* stream) :
    -     }
    - #endif
    - 
    --    if (mGif->SColorMap) {
    -+    const ColorMapObject* cmap = mGif->SColorMap;
    -+    if (cmap) {
    -         // calculate bg color
    -         GraphicsControlBlock gcb;
    -         DGifSavedExtensionToGCB(mGif, 0, &gcb);
    --        if (gcb.TransparentColor == NO_TRANSPARENT_COLOR) {
    --            mBgColor = gifColorToColor8888(mGif->SColorMap->Colors[mGif->SBackGroundColor]);
    -+        if (gcb.TransparentColor == NO_TRANSPARENT_COLOR
    -+                && mGif->SBackGroundColor < cmap->ColorCount) {
    -+            mBgColor = gifColorToColor8888(cmap->Colors[mGif->SBackGroundColor]);
    -         }
    -     }
    - }
    -@@ -359,4 +361,3 @@ static RegistryEntry gEntry = {
    -         acceptsBuffers,
    - };
    - static Registry gRegister(gEntry);
    --
    diff --git a/packages_apps_messaging.patch b/packages_apps_messaging.patch
    index 140fa4d..447d1a9 100644
    --- a/packages_apps_messaging.patch
    +++ b/packages_apps_messaging.patch
    @@ -26,92 +26,3 @@ index d50cf47..6801165 100644
          }
      
          @Override
    -diff --git a/src/com/android/messaging/ui/conversationlist/ShareIntentActivity.java b/src/com/android/messaging/ui/conversationlist/ShareIntentActivity.java
    -index 83b7be9..1c91e46 100644
    ---- a/src/com/android/messaging/ui/conversationlist/ShareIntentActivity.java
    -+++ b/src/com/android/messaging/ui/conversationlist/ShareIntentActivity.java
    -@@ -35,6 +35,7 @@ import com.android.messaging.util.ContentType;
    - import com.android.messaging.util.LogUtil;
    - import com.android.messaging.util.MediaMetadataRetrieverWrapper;
    - import com.android.messaging.util.FileUtil;
    -+import com.android.messaging.util.UriUtil;
    - 
    - import java.io.IOException;
    - import java.util.ArrayList;
    -@@ -75,6 +76,12 @@ public class ShareIntentActivity extends BaseBugleActivity implements
    -         final String action = intent.getAction();
    -         if (Intent.ACTION_SEND.equals(action)) {
    -             final Uri contentUri = (Uri) intent.getParcelableExtra(Intent.EXTRA_STREAM);
    -+            if (UriUtil.isFileUri(contentUri)) {
    -+                LogUtil.i(
    -+                    LogUtil.BUGLE_TAG,
    -+                    "Ignoring attachment from file URI which are no longer supported.");
    -+                return;
    -+            }
    -             final String contentType = extractContentType(contentUri, intent.getType());
    -             if (LogUtil.isLoggable(LogUtil.BUGLE_TAG, LogUtil.DEBUG)) {
    -                 LogUtil.d(LogUtil.BUGLE_TAG, String.format(
    -@@ -112,6 +119,12 @@ public class ShareIntentActivity extends BaseBugleActivity implements
    -                 if (imageUris != null && imageUris.size() > 0) {
    -                     mDraftMessage = MessageData.createSharedMessage(null);
    -                     for (final Uri imageUri : imageUris) {
    -+                        if (UriUtil.isFileUri(imageUri)) {
    -+                            LogUtil.i(
    -+                                LogUtil.BUGLE_TAG,
    -+                                "Ignoring attachment from file URI which are no longer supported.");
    -+                            continue;
    -+                        }
    -                         final String actualContentType = extractContentType(imageUri, contentType);
    -                         addSharedImagePartToDraft(actualContentType, imageUri);
    -                     }
    -diff --git a/src/com/android/messaging/util/DebugUtils.java b/src/com/android/messaging/util/DebugUtils.java
    -index f2c1d65..1362f83 100644
    ---- a/src/com/android/messaging/util/DebugUtils.java
    -+++ b/src/com/android/messaging/util/DebugUtils.java
    -@@ -22,12 +22,15 @@ import android.app.FragmentManager;
    - import android.app.FragmentTransaction;
    - import android.content.Context;
    - import android.content.DialogInterface;
    -+import android.content.Intent;
    - import android.media.MediaPlayer;
    -+import android.net.Uri;
    - import android.os.Environment;
    - import android.telephony.SmsMessage;
    - import android.text.TextUtils;
    - import android.widget.ArrayAdapter;
    - 
    -+import com.android.messaging.Factory;
    - import com.android.messaging.R;
    - import com.android.messaging.datamodel.SyncManager;
    - import com.android.messaging.datamodel.action.DumpDatabaseAction;
    -@@ -179,6 +182,13 @@ public class DebugUtils {
    -             }
    -         });
    - 
    -+        arrayAdapter.add(new DebugAction("Test sharing a file URI") {
    -+            @Override
    -+            public void run() {
    -+                shareFileUri();
    -+            }
    -+        });
    -+
    -         builder.setAdapter(arrayAdapter,
    -                 new android.content.DialogInterface.OnClickListener() {
    -             @Override
    -@@ -422,4 +432,16 @@ public class DebugUtils {
    -     public static boolean debugClassZeroSmsEnabled() {
    -         return sDebugClassZeroSms;
    -     }
    -+
    -+    /** Shares a ringtone file via file URI. */
    -+    private static void shareFileUri() {
    -+        final String packageName = "com.android.messaging";
    -+        final String fileName = "/system/media/audio/ringtones/Andromeda.ogg";
    -+
    -+        Intent intent = new Intent(Intent.ACTION_SEND);
    -+        intent.setPackage(packageName);
    -+        intent.putExtra(Intent.EXTRA_STREAM, Uri.parse("file://" + fileName));
    -+        intent.setType("image/*");
    -+        Factory.get().getApplicationContext().startActivity(intent);
    -+    }
    - }
    diff --git a/system_bt.patch b/system_bt.patch
    index 4936f3b..d6efd66 100644
    --- a/system_bt.patch
    +++ b/system_bt.patch
    @@ -1,15 +1,240 @@
    -diff --git a/Android.mk b/Android.mk
    -index 29760e4e0..43a9592be 100644
    ---- a/Android.mk
    -+++ b/Android.mk
    -@@ -38,6 +38,7 @@ bluetooth_CFLAGS += \
    -   -Wno-gnu-variable-sized-type-not-at-end \
    -   -Wno-typedef-redefinition \
    -   -Wno-unused-parameter \
    -+  -Wno-unused-variable \
    -   -UNDEBUG \
    -   -DLOG_NDEBUG=1
    +diff --git a/bta/ag/bta_ag_act.c b/bta/ag/bta_ag_act.c
    +index 285a967c5..2d0e75ad8 100644
    +--- a/bta/ag/bta_ag_act.c
    ++++ b/bta/ag/bta_ag_act.c
    +@@ -68,7 +68,7 @@ const tBTA_SERVICE_MASK bta_ag_svc_mask[BTA_AG_NUM_IDX] =
    + };
    + 
    + typedef void (*tBTA_AG_ATCMD_CBACK)(tBTA_AG_SCB *p_scb, UINT16 cmd, UINT8 arg_type,
    +-                                    char *p_arg, INT16 int_arg);
    ++                                    char *p_arg, char* p_end, INT16 int_arg);
    + 
    + const tBTA_AG_ATCMD_CBACK bta_ag_at_cback_tbl[BTA_AG_NUM_IDX] =
    + {
    +diff --git a/bta/ag/bta_ag_at.c b/bta/ag/bta_ag_at.c
    +index 36061756d..2621b0997 100644
    +--- a/bta/ag/bta_ag_at.c
    ++++ b/bta/ag/bta_ag_at.c
    +@@ -25,6 +25,7 @@
    + #include <string.h>
    + #include "bt_common.h"
    + #include "bta_ag_at.h"
    ++#include "log/log.h"
    + #include "utl.h"
    + 
    + /*****************************************************************************
    +@@ -77,7 +78,7 @@ void bta_ag_at_reinit(tBTA_AG_AT_CB *p_cb)
    + ** Returns          void
    + **
    + ******************************************************************************/
    +-void bta_ag_process_at(tBTA_AG_AT_CB *p_cb)
    ++void bta_ag_process_at(tBTA_AG_AT_CB *p_cb, char* p_end)
    + {
    +     UINT16      idx;
    +     UINT8       arg_type;
    +@@ -97,7 +98,11 @@ void bta_ag_process_at(tBTA_AG_AT_CB *p_cb)
    +     {
    +         /* start of argument is p + strlen matching command */
    +         p_arg = p_cb->p_cmd_buf + strlen(p_cb->p_at_tbl[idx].p_cmd);
    +-
    ++        if (p_arg > p_end) {
    ++            //(*p_cb->p_err_cback)((tBTA_AG_SCB*)p_cb->p_user, false, nullptr);
    ++            android_errorWriteLog(0x534e4554, "112860487");
    ++            return;
    ++        }
    +         /* if no argument */
    +         if (p_arg[0] == 0)
    +         {
    +@@ -151,14 +156,14 @@ void bta_ag_process_at(tBTA_AG_AT_CB *p_cb)
    + 
    +                     (*p_cb->p_cmd_cback)(p_cb->p_user,
    +                                          p_cb->p_at_tbl[idx].command_id,
    +-                                         arg_type, p_arg, int_arg);
    ++                                         arg_type, p_arg, p_end, int_arg);
    +                 }
    +             }
    +             else
    +             {
    +                 (*p_cb->p_cmd_cback)(p_cb->p_user,
    +                                      p_cb->p_at_tbl[idx].command_id,
    +-                                     arg_type, p_arg, int_arg);
    ++                                     arg_type, p_arg, p_end, int_arg);
    +             }
    +         }
    +         /* else error */
    +@@ -216,8 +221,9 @@ void bta_ag_at_parse(tBTA_AG_AT_CB *p_cb, char *p_buf, UINT16 len)
    +                     (p_cb->p_cmd_buf[1] == 'T' || p_cb->p_cmd_buf[1] == 't'))
    +                 {
    +                     p_save = p_cb->p_cmd_buf;
    ++		    char* p_end = p_cb->p_cmd_buf + p_cb->cmd_pos;
    +                     p_cb->p_cmd_buf += 2;
    +-                    bta_ag_process_at(p_cb);
    ++                    bta_ag_process_at(p_cb, p_end);
    +                     p_cb->p_cmd_buf = p_save;
    +                 }
      
    +diff --git a/bta/ag/bta_ag_at.h b/bta/ag/bta_ag_at.h
    +index 4b78a33f3..b2dae6eb8 100644
    +--- a/bta/ag/bta_ag_at.h
    ++++ b/bta/ag/bta_ag_at.h
    +@@ -56,7 +56,7 @@ typedef struct
    + 
    + /* callback function executed when command is parsed */
    + typedef void (tBTA_AG_AT_CMD_CBACK)(void *p_user, UINT16 command_id, UINT8 arg_type,
    +-                                    char *p_arg, INT16 int_arg);
    ++                                    char *p_arg, char *p_end, INT16 int_arg);
    + 
    + /* callback function executed to send "ERROR" result code */
    + typedef void (tBTA_AG_AT_ERR_CBACK)(void *p_user, BOOLEAN unknown, char *p_arg);
    +diff --git a/bta/ag/bta_ag_cmd.c b/bta/ag/bta_ag_cmd.c
    +index ebc4f4fbe..bbb4214fd 100644
    +--- a/bta/ag/bta_ag_cmd.c
    ++++ b/bta/ag/bta_ag_cmd.c
    +@@ -29,6 +29,7 @@
    + #include "bta_ag_int.h"
    + #include "bta_api.h"
    + #include "bta_sys.h"
    ++#include "log/log.h"
    + #include "bt_common.h"
    + #include "osi/include/log.h"
    + #include "port_api.h"
    +@@ -412,25 +413,24 @@ static void bta_ag_send_ind(tBTA_AG_SCB *p_scb, UINT16 id, UINT16 value, BOOLEAN
    + ** Returns          TRUE if parsed ok, FALSE otherwise.
    + **
    + *******************************************************************************/
    +-static BOOLEAN bta_ag_parse_cmer(char *p_s, BOOLEAN *p_enabled)
    ++static BOOLEAN bta_ag_parse_cmer(char *p_s, char *p_end, BOOLEAN *p_enabled)
    + {
    +     INT16   n[4] = {-1, -1, -1, -1};
    +     int     i;
    +     char    *p;
    + 
    +-    for (i = 0; i < 4; i++)
    ++    for (i = 0; i < 4; i++, p_s = p + 1)
    +     {
    +         /* skip to comma delimiter */
    +-        for (p = p_s; *p != ',' && *p != 0; p++);
    ++        for (p = p_s; p < p_end && *p != ',' && *p != 0; p++);
    + 
    +         /* get integer value */
    ++	if (p > p_end) {
    ++            android_errorWriteLog(0x534e4554, "112860487");
    ++            return false;
    ++        }
    +         *p = 0;
    +         n[i] = utl_str2int(p_s);
    +-        p_s = p + 1;
    +-        if (p_s == 0)
    +-        {
    +-            break;
    +-        }
    +     }
    + 
    +     /* process values */
    +@@ -496,7 +496,7 @@ static UINT8 bta_ag_parse_chld(tBTA_AG_SCB *p_scb, char *p_s)
    + ** Returns          Returns bitmap of supported codecs.
    + **
    + *******************************************************************************/
    +-static tBTA_AG_PEER_CODEC bta_ag_parse_bac(tBTA_AG_SCB *p_scb, char *p_s)
    ++static tBTA_AG_PEER_CODEC bta_ag_parse_bac(tBTA_AG_SCB *p_scb, char *p_s, char *p_end)
    + {
    +     tBTA_AG_PEER_CODEC  retval = BTA_AG_CODEC_NONE;
    +     UINT16  uuid_codec;
    +@@ -506,9 +506,13 @@ static tBTA_AG_PEER_CODEC bta_ag_parse_bac(tBTA_AG_SCB *p_scb, char *p_s)
    +     while(p_s)
    +     {
    +         /* skip to comma delimiter */
    +-        for(p = p_s; *p != ',' && *p != 0; p++);
    ++        for(p = p_s; p < p_end && *p != ',' && *p != 0; p++);
    + 
    +         /* get integre value */
    ++	if (p > p_end) {
    ++            android_errorWriteLog(0x534e4554, "112860487");
    ++            break;
    ++        }
    +         if (*p != 0)
    +         {
    +             *p = 0;
    +@@ -660,7 +664,7 @@ void bta_ag_send_call_inds(tBTA_AG_SCB *p_scb, tBTA_AG_RES result)
    + **
    + *******************************************************************************/
    + void bta_ag_at_hsp_cback(tBTA_AG_SCB *p_scb, UINT16 command_id, UINT8 arg_type,
    +-                                char *p_arg, INT16 int_arg)
    ++                                char *p_arg, char *p_end, INT16 int_arg)
    + {
    +     APPL_TRACE_DEBUG("AT cmd:%d arg_type:%d arg:%d arg:%s", command_id, arg_type,
    +                       int_arg, p_arg);
    +@@ -671,6 +675,13 @@ void bta_ag_at_hsp_cback(tBTA_AG_SCB *p_scb, UINT16 command_id, UINT8 arg_type,
    +     val.hdr.handle = bta_ag_scb_to_idx(p_scb);
    +     val.hdr.app_id = p_scb->app_id;
    +     val.num = (UINT16) int_arg;
    ++ 
    ++    if ((p_end - p_arg + 1) >= (long)sizeof(val.str)) {
    ++        APPL_TRACE_ERROR("%s: p_arg is too long, send error and return", __func__);
    ++        bta_ag_send_error(p_scb, BTA_AG_ERR_TEXT_TOO_LONG);
    ++        android_errorWriteLog(0x534e4554, "112860487");
    ++        return;
    ++    }
    +     strlcpy(val.str, p_arg, BTA_AG_AT_MAX_LEN);
    + 
    +     /* call callback with event */
    +@@ -904,7 +915,7 @@ static bool bta_ag_parse_biev_response(tBTA_AG_SCB *p_scb, tBTA_AG_VAL *val)
    + **
    + *******************************************************************************/
    + void bta_ag_at_hfp_cback(tBTA_AG_SCB *p_scb, UINT16 cmd, UINT8 arg_type,
    +-                                char *p_arg, INT16 int_arg)
    ++                                char *p_arg, char *p_end, INT16 int_arg)
    + {
    +     tBTA_AG_VAL     val;
    +     tBTA_AG_SCB     *ag_scb;
    +@@ -929,6 +940,13 @@ void bta_ag_at_hfp_cback(tBTA_AG_SCB *p_scb, UINT16 cmd, UINT8 arg_type,
    +     val.hdr.status = BTA_AG_SUCCESS;
    +     val.num = int_arg;
    +     bdcpy(val.bd_addr, p_scb->peer_addr);
    ++ 
    ++    if ((p_end - p_arg + 1) >= (long)sizeof(val.str)) {
    ++        APPL_TRACE_ERROR("%s: p_arg is too long, send error and return", __func__);
    ++        bta_ag_send_error(p_scb, BTA_AG_ERR_TEXT_TOO_LONG);
    ++        android_errorWriteLog(0x534e4554, "112860487");
    ++        return;
    ++    }
    +     strlcpy(val.str, p_arg, BTA_AG_AT_MAX_LEN);
    + 
    +     /**
    +@@ -1115,7 +1133,7 @@ void bta_ag_at_hfp_cback(tBTA_AG_SCB *p_scb, UINT16 cmd, UINT8 arg_type,
    + 
    +         case BTA_AG_LOCAL_EVT_CMER:
    +             /* if parsed ok store setting, send OK */
    +-            if (bta_ag_parse_cmer(p_arg, &p_scb->cmer_enabled))
    ++	    if (bta_ag_parse_cmer(p_arg, p_end, &p_scb->cmer_enabled))
    +             {
    +                 bta_ag_send_ok(p_scb);
    + 
    +@@ -1304,7 +1322,7 @@ void bta_ag_at_hfp_cback(tBTA_AG_SCB *p_scb, UINT16 cmd, UINT8 arg_type,
    +             /* store available codecs from the peer */
    +             if((p_scb->peer_features & BTA_AG_PEER_FEAT_CODEC) && (p_scb->features & BTA_AG_FEAT_CODEC))
    +             {
    +-                p_scb->peer_codecs = bta_ag_parse_bac(p_scb, p_arg);
    ++                p_scb->peer_codecs = bta_ag_parse_bac(p_scb, p_arg, p_end);
    +                 p_scb->codec_updated = TRUE;
    + 
    +                 if (p_scb->peer_codecs & BTA_AG_CODEC_MSBC)
    +diff --git a/bta/ag/bta_ag_int.h b/bta/ag/bta_ag_int.h
    +index c1e685f28..eac98c292 100644
    +--- a/bta/ag/bta_ag_int.h
    ++++ b/bta/ag/bta_ag_int.h
    +@@ -378,9 +378,9 @@ extern void bta_ag_sco_conn_rsp(tBTA_AG_SCB *p_scb, tBTM_ESCO_CONN_REQ_EVT_DATA
    + 
    + /* AT command functions */
    + extern void bta_ag_at_hsp_cback(tBTA_AG_SCB *p_scb, UINT16 cmd, UINT8 arg_type,
    +-                                char *p_arg, INT16 int_arg);
    ++                                char *p_arg, char *p_end, INT16 int_arg);
    + extern void bta_ag_at_hfp_cback(tBTA_AG_SCB *p_scb, UINT16 cmd, UINT8 arg_type,
    +-                                char *p_arg, INT16 int_arg);
    ++                                char *p_arg, char *p_end, INT16 int_arg);
    + extern void bta_ag_at_err_cback(tBTA_AG_SCB *p_scb, BOOLEAN unknown, char *p_arg);
    + extern BOOLEAN bta_ag_inband_enabled(tBTA_AG_SCB *p_scb);
    + extern void bta_ag_send_call_inds(tBTA_AG_SCB *p_scb, tBTA_AG_RES result);
     diff --git a/bta/av/bta_av_act.c b/bta/av/bta_av_act.c
     index 9cc802f0a..7154865c6 100644
     --- a/bta/av/bta_av_act.c
    @@ -42,7 +267,7 @@ index 9cc802f0a..7154865c6 100644
                      p_rc_rsp->get_caps.status = AVRC_STS_INTERNAL_ERR;
                  }
     diff --git a/bta/dm/bta_dm_act.c b/bta/dm/bta_dm_act.c
    -index 1bf741d92..3884a5c55 100644
    +index 1bf741d92..7870a02b1 100644
     --- a/bta/dm/bta_dm_act.c
     +++ b/bta/dm/bta_dm_act.c
     @@ -26,6 +26,7 @@
    @@ -62,50 +287,7 @@ index 1bf741d92..3884a5c55 100644
      static void bta_dm_inq_results_cb (tBTM_INQ_RESULTS *p_inq, UINT8 *p_eir);
      static void bta_dm_inq_cmpl_cb (void * p_result);
      static void bta_dm_service_search_remname_cback (BD_ADDR bd_addr, DEV_CLASS dc, BD_NAME bd_name);
    -@@ -132,9 +135,11 @@ static void bta_dm_ctrl_features_rd_cmpl_cback(tBTM_STATUS result);
    - 
    - static void bta_dm_reset_sec_dev_pending(BD_ADDR remote_bd_addr);
    - static void bta_dm_remove_sec_dev_entry(BD_ADDR remote_bd_addr);
    -+#if (defined(BTA_GATT_INCLUDED) && BTA_GATT_INCLUDED)
    - static void bta_dm_observe_results_cb(tBTM_INQ_RESULTS *p_inq, UINT8 *p_eir);
    - static void bta_dm_observe_cmpl_cb(void * p_result);
    - static void bta_dm_delay_role_switch_cback(void *data);
    -+#endif
    - extern void sdpu_uuid16_to_uuid128(UINT16 uuid16, UINT8* p_uuid128);
    - static void bta_dm_disable_timer_cback(void *data);
    - 
    -@@ -383,7 +388,9 @@ static void bta_dm_sys_hw_cback( tBTA_SYS_HW_EVT status )
    - 
    -         /* hw is ready, go on with BTA DM initialization */
    -         alarm_free(bta_dm_search_cb.search_timer);
    -+#if (defined(BTA_GATT_INCLUDED) && BTA_GATT_INCLUDED)
    -         alarm_free(bta_dm_search_cb.gatt_close_timer);
    -+#endif
    -         memset(&bta_dm_search_cb, 0, sizeof(bta_dm_search_cb));
    -         /*
    -          * TODO: Should alarm_free() the bta_dm_search_cb timers during
    -@@ -391,8 +398,10 @@ static void bta_dm_sys_hw_cback( tBTA_SYS_HW_EVT status )
    -          */
    -         bta_dm_search_cb.search_timer =
    -           alarm_new("bta_dm_search.search_timer");
    -+#if (defined(BTA_GATT_INCLUDED) && BTA_GATT_INCLUDED)
    -         bta_dm_search_cb.gatt_close_timer =
    -           alarm_new("bta_dm_search.gatt_close_timer");
    -+#endif
    - 
    -         memset(&bta_dm_conn_srvcs, 0, sizeof(bta_dm_conn_srvcs));
    -         memset(&bta_dm_di_cb, 0, sizeof(tBTA_DM_DI_CB));
    -@@ -710,7 +719,9 @@ void bta_dm_remove_device(tBTA_DM_MSG *p_data)
    - 
    -     /* If ACL exists for the device in the remove_bond message*/
    -     BOOLEAN continue_delete_dev = FALSE;
    -+#if (defined(BTA_GATT_INCLUDED) && BTA_GATT_INCLUDED)
    -     UINT8 other_transport = BT_TRANSPORT_INVALID;
    -+#endif
    - 
    -     if (BTM_IsAclConnectionUp(p_dev->bd_addr, BT_TRANSPORT_LE) ||
    -         BTM_IsAclConnectionUp(p_dev->bd_addr, BT_TRANSPORT_BR_EDR))
    -@@ -1601,7 +1612,7 @@ void bta_dm_sdp_result (tBTA_DM_MSG *p_data)
    +@@ -1601,7 +1604,7 @@ void bta_dm_sdp_result (tBTA_DM_MSG *p_data)
      #endif
      
          UINT32 num_uuids = 0;
    @@ -114,7 +296,7 @@ index 1bf741d92..3884a5c55 100644
      
          if((p_data->sdp_event.sdp_result == SDP_SUCCESS)
              || (p_data->sdp_event.sdp_result == SDP_NO_RECS_MATCH)
    -@@ -1679,8 +1690,12 @@ void bta_dm_sdp_result (tBTA_DM_MSG *p_data)
    +@@ -1679,8 +1682,12 @@ void bta_dm_sdp_result (tBTA_DM_MSG *p_data)
                                  (tBTA_SERVICE_MASK)(BTA_SERVICE_ID_TO_SERVICE_MASK(bta_dm_search_cb.service_index-1));
                              tmp_svc = bta_service_id_to_uuid_lkup_tbl[bta_dm_search_cb.service_index-1];
                              /* Add to the list of UUIDs */
    @@ -129,7 +311,7 @@ index 1bf741d92..3884a5c55 100644
                          }
                      }
                  }
    -@@ -1719,8 +1734,12 @@ void bta_dm_sdp_result (tBTA_DM_MSG *p_data)
    +@@ -1719,8 +1726,12 @@ void bta_dm_sdp_result (tBTA_DM_MSG *p_data)
                      {
                          if (SDP_FindServiceUUIDInRec_128bit(p_sdp_rec, &temp_uuid))
                          {
    @@ -144,7 +326,7 @@ index 1bf741d92..3884a5c55 100644
                          }
                      }
                  } while (p_sdp_rec);
    -@@ -3322,12 +3341,16 @@ void bta_dm_acl_change(tBTA_DM_MSG *p_data)
    +@@ -3322,12 +3333,16 @@ void bta_dm_acl_change(tBTA_DM_MSG *p_data)
              }
              if (conn.link_down.is_removed)
              {
    @@ -164,19 +346,6 @@ index 1bf741d92..3884a5c55 100644
      #endif
               }
      
    -diff --git a/bta/dm/bta_dm_api.c b/bta/dm/bta_dm_api.c
    -index 82dd8b229..f7a607ee6 100644
    ---- a/bta/dm/bta_dm_api.c
    -+++ b/bta/dm/bta_dm_api.c
    -@@ -1231,6 +1231,8 @@ void BTA_DmDiscoverByTransport(BD_ADDR bd_addr, tBTA_SERVICE_MASK_EXT *p_service
    - {
    - #if BLE_INCLUDED == TRUE && BTA_GATT_INCLUDED == TRUE
    -     bta_dm_discover_send_msg(bd_addr, p_services, p_cback, sdp_search, transport);
    -+#else
    -+return;
    - #endif
    - }
    - 
     diff --git a/bta/gatt/bta_gattc_cache.c b/bta/gatt/bta_gattc_cache.c
     index 63c424696..45d258824 100644
     --- a/bta/gatt/bta_gattc_cache.c
    @@ -190,6 +359,31 @@ index 63c424696..45d258824 100644
              APPL_TRACE_ERROR("%s: can't read GATT attributes: %s", __func__, fname);
              goto done;
          }
    +diff --git a/bta/hh/bta_hh_act.c b/bta/hh/bta_hh_act.c
    +index f799e67e4..7d0e5bd0b 100644
    +--- a/bta/hh/bta_hh_act.c
    ++++ b/bta/hh/bta_hh_act.c
    +@@ -26,6 +26,7 @@
    + 
    + #if defined(BTA_HH_INCLUDED) && (BTA_HH_INCLUDED == TRUE)
    + 
    ++#include <log/log.h>
    + #include <string.h>
    + 
    + #include "bta_sys.h"
    +@@ -764,6 +765,12 @@ void bta_hh_ctrl_dat_act(tBTA_HH_DEV_CB *p_cb, tBTA_HH_DATA * p_data)
    +     APPL_TRACE_DEBUG("Ctrl DATA received w4: event[%s]",
    +                         bta_hh_get_w4_event(p_cb->w4_evt));
    + #endif
    ++    if (pdata->len == 0) {
    ++        android_errorWriteLog(0x534e4554, "116108738");
    ++        p_cb->w4_evt = 0;
    ++        osi_free_and_reset((void**)&pdata);
    ++        return;
    ++    }
    +     hs_data.status  = BTA_HH_OK;
    +     hs_data.handle  = p_cb->hid_handle;
    + 
     diff --git a/bta/pan/bta_pan_act.c b/bta/pan/bta_pan_act.c
     index 199547817..4367fce68 100644
     --- a/bta/pan/bta_pan_act.c
    @@ -254,91 +448,6 @@ index 199547817..4367fce68 100644
          fixed_queue_enqueue(p_scb->data_queue, p_new_buf);
          BT_HDR *p_event = (BT_HDR *)osi_malloc(sizeof(BT_HDR));
          p_event->layer_specific = handle;
    -diff --git a/btif/src/btif_dm.c b/btif/src/btif_dm.c
    -index f54b64277..38c324c9e 100644
    ---- a/btif/src/btif_dm.c
    -+++ b/btif/src/btif_dm.c
    -@@ -52,6 +52,7 @@
    - #include "btu.h"
    - #include "bt_common.h"
    - #include "bta_gatt_api.h"
    -+#include "bta_api.h"
    - #include "device/include/interop.h"
    - #include "include/stack_config.h"
    - #include "osi/include/allocator.h"
    -@@ -234,12 +235,12 @@ static void btif_dm_ble_passkey_req_evt(tBTA_DM_PIN_REQ *p_pin_req);
    - static void btif_dm_ble_key_nc_req_evt(tBTA_DM_SP_KEY_NOTIF *p_notif_req) ;
    - static void btif_dm_ble_oob_req_evt(tBTA_DM_SP_RMT_OOB *req_oob_type);
    - static void btif_dm_ble_sc_oob_req_evt(tBTA_DM_SP_RMT_OOB *req_oob_type);
    --#endif
    - 
    - static void bte_scan_filt_param_cfg_evt(UINT8 action_type,
    -                                            tBTA_DM_BLE_PF_AVBL_SPACE avbl_space,
    -                                            tBTA_DM_BLE_REF_VALUE ref_value,
    -                                            tBTA_STATUS status);
    -+#endif
    - 
    - static char* btif_get_default_local_name();
    - 
    -@@ -2241,7 +2242,6 @@ static void bta_energy_info_cb(tBTA_DM_BLE_TX_TIME_MS tx_time, tBTA_DM_BLE_RX_TI
    -     btif_transfer_context(btif_dm_upstreams_evt, BTA_DM_ENER_INFO_READ,
    -                           (char*) &btif_cb, sizeof(btif_activity_energy_info_cb_t), NULL);
    - }
    --#endif
    - 
    - /*******************************************************************************
    - **
    -@@ -2269,6 +2269,7 @@ static void bte_scan_filt_param_cfg_evt(UINT8 action_type,
    -     }
    - }
    - 
    -+#endif
    - /*****************************************************************************
    - **
    - **   btif api functions (no context switch)
    -@@ -2395,6 +2396,7 @@ bt_status_t btif_dm_create_bond_out_of_band(const bt_bdaddr_t *bd_addr, int tran
    -     bdcpy(oob_cb.bdaddr, bd_addr->address);
    -     memcpy(&oob_cb.oob_data, oob_data, sizeof(bt_out_of_band_data_t));
    - 
    -+#if (defined(BLE_INCLUDED) && (BLE_INCLUDED == TRUE))
    -     uint8_t empty[] = {0, 0, 0, 0, 0, 0, 0};
    -     // If LE Bluetooth Device Address is provided, use provided address type
    -     // value.
    -@@ -2407,6 +2409,7 @@ bt_status_t btif_dm_create_bond_out_of_band(const bt_bdaddr_t *bd_addr, int tran
    -             BTM_SecAddBleDevice(bd_addr->address, NULL, BT_DEVICE_TYPE_BLE, address_type);
    -         }
    -     }
    -+#endif
    - 
    -     bdstr_t bdstr;
    -     BTIF_TRACE_EVENT("%s: bd_addr=%s, transport=%d", __FUNCTION__, bdaddr_to_string(bd_addr, bdstr, sizeof(bdstr)), transport);
    -@@ -2710,8 +2713,10 @@ bt_status_t btif_dm_get_remote_services_by_transport(bt_bdaddr_t *remote_addr, c
    -     mask_ext.p_uuid = NULL;
    -     mask_ext.srvc_mask = BTA_ALL_SERVICE_MASK;
    - 
    -+#if ((defined BLE_INCLUDED) && (BLE_INCLUDED == TRUE))
    -     BTA_DmDiscoverByTransport(remote_addr->address, &mask_ext,
    -                    bte_dm_search_services_evt, TRUE, transport);
    -+#endif
    - 
    -     return BT_STATUS_SUCCESS;
    - }
    -@@ -2957,6 +2962,7 @@ BOOLEAN btif_dm_get_smp_config(tBTE_APPL_CFG* p_cfg) {
    -     strncpy(conf, recv, 64);
    -     conf[63] = 0; // null terminate
    - 
    -+#if ((defined BLE_INCLUDED) && (BLE_INCLUDED == TRUE))
    -     if ((pch = strtok(conf, ",")) != NULL)
    -         p_cfg->ble_auth_req = (UINT8) strtoul(pch, &endptr, 16);
    -     else
    -@@ -2981,6 +2987,7 @@ BOOLEAN btif_dm_get_smp_config(tBTE_APPL_CFG* p_cfg) {
    -         p_cfg->ble_max_key_size =  (UINT8) strtoul(pch, &endptr, 16);
    -     else
    -         return FALSE;
    -+#endif
    - 
    -     return TRUE;
    - }
     diff --git a/btif/src/btif_hf.c b/btif/src/btif_hf.c
     index 6abf09901..9d963d1de 100644
     --- a/btif/src/btif_hf.c
    @@ -434,21 +543,10 @@ index d02dfa0b8..90d74cf53 100644
              return handle;
          }
     diff --git a/btif/src/btif_storage.c b/btif/src/btif_storage.c
    -index 83dcc8c47..139fcdcf5 100644
    +index 83dcc8c47..d02b09a55 100644
     --- a/btif/src/btif_storage.c
     +++ b/btif/src/btif_storage.c
    -@@ -163,8 +163,10 @@ extern void btif_gatts_add_bonded_dev_from_nv(BD_ADDR bda);
    - **  Internal Functions
    - ************************************************************************************/
    - 
    -+#if (BLE_INCLUDED == TRUE)
    - static bt_status_t btif_in_fetch_bonded_ble_device(const char *remote_bd_addr,int add,
    -                                               btif_bonded_devices_t *p_bonded_devices);
    -+#endif
    - static bt_status_t btif_in_fetch_bonded_device(const char *bdstr);
    - 
    - /************************************************************************************
    -@@ -229,6 +231,10 @@ static int prop2cfg(bt_bdaddr_t *remote_bd_addr, bt_property_t *prop)
    +@@ -229,6 +229,10 @@ static int prop2cfg(bt_bdaddr_t *remote_bd_addr, bt_property_t *prop)
                      bt_uuid_t *p_uuid = (bt_uuid_t*)prop->val + i;
                      memset(buf, 0, sizeof(buf));
                      uuid_to_string_legacy(p_uuid, buf);
    @@ -459,44 +557,6 @@ index 83dcc8c47..139fcdcf5 100644
                      strcat(value, buf);
                      //strcat(value, ";");
                      strcat(value, " ");
    -@@ -493,6 +499,7 @@ static bt_status_t btif_in_fetch_bonded_devices(btif_bonded_devices_t *p_bonded_
    -     return BT_STATUS_SUCCESS;
    - }
    - 
    -+#if (BLE_INCLUDED == TRUE)
    - static void btif_read_le_key(const uint8_t key_type, const size_t key_len, bt_bdaddr_t bd_addr,
    -                  const uint8_t addr_type, const bool add_key, bool *device_added, bool *key_found)
    - {
    -@@ -524,6 +531,7 @@ static void btif_read_le_key(const uint8_t key_type, const size_t key_len, bt_bd
    -         *key_found = true;
    -     }
    - }
    -+#endif
    - 
    - /*******************************************************************************
    -  * Functions
    -diff --git a/hci/src/hci_hal_h4.c b/hci/src/hci_hal_h4.c
    -index 9c7afe53d..0ea5dfd62 100644
    ---- a/hci/src/hci_hal_h4.c
    -+++ b/hci/src/hci_hal_h4.c
    -@@ -30,6 +30,7 @@
    - #include "osi/include/reactor.h"
    - #include "osi/include/thread.h"
    - #include "vendor.h"
    -+#include "bt_target.h"
    - 
    - #define HCI_HAL_SERIAL_BUFFER_SIZE 1026
    - #define HCI_BLE_EVENT 0x3e
    -@@ -238,7 +239,9 @@ static void event_uart_has_bytes(eager_reader_t *reader, UNUSED_ATTR void *conte
    -       LOG_ERROR(LOG_TAG, "%s Unknown HCI message type 0x%x (min=0x%x max=0x%x). Aborting...",
    -                 __func__, type_byte, DATA_TYPE_ACL, DATA_TYPE_EVENT);
    -       LOG_EVENT_INT(BT_HCI_UNKNOWN_MESSAGE_TYPE_NUM, type_byte);
    -+#if (!defined(LEGACY_BRCM_HCI) || (LEGACY_BRCM_HCI == FALSE))
    -       assert(false && "Unknown HCI message type");
    -+#endif
    -       return;
    -     }
    - 
     diff --git a/osi/src/alarm.c b/osi/src/alarm.c
     index 69ded69e4..5f9e42ce3 100644
     --- a/osi/src/alarm.c
    @@ -677,6 +737,179 @@ index adc1ae731..91a58403e 100644
                      p_cfg->num_codec++;
                      p_cfg->codec_info[0] = elem_len;
                      memcpy(&p_cfg->codec_info[1], p, tmp);
    +diff --git a/stack/avdt/avdt_scb_act.c b/stack/avdt/avdt_scb_act.c
    +index ed0b67536..350f28e41 100644
    +--- a/stack/avdt/avdt_scb_act.c
    ++++ b/stack/avdt/avdt_scb_act.c
    +@@ -23,6 +23,7 @@
    +  *
    +  ******************************************************************************/
    + 
    ++#include <cutils/log.h>
    + #include <string.h>
    + #include "bt_types.h"
    + #include "bt_target.h"
    +@@ -256,10 +257,14 @@ void avdt_scb_hdl_pkt_no_frag(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data)
    +     UINT16  offset;
    +     UINT16  ex_len;
    +     UINT8   pad_len = 0;
    ++    UINT16  len = p_data->p_pkt->len;
    + 
    +     p = p_start = (UINT8 *)(p_data->p_pkt + 1) + p_data->p_pkt->offset;
    + 
    +     /* parse media packet header */
    ++    offset = 12;
    ++    // AVDT_MSG_PRS_OCTET1(1) + AVDT_MSG_PRS_M_PT(1) + UINT16(2) + UINT32(4) + 4
    ++    if (offset > len) goto length_error;
    +     AVDT_MSG_PRS_OCTET1(p, o_v, o_p, o_x, o_cc);
    +     AVDT_MSG_PRS_M_PT(p, m_pt, marker);
    +     BE_STREAM_TO_UINT16(seq, p);
    +@@ -269,19 +274,20 @@ void avdt_scb_hdl_pkt_no_frag(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data)
    +     UNUSED(o_v);
    + 
    +     /* skip over any csrc's in packet */
    ++    offset += o_cc * 4;
    +     p += o_cc * 4;
    + 
    +     /* check for and skip over extension header */
    +     if (o_x)
    +     {
    ++	offset += 4;
    ++        if (offset > len) goto length_error;
    +         p += 2;
    +         BE_STREAM_TO_UINT16(ex_len, p);
    ++	offset += ex_len * 4;
    +         p += ex_len * 4;
    +     }
    + 
    +-    /* save our new offset */
    +-    offset = (UINT16) (p - p_start);
    +-
    +     /* adjust length for any padding at end of packet */
    +     if (o_p)
    +     {
    +@@ -325,6 +331,13 @@ void avdt_scb_hdl_pkt_no_frag(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data)
    +             osi_free_and_reset((void **)&p_data->p_pkt);
    +         }
    +     }
    ++    return;
    ++
    ++length_error:
    ++    android_errorWriteLog(0x534e4554, "111450156");
    ++    AVDT_TRACE_WARNING("%s: hdl packet length %d too short: must be at least %d",
    ++                       __func__, len, offset);
    ++    osi_free_and_reset((void**)&p_data->p_pkt);
    + }
    + 
    + #if AVDT_REPORTING == TRUE
    +@@ -343,14 +356,24 @@ UINT8 * avdt_scb_hdl_report(tAVDT_SCB *p_scb, UINT8 *p, UINT16 len)
    +     UINT8   *p_start = p;
    +     UINT32  ssrc;
    +     UINT8   o_v, o_p, o_cc;
    ++    UINT16  min_len = 0;
    +     AVDT_REPORT_TYPE    pt;
    +     tAVDT_REPORT_DATA   report, *p_rpt;
    ++    UINT8 sdes_type;
    + 
    +     AVDT_TRACE_DEBUG( "avdt_scb_hdl_report");
    +     if(p_scb->cs.p_report_cback)
    +     {
    +         p_rpt = &report;
    +         /* parse report packet header */
    ++	min_len += 8;
    ++        if (min_len > len) {
    ++            android_errorWriteLog(0x534e4554, "111450156");
    ++            AVDT_TRACE_WARNING(
    ++                "%s: hdl packet length %d too short: must be at least %d", __func__,
    ++                len, min_len);
    ++            goto avdt_scb_hdl_report_exit;
    ++        }
    +         AVDT_MSG_PRS_RPT_OCTET1(p, o_v, o_p, o_cc);
    +         pt = *p++;
    +         p += 2;
    +@@ -362,6 +385,14 @@ UINT8 * avdt_scb_hdl_report(tAVDT_SCB *p_scb, UINT8 *p, UINT16 len)
    +         switch(pt)
    +         {
    +         case AVDT_RTCP_PT_SR:   /* the packet type - SR (Sender Report) */
    ++	    min_len += 20;
    ++            if (min_len > len) {
    ++                android_errorWriteLog(0x534e4554, "111450156");
    ++                AVDT_TRACE_WARNING(
    ++                  "%s: hdl packet length %d too short: must be at least %d",
    ++                  __func__, len, min_len);
    ++                goto avdt_scb_hdl_report_exit;
    ++            }
    +             BE_STREAM_TO_UINT32(report.sr.ntp_sec, p);
    +             BE_STREAM_TO_UINT32(report.sr.ntp_frac, p);
    +             BE_STREAM_TO_UINT32(report.sr.rtp_time, p);
    +@@ -370,6 +401,14 @@ UINT8 * avdt_scb_hdl_report(tAVDT_SCB *p_scb, UINT8 *p, UINT16 len)
    +             break;
    + 
    +         case AVDT_RTCP_PT_RR:   /* the packet type - RR (Receiver Report) */
    ++	    min_len += 20;
    ++            if (min_len > len) {
    ++                android_errorWriteLog(0x534e4554, "111450156");
    ++                AVDT_TRACE_WARNING(
    ++                  "%s: hdl packet length %d too short: must be at least %d",
    ++                  __func__, len, min_len);
    ++                goto avdt_scb_hdl_report_exit;
    ++            }
    +             report.rr.frag_lost = *p;
    +             BE_STREAM_TO_UINT32(report.rr.packet_lost, p);
    +             report.rr.packet_lost &= 0xFFFFFF;
    +@@ -380,12 +419,42 @@ UINT8 * avdt_scb_hdl_report(tAVDT_SCB *p_scb, UINT8 *p, UINT16 len)
    +             break;
    + 
    +         case AVDT_RTCP_PT_SDES: /* the packet type - SDES (Source Description) */
    +-            if(*p == AVDT_RTCP_SDES_CNAME)
    ++            min_len += 1;
    ++            if (min_len > len) {
    ++                android_errorWriteLog(0x534e4554, "111450156");
    ++                AVDT_TRACE_WARNING(
    ++                 "%s: hdl packet length %d too short: must be at least %d",
    ++                  __func__, len, min_len);
    ++                goto avdt_scb_hdl_report_exit;
    ++            }
    ++            BE_STREAM_TO_UINT8(sdes_type, p);
    ++            if(sdes_type == AVDT_RTCP_SDES_CNAME)
    +             {
    +-                p_rpt = (tAVDT_REPORT_DATA *)(p+2);
    ++              UINT8 name_length;
    ++              min_len += 1;
    ++              if (min_len > len) {
    ++                android_errorWriteLog(0x534e4554, "111450156");
    ++                AVDT_TRACE_WARNING(
    ++                  "%s: hdl packet length %d too short: must be at least %d",
    ++                  __func__, len, min_len);
    ++                goto avdt_scb_hdl_report_exit;
    ++              }
    ++              BE_STREAM_TO_UINT8(name_length, p);
    ++              if (name_length > len - 2 || name_length > AVDT_MAX_CNAME_SIZE) {
    ++                result = AVDT_BAD_PARAMS;
    ++              } else {
    ++                BE_STREAM_TO_ARRAY(p, &(report.cname[0]), name_length);
    ++              }
    +             }
    +             else
    +             {
    ++	        if (min_len + 1 > len) {
    ++                    android_errorWriteLog(0x534e4554, "111450156");
    ++                    AVDT_TRACE_WARNING(
    ++                      "%s: hdl packet length %d too short: must be at least %d",
    ++                      __func__, len, min_len);
    ++                    goto avdt_scb_hdl_report_exit;
    ++                }
    +                 AVDT_TRACE_WARNING( " - SDES SSRC=0x%08x sc=%d %d len=%d %s",
    +                     ssrc, o_cc, *p, *(p+1), p+2);
    +                 result = AVDT_BUSY;
    +@@ -401,6 +470,7 @@ UINT8 * avdt_scb_hdl_report(tAVDT_SCB *p_scb, UINT8 *p, UINT16 len)
    +             (*p_scb->cs.p_report_cback)(avdt_scb_to_hdl(p_scb), pt, p_rpt);
    + 
    +     }
    ++avdt_scb_hdl_report_exit:
    +     p_start += len;
    +     return p_start;
    + }
     diff --git a/stack/avrc/avrc_pars_ct.c b/stack/avrc/avrc_pars_ct.c
     index 63cc38407..eb1ff99c5 100644
     --- a/stack/avrc/avrc_pars_ct.c
    @@ -1182,26 +1415,6 @@ index 13fb189e7..65acd33f6 100644
      }
      
      
    -diff --git a/stack/btm/btm_acl.c b/stack/btm/btm_acl.c
    -index 4819012b8..5a1d9fdbb 100644
    ---- a/stack/btm/btm_acl.c
    -+++ b/stack/btm/btm_acl.c
    -@@ -899,6 +899,7 @@ void BTM_SetDefaultLinkPolicy (UINT16 settings)
    - }
    - 
    - 
    -+#if (defined(BLE_INCLUDED) && (BLE_INCLUDED == TRUE))
    - void btm_use_preferred_conn_params(BD_ADDR bda) {
    -     tL2C_LCB *p_lcb = l2cu_find_lcb_by_bd_addr (bda, BT_TRANSPORT_LE);
    -     tBTM_SEC_DEV_REC    *p_dev_rec = btm_find_or_alloc_dev (bda);
    -@@ -934,6 +935,7 @@ void btm_use_preferred_conn_params(BD_ADDR bda) {
    -                                            0, 0);
    -     }
    - }
    -+#endif
    - 
    - /*******************************************************************************
    - **
     diff --git a/stack/btm/btm_dev.c b/stack/btm/btm_dev.c
     index 8df005bf8..b278dea8f 100644
     --- a/stack/btm/btm_dev.c
    @@ -1260,53 +1473,6 @@ index 688ed889d..9f9ed0a50 100644
      #if BLE_INCLUDED == TRUE
            gatt_free();
      #endif
    -diff --git a/stack/gap/gap_conn.c b/stack/gap/gap_conn.c
    -index 1ee2c97b4..72861c3d7 100644
    ---- a/stack/gap/gap_conn.c
    -+++ b/stack/gap/gap_conn.c
    -@@ -203,6 +203,7 @@ UINT16 GAP_ConnOpen (char *p_serv_name, UINT8 service_id, BOOLEAN is_server,
    -         }
    -     }
    - 
    -+#if BLE_INCLUDED == TRUE
    -     if (transport == BT_TRANSPORT_LE)
    -     {
    -         p_ccb->psm = L2CA_REGISTER_COC (psm, &gap_cb.conn.reg_info,
    -@@ -215,6 +216,7 @@ UINT16 GAP_ConnOpen (char *p_serv_name, UINT8 service_id, BOOLEAN is_server,
    -         }
    -     }
    - 
    -+#endif
    -     /* Register with Security Manager for the specific security level */
    -     p_ccb->service_id = service_id;
    -     if (!BTM_SetSecurityLevel ((UINT8)!is_server, p_serv_name,
    -@@ -274,6 +276,7 @@ UINT16 GAP_ConnOpen (char *p_serv_name, UINT8 service_id, BOOLEAN is_server,
    -             }
    -         }
    - 
    -+#if BLE_INCLUDED == TRUE
    -         if (p_rem_bda && (transport == BT_TRANSPORT_LE))
    -         {
    -             cid = L2CA_CONNECT_COC_REQ (p_ccb->psm, p_rem_bda, &p_ccb->local_coc_cfg);
    -@@ -283,6 +286,7 @@ UINT16 GAP_ConnOpen (char *p_serv_name, UINT8 service_id, BOOLEAN is_server,
    -                 return (p_ccb->gap_handle);
    -             }
    -         }
    -+#endif
    - 
    -         gap_release_ccb (p_ccb);
    -         return (GAP_INVALID_HANDLE);
    -@@ -1229,8 +1233,10 @@ static void gap_release_ccb (tGAP_CCB *p_ccb)
    -     if (p_ccb->transport == BT_TRANSPORT_BR_EDR)
    -         L2CA_DEREGISTER (psm);
    - 
    -+#if BLE_INCLUDED == TRUE
    -     if(p_ccb->transport == BT_TRANSPORT_LE)
    -         L2CA_DEREGISTER_COC (psm);
    -+#endif
    - }
    - 
    - #if (GAP_CONN_POST_EVT_INCLUDED == TRUE)
     diff --git a/stack/gatt/gatt_cl.c b/stack/gatt/gatt_cl.c
     index 433a2f1dc..6a50d5e21 100644
     --- a/stack/gatt/gatt_cl.c
    @@ -1466,26 +1632,6 @@ index dcc37bc72..1c751f3f5 100644
      #define RFCOMM_FRAME_IS_CMD(initiator, cr)                  \
          (( (initiator) && !(cr)) || (!(initiator) &&  (cr)))
      
    -diff --git a/stack/l2cap/l2c_api.c b/stack/l2cap/l2c_api.c
    -index 62012c675..e4116a791 100644
    ---- a/stack/l2cap/l2c_api.c
    -+++ b/stack/l2cap/l2c_api.c
    -@@ -332,6 +332,7 @@ UINT16 L2CA_ErtmConnectReq (UINT16 psm, BD_ADDR p_bd_addr, tL2CAP_ERTM_INFO *p_e
    -     return (p_ccb->local_cid);
    - }
    - 
    -+#if (BLE_INCLUDED == TRUE)
    - /*******************************************************************************
    - **
    - ** Function         L2CA_RegisterLECoc
    -@@ -544,6 +545,7 @@ UINT16 L2CA_ConnectLECocReq(UINT16 psm, BD_ADDR p_bd_addr, tL2CAP_LE_CFG_INFO *p
    -     /* Return the local CID as our handle */
    -     return p_ccb->local_cid;
    - }
    -+#endif
    - 
    - /*******************************************************************************
    - **
     diff --git a/stack/l2cap/l2c_ble.c b/stack/l2cap/l2c_ble.c
     index 95de4e34c..f5072e364 100644
     --- a/stack/l2cap/l2c_ble.c
    @@ -1593,163 +1739,8 @@ index 95de4e34c..f5072e364 100644
                  STREAM_TO_UINT16 (rcid, p);
                  STREAM_TO_UINT16 (lcid, p);
      
    -diff --git a/stack/l2cap/l2c_csm.c b/stack/l2cap/l2c_csm.c
    -index dedffc8a5..67bdc4049 100644
    ---- a/stack/l2cap/l2c_csm.c
    -+++ b/stack/l2cap/l2c_csm.c
    -@@ -169,6 +169,7 @@ static void l2c_csm_closed (tL2C_CCB *p_ccb, UINT16 event, void *p_data)
    -         break;
    - 
    -     case L2CEVT_LP_CONNECT_CFM:                         /* Link came up         */
    -+#if (BLE_INCLUDED == TRUE)
    -         if (p_ccb->p_lcb->transport == BT_TRANSPORT_LE)
    -         {
    -             p_ccb->chnl_state = CST_ORIG_W4_SEC_COMP;
    -@@ -176,6 +177,7 @@ static void l2c_csm_closed (tL2C_CCB *p_ccb, UINT16 event, void *p_data)
    -                     &l2c_link_sec_comp, p_ccb);
    -         }
    -         else
    -+#endif
    -         {
    -             p_ccb->chnl_state = CST_ORIG_W4_SEC_COMP;
    -             btm_sec_l2cap_access_req (p_ccb->p_lcb->remote_bd_addr, p_ccb->p_rcb->psm,
    -@@ -195,6 +197,7 @@ static void l2c_csm_closed (tL2C_CCB *p_ccb, UINT16 event, void *p_data)
    -         break;
    - 
    -     case L2CEVT_L2CA_CONNECT_REQ:                       /* API connect request  */
    -+#if (BLE_INCLUDED == TRUE)
    -         if (p_ccb->p_lcb->transport == BT_TRANSPORT_LE)
    -         {
    -             p_ccb->chnl_state = CST_ORIG_W4_SEC_COMP;
    -@@ -202,6 +205,7 @@ static void l2c_csm_closed (tL2C_CCB *p_ccb, UINT16 event, void *p_data)
    -                     &l2c_link_sec_comp, p_ccb);
    -         }
    -         else
    -+#endif
    -         {
    -             /* Cancel sniff mode if needed */
    -             {
    -@@ -258,6 +262,7 @@ Event uninit_use_in_call: Using uninitialized value "settings.min" in call to fu
    -         /* stop link timer to avoid race condition between A2MP, Security, and L2CAP */
    -         alarm_cancel(p_ccb->p_lcb->l2c_lcb_timer);
    - 
    -+#if (BLE_INCLUDED == TRUE)
    -         if (p_ccb->p_lcb->transport == BT_TRANSPORT_LE)
    -         {
    -             p_ccb->chnl_state = CST_TERM_W4_SEC_COMP;
    -@@ -265,6 +270,7 @@ Event uninit_use_in_call: Using uninitialized value "settings.min" in call to fu
    -                     &l2c_link_sec_comp, p_ccb);
    -         }
    -         else
    -+#endif
    -         {
    -             /* Cancel sniff mode if needed */
    -             {
    -@@ -358,12 +364,14 @@ static void l2c_csm_orig_w4_sec_comp (tL2C_CCB *p_ccb, UINT16 event, void *p_dat
    - 
    -     case L2CEVT_SEC_RE_SEND_CMD:                    /* BTM has enough info to proceed */
    -     case L2CEVT_LP_CONNECT_CFM:                     /* Link came up         */
    -+#if (BLE_INCLUDED == TRUE)
    -         if (p_ccb->p_lcb->transport == BT_TRANSPORT_LE)
    -         {
    -              l2ble_sec_access_req(p_ccb->p_lcb->remote_bd_addr, p_ccb->p_rcb->psm, FALSE,
    -                     &l2c_link_sec_comp, p_ccb);
    -         }
    -         else
    -+#endif
    -         {
    -             btm_sec_l2cap_access_req (p_ccb->p_lcb->remote_bd_addr, p_ccb->p_rcb->psm,
    -                                   p_ccb->p_lcb->handle, TRUE, &l2c_link_sec_comp, p_ccb);
    -@@ -373,6 +381,7 @@ static void l2c_csm_orig_w4_sec_comp (tL2C_CCB *p_ccb, UINT16 event, void *p_dat
    -     case L2CEVT_SEC_COMP:                            /* Security completed success */
    -         /* Wait for the info resp in this state before sending connect req (if needed) */
    -         p_ccb->chnl_state = CST_W4_L2CAP_CONNECT_RSP;
    -+#if (BLE_INCLUDED == TRUE)
    -         if (p_ccb->p_lcb->transport == BT_TRANSPORT_LE)
    -         {
    -             alarm_set_on_queue(p_ccb->l2c_ccb_timer,
    -@@ -382,6 +391,7 @@ static void l2c_csm_orig_w4_sec_comp (tL2C_CCB *p_ccb, UINT16 event, void *p_dat
    -             l2cble_credit_based_conn_req (p_ccb);          /* Start Connection     */
    -         }
    -         else
    -+#endif
    -         {
    -             if (!p_ccb->p_lcb->w4_info_rsp)
    -             {
    -@@ -514,9 +524,11 @@ static void l2c_csm_term_w4_sec_comp (tL2C_CCB *p_ccb, UINT16 event, void *p_dat
    -         }
    -         else
    -         {
    -+#if (BLE_INCLUDED == TRUE)
    -             if (p_ccb->p_lcb->transport == BT_TRANSPORT_LE)
    -                 l2cu_reject_ble_connection(p_ccb->p_lcb, p_ccb->remote_id, L2CAP_LE_INSUFFICIENT_AUTHENTICATION);
    -             else
    -+#endif
    -                 l2cu_send_peer_connect_rsp (p_ccb, L2CAP_CONN_SECURITY_BLOCK, 0);
    -             l2cu_release_ccb (p_ccb);
    -         }
    -@@ -721,6 +733,7 @@ static void l2c_csm_w4_l2ca_connect_rsp (tL2C_CCB *p_ccb, UINT16 event, void *p_
    - 
    -     case L2CEVT_L2CA_CONNECT_RSP:
    -         p_ci = (tL2C_CONN_INFO *)p_data;
    -+#if (BLE_INCLUDED == TRUE)
    -         if (p_ccb->p_lcb->transport == BT_TRANSPORT_LE)
    -         {
    -             /* Result should be OK or Reject */
    -@@ -737,6 +750,7 @@ static void l2c_csm_w4_l2ca_connect_rsp (tL2C_CCB *p_ccb, UINT16 event, void *p_
    -             }
    -         }
    -         else
    -+#endif
    -         {
    -             /* Result should be OK or PENDING */
    -             if ((!p_ci) || (p_ci->l2cap_result == L2CAP_CONN_OK))
    -@@ -762,9 +776,11 @@ static void l2c_csm_w4_l2ca_connect_rsp (tL2C_CCB *p_ccb, UINT16 event, void *p_
    - 
    -     case L2CEVT_L2CA_CONNECT_RSP_NEG:
    -         p_ci = (tL2C_CONN_INFO *)p_data;
    -+#if (BLE_INCLUDED == TRUE)
    -         if (p_ccb->p_lcb->transport == BT_TRANSPORT_LE)
    -             l2cble_credit_based_conn_res (p_ccb, p_ci->l2cap_result);
    -         else
    -+#endif
    -             l2cu_send_peer_connect_rsp (p_ccb, p_ci->l2cap_result, p_ci->l2cap_status);
    -         l2cu_release_ccb (p_ccb);
    -         break;
    -@@ -1185,9 +1201,11 @@ static void l2c_csm_open (tL2C_CCB *p_ccb, UINT16 event, void *p_data)
    -             }
    -         }
    - 
    -+#if (BLE_INCLUDED == TRUE)
    -         if (p_ccb->p_lcb->transport == BT_TRANSPORT_LE)
    -             l2cble_send_peer_disc_req (p_ccb);
    -         else
    -+#endif
    -             l2cu_send_peer_disc_req (p_ccb);
    - 
    -         p_ccb->chnl_state = CST_W4_L2CAP_DISCONNECT_RSP;
    -@@ -1226,7 +1244,9 @@ static void l2c_csm_open (tL2C_CCB *p_ccb, UINT16 event, void *p_data)
    -     case L2CEVT_L2CA_SEND_FLOW_CONTROL_CREDIT:
    -         L2CAP_TRACE_DEBUG("%s Sending credit",__func__);
    -         credit = (UINT16*)p_data;
    -+#if (BLE_INCLUDED == TRUE)
    -         l2cble_send_flow_control_credit(p_ccb, *credit);
    -+#endif
    -         break;
    - 
    -     case L2CEVT_L2CAP_RECV_FLOW_CONTROL_CREDIT:
    -@@ -1237,7 +1257,9 @@ static void l2c_csm_open (tL2C_CCB *p_ccb, UINT16 event, void *p_data)
    -             /* we have received credits more than max coc credits,
    -              * so disconnecting the Le Coc Channel
    -              */
    -+#if (BLE_INCLUDED == TRUE)
    -             l2cble_send_peer_disc_req (p_ccb);
    -+#endif
    -         }
    -         else
    -         {
     diff --git a/stack/l2cap/l2c_fcr.c b/stack/l2cap/l2c_fcr.c
    -index 5ba8b5619..b6a715762 100644
    +index 5ba8b5619..2b041f193 100644
     --- a/stack/l2cap/l2c_fcr.c
     +++ b/stack/l2cap/l2c_fcr.c
     @@ -24,6 +24,7 @@
    @@ -1760,22 +1751,21 @@ index 5ba8b5619..b6a715762 100644
      #include <stdio.h>
      #include <stdlib.h>
      #include <string.h>
    -@@ -848,6 +849,14 @@ void l2c_lcc_proc_pdu(tL2C_CCB *p_ccb, BT_HDR *p_buf)
    +@@ -848,6 +849,13 @@ void l2c_lcc_proc_pdu(tL2C_CCB *p_ccb, BT_HDR *p_buf)
                  return;
              }
      
    -+	if (sdu_length < p_buf->len) {
    -+		L2CAP_TRACE_ERROR("%s: Invalid sdu_length: %d", __func__, sdu_length);
    -+		android_errorWriteWithInfoLog(0x534e4554, "112321180", -1, NULL, 0);
    -+		/* Discard the buffer */
    -+		osi_free(p_buf);
    -+		return;
    -+	}
    -+
    ++        if (sdu_length < p_buf->len) {
    ++            L2CAP_TRACE_ERROR("%s: Invalid sdu_length: %d", __func__, sdu_length);
    ++            android_errorWriteWithInfoLog(0x534e4554, "112321180", -1, NULL, 0);
    ++            /* Discard the buffer */
    ++            osi_free(p_buf);
    ++            return;
    ++        }
      
              if ((p_data = (BT_HDR *) osi_malloc(L2CAP_MAX_BUF_SIZE)) == NULL)
              {
    -@@ -865,7 +874,24 @@ void l2c_lcc_proc_pdu(tL2C_CCB *p_ccb, BT_HDR *p_buf)
    +@@ -865,7 +873,24 @@ void l2c_lcc_proc_pdu(tL2C_CCB *p_ccb, BT_HDR *p_buf)
      
          }
          else
    @@ -1800,7 +1790,7 @@ index 5ba8b5619..b6a715762 100644
      
          memcpy((UINT8*)(p_data + 1) + p_data->offset + p_data->len, (UINT8*)(p_buf + 1) + p_buf->offset, p_buf->len);
          p_data->len += p_buf->len;
    -@@ -881,11 +907,6 @@ void l2c_lcc_proc_pdu(tL2C_CCB *p_ccb, BT_HDR *p_buf)
    +@@ -881,11 +906,6 @@ void l2c_lcc_proc_pdu(tL2C_CCB *p_ccb, BT_HDR *p_buf)
          {
              p_ccb->is_first_seg = FALSE;
          }
    @@ -2098,58 +2088,6 @@ index 3c48d6974..5eced537a 100644
                      STREAM_TO_UINT32( p_lcb->peer_ext_fea, p );
      
      #if (L2CAP_NUM_FIXED_CHNLS > 0)
    -diff --git a/stack/l2cap/l2c_utils.c b/stack/l2cap/l2c_utils.c
    -index 58ac4b06b..aeff5781c 100644
    ---- a/stack/l2cap/l2c_utils.c
    -+++ b/stack/l2cap/l2c_utils.c
    -@@ -253,6 +253,7 @@ void l2cu_release_lcb (tL2C_LCB *p_lcb)
    -         (*p_cb) (L2CAP_PING_RESULT_NO_LINK);
    -     }
    - 
    -+#if (BLE_INCLUDED == TRUE)
    -     /* Check and release all the LE COC connections waiting for security */
    -     if (p_lcb->le_sec_pending_q)
    -     {
    -@@ -266,6 +267,7 @@ void l2cu_release_lcb (tL2C_LCB *p_lcb)
    -         fixed_queue_free(p_lcb->le_sec_pending_q, NULL);
    -         p_lcb->le_sec_pending_q = NULL;
    -     }
    -+#endif
    - }
    - 
    - 
    -@@ -1817,6 +1819,7 @@ tL2C_RCB *l2cu_allocate_rcb (UINT16 psm)
    -     return (NULL);
    - }
    - 
    -+#if (BLE_INCLUDED == TRUE)
    - /*******************************************************************************
    - **
    - ** Function         l2cu_allocate_ble_rcb
    -@@ -1848,6 +1851,7 @@ tL2C_RCB *l2cu_allocate_ble_rcb (UINT16 psm)
    -     /* If here, no free RCB found */
    -     return (NULL);
    - }
    -+#endif
    - 
    - /*******************************************************************************
    - **
    -@@ -1922,6 +1926,7 @@ tL2C_RCB *l2cu_find_rcb_by_psm (UINT16 psm)
    -     return (NULL);
    - }
    - 
    -+#if (BLE_INCLUDED == TRUE)
    - /*******************************************************************************
    - **
    - ** Function         l2cu_find_ble_rcb_by_psm
    -@@ -1946,6 +1951,7 @@ tL2C_RCB *l2cu_find_ble_rcb_by_psm (UINT16 psm)
    -     /* If here, no match found */
    -     return (NULL);
    - }
    -+#endif
    - 
    - /*******************************************************************************
    - **
     diff --git a/stack/l2cap/l2cap_client.c b/stack/l2cap/l2cap_client.c
     index 7e8b3cb6f..cd7edfe1f 100644
     --- a/stack/l2cap/l2cap_client.c
    @@ -2175,7 +2113,7 @@ index 7e8b3cb6f..cd7edfe1f 100644
          fragment->len = client->remote_mtu;
          memcpy(fragment->data + fragment->offset, bt_packet->data + bt_packet->offset, client->remote_mtu);
     diff --git a/stack/mcap/mca_cact.c b/stack/mcap/mca_cact.c
    -index 583a34215..64e05f4e2 100644
    +index 583a34215..6eaf23f61 100644
     --- a/stack/mcap/mca_cact.c
     +++ b/stack/mcap/mca_cact.c
     @@ -22,6 +22,7 @@
    @@ -2224,6 +2162,35 @@ index 583a34215..64e05f4e2 100644
          MCA_TRACE_DEBUG ("received mdl id: %d ", evt_data.hdr.mdl_id);
          if (p_ccb->status == MCA_CCB_STAT_PENDING)
          {
    +@@ -459,14 +469,23 @@ void mca_ccb_hdl_rsp(tMCA_CCB *p_ccb, tMCA_CCB_EVT *p_data)
    +     tMCA_RESULT result = MCA_BAD_HANDLE;
    +     tMCA_TC_TBL *p_tbl;
    + 
    +-    if (p_ccb->p_tx_req)
    +-    {
    ++    if (p_pkt->len < sizeof(evt_data.hdr.op_code) +
    ++                     sizeof(evt_data.rsp.rsp_code) +
    ++                     sizeof(evt_data.hdr.mdl_id)) {
    ++        android_errorWriteLog(0x534e4554, "116319076");
    ++        MCA_TRACE_ERROR("%s: Response packet is too short", __func__);
    ++    } else if (p_ccb->p_tx_req) {
    +         /* verify that the received response matches the sent request */
    +         p = (UINT8 *)(p_pkt + 1) + p_pkt->offset;
    +         evt_data.hdr.op_code = *p++;
    +-        if ((evt_data.hdr.op_code == 0) ||
    +-            ((p_ccb->p_tx_req->op_code + 1) == evt_data.hdr.op_code))
    +-        {
    ++	if ((evt_data.hdr.op_code == MCA_OP_MDL_CREATE_RSP) &&
    ++            (p_pkt->len <
    ++             sizeof(evt_data.hdr.op_code) + sizeof(evt_data.rsp.rsp_code) +
    ++             sizeof(evt_data.hdr.mdl_id) + sizeof(evt_data.create_cfm.cfg))) {
    ++            android_errorWriteLog(0x534e4554, "116319076");
    ++            MCA_TRACE_ERROR("%s: MDL Create Response packet is too short", __func__);
    ++        } else if ((evt_data.hdr.op_code == 0) ||
    ++               ((p_ccb->p_tx_req->op_code + 1) == evt_data.hdr.op_code)) {
    +             evt_data.rsp.rsp_code = *p++;
    +             mca_stop_timer(p_ccb);
    +             BE_STREAM_TO_UINT16 (evt_data.hdr.mdl_id, p);
     diff --git a/stack/pan/pan_main.c b/stack/pan/pan_main.c
     index 5c3a36739..9c90e5834 100644
     --- a/stack/pan/pan_main.c
    @@ -2377,7 +2344,7 @@ index 739469f64..d7fb8e5cf 100644
              ea                   = *p_data & RFCOMM_EA;
              cr                   = (*p_data & RFCOMM_CR_MASK) >> RFCOMM_SHIFT_CR;
     diff --git a/stack/sdp/sdp_discovery.c b/stack/sdp/sdp_discovery.c
    -index ec20689e3..5dcf9915e 100644
    +index ec20689e3..416085db4 100644
     --- a/stack/sdp/sdp_discovery.c
     +++ b/stack/sdp/sdp_discovery.c
     @@ -29,6 +29,7 @@
    @@ -2388,7 +2355,7 @@ index ec20689e3..5dcf9915e 100644
      #include "hcidefs.h"
      #include "hcimsgs.h"
      #include "sdp_api.h"
    -@@ -45,9 +46,12 @@
    +@@ -45,12 +46,15 @@
      /*              L O C A L    F U N C T I O N     P R O T O T Y P E S            */
      /********************************************************************************/
      #if SDP_CLIENT_ENABLED == TRUE
    @@ -2403,7 +2370,11 @@ index ec20689e3..5dcf9915e 100644
     +                                                      uint8_t* p_reply_end);
      static UINT8         *save_attr_seq (tCONN_CB *p_ccb, UINT8 *p, UINT8 *p_msg_end);
      static tSDP_DISC_REC *add_record (tSDP_DISCOVERY_DB *p_db, BD_ADDR p_bda);
    - static UINT8         *add_attr (UINT8 *p, tSDP_DISCOVERY_DB *p_db, tSDP_DISC_REC *p_rec,
    +-static UINT8         *add_attr (UINT8 *p, tSDP_DISCOVERY_DB *p_db, tSDP_DISC_REC *p_rec,
    ++static UINT8         *add_attr (UINT8 *p, UINT8 *p_end, tSDP_DISCOVERY_DB *p_db, tSDP_DISC_REC *p_rec,
    +                                 UINT16 attr_id, tSDP_DISC_ATTR *p_parent_attr, UINT8 nest_level);
    + 
    + /* Safety check in case we go crazy */
     @@ -193,7 +197,7 @@ void sdp_disc_connected (tCONN_CB *p_ccb)
          {
              p_ccb->disc_state = SDP_DISC_WAIT_SEARCH_ATTR;
    @@ -2448,7 +2419,7 @@ index ec20689e3..5dcf9915e 100644
                  invalid_pdu = FALSE;
              }
              break;
    -@@ -280,12 +285,18 @@ void sdp_disc_server_rsp (tCONN_CB *p_ccb, BT_HDR *p_msg)
    +@@ -280,12 +285,19 @@ void sdp_disc_server_rsp (tCONN_CB *p_ccb, BT_HDR *p_msg)
      ** Returns          void
      **
      *******************************************************************************/
    @@ -2462,13 +2433,14 @@ index ec20689e3..5dcf9915e 100644
      
     +    if (p_reply + 8 > p_reply_end) {
     +        android_errorWriteLog(0x534e4554, "74249842");
    -+        sdp_disconnect(p_ccb, SDP_GENERIC_ERROR);
    -+        return;
    ++         sdp_disconnect(p_ccb, SDP_GENERIC_ERROR);
    ++         return;
     +    }
    ++
          /* Skip transaction, and param len */
          p_reply += 4;
          BE_STREAM_TO_UINT16 (total, p_reply);
    -@@ -306,6 +317,12 @@ static void process_service_search_rsp (tCONN_CB *p_ccb, UINT8 *p_reply)
    +@@ -306,6 +318,12 @@ static void process_service_search_rsp (tCONN_CB *p_ccb, UINT8 *p_reply)
          if (p_ccb->num_handles > sdp_cb.max_recs_per_search)
              p_ccb->num_handles = sdp_cb.max_recs_per_search;
      
    @@ -2481,7 +2453,7 @@ index ec20689e3..5dcf9915e 100644
          for (xx = orig; xx < p_ccb->num_handles; xx++)
              BE_STREAM_TO_UINT32 (p_ccb->handles[xx], p_reply);
      
    -@@ -317,6 +334,11 @@ static void process_service_search_rsp (tCONN_CB *p_ccb, UINT8 *p_reply)
    +@@ -317,6 +335,11 @@ static void process_service_search_rsp (tCONN_CB *p_ccb, UINT8 *p_reply)
                  sdp_disconnect (p_ccb, SDP_INVALID_CONT_STATE);
                  return;
              }
    @@ -2493,7 +2465,7 @@ index ec20689e3..5dcf9915e 100644
              /* stay in the same state */
              sdp_snd_service_search_req(p_ccb, cont_len, p_reply);
          }
    -@@ -326,7 +348,7 @@ static void process_service_search_rsp (tCONN_CB *p_ccb, UINT8 *p_reply)
    +@@ -326,7 +349,7 @@ static void process_service_search_rsp (tCONN_CB *p_ccb, UINT8 *p_reply)
              p_ccb->disc_state = SDP_DISC_WAIT_ATTR;
      
              /* Kick off the first attribute request */
    @@ -2502,7 +2474,7 @@ index ec20689e3..5dcf9915e 100644
          }
      }
      
    -@@ -367,10 +389,18 @@ static void sdp_copy_raw_data (tCONN_CB *p_ccb, BOOLEAN offset)
    +@@ -367,10 +390,18 @@ static void sdp_copy_raw_data (tCONN_CB *p_ccb, BOOLEAN offset)
      
              if(offset)
              {
    @@ -2522,7 +2494,7 @@ index ec20689e3..5dcf9915e 100644
              {
                  cpy_len = list_len;
              }
    -@@ -395,7 +425,8 @@ static void sdp_copy_raw_data (tCONN_CB *p_ccb, BOOLEAN offset)
    +@@ -395,7 +426,8 @@ static void sdp_copy_raw_data (tCONN_CB *p_ccb, BOOLEAN offset)
      ** Returns          void
      **
      *******************************************************************************/
    @@ -2532,7 +2504,7 @@ index ec20689e3..5dcf9915e 100644
      {
          UINT8           *p_start, *p_param_len;
          UINT16          param_len, list_byte_count;
    -@@ -502,8 +533,12 @@ static void process_service_attr_rsp (tCONN_CB *p_ccb, UINT8 *p_reply)
    +@@ -502,8 +534,12 @@ static void process_service_attr_rsp (tCONN_CB *p_ccb, UINT8 *p_reply)
              /* Was this a continuation request ? */
              if (cont_request_needed)
              {
    @@ -2547,7 +2519,7 @@ index ec20689e3..5dcf9915e 100644
              }
              else
                  UINT8_TO_BE_STREAM (p, 0);
    -@@ -541,7 +576,8 @@ static void process_service_attr_rsp (tCONN_CB *p_ccb, UINT8 *p_reply)
    +@@ -541,7 +577,8 @@ static void process_service_attr_rsp (tCONN_CB *p_ccb, UINT8 *p_reply)
      ** Returns          void
      **
      *******************************************************************************/
    @@ -2557,7 +2529,7 @@ index ec20689e3..5dcf9915e 100644
      {
          UINT8           *p, *p_start, *p_end, *p_param_len;
          UINT8           type;
    -@@ -555,6 +591,14 @@ static void process_service_search_attr_rsp (tCONN_CB *p_ccb, UINT8 *p_reply)
    +@@ -555,6 +592,14 @@ static void process_service_search_attr_rsp (tCONN_CB *p_ccb, UINT8 *p_reply)
          /* If p_reply is NULL, we were called for the initial read */
          if (p_reply)
          {
    @@ -2572,7 +2544,7 @@ index ec20689e3..5dcf9915e 100644
      #if (SDP_DEBUG_RAW == TRUE)
              SDP_TRACE_WARNING("ID & len: 0x%02x-%02x-%02x-%02x",
                  p_reply[0], p_reply[1], p_reply[2], p_reply[3]);
    -@@ -578,6 +622,14 @@ static void process_service_search_attr_rsp (tCONN_CB *p_ccb, UINT8 *p_reply)
    +@@ -578,6 +623,14 @@ static void process_service_search_attr_rsp (tCONN_CB *p_ccb, UINT8 *p_reply)
              SDP_TRACE_WARNING("list_len: %d, list_byte_count: %d",
                  p_ccb->list_len, lists_byte_count);
      #endif
    @@ -2587,7 +2559,7 @@ index ec20689e3..5dcf9915e 100644
              if (p_ccb->rsp_list == NULL)
                  p_ccb->rsp_list = (UINT8 *)osi_malloc(SDP_MAX_LIST_BYTE_COUNT);
              memcpy (&p_ccb->rsp_list[p_ccb->list_len], p_reply, lists_byte_count);
    -@@ -641,8 +693,12 @@ static void process_service_search_attr_rsp (tCONN_CB *p_ccb, UINT8 *p_reply)
    +@@ -641,8 +694,12 @@ static void process_service_search_attr_rsp (tCONN_CB *p_ccb, UINT8 *p_reply)
              /* No continuation for first request */
              if (p_reply)
              {
    @@ -2602,6 +2574,99 @@ index ec20689e3..5dcf9915e 100644
              }
              else
                  UINT8_TO_BE_STREAM (p, 0);
    +@@ -764,7 +821,7 @@ static UINT8 *save_attr_seq (tCONN_CB *p_ccb, UINT8 *p, UINT8 *p_msg_end)
    +         BE_STREAM_TO_UINT16 (attr_id, p);
    + 
    +         /* Now, add the attribute value */
    +-        p = add_attr (p, p_ccb->p_db, p_rec, attr_id, NULL, 0);
    ++        p = add_attr (p, p_seq_end, p_ccb->p_db, p_rec, attr_id, NULL, 0);
    + 
    +         if (!p)
    +         {
    +@@ -830,7 +887,7 @@ tSDP_DISC_REC *add_record (tSDP_DISCOVERY_DB *p_db, BD_ADDR p_bda)
    + ** Returns          pointer to next byte in data stream
    + **
    + *******************************************************************************/
    +-static UINT8 *add_attr (UINT8 *p, tSDP_DISCOVERY_DB *p_db, tSDP_DISC_REC *p_rec,
    ++static UINT8 *add_attr (UINT8 *p, UINT8 *p_end, tSDP_DISCOVERY_DB *p_db, tSDP_DISC_REC *p_rec,
    +                         UINT16 attr_id, tSDP_DISC_ATTR *p_parent_attr, UINT8 nest_level)
    + {
    +     tSDP_DISC_ATTR  *p_attr;
    +@@ -839,7 +896,7 @@ static UINT8 *add_attr (UINT8 *p, tSDP_DISCOVERY_DB *p_db, tSDP_DISC_REC *p_rec,
    +     UINT16          attr_type;
    +     UINT16          id;
    +     UINT8           type;
    +-    UINT8           *p_end;
    ++    UINT8           *p_attr_end;
    +     UINT8           is_additional_list = nest_level & SDP_ADDITIONAL_LIST_MASK;
    + 
    +     nest_level &= ~(SDP_ADDITIONAL_LIST_MASK);
    +@@ -856,6 +913,13 @@ static UINT8 *add_attr (UINT8 *p, tSDP_DISCOVERY_DB *p_db, tSDP_DISC_REC *p_rec,
    +     else
    +         total_len = sizeof (tSDP_DISC_ATTR);
    + 
    ++    p_attr_end = p + attr_len;
    ++    if (p_attr_end > p_end) {
    ++        android_errorWriteLog(0x534e4554, "115900043");
    ++        SDP_TRACE_WARNING("%s: SDP - Attribute length beyond p_end", __func__);
    ++        return NULL;
    ++    }
    ++
    +     /* Ensure it is a multiple of 4 */
    +     total_len = (total_len + 3) & ~3;
    + 
    +@@ -882,18 +946,17 @@ static UINT8 *add_attr (UINT8 *p, tSDP_DISCOVERY_DB *p_db, tSDP_DISC_REC *p_rec,
    +                 /* Reserve the memory for the attribute now, as we need to add sub-attributes */
    +                 p_db->p_free_mem += sizeof (tSDP_DISC_ATTR);
    +                 p_db->mem_free   -= sizeof (tSDP_DISC_ATTR);
    +-                p_end             = p + attr_len;
    +                 total_len         = 0;
    + 
    +                 /* SDP_TRACE_DEBUG ("SDP - attr nest level:%d(list)", nest_level); */
    +                 if (nest_level >= MAX_NEST_LEVELS)
    +                 {
    +                     SDP_TRACE_ERROR ("SDP - attr nesting too deep");
    +-                    return (p_end);
    ++                    return p_attr_end;
    +                 }
    + 
    +                 /* Now, add the list entry */
    +-                p = add_attr (p, p_db, p_rec, ATTR_ID_PROTOCOL_DESC_LIST, p_attr, (UINT8)(nest_level + 1));
    ++                p = add_attr (p, p_end, p_db, p_rec, ATTR_ID_PROTOCOL_DESC_LIST, p_attr, (UINT8)(nest_level + 1));
    + 
    +                 break;
    +             }
    +@@ -966,7 +1029,7 @@ static UINT8 *add_attr (UINT8 *p, tSDP_DISCOVERY_DB *p_db, tSDP_DISC_REC *p_rec,
    +             break;
    +         default:
    +             SDP_TRACE_WARNING ("SDP - bad len in UUID attr: %d", attr_len);
    +-            return (p + attr_len);
    ++            return p_attr_end;
    +         }
    +         break;
    + 
    +@@ -988,10 +1051,10 @@ static UINT8 *add_attr (UINT8 *p, tSDP_DISCOVERY_DB *p_db, tSDP_DISC_REC *p_rec,
    +             nest_level |= SDP_ADDITIONAL_LIST_MASK;
    +         /* SDP_TRACE_DEBUG ("SDP - attr nest level:0x%x(finish)", nest_level); */
    + 
    +-        while (p < p_end)
    ++        while (p < p_attr_end)
    +         {
    +             /* Now, add the list entry */
    +-            p = add_attr (p, p_db, p_rec, 0, p_attr, (UINT8)(nest_level + 1));
    ++            p = add_attr (p, p_end, p_db, p_rec, 0, p_attr, (UINT8)(nest_level + 1));
    + 
    +             if (!p)
    +                 return (NULL);
    +@@ -1011,7 +1074,7 @@ static UINT8 *add_attr (UINT8 *p, tSDP_DISCOVERY_DB *p_db, tSDP_DISC_REC *p_rec,
    +             break;
    +         default:
    +             SDP_TRACE_WARNING ("SDP - bad len in boolean attr: %d", attr_len);
    +-            return (p + attr_len);
    ++            return p_attr_end;
    +         }
    +         break;
    + 
     diff --git a/stack/sdp/sdp_main.c b/stack/sdp/sdp_main.c
     index c88881799..7cbe2d37b 100644
     --- a/stack/sdp/sdp_main.c
    
    From 5e6f99453a81ffcbc6fc8e318ba381922ee68ab5 Mon Sep 17 00:00:00 2001
    From: AndDiSa <anddisa@googlemail.com>
    Date: Thu, 10 Jan 2019 18:13:55 +0100
    Subject: [PATCH 108/159] update patches
    
    Change-Id: If67c0888fcddedff9bca3ce91ee88fc9a103969f
    ---
     external_aac.patch             | 135 +++++++++++++++++++++++++++++++++
     external_android_clat.patch    |  39 ++++++++++
     external_chromium_libpac.patch | 116 ++++++++++++++++++++++++++++
     external_curl.patch            |  63 +++++++++++++++
     external_e2fsprogs.patch       |  28 +++++++
     external_libdrm.patch          |  15 ++++
     external_neven.patch           |  13 ++++
     external_svox.patch            |  27 +++++++
     frameworks_ex.patch            |  27 +++++++
     9 files changed, 463 insertions(+)
    
    diff --git a/external_aac.patch b/external_aac.patch
    index e69de29..3475fb1 100644
    --- a/external_aac.patch
    +++ b/external_aac.patch
    @@ -0,0 +1,135 @@
    +diff --git a/Android.mk b/Android.mk
    +index 4c28670..9ffa0eb 100644
    +--- a/Android.mk
    ++++ b/Android.mk
    +@@ -55,6 +55,8 @@ LOCAL_C_INCLUDES := \
    + 
    + LOCAL_CPPFLAGS += -std=c++98
    + 
    ++LOCAL_SHARED_LIBRARIES := liblog
    ++
    + LOCAL_MODULE:= libFraunhoferAAC
    + 
    + include $(BUILD_STATIC_LIBRARY)
    +diff --git a/libMpegTPDec/src/tpdec_asc.cpp b/libMpegTPDec/src/tpdec_asc.cpp
    +index 96a1b35..e80d0e5 100644
    +--- a/libMpegTPDec/src/tpdec_asc.cpp
    ++++ b/libMpegTPDec/src/tpdec_asc.cpp
    +@@ -118,7 +118,9 @@ int  CProgramConfig_IsValid ( const CProgramConfig *pPce )
    + 
    + /*
    +  * Read the extension for height info.
    +- * return 0 if successfull or -1 if the CRC failed.
    ++ * return 0 if successfull,
    ++ *       -1 if the CRC failed,
    ++ *       -2 if invalid HeightInfo.
    +  */
    + static
    + int CProgramConfig_ReadHeightExt(
    +@@ -146,15 +148,21 @@ int CProgramConfig_ReadHeightExt(
    + 
    +     for (i=0; i < pPce->NumFrontChannelElements; i++)
    +     {
    +-      pPce->FrontElementHeightInfo[i] = (UCHAR) FDKreadBits(bs,2);
    ++      if ((pPce->FrontElementHeightInfo[i] = (UCHAR) FDKreadBits(bs,2)) >= PC_NUM_HEIGHT_LAYER) {
    ++        err = -2; /* height information is out of the valid range */
    ++      }
    +     }
    +     for (i=0; i < pPce->NumSideChannelElements; i++)
    +     {
    +-      pPce->SideElementHeightInfo[i] = (UCHAR) FDKreadBits(bs,2);
    ++      if ((pPce->SideElementHeightInfo[i] = (UCHAR) FDKreadBits(bs,2)) >= PC_NUM_HEIGHT_LAYER) {
    ++        err = -2; /* height information is out of the valid range */
    ++      }
    +     }
    +     for (i=0; i < pPce->NumBackChannelElements; i++)
    +     {
    +-      pPce->BackElementHeightInfo[i] = (UCHAR) FDKreadBits(bs,2);
    ++      if ((pPce->BackElementHeightInfo[i] = (UCHAR) FDKreadBits(bs,2)) >= PC_NUM_HEIGHT_LAYER) {
    ++        err = -2; /* height information is out of the valid range */
    ++      }
    +     }
    +     FDKbyteAlign(bs, alignmentAnchor);
    + 
    +@@ -163,6 +171,13 @@ int CProgramConfig_ReadHeightExt(
    +       /* CRC failed */
    +       err = -1;
    +     }
    ++    if (err!=0) {
    ++      /* Reset whole height information in case an error occured during parsing. The return
    ++         value ensures that pPce->isValid is set to 0 and implicit channel mapping is used. */
    ++      FDKmemclear(pPce->FrontElementHeightInfo, sizeof(pPce->FrontElementHeightInfo));
    ++      FDKmemclear(pPce->SideElementHeightInfo, sizeof(pPce->SideElementHeightInfo));
    ++      FDKmemclear(pPce->BackElementHeightInfo, sizeof(pPce->BackElementHeightInfo));
    ++    }
    +   }
    +   else {
    +     /* No valid extension data found -> restore the initial bitbuffer state */
    +diff --git a/libSBRdec/src/lpp_tran.cpp b/libSBRdec/src/lpp_tran.cpp
    +index 117e739..e332c25 100644
    +--- a/libSBRdec/src/lpp_tran.cpp
    ++++ b/libSBRdec/src/lpp_tran.cpp
    +@@ -96,6 +96,10 @@ amm-info@iis.fraunhofer.de
    +   \sa lppTransposer(), main_audio.cpp, sbr_scale.h, \ref documentationOverview
    + */
    + 
    ++#ifdef __ANDROID__
    ++#include "log/log.h"
    ++#endif
    ++
    + #include "lpp_tran.h"
    + 
    + #include "sbr_ram.h"
    +@@ -256,7 +260,6 @@ void lppTransposer (HANDLE_SBR_LPP_TRANS hLppTrans,    /*!< Handle of lpp transp
    +   int ovLowBandShift;
    +   int lowBandShift;
    + /*  int ovHighBandShift;*/
    +-  int targetStopBand;
    + 
    + 
    +   alphai[0] = FL2FXCONST_SGL(0.0f);
    +@@ -273,24 +276,32 @@ void lppTransposer (HANDLE_SBR_LPP_TRANS hLppTrans,    /*!< Handle of lpp transp
    + 
    +   autoCorrLength = pSettings->nCols + pSettings->overlap;
    + 
    +-  /* Set upper subbands to zero:
    +-     This is required in case that the patches do not cover the complete highband
    +-     (because the last patch would be too short).
    +-     Possible optimization: Clearing bands up to usb would be sufficient here. */
    +-  targetStopBand = patchParam[pSettings->noOfPatches-1].targetStartBand
    +-                 + patchParam[pSettings->noOfPatches-1].numBandsInPatch;
    ++  if (pSettings->noOfPatches > 0) {
    ++    /* Set upper subbands to zero:
    ++       This is required in case that the patches do not cover the complete highband
    ++       (because the last patch would be too short).
    ++       Possible optimization: Clearing bands up to usb would be sufficient here. */
    ++    int targetStopBand = patchParam[pSettings->noOfPatches-1].targetStartBand
    ++                   + patchParam[pSettings->noOfPatches-1].numBandsInPatch;
    + 
    +-  int memSize = ((64) - targetStopBand) * sizeof(FIXP_DBL);
    ++    int memSize = ((64) - targetStopBand) * sizeof(FIXP_DBL);
    + 
    +-  if (!useLP) {
    ++    if (!useLP) {
    ++      for (i = startSample; i < stopSampleClear; i++) {
    ++        FDKmemclear(&qmfBufferReal[i][targetStopBand], memSize);
    ++        FDKmemclear(&qmfBufferImag[i][targetStopBand], memSize);
    ++      }
    ++    } else
    +     for (i = startSample; i < stopSampleClear; i++) {
    +       FDKmemclear(&qmfBufferReal[i][targetStopBand], memSize);
    +-      FDKmemclear(&qmfBufferImag[i][targetStopBand], memSize);
    +     }
    +-  } else
    +-  for (i = startSample; i < stopSampleClear; i++) {
    +-    FDKmemclear(&qmfBufferReal[i][targetStopBand], memSize);
    +   }
    ++#ifdef __ANDROID__
    ++  else {
    ++    // Safetynet logging
    ++    android_errorWriteLog(0x534e4554, "112160868");
    ++  }
    ++#endif
    + 
    +   /* init bwIndex for each patch */
    +   FDKmemclear(bwIndex, pSettings->noOfPatches*sizeof(INT));
    diff --git a/external_android_clat.patch b/external_android_clat.patch
    index e69de29..f743e3d 100644
    --- a/external_android_clat.patch
    +++ b/external_android_clat.patch
    @@ -0,0 +1,39 @@
    +diff --git a/clatd.c b/clatd.c
    +index d57ea59..fd89e0a 100644
    +--- a/clatd.c
    ++++ b/clatd.c
    +@@ -382,19 +382,28 @@ void event_loop(struct tun_data *tunnel) {
    +   last_interface_poll = time(NULL);
    + 
    +   while(running) {
    +-    if(poll(wait_fd, 2, NO_TRAFFIC_INTERFACE_POLL_FREQUENCY*1000) == -1) {
    +-      if(errno != EINTR) {
    +-        logmsg(ANDROID_LOG_WARN,"event_loop/poll returned an error: %s",strerror(errno));
    ++    if (poll(wait_fd, ARRAY_SIZE(wait_fd),
    ++             NO_TRAFFIC_INTERFACE_POLL_FREQUENCY * 1000) == -1) {
    ++      if (errno != EINTR) {
    ++        logmsg(ANDROID_LOG_WARN,"event_loop/poll returned an error: %s", strerror(errno));
    +       }
    +     } else {
    ++      if (wait_fd[0].revents & POLLIN) {
    ++        ring_read(&tunnel->ring, tunnel->fd4, 0 /* to_ipv6 */);
    ++      }
    ++      // If any other bit is set, assume it's due to an error (i.e. POLLERR).
    ++      if (wait_fd[0].revents & ~POLLIN) {
    ++        // ring_read doesn't clear the error indication on the socket.
    ++        recv(tunnel->read_fd6, NULL, 0, MSG_PEEK);
    ++        logmsg(ANDROID_LOG_WARN, "event_loop: clearing error on read_fd6: %s",
    ++               strerror(errno));
    ++      }
    ++
    +       // Call read_packet if the socket has data to be read, but also if an
    +       // error is waiting. If we don't call read() after getting POLLERR, a
    +       // subsequent poll() will return immediately with POLLERR again,
    +       // causing this code to spin in a loop. Calling read() will clear the
    +       // socket error flag instead.
    +-      if (wait_fd[0].revents) {
    +-        ring_read(&tunnel->ring, tunnel->fd4, 0 /* to_ipv6 */);
    +-      }
    +       if (wait_fd[1].revents) {
    +         read_packet(tunnel->fd4, tunnel->write_fd6, 1 /* to_ipv6 */);
    +       }
    diff --git a/external_chromium_libpac.patch b/external_chromium_libpac.patch
    index e69de29..27db9a9 100644
    --- a/external_chromium_libpac.patch
    +++ b/external_chromium_libpac.patch
    @@ -0,0 +1,116 @@
    +diff --git a/Android.mk b/Android.mk
    +index e8a2b26..ae0e768 100644
    +--- a/Android.mk
    ++++ b/Android.mk
    +@@ -18,6 +18,7 @@ LOCAL_CFLAGS += \
    +   -Wno-import \
    +   -Wno-format \
    +   -Wno-unused-parameter \
    ++  -Werror
    + 
    + LOCAL_C_INCLUDES += $(LOCAL_PATH)/src $(LOCAL_PATH)/../v8
    + 
    +@@ -28,3 +29,5 @@ LOCAL_SHARED_LIBRARIES := libutils liblog libicuuc libicui18n
    + LOCAL_CXX_STL := libc++
    + 
    + include $(BUILD_SHARED_LIBRARY)
    ++
    ++include $(LOCAL_PATH)/test/Android.mk
    +diff --git a/src/net_util.cc b/src/net_util.cc
    +index 992cdd1..8eef03a 100644
    +--- a/src/net_util.cc
    ++++ b/src/net_util.cc
    +@@ -64,7 +64,7 @@ bool ParseCIDRBlock(const std::string& cidr_literal,
    +   //   <IPv6-literal> "/" <number of bits>
    + 
    +   std::vector<std::string> parts;
    +-  unsigned int split = cidr_literal.find('/');
    ++  size_t split = cidr_literal.find('/');
    +   if (split == std::string::npos)
    +     return false;
    +   parts.push_back(cidr_literal.substr(0, split));
    +diff --git a/test/Android.mk b/test/Android.mk
    +index 9c9722e..edf9107 100644
    +--- a/test/Android.mk
    ++++ b/test/Android.mk
    +@@ -18,6 +18,6 @@ LOCAL_CFLAGS += \
    + 
    + LOCAL_C_INCLUDES += $(LOCAL_PATH)/../src $(LOCAL_PATH)/ external/v8
    + 
    +-LOCAL_SHARED_LIBRARIES := libpac libutils liblog
    ++LOCAL_SHARED_LIBRARIES := libpac libutils liblog libandroid_runtime
    + 
    + include $(BUILD_NATIVE_TEST)
    +diff --git a/test/js-unittest/change_element_kind.js b/test/js-unittest/change_element_kind.js
    +new file mode 100644
    +index 0000000..335d59e
    +--- /dev/null
    ++++ b/test/js-unittest/change_element_kind.js
    +@@ -0,0 +1,15 @@
    ++// PAC script with getter that changes element kind.
    ++
    ++function FindProxyForURL(url, host) {
    ++  let arr = [];
    ++  arr[1000] = 0x1234;
    ++
    ++  arr.__defineGetter__(256, function () {
    ++    delete arr[256];
    ++    arr.unshift(1.1);
    ++  });
    ++
    ++  let results = Object.entries(arr);
    ++  let str = results.toString();
    ++  return "DIRECT";
    ++}
    +diff --git a/test/proxy_resolver_v8_unittest.cc b/test/proxy_resolver_v8_unittest.cc
    +index ad9c826..be7ecee 100644
    +--- a/test/proxy_resolver_v8_unittest.cc
    ++++ b/test/proxy_resolver_v8_unittest.cc
    +@@ -544,5 +544,19 @@ TEST(ProxyResolverV8Test, DNSResolutionOfInternationDomainName) {
    +   EXPECT_EQ("xn--bcher-kva.ch", bindings->dns_resolves_ex[0]);
    + }
    + 
    ++TEST(ProxyResolverV8Test, GetterChangesElementKind) {
    ++  ProxyResolverV8WithMockBindings resolver(new MockJSBindings());
    ++  int result = resolver.SetPacScript(String16(CHANGE_ELEMENT_KIND_JS));
    ++  EXPECT_EQ(OK, result);
    ++
    ++  // Execute FindProxyForURL().
    ++  result = resolver.GetProxyForURL(kQueryUrl, kQueryHost, &kResults);
    ++
    ++  EXPECT_EQ(OK, result);
    ++  std::vector<std::string> proxies = string16ToProxyList(kResults);
    ++  EXPECT_EQ(1U, proxies.size());
    ++  EXPECT_EQ("DIRECT", proxies[0]);
    ++}
    ++
    + }  // namespace
    + }  // namespace net
    +diff --git a/test/proxy_test_script.h b/test/proxy_test_script.h
    +index 1042366..80c96c7 100644
    +--- a/test/proxy_test_script.h
    ++++ b/test/proxy_test_script.h
    +@@ -78,6 +78,23 @@
    +   "function fn() {}\n" \
    +   "\n" \
    + 
    ++#define CHANGE_ELEMENT_KIND_JS \
    ++  "// PAC script with getter that changes element kind.\n" \
    ++  "	\n" \
    ++  "function FindProxyForURL(url, host) {\n" \
    ++  "  let arr = [];\n" \
    ++  "  arr[1000] = 0x1234;\n" \
    ++  "\n" \
    ++  "  arr.__defineGetter__(256, function () {\n" \
    ++  "    delete arr[256];\n" \
    ++  "    arr.unshift(1.1);\n" \
    ++  "  });\n" \
    ++  "\n" \
    ++  "  let results = Object.entries(arr);\n" \
    ++  "  let str = results.toString(); \n" \
    ++  "  return \"DIRECT\";\n" \
    ++  "}\n" \
    ++
    + #define DIRECT_JS \
    +   "function FindProxyForURL(url, host) {\n" \
    +   "  return \"DIRECT\";\n" \
    diff --git a/external_curl.patch b/external_curl.patch
    index e69de29..b1cd374 100644
    --- a/external_curl.patch
    +++ b/external_curl.patch
    @@ -0,0 +1,63 @@
    +diff --git a/lib/curl_config.h b/lib/curl_config.h
    +index 0288018..e9b7958 100644
    +--- a/lib/curl_config.h
    ++++ b/lib/curl_config.h
    +@@ -17,22 +17,22 @@
    + /* #undef CURL_DISABLE_CRYPTO_AUTH */
    + 
    + /* to disable DICT */
    +-/* #undef CURL_DISABLE_DICT */
    ++#define CURL_DISABLE_DICT 1
    + 
    + /* to disable FILE */
    + /* #undef CURL_DISABLE_FILE */
    + 
    + /* to disable FTP */
    +-/* #undef CURL_DISABLE_FTP */
    ++#define CURL_DISABLE_FTP 1
    + 
    + /* to disable Gopher */
    +-/* #undef CURL_DISABLE_GOPHER */
    ++#define CURL_DISABLE_GOPHER 1
    + 
    + /* to disable HTTP */
    + /* #undef CURL_DISABLE_HTTP */
    + 
    + /* to disable IMAP */
    +-/* #undef CURL_DISABLE_IMAP */
    ++#define CURL_DISABLE_IMAP 1
    + 
    + /* to disable LDAP */
    + #define CURL_DISABLE_LDAP 1
    +@@ -44,25 +44,25 @@
    + /* #undef CURL_DISABLE_LIBCURL_OPTION */
    + 
    + /* to disable POP3 */
    +-/* #undef CURL_DISABLE_POP3 */
    ++#define CURL_DISABLE_POP3 1
    + 
    + /* to disable proxies */
    + /* #undef CURL_DISABLE_PROXY */
    + 
    + /* to disable RTSP */
    +-/* #undef CURL_DISABLE_RTSP */
    ++#define CURL_DISABLE_RTSP 1
    + 
    + /* to disable SMB/CIFS */
    +-/* #undef CURL_DISABLE_SMB */
    ++#define CURL_DISABLE_SMB 1
    + 
    + /* to disable SMTP */
    +-/* #undef CURL_DISABLE_SMTP */
    ++#define CURL_DISABLE_SMTP 1
    + 
    + /* to disable TELNET */
    +-/* #undef CURL_DISABLE_TELNET */
    ++#define CURL_DISABLE_TELNET 1
    + 
    + /* to disable TFTP */
    +-/* #undef CURL_DISABLE_TFTP */
    ++#define CURL_DISABLE_TFTP 1
    + 
    + /* to disable TLS-SRP authentication */
    + /* #undef CURL_DISABLE_TLS_SRP */
    diff --git a/external_e2fsprogs.patch b/external_e2fsprogs.patch
    index e69de29..0718beb 100644
    --- a/external_e2fsprogs.patch
    +++ b/external_e2fsprogs.patch
    @@ -0,0 +1,28 @@
    +diff --git a/e2fsck/logfile.c b/e2fsck/logfile.c
    +index 40e5acb7..3e4df8a7 100644
    +--- a/e2fsck/logfile.c
    ++++ b/e2fsck/logfile.c
    +@@ -67,7 +67,7 @@ static void expand_percent_expression(e2fsck_t ctx, char ch,
    + 				      struct string *s, int *flags)
    + {
    + 	struct tm	*tm = NULL, tm_struct;
    +-	struct passwd	*pw = NULL, pw_struct;
    ++	struct passwd	*pw = NULL;
    + 	char		*cp;
    + 	char		buf[256];
    + 
    +diff --git a/misc/blkid.c b/misc/blkid.c
    +index 388abad0..248cacf6 100644
    +--- a/misc/blkid.c
    ++++ b/misc/blkid.c
    +@@ -86,7 +86,9 @@ static void safe_print(const char *cp, int len)
    + 			fputc('^', stdout);
    + 			ch ^= 0x40; /* ^@, ^A, ^B; ^? for DEL */
    + 		}
    +-		fputc(ch, stdout);
    ++		if (ch != '"') {
    ++			fputc(ch, stdout);
    ++		}
    + 	}
    + }
    + 
    diff --git a/external_libdrm.patch b/external_libdrm.patch
    index e69de29..dbc6b3d 100644
    --- a/external_libdrm.patch
    +++ b/external_libdrm.patch
    @@ -0,0 +1,15 @@
    +diff --git a/xf86drm.c b/xf86drm.c
    +index 7e28b4f7..67f9f838 100644
    +--- a/xf86drm.c
    ++++ b/xf86drm.c
    +@@ -732,8 +732,8 @@ int drmOpen(const char *name, const char *busid)
    +  */
    + int drmOpenWithType(const char *name, const char *busid, int type)
    + {
    +-    if (!drmAvailable() && name != NULL && drm_server_info &&
    +-        drm_server_info->load_module) {
    ++    if (name != NULL && drm_server_info &&
    ++        drm_server_info->load_module && !drmAvailable()) {
    + 	/* try to load the kernel module */
    + 	if (!drm_server_info->load_module(name)) {
    + 	    drmMsg("[drm] failed to load kernel module \"%s\"\n", name);
    diff --git a/external_neven.patch b/external_neven.patch
    index e69de29..d1869e6 100644
    --- a/external_neven.patch
    +++ b/external_neven.patch
    @@ -0,0 +1,13 @@
    +diff --git a/Embedded/common/src/b_BitFeatureEm/Scanner.c b/Embedded/common/src/b_BitFeatureEm/Scanner.c
    +index 327e714..1a0ae2a 100644
    +--- a/Embedded/common/src/b_BitFeatureEm/Scanner.c
    ++++ b/Embedded/common/src/b_BitFeatureEm/Scanner.c
    +@@ -1064,7 +1064,7 @@ void bbf_Scanner_addOutPos( struct bbs_Context* cpA,
    + 							uint32 scaleA, 
    + 							int32 actA )
    + {
    +-	if( ( ptrA->outCountE * 4 ) < ptrA->outArrE.sizeE )
    ++	if( ( ptrA->outCountE * 4 + 3 ) < ptrA->outArrE.sizeE )
    + 	{
    +         ptrA->outArrE.arrPtrE[ ptrA->outCountE * 4 + 0 ] = xA;
    +         ptrA->outArrE.arrPtrE[ ptrA->outCountE * 4 + 1 ] = yA;
    diff --git a/external_svox.patch b/external_svox.patch
    index e69de29..c5ecb05 100644
    --- a/external_svox.patch
    +++ b/external_svox.patch
    @@ -0,0 +1,27 @@
    +diff --git a/pico/tts/svox_ssml_parser.cpp b/pico/tts/svox_ssml_parser.cpp
    +index 1e86940..94cd25a 100755
    +--- a/pico/tts/svox_ssml_parser.cpp
    ++++ b/pico/tts/svox_ssml_parser.cpp
    +@@ -57,7 +57,12 @@ SvoxSsmlParser::SvoxSsmlParser() : m_isInBreak(0), m_appendix(NULL), m_docLangua
    +         XML_SetUserData(mParser, (void*)this);
    +         m_datasize = 512;
    +         m_data = new char[m_datasize];
    +-        m_data[0] = '\0';
    ++        if (!m_data)
    ++        {
    ++            ALOGE("Error: failed to allocate memory for string!\n");
    ++        } else {
    ++            memset(m_data, 0, m_datasize);
    ++        }
    +     }
    + }
    + 
    +@@ -120,6 +125,8 @@ void SvoxSsmlParser::startElement(const XML_Char* element, const XML_Char** attr
    +             {
    +                 ALOGE("Error: failed to allocate memory for string!\n");
    +                 return;
    ++            } else {
    ++                memset(m_data, 0, m_datasize);
    +             }
    +         }
    + 
    diff --git a/frameworks_ex.patch b/frameworks_ex.patch
    index e69de29..b17a126 100644
    --- a/frameworks_ex.patch
    +++ b/frameworks_ex.patch
    @@ -0,0 +1,27 @@
    +diff --git a/framesequence/jni/FrameSequence_gif.cpp b/framesequence/jni/FrameSequence_gif.cpp
    +index 5118319..f6f46da 100644
    +--- a/framesequence/jni/FrameSequence_gif.cpp
    ++++ b/framesequence/jni/FrameSequence_gif.cpp
    +@@ -111,12 +111,14 @@ FrameSequence_gif::FrameSequence_gif(Stream* stream) :
    +     }
    + #endif
    + 
    +-    if (mGif->SColorMap) {
    ++    const ColorMapObject* cmap = mGif->SColorMap;
    ++    if (cmap) {
    +         // calculate bg color
    +         GraphicsControlBlock gcb;
    +         DGifSavedExtensionToGCB(mGif, 0, &gcb);
    +-        if (gcb.TransparentColor == NO_TRANSPARENT_COLOR) {
    +-            mBgColor = gifColorToColor8888(mGif->SColorMap->Colors[mGif->SBackGroundColor]);
    ++        if (gcb.TransparentColor == NO_TRANSPARENT_COLOR
    ++                && mGif->SBackGroundColor < cmap->ColorCount) {
    ++            mBgColor = gifColorToColor8888(cmap->Colors[mGif->SBackGroundColor]);
    +         }
    +     }
    + }
    +@@ -359,4 +361,3 @@ static RegistryEntry gEntry = {
    +         acceptsBuffers,
    + };
    + static Registry gRegister(gEntry);
    +-
    
    From a3e9babcd34356a6717749faad8b3bd2c962ca8f Mon Sep 17 00:00:00 2001
    From: AndDiSa <anddisa@googlemail.com>
    Date: Fri, 8 Feb 2019 18:20:13 +0100
    Subject: [PATCH 109/159] update patches
    
    Change-Id: If7df0f3518a060c5d2d4aebc421f9a62ada26b9c
    ---
     build.patch                      |   4 +-
     external_opencv.patch            |  71 +++++++++
     external_skia.patch              | 102 ++++++++++++-
     external_wpa_supplicant_8.patch  | 136 +++++++++++-------
     packages_apps_email.patch        |  71 +++++++++
     packages_apps_unifiedemail.patch |  91 ++++++++++++
     system_bt.patch                  | 237 +++++++++++++++++++++++++++++--
     system_sepolicy.patch            |  20 ++-
     8 files changed, 664 insertions(+), 68 deletions(-)
     create mode 100644 external_opencv.patch
     create mode 100644 packages_apps_email.patch
     create mode 100644 packages_apps_unifiedemail.patch
    
    diff --git a/build.patch b/build.patch
    index 0730220..173e07f 100644
    --- a/build.patch
    +++ b/build.patch
    @@ -323,7 +323,7 @@ index 000000000..80664faf2
     +ALL_PREBUILT += $(INSTALLED_KERNEL_TARGET)
     +endif
     diff --git a/core/version_defaults.mk b/core/version_defaults.mk
    -index 7c9634490..546e6fb09 100644
    +index 7c9634490..34e983cd5 100644
     --- a/core/version_defaults.mk
     +++ b/core/version_defaults.mk
     @@ -131,7 +131,7 @@ ifeq "" "$(PLATFORM_SECURITY_PATCH)"
    @@ -331,7 +331,7 @@ index 7c9634490..546e6fb09 100644
          #  It must match one of the Android Security Patch Level strings of the Public Security Bulletins.
          #  If there is no $PLATFORM_SECURITY_PATCH set, keep it empty.
     -    PLATFORM_SECURITY_PATCH := 2017-08-05
    -+    PLATFORM_SECURITY_PATCH := 2019-01-05
    ++    PLATFORM_SECURITY_PATCH := 2019-02-05
      endif
      
      ifeq "" "$(PLATFORM_BASE_OS)"
    diff --git a/external_opencv.patch b/external_opencv.patch
    new file mode 100644
    index 0000000..ece3db5
    --- /dev/null
    +++ b/external_opencv.patch
    @@ -0,0 +1,71 @@
    +diff --git a/otherlibs/highgui/grfmt_bmp.cpp b/otherlibs/highgui/grfmt_bmp.cpp
    +index c67ed4132..b39e23a53 100644
    +--- a/otherlibs/highgui/grfmt_bmp.cpp
    ++++ b/otherlibs/highgui/grfmt_bmp.cpp
    +@@ -102,6 +102,7 @@ bool  GrFmtBmpReader::ReadHeader()
    +         m_offset = m_strm.GetDWord();
    + 
    +         int  size = m_strm.GetDWord();
    ++	assert(size > 0);
    + 
    +         if( size >= 36 )
    +         {
    +diff --git a/otherlibs/highgui/grfmt_jpeg2000.cpp b/otherlibs/highgui/grfmt_jpeg2000.cpp
    +index 53067f278..529c9f6f7 100644
    +--- a/otherlibs/highgui/grfmt_jpeg2000.cpp
    ++++ b/otherlibs/highgui/grfmt_jpeg2000.cpp
    +@@ -49,7 +49,8 @@
    + GrFmtJpeg2000::GrFmtJpeg2000()
    + {
    +     m_sign_len = 12;
    +-    m_signature = "\x00\x00\x00\x0cjP  \r\n\x87\n";
    ++    static const unsigned char signature_[12] = { 0, 0, 0, 0x0c, 'j', 'P', ' ', ' ', 13, 10, 0x87, 10};
    ++    m_signature = String((const char*)signature_, (const char*)signature_ + sizeof(signature_));
    +     m_description = "JPEG-2000 files (*.jp2)";
    +     jas_init();
    + }
    +@@ -115,6 +116,8 @@ bool  GrFmtJpeg2000Reader::ReadHeader()
    +     {
    +         m_image = jas_image_decode( m_stream, -1, 0 );
    +         if( m_image ) {
    ++            assert(0 == (jas_image_tlx(image));
    ++            assert(0 == (jas_image_tly(image));
    +             m_width = jas_image_width( m_image );
    +             m_height = jas_image_height( m_image );
    + 
    +@@ -123,6 +126,7 @@ bool  GrFmtJpeg2000Reader::ReadHeader()
    +             for( int i = 0; i < numcmpts; i++ )
    +             {
    +                 int depth = jas_image_cmptprec( m_image, i );
    ++		assert(depth == 0 || depth == depth_i);
    +                 if( depth > m_bit_depth )
    +                     m_bit_depth = depth;
    +                 if( m_bit_depth > 8 )
    +@@ -130,11 +134,27 @@ bool  GrFmtJpeg2000Reader::ReadHeader()
    + 
    +                 if( jas_image_cmpttype( m_image, i ) > 2 )
    +                     continue;
    ++                int sgnd = jas_image_cmptsgnd(image, i);
    ++                int xstart = jas_image_cmpttlx(image, i);
    ++                int xend = jas_image_cmptbrx(image, i);
    ++                int xstep = jas_image_cmpthstep(image, i);
    ++                int ystart = jas_image_cmpttly(image, i);
    ++                int yend = jas_image_cmptbry(image, i);
    ++                int ystep = jas_image_cmptvstep(image, i);
    ++		assert(sgnd == 0);
    ++                assert(xstart == 0);
    ++                assert(ystart == 0);
    ++                assert(xstep == 1);
    ++                assert(ystep == 1);
    ++                assert(xend == m_width);
    ++                assert(yend == m_height);
    +                 cntcmpts++;
    +             }
    + 
    +             if( cntcmpts )
    +             {
    ++                assert(depth == 8 || depth == 16);
    ++                assert(cntcmpts == 1 || cntcmpts == 3);
    +                 m_iscolor = (cntcmpts > 1);
    + 
    +                 result = true;
    diff --git a/external_skia.patch b/external_skia.patch
    index 9bc6892..5d3bb9a 100644
    --- a/external_skia.patch
    +++ b/external_skia.patch
    @@ -1,8 +1,16 @@
     diff --git a/Android.mk b/Android.mk
    -index 77c258aa06..4dbd17bb63 100644
    +index 77c258aa06..a501e2cb50 100644
     --- a/Android.mk
     +++ b/Android.mk
    -@@ -643,7 +643,6 @@ LOCAL_SRC_FILES := \
    +@@ -89,6 +89,7 @@ LOCAL_SRC_FILES := \
    + 	src/codec/SkWebpCodec.cpp \
    + 	src/codec/SkCodecImageGenerator.cpp \
    + 	src/ports/SkImageGenerator_skia.cpp \
    ++	src/android/SkAndroidFrameworkUtils.cpp \
    + 	src/android/SkBitmapRegionCanvas.cpp \
    + 	src/android/SkBitmapRegionCodec.cpp \
    + 	src/android/SkBitmapRegionDecoder.cpp \
    +@@ -643,7 +644,6 @@ LOCAL_SRC_FILES := \
      	src/utils/SkPatchGrid.cpp \
      	src/utils/SkPatchUtils.cpp \
      	src/utils/SkRGBAToYUV.cpp \
    @@ -22,6 +30,37 @@ index e51da0fc6e..f362c99aca 100644
      	../tests/RTreeTest.cpp \
      	../tests/RandomTest.cpp \
      	../tests/ReadPixelsTest.cpp \
    +diff --git a/include/android/SkAndroidFrameworkUtils.h b/include/android/SkAndroidFrameworkUtils.h
    +new file mode 100644
    +index 0000000000..abe959983b
    +--- /dev/null
    ++++ b/include/android/SkAndroidFrameworkUtils.h
    +@@ -0,0 +1,25 @@
    ++/*
    ++ * Copyright 2017 Google Inc.
    ++ *
    ++ * Use of this source code is governed by a BSD-style license that can be
    ++ * found in the LICENSE file.
    ++ */
    ++
    ++#ifndef SkAndroidFrameworkUtils_DEFINED
    ++#define SkAndroidFrameworkUtils_DEFINED
    ++
    ++#include "SkTypes.h"
    ++
    ++#ifdef SK_BUILD_FOR_ANDROID_FRAMEWORK
    ++
    ++/**
    ++ *  SkAndroidFrameworkUtils expose private APIs used only by Android framework.
    ++ */
    ++class SkAndroidFrameworkUtils {
    ++public:
    ++    static void SafetyNetLog(const char*);
    ++};
    ++
    ++#endif // SK_BUILD_FOR_ANDROID_FRAMEWORK
    ++
    ++#endif // SkAndroidFrameworkUtils_DEFINED
     diff --git a/include/core/SkOSFile.h b/include/core/SkOSFile.h
     index f977327e25..cb775e2bc1 100644
     --- a/include/core/SkOSFile.h
    @@ -133,6 +172,31 @@ diff --git a/resources/invalid_images/b38116746.ico b/resources/invalid_images/b
     new file mode 100644
     index 0000000000..35ee5b5a28
     Binary files /dev/null and b/resources/invalid_images/b38116746.ico differ
    +diff --git a/src/android/SkAndroidFrameworkUtils.cpp b/src/android/SkAndroidFrameworkUtils.cpp
    +new file mode 100644
    +index 0000000000..968b7b7d08
    +--- /dev/null
    ++++ b/src/android/SkAndroidFrameworkUtils.cpp
    +@@ -0,0 +1,19 @@
    ++/*
    ++ * Copyright 2017 Google Inc.
    ++ *
    ++ * Use of this source code is governed by a BSD-style license that can be
    ++ * found in the LICENSE file.
    ++ */
    ++
    ++#include "SkAndroidFrameworkUtils.h"
    ++
    ++#ifdef SK_BUILD_FOR_ANDROID_FRAMEWORK
    ++
    ++#include <log/log.h>
    ++
    ++void SkAndroidFrameworkUtils::SafetyNetLog(const char* bugNumber) {
    ++    android_errorWriteLog(0x534e4554, bugNumber);
    ++}
    ++
    ++#endif // SK_BUILD_FOR_ANDROID_FRAMEWORK
    ++
     diff --git a/src/codec/SkIcoCodec.cpp b/src/codec/SkIcoCodec.cpp
     index dc4222a43c..8b3d26dd86 100644
     --- a/src/codec/SkIcoCodec.cpp
    @@ -179,6 +243,40 @@ index 9a3f248af5..5a3740d2c0 100644
      #include "SkTypes.h"
      
      /*
    +diff --git a/src/codec/SkSwizzler.cpp b/src/codec/SkSwizzler.cpp
    +index 133736879f..f4be612c4d 100644
    +--- a/src/codec/SkSwizzler.cpp
    ++++ b/src/codec/SkSwizzler.cpp
    +@@ -11,6 +11,10 @@
    + #include "SkSwizzler.h"
    + #include "SkTemplates.h"
    + 
    ++#ifdef SK_BUILD_FOR_ANDROID_FRAMEWORK
    ++    #include "SkAndroidFrameworkUtils.h"
    ++#endif
    ++
    + static void copy(void* dst, const uint8_t* src, int width, int bpp, int deltaSrc, int offset,
    +         const SkPMColor ctable[]) {
    +     // This function must not be called if we are sampling.  If we are not
    +@@ -937,6 +941,18 @@ int SkSwizzler::onSetSampleX(int sampleX) {
    +     fSwizzleWidth = get_scaled_dimension(fSrcWidth, sampleX);
    +     fAllocatedWidth = get_scaled_dimension(fDstWidth, sampleX);
    + 
    ++    if (fDstOffsetBytes > 0) {
    ++        const size_t dstSwizzleBytes   = fSwizzleWidth   * fDstBPP;
    ++        const size_t dstAllocatedBytes = fAllocatedWidth * fDstBPP;
    ++        if (fDstOffsetBytes + dstSwizzleBytes > dstAllocatedBytes) {
    ++#ifdef SK_BUILD_FOR_ANDROID_FRAMEWORK
    ++            SkAndroidFrameworkUtils::SafetyNetLog("118143775");
    ++#endif
    ++            SkASSERT(dstSwizzleBytes < dstAllocatedBytes);
    ++            fDstOffsetBytes = dstAllocatedBytes - dstSwizzleBytes;
    ++        }
    ++    }
    ++
    +     // The optimized swizzler functions do not support sampling.  Sampled swizzles
    +     // are already fast because they skip pixels.  We haven't seen a situation
    +     // where speeding up sampling has a significant impact on total decode time.
     diff --git a/src/codec/SkWebpCodec.cpp b/src/codec/SkWebpCodec.cpp
     index 6cfb385294..8acd205d13 100644
     --- a/src/codec/SkWebpCodec.cpp
    diff --git a/external_wpa_supplicant_8.patch b/external_wpa_supplicant_8.patch
    index ca73422..61b33e4 100644
    --- a/external_wpa_supplicant_8.patch
    +++ b/external_wpa_supplicant_8.patch
    @@ -1,5 +1,5 @@
     diff --git a/hostapd/Android.mk b/hostapd/Android.mk
    -index 67ca129..588fed9 100644
    +index 67ca1295..588fed90 100644
     --- a/hostapd/Android.mk
     +++ b/hostapd/Android.mk
     @@ -210,11 +210,6 @@ L_CFLAGS += -DCONFIG_RSN_PREAUTH
    @@ -15,7 +15,7 @@ index 67ca129..588fed9 100644
      NEED_AES_OMAC1=y
      CONFIG_PROXYARP=y
     diff --git a/hostapd/Makefile b/hostapd/Makefile
    -index fa4af82..7a5781f 100644
    +index fa4af82a..7a5781f1 100644
     --- a/hostapd/Makefile
     +++ b/hostapd/Makefile
     @@ -248,11 +248,6 @@ CFLAGS += -DCONFIG_RSN_PREAUTH
    @@ -31,7 +31,7 @@ index fa4af82..7a5781f 100644
      NEED_AES_OMAC1=y
      CONFIG_PROXYARP=y
     diff --git a/hostapd/android.config b/hostapd/android.config
    -index e382c40..e8fd2df 100644
    +index e382c408..e8fd2dfd 100644
     --- a/hostapd/android.config
     +++ b/hostapd/android.config
     @@ -44,9 +44,6 @@ CONFIG_DRIVER_NL80211_QCA=y
    @@ -45,7 +45,7 @@ index e382c40..e8fd2df 100644
      # This version is an experimental implementation based on IEEE 802.11w/D1.0
      # draft and is subject to change since the standard has not yet been finalized.
     diff --git a/hostapd/config_file.c b/hostapd/config_file.c
    -index c35d5ae..8f49179 100644
    +index c35d5aec..8f49179d 100644
     --- a/hostapd/config_file.c
     +++ b/hostapd/config_file.c
     @@ -2515,10 +2515,9 @@ static int hostapd_config_fill(struct hostapd_config *conf,
    @@ -62,7 +62,7 @@ index c35d5ae..8f49179 100644
      	} else if (os_strcmp(buf, "mobility_domain") == 0) {
      		if (os_strlen(pos) != 2 * MOBILITY_DOMAIN_ID_LEN ||
     diff --git a/hostapd/ctrl_iface.c b/hostapd/ctrl_iface.c
    -index a87f117..09e3bc4 100644
    +index a87f1174..09e3bc40 100644
     --- a/hostapd/ctrl_iface.c
     +++ b/hostapd/ctrl_iface.c
     @@ -1531,6 +1531,67 @@ static int hostapd_ctrl_iface_mgmt_tx(struct hostapd_data *hapd, char *cmd)
    @@ -145,7 +145,7 @@ index a87f117..09e3bc4 100644
      		if (hostapd_ctrl_iface_eapol_rx(hapd, buf + 9) < 0)
      			reply_len = -1;
     diff --git a/hostapd/defconfig b/hostapd/defconfig
    -index f7b60e0..5ee37dd 100644
    +index f7b60e04..5ee37dd9 100644
     --- a/hostapd/defconfig
     +++ b/hostapd/defconfig
     @@ -50,9 +50,6 @@ CONFIG_IAPP=y
    @@ -159,7 +159,7 @@ index f7b60e0..5ee37dd 100644
      CONFIG_IEEE80211W=y
      
     diff --git a/hostapd/hostapd.conf b/hostapd/hostapd.conf
    -index d943a43..1648fd0 100644
    +index d943a43d..1648fd0b 100644
     --- a/hostapd/hostapd.conf
     +++ b/hostapd/hostapd.conf
     @@ -1192,12 +1192,6 @@ own_ip_addr=127.0.0.1
    @@ -176,7 +176,7 @@ index d943a43..1648fd0 100644
      # 0 = disabled (default)
      # 1 = optional
     diff --git a/src/ap/Makefile b/src/ap/Makefile
    -index 98788fe..d67405f 100644
    +index 98788fef..d67405f8 100644
     --- a/src/ap/Makefile
     +++ b/src/ap/Makefile
     @@ -45,7 +45,6 @@ LIB_OBJS= \
    @@ -188,7 +188,7 @@ index 98788fe..d67405f 100644
      	preauth_auth.o \
      	sta_info.o \
     diff --git a/src/ap/ap_config.h b/src/ap/ap_config.h
    -index 2d07c67..4b00c29 100644
    +index 2d07c67b..4b00c296 100644
     --- a/src/ap/ap_config.h
     +++ b/src/ap/ap_config.h
     @@ -322,7 +322,6 @@ struct hostapd_bss_config {
    @@ -200,7 +200,7 @@ index 2d07c67..4b00c29 100644
      #ifdef CONFIG_IEEE80211R
      	/* IEEE 802.11r - Fast BSS Transition */
     diff --git a/src/ap/ieee802_11.c b/src/ap/ieee802_11.c
    -index 6a373c5..b1cfb51 100644
    +index 6a373c54..b1cfb51c 100644
     --- a/src/ap/ieee802_11.c
     +++ b/src/ap/ieee802_11.c
     @@ -1774,6 +1774,7 @@ static int add_associated_sta(struct hostapd_data *hapd,
    @@ -266,7 +266,7 @@ index 6a373c5..b1cfb51 100644
      #endif /* CONFIG_TESTING_OPTIONS */
     diff --git a/src/ap/peerkey_auth.c b/src/ap/peerkey_auth.c
     deleted file mode 100644
    -index efc1d7e..0000000
    +index efc1d7e4..00000000
     --- a/src/ap/peerkey_auth.c
     +++ /dev/null
     @@ -1,396 +0,0 @@
    @@ -667,7 +667,7 @@ index efc1d7e..0000000
     -
     -#endif /* CONFIG_PEERKEY */
     diff --git a/src/ap/wnm_ap.c b/src/ap/wnm_ap.c
    -index 41d50ce..02daa9b 100644
    +index 41d50ceb..02daa9bc 100644
     --- a/src/ap/wnm_ap.c
     +++ b/src/ap/wnm_ap.c
     @@ -202,6 +202,13 @@ static void ieee802_11_rx_wnmsleep_req(struct hostapd_data *hapd,
    @@ -685,7 +685,7 @@ index 41d50ce..02daa9b 100644
      	while (pos + 1 < frm + len) {
      		u8 ie_len = pos[1];
     diff --git a/src/ap/wpa_auth.c b/src/ap/wpa_auth.c
    -index 3587086..e5974ff 100644
    +index 35870864..e5974ff1 100644
     --- a/src/ap/wpa_auth.c
     +++ b/src/ap/wpa_auth.c
     @@ -879,8 +879,7 @@ void wpa_receive(struct wpa_authenticator *wpa_auth,
    @@ -880,7 +880,7 @@ index 3587086..e5974ff 100644
      			     struct rsn_pmksa_cache_entry *entry)
      {
     diff --git a/src/ap/wpa_auth.h b/src/ap/wpa_auth.h
    -index 0de8d97..032b0a3 100644
    +index 0de8d976..032b0a32 100644
     --- a/src/ap/wpa_auth.h
     +++ b/src/ap/wpa_auth.h
     @@ -147,7 +147,6 @@ struct wpa_auth_config {
    @@ -909,7 +909,7 @@ index 0de8d97..032b0a3 100644
      			     struct rsn_pmksa_cache_entry *entry);
      struct rsn_pmksa_cache_entry *
     diff --git a/src/ap/wpa_auth_ft.c b/src/ap/wpa_auth_ft.c
    -index 42242a5..e63b99a 100644
    +index 42242a54..e63b99ad 100644
     --- a/src/ap/wpa_auth_ft.c
     +++ b/src/ap/wpa_auth_ft.c
     @@ -780,6 +780,14 @@ void wpa_ft_install_ptk(struct wpa_state_machine *sm)
    @@ -944,7 +944,7 @@ index 42242a5..e63b99a 100644
      
      	buflen = 2 + sizeof(struct rsn_mdie) + 2 + sizeof(struct rsn_ftie) +
     diff --git a/src/ap/wpa_auth_glue.c b/src/ap/wpa_auth_glue.c
    -index 5fe0987..cbc1dbc 100644
    +index 5fe0987f..cbc1dbc4 100644
     --- a/src/ap/wpa_auth_glue.c
     +++ b/src/ap/wpa_auth_glue.c
     @@ -44,7 +44,6 @@ static void hostapd_wpa_auth_conf(struct hostapd_bss_config *conf,
    @@ -956,7 +956,7 @@ index 5fe0987..cbc1dbc 100644
      	wconf->wmm_uapsd = conf->wmm_uapsd;
      	wconf->disable_pmksa_caching = conf->disable_pmksa_caching;
     diff --git a/src/ap/wpa_auth_i.h b/src/ap/wpa_auth_i.h
    -index 72b7eb3..b781605 100644
    +index 72b7eb37..b781605e 100644
     --- a/src/ap/wpa_auth_i.h
     +++ b/src/ap/wpa_auth_i.h
     @@ -65,6 +65,7 @@ struct wpa_state_machine {
    @@ -989,7 +989,7 @@ index 72b7eb3..b781605 100644
      int wpa_write_mdie(struct wpa_auth_config *conf, u8 *buf, size_t len);
      int wpa_write_ftie(struct wpa_auth_config *conf, const u8 *r0kh_id,
     diff --git a/src/ap/wpa_auth_ie.c b/src/ap/wpa_auth_ie.c
    -index f79783b..8f855b8 100644
    +index f79783b9..8f855b83 100644
     --- a/src/ap/wpa_auth_ie.c
     +++ b/src/ap/wpa_auth_ie.c
     @@ -230,8 +230,6 @@ int wpa_write_rsn_ie(struct wpa_auth_config *conf, u8 *buf, size_t len,
    @@ -1039,7 +1039,7 @@ index f79783b..8f855b8 100644
      	if (pos[1] > RSN_SELECTOR_LEN + 2 &&
      	    RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_IGTK) {
     diff --git a/src/ap/wpa_auth_ie.h b/src/ap/wpa_auth_ie.h
    -index d2067ba..0e2b3df 100644
    +index d2067ba3..0e2b3df3 100644
     --- a/src/ap/wpa_auth_ie.h
     +++ b/src/ap/wpa_auth_ie.h
     @@ -19,16 +19,6 @@ struct wpa_eapol_ie_parse {
    @@ -1060,7 +1060,7 @@ index d2067ba..0e2b3df 100644
      	const u8 *igtk;
      	size_t igtk_len;
     diff --git a/src/common/privsep_commands.h b/src/common/privsep_commands.h
    -index 8dff303..15a1bfc 100644
    +index 8dff3038..15a1bfcd 100644
     --- a/src/common/privsep_commands.h
     +++ b/src/common/privsep_commands.h
     @@ -84,7 +84,6 @@ enum privsep_event {
    @@ -1072,7 +1072,7 @@ index 8dff303..15a1bfc 100644
      	PRIVSEP_EVENT_RX_EAPOL,
      	PRIVSEP_EVENT_SCAN_STARTED,
     diff --git a/src/common/wpa_common.c b/src/common/wpa_common.c
    -index d6295b2..41a49d0 100644
    +index d6295b2d..41a49d0e 100644
     --- a/src/common/wpa_common.c
     +++ b/src/common/wpa_common.c
     @@ -133,10 +133,6 @@ int wpa_eapol_key_mic(const u8 *key, size_t key_len, int akmp, int ver,
    @@ -1099,7 +1099,7 @@ index d6295b2..41a49d0 100644
      		os_memcpy(data, addr1, ETH_ALEN);
      		os_memcpy(data + ETH_ALEN, addr2, ETH_ALEN);
     diff --git a/src/common/wpa_common.h b/src/common/wpa_common.h
    -index af1d0f0..642b28c 100644
    +index af1d0f0c..642b28c3 100644
     --- a/src/common/wpa_common.h
     +++ b/src/common/wpa_common.h
     @@ -88,12 +88,6 @@ RSN_SELECTOR(0x00, 0x0f, 0xac, 13)
    @@ -1159,8 +1159,30 @@ index af1d0f0..642b28c 100644
      struct rsn_error_kde {
      	be16 mui;
      	be16 error_type;
    +diff --git a/src/crypto/random.c b/src/crypto/random.c
    +index 3a86a93a..5d671bdc 100644
    +--- a/src/crypto/random.c
    ++++ b/src/crypto/random.c
    +@@ -160,10 +160,17 @@ int random_get_bytes(void *buf, size_t len)
    + 	wpa_printf(MSG_MSGDUMP, "Get randomness: len=%u entropy=%u",
    + 		   (unsigned int) len, entropy);
    + 
    ++#ifdef CONFIG_USE_OPENSSL_RNG
    ++	/* Start with assumed strong randomness from OpenSSL */
    ++	ret = crypto_get_random(buf, len);
    ++	wpa_hexdump_key(MSG_EXCESSIVE, "random from crypto_get_random",
    ++			buf, len);
    ++#else /* CONFIG_USE_OPENSSL_RNG */
    + 	/* Start with assumed strong randomness from OS */
    + 	ret = os_get_random(buf, len);
    + 	wpa_hexdump_key(MSG_EXCESSIVE, "random from os_get_random",
    + 			buf, len);
    ++#endif /* CONFIG_USE_OPENSSL_RNG */
    + 
    + 	/* Mix in additional entropy extracted from the internal pool */
    + 	left = len;
     diff --git a/src/drivers/driver.h b/src/drivers/driver.h
    -index b7e0d16..bae4777 100644
    +index b7e0d163..bae47778 100644
     --- a/src/drivers/driver.h
     +++ b/src/drivers/driver.h
     @@ -3647,17 +3647,6 @@ enum wpa_event_type {
    @@ -1196,7 +1218,7 @@ index b7e0d16..bae4777 100644
      	 * struct tdls - Data for EVENT_TDLS
      	 */
     diff --git a/src/drivers/driver_common.c b/src/drivers/driver_common.c
    -index b32d35f..7c35277 100644
    +index b32d35f4..7c35277e 100644
     --- a/src/drivers/driver_common.c
     +++ b/src/drivers/driver_common.c
     @@ -35,7 +35,6 @@ const char * event_to_string(enum wpa_event_type event)
    @@ -1208,7 +1230,7 @@ index b32d35f..7c35277 100644
      	E2S(FT_RESPONSE);
      	E2S(IBSS_RSN_START);
     diff --git a/src/drivers/driver_privsep.c b/src/drivers/driver_privsep.c
    -index 43d4193..6fd298d 100644
    +index 43d41937..6fd298d6 100644
     --- a/src/drivers/driver_privsep.c
     +++ b/src/drivers/driver_privsep.c
     @@ -464,19 +464,6 @@ static void wpa_driver_privsep_event_pmkid_candidate(void *ctx, u8 *buf,
    @@ -1243,7 +1265,7 @@ index 43d4193..6fd298d 100644
      		wpa_driver_privsep_event_ft_response(drv->ctx, event_buf,
      						     event_len);
     diff --git a/src/drivers/driver_wext.c b/src/drivers/driver_wext.c
    -index 791cd5d..e149ed2 100644
    +index 791cd5d4..e149ed2d 100644
     --- a/src/drivers/driver_wext.c
     +++ b/src/drivers/driver_wext.c
     @@ -290,15 +290,6 @@ wpa_driver_wext_event_wireless_custom(void *ctx, char *custom)
    @@ -1272,7 +1294,7 @@ index 791cd5d..e149ed2 100644
      				wpa_driver_wext_event_assoc_ies(drv);
      				wpa_supplicant_event(drv->ctx, EVENT_ASSOC,
     diff --git a/src/rsn_supp/Makefile b/src/rsn_supp/Makefile
    -index d5e61fe..c2d81f2 100644
    +index d5e61fe7..c2d81f27 100644
     --- a/src/rsn_supp/Makefile
     +++ b/src/rsn_supp/Makefile
     @@ -10,7 +10,6 @@ include ../lib.rules
    @@ -1293,7 +1315,7 @@ index d5e61fe..c2d81f2 100644
      	wpa.o \
     diff --git a/src/rsn_supp/peerkey.c b/src/rsn_supp/peerkey.c
     deleted file mode 100644
    -index 79764d9..0000000
    +index 79764d94..00000000
     --- a/src/rsn_supp/peerkey.c
     +++ /dev/null
     @@ -1,1155 +0,0 @@
    @@ -2454,7 +2476,7 @@ index 79764d9..0000000
     -#endif /* CONFIG_PEERKEY */
     diff --git a/src/rsn_supp/peerkey.h b/src/rsn_supp/peerkey.h
     deleted file mode 100644
    -index 6ccd948..0000000
    +index 6ccd948b..00000000
     --- a/src/rsn_supp/peerkey.h
     +++ /dev/null
     @@ -1,82 +0,0 @@
    @@ -2541,7 +2563,7 @@ index 6ccd948..0000000
     -
     -#endif /* PEERKEY_H */
     diff --git a/src/rsn_supp/tdls.c b/src/rsn_supp/tdls.c
    -index e424168..9eb9738 100644
    +index e4241681..9eb97386 100644
     --- a/src/rsn_supp/tdls.c
     +++ b/src/rsn_supp/tdls.c
     @@ -112,6 +112,7 @@ struct wpa_tdls_peer {
    @@ -2645,7 +2667,7 @@ index e424168..9eb9738 100644
      
      #if 0
     diff --git a/src/rsn_supp/wpa.c b/src/rsn_supp/wpa.c
    -index 3c47879..a22e36d 100644
    +index 3c478792..a22e36da 100644
     --- a/src/rsn_supp/wpa.c
     +++ b/src/rsn_supp/wpa.c
     @@ -21,7 +21,6 @@
    @@ -3165,7 +3187,7 @@ index 3c47879..a22e36d 100644
      
      int wpa_sm_get_p2p_ip_addr(struct wpa_sm *sm, u8 *buf)
     diff --git a/src/rsn_supp/wpa.h b/src/rsn_supp/wpa.h
    -index c89799a..b55baac 100644
    +index c89799ac..b55baac6 100644
     --- a/src/rsn_supp/wpa.h
     +++ b/src/rsn_supp/wpa.h
     @@ -95,7 +95,6 @@ enum wpa_sm_conf_params {
    @@ -3201,7 +3223,7 @@ index c89799a..b55baac 100644
      
      int wpa_sm_set_ft_params(struct wpa_sm *sm, const u8 *ies, size_t ies_len);
     diff --git a/src/rsn_supp/wpa_ft.c b/src/rsn_supp/wpa_ft.c
    -index 205793e..d45bb45 100644
    +index 205793e7..d45bb458 100644
     --- a/src/rsn_supp/wpa_ft.c
     +++ b/src/rsn_supp/wpa_ft.c
     @@ -153,6 +153,7 @@ static u8 * wpa_ft_gen_req_ies(struct wpa_sm *sm, size_t *len,
    @@ -3234,7 +3256,7 @@ index 205793e..d45bb45 100644
      		return -1;
      
     diff --git a/src/rsn_supp/wpa_i.h b/src/rsn_supp/wpa_i.h
    -index f653ba6..2243613 100644
    +index f653ba6e..2243613f 100644
     --- a/src/rsn_supp/wpa_i.h
     +++ b/src/rsn_supp/wpa_i.h
     @@ -11,7 +11,6 @@
    @@ -3292,7 +3314,7 @@ index f653ba6..2243613 100644
      	u8 target_ap[ETH_ALEN]; /* over-the-DS target AP */
      	int set_ptk_after_assoc;
     diff --git a/src/rsn_supp/wpa_ie.c b/src/rsn_supp/wpa_ie.c
    -index c44844e..4e0c3f4 100644
    +index c44844ec..4e0c3f45 100644
     --- a/src/rsn_supp/wpa_ie.c
     +++ b/src/rsn_supp/wpa_ie.c
     @@ -405,44 +405,6 @@ static int wpa_parse_generic(const u8 *pos, const u8 *end,
    @@ -3341,7 +3363,7 @@ index c44844e..4e0c3f4 100644
      	if (pos[1] > RSN_SELECTOR_LEN + 2 &&
      	    RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_IGTK) {
     diff --git a/src/rsn_supp/wpa_ie.h b/src/rsn_supp/wpa_ie.h
    -index fe95af0..0e72af5 100644
    +index fe95af0a..0e72af56 100644
     --- a/src/rsn_supp/wpa_ie.h
     +++ b/src/rsn_supp/wpa_ie.h
     @@ -21,16 +21,6 @@ struct wpa_eapol_ie_parse {
    @@ -3362,7 +3384,7 @@ index fe95af0..0e72af5 100644
      	const u8 *igtk;
      	size_t igtk_len;
     diff --git a/wpa_supplicant/Android.mk b/wpa_supplicant/Android.mk
    -index f65076c..71236a5 100644
    +index f65076c7..802c4ae9 100644
     --- a/wpa_supplicant/Android.mk
     +++ b/wpa_supplicant/Android.mk
     @@ -247,15 +247,10 @@ ifdef CONFIG_TDLS_TESTING
    @@ -3391,8 +3413,16 @@ index f65076c..71236a5 100644
      endif
      
      ifdef CONFIG_ACS
    +@@ -931,6 +923,7 @@ endif
    + 
    + ifndef CONFIG_TLS
    + CONFIG_TLS=openssl
    ++L_CFLAGS += -DCONFIG_USE_OPENSSL_RNG
    + endif
    + 
    + ifdef CONFIG_TLSV11
     diff --git a/wpa_supplicant/Makefile b/wpa_supplicant/Makefile
    -index 550d44b..b057f7f 100644
    +index 550d44b2..b057f7f1 100644
     --- a/wpa_supplicant/Makefile
     +++ b/wpa_supplicant/Makefile
     @@ -286,15 +286,10 @@ ifdef CONFIG_TDLS_TESTING
    @@ -3422,7 +3452,7 @@ index 550d44b..b057f7f 100644
      
      ifdef CONFIG_ACS
     diff --git a/wpa_supplicant/android.config b/wpa_supplicant/android.config
    -index 0a8bf98..8eb6443 100644
    +index 0a8bf981..8eb64431 100644
     --- a/wpa_supplicant/android.config
     +++ b/wpa_supplicant/android.config
     @@ -263,9 +263,6 @@ CONFIG_ELOOP=eloop
    @@ -3436,7 +3466,7 @@ index 0a8bf98..8eb6443 100644
      # Driver support is also needed for IEEE 802.11w.
      CONFIG_IEEE80211W=y
     diff --git a/wpa_supplicant/config.c b/wpa_supplicant/config.c
    -index 4376676..6cbbe2d 100644
    +index 43766763..6cbbe2d7 100644
     --- a/wpa_supplicant/config.c
     +++ b/wpa_supplicant/config.c
     @@ -1810,6 +1810,24 @@ static char * wpa_config_write_mesh_basic_rates(const struct parse_data *data,
    @@ -3474,7 +3504,7 @@ index 4376676..6cbbe2d 100644
      	{ INT_RANGE(frequency, 0, 65000) },
      	{ INT_RANGE(fixed_freq, 0, 1) },
     diff --git a/wpa_supplicant/config_file.c b/wpa_supplicant/config_file.c
    -index 38061f1..1d317fc 100644
    +index 38061f1c..1d317fc5 100644
     --- a/wpa_supplicant/config_file.c
     +++ b/wpa_supplicant/config_file.c
     @@ -752,7 +752,6 @@ static void wpa_config_write_network(FILE *f, struct wpa_ssid *ssid)
    @@ -3486,7 +3516,7 @@ index 38061f1..1d317fc 100644
      	INT(max_oper_chwidth);
      	INT(pbss);
     diff --git a/wpa_supplicant/config_ssid.h b/wpa_supplicant/config_ssid.h
    -index eb7b87b..5b6f426 100644
    +index eb7b87be..5b6f426d 100644
     --- a/wpa_supplicant/config_ssid.h
     +++ b/wpa_supplicant/config_ssid.h
     @@ -387,17 +387,6 @@ struct wpa_ssid {
    @@ -3508,7 +3538,7 @@ index eb7b87b..5b6f426 100644
      	 * id_str - Network identifier string for external scripts
      	 *
     diff --git a/wpa_supplicant/config_winreg.c b/wpa_supplicant/config_winreg.c
    -index 199f04f..ca70474 100644
    +index 199f04fb..ca70474e 100644
     --- a/wpa_supplicant/config_winreg.c
     +++ b/wpa_supplicant/config_winreg.c
     @@ -924,7 +924,6 @@ static int wpa_config_write_network(HKEY hk, struct wpa_ssid *ssid, int id)
    @@ -3520,7 +3550,7 @@ index 199f04f..ca70474 100644
      	write_int(netw, "ieee80211w", ssid->ieee80211w,
      		  MGMT_FRAME_PROTECTION_DEFAULT);
     diff --git a/wpa_supplicant/ctrl_iface.c b/wpa_supplicant/ctrl_iface.c
    -index 8574437..80f1d41 100644
    +index 85744379..80f1d410 100644
     --- a/wpa_supplicant/ctrl_iface.c
     +++ b/wpa_supplicant/ctrl_iface.c
     @@ -575,27 +575,6 @@ static int wpa_supplicant_ctrl_iface_preauth(struct wpa_supplicant *wpa_s,
    @@ -3564,7 +3594,7 @@ index 8574437..80f1d41 100644
      	} else if (os_strncmp(buf, "FT_DS ", 6) == 0) {
      		if (wpa_supplicant_ctrl_iface_ft_ds(wpa_s, buf + 6))
     diff --git a/wpa_supplicant/defconfig b/wpa_supplicant/defconfig
    -index 1d05198..5531386 100644
    +index 1d05198f..55313869 100644
     --- a/wpa_supplicant/defconfig
     +++ b/wpa_supplicant/defconfig
     @@ -288,9 +288,6 @@ CONFIG_BACKEND=file
    @@ -3578,7 +3608,7 @@ index 1d05198..5531386 100644
      # Driver support is also needed for IEEE 802.11w.
      #CONFIG_IEEE80211W=y
     diff --git a/wpa_supplicant/events.c b/wpa_supplicant/events.c
    -index 1b3d8a9..46f2924 100644
    +index 1b3d8a91..46f29240 100644
     --- a/wpa_supplicant/events.c
     +++ b/wpa_supplicant/events.c
     @@ -2790,18 +2790,6 @@ wpa_supplicant_event_interface_status(struct wpa_supplicant *wpa_s,
    @@ -3613,7 +3643,7 @@ index 1b3d8a9..46f2924 100644
      	case EVENT_TDLS:
      		wpa_supplicant_event_tdls(wpa_s, data);
     diff --git a/wpa_supplicant/wnm_sta.c b/wpa_supplicant/wnm_sta.c
    -index f77d51a..7dc1909 100644
    +index f77d51ae..7dc1909d 100644
     --- a/wpa_supplicant/wnm_sta.c
     +++ b/wpa_supplicant/wnm_sta.c
     @@ -259,7 +259,7 @@ static void ieee802_11_rx_wnmsleep_resp(struct wpa_supplicant *wpa_s,
    @@ -3635,7 +3665,7 @@ index f77d51a..7dc1909 100644
      	    wnmsleep_ie->status == WNM_STATUS_SLEEP_EXIT_ACCEPT_GTK_UPDATE) {
      		wpa_printf(MSG_DEBUG, "Successfully recv WNM-Sleep Response "
     diff --git a/wpa_supplicant/wpa_cli.c b/wpa_supplicant/wpa_cli.c
    -index 36a7a4e..ac1a36f 100644
    +index 36a7a4eb..ac1a36fb 100644
     --- a/wpa_supplicant/wpa_cli.c
     +++ b/wpa_supplicant/wpa_cli.c
     @@ -861,13 +861,6 @@ static int wpa_cli_cmd_bss_flush(struct wpa_ctrl *ctrl, int argc, char *argv[])
    @@ -3672,7 +3702,7 @@ index 36a7a4e..ac1a36f 100644
      	  cli_cmd_flag_none,
      	  "<addr> = request over-the-DS FT with <addr>" },
     diff --git a/wpa_supplicant/wpa_priv.c b/wpa_supplicant/wpa_priv.c
    -index 511df4f..483b6d8 100644
    +index 511df4f1..483b6d85 100644
     --- a/wpa_supplicant/wpa_priv.c
     +++ b/wpa_supplicant/wpa_priv.c
     @@ -990,12 +990,6 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event,
    @@ -3689,7 +3719,7 @@ index 511df4f..483b6d8 100644
      		wpa_priv_send_ft_response(iface, data);
      		break;
     diff --git a/wpa_supplicant/wpa_supplicant.c b/wpa_supplicant/wpa_supplicant.c
    -index 51bb245..aba93da 100644
    +index 51bb2457..aba93da1 100644
     --- a/wpa_supplicant/wpa_supplicant.c
     +++ b/wpa_supplicant/wpa_supplicant.c
     @@ -3238,16 +3238,6 @@ void wpa_supplicant_rx_eapol(void *ctx, const u8 *src_addr,
    @@ -3710,7 +3740,7 @@ index 51bb245..aba93da 100644
      	    (wpa_s->last_eapol_matches_bssid &&
      #ifdef CONFIG_AP
     diff --git a/wpa_supplicant/wpa_supplicant.conf b/wpa_supplicant/wpa_supplicant.conf
    -index e55b380..512116a 100644
    +index e55b380f..512116a0 100644
     --- a/wpa_supplicant/wpa_supplicant.conf
     +++ b/wpa_supplicant/wpa_supplicant.conf
     @@ -865,12 +865,6 @@ fast_reauth=1
    @@ -3727,7 +3757,7 @@ index e55b380..512116a 100644
      # enforce rekeying of PTK to mitigate some attacks against TKIP deficiencies.
      #
     diff --git a/wpa_supplicant/wpa_supplicant_template.conf b/wpa_supplicant/wpa_supplicant_template.conf
    -index f3f2a64..d511029 100644
    +index f3f2a641..d5110295 100644
     --- a/wpa_supplicant/wpa_supplicant_template.conf
     +++ b/wpa_supplicant/wpa_supplicant_template.conf
     @@ -3,4 +3,4 @@ update_config=1
    @@ -3737,7 +3767,7 @@ index f3f2a64..d511029 100644
     -pmf=1
     +pmf=0
     diff --git a/wpa_supplicant/wpas_glue.c b/wpa_supplicant/wpas_glue.c
    -index f84c8b9..8c1d4fc 100644
    +index f84c8b90..8c1d4fcb 100644
     --- a/wpa_supplicant/wpas_glue.c
     +++ b/wpa_supplicant/wpas_glue.c
     @@ -1105,7 +1105,6 @@ void wpa_supplicant_rsn_supp_set_config(struct wpa_supplicant *wpa_s,
    diff --git a/packages_apps_email.patch b/packages_apps_email.patch
    new file mode 100644
    index 0000000..0ed3187
    --- /dev/null
    +++ b/packages_apps_email.patch
    @@ -0,0 +1,71 @@
    +diff --git a/AndroidManifest.xml b/AndroidManifest.xml
    +index bbe02d4ae..ae130648d 100644
    +--- a/AndroidManifest.xml
    ++++ b/AndroidManifest.xml
    +@@ -89,7 +89,7 @@
    + 
    +         <uses-library android:name="org.apache.http.legacy" android:required="false" />
    +         <activity
    +-            android:name="com.android.email.activity.ComposeActivityEmail"
    ++            android:name="com.android.email.activity.ComposeActivityEmailExternal"
    +             android:label="@string/app_name"
    +             android:documentLaunchMode="intoExisting"
    +             android:autoRemoveFromRecents="true"
    +@@ -144,6 +144,19 @@
    +                 <data android:scheme="mailto" />
    +             </intent-filter>
    + 
    ++        </activity>
    ++
    ++        <!--
    ++            There are 2 ComposeActivityEmail activities (here and above) because one is listening
    ++             for intents broadcasted internally and the other for those broadcasted from external
    ++             applications. Refer to b/32068883.
    ++        -->
    ++        <activity android:name="com.android.email.activity.ComposeActivityEmail"
    ++            android:exported="false"
    ++            android:label="@string/app_name"
    ++            android:documentLaunchMode="intoExisting"
    ++            android:autoRemoveFromRecents="true"
    ++            android:theme="@style/ComposeTheme">
    +             <intent-filter>
    +                 <action android:name="com.android.mail.intent.action.LAUNCH_COMPOSE" />
    +                 <category android:name="android.intent.category.DEFAULT" />
    +diff --git a/src/com/android/email/activity/ComposeActivityEmailExternal.java b/src/com/android/email/activity/ComposeActivityEmailExternal.java
    +new file mode 100644
    +index 000000000..455193bea
    +--- /dev/null
    ++++ b/src/com/android/email/activity/ComposeActivityEmailExternal.java
    +@@ -0,0 +1,32 @@
    ++/**
    ++ * Copyright (C) 2018 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 com.android.email.activity;
    ++
    ++/**
    ++ * A subclass of {@link ComposeActivityEmail} which is exported for other Android packages to open.
    ++ */
    ++public class ComposeActivityEmailExternal extends ComposeActivityEmail {
    ++
    ++  /**
    ++   * Only relevant when WebView Compose is enabled. Change this when WebView
    ++   * Compose is enabled for Email.
    ++   */
    ++  @Override
    ++  public boolean isExternal() {
    ++      return false;
    ++  }
    ++}
    diff --git a/packages_apps_unifiedemail.patch b/packages_apps_unifiedemail.patch
    new file mode 100644
    index 0000000..ac67809
    --- /dev/null
    +++ b/packages_apps_unifiedemail.patch
    @@ -0,0 +1,91 @@
    +diff --git a/src/com/android/mail/compose/ComposeActivity.java b/src/com/android/mail/compose/ComposeActivity.java
    +index 5f125abe6..cae4f2cea 100644
    +--- a/src/com/android/mail/compose/ComposeActivity.java
    ++++ b/src/com/android/mail/compose/ComposeActivity.java
    +@@ -147,7 +147,8 @@ public class ComposeActivity extends ActionBarActivity
    +      * An {@link Intent} action that launches {@link ComposeActivity}, but is handled as if the
    +      * {@link Activity} were launched with no special action.
    +      */
    +-    private static final String ACTION_LAUNCH_COMPOSE =
    ++    @VisibleForTesting
    ++    static final String ACTION_LAUNCH_COMPOSE =
    +             "com.android.mail.intent.action.LAUNCH_COMPOSE";
    + 
    +     // Identifiers for which type of composition this is
    +@@ -509,6 +510,11 @@ public class ComposeActivity extends ActionBarActivity
    +         context.startActivity(intent);
    +     }
    + 
    ++    /** Returns true if activity is started from an intent from an external application. */
    ++    public boolean isExternal() {
    ++        return false;
    ++    }
    ++
    +     @Override
    +     protected void onCreate(Bundle savedInstanceState) {
    +         super.onCreate(savedInstanceState);
    +@@ -528,6 +534,16 @@ public class ComposeActivity extends ActionBarActivity
    +         checkValidAccounts();
    +     }
    + 
    ++    /** Used for escaping plaintext. If the input is null, then it will return an empty String. */
    ++    private static String escapeAndReplaceHtml(CharSequence text) {
    ++      if (text == null) {
    ++        return "";
    ++      }
    ++      String body = Html.escapeHtml(text);
    ++      // Replace \r\n and \n with <br> tags
    ++      return body.replaceAll("(&#13;&#10;|&#10;)", "<br>");
    ++    }
    ++
    +     private void finishCreate() {
    +         final Bundle savedState = mInnerSavedState;
    +         findViews();
    +@@ -566,6 +582,9 @@ public class ComposeActivity extends ActionBarActivity
    +             message = intent.getParcelableExtra(ORIGINAL_DRAFT_MESSAGE);
    +             previews = intent.getParcelableArrayListExtra(EXTRA_ATTACHMENT_PREVIEWS);
    +             mRefMessage = intent.getParcelableExtra(EXTRA_IN_REFERENCE_TO_MESSAGE);
    ++            if (isExternal() && mRefMessage != null && !TextUtils.isEmpty(mRefMessage.bodyHtml)) {
    ++                mRefMessage.bodyHtml = escapeAndReplaceHtml(mRefMessage.bodyHtml);
    ++            }
    +             mRefMessageUri = intent.getParcelableExtra(EXTRA_IN_REFERENCE_TO_MESSAGE_URI);
    +             quotedText = null;
    + 
    +@@ -1532,6 +1551,9 @@ public class ComposeActivity extends ActionBarActivity
    +                 }
    +                 String body = intent.getStringExtra(EXTRA_BODY);
    +                 if (body != null) {
    ++                    if (isExternal()) {
    ++                        body = escapeAndReplaceHtml(body);
    ++                    }
    +                     setBody(body, false /* withSignature */);
    +                 }
    +             }
    +@@ -1695,7 +1717,10 @@ public class ComposeActivity extends ActionBarActivity
    +                 } else if (EXTRA_BODY.equals(extra)) {
    +                     setBody(value, true /* with signature */);
    +                 } else if (EXTRA_QUOTED_TEXT.equals(extra)) {
    +-                    initQuotedText(value, true /* shouldQuoteText */);
    ++                     if (isExternal()) {
    ++                         value = escapeAndReplaceHtml(value);
    ++                     }
    ++                     initQuotedText(value, true /* shouldQuoteText */);
    +                 }
    +             }
    +         }
    +diff --git a/src/com/android/mail/providers/Attachment.java b/src/com/android/mail/providers/Attachment.java
    +index b8e86edeb..af4b3e326 100644
    +--- a/src/com/android/mail/providers/Attachment.java
    ++++ b/src/com/android/mail/providers/Attachment.java
    +@@ -245,6 +245,11 @@ public class Attachment implements Parcelable {
    +                 name = MimeUtility.getHeaderParameter(contentDisposition, "filename");
    +             }
    + 
    ++            // Prevent passing in a file path as part of the name.
    ++            if (name != null) {
    ++                name = name.replace('/', '_');
    ++            }
    ++
    +             contentType = MimeType.inferMimeType(name, part.getMimeType());
    +             uri = EmlAttachmentProvider.getAttachmentUri(emlFileUri, messageId, cid);
    +             contentUri = uri;
    diff --git a/system_bt.patch b/system_bt.patch
    index d6efd66..efab3bf 100644
    --- a/system_bt.patch
    +++ b/system_bt.patch
    @@ -384,6 +384,36 @@ index f799e67e4..7d0e5bd0b 100644
          hs_data.status  = BTA_HH_OK;
          hs_data.handle  = p_cb->hid_handle;
      
    +diff --git a/bta/hl/bta_hl_main.c b/bta/hl/bta_hl_main.c
    +index b4d96cd8b..c4d9ed3dd 100644
    +--- a/bta/hl/bta_hl_main.c
    ++++ b/bta/hl/bta_hl_main.c
    +@@ -1564,7 +1564,6 @@ static void bta_hl_sdp_query_results(tBTA_HL_CB *p_cb, tBTA_HL_DATA *p_data)
    +     tBTA_HL_MCL_CB      *p_mcb =  BTA_HL_GET_MCL_CB_PTR( app_idx,  mcl_idx);
    +     tBTA_HL_SDP         *p_sdp=NULL;
    +     UINT16              event;
    +-    BOOLEAN             release_sdp_buf=FALSE;
    +     UNUSED(p_cb);
    + 
    +     event = p_data->hdr.event;
    +@@ -1572,7 +1571,6 @@ static void bta_hl_sdp_query_results(tBTA_HL_CB *p_cb, tBTA_HL_DATA *p_data)
    +     if (event == BTA_HL_SDP_QUERY_OK_EVT) {
    +         p_sdp = (tBTA_HL_SDP *)osi_malloc(sizeof(tBTA_HL_SDP));
    +         memcpy(p_sdp, &p_mcb->sdp, sizeof(tBTA_HL_SDP));
    +-        release_sdp_buf = TRUE;
    +     } else {
    +         status = BTA_HL_STATUS_SDP_FAIL;
    +     }
    +@@ -1589,9 +1587,6 @@ static void bta_hl_sdp_query_results(tBTA_HL_CB *p_cb, tBTA_HL_DATA *p_data)
    +                                p_mcb->bd_addr,p_sdp,status);
    +     p_acb->p_cback(BTA_HL_SDP_QUERY_CFM_EVT,(tBTA_HL *) &evt_data );
    + 
    +-    if (release_sdp_buf)
    +-        osi_free_and_reset((void **)&p_sdp);
    +-
    +     if (p_data->cch_sdp.release_mcl_cb) {
    +         memset(p_mcb, 0, sizeof(tBTA_HL_MCL_CB));
    +     } else {
     diff --git a/bta/pan/bta_pan_act.c b/bta/pan/bta_pan_act.c
     index 199547817..4367fce68 100644
     --- a/bta/pan/bta_pan_act.c
    @@ -503,6 +533,22 @@ index 6abf09901..9d963d1de 100644
                          ag_res.num = type;
      
                          if (res == BTA_AG_CALL_WAIT_RES)
    +diff --git a/btif/src/btif_hl.c b/btif/src/btif_hl.c
    +index eec9d3449..f0e2a879f 100644
    +--- a/btif/src/btif_hl.c
    ++++ b/btif/src/btif_hl.c
    +@@ -2333,6 +2333,11 @@ static BOOLEAN btif_hl_proc_sdp_query_cfm(tBTA_HL *p_data){
    +                 }
    +             }
    +         }
    ++
    ++    // this was allocated in bta_hl_sdp_query_results
    ++    osi_free_and_reset((void**)&p_data->sdp_query_cfm.p_sdp);
    ++ 
    ++
    +     return status;
    + }
    + 
     diff --git a/btif/src/btif_rc.c b/btif/src/btif_rc.c
     index 6572fd74e..133277a35 100644
     --- a/btif/src/btif_rc.c
    @@ -3141,7 +3187,7 @@ index fd3dc64fe..49f2d1104 100644
      
      #define ECC_PointMult(q, p, n, keyLength)  ECC_PointMult_Bin_NAF(q, p, n, keyLength)
     diff --git a/stack/smp/smp_act.c b/stack/smp/smp_act.c
    -index e4152a478..16d5e1a2d 100644
    +index e4152a478..fafb11fa8 100644
     --- a/stack/smp/smp_act.c
     +++ b/stack/smp/smp_act.c
     @@ -16,11 +16,13 @@
    @@ -3158,7 +3204,60 @@ index e4152a478..16d5e1a2d 100644
      #include "stack/smp/smp_int.h"
      #include "utils/include/bt_utils.h"
      
    -@@ -750,6 +752,18 @@ void smp_process_pairing_public_key(tSMP_CB *p_cb, tSMP_INT_DATA *p_data)
    +@@ -396,7 +398,7 @@ void smp_send_keypress_notification(tSMP_CB *p_cb, tSMP_INT_DATA *p_data)
    + *******************************************************************************/
    + void smp_send_enc_info(tSMP_CB *p_cb, tSMP_INT_DATA *p_data)
    + {
    +-    tBTM_LE_LENC_KEYS   le_key;
    ++    tBTM_LE_KEY_VALUE le_key;
    + 
    +     SMP_TRACE_DEBUG("%s p_cb->loc_enc_size = %d", __func__, p_cb->loc_enc_size);
    +     smp_update_key_mask (p_cb, SMP_SEC_KEY_TYPE_ENC, FALSE);
    +@@ -405,14 +407,13 @@ void smp_send_enc_info(tSMP_CB *p_cb, tSMP_INT_DATA *p_data)
    +     smp_send_cmd(SMP_OPCODE_MASTER_ID, p_cb);
    + 
    +     /* save the DIV and key size information when acting as slave device */
    +-    memcpy(le_key.ltk, p_cb->ltk, BT_OCTET16_LEN);
    +-    le_key.div =  p_cb->div;
    +-    le_key.key_size = p_cb->loc_enc_size;
    +-    le_key.sec_level = p_cb->sec_level;
    ++    memcpy(le_key.lenc_key.ltk, p_cb->ltk, BT_OCTET16_LEN);
    ++    le_key.lenc_key.div = p_cb->div;
    ++    le_key.lenc_key.key_size = p_cb->loc_enc_size;
    ++    le_key.lenc_key.sec_level = p_cb->sec_level;
    + 
    +     if ((p_cb->peer_auth_req & SMP_AUTH_BOND) && (p_cb->loc_auth_req & SMP_AUTH_BOND))
    +-        btm_sec_save_le_key(p_cb->pairing_bda, BTM_LE_KEY_LENC,
    +-                            (tBTM_LE_KEY_VALUE *)&le_key, TRUE);
    ++        btm_sec_save_le_key(p_cb->pairing_bda, BTM_LE_KEY_LENC, &le_key, true);
    + 
    +     SMP_TRACE_WARNING ("%s", __func__);
    + 
    +@@ -446,17 +447,17 @@ void smp_send_id_info(tSMP_CB *p_cb, tSMP_INT_DATA *p_data)
    + *******************************************************************************/
    + void smp_send_csrk_info(tSMP_CB *p_cb, tSMP_INT_DATA *p_data)
    + {
    +-    tBTM_LE_LCSRK_KEYS  key;
    ++    tBTM_LE_KEY_VALUE key;
    +     SMP_TRACE_DEBUG("%s", __func__);
    +     smp_update_key_mask (p_cb, SMP_SEC_KEY_TYPE_CSRK, FALSE);
    + 
    +     if (smp_send_cmd(SMP_OPCODE_SIGN_INFO, p_cb))
    +     {
    +-        key.div = p_cb->div;
    +-        key.sec_level = p_cb->sec_level;
    +-        key.counter = 0; /* initialize the local counter */
    +-        memcpy (key.csrk, p_cb->csrk, BT_OCTET16_LEN);
    +-        btm_sec_save_le_key(p_cb->pairing_bda, BTM_LE_KEY_LCSRK, (tBTM_LE_KEY_VALUE *)&key, TRUE);
    ++        key.lcsrk_key.div = p_cb->div;
    ++        key.lcsrk_key.sec_level = p_cb->sec_level;
    ++        key.lcsrk_key.counter = 0; /* initialize the local counter */
    ++        memcpy(key.lcsrk_key.csrk, p_cb->csrk, BT_OCTET16_LEN);
    ++        btm_sec_save_le_key(p_cb->pairing_bda, BTM_LE_KEY_LCSRK, &key, true);
    +     }
    + 
    +     smp_key_distribution_by_transport(p_cb, NULL);
    +@@ -750,6 +751,18 @@ void smp_process_pairing_public_key(tSMP_CB *p_cb, tSMP_INT_DATA *p_data)
      
          STREAM_TO_ARRAY(p_cb->peer_publ_key.x, p, BT_OCTET32_LEN);
          STREAM_TO_ARRAY(p_cb->peer_publ_key.y, p, BT_OCTET32_LEN);
    @@ -3177,7 +3276,7 @@ index e4152a478..16d5e1a2d 100644
          p_cb->flags |= SMP_PAIR_FLAG_HAVE_PEER_PUBL_KEY;
      
          smp_wait_for_both_public_keys(p_cb, NULL);
    -@@ -815,14 +829,20 @@ void smp_process_keypress_notification(tSMP_CB *p_cb, tSMP_INT_DATA *p_data)
    +@@ -815,14 +828,20 @@ void smp_process_keypress_notification(tSMP_CB *p_cb, tSMP_INT_DATA *p_data)
          UINT8 reason = SMP_INVALID_PARAMETERS;
      
          SMP_TRACE_DEBUG("%s", __func__);
    @@ -3199,7 +3298,7 @@ index e4152a478..16d5e1a2d 100644
          if (p != NULL)
          {
              STREAM_TO_UINT8(p_cb->peer_keypress_notification, p);
    -@@ -997,8 +1017,17 @@ void smp_br_select_next_key(tSMP_CB *p_cb, tSMP_INT_DATA *p_data)
    +@@ -997,8 +1016,17 @@ void smp_br_select_next_key(tSMP_CB *p_cb, tSMP_INT_DATA *p_data)
      void smp_proc_enc_info(tSMP_CB *p_cb, tSMP_INT_DATA *p_data)
      {
          UINT8   *p = (UINT8 *)p_data;
    @@ -3217,8 +3316,12 @@ index e4152a478..16d5e1a2d 100644
          STREAM_TO_ARRAY(p_cb->ltk, p, BT_OCTET16_LEN);
      
          smp_key_distribution(p_cb, NULL);
    -@@ -1013,6 +1042,16 @@ void smp_proc_master_id(tSMP_CB *p_cb, tSMP_INT_DATA *p_data)
    -     tBTM_LE_PENC_KEYS   le_key;
    +@@ -1010,36 +1038,54 @@ void smp_proc_enc_info(tSMP_CB *p_cb, tSMP_INT_DATA *p_data)
    + void smp_proc_master_id(tSMP_CB *p_cb, tSMP_INT_DATA *p_data)
    + {
    +     UINT8   *p = (UINT8 *)p_data;
    +-    tBTM_LE_PENC_KEYS   le_key;
    ++    tBTM_LE_KEY_VALUE le_key;
      
          SMP_TRACE_DEBUG("%s", __func__);
     +
    @@ -3233,8 +3336,27 @@ index e4152a478..16d5e1a2d 100644
     +
          smp_update_key_mask (p_cb, SMP_SEC_KEY_TYPE_ENC, TRUE);
      
    -     STREAM_TO_UINT16(le_key.ediv, p);
    -@@ -1032,14 +1071,23 @@ void smp_proc_master_id(tSMP_CB *p_cb, tSMP_INT_DATA *p_data)
    +-    STREAM_TO_UINT16(le_key.ediv, p);
    +-    STREAM_TO_ARRAY(le_key.rand, p, BT_OCTET8_LEN );
    ++    STREAM_TO_UINT16(le_key.penc_key.ediv, p);
    ++    STREAM_TO_ARRAY(le_key.penc_key.rand, p, BT_OCTET8_LEN);
    + 
    +     /* store the encryption keys from peer device */
    +-    memcpy(le_key.ltk, p_cb->ltk, BT_OCTET16_LEN);
    +-    le_key.sec_level = p_cb->sec_level;
    +-    le_key.key_size  = p_cb->loc_enc_size;
    ++    memcpy(le_key.penc_key.ltk, p_cb->ltk, BT_OCTET16_LEN);
    ++    le_key.penc_key.sec_level = p_cb->sec_level;
    ++    le_key.penc_key.key_size = p_cb->loc_enc_size;
    ++
    + 
    +     if ((p_cb->peer_auth_req & SMP_AUTH_BOND) && (p_cb->loc_auth_req & SMP_AUTH_BOND))
    +-        btm_sec_save_le_key(p_cb->pairing_bda,
    +-                            BTM_LE_KEY_PENC,
    +-                            (tBTM_LE_KEY_VALUE *)&le_key, TRUE);
    ++       btm_sec_save_le_key(p_cb->pairing_bda, BTM_LE_KEY_PENC, &le_key, true);
    + 
    +     smp_key_distribution(p_cb, NULL);
      }
      
      /*******************************************************************************
    @@ -3259,6 +3381,65 @@ index e4152a478..16d5e1a2d 100644
          STREAM_TO_ARRAY (p_cb->tk, p, BT_OCTET16_LEN);   /* reuse TK for IRK */
          smp_key_distribution_by_transport(p_cb, NULL);
      }
    +@@ -1051,24 +1097,24 @@ void smp_proc_id_info(tSMP_CB *p_cb, tSMP_INT_DATA *p_data)
    + void smp_proc_id_addr(tSMP_CB *p_cb, tSMP_INT_DATA *p_data)
    + {
    +     UINT8   *p = (UINT8 *)p_data;
    +-    tBTM_LE_PID_KEYS    pid_key;
    ++    tBTM_LE_KEY_VALUE pid_key;
    + 
    +     SMP_TRACE_DEBUG("%s", __func__);
    +     smp_update_key_mask (p_cb, SMP_SEC_KEY_TYPE_ID, TRUE);
    + 
    +-    STREAM_TO_UINT8(pid_key.addr_type, p);
    +-    STREAM_TO_BDADDR(pid_key.static_addr, p);
    +-    memcpy(pid_key.irk, p_cb->tk, BT_OCTET16_LEN);
    ++    STREAM_TO_UINT8(pid_key.pid_key.addr_type, p);
    ++    STREAM_TO_BDADDR(pid_key.pid_key.static_addr, p);
    ++    memcpy(pid_key.pid_key.irk, p_cb->tk, BT_OCTET16_LEN);
    + 
    +     /* to use as BD_ADDR for lk derived from ltk */
    +-    p_cb->id_addr_rcvd = TRUE;
    +-    p_cb->id_addr_type = pid_key.addr_type;
    +-    memcpy(p_cb->id_addr, pid_key.static_addr, BD_ADDR_LEN);
    ++     p_cb->id_addr_rcvd = true;
    ++     p_cb->id_addr_type = pid_key.pid_key.addr_type;
    ++     memcpy(p_cb->id_addr, pid_key.pid_key.static_addr, BD_ADDR_LEN);
    + 
    +     /* store the ID key from peer device */
    +     if ((p_cb->peer_auth_req & SMP_AUTH_BOND) && (p_cb->loc_auth_req & SMP_AUTH_BOND))
    +-        btm_sec_save_le_key(p_cb->pairing_bda, BTM_LE_KEY_PID,
    +-                            (tBTM_LE_KEY_VALUE *)&pid_key, TRUE);
    ++       btm_sec_save_le_key(p_cb->pairing_bda, BTM_LE_KEY_PID, &pid_key, true);
    ++
    +     smp_key_distribution_by_transport(p_cb, NULL);
    + }
    + 
    +@@ -1078,20 +1124,17 @@ void smp_proc_id_addr(tSMP_CB *p_cb, tSMP_INT_DATA *p_data)
    + *******************************************************************************/
    + void smp_proc_srk_info(tSMP_CB *p_cb, tSMP_INT_DATA *p_data)
    + {
    +-    tBTM_LE_PCSRK_KEYS   le_key;
    ++    tBTM_LE_KEY_VALUE le_key;
    + 
    +     SMP_TRACE_DEBUG("%s", __func__);
    +     smp_update_key_mask (p_cb, SMP_SEC_KEY_TYPE_CSRK, TRUE);
    + 
    +     /* save CSRK to security record */
    +-    le_key.sec_level = p_cb->sec_level;
    +-    memcpy (le_key.csrk, p_data, BT_OCTET16_LEN);   /* get peer CSRK */
    +-    le_key.counter = 0; /* initialize the peer counter */
    ++    le_key.pcsrk_key.sec_level = p_cb->sec_level;
    ++    le_key.pcsrk_key.counter = 0;
    + 
    +     if ((p_cb->peer_auth_req & SMP_AUTH_BOND) && (p_cb->loc_auth_req & SMP_AUTH_BOND))
    +-        btm_sec_save_le_key(p_cb->pairing_bda,
    +-                            BTM_LE_KEY_PCSRK,
    +-                            (tBTM_LE_KEY_VALUE *)&le_key, TRUE);
    ++       btm_sec_save_le_key(p_cb->pairing_bda, BTM_LE_KEY_PCSRK, &le_key, true);
    +     smp_key_distribution_by_transport(p_cb, NULL);
    + }
    + 
     diff --git a/stack/smp/smp_br_main.c b/stack/smp/smp_br_main.c
     index 11039ec20..fc0d04811 100644
     --- a/stack/smp/smp_br_main.c
    @@ -3312,7 +3493,7 @@ index c3709f8a3..67a2b397a 100644
      
          SMP_TRACE_EVENT("main smp_sm_event");
     diff --git a/stack/smp/smp_utils.c b/stack/smp/smp_utils.c
    -index a7357db05..675cb4251 100644
    +index a7357db05..42d4df911 100644
     --- a/stack/smp/smp_utils.c
     +++ b/stack/smp/smp_utils.c
     @@ -297,8 +297,7 @@ BOOLEAN  smp_send_msg_to_L2CAP(BD_ADDR rem_bda, BT_HDR *p_toL2CAP)
    @@ -3325,3 +3506,41 @@ index a7357db05..675cb4251 100644
              return FALSE;
          }
          else
    +@@ -1460,23 +1459,24 @@ BOOLEAN smp_check_commitment(tSMP_CB *p_cb)
    + *******************************************************************************/
    + void smp_save_secure_connections_long_term_key(tSMP_CB *p_cb)
    + {
    +-    tBTM_LE_LENC_KEYS   lle_key;
    +-    tBTM_LE_PENC_KEYS   ple_key;
    ++    tBTM_LE_KEY_VALUE lle_key;
    ++    tBTM_LE_KEY_VALUE ple_key;
    + 
    +     SMP_TRACE_DEBUG("%s-Save LTK as local LTK key", __func__);
    +-    memcpy(lle_key.ltk, p_cb->ltk, BT_OCTET16_LEN);
    +-    lle_key.div = 0;
    +-    lle_key.key_size = p_cb->loc_enc_size;
    +-    lle_key.sec_level = p_cb->sec_level;
    +-    btm_sec_save_le_key(p_cb->pairing_bda, BTM_LE_KEY_LENC, (tBTM_LE_KEY_VALUE *)&lle_key, TRUE);
    ++    memcpy(lle_key.lenc_key.ltk, p_cb->ltk, BT_OCTET16_LEN);
    ++    lle_key.lenc_key.div = 0;
    ++    lle_key.lenc_key.key_size = p_cb->loc_enc_size;
    ++    lle_key.lenc_key.sec_level = p_cb->sec_level;
    ++    btm_sec_save_le_key(p_cb->pairing_bda, BTM_LE_KEY_LENC, &lle_key, true);
    + 
    +     SMP_TRACE_DEBUG("%s-Save LTK as peer LTK key", __func__);
    +-    ple_key.ediv = 0;
    +-    memset(ple_key.rand, 0, BT_OCTET8_LEN);
    +-    memcpy(ple_key.ltk, p_cb->ltk, BT_OCTET16_LEN);
    +-    ple_key.sec_level = p_cb->sec_level;
    +-    ple_key.key_size  = p_cb->loc_enc_size;
    +-    btm_sec_save_le_key(p_cb->pairing_bda, BTM_LE_KEY_PENC, (tBTM_LE_KEY_VALUE *)&ple_key, TRUE);
    ++    ple_key.penc_key.ediv = 0;
    ++    memset(ple_key.penc_key.rand, 0, BT_OCTET8_LEN);
    ++    memcpy(ple_key.penc_key.ltk, p_cb->ltk, BT_OCTET16_LEN);
    ++    ple_key.penc_key.sec_level = p_cb->sec_level;
    ++    ple_key.penc_key.key_size = p_cb->loc_enc_size;
    ++    btm_sec_save_le_key(p_cb->pairing_bda, BTM_LE_KEY_PENC, &ple_key, true);
    ++
    + }
    + 
    + /*******************************************************************************
    diff --git a/system_sepolicy.patch b/system_sepolicy.patch
    index fe8ec94..329aaff 100644
    --- a/system_sepolicy.patch
    +++ b/system_sepolicy.patch
    @@ -155,10 +155,10 @@ index 45569de4..5013ad30 100644
      neverallow {
        domain
     diff --git a/file.te b/file.te
    -index 87cec829..bdc7cbe6 100644
    +index 87cec829..1ebe2163 100644
     --- a/file.te
     +++ b/file.te
    -@@ -46,6 +46,8 @@ type devpts, fs_type, mlstrustedobject;
    +@@ -46,12 +46,14 @@ type devpts, fs_type, mlstrustedobject;
      type tmpfs, fs_type;
      type shm, fs_type;
      type mqueue, fs_type;
    @@ -167,6 +167,22 @@ index 87cec829..bdc7cbe6 100644
      type fuse, sdcard_type, fs_type, mlstrustedobject;
      type sdcardfs, sdcard_type, fs_type, mlstrustedobject;
      type vfat, sdcard_type, fs_type, mlstrustedobject;
    + type debugfs, fs_type;
    +-type debugfs_trace_marker, fs_type, debugfs_type, mlstrustedobject;
    +-type debugfs_tracing, fs_type, debugfs_type;
    ++type debugfs_trace_marker, fs_type, debugfs_type, tracefs_type, mlstrustedobject;
    ++type debugfs_tracing, fs_type, debugfs_type, tracefs_type;
    + type pstorefs, fs_type;
    + type functionfs, fs_type;
    + type oemfs, fs_type, contextmount_type;
    +@@ -245,6 +247,7 @@ type property_contexts, file_type;
    + allow fs_type self:filesystem associate;
    + allow sysfs_type sysfs:filesystem associate;
    + allow debugfs_type { debugfs debugfs_tracing }:filesystem associate;
    ++allow tracefs_type debugfs_tracing:filesystem associate;
    + allow file_type labeledfs:filesystem associate;
    + allow file_type tmpfs:filesystem associate;
    + allow file_type rootfs:filesystem associate;
     diff --git a/mediaserver.te b/mediaserver.te
     index 5fbaa303..dc05e14b 100644
     --- a/mediaserver.te
    
    From e5434c6110da1659abe4392335327fdae31bc6d7 Mon Sep 17 00:00:00 2001
    From: AndDiSa <anddisa@googlemail.com>
    Date: Sat, 9 Feb 2019 13:58:22 +0100
    Subject: [PATCH 110/159] update patches
    
    Change-Id: If2fe69b1f1a334718f9f31a4cab9e7f4ce6623fa
    ---
     external_opencv.patch | 34 ++++++++++++++++++++++++++++++++++
     1 file changed, 34 insertions(+)
    
    diff --git a/external_opencv.patch b/external_opencv.patch
    index ece3db5..12f50e2 100644
    --- a/external_opencv.patch
    +++ b/external_opencv.patch
    @@ -1,3 +1,37 @@
    +diff --git a/otherlibs/highgui/bitstrm.cpp b/otherlibs/highgui/bitstrm.cpp
    +index 3a3bb1aaa..17a599356 100644
    +--- a/otherlibs/highgui/bitstrm.cpp
    ++++ b/otherlibs/highgui/bitstrm.cpp
    +@@ -209,13 +209,18 @@ void  RBaseStream::SetPos( int pos )
    + int  RBaseStream::GetPos()
    + {
    +     assert( IsOpened() );
    +-    return m_block_pos - m_block_size + (int)(m_current - m_start);
    ++    int pos = validateToInt((m_current - m_start) + m_block_pos - m_block_size );
    ++    //assert(pos >= m_block_pos); // overflow check
    ++    assert(pos >= 0); // overflow check
    ++    return pos;
    + }
    + 
    + void  RBaseStream::Skip( int bytes )
    + {
    +     assert( bytes >= 0 );
    ++    uchar* old = m_current;
    +     m_current += bytes;
    ++    assert(m_current >= old);
    + }
    + 
    + jmp_buf& RBaseStream::JmpBuf()
    +@@ -746,6 +751,9 @@ void  WBaseStream::WriteBlock()
    + {
    +     int size = (int)(m_current - m_start);
    +     assert( m_file != 0 );
    ++    assert( IsOpened() );
    ++    if (size == 0 )
    ++        return;
    + 
    +     //fseek( m_file, m_block_pos, SEEK_SET );
    +     fwrite( m_start, 1, size, m_file );
     diff --git a/otherlibs/highgui/grfmt_bmp.cpp b/otherlibs/highgui/grfmt_bmp.cpp
     index c67ed4132..b39e23a53 100644
     --- a/otherlibs/highgui/grfmt_bmp.cpp
    
    From 4c19cf0aea11cadba3442869c0d7961bfb642573 Mon Sep 17 00:00:00 2001
    From: AndDiSa <anddisa@googlemail.com>
    Date: Mon, 18 Feb 2019 18:11:17 +0100
    Subject: [PATCH 111/159] Switch to the nougat-iot-release branch of GCC 4.9
    
    Provides fixed stripper symlink, and a slightly updated Android GCC.
    
    Change-Id: I8240a8fb5aea0d0f1a134ea06f06ed2cb8b64b48
    ---
     default.xml | 2 +-
     1 file changed, 1 insertion(+), 1 deletion(-)
    
    diff --git a/default.xml b/default.xml
    index 50a594e..96bee37 100644
    --- a/default.xml
    +++ b/default.xml
    @@ -452,7 +452,7 @@
       <project path="prebuilts/eclipse" name="platform/prebuilts/eclipse" groups="pdk" />
       <project path="prebuilts/eclipse-build-deps" name="platform/prebuilts/eclipse-build-deps" groups="notdefault,eclipse" />
       <project path="prebuilts/gcc/linux-x86/aarch64/aarch64-linux-android-4.9" name="platform/prebuilts/gcc/linux-x86/aarch64/aarch64-linux-android-4.9" groups="pdk,linux,arm" />
    -  <project path="prebuilts/gcc/linux-x86/arm/arm-linux-androideabi-4.9" name="platform/prebuilts/gcc/linux-x86/arm/arm-linux-androideabi-4.9" groups="pdk,linux,arm" />
    +  <project path="prebuilts/gcc/linux-x86/arm/arm-linux-androideabi-4.9" name="platform/prebuilts/gcc/linux-x86/arm/arm-linux-androideabi-4.9" revision="nougat-iot-release" groups="pdk,linux,arm" />
       <project path="prebuilts/gcc/linux-x86/arm/arm-eabi-4.8" name="platform/prebuilts/gcc/linux-x86/arm/arm-eabi-4.8" groups="pdk,linux,arm" />
       <project path="prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.11-4.8" name="platform/prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.11-4.8" groups="pdk,linux" />
       <project path="prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.15-4.8" name="platform/prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.15-4.8"  groups="pdk,linux" />
    
    From 9f31097af0b6ff79fd6191cbca30d586bdef9fe9 Mon Sep 17 00:00:00 2001
    From: AndDiSa <anddisa@googlemail.com>
    Date: Sat, 9 Mar 2019 14:02:23 +0100
    Subject: [PATCH 112/159] update patches
    
    Change-Id: I7f640f764654eed069951591f8e5c22598b7ecb6
    ---
     build.patch                  |      4 +-
     external_libavc.patch        |     30 +
     external_libhevc.patch       |     23 +-
     external_libnfc-nci.patch    |    541 +-
     external_skia.patch          |    550 +-
     external_sqlite.patch        | 243190 +++++++++++++++++++++++++++++++-
     frameworks_av.patch          |   1390 +-
     frameworks_base.patch        |    858 +-
     frameworks_native.patch      |    201 +
     packages_apps_settings.patch |     58 +
     system_bt.patch              |    417 +-
     11 files changed, 246833 insertions(+), 429 deletions(-)
    
    diff --git a/build.patch b/build.patch
    index 173e07f..53c6c6c 100644
    --- a/build.patch
    +++ b/build.patch
    @@ -323,7 +323,7 @@ index 000000000..80664faf2
     +ALL_PREBUILT += $(INSTALLED_KERNEL_TARGET)
     +endif
     diff --git a/core/version_defaults.mk b/core/version_defaults.mk
    -index 7c9634490..34e983cd5 100644
    +index 7c9634490..5376c6b46 100644
     --- a/core/version_defaults.mk
     +++ b/core/version_defaults.mk
     @@ -131,7 +131,7 @@ ifeq "" "$(PLATFORM_SECURITY_PATCH)"
    @@ -331,7 +331,7 @@ index 7c9634490..34e983cd5 100644
          #  It must match one of the Android Security Patch Level strings of the Public Security Bulletins.
          #  If there is no $PLATFORM_SECURITY_PATCH set, keep it empty.
     -    PLATFORM_SECURITY_PATCH := 2017-08-05
    -+    PLATFORM_SECURITY_PATCH := 2019-02-05
    ++    PLATFORM_SECURITY_PATCH := 2019-03-05
      endif
      
      ifeq "" "$(PLATFORM_BASE_OS)"
    diff --git a/external_libavc.patch b/external_libavc.patch
    index d964acb..57dcecf 100644
    --- a/external_libavc.patch
    +++ b/external_libavc.patch
    @@ -416,6 +416,36 @@ index 772964a..f087f8d 100644
      
                  size = num_entries * sizeof(void *);
                  size += PAD_MAP_IDX_POC * sizeof(void *);
    +diff --git a/decoder/ih264d_parse_headers.c b/decoder/ih264d_parse_headers.c
    +index d8c37a6..47db800 100644
    +--- a/decoder/ih264d_parse_headers.c
    ++++ b/decoder/ih264d_parse_headers.c
    +@@ -904,12 +904,25 @@ WORD32 ih264d_parse_sps(dec_struct_t *ps_dec, dec_bit_stream_t *ps_bitstrm)
    +             ps_dec->u1_res_changed = 1;
    +             return IVD_RES_CHANGED;
    +         }
    ++
    ++        if((ps_dec->i4_header_decoded & 1) && (ps_dec->u2_disp_width != i4_cropped_wd))
    ++        {
    ++            ps_dec->u1_res_changed = 1;
    ++            return IVD_RES_CHANGED;
    ++        }
    ++
    +         if((ps_dec->i4_header_decoded & 1) && (ps_dec->u2_pic_ht != u2_pic_ht))
    +         {
    +             ps_dec->u1_res_changed = 1;
    +             return IVD_RES_CHANGED;
    +         }
    + 
    ++        if((ps_dec->i4_header_decoded & 1) && (ps_dec->u2_disp_height != i4_cropped_ht))
    ++        {
    ++            ps_dec->u1_res_changed = 1;
    ++            return IVD_RES_CHANGED;
    ++        }
    ++
    +         /* Check for unsupported resolutions */
    +         if((u2_pic_wd > H264_MAX_FRAME_WIDTH) || (u2_pic_ht > H264_MAX_FRAME_HEIGHT))
    +         {
     diff --git a/decoder/ih264d_parse_pslice.c b/decoder/ih264d_parse_pslice.c
     index bcfbe05..9b9256b 100644
     --- a/decoder/ih264d_parse_pslice.c
    diff --git a/external_libhevc.patch b/external_libhevc.patch
    index 91fa150..b29738f 100644
    --- a/external_libhevc.patch
    +++ b/external_libhevc.patch
    @@ -4182,7 +4182,7 @@ index d656519..d2ea7a5 100644
      
          if(1 == ps_codec->i4_pic_present)
     diff --git a/decoder/ihevcd_parse_headers.c b/decoder/ihevcd_parse_headers.c
    -index c0f1564..5fe955a 100644
    +index c0f1564..78b578a 100644
     --- a/decoder/ihevcd_parse_headers.c
     +++ b/decoder/ihevcd_parse_headers.c
     @@ -1272,12 +1272,6 @@ IHEVCD_ERROR_T ihevcd_parse_sps(codec_t *ps_codec)
    @@ -4267,7 +4267,26 @@ index c0f1564..5fe955a 100644
              ps_sps->i1_num_long_term_ref_pics_sps = value;
      
              for(i = 0; i < ps_sps->i1_num_long_term_ref_pics_sps; i++)
    -@@ -1797,6 +1815,35 @@ IHEVCD_ERROR_T ihevcd_parse_pps(codec_t *ps_codec)
    +@@ -1576,6 +1594,18 @@ IHEVCD_ERROR_T ihevcd_parse_sps(codec_t *ps_codec)
    +         if((0 >= disp_wd) || (0 >= disp_ht))
    +             return IHEVCD_INVALID_PARAMETER;
    + 
    ++        if((0 != ps_codec->u4_allocate_dynamic_done) &&
    ++                            ((ps_codec->i4_disp_wd != disp_wd) ||
    ++                            (ps_codec->i4_disp_ht != disp_ht)))
    ++        {
    ++            if(0 == ps_codec->i4_first_pic_done)
    ++            {
    ++                return IHEVCD_INVALID_PARAMETER;
    ++            }
    ++            ps_codec->i4_reset_flag = 1;
    ++            return (IHEVCD_ERROR_T)IVD_RES_CHANGED;
    ++        }
    ++
    +         ps_codec->i4_disp_wd = disp_wd;
    +         ps_codec->i4_disp_ht = disp_ht;
    + 
    +@@ -1797,6 +1827,35 @@ IHEVCD_ERROR_T ihevcd_parse_pps(codec_t *ps_codec)
          BITS_PARSE("tiles_enabled_flag", value, ps_bitstrm, 1);
          ps_pps->i1_tiles_enabled_flag = value;
      
    diff --git a/external_libnfc-nci.patch b/external_libnfc-nci.patch
    index 99a1ff8..a0eaf05 100644
    --- a/external_libnfc-nci.patch
    +++ b/external_libnfc-nci.patch
    @@ -1,5 +1,58 @@
    +diff --git a/halimpl/pn54x/hal/phNxpNciHal_ext.c b/halimpl/pn54x/hal/phNxpNciHal_ext.c
    +index 893f986..1806800 100644
    +--- a/halimpl/pn54x/hal/phNxpNciHal_ext.c
    ++++ b/halimpl/pn54x/hal/phNxpNciHal_ext.c
    +@@ -13,6 +13,7 @@
    +  * See the License for the specific language governing permissions and
    +  * limitations under the License.
    +  */
    ++#include <log/log.h>
    + #include <phNxpNciHal_ext.h>
    + #include <phNxpNciHal.h>
    + #include <phTmlNfc.h>
    +@@ -109,6 +110,16 @@ NFCSTATUS phNxpNciHal_process_ext_rsp (uint8_t *p_ntf, uint16_t *p_len)
    +     NFCSTATUS status = NFCSTATUS_SUCCESS;
    +     uint16_t rf_technology_length_param = 0;
    + 
    ++    if (p_ntf[0] == 0x61 && p_ntf[1] == 0x05 && *p_len < 14) {
    ++        if(*p_len <= 6) {
    ++            android_errorWriteLog(0x534e4554, "118152591");
    ++        }
    ++        NXPLOG_NCIHAL_E("RF_INTF_ACTIVATED_NTF length error!");
    ++        status = NFCSTATUS_FAILED;
    ++        return status;
    ++    }
    ++
    ++
    +     if (p_ntf[0] == 0x61 &&
    +         p_ntf[1] == 0x05 &&
    +         p_ntf[4] == 0x03 &&
    +diff --git a/src/nfa/dm/nfa_dm_api.c b/src/nfa/dm/nfa_dm_api.c
    +index 89f667f..fb4bdf9 100644
    +--- a/src/nfa/dm/nfa_dm_api.c
    ++++ b/src/nfa/dm/nfa_dm_api.c
    +@@ -23,6 +23,7 @@
    +  *
    +  ******************************************************************************/
    + #include <string.h>
    ++#include <log/log.h>
    + #include "nfa_api.h"
    + #include "nfa_sys.h"
    + #include "nfa_dm_int.h"
    +@@ -869,6 +870,11 @@ tNFA_STATUS NFA_SendRawFrame (UINT8  *p_raw_data,
    +         return (NFA_STATUS_INVALID_PARAM);
    + 
    +     size = BT_HDR_SIZE + NCI_MSG_OFFSET_SIZE + NCI_DATA_HDR_SIZE + data_len;
    ++    /* Check for integer overflow */
    ++    if (size < data_len) {
    ++        android_errorWriteLog(0x534e4554, "120664978");
    ++        return NFA_STATUS_INVALID_PARAM;
    ++    }
    +     if ((p_msg = (BT_HDR *) GKI_getbuf (size)) != NULL)
    +     {
    +         p_msg->event  = NFA_DM_API_RAW_FRAME_EVT;
     diff --git a/src/nfc/llcp/llcp_dlc.c b/src/nfc/llcp/llcp_dlc.c
    -index 95bcac5..30e1358 100644
    +index 95bcac5..c8a300b 100644
     --- a/src/nfc/llcp/llcp_dlc.c
     +++ b/src/nfc/llcp/llcp_dlc.c
     @@ -26,6 +26,7 @@
    @@ -26,8 +79,19 @@ index 95bcac5..30e1358 100644
              info_len = i_pdu_length - LLCP_PDU_HEADER_SIZE - LLCP_SEQUENCE_SIZE;
      
              if (info_len > p_dlcb->local_miu)
    +@@ -1088,6 +1098,10 @@ static void llcp_dlc_proc_rr_rnr_pdu (UINT8 dsap, UINT8 ptype, UINT8 ssap, UINT1
    +     {
    +         error_flags = 0;
    + 
    ++        if (length == 0) {
    ++            android_errorWriteLog(0x534e4554, "116788646");
    ++            return;
    ++        }
    +         rcv_seq = LLCP_GET_NR (*p_data);
    + 
    +         if (length != LLCP_PDU_RR_SIZE - LLCP_PDU_HEADER_SIZE)
     diff --git a/src/nfc/llcp/llcp_link.c b/src/nfc/llcp/llcp_link.c
    -index d70349c..9249539 100644
    +index d70349c..5153b74 100644
     --- a/src/nfc/llcp/llcp_link.c
     +++ b/src/nfc/llcp/llcp_link.c
     @@ -23,6 +23,7 @@
    @@ -84,6 +148,15 @@ index d70349c..9249539 100644
              LLCP_TRACE_ERROR0 ("llcp_link_proc_agf_pdu (): Received invalid AGF PDU");
              GKI_freebuf (p_agf);
              return;
    +@@ -1180,7 +1188,7 @@ static void llcp_link_proc_agf_pdu (BT_HDR *p_agf)
    +     agf_length = p_agf->len;
    +     p = (UINT8 *) (p_agf + 1) + p_agf->offset;
    + 
    +-    while (agf_length > 0)
    ++    while (agf_length > >= LLCP_PDU_HEADER_SIZE)
    +     {
    +         /* get length of PDU */
    +         p_pdu_length = p;
     @@ -1207,7 +1215,8 @@ static void llcp_link_proc_agf_pdu (BT_HDR *p_agf)
                  GKI_freebuf (p_agf);
                  llcp_link_deactivate (LLCP_LINK_REMOTE_INITIATED);
    @@ -94,6 +167,249 @@ index d70349c..9249539 100644
              else if (ptype == LLCP_PDU_SYMM_TYPE)
              {
                  LLCP_TRACE_ERROR0 ("llcp_link_proc_agf_pdu (): SYMM PDU exchange shall not be in AGF");
    +diff --git a/src/nfc/llcp/llcp_util.c b/src/nfc/llcp/llcp_util.c
    +index 2f4420c..db2c25e 100644
    +--- a/src/nfc/llcp/llcp_util.c
    ++++ b/src/nfc/llcp/llcp_util.c
    +@@ -26,6 +26,7 @@
    + #include <string.h>
    + #include "gki.h"
    + #include "nfc_target.h"
    ++#include <log/log.h>
    + #include "bt_types.h"
    + #include "trace_api.h"
    + #include "llcp_int.h"
    +@@ -45,21 +46,34 @@ BOOLEAN llcp_util_parse_link_params (UINT16 length, UINT8 *p_bytes)
    + {
    +     UINT8 param_type, param_len, *p = p_bytes;
    + 
    +-    while (length)
    ++    while (length >= 2)
    +     {
    +-        BE_STREAM_TO_UINT8 (param_type, p);
    +-        length--;
    +-
    ++        BE_STREAM_TO_UINT8(param_type, p);
    ++        BE_STREAM_TO_UINT8(param_len, p);
    ++        if (length < param_len + 2) {
    ++            android_errorWriteLog(0x534e4554, "114238578");
    ++            LOG(ERROR) << StringPrintf("Bad TLV's");
    ++            return false;
    ++        }
    ++        length -= param_len + 2;
    +         switch (param_type)
    +         {
    +         case LLCP_VERSION_TYPE:
    +-            BE_STREAM_TO_UINT8 (param_len, p);
    ++            if (param_len != LLCP_VERSION_LEN) {
    ++                android_errorWriteLog(0x534e4554, "114238578");
    ++                LOG(ERROR) << StringPrintf("Bad TLV's");
    ++                return false;
    ++            }
    +             BE_STREAM_TO_UINT8 (llcp_cb.lcb.peer_version, p);
    +             LLCP_TRACE_DEBUG1 ("Peer Version - 0x%02X", llcp_cb.lcb.peer_version);
    +             break;
    + 
    +         case LLCP_MIUX_TYPE:
    +-            BE_STREAM_TO_UINT8 (param_len, p);
    ++            if (param_len != LLCP_MIUX_LEN) {
    ++                android_errorWriteLog(0x534e4554, "114238578");
    ++                LOG(ERROR) << StringPrintf("Bad TLV's");
    ++                return false;
    ++            }
    +             BE_STREAM_TO_UINT16 (llcp_cb.lcb.peer_miu, p);
    +             llcp_cb.lcb.peer_miu &= LLCP_MIUX_MASK;
    +             llcp_cb.lcb.peer_miu += LLCP_DEFAULT_MIU;
    +@@ -67,38 +81,41 @@ BOOLEAN llcp_util_parse_link_params (UINT16 length, UINT8 *p_bytes)
    +             break;
    + 
    +         case LLCP_WKS_TYPE:
    +-            BE_STREAM_TO_UINT8 (param_len, p);
    ++            if (param_len != LLCP_WKS_LEN) {
    ++                android_errorWriteLog(0x534e4554, "114238578");
    ++                LOG(ERROR) << StringPrintf("Bad TLV's");
    ++                return false;
    ++            }
    +             BE_STREAM_TO_UINT16 (llcp_cb.lcb.peer_wks, p);
    +             LLCP_TRACE_DEBUG1 ("Peer WKS - 0x%04X", llcp_cb.lcb.peer_wks);
    +             break;
    + 
    +         case LLCP_LTO_TYPE:
    +-            BE_STREAM_TO_UINT8 (param_len, p);
    ++            if (param_len != LLCP_LTO_LEN) {
    ++                android_errorWriteLog(0x534e4554, "114238578");
    ++                LOG(ERROR) << StringPrintf("Bad TLV's");
    ++                return false;
    ++            }
    +             BE_STREAM_TO_UINT8 (llcp_cb.lcb.peer_lto, p);
    +             llcp_cb.lcb.peer_lto *= LLCP_LTO_UNIT;  /* 10ms unit */
    +             LLCP_TRACE_DEBUG1 ("Peer LTO - %d ms", llcp_cb.lcb.peer_lto);
    +             break;
    + 
    +         case LLCP_OPT_TYPE:
    +-            BE_STREAM_TO_UINT8 (param_len, p);
    ++            if (param_len != LLCP_OPT_LEN) {
    ++                android_errorWriteLog(0x534e4554, "114238578");
    ++                LOG(ERROR) << StringPrintf("Bad TLV's");
    ++                return false;
    ++            }
    +             BE_STREAM_TO_UINT8 (llcp_cb.lcb.peer_opt, p);
    +             LLCP_TRACE_DEBUG1 ("Peer OPT - 0x%02X", llcp_cb.lcb.peer_opt);
    +             break;
    + 
    +         default:
    +             LLCP_TRACE_ERROR1 ("llcp_util_parse_link_params (): Unexpected type 0x%x", param_type);
    +-            BE_STREAM_TO_UINT8 (param_len, p);
    +             p += param_len;
    +             break;
    +         }
    +-
    +-        if (length >= param_len + 1)
    +-            length -= param_len + 1;
    +-        else
    +-        {
    +-            LLCP_TRACE_ERROR0 ("llcp_util_parse_link_params (): Bad LTV's");
    +-            return (FALSE);
    +-        }
    +     }
    +     return (TRUE);
    + }
    +@@ -498,15 +515,26 @@ tLLCP_STATUS llcp_util_parse_connect (UINT8  *p_bytes, UINT16 length, tLLCP_CONN
    +     p_params->sn[0] = 0;
    +     p_params->sn[1] = 0;
    + 
    +-    while (length)
    ++    while (length >= 2)
    +     {
    +-        BE_STREAM_TO_UINT8 (param_type, p);
    +-        length--;
    ++        BE_STREAM_TO_UINT8(param_type, p);
    ++        BE_STREAM_TO_UINT8(param_len, p);
    ++        /* check remaining lengh */
    ++        if (length < param_len + 2) {
    ++            android_errorWriteLog(0x534e4554, "111660010");
    ++            LOG(ERROR) << StringPrintf("Bad TLV's");
    ++            return LLCP_STATUS_FAIL;
    ++        }
    ++        length -= param_len + 2;
    + 
    +         switch (param_type)
    +         {
    +         case LLCP_MIUX_TYPE:
    +-            BE_STREAM_TO_UINT8 (param_len, p);
    ++            if (param_len != LLCP_MIUX_LEN) {
    ++                android_errorWriteLog(0x534e4554, "111660010");
    ++                LOG(ERROR) << StringPrintf("Bad TLV's");
    ++                return LLCP_STATUS_FAIL;
    ++            }
    +             BE_STREAM_TO_UINT16 (p_params->miu, p);
    +             p_params->miu &= LLCP_MIUX_MASK;
    +             p_params->miu += LLCP_DEFAULT_MIU;
    +@@ -515,7 +543,11 @@ tLLCP_STATUS llcp_util_parse_connect (UINT8  *p_bytes, UINT16 length, tLLCP_CONN
    +             break;
    + 
    +         case LLCP_RW_TYPE:
    +-            BE_STREAM_TO_UINT8 (param_len, p);
    ++            if (param_len != LLCP_RW_LEN) {
    ++                android_errorWriteLog(0x534e4554, "111660010");
    ++                LOG(ERROR) << StringPrintf("Bad TLV's");
    ++                return LLCP_STATUS_FAIL;
    ++            }
    +             BE_STREAM_TO_UINT8 (p_params->rw, p);
    +             p_params->rw &= 0x0F;
    + 
    +@@ -523,8 +555,6 @@ tLLCP_STATUS llcp_util_parse_connect (UINT8  *p_bytes, UINT16 length, tLLCP_CONN
    +             break;
    + 
    +         case LLCP_SN_TYPE:
    +-            BE_STREAM_TO_UINT8 (param_len, p);
    +-
    +             if (param_len == 0)
    +             {
    +                 /* indicate that SN type is included without SN */
    +@@ -547,21 +577,9 @@ tLLCP_STATUS llcp_util_parse_connect (UINT8  *p_bytes, UINT16 length, tLLCP_CONN
    + 
    +         default:
    +             LLCP_TRACE_ERROR1 ("llcp_util_parse_connect (): Unexpected type 0x%x", param_type);
    +-            BE_STREAM_TO_UINT8 (param_len, p);
    +             p += param_len;
    +             break;
    +         }
    +-
    +-        /* check remaining lengh */
    +-        if (length >= param_len + 1)
    +-        {
    +-            length -= param_len + 1;
    +-        }
    +-        else
    +-        {
    +-            LLCP_TRACE_ERROR0 ("llcp_util_parse_connect (): Bad LTV's");
    +-            return LLCP_STATUS_FAIL;
    +-        }
    +     }
    +     return LLCP_STATUS_SUCCESS;
    + }
    +@@ -641,15 +659,25 @@ tLLCP_STATUS llcp_util_parse_cc (UINT8 *p_bytes, UINT16 length, UINT16 *p_miu, U
    +     *p_miu = LLCP_DEFAULT_MIU;
    +     *p_rw  = LLCP_DEFAULT_RW;
    + 
    +-    while (length)
    ++    while (length >= 2)
    +     {
    +         BE_STREAM_TO_UINT8 (param_type, p);
    +-        length--;
    ++        BE_STREAM_TO_UINT8(param_len, p);
    ++        if (length < param_len + 2) {
    ++            android_errorWriteLog(0x534e4554, "114237888");
    ++            LOG(ERROR) << StringPrintf("Bad TLV's");
    ++            return LLCP_STATUS_FAIL;
    ++        }
    ++        length -= param_len + 2;
    + 
    +         switch (param_type)
    +         {
    +         case LLCP_MIUX_TYPE:
    +-            BE_STREAM_TO_UINT8 (param_len, p);
    ++            if (param_len != LLCP_MIUX_LEN) {
    ++                android_errorWriteLog(0x534e4554, "114237888");
    ++                LOG(ERROR) << StringPrintf("Bad TLV's");
    ++                return LLCP_STATUS_FAIL;
    ++            }
    +             BE_STREAM_TO_UINT16 ((*p_miu), p);
    +             (*p_miu) &= LLCP_MIUX_MASK;
    +             (*p_miu) += LLCP_DEFAULT_MIU;
    +@@ -658,7 +686,11 @@ tLLCP_STATUS llcp_util_parse_cc (UINT8 *p_bytes, UINT16 length, UINT16 *p_miu, U
    +             break;
    + 
    +         case LLCP_RW_TYPE:
    +-            BE_STREAM_TO_UINT8 (param_len, p);
    ++            if (param_len != LLCP_RW_LEN) {
    ++               android_errorWriteLog(0x534e4554, "114237888");
    ++               LOG(ERROR) << StringPrintf("Bad TLV's");
    ++               return LLCP_STATUS_FAIL;
    ++            }
    +             BE_STREAM_TO_UINT8 ((*p_rw), p);
    +             (*p_rw) &= 0x0F;
    + 
    +@@ -667,18 +699,9 @@ tLLCP_STATUS llcp_util_parse_cc (UINT8 *p_bytes, UINT16 length, UINT16 *p_miu, U
    + 
    +         default:
    +             LLCP_TRACE_ERROR1 ("llcp_util_parse_cc (): Unexpected type 0x%x", param_type);
    +-            BE_STREAM_TO_UINT8 (param_len, p);
    +             p += param_len;
    +             break;
    +         }
    +-
    +-        if (length >= param_len + 1)
    +-            length -= param_len + 1;
    +-        else
    +-        {
    +-            LLCP_TRACE_ERROR0 ("llcp_util_parse_cc (): Bad LTV's");
    +-            return LLCP_STATUS_FAIL;
    +-        }
    +     }
    +     return LLCP_STATUS_SUCCESS;
    + }
     diff --git a/src/nfc/nfc/nfc_ncif.c b/src/nfc/nfc/nfc_ncif.c
     index 2e2c14f..739bae2 100644
     --- a/src/nfc/nfc/nfc_ncif.c
    @@ -159,8 +475,96 @@ index 2e2c14f..739bae2 100644
                      pn                 += tl;
                  }
                  (*nfc_cb.p_resp_cback) (NFC_GET_ROUTING_REVT, (tNFC_RESPONSE *) &evt_data);
    +diff --git a/src/nfc/tags/ce_t4t.c b/src/nfc/tags/ce_t4t.c
    +index b812cff..84e55db 100644
    +--- a/src/nfc/tags/ce_t4t.c
    ++++ b/src/nfc/tags/ce_t4t.c
    +@@ -23,6 +23,7 @@
    +  *  mode.
    +  *
    +  ******************************************************************************/
    ++#include <log/log.h>
    + #include <string.h>
    + #include "nfc_target.h"
    + #include "bt_types.h"
    +@@ -431,6 +432,14 @@ static void ce_t4t_process_select_app_cmd (UINT8 *p_cmd, BT_HDR *p_c_apdu)
    +     /* Lc Byte */
    +     BE_STREAM_TO_UINT8 (data_len, p_cmd);
    + 
    ++    /*CLS+INS+P1+P2+Lc+Data*/
    ++    if (data_len > (p_c_apdu->len - T4T_CMD_MAX_HDR_SIZE)) {
    ++        LOG(ERROR) << StringPrintf("Wrong length in ce_t4t_process_select_app_cmd");
    ++        android_errorWriteLog(0x534e4554, "115635871");
    ++        ce_t4t_send_status(T4T_RSP_WRONG_LENGTH);
    ++        GKI_freebuf(p_c_apdu);
    ++        return;
    ++    }
    + #if (CE_TEST_INCLUDED == TRUE)
    +     if (mapping_aid_test_enabled)
    +     {
    +@@ -600,6 +609,7 @@ static void ce_t4t_data_cback (UINT8 conn_id, tNFC_CONN_EVT event, tNFC_CONN *p_
    +     BT_HDR  *p_c_apdu;
    +     UINT8   *p_cmd;
    +     UINT8    cla, instruct, select_type = 0, length;
    ++    UINT8    cla = 0, instruct = 0, select_type = 0, length = 0;
    +     UINT16   offset, max_file_size;
    +     tCE_DATA ce_data;
    + 
    +@@ -622,6 +632,13 @@ static void ce_t4t_data_cback (UINT8 conn_id, tNFC_CONN_EVT event, tNFC_CONN *p_
    +     CE_TRACE_DEBUG1 ("ce_t4t_data_cback (): conn_id = 0x%02X", conn_id);
    + 
    +     p_cmd = (UINT8 *) (p_c_apdu + 1) + p_c_apdu->offset;
    ++    if (p_c_apdu->len == 0) {
    ++        LOG(ERROR) << StringPrintf("Wrong length in ce_t4t_data_cback");
    ++        android_errorWriteLog(0x534e4554, "115635871");
    ++        ce_t4t_send_status(T4T_RSP_WRONG_LENGTH);
    ++        if (p_c_apdu) GKI_freebuf(p_c_apdu);
    ++            return;
    ++    }
    + 
    +     /* Class Byte */
    +     BE_STREAM_TO_UINT8 (cla, p_cmd);
    +@@ -636,18 +653,26 @@ static void ce_t4t_data_cback (UINT8 conn_id, tNFC_CONN_EVT event, tNFC_CONN *p_
    +         return;
    +     }
    + 
    +-    /* Instruction Byte */
    +-    BE_STREAM_TO_UINT8 (instruct, p_cmd);
    +-
    +-    if ((cla == T4T_CMD_CLASS) && (instruct == T4T_CMD_INS_SELECT))
    +-    {
    +-        /* P1 Byte */
    +-        BE_STREAM_TO_UINT8 (select_type, p_cmd);
    +-
    +-        if (select_type == T4T_CMD_P1_SELECT_BY_NAME)
    +-        {
    +-            ce_t4t_process_select_app_cmd (p_cmd, p_c_apdu);
    +-            return;
    ++    /*CLA+INS+P1+P2 = 4 bytes*/
    ++    if (p_c_apdu->len >= T4T_CMD_MIN_HDR_SIZE) {
    ++        /* Instruction Byte */
    ++        BE_STREAM_TO_UINT8(instruct, p_cmd);
    ++        if ((cla == T4T_CMD_CLASS) && (instruct == T4T_CMD_INS_SELECT)) {
    ++            /* P1 Byte */
    ++            BE_STREAM_TO_UINT8(select_type, p_cmd);
    ++            if (select_type == T4T_CMD_P1_SELECT_BY_NAME) {
    ++                /*CLA+INS+P1+P2+Lc = 5 bytes*/
    ++                if (p_c_apdu->len >= T4T_CMD_MAX_HDR_SIZE) {
    ++                    ce_t4t_process_select_app_cmd(p_cmd, p_c_apdu);
    ++                    return;
    ++                } else {
    ++                    LOG(ERROR) << StringPrintf("Wrong length in select app cmd");
    ++                    android_errorWriteLog(0x534e4554, "115635871");
    ++                    ce_t4t_send_status(T4T_RSP_NOT_FOUND);
    ++                    if (p_c_apdu) GKI_freebuf(p_c_apdu);
    ++                        return;
    ++                }
    ++            }
    +         }
    +     }
    + 
     diff --git a/src/nfc/tags/rw_t2t_ndef.c b/src/nfc/tags/rw_t2t_ndef.c
    -index 3304a90..42a558e 100644
    +index 3304a90..37dd8e4 100644
     --- a/src/nfc/tags/rw_t2t_ndef.c
     +++ b/src/nfc/tags/rw_t2t_ndef.c
     @@ -23,6 +23,7 @@
    @@ -171,7 +575,21 @@ index 3304a90..42a558e 100644
      #include <string.h>
      #include "nfc_target.h"
      
    -@@ -664,6 +665,10 @@ static void rw_t2t_handle_tlv_detect_rsp (UINT8 *p_data)
    +@@ -646,7 +647,12 @@ static void rw_t2t_handle_tlv_detect_rsp (UINT8 *p_data)
    +                 break;
    + 
    +             case TAG_LOCK_CTRL_TLV:
    +-                p_t2t->bytes_count--;
    ++                if (p_t2t->bytes_count > 0) {
    ++                    p_t2t->bytes_count--;
    ++                } else {
    ++                    LOG(ERROR) << StringPrintf("Underflow p_t2t->bytes_count!");
    ++                    android_errorWriteLog(0x534e4554, "120506143");
    ++                }
    +                 if (  (tlvtype == TAG_LOCK_CTRL_TLV)
    +                     ||(tlvtype == TAG_NDEF_TLV)  )
    +                 {
    +@@ -664,6 +670,10 @@ static void rw_t2t_handle_tlv_detect_rsp (UINT8 *p_data)
      
                              /* Extract lockbytes info addressed by this Lock TLV */
                              xx = 0;
    @@ -182,3 +600,118 @@ index 3304a90..42a558e 100644
                              while (xx < count)
                              {
                                  p_t2t->lockbyte[p_t2t->num_lockbytes].tlv_index     = p_t2t->num_lock_tlvs;
    +@@ -689,7 +699,12 @@ static void rw_t2t_handle_tlv_detect_rsp (UINT8 *p_data)
    +                 break;
    + 
    +             case TAG_MEM_CTRL_TLV:
    +-                p_t2t->bytes_count--;
    ++                if (p_t2t->bytes_count > 0) {
    ++                    p_t2t->bytes_count--;
    ++                } else {
    ++                    LOG(ERROR) << StringPrintf("bytes_count underflow!");
    ++                    android_errorWriteLog(0x534e4554, "120506143");
    ++                }
    +                 if (  (tlvtype == TAG_MEM_CTRL_TLV)
    +                     ||(tlvtype == TAG_NDEF_TLV)  )
    +                 {
    +@@ -724,7 +739,12 @@ static void rw_t2t_handle_tlv_detect_rsp (UINT8 *p_data)
    +                 break;
    + 
    +             case TAG_PROPRIETARY_TLV:
    +-                p_t2t->bytes_count--;
    ++                if (p_t2t->bytes_count > 0) {
    ++                    p_t2t->bytes_count--;
    ++                } else {
    ++                    LOG(ERROR) << StringPrintf("bytes_count underflow!");
    ++                    android_errorWriteLog(0x534e4554, "120506143");
    ++                }
    +                 if (tlvtype == TAG_PROPRIETARY_TLV)
    +                 {
    +                     found = TRUE;
    +diff --git a/src/nfc/tags/rw_t3t.c b/src/nfc/tags/rw_t3t.c
    +index f8ec361..70cb2e3 100644
    +--- a/src/nfc/tags/rw_t3t.c
    ++++ b/src/nfc/tags/rw_t3t.c
    +@@ -1285,6 +1285,10 @@ void rw_t3t_act_handle_ndef_detect_rsp (tRW_T3T_CB *p_cb, BT_HDR *p_msg_rsp)
    +              ||(memcmp (p_cb->peer_nfcid2, &p_t3t_rsp[T3T_MSG_RSP_OFFSET_IDM], NCI_NFCID2_LEN) != 0)  )   /* verify response IDm */
    +     {
    +         evt_data.status = NFC_STATUS_FAILED;
    ++    } else if (p_msg_rsp->len <
    ++               (T3T_MSG_RSP_OFFSET_CHECK_DATA + T3T_MSG_BLOCKSIZE)) {
    ++        evt_data.status = NFC_STATUS_FAILED;
    ++        android_errorWriteLog(0x534e4554, "120428041");
    +     }
    +     else
    +     {
    +@@ -1399,7 +1403,7 @@ void rw_t3t_act_handle_check_rsp (tRW_T3T_CB *p_cb, BT_HDR *p_msg_rsp)
    +         nfc_status = NFC_STATUS_FAILED;
    +         GKI_freebuf (p_msg_rsp);
    +     }
    +-    else
    ++    else if (p_msg_rsp->len >= T3T_MSG_RSP_OFFSET_CHECK_DATA) {
    +     {
    +         /* Copy incoming data into buffer */
    +         p_msg_rsp->offset += T3T_MSG_RSP_OFFSET_CHECK_DATA;     /* Skip over t3t header */
    +@@ -1407,6 +1411,10 @@ void rw_t3t_act_handle_check_rsp (tRW_T3T_CB *p_cb, BT_HDR *p_msg_rsp)
    +         evt_data.status = NFC_STATUS_OK;
    +         evt_data.p_data = p_msg_rsp;
    +         (*(rw_cb.p_cback)) (RW_T3T_CHECK_EVT, (tRW_DATA *) &evt_data);
    ++    } else {
    ++        android_errorWriteLog(0x534e4554, "120503926");
    ++        nfc_status = NFC_STATUS_FAILED;
    ++        GKI_freebuf(p_msg_rsp);
    +     }
    + 
    + 
    +@@ -1667,8 +1675,12 @@ static void rw_t3t_handle_get_sc_poll_rsp (tRW_T3T_CB *p_cb, UINT8 nci_status, U
    +             {
    +                 RW_TRACE_DEBUG1 ("FeliCa Lite tag detected (system code %04X)", sc);
    +                 /* Store system code */
    +-                p_cb->system_codes[p_cb->num_system_codes++] = sc;
    +-
    ++                if (p_cb->num_system_codes < T3T_MAX_SYSTEM_CODES) {
    ++                    p_cb->system_codes[p_cb->num_system_codes++] = sc;
    ++                } else {
    ++                    LOG(ERROR) << StringPrintf("Exceed T3T_MAX_SYSTEM_CODES!");
    ++                    android_errorWriteLog(0x534e4554, "120499324");
    ++                }
    +                 /* Poll for NDEF system code */
    +                 if ((status = (tNFC_STATUS) nci_snd_t3t_polling (T3T_SYSTEM_CODE_NDEF, 0, 0)) == NCI_STATUS_OK)
    +                 {
    +@@ -1956,6 +1968,10 @@ void rw_t3t_act_handle_fmt_rsp (tRW_T3T_CB *p_cb, BT_HDR *p_msg_rsp)
    +                  ||(memcmp (p_cb->peer_nfcid2, &p_t3t_rsp[T3T_MSG_RSP_OFFSET_IDM], NCI_NFCID2_LEN) != 0)  )   /* verify response IDm */
    +         {
    +             evt_data.status = NFC_STATUS_FAILED;
    ++	} else if (p_msg_rsp->len <
    ++                   (T3T_MSG_RSP_OFFSET_CHECK_DATA + T3T_MSG_BLOCKSIZE)) {
    ++            evt_data.status = NFC_STATUS_FAILED;
    ++            android_errorWriteLog(0x534e4554, "120506143");
    +         }
    +         else
    +         {
    +@@ -2168,19 +2184,17 @@ void rw_t3t_act_handle_sro_rsp (tRW_T3T_CB *p_cb, BT_HDR *p_msg_rsp)
    +                  ||(memcmp (p_cb->peer_nfcid2, &p_t3t_rsp[T3T_MSG_RSP_OFFSET_IDM], NCI_NFCID2_LEN) != 0)  )   /* verify response IDm */
    +         {
    +             evt_data.status = NFC_STATUS_FAILED;
    ++	} else if (p_msg_rsp->len <
    ++                   (T3T_MSG_RSP_OFFSET_CHECK_DATA + T3T_MSG_BLOCKSIZE)) {
    ++            evt_data.status = NFC_STATUS_FAILED;
    ++            android_errorWriteLog(0x534e4554, "120506143");
    +         }
    +         else
    +         {
    +             /* Check if memory configuration (MC) block to see if SYS_OP=1 (NDEF enabled) */
    +             p_mc = &p_t3t_rsp[T3T_MSG_RSP_OFFSET_CHECK_DATA];  /* Point to MC data of CHECK response */
    +-
    +-            if (p_mc[T3T_MSG_FELICALITE_MC_OFFSET_SYS_OP] != 0x01)
    +-            {
    +-                /* Tag is not currently enabled for NDEF */
    +-                evt_data.status = NFC_STATUS_FAILED;
    +-            }
    +-            else
    +-            {
    ++            evt_data.status = NFC_STATUS_FAILED;
    ++            if (p_mc[T3T_MSG_FELICALITE_MC_OFFSET_SYS_OP] == 0x01) {
    +                 /* Set MC_SP field with MC[0] = 0x00 & MC[1] = 0xC0 (Hardlock) to change access permission from RW to RO */
    +                 p_mc[T3T_MSG_FELICALITE_MC_OFFSET_MC_SP]     = 0x00;
    +                 /* Not changing the access permission of Subtraction Register and MC[0:1] */
    diff --git a/external_skia.patch b/external_skia.patch
    index 5d3bb9a..0c20b90 100644
    --- a/external_skia.patch
    +++ b/external_skia.patch
    @@ -168,6 +168,234 @@ index 4502416fd9..265fb641c7 100644
      
          typedef SkStreamAsset INHERITED;
      };
    +diff --git a/include/core/SkTypes.h b/include/core/SkTypes.h
    +index 756eae8628..5c721fc6b3 100644
    +--- a/include/core/SkTypes.h
    ++++ b/include/core/SkTypes.h
    +@@ -69,26 +69,45 @@ SK_API extern void sk_out_of_memory(void);
    + */
    + SK_API extern void sk_abort_no_print(void);
    + 
    ++/** Free memory returned by sk_malloc(). It is safe to pass null. */
    ++SK_API extern void sk_free(void*);
    ++
    + enum {
    +-    SK_MALLOC_TEMP  = 0x01, //!< hint to sk_malloc that the requested memory will be freed in the scope of the stack frame
    +-    SK_MALLOC_THROW = 0x02  //!< instructs sk_malloc to call sk_throw if the memory cannot be allocated.
    ++#ifdef SK_SUPPORT_LEGACY_MALLOC_PORTING_LAYER
    ++    SK_MALLOC_TEMP = 1,
    ++#else
    ++    /**
    ++     *  If this bit is set, the returned buffer must be zero-initialized. If this bit is not set
    ++     *  the buffer can be uninitialized.
    ++     */
    ++    SK_MALLOC_ZERO_INITIALIZE   = 1 << 0,
    ++#endif
    ++
    ++    /**
    ++     *  If this bit is set, the implementation must throw/crash/quit if the request cannot
    ++     *  be fulfilled. If this bit is not set, then it should return nullptr on failure.
    ++     */
    ++    SK_MALLOC_THROW             = 1 << 1,
    + };
    +-/** Return a block of memory (at least 4-byte aligned) of at least the
    +-    specified size. If the requested memory cannot be returned, either
    +-    return null (if SK_MALLOC_TEMP bit is clear) or throw an exception
    +-    (if SK_MALLOC_TEMP bit is set). To free the memory, call sk_free().
    +-*/
    ++/**
    ++ *  Return a block of memory (at least 4-byte aligned) of at least the specified size.
    ++ *  If the requested memory cannot be returned, either return nullptr or throw/exit, depending
    ++ *  on the SK_MALLOC_THROW bit. If the allocation succeeds, the memory will be zero-initialized
    ++ *  if the SK_MALLOC_ZERO_INITIALIZE bit was set.
    ++ *
    ++ *  To free the memory, call sk_free()
    ++ */
    + SK_API extern void* sk_malloc_flags(size_t size, unsigned flags);
    +-/** Same as sk_malloc(), but hard coded to pass SK_MALLOC_THROW as the flag
    +-*/
    +-SK_API extern void* sk_malloc_throw(size_t size);
    ++
    + /** Same as standard realloc(), but this one never returns null on failure. It will throw
    +-    an exception if it fails.
    +-*/
    ++ *  an exception if it fails.
    ++ */
    + SK_API extern void* sk_realloc_throw(void* buffer, size_t size);
    +-/** Free memory returned by sk_malloc(). It is safe to pass null.
    +-*/
    +-SK_API extern void sk_free(void*);
    ++
    ++#ifdef SK_SUPPORT_LEGACY_MALLOC_PORTING_LAYER
    ++
    ++/** Same as sk_malloc_flags(), but hard coded to pass SK_MALLOC_THROW as the flag */
    ++SK_API extern void* sk_malloc_throw(size_t size);
    + 
    + /** Much like calloc: returns a pointer to at least size zero bytes, or NULL on failure.
    +  */
    +@@ -98,6 +117,37 @@ SK_API extern void* sk_calloc(size_t size);
    +  */
    + SK_API extern void* sk_calloc_throw(size_t size);
    + 
    ++#else
    ++static inline void* sk_malloc_throw(size_t size) {
    ++    return sk_malloc_flags(size, SK_MALLOC_THROW);
    ++}
    ++
    ++static inline void* sk_calloc_throw(size_t size) {
    ++    return sk_malloc_flags(size, SK_MALLOC_THROW | SK_MALLOC_ZERO_INITIALIZE);
    ++}
    ++#endif
    ++
    ++static inline void* sk_calloc_canfail(size_t size) {
    ++#ifdef SK_SUPPORT_LEGACY_MALLOC_PORTING_LAYER
    ++    return sk_calloc(size);
    ++#else
    ++    return sk_malloc_flags(size, SK_MALLOC_ZERO_INITIALIZE);
    ++#endif
    ++}
    ++
    ++// Performs a safe multiply count * elemSize, checking for overflow
    ++SK_API extern void* sk_calloc_throw(size_t count, size_t elemSize);
    ++SK_API extern void* sk_malloc_throw(size_t count, size_t elemSize);
    ++SK_API extern void* sk_realloc_throw(void* buffer, size_t count, size_t elemSize);
    ++
    ++/**
    ++ *  These variants return nullptr on failure
    ++ */
    ++static inline void* sk_malloc_canfail(size_t size) {
    ++    return sk_malloc_flags(size, 0);
    ++}
    ++SK_API extern void* sk_malloc_canfail(size_t count, size_t elemSize);
    ++
    + // bzero is safer than memset, but we can't rely on it, so... sk_bzero()
    + static inline void sk_bzero(void* buffer, size_t size) {
    +     // Please c.f. sk_careful_memcpy.  It's undefined behavior to call memset(null, 0, 0).
    +@@ -291,6 +341,7 @@ typedef uint8_t SkBool8;
    + #define SK_MaxU32   0xFFFFFFFF
    + #define SK_MinU32   0
    + #define SK_NaN32    (1 << 31)
    ++#define SK_MaxSizeT SIZE_MAX
    + 
    + /** Returns true if the value can be represented with signed 16bits
    +  */
    +@@ -682,7 +733,11 @@ public:
    +                 SkASSERT(fPtr != fStorage); // otherwise we lied when setting didChangeAlloc.
    +                 fPtr = fStorage;
    +             } else {
    ++              #ifdef SK_SUPPORT_LEGACY_MALLOC_PORTING_LAYER
    +                 fPtr = sk_malloc_flags(size, SK_MALLOC_THROW | SK_MALLOC_TEMP);
    ++              #else
    ++                fPtr = sk_malloc_flags(size, SK_MALLOC_THROW | SK_MALLOC_ZERO_INITIALIZE);
    ++              #endif
    +             }
    + 
    +             fSize = size;
    +diff --git a/include/private/SkTArray.h b/include/private/SkTArray.h
    +index 5330e49307..77bba3f3db 100644
    +--- a/include/private/SkTArray.h
    ++++ b/include/private/SkTArray.h
    +@@ -380,7 +380,7 @@ protected:
    +             fMemArray = preAllocStorage;
    +         } else {
    +             fAllocCount = SkMax32(fCount, fReserveCount);
    +-            fMemArray = sk_malloc_throw(fAllocCount * sizeof(T));
    ++            fMemArray = sk_malloc_throw(fAllocCount, sizeof(T));
    +         }
    + 
    +         this->copy(array);
    +@@ -449,7 +449,7 @@ private:
    +             if (fAllocCount == fReserveCount && fPreAllocMemArray) {
    +                 newMemArray = (char*) fPreAllocMemArray;
    +             } else {
    +-                newMemArray = (char*) sk_malloc_throw(fAllocCount*sizeof(T));
    ++                newMemArray = (char*) sk_malloc_throw(fAllocCount, sizeof(T));
    +             }
    + 
    +             this->move(newMemArray);
    +diff --git a/include/private/SkTemplates.h b/include/private/SkTemplates.h
    +index e36910e814..495ae75850 100644
    +--- a/include/private/SkTemplates.h
    ++++ b/include/private/SkTemplates.h
    +@@ -202,12 +202,7 @@ public:
    +             }
    + 
    +             if (count > kCount) {
    +-                const uint64_t size64 = sk_64_mul(count, sizeof(T));
    +-                const size_t size = static_cast<size_t>(size64);
    +-                if (size != size64) {
    +-                    sk_out_of_memory();
    +-                }
    +-                fArray = (T*) sk_malloc_throw(size);
    ++                fArray = (T*) sk_malloc_throw(count, sizeof(T));
    +             } else if (count > 0) {
    +                 fArray = (T*) fStorage;
    +             } else {
    +@@ -269,7 +264,7 @@ public:
    + 
    +     /** Allocates space for 'count' Ts. */
    +     explicit SkAutoTMalloc(size_t count) {
    +-        fPtr = (T*)sk_malloc_flags(count * sizeof(T), SK_MALLOC_THROW);
    ++        fPtr = (T*)sk_malloc_throw(count, sizeof(T));
    +     }
    + 
    +     ~SkAutoTMalloc() {
    +@@ -284,7 +279,7 @@ public:
    +     /** Resize the memory area pointed to by the current ptr without preserving contents. */
    +     T* reset(size_t count) {
    +         sk_free(fPtr);
    +-        fPtr = (T*)sk_malloc_flags(count * sizeof(T), SK_MALLOC_THROW);
    ++        fPtr = (T*)sk_malloc_throw(count, sizeof(T));
    +         return fPtr;
    +     }
    + 
    +@@ -334,7 +329,7 @@ public:
    + 
    +     SkAutoSTMalloc(size_t count) {
    +         if (count > kCount) {
    +-            fPtr = (T*)sk_malloc_flags(count * sizeof(T), SK_MALLOC_THROW | SK_MALLOC_TEMP);
    ++            fPtr = (T*)sk_malloc_throw(count, sizeof(T));
    +         } else {
    +             fPtr = fTStorage;
    +         }
    +@@ -352,7 +347,7 @@ public:
    +             sk_free(fPtr);
    +         }
    +         if (count > kCount) {
    +-            fPtr = (T*)sk_malloc_throw(count * sizeof(T));
    ++            fPtr = (T*)sk_malloc_throw(count, sizeof(T));
    +         } else {
    +             fPtr = fTStorage;
    +         }
    +@@ -381,13 +376,13 @@ public:
    +     void realloc(size_t count) {
    +         if (count > kCount) {
    +             if (fPtr == fTStorage) {
    +-                fPtr = (T*)sk_malloc_throw(count * sizeof(T));
    ++                fPtr = (T*)sk_malloc_throw(count, sizeof(T));
    +                 memcpy(fPtr, fTStorage, kCount * sizeof(T));
    +             } else {
    +-                fPtr = (T*)sk_realloc_throw(fPtr, count * sizeof(T));
    ++                fPtr = (T*)sk_realloc_throw(fPtr, count, sizeof(T));
    +             }
    +         } else if (fPtr != fTStorage) {
    +-            fPtr = (T*)sk_realloc_throw(fPtr, count * sizeof(T));
    ++            fPtr = (T*)sk_realloc_throw(fPtr, count, sizeof(T));
    +         }
    +     }
    + 
    +diff --git a/public.bzl b/public.bzl
    +index 986bfd9342..9caa4896c1 100644
    +--- a/public.bzl
    ++++ b/public.bzl
    +@@ -521,6 +521,7 @@ DEFINES_ALL = [
    +     "SK_USE_FREETYPE_EMBOLDEN",
    +     # Turn on a few Google3-specific build fixes.
    +     "GOOGLE3",
    ++    "SK_SUPPORT_LEGACY_MALLOC_PORTING_LAYER",
    + ]
    + 
    + ################################################################################
     diff --git a/resources/invalid_images/b38116746.ico b/resources/invalid_images/b38116746.ico
     new file mode 100644
     index 0000000000..35ee5b5a28
    @@ -198,7 +426,7 @@ index 0000000000..968b7b7d08
     +#endif // SK_BUILD_FOR_ANDROID_FRAMEWORK
     +
     diff --git a/src/codec/SkIcoCodec.cpp b/src/codec/SkIcoCodec.cpp
    -index dc4222a43c..8b3d26dd86 100644
    +index dc4222a43c..6c3625886e 100644
     --- a/src/codec/SkIcoCodec.cpp
     +++ b/src/codec/SkIcoCodec.cpp
     @@ -14,6 +14,7 @@
    @@ -216,7 +444,7 @@ index dc4222a43c..8b3d26dd86 100644
     -        SkAutoTUnref<SkData> data(
     -                SkData::NewFromStream(inputStream.get(), size));
     -        if (nullptr == data.get()) {
    -+        SkAutoFree buffer(sk_malloc_flags(size, 0));
    ++        SkAutoFree buffer(sk_malloc_canfail(size));
     +        if (!buffer.get()) {
     +            SkCodecPrintf("Warning: OOM trying to create embedded stream.\n");
     +            break;
    @@ -293,6 +521,86 @@ index 6cfb385294..8acd205d13 100644
                  return kIncompleteInput;
              }
      
    +diff --git a/src/core/SkMallocPixelRef.cpp b/src/core/SkMallocPixelRef.cpp
    +index fffc044848..384f8a61bd 100644
    +--- a/src/core/SkMallocPixelRef.cpp
    ++++ b/src/core/SkMallocPixelRef.cpp
    +@@ -8,8 +8,27 @@
    + #include "SkMallocPixelRef.h"
    + #include "SkBitmap.h"
    + #include "SkReadBuffer.h"
    ++#include "SkSafeMath.h"
    + #include "SkWriteBuffer.h"
    + 
    ++void* sk_calloc_throw(size_t count, size_t elemSize) {
    ++    return sk_calloc_throw(SkSafeMath::Mul(count, elemSize));
    ++}
    ++
    ++void* sk_malloc_throw(size_t count, size_t elemSize) {
    ++    return sk_malloc_throw(SkSafeMath::Mul(count, elemSize));
    ++}
    ++
    ++void* sk_realloc_throw(void* buffer, size_t count, size_t elemSize) {
    ++    return sk_realloc_throw(buffer, SkSafeMath::Mul(count, elemSize));
    ++}
    ++
    ++void* sk_malloc_canfail(size_t count, size_t elemSize) {
    ++    return sk_malloc_canfail(SkSafeMath::Mul(count, elemSize));
    ++}
    ++
    ++///////////////////////////////////////////////////////////////////////////////////////////////////
    ++
    + // assumes ptr was allocated via sk_malloc
    + static void sk_free_releaseproc(void* ptr, void*) {
    +     sk_free(ptr);
    +@@ -97,7 +116,7 @@ SkMallocPixelRef* SkMallocPixelRef::NewAllocate(const SkImageInfo& info,
    + SkMallocPixelRef* SkMallocPixelRef::NewZeroed(const SkImageInfo& info,
    +                                               size_t rowBytes,
    +                                               SkColorTable* ctable) {
    +-    return NewUsing(sk_calloc, info, rowBytes, ctable);
    ++    return NewUsing(sk_calloc_canfail, info, rowBytes, ctable);
    + }
    + 
    + SkMallocPixelRef* SkMallocPixelRef::NewWithProc(const SkImageInfo& info,
    +diff --git a/src/core/SkMath.cpp b/src/core/SkMath.cpp
    +index af93d7ecb2..a10cfc344b 100644
    +--- a/src/core/SkMath.cpp
    ++++ b/src/core/SkMath.cpp
    +@@ -8,6 +8,7 @@
    + #include "SkMathPriv.h"
    + #include "SkFloatBits.h"
    + #include "SkFloatingPoint.h"
    ++#include "SkSafeMath.h"
    + #include "SkScalar.h"
    + 
    + const uint32_t gIEEENotANumber = 0x7FFFFFFF;
    +@@ -136,8 +137,6 @@ int32_t SkSqrtBits(int32_t x, int count) {
    +     return root;
    + }
    + 
    +-///////////////////////////////////////////////////////////////////////////////
    +-
    + float SkScalarSinCos(float radians, float* cosValue) {
    +     float sinValue = sk_float_sin(radians);
    + 
    +@@ -153,3 +152,17 @@ float SkScalarSinCos(float radians, float* cosValue) {
    +     }
    +     return sinValue;
    + }
    ++
    ++///////////////////////////////////////////////////////////////////////////////////////////////////
    ++
    ++size_t SkSafeMath::Add(size_t x, size_t y) {
    ++    SkSafeMath tmp;
    ++    size_t sum = tmp.add(x, y);
    ++    return tmp.ok() ? sum : SK_MaxSizeT;
    ++}
    ++
    ++size_t SkSafeMath::Mul(size_t x, size_t y) {
    ++    SkSafeMath tmp;
    ++    size_t prod = tmp.mul(x, y);
    ++    return tmp.ok() ? prod : SK_MaxSizeT;
    ++}
     diff --git a/src/core/SkPath.cpp b/src/core/SkPath.cpp
     index 320448a30e..9eb5cd184b 100644
     --- a/src/core/SkPath.cpp
    @@ -305,6 +613,136 @@ index 320448a30e..9eb5cd184b 100644
      #include "SkStringUtils.h"
      #include "SkStream.h"
      
    +diff --git a/src/core/SkRegion_path.cpp b/src/core/SkRegion_path.cpp
    +index 9289641c69..bfbfb4c569 100644
    +--- a/src/core/SkRegion_path.cpp
    ++++ b/src/core/SkRegion_path.cpp
    +@@ -141,12 +141,7 @@ bool SkRgnBuilder::init(int maxHeight, int maxTransitions, bool pathIsInverse) {
    +     }
    +     fStorageCount = sk_64_asS32(count);
    + 
    +-    int64_t size = sk_64_mul(fStorageCount, sizeof(SkRegion::RunType));
    +-    if (size < 0 || !sk_64_isS32(size)) {
    +-        return false;
    +-    }
    +-
    +-    fStorage = (SkRegion::RunType*)sk_malloc_flags(sk_64_asS32(size), 0);
    ++    fStorage = (SkRegion::RunType*)sk_malloc_canfail(fStorageCount, sizeof(SkRegion::RunType));
    +     if (nullptr == fStorage) {
    +         return false;
    +     }
    +diff --git a/src/core/SkSafeMath.h b/src/core/SkSafeMath.h
    +new file mode 100644
    +index 0000000000..bdea2ba93d
    +--- /dev/null
    ++++ b/src/core/SkSafeMath.h
    +@@ -0,0 +1,106 @@
    ++/*
    ++ * Copyright 2017 Google Inc.
    ++ *
    ++ * Use of this source code is governed by a BSD-style license that can be
    ++ * found in the LICENSE file.
    ++ */
    ++
    ++#ifndef SkSafeMath_DEFINED
    ++#define SkSafeMath_DEFINED
    ++
    ++#include "SkTFitsIn.h"
    ++
    ++// SkSafeMath always check that a series of operations do not overflow.
    ++// This must be correct for all platforms, because this is a check for safety at runtime.
    ++
    ++class SkSafeMath {
    ++public:
    ++    SkSafeMath() = default;
    ++
    ++    bool ok() const { return fOK; }
    ++    explicit operator bool() const { return fOK; }
    ++
    ++    size_t mul(size_t x, size_t y) {
    ++        return sizeof(size_t) == sizeof(uint64_t) ? mul64(x, y) : mul32(x, y);
    ++    }
    ++
    ++    size_t add(size_t x, size_t y) {
    ++        size_t result = x + y;
    ++        fOK &= result >= x;
    ++        return result;
    ++    }
    ++
    ++    /**
    ++     *  Return a + b, unless this result is an overflow/underflow. In those cases, fOK will
    ++     *  be set to false, and it is undefined what this returns.
    ++     */
    ++    int addInt(int a, int b) {
    ++        if (b < 0 && a < std::numeric_limits<int>::min() - b) {
    ++            fOK = false;
    ++            return a;
    ++        } else if (b > 0 && a > std::numeric_limits<int>::max() - b) {
    ++            fOK = false;
    ++            return a;
    ++        }
    ++        return a + b;
    ++    }
    ++
    ++    size_t alignUp(size_t x, size_t alignment) {
    ++        SkASSERT(alignment && !(alignment & (alignment - 1)));
    ++        return add(x, alignment - 1) & ~(alignment - 1);
    ++    }
    ++
    ++    template <typename T> T castTo(size_t value) {
    ++        if (!SkTFitsIn<T>(value)) {
    ++            fOK = false;
    ++        }
    ++        return static_cast<T>(value);
    ++    }
    ++
    ++    // These saturate to their results
    ++    static size_t Add(size_t x, size_t y);
    ++    static size_t Mul(size_t x, size_t y);
    ++    static size_t Align4(size_t x) {
    ++        SkSafeMath safe;
    ++        return safe.alignUp(x, 4);
    ++    }
    ++
    ++private:
    ++    uint32_t mul32(uint32_t x, uint32_t y) {
    ++        uint64_t bx = x;
    ++        uint64_t by = y;
    ++        uint64_t result = bx * by;
    ++        fOK &= result >> 32 == 0;
    ++        return result;
    ++    }
    ++
    ++    uint64_t mul64(uint64_t x, uint64_t y) {
    ++        if (x <= std::numeric_limits<uint64_t>::max() >> 32
    ++            && y <= std::numeric_limits<uint64_t>::max() >> 32) {
    ++            return x * y;
    ++        } else {
    ++            auto hi = [](uint64_t x) { return x >> 32; };
    ++            auto lo = [](uint64_t x) { return x & 0xFFFFFFFF; };
    ++
    ++            uint64_t lx_ly = lo(x) * lo(y);
    ++            uint64_t hx_ly = hi(x) * lo(y);
    ++            uint64_t lx_hy = lo(x) * hi(y);
    ++            uint64_t hx_hy = hi(x) * hi(y);
    ++            uint64_t result = 0;
    ++            result = this->add(lx_ly, (hx_ly << 32));
    ++            result = this->add(result, (lx_hy << 32));
    ++            fOK &= (hx_hy + (hx_ly >> 32) + (lx_hy >> 32)) == 0;
    ++
    ++            #if defined(SK_DEBUG) && defined(__clang__) && defined(__x86_64__)
    ++                auto double_check = (unsigned __int128)x * y;
    ++                SkASSERT(result == (double_check & 0xFFFFFFFFFFFFFFFF));
    ++                SkASSERT(!fOK || (double_check >> 64 == 0));
    ++            #endif
    ++
    ++            return result;
    ++        }
    ++    }
    ++    bool fOK = true;
    ++};
    ++
    ++#endif//SkSafeMath_DEFINED
     diff --git a/src/core/SkStream.cpp b/src/core/SkStream.cpp
     index 9529308e86..4f00768747 100644
     --- a/src/core/SkStream.cpp
    @@ -468,6 +906,114 @@ index 9529308e86..4f00768747 100644
      }
      
      ///////////////////////////////////////////////////////////////////////////////
    +diff --git a/src/gpu/GrBufferAllocPool.cpp b/src/gpu/GrBufferAllocPool.cpp
    +index 73b70bf861..c6e8544666 100644
    +--- a/src/gpu/GrBufferAllocPool.cpp
    ++++ b/src/gpu/GrBufferAllocPool.cpp
    +@@ -283,7 +283,7 @@ void* GrBufferAllocPool::resetCpuData(size_t newSize) {
    +     sk_free(fCpuData);
    +     if (newSize) {
    +         if (fGpu->caps()->mustClearUploadedBufferData()) {
    +-            fCpuData = sk_calloc(newSize);
    ++            fCpuData = sk_calloc_canfail(newSize);
    +         } else {
    +             fCpuData = sk_malloc_throw(newSize);
    +         }
    +diff --git a/src/ports/SkMemory_malloc.cpp b/src/ports/SkMemory_malloc.cpp
    +index 9fc17b7c34..ccc39e68d2 100644
    +--- a/src/ports/SkMemory_malloc.cpp
    ++++ b/src/ports/SkMemory_malloc.cpp
    +@@ -39,10 +39,6 @@ void sk_out_of_memory(void) {
    +     abort();
    + }
    + 
    +-void* sk_malloc_throw(size_t size) {
    +-    return sk_malloc_flags(size, SK_MALLOC_THROW);
    +-}
    +-
    + void* sk_realloc_throw(void* addr, size_t size) {
    +     return throw_on_failure(size, realloc(addr, size));
    + }
    +@@ -54,7 +50,16 @@ void sk_free(void* p) {
    + }
    + 
    + void* sk_malloc_flags(size_t size, unsigned flags) {
    +-    void* p = malloc(size);
    ++    void* p;
    ++#ifdef SK_SUPPORT_LEGACY_MALLOC_PORTING_LAYER
    ++    p = malloc(size);
    ++#else
    ++    if (flags & SK_MALLOC_ZERO_INITIALIZE) {
    ++        p = calloc(size, 1);
    ++    } else {
    ++        p = malloc(size);
    ++    }
    ++#endif
    +     if (flags & SK_MALLOC_THROW) {
    +         return throw_on_failure(size, p);
    +     } else {
    +@@ -62,10 +67,15 @@ void* sk_malloc_flags(size_t size, unsigned flags) {
    +     }
    + }
    + 
    ++#ifdef SK_SUPPORT_LEGACY_MALLOC_PORTING_LAYER
    ++void* sk_malloc_throw(size_t size) {
    ++    return sk_malloc_flags(size, SK_MALLOC_THROW);
    ++}
    + void* sk_calloc(size_t size) {
    +     return calloc(size, 1);
    + }
    +-
    + void* sk_calloc_throw(size_t size) {
    +     return throw_on_failure(size, sk_calloc(size));
    + }
    ++#endif
    ++
    +diff --git a/src/ports/SkMemory_mozalloc.cpp b/src/ports/SkMemory_mozalloc.cpp
    +index f8a996307e..7ddf69423c 100644
    +--- a/src/ports/SkMemory_mozalloc.cpp
    ++++ b/src/ports/SkMemory_mozalloc.cpp
    +@@ -21,22 +21,28 @@ void sk_out_of_memory(void) {
    +     mozalloc_handle_oom(0);
    + }
    + 
    +-void* sk_malloc_throw(size_t size) {
    +-    return sk_malloc_flags(size, SK_MALLOC_THROW);
    ++void sk_free(void* p) {
    ++    free(p);
    + }
    + 
    + void* sk_realloc_throw(void* addr, size_t size) {
    +     return moz_xrealloc(addr, size);
    + }
    + 
    +-void sk_free(void* p) {
    +-    free(p);
    +-}
    +-
    + void* sk_malloc_flags(size_t size, unsigned flags) {
    ++#ifndef SK_SUPPORT_LEGACY_MALLOC_PORTING_LAYER
    ++    if (flags & SK_MALLOC_ZERO_INITIALIZE) {
    ++        return (flags & SK_MALLOC_THROW) ? moz_xcalloc(size, 1) : calloc(size, 1);
    ++    }
    ++#endif
    +     return (flags & SK_MALLOC_THROW) ? moz_xmalloc(size) : malloc(size);
    + }
    + 
    ++#ifdef SK_SUPPORT_LEGACY_MALLOC_PORTING_LAYER
    ++void* sk_malloc_throw(size_t size) {
    ++    return sk_malloc_flags(size, SK_MALLOC_THROW);
    ++}
    ++
    + void* sk_calloc(size_t size) {
    +     return calloc(size, 1);
    + }
    +@@ -44,3 +50,5 @@ void* sk_calloc(size_t size) {
    + void* sk_calloc_throw(size_t size) {
    +     return moz_xcalloc(size, 1);
    + }
    ++#endif
    ++
     diff --git a/src/ports/SkOSFile_posix.cpp b/src/ports/SkOSFile_posix.cpp
     index 396de68bbe..48b5b95ad3 100644
     --- a/src/ports/SkOSFile_posix.cpp
    diff --git a/external_sqlite.patch b/external_sqlite.patch
    index a5fb9ae..ea9a10c 100644
    --- a/external_sqlite.patch
    +++ b/external_sqlite.patch
    @@ -7,396 +7,242980 @@ index 96cdf7f..6fe7d18 100644
     +URL: https://sqlite.org/src/tarball/SQLite-69906880.tar.gz?uuid=69906880cee1f246cce494672402e0c7f29bd4ec19c437d26d603870d2bd625d
      Version: 3.9.2
      BugComponent: 24950
    +diff --git a/dist/Android.bp b/dist/Android.bp
    +new file mode 100644
    +index 0000000..2211d1f
    +--- /dev/null
    ++++ b/dist/Android.bp
    +@@ -0,0 +1,168 @@
    ++//
    ++//
    ++// Build the library
    ++//
    ++//
    ++
    ++cc_defaults {
    ++    name: "sqlite-minimal-defaults",
    ++    host_supported: true,
    ++
    ++    // static analysis is too slow on these huge files.
    ++    tidy_checks: [
    ++        "-clang-analyzer-*",
    ++    ],
    ++
    ++    // NOTE the following flags,
    ++    //   SQLITE_TEMP_STORE=3 causes all TEMP files to go into RAM. and thats the behavior we want
    ++    //   SQLITE_ENABLE_FTS3   enables usage of FTS3 - NOT FTS1 or 2.
    ++    //   SQLITE_DEFAULT_AUTOVACUUM=1  causes the databases to be subject to auto-vacuum
    ++    cflags: [
    ++        "-DNDEBUG=1",
    ++        "-DHAVE_USLEEP=1",
    ++        "-DSQLITE_HAVE_ISNAN",
    ++        "-DSQLITE_DEFAULT_JOURNAL_SIZE_LIMIT=1048576",
    ++        "-DSQLITE_THREADSAFE=2",
    ++        "-DSQLITE_TEMP_STORE=3",
    ++        "-DSQLITE_POWERSAFE_OVERWRITE=1",
    ++        "-DSQLITE_DEFAULT_FILE_FORMAT=4",
    ++        "-DSQLITE_DEFAULT_AUTOVACUUM=1",
    ++        "-DSQLITE_ENABLE_MEMORY_MANAGEMENT=1",
    ++        "-DSQLITE_ENABLE_FTS3",
    ++        "-DSQLITE_ENABLE_FTS3_BACKWARDS",
    ++        "-DSQLITE_ENABLE_FTS4",
    ++        "-DSQLITE_OMIT_BUILTIN_TEST",
    ++        "-DSQLITE_OMIT_COMPILEOPTION_DIAGS",
    ++        "-DSQLITE_OMIT_LOAD_EXTENSION",
    ++        "-DSQLITE_DEFAULT_FILE_PERMISSIONS=0600",
    ++        "-DSQLITE_SECURE_DELETE",
    ++        "-DSQLITE_ENABLE_BATCH_ATOMIC_WRITE",
    ++        "-Wno-unused-parameter",
    ++        "-Werror",
    ++    ],
    ++
    ++    target: {
    ++        linux_glibc: {
    ++            cflags: ["-DHAVE_POSIX_FALLOCATE=1"],
    ++        },
    ++    },
    ++}
    ++
    ++cc_defaults {
    ++    name: "sqlite-defaults",
    ++    defaults: ["sqlite-minimal-defaults"],
    ++    target: {
    ++        android: {
    ++            cflags: [
    ++                "-DUSE_PREAD64",
    ++                "-Dfdatasync=fdatasync",
    ++                "-DHAVE_MALLOC_H=1",
    ++                "-DHAVE_MALLOC_USABLE_SIZE",
    ++            ],
    ++        },
    ++    },
    ++}
    ++
    ++cc_library {
    ++    name: "libsqlite",
    ++    defaults: ["sqlite-defaults"],
    ++    vendor_available: true,
    ++    vndk: {
    ++        enabled: true,
    ++    },
    ++
    ++    srcs: ["sqlite3.c"],
    ++
    ++    target: {
    ++        android: {
    ++            shared_libs: [
    ++                "libdl",
    ++                "liblog",
    ++                "libutils",
    ++                "libicuuc",
    ++                "libicui18n",
    ++            ],
    ++            cflags: ["-DSQLITE_ENABLE_ICU"],
    ++
    ++            // include android specific methods
    ++            whole_static_libs: ["libsqlite3_android"],
    ++        },
    ++        host: {
    ++            static_libs: [
    ++                "liblog",
    ++                "libutils",
    ++            ],
    ++        },
    ++        not_windows: {
    ++            shared_libs: [
    ++                "libicuuc",
    ++                "libicui18n",
    ++            ],
    ++
    ++            // include android specific methods
    ++            whole_static_libs: ["libsqlite3_android"],
    ++        },
    ++        windows: {
    ++            enabled: true,
    ++        },
    ++        vendor: {
    ++            cflags: ["-USQLITE_ENABLE_ICU"],
    ++            exclude_shared_libs: ["libicuuc", "libicui18n"],
    ++        },
    ++    },
    ++
    ++    export_include_dirs: ["."],
    ++}
    ++
    ++//
    ++//
    ++// Build the device command line tool sqlite3
    ++//
    ++//
    ++
    ++cc_binary {
    ++    name: "sqlite3",
    ++    defaults: ["sqlite-defaults"],
    ++
    ++    srcs: ["shell.c"],
    ++
    ++    tags: ["debug"],
    ++
    ++    target: {
    ++        android: {
    ++            shared_libs: [
    ++                "libsqlite",
    ++                "libicuuc",
    ++                "libicui18n",
    ++                "liblog",
    ++                "libutils",
    ++            ],
    ++            static_libs: [
    ++                "libicuandroid_utils",
    ++            ],
    ++        },
    ++        host: {
    ++            cflags: ["-DNO_ANDROID_FUNCS=1"],
    ++            static_libs: [
    ++                "libsqlite",
    ++                // sqlite3MemsysAlarm uses LOG()
    ++                "liblog",
    ++            ],
    ++        },
    ++
    ++        windows: {
    ++            enabled: true,
    ++        },
    ++    },
    ++}
    ++
    ++// Build a minimal version of sqlite3 without any android specific
    ++// features against the NDK. This is used by libcore's JDBC related
    ++// unit tests.
    ++cc_library_static {
    ++    name: "libsqlite_static_minimal",
    ++    defaults: ["sqlite-minimal-defaults"],
    ++    srcs: ["sqlite3.c"],
    ++    sdk_version: "23",
    ++    export_include_dirs: ["."],
    ++}
     diff --git a/dist/Android.patch b/dist/Android.patch
    -index 58557e6..f766487 100644
    +index 58557e6..c5f7e1d 100644
     --- a/dist/Android.patch
     +++ b/dist/Android.patch
    -@@ -1,6 +1,6 @@
    +@@ -1,7 +1,7 @@
      diff -r -u -d orig/shell.c ./shell.c
     ---- orig/shell.c	2015-11-03 01:44:04.000000000 -0800
     -+++ ./shell.c	2015-12-23 09:50:51.081951250 -0800
    -+--- orig/shell.c	2017-07-21 01:25:18.136530117 -0700
    -++++ ./shell.c	2017-07-21 01:25:55.316260658 -0700
    - @@ -52,6 +52,12 @@
    +-@@ -52,6 +52,12 @@
    ++--- orig/shell.c	2018-04-13 17:25:47.747857988 -0700
    +++++ ./shell.c	2018-04-13 17:25:47.787857731 -0700
    ++@@ -87,6 +87,12 @@
       #endif
       #include <ctype.h>
    -@@ -38,9 +38,9 @@ diff -r -u -d orig/shell.c ./shell.c
    -  }
    +  #include <stdarg.h>
    +@@ -14,10 +14,10 @@ diff -r -u -d orig/shell.c ./shell.c
       
    - diff -r -u -d orig/sqlite3.c ./sqlite3.c
    +  #if !defined(_WIN32) && !defined(WIN32)
    +  # include <signal.h>
    +-@@ -1943,6 +1949,22 @@
    +-                             readfileFunc, 0, 0);
    +-     sqlite3_create_function(p->db, "writefile", 2, SQLITE_UTF8, 0,
    +-                             writefileFunc, 0, 0);
    ++@@ -10389,6 +10395,23 @@
    ++                             editFunc, 0, 0);
    ++     sqlite3_create_function(p->db, "edit", 2, SQLITE_UTF8, 0,
    ++                             editFunc, 0, 0);
    + +
    + +    // Begin Android Add
    + +    #ifndef NO_ANDROID_FUNCS
    +@@ -34,55 +34,14 @@ diff -r -u -d orig/shell.c ./shell.c
    + +        }
    + +    #endif
    + +    // End Android Add
    +-   }
    +- }
    +- 
    +-diff -r -u -d orig/sqlite3.c ./sqlite3.c
     ---- orig/sqlite3.c	2015-11-03 01:44:04.000000000 -0800
     -+++ ./sqlite3.c	2015-12-23 09:50:51.113951381 -0800
     -@@ -26470,6 +26470,13 @@
    -+--- orig/sqlite3.c	2017-07-21 01:25:18.524527313 -0700
    -++++ ./sqlite3.c	2017-07-21 01:25:55.356260367 -0700
    -+@@ -26474,6 +26474,13 @@
    -  /* #include "sqliteInt.h" */
    -  #if SQLITE_OS_UNIX              /* This file is used on unix only */
    -  
    -@@ -54,7 +54,7 @@ diff -r -u -d orig/sqlite3.c ./sqlite3.c
    -  /*
    -  ** There are various methods for file locking used for concurrency
    -  ** control:
    +- /* #include "sqliteInt.h" */
    +- #if SQLITE_OS_UNIX              /* This file is used on unix only */
    +- 
    +-+/* Use posix_fallocate() if it is available
    +-+*/
    +-+#if !defined(HAVE_POSIX_FALLOCATE) \
    +-+      && (_XOPEN_SOURCE >= 600 || _POSIX_C_SOURCE >= 200112L)
    +-+# define HAVE_POSIX_FALLOCATE 1
    +-+#endif
    + +
    +- /*
    +- ** There are various methods for file locking used for concurrency
    +- ** control:
     -@@ -27024,7 +27031,12 @@
    -+@@ -27028,7 +27035,12 @@
    -  #else
    -    { "pread64",      (sqlite3_syscall_ptr)0,          0  },
    -  #endif
    -@@ -67,7 +67,7 @@ diff -r -u -d orig/sqlite3.c ./sqlite3.c
    -  
    -    { "write",        (sqlite3_syscall_ptr)write,      0  },
    -  #define osWrite     ((ssize_t(*)(int,const void*,size_t))aSyscall[11].pCurrent)
    +- #else
    +-   { "pread64",      (sqlite3_syscall_ptr)0,          0  },
    +- #endif
    +-+#ifdef ANDROID
    +-+// Bionic defines pread64 using off64_t rather than off_t.
    +-+#define osPread64   ((ssize_t(*)(int,void*,size_t,off64_t))aSyscall[10].pCurrent)
    +-+#else
    +- #define osPread64   ((ssize_t(*)(int,void*,size_t,off_t))aSyscall[10].pCurrent)
    +-+#endif
    +- 
    +-   { "write",        (sqlite3_syscall_ptr)write,      0  },
    +- #define osWrite     ((ssize_t(*)(int,const void*,size_t))aSyscall[11].pCurrent)
     -@@ -27042,8 +27054,14 @@
    -+@@ -27046,8 +27058,14 @@
    -  #else
    -    { "pwrite64",     (sqlite3_syscall_ptr)0,          0  },
    -  #endif
    -@@ -82,7 +82,7 @@ diff -r -u -d orig/sqlite3.c ./sqlite3.c
    -  
    -    { "fchmod",       (sqlite3_syscall_ptr)fchmod,     0  },
    -  #define osFchmod    ((int(*)(int,mode_t))aSyscall[14].pCurrent)
    +- #else
    +-   { "pwrite64",     (sqlite3_syscall_ptr)0,          0  },
    +- #endif
    +-+#ifdef ANDROID
    +-+// Bionic defines pwrite64 using off64_t rather than off_t.
    +-+#define osPwrite64  ((ssize_t(*)(int,const void*,size_t,off64_t))\
    +-+                    aSyscall[13].pCurrent)
    +-+#else
    +- #define osPwrite64  ((ssize_t(*)(int,const void*,size_t,off_t))\
    +-                     aSyscall[13].pCurrent)
    +-+#endif
    +- 
    +-   { "fchmod",       (sqlite3_syscall_ptr)fchmod,     0  },
    +- #define osFchmod    ((int(*)(int,mode_t))aSyscall[14].pCurrent)
     -@@ -30292,7 +30310,7 @@
    -+@@ -30296,7 +30314,7 @@
    ++     if( p->openMode==SHELL_OPEN_ZIPFILE ){
    ++       char *zSql = sqlite3_mprintf(
    ++          "CREATE VIRTUAL TABLE zip USING zipfile(%Q);", p->zDbFilename);
    ++diff -r -u -d orig/sqlite3.c ./sqlite3.c
    ++--- orig/sqlite3.c	2018-12-27 15:39:18.784267281 -0800
    +++++ ./sqlite3.c	2018-12-27 15:39:18.788267250 -0800
    ++@@ -34428,7 +34428,7 @@
         SimulateIOError( rc=1 );
         if( rc!=0 ){
           storeLastErrno((unixFile*)id, errno);
    -@@ -91,7 +91,7 @@ diff -r -u -d orig/sqlite3.c ./sqlite3.c
    +@@ -91,7 +50,7 @@ diff -r -u -d orig/sqlite3.c ./sqlite3.c
         }
         *pSize = buf.st_size;
       
     -@@ -30328,7 +30346,7 @@
    -+@@ -30332,7 +30350,7 @@
    ++@@ -34464,7 +34464,7 @@
           struct stat buf;              /* Used to hold return values of fstat() */
          
           if( osFstat(pFile->h, &buf) ){
    -@@ -100,7 +100,7 @@ diff -r -u -d orig/sqlite3.c ./sqlite3.c
    +@@ -100,34 +59,25 @@ diff -r -u -d orig/sqlite3.c ./sqlite3.c
           }
       
           nSize = ((nByte+pFile->szChunk-1) / pFile->szChunk) * pFile->szChunk;
     -@@ -30913,7 +30931,7 @@
    -+@@ -30917,7 +30935,7 @@
    ++@@ -35139,7 +35139,7 @@
           ** with the same permissions.
           */
    -      if( osFstat(pDbFd->h, &sStat) && pInode->bProcessLock==0 ){
    -@@ -109,7 +109,7 @@ diff -r -u -d orig/sqlite3.c ./sqlite3.c
    +-     if( osFstat(pDbFd->h, &sStat) && pInode->bProcessLock==0 ){
    ++     if( osFstat(pDbFd->h, &sStat) ){
    + -      rc = SQLITE_IOERR_FSTAT;
    + +      rc = unixLogError(SQLITE_IOERR_FSTAT, "fstat", pDbFd->zPath);
             goto shm_open_err;
           }
       
     -@@ -32260,7 +32278,7 @@
    -+@@ -32264,7 +32282,7 @@
    -        *pUid = sStat.st_uid;
    -        *pGid = sStat.st_gid;
    -      }else{
    -@@ -118,7 +118,7 @@ diff -r -u -d orig/sqlite3.c ./sqlite3.c
    -      }
    -    }else if( flags & SQLITE_OPEN_DELETEONCLOSE ){
    -      *pMode = 0600;
    +-       *pUid = sStat.st_uid;
    +-       *pGid = sStat.st_gid;
    +-     }else{
    +--      rc = SQLITE_IOERR_FSTAT;
    +-+      rc = unixLogError(SQLITE_IOERR_FSTAT, "stat", zDb);
    +-     }
    +-   }else if( flags & SQLITE_OPEN_DELETEONCLOSE ){
    +-     *pMode = 0600;
     -@@ -108046,7 +108064,7 @@
    -+@@ -108062,7 +108080,7 @@
    ++@@ -118054,7 +118054,7 @@
         }
         if( pDb->pSchema->file_format>SQLITE_MAX_FILE_FORMAT ){
           sqlite3SetString(pzErrMsg, db, "unsupported file format");
    -@@ -127,7 +127,7 @@ diff -r -u -d orig/sqlite3.c ./sqlite3.c
    + -    rc = SQLITE_ERROR;
    +-+    rc = SQLITE_CORRUPT_BKPT; // Android Change from "rc = SQLITE_ERROR;"
    +++    rc = SQLITE_CORRUPT_BKPT; // Android Change from "rc = SQLITE_ERROR;";
           goto initone_error_out;
         }
       
     -@@ -139786,16 +139804,28 @@
    -+@@ -139799,16 +139817,28 @@
    ++@@ -152769,13 +152769,25 @@
         ** module with sqlite.
         */
         if( SQLITE_OK==rc 
    -diff --git a/dist/orig/sqlite3.c b/dist/orig/sqlite3.c
    -index 0ae407d..f943a00 100644
    ---- a/dist/orig/sqlite3.c
    -+++ b/dist/orig/sqlite3.c
    -@@ -327,7 +327,7 @@ extern "C" {
    +@@ -152,8 +102,4 @@ diff -r -u -d orig/sqlite3.c ./sqlite3.c
    + +#endif
    +      rc = sqlite3_create_module_v2(
    +          db, "fts3", &fts3Module, (void *)pHash, hashDestroy
    +--    );
    +-+        );
    +-     if( rc==SQLITE_OK ){
    +-       rc = sqlite3_create_module_v2(
    +-           db, "fts4", &fts3Module, (void *)pHash, 0
    ++     );
    +diff --git a/dist/README-Android b/dist/README-Android
    +index 549c3f9..0ceec52 100644
    +--- a/dist/README-Android
    ++++ b/dist/README-Android
    +@@ -1,7 +1,7 @@
    + SQLite on Android
    + 
    + The Android port of SQLite contains a few customizations.
    +-They are immortalized in Android.patch to ease future upgraded.
    ++They are immortalized in Android.patch to ease future upgrades.
    + 
    + This file can be regenerated using:
    + 
    +diff --git a/dist/orig/shell.c b/dist/orig/shell.c
    +index f790871..41baf67 100644
    +--- a/dist/orig/shell.c
    ++++ b/dist/orig/shell.c
    +@@ -1,3 +1,21 @@
    ++/* DO NOT EDIT!
    ++** This file is automatically generated by the script in the canonical
    ++** SQLite source tree at tool/mkshellc.tcl.  That script combines source
    ++** code from various constituent source files of SQLite into this single
    ++** "shell.c" file used to implement the SQLite command-line shell.
    ++**
    ++** Most of the code found below comes from the "src/shell.c.in" file in
    ++** the canonical SQLite source tree.  That main file contains "INCLUDE"
    ++** lines that specify other files in the canonical source tree that are
    ++** inserted to getnerate this complete program source file.
    ++**
    ++** The code from multiple files is combined into this single "shell.c"
    ++** source file to help make the command-line program easier to compile.
    ++**
    ++** To modify this program, get a copy of the canonical SQLite source tree,
    ++** edit the src/shell.c.in" and/or some of the other files that are included
    ++** by "src/shell.c.in", then rerun the tool/mkshellc.tcl script.
    ++*/
    + /*
    + ** 2001 September 15
    + **
    +@@ -18,11 +36,25 @@
    + #endif
    + 
    + /*
    +-** If requested, include the SQLite compiler options file for MSVC.
    ++** Warning pragmas copied from msvc.h in the core.
      */
    - #define SQLITE_VERSION        "3.9.2"
    - #define SQLITE_VERSION_NUMBER 3009002
    --#define SQLITE_SOURCE_ID      "2015-11-02 18:31:45 bda77dda9697c463c3d0704014d51627fceee328"
    -+#define SQLITE_SOURCE_ID      "2017-07-21 07:45:23 69906880cee1f246cce494672402e0c7f29bd4ec19c437d26d603870d2bd625d"
    +-#if defined(INCLUDE_MSVC_H)
    +-#include "msvc.h"
    +-#endif
    ++#if defined(_MSC_VER)
    ++#pragma warning(disable : 4054)
    ++#pragma warning(disable : 4055)
    ++#pragma warning(disable : 4100)
    ++#pragma warning(disable : 4127)
    ++#pragma warning(disable : 4130)
    ++#pragma warning(disable : 4152)
    ++#pragma warning(disable : 4189)
    ++#pragma warning(disable : 4206)
    ++#pragma warning(disable : 4210)
    ++#pragma warning(disable : 4232)
    ++#pragma warning(disable : 4244)
    ++#pragma warning(disable : 4305)
    ++#pragma warning(disable : 4306)
    ++#pragma warning(disable : 4702)
    ++#pragma warning(disable : 4706)
    ++#endif /* defined(_MSC_VER) */
      
      /*
    - ** CAPI3REF: Run-Time Library Version Numbers
    -@@ -4566,6 +4566,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_value_bytes16(sqlite3_value*);
    - SQLITE_API double SQLITE_STDCALL sqlite3_value_double(sqlite3_value*);
    - SQLITE_API int SQLITE_STDCALL sqlite3_value_int(sqlite3_value*);
    - SQLITE_API sqlite3_int64 SQLITE_STDCALL sqlite3_value_int64(sqlite3_value*);
    -+SQLITE_API void *SQLITE_STDCALL sqlite3_value_pointer(sqlite3_value*);
    - SQLITE_API const unsigned char *SQLITE_STDCALL sqlite3_value_text(sqlite3_value*);
    - SQLITE_API const void *SQLITE_STDCALL sqlite3_value_text16(sqlite3_value*);
    - SQLITE_API const void *SQLITE_STDCALL sqlite3_value_text16le(sqlite3_value*);
    -@@ -4878,6 +4879,7 @@ SQLITE_API void SQLITE_STDCALL sqlite3_result_error_code(sqlite3_context*, int);
    - SQLITE_API void SQLITE_STDCALL sqlite3_result_int(sqlite3_context*, int);
    - SQLITE_API void SQLITE_STDCALL sqlite3_result_int64(sqlite3_context*, sqlite3_int64);
    - SQLITE_API void SQLITE_STDCALL sqlite3_result_null(sqlite3_context*);
    -+SQLITE_API void SQLITE_STDCALL sqlite3_result_pointer(sqlite3_context*, void*);
    - SQLITE_API void SQLITE_STDCALL sqlite3_result_text(sqlite3_context*, const char*, int, void(*)(void*));
    - SQLITE_API void SQLITE_STDCALL sqlite3_result_text64(sqlite3_context*, const char*,sqlite3_uint64,
    -                            void(*)(void*), unsigned char encoding);
    -@@ -15415,6 +15417,7 @@ struct Mem {
    -     double r;           /* Real value used when MEM_Real is set in flags */
    -     i64 i;              /* Integer value used when MEM_Int is set in flags */
    -     int nZero;          /* Used when bit MEM_Zero is set in flags */
    -+    void *pPtr;         /* Pointer when flags==MEM_Ptr|MEM_Null */
    -     FuncDef *pDef;      /* Used only when flags==MEM_Agg */
    -     RowSet *pRowSet;    /* Used only when flags==MEM_RowSet */
    -     VdbeFrame *pFrame;  /* Used when flags==MEM_Frame */
    -@@ -15472,6 +15475,7 @@ struct Mem {
    - ** policy for Mem.z.  The MEM_Term flag tells us whether or not the
    - ** string is \000 or \u0000 terminated
    + ** No support for loadable extensions in VxWorks.
    +@@ -47,6 +79,9 @@
    + #include <stdio.h>
    + #include <assert.h>
    + #include "sqlite3.h"
    ++typedef sqlite3_int64 i64;
    ++typedef sqlite3_uint64 u64;
    ++typedef unsigned char u8;
    + #if SQLITE_USER_AUTHENTICATION
    + # include "sqlite3userauth.h"
    + #endif
    +@@ -58,9 +93,19 @@
    + # if !defined(__RTP__) && !defined(_WRS_KERNEL)
    + #  include <pwd.h>
    + # endif
    ++#endif
    ++#if (!defined(_WIN32) && !defined(WIN32)) || defined(__MINGW32__)
    + # include <unistd.h>
    +-# include <sys/types.h>
    ++# include <dirent.h>
    ++# if defined(__MINGW32__)
    ++#  define DIRENT dirent
    ++#  ifndef S_ISLNK
    ++#   define S_ISLNK(mode) (0)
    ++#  endif
    ++# endif
    + #endif
    ++#include <sys/types.h>
    ++#include <sys/stat.h>
    + 
    + #if HAVE_READLINE
    + # include <readline/readline.h>
    +@@ -90,7 +135,7 @@
    + 
    + #else
    + 
    +-# define shell_read_history(X) 
    ++# define shell_read_history(X)
    + # define shell_write_history(X)
    + # define shell_stifle_history(X)
    + 
    +@@ -136,6 +181,16 @@
    + #define IsDigit(X)  isdigit((unsigned char)X)
    + #define ToLower(X)  (char)tolower((unsigned char)X)
    + 
    ++#if defined(_WIN32) || defined(WIN32)
    ++#include <windows.h>
    ++
    ++/* string conversion routines only needed on Win32 */
    ++extern char *sqlite3_win32_unicode_to_utf8(LPCWSTR);
    ++extern char *sqlite3_win32_mbcs_to_utf8_v2(const char *, int);
    ++extern char *sqlite3_win32_utf8_to_mbcs_v2(const char *, int);
    ++extern LPWSTR sqlite3_win32_utf8_to_unicode(const char *zText);
    ++#endif
    ++
    + /* On Windows, we normally run with output mode of TEXT so that \n characters
    + ** are automatically translated into \r\n.  However, this behavior needs
    + ** to be disabled in some cases (ex: when generating CSV output and when
    +@@ -143,17 +198,17 @@
    + ** routines take care of that.
      */
    -+#define MEM_Ptr       0x8000   /* u.pPtr is valid if type==SQLITE_NULL */
    - #define MEM_Term      0x0200   /* String rep is nul terminated */
    - #define MEM_Dyn       0x0400   /* Need to call Mem.xDel() on Mem.z */
    - #define MEM_Static    0x0800   /* Mem.z points to a static string */
    -@@ -15487,7 +15491,7 @@ struct Mem {
    - ** Clear any existing type flags from a Mem and replace them with f
    + #if defined(_WIN32) || defined(WIN32)
    +-static void setBinaryMode(FILE *out){
    +-  fflush(out);
    +-  _setmode(_fileno(out), _O_BINARY);
    ++static void setBinaryMode(FILE *file, int isOutput){
    ++  if( isOutput ) fflush(file);
    ++  _setmode(_fileno(file), _O_BINARY);
    + }
    +-static void setTextMode(FILE *out){
    +-  fflush(out);
    +-  _setmode(_fileno(out), _O_TEXT);
    ++static void setTextMode(FILE *file, int isOutput){
    ++  if( isOutput ) fflush(file);
    ++  _setmode(_fileno(file), _O_TEXT);
    + }
    + #else
    +-# define setBinaryMode(X)
    +-# define setTextMode(X)
    ++# define setBinaryMode(X,Y)
    ++# define setTextMode(X,Y)
    + #endif
    + 
    + 
    +@@ -165,7 +220,7 @@ static sqlite3_int64 timeOfDay(void){
    +   static sqlite3_vfs *clockVfs = 0;
    +   sqlite3_int64 t;
    +   if( clockVfs==0 ) clockVfs = sqlite3_vfs_find(0);
    +-  if( clockVfs->iVersion>=1 && clockVfs->xCurrentTimeInt64!=0 ){
    ++  if( clockVfs->iVersion>=2 && clockVfs->xCurrentTimeInt64!=0 ){
    +     clockVfs->xCurrentTimeInt64(clockVfs, &t);
    +   }else{
    +     double r;
    +@@ -204,7 +259,7 @@ static void beginTimer(void){
    + 
    + /* Return the difference of two time_structs in seconds */
    + static double timeDiff(struct timeval *pStart, struct timeval *pEnd){
    +-  return (pEnd->tv_usec - pStart->tv_usec)*0.000001 + 
    ++  return (pEnd->tv_usec - pStart->tv_usec)*0.000001 +
    +          (double)(pEnd->tv_sec - pStart->tv_sec);
    + }
    + 
    +@@ -229,8 +284,6 @@ static void endTimer(void){
    + 
    + #elif (defined(_WIN32) || defined(WIN32))
    + 
    +-#include <windows.h>
    +-
    + /* Saved resource information for the beginning of an operation */
    + static HANDLE hProcess;
    + static FILETIME ftKernelBegin;
    +@@ -261,7 +314,7 @@ static int hasTimer(void){
    +         if( NULL != getProcessTimesAddr ){
    +           return 1;
    +         }
    +-        FreeLibrary(hinstLib); 
    ++        FreeLibrary(hinstLib);
    +       }
    +     }
    +   }
    +@@ -307,7 +360,7 @@ static void endTimer(void){
    + #define HAS_TIMER hasTimer()
    + 
    + #else
    +-#define BEGIN_TIMER 
    ++#define BEGIN_TIMER
    + #define END_TIMER
    + #define HAS_TIMER 0
    + #endif
    +@@ -317,6 +370,11 @@ static void endTimer(void){
    + */
    + #define UNUSED_PARAMETER(x) (void)(x)
    + 
    ++/*
    ++** Number of elements in an array
    ++*/
    ++#define ArraySize(X)  (int)(sizeof(X)/sizeof(X[0]))
    ++
    + /*
    + ** If the following flag is set, then command execution stops
    + ** at an error if we are not interactive.
    +@@ -329,6 +387,13 @@ static int bail_on_error = 0;
      */
    - #define MemSetTypeFlag(p, f) \
    --   ((p)->flags = ((p)->flags&~(MEM_TypeMask|MEM_Zero))|f)
    -+   ((p)->flags = ((p)->flags&~(MEM_TypeMask|MEM_Zero|MEM_Ptr))|f)
    + static int stdin_is_interactive = 1;
    + 
    ++/*
    ++** On Windows systems we have to know if standard output is a console
    ++** in order to translate UTF-8 into MBCS.  The following variable is
    ++** true if translation is required.
    ++*/
    ++static int stdout_is_console = 1;
    ++
    + /*
    + ** The following is the open SQLite database.  We make a pointer
    + ** to this database a static variable so that it can be accessed
    +@@ -354,6 +419,38 @@ static char *Argv0;
    + static char mainPrompt[20];     /* First line prompt. default: "sqlite> "*/
    + static char continuePrompt[20]; /* Continuation prompt. default: "   ...> " */
      
    ++/*
    ++** Render output like fprintf().  Except, if the output is going to the
    ++** console and if this is running on a Windows machine, translate the
    ++** output from UTF-8 into MBCS.
    ++*/
    ++#if defined(_WIN32) || defined(WIN32)
    ++void utf8_printf(FILE *out, const char *zFormat, ...){
    ++  va_list ap;
    ++  va_start(ap, zFormat);
    ++  if( stdout_is_console && (out==stdout || out==stderr) ){
    ++    char *z1 = sqlite3_vmprintf(zFormat, ap);
    ++    char *z2 = sqlite3_win32_utf8_to_mbcs_v2(z1, 0);
    ++    sqlite3_free(z1);
    ++    fputs(z2, out);
    ++    sqlite3_free(z2);
    ++  }else{
    ++    vfprintf(out, zFormat, ap);
    ++  }
    ++  va_end(ap);
    ++}
    ++#elif !defined(utf8_printf)
    ++# define utf8_printf fprintf
    ++#endif
    ++
    ++/*
    ++** Render output like fprintf().  This should not be used on anything that
    ++** includes string formatting (e.g. "%s").
    ++*/
    ++#if !defined(raw_printf)
    ++# define raw_printf fprintf
    ++#endif
    ++
      /*
    - ** Return true if a memory cell is not marked as invalid.  This macro
    -@@ -71138,6 +71142,11 @@ SQLITE_API sqlite_int64 SQLITE_STDCALL sqlite3_value_int64(sqlite3_value *pVal){
    - SQLITE_API unsigned int SQLITE_STDCALL sqlite3_value_subtype(sqlite3_value *pVal){
    -   return ((Mem*)pVal)->eSubtype;
    + ** Write I/O traces to the following stream.
    + */
    +@@ -375,11 +472,41 @@ static void SQLITE_CDECL iotracePrintf(const char *zFormat, ...){
    +   va_start(ap, zFormat);
    +   z = sqlite3_vmprintf(zFormat, ap);
    +   va_end(ap);
    +-  fprintf(iotrace, "%s", z);
    ++  utf8_printf(iotrace, "%s", z);
    +   sqlite3_free(z);
      }
    -+SQLITE_API void *SQLITE_STDCALL sqlite3_value_pointer(sqlite3_value *pVal){
    -+  Mem *p = (Mem*)pVal;
    -+  if( (p->flags&(MEM_TypeMask|MEM_Ptr))==(MEM_Null|MEM_Ptr) ) return p->u.pPtr;
    -+  return 0;
    + #endif
    + 
    ++/*
    ++** Output string zUtf to stream pOut as w characters.  If w is negative,
    ++** then right-justify the text.  W is the width in UTF-8 characters, not
    ++** in bytes.  This is different from the %*.*s specification in printf
    ++** since with %*.*s the width is measured in bytes, not characters.
    ++*/
    ++static void utf8_width_print(FILE *pOut, int w, const char *zUtf){
    ++  int i;
    ++  int n;
    ++  int aw = w<0 ? -w : w;
    ++  char zBuf[1000];
    ++  if( aw>(int)sizeof(zBuf)/3 ) aw = (int)sizeof(zBuf)/3;
    ++  for(i=n=0; zUtf[i]; i++){
    ++    if( (zUtf[i]&0xc0)!=0x80 ){
    ++      n++;
    ++      if( n==aw ){
    ++        do{ i++; }while( (zUtf[i]&0xc0)==0x80 );
    ++        break;
    ++      }
    ++    }
    ++  }
    ++  if( n>=aw ){
    ++    utf8_printf(pOut, "%.*s", i, zUtf);
    ++  }else if( w<0 ){
    ++    utf8_printf(pOut, "%*s%s", aw-n, "", zUtf);
    ++  }else{
    ++    utf8_printf(pOut, "%s%*s", zUtf, aw-n, "");
    ++  }
     +}
    - SQLITE_API const unsigned char *SQLITE_STDCALL sqlite3_value_text(sqlite3_value *pVal){
    -   return (const unsigned char *)sqlite3ValueText(pVal, SQLITE_UTF8);
    ++
    + 
    + /*
    + ** Determines if a string is a number of not.
    +@@ -409,26 +536,26 @@ static int isNumber(const char *z, int *realnum){
      }
    -@@ -71312,6 +71321,13 @@ SQLITE_API void SQLITE_STDCALL sqlite3_result_int64(sqlite3_context *pCtx, i64 i
    -   assert( sqlite3_mutex_held(pCtx->pOut->db->mutex) );
    -   sqlite3VdbeMemSetInt64(pCtx->pOut, iVal);
    + 
    + /*
    +-** A global char* and an SQL function to access its current value 
    +-** from within an SQL statement. This program used to use the 
    +-** sqlite_exec_printf() API to substitue a string into an SQL statement.
    +-** The correct way to do this with sqlite3 is to use the bind API, but
    +-** since the shell is built around the callback paradigm it would be a lot
    +-** of work. Instead just use this hack, which is quite harmless.
    ++** Compute a string length that is limited to what can be stored in
    ++** lower 30 bits of a 32-bit signed integer.
    + */
    +-static const char *zShellStatic = 0;
    +-static void shellstaticFunc(
    +-  sqlite3_context *context,
    +-  int argc,
    +-  sqlite3_value **argv
    +-){
    +-  assert( 0==argc );
    +-  assert( zShellStatic );
    +-  UNUSED_PARAMETER(argc);
    +-  UNUSED_PARAMETER(argv);
    +-  sqlite3_result_text(context, zShellStatic, -1, SQLITE_STATIC);
    ++static int strlen30(const char *z){
    ++  const char *z2 = z;
    ++  while( *z2 ){ z2++; }
    ++  return 0x3fffffff & (int)(z2 - z);
      }
    -+SQLITE_API void SQLITE_STDCALL sqlite3_result_pointer(sqlite3_context *pCtx, void *pPtr){
    -+  assert( sqlite3_mutex_held(pCtx->pOut->db->mutex) );
    -+  sqlite3VdbeMemSetNull(pCtx->pOut);
    -+  assert( (pCtx->pOut->flags & (MEM_TypeMask|MEM_Ptr))==MEM_Null );
    -+  pCtx->pOut->flags |= MEM_Ptr;
    -+  pCtx->pOut->u.pPtr = pPtr;
    + 
    ++/*
    ++** Return the length of a string in characters.  Multibyte UTF8 characters
    ++** count as a single character.
    ++*/
    ++static int strlenChar(const char *z){
    ++  int n = 0;
    ++  while( *z ){
    ++    if( (0xc0&*(z++))!=0x80 ) n++;
    ++  }
    ++  return n;
     +}
    - SQLITE_API void SQLITE_STDCALL sqlite3_result_null(sqlite3_context *pCtx){
    -   assert( sqlite3_mutex_held(pCtx->pOut->db->mutex) );
    -   sqlite3VdbeMemSetNull(pCtx->pOut);
    -@@ -139172,7 +139188,7 @@ static int fts3ColumnMethod(
    -   }else if( iCol==p->nColumn ){
    -     /* The extra column whose name is the same as the table.
    -     ** Return a blob which is a pointer to the cursor.  */
    --    sqlite3_result_blob(pCtx, &pCsr, sizeof(pCsr), SQLITE_TRANSIENT);
    -+    sqlite3_result_pointer(pCtx, pCsr);
    -   }else if( iCol==p->nColumn+2 && pCsr->pExpr ){
    -     sqlite3_result_int64(pCtx, pCsr->iLangid);
    -   }else{
    -@@ -139384,16 +139400,13 @@ static int fts3FunctionArg(
    -   sqlite3_value *pVal,            /* argv[0] passed to function */
    -   Fts3Cursor **ppCsr              /* OUT: Store cursor handle here */
    - ){
    --  Fts3Cursor *pRet;
    --  if( sqlite3_value_type(pVal)!=SQLITE_BLOB 
    --   || sqlite3_value_bytes(pVal)!=sizeof(Fts3Cursor *)
    --  ){
    -+  Fts3Cursor *pRet = (Fts3Cursor*)sqlite3_value_pointer(pVal);
    -+  if( pRet==0 ){
    -     char *zErr = sqlite3_mprintf("illegal first argument to %s", zFunc);
    -     sqlite3_result_error(pContext, zErr, -1);
    -     sqlite3_free(zErr);
    -     return SQLITE_ERROR;
    + 
    + /*
    + ** This routine reads a line of text from FILE in, stores
    +@@ -465,6 +592,25 @@ static char *local_getline(char *zLine, FILE *in){
    +       break;
    +     }
        }
    --  memcpy(&pRet, sqlite3_value_blob(pVal), sizeof(Fts3Cursor *));
    -   *ppCsr = pRet;
    -   return SQLITE_OK;
    ++#if defined(_WIN32) || defined(WIN32)
    ++  /* For interactive input on Windows systems, translate the
    ++  ** multi-byte characterset characters into UTF-8. */
    ++  if( stdin_is_interactive && in==stdin ){
    ++    char *zTrans = sqlite3_win32_mbcs_to_utf8_v2(zLine, 0);
    ++    if( zTrans ){
    ++      int nTrans = strlen30(zTrans)+1;
    ++      if( nTrans>nLine ){
    ++        zLine = realloc(zLine, nTrans);
    ++        if( zLine==0 ){
    ++          sqlite3_free(zTrans);
    ++          return 0;
    ++        }
    ++      }
    ++      memcpy(zLine, zTrans, nTrans);
    ++      sqlite3_free(zTrans);
    ++    }
    ++  }
    ++#endif /* defined(_WIN32) || defined(WIN32) */
    +   return zLine;
      }
    -@@ -180602,7 +180615,7 @@ static void fts5SourceIdFunc(
    -   sqlite3_value **apVal           /* Function arguments */
    - ){
    -   assert( nArg==0 );
    --  sqlite3_result_text(pCtx, "fts5: 2015-11-02 18:31:45 bda77dda9697c463c3d0704014d51627fceee328", -1, SQLITE_TRANSIENT);
    -+  sqlite3_result_text(pCtx, "fts5: 2017-07-21 07:45:23 69906880cee1f246cce494672402e0c7f29bd4ec19c437d26d603870d2bd625d", -1, SQLITE_TRANSIENT);
    + 
    +@@ -502,2132 +648,11635 @@ static char *one_input_line(FILE *in, char *zPrior, int isContinuation){
    +   return zResult;
      }
      
    - static int fts5Init(sqlite3 *db){
    -diff --git a/dist/orig/sqlite3.h b/dist/orig/sqlite3.h
    -index 7cca0ac..a0c0e4e 100644
    ---- a/dist/orig/sqlite3.h
    -+++ b/dist/orig/sqlite3.h
    -@@ -113,7 +113,7 @@ extern "C" {
    +-/*
    +-** Shell output mode information from before ".explain on", 
    +-** saved so that it can be restored by ".explain off"
    +-*/
    +-typedef struct SavedModeInfo SavedModeInfo;
    +-struct SavedModeInfo {
    +-  int valid;          /* Is there legit data in here? */
    +-  int mode;           /* Mode prior to ".explain on" */
    +-  int showHeader;     /* The ".header" setting prior to ".explain on" */
    +-  int colWidth[100];  /* Column widths prior to ".explain on" */
    +-};
    + 
    + /*
    +-** State information about the database connection is contained in an
    +-** instance of the following structure.
    ++** Return the value of a hexadecimal digit.  Return -1 if the input
    ++** is not a hex digit.
      */
    - #define SQLITE_VERSION        "3.9.2"
    - #define SQLITE_VERSION_NUMBER 3009002
    --#define SQLITE_SOURCE_ID      "2015-11-02 18:31:45 bda77dda9697c463c3d0704014d51627fceee328"
    -+#define SQLITE_SOURCE_ID      "2017-07-21 07:45:23 69906880cee1f246cce494672402e0c7f29bd4ec19c437d26d603870d2bd625d"
    +-typedef struct ShellState ShellState;
    +-struct ShellState {
    +-  sqlite3 *db;           /* The database */
    +-  int echoOn;            /* True to echo input commands */
    +-  int autoEQP;           /* Run EXPLAIN QUERY PLAN prior to seach SQL stmt */
    +-  int statsOn;           /* True to display memory stats before each finalize */
    +-  int scanstatsOn;       /* True to display scan stats before each finalize */
    +-  int backslashOn;       /* Resolve C-style \x escapes in SQL input text */
    +-  int outCount;          /* Revert to stdout when reaching zero */
    +-  int cnt;               /* Number of records displayed so far */
    +-  FILE *out;             /* Write results here */
    +-  FILE *traceOut;        /* Output for sqlite3_trace() */
    +-  int nErr;              /* Number of errors seen */
    +-  int mode;              /* An output mode setting */
    +-  int writableSchema;    /* True if PRAGMA writable_schema=ON */
    +-  int showHeader;        /* True to show column names in List or Column mode */
    +-  unsigned shellFlgs;    /* Various flags */
    +-  char *zDestTable;      /* Name of destination table when MODE_Insert */
    +-  char colSeparator[20]; /* Column separator character for several modes */
    +-  char rowSeparator[20]; /* Row separator character for MODE_Ascii */
    +-  int colWidth[100];     /* Requested width of each column when in column mode*/
    +-  int actualWidth[100];  /* Actual width of each column */
    +-  char nullValue[20];    /* The text to print when a NULL comes back from
    +-                         ** the database */
    +-  SavedModeInfo normalMode;/* Holds the mode just before .explain ON */
    +-  char outfile[FILENAME_MAX]; /* Filename for *out */
    +-  const char *zDbFilename;    /* name of the database file */
    +-  char *zFreeOnClose;         /* Filename to free when closing */
    +-  const char *zVfs;           /* Name of VFS to use */
    +-  sqlite3_stmt *pStmt;   /* Current statement if any. */
    +-  FILE *pLog;            /* Write log output here */
    +-  int *aiIndent;         /* Array of indents used in MODE_Explain */
    +-  int nIndent;           /* Size of array aiIndent[] */
    +-  int iIndent;           /* Index of current op in aiIndent[] */
    +-};
    ++static int hexDigitValue(char c){
    ++  if( c>='0' && c<='9' ) return c - '0';
    ++  if( c>='a' && c<='f' ) return c - 'a' + 10;
    ++  if( c>='A' && c<='F' ) return c - 'A' + 10;
    ++  return -1;
    ++}
      
      /*
    - ** CAPI3REF: Run-Time Library Version Numbers
    -@@ -4352,6 +4352,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_value_bytes16(sqlite3_value*);
    - SQLITE_API double SQLITE_STDCALL sqlite3_value_double(sqlite3_value*);
    - SQLITE_API int SQLITE_STDCALL sqlite3_value_int(sqlite3_value*);
    - SQLITE_API sqlite3_int64 SQLITE_STDCALL sqlite3_value_int64(sqlite3_value*);
    -+SQLITE_API void *SQLITE_STDCALL sqlite3_value_pointer(sqlite3_value*);
    - SQLITE_API const unsigned char *SQLITE_STDCALL sqlite3_value_text(sqlite3_value*);
    - SQLITE_API const void *SQLITE_STDCALL sqlite3_value_text16(sqlite3_value*);
    - SQLITE_API const void *SQLITE_STDCALL sqlite3_value_text16le(sqlite3_value*);
    -@@ -4664,6 +4665,7 @@ SQLITE_API void SQLITE_STDCALL sqlite3_result_error_code(sqlite3_context*, int);
    - SQLITE_API void SQLITE_STDCALL sqlite3_result_int(sqlite3_context*, int);
    - SQLITE_API void SQLITE_STDCALL sqlite3_result_int64(sqlite3_context*, sqlite3_int64);
    - SQLITE_API void SQLITE_STDCALL sqlite3_result_null(sqlite3_context*);
    -+SQLITE_API void SQLITE_STDCALL sqlite3_result_pointer(sqlite3_context*, void*);
    - SQLITE_API void SQLITE_STDCALL sqlite3_result_text(sqlite3_context*, const char*, int, void(*)(void*));
    - SQLITE_API void SQLITE_STDCALL sqlite3_result_text64(sqlite3_context*, const char*,sqlite3_uint64,
    -                            void(*)(void*), unsigned char encoding);
    -diff --git a/dist/sqlite3.c b/dist/sqlite3.c
    -index b0536a4..715b2f7 100644
    ---- a/dist/sqlite3.c
    -+++ b/dist/sqlite3.c
    -@@ -327,7 +327,7 @@ extern "C" {
    +-** These are the allowed shellFlgs values
    ++** Interpret zArg as an integer value, possibly with suffixes.
      */
    - #define SQLITE_VERSION        "3.9.2"
    - #define SQLITE_VERSION_NUMBER 3009002
    --#define SQLITE_SOURCE_ID      "2015-11-02 18:31:45 bda77dda9697c463c3d0704014d51627fceee328"
    -+#define SQLITE_SOURCE_ID      "2017-07-21 07:45:23 69906880cee1f246cce494672402e0c7f29bd4ec19c437d26d603870d2bd625d"
    +-#define SHFLG_Scratch     0x00001     /* The --scratch option is used */
    +-#define SHFLG_Pagecache   0x00002     /* The --pagecache option is used */
    +-#define SHFLG_Lookaside   0x00004     /* Lookaside memory is used */
    ++static sqlite3_int64 integerValue(const char *zArg){
    ++  sqlite3_int64 v = 0;
    ++  static const struct { char *zSuffix; int iMult; } aMult[] = {
    ++    { "KiB", 1024 },
    ++    { "MiB", 1024*1024 },
    ++    { "GiB", 1024*1024*1024 },
    ++    { "KB",  1000 },
    ++    { "MB",  1000000 },
    ++    { "GB",  1000000000 },
    ++    { "K",   1000 },
    ++    { "M",   1000000 },
    ++    { "G",   1000000000 },
    ++  };
    ++  int i;
    ++  int isNeg = 0;
    ++  if( zArg[0]=='-' ){
    ++    isNeg = 1;
    ++    zArg++;
    ++  }else if( zArg[0]=='+' ){
    ++    zArg++;
    ++  }
    ++  if( zArg[0]=='0' && zArg[1]=='x' ){
    ++    int x;
    ++    zArg += 2;
    ++    while( (x = hexDigitValue(zArg[0]))>=0 ){
    ++      v = (v<<4) + x;
    ++      zArg++;
    ++    }
    ++  }else{
    ++    while( IsDigit(zArg[0]) ){
    ++      v = v*10 + zArg[0] - '0';
    ++      zArg++;
    ++    }
    ++  }
    ++  for(i=0; i<ArraySize(aMult); i++){
    ++    if( sqlite3_stricmp(aMult[i].zSuffix, zArg)==0 ){
    ++      v *= aMult[i].iMult;
    ++      break;
    ++    }
    ++  }
    ++  return isNeg? -v : v;
    ++}
      
      /*
    - ** CAPI3REF: Run-Time Library Version Numbers
    -@@ -4566,6 +4566,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_value_bytes16(sqlite3_value*);
    - SQLITE_API double SQLITE_STDCALL sqlite3_value_double(sqlite3_value*);
    - SQLITE_API int SQLITE_STDCALL sqlite3_value_int(sqlite3_value*);
    - SQLITE_API sqlite3_int64 SQLITE_STDCALL sqlite3_value_int64(sqlite3_value*);
    -+SQLITE_API void *SQLITE_STDCALL sqlite3_value_pointer(sqlite3_value*);
    - SQLITE_API const unsigned char *SQLITE_STDCALL sqlite3_value_text(sqlite3_value*);
    - SQLITE_API const void *SQLITE_STDCALL sqlite3_value_text16(sqlite3_value*);
    - SQLITE_API const void *SQLITE_STDCALL sqlite3_value_text16le(sqlite3_value*);
    -@@ -4878,6 +4879,7 @@ SQLITE_API void SQLITE_STDCALL sqlite3_result_error_code(sqlite3_context*, int);
    - SQLITE_API void SQLITE_STDCALL sqlite3_result_int(sqlite3_context*, int);
    - SQLITE_API void SQLITE_STDCALL sqlite3_result_int64(sqlite3_context*, sqlite3_int64);
    - SQLITE_API void SQLITE_STDCALL sqlite3_result_null(sqlite3_context*);
    -+SQLITE_API void SQLITE_STDCALL sqlite3_result_pointer(sqlite3_context*, void*);
    - SQLITE_API void SQLITE_STDCALL sqlite3_result_text(sqlite3_context*, const char*, int, void(*)(void*));
    - SQLITE_API void SQLITE_STDCALL sqlite3_result_text64(sqlite3_context*, const char*,sqlite3_uint64,
    -                            void(*)(void*), unsigned char encoding);
    -@@ -15415,6 +15417,7 @@ struct Mem {
    -     double r;           /* Real value used when MEM_Real is set in flags */
    -     i64 i;              /* Integer value used when MEM_Int is set in flags */
    -     int nZero;          /* Used when bit MEM_Zero is set in flags */
    -+    void *pPtr;         /* Pointer when flags==MEM_Ptr|MEM_Null */
    -     FuncDef *pDef;      /* Used only when flags==MEM_Agg */
    -     RowSet *pRowSet;    /* Used only when flags==MEM_RowSet */
    -     VdbeFrame *pFrame;  /* Used when flags==MEM_Frame */
    -@@ -15472,6 +15475,7 @@ struct Mem {
    - ** policy for Mem.z.  The MEM_Term flag tells us whether or not the
    - ** string is \000 or \u0000 terminated
    +-** These are the allowed modes.
    ++** A variable length string to which one can append text.
      */
    -+#define MEM_Ptr       0x8000   /* u.pPtr is valid if type==SQLITE_NULL */
    - #define MEM_Term      0x0200   /* String rep is nul terminated */
    - #define MEM_Dyn       0x0400   /* Need to call Mem.xDel() on Mem.z */
    - #define MEM_Static    0x0800   /* Mem.z points to a static string */
    -@@ -15487,7 +15491,7 @@ struct Mem {
    - ** Clear any existing type flags from a Mem and replace them with f
    +-#define MODE_Line     0  /* One column per line.  Blank line between records */
    +-#define MODE_Column   1  /* One record per line in neat columns */
    +-#define MODE_List     2  /* One record per line with a separator */
    +-#define MODE_Semi     3  /* Same as MODE_List but append ";" to each line */
    +-#define MODE_Html     4  /* Generate an XHTML table */
    +-#define MODE_Insert   5  /* Generate SQL "insert" statements */
    +-#define MODE_Tcl      6  /* Generate ANSI-C or TCL quoted elements */
    +-#define MODE_Csv      7  /* Quote strings, numbers are plain */
    +-#define MODE_Explain  8  /* Like MODE_Column, but do not truncate data */
    +-#define MODE_Ascii    9  /* Use ASCII unit and record separators (0x1F/0x1E) */
    +-
    +-static const char *modeDescr[] = {
    +-  "line",
    +-  "column",
    +-  "list",
    +-  "semi",
    +-  "html",
    +-  "insert",
    +-  "tcl",
    +-  "csv",
    +-  "explain",
    +-  "ascii",
    ++typedef struct ShellText ShellText;
    ++struct ShellText {
    ++  char *z;
    ++  int n;
    ++  int nAlloc;
    + };
    + 
    + /*
    +-** These are the column/row/line separators used by the various
    +-** import/export modes.
    ++** Initialize and destroy a ShellText object
    + */
    +-#define SEP_Column    "|"
    +-#define SEP_Row       "\n"
    +-#define SEP_Tab       "\t"
    +-#define SEP_Space     " "
    +-#define SEP_Comma     ","
    +-#define SEP_CrLf      "\r\n"
    +-#define SEP_Unit      "\x1F"
    +-#define SEP_Record    "\x1E"
    ++static void initText(ShellText *p){
    ++  memset(p, 0, sizeof(*p));
    ++}
    ++static void freeText(ShellText *p){
    ++  free(p->z);
    ++  initText(p);
    ++}
    + 
    +-/*
    +-** Number of elements in an array
    ++/* zIn is either a pointer to a NULL-terminated string in memory obtained
    ++** from malloc(), or a NULL pointer. The string pointed to by zAppend is
    ++** added to zIn, and the result returned in memory obtained from malloc().
    ++** zIn, if it was not NULL, is freed.
    ++**
    ++** If the third argument, quote, is not '\0', then it is used as a
    ++** quote character for zAppend.
    + */
    +-#define ArraySize(X)  (int)(sizeof(X)/sizeof(X[0]))
    ++static void appendText(ShellText *p, char const *zAppend, char quote){
    ++  int len;
    ++  int i;
    ++  int nAppend = strlen30(zAppend);
    ++
    ++  len = nAppend+p->n+1;
    ++  if( quote ){
    ++    len += 2;
    ++    for(i=0; i<nAppend; i++){
    ++      if( zAppend[i]==quote ) len++;
    ++    }
    ++  }
    ++
    ++  if( p->n+len>=p->nAlloc ){
    ++    p->nAlloc = p->nAlloc*2 + len + 20;
    ++    p->z = realloc(p->z, p->nAlloc);
    ++    if( p->z==0 ){
    ++      memset(p, 0, sizeof(*p));
    ++      return;
    ++    }
    ++  }
    ++
    ++  if( quote ){
    ++    char *zCsr = p->z+p->n;
    ++    *zCsr++ = quote;
    ++    for(i=0; i<nAppend; i++){
    ++      *zCsr++ = zAppend[i];
    ++      if( zAppend[i]==quote ) *zCsr++ = quote;
    ++    }
    ++    *zCsr++ = quote;
    ++    p->n = (int)(zCsr - p->z);
    ++    *zCsr = '\0';
    ++  }else{
    ++    memcpy(p->z+p->n, zAppend, nAppend);
    ++    p->n += nAppend;
    ++    p->z[p->n] = '\0';
    ++  }
    ++}
    + 
    + /*
    +-** Compute a string length that is limited to what can be stored in
    +-** lower 30 bits of a 32-bit signed integer.
    ++** Attempt to determine if identifier zName needs to be quoted, either
    ++** because it contains non-alphanumeric characters, or because it is an
    ++** SQLite keyword.  Be conservative in this estimate:  When in doubt assume
    ++** that quoting is required.
    ++**
    ++** Return '"' if quoting is required.  Return 0 if no quoting is required.
      */
    - #define MemSetTypeFlag(p, f) \
    --   ((p)->flags = ((p)->flags&~(MEM_TypeMask|MEM_Zero))|f)
    -+   ((p)->flags = ((p)->flags&~(MEM_TypeMask|MEM_Zero|MEM_Ptr))|f)
    +-static int strlen30(const char *z){
    +-  const char *z2 = z;
    +-  while( *z2 ){ z2++; }
    +-  return 0x3fffffff & (int)(z2 - z);
    ++static char quoteChar(const char *zName){
    ++  /* All SQLite keywords, in alphabetical order */
    ++  static const char *azKeywords[] = {
    ++    "ABORT", "ACTION", "ADD", "AFTER", "ALL", "ALTER", "ANALYZE", "AND", "AS",
    ++    "ASC", "ATTACH", "AUTOINCREMENT", "BEFORE", "BEGIN", "BETWEEN", "BY",
    ++    "CASCADE", "CASE", "CAST", "CHECK", "COLLATE", "COLUMN", "COMMIT",
    ++    "CONFLICT", "CONSTRAINT", "CREATE", "CROSS", "CURRENT_DATE",
    ++    "CURRENT_TIME", "CURRENT_TIMESTAMP", "DATABASE", "DEFAULT", "DEFERRABLE",
    ++    "DEFERRED", "DELETE", "DESC", "DETACH", "DISTINCT", "DROP", "EACH",
    ++    "ELSE", "END", "ESCAPE", "EXCEPT", "EXCLUSIVE", "EXISTS", "EXPLAIN",
    ++    "FAIL", "FOR", "FOREIGN", "FROM", "FULL", "GLOB", "GROUP", "HAVING", "IF",
    ++    "IGNORE", "IMMEDIATE", "IN", "INDEX", "INDEXED", "INITIALLY", "INNER",
    ++    "INSERT", "INSTEAD", "INTERSECT", "INTO", "IS", "ISNULL", "JOIN", "KEY",
    ++    "LEFT", "LIKE", "LIMIT", "MATCH", "NATURAL", "NO", "NOT", "NOTNULL",
    ++    "NULL", "OF", "OFFSET", "ON", "OR", "ORDER", "OUTER", "PLAN", "PRAGMA",
    ++    "PRIMARY", "QUERY", "RAISE", "RECURSIVE", "REFERENCES", "REGEXP",
    ++    "REINDEX", "RELEASE", "RENAME", "REPLACE", "RESTRICT", "RIGHT",
    ++    "ROLLBACK", "ROW", "SAVEPOINT", "SELECT", "SET", "TABLE", "TEMP",
    ++    "TEMPORARY", "THEN", "TO", "TRANSACTION", "TRIGGER", "UNION", "UNIQUE",
    ++    "UPDATE", "USING", "VACUUM", "VALUES", "VIEW", "VIRTUAL", "WHEN", "WHERE",
    ++    "WITH", "WITHOUT",
    ++  };
    ++  int i, lwr, upr, mid, c;
    ++  if( !isalpha((unsigned char)zName[0]) && zName[0]!='_' ) return '"';
    ++  for(i=0; zName[i]; i++){
    ++    if( !isalnum((unsigned char)zName[i]) && zName[i]!='_' ) return '"';
    ++  }
    ++  lwr = 0;
    ++  upr = sizeof(azKeywords)/sizeof(azKeywords[0]) - 1;
    ++  while( lwr<=upr ){
    ++    mid = (lwr+upr)/2;
    ++    c = sqlite3_stricmp(azKeywords[mid], zName);
    ++    if( c==0 ) return '"';
    ++    if( c<0 ){
    ++      lwr = mid+1;
    ++    }else{
    ++      upr = mid-1;
    ++    }
    ++  }
    ++  return 0;
    + }
      
      /*
    - ** Return true if a memory cell is not marked as invalid.  This macro
    -@@ -71156,6 +71160,11 @@ SQLITE_API sqlite_int64 SQLITE_STDCALL sqlite3_value_int64(sqlite3_value *pVal){
    - SQLITE_API unsigned int SQLITE_STDCALL sqlite3_value_subtype(sqlite3_value *pVal){
    -   return ((Mem*)pVal)->eSubtype;
    +-** A callback for the sqlite3_log() interface.
    ++** Construct a fake object name and column list to describe the structure
    ++** of the view, virtual table, or table valued function zSchema.zName.
    + */
    +-static void shellLog(void *pArg, int iErrCode, const char *zMsg){
    +-  ShellState *p = (ShellState*)pArg;
    +-  if( p->pLog==0 ) return;
    +-  fprintf(p->pLog, "(%d) %s\n", iErrCode, zMsg);
    +-  fflush(p->pLog);
    ++static char *shellFakeSchema(
    ++  sqlite3 *db,            /* The database connection containing the vtab */
    ++  const char *zSchema,    /* Schema of the database holding the vtab */
    ++  const char *zName       /* The name of the virtual table */
    ++){
    ++  sqlite3_stmt *pStmt = 0;
    ++  char *zSql;
    ++  ShellText s;
    ++  char cQuote;
    ++  char *zDiv = "(";
    ++  int nRow = 0;
    ++
    ++  zSql = sqlite3_mprintf("PRAGMA \"%w\".table_info=%Q;",
    ++                         zSchema ? zSchema : "main", zName);
    ++  sqlite3_prepare_v2(db, zSql, -1, &pStmt, 0);
    ++  sqlite3_free(zSql);
    ++  initText(&s);
    ++  if( zSchema ){
    ++    cQuote = quoteChar(zSchema);
    ++    if( cQuote && sqlite3_stricmp(zSchema,"temp")==0 ) cQuote = 0;
    ++    appendText(&s, zSchema, cQuote);
    ++    appendText(&s, ".", 0);
    ++  }
    ++  cQuote = quoteChar(zName);
    ++  appendText(&s, zName, cQuote);
    ++  while( sqlite3_step(pStmt)==SQLITE_ROW ){
    ++    const char *zCol = (const char*)sqlite3_column_text(pStmt, 1);
    ++    nRow++;
    ++    appendText(&s, zDiv, 0);
    ++    zDiv = ",";
    ++    cQuote = quoteChar(zCol);
    ++    appendText(&s, zCol, cQuote);
    ++  }
    ++  appendText(&s, ")", 0);
    ++  sqlite3_finalize(pStmt);
    ++  if( nRow==0 ){
    ++    freeText(&s);
    ++    s.z = 0;
    ++  }
    ++  return s.z;
      }
    -+SQLITE_API void *SQLITE_STDCALL sqlite3_value_pointer(sqlite3_value *pVal){
    -+  Mem *p = (Mem*)pVal;
    -+  if( (p->flags&(MEM_TypeMask|MEM_Ptr))==(MEM_Null|MEM_Ptr) ) return p->u.pPtr;
    -+  return 0;
    + 
    + /*
    +-** Output the given string as a hex-encoded blob (eg. X'1234' )
    ++** SQL function:  shell_module_schema(X)
    ++**
    ++** Return a fake schema for the table-valued function or eponymous virtual
    ++** table X.
    + */
    +-static void output_hex_blob(FILE *out, const void *pBlob, int nBlob){
    +-  int i;
    +-  char *zBlob = (char *)pBlob;
    +-  fprintf(out,"X'");
    +-  for(i=0; i<nBlob; i++){ fprintf(out,"%02x",zBlob[i]&0xff); }
    +-  fprintf(out,"'");
    ++static void shellModuleSchema(
    ++  sqlite3_context *pCtx,
    ++  int nVal,
    ++  sqlite3_value **apVal
    ++){
    ++  const char *zName = (const char*)sqlite3_value_text(apVal[0]);
    ++  char *zFake = shellFakeSchema(sqlite3_context_db_handle(pCtx), 0, zName);
    ++  UNUSED_PARAMETER(nVal);
    ++  if( zFake ){
    ++    sqlite3_result_text(pCtx, sqlite3_mprintf("/* %s */", zFake),
    ++                        -1, sqlite3_free);
    ++    free(zFake);
    ++  }
    + }
    + 
    + /*
    +-** Output the given string as a quoted string using SQL quoting conventions.
    ++** SQL function:  shell_add_schema(S,X)
    ++**
    ++** Add the schema name X to the CREATE statement in S and return the result.
    ++** Examples:
    ++**
    ++**    CREATE TABLE t1(x)   ->   CREATE TABLE xyz.t1(x);
    ++**
    ++** Also works on
    ++**
    ++**    CREATE INDEX
    ++**    CREATE UNIQUE INDEX
    ++**    CREATE VIEW
    ++**    CREATE TRIGGER
    ++**    CREATE VIRTUAL TABLE
    ++**
    ++** This UDF is used by the .schema command to insert the schema name of
    ++** attached databases into the middle of the sqlite_master.sql field.
    + */
    +-static void output_quoted_string(FILE *out, const char *z){
    +-  int i;
    +-  int nSingle = 0;
    +-  setBinaryMode(out);
    +-  for(i=0; z[i]; i++){
    +-    if( z[i]=='\'' ) nSingle++;
    +-  }
    +-  if( nSingle==0 ){
    +-    fprintf(out,"'%s'",z);
    +-  }else{
    +-    fprintf(out,"'");
    +-    while( *z ){
    +-      for(i=0; z[i] && z[i]!='\''; i++){}
    +-      if( i==0 ){
    +-        fprintf(out,"''");
    +-        z++;
    +-      }else if( z[i]=='\'' ){
    +-        fprintf(out,"%.*s''",i,z);
    +-        z += i+1;
    +-      }else{
    +-        fprintf(out,"%s",z);
    +-        break;
    ++static void shellAddSchemaName(
    ++  sqlite3_context *pCtx,
    ++  int nVal,
    ++  sqlite3_value **apVal
    ++){
    ++  static const char *aPrefix[] = {
    ++     "TABLE",
    ++     "INDEX",
    ++     "UNIQUE INDEX",
    ++     "VIEW",
    ++     "TRIGGER",
    ++     "VIRTUAL TABLE"
    ++  };
    ++  int i = 0;
    ++  const char *zIn = (const char*)sqlite3_value_text(apVal[0]);
    ++  const char *zSchema = (const char*)sqlite3_value_text(apVal[1]);
    ++  const char *zName = (const char*)sqlite3_value_text(apVal[2]);
    ++  sqlite3 *db = sqlite3_context_db_handle(pCtx);
    ++  UNUSED_PARAMETER(nVal);
    ++  if( zIn!=0 && strncmp(zIn, "CREATE ", 7)==0 ){
    ++    for(i=0; i<(int)(sizeof(aPrefix)/sizeof(aPrefix[0])); i++){
    ++      int n = strlen30(aPrefix[i]);
    ++      if( strncmp(zIn+7, aPrefix[i], n)==0 && zIn[n+7]==' ' ){
    ++        char *z = 0;
    ++        char *zFake = 0;
    ++        if( zSchema ){
    ++          char cQuote = quoteChar(zSchema);
    ++          if( cQuote && sqlite3_stricmp(zSchema,"temp")!=0 ){
    ++            z = sqlite3_mprintf("%.*s \"%w\".%s", n+7, zIn, zSchema, zIn+n+8);
    ++          }else{
    ++            z = sqlite3_mprintf("%.*s %s.%s", n+7, zIn, zSchema, zIn+n+8);
    ++          }
    ++        }
    ++        if( zName
    ++         && aPrefix[i][0]=='V'
    ++         && (zFake = shellFakeSchema(db, zSchema, zName))!=0
    ++        ){
    ++          if( z==0 ){
    ++            z = sqlite3_mprintf("%s\n/* %s */", zIn, zFake);
    ++          }else{
    ++            z = sqlite3_mprintf("%z\n/* %s */", z, zFake);
    ++          }
    ++          free(zFake);
    ++        }
    ++        if( z ){
    ++          sqlite3_result_text(pCtx, z, -1, sqlite3_free);
    ++          return;
    ++        }
    +       }
    +     }
    +-    fprintf(out,"'");
    +   }
    +-  setTextMode(out);
    ++  sqlite3_result_value(pCtx, apVal[0]);
    + }
    + 
    + /*
    +-** Output the given string as a quoted according to C or TCL quoting rules.
    ++** The source code for several run-time loadable extensions is inserted
    ++** below by the ../tool/mkshellc.tcl script.  Before processing that included
    ++** code, we need to override some macros to make the included program code
    ++** work here in the middle of this regular program.
    + */
    +-static void output_c_string(FILE *out, const char *z){
    +-  unsigned int c;
    +-  fputc('"', out);
    +-  while( (c = *(z++))!=0 ){
    +-    if( c=='\\' ){
    +-      fputc(c, out);
    +-      fputc(c, out);
    +-    }else if( c=='"' ){
    +-      fputc('\\', out);
    +-      fputc('"', out);
    +-    }else if( c=='\t' ){
    +-      fputc('\\', out);
    +-      fputc('t', out);
    +-    }else if( c=='\n' ){
    +-      fputc('\\', out);
    +-      fputc('n', out);
    +-    }else if( c=='\r' ){
    +-      fputc('\\', out);
    +-      fputc('r', out);
    +-    }else if( !isprint(c&0xff) ){
    +-      fprintf(out, "\\%03o", c&0xff);
    +-    }else{
    +-      fputc(c, out);
    +-    }
    +-  }
    +-  fputc('"', out);
    +-}
    ++#define SQLITE_EXTENSION_INIT1
    ++#define SQLITE_EXTENSION_INIT2(X) (void)(X)
    + 
    ++#if defined(_WIN32) && defined(_MSC_VER)
    ++/************************* Begin test_windirent.h ******************/
    + /*
    +-** Output the given string with characters that are special to
    +-** HTML escaped.
    ++** 2015 November 30
    ++**
    ++** 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 declarations for most of the opendir() family of
    ++** POSIX functions on Win32 using the MSVCRT.
    + */
    +-static void output_html_string(FILE *out, const char *z){
    +-  int i;
    +-  if( z==0 ) z = "";
    +-  while( *z ){
    +-    for(i=0;   z[i] 
    +-            && z[i]!='<' 
    +-            && z[i]!='&' 
    +-            && z[i]!='>' 
    +-            && z[i]!='\"' 
    +-            && z[i]!='\'';
    +-        i++){}
    +-    if( i>0 ){
    +-      fprintf(out,"%.*s",i,z);
    +-    }
    +-    if( z[i]=='<' ){
    +-      fprintf(out,"&lt;");
    +-    }else if( z[i]=='&' ){
    +-      fprintf(out,"&amp;");
    +-    }else if( z[i]=='>' ){
    +-      fprintf(out,"&gt;");
    +-    }else if( z[i]=='\"' ){
    +-      fprintf(out,"&quot;");
    +-    }else if( z[i]=='\'' ){
    +-      fprintf(out,"&#39;");
    +-    }else{
    +-      break;
    +-    }
    +-    z += i + 1;
    +-  }
    +-}
    ++
    ++#if defined(_WIN32) && defined(_MSC_VER) && !defined(SQLITE_WINDIRENT_H)
    ++#define SQLITE_WINDIRENT_H
    + 
    + /*
    +-** If a field contains any character identified by a 1 in the following
    +-** array, then the string must be quoted for CSV.
    ++** We need several data types from the Windows SDK header.
    + */
    +-static const char needCsvQuote[] = {
    +-  1, 1, 1, 1, 1, 1, 1, 1,   1, 1, 1, 1, 1, 1, 1, 1,   
    +-  1, 1, 1, 1, 1, 1, 1, 1,   1, 1, 1, 1, 1, 1, 1, 1,   
    +-  1, 0, 1, 0, 0, 0, 0, 1,   0, 0, 0, 0, 0, 0, 0, 0, 
    +-  0, 0, 0, 0, 0, 0, 0, 0,   0, 0, 0, 0, 0, 0, 0, 0, 
    +-  0, 0, 0, 0, 0, 0, 0, 0,   0, 0, 0, 0, 0, 0, 0, 0, 
    +-  0, 0, 0, 0, 0, 0, 0, 0,   0, 0, 0, 0, 0, 0, 0, 0, 
    +-  0, 0, 0, 0, 0, 0, 0, 0,   0, 0, 0, 0, 0, 0, 0, 0, 
    +-  0, 0, 0, 0, 0, 0, 0, 0,   0, 0, 0, 0, 0, 0, 0, 1, 
    +-  1, 1, 1, 1, 1, 1, 1, 1,   1, 1, 1, 1, 1, 1, 1, 1,   
    +-  1, 1, 1, 1, 1, 1, 1, 1,   1, 1, 1, 1, 1, 1, 1, 1,   
    +-  1, 1, 1, 1, 1, 1, 1, 1,   1, 1, 1, 1, 1, 1, 1, 1,   
    +-  1, 1, 1, 1, 1, 1, 1, 1,   1, 1, 1, 1, 1, 1, 1, 1,   
    +-  1, 1, 1, 1, 1, 1, 1, 1,   1, 1, 1, 1, 1, 1, 1, 1,   
    +-  1, 1, 1, 1, 1, 1, 1, 1,   1, 1, 1, 1, 1, 1, 1, 1,   
    +-  1, 1, 1, 1, 1, 1, 1, 1,   1, 1, 1, 1, 1, 1, 1, 1,   
    +-  1, 1, 1, 1, 1, 1, 1, 1,   1, 1, 1, 1, 1, 1, 1, 1,   
    ++
    ++#define WIN32_LEAN_AND_MEAN
    ++#include "windows.h"
    ++
    ++/*
    ++** We need several support functions from the SQLite core.
    ++*/
    ++
    ++
    ++/*
    ++** We need several things from the ANSI and MSVCRT headers.
    ++*/
    ++
    ++#include <stdio.h>
    ++#include <stdlib.h>
    ++#include <errno.h>
    ++#include <io.h>
    ++#include <limits.h>
    ++#include <sys/types.h>
    ++#include <sys/stat.h>
    ++
    ++/*
    ++** We may need several defines that should have been in "sys/stat.h".
    ++*/
    ++
    ++#ifndef S_ISREG
    ++#define S_ISREG(mode) (((mode) & S_IFMT) == S_IFREG)
    ++#endif
    ++
    ++#ifndef S_ISDIR
    ++#define S_ISDIR(mode) (((mode) & S_IFMT) == S_IFDIR)
    ++#endif
    ++
    ++#ifndef S_ISLNK
    ++#define S_ISLNK(mode) (0)
    ++#endif
    ++
    ++/*
    ++** We may need to provide the "mode_t" type.
    ++*/
    ++
    ++#ifndef MODE_T_DEFINED
    ++  #define MODE_T_DEFINED
    ++  typedef unsigned short mode_t;
    ++#endif
    ++
    ++/*
    ++** We may need to provide the "ino_t" type.
    ++*/
    ++
    ++#ifndef INO_T_DEFINED
    ++  #define INO_T_DEFINED
    ++  typedef unsigned short ino_t;
    ++#endif
    ++
    ++/*
    ++** We need to define "NAME_MAX" if it was not present in "limits.h".
    ++*/
    ++
    ++#ifndef NAME_MAX
    ++#  ifdef FILENAME_MAX
    ++#    define NAME_MAX (FILENAME_MAX)
    ++#  else
    ++#    define NAME_MAX (260)
    ++#  endif
    ++#endif
    ++
    ++/*
    ++** We need to define "NULL_INTPTR_T" and "BAD_INTPTR_T".
    ++*/
    ++
    ++#ifndef NULL_INTPTR_T
    ++#  define NULL_INTPTR_T ((intptr_t)(0))
    ++#endif
    ++
    ++#ifndef BAD_INTPTR_T
    ++#  define BAD_INTPTR_T ((intptr_t)(-1))
    ++#endif
    ++
    ++/*
    ++** We need to provide the necessary structures and related types.
    ++*/
    ++
    ++#ifndef DIRENT_DEFINED
    ++#define DIRENT_DEFINED
    ++typedef struct DIRENT DIRENT;
    ++typedef DIRENT *LPDIRENT;
    ++struct DIRENT {
    ++  ino_t d_ino;               /* Sequence number, do not use. */
    ++  unsigned d_attributes;     /* Win32 file attributes. */
    ++  char d_name[NAME_MAX + 1]; /* Name within the directory. */
    + };
    ++#endif
    ++
    ++#ifndef DIR_DEFINED
    ++#define DIR_DEFINED
    ++typedef struct DIR DIR;
    ++typedef DIR *LPDIR;
    ++struct DIR {
    ++  intptr_t d_handle; /* Value returned by "_findfirst". */
    ++  DIRENT d_first;    /* DIRENT constructed based on "_findfirst". */
    ++  DIRENT d_next;     /* DIRENT constructed based on "_findnext". */
    ++};
    ++#endif
    + 
    + /*
    +-** Output a single term of CSV.  Actually, p->colSeparator is used for
    +-** the separator, which may or may not be a comma.  p->nullValue is
    +-** the null value.  Strings are quoted if necessary.  The separator
    +-** is only issued if bSep is true.
    ++** Provide a macro, for use by the implementation, to determine if a
    ++** particular directory entry should be skipped over when searching for
    ++** the next directory entry that should be returned by the readdir() or
    ++** readdir_r() functions.
    + */
    +-static void output_csv(ShellState *p, const char *z, int bSep){
    +-  FILE *out = p->out;
    +-  if( z==0 ){
    +-    fprintf(out,"%s",p->nullValue);
    ++
    ++#ifndef is_filtered
    ++#  define is_filtered(a) ((((a).attrib)&_A_HIDDEN) || (((a).attrib)&_A_SYSTEM))
    ++#endif
    ++
    ++/*
    ++** Provide the function prototype for the POSIX compatiable getenv()
    ++** function.  This function is not thread-safe.
    ++*/
    ++
    ++extern const char *windirent_getenv(const char *name);
    ++
    ++/*
    ++** Finally, we can provide the function prototypes for the opendir(),
    ++** readdir(), readdir_r(), and closedir() POSIX functions.
    ++*/
    ++
    ++extern LPDIR opendir(const char *dirname);
    ++extern LPDIRENT readdir(LPDIR dirp);
    ++extern INT readdir_r(LPDIR dirp, LPDIRENT entry, LPDIRENT *result);
    ++extern INT closedir(LPDIR dirp);
    ++
    ++#endif /* defined(WIN32) && defined(_MSC_VER) */
    ++
    ++/************************* End test_windirent.h ********************/
    ++/************************* Begin test_windirent.c ******************/
    ++/*
    ++** 2015 November 30
    ++**
    ++** 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 to implement most of the opendir() family of
    ++** POSIX functions on Win32 using the MSVCRT.
    ++*/
    ++
    ++#if defined(_WIN32) && defined(_MSC_VER)
    ++/* #include "test_windirent.h" */
    ++
    ++/*
    ++** Implementation of the POSIX getenv() function using the Win32 API.
    ++** This function is not thread-safe.
    ++*/
    ++const char *windirent_getenv(
    ++  const char *name
    ++){
    ++  static char value[32768]; /* Maximum length, per MSDN */
    ++  DWORD dwSize = sizeof(value) / sizeof(char); /* Size in chars */
    ++  DWORD dwRet; /* Value returned by GetEnvironmentVariableA() */
    ++
    ++  memset(value, 0, sizeof(value));
    ++  dwRet = GetEnvironmentVariableA(name, value, dwSize);
    ++  if( dwRet==0 || dwRet>dwSize ){
    ++    /*
    ++    ** The function call to GetEnvironmentVariableA() failed -OR-
    ++    ** the buffer is not large enough.  Either way, return NULL.
    ++    */
    ++    return 0;
    +   }else{
    +-    int i;
    +-    int nSep = strlen30(p->colSeparator);
    +-    for(i=0; z[i]; i++){
    +-      if( needCsvQuote[((unsigned char*)z)[i]] 
    +-         || (z[i]==p->colSeparator[0] && 
    +-             (nSep==1 || memcmp(z, p->colSeparator, nSep)==0)) ){
    +-        i = 0;
    +-        break;
    +-      }
    +-    }
    +-    if( i==0 ){
    +-      putc('"', out);
    +-      for(i=0; z[i]; i++){
    +-        if( z[i]=='"' ) putc('"', out);
    +-        putc(z[i], out);
    +-      }
    +-      putc('"', out);
    +-    }else{
    +-      fprintf(out, "%s", z);
    ++    /*
    ++    ** The function call to GetEnvironmentVariableA() succeeded
    ++    ** -AND- the buffer contains the entire value.
    ++    */
    ++    return value;
    ++  }
     +}
    - SQLITE_API const unsigned char *SQLITE_STDCALL sqlite3_value_text(sqlite3_value *pVal){
    -   return (const unsigned char *)sqlite3ValueText(pVal, SQLITE_UTF8);
    ++
    ++/*
    ++** Implementation of the POSIX opendir() function using the MSVCRT.
    ++*/
    ++LPDIR opendir(
    ++  const char *dirname
    ++){
    ++  struct _finddata_t data;
    ++  LPDIR dirp = (LPDIR)sqlite3_malloc(sizeof(DIR));
    ++  SIZE_T namesize = sizeof(data.name) / sizeof(data.name[0]);
    ++
    ++  if( dirp==NULL ) return NULL;
    ++  memset(dirp, 0, sizeof(DIR));
    ++
    ++  /* TODO: Remove this if Unix-style root paths are not used. */
    ++  if( sqlite3_stricmp(dirname, "/")==0 ){
    ++    dirname = windirent_getenv("SystemDrive");
    ++  }
    ++
    ++  memset(&data, 0, sizeof(struct _finddata_t));
    ++  _snprintf(data.name, namesize, "%s\\*", dirname);
    ++  dirp->d_handle = _findfirst(data.name, &data);
    ++
    ++  if( dirp->d_handle==BAD_INTPTR_T ){
    ++    closedir(dirp);
    ++    return NULL;
    ++  }
    ++
    ++  /* TODO: Remove this block to allow hidden and/or system files. */
    ++  if( is_filtered(data) ){
    ++next:
    ++
    ++    memset(&data, 0, sizeof(struct _finddata_t));
    ++    if( _findnext(dirp->d_handle, &data)==-1 ){
    ++      closedir(dirp);
    ++      return NULL;
    +     }
    ++
    ++    /* TODO: Remove this block to allow hidden and/or system files. */
    ++    if( is_filtered(data) ) goto next;
    +   }
    +-  if( bSep ){
    +-    fprintf(p->out, "%s", p->colSeparator);
    ++
    ++  dirp->d_first.d_attributes = data.attrib;
    ++  strncpy(dirp->d_first.d_name, data.name, NAME_MAX);
    ++  dirp->d_first.d_name[NAME_MAX] = '\0';
    ++
    ++  return dirp;
    ++}
    ++
    ++/*
    ++** Implementation of the POSIX readdir() function using the MSVCRT.
    ++*/
    ++LPDIRENT readdir(
    ++  LPDIR dirp
    ++){
    ++  struct _finddata_t data;
    ++
    ++  if( dirp==NULL ) return NULL;
    ++
    ++  if( dirp->d_first.d_ino==0 ){
    ++    dirp->d_first.d_ino++;
    ++    dirp->d_next.d_ino++;
    ++
    ++    return &dirp->d_first;
    +   }
    ++
    ++next:
    ++
    ++  memset(&data, 0, sizeof(struct _finddata_t));
    ++  if( _findnext(dirp->d_handle, &data)==-1 ) return NULL;
    ++
    ++  /* TODO: Remove this block to allow hidden and/or system files. */
    ++  if( is_filtered(data) ) goto next;
    ++
    ++  dirp->d_next.d_ino++;
    ++  dirp->d_next.d_attributes = data.attrib;
    ++  strncpy(dirp->d_next.d_name, data.name, NAME_MAX);
    ++  dirp->d_next.d_name[NAME_MAX] = '\0';
    ++
    ++  return &dirp->d_next;
      }
    -@@ -71330,6 +71339,13 @@ SQLITE_API void SQLITE_STDCALL sqlite3_result_int64(sqlite3_context *pCtx, i64 i
    -   assert( sqlite3_mutex_held(pCtx->pOut->db->mutex) );
    -   sqlite3VdbeMemSetInt64(pCtx->pOut, iVal);
    + 
    +-#ifdef SIGINT
    + /*
    +-** This routine runs when the user presses Ctrl-C
    ++** Implementation of the POSIX readdir_r() function using the MSVCRT.
    + */
    +-static void interrupt_handler(int NotUsed){
    +-  UNUSED_PARAMETER(NotUsed);
    +-  seenInterrupt++;
    +-  if( seenInterrupt>2 ) exit(1);
    +-  if( globalDb ) sqlite3_interrupt(globalDb);
    ++INT readdir_r(
    ++  LPDIR dirp,
    ++  LPDIRENT entry,
    ++  LPDIRENT *result
    ++){
    ++  struct _finddata_t data;
    ++
    ++  if( dirp==NULL ) return EBADF;
    ++
    ++  if( dirp->d_first.d_ino==0 ){
    ++    dirp->d_first.d_ino++;
    ++    dirp->d_next.d_ino++;
    ++
    ++    entry->d_ino = dirp->d_first.d_ino;
    ++    entry->d_attributes = dirp->d_first.d_attributes;
    ++    strncpy(entry->d_name, dirp->d_first.d_name, NAME_MAX);
    ++    entry->d_name[NAME_MAX] = '\0';
    ++
    ++    *result = entry;
    ++    return 0;
    ++  }
    ++
    ++next:
    ++
    ++  memset(&data, 0, sizeof(struct _finddata_t));
    ++  if( _findnext(dirp->d_handle, &data)==-1 ){
    ++    *result = NULL;
    ++    return ENOENT;
    ++  }
    ++
    ++  /* TODO: Remove this block to allow hidden and/or system files. */
    ++  if( is_filtered(data) ) goto next;
    ++
    ++  entry->d_ino = (ino_t)-1; /* not available */
    ++  entry->d_attributes = data.attrib;
    ++  strncpy(entry->d_name, data.name, NAME_MAX);
    ++  entry->d_name[NAME_MAX] = '\0';
    ++
    ++  *result = entry;
    ++  return 0;
      }
    -+SQLITE_API void SQLITE_STDCALL sqlite3_result_pointer(sqlite3_context *pCtx, void *pPtr){
    -+  assert( sqlite3_mutex_held(pCtx->pOut->db->mutex) );
    -+  sqlite3VdbeMemSetNull(pCtx->pOut);
    -+  assert( (pCtx->pOut->flags & (MEM_TypeMask|MEM_Ptr))==MEM_Null );
    -+  pCtx->pOut->flags |= MEM_Ptr;
    -+  pCtx->pOut->u.pPtr = pPtr;
    +-#endif
    + 
    + /*
    +-** This is the callback routine that the shell
    +-** invokes for each row of a query result.
    ++** Implementation of the POSIX closedir() function using the MSVCRT.
    + */
    +-static int shell_callback(
    +-  void *pArg,
    +-  int nArg,        /* Number of result columns */
    +-  char **azArg,    /* Text of each result column */
    +-  char **azCol,    /* Column names */
    +-  int *aiType      /* Column types */
    ++INT closedir(
    ++  LPDIR dirp
    + ){
    +-  int i;
    +-  ShellState *p = (ShellState*)pArg;
    ++  INT result = 0;
    + 
    +-  switch( p->mode ){
    +-    case MODE_Line: {
    +-      int w = 5;
    +-      if( azArg==0 ) break;
    +-      for(i=0; i<nArg; i++){
    +-        int len = strlen30(azCol[i] ? azCol[i] : "");
    +-        if( len>w ) w = len;
    +-      }
    +-      if( p->cnt++>0 ) fprintf(p->out, "%s", p->rowSeparator);
    +-      for(i=0; i<nArg; i++){
    +-        fprintf(p->out,"%*s = %s%s", w, azCol[i],
    +-                azArg[i] ? azArg[i] : p->nullValue, p->rowSeparator);
    +-      }
    +-      break;
    +-    }
    +-    case MODE_Explain:
    +-    case MODE_Column: {
    +-      if( p->cnt++==0 ){
    +-        for(i=0; i<nArg; i++){
    +-          int w, n;
    +-          if( i<ArraySize(p->colWidth) ){
    +-            w = p->colWidth[i];
    +-          }else{
    +-            w = 0;
    +-          }
    +-          if( w==0 ){
    +-            w = strlen30(azCol[i] ? azCol[i] : "");
    +-            if( w<10 ) w = 10;
    +-            n = strlen30(azArg && azArg[i] ? azArg[i] : p->nullValue);
    +-            if( w<n ) w = n;
    +-          }
    +-          if( i<ArraySize(p->actualWidth) ){
    +-            p->actualWidth[i] = w;
    +-          }
    +-          if( p->showHeader ){
    +-            if( w<0 ){
    +-              fprintf(p->out,"%*.*s%s",-w,-w,azCol[i],
    +-                      i==nArg-1 ? p->rowSeparator : "  ");
    +-            }else{
    +-              fprintf(p->out,"%-*.*s%s",w,w,azCol[i],
    +-                      i==nArg-1 ? p->rowSeparator : "  ");
    +-            }
    +-          }
    +-        }
    +-        if( p->showHeader ){
    +-          for(i=0; i<nArg; i++){
    +-            int w;
    +-            if( i<ArraySize(p->actualWidth) ){
    +-               w = p->actualWidth[i];
    +-               if( w<0 ) w = -w;
    +-            }else{
    +-               w = 10;
    +-            }
    +-            fprintf(p->out,"%-*.*s%s",w,w,"-----------------------------------"
    +-                   "----------------------------------------------------------",
    +-                    i==nArg-1 ? p->rowSeparator : "  ");
    +-          }
    +-        }
    +-      }
    +-      if( azArg==0 ) break;
    +-      for(i=0; i<nArg; i++){
    +-        int w;
    +-        if( i<ArraySize(p->actualWidth) ){
    +-           w = p->actualWidth[i];
    +-        }else{
    +-           w = 10;
    +-        }
    +-        if( p->mode==MODE_Explain && azArg[i] && strlen30(azArg[i])>w ){
    +-          w = strlen30(azArg[i]);
    +-        }
    +-        if( i==1 && p->aiIndent && p->pStmt ){
    +-          if( p->iIndent<p->nIndent ){
    +-            fprintf(p->out, "%*.s", p->aiIndent[p->iIndent], "");
    +-          }
    +-          p->iIndent++;
    +-        }
    +-        if( w<0 ){
    +-          fprintf(p->out,"%*.*s%s",-w,-w,
    +-              azArg[i] ? azArg[i] : p->nullValue,
    +-              i==nArg-1 ? p->rowSeparator : "  ");
    +-        }else{
    +-          fprintf(p->out,"%-*.*s%s",w,w,
    +-              azArg[i] ? azArg[i] : p->nullValue,
    +-              i==nArg-1 ? p->rowSeparator : "  ");
    +-        }
    +-      }
    +-      break;
    +-    }
    +-    case MODE_Semi:
    +-    case MODE_List: {
    +-      if( p->cnt++==0 && p->showHeader ){
    +-        for(i=0; i<nArg; i++){
    +-          fprintf(p->out,"%s%s",azCol[i],
    +-                  i==nArg-1 ? p->rowSeparator : p->colSeparator);
    +-        }
    +-      }
    +-      if( azArg==0 ) break;
    +-      for(i=0; i<nArg; i++){
    +-        char *z = azArg[i];
    +-        if( z==0 ) z = p->nullValue;
    +-        fprintf(p->out, "%s", z);
    +-        if( i<nArg-1 ){
    +-          fprintf(p->out, "%s", p->colSeparator);
    +-        }else if( p->mode==MODE_Semi ){
    +-          fprintf(p->out, ";%s", p->rowSeparator);
    +-        }else{
    +-          fprintf(p->out, "%s", p->rowSeparator);
    +-        }
    +-      }
    +-      break;
    +-    }
    +-    case MODE_Html: {
    +-      if( p->cnt++==0 && p->showHeader ){
    +-        fprintf(p->out,"<TR>");
    +-        for(i=0; i<nArg; i++){
    +-          fprintf(p->out,"<TH>");
    +-          output_html_string(p->out, azCol[i]);
    +-          fprintf(p->out,"</TH>\n");
    +-        }
    +-        fprintf(p->out,"</TR>\n");
    +-      }
    +-      if( azArg==0 ) break;
    +-      fprintf(p->out,"<TR>");
    +-      for(i=0; i<nArg; i++){
    +-        fprintf(p->out,"<TD>");
    +-        output_html_string(p->out, azArg[i] ? azArg[i] : p->nullValue);
    +-        fprintf(p->out,"</TD>\n");
    +-      }
    +-      fprintf(p->out,"</TR>\n");
    +-      break;
    +-    }
    +-    case MODE_Tcl: {
    +-      if( p->cnt++==0 && p->showHeader ){
    +-        for(i=0; i<nArg; i++){
    +-          output_c_string(p->out,azCol[i] ? azCol[i] : "");
    +-          if(i<nArg-1) fprintf(p->out, "%s", p->colSeparator);
    +-        }
    +-        fprintf(p->out, "%s", p->rowSeparator);
    +-      }
    +-      if( azArg==0 ) break;
    +-      for(i=0; i<nArg; i++){
    +-        output_c_string(p->out, azArg[i] ? azArg[i] : p->nullValue);
    +-        if(i<nArg-1) fprintf(p->out, "%s", p->colSeparator);
    +-      }
    +-      fprintf(p->out, "%s", p->rowSeparator);
    +-      break;
    +-    }
    +-    case MODE_Csv: {
    +-      setBinaryMode(p->out);
    +-      if( p->cnt++==0 && p->showHeader ){
    +-        for(i=0; i<nArg; i++){
    +-          output_csv(p, azCol[i] ? azCol[i] : "", i<nArg-1);
    +-        }
    +-        fprintf(p->out, "%s", p->rowSeparator);
    +-      }
    +-      if( nArg>0 ){
    +-        for(i=0; i<nArg; i++){
    +-          output_csv(p, azArg[i], i<nArg-1);
    +-        }
    +-        fprintf(p->out, "%s", p->rowSeparator);
    +-      }
    +-      setTextMode(p->out);
    +-      break;
    +-    }
    +-    case MODE_Insert: {
    +-      p->cnt++;
    +-      if( azArg==0 ) break;
    +-      fprintf(p->out,"INSERT INTO %s",p->zDestTable);
    +-      if( p->showHeader ){
    +-        fprintf(p->out,"(");
    +-        for(i=0; i<nArg; i++){
    +-          char *zSep = i>0 ? ",": "";
    +-          fprintf(p->out, "%s%s", zSep, azCol[i]);
    +-        }
    +-        fprintf(p->out,")");
    +-      }
    +-      fprintf(p->out," VALUES(");
    +-      for(i=0; i<nArg; i++){
    +-        char *zSep = i>0 ? ",": "";
    +-        if( (azArg[i]==0) || (aiType && aiType[i]==SQLITE_NULL) ){
    +-          fprintf(p->out,"%sNULL",zSep);
    +-        }else if( aiType && aiType[i]==SQLITE_TEXT ){
    +-          if( zSep[0] ) fprintf(p->out,"%s",zSep);
    +-          output_quoted_string(p->out, azArg[i]);
    +-        }else if( aiType && (aiType[i]==SQLITE_INTEGER
    +-                             || aiType[i]==SQLITE_FLOAT) ){
    +-          fprintf(p->out,"%s%s",zSep, azArg[i]);
    +-        }else if( aiType && aiType[i]==SQLITE_BLOB && p->pStmt ){
    +-          const void *pBlob = sqlite3_column_blob(p->pStmt, i);
    +-          int nBlob = sqlite3_column_bytes(p->pStmt, i);
    +-          if( zSep[0] ) fprintf(p->out,"%s",zSep);
    +-          output_hex_blob(p->out, pBlob, nBlob);
    +-        }else if( isNumber(azArg[i], 0) ){
    +-          fprintf(p->out,"%s%s",zSep, azArg[i]);
    +-        }else{
    +-          if( zSep[0] ) fprintf(p->out,"%s",zSep);
    +-          output_quoted_string(p->out, azArg[i]);
    +-        }
    +-      }
    +-      fprintf(p->out,");\n");
    +-      break;
    +-    }
    +-    case MODE_Ascii: {
    +-      if( p->cnt++==0 && p->showHeader ){
    +-        for(i=0; i<nArg; i++){
    +-          if( i>0 ) fprintf(p->out, "%s", p->colSeparator);
    +-          fprintf(p->out,"%s",azCol[i] ? azCol[i] : "");
    +-        }
    +-        fprintf(p->out, "%s", p->rowSeparator);
    +-      }
    +-      if( azArg==0 ) break;
    +-      for(i=0; i<nArg; i++){
    +-        if( i>0 ) fprintf(p->out, "%s", p->colSeparator);
    +-        fprintf(p->out,"%s",azArg[i] ? azArg[i] : p->nullValue);
    +-      }
    +-      fprintf(p->out, "%s", p->rowSeparator);
    +-      break;
    +-    }
    ++  if( dirp==NULL ) return EINVAL;
    ++
    ++  if( dirp->d_handle!=NULL_INTPTR_T && dirp->d_handle!=BAD_INTPTR_T ){
    ++    result = _findclose(dirp->d_handle);
    +   }
    +-  return 0;
    ++
    ++  sqlite3_free(dirp);
    ++  return result;
    + }
    + 
    ++#endif /* defined(WIN32) && defined(_MSC_VER) */
    ++
    ++/************************* End test_windirent.c ********************/
    ++#define dirent DIRENT
    ++#endif
    ++/************************* Begin ../ext/misc/shathree.c ******************/
    + /*
    +-** This is the callback routine that the SQLite library
    +-** invokes for each row of a query result.
    ++** 2017-03-08
    ++**
    ++** 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 SQLite extension implements a functions that compute SHA1 hashes.
    ++** Two SQL functions are implemented:
    ++**
    ++**     sha3(X,SIZE)
    ++**     sha3_query(Y,SIZE)
    ++**
    ++** The sha3(X) function computes the SHA3 hash of the input X, or NULL if
    ++** X is NULL.
    ++**
    ++** The sha3_query(Y) function evalutes all queries in the SQL statements of Y
    ++** and returns a hash of their results.
    ++**
    ++** The SIZE argument is optional.  If omitted, the SHA3-256 hash algorithm
    ++** is used.  If SIZE is included it must be one of the integers 224, 256,
    ++** 384, or 512, to determine SHA3 hash variant that is computed.
    + */
    +-static int callback(void *pArg, int nArg, char **azArg, char **azCol){
    +-  /* since we don't have type info, call the shell_callback with a NULL value */
    +-  return shell_callback(pArg, nArg, azArg, azCol, NULL);
    +-}
    ++SQLITE_EXTENSION_INIT1
    ++#include <assert.h>
    ++#include <string.h>
    ++#include <stdarg.h>
    ++/* typedef sqlite3_uint64 u64; */
    + 
    ++/******************************************************************************
    ++** The Hash Engine
    ++*/
    + /*
    +-** Set the destination table field of the ShellState structure to
    +-** the name of the table given.  Escape any quote characters in the
    +-** table name.
    ++** Macros to determine whether the machine is big or little endian,
    ++** 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
    ++** -DSHA3_BYTEORDER=0 is set, then byte-order is determined
    ++** at run-time.
    + */
    +-static void set_table_name(ShellState *p, const char *zName){
    +-  int i, n;
    +-  int needQuote;
    +-  char *z;
    ++#ifndef SHA3_BYTEORDER
    ++# 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__)
    ++#   define SHA3_BYTEORDER    1234
    ++# elif defined(sparc)    || defined(__ppc__)
    ++#   define SHA3_BYTEORDER    4321
    ++# else
    ++#   define SHA3_BYTEORDER 0
    ++# endif
    ++#endif
    + 
    +-  if( p->zDestTable ){
    +-    free(p->zDestTable);
    +-    p->zDestTable = 0;
    +-  }
    +-  if( zName==0 ) return;
    +-  needQuote = !isalpha((unsigned char)*zName) && *zName!='_';
    +-  for(i=n=0; zName[i]; i++, n++){
    +-    if( !isalnum((unsigned char)zName[i]) && zName[i]!='_' ){
    +-      needQuote = 1;
    +-      if( zName[i]=='\'' ) n++;
    +-    }
    ++
    ++/*
    ++** State structure for a SHA3 hash in progress
    ++*/
    ++typedef struct SHA3Context SHA3Context;
    ++struct SHA3Context {
    ++  union {
    ++    u64 s[25];                /* Keccak state. 5x5 lines of 64 bits each */
    ++    unsigned char x[1600];    /* ... or 1600 bytes */
    ++  } u;
    ++  unsigned nRate;        /* Bytes of input accepted per Keccak iteration */
    ++  unsigned nLoaded;      /* Input bytes loaded into u.x[] so far this cycle */
    ++  unsigned ixMask;       /* Insert next input into u.x[nLoaded^ixMask]. */
    ++};
    ++
    ++/*
    ++** A single step of the Keccak mixing function for a 1600-bit state
    ++*/
    ++static void KeccakF1600Step(SHA3Context *p){
    ++  int i;
    ++  u64 b0, b1, b2, b3, b4;
    ++  u64 c0, c1, c2, c3, c4;
    ++  u64 d0, d1, d2, d3, d4;
    ++  static const u64 RC[] = {
    ++    0x0000000000000001ULL,  0x0000000000008082ULL,
    ++    0x800000000000808aULL,  0x8000000080008000ULL,
    ++    0x000000000000808bULL,  0x0000000080000001ULL,
    ++    0x8000000080008081ULL,  0x8000000000008009ULL,
    ++    0x000000000000008aULL,  0x0000000000000088ULL,
    ++    0x0000000080008009ULL,  0x000000008000000aULL,
    ++    0x000000008000808bULL,  0x800000000000008bULL,
    ++    0x8000000000008089ULL,  0x8000000000008003ULL,
    ++    0x8000000000008002ULL,  0x8000000000000080ULL,
    ++    0x000000000000800aULL,  0x800000008000000aULL,
    ++    0x8000000080008081ULL,  0x8000000000008080ULL,
    ++    0x0000000080000001ULL,  0x8000000080008008ULL
    ++  };
    ++# define a00 (p->u.s[0])
    ++# define a01 (p->u.s[1])
    ++# define a02 (p->u.s[2])
    ++# define a03 (p->u.s[3])
    ++# define a04 (p->u.s[4])
    ++# define a10 (p->u.s[5])
    ++# define a11 (p->u.s[6])
    ++# define a12 (p->u.s[7])
    ++# define a13 (p->u.s[8])
    ++# define a14 (p->u.s[9])
    ++# define a20 (p->u.s[10])
    ++# define a21 (p->u.s[11])
    ++# define a22 (p->u.s[12])
    ++# define a23 (p->u.s[13])
    ++# define a24 (p->u.s[14])
    ++# define a30 (p->u.s[15])
    ++# define a31 (p->u.s[16])
    ++# define a32 (p->u.s[17])
    ++# define a33 (p->u.s[18])
    ++# define a34 (p->u.s[19])
    ++# define a40 (p->u.s[20])
    ++# define a41 (p->u.s[21])
    ++# define a42 (p->u.s[22])
    ++# define a43 (p->u.s[23])
    ++# define a44 (p->u.s[24])
    ++# define ROL64(a,x) ((a<<x)|(a>>(64-x)))
    ++
    ++  for(i=0; i<24; i+=4){
    ++    c0 = a00^a10^a20^a30^a40;
    ++    c1 = a01^a11^a21^a31^a41;
    ++    c2 = a02^a12^a22^a32^a42;
    ++    c3 = a03^a13^a23^a33^a43;
    ++    c4 = a04^a14^a24^a34^a44;
    ++    d0 = c4^ROL64(c1, 1);
    ++    d1 = c0^ROL64(c2, 1);
    ++    d2 = c1^ROL64(c3, 1);
    ++    d3 = c2^ROL64(c4, 1);
    ++    d4 = c3^ROL64(c0, 1);
    ++
    ++    b0 = (a00^d0);
    ++    b1 = ROL64((a11^d1), 44);
    ++    b2 = ROL64((a22^d2), 43);
    ++    b3 = ROL64((a33^d3), 21);
    ++    b4 = ROL64((a44^d4), 14);
    ++    a00 =   b0 ^((~b1)&  b2 );
    ++    a00 ^= RC[i];
    ++    a11 =   b1 ^((~b2)&  b3 );
    ++    a22 =   b2 ^((~b3)&  b4 );
    ++    a33 =   b3 ^((~b4)&  b0 );
    ++    a44 =   b4 ^((~b0)&  b1 );
    ++
    ++    b2 = ROL64((a20^d0), 3);
    ++    b3 = ROL64((a31^d1), 45);
    ++    b4 = ROL64((a42^d2), 61);
    ++    b0 = ROL64((a03^d3), 28);
    ++    b1 = ROL64((a14^d4), 20);
    ++    a20 =   b0 ^((~b1)&  b2 );
    ++    a31 =   b1 ^((~b2)&  b3 );
    ++    a42 =   b2 ^((~b3)&  b4 );
    ++    a03 =   b3 ^((~b4)&  b0 );
    ++    a14 =   b4 ^((~b0)&  b1 );
    ++
    ++    b4 = ROL64((a40^d0), 18);
    ++    b0 = ROL64((a01^d1), 1);
    ++    b1 = ROL64((a12^d2), 6);
    ++    b2 = ROL64((a23^d3), 25);
    ++    b3 = ROL64((a34^d4), 8);
    ++    a40 =   b0 ^((~b1)&  b2 );
    ++    a01 =   b1 ^((~b2)&  b3 );
    ++    a12 =   b2 ^((~b3)&  b4 );
    ++    a23 =   b3 ^((~b4)&  b0 );
    ++    a34 =   b4 ^((~b0)&  b1 );
    ++
    ++    b1 = ROL64((a10^d0), 36);
    ++    b2 = ROL64((a21^d1), 10);
    ++    b3 = ROL64((a32^d2), 15);
    ++    b4 = ROL64((a43^d3), 56);
    ++    b0 = ROL64((a04^d4), 27);
    ++    a10 =   b0 ^((~b1)&  b2 );
    ++    a21 =   b1 ^((~b2)&  b3 );
    ++    a32 =   b2 ^((~b3)&  b4 );
    ++    a43 =   b3 ^((~b4)&  b0 );
    ++    a04 =   b4 ^((~b0)&  b1 );
    ++
    ++    b3 = ROL64((a30^d0), 41);
    ++    b4 = ROL64((a41^d1), 2);
    ++    b0 = ROL64((a02^d2), 62);
    ++    b1 = ROL64((a13^d3), 55);
    ++    b2 = ROL64((a24^d4), 39);
    ++    a30 =   b0 ^((~b1)&  b2 );
    ++    a41 =   b1 ^((~b2)&  b3 );
    ++    a02 =   b2 ^((~b3)&  b4 );
    ++    a13 =   b3 ^((~b4)&  b0 );
    ++    a24 =   b4 ^((~b0)&  b1 );
    ++
    ++    c0 = a00^a20^a40^a10^a30;
    ++    c1 = a11^a31^a01^a21^a41;
    ++    c2 = a22^a42^a12^a32^a02;
    ++    c3 = a33^a03^a23^a43^a13;
    ++    c4 = a44^a14^a34^a04^a24;
    ++    d0 = c4^ROL64(c1, 1);
    ++    d1 = c0^ROL64(c2, 1);
    ++    d2 = c1^ROL64(c3, 1);
    ++    d3 = c2^ROL64(c4, 1);
    ++    d4 = c3^ROL64(c0, 1);
    ++
    ++    b0 = (a00^d0);
    ++    b1 = ROL64((a31^d1), 44);
    ++    b2 = ROL64((a12^d2), 43);
    ++    b3 = ROL64((a43^d3), 21);
    ++    b4 = ROL64((a24^d4), 14);
    ++    a00 =   b0 ^((~b1)&  b2 );
    ++    a00 ^= RC[i+1];
    ++    a31 =   b1 ^((~b2)&  b3 );
    ++    a12 =   b2 ^((~b3)&  b4 );
    ++    a43 =   b3 ^((~b4)&  b0 );
    ++    a24 =   b4 ^((~b0)&  b1 );
    ++
    ++    b2 = ROL64((a40^d0), 3);
    ++    b3 = ROL64((a21^d1), 45);
    ++    b4 = ROL64((a02^d2), 61);
    ++    b0 = ROL64((a33^d3), 28);
    ++    b1 = ROL64((a14^d4), 20);
    ++    a40 =   b0 ^((~b1)&  b2 );
    ++    a21 =   b1 ^((~b2)&  b3 );
    ++    a02 =   b2 ^((~b3)&  b4 );
    ++    a33 =   b3 ^((~b4)&  b0 );
    ++    a14 =   b4 ^((~b0)&  b1 );
    ++
    ++    b4 = ROL64((a30^d0), 18);
    ++    b0 = ROL64((a11^d1), 1);
    ++    b1 = ROL64((a42^d2), 6);
    ++    b2 = ROL64((a23^d3), 25);
    ++    b3 = ROL64((a04^d4), 8);
    ++    a30 =   b0 ^((~b1)&  b2 );
    ++    a11 =   b1 ^((~b2)&  b3 );
    ++    a42 =   b2 ^((~b3)&  b4 );
    ++    a23 =   b3 ^((~b4)&  b0 );
    ++    a04 =   b4 ^((~b0)&  b1 );
    ++
    ++    b1 = ROL64((a20^d0), 36);
    ++    b2 = ROL64((a01^d1), 10);
    ++    b3 = ROL64((a32^d2), 15);
    ++    b4 = ROL64((a13^d3), 56);
    ++    b0 = ROL64((a44^d4), 27);
    ++    a20 =   b0 ^((~b1)&  b2 );
    ++    a01 =   b1 ^((~b2)&  b3 );
    ++    a32 =   b2 ^((~b3)&  b4 );
    ++    a13 =   b3 ^((~b4)&  b0 );
    ++    a44 =   b4 ^((~b0)&  b1 );
    ++
    ++    b3 = ROL64((a10^d0), 41);
    ++    b4 = ROL64((a41^d1), 2);
    ++    b0 = ROL64((a22^d2), 62);
    ++    b1 = ROL64((a03^d3), 55);
    ++    b2 = ROL64((a34^d4), 39);
    ++    a10 =   b0 ^((~b1)&  b2 );
    ++    a41 =   b1 ^((~b2)&  b3 );
    ++    a22 =   b2 ^((~b3)&  b4 );
    ++    a03 =   b3 ^((~b4)&  b0 );
    ++    a34 =   b4 ^((~b0)&  b1 );
    ++
    ++    c0 = a00^a40^a30^a20^a10;
    ++    c1 = a31^a21^a11^a01^a41;
    ++    c2 = a12^a02^a42^a32^a22;
    ++    c3 = a43^a33^a23^a13^a03;
    ++    c4 = a24^a14^a04^a44^a34;
    ++    d0 = c4^ROL64(c1, 1);
    ++    d1 = c0^ROL64(c2, 1);
    ++    d2 = c1^ROL64(c3, 1);
    ++    d3 = c2^ROL64(c4, 1);
    ++    d4 = c3^ROL64(c0, 1);
    ++
    ++    b0 = (a00^d0);
    ++    b1 = ROL64((a21^d1), 44);
    ++    b2 = ROL64((a42^d2), 43);
    ++    b3 = ROL64((a13^d3), 21);
    ++    b4 = ROL64((a34^d4), 14);
    ++    a00 =   b0 ^((~b1)&  b2 );
    ++    a00 ^= RC[i+2];
    ++    a21 =   b1 ^((~b2)&  b3 );
    ++    a42 =   b2 ^((~b3)&  b4 );
    ++    a13 =   b3 ^((~b4)&  b0 );
    ++    a34 =   b4 ^((~b0)&  b1 );
    ++
    ++    b2 = ROL64((a30^d0), 3);
    ++    b3 = ROL64((a01^d1), 45);
    ++    b4 = ROL64((a22^d2), 61);
    ++    b0 = ROL64((a43^d3), 28);
    ++    b1 = ROL64((a14^d4), 20);
    ++    a30 =   b0 ^((~b1)&  b2 );
    ++    a01 =   b1 ^((~b2)&  b3 );
    ++    a22 =   b2 ^((~b3)&  b4 );
    ++    a43 =   b3 ^((~b4)&  b0 );
    ++    a14 =   b4 ^((~b0)&  b1 );
    ++
    ++    b4 = ROL64((a10^d0), 18);
    ++    b0 = ROL64((a31^d1), 1);
    ++    b1 = ROL64((a02^d2), 6);
    ++    b2 = ROL64((a23^d3), 25);
    ++    b3 = ROL64((a44^d4), 8);
    ++    a10 =   b0 ^((~b1)&  b2 );
    ++    a31 =   b1 ^((~b2)&  b3 );
    ++    a02 =   b2 ^((~b3)&  b4 );
    ++    a23 =   b3 ^((~b4)&  b0 );
    ++    a44 =   b4 ^((~b0)&  b1 );
    ++
    ++    b1 = ROL64((a40^d0), 36);
    ++    b2 = ROL64((a11^d1), 10);
    ++    b3 = ROL64((a32^d2), 15);
    ++    b4 = ROL64((a03^d3), 56);
    ++    b0 = ROL64((a24^d4), 27);
    ++    a40 =   b0 ^((~b1)&  b2 );
    ++    a11 =   b1 ^((~b2)&  b3 );
    ++    a32 =   b2 ^((~b3)&  b4 );
    ++    a03 =   b3 ^((~b4)&  b0 );
    ++    a24 =   b4 ^((~b0)&  b1 );
    ++
    ++    b3 = ROL64((a20^d0), 41);
    ++    b4 = ROL64((a41^d1), 2);
    ++    b0 = ROL64((a12^d2), 62);
    ++    b1 = ROL64((a33^d3), 55);
    ++    b2 = ROL64((a04^d4), 39);
    ++    a20 =   b0 ^((~b1)&  b2 );
    ++    a41 =   b1 ^((~b2)&  b3 );
    ++    a12 =   b2 ^((~b3)&  b4 );
    ++    a33 =   b3 ^((~b4)&  b0 );
    ++    a04 =   b4 ^((~b0)&  b1 );
    ++
    ++    c0 = a00^a30^a10^a40^a20;
    ++    c1 = a21^a01^a31^a11^a41;
    ++    c2 = a42^a22^a02^a32^a12;
    ++    c3 = a13^a43^a23^a03^a33;
    ++    c4 = a34^a14^a44^a24^a04;
    ++    d0 = c4^ROL64(c1, 1);
    ++    d1 = c0^ROL64(c2, 1);
    ++    d2 = c1^ROL64(c3, 1);
    ++    d3 = c2^ROL64(c4, 1);
    ++    d4 = c3^ROL64(c0, 1);
    ++
    ++    b0 = (a00^d0);
    ++    b1 = ROL64((a01^d1), 44);
    ++    b2 = ROL64((a02^d2), 43);
    ++    b3 = ROL64((a03^d3), 21);
    ++    b4 = ROL64((a04^d4), 14);
    ++    a00 =   b0 ^((~b1)&  b2 );
    ++    a00 ^= RC[i+3];
    ++    a01 =   b1 ^((~b2)&  b3 );
    ++    a02 =   b2 ^((~b3)&  b4 );
    ++    a03 =   b3 ^((~b4)&  b0 );
    ++    a04 =   b4 ^((~b0)&  b1 );
    ++
    ++    b2 = ROL64((a10^d0), 3);
    ++    b3 = ROL64((a11^d1), 45);
    ++    b4 = ROL64((a12^d2), 61);
    ++    b0 = ROL64((a13^d3), 28);
    ++    b1 = ROL64((a14^d4), 20);
    ++    a10 =   b0 ^((~b1)&  b2 );
    ++    a11 =   b1 ^((~b2)&  b3 );
    ++    a12 =   b2 ^((~b3)&  b4 );
    ++    a13 =   b3 ^((~b4)&  b0 );
    ++    a14 =   b4 ^((~b0)&  b1 );
    ++
    ++    b4 = ROL64((a20^d0), 18);
    ++    b0 = ROL64((a21^d1), 1);
    ++    b1 = ROL64((a22^d2), 6);
    ++    b2 = ROL64((a23^d3), 25);
    ++    b3 = ROL64((a24^d4), 8);
    ++    a20 =   b0 ^((~b1)&  b2 );
    ++    a21 =   b1 ^((~b2)&  b3 );
    ++    a22 =   b2 ^((~b3)&  b4 );
    ++    a23 =   b3 ^((~b4)&  b0 );
    ++    a24 =   b4 ^((~b0)&  b1 );
    ++
    ++    b1 = ROL64((a30^d0), 36);
    ++    b2 = ROL64((a31^d1), 10);
    ++    b3 = ROL64((a32^d2), 15);
    ++    b4 = ROL64((a33^d3), 56);
    ++    b0 = ROL64((a34^d4), 27);
    ++    a30 =   b0 ^((~b1)&  b2 );
    ++    a31 =   b1 ^((~b2)&  b3 );
    ++    a32 =   b2 ^((~b3)&  b4 );
    ++    a33 =   b3 ^((~b4)&  b0 );
    ++    a34 =   b4 ^((~b0)&  b1 );
    ++
    ++    b3 = ROL64((a40^d0), 41);
    ++    b4 = ROL64((a41^d1), 2);
    ++    b0 = ROL64((a42^d2), 62);
    ++    b1 = ROL64((a43^d3), 55);
    ++    b2 = ROL64((a44^d4), 39);
    ++    a40 =   b0 ^((~b1)&  b2 );
    ++    a41 =   b1 ^((~b2)&  b3 );
    ++    a42 =   b2 ^((~b3)&  b4 );
    ++    a43 =   b3 ^((~b4)&  b0 );
    ++    a44 =   b4 ^((~b0)&  b1 );
    +   }
    +-  if( needQuote ) n += 2;
    +-  z = p->zDestTable = malloc( n+1 );
    +-  if( z==0 ){
    +-    fprintf(stderr,"Error: out of memory\n");
    +-    exit(1);
     +}
    - SQLITE_API void SQLITE_STDCALL sqlite3_result_null(sqlite3_context *pCtx){
    -   assert( sqlite3_mutex_held(pCtx->pOut->db->mutex) );
    -   sqlite3VdbeMemSetNull(pCtx->pOut);
    -@@ -139190,7 +139206,7 @@ static int fts3ColumnMethod(
    -   }else if( iCol==p->nColumn ){
    -     /* The extra column whose name is the same as the table.
    -     ** Return a blob which is a pointer to the cursor.  */
    --    sqlite3_result_blob(pCtx, &pCsr, sizeof(pCsr), SQLITE_TRANSIENT);
    -+    sqlite3_result_pointer(pCtx, pCsr);
    -   }else if( iCol==p->nColumn+2 && pCsr->pExpr ){
    -     sqlite3_result_int64(pCtx, pCsr->iLangid);
    ++
    ++/*
    ++** Initialize a new hash.  iSize determines the size of the hash
    ++** in bits and should be one of 224, 256, 384, or 512.  Or iSize
    ++** can be zero to use the default hash size of 256 bits.
    ++*/
    ++static void SHA3Init(SHA3Context *p, int iSize){
    ++  memset(p, 0, sizeof(*p));
    ++  if( iSize>=128 && iSize<=512 ){
    ++    p->nRate = (1600 - ((iSize + 31)&~31)*2)/8;
    ++  }else{
    ++    p->nRate = (1600 - 2*256)/8;
    +   }
    +-  n = 0;
    +-  if( needQuote ) z[n++] = '\'';
    +-  for(i=0; zName[i]; i++){
    +-    z[n++] = zName[i];
    +-    if( zName[i]=='\'' ) z[n++] = '\'';
    ++#if SHA3_BYTEORDER==1234
    ++  /* Known to be little-endian at compile-time. No-op */
    ++#elif SHA3_BYTEORDER==4321
    ++  p->ixMask = 7;  /* Big-endian */
    ++#else
    ++  {
    ++    static unsigned int one = 1;
    ++    if( 1==*(unsigned char*)&one ){
    ++      /* Little endian.  No byte swapping. */
    ++      p->ixMask = 0;
    ++    }else{
    ++      /* Big endian.  Byte swap. */
    ++      p->ixMask = 7;
    ++    }
    +   }
    +-  if( needQuote ) z[n++] = '\'';
    +-  z[n] = 0;
    ++#endif
    + }
    + 
    +-/* zIn is either a pointer to a NULL-terminated string in memory obtained
    +-** from malloc(), or a NULL pointer. The string pointed to by zAppend is
    +-** added to zIn, and the result returned in memory obtained from malloc().
    +-** zIn, if it was not NULL, is freed.
    +-**
    +-** If the third argument, quote, is not '\0', then it is used as a 
    +-** quote character for zAppend.
    ++/*
    ++** Make consecutive calls to the SHA3Update function to add new content
    ++** to the hash
    + */
    +-static char *appendText(char *zIn, char const *zAppend, char quote){
    +-  int len;
    +-  int i;
    +-  int nAppend = strlen30(zAppend);
    +-  int nIn = (zIn?strlen30(zIn):0);
    +-
    +-  len = nAppend+nIn+1;
    +-  if( quote ){
    +-    len += 2;
    +-    for(i=0; i<nAppend; i++){
    +-      if( zAppend[i]==quote ) len++;
    ++static void SHA3Update(
    ++  SHA3Context *p,
    ++  const unsigned char *aData,
    ++  unsigned int nData
    ++){
    ++  unsigned int i = 0;
    ++#if SHA3_BYTEORDER==1234
    ++  if( (p->nLoaded % 8)==0 && ((aData - (const unsigned char*)0)&7)==0 ){
    ++    for(; i+7<nData; i+=8){
    ++      p->u.s[p->nLoaded/8] ^= *(u64*)&aData[i];
    ++      p->nLoaded += 8;
    ++      if( p->nLoaded>=p->nRate ){
    ++        KeccakF1600Step(p);
    ++        p->nLoaded = 0;
    ++      }
    +     }
    +   }
    +-
    +-  zIn = (char *)realloc(zIn, len);
    +-  if( !zIn ){
    +-    return 0;
    ++#endif
    ++  for(; i<nData; i++){
    ++#if SHA3_BYTEORDER==1234
    ++    p->u.x[p->nLoaded] ^= aData[i];
    ++#elif SHA3_BYTEORDER==4321
    ++    p->u.x[p->nLoaded^0x07] ^= aData[i];
    ++#else
    ++    p->u.x[p->nLoaded^p->ixMask] ^= aData[i];
    ++#endif
    ++    p->nLoaded++;
    ++    if( p->nLoaded==p->nRate ){
    ++      KeccakF1600Step(p);
    ++      p->nLoaded = 0;
    ++    }
    +   }
    ++}
    + 
    +-  if( quote ){
    +-    char *zCsr = &zIn[nIn];
    +-    *zCsr++ = quote;
    +-    for(i=0; i<nAppend; i++){
    +-      *zCsr++ = zAppend[i];
    +-      if( zAppend[i]==quote ) *zCsr++ = quote;
    +-    }
    +-    *zCsr++ = quote;
    +-    *zCsr++ = '\0';
    +-    assert( (zCsr-zIn)==len );
    ++/*
    ++** After all content has been added, invoke SHA3Final() to compute
    ++** the final hash.  The function returns a pointer to the binary
    ++** hash value.
    ++*/
    ++static unsigned char *SHA3Final(SHA3Context *p){
    ++  unsigned int i;
    ++  if( p->nLoaded==p->nRate-1 ){
    ++    const unsigned char c1 = 0x86;
    ++    SHA3Update(p, &c1, 1);
        }else{
    -@@ -139402,16 +139418,13 @@ static int fts3FunctionArg(
    -   sqlite3_value *pVal,            /* argv[0] passed to function */
    -   Fts3Cursor **ppCsr              /* OUT: Store cursor handle here */
    +-    memcpy(&zIn[nIn], zAppend, nAppend);
    +-    zIn[len-1] = '\0';
    ++    const unsigned char c2 = 0x06;
    ++    const unsigned char c3 = 0x80;
    ++    SHA3Update(p, &c2, 1);
    ++    p->nLoaded = p->nRate - 1;
    ++    SHA3Update(p, &c3, 1);
    +   }
    +-
    +-  return zIn;
    ++  for(i=0; i<p->nRate; i++){
    ++    p->u.x[i+p->nRate] = p->u.x[i^p->ixMask];
    ++  }
    ++  return &p->u.x[p->nRate];
    + }
    +-
    ++/* End of the hashing logic
    ++*****************************************************************************/
    + 
    + /*
    +-** Execute a query statement that will generate SQL output.  Print
    +-** the result columns, comma-separated, on a line and then add a
    +-** semicolon terminator to the end of that line.
    ++** Implementation of the sha3(X,SIZE) function.
    + **
    +-** If the number of columns is 1 and that column contains text "--"
    +-** then write the semicolon on a separate line.  That way, if a 
    +-** "--" comment occurs at the end of the statement, the comment
    +-** won't consume the semicolon terminator.
    ++** Return a BLOB which is the SIZE-bit SHA3 hash of X.  The default
    ++** size is 256.  If X is a BLOB, it is hashed as is.  
    ++** For all other non-NULL types of input, X is converted into a UTF-8 string
    ++** and the string is hashed without the trailing 0x00 terminator.  The hash
    ++** of a NULL value is NULL.
    + */
    +-static int run_table_dump_query(
    +-  ShellState *p,           /* Query context */
    +-  const char *zSelect,     /* SELECT statement to extract content */
    +-  const char *zFirstRow    /* Print before first row, if not NULL */
    ++static void sha3Func(
    ++  sqlite3_context *context,
    ++  int argc,
    ++  sqlite3_value **argv
      ){
    --  Fts3Cursor *pRet;
    --  if( sqlite3_value_type(pVal)!=SQLITE_BLOB 
    --   || sqlite3_value_bytes(pVal)!=sizeof(Fts3Cursor *)
    --  ){
    -+  Fts3Cursor *pRet = (Fts3Cursor*)sqlite3_value_pointer(pVal);
    -+  if( pRet==0 ){
    -     char *zErr = sqlite3_mprintf("illegal first argument to %s", zFunc);
    -     sqlite3_result_error(pContext, zErr, -1);
    -     sqlite3_free(zErr);
    -     return SQLITE_ERROR;
    +-  sqlite3_stmt *pSelect;
    +-  int rc;
    +-  int nResult;
    +-  int i;
    +-  const char *z;
    +-  rc = sqlite3_prepare_v2(p->db, zSelect, -1, &pSelect, 0);
    +-  if( rc!=SQLITE_OK || !pSelect ){
    +-    fprintf(p->out, "/**** ERROR: (%d) %s *****/\n", rc, sqlite3_errmsg(p->db));
    +-    if( (rc&0xff)!=SQLITE_CORRUPT ) p->nErr++;
    +-    return rc;
    +-  }
    +-  rc = sqlite3_step(pSelect);
    +-  nResult = sqlite3_column_count(pSelect);
    +-  while( rc==SQLITE_ROW ){
    +-    if( zFirstRow ){
    +-      fprintf(p->out, "%s", zFirstRow);
    +-      zFirstRow = 0;
    +-    }
    +-    z = (const char*)sqlite3_column_text(pSelect, 0);
    +-    fprintf(p->out, "%s", z);
    +-    for(i=1; i<nResult; i++){ 
    +-      fprintf(p->out, ",%s", sqlite3_column_text(pSelect, i));
    ++  SHA3Context cx;
    ++  int eType = sqlite3_value_type(argv[0]);
    ++  int nByte = sqlite3_value_bytes(argv[0]);
    ++  int iSize;
    ++  if( argc==1 ){
    ++    iSize = 256;
    ++  }else{
    ++    iSize = sqlite3_value_int(argv[1]);
    ++    if( iSize!=224 && iSize!=256 && iSize!=384 && iSize!=512 ){
    ++      sqlite3_result_error(context, "SHA3 size should be one of: 224 256 "
    ++                                    "384 512", -1);
    ++      return;
    +     }
    +-    if( z==0 ) z = "";
    +-    while( z[0] && (z[0]!='-' || z[1]!='-') ) z++;
    +-    if( z[0] ){
    +-      fprintf(p->out, "\n;\n");
    +-    }else{
    +-      fprintf(p->out, ";\n");
    +-    }    
    +-    rc = sqlite3_step(pSelect);
        }
    --  memcpy(&pRet, sqlite3_value_blob(pVal), sizeof(Fts3Cursor *));
    -   *ppCsr = pRet;
    -   return SQLITE_OK;
    +-  rc = sqlite3_finalize(pSelect);
    +-  if( rc!=SQLITE_OK ){
    +-    fprintf(p->out, "/**** ERROR: (%d) %s *****/\n", rc, sqlite3_errmsg(p->db));
    +-    if( (rc&0xff)!=SQLITE_CORRUPT ) p->nErr++;
    ++  if( eType==SQLITE_NULL ) return;
    ++  SHA3Init(&cx, iSize);
    ++  if( eType==SQLITE_BLOB ){
    ++    SHA3Update(&cx, sqlite3_value_blob(argv[0]), nByte);
    ++  }else{
    ++    SHA3Update(&cx, sqlite3_value_text(argv[0]), nByte);
    +   }
    +-  return rc;
    ++  sqlite3_result_blob(context, SHA3Final(&cx), iSize/8, SQLITE_TRANSIENT);
      }
    -@@ -180632,7 +180645,7 @@ static void fts5SourceIdFunc(
    -   sqlite3_value **apVal           /* Function arguments */
    + 
    +-/*
    +-** Allocate space and save off current error string.
    ++/* Compute a string using sqlite3_vsnprintf() with a maximum length
    ++** of 50 bytes and add it to the hash.
    + */
    +-static char *save_err_msg(
    +-  sqlite3 *db            /* Database to query */
    ++static void hash_step_vformat(
    ++  SHA3Context *p,                 /* Add content to this context */
    ++  const char *zFormat,
    ++  ...
      ){
    -   assert( nArg==0 );
    --  sqlite3_result_text(pCtx, "fts5: 2015-11-02 18:31:45 bda77dda9697c463c3d0704014d51627fceee328", -1, SQLITE_TRANSIENT);
    -+  sqlite3_result_text(pCtx, "fts5: 2017-07-21 07:45:23 69906880cee1f246cce494672402e0c7f29bd4ec19c437d26d603870d2bd625d", -1, SQLITE_TRANSIENT);
    +-  int nErrMsg = 1+strlen30(sqlite3_errmsg(db));
    +-  char *zErrMsg = sqlite3_malloc64(nErrMsg);
    +-  if( zErrMsg ){
    +-    memcpy(zErrMsg, sqlite3_errmsg(db), nErrMsg);
    +-  }
    +-  return zErrMsg;
    ++  va_list ap;
    ++  int n;
    ++  char zBuf[50];
    ++  va_start(ap, zFormat);
    ++  sqlite3_vsnprintf(sizeof(zBuf),zBuf,zFormat,ap);
    ++  va_end(ap);
    ++  n = (int)strlen(zBuf);
    ++  SHA3Update(p, (unsigned char*)zBuf, n);
      }
      
    - static int fts5Init(sqlite3 *db){
    -diff --git a/dist/sqlite3.h b/dist/sqlite3.h
    -index 7cca0ac..a0c0e4e 100644
    ---- a/dist/sqlite3.h
    -+++ b/dist/sqlite3.h
    -@@ -113,7 +113,7 @@ extern "C" {
    + /*
    +-** Display memory stats.
    ++** Implementation of the sha3_query(SQL,SIZE) function.
    ++**
    ++** This function compiles and runs the SQL statement(s) given in the
    ++** argument. The results are hashed using a SIZE-bit SHA3.  The default
    ++** size is 256.
    ++**
    ++** The format of the byte stream that is hashed is summarized as follows:
    ++**
    ++**       S<n>:<sql>
    ++**       R
    ++**       N
    ++**       I<int>
    ++**       F<ieee-float>
    ++**       B<size>:<bytes>
    ++**       T<size>:<text>
    ++**
    ++** <sql> is the original SQL text for each statement run and <n> is
    ++** the size of that text.  The SQL text is UTF-8.  A single R character
    ++** occurs before the start of each row.  N means a NULL value.
    ++** I mean an 8-byte little-endian integer <int>.  F is a floating point
    ++** number with an 8-byte little-endian IEEE floating point value <ieee-float>.
    ++** B means blobs of <size> bytes.  T means text rendered as <size>
    ++** bytes of UTF-8.  The <n> and <size> values are expressed as an ASCII
    ++** text integers.
    ++**
    ++** For each SQL statement in the X input, there is one S segment.  Each
    ++** S segment is followed by zero or more R segments, one for each row in the
    ++** result set.  After each R, there are one or more N, I, F, B, or T segments,
    ++** one for each column in the result set.  Segments are concatentated directly
    ++** with no delimiters of any kind.
      */
    - #define SQLITE_VERSION        "3.9.2"
    - #define SQLITE_VERSION_NUMBER 3009002
    --#define SQLITE_SOURCE_ID      "2015-11-02 18:31:45 bda77dda9697c463c3d0704014d51627fceee328"
    -+#define SQLITE_SOURCE_ID      "2017-07-21 07:45:23 69906880cee1f246cce494672402e0c7f29bd4ec19c437d26d603870d2bd625d"
    +-static int display_stats(
    +-  sqlite3 *db,                /* Database to query */
    +-  ShellState *pArg,           /* Pointer to ShellState */
    +-  int bReset                  /* True to reset the stats */
    ++static void sha3QueryFunc(
    ++  sqlite3_context *context,
    ++  int argc,
    ++  sqlite3_value **argv
    + ){
    +-  int iCur;
    +-  int iHiwtr;
    ++  sqlite3 *db = sqlite3_context_db_handle(context);
    ++  const char *zSql = (const char*)sqlite3_value_text(argv[0]);
    ++  sqlite3_stmt *pStmt = 0;
    ++  int nCol;                   /* Number of columns in the result set */
    ++  int i;                      /* Loop counter */
    ++  int rc;
    ++  int n;
    ++  const char *z;
    ++  SHA3Context cx;
    ++  int iSize;
    + 
    +-  if( pArg && pArg->out ){
    +-    
    +-    iHiwtr = iCur = -1;
    +-    sqlite3_status(SQLITE_STATUS_MEMORY_USED, &iCur, &iHiwtr, bReset);
    +-    fprintf(pArg->out,
    +-            "Memory Used:                         %d (max %d) bytes\n",
    +-            iCur, iHiwtr);
    +-    iHiwtr = iCur = -1;
    +-    sqlite3_status(SQLITE_STATUS_MALLOC_COUNT, &iCur, &iHiwtr, bReset);
    +-    fprintf(pArg->out, "Number of Outstanding Allocations:   %d (max %d)\n",
    +-            iCur, iHiwtr);
    +-    if( pArg->shellFlgs & SHFLG_Pagecache ){
    +-      iHiwtr = iCur = -1;
    +-      sqlite3_status(SQLITE_STATUS_PAGECACHE_USED, &iCur, &iHiwtr, bReset);
    +-      fprintf(pArg->out,
    +-              "Number of Pcache Pages Used:         %d (max %d) pages\n",
    +-              iCur, iHiwtr);
    +-    }
    +-    iHiwtr = iCur = -1;
    +-    sqlite3_status(SQLITE_STATUS_PAGECACHE_OVERFLOW, &iCur, &iHiwtr, bReset);
    +-    fprintf(pArg->out,
    +-            "Number of Pcache Overflow Bytes:     %d (max %d) bytes\n",
    +-            iCur, iHiwtr);
    +-    if( pArg->shellFlgs & SHFLG_Scratch ){
    +-      iHiwtr = iCur = -1;
    +-      sqlite3_status(SQLITE_STATUS_SCRATCH_USED, &iCur, &iHiwtr, bReset);
    +-      fprintf(pArg->out, "Number of Scratch Allocations Used:  %d (max %d)\n",
    +-              iCur, iHiwtr);
    ++  if( argc==1 ){
    ++    iSize = 256;
    ++  }else{
    ++    iSize = sqlite3_value_int(argv[1]);
    ++    if( iSize!=224 && iSize!=256 && iSize!=384 && iSize!=512 ){
    ++      sqlite3_result_error(context, "SHA3 size should be one of: 224 256 "
    ++                                    "384 512", -1);
    ++      return;
    +     }
    +-    iHiwtr = iCur = -1;
    +-    sqlite3_status(SQLITE_STATUS_SCRATCH_OVERFLOW, &iCur, &iHiwtr, bReset);
    +-    fprintf(pArg->out,
    +-            "Number of Scratch Overflow Bytes:    %d (max %d) bytes\n",
    +-            iCur, iHiwtr);
    +-    iHiwtr = iCur = -1;
    +-    sqlite3_status(SQLITE_STATUS_MALLOC_SIZE, &iCur, &iHiwtr, bReset);
    +-    fprintf(pArg->out, "Largest Allocation:                  %d bytes\n",
    +-            iHiwtr);
    +-    iHiwtr = iCur = -1;
    +-    sqlite3_status(SQLITE_STATUS_PAGECACHE_SIZE, &iCur, &iHiwtr, bReset);
    +-    fprintf(pArg->out, "Largest Pcache Allocation:           %d bytes\n",
    +-            iHiwtr);
    +-    iHiwtr = iCur = -1;
    +-    sqlite3_status(SQLITE_STATUS_SCRATCH_SIZE, &iCur, &iHiwtr, bReset);
    +-    fprintf(pArg->out, "Largest Scratch Allocation:          %d bytes\n",
    +-            iHiwtr);
    +-#ifdef YYTRACKMAXSTACKDEPTH
    +-    iHiwtr = iCur = -1;
    +-    sqlite3_status(SQLITE_STATUS_PARSER_STACK, &iCur, &iHiwtr, bReset);
    +-    fprintf(pArg->out, "Deepest Parser Stack:                %d (max %d)\n",
    +-            iCur, iHiwtr);
    +-#endif
    +   }
    +-
    +-  if( pArg && pArg->out && db ){
    +-    if( pArg->shellFlgs & SHFLG_Lookaside ){
    +-      iHiwtr = iCur = -1;
    +-      sqlite3_db_status(db, SQLITE_DBSTATUS_LOOKASIDE_USED,
    +-                        &iCur, &iHiwtr, bReset);
    +-      fprintf(pArg->out, "Lookaside Slots Used:                %d (max %d)\n",
    +-              iCur, iHiwtr);
    +-      sqlite3_db_status(db, SQLITE_DBSTATUS_LOOKASIDE_HIT,
    +-                        &iCur, &iHiwtr, bReset);
    +-      fprintf(pArg->out, "Successful lookaside attempts:       %d\n", iHiwtr);
    +-      sqlite3_db_status(db, SQLITE_DBSTATUS_LOOKASIDE_MISS_SIZE,
    +-                        &iCur, &iHiwtr, bReset);
    +-      fprintf(pArg->out, "Lookaside failures due to size:      %d\n", iHiwtr);
    +-      sqlite3_db_status(db, SQLITE_DBSTATUS_LOOKASIDE_MISS_FULL,
    +-                        &iCur, &iHiwtr, bReset);
    +-      fprintf(pArg->out, "Lookaside failures due to OOM:       %d\n", iHiwtr);
    ++  if( zSql==0 ) return;
    ++  SHA3Init(&cx, iSize);
    ++  while( zSql[0] ){
    ++    rc = sqlite3_prepare_v2(db, zSql, -1, &pStmt, &zSql);
    ++    if( rc ){
    ++      char *zMsg = sqlite3_mprintf("error SQL statement [%s]: %s",
    ++                                   zSql, sqlite3_errmsg(db));
    ++      sqlite3_finalize(pStmt);
    ++      sqlite3_result_error(context, zMsg, -1);
    ++      sqlite3_free(zMsg);
    ++      return;
    +     }
    +-    iHiwtr = iCur = -1;
    +-    sqlite3_db_status(db, SQLITE_DBSTATUS_CACHE_USED, &iCur, &iHiwtr, bReset);
    +-    fprintf(pArg->out, "Pager Heap Usage:                    %d bytes\n",iCur);
    +-    iHiwtr = iCur = -1;
    +-    sqlite3_db_status(db, SQLITE_DBSTATUS_CACHE_HIT, &iCur, &iHiwtr, 1);
    +-    fprintf(pArg->out, "Page cache hits:                     %d\n", iCur);
    +-    iHiwtr = iCur = -1;
    +-    sqlite3_db_status(db, SQLITE_DBSTATUS_CACHE_MISS, &iCur, &iHiwtr, 1);
    +-    fprintf(pArg->out, "Page cache misses:                   %d\n", iCur); 
    +-    iHiwtr = iCur = -1;
    +-    sqlite3_db_status(db, SQLITE_DBSTATUS_CACHE_WRITE, &iCur, &iHiwtr, 1);
    +-    fprintf(pArg->out, "Page cache writes:                   %d\n", iCur); 
    +-    iHiwtr = iCur = -1;
    +-    sqlite3_db_status(db, SQLITE_DBSTATUS_SCHEMA_USED, &iCur, &iHiwtr, bReset);
    +-    fprintf(pArg->out, "Schema Heap Usage:                   %d bytes\n",iCur); 
    +-    iHiwtr = iCur = -1;
    +-    sqlite3_db_status(db, SQLITE_DBSTATUS_STMT_USED, &iCur, &iHiwtr, bReset);
    +-    fprintf(pArg->out, "Statement Heap/Lookaside Usage:      %d bytes\n",iCur); 
    ++    if( !sqlite3_stmt_readonly(pStmt) ){
    ++      char *zMsg = sqlite3_mprintf("non-query: [%s]", sqlite3_sql(pStmt));
    ++      sqlite3_finalize(pStmt);
    ++      sqlite3_result_error(context, zMsg, -1);
    ++      sqlite3_free(zMsg);
    ++      return;
    ++    }
    ++    nCol = sqlite3_column_count(pStmt);
    ++    z = sqlite3_sql(pStmt);
    ++    n = (int)strlen(z);
    ++    hash_step_vformat(&cx,"S%d:",n);
    ++    SHA3Update(&cx,(unsigned char*)z,n);
    ++
    ++    /* Compute a hash over the result of the query */
    ++    while( SQLITE_ROW==sqlite3_step(pStmt) ){
    ++      SHA3Update(&cx,(const unsigned char*)"R",1);
    ++      for(i=0; i<nCol; i++){
    ++        switch( sqlite3_column_type(pStmt,i) ){
    ++          case SQLITE_NULL: {
    ++            SHA3Update(&cx, (const unsigned char*)"N",1);
    ++            break;
    ++          }
    ++          case SQLITE_INTEGER: {
    ++            sqlite3_uint64 u;
    ++            int j;
    ++            unsigned char x[9];
    ++            sqlite3_int64 v = sqlite3_column_int64(pStmt,i);
    ++            memcpy(&u, &v, 8);
    ++            for(j=8; j>=1; j--){
    ++              x[j] = u & 0xff;
    ++              u >>= 8;
    ++            }
    ++            x[0] = 'I';
    ++            SHA3Update(&cx, x, 9);
    ++            break;
    ++          }
    ++          case SQLITE_FLOAT: {
    ++            sqlite3_uint64 u;
    ++            int j;
    ++            unsigned char x[9];
    ++            double r = sqlite3_column_double(pStmt,i);
    ++            memcpy(&u, &r, 8);
    ++            for(j=8; j>=1; j--){
    ++              x[j] = u & 0xff;
    ++              u >>= 8;
    ++            }
    ++            x[0] = 'F';
    ++            SHA3Update(&cx,x,9);
    ++            break;
    ++          }
    ++          case SQLITE_TEXT: {
    ++            int n2 = sqlite3_column_bytes(pStmt, i);
    ++            const unsigned char *z2 = sqlite3_column_text(pStmt, i);
    ++            hash_step_vformat(&cx,"T%d:",n2);
    ++            SHA3Update(&cx, z2, n2);
    ++            break;
    ++          }
    ++          case SQLITE_BLOB: {
    ++            int n2 = sqlite3_column_bytes(pStmt, i);
    ++            const unsigned char *z2 = sqlite3_column_blob(pStmt, i);
    ++            hash_step_vformat(&cx,"B%d:",n2);
    ++            SHA3Update(&cx, z2, n2);
    ++            break;
    ++          }
    ++        }
    ++      }
    ++    }
    ++    sqlite3_finalize(pStmt);
    +   }
    ++  sqlite3_result_blob(context, SHA3Final(&cx), iSize/8, SQLITE_TRANSIENT);
    ++}
    + 
    +-  if( pArg && pArg->out && db && pArg->pStmt ){
    +-    iCur = sqlite3_stmt_status(pArg->pStmt, SQLITE_STMTSTATUS_FULLSCAN_STEP,
    +-                               bReset);
    +-    fprintf(pArg->out, "Fullscan Steps:                      %d\n", iCur);
    +-    iCur = sqlite3_stmt_status(pArg->pStmt, SQLITE_STMTSTATUS_SORT, bReset);
    +-    fprintf(pArg->out, "Sort Operations:                     %d\n", iCur);
    +-    iCur = sqlite3_stmt_status(pArg->pStmt, SQLITE_STMTSTATUS_AUTOINDEX,bReset);
    +-    fprintf(pArg->out, "Autoindex Inserts:                   %d\n", iCur);
    +-    iCur = sqlite3_stmt_status(pArg->pStmt, SQLITE_STMTSTATUS_VM_STEP, bReset);
    +-    fprintf(pArg->out, "Virtual Machine Steps:               %d\n", iCur);
    +-  }
    + 
    +-  /* Do not remove this machine readable comment: extra-stats-output-here */
    ++#ifdef _WIN32
    + 
    +-  return 0;
    ++#endif
    ++int sqlite3_shathree_init(
    ++  sqlite3 *db,
    ++  char **pzErrMsg,
    ++  const sqlite3_api_routines *pApi
    ++){
    ++  int rc = SQLITE_OK;
    ++  SQLITE_EXTENSION_INIT2(pApi);
    ++  (void)pzErrMsg;  /* Unused parameter */
    ++  rc = sqlite3_create_function(db, "sha3", 1, SQLITE_UTF8, 0,
    ++                               sha3Func, 0, 0);
    ++  if( rc==SQLITE_OK ){
    ++    rc = sqlite3_create_function(db, "sha3", 2, SQLITE_UTF8, 0,
    ++                                 sha3Func, 0, 0);
    ++  }
    ++  if( rc==SQLITE_OK ){
    ++    rc = sqlite3_create_function(db, "sha3_query", 1, SQLITE_UTF8, 0,
    ++                                 sha3QueryFunc, 0, 0);
    ++  }
    ++  if( rc==SQLITE_OK ){
    ++    rc = sqlite3_create_function(db, "sha3_query", 2, SQLITE_UTF8, 0,
    ++                                 sha3QueryFunc, 0, 0);
    ++  }
    ++  return rc;
    + }
      
    ++/************************* End ../ext/misc/shathree.c ********************/
    ++/************************* Begin ../ext/misc/fileio.c ******************/
      /*
    - ** CAPI3REF: Run-Time Library Version Numbers
    -@@ -4352,6 +4352,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_value_bytes16(sqlite3_value*);
    - SQLITE_API double SQLITE_STDCALL sqlite3_value_double(sqlite3_value*);
    - SQLITE_API int SQLITE_STDCALL sqlite3_value_int(sqlite3_value*);
    - SQLITE_API sqlite3_int64 SQLITE_STDCALL sqlite3_value_int64(sqlite3_value*);
    -+SQLITE_API void *SQLITE_STDCALL sqlite3_value_pointer(sqlite3_value*);
    - SQLITE_API const unsigned char *SQLITE_STDCALL sqlite3_value_text(sqlite3_value*);
    - SQLITE_API const void *SQLITE_STDCALL sqlite3_value_text16(sqlite3_value*);
    - SQLITE_API const void *SQLITE_STDCALL sqlite3_value_text16le(sqlite3_value*);
    -@@ -4664,6 +4665,7 @@ SQLITE_API void SQLITE_STDCALL sqlite3_result_error_code(sqlite3_context*, int);
    - SQLITE_API void SQLITE_STDCALL sqlite3_result_int(sqlite3_context*, int);
    - SQLITE_API void SQLITE_STDCALL sqlite3_result_int64(sqlite3_context*, sqlite3_int64);
    - SQLITE_API void SQLITE_STDCALL sqlite3_result_null(sqlite3_context*);
    -+SQLITE_API void SQLITE_STDCALL sqlite3_result_pointer(sqlite3_context*, void*);
    - SQLITE_API void SQLITE_STDCALL sqlite3_result_text(sqlite3_context*, const char*, int, void(*)(void*));
    - SQLITE_API void SQLITE_STDCALL sqlite3_result_text64(sqlite3_context*, const char*,sqlite3_uint64,
    -                            void(*)(void*), unsigned char encoding);
    +-** Display scan stats.
    ++** 2014-06-13
    ++**
    ++** 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 SQLite extension implements SQL functions readfile() and
    ++** writefile(), and eponymous virtual type "fsdir".
    ++**
    ++** WRITEFILE(FILE, DATA [, MODE [, MTIME]]):
    ++**
    ++**   If neither of the optional arguments is present, then this UDF
    ++**   function writes blob DATA to file FILE. If successful, the number
    ++**   of bytes written is returned. If an error occurs, NULL is returned.
    ++**
    ++**   If the first option argument - MODE - is present, then it must
    ++**   be passed an integer value that corresponds to a POSIX mode
    ++**   value (file type + permissions, as returned in the stat.st_mode
    ++**   field by the stat() system call). Three types of files may
    ++**   be written/created:
    ++**
    ++**     regular files:  (mode & 0170000)==0100000
    ++**     symbolic links: (mode & 0170000)==0120000
    ++**     directories:    (mode & 0170000)==0040000
    ++**
    ++**   For a directory, the DATA is ignored. For a symbolic link, it is
    ++**   interpreted as text and used as the target of the link. For a
    ++**   regular file, it is interpreted as a blob and written into the
    ++**   named file. Regardless of the type of file, its permissions are
    ++**   set to (mode & 0777) before returning.
    ++**
    ++**   If the optional MTIME argument is present, then it is interpreted
    ++**   as an integer - the number of seconds since the unix epoch. The
    ++**   modification-time of the target file is set to this value before
    ++**   returning.
    ++**
    ++**   If three or more arguments are passed to this function and an
    ++**   error is encountered, an exception is raised.
    ++**
    ++** READFILE(FILE):
    ++**
    ++**   Read and return the contents of file FILE (type blob) from disk.
    ++**
    ++** FSDIR:
    ++**
    ++**   Used as follows:
    ++**
    ++**     SELECT * FROM fsdir($path [, $dir]);
    ++**
    ++**   Parameter $path is an absolute or relative pathname. If the file that it
    ++**   refers to does not exist, it is an error. If the path refers to a regular
    ++**   file or symbolic link, it returns a single row. Or, if the path refers
    ++**   to a directory, it returns one row for the directory, and one row for each
    ++**   file within the hierarchy rooted at $path.
    ++**
    ++**   Each row has the following columns:
    ++**
    ++**     name:  Path to file or directory (text value).
    ++**     mode:  Value of stat.st_mode for directory entry (an integer).
    ++**     mtime: Value of stat.st_mtime for directory entry (an integer).
    ++**     data:  For a regular file, a blob containing the file data. For a
    ++**            symlink, a text value containing the text of the link. For a
    ++**            directory, NULL.
    ++**
    ++**   If a non-NULL value is specified for the optional $dir parameter and
    ++**   $path is a relative path, then $path is interpreted relative to $dir. 
    ++**   And the paths returned in the "name" column of the table are also 
    ++**   relative to directory $dir.
    + */
    +-static void display_scanstats(
    +-  sqlite3 *db,                    /* Database to query */
    +-  ShellState *pArg                /* Pointer to ShellState */
    +-){
    +-#ifndef SQLITE_ENABLE_STMT_SCANSTATUS
    +-  UNUSED_PARAMETER(db);
    +-  UNUSED_PARAMETER(pArg);
    ++SQLITE_EXTENSION_INIT1
    ++#include <stdio.h>
    ++#include <string.h>
    ++#include <assert.h>
    ++
    ++#include <sys/types.h>
    ++#include <sys/stat.h>
    ++#include <fcntl.h>
    ++#if !defined(_WIN32) && !defined(WIN32)
    ++#  include <unistd.h>
    ++#  include <dirent.h>
    ++#  include <utime.h>
    ++#  include <sys/time.h>
    + #else
    +-  int i, k, n, mx;
    +-  fprintf(pArg->out, "-------- scanstats --------\n");
    +-  mx = 0;
    +-  for(k=0; k<=mx; k++){
    +-    double rEstLoop = 1.0;
    +-    for(i=n=0; 1; i++){
    +-      sqlite3_stmt *p = pArg->pStmt;
    +-      sqlite3_int64 nLoop, nVisit;
    +-      double rEst;
    +-      int iSid;
    +-      const char *zExplain;
    +-      if( sqlite3_stmt_scanstatus(p, i, SQLITE_SCANSTAT_NLOOP, (void*)&nLoop) ){
    +-        break;
    +-      }
    +-      sqlite3_stmt_scanstatus(p, i, SQLITE_SCANSTAT_SELECTID, (void*)&iSid);
    +-      if( iSid>mx ) mx = iSid;
    +-      if( iSid!=k ) continue;
    +-      if( n==0 ){
    +-        rEstLoop = (double)nLoop;
    +-        if( k>0 ) fprintf(pArg->out, "-------- subquery %d -------\n", k);
    +-      }
    +-      n++;
    +-      sqlite3_stmt_scanstatus(p, i, SQLITE_SCANSTAT_NVISIT, (void*)&nVisit);
    +-      sqlite3_stmt_scanstatus(p, i, SQLITE_SCANSTAT_EST, (void*)&rEst);
    +-      sqlite3_stmt_scanstatus(p, i, SQLITE_SCANSTAT_EXPLAIN, (void*)&zExplain);
    +-      fprintf(pArg->out, "Loop %2d: %s\n", n, zExplain);
    +-      rEstLoop *= rEst;
    +-      fprintf(pArg->out, 
    +-          "         nLoop=%-8lld nRow=%-8lld estRow=%-8lld estRow/Loop=%-8g\n",
    +-          nLoop, nVisit, (sqlite3_int64)(rEstLoop+0.5), rEst
    +-      );
    +-    }
    +-  }
    +-  fprintf(pArg->out, "---------------------------\n");
    ++#  include "windows.h"
    ++#  include <io.h>
    ++#  include <direct.h>
    ++/* #  include "test_windirent.h" */
    ++#  define dirent DIRENT
    ++#  ifndef stat
    ++#    define stat _stat
    ++#  endif
    ++#  define mkdir(path,mode) _mkdir(path)
    ++#  define lstat(path,buf) stat(path,buf)
    + #endif
    +-}
    ++#include <time.h>
    ++#include <errno.h>
    ++
    ++
    ++#define FSDIR_SCHEMA "(name,mode,mtime,data,path HIDDEN,dir HIDDEN)"
    + 
    + /*
    +-** Parameter azArray points to a zero-terminated array of strings. zStr
    +-** points to a single nul-terminated string. Return non-zero if zStr
    +-** is equal, according to strcmp(), to any of the strings in the array.
    +-** Otherwise, return zero.
    ++** Set the result stored by context ctx to a blob containing the 
    ++** contents of file zName.
    + */
    +-static int str_in_array(const char *zStr, const char **azArray){
    +-  int i;
    +-  for(i=0; azArray[i]; i++){
    +-    if( 0==strcmp(zStr, azArray[i]) ) return 1;
    ++static void readFileContents(sqlite3_context *ctx, const char *zName){
    ++  FILE *in;
    ++  long nIn;
    ++  void *pBuf;
    ++
    ++  in = fopen(zName, "rb");
    ++  if( in==0 ) return;
    ++  fseek(in, 0, SEEK_END);
    ++  nIn = ftell(in);
    ++  rewind(in);
    ++  pBuf = sqlite3_malloc( nIn );
    ++  if( pBuf && 1==fread(pBuf, nIn, 1, in) ){
    ++    sqlite3_result_blob(ctx, pBuf, nIn, sqlite3_free);
    ++  }else{
    ++    sqlite3_free(pBuf);
    +   }
    +-  return 0;
    ++  fclose(in);
    + }
    + 
    + /*
    +-** If compiled statement pSql appears to be an EXPLAIN statement, allocate
    +-** and populate the ShellState.aiIndent[] array with the number of
    +-** spaces each opcode should be indented before it is output. 
    +-**
    +-** The indenting rules are:
    +-**
    +-**     * For each "Next", "Prev", "VNext" or "VPrev" instruction, indent
    +-**       all opcodes that occur between the p2 jump destination and the opcode
    +-**       itself by 2 spaces.
    +-**
    +-**     * For each "Goto", if the jump destination is earlier in the program
    +-**       and ends on one of:
    +-**          Yield  SeekGt  SeekLt  RowSetRead  Rewind
    +-**       or if the P1 parameter is one instead of zero,
    +-**       then indent all opcodes between the earlier instruction
    +-**       and "Goto" by 2 spaces.
    ++** Implementation of the "readfile(X)" SQL function.  The entire content
    ++** of the file named X is read and returned as a BLOB.  NULL is returned
    ++** if the file does not exist or is unreadable.
    + */
    +-static void explain_data_prepare(ShellState *p, sqlite3_stmt *pSql){
    +-  const char *zSql;               /* The text of the SQL statement */
    +-  const char *z;                  /* Used to check if this is an EXPLAIN */
    +-  int *abYield = 0;               /* True if op is an OP_Yield */
    +-  int nAlloc = 0;                 /* Allocated size of p->aiIndent[], abYield */
    +-  int iOp;                        /* Index of operation in p->aiIndent[] */
    +-
    +-  const char *azNext[] = { "Next", "Prev", "VPrev", "VNext", "SorterNext",
    +-                           "NextIfOpen", "PrevIfOpen", 0 };
    +-  const char *azYield[] = { "Yield", "SeekLT", "SeekGT", "RowSetRead",
    +-                            "Rewind", 0 };
    +-  const char *azGoto[] = { "Goto", 0 };
    +-
    +-  /* Try to figure out if this is really an EXPLAIN statement. If this
    +-  ** cannot be verified, return early.  */
    +-  zSql = sqlite3_sql(pSql);
    +-  if( zSql==0 ) return;
    +-  for(z=zSql; *z==' ' || *z=='\t' || *z=='\n' || *z=='\f' || *z=='\r'; z++);
    +-  if( sqlite3_strnicmp(z, "explain", 7) ) return;
    +-
    +-  for(iOp=0; SQLITE_ROW==sqlite3_step(pSql); iOp++){
    +-    int i;
    +-    int iAddr = sqlite3_column_int(pSql, 0);
    +-    const char *zOp = (const char*)sqlite3_column_text(pSql, 1);
    +-
    +-    /* Set p2 to the P2 field of the current opcode. Then, assuming that
    +-    ** p2 is an instruction address, set variable p2op to the index of that
    +-    ** instruction in the aiIndent[] array. p2 and p2op may be different if
    +-    ** the current instruction is part of a sub-program generated by an
    +-    ** SQL trigger or foreign key.  */
    +-    int p2 = sqlite3_column_int(pSql, 3);
    +-    int p2op = (p2 + (iOp-iAddr));
    +-
    +-    /* Grow the p->aiIndent array as required */
    +-    if( iOp>=nAlloc ){
    +-      nAlloc += 100;
    +-      p->aiIndent = (int*)sqlite3_realloc64(p->aiIndent, nAlloc*sizeof(int));
    +-      abYield = (int*)sqlite3_realloc64(abYield, nAlloc*sizeof(int));
    +-    }
    +-    abYield[iOp] = str_in_array(zOp, azYield);
    +-    p->aiIndent[iOp] = 0;
    +-    p->nIndent = iOp+1;
    +-
    +-    if( str_in_array(zOp, azNext) ){
    +-      for(i=p2op; i<iOp; i++) p->aiIndent[i] += 2;
    +-    }
    +-    if( str_in_array(zOp, azGoto) && p2op<p->nIndent
    +-     && (abYield[p2op] || sqlite3_column_int(pSql, 2))
    +-    ){
    +-      for(i=p2op+1; i<iOp; i++) p->aiIndent[i] += 2;
    +-    }
    +-  }
    +-
    +-  p->iIndent = 0;
    +-  sqlite3_free(abYield);
    +-  sqlite3_reset(pSql);
    ++static void readfileFunc(
    ++  sqlite3_context *context,
    ++  int argc,
    ++  sqlite3_value **argv
    ++){
    ++  const char *zName;
    ++  (void)(argc);  /* Unused parameter */
    ++  zName = (const char*)sqlite3_value_text(argv[0]);
    ++  if( zName==0 ) return;
    ++  readFileContents(context, zName);
    + }
    + 
    + /*
    +-** Free the array allocated by explain_data_prepare().
    ++** Set the error message contained in context ctx to the results of
    ++** vprintf(zFmt, ...).
    + */
    +-static void explain_data_delete(ShellState *p){
    +-  sqlite3_free(p->aiIndent);
    +-  p->aiIndent = 0;
    +-  p->nIndent = 0;
    +-  p->iIndent = 0;
    ++static void ctxErrorMsg(sqlite3_context *ctx, const char *zFmt, ...){
    ++  char *zMsg = 0;
    ++  va_list ap;
    ++  va_start(ap, zFmt);
    ++  zMsg = sqlite3_vmprintf(zFmt, ap);
    ++  sqlite3_result_error(ctx, zMsg, -1);
    ++  sqlite3_free(zMsg);
    ++  va_end(ap);
    + }
    + 
    + /*
    +-** Execute a statement or set of statements.  Print 
    +-** any result rows/columns depending on the current mode 
    +-** set via the supplied callback.
    ++** Argument zFile is the name of a file that will be created and/or written
    ++** by SQL function writefile(). This function ensures that the directory
    ++** zFile will be written to exists, creating it if required. The permissions
    ++** for any path components created by this function are set to (mode&0777).
    + **
    +-** This is very similar to SQLite's built-in sqlite3_exec() 
    +-** function except it takes a slightly different callback 
    +-** and callback data argument.
    ++** If an OOM condition is encountered, SQLITE_NOMEM is returned. Otherwise,
    ++** SQLITE_OK is returned if the directory is successfully created, or
    ++** SQLITE_ERROR otherwise.
    + */
    +-static int shell_exec(
    +-  sqlite3 *db,                              /* An open database */
    +-  const char *zSql,                         /* SQL to be evaluated */
    +-  int (*xCallback)(void*,int,char**,char**,int*),   /* Callback function */
    +-                                            /* (not the same as sqlite3_exec) */
    +-  ShellState *pArg,                         /* Pointer to ShellState */
    +-  char **pzErrMsg                           /* Error msg written here */
    ++static int makeDirectory(
    ++  const char *zFile,
    ++  mode_t mode
    + ){
    +-  sqlite3_stmt *pStmt = NULL;     /* Statement to execute. */
    +-  int rc = SQLITE_OK;             /* Return Code */
    +-  int rc2;
    +-  const char *zLeftover;          /* Tail of unprocessed SQL */
    ++  char *zCopy = sqlite3_mprintf("%s", zFile);
    ++  int rc = SQLITE_OK;
    + 
    +-  if( pzErrMsg ){
    +-    *pzErrMsg = NULL;
    +-  }
    ++  if( zCopy==0 ){
    ++    rc = SQLITE_NOMEM;
    ++  }else{
    ++    int nCopy = (int)strlen(zCopy);
    ++    int i = 1;
    + 
    +-  while( zSql[0] && (SQLITE_OK == rc) ){
    +-    rc = sqlite3_prepare_v2(db, zSql, -1, &pStmt, &zLeftover);
    +-    if( SQLITE_OK != rc ){
    +-      if( pzErrMsg ){
    +-        *pzErrMsg = save_err_msg(db);
    +-      }
    +-    }else{
    +-      if( !pStmt ){
    +-        /* this happens for a comment or white-space */
    +-        zSql = zLeftover;
    +-        while( IsSpace(zSql[0]) ) zSql++;
    +-        continue;
    +-      }
    ++    while( rc==SQLITE_OK ){
    ++      struct stat sStat;
    ++      int rc2;
    + 
    +-      /* save off the prepared statment handle and reset row count */
    +-      if( pArg ){
    +-        pArg->pStmt = pStmt;
    +-        pArg->cnt = 0;
    +-      }
    ++      for(; zCopy[i]!='/' && i<nCopy; i++);
    ++      if( i==nCopy ) break;
    ++      zCopy[i] = '\0';
    + 
    +-      /* echo the sql statement if echo on */
    +-      if( pArg && pArg->echoOn ){
    +-        const char *zStmtSql = sqlite3_sql(pStmt);
    +-        fprintf(pArg->out, "%s\n", zStmtSql ? zStmtSql : zSql);
    ++      rc2 = stat(zCopy, &sStat);
    ++      if( rc2!=0 ){
    ++        if( mkdir(zCopy, mode & 0777) ) rc = SQLITE_ERROR;
    ++      }else{
    ++        if( !S_ISDIR(sStat.st_mode) ) rc = SQLITE_ERROR;
    +       }
    ++      zCopy[i] = '/';
    ++      i++;
    ++    }
    + 
    +-      /* Show the EXPLAIN QUERY PLAN if .eqp is on */
    +-      if( pArg && pArg->autoEQP ){
    +-        sqlite3_stmt *pExplain;
    +-        char *zEQP = sqlite3_mprintf("EXPLAIN QUERY PLAN %s",
    +-                                     sqlite3_sql(pStmt));
    +-        rc = sqlite3_prepare_v2(db, zEQP, -1, &pExplain, 0);
    +-        if( rc==SQLITE_OK ){
    +-          while( sqlite3_step(pExplain)==SQLITE_ROW ){
    +-            fprintf(pArg->out,"--EQP-- %d,", sqlite3_column_int(pExplain, 0));
    +-            fprintf(pArg->out,"%d,", sqlite3_column_int(pExplain, 1));
    +-            fprintf(pArg->out,"%d,", sqlite3_column_int(pExplain, 2));
    +-            fprintf(pArg->out,"%s\n", sqlite3_column_text(pExplain, 3));
    +-          }
    +-        }
    +-        sqlite3_finalize(pExplain);
    +-        sqlite3_free(zEQP);
    +-      }
    ++    sqlite3_free(zCopy);
    ++  }
    + 
    +-      /* If the shell is currently in ".explain" mode, gather the extra
    +-      ** data required to add indents to the output.*/
    +-      if( pArg && pArg->mode==MODE_Explain ){
    +-        explain_data_prepare(pArg, pStmt);
    +-      }
    ++  return rc;
    ++}
    + 
    +-      /* perform the first step.  this will tell us if we
    +-      ** have a result set or not and how wide it is.
    +-      */
    +-      rc = sqlite3_step(pStmt);
    +-      /* if we have a result set... */
    +-      if( SQLITE_ROW == rc ){
    +-        /* if we have a callback... */
    +-        if( xCallback ){
    +-          /* allocate space for col name ptr, value ptr, and type */
    +-          int nCol = sqlite3_column_count(pStmt);
    +-          void *pData = sqlite3_malloc64(3*nCol*sizeof(const char*) + 1);
    +-          if( !pData ){
    +-            rc = SQLITE_NOMEM;
    +-          }else{
    +-            char **azCols = (char **)pData;      /* Names of result columns */
    +-            char **azVals = &azCols[nCol];       /* Results */
    +-            int *aiTypes = (int *)&azVals[nCol]; /* Result types */
    +-            int i, x;
    +-            assert(sizeof(int) <= sizeof(char *)); 
    +-            /* save off ptrs to column names */
    +-            for(i=0; i<nCol; i++){
    +-              azCols[i] = (char *)sqlite3_column_name(pStmt, i);
    +-            }
    +-            do{
    +-              /* extract the data and data types */
    +-              for(i=0; i<nCol; i++){
    +-                aiTypes[i] = x = sqlite3_column_type(pStmt, i);
    +-                if( x==SQLITE_BLOB && pArg && pArg->mode==MODE_Insert ){
    +-                  azVals[i] = "";
    +-                }else{
    +-                  azVals[i] = (char*)sqlite3_column_text(pStmt, i);
    +-                }
    +-                if( !azVals[i] && (aiTypes[i]!=SQLITE_NULL) ){
    +-                  rc = SQLITE_NOMEM;
    +-                  break; /* from for */
    +-                }
    +-              } /* end for */
    +-
    +-              /* if data and types extracted successfully... */
    +-              if( SQLITE_ROW == rc ){ 
    +-                /* call the supplied callback with the result row data */
    +-                if( xCallback(pArg, nCol, azVals, azCols, aiTypes) ){
    +-                  rc = SQLITE_ABORT;
    +-                }else{
    +-                  rc = sqlite3_step(pStmt);
    +-                }
    +-              }
    +-            } while( SQLITE_ROW == rc );
    +-            sqlite3_free(pData);
    +-          }
    +-        }else{
    +-          do{
    +-            rc = sqlite3_step(pStmt);
    +-          } while( rc == SQLITE_ROW );
    ++/*
    ++** This function does the work for the writefile() UDF. Refer to 
    ++** header comments at the top of this file for details.
    ++*/
    ++static int writeFile(
    ++  sqlite3_context *pCtx,          /* Context to return bytes written in */
    ++  const char *zFile,              /* File to write */
    ++  sqlite3_value *pData,           /* Data to write */
    ++  mode_t mode,                    /* MODE parameter passed to writefile() */
    ++  sqlite3_int64 mtime             /* MTIME parameter (or -1 to not set time) */
    ++){
    ++#if !defined(_WIN32) && !defined(WIN32)
    ++  if( S_ISLNK(mode) ){
    ++    const char *zTo = (const char*)sqlite3_value_text(pData);
    ++    if( symlink(zTo, zFile)<0 ) return 1;
    ++  }else
    ++#endif
    ++  {
    ++    if( S_ISDIR(mode) ){
    ++      if( mkdir(zFile, mode) ){
    ++        /* The mkdir() call to create the directory failed. This might not
    ++        ** be an error though - if there is already a directory at the same
    ++        ** path and either the permissions already match or can be changed
    ++        ** to do so using chmod(), it is not an error.  */
    ++        struct stat sStat;
    ++        if( errno!=EEXIST
    ++         || 0!=stat(zFile, &sStat)
    ++         || !S_ISDIR(sStat.st_mode)
    ++         || ((sStat.st_mode&0777)!=(mode&0777) && 0!=chmod(zFile, mode&0777))
    ++        ){
    ++          return 1;
    +         }
    +       }
    +-
    +-      explain_data_delete(pArg);
    +-
    +-      /* print usage stats if stats on */
    +-      if( pArg && pArg->statsOn ){
    +-        display_stats(db, pArg, 0);
    +-      }
    +-
    +-      /* print loop-counters if required */
    +-      if( pArg && pArg->scanstatsOn ){
    +-        display_scanstats(db, pArg);
    ++    }else{
    ++      sqlite3_int64 nWrite = 0;
    ++      const char *z;
    ++      int rc = 0;
    ++      FILE *out = fopen(zFile, "wb");
    ++      if( out==0 ) return 1;
    ++      z = (const char*)sqlite3_value_blob(pData);
    ++      if( z ){
    ++        sqlite3_int64 n = fwrite(z, 1, sqlite3_value_bytes(pData), out);
    ++        nWrite = sqlite3_value_bytes(pData);
    ++        if( nWrite!=n ){
    ++          rc = 1;
    ++        }
    +       }
    +-
    +-      /* Finalize the statement just executed. If this fails, save a 
    +-      ** copy of the error message. Otherwise, set zSql to point to the
    +-      ** next statement to execute. */
    +-      rc2 = sqlite3_finalize(pStmt);
    +-      if( rc!=SQLITE_NOMEM ) rc = rc2;
    +-      if( rc==SQLITE_OK ){
    +-        zSql = zLeftover;
    +-        while( IsSpace(zSql[0]) ) zSql++;
    +-      }else if( pzErrMsg ){
    +-        *pzErrMsg = save_err_msg(db);
    ++      fclose(out);
    ++      if( rc==0 && mode && chmod(zFile, mode & 0777) ){
    ++        rc = 1;
    +       }
    ++      if( rc ) return 2;
    ++      sqlite3_result_int64(pCtx, nWrite);
    ++    }
    ++  }
    + 
    +-      /* clear saved stmt handle */
    +-      if( pArg ){
    +-        pArg->pStmt = NULL;
    +-      }
    ++  if( mtime>=0 ){
    ++#if defined(_WIN32)
    ++    /* Windows */
    ++    FILETIME lastAccess;
    ++    FILETIME lastWrite;
    ++    SYSTEMTIME currentTime;
    ++    LONGLONG intervals;
    ++    HANDLE hFile;
    ++    GetSystemTime(&currentTime);
    ++    SystemTimeToFileTime(&currentTime, &lastAccess);
    ++    intervals = Int32x32To64(mtime, 10000000) + 116444736000000000;
    ++    lastWrite.dwLowDateTime = (DWORD)intervals;
    ++    lastWrite.dwHighDateTime = intervals >> 32;
    ++    hFile = CreateFile(
    ++      zFile, FILE_WRITE_ATTRIBUTES, 0, NULL, OPEN_EXISTING,
    ++      FILE_FLAG_BACKUP_SEMANTICS, NULL
    ++    );
    ++    if( hFile!=INVALID_HANDLE_VALUE ){
    ++      BOOL bResult = SetFileTime(hFile, NULL, &lastAccess, &lastWrite);
    ++      CloseHandle(hFile);
    ++      return !bResult;
    ++    }else{
    ++      return 1;
    +     }
    +-  } /* end while */
    ++#elif defined(AT_FDCWD) && 0 /* utimensat() is not univerally available */
    ++    /* Recent unix */
    ++    struct timespec times[2];
    ++    times[0].tv_nsec = times[1].tv_nsec = 0;
    ++    times[0].tv_sec = time(0);
    ++    times[1].tv_sec = mtime;
    ++    if( utimensat(AT_FDCWD, zFile, times, AT_SYMLINK_NOFOLLOW) ){
    ++      return 1;
    ++    }
    ++#else
    ++    /* Legacy unix */
    ++    struct timeval times[2];
    ++    times[0].tv_usec = times[1].tv_usec = 0;
    ++    times[0].tv_sec = time(0);
    ++    times[1].tv_sec = mtime;
    ++    if( utimes(zFile, times) ){
    ++      return 1;
    ++    }
    ++#endif
    ++  }
    + 
    +-  return rc;
    ++  return 0;
    + }
    + 
    +-
    + /*
    +-** This is a different callback routine used for dumping the database.
    +-** Each row received by this callback consists of a table name,
    +-** the table type ("index" or "table") and SQL to create the table.
    +-** This routine should print text sufficient to recreate the table.
    ++** Implementation of the "writefile(W,X[,Y[,Z]]])" SQL function.  
    ++** Refer to header comments at the top of this file for details.
    + */
    +-static int dump_callback(void *pArg, int nArg, char **azArg, char **azCol){
    +-  int rc;
    +-  const char *zTable;
    +-  const char *zType;
    +-  const char *zSql;
    +-  const char *zPrepStmt = 0;
    +-  ShellState *p = (ShellState *)pArg;
    ++static void writefileFunc(
    ++  sqlite3_context *context,
    ++  int argc,
    ++  sqlite3_value **argv
    ++){
    ++  const char *zFile;
    ++  mode_t mode = 0;
    ++  int res;
    ++  sqlite3_int64 mtime = -1;
    + 
    +-  UNUSED_PARAMETER(azCol);
    +-  if( nArg!=3 ) return 1;
    +-  zTable = azArg[0];
    +-  zType = azArg[1];
    +-  zSql = azArg[2];
    +-  
    +-  if( strcmp(zTable, "sqlite_sequence")==0 ){
    +-    zPrepStmt = "DELETE FROM sqlite_sequence;\n";
    +-  }else if( sqlite3_strglob("sqlite_stat?", zTable)==0 ){
    +-    fprintf(p->out, "ANALYZE sqlite_master;\n");
    +-  }else if( strncmp(zTable, "sqlite_", 7)==0 ){
    +-    return 0;
    +-  }else if( strncmp(zSql, "CREATE VIRTUAL TABLE", 20)==0 ){
    +-    char *zIns;
    +-    if( !p->writableSchema ){
    +-      fprintf(p->out, "PRAGMA writable_schema=ON;\n");
    +-      p->writableSchema = 1;
    +-    }
    +-    zIns = sqlite3_mprintf(
    +-       "INSERT INTO sqlite_master(type,name,tbl_name,rootpage,sql)"
    +-       "VALUES('table','%q','%q',0,'%q');",
    +-       zTable, zTable, zSql);
    +-    fprintf(p->out, "%s\n", zIns);
    +-    sqlite3_free(zIns);
    +-    return 0;
    +-  }else{
    +-    fprintf(p->out, "%s;\n", zSql);
    ++  if( argc<2 || argc>4 ){
    ++    sqlite3_result_error(context, 
    ++        "wrong number of arguments to function writefile()", -1
    ++    );
    ++    return;
    +   }
    + 
    +-  if( strcmp(zType, "table")==0 ){
    +-    sqlite3_stmt *pTableInfo = 0;
    +-    char *zSelect = 0;
    +-    char *zTableInfo = 0;
    +-    char *zTmp = 0;
    +-    int nRow = 0;
    +-   
    +-    zTableInfo = appendText(zTableInfo, "PRAGMA table_info(", 0);
    +-    zTableInfo = appendText(zTableInfo, zTable, '"');
    +-    zTableInfo = appendText(zTableInfo, ");", 0);
    +-
    +-    rc = sqlite3_prepare_v2(p->db, zTableInfo, -1, &pTableInfo, 0);
    +-    free(zTableInfo);
    +-    if( rc!=SQLITE_OK || !pTableInfo ){
    +-      return 1;
    +-    }
    ++  zFile = (const char*)sqlite3_value_text(argv[0]);
    ++  if( zFile==0 ) return;
    ++  if( argc>=3 ){
    ++    mode = (mode_t)sqlite3_value_int(argv[2]);
    ++  }
    ++  if( argc==4 ){
    ++    mtime = sqlite3_value_int64(argv[3]);
    ++  }
    + 
    +-    zSelect = appendText(zSelect, "SELECT 'INSERT INTO ' || ", 0);
    +-    /* Always quote the table name, even if it appears to be pure ascii,
    +-    ** in case it is a keyword. Ex:  INSERT INTO "table" ... */
    +-    zTmp = appendText(zTmp, zTable, '"');
    +-    if( zTmp ){
    +-      zSelect = appendText(zSelect, zTmp, '\'');
    +-      free(zTmp);
    +-    }
    +-    zSelect = appendText(zSelect, " || ' VALUES(' || ", 0);
    +-    rc = sqlite3_step(pTableInfo);
    +-    while( rc==SQLITE_ROW ){
    +-      const char *zText = (const char *)sqlite3_column_text(pTableInfo, 1);
    +-      zSelect = appendText(zSelect, "quote(", 0);
    +-      zSelect = appendText(zSelect, zText, '"');
    +-      rc = sqlite3_step(pTableInfo);
    +-      if( rc==SQLITE_ROW ){
    +-        zSelect = appendText(zSelect, "), ", 0);
    +-      }else{
    +-        zSelect = appendText(zSelect, ") ", 0);
    +-      }
    +-      nRow++;
    +-    }
    +-    rc = sqlite3_finalize(pTableInfo);
    +-    if( rc!=SQLITE_OK || nRow==0 ){
    +-      free(zSelect);
    +-      return 1;
    ++  res = writeFile(context, zFile, argv[1], mode, mtime);
    ++  if( res==1 && errno==ENOENT ){
    ++    if( makeDirectory(zFile, mode)==SQLITE_OK ){
    ++      res = writeFile(context, zFile, argv[1], mode, mtime);
    +     }
    +-    zSelect = appendText(zSelect, "|| ')' FROM  ", 0);
    +-    zSelect = appendText(zSelect, zTable, '"');
    ++  }
    + 
    +-    rc = run_table_dump_query(p, zSelect, zPrepStmt);
    +-    if( rc==SQLITE_CORRUPT ){
    +-      zSelect = appendText(zSelect, " ORDER BY rowid DESC", 0);
    +-      run_table_dump_query(p, zSelect, 0);
    ++  if( argc>2 && res!=0 ){
    ++    if( S_ISLNK(mode) ){
    ++      ctxErrorMsg(context, "failed to create symlink: %s", zFile);
    ++    }else if( S_ISDIR(mode) ){
    ++      ctxErrorMsg(context, "failed to create directory: %s", zFile);
    ++    }else{
    ++      ctxErrorMsg(context, "failed to write file: %s", zFile);
    +     }
    +-    free(zSelect);
    +   }
    +-  return 0;
    + }
    + 
    + /*
    +-** Run zQuery.  Use dump_callback() as the callback routine so that
    +-** the contents of the query are output as SQL statements.
    ++** SQL function:   lsmode(MODE)
    + **
    +-** If we get a SQLITE_CORRUPT error, rerun the query after appending
    +-** "ORDER BY rowid DESC" to the end.
    ++** Given a numberic st_mode from stat(), convert it into a human-readable
    ++** text string in the style of "ls -l".
    + */
    +-static int run_schema_dump_query(
    +-  ShellState *p, 
    +-  const char *zQuery
    ++static void lsModeFunc(
    ++  sqlite3_context *context,
    ++  int argc,
    ++  sqlite3_value **argv
    ++){
    ++  int i;
    ++  int iMode = sqlite3_value_int(argv[0]);
    ++  char z[16];
    ++  (void)argc;
    ++  if( S_ISLNK(iMode) ){
    ++    z[0] = 'l';
    ++  }else if( S_ISREG(iMode) ){
    ++    z[0] = '-';
    ++  }else if( S_ISDIR(iMode) ){
    ++    z[0] = 'd';
    ++  }else{
    ++    z[0] = '?';
    ++  }
    ++  for(i=0; i<3; i++){
    ++    int m = (iMode >> ((2-i)*3));
    ++    char *a = &z[1 + i*3];
    ++    a[0] = (m & 0x4) ? 'r' : '-';
    ++    a[1] = (m & 0x2) ? 'w' : '-';
    ++    a[2] = (m & 0x1) ? 'x' : '-';
    ++  }
    ++  z[10] = '\0';
    ++  sqlite3_result_text(context, z, -1, SQLITE_TRANSIENT);
    ++}
    ++
    ++#ifndef SQLITE_OMIT_VIRTUALTABLE
    ++
    ++/* 
    ++** Cursor type for recursively iterating through a directory structure.
    ++*/
    ++typedef struct fsdir_cursor fsdir_cursor;
    ++typedef struct FsdirLevel FsdirLevel;
    ++
    ++struct FsdirLevel {
    ++  DIR *pDir;                 /* From opendir() */
    ++  char *zDir;                /* Name of directory (nul-terminated) */
    ++};
    ++
    ++struct fsdir_cursor {
    ++  sqlite3_vtab_cursor base;  /* Base class - must be first */
    ++
    ++  int nLvl;                  /* Number of entries in aLvl[] array */
    ++  int iLvl;                  /* Index of current entry */
    ++  FsdirLevel *aLvl;          /* Hierarchy of directories being traversed */
    ++
    ++  const char *zBase;
    ++  int nBase;
    ++
    ++  struct stat sStat;         /* Current lstat() results */
    ++  char *zPath;               /* Path to current entry */
    ++  sqlite3_int64 iRowid;      /* Current rowid */
    ++};
    ++
    ++typedef struct fsdir_tab fsdir_tab;
    ++struct fsdir_tab {
    ++  sqlite3_vtab base;         /* Base class - must be first */
    ++};
    ++
    ++/*
    ++** Construct a new fsdir virtual table object.
    ++*/
    ++static int fsdirConnect(
    ++  sqlite3 *db,
    ++  void *pAux,
    ++  int argc, const char *const*argv,
    ++  sqlite3_vtab **ppVtab,
    ++  char **pzErr
    + ){
    ++  fsdir_tab *pNew = 0;
    +   int rc;
    +-  char *zErr = 0;
    +-  rc = sqlite3_exec(p->db, zQuery, dump_callback, p, &zErr);
    +-  if( rc==SQLITE_CORRUPT ){
    +-    char *zQ2;
    +-    int len = strlen30(zQuery);
    +-    fprintf(p->out, "/****** CORRUPTION ERROR *******/\n");
    +-    if( zErr ){
    +-      fprintf(p->out, "/****** %s ******/\n", zErr);
    +-      sqlite3_free(zErr);
    +-      zErr = 0;
    ++  (void)pAux;
    ++  (void)argc;
    ++  (void)argv;
    ++  (void)pzErr;
    ++  rc = sqlite3_declare_vtab(db, "CREATE TABLE x" FSDIR_SCHEMA);
    ++  if( rc==SQLITE_OK ){
    ++    pNew = (fsdir_tab*)sqlite3_malloc( sizeof(*pNew) );
    ++    if( pNew==0 ) return SQLITE_NOMEM;
    ++    memset(pNew, 0, sizeof(*pNew));
    ++  }
    ++  *ppVtab = (sqlite3_vtab*)pNew;
    ++  return rc;
    ++}
    ++
    ++/*
    ++** This method is the destructor for fsdir vtab objects.
    ++*/
    ++static int fsdirDisconnect(sqlite3_vtab *pVtab){
    ++  sqlite3_free(pVtab);
    ++  return SQLITE_OK;
    ++}
    ++
    ++/*
    ++** Constructor for a new fsdir_cursor object.
    ++*/
    ++static int fsdirOpen(sqlite3_vtab *p, sqlite3_vtab_cursor **ppCursor){
    ++  fsdir_cursor *pCur;
    ++  (void)p;
    ++  pCur = sqlite3_malloc( sizeof(*pCur) );
    ++  if( pCur==0 ) return SQLITE_NOMEM;
    ++  memset(pCur, 0, sizeof(*pCur));
    ++  pCur->iLvl = -1;
    ++  *ppCursor = &pCur->base;
    ++  return SQLITE_OK;
    ++}
    ++
    ++/*
    ++** Reset a cursor back to the state it was in when first returned
    ++** by fsdirOpen().
    ++*/
    ++static void fsdirResetCursor(fsdir_cursor *pCur){
    ++  int i;
    ++  for(i=0; i<=pCur->iLvl; i++){
    ++    FsdirLevel *pLvl = &pCur->aLvl[i];
    ++    if( pLvl->pDir ) closedir(pLvl->pDir);
    ++    sqlite3_free(pLvl->zDir);
    ++  }
    ++  sqlite3_free(pCur->zPath);
    ++  pCur->aLvl = 0;
    ++  pCur->zPath = 0;
    ++  pCur->zBase = 0;
    ++  pCur->nBase = 0;
    ++  pCur->iLvl = -1;
    ++  pCur->iRowid = 1;
    ++}
    ++
    ++/*
    ++** Destructor for an fsdir_cursor.
    ++*/
    ++static int fsdirClose(sqlite3_vtab_cursor *cur){
    ++  fsdir_cursor *pCur = (fsdir_cursor*)cur;
    ++
    ++  fsdirResetCursor(pCur);
    ++  sqlite3_free(pCur->aLvl);
    ++  sqlite3_free(pCur);
    ++  return SQLITE_OK;
    ++}
    ++
    ++/*
    ++** Set the error message for the virtual table associated with cursor
    ++** pCur to the results of vprintf(zFmt, ...).
    ++*/
    ++static void fsdirSetErrmsg(fsdir_cursor *pCur, const char *zFmt, ...){
    ++  va_list ap;
    ++  va_start(ap, zFmt);
    ++  pCur->base.pVtab->zErrMsg = sqlite3_vmprintf(zFmt, ap);
    ++  va_end(ap);
    ++}
    ++
    ++
    ++/*
    ++** Advance an fsdir_cursor to its next row of output.
    ++*/
    ++static int fsdirNext(sqlite3_vtab_cursor *cur){
    ++  fsdir_cursor *pCur = (fsdir_cursor*)cur;
    ++  mode_t m = pCur->sStat.st_mode;
    ++
    ++  pCur->iRowid++;
    ++  if( S_ISDIR(m) ){
    ++    /* Descend into this directory */
    ++    int iNew = pCur->iLvl + 1;
    ++    FsdirLevel *pLvl;
    ++    if( iNew>=pCur->nLvl ){
    ++      int nNew = iNew+1;
    ++      int nByte = nNew*sizeof(FsdirLevel);
    ++      FsdirLevel *aNew = (FsdirLevel*)sqlite3_realloc(pCur->aLvl, nByte);
    ++      if( aNew==0 ) return SQLITE_NOMEM;
    ++      memset(&aNew[pCur->nLvl], 0, sizeof(FsdirLevel)*(nNew-pCur->nLvl));
    ++      pCur->aLvl = aNew;
    ++      pCur->nLvl = nNew;
    ++    }
    ++    pCur->iLvl = iNew;
    ++    pLvl = &pCur->aLvl[iNew];
    ++    
    ++    pLvl->zDir = pCur->zPath;
    ++    pCur->zPath = 0;
    ++    pLvl->pDir = opendir(pLvl->zDir);
    ++    if( pLvl->pDir==0 ){
    ++      fsdirSetErrmsg(pCur, "cannot read directory: %s", pCur->zPath);
    ++      return SQLITE_ERROR;
    +     }
    +-    zQ2 = malloc( len+100 );
    +-    if( zQ2==0 ) return rc;
    +-    sqlite3_snprintf(len+100, zQ2, "%s ORDER BY rowid DESC", zQuery);
    +-    rc = sqlite3_exec(p->db, zQ2, dump_callback, p, &zErr);
    +-    if( rc ){
    +-      fprintf(p->out, "/****** ERROR: %s ******/\n", zErr);
    +-    }else{
    +-      rc = SQLITE_CORRUPT;
    ++  }
    ++
    ++  while( pCur->iLvl>=0 ){
    ++    FsdirLevel *pLvl = &pCur->aLvl[pCur->iLvl];
    ++    struct dirent *pEntry = readdir(pLvl->pDir);
    ++    if( pEntry ){
    ++      if( pEntry->d_name[0]=='.' ){
    ++       if( pEntry->d_name[1]=='.' && pEntry->d_name[2]=='\0' ) continue;
    ++       if( pEntry->d_name[1]=='\0' ) continue;
    ++      }
    ++      sqlite3_free(pCur->zPath);
    ++      pCur->zPath = sqlite3_mprintf("%s/%s", pLvl->zDir, pEntry->d_name);
    ++      if( pCur->zPath==0 ) return SQLITE_NOMEM;
    ++      if( lstat(pCur->zPath, &pCur->sStat) ){
    ++        fsdirSetErrmsg(pCur, "cannot stat file: %s", pCur->zPath);
    ++        return SQLITE_ERROR;
    ++      }
    ++      return SQLITE_OK;
    +     }
    +-    sqlite3_free(zErr);
    +-    free(zQ2);
    ++    closedir(pLvl->pDir);
    ++    sqlite3_free(pLvl->zDir);
    ++    pLvl->pDir = 0;
    ++    pLvl->zDir = 0;
    ++    pCur->iLvl--;
    +   }
    +-  return rc;
    ++
    ++  /* EOF */
    ++  sqlite3_free(pCur->zPath);
    ++  pCur->zPath = 0;
    ++  return SQLITE_OK;
    + }
    + 
    + /*
    +-** Text of a help message
    ++** Return values of columns for the row at which the series_cursor
    ++** is currently pointing.
    + */
    +-static char zHelp[] =
    +-  ".backup ?DB? FILE      Backup DB (default \"main\") to FILE\n"
    +-  ".bail on|off           Stop after hitting an error.  Default OFF\n"
    +-  ".binary on|off         Turn binary output on or off.  Default OFF\n"
    +-  ".clone NEWDB           Clone data into NEWDB from the existing database\n"
    +-  ".databases             List names and files of attached databases\n"
    +-  ".dbinfo ?DB?           Show status information about the database\n"
    +-  ".dump ?TABLE? ...      Dump the database in an SQL text format\n"
    +-  "                         If TABLE specified, only dump tables matching\n"
    +-  "                         LIKE pattern TABLE.\n"
    +-  ".echo on|off           Turn command echo on or off\n"
    +-  ".eqp on|off            Enable or disable automatic EXPLAIN QUERY PLAN\n"
    +-  ".exit                  Exit this program\n"
    +-  ".explain ?on|off?      Turn output mode suitable for EXPLAIN on or off.\n"
    +-  "                         With no args, it turns EXPLAIN on.\n"
    +-  ".fullschema            Show schema and the content of sqlite_stat tables\n"
    +-  ".headers on|off        Turn display of headers on or off\n"
    +-  ".help                  Show this message\n"
    +-  ".import FILE TABLE     Import data from FILE into TABLE\n"
    +-  ".indexes ?TABLE?       Show names of all indexes\n"
    +-  "                         If TABLE specified, only show indexes for tables\n"
    +-  "                         matching LIKE pattern TABLE.\n"
    +-#ifdef SQLITE_ENABLE_IOTRACE
    +-  ".iotrace FILE          Enable I/O diagnostic logging to FILE\n"
    +-#endif
    +-  ".limit ?LIMIT? ?VAL?   Display or change the value of an SQLITE_LIMIT\n"
    +-#ifndef SQLITE_OMIT_LOAD_EXTENSION
    +-  ".load FILE ?ENTRY?     Load an extension library\n"
    ++static int fsdirColumn(
    ++  sqlite3_vtab_cursor *cur,   /* The cursor */
    ++  sqlite3_context *ctx,       /* First argument to sqlite3_result_...() */
    ++  int i                       /* Which column to return */
    ++){
    ++  fsdir_cursor *pCur = (fsdir_cursor*)cur;
    ++  switch( i ){
    ++    case 0: { /* name */
    ++      sqlite3_result_text(ctx, &pCur->zPath[pCur->nBase], -1, SQLITE_TRANSIENT);
    ++      break;
    ++    }
    ++
    ++    case 1: /* mode */
    ++      sqlite3_result_int64(ctx, pCur->sStat.st_mode);
    ++      break;
    ++
    ++    case 2: /* mtime */
    ++      sqlite3_result_int64(ctx, pCur->sStat.st_mtime);
    ++      break;
    ++
    ++    case 3: { /* data */
    ++      mode_t m = pCur->sStat.st_mode;
    ++      if( S_ISDIR(m) ){
    ++        sqlite3_result_null(ctx);
    ++#if !defined(_WIN32) && !defined(WIN32)
    ++      }else if( S_ISLNK(m) ){
    ++        char aStatic[64];
    ++        char *aBuf = aStatic;
    ++        int nBuf = 64;
    ++        int n;
    ++
    ++        while( 1 ){
    ++          n = readlink(pCur->zPath, aBuf, nBuf);
    ++          if( n<nBuf ) break;
    ++          if( aBuf!=aStatic ) sqlite3_free(aBuf);
    ++          nBuf = nBuf*2;
    ++          aBuf = sqlite3_malloc(nBuf);
    ++          if( aBuf==0 ){
    ++            sqlite3_result_error_nomem(ctx);
    ++            return SQLITE_NOMEM;
    ++          }
    ++        }
    ++
    ++        sqlite3_result_text(ctx, aBuf, n, SQLITE_TRANSIENT);
    ++        if( aBuf!=aStatic ) sqlite3_free(aBuf);
    + #endif
    +-  ".log FILE|off          Turn logging on or off.  FILE can be stderr/stdout\n"
    +-  ".mode MODE ?TABLE?     Set output mode where MODE is one of:\n"
    +-  "                         ascii    Columns/rows delimited by 0x1F and 0x1E\n"
    +-  "                         csv      Comma-separated values\n"
    +-  "                         column   Left-aligned columns.  (See .width)\n"
    +-  "                         html     HTML <table> code\n"
    +-  "                         insert   SQL insert statements for TABLE\n"
    +-  "                         line     One value per line\n"
    +-  "                         list     Values delimited by .separator strings\n"
    +-  "                         tabs     Tab-separated values\n"
    +-  "                         tcl      TCL list elements\n"
    +-  ".nullvalue STRING      Use STRING in place of NULL values\n"
    +-  ".once FILENAME         Output for the next SQL command only to FILENAME\n"
    +-  ".open ?FILENAME?       Close existing database and reopen FILENAME\n"
    +-  ".output ?FILENAME?     Send output to FILENAME or stdout\n"
    +-  ".print STRING...       Print literal STRING\n"
    +-  ".prompt MAIN CONTINUE  Replace the standard prompts\n"
    +-  ".quit                  Exit this program\n"
    +-  ".read FILENAME         Execute SQL in FILENAME\n"
    +-  ".restore ?DB? FILE     Restore content of DB (default \"main\") from FILE\n"
    +-  ".save FILE             Write in-memory database into FILE\n"
    +-  ".scanstats on|off      Turn sqlite3_stmt_scanstatus() metrics on or off\n"
    +-  ".schema ?TABLE?        Show the CREATE statements\n"
    +-  "                         If TABLE specified, only show tables matching\n"
    +-  "                         LIKE pattern TABLE.\n"
    +-  ".separator COL ?ROW?   Change the column separator and optionally the row\n"
    +-  "                         separator for both the output mode and .import\n"
    +-  ".shell CMD ARGS...     Run CMD ARGS... in a system shell\n"
    +-  ".show                  Show the current values for various settings\n"
    +-  ".stats on|off          Turn stats on or off\n"
    +-  ".system CMD ARGS...    Run CMD ARGS... in a system shell\n"
    +-  ".tables ?TABLE?        List names of tables\n"
    +-  "                         If TABLE specified, only list tables matching\n"
    +-  "                         LIKE pattern TABLE.\n"
    +-  ".timeout MS            Try opening locked tables for MS milliseconds\n"
    +-  ".timer on|off          Turn SQL timer on or off\n"
    +-  ".trace FILE|off        Output each SQL statement as it is run\n"
    +-  ".vfsname ?AUX?         Print the name of the VFS stack\n"
    +-  ".width NUM1 NUM2 ...   Set column widths for \"column\" mode\n"
    +-  "                         Negative values right-justify\n"
    +-;
    ++      }else{
    ++        readFileContents(ctx, pCur->zPath);
    ++      }
    ++    }
    ++  }
    ++  return SQLITE_OK;
    ++}
    + 
    +-/* Forward reference */
    +-static int process_input(ShellState *p, FILE *in);
    + /*
    +-** Implementation of the "readfile(X)" SQL function.  The entire content
    +-** of the file named X is read and returned as a BLOB.  NULL is returned
    +-** if the file does not exist or is unreadable.
    ++** Return the rowid for the current row. In this implementation, the
    ++** first row returned is assigned rowid value 1, and each subsequent
    ++** row a value 1 more than that of the previous.
    + */
    +-static void readfileFunc(
    +-  sqlite3_context *context,
    +-  int argc,
    +-  sqlite3_value **argv
    ++static int fsdirRowid(sqlite3_vtab_cursor *cur, sqlite_int64 *pRowid){
    ++  fsdir_cursor *pCur = (fsdir_cursor*)cur;
    ++  *pRowid = pCur->iRowid;
    ++  return SQLITE_OK;
    ++}
    ++
    ++/*
    ++** Return TRUE if the cursor has been moved off of the last
    ++** row of output.
    ++*/
    ++static int fsdirEof(sqlite3_vtab_cursor *cur){
    ++  fsdir_cursor *pCur = (fsdir_cursor*)cur;
    ++  return (pCur->zPath==0);
    ++}
    ++
    ++/*
    ++** xFilter callback.
    ++*/
    ++static int fsdirFilter(
    ++  sqlite3_vtab_cursor *cur, 
    ++  int idxNum, const char *idxStr,
    ++  int argc, sqlite3_value **argv
    + ){
    +-  const char *zName;
    +-  FILE *in;
    +-  long nIn;
    +-  void *pBuf;
    ++  const char *zDir = 0;
    ++  fsdir_cursor *pCur = (fsdir_cursor*)cur;
    ++  (void)idxStr;
    ++  fsdirResetCursor(pCur);
    ++
    ++  if( idxNum==0 ){
    ++    fsdirSetErrmsg(pCur, "table function fsdir requires an argument");
    ++    return SQLITE_ERROR;
    ++  }
    + 
    +-  UNUSED_PARAMETER(argc);
    +-  zName = (const char*)sqlite3_value_text(argv[0]);
    +-  if( zName==0 ) return;
    +-  in = fopen(zName, "rb");
    +-  if( in==0 ) return;
    +-  fseek(in, 0, SEEK_END);
    +-  nIn = ftell(in);
    +-  rewind(in);
    +-  pBuf = sqlite3_malloc64( nIn );
    +-  if( pBuf && 1==fread(pBuf, nIn, 1, in) ){
    +-    sqlite3_result_blob(context, pBuf, nIn, sqlite3_free);
    ++  assert( argc==idxNum && (argc==1 || argc==2) );
    ++  zDir = (const char*)sqlite3_value_text(argv[0]);
    ++  if( zDir==0 ){
    ++    fsdirSetErrmsg(pCur, "table function fsdir requires a non-NULL argument");
    ++    return SQLITE_ERROR;
    ++  }
    ++  if( argc==2 ){
    ++    pCur->zBase = (const char*)sqlite3_value_text(argv[1]);
    ++  }
    ++  if( pCur->zBase ){
    ++    pCur->nBase = (int)strlen(pCur->zBase)+1;
    ++    pCur->zPath = sqlite3_mprintf("%s/%s", pCur->zBase, zDir);
    +   }else{
    +-    sqlite3_free(pBuf);
    ++    pCur->zPath = sqlite3_mprintf("%s", zDir);
    +   }
    +-  fclose(in);
    ++
    ++  if( pCur->zPath==0 ){
    ++    return SQLITE_NOMEM;
    ++  }
    ++  if( lstat(pCur->zPath, &pCur->sStat) ){
    ++    fsdirSetErrmsg(pCur, "cannot stat file: %s", pCur->zPath);
    ++    return SQLITE_ERROR;
    ++  }
    ++
    ++  return SQLITE_OK;
    + }
    + 
    + /*
    +-** Implementation of the "writefile(X,Y)" SQL function.  The argument Y
    +-** is written into file X.  The number of bytes written is returned.  Or
    +-** NULL is returned if something goes wrong, such as being unable to open
    +-** file X for writing.
    ++** SQLite will invoke this method one or more times while planning a query
    ++** that uses the generate_series virtual table.  This routine needs to create
    ++** a query plan for each invocation and compute an estimated cost for that
    ++** plan.
    ++**
    ++** In this implementation idxNum is used to represent the
    ++** query plan.  idxStr is unused.
    ++**
    ++** The query plan is represented by bits in idxNum:
    ++**
    ++**  (1)  start = $value  -- constraint exists
    ++**  (2)  stop = $value   -- constraint exists
    ++**  (4)  step = $value   -- constraint exists
    ++**  (8)  output in descending order
    + */
    +-static void writefileFunc(
    +-  sqlite3_context *context,
    +-  int argc,
    +-  sqlite3_value **argv
    ++static int fsdirBestIndex(
    ++  sqlite3_vtab *tab,
    ++  sqlite3_index_info *pIdxInfo
    + ){
    +-  FILE *out;
    +-  const char *z;
    +-  sqlite3_int64 rc;
    +-  const char *zFile;
    ++  int i;                 /* Loop over constraints */
    ++  int idx4 = -1;
    ++  int idx5 = -1;
    ++  const struct sqlite3_index_constraint *pConstraint;
    ++
    ++  (void)tab;
    ++  pConstraint = pIdxInfo->aConstraint;
    ++  for(i=0; i<pIdxInfo->nConstraint; i++, pConstraint++){
    ++    if( pConstraint->usable==0 ) continue;
    ++    if( pConstraint->op!=SQLITE_INDEX_CONSTRAINT_EQ ) continue;
    ++    if( pConstraint->iColumn==4 ) idx4 = i;
    ++    if( pConstraint->iColumn==5 ) idx5 = i;
    ++  }
    + 
    +-  UNUSED_PARAMETER(argc);
    +-  zFile = (const char*)sqlite3_value_text(argv[0]);
    +-  if( zFile==0 ) return;
    +-  out = fopen(zFile, "wb");
    +-  if( out==0 ) return;
    +-  z = (const char*)sqlite3_value_blob(argv[1]);
    +-  if( z==0 ){
    +-    rc = 0;
    ++  if( idx4<0 ){
    ++    pIdxInfo->idxNum = 0;
    ++    pIdxInfo->estimatedCost = (double)(((sqlite3_int64)1) << 50);
    +   }else{
    +-    rc = fwrite(z, 1, sqlite3_value_bytes(argv[1]), out);
    ++    pIdxInfo->aConstraintUsage[idx4].omit = 1;
    ++    pIdxInfo->aConstraintUsage[idx4].argvIndex = 1;
    ++    if( idx5>=0 ){
    ++      pIdxInfo->aConstraintUsage[idx5].omit = 1;
    ++      pIdxInfo->aConstraintUsage[idx5].argvIndex = 2;
    ++      pIdxInfo->idxNum = 2;
    ++      pIdxInfo->estimatedCost = 10.0;
    ++    }else{
    ++      pIdxInfo->idxNum = 1;
    ++      pIdxInfo->estimatedCost = 100.0;
    ++    }
    ++  }
    ++
    ++  return SQLITE_OK;
    ++}
    ++
    ++/*
    ++** Register the "fsdir" virtual table.
    ++*/
    ++static int fsdirRegister(sqlite3 *db){
    ++  static sqlite3_module fsdirModule = {
    ++    0,                         /* iVersion */
    ++    0,                         /* xCreate */
    ++    fsdirConnect,              /* xConnect */
    ++    fsdirBestIndex,            /* xBestIndex */
    ++    fsdirDisconnect,           /* xDisconnect */
    ++    0,                         /* xDestroy */
    ++    fsdirOpen,                 /* xOpen - open a cursor */
    ++    fsdirClose,                /* xClose - close a cursor */
    ++    fsdirFilter,               /* xFilter - configure scan constraints */
    ++    fsdirNext,                 /* xNext - advance a cursor */
    ++    fsdirEof,                  /* xEof - check for end of scan */
    ++    fsdirColumn,               /* xColumn - read data */
    ++    fsdirRowid,                /* xRowid - read data */
    ++    0,                         /* xUpdate */
    ++    0,                         /* xBegin */
    ++    0,                         /* xSync */
    ++    0,                         /* xCommit */
    ++    0,                         /* xRollback */
    ++    0,                         /* xFindMethod */
    ++    0,                         /* xRename */
    ++    0,                         /* xSavepoint */
    ++    0,                         /* xRelease */
    ++    0                          /* xRollbackTo */
    ++  };
    ++
    ++  int rc = sqlite3_create_module(db, "fsdir", &fsdirModule, 0);
    ++  return rc;
    ++}
    ++#else         /* SQLITE_OMIT_VIRTUALTABLE */
    ++# define fsdirRegister(x) SQLITE_OK
    ++#endif
    ++
    ++#ifdef _WIN32
    ++
    ++#endif
    ++int sqlite3_fileio_init(
    ++  sqlite3 *db, 
    ++  char **pzErrMsg, 
    ++  const sqlite3_api_routines *pApi
    ++){
    ++  int rc = SQLITE_OK;
    ++  SQLITE_EXTENSION_INIT2(pApi);
    ++  (void)pzErrMsg;  /* Unused parameter */
    ++  rc = sqlite3_create_function(db, "readfile", 1, SQLITE_UTF8, 0,
    ++                               readfileFunc, 0, 0);
    ++  if( rc==SQLITE_OK ){
    ++    rc = sqlite3_create_function(db, "writefile", -1, SQLITE_UTF8, 0,
    ++                                 writefileFunc, 0, 0);
    ++  }
    ++  if( rc==SQLITE_OK ){
    ++    rc = sqlite3_create_function(db, "lsmode", 1, SQLITE_UTF8, 0,
    ++                                 lsModeFunc, 0, 0);
    ++  }
    ++  if( rc==SQLITE_OK ){
    ++    rc = fsdirRegister(db);
    ++  }
    ++  return rc;
    ++}
    ++
    ++/************************* End ../ext/misc/fileio.c ********************/
    ++/************************* Begin ../ext/misc/completion.c ******************/
    ++/*
    ++** 2017-07-10
    ++**
    ++** 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 implements an eponymous virtual table that returns suggested
    ++** completions for a partial SQL input.
    ++**
    ++** Suggested usage:
    ++**
    ++**     SELECT DISTINCT candidate COLLATE nocase
    ++**       FROM completion($prefix,$wholeline)
    ++**      ORDER BY 1;
    ++**
    ++** The two query parameters are optional.  $prefix is the text of the
    ++** current word being typed and that is to be completed.  $wholeline is
    ++** the complete input line, used for context.
    ++**
    ++** The raw completion() table might return the same candidate multiple
    ++** times, for example if the same column name is used to two or more
    ++** tables.  And the candidates are returned in an arbitrary order.  Hence,
    ++** the DISTINCT and ORDER BY are recommended.
    ++**
    ++** This virtual table operates at the speed of human typing, and so there
    ++** is no attempt to make it fast.  Even a slow implementation will be much
    ++** faster than any human can type.
    ++**
    ++*/
    ++SQLITE_EXTENSION_INIT1
    ++#include <assert.h>
    ++#include <string.h>
    ++#include <ctype.h>
    ++
    ++#ifndef SQLITE_OMIT_VIRTUALTABLE
    ++
    ++/* completion_vtab is a subclass of sqlite3_vtab which will
    ++** serve as the underlying representation of a completion virtual table
    ++*/
    ++typedef struct completion_vtab completion_vtab;
    ++struct completion_vtab {
    ++  sqlite3_vtab base;  /* Base class - must be first */
    ++  sqlite3 *db;        /* Database connection for this completion vtab */
    ++};
    ++
    ++/* completion_cursor is a subclass of sqlite3_vtab_cursor which will
    ++** serve as the underlying representation of a cursor that scans
    ++** over rows of the result
    ++*/
    ++typedef struct completion_cursor completion_cursor;
    ++struct completion_cursor {
    ++  sqlite3_vtab_cursor base;  /* Base class - must be first */
    ++  sqlite3 *db;               /* Database connection for this cursor */
    ++  int nPrefix, nLine;        /* Number of bytes in zPrefix and zLine */
    ++  char *zPrefix;             /* The prefix for the word we want to complete */
    ++  char *zLine;               /* The whole that we want to complete */
    ++  const char *zCurrentRow;   /* Current output row */
    ++  sqlite3_stmt *pStmt;       /* Current statement */
    ++  sqlite3_int64 iRowid;      /* The rowid */
    ++  int ePhase;                /* Current phase */
    ++  int j;                     /* inter-phase counter */
    ++};
    ++
    ++/* Values for ePhase:
    ++*/
    ++#define COMPLETION_FIRST_PHASE   1
    ++#define COMPLETION_KEYWORDS      1
    ++#define COMPLETION_PRAGMAS       2
    ++#define COMPLETION_FUNCTIONS     3
    ++#define COMPLETION_COLLATIONS    4
    ++#define COMPLETION_INDEXES       5
    ++#define COMPLETION_TRIGGERS      6
    ++#define COMPLETION_DATABASES     7
    ++#define COMPLETION_TABLES        8
    ++#define COMPLETION_COLUMNS       9
    ++#define COMPLETION_MODULES       10
    ++#define COMPLETION_EOF           11
    ++
    ++/*
    ++** The completionConnect() method is invoked to create a new
    ++** completion_vtab that describes the completion virtual table.
    ++**
    ++** Think of this routine as the constructor for completion_vtab objects.
    ++**
    ++** All this routine needs to do is:
    ++**
    ++**    (1) Allocate the completion_vtab object and initialize all fields.
    ++**
    ++**    (2) Tell SQLite (via the sqlite3_declare_vtab() interface) what the
    ++**        result set of queries against completion will look like.
    ++*/
    ++static int completionConnect(
    ++  sqlite3 *db,
    ++  void *pAux,
    ++  int argc, const char *const*argv,
    ++  sqlite3_vtab **ppVtab,
    ++  char **pzErr
    ++){
    ++  completion_vtab *pNew;
    ++  int rc;
    ++
    ++  (void)(pAux);    /* Unused parameter */
    ++  (void)(argc);    /* Unused parameter */
    ++  (void)(argv);    /* Unused parameter */
    ++  (void)(pzErr);   /* Unused parameter */
    ++
    ++/* Column numbers */
    ++#define COMPLETION_COLUMN_CANDIDATE 0  /* Suggested completion of the input */
    ++#define COMPLETION_COLUMN_PREFIX    1  /* Prefix of the word to be completed */
    ++#define COMPLETION_COLUMN_WHOLELINE 2  /* Entire line seen so far */
    ++#define COMPLETION_COLUMN_PHASE     3  /* ePhase - used for debugging only */
    ++
    ++  rc = sqlite3_declare_vtab(db,
    ++      "CREATE TABLE x("
    ++      "  candidate TEXT,"
    ++      "  prefix TEXT HIDDEN,"
    ++      "  wholeline TEXT HIDDEN,"
    ++      "  phase INT HIDDEN"        /* Used for debugging only */
    ++      ")");
    ++  if( rc==SQLITE_OK ){
    ++    pNew = sqlite3_malloc( sizeof(*pNew) );
    ++    *ppVtab = (sqlite3_vtab*)pNew;
    ++    if( pNew==0 ) return SQLITE_NOMEM;
    ++    memset(pNew, 0, sizeof(*pNew));
    ++    pNew->db = db;
    ++  }
    ++  return rc;
    ++}
    ++
    ++/*
    ++** This method is the destructor for completion_cursor objects.
    ++*/
    ++static int completionDisconnect(sqlite3_vtab *pVtab){
    ++  sqlite3_free(pVtab);
    ++  return SQLITE_OK;
    ++}
    ++
    ++/*
    ++** Constructor for a new completion_cursor object.
    ++*/
    ++static int completionOpen(sqlite3_vtab *p, sqlite3_vtab_cursor **ppCursor){
    ++  completion_cursor *pCur;
    ++  pCur = sqlite3_malloc( sizeof(*pCur) );
    ++  if( pCur==0 ) return SQLITE_NOMEM;
    ++  memset(pCur, 0, sizeof(*pCur));
    ++  pCur->db = ((completion_vtab*)p)->db;
    ++  *ppCursor = &pCur->base;
    ++  return SQLITE_OK;
    ++}
    ++
    ++/*
    ++** Reset the completion_cursor.
    ++*/
    ++static void completionCursorReset(completion_cursor *pCur){
    ++  sqlite3_free(pCur->zPrefix);   pCur->zPrefix = 0;  pCur->nPrefix = 0;
    ++  sqlite3_free(pCur->zLine);     pCur->zLine = 0;    pCur->nLine = 0;
    ++  sqlite3_finalize(pCur->pStmt); pCur->pStmt = 0;
    ++  pCur->j = 0;
    ++}
    ++
    ++/*
    ++** Destructor for a completion_cursor.
    ++*/
    ++static int completionClose(sqlite3_vtab_cursor *cur){
    ++  completionCursorReset((completion_cursor*)cur);
    ++  sqlite3_free(cur);
    ++  return SQLITE_OK;
    ++}
    ++
    ++/*
    ++** All SQL keywords understood by SQLite
    ++*/
    ++static const char *completionKwrds[] = {
    ++  "ABORT", "ACTION", "ADD", "AFTER", "ALL", "ALTER", "ANALYZE", "AND", "AS",
    ++  "ASC", "ATTACH", "AUTOINCREMENT", "BEFORE", "BEGIN", "BETWEEN", "BY",
    ++  "CASCADE", "CASE", "CAST", "CHECK", "COLLATE", "COLUMN", "COMMIT",
    ++  "CONFLICT", "CONSTRAINT", "CREATE", "CROSS", "CURRENT_DATE",
    ++  "CURRENT_TIME", "CURRENT_TIMESTAMP", "DATABASE", "DEFAULT", "DEFERRABLE",
    ++  "DEFERRED", "DELETE", "DESC", "DETACH", "DISTINCT", "DROP", "EACH",
    ++  "ELSE", "END", "ESCAPE", "EXCEPT", "EXCLUSIVE", "EXISTS", "EXPLAIN",
    ++  "FAIL", "FOR", "FOREIGN", "FROM", "FULL", "GLOB", "GROUP", "HAVING", "IF",
    ++  "IGNORE", "IMMEDIATE", "IN", "INDEX", "INDEXED", "INITIALLY", "INNER",
    ++  "INSERT", "INSTEAD", "INTERSECT", "INTO", "IS", "ISNULL", "JOIN", "KEY",
    ++  "LEFT", "LIKE", "LIMIT", "MATCH", "NATURAL", "NO", "NOT", "NOTNULL",
    ++  "NULL", "OF", "OFFSET", "ON", "OR", "ORDER", "OUTER", "PLAN", "PRAGMA",
    ++  "PRIMARY", "QUERY", "RAISE", "RECURSIVE", "REFERENCES", "REGEXP",
    ++  "REINDEX", "RELEASE", "RENAME", "REPLACE", "RESTRICT", "RIGHT",
    ++  "ROLLBACK", "ROW", "SAVEPOINT", "SELECT", "SET", "TABLE", "TEMP",
    ++  "TEMPORARY", "THEN", "TO", "TRANSACTION", "TRIGGER", "UNION", "UNIQUE",
    ++  "UPDATE", "USING", "VACUUM", "VALUES", "VIEW", "VIRTUAL", "WHEN", "WHERE",
    ++  "WITH", "WITHOUT",
    ++};
    ++#define completionKwCount \
    ++   (int)(sizeof(completionKwrds)/sizeof(completionKwrds[0]))
    ++
    ++/*
    ++** Advance a completion_cursor to its next row of output.
    ++**
    ++** The ->ePhase, ->j, and ->pStmt fields of the completion_cursor object
    ++** record the current state of the scan.  This routine sets ->zCurrentRow
    ++** to the current row of output and then returns.  If no more rows remain,
    ++** then ->ePhase is set to COMPLETION_EOF which will signal the virtual
    ++** table that has reached the end of its scan.
    ++**
    ++** The current implementation just lists potential identifiers and
    ++** keywords and filters them by zPrefix.  Future enhancements should
    ++** take zLine into account to try to restrict the set of identifiers and
    ++** keywords based on what would be legal at the current point of input.
    ++*/
    ++static int completionNext(sqlite3_vtab_cursor *cur){
    ++  completion_cursor *pCur = (completion_cursor*)cur;
    ++  int eNextPhase = 0;  /* Next phase to try if current phase reaches end */
    ++  int iCol = -1;       /* If >=0, step pCur->pStmt and use the i-th column */
    ++  pCur->iRowid++;
    ++  while( pCur->ePhase!=COMPLETION_EOF ){
    ++    switch( pCur->ePhase ){
    ++      case COMPLETION_KEYWORDS: {
    ++        if( pCur->j >= completionKwCount ){
    ++          pCur->zCurrentRow = 0;
    ++          pCur->ePhase = COMPLETION_DATABASES;
    ++        }else{
    ++          pCur->zCurrentRow = completionKwrds[pCur->j++];
    ++        }
    ++        iCol = -1;
    ++        break;
    ++      }
    ++      case COMPLETION_DATABASES: {
    ++        if( pCur->pStmt==0 ){
    ++          sqlite3_prepare_v2(pCur->db, "PRAGMA database_list", -1,
    ++                             &pCur->pStmt, 0);
    ++        }
    ++        iCol = 1;
    ++        eNextPhase = COMPLETION_TABLES;
    ++        break;
    ++      }
    ++      case COMPLETION_TABLES: {
    ++        if( pCur->pStmt==0 ){
    ++          sqlite3_stmt *pS2;
    ++          char *zSql = 0;
    ++          const char *zSep = "";
    ++          sqlite3_prepare_v2(pCur->db, "PRAGMA database_list", -1, &pS2, 0);
    ++          while( sqlite3_step(pS2)==SQLITE_ROW ){
    ++            const char *zDb = (const char*)sqlite3_column_text(pS2, 1);
    ++            zSql = sqlite3_mprintf(
    ++               "%z%s"
    ++               "SELECT name FROM \"%w\".sqlite_master"
    ++               " WHERE type='table'",
    ++               zSql, zSep, zDb
    ++            );
    ++            if( zSql==0 ) return SQLITE_NOMEM;
    ++            zSep = " UNION ";
    ++          }
    ++          sqlite3_finalize(pS2);
    ++          sqlite3_prepare_v2(pCur->db, zSql, -1, &pCur->pStmt, 0);
    ++          sqlite3_free(zSql);
    ++        }
    ++        iCol = 0;
    ++        eNextPhase = COMPLETION_COLUMNS;
    ++        break;
    ++      }
    ++      case COMPLETION_COLUMNS: {
    ++        if( pCur->pStmt==0 ){
    ++          sqlite3_stmt *pS2;
    ++          char *zSql = 0;
    ++          const char *zSep = "";
    ++          sqlite3_prepare_v2(pCur->db, "PRAGMA database_list", -1, &pS2, 0);
    ++          while( sqlite3_step(pS2)==SQLITE_ROW ){
    ++            const char *zDb = (const char*)sqlite3_column_text(pS2, 1);
    ++            zSql = sqlite3_mprintf(
    ++               "%z%s"
    ++               "SELECT pti.name FROM \"%w\".sqlite_master AS sm"
    ++                       " JOIN pragma_table_info(sm.name,%Q) AS pti"
    ++               " WHERE sm.type='table'",
    ++               zSql, zSep, zDb, zDb
    ++            );
    ++            if( zSql==0 ) return SQLITE_NOMEM;
    ++            zSep = " UNION ";
    ++          }
    ++          sqlite3_finalize(pS2);
    ++          sqlite3_prepare_v2(pCur->db, zSql, -1, &pCur->pStmt, 0);
    ++          sqlite3_free(zSql);
    ++        }
    ++        iCol = 0;
    ++        eNextPhase = COMPLETION_EOF;
    ++        break;
    ++      }
    ++    }
    ++    if( iCol<0 ){
    ++      /* This case is when the phase presets zCurrentRow */
    ++      if( pCur->zCurrentRow==0 ) continue;
    ++    }else{
    ++      if( sqlite3_step(pCur->pStmt)==SQLITE_ROW ){
    ++        /* Extract the next row of content */
    ++        pCur->zCurrentRow = (const char*)sqlite3_column_text(pCur->pStmt, iCol);
    ++      }else{
    ++        /* When all rows are finished, advance to the next phase */
    ++        sqlite3_finalize(pCur->pStmt);
    ++        pCur->pStmt = 0;
    ++        pCur->ePhase = eNextPhase;
    ++        continue;
    ++      }
    ++    }
    ++    if( pCur->nPrefix==0 ) break;
    ++    if( sqlite3_strnicmp(pCur->zPrefix, pCur->zCurrentRow, pCur->nPrefix)==0 ){
    ++      break;
    ++    }
    ++  }
    ++
    ++  return SQLITE_OK;
    ++}
    ++
    ++/*
    ++** Return values of columns for the row at which the completion_cursor
    ++** is currently pointing.
    ++*/
    ++static int completionColumn(
    ++  sqlite3_vtab_cursor *cur,   /* The cursor */
    ++  sqlite3_context *ctx,       /* First argument to sqlite3_result_...() */
    ++  int i                       /* Which column to return */
    ++){
    ++  completion_cursor *pCur = (completion_cursor*)cur;
    ++  switch( i ){
    ++    case COMPLETION_COLUMN_CANDIDATE: {
    ++      sqlite3_result_text(ctx, pCur->zCurrentRow, -1, SQLITE_TRANSIENT);
    ++      break;
    ++    }
    ++    case COMPLETION_COLUMN_PREFIX: {
    ++      sqlite3_result_text(ctx, pCur->zPrefix, -1, SQLITE_TRANSIENT);
    ++      break;
    ++    }
    ++    case COMPLETION_COLUMN_WHOLELINE: {
    ++      sqlite3_result_text(ctx, pCur->zLine, -1, SQLITE_TRANSIENT);
    ++      break;
    ++    }
    ++    case COMPLETION_COLUMN_PHASE: {
    ++      sqlite3_result_int(ctx, pCur->ePhase);
    ++      break;
    ++    }
    ++  }
    ++  return SQLITE_OK;
    ++}
    ++
    ++/*
    ++** Return the rowid for the current row.  In this implementation, the
    ++** rowid is the same as the output value.
    ++*/
    ++static int completionRowid(sqlite3_vtab_cursor *cur, sqlite_int64 *pRowid){
    ++  completion_cursor *pCur = (completion_cursor*)cur;
    ++  *pRowid = pCur->iRowid;
    ++  return SQLITE_OK;
    ++}
    ++
    ++/*
    ++** Return TRUE if the cursor has been moved off of the last
    ++** row of output.
    ++*/
    ++static int completionEof(sqlite3_vtab_cursor *cur){
    ++  completion_cursor *pCur = (completion_cursor*)cur;
    ++  return pCur->ePhase >= COMPLETION_EOF;
    ++}
    ++
    ++/*
    ++** This method is called to "rewind" the completion_cursor object back
    ++** to the first row of output.  This method is always called at least
    ++** once prior to any call to completionColumn() or completionRowid() or 
    ++** completionEof().
    ++*/
    ++static int completionFilter(
    ++  sqlite3_vtab_cursor *pVtabCursor, 
    ++  int idxNum, const char *idxStr,
    ++  int argc, sqlite3_value **argv
    ++){
    ++  completion_cursor *pCur = (completion_cursor *)pVtabCursor;
    ++  int iArg = 0;
    ++  (void)(idxStr);   /* Unused parameter */
    ++  (void)(argc);     /* Unused parameter */
    ++  completionCursorReset(pCur);
    ++  if( idxNum & 1 ){
    ++    pCur->nPrefix = sqlite3_value_bytes(argv[iArg]);
    ++    if( pCur->nPrefix>0 ){
    ++      pCur->zPrefix = sqlite3_mprintf("%s", sqlite3_value_text(argv[iArg]));
    ++      if( pCur->zPrefix==0 ) return SQLITE_NOMEM;
    ++    }
    ++    iArg++;
    ++  }
    ++  if( idxNum & 2 ){
    ++    pCur->nLine = sqlite3_value_bytes(argv[iArg]);
    ++    if( pCur->nLine>0 ){
    ++      pCur->zLine = sqlite3_mprintf("%s", sqlite3_value_text(argv[iArg]));
    ++      if( pCur->zLine==0 ) return SQLITE_NOMEM;
    ++    }
    ++    iArg++;
    ++  }
    ++  if( pCur->zLine!=0 && pCur->zPrefix==0 ){
    ++    int i = pCur->nLine;
    ++    while( i>0 && (isalnum(pCur->zLine[i-1]) || pCur->zLine[i-1]=='_') ){
    ++      i--;
    ++    }
    ++    pCur->nPrefix = pCur->nLine - i;
    ++    if( pCur->nPrefix>0 ){
    ++      pCur->zPrefix = sqlite3_mprintf("%.*s", pCur->nPrefix, pCur->zLine + i);
    ++      if( pCur->zPrefix==0 ) return SQLITE_NOMEM;
    ++    }
    ++  }
    ++  pCur->iRowid = 0;
    ++  pCur->ePhase = COMPLETION_FIRST_PHASE;
    ++  return completionNext(pVtabCursor);
    ++}
    ++
    ++/*
    ++** SQLite will invoke this method one or more times while planning a query
    ++** that uses the completion virtual table.  This routine needs to create
    ++** a query plan for each invocation and compute an estimated cost for that
    ++** plan.
    ++**
    ++** There are two hidden parameters that act as arguments to the table-valued
    ++** function:  "prefix" and "wholeline".  Bit 0 of idxNum is set if "prefix"
    ++** is available and bit 1 is set if "wholeline" is available.
    ++*/
    ++static int completionBestIndex(
    ++  sqlite3_vtab *tab,
    ++  sqlite3_index_info *pIdxInfo
    ++){
    ++  int i;                 /* Loop over constraints */
    ++  int idxNum = 0;        /* The query plan bitmask */
    ++  int prefixIdx = -1;    /* Index of the start= constraint, or -1 if none */
    ++  int wholelineIdx = -1; /* Index of the stop= constraint, or -1 if none */
    ++  int nArg = 0;          /* Number of arguments that completeFilter() expects */
    ++  const struct sqlite3_index_constraint *pConstraint;
    ++
    ++  (void)(tab);    /* Unused parameter */
    ++  pConstraint = pIdxInfo->aConstraint;
    ++  for(i=0; i<pIdxInfo->nConstraint; i++, pConstraint++){
    ++    if( pConstraint->usable==0 ) continue;
    ++    if( pConstraint->op!=SQLITE_INDEX_CONSTRAINT_EQ ) continue;
    ++    switch( pConstraint->iColumn ){
    ++      case COMPLETION_COLUMN_PREFIX:
    ++        prefixIdx = i;
    ++        idxNum |= 1;
    ++        break;
    ++      case COMPLETION_COLUMN_WHOLELINE:
    ++        wholelineIdx = i;
    ++        idxNum |= 2;
    ++        break;
    ++    }
    ++  }
    ++  if( prefixIdx>=0 ){
    ++    pIdxInfo->aConstraintUsage[prefixIdx].argvIndex = ++nArg;
    ++    pIdxInfo->aConstraintUsage[prefixIdx].omit = 1;
    ++  }
    ++  if( wholelineIdx>=0 ){
    ++    pIdxInfo->aConstraintUsage[wholelineIdx].argvIndex = ++nArg;
    ++    pIdxInfo->aConstraintUsage[wholelineIdx].omit = 1;
    ++  }
    ++  pIdxInfo->idxNum = idxNum;
    ++  pIdxInfo->estimatedCost = (double)5000 - 1000*nArg;
    ++  pIdxInfo->estimatedRows = 500 - 100*nArg;
    ++  return SQLITE_OK;
    ++}
    ++
    ++/*
    ++** This following structure defines all the methods for the 
    ++** completion virtual table.
    ++*/
    ++static sqlite3_module completionModule = {
    ++  0,                         /* iVersion */
    ++  0,                         /* xCreate */
    ++  completionConnect,         /* xConnect */
    ++  completionBestIndex,       /* xBestIndex */
    ++  completionDisconnect,      /* xDisconnect */
    ++  0,                         /* xDestroy */
    ++  completionOpen,            /* xOpen - open a cursor */
    ++  completionClose,           /* xClose - close a cursor */
    ++  completionFilter,          /* xFilter - configure scan constraints */
    ++  completionNext,            /* xNext - advance a cursor */
    ++  completionEof,             /* xEof - check for end of scan */
    ++  completionColumn,          /* xColumn - read data */
    ++  completionRowid,           /* xRowid - read data */
    ++  0,                         /* xUpdate */
    ++  0,                         /* xBegin */
    ++  0,                         /* xSync */
    ++  0,                         /* xCommit */
    ++  0,                         /* xRollback */
    ++  0,                         /* xFindMethod */
    ++  0,                         /* xRename */
    ++  0,                         /* xSavepoint */
    ++  0,                         /* xRelease */
    ++  0                          /* xRollbackTo */
    ++};
    ++
    ++#endif /* SQLITE_OMIT_VIRTUALTABLE */
    ++
    ++int sqlite3CompletionVtabInit(sqlite3 *db){
    ++  int rc = SQLITE_OK;
    ++#ifndef SQLITE_OMIT_VIRTUALTABLE
    ++  rc = sqlite3_create_module(db, "completion", &completionModule, 0);
    ++#endif
    ++  return rc;
    ++}
    ++
    ++#ifdef _WIN32
    ++
    ++#endif
    ++int sqlite3_completion_init(
    ++  sqlite3 *db, 
    ++  char **pzErrMsg, 
    ++  const sqlite3_api_routines *pApi
    ++){
    ++  int rc = SQLITE_OK;
    ++  SQLITE_EXTENSION_INIT2(pApi);
    ++  (void)(pzErrMsg);  /* Unused parameter */
    ++#ifndef SQLITE_OMIT_VIRTUALTABLE
    ++  rc = sqlite3CompletionVtabInit(db);
    ++#endif
    ++  return rc;
    ++}
    ++
    ++/************************* End ../ext/misc/completion.c ********************/
    ++/************************* Begin ../ext/misc/appendvfs.c ******************/
    ++/*
    ++** 2017-10-20
    ++**
    ++** 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 implements a VFS shim that allows an SQLite database to be
    ++** appended onto the end of some other file, such as an executable.
    ++**
    ++** A special record must appear at the end of the file that identifies the
    ++** file as an appended database and provides an offset to page 1.  For
    ++** best performance page 1 should be located at a disk page boundary, though
    ++** that is not required.
    ++**
    ++** When opening a database using this VFS, the connection might treat
    ++** the file as an ordinary SQLite database, or it might treat is as a
    ++** database appended onto some other file.  Here are the rules:
    ++**
    ++**  (1)  When opening a new empty file, that file is treated as an ordinary
    ++**       database.
    ++**
    ++**  (2)  When opening a file that begins with the standard SQLite prefix
    ++**       string "SQLite format 3", that file is treated as an ordinary
    ++**       database.
    ++**
    ++**  (3)  When opening a file that ends with the appendvfs trailer string
    ++**       "Start-Of-SQLite3-NNNNNNNN" that file is treated as an appended
    ++**       database.
    ++**
    ++**  (4)  If none of the above apply and the SQLITE_OPEN_CREATE flag is
    ++**       set, then a new database is appended to the already existing file.
    ++**
    ++**  (5)  Otherwise, SQLITE_CANTOPEN is returned.
    ++**
    ++** To avoid unnecessary complications with the PENDING_BYTE, the size of
    ++** the file containing the database is limited to 1GB.  This VFS will refuse
    ++** to read or write past the 1GB mark.  This restriction might be lifted in
    ++** future versions.  For now, if you need a large database, then keep the
    ++** database in a separate file.
    ++**
    ++** If the file being opened is not an appended database, then this shim is
    ++** a pass-through into the default underlying VFS.
    ++**/
    ++SQLITE_EXTENSION_INIT1
    ++#include <string.h>
    ++#include <assert.h>
    ++
    ++/* The append mark at the end of the database is:
    ++**
    ++**     Start-Of-SQLite3-NNNNNNNN
    ++**     123456789 123456789 12345
    ++**
    ++** The NNNNNNNN represents a 64-bit big-endian unsigned integer which is
    ++** the offset to page 1.
    ++*/
    ++#define APND_MARK_PREFIX     "Start-Of-SQLite3-"
    ++#define APND_MARK_PREFIX_SZ  17
    ++#define APND_MARK_SIZE       25
    ++
    ++/*
    ++** Maximum size of the combined prefix + database + append-mark.  This
    ++** must be less than 0x40000000 to avoid locking issues on Windows.
    ++*/
    ++#define APND_MAX_SIZE  (65536*15259)
    ++
    ++/*
    ++** Forward declaration of objects used by this utility
    ++*/
    ++typedef struct sqlite3_vfs ApndVfs;
    ++typedef struct ApndFile ApndFile;
    ++
    ++/* Access to a lower-level VFS that (might) implement dynamic loading,
    ++** access to randomness, etc.
    ++*/
    ++#define ORIGVFS(p)  ((sqlite3_vfs*)((p)->pAppData))
    ++#define ORIGFILE(p) ((sqlite3_file*)(((ApndFile*)(p))+1))
    ++
    ++/* An open file */
    ++struct ApndFile {
    ++  sqlite3_file base;              /* IO methods */
    ++  sqlite3_int64 iPgOne;           /* File offset to page 1 */
    ++  sqlite3_int64 iMark;            /* Start of the append-mark */
    ++};
    ++
    ++/*
    ++** Methods for ApndFile
    ++*/
    ++static int apndClose(sqlite3_file*);
    ++static int apndRead(sqlite3_file*, void*, int iAmt, sqlite3_int64 iOfst);
    ++static int apndWrite(sqlite3_file*,const void*,int iAmt, sqlite3_int64 iOfst);
    ++static int apndTruncate(sqlite3_file*, sqlite3_int64 size);
    ++static int apndSync(sqlite3_file*, int flags);
    ++static int apndFileSize(sqlite3_file*, sqlite3_int64 *pSize);
    ++static int apndLock(sqlite3_file*, int);
    ++static int apndUnlock(sqlite3_file*, int);
    ++static int apndCheckReservedLock(sqlite3_file*, int *pResOut);
    ++static int apndFileControl(sqlite3_file*, int op, void *pArg);
    ++static int apndSectorSize(sqlite3_file*);
    ++static int apndDeviceCharacteristics(sqlite3_file*);
    ++static int apndShmMap(sqlite3_file*, int iPg, int pgsz, int, void volatile**);
    ++static int apndShmLock(sqlite3_file*, int offset, int n, int flags);
    ++static void apndShmBarrier(sqlite3_file*);
    ++static int apndShmUnmap(sqlite3_file*, int deleteFlag);
    ++static int apndFetch(sqlite3_file*, sqlite3_int64 iOfst, int iAmt, void **pp);
    ++static int apndUnfetch(sqlite3_file*, sqlite3_int64 iOfst, void *p);
    ++
    ++/*
    ++** Methods for ApndVfs
    ++*/
    ++static int apndOpen(sqlite3_vfs*, const char *, sqlite3_file*, int , int *);
    ++static int apndDelete(sqlite3_vfs*, const char *zName, int syncDir);
    ++static int apndAccess(sqlite3_vfs*, const char *zName, int flags, int *);
    ++static int apndFullPathname(sqlite3_vfs*, const char *zName, int, char *zOut);
    ++static void *apndDlOpen(sqlite3_vfs*, const char *zFilename);
    ++static void apndDlError(sqlite3_vfs*, int nByte, char *zErrMsg);
    ++static void (*apndDlSym(sqlite3_vfs *pVfs, void *p, const char*zSym))(void);
    ++static void apndDlClose(sqlite3_vfs*, void*);
    ++static int apndRandomness(sqlite3_vfs*, int nByte, char *zOut);
    ++static int apndSleep(sqlite3_vfs*, int microseconds);
    ++static int apndCurrentTime(sqlite3_vfs*, double*);
    ++static int apndGetLastError(sqlite3_vfs*, int, char *);
    ++static int apndCurrentTimeInt64(sqlite3_vfs*, sqlite3_int64*);
    ++static int apndSetSystemCall(sqlite3_vfs*, const char*,sqlite3_syscall_ptr);
    ++static sqlite3_syscall_ptr apndGetSystemCall(sqlite3_vfs*, const char *z);
    ++static const char *apndNextSystemCall(sqlite3_vfs*, const char *zName);
    ++
    ++static sqlite3_vfs apnd_vfs = {
    ++  3,                            /* iVersion (set when registered) */
    ++  0,                            /* szOsFile (set when registered) */
    ++  1024,                         /* mxPathname */
    ++  0,                            /* pNext */
    ++  "apndvfs",                    /* zName */
    ++  0,                            /* pAppData (set when registered) */ 
    ++  apndOpen,                     /* xOpen */
    ++  apndDelete,                   /* xDelete */
    ++  apndAccess,                   /* xAccess */
    ++  apndFullPathname,             /* xFullPathname */
    ++  apndDlOpen,                   /* xDlOpen */
    ++  apndDlError,                  /* xDlError */
    ++  apndDlSym,                    /* xDlSym */
    ++  apndDlClose,                  /* xDlClose */
    ++  apndRandomness,               /* xRandomness */
    ++  apndSleep,                    /* xSleep */
    ++  apndCurrentTime,              /* xCurrentTime */
    ++  apndGetLastError,             /* xGetLastError */
    ++  apndCurrentTimeInt64,         /* xCurrentTimeInt64 */
    ++  apndSetSystemCall,            /* xSetSystemCall */
    ++  apndGetSystemCall,            /* xGetSystemCall */
    ++  apndNextSystemCall            /* xNextSystemCall */
    ++};
    ++
    ++static const sqlite3_io_methods apnd_io_methods = {
    ++  3,                              /* iVersion */
    ++  apndClose,                      /* xClose */
    ++  apndRead,                       /* xRead */
    ++  apndWrite,                      /* xWrite */
    ++  apndTruncate,                   /* xTruncate */
    ++  apndSync,                       /* xSync */
    ++  apndFileSize,                   /* xFileSize */
    ++  apndLock,                       /* xLock */
    ++  apndUnlock,                     /* xUnlock */
    ++  apndCheckReservedLock,          /* xCheckReservedLock */
    ++  apndFileControl,                /* xFileControl */
    ++  apndSectorSize,                 /* xSectorSize */
    ++  apndDeviceCharacteristics,      /* xDeviceCharacteristics */
    ++  apndShmMap,                     /* xShmMap */
    ++  apndShmLock,                    /* xShmLock */
    ++  apndShmBarrier,                 /* xShmBarrier */
    ++  apndShmUnmap,                   /* xShmUnmap */
    ++  apndFetch,                      /* xFetch */
    ++  apndUnfetch                     /* xUnfetch */
    ++};
    ++
    ++
    ++
    ++/*
    ++** Close an apnd-file.
    ++*/
    ++static int apndClose(sqlite3_file *pFile){
    ++  pFile = ORIGFILE(pFile);
    ++  return pFile->pMethods->xClose(pFile);
    ++}
    ++
    ++/*
    ++** Read data from an apnd-file.
    ++*/
    ++static int apndRead(
    ++  sqlite3_file *pFile, 
    ++  void *zBuf, 
    ++  int iAmt, 
    ++  sqlite_int64 iOfst
    ++){
    ++  ApndFile *p = (ApndFile *)pFile;
    ++  pFile = ORIGFILE(pFile);
    ++  return pFile->pMethods->xRead(pFile, zBuf, iAmt, iOfst+p->iPgOne);
    ++}
    ++
    ++/*
    ++** Add the append-mark onto the end of the file.
    ++*/
    ++static int apndWriteMark(ApndFile *p, sqlite3_file *pFile){
    ++  int i;
    ++  unsigned char a[APND_MARK_SIZE];
    ++  memcpy(a, APND_MARK_PREFIX, APND_MARK_PREFIX_SZ);
    ++  for(i=0; i<8; i++){
    ++    a[APND_MARK_PREFIX_SZ+i] = (p->iPgOne >> (56 - i*8)) & 0xff;
    ++  }
    ++  return pFile->pMethods->xWrite(pFile, a, APND_MARK_SIZE, p->iMark);
    ++}
    ++
    ++/*
    ++** Write data to an apnd-file.
    ++*/
    ++static int apndWrite(
    ++  sqlite3_file *pFile,
    ++  const void *zBuf,
    ++  int iAmt,
    ++  sqlite_int64 iOfst
    ++){
    ++  int rc;
    ++  ApndFile *p = (ApndFile *)pFile;
    ++  pFile = ORIGFILE(pFile);
    ++  if( iOfst+iAmt>=APND_MAX_SIZE ) return SQLITE_FULL;
    ++  rc = pFile->pMethods->xWrite(pFile, zBuf, iAmt, iOfst+p->iPgOne);
    ++  if( rc==SQLITE_OK &&  iOfst + iAmt + p->iPgOne > p->iMark ){
    ++    sqlite3_int64 sz = 0;
    ++    rc = pFile->pMethods->xFileSize(pFile, &sz);
    ++    if( rc==SQLITE_OK ){
    ++      p->iMark = sz - APND_MARK_SIZE;
    ++      if( iOfst + iAmt + p->iPgOne > p->iMark ){
    ++        p->iMark = p->iPgOne + iOfst + iAmt;
    ++        rc = apndWriteMark(p, pFile);
    ++      }
    ++    }
    ++  }
    ++  return rc;
    ++}
    ++
    ++/*
    ++** Truncate an apnd-file.
    ++*/
    ++static int apndTruncate(sqlite3_file *pFile, sqlite_int64 size){
    ++  int rc;
    ++  ApndFile *p = (ApndFile *)pFile;
    ++  pFile = ORIGFILE(pFile);
    ++  rc = pFile->pMethods->xTruncate(pFile, size+p->iPgOne+APND_MARK_SIZE);
    ++  if( rc==SQLITE_OK ){
    ++    p->iMark = p->iPgOne+size;
    ++    rc = apndWriteMark(p, pFile);
    ++  }
    ++  return rc;
    ++}
    ++
    ++/*
    ++** Sync an apnd-file.
    ++*/
    ++static int apndSync(sqlite3_file *pFile, int flags){
    ++  pFile = ORIGFILE(pFile);
    ++  return pFile->pMethods->xSync(pFile, flags);
    ++}
    ++
    ++/*
    ++** Return the current file-size of an apnd-file.
    ++*/
    ++static int apndFileSize(sqlite3_file *pFile, sqlite_int64 *pSize){
    ++  ApndFile *p = (ApndFile *)pFile;
    ++  int rc;
    ++  pFile = ORIGFILE(p);
    ++  rc = pFile->pMethods->xFileSize(pFile, pSize);
    ++  if( rc==SQLITE_OK && p->iPgOne ){
    ++    *pSize -= p->iPgOne + APND_MARK_SIZE;
    ++  }
    ++  return rc;
    ++}
    ++
    ++/*
    ++** Lock an apnd-file.
    ++*/
    ++static int apndLock(sqlite3_file *pFile, int eLock){
    ++  pFile = ORIGFILE(pFile);
    ++  return pFile->pMethods->xLock(pFile, eLock);
    ++}
    ++
    ++/*
    ++** Unlock an apnd-file.
    ++*/
    ++static int apndUnlock(sqlite3_file *pFile, int eLock){
    ++  pFile = ORIGFILE(pFile);
    ++  return pFile->pMethods->xUnlock(pFile, eLock);
    ++}
    ++
    ++/*
    ++** Check if another file-handle holds a RESERVED lock on an apnd-file.
    ++*/
    ++static int apndCheckReservedLock(sqlite3_file *pFile, int *pResOut){
    ++  pFile = ORIGFILE(pFile);
    ++  return pFile->pMethods->xCheckReservedLock(pFile, pResOut);
    ++}
    ++
    ++/*
    ++** File control method. For custom operations on an apnd-file.
    ++*/
    ++static int apndFileControl(sqlite3_file *pFile, int op, void *pArg){
    ++  ApndFile *p = (ApndFile *)pFile;
    ++  int rc;
    ++  pFile = ORIGFILE(pFile);
    ++  rc = pFile->pMethods->xFileControl(pFile, op, pArg);
    ++  if( rc==SQLITE_OK && op==SQLITE_FCNTL_VFSNAME ){
    ++    *(char**)pArg = sqlite3_mprintf("apnd(%lld)/%z", p->iPgOne, *(char**)pArg);
    ++  }
    ++  return rc;
    ++}
    ++
    ++/*
    ++** Return the sector-size in bytes for an apnd-file.
    ++*/
    ++static int apndSectorSize(sqlite3_file *pFile){
    ++  pFile = ORIGFILE(pFile);
    ++  return pFile->pMethods->xSectorSize(pFile);
    ++}
    ++
    ++/*
    ++** Return the device characteristic flags supported by an apnd-file.
    ++*/
    ++static int apndDeviceCharacteristics(sqlite3_file *pFile){
    ++  pFile = ORIGFILE(pFile);
    ++  return pFile->pMethods->xDeviceCharacteristics(pFile);
    ++}
    ++
    ++/* Create a shared memory file mapping */
    ++static int apndShmMap(
    ++  sqlite3_file *pFile,
    ++  int iPg,
    ++  int pgsz,
    ++  int bExtend,
    ++  void volatile **pp
    ++){
    ++  pFile = ORIGFILE(pFile);
    ++  return pFile->pMethods->xShmMap(pFile,iPg,pgsz,bExtend,pp);
    ++}
    ++
    ++/* Perform locking on a shared-memory segment */
    ++static int apndShmLock(sqlite3_file *pFile, int offset, int n, int flags){
    ++  pFile = ORIGFILE(pFile);
    ++  return pFile->pMethods->xShmLock(pFile,offset,n,flags);
    ++}
    ++
    ++/* Memory barrier operation on shared memory */
    ++static void apndShmBarrier(sqlite3_file *pFile){
    ++  pFile = ORIGFILE(pFile);
    ++  pFile->pMethods->xShmBarrier(pFile);
    ++}
    ++
    ++/* Unmap a shared memory segment */
    ++static int apndShmUnmap(sqlite3_file *pFile, int deleteFlag){
    ++  pFile = ORIGFILE(pFile);
    ++  return pFile->pMethods->xShmUnmap(pFile,deleteFlag);
    ++}
    ++
    ++/* Fetch a page of a memory-mapped file */
    ++static int apndFetch(
    ++  sqlite3_file *pFile,
    ++  sqlite3_int64 iOfst,
    ++  int iAmt,
    ++  void **pp
    ++){
    ++  ApndFile *p = (ApndFile *)pFile;
    ++  pFile = ORIGFILE(pFile);
    ++  return pFile->pMethods->xFetch(pFile, iOfst+p->iPgOne, iAmt, pp);
    ++}
    ++
    ++/* Release a memory-mapped page */
    ++static int apndUnfetch(sqlite3_file *pFile, sqlite3_int64 iOfst, void *pPage){
    ++  ApndFile *p = (ApndFile *)pFile;
    ++  pFile = ORIGFILE(pFile);
    ++  return pFile->pMethods->xUnfetch(pFile, iOfst+p->iPgOne, pPage);
    ++}
    ++
    ++/*
    ++** Check to see if the file is an ordinary SQLite database file.
    ++*/
    ++static int apndIsOrdinaryDatabaseFile(sqlite3_int64 sz, sqlite3_file *pFile){
    ++  int rc;
    ++  char zHdr[16];
    ++  static const char aSqliteHdr[] = "SQLite format 3";
    ++  if( sz<512 ) return 0;
    ++  rc = pFile->pMethods->xRead(pFile, zHdr, sizeof(zHdr), 0);
    ++  if( rc ) return 0;
    ++  return memcmp(zHdr, aSqliteHdr, sizeof(zHdr))==0;
    ++}
    ++
    ++/*
    ++** Try to read the append-mark off the end of a file.  Return the
    ++** start of the appended database if the append-mark is present.  If
    ++** there is no append-mark, return -1;
    ++*/
    ++static sqlite3_int64 apndReadMark(sqlite3_int64 sz, sqlite3_file *pFile){
    ++  int rc, i;
    ++  sqlite3_int64 iMark;
    ++  unsigned char a[APND_MARK_SIZE];
    ++
    ++  if( sz<=APND_MARK_SIZE ) return -1;
    ++  rc = pFile->pMethods->xRead(pFile, a, APND_MARK_SIZE, sz-APND_MARK_SIZE);
    ++  if( rc ) return -1;
    ++  if( memcmp(a, APND_MARK_PREFIX, APND_MARK_PREFIX_SZ)!=0 ) return -1;
    ++  iMark = ((sqlite3_int64)(a[APND_MARK_PREFIX_SZ]&0x7f))<<56;
    ++  for(i=1; i<8; i++){    
    ++    iMark += (sqlite3_int64)a[APND_MARK_PREFIX_SZ+i]<<(56-8*i);
    ++  }
    ++  return iMark;
    ++}
    ++
    ++/*
    ++** Open an apnd file handle.
    ++*/
    ++static int apndOpen(
    ++  sqlite3_vfs *pVfs,
    ++  const char *zName,
    ++  sqlite3_file *pFile,
    ++  int flags,
    ++  int *pOutFlags
    ++){
    ++  ApndFile *p;
    ++  sqlite3_file *pSubFile;
    ++  sqlite3_vfs *pSubVfs;
    ++  int rc;
    ++  sqlite3_int64 sz;
    ++  pSubVfs = ORIGVFS(pVfs);
    ++  if( (flags & SQLITE_OPEN_MAIN_DB)==0 ){
    ++    return pSubVfs->xOpen(pSubVfs, zName, pFile, flags, pOutFlags);
    ++  }
    ++  p = (ApndFile*)pFile;
    ++  memset(p, 0, sizeof(*p));
    ++  pSubFile = ORIGFILE(pFile);
    ++  p->base.pMethods = &apnd_io_methods;
    ++  rc = pSubVfs->xOpen(pSubVfs, zName, pSubFile, flags, pOutFlags);
    ++  if( rc ) goto apnd_open_done;
    ++  rc = pSubFile->pMethods->xFileSize(pSubFile, &sz);
    ++  if( rc ){
    ++    pSubFile->pMethods->xClose(pSubFile);
    ++    goto apnd_open_done;
    ++  }
    ++  if( apndIsOrdinaryDatabaseFile(sz, pSubFile) ){
    ++    memmove(pFile, pSubFile, pSubVfs->szOsFile);
    ++    return SQLITE_OK;
    ++  }
    ++  p->iMark = 0;
    ++  p->iPgOne = apndReadMark(sz, pFile);
    ++  if( p->iPgOne>0 ){
    ++    return SQLITE_OK;
    ++  }
    ++  if( (flags & SQLITE_OPEN_CREATE)==0 ){
    ++    pSubFile->pMethods->xClose(pSubFile);
    ++    rc = SQLITE_CANTOPEN;
    ++  }
    ++  p->iPgOne = (sz+0xfff) & ~(sqlite3_int64)0xfff;
    ++apnd_open_done:
    ++  if( rc ) pFile->pMethods = 0;
    ++  return rc;
    ++}
    ++
    ++/*
    ++** All other VFS methods are pass-thrus.
    ++*/
    ++static int apndDelete(sqlite3_vfs *pVfs, const char *zPath, int dirSync){
    ++  return ORIGVFS(pVfs)->xDelete(ORIGVFS(pVfs), zPath, dirSync);
    ++}
    ++static int apndAccess(
    ++  sqlite3_vfs *pVfs, 
    ++  const char *zPath, 
    ++  int flags, 
    ++  int *pResOut
    ++){
    ++  return ORIGVFS(pVfs)->xAccess(ORIGVFS(pVfs), zPath, flags, pResOut);
    ++}
    ++static int apndFullPathname(
    ++  sqlite3_vfs *pVfs, 
    ++  const char *zPath, 
    ++  int nOut, 
    ++  char *zOut
    ++){
    ++  return ORIGVFS(pVfs)->xFullPathname(ORIGVFS(pVfs),zPath,nOut,zOut);
    ++}
    ++static void *apndDlOpen(sqlite3_vfs *pVfs, const char *zPath){
    ++  return ORIGVFS(pVfs)->xDlOpen(ORIGVFS(pVfs), zPath);
    ++}
    ++static void apndDlError(sqlite3_vfs *pVfs, int nByte, char *zErrMsg){
    ++  ORIGVFS(pVfs)->xDlError(ORIGVFS(pVfs), nByte, zErrMsg);
    ++}
    ++static void (*apndDlSym(sqlite3_vfs *pVfs, void *p, const char *zSym))(void){
    ++  return ORIGVFS(pVfs)->xDlSym(ORIGVFS(pVfs), p, zSym);
    ++}
    ++static void apndDlClose(sqlite3_vfs *pVfs, void *pHandle){
    ++  ORIGVFS(pVfs)->xDlClose(ORIGVFS(pVfs), pHandle);
    ++}
    ++static int apndRandomness(sqlite3_vfs *pVfs, int nByte, char *zBufOut){
    ++  return ORIGVFS(pVfs)->xRandomness(ORIGVFS(pVfs), nByte, zBufOut);
    ++}
    ++static int apndSleep(sqlite3_vfs *pVfs, int nMicro){
    ++  return ORIGVFS(pVfs)->xSleep(ORIGVFS(pVfs), nMicro);
    ++}
    ++static int apndCurrentTime(sqlite3_vfs *pVfs, double *pTimeOut){
    ++  return ORIGVFS(pVfs)->xCurrentTime(ORIGVFS(pVfs), pTimeOut);
    ++}
    ++static int apndGetLastError(sqlite3_vfs *pVfs, int a, char *b){
    ++  return ORIGVFS(pVfs)->xGetLastError(ORIGVFS(pVfs), a, b);
    ++}
    ++static int apndCurrentTimeInt64(sqlite3_vfs *pVfs, sqlite3_int64 *p){
    ++  return ORIGVFS(pVfs)->xCurrentTimeInt64(ORIGVFS(pVfs), p);
    ++}
    ++static int apndSetSystemCall(
    ++  sqlite3_vfs *pVfs,
    ++  const char *zName,
    ++  sqlite3_syscall_ptr pCall
    ++){
    ++  return ORIGVFS(pVfs)->xSetSystemCall(ORIGVFS(pVfs),zName,pCall);
    ++}
    ++static sqlite3_syscall_ptr apndGetSystemCall(
    ++  sqlite3_vfs *pVfs,
    ++  const char *zName
    ++){
    ++  return ORIGVFS(pVfs)->xGetSystemCall(ORIGVFS(pVfs),zName);
    ++}
    ++static const char *apndNextSystemCall(sqlite3_vfs *pVfs, const char *zName){
    ++  return ORIGVFS(pVfs)->xNextSystemCall(ORIGVFS(pVfs), zName);
    ++}
    ++
    ++  
    ++#ifdef _WIN32
    ++
    ++#endif
    ++/* 
    ++** This routine is called when the extension is loaded.
    ++** Register the new VFS.
    ++*/
    ++int sqlite3_appendvfs_init(
    ++  sqlite3 *db, 
    ++  char **pzErrMsg, 
    ++  const sqlite3_api_routines *pApi
    ++){
    ++  int rc = SQLITE_OK;
    ++  sqlite3_vfs *pOrig;
    ++  SQLITE_EXTENSION_INIT2(pApi);
    ++  (void)pzErrMsg;
    ++  (void)db;
    ++  pOrig = sqlite3_vfs_find(0);
    ++  apnd_vfs.iVersion = pOrig->iVersion;
    ++  apnd_vfs.pAppData = pOrig;
    ++  apnd_vfs.szOsFile = pOrig->szOsFile + sizeof(ApndFile);
    ++  rc = sqlite3_vfs_register(&apnd_vfs, 0);
    ++#ifdef APPENDVFS_TEST
    ++  if( rc==SQLITE_OK ){
    ++    rc = sqlite3_auto_extension((void(*)(void))apndvfsRegister);
    ++  }
    ++#endif
    ++  if( rc==SQLITE_OK ) rc = SQLITE_OK_LOAD_PERMANENTLY;
    ++  return rc;
    ++}
    ++
    ++/************************* End ../ext/misc/appendvfs.c ********************/
    ++#ifdef SQLITE_HAVE_ZLIB
    ++/************************* Begin ../ext/misc/zipfile.c ******************/
    ++/*
    ++** 2017-12-26
    ++**
    ++** 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 implements a virtual table for reading and writing ZIP archive
    ++** files.
    ++**
    ++** Usage example:
    ++**
    ++**     SELECT name, sz, datetime(mtime,'unixepoch') FROM zipfile($filename);
    ++**
    ++** Current limitations:
    ++**
    ++**    *  No support for encryption
    ++**    *  No support for ZIP archives spanning multiple files
    ++**    *  No support for zip64 extensions
    ++**    *  Only the "inflate/deflate" (zlib) compression method is supported
    ++*/
    ++SQLITE_EXTENSION_INIT1
    ++#include <stdio.h>
    ++#include <string.h>
    ++#include <assert.h>
    ++
    ++#include <sys/types.h>
    ++#include <sys/stat.h>
    ++#include <fcntl.h>
    ++#if !defined(_WIN32) && !defined(WIN32)
    ++#  include <unistd.h>
    ++#  include <dirent.h>
    ++#  include <utime.h>
    ++#else
    ++#  include <io.h>
    ++#endif
    ++#include <time.h>
    ++#include <errno.h>
    ++
    ++#include <zlib.h>
    ++
    ++#ifndef SQLITE_OMIT_VIRTUALTABLE
    ++
    ++#ifndef SQLITE_AMALGAMATION
    ++/* typedef sqlite3_int64 i64; */
    ++/* typedef unsigned char u8; */
    ++typedef unsigned short u16;
    ++typedef unsigned long u32;
    ++#define MIN(a,b) ((a)<(b) ? (a) : (b))
    ++#endif
    ++
    ++static const char ZIPFILE_SCHEMA[] = 
    ++  "CREATE TABLE y("
    ++    "name PRIMARY KEY,"  /* 0: Name of file in zip archive */
    ++    "mode,"              /* 1: POSIX mode for file */
    ++    "mtime,"             /* 2: Last modification time (secs since 1970)*/
    ++    "sz,"                /* 3: Size of object */
    ++    "rawdata,"           /* 4: Raw data */
    ++    "data,"              /* 5: Uncompressed data */
    ++    "method,"            /* 6: Compression method (integer) */
    ++    "z HIDDEN"           /* 7: Name of zip file */
    ++  ") WITHOUT ROWID;";
    ++
    ++#define ZIPFILE_F_COLUMN_IDX 7    /* Index of column "file" in the above */
    ++#define ZIPFILE_BUFFER_SIZE (64*1024)
    ++
    ++
    ++/*
    ++** Magic numbers used to read and write zip files.
    ++**
    ++** ZIPFILE_NEWENTRY_MADEBY:
    ++**   Use this value for the "version-made-by" field in new zip file
    ++**   entries. The upper byte indicates "unix", and the lower byte 
    ++**   indicates that the zip file matches pkzip specification 3.0. 
    ++**   This is what info-zip seems to do.
    ++**
    ++** ZIPFILE_NEWENTRY_REQUIRED:
    ++**   Value for "version-required-to-extract" field of new entries.
    ++**   Version 2.0 is required to support folders and deflate compression.
    ++**
    ++** ZIPFILE_NEWENTRY_FLAGS:
    ++**   Value for "general-purpose-bit-flags" field of new entries. Bit
    ++**   11 means "utf-8 filename and comment".
    ++**
    ++** ZIPFILE_SIGNATURE_CDS:
    ++**   First 4 bytes of a valid CDS record.
    ++**
    ++** ZIPFILE_SIGNATURE_LFH:
    ++**   First 4 bytes of a valid LFH record.
    ++*/
    ++#define ZIPFILE_EXTRA_TIMESTAMP   0x5455
    ++#define ZIPFILE_NEWENTRY_MADEBY   ((3<<8) + 30)
    ++#define ZIPFILE_NEWENTRY_REQUIRED 20
    ++#define ZIPFILE_NEWENTRY_FLAGS    0x800
    ++#define ZIPFILE_SIGNATURE_CDS     0x02014b50
    ++#define ZIPFILE_SIGNATURE_LFH     0x04034b50
    ++#define ZIPFILE_SIGNATURE_EOCD    0x06054b50
    ++#define ZIPFILE_LFH_FIXED_SZ      30
    ++
    ++/*
    ++** Set the error message contained in context ctx to the results of
    ++** vprintf(zFmt, ...).
    ++*/
    ++static void zipfileCtxErrorMsg(sqlite3_context *ctx, const char *zFmt, ...){
    ++  char *zMsg = 0;
    ++  va_list ap;
    ++  va_start(ap, zFmt);
    ++  zMsg = sqlite3_vmprintf(zFmt, ap);
    ++  sqlite3_result_error(ctx, zMsg, -1);
    ++  sqlite3_free(zMsg);
    ++  va_end(ap);
    ++}
    ++
    ++
    ++/*
    ++*** 4.3.16  End of central directory record:
    ++***
    ++***   end of central dir signature    4 bytes  (0x06054b50)
    ++***   number of this disk             2 bytes
    ++***   number of the disk with the
    ++***   start of the central directory  2 bytes
    ++***   total number of entries in the
    ++***   central directory on this disk  2 bytes
    ++***   total number of entries in
    ++***   the central directory           2 bytes
    ++***   size of the central directory   4 bytes
    ++***   offset of start of central
    ++***   directory with respect to
    ++***   the starting disk number        4 bytes
    ++***   .ZIP file comment length        2 bytes
    ++***   .ZIP file comment       (variable size)
    ++*/
    ++typedef struct ZipfileEOCD ZipfileEOCD;
    ++struct ZipfileEOCD {
    ++  u16 iDisk;
    ++  u16 iFirstDisk;
    ++  u16 nEntry;
    ++  u16 nEntryTotal;
    ++  u32 nSize;
    ++  u32 iOffset;
    ++};
    ++
    ++/*
    ++*** 4.3.12  Central directory structure:
    ++***
    ++*** ...
    ++***
    ++***   central file header signature   4 bytes  (0x02014b50)
    ++***   version made by                 2 bytes
    ++***   version needed to extract       2 bytes
    ++***   general purpose bit flag        2 bytes
    ++***   compression method              2 bytes
    ++***   last mod file time              2 bytes
    ++***   last mod file date              2 bytes
    ++***   crc-32                          4 bytes
    ++***   compressed size                 4 bytes
    ++***   uncompressed size               4 bytes
    ++***   file name length                2 bytes
    ++***   extra field length              2 bytes
    ++***   file comment length             2 bytes
    ++***   disk number start               2 bytes
    ++***   internal file attributes        2 bytes
    ++***   external file attributes        4 bytes
    ++***   relative offset of local header 4 bytes
    ++*/
    ++typedef struct ZipfileCDS ZipfileCDS;
    ++struct ZipfileCDS {
    ++  u16 iVersionMadeBy;
    ++  u16 iVersionExtract;
    ++  u16 flags;
    ++  u16 iCompression;
    ++  u16 mTime;
    ++  u16 mDate;
    ++  u32 crc32;
    ++  u32 szCompressed;
    ++  u32 szUncompressed;
    ++  u16 nFile;
    ++  u16 nExtra;
    ++  u16 nComment;
    ++  u16 iDiskStart;
    ++  u16 iInternalAttr;
    ++  u32 iExternalAttr;
    ++  u32 iOffset;
    ++  char *zFile;                    /* Filename (sqlite3_malloc()) */
    ++};
    ++
    ++/*
    ++*** 4.3.7  Local file header:
    ++***
    ++***   local file header signature     4 bytes  (0x04034b50)
    ++***   version needed to extract       2 bytes
    ++***   general purpose bit flag        2 bytes
    ++***   compression method              2 bytes
    ++***   last mod file time              2 bytes
    ++***   last mod file date              2 bytes
    ++***   crc-32                          4 bytes
    ++***   compressed size                 4 bytes
    ++***   uncompressed size               4 bytes
    ++***   file name length                2 bytes
    ++***   extra field length              2 bytes
    ++***   
    ++*/
    ++typedef struct ZipfileLFH ZipfileLFH;
    ++struct ZipfileLFH {
    ++  u16 iVersionExtract;
    ++  u16 flags;
    ++  u16 iCompression;
    ++  u16 mTime;
    ++  u16 mDate;
    ++  u32 crc32;
    ++  u32 szCompressed;
    ++  u32 szUncompressed;
    ++  u16 nFile;
    ++  u16 nExtra;
    ++};
    ++
    ++typedef struct ZipfileEntry ZipfileEntry;
    ++struct ZipfileEntry {
    ++  char *zPath;               /* Path of zipfile entry */
    ++  u8 *aCdsEntry;             /* Buffer containing entire CDS entry */
    ++  int nCdsEntry;             /* Size of buffer aCdsEntry[] in bytes */
    ++  int bDeleted;              /* True if entry has been deleted */
    ++  ZipfileEntry *pNext;       /* Next element in in-memory CDS */
    ++};
    ++
    ++/* 
    ++** Cursor type for recursively iterating through a directory structure.
    ++*/
    ++typedef struct ZipfileCsr ZipfileCsr;
    ++struct ZipfileCsr {
    ++  sqlite3_vtab_cursor base;  /* Base class - must be first */
    ++  i64 iId;                   /* Cursor ID */
    ++  int bEof;                  /* True when at EOF */
    ++
    ++  /* Used outside of write transactions */
    ++  FILE *pFile;               /* Zip file */
    ++  i64 iNextOff;              /* Offset of next record in central directory */
    ++  ZipfileEOCD eocd;          /* Parse of central directory record */
    ++
    ++  /* Used inside write transactions */
    ++  ZipfileEntry *pCurrent;
    ++
    ++  ZipfileCDS cds;            /* Central Directory Structure */
    ++  ZipfileLFH lfh;            /* Local File Header for current entry */
    ++  i64 iDataOff;              /* Offset in zipfile to data */
    ++  u32 mTime;                 /* Extended mtime value */
    ++  int flags;                 /* Flags byte (see below for bits) */
    ++  ZipfileCsr *pCsrNext;      /* Next cursor on same virtual table */
    ++};
    ++
    ++/*
    ++** Values for ZipfileCsr.flags.
    ++*/
    ++#define ZIPFILE_MTIME_VALID 0x0001
    ++
    ++typedef struct ZipfileTab ZipfileTab;
    ++struct ZipfileTab {
    ++  sqlite3_vtab base;         /* Base class - must be first */
    ++  char *zFile;               /* Zip file this table accesses (may be NULL) */
    ++  u8 *aBuffer;               /* Temporary buffer used for various tasks */
    ++
    ++  ZipfileCsr *pCsrList;      /* List of cursors */
    ++  i64 iNextCsrid;
    ++
    ++  /* The following are used by write transactions only */
    ++  ZipfileEntry *pFirstEntry; /* Linked list of all files (if pWriteFd!=0) */
    ++  ZipfileEntry *pLastEntry;  /* Last element in pFirstEntry list */
    ++  FILE *pWriteFd;            /* File handle open on zip archive */
    ++  i64 szCurrent;             /* Current size of zip archive */
    ++  i64 szOrig;                /* Size of archive at start of transaction */
    ++};
    ++
    ++static void zipfileDequote(char *zIn){
    ++  char q = zIn[0];
    ++  if( q=='"' || q=='\'' || q=='`' || q=='[' ){
    ++    char c;
    ++    int iIn = 1;
    ++    int iOut = 0;
    ++    if( q=='[' ) q = ']';
    ++    while( (c = zIn[iIn++]) ){
    ++      if( c==q ){
    ++        if( zIn[iIn++]!=q ) break;
    ++      }
    ++      zIn[iOut++] = c;
    ++    }
    ++    zIn[iOut] = '\0';
    ++  }
    ++}
    ++
    ++/*
    ++** Construct a new ZipfileTab virtual table object.
    ++** 
    ++**   argv[0]   -> module name  ("zipfile")
    ++**   argv[1]   -> database name
    ++**   argv[2]   -> table name
    ++**   argv[...] -> "column name" and other module argument fields.
    ++*/
    ++static int zipfileConnect(
    ++  sqlite3 *db,
    ++  void *pAux,
    ++  int argc, const char *const*argv,
    ++  sqlite3_vtab **ppVtab,
    ++  char **pzErr
    ++){
    ++  int nByte = sizeof(ZipfileTab) + ZIPFILE_BUFFER_SIZE;
    ++  int nFile = 0;
    ++  const char *zFile = 0;
    ++  ZipfileTab *pNew = 0;
    ++  int rc;
    ++
    ++  if( argc>3 ){
    ++    zFile = argv[3];
    ++    nFile = (int)strlen(zFile)+1;
    ++  }
    ++
    ++  rc = sqlite3_declare_vtab(db, ZIPFILE_SCHEMA);
    ++  if( rc==SQLITE_OK ){
    ++    pNew = (ZipfileTab*)sqlite3_malloc(nByte+nFile);
    ++    if( pNew==0 ) return SQLITE_NOMEM;
    ++    memset(pNew, 0, nByte+nFile);
    ++    pNew->aBuffer = (u8*)&pNew[1];
    ++    if( zFile ){
    ++      pNew->zFile = (char*)&pNew->aBuffer[ZIPFILE_BUFFER_SIZE];
    ++      memcpy(pNew->zFile, zFile, nFile);
    ++      zipfileDequote(pNew->zFile);
    ++    }
    ++  }
    ++  *ppVtab = (sqlite3_vtab*)pNew;
    ++  return rc;
    ++}
    ++
    ++/*
    ++** This method is the destructor for zipfile vtab objects.
    ++*/
    ++static int zipfileDisconnect(sqlite3_vtab *pVtab){
    ++  sqlite3_free(pVtab);
    ++  return SQLITE_OK;
    ++}
    ++
    ++/*
    ++** Constructor for a new ZipfileCsr object.
    ++*/
    ++static int zipfileOpen(sqlite3_vtab *p, sqlite3_vtab_cursor **ppCsr){
    ++  ZipfileTab *pTab = (ZipfileTab*)p;
    ++  ZipfileCsr *pCsr;
    ++  pCsr = sqlite3_malloc(sizeof(*pCsr));
    ++  *ppCsr = (sqlite3_vtab_cursor*)pCsr;
    ++  if( pCsr==0 ){
    ++    return SQLITE_NOMEM;
    ++  }
    ++  memset(pCsr, 0, sizeof(*pCsr));
    ++  pCsr->iId = ++pTab->iNextCsrid;
    ++  pCsr->pCsrNext = pTab->pCsrList;
    ++  pTab->pCsrList = pCsr;
    ++  return SQLITE_OK;
    ++}
    ++
    ++/*
    ++** Reset a cursor back to the state it was in when first returned
    ++** by zipfileOpen().
    ++*/
    ++static void zipfileResetCursor(ZipfileCsr *pCsr){
    ++  sqlite3_free(pCsr->cds.zFile);
    ++  pCsr->cds.zFile = 0;
    ++  pCsr->bEof = 0;
    ++  if( pCsr->pFile ){
    ++    fclose(pCsr->pFile);
    ++    pCsr->pFile = 0;
    ++  }
    ++}
    ++
    ++/*
    ++** Destructor for an ZipfileCsr.
    ++*/
    ++static int zipfileClose(sqlite3_vtab_cursor *cur){
    ++  ZipfileCsr *pCsr = (ZipfileCsr*)cur;
    ++  ZipfileTab *pTab = (ZipfileTab*)(pCsr->base.pVtab);
    ++  ZipfileCsr **pp;
    ++  zipfileResetCursor(pCsr);
    ++
    ++  /* Remove this cursor from the ZipfileTab.pCsrList list. */
    ++  for(pp=&pTab->pCsrList; *pp; pp=&((*pp)->pCsrNext)){
    ++    if( *pp==pCsr ){ 
    ++      *pp = pCsr->pCsrNext;
    ++      break;
    ++    }
    ++  }
    ++
    ++  sqlite3_free(pCsr);
    ++  return SQLITE_OK;
    ++}
    ++
    ++/*
    ++** Set the error message for the virtual table associated with cursor
    ++** pCsr to the results of vprintf(zFmt, ...).
    ++*/
    ++static void zipfileSetErrmsg(ZipfileCsr *pCsr, const char *zFmt, ...){
    ++  va_list ap;
    ++  va_start(ap, zFmt);
    ++  pCsr->base.pVtab->zErrMsg = sqlite3_vmprintf(zFmt, ap);
    ++  va_end(ap);
    ++}
    ++
    ++static int zipfileReadData(
    ++  FILE *pFile,                    /* Read from this file */
    ++  u8 *aRead,                      /* Read into this buffer */
    ++  int nRead,                      /* Number of bytes to read */
    ++  i64 iOff,                       /* Offset to read from */
    ++  char **pzErrmsg                 /* OUT: Error message (from sqlite3_malloc) */
    ++){
    ++  size_t n;
    ++  fseek(pFile, (long)iOff, SEEK_SET);
    ++  n = fread(aRead, 1, nRead, pFile);
    ++  if( (int)n!=nRead ){
    ++    *pzErrmsg = sqlite3_mprintf("error in fread()");
    ++    return SQLITE_ERROR;
    ++  }
    ++  return SQLITE_OK;
    ++}
    ++
    ++static int zipfileAppendData(
    ++  ZipfileTab *pTab,
    ++  const u8 *aWrite,
    ++  int nWrite
    ++){
    ++  size_t n;
    ++  fseek(pTab->pWriteFd, (long)pTab->szCurrent, SEEK_SET);
    ++  n = fwrite(aWrite, 1, nWrite, pTab->pWriteFd);
    ++  if( (int)n!=nWrite ){
    ++    pTab->base.zErrMsg = sqlite3_mprintf("error in fwrite()");
    ++    return SQLITE_ERROR;
    ++  }
    ++  pTab->szCurrent += nWrite;
    ++  return SQLITE_OK;
    ++}
    ++
    ++static u16 zipfileGetU16(const u8 *aBuf){
    ++  return (aBuf[1] << 8) + aBuf[0];
    ++}
    ++static u32 zipfileGetU32(const u8 *aBuf){
    ++  return ((u32)(aBuf[3]) << 24)
    ++       + ((u32)(aBuf[2]) << 16)
    ++       + ((u32)(aBuf[1]) <<  8)
    ++       + ((u32)(aBuf[0]) <<  0);
    ++}
    ++
    ++static void zipfilePutU16(u8 *aBuf, u16 val){
    ++  aBuf[0] = val & 0xFF;
    ++  aBuf[1] = (val>>8) & 0xFF;
    ++}
    ++static void zipfilePutU32(u8 *aBuf, u32 val){
    ++  aBuf[0] = val & 0xFF;
    ++  aBuf[1] = (val>>8) & 0xFF;
    ++  aBuf[2] = (val>>16) & 0xFF;
    ++  aBuf[3] = (val>>24) & 0xFF;
    ++}
    ++
    ++#define zipfileRead32(aBuf) ( aBuf+=4, zipfileGetU32(aBuf-4) )
    ++#define zipfileRead16(aBuf) ( aBuf+=2, zipfileGetU16(aBuf-2) )
    ++
    ++#define zipfileWrite32(aBuf,val) { zipfilePutU32(aBuf,val); aBuf+=4; }
    ++#define zipfileWrite16(aBuf,val) { zipfilePutU16(aBuf,val); aBuf+=2; }
    ++
    ++static u8* zipfileCsrBuffer(ZipfileCsr *pCsr){
    ++  return ((ZipfileTab*)(pCsr->base.pVtab))->aBuffer;
    ++}
    ++
    ++/*
    ++** Magic numbers used to read CDS records.
    ++*/
    ++#define ZIPFILE_CDS_FIXED_SZ         46
    ++#define ZIPFILE_CDS_NFILE_OFF        28
    ++
    ++/*
    ++** Decode the CDS record in buffer aBuf into (*pCDS). Return SQLITE_ERROR
    ++** if the record is not well-formed, or SQLITE_OK otherwise.
    ++*/
    ++static int zipfileReadCDS(u8 *aBuf, ZipfileCDS *pCDS){
    ++  u8 *aRead = aBuf;
    ++  u32 sig = zipfileRead32(aRead);
    ++  int rc = SQLITE_OK;
    ++  if( sig!=ZIPFILE_SIGNATURE_CDS ){
    ++    rc = SQLITE_ERROR;
    ++  }else{
    ++    pCDS->iVersionMadeBy = zipfileRead16(aRead);
    ++    pCDS->iVersionExtract = zipfileRead16(aRead);
    ++    pCDS->flags = zipfileRead16(aRead);
    ++    pCDS->iCompression = zipfileRead16(aRead);
    ++    pCDS->mTime = zipfileRead16(aRead);
    ++    pCDS->mDate = zipfileRead16(aRead);
    ++    pCDS->crc32 = zipfileRead32(aRead);
    ++    pCDS->szCompressed = zipfileRead32(aRead);
    ++    pCDS->szUncompressed = zipfileRead32(aRead);
    ++    assert( aRead==&aBuf[ZIPFILE_CDS_NFILE_OFF] );
    ++    pCDS->nFile = zipfileRead16(aRead);
    ++    pCDS->nExtra = zipfileRead16(aRead);
    ++    pCDS->nComment = zipfileRead16(aRead);
    ++    pCDS->iDiskStart = zipfileRead16(aRead);
    ++    pCDS->iInternalAttr = zipfileRead16(aRead);
    ++    pCDS->iExternalAttr = zipfileRead32(aRead);
    ++    pCDS->iOffset = zipfileRead32(aRead);
    ++    assert( aRead==&aBuf[ZIPFILE_CDS_FIXED_SZ] );
    ++  }
    ++
    ++  return rc;
    ++}
    ++
    ++/*
    ++** Read the CDS record for the current entry from disk into pCsr->cds.
    ++*/
    ++static int zipfileCsrReadCDS(ZipfileCsr *pCsr){
    ++  char **pzErr = &pCsr->base.pVtab->zErrMsg;
    ++  u8 *aRead;
    ++  int rc = SQLITE_OK;
    ++
    ++  sqlite3_free(pCsr->cds.zFile);
    ++  pCsr->cds.zFile = 0;
    ++
    ++  if( pCsr->pCurrent==0 ){
    ++    aRead = zipfileCsrBuffer(pCsr);
    ++    rc = zipfileReadData(
    ++        pCsr->pFile, aRead, ZIPFILE_CDS_FIXED_SZ, pCsr->iNextOff, pzErr
    ++    );
    ++  }else{
    ++    aRead = pCsr->pCurrent->aCdsEntry;
    ++  }
    ++
    ++  if( rc==SQLITE_OK ){
    ++    rc = zipfileReadCDS(aRead, &pCsr->cds);
    ++    if( rc!=SQLITE_OK ){
    ++      assert( pCsr->pCurrent==0 );
    ++      zipfileSetErrmsg(pCsr,"failed to read CDS at offset %lld",pCsr->iNextOff);
    ++    }else{
    ++      int nRead;
    ++      if( pCsr->pCurrent==0 ){
    ++        nRead = pCsr->cds.nFile + pCsr->cds.nExtra;
    ++        aRead = zipfileCsrBuffer(pCsr);
    ++        pCsr->iNextOff += ZIPFILE_CDS_FIXED_SZ;
    ++        rc = zipfileReadData(pCsr->pFile, aRead, nRead, pCsr->iNextOff, pzErr);
    ++      }else{
    ++        aRead = &aRead[ZIPFILE_CDS_FIXED_SZ];
    ++      }
    ++
    ++      if( rc==SQLITE_OK ){
    ++        pCsr->cds.zFile = sqlite3_mprintf("%.*s", (int)pCsr->cds.nFile, aRead);
    ++        pCsr->iNextOff += pCsr->cds.nFile;
    ++        pCsr->iNextOff += pCsr->cds.nExtra;
    ++        pCsr->iNextOff += pCsr->cds.nComment;
    ++      }
    ++
    ++      /* Scan the cds.nExtra bytes of "extra" fields for any that can
    ++      ** be interpreted. The general format of an extra field is:
    ++      **
    ++      **   Header ID    2 bytes
    ++      **   Data Size    2 bytes
    ++      **   Data         N bytes
    ++      **
    ++      */
    ++      if( rc==SQLITE_OK ){
    ++        u8 *p = &aRead[pCsr->cds.nFile];
    ++        u8 *pEnd = &p[pCsr->cds.nExtra];
    ++
    ++        while( p<pEnd ){
    ++          u16 id = zipfileRead16(p);
    ++          u16 nByte = zipfileRead16(p);
    ++
    ++          switch( id ){
    ++            case ZIPFILE_EXTRA_TIMESTAMP: {
    ++              u8 b = p[0];
    ++              if( b & 0x01 ){     /* 0x01 -> modtime is present */
    ++                pCsr->mTime = zipfileGetU32(&p[1]);
    ++                pCsr->flags |= ZIPFILE_MTIME_VALID;
    ++              }
    ++              break;
    ++            }
    ++          }
    ++
    ++          p += nByte;
    ++        }
    ++      }
    ++    }
    ++  }
    ++
    ++  return rc;
    ++}
    ++
    ++static FILE *zipfileGetFd(ZipfileCsr *pCsr){
    ++  if( pCsr->pFile ) return pCsr->pFile;
    ++  return ((ZipfileTab*)(pCsr->base.pVtab))->pWriteFd;
    ++}
    ++
    ++static int zipfileReadLFH(
    ++  FILE *pFd, 
    ++  i64 iOffset,
    ++  u8 *aTmp, 
    ++  ZipfileLFH *pLFH, 
    ++  char **pzErr
    ++){
    ++  u8 *aRead = aTmp;
    ++  static const int szFix = ZIPFILE_LFH_FIXED_SZ;
    ++  int rc;
    ++
    ++  rc = zipfileReadData(pFd, aRead, szFix, iOffset, pzErr);
    ++  if( rc==SQLITE_OK ){
    ++    u32 sig = zipfileRead32(aRead);
    ++    if( sig!=ZIPFILE_SIGNATURE_LFH ){
    ++      *pzErr = sqlite3_mprintf("failed to read LFH at offset %d", (int)iOffset);
    ++      rc = SQLITE_ERROR;
    ++    }else{
    ++      pLFH->iVersionExtract = zipfileRead16(aRead);
    ++      pLFH->flags = zipfileRead16(aRead);
    ++      pLFH->iCompression = zipfileRead16(aRead);
    ++      pLFH->mTime = zipfileRead16(aRead);
    ++      pLFH->mDate = zipfileRead16(aRead);
    ++      pLFH->crc32 = zipfileRead32(aRead);
    ++      pLFH->szCompressed = zipfileRead32(aRead);
    ++      pLFH->szUncompressed = zipfileRead32(aRead);
    ++      pLFH->nFile = zipfileRead16(aRead);
    ++      pLFH->nExtra = zipfileRead16(aRead);
    ++      assert( aRead==&aTmp[szFix] );
    ++    }
    ++  }
    ++  return rc;
    ++}
    ++
    ++static int zipfileCsrReadLFH(ZipfileCsr *pCsr){
    ++  FILE *pFile = zipfileGetFd(pCsr);
    ++  char **pzErr = &pCsr->base.pVtab->zErrMsg;
    ++  u8 *aRead = zipfileCsrBuffer(pCsr);
    ++  int rc = zipfileReadLFH(pFile, pCsr->cds.iOffset, aRead, &pCsr->lfh, pzErr);
    ++  pCsr->iDataOff =  pCsr->cds.iOffset + ZIPFILE_LFH_FIXED_SZ;
    ++  pCsr->iDataOff += pCsr->lfh.nFile+pCsr->lfh.nExtra;
    ++  return rc;
    ++}
    ++
    ++
    ++/*
    ++** Advance an ZipfileCsr to its next row of output.
    ++*/
    ++static int zipfileNext(sqlite3_vtab_cursor *cur){
    ++  ZipfileCsr *pCsr = (ZipfileCsr*)cur;
    ++  int rc = SQLITE_OK;
    ++  pCsr->flags = 0;
    ++
    ++  if( pCsr->pCurrent==0 ){
    ++    i64 iEof = pCsr->eocd.iOffset + pCsr->eocd.nSize;
    ++    if( pCsr->iNextOff>=iEof ){
    ++      pCsr->bEof = 1;
    ++    }
    ++  }else{
    ++    assert( pCsr->pFile==0 );
    ++    do {
    ++      pCsr->pCurrent = pCsr->pCurrent->pNext;
    ++    }while( pCsr->pCurrent && pCsr->pCurrent->bDeleted );
    ++    if( pCsr->pCurrent==0 ){
    ++      pCsr->bEof = 1;
    ++    }
    ++  }
    ++
    ++  if( pCsr->bEof==0 ){
    ++    rc = zipfileCsrReadCDS(pCsr);
    ++    if( rc==SQLITE_OK ){
    ++      rc = zipfileCsrReadLFH(pCsr);
    ++    }
    ++  }
    ++
    ++  return rc;
    ++}
    ++
    ++/*
    ++** "Standard" MS-DOS time format:
    ++**
    ++**   File modification time:
    ++**     Bits 00-04: seconds divided by 2
    ++**     Bits 05-10: minute
    ++**     Bits 11-15: hour
    ++**   File modification date:
    ++**     Bits 00-04: day
    ++**     Bits 05-08: month (1-12)
    ++**     Bits 09-15: years from 1980 
    ++*/
    ++static time_t zipfileMtime(ZipfileCsr *pCsr){
    ++  struct tm t;
    ++  memset(&t, 0, sizeof(t));
    ++  t.tm_sec = (pCsr->cds.mTime & 0x1F)*2;
    ++  t.tm_min = (pCsr->cds.mTime >> 5) & 0x2F;
    ++  t.tm_hour = (pCsr->cds.mTime >> 11) & 0x1F;
    ++
    ++  t.tm_mday = (pCsr->cds.mDate & 0x1F);
    ++  t.tm_mon = ((pCsr->cds.mDate >> 5) & 0x0F) - 1;
    ++  t.tm_year = 80 + ((pCsr->cds.mDate >> 9) & 0x7F);
    ++
    ++  return mktime(&t);
    ++}
    ++
    ++static void zipfileMtimeToDos(ZipfileCDS *pCds, u32 mTime){
    ++  time_t t = (time_t)mTime;
    ++  struct tm res;
    ++
    ++#if !defined(_WIN32) && !defined(WIN32)
    ++  localtime_r(&t, &res);
    ++#else
    ++  memcpy(&res, localtime(&t), sizeof(struct tm));
    ++#endif
    ++
    ++  pCds->mTime = (u16)(
    ++    (res.tm_sec / 2) + 
    ++    (res.tm_min << 5) +
    ++    (res.tm_hour << 11));
    ++
    ++  pCds->mDate = (u16)(
    ++    (res.tm_mday-1) +
    ++    ((res.tm_mon+1) << 5) +
    ++    ((res.tm_year-80) << 9));
    ++}
    ++
    ++static void zipfileInflate(
    ++  sqlite3_context *pCtx,          /* Store error here, if any */
    ++  const u8 *aIn,                  /* Compressed data */
    ++  int nIn,                        /* Size of buffer aIn[] in bytes */
    ++  int nOut                        /* Expected output size */
    ++){
    ++  u8 *aRes = sqlite3_malloc(nOut);
    ++  if( aRes==0 ){
    ++    sqlite3_result_error_nomem(pCtx);
    ++  }else{
    ++    int err;
    ++    z_stream str;
    ++    memset(&str, 0, sizeof(str));
    ++
    ++    str.next_in = (Byte*)aIn;
    ++    str.avail_in = nIn;
    ++    str.next_out = (Byte*)aRes;
    ++    str.avail_out = nOut;
    ++
    ++    err = inflateInit2(&str, -15);
    ++    if( err!=Z_OK ){
    ++      zipfileCtxErrorMsg(pCtx, "inflateInit2() failed (%d)", err);
    ++    }else{
    ++      err = inflate(&str, Z_NO_FLUSH);
    ++      if( err!=Z_STREAM_END ){
    ++        zipfileCtxErrorMsg(pCtx, "inflate() failed (%d)", err);
    ++      }else{
    ++        sqlite3_result_blob(pCtx, aRes, nOut, SQLITE_TRANSIENT);
    ++      }
    ++    }
    ++    sqlite3_free(aRes);
    ++    inflateEnd(&str);
    ++  }
    ++}
    ++
    ++static int zipfileDeflate(
    ++  ZipfileTab *pTab,               /* Set error message here */
    ++  const u8 *aIn, int nIn,         /* Input */
    ++  u8 **ppOut, int *pnOut          /* Output */
    ++){
    ++  int nAlloc = (int)compressBound(nIn);
    ++  u8 *aOut;
    ++  int rc = SQLITE_OK;
    ++
    ++  aOut = (u8*)sqlite3_malloc(nAlloc);
    ++  if( aOut==0 ){
    ++    rc = SQLITE_NOMEM;
    ++  }else{
    ++    int res;
    ++    z_stream str;
    ++    memset(&str, 0, sizeof(str));
    ++    str.next_in = (Bytef*)aIn;
    ++    str.avail_in = nIn;
    ++    str.next_out = aOut;
    ++    str.avail_out = nAlloc;
    ++
    ++    deflateInit2(&str, 9, Z_DEFLATED, -15, 8, Z_DEFAULT_STRATEGY);
    ++    res = deflate(&str, Z_FINISH);
    ++
    ++    if( res==Z_STREAM_END ){
    ++      *ppOut = aOut;
    ++      *pnOut = (int)str.total_out;
    ++    }else{
    ++      sqlite3_free(aOut);
    ++      pTab->base.zErrMsg = sqlite3_mprintf("zipfile: deflate() error");
    ++      rc = SQLITE_ERROR;
    ++    }
    ++    deflateEnd(&str);
    ++  }
    ++
    ++  return rc;
    ++}
    ++
    ++
    ++/*
    ++** Return values of columns for the row at which the series_cursor
    ++** is currently pointing.
    ++*/
    ++static int zipfileColumn(
    ++  sqlite3_vtab_cursor *cur,   /* The cursor */
    ++  sqlite3_context *ctx,       /* First argument to sqlite3_result_...() */
    ++  int i                       /* Which column to return */
    ++){
    ++  ZipfileCsr *pCsr = (ZipfileCsr*)cur;
    ++  int rc = SQLITE_OK;
    ++  switch( i ){
    ++    case 0:   /* name */
    ++      sqlite3_result_text(ctx, pCsr->cds.zFile, -1, SQLITE_TRANSIENT);
    ++      break;
    ++    case 1:   /* mode */
    ++      /* TODO: Whether or not the following is correct surely depends on
    ++      ** the platform on which the archive was created.  */
    ++      sqlite3_result_int(ctx, pCsr->cds.iExternalAttr >> 16);
    ++      break;
    ++    case 2: { /* mtime */
    ++      if( pCsr->flags & ZIPFILE_MTIME_VALID ){
    ++        sqlite3_result_int64(ctx, pCsr->mTime);
    ++      }else{
    ++        sqlite3_result_int64(ctx, zipfileMtime(pCsr));
    ++      }
    ++      break;
    ++    }
    ++    case 3: { /* sz */
    ++      if( sqlite3_vtab_nochange(ctx)==0 ){
    ++        sqlite3_result_int64(ctx, pCsr->cds.szUncompressed);
    ++      }
    ++      break;
    ++    }
    ++    case 4:   /* rawdata */
    ++      if( sqlite3_vtab_nochange(ctx) ) break;
    ++    case 5: { /* data */
    ++      if( i==4 || pCsr->cds.iCompression==0 || pCsr->cds.iCompression==8 ){
    ++        int sz = pCsr->cds.szCompressed;
    ++        int szFinal = pCsr->cds.szUncompressed;
    ++        if( szFinal>0 ){
    ++          u8 *aBuf = sqlite3_malloc(sz);
    ++          if( aBuf==0 ){
    ++            rc = SQLITE_NOMEM;
    ++          }else{
    ++            FILE *pFile = zipfileGetFd(pCsr);
    ++            rc = zipfileReadData(pFile, aBuf, sz, pCsr->iDataOff,
    ++                &pCsr->base.pVtab->zErrMsg
    ++            );
    ++          }
    ++          if( rc==SQLITE_OK ){
    ++            if( i==5 && pCsr->cds.iCompression ){
    ++              zipfileInflate(ctx, aBuf, sz, szFinal);
    ++            }else{
    ++              sqlite3_result_blob(ctx, aBuf, sz, SQLITE_TRANSIENT);
    ++            }
    ++            sqlite3_free(aBuf);
    ++          }
    ++        }else{
    ++          /* Figure out if this is a directory or a zero-sized file. Consider
    ++          ** it to be a directory either if the mode suggests so, or if
    ++          ** the final character in the name is '/'.  */
    ++          u32 mode = pCsr->cds.iExternalAttr >> 16;
    ++          if( !(mode & S_IFDIR) && pCsr->cds.zFile[pCsr->cds.nFile-1]!='/' ){
    ++            sqlite3_result_blob(ctx, "", 0, SQLITE_STATIC);
    ++          }
    ++        }
    ++      }
    ++      break;
    ++    }
    ++    case 6:   /* method */
    ++      sqlite3_result_int(ctx, pCsr->cds.iCompression);
    ++      break;
    ++    case 7:   /* z */
    ++      sqlite3_result_int64(ctx, pCsr->iId);
    ++      break;
    ++  }
    ++
    ++  return rc;
    ++}
    ++
    ++/*
    ++** Return the rowid for the current row.
    ++*/
    ++static int zipfileRowid(sqlite3_vtab_cursor *cur, sqlite_int64 *pRowid){
    ++  assert( 0 );
    ++  return SQLITE_OK;
    ++}
    ++
    ++/*
    ++** Return TRUE if the cursor has been moved off of the last
    ++** row of output.
    ++*/
    ++static int zipfileEof(sqlite3_vtab_cursor *cur){
    ++  ZipfileCsr *pCsr = (ZipfileCsr*)cur;
    ++  return pCsr->bEof;
    ++}
    ++
    ++/*
    ++*/
    ++static int zipfileReadEOCD(
    ++  ZipfileTab *pTab,               /* Return errors here */
    ++  FILE *pFile,                    /* Read from this file */
    ++  ZipfileEOCD *pEOCD              /* Object to populate */
    ++){
    ++  u8 *aRead = pTab->aBuffer;      /* Temporary buffer */
    ++  i64 szFile;                     /* Total size of file in bytes */
    ++  int nRead;                      /* Bytes to read from file */
    ++  i64 iOff;                       /* Offset to read from */
    ++  int rc;
    ++
    ++  fseek(pFile, 0, SEEK_END);
    ++  szFile = (i64)ftell(pFile);
    ++  if( szFile==0 ){
    ++    memset(pEOCD, 0, sizeof(ZipfileEOCD));
    ++    return SQLITE_OK;
    ++  }
    ++  nRead = (int)(MIN(szFile, ZIPFILE_BUFFER_SIZE));
    ++  iOff = szFile - nRead;
    ++
    ++  rc = zipfileReadData(pFile, aRead, nRead, iOff, &pTab->base.zErrMsg);
    ++  if( rc==SQLITE_OK ){
    ++    int i;
    ++
    ++    /* Scan backwards looking for the signature bytes */
    ++    for(i=nRead-20; i>=0; i--){
    ++      if( aRead[i]==0x50 && aRead[i+1]==0x4b 
    ++       && aRead[i+2]==0x05 && aRead[i+3]==0x06 
    ++      ){
    ++        break;
    ++      }
    ++    }
    ++    if( i<0 ){
    ++      pTab->base.zErrMsg = sqlite3_mprintf(
    ++          "cannot find end of central directory record"
    ++      );
    ++      return SQLITE_ERROR;
    ++    }
    ++
    ++    aRead += i+4;
    ++    pEOCD->iDisk = zipfileRead16(aRead);
    ++    pEOCD->iFirstDisk = zipfileRead16(aRead);
    ++    pEOCD->nEntry = zipfileRead16(aRead);
    ++    pEOCD->nEntryTotal = zipfileRead16(aRead);
    ++    pEOCD->nSize = zipfileRead32(aRead);
    ++    pEOCD->iOffset = zipfileRead32(aRead);
    ++
    ++#if 0
    ++    printf("iDisk=%d  iFirstDisk=%d  nEntry=%d  "
    ++           "nEntryTotal=%d  nSize=%d  iOffset=%d", 
    ++           (int)pEOCD->iDisk, (int)pEOCD->iFirstDisk, (int)pEOCD->nEntry,
    ++           (int)pEOCD->nEntryTotal, (int)pEOCD->nSize, (int)pEOCD->iOffset
    ++    );
    ++#endif
    ++  }
    ++
    ++  return SQLITE_OK;
    ++}
    ++
    ++/*
    ++** xFilter callback.
    ++*/
    ++static int zipfileFilter(
    ++  sqlite3_vtab_cursor *cur, 
    ++  int idxNum, const char *idxStr,
    ++  int argc, sqlite3_value **argv
    ++){
    ++  ZipfileTab *pTab = (ZipfileTab*)cur->pVtab;
    ++  ZipfileCsr *pCsr = (ZipfileCsr*)cur;
    ++  const char *zFile;              /* Zip file to scan */
    ++  int rc = SQLITE_OK;             /* Return Code */
    ++
    ++  zipfileResetCursor(pCsr);
    ++
    ++  if( pTab->zFile ){
    ++    zFile = pTab->zFile;
    ++  }else if( idxNum==0 ){
    ++    /* Error. This is an eponymous virtual table and the user has not 
    ++    ** supplied a file name. */
    ++    zipfileSetErrmsg(pCsr, "table function zipfile() requires an argument");
    ++    return SQLITE_ERROR;
    ++  }else{
    ++    zFile = (const char*)sqlite3_value_text(argv[0]);
    ++  }
    ++
    ++  if( pTab->pWriteFd==0 ){
    ++    pCsr->pFile = fopen(zFile, "rb");
    ++    if( pCsr->pFile==0 ){
    ++      zipfileSetErrmsg(pCsr, "cannot open file: %s", zFile);
    ++      rc = SQLITE_ERROR;
    ++    }else{
    ++      rc = zipfileReadEOCD(pTab, pCsr->pFile, &pCsr->eocd);
    ++      if( rc==SQLITE_OK ){
    ++        if( pCsr->eocd.nEntry==0 ){
    ++          pCsr->bEof = 1;
    ++        }else{
    ++          pCsr->iNextOff = pCsr->eocd.iOffset;
    ++          rc = zipfileNext(cur);
    ++        }
    ++      }
    ++    }
    ++  }else{
    ++    ZipfileEntry e;
    ++    memset(&e, 0, sizeof(e));
    ++    e.pNext = pTab->pFirstEntry;
    ++    pCsr->pCurrent = &e;
    ++    rc = zipfileNext(cur);
    ++    assert( pCsr->pCurrent!=&e );
    ++  }
    ++
    ++  return rc;
    ++}
    ++
    ++/*
    ++** xBestIndex callback.
    ++*/
    ++static int zipfileBestIndex(
    ++  sqlite3_vtab *tab,
    ++  sqlite3_index_info *pIdxInfo
    ++){
    ++  int i;
    ++
    ++  for(i=0; i<pIdxInfo->nConstraint; i++){
    ++    const struct sqlite3_index_constraint *pCons = &pIdxInfo->aConstraint[i];
    ++    if( pCons->usable==0 ) continue;
    ++    if( pCons->op!=SQLITE_INDEX_CONSTRAINT_EQ ) continue;
    ++    if( pCons->iColumn!=ZIPFILE_F_COLUMN_IDX ) continue;
    ++    break;
    ++  }
    ++
    ++  if( i<pIdxInfo->nConstraint ){
    ++    pIdxInfo->aConstraintUsage[i].argvIndex = 1;
    ++    pIdxInfo->aConstraintUsage[i].omit = 1;
    ++    pIdxInfo->estimatedCost = 1000.0;
    ++    pIdxInfo->idxNum = 1;
    ++  }else{
    ++    pIdxInfo->estimatedCost = (double)(((sqlite3_int64)1) << 50);
    ++    pIdxInfo->idxNum = 0;
    ++  }
    ++
    ++  return SQLITE_OK;
    ++}
    ++
    ++/*
    ++** Add object pNew to the end of the linked list that begins at
    ++** ZipfileTab.pFirstEntry and ends with pLastEntry.
    ++*/
    ++static void zipfileAddEntry(
    ++  ZipfileTab *pTab, 
    ++  ZipfileEntry *pBefore, 
    ++  ZipfileEntry *pNew
    ++){
    ++  assert( (pTab->pFirstEntry==0)==(pTab->pLastEntry==0) );
    ++  assert( pNew->pNext==0 );
    ++  if( pBefore==0 ){
    ++    if( pTab->pFirstEntry==0 ){
    ++      pTab->pFirstEntry = pTab->pLastEntry = pNew;
    ++    }else{
    ++      assert( pTab->pLastEntry->pNext==0 );
    ++      pTab->pLastEntry->pNext = pNew;
    ++      pTab->pLastEntry = pNew;
    ++    }
    ++  }else{
    ++    ZipfileEntry **pp;
    ++    for(pp=&pTab->pFirstEntry; *pp!=pBefore; pp=&((*pp)->pNext));
    ++    pNew->pNext = pBefore;
    ++    *pp = pNew;
    ++  }
    ++}
    ++
    ++static int zipfileLoadDirectory(ZipfileTab *pTab){
    ++  ZipfileEOCD eocd;
    ++  int rc;
    ++
    ++  rc = zipfileReadEOCD(pTab, pTab->pWriteFd, &eocd);
    ++  if( rc==SQLITE_OK && eocd.nEntry>0 ){
    ++    int i;
    ++    int iOff = 0;
    ++    u8 *aBuf = sqlite3_malloc(eocd.nSize);
    ++    if( aBuf==0 ){
    ++      rc = SQLITE_NOMEM;
    ++    }else{
    ++      rc = zipfileReadData(
    ++          pTab->pWriteFd, aBuf, eocd.nSize, eocd.iOffset, &pTab->base.zErrMsg
    ++      );
    ++    }
    ++
    ++    for(i=0; rc==SQLITE_OK && i<eocd.nEntry; i++){
    ++      u16 nFile;
    ++      u16 nExtra;
    ++      u16 nComment;
    ++      ZipfileEntry *pNew;
    ++      u8 *aRec = &aBuf[iOff];
    ++
    ++      nFile = zipfileGetU16(&aRec[ZIPFILE_CDS_NFILE_OFF]);
    ++      nExtra = zipfileGetU16(&aRec[ZIPFILE_CDS_NFILE_OFF+2]);
    ++      nComment = zipfileGetU16(&aRec[ZIPFILE_CDS_NFILE_OFF+4]);
    ++
    ++      pNew = sqlite3_malloc(
    ++          sizeof(ZipfileEntry) 
    ++        + nFile+1 
    ++        + ZIPFILE_CDS_FIXED_SZ+nFile+nExtra+nComment
    ++      );
    ++      if( pNew==0 ){
    ++        rc = SQLITE_NOMEM;
    ++      }else{
    ++        memset(pNew, 0, sizeof(ZipfileEntry));
    ++        pNew->zPath = (char*)&pNew[1];
    ++        memcpy(pNew->zPath, &aRec[ZIPFILE_CDS_FIXED_SZ], nFile);
    ++        pNew->zPath[nFile] = '\0';
    ++        pNew->aCdsEntry = (u8*)&pNew->zPath[nFile+1];
    ++        pNew->nCdsEntry = ZIPFILE_CDS_FIXED_SZ+nFile+nExtra+nComment;
    ++        memcpy(pNew->aCdsEntry, aRec, pNew->nCdsEntry);
    ++        zipfileAddEntry(pTab, 0, pNew);
    ++      }
    ++
    ++      iOff += ZIPFILE_CDS_FIXED_SZ+nFile+nExtra+nComment;
    ++    }
    ++
    ++    sqlite3_free(aBuf);
    ++  }
    ++
    ++  return rc;
    ++}
    ++
    ++static ZipfileEntry *zipfileNewEntry(
    ++  ZipfileCDS *pCds,               /* Values for fixed size part of CDS */
    ++  const char *zPath,              /* Path for new entry */
    ++  int nPath,                      /* strlen(zPath) */
    ++  u32 mTime                       /* Modification time (or 0) */
    ++){
    ++  u8 *aWrite;
    ++  ZipfileEntry *pNew;
    ++  pCds->nFile = (u16)nPath;
    ++  pCds->nExtra = mTime ? 9 : 0;
    ++  pNew = (ZipfileEntry*)sqlite3_malloc(
    ++    sizeof(ZipfileEntry) + 
    ++    nPath+1 + 
    ++    ZIPFILE_CDS_FIXED_SZ + nPath + pCds->nExtra
    ++  );
    ++
    ++  if( pNew ){
    ++    memset(pNew, 0, sizeof(ZipfileEntry));
    ++    pNew->zPath = (char*)&pNew[1];
    ++    pNew->aCdsEntry = (u8*)&pNew->zPath[nPath+1];
    ++    pNew->nCdsEntry = ZIPFILE_CDS_FIXED_SZ + nPath + pCds->nExtra;
    ++    memcpy(pNew->zPath, zPath, nPath+1);
    ++
    ++    aWrite = pNew->aCdsEntry;
    ++    zipfileWrite32(aWrite, ZIPFILE_SIGNATURE_CDS);
    ++    zipfileWrite16(aWrite, pCds->iVersionMadeBy);
    ++    zipfileWrite16(aWrite, pCds->iVersionExtract);
    ++    zipfileWrite16(aWrite, pCds->flags);
    ++    zipfileWrite16(aWrite, pCds->iCompression);
    ++    zipfileWrite16(aWrite, pCds->mTime);
    ++    zipfileWrite16(aWrite, pCds->mDate);
    ++    zipfileWrite32(aWrite, pCds->crc32);
    ++    zipfileWrite32(aWrite, pCds->szCompressed);
    ++    zipfileWrite32(aWrite, pCds->szUncompressed);
    ++    zipfileWrite16(aWrite, pCds->nFile);
    ++    zipfileWrite16(aWrite, pCds->nExtra);
    ++    zipfileWrite16(aWrite, pCds->nComment);      assert( pCds->nComment==0 );
    ++    zipfileWrite16(aWrite, pCds->iDiskStart);
    ++    zipfileWrite16(aWrite, pCds->iInternalAttr);
    ++    zipfileWrite32(aWrite, pCds->iExternalAttr);
    ++    zipfileWrite32(aWrite, pCds->iOffset);
    ++    assert( aWrite==&pNew->aCdsEntry[ZIPFILE_CDS_FIXED_SZ] );
    ++    memcpy(aWrite, zPath, nPath);
    ++    if( pCds->nExtra ){
    ++      aWrite += nPath;
    ++      zipfileWrite16(aWrite, ZIPFILE_EXTRA_TIMESTAMP);
    ++      zipfileWrite16(aWrite, 5);
    ++      *aWrite++ = 0x01;
    ++      zipfileWrite32(aWrite, mTime);
    ++    }
    ++  }
    ++
    ++  return pNew;
    ++}
    ++
    ++static int zipfileAppendEntry(
    ++  ZipfileTab *pTab,
    ++  ZipfileCDS *pCds,
    ++  const char *zPath,              /* Path for new entry */
    ++  int nPath,                      /* strlen(zPath) */
    ++  const u8 *pData,
    ++  int nData,
    ++  u32 mTime
    ++){
    ++  u8 *aBuf = pTab->aBuffer;
    ++  int rc;
    ++
    ++  zipfileWrite32(aBuf, ZIPFILE_SIGNATURE_LFH);
    ++  zipfileWrite16(aBuf, pCds->iVersionExtract);
    ++  zipfileWrite16(aBuf, pCds->flags);
    ++  zipfileWrite16(aBuf, pCds->iCompression);
    ++  zipfileWrite16(aBuf, pCds->mTime);
    ++  zipfileWrite16(aBuf, pCds->mDate);
    ++  zipfileWrite32(aBuf, pCds->crc32);
    ++  zipfileWrite32(aBuf, pCds->szCompressed);
    ++  zipfileWrite32(aBuf, pCds->szUncompressed);
    ++  zipfileWrite16(aBuf, (u16)nPath);
    ++  zipfileWrite16(aBuf, pCds->nExtra);
    ++  assert( aBuf==&pTab->aBuffer[ZIPFILE_LFH_FIXED_SZ] );
    ++  rc = zipfileAppendData(pTab, pTab->aBuffer, (int)(aBuf - pTab->aBuffer));
    ++  if( rc==SQLITE_OK ){
    ++    rc = zipfileAppendData(pTab, (const u8*)zPath, nPath);
    ++  }
    ++
    ++  if( rc==SQLITE_OK && pCds->nExtra ){
    ++    aBuf = pTab->aBuffer;
    ++    zipfileWrite16(aBuf, ZIPFILE_EXTRA_TIMESTAMP);
    ++    zipfileWrite16(aBuf, 5);
    ++    *aBuf++ = 0x01;
    ++    zipfileWrite32(aBuf, mTime);
    ++    rc = zipfileAppendData(pTab, pTab->aBuffer, 9);
    ++  }
    ++
    ++  if( rc==SQLITE_OK ){
    ++    rc = zipfileAppendData(pTab, pData, nData);
    ++  }
    ++
    ++  return rc;
    ++}
    ++
    ++static int zipfileGetMode(
    ++  ZipfileTab *pTab, 
    ++  sqlite3_value *pVal, 
    ++  u32 defaultMode,                /* Value to use if pVal IS NULL */
    ++  u32 *pMode
    ++){
    ++  const char *z = (const char*)sqlite3_value_text(pVal);
    ++  u32 mode = 0;
    ++  if( z==0 ){
    ++    mode = defaultMode;
    ++  }else if( z[0]>='0' && z[0]<='9' ){
    ++    mode = (unsigned int)sqlite3_value_int(pVal);
    ++  }else{
    ++    const char zTemplate[11] = "-rwxrwxrwx";
    ++    int i;
    ++    if( strlen(z)!=10 ) goto parse_error;
    ++    switch( z[0] ){
    ++      case '-': mode |= S_IFREG; break;
    ++      case 'd': mode |= S_IFDIR; break;
    ++#if !defined(_WIN32) && !defined(WIN32)
    ++      case 'l': mode |= S_IFLNK; break;
    ++#endif
    ++      default: goto parse_error;
    ++    }
    ++    for(i=1; i<10; i++){
    ++      if( z[i]==zTemplate[i] ) mode |= 1 << (9-i);
    ++      else if( z[i]!='-' ) goto parse_error;
    ++    }
    ++  }
    ++  *pMode = mode;
    ++  return SQLITE_OK;
    ++
    ++ parse_error:
    ++  pTab->base.zErrMsg = sqlite3_mprintf("zipfile: parse error in mode: %s", z);
    ++  return SQLITE_ERROR;
    ++}
    ++
    ++/*
    ++** Both (const char*) arguments point to nul-terminated strings. Argument
    ++** nB is the value of strlen(zB). This function returns 0 if the strings are
    ++** identical, ignoring any trailing '/' character in either path.  */
    ++static int zipfileComparePath(const char *zA, const char *zB, int nB){
    ++  int nA = (int)strlen(zA);
    ++  if( zA[nA-1]=='/' ) nA--;
    ++  if( zB[nB-1]=='/' ) nB--;
    ++  if( nA==nB && memcmp(zA, zB, nA)==0 ) return 0;
    ++  return 1;
    ++}
    ++
    ++/*
    ++** xUpdate method.
    ++*/
    ++static int zipfileUpdate(
    ++  sqlite3_vtab *pVtab, 
    ++  int nVal, 
    ++  sqlite3_value **apVal, 
    ++  sqlite_int64 *pRowid
    ++){
    ++  ZipfileTab *pTab = (ZipfileTab*)pVtab;
    ++  int rc = SQLITE_OK;             /* Return Code */
    ++  ZipfileEntry *pNew = 0;         /* New in-memory CDS entry */
    ++
    ++  u32 mode = 0;                   /* Mode for new entry */
    ++  i64 mTime = 0;                  /* Modification time for new entry */
    ++  i64 sz = 0;                     /* Uncompressed size */
    ++  const char *zPath = 0;          /* Path for new entry */
    ++  int nPath = 0;                  /* strlen(zPath) */
    ++  const u8 *pData = 0;            /* Pointer to buffer containing content */
    ++  int nData = 0;                  /* Size of pData buffer in bytes */
    ++  int iMethod = 0;                /* Compression method for new entry */
    ++  u8 *pFree = 0;                  /* Free this */
    ++  char *zFree = 0;                /* Also free this */
    ++  ZipfileCDS cds;                 /* New Central Directory Structure entry */
    ++  ZipfileEntry *pOld = 0;
    ++  int bIsDir = 0;
    ++  u32 iCrc32 = 0;
    ++
    ++  assert( pTab->zFile );
    ++  assert( pTab->pWriteFd );
    ++
    ++  if( sqlite3_value_type(apVal[0])!=SQLITE_NULL ){
    ++    const char *zDelete = (const char*)sqlite3_value_text(apVal[0]);
    ++    int nDelete = (int)strlen(zDelete);
    ++    for(pOld=pTab->pFirstEntry; 1; pOld=pOld->pNext){
    ++      if( pOld->bDeleted ) continue;
    ++      if( zipfileComparePath(pOld->zPath, zDelete, nDelete)==0 ){
    ++        pOld->bDeleted = 1;
    ++        break;
    ++      }
    ++      assert( pOld->pNext );
    ++    }
    ++    if( nVal==1 ) return SQLITE_OK;
    ++  }
    ++
    ++  /* Check that "sz" and "rawdata" are both NULL: */
    ++  if( sqlite3_value_type(apVal[5])!=SQLITE_NULL
    ++   || sqlite3_value_type(apVal[6])!=SQLITE_NULL
    ++  ){
    ++    rc = SQLITE_CONSTRAINT;
    ++  }
    ++
    ++  if( rc==SQLITE_OK ){
    ++    if( sqlite3_value_type(apVal[7])==SQLITE_NULL ){
    ++      /* data=NULL. A directory */
    ++      bIsDir = 1;
    ++    }else{
    ++      /* Value specified for "data", and possibly "method". This must be
    ++      ** a regular file or a symlink. */
    ++      const u8 *aIn = sqlite3_value_blob(apVal[7]);
    ++      int nIn = sqlite3_value_bytes(apVal[7]);
    ++      int bAuto = sqlite3_value_type(apVal[8])==SQLITE_NULL;
    ++
    ++      iMethod = sqlite3_value_int(apVal[8]);
    ++      sz = nIn;
    ++      pData = aIn;
    ++      nData = nIn;
    ++      if( iMethod!=0 && iMethod!=8 ){
    ++        rc = SQLITE_CONSTRAINT;
    ++      }else{
    ++        if( bAuto || iMethod ){
    ++          int nCmp;
    ++          rc = zipfileDeflate(pTab, aIn, nIn, &pFree, &nCmp);
    ++          if( rc==SQLITE_OK ){
    ++            if( iMethod || nCmp<nIn ){
    ++              iMethod = 8;
    ++              pData = pFree;
    ++              nData = nCmp;
    ++            }
    ++          }
    ++        }
    ++        iCrc32 = crc32(0, aIn, nIn);
    ++      }
    ++    }
    ++  }
    ++
    ++  if( rc==SQLITE_OK ){
    ++    rc = zipfileGetMode(pTab, apVal[3], 
    ++        (bIsDir ? (S_IFDIR + 0755) : (S_IFREG + 0644)), &mode
    ++    );
    ++    if( rc==SQLITE_OK && (bIsDir == ((mode & S_IFDIR)==0)) ){
    ++      /* The "mode" attribute is a directory, but data has been specified.
    ++      ** Or vice-versa - no data but "mode" is a file or symlink.  */
    ++      rc = SQLITE_CONSTRAINT;
    ++    }
    ++  }
    ++
    ++  if( rc==SQLITE_OK ){
    ++    zPath = (const char*)sqlite3_value_text(apVal[2]);
    ++    nPath = (int)strlen(zPath);
    ++    if( sqlite3_value_type(apVal[4])==SQLITE_NULL ){
    ++      mTime = (sqlite3_int64)time(0);
    ++    }else{
    ++      mTime = sqlite3_value_int64(apVal[4]);
    ++    }
    ++  }
    ++
    ++  if( rc==SQLITE_OK && bIsDir ){
    ++    /* For a directory, check that the last character in the path is a
    ++    ** '/'. This appears to be required for compatibility with info-zip
    ++    ** (the unzip command on unix). It does not create directories
    ++    ** otherwise.  */
    ++    if( zPath[nPath-1]!='/' ){
    ++      zFree = sqlite3_mprintf("%s/", zPath);
    ++      if( zFree==0 ){ rc = SQLITE_NOMEM; }
    ++      zPath = (const char*)zFree;
    ++      nPath++;
    ++    }
    ++  }
    ++
    ++  /* Check that we're not inserting a duplicate entry */
    ++  if( rc==SQLITE_OK ){
    ++    ZipfileEntry *p;
    ++    for(p=pTab->pFirstEntry; p; p=p->pNext){
    ++      if( p->bDeleted ) continue;
    ++      if( zipfileComparePath(p->zPath, zPath, nPath)==0 ){
    ++        rc = SQLITE_CONSTRAINT;
    ++        break;
    ++      }
    ++    }
    ++  }
    ++
    ++  if( rc==SQLITE_OK ){
    ++    /* Create the new CDS record. */
    ++    memset(&cds, 0, sizeof(cds));
    ++    cds.iVersionMadeBy = ZIPFILE_NEWENTRY_MADEBY;
    ++    cds.iVersionExtract = ZIPFILE_NEWENTRY_REQUIRED;
    ++    cds.flags = ZIPFILE_NEWENTRY_FLAGS;
    ++    cds.iCompression = (u16)iMethod;
    ++    zipfileMtimeToDos(&cds, (u32)mTime);
    ++    cds.crc32 = iCrc32;
    ++    cds.szCompressed = nData;
    ++    cds.szUncompressed = (u32)sz;
    ++    cds.iExternalAttr = (mode<<16);
    ++    cds.iOffset = (u32)pTab->szCurrent;
    ++    pNew = zipfileNewEntry(&cds, zPath, nPath, (u32)mTime);
    ++    if( pNew==0 ){
    ++      rc = SQLITE_NOMEM;
    ++    }else{
    ++      zipfileAddEntry(pTab, pOld, pNew);
    ++    }
    ++  }
    ++
    ++  /* Append the new header+file to the archive */
    ++  if( rc==SQLITE_OK ){
    ++    rc = zipfileAppendEntry(pTab, &cds, zPath, nPath, pData, nData, (u32)mTime);
    ++  }
    ++
    ++  if( rc!=SQLITE_OK && pOld ){
    ++    pOld->bDeleted = 0;
    ++  }
    ++  sqlite3_free(pFree);
    ++  sqlite3_free(zFree);
    ++  return rc;
    ++}
    ++
    ++static int zipfileAppendEOCD(ZipfileTab *pTab, ZipfileEOCD *p){
    ++  u8 *aBuf = pTab->aBuffer;
    ++
    ++  zipfileWrite32(aBuf, ZIPFILE_SIGNATURE_EOCD);
    ++  zipfileWrite16(aBuf, p->iDisk);
    ++  zipfileWrite16(aBuf, p->iFirstDisk);
    ++  zipfileWrite16(aBuf, p->nEntry);
    ++  zipfileWrite16(aBuf, p->nEntryTotal);
    ++  zipfileWrite32(aBuf, p->nSize);
    ++  zipfileWrite32(aBuf, p->iOffset);
    ++  zipfileWrite16(aBuf, 0);        /* Size of trailing comment in bytes*/
    ++
    ++  assert( (aBuf-pTab->aBuffer)==22 );
    ++  return zipfileAppendData(pTab, pTab->aBuffer, (int)(aBuf - pTab->aBuffer));
    ++}
    ++
    ++static void zipfileCleanupTransaction(ZipfileTab *pTab){
    ++  ZipfileEntry *pEntry;
    ++  ZipfileEntry *pNext;
    ++
    ++  for(pEntry=pTab->pFirstEntry; pEntry; pEntry=pNext){
    ++    pNext = pEntry->pNext;
    ++    sqlite3_free(pEntry);
    ++  }
    ++  pTab->pFirstEntry = 0;
    ++  pTab->pLastEntry = 0;
    ++  fclose(pTab->pWriteFd);
    ++  pTab->pWriteFd = 0;
    ++  pTab->szCurrent = 0;
    ++  pTab->szOrig = 0;
    ++}
    ++
    ++static int zipfileBegin(sqlite3_vtab *pVtab){
    ++  ZipfileTab *pTab = (ZipfileTab*)pVtab;
    ++  int rc = SQLITE_OK;
    ++
    ++  assert( pTab->pWriteFd==0 );
    ++
    ++  /* This table is only writable if a default archive path was specified 
    ++  ** as part of the CREATE VIRTUAL TABLE statement. */
    ++  if( pTab->zFile==0 ){
    ++    pTab->base.zErrMsg = sqlite3_mprintf(
    ++        "zipfile: writing requires a default archive"
    ++    );
    ++    return SQLITE_ERROR;
    ++  }
    ++
    ++  /* Open a write fd on the file. Also load the entire central directory
    ++  ** structure into memory. During the transaction any new file data is 
    ++  ** appended to the archive file, but the central directory is accumulated
    ++  ** in main-memory until the transaction is committed.  */
    ++  pTab->pWriteFd = fopen(pTab->zFile, "ab+");
    ++  if( pTab->pWriteFd==0 ){
    ++    pTab->base.zErrMsg = sqlite3_mprintf(
    ++        "zipfile: failed to open file %s for writing", pTab->zFile
    ++    );
    ++    rc = SQLITE_ERROR;
    ++  }else{
    ++    fseek(pTab->pWriteFd, 0, SEEK_END);
    ++    pTab->szCurrent = pTab->szOrig = (i64)ftell(pTab->pWriteFd);
    ++    rc = zipfileLoadDirectory(pTab);
    ++  }
    ++
    ++  if( rc!=SQLITE_OK ){
    ++    zipfileCleanupTransaction(pTab);
    ++  }
    ++
    ++  return rc;
    ++}
    ++
    ++static int zipfileCommit(sqlite3_vtab *pVtab){
    ++  ZipfileTab *pTab = (ZipfileTab*)pVtab;
    ++  int rc = SQLITE_OK;
    ++  if( pTab->pWriteFd ){
    ++    i64 iOffset = pTab->szCurrent;
    ++    ZipfileEntry *p;
    ++    ZipfileEOCD eocd;
    ++    int nEntry = 0;
    ++
    ++    /* Write out all undeleted entries */
    ++    for(p=pTab->pFirstEntry; rc==SQLITE_OK && p; p=p->pNext){
    ++      if( p->bDeleted ) continue;
    ++      rc = zipfileAppendData(pTab, p->aCdsEntry, p->nCdsEntry);
    ++      nEntry++;
    ++    }
    ++
    ++    /* Write out the EOCD record */
    ++    eocd.iDisk = 0;
    ++    eocd.iFirstDisk = 0;
    ++    eocd.nEntry = (u16)nEntry;
    ++    eocd.nEntryTotal = (u16)nEntry;
    ++    eocd.nSize = (u32)(pTab->szCurrent - iOffset);
    ++    eocd.iOffset = (u32)iOffset;
    ++    rc = zipfileAppendEOCD(pTab, &eocd);
    ++
    ++    zipfileCleanupTransaction(pTab);
    ++  }
    ++  return rc;
    ++}
    ++
    ++static int zipfileRollback(sqlite3_vtab *pVtab){
    ++  return zipfileCommit(pVtab);
    ++}
    ++
    ++static ZipfileCsr *zipfileFindCursor(ZipfileTab *pTab, i64 iId){
    ++  ZipfileCsr *pCsr;
    ++  for(pCsr=pTab->pCsrList; pCsr; pCsr=pCsr->pCsrNext){
    ++    if( iId==pCsr->iId ) break;
    ++  }
    ++  return pCsr;
    ++}
    ++
    ++static void zipfileFunctionCds(
    ++  sqlite3_context *context,
    ++  int argc,
    ++  sqlite3_value **argv
    ++){
    ++  ZipfileCsr *pCsr;
    ++  ZipfileTab *pTab = (ZipfileTab*)sqlite3_user_data(context);
    ++  assert( argc>0 );
    ++
    ++  pCsr = zipfileFindCursor(pTab, sqlite3_value_int64(argv[0]));
    ++  if( pCsr ){
    ++    ZipfileCDS *p = &pCsr->cds;
    ++    char *zRes = sqlite3_mprintf("{"
    ++        "\"version-made-by\" : %u, "
    ++        "\"version-to-extract\" : %u, "
    ++        "\"flags\" : %u, "
    ++        "\"compression\" : %u, "
    ++        "\"time\" : %u, "
    ++        "\"date\" : %u, "
    ++        "\"crc32\" : %u, "
    ++        "\"compressed-size\" : %u, "
    ++        "\"uncompressed-size\" : %u, "
    ++        "\"file-name-length\" : %u, "
    ++        "\"extra-field-length\" : %u, "
    ++        "\"file-comment-length\" : %u, "
    ++        "\"disk-number-start\" : %u, "
    ++        "\"internal-attr\" : %u, "
    ++        "\"external-attr\" : %u, "
    ++        "\"offset\" : %u }",
    ++        (u32)p->iVersionMadeBy, (u32)p->iVersionExtract,
    ++        (u32)p->flags, (u32)p->iCompression,
    ++        (u32)p->mTime, (u32)p->mDate,
    ++        (u32)p->crc32, (u32)p->szCompressed,
    ++        (u32)p->szUncompressed, (u32)p->nFile,
    ++        (u32)p->nExtra, (u32)p->nComment,
    ++        (u32)p->iDiskStart, (u32)p->iInternalAttr,
    ++        (u32)p->iExternalAttr, (u32)p->iOffset
    ++    );
    ++
    ++    if( zRes==0 ){
    ++      sqlite3_result_error_nomem(context);
    ++    }else{
    ++      sqlite3_result_text(context, zRes, -1, SQLITE_TRANSIENT);
    ++      sqlite3_free(zRes);
    ++    }
    ++  }
    ++}
    ++
    ++
    ++/*
    ++** xFindFunction method.
    ++*/
    ++static int zipfileFindFunction(
    ++  sqlite3_vtab *pVtab,            /* Virtual table handle */
    ++  int nArg,                       /* Number of SQL function arguments */
    ++  const char *zName,              /* Name of SQL function */
    ++  void (**pxFunc)(sqlite3_context*,int,sqlite3_value**), /* OUT: Result */
    ++  void **ppArg                    /* OUT: User data for *pxFunc */
    ++){
    ++  if( nArg>0 ){
    ++    if( sqlite3_stricmp("zipfile_cds", zName)==0 ){
    ++      *pxFunc = zipfileFunctionCds;
    ++      *ppArg = (void*)pVtab;
    ++      return 1;
    ++    }
    ++  }
    ++
    ++  return 0;
    ++}
    ++
    ++/*
    ++** Register the "zipfile" virtual table.
    ++*/
    ++static int zipfileRegister(sqlite3 *db){
    ++  static sqlite3_module zipfileModule = {
    ++    1,                         /* iVersion */
    ++    zipfileConnect,            /* xCreate */
    ++    zipfileConnect,            /* xConnect */
    ++    zipfileBestIndex,          /* xBestIndex */
    ++    zipfileDisconnect,         /* xDisconnect */
    ++    zipfileDisconnect,         /* xDestroy */
    ++    zipfileOpen,               /* xOpen - open a cursor */
    ++    zipfileClose,              /* xClose - close a cursor */
    ++    zipfileFilter,             /* xFilter - configure scan constraints */
    ++    zipfileNext,               /* xNext - advance a cursor */
    ++    zipfileEof,                /* xEof - check for end of scan */
    ++    zipfileColumn,             /* xColumn - read data */
    ++    zipfileRowid,              /* xRowid - read data */
    ++    zipfileUpdate,             /* xUpdate */
    ++    zipfileBegin,              /* xBegin */
    ++    0,                         /* xSync */
    ++    zipfileCommit,             /* xCommit */
    ++    zipfileRollback,           /* xRollback */
    ++    zipfileFindFunction,       /* xFindMethod */
    ++    0,                         /* xRename */
    ++  };
    ++
    ++  int rc = sqlite3_create_module(db, "zipfile"  , &zipfileModule, 0);
    ++  if( rc==SQLITE_OK ){
    ++    rc = sqlite3_overload_function(db, "zipfile_cds", -1);
    ++  }
    ++  return rc;
    ++}
    ++#else         /* SQLITE_OMIT_VIRTUALTABLE */
    ++# define zipfileRegister(x) SQLITE_OK
    ++#endif
    ++
    ++#ifdef _WIN32
    ++
    ++#endif
    ++int sqlite3_zipfile_init(
    ++  sqlite3 *db, 
    ++  char **pzErrMsg, 
    ++  const sqlite3_api_routines *pApi
    ++){
    ++  SQLITE_EXTENSION_INIT2(pApi);
    ++  (void)pzErrMsg;  /* Unused parameter */
    ++  return zipfileRegister(db);
    ++}
    ++
    ++/************************* End ../ext/misc/zipfile.c ********************/
    ++/************************* Begin ../ext/misc/sqlar.c ******************/
    ++/*
    ++** 2017-12-17
    ++**
    ++** 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.
    ++**
    ++******************************************************************************
    ++**
    ++** Utility functions sqlar_compress() and sqlar_uncompress(). Useful
    ++** for working with sqlar archives and used by the shell tool's built-in
    ++** sqlar support.
    ++*/
    ++SQLITE_EXTENSION_INIT1
    ++#include <zlib.h>
    ++
    ++/*
    ++** Implementation of the "sqlar_compress(X)" SQL function.
    ++**
    ++** If the type of X is SQLITE_BLOB, and compressing that blob using
    ++** zlib utility function compress() yields a smaller blob, return the
    ++** compressed blob. Otherwise, return a copy of X.
    ++**
    ++** SQLar uses the "zlib format" for compressed content.  The zlib format
    ++** contains a two-byte identification header and a four-byte checksum at
    ++** the end.  This is different from ZIP which uses the raw deflate format.
    ++**
    ++** Future enhancements to SQLar might add support for new compression formats.
    ++** If so, those new formats will be identified by alternative headers in the
    ++** compressed data.
    ++*/
    ++static void sqlarCompressFunc(
    ++  sqlite3_context *context,
    ++  int argc,
    ++  sqlite3_value **argv
    ++){
    ++  assert( argc==1 );
    ++  if( sqlite3_value_type(argv[0])==SQLITE_BLOB ){
    ++    const Bytef *pData = sqlite3_value_blob(argv[0]);
    ++    uLong nData = sqlite3_value_bytes(argv[0]);
    ++    uLongf nOut = compressBound(nData);
    ++    Bytef *pOut;
    ++
    ++    pOut = (Bytef*)sqlite3_malloc(nOut);
    ++    if( pOut==0 ){
    ++      sqlite3_result_error_nomem(context);
    ++      return;
    ++    }else{
    ++      if( Z_OK!=compress(pOut, &nOut, pData, nData) ){
    ++        sqlite3_result_error(context, "error in compress()", -1);
    ++      }else if( nOut<nData ){
    ++        sqlite3_result_blob(context, pOut, nOut, SQLITE_TRANSIENT);
    ++      }else{
    ++        sqlite3_result_value(context, argv[0]);
    ++      }
    ++      sqlite3_free(pOut);
    ++    }
    ++  }else{
    ++    sqlite3_result_value(context, argv[0]);
    ++  }
    ++}
    ++
    ++/*
    ++** Implementation of the "sqlar_uncompress(X,SZ)" SQL function
    ++**
    ++** Parameter SZ is interpreted as an integer. If it is less than or
    ++** equal to zero, then this function returns a copy of X. Or, if
    ++** SZ is equal to the size of X when interpreted as a blob, also
    ++** return a copy of X. Otherwise, decompress blob X using zlib
    ++** utility function uncompress() and return the results (another
    ++** blob).
    ++*/
    ++static void sqlarUncompressFunc(
    ++  sqlite3_context *context,
    ++  int argc,
    ++  sqlite3_value **argv
    ++){
    ++  uLong nData;
    ++  uLongf sz;
    ++
    ++  assert( argc==2 );
    ++  sz = sqlite3_value_int(argv[1]);
    ++
    ++  if( sz<=0 || sz==(nData = sqlite3_value_bytes(argv[0])) ){
    ++    sqlite3_result_value(context, argv[0]);
    ++  }else{
    ++    const Bytef *pData= sqlite3_value_blob(argv[0]);
    ++    Bytef *pOut = sqlite3_malloc(sz);
    ++    if( Z_OK!=uncompress(pOut, &sz, pData, nData) ){
    ++      sqlite3_result_error(context, "error in uncompress()", -1);
    ++    }else{
    ++      sqlite3_result_blob(context, pOut, sz, SQLITE_TRANSIENT);
    ++    }
    ++    sqlite3_free(pOut);
    ++  }
    ++}
    ++
    ++
    ++#ifdef _WIN32
    ++
    ++#endif
    ++int sqlite3_sqlar_init(
    ++  sqlite3 *db, 
    ++  char **pzErrMsg, 
    ++  const sqlite3_api_routines *pApi
    ++){
    ++  int rc = SQLITE_OK;
    ++  SQLITE_EXTENSION_INIT2(pApi);
    ++  (void)pzErrMsg;  /* Unused parameter */
    ++  rc = sqlite3_create_function(db, "sqlar_compress", 1, SQLITE_UTF8, 0,
    ++                               sqlarCompressFunc, 0, 0);
    ++  if( rc==SQLITE_OK ){
    ++    rc = sqlite3_create_function(db, "sqlar_uncompress", 2, SQLITE_UTF8, 0,
    ++                                 sqlarUncompressFunc, 0, 0);
    ++  }
    ++  return rc;
    ++}
    ++
    ++/************************* End ../ext/misc/sqlar.c ********************/
    ++#endif
    ++/************************* Begin ../ext/expert/sqlite3expert.h ******************/
    ++/*
    ++** 2017 April 07
    ++**
    ++** 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.
    ++**
    ++*************************************************************************
    ++*/
    ++
    ++
    ++
    ++typedef struct sqlite3expert sqlite3expert;
    ++
    ++/*
    ++** Create a new sqlite3expert object.
    ++**
    ++** If successful, a pointer to the new object is returned and (*pzErr) set
    ++** to NULL. Or, if an error occurs, NULL is returned and (*pzErr) set to
    ++** an English-language error message. In this case it is the responsibility
    ++** of the caller to eventually free the error message buffer using
    ++** sqlite3_free().
    ++*/
    ++sqlite3expert *sqlite3_expert_new(sqlite3 *db, char **pzErr);
    ++
    ++/*
    ++** Configure an sqlite3expert object.
    ++**
    ++** EXPERT_CONFIG_SAMPLE:
    ++**   By default, sqlite3_expert_analyze() generates sqlite_stat1 data for
    ++**   each candidate index. This involves scanning and sorting the entire
    ++**   contents of each user database table once for each candidate index
    ++**   associated with the table. For large databases, this can be 
    ++**   prohibitively slow. This option allows the sqlite3expert object to
    ++**   be configured so that sqlite_stat1 data is instead generated based on a
    ++**   subset of each table, or so that no sqlite_stat1 data is used at all.
    ++**
    ++**   A single integer argument is passed to this option. If the value is less
    ++**   than or equal to zero, then no sqlite_stat1 data is generated or used by
    ++**   the analysis - indexes are recommended based on the database schema only.
    ++**   Or, if the value is 100 or greater, complete sqlite_stat1 data is
    ++**   generated for each candidate index (this is the default). Finally, if the
    ++**   value falls between 0 and 100, then it represents the percentage of user
    ++**   table rows that should be considered when generating sqlite_stat1 data.
    ++**
    ++**   Examples:
    ++**
    ++**     // Do not generate any sqlite_stat1 data
    ++**     sqlite3_expert_config(pExpert, EXPERT_CONFIG_SAMPLE, 0);
    ++**
    ++**     // Generate sqlite_stat1 data based on 10% of the rows in each table.
    ++**     sqlite3_expert_config(pExpert, EXPERT_CONFIG_SAMPLE, 10);
    ++*/
    ++int sqlite3_expert_config(sqlite3expert *p, int op, ...);
    ++
    ++#define EXPERT_CONFIG_SAMPLE 1    /* int */
    ++
    ++/*
    ++** Specify zero or more SQL statements to be included in the analysis.
    ++**
    ++** Buffer zSql must contain zero or more complete SQL statements. This
    ++** function parses all statements contained in the buffer and adds them
    ++** to the internal list of statements to analyze. If successful, SQLITE_OK
    ++** is returned and (*pzErr) set to NULL. Or, if an error occurs - for example
    ++** due to a error in the SQL - an SQLite error code is returned and (*pzErr)
    ++** may be set to point to an English language error message. In this case
    ++** the caller is responsible for eventually freeing the error message buffer
    ++** using sqlite3_free().
    ++**
    ++** If an error does occur while processing one of the statements in the
    ++** buffer passed as the second argument, none of the statements in the
    ++** buffer are added to the analysis.
    ++**
    ++** This function must be called before sqlite3_expert_analyze(). If a call
    ++** to this function is made on an sqlite3expert object that has already
    ++** been passed to sqlite3_expert_analyze() SQLITE_MISUSE is returned
    ++** immediately and no statements are added to the analysis.
    ++*/
    ++int sqlite3_expert_sql(
    ++  sqlite3expert *p,               /* From a successful sqlite3_expert_new() */
    ++  const char *zSql,               /* SQL statement(s) to add */
    ++  char **pzErr                    /* OUT: Error message (if any) */
    ++);
    ++
    ++
    ++/*
    ++** This function is called after the sqlite3expert object has been configured
    ++** with all SQL statements using sqlite3_expert_sql() to actually perform
    ++** the analysis. Once this function has been called, it is not possible to
    ++** add further SQL statements to the analysis.
    ++**
    ++** If successful, SQLITE_OK is returned and (*pzErr) is set to NULL. Or, if
    ++** an error occurs, an SQLite error code is returned and (*pzErr) set to 
    ++** point to a buffer containing an English language error message. In this
    ++** case it is the responsibility of the caller to eventually free the buffer
    ++** using sqlite3_free().
    ++**
    ++** If an error does occur within this function, the sqlite3expert object
    ++** is no longer useful for any purpose. At that point it is no longer
    ++** possible to add further SQL statements to the object or to re-attempt
    ++** the analysis. The sqlite3expert object must still be freed using a call
    ++** sqlite3_expert_destroy().
    ++*/
    ++int sqlite3_expert_analyze(sqlite3expert *p, char **pzErr);
    ++
    ++/*
    ++** Return the total number of statements loaded using sqlite3_expert_sql().
    ++** The total number of SQL statements may be different from the total number
    ++** to calls to sqlite3_expert_sql().
    ++*/
    ++int sqlite3_expert_count(sqlite3expert*);
    ++
    ++/*
    ++** Return a component of the report.
    ++**
    ++** This function is called after sqlite3_expert_analyze() to extract the
    ++** results of the analysis. Each call to this function returns either a
    ++** NULL pointer or a pointer to a buffer containing a nul-terminated string.
    ++** The value passed as the third argument must be one of the EXPERT_REPORT_*
    ++** #define constants defined below.
    ++**
    ++** For some EXPERT_REPORT_* parameters, the buffer returned contains 
    ++** information relating to a specific SQL statement. In these cases that
    ++** SQL statement is identified by the value passed as the second argument.
    ++** SQL statements are numbered from 0 in the order in which they are parsed.
    ++** If an out-of-range value (less than zero or equal to or greater than the
    ++** value returned by sqlite3_expert_count()) is passed as the second argument
    ++** along with such an EXPERT_REPORT_* parameter, NULL is always returned.
    ++**
    ++** EXPERT_REPORT_SQL:
    ++**   Return the text of SQL statement iStmt.
    ++**
    ++** EXPERT_REPORT_INDEXES:
    ++**   Return a buffer containing the CREATE INDEX statements for all recommended
    ++**   indexes for statement iStmt. If there are no new recommeded indexes, NULL 
    ++**   is returned.
    ++**
    ++** EXPERT_REPORT_PLAN:
    ++**   Return a buffer containing the EXPLAIN QUERY PLAN output for SQL query
    ++**   iStmt after the proposed indexes have been added to the database schema.
    ++**
    ++** EXPERT_REPORT_CANDIDATES:
    ++**   Return a pointer to a buffer containing the CREATE INDEX statements 
    ++**   for all indexes that were tested (for all SQL statements). The iStmt
    ++**   parameter is ignored for EXPERT_REPORT_CANDIDATES calls.
    ++*/
    ++const char *sqlite3_expert_report(sqlite3expert*, int iStmt, int eReport);
    ++
    ++/*
    ++** Values for the third argument passed to sqlite3_expert_report().
    ++*/
    ++#define EXPERT_REPORT_SQL        1
    ++#define EXPERT_REPORT_INDEXES    2
    ++#define EXPERT_REPORT_PLAN       3
    ++#define EXPERT_REPORT_CANDIDATES 4
    ++
    ++/*
    ++** Free an (sqlite3expert*) handle and all associated resources. There 
    ++** should be one call to this function for each successful call to 
    ++** sqlite3-expert_new().
    ++*/
    ++void sqlite3_expert_destroy(sqlite3expert*);
    ++
    ++
    ++
    ++/************************* End ../ext/expert/sqlite3expert.h ********************/
    ++/************************* Begin ../ext/expert/sqlite3expert.c ******************/
    ++/*
    ++** 2017 April 09
    ++**
    ++** 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.
    ++**
    ++*************************************************************************
    ++*/
    ++#include <assert.h>
    ++#include <string.h>
    ++#include <stdio.h>
    ++
    ++#ifndef SQLITE_OMIT_VIRTUALTABLE 
    ++
    ++/* typedef sqlite3_int64 i64; */
    ++/* typedef sqlite3_uint64 u64; */
    ++
    ++typedef struct IdxColumn IdxColumn;
    ++typedef struct IdxConstraint IdxConstraint;
    ++typedef struct IdxScan IdxScan;
    ++typedef struct IdxStatement IdxStatement;
    ++typedef struct IdxTable IdxTable;
    ++typedef struct IdxWrite IdxWrite;
    ++
    ++#define STRLEN  (int)strlen
    ++
    ++/*
    ++** A temp table name that we assume no user database will actually use.
    ++** If this assumption proves incorrect triggers on the table with the
    ++** conflicting name will be ignored.
    ++*/
    ++#define UNIQUE_TABLE_NAME "t592690916721053953805701627921227776"
    ++
    ++/*
    ++** A single constraint. Equivalent to either "col = ?" or "col < ?" (or
    ++** any other type of single-ended range constraint on a column).
    ++**
    ++** pLink:
    ++**   Used to temporarily link IdxConstraint objects into lists while
    ++**   creating candidate indexes.
    ++*/
    ++struct IdxConstraint {
    ++  char *zColl;                    /* Collation sequence */
    ++  int bRange;                     /* True for range, false for eq */
    ++  int iCol;                       /* Constrained table column */
    ++  int bFlag;                      /* Used by idxFindCompatible() */
    ++  int bDesc;                      /* True if ORDER BY <expr> DESC */
    ++  IdxConstraint *pNext;           /* Next constraint in pEq or pRange list */
    ++  IdxConstraint *pLink;           /* See above */
    ++};
    ++
    ++/*
    ++** A single scan of a single table.
    ++*/
    ++struct IdxScan {
    ++  IdxTable *pTab;                 /* Associated table object */
    ++  int iDb;                        /* Database containing table zTable */
    ++  i64 covering;                   /* Mask of columns required for cov. index */
    ++  IdxConstraint *pOrder;          /* ORDER BY columns */
    ++  IdxConstraint *pEq;             /* List of == constraints */
    ++  IdxConstraint *pRange;          /* List of < constraints */
    ++  IdxScan *pNextScan;             /* Next IdxScan object for same analysis */
    ++};
    ++
    ++/*
    ++** Information regarding a single database table. Extracted from 
    ++** "PRAGMA table_info" by function idxGetTableInfo().
    ++*/
    ++struct IdxColumn {
    ++  char *zName;
    ++  char *zColl;
    ++  int iPk;
    ++};
    ++struct IdxTable {
    ++  int nCol;
    ++  char *zName;                    /* Table name */
    ++  IdxColumn *aCol;
    ++  IdxTable *pNext;                /* Next table in linked list of all tables */
    ++};
    ++
    ++/*
    ++** An object of the following type is created for each unique table/write-op
    ++** seen. The objects are stored in a singly-linked list beginning at
    ++** sqlite3expert.pWrite.
    ++*/
    ++struct IdxWrite {
    ++  IdxTable *pTab;
    ++  int eOp;                        /* SQLITE_UPDATE, DELETE or INSERT */
    ++  IdxWrite *pNext;
    ++};
    ++
    ++/*
    ++** Each statement being analyzed is represented by an instance of this
    ++** structure.
    ++*/
    ++struct IdxStatement {
    ++  int iId;                        /* Statement number */
    ++  char *zSql;                     /* SQL statement */
    ++  char *zIdx;                     /* Indexes */
    ++  char *zEQP;                     /* Plan */
    ++  IdxStatement *pNext;
    ++};
    ++
    ++
    ++/*
    ++** A hash table for storing strings. With space for a payload string
    ++** with each entry. Methods are:
    ++**
    ++**   idxHashInit()
    ++**   idxHashClear()
    ++**   idxHashAdd()
    ++**   idxHashSearch()
    ++*/
    ++#define IDX_HASH_SIZE 1023
    ++typedef struct IdxHashEntry IdxHashEntry;
    ++typedef struct IdxHash IdxHash;
    ++struct IdxHashEntry {
    ++  char *zKey;                     /* nul-terminated key */
    ++  char *zVal;                     /* nul-terminated value string */
    ++  char *zVal2;                    /* nul-terminated value string 2 */
    ++  IdxHashEntry *pHashNext;        /* Next entry in same hash bucket */
    ++  IdxHashEntry *pNext;            /* Next entry in hash */
    ++};
    ++struct IdxHash {
    ++  IdxHashEntry *pFirst;
    ++  IdxHashEntry *aHash[IDX_HASH_SIZE];
    ++};
    ++
    ++/*
    ++** sqlite3expert object.
    ++*/
    ++struct sqlite3expert {
    ++  int iSample;                    /* Percentage of tables to sample for stat1 */
    ++  sqlite3 *db;                    /* User database */
    ++  sqlite3 *dbm;                   /* In-memory db for this analysis */
    ++  sqlite3 *dbv;                   /* Vtab schema for this analysis */
    ++  IdxTable *pTable;               /* List of all IdxTable objects */
    ++  IdxScan *pScan;                 /* List of scan objects */
    ++  IdxWrite *pWrite;               /* List of write objects */
    ++  IdxStatement *pStatement;       /* List of IdxStatement objects */
    ++  int bRun;                       /* True once analysis has run */
    ++  char **pzErrmsg;
    ++  int rc;                         /* Error code from whereinfo hook */
    ++  IdxHash hIdx;                   /* Hash containing all candidate indexes */
    ++  char *zCandidates;              /* For EXPERT_REPORT_CANDIDATES */
    ++};
    ++
    ++
    ++/*
    ++** Allocate and return nByte bytes of zeroed memory using sqlite3_malloc(). 
    ++** If the allocation fails, set *pRc to SQLITE_NOMEM and return NULL.
    ++*/
    ++static void *idxMalloc(int *pRc, int nByte){
    ++  void *pRet;
    ++  assert( *pRc==SQLITE_OK );
    ++  assert( nByte>0 );
    ++  pRet = sqlite3_malloc(nByte);
    ++  if( pRet ){
    ++    memset(pRet, 0, nByte);
    ++  }else{
    ++    *pRc = SQLITE_NOMEM;
    ++  }
    ++  return pRet;
    ++}
    ++
    ++/*
    ++** Initialize an IdxHash hash table.
    ++*/
    ++static void idxHashInit(IdxHash *pHash){
    ++  memset(pHash, 0, sizeof(IdxHash));
    ++}
    ++
    ++/*
    ++** Reset an IdxHash hash table.
    ++*/
    ++static void idxHashClear(IdxHash *pHash){
    ++  int i;
    ++  for(i=0; i<IDX_HASH_SIZE; i++){
    ++    IdxHashEntry *pEntry;
    ++    IdxHashEntry *pNext;
    ++    for(pEntry=pHash->aHash[i]; pEntry; pEntry=pNext){
    ++      pNext = pEntry->pHashNext;
    ++      sqlite3_free(pEntry->zVal2);
    ++      sqlite3_free(pEntry);
    ++    }
    ++  }
    ++  memset(pHash, 0, sizeof(IdxHash));
    ++}
    ++
    ++/*
    ++** Return the index of the hash bucket that the string specified by the
    ++** arguments to this function belongs.
    ++*/
    ++static int idxHashString(const char *z, int n){
    ++  unsigned int ret = 0;
    ++  int i;
    ++  for(i=0; i<n; i++){
    ++    ret += (ret<<3) + (unsigned char)(z[i]);
    ++  }
    ++  return (int)(ret % IDX_HASH_SIZE);
    ++}
    ++
    ++/*
    ++** If zKey is already present in the hash table, return non-zero and do
    ++** nothing. Otherwise, add an entry with key zKey and payload string zVal to
    ++** the hash table passed as the second argument. 
    ++*/
    ++static int idxHashAdd(
    ++  int *pRc, 
    ++  IdxHash *pHash, 
    ++  const char *zKey,
    ++  const char *zVal
    ++){
    ++  int nKey = STRLEN(zKey);
    ++  int iHash = idxHashString(zKey, nKey);
    ++  int nVal = (zVal ? STRLEN(zVal) : 0);
    ++  IdxHashEntry *pEntry;
    ++  assert( iHash>=0 );
    ++  for(pEntry=pHash->aHash[iHash]; pEntry; pEntry=pEntry->pHashNext){
    ++    if( STRLEN(pEntry->zKey)==nKey && 0==memcmp(pEntry->zKey, zKey, nKey) ){
    ++      return 1;
    ++    }
    ++  }
    ++  pEntry = idxMalloc(pRc, sizeof(IdxHashEntry) + nKey+1 + nVal+1);
    ++  if( pEntry ){
    ++    pEntry->zKey = (char*)&pEntry[1];
    ++    memcpy(pEntry->zKey, zKey, nKey);
    ++    if( zVal ){
    ++      pEntry->zVal = &pEntry->zKey[nKey+1];
    ++      memcpy(pEntry->zVal, zVal, nVal);
    ++    }
    ++    pEntry->pHashNext = pHash->aHash[iHash];
    ++    pHash->aHash[iHash] = pEntry;
    ++
    ++    pEntry->pNext = pHash->pFirst;
    ++    pHash->pFirst = pEntry;
    ++  }
    ++  return 0;
    ++}
    ++
    ++/*
    ++** If zKey/nKey is present in the hash table, return a pointer to the 
    ++** hash-entry object.
    ++*/
    ++static IdxHashEntry *idxHashFind(IdxHash *pHash, const char *zKey, int nKey){
    ++  int iHash;
    ++  IdxHashEntry *pEntry;
    ++  if( nKey<0 ) nKey = STRLEN(zKey);
    ++  iHash = idxHashString(zKey, nKey);
    ++  assert( iHash>=0 );
    ++  for(pEntry=pHash->aHash[iHash]; pEntry; pEntry=pEntry->pHashNext){
    ++    if( STRLEN(pEntry->zKey)==nKey && 0==memcmp(pEntry->zKey, zKey, nKey) ){
    ++      return pEntry;
    ++    }
    ++  }
    ++  return 0;
    ++}
    ++
    ++/*
    ++** If the hash table contains an entry with a key equal to the string
    ++** passed as the final two arguments to this function, return a pointer
    ++** to the payload string. Otherwise, if zKey/nKey is not present in the
    ++** hash table, return NULL.
    ++*/
    ++static const char *idxHashSearch(IdxHash *pHash, const char *zKey, int nKey){
    ++  IdxHashEntry *pEntry = idxHashFind(pHash, zKey, nKey);
    ++  if( pEntry ) return pEntry->zVal;
    ++  return 0;
    ++}
    ++
    ++/*
    ++** Allocate and return a new IdxConstraint object. Set the IdxConstraint.zColl
    ++** variable to point to a copy of nul-terminated string zColl.
    ++*/
    ++static IdxConstraint *idxNewConstraint(int *pRc, const char *zColl){
    ++  IdxConstraint *pNew;
    ++  int nColl = STRLEN(zColl);
    ++
    ++  assert( *pRc==SQLITE_OK );
    ++  pNew = (IdxConstraint*)idxMalloc(pRc, sizeof(IdxConstraint) * nColl + 1);
    ++  if( pNew ){
    ++    pNew->zColl = (char*)&pNew[1];
    ++    memcpy(pNew->zColl, zColl, nColl+1);
    ++  }
    ++  return pNew;
    ++}
    ++
    ++/*
    ++** An error associated with database handle db has just occurred. Pass
    ++** the error message to callback function xOut.
    ++*/
    ++static void idxDatabaseError(
    ++  sqlite3 *db,                    /* Database handle */
    ++  char **pzErrmsg                 /* Write error here */
    ++){
    ++  *pzErrmsg = sqlite3_mprintf("%s", sqlite3_errmsg(db));
    ++}
    ++
    ++/*
    ++** Prepare an SQL statement.
    ++*/
    ++static int idxPrepareStmt(
    ++  sqlite3 *db,                    /* Database handle to compile against */
    ++  sqlite3_stmt **ppStmt,          /* OUT: Compiled SQL statement */
    ++  char **pzErrmsg,                /* OUT: sqlite3_malloc()ed error message */
    ++  const char *zSql                /* SQL statement to compile */
    ++){
    ++  int rc = sqlite3_prepare_v2(db, zSql, -1, ppStmt, 0);
    ++  if( rc!=SQLITE_OK ){
    ++    *ppStmt = 0;
    ++    idxDatabaseError(db, pzErrmsg);
    ++  }
    ++  return rc;
    ++}
    ++
    ++/*
    ++** Prepare an SQL statement using the results of a printf() formatting.
    ++*/
    ++static int idxPrintfPrepareStmt(
    ++  sqlite3 *db,                    /* Database handle to compile against */
    ++  sqlite3_stmt **ppStmt,          /* OUT: Compiled SQL statement */
    ++  char **pzErrmsg,                /* OUT: sqlite3_malloc()ed error message */
    ++  const char *zFmt,               /* printf() format of SQL statement */
    ++  ...                             /* Trailing printf() arguments */
    ++){
    ++  va_list ap;
    ++  int rc;
    ++  char *zSql;
    ++  va_start(ap, zFmt);
    ++  zSql = sqlite3_vmprintf(zFmt, ap);
    ++  if( zSql==0 ){
    ++    rc = SQLITE_NOMEM;
    ++  }else{
    ++    rc = idxPrepareStmt(db, ppStmt, pzErrmsg, zSql);
    ++    sqlite3_free(zSql);
    ++  }
    ++  va_end(ap);
    ++  return rc;
    ++}
    ++
    ++
    ++/*************************************************************************
    ++** Beginning of virtual table implementation.
    ++*/
    ++typedef struct ExpertVtab ExpertVtab;
    ++struct ExpertVtab {
    ++  sqlite3_vtab base;
    ++  IdxTable *pTab;
    ++  sqlite3expert *pExpert;
    ++};
    ++
    ++typedef struct ExpertCsr ExpertCsr;
    ++struct ExpertCsr {
    ++  sqlite3_vtab_cursor base;
    ++  sqlite3_stmt *pData;
    ++};
    ++
    ++static char *expertDequote(const char *zIn){
    ++  int n = STRLEN(zIn);
    ++  char *zRet = sqlite3_malloc(n);
    ++
    ++  assert( zIn[0]=='\'' );
    ++  assert( zIn[n-1]=='\'' );
    ++
    ++  if( zRet ){
    ++    int iOut = 0;
    ++    int iIn = 0;
    ++    for(iIn=1; iIn<(n-1); iIn++){
    ++      if( zIn[iIn]=='\'' ){
    ++        assert( zIn[iIn+1]=='\'' );
    ++        iIn++;
    ++      }
    ++      zRet[iOut++] = zIn[iIn];
    ++    }
    ++    zRet[iOut] = '\0';
    ++  }
    ++
    ++  return zRet;
    ++}
    ++
    ++/* 
    ++** This function is the implementation of both the xConnect and xCreate
    ++** methods of the r-tree virtual table.
    ++**
    ++**   argv[0]   -> module name
    ++**   argv[1]   -> database name
    ++**   argv[2]   -> table name
    ++**   argv[...] -> column names...
    ++*/
    ++static int expertConnect(
    ++  sqlite3 *db,
    ++  void *pAux,
    ++  int argc, const char *const*argv,
    ++  sqlite3_vtab **ppVtab,
    ++  char **pzErr
    ++){
    ++  sqlite3expert *pExpert = (sqlite3expert*)pAux;
    ++  ExpertVtab *p = 0;
    ++  int rc;
    ++
    ++  if( argc!=4 ){
    ++    *pzErr = sqlite3_mprintf("internal error!");
    ++    rc = SQLITE_ERROR;
    ++  }else{
    ++    char *zCreateTable = expertDequote(argv[3]);
    ++    if( zCreateTable ){
    ++      rc = sqlite3_declare_vtab(db, zCreateTable);
    ++      if( rc==SQLITE_OK ){
    ++        p = idxMalloc(&rc, sizeof(ExpertVtab));
    ++      }
    ++      if( rc==SQLITE_OK ){
    ++        p->pExpert = pExpert;
    ++        p->pTab = pExpert->pTable;
    ++        assert( sqlite3_stricmp(p->pTab->zName, argv[2])==0 );
    ++      }
    ++      sqlite3_free(zCreateTable);
    ++    }else{
    ++      rc = SQLITE_NOMEM;
    ++    }
    ++  }
    ++
    ++  *ppVtab = (sqlite3_vtab*)p;
    ++  return rc;
    ++}
    ++
    ++static int expertDisconnect(sqlite3_vtab *pVtab){
    ++  ExpertVtab *p = (ExpertVtab*)pVtab;
    ++  sqlite3_free(p);
    ++  return SQLITE_OK;
    ++}
    ++
    ++static int expertBestIndex(sqlite3_vtab *pVtab, sqlite3_index_info *pIdxInfo){
    ++  ExpertVtab *p = (ExpertVtab*)pVtab;
    ++  int rc = SQLITE_OK;
    ++  int n = 0;
    ++  IdxScan *pScan;
    ++  const int opmask = 
    ++    SQLITE_INDEX_CONSTRAINT_EQ | SQLITE_INDEX_CONSTRAINT_GT |
    ++    SQLITE_INDEX_CONSTRAINT_LT | SQLITE_INDEX_CONSTRAINT_GE |
    ++    SQLITE_INDEX_CONSTRAINT_LE;
    ++
    ++  pScan = idxMalloc(&rc, sizeof(IdxScan));
    ++  if( pScan ){
    ++    int i;
    ++
    ++    /* Link the new scan object into the list */
    ++    pScan->pTab = p->pTab;
    ++    pScan->pNextScan = p->pExpert->pScan;
    ++    p->pExpert->pScan = pScan;
    ++
    ++    /* Add the constraints to the IdxScan object */
    ++    for(i=0; i<pIdxInfo->nConstraint; i++){
    ++      struct sqlite3_index_constraint *pCons = &pIdxInfo->aConstraint[i];
    ++      if( pCons->usable 
    ++       && pCons->iColumn>=0 
    ++       && p->pTab->aCol[pCons->iColumn].iPk==0
    ++       && (pCons->op & opmask) 
    ++      ){
    ++        IdxConstraint *pNew;
    ++        const char *zColl = sqlite3_vtab_collation(pIdxInfo, i);
    ++        pNew = idxNewConstraint(&rc, zColl);
    ++        if( pNew ){
    ++          pNew->iCol = pCons->iColumn;
    ++          if( pCons->op==SQLITE_INDEX_CONSTRAINT_EQ ){
    ++            pNew->pNext = pScan->pEq;
    ++            pScan->pEq = pNew;
    ++          }else{
    ++            pNew->bRange = 1;
    ++            pNew->pNext = pScan->pRange;
    ++            pScan->pRange = pNew;
    ++          }
    ++        }
    ++        n++;
    ++        pIdxInfo->aConstraintUsage[i].argvIndex = n;
    ++      }
    ++    }
    ++
    ++    /* Add the ORDER BY to the IdxScan object */
    ++    for(i=pIdxInfo->nOrderBy-1; i>=0; i--){
    ++      int iCol = pIdxInfo->aOrderBy[i].iColumn;
    ++      if( iCol>=0 ){
    ++        IdxConstraint *pNew = idxNewConstraint(&rc, p->pTab->aCol[iCol].zColl);
    ++        if( pNew ){
    ++          pNew->iCol = iCol;
    ++          pNew->bDesc = pIdxInfo->aOrderBy[i].desc;
    ++          pNew->pNext = pScan->pOrder;
    ++          pNew->pLink = pScan->pOrder;
    ++          pScan->pOrder = pNew;
    ++          n++;
    ++        }
    ++      }
    ++    }
    ++  }
    ++
    ++  pIdxInfo->estimatedCost = 1000000.0 / (n+1);
    ++  return rc;
    ++}
    ++
    ++static int expertUpdate(
    ++  sqlite3_vtab *pVtab, 
    ++  int nData, 
    ++  sqlite3_value **azData, 
    ++  sqlite_int64 *pRowid
    ++){
    ++  (void)pVtab;
    ++  (void)nData;
    ++  (void)azData;
    ++  (void)pRowid;
    ++  return SQLITE_OK;
    ++}
    ++
    ++/* 
    ++** Virtual table module xOpen method.
    ++*/
    ++static int expertOpen(sqlite3_vtab *pVTab, sqlite3_vtab_cursor **ppCursor){
    ++  int rc = SQLITE_OK;
    ++  ExpertCsr *pCsr;
    ++  (void)pVTab;
    ++  pCsr = idxMalloc(&rc, sizeof(ExpertCsr));
    ++  *ppCursor = (sqlite3_vtab_cursor*)pCsr;
    ++  return rc;
    ++}
    ++
    ++/* 
    ++** Virtual table module xClose method.
    ++*/
    ++static int expertClose(sqlite3_vtab_cursor *cur){
    ++  ExpertCsr *pCsr = (ExpertCsr*)cur;
    ++  sqlite3_finalize(pCsr->pData);
    ++  sqlite3_free(pCsr);
    ++  return SQLITE_OK;
    ++}
    ++
    ++/*
    ++** Virtual table module xEof method.
    ++**
    ++** Return non-zero if the cursor does not currently point to a valid 
    ++** record (i.e if the scan has finished), or zero otherwise.
    ++*/
    ++static int expertEof(sqlite3_vtab_cursor *cur){
    ++  ExpertCsr *pCsr = (ExpertCsr*)cur;
    ++  return pCsr->pData==0;
    ++}
    ++
    ++/* 
    ++** Virtual table module xNext method.
    ++*/
    ++static int expertNext(sqlite3_vtab_cursor *cur){
    ++  ExpertCsr *pCsr = (ExpertCsr*)cur;
    ++  int rc = SQLITE_OK;
    ++
    ++  assert( pCsr->pData );
    ++  rc = sqlite3_step(pCsr->pData);
    ++  if( rc!=SQLITE_ROW ){
    ++    rc = sqlite3_finalize(pCsr->pData);
    ++    pCsr->pData = 0;
    ++  }else{
    ++    rc = SQLITE_OK;
    ++  }
    ++
    ++  return rc;
    ++}
    ++
    ++/* 
    ++** Virtual table module xRowid method.
    ++*/
    ++static int expertRowid(sqlite3_vtab_cursor *cur, sqlite_int64 *pRowid){
    ++  (void)cur;
    ++  *pRowid = 0;
    ++  return SQLITE_OK;
    ++}
    ++
    ++/* 
    ++** Virtual table module xColumn method.
    ++*/
    ++static int expertColumn(sqlite3_vtab_cursor *cur, sqlite3_context *ctx, int i){
    ++  ExpertCsr *pCsr = (ExpertCsr*)cur;
    ++  sqlite3_value *pVal;
    ++  pVal = sqlite3_column_value(pCsr->pData, i);
    ++  if( pVal ){
    ++    sqlite3_result_value(ctx, pVal);
    ++  }
    ++  return SQLITE_OK;
    ++}
    ++
    ++/* 
    ++** Virtual table module xFilter method.
    ++*/
    ++static int expertFilter(
    ++  sqlite3_vtab_cursor *cur, 
    ++  int idxNum, const char *idxStr,
    ++  int argc, sqlite3_value **argv
    ++){
    ++  ExpertCsr *pCsr = (ExpertCsr*)cur;
    ++  ExpertVtab *pVtab = (ExpertVtab*)(cur->pVtab);
    ++  sqlite3expert *pExpert = pVtab->pExpert;
    ++  int rc;
    ++
    ++  (void)idxNum;
    ++  (void)idxStr;
    ++  (void)argc;
    ++  (void)argv;
    ++  rc = sqlite3_finalize(pCsr->pData);
    ++  pCsr->pData = 0;
    ++  if( rc==SQLITE_OK ){
    ++    rc = idxPrintfPrepareStmt(pExpert->db, &pCsr->pData, &pVtab->base.zErrMsg,
    ++        "SELECT * FROM main.%Q WHERE sample()", pVtab->pTab->zName
    ++    );
    ++  }
    ++
    ++  if( rc==SQLITE_OK ){
    ++    rc = expertNext(cur);
    ++  }
    ++  return rc;
    ++}
    ++
    ++static int idxRegisterVtab(sqlite3expert *p){
    ++  static sqlite3_module expertModule = {
    ++    2,                            /* iVersion */
    ++    expertConnect,                /* xCreate - create a table */
    ++    expertConnect,                /* xConnect - connect to an existing table */
    ++    expertBestIndex,              /* xBestIndex - Determine search strategy */
    ++    expertDisconnect,             /* xDisconnect - Disconnect from a table */
    ++    expertDisconnect,             /* xDestroy - Drop a table */
    ++    expertOpen,                   /* xOpen - open a cursor */
    ++    expertClose,                  /* xClose - close a cursor */
    ++    expertFilter,                 /* xFilter - configure scan constraints */
    ++    expertNext,                   /* xNext - advance a cursor */
    ++    expertEof,                    /* xEof */
    ++    expertColumn,                 /* xColumn - read data */
    ++    expertRowid,                  /* xRowid - read data */
    ++    expertUpdate,                 /* xUpdate - write data */
    ++    0,                            /* xBegin - begin transaction */
    ++    0,                            /* xSync - sync transaction */
    ++    0,                            /* xCommit - commit transaction */
    ++    0,                            /* xRollback - rollback transaction */
    ++    0,                            /* xFindFunction - function overloading */
    ++    0,                            /* xRename - rename the table */
    ++    0,                            /* xSavepoint */
    ++    0,                            /* xRelease */
    ++    0,                            /* xRollbackTo */
    ++  };
    ++
    ++  return sqlite3_create_module(p->dbv, "expert", &expertModule, (void*)p);
    ++}
    ++/*
    ++** End of virtual table implementation.
    ++*************************************************************************/
    ++/*
    ++** Finalize SQL statement pStmt. If (*pRc) is SQLITE_OK when this function
    ++** is called, set it to the return value of sqlite3_finalize() before
    ++** returning. Otherwise, discard the sqlite3_finalize() return value.
    ++*/
    ++static void idxFinalize(int *pRc, sqlite3_stmt *pStmt){
    ++  int rc = sqlite3_finalize(pStmt);
    ++  if( *pRc==SQLITE_OK ) *pRc = rc;
    ++}
    ++
    ++/*
    ++** Attempt to allocate an IdxTable structure corresponding to table zTab
    ++** in the main database of connection db. If successful, set (*ppOut) to
    ++** point to the new object and return SQLITE_OK. Otherwise, return an
    ++** SQLite error code and set (*ppOut) to NULL. In this case *pzErrmsg may be
    ++** set to point to an error string.
    ++**
    ++** It is the responsibility of the caller to eventually free either the
    ++** IdxTable object or error message using sqlite3_free().
    ++*/
    ++static int idxGetTableInfo(
    ++  sqlite3 *db,                    /* Database connection to read details from */
    ++  const char *zTab,               /* Table name */
    ++  IdxTable **ppOut,               /* OUT: New object (if successful) */
    ++  char **pzErrmsg                 /* OUT: Error message (if not) */
    ++){
    ++  sqlite3_stmt *p1 = 0;
    ++  int nCol = 0;
    ++  int nTab = STRLEN(zTab);
    ++  int nByte = sizeof(IdxTable) + nTab + 1;
    ++  IdxTable *pNew = 0;
    ++  int rc, rc2;
    ++  char *pCsr = 0;
    ++
    ++  rc = idxPrintfPrepareStmt(db, &p1, pzErrmsg, "PRAGMA table_info=%Q", zTab);
    ++  while( rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(p1) ){
    ++    const char *zCol = (const char*)sqlite3_column_text(p1, 1);
    ++    nByte += 1 + STRLEN(zCol);
    ++    rc = sqlite3_table_column_metadata(
    ++        db, "main", zTab, zCol, 0, &zCol, 0, 0, 0
    ++    );
    ++    nByte += 1 + STRLEN(zCol);
    ++    nCol++;
    ++  }
    ++  rc2 = sqlite3_reset(p1);
    ++  if( rc==SQLITE_OK ) rc = rc2;
    ++
    ++  nByte += sizeof(IdxColumn) * nCol;
    ++  if( rc==SQLITE_OK ){
    ++    pNew = idxMalloc(&rc, nByte);
    ++  }
    ++  if( rc==SQLITE_OK ){
    ++    pNew->aCol = (IdxColumn*)&pNew[1];
    ++    pNew->nCol = nCol;
    ++    pCsr = (char*)&pNew->aCol[nCol];
    ++  }
    ++
    ++  nCol = 0;
    ++  while( rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(p1) ){
    ++    const char *zCol = (const char*)sqlite3_column_text(p1, 1);
    ++    int nCopy = STRLEN(zCol) + 1;
    ++    pNew->aCol[nCol].zName = pCsr;
    ++    pNew->aCol[nCol].iPk = sqlite3_column_int(p1, 5);
    ++    memcpy(pCsr, zCol, nCopy);
    ++    pCsr += nCopy;
    ++
    ++    rc = sqlite3_table_column_metadata(
    ++        db, "main", zTab, zCol, 0, &zCol, 0, 0, 0
    ++    );
    ++    if( rc==SQLITE_OK ){
    ++      nCopy = STRLEN(zCol) + 1;
    ++      pNew->aCol[nCol].zColl = pCsr;
    ++      memcpy(pCsr, zCol, nCopy);
    ++      pCsr += nCopy;
    ++    }
    ++
    ++    nCol++;
    ++  }
    ++  idxFinalize(&rc, p1);
    ++
    ++  if( rc!=SQLITE_OK ){
    ++    sqlite3_free(pNew);
    ++    pNew = 0;
    ++  }else{
    ++    pNew->zName = pCsr;
    ++    memcpy(pNew->zName, zTab, nTab+1);
    ++  }
    ++
    ++  *ppOut = pNew;
    ++  return rc;
    ++}
    ++
    ++/*
    ++** This function is a no-op if *pRc is set to anything other than 
    ++** SQLITE_OK when it is called.
    ++**
    ++** If *pRc is initially set to SQLITE_OK, then the text specified by
    ++** the printf() style arguments is appended to zIn and the result returned
    ++** in a buffer allocated by sqlite3_malloc(). sqlite3_free() is called on
    ++** zIn before returning.
    ++*/
    ++static char *idxAppendText(int *pRc, char *zIn, const char *zFmt, ...){
    ++  va_list ap;
    ++  char *zAppend = 0;
    ++  char *zRet = 0;
    ++  int nIn = zIn ? STRLEN(zIn) : 0;
    ++  int nAppend = 0;
    ++  va_start(ap, zFmt);
    ++  if( *pRc==SQLITE_OK ){
    ++    zAppend = sqlite3_vmprintf(zFmt, ap);
    ++    if( zAppend ){
    ++      nAppend = STRLEN(zAppend);
    ++      zRet = (char*)sqlite3_malloc(nIn + nAppend + 1);
    ++    }
    ++    if( zAppend && zRet ){
    ++      if( nIn ) memcpy(zRet, zIn, nIn);
    ++      memcpy(&zRet[nIn], zAppend, nAppend+1);
    ++    }else{
    ++      sqlite3_free(zRet);
    ++      zRet = 0;
    ++      *pRc = SQLITE_NOMEM;
    ++    }
    ++    sqlite3_free(zAppend);
    ++    sqlite3_free(zIn);
    ++  }
    ++  va_end(ap);
    ++  return zRet;
    ++}
    ++
    ++/*
    ++** Return true if zId must be quoted in order to use it as an SQL
    ++** identifier, or false otherwise.
    ++*/
    ++static int idxIdentifierRequiresQuotes(const char *zId){
    ++  int i;
    ++  for(i=0; zId[i]; i++){
    ++    if( !(zId[i]=='_')
    ++     && !(zId[i]>='0' && zId[i]<='9')
    ++     && !(zId[i]>='a' && zId[i]<='z')
    ++     && !(zId[i]>='A' && zId[i]<='Z')
    ++    ){
    ++      return 1;
    ++    }
    ++  }
    ++  return 0;
    ++}
    ++
    ++/*
    ++** This function appends an index column definition suitable for constraint
    ++** pCons to the string passed as zIn and returns the result.
    ++*/
    ++static char *idxAppendColDefn(
    ++  int *pRc,                       /* IN/OUT: Error code */
    ++  char *zIn,                      /* Column defn accumulated so far */
    ++  IdxTable *pTab,                 /* Table index will be created on */
    ++  IdxConstraint *pCons
    ++){
    ++  char *zRet = zIn;
    ++  IdxColumn *p = &pTab->aCol[pCons->iCol];
    ++  if( zRet ) zRet = idxAppendText(pRc, zRet, ", ");
    ++
    ++  if( idxIdentifierRequiresQuotes(p->zName) ){
    ++    zRet = idxAppendText(pRc, zRet, "%Q", p->zName);
    ++  }else{
    ++    zRet = idxAppendText(pRc, zRet, "%s", p->zName);
    ++  }
    ++
    ++  if( sqlite3_stricmp(p->zColl, pCons->zColl) ){
    ++    if( idxIdentifierRequiresQuotes(pCons->zColl) ){
    ++      zRet = idxAppendText(pRc, zRet, " COLLATE %Q", pCons->zColl);
    ++    }else{
    ++      zRet = idxAppendText(pRc, zRet, " COLLATE %s", pCons->zColl);
    ++    }
    ++  }
    ++
    ++  if( pCons->bDesc ){
    ++    zRet = idxAppendText(pRc, zRet, " DESC");
    ++  }
    ++  return zRet;
    ++}
    ++
    ++/*
    ++** Search database dbm for an index compatible with the one idxCreateFromCons()
    ++** would create from arguments pScan, pEq and pTail. If no error occurs and 
    ++** such an index is found, return non-zero. Or, if no such index is found,
    ++** return zero.
    ++**
    ++** If an error occurs, set *pRc to an SQLite error code and return zero.
    ++*/
    ++static int idxFindCompatible(
    ++  int *pRc,                       /* OUT: Error code */
    ++  sqlite3* dbm,                   /* Database to search */
    ++  IdxScan *pScan,                 /* Scan for table to search for index on */
    ++  IdxConstraint *pEq,             /* List of == constraints */
    ++  IdxConstraint *pTail            /* List of range constraints */
    ++){
    ++  const char *zTbl = pScan->pTab->zName;
    ++  sqlite3_stmt *pIdxList = 0;
    ++  IdxConstraint *pIter;
    ++  int nEq = 0;                    /* Number of elements in pEq */
    ++  int rc;
    ++
    ++  /* Count the elements in list pEq */
    ++  for(pIter=pEq; pIter; pIter=pIter->pLink) nEq++;
    ++
    ++  rc = idxPrintfPrepareStmt(dbm, &pIdxList, 0, "PRAGMA index_list=%Q", zTbl);
    ++  while( rc==SQLITE_OK && sqlite3_step(pIdxList)==SQLITE_ROW ){
    ++    int bMatch = 1;
    ++    IdxConstraint *pT = pTail;
    ++    sqlite3_stmt *pInfo = 0;
    ++    const char *zIdx = (const char*)sqlite3_column_text(pIdxList, 1);
    ++
    ++    /* Zero the IdxConstraint.bFlag values in the pEq list */
    ++    for(pIter=pEq; pIter; pIter=pIter->pLink) pIter->bFlag = 0;
    ++
    ++    rc = idxPrintfPrepareStmt(dbm, &pInfo, 0, "PRAGMA index_xInfo=%Q", zIdx);
    ++    while( rc==SQLITE_OK && sqlite3_step(pInfo)==SQLITE_ROW ){
    ++      int iIdx = sqlite3_column_int(pInfo, 0);
    ++      int iCol = sqlite3_column_int(pInfo, 1);
    ++      const char *zColl = (const char*)sqlite3_column_text(pInfo, 4);
    ++
    ++      if( iIdx<nEq ){
    ++        for(pIter=pEq; pIter; pIter=pIter->pLink){
    ++          if( pIter->bFlag ) continue;
    ++          if( pIter->iCol!=iCol ) continue;
    ++          if( sqlite3_stricmp(pIter->zColl, zColl) ) continue;
    ++          pIter->bFlag = 1;
    ++          break;
    ++        }
    ++        if( pIter==0 ){
    ++          bMatch = 0;
    ++          break;
    ++        }
    ++      }else{
    ++        if( pT ){
    ++          if( pT->iCol!=iCol || sqlite3_stricmp(pT->zColl, zColl) ){
    ++            bMatch = 0;
    ++            break;
    ++          }
    ++          pT = pT->pLink;
    ++        }
    ++      }
    ++    }
    ++    idxFinalize(&rc, pInfo);
    ++
    ++    if( rc==SQLITE_OK && bMatch ){
    ++      sqlite3_finalize(pIdxList);
    ++      return 1;
    ++    }
    ++  }
    ++  idxFinalize(&rc, pIdxList);
    ++
    ++  *pRc = rc;
    ++  return 0;
    ++}
    ++
    ++static int idxCreateFromCons(
    ++  sqlite3expert *p,
    ++  IdxScan *pScan,
    ++  IdxConstraint *pEq, 
    ++  IdxConstraint *pTail
    ++){
    ++  sqlite3 *dbm = p->dbm;
    ++  int rc = SQLITE_OK;
    ++  if( (pEq || pTail) && 0==idxFindCompatible(&rc, dbm, pScan, pEq, pTail) ){
    ++    IdxTable *pTab = pScan->pTab;
    ++    char *zCols = 0;
    ++    char *zIdx = 0;
    ++    IdxConstraint *pCons;
    ++    unsigned int h = 0;
    ++    const char *zFmt;
    ++
    ++    for(pCons=pEq; pCons; pCons=pCons->pLink){
    ++      zCols = idxAppendColDefn(&rc, zCols, pTab, pCons);
    ++    }
    ++    for(pCons=pTail; pCons; pCons=pCons->pLink){
    ++      zCols = idxAppendColDefn(&rc, zCols, pTab, pCons);
    ++    }
    ++
    ++    if( rc==SQLITE_OK ){
    ++      /* Hash the list of columns to come up with a name for the index */
    ++      const char *zTable = pScan->pTab->zName;
    ++      char *zName;                /* Index name */
    ++      int i;
    ++      for(i=0; zCols[i]; i++){
    ++        h += ((h<<3) + zCols[i]);
    ++      }
    ++      zName = sqlite3_mprintf("%s_idx_%08x", zTable, h);
    ++      if( zName==0 ){ 
    ++        rc = SQLITE_NOMEM;
    ++      }else{
    ++        if( idxIdentifierRequiresQuotes(zTable) ){
    ++          zFmt = "CREATE INDEX '%q' ON %Q(%s)";
    ++        }else{
    ++          zFmt = "CREATE INDEX %s ON %s(%s)";
    ++        }
    ++        zIdx = sqlite3_mprintf(zFmt, zName, zTable, zCols);
    ++        if( !zIdx ){
    ++          rc = SQLITE_NOMEM;
    ++        }else{
    ++          rc = sqlite3_exec(dbm, zIdx, 0, 0, p->pzErrmsg);
    ++          idxHashAdd(&rc, &p->hIdx, zName, zIdx);
    ++        }
    ++        sqlite3_free(zName);
    ++        sqlite3_free(zIdx);
    ++      }
    ++    }
    ++
    ++    sqlite3_free(zCols);
    ++  }
    ++  return rc;
    ++}
    ++
    ++/*
    ++** Return true if list pList (linked by IdxConstraint.pLink) contains
    ++** a constraint compatible with *p. Otherwise return false.
    ++*/
    ++static int idxFindConstraint(IdxConstraint *pList, IdxConstraint *p){
    ++  IdxConstraint *pCmp;
    ++  for(pCmp=pList; pCmp; pCmp=pCmp->pLink){
    ++    if( p->iCol==pCmp->iCol ) return 1;
    ++  }
    ++  return 0;
    ++}
    ++
    ++static int idxCreateFromWhere(
    ++  sqlite3expert *p, 
    ++  IdxScan *pScan,                 /* Create indexes for this scan */
    ++  IdxConstraint *pTail            /* range/ORDER BY constraints for inclusion */
    ++){
    ++  IdxConstraint *p1 = 0;
    ++  IdxConstraint *pCon;
    ++  int rc;
    ++
    ++  /* Gather up all the == constraints. */
    ++  for(pCon=pScan->pEq; pCon; pCon=pCon->pNext){
    ++    if( !idxFindConstraint(p1, pCon) && !idxFindConstraint(pTail, pCon) ){
    ++      pCon->pLink = p1;
    ++      p1 = pCon;
    ++    }
    ++  }
    ++
    ++  /* Create an index using the == constraints collected above. And the
    ++  ** range constraint/ORDER BY terms passed in by the caller, if any. */
    ++  rc = idxCreateFromCons(p, pScan, p1, pTail);
    ++
    ++  /* If no range/ORDER BY passed by the caller, create a version of the
    ++  ** index for each range constraint.  */
    ++  if( pTail==0 ){
    ++    for(pCon=pScan->pRange; rc==SQLITE_OK && pCon; pCon=pCon->pNext){
    ++      assert( pCon->pLink==0 );
    ++      if( !idxFindConstraint(p1, pCon) && !idxFindConstraint(pTail, pCon) ){
    ++        rc = idxCreateFromCons(p, pScan, p1, pCon);
    ++      }
    ++    }
    ++  }
    ++
    ++  return rc;
    ++}
    ++
    ++/*
    ++** Create candidate indexes in database [dbm] based on the data in 
    ++** linked-list pScan.
    ++*/
    ++static int idxCreateCandidates(sqlite3expert *p){
    ++  int rc = SQLITE_OK;
    ++  IdxScan *pIter;
    ++
    ++  for(pIter=p->pScan; pIter && rc==SQLITE_OK; pIter=pIter->pNextScan){
    ++    rc = idxCreateFromWhere(p, pIter, 0);
    ++    if( rc==SQLITE_OK && pIter->pOrder ){
    ++      rc = idxCreateFromWhere(p, pIter, pIter->pOrder);
    ++    }
    ++  }
    ++
    ++  return rc;
    ++}
    ++
    ++/*
    ++** Free all elements of the linked list starting at pConstraint.
    ++*/
    ++static void idxConstraintFree(IdxConstraint *pConstraint){
    ++  IdxConstraint *pNext;
    ++  IdxConstraint *p;
    ++
    ++  for(p=pConstraint; p; p=pNext){
    ++    pNext = p->pNext;
    ++    sqlite3_free(p);
    ++  }
    ++}
    ++
    ++/*
    ++** Free all elements of the linked list starting from pScan up until pLast
    ++** (pLast is not freed).
    ++*/
    ++static void idxScanFree(IdxScan *pScan, IdxScan *pLast){
    ++  IdxScan *p;
    ++  IdxScan *pNext;
    ++  for(p=pScan; p!=pLast; p=pNext){
    ++    pNext = p->pNextScan;
    ++    idxConstraintFree(p->pOrder);
    ++    idxConstraintFree(p->pEq);
    ++    idxConstraintFree(p->pRange);
    ++    sqlite3_free(p);
    ++  }
    ++}
    ++
    ++/*
    ++** Free all elements of the linked list starting from pStatement up 
    ++** until pLast (pLast is not freed).
    ++*/
    ++static void idxStatementFree(IdxStatement *pStatement, IdxStatement *pLast){
    ++  IdxStatement *p;
    ++  IdxStatement *pNext;
    ++  for(p=pStatement; p!=pLast; p=pNext){
    ++    pNext = p->pNext;
    ++    sqlite3_free(p->zEQP);
    ++    sqlite3_free(p->zIdx);
    ++    sqlite3_free(p);
    ++  }
    ++}
    ++
    ++/*
    ++** Free the linked list of IdxTable objects starting at pTab.
    ++*/
    ++static void idxTableFree(IdxTable *pTab){
    ++  IdxTable *pIter;
    ++  IdxTable *pNext;
    ++  for(pIter=pTab; pIter; pIter=pNext){
    ++    pNext = pIter->pNext;
    ++    sqlite3_free(pIter);
    ++  }
    ++}
    ++
    ++/*
    ++** Free the linked list of IdxWrite objects starting at pTab.
    ++*/
    ++static void idxWriteFree(IdxWrite *pTab){
    ++  IdxWrite *pIter;
    ++  IdxWrite *pNext;
    ++  for(pIter=pTab; pIter; pIter=pNext){
    ++    pNext = pIter->pNext;
    ++    sqlite3_free(pIter);
    ++  }
    ++}
    ++
    ++
    ++
    ++/*
    ++** This function is called after candidate indexes have been created. It
    ++** runs all the queries to see which indexes they prefer, and populates
    ++** IdxStatement.zIdx and IdxStatement.zEQP with the results.
    ++*/
    ++int idxFindIndexes(
    ++  sqlite3expert *p,
    ++  char **pzErr                         /* OUT: Error message (sqlite3_malloc) */
    ++){
    ++  IdxStatement *pStmt;
    ++  sqlite3 *dbm = p->dbm;
    ++  int rc = SQLITE_OK;
    ++
    ++  IdxHash hIdx;
    ++  idxHashInit(&hIdx);
    ++
    ++  for(pStmt=p->pStatement; rc==SQLITE_OK && pStmt; pStmt=pStmt->pNext){
    ++    IdxHashEntry *pEntry;
    ++    sqlite3_stmt *pExplain = 0;
    ++    idxHashClear(&hIdx);
    ++    rc = idxPrintfPrepareStmt(dbm, &pExplain, pzErr,
    ++        "EXPLAIN QUERY PLAN %s", pStmt->zSql
    ++    );
    ++    while( rc==SQLITE_OK && sqlite3_step(pExplain)==SQLITE_ROW ){
    ++      int iSelectid = sqlite3_column_int(pExplain, 0);
    ++      int iOrder = sqlite3_column_int(pExplain, 1);
    ++      int iFrom = sqlite3_column_int(pExplain, 2);
    ++      const char *zDetail = (const char*)sqlite3_column_text(pExplain, 3);
    ++      int nDetail = STRLEN(zDetail);
    ++      int i;
    ++
    ++      for(i=0; i<nDetail; i++){
    ++        const char *zIdx = 0;
    ++        if( memcmp(&zDetail[i], " USING INDEX ", 13)==0 ){
    ++          zIdx = &zDetail[i+13];
    ++        }else if( memcmp(&zDetail[i], " USING COVERING INDEX ", 22)==0 ){
    ++          zIdx = &zDetail[i+22];
    ++        }
    ++        if( zIdx ){
    ++          const char *zSql;
    ++          int nIdx = 0;
    ++          while( zIdx[nIdx]!='\0' && (zIdx[nIdx]!=' ' || zIdx[nIdx+1]!='(') ){
    ++            nIdx++;
    ++          }
    ++          zSql = idxHashSearch(&p->hIdx, zIdx, nIdx);
    ++          if( zSql ){
    ++            idxHashAdd(&rc, &hIdx, zSql, 0);
    ++            if( rc ) goto find_indexes_out;
    ++          }
    ++          break;
    ++        }
    ++      }
    ++
    ++      pStmt->zEQP = idxAppendText(&rc, pStmt->zEQP, "%d|%d|%d|%s\n", 
    ++          iSelectid, iOrder, iFrom, zDetail
    ++      );
    ++    }
    ++
    ++    for(pEntry=hIdx.pFirst; pEntry; pEntry=pEntry->pNext){
    ++      pStmt->zIdx = idxAppendText(&rc, pStmt->zIdx, "%s;\n", pEntry->zKey);
    ++    }
    ++
    ++    idxFinalize(&rc, pExplain);
    ++  }
    ++
    ++ find_indexes_out:
    ++  idxHashClear(&hIdx);
    ++  return rc;
    ++}
    ++
    ++static int idxAuthCallback(
    ++  void *pCtx,
    ++  int eOp,
    ++  const char *z3,
    ++  const char *z4,
    ++  const char *zDb,
    ++  const char *zTrigger
    ++){
    ++  int rc = SQLITE_OK;
    ++  (void)z4;
    ++  (void)zTrigger;
    ++  if( eOp==SQLITE_INSERT || eOp==SQLITE_UPDATE || eOp==SQLITE_DELETE ){
    ++    if( sqlite3_stricmp(zDb, "main")==0 ){
    ++      sqlite3expert *p = (sqlite3expert*)pCtx;
    ++      IdxTable *pTab;
    ++      for(pTab=p->pTable; pTab; pTab=pTab->pNext){
    ++        if( 0==sqlite3_stricmp(z3, pTab->zName) ) break;
    ++      }
    ++      if( pTab ){
    ++        IdxWrite *pWrite;
    ++        for(pWrite=p->pWrite; pWrite; pWrite=pWrite->pNext){
    ++          if( pWrite->pTab==pTab && pWrite->eOp==eOp ) break;
    ++        }
    ++        if( pWrite==0 ){
    ++          pWrite = idxMalloc(&rc, sizeof(IdxWrite));
    ++          if( rc==SQLITE_OK ){
    ++            pWrite->pTab = pTab;
    ++            pWrite->eOp = eOp;
    ++            pWrite->pNext = p->pWrite;
    ++            p->pWrite = pWrite;
    ++          }
    ++        }
    ++      }
    ++    }
    ++  }
    ++  return rc;
    ++}
    ++
    ++static int idxProcessOneTrigger(
    ++  sqlite3expert *p, 
    ++  IdxWrite *pWrite, 
    ++  char **pzErr
    ++){
    ++  static const char *zInt = UNIQUE_TABLE_NAME;
    ++  static const char *zDrop = "DROP TABLE " UNIQUE_TABLE_NAME;
    ++  IdxTable *pTab = pWrite->pTab;
    ++  const char *zTab = pTab->zName;
    ++  const char *zSql = 
    ++    "SELECT 'CREATE TEMP' || substr(sql, 7) FROM sqlite_master "
    ++    "WHERE tbl_name = %Q AND type IN ('table', 'trigger') "
    ++    "ORDER BY type;";
    ++  sqlite3_stmt *pSelect = 0;
    ++  int rc = SQLITE_OK;
    ++  char *zWrite = 0;
    ++
    ++  /* Create the table and its triggers in the temp schema */
    ++  rc = idxPrintfPrepareStmt(p->db, &pSelect, pzErr, zSql, zTab, zTab);
    ++  while( rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pSelect) ){
    ++    const char *zCreate = (const char*)sqlite3_column_text(pSelect, 0);
    ++    rc = sqlite3_exec(p->dbv, zCreate, 0, 0, pzErr);
    ++  }
    ++  idxFinalize(&rc, pSelect);
    ++
    ++  /* Rename the table in the temp schema to zInt */
    ++  if( rc==SQLITE_OK ){
    ++    char *z = sqlite3_mprintf("ALTER TABLE temp.%Q RENAME TO %Q", zTab, zInt);
    ++    if( z==0 ){
    ++      rc = SQLITE_NOMEM;
    ++    }else{
    ++      rc = sqlite3_exec(p->dbv, z, 0, 0, pzErr);
    ++      sqlite3_free(z);
    ++    }
    ++  }
    ++
    ++  switch( pWrite->eOp ){
    ++    case SQLITE_INSERT: {
    ++      int i;
    ++      zWrite = idxAppendText(&rc, zWrite, "INSERT INTO %Q VALUES(", zInt);
    ++      for(i=0; i<pTab->nCol; i++){
    ++        zWrite = idxAppendText(&rc, zWrite, "%s?", i==0 ? "" : ", ");
    ++      }
    ++      zWrite = idxAppendText(&rc, zWrite, ")");
    ++      break;
    ++    }
    ++    case SQLITE_UPDATE: {
    ++      int i;
    ++      zWrite = idxAppendText(&rc, zWrite, "UPDATE %Q SET ", zInt);
    ++      for(i=0; i<pTab->nCol; i++){
    ++        zWrite = idxAppendText(&rc, zWrite, "%s%Q=?", i==0 ? "" : ", ", 
    ++            pTab->aCol[i].zName
    ++        );
    ++      }
    ++      break;
    ++    }
    ++    default: {
    ++      assert( pWrite->eOp==SQLITE_DELETE );
    ++      if( rc==SQLITE_OK ){
    ++        zWrite = sqlite3_mprintf("DELETE FROM %Q", zInt);
    ++        if( zWrite==0 ) rc = SQLITE_NOMEM;
    ++      }
    ++    }
    ++  }
    ++
    ++  if( rc==SQLITE_OK ){
    ++    sqlite3_stmt *pX = 0;
    ++    rc = sqlite3_prepare_v2(p->dbv, zWrite, -1, &pX, 0);
    ++    idxFinalize(&rc, pX);
    ++    if( rc!=SQLITE_OK ){
    ++      idxDatabaseError(p->dbv, pzErr);
    ++    }
    ++  }
    ++  sqlite3_free(zWrite);
    ++
    ++  if( rc==SQLITE_OK ){
    ++    rc = sqlite3_exec(p->dbv, zDrop, 0, 0, pzErr);
    ++  }
    ++
    ++  return rc;
    ++}
    ++
    ++static int idxProcessTriggers(sqlite3expert *p, char **pzErr){
    ++  int rc = SQLITE_OK;
    ++  IdxWrite *pEnd = 0;
    ++  IdxWrite *pFirst = p->pWrite;
    ++
    ++  while( rc==SQLITE_OK && pFirst!=pEnd ){
    ++    IdxWrite *pIter;
    ++    for(pIter=pFirst; rc==SQLITE_OK && pIter!=pEnd; pIter=pIter->pNext){
    ++      rc = idxProcessOneTrigger(p, pIter, pzErr);
    ++    }
    ++    pEnd = pFirst;
    ++    pFirst = p->pWrite;
    ++  }
    ++
    ++  return rc;
    ++}
    ++
    ++
    ++static int idxCreateVtabSchema(sqlite3expert *p, char **pzErrmsg){
    ++  int rc = idxRegisterVtab(p);
    ++  sqlite3_stmt *pSchema = 0;
    ++
    ++  /* For each table in the main db schema:
    ++  **
    ++  **   1) Add an entry to the p->pTable list, and
    ++  **   2) Create the equivalent virtual table in dbv.
    ++  */
    ++  rc = idxPrepareStmt(p->db, &pSchema, pzErrmsg,
    ++      "SELECT type, name, sql, 1 FROM sqlite_master "
    ++      "WHERE type IN ('table','view') AND name NOT LIKE 'sqlite_%%' "
    ++      " UNION ALL "
    ++      "SELECT type, name, sql, 2 FROM sqlite_master "
    ++      "WHERE type = 'trigger'"
    ++      "  AND tbl_name IN(SELECT name FROM sqlite_master WHERE type = 'view') "
    ++      "ORDER BY 4, 1"
    ++  );
    ++  while( rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pSchema) ){
    ++    const char *zType = (const char*)sqlite3_column_text(pSchema, 0);
    ++    const char *zName = (const char*)sqlite3_column_text(pSchema, 1);
    ++    const char *zSql = (const char*)sqlite3_column_text(pSchema, 2);
    ++
    ++    if( zType[0]=='v' || zType[1]=='r' ){
    ++      rc = sqlite3_exec(p->dbv, zSql, 0, 0, pzErrmsg);
    ++    }else{
    ++      IdxTable *pTab;
    ++      rc = idxGetTableInfo(p->db, zName, &pTab, pzErrmsg);
    ++      if( rc==SQLITE_OK ){
    ++        int i;
    ++        char *zInner = 0;
    ++        char *zOuter = 0;
    ++        pTab->pNext = p->pTable;
    ++        p->pTable = pTab;
    ++
    ++        /* The statement the vtab will pass to sqlite3_declare_vtab() */
    ++        zInner = idxAppendText(&rc, 0, "CREATE TABLE x(");
    ++        for(i=0; i<pTab->nCol; i++){
    ++          zInner = idxAppendText(&rc, zInner, "%s%Q COLLATE %s", 
    ++              (i==0 ? "" : ", "), pTab->aCol[i].zName, pTab->aCol[i].zColl
    ++          );
    ++        }
    ++        zInner = idxAppendText(&rc, zInner, ")");
    ++
    ++        /* The CVT statement to create the vtab */
    ++        zOuter = idxAppendText(&rc, 0, 
    ++            "CREATE VIRTUAL TABLE %Q USING expert(%Q)", zName, zInner
    ++        );
    ++        if( rc==SQLITE_OK ){
    ++          rc = sqlite3_exec(p->dbv, zOuter, 0, 0, pzErrmsg);
    ++        }
    ++        sqlite3_free(zInner);
    ++        sqlite3_free(zOuter);
    ++      }
    ++    }
    ++  }
    ++  idxFinalize(&rc, pSchema);
    ++  return rc;
    ++}
    ++
    ++struct IdxSampleCtx {
    ++  int iTarget;
    ++  double target;                  /* Target nRet/nRow value */
    ++  double nRow;                    /* Number of rows seen */
    ++  double nRet;                    /* Number of rows returned */
    ++};
    ++
    ++static void idxSampleFunc(
    ++  sqlite3_context *pCtx,
    ++  int argc,
    ++  sqlite3_value **argv
    ++){
    ++  struct IdxSampleCtx *p = (struct IdxSampleCtx*)sqlite3_user_data(pCtx);
    ++  int bRet;
    ++
    ++  (void)argv;
    ++  assert( argc==0 );
    ++  if( p->nRow==0.0 ){
    ++    bRet = 1;
    ++  }else{
    ++    bRet = (p->nRet / p->nRow) <= p->target;
    ++    if( bRet==0 ){
    ++      unsigned short rnd;
    ++      sqlite3_randomness(2, (void*)&rnd);
    ++      bRet = ((int)rnd % 100) <= p->iTarget;
    ++    }
    ++  }
    ++
    ++  sqlite3_result_int(pCtx, bRet);
    ++  p->nRow += 1.0;
    ++  p->nRet += (double)bRet;
    ++}
    ++
    ++struct IdxRemCtx {
    ++  int nSlot;
    ++  struct IdxRemSlot {
    ++    int eType;                    /* SQLITE_NULL, INTEGER, REAL, TEXT, BLOB */
    ++    i64 iVal;                     /* SQLITE_INTEGER value */
    ++    double rVal;                  /* SQLITE_FLOAT value */
    ++    int nByte;                    /* Bytes of space allocated at z */
    ++    int n;                        /* Size of buffer z */
    ++    char *z;                      /* SQLITE_TEXT/BLOB value */
    ++  } aSlot[1];
    ++};
    ++
    ++/*
    ++** Implementation of scalar function rem().
    ++*/
    ++static void idxRemFunc(
    ++  sqlite3_context *pCtx,
    ++  int argc,
    ++  sqlite3_value **argv
    ++){
    ++  struct IdxRemCtx *p = (struct IdxRemCtx*)sqlite3_user_data(pCtx);
    ++  struct IdxRemSlot *pSlot;
    ++  int iSlot;
    ++  assert( argc==2 );
    ++
    ++  iSlot = sqlite3_value_int(argv[0]);
    ++  assert( iSlot<=p->nSlot );
    ++  pSlot = &p->aSlot[iSlot];
    ++
    ++  switch( pSlot->eType ){
    ++    case SQLITE_NULL:
    ++      /* no-op */
    ++      break;
    ++
    ++    case SQLITE_INTEGER:
    ++      sqlite3_result_int64(pCtx, pSlot->iVal);
    ++      break;
    ++
    ++    case SQLITE_FLOAT:
    ++      sqlite3_result_double(pCtx, pSlot->rVal);
    ++      break;
    ++
    ++    case SQLITE_BLOB:
    ++      sqlite3_result_blob(pCtx, pSlot->z, pSlot->n, SQLITE_TRANSIENT);
    ++      break;
    ++
    ++    case SQLITE_TEXT:
    ++      sqlite3_result_text(pCtx, pSlot->z, pSlot->n, SQLITE_TRANSIENT);
    ++      break;
    ++  }
    ++
    ++  pSlot->eType = sqlite3_value_type(argv[1]);
    ++  switch( pSlot->eType ){
    ++    case SQLITE_NULL:
    ++      /* no-op */
    ++      break;
    ++
    ++    case SQLITE_INTEGER:
    ++      pSlot->iVal = sqlite3_value_int64(argv[1]);
    ++      break;
    ++
    ++    case SQLITE_FLOAT:
    ++      pSlot->rVal = sqlite3_value_double(argv[1]);
    ++      break;
    ++
    ++    case SQLITE_BLOB:
    ++    case SQLITE_TEXT: {
    ++      int nByte = sqlite3_value_bytes(argv[1]);
    ++      if( nByte>pSlot->nByte ){
    ++        char *zNew = (char*)sqlite3_realloc(pSlot->z, nByte*2);
    ++        if( zNew==0 ){
    ++          sqlite3_result_error_nomem(pCtx);
    ++          return;
    ++        }
    ++        pSlot->nByte = nByte*2;
    ++        pSlot->z = zNew;
    ++      }
    ++      pSlot->n = nByte;
    ++      if( pSlot->eType==SQLITE_BLOB ){
    ++        memcpy(pSlot->z, sqlite3_value_blob(argv[1]), nByte);
    ++      }else{
    ++        memcpy(pSlot->z, sqlite3_value_text(argv[1]), nByte);
    ++      }
    ++      break;
    ++    }
    ++  }
    ++}
    ++
    ++static int idxLargestIndex(sqlite3 *db, int *pnMax, char **pzErr){
    ++  int rc = SQLITE_OK;
    ++  const char *zMax = 
    ++    "SELECT max(i.seqno) FROM "
    ++    "  sqlite_master AS s, "
    ++    "  pragma_index_list(s.name) AS l, "
    ++    "  pragma_index_info(l.name) AS i "
    ++    "WHERE s.type = 'table'";
    ++  sqlite3_stmt *pMax = 0;
    ++
    ++  *pnMax = 0;
    ++  rc = idxPrepareStmt(db, &pMax, pzErr, zMax);
    ++  if( rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pMax) ){
    ++    *pnMax = sqlite3_column_int(pMax, 0) + 1;
    ++  }
    ++  idxFinalize(&rc, pMax);
    ++
    ++  return rc;
    ++}
    ++
    ++static int idxPopulateOneStat1(
    ++  sqlite3expert *p,
    ++  sqlite3_stmt *pIndexXInfo,
    ++  sqlite3_stmt *pWriteStat,
    ++  const char *zTab,
    ++  const char *zIdx,
    ++  char **pzErr
    ++){
    ++  char *zCols = 0;
    ++  char *zOrder = 0;
    ++  char *zQuery = 0;
    ++  int nCol = 0;
    ++  int i;
    ++  sqlite3_stmt *pQuery = 0;
    ++  int *aStat = 0;
    ++  int rc = SQLITE_OK;
    ++
    ++  assert( p->iSample>0 );
    ++
    ++  /* Formulate the query text */
    ++  sqlite3_bind_text(pIndexXInfo, 1, zIdx, -1, SQLITE_STATIC);
    ++  while( SQLITE_OK==rc && SQLITE_ROW==sqlite3_step(pIndexXInfo) ){
    ++    const char *zComma = zCols==0 ? "" : ", ";
    ++    const char *zName = (const char*)sqlite3_column_text(pIndexXInfo, 0);
    ++    const char *zColl = (const char*)sqlite3_column_text(pIndexXInfo, 1);
    ++    zCols = idxAppendText(&rc, zCols, 
    ++        "%sx.%Q IS rem(%d, x.%Q) COLLATE %s", zComma, zName, nCol, zName, zColl
    ++    );
    ++    zOrder = idxAppendText(&rc, zOrder, "%s%d", zComma, ++nCol);
    ++  }
    ++  sqlite3_reset(pIndexXInfo);
    ++  if( rc==SQLITE_OK ){
    ++    if( p->iSample==100 ){
    ++      zQuery = sqlite3_mprintf(
    ++          "SELECT %s FROM %Q x ORDER BY %s", zCols, zTab, zOrder
    ++      );
    ++    }else{
    ++      zQuery = sqlite3_mprintf(
    ++          "SELECT %s FROM temp."UNIQUE_TABLE_NAME" x ORDER BY %s", zCols, zOrder
    ++      );
    ++    }
    ++  }
    ++  sqlite3_free(zCols);
    ++  sqlite3_free(zOrder);
    ++
    ++  /* Formulate the query text */
    ++  if( rc==SQLITE_OK ){
    ++    sqlite3 *dbrem = (p->iSample==100 ? p->db : p->dbv);
    ++    rc = idxPrepareStmt(dbrem, &pQuery, pzErr, zQuery);
    ++  }
    ++  sqlite3_free(zQuery);
    ++
    ++  if( rc==SQLITE_OK ){
    ++    aStat = (int*)idxMalloc(&rc, sizeof(int)*(nCol+1));
    ++  }
    ++  if( rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pQuery) ){
    ++    IdxHashEntry *pEntry;
    ++    char *zStat = 0;
    ++    for(i=0; i<=nCol; i++) aStat[i] = 1;
    ++    while( rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pQuery) ){
    ++      aStat[0]++;
    ++      for(i=0; i<nCol; i++){
    ++        if( sqlite3_column_int(pQuery, i)==0 ) break;
    ++      }
    ++      for(/*no-op*/; i<nCol; i++){
    ++        aStat[i+1]++;
    ++      }
    ++    }
    ++
    ++    if( rc==SQLITE_OK ){
    ++      int s0 = aStat[0];
    ++      zStat = sqlite3_mprintf("%d", s0);
    ++      if( zStat==0 ) rc = SQLITE_NOMEM;
    ++      for(i=1; rc==SQLITE_OK && i<=nCol; i++){
    ++        zStat = idxAppendText(&rc, zStat, " %d", (s0+aStat[i]/2) / aStat[i]);
    ++      }
    ++    }
    ++
    ++    if( rc==SQLITE_OK ){
    ++      sqlite3_bind_text(pWriteStat, 1, zTab, -1, SQLITE_STATIC);
    ++      sqlite3_bind_text(pWriteStat, 2, zIdx, -1, SQLITE_STATIC);
    ++      sqlite3_bind_text(pWriteStat, 3, zStat, -1, SQLITE_STATIC);
    ++      sqlite3_step(pWriteStat);
    ++      rc = sqlite3_reset(pWriteStat);
    ++    }
    ++
    ++    pEntry = idxHashFind(&p->hIdx, zIdx, STRLEN(zIdx));
    ++    if( pEntry ){
    ++      assert( pEntry->zVal2==0 );
    ++      pEntry->zVal2 = zStat;
    ++    }else{
    ++      sqlite3_free(zStat);
    ++    }
    ++  }
    ++  sqlite3_free(aStat);
    ++  idxFinalize(&rc, pQuery);
    ++
    ++  return rc;
    ++}
    ++
    ++static int idxBuildSampleTable(sqlite3expert *p, const char *zTab){
    ++  int rc;
    ++  char *zSql;
    ++
    ++  rc = sqlite3_exec(p->dbv,"DROP TABLE IF EXISTS temp."UNIQUE_TABLE_NAME,0,0,0);
    ++  if( rc!=SQLITE_OK ) return rc;
    ++
    ++  zSql = sqlite3_mprintf(
    ++      "CREATE TABLE temp." UNIQUE_TABLE_NAME " AS SELECT * FROM %Q", zTab
    ++  );
    ++  if( zSql==0 ) return SQLITE_NOMEM;
    ++  rc = sqlite3_exec(p->dbv, zSql, 0, 0, 0);
    ++  sqlite3_free(zSql);
    ++
    ++  return rc;
    ++}
    ++
    ++/*
    ++** This function is called as part of sqlite3_expert_analyze(). Candidate
    ++** indexes have already been created in database sqlite3expert.dbm, this
    ++** function populates sqlite_stat1 table in the same database.
    ++**
    ++** The stat1 data is generated by querying the 
    ++*/
    ++static int idxPopulateStat1(sqlite3expert *p, char **pzErr){
    ++  int rc = SQLITE_OK;
    ++  int nMax =0;
    ++  struct IdxRemCtx *pCtx = 0;
    ++  struct IdxSampleCtx samplectx; 
    ++  int i;
    ++  i64 iPrev = -100000;
    ++  sqlite3_stmt *pAllIndex = 0;
    ++  sqlite3_stmt *pIndexXInfo = 0;
    ++  sqlite3_stmt *pWrite = 0;
    ++
    ++  const char *zAllIndex =
    ++    "SELECT s.rowid, s.name, l.name FROM "
    ++    "  sqlite_master AS s, "
    ++    "  pragma_index_list(s.name) AS l "
    ++    "WHERE s.type = 'table'";
    ++  const char *zIndexXInfo = 
    ++    "SELECT name, coll FROM pragma_index_xinfo(?) WHERE key";
    ++  const char *zWrite = "INSERT INTO sqlite_stat1 VALUES(?, ?, ?)";
    ++
    ++  /* If iSample==0, no sqlite_stat1 data is required. */
    ++  if( p->iSample==0 ) return SQLITE_OK;
    ++
    ++  rc = idxLargestIndex(p->dbm, &nMax, pzErr);
    ++  if( nMax<=0 || rc!=SQLITE_OK ) return rc;
    ++
    ++  rc = sqlite3_exec(p->dbm, "ANALYZE; PRAGMA writable_schema=1", 0, 0, 0);
    ++
    ++  if( rc==SQLITE_OK ){
    ++    int nByte = sizeof(struct IdxRemCtx) + (sizeof(struct IdxRemSlot) * nMax);
    ++    pCtx = (struct IdxRemCtx*)idxMalloc(&rc, nByte);
    ++  }
    ++
    ++  if( rc==SQLITE_OK ){
    ++    sqlite3 *dbrem = (p->iSample==100 ? p->db : p->dbv);
    ++    rc = sqlite3_create_function(
    ++        dbrem, "rem", 2, SQLITE_UTF8, (void*)pCtx, idxRemFunc, 0, 0
    ++    );
    ++  }
    ++  if( rc==SQLITE_OK ){
    ++    rc = sqlite3_create_function(
    ++        p->db, "sample", 0, SQLITE_UTF8, (void*)&samplectx, idxSampleFunc, 0, 0
    ++    );
    ++  }
    ++
    ++  if( rc==SQLITE_OK ){
    ++    pCtx->nSlot = nMax+1;
    ++    rc = idxPrepareStmt(p->dbm, &pAllIndex, pzErr, zAllIndex);
    ++  }
    ++  if( rc==SQLITE_OK ){
    ++    rc = idxPrepareStmt(p->dbm, &pIndexXInfo, pzErr, zIndexXInfo);
    ++  }
    ++  if( rc==SQLITE_OK ){
    ++    rc = idxPrepareStmt(p->dbm, &pWrite, pzErr, zWrite);
    ++  }
    ++
    ++  while( rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pAllIndex) ){
    ++    i64 iRowid = sqlite3_column_int64(pAllIndex, 0);
    ++    const char *zTab = (const char*)sqlite3_column_text(pAllIndex, 1);
    ++    const char *zIdx = (const char*)sqlite3_column_text(pAllIndex, 2);
    ++    if( p->iSample<100 && iPrev!=iRowid ){
    ++      samplectx.target = (double)p->iSample / 100.0;
    ++      samplectx.iTarget = p->iSample;
    ++      samplectx.nRow = 0.0;
    ++      samplectx.nRet = 0.0;
    ++      rc = idxBuildSampleTable(p, zTab);
    ++      if( rc!=SQLITE_OK ) break;
    ++    }
    ++    rc = idxPopulateOneStat1(p, pIndexXInfo, pWrite, zTab, zIdx, pzErr);
    ++    iPrev = iRowid;
    ++  }
    ++  if( rc==SQLITE_OK && p->iSample<100 ){
    ++    rc = sqlite3_exec(p->dbv, 
    ++        "DROP TABLE IF EXISTS temp." UNIQUE_TABLE_NAME, 0,0,0
    ++    );
    ++  }
    ++
    ++  idxFinalize(&rc, pAllIndex);
    ++  idxFinalize(&rc, pIndexXInfo);
    ++  idxFinalize(&rc, pWrite);
    ++
    ++  for(i=0; i<pCtx->nSlot; i++){
    ++    sqlite3_free(pCtx->aSlot[i].z);
    ++  }
    ++  sqlite3_free(pCtx);
    ++
    ++  if( rc==SQLITE_OK ){
    ++    rc = sqlite3_exec(p->dbm, "ANALYZE sqlite_master", 0, 0, 0);
    ++  }
    ++
    ++  sqlite3_exec(p->db, "DROP TABLE IF EXISTS temp."UNIQUE_TABLE_NAME,0,0,0);
    ++  return rc;
    ++}
    ++
    ++/*
    ++** Allocate a new sqlite3expert object.
    ++*/
    ++sqlite3expert *sqlite3_expert_new(sqlite3 *db, char **pzErrmsg){
    ++  int rc = SQLITE_OK;
    ++  sqlite3expert *pNew;
    ++
    ++  pNew = (sqlite3expert*)idxMalloc(&rc, sizeof(sqlite3expert));
    ++
    ++  /* Open two in-memory databases to work with. The "vtab database" (dbv)
    ++  ** will contain a virtual table corresponding to each real table in
    ++  ** the user database schema, and a copy of each view. It is used to
    ++  ** collect information regarding the WHERE, ORDER BY and other clauses
    ++  ** of the user's query.
    ++  */
    ++  if( rc==SQLITE_OK ){
    ++    pNew->db = db;
    ++    pNew->iSample = 100;
    ++    rc = sqlite3_open(":memory:", &pNew->dbv);
    ++  }
    ++  if( rc==SQLITE_OK ){
    ++    rc = sqlite3_open(":memory:", &pNew->dbm);
    ++    if( rc==SQLITE_OK ){
    ++      sqlite3_db_config(pNew->dbm, SQLITE_DBCONFIG_TRIGGER_EQP, 1, (int*)0);
    ++    }
    ++  }
    ++  
    ++
    ++  /* Copy the entire schema of database [db] into [dbm]. */
    ++  if( rc==SQLITE_OK ){
    ++    sqlite3_stmt *pSql;
    ++    rc = idxPrintfPrepareStmt(pNew->db, &pSql, pzErrmsg, 
    ++        "SELECT sql FROM sqlite_master WHERE name NOT LIKE 'sqlite_%%'"
    ++        " AND sql NOT LIKE 'CREATE VIRTUAL %%'"
    ++    );
    ++    while( rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pSql) ){
    ++      const char *zSql = (const char*)sqlite3_column_text(pSql, 0);
    ++      rc = sqlite3_exec(pNew->dbm, zSql, 0, 0, pzErrmsg);
    ++    }
    ++    idxFinalize(&rc, pSql);
    ++  }
    ++
    ++  /* Create the vtab schema */
    ++  if( rc==SQLITE_OK ){
    ++    rc = idxCreateVtabSchema(pNew, pzErrmsg);
    ++  }
    ++
    ++  /* Register the auth callback with dbv */
    ++  if( rc==SQLITE_OK ){
    ++    sqlite3_set_authorizer(pNew->dbv, idxAuthCallback, (void*)pNew);
    ++  }
    ++
    ++  /* If an error has occurred, free the new object and reutrn NULL. Otherwise,
    ++  ** return the new sqlite3expert handle.  */
    ++  if( rc!=SQLITE_OK ){
    ++    sqlite3_expert_destroy(pNew);
    ++    pNew = 0;
    ++  }
    ++  return pNew;
    ++}
    ++
    ++/*
    ++** Configure an sqlite3expert object.
    ++*/
    ++int sqlite3_expert_config(sqlite3expert *p, int op, ...){
    ++  int rc = SQLITE_OK;
    ++  va_list ap;
    ++  va_start(ap, op);
    ++  switch( op ){
    ++    case EXPERT_CONFIG_SAMPLE: {
    ++      int iVal = va_arg(ap, int);
    ++      if( iVal<0 ) iVal = 0;
    ++      if( iVal>100 ) iVal = 100;
    ++      p->iSample = iVal;
    ++      break;
    ++    }
    ++    default:
    ++      rc = SQLITE_NOTFOUND;
    ++      break;
    ++  }
    ++
    ++  va_end(ap);
    ++  return rc;
    ++}
    ++
    ++/*
    ++** Add an SQL statement to the analysis.
    ++*/
    ++int sqlite3_expert_sql(
    ++  sqlite3expert *p,               /* From sqlite3_expert_new() */
    ++  const char *zSql,               /* SQL statement to add */
    ++  char **pzErr                    /* OUT: Error message (if any) */
    ++){
    ++  IdxScan *pScanOrig = p->pScan;
    ++  IdxStatement *pStmtOrig = p->pStatement;
    ++  int rc = SQLITE_OK;
    ++  const char *zStmt = zSql;
    ++
    ++  if( p->bRun ) return SQLITE_MISUSE;
    ++
    ++  while( rc==SQLITE_OK && zStmt && zStmt[0] ){
    ++    sqlite3_stmt *pStmt = 0;
    ++    rc = sqlite3_prepare_v2(p->dbv, zStmt, -1, &pStmt, &zStmt);
    ++    if( rc==SQLITE_OK ){
    ++      if( pStmt ){
    ++        IdxStatement *pNew;
    ++        const char *z = sqlite3_sql(pStmt);
    ++        int n = STRLEN(z);
    ++        pNew = (IdxStatement*)idxMalloc(&rc, sizeof(IdxStatement) + n+1);
    ++        if( rc==SQLITE_OK ){
    ++          pNew->zSql = (char*)&pNew[1];
    ++          memcpy(pNew->zSql, z, n+1);
    ++          pNew->pNext = p->pStatement;
    ++          if( p->pStatement ) pNew->iId = p->pStatement->iId+1;
    ++          p->pStatement = pNew;
    ++        }
    ++        sqlite3_finalize(pStmt);
    ++      }
    ++    }else{
    ++      idxDatabaseError(p->dbv, pzErr);
    ++    }
    ++  }
    ++
    ++  if( rc!=SQLITE_OK ){
    ++    idxScanFree(p->pScan, pScanOrig);
    ++    idxStatementFree(p->pStatement, pStmtOrig);
    ++    p->pScan = pScanOrig;
    ++    p->pStatement = pStmtOrig;
    ++  }
    ++
    ++  return rc;
    ++}
    ++
    ++int sqlite3_expert_analyze(sqlite3expert *p, char **pzErr){
    ++  int rc;
    ++  IdxHashEntry *pEntry;
    ++
    ++  /* Do trigger processing to collect any extra IdxScan structures */
    ++  rc = idxProcessTriggers(p, pzErr);
    ++
    ++  /* Create candidate indexes within the in-memory database file */
    ++  if( rc==SQLITE_OK ){
    ++    rc = idxCreateCandidates(p);
    ++  }
    ++
    ++  /* Generate the stat1 data */
    ++  if( rc==SQLITE_OK ){
    ++    rc = idxPopulateStat1(p, pzErr);
    ++  }
    ++
    ++  /* Formulate the EXPERT_REPORT_CANDIDATES text */
    ++  for(pEntry=p->hIdx.pFirst; pEntry; pEntry=pEntry->pNext){
    ++    p->zCandidates = idxAppendText(&rc, p->zCandidates, 
    ++        "%s;%s%s\n", pEntry->zVal, 
    ++        pEntry->zVal2 ? " -- stat1: " : "", pEntry->zVal2
    ++    );
    ++  }
    ++
    ++  /* Figure out which of the candidate indexes are preferred by the query
    ++  ** planner and report the results to the user.  */
    ++  if( rc==SQLITE_OK ){
    ++    rc = idxFindIndexes(p, pzErr);
    ++  }
    ++
    ++  if( rc==SQLITE_OK ){
    ++    p->bRun = 1;
    ++  }
    ++  return rc;
    ++}
    ++
    ++/*
    ++** Return the total number of statements that have been added to this
    ++** sqlite3expert using sqlite3_expert_sql().
    ++*/
    ++int sqlite3_expert_count(sqlite3expert *p){
    ++  int nRet = 0;
    ++  if( p->pStatement ) nRet = p->pStatement->iId+1;
    ++  return nRet;
    ++}
    ++
    ++/*
    ++** Return a component of the report.
    ++*/
    ++const char *sqlite3_expert_report(sqlite3expert *p, int iStmt, int eReport){
    ++  const char *zRet = 0;
    ++  IdxStatement *pStmt;
    ++
    ++  if( p->bRun==0 ) return 0;
    ++  for(pStmt=p->pStatement; pStmt && pStmt->iId!=iStmt; pStmt=pStmt->pNext);
    ++  switch( eReport ){
    ++    case EXPERT_REPORT_SQL:
    ++      if( pStmt ) zRet = pStmt->zSql;
    ++      break;
    ++    case EXPERT_REPORT_INDEXES:
    ++      if( pStmt ) zRet = pStmt->zIdx;
    ++      break;
    ++    case EXPERT_REPORT_PLAN:
    ++      if( pStmt ) zRet = pStmt->zEQP;
    ++      break;
    ++    case EXPERT_REPORT_CANDIDATES:
    ++      zRet = p->zCandidates;
    ++      break;
    ++  }
    ++  return zRet;
    ++}
    ++
    ++/*
    ++** Free an sqlite3expert object.
    ++*/
    ++void sqlite3_expert_destroy(sqlite3expert *p){
    ++  if( p ){
    ++    sqlite3_close(p->dbm);
    ++    sqlite3_close(p->dbv);
    ++    idxScanFree(p->pScan, 0);
    ++    idxStatementFree(p->pStatement, 0);
    ++    idxTableFree(p->pTable);
    ++    idxWriteFree(p->pWrite);
    ++    idxHashClear(&p->hIdx);
    ++    sqlite3_free(p->zCandidates);
    ++    sqlite3_free(p);
    ++  }
    ++}
    ++
    ++#endif /* ifndef SQLITE_OMIT_VIRTUAL_TABLE */
    ++
    ++/************************* End ../ext/expert/sqlite3expert.c ********************/
    ++
    ++#if defined(SQLITE_ENABLE_SESSION)
    ++/*
    ++** State information for a single open session
    ++*/
    ++typedef struct OpenSession OpenSession;
    ++struct OpenSession {
    ++  char *zName;             /* Symbolic name for this session */
    ++  int nFilter;             /* Number of xFilter rejection GLOB patterns */
    ++  char **azFilter;         /* Array of xFilter rejection GLOB patterns */
    ++  sqlite3_session *p;      /* The open session */
    ++};
    ++#endif
    ++
    ++/*
    ++** Shell output mode information from before ".explain on",
    ++** saved so that it can be restored by ".explain off"
    ++*/
    ++typedef struct SavedModeInfo SavedModeInfo;
    ++struct SavedModeInfo {
    ++  int valid;          /* Is there legit data in here? */
    ++  int mode;           /* Mode prior to ".explain on" */
    ++  int showHeader;     /* The ".header" setting prior to ".explain on" */
    ++  int colWidth[100];  /* Column widths prior to ".explain on" */
    ++};
    ++
    ++typedef struct ExpertInfo ExpertInfo;
    ++struct ExpertInfo {
    ++  sqlite3expert *pExpert;
    ++  int bVerbose;
    ++};
    ++
    ++/*
    ++** State information about the database connection is contained in an
    ++** instance of the following structure.
    ++*/
    ++typedef struct ShellState ShellState;
    ++struct ShellState {
    ++  sqlite3 *db;           /* The database */
    ++  u8 autoExplain;        /* Automatically turn on .explain mode */
    ++  u8 autoEQP;            /* Run EXPLAIN QUERY PLAN prior to seach SQL stmt */
    ++  u8 statsOn;            /* True to display memory stats before each finalize */
    ++  u8 scanstatsOn;        /* True to display scan stats before each finalize */
    ++  u8 openMode;           /* SHELL_OPEN_NORMAL, _APPENDVFS, or _ZIPFILE */
    ++  u8 doXdgOpen;          /* Invoke start/open/xdg-open in output_reset() */
    ++  int outCount;          /* Revert to stdout when reaching zero */
    ++  int cnt;               /* Number of records displayed so far */
    ++  FILE *out;             /* Write results here */
    ++  FILE *traceOut;        /* Output for sqlite3_trace() */
    ++  int nErr;              /* Number of errors seen */
    ++  int mode;              /* An output mode setting */
    ++  int modePrior;         /* Saved mode */
    ++  int cMode;             /* temporary output mode for the current query */
    ++  int normalMode;        /* Output mode before ".explain on" */
    ++  int writableSchema;    /* True if PRAGMA writable_schema=ON */
    ++  int showHeader;        /* True to show column names in List or Column mode */
    ++  int nCheck;            /* Number of ".check" commands run */
    ++  unsigned shellFlgs;    /* Various flags */
    ++  char *zDestTable;      /* Name of destination table when MODE_Insert */
    ++  char *zTempFile;       /* Temporary file that might need deleting */
    ++  char zTestcase[30];    /* Name of current test case */
    ++  char colSeparator[20]; /* Column separator character for several modes */
    ++  char rowSeparator[20]; /* Row separator character for MODE_Ascii */
    ++  char colSepPrior[20];  /* Saved column separator */
    ++  char rowSepPrior[20];  /* Saved row separator */
    ++  int colWidth[100];     /* Requested width of each column when in column mode*/
    ++  int actualWidth[100];  /* Actual width of each column */
    ++  char nullValue[20];    /* The text to print when a NULL comes back from
    ++                         ** the database */
    ++  char outfile[FILENAME_MAX]; /* Filename for *out */
    ++  const char *zDbFilename;    /* name of the database file */
    ++  char *zFreeOnClose;         /* Filename to free when closing */
    ++  const char *zVfs;           /* Name of VFS to use */
    ++  sqlite3_stmt *pStmt;   /* Current statement if any. */
    ++  FILE *pLog;            /* Write log output here */
    ++  int *aiIndent;         /* Array of indents used in MODE_Explain */
    ++  int nIndent;           /* Size of array aiIndent[] */
    ++  int iIndent;           /* Index of current op in aiIndent[] */
    ++#if defined(SQLITE_ENABLE_SESSION)
    ++  int nSession;             /* Number of active sessions */
    ++  OpenSession aSession[4];  /* Array of sessions.  [0] is in focus. */
    ++#endif
    ++  ExpertInfo expert;        /* Valid if previous command was ".expert OPT..." */
    ++};
    ++
    ++
    ++/* Allowed values for ShellState.autoEQP
    ++*/
    ++#define AUTOEQP_off      0
    ++#define AUTOEQP_on       1
    ++#define AUTOEQP_trigger  2
    ++#define AUTOEQP_full     3
    ++
    ++/* Allowed values for ShellState.openMode
    ++*/
    ++#define SHELL_OPEN_UNSPEC     0      /* No open-mode specified */
    ++#define SHELL_OPEN_NORMAL     1      /* Normal database file */
    ++#define SHELL_OPEN_APPENDVFS  2      /* Use appendvfs */
    ++#define SHELL_OPEN_ZIPFILE    3      /* Use the zipfile virtual table */
    ++
    ++/*
    ++** These are the allowed shellFlgs values
    ++*/
    ++#define SHFLG_Pagecache      0x00000001 /* The --pagecache option is used */
    ++#define SHFLG_Lookaside      0x00000002 /* Lookaside memory is used */
    ++#define SHFLG_Backslash      0x00000004 /* The --backslash option is used */
    ++#define SHFLG_PreserveRowid  0x00000008 /* .dump preserves rowid values */
    ++#define SHFLG_Newlines       0x00000010 /* .dump --newline flag */
    ++#define SHFLG_CountChanges   0x00000020 /* .changes setting */
    ++#define SHFLG_Echo           0x00000040 /* .echo or --echo setting */
    ++
    ++/*
    ++** Macros for testing and setting shellFlgs
    ++*/
    ++#define ShellHasFlag(P,X)    (((P)->shellFlgs & (X))!=0)
    ++#define ShellSetFlag(P,X)    ((P)->shellFlgs|=(X))
    ++#define ShellClearFlag(P,X)  ((P)->shellFlgs&=(~(X)))
    ++
    ++/*
    ++** These are the allowed modes.
    ++*/
    ++#define MODE_Line     0  /* One column per line.  Blank line between records */
    ++#define MODE_Column   1  /* One record per line in neat columns */
    ++#define MODE_List     2  /* One record per line with a separator */
    ++#define MODE_Semi     3  /* Same as MODE_List but append ";" to each line */
    ++#define MODE_Html     4  /* Generate an XHTML table */
    ++#define MODE_Insert   5  /* Generate SQL "insert" statements */
    ++#define MODE_Quote    6  /* Quote values as for SQL */
    ++#define MODE_Tcl      7  /* Generate ANSI-C or TCL quoted elements */
    ++#define MODE_Csv      8  /* Quote strings, numbers are plain */
    ++#define MODE_Explain  9  /* Like MODE_Column, but do not truncate data */
    ++#define MODE_Ascii   10  /* Use ASCII unit and record separators (0x1F/0x1E) */
    ++#define MODE_Pretty  11  /* Pretty-print schemas */
    ++
    ++static const char *modeDescr[] = {
    ++  "line",
    ++  "column",
    ++  "list",
    ++  "semi",
    ++  "html",
    ++  "insert",
    ++  "quote",
    ++  "tcl",
    ++  "csv",
    ++  "explain",
    ++  "ascii",
    ++  "prettyprint",
    ++};
    ++
    ++/*
    ++** These are the column/row/line separators used by the various
    ++** import/export modes.
    ++*/
    ++#define SEP_Column    "|"
    ++#define SEP_Row       "\n"
    ++#define SEP_Tab       "\t"
    ++#define SEP_Space     " "
    ++#define SEP_Comma     ","
    ++#define SEP_CrLf      "\r\n"
    ++#define SEP_Unit      "\x1F"
    ++#define SEP_Record    "\x1E"
    ++
    ++/*
    ++** A callback for the sqlite3_log() interface.
    ++*/
    ++static void shellLog(void *pArg, int iErrCode, const char *zMsg){
    ++  ShellState *p = (ShellState*)pArg;
    ++  if( p->pLog==0 ) return;
    ++  utf8_printf(p->pLog, "(%d) %s\n", iErrCode, zMsg);
    ++  fflush(p->pLog);
    ++}
    ++
    ++/*
    ++** SQL function:  shell_putsnl(X)
    ++**
    ++** Write the text X to the screen (or whatever output is being directed)
    ++** adding a newline at the end, and then return X.
    ++*/
    ++static void shellPutsFunc(
    ++  sqlite3_context *pCtx,
    ++  int nVal,
    ++  sqlite3_value **apVal
    ++){
    ++  ShellState *p = (ShellState*)sqlite3_user_data(pCtx);
    ++  (void)nVal;
    ++  utf8_printf(p->out, "%s\n", sqlite3_value_text(apVal[0]));
    ++  sqlite3_result_value(pCtx, apVal[0]);
    ++}
    ++
    ++/*
    ++** SQL function:   edit(VALUE)
    ++**                 edit(VALUE,EDITOR)
    ++**
    ++** These steps:
    ++**
    ++**     (1) Write VALUE into a temporary file.
    ++**     (2) Run program EDITOR on that temporary file.
    ++**     (3) Read the temporary file back and return its content as the result.
    ++**     (4) Delete the temporary file
    ++**
    ++** If the EDITOR argument is omitted, use the value in the VISUAL
    ++** environment variable.  If still there is no EDITOR, through an error.
    ++**
    ++** Also throw an error if the EDITOR program returns a non-zero exit code.
    ++*/
    ++static void editFunc(
    ++  sqlite3_context *context,
    ++  int argc,
    ++  sqlite3_value **argv
    ++){
    ++  const char *zEditor;
    ++  char *zTempFile = 0;
    ++  sqlite3 *db;
    ++  char *zCmd = 0;
    ++  int bBin;
    ++  int rc;
    ++  FILE *f = 0;
    ++  sqlite3_int64 sz;
    ++  sqlite3_int64 x;
    ++  unsigned char *p = 0;
    ++
    ++  if( argc==2 ){
    ++    zEditor = (const char*)sqlite3_value_text(argv[1]);
    ++  }else{
    ++    zEditor = getenv("VISUAL");
    ++  }
    ++  if( zEditor==0 ){
    ++    sqlite3_result_error(context, "no editor for edit()", -1);
    ++    return;
    ++  }
    ++  if( sqlite3_value_type(argv[0])==SQLITE_NULL ){
    ++    sqlite3_result_error(context, "NULL input to edit()", -1);
    ++    return;
    ++  }
    ++  db = sqlite3_context_db_handle(context);
    ++  zTempFile = 0;
    ++  sqlite3_file_control(db, 0, SQLITE_FCNTL_TEMPFILENAME, &zTempFile);
    ++  if( zTempFile==0 ){
    ++    sqlite3_uint64 r = 0;
    ++    sqlite3_randomness(sizeof(r), &r);
    ++    zTempFile = sqlite3_mprintf("temp%llx", r);
    ++    if( zTempFile==0 ){
    ++      sqlite3_result_error_nomem(context);
    ++      return;
    ++    }
    ++  }
    ++  bBin = sqlite3_value_type(argv[0])==SQLITE_BLOB;
    ++  f = fopen(zTempFile, bBin ? "wb" : "w");
    ++  if( f==0 ){
    ++    sqlite3_result_error(context, "edit() cannot open temp file", -1);
    ++    goto edit_func_end;
    ++  }
    ++  sz = sqlite3_value_bytes(argv[0]);
    ++  if( bBin ){
    ++    x = fwrite(sqlite3_value_blob(argv[0]), 1, sz, f);
    ++  }else{
    ++    x = fwrite(sqlite3_value_text(argv[0]), 1, sz, f);
    ++  }
    ++  fclose(f);
    ++  f = 0;
    ++  if( x!=sz ){
    ++    sqlite3_result_error(context, "edit() could not write the whole file", -1);
    ++    goto edit_func_end;
    ++  }
    ++  zCmd = sqlite3_mprintf("%s \"%s\"", zEditor, zTempFile);
    ++  if( zCmd==0 ){
    ++    sqlite3_result_error_nomem(context);
    ++    goto edit_func_end;
    ++  }
    ++  rc = system(zCmd);
    ++  sqlite3_free(zCmd);
    ++  if( rc ){
    ++    sqlite3_result_error(context, "EDITOR returned non-zero", -1);
    ++    goto edit_func_end;
    ++  }
    ++  f = fopen(zTempFile, bBin ? "rb" : "r");
    ++  if( f==0 ){
    ++    sqlite3_result_error(context,
    ++      "edit() cannot reopen temp file after edit", -1);
    ++    goto edit_func_end;
    ++  }
    ++  fseek(f, 0, SEEK_END);
    ++  sz = ftell(f);
    ++  rewind(f);
    ++  p = sqlite3_malloc64( sz+(bBin==0) );
    ++  if( p==0 ){
    ++    sqlite3_result_error_nomem(context);
    ++    goto edit_func_end;
    ++  }
    ++  if( bBin ){
    ++    x = fread(p, 1, sz, f);
    ++  }else{
    ++    x = fread(p, 1, sz, f);
    ++    p[sz] = 0;
    ++  }
    ++  fclose(f);
    ++  f = 0;
    ++  if( x!=sz ){
    ++    sqlite3_result_error(context, "could not read back the whole file", -1);
    ++    goto edit_func_end;
    ++  }
    ++  if( bBin ){
    ++    sqlite3_result_blob(context, p, sz, sqlite3_free);
    ++  }else{
    ++    sqlite3_result_text(context, (const char*)p, sz, sqlite3_free);
    ++  }
    ++  p = 0;
    ++
    ++edit_func_end:
    ++  if( f ) fclose(f);
    ++  unlink(zTempFile);
    ++  sqlite3_free(zTempFile);
    ++  sqlite3_free(p);
    ++}
    ++
    ++/*
    ++** Save or restore the current output mode
    ++*/
    ++static void outputModePush(ShellState *p){
    ++  p->modePrior = p->mode;
    ++  memcpy(p->colSepPrior, p->colSeparator, sizeof(p->colSeparator));
    ++  memcpy(p->rowSepPrior, p->rowSeparator, sizeof(p->rowSeparator));
    ++}
    ++static void outputModePop(ShellState *p){
    ++  p->mode = p->modePrior;
    ++  memcpy(p->colSeparator, p->colSepPrior, sizeof(p->colSeparator));
    ++  memcpy(p->rowSeparator, p->rowSepPrior, sizeof(p->rowSeparator));
    ++}
    ++
    ++/*
    ++** Output the given string as a hex-encoded blob (eg. X'1234' )
    ++*/
    ++static void output_hex_blob(FILE *out, const void *pBlob, int nBlob){
    ++  int i;
    ++  char *zBlob = (char *)pBlob;
    ++  raw_printf(out,"X'");
    ++  for(i=0; i<nBlob; i++){ raw_printf(out,"%02x",zBlob[i]&0xff); }
    ++  raw_printf(out,"'");
    ++}
    ++
    ++/*
    ++** Find a string that is not found anywhere in z[].  Return a pointer
    ++** to that string.
    ++**
    ++** Try to use zA and zB first.  If both of those are already found in z[]
    ++** then make up some string and store it in the buffer zBuf.
    ++*/
    ++static const char *unused_string(
    ++  const char *z,                    /* Result must not appear anywhere in z */
    ++  const char *zA, const char *zB,   /* Try these first */
    ++  char *zBuf                        /* Space to store a generated string */
    ++){
    ++  unsigned i = 0;
    ++  if( strstr(z, zA)==0 ) return zA;
    ++  if( strstr(z, zB)==0 ) return zB;
    ++  do{
    ++    sqlite3_snprintf(20,zBuf,"(%s%u)", zA, i++);
    ++  }while( strstr(z,zBuf)!=0 );
    ++  return zBuf;
    ++}
    ++
    ++/*
    ++** Output the given string as a quoted string using SQL quoting conventions.
    ++**
    ++** See also: output_quoted_escaped_string()
    ++*/
    ++static void output_quoted_string(FILE *out, const char *z){
    ++  int i;
    ++  char c;
    ++  setBinaryMode(out, 1);
    ++  for(i=0; (c = z[i])!=0 && c!='\''; i++){}
    ++  if( c==0 ){
    ++    utf8_printf(out,"'%s'",z);
    ++  }else{
    ++    raw_printf(out, "'");
    ++    while( *z ){
    ++      for(i=0; (c = z[i])!=0 && c!='\''; i++){}
    ++      if( c=='\'' ) i++;
    ++      if( i ){
    ++        utf8_printf(out, "%.*s", i, z);
    ++        z += i;
    ++      }
    ++      if( c=='\'' ){
    ++        raw_printf(out, "'");
    ++        continue;
    ++      }
    ++      if( c==0 ){
    ++        break;
    ++      }
    ++      z++;
    ++    }
    ++    raw_printf(out, "'");
    ++  }
    ++  setTextMode(out, 1);
    ++}
    ++
    ++/*
    ++** Output the given string as a quoted string using SQL quoting conventions.
    ++** Additionallly , escape the "\n" and "\r" characters so that they do not
    ++** get corrupted by end-of-line translation facilities in some operating
    ++** systems.
    ++**
    ++** This is like output_quoted_string() but with the addition of the \r\n
    ++** escape mechanism.
    ++*/
    ++static void output_quoted_escaped_string(FILE *out, const char *z){
    ++  int i;
    ++  char c;
    ++  setBinaryMode(out, 1);
    ++  for(i=0; (c = z[i])!=0 && c!='\'' && c!='\n' && c!='\r'; i++){}
    ++  if( c==0 ){
    ++    utf8_printf(out,"'%s'",z);
    ++  }else{
    ++    const char *zNL = 0;
    ++    const char *zCR = 0;
    ++    int nNL = 0;
    ++    int nCR = 0;
    ++    char zBuf1[20], zBuf2[20];
    ++    for(i=0; z[i]; i++){
    ++      if( z[i]=='\n' ) nNL++;
    ++      if( z[i]=='\r' ) nCR++;
    ++    }
    ++    if( nNL ){
    ++      raw_printf(out, "replace(");
    ++      zNL = unused_string(z, "\\n", "\\012", zBuf1);
    ++    }
    ++    if( nCR ){
    ++      raw_printf(out, "replace(");
    ++      zCR = unused_string(z, "\\r", "\\015", zBuf2);
    ++    }
    ++    raw_printf(out, "'");
    ++    while( *z ){
    ++      for(i=0; (c = z[i])!=0 && c!='\n' && c!='\r' && c!='\''; i++){}
    ++      if( c=='\'' ) i++;
    ++      if( i ){
    ++        utf8_printf(out, "%.*s", i, z);
    ++        z += i;
    ++      }
    ++      if( c=='\'' ){
    ++        raw_printf(out, "'");
    ++        continue;
    ++      }
    ++      if( c==0 ){
    ++        break;
    ++      }
    ++      z++;
    ++      if( c=='\n' ){
    ++        raw_printf(out, "%s", zNL);
    ++        continue;
    ++      }
    ++      raw_printf(out, "%s", zCR);
    ++    }
    ++    raw_printf(out, "'");
    ++    if( nCR ){
    ++      raw_printf(out, ",'%s',char(13))", zCR);
    ++    }
    ++    if( nNL ){
    ++      raw_printf(out, ",'%s',char(10))", zNL);
    ++    }
    ++  }
    ++  setTextMode(out, 1);
    ++}
    ++
    ++/*
    ++** Output the given string as a quoted according to C or TCL quoting rules.
    ++*/
    ++static void output_c_string(FILE *out, const char *z){
    ++  unsigned int c;
    ++  fputc('"', out);
    ++  while( (c = *(z++))!=0 ){
    ++    if( c=='\\' ){
    ++      fputc(c, out);
    ++      fputc(c, out);
    ++    }else if( c=='"' ){
    ++      fputc('\\', out);
    ++      fputc('"', out);
    ++    }else if( c=='\t' ){
    ++      fputc('\\', out);
    ++      fputc('t', out);
    ++    }else if( c=='\n' ){
    ++      fputc('\\', out);
    ++      fputc('n', out);
    ++    }else if( c=='\r' ){
    ++      fputc('\\', out);
    ++      fputc('r', out);
    ++    }else if( !isprint(c&0xff) ){
    ++      raw_printf(out, "\\%03o", c&0xff);
    ++    }else{
    ++      fputc(c, out);
    ++    }
    ++  }
    ++  fputc('"', out);
    ++}
    ++
    ++/*
    ++** Output the given string with characters that are special to
    ++** HTML escaped.
    ++*/
    ++static void output_html_string(FILE *out, const char *z){
    ++  int i;
    ++  if( z==0 ) z = "";
    ++  while( *z ){
    ++    for(i=0;   z[i]
    ++            && z[i]!='<'
    ++            && z[i]!='&'
    ++            && z[i]!='>'
    ++            && z[i]!='\"'
    ++            && z[i]!='\'';
    ++        i++){}
    ++    if( i>0 ){
    ++      utf8_printf(out,"%.*s",i,z);
    ++    }
    ++    if( z[i]=='<' ){
    ++      raw_printf(out,"&lt;");
    ++    }else if( z[i]=='&' ){
    ++      raw_printf(out,"&amp;");
    ++    }else if( z[i]=='>' ){
    ++      raw_printf(out,"&gt;");
    ++    }else if( z[i]=='\"' ){
    ++      raw_printf(out,"&quot;");
    ++    }else if( z[i]=='\'' ){
    ++      raw_printf(out,"&#39;");
    ++    }else{
    ++      break;
    ++    }
    ++    z += i + 1;
    ++  }
    ++}
    ++
    ++/*
    ++** If a field contains any character identified by a 1 in the following
    ++** array, then the string must be quoted for CSV.
    ++*/
    ++static const char needCsvQuote[] = {
    ++  1, 1, 1, 1, 1, 1, 1, 1,   1, 1, 1, 1, 1, 1, 1, 1,
    ++  1, 1, 1, 1, 1, 1, 1, 1,   1, 1, 1, 1, 1, 1, 1, 1,
    ++  1, 0, 1, 0, 0, 0, 0, 1,   0, 0, 0, 0, 0, 0, 0, 0,
    ++  0, 0, 0, 0, 0, 0, 0, 0,   0, 0, 0, 0, 0, 0, 0, 0,
    ++  0, 0, 0, 0, 0, 0, 0, 0,   0, 0, 0, 0, 0, 0, 0, 0,
    ++  0, 0, 0, 0, 0, 0, 0, 0,   0, 0, 0, 0, 0, 0, 0, 0,
    ++  0, 0, 0, 0, 0, 0, 0, 0,   0, 0, 0, 0, 0, 0, 0, 0,
    ++  0, 0, 0, 0, 0, 0, 0, 0,   0, 0, 0, 0, 0, 0, 0, 1,
    ++  1, 1, 1, 1, 1, 1, 1, 1,   1, 1, 1, 1, 1, 1, 1, 1,
    ++  1, 1, 1, 1, 1, 1, 1, 1,   1, 1, 1, 1, 1, 1, 1, 1,
    ++  1, 1, 1, 1, 1, 1, 1, 1,   1, 1, 1, 1, 1, 1, 1, 1,
    ++  1, 1, 1, 1, 1, 1, 1, 1,   1, 1, 1, 1, 1, 1, 1, 1,
    ++  1, 1, 1, 1, 1, 1, 1, 1,   1, 1, 1, 1, 1, 1, 1, 1,
    ++  1, 1, 1, 1, 1, 1, 1, 1,   1, 1, 1, 1, 1, 1, 1, 1,
    ++  1, 1, 1, 1, 1, 1, 1, 1,   1, 1, 1, 1, 1, 1, 1, 1,
    ++  1, 1, 1, 1, 1, 1, 1, 1,   1, 1, 1, 1, 1, 1, 1, 1,
    ++};
    ++
    ++/*
    ++** Output a single term of CSV.  Actually, p->colSeparator is used for
    ++** the separator, which may or may not be a comma.  p->nullValue is
    ++** the null value.  Strings are quoted if necessary.  The separator
    ++** is only issued if bSep is true.
    ++*/
    ++static void output_csv(ShellState *p, const char *z, int bSep){
    ++  FILE *out = p->out;
    ++  if( z==0 ){
    ++    utf8_printf(out,"%s",p->nullValue);
    ++  }else{
    ++    int i;
    ++    int nSep = strlen30(p->colSeparator);
    ++    for(i=0; z[i]; i++){
    ++      if( needCsvQuote[((unsigned char*)z)[i]]
    ++         || (z[i]==p->colSeparator[0] &&
    ++             (nSep==1 || memcmp(z, p->colSeparator, nSep)==0)) ){
    ++        i = 0;
    ++        break;
    ++      }
    ++    }
    ++    if( i==0 ){
    ++      char *zQuoted = sqlite3_mprintf("\"%w\"", z);
    ++      utf8_printf(out, "%s", zQuoted);
    ++      sqlite3_free(zQuoted);
    ++    }else{
    ++      utf8_printf(out, "%s", z);
    ++    }
    ++  }
    ++  if( bSep ){
    ++    utf8_printf(p->out, "%s", p->colSeparator);
    ++  }
    ++}
    ++
    ++/*
    ++** This routine runs when the user presses Ctrl-C
    ++*/
    ++static void interrupt_handler(int NotUsed){
    ++  UNUSED_PARAMETER(NotUsed);
    ++  seenInterrupt++;
    ++  if( seenInterrupt>2 ) exit(1);
    ++  if( globalDb ) sqlite3_interrupt(globalDb);
    ++}
    ++
    ++#if (defined(_WIN32) || defined(WIN32)) && !defined(_WIN32_WCE)
    ++/*
    ++** This routine runs for console events (e.g. Ctrl-C) on Win32
    ++*/
    ++static BOOL WINAPI ConsoleCtrlHandler(
    ++  DWORD dwCtrlType /* One of the CTRL_*_EVENT constants */
    ++){
    ++  if( dwCtrlType==CTRL_C_EVENT ){
    ++    interrupt_handler(0);
    ++    return TRUE;
    ++  }
    ++  return FALSE;
    ++}
    ++#endif
    ++
    ++#ifndef SQLITE_OMIT_AUTHORIZATION
    ++/*
    ++** When the ".auth ON" is set, the following authorizer callback is
    ++** invoked.  It always returns SQLITE_OK.
    ++*/
    ++static int shellAuth(
    ++  void *pClientData,
    ++  int op,
    ++  const char *zA1,
    ++  const char *zA2,
    ++  const char *zA3,
    ++  const char *zA4
    ++){
    ++  ShellState *p = (ShellState*)pClientData;
    ++  static const char *azAction[] = { 0,
    ++     "CREATE_INDEX",         "CREATE_TABLE",         "CREATE_TEMP_INDEX",
    ++     "CREATE_TEMP_TABLE",    "CREATE_TEMP_TRIGGER",  "CREATE_TEMP_VIEW",
    ++     "CREATE_TRIGGER",       "CREATE_VIEW",          "DELETE",
    ++     "DROP_INDEX",           "DROP_TABLE",           "DROP_TEMP_INDEX",
    ++     "DROP_TEMP_TABLE",      "DROP_TEMP_TRIGGER",    "DROP_TEMP_VIEW",
    ++     "DROP_TRIGGER",         "DROP_VIEW",            "INSERT",
    ++     "PRAGMA",               "READ",                 "SELECT",
    ++     "TRANSACTION",          "UPDATE",               "ATTACH",
    ++     "DETACH",               "ALTER_TABLE",          "REINDEX",
    ++     "ANALYZE",              "CREATE_VTABLE",        "DROP_VTABLE",
    ++     "FUNCTION",             "SAVEPOINT",            "RECURSIVE"
    ++  };
    ++  int i;
    ++  const char *az[4];
    ++  az[0] = zA1;
    ++  az[1] = zA2;
    ++  az[2] = zA3;
    ++  az[3] = zA4;
    ++  utf8_printf(p->out, "authorizer: %s", azAction[op]);
    ++  for(i=0; i<4; i++){
    ++    raw_printf(p->out, " ");
    ++    if( az[i] ){
    ++      output_c_string(p->out, az[i]);
    ++    }else{
    ++      raw_printf(p->out, "NULL");
    ++    }
    ++  }
    ++  raw_printf(p->out, "\n");
    ++  return SQLITE_OK;
    ++}
    ++#endif
    ++
    ++/*
    ++** Print a schema statement.  Part of MODE_Semi and MODE_Pretty output.
    ++**
    ++** This routine converts some CREATE TABLE statements for shadow tables
    ++** in FTS3/4/5 into CREATE TABLE IF NOT EXISTS statements.
    ++*/
    ++static void printSchemaLine(FILE *out, const char *z, const char *zTail){
    ++  if( sqlite3_strglob("CREATE TABLE ['\"]*", z)==0 ){
    ++    utf8_printf(out, "CREATE TABLE IF NOT EXISTS %s%s", z+13, zTail);
    ++  }else{
    ++    utf8_printf(out, "%s%s", z, zTail);
    ++  }
    ++}
    ++static void printSchemaLineN(FILE *out, char *z, int n, const char *zTail){
    ++  char c = z[n];
    ++  z[n] = 0;
    ++  printSchemaLine(out, z, zTail);
    ++  z[n] = c;
    ++}
    ++
    ++/*
    ++** Return true if string z[] has nothing but whitespace and comments to the
    ++** end of the first line.
    ++*/
    ++static int wsToEol(const char *z){
    ++  int i;
    ++  for(i=0; z[i]; i++){
    ++    if( z[i]=='\n' ) return 1;
    ++    if( IsSpace(z[i]) ) continue;
    ++    if( z[i]=='-' && z[i+1]=='-' ) return 1;
    ++    return 0;
    ++  }
    ++  return 1;
    ++}
    ++    
    ++
    ++/*
    ++** This is the callback routine that the shell
    ++** invokes for each row of a query result.
    ++*/
    ++static int shell_callback(
    ++  void *pArg,
    ++  int nArg,        /* Number of result columns */
    ++  char **azArg,    /* Text of each result column */
    ++  char **azCol,    /* Column names */
    ++  int *aiType      /* Column types */
    ++){
    ++  int i;
    ++  ShellState *p = (ShellState*)pArg;
    ++
    ++  if( azArg==0 ) return 0;
    ++  switch( p->cMode ){
    ++    case MODE_Line: {
    ++      int w = 5;
    ++      if( azArg==0 ) break;
    ++      for(i=0; i<nArg; i++){
    ++        int len = strlen30(azCol[i] ? azCol[i] : "");
    ++        if( len>w ) w = len;
    ++      }
    ++      if( p->cnt++>0 ) utf8_printf(p->out, "%s", p->rowSeparator);
    ++      for(i=0; i<nArg; i++){
    ++        utf8_printf(p->out,"%*s = %s%s", w, azCol[i],
    ++                azArg[i] ? azArg[i] : p->nullValue, p->rowSeparator);
    ++      }
    ++      break;
    ++    }
    ++    case MODE_Explain:
    ++    case MODE_Column: {
    ++      static const int aExplainWidths[] = {4, 13, 4, 4, 4, 13, 2, 13};
    ++      const int *colWidth;
    ++      int showHdr;
    ++      char *rowSep;
    ++      if( p->cMode==MODE_Column ){
    ++        colWidth = p->colWidth;
    ++        showHdr = p->showHeader;
    ++        rowSep = p->rowSeparator;
    ++      }else{
    ++        colWidth = aExplainWidths;
    ++        showHdr = 1;
    ++        rowSep = SEP_Row;
    ++      }
    ++      if( p->cnt++==0 ){
    ++        for(i=0; i<nArg; i++){
    ++          int w, n;
    ++          if( i<ArraySize(p->colWidth) ){
    ++            w = colWidth[i];
    ++          }else{
    ++            w = 0;
    ++          }
    ++          if( w==0 ){
    ++            w = strlenChar(azCol[i] ? azCol[i] : "");
    ++            if( w<10 ) w = 10;
    ++            n = strlenChar(azArg && azArg[i] ? azArg[i] : p->nullValue);
    ++            if( w<n ) w = n;
    ++          }
    ++          if( i<ArraySize(p->actualWidth) ){
    ++            p->actualWidth[i] = w;
    ++          }
    ++          if( showHdr ){
    ++            utf8_width_print(p->out, w, azCol[i]);
    ++            utf8_printf(p->out, "%s", i==nArg-1 ? rowSep : "  ");
    ++          }
    ++        }
    ++        if( showHdr ){
    ++          for(i=0; i<nArg; i++){
    ++            int w;
    ++            if( i<ArraySize(p->actualWidth) ){
    ++               w = p->actualWidth[i];
    ++               if( w<0 ) w = -w;
    ++            }else{
    ++               w = 10;
    ++            }
    ++            utf8_printf(p->out,"%-*.*s%s",w,w,
    ++                   "----------------------------------------------------------"
    ++                   "----------------------------------------------------------",
    ++                    i==nArg-1 ? rowSep : "  ");
    ++          }
    ++        }
    ++      }
    ++      if( azArg==0 ) break;
    ++      for(i=0; i<nArg; i++){
    ++        int w;
    ++        if( i<ArraySize(p->actualWidth) ){
    ++           w = p->actualWidth[i];
    ++        }else{
    ++           w = 10;
    ++        }
    ++        if( p->cMode==MODE_Explain && azArg[i] && strlenChar(azArg[i])>w ){
    ++          w = strlenChar(azArg[i]);
    ++        }
    ++        if( i==1 && p->aiIndent && p->pStmt ){
    ++          if( p->iIndent<p->nIndent ){
    ++            utf8_printf(p->out, "%*.s", p->aiIndent[p->iIndent], "");
    ++          }
    ++          p->iIndent++;
    ++        }
    ++        utf8_width_print(p->out, w, azArg[i] ? azArg[i] : p->nullValue);
    ++        utf8_printf(p->out, "%s", i==nArg-1 ? rowSep : "  ");
    ++      }
    ++      break;
    ++    }
    ++    case MODE_Semi: {   /* .schema and .fullschema output */
    ++      printSchemaLine(p->out, azArg[0], ";\n");
    ++      break;
    ++    }
    ++    case MODE_Pretty: {  /* .schema and .fullschema with --indent */
    ++      char *z;
    ++      int j;
    ++      int nParen = 0;
    ++      char cEnd = 0;
    ++      char c;
    ++      int nLine = 0;
    ++      assert( nArg==1 );
    ++      if( azArg[0]==0 ) break;
    ++      if( sqlite3_strlike("CREATE VIEW%", azArg[0], 0)==0
    ++       || sqlite3_strlike("CREATE TRIG%", azArg[0], 0)==0
    ++      ){
    ++        utf8_printf(p->out, "%s;\n", azArg[0]);
    ++        break;
    ++      }
    ++      z = sqlite3_mprintf("%s", azArg[0]);
    ++      j = 0;
    ++      for(i=0; IsSpace(z[i]); i++){}
    ++      for(; (c = z[i])!=0; i++){
    ++        if( IsSpace(c) ){
    ++          if( z[j-1]=='\r' ) z[j-1] = '\n';
    ++          if( IsSpace(z[j-1]) || z[j-1]=='(' ) continue;
    ++        }else if( (c=='(' || c==')') && j>0 && IsSpace(z[j-1]) ){
    ++          j--;
    ++        }
    ++        z[j++] = c;
    ++      }
    ++      while( j>0 && IsSpace(z[j-1]) ){ j--; }
    ++      z[j] = 0;
    ++      if( strlen30(z)>=79 ){
    ++        for(i=j=0; (c = z[i])!=0; i++){  /* Copy changes from z[i] back to z[j] */
    ++          if( c==cEnd ){
    ++            cEnd = 0;
    ++          }else if( c=='"' || c=='\'' || c=='`' ){
    ++            cEnd = c;
    ++          }else if( c=='[' ){
    ++            cEnd = ']';
    ++          }else if( c=='-' && z[i+1]=='-' ){
    ++            cEnd = '\n';
    ++          }else if( c=='(' ){
    ++            nParen++;
    ++          }else if( c==')' ){
    ++            nParen--;
    ++            if( nLine>0 && nParen==0 && j>0 ){
    ++              printSchemaLineN(p->out, z, j, "\n");
    ++              j = 0;
    ++            }
    ++          }
    ++          z[j++] = c;
    ++          if( nParen==1 && cEnd==0
    ++           && (c=='(' || c=='\n' || (c==',' && !wsToEol(z+i+1)))
    ++          ){
    ++            if( c=='\n' ) j--;
    ++            printSchemaLineN(p->out, z, j, "\n  ");
    ++            j = 0;
    ++            nLine++;
    ++            while( IsSpace(z[i+1]) ){ i++; }
    ++          }
    ++        }
    ++        z[j] = 0;
    ++      }
    ++      printSchemaLine(p->out, z, ";\n");
    ++      sqlite3_free(z);
    ++      break;
    ++    }
    ++    case MODE_List: {
    ++      if( p->cnt++==0 && p->showHeader ){
    ++        for(i=0; i<nArg; i++){
    ++          utf8_printf(p->out,"%s%s",azCol[i],
    ++                  i==nArg-1 ? p->rowSeparator : p->colSeparator);
    ++        }
    ++      }
    ++      if( azArg==0 ) break;
    ++      for(i=0; i<nArg; i++){
    ++        char *z = azArg[i];
    ++        if( z==0 ) z = p->nullValue;
    ++        utf8_printf(p->out, "%s", z);
    ++        if( i<nArg-1 ){
    ++          utf8_printf(p->out, "%s", p->colSeparator);
    ++        }else{
    ++          utf8_printf(p->out, "%s", p->rowSeparator);
    ++        }
    ++      }
    ++      break;
    ++    }
    ++    case MODE_Html: {
    ++      if( p->cnt++==0 && p->showHeader ){
    ++        raw_printf(p->out,"<TR>");
    ++        for(i=0; i<nArg; i++){
    ++          raw_printf(p->out,"<TH>");
    ++          output_html_string(p->out, azCol[i]);
    ++          raw_printf(p->out,"</TH>\n");
    ++        }
    ++        raw_printf(p->out,"</TR>\n");
    ++      }
    ++      if( azArg==0 ) break;
    ++      raw_printf(p->out,"<TR>");
    ++      for(i=0; i<nArg; i++){
    ++        raw_printf(p->out,"<TD>");
    ++        output_html_string(p->out, azArg[i] ? azArg[i] : p->nullValue);
    ++        raw_printf(p->out,"</TD>\n");
    ++      }
    ++      raw_printf(p->out,"</TR>\n");
    ++      break;
    ++    }
    ++    case MODE_Tcl: {
    ++      if( p->cnt++==0 && p->showHeader ){
    ++        for(i=0; i<nArg; i++){
    ++          output_c_string(p->out,azCol[i] ? azCol[i] : "");
    ++          if(i<nArg-1) utf8_printf(p->out, "%s", p->colSeparator);
    ++        }
    ++        utf8_printf(p->out, "%s", p->rowSeparator);
    ++      }
    ++      if( azArg==0 ) break;
    ++      for(i=0; i<nArg; i++){
    ++        output_c_string(p->out, azArg[i] ? azArg[i] : p->nullValue);
    ++        if(i<nArg-1) utf8_printf(p->out, "%s", p->colSeparator);
    ++      }
    ++      utf8_printf(p->out, "%s", p->rowSeparator);
    ++      break;
    ++    }
    ++    case MODE_Csv: {
    ++      setBinaryMode(p->out, 1);
    ++      if( p->cnt++==0 && p->showHeader ){
    ++        for(i=0; i<nArg; i++){
    ++          output_csv(p, azCol[i] ? azCol[i] : "", i<nArg-1);
    ++        }
    ++        utf8_printf(p->out, "%s", p->rowSeparator);
    ++      }
    ++      if( nArg>0 ){
    ++        for(i=0; i<nArg; i++){
    ++          output_csv(p, azArg[i], i<nArg-1);
    ++        }
    ++        utf8_printf(p->out, "%s", p->rowSeparator);
    ++      }
    ++      setTextMode(p->out, 1);
    ++      break;
    ++    }
    ++    case MODE_Insert: {
    ++      if( azArg==0 ) break;
    ++      utf8_printf(p->out,"INSERT INTO %s",p->zDestTable);
    ++      if( p->showHeader ){
    ++        raw_printf(p->out,"(");
    ++        for(i=0; i<nArg; i++){
    ++          if( i>0 ) raw_printf(p->out, ",");
    ++          if( quoteChar(azCol[i]) ){
    ++            char *z = sqlite3_mprintf("\"%w\"", azCol[i]);
    ++            utf8_printf(p->out, "%s", z);
    ++            sqlite3_free(z);
    ++          }else{
    ++            raw_printf(p->out, "%s", azCol[i]);
    ++          }
    ++        }
    ++        raw_printf(p->out,")");
    ++      }
    ++      p->cnt++;
    ++      for(i=0; i<nArg; i++){
    ++        raw_printf(p->out, i>0 ? "," : " VALUES(");
    ++        if( (azArg[i]==0) || (aiType && aiType[i]==SQLITE_NULL) ){
    ++          utf8_printf(p->out,"NULL");
    ++        }else if( aiType && aiType[i]==SQLITE_TEXT ){
    ++          if( ShellHasFlag(p, SHFLG_Newlines) ){
    ++            output_quoted_string(p->out, azArg[i]);
    ++          }else{
    ++            output_quoted_escaped_string(p->out, azArg[i]);
    ++          }
    ++        }else if( aiType && aiType[i]==SQLITE_INTEGER ){
    ++          utf8_printf(p->out,"%s", azArg[i]);
    ++        }else if( aiType && aiType[i]==SQLITE_FLOAT ){
    ++          char z[50];
    ++          double r = sqlite3_column_double(p->pStmt, i);
    ++          sqlite3_snprintf(50,z,"%!.20g", r);
    ++          raw_printf(p->out, "%s", z);
    ++        }else if( aiType && aiType[i]==SQLITE_BLOB && p->pStmt ){
    ++          const void *pBlob = sqlite3_column_blob(p->pStmt, i);
    ++          int nBlob = sqlite3_column_bytes(p->pStmt, i);
    ++          output_hex_blob(p->out, pBlob, nBlob);
    ++        }else if( isNumber(azArg[i], 0) ){
    ++          utf8_printf(p->out,"%s", azArg[i]);
    ++        }else if( ShellHasFlag(p, SHFLG_Newlines) ){
    ++          output_quoted_string(p->out, azArg[i]);
    ++        }else{
    ++          output_quoted_escaped_string(p->out, azArg[i]);
    ++        }
    ++      }
    ++      raw_printf(p->out,");\n");
    ++      break;
    ++    }
    ++    case MODE_Quote: {
    ++      if( azArg==0 ) break;
    ++      if( p->cnt==0 && p->showHeader ){
    ++        for(i=0; i<nArg; i++){
    ++          if( i>0 ) raw_printf(p->out, ",");
    ++          output_quoted_string(p->out, azCol[i]);
    ++        }
    ++        raw_printf(p->out,"\n");
    ++      }
    ++      p->cnt++;
    ++      for(i=0; i<nArg; i++){
    ++        if( i>0 ) raw_printf(p->out, ",");
    ++        if( (azArg[i]==0) || (aiType && aiType[i]==SQLITE_NULL) ){
    ++          utf8_printf(p->out,"NULL");
    ++        }else if( aiType && aiType[i]==SQLITE_TEXT ){
    ++          output_quoted_string(p->out, azArg[i]);
    ++        }else if( aiType && aiType[i]==SQLITE_INTEGER ){
    ++          utf8_printf(p->out,"%s", azArg[i]);
    ++        }else if( aiType && aiType[i]==SQLITE_FLOAT ){
    ++          char z[50];
    ++          double r = sqlite3_column_double(p->pStmt, i);
    ++          sqlite3_snprintf(50,z,"%!.20g", r);
    ++          raw_printf(p->out, "%s", z);
    ++        }else if( aiType && aiType[i]==SQLITE_BLOB && p->pStmt ){
    ++          const void *pBlob = sqlite3_column_blob(p->pStmt, i);
    ++          int nBlob = sqlite3_column_bytes(p->pStmt, i);
    ++          output_hex_blob(p->out, pBlob, nBlob);
    ++        }else if( isNumber(azArg[i], 0) ){
    ++          utf8_printf(p->out,"%s", azArg[i]);
    ++        }else{
    ++          output_quoted_string(p->out, azArg[i]);
    ++        }
    ++      }
    ++      raw_printf(p->out,"\n");
    ++      break;
    ++    }
    ++    case MODE_Ascii: {
    ++      if( p->cnt++==0 && p->showHeader ){
    ++        for(i=0; i<nArg; i++){
    ++          if( i>0 ) utf8_printf(p->out, "%s", p->colSeparator);
    ++          utf8_printf(p->out,"%s",azCol[i] ? azCol[i] : "");
    ++        }
    ++        utf8_printf(p->out, "%s", p->rowSeparator);
    ++      }
    ++      if( azArg==0 ) break;
    ++      for(i=0; i<nArg; i++){
    ++        if( i>0 ) utf8_printf(p->out, "%s", p->colSeparator);
    ++        utf8_printf(p->out,"%s",azArg[i] ? azArg[i] : p->nullValue);
    ++      }
    ++      utf8_printf(p->out, "%s", p->rowSeparator);
    ++      break;
    ++    }
    ++  }
    ++  return 0;
    ++}
    ++
    ++/*
    ++** This is the callback routine that the SQLite library
    ++** invokes for each row of a query result.
    ++*/
    ++static int callback(void *pArg, int nArg, char **azArg, char **azCol){
    ++  /* since we don't have type info, call the shell_callback with a NULL value */
    ++  return shell_callback(pArg, nArg, azArg, azCol, NULL);
    ++}
    ++
    ++/*
    ++** This is the callback routine from sqlite3_exec() that appends all
    ++** output onto the end of a ShellText object.
    ++*/
    ++static int captureOutputCallback(void *pArg, int nArg, char **azArg, char **az){
    ++  ShellText *p = (ShellText*)pArg;
    ++  int i;
    ++  UNUSED_PARAMETER(az);
    ++  if( azArg==0 ) return 0;
    ++  if( p->n ) appendText(p, "|", 0);
    ++  for(i=0; i<nArg; i++){
    ++    if( i ) appendText(p, ",", 0);
    ++    if( azArg[i] ) appendText(p, azArg[i], 0);
    ++  }
    ++  return 0;
    ++}
    ++
    ++/*
    ++** Generate an appropriate SELFTEST table in the main database.
    ++*/
    ++static void createSelftestTable(ShellState *p){
    ++  char *zErrMsg = 0;
    ++  sqlite3_exec(p->db,
    ++    "SAVEPOINT selftest_init;\n"
    ++    "CREATE TABLE IF NOT EXISTS selftest(\n"
    ++    "  tno INTEGER PRIMARY KEY,\n"   /* Test number */
    ++    "  op TEXT,\n"                   /* Operator:  memo run */
    ++    "  cmd TEXT,\n"                  /* Command text */
    ++    "  ans TEXT\n"                   /* Desired answer */
    ++    ");"
    ++    "CREATE TEMP TABLE [_shell$self](op,cmd,ans);\n"
    ++    "INSERT INTO [_shell$self](rowid,op,cmd)\n"
    ++    "  VALUES(coalesce((SELECT (max(tno)+100)/10 FROM selftest),10),\n"
    ++    "         'memo','Tests generated by --init');\n"
    ++    "INSERT INTO [_shell$self]\n"
    ++    "  SELECT 'run',\n"
    ++    "    'SELECT hex(sha3_query(''SELECT type,name,tbl_name,sql "
    ++                                 "FROM sqlite_master ORDER BY 2'',224))',\n"
    ++    "    hex(sha3_query('SELECT type,name,tbl_name,sql "
    ++                          "FROM sqlite_master ORDER BY 2',224));\n"
    ++    "INSERT INTO [_shell$self]\n"
    ++    "  SELECT 'run',"
    ++    "    'SELECT hex(sha3_query(''SELECT * FROM \"' ||"
    ++    "        printf('%w',name) || '\" NOT INDEXED'',224))',\n"
    ++    "    hex(sha3_query(printf('SELECT * FROM \"%w\" NOT INDEXED',name),224))\n"
    ++    "  FROM (\n"
    ++    "    SELECT name FROM sqlite_master\n"
    ++    "     WHERE type='table'\n"
    ++    "       AND name<>'selftest'\n"
    ++    "       AND coalesce(rootpage,0)>0\n"
    ++    "  )\n"
    ++    " ORDER BY name;\n"
    ++    "INSERT INTO [_shell$self]\n"
    ++    "  VALUES('run','PRAGMA integrity_check','ok');\n"
    ++    "INSERT INTO selftest(tno,op,cmd,ans)"
    ++    "  SELECT rowid*10,op,cmd,ans FROM [_shell$self];\n"
    ++    "DROP TABLE [_shell$self];"
    ++    ,0,0,&zErrMsg);
    ++  if( zErrMsg ){
    ++    utf8_printf(stderr, "SELFTEST initialization failure: %s\n", zErrMsg);
    ++    sqlite3_free(zErrMsg);
    ++  }
    ++  sqlite3_exec(p->db, "RELEASE selftest_init",0,0,0);
    ++}
    ++
    ++
    ++/*
    ++** Set the destination table field of the ShellState structure to
    ++** the name of the table given.  Escape any quote characters in the
    ++** table name.
    ++*/
    ++static void set_table_name(ShellState *p, const char *zName){
    ++  int i, n;
    ++  char cQuote;
    ++  char *z;
    ++
    ++  if( p->zDestTable ){
    ++    free(p->zDestTable);
    ++    p->zDestTable = 0;
    ++  }
    ++  if( zName==0 ) return;
    ++  cQuote = quoteChar(zName);
    ++  n = strlen30(zName);
    ++  if( cQuote ) n += n+2;
    ++  z = p->zDestTable = malloc( n+1 );
    ++  if( z==0 ){
    ++    raw_printf(stderr,"Error: out of memory\n");
    ++    exit(1);
    ++  }
    ++  n = 0;
    ++  if( cQuote ) z[n++] = cQuote;
    ++  for(i=0; zName[i]; i++){
    ++    z[n++] = zName[i];
    ++    if( zName[i]==cQuote ) z[n++] = cQuote;
    ++  }
    ++  if( cQuote ) z[n++] = cQuote;
    ++  z[n] = 0;
    ++}
    ++
    ++
    ++/*
    ++** Execute a query statement that will generate SQL output.  Print
    ++** the result columns, comma-separated, on a line and then add a
    ++** semicolon terminator to the end of that line.
    ++**
    ++** If the number of columns is 1 and that column contains text "--"
    ++** then write the semicolon on a separate line.  That way, if a
    ++** "--" comment occurs at the end of the statement, the comment
    ++** won't consume the semicolon terminator.
    ++*/
    ++static int run_table_dump_query(
    ++  ShellState *p,           /* Query context */
    ++  const char *zSelect,     /* SELECT statement to extract content */
    ++  const char *zFirstRow    /* Print before first row, if not NULL */
    ++){
    ++  sqlite3_stmt *pSelect;
    ++  int rc;
    ++  int nResult;
    ++  int i;
    ++  const char *z;
    ++  rc = sqlite3_prepare_v2(p->db, zSelect, -1, &pSelect, 0);
    ++  if( rc!=SQLITE_OK || !pSelect ){
    ++    utf8_printf(p->out, "/**** ERROR: (%d) %s *****/\n", rc,
    ++                sqlite3_errmsg(p->db));
    ++    if( (rc&0xff)!=SQLITE_CORRUPT ) p->nErr++;
    ++    return rc;
    ++  }
    ++  rc = sqlite3_step(pSelect);
    ++  nResult = sqlite3_column_count(pSelect);
    ++  while( rc==SQLITE_ROW ){
    ++    if( zFirstRow ){
    ++      utf8_printf(p->out, "%s", zFirstRow);
    ++      zFirstRow = 0;
    ++    }
    ++    z = (const char*)sqlite3_column_text(pSelect, 0);
    ++    utf8_printf(p->out, "%s", z);
    ++    for(i=1; i<nResult; i++){
    ++      utf8_printf(p->out, ",%s", sqlite3_column_text(pSelect, i));
    ++    }
    ++    if( z==0 ) z = "";
    ++    while( z[0] && (z[0]!='-' || z[1]!='-') ) z++;
    ++    if( z[0] ){
    ++      raw_printf(p->out, "\n;\n");
    ++    }else{
    ++      raw_printf(p->out, ";\n");
    ++    }
    ++    rc = sqlite3_step(pSelect);
    ++  }
    ++  rc = sqlite3_finalize(pSelect);
    ++  if( rc!=SQLITE_OK ){
    ++    utf8_printf(p->out, "/**** ERROR: (%d) %s *****/\n", rc,
    ++                sqlite3_errmsg(p->db));
    ++    if( (rc&0xff)!=SQLITE_CORRUPT ) p->nErr++;
    ++  }
    ++  return rc;
    ++}
    ++
    ++/*
    ++** Allocate space and save off current error string.
    ++*/
    ++static char *save_err_msg(
    ++  sqlite3 *db            /* Database to query */
    ++){
    ++  int nErrMsg = 1+strlen30(sqlite3_errmsg(db));
    ++  char *zErrMsg = sqlite3_malloc64(nErrMsg);
    ++  if( zErrMsg ){
    ++    memcpy(zErrMsg, sqlite3_errmsg(db), nErrMsg);
    ++  }
    ++  return zErrMsg;
    ++}
    ++
    ++#ifdef __linux__
    ++/*
    ++** Attempt to display I/O stats on Linux using /proc/PID/io
    ++*/
    ++static void displayLinuxIoStats(FILE *out){
    ++  FILE *in;
    ++  char z[200];
    ++  sqlite3_snprintf(sizeof(z), z, "/proc/%d/io", getpid());
    ++  in = fopen(z, "rb");
    ++  if( in==0 ) return;
    ++  while( fgets(z, sizeof(z), in)!=0 ){
    ++    static const struct {
    ++      const char *zPattern;
    ++      const char *zDesc;
    ++    } aTrans[] = {
    ++      { "rchar: ",                  "Bytes received by read():" },
    ++      { "wchar: ",                  "Bytes sent to write():"    },
    ++      { "syscr: ",                  "Read() system calls:"      },
    ++      { "syscw: ",                  "Write() system calls:"     },
    ++      { "read_bytes: ",             "Bytes read from storage:"  },
    ++      { "write_bytes: ",            "Bytes written to storage:" },
    ++      { "cancelled_write_bytes: ",  "Cancelled write bytes:"    },
    ++    };
    ++    int i;
    ++    for(i=0; i<ArraySize(aTrans); i++){
    ++      int n = strlen30(aTrans[i].zPattern);
    ++      if( strncmp(aTrans[i].zPattern, z, n)==0 ){
    ++        utf8_printf(out, "%-36s %s", aTrans[i].zDesc, &z[n]);
    ++        break;
    ++      }
    ++    }
    ++  }
    ++  fclose(in);
    ++}
    ++#endif
    ++
    ++/*
    ++** Display a single line of status using 64-bit values.
    ++*/
    ++static void displayStatLine(
    ++  ShellState *p,            /* The shell context */
    ++  char *zLabel,             /* Label for this one line */
    ++  char *zFormat,            /* Format for the result */
    ++  int iStatusCtrl,          /* Which status to display */
    ++  int bReset                /* True to reset the stats */
    ++){
    ++  sqlite3_int64 iCur = -1;
    ++  sqlite3_int64 iHiwtr = -1;
    ++  int i, nPercent;
    ++  char zLine[200];
    ++  sqlite3_status64(iStatusCtrl, &iCur, &iHiwtr, bReset);
    ++  for(i=0, nPercent=0; zFormat[i]; i++){
    ++    if( zFormat[i]=='%' ) nPercent++;
    ++  }
    ++  if( nPercent>1 ){
    ++    sqlite3_snprintf(sizeof(zLine), zLine, zFormat, iCur, iHiwtr);
    ++  }else{
    ++    sqlite3_snprintf(sizeof(zLine), zLine, zFormat, iHiwtr);
    ++  }
    ++  raw_printf(p->out, "%-36s %s\n", zLabel, zLine);
    ++}
    ++
    ++/*
    ++** Display memory stats.
    ++*/
    ++static int display_stats(
    ++  sqlite3 *db,                /* Database to query */
    ++  ShellState *pArg,           /* Pointer to ShellState */
    ++  int bReset                  /* True to reset the stats */
    ++){
    ++  int iCur;
    ++  int iHiwtr;
    ++
    ++  if( pArg && pArg->out ){
    ++    displayStatLine(pArg, "Memory Used:",
    ++       "%lld (max %lld) bytes", SQLITE_STATUS_MEMORY_USED, bReset);
    ++    displayStatLine(pArg, "Number of Outstanding Allocations:",
    ++       "%lld (max %lld)", SQLITE_STATUS_MALLOC_COUNT, bReset);
    ++    if( pArg->shellFlgs & SHFLG_Pagecache ){
    ++      displayStatLine(pArg, "Number of Pcache Pages Used:",
    ++         "%lld (max %lld) pages", SQLITE_STATUS_PAGECACHE_USED, bReset);
    ++    }
    ++    displayStatLine(pArg, "Number of Pcache Overflow Bytes:",
    ++       "%lld (max %lld) bytes", SQLITE_STATUS_PAGECACHE_OVERFLOW, bReset);
    ++    displayStatLine(pArg, "Largest Allocation:",
    ++       "%lld bytes", SQLITE_STATUS_MALLOC_SIZE, bReset);
    ++    displayStatLine(pArg, "Largest Pcache Allocation:",
    ++       "%lld bytes", SQLITE_STATUS_PAGECACHE_SIZE, bReset);
    ++#ifdef YYTRACKMAXSTACKDEPTH
    ++    displayStatLine(pArg, "Deepest Parser Stack:",
    ++       "%lld (max %lld)", SQLITE_STATUS_PARSER_STACK, bReset);
    ++#endif
    ++  }
    ++
    ++  if( pArg && pArg->out && db ){
    ++    if( pArg->shellFlgs & SHFLG_Lookaside ){
    ++      iHiwtr = iCur = -1;
    ++      sqlite3_db_status(db, SQLITE_DBSTATUS_LOOKASIDE_USED,
    ++                        &iCur, &iHiwtr, bReset);
    ++      raw_printf(pArg->out,
    ++              "Lookaside Slots Used:                %d (max %d)\n",
    ++              iCur, iHiwtr);
    ++      sqlite3_db_status(db, SQLITE_DBSTATUS_LOOKASIDE_HIT,
    ++                        &iCur, &iHiwtr, bReset);
    ++      raw_printf(pArg->out, "Successful lookaside attempts:       %d\n",
    ++              iHiwtr);
    ++      sqlite3_db_status(db, SQLITE_DBSTATUS_LOOKASIDE_MISS_SIZE,
    ++                        &iCur, &iHiwtr, bReset);
    ++      raw_printf(pArg->out, "Lookaside failures due to size:      %d\n",
    ++              iHiwtr);
    ++      sqlite3_db_status(db, SQLITE_DBSTATUS_LOOKASIDE_MISS_FULL,
    ++                        &iCur, &iHiwtr, bReset);
    ++      raw_printf(pArg->out, "Lookaside failures due to OOM:       %d\n",
    ++              iHiwtr);
    ++    }
    ++    iHiwtr = iCur = -1;
    ++    sqlite3_db_status(db, SQLITE_DBSTATUS_CACHE_USED, &iCur, &iHiwtr, bReset);
    ++    raw_printf(pArg->out, "Pager Heap Usage:                    %d bytes\n",
    ++            iCur);
    ++    iHiwtr = iCur = -1;
    ++    sqlite3_db_status(db, SQLITE_DBSTATUS_CACHE_HIT, &iCur, &iHiwtr, 1);
    ++    raw_printf(pArg->out, "Page cache hits:                     %d\n", iCur);
    ++    iHiwtr = iCur = -1;
    ++    sqlite3_db_status(db, SQLITE_DBSTATUS_CACHE_MISS, &iCur, &iHiwtr, 1);
    ++    raw_printf(pArg->out, "Page cache misses:                   %d\n", iCur);
    ++    iHiwtr = iCur = -1;
    ++    sqlite3_db_status(db, SQLITE_DBSTATUS_CACHE_WRITE, &iCur, &iHiwtr, 1);
    ++    raw_printf(pArg->out, "Page cache writes:                   %d\n", iCur);
    ++    iHiwtr = iCur = -1;
    ++    sqlite3_db_status(db, SQLITE_DBSTATUS_SCHEMA_USED, &iCur, &iHiwtr, bReset);
    ++    raw_printf(pArg->out, "Schema Heap Usage:                   %d bytes\n",
    ++            iCur);
    ++    iHiwtr = iCur = -1;
    ++    sqlite3_db_status(db, SQLITE_DBSTATUS_STMT_USED, &iCur, &iHiwtr, bReset);
    ++    raw_printf(pArg->out, "Statement Heap/Lookaside Usage:      %d bytes\n",
    ++            iCur);
    ++  }
    ++
    ++  if( pArg && pArg->out && db && pArg->pStmt ){
    ++    iCur = sqlite3_stmt_status(pArg->pStmt, SQLITE_STMTSTATUS_FULLSCAN_STEP,
    ++                               bReset);
    ++    raw_printf(pArg->out, "Fullscan Steps:                      %d\n", iCur);
    ++    iCur = sqlite3_stmt_status(pArg->pStmt, SQLITE_STMTSTATUS_SORT, bReset);
    ++    raw_printf(pArg->out, "Sort Operations:                     %d\n", iCur);
    ++    iCur = sqlite3_stmt_status(pArg->pStmt, SQLITE_STMTSTATUS_AUTOINDEX,bReset);
    ++    raw_printf(pArg->out, "Autoindex Inserts:                   %d\n", iCur);
    ++    iCur = sqlite3_stmt_status(pArg->pStmt, SQLITE_STMTSTATUS_VM_STEP, bReset);
    ++    raw_printf(pArg->out, "Virtual Machine Steps:               %d\n", iCur);
    ++  }
    ++
    ++#ifdef __linux__
    ++  displayLinuxIoStats(pArg->out);
    ++#endif
    ++
    ++  /* Do not remove this machine readable comment: extra-stats-output-here */
    ++
    ++  return 0;
    ++}
    ++
    ++/*
    ++** Display scan stats.
    ++*/
    ++static void display_scanstats(
    ++  sqlite3 *db,                    /* Database to query */
    ++  ShellState *pArg                /* Pointer to ShellState */
    ++){
    ++#ifndef SQLITE_ENABLE_STMT_SCANSTATUS
    ++  UNUSED_PARAMETER(db);
    ++  UNUSED_PARAMETER(pArg);
    ++#else
    ++  int i, k, n, mx;
    ++  raw_printf(pArg->out, "-------- scanstats --------\n");
    ++  mx = 0;
    ++  for(k=0; k<=mx; k++){
    ++    double rEstLoop = 1.0;
    ++    for(i=n=0; 1; i++){
    ++      sqlite3_stmt *p = pArg->pStmt;
    ++      sqlite3_int64 nLoop, nVisit;
    ++      double rEst;
    ++      int iSid;
    ++      const char *zExplain;
    ++      if( sqlite3_stmt_scanstatus(p, i, SQLITE_SCANSTAT_NLOOP, (void*)&nLoop) ){
    ++        break;
    ++      }
    ++      sqlite3_stmt_scanstatus(p, i, SQLITE_SCANSTAT_SELECTID, (void*)&iSid);
    ++      if( iSid>mx ) mx = iSid;
    ++      if( iSid!=k ) continue;
    ++      if( n==0 ){
    ++        rEstLoop = (double)nLoop;
    ++        if( k>0 ) raw_printf(pArg->out, "-------- subquery %d -------\n", k);
    ++      }
    ++      n++;
    ++      sqlite3_stmt_scanstatus(p, i, SQLITE_SCANSTAT_NVISIT, (void*)&nVisit);
    ++      sqlite3_stmt_scanstatus(p, i, SQLITE_SCANSTAT_EST, (void*)&rEst);
    ++      sqlite3_stmt_scanstatus(p, i, SQLITE_SCANSTAT_EXPLAIN, (void*)&zExplain);
    ++      utf8_printf(pArg->out, "Loop %2d: %s\n", n, zExplain);
    ++      rEstLoop *= rEst;
    ++      raw_printf(pArg->out,
    ++          "         nLoop=%-8lld nRow=%-8lld estRow=%-8lld estRow/Loop=%-8g\n",
    ++          nLoop, nVisit, (sqlite3_int64)(rEstLoop+0.5), rEst
    ++      );
    ++    }
    ++  }
    ++  raw_printf(pArg->out, "---------------------------\n");
    ++#endif
    ++}
    ++
    ++/*
    ++** Parameter azArray points to a zero-terminated array of strings. zStr
    ++** points to a single nul-terminated string. Return non-zero if zStr
    ++** is equal, according to strcmp(), to any of the strings in the array.
    ++** Otherwise, return zero.
    ++*/
    ++static int str_in_array(const char *zStr, const char **azArray){
    ++  int i;
    ++  for(i=0; azArray[i]; i++){
    ++    if( 0==strcmp(zStr, azArray[i]) ) return 1;
    ++  }
    ++  return 0;
    ++}
    ++
    ++/*
    ++** If compiled statement pSql appears to be an EXPLAIN statement, allocate
    ++** and populate the ShellState.aiIndent[] array with the number of
    ++** spaces each opcode should be indented before it is output.
    ++**
    ++** The indenting rules are:
    ++**
    ++**     * For each "Next", "Prev", "VNext" or "VPrev" instruction, indent
    ++**       all opcodes that occur between the p2 jump destination and the opcode
    ++**       itself by 2 spaces.
    ++**
    ++**     * For each "Goto", if the jump destination is earlier in the program
    ++**       and ends on one of:
    ++**          Yield  SeekGt  SeekLt  RowSetRead  Rewind
    ++**       or if the P1 parameter is one instead of zero,
    ++**       then indent all opcodes between the earlier instruction
    ++**       and "Goto" by 2 spaces.
    ++*/
    ++static void explain_data_prepare(ShellState *p, sqlite3_stmt *pSql){
    ++  const char *zSql;               /* The text of the SQL statement */
    ++  const char *z;                  /* Used to check if this is an EXPLAIN */
    ++  int *abYield = 0;               /* True if op is an OP_Yield */
    ++  int nAlloc = 0;                 /* Allocated size of p->aiIndent[], abYield */
    ++  int iOp;                        /* Index of operation in p->aiIndent[] */
    ++
    ++  const char *azNext[] = { "Next", "Prev", "VPrev", "VNext", "SorterNext",
    ++                           "NextIfOpen", "PrevIfOpen", 0 };
    ++  const char *azYield[] = { "Yield", "SeekLT", "SeekGT", "RowSetRead",
    ++                            "Rewind", 0 };
    ++  const char *azGoto[] = { "Goto", 0 };
    ++
    ++  /* Try to figure out if this is really an EXPLAIN statement. If this
    ++  ** cannot be verified, return early.  */
    ++  if( sqlite3_column_count(pSql)!=8 ){
    ++    p->cMode = p->mode;
    ++    return;
    ++  }
    ++  zSql = sqlite3_sql(pSql);
    ++  if( zSql==0 ) return;
    ++  for(z=zSql; *z==' ' || *z=='\t' || *z=='\n' || *z=='\f' || *z=='\r'; z++);
    ++  if( sqlite3_strnicmp(z, "explain", 7) ){
    ++    p->cMode = p->mode;
    ++    return;
    ++  }
    ++
    ++  for(iOp=0; SQLITE_ROW==sqlite3_step(pSql); iOp++){
    ++    int i;
    ++    int iAddr = sqlite3_column_int(pSql, 0);
    ++    const char *zOp = (const char*)sqlite3_column_text(pSql, 1);
    ++
    ++    /* Set p2 to the P2 field of the current opcode. Then, assuming that
    ++    ** p2 is an instruction address, set variable p2op to the index of that
    ++    ** instruction in the aiIndent[] array. p2 and p2op may be different if
    ++    ** the current instruction is part of a sub-program generated by an
    ++    ** SQL trigger or foreign key.  */
    ++    int p2 = sqlite3_column_int(pSql, 3);
    ++    int p2op = (p2 + (iOp-iAddr));
    ++
    ++    /* Grow the p->aiIndent array as required */
    ++    if( iOp>=nAlloc ){
    ++      if( iOp==0 ){
    ++        /* Do further verfication that this is explain output.  Abort if
    ++        ** it is not */
    ++        static const char *explainCols[] = {
    ++           "addr", "opcode", "p1", "p2", "p3", "p4", "p5", "comment" };
    ++        int jj;
    ++        for(jj=0; jj<ArraySize(explainCols); jj++){
    ++          if( strcmp(sqlite3_column_name(pSql,jj),explainCols[jj])!=0 ){
    ++            p->cMode = p->mode;
    ++            sqlite3_reset(pSql);
    ++            return;
    ++          }
    ++        }
    ++      }
    ++      nAlloc += 100;
    ++      p->aiIndent = (int*)sqlite3_realloc64(p->aiIndent, nAlloc*sizeof(int));
    ++      abYield = (int*)sqlite3_realloc64(abYield, nAlloc*sizeof(int));
    ++    }
    ++    abYield[iOp] = str_in_array(zOp, azYield);
    ++    p->aiIndent[iOp] = 0;
    ++    p->nIndent = iOp+1;
    ++
    ++    if( str_in_array(zOp, azNext) ){
    ++      for(i=p2op; i<iOp; i++) p->aiIndent[i] += 2;
    ++    }
    ++    if( str_in_array(zOp, azGoto) && p2op<p->nIndent
    ++     && (abYield[p2op] || sqlite3_column_int(pSql, 2))
    ++    ){
    ++      for(i=p2op; i<iOp; i++) p->aiIndent[i] += 2;
    ++    }
    ++  }
    ++
    ++  p->iIndent = 0;
    ++  sqlite3_free(abYield);
    ++  sqlite3_reset(pSql);
    ++}
    ++
    ++/*
    ++** Free the array allocated by explain_data_prepare().
    ++*/
    ++static void explain_data_delete(ShellState *p){
    ++  sqlite3_free(p->aiIndent);
    ++  p->aiIndent = 0;
    ++  p->nIndent = 0;
    ++  p->iIndent = 0;
    ++}
    ++
    ++/*
    ++** Disable and restore .wheretrace and .selecttrace settings.
    ++*/
    ++#if defined(SQLITE_DEBUG) && defined(SQLITE_ENABLE_SELECTTRACE)
    ++extern int sqlite3SelectTrace;
    ++static int savedSelectTrace;
    ++#endif
    ++#if defined(SQLITE_DEBUG) && defined(SQLITE_ENABLE_WHERETRACE)
    ++extern int sqlite3WhereTrace;
    ++static int savedWhereTrace;
    ++#endif
    ++static void disable_debug_trace_modes(void){
    ++#if defined(SQLITE_DEBUG) && defined(SQLITE_ENABLE_SELECTTRACE)
    ++  savedSelectTrace = sqlite3SelectTrace;
    ++  sqlite3SelectTrace = 0;
    ++#endif
    ++#if defined(SQLITE_DEBUG) && defined(SQLITE_ENABLE_WHERETRACE)
    ++  savedWhereTrace = sqlite3WhereTrace;
    ++  sqlite3WhereTrace = 0;
    ++#endif
    ++}
    ++static void restore_debug_trace_modes(void){
    ++#if defined(SQLITE_DEBUG) && defined(SQLITE_ENABLE_SELECTTRACE)
    ++  sqlite3SelectTrace = savedSelectTrace;
    ++#endif
    ++#if defined(SQLITE_DEBUG) && defined(SQLITE_ENABLE_WHERETRACE)
    ++  sqlite3WhereTrace = savedWhereTrace;
    ++#endif
    ++}
    ++
    ++/*
    ++** Run a prepared statement
    ++*/
    ++static void exec_prepared_stmt(
    ++  ShellState *pArg,                                /* Pointer to ShellState */
    ++  sqlite3_stmt *pStmt,                             /* Statment to run */
    ++  int (*xCallback)(void*,int,char**,char**,int*)   /* Callback function */
    ++){
    ++  int rc;
    ++
    ++  /* perform the first step.  this will tell us if we
    ++  ** have a result set or not and how wide it is.
    ++  */
    ++  rc = sqlite3_step(pStmt);
    ++  /* if we have a result set... */
    ++  if( SQLITE_ROW == rc ){
    ++    /* if we have a callback... */
    ++    if( xCallback ){
    ++      /* allocate space for col name ptr, value ptr, and type */
    ++      int nCol = sqlite3_column_count(pStmt);
    ++      void *pData = sqlite3_malloc64(3*nCol*sizeof(const char*) + 1);
    ++      if( !pData ){
    ++        rc = SQLITE_NOMEM;
    ++      }else{
    ++        char **azCols = (char **)pData;      /* Names of result columns */
    ++        char **azVals = &azCols[nCol];       /* Results */
    ++        int *aiTypes = (int *)&azVals[nCol]; /* Result types */
    ++        int i, x;
    ++        assert(sizeof(int) <= sizeof(char *));
    ++        /* save off ptrs to column names */
    ++        for(i=0; i<nCol; i++){
    ++          azCols[i] = (char *)sqlite3_column_name(pStmt, i);
    ++        }
    ++        do{
    ++          /* extract the data and data types */
    ++          for(i=0; i<nCol; i++){
    ++            aiTypes[i] = x = sqlite3_column_type(pStmt, i);
    ++            if( x==SQLITE_BLOB && pArg && pArg->cMode==MODE_Insert ){
    ++              azVals[i] = "";
    ++            }else{
    ++              azVals[i] = (char*)sqlite3_column_text(pStmt, i);
    ++            }
    ++            if( !azVals[i] && (aiTypes[i]!=SQLITE_NULL) ){
    ++              rc = SQLITE_NOMEM;
    ++              break; /* from for */
    ++            }
    ++          } /* end for */
    ++
    ++          /* if data and types extracted successfully... */
    ++          if( SQLITE_ROW == rc ){
    ++            /* call the supplied callback with the result row data */
    ++            if( xCallback(pArg, nCol, azVals, azCols, aiTypes) ){
    ++              rc = SQLITE_ABORT;
    ++            }else{
    ++              rc = sqlite3_step(pStmt);
    ++            }
    ++          }
    ++        } while( SQLITE_ROW == rc );
    ++        sqlite3_free(pData);
    ++      }
    ++    }else{
    ++      do{
    ++        rc = sqlite3_step(pStmt);
    ++      } while( rc == SQLITE_ROW );
    ++    }
    ++  }
    ++}
    ++
    ++#ifndef SQLITE_OMIT_VIRTUALTABLE
    ++/*
    ++** This function is called to process SQL if the previous shell command
    ++** was ".expert". It passes the SQL in the second argument directly to
    ++** the sqlite3expert object.
    ++**
    ++** If successful, SQLITE_OK is returned. Otherwise, an SQLite error
    ++** code. In this case, (*pzErr) may be set to point to a buffer containing
    ++** an English language error message. It is the responsibility of the
    ++** caller to eventually free this buffer using sqlite3_free().
    ++*/
    ++static int expertHandleSQL(
    ++  ShellState *pState, 
    ++  const char *zSql, 
    ++  char **pzErr
    ++){
    ++  assert( pState->expert.pExpert );
    ++  assert( pzErr==0 || *pzErr==0 );
    ++  return sqlite3_expert_sql(pState->expert.pExpert, zSql, pzErr);
    ++}
    ++
    ++/*
    ++** This function is called either to silently clean up the object
    ++** created by the ".expert" command (if bCancel==1), or to generate a 
    ++** report from it and then clean it up (if bCancel==0).
    ++**
    ++** If successful, SQLITE_OK is returned. Otherwise, an SQLite error
    ++** code. In this case, (*pzErr) may be set to point to a buffer containing
    ++** an English language error message. It is the responsibility of the
    ++** caller to eventually free this buffer using sqlite3_free().
    ++*/
    ++static int expertFinish(
    ++  ShellState *pState,
    ++  int bCancel,
    ++  char **pzErr
    ++){
    ++  int rc = SQLITE_OK;
    ++  sqlite3expert *p = pState->expert.pExpert;
    ++  assert( p );
    ++  assert( bCancel || pzErr==0 || *pzErr==0 );
    ++  if( bCancel==0 ){
    ++    FILE *out = pState->out;
    ++    int bVerbose = pState->expert.bVerbose;
    ++
    ++    rc = sqlite3_expert_analyze(p, pzErr);
    ++    if( rc==SQLITE_OK ){
    ++      int nQuery = sqlite3_expert_count(p);
    ++      int i;
    ++
    ++      if( bVerbose ){
    ++        const char *zCand = sqlite3_expert_report(p,0,EXPERT_REPORT_CANDIDATES);
    ++        raw_printf(out, "-- Candidates -----------------------------\n");
    ++        raw_printf(out, "%s\n", zCand);
    ++      }
    ++      for(i=0; i<nQuery; i++){
    ++        const char *zSql = sqlite3_expert_report(p, i, EXPERT_REPORT_SQL);
    ++        const char *zIdx = sqlite3_expert_report(p, i, EXPERT_REPORT_INDEXES);
    ++        const char *zEQP = sqlite3_expert_report(p, i, EXPERT_REPORT_PLAN);
    ++        if( zIdx==0 ) zIdx = "(no new indexes)\n";
    ++        if( bVerbose ){
    ++          raw_printf(out, "-- Query %d --------------------------------\n",i+1);
    ++          raw_printf(out, "%s\n\n", zSql);
    ++        }
    ++        raw_printf(out, "%s\n", zIdx);
    ++        raw_printf(out, "%s\n", zEQP);
    ++      }
    ++    }
    ++  }
    ++  sqlite3_expert_destroy(p);
    ++  pState->expert.pExpert = 0;
    ++  return rc;
    ++}
    ++
    ++/*
    ++** Implementation of ".expert" dot command.
    ++*/
    ++static int expertDotCommand(
    ++  ShellState *pState,             /* Current shell tool state */
    ++  char **azArg,                   /* Array of arguments passed to dot command */
    ++  int nArg                        /* Number of entries in azArg[] */
    ++){
    ++  int rc = SQLITE_OK;
    ++  char *zErr = 0;
    ++  int i;
    ++  int iSample = 0;
    ++
    ++  assert( pState->expert.pExpert==0 );
    ++  memset(&pState->expert, 0, sizeof(ExpertInfo));
    ++
    ++  for(i=1; rc==SQLITE_OK && i<nArg; i++){
    ++    char *z = azArg[i];
    ++    int n;
    ++    if( z[0]=='-' && z[1]=='-' ) z++;
    ++    n = strlen30(z);
    ++    if( n>=2 && 0==strncmp(z, "-verbose", n) ){
    ++      pState->expert.bVerbose = 1;
    ++    }
    ++    else if( n>=2 && 0==strncmp(z, "-sample", n) ){
    ++      if( i==(nArg-1) ){
    ++        raw_printf(stderr, "option requires an argument: %s\n", z);
    ++        rc = SQLITE_ERROR;
    ++      }else{
    ++        iSample = (int)integerValue(azArg[++i]);
    ++        if( iSample<0 || iSample>100 ){
    ++          raw_printf(stderr, "value out of range: %s\n", azArg[i]);
    ++          rc = SQLITE_ERROR;
    ++        }
    ++      }
    ++    }
    ++    else{
    ++      raw_printf(stderr, "unknown option: %s\n", z);
    ++      rc = SQLITE_ERROR;
    ++    }
    ++  }
    ++
    ++  if( rc==SQLITE_OK ){
    ++    pState->expert.pExpert = sqlite3_expert_new(pState->db, &zErr);
    ++    if( pState->expert.pExpert==0 ){
    ++      raw_printf(stderr, "sqlite3_expert_new: %s\n", zErr);
    ++      rc = SQLITE_ERROR;
    ++    }else{
    ++      sqlite3_expert_config(
    ++          pState->expert.pExpert, EXPERT_CONFIG_SAMPLE, iSample
    ++      );
    ++    }
    ++  }
    ++
    ++  return rc;
    ++}
    ++#endif /* ifndef SQLITE_OMIT_VIRTUALTABLE */
    ++
    ++/*
    ++** Execute a statement or set of statements.  Print
    ++** any result rows/columns depending on the current mode
    ++** set via the supplied callback.
    ++**
    ++** This is very similar to SQLite's built-in sqlite3_exec()
    ++** function except it takes a slightly different callback
    ++** and callback data argument.
    ++*/
    ++static int shell_exec(
    ++  sqlite3 *db,                              /* An open database */
    ++  const char *zSql,                         /* SQL to be evaluated */
    ++  int (*xCallback)(void*,int,char**,char**,int*),   /* Callback function */
    ++                                            /* (not the same as sqlite3_exec) */
    ++  ShellState *pArg,                         /* Pointer to ShellState */
    ++  char **pzErrMsg                           /* Error msg written here */
    ++){
    ++  sqlite3_stmt *pStmt = NULL;     /* Statement to execute. */
    ++  int rc = SQLITE_OK;             /* Return Code */
    ++  int rc2;
    ++  const char *zLeftover;          /* Tail of unprocessed SQL */
    ++
    ++  if( pzErrMsg ){
    ++    *pzErrMsg = NULL;
    ++  }
    ++
    ++#ifndef SQLITE_OMIT_VIRTUALTABLE
    ++  if( pArg->expert.pExpert ){
    ++    rc = expertHandleSQL(pArg, zSql, pzErrMsg);
    ++    return expertFinish(pArg, (rc!=SQLITE_OK), pzErrMsg);
    ++  }
    ++#endif
    ++
    ++  while( zSql[0] && (SQLITE_OK == rc) ){
    ++    static const char *zStmtSql;
    ++    rc = sqlite3_prepare_v2(db, zSql, -1, &pStmt, &zLeftover);
    ++    if( SQLITE_OK != rc ){
    ++      if( pzErrMsg ){
    ++        *pzErrMsg = save_err_msg(db);
    ++      }
    ++    }else{
    ++      if( !pStmt ){
    ++        /* this happens for a comment or white-space */
    ++        zSql = zLeftover;
    ++        while( IsSpace(zSql[0]) ) zSql++;
    ++        continue;
    ++      }
    ++      zStmtSql = sqlite3_sql(pStmt);
    ++      if( zStmtSql==0 ) zStmtSql = "";
    ++      while( IsSpace(zStmtSql[0]) ) zStmtSql++;
    ++
    ++      /* save off the prepared statment handle and reset row count */
    ++      if( pArg ){
    ++        pArg->pStmt = pStmt;
    ++        pArg->cnt = 0;
    ++      }
    ++
    ++      /* echo the sql statement if echo on */
    ++      if( pArg && ShellHasFlag(pArg, SHFLG_Echo) ){
    ++        utf8_printf(pArg->out, "%s\n", zStmtSql ? zStmtSql : zSql);
    ++      }
    ++
    ++      /* Show the EXPLAIN QUERY PLAN if .eqp is on */
    ++      if( pArg && pArg->autoEQP && sqlite3_strlike("EXPLAIN%",zStmtSql,0)!=0 ){
    ++        sqlite3_stmt *pExplain;
    ++        char *zEQP;
    ++        int triggerEQP = 0;
    ++        disable_debug_trace_modes();
    ++        sqlite3_db_config(db, SQLITE_DBCONFIG_TRIGGER_EQP, -1, &triggerEQP);
    ++        if( pArg->autoEQP>=AUTOEQP_trigger ){
    ++          sqlite3_db_config(db, SQLITE_DBCONFIG_TRIGGER_EQP, 1, 0);
    ++        }
    ++        zEQP = sqlite3_mprintf("EXPLAIN QUERY PLAN %s", zStmtSql);
    ++        rc = sqlite3_prepare_v2(db, zEQP, -1, &pExplain, 0);
    ++        if( rc==SQLITE_OK ){
    ++          while( sqlite3_step(pExplain)==SQLITE_ROW ){
    ++            raw_printf(pArg->out,"--EQP-- %d,",sqlite3_column_int(pExplain, 0));
    ++            raw_printf(pArg->out,"%d,", sqlite3_column_int(pExplain, 1));
    ++            raw_printf(pArg->out,"%d,", sqlite3_column_int(pExplain, 2));
    ++            utf8_printf(pArg->out,"%s\n", sqlite3_column_text(pExplain, 3));
    ++          }
    ++        }
    ++        sqlite3_finalize(pExplain);
    ++        sqlite3_free(zEQP);
    ++        if( pArg->autoEQP>=AUTOEQP_full ){
    ++          /* Also do an EXPLAIN for ".eqp full" mode */
    ++          zEQP = sqlite3_mprintf("EXPLAIN %s", zStmtSql);
    ++          rc = sqlite3_prepare_v2(db, zEQP, -1, &pExplain, 0);
    ++          if( rc==SQLITE_OK ){
    ++            pArg->cMode = MODE_Explain;
    ++            explain_data_prepare(pArg, pExplain);
    ++            exec_prepared_stmt(pArg, pExplain, xCallback);
    ++            explain_data_delete(pArg);
    ++          }
    ++          sqlite3_finalize(pExplain);
    ++          sqlite3_free(zEQP);
    ++        }
    ++        sqlite3_db_config(db, SQLITE_DBCONFIG_TRIGGER_EQP, triggerEQP, 0);
    ++        restore_debug_trace_modes();
    ++      }
    ++
    ++      if( pArg ){
    ++        pArg->cMode = pArg->mode;
    ++        if( pArg->autoExplain
    ++         && sqlite3_column_count(pStmt)==8
    ++         && sqlite3_strlike("EXPLAIN%", zStmtSql,0)==0
    ++        ){
    ++          pArg->cMode = MODE_Explain;
    ++        }
    ++
    ++        /* If the shell is currently in ".explain" mode, gather the extra
    ++        ** data required to add indents to the output.*/
    ++        if( pArg->cMode==MODE_Explain ){
    ++          explain_data_prepare(pArg, pStmt);
    ++        }
    ++      }
    ++
    ++      exec_prepared_stmt(pArg, pStmt, xCallback);
    ++      explain_data_delete(pArg);
    ++
    ++      /* print usage stats if stats on */
    ++      if( pArg && pArg->statsOn ){
    ++        display_stats(db, pArg, 0);
    ++      }
    ++
    ++      /* print loop-counters if required */
    ++      if( pArg && pArg->scanstatsOn ){
    ++        display_scanstats(db, pArg);
    ++      }
    ++
    ++      /* Finalize the statement just executed. If this fails, save a
    ++      ** copy of the error message. Otherwise, set zSql to point to the
    ++      ** next statement to execute. */
    ++      rc2 = sqlite3_finalize(pStmt);
    ++      if( rc!=SQLITE_NOMEM ) rc = rc2;
    ++      if( rc==SQLITE_OK ){
    ++        zSql = zLeftover;
    ++        while( IsSpace(zSql[0]) ) zSql++;
    ++      }else if( pzErrMsg ){
    ++        *pzErrMsg = save_err_msg(db);
    ++      }
    ++
    ++      /* clear saved stmt handle */
    ++      if( pArg ){
    ++        pArg->pStmt = NULL;
    ++      }
    ++    }
    ++  } /* end while */
    ++
    ++  return rc;
    ++}
    ++
    ++/*
    ++** Release memory previously allocated by tableColumnList().
    ++*/
    ++static void freeColumnList(char **azCol){
    ++  int i;
    ++  for(i=1; azCol[i]; i++){
    ++    sqlite3_free(azCol[i]);
    ++  }
    ++  /* azCol[0] is a static string */
    ++  sqlite3_free(azCol);
    ++}
    ++
    ++/*
    ++** Return a list of pointers to strings which are the names of all
    ++** columns in table zTab.   The memory to hold the names is dynamically
    ++** allocated and must be released by the caller using a subsequent call
    ++** to freeColumnList().
    ++**
    ++** The azCol[0] entry is usually NULL.  However, if zTab contains a rowid
    ++** value that needs to be preserved, then azCol[0] is filled in with the
    ++** name of the rowid column.
    ++**
    ++** The first regular column in the table is azCol[1].  The list is terminated
    ++** by an entry with azCol[i]==0.
    ++*/
    ++static char **tableColumnList(ShellState *p, const char *zTab){
    ++  char **azCol = 0;
    ++  sqlite3_stmt *pStmt;
    ++  char *zSql;
    ++  int nCol = 0;
    ++  int nAlloc = 0;
    ++  int nPK = 0;       /* Number of PRIMARY KEY columns seen */
    ++  int isIPK = 0;     /* True if one PRIMARY KEY column of type INTEGER */
    ++  int preserveRowid = ShellHasFlag(p, SHFLG_PreserveRowid);
    ++  int rc;
    ++
    ++  zSql = sqlite3_mprintf("PRAGMA table_info=%Q", zTab);
    ++  rc = sqlite3_prepare_v2(p->db, zSql, -1, &pStmt, 0);
    ++  sqlite3_free(zSql);
    ++  if( rc ) return 0;
    ++  while( sqlite3_step(pStmt)==SQLITE_ROW ){
    ++    if( nCol>=nAlloc-2 ){
    ++      nAlloc = nAlloc*2 + nCol + 10;
    ++      azCol = sqlite3_realloc(azCol, nAlloc*sizeof(azCol[0]));
    ++      if( azCol==0 ){
    ++        raw_printf(stderr, "Error: out of memory\n");
    ++        exit(1);
    ++      }
    ++    }
    ++    azCol[++nCol] = sqlite3_mprintf("%s", sqlite3_column_text(pStmt, 1));
    ++    if( sqlite3_column_int(pStmt, 5) ){
    ++      nPK++;
    ++      if( nPK==1
    ++       && sqlite3_stricmp((const char*)sqlite3_column_text(pStmt,2),
    ++                          "INTEGER")==0
    ++      ){
    ++        isIPK = 1;
    ++      }else{
    ++        isIPK = 0;
    ++      }
    ++    }
    ++  }
    ++  sqlite3_finalize(pStmt);
    ++  if( azCol==0 ) return 0;
    ++  azCol[0] = 0;
    ++  azCol[nCol+1] = 0;
    ++
    ++  /* The decision of whether or not a rowid really needs to be preserved
    ++  ** is tricky.  We never need to preserve a rowid for a WITHOUT ROWID table
    ++  ** or a table with an INTEGER PRIMARY KEY.  We are unable to preserve
    ++  ** rowids on tables where the rowid is inaccessible because there are other
    ++  ** columns in the table named "rowid", "_rowid_", and "oid".
    ++  */
    ++  if( preserveRowid && isIPK ){
    ++    /* If a single PRIMARY KEY column with type INTEGER was seen, then it
    ++    ** might be an alise for the ROWID.  But it might also be a WITHOUT ROWID
    ++    ** table or a INTEGER PRIMARY KEY DESC column, neither of which are
    ++    ** ROWID aliases.  To distinguish these cases, check to see if
    ++    ** there is a "pk" entry in "PRAGMA index_list".  There will be
    ++    ** no "pk" index if the PRIMARY KEY really is an alias for the ROWID.
    ++    */
    ++    zSql = sqlite3_mprintf("SELECT 1 FROM pragma_index_list(%Q)"
    ++                           " WHERE origin='pk'", zTab);
    ++    rc = sqlite3_prepare_v2(p->db, zSql, -1, &pStmt, 0);
    ++    sqlite3_free(zSql);
    ++    if( rc ){
    ++      freeColumnList(azCol);
    ++      return 0;
    ++    }
    ++    rc = sqlite3_step(pStmt);
    ++    sqlite3_finalize(pStmt);
    ++    preserveRowid = rc==SQLITE_ROW;
    ++  }
    ++  if( preserveRowid ){
    ++    /* Only preserve the rowid if we can find a name to use for the
    ++    ** rowid */
    ++    static char *azRowid[] = { "rowid", "_rowid_", "oid" };
    ++    int i, j;
    ++    for(j=0; j<3; j++){
    ++      for(i=1; i<=nCol; i++){
    ++        if( sqlite3_stricmp(azRowid[j],azCol[i])==0 ) break;
    ++      }
    ++      if( i>nCol ){
    ++        /* At this point, we know that azRowid[j] is not the name of any
    ++        ** ordinary column in the table.  Verify that azRowid[j] is a valid
    ++        ** name for the rowid before adding it to azCol[0].  WITHOUT ROWID
    ++        ** tables will fail this last check */
    ++        rc = sqlite3_table_column_metadata(p->db,0,zTab,azRowid[j],0,0,0,0,0);
    ++        if( rc==SQLITE_OK ) azCol[0] = azRowid[j];
    ++        break;
    ++      }
    ++    }
    ++  }
    ++  return azCol;
    ++}
    ++
    ++/*
    ++** Toggle the reverse_unordered_selects setting.
    ++*/
    ++static void toggleSelectOrder(sqlite3 *db){
    ++  sqlite3_stmt *pStmt = 0;
    ++  int iSetting = 0;
    ++  char zStmt[100];
    ++  sqlite3_prepare_v2(db, "PRAGMA reverse_unordered_selects", -1, &pStmt, 0);
    ++  if( sqlite3_step(pStmt)==SQLITE_ROW ){
    ++    iSetting = sqlite3_column_int(pStmt, 0);
    ++  }
    ++  sqlite3_finalize(pStmt);
    ++  sqlite3_snprintf(sizeof(zStmt), zStmt,
    ++       "PRAGMA reverse_unordered_selects(%d)", !iSetting);
    ++  sqlite3_exec(db, zStmt, 0, 0, 0);
    ++}
    ++
    ++/*
    ++** This is a different callback routine used for dumping the database.
    ++** Each row received by this callback consists of a table name,
    ++** the table type ("index" or "table") and SQL to create the table.
    ++** This routine should print text sufficient to recreate the table.
    ++*/
    ++static int dump_callback(void *pArg, int nArg, char **azArg, char **azNotUsed){
    ++  int rc;
    ++  const char *zTable;
    ++  const char *zType;
    ++  const char *zSql;
    ++  ShellState *p = (ShellState *)pArg;
    ++
    ++  UNUSED_PARAMETER(azNotUsed);
    ++  if( nArg!=3 || azArg==0 ) return 0;
    ++  zTable = azArg[0];
    ++  zType = azArg[1];
    ++  zSql = azArg[2];
    ++
    ++  if( strcmp(zTable, "sqlite_sequence")==0 ){
    ++    raw_printf(p->out, "DELETE FROM sqlite_sequence;\n");
    ++  }else if( sqlite3_strglob("sqlite_stat?", zTable)==0 ){
    ++    raw_printf(p->out, "ANALYZE sqlite_master;\n");
    ++  }else if( strncmp(zTable, "sqlite_", 7)==0 ){
    ++    return 0;
    ++  }else if( strncmp(zSql, "CREATE VIRTUAL TABLE", 20)==0 ){
    ++    char *zIns;
    ++    if( !p->writableSchema ){
    ++      raw_printf(p->out, "PRAGMA writable_schema=ON;\n");
    ++      p->writableSchema = 1;
    ++    }
    ++    zIns = sqlite3_mprintf(
    ++       "INSERT INTO sqlite_master(type,name,tbl_name,rootpage,sql)"
    ++       "VALUES('table','%q','%q',0,'%q');",
    ++       zTable, zTable, zSql);
    ++    utf8_printf(p->out, "%s\n", zIns);
    ++    sqlite3_free(zIns);
    ++    return 0;
    ++  }else{
    ++    printSchemaLine(p->out, zSql, ";\n");
    ++  }
    ++
    ++  if( strcmp(zType, "table")==0 ){
    ++    ShellText sSelect;
    ++    ShellText sTable;
    ++    char **azCol;
    ++    int i;
    ++    char *savedDestTable;
    ++    int savedMode;
    ++
    ++    azCol = tableColumnList(p, zTable);
    ++    if( azCol==0 ){
    ++      p->nErr++;
    ++      return 0;
    ++    }
    ++
    ++    /* Always quote the table name, even if it appears to be pure ascii,
    ++    ** in case it is a keyword. Ex:  INSERT INTO "table" ... */
    ++    initText(&sTable);
    ++    appendText(&sTable, zTable, quoteChar(zTable));
    ++    /* If preserving the rowid, add a column list after the table name.
    ++    ** In other words:  "INSERT INTO tab(rowid,a,b,c,...) VALUES(...)"
    ++    ** instead of the usual "INSERT INTO tab VALUES(...)".
    ++    */
    ++    if( azCol[0] ){
    ++      appendText(&sTable, "(", 0);
    ++      appendText(&sTable, azCol[0], 0);
    ++      for(i=1; azCol[i]; i++){
    ++        appendText(&sTable, ",", 0);
    ++        appendText(&sTable, azCol[i], quoteChar(azCol[i]));
    ++      }
    ++      appendText(&sTable, ")", 0);
    ++    }
    ++
    ++    /* Build an appropriate SELECT statement */
    ++    initText(&sSelect);
    ++    appendText(&sSelect, "SELECT ", 0);
    ++    if( azCol[0] ){
    ++      appendText(&sSelect, azCol[0], 0);
    ++      appendText(&sSelect, ",", 0);
    ++    }
    ++    for(i=1; azCol[i]; i++){
    ++      appendText(&sSelect, azCol[i], quoteChar(azCol[i]));
    ++      if( azCol[i+1] ){
    ++        appendText(&sSelect, ",", 0);
    ++      }
    ++    }
    ++    freeColumnList(azCol);
    ++    appendText(&sSelect, " FROM ", 0);
    ++    appendText(&sSelect, zTable, quoteChar(zTable));
    ++
    ++    savedDestTable = p->zDestTable;
    ++    savedMode = p->mode;
    ++    p->zDestTable = sTable.z;
    ++    p->mode = p->cMode = MODE_Insert;
    ++    rc = shell_exec(p->db, sSelect.z, shell_callback, p, 0);
    ++    if( (rc&0xff)==SQLITE_CORRUPT ){
    ++      raw_printf(p->out, "/****** CORRUPTION ERROR *******/\n");
    ++      toggleSelectOrder(p->db);
    ++      shell_exec(p->db, sSelect.z, shell_callback, p, 0);
    ++      toggleSelectOrder(p->db);
    ++    }
    ++    p->zDestTable = savedDestTable;
    ++    p->mode = savedMode;
    ++    freeText(&sTable);
    ++    freeText(&sSelect);
    ++    if( rc ) p->nErr++;
    ++  }
    ++  return 0;
    ++}
    ++
    ++/*
    ++** Run zQuery.  Use dump_callback() as the callback routine so that
    ++** the contents of the query are output as SQL statements.
    ++**
    ++** If we get a SQLITE_CORRUPT error, rerun the query after appending
    ++** "ORDER BY rowid DESC" to the end.
    ++*/
    ++static int run_schema_dump_query(
    ++  ShellState *p,
    ++  const char *zQuery
    ++){
    ++  int rc;
    ++  char *zErr = 0;
    ++  rc = sqlite3_exec(p->db, zQuery, dump_callback, p, &zErr);
    ++  if( rc==SQLITE_CORRUPT ){
    ++    char *zQ2;
    ++    int len = strlen30(zQuery);
    ++    raw_printf(p->out, "/****** CORRUPTION ERROR *******/\n");
    ++    if( zErr ){
    ++      utf8_printf(p->out, "/****** %s ******/\n", zErr);
    ++      sqlite3_free(zErr);
    ++      zErr = 0;
    ++    }
    ++    zQ2 = malloc( len+100 );
    ++    if( zQ2==0 ) return rc;
    ++    sqlite3_snprintf(len+100, zQ2, "%s ORDER BY rowid DESC", zQuery);
    ++    rc = sqlite3_exec(p->db, zQ2, dump_callback, p, &zErr);
    ++    if( rc ){
    ++      utf8_printf(p->out, "/****** ERROR: %s ******/\n", zErr);
    ++    }else{
    ++      rc = SQLITE_CORRUPT;
    ++    }
    ++    sqlite3_free(zErr);
    ++    free(zQ2);
    ++  }
    ++  return rc;
    ++}
    ++
    ++/*
    ++** Text of a help message
    ++*/
    ++static char zHelp[] =
    ++#if defined(SQLITE_HAVE_ZLIB) && !defined(SQLITE_OMIT_VIRTUALTABLE)
    ++  ".archive ...           Manage SQL archives: \".archive --help\" for details\n"
    ++#endif
    ++#ifndef SQLITE_OMIT_AUTHORIZATION
    ++  ".auth ON|OFF           Show authorizer callbacks\n"
    ++#endif
    ++  ".backup ?DB? FILE      Backup DB (default \"main\") to FILE\n"
    ++  ".bail on|off           Stop after hitting an error.  Default OFF\n"
    ++  ".binary on|off         Turn binary output on or off.  Default OFF\n"
    ++  ".cd DIRECTORY          Change the working directory to DIRECTORY\n"
    ++  ".changes on|off        Show number of rows changed by SQL\n"
    ++  ".check GLOB            Fail if output since .testcase does not match\n"
    ++  ".clone NEWDB           Clone data into NEWDB from the existing database\n"
    ++  ".databases             List names and files of attached databases\n"
    ++  ".dbinfo ?DB?           Show status information about the database\n"
    ++  ".dump ?TABLE? ...      Dump the database in an SQL text format\n"
    ++  "                         If TABLE specified, only dump tables matching\n"
    ++  "                         LIKE pattern TABLE.\n"
    ++  ".echo on|off           Turn command echo on or off\n"
    ++  ".eqp on|off|full       Enable or disable automatic EXPLAIN QUERY PLAN\n"
    ++  ".excel                 Display the output of next command in a spreadsheet\n"
    ++  ".exit                  Exit this program\n"
    ++  ".expert                EXPERIMENTAL. Suggest indexes for specified queries\n"
    ++/* Because explain mode comes on automatically now, the ".explain" mode
    ++** is removed from the help screen.  It is still supported for legacy, however */
    ++/*".explain ?on|off|auto? Turn EXPLAIN output mode on or off or to automatic\n"*/
    ++  ".fullschema ?--indent? Show schema and the content of sqlite_stat tables\n"
    ++  ".headers on|off        Turn display of headers on or off\n"
    ++  ".help                  Show this message\n"
    ++  ".import FILE TABLE     Import data from FILE into TABLE\n"
    ++#ifndef SQLITE_OMIT_TEST_CONTROL
    ++  ".imposter INDEX TABLE  Create imposter table TABLE on index INDEX\n"
    ++#endif
    ++  ".indexes ?TABLE?       Show names of all indexes\n"
    ++  "                         If TABLE specified, only show indexes for tables\n"
    ++  "                         matching LIKE pattern TABLE.\n"
    ++#ifdef SQLITE_ENABLE_IOTRACE
    ++  ".iotrace FILE          Enable I/O diagnostic logging to FILE\n"
    ++#endif
    ++  ".limit ?LIMIT? ?VAL?   Display or change the value of an SQLITE_LIMIT\n"
    ++  ".lint OPTIONS          Report potential schema issues. Options:\n"
    ++  "                         fkey-indexes     Find missing foreign key indexes\n"
    ++#ifndef SQLITE_OMIT_LOAD_EXTENSION
    ++  ".load FILE ?ENTRY?     Load an extension library\n"
    ++#endif
    ++  ".log FILE|off          Turn logging on or off.  FILE can be stderr/stdout\n"
    ++  ".mode MODE ?TABLE?     Set output mode where MODE is one of:\n"
    ++  "                         ascii    Columns/rows delimited by 0x1F and 0x1E\n"
    ++  "                         csv      Comma-separated values\n"
    ++  "                         column   Left-aligned columns.  (See .width)\n"
    ++  "                         html     HTML <table> code\n"
    ++  "                         insert   SQL insert statements for TABLE\n"
    ++  "                         line     One value per line\n"
    ++  "                         list     Values delimited by \"|\"\n"
    ++  "                         quote    Escape answers as for SQL\n"
    ++  "                         tabs     Tab-separated values\n"
    ++  "                         tcl      TCL list elements\n"
    ++  ".nullvalue STRING      Use STRING in place of NULL values\n"
    ++  ".once (-e|-x|FILE)     Output for the next SQL command only to FILE\n"
    ++  "                         or invoke system text editor (-e) or spreadsheet (-x)\n"
    ++  "                         on the output.\n"
    ++  ".open ?OPTIONS? ?FILE? Close existing database and reopen FILE\n"
    ++  "                         The --new option starts with an empty file\n"
    ++  ".output ?FILE?         Send output to FILE or stdout\n"
    ++  ".print STRING...       Print literal STRING\n"
    ++  ".prompt MAIN CONTINUE  Replace the standard prompts\n"
    ++  ".quit                  Exit this program\n"
    ++  ".read FILENAME         Execute SQL in FILENAME\n"
    ++  ".restore ?DB? FILE     Restore content of DB (default \"main\") from FILE\n"
    ++  ".save FILE             Write in-memory database into FILE\n"
    ++  ".scanstats on|off      Turn sqlite3_stmt_scanstatus() metrics on or off\n"
    ++  ".schema ?PATTERN?      Show the CREATE statements matching PATTERN\n"
    ++  "                          Add --indent for pretty-printing\n"
    ++  ".selftest ?--init?     Run tests defined in the SELFTEST table\n"
    ++  ".separator COL ?ROW?   Change the column separator and optionally the row\n"
    ++  "                         separator for both the output mode and .import\n"
    ++#if defined(SQLITE_ENABLE_SESSION)
    ++  ".session CMD ...       Create or control sessions\n"
    ++#endif
    ++  ".sha3sum ?OPTIONS...?  Compute a SHA3 hash of database content\n"
    ++  ".shell CMD ARGS...     Run CMD ARGS... in a system shell\n"
    ++  ".show                  Show the current values for various settings\n"
    ++  ".stats ?on|off?        Show stats or turn stats on or off\n"
    ++  ".system CMD ARGS...    Run CMD ARGS... in a system shell\n"
    ++  ".tables ?TABLE?        List names of tables\n"
    ++  "                         If TABLE specified, only list tables matching\n"
    ++  "                         LIKE pattern TABLE.\n"
    ++  ".testcase NAME         Begin redirecting output to 'testcase-out.txt'\n"
    ++  ".timeout MS            Try opening locked tables for MS milliseconds\n"
    ++  ".timer on|off          Turn SQL timer on or off\n"
    ++  ".trace FILE|off        Output each SQL statement as it is run\n"
    ++  ".vfsinfo ?AUX?         Information about the top-level VFS\n"
    ++  ".vfslist               List all available VFSes\n"
    ++  ".vfsname ?AUX?         Print the name of the VFS stack\n"
    ++  ".width NUM1 NUM2 ...   Set column widths for \"column\" mode\n"
    ++  "                         Negative values right-justify\n"
    ++;
    ++
    ++#if defined(SQLITE_ENABLE_SESSION)
    ++/*
    ++** Print help information for the ".sessions" command
    ++*/
    ++void session_help(ShellState *p){
    ++  raw_printf(p->out,
    ++    ".session ?NAME? SUBCOMMAND ?ARGS...?\n"
    ++    "If ?NAME? is omitted, the first defined session is used.\n"
    ++    "Subcommands:\n"
    ++    "   attach TABLE             Attach TABLE\n"
    ++    "   changeset FILE           Write a changeset into FILE\n"
    ++    "   close                    Close one session\n"
    ++    "   enable ?BOOLEAN?         Set or query the enable bit\n"
    ++    "   filter GLOB...           Reject tables matching GLOBs\n"
    ++    "   indirect ?BOOLEAN?       Mark or query the indirect status\n"
    ++    "   isempty                  Query whether the session is empty\n"
    ++    "   list                     List currently open session names\n"
    ++    "   open DB NAME             Open a new session on DB\n"
    ++    "   patchset FILE            Write a patchset into FILE\n"
    ++  );
    ++}
    ++#endif
    ++
    ++
    ++/* Forward reference */
    ++static int process_input(ShellState *p, FILE *in);
    ++
    ++/*
    ++** Read the content of file zName into memory obtained from sqlite3_malloc64()
    ++** and return a pointer to the buffer. The caller is responsible for freeing
    ++** the memory.
    ++**
    ++** If parameter pnByte is not NULL, (*pnByte) is set to the number of bytes
    ++** read.
    ++**
    ++** For convenience, a nul-terminator byte is always appended to the data read
    ++** from the file before the buffer is returned. This byte is not included in
    ++** the final value of (*pnByte), if applicable.
    ++**
    ++** NULL is returned if any error is encountered. The final value of *pnByte
    ++** is undefined in this case.
    ++*/
    ++static char *readFile(const char *zName, int *pnByte){
    ++  FILE *in = fopen(zName, "rb");
    ++  long nIn;
    ++  size_t nRead;
    ++  char *pBuf;
    ++  if( in==0 ) return 0;
    ++  fseek(in, 0, SEEK_END);
    ++  nIn = ftell(in);
    ++  rewind(in);
    ++  pBuf = sqlite3_malloc64( nIn+1 );
    ++  if( pBuf==0 ) return 0;
    ++  nRead = fread(pBuf, nIn, 1, in);
    ++  fclose(in);
    ++  if( nRead!=1 ){
    ++    sqlite3_free(pBuf);
    ++    return 0;
    ++  }
    ++  pBuf[nIn] = 0;
    ++  if( pnByte ) *pnByte = nIn;
    ++  return pBuf;
    ++}
    ++
    ++#if defined(SQLITE_ENABLE_SESSION)
    ++/*
    ++** Close a single OpenSession object and release all of its associated
    ++** resources.
    ++*/
    ++static void session_close(OpenSession *pSession){
    ++  int i;
    ++  sqlite3session_delete(pSession->p);
    ++  sqlite3_free(pSession->zName);
    ++  for(i=0; i<pSession->nFilter; i++){
    ++    sqlite3_free(pSession->azFilter[i]);
    ++  }
    ++  sqlite3_free(pSession->azFilter);
    ++  memset(pSession, 0, sizeof(OpenSession));
    ++}
    ++#endif
    ++
    ++/*
    ++** Close all OpenSession objects and release all associated resources.
    ++*/
    ++#if defined(SQLITE_ENABLE_SESSION)
    ++static void session_close_all(ShellState *p){
    ++  int i;
    ++  for(i=0; i<p->nSession; i++){
    ++    session_close(&p->aSession[i]);
    ++  }
    ++  p->nSession = 0;
    ++}
    ++#else
    ++# define session_close_all(X)
    ++#endif
    ++
    ++/*
    ++** Implementation of the xFilter function for an open session.  Omit
    ++** any tables named by ".session filter" but let all other table through.
    ++*/
    ++#if defined(SQLITE_ENABLE_SESSION)
    ++static int session_filter(void *pCtx, const char *zTab){
    ++  OpenSession *pSession = (OpenSession*)pCtx;
    ++  int i;
    ++  for(i=0; i<pSession->nFilter; i++){
    ++    if( sqlite3_strglob(pSession->azFilter[i], zTab)==0 ) return 0;
    ++  }
    ++  return 1;
    ++}
    ++#endif
    ++
    ++/*
    ++** Try to deduce the type of file for zName based on its content.  Return
    ++** one of the SHELL_OPEN_* constants.
    ++*/
    ++static int deduceDatabaseType(const char *zName){
    ++  FILE *f = fopen(zName, "rb");
    ++  size_t n;
    ++  int rc = SHELL_OPEN_UNSPEC;
    ++  char zBuf[100];
    ++  if( f==0 ) return SHELL_OPEN_NORMAL;
    ++  fseek(f, -25, SEEK_END);
    ++  n = fread(zBuf, 25, 1, f);
    ++  if( n==1 && memcmp(zBuf, "Start-Of-SQLite3-", 17)==0 ){
    ++    rc = SHELL_OPEN_APPENDVFS;
    ++  }else{
    ++    fseek(f, -22, SEEK_END);
    ++    n = fread(zBuf, 22, 1, f);
    ++    if( n==1 && zBuf[0]==0x50 && zBuf[1]==0x4b && zBuf[2]==0x05
    ++       && zBuf[3]==0x06 ){
    ++      rc = SHELL_OPEN_ZIPFILE;
    ++    }
    ++  }
    ++  fclose(f);
    ++  return rc;  
    ++}
    ++
    ++/*
    ++** Make sure the database is open.  If it is not, then open it.  If
    ++** the database fails to open, print an error message and exit.
    ++*/
    ++static void open_db(ShellState *p, int keepAlive){
    ++  if( p->db==0 ){
    ++    sqlite3_initialize();
    ++    if( p->openMode==SHELL_OPEN_UNSPEC && access(p->zDbFilename,0)==0 ){
    ++      p->openMode = deduceDatabaseType(p->zDbFilename);
    ++    }
    ++    switch( p->openMode ){
    ++      case SHELL_OPEN_APPENDVFS: {
    ++        sqlite3_open_v2(p->zDbFilename, &p->db, 
    ++           SQLITE_OPEN_READWRITE|SQLITE_OPEN_CREATE, "apndvfs");
    ++        break;
    ++      }
    ++      case SHELL_OPEN_ZIPFILE: {
    ++        sqlite3_open(":memory:", &p->db);
    ++        break;
    ++      }
    ++      case SHELL_OPEN_UNSPEC:
    ++      case SHELL_OPEN_NORMAL: {
    ++        sqlite3_open(p->zDbFilename, &p->db);
    ++        break;
    ++      }
    ++    }
    ++    globalDb = p->db;
    ++    if( p->db==0 || SQLITE_OK!=sqlite3_errcode(p->db) ){
    ++      utf8_printf(stderr,"Error: unable to open database \"%s\": %s\n",
    ++          p->zDbFilename, sqlite3_errmsg(p->db));
    ++      if( keepAlive ) return;
    ++      exit(1);
    ++    }
    ++#ifndef SQLITE_OMIT_LOAD_EXTENSION
    ++    sqlite3_enable_load_extension(p->db, 1);
    ++#endif
    ++    sqlite3_fileio_init(p->db, 0, 0);
    ++    sqlite3_shathree_init(p->db, 0, 0);
    ++    sqlite3_completion_init(p->db, 0, 0);
    ++#ifdef SQLITE_HAVE_ZLIB
    ++    sqlite3_zipfile_init(p->db, 0, 0);
    ++    sqlite3_sqlar_init(p->db, 0, 0);
    ++#endif
    ++    sqlite3_create_function(p->db, "shell_add_schema", 3, SQLITE_UTF8, 0,
    ++                            shellAddSchemaName, 0, 0);
    ++    sqlite3_create_function(p->db, "shell_module_schema", 1, SQLITE_UTF8, 0,
    ++                            shellModuleSchema, 0, 0);
    ++    sqlite3_create_function(p->db, "shell_putsnl", 1, SQLITE_UTF8, p,
    ++                            shellPutsFunc, 0, 0);
    ++    sqlite3_create_function(p->db, "edit", 1, SQLITE_UTF8, 0,
    ++                            editFunc, 0, 0);
    ++    sqlite3_create_function(p->db, "edit", 2, SQLITE_UTF8, 0,
    ++                            editFunc, 0, 0);
    ++    if( p->openMode==SHELL_OPEN_ZIPFILE ){
    ++      char *zSql = sqlite3_mprintf(
    ++         "CREATE VIRTUAL TABLE zip USING zipfile(%Q);", p->zDbFilename);
    ++      sqlite3_exec(p->db, zSql, 0, 0, 0);
    ++      sqlite3_free(zSql);
    ++    }
    ++  }
    ++}
    ++
    ++#if HAVE_READLINE || HAVE_EDITLINE
    ++/*
    ++** Readline completion callbacks
    ++*/
    ++static char *readline_completion_generator(const char *text, int state){
    ++  static sqlite3_stmt *pStmt = 0;
    ++  char *zRet;
    ++  if( state==0 ){
    ++    char *zSql;
    ++    sqlite3_finalize(pStmt);
    ++    zSql = sqlite3_mprintf("SELECT DISTINCT candidate COLLATE nocase"
    ++                           "  FROM completion(%Q) ORDER BY 1", text);
    ++    sqlite3_prepare_v2(globalDb, zSql, -1, &pStmt, 0);
    ++    sqlite3_free(zSql);
    ++  }
    ++  if( sqlite3_step(pStmt)==SQLITE_ROW ){
    ++    zRet = strdup((const char*)sqlite3_column_text(pStmt, 0));
    ++  }else{
    ++    sqlite3_finalize(pStmt);
    ++    pStmt = 0;
    ++    zRet = 0;
    ++  }
    ++  return zRet;
    ++}
    ++static char **readline_completion(const char *zText, int iStart, int iEnd){
    ++  rl_attempted_completion_over = 1;
    ++  return rl_completion_matches(zText, readline_completion_generator);
    ++}
    ++
    ++#elif HAVE_LINENOISE
    ++/*
    ++** Linenoise completion callback
    ++*/
    ++static void linenoise_completion(const char *zLine, linenoiseCompletions *lc){
    ++  int nLine = strlen30(zLine);
    ++  int i, iStart;
    ++  sqlite3_stmt *pStmt = 0;
    ++  char *zSql;
    ++  char zBuf[1000];
    ++
    ++  if( nLine>sizeof(zBuf)-30 ) return;
    ++  if( zLine[0]=='.' ) return;
    ++  for(i=nLine-1; i>=0 && (isalnum(zLine[i]) || zLine[i]=='_'); i--){}
    ++  if( i==nLine-1 ) return;
    ++  iStart = i+1;
    ++  memcpy(zBuf, zLine, iStart);
    ++  zSql = sqlite3_mprintf("SELECT DISTINCT candidate COLLATE nocase"
    ++                         "  FROM completion(%Q,%Q) ORDER BY 1",
    ++                         &zLine[iStart], zLine);
    ++  sqlite3_prepare_v2(globalDb, zSql, -1, &pStmt, 0);
    ++  sqlite3_free(zSql);
    ++  sqlite3_exec(globalDb, "PRAGMA page_count", 0, 0, 0); /* Load the schema */
    ++  while( sqlite3_step(pStmt)==SQLITE_ROW ){
    ++    const char *zCompletion = (const char*)sqlite3_column_text(pStmt, 0);
    ++    int nCompletion = sqlite3_column_bytes(pStmt, 0);
    ++    if( iStart+nCompletion < sizeof(zBuf)-1 ){
    ++      memcpy(zBuf+iStart, zCompletion, nCompletion+1);
    ++      linenoiseAddCompletion(lc, zBuf);
    ++    }
    ++  }
    ++  sqlite3_finalize(pStmt);
    ++}
    ++#endif
    ++
    ++/*
    ++** Do C-language style dequoting.
    ++**
    ++**    \a    -> alarm
    ++**    \b    -> backspace
    ++**    \t    -> tab
    ++**    \n    -> newline
    ++**    \v    -> vertical tab
    ++**    \f    -> form feed
    ++**    \r    -> carriage return
    ++**    \s    -> space
    ++**    \"    -> "
    ++**    \'    -> '
    ++**    \\    -> backslash
    ++**    \NNN  -> ascii character NNN in octal
    ++*/
    ++static void resolve_backslashes(char *z){
    ++  int i, j;
    ++  char c;
    ++  while( *z && *z!='\\' ) z++;
    ++  for(i=j=0; (c = z[i])!=0; i++, j++){
    ++    if( c=='\\' && z[i+1]!=0 ){
    ++      c = z[++i];
    ++      if( c=='a' ){
    ++        c = '\a';
    ++      }else if( c=='b' ){
    ++        c = '\b';
    ++      }else if( c=='t' ){
    ++        c = '\t';
    ++      }else if( c=='n' ){
    ++        c = '\n';
    ++      }else if( c=='v' ){
    ++        c = '\v';
    ++      }else if( c=='f' ){
    ++        c = '\f';
    ++      }else if( c=='r' ){
    ++        c = '\r';
    ++      }else if( c=='"' ){
    ++        c = '"';
    ++      }else if( c=='\'' ){
    ++        c = '\'';
    ++      }else if( c=='\\' ){
    ++        c = '\\';
    ++      }else if( c>='0' && c<='7' ){
    ++        c -= '0';
    ++        if( z[i+1]>='0' && z[i+1]<='7' ){
    ++          i++;
    ++          c = (c<<3) + z[i] - '0';
    ++          if( z[i+1]>='0' && z[i+1]<='7' ){
    ++            i++;
    ++            c = (c<<3) + z[i] - '0';
    ++          }
    ++        }
    ++      }
    ++    }
    ++    z[j] = c;
    ++  }
    ++  if( j<i ) z[j] = 0;
    ++}
    ++
    ++/*
    ++** Interpret zArg as either an integer or a boolean value.  Return 1 or 0
    ++** for TRUE and FALSE.  Return the integer value if appropriate.
    ++*/
    ++static int booleanValue(const char *zArg){
    ++  int i;
    ++  if( zArg[0]=='0' && zArg[1]=='x' ){
    ++    for(i=2; hexDigitValue(zArg[i])>=0; i++){}
    ++  }else{
    ++    for(i=0; zArg[i]>='0' && zArg[i]<='9'; i++){}
    ++  }
    ++  if( i>0 && zArg[i]==0 ) return (int)(integerValue(zArg) & 0xffffffff);
    ++  if( sqlite3_stricmp(zArg, "on")==0 || sqlite3_stricmp(zArg,"yes")==0 ){
    ++    return 1;
    ++  }
    ++  if( sqlite3_stricmp(zArg, "off")==0 || sqlite3_stricmp(zArg,"no")==0 ){
    ++    return 0;
    ++  }
    ++  utf8_printf(stderr, "ERROR: Not a boolean value: \"%s\". Assuming \"no\".\n",
    ++          zArg);
    ++  return 0;
    ++}
    ++
    ++/*
    ++** Set or clear a shell flag according to a boolean value.
    ++*/
    ++static void setOrClearFlag(ShellState *p, unsigned mFlag, const char *zArg){
    ++  if( booleanValue(zArg) ){
    ++    ShellSetFlag(p, mFlag);
    ++  }else{
    ++    ShellClearFlag(p, mFlag);
    ++  }
    ++}
    ++
    ++/*
    ++** Close an output file, assuming it is not stderr or stdout
    ++*/
    ++static void output_file_close(FILE *f){
    ++  if( f && f!=stdout && f!=stderr ) fclose(f);
    ++}
    ++
    ++/*
    ++** Try to open an output file.   The names "stdout" and "stderr" are
    ++** recognized and do the right thing.  NULL is returned if the output
    ++** filename is "off".
    ++*/
    ++static FILE *output_file_open(const char *zFile, int bTextMode){
    ++  FILE *f;
    ++  if( strcmp(zFile,"stdout")==0 ){
    ++    f = stdout;
    ++  }else if( strcmp(zFile, "stderr")==0 ){
    ++    f = stderr;
    ++  }else if( strcmp(zFile, "off")==0 ){
    ++    f = 0;
    ++  }else{
    ++    f = fopen(zFile, bTextMode ? "w" : "wb");
    ++    if( f==0 ){
    ++      utf8_printf(stderr, "Error: cannot open \"%s\"\n", zFile);
    ++    }
    ++  }
    ++  return f;
    ++}
    ++
    ++#if !defined(SQLITE_UNTESTABLE)
    ++#if !defined(SQLITE_OMIT_TRACE) && !defined(SQLITE_OMIT_FLOATING_POINT)
    ++/*
    ++** A routine for handling output from sqlite3_trace().
    ++*/
    ++static int sql_trace_callback(
    ++  unsigned mType,
    ++  void *pArg,
    ++  void *pP,
    ++  void *pX
    ++){
    ++  FILE *f = (FILE*)pArg;
    ++  UNUSED_PARAMETER(mType);
    ++  UNUSED_PARAMETER(pP);
    ++  if( f ){
    ++    const char *z = (const char*)pX;
    ++    int i = strlen30(z);
    ++    while( i>0 && z[i-1]==';' ){ i--; }
    ++    utf8_printf(f, "%.*s;\n", i, z);
    ++  }
    ++  return 0;
    ++}
    ++#endif
    ++#endif
    ++
    ++/*
    ++** A no-op routine that runs with the ".breakpoint" doc-command.  This is
    ++** a useful spot to set a debugger breakpoint.
    ++*/
    ++static void test_breakpoint(void){
    ++  static int nCall = 0;
    ++  nCall++;
    ++}
    ++
    ++/*
    ++** An object used to read a CSV and other files for import.
    ++*/
    ++typedef struct ImportCtx ImportCtx;
    ++struct ImportCtx {
    ++  const char *zFile;  /* Name of the input file */
    ++  FILE *in;           /* Read the CSV text from this input stream */
    ++  char *z;            /* Accumulated text for a field */
    ++  int n;              /* Number of bytes in z */
    ++  int nAlloc;         /* Space allocated for z[] */
    ++  int nLine;          /* Current line number */
    ++  int bNotFirst;      /* True if one or more bytes already read */
    ++  int cTerm;          /* Character that terminated the most recent field */
    ++  int cColSep;        /* The column separator character.  (Usually ",") */
    ++  int cRowSep;        /* The row separator character.  (Usually "\n") */
    ++};
    ++
    ++/* Append a single byte to z[] */
    ++static void import_append_char(ImportCtx *p, int c){
    ++  if( p->n+1>=p->nAlloc ){
    ++    p->nAlloc += p->nAlloc + 100;
    ++    p->z = sqlite3_realloc64(p->z, p->nAlloc);
    ++    if( p->z==0 ){
    ++      raw_printf(stderr, "out of memory\n");
    ++      exit(1);
    ++    }
    ++  }
    ++  p->z[p->n++] = (char)c;
    ++}
    ++
    ++/* Read a single field of CSV text.  Compatible with rfc4180 and extended
    ++** with the option of having a separator other than ",".
    ++**
    ++**   +  Input comes from p->in.
    ++**   +  Store results in p->z of length p->n.  Space to hold p->z comes
    ++**      from sqlite3_malloc64().
    ++**   +  Use p->cSep as the column separator.  The default is ",".
    ++**   +  Use p->rSep as the row separator.  The default is "\n".
    ++**   +  Keep track of the line number in p->nLine.
    ++**   +  Store the character that terminates the field in p->cTerm.  Store
    ++**      EOF on end-of-file.
    ++**   +  Report syntax errors on stderr
    ++*/
    ++static char *SQLITE_CDECL csv_read_one_field(ImportCtx *p){
    ++  int c;
    ++  int cSep = p->cColSep;
    ++  int rSep = p->cRowSep;
    ++  p->n = 0;
    ++  c = fgetc(p->in);
    ++  if( c==EOF || seenInterrupt ){
    ++    p->cTerm = EOF;
    ++    return 0;
    ++  }
    ++  if( c=='"' ){
    ++    int pc, ppc;
    ++    int startLine = p->nLine;
    ++    int cQuote = c;
    ++    pc = ppc = 0;
    ++    while( 1 ){
    ++      c = fgetc(p->in);
    ++      if( c==rSep ) p->nLine++;
    ++      if( c==cQuote ){
    ++        if( pc==cQuote ){
    ++          pc = 0;
    ++          continue;
    ++        }
    ++      }
    ++      if( (c==cSep && pc==cQuote)
    ++       || (c==rSep && pc==cQuote)
    ++       || (c==rSep && pc=='\r' && ppc==cQuote)
    ++       || (c==EOF && pc==cQuote)
    ++      ){
    ++        do{ p->n--; }while( p->z[p->n]!=cQuote );
    ++        p->cTerm = c;
    ++        break;
    ++      }
    ++      if( pc==cQuote && c!='\r' ){
    ++        utf8_printf(stderr, "%s:%d: unescaped %c character\n",
    ++                p->zFile, p->nLine, cQuote);
    ++      }
    ++      if( c==EOF ){
    ++        utf8_printf(stderr, "%s:%d: unterminated %c-quoted field\n",
    ++                p->zFile, startLine, cQuote);
    ++        p->cTerm = c;
    ++        break;
    ++      }
    ++      import_append_char(p, c);
    ++      ppc = pc;
    ++      pc = c;
    ++    }
    ++  }else{
    ++    /* If this is the first field being parsed and it begins with the
    ++    ** UTF-8 BOM  (0xEF BB BF) then skip the BOM */
    ++    if( (c&0xff)==0xef && p->bNotFirst==0 ){
    ++      import_append_char(p, c);
    ++      c = fgetc(p->in);
    ++      if( (c&0xff)==0xbb ){
    ++        import_append_char(p, c);
    ++        c = fgetc(p->in);
    ++        if( (c&0xff)==0xbf ){
    ++          p->bNotFirst = 1;
    ++          p->n = 0;
    ++          return csv_read_one_field(p);
    ++        }
    ++      }
    ++    }
    ++    while( c!=EOF && c!=cSep && c!=rSep ){
    ++      import_append_char(p, c);
    ++      c = fgetc(p->in);
    ++    }
    ++    if( c==rSep ){
    ++      p->nLine++;
    ++      if( p->n>0 && p->z[p->n-1]=='\r' ) p->n--;
    ++    }
    ++    p->cTerm = c;
    ++  }
    ++  if( p->z ) p->z[p->n] = 0;
    ++  p->bNotFirst = 1;
    ++  return p->z;
    ++}
    ++
    ++/* Read a single field of ASCII delimited text.
    ++**
    ++**   +  Input comes from p->in.
    ++**   +  Store results in p->z of length p->n.  Space to hold p->z comes
    ++**      from sqlite3_malloc64().
    ++**   +  Use p->cSep as the column separator.  The default is "\x1F".
    ++**   +  Use p->rSep as the row separator.  The default is "\x1E".
    ++**   +  Keep track of the row number in p->nLine.
    ++**   +  Store the character that terminates the field in p->cTerm.  Store
    ++**      EOF on end-of-file.
    ++**   +  Report syntax errors on stderr
    ++*/
    ++static char *SQLITE_CDECL ascii_read_one_field(ImportCtx *p){
    ++  int c;
    ++  int cSep = p->cColSep;
    ++  int rSep = p->cRowSep;
    ++  p->n = 0;
    ++  c = fgetc(p->in);
    ++  if( c==EOF || seenInterrupt ){
    ++    p->cTerm = EOF;
    ++    return 0;
    ++  }
    ++  while( c!=EOF && c!=cSep && c!=rSep ){
    ++    import_append_char(p, c);
    ++    c = fgetc(p->in);
    ++  }
    ++  if( c==rSep ){
    ++    p->nLine++;
    ++  }
    ++  p->cTerm = c;
    ++  if( p->z ) p->z[p->n] = 0;
    ++  return p->z;
    ++}
    ++
    ++/*
    ++** Try to transfer data for table zTable.  If an error is seen while
    ++** moving forward, try to go backwards.  The backwards movement won't
    ++** work for WITHOUT ROWID tables.
    ++*/
    ++static void tryToCloneData(
    ++  ShellState *p,
    ++  sqlite3 *newDb,
    ++  const char *zTable
    ++){
    ++  sqlite3_stmt *pQuery = 0;
    ++  sqlite3_stmt *pInsert = 0;
    ++  char *zQuery = 0;
    ++  char *zInsert = 0;
    ++  int rc;
    ++  int i, j, n;
    ++  int nTable = strlen30(zTable);
    ++  int k = 0;
    ++  int cnt = 0;
    ++  const int spinRate = 10000;
    ++
    ++  zQuery = sqlite3_mprintf("SELECT * FROM \"%w\"", zTable);
    ++  rc = sqlite3_prepare_v2(p->db, zQuery, -1, &pQuery, 0);
    ++  if( rc ){
    ++    utf8_printf(stderr, "Error %d: %s on [%s]\n",
    ++            sqlite3_extended_errcode(p->db), sqlite3_errmsg(p->db),
    ++            zQuery);
    ++    goto end_data_xfer;
    ++  }
    ++  n = sqlite3_column_count(pQuery);
    ++  zInsert = sqlite3_malloc64(200 + nTable + n*3);
    ++  if( zInsert==0 ){
    ++    raw_printf(stderr, "out of memory\n");
    ++    goto end_data_xfer;
    ++  }
    ++  sqlite3_snprintf(200+nTable,zInsert,
    ++                   "INSERT OR IGNORE INTO \"%s\" VALUES(?", zTable);
    ++  i = strlen30(zInsert);
    ++  for(j=1; j<n; j++){
    ++    memcpy(zInsert+i, ",?", 2);
    ++    i += 2;
    ++  }
    ++  memcpy(zInsert+i, ");", 3);
    ++  rc = sqlite3_prepare_v2(newDb, zInsert, -1, &pInsert, 0);
    ++  if( rc ){
    ++    utf8_printf(stderr, "Error %d: %s on [%s]\n",
    ++            sqlite3_extended_errcode(newDb), sqlite3_errmsg(newDb),
    ++            zQuery);
    ++    goto end_data_xfer;
    ++  }
    ++  for(k=0; k<2; k++){
    ++    while( (rc = sqlite3_step(pQuery))==SQLITE_ROW ){
    ++      for(i=0; i<n; i++){
    ++        switch( sqlite3_column_type(pQuery, i) ){
    ++          case SQLITE_NULL: {
    ++            sqlite3_bind_null(pInsert, i+1);
    ++            break;
    ++          }
    ++          case SQLITE_INTEGER: {
    ++            sqlite3_bind_int64(pInsert, i+1, sqlite3_column_int64(pQuery,i));
    ++            break;
    ++          }
    ++          case SQLITE_FLOAT: {
    ++            sqlite3_bind_double(pInsert, i+1, sqlite3_column_double(pQuery,i));
    ++            break;
    ++          }
    ++          case SQLITE_TEXT: {
    ++            sqlite3_bind_text(pInsert, i+1,
    ++                             (const char*)sqlite3_column_text(pQuery,i),
    ++                             -1, SQLITE_STATIC);
    ++            break;
    ++          }
    ++          case SQLITE_BLOB: {
    ++            sqlite3_bind_blob(pInsert, i+1, sqlite3_column_blob(pQuery,i),
    ++                                            sqlite3_column_bytes(pQuery,i),
    ++                                            SQLITE_STATIC);
    ++            break;
    ++          }
    ++        }
    ++      } /* End for */
    ++      rc = sqlite3_step(pInsert);
    ++      if( rc!=SQLITE_OK && rc!=SQLITE_ROW && rc!=SQLITE_DONE ){
    ++        utf8_printf(stderr, "Error %d: %s\n", sqlite3_extended_errcode(newDb),
    ++                        sqlite3_errmsg(newDb));
    ++      }
    ++      sqlite3_reset(pInsert);
    ++      cnt++;
    ++      if( (cnt%spinRate)==0 ){
    ++        printf("%c\b", "|/-\\"[(cnt/spinRate)%4]);
    ++        fflush(stdout);
    ++      }
    ++    } /* End while */
    ++    if( rc==SQLITE_DONE ) break;
    ++    sqlite3_finalize(pQuery);
    ++    sqlite3_free(zQuery);
    ++    zQuery = sqlite3_mprintf("SELECT * FROM \"%w\" ORDER BY rowid DESC;",
    ++                             zTable);
    ++    rc = sqlite3_prepare_v2(p->db, zQuery, -1, &pQuery, 0);
    ++    if( rc ){
    ++      utf8_printf(stderr, "Warning: cannot step \"%s\" backwards", zTable);
    ++      break;
    ++    }
    ++  } /* End for(k=0...) */
    ++
    ++end_data_xfer:
    ++  sqlite3_finalize(pQuery);
    ++  sqlite3_finalize(pInsert);
    ++  sqlite3_free(zQuery);
    ++  sqlite3_free(zInsert);
    ++}
    ++
    ++
    ++/*
    ++** Try to transfer all rows of the schema that match zWhere.  For
    ++** each row, invoke xForEach() on the object defined by that row.
    ++** If an error is encountered while moving forward through the
    ++** sqlite_master table, try again moving backwards.
    ++*/
    ++static void tryToCloneSchema(
    ++  ShellState *p,
    ++  sqlite3 *newDb,
    ++  const char *zWhere,
    ++  void (*xForEach)(ShellState*,sqlite3*,const char*)
    ++){
    ++  sqlite3_stmt *pQuery = 0;
    ++  char *zQuery = 0;
    ++  int rc;
    ++  const unsigned char *zName;
    ++  const unsigned char *zSql;
    ++  char *zErrMsg = 0;
    ++
    ++  zQuery = sqlite3_mprintf("SELECT name, sql FROM sqlite_master"
    ++                           " WHERE %s", zWhere);
    ++  rc = sqlite3_prepare_v2(p->db, zQuery, -1, &pQuery, 0);
    ++  if( rc ){
    ++    utf8_printf(stderr, "Error: (%d) %s on [%s]\n",
    ++                    sqlite3_extended_errcode(p->db), sqlite3_errmsg(p->db),
    ++                    zQuery);
    ++    goto end_schema_xfer;
    ++  }
    ++  while( (rc = sqlite3_step(pQuery))==SQLITE_ROW ){
    ++    zName = sqlite3_column_text(pQuery, 0);
    ++    zSql = sqlite3_column_text(pQuery, 1);
    ++    printf("%s... ", zName); fflush(stdout);
    ++    sqlite3_exec(newDb, (const char*)zSql, 0, 0, &zErrMsg);
    ++    if( zErrMsg ){
    ++      utf8_printf(stderr, "Error: %s\nSQL: [%s]\n", zErrMsg, zSql);
    ++      sqlite3_free(zErrMsg);
    ++      zErrMsg = 0;
    ++    }
    ++    if( xForEach ){
    ++      xForEach(p, newDb, (const char*)zName);
    ++    }
    ++    printf("done\n");
    ++  }
    ++  if( rc!=SQLITE_DONE ){
    ++    sqlite3_finalize(pQuery);
    ++    sqlite3_free(zQuery);
    ++    zQuery = sqlite3_mprintf("SELECT name, sql FROM sqlite_master"
    ++                             " WHERE %s ORDER BY rowid DESC", zWhere);
    ++    rc = sqlite3_prepare_v2(p->db, zQuery, -1, &pQuery, 0);
    ++    if( rc ){
    ++      utf8_printf(stderr, "Error: (%d) %s on [%s]\n",
    ++                      sqlite3_extended_errcode(p->db), sqlite3_errmsg(p->db),
    ++                      zQuery);
    ++      goto end_schema_xfer;
    ++    }
    ++    while( (rc = sqlite3_step(pQuery))==SQLITE_ROW ){
    ++      zName = sqlite3_column_text(pQuery, 0);
    ++      zSql = sqlite3_column_text(pQuery, 1);
    ++      printf("%s... ", zName); fflush(stdout);
    ++      sqlite3_exec(newDb, (const char*)zSql, 0, 0, &zErrMsg);
    ++      if( zErrMsg ){
    ++        utf8_printf(stderr, "Error: %s\nSQL: [%s]\n", zErrMsg, zSql);
    ++        sqlite3_free(zErrMsg);
    ++        zErrMsg = 0;
    ++      }
    ++      if( xForEach ){
    ++        xForEach(p, newDb, (const char*)zName);
    ++      }
    ++      printf("done\n");
    ++    }
    ++  }
    ++end_schema_xfer:
    ++  sqlite3_finalize(pQuery);
    ++  sqlite3_free(zQuery);
    ++}
    ++
    ++/*
    ++** Open a new database file named "zNewDb".  Try to recover as much information
    ++** as possible out of the main database (which might be corrupt) and write it
    ++** into zNewDb.
    ++*/
    ++static void tryToClone(ShellState *p, const char *zNewDb){
    ++  int rc;
    ++  sqlite3 *newDb = 0;
    ++  if( access(zNewDb,0)==0 ){
    ++    utf8_printf(stderr, "File \"%s\" already exists.\n", zNewDb);
    ++    return;
    ++  }
    ++  rc = sqlite3_open(zNewDb, &newDb);
    ++  if( rc ){
    ++    utf8_printf(stderr, "Cannot create output database: %s\n",
    ++            sqlite3_errmsg(newDb));
    ++  }else{
    ++    sqlite3_exec(p->db, "PRAGMA writable_schema=ON;", 0, 0, 0);
    ++    sqlite3_exec(newDb, "BEGIN EXCLUSIVE;", 0, 0, 0);
    ++    tryToCloneSchema(p, newDb, "type='table'", tryToCloneData);
    ++    tryToCloneSchema(p, newDb, "type!='table'", 0);
    ++    sqlite3_exec(newDb, "COMMIT;", 0, 0, 0);
    ++    sqlite3_exec(p->db, "PRAGMA writable_schema=OFF;", 0, 0, 0);
    +   }
    +-  fclose(out);
    +-  sqlite3_result_int64(context, rc);
    ++  sqlite3_close(newDb);
    + }
    + 
    + /*
    +-** Make sure the database is open.  If it is not, then open it.  If
    +-** the database fails to open, print an error message and exit.
    ++** Change the output file back to stdout.
    ++**
    ++** If the p->doXdgOpen flag is set, that means the output was being
    ++** redirected to a temporary file named by p->zTempFile.  In that case,
    ++** launch start/open/xdg-open on that temporary file.
    + */
    +-static void open_db(ShellState *p, int keepAlive){
    +-  if( p->db==0 ){
    +-    sqlite3_initialize();
    +-    sqlite3_open(p->zDbFilename, &p->db);
    +-    globalDb = p->db;
    +-    if( p->db && sqlite3_errcode(p->db)==SQLITE_OK ){
    +-      sqlite3_create_function(p->db, "shellstatic", 0, SQLITE_UTF8, 0,
    +-          shellstaticFunc, 0, 0);
    +-    }
    +-    if( p->db==0 || SQLITE_OK!=sqlite3_errcode(p->db) ){
    +-      fprintf(stderr,"Error: unable to open database \"%s\": %s\n", 
    +-          p->zDbFilename, sqlite3_errmsg(p->db));
    +-      if( keepAlive ) return;
    +-      exit(1);
    +-    }
    +-#ifndef SQLITE_OMIT_LOAD_EXTENSION
    +-    sqlite3_enable_load_extension(p->db, 1);
    ++static void output_reset(ShellState *p){
    ++  if( p->outfile[0]=='|' ){
    ++#ifndef SQLITE_OMIT_POPEN
    ++    pclose(p->out);
    + #endif
    +-    sqlite3_create_function(p->db, "readfile", 1, SQLITE_UTF8, 0,
    +-                            readfileFunc, 0, 0);
    +-    sqlite3_create_function(p->db, "writefile", 2, SQLITE_UTF8, 0,
    +-                            writefileFunc, 0, 0);
    ++  }else{
    ++    output_file_close(p->out);
    ++    if( p->doXdgOpen ){
    ++      const char *zXdgOpenCmd =
    ++#if defined(_WIN32)
    ++      "start";
    ++#elif defined(__APPLE__)
    ++      "open";
    ++#else
    ++      "xdg-open";
    ++#endif
    ++      char *zCmd;
    ++      zCmd = sqlite3_mprintf("%s %s", zXdgOpenCmd, p->zTempFile);
    ++      if( system(zCmd) ){
    ++        utf8_printf(stderr, "Failed: [%s]\n", zCmd);
    ++      }
    ++      sqlite3_free(zCmd);
    ++      outputModePop(p);
    ++      p->doXdgOpen = 0;
    ++    }
    +   }
    ++  p->outfile[0] = 0;
    ++  p->out = stdout;
    + }
    + 
    + /*
    +-** Do C-language style dequoting.
    +-**
    +-**    \a    -> alarm
    +-**    \b    -> backspace
    +-**    \t    -> tab
    +-**    \n    -> newline
    +-**    \v    -> vertical tab
    +-**    \f    -> form feed
    +-**    \r    -> carriage return
    +-**    \s    -> space
    +-**    \"    -> "
    +-**    \'    -> '
    +-**    \\    -> backslash
    +-**    \NNN  -> ascii character NNN in octal
    ++** Run an SQL command and return the single integer result.
    + */
    +-static void resolve_backslashes(char *z){
    +-  int i, j;
    +-  char c;
    +-  while( *z && *z!='\\' ) z++;
    +-  for(i=j=0; (c = z[i])!=0; i++, j++){
    +-    if( c=='\\' && z[i+1]!=0 ){
    +-      c = z[++i];
    +-      if( c=='a' ){
    +-        c = '\a';
    +-      }else if( c=='b' ){
    +-        c = '\b';
    +-      }else if( c=='t' ){
    +-        c = '\t';
    +-      }else if( c=='n' ){
    +-        c = '\n';
    +-      }else if( c=='v' ){
    +-        c = '\v';
    +-      }else if( c=='f' ){
    +-        c = '\f';
    +-      }else if( c=='r' ){
    +-        c = '\r';
    +-      }else if( c=='"' ){
    +-        c = '"';
    +-      }else if( c=='\'' ){
    +-        c = '\'';
    +-      }else if( c=='\\' ){
    +-        c = '\\';
    +-      }else if( c>='0' && c<='7' ){
    +-        c -= '0';
    +-        if( z[i+1]>='0' && z[i+1]<='7' ){
    +-          i++;
    +-          c = (c<<3) + z[i] - '0';
    +-          if( z[i+1]>='0' && z[i+1]<='7' ){
    +-            i++;
    +-            c = (c<<3) + z[i] - '0';
    +-          }
    +-        }
    +-      }
    +-    }
    +-    z[j] = c;
    ++static int db_int(ShellState *p, const char *zSql){
    ++  sqlite3_stmt *pStmt;
    ++  int res = 0;
    ++  sqlite3_prepare_v2(p->db, zSql, -1, &pStmt, 0);
    ++  if( pStmt && sqlite3_step(pStmt)==SQLITE_ROW ){
    ++    res = sqlite3_column_int(pStmt,0);
    +   }
    +-  if( j<i ) z[j] = 0;
    ++  sqlite3_finalize(pStmt);
    ++  return res;
    + }
    + 
    + /*
    +-** Return the value of a hexadecimal digit.  Return -1 if the input
    +-** is not a hex digit.
    ++** Convert a 2-byte or 4-byte big-endian integer into a native integer
    + */
    +-static int hexDigitValue(char c){
    +-  if( c>='0' && c<='9' ) return c - '0';
    +-  if( c>='a' && c<='f' ) return c - 'a' + 10;
    +-  if( c>='A' && c<='F' ) return c - 'A' + 10;
    +-  return -1;
    ++static unsigned int get2byteInt(unsigned char *a){
    ++  return (a[0]<<8) + a[1];
    ++}
    ++static unsigned int get4byteInt(unsigned char *a){
    ++  return (a[0]<<24) + (a[1]<<16) + (a[2]<<8) + a[3];
    + }
    + 
    + /*
    +-** Interpret zArg as an integer value, possibly with suffixes.
    ++** Implementation of the ".info" command.
    ++**
    ++** Return 1 on error, 2 to exit, and 0 otherwise.
    + */
    +-static sqlite3_int64 integerValue(const char *zArg){
    +-  sqlite3_int64 v = 0;
    +-  static const struct { char *zSuffix; int iMult; } aMult[] = {
    +-    { "KiB", 1024 },
    +-    { "MiB", 1024*1024 },
    +-    { "GiB", 1024*1024*1024 },
    +-    { "KB",  1000 },
    +-    { "MB",  1000000 },
    +-    { "GB",  1000000000 },
    +-    { "K",   1000 },
    +-    { "M",   1000000 },
    +-    { "G",   1000000000 },
    ++static int shell_dbinfo_command(ShellState *p, int nArg, char **azArg){
    ++  static const struct { const char *zName; int ofst; } aField[] = {
    ++     { "file change counter:",  24  },
    ++     { "database page count:",  28  },
    ++     { "freelist page count:",  36  },
    ++     { "schema cookie:",        40  },
    ++     { "schema format:",        44  },
    ++     { "default cache size:",   48  },
    ++     { "autovacuum top root:",  52  },
    ++     { "incremental vacuum:",   64  },
    ++     { "text encoding:",        56  },
    ++     { "user version:",         60  },
    ++     { "application id:",       68  },
    ++     { "software version:",     96  },
    ++  };
    ++  static const struct { const char *zName; const char *zSql; } aQuery[] = {
    ++     { "number of tables:",
    ++       "SELECT count(*) FROM %s WHERE type='table'" },
    ++     { "number of indexes:",
    ++       "SELECT count(*) FROM %s WHERE type='index'" },
    ++     { "number of triggers:",
    ++       "SELECT count(*) FROM %s WHERE type='trigger'" },
    ++     { "number of views:",
    ++       "SELECT count(*) FROM %s WHERE type='view'" },
    ++     { "schema size:",
    ++       "SELECT total(length(sql)) FROM %s" },
    +   };
    +   int i;
    +-  int isNeg = 0;
    +-  if( zArg[0]=='-' ){
    +-    isNeg = 1;
    +-    zArg++;
    +-  }else if( zArg[0]=='+' ){
    +-    zArg++;
    ++  char *zSchemaTab;
    ++  char *zDb = nArg>=2 ? azArg[1] : "main";
    ++  sqlite3_stmt *pStmt = 0;
    ++  unsigned char aHdr[100];
    ++  open_db(p, 0);
    ++  if( p->db==0 ) return 1;
    ++  sqlite3_prepare_v2(p->db,"SELECT data FROM sqlite_dbpage(?1) WHERE pgno=1",
    ++                     -1, &pStmt, 0);
    ++  sqlite3_bind_text(pStmt, 1, zDb, -1, SQLITE_STATIC);
    ++  if( sqlite3_step(pStmt)==SQLITE_ROW
    ++   && sqlite3_column_bytes(pStmt,0)>100
    ++  ){
    ++    memcpy(aHdr, sqlite3_column_blob(pStmt,0), 100);
    ++    sqlite3_finalize(pStmt);
    ++  }else{
    ++    raw_printf(stderr, "unable to read database header\n");
    ++    sqlite3_finalize(pStmt);
    ++    return 1;
    +   }
    +-  if( zArg[0]=='0' && zArg[1]=='x' ){
    +-    int x;
    +-    zArg += 2;
    +-    while( (x = hexDigitValue(zArg[0]))>=0 ){
    +-      v = (v<<4) + x;
    +-      zArg++;
    ++  i = get2byteInt(aHdr+16);
    ++  if( i==1 ) i = 65536;
    ++  utf8_printf(p->out, "%-20s %d\n", "database page size:", i);
    ++  utf8_printf(p->out, "%-20s %d\n", "write format:", aHdr[18]);
    ++  utf8_printf(p->out, "%-20s %d\n", "read format:", aHdr[19]);
    ++  utf8_printf(p->out, "%-20s %d\n", "reserved bytes:", aHdr[20]);
    ++  for(i=0; i<ArraySize(aField); i++){
    ++    int ofst = aField[i].ofst;
    ++    unsigned int val = get4byteInt(aHdr + ofst);
    ++    utf8_printf(p->out, "%-20s %u", aField[i].zName, val);
    ++    switch( ofst ){
    ++      case 56: {
    ++        if( val==1 ) raw_printf(p->out, " (utf8)");
    ++        if( val==2 ) raw_printf(p->out, " (utf16le)");
    ++        if( val==3 ) raw_printf(p->out, " (utf16be)");
    ++      }
    +     }
    ++    raw_printf(p->out, "\n");
    ++  }
    ++  if( zDb==0 ){
    ++    zSchemaTab = sqlite3_mprintf("main.sqlite_master");
    ++  }else if( strcmp(zDb,"temp")==0 ){
    ++    zSchemaTab = sqlite3_mprintf("%s", "sqlite_temp_master");
    +   }else{
    +-    while( IsDigit(zArg[0]) ){
    +-      v = v*10 + zArg[0] - '0';
    +-      zArg++;
    +-    }
    ++    zSchemaTab = sqlite3_mprintf("\"%w\".sqlite_master", zDb);
    +   }
    +-  for(i=0; i<ArraySize(aMult); i++){
    +-    if( sqlite3_stricmp(aMult[i].zSuffix, zArg)==0 ){
    +-      v *= aMult[i].iMult;
    +-      break;
    +-    }
    ++  for(i=0; i<ArraySize(aQuery); i++){
    ++    char *zSql = sqlite3_mprintf(aQuery[i].zSql, zSchemaTab);
    ++    int val = db_int(p, zSql);
    ++    sqlite3_free(zSql);
    ++    utf8_printf(p->out, "%-20s %d\n", aQuery[i].zName, val);
    +   }
    +-  return isNeg? -v : v;
    ++  sqlite3_free(zSchemaTab);
    ++  return 0;
    + }
    + 
    + /*
    +-** Interpret zArg as either an integer or a boolean value.  Return 1 or 0
    +-** for TRUE and FALSE.  Return the integer value if appropriate.
    ++** Print the current sqlite3_errmsg() value to stderr and return 1.
    + */
    +-static int booleanValue(char *zArg){
    +-  int i;
    +-  if( zArg[0]=='0' && zArg[1]=='x' ){
    +-    for(i=2; hexDigitValue(zArg[i])>=0; i++){}
    +-  }else{
    +-    for(i=0; zArg[i]>='0' && zArg[i]<='9'; i++){}
    +-  }
    +-  if( i>0 && zArg[i]==0 ) return (int)(integerValue(zArg) & 0xffffffff);
    +-  if( sqlite3_stricmp(zArg, "on")==0 || sqlite3_stricmp(zArg,"yes")==0 ){
    +-    return 1;
    +-  }
    +-  if( sqlite3_stricmp(zArg, "off")==0 || sqlite3_stricmp(zArg,"no")==0 ){
    +-    return 0;
    +-  }
    +-  fprintf(stderr, "ERROR: Not a boolean value: \"%s\". Assuming \"no\".\n",
    +-          zArg);
    +-  return 0;
    ++static int shellDatabaseError(sqlite3 *db){
    ++  const char *zErr = sqlite3_errmsg(db);
    ++  utf8_printf(stderr, "Error: %s\n", zErr);
    ++  return 1;
    + }
    + 
    + /*
    +-** Close an output file, assuming it is not stderr or stdout
    ++** Print an out-of-memory message to stderr and return 1.
    + */
    +-static void output_file_close(FILE *f){
    +-  if( f && f!=stdout && f!=stderr ) fclose(f);
    ++static int shellNomemError(void){
    ++  raw_printf(stderr, "Error: out of memory\n");
    ++  return 1;
    + }
    + 
    + /*
    +-** Try to open an output file.   The names "stdout" and "stderr" are
    +-** recognized and do the right thing.  NULL is returned if the output 
    +-** filename is "off".
    ++** Compare the pattern in zGlob[] against the text in z[].  Return TRUE
    ++** if they match and FALSE (0) if they do not match.
    ++**
    ++** Globbing rules:
    ++**
    ++**      '*'       Matches any sequence of zero or more characters.
    ++**
    ++**      '?'       Matches exactly one character.
    ++**
    ++**     [...]      Matches one character from the enclosed list of
    ++**                characters.
    ++**
    ++**     [^...]     Matches one character not in the enclosed list.
    ++**
    ++**      '#'       Matches any sequence of one or more digits with an
    ++**                optional + or - sign in front
    ++**
    ++**      ' '       Any span of whitespace matches any other span of
    ++**                whitespace.
    ++**
    ++** Extra whitespace at the end of z[] is ignored.
    + */
    +-static FILE *output_file_open(const char *zFile){
    +-  FILE *f;
    +-  if( strcmp(zFile,"stdout")==0 ){
    +-    f = stdout;
    +-  }else if( strcmp(zFile, "stderr")==0 ){
    +-    f = stderr;
    +-  }else if( strcmp(zFile, "off")==0 ){
    +-    f = 0;
    +-  }else{
    +-    f = fopen(zFile, "wb");
    +-    if( f==0 ){
    +-      fprintf(stderr, "Error: cannot open \"%s\"\n", zFile);
    ++static int testcase_glob(const char *zGlob, const char *z){
    ++  int c, c2;
    ++  int invert;
    ++  int seen;
    ++
    ++  while( (c = (*(zGlob++)))!=0 ){
    ++    if( IsSpace(c) ){
    ++      if( !IsSpace(*z) ) return 0;
    ++      while( IsSpace(*zGlob) ) zGlob++;
    ++      while( IsSpace(*z) ) z++;
    ++    }else if( c=='*' ){
    ++      while( (c=(*(zGlob++))) == '*' || c=='?' ){
    ++        if( c=='?' && (*(z++))==0 ) return 0;
    ++      }
    ++      if( c==0 ){
    ++        return 1;
    ++      }else if( c=='[' ){
    ++        while( *z && testcase_glob(zGlob-1,z)==0 ){
    ++          z++;
    ++        }
    ++        return (*z)!=0;
    ++      }
    ++      while( (c2 = (*(z++)))!=0 ){
    ++        while( c2!=c ){
    ++          c2 = *(z++);
    ++          if( c2==0 ) return 0;
    ++        }
    ++        if( testcase_glob(zGlob,z) ) return 1;
    ++      }
    ++      return 0;
    ++    }else if( c=='?' ){
    ++      if( (*(z++))==0 ) return 0;
    ++    }else if( c=='[' ){
    ++      int prior_c = 0;
    ++      seen = 0;
    ++      invert = 0;
    ++      c = *(z++);
    ++      if( c==0 ) return 0;
    ++      c2 = *(zGlob++);
    ++      if( c2=='^' ){
    ++        invert = 1;
    ++        c2 = *(zGlob++);
    ++      }
    ++      if( c2==']' ){
    ++        if( c==']' ) seen = 1;
    ++        c2 = *(zGlob++);
    ++      }
    ++      while( c2 && c2!=']' ){
    ++        if( c2=='-' && zGlob[0]!=']' && zGlob[0]!=0 && prior_c>0 ){
    ++          c2 = *(zGlob++);
    ++          if( c>=prior_c && c<=c2 ) seen = 1;
    ++          prior_c = 0;
    ++        }else{
    ++          if( c==c2 ){
    ++            seen = 1;
    ++          }
    ++          prior_c = c2;
    ++        }
    ++        c2 = *(zGlob++);
    ++      }
    ++      if( c2==0 || (seen ^ invert)==0 ) return 0;
    ++    }else if( c=='#' ){
    ++      if( (z[0]=='-' || z[0]=='+') && IsDigit(z[1]) ) z++;
    ++      if( !IsDigit(z[0]) ) return 0;
    ++      z++;
    ++      while( IsDigit(z[0]) ){ z++; }
    ++    }else{
    ++      if( c!=(*(z++)) ) return 0;
    +     }
    +   }
    +-  return f;
    ++  while( IsSpace(*z) ){ z++; }
    ++  return *z==0;
    + }
    + 
    ++
    + /*
    +-** A routine for handling output from sqlite3_trace().
    ++** Compare the string as a command-line option with either one or two
    ++** initial "-" characters.
    + */
    +-static void sql_trace_callback(void *pArg, const char *z){
    +-  FILE *f = (FILE*)pArg;
    +-  if( f ){
    +-    int i = (int)strlen(z);
    +-    while( i>0 && z[i-1]==';' ){ i--; }
    +-    fprintf(f, "%.*s;\n", i, z);
    +-  }
    ++static int optionMatch(const char *zStr, const char *zOpt){
    ++  if( zStr[0]!='-' ) return 0;
    ++  zStr++;
    ++  if( zStr[0]=='-' ) zStr++;
    ++  return strcmp(zStr, zOpt)==0;
    + }
    + 
    + /*
    +-** A no-op routine that runs with the ".breakpoint" doc-command.  This is
    +-** a useful spot to set a debugger breakpoint.
    ++** Delete a file.
    + */
    +-static void test_breakpoint(void){
    +-  static int nCall = 0;
    +-  nCall++;
    ++int shellDeleteFile(const char *zFilename){
    ++  int rc;
    ++#ifdef _WIN32
    ++  wchar_t *z = sqlite3_win32_utf8_to_unicode(zFilename);
    ++  rc = _wunlink(z);
    ++  sqlite3_free(z);
    ++#else
    ++  rc = unlink(zFilename);
    ++#endif
    ++  return rc;
    + }
    + 
    + /*
    +-** An object used to read a CSV and other files for import.
    ++** Try to delete the temporary file (if there is one) and free the
    ++** memory used to hold the name of the temp file.
    + */
    +-typedef struct ImportCtx ImportCtx;
    +-struct ImportCtx {
    +-  const char *zFile;  /* Name of the input file */
    +-  FILE *in;           /* Read the CSV text from this input stream */
    +-  char *z;            /* Accumulated text for a field */
    +-  int n;              /* Number of bytes in z */
    +-  int nAlloc;         /* Space allocated for z[] */
    +-  int nLine;          /* Current line number */
    +-  int cTerm;          /* Character that terminated the most recent field */
    +-  int cColSep;        /* The column separator character.  (Usually ",") */
    +-  int cRowSep;        /* The row separator character.  (Usually "\n") */
    +-};
    +-
    +-/* Append a single byte to z[] */
    +-static void import_append_char(ImportCtx *p, int c){
    +-  if( p->n+1>=p->nAlloc ){
    +-    p->nAlloc += p->nAlloc + 100;
    +-    p->z = sqlite3_realloc64(p->z, p->nAlloc);
    +-    if( p->z==0 ){
    +-      fprintf(stderr, "out of memory\n");
    +-      exit(1);
    +-    }
    +-  }
    +-  p->z[p->n++] = (char)c;
    ++static void clearTempFile(ShellState *p){
    ++  if( p->zTempFile==0 ) return;
    ++  if( p->doXdgOpen ) return;
    ++  if( shellDeleteFile(p->zTempFile) ) return;
    ++  sqlite3_free(p->zTempFile);
    ++  p->zTempFile = 0;
    + }
    + 
    +-/* Read a single field of CSV text.  Compatible with rfc4180 and extended
    +-** with the option of having a separator other than ",".
    +-**
    +-**   +  Input comes from p->in.
    +-**   +  Store results in p->z of length p->n.  Space to hold p->z comes
    +-**      from sqlite3_malloc64().
    +-**   +  Use p->cSep as the column separator.  The default is ",".
    +-**   +  Use p->rSep as the row separator.  The default is "\n".
    +-**   +  Keep track of the line number in p->nLine.
    +-**   +  Store the character that terminates the field in p->cTerm.  Store
    +-**      EOF on end-of-file.
    +-**   +  Report syntax errors on stderr
    ++/*
    ++** Create a new temp file name with the given suffix.
    + */
    +-static char *SQLITE_CDECL csv_read_one_field(ImportCtx *p){
    +-  int c;
    +-  int cSep = p->cColSep;
    +-  int rSep = p->cRowSep;
    +-  p->n = 0;
    +-  c = fgetc(p->in);
    +-  if( c==EOF || seenInterrupt ){
    +-    p->cTerm = EOF;
    +-    return 0;
    ++static void newTempFile(ShellState *p, const char *zSuffix){
    ++  clearTempFile(p);
    ++  sqlite3_free(p->zTempFile);
    ++  p->zTempFile = 0;
    ++  if( p->db ){
    ++    sqlite3_file_control(p->db, 0, SQLITE_FCNTL_TEMPFILENAME, &p->zTempFile);
    +   }
    +-  if( c=='"' ){
    +-    int pc, ppc;
    +-    int startLine = p->nLine;
    +-    int cQuote = c;
    +-    pc = ppc = 0;
    +-    while( 1 ){
    +-      c = fgetc(p->in);
    +-      if( c==rSep ) p->nLine++;
    +-      if( c==cQuote ){
    +-        if( pc==cQuote ){
    +-          pc = 0;
    +-          continue;
    +-        }
    +-      }
    +-      if( (c==cSep && pc==cQuote)
    +-       || (c==rSep && pc==cQuote)
    +-       || (c==rSep && pc=='\r' && ppc==cQuote)
    +-       || (c==EOF && pc==cQuote)
    +-      ){
    +-        do{ p->n--; }while( p->z[p->n]!=cQuote );
    +-        p->cTerm = c;
    +-        break;
    +-      }
    +-      if( pc==cQuote && c!='\r' ){
    +-        fprintf(stderr, "%s:%d: unescaped %c character\n",
    +-                p->zFile, p->nLine, cQuote);
    +-      }
    +-      if( c==EOF ){
    +-        fprintf(stderr, "%s:%d: unterminated %c-quoted field\n",
    +-                p->zFile, startLine, cQuote);
    +-        p->cTerm = c;
    +-        break;
    +-      }
    +-      import_append_char(p, c);
    +-      ppc = pc;
    +-      pc = c;
    +-    }
    ++  if( p->zTempFile==0 ){
    ++    sqlite3_uint64 r;
    ++    sqlite3_randomness(sizeof(r), &r);
    ++    p->zTempFile = sqlite3_mprintf("temp%llx.%s", r, zSuffix);
    +   }else{
    +-    while( c!=EOF && c!=cSep && c!=rSep ){
    +-      import_append_char(p, c);
    +-      c = fgetc(p->in);
    +-    }
    +-    if( c==rSep ){
    +-      p->nLine++;
    +-      if( p->n>0 && p->z[p->n-1]=='\r' ) p->n--;
    +-    }
    +-    p->cTerm = c;
    ++    p->zTempFile = sqlite3_mprintf("%z.%s", p->zTempFile, zSuffix);
    ++  }
    ++  if( p->zTempFile==0 ){
    ++    raw_printf(stderr, "out of memory\n");
    ++    exit(1);
    +   }
    +-  if( p->z ) p->z[p->n] = 0;
    +-  return p->z;
    + }
    + 
    +-/* Read a single field of ASCII delimited text.
    ++
    ++/*
    ++** The implementation of SQL scalar function fkey_collate_clause(), used
    ++** by the ".lint fkey-indexes" command. This scalar function is always
    ++** called with four arguments - the parent table name, the parent column name,
    ++** the child table name and the child column name.
    + **
    +-**   +  Input comes from p->in.
    +-**   +  Store results in p->z of length p->n.  Space to hold p->z comes
    +-**      from sqlite3_malloc64().
    +-**   +  Use p->cSep as the column separator.  The default is "\x1F".
    +-**   +  Use p->rSep as the row separator.  The default is "\x1E".
    +-**   +  Keep track of the row number in p->nLine.
    +-**   +  Store the character that terminates the field in p->cTerm.  Store
    +-**      EOF on end-of-file.
    +-**   +  Report syntax errors on stderr
    ++**   fkey_collate_clause('parent-tab', 'parent-col', 'child-tab', 'child-col')
    ++**
    ++** If either of the named tables or columns do not exist, this function
    ++** returns an empty string. An empty string is also returned if both tables
    ++** and columns exist but have the same default collation sequence. Or,
    ++** if both exist but the default collation sequences are different, this
    ++** function returns the string " COLLATE <parent-collation>", where
    ++** <parent-collation> is the default collation sequence of the parent column.
    + */
    +-static char *SQLITE_CDECL ascii_read_one_field(ImportCtx *p){
    +-  int c;
    +-  int cSep = p->cColSep;
    +-  int rSep = p->cRowSep;
    +-  p->n = 0;
    +-  c = fgetc(p->in);
    +-  if( c==EOF || seenInterrupt ){
    +-    p->cTerm = EOF;
    +-    return 0;
    +-  }
    +-  while( c!=EOF && c!=cSep && c!=rSep ){
    +-    import_append_char(p, c);
    +-    c = fgetc(p->in);
    ++static void shellFkeyCollateClause(
    ++  sqlite3_context *pCtx,
    ++  int nVal,
    ++  sqlite3_value **apVal
    ++){
    ++  sqlite3 *db = sqlite3_context_db_handle(pCtx);
    ++  const char *zParent;
    ++  const char *zParentCol;
    ++  const char *zParentSeq;
    ++  const char *zChild;
    ++  const char *zChildCol;
    ++  const char *zChildSeq = 0;  /* Initialize to avoid false-positive warning */
    ++  int rc;
    ++
    ++  assert( nVal==4 );
    ++  zParent = (const char*)sqlite3_value_text(apVal[0]);
    ++  zParentCol = (const char*)sqlite3_value_text(apVal[1]);
    ++  zChild = (const char*)sqlite3_value_text(apVal[2]);
    ++  zChildCol = (const char*)sqlite3_value_text(apVal[3]);
    ++
    ++  sqlite3_result_text(pCtx, "", -1, SQLITE_STATIC);
    ++  rc = sqlite3_table_column_metadata(
    ++      db, "main", zParent, zParentCol, 0, &zParentSeq, 0, 0, 0
    ++  );
    ++  if( rc==SQLITE_OK ){
    ++    rc = sqlite3_table_column_metadata(
    ++        db, "main", zChild, zChildCol, 0, &zChildSeq, 0, 0, 0
    ++    );
    +   }
    +-  if( c==rSep ){
    +-    p->nLine++;
    ++
    ++  if( rc==SQLITE_OK && sqlite3_stricmp(zParentSeq, zChildSeq) ){
    ++    char *z = sqlite3_mprintf(" COLLATE %s", zParentSeq);
    ++    sqlite3_result_text(pCtx, z, -1, SQLITE_TRANSIENT);
    ++    sqlite3_free(z);
    +   }
    +-  p->cTerm = c;
    +-  if( p->z ) p->z[p->n] = 0;
    +-  return p->z;
    + }
    + 
    ++
    + /*
    +-** Try to transfer data for table zTable.  If an error is seen while
    +-** moving forward, try to go backwards.  The backwards movement won't
    +-** work for WITHOUT ROWID tables.
    ++** The implementation of dot-command ".lint fkey-indexes".
    + */
    +-static void tryToCloneData(
    +-  ShellState *p,
    +-  sqlite3 *newDb,
    +-  const char *zTable
    ++static int lintFkeyIndexes(
    ++  ShellState *pState,             /* Current shell tool state */
    ++  char **azArg,                   /* Array of arguments passed to dot command */
    ++  int nArg                        /* Number of entries in azArg[] */
    + ){
    +-  sqlite3_stmt *pQuery = 0; 
    +-  sqlite3_stmt *pInsert = 0;
    +-  char *zQuery = 0;
    +-  char *zInsert = 0;
    +-  int rc;
    +-  int i, j, n;
    +-  int nTable = (int)strlen(zTable);
    +-  int k = 0;
    +-  int cnt = 0;
    +-  const int spinRate = 10000;
    +-
    +-  zQuery = sqlite3_mprintf("SELECT * FROM \"%w\"", zTable);
    +-  rc = sqlite3_prepare_v2(p->db, zQuery, -1, &pQuery, 0);
    +-  if( rc ){
    +-    fprintf(stderr, "Error %d: %s on [%s]\n",
    +-            sqlite3_extended_errcode(p->db), sqlite3_errmsg(p->db),
    +-            zQuery);
    +-    goto end_data_xfer;
    +-  }
    +-  n = sqlite3_column_count(pQuery);
    +-  zInsert = sqlite3_malloc64(200 + nTable + n*3);
    +-  if( zInsert==0 ){
    +-    fprintf(stderr, "out of memory\n");
    +-    goto end_data_xfer;
    ++  sqlite3 *db = pState->db;       /* Database handle to query "main" db of */
    ++  FILE *out = pState->out;        /* Stream to write non-error output to */
    ++  int bVerbose = 0;               /* If -verbose is present */
    ++  int bGroupByParent = 0;         /* If -groupbyparent is present */
    ++  int i;                          /* To iterate through azArg[] */
    ++  const char *zIndent = "";       /* How much to indent CREATE INDEX by */
    ++  int rc;                         /* Return code */
    ++  sqlite3_stmt *pSql = 0;         /* Compiled version of SQL statement below */
    ++
    ++  /*
    ++  ** This SELECT statement returns one row for each foreign key constraint
    ++  ** in the schema of the main database. The column values are:
    ++  **
    ++  ** 0. The text of an SQL statement similar to:
    ++  **
    ++  **      "EXPLAIN QUERY PLAN SELECT 1 FROM child_table WHERE child_key=?"
    ++  **
    ++  **    This SELECT is similar to the one that the foreign keys implementation
    ++  **    needs to run internally on child tables. If there is an index that can
    ++  **    be used to optimize this query, then it can also be used by the FK
    ++  **    implementation to optimize DELETE or UPDATE statements on the parent
    ++  **    table.
    ++  **
    ++  ** 1. A GLOB pattern suitable for sqlite3_strglob(). If the plan output by
    ++  **    the EXPLAIN QUERY PLAN command matches this pattern, then the schema
    ++  **    contains an index that can be used to optimize the query.
    ++  **
    ++  ** 2. Human readable text that describes the child table and columns. e.g.
    ++  **
    ++  **       "child_table(child_key1, child_key2)"
    ++  **
    ++  ** 3. Human readable text that describes the parent table and columns. e.g.
    ++  **
    ++  **       "parent_table(parent_key1, parent_key2)"
    ++  **
    ++  ** 4. A full CREATE INDEX statement for an index that could be used to
    ++  **    optimize DELETE or UPDATE statements on the parent table. e.g.
    ++  **
    ++  **       "CREATE INDEX child_table_child_key ON child_table(child_key)"
    ++  **
    ++  ** 5. The name of the parent table.
    ++  **
    ++  ** These six values are used by the C logic below to generate the report.
    ++  */
    ++  const char *zSql =
    ++  "SELECT "
    ++    "     'EXPLAIN QUERY PLAN SELECT 1 FROM ' || quote(s.name) || ' WHERE '"
    ++    "  || group_concat(quote(s.name) || '.' || quote(f.[from]) || '=?' "
    ++    "  || fkey_collate_clause("
    ++    "       f.[table], COALESCE(f.[to], p.[name]), s.name, f.[from]),' AND ')"
    ++    ", "
    ++    "     'SEARCH TABLE ' || s.name || ' USING COVERING INDEX*('"
    ++    "  || group_concat('*=?', ' AND ') || ')'"
    ++    ", "
    ++    "     s.name  || '(' || group_concat(f.[from],  ', ') || ')'"
    ++    ", "
    ++    "     f.[table] || '(' || group_concat(COALESCE(f.[to], p.[name])) || ')'"
    ++    ", "
    ++    "     'CREATE INDEX ' || quote(s.name ||'_'|| group_concat(f.[from], '_'))"
    ++    "  || ' ON ' || quote(s.name) || '('"
    ++    "  || group_concat(quote(f.[from]) ||"
    ++    "        fkey_collate_clause("
    ++    "          f.[table], COALESCE(f.[to], p.[name]), s.name, f.[from]), ', ')"
    ++    "  || ');'"
    ++    ", "
    ++    "     f.[table] "
    ++    "FROM sqlite_master AS s, pragma_foreign_key_list(s.name) AS f "
    ++    "LEFT JOIN pragma_table_info AS p ON (pk-1=seq AND p.arg=f.[table]) "
    ++    "GROUP BY s.name, f.id "
    ++    "ORDER BY (CASE WHEN ? THEN f.[table] ELSE s.name END)"
    ++  ;
    ++  const char *zGlobIPK = "SEARCH TABLE * USING INTEGER PRIMARY KEY (rowid=?)";
    ++
    ++  for(i=2; i<nArg; i++){
    ++    int n = strlen30(azArg[i]);
    ++    if( n>1 && sqlite3_strnicmp("-verbose", azArg[i], n)==0 ){
    ++      bVerbose = 1;
    ++    }
    ++    else if( n>1 && sqlite3_strnicmp("-groupbyparent", azArg[i], n)==0 ){
    ++      bGroupByParent = 1;
    ++      zIndent = "    ";
    ++    }
    ++    else{
    ++      raw_printf(stderr, "Usage: %s %s ?-verbose? ?-groupbyparent?\n",
    ++          azArg[0], azArg[1]
    ++      );
    ++      return SQLITE_ERROR;
    ++    }
    +   }
    +-  sqlite3_snprintf(200+nTable,zInsert,
    +-                   "INSERT OR IGNORE INTO \"%s\" VALUES(?", zTable);
    +-  i = (int)strlen(zInsert);
    +-  for(j=1; j<n; j++){
    +-    memcpy(zInsert+i, ",?", 2);
    +-    i += 2;
    ++
    ++  /* Register the fkey_collate_clause() SQL function */
    ++  rc = sqlite3_create_function(db, "fkey_collate_clause", 4, SQLITE_UTF8,
    ++      0, shellFkeyCollateClause, 0, 0
    ++  );
    ++
    ++
    ++  if( rc==SQLITE_OK ){
    ++    rc = sqlite3_prepare_v2(db, zSql, -1, &pSql, 0);
    +   }
    +-  memcpy(zInsert+i, ");", 3);
    +-  rc = sqlite3_prepare_v2(newDb, zInsert, -1, &pInsert, 0);
    +-  if( rc ){
    +-    fprintf(stderr, "Error %d: %s on [%s]\n",
    +-            sqlite3_extended_errcode(newDb), sqlite3_errmsg(newDb),
    +-            zQuery);
    +-    goto end_data_xfer;
    ++  if( rc==SQLITE_OK ){
    ++    sqlite3_bind_int(pSql, 1, bGroupByParent);
    +   }
    +-  for(k=0; k<2; k++){
    +-    while( (rc = sqlite3_step(pQuery))==SQLITE_ROW ){
    +-      for(i=0; i<n; i++){
    +-        switch( sqlite3_column_type(pQuery, i) ){
    +-          case SQLITE_NULL: {
    +-            sqlite3_bind_null(pInsert, i+1);
    +-            break;
    +-          }
    +-          case SQLITE_INTEGER: {
    +-            sqlite3_bind_int64(pInsert, i+1, sqlite3_column_int64(pQuery,i));
    +-            break;
    +-          }
    +-          case SQLITE_FLOAT: {
    +-            sqlite3_bind_double(pInsert, i+1, sqlite3_column_double(pQuery,i));
    +-            break;
    +-          }
    +-          case SQLITE_TEXT: {
    +-            sqlite3_bind_text(pInsert, i+1,
    +-                             (const char*)sqlite3_column_text(pQuery,i),
    +-                             -1, SQLITE_STATIC);
    +-            break;
    +-          }
    +-          case SQLITE_BLOB: {
    +-            sqlite3_bind_blob(pInsert, i+1, sqlite3_column_blob(pQuery,i),
    +-                                            sqlite3_column_bytes(pQuery,i),
    +-                                            SQLITE_STATIC);
    +-            break;
    +-          }
    +-        }
    +-      } /* End for */
    +-      rc = sqlite3_step(pInsert);
    +-      if( rc!=SQLITE_OK && rc!=SQLITE_ROW && rc!=SQLITE_DONE ){
    +-        fprintf(stderr, "Error %d: %s\n", sqlite3_extended_errcode(newDb),
    +-                        sqlite3_errmsg(newDb));
    +-      }
    +-      sqlite3_reset(pInsert);
    +-      cnt++;
    +-      if( (cnt%spinRate)==0 ){
    +-        printf("%c\b", "|/-\\"[(cnt/spinRate)%4]);
    +-        fflush(stdout);
    ++
    ++  if( rc==SQLITE_OK ){
    ++    int rc2;
    ++    char *zPrev = 0;
    ++    while( SQLITE_ROW==sqlite3_step(pSql) ){
    ++      int res = -1;
    ++      sqlite3_stmt *pExplain = 0;
    ++      const char *zEQP = (const char*)sqlite3_column_text(pSql, 0);
    ++      const char *zGlob = (const char*)sqlite3_column_text(pSql, 1);
    ++      const char *zFrom = (const char*)sqlite3_column_text(pSql, 2);
    ++      const char *zTarget = (const char*)sqlite3_column_text(pSql, 3);
    ++      const char *zCI = (const char*)sqlite3_column_text(pSql, 4);
    ++      const char *zParent = (const char*)sqlite3_column_text(pSql, 5);
    ++
    ++      rc = sqlite3_prepare_v2(db, zEQP, -1, &pExplain, 0);
    ++      if( rc!=SQLITE_OK ) break;
    ++      if( SQLITE_ROW==sqlite3_step(pExplain) ){
    ++        const char *zPlan = (const char*)sqlite3_column_text(pExplain, 3);
    ++        res = (
    ++              0==sqlite3_strglob(zGlob, zPlan)
    ++           || 0==sqlite3_strglob(zGlobIPK, zPlan)
    ++        );
    ++      }
    ++      rc = sqlite3_finalize(pExplain);
    ++      if( rc!=SQLITE_OK ) break;
    ++
    ++      if( res<0 ){
    ++        raw_printf(stderr, "Error: internal error");
    ++        break;
    ++      }else{
    ++        if( bGroupByParent
    ++        && (bVerbose || res==0)
    ++        && (zPrev==0 || sqlite3_stricmp(zParent, zPrev))
    ++        ){
    ++          raw_printf(out, "-- Parent table %s\n", zParent);
    ++          sqlite3_free(zPrev);
    ++          zPrev = sqlite3_mprintf("%s", zParent);
    ++        }
    ++
    ++        if( res==0 ){
    ++          raw_printf(out, "%s%s --> %s\n", zIndent, zCI, zTarget);
    ++        }else if( bVerbose ){
    ++          raw_printf(out, "%s/* no extra indexes required for %s -> %s */\n",
    ++              zIndent, zFrom, zTarget
    ++          );
    ++        }
    +       }
    +-    } /* End while */
    +-    if( rc==SQLITE_DONE ) break;
    +-    sqlite3_finalize(pQuery);
    +-    sqlite3_free(zQuery);
    +-    zQuery = sqlite3_mprintf("SELECT * FROM \"%w\" ORDER BY rowid DESC;",
    +-                             zTable);
    +-    rc = sqlite3_prepare_v2(p->db, zQuery, -1, &pQuery, 0);
    +-    if( rc ){
    +-      fprintf(stderr, "Warning: cannot step \"%s\" backwards", zTable);
    +-      break;
    +     }
    +-  } /* End for(k=0...) */
    ++    sqlite3_free(zPrev);
    + 
    +-end_data_xfer:
    +-  sqlite3_finalize(pQuery);
    +-  sqlite3_finalize(pInsert);
    +-  sqlite3_free(zQuery);
    +-  sqlite3_free(zInsert);
    +-}
    ++    if( rc!=SQLITE_OK ){
    ++      raw_printf(stderr, "%s\n", sqlite3_errmsg(db));
    ++    }
    ++
    ++    rc2 = sqlite3_finalize(pSql);
    ++    if( rc==SQLITE_OK && rc2!=SQLITE_OK ){
    ++      rc = rc2;
    ++      raw_printf(stderr, "%s\n", sqlite3_errmsg(db));
    ++    }
    ++  }else{
    ++    raw_printf(stderr, "%s\n", sqlite3_errmsg(db));
    ++  }
    + 
    ++  return rc;
    ++}
    + 
    + /*
    +-** Try to transfer all rows of the schema that match zWhere.  For
    +-** each row, invoke xForEach() on the object defined by that row.
    +-** If an error is encountered while moving forward through the
    +-** sqlite_master table, try again moving backwards.
    ++** Implementation of ".lint" dot command.
    + */
    +-static void tryToCloneSchema(
    +-  ShellState *p,
    +-  sqlite3 *newDb,
    +-  const char *zWhere,
    +-  void (*xForEach)(ShellState*,sqlite3*,const char*)
    ++static int lintDotCommand(
    ++  ShellState *pState,             /* Current shell tool state */
    ++  char **azArg,                   /* Array of arguments passed to dot command */
    ++  int nArg                        /* Number of entries in azArg[] */
    + ){
    +-  sqlite3_stmt *pQuery = 0;
    +-  char *zQuery = 0;
    +-  int rc;
    +-  const unsigned char *zName;
    +-  const unsigned char *zSql;
    +-  char *zErrMsg = 0;
    ++  int n;
    ++  n = (nArg>=2 ? strlen30(azArg[1]) : 0);
    ++  if( n<1 || sqlite3_strnicmp(azArg[1], "fkey-indexes", n) ) goto usage;
    ++  return lintFkeyIndexes(pState, azArg, nArg);
    ++
    ++ usage:
    ++  raw_printf(stderr, "Usage %s sub-command ?switches...?\n", azArg[0]);
    ++  raw_printf(stderr, "Where sub-commands are:\n");
    ++  raw_printf(stderr, "    fkey-indexes\n");
    ++  return SQLITE_ERROR;
    ++}
    + 
    +-  zQuery = sqlite3_mprintf("SELECT name, sql FROM sqlite_master"
    +-                           " WHERE %s", zWhere);
    +-  rc = sqlite3_prepare_v2(p->db, zQuery, -1, &pQuery, 0);
    +-  if( rc ){
    +-    fprintf(stderr, "Error: (%d) %s on [%s]\n",
    +-                    sqlite3_extended_errcode(p->db), sqlite3_errmsg(p->db),
    +-                    zQuery);
    +-    goto end_schema_xfer;
    +-  }
    +-  while( (rc = sqlite3_step(pQuery))==SQLITE_ROW ){
    +-    zName = sqlite3_column_text(pQuery, 0);
    +-    zSql = sqlite3_column_text(pQuery, 1);
    +-    printf("%s... ", zName); fflush(stdout);
    +-    sqlite3_exec(newDb, (const char*)zSql, 0, 0, &zErrMsg);
    +-    if( zErrMsg ){
    +-      fprintf(stderr, "Error: %s\nSQL: [%s]\n", zErrMsg, zSql);
    +-      sqlite3_free(zErrMsg);
    +-      zErrMsg = 0;
    +-    }
    +-    if( xForEach ){
    +-      xForEach(p, newDb, (const char*)zName);
    ++#if !defined(SQLITE_OMIT_VIRTUALTABLE) && defined(SQLITE_HAVE_ZLIB)
    ++/*********************************************************************************
    ++** The ".archive" or ".ar" command.
    ++*/
    ++static void shellPrepare(
    ++  sqlite3 *db, 
    ++  int *pRc, 
    ++  const char *zSql, 
    ++  sqlite3_stmt **ppStmt
    ++){
    ++  *ppStmt = 0;
    ++  if( *pRc==SQLITE_OK ){
    ++    int rc = sqlite3_prepare_v2(db, zSql, -1, ppStmt, 0);
    ++    if( rc!=SQLITE_OK ){
    ++      raw_printf(stderr, "sql error: %s (%d)\n", 
    ++          sqlite3_errmsg(db), sqlite3_errcode(db)
    ++      );
    ++      *pRc = rc;
    +     }
    +-    printf("done\n");
    +   }
    +-  if( rc!=SQLITE_DONE ){
    +-    sqlite3_finalize(pQuery);
    +-    sqlite3_free(zQuery);
    +-    zQuery = sqlite3_mprintf("SELECT name, sql FROM sqlite_master"
    +-                             " WHERE %s ORDER BY rowid DESC", zWhere);
    +-    rc = sqlite3_prepare_v2(p->db, zQuery, -1, &pQuery, 0);
    +-    if( rc ){
    +-      fprintf(stderr, "Error: (%d) %s on [%s]\n",
    +-                      sqlite3_extended_errcode(p->db), sqlite3_errmsg(p->db),
    +-                      zQuery);
    +-      goto end_schema_xfer;
    ++}
    ++
    ++static void shellPreparePrintf(
    ++  sqlite3 *db, 
    ++  int *pRc, 
    ++  sqlite3_stmt **ppStmt,
    ++  const char *zFmt, 
    ++  ...
    ++){
    ++  *ppStmt = 0;
    ++  if( *pRc==SQLITE_OK ){
    ++    va_list ap;
    ++    char *z;
    ++    va_start(ap, zFmt);
    ++    z = sqlite3_vmprintf(zFmt, ap);
    ++    if( z==0 ){
    ++      *pRc = SQLITE_NOMEM;
    ++    }else{
    ++      shellPrepare(db, pRc, z, ppStmt);
    ++      sqlite3_free(z);
    +     }
    +-    while( (rc = sqlite3_step(pQuery))==SQLITE_ROW ){
    +-      zName = sqlite3_column_text(pQuery, 0);
    +-      zSql = sqlite3_column_text(pQuery, 1);
    +-      printf("%s... ", zName); fflush(stdout);
    +-      sqlite3_exec(newDb, (const char*)zSql, 0, 0, &zErrMsg);
    +-      if( zErrMsg ){
    +-        fprintf(stderr, "Error: %s\nSQL: [%s]\n", zErrMsg, zSql);
    +-        sqlite3_free(zErrMsg);
    +-        zErrMsg = 0;
    +-      }
    +-      if( xForEach ){
    +-        xForEach(p, newDb, (const char*)zName);
    ++  }
    ++}
    ++
    ++static void shellFinalize(
    ++  int *pRc, 
    ++  sqlite3_stmt *pStmt
    ++){
    ++  if( pStmt ){
    ++    sqlite3 *db = sqlite3_db_handle(pStmt);
    ++    int rc = sqlite3_finalize(pStmt);
    ++    if( *pRc==SQLITE_OK ){
    ++      if( rc!=SQLITE_OK ){
    ++        raw_printf(stderr, "SQL error: %s\n", sqlite3_errmsg(db));
    +       }
    +-      printf("done\n");
    ++      *pRc = rc;
    +     }
    +   }
    +-end_schema_xfer:
    +-  sqlite3_finalize(pQuery);
    +-  sqlite3_free(zQuery);
    + }
    + 
    ++static void shellReset(
    ++  int *pRc, 
    ++  sqlite3_stmt *pStmt
    ++){
    ++  int rc = sqlite3_reset(pStmt);
    ++  if( *pRc==SQLITE_OK ){
    ++    if( rc!=SQLITE_OK ){
    ++      sqlite3 *db = sqlite3_db_handle(pStmt);
    ++      raw_printf(stderr, "SQL error: %s\n", sqlite3_errmsg(db));
    ++    }
    ++    *pRc = rc;
    ++  }
    ++}
    ++/*
    ++** Structure representing a single ".ar" command.
    ++*/
    ++typedef struct ArCommand ArCommand;
    ++struct ArCommand {
    ++  u8 eCmd;                        /* An AR_CMD_* value */
    ++  u8 bVerbose;                    /* True if --verbose */
    ++  u8 bZip;                        /* True if the archive is a ZIP */
    ++  u8 bDryRun;                     /* True if --dry-run */
    ++  u8 bAppend;                     /* True if --append */
    ++  int nArg;                       /* Number of command arguments */
    ++  char *zSrcTable;                /* "sqlar", "zipfile($file)" or "zip" */
    ++  const char *zFile;              /* --file argument, or NULL */
    ++  const char *zDir;               /* --directory argument, or NULL */
    ++  char **azArg;                   /* Array of command arguments */
    ++  ShellState *p;                  /* Shell state */
    ++  sqlite3 *db;                    /* Database containing the archive */
    ++};
    ++
    + /*
    +-** Open a new database file named "zNewDb".  Try to recover as much information
    +-** as possible out of the main database (which might be corrupt) and write it
    +-** into zNewDb.
    ++** Print a usage message for the .ar command to stderr and return SQLITE_ERROR.
    + */
    +-static void tryToClone(ShellState *p, const char *zNewDb){
    +-  int rc;
    +-  sqlite3 *newDb = 0;
    +-  if( access(zNewDb,0)==0 ){
    +-    fprintf(stderr, "File \"%s\" already exists.\n", zNewDb);
    +-    return;
    +-  }
    +-  rc = sqlite3_open(zNewDb, &newDb);
    +-  if( rc ){
    +-    fprintf(stderr, "Cannot create output database: %s\n",
    +-            sqlite3_errmsg(newDb));
    +-  }else{
    +-    sqlite3_exec(p->db, "PRAGMA writable_schema=ON;", 0, 0, 0);
    +-    sqlite3_exec(newDb, "BEGIN EXCLUSIVE;", 0, 0, 0);
    +-    tryToCloneSchema(p, newDb, "type='table'", tryToCloneData);
    +-    tryToCloneSchema(p, newDb, "type!='table'", 0);
    +-    sqlite3_exec(newDb, "COMMIT;", 0, 0, 0);
    +-    sqlite3_exec(p->db, "PRAGMA writable_schema=OFF;", 0, 0, 0);
    ++static int arUsage(FILE *f){
    ++  raw_printf(f,
    ++"\n"
    ++"Usage: .ar [OPTION...] [FILE...]\n"
    ++"The .ar command manages sqlar archives.\n"
    ++"\n"
    ++"Examples:\n"
    ++"  .ar -cf archive.sar foo bar    # Create archive.sar from files foo and bar\n"
    ++"  .ar -tf archive.sar            # List members of archive.sar\n"
    ++"  .ar -xvf archive.sar           # Verbosely extract files from archive.sar\n"
    ++"\n"
    ++"Each command line must feature exactly one command option:\n"
    ++"  -c, --create               Create a new archive\n"
    ++"  -u, --update               Update or add files to an existing archive\n"
    ++"  -t, --list                 List contents of archive\n"
    ++"  -x, --extract              Extract files from archive\n"
    ++"\n"
    ++"And zero or more optional options:\n"
    ++"  -v, --verbose              Print each filename as it is processed\n"
    ++"  -f FILE, --file FILE       Operate on archive FILE (default is current db)\n"
    ++"  -a FILE, --append FILE     Operate on FILE opened using the apndvfs VFS\n"
    ++"  -C DIR, --directory DIR    Change to directory DIR to read/extract files\n"
    ++"  -n, --dryrun               Show the SQL that would have occurred\n"
    ++"\n"
    ++"See also: http://sqlite.org/cli.html#sqlar_archive_support\n"
    ++"\n"
    ++);
    ++  return SQLITE_ERROR;
    ++}
    ++
    ++/*
    ++** Print an error message for the .ar command to stderr and return 
    ++** SQLITE_ERROR.
    ++*/
    ++static int arErrorMsg(const char *zFmt, ...){
    ++  va_list ap;
    ++  char *z;
    ++  va_start(ap, zFmt);
    ++  z = sqlite3_vmprintf(zFmt, ap);
    ++  va_end(ap);
    ++  raw_printf(stderr, "Error: %s (try \".ar --help\")\n", z);
    ++  sqlite3_free(z);
    ++  return SQLITE_ERROR;
    ++}
    ++
    ++/*
    ++** Values for ArCommand.eCmd.
    ++*/
    ++#define AR_CMD_CREATE       1
    ++#define AR_CMD_EXTRACT      2
    ++#define AR_CMD_LIST         3
    ++#define AR_CMD_UPDATE       4
    ++#define AR_CMD_HELP         5
    ++
    ++/*
    ++** Other (non-command) switches.
    ++*/
    ++#define AR_SWITCH_VERBOSE     6
    ++#define AR_SWITCH_FILE        7
    ++#define AR_SWITCH_DIRECTORY   8
    ++#define AR_SWITCH_APPEND      9
    ++#define AR_SWITCH_DRYRUN     10
    ++
    ++static int arProcessSwitch(ArCommand *pAr, int eSwitch, const char *zArg){
    ++  switch( eSwitch ){
    ++    case AR_CMD_CREATE:
    ++    case AR_CMD_EXTRACT:
    ++    case AR_CMD_LIST:
    ++    case AR_CMD_UPDATE:
    ++    case AR_CMD_HELP:
    ++      if( pAr->eCmd ){
    ++        return arErrorMsg("multiple command options");
    ++      }
    ++      pAr->eCmd = eSwitch;
    ++      break;
    ++
    ++    case AR_SWITCH_DRYRUN:
    ++      pAr->bDryRun = 1;
    ++      break;
    ++    case AR_SWITCH_VERBOSE:
    ++      pAr->bVerbose = 1;
    ++      break;
    ++    case AR_SWITCH_APPEND:
    ++      pAr->bAppend = 1;
    ++      /* Fall thru into --file */
    ++    case AR_SWITCH_FILE:
    ++      pAr->zFile = zArg;
    ++      break;
    ++    case AR_SWITCH_DIRECTORY:
    ++      pAr->zDir = zArg;
    ++      break;
    +   }
    +-  sqlite3_close(newDb);
    ++
    ++  return SQLITE_OK;
    + }
    + 
    + /*
    +-** Change the output file back to stdout
    ++** Parse the command line for an ".ar" command. The results are written into
    ++** structure (*pAr). SQLITE_OK is returned if the command line is parsed
    ++** successfully, otherwise an error message is written to stderr and 
    ++** SQLITE_ERROR returned.
    + */
    +-static void output_reset(ShellState *p){
    +-  if( p->outfile[0]=='|' ){
    +-#ifndef SQLITE_OMIT_POPEN
    +-    pclose(p->out);
    +-#endif
    ++static int arParseCommand(
    ++  char **azArg,                   /* Array of arguments passed to dot command */
    ++  int nArg,                       /* Number of entries in azArg[] */
    ++  ArCommand *pAr                  /* Populate this object */
    ++){
    ++  struct ArSwitch {
    ++    const char *zLong;
    ++    char cShort;
    ++    u8 eSwitch;
    ++    u8 bArg;
    ++  } aSwitch[] = {
    ++    { "create",    'c', AR_CMD_CREATE,       0 },
    ++    { "extract",   'x', AR_CMD_EXTRACT,      0 },
    ++    { "list",      't', AR_CMD_LIST,         0 },
    ++    { "update",    'u', AR_CMD_UPDATE,       0 },
    ++    { "help",      'h', AR_CMD_HELP,         0 },
    ++    { "verbose",   'v', AR_SWITCH_VERBOSE,   0 },
    ++    { "file",      'f', AR_SWITCH_FILE,      1 },
    ++    { "append",    'a', AR_SWITCH_APPEND,    1 },
    ++    { "directory", 'C', AR_SWITCH_DIRECTORY, 1 },
    ++    { "dryrun",    'n', AR_SWITCH_DRYRUN,    0 },
    ++  };
    ++  int nSwitch = sizeof(aSwitch) / sizeof(struct ArSwitch);
    ++  struct ArSwitch *pEnd = &aSwitch[nSwitch];
    ++
    ++  if( nArg<=1 ){
    ++    return arUsage(stderr);
    +   }else{
    +-    output_file_close(p->out);
    ++    char *z = azArg[1];
    ++    memset(pAr, 0, sizeof(ArCommand));
    ++
    ++    if( z[0]!='-' ){
    ++      /* Traditional style [tar] invocation */
    ++      int i;
    ++      int iArg = 2;
    ++      for(i=0; z[i]; i++){
    ++        const char *zArg = 0;
    ++        struct ArSwitch *pOpt;
    ++        for(pOpt=&aSwitch[0]; pOpt<pEnd; pOpt++){
    ++          if( z[i]==pOpt->cShort ) break;
    ++        }
    ++        if( pOpt==pEnd ){
    ++          return arErrorMsg("unrecognized option: %c", z[i]);
    ++        }
    ++        if( pOpt->bArg ){
    ++          if( iArg>=nArg ){
    ++            return arErrorMsg("option requires an argument: %c",z[i]);
    ++          }
    ++          zArg = azArg[iArg++];
    ++        }
    ++        if( arProcessSwitch(pAr, pOpt->eSwitch, zArg) ) return SQLITE_ERROR;
    ++      }
    ++      pAr->nArg = nArg-iArg;
    ++      if( pAr->nArg>0 ){
    ++        pAr->azArg = &azArg[iArg];
    ++      }
    ++    }else{
    ++      /* Non-traditional invocation */
    ++      int iArg;
    ++      for(iArg=1; iArg<nArg; iArg++){
    ++        int n;
    ++        z = azArg[iArg];
    ++        if( z[0]!='-' ){
    ++          /* All remaining command line words are command arguments. */
    ++          pAr->azArg = &azArg[iArg];
    ++          pAr->nArg = nArg-iArg;
    ++          break;
    ++        }
    ++        n = strlen30(z);
    ++
    ++        if( z[1]!='-' ){
    ++          int i;
    ++          /* One or more short options */
    ++          for(i=1; i<n; i++){
    ++            const char *zArg = 0;
    ++            struct ArSwitch *pOpt;
    ++            for(pOpt=&aSwitch[0]; pOpt<pEnd; pOpt++){
    ++              if( z[i]==pOpt->cShort ) break;
    ++            }
    ++            if( pOpt==pEnd ){
    ++              return arErrorMsg("unrecognized option: %c\n", z[i]);
    ++            }
    ++            if( pOpt->bArg ){
    ++              if( i<(n-1) ){
    ++                zArg = &z[i+1];
    ++                i = n;
    ++              }else{
    ++                if( iArg>=(nArg-1) ){
    ++                  return arErrorMsg("option requires an argument: %c\n",z[i]);
    ++                }
    ++                zArg = azArg[++iArg];
    ++              }
    ++            }
    ++            if( arProcessSwitch(pAr, pOpt->eSwitch, zArg) ) return SQLITE_ERROR;
    ++          }
    ++        }else if( z[2]=='\0' ){
    ++          /* A -- option, indicating that all remaining command line words
    ++          ** are command arguments.  */
    ++          pAr->azArg = &azArg[iArg+1];
    ++          pAr->nArg = nArg-iArg-1;
    ++          break;
    ++        }else{
    ++          /* A long option */
    ++          const char *zArg = 0;             /* Argument for option, if any */
    ++          struct ArSwitch *pMatch = 0;      /* Matching option */
    ++          struct ArSwitch *pOpt;            /* Iterator */
    ++          for(pOpt=&aSwitch[0]; pOpt<pEnd; pOpt++){
    ++            const char *zLong = pOpt->zLong;
    ++            if( (n-2)<=strlen30(zLong) && 0==memcmp(&z[2], zLong, n-2) ){
    ++              if( pMatch ){
    ++                return arErrorMsg("ambiguous option: %s",z);
    ++              }else{
    ++                pMatch = pOpt;
    ++              }
    ++            }
    ++          }
    ++
    ++          if( pMatch==0 ){
    ++            return arErrorMsg("unrecognized option: %s", z);
    ++          }
    ++          if( pMatch->bArg ){
    ++            if( iArg>=(nArg-1) ){
    ++              return arErrorMsg("option requires an argument: %s", z);
    ++            }
    ++            zArg = azArg[++iArg];
    ++          }
    ++          if( arProcessSwitch(pAr, pMatch->eSwitch, zArg) ) return SQLITE_ERROR;
    ++        }
    ++      }
    ++    }
    +   }
    +-  p->outfile[0] = 0;
    +-  p->out = stdout;
    ++
    ++  return SQLITE_OK;
    + }
    + 
    + /*
    +-** Run an SQL command and return the single integer result.
    ++** This function assumes that all arguments within the ArCommand.azArg[]
    ++** array refer to archive members, as for the --extract or --list commands. 
    ++** It checks that each of them are present. If any specified file is not
    ++** present in the archive, an error is printed to stderr and an error
    ++** code returned. Otherwise, if all specified arguments are present in
    ++** the archive, SQLITE_OK is returned.
    ++**
    ++** This function strips any trailing '/' characters from each argument.
    ++** This is consistent with the way the [tar] command seems to work on
    ++** Linux.
    + */
    +-static int db_int(ShellState *p, const char *zSql){
    +-  sqlite3_stmt *pStmt;
    +-  int res = 0;
    +-  sqlite3_prepare_v2(p->db, zSql, -1, &pStmt, 0);
    +-  if( pStmt && sqlite3_step(pStmt)==SQLITE_ROW ){
    +-    res = sqlite3_column_int(pStmt,0);
    ++static int arCheckEntries(ArCommand *pAr){
    ++  int rc = SQLITE_OK;
    ++  if( pAr->nArg ){
    ++    int i, j;
    ++    sqlite3_stmt *pTest = 0;
    ++
    ++    shellPreparePrintf(pAr->db, &rc, &pTest,
    ++        "SELECT name FROM %s WHERE name=$name", 
    ++        pAr->zSrcTable
    ++    );
    ++    j = sqlite3_bind_parameter_index(pTest, "$name");
    ++    for(i=0; i<pAr->nArg && rc==SQLITE_OK; i++){
    ++      char *z = pAr->azArg[i];
    ++      int n = strlen30(z);
    ++      int bOk = 0;
    ++      while( n>0 && z[n-1]=='/' ) n--;
    ++      z[n] = '\0';
    ++      sqlite3_bind_text(pTest, j, z, -1, SQLITE_STATIC);
    ++      if( SQLITE_ROW==sqlite3_step(pTest) ){
    ++        bOk = 1;
    ++      }
    ++      shellReset(&rc, pTest);
    ++      if( rc==SQLITE_OK && bOk==0 ){
    ++        utf8_printf(stderr, "not found in archive: %s\n", z);
    ++        rc = SQLITE_ERROR;
    ++      }
    ++    }
    ++    shellFinalize(&rc, pTest);
    +   }
    +-  sqlite3_finalize(pStmt);
    +-  return res;
    ++  return rc;
    + }
    + 
    + /*
    +-** Convert a 2-byte or 4-byte big-endian integer into a native integer
    ++** Format a WHERE clause that can be used against the "sqlar" table to
    ++** identify all archive members that match the command arguments held
    ++** in (*pAr). Leave this WHERE clause in (*pzWhere) before returning.
    ++** The caller is responsible for eventually calling sqlite3_free() on
    ++** any non-NULL (*pzWhere) value.
    + */
    +-unsigned int get2byteInt(unsigned char *a){
    +-  return (a[0]<<8) + a[1];
    +-}
    +-unsigned int get4byteInt(unsigned char *a){
    +-  return (a[0]<<24) + (a[1]<<16) + (a[2]<<8) + a[3];
    ++static void arWhereClause(
    ++  int *pRc, 
    ++  ArCommand *pAr, 
    ++  char **pzWhere                  /* OUT: New WHERE clause */
    ++){
    ++  char *zWhere = 0;
    ++  if( *pRc==SQLITE_OK ){
    ++    if( pAr->nArg==0 ){
    ++      zWhere = sqlite3_mprintf("1");
    ++    }else{
    ++      int i;
    ++      const char *zSep = "";
    ++      for(i=0; i<pAr->nArg; i++){
    ++        const char *z = pAr->azArg[i];
    ++        zWhere = sqlite3_mprintf(
    ++          "%z%s name = '%q' OR substr(name,1,%d) = '%q/'", 
    ++          zWhere, zSep, z, strlen30(z)+1, z
    ++        );
    ++        if( zWhere==0 ){
    ++          *pRc = SQLITE_NOMEM;
    ++          break;
    ++        }
    ++        zSep = " OR ";
    ++      }
    ++    }
    ++  }
    ++  *pzWhere = zWhere;
    + }
    + 
    + /*
    +-** Implementation of the ".info" command.
    +-**
    +-** Return 1 on error, 2 to exit, and 0 otherwise.
    ++** Implementation of .ar "lisT" command. 
    + */
    +-static int shell_dbinfo_command(ShellState *p, int nArg, char **azArg){
    +-  static const struct { const char *zName; int ofst; } aField[] = {
    +-     { "file change counter:",  24  },
    +-     { "database page count:",  28  },
    +-     { "freelist page count:",  36  },
    +-     { "schema cookie:",        40  },
    +-     { "schema format:",        44  },
    +-     { "default cache size:",   48  },
    +-     { "autovacuum top root:",  52  },
    +-     { "incremental vacuum:",   64  },
    +-     { "text encoding:",        56  },
    +-     { "user version:",         60  },
    +-     { "application id:",       68  },
    +-     { "software version:",     96  },
    +-  };
    +-  static const struct { const char *zName; const char *zSql; } aQuery[] = {
    +-     { "number of tables:",
    +-       "SELECT count(*) FROM %s WHERE type='table'" },
    +-     { "number of indexes:",
    +-       "SELECT count(*) FROM %s WHERE type='index'" },
    +-     { "number of triggers:",
    +-       "SELECT count(*) FROM %s WHERE type='trigger'" },
    +-     { "number of views:",
    +-       "SELECT count(*) FROM %s WHERE type='view'" },
    +-     { "schema size:",
    +-       "SELECT total(length(sql)) FROM %s" },
    ++static int arListCommand(ArCommand *pAr){
    ++  const char *zSql = "SELECT %s FROM %s WHERE %s"; 
    ++  const char *azCols[] = {
    ++    "name",
    ++    "lsmode(mode), sz, datetime(mtime, 'unixepoch'), name"
    +   };
    +-  sqlite3_file *pFile;
    +-  int i;
    +-  char *zSchemaTab;
    +-  char *zDb = nArg>=2 ? azArg[1] : "main";
    +-  unsigned char aHdr[100];
    +-  open_db(p, 0);
    +-  if( p->db==0 ) return 1;
    +-  sqlite3_file_control(p->db, zDb, SQLITE_FCNTL_FILE_POINTER, &pFile);
    +-  if( pFile==0 || pFile->pMethods==0 || pFile->pMethods->xRead==0 ){
    +-    return 1;
    ++
    ++  char *zWhere = 0;
    ++  sqlite3_stmt *pSql = 0;
    ++  int rc;
    ++
    ++  rc = arCheckEntries(pAr);
    ++  arWhereClause(&rc, pAr, &zWhere);
    ++
    ++  shellPreparePrintf(pAr->db, &rc, &pSql, zSql, azCols[pAr->bVerbose],
    ++                     pAr->zSrcTable, zWhere);
    ++  if( pAr->bDryRun ){
    ++    utf8_printf(pAr->p->out, "%s\n", sqlite3_sql(pSql));
    ++  }else{
    ++    while( rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pSql) ){
    ++      if( pAr->bVerbose ){
    ++        utf8_printf(pAr->p->out, "%s % 10d  %s  %s\n",
    ++            sqlite3_column_text(pSql, 0),
    ++            sqlite3_column_int(pSql, 1), 
    ++            sqlite3_column_text(pSql, 2),
    ++            sqlite3_column_text(pSql, 3)
    ++        );
    ++      }else{
    ++        utf8_printf(pAr->p->out, "%s\n", sqlite3_column_text(pSql, 0));
    ++      }
    ++    }
    +   }
    +-  i = pFile->pMethods->xRead(pFile, aHdr, 100, 0);
    +-  if( i!=SQLITE_OK ){
    +-    fprintf(stderr, "unable to read database header\n");
    +-    return 1;
    ++  shellFinalize(&rc, pSql);
    ++  return rc;
    ++}
    ++
    ++
    ++/*
    ++** Implementation of .ar "eXtract" command. 
    ++*/
    ++static int arExtractCommand(ArCommand *pAr){
    ++  const char *zSql1 = 
    ++    "SELECT "
    ++    " ($dir || name),"
    ++    " writefile(($dir || name), %s, mode, mtime) "
    ++    "FROM %s WHERE (%s) AND (data IS NULL OR $dirOnly = 0)";
    ++
    ++  const char *azExtraArg[] = { 
    ++    "sqlar_uncompress(data, sz)",
    ++    "data"
    ++  };
    ++
    ++  sqlite3_stmt *pSql = 0;
    ++  int rc = SQLITE_OK;
    ++  char *zDir = 0;
    ++  char *zWhere = 0;
    ++  int i, j;
    ++
    ++  /* If arguments are specified, check that they actually exist within
    ++  ** the archive before proceeding. And formulate a WHERE clause to
    ++  ** match them.  */
    ++  rc = arCheckEntries(pAr);
    ++  arWhereClause(&rc, pAr, &zWhere);
    ++
    ++  if( rc==SQLITE_OK ){
    ++    if( pAr->zDir ){
    ++      zDir = sqlite3_mprintf("%s/", pAr->zDir);
    ++    }else{
    ++      zDir = sqlite3_mprintf("");
    ++    }
    ++    if( zDir==0 ) rc = SQLITE_NOMEM;
    +   }
    +-  i = get2byteInt(aHdr+16);
    +-  if( i==1 ) i = 65536;
    +-  fprintf(p->out, "%-20s %d\n", "database page size:", i);
    +-  fprintf(p->out, "%-20s %d\n", "write format:", aHdr[18]);
    +-  fprintf(p->out, "%-20s %d\n", "read format:", aHdr[19]);
    +-  fprintf(p->out, "%-20s %d\n", "reserved bytes:", aHdr[20]);
    +-  for(i=0; i<ArraySize(aField); i++){
    +-    int ofst = aField[i].ofst;
    +-    unsigned int val = get4byteInt(aHdr + ofst);
    +-    fprintf(p->out, "%-20s %u", aField[i].zName, val);
    +-    switch( ofst ){
    +-      case 56: {
    +-        if( val==1 ) fprintf(p->out, " (utf8)"); 
    +-        if( val==2 ) fprintf(p->out, " (utf16le)"); 
    +-        if( val==3 ) fprintf(p->out, " (utf16be)"); 
    ++
    ++  shellPreparePrintf(pAr->db, &rc, &pSql, zSql1, 
    ++      azExtraArg[pAr->bZip], pAr->zSrcTable, zWhere
    ++  );
    ++
    ++  if( rc==SQLITE_OK ){
    ++    j = sqlite3_bind_parameter_index(pSql, "$dir");
    ++    sqlite3_bind_text(pSql, j, zDir, -1, SQLITE_STATIC);
    ++
    ++    /* Run the SELECT statement twice. The first time, writefile() is called
    ++    ** for all archive members that should be extracted. The second time,
    ++    ** only for the directories. This is because the timestamps for
    ++    ** extracted directories must be reset after they are populated (as
    ++    ** populating them changes the timestamp).  */
    ++    for(i=0; i<2; i++){
    ++      j = sqlite3_bind_parameter_index(pSql, "$dirOnly");
    ++      sqlite3_bind_int(pSql, j, i);
    ++      if( pAr->bDryRun ){
    ++        utf8_printf(pAr->p->out, "%s\n", sqlite3_sql(pSql));
    ++      }else{
    ++        while( rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pSql) ){
    ++          if( i==0 && pAr->bVerbose ){
    ++            utf8_printf(pAr->p->out, "%s\n", sqlite3_column_text(pSql, 0));
    ++          }
    ++        }
    +       }
    ++      shellReset(&rc, pSql);
    +     }
    +-    fprintf(p->out, "\n");
    ++    shellFinalize(&rc, pSql);
    +   }
    +-  if( zDb==0 ){
    +-    zSchemaTab = sqlite3_mprintf("main.sqlite_master");
    +-  }else if( strcmp(zDb,"temp")==0 ){
    +-    zSchemaTab = sqlite3_mprintf("%s", "sqlite_temp_master");
    ++
    ++  sqlite3_free(zDir);
    ++  sqlite3_free(zWhere);
    ++  return rc;
    ++}
    ++
    ++/*
    ++** Run the SQL statement in zSql.  Or if doing a --dryrun, merely print it out.
    ++*/
    ++static int arExecSql(ArCommand *pAr, const char *zSql){
    ++  int rc;
    ++  if( pAr->bDryRun ){
    ++    utf8_printf(pAr->p->out, "%s\n", zSql);
    ++    rc = SQLITE_OK;
    +   }else{
    +-    zSchemaTab = sqlite3_mprintf("\"%w\".sqlite_master", zDb);
    +-  }
    +-  for(i=0; i<ArraySize(aQuery); i++){
    +-    char *zSql = sqlite3_mprintf(aQuery[i].zSql, zSchemaTab);
    +-    int val = db_int(p, zSql);
    +-    sqlite3_free(zSql);
    +-    fprintf(p->out, "%-20s %d\n", aQuery[i].zName, val);
    ++    char *zErr = 0;
    ++    rc = sqlite3_exec(pAr->db, zSql, 0, 0, &zErr);
    ++    if( zErr ){
    ++      utf8_printf(stdout, "ERROR: %s\n", zErr);
    ++      sqlite3_free(zErr);
    ++    }
    +   }
    +-  sqlite3_free(zSchemaTab);
    +-  return 0;
    ++  return rc;
    + }
    + 
    ++
    + /*
    +-** Print the current sqlite3_errmsg() value to stderr and return 1.
    ++** Implementation of .ar "create" and "update" commands.
    ++**
    ++** Create the "sqlar" table in the database if it does not already exist.
    ++** Then add each file in the azFile[] array to the archive. Directories
    ++** are added recursively. If argument bVerbose is non-zero, a message is
    ++** printed on stdout for each file archived.
    ++**
    ++** The create command is the same as update, except that it drops
    ++** any existing "sqlar" table before beginning.
    + */
    +-static int shellDatabaseError(sqlite3 *db){
    +-  const char *zErr = sqlite3_errmsg(db);
    +-  fprintf(stderr, "Error: %s\n", zErr);
    +-  return 1;
    ++static int arCreateOrUpdateCommand(
    ++  ArCommand *pAr,                 /* Command arguments and options */
    ++  int bUpdate                     /* true for a --create.  false for --update */
    ++){
    ++  const char *zCreate = 
    ++      "CREATE TABLE IF NOT EXISTS sqlar(\n"
    ++      "  name TEXT PRIMARY KEY,  -- name of the file\n"
    ++      "  mode INT,               -- access permissions\n"
    ++      "  mtime INT,              -- last modification time\n"
    ++      "  sz INT,                 -- original file size\n"
    ++      "  data BLOB               -- compressed content\n"
    ++      ")";
    ++  const char *zDrop = "DROP TABLE IF EXISTS sqlar";
    ++  const char *zInsertFmt = 
    ++     "REPLACE INTO sqlar(name,mode,mtime,sz,data)\n"
    ++     "  SELECT\n"
    ++     "    %s,\n"
    ++     "    mode,\n"
    ++     "    mtime,\n"
    ++     "    CASE substr(lsmode(mode),1,1)\n"
    ++     "      WHEN '-' THEN length(data)\n"
    ++     "      WHEN 'd' THEN 0\n"
    ++     "      ELSE -1 END,\n"
    ++     "    CASE WHEN lsmode(mode) LIKE 'd%%' THEN NULL else data END\n"
    ++     "  FROM fsdir(%Q,%Q)\n"
    ++     "  WHERE lsmode(mode) NOT LIKE '?%%';";
    ++  int i;                          /* For iterating through azFile[] */
    ++  int rc;                         /* Return code */
    ++
    ++  rc = arExecSql(pAr, "SAVEPOINT ar;");
    ++  if( rc!=SQLITE_OK ) return rc;
    ++  if( bUpdate==0 ){
    ++    rc = arExecSql(pAr, zDrop);
    ++    if( rc!=SQLITE_OK ) return rc;
    ++  }
    ++  rc = arExecSql(pAr, zCreate);
    ++  for(i=0; i<pAr->nArg && rc==SQLITE_OK; i++){
    ++    char *zSql = sqlite3_mprintf(zInsertFmt,
    ++        pAr->bVerbose ? "shell_putsnl(name)" : "name",
    ++        pAr->azArg[i], pAr->zDir);
    ++    rc = arExecSql(pAr, zSql);
    ++    sqlite3_free(zSql);
    ++  }
    ++  if( rc!=SQLITE_OK ){
    ++    arExecSql(pAr, "ROLLBACK TO ar; RELEASE ar;");
    ++  }else{
    ++    rc = arExecSql(pAr, "RELEASE ar;");
    ++  }
    ++  return rc;
    + }
    + 
    + /*
    +-** Print an out-of-memory message to stderr and return 1.
    ++** Implementation of ".ar" dot command.
    + */
    +-static int shellNomemError(void){
    +-  fprintf(stderr, "Error: out of memory\n");
    +-  return 1;
    ++static int arDotCommand(
    ++  ShellState *pState,             /* Current shell tool state */
    ++  char **azArg,                   /* Array of arguments passed to dot command */
    ++  int nArg                        /* Number of entries in azArg[] */
    ++){
    ++  ArCommand cmd;
    ++  int rc;
    ++  memset(&cmd, 0, sizeof(cmd));
    ++  rc = arParseCommand(azArg, nArg, &cmd);
    ++  if( rc==SQLITE_OK ){
    ++    int eDbType = SHELL_OPEN_UNSPEC;
    ++    cmd.p = pState;
    ++    cmd.db = pState->db;
    ++    if( cmd.zFile ){
    ++      eDbType = deduceDatabaseType(cmd.zFile);
    ++    }else{
    ++      eDbType = pState->openMode;
    ++    }
    ++    if( eDbType==SHELL_OPEN_ZIPFILE ){
    ++      if( cmd.zFile==0 ){
    ++        cmd.zSrcTable = sqlite3_mprintf("zip");
    ++      }else{
    ++        cmd.zSrcTable = sqlite3_mprintf("zipfile(%Q)", cmd.zFile);
    ++      }
    ++      if( cmd.eCmd==AR_CMD_CREATE || cmd.eCmd==AR_CMD_UPDATE ){
    ++        utf8_printf(stderr, "zip archives are read-only\n");
    ++        rc = SQLITE_ERROR;
    ++        goto end_ar_command;
    ++      }
    ++      cmd.bZip = 1;
    ++    }else if( cmd.zFile ){
    ++      int flags;
    ++      if( cmd.bAppend ) eDbType = SHELL_OPEN_APPENDVFS;
    ++      if( cmd.eCmd==AR_CMD_CREATE || cmd.eCmd==AR_CMD_UPDATE ){
    ++        flags = SQLITE_OPEN_READWRITE|SQLITE_OPEN_CREATE;
    ++      }else{
    ++        flags = SQLITE_OPEN_READONLY;
    ++      }
    ++      cmd.db = 0;
    ++      if( cmd.bDryRun ){
    ++        utf8_printf(pState->out, "-- open database '%s'%s\n", cmd.zFile,
    ++             eDbType==SHELL_OPEN_APPENDVFS ? " using 'apndvfs'" : "");
    ++      }
    ++      rc = sqlite3_open_v2(cmd.zFile, &cmd.db, flags, 
    ++             eDbType==SHELL_OPEN_APPENDVFS ? "apndvfs" : 0);
    ++      if( rc!=SQLITE_OK ){
    ++        utf8_printf(stderr, "cannot open file: %s (%s)\n", 
    ++            cmd.zFile, sqlite3_errmsg(cmd.db)
    ++        );
    ++        goto end_ar_command;
    ++      }
    ++      sqlite3_fileio_init(cmd.db, 0, 0);
    ++#ifdef SQLITE_HAVE_ZLIB
    ++      sqlite3_sqlar_init(cmd.db, 0, 0);
    ++#endif
    ++      sqlite3_create_function(cmd.db, "shell_putsnl", 1, SQLITE_UTF8, cmd.p,
    ++                              shellPutsFunc, 0, 0);
    ++
    ++    }
    ++    if( cmd.zSrcTable==0 ){
    ++      if( cmd.eCmd!=AR_CMD_CREATE
    ++       && sqlite3_table_column_metadata(cmd.db,0,"sqlar","name",0,0,0,0,0)
    ++      ){
    ++        utf8_printf(stderr, "database does not contain an 'sqlar' table\n");
    ++        rc = SQLITE_ERROR;
    ++        goto end_ar_command;
    ++      }
    ++      cmd.zSrcTable = sqlite3_mprintf("sqlar");
    ++    }
    ++
    ++    switch( cmd.eCmd ){
    ++      case AR_CMD_CREATE:
    ++        rc = arCreateOrUpdateCommand(&cmd, 0);
    ++        break;
    ++
    ++      case AR_CMD_EXTRACT:
    ++        rc = arExtractCommand(&cmd);
    ++        break;
    ++
    ++      case AR_CMD_LIST:
    ++        rc = arListCommand(&cmd);
    ++        break;
    ++
    ++      case AR_CMD_HELP:
    ++        arUsage(pState->out);
    ++        break;
    ++
    ++      default:
    ++        assert( cmd.eCmd==AR_CMD_UPDATE );
    ++        rc = arCreateOrUpdateCommand(&cmd, 1);
    ++        break;
    ++    }
    ++  }
    ++end_ar_command:
    ++  if( cmd.db!=pState->db ){
    ++    sqlite3_close(cmd.db);
    ++  }
    ++  sqlite3_free(cmd.zSrcTable);
    ++
    ++  return rc;
    + }
    ++/* End of the ".archive" or ".ar" command logic
    ++**********************************************************************************/
    ++#endif /* !defined(SQLITE_OMIT_VIRTUALTABLE) && defined(SQLITE_HAVE_ZLIB) */
    ++
    + 
    + /*
    + ** If an input line begins with "." then invoke this routine to
    +@@ -2642,6 +12291,12 @@ static int do_meta_command(char *zLine, ShellState *p){
    +   int rc = 0;
    +   char *azArg[50];
    + 
    ++#ifndef SQLITE_OMIT_VIRTUALTABLE
    ++  if( p->expert.pExpert ){
    ++    expertFinish(p, 1, 0);
    ++  }
    ++#endif
    ++
    +   /* Parse the input line into tokens.
    +   */
    +   while( zLine[h] && nArg<ArraySize(azArg) ){
    +@@ -2650,9 +12305,9 @@ static int do_meta_command(char *zLine, ShellState *p){
    +     if( zLine[h]=='\'' || zLine[h]=='"' ){
    +       int delim = zLine[h++];
    +       azArg[nArg++] = &zLine[h];
    +-      while( zLine[h] && zLine[h]!=delim ){ 
    ++      while( zLine[h] && zLine[h]!=delim ){
    +         if( zLine[h]=='\\' && delim=='"' && zLine[h+1]!=0 ) h++;
    +-        h++; 
    ++        h++;
    +       }
    +       if( zLine[h]==delim ){
    +         zLine[h++] = 0;
    +@@ -2671,6 +12326,31 @@ static int do_meta_command(char *zLine, ShellState *p){
    +   if( nArg==0 ) return 0; /* no tokens, no error */
    +   n = strlen30(azArg[0]);
    +   c = azArg[0][0];
    ++  clearTempFile(p);
    ++
    ++#ifndef SQLITE_OMIT_AUTHORIZATION
    ++  if( c=='a' && strncmp(azArg[0], "auth", n)==0 ){
    ++    if( nArg!=2 ){
    ++      raw_printf(stderr, "Usage: .auth ON|OFF\n");
    ++      rc = 1;
    ++      goto meta_command_exit;
    ++    }
    ++    open_db(p, 0);
    ++    if( booleanValue(azArg[1]) ){
    ++      sqlite3_set_authorizer(p->db, shellAuth, p);
    ++    }else{
    ++      sqlite3_set_authorizer(p->db, 0, 0);
    ++    }
    ++  }else
    ++#endif
    ++
    ++#if !defined(SQLITE_OMIT_VIRTUALTABLE) && defined(SQLITE_HAVE_ZLIB)
    ++  if( c=='a' && strncmp(azArg[0], "archive", n)==0 ){
    ++    open_db(p, 0);
    ++    rc = arDotCommand(p, azArg, nArg);
    ++  }else
    ++#endif
    ++
    +   if( (c=='b' && n>=3 && strncmp(azArg[0], "backup", n)==0)
    +    || (c=='s' && n>=3 && strncmp(azArg[0], "save", n)==0)
    +   ){
    +@@ -2685,7 +12365,7 @@ static int do_meta_command(char *zLine, ShellState *p){
    +         while( z[0]=='-' ) z++;
    +         /* No options to process at this time */
    +         {
    +-          fprintf(stderr, "unknown option: %s\n", azArg[j]);
    ++          utf8_printf(stderr, "unknown option: %s\n", azArg[j]);
    +           return 1;
    +         }
    +       }else if( zDestFile==0 ){
    +@@ -2694,25 +12374,25 @@ static int do_meta_command(char *zLine, ShellState *p){
    +         zDb = zDestFile;
    +         zDestFile = azArg[j];
    +       }else{
    +-        fprintf(stderr, "too many arguments to .backup\n");
    ++        raw_printf(stderr, "too many arguments to .backup\n");
    +         return 1;
    +       }
    +     }
    +     if( zDestFile==0 ){
    +-      fprintf(stderr, "missing FILENAME argument on .backup\n");
    ++      raw_printf(stderr, "missing FILENAME argument on .backup\n");
    +       return 1;
    +     }
    +     if( zDb==0 ) zDb = "main";
    +     rc = sqlite3_open(zDestFile, &pDest);
    +     if( rc!=SQLITE_OK ){
    +-      fprintf(stderr, "Error: cannot open \"%s\"\n", zDestFile);
    ++      utf8_printf(stderr, "Error: cannot open \"%s\"\n", zDestFile);
    +       sqlite3_close(pDest);
    +       return 1;
    +     }
    +     open_db(p, 0);
    +     pBackup = sqlite3_backup_init(pDest, "main", p->db, zDb);
    +     if( pBackup==0 ){
    +-      fprintf(stderr, "Error: %s\n", sqlite3_errmsg(pDest));
    ++      utf8_printf(stderr, "Error: %s\n", sqlite3_errmsg(pDest));
    +       sqlite3_close(pDest);
    +       return 1;
    +     }
    +@@ -2721,7 +12401,7 @@ static int do_meta_command(char *zLine, ShellState *p){
    +     if( rc==SQLITE_DONE ){
    +       rc = 0;
    +     }else{
    +-      fprintf(stderr, "Error: %s\n", sqlite3_errmsg(pDest));
    ++      utf8_printf(stderr, "Error: %s\n", sqlite3_errmsg(pDest));
    +       rc = 1;
    +     }
    +     sqlite3_close(pDest);
    +@@ -2731,7 +12411,7 @@ static int do_meta_command(char *zLine, ShellState *p){
    +     if( nArg==2 ){
    +       bail_on_error = booleanValue(azArg[1]);
    +     }else{
    +-      fprintf(stderr, "Usage: .bail on|off\n");
    ++      raw_printf(stderr, "Usage: .bail on|off\n");
    +       rc = 1;
    +     }
    +   }else
    +@@ -2739,12 +12419,31 @@ static int do_meta_command(char *zLine, ShellState *p){
    +   if( c=='b' && n>=3 && strncmp(azArg[0], "binary", n)==0 ){
    +     if( nArg==2 ){
    +       if( booleanValue(azArg[1]) ){
    +-        setBinaryMode(p->out);
    ++        setBinaryMode(p->out, 1);
    +       }else{
    +-        setTextMode(p->out);
    ++        setTextMode(p->out, 1);
    ++      }
    ++    }else{
    ++      raw_printf(stderr, "Usage: .binary on|off\n");
    ++      rc = 1;
    ++    }
    ++  }else
    ++
    ++  if( c=='c' && strcmp(azArg[0],"cd")==0 ){
    ++    if( nArg==2 ){
    ++#if defined(_WIN32) || defined(WIN32)
    ++      wchar_t *z = sqlite3_win32_utf8_to_unicode(azArg[1]);
    ++      rc = !SetCurrentDirectoryW(z);
    ++      sqlite3_free(z);
    ++#else
    ++      rc = chdir(azArg[1]);
    ++#endif
    ++      if( rc ){
    ++        utf8_printf(stderr, "Cannot change to directory \"%s\"\n", azArg[1]);
    ++        rc = 1;
    +       }
    +     }else{
    +-      fprintf(stderr, "Usage: .binary on|off\n");
    ++      raw_printf(stderr, "Usage: .cd DIRECTORY\n");
    +       rc = 1;
    +     }
    +   }else
    +@@ -2756,11 +12455,45 @@ static int do_meta_command(char *zLine, ShellState *p){
    +     test_breakpoint();
    +   }else
    + 
    ++  if( c=='c' && n>=3 && strncmp(azArg[0], "changes", n)==0 ){
    ++    if( nArg==2 ){
    ++      setOrClearFlag(p, SHFLG_CountChanges, azArg[1]);
    ++    }else{
    ++      raw_printf(stderr, "Usage: .changes on|off\n");
    ++      rc = 1;
    ++    }
    ++  }else
    ++
    ++  /* Cancel output redirection, if it is currently set (by .testcase)
    ++  ** Then read the content of the testcase-out.txt file and compare against
    ++  ** azArg[1].  If there are differences, report an error and exit.
    ++  */
    ++  if( c=='c' && n>=3 && strncmp(azArg[0], "check", n)==0 ){
    ++    char *zRes = 0;
    ++    output_reset(p);
    ++    if( nArg!=2 ){
    ++      raw_printf(stderr, "Usage: .check GLOB-PATTERN\n");
    ++      rc = 2;
    ++    }else if( (zRes = readFile("testcase-out.txt", 0))==0 ){
    ++      raw_printf(stderr, "Error: cannot read 'testcase-out.txt'\n");
    ++      rc = 2;
    ++    }else if( testcase_glob(azArg[1],zRes)==0 ){
    ++      utf8_printf(stderr,
    ++                 "testcase-%s FAILED\n Expected: [%s]\n      Got: [%s]\n",
    ++                 p->zTestcase, azArg[1], zRes);
    ++      rc = 1;
    ++    }else{
    ++      utf8_printf(stdout, "testcase-%s ok\n", p->zTestcase);
    ++      p->nCheck++;
    ++    }
    ++    sqlite3_free(zRes);
    ++  }else
    ++
    +   if( c=='c' && strncmp(azArg[0], "clone", n)==0 ){
    +     if( nArg==2 ){
    +       tryToClone(p, azArg[1]);
    +     }else{
    +-      fprintf(stderr, "Usage: .clone FILENAME\n");
    ++      raw_printf(stderr, "Usage: .clone FILENAME\n");
    +       rc = 1;
    +     }
    +   }else
    +@@ -2770,15 +12503,14 @@ static int do_meta_command(char *zLine, ShellState *p){
    +     char *zErrMsg = 0;
    +     open_db(p, 0);
    +     memcpy(&data, p, sizeof(data));
    +-    data.showHeader = 1;
    +-    data.mode = MODE_Column;
    +-    data.colWidth[0] = 3;
    +-    data.colWidth[1] = 15;
    +-    data.colWidth[2] = 58;
    ++    data.showHeader = 0;
    ++    data.cMode = data.mode = MODE_List;
    ++    sqlite3_snprintf(sizeof(data.colSeparator),data.colSeparator,": ");
    +     data.cnt = 0;
    +-    sqlite3_exec(p->db, "PRAGMA database_list; ", callback, &data, &zErrMsg);
    ++    sqlite3_exec(p->db, "SELECT name, file FROM pragma_database_list",
    ++                 callback, &data, &zErrMsg);
    +     if( zErrMsg ){
    +-      fprintf(stderr,"Error: %s\n", zErrMsg);
    ++      utf8_printf(stderr,"Error: %s\n", zErrMsg);
    +       sqlite3_free(zErrMsg);
    +       rc = 1;
    +     }
    +@@ -2789,26 +12521,60 @@ static int do_meta_command(char *zLine, ShellState *p){
    +   }else
    + 
    +   if( c=='d' && strncmp(azArg[0], "dump", n)==0 ){
    ++    const char *zLike = 0;
    ++    int i;
    ++    int savedShowHeader = p->showHeader;
    ++    ShellClearFlag(p, SHFLG_PreserveRowid|SHFLG_Newlines);
    ++    for(i=1; i<nArg; i++){
    ++      if( azArg[i][0]=='-' ){
    ++        const char *z = azArg[i]+1;
    ++        if( z[0]=='-' ) z++;
    ++        if( strcmp(z,"preserve-rowids")==0 ){
    ++#ifdef SQLITE_OMIT_VIRTUALTABLE
    ++          raw_printf(stderr, "The --preserve-rowids option is not compatible"
    ++                             " with SQLITE_OMIT_VIRTUALTABLE\n");
    ++          rc = 1;
    ++          goto meta_command_exit;
    ++#else
    ++          ShellSetFlag(p, SHFLG_PreserveRowid);
    ++#endif
    ++        }else
    ++        if( strcmp(z,"newlines")==0 ){
    ++          ShellSetFlag(p, SHFLG_Newlines);
    ++        }else
    ++        {
    ++          raw_printf(stderr, "Unknown option \"%s\" on \".dump\"\n", azArg[i]);
    ++          rc = 1;
    ++          goto meta_command_exit;
    ++        }
    ++      }else if( zLike ){
    ++        raw_printf(stderr, "Usage: .dump ?--preserve-rowids? "
    ++                           "?--newlines? ?LIKE-PATTERN?\n");
    ++        rc = 1;
    ++        goto meta_command_exit;
    ++      }else{
    ++        zLike = azArg[i];
    ++      }
    ++    }
    +     open_db(p, 0);
    +     /* When playing back a "dump", the content might appear in an order
    +     ** which causes immediate foreign key constraints to be violated.
    +     ** So disable foreign-key constraint enforcement to prevent problems. */
    +-    if( nArg!=1 && nArg!=2 ){
    +-      fprintf(stderr, "Usage: .dump ?LIKE-PATTERN?\n");
    +-      rc = 1;
    +-      goto meta_command_exit;
    +-    }
    +-    fprintf(p->out, "PRAGMA foreign_keys=OFF;\n");
    +-    fprintf(p->out, "BEGIN TRANSACTION;\n");
    ++    raw_printf(p->out, "PRAGMA foreign_keys=OFF;\n");
    ++    raw_printf(p->out, "BEGIN TRANSACTION;\n");
    +     p->writableSchema = 0;
    ++    p->showHeader = 0;
    ++    /* Set writable_schema=ON since doing so forces SQLite to initialize
    ++    ** as much of the schema as it can even if the sqlite_master table is
    ++    ** corrupt. */
    +     sqlite3_exec(p->db, "SAVEPOINT dump; PRAGMA writable_schema=ON", 0, 0, 0);
    +     p->nErr = 0;
    +-    if( nArg==1 ){
    +-      run_schema_dump_query(p, 
    ++    if( zLike==0 ){
    ++      run_schema_dump_query(p,
    +         "SELECT name, type, sql FROM sqlite_master "
    +         "WHERE sql NOT NULL AND type=='table' AND name!='sqlite_sequence'"
    +       );
    +-      run_schema_dump_query(p, 
    ++      run_schema_dump_query(p,
    +         "SELECT name, type, sql FROM sqlite_master "
    +         "WHERE name=='sqlite_sequence'"
    +       );
    +@@ -2817,47 +12583,53 @@ static int do_meta_command(char *zLine, ShellState *p){
    +         "WHERE sql NOT NULL AND type IN ('index','trigger','view')", 0
    +       );
    +     }else{
    +-      int i;
    +-      for(i=1; i<nArg; i++){
    +-        zShellStatic = azArg[i];
    +-        run_schema_dump_query(p,
    +-          "SELECT name, type, sql FROM sqlite_master "
    +-          "WHERE tbl_name LIKE shellstatic() AND type=='table'"
    +-          "  AND sql NOT NULL");
    +-        run_table_dump_query(p,
    +-          "SELECT sql FROM sqlite_master "
    +-          "WHERE sql NOT NULL"
    +-          "  AND type IN ('index','trigger','view')"
    +-          "  AND tbl_name LIKE shellstatic()", 0
    +-        );
    +-        zShellStatic = 0;
    +-      }
    ++      char *zSql;
    ++      zSql = sqlite3_mprintf(
    ++        "SELECT name, type, sql FROM sqlite_master "
    ++        "WHERE tbl_name LIKE %Q AND type=='table'"
    ++        "  AND sql NOT NULL", zLike);
    ++      run_schema_dump_query(p,zSql);
    ++      sqlite3_free(zSql);
    ++      zSql = sqlite3_mprintf(
    ++        "SELECT sql FROM sqlite_master "
    ++        "WHERE sql NOT NULL"
    ++        "  AND type IN ('index','trigger','view')"
    ++        "  AND tbl_name LIKE %Q", zLike);
    ++      run_table_dump_query(p, zSql, 0);
    ++      sqlite3_free(zSql);
    +     }
    +     if( p->writableSchema ){
    +-      fprintf(p->out, "PRAGMA writable_schema=OFF;\n");
    ++      raw_printf(p->out, "PRAGMA writable_schema=OFF;\n");
    +       p->writableSchema = 0;
    +     }
    +     sqlite3_exec(p->db, "PRAGMA writable_schema=OFF;", 0, 0, 0);
    +     sqlite3_exec(p->db, "RELEASE dump;", 0, 0, 0);
    +-    fprintf(p->out, p->nErr ? "ROLLBACK; -- due to errors\n" : "COMMIT;\n");
    ++    raw_printf(p->out, p->nErr ? "ROLLBACK; -- due to errors\n" : "COMMIT;\n");
    ++    p->showHeader = savedShowHeader;
    +   }else
    + 
    +   if( c=='e' && strncmp(azArg[0], "echo", n)==0 ){
    +     if( nArg==2 ){
    +-      p->echoOn = booleanValue(azArg[1]);
    ++      setOrClearFlag(p, SHFLG_Echo, azArg[1]);
    +     }else{
    +-      fprintf(stderr, "Usage: .echo on|off\n");
    ++      raw_printf(stderr, "Usage: .echo on|off\n");
    +       rc = 1;
    +     }
    +   }else
    + 
    +   if( c=='e' && strncmp(azArg[0], "eqp", n)==0 ){
    +     if( nArg==2 ){
    +-      p->autoEQP = booleanValue(azArg[1]);
    ++      if( strcmp(azArg[1],"full")==0 ){
    ++        p->autoEQP = AUTOEQP_full;
    ++      }else if( strcmp(azArg[1],"trigger")==0 ){
    ++        p->autoEQP = AUTOEQP_trigger;
    ++      }else{
    ++        p->autoEQP = booleanValue(azArg[1]);
    ++      }
    +     }else{
    +-      fprintf(stderr, "Usage: .eqp on|off\n");
    ++      raw_printf(stderr, "Usage: .eqp off|on|trigger|full\n");
    +       rc = 1;
    +-    }   
    ++    }
    +   }else
    + 
    +   if( c=='e' && strncmp(azArg[0], "exit", n)==0 ){
    +@@ -2865,54 +12637,54 @@ static int do_meta_command(char *zLine, ShellState *p){
    +     rc = 2;
    +   }else
    + 
    ++  /* The ".explain" command is automatic now.  It is largely pointless.  It
    ++  ** retained purely for backwards compatibility */
    +   if( c=='e' && strncmp(azArg[0], "explain", n)==0 ){
    +-    int val = nArg>=2 ? booleanValue(azArg[1]) : 1;
    +-    if(val == 1) {
    +-      if(!p->normalMode.valid) {
    +-        p->normalMode.valid = 1;
    +-        p->normalMode.mode = p->mode;
    +-        p->normalMode.showHeader = p->showHeader;
    +-        memcpy(p->normalMode.colWidth,p->colWidth,sizeof(p->colWidth));
    +-      }
    +-      /* We could put this code under the !p->explainValid
    +-      ** condition so that it does not execute if we are already in
    +-      ** explain mode. However, always executing it allows us an easy
    +-      ** was to reset to explain mode in case the user previously
    +-      ** did an .explain followed by a .width, .mode or .header
    +-      ** command.
    +-      */
    ++    int val = 1;
    ++    if( nArg>=2 ){
    ++      if( strcmp(azArg[1],"auto")==0 ){
    ++        val = 99;
    ++      }else{
    ++        val =  booleanValue(azArg[1]);
    ++      }
    ++    }
    ++    if( val==1 && p->mode!=MODE_Explain ){
    ++      p->normalMode = p->mode;
    +       p->mode = MODE_Explain;
    +-      p->showHeader = 1;
    +-      memset(p->colWidth,0,sizeof(p->colWidth));
    +-      p->colWidth[0] = 4;                  /* addr */
    +-      p->colWidth[1] = 13;                 /* opcode */
    +-      p->colWidth[2] = 4;                  /* P1 */
    +-      p->colWidth[3] = 4;                  /* P2 */
    +-      p->colWidth[4] = 4;                  /* P3 */
    +-      p->colWidth[5] = 13;                 /* P4 */
    +-      p->colWidth[6] = 2;                  /* P5 */
    +-      p->colWidth[7] = 13;                  /* Comment */
    +-    }else if (p->normalMode.valid) {
    +-      p->normalMode.valid = 0;
    +-      p->mode = p->normalMode.mode;
    +-      p->showHeader = p->normalMode.showHeader;
    +-      memcpy(p->colWidth,p->normalMode.colWidth,sizeof(p->colWidth));
    ++      p->autoExplain = 0;
    ++    }else if( val==0 ){
    ++      if( p->mode==MODE_Explain ) p->mode = p->normalMode;
    ++      p->autoExplain = 0;
    ++    }else if( val==99 ){
    ++      if( p->mode==MODE_Explain ) p->mode = p->normalMode;
    ++      p->autoExplain = 1;
    +     }
    +   }else
    + 
    ++#ifndef SQLITE_OMIT_VIRTUALTABLE
    ++  if( c=='e' && strncmp(azArg[0], "expert", n)==0 ){
    ++    open_db(p, 0);
    ++    expertDotCommand(p, azArg, nArg);
    ++  }else
    ++#endif
    ++
    +   if( c=='f' && strncmp(azArg[0], "fullschema", n)==0 ){
    +     ShellState data;
    +     char *zErrMsg = 0;
    +     int doStats = 0;
    ++    memcpy(&data, p, sizeof(data));
    ++    data.showHeader = 0;
    ++    data.cMode = data.mode = MODE_Semi;
    ++    if( nArg==2 && optionMatch(azArg[1], "indent") ){
    ++      data.cMode = data.mode = MODE_Pretty;
    ++      nArg = 1;
    ++    }
    +     if( nArg!=1 ){
    +-      fprintf(stderr, "Usage: .fullschema\n");
    ++      raw_printf(stderr, "Usage: .fullschema ?--indent?\n");
    +       rc = 1;
    +       goto meta_command_exit;
    +     }
    +     open_db(p, 0);
    +-    memcpy(&data, p, sizeof(data));
    +-    data.showHeader = 0;
    +-    data.mode = MODE_Semi;
    +     rc = sqlite3_exec(p->db,
    +        "SELECT sql FROM"
    +        "  (SELECT sql sql, type type, tbl_name tbl_name, name name, rowid x"
    +@@ -2932,12 +12704,12 @@ static int do_meta_command(char *zLine, ShellState *p){
    +       sqlite3_finalize(pStmt);
    +     }
    +     if( doStats==0 ){
    +-      fprintf(p->out, "/* No STAT tables available */\n");
    ++      raw_printf(p->out, "/* No STAT tables available */\n");
    +     }else{
    +-      fprintf(p->out, "ANALYZE sqlite_master;\n");
    ++      raw_printf(p->out, "ANALYZE sqlite_master;\n");
    +       sqlite3_exec(p->db, "SELECT 'ANALYZE sqlite_master'",
    +                    callback, &data, &zErrMsg);
    +-      data.mode = MODE_Insert;
    ++      data.cMode = data.mode = MODE_Insert;
    +       data.zDestTable = "sqlite_stat1";
    +       shell_exec(p->db, "SELECT * FROM sqlite_stat1",
    +                  shell_callback, &data,&zErrMsg);
    +@@ -2947,7 +12719,7 @@ static int do_meta_command(char *zLine, ShellState *p){
    +       data.zDestTable = "sqlite_stat4";
    +       shell_exec(p->db, "SELECT * FROM sqlite_stat4",
    +                  shell_callback, &data, &zErrMsg);
    +-      fprintf(p->out, "ANALYZE sqlite_master;\n");
    ++      raw_printf(p->out, "ANALYZE sqlite_master;\n");
    +     }
    +   }else
    + 
    +@@ -2955,13 +12727,13 @@ static int do_meta_command(char *zLine, ShellState *p){
    +     if( nArg==2 ){
    +       p->showHeader = booleanValue(azArg[1]);
    +     }else{
    +-      fprintf(stderr, "Usage: .headers on|off\n");
    ++      raw_printf(stderr, "Usage: .headers on|off\n");
    +       rc = 1;
    +     }
    +   }else
    + 
    +   if( c=='h' && strncmp(azArg[0], "help", n)==0 ){
    +-    fprintf(p->out, "%s", zHelp);
    ++    utf8_printf(p->out, "%s", zHelp);
    +   }else
    + 
    +   if( c=='i' && strncmp(azArg[0], "import", n)==0 ){
    +@@ -2979,7 +12751,7 @@ static int do_meta_command(char *zLine, ShellState *p){
    +     int (SQLITE_CDECL *xCloser)(FILE*);      /* Func to close file */
    + 
    +     if( nArg!=3 ){
    +-      fprintf(stderr, "Usage: .import FILE TABLE\n");
    ++      raw_printf(stderr, "Usage: .import FILE TABLE\n");
    +       goto meta_command_exit;
    +     }
    +     zFile = azArg[1];
    +@@ -2989,17 +12761,18 @@ static int do_meta_command(char *zLine, ShellState *p){
    +     open_db(p, 0);
    +     nSep = strlen30(p->colSeparator);
    +     if( nSep==0 ){
    +-      fprintf(stderr, "Error: non-null column separator required for import\n");
    ++      raw_printf(stderr,
    ++                 "Error: non-null column separator required for import\n");
    +       return 1;
    +     }
    +     if( nSep>1 ){
    +-      fprintf(stderr, "Error: multi-character column separators not allowed"
    ++      raw_printf(stderr, "Error: multi-character column separators not allowed"
    +                       " for import\n");
    +       return 1;
    +     }
    +     nSep = strlen30(p->rowSeparator);
    +     if( nSep==0 ){
    +-      fprintf(stderr, "Error: non-null row separator required for import\n");
    ++      raw_printf(stderr, "Error: non-null row separator required for import\n");
    +       return 1;
    +     }
    +     if( nSep==2 && p->mode==MODE_Csv && strcmp(p->rowSeparator, SEP_CrLf)==0 ){
    +@@ -3011,7 +12784,7 @@ static int do_meta_command(char *zLine, ShellState *p){
    +       nSep = strlen30(p->rowSeparator);
    +     }
    +     if( nSep>1 ){
    +-      fprintf(stderr, "Error: multi-character row separators not allowed"
    ++      raw_printf(stderr, "Error: multi-character row separators not allowed"
    +                       " for import\n");
    +       return 1;
    +     }
    +@@ -3019,7 +12792,7 @@ static int do_meta_command(char *zLine, ShellState *p){
    +     sCtx.nLine = 1;
    +     if( sCtx.zFile[0]=='|' ){
    + #ifdef SQLITE_OMIT_POPEN
    +-      fprintf(stderr, "Error: pipes are not supported in this OS\n");
    ++      raw_printf(stderr, "Error: pipes are not supported in this OS\n");
    +       return 1;
    + #else
    +       sCtx.in = popen(sCtx.zFile+1, "r");
    +@@ -3036,14 +12809,14 @@ static int do_meta_command(char *zLine, ShellState *p){
    +       xRead = csv_read_one_field;
    +     }
    +     if( sCtx.in==0 ){
    +-      fprintf(stderr, "Error: cannot open \"%s\"\n", zFile);
    ++      utf8_printf(stderr, "Error: cannot open \"%s\"\n", zFile);
    +       return 1;
    +     }
    +     sCtx.cColSep = p->colSeparator[0];
    +     sCtx.cRowSep = p->rowSeparator[0];
    +     zSql = sqlite3_mprintf("SELECT * FROM %s", zTable);
    +     if( zSql==0 ){
    +-      fprintf(stderr, "Error: out of memory\n");
    ++      raw_printf(stderr, "Error: out of memory\n");
    +       xCloser(sCtx.in);
    +       return 1;
    +     }
    +@@ -3054,7 +12827,7 @@ static int do_meta_command(char *zLine, ShellState *p){
    +       char *zCreate = sqlite3_mprintf("CREATE TABLE %s", zTable);
    +       char cSep = '(';
    +       while( xRead(&sCtx) ){
    +-        zCreate = sqlite3_mprintf("%z%c\n  \"%s\" TEXT", zCreate, cSep, sCtx.z);
    ++        zCreate = sqlite3_mprintf("%z%c\n  \"%w\" TEXT", zCreate, cSep, sCtx.z);
    +         cSep = ',';
    +         if( sCtx.cTerm!=sCtx.cColSep ) break;
    +       }
    +@@ -3062,14 +12835,14 @@ static int do_meta_command(char *zLine, ShellState *p){
    +         sqlite3_free(zCreate);
    +         sqlite3_free(sCtx.z);
    +         xCloser(sCtx.in);
    +-        fprintf(stderr,"%s: empty file\n", sCtx.zFile);
    ++        utf8_printf(stderr,"%s: empty file\n", sCtx.zFile);
    +         return 1;
    +       }
    +       zCreate = sqlite3_mprintf("%z\n)", zCreate);
    +       rc = sqlite3_exec(p->db, zCreate, 0, 0, 0);
    +       sqlite3_free(zCreate);
    +       if( rc ){
    +-        fprintf(stderr, "CREATE TABLE %s(...) failed: %s\n", zTable,
    ++        utf8_printf(stderr, "CREATE TABLE %s(...) failed: %s\n", zTable,
    +                 sqlite3_errmsg(p->db));
    +         sqlite3_free(sCtx.z);
    +         xCloser(sCtx.in);
    +@@ -3080,7 +12853,7 @@ static int do_meta_command(char *zLine, ShellState *p){
    +     sqlite3_free(zSql);
    +     if( rc ){
    +       if (pStmt) sqlite3_finalize(pStmt);
    +-      fprintf(stderr,"Error: %s\n", sqlite3_errmsg(p->db));
    ++      utf8_printf(stderr,"Error: %s\n", sqlite3_errmsg(p->db));
    +       xCloser(sCtx.in);
    +       return 1;
    +     }
    +@@ -3090,7 +12863,7 @@ static int do_meta_command(char *zLine, ShellState *p){
    +     if( nCol==0 ) return 0; /* no columns, no error */
    +     zSql = sqlite3_malloc64( nByte*2 + 20 + nCol*2 );
    +     if( zSql==0 ){
    +-      fprintf(stderr, "Error: out of memory\n");
    ++      raw_printf(stderr, "Error: out of memory\n");
    +       xCloser(sCtx.in);
    +       return 1;
    +     }
    +@@ -3105,7 +12878,7 @@ static int do_meta_command(char *zLine, ShellState *p){
    +     rc = sqlite3_prepare_v2(p->db, zSql, -1, &pStmt, 0);
    +     sqlite3_free(zSql);
    +     if( rc ){
    +-      fprintf(stderr, "Error: %s\n", sqlite3_errmsg(p->db));
    ++      utf8_printf(stderr, "Error: %s\n", sqlite3_errmsg(p->db));
    +       if (pStmt) sqlite3_finalize(pStmt);
    +       xCloser(sCtx.in);
    +       return 1;
    +@@ -3129,7 +12902,7 @@ static int do_meta_command(char *zLine, ShellState *p){
    +         if( p->mode==MODE_Ascii && (z==0 || z[0]==0) && i==0 ) break;
    +         sqlite3_bind_text(pStmt, i+1, z, -1, SQLITE_TRANSIENT);
    +         if( i<nCol-1 && sCtx.cTerm!=sCtx.cColSep ){
    +-          fprintf(stderr, "%s:%d: expected %d columns but found %d - "
    ++          utf8_printf(stderr, "%s:%d: expected %d columns but found %d - "
    +                           "filling the rest with NULL\n",
    +                           sCtx.zFile, startLine, nCol, i+1);
    +           i += 2;
    +@@ -3141,7 +12914,7 @@ static int do_meta_command(char *zLine, ShellState *p){
    +           xRead(&sCtx);
    +           i++;
    +         }while( sCtx.cTerm==sCtx.cColSep );
    +-        fprintf(stderr, "%s:%d: expected %d columns but found %d - "
    ++        utf8_printf(stderr, "%s:%d: expected %d columns but found %d - "
    +                         "extras ignored\n",
    +                         sCtx.zFile, startLine, nCol, i);
    +       }
    +@@ -3149,8 +12922,8 @@ static int do_meta_command(char *zLine, ShellState *p){
    +         sqlite3_step(pStmt);
    +         rc = sqlite3_reset(pStmt);
    +         if( rc!=SQLITE_OK ){
    +-          fprintf(stderr, "%s:%d: INSERT failed: %s\n", sCtx.zFile, startLine,
    +-                  sqlite3_errmsg(p->db));
    ++          utf8_printf(stderr, "%s:%d: INSERT failed: %s\n", sCtx.zFile,
    ++                      startLine, sqlite3_errmsg(p->db));
    +         }
    +       }
    +     }while( sCtx.cTerm!=EOF );
    +@@ -3161,50 +12934,78 @@ static int do_meta_command(char *zLine, ShellState *p){
    +     if( needCommit ) sqlite3_exec(p->db, "COMMIT", 0, 0, 0);
    +   }else
    + 
    +-  if( c=='i' && (strncmp(azArg[0], "indices", n)==0
    +-                 || strncmp(azArg[0], "indexes", n)==0) ){
    +-    ShellState data;
    +-    char *zErrMsg = 0;
    +-    open_db(p, 0);
    +-    memcpy(&data, p, sizeof(data));
    +-    data.showHeader = 0;
    +-    data.mode = MODE_List;
    +-    if( nArg==1 ){
    +-      rc = sqlite3_exec(p->db,
    +-        "SELECT name FROM sqlite_master "
    +-        "WHERE type='index' AND name NOT LIKE 'sqlite_%' "
    +-        "UNION ALL "
    +-        "SELECT name FROM sqlite_temp_master "
    +-        "WHERE type='index' "
    +-        "ORDER BY 1",
    +-        callback, &data, &zErrMsg
    +-      );
    +-    }else if( nArg==2 ){
    +-      zShellStatic = azArg[1];
    +-      rc = sqlite3_exec(p->db,
    +-        "SELECT name FROM sqlite_master "
    +-        "WHERE type='index' AND tbl_name LIKE shellstatic() "
    +-        "UNION ALL "
    +-        "SELECT name FROM sqlite_temp_master "
    +-        "WHERE type='index' AND tbl_name LIKE shellstatic() "
    +-        "ORDER BY 1",
    +-        callback, &data, &zErrMsg
    +-      );
    +-      zShellStatic = 0;
    +-    }else{
    +-      fprintf(stderr, "Usage: .indexes ?LIKE-PATTERN?\n");
    ++#ifndef SQLITE_UNTESTABLE
    ++  if( c=='i' && strncmp(azArg[0], "imposter", n)==0 ){
    ++    char *zSql;
    ++    char *zCollist = 0;
    ++    sqlite3_stmt *pStmt;
    ++    int tnum = 0;
    ++    int i;
    ++    if( nArg!=3 ){
    ++      utf8_printf(stderr, "Usage: .imposter INDEX IMPOSTER\n");
    +       rc = 1;
    +       goto meta_command_exit;
    +     }
    +-    if( zErrMsg ){
    +-      fprintf(stderr,"Error: %s\n", zErrMsg);
    +-      sqlite3_free(zErrMsg);
    ++    open_db(p, 0);
    ++    zSql = sqlite3_mprintf("SELECT rootpage FROM sqlite_master"
    ++                           " WHERE name='%q' AND type='index'", azArg[1]);
    ++    sqlite3_prepare_v2(p->db, zSql, -1, &pStmt, 0);
    ++    sqlite3_free(zSql);
    ++    if( sqlite3_step(pStmt)==SQLITE_ROW ){
    ++      tnum = sqlite3_column_int(pStmt, 0);
    ++    }
    ++    sqlite3_finalize(pStmt);
    ++    if( tnum==0 ){
    ++      utf8_printf(stderr, "no such index: \"%s\"\n", azArg[1]);
    +       rc = 1;
    +-    }else if( rc != SQLITE_OK ){
    +-      fprintf(stderr,"Error: querying sqlite_master and sqlite_temp_master\n");
    ++      goto meta_command_exit;
    ++    }
    ++    zSql = sqlite3_mprintf("PRAGMA index_xinfo='%q'", azArg[1]);
    ++    rc = sqlite3_prepare_v2(p->db, zSql, -1, &pStmt, 0);
    ++    sqlite3_free(zSql);
    ++    i = 0;
    ++    while( sqlite3_step(pStmt)==SQLITE_ROW ){
    ++      char zLabel[20];
    ++      const char *zCol = (const char*)sqlite3_column_text(pStmt,2);
    ++      i++;
    ++      if( zCol==0 ){
    ++        if( sqlite3_column_int(pStmt,1)==-1 ){
    ++          zCol = "_ROWID_";
    ++        }else{
    ++          sqlite3_snprintf(sizeof(zLabel),zLabel,"expr%d",i);
    ++          zCol = zLabel;
    ++        }
    ++      }
    ++      if( zCollist==0 ){
    ++        zCollist = sqlite3_mprintf("\"%w\"", zCol);
    ++      }else{
    ++        zCollist = sqlite3_mprintf("%z,\"%w\"", zCollist, zCol);
    ++      }
    ++    }
    ++    sqlite3_finalize(pStmt);
    ++    zSql = sqlite3_mprintf(
    ++          "CREATE TABLE \"%w\"(%s,PRIMARY KEY(%s))WITHOUT ROWID",
    ++          azArg[2], zCollist, zCollist);
    ++    sqlite3_free(zCollist);
    ++    rc = sqlite3_test_control(SQLITE_TESTCTRL_IMPOSTER, p->db, "main", 1, tnum);
    ++    if( rc==SQLITE_OK ){
    ++      rc = sqlite3_exec(p->db, zSql, 0, 0, 0);
    ++      sqlite3_test_control(SQLITE_TESTCTRL_IMPOSTER, p->db, "main", 0, 0);
    ++      if( rc ){
    ++        utf8_printf(stderr, "Error in [%s]: %s\n", zSql, sqlite3_errmsg(p->db));
    ++      }else{
    ++        utf8_printf(stdout, "%s;\n", zSql);
    ++        raw_printf(stdout,
    ++           "WARNING: writing to an imposter table will corrupt the index!\n"
    ++        );
    ++      }
    ++    }else{
    ++      raw_printf(stderr, "SQLITE_TESTCTRL_IMPOSTER returns %d\n", rc);
    +       rc = 1;
    +     }
    ++    sqlite3_free(zSql);
    +   }else
    ++#endif /* !defined(SQLITE_OMIT_TEST_CONTROL) */
    + 
    + #ifdef SQLITE_ENABLE_IOTRACE
    +   if( c=='i' && strncmp(azArg[0], "iotrace", n)==0 ){
    +@@ -3219,7 +13020,7 @@ static int do_meta_command(char *zLine, ShellState *p){
    +     }else{
    +       iotrace = fopen(azArg[1], "w");
    +       if( iotrace==0 ){
    +-        fprintf(stderr, "Error: cannot open \"%s\"\n", azArg[1]);
    ++        utf8_printf(stderr, "Error: cannot open \"%s\"\n", azArg[1]);
    +         sqlite3IoTrace = 0;
    +         rc = 1;
    +       }else{
    +@@ -3228,6 +13029,7 @@ static int do_meta_command(char *zLine, ShellState *p){
    +     }
    +   }else
    + #endif
    ++
    +   if( c=='l' && n>=5 && strncmp(azArg[0], "limits", n)==0 ){
    +     static const struct {
    +        const char *zLimitName;   /* Name of a limit */
    +@@ -3250,11 +13052,11 @@ static int do_meta_command(char *zLine, ShellState *p){
    +     open_db(p, 0);
    +     if( nArg==1 ){
    +       for(i=0; i<ArraySize(aLimit); i++){
    +-        printf("%20s %d\n", aLimit[i].zLimitName, 
    ++        printf("%20s %d\n", aLimit[i].zLimitName,
    +                sqlite3_limit(p->db, aLimit[i].limitCode, -1));
    +       }
    +     }else if( nArg>3 ){
    +-      fprintf(stderr, "Usage: .limit NAME ?NEW-VALUE?\n");
    ++      raw_printf(stderr, "Usage: .limit NAME ?NEW-VALUE?\n");
    +       rc = 1;
    +       goto meta_command_exit;
    +     }else{
    +@@ -3265,14 +13067,14 @@ static int do_meta_command(char *zLine, ShellState *p){
    +           if( iLimit<0 ){
    +             iLimit = i;
    +           }else{
    +-            fprintf(stderr, "ambiguous limit: \"%s\"\n", azArg[1]);
    ++            utf8_printf(stderr, "ambiguous limit: \"%s\"\n", azArg[1]);
    +             rc = 1;
    +             goto meta_command_exit;
    +           }
    +         }
    +       }
    +       if( iLimit<0 ){
    +-        fprintf(stderr, "unknown limit: \"%s\"\n"
    ++        utf8_printf(stderr, "unknown limit: \"%s\"\n"
    +                         "enter \".limits\" with no arguments for a list.\n",
    +                          azArg[1]);
    +         rc = 1;
    +@@ -3287,12 +13089,17 @@ static int do_meta_command(char *zLine, ShellState *p){
    +     }
    +   }else
    + 
    ++  if( c=='l' && n>2 && strncmp(azArg[0], "lint", n)==0 ){
    ++    open_db(p, 0);
    ++    lintDotCommand(p, azArg, nArg);
    ++  }else
    ++
    + #ifndef SQLITE_OMIT_LOAD_EXTENSION
    +   if( c=='l' && strncmp(azArg[0], "load", n)==0 ){
    +     const char *zFile, *zProc;
    +     char *zErrMsg = 0;
    +     if( nArg<2 ){
    +-      fprintf(stderr, "Usage: .load FILE ?ENTRYPOINT?\n");
    ++      raw_printf(stderr, "Usage: .load FILE ?ENTRYPOINT?\n");
    +       rc = 1;
    +       goto meta_command_exit;
    +     }
    +@@ -3301,7 +13108,7 @@ static int do_meta_command(char *zLine, ShellState *p){
    +     open_db(p, 0);
    +     rc = sqlite3_load_extension(p->db, zFile, zProc, &zErrMsg);
    +     if( rc!=SQLITE_OK ){
    +-      fprintf(stderr, "Error: %s\n", zErrMsg);
    ++      utf8_printf(stderr, "Error: %s\n", zErrMsg);
    +       sqlite3_free(zErrMsg);
    +       rc = 1;
    +     }
    +@@ -3310,30 +13117,35 @@ static int do_meta_command(char *zLine, ShellState *p){
    + 
    +   if( c=='l' && strncmp(azArg[0], "log", n)==0 ){
    +     if( nArg!=2 ){
    +-      fprintf(stderr, "Usage: .log FILENAME\n");
    ++      raw_printf(stderr, "Usage: .log FILENAME\n");
    +       rc = 1;
    +     }else{
    +       const char *zFile = azArg[1];
    +       output_file_close(p->pLog);
    +-      p->pLog = output_file_open(zFile);
    ++      p->pLog = output_file_open(zFile, 0);
    +     }
    +   }else
    + 
    +   if( c=='m' && strncmp(azArg[0], "mode", n)==0 ){
    +     const char *zMode = nArg>=2 ? azArg[1] : "";
    +-    int n2 = (int)strlen(zMode);
    ++    int n2 = strlen30(zMode);
    +     int c2 = zMode[0];
    +     if( c2=='l' && n2>2 && strncmp(azArg[1],"lines",n2)==0 ){
    +       p->mode = MODE_Line;
    ++      sqlite3_snprintf(sizeof(p->rowSeparator), p->rowSeparator, SEP_Row);
    +     }else if( c2=='c' && strncmp(azArg[1],"columns",n2)==0 ){
    +       p->mode = MODE_Column;
    ++      sqlite3_snprintf(sizeof(p->rowSeparator), p->rowSeparator, SEP_Row);
    +     }else if( c2=='l' && n2>2 && strncmp(azArg[1],"list",n2)==0 ){
    +       p->mode = MODE_List;
    ++      sqlite3_snprintf(sizeof(p->colSeparator), p->colSeparator, SEP_Column);
    ++      sqlite3_snprintf(sizeof(p->rowSeparator), p->rowSeparator, SEP_Row);
    +     }else if( c2=='h' && strncmp(azArg[1],"html",n2)==0 ){
    +       p->mode = MODE_Html;
    +     }else if( c2=='t' && strncmp(azArg[1],"tcl",n2)==0 ){
    +       p->mode = MODE_Tcl;
    +       sqlite3_snprintf(sizeof(p->colSeparator), p->colSeparator, SEP_Space);
    ++      sqlite3_snprintf(sizeof(p->rowSeparator), p->rowSeparator, SEP_Row);
    +     }else if( c2=='c' && strncmp(azArg[1],"csv",n2)==0 ){
    +       p->mode = MODE_Csv;
    +       sqlite3_snprintf(sizeof(p->colSeparator), p->colSeparator, SEP_Comma);
    +@@ -3344,15 +13156,20 @@ static int do_meta_command(char *zLine, ShellState *p){
    +     }else if( c2=='i' && strncmp(azArg[1],"insert",n2)==0 ){
    +       p->mode = MODE_Insert;
    +       set_table_name(p, nArg>=3 ? azArg[2] : "table");
    ++    }else if( c2=='q' && strncmp(azArg[1],"quote",n2)==0 ){
    ++      p->mode = MODE_Quote;
    +     }else if( c2=='a' && strncmp(azArg[1],"ascii",n2)==0 ){
    +       p->mode = MODE_Ascii;
    +       sqlite3_snprintf(sizeof(p->colSeparator), p->colSeparator, SEP_Unit);
    +       sqlite3_snprintf(sizeof(p->rowSeparator), p->rowSeparator, SEP_Record);
    +-    }else {
    +-      fprintf(stderr,"Error: mode should be one of: "
    +-         "ascii column csv html insert line list tabs tcl\n");
    ++    }else if( nArg==1 ){
    ++      raw_printf(p->out, "current output mode: %s\n", modeDescr[p->mode]);
    ++    }else{
    ++      raw_printf(stderr, "Error: mode should be one of: "
    ++         "ascii column csv html insert line list quote tabs tcl\n");
    +       rc = 1;
    +     }
    ++    p->cMode = p->mode;
    +   }else
    + 
    +   if( c=='n' && strncmp(azArg[0], "nullvalue", n)==0 ){
    +@@ -3360,42 +13177,81 @@ static int do_meta_command(char *zLine, ShellState *p){
    +       sqlite3_snprintf(sizeof(p->nullValue), p->nullValue,
    +                        "%.*s", (int)ArraySize(p->nullValue)-1, azArg[1]);
    +     }else{
    +-      fprintf(stderr, "Usage: .nullvalue STRING\n");
    ++      raw_printf(stderr, "Usage: .nullvalue STRING\n");
    +       rc = 1;
    +     }
    +   }else
    + 
    +   if( c=='o' && strncmp(azArg[0], "open", n)==0 && n>=2 ){
    +-    sqlite3 *savedDb = p->db;
    +-    const char *zSavedFilename = p->zDbFilename;
    +-    char *zNewFilename = 0;
    ++    char *zNewFilename;  /* Name of the database file to open */
    ++    int iName = 1;       /* Index in azArg[] of the filename */
    ++    int newFlag = 0;     /* True to delete file before opening */
    ++    /* Close the existing database */
    ++    session_close_all(p);
    ++    sqlite3_close(p->db);
    +     p->db = 0;
    +-    if( nArg>=2 ) zNewFilename = sqlite3_mprintf("%s", azArg[1]);
    +-    p->zDbFilename = zNewFilename;
    +-    open_db(p, 1);
    +-    if( p->db!=0 ){
    +-      sqlite3_close(savedDb);
    +-      sqlite3_free(p->zFreeOnClose);
    +-      p->zFreeOnClose = zNewFilename;
    +-    }else{
    +-      sqlite3_free(zNewFilename);
    +-      p->db = savedDb;
    +-      p->zDbFilename = zSavedFilename;
    ++    p->zDbFilename = 0;
    ++    sqlite3_free(p->zFreeOnClose);
    ++    p->zFreeOnClose = 0;
    ++    p->openMode = SHELL_OPEN_UNSPEC;
    ++    /* Check for command-line arguments */
    ++    for(iName=1; iName<nArg && azArg[iName][0]=='-'; iName++){
    ++      const char *z = azArg[iName];
    ++      if( optionMatch(z,"new") ){
    ++        newFlag = 1;
    ++#ifdef SQLITE_HAVE_ZIP
    ++      }else if( optionMatch(z, "zip") ){
    ++        p->openMode = SHELL_OPEN_ZIPFILE;
    ++#endif
    ++      }else if( optionMatch(z, "append") ){
    ++        p->openMode = SHELL_OPEN_APPENDVFS;
    ++      }else if( z[0]=='-' ){
    ++        utf8_printf(stderr, "unknown option: %s\n", z);
    ++        rc = 1;
    ++        goto meta_command_exit;
    ++      }
    ++    }
    ++    /* If a filename is specified, try to open it first */
    ++    zNewFilename = nArg>iName ? sqlite3_mprintf("%s", azArg[iName]) : 0;
    ++    if( zNewFilename ){
    ++      if( newFlag ) shellDeleteFile(zNewFilename);
    ++      p->zDbFilename = zNewFilename;
    ++      open_db(p, 1);
    ++      if( p->db==0 ){
    ++        utf8_printf(stderr, "Error: cannot open '%s'\n", zNewFilename);
    ++        sqlite3_free(zNewFilename);
    ++      }else{
    ++        p->zFreeOnClose = zNewFilename;
    ++      }
    ++    }
    ++    if( p->db==0 ){
    ++      /* As a fall-back open a TEMP database */
    ++      p->zDbFilename = 0;
    ++      open_db(p, 0);
    +     }
    +   }else
    + 
    +-  if( c=='o'
    +-   && (strncmp(azArg[0], "output", n)==0 || strncmp(azArg[0], "once", n)==0)
    ++  if( (c=='o'
    ++        && (strncmp(azArg[0], "output", n)==0||strncmp(azArg[0], "once", n)==0))
    ++   || (c=='e' && n==5 && strcmp(azArg[0],"excel")==0)
    +   ){
    +     const char *zFile = nArg>=2 ? azArg[1] : "stdout";
    ++    int bTxtMode = 0;
    ++    if( azArg[0][0]=='e' ){
    ++      /* Transform the ".excel" command into ".once -x" */
    ++      nArg = 2;
    ++      azArg[0] = "once";
    ++      zFile = azArg[1] = "-x";
    ++      n = 4;
    ++    }
    +     if( nArg>2 ){
    +-      fprintf(stderr, "Usage: .%s FILE\n", azArg[0]);
    ++      utf8_printf(stderr, "Usage: .%s [-e|-x|FILE]\n", azArg[0]);
    +       rc = 1;
    +       goto meta_command_exit;
    +     }
    +     if( n>1 && strncmp(azArg[0], "once", n)==0 ){
    +       if( nArg<2 ){
    +-        fprintf(stderr, "Usage: .once FILE\n");
    ++        raw_printf(stderr, "Usage: .once (-e|-x|FILE)\n");
    +         rc = 1;
    +         goto meta_command_exit;
    +       }
    +@@ -3404,15 +13260,30 @@ static int do_meta_command(char *zLine, ShellState *p){
    +       p->outCount = 0;
    +     }
    +     output_reset(p);
    ++    if( zFile[0]=='-' && zFile[1]=='-' ) zFile++;
    ++    if( strcmp(zFile, "-e")==0 || strcmp(zFile, "-x")==0 ){
    ++      p->doXdgOpen = 1;
    ++      outputModePush(p);
    ++      if( zFile[1]=='x' ){
    ++        newTempFile(p, "csv");
    ++        p->mode = MODE_Csv;
    ++        sqlite3_snprintf(sizeof(p->colSeparator), p->colSeparator, SEP_Comma);
    ++        sqlite3_snprintf(sizeof(p->rowSeparator), p->rowSeparator, SEP_CrLf);
    ++      }else{
    ++        newTempFile(p, "txt");
    ++        bTxtMode = 1;
    ++      }
    ++      zFile = p->zTempFile;
    ++    }
    +     if( zFile[0]=='|' ){
    + #ifdef SQLITE_OMIT_POPEN
    +-      fprintf(stderr,"Error: pipes are not supported in this OS\n");
    ++      raw_printf(stderr, "Error: pipes are not supported in this OS\n");
    +       rc = 1;
    +       p->out = stdout;
    + #else
    +       p->out = popen(zFile + 1, "w");
    +       if( p->out==0 ){
    +-        fprintf(stderr,"Error: cannot open pipe \"%s\"\n", zFile + 1);
    ++        utf8_printf(stderr,"Error: cannot open pipe \"%s\"\n", zFile + 1);
    +         p->out = stdout;
    +         rc = 1;
    +       }else{
    +@@ -3420,10 +13291,10 @@ static int do_meta_command(char *zLine, ShellState *p){
    +       }
    + #endif
    +     }else{
    +-      p->out = output_file_open(zFile);
    ++      p->out = output_file_open(zFile, bTxtMode);
    +       if( p->out==0 ){
    +         if( strcmp(zFile,"off")!=0 ){
    +-          fprintf(stderr,"Error: cannot write to \"%s\"\n", zFile);
    ++          utf8_printf(stderr,"Error: cannot write to \"%s\"\n", zFile);
    +         }
    +         p->out = stdout;
    +         rc = 1;
    +@@ -3436,10 +13307,10 @@ static int do_meta_command(char *zLine, ShellState *p){
    +   if( c=='p' && n>=3 && strncmp(azArg[0], "print", n)==0 ){
    +     int i;
    +     for(i=1; i<nArg; i++){
    +-      if( i>1 ) fprintf(p->out, " ");
    +-      fprintf(p->out, "%s", azArg[i]);
    ++      if( i>1 ) raw_printf(p->out, " ");
    ++      utf8_printf(p->out, "%s", azArg[i]);
    +     }
    +-    fprintf(p->out, "\n");
    ++    raw_printf(p->out, "\n");
    +   }else
    + 
    +   if( c=='p' && strncmp(azArg[0], "prompt", n)==0 ){
    +@@ -3458,13 +13329,13 @@ static int do_meta_command(char *zLine, ShellState *p){
    +   if( c=='r' && n>=3 && strncmp(azArg[0], "read", n)==0 ){
    +     FILE *alt;
    +     if( nArg!=2 ){
    +-      fprintf(stderr, "Usage: .read FILE\n");
    ++      raw_printf(stderr, "Usage: .read FILE\n");
    +       rc = 1;
    +       goto meta_command_exit;
    +     }
    +     alt = fopen(azArg[1], "rb");
    +     if( alt==0 ){
    +-      fprintf(stderr,"Error: cannot open \"%s\"\n", azArg[1]);
    ++      utf8_printf(stderr,"Error: cannot open \"%s\"\n", azArg[1]);
    +       rc = 1;
    +     }else{
    +       rc = process_input(p, alt);
    +@@ -3486,20 +13357,20 @@ static int do_meta_command(char *zLine, ShellState *p){
    +       zSrcFile = azArg[2];
    +       zDb = azArg[1];
    +     }else{
    +-      fprintf(stderr, "Usage: .restore ?DB? FILE\n");
    ++      raw_printf(stderr, "Usage: .restore ?DB? FILE\n");
    +       rc = 1;
    +       goto meta_command_exit;
    +     }
    +     rc = sqlite3_open(zSrcFile, &pSrc);
    +     if( rc!=SQLITE_OK ){
    +-      fprintf(stderr, "Error: cannot open \"%s\"\n", zSrcFile);
    ++      utf8_printf(stderr, "Error: cannot open \"%s\"\n", zSrcFile);
    +       sqlite3_close(pSrc);
    +       return 1;
    +     }
    +     open_db(p, 0);
    +     pBackup = sqlite3_backup_init(p->db, zDb, pSrc, "main");
    +     if( pBackup==0 ){
    +-      fprintf(stderr, "Error: %s\n", sqlite3_errmsg(p->db));
    ++      utf8_printf(stderr, "Error: %s\n", sqlite3_errmsg(p->db));
    +       sqlite3_close(pSrc);
    +       return 1;
    +     }
    +@@ -3514,10 +13385,10 @@ static int do_meta_command(char *zLine, ShellState *p){
    +     if( rc==SQLITE_DONE ){
    +       rc = 0;
    +     }else if( rc==SQLITE_BUSY || rc==SQLITE_LOCKED ){
    +-      fprintf(stderr, "Error: source database is busy\n");
    ++      raw_printf(stderr, "Error: source database is busy\n");
    +       rc = 1;
    +     }else{
    +-      fprintf(stderr, "Error: %s\n", sqlite3_errmsg(p->db));
    ++      utf8_printf(stderr, "Error: %s\n", sqlite3_errmsg(p->db));
    +       rc = 1;
    +     }
    +     sqlite3_close(pSrc);
    +@@ -3528,100 +13399,336 @@ static int do_meta_command(char *zLine, ShellState *p){
    +     if( nArg==2 ){
    +       p->scanstatsOn = booleanValue(azArg[1]);
    + #ifndef SQLITE_ENABLE_STMT_SCANSTATUS
    +-      fprintf(stderr, "Warning: .scanstats not available in this build.\n");
    ++      raw_printf(stderr, "Warning: .scanstats not available in this build.\n");
    + #endif
    +     }else{
    +-      fprintf(stderr, "Usage: .scanstats on|off\n");
    ++      raw_printf(stderr, "Usage: .scanstats on|off\n");
    +       rc = 1;
    +     }
    +   }else
    + 
    +   if( c=='s' && strncmp(azArg[0], "schema", n)==0 ){
    ++    ShellText sSelect;
    +     ShellState data;
    +     char *zErrMsg = 0;
    ++    const char *zDiv = "(";
    ++    const char *zName = 0;
    ++    int iSchema = 0;
    ++    int bDebug = 0;
    ++    int ii;
    ++
    +     open_db(p, 0);
    +     memcpy(&data, p, sizeof(data));
    +     data.showHeader = 0;
    +-    data.mode = MODE_Semi;
    +-    if( nArg==2 ){
    +-      int i;
    +-      for(i=0; azArg[1][i]; i++) azArg[1][i] = ToLower(azArg[1][i]);
    +-      if( strcmp(azArg[1],"sqlite_master")==0 ){
    +-        char *new_argv[2], *new_colv[2];
    +-        new_argv[0] = "CREATE TABLE sqlite_master (\n"
    +-                      "  type text,\n"
    +-                      "  name text,\n"
    +-                      "  tbl_name text,\n"
    +-                      "  rootpage integer,\n"
    +-                      "  sql text\n"
    +-                      ")";
    +-        new_argv[1] = 0;
    +-        new_colv[0] = "sql";
    +-        new_colv[1] = 0;
    +-        callback(&data, 1, new_argv, new_colv);
    +-        rc = SQLITE_OK;
    +-      }else if( strcmp(azArg[1],"sqlite_temp_master")==0 ){
    ++    data.cMode = data.mode = MODE_Semi;
    ++    initText(&sSelect);
    ++    for(ii=1; ii<nArg; ii++){
    ++      if( optionMatch(azArg[ii],"indent") ){
    ++        data.cMode = data.mode = MODE_Pretty;
    ++      }else if( optionMatch(azArg[ii],"debug") ){
    ++        bDebug = 1;
    ++      }else if( zName==0 ){
    ++        zName = azArg[ii];
    ++      }else{
    ++        raw_printf(stderr, "Usage: .schema ?--indent? ?LIKE-PATTERN?\n");
    ++        rc = 1;
    ++        goto meta_command_exit;
    ++      }
    ++    }
    ++    if( zName!=0 ){
    ++      int isMaster = sqlite3_strlike(zName, "sqlite_master", 0)==0;
    ++      if( isMaster || sqlite3_strlike(zName,"sqlite_temp_master",0)==0 ){
    +         char *new_argv[2], *new_colv[2];
    +-        new_argv[0] = "CREATE TEMP TABLE sqlite_temp_master (\n"
    ++        new_argv[0] = sqlite3_mprintf(
    ++                      "CREATE TABLE %s (\n"
    +                       "  type text,\n"
    +                       "  name text,\n"
    +                       "  tbl_name text,\n"
    +                       "  rootpage integer,\n"
    +                       "  sql text\n"
    +-                      ")";
    ++                      ")", isMaster ? "sqlite_master" : "sqlite_temp_master");
    +         new_argv[1] = 0;
    +         new_colv[0] = "sql";
    +         new_colv[1] = 0;
    +         callback(&data, 1, new_argv, new_colv);
    +-        rc = SQLITE_OK;
    ++        sqlite3_free(new_argv[0]);
    ++      }
    ++    }
    ++    if( zDiv ){
    ++      sqlite3_stmt *pStmt = 0;
    ++      rc = sqlite3_prepare_v2(p->db, "SELECT name FROM pragma_database_list",
    ++                              -1, &pStmt, 0);
    ++      if( rc ){
    ++        utf8_printf(stderr, "Error: %s\n", sqlite3_errmsg(p->db));
    ++        sqlite3_finalize(pStmt);
    ++        rc = 1;
    ++        goto meta_command_exit;
    ++      }
    ++      appendText(&sSelect, "SELECT sql FROM", 0);
    ++      iSchema = 0;
    ++      while( sqlite3_step(pStmt)==SQLITE_ROW ){
    ++        const char *zDb = (const char*)sqlite3_column_text(pStmt, 0);
    ++        char zScNum[30];
    ++        sqlite3_snprintf(sizeof(zScNum), zScNum, "%d", ++iSchema);
    ++        appendText(&sSelect, zDiv, 0);
    ++        zDiv = " UNION ALL ";
    ++        appendText(&sSelect, "SELECT shell_add_schema(sql,", 0);
    ++        if( sqlite3_stricmp(zDb, "main")!=0 ){
    ++          appendText(&sSelect, zDb, '"');
    ++        }else{
    ++          appendText(&sSelect, "NULL", 0);
    ++        }
    ++        appendText(&sSelect, ",name) AS sql, type, tbl_name, name, rowid,", 0);
    ++        appendText(&sSelect, zScNum, 0);
    ++        appendText(&sSelect, " AS snum, ", 0);
    ++        appendText(&sSelect, zDb, '\'');
    ++        appendText(&sSelect, " AS sname FROM ", 0);
    ++        appendText(&sSelect, zDb, '"');
    ++        appendText(&sSelect, ".sqlite_master", 0);
    ++      }
    ++      sqlite3_finalize(pStmt);
    ++#ifdef SQLITE_INTROSPECTION_PRAGMAS
    ++      if( zName ){
    ++        appendText(&sSelect,
    ++           " UNION ALL SELECT shell_module_schema(name),"
    ++           " 'table', name, name, name, 9e+99, 'main' FROM pragma_module_list", 0);
    ++      }
    ++#endif
    ++      appendText(&sSelect, ") WHERE ", 0);
    ++      if( zName ){
    ++        char *zQarg = sqlite3_mprintf("%Q", zName);
    ++        if( strchr(zName, '.') ){
    ++          appendText(&sSelect, "lower(printf('%s.%s',sname,tbl_name))", 0);
    ++        }else{
    ++          appendText(&sSelect, "lower(tbl_name)", 0);
    ++        }
    ++        appendText(&sSelect, strchr(zName, '*') ? " GLOB " : " LIKE ", 0);
    ++        appendText(&sSelect, zQarg, 0);
    ++        appendText(&sSelect, " AND ", 0);
    ++        sqlite3_free(zQarg);
    ++      }
    ++      appendText(&sSelect, "type!='meta' AND sql IS NOT NULL"
    ++                           " ORDER BY snum, rowid", 0);
    ++      if( bDebug ){
    ++        utf8_printf(p->out, "SQL: %s;\n", sSelect.z);
    +       }else{
    +-        zShellStatic = azArg[1];
    +-        rc = sqlite3_exec(p->db,
    +-          "SELECT sql FROM "
    +-          "  (SELECT sql sql, type type, tbl_name tbl_name, name name, rowid x"
    +-          "     FROM sqlite_master UNION ALL"
    +-          "   SELECT sql, type, tbl_name, name, rowid FROM sqlite_temp_master) "
    +-          "WHERE lower(tbl_name) LIKE shellstatic()"
    +-          "  AND type!='meta' AND sql NOTNULL "
    +-          "ORDER BY rowid",
    +-          callback, &data, &zErrMsg);
    +-        zShellStatic = 0;
    ++        rc = sqlite3_exec(p->db, sSelect.z, callback, &data, &zErrMsg);
    +       }
    +-    }else if( nArg==1 ){
    +-      rc = sqlite3_exec(p->db,
    +-         "SELECT sql FROM "
    +-         "  (SELECT sql sql, type type, tbl_name tbl_name, name name, rowid x"
    +-         "     FROM sqlite_master UNION ALL"
    +-         "   SELECT sql, type, tbl_name, name, rowid FROM sqlite_temp_master) "
    +-         "WHERE type!='meta' AND sql NOTNULL AND name NOT LIKE 'sqlite_%' "
    +-         "ORDER BY rowid",
    +-         callback, &data, &zErrMsg
    +-      );
    +-    }else{
    +-      fprintf(stderr, "Usage: .schema ?LIKE-PATTERN?\n");
    +-      rc = 1;
    +-      goto meta_command_exit;
    ++      freeText(&sSelect);
    +     }
    +     if( zErrMsg ){
    +-      fprintf(stderr,"Error: %s\n", zErrMsg);
    ++      utf8_printf(stderr,"Error: %s\n", zErrMsg);
    +       sqlite3_free(zErrMsg);
    +       rc = 1;
    +     }else if( rc != SQLITE_OK ){
    +-      fprintf(stderr,"Error: querying schema information\n");
    ++      raw_printf(stderr,"Error: querying schema information\n");
    +       rc = 1;
    +     }else{
    +       rc = 0;
    +     }
    +   }else
    + 
    +-
    + #if defined(SQLITE_DEBUG) && defined(SQLITE_ENABLE_SELECTTRACE)
    +   if( c=='s' && n==11 && strncmp(azArg[0], "selecttrace", n)==0 ){
    +-    extern int sqlite3SelectTrace;
    +-    sqlite3SelectTrace = integerValue(azArg[1]);
    ++    sqlite3SelectTrace = (int)integerValue(azArg[1]);
    +   }else
    + #endif
    + 
    ++#if defined(SQLITE_ENABLE_SESSION)
    ++  if( c=='s' && strncmp(azArg[0],"session",n)==0 && n>=3 ){
    ++    OpenSession *pSession = &p->aSession[0];
    ++    char **azCmd = &azArg[1];
    ++    int iSes = 0;
    ++    int nCmd = nArg - 1;
    ++    int i;
    ++    if( nArg<=1 ) goto session_syntax_error;
    ++    open_db(p, 0);
    ++    if( nArg>=3 ){
    ++      for(iSes=0; iSes<p->nSession; iSes++){
    ++        if( strcmp(p->aSession[iSes].zName, azArg[1])==0 ) break;
    ++      }
    ++      if( iSes<p->nSession ){
    ++        pSession = &p->aSession[iSes];
    ++        azCmd++;
    ++        nCmd--;
    ++      }else{
    ++        pSession = &p->aSession[0];
    ++        iSes = 0;
    ++      }
    ++    }
    ++
    ++    /* .session attach TABLE
    ++    ** Invoke the sqlite3session_attach() interface to attach a particular
    ++    ** table so that it is never filtered.
    ++    */
    ++    if( strcmp(azCmd[0],"attach")==0 ){
    ++      if( nCmd!=2 ) goto session_syntax_error;
    ++      if( pSession->p==0 ){
    ++        session_not_open:
    ++        raw_printf(stderr, "ERROR: No sessions are open\n");
    ++      }else{
    ++        rc = sqlite3session_attach(pSession->p, azCmd[1]);
    ++        if( rc ){
    ++          raw_printf(stderr, "ERROR: sqlite3session_attach() returns %d\n", rc);
    ++          rc = 0;
    ++        }
    ++      }
    ++    }else
    ++
    ++    /* .session changeset FILE
    ++    ** .session patchset FILE
    ++    ** Write a changeset or patchset into a file.  The file is overwritten.
    ++    */
    ++    if( strcmp(azCmd[0],"changeset")==0 || strcmp(azCmd[0],"patchset")==0 ){
    ++      FILE *out = 0;
    ++      if( nCmd!=2 ) goto session_syntax_error;
    ++      if( pSession->p==0 ) goto session_not_open;
    ++      out = fopen(azCmd[1], "wb");
    ++      if( out==0 ){
    ++        utf8_printf(stderr, "ERROR: cannot open \"%s\" for writing\n", azCmd[1]);
    ++      }else{
    ++        int szChng;
    ++        void *pChng;
    ++        if( azCmd[0][0]=='c' ){
    ++          rc = sqlite3session_changeset(pSession->p, &szChng, &pChng);
    ++        }else{
    ++          rc = sqlite3session_patchset(pSession->p, &szChng, &pChng);
    ++        }
    ++        if( rc ){
    ++          printf("Error: error code %d\n", rc);
    ++          rc = 0;
    ++        }
    ++        if( pChng
    ++          && fwrite(pChng, szChng, 1, out)!=1 ){
    ++          raw_printf(stderr, "ERROR: Failed to write entire %d-byte output\n",
    ++                  szChng);
    ++        }
    ++        sqlite3_free(pChng);
    ++        fclose(out);
    ++      }
    ++    }else
    ++
    ++    /* .session close
    ++    ** Close the identified session
    ++    */
    ++    if( strcmp(azCmd[0], "close")==0 ){
    ++      if( nCmd!=1 ) goto session_syntax_error;
    ++      if( p->nSession ){
    ++        session_close(pSession);
    ++        p->aSession[iSes] = p->aSession[--p->nSession];
    ++      }
    ++    }else
    ++
    ++    /* .session enable ?BOOLEAN?
    ++    ** Query or set the enable flag
    ++    */
    ++    if( strcmp(azCmd[0], "enable")==0 ){
    ++      int ii;
    ++      if( nCmd>2 ) goto session_syntax_error;
    ++      ii = nCmd==1 ? -1 : booleanValue(azCmd[1]);
    ++      if( p->nSession ){
    ++        ii = sqlite3session_enable(pSession->p, ii);
    ++        utf8_printf(p->out, "session %s enable flag = %d\n",
    ++                    pSession->zName, ii);
    ++      }
    ++    }else
    ++
    ++    /* .session filter GLOB ....
    ++    ** Set a list of GLOB patterns of table names to be excluded.
    ++    */
    ++    if( strcmp(azCmd[0], "filter")==0 ){
    ++      int ii, nByte;
    ++      if( nCmd<2 ) goto session_syntax_error;
    ++      if( p->nSession ){
    ++        for(ii=0; ii<pSession->nFilter; ii++){
    ++          sqlite3_free(pSession->azFilter[ii]);
    ++        }
    ++        sqlite3_free(pSession->azFilter);
    ++        nByte = sizeof(pSession->azFilter[0])*(nCmd-1);
    ++        pSession->azFilter = sqlite3_malloc( nByte );
    ++        if( pSession->azFilter==0 ){
    ++          raw_printf(stderr, "Error: out or memory\n");
    ++          exit(1);
    ++        }
    ++        for(ii=1; ii<nCmd; ii++){
    ++          pSession->azFilter[ii-1] = sqlite3_mprintf("%s", azCmd[ii]);
    ++        }
    ++        pSession->nFilter = ii-1;
    ++      }
    ++    }else
    ++
    ++    /* .session indirect ?BOOLEAN?
    ++    ** Query or set the indirect flag
    ++    */
    ++    if( strcmp(azCmd[0], "indirect")==0 ){
    ++      int ii;
    ++      if( nCmd>2 ) goto session_syntax_error;
    ++      ii = nCmd==1 ? -1 : booleanValue(azCmd[1]);
    ++      if( p->nSession ){
    ++        ii = sqlite3session_indirect(pSession->p, ii);
    ++        utf8_printf(p->out, "session %s indirect flag = %d\n",
    ++                    pSession->zName, ii);
    ++      }
    ++    }else
    ++
    ++    /* .session isempty
    ++    ** Determine if the session is empty
    ++    */
    ++    if( strcmp(azCmd[0], "isempty")==0 ){
    ++      int ii;
    ++      if( nCmd!=1 ) goto session_syntax_error;
    ++      if( p->nSession ){
    ++        ii = sqlite3session_isempty(pSession->p);
    ++        utf8_printf(p->out, "session %s isempty flag = %d\n",
    ++                    pSession->zName, ii);
    ++      }
    ++    }else
    ++
    ++    /* .session list
    ++    ** List all currently open sessions
    ++    */
    ++    if( strcmp(azCmd[0],"list")==0 ){
    ++      for(i=0; i<p->nSession; i++){
    ++        utf8_printf(p->out, "%d %s\n", i, p->aSession[i].zName);
    ++      }
    ++    }else
    ++
    ++    /* .session open DB NAME
    ++    ** Open a new session called NAME on the attached database DB.
    ++    ** DB is normally "main".
    ++    */
    ++    if( strcmp(azCmd[0],"open")==0 ){
    ++      char *zName;
    ++      if( nCmd!=3 ) goto session_syntax_error;
    ++      zName = azCmd[2];
    ++      if( zName[0]==0 ) goto session_syntax_error;
    ++      for(i=0; i<p->nSession; i++){
    ++        if( strcmp(p->aSession[i].zName,zName)==0 ){
    ++          utf8_printf(stderr, "Session \"%s\" already exists\n", zName);
    ++          goto meta_command_exit;
    ++        }
    ++      }
    ++      if( p->nSession>=ArraySize(p->aSession) ){
    ++        raw_printf(stderr, "Maximum of %d sessions\n", ArraySize(p->aSession));
    ++        goto meta_command_exit;
    ++      }
    ++      pSession = &p->aSession[p->nSession];
    ++      rc = sqlite3session_create(p->db, azCmd[1], &pSession->p);
    ++      if( rc ){
    ++        raw_printf(stderr, "Cannot open session: error code=%d\n", rc);
    ++        rc = 0;
    ++        goto meta_command_exit;
    ++      }
    ++      pSession->nFilter = 0;
    ++      sqlite3session_table_filter(pSession->p, session_filter, pSession);
    ++      p->nSession++;
    ++      pSession->zName = sqlite3_mprintf("%s", zName);
    ++    }else
    ++    /* If no command name matches, show a syntax error */
    ++    session_syntax_error:
    ++    session_help(p);
    ++  }else
    ++#endif
    + 
    + #ifdef SQLITE_DEBUG
    +   /* Undocumented commands for internal testing.  Subject to change
    +@@ -3631,7 +13738,7 @@ static int do_meta_command(char *zLine, ShellState *p){
    +       int i, v;
    +       for(i=1; i<nArg; i++){
    +         v = booleanValue(azArg[i]);
    +-        fprintf(p->out, "%s: %d 0x%x\n", azArg[i], v, v);
    ++        utf8_printf(p->out, "%s: %d 0x%x\n", azArg[i], v, v);
    +       }
    +     }
    +     if( strncmp(azArg[0]+9, "integer", n-9)==0 ){
    +@@ -3640,15 +13747,121 @@ static int do_meta_command(char *zLine, ShellState *p){
    +         char zBuf[200];
    +         v = integerValue(azArg[i]);
    +         sqlite3_snprintf(sizeof(zBuf),zBuf,"%s: %lld 0x%llx\n", azArg[i],v,v);
    +-        fprintf(p->out, "%s", zBuf);
    ++        utf8_printf(p->out, "%s", zBuf);
    +       }
    +     }
    +   }else
    + #endif
    + 
    ++  if( c=='s' && n>=4 && strncmp(azArg[0],"selftest",n)==0 ){
    ++    int bIsInit = 0;         /* True to initialize the SELFTEST table */
    ++    int bVerbose = 0;        /* Verbose output */
    ++    int bSelftestExists;     /* True if SELFTEST already exists */
    ++    int i, k;                /* Loop counters */
    ++    int nTest = 0;           /* Number of tests runs */
    ++    int nErr = 0;            /* Number of errors seen */
    ++    ShellText str;           /* Answer for a query */
    ++    sqlite3_stmt *pStmt = 0; /* Query against the SELFTEST table */
    ++
    ++    open_db(p,0);
    ++    for(i=1; i<nArg; i++){
    ++      const char *z = azArg[i];
    ++      if( z[0]=='-' && z[1]=='-' ) z++;
    ++      if( strcmp(z,"-init")==0 ){
    ++        bIsInit = 1;
    ++      }else
    ++      if( strcmp(z,"-v")==0 ){
    ++        bVerbose++;
    ++      }else
    ++      {
    ++        utf8_printf(stderr, "Unknown option \"%s\" on \"%s\"\n",
    ++                    azArg[i], azArg[0]);
    ++        raw_printf(stderr, "Should be one of: --init -v\n");
    ++        rc = 1;
    ++        goto meta_command_exit;
    ++      }
    ++    }
    ++    if( sqlite3_table_column_metadata(p->db,"main","selftest",0,0,0,0,0,0)
    ++           != SQLITE_OK ){
    ++      bSelftestExists = 0;
    ++    }else{
    ++      bSelftestExists = 1;
    ++    }
    ++    if( bIsInit ){
    ++      createSelftestTable(p);
    ++      bSelftestExists = 1;
    ++    }
    ++    initText(&str);
    ++    appendText(&str, "x", 0);
    ++    for(k=bSelftestExists; k>=0; k--){
    ++      if( k==1 ){
    ++        rc = sqlite3_prepare_v2(p->db,
    ++            "SELECT tno,op,cmd,ans FROM selftest ORDER BY tno",
    ++            -1, &pStmt, 0);
    ++      }else{
    ++        rc = sqlite3_prepare_v2(p->db,
    ++          "VALUES(0,'memo','Missing SELFTEST table - default checks only',''),"
    ++          "      (1,'run','PRAGMA integrity_check','ok')",
    ++          -1, &pStmt, 0);
    ++      }
    ++      if( rc ){
    ++        raw_printf(stderr, "Error querying the selftest table\n");
    ++        rc = 1;
    ++        sqlite3_finalize(pStmt);
    ++        goto meta_command_exit;
    ++      }
    ++      for(i=1; sqlite3_step(pStmt)==SQLITE_ROW; i++){
    ++        int tno = sqlite3_column_int(pStmt, 0);
    ++        const char *zOp = (const char*)sqlite3_column_text(pStmt, 1);
    ++        const char *zSql = (const char*)sqlite3_column_text(pStmt, 2);
    ++        const char *zAns = (const char*)sqlite3_column_text(pStmt, 3);
    ++
    ++        k = 0;
    ++        if( bVerbose>0 ){
    ++          char *zQuote = sqlite3_mprintf("%q", zSql);
    ++          printf("%d: %s %s\n", tno, zOp, zSql);
    ++          sqlite3_free(zQuote);
    ++        }
    ++        if( strcmp(zOp,"memo")==0 ){
    ++          utf8_printf(p->out, "%s\n", zSql);
    ++        }else
    ++        if( strcmp(zOp,"run")==0 ){
    ++          char *zErrMsg = 0;
    ++          str.n = 0;
    ++          str.z[0] = 0;
    ++          rc = sqlite3_exec(p->db, zSql, captureOutputCallback, &str, &zErrMsg);
    ++          nTest++;
    ++          if( bVerbose ){
    ++            utf8_printf(p->out, "Result: %s\n", str.z);
    ++          }
    ++          if( rc || zErrMsg ){
    ++            nErr++;
    ++            rc = 1;
    ++            utf8_printf(p->out, "%d: error-code-%d: %s\n", tno, rc, zErrMsg);
    ++            sqlite3_free(zErrMsg);
    ++          }else if( strcmp(zAns,str.z)!=0 ){
    ++            nErr++;
    ++            rc = 1;
    ++            utf8_printf(p->out, "%d: Expected: [%s]\n", tno, zAns);
    ++            utf8_printf(p->out, "%d:      Got: [%s]\n", tno, str.z);
    ++          }
    ++        }else
    ++        {
    ++          utf8_printf(stderr,
    ++            "Unknown operation \"%s\" on selftest line %d\n", zOp, tno);
    ++          rc = 1;
    ++          break;
    ++        }
    ++      } /* End loop over rows of content from SELFTEST */
    ++      sqlite3_finalize(pStmt);
    ++    } /* End loop over k */
    ++    freeText(&str);
    ++    utf8_printf(p->out, "%d errors out of %d tests\n", nErr, nTest);
    ++  }else
    ++
    +   if( c=='s' && strncmp(azArg[0], "separator", n)==0 ){
    +     if( nArg<2 || nArg>3 ){
    +-      fprintf(stderr, "Usage: .separator COL ?ROW?\n");
    ++      raw_printf(stderr, "Usage: .separator COL ?ROW?\n");
    +       rc = 1;
    +     }
    +     if( nArg>=2 ){
    +@@ -3661,13 +13874,129 @@ static int do_meta_command(char *zLine, ShellState *p){
    +     }
    +   }else
    + 
    ++  if( c=='s' && n>=4 && strncmp(azArg[0],"sha3sum",n)==0 ){
    ++    const char *zLike = 0;   /* Which table to checksum. 0 means everything */
    ++    int i;                   /* Loop counter */
    ++    int bSchema = 0;         /* Also hash the schema */
    ++    int bSeparate = 0;       /* Hash each table separately */
    ++    int iSize = 224;         /* Hash algorithm to use */
    ++    int bDebug = 0;          /* Only show the query that would have run */
    ++    sqlite3_stmt *pStmt;     /* For querying tables names */
    ++    char *zSql;              /* SQL to be run */
    ++    char *zSep;              /* Separator */
    ++    ShellText sSql;          /* Complete SQL for the query to run the hash */
    ++    ShellText sQuery;        /* Set of queries used to read all content */
    ++    open_db(p, 0);
    ++    for(i=1; i<nArg; i++){
    ++      const char *z = azArg[i];
    ++      if( z[0]=='-' ){
    ++        z++;
    ++        if( z[0]=='-' ) z++;
    ++        if( strcmp(z,"schema")==0 ){
    ++          bSchema = 1;
    ++        }else
    ++        if( strcmp(z,"sha3-224")==0 || strcmp(z,"sha3-256")==0
    ++         || strcmp(z,"sha3-384")==0 || strcmp(z,"sha3-512")==0
    ++        ){
    ++          iSize = atoi(&z[5]);
    ++        }else
    ++        if( strcmp(z,"debug")==0 ){
    ++          bDebug = 1;
    ++        }else
    ++        {
    ++          utf8_printf(stderr, "Unknown option \"%s\" on \"%s\"\n",
    ++                      azArg[i], azArg[0]);
    ++          raw_printf(stderr, "Should be one of: --schema"
    ++                             " --sha3-224 --sha3-255 --sha3-384 --sha3-512\n");
    ++          rc = 1;
    ++          goto meta_command_exit;
    ++        }
    ++      }else if( zLike ){
    ++        raw_printf(stderr, "Usage: .sha3sum ?OPTIONS? ?LIKE-PATTERN?\n");
    ++        rc = 1;
    ++        goto meta_command_exit;
    ++      }else{
    ++        zLike = z;
    ++        bSeparate = 1;
    ++        if( sqlite3_strlike("sqlite_%", zLike, 0)==0 ) bSchema = 1;
    ++      }
    ++    }
    ++    if( bSchema ){
    ++      zSql = "SELECT lower(name) FROM sqlite_master"
    ++             " WHERE type='table' AND coalesce(rootpage,0)>1"
    ++             " UNION ALL SELECT 'sqlite_master'"
    ++             " ORDER BY 1 collate nocase";
    ++    }else{
    ++      zSql = "SELECT lower(name) FROM sqlite_master"
    ++             " WHERE type='table' AND coalesce(rootpage,0)>1"
    ++             " AND name NOT LIKE 'sqlite_%'"
    ++             " ORDER BY 1 collate nocase";
    ++    }
    ++    sqlite3_prepare_v2(p->db, zSql, -1, &pStmt, 0);
    ++    initText(&sQuery);
    ++    initText(&sSql);
    ++    appendText(&sSql, "WITH [sha3sum$query](a,b) AS(",0);
    ++    zSep = "VALUES(";
    ++    while( SQLITE_ROW==sqlite3_step(pStmt) ){
    ++      const char *zTab = (const char*)sqlite3_column_text(pStmt,0);
    ++      if( zLike && sqlite3_strlike(zLike, zTab, 0)!=0 ) continue;
    ++      if( strncmp(zTab, "sqlite_",7)!=0 ){
    ++        appendText(&sQuery,"SELECT * FROM ", 0);
    ++        appendText(&sQuery,zTab,'"');
    ++        appendText(&sQuery," NOT INDEXED;", 0);
    ++      }else if( strcmp(zTab, "sqlite_master")==0 ){
    ++        appendText(&sQuery,"SELECT type,name,tbl_name,sql FROM sqlite_master"
    ++                           " ORDER BY name;", 0);
    ++      }else if( strcmp(zTab, "sqlite_sequence")==0 ){
    ++        appendText(&sQuery,"SELECT name,seq FROM sqlite_sequence"
    ++                           " ORDER BY name;", 0);
    ++      }else if( strcmp(zTab, "sqlite_stat1")==0 ){
    ++        appendText(&sQuery,"SELECT tbl,idx,stat FROM sqlite_stat1"
    ++                           " ORDER BY tbl,idx;", 0);
    ++      }else if( strcmp(zTab, "sqlite_stat3")==0
    ++             || strcmp(zTab, "sqlite_stat4")==0 ){
    ++        appendText(&sQuery, "SELECT * FROM ", 0);
    ++        appendText(&sQuery, zTab, 0);
    ++        appendText(&sQuery, " ORDER BY tbl, idx, rowid;\n", 0);
    ++      }
    ++      appendText(&sSql, zSep, 0);
    ++      appendText(&sSql, sQuery.z, '\'');
    ++      sQuery.n = 0;
    ++      appendText(&sSql, ",", 0);
    ++      appendText(&sSql, zTab, '\'');
    ++      zSep = "),(";
    ++    }
    ++    sqlite3_finalize(pStmt);
    ++    if( bSeparate ){
    ++      zSql = sqlite3_mprintf(
    ++          "%s))"
    ++          " SELECT lower(hex(sha3_query(a,%d))) AS hash, b AS label"
    ++          "   FROM [sha3sum$query]",
    ++          sSql.z, iSize);
    ++    }else{
    ++      zSql = sqlite3_mprintf(
    ++          "%s))"
    ++          " SELECT lower(hex(sha3_query(group_concat(a,''),%d))) AS hash"
    ++          "   FROM [sha3sum$query]",
    ++          sSql.z, iSize);
    ++    }
    ++    freeText(&sQuery);
    ++    freeText(&sSql);
    ++    if( bDebug ){
    ++      utf8_printf(p->out, "%s\n", zSql);
    ++    }else{
    ++      shell_exec(p->db, zSql, shell_callback, p, 0);
    ++    }
    ++    sqlite3_free(zSql);
    ++  }else
    ++
    +   if( c=='s'
    +    && (strncmp(azArg[0], "shell", n)==0 || strncmp(azArg[0],"system",n)==0)
    +   ){
    +     char *zCmd;
    +     int i, x;
    +     if( nArg<2 ){
    +-      fprintf(stderr, "Usage: .system COMMAND\n");
    ++      raw_printf(stderr, "Usage: .system COMMAND\n");
    +       rc = 1;
    +       goto meta_command_exit;
    +     }
    +@@ -3678,93 +14007,104 @@ static int do_meta_command(char *zLine, ShellState *p){
    +     }
    +     x = system(zCmd);
    +     sqlite3_free(zCmd);
    +-    if( x ) fprintf(stderr, "System command returns %d\n", x);
    ++    if( x ) raw_printf(stderr, "System command returns %d\n", x);
    +   }else
    + 
    +   if( c=='s' && strncmp(azArg[0], "show", n)==0 ){
    ++    static const char *azBool[] = { "off", "on", "trigger", "full"};
    +     int i;
    +     if( nArg!=1 ){
    +-      fprintf(stderr, "Usage: .show\n");
    ++      raw_printf(stderr, "Usage: .show\n");
    +       rc = 1;
    +       goto meta_command_exit;
    +     }
    +-    fprintf(p->out,"%12.12s: %s\n","echo", p->echoOn ? "on" : "off");
    +-    fprintf(p->out,"%12.12s: %s\n","eqp", p->autoEQP ? "on" : "off");
    +-    fprintf(p->out,"%9.9s: %s\n","explain", p->normalMode.valid ? "on" :"off");
    +-    fprintf(p->out,"%12.12s: %s\n","headers", p->showHeader ? "on" : "off");
    +-    fprintf(p->out,"%12.12s: %s\n","mode", modeDescr[p->mode]);
    +-    fprintf(p->out,"%12.12s: ", "nullvalue");
    ++    utf8_printf(p->out, "%12.12s: %s\n","echo",
    ++                                  azBool[ShellHasFlag(p, SHFLG_Echo)]);
    ++    utf8_printf(p->out, "%12.12s: %s\n","eqp", azBool[p->autoEQP&3]);
    ++    utf8_printf(p->out, "%12.12s: %s\n","explain",
    ++         p->mode==MODE_Explain ? "on" : p->autoExplain ? "auto" : "off");
    ++    utf8_printf(p->out,"%12.12s: %s\n","headers", azBool[p->showHeader!=0]);
    ++    utf8_printf(p->out, "%12.12s: %s\n","mode", modeDescr[p->mode]);
    ++    utf8_printf(p->out, "%12.12s: ", "nullvalue");
    +       output_c_string(p->out, p->nullValue);
    +-      fprintf(p->out, "\n");
    +-    fprintf(p->out,"%12.12s: %s\n","output",
    ++      raw_printf(p->out, "\n");
    ++    utf8_printf(p->out,"%12.12s: %s\n","output",
    +             strlen30(p->outfile) ? p->outfile : "stdout");
    +-    fprintf(p->out,"%12.12s: ", "colseparator");
    ++    utf8_printf(p->out,"%12.12s: ", "colseparator");
    +       output_c_string(p->out, p->colSeparator);
    +-      fprintf(p->out, "\n");
    +-    fprintf(p->out,"%12.12s: ", "rowseparator");
    ++      raw_printf(p->out, "\n");
    ++    utf8_printf(p->out,"%12.12s: ", "rowseparator");
    +       output_c_string(p->out, p->rowSeparator);
    +-      fprintf(p->out, "\n");
    +-    fprintf(p->out,"%12.12s: %s\n","stats", p->statsOn ? "on" : "off");
    +-    fprintf(p->out,"%12.12s: ","width");
    ++      raw_printf(p->out, "\n");
    ++    utf8_printf(p->out, "%12.12s: %s\n","stats", azBool[p->statsOn!=0]);
    ++    utf8_printf(p->out, "%12.12s: ", "width");
    +     for (i=0;i<(int)ArraySize(p->colWidth) && p->colWidth[i] != 0;i++) {
    +-      fprintf(p->out,"%d ",p->colWidth[i]);
    ++      raw_printf(p->out, "%d ", p->colWidth[i]);
    +     }
    +-    fprintf(p->out,"\n");
    ++    raw_printf(p->out, "\n");
    ++    utf8_printf(p->out, "%12.12s: %s\n", "filename",
    ++                p->zDbFilename ? p->zDbFilename : "");
    +   }else
    + 
    +   if( c=='s' && strncmp(azArg[0], "stats", n)==0 ){
    +     if( nArg==2 ){
    +       p->statsOn = booleanValue(azArg[1]);
    ++    }else if( nArg==1 ){
    ++      display_stats(p->db, p, 0);
    +     }else{
    +-      fprintf(stderr, "Usage: .stats on|off\n");
    ++      raw_printf(stderr, "Usage: .stats ?on|off?\n");
    +       rc = 1;
    +     }
    +   }else
    + 
    +-  if( c=='t' && n>1 && strncmp(azArg[0], "tables", n)==0 ){
    ++  if( (c=='t' && n>1 && strncmp(azArg[0], "tables", n)==0)
    ++   || (c=='i' && (strncmp(azArg[0], "indices", n)==0
    ++                 || strncmp(azArg[0], "indexes", n)==0) )
    ++  ){
    +     sqlite3_stmt *pStmt;
    +     char **azResult;
    +     int nRow, nAlloc;
    +-    char *zSql = 0;
    +     int ii;
    ++    ShellText s;
    ++    initText(&s);
    +     open_db(p, 0);
    +     rc = sqlite3_prepare_v2(p->db, "PRAGMA database_list", -1, &pStmt, 0);
    +     if( rc ) return shellDatabaseError(p->db);
    + 
    +-    /* Create an SQL statement to query for the list of tables in the
    +-    ** main and all attached databases where the table name matches the
    +-    ** LIKE pattern bound to variable "?1". */
    +-    zSql = sqlite3_mprintf(
    +-        "SELECT name FROM sqlite_master"
    +-        " WHERE type IN ('table','view')"
    +-        "   AND name NOT LIKE 'sqlite_%%'"
    +-        "   AND name LIKE ?1");
    +-    while( zSql && sqlite3_step(pStmt)==SQLITE_ROW ){
    ++    if( nArg>2 && c=='i' ){
    ++      /* It is an historical accident that the .indexes command shows an error
    ++      ** when called with the wrong number of arguments whereas the .tables
    ++      ** command does not. */
    ++      raw_printf(stderr, "Usage: .indexes ?LIKE-PATTERN?\n");
    ++      rc = 1;
    ++      goto meta_command_exit;
    ++    }
    ++    for(ii=0; sqlite3_step(pStmt)==SQLITE_ROW; ii++){
    +       const char *zDbName = (const char*)sqlite3_column_text(pStmt, 1);
    +-      if( zDbName==0 || strcmp(zDbName,"main")==0 ) continue;
    +-      if( strcmp(zDbName,"temp")==0 ){
    +-        zSql = sqlite3_mprintf(
    +-                 "%z UNION ALL "
    +-                 "SELECT 'temp.' || name FROM sqlite_temp_master"
    +-                 " WHERE type IN ('table','view')"
    +-                 "   AND name NOT LIKE 'sqlite_%%'"
    +-                 "   AND name LIKE ?1", zSql);
    ++      if( zDbName==0 ) continue;
    ++      if( s.z && s.z[0] ) appendText(&s, " UNION ALL ", 0);
    ++      if( sqlite3_stricmp(zDbName, "main")==0 ){
    ++        appendText(&s, "SELECT name FROM ", 0);
    ++      }else{
    ++        appendText(&s, "SELECT ", 0);
    ++        appendText(&s, zDbName, '\'');
    ++        appendText(&s, "||'.'||name FROM ", 0);
    ++      }
    ++      appendText(&s, zDbName, '"');
    ++      appendText(&s, ".sqlite_master ", 0);
    ++      if( c=='t' ){
    ++        appendText(&s," WHERE type IN ('table','view')"
    ++                      "   AND name NOT LIKE 'sqlite_%'"
    ++                      "   AND name LIKE ?1", 0);
    +       }else{
    +-        zSql = sqlite3_mprintf(
    +-                 "%z UNION ALL "
    +-                 "SELECT '%q.' || name FROM \"%w\".sqlite_master"
    +-                 " WHERE type IN ('table','view')"
    +-                 "   AND name NOT LIKE 'sqlite_%%'"
    +-                 "   AND name LIKE ?1", zSql, zDbName, zDbName);
    ++        appendText(&s," WHERE type='index'"
    ++                      "   AND tbl_name LIKE ?1", 0);
    +       }
    +     }
    +     rc = sqlite3_finalize(pStmt);
    +-    if( zSql && rc==SQLITE_OK ){
    +-      zSql = sqlite3_mprintf("%z ORDER BY 1", zSql);
    +-      if( zSql ) rc = sqlite3_prepare_v2(p->db, zSql, -1, &pStmt, 0);
    +-    }
    +-    sqlite3_free(zSql);
    +-    if( !zSql ) return shellNomemError();
    ++    appendText(&s, " ORDER BY 1", 0);
    ++    rc = sqlite3_prepare_v2(p->db, s.z, -1, &pStmt, 0);
    ++    freeText(&s);
    +     if( rc ) return shellDatabaseError(p->db);
    + 
    +     /* Run the SQL statement prepared by the above block. Store the results
    +@@ -3814,9 +14154,10 @@ static int do_meta_command(char *zLine, ShellState *p){
    +       for(i=0; i<nPrintRow; i++){
    +         for(j=i; j<nRow; j+=nPrintRow){
    +           char *zSp = j<nPrintRow ? "" : "  ";
    +-          fprintf(p->out, "%s%-*s", zSp, maxlen, azResult[j] ? azResult[j]:"");
    ++          utf8_printf(p->out, "%s%-*s", zSp, maxlen,
    ++                      azResult[j] ? azResult[j]:"");
    +         }
    +-        fprintf(p->out, "\n");
    ++        raw_printf(p->out, "\n");
    +       }
    +     }
    + 
    +@@ -3824,63 +14165,105 @@ static int do_meta_command(char *zLine, ShellState *p){
    +     sqlite3_free(azResult);
    +   }else
    + 
    +-  if( c=='t' && n>=8 && strncmp(azArg[0], "testctrl", n)==0 && nArg>=2 ){
    ++  /* Begin redirecting output to the file "testcase-out.txt" */
    ++  if( c=='t' && strcmp(azArg[0],"testcase")==0 ){
    ++    output_reset(p);
    ++    p->out = output_file_open("testcase-out.txt", 0);
    ++    if( p->out==0 ){
    ++      raw_printf(stderr, "Error: cannot open 'testcase-out.txt'\n");
    ++    }
    ++    if( nArg>=2 ){
    ++      sqlite3_snprintf(sizeof(p->zTestcase), p->zTestcase, "%s", azArg[1]);
    ++    }else{
    ++      sqlite3_snprintf(sizeof(p->zTestcase), p->zTestcase, "?");
    ++    }
    ++  }else
    ++
    ++#ifndef SQLITE_UNTESTABLE
    ++  if( c=='t' && n>=8 && strncmp(azArg[0], "testctrl", n)==0 ){
    +     static const struct {
    +        const char *zCtrlName;   /* Name of a test-control option */
    +        int ctrlCode;            /* Integer code for that option */
    ++       const char *zUsage;      /* Usage notes */
    +     } aCtrl[] = {
    +-      { "prng_save",             SQLITE_TESTCTRL_PRNG_SAVE              },
    +-      { "prng_restore",          SQLITE_TESTCTRL_PRNG_RESTORE           },
    +-      { "prng_reset",            SQLITE_TESTCTRL_PRNG_RESET             },
    +-      { "bitvec_test",           SQLITE_TESTCTRL_BITVEC_TEST            },
    +-      { "fault_install",         SQLITE_TESTCTRL_FAULT_INSTALL          },
    +-      { "benign_malloc_hooks",   SQLITE_TESTCTRL_BENIGN_MALLOC_HOOKS    },
    +-      { "pending_byte",          SQLITE_TESTCTRL_PENDING_BYTE           },
    +-      { "assert",                SQLITE_TESTCTRL_ASSERT                 },
    +-      { "always",                SQLITE_TESTCTRL_ALWAYS                 },
    +-      { "reserve",               SQLITE_TESTCTRL_RESERVE                },
    +-      { "optimizations",         SQLITE_TESTCTRL_OPTIMIZATIONS          },
    +-      { "iskeyword",             SQLITE_TESTCTRL_ISKEYWORD              },
    +-      { "scratchmalloc",         SQLITE_TESTCTRL_SCRATCHMALLOC          },
    +-      { "byteorder",             SQLITE_TESTCTRL_BYTEORDER              },
    +-      { "never_corrupt",         SQLITE_TESTCTRL_NEVER_CORRUPT          },
    +-      { "imposter",              SQLITE_TESTCTRL_IMPOSTER               },
    ++      { "always",             SQLITE_TESTCTRL_ALWAYS,        "BOOLEAN"            },
    ++      { "assert",             SQLITE_TESTCTRL_ASSERT,        "BOOLEAN"            },
    ++    /*{ "benign_malloc_hooks",SQLITE_TESTCTRL_BENIGN_MALLOC_HOOKS, ""          },*/
    ++    /*{ "bitvec_test",        SQLITE_TESTCTRL_BITVEC_TEST,   ""                },*/
    ++      { "byteorder",          SQLITE_TESTCTRL_BYTEORDER,     ""                   },
    ++    /*{ "fault_install",      SQLITE_TESTCTRL_FAULT_INSTALL, ""                }, */
    ++      { "imposter",           SQLITE_TESTCTRL_IMPOSTER,   "SCHEMA ON/OFF ROOTPAGE"},
    ++#ifdef SQLITE_N_KEYWORD
    ++      { "iskeyword",          SQLITE_TESTCTRL_ISKEYWORD,     "IDENTIFIER"         },
    ++#endif
    ++      { "localtime_fault",    SQLITE_TESTCTRL_LOCALTIME_FAULT,"BOOLEAN"           },
    ++      { "never_corrupt",      SQLITE_TESTCTRL_NEVER_CORRUPT, "BOOLEAN"            },
    ++      { "optimizations",      SQLITE_TESTCTRL_OPTIMIZATIONS, "DISABLE-MASK"       },
    ++#ifdef YYCOVERAGE
    ++      { "parser_coverage",    SQLITE_TESTCTRL_PARSER_COVERAGE, ""                 },
    ++#endif
    ++      { "pending_byte",       SQLITE_TESTCTRL_PENDING_BYTE,  "OFFSET  "           },
    ++      { "prng_reset",         SQLITE_TESTCTRL_PRNG_RESET,    ""                   },
    ++      { "prng_restore",       SQLITE_TESTCTRL_PRNG_RESTORE,  ""                   },
    ++      { "prng_save",          SQLITE_TESTCTRL_PRNG_SAVE,     ""                   },
    ++      { "reserve",            SQLITE_TESTCTRL_RESERVE,       "BYTES-OF-RESERVE"   },
    +     };
    +     int testctrl = -1;
    +-    int rc2 = 0;
    ++    int iCtrl = -1;
    ++    int rc2 = 0;    /* 0: usage.  1: %d  2: %x  3: no-output */
    ++    int isOk = 0;
    +     int i, n2;
    ++    const char *zCmd = 0;
    ++
    +     open_db(p, 0);
    ++    zCmd = nArg>=2 ? azArg[1] : "help";
    ++
    ++    /* The argument can optionally begin with "-" or "--" */
    ++    if( zCmd[0]=='-' && zCmd[1] ){
    ++      zCmd++;
    ++      if( zCmd[0]=='-' && zCmd[1] ) zCmd++;
    ++    }
    ++
    ++    /* --help lists all test-controls */
    ++    if( strcmp(zCmd,"help")==0 ){
    ++      utf8_printf(p->out, "Available test-controls:\n");
    ++      for(i=0; i<ArraySize(aCtrl); i++){
    ++        utf8_printf(p->out, "  .testctrl %s %s\n",
    ++                    aCtrl[i].zCtrlName, aCtrl[i].zUsage);
    ++      }
    ++      rc = 1;
    ++      goto meta_command_exit;
    ++    }
    + 
    +     /* convert testctrl text option to value. allow any unique prefix
    +     ** of the option name, or a numerical value. */
    +-    n2 = strlen30(azArg[1]);
    ++    n2 = strlen30(zCmd);
    +     for(i=0; i<ArraySize(aCtrl); i++){
    +-      if( strncmp(azArg[1], aCtrl[i].zCtrlName, n2)==0 ){
    ++      if( strncmp(zCmd, aCtrl[i].zCtrlName, n2)==0 ){
    +         if( testctrl<0 ){
    +           testctrl = aCtrl[i].ctrlCode;
    ++          iCtrl = i;
    +         }else{
    +-          fprintf(stderr, "ambiguous option name: \"%s\"\n", azArg[1]);
    +-          testctrl = -1;
    +-          break;
    ++          utf8_printf(stderr, "Error: ambiguous test-control: \"%s\"\n"
    ++                              "Use \".testctrl --help\" for help\n", zCmd);
    ++          rc = 1;
    ++          goto meta_command_exit;
    +         }
    +       }
    +     }
    +-    if( testctrl<0 ) testctrl = (int)integerValue(azArg[1]);
    +-    if( (testctrl<SQLITE_TESTCTRL_FIRST) || (testctrl>SQLITE_TESTCTRL_LAST) ){
    +-      fprintf(stderr,"Error: invalid testctrl option: %s\n", azArg[1]);
    ++    if( testctrl<0 ){
    ++      utf8_printf(stderr,"Error: unknown test-control: %s\n"
    ++                         "Use \".testctrl --help\" for help\n", zCmd);
    +     }else{
    +       switch(testctrl){
    + 
    +         /* sqlite3_test_control(int, db, int) */
    +         case SQLITE_TESTCTRL_OPTIMIZATIONS:
    +-        case SQLITE_TESTCTRL_RESERVE:             
    ++        case SQLITE_TESTCTRL_RESERVE:
    +           if( nArg==3 ){
    +-            int opt = (int)strtol(azArg[2], 0, 0);        
    ++            int opt = (int)strtol(azArg[2], 0, 0);
    +             rc2 = sqlite3_test_control(testctrl, p->db, opt);
    +-            fprintf(p->out, "%d (0x%08x)\n", rc2, rc2);
    +-          } else {
    +-            fprintf(stderr,"Error: testctrl %s takes a single int option\n",
    +-                    azArg[1]);
    ++            isOk = 3;
    +           }
    +           break;
    + 
    +@@ -3891,108 +14274,112 @@ static int do_meta_command(char *zLine, ShellState *p){
    +         case SQLITE_TESTCTRL_BYTEORDER:
    +           if( nArg==2 ){
    +             rc2 = sqlite3_test_control(testctrl);
    +-            fprintf(p->out, "%d (0x%08x)\n", rc2, rc2);
    +-          } else {
    +-            fprintf(stderr,"Error: testctrl %s takes no options\n", azArg[1]);
    ++            isOk = testctrl==SQLITE_TESTCTRL_BYTEORDER ? 1 : 3;
    +           }
    +           break;
    + 
    +         /* sqlite3_test_control(int, uint) */
    +-        case SQLITE_TESTCTRL_PENDING_BYTE:        
    ++        case SQLITE_TESTCTRL_PENDING_BYTE:
    +           if( nArg==3 ){
    +             unsigned int opt = (unsigned int)integerValue(azArg[2]);
    +             rc2 = sqlite3_test_control(testctrl, opt);
    +-            fprintf(p->out, "%d (0x%08x)\n", rc2, rc2);
    +-          } else {
    +-            fprintf(stderr,"Error: testctrl %s takes a single unsigned"
    +-                           " int option\n", azArg[1]);
    ++            isOk = 3;
    ++          }
    ++          break;
    ++
    ++        /* sqlite3_test_control(int, int) */
    ++        case SQLITE_TESTCTRL_ASSERT:
    ++        case SQLITE_TESTCTRL_ALWAYS:
    ++          if( nArg==3 ){
    ++            int opt = booleanValue(azArg[2]);
    ++            rc2 = sqlite3_test_control(testctrl, opt);
    ++            isOk = 1;
    +           }
    +           break;
    +-          
    ++
    +         /* sqlite3_test_control(int, int) */
    +-        case SQLITE_TESTCTRL_ASSERT:              
    +-        case SQLITE_TESTCTRL_ALWAYS:      
    +-        case SQLITE_TESTCTRL_NEVER_CORRUPT:        
    ++        case SQLITE_TESTCTRL_LOCALTIME_FAULT:
    ++        case SQLITE_TESTCTRL_NEVER_CORRUPT:
    +           if( nArg==3 ){
    +-            int opt = booleanValue(azArg[2]);        
    ++            int opt = booleanValue(azArg[2]);
    +             rc2 = sqlite3_test_control(testctrl, opt);
    +-            fprintf(p->out, "%d (0x%08x)\n", rc2, rc2);
    +-          } else {
    +-            fprintf(stderr,"Error: testctrl %s takes a single int option\n",
    +-                            azArg[1]);
    ++            isOk = 3;
    +           }
    +           break;
    + 
    +         /* sqlite3_test_control(int, char *) */
    + #ifdef SQLITE_N_KEYWORD
    +-        case SQLITE_TESTCTRL_ISKEYWORD:           
    ++        case SQLITE_TESTCTRL_ISKEYWORD:
    +           if( nArg==3 ){
    +-            const char *opt = azArg[2];        
    ++            const char *opt = azArg[2];
    +             rc2 = sqlite3_test_control(testctrl, opt);
    +-            fprintf(p->out, "%d (0x%08x)\n", rc2, rc2);
    +-          } else {
    +-            fprintf(stderr,"Error: testctrl %s takes a single char * option\n",
    +-                            azArg[1]);
    ++            isOk = 1;
    +           }
    +           break;
    + #endif
    + 
    +         case SQLITE_TESTCTRL_IMPOSTER:
    +           if( nArg==5 ){
    +-            rc2 = sqlite3_test_control(testctrl, p->db, 
    ++            rc2 = sqlite3_test_control(testctrl, p->db,
    +                           azArg[2],
    +                           integerValue(azArg[3]),
    +                           integerValue(azArg[4]));
    +-            fprintf(p->out, "%d (0x%08x)\n", rc2, rc2);
    +-          }else{
    +-            fprintf(stderr,"Usage: .testctrl imposter dbName onoff tnum\n");
    ++            isOk = 3;
    +           }
    +           break;
    + 
    +-        case SQLITE_TESTCTRL_BITVEC_TEST:         
    +-        case SQLITE_TESTCTRL_FAULT_INSTALL:       
    +-        case SQLITE_TESTCTRL_BENIGN_MALLOC_HOOKS: 
    +-        case SQLITE_TESTCTRL_SCRATCHMALLOC:       
    +-        default:
    +-          fprintf(stderr,"Error: CLI support for testctrl %s not implemented\n",
    +-                  azArg[1]);
    +-          break;
    ++#ifdef YYCOVERAGE
    ++        case SQLITE_TESTCTRL_PARSER_COVERAGE:
    ++          if( nArg==2 ){
    ++            sqlite3_test_control(testctrl, p->out);
    ++            isOk = 3;
    ++          }
    ++#endif
    +       }
    +     }
    ++    if( isOk==0 && iCtrl>=0 ){
    ++      utf8_printf(p->out, "Usage: .testctrl %s %s\n", zCmd, aCtrl[iCtrl].zUsage);
    ++      rc = 1;
    ++    }else if( isOk==1 ){
    ++      raw_printf(p->out, "%d\n", rc2);
    ++    }else if( isOk==2 ){
    ++      raw_printf(p->out, "0x%08x\n", rc2);
    ++    }
    +   }else
    ++#endif /* !defined(SQLITE_UNTESTABLE) */
    + 
    +   if( c=='t' && n>4 && strncmp(azArg[0], "timeout", n)==0 ){
    +     open_db(p, 0);
    +     sqlite3_busy_timeout(p->db, nArg>=2 ? (int)integerValue(azArg[1]) : 0);
    +   }else
    +-    
    ++
    +   if( c=='t' && n>=5 && strncmp(azArg[0], "timer", n)==0 ){
    +     if( nArg==2 ){
    +       enableTimer = booleanValue(azArg[1]);
    +       if( enableTimer && !HAS_TIMER ){
    +-        fprintf(stderr, "Error: timer not available on this system.\n");
    ++        raw_printf(stderr, "Error: timer not available on this system.\n");
    +         enableTimer = 0;
    +       }
    +     }else{
    +-      fprintf(stderr, "Usage: .timer on|off\n");
    ++      raw_printf(stderr, "Usage: .timer on|off\n");
    +       rc = 1;
    +     }
    +   }else
    +-  
    ++
    +   if( c=='t' && strncmp(azArg[0], "trace", n)==0 ){
    +     open_db(p, 0);
    +     if( nArg!=2 ){
    +-      fprintf(stderr, "Usage: .trace FILE|off\n");
    ++      raw_printf(stderr, "Usage: .trace FILE|off\n");
    +       rc = 1;
    +       goto meta_command_exit;
    +     }
    +     output_file_close(p->traceOut);
    +-    p->traceOut = output_file_open(azArg[1]);
    ++    p->traceOut = output_file_open(azArg[1], 0);
    + #if !defined(SQLITE_OMIT_TRACE) && !defined(SQLITE_OMIT_FLOATING_POINT)
    +     if( p->traceOut==0 ){
    +-      sqlite3_trace(p->db, 0, 0);
    ++      sqlite3_trace_v2(p->db, 0, 0, 0);
    +     }else{
    +-      sqlite3_trace(p->db, sql_trace_callback, p->traceOut);
    ++      sqlite3_trace_v2(p->db, SQLITE_TRACE_STMT, sql_trace_callback,p->traceOut);
    +     }
    + #endif
    +   }else
    +@@ -4000,71 +14387,114 @@ static int do_meta_command(char *zLine, ShellState *p){
    + #if SQLITE_USER_AUTHENTICATION
    +   if( c=='u' && strncmp(azArg[0], "user", n)==0 ){
    +     if( nArg<2 ){
    +-      fprintf(stderr, "Usage: .user SUBCOMMAND ...\n");
    ++      raw_printf(stderr, "Usage: .user SUBCOMMAND ...\n");
    +       rc = 1;
    +       goto meta_command_exit;
    +     }
    +     open_db(p, 0);
    +     if( strcmp(azArg[1],"login")==0 ){
    +       if( nArg!=4 ){
    +-        fprintf(stderr, "Usage: .user login USER PASSWORD\n");
    ++        raw_printf(stderr, "Usage: .user login USER PASSWORD\n");
    +         rc = 1;
    +         goto meta_command_exit;
    +       }
    +-      rc = sqlite3_user_authenticate(p->db, azArg[2], azArg[3],
    +-                                    (int)strlen(azArg[3]));
    ++      rc = sqlite3_user_authenticate(p->db, azArg[2], azArg[3], strlen30(azArg[3]));
    +       if( rc ){
    +-        fprintf(stderr, "Authentication failed for user %s\n", azArg[2]);
    ++        utf8_printf(stderr, "Authentication failed for user %s\n", azArg[2]);
    +         rc = 1;
    +       }
    +     }else if( strcmp(azArg[1],"add")==0 ){
    +       if( nArg!=5 ){
    +-        fprintf(stderr, "Usage: .user add USER PASSWORD ISADMIN\n");
    ++        raw_printf(stderr, "Usage: .user add USER PASSWORD ISADMIN\n");
    +         rc = 1;
    +         goto meta_command_exit;
    +       }
    +-      rc = sqlite3_user_add(p->db, azArg[2],
    +-                            azArg[3], (int)strlen(azArg[3]),
    ++      rc = sqlite3_user_add(p->db, azArg[2], azArg[3], strlen30(azArg[3]),
    +                             booleanValue(azArg[4]));
    +       if( rc ){
    +-        fprintf(stderr, "User-Add failed: %d\n", rc);
    ++        raw_printf(stderr, "User-Add failed: %d\n", rc);
    +         rc = 1;
    +       }
    +     }else if( strcmp(azArg[1],"edit")==0 ){
    +       if( nArg!=5 ){
    +-        fprintf(stderr, "Usage: .user edit USER PASSWORD ISADMIN\n");
    ++        raw_printf(stderr, "Usage: .user edit USER PASSWORD ISADMIN\n");
    +         rc = 1;
    +         goto meta_command_exit;
    +       }
    +-      rc = sqlite3_user_change(p->db, azArg[2],
    +-                              azArg[3], (int)strlen(azArg[3]),
    ++      rc = sqlite3_user_change(p->db, azArg[2], azArg[3], strlen30(azArg[3]),
    +                               booleanValue(azArg[4]));
    +       if( rc ){
    +-        fprintf(stderr, "User-Edit failed: %d\n", rc);
    ++        raw_printf(stderr, "User-Edit failed: %d\n", rc);
    +         rc = 1;
    +       }
    +     }else if( strcmp(azArg[1],"delete")==0 ){
    +       if( nArg!=3 ){
    +-        fprintf(stderr, "Usage: .user delete USER\n");
    ++        raw_printf(stderr, "Usage: .user delete USER\n");
    +         rc = 1;
    +         goto meta_command_exit;
    +       }
    +       rc = sqlite3_user_delete(p->db, azArg[2]);
    +       if( rc ){
    +-        fprintf(stderr, "User-Delete failed: %d\n", rc);
    ++        raw_printf(stderr, "User-Delete failed: %d\n", rc);
    +         rc = 1;
    +       }
    +     }else{
    +-      fprintf(stderr, "Usage: .user login|add|edit|delete ...\n");
    ++      raw_printf(stderr, "Usage: .user login|add|edit|delete ...\n");
    +       rc = 1;
    +       goto meta_command_exit;
    +-    }    
    ++    }
    +   }else
    + #endif /* SQLITE_USER_AUTHENTICATION */
    + 
    +   if( c=='v' && strncmp(azArg[0], "version", n)==0 ){
    +-    fprintf(p->out, "SQLite %s %s\n" /*extra-version-info*/,
    ++    utf8_printf(p->out, "SQLite %s %s\n" /*extra-version-info*/,
    +         sqlite3_libversion(), sqlite3_sourceid());
    ++#if SQLITE_HAVE_ZLIB
    ++    utf8_printf(p->out, "zlib version %s\n", zlibVersion());
    ++#endif
    ++#define CTIMEOPT_VAL_(opt) #opt
    ++#define CTIMEOPT_VAL(opt) CTIMEOPT_VAL_(opt)
    ++#if defined(__clang__) && defined(__clang_major__)
    ++    utf8_printf(p->out, "clang-" CTIMEOPT_VAL(__clang_major__) "."
    ++                    CTIMEOPT_VAL(__clang_minor__) "."
    ++                    CTIMEOPT_VAL(__clang_patchlevel__) "\n");
    ++#elif defined(_MSC_VER)
    ++    utf8_printf(p->out, "msvc-" CTIMEOPT_VAL(_MSC_VER) "\n");
    ++#elif defined(__GNUC__) && defined(__VERSION__)
    ++    utf8_printf(p->out, "gcc-" __VERSION__ "\n");
    ++#endif
    ++  }else
    ++
    ++  if( c=='v' && strncmp(azArg[0], "vfsinfo", n)==0 ){
    ++    const char *zDbName = nArg==2 ? azArg[1] : "main";
    ++    sqlite3_vfs *pVfs = 0;
    ++    if( p->db ){
    ++      sqlite3_file_control(p->db, zDbName, SQLITE_FCNTL_VFS_POINTER, &pVfs);
    ++      if( pVfs ){
    ++        utf8_printf(p->out, "vfs.zName      = \"%s\"\n", pVfs->zName);
    ++        raw_printf(p->out, "vfs.iVersion   = %d\n", pVfs->iVersion);
    ++        raw_printf(p->out, "vfs.szOsFile   = %d\n", pVfs->szOsFile);
    ++        raw_printf(p->out, "vfs.mxPathname = %d\n", pVfs->mxPathname);
    ++      }
    ++    }
    ++  }else
    ++
    ++  if( c=='v' && strncmp(azArg[0], "vfslist", n)==0 ){
    ++    sqlite3_vfs *pVfs;
    ++    sqlite3_vfs *pCurrent = 0;
    ++    if( p->db ){
    ++      sqlite3_file_control(p->db, "main", SQLITE_FCNTL_VFS_POINTER, &pCurrent);
    ++    }
    ++    for(pVfs=sqlite3_vfs_find(0); pVfs; pVfs=pVfs->pNext){
    ++      utf8_printf(p->out, "vfs.zName      = \"%s\"%s\n", pVfs->zName,
    ++           pVfs==pCurrent ? "  <--- CURRENT" : "");
    ++      raw_printf(p->out, "vfs.iVersion   = %d\n", pVfs->iVersion);
    ++      raw_printf(p->out, "vfs.szOsFile   = %d\n", pVfs->szOsFile);
    ++      raw_printf(p->out, "vfs.mxPathname = %d\n", pVfs->mxPathname);
    ++      if( pVfs->pNext ){
    ++        raw_printf(p->out, "-----------------------------------\n");
    ++      }
    ++    }
    +   }else
    + 
    +   if( c=='v' && strncmp(azArg[0], "vfsname", n)==0 ){
    +@@ -4073,7 +14503,7 @@ static int do_meta_command(char *zLine, ShellState *p){
    +     if( p->db ){
    +       sqlite3_file_control(p->db, zDbName, SQLITE_FCNTL_VFSNAME, &zVfsName);
    +       if( zVfsName ){
    +-        fprintf(p->out, "%s\n", zVfsName);
    ++        utf8_printf(p->out, "%s\n", zVfsName);
    +         sqlite3_free(zVfsName);
    +       }
    +     }
    +@@ -4081,7 +14511,6 @@ static int do_meta_command(char *zLine, ShellState *p){
    + 
    + #if defined(SQLITE_DEBUG) && defined(SQLITE_ENABLE_WHERETRACE)
    +   if( c=='w' && strncmp(azArg[0], "wheretrace", n)==0 ){
    +-    extern int sqlite3WhereTrace;
    +     sqlite3WhereTrace = nArg>=2 ? booleanValue(azArg[1]) : 0xff;
    +   }else
    + #endif
    +@@ -4095,7 +14524,7 @@ static int do_meta_command(char *zLine, ShellState *p){
    +   }else
    + 
    +   {
    +-    fprintf(stderr, "Error: unknown command or invalid arguments: "
    ++    utf8_printf(stderr, "Error: unknown command or invalid arguments: "
    +       " \"%s\". Enter \".help\" for help\n", azArg[0]);
    +     rc = 1;
    +   }
    +@@ -4173,6 +14602,42 @@ static int line_is_complete(char *zSql, int nSql){
    +   return rc;
    + }
    + 
    ++/*
    ++** Run a single line of SQL
    ++*/
    ++static int runOneSqlLine(ShellState *p, char *zSql, FILE *in, int startline){
    ++  int rc;
    ++  char *zErrMsg = 0;
    ++
    ++  open_db(p, 0);
    ++  if( ShellHasFlag(p,SHFLG_Backslash) ) resolve_backslashes(zSql);
    ++  BEGIN_TIMER;
    ++  rc = shell_exec(p->db, zSql, shell_callback, p, &zErrMsg);
    ++  END_TIMER;
    ++  if( rc || zErrMsg ){
    ++    char zPrefix[100];
    ++    if( in!=0 || !stdin_is_interactive ){
    ++      sqlite3_snprintf(sizeof(zPrefix), zPrefix,
    ++                       "Error: near line %d:", startline);
    ++    }else{
    ++      sqlite3_snprintf(sizeof(zPrefix), zPrefix, "Error:");
    ++    }
    ++    if( zErrMsg!=0 ){
    ++      utf8_printf(stderr, "%s %s\n", zPrefix, zErrMsg);
    ++      sqlite3_free(zErrMsg);
    ++      zErrMsg = 0;
    ++    }else{
    ++      utf8_printf(stderr, "%s %s\n", zPrefix, sqlite3_errmsg(p->db));
    ++    }
    ++    return 1;
    ++  }else if( ShellHasFlag(p, SHFLG_CountChanges) ){
    ++    raw_printf(p->out, "changes: %3d   total_changes: %d\n",
    ++            sqlite3_changes(p->db), sqlite3_total_changes(p->db));
    ++  }
    ++  return 0;
    ++}
    ++
    ++
    + /*
    + ** Read input from *in and process it.  If *in==0 then input
    + ** is interactive - the user is typing it it.  Otherwise, input
    +@@ -4189,7 +14654,6 @@ static int process_input(ShellState *p, FILE *in){
    +   int nSql = 0;             /* Bytes of zSql[] used */
    +   int nAlloc = 0;           /* Allocated zSql[] space */
    +   int nSqlPrior = 0;        /* Bytes of zSql[] used by prior line */
    +-  char *zErrMsg;            /* Error message returned */
    +   int rc;                   /* Error code */
    +   int errCnt = 0;           /* Number of errors seen */
    +   int lineno = 0;           /* Current line number */
    +@@ -4200,7 +14664,7 @@ static int process_input(ShellState *p, FILE *in){
    +     zLine = one_input_line(in, zLine, nSql>0);
    +     if( zLine==0 ){
    +       /* End of input */
    +-      if( stdin_is_interactive ) printf("\n");
    ++      if( in==0 && stdin_is_interactive ) printf("\n");
    +       break;
    +     }
    +     if( seenInterrupt ){
    +@@ -4209,11 +14673,11 @@ static int process_input(ShellState *p, FILE *in){
    +     }
    +     lineno++;
    +     if( nSql==0 && _all_whitespace(zLine) ){
    +-      if( p->echoOn ) printf("%s\n", zLine);
    ++      if( ShellHasFlag(p, SHFLG_Echo) ) printf("%s\n", zLine);
    +       continue;
    +     }
    +     if( zLine && zLine[0]=='.' && nSql==0 ){
    +-      if( p->echoOn ) printf("%s\n", zLine);
    ++      if( ShellHasFlag(p, SHFLG_Echo) ) printf("%s\n", zLine);
    +       rc = do_meta_command(zLine, p);
    +       if( rc==2 ){ /* exit requested */
    +         break;
    +@@ -4230,7 +14694,7 @@ static int process_input(ShellState *p, FILE *in){
    +       nAlloc = nSql+nLine+100;
    +       zSql = realloc(zSql, nAlloc);
    +       if( zSql==0 ){
    +-        fprintf(stderr, "Error: out of memory\n");
    ++        raw_printf(stderr, "Error: out of memory\n");
    +         exit(1);
    +       }
    +     }
    +@@ -4249,44 +14713,21 @@ static int process_input(ShellState *p, FILE *in){
    +     }
    +     if( nSql && line_contains_semicolon(&zSql[nSqlPrior], nSql-nSqlPrior)
    +                 && sqlite3_complete(zSql) ){
    +-      p->cnt = 0;
    +-      open_db(p, 0);
    +-      if( p->backslashOn ) resolve_backslashes(zSql);
    +-      BEGIN_TIMER;
    +-      rc = shell_exec(p->db, zSql, shell_callback, p, &zErrMsg);
    +-      END_TIMER;
    +-      if( rc || zErrMsg ){
    +-        char zPrefix[100];
    +-        if( in!=0 || !stdin_is_interactive ){
    +-          sqlite3_snprintf(sizeof(zPrefix), zPrefix, 
    +-                           "Error: near line %d:", startline);
    +-        }else{
    +-          sqlite3_snprintf(sizeof(zPrefix), zPrefix, "Error:");
    +-        }
    +-        if( zErrMsg!=0 ){
    +-          fprintf(stderr, "%s %s\n", zPrefix, zErrMsg);
    +-          sqlite3_free(zErrMsg);
    +-          zErrMsg = 0;
    +-        }else{
    +-          fprintf(stderr, "%s %s\n", zPrefix, sqlite3_errmsg(p->db));
    +-        }
    +-        errCnt++;
    +-      }
    ++      errCnt += runOneSqlLine(p, zSql, in, startline);
    +       nSql = 0;
    +       if( p->outCount ){
    +         output_reset(p);
    +         p->outCount = 0;
    ++      }else{
    ++        clearTempFile(p);
    +       }
    +     }else if( nSql && _all_whitespace(zSql) ){
    +-      if( p->echoOn ) printf("%s\n", zSql);
    ++      if( ShellHasFlag(p, SHFLG_Echo) ) printf("%s\n", zSql);
    +       nSql = 0;
    +     }
    +   }
    +-  if( nSql ){
    +-    if( !_all_whitespace(zSql) ){
    +-      fprintf(stderr, "Error: incomplete SQL: %s\n", zSql);
    +-      errCnt++;
    +-    }
    ++  if( nSql && !_all_whitespace(zSql) ){
    ++    runOneSqlLine(p, zSql, in, startline);
    +   }
    +   free(zSql);
    +   free(zLine);
    +@@ -4297,8 +14738,13 @@ static int process_input(ShellState *p, FILE *in){
    + ** Return a pathname which is the user's home directory.  A
    + ** 0 return indicates an error of some kind.
    + */
    +-static char *find_home_dir(void){
    ++static char *find_home_dir(int clearFlag){
    +   static char *home_dir = NULL;
    ++  if( clearFlag ){
    ++    free(home_dir);
    ++    home_dir = 0;
    ++    return 0;
    ++  }
    +   if( home_dir ) return home_dir;
    + 
    + #if !defined(_WIN32) && !defined(WIN32) && !defined(_WIN32_WCE) \
    +@@ -4373,9 +14819,9 @@ static void process_sqliterc(
    +   FILE *in = NULL;
    + 
    +   if (sqliterc == NULL) {
    +-    home_dir = find_home_dir();
    ++    home_dir = find_home_dir(0);
    +     if( home_dir==0 ){
    +-      fprintf(stderr, "-- warning: cannot find home directory;"
    ++      raw_printf(stderr, "-- warning: cannot find home directory;"
    +                       " cannot read ~/.sqliterc\n");
    +       return;
    +     }
    +@@ -4386,7 +14832,7 @@ static void process_sqliterc(
    +   in = fopen(sqliterc,"rb");
    +   if( in ){
    +     if( stdin_is_interactive ){
    +-      fprintf(stderr,"-- Loading resources from %s\n",sqliterc);
    ++      utf8_printf(stderr,"-- Loading resources from %s\n",sqliterc);
    +     }
    +     process_input(p,in);
    +     fclose(in);
    +@@ -4397,7 +14843,7 @@ static void process_sqliterc(
    + /*
    + ** Show available command line options
    + */
    +-static const char zOptions[] = 
    ++static const char zOptions[] =
    +   "   -ascii               set output mode to 'ascii'\n"
    +   "   -bail                stop after hitting an error\n"
    +   "   -batch               force batch I/O\n"
    +@@ -4423,7 +14869,7 @@ static const char zOptions[] =
    +   "   -newline SEP         set output row separator. Default: '\\n'\n"
    +   "   -nullvalue TEXT      set text string for NULL values. Default ''\n"
    +   "   -pagecache SIZE N    use N slots of SZ bytes each for page cache memory\n"
    +-  "   -scratch SIZE N      use N slots of SZ bytes each for scratch memory\n"
    ++  "   -quote               set output mode to 'quote'\n"
    +   "   -separator SEP       set output column separator. Default: '|'\n"
    +   "   -stats               print memory stats before each finalize\n"
    +   "   -version             show SQLite version\n"
    +@@ -4433,14 +14879,14 @@ static const char zOptions[] =
    + #endif
    + ;
    + static void usage(int showDetail){
    +-  fprintf(stderr,
    +-      "Usage: %s [OPTIONS] FILENAME [SQL]\n"  
    ++  utf8_printf(stderr,
    ++      "Usage: %s [OPTIONS] FILENAME [SQL]\n"
    +       "FILENAME is the name of an SQLite database. A new database is created\n"
    +       "if the file does not previously exist.\n", Argv0);
    +   if( showDetail ){
    +-    fprintf(stderr, "OPTIONS include:\n%s", zOptions);
    ++    utf8_printf(stderr, "OPTIONS include:\n%s", zOptions);
    +   }else{
    +-    fprintf(stderr, "Use the -help option for additional information\n");
    ++    raw_printf(stderr, "Use the -help option for additional information\n");
    +   }
    +   exit(1);
    + }
    +@@ -4450,7 +14896,8 @@ static void usage(int showDetail){
    + */
    + static void main_init(ShellState *data) {
    +   memset(data, 0, sizeof(*data));
    +-  data->mode = MODE_List;
    ++  data->normalMode = data->cMode = data->mode = MODE_List;
    ++  data->autoExplain = 1;
    +   memcpy(data->colSeparator,SEP_Column, 2);
    +   memcpy(data->rowSeparator,SEP_Row, 2);
    +   data->showHeader = 0;
    +@@ -4488,14 +14935,27 @@ static void printBold(const char *zText){
    + */
    + static char *cmdline_option_value(int argc, char **argv, int i){
    +   if( i==argc ){
    +-    fprintf(stderr, "%s: Error: missing argument to %s\n",
    ++    utf8_printf(stderr, "%s: Error: missing argument to %s\n",
    +             argv[0], argv[argc-1]);
    +     exit(1);
    +   }
    +   return argv[i];
    + }
    + 
    ++#ifndef SQLITE_SHELL_IS_UTF8
    ++#  if (defined(_WIN32) || defined(WIN32)) && defined(_MSC_VER)
    ++#    define SQLITE_SHELL_IS_UTF8          (0)
    ++#  else
    ++#    define SQLITE_SHELL_IS_UTF8          (1)
    ++#  endif
    ++#endif
    ++
    ++#if SQLITE_SHELL_IS_UTF8
    + int SQLITE_CDECL main(int argc, char **argv){
    ++#else
    ++int SQLITE_CDECL wmain(int argc, wchar_t **wargv){
    ++  char **argv;
    ++#endif
    +   char *zErrMsg = 0;
    +   ShellState data;
    +   const char *zInitFile = 0;
    +@@ -4506,24 +14966,44 @@ int SQLITE_CDECL main(int argc, char **argv){
    +   int nCmd = 0;
    +   char **azCmd = 0;
    + 
    ++  setBinaryMode(stdin, 0);
    ++  setvbuf(stderr, 0, _IONBF, 0); /* Make sure stderr is unbuffered */
    ++  stdin_is_interactive = isatty(0);
    ++  stdout_is_console = isatty(1);
    ++
    + #if USE_SYSTEM_SQLITE+0!=1
    +-  if( strcmp(sqlite3_sourceid(),SQLITE_SOURCE_ID)!=0 ){
    +-    fprintf(stderr, "SQLite header and source version mismatch\n%s\n%s\n",
    ++  if( strncmp(sqlite3_sourceid(),SQLITE_SOURCE_ID,60)!=0 ){
    ++    utf8_printf(stderr, "SQLite header and source version mismatch\n%s\n%s\n",
    +             sqlite3_sourceid(), SQLITE_SOURCE_ID);
    +     exit(1);
    +   }
    + #endif
    +-  setBinaryMode(stdin);
    +-  setvbuf(stderr, 0, _IONBF, 0); /* Make sure stderr is unbuffered */
    +-  Argv0 = argv[0];
    +   main_init(&data);
    +-  stdin_is_interactive = isatty(0);
    ++#if !SQLITE_SHELL_IS_UTF8
    ++  sqlite3_initialize();
    ++  argv = sqlite3_malloc64(sizeof(argv[0])*argc);
    ++  if( argv==0 ){
    ++    raw_printf(stderr, "out of memory\n");
    ++    exit(1);
    ++  }
    ++  for(i=0; i<argc; i++){
    ++    argv[i] = sqlite3_win32_unicode_to_utf8(wargv[i]);
    ++    if( argv[i]==0 ){
    ++      raw_printf(stderr, "out of memory\n");
    ++      exit(1);
    ++    }
    ++  }
    ++#endif
    ++  assert( argc>=1 && argv && argv[0] );
    ++  Argv0 = argv[0];
    + 
    +   /* Make sure we have a valid signal handler early, before anything
    +   ** else is done.
    +   */
    + #ifdef SIGINT
    +   signal(SIGINT, interrupt_handler);
    ++#elif (defined(_WIN32) || defined(WIN32)) && !defined(_WIN32_WCE)
    ++  SetConsoleCtrlHandler(ConsoleCtrlHandler, TRUE);
    + #endif
    + 
    + #ifdef SQLITE_SHELL_DBNAME_PROC
    +@@ -4556,7 +15036,7 @@ int SQLITE_CDECL main(int argc, char **argv){
    +         nCmd++;
    +         azCmd = realloc(azCmd, sizeof(azCmd[0])*nCmd);
    +         if( azCmd==0 ){
    +-          fprintf(stderr, "out of memory\n");
    ++          raw_printf(stderr, "out of memory\n");
    +           exit(1);
    +         }
    +         azCmd[nCmd-1] = z;
    +@@ -4573,7 +15053,7 @@ int SQLITE_CDECL main(int argc, char **argv){
    +       zInitFile = cmdline_option_value(argc, argv, ++i);
    +     }else if( strcmp(z,"-batch")==0 ){
    +       /* Need to check for batch mode here to so we can avoid printing
    +-      ** informational messages (like from process_sqliterc) before 
    ++      ** informational messages (like from process_sqliterc) before
    +       ** we do the actual processing of arguments later in a second pass.
    +       */
    +       stdin_is_interactive = 0;
    +@@ -4586,25 +15066,17 @@ int SQLITE_CDECL main(int argc, char **argv){
    +       szHeap = integerValue(zSize);
    +       if( szHeap>0x7fff0000 ) szHeap = 0x7fff0000;
    +       sqlite3_config(SQLITE_CONFIG_HEAP, malloc((int)szHeap), (int)szHeap, 64);
    ++#else
    ++      (void)cmdline_option_value(argc, argv, ++i);
    + #endif
    +-    }else if( strcmp(z,"-scratch")==0 ){
    +-      int n, sz;
    +-      sz = (int)integerValue(cmdline_option_value(argc,argv,++i));
    +-      if( sz>400000 ) sz = 400000;
    +-      if( sz<2500 ) sz = 2500;
    +-      n = (int)integerValue(cmdline_option_value(argc,argv,++i));
    +-      if( n>10 ) n = 10;
    +-      if( n<1 ) n = 1;
    +-      sqlite3_config(SQLITE_CONFIG_SCRATCH, malloc(n*sz+1), sz, n);
    +-      data.shellFlgs |= SHFLG_Scratch;
    +     }else if( strcmp(z,"-pagecache")==0 ){
    +       int n, sz;
    +       sz = (int)integerValue(cmdline_option_value(argc,argv,++i));
    +       if( sz>70000 ) sz = 70000;
    +-      if( sz<800 ) sz = 800;
    ++      if( sz<0 ) sz = 0;
    +       n = (int)integerValue(cmdline_option_value(argc,argv,++i));
    +-      if( n<10 ) n = 10;
    +-      sqlite3_config(SQLITE_CONFIG_PAGECACHE, malloc(n*sz+1), sz, n);
    ++      sqlite3_config(SQLITE_CONFIG_PAGECACHE,
    ++                    (n>0 && sz>0) ? malloc(n*sz) : 0, sz, n);
    +       data.shellFlgs |= SHFLG_Pagecache;
    +     }else if( strcmp(z,"-lookaside")==0 ){
    +       int n, sz;
    +@@ -4638,9 +15110,15 @@ int SQLITE_CDECL main(int argc, char **argv){
    +       if( pVfs ){
    +         sqlite3_vfs_register(pVfs, 1);
    +       }else{
    +-        fprintf(stderr, "no such VFS: \"%s\"\n", argv[i]);
    ++        utf8_printf(stderr, "no such VFS: \"%s\"\n", argv[i]);
    +         exit(1);
    +       }
    ++#ifdef SQLITE_HAVE_ZIP
    ++    }else if( strcmp(z,"-zip")==0 ){
    ++      data.openMode = SHELL_OPEN_ZIPFILE;
    ++#endif
    ++    }else if( strcmp(z,"-append")==0 ){
    ++      data.openMode = SHELL_OPEN_APPENDVFS;
    +     }
    +   }
    +   if( data.zDbFilename==0 ){
    +@@ -4648,11 +15126,12 @@ int SQLITE_CDECL main(int argc, char **argv){
    +     data.zDbFilename = ":memory:";
    +     warnInmemoryDb = argc==1;
    + #else
    +-    fprintf(stderr,"%s: Error: no database filename specified\n", Argv0);
    ++    utf8_printf(stderr,"%s: Error: no database filename specified\n", Argv0);
    +     return 1;
    + #endif
    +   }
    +   data.out = stdout;
    ++  sqlite3_appendvfs_init(0,0,0);
    + 
    +   /* Go ahead and open the database file if it already exists.  If the
    +   ** file does not exist, delay opening it.  This prevents empty database
    +@@ -4684,6 +15163,8 @@ int SQLITE_CDECL main(int argc, char **argv){
    +       data.mode = MODE_Html;
    +     }else if( strcmp(z,"-list")==0 ){
    +       data.mode = MODE_List;
    ++    }else if( strcmp(z,"-quote")==0 ){
    ++      data.mode = MODE_Quote;
    +     }else if( strcmp(z,"-line")==0 ){
    +       data.mode = MODE_Line;
    +     }else if( strcmp(z,"-column")==0 ){
    +@@ -4691,6 +15172,12 @@ int SQLITE_CDECL main(int argc, char **argv){
    +     }else if( strcmp(z,"-csv")==0 ){
    +       data.mode = MODE_Csv;
    +       memcpy(data.colSeparator,",",2);
    ++#ifdef SQLITE_HAVE_ZIP
    ++    }else if( strcmp(z,"-zip")==0 ){
    ++      data.openMode = SHELL_OPEN_ZIPFILE;
    ++#endif
    ++    }else if( strcmp(z,"-append")==0 ){
    ++      data.openMode = SHELL_OPEN_APPENDVFS;
    +     }else if( strcmp(z,"-ascii")==0 ){
    +       data.mode = MODE_Ascii;
    +       sqlite3_snprintf(sizeof(data.colSeparator), data.colSeparator,
    +@@ -4711,9 +15198,11 @@ int SQLITE_CDECL main(int argc, char **argv){
    +     }else if( strcmp(z,"-noheader")==0 ){
    +       data.showHeader = 0;
    +     }else if( strcmp(z,"-echo")==0 ){
    +-      data.echoOn = 1;
    ++      ShellSetFlag(&data, SHFLG_Echo);
    +     }else if( strcmp(z,"-eqp")==0 ){
    +-      data.autoEQP = 1;
    ++      data.autoEQP = AUTOEQP_on;
    ++    }else if( strcmp(z,"-eqpfull")==0 ){
    ++      data.autoEQP = AUTOEQP_full;
    +     }else if( strcmp(z,"-stats")==0 ){
    +       data.statsOn = 1;
    +     }else if( strcmp(z,"-scanstats")==0 ){
    +@@ -4724,7 +15213,7 @@ int SQLITE_CDECL main(int argc, char **argv){
    +       ** prior to sending the SQL into SQLite.  Useful for injecting
    +       ** crazy bytes in the middle of SQL statements for testing and debugging.
    +       */
    +-      data.backslashOn = 1;
    ++      ShellSetFlag(&data, SHFLG_Backslash);
    +     }else if( strcmp(z,"-bail")==0 ){
    +       bail_on_error = 1;
    +     }else if( strcmp(z,"-version")==0 ){
    +@@ -4736,8 +15225,6 @@ int SQLITE_CDECL main(int argc, char **argv){
    +       stdin_is_interactive = 0;
    +     }else if( strcmp(z,"-heap")==0 ){
    +       i++;
    +-    }else if( strcmp(z,"-scratch")==0 ){
    +-      i+=2;
    +     }else if( strcmp(z,"-pagecache")==0 ){
    +       i+=2;
    +     }else if( strcmp(z,"-lookaside")==0 ){
    +@@ -4770,18 +15257,19 @@ int SQLITE_CDECL main(int argc, char **argv){
    +         open_db(&data, 0);
    +         rc = shell_exec(data.db, z, shell_callback, &data, &zErrMsg);
    +         if( zErrMsg!=0 ){
    +-          fprintf(stderr,"Error: %s\n", zErrMsg);
    ++          utf8_printf(stderr,"Error: %s\n", zErrMsg);
    +           if( bail_on_error ) return rc!=0 ? rc : 1;
    +         }else if( rc!=0 ){
    +-          fprintf(stderr,"Error: unable to process SQL \"%s\"\n", z);
    ++          utf8_printf(stderr,"Error: unable to process SQL \"%s\"\n", z);
    +           if( bail_on_error ) return rc;
    +         }
    +       }
    +     }else{
    +-      fprintf(stderr,"%s: Error: unknown option: %s\n", Argv0, z);
    +-      fprintf(stderr,"Use -help for a list of options.\n");
    ++      utf8_printf(stderr,"%s: Error: unknown option: %s\n", Argv0, z);
    ++      raw_printf(stderr,"Use -help for a list of options.\n");
    +       return 1;
    +     }
    ++    data.cMode = data.mode;
    +   }
    + 
    +   if( !readStdin ){
    +@@ -4797,10 +15285,10 @@ int SQLITE_CDECL main(int argc, char **argv){
    +         open_db(&data, 0);
    +         rc = shell_exec(data.db, azCmd[i], shell_callback, &data, &zErrMsg);
    +         if( zErrMsg!=0 ){
    +-          fprintf(stderr,"Error: %s\n", zErrMsg);
    ++          utf8_printf(stderr,"Error: %s\n", zErrMsg);
    +           return rc!=0 ? rc : 1;
    +         }else if( rc!=0 ){
    +-          fprintf(stderr,"Error: unable to process SQL: %s\n", azCmd[i]);
    ++          utf8_printf(stderr,"Error: unable to process SQL: %s\n", azCmd[i]);
    +           return rc;
    +         }
    +       }
    +@@ -4824,7 +15312,7 @@ int SQLITE_CDECL main(int argc, char **argv){
    +         printf(".\nUse \".open FILENAME\" to reopen on a "
    +                "persistent database.\n");
    +       }
    +-      zHome = find_home_dir();
    ++      zHome = find_home_dir(0);
    +       if( zHome ){
    +         nHistory = strlen30(zHome) + 20;
    +         if( (zHistory = malloc(nHistory))!=0 ){
    +@@ -4832,9 +15320,14 @@ int SQLITE_CDECL main(int argc, char **argv){
    +         }
    +       }
    +       if( zHistory ){ shell_read_history(zHistory); }
    ++#if HAVE_READLINE || HAVE_EDITLINE
    ++      rl_attempted_completion_function = readline_completion;
    ++#elif HAVE_LINENOISE
    ++      linenoiseSetCompletionCallback(linenoise_completion);
    ++#endif
    +       rc = process_input(&data, 0);
    +       if( zHistory ){
    +-        shell_stifle_history(100);
    ++        shell_stifle_history(2000);
    +         shell_write_history(zHistory);
    +         free(zHistory);
    +       }
    +@@ -4844,8 +15337,17 @@ int SQLITE_CDECL main(int argc, char **argv){
    +   }
    +   set_table_name(&data, 0);
    +   if( data.db ){
    ++    session_close_all(&data);
    +     sqlite3_close(data.db);
    +   }
    +-  sqlite3_free(data.zFreeOnClose); 
    ++  sqlite3_free(data.zFreeOnClose);
    ++  find_home_dir(1);
    ++  output_reset(&data);
    ++  data.doXdgOpen = 0;
    ++  clearTempFile(&data);
    ++#if !SQLITE_SHELL_IS_UTF8
    ++  for(i=0; i<argc; i++) sqlite3_free(argv[i]);
    ++  sqlite3_free(argv);
    ++#endif
    +   return rc;
    + }
    +diff --git a/dist/orig/sqlite3.c b/dist/orig/sqlite3.c
    +index 0ae407d..8e495f1 100644
    +--- a/dist/orig/sqlite3.c
    ++++ b/dist/orig/sqlite3.c
    +@@ -1,6 +1,6 @@
    + /******************************************************************************
    + ** This file is an amalgamation of many separate C source files from SQLite
    +-** version 3.9.2.  By combining all the individual C code files into this 
    ++** version 3.22.0.  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
    +@@ -9,7 +9,7 @@
    + **
    + ** This file is all you need to compile SQLite.  To use SQLite in other
    + ** programs, you need this file and the "sqlite3.h" header file that defines
    +-** the programming interface to the SQLite library.  (If you do not have 
    ++** the programming interface to the SQLite library.  (If you do not have
    + ** the "sqlite3.h" header file at hand, you will find a copy embedded within
    + ** the text of this file.  Search for "Begin file sqlite3.h" to find the start
    + ** of the embedded sqlite3.h header file.) Additional code files may be needed
    +@@ -22,6 +22,761 @@
    + #ifndef SQLITE_PRIVATE
    + # define SQLITE_PRIVATE static
    + #endif
    ++/************** Begin file ctime.c *******************************************/
    ++/*
    ++** 2010 February 23
    ++**
    ++** 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 implements routines used to report what compile-time options
    ++** SQLite was built with.
    ++*/
    ++
    ++#ifndef SQLITE_OMIT_COMPILEOPTION_DIAGS
    ++
    ++/*
    ++** Include the configuration header output by 'configure' if we're using the
    ++** autoconf-based build
    ++*/
    ++#if defined(_HAVE_SQLITE_CONFIG_H) && !defined(SQLITECONFIG_H)
    ++#include "config.h"
    ++#define SQLITECONFIG_H 1
    ++#endif
    ++
    ++/* These macros are provided to "stringify" the value of the define
    ++** for those options in which the value is meaningful. */
    ++#define CTIMEOPT_VAL_(opt) #opt
    ++#define CTIMEOPT_VAL(opt) CTIMEOPT_VAL_(opt)
    ++
    ++/*
    ++** An array of names of all compile-time options.  This array should 
    ++** be sorted A-Z.
    ++**
    ++** This array looks large, but in a typical installation actually uses
    ++** only a handful of compile-time options, so most times this array is usually
    ++** rather short and uses little memory space.
    ++*/
    ++static const char * const sqlite3azCompileOpt[] = {
    ++
    ++/* 
    ++** BEGIN CODE GENERATED BY tool/mkctime.tcl 
    ++*/
    ++#if SQLITE_32BIT_ROWID
    ++  "32BIT_ROWID",
    ++#endif
    ++#if SQLITE_4_BYTE_ALIGNED_MALLOC
    ++  "4_BYTE_ALIGNED_MALLOC",
    ++#endif
    ++#if SQLITE_64BIT_STATS
    ++  "64BIT_STATS",
    ++#endif
    ++#if SQLITE_ALLOW_COVERING_INDEX_SCAN
    ++  "ALLOW_COVERING_INDEX_SCAN",
    ++#endif
    ++#if SQLITE_ALLOW_URI_AUTHORITY
    ++  "ALLOW_URI_AUTHORITY",
    ++#endif
    ++#ifdef SQLITE_BITMASK_TYPE
    ++  "BITMASK_TYPE=" CTIMEOPT_VAL(SQLITE_BITMASK_TYPE),
    ++#endif
    ++#if SQLITE_BUG_COMPATIBLE_20160819
    ++  "BUG_COMPATIBLE_20160819",
    ++#endif
    ++#if SQLITE_CASE_SENSITIVE_LIKE
    ++  "CASE_SENSITIVE_LIKE",
    ++#endif
    ++#if SQLITE_CHECK_PAGES
    ++  "CHECK_PAGES",
    ++#endif
    ++#if defined(__clang__) && defined(__clang_major__)
    ++  "COMPILER=clang-" CTIMEOPT_VAL(__clang_major__) "."
    ++                    CTIMEOPT_VAL(__clang_minor__) "."
    ++                    CTIMEOPT_VAL(__clang_patchlevel__),
    ++#elif defined(_MSC_VER)
    ++  "COMPILER=msvc-" CTIMEOPT_VAL(_MSC_VER),
    ++#elif defined(__GNUC__) && defined(__VERSION__)
    ++  "COMPILER=gcc-" __VERSION__,
    ++#endif
    ++#if SQLITE_COVERAGE_TEST
    ++  "COVERAGE_TEST",
    ++#endif
    ++#if SQLITE_DEBUG
    ++  "DEBUG",
    ++#endif
    ++#if SQLITE_DEFAULT_AUTOMATIC_INDEX
    ++  "DEFAULT_AUTOMATIC_INDEX",
    ++#endif
    ++#if SQLITE_DEFAULT_AUTOVACUUM
    ++  "DEFAULT_AUTOVACUUM",
    ++#endif
    ++#ifdef SQLITE_DEFAULT_CACHE_SIZE
    ++  "DEFAULT_CACHE_SIZE=" CTIMEOPT_VAL(SQLITE_DEFAULT_CACHE_SIZE),
    ++#endif
    ++#if SQLITE_DEFAULT_CKPTFULLFSYNC
    ++  "DEFAULT_CKPTFULLFSYNC",
    ++#endif
    ++#ifdef SQLITE_DEFAULT_FILE_FORMAT
    ++  "DEFAULT_FILE_FORMAT=" CTIMEOPT_VAL(SQLITE_DEFAULT_FILE_FORMAT),
    ++#endif
    ++#ifdef SQLITE_DEFAULT_FILE_PERMISSIONS
    ++  "DEFAULT_FILE_PERMISSIONS=" CTIMEOPT_VAL(SQLITE_DEFAULT_FILE_PERMISSIONS),
    ++#endif
    ++#if SQLITE_DEFAULT_FOREIGN_KEYS
    ++  "DEFAULT_FOREIGN_KEYS",
    ++#endif
    ++#ifdef SQLITE_DEFAULT_JOURNAL_SIZE_LIMIT
    ++  "DEFAULT_JOURNAL_SIZE_LIMIT=" CTIMEOPT_VAL(SQLITE_DEFAULT_JOURNAL_SIZE_LIMIT),
    ++#endif
    ++#ifdef SQLITE_DEFAULT_LOCKING_MODE
    ++  "DEFAULT_LOCKING_MODE=" CTIMEOPT_VAL(SQLITE_DEFAULT_LOCKING_MODE),
    ++#endif
    ++#ifdef SQLITE_DEFAULT_LOOKASIDE
    ++  "DEFAULT_LOOKASIDE=" CTIMEOPT_VAL(SQLITE_DEFAULT_LOOKASIDE),
    ++#endif
    ++#if SQLITE_DEFAULT_MEMSTATUS
    ++  "DEFAULT_MEMSTATUS",
    ++#endif
    ++#ifdef SQLITE_DEFAULT_MMAP_SIZE
    ++  "DEFAULT_MMAP_SIZE=" CTIMEOPT_VAL(SQLITE_DEFAULT_MMAP_SIZE),
    ++#endif
    ++#ifdef SQLITE_DEFAULT_PAGE_SIZE
    ++  "DEFAULT_PAGE_SIZE=" CTIMEOPT_VAL(SQLITE_DEFAULT_PAGE_SIZE),
    ++#endif
    ++#ifdef SQLITE_DEFAULT_PCACHE_INITSZ
    ++  "DEFAULT_PCACHE_INITSZ=" CTIMEOPT_VAL(SQLITE_DEFAULT_PCACHE_INITSZ),
    ++#endif
    ++#ifdef SQLITE_DEFAULT_PROXYDIR_PERMISSIONS
    ++  "DEFAULT_PROXYDIR_PERMISSIONS=" CTIMEOPT_VAL(SQLITE_DEFAULT_PROXYDIR_PERMISSIONS),
    ++#endif
    ++#if SQLITE_DEFAULT_RECURSIVE_TRIGGERS
    ++  "DEFAULT_RECURSIVE_TRIGGERS",
    ++#endif
    ++#ifdef SQLITE_DEFAULT_ROWEST
    ++  "DEFAULT_ROWEST=" CTIMEOPT_VAL(SQLITE_DEFAULT_ROWEST),
    ++#endif
    ++#ifdef SQLITE_DEFAULT_SECTOR_SIZE
    ++  "DEFAULT_SECTOR_SIZE=" CTIMEOPT_VAL(SQLITE_DEFAULT_SECTOR_SIZE),
    ++#endif
    ++#ifdef SQLITE_DEFAULT_SYNCHRONOUS
    ++  "DEFAULT_SYNCHRONOUS=" CTIMEOPT_VAL(SQLITE_DEFAULT_SYNCHRONOUS),
    ++#endif
    ++#ifdef SQLITE_DEFAULT_WAL_AUTOCHECKPOINT
    ++  "DEFAULT_WAL_AUTOCHECKPOINT=" CTIMEOPT_VAL(SQLITE_DEFAULT_WAL_AUTOCHECKPOINT),
    ++#endif
    ++#ifdef SQLITE_DEFAULT_WAL_SYNCHRONOUS
    ++  "DEFAULT_WAL_SYNCHRONOUS=" CTIMEOPT_VAL(SQLITE_DEFAULT_WAL_SYNCHRONOUS),
    ++#endif
    ++#ifdef SQLITE_DEFAULT_WORKER_THREADS
    ++  "DEFAULT_WORKER_THREADS=" CTIMEOPT_VAL(SQLITE_DEFAULT_WORKER_THREADS),
    ++#endif
    ++#if SQLITE_DIRECT_OVERFLOW_READ
    ++  "DIRECT_OVERFLOW_READ",
    ++#endif
    ++#if SQLITE_DISABLE_DIRSYNC
    ++  "DISABLE_DIRSYNC",
    ++#endif
    ++#if SQLITE_DISABLE_FTS3_UNICODE
    ++  "DISABLE_FTS3_UNICODE",
    ++#endif
    ++#if SQLITE_DISABLE_FTS4_DEFERRED
    ++  "DISABLE_FTS4_DEFERRED",
    ++#endif
    ++#if SQLITE_DISABLE_INTRINSIC
    ++  "DISABLE_INTRINSIC",
    ++#endif
    ++#if SQLITE_DISABLE_LFS
    ++  "DISABLE_LFS",
    ++#endif
    ++#if SQLITE_DISABLE_PAGECACHE_OVERFLOW_STATS
    ++  "DISABLE_PAGECACHE_OVERFLOW_STATS",
    ++#endif
    ++#if SQLITE_DISABLE_SKIPAHEAD_DISTINCT
    ++  "DISABLE_SKIPAHEAD_DISTINCT",
    ++#endif
    ++#ifdef SQLITE_ENABLE_8_3_NAMES
    ++  "ENABLE_8_3_NAMES=" CTIMEOPT_VAL(SQLITE_ENABLE_8_3_NAMES),
    ++#endif
    ++#if SQLITE_ENABLE_API_ARMOR
    ++  "ENABLE_API_ARMOR",
    ++#endif
    ++#if SQLITE_ENABLE_ATOMIC_WRITE
    ++  "ENABLE_ATOMIC_WRITE",
    ++#endif
    ++#if SQLITE_ENABLE_BATCH_ATOMIC_WRITE
    ++  "ENABLE_BATCH_ATOMIC_WRITE",
    ++#endif
    ++#if SQLITE_ENABLE_CEROD
    ++  "ENABLE_CEROD",
    ++#endif
    ++#if SQLITE_ENABLE_COLUMN_METADATA
    ++  "ENABLE_COLUMN_METADATA",
    ++#endif
    ++#if SQLITE_ENABLE_COLUMN_USED_MASK
    ++  "ENABLE_COLUMN_USED_MASK",
    ++#endif
    ++#if SQLITE_ENABLE_COSTMULT
    ++  "ENABLE_COSTMULT",
    ++#endif
    ++#if SQLITE_ENABLE_CURSOR_HINTS
    ++  "ENABLE_CURSOR_HINTS",
    ++#endif
    ++#if SQLITE_ENABLE_DBSTAT_VTAB
    ++  "ENABLE_DBSTAT_VTAB",
    ++#endif
    ++#if SQLITE_ENABLE_EXPENSIVE_ASSERT
    ++  "ENABLE_EXPENSIVE_ASSERT",
    ++#endif
    ++#if SQLITE_ENABLE_FTS1
    ++  "ENABLE_FTS1",
    ++#endif
    ++#if SQLITE_ENABLE_FTS2
    ++  "ENABLE_FTS2",
    ++#endif
    ++#if SQLITE_ENABLE_FTS3
    ++  "ENABLE_FTS3",
    ++#endif
    ++#if SQLITE_ENABLE_FTS3_PARENTHESIS
    ++  "ENABLE_FTS3_PARENTHESIS",
    ++#endif
    ++#if SQLITE_ENABLE_FTS3_TOKENIZER
    ++  "ENABLE_FTS3_TOKENIZER",
    ++#endif
    ++#if SQLITE_ENABLE_FTS4
    ++  "ENABLE_FTS4",
    ++#endif
    ++#if SQLITE_ENABLE_FTS5
    ++  "ENABLE_FTS5",
    ++#endif
    ++#if SQLITE_ENABLE_HIDDEN_COLUMNS
    ++  "ENABLE_HIDDEN_COLUMNS",
    ++#endif
    ++#if SQLITE_ENABLE_ICU
    ++  "ENABLE_ICU",
    ++#endif
    ++#if SQLITE_ENABLE_IOTRACE
    ++  "ENABLE_IOTRACE",
    ++#endif
    ++#if SQLITE_ENABLE_JSON1
    ++  "ENABLE_JSON1",
    ++#endif
    ++#if SQLITE_ENABLE_LOAD_EXTENSION
    ++  "ENABLE_LOAD_EXTENSION",
    ++#endif
    ++#ifdef SQLITE_ENABLE_LOCKING_STYLE
    ++  "ENABLE_LOCKING_STYLE=" CTIMEOPT_VAL(SQLITE_ENABLE_LOCKING_STYLE),
    ++#endif
    ++#if SQLITE_ENABLE_MEMORY_MANAGEMENT
    ++  "ENABLE_MEMORY_MANAGEMENT",
    ++#endif
    ++#if SQLITE_ENABLE_MEMSYS3
    ++  "ENABLE_MEMSYS3",
    ++#endif
    ++#if SQLITE_ENABLE_MEMSYS5
    ++  "ENABLE_MEMSYS5",
    ++#endif
    ++#if SQLITE_ENABLE_MULTIPLEX
    ++  "ENABLE_MULTIPLEX",
    ++#endif
    ++#if SQLITE_ENABLE_NULL_TRIM
    ++  "ENABLE_NULL_TRIM",
    ++#endif
    ++#if SQLITE_ENABLE_OVERSIZE_CELL_CHECK
    ++  "ENABLE_OVERSIZE_CELL_CHECK",
    ++#endif
    ++#if SQLITE_ENABLE_PREUPDATE_HOOK
    ++  "ENABLE_PREUPDATE_HOOK",
    ++#endif
    ++#if SQLITE_ENABLE_QPSG
    ++  "ENABLE_QPSG",
    ++#endif
    ++#if SQLITE_ENABLE_RBU
    ++  "ENABLE_RBU",
    ++#endif
    ++#if SQLITE_ENABLE_RTREE
    ++  "ENABLE_RTREE",
    ++#endif
    ++#if SQLITE_ENABLE_SELECTTRACE
    ++  "ENABLE_SELECTTRACE",
    ++#endif
    ++#if SQLITE_ENABLE_SESSION
    ++  "ENABLE_SESSION",
    ++#endif
    ++#if SQLITE_ENABLE_SNAPSHOT
    ++  "ENABLE_SNAPSHOT",
    ++#endif
    ++#if SQLITE_ENABLE_SQLLOG
    ++  "ENABLE_SQLLOG",
    ++#endif
    ++#if defined(SQLITE_ENABLE_STAT4)
    ++  "ENABLE_STAT4",
    ++#elif defined(SQLITE_ENABLE_STAT3)
    ++  "ENABLE_STAT3",
    ++#endif
    ++#if SQLITE_ENABLE_STMTVTAB
    ++  "ENABLE_STMTVTAB",
    ++#endif
    ++#if SQLITE_ENABLE_STMT_SCANSTATUS
    ++  "ENABLE_STMT_SCANSTATUS",
    ++#endif
    ++#if SQLITE_ENABLE_UNKNOWN_SQL_FUNCTION
    ++  "ENABLE_UNKNOWN_SQL_FUNCTION",
    ++#endif
    ++#if SQLITE_ENABLE_UNLOCK_NOTIFY
    ++  "ENABLE_UNLOCK_NOTIFY",
    ++#endif
    ++#if SQLITE_ENABLE_UPDATE_DELETE_LIMIT
    ++  "ENABLE_UPDATE_DELETE_LIMIT",
    ++#endif
    ++#if SQLITE_ENABLE_URI_00_ERROR
    ++  "ENABLE_URI_00_ERROR",
    ++#endif
    ++#if SQLITE_ENABLE_VFSTRACE
    ++  "ENABLE_VFSTRACE",
    ++#endif
    ++#if SQLITE_ENABLE_WHERETRACE
    ++  "ENABLE_WHERETRACE",
    ++#endif
    ++#if SQLITE_ENABLE_ZIPVFS
    ++  "ENABLE_ZIPVFS",
    ++#endif
    ++#if SQLITE_EXPLAIN_ESTIMATED_ROWS
    ++  "EXPLAIN_ESTIMATED_ROWS",
    ++#endif
    ++#if SQLITE_EXTRA_IFNULLROW
    ++  "EXTRA_IFNULLROW",
    ++#endif
    ++#ifdef SQLITE_EXTRA_INIT
    ++  "EXTRA_INIT=" CTIMEOPT_VAL(SQLITE_EXTRA_INIT),
    ++#endif
    ++#ifdef SQLITE_EXTRA_SHUTDOWN
    ++  "EXTRA_SHUTDOWN=" CTIMEOPT_VAL(SQLITE_EXTRA_SHUTDOWN),
    ++#endif
    ++#ifdef SQLITE_FTS3_MAX_EXPR_DEPTH
    ++  "FTS3_MAX_EXPR_DEPTH=" CTIMEOPT_VAL(SQLITE_FTS3_MAX_EXPR_DEPTH),
    ++#endif
    ++#if SQLITE_FTS5_ENABLE_TEST_MI
    ++  "FTS5_ENABLE_TEST_MI",
    ++#endif
    ++#if SQLITE_FTS5_NO_WITHOUT_ROWID
    ++  "FTS5_NO_WITHOUT_ROWID",
    ++#endif
    ++#if SQLITE_HAS_CODEC
    ++  "HAS_CODEC",
    ++#endif
    ++#if HAVE_ISNAN || SQLITE_HAVE_ISNAN
    ++  "HAVE_ISNAN",
    ++#endif
    ++#if SQLITE_HOMEGROWN_RECURSIVE_MUTEX
    ++  "HOMEGROWN_RECURSIVE_MUTEX",
    ++#endif
    ++#if SQLITE_IGNORE_AFP_LOCK_ERRORS
    ++  "IGNORE_AFP_LOCK_ERRORS",
    ++#endif
    ++#if SQLITE_IGNORE_FLOCK_LOCK_ERRORS
    ++  "IGNORE_FLOCK_LOCK_ERRORS",
    ++#endif
    ++#if SQLITE_INLINE_MEMCPY
    ++  "INLINE_MEMCPY",
    ++#endif
    ++#if SQLITE_INT64_TYPE
    ++  "INT64_TYPE",
    ++#endif
    ++#ifdef SQLITE_INTEGRITY_CHECK_ERROR_MAX
    ++  "INTEGRITY_CHECK_ERROR_MAX=" CTIMEOPT_VAL(SQLITE_INTEGRITY_CHECK_ERROR_MAX),
    ++#endif
    ++#if SQLITE_LIKE_DOESNT_MATCH_BLOBS
    ++  "LIKE_DOESNT_MATCH_BLOBS",
    ++#endif
    ++#if SQLITE_LOCK_TRACE
    ++  "LOCK_TRACE",
    ++#endif
    ++#if SQLITE_LOG_CACHE_SPILL
    ++  "LOG_CACHE_SPILL",
    ++#endif
    ++#ifdef SQLITE_MALLOC_SOFT_LIMIT
    ++  "MALLOC_SOFT_LIMIT=" CTIMEOPT_VAL(SQLITE_MALLOC_SOFT_LIMIT),
    ++#endif
    ++#ifdef SQLITE_MAX_ATTACHED
    ++  "MAX_ATTACHED=" CTIMEOPT_VAL(SQLITE_MAX_ATTACHED),
    ++#endif
    ++#ifdef SQLITE_MAX_COLUMN
    ++  "MAX_COLUMN=" CTIMEOPT_VAL(SQLITE_MAX_COLUMN),
    ++#endif
    ++#ifdef SQLITE_MAX_COMPOUND_SELECT
    ++  "MAX_COMPOUND_SELECT=" CTIMEOPT_VAL(SQLITE_MAX_COMPOUND_SELECT),
    ++#endif
    ++#ifdef SQLITE_MAX_DEFAULT_PAGE_SIZE
    ++  "MAX_DEFAULT_PAGE_SIZE=" CTIMEOPT_VAL(SQLITE_MAX_DEFAULT_PAGE_SIZE),
    ++#endif
    ++#ifdef SQLITE_MAX_EXPR_DEPTH
    ++  "MAX_EXPR_DEPTH=" CTIMEOPT_VAL(SQLITE_MAX_EXPR_DEPTH),
    ++#endif
    ++#ifdef SQLITE_MAX_FUNCTION_ARG
    ++  "MAX_FUNCTION_ARG=" CTIMEOPT_VAL(SQLITE_MAX_FUNCTION_ARG),
    ++#endif
    ++#ifdef SQLITE_MAX_LENGTH
    ++  "MAX_LENGTH=" CTIMEOPT_VAL(SQLITE_MAX_LENGTH),
    ++#endif
    ++#ifdef SQLITE_MAX_LIKE_PATTERN_LENGTH
    ++  "MAX_LIKE_PATTERN_LENGTH=" CTIMEOPT_VAL(SQLITE_MAX_LIKE_PATTERN_LENGTH),
    ++#endif
    ++#ifdef SQLITE_MAX_MEMORY
    ++  "MAX_MEMORY=" CTIMEOPT_VAL(SQLITE_MAX_MEMORY),
    ++#endif
    ++#ifdef SQLITE_MAX_MMAP_SIZE
    ++  "MAX_MMAP_SIZE=" CTIMEOPT_VAL(SQLITE_MAX_MMAP_SIZE),
    ++#endif
    ++#ifdef SQLITE_MAX_MMAP_SIZE_
    ++  "MAX_MMAP_SIZE_=" CTIMEOPT_VAL(SQLITE_MAX_MMAP_SIZE_),
    ++#endif
    ++#ifdef SQLITE_MAX_PAGE_COUNT
    ++  "MAX_PAGE_COUNT=" CTIMEOPT_VAL(SQLITE_MAX_PAGE_COUNT),
    ++#endif
    ++#ifdef SQLITE_MAX_PAGE_SIZE
    ++  "MAX_PAGE_SIZE=" CTIMEOPT_VAL(SQLITE_MAX_PAGE_SIZE),
    ++#endif
    ++#ifdef SQLITE_MAX_SCHEMA_RETRY
    ++  "MAX_SCHEMA_RETRY=" CTIMEOPT_VAL(SQLITE_MAX_SCHEMA_RETRY),
    ++#endif
    ++#ifdef SQLITE_MAX_SQL_LENGTH
    ++  "MAX_SQL_LENGTH=" CTIMEOPT_VAL(SQLITE_MAX_SQL_LENGTH),
    ++#endif
    ++#ifdef SQLITE_MAX_TRIGGER_DEPTH
    ++  "MAX_TRIGGER_DEPTH=" CTIMEOPT_VAL(SQLITE_MAX_TRIGGER_DEPTH),
    ++#endif
    ++#ifdef SQLITE_MAX_VARIABLE_NUMBER
    ++  "MAX_VARIABLE_NUMBER=" CTIMEOPT_VAL(SQLITE_MAX_VARIABLE_NUMBER),
    ++#endif
    ++#ifdef SQLITE_MAX_VDBE_OP
    ++  "MAX_VDBE_OP=" CTIMEOPT_VAL(SQLITE_MAX_VDBE_OP),
    ++#endif
    ++#ifdef SQLITE_MAX_WORKER_THREADS
    ++  "MAX_WORKER_THREADS=" CTIMEOPT_VAL(SQLITE_MAX_WORKER_THREADS),
    ++#endif
    ++#if SQLITE_MEMDEBUG
    ++  "MEMDEBUG",
    ++#endif
    ++#if SQLITE_MIXED_ENDIAN_64BIT_FLOAT
    ++  "MIXED_ENDIAN_64BIT_FLOAT",
    ++#endif
    ++#if SQLITE_MMAP_READWRITE
    ++  "MMAP_READWRITE",
    ++#endif
    ++#if SQLITE_MUTEX_NOOP
    ++  "MUTEX_NOOP",
    ++#endif
    ++#if SQLITE_MUTEX_NREF
    ++  "MUTEX_NREF",
    ++#endif
    ++#if SQLITE_MUTEX_OMIT
    ++  "MUTEX_OMIT",
    ++#endif
    ++#if SQLITE_MUTEX_PTHREADS
    ++  "MUTEX_PTHREADS",
    ++#endif
    ++#if SQLITE_MUTEX_W32
    ++  "MUTEX_W32",
    ++#endif
    ++#if SQLITE_NEED_ERR_NAME
    ++  "NEED_ERR_NAME",
    ++#endif
    ++#if SQLITE_NOINLINE
    ++  "NOINLINE",
    ++#endif
    ++#if SQLITE_NO_SYNC
    ++  "NO_SYNC",
    ++#endif
    ++#if SQLITE_OMIT_ALTERTABLE
    ++  "OMIT_ALTERTABLE",
    ++#endif
    ++#if SQLITE_OMIT_ANALYZE
    ++  "OMIT_ANALYZE",
    ++#endif
    ++#if SQLITE_OMIT_ATTACH
    ++  "OMIT_ATTACH",
    ++#endif
    ++#if SQLITE_OMIT_AUTHORIZATION
    ++  "OMIT_AUTHORIZATION",
    ++#endif
    ++#if SQLITE_OMIT_AUTOINCREMENT
    ++  "OMIT_AUTOINCREMENT",
    ++#endif
    ++#if SQLITE_OMIT_AUTOINIT
    ++  "OMIT_AUTOINIT",
    ++#endif
    ++#if SQLITE_OMIT_AUTOMATIC_INDEX
    ++  "OMIT_AUTOMATIC_INDEX",
    ++#endif
    ++#if SQLITE_OMIT_AUTORESET
    ++  "OMIT_AUTORESET",
    ++#endif
    ++#if SQLITE_OMIT_AUTOVACUUM
    ++  "OMIT_AUTOVACUUM",
    ++#endif
    ++#if SQLITE_OMIT_BETWEEN_OPTIMIZATION
    ++  "OMIT_BETWEEN_OPTIMIZATION",
    ++#endif
    ++#if SQLITE_OMIT_BLOB_LITERAL
    ++  "OMIT_BLOB_LITERAL",
    ++#endif
    ++#if SQLITE_OMIT_BTREECOUNT
    ++  "OMIT_BTREECOUNT",
    ++#endif
    ++#if SQLITE_OMIT_CAST
    ++  "OMIT_CAST",
    ++#endif
    ++#if SQLITE_OMIT_CHECK
    ++  "OMIT_CHECK",
    ++#endif
    ++#if SQLITE_OMIT_COMPLETE
    ++  "OMIT_COMPLETE",
    ++#endif
    ++#if SQLITE_OMIT_COMPOUND_SELECT
    ++  "OMIT_COMPOUND_SELECT",
    ++#endif
    ++#if SQLITE_OMIT_CONFLICT_CLAUSE
    ++  "OMIT_CONFLICT_CLAUSE",
    ++#endif
    ++#if SQLITE_OMIT_CTE
    ++  "OMIT_CTE",
    ++#endif
    ++#if SQLITE_OMIT_DATETIME_FUNCS
    ++  "OMIT_DATETIME_FUNCS",
    ++#endif
    ++#if SQLITE_OMIT_DECLTYPE
    ++  "OMIT_DECLTYPE",
    ++#endif
    ++#if SQLITE_OMIT_DEPRECATED
    ++  "OMIT_DEPRECATED",
    ++#endif
    ++#if SQLITE_OMIT_DISKIO
    ++  "OMIT_DISKIO",
    ++#endif
    ++#if SQLITE_OMIT_EXPLAIN
    ++  "OMIT_EXPLAIN",
    ++#endif
    ++#if SQLITE_OMIT_FLAG_PRAGMAS
    ++  "OMIT_FLAG_PRAGMAS",
    ++#endif
    ++#if SQLITE_OMIT_FLOATING_POINT
    ++  "OMIT_FLOATING_POINT",
    ++#endif
    ++#if SQLITE_OMIT_FOREIGN_KEY
    ++  "OMIT_FOREIGN_KEY",
    ++#endif
    ++#if SQLITE_OMIT_GET_TABLE
    ++  "OMIT_GET_TABLE",
    ++#endif
    ++#if SQLITE_OMIT_HEX_INTEGER
    ++  "OMIT_HEX_INTEGER",
    ++#endif
    ++#if SQLITE_OMIT_INCRBLOB
    ++  "OMIT_INCRBLOB",
    ++#endif
    ++#if SQLITE_OMIT_INTEGRITY_CHECK
    ++  "OMIT_INTEGRITY_CHECK",
    ++#endif
    ++#if SQLITE_OMIT_LIKE_OPTIMIZATION
    ++  "OMIT_LIKE_OPTIMIZATION",
    ++#endif
    ++#if SQLITE_OMIT_LOAD_EXTENSION
    ++  "OMIT_LOAD_EXTENSION",
    ++#endif
    ++#if SQLITE_OMIT_LOCALTIME
    ++  "OMIT_LOCALTIME",
    ++#endif
    ++#if SQLITE_OMIT_LOOKASIDE
    ++  "OMIT_LOOKASIDE",
    ++#endif
    ++#if SQLITE_OMIT_MEMORYDB
    ++  "OMIT_MEMORYDB",
    ++#endif
    ++#if SQLITE_OMIT_OR_OPTIMIZATION
    ++  "OMIT_OR_OPTIMIZATION",
    ++#endif
    ++#if SQLITE_OMIT_PAGER_PRAGMAS
    ++  "OMIT_PAGER_PRAGMAS",
    ++#endif
    ++#if SQLITE_OMIT_PARSER_TRACE
    ++  "OMIT_PARSER_TRACE",
    ++#endif
    ++#if SQLITE_OMIT_POPEN
    ++  "OMIT_POPEN",
    ++#endif
    ++#if SQLITE_OMIT_PRAGMA
    ++  "OMIT_PRAGMA",
    ++#endif
    ++#if SQLITE_OMIT_PROGRESS_CALLBACK
    ++  "OMIT_PROGRESS_CALLBACK",
    ++#endif
    ++#if SQLITE_OMIT_QUICKBALANCE
    ++  "OMIT_QUICKBALANCE",
    ++#endif
    ++#if SQLITE_OMIT_REINDEX
    ++  "OMIT_REINDEX",
    ++#endif
    ++#if SQLITE_OMIT_SCHEMA_PRAGMAS
    ++  "OMIT_SCHEMA_PRAGMAS",
    ++#endif
    ++#if SQLITE_OMIT_SCHEMA_VERSION_PRAGMAS
    ++  "OMIT_SCHEMA_VERSION_PRAGMAS",
    ++#endif
    ++#if SQLITE_OMIT_SHARED_CACHE
    ++  "OMIT_SHARED_CACHE",
    ++#endif
    ++#if SQLITE_OMIT_SHUTDOWN_DIRECTORIES
    ++  "OMIT_SHUTDOWN_DIRECTORIES",
    ++#endif
    ++#if SQLITE_OMIT_SUBQUERY
    ++  "OMIT_SUBQUERY",
    ++#endif
    ++#if SQLITE_OMIT_TCL_VARIABLE
    ++  "OMIT_TCL_VARIABLE",
    ++#endif
    ++#if SQLITE_OMIT_TEMPDB
    ++  "OMIT_TEMPDB",
    ++#endif
    ++#if SQLITE_OMIT_TEST_CONTROL
    ++  "OMIT_TEST_CONTROL",
    ++#endif
    ++#if SQLITE_OMIT_TRACE
    ++  "OMIT_TRACE",
    ++#endif
    ++#if SQLITE_OMIT_TRIGGER
    ++  "OMIT_TRIGGER",
    ++#endif
    ++#if SQLITE_OMIT_TRUNCATE_OPTIMIZATION
    ++  "OMIT_TRUNCATE_OPTIMIZATION",
    ++#endif
    ++#if SQLITE_OMIT_UTF16
    ++  "OMIT_UTF16",
    ++#endif
    ++#if SQLITE_OMIT_VACUUM
    ++  "OMIT_VACUUM",
    ++#endif
    ++#if SQLITE_OMIT_VIEW
    ++  "OMIT_VIEW",
    ++#endif
    ++#if SQLITE_OMIT_VIRTUALTABLE
    ++  "OMIT_VIRTUALTABLE",
    ++#endif
    ++#if SQLITE_OMIT_WAL
    ++  "OMIT_WAL",
    ++#endif
    ++#if SQLITE_OMIT_WSD
    ++  "OMIT_WSD",
    ++#endif
    ++#if SQLITE_OMIT_XFER_OPT
    ++  "OMIT_XFER_OPT",
    ++#endif
    ++#if SQLITE_PCACHE_SEPARATE_HEADER
    ++  "PCACHE_SEPARATE_HEADER",
    ++#endif
    ++#if SQLITE_PERFORMANCE_TRACE
    ++  "PERFORMANCE_TRACE",
    ++#endif
    ++#if SQLITE_POWERSAFE_OVERWRITE
    ++  "POWERSAFE_OVERWRITE",
    ++#endif
    ++#if SQLITE_PREFER_PROXY_LOCKING
    ++  "PREFER_PROXY_LOCKING",
    ++#endif
    ++#if SQLITE_PROXY_DEBUG
    ++  "PROXY_DEBUG",
    ++#endif
    ++#if SQLITE_REVERSE_UNORDERED_SELECTS
    ++  "REVERSE_UNORDERED_SELECTS",
    ++#endif
    ++#if SQLITE_RTREE_INT_ONLY
    ++  "RTREE_INT_ONLY",
    ++#endif
    ++#if SQLITE_SECURE_DELETE
    ++  "SECURE_DELETE",
    ++#endif
    ++#if SQLITE_SMALL_STACK
    ++  "SMALL_STACK",
    ++#endif
    ++#ifdef SQLITE_SORTER_PMASZ
    ++  "SORTER_PMASZ=" CTIMEOPT_VAL(SQLITE_SORTER_PMASZ),
    ++#endif
    ++#if SQLITE_SOUNDEX
    ++  "SOUNDEX",
    ++#endif
    ++#ifdef SQLITE_STAT4_SAMPLES
    ++  "STAT4_SAMPLES=" CTIMEOPT_VAL(SQLITE_STAT4_SAMPLES),
    ++#endif
    ++#ifdef SQLITE_STMTJRNL_SPILL
    ++  "STMTJRNL_SPILL=" CTIMEOPT_VAL(SQLITE_STMTJRNL_SPILL),
    ++#endif
    ++#if SQLITE_SUBSTR_COMPATIBILITY
    ++  "SUBSTR_COMPATIBILITY",
    ++#endif
    ++#if SQLITE_SYSTEM_MALLOC
    ++  "SYSTEM_MALLOC",
    ++#endif
    ++#if SQLITE_TCL
    ++  "TCL",
    ++#endif
    ++#ifdef SQLITE_TEMP_STORE
    ++  "TEMP_STORE=" CTIMEOPT_VAL(SQLITE_TEMP_STORE),
    ++#endif
    ++#if SQLITE_TEST
    ++  "TEST",
    ++#endif
    ++#if defined(SQLITE_THREADSAFE)
    ++  "THREADSAFE=" CTIMEOPT_VAL(SQLITE_THREADSAFE),
    ++#elif defined(THREADSAFE)
    ++  "THREADSAFE=" CTIMEOPT_VAL(THREADSAFE),
    ++#else
    ++  "THREADSAFE=1",
    ++#endif
    ++#if SQLITE_UNLINK_AFTER_CLOSE
    ++  "UNLINK_AFTER_CLOSE",
    ++#endif
    ++#if SQLITE_UNTESTABLE
    ++  "UNTESTABLE",
    ++#endif
    ++#if SQLITE_USER_AUTHENTICATION
    ++  "USER_AUTHENTICATION",
    ++#endif
    ++#if SQLITE_USE_ALLOCA
    ++  "USE_ALLOCA",
    ++#endif
    ++#if SQLITE_USE_FCNTL_TRACE
    ++  "USE_FCNTL_TRACE",
    ++#endif
    ++#if SQLITE_USE_URI
    ++  "USE_URI",
    ++#endif
    ++#if SQLITE_VDBE_COVERAGE
    ++  "VDBE_COVERAGE",
    ++#endif
    ++#if SQLITE_WIN32_MALLOC
    ++  "WIN32_MALLOC",
    ++#endif
    ++#if SQLITE_ZERO_MALLOC
    ++  "ZERO_MALLOC",
    ++#endif
    ++/* 
    ++** END CODE GENERATED BY tool/mkctime.tcl 
    ++*/
    ++};
    ++
    ++SQLITE_PRIVATE const char **sqlite3CompileOptions(int *pnOpt){
    ++  *pnOpt = sizeof(sqlite3azCompileOpt) / sizeof(sqlite3azCompileOpt[0]);
    ++  return (const char**)sqlite3azCompileOpt;
    ++}
    ++
    ++#endif /* SQLITE_OMIT_COMPILEOPTION_DIAGS */
    ++
    ++/************** End of ctime.c ***********************************************/
    + /************** Begin file sqliteInt.h ***************************************/
    + /*
    + ** 2001 September 15
    +@@ -37,8 +792,43 @@
    + ** Internal interface definitions for SQLite.
    + **
    + */
    +-#ifndef _SQLITEINT_H_
    +-#define _SQLITEINT_H_
    ++#ifndef SQLITEINT_H
    ++#define SQLITEINT_H
    ++
    ++/* Special Comments:
    ++**
    ++** Some comments have special meaning to the tools that measure test
    ++** coverage:
    ++**
    ++**    NO_TEST                     - The branches on this line are not
    ++**                                  measured by branch coverage.  This is
    ++**                                  used on lines of code that actually
    ++**                                  implement parts of coverage testing.
    ++**
    ++**    OPTIMIZATION-IF-TRUE        - This branch is allowed to alway be false
    ++**                                  and the correct answer is still obtained,
    ++**                                  though perhaps more slowly.
    ++**
    ++**    OPTIMIZATION-IF-FALSE       - This branch is allowed to alway be true
    ++**                                  and the correct answer is still obtained,
    ++**                                  though perhaps more slowly.
    ++**
    ++**    PREVENTS-HARMLESS-OVERREAD  - This branch prevents a buffer overread
    ++**                                  that would be harmless and undetectable
    ++**                                  if it did occur.  
    ++**
    ++** In all cases, the special comment must be enclosed in the usual
    ++** slash-asterisk...asterisk-slash comment marks, with no spaces between the 
    ++** asterisks and the comment text.
    ++*/
    ++
    ++/*
    ++** Make sure the Tcl calling convention macro is defined.  This macro is
    ++** only used by test code and Tcl integration code.
    ++*/
    ++#ifndef SQLITE_TCLAPI
    ++#  define SQLITE_TCLAPI
    ++#endif
    + 
    + /*
    + ** Include the header file used to customize the compiler options for MSVC.
    +@@ -62,8 +852,8 @@
    + **
    + ** This file contains code that is specific to MSVC.
    + */
    +-#ifndef _MSVC_H_
    +-#define _MSVC_H_
    ++#ifndef SQLITE_MSVC_H
    ++#define SQLITE_MSVC_H
    + 
    + #if defined(_MSC_VER)
    + #pragma warning(disable : 4054)
    +@@ -83,7 +873,7 @@
    + #pragma warning(disable : 4706)
    + #endif /* defined(_MSC_VER) */
    + 
    +-#endif /* _MSVC_H_ */
    ++#endif /* SQLITE_MSVC_H */
    + 
    + /************** End of msvc.h ************************************************/
    + /************** Continuing where we left off in sqliteInt.h ******************/
    +@@ -121,6 +911,9 @@
    + #else
    + /* This is not VxWorks. */
    + #define OS_VXWORKS 0
    ++#define HAVE_FCHOWN 1
    ++#define HAVE_READLINK 1
    ++#define HAVE_LSTAT 1
    + #endif /* defined(_WRS_KERNEL) */
    + 
    + /************** End of vxworks.h *********************************************/
    +@@ -158,12 +951,29 @@
    + # define _LARGEFILE_SOURCE 1
    + #endif
    + 
    +-/* What version of GCC is being used.  0 means GCC is not being used */
    +-#ifdef __GNUC__
    ++/* The GCC_VERSION and MSVC_VERSION macros are used to
    ++** conditionally include optimizations for each of these compilers.  A
    ++** value of 0 means that compiler is not being used.  The
    ++** SQLITE_DISABLE_INTRINSIC macro means do not use any compiler-specific
    ++** optimizations, and hence set all compiler macros to 0
    ++**
    ++** There was once also a CLANG_VERSION macro.  However, we learn that the
    ++** version numbers in clang are for "marketing" only and are inconsistent
    ++** and unreliable.  Fortunately, all versions of clang also recognize the
    ++** gcc version numbers and have reasonable settings for gcc version numbers,
    ++** so the GCC_VERSION macro will be set to a correct non-zero value even
    ++** when compiling with clang.
    ++*/
    ++#if defined(__GNUC__) && !defined(SQLITE_DISABLE_INTRINSIC)
    + # define GCC_VERSION (__GNUC__*1000000+__GNUC_MINOR__*1000+__GNUC_PATCHLEVEL__)
    + #else
    + # define GCC_VERSION 0
    + #endif
    ++#if defined(_MSC_VER) && !defined(SQLITE_DISABLE_INTRINSIC)
    ++# define MSVC_VERSION _MSC_VER
    ++#else
    ++# define MSVC_VERSION 0
    ++#endif
    + 
    + /* Needed for various definitions... */
    + #if defined(__GNUC__) && !defined(_GNU_SOURCE)
    +@@ -213,7 +1023,7 @@
    + /************** Include sqlite3.h in the middle of sqliteInt.h ***************/
    + /************** Begin file sqlite3.h *****************************************/
    + /*
    +-** 2001 September 15
    ++** 2001-09-15
    + **
    + ** The author disclaims copyright to this source code.  In place of
    + ** a legal notice, here is a blessing:
    +@@ -244,8 +1054,8 @@
    + ** the version number) and changes its name to "sqlite3.h" as
    + ** part of the build process.
    + */
    +-#ifndef _SQLITE3_H_
    +-#define _SQLITE3_H_
    ++#ifndef SQLITE3_H
    ++#define SQLITE3_H
    + #include <stdarg.h>     /* Needed for the definition of va_list */
    + 
    + /*
    +@@ -268,8 +1078,17 @@ extern "C" {
    + #ifndef SQLITE_CDECL
    + # define SQLITE_CDECL
    + #endif
    ++#ifndef SQLITE_APICALL
    ++# define SQLITE_APICALL
    ++#endif
    + #ifndef SQLITE_STDCALL
    +-# define SQLITE_STDCALL
    ++# define SQLITE_STDCALL SQLITE_APICALL
    ++#endif
    ++#ifndef SQLITE_CALLBACK
    ++# define SQLITE_CALLBACK
    ++#endif
    ++#ifndef SQLITE_SYSAPI
    ++# define SQLITE_SYSAPI
    + #endif
    + 
    + /*
    +@@ -313,25 +1132,28 @@ extern "C" {
    + ** be held constant and Z will be incremented or else Y will be incremented
    + ** and Z will be reset to zero.
    + **
    +-** Since version 3.6.18, SQLite source code has been stored in the
    ++** Since [version 3.6.18] ([dateof:3.6.18]), 
    ++** SQLite source code has been stored in the
    + ** <a href="http://www.fossil-scm.org/">Fossil configuration management
    + ** system</a>.  ^The SQLITE_SOURCE_ID macro evaluates to
    + ** a string which identifies a particular check-in of SQLite
    + ** within its configuration management system.  ^The SQLITE_SOURCE_ID
    +-** string contains the date and time of the check-in (UTC) and an SHA1
    +-** hash of the entire source tree.
    ++** string contains the date and time of the check-in (UTC) and a SHA1
    ++** or SHA3-256 hash of the entire source tree.  If the source code has
    ++** been edited in any way since it was last checked in, then the last
    ++** four hexadecimal digits of the hash may be modified.
    + **
    + ** See also: [sqlite3_libversion()],
    + ** [sqlite3_libversion_number()], [sqlite3_sourceid()],
    + ** [sqlite_version()] and [sqlite_source_id()].
    + */
    +-#define SQLITE_VERSION        "3.9.2"
    +-#define SQLITE_VERSION_NUMBER 3009002
    +-#define SQLITE_SOURCE_ID      "2015-11-02 18:31:45 bda77dda9697c463c3d0704014d51627fceee328"
    ++#define SQLITE_VERSION        "3.22.0"
    ++#define SQLITE_VERSION_NUMBER 3022000
    ++#define SQLITE_SOURCE_ID      "2018-12-19 01:30:22 c255889bd95bd5430dc7ced3317011ae2abb483d6c9af883af3dc7d6c2c2f234"
    + 
    + /*
    + ** CAPI3REF: Run-Time Library Version Numbers
    +-** KEYWORDS: sqlite3_version, sqlite3_sourceid
    ++** KEYWORDS: sqlite3_version sqlite3_sourceid
    + **
    + ** These interfaces provide the same information as the [SQLITE_VERSION],
    + ** [SQLITE_VERSION_NUMBER], and [SQLITE_SOURCE_ID] C preprocessor macros
    +@@ -343,7 +1165,7 @@ extern "C" {
    + **
    + ** <blockquote><pre>
    + ** assert( sqlite3_libversion_number()==SQLITE_VERSION_NUMBER );
    +-** assert( strcmp(sqlite3_sourceid(),SQLITE_SOURCE_ID)==0 );
    ++** assert( strncmp(sqlite3_sourceid(),SQLITE_SOURCE_ID,80)==0 );
    + ** assert( strcmp(sqlite3_libversion(),SQLITE_VERSION)==0 );
    + ** </pre></blockquote>)^
    + **
    +@@ -353,16 +1175,18 @@ extern "C" {
    + ** function is provided for use in DLLs since DLL users usually do not have
    + ** direct access to string constants within the DLL.  ^The
    + ** sqlite3_libversion_number() function returns an integer equal to
    +-** [SQLITE_VERSION_NUMBER].  ^The sqlite3_sourceid() function returns 
    ++** [SQLITE_VERSION_NUMBER].  ^(The sqlite3_sourceid() function returns 
    + ** a pointer to a string constant whose value is the same as the 
    +-** [SQLITE_SOURCE_ID] C preprocessor macro.
    ++** [SQLITE_SOURCE_ID] C preprocessor macro.  Except if SQLite is built
    ++** using an edited copy of [the amalgamation], then the last four characters
    ++** of the hash might be different from [SQLITE_SOURCE_ID].)^
    + **
    + ** See also: [sqlite_version()] and [sqlite_source_id()].
    + */
    + SQLITE_API const char sqlite3_version[] = SQLITE_VERSION;
    +-SQLITE_API const char *SQLITE_STDCALL sqlite3_libversion(void);
    +-SQLITE_API const char *SQLITE_STDCALL sqlite3_sourceid(void);
    +-SQLITE_API int SQLITE_STDCALL sqlite3_libversion_number(void);
    ++SQLITE_API const char *sqlite3_libversion(void);
    ++SQLITE_API const char *sqlite3_sourceid(void);
    ++SQLITE_API int sqlite3_libversion_number(void);
    + 
    + /*
    + ** CAPI3REF: Run-Time Library Compilation Options Diagnostics
    +@@ -387,8 +1211,8 @@ SQLITE_API int SQLITE_STDCALL sqlite3_libversion_number(void);
    + ** [sqlite_compileoption_get()] and the [compile_options pragma].
    + */
    + #ifndef SQLITE_OMIT_COMPILEOPTION_DIAGS
    +-SQLITE_API int SQLITE_STDCALL sqlite3_compileoption_used(const char *zOptName);
    +-SQLITE_API const char *SQLITE_STDCALL sqlite3_compileoption_get(int N);
    ++SQLITE_API int sqlite3_compileoption_used(const char *zOptName);
    ++SQLITE_API const char *sqlite3_compileoption_get(int N);
    + #endif
    + 
    + /*
    +@@ -427,7 +1251,7 @@ SQLITE_API const char *SQLITE_STDCALL sqlite3_compileoption_get(int N);
    + **
    + ** See the [threading mode] documentation for additional information.
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_threadsafe(void);
    ++SQLITE_API int sqlite3_threadsafe(void);
    + 
    + /*
    + ** CAPI3REF: Database Connection Handle
    +@@ -463,7 +1287,11 @@ typedef struct sqlite3 sqlite3;
    + */
    + #ifdef SQLITE_INT64_TYPE
    +   typedef SQLITE_INT64_TYPE sqlite_int64;
    +-  typedef unsigned SQLITE_INT64_TYPE sqlite_uint64;
    ++# ifdef SQLITE_UINT64_TYPE
    ++    typedef SQLITE_UINT64_TYPE sqlite_uint64;
    ++# else  
    ++    typedef unsigned SQLITE_INT64_TYPE sqlite_uint64;
    ++# endif
    + #elif defined(_MSC_VER) || defined(__BORLANDC__)
    +   typedef __int64 sqlite_int64;
    +   typedef unsigned __int64 sqlite_uint64;
    +@@ -524,8 +1352,8 @@ typedef sqlite_uint64 sqlite3_uint64;
    + ** ^Calling sqlite3_close() or sqlite3_close_v2() with a NULL pointer
    + ** argument is a harmless no-op.
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_close(sqlite3*);
    +-SQLITE_API int SQLITE_STDCALL sqlite3_close_v2(sqlite3*);
    ++SQLITE_API int sqlite3_close(sqlite3*);
    ++SQLITE_API int sqlite3_close_v2(sqlite3*);
    + 
    + /*
    + ** The type for a callback function.
    +@@ -561,7 +1389,7 @@ typedef int (*sqlite3_callback)(void*,int,char**, char**);
    + ** from [sqlite3_malloc()] and passed back through the 5th parameter.
    + ** To avoid memory leaks, the application should invoke [sqlite3_free()]
    + ** on error message strings returned through the 5th parameter of
    +-** of sqlite3_exec() after the error message string is no longer needed.
    ++** sqlite3_exec() after the error message string is no longer needed.
    + ** ^If the 5th parameter to sqlite3_exec() is not NULL and no errors
    + ** occur, then sqlite3_exec() sets the pointer in its 5th parameter to
    + ** NULL before returning.
    +@@ -596,7 +1424,7 @@ typedef int (*sqlite3_callback)(void*,int,char**, char**);
    + **      the 2nd parameter of sqlite3_exec() while sqlite3_exec() is running.
    + ** </ul>
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_exec(
    ++SQLITE_API int sqlite3_exec(
    +   sqlite3*,                                  /* An open database */
    +   const char *sql,                           /* SQL to be evaluated */
    +   int (*callback)(void*,int,char**,char**),  /* Callback function */
    +@@ -617,7 +1445,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_exec(
    + */
    + #define SQLITE_OK           0   /* Successful result */
    + /* beginning-of-error-codes */
    +-#define SQLITE_ERROR        1   /* SQL error or missing database */
    ++#define SQLITE_ERROR        1   /* Generic error */
    + #define SQLITE_INTERNAL     2   /* Internal logic error in SQLite */
    + #define SQLITE_PERM         3   /* Access permission denied */
    + #define SQLITE_ABORT        4   /* Callback routine requested an abort */
    +@@ -632,7 +1460,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_exec(
    + #define SQLITE_FULL        13   /* Insertion failed because database is full */
    + #define SQLITE_CANTOPEN    14   /* Unable to open the database file */
    + #define SQLITE_PROTOCOL    15   /* Database lock protocol error */
    +-#define SQLITE_EMPTY       16   /* Database is empty */
    ++#define SQLITE_EMPTY       16   /* Internal use only */
    + #define SQLITE_SCHEMA      17   /* The database schema changed */
    + #define SQLITE_TOOBIG      18   /* String or BLOB exceeds size limit */
    + #define SQLITE_CONSTRAINT  19   /* Abort due to constraint violation */
    +@@ -640,7 +1468,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_exec(
    + #define SQLITE_MISUSE      21   /* Library used incorrectly */
    + #define SQLITE_NOLFS       22   /* Uses OS features not supported on host */
    + #define SQLITE_AUTH        23   /* Authorization denied */
    +-#define SQLITE_FORMAT      24   /* Auxiliary database format error */
    ++#define SQLITE_FORMAT      24   /* Not used */
    + #define SQLITE_RANGE       25   /* 2nd parameter to sqlite3_bind out of range */
    + #define SQLITE_NOTADB      26   /* File opened that is not a database file */
    + #define SQLITE_NOTICE      27   /* Notifications from sqlite3_log() */
    +@@ -657,7 +1485,8 @@ SQLITE_API int SQLITE_STDCALL sqlite3_exec(
    + ** [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
    ++** address this, newer versions of SQLite (version 3.3.8 [dateof:3.3.8]
    ++** and later) include
    + ** support for additional result codes that provide more detailed information
    + ** about errors. These [extended result codes] are enabled or disabled
    + ** on a per database connection basis using the
    +@@ -665,6 +1494,8 @@ SQLITE_API int SQLITE_STDCALL sqlite3_exec(
    + ** the most recent error can be obtained using
    + ** [sqlite3_extended_errcode()].
    + */
    ++#define SQLITE_ERROR_MISSING_COLLSEQ   (SQLITE_ERROR | (1<<8))
    ++#define SQLITE_ERROR_RETRY             (SQLITE_ERROR | (2<<8))
    + #define SQLITE_IOERR_READ              (SQLITE_IOERR | (1<<8))
    + #define SQLITE_IOERR_SHORT_READ        (SQLITE_IOERR | (2<<8))
    + #define SQLITE_IOERR_WRITE             (SQLITE_IOERR | (3<<8))
    +@@ -692,6 +1523,10 @@ SQLITE_API int SQLITE_STDCALL sqlite3_exec(
    + #define SQLITE_IOERR_GETTEMPPATH       (SQLITE_IOERR | (25<<8))
    + #define SQLITE_IOERR_CONVPATH          (SQLITE_IOERR | (26<<8))
    + #define SQLITE_IOERR_VNODE             (SQLITE_IOERR | (27<<8))
    ++#define SQLITE_IOERR_AUTH              (SQLITE_IOERR | (28<<8))
    ++#define SQLITE_IOERR_BEGIN_ATOMIC      (SQLITE_IOERR | (29<<8))
    ++#define SQLITE_IOERR_COMMIT_ATOMIC     (SQLITE_IOERR | (30<<8))
    ++#define SQLITE_IOERR_ROLLBACK_ATOMIC   (SQLITE_IOERR | (31<<8))
    + #define SQLITE_LOCKED_SHAREDCACHE      (SQLITE_LOCKED |  (1<<8))
    + #define SQLITE_BUSY_RECOVERY           (SQLITE_BUSY   |  (1<<8))
    + #define SQLITE_BUSY_SNAPSHOT           (SQLITE_BUSY   |  (2<<8))
    +@@ -704,6 +1539,8 @@ SQLITE_API int SQLITE_STDCALL sqlite3_exec(
    + #define SQLITE_READONLY_CANTLOCK       (SQLITE_READONLY | (2<<8))
    + #define SQLITE_READONLY_ROLLBACK       (SQLITE_READONLY | (3<<8))
    + #define SQLITE_READONLY_DBMOVED        (SQLITE_READONLY | (4<<8))
    ++#define SQLITE_READONLY_CANTINIT       (SQLITE_READONLY | (5<<8))
    ++#define SQLITE_READONLY_DIRECTORY      (SQLITE_READONLY | (6<<8))
    + #define SQLITE_ABORT_ROLLBACK          (SQLITE_ABORT | (2<<8))
    + #define SQLITE_CONSTRAINT_CHECK        (SQLITE_CONSTRAINT | (1<<8))
    + #define SQLITE_CONSTRAINT_COMMITHOOK   (SQLITE_CONSTRAINT | (2<<8))
    +@@ -719,6 +1556,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_exec(
    + #define SQLITE_NOTICE_RECOVER_ROLLBACK (SQLITE_NOTICE | (2<<8))
    + #define SQLITE_WARNING_AUTOINDEX       (SQLITE_WARNING | (1<<8))
    + #define SQLITE_AUTH_USER               (SQLITE_AUTH | (1<<8))
    ++#define SQLITE_OK_LOAD_PERMANENTLY     (SQLITE_OK | (1<<8))
    + 
    + /*
    + ** CAPI3REF: Flags For File Open Operations
    +@@ -773,10 +1611,15 @@ SQLITE_API int SQLITE_STDCALL 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.  The
    ++** flag indicates 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.
    ++**
    ++** The SQLITE_IOCAP_BATCH_ATOMIC property means that the underlying
    ++** filesystem supports doing multiple write operations atomically when those
    ++** write operations are bracketed by [SQLITE_FCNTL_BEGIN_ATOMIC_WRITE] and
    ++** [SQLITE_FCNTL_COMMIT_ATOMIC_WRITE].
    + */
    + #define SQLITE_IOCAP_ATOMIC                 0x00000001
    + #define SQLITE_IOCAP_ATOMIC512              0x00000002
    +@@ -792,6 +1635,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_exec(
    + #define SQLITE_IOCAP_UNDELETABLE_WHEN_OPEN  0x00000800
    + #define SQLITE_IOCAP_POWERSAFE_OVERWRITE    0x00001000
    + #define SQLITE_IOCAP_IMMUTABLE              0x00002000
    ++#define SQLITE_IOCAP_BATCH_ATOMIC           0x00004000
    + 
    + /*
    + ** CAPI3REF: File Locking Levels
    +@@ -923,6 +1767,10 @@ struct sqlite3_file {
    + ** <li> [SQLITE_IOCAP_ATOMIC64K]
    + ** <li> [SQLITE_IOCAP_SAFE_APPEND]
    + ** <li> [SQLITE_IOCAP_SEQUENTIAL]
    ++** <li> [SQLITE_IOCAP_UNDELETABLE_WHEN_OPEN]
    ++** <li> [SQLITE_IOCAP_POWERSAFE_OVERWRITE]
    ++** <li> [SQLITE_IOCAP_IMMUTABLE]
    ++** <li> [SQLITE_IOCAP_BATCH_ATOMIC]
    + ** </ul>
    + **
    + ** The SQLITE_IOCAP_ATOMIC property means that all writes of
    +@@ -1007,8 +1855,13 @@ struct sqlite3_io_methods {
    + ** <li>[[SQLITE_FCNTL_FILE_POINTER]]
    + ** The [SQLITE_FCNTL_FILE_POINTER] opcode is used to obtain a pointer
    + ** to the [sqlite3_file] object associated with a particular database
    +-** connection.  See the [sqlite3_file_control()] documentation for
    +-** additional information.
    ++** connection.  See also [SQLITE_FCNTL_JOURNAL_POINTER].
    ++**
    ++** <li>[[SQLITE_FCNTL_JOURNAL_POINTER]]
    ++** The [SQLITE_FCNTL_JOURNAL_POINTER] opcode is used to obtain a pointer
    ++** to the [sqlite3_file] object associated with the journal file (either
    ++** the [rollback journal] or the [write-ahead log]) for a particular database
    ++** connection.  See also [SQLITE_FCNTL_FILE_POINTER].
    + **
    + ** <li>[[SQLITE_FCNTL_SYNC_OMITTED]]
    + ** No longer in use.
    +@@ -1046,7 +1899,7 @@ struct sqlite3_io_methods {
    + ** opcode allows these two values (10 retries and 25 milliseconds of delay)
    + ** to be adjusted.  The values are changed for all database connections
    + ** within the same process.  The argument is a pointer to an array of two
    +-** integers where the first integer i the new retry count and the second
    ++** integers where the first integer is the new retry count and the second
    + ** integer is the delay.  If either integer is negative, then the setting
    + ** is not changed but instead the prior value of that setting is written
    + ** into the array entry, allowing the current retry settings to be
    +@@ -1095,6 +1948,15 @@ struct sqlite3_io_methods {
    + ** pointer in case this file-control is not implemented.  This file-control
    + ** is intended for diagnostic use only.
    + **
    ++** <li>[[SQLITE_FCNTL_VFS_POINTER]]
    ++** ^The [SQLITE_FCNTL_VFS_POINTER] opcode finds a pointer to the top-level
    ++** [VFSes] currently in use.  ^(The argument X in
    ++** sqlite3_file_control(db,SQLITE_FCNTL_VFS_POINTER,X) must be
    ++** of type "[sqlite3_vfs] **".  This opcodes will set *X
    ++** to a pointer to the top-level VFS.)^
    ++** ^When there are multiple VFS shims in the stack, this opcode finds the
    ++** upper-most shim only.
    ++**
    + ** <li>[[SQLITE_FCNTL_PRAGMA]]
    + ** ^Whenever a [PRAGMA] statement is parsed, an [SQLITE_FCNTL_PRAGMA] 
    + ** file control is sent to the open [sqlite3_file] object corresponding
    +@@ -1165,6 +2027,12 @@ struct sqlite3_io_methods {
    + ** on whether or not the file has been renamed, moved, or deleted since it
    + ** was first opened.
    + **
    ++** <li>[[SQLITE_FCNTL_WIN32_GET_HANDLE]]
    ++** The [SQLITE_FCNTL_WIN32_GET_HANDLE] opcode can be used to obtain the
    ++** underlying native file handle associated with a file handle.  This file
    ++** control interprets its argument as a pointer to a native file handle and
    ++** writes the resulting value there.
    ++**
    + ** <li>[[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
    +@@ -1186,6 +2054,40 @@ struct sqlite3_io_methods {
    + ** The [SQLITE_FCNTL_RBU] opcode is implemented by the special VFS used by
    + ** the RBU extension only.  All other VFS should return SQLITE_NOTFOUND for
    + ** this opcode.  
    ++**
    ++** <li>[[SQLITE_FCNTL_BEGIN_ATOMIC_WRITE]]
    ++** If the [SQLITE_FCNTL_BEGIN_ATOMIC_WRITE] opcode returns SQLITE_OK, then
    ++** the file descriptor is placed in "batch write mode", which
    ++** means all subsequent write operations will be deferred and done
    ++** atomically at the next [SQLITE_FCNTL_COMMIT_ATOMIC_WRITE].  Systems
    ++** that do not support batch atomic writes will return SQLITE_NOTFOUND.
    ++** ^Following a successful SQLITE_FCNTL_BEGIN_ATOMIC_WRITE and prior to
    ++** the closing [SQLITE_FCNTL_COMMIT_ATOMIC_WRITE] or
    ++** [SQLITE_FCNTL_ROLLBACK_ATOMIC_WRITE], SQLite will make
    ++** no VFS interface calls on the same [sqlite3_file] file descriptor
    ++** except for calls to the xWrite method and the xFileControl method
    ++** with [SQLITE_FCNTL_SIZE_HINT].
    ++**
    ++** <li>[[SQLITE_FCNTL_COMMIT_ATOMIC_WRITE]]
    ++** The [SQLITE_FCNTL_COMMIT_ATOMIC_WRITE] opcode causes all write
    ++** operations since the previous successful call to 
    ++** [SQLITE_FCNTL_BEGIN_ATOMIC_WRITE] to be performed atomically.
    ++** This file control returns [SQLITE_OK] if and only if the writes were
    ++** all performed successfully and have been committed to persistent storage.
    ++** ^Regardless of whether or not it is successful, this file control takes
    ++** the file descriptor out of batch write mode so that all subsequent
    ++** write operations are independent.
    ++** ^SQLite will never invoke SQLITE_FCNTL_COMMIT_ATOMIC_WRITE without
    ++** a prior successful call to [SQLITE_FCNTL_BEGIN_ATOMIC_WRITE].
    ++**
    ++** <li>[[SQLITE_FCNTL_ROLLBACK_ATOMIC_WRITE]]
    ++** The [SQLITE_FCNTL_ROLLBACK_ATOMIC_WRITE] opcode causes all write
    ++** operations since the previous successful call to 
    ++** [SQLITE_FCNTL_BEGIN_ATOMIC_WRITE] to be rolled back.
    ++** ^This file control takes the file descriptor out of batch write mode
    ++** so that all subsequent write operations are independent.
    ++** ^SQLite will never invoke SQLITE_FCNTL_ROLLBACK_ATOMIC_WRITE without
    ++** a prior successful call to [SQLITE_FCNTL_BEGIN_ATOMIC_WRITE].
    + ** </ul>
    + */
    + #define SQLITE_FCNTL_LOCKSTATE               1
    +@@ -1213,6 +2115,13 @@ struct sqlite3_io_methods {
    + #define SQLITE_FCNTL_WAL_BLOCK              24
    + #define SQLITE_FCNTL_ZIPVFS                 25
    + #define SQLITE_FCNTL_RBU                    26
    ++#define SQLITE_FCNTL_VFS_POINTER            27
    ++#define SQLITE_FCNTL_JOURNAL_POINTER        28
    ++#define SQLITE_FCNTL_WIN32_GET_HANDLE       29
    ++#define SQLITE_FCNTL_PDB                    30
    ++#define SQLITE_FCNTL_BEGIN_ATOMIC_WRITE     31
    ++#define SQLITE_FCNTL_COMMIT_ATOMIC_WRITE    32
    ++#define SQLITE_FCNTL_ROLLBACK_ATOMIC_WRITE  33
    + 
    + /* deprecated names */
    + #define SQLITE_GET_LOCKPROXYFILE      SQLITE_FCNTL_GET_LOCKPROXYFILE
    +@@ -1232,6 +2141,16 @@ struct sqlite3_io_methods {
    + */
    + typedef struct sqlite3_mutex sqlite3_mutex;
    + 
    ++/*
    ++** CAPI3REF: Loadable Extension Thunk
    ++**
    ++** A pointer to the opaque sqlite3_api_routines structure is passed as
    ++** the third parameter to entry points of [loadable extensions].  This
    ++** structure must be typedefed in order to work around compiler warnings
    ++** on some platforms.
    ++*/
    ++typedef struct sqlite3_api_routines sqlite3_api_routines;
    ++
    + /*
    + ** CAPI3REF: OS Interface Object
    + **
    +@@ -1240,12 +2159,18 @@ typedef struct sqlite3_mutex sqlite3_mutex;
    + ** in the name of the object stands for "virtual file system".  See
    + ** the [VFS | VFS documentation] for further information.
    + **
    +-** The value of the iVersion field is initially 1 but may be larger in
    +-** future versions of SQLite.  Additional fields may be appended to this
    +-** object when the iVersion value is increased.  Note that the structure
    +-** of the sqlite3_vfs object changes in the transaction between
    +-** SQLite version 3.5.9 and 3.6.0 and yet the iVersion field was not
    +-** modified.
    ++** The VFS interface is sometimes extended by adding new methods onto
    ++** the end.  Each time such an extension occurs, the iVersion field
    ++** is incremented.  The iVersion value started out as 1 in
    ++** SQLite [version 3.5.0] on [dateof:3.5.0], then increased to 2
    ++** with SQLite [version 3.7.0] on [dateof:3.7.0], and then increased
    ++** to 3 with SQLite [version 3.7.6] on [dateof:3.7.6].  Additional fields
    ++** may be appended to the sqlite3_vfs object and the iVersion value
    ++** may increase again in future versions of SQLite.
    ++** Note that the structure
    ++** of the sqlite3_vfs object changes in the transition from
    ++** SQLite [version 3.5.9] to [version 3.6.0] on [dateof:3.6.0]
    ++** and yet the iVersion field was not modified.
    + **
    + ** The szOsFile field is the size of the subclassed [sqlite3_file]
    + ** structure used by this VFS.  mxPathname is the maximum length of
    +@@ -1425,7 +2350,7 @@ struct sqlite3_vfs {
    +   const char *(*xNextSystemCall)(sqlite3_vfs*, const char *zName);
    +   /*
    +   ** The methods above are in versions 1 through 3 of the sqlite_vfs object.
    +-  ** New fields may be appended in figure versions.  The iVersion
    ++  ** New fields may be appended in future versions.  The iVersion
    +   ** value will increment whenever this happens. 
    +   */
    + };
    +@@ -1567,10 +2492,10 @@ struct sqlite3_vfs {
    + ** must return [SQLITE_OK] on success and some other [error code] upon
    + ** failure.
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_initialize(void);
    +-SQLITE_API int SQLITE_STDCALL sqlite3_shutdown(void);
    +-SQLITE_API int SQLITE_STDCALL sqlite3_os_init(void);
    +-SQLITE_API int SQLITE_STDCALL sqlite3_os_end(void);
    ++SQLITE_API int sqlite3_initialize(void);
    ++SQLITE_API int sqlite3_shutdown(void);
    ++SQLITE_API int sqlite3_os_init(void);
    ++SQLITE_API int sqlite3_os_end(void);
    + 
    + /*
    + ** CAPI3REF: Configuring The SQLite Library
    +@@ -1603,7 +2528,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_os_end(void);
    + ** ^If the option is unknown or SQLite is unable to set the option
    + ** then this routine returns a non-zero [error code].
    + */
    +-SQLITE_API int SQLITE_CDECL sqlite3_config(int, ...);
    ++SQLITE_API int sqlite3_config(int, ...);
    + 
    + /*
    + ** CAPI3REF: Configure database connections
    +@@ -1622,7 +2547,7 @@ SQLITE_API int SQLITE_CDECL sqlite3_config(int, ...);
    + ** ^Calls to sqlite3_db_config() return SQLITE_OK if and only if
    + ** the call is considered successful.
    + */
    +-SQLITE_API int SQLITE_CDECL sqlite3_db_config(sqlite3*, int op, ...);
    ++SQLITE_API int sqlite3_db_config(sqlite3*, int op, ...);
    + 
    + /*
    + ** CAPI3REF: Memory Allocation Routines
    +@@ -1773,6 +2698,16 @@ struct sqlite3_mem_methods {
    + ** routines with a wrapper that simulations memory allocation failure or
    + ** tracks memory usage, for example. </dd>
    + **
    ++** [[SQLITE_CONFIG_SMALL_MALLOC]] <dt>SQLITE_CONFIG_SMALL_MALLOC</dt>
    ++** <dd> ^The SQLITE_CONFIG_SMALL_MALLOC option takes single argument of
    ++** type int, interpreted as a boolean, which if true provides a hint to
    ++** SQLite that it should avoid large memory allocations if possible.
    ++** SQLite will run faster if it is free to make large memory allocations,
    ++** but some application might prefer to run slower in exchange for
    ++** guarantees about memory fragmentation that are possible if large
    ++** allocations are avoided.  This hint is normally off.
    ++** </dd>
    ++**
    + ** [[SQLITE_CONFIG_MEMSTATUS]] <dt>SQLITE_CONFIG_MEMSTATUS</dt>
    + ** <dd> ^The SQLITE_CONFIG_MEMSTATUS option takes single argument of type int,
    + ** interpreted as a boolean, which enables or disables the collection of
    +@@ -1790,57 +2725,43 @@ struct sqlite3_mem_methods {
    + ** </dd>
    + **
    + ** [[SQLITE_CONFIG_SCRATCH]] <dt>SQLITE_CONFIG_SCRATCH</dt>
    +-** <dd> ^The SQLITE_CONFIG_SCRATCH option specifies a static memory buffer
    +-** that SQLite can use for scratch memory.  ^(There are three arguments
    +-** to SQLITE_CONFIG_SCRATCH:  A pointer an 8-byte
    +-** aligned memory buffer from which the scratch allocations will be
    +-** drawn, the size of each scratch allocation (sz),
    +-** and the maximum number of scratch allocations (N).)^
    +-** The first argument must be a pointer to an 8-byte aligned buffer
    +-** of at least sz*N bytes of memory.
    +-** ^SQLite will not use more than one scratch buffers per thread.
    +-** ^SQLite will never request a scratch buffer that is more than 6
    +-** times the database page size.
    +-** ^If SQLite needs needs additional
    +-** scratch memory beyond what is provided by this configuration option, then 
    +-** [sqlite3_malloc()] will be used to obtain the memory needed.<p>
    +-** ^When the application provides any amount of scratch memory using
    +-** SQLITE_CONFIG_SCRATCH, SQLite avoids unnecessary large
    +-** [sqlite3_malloc|heap allocations].
    +-** This can help [Robson proof|prevent memory allocation failures] due to heap
    +-** fragmentation in low-memory embedded systems.
    ++** <dd> The SQLITE_CONFIG_SCRATCH option is no longer used.
    + ** </dd>
    + **
    + ** [[SQLITE_CONFIG_PAGECACHE]] <dt>SQLITE_CONFIG_PAGECACHE</dt>
    +-** <dd> ^The SQLITE_CONFIG_PAGECACHE option specifies a static memory buffer
    ++** <dd> ^The SQLITE_CONFIG_PAGECACHE option specifies a memory pool
    + ** that SQLite can use for the database page cache with the default page
    + ** cache implementation.  
    +-** This configuration should not be used if an application-define page
    +-** cache implementation is loaded using the [SQLITE_CONFIG_PCACHE2]
    +-** configuration option.
    ++** This configuration option is a no-op if an application-define page
    ++** cache implementation is loaded using the [SQLITE_CONFIG_PCACHE2].
    + ** ^There are three arguments to SQLITE_CONFIG_PAGECACHE: A pointer to
    +-** 8-byte aligned
    +-** memory, the size of each page buffer (sz), and the number of pages (N).
    ++** 8-byte aligned memory (pMem), the size of each page cache line (sz),
    ++** and the number of cache lines (N).
    + ** The sz argument should be the size of the largest database page
    + ** (a power of two between 512 and 65536) plus some extra bytes for each
    + ** page header.  ^The number of extra bytes needed by the page header
    +-** can be determined using the [SQLITE_CONFIG_PCACHE_HDRSZ] option 
    +-** to [sqlite3_config()].
    ++** can be determined using [SQLITE_CONFIG_PCACHE_HDRSZ].
    + ** ^It is harmless, apart from the wasted memory,
    +-** for the sz parameter to be larger than necessary.  The first
    +-** argument should pointer to an 8-byte aligned block of memory that
    +-** is at least sz*N bytes of memory, otherwise subsequent behavior is
    +-** undefined.
    +-** ^SQLite will use the memory provided by the first argument to satisfy its
    +-** memory needs for the first N pages that it adds to cache.  ^If additional
    +-** page cache memory is needed beyond what is provided by this option, then
    +-** SQLite goes to [sqlite3_malloc()] for the additional storage space.</dd>
    ++** for the sz parameter to be larger than necessary.  The pMem
    ++** argument must be either a NULL pointer or a pointer to an 8-byte
    ++** aligned block of memory of at least sz*N bytes, otherwise
    ++** subsequent behavior is undefined.
    ++** ^When pMem is not NULL, SQLite will strive to use the memory provided
    ++** to satisfy page cache needs, falling back to [sqlite3_malloc()] if
    ++** a page cache line is larger than sz bytes or if all of the pMem buffer
    ++** is exhausted.
    ++** ^If pMem is NULL and N is non-zero, then each database connection
    ++** does an initial bulk allocation for page cache memory
    ++** from [sqlite3_malloc()] sufficient for N cache lines if N is positive or
    ++** of -1024*N bytes if N is negative, . ^If additional
    ++** page cache memory is needed beyond what is provided by the initial
    ++** allocation, then SQLite goes to [sqlite3_malloc()] separately for each
    ++** additional cache line. </dd>
    + **
    + ** [[SQLITE_CONFIG_HEAP]] <dt>SQLITE_CONFIG_HEAP</dt>
    + ** <dd> ^The SQLITE_CONFIG_HEAP option specifies a static memory buffer 
    + ** that SQLite will use for all of its dynamic memory allocation needs
    +-** beyond those provided for by [SQLITE_CONFIG_SCRATCH] and
    +-** [SQLITE_CONFIG_PAGECACHE].
    ++** beyond those provided for by [SQLITE_CONFIG_PAGECACHE].
    + ** ^The SQLITE_CONFIG_HEAP option is only available if SQLite is compiled
    + ** with either [SQLITE_ENABLE_MEMSYS3] or [SQLITE_ENABLE_MEMSYS5] and returns
    + ** [SQLITE_ERROR] if invoked otherwise.
    +@@ -2012,6 +2933,20 @@ struct sqlite3_mem_methods {
    + ** is enabled (using the [PRAGMA threads] command) and the amount of content
    + ** to be sorted exceeds the page size times the minimum of the
    + ** [PRAGMA cache_size] setting and this value.
    ++**
    ++** [[SQLITE_CONFIG_STMTJRNL_SPILL]]
    ++** <dt>SQLITE_CONFIG_STMTJRNL_SPILL
    ++** <dd>^The SQLITE_CONFIG_STMTJRNL_SPILL option takes a single parameter which
    ++** becomes the [statement journal] spill-to-disk threshold.  
    ++** [Statement journals] are held in memory until their size (in bytes)
    ++** exceeds this threshold, at which point they are written to disk.
    ++** Or if the threshold is -1, statement journals are always held
    ++** exclusively in memory.
    ++** Since many statement journals never become large, setting the spill
    ++** threshold to a value such as 64KiB can greatly reduce the amount of
    ++** I/O required to support statement rollback.
    ++** The default value for this setting is controlled by the
    ++** [SQLITE_STMTJRNL_SPILL] compile-time option.
    + ** </dl>
    + */
    + #define SQLITE_CONFIG_SINGLETHREAD  1  /* nil */
    +@@ -2019,7 +2954,7 @@ struct sqlite3_mem_methods {
    + #define SQLITE_CONFIG_SERIALIZED    3  /* nil */
    + #define SQLITE_CONFIG_MALLOC        4  /* sqlite3_mem_methods* */
    + #define SQLITE_CONFIG_GETMALLOC     5  /* sqlite3_mem_methods* */
    +-#define SQLITE_CONFIG_SCRATCH       6  /* void*, int sz, int N */
    ++#define SQLITE_CONFIG_SCRATCH       6  /* No longer used */
    + #define SQLITE_CONFIG_PAGECACHE     7  /* void*, int sz, int N */
    + #define SQLITE_CONFIG_HEAP          8  /* void*, int nByte, int min */
    + #define SQLITE_CONFIG_MEMSTATUS     9  /* boolean */
    +@@ -2039,6 +2974,8 @@ struct sqlite3_mem_methods {
    + #define SQLITE_CONFIG_WIN32_HEAPSIZE      23  /* int nByte */
    + #define SQLITE_CONFIG_PCACHE_HDRSZ        24  /* int *psz */
    + #define SQLITE_CONFIG_PMASZ               25  /* unsigned int szPma */
    ++#define SQLITE_CONFIG_STMTJRNL_SPILL      26  /* int nByte */
    ++#define SQLITE_CONFIG_SMALL_MALLOC        27  /* boolean */
    + 
    + /*
    + ** CAPI3REF: Database Connection Configuration Options
    +@@ -2096,12 +3033,88 @@ struct sqlite3_mem_methods {
    + ** following this call.  The second parameter may be a NULL pointer, in
    + ** which case the trigger setting is not reported back. </dd>
    + **
    ++** <dt>SQLITE_DBCONFIG_ENABLE_FTS3_TOKENIZER</dt>
    ++** <dd> ^This option is used to enable or disable the two-argument
    ++** version of the [fts3_tokenizer()] function which is part of the
    ++** [FTS3] full-text search engine extension.
    ++** There should be two additional arguments.
    ++** The first argument is an integer which is 0 to disable fts3_tokenizer() or
    ++** positive to enable fts3_tokenizer() or negative to leave the setting
    ++** unchanged.
    ++** The second parameter is a pointer to an integer into which
    ++** is written 0 or 1 to indicate whether fts3_tokenizer is disabled or enabled
    ++** following this call.  The second parameter may be a NULL pointer, in
    ++** which case the new setting is not reported back. </dd>
    ++**
    ++** <dt>SQLITE_DBCONFIG_ENABLE_LOAD_EXTENSION</dt>
    ++** <dd> ^This option is used to enable or disable the [sqlite3_load_extension()]
    ++** interface independently of the [load_extension()] SQL function.
    ++** The [sqlite3_enable_load_extension()] API enables or disables both the
    ++** C-API [sqlite3_load_extension()] and the SQL function [load_extension()].
    ++** There should be two additional arguments.
    ++** When the first argument to this interface is 1, then only the C-API is
    ++** enabled and the SQL function remains disabled.  If the first argument to
    ++** this interface is 0, then both the C-API and the SQL function are disabled.
    ++** If the first argument is -1, then no changes are made to state of either the
    ++** C-API or the SQL function.
    ++** The second parameter is a pointer to an integer into which
    ++** is written 0 or 1 to indicate whether [sqlite3_load_extension()] interface
    ++** is disabled or enabled following this call.  The second parameter may
    ++** be a NULL pointer, in which case the new setting is not reported back.
    ++** </dd>
    ++**
    ++** <dt>SQLITE_DBCONFIG_MAINDBNAME</dt>
    ++** <dd> ^This option is used to change the name of the "main" database
    ++** schema.  ^The sole argument is a pointer to a constant UTF8 string
    ++** which will become the new schema name in place of "main".  ^SQLite
    ++** does not make a copy of the new main schema name string, so the application
    ++** must ensure that the argument passed into this DBCONFIG option is unchanged
    ++** until after the database connection closes.
    ++** </dd>
    ++**
    ++** <dt>SQLITE_DBCONFIG_NO_CKPT_ON_CLOSE</dt>
    ++** <dd> Usually, when a database in wal mode is closed or detached from a 
    ++** database handle, SQLite checks if this will mean that there are now no 
    ++** connections at all to the database. If so, it performs a checkpoint 
    ++** operation before closing the connection. This option may be used to
    ++** override this behaviour. The first parameter passed to this operation
    ++** is an integer - non-zero to disable checkpoints-on-close, or zero (the
    ++** default) to enable them. The second parameter is a pointer to an integer
    ++** into which is written 0 or 1 to indicate whether checkpoints-on-close
    ++** have been disabled - 0 if they are not disabled, 1 if they are.
    ++** </dd>
    ++** <dt>SQLITE_DBCONFIG_ENABLE_QPSG</dt>
    ++** <dd>^(The SQLITE_DBCONFIG_ENABLE_QPSG option activates or deactivates
    ++** the [query planner stability guarantee] (QPSG).  When the QPSG is active,
    ++** a single SQL query statement will always use the same algorithm regardless
    ++** of values of [bound parameters].)^ The QPSG disables some query optimizations
    ++** that look at the values of bound parameters, which can make some queries
    ++** slower.  But the QPSG has the advantage of more predictable behavior.  With
    ++** the QPSG active, SQLite will always use the same query plan in the field as
    ++** was used during testing in the lab.
    ++** </dd>
    ++** <dt>SQLITE_DBCONFIG_TRIGGER_EQP</dt>
    ++** <dd> By default, the output of EXPLAIN QUERY PLAN commands does not 
    ++** include output for any operations performed by trigger programs. This
    ++** option is used to set or clear (the default) a flag that governs this
    ++** behavior. The first parameter passed to this operation is an integer -
    ++** non-zero to enable output for trigger programs, or zero to disable it.
    ++** The second parameter is a pointer to an integer into which is written 
    ++** 0 or 1 to indicate whether output-for-triggers has been disabled - 0 if 
    ++** it is not disabled, 1 if it is.  
    ++** </dd>
    + ** </dl>
    + */
    +-#define SQLITE_DBCONFIG_LOOKASIDE       1001  /* void* int int */
    +-#define SQLITE_DBCONFIG_ENABLE_FKEY     1002  /* int int* */
    +-#define SQLITE_DBCONFIG_ENABLE_TRIGGER  1003  /* int int* */
    +-
    ++#define SQLITE_DBCONFIG_MAINDBNAME            1000 /* const char* */
    ++#define SQLITE_DBCONFIG_LOOKASIDE             1001 /* void* int int */
    ++#define SQLITE_DBCONFIG_ENABLE_FKEY           1002 /* int int* */
    ++#define SQLITE_DBCONFIG_ENABLE_TRIGGER        1003 /* int int* */
    ++#define SQLITE_DBCONFIG_ENABLE_FTS3_TOKENIZER 1004 /* int int* */
    ++#define SQLITE_DBCONFIG_ENABLE_LOAD_EXTENSION 1005 /* int int* */
    ++#define SQLITE_DBCONFIG_NO_CKPT_ON_CLOSE      1006 /* int int* */
    ++#define SQLITE_DBCONFIG_ENABLE_QPSG           1007 /* int int* */
    ++#define SQLITE_DBCONFIG_TRIGGER_EQP           1008 /* int int* */
    ++#define SQLITE_DBCONFIG_MAX                   1008 /* Largest DBCONFIG */
    + 
    + /*
    + ** CAPI3REF: Enable Or Disable Extended Result Codes
    +@@ -2111,7 +3124,7 @@ struct sqlite3_mem_methods {
    + ** [extended result codes] feature of SQLite. ^The extended result
    + ** codes are disabled by default for historical compatibility.
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_extended_result_codes(sqlite3*, int onoff);
    ++SQLITE_API int sqlite3_extended_result_codes(sqlite3*, int onoff);
    + 
    + /*
    + ** CAPI3REF: Last Insert Rowid
    +@@ -2125,20 +3138,30 @@ SQLITE_API int SQLITE_STDCALL sqlite3_extended_result_codes(sqlite3*, int onoff)
    + ** the table has a column of type [INTEGER PRIMARY KEY] then that column
    + ** is another alias for the rowid.
    + **
    +-** ^The sqlite3_last_insert_rowid(D) interface returns the [rowid] of the 
    +-** most recent successful [INSERT] into a rowid table or [virtual table]
    +-** on database connection D.
    +-** ^Inserts into [WITHOUT ROWID] tables are not recorded.
    +-** ^If no successful [INSERT]s into rowid tables
    +-** have ever occurred on the database connection D, 
    +-** then sqlite3_last_insert_rowid(D) returns zero.
    +-**
    +-** ^(If an [INSERT] occurs within a trigger or within a [virtual table]
    +-** method, then this routine will return the [rowid] of the inserted
    +-** row as long as the trigger or virtual table method is running.
    +-** But once the trigger or virtual table method ends, the value returned 
    +-** by this routine reverts to what it was before the trigger or virtual
    +-** table method began.)^
    ++** ^The sqlite3_last_insert_rowid(D) interface usually returns the [rowid] of
    ++** the most recent successful [INSERT] into a rowid table or [virtual table]
    ++** on database connection D. ^Inserts into [WITHOUT ROWID] tables are not
    ++** recorded. ^If no successful [INSERT]s into rowid tables have ever occurred 
    ++** on the database connection D, then sqlite3_last_insert_rowid(D) returns 
    ++** zero.
    ++**
    ++** As well as being set automatically as rows are inserted into database
    ++** tables, the value returned by this function may be set explicitly by
    ++** [sqlite3_set_last_insert_rowid()]
    ++**
    ++** Some virtual table implementations may INSERT rows into rowid tables as
    ++** part of committing a transaction (e.g. to flush data accumulated in memory
    ++** to disk). In this case subsequent calls to this function return the rowid
    ++** associated with these internal INSERT operations, which leads to 
    ++** unintuitive results. Virtual table implementations that do write to rowid
    ++** tables in this way can avoid this problem by restoring the original 
    ++** rowid value using [sqlite3_set_last_insert_rowid()] before returning 
    ++** control to the user.
    ++**
    ++** ^(If an [INSERT] occurs within a trigger then this routine will 
    ++** return the [rowid] of the inserted row as long as the trigger is 
    ++** running. Once the trigger program ends, the value returned 
    ++** by this routine reverts to what it was before the trigger was fired.)^
    + **
    + ** ^An [INSERT] that fails due to a constraint violation is not a
    + ** successful [INSERT] and does not change the value returned by this
    +@@ -2163,7 +3186,17 @@ SQLITE_API int SQLITE_STDCALL sqlite3_extended_result_codes(sqlite3*, int onoff)
    + ** unpredictable and might not equal either the old or the new
    + ** last insert [rowid].
    + */
    +-SQLITE_API sqlite3_int64 SQLITE_STDCALL sqlite3_last_insert_rowid(sqlite3*);
    ++SQLITE_API sqlite3_int64 sqlite3_last_insert_rowid(sqlite3*);
    ++
    ++/*
    ++** CAPI3REF: Set the Last Insert Rowid value.
    ++** METHOD: sqlite3
    ++**
    ++** The sqlite3_set_last_insert_rowid(D, R) method allows the application to
    ++** set the value returned by calling sqlite3_last_insert_rowid(D) to R 
    ++** without inserting a row into the database.
    ++*/
    ++SQLITE_API void sqlite3_set_last_insert_rowid(sqlite3*,sqlite3_int64);
    + 
    + /*
    + ** CAPI3REF: Count The Number Of Rows Modified
    +@@ -2216,7 +3249,7 @@ SQLITE_API sqlite3_int64 SQLITE_STDCALL sqlite3_last_insert_rowid(sqlite3*);
    + ** while [sqlite3_changes()] is running then the value returned
    + ** is unpredictable and not meaningful.
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_changes(sqlite3*);
    ++SQLITE_API int sqlite3_changes(sqlite3*);
    + 
    + /*
    + ** CAPI3REF: Total Number Of Rows Modified
    +@@ -2240,7 +3273,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_changes(sqlite3*);
    + ** while [sqlite3_total_changes()] is running then the value
    + ** returned is unpredictable and not meaningful.
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_total_changes(sqlite3*);
    ++SQLITE_API int sqlite3_total_changes(sqlite3*);
    + 
    + /*
    + ** CAPI3REF: Interrupt A Long-Running Query
    +@@ -2276,11 +3309,8 @@ SQLITE_API int SQLITE_STDCALL sqlite3_total_changes(sqlite3*);
    + ** ^A call to sqlite3_interrupt(D) that occurs when there are no running
    + ** SQL statements is a no-op and has no effect on SQL statements
    + ** that are started after the sqlite3_interrupt() call returns.
    +-**
    +-** If the database connection closes while [sqlite3_interrupt()]
    +-** is running then bad things will likely happen.
    + */
    +-SQLITE_API void SQLITE_STDCALL sqlite3_interrupt(sqlite3*);
    ++SQLITE_API void sqlite3_interrupt(sqlite3*);
    + 
    + /*
    + ** CAPI3REF: Determine If An SQL Statement Is Complete
    +@@ -2315,8 +3345,8 @@ SQLITE_API void SQLITE_STDCALL sqlite3_interrupt(sqlite3*);
    + ** The input to [sqlite3_complete16()] must be a zero-terminated
    + ** UTF-16 string in native byte order.
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_complete(const char *sql);
    +-SQLITE_API int SQLITE_STDCALL sqlite3_complete16(const void *sql);
    ++SQLITE_API int sqlite3_complete(const char *sql);
    ++SQLITE_API int sqlite3_complete16(const void *sql);
    + 
    + /*
    + ** CAPI3REF: Register A Callback To Handle SQLITE_BUSY Errors
    +@@ -2377,7 +3407,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_complete16(const void *sql);
    + ** A busy handler must not close the database connection
    + ** or [prepared statement] that invoked the busy handler.
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_busy_handler(sqlite3*, int(*)(void*,int), void*);
    ++SQLITE_API int sqlite3_busy_handler(sqlite3*,int(*)(void*,int),void*);
    + 
    + /*
    + ** CAPI3REF: Set A Busy Timeout
    +@@ -2400,7 +3430,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_busy_handler(sqlite3*, int(*)(void*,int),
    + **
    + ** See also:  [PRAGMA busy_timeout]
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_busy_timeout(sqlite3*, int ms);
    ++SQLITE_API int sqlite3_busy_timeout(sqlite3*, int ms);
    + 
    + /*
    + ** CAPI3REF: Convenience Routines For Running Queries
    +@@ -2475,7 +3505,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_busy_timeout(sqlite3*, int ms);
    + ** reflected in subsequent calls to [sqlite3_errcode()] or
    + ** [sqlite3_errmsg()].
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_get_table(
    ++SQLITE_API int sqlite3_get_table(
    +   sqlite3 *db,          /* An open database */
    +   const char *zSql,     /* SQL to be evaluated */
    +   char ***pazResult,    /* Results of the query */
    +@@ -2483,7 +3513,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_get_table(
    +   int *pnColumn,        /* Number of result columns written here */
    +   char **pzErrmsg       /* Error msg written here */
    + );
    +-SQLITE_API void SQLITE_STDCALL sqlite3_free_table(char **result);
    ++SQLITE_API void sqlite3_free_table(char **result);
    + 
    + /*
    + ** CAPI3REF: Formatted String Printing Functions
    +@@ -2589,10 +3619,10 @@ SQLITE_API void SQLITE_STDCALL sqlite3_free_table(char **result);
    + ** addition that after the string has been read and copied into
    + ** the result, [sqlite3_free()] is called on the input string.)^
    + */
    +-SQLITE_API char *SQLITE_CDECL sqlite3_mprintf(const char*,...);
    +-SQLITE_API char *SQLITE_STDCALL sqlite3_vmprintf(const char*, va_list);
    +-SQLITE_API char *SQLITE_CDECL sqlite3_snprintf(int,char*,const char*, ...);
    +-SQLITE_API char *SQLITE_STDCALL sqlite3_vsnprintf(int,char*,const char*, va_list);
    ++SQLITE_API char *sqlite3_mprintf(const char*,...);
    ++SQLITE_API char *sqlite3_vmprintf(const char*, va_list);
    ++SQLITE_API char *sqlite3_snprintf(int,char*,const char*, ...);
    ++SQLITE_API char *sqlite3_vsnprintf(int,char*,const char*, va_list);
    + 
    + /*
    + ** CAPI3REF: Memory Allocation Subsystem
    +@@ -2682,12 +3712,12 @@ SQLITE_API char *SQLITE_STDCALL sqlite3_vsnprintf(int,char*,const char*, va_list
    + ** a block of memory after it has been released using
    + ** [sqlite3_free()] or [sqlite3_realloc()].
    + */
    +-SQLITE_API void *SQLITE_STDCALL sqlite3_malloc(int);
    +-SQLITE_API void *SQLITE_STDCALL sqlite3_malloc64(sqlite3_uint64);
    +-SQLITE_API void *SQLITE_STDCALL sqlite3_realloc(void*, int);
    +-SQLITE_API void *SQLITE_STDCALL sqlite3_realloc64(void*, sqlite3_uint64);
    +-SQLITE_API void SQLITE_STDCALL sqlite3_free(void*);
    +-SQLITE_API sqlite3_uint64 SQLITE_STDCALL sqlite3_msize(void*);
    ++SQLITE_API void *sqlite3_malloc(int);
    ++SQLITE_API void *sqlite3_malloc64(sqlite3_uint64);
    ++SQLITE_API void *sqlite3_realloc(void*, int);
    ++SQLITE_API void *sqlite3_realloc64(void*, sqlite3_uint64);
    ++SQLITE_API void sqlite3_free(void*);
    ++SQLITE_API sqlite3_uint64 sqlite3_msize(void*);
    + 
    + /*
    + ** CAPI3REF: Memory Allocator Statistics
    +@@ -2712,8 +3742,8 @@ SQLITE_API sqlite3_uint64 SQLITE_STDCALL sqlite3_msize(void*);
    + ** by [sqlite3_memory_highwater(1)] is the high-water mark
    + ** prior to the reset.
    + */
    +-SQLITE_API sqlite3_int64 SQLITE_STDCALL sqlite3_memory_used(void);
    +-SQLITE_API sqlite3_int64 SQLITE_STDCALL sqlite3_memory_highwater(int resetFlag);
    ++SQLITE_API sqlite3_int64 sqlite3_memory_used(void);
    ++SQLITE_API sqlite3_int64 sqlite3_memory_highwater(int resetFlag);
    + 
    + /*
    + ** CAPI3REF: Pseudo-Random Number Generator
    +@@ -2736,17 +3766,19 @@ SQLITE_API sqlite3_int64 SQLITE_STDCALL sqlite3_memory_highwater(int resetFlag);
    + ** internally and without recourse to the [sqlite3_vfs] xRandomness
    + ** method.
    + */
    +-SQLITE_API void SQLITE_STDCALL sqlite3_randomness(int N, void *P);
    ++SQLITE_API void sqlite3_randomness(int N, void *P);
    + 
    + /*
    + ** CAPI3REF: Compile-Time Authorization Callbacks
    + ** METHOD: sqlite3
    ++** KEYWORDS: {authorizer callback}
    + **
    + ** ^This routine registers an authorizer callback with a particular
    + ** [database connection], supplied in the first argument.
    + ** ^The authorizer callback is invoked as SQL statements are being compiled
    + ** by [sqlite3_prepare()] or its variants [sqlite3_prepare_v2()],
    +-** [sqlite3_prepare16()] and [sqlite3_prepare16_v2()].  ^At various
    ++** [sqlite3_prepare_v3()], [sqlite3_prepare16()], [sqlite3_prepare16_v2()],
    ++** and [sqlite3_prepare16_v3()].  ^At various
    + ** points during the compilation process, as logic is being created
    + ** to perform various actions, the authorizer callback is invoked to
    + ** see if those actions are allowed.  ^The authorizer callback should
    +@@ -2768,8 +3800,10 @@ SQLITE_API void SQLITE_STDCALL sqlite3_randomness(int N, void *P);
    + ** parameter to the sqlite3_set_authorizer() interface. ^The second parameter
    + ** to the callback is an integer [SQLITE_COPY | action code] that specifies
    + ** the particular action to be authorized. ^The third through sixth parameters
    +-** to the callback are zero-terminated strings that contain additional
    +-** details about the action to be authorized.
    ++** to the callback are either NULL pointers or zero-terminated strings
    ++** that contain additional details about the action to be authorized.
    ++** Applications must always be prepared to encounter a NULL pointer in any
    ++** of the third through the sixth parameters of the authorization callback.
    + **
    + ** ^If the action code is [SQLITE_READ]
    + ** and the callback returns [SQLITE_IGNORE] then the
    +@@ -2778,6 +3812,10 @@ SQLITE_API void SQLITE_STDCALL sqlite3_randomness(int N, void *P);
    + ** been read if [SQLITE_OK] had been returned.  The [SQLITE_IGNORE]
    + ** return can be used to deny an untrusted user access to individual
    + ** columns of a table.
    ++** ^When a table is referenced by a [SELECT] but no column values are
    ++** extracted from that table (for example in a query like
    ++** "SELECT count(*) FROM tab") then the [SQLITE_READ] authorizer callback
    ++** is invoked once for that table with a column name that is an empty string.
    + ** ^If the action code is [SQLITE_DELETE] and the callback returns
    + ** [SQLITE_IGNORE] then the [DELETE] operation proceeds but the
    + ** [truncate optimization] is disabled and all rows are deleted individually.
    +@@ -2819,7 +3857,7 @@ SQLITE_API void SQLITE_STDCALL sqlite3_randomness(int N, void *P);
    + ** as stated in the previous paragraph, sqlite3_step() invokes
    + ** sqlite3_prepare_v2() to reprepare a statement after a schema change.
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_set_authorizer(
    ++SQLITE_API int sqlite3_set_authorizer(
    +   sqlite3*,
    +   int (*xAuth)(void*,int,const char*,const char*,const char*,const char*),
    +   void *pUserData
    +@@ -2899,6 +3937,9 @@ SQLITE_API int SQLITE_STDCALL sqlite3_set_authorizer(
    + ** CAPI3REF: Tracing And Profiling Functions
    + ** METHOD: sqlite3
    + **
    ++** These routines are deprecated. Use the [sqlite3_trace_v2()] interface
    ++** instead of the routines described here.
    ++**
    + ** These routines register callback functions that can be used for
    + ** tracing and profiling the execution of SQL statements.
    + **
    +@@ -2924,10 +3965,104 @@ SQLITE_API int SQLITE_STDCALL sqlite3_set_authorizer(
    + ** sqlite3_profile() function is considered experimental and is
    + ** subject to change in future versions of SQLite.
    + */
    +-SQLITE_API void *SQLITE_STDCALL sqlite3_trace(sqlite3*, void(*xTrace)(void*,const char*), void*);
    +-SQLITE_API SQLITE_EXPERIMENTAL void *SQLITE_STDCALL sqlite3_profile(sqlite3*,
    ++SQLITE_API SQLITE_DEPRECATED void *sqlite3_trace(sqlite3*,
    ++   void(*xTrace)(void*,const char*), void*);
    ++SQLITE_API SQLITE_DEPRECATED void *sqlite3_profile(sqlite3*,
    +    void(*xProfile)(void*,const char*,sqlite3_uint64), void*);
    + 
    ++/*
    ++** CAPI3REF: SQL Trace Event Codes
    ++** KEYWORDS: SQLITE_TRACE
    ++**
    ++** These constants identify classes of events that can be monitored
    ++** using the [sqlite3_trace_v2()] tracing logic.  The M argument
    ++** to [sqlite3_trace_v2(D,M,X,P)] is an OR-ed combination of one or more of
    ++** the following constants.  ^The first argument to the trace callback
    ++** is one of the following constants.
    ++**
    ++** New tracing constants may be added in future releases.
    ++**
    ++** ^A trace callback has four arguments: xCallback(T,C,P,X).
    ++** ^The T argument is one of the integer type codes above.
    ++** ^The C argument is a copy of the context pointer passed in as the
    ++** fourth argument to [sqlite3_trace_v2()].
    ++** The P and X arguments are pointers whose meanings depend on T.
    ++**
    ++** <dl>
    ++** [[SQLITE_TRACE_STMT]] <dt>SQLITE_TRACE_STMT</dt>
    ++** <dd>^An SQLITE_TRACE_STMT callback is invoked when a prepared statement
    ++** first begins running and possibly at other times during the
    ++** execution of the prepared statement, such as at the start of each
    ++** trigger subprogram. ^The P argument is a pointer to the
    ++** [prepared statement]. ^The X argument is a pointer to a string which
    ++** is the unexpanded SQL text of the prepared statement or an SQL comment 
    ++** that indicates the invocation of a trigger.  ^The callback can compute
    ++** the same text that would have been returned by the legacy [sqlite3_trace()]
    ++** interface by using the X argument when X begins with "--" and invoking
    ++** [sqlite3_expanded_sql(P)] otherwise.
    ++**
    ++** [[SQLITE_TRACE_PROFILE]] <dt>SQLITE_TRACE_PROFILE</dt>
    ++** <dd>^An SQLITE_TRACE_PROFILE callback provides approximately the same
    ++** information as is provided by the [sqlite3_profile()] callback.
    ++** ^The P argument is a pointer to the [prepared statement] and the
    ++** X argument points to a 64-bit integer which is the estimated of
    ++** the number of nanosecond that the prepared statement took to run.
    ++** ^The SQLITE_TRACE_PROFILE callback is invoked when the statement finishes.
    ++**
    ++** [[SQLITE_TRACE_ROW]] <dt>SQLITE_TRACE_ROW</dt>
    ++** <dd>^An SQLITE_TRACE_ROW callback is invoked whenever a prepared
    ++** statement generates a single row of result.  
    ++** ^The P argument is a pointer to the [prepared statement] and the
    ++** X argument is unused.
    ++**
    ++** [[SQLITE_TRACE_CLOSE]] <dt>SQLITE_TRACE_CLOSE</dt>
    ++** <dd>^An SQLITE_TRACE_CLOSE callback is invoked when a database
    ++** connection closes.
    ++** ^The P argument is a pointer to the [database connection] object
    ++** and the X argument is unused.
    ++** </dl>
    ++*/
    ++#define SQLITE_TRACE_STMT       0x01
    ++#define SQLITE_TRACE_PROFILE    0x02
    ++#define SQLITE_TRACE_ROW        0x04
    ++#define SQLITE_TRACE_CLOSE      0x08
    ++
    ++/*
    ++** CAPI3REF: SQL Trace Hook
    ++** METHOD: sqlite3
    ++**
    ++** ^The sqlite3_trace_v2(D,M,X,P) interface registers a trace callback
    ++** function X against [database connection] D, using property mask M
    ++** and context pointer P.  ^If the X callback is
    ++** NULL or if the M mask is zero, then tracing is disabled.  The
    ++** M argument should be the bitwise OR-ed combination of
    ++** zero or more [SQLITE_TRACE] constants.
    ++**
    ++** ^Each call to either sqlite3_trace() or sqlite3_trace_v2() overrides 
    ++** (cancels) any prior calls to sqlite3_trace() or sqlite3_trace_v2().
    ++**
    ++** ^The X callback is invoked whenever any of the events identified by 
    ++** mask M occur.  ^The integer return value from the callback is currently
    ++** ignored, though this may change in future releases.  Callback
    ++** implementations should return zero to ensure future compatibility.
    ++**
    ++** ^A trace callback is invoked with four arguments: callback(T,C,P,X).
    ++** ^The T argument is one of the [SQLITE_TRACE]
    ++** constants to indicate why the callback was invoked.
    ++** ^The C argument is a copy of the context pointer.
    ++** The P and X arguments are pointers whose meanings depend on T.
    ++**
    ++** The sqlite3_trace_v2() interface is intended to replace the legacy
    ++** interfaces [sqlite3_trace()] and [sqlite3_profile()], both of which
    ++** are deprecated.
    ++*/
    ++SQLITE_API int sqlite3_trace_v2(
    ++  sqlite3*,
    ++  unsigned uMask,
    ++  int(*xCallback)(unsigned,void*,void*,void*),
    ++  void *pCtx
    ++);
    ++
    + /*
    + ** CAPI3REF: Query Progress Callbacks
    + ** METHOD: sqlite3
    +@@ -2960,7 +4095,7 @@ SQLITE_API SQLITE_EXPERIMENTAL void *SQLITE_STDCALL sqlite3_profile(sqlite3*,
    + ** database connections for the meaning of "modify" in this paragraph.
    + **
    + */
    +-SQLITE_API void SQLITE_STDCALL sqlite3_progress_handler(sqlite3*, int, int(*)(void*), void*);
    ++SQLITE_API void sqlite3_progress_handler(sqlite3*, int, int(*)(void*), void*);
    + 
    + /*
    + ** CAPI3REF: Opening A New Database Connection
    +@@ -3050,10 +4185,10 @@ SQLITE_API void SQLITE_STDCALL sqlite3_progress_handler(sqlite3*, int, int(*)(vo
    + ** ^If [URI filename] interpretation is enabled, and the filename argument
    + ** begins with "file:", then the filename is interpreted as a URI. ^URI
    + ** filename interpretation is enabled if the [SQLITE_OPEN_URI] flag is
    +-** set in the fourth argument to sqlite3_open_v2(), or if it has
    ++** set in the third argument to sqlite3_open_v2(), or if it has
    + ** been enabled globally using the [SQLITE_CONFIG_URI] option with the
    + ** [sqlite3_config()] method or by the [SQLITE_USE_URI] compile-time option.
    +-** As of SQLite version 3.7.7, URI filename interpretation is turned off
    ++** URI filename interpretation is turned off
    + ** by default, but future releases of SQLite might enable URI filename
    + ** interpretation by default.  See "[URI filenames]" for additional
    + ** information.
    +@@ -3189,15 +4324,15 @@ SQLITE_API void SQLITE_STDCALL sqlite3_progress_handler(sqlite3*, int, int(*)(vo
    + **
    + ** See also: [sqlite3_temp_directory]
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_open(
    ++SQLITE_API int sqlite3_open(
    +   const char *filename,   /* Database filename (UTF-8) */
    +   sqlite3 **ppDb          /* OUT: SQLite db handle */
    + );
    +-SQLITE_API int SQLITE_STDCALL sqlite3_open16(
    ++SQLITE_API int sqlite3_open16(
    +   const void *filename,   /* Database filename (UTF-16) */
    +   sqlite3 **ppDb          /* OUT: SQLite db handle */
    + );
    +-SQLITE_API int SQLITE_STDCALL sqlite3_open_v2(
    ++SQLITE_API int sqlite3_open_v2(
    +   const char *filename,   /* Database filename (UTF-8) */
    +   sqlite3 **ppDb,         /* OUT: SQLite db handle */
    +   int flags,              /* Flags */
    +@@ -3243,9 +4378,9 @@ SQLITE_API int SQLITE_STDCALL sqlite3_open_v2(
    + ** VFS method, then the behavior of this routine is undefined and probably
    + ** undesirable.
    + */
    +-SQLITE_API const char *SQLITE_STDCALL sqlite3_uri_parameter(const char *zFilename, const char *zParam);
    +-SQLITE_API int SQLITE_STDCALL sqlite3_uri_boolean(const char *zFile, const char *zParam, int bDefault);
    +-SQLITE_API sqlite3_int64 SQLITE_STDCALL sqlite3_uri_int64(const char*, const char*, sqlite3_int64);
    ++SQLITE_API const char *sqlite3_uri_parameter(const char *zFilename, const char *zParam);
    ++SQLITE_API int sqlite3_uri_boolean(const char *zFile, const char *zParam, int bDefault);
    ++SQLITE_API sqlite3_int64 sqlite3_uri_int64(const char*, const char*, sqlite3_int64);
    + 
    + 
    + /*
    +@@ -3289,11 +4424,11 @@ SQLITE_API sqlite3_int64 SQLITE_STDCALL sqlite3_uri_int64(const char*, const cha
    + ** was invoked incorrectly by the application.  In that case, the
    + ** error code and message may or may not be set.
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_errcode(sqlite3 *db);
    +-SQLITE_API int SQLITE_STDCALL sqlite3_extended_errcode(sqlite3 *db);
    +-SQLITE_API const char *SQLITE_STDCALL sqlite3_errmsg(sqlite3*);
    +-SQLITE_API const void *SQLITE_STDCALL sqlite3_errmsg16(sqlite3*);
    +-SQLITE_API const char *SQLITE_STDCALL sqlite3_errstr(int);
    ++SQLITE_API int sqlite3_errcode(sqlite3 *db);
    ++SQLITE_API int sqlite3_extended_errcode(sqlite3 *db);
    ++SQLITE_API const char *sqlite3_errmsg(sqlite3*);
    ++SQLITE_API const void *sqlite3_errmsg16(sqlite3*);
    ++SQLITE_API const char *sqlite3_errstr(int);
    + 
    + /*
    + ** CAPI3REF: Prepared Statement Object
    +@@ -3361,7 +4496,7 @@ typedef struct sqlite3_stmt sqlite3_stmt;
    + **
    + ** New run-time limit categories may be added in future releases.
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_limit(sqlite3*, int id, int newVal);
    ++SQLITE_API int sqlite3_limit(sqlite3*, int id, int newVal);
    + 
    + /*
    + ** CAPI3REF: Run-Time Limit Categories
    +@@ -3392,9 +4527,9 @@ SQLITE_API int SQLITE_STDCALL sqlite3_limit(sqlite3*, int id, int newVal);
    + **
    + ** [[SQLITE_LIMIT_VDBE_OP]] ^(<dt>SQLITE_LIMIT_VDBE_OP</dt>
    + ** <dd>The maximum number of instructions in a virtual machine program
    +-** used to implement an SQL statement.  This limit is not currently
    +-** enforced, though that might be added in some future release of
    +-** SQLite.</dd>)^
    ++** used to implement an SQL statement.  If [sqlite3_prepare_v2()] or
    ++** the equivalent tries to allocate space for more than this many opcodes
    ++** in a single prepared statement, an SQLITE_NOMEM error is returned.</dd>)^
    + **
    + ** [[SQLITE_LIMIT_FUNCTION_ARG]] ^(<dt>SQLITE_LIMIT_FUNCTION_ARG</dt>
    + ** <dd>The maximum number of arguments on a function.</dd>)^
    +@@ -3432,23 +4567,59 @@ SQLITE_API int SQLITE_STDCALL sqlite3_limit(sqlite3*, int id, int newVal);
    + #define SQLITE_LIMIT_TRIGGER_DEPTH            10
    + #define SQLITE_LIMIT_WORKER_THREADS           11
    + 
    ++/*
    ++** CAPI3REF: Prepare Flags
    ++**
    ++** These constants define various flags that can be passed into
    ++** "prepFlags" parameter of the [sqlite3_prepare_v3()] and
    ++** [sqlite3_prepare16_v3()] interfaces.
    ++**
    ++** New flags may be added in future releases of SQLite.
    ++**
    ++** <dl>
    ++** [[SQLITE_PREPARE_PERSISTENT]] ^(<dt>SQLITE_PREPARE_PERSISTENT</dt>
    ++** <dd>The SQLITE_PREPARE_PERSISTENT flag is a hint to the query planner
    ++** that the prepared statement will be retained for a long time and
    ++** probably reused many times.)^ ^Without this flag, [sqlite3_prepare_v3()]
    ++** and [sqlite3_prepare16_v3()] assume that the prepared statement will 
    ++** be used just once or at most a few times and then destroyed using
    ++** [sqlite3_finalize()] relatively soon. The current implementation acts
    ++** on this hint by avoiding the use of [lookaside memory] so as not to
    ++** deplete the limited store of lookaside memory. Future versions of
    ++** SQLite may act on this hint differently.
    ++** </dl>
    ++*/
    ++#define SQLITE_PREPARE_PERSISTENT              0x01
    ++
    + /*
    + ** CAPI3REF: Compiling An SQL Statement
    + ** KEYWORDS: {SQL statement compiler}
    + ** METHOD: sqlite3
    + ** CONSTRUCTOR: sqlite3_stmt
    + **
    +-** To execute an SQL query, it must first be compiled into a byte-code
    +-** program using one of these routines.
    ++** To execute an SQL statement, it must first be compiled into a byte-code
    ++** program using one of these routines.  Or, in other words, these routines
    ++** are constructors for the [prepared statement] object.
    ++**
    ++** The preferred routine to use is [sqlite3_prepare_v2()].  The
    ++** [sqlite3_prepare()] interface is legacy and should be avoided.
    ++** [sqlite3_prepare_v3()] has an extra "prepFlags" option that is used
    ++** for special purposes.
    ++**
    ++** The use of the UTF-8 interfaces is preferred, as SQLite currently
    ++** does all parsing using UTF-8.  The UTF-16 interfaces are provided
    ++** as a convenience.  The UTF-16 interfaces work by converting the
    ++** input text into UTF-8, then invoking the corresponding UTF-8 interface.
    + **
    + ** The first argument, "db", is a [database connection] obtained from a
    + ** prior successful call to [sqlite3_open()], [sqlite3_open_v2()] or
    + ** [sqlite3_open16()].  The database connection must not have been closed.
    + **
    + ** The second argument, "zSql", is the statement to be compiled, encoded
    +-** as either UTF-8 or UTF-16.  The sqlite3_prepare() and sqlite3_prepare_v2()
    +-** interfaces use UTF-8, and sqlite3_prepare16() and sqlite3_prepare16_v2()
    +-** use UTF-16.
    ++** as either UTF-8 or UTF-16.  The sqlite3_prepare(), sqlite3_prepare_v2(),
    ++** and sqlite3_prepare_v3()
    ++** interfaces use UTF-8, and sqlite3_prepare16(), sqlite3_prepare16_v2(),
    ++** and sqlite3_prepare16_v3() use UTF-16.
    + **
    + ** ^If the nByte argument is negative, then zSql is read up to the
    + ** first zero terminator. ^If nByte is positive, then it is the
    +@@ -3475,10 +4646,11 @@ SQLITE_API int SQLITE_STDCALL sqlite3_limit(sqlite3*, int id, int newVal);
    + ** ^On success, the sqlite3_prepare() family of routines return [SQLITE_OK];
    + ** otherwise an [error code] is returned.
    + **
    +-** The sqlite3_prepare_v2() and sqlite3_prepare16_v2() interfaces are
    +-** recommended for all new programs. The two older interfaces are retained
    +-** for backwards compatibility, but their use is discouraged.
    +-** ^In the "v2" interfaces, the prepared statement
    ++** The sqlite3_prepare_v2(), sqlite3_prepare_v3(), sqlite3_prepare16_v2(),
    ++** and sqlite3_prepare16_v3() interfaces are recommended for all new programs.
    ++** The older interfaces (sqlite3_prepare() and sqlite3_prepare16())
    ++** are retained for backwards compatibility, but their use is discouraged.
    ++** ^In the "vX" interfaces, the prepared statement
    + ** that is returned (the [sqlite3_stmt] object) contains a copy of the
    + ** original SQL text. This causes the [sqlite3_step()] interface to
    + ** behave differently in three ways:
    +@@ -3511,46 +4683,93 @@ SQLITE_API int SQLITE_STDCALL sqlite3_limit(sqlite3*, int id, int newVal);
    + ** or [GLOB] operator or if the parameter is compared to an indexed column
    + ** and the [SQLITE_ENABLE_STAT3] compile-time option is enabled.
    + ** </li>
    ++**
    ++** <p>^sqlite3_prepare_v3() differs from sqlite3_prepare_v2() only in having
    ++** the extra prepFlags parameter, which is a bit array consisting of zero or
    ++** more of the [SQLITE_PREPARE_PERSISTENT|SQLITE_PREPARE_*] flags.  ^The
    ++** sqlite3_prepare_v2() interface works exactly the same as
    ++** sqlite3_prepare_v3() with a zero prepFlags parameter.
    + ** </ol>
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_prepare(
    ++SQLITE_API int sqlite3_prepare(
    ++  sqlite3 *db,            /* Database handle */
    ++  const char *zSql,       /* SQL statement, UTF-8 encoded */
    ++  int nByte,              /* Maximum length of zSql in bytes. */
    ++  sqlite3_stmt **ppStmt,  /* OUT: Statement handle */
    ++  const char **pzTail     /* OUT: Pointer to unused portion of zSql */
    ++);
    ++SQLITE_API int sqlite3_prepare_v2(
    +   sqlite3 *db,            /* Database handle */
    +   const char *zSql,       /* SQL statement, UTF-8 encoded */
    +   int nByte,              /* Maximum length of zSql in bytes. */
    +   sqlite3_stmt **ppStmt,  /* OUT: Statement handle */
    +   const char **pzTail     /* OUT: Pointer to unused portion of zSql */
    + );
    +-SQLITE_API int SQLITE_STDCALL sqlite3_prepare_v2(
    ++SQLITE_API int sqlite3_prepare_v3(
    +   sqlite3 *db,            /* Database handle */
    +   const char *zSql,       /* SQL statement, UTF-8 encoded */
    +   int nByte,              /* Maximum length of zSql in bytes. */
    ++  unsigned int prepFlags, /* Zero or more SQLITE_PREPARE_ flags */
    +   sqlite3_stmt **ppStmt,  /* OUT: Statement handle */
    +   const char **pzTail     /* OUT: Pointer to unused portion of zSql */
    + );
    +-SQLITE_API int SQLITE_STDCALL sqlite3_prepare16(
    ++SQLITE_API int sqlite3_prepare16(
    +   sqlite3 *db,            /* Database handle */
    +   const void *zSql,       /* SQL statement, UTF-16 encoded */
    +   int nByte,              /* Maximum length of zSql in bytes. */
    +   sqlite3_stmt **ppStmt,  /* OUT: Statement handle */
    +   const void **pzTail     /* OUT: Pointer to unused portion of zSql */
    + );
    +-SQLITE_API int SQLITE_STDCALL sqlite3_prepare16_v2(
    ++SQLITE_API int sqlite3_prepare16_v2(
    +   sqlite3 *db,            /* Database handle */
    +   const void *zSql,       /* SQL statement, UTF-16 encoded */
    +   int nByte,              /* Maximum length of zSql in bytes. */
    +   sqlite3_stmt **ppStmt,  /* OUT: Statement handle */
    +   const void **pzTail     /* OUT: Pointer to unused portion of zSql */
    + );
    ++SQLITE_API int sqlite3_prepare16_v3(
    ++  sqlite3 *db,            /* Database handle */
    ++  const void *zSql,       /* SQL statement, UTF-16 encoded */
    ++  int nByte,              /* Maximum length of zSql in bytes. */
    ++  unsigned int prepFlags, /* Zero or more SQLITE_PREPARE_ flags */
    ++  sqlite3_stmt **ppStmt,  /* OUT: Statement handle */
    ++  const void **pzTail     /* OUT: Pointer to unused portion of zSql */
    ++);
    + 
    + /*
    + ** CAPI3REF: Retrieving Statement SQL
    + ** METHOD: sqlite3_stmt
    + **
    +-** ^This interface can be used to retrieve a saved copy of the original
    +-** SQL text used to create a [prepared statement] if that statement was
    +-** compiled using either [sqlite3_prepare_v2()] or [sqlite3_prepare16_v2()].
    ++** ^The sqlite3_sql(P) interface returns a pointer to a copy of the UTF-8
    ++** SQL text used to create [prepared statement] P if P was
    ++** created by [sqlite3_prepare_v2()], [sqlite3_prepare_v3()],
    ++** [sqlite3_prepare16_v2()], or [sqlite3_prepare16_v3()].
    ++** ^The sqlite3_expanded_sql(P) interface returns a pointer to a UTF-8
    ++** string containing the SQL text of prepared statement P with
    ++** [bound parameters] expanded.
    ++**
    ++** ^(For example, if a prepared statement is created using the SQL
    ++** text "SELECT $abc,:xyz" and if parameter $abc is bound to integer 2345
    ++** and parameter :xyz is unbound, then sqlite3_sql() will return
    ++** the original string, "SELECT $abc,:xyz" but sqlite3_expanded_sql()
    ++** will return "SELECT 2345,NULL".)^
    ++**
    ++** ^The sqlite3_expanded_sql() interface returns NULL if insufficient memory
    ++** is available to hold the result, or if the result would exceed the
    ++** the maximum string length determined by the [SQLITE_LIMIT_LENGTH].
    ++**
    ++** ^The [SQLITE_TRACE_SIZE_LIMIT] compile-time option limits the size of
    ++** bound parameter expansions.  ^The [SQLITE_OMIT_TRACE] compile-time
    ++** option causes sqlite3_expanded_sql() to always return NULL.
    ++**
    ++** ^The string returned by sqlite3_sql(P) is managed by SQLite and is
    ++** automatically freed when the prepared statement is finalized.
    ++** ^The string returned by sqlite3_expanded_sql(P), on the other hand,
    ++** is obtained from [sqlite3_malloc()] and must be free by the application
    ++** by passing it to [sqlite3_free()].
    + */
    +-SQLITE_API const char *SQLITE_STDCALL sqlite3_sql(sqlite3_stmt *pStmt);
    ++SQLITE_API const char *sqlite3_sql(sqlite3_stmt *pStmt);
    ++SQLITE_API char *sqlite3_expanded_sql(sqlite3_stmt *pStmt);
    + 
    + /*
    + ** CAPI3REF: Determine If An SQL Statement Writes The Database
    +@@ -3581,8 +4800,12 @@ SQLITE_API const char *SQLITE_STDCALL sqlite3_sql(sqlite3_stmt *pStmt);
    + ** sqlite3_stmt_readonly() to return true since, while those statements
    + ** change the configuration of a database connection, they do not make 
    + ** changes to the content of the database files on disk.
    ++** ^The sqlite3_stmt_readonly() interface returns true for [BEGIN] since
    ++** [BEGIN] merely sets internal flags, but the [BEGIN|BEGIN IMMEDIATE] and
    ++** [BEGIN|BEGIN EXCLUSIVE] commands do touch the database and so
    ++** sqlite3_stmt_readonly() returns false for those commands.
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_stmt_readonly(sqlite3_stmt *pStmt);
    ++SQLITE_API int sqlite3_stmt_readonly(sqlite3_stmt *pStmt);
    + 
    + /*
    + ** CAPI3REF: Determine If A Prepared Statement Has Been Reset
    +@@ -3603,7 +4826,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_stmt_readonly(sqlite3_stmt *pStmt);
    + ** for example, in diagnostic routines to search for prepared 
    + ** statements that are holding a transaction open.
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_stmt_busy(sqlite3_stmt*);
    ++SQLITE_API int sqlite3_stmt_busy(sqlite3_stmt*);
    + 
    + /*
    + ** CAPI3REF: Dynamically Typed Value Object
    +@@ -3639,12 +4862,13 @@ SQLITE_API int SQLITE_STDCALL sqlite3_stmt_busy(sqlite3_stmt*);
    + ** implementation of [application-defined SQL functions] are protected.
    + ** ^The sqlite3_value object returned by
    + ** [sqlite3_column_value()] is unprotected.
    +-** Unprotected sqlite3_value objects may only be used with
    +-** [sqlite3_result_value()] and [sqlite3_bind_value()].
    ++** Unprotected sqlite3_value objects may only be used as arguments
    ++** to [sqlite3_result_value()], [sqlite3_bind_value()], and
    ++** [sqlite3_value_dup()].
    + ** The [sqlite3_value_blob | sqlite3_value_type()] family of
    + ** interfaces require protected sqlite3_value objects.
    + */
    +-typedef struct Mem sqlite3_value;
    ++typedef struct sqlite3_value sqlite3_value;
    + 
    + /*
    + ** CAPI3REF: SQL Function Context Object
    +@@ -3746,6 +4970,15 @@ typedef struct sqlite3_context sqlite3_context;
    + ** [sqlite3_blob_open | incremental BLOB I/O] routines.
    + ** ^A negative value for the zeroblob results in a zero-length BLOB.
    + **
    ++** ^The sqlite3_bind_pointer(S,I,P,T,D) routine causes the I-th parameter in
    ++** [prepared statement] S to have an SQL value of NULL, but to also be
    ++** associated with the pointer P of type T.  ^D is either a NULL pointer or
    ++** a pointer to a destructor function for P. ^SQLite will invoke the
    ++** destructor D with a single argument of P when it is finished using
    ++** P.  The T parameter should be a static string, preferably a string
    ++** literal. The sqlite3_bind_pointer() routine is part of the
    ++** [pointer passing interface] added for SQLite 3.20.0.
    ++**
    + ** ^If any of the sqlite3_bind_*() routines are called with a NULL pointer
    + ** for the [prepared statement] or with a prepared statement for which
    + ** [sqlite3_step()] has been called more recently than [sqlite3_reset()],
    +@@ -3767,20 +5000,21 @@ typedef struct sqlite3_context sqlite3_context;
    + ** See also: [sqlite3_bind_parameter_count()],
    + ** [sqlite3_bind_parameter_name()], and [sqlite3_bind_parameter_index()].
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_bind_blob(sqlite3_stmt*, int, const void*, int n, void(*)(void*));
    +-SQLITE_API int SQLITE_STDCALL sqlite3_bind_blob64(sqlite3_stmt*, int, const void*, sqlite3_uint64,
    ++SQLITE_API int sqlite3_bind_blob(sqlite3_stmt*, int, const void*, int n, void(*)(void*));
    ++SQLITE_API int sqlite3_bind_blob64(sqlite3_stmt*, int, const void*, sqlite3_uint64,
    +                         void(*)(void*));
    +-SQLITE_API int SQLITE_STDCALL sqlite3_bind_double(sqlite3_stmt*, int, double);
    +-SQLITE_API int SQLITE_STDCALL sqlite3_bind_int(sqlite3_stmt*, int, int);
    +-SQLITE_API int SQLITE_STDCALL sqlite3_bind_int64(sqlite3_stmt*, int, sqlite3_int64);
    +-SQLITE_API int SQLITE_STDCALL sqlite3_bind_null(sqlite3_stmt*, int);
    +-SQLITE_API int SQLITE_STDCALL sqlite3_bind_text(sqlite3_stmt*,int,const char*,int,void(*)(void*));
    +-SQLITE_API int SQLITE_STDCALL sqlite3_bind_text16(sqlite3_stmt*, int, const void*, int, void(*)(void*));
    +-SQLITE_API int SQLITE_STDCALL sqlite3_bind_text64(sqlite3_stmt*, int, const char*, sqlite3_uint64,
    ++SQLITE_API int sqlite3_bind_double(sqlite3_stmt*, int, double);
    ++SQLITE_API int sqlite3_bind_int(sqlite3_stmt*, int, int);
    ++SQLITE_API int sqlite3_bind_int64(sqlite3_stmt*, int, sqlite3_int64);
    ++SQLITE_API int sqlite3_bind_null(sqlite3_stmt*, int);
    ++SQLITE_API int sqlite3_bind_text(sqlite3_stmt*,int,const char*,int,void(*)(void*));
    ++SQLITE_API int sqlite3_bind_text16(sqlite3_stmt*, int, const void*, int, void(*)(void*));
    ++SQLITE_API int sqlite3_bind_text64(sqlite3_stmt*, int, const char*, sqlite3_uint64,
    +                          void(*)(void*), unsigned char encoding);
    +-SQLITE_API int SQLITE_STDCALL sqlite3_bind_value(sqlite3_stmt*, int, const sqlite3_value*);
    +-SQLITE_API int SQLITE_STDCALL sqlite3_bind_zeroblob(sqlite3_stmt*, int, int n);
    +-SQLITE_API int SQLITE_STDCALL sqlite3_bind_zeroblob64(sqlite3_stmt*, int, sqlite3_uint64);
    ++SQLITE_API int sqlite3_bind_value(sqlite3_stmt*, int, const sqlite3_value*);
    ++SQLITE_API int sqlite3_bind_pointer(sqlite3_stmt*, int, void*, const char*,void(*)(void*));
    ++SQLITE_API int sqlite3_bind_zeroblob(sqlite3_stmt*, int, int n);
    ++SQLITE_API int sqlite3_bind_zeroblob64(sqlite3_stmt*, int, sqlite3_uint64);
    + 
    + /*
    + ** CAPI3REF: Number Of SQL Parameters
    +@@ -3801,7 +5035,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_bind_zeroblob64(sqlite3_stmt*, int, sqlite
    + ** [sqlite3_bind_parameter_name()], and
    + ** [sqlite3_bind_parameter_index()].
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_bind_parameter_count(sqlite3_stmt*);
    ++SQLITE_API int sqlite3_bind_parameter_count(sqlite3_stmt*);
    + 
    + /*
    + ** CAPI3REF: Name Of A Host Parameter
    +@@ -3822,14 +5056,14 @@ SQLITE_API int SQLITE_STDCALL sqlite3_bind_parameter_count(sqlite3_stmt*);
    + ** ^If the value N is out of range or if the N-th parameter is
    + ** nameless, then NULL is returned.  ^The returned string is
    + ** always in UTF-8 encoding even if the named parameter was
    +-** originally specified as UTF-16 in [sqlite3_prepare16()] or
    +-** [sqlite3_prepare16_v2()].
    ++** originally specified as UTF-16 in [sqlite3_prepare16()],
    ++** [sqlite3_prepare16_v2()], or [sqlite3_prepare16_v3()].
    + **
    + ** See also: [sqlite3_bind_blob|sqlite3_bind()],
    + ** [sqlite3_bind_parameter_count()], and
    + ** [sqlite3_bind_parameter_index()].
    + */
    +-SQLITE_API const char *SQLITE_STDCALL sqlite3_bind_parameter_name(sqlite3_stmt*, int);
    ++SQLITE_API const char *sqlite3_bind_parameter_name(sqlite3_stmt*, int);
    + 
    + /*
    + ** CAPI3REF: Index Of A Parameter With A Given Name
    +@@ -3840,13 +5074,14 @@ SQLITE_API const char *SQLITE_STDCALL sqlite3_bind_parameter_name(sqlite3_stmt*,
    + ** parameter to [sqlite3_bind_blob|sqlite3_bind()].  ^A zero
    + ** is returned if no matching parameter is found.  ^The parameter
    + ** name must be given in UTF-8 even if the original statement
    +-** was prepared from UTF-16 text using [sqlite3_prepare16_v2()].
    ++** was prepared from UTF-16 text using [sqlite3_prepare16_v2()] or
    ++** [sqlite3_prepare16_v3()].
    + **
    + ** See also: [sqlite3_bind_blob|sqlite3_bind()],
    + ** [sqlite3_bind_parameter_count()], and
    + ** [sqlite3_bind_parameter_name()].
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_bind_parameter_index(sqlite3_stmt*, const char *zName);
    ++SQLITE_API int sqlite3_bind_parameter_index(sqlite3_stmt*, const char *zName);
    + 
    + /*
    + ** CAPI3REF: Reset All Bindings On A Prepared Statement
    +@@ -3856,19 +5091,23 @@ SQLITE_API int SQLITE_STDCALL sqlite3_bind_parameter_index(sqlite3_stmt*, const
    + ** the [sqlite3_bind_blob | bindings] on a [prepared statement].
    + ** ^Use this routine to reset all host parameters to NULL.
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_clear_bindings(sqlite3_stmt*);
    ++SQLITE_API int sqlite3_clear_bindings(sqlite3_stmt*);
    + 
    + /*
    + ** CAPI3REF: Number Of Columns In A Result Set
    + ** METHOD: sqlite3_stmt
    + **
    + ** ^Return the number of columns in the result set returned by the
    +-** [prepared statement]. ^This routine returns 0 if pStmt is an SQL
    +-** statement that does not return data (for example an [UPDATE]).
    ++** [prepared statement]. ^If this routine returns 0, that means the 
    ++** [prepared statement] returns no data (for example an [UPDATE]).
    ++** ^However, just because this routine returns a positive number does not
    ++** mean that one or more rows of data will be returned.  ^A SELECT statement
    ++** will always have a positive sqlite3_column_count() but depending on the
    ++** WHERE clause constraints and the table content, it might return no rows.
    + **
    + ** See also: [sqlite3_data_count()]
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_column_count(sqlite3_stmt *pStmt);
    ++SQLITE_API int sqlite3_column_count(sqlite3_stmt *pStmt);
    + 
    + /*
    + ** CAPI3REF: Column Names In A Result Set
    +@@ -3897,8 +5136,8 @@ SQLITE_API int SQLITE_STDCALL sqlite3_column_count(sqlite3_stmt *pStmt);
    + ** then the name of the column is unspecified and may change from
    + ** one release of SQLite to the next.
    + */
    +-SQLITE_API const char *SQLITE_STDCALL sqlite3_column_name(sqlite3_stmt*, int N);
    +-SQLITE_API const void *SQLITE_STDCALL sqlite3_column_name16(sqlite3_stmt*, int N);
    ++SQLITE_API const char *sqlite3_column_name(sqlite3_stmt*, int N);
    ++SQLITE_API const void *sqlite3_column_name16(sqlite3_stmt*, int N);
    + 
    + /*
    + ** CAPI3REF: Source Of Data In A Query Result
    +@@ -3946,12 +5185,12 @@ SQLITE_API const void *SQLITE_STDCALL sqlite3_column_name16(sqlite3_stmt*, int N
    + ** for the same [prepared statement] and result column
    + ** at the same time then the results are undefined.
    + */
    +-SQLITE_API const char *SQLITE_STDCALL sqlite3_column_database_name(sqlite3_stmt*,int);
    +-SQLITE_API const void *SQLITE_STDCALL sqlite3_column_database_name16(sqlite3_stmt*,int);
    +-SQLITE_API const char *SQLITE_STDCALL sqlite3_column_table_name(sqlite3_stmt*,int);
    +-SQLITE_API const void *SQLITE_STDCALL sqlite3_column_table_name16(sqlite3_stmt*,int);
    +-SQLITE_API const char *SQLITE_STDCALL sqlite3_column_origin_name(sqlite3_stmt*,int);
    +-SQLITE_API const void *SQLITE_STDCALL sqlite3_column_origin_name16(sqlite3_stmt*,int);
    ++SQLITE_API const char *sqlite3_column_database_name(sqlite3_stmt*,int);
    ++SQLITE_API const void *sqlite3_column_database_name16(sqlite3_stmt*,int);
    ++SQLITE_API const char *sqlite3_column_table_name(sqlite3_stmt*,int);
    ++SQLITE_API const void *sqlite3_column_table_name16(sqlite3_stmt*,int);
    ++SQLITE_API const char *sqlite3_column_origin_name(sqlite3_stmt*,int);
    ++SQLITE_API const void *sqlite3_column_origin_name16(sqlite3_stmt*,int);
    + 
    + /*
    + ** CAPI3REF: Declared Datatype Of A Query Result
    +@@ -3983,23 +5222,25 @@ SQLITE_API const void *SQLITE_STDCALL sqlite3_column_origin_name16(sqlite3_stmt*
    + ** is associated with individual values, not with the containers
    + ** used to hold those values.
    + */
    +-SQLITE_API const char *SQLITE_STDCALL sqlite3_column_decltype(sqlite3_stmt*,int);
    +-SQLITE_API const void *SQLITE_STDCALL sqlite3_column_decltype16(sqlite3_stmt*,int);
    ++SQLITE_API const char *sqlite3_column_decltype(sqlite3_stmt*,int);
    ++SQLITE_API const void *sqlite3_column_decltype16(sqlite3_stmt*,int);
    + 
    + /*
    + ** CAPI3REF: Evaluate An SQL Statement
    + ** METHOD: sqlite3_stmt
    + **
    +-** After a [prepared statement] has been prepared using either
    +-** [sqlite3_prepare_v2()] or [sqlite3_prepare16_v2()] or one of the legacy
    ++** After a [prepared statement] has been prepared using any of
    ++** [sqlite3_prepare_v2()], [sqlite3_prepare_v3()], [sqlite3_prepare16_v2()],
    ++** or [sqlite3_prepare16_v3()] or one of the legacy
    + ** interfaces [sqlite3_prepare()] or [sqlite3_prepare16()], this function
    + ** must be called one or more times to evaluate the statement.
    + **
    + ** The details of the behavior of the sqlite3_step() interface depend
    +-** on whether the statement was prepared using the newer "v2" interface
    +-** [sqlite3_prepare_v2()] and [sqlite3_prepare16_v2()] or the older legacy
    +-** interface [sqlite3_prepare()] and [sqlite3_prepare16()].  The use of the
    +-** new "v2" interface is recommended for new applications but the legacy
    ++** on whether the statement was prepared using the newer "vX" interfaces
    ++** [sqlite3_prepare_v3()], [sqlite3_prepare_v2()], [sqlite3_prepare16_v3()],
    ++** [sqlite3_prepare16_v2()] or the older legacy
    ++** interfaces [sqlite3_prepare()] and [sqlite3_prepare16()].  The use of the
    ++** new "vX" interface is recommended for new applications but the legacy
    + ** interface will continue to be supported.
    + **
    + ** ^In the legacy interface, the return value will be either [SQLITE_BUSY],
    +@@ -4045,7 +5286,8 @@ SQLITE_API const void *SQLITE_STDCALL sqlite3_column_decltype16(sqlite3_stmt*,in
    + ** other than [SQLITE_ROW] before any subsequent invocation of
    + ** sqlite3_step().  Failure to reset the prepared statement using 
    + ** [sqlite3_reset()] would result in an [SQLITE_MISUSE] return from
    +-** sqlite3_step().  But after version 3.6.23.1, sqlite3_step() began
    ++** sqlite3_step().  But after [version 3.6.23.1] ([dateof:3.6.23.1],
    ++** sqlite3_step() began
    + ** calling [sqlite3_reset()] automatically in this circumstance rather
    + ** than returning [SQLITE_MISUSE].  This is not considered a compatibility
    + ** break because any application that ever receives an SQLITE_MISUSE error
    +@@ -4059,12 +5301,13 @@ SQLITE_API const void *SQLITE_STDCALL sqlite3_column_decltype16(sqlite3_stmt*,in
    + ** specific [error codes] that better describes the error.
    + ** We admit that this is a goofy design.  The problem has been fixed
    + ** with the "v2" interface.  If you prepare all of your SQL statements
    +-** using either [sqlite3_prepare_v2()] or [sqlite3_prepare16_v2()] instead
    ++** using [sqlite3_prepare_v3()] or [sqlite3_prepare_v2()]
    ++** or [sqlite3_prepare16_v2()] or [sqlite3_prepare16_v3()] instead
    + ** of the legacy [sqlite3_prepare()] and [sqlite3_prepare16()] interfaces,
    + ** then the more specific [error codes] are returned directly
    +-** by sqlite3_step().  The use of the "v2" interface is recommended.
    ++** by sqlite3_step().  The use of the "vX" interfaces is recommended.
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_step(sqlite3_stmt*);
    ++SQLITE_API int sqlite3_step(sqlite3_stmt*);
    + 
    + /*
    + ** CAPI3REF: Number of columns in a result set
    +@@ -4085,7 +5328,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_step(sqlite3_stmt*);
    + **
    + ** See also: [sqlite3_column_count()]
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_data_count(sqlite3_stmt *pStmt);
    ++SQLITE_API int sqlite3_data_count(sqlite3_stmt *pStmt);
    + 
    + /*
    + ** CAPI3REF: Fundamental Datatypes
    +@@ -4124,6 +5367,28 @@ SQLITE_API int SQLITE_STDCALL sqlite3_data_count(sqlite3_stmt *pStmt);
    + ** KEYWORDS: {column access functions}
    + ** METHOD: sqlite3_stmt
    + **
    ++** <b>Summary:</b>
    ++** <blockquote><table border=0 cellpadding=0 cellspacing=0>
    ++** <tr><td><b>sqlite3_column_blob</b><td>&rarr;<td>BLOB result
    ++** <tr><td><b>sqlite3_column_double</b><td>&rarr;<td>REAL result
    ++** <tr><td><b>sqlite3_column_int</b><td>&rarr;<td>32-bit INTEGER result
    ++** <tr><td><b>sqlite3_column_int64</b><td>&rarr;<td>64-bit INTEGER result
    ++** <tr><td><b>sqlite3_column_text</b><td>&rarr;<td>UTF-8 TEXT result
    ++** <tr><td><b>sqlite3_column_text16</b><td>&rarr;<td>UTF-16 TEXT result
    ++** <tr><td><b>sqlite3_column_value</b><td>&rarr;<td>The result as an 
    ++** [sqlite3_value|unprotected sqlite3_value] object.
    ++** <tr><td>&nbsp;<td>&nbsp;<td>&nbsp;
    ++** <tr><td><b>sqlite3_column_bytes</b><td>&rarr;<td>Size of a BLOB
    ++** or a UTF-8 TEXT result in bytes
    ++** <tr><td><b>sqlite3_column_bytes16&nbsp;&nbsp;</b>
    ++** <td>&rarr;&nbsp;&nbsp;<td>Size of UTF-16
    ++** TEXT in bytes
    ++** <tr><td><b>sqlite3_column_type</b><td>&rarr;<td>Default
    ++** datatype of the result
    ++** </table></blockquote>
    ++**
    ++** <b>Details:</b>
    ++**
    + ** ^These routines return information about a single column of the current
    + ** result row of a query.  ^In every case the first argument is a pointer
    + ** to the [prepared statement] that is being evaluated (the [sqlite3_stmt*]
    +@@ -4145,16 +5410,29 @@ SQLITE_API int SQLITE_STDCALL sqlite3_data_count(sqlite3_stmt *pStmt);
    + ** are called from a different thread while any of these routines
    + ** are pending, then the results are undefined.
    + **
    ++** The first six interfaces (_blob, _double, _int, _int64, _text, and _text16)
    ++** each return the value of a result column in a specific data format.  If
    ++** the result column is not initially in the requested format (for example,
    ++** if the query returns an integer but the sqlite3_column_text() interface
    ++** is used to extract the value) then an automatic type conversion is performed.
    ++**
    + ** ^The sqlite3_column_type() routine returns the
    + ** [SQLITE_INTEGER | datatype code] for the initial data type
    + ** of the result column.  ^The returned value is one of [SQLITE_INTEGER],
    +-** [SQLITE_FLOAT], [SQLITE_TEXT], [SQLITE_BLOB], or [SQLITE_NULL].  The value
    +-** returned by sqlite3_column_type() is only meaningful if no type
    +-** conversions have occurred as described below.  After a type conversion,
    +-** the value returned by sqlite3_column_type() is undefined.  Future
    ++** [SQLITE_FLOAT], [SQLITE_TEXT], [SQLITE_BLOB], or [SQLITE_NULL].
    ++** The return value of sqlite3_column_type() can be used to decide which
    ++** of the first six interface should be used to extract the column value.
    ++** The value returned by sqlite3_column_type() is only meaningful if no
    ++** automatic type conversions have occurred for the value in question.  
    ++** After a type conversion, the result of calling sqlite3_column_type()
    ++** is undefined, though harmless.  Future
    + ** versions of SQLite may change the behavior of sqlite3_column_type()
    + ** following a type conversion.
    + **
    ++** If the result is a BLOB or a TEXT string, then the sqlite3_column_bytes()
    ++** or sqlite3_column_bytes16() interfaces can be used to determine the size
    ++** of that BLOB or string.
    ++**
    + ** ^If the result is a BLOB or UTF-8 string then the sqlite3_column_bytes()
    + ** routine returns the number of bytes in that BLOB or string.
    + ** ^If the result is a UTF-16 string, then sqlite3_column_bytes() converts
    +@@ -4191,9 +5469,13 @@ SQLITE_API int SQLITE_STDCALL sqlite3_data_count(sqlite3_stmt *pStmt);
    + ** [sqlite3_column_value()] is used in any other way, including calls
    + ** to routines like [sqlite3_value_int()], [sqlite3_value_text()],
    + ** or [sqlite3_value_bytes()], the behavior is not threadsafe.
    ++** Hence, the sqlite3_column_value() interface
    ++** is normally only useful within the implementation of 
    ++** [application-defined SQL functions] or [virtual tables], not within
    ++** top-level application code.
    + **
    +-** These routines attempt to convert the value where appropriate.  ^For
    +-** example, if the internal representation is FLOAT and a text result
    ++** The these routines may attempt to convert the datatype of the result.
    ++** ^For example, if the internal representation is FLOAT and a text result
    + ** is requested, [sqlite3_snprintf()] is used internally to perform the
    + ** conversion automatically.  ^(The following table details the conversions
    + ** that are applied:
    +@@ -4265,7 +5547,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_data_count(sqlite3_stmt *pStmt);
    + ** ^The pointers returned are valid until a type conversion occurs as
    + ** described above, or until [sqlite3_step()] or [sqlite3_reset()] or
    + ** [sqlite3_finalize()] is called.  ^The memory space used to hold strings
    +-** and BLOBs is freed automatically.  Do <em>not</em> pass the pointers returned
    ++** and BLOBs is freed automatically.  Do not pass the pointers returned
    + ** from [sqlite3_column_blob()], [sqlite3_column_text()], etc. into
    + ** [sqlite3_free()].
    + **
    +@@ -4275,16 +5557,16 @@ SQLITE_API int SQLITE_STDCALL sqlite3_data_count(sqlite3_stmt *pStmt);
    + ** pointer.  Subsequent calls to [sqlite3_errcode()] will return
    + ** [SQLITE_NOMEM].)^
    + */
    +-SQLITE_API const void *SQLITE_STDCALL sqlite3_column_blob(sqlite3_stmt*, int iCol);
    +-SQLITE_API int SQLITE_STDCALL sqlite3_column_bytes(sqlite3_stmt*, int iCol);
    +-SQLITE_API int SQLITE_STDCALL sqlite3_column_bytes16(sqlite3_stmt*, int iCol);
    +-SQLITE_API double SQLITE_STDCALL sqlite3_column_double(sqlite3_stmt*, int iCol);
    +-SQLITE_API int SQLITE_STDCALL sqlite3_column_int(sqlite3_stmt*, int iCol);
    +-SQLITE_API sqlite3_int64 SQLITE_STDCALL sqlite3_column_int64(sqlite3_stmt*, int iCol);
    +-SQLITE_API const unsigned char *SQLITE_STDCALL sqlite3_column_text(sqlite3_stmt*, int iCol);
    +-SQLITE_API const void *SQLITE_STDCALL sqlite3_column_text16(sqlite3_stmt*, int iCol);
    +-SQLITE_API int SQLITE_STDCALL sqlite3_column_type(sqlite3_stmt*, int iCol);
    +-SQLITE_API sqlite3_value *SQLITE_STDCALL sqlite3_column_value(sqlite3_stmt*, int iCol);
    ++SQLITE_API const void *sqlite3_column_blob(sqlite3_stmt*, int iCol);
    ++SQLITE_API double sqlite3_column_double(sqlite3_stmt*, int iCol);
    ++SQLITE_API int sqlite3_column_int(sqlite3_stmt*, int iCol);
    ++SQLITE_API sqlite3_int64 sqlite3_column_int64(sqlite3_stmt*, int iCol);
    ++SQLITE_API const unsigned char *sqlite3_column_text(sqlite3_stmt*, int iCol);
    ++SQLITE_API const void *sqlite3_column_text16(sqlite3_stmt*, int iCol);
    ++SQLITE_API sqlite3_value *sqlite3_column_value(sqlite3_stmt*, int iCol);
    ++SQLITE_API int sqlite3_column_bytes(sqlite3_stmt*, int iCol);
    ++SQLITE_API int sqlite3_column_bytes16(sqlite3_stmt*, int iCol);
    ++SQLITE_API int sqlite3_column_type(sqlite3_stmt*, int iCol);
    + 
    + /*
    + ** CAPI3REF: Destroy A Prepared Statement Object
    +@@ -4312,7 +5594,7 @@ SQLITE_API sqlite3_value *SQLITE_STDCALL sqlite3_column_value(sqlite3_stmt*, int
    + ** statement after it has been finalized can result in undefined and
    + ** undesirable behavior such as segfaults and heap corruption.
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_finalize(sqlite3_stmt *pStmt);
    ++SQLITE_API int sqlite3_finalize(sqlite3_stmt *pStmt);
    + 
    + /*
    + ** CAPI3REF: Reset A Prepared Statement Object
    +@@ -4339,7 +5621,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_finalize(sqlite3_stmt *pStmt);
    + ** ^The [sqlite3_reset(S)] interface does not change the values
    + ** of any [sqlite3_bind_blob|bindings] on the [prepared statement] S.
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_reset(sqlite3_stmt *pStmt);
    ++SQLITE_API int sqlite3_reset(sqlite3_stmt *pStmt);
    + 
    + /*
    + ** CAPI3REF: Create Or Redefine SQL Functions
    +@@ -4439,7 +5721,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_reset(sqlite3_stmt *pStmt);
    + ** close the database connection nor finalize or reset the prepared
    + ** statement in which the function is running.
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_create_function(
    ++SQLITE_API int sqlite3_create_function(
    +   sqlite3 *db,
    +   const char *zFunctionName,
    +   int nArg,
    +@@ -4449,7 +5731,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_create_function(
    +   void (*xStep)(sqlite3_context*,int,sqlite3_value**),
    +   void (*xFinal)(sqlite3_context*)
    + );
    +-SQLITE_API int SQLITE_STDCALL sqlite3_create_function16(
    ++SQLITE_API int sqlite3_create_function16(
    +   sqlite3 *db,
    +   const void *zFunctionName,
    +   int nArg,
    +@@ -4459,7 +5741,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_create_function16(
    +   void (*xStep)(sqlite3_context*,int,sqlite3_value**),
    +   void (*xFinal)(sqlite3_context*)
    + );
    +-SQLITE_API int SQLITE_STDCALL sqlite3_create_function_v2(
    ++SQLITE_API int sqlite3_create_function_v2(
    +   sqlite3 *db,
    +   const char *zFunctionName,
    +   int nArg,
    +@@ -4505,12 +5787,12 @@ SQLITE_API int SQLITE_STDCALL sqlite3_create_function_v2(
    + ** these functions, we will not explain what they do.
    + */
    + #ifndef SQLITE_OMIT_DEPRECATED
    +-SQLITE_API SQLITE_DEPRECATED int SQLITE_STDCALL sqlite3_aggregate_count(sqlite3_context*);
    +-SQLITE_API SQLITE_DEPRECATED int SQLITE_STDCALL sqlite3_expired(sqlite3_stmt*);
    +-SQLITE_API SQLITE_DEPRECATED int SQLITE_STDCALL sqlite3_transfer_bindings(sqlite3_stmt*, sqlite3_stmt*);
    +-SQLITE_API SQLITE_DEPRECATED int SQLITE_STDCALL sqlite3_global_recover(void);
    +-SQLITE_API SQLITE_DEPRECATED void SQLITE_STDCALL sqlite3_thread_cleanup(void);
    +-SQLITE_API SQLITE_DEPRECATED int SQLITE_STDCALL sqlite3_memory_alarm(void(*)(void*,sqlite3_int64,int),
    ++SQLITE_API SQLITE_DEPRECATED int sqlite3_aggregate_count(sqlite3_context*);
    ++SQLITE_API SQLITE_DEPRECATED int sqlite3_expired(sqlite3_stmt*);
    ++SQLITE_API SQLITE_DEPRECATED int sqlite3_transfer_bindings(sqlite3_stmt*, sqlite3_stmt*);
    ++SQLITE_API SQLITE_DEPRECATED int sqlite3_global_recover(void);
    ++SQLITE_API SQLITE_DEPRECATED void sqlite3_thread_cleanup(void);
    ++SQLITE_API SQLITE_DEPRECATED int sqlite3_memory_alarm(void(*)(void*,sqlite3_int64,int),
    +                       void*,sqlite3_int64);
    + #endif
    + 
    +@@ -4518,21 +5800,43 @@ SQLITE_API SQLITE_DEPRECATED int SQLITE_STDCALL sqlite3_memory_alarm(void(*)(voi
    + ** CAPI3REF: Obtaining SQL Values
    + ** METHOD: sqlite3_value
    + **
    +-** The C-language implementation of SQL functions and aggregates uses
    +-** this set of interface routines to access the parameter values on
    +-** the function or aggregate.  
    +-**
    +-** The xFunc (for scalar functions) or xStep (for aggregates) parameters
    +-** to [sqlite3_create_function()] and [sqlite3_create_function16()]
    +-** define callbacks that implement the SQL functions and aggregates.
    +-** The 3rd parameter to these callbacks is an array of pointers to
    +-** [protected sqlite3_value] objects.  There is one [sqlite3_value] object for
    +-** each parameter to the SQL function.  These routines are used to
    +-** extract values from the [sqlite3_value] objects.
    ++** <b>Summary:</b>
    ++** <blockquote><table border=0 cellpadding=0 cellspacing=0>
    ++** <tr><td><b>sqlite3_value_blob</b><td>&rarr;<td>BLOB value
    ++** <tr><td><b>sqlite3_value_double</b><td>&rarr;<td>REAL value
    ++** <tr><td><b>sqlite3_value_int</b><td>&rarr;<td>32-bit INTEGER value
    ++** <tr><td><b>sqlite3_value_int64</b><td>&rarr;<td>64-bit INTEGER value
    ++** <tr><td><b>sqlite3_value_pointer</b><td>&rarr;<td>Pointer value
    ++** <tr><td><b>sqlite3_value_text</b><td>&rarr;<td>UTF-8 TEXT value
    ++** <tr><td><b>sqlite3_value_text16</b><td>&rarr;<td>UTF-16 TEXT value in
    ++** the native byteorder
    ++** <tr><td><b>sqlite3_value_text16be</b><td>&rarr;<td>UTF-16be TEXT value
    ++** <tr><td><b>sqlite3_value_text16le</b><td>&rarr;<td>UTF-16le TEXT value
    ++** <tr><td>&nbsp;<td>&nbsp;<td>&nbsp;
    ++** <tr><td><b>sqlite3_value_bytes</b><td>&rarr;<td>Size of a BLOB
    ++** or a UTF-8 TEXT in bytes
    ++** <tr><td><b>sqlite3_value_bytes16&nbsp;&nbsp;</b>
    ++** <td>&rarr;&nbsp;&nbsp;<td>Size of UTF-16
    ++** TEXT in bytes
    ++** <tr><td><b>sqlite3_value_type</b><td>&rarr;<td>Default
    ++** datatype of the value
    ++** <tr><td><b>sqlite3_value_numeric_type&nbsp;&nbsp;</b>
    ++** <td>&rarr;&nbsp;&nbsp;<td>Best numeric datatype of the value
    ++** <tr><td><b>sqlite3_value_nochange&nbsp;&nbsp;</b>
    ++** <td>&rarr;&nbsp;&nbsp;<td>True if the column is unchanged in an UPDATE
    ++** against a virtual table.
    ++** </table></blockquote>
    ++**
    ++** <b>Details:</b>
    ++**
    ++** These routines extract type, size, and content information from
    ++** [protected sqlite3_value] objects.  Protected sqlite3_value objects
    ++** are used to pass parameter information into implementation of
    ++** [application-defined SQL functions] and [virtual tables].
    + **
    + ** These routines work only with [protected sqlite3_value] objects.
    + ** Any attempt to use these routines on an [unprotected sqlite3_value]
    +-** object results in undefined behavior.
    ++** is not threadsafe.
    + **
    + ** ^These routines work just like the corresponding [column access functions]
    + ** except that these routines take a single [protected sqlite3_value] object
    +@@ -4543,6 +5847,24 @@ SQLITE_API SQLITE_DEPRECATED int SQLITE_STDCALL sqlite3_memory_alarm(void(*)(voi
    + ** sqlite3_value_text16be() and sqlite3_value_text16le() interfaces
    + ** extract UTF-16 strings as big-endian and little-endian respectively.
    + **
    ++** ^If [sqlite3_value] object V was initialized 
    ++** using [sqlite3_bind_pointer(S,I,P,X,D)] or [sqlite3_result_pointer(C,P,X,D)]
    ++** and if X and Y are strings that compare equal according to strcmp(X,Y),
    ++** then sqlite3_value_pointer(V,Y) will return the pointer P.  ^Otherwise,
    ++** sqlite3_value_pointer(V,Y) returns a NULL. The sqlite3_bind_pointer() 
    ++** routine is part of the [pointer passing interface] added for SQLite 3.20.0.
    ++**
    ++** ^(The sqlite3_value_type(V) interface returns the
    ++** [SQLITE_INTEGER | datatype code] for the initial datatype of the
    ++** [sqlite3_value] object V. The returned value is one of [SQLITE_INTEGER],
    ++** [SQLITE_FLOAT], [SQLITE_TEXT], [SQLITE_BLOB], or [SQLITE_NULL].)^
    ++** Other interfaces might change the datatype for an sqlite3_value object.
    ++** For example, if the datatype is initially SQLITE_INTEGER and
    ++** sqlite3_value_text(V) is called to extract a text value for that
    ++** integer, then subsequent calls to sqlite3_value_type(V) might return
    ++** SQLITE_TEXT.  Whether or not a persistent internal datatype conversion
    ++** occurs is undefined and may change from one release of SQLite to the next.
    ++**
    + ** ^(The sqlite3_value_numeric_type() interface attempts to apply
    + ** numeric affinity to the value.  This means that an attempt is
    + ** made to convert the value to an integer or floating point.  If
    +@@ -4551,6 +5873,19 @@ SQLITE_API SQLITE_DEPRECATED int SQLITE_STDCALL sqlite3_memory_alarm(void(*)(voi
    + ** then the conversion is performed.  Otherwise no conversion occurs.
    + ** The [SQLITE_INTEGER | datatype] after conversion is returned.)^
    + **
    ++** ^Within the [xUpdate] method of a [virtual table], the
    ++** sqlite3_value_nochange(X) interface returns true if and only if
    ++** the column corresponding to X is unchanged by the UPDATE operation
    ++** that the xUpdate method call was invoked to implement and if
    ++** and the prior [xColumn] method call that was invoked to extracted
    ++** the value for that column returned without setting a result (probably
    ++** because it queried [sqlite3_vtab_nochange()] and found that the column
    ++** was unchanging).  ^Within an [xUpdate] method, any value for which
    ++** sqlite3_value_nochange(X) is true will in all other respects appear
    ++** to be a NULL value.  If sqlite3_value_nochange(X) is invoked anywhere other
    ++** than within an [xUpdate] method call for an UPDATE statement, then
    ++** the return value is arbitrary and meaningless.
    ++**
    + ** Please pay particular attention to the fact that the pointer returned
    + ** from [sqlite3_value_blob()], [sqlite3_value_text()], or
    + ** [sqlite3_value_text16()] can be invalidated by a subsequent call to
    +@@ -4560,18 +5895,20 @@ SQLITE_API SQLITE_DEPRECATED int SQLITE_STDCALL sqlite3_memory_alarm(void(*)(voi
    + ** These routines must be called from the same thread as
    + ** the SQL function that supplied the [sqlite3_value*] parameters.
    + */
    +-SQLITE_API const void *SQLITE_STDCALL sqlite3_value_blob(sqlite3_value*);
    +-SQLITE_API int SQLITE_STDCALL sqlite3_value_bytes(sqlite3_value*);
    +-SQLITE_API int SQLITE_STDCALL sqlite3_value_bytes16(sqlite3_value*);
    +-SQLITE_API double SQLITE_STDCALL sqlite3_value_double(sqlite3_value*);
    +-SQLITE_API int SQLITE_STDCALL sqlite3_value_int(sqlite3_value*);
    +-SQLITE_API sqlite3_int64 SQLITE_STDCALL sqlite3_value_int64(sqlite3_value*);
    +-SQLITE_API const unsigned char *SQLITE_STDCALL sqlite3_value_text(sqlite3_value*);
    +-SQLITE_API const void *SQLITE_STDCALL sqlite3_value_text16(sqlite3_value*);
    +-SQLITE_API const void *SQLITE_STDCALL sqlite3_value_text16le(sqlite3_value*);
    +-SQLITE_API const void *SQLITE_STDCALL sqlite3_value_text16be(sqlite3_value*);
    +-SQLITE_API int SQLITE_STDCALL sqlite3_value_type(sqlite3_value*);
    +-SQLITE_API int SQLITE_STDCALL sqlite3_value_numeric_type(sqlite3_value*);
    ++SQLITE_API const void *sqlite3_value_blob(sqlite3_value*);
    ++SQLITE_API double sqlite3_value_double(sqlite3_value*);
    ++SQLITE_API int sqlite3_value_int(sqlite3_value*);
    ++SQLITE_API sqlite3_int64 sqlite3_value_int64(sqlite3_value*);
    ++SQLITE_API void *sqlite3_value_pointer(sqlite3_value*, const char*);
    ++SQLITE_API const unsigned char *sqlite3_value_text(sqlite3_value*);
    ++SQLITE_API const void *sqlite3_value_text16(sqlite3_value*);
    ++SQLITE_API const void *sqlite3_value_text16le(sqlite3_value*);
    ++SQLITE_API const void *sqlite3_value_text16be(sqlite3_value*);
    ++SQLITE_API int sqlite3_value_bytes(sqlite3_value*);
    ++SQLITE_API int sqlite3_value_bytes16(sqlite3_value*);
    ++SQLITE_API int sqlite3_value_type(sqlite3_value*);
    ++SQLITE_API int sqlite3_value_numeric_type(sqlite3_value*);
    ++SQLITE_API int sqlite3_value_nochange(sqlite3_value*);
    + 
    + /*
    + ** CAPI3REF: Finding The Subtype Of SQL Values
    +@@ -4582,12 +5919,8 @@ SQLITE_API int SQLITE_STDCALL sqlite3_value_numeric_type(sqlite3_value*);
    + ** information can be used to pass a limited amount of context from
    + ** one SQL function to another.  Use the [sqlite3_result_subtype()]
    + ** routine to set the subtype for the return value of an SQL function.
    +-**
    +-** SQLite makes no use of subtype itself.  It merely passes the subtype
    +-** from the result of one [application-defined SQL function] into the
    +-** input of another.
    + */
    +-SQLITE_API unsigned int SQLITE_STDCALL sqlite3_value_subtype(sqlite3_value*);
    ++SQLITE_API unsigned int sqlite3_value_subtype(sqlite3_value*);
    + 
    + /*
    + ** CAPI3REF: Copy And Free SQL Values
    +@@ -4603,8 +5936,8 @@ SQLITE_API unsigned int SQLITE_STDCALL sqlite3_value_subtype(sqlite3_value*);
    + ** previously obtained from [sqlite3_value_dup()].  ^If V is a NULL pointer
    + ** then sqlite3_value_free(V) is a harmless no-op.
    + */
    +-SQLITE_API SQLITE_EXPERIMENTAL sqlite3_value *SQLITE_STDCALL sqlite3_value_dup(const sqlite3_value*);
    +-SQLITE_API SQLITE_EXPERIMENTAL void SQLITE_STDCALL sqlite3_value_free(sqlite3_value*);
    ++SQLITE_API sqlite3_value *sqlite3_value_dup(const sqlite3_value*);
    ++SQLITE_API void sqlite3_value_free(sqlite3_value*);
    + 
    + /*
    + ** CAPI3REF: Obtain Aggregate Function Context
    +@@ -4649,7 +5982,7 @@ SQLITE_API SQLITE_EXPERIMENTAL void SQLITE_STDCALL sqlite3_value_free(sqlite3_va
    + ** This routine must be called from the same thread in which
    + ** the aggregate SQL function is running.
    + */
    +-SQLITE_API void *SQLITE_STDCALL sqlite3_aggregate_context(sqlite3_context*, int nBytes);
    ++SQLITE_API void *sqlite3_aggregate_context(sqlite3_context*, int nBytes);
    + 
    + /*
    + ** CAPI3REF: User Data For Functions
    +@@ -4664,7 +5997,7 @@ SQLITE_API void *SQLITE_STDCALL sqlite3_aggregate_context(sqlite3_context*, int
    + ** This routine must be called from the same thread in which
    + ** the application-defined function is running.
    + */
    +-SQLITE_API void *SQLITE_STDCALL sqlite3_user_data(sqlite3_context*);
    ++SQLITE_API void *sqlite3_user_data(sqlite3_context*);
    + 
    + /*
    + ** CAPI3REF: Database Connection For Functions
    +@@ -4676,7 +6009,7 @@ SQLITE_API void *SQLITE_STDCALL sqlite3_user_data(sqlite3_context*);
    + ** and [sqlite3_create_function16()] routines that originally
    + ** registered the application defined function.
    + */
    +-SQLITE_API sqlite3 *SQLITE_STDCALL sqlite3_context_db_handle(sqlite3_context*);
    ++SQLITE_API sqlite3 *sqlite3_context_db_handle(sqlite3_context*);
    + 
    + /*
    + ** CAPI3REF: Function Auxiliary Data
    +@@ -4693,10 +6026,11 @@ SQLITE_API sqlite3 *SQLITE_STDCALL sqlite3_context_db_handle(sqlite3_context*);
    + ** the compiled regular expression can be reused on multiple
    + ** invocations of the same function.
    + **
    +-** ^The sqlite3_get_auxdata() interface returns a pointer to the metadata
    +-** associated by the sqlite3_set_auxdata() function with the Nth argument
    +-** value to the application-defined function. ^If there is no metadata
    +-** associated with the function argument, this sqlite3_get_auxdata() interface
    ++** ^The sqlite3_get_auxdata(C,N) interface returns a pointer to the metadata
    ++** associated by the sqlite3_set_auxdata(C,N,P,X) function with the Nth argument
    ++** value to the application-defined function.  ^N is zero for the left-most
    ++** function argument.  ^If there is no metadata
    ++** associated with the function argument, the sqlite3_get_auxdata(C,N) interface
    + ** returns a NULL pointer.
    + **
    + ** ^The sqlite3_set_auxdata(C,N,P,X) interface saves P as metadata for the N-th
    +@@ -4708,12 +6042,13 @@ SQLITE_API sqlite3 *SQLITE_STDCALL sqlite3_context_db_handle(sqlite3_context*);
    + ** SQLite will invoke the destructor function X with parameter P exactly
    + ** once, when the metadata is discarded.
    + ** SQLite is free to discard the metadata at any time, including: <ul>
    +-** <li> when the corresponding function parameter changes, or
    +-** <li> when [sqlite3_reset()] or [sqlite3_finalize()] is called for the
    +-**      SQL statement, or
    +-** <li> when sqlite3_set_auxdata() is invoked again on the same parameter, or
    +-** <li> during the original sqlite3_set_auxdata() call when a memory 
    +-**      allocation error occurs. </ul>)^
    ++** <li> ^(when the corresponding function parameter changes)^, or
    ++** <li> ^(when [sqlite3_reset()] or [sqlite3_finalize()] is called for the
    ++**      SQL statement)^, or
    ++** <li> ^(when sqlite3_set_auxdata() is invoked again on the same
    ++**       parameter)^, or
    ++** <li> ^(during the original sqlite3_set_auxdata() call when a memory 
    ++**      allocation error occurs.)^ </ul>
    + **
    + ** Note the last bullet in particular.  The destructor X in 
    + ** sqlite3_set_auxdata(C,N,P,X) might be called immediately, before the
    +@@ -4726,11 +6061,15 @@ SQLITE_API sqlite3 *SQLITE_STDCALL sqlite3_context_db_handle(sqlite3_context*);
    + ** function parameters that are compile-time constants, including literal
    + ** values and [parameters] and expressions composed from the same.)^
    + **
    ++** The value of the N parameter to these interfaces should be non-negative.
    ++** Future enhancements may make use of negative N values to define new
    ++** kinds of function caching behavior.
    ++**
    + ** These routines must be called from the same thread in which
    + ** the SQL function is running.
    + */
    +-SQLITE_API void *SQLITE_STDCALL sqlite3_get_auxdata(sqlite3_context*, int N);
    +-SQLITE_API void SQLITE_STDCALL sqlite3_set_auxdata(sqlite3_context*, int N, void*, void (*)(void*));
    ++SQLITE_API void *sqlite3_get_auxdata(sqlite3_context*, int N);
    ++SQLITE_API void sqlite3_set_auxdata(sqlite3_context*, int N, void*, void (*)(void*));
    + 
    + 
    + /*
    +@@ -4849,7 +6188,7 @@ typedef void (*sqlite3_destructor_type)(void*);
    + ** when it has finished using that result.
    + ** ^If the 4th parameter to the sqlite3_result_text* interfaces
    + ** or sqlite3_result_blob is the special constant SQLITE_TRANSIENT
    +-** then SQLite makes a copy of the result into space obtained from
    ++** then SQLite makes a copy of the result into space obtained
    + ** from [sqlite3_malloc()] before it returns.
    + **
    + ** ^The sqlite3_result_value() interface sets the result of
    +@@ -4862,31 +6201,43 @@ typedef void (*sqlite3_destructor_type)(void*);
    + ** [unprotected sqlite3_value] object is required, so either
    + ** kind of [sqlite3_value] object can be used with this interface.
    + **
    ++** ^The sqlite3_result_pointer(C,P,T,D) interface sets the result to an
    ++** SQL NULL value, just like [sqlite3_result_null(C)], except that it
    ++** also associates the host-language pointer P or type T with that 
    ++** NULL value such that the pointer can be retrieved within an
    ++** [application-defined SQL function] using [sqlite3_value_pointer()].
    ++** ^If the D parameter is not NULL, then it is a pointer to a destructor
    ++** for the P parameter.  ^SQLite invokes D with P as its only argument
    ++** when SQLite is finished with P.  The T parameter should be a static
    ++** string and preferably a string literal. The sqlite3_result_pointer()
    ++** routine is part of the [pointer passing interface] added for SQLite 3.20.0.
    ++**
    + ** If these routines are called from within the different thread
    + ** than the one containing the application-defined function that received
    + ** the [sqlite3_context] pointer, the results are undefined.
    + */
    +-SQLITE_API void SQLITE_STDCALL sqlite3_result_blob(sqlite3_context*, const void*, int, void(*)(void*));
    +-SQLITE_API void SQLITE_STDCALL sqlite3_result_blob64(sqlite3_context*,const void*,
    ++SQLITE_API void sqlite3_result_blob(sqlite3_context*, const void*, int, void(*)(void*));
    ++SQLITE_API void sqlite3_result_blob64(sqlite3_context*,const void*,
    +                            sqlite3_uint64,void(*)(void*));
    +-SQLITE_API void SQLITE_STDCALL sqlite3_result_double(sqlite3_context*, double);
    +-SQLITE_API void SQLITE_STDCALL sqlite3_result_error(sqlite3_context*, const char*, int);
    +-SQLITE_API void SQLITE_STDCALL sqlite3_result_error16(sqlite3_context*, const void*, int);
    +-SQLITE_API void SQLITE_STDCALL sqlite3_result_error_toobig(sqlite3_context*);
    +-SQLITE_API void SQLITE_STDCALL sqlite3_result_error_nomem(sqlite3_context*);
    +-SQLITE_API void SQLITE_STDCALL sqlite3_result_error_code(sqlite3_context*, int);
    +-SQLITE_API void SQLITE_STDCALL sqlite3_result_int(sqlite3_context*, int);
    +-SQLITE_API void SQLITE_STDCALL sqlite3_result_int64(sqlite3_context*, sqlite3_int64);
    +-SQLITE_API void SQLITE_STDCALL sqlite3_result_null(sqlite3_context*);
    +-SQLITE_API void SQLITE_STDCALL sqlite3_result_text(sqlite3_context*, const char*, int, void(*)(void*));
    +-SQLITE_API void SQLITE_STDCALL sqlite3_result_text64(sqlite3_context*, const char*,sqlite3_uint64,
    ++SQLITE_API void sqlite3_result_double(sqlite3_context*, double);
    ++SQLITE_API void sqlite3_result_error(sqlite3_context*, const char*, int);
    ++SQLITE_API void sqlite3_result_error16(sqlite3_context*, const void*, int);
    ++SQLITE_API void sqlite3_result_error_toobig(sqlite3_context*);
    ++SQLITE_API void sqlite3_result_error_nomem(sqlite3_context*);
    ++SQLITE_API void sqlite3_result_error_code(sqlite3_context*, int);
    ++SQLITE_API void sqlite3_result_int(sqlite3_context*, int);
    ++SQLITE_API void sqlite3_result_int64(sqlite3_context*, sqlite3_int64);
    ++SQLITE_API void sqlite3_result_null(sqlite3_context*);
    ++SQLITE_API void sqlite3_result_text(sqlite3_context*, const char*, int, void(*)(void*));
    ++SQLITE_API void sqlite3_result_text64(sqlite3_context*, const char*,sqlite3_uint64,
    +                            void(*)(void*), unsigned char encoding);
    +-SQLITE_API void SQLITE_STDCALL sqlite3_result_text16(sqlite3_context*, const void*, int, void(*)(void*));
    +-SQLITE_API void SQLITE_STDCALL sqlite3_result_text16le(sqlite3_context*, const void*, int,void(*)(void*));
    +-SQLITE_API void SQLITE_STDCALL sqlite3_result_text16be(sqlite3_context*, const void*, int,void(*)(void*));
    +-SQLITE_API void SQLITE_STDCALL sqlite3_result_value(sqlite3_context*, sqlite3_value*);
    +-SQLITE_API void SQLITE_STDCALL sqlite3_result_zeroblob(sqlite3_context*, int n);
    +-SQLITE_API int SQLITE_STDCALL sqlite3_result_zeroblob64(sqlite3_context*, sqlite3_uint64 n);
    ++SQLITE_API void sqlite3_result_text16(sqlite3_context*, const void*, int, void(*)(void*));
    ++SQLITE_API void sqlite3_result_text16le(sqlite3_context*, const void*, int,void(*)(void*));
    ++SQLITE_API void sqlite3_result_text16be(sqlite3_context*, const void*, int,void(*)(void*));
    ++SQLITE_API void sqlite3_result_value(sqlite3_context*, sqlite3_value*);
    ++SQLITE_API void sqlite3_result_pointer(sqlite3_context*, void*,const char*,void(*)(void*));
    ++SQLITE_API void sqlite3_result_zeroblob(sqlite3_context*, int n);
    ++SQLITE_API int sqlite3_result_zeroblob64(sqlite3_context*, sqlite3_uint64 n);
    + 
    + 
    + /*
    +@@ -4901,7 +6252,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_result_zeroblob64(sqlite3_context*, sqlite
    + ** The number of subtype bytes preserved by SQLite might increase
    + ** in future releases of SQLite.
    + */
    +-SQLITE_API void SQLITE_STDCALL sqlite3_result_subtype(sqlite3_context*,unsigned int);
    ++SQLITE_API void sqlite3_result_subtype(sqlite3_context*,unsigned int);
    + 
    + /*
    + ** CAPI3REF: Define New Collating Sequences
    +@@ -4983,14 +6334,14 @@ SQLITE_API void SQLITE_STDCALL sqlite3_result_subtype(sqlite3_context*,unsigned
    + **
    + ** See also:  [sqlite3_collation_needed()] and [sqlite3_collation_needed16()].
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_create_collation(
    ++SQLITE_API int sqlite3_create_collation(
    +   sqlite3*, 
    +   const char *zName, 
    +   int eTextRep, 
    +   void *pArg,
    +   int(*xCompare)(void*,int,const void*,int,const void*)
    + );
    +-SQLITE_API int SQLITE_STDCALL sqlite3_create_collation_v2(
    ++SQLITE_API int sqlite3_create_collation_v2(
    +   sqlite3*, 
    +   const char *zName, 
    +   int eTextRep, 
    +@@ -4998,7 +6349,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_create_collation_v2(
    +   int(*xCompare)(void*,int,const void*,int,const void*),
    +   void(*xDestroy)(void*)
    + );
    +-SQLITE_API int SQLITE_STDCALL sqlite3_create_collation16(
    ++SQLITE_API int sqlite3_create_collation16(
    +   sqlite3*, 
    +   const void *zName,
    +   int eTextRep, 
    +@@ -5033,12 +6384,12 @@ SQLITE_API int SQLITE_STDCALL sqlite3_create_collation16(
    + ** [sqlite3_create_collation()], [sqlite3_create_collation16()], or
    + ** [sqlite3_create_collation_v2()].
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_collation_needed(
    ++SQLITE_API int sqlite3_collation_needed(
    +   sqlite3*, 
    +   void*, 
    +   void(*)(void*,sqlite3*,int eTextRep,const char*)
    + );
    +-SQLITE_API int SQLITE_STDCALL sqlite3_collation_needed16(
    ++SQLITE_API int sqlite3_collation_needed16(
    +   sqlite3*, 
    +   void*,
    +   void(*)(void*,sqlite3*,int eTextRep,const void*)
    +@@ -5052,11 +6403,11 @@ SQLITE_API int SQLITE_STDCALL sqlite3_collation_needed16(
    + ** The code to implement this API is not available in the public release
    + ** of SQLite.
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_key(
    ++SQLITE_API int sqlite3_key(
    +   sqlite3 *db,                   /* Database to be rekeyed */
    +   const void *pKey, int nKey     /* The key */
    + );
    +-SQLITE_API int SQLITE_STDCALL sqlite3_key_v2(
    ++SQLITE_API int sqlite3_key_v2(
    +   sqlite3 *db,                   /* Database to be rekeyed */
    +   const char *zDbName,           /* Name of the database */
    +   const void *pKey, int nKey     /* The key */
    +@@ -5070,11 +6421,11 @@ SQLITE_API int SQLITE_STDCALL sqlite3_key_v2(
    + ** The code to implement this API is not available in the public release
    + ** of SQLite.
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_rekey(
    ++SQLITE_API int sqlite3_rekey(
    +   sqlite3 *db,                   /* Database to be rekeyed */
    +   const void *pKey, int nKey     /* The new key */
    + );
    +-SQLITE_API int SQLITE_STDCALL sqlite3_rekey_v2(
    ++SQLITE_API int sqlite3_rekey_v2(
    +   sqlite3 *db,                   /* Database to be rekeyed */
    +   const char *zDbName,           /* Name of the database */
    +   const void *pKey, int nKey     /* The new key */
    +@@ -5084,7 +6435,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_rekey_v2(
    + ** Specify the activation key for a SEE database.  Unless 
    + ** activated, none of the SEE routines will work.
    + */
    +-SQLITE_API void SQLITE_STDCALL sqlite3_activate_see(
    ++SQLITE_API void sqlite3_activate_see(
    +   const char *zPassPhrase        /* Activation phrase */
    + );
    + #endif
    +@@ -5094,7 +6445,7 @@ SQLITE_API void SQLITE_STDCALL sqlite3_activate_see(
    + ** Specify the activation key for a CEROD database.  Unless 
    + ** activated, none of the CEROD routines will work.
    + */
    +-SQLITE_API void SQLITE_STDCALL sqlite3_activate_cerod(
    ++SQLITE_API void sqlite3_activate_cerod(
    +   const char *zPassPhrase        /* Activation phrase */
    + );
    + #endif
    +@@ -5116,7 +6467,7 @@ SQLITE_API void SQLITE_STDCALL sqlite3_activate_cerod(
    + ** all, then the behavior of sqlite3_sleep() may deviate from the description
    + ** in the previous paragraphs.
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_sleep(int);
    ++SQLITE_API int sqlite3_sleep(int);
    + 
    + /*
    + ** CAPI3REF: Name Of The Folder Holding Temporary Files
    +@@ -5235,7 +6586,7 @@ SQLITE_API char *sqlite3_data_directory;
    + ** connection while this routine is running, then the return value
    + ** is undefined.
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_get_autocommit(sqlite3*);
    ++SQLITE_API int sqlite3_get_autocommit(sqlite3*);
    + 
    + /*
    + ** CAPI3REF: Find The Database Handle Of A Prepared Statement
    +@@ -5248,7 +6599,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_get_autocommit(sqlite3*);
    + ** to the [sqlite3_prepare_v2()] call (or its variants) that was used to
    + ** create the statement in the first place.
    + */
    +-SQLITE_API sqlite3 *SQLITE_STDCALL sqlite3_db_handle(sqlite3_stmt*);
    ++SQLITE_API sqlite3 *sqlite3_db_handle(sqlite3_stmt*);
    + 
    + /*
    + ** CAPI3REF: Return The Filename For A Database Connection
    +@@ -5265,7 +6616,7 @@ SQLITE_API sqlite3 *SQLITE_STDCALL sqlite3_db_handle(sqlite3_stmt*);
    + ** will be an absolute pathname, even if the filename used
    + ** to open the database originally was a URI or relative pathname.
    + */
    +-SQLITE_API const char *SQLITE_STDCALL sqlite3_db_filename(sqlite3 *db, const char *zDbName);
    ++SQLITE_API const char *sqlite3_db_filename(sqlite3 *db, const char *zDbName);
    + 
    + /*
    + ** CAPI3REF: Determine if a database is read-only
    +@@ -5275,7 +6626,7 @@ SQLITE_API const char *SQLITE_STDCALL sqlite3_db_filename(sqlite3 *db, const cha
    + ** of connection D is read-only, 0 if it is read/write, or -1 if N is not
    + ** the name of a database on connection D.
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_db_readonly(sqlite3 *db, const char *zDbName);
    ++SQLITE_API int sqlite3_db_readonly(sqlite3 *db, const char *zDbName);
    + 
    + /*
    + ** CAPI3REF: Find the next prepared statement
    +@@ -5291,7 +6642,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_db_readonly(sqlite3 *db, const char *zDbNa
    + ** [sqlite3_next_stmt(D,S)] must refer to an open database
    + ** connection and in particular must not be a NULL pointer.
    + */
    +-SQLITE_API sqlite3_stmt *SQLITE_STDCALL sqlite3_next_stmt(sqlite3 *pDb, sqlite3_stmt *pStmt);
    ++SQLITE_API sqlite3_stmt *sqlite3_next_stmt(sqlite3 *pDb, sqlite3_stmt *pStmt);
    + 
    + /*
    + ** CAPI3REF: Commit And Rollback Notification Callbacks
    +@@ -5340,8 +6691,8 @@ SQLITE_API sqlite3_stmt *SQLITE_STDCALL sqlite3_next_stmt(sqlite3 *pDb, sqlite3_
    + **
    + ** See also the [sqlite3_update_hook()] interface.
    + */
    +-SQLITE_API void *SQLITE_STDCALL sqlite3_commit_hook(sqlite3*, int(*)(void*), void*);
    +-SQLITE_API void *SQLITE_STDCALL sqlite3_rollback_hook(sqlite3*, void(*)(void *), void*);
    ++SQLITE_API void *sqlite3_commit_hook(sqlite3*, int(*)(void*), void*);
    ++SQLITE_API void *sqlite3_rollback_hook(sqlite3*, void(*)(void *), void*);
    + 
    + /*
    + ** CAPI3REF: Data Change Notification Callbacks
    +@@ -5350,7 +6701,7 @@ SQLITE_API void *SQLITE_STDCALL sqlite3_rollback_hook(sqlite3*, void(*)(void *),
    + ** ^The sqlite3_update_hook() interface registers a callback function
    + ** with the [database connection] identified by the first argument
    + ** to be invoked whenever a row is updated, inserted or deleted in
    +-** a rowid table.
    ++** a [rowid table].
    + ** ^Any callback set by a previous call to this function
    + ** for the same database connection is overridden.
    + **
    +@@ -5371,7 +6722,7 @@ SQLITE_API void *SQLITE_STDCALL sqlite3_rollback_hook(sqlite3*, void(*)(void *),
    + ** ^The update hook is not invoked when [WITHOUT ROWID] tables are modified.
    + **
    + ** ^In the current implementation, the update hook
    +-** is not invoked when duplication rows are deleted because of an
    ++** is not invoked when conflicting rows are deleted because of an
    + ** [ON CONFLICT | ON CONFLICT REPLACE] clause.  ^Nor is the update hook
    + ** invoked when rows are deleted using the [truncate optimization].
    + ** The exceptions defined in this paragraph might change in a future
    +@@ -5389,10 +6740,10 @@ SQLITE_API void *SQLITE_STDCALL sqlite3_rollback_hook(sqlite3*, void(*)(void *),
    + ** on the same [database connection] D, or NULL for
    + ** the first call on D.
    + **
    +-** See also the [sqlite3_commit_hook()] and [sqlite3_rollback_hook()]
    +-** interfaces.
    ++** See also the [sqlite3_commit_hook()], [sqlite3_rollback_hook()],
    ++** and [sqlite3_preupdate_hook()] interfaces.
    + */
    +-SQLITE_API void *SQLITE_STDCALL sqlite3_update_hook(
    ++SQLITE_API void *sqlite3_update_hook(
    +   sqlite3*, 
    +   void(*)(void *,int ,char const *,char const *,sqlite3_int64),
    +   void*
    +@@ -5407,7 +6758,8 @@ SQLITE_API void *SQLITE_STDCALL sqlite3_update_hook(
    + ** and disabled if the argument is false.)^
    + **
    + ** ^Cache sharing is enabled and disabled for an entire process.
    +-** This is a change as of SQLite version 3.5.0. In prior versions of SQLite,
    ++** This is a change as of SQLite [version 3.5.0] ([dateof:3.5.0]). 
    ++** In prior versions of SQLite,
    + ** sharing was enabled or disabled for each thread separately.
    + **
    + ** ^(The cache sharing mode set by this interface effects all subsequent
    +@@ -5432,7 +6784,7 @@ SQLITE_API void *SQLITE_STDCALL sqlite3_update_hook(
    + **
    + ** See Also:  [SQLite Shared-Cache Mode]
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_enable_shared_cache(int);
    ++SQLITE_API int sqlite3_enable_shared_cache(int);
    + 
    + /*
    + ** CAPI3REF: Attempt To Free Heap Memory
    +@@ -5448,7 +6800,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_enable_shared_cache(int);
    + **
    + ** See also: [sqlite3_db_release_memory()]
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_release_memory(int);
    ++SQLITE_API int sqlite3_release_memory(int);
    + 
    + /*
    + ** CAPI3REF: Free Memory Used By A Database Connection
    +@@ -5462,7 +6814,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_release_memory(int);
    + **
    + ** See also: [sqlite3_release_memory()]
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_db_release_memory(sqlite3*);
    ++SQLITE_API int sqlite3_db_release_memory(sqlite3*);
    + 
    + /*
    + ** CAPI3REF: Impose A Limit On Heap Size
    +@@ -5501,7 +6853,8 @@ SQLITE_API int SQLITE_STDCALL sqlite3_db_release_memory(sqlite3*);
    + **      from the heap.
    + ** </ul>)^
    + **
    +-** Beginning with SQLite version 3.7.3, the soft heap limit is enforced
    ++** Beginning with SQLite [version 3.7.3] ([dateof:3.7.3]), 
    ++** the soft heap limit is enforced
    + ** regardless of whether or not the [SQLITE_ENABLE_MEMORY_MANAGEMENT]
    + ** compile-time option is invoked.  With [SQLITE_ENABLE_MEMORY_MANAGEMENT],
    + ** the soft heap limit is enforced on every memory allocation.  Without
    +@@ -5514,7 +6867,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_db_release_memory(sqlite3*);
    + ** The circumstances under which SQLite will enforce the soft heap limit may
    + ** changes in future releases of SQLite.
    + */
    +-SQLITE_API sqlite3_int64 SQLITE_STDCALL sqlite3_soft_heap_limit64(sqlite3_int64 N);
    ++SQLITE_API sqlite3_int64 sqlite3_soft_heap_limit64(sqlite3_int64 N);
    + 
    + /*
    + ** CAPI3REF: Deprecated Soft Heap Limit Interface
    +@@ -5525,7 +6878,7 @@ SQLITE_API sqlite3_int64 SQLITE_STDCALL sqlite3_soft_heap_limit64(sqlite3_int64
    + ** only.  All new applications should use the
    + ** [sqlite3_soft_heap_limit64()] interface rather than this one.
    + */
    +-SQLITE_API SQLITE_DEPRECATED void SQLITE_STDCALL sqlite3_soft_heap_limit(int N);
    ++SQLITE_API SQLITE_DEPRECATED void sqlite3_soft_heap_limit(int N);
    + 
    + 
    + /*
    +@@ -5540,9 +6893,11 @@ SQLITE_API SQLITE_DEPRECATED void SQLITE_STDCALL sqlite3_soft_heap_limit(int N);
    + ** column exists.  ^The sqlite3_table_column_metadata() interface returns
    + ** SQLITE_ERROR and if the specified column does not exist.
    + ** ^If the column-name parameter to sqlite3_table_column_metadata() is a
    +-** NULL pointer, then this routine simply checks for the existance of the
    ++** NULL pointer, then this routine simply checks for the existence of the
    + ** table and returns SQLITE_OK if the table exists and SQLITE_ERROR if it
    +-** does not.
    ++** does not.  If the table name parameter T in a call to
    ++** sqlite3_table_column_metadata(X,D,T,C,...) is NULL then the result is
    ++** undefined behavior.
    + **
    + ** ^The column is identified by the second, third and fourth parameters to
    + ** this function. ^(The second parameter is either the name of the database
    +@@ -5595,7 +6950,7 @@ SQLITE_API SQLITE_DEPRECATED void SQLITE_STDCALL sqlite3_soft_heap_limit(int N);
    + ** parsed, if that has not already been done, and returns an error if
    + ** any errors are encountered while loading the schema.
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_table_column_metadata(
    ++SQLITE_API int sqlite3_table_column_metadata(
    +   sqlite3 *db,                /* Connection handle */
    +   const char *zDbName,        /* Database name or NULL */
    +   const char *zTableName,     /* Table name */
    +@@ -5637,12 +6992,21 @@ SQLITE_API int SQLITE_STDCALL sqlite3_table_column_metadata(
    + ** should free this memory by calling [sqlite3_free()].
    + **
    + ** ^Extension loading must be enabled using
    +-** [sqlite3_enable_load_extension()] prior to calling this API,
    ++** [sqlite3_enable_load_extension()] or
    ++** [sqlite3_db_config](db,[SQLITE_DBCONFIG_ENABLE_LOAD_EXTENSION],1,NULL)
    ++** prior to calling this API,
    + ** otherwise an error will be returned.
    + **
    ++** <b>Security warning:</b> It is recommended that the 
    ++** [SQLITE_DBCONFIG_ENABLE_LOAD_EXTENSION] method be used to enable only this
    ++** interface.  The use of the [sqlite3_enable_load_extension()] interface
    ++** should be avoided.  This will keep the SQL function [load_extension()]
    ++** disabled and prevent SQL injections from giving attackers
    ++** access to extension loading capabilities.
    ++**
    + ** See also the [load_extension() SQL function].
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_load_extension(
    ++SQLITE_API int sqlite3_load_extension(
    +   sqlite3 *db,          /* Load the extension into this database connection */
    +   const char *zFile,    /* Name of the shared library containing extension */
    +   const char *zProc,    /* Entry point.  Derived from zFile if 0 */
    +@@ -5662,8 +7026,19 @@ SQLITE_API int SQLITE_STDCALL sqlite3_load_extension(
    + ** ^Call the sqlite3_enable_load_extension() routine with onoff==1
    + ** to turn extension loading on and call it with onoff==0 to turn
    + ** it back off again.
    ++**
    ++** ^This interface enables or disables both the C-API
    ++** [sqlite3_load_extension()] and the SQL function [load_extension()].
    ++** ^(Use [sqlite3_db_config](db,[SQLITE_DBCONFIG_ENABLE_LOAD_EXTENSION],..)
    ++** to enable or disable only the C-API.)^
    ++**
    ++** <b>Security warning:</b> It is recommended that extension loading
    ++** be disabled using the [SQLITE_DBCONFIG_ENABLE_LOAD_EXTENSION] method
    ++** rather than this interface, so the [load_extension()] SQL function
    ++** remains disabled. This will prevent SQL injections from giving attackers
    ++** access to extension loading capabilities.
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_enable_load_extension(sqlite3 *db, int onoff);
    ++SQLITE_API int sqlite3_enable_load_extension(sqlite3 *db, int onoff);
    + 
    + /*
    + ** CAPI3REF: Automatically Load Statically Linked Extensions
    +@@ -5675,7 +7050,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_enable_load_extension(sqlite3 *db, int ono
    + **
    + ** ^(Even though the function prototype shows that xEntryPoint() takes
    + ** no arguments and returns void, SQLite invokes xEntryPoint() with three
    +-** arguments and expects and integer result as if the signature of the
    ++** arguments and expects an integer result as if the signature of the
    + ** entry point where as follows:
    + **
    + ** <blockquote><pre>
    +@@ -5701,7 +7076,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_enable_load_extension(sqlite3 *db, int ono
    + ** See also: [sqlite3_reset_auto_extension()]
    + ** and [sqlite3_cancel_auto_extension()]
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_auto_extension(void (*xEntryPoint)(void));
    ++SQLITE_API int sqlite3_auto_extension(void(*xEntryPoint)(void));
    + 
    + /*
    + ** CAPI3REF: Cancel Automatic Extension Loading
    +@@ -5713,7 +7088,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_auto_extension(void (*xEntryPoint)(void));
    + ** unregistered and it returns 0 if X was not on the list of initialization
    + ** routines.
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_cancel_auto_extension(void (*xEntryPoint)(void));
    ++SQLITE_API int sqlite3_cancel_auto_extension(void(*xEntryPoint)(void));
    + 
    + /*
    + ** CAPI3REF: Reset Automatic Extension Loading
    +@@ -5721,7 +7096,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_cancel_auto_extension(void (*xEntryPoint)(
    + ** ^This interface disables all automatic extensions previously
    + ** registered using [sqlite3_auto_extension()].
    + */
    +-SQLITE_API void SQLITE_STDCALL sqlite3_reset_auto_extension(void);
    ++SQLITE_API void sqlite3_reset_auto_extension(void);
    + 
    + /*
    + ** The interface to the virtual-table mechanism is currently considered
    +@@ -5823,6 +7198,17 @@ struct sqlite3_module {
    + ** ^Information about the ORDER BY clause is stored in aOrderBy[].
    + ** ^Each term of aOrderBy records a column of the ORDER BY clause.
    + **
    ++** The colUsed field indicates which columns of the virtual table may be
    ++** required by the current scan. Virtual table columns are numbered from
    ++** zero in the order in which they appear within the CREATE TABLE statement
    ++** passed to sqlite3_declare_vtab(). For the first 63 columns (columns 0-62),
    ++** the corresponding bit is set within the colUsed mask if the column may be
    ++** required by SQLite. If the table has at least 64 columns and any column
    ++** to the right of the first 63 is required, then bit 63 of colUsed is also
    ++** set. In other words, column iCol may be required if the expression
    ++** (colUsed & ((sqlite3_uint64)1 << (iCol>=63 ? 63 : iCol))) evaluates to 
    ++** non-zero.
    ++**
    + ** The [xBestIndex] method must fill aConstraintUsage[] with information
    + ** about what parameters to pass to xFilter.  ^If argvIndex>0 then
    + ** the right-hand side of the corresponding aConstraint[] is evaluated
    +@@ -5864,13 +7250,15 @@ struct sqlite3_module {
    + ** the xUpdate method are automatically rolled back by SQLite.
    + **
    + ** IMPORTANT: The estimatedRows field was added to the sqlite3_index_info
    +-** structure for SQLite version 3.8.2. If a virtual table extension is
    ++** structure for SQLite [version 3.8.2] ([dateof:3.8.2]). 
    ++** If a virtual table extension is
    + ** used with an SQLite version earlier than 3.8.2, the results of attempting 
    + ** to read or write the estimatedRows field are undefined (but are likely 
    + ** to included crashing the application). The estimatedRows field should
    + ** therefore only be used if [sqlite3_libversion_number()] returns a
    + ** value greater than or equal to 3008002. Similarly, the idxFlags field
    +-** was added for version 3.9.0. It may therefore only be used if
    ++** was added for [version 3.9.0] ([dateof:3.9.0]). 
    ++** It may therefore only be used if
    + ** sqlite3_libversion_number() returns a value greater than or equal to
    + ** 3009000.
    + */
    +@@ -5878,7 +7266,7 @@ struct sqlite3_index_info {
    +   /* Inputs */
    +   int nConstraint;           /* Number of entries in aConstraint */
    +   struct sqlite3_index_constraint {
    +-     int iColumn;              /* Column on left-hand side of constraint */
    ++     int iColumn;              /* Column constrained.  -1 for ROWID */
    +      unsigned char op;         /* Constraint operator */
    +      unsigned char usable;     /* True if this constraint is usable */
    +      int iTermOffset;          /* Used internally - xBestIndex should ignore */
    +@@ -5902,6 +7290,8 @@ struct sqlite3_index_info {
    +   sqlite3_int64 estimatedRows;    /* Estimated number of rows returned */
    +   /* Fields below are only available in SQLite 3.9.0 and later */
    +   int idxFlags;              /* Mask of SQLITE_INDEX_SCAN_* flags */
    ++  /* Fields below are only available in SQLite 3.10.0 and later */
    ++  sqlite3_uint64 colUsed;    /* Input: Mask of columns used by statement */
    + };
    + 
    + /*
    +@@ -5917,12 +7307,20 @@ struct sqlite3_index_info {
    + ** an operator that is part of a constraint term in the wHERE clause of
    + ** a query that uses a [virtual table].
    + */
    +-#define SQLITE_INDEX_CONSTRAINT_EQ    2
    +-#define SQLITE_INDEX_CONSTRAINT_GT    4
    +-#define SQLITE_INDEX_CONSTRAINT_LE    8
    +-#define SQLITE_INDEX_CONSTRAINT_LT    16
    +-#define SQLITE_INDEX_CONSTRAINT_GE    32
    +-#define SQLITE_INDEX_CONSTRAINT_MATCH 64
    ++#define SQLITE_INDEX_CONSTRAINT_EQ         2
    ++#define SQLITE_INDEX_CONSTRAINT_GT         4
    ++#define SQLITE_INDEX_CONSTRAINT_LE         8
    ++#define SQLITE_INDEX_CONSTRAINT_LT        16
    ++#define SQLITE_INDEX_CONSTRAINT_GE        32
    ++#define SQLITE_INDEX_CONSTRAINT_MATCH     64
    ++#define SQLITE_INDEX_CONSTRAINT_LIKE      65
    ++#define SQLITE_INDEX_CONSTRAINT_GLOB      66
    ++#define SQLITE_INDEX_CONSTRAINT_REGEXP    67
    ++#define SQLITE_INDEX_CONSTRAINT_NE        68
    ++#define SQLITE_INDEX_CONSTRAINT_ISNOT     69
    ++#define SQLITE_INDEX_CONSTRAINT_ISNOTNULL 70
    ++#define SQLITE_INDEX_CONSTRAINT_ISNULL    71
    ++#define SQLITE_INDEX_CONSTRAINT_IS        72
    + 
    + /*
    + ** CAPI3REF: Register A Virtual Table Implementation
    +@@ -5950,13 +7348,13 @@ struct sqlite3_index_info {
    + ** interface is equivalent to sqlite3_create_module_v2() with a NULL
    + ** destructor.
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_create_module(
    ++SQLITE_API int sqlite3_create_module(
    +   sqlite3 *db,               /* SQLite connection to register module with */
    +   const char *zName,         /* Name of the module */
    +   const sqlite3_module *p,   /* Methods for the module */
    +   void *pClientData          /* Client data for xCreate/xConnect */
    + );
    +-SQLITE_API int SQLITE_STDCALL sqlite3_create_module_v2(
    ++SQLITE_API int sqlite3_create_module_v2(
    +   sqlite3 *db,               /* SQLite connection to register module with */
    +   const char *zName,         /* Name of the module */
    +   const sqlite3_module *p,   /* Methods for the module */
    +@@ -6019,7 +7417,7 @@ struct sqlite3_vtab_cursor {
    + ** to declare the format (the names and datatypes of the columns) of
    + ** the virtual tables they implement.
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_declare_vtab(sqlite3*, const char *zSQL);
    ++SQLITE_API int sqlite3_declare_vtab(sqlite3*, const char *zSQL);
    + 
    + /*
    + ** CAPI3REF: Overload A Function For A Virtual Table
    +@@ -6038,7 +7436,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_declare_vtab(sqlite3*, const char *zSQL);
    + ** purpose is to be a placeholder function that can be overloaded
    + ** by a [virtual table].
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_overload_function(sqlite3*, const char *zFuncName, int nArg);
    ++SQLITE_API int sqlite3_overload_function(sqlite3*, const char *zFuncName, int nArg);
    + 
    + /*
    + ** The interface to the virtual-table mechanism defined above (back up
    +@@ -6113,6 +7511,12 @@ typedef struct sqlite3_blob sqlite3_blob;
    + ** [database connection] error code and message accessible via 
    + ** [sqlite3_errcode()] and [sqlite3_errmsg()] and related functions. 
    + **
    ++** A BLOB referenced by sqlite3_blob_open() may be read using the
    ++** [sqlite3_blob_read()] interface and modified by using
    ++** [sqlite3_blob_write()].  The [BLOB handle] can be moved to a
    ++** different row of the same table using the [sqlite3_blob_reopen()]
    ++** interface.  However, the column, table, or database of a [BLOB handle]
    ++** cannot be changed after the [BLOB handle] is opened.
    + **
    + ** ^(If the row that a BLOB handle points to is modified by an
    + ** [UPDATE], [DELETE], or by [ON CONFLICT] side-effects
    +@@ -6136,8 +7540,12 @@ typedef struct sqlite3_blob sqlite3_blob;
    + **
    + ** To avoid a resource leak, every open [BLOB handle] should eventually
    + ** be released by a call to [sqlite3_blob_close()].
    ++**
    ++** See also: [sqlite3_blob_close()],
    ++** [sqlite3_blob_reopen()], [sqlite3_blob_read()],
    ++** [sqlite3_blob_bytes()], [sqlite3_blob_write()].
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_blob_open(
    ++SQLITE_API int sqlite3_blob_open(
    +   sqlite3*,
    +   const char *zDb,
    +   const char *zTable,
    +@@ -6151,11 +7559,11 @@ SQLITE_API int SQLITE_STDCALL sqlite3_blob_open(
    + ** CAPI3REF: Move a BLOB Handle to a New Row
    + ** METHOD: sqlite3_blob
    + **
    +-** ^This function is used to move an existing blob handle so that it points
    ++** ^This function is used to move an existing [BLOB handle] so that it points
    + ** to a different row of the same database table. ^The new row is identified
    + ** by the rowid value passed as the second argument. Only the row can be
    + ** changed. ^The database, table and column on which the blob handle is open
    +-** remain the same. Moving an existing blob handle to a new row can be
    ++** remain the same. Moving an existing [BLOB handle] to a new row is
    + ** faster than closing the existing handle and opening a new one.
    + **
    + ** ^(The new row must meet the same criteria as for [sqlite3_blob_open()] -
    +@@ -6170,7 +7578,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_blob_open(
    + **
    + ** ^This function sets the database handle error code and message.
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_blob_reopen(sqlite3_blob *, sqlite3_int64);
    ++SQLITE_API int sqlite3_blob_reopen(sqlite3_blob *, sqlite3_int64);
    + 
    + /*
    + ** CAPI3REF: Close A BLOB Handle
    +@@ -6193,7 +7601,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_blob_reopen(sqlite3_blob *, sqlite3_int64)
    + ** is passed a valid open blob handle, the values returned by the 
    + ** sqlite3_errcode() and sqlite3_errmsg() functions are set before returning.
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_blob_close(sqlite3_blob *);
    ++SQLITE_API int sqlite3_blob_close(sqlite3_blob *);
    + 
    + /*
    + ** CAPI3REF: Return The Size Of An Open BLOB
    +@@ -6209,7 +7617,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_blob_close(sqlite3_blob *);
    + ** been closed by [sqlite3_blob_close()].  Passing any other pointer in
    + ** to this routine results in undefined and probably undesirable behavior.
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_blob_bytes(sqlite3_blob *);
    ++SQLITE_API int sqlite3_blob_bytes(sqlite3_blob *);
    + 
    + /*
    + ** CAPI3REF: Read Data From A BLOB Incrementally
    +@@ -6238,7 +7646,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_blob_bytes(sqlite3_blob *);
    + **
    + ** See also: [sqlite3_blob_write()].
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_blob_read(sqlite3_blob *, void *Z, int N, int iOffset);
    ++SQLITE_API int sqlite3_blob_read(sqlite3_blob *, void *Z, int N, int iOffset);
    + 
    + /*
    + ** CAPI3REF: Write Data Into A BLOB Incrementally
    +@@ -6280,7 +7688,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_blob_read(sqlite3_blob *, void *Z, int N,
    + **
    + ** See also: [sqlite3_blob_read()].
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_blob_write(sqlite3_blob *, const void *z, int n, int iOffset);
    ++SQLITE_API int sqlite3_blob_write(sqlite3_blob *, const void *z, int n, int iOffset);
    + 
    + /*
    + ** CAPI3REF: Virtual File System Objects
    +@@ -6311,9 +7719,9 @@ SQLITE_API int SQLITE_STDCALL sqlite3_blob_write(sqlite3_blob *, const void *z,
    + ** ^(If the default VFS is unregistered, another VFS is chosen as
    + ** the default.  The choice for the new VFS is arbitrary.)^
    + */
    +-SQLITE_API sqlite3_vfs *SQLITE_STDCALL sqlite3_vfs_find(const char *zVfsName);
    +-SQLITE_API int SQLITE_STDCALL sqlite3_vfs_register(sqlite3_vfs*, int makeDflt);
    +-SQLITE_API int SQLITE_STDCALL sqlite3_vfs_unregister(sqlite3_vfs*);
    ++SQLITE_API sqlite3_vfs *sqlite3_vfs_find(const char *zVfsName);
    ++SQLITE_API int sqlite3_vfs_register(sqlite3_vfs*, int makeDflt);
    ++SQLITE_API int sqlite3_vfs_unregister(sqlite3_vfs*);
    + 
    + /*
    + ** CAPI3REF: Mutexes
    +@@ -6429,11 +7837,11 @@ SQLITE_API int SQLITE_STDCALL sqlite3_vfs_unregister(sqlite3_vfs*);
    + **
    + ** See also: [sqlite3_mutex_held()] and [sqlite3_mutex_notheld()].
    + */
    +-SQLITE_API sqlite3_mutex *SQLITE_STDCALL sqlite3_mutex_alloc(int);
    +-SQLITE_API void SQLITE_STDCALL sqlite3_mutex_free(sqlite3_mutex*);
    +-SQLITE_API void SQLITE_STDCALL sqlite3_mutex_enter(sqlite3_mutex*);
    +-SQLITE_API int SQLITE_STDCALL sqlite3_mutex_try(sqlite3_mutex*);
    +-SQLITE_API void SQLITE_STDCALL sqlite3_mutex_leave(sqlite3_mutex*);
    ++SQLITE_API sqlite3_mutex *sqlite3_mutex_alloc(int);
    ++SQLITE_API void sqlite3_mutex_free(sqlite3_mutex*);
    ++SQLITE_API void sqlite3_mutex_enter(sqlite3_mutex*);
    ++SQLITE_API int sqlite3_mutex_try(sqlite3_mutex*);
    ++SQLITE_API void sqlite3_mutex_leave(sqlite3_mutex*);
    + 
    + /*
    + ** CAPI3REF: Mutex Methods Object
    +@@ -6543,8 +7951,8 @@ struct sqlite3_mutex_methods {
    + ** interface should also return 1 when given a NULL pointer.
    + */
    + #ifndef NDEBUG
    +-SQLITE_API int SQLITE_STDCALL sqlite3_mutex_held(sqlite3_mutex*);
    +-SQLITE_API int SQLITE_STDCALL sqlite3_mutex_notheld(sqlite3_mutex*);
    ++SQLITE_API int sqlite3_mutex_held(sqlite3_mutex*);
    ++SQLITE_API int sqlite3_mutex_notheld(sqlite3_mutex*);
    + #endif
    + 
    + /*
    +@@ -6563,7 +7971,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_mutex_notheld(sqlite3_mutex*);
    + #define SQLITE_MUTEX_STATIC_MEM       3  /* sqlite3_malloc() */
    + #define SQLITE_MUTEX_STATIC_MEM2      4  /* NOT USED */
    + #define SQLITE_MUTEX_STATIC_OPEN      4  /* sqlite3BtreeOpen() */
    +-#define SQLITE_MUTEX_STATIC_PRNG      5  /* sqlite3_random() */
    ++#define SQLITE_MUTEX_STATIC_PRNG      5  /* sqlite3_randomness() */
    + #define SQLITE_MUTEX_STATIC_LRU       6  /* lru page list */
    + #define SQLITE_MUTEX_STATIC_LRU2      7  /* NOT USED */
    + #define SQLITE_MUTEX_STATIC_PMEM      7  /* sqlite3PageMalloc() */
    +@@ -6584,7 +7992,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_mutex_notheld(sqlite3_mutex*);
    + ** ^If the [threading mode] is Single-thread or Multi-thread then this
    + ** routine returns a NULL pointer.
    + */
    +-SQLITE_API sqlite3_mutex *SQLITE_STDCALL sqlite3_db_mutex(sqlite3*);
    ++SQLITE_API sqlite3_mutex *sqlite3_db_mutex(sqlite3*);
    + 
    + /*
    + ** CAPI3REF: Low-Level Control Of Database Files
    +@@ -6603,9 +8011,9 @@ SQLITE_API sqlite3_mutex *SQLITE_STDCALL sqlite3_db_mutex(sqlite3*);
    + ** the xFileControl method.  ^The return value of the xFileControl
    + ** method becomes the return value of this routine.
    + **
    +-** ^The SQLITE_FCNTL_FILE_POINTER value for the op parameter causes
    ++** ^The [SQLITE_FCNTL_FILE_POINTER] value for the op parameter causes
    + ** a pointer to the underlying [sqlite3_file] object to be written into
    +-** the space pointed to by the 4th parameter.  ^The SQLITE_FCNTL_FILE_POINTER
    ++** the space pointed to by the 4th parameter.  ^The [SQLITE_FCNTL_FILE_POINTER]
    + ** case is a short-circuit path which does not actually invoke the
    + ** underlying sqlite3_io_methods.xFileControl method.
    + **
    +@@ -6617,9 +8025,9 @@ SQLITE_API sqlite3_mutex *SQLITE_STDCALL sqlite3_db_mutex(sqlite3*);
    + ** an incorrect zDbName and an SQLITE_ERROR return from the underlying
    + ** xFileControl method.
    + **
    +-** See also: [SQLITE_FCNTL_LOCKSTATE]
    ++** See also: [file control opcodes]
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_file_control(sqlite3*, const char *zDbName, int op, void*);
    ++SQLITE_API int sqlite3_file_control(sqlite3*, const char *zDbName, int op, void*);
    + 
    + /*
    + ** CAPI3REF: Testing Interface
    +@@ -6638,7 +8046,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_file_control(sqlite3*, const char *zDbName
    + ** Unlike most of the SQLite API, this function is not guaranteed to
    + ** operate consistently from one release to the next.
    + */
    +-SQLITE_API int SQLITE_CDECL sqlite3_test_control(int op, ...);
    ++SQLITE_API int sqlite3_test_control(int op, ...);
    + 
    + /*
    + ** CAPI3REF: Testing Interface Operation Codes
    +@@ -6664,16 +8072,18 @@ SQLITE_API int SQLITE_CDECL sqlite3_test_control(int op, ...);
    + #define SQLITE_TESTCTRL_RESERVE                 14
    + #define SQLITE_TESTCTRL_OPTIMIZATIONS           15
    + #define SQLITE_TESTCTRL_ISKEYWORD               16
    +-#define SQLITE_TESTCTRL_SCRATCHMALLOC           17
    ++#define SQLITE_TESTCTRL_SCRATCHMALLOC           17  /* NOT USED */
    + #define SQLITE_TESTCTRL_LOCALTIME_FAULT         18
    + #define SQLITE_TESTCTRL_EXPLAIN_STMT            19  /* NOT USED */
    ++#define SQLITE_TESTCTRL_ONCE_RESET_THRESHOLD    19
    + #define SQLITE_TESTCTRL_NEVER_CORRUPT           20
    + #define SQLITE_TESTCTRL_VDBE_COVERAGE           21
    + #define SQLITE_TESTCTRL_BYTEORDER               22
    + #define SQLITE_TESTCTRL_ISINIT                  23
    + #define SQLITE_TESTCTRL_SORTER_MMAP             24
    + #define SQLITE_TESTCTRL_IMPOSTER                25
    +-#define SQLITE_TESTCTRL_LAST                    25
    ++#define SQLITE_TESTCTRL_PARSER_COVERAGE         26
    ++#define SQLITE_TESTCTRL_LAST                    26  /* Largest TESTCTRL */
    + 
    + /*
    + ** CAPI3REF: SQLite Runtime Status
    +@@ -6701,8 +8111,8 @@ SQLITE_API int SQLITE_CDECL sqlite3_test_control(int op, ...);
    + **
    + ** See also: [sqlite3_db_status()]
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_status(int op, int *pCurrent, int *pHighwater, int resetFlag);
    +-SQLITE_API int SQLITE_STDCALL sqlite3_status64(
    ++SQLITE_API int sqlite3_status(int op, int *pCurrent, int *pHighwater, int resetFlag);
    ++SQLITE_API int sqlite3_status64(
    +   int op,
    +   sqlite3_int64 *pCurrent,
    +   sqlite3_int64 *pHighwater,
    +@@ -6722,8 +8132,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_status64(
    + ** <dd>This parameter is the current amount of memory checked out
    + ** using [sqlite3_malloc()], either directly or indirectly.  The
    + ** figure includes calls made to [sqlite3_malloc()] by the application
    +-** and internal memory usage by the SQLite library.  Scratch memory
    +-** controlled by [SQLITE_CONFIG_SCRATCH] and auxiliary page-cache
    ++** and internal memory usage by the SQLite library.  Auxiliary page-cache
    + ** memory controlled by [SQLITE_CONFIG_PAGECACHE] is not included in
    + ** this parameter.  The amount returned is the sum of the allocation
    + ** sizes as reported by the xSize method in [sqlite3_mem_methods].</dd>)^
    +@@ -6761,32 +8170,18 @@ SQLITE_API int SQLITE_STDCALL sqlite3_status64(
    + ** *pHighwater parameter to [sqlite3_status()] is of interest.  
    + ** The value written into the *pCurrent parameter is undefined.</dd>)^
    + **
    +-** [[SQLITE_STATUS_SCRATCH_USED]] ^(<dt>SQLITE_STATUS_SCRATCH_USED</dt>
    +-** <dd>This parameter returns the number of allocations used out of the
    +-** [scratch memory allocator] configured using
    +-** [SQLITE_CONFIG_SCRATCH].  The value returned is in allocations, not
    +-** in bytes.  Since a single thread may only have one scratch allocation
    +-** outstanding at time, this parameter also reports the number of threads
    +-** using scratch memory at the same time.</dd>)^
    ++** [[SQLITE_STATUS_SCRATCH_USED]] <dt>SQLITE_STATUS_SCRATCH_USED</dt>
    ++** <dd>No longer used.</dd>
    + **
    + ** [[SQLITE_STATUS_SCRATCH_OVERFLOW]] ^(<dt>SQLITE_STATUS_SCRATCH_OVERFLOW</dt>
    +-** <dd>This parameter returns the number of bytes of scratch memory
    +-** allocation which could not be satisfied by the [SQLITE_CONFIG_SCRATCH]
    +-** buffer and where forced to overflow to [sqlite3_malloc()].  The values
    +-** returned include overflows because the requested allocation was too
    +-** larger (that is, because the requested allocation was larger than the
    +-** "sz" parameter to [SQLITE_CONFIG_SCRATCH]) and because no scratch buffer
    +-** slots were available.
    +-** </dd>)^
    +-**
    +-** [[SQLITE_STATUS_SCRATCH_SIZE]] ^(<dt>SQLITE_STATUS_SCRATCH_SIZE</dt>
    +-** <dd>This parameter records the largest memory allocation request
    +-** handed to [scratch memory allocator].  Only the value returned in the
    +-** *pHighwater parameter to [sqlite3_status()] is of interest.  
    +-** The value written into the *pCurrent parameter is undefined.</dd>)^
    ++** <dd>No longer used.</dd>
    ++**
    ++** [[SQLITE_STATUS_SCRATCH_SIZE]] <dt>SQLITE_STATUS_SCRATCH_SIZE</dt>
    ++** <dd>No longer used.</dd>
    + **
    + ** [[SQLITE_STATUS_PARSER_STACK]] ^(<dt>SQLITE_STATUS_PARSER_STACK</dt>
    +-** <dd>This parameter records the deepest parser stack.  It is only
    ++** <dd>The *pHighwater parameter records the deepest parser stack. 
    ++** The *pCurrent value is undefined.  The *pHighwater value is only
    + ** meaningful if SQLite is compiled with [YYTRACKMAXSTACKDEPTH].</dd>)^
    + ** </dl>
    + **
    +@@ -6795,12 +8190,12 @@ SQLITE_API int SQLITE_STDCALL sqlite3_status64(
    + #define SQLITE_STATUS_MEMORY_USED          0
    + #define SQLITE_STATUS_PAGECACHE_USED       1
    + #define SQLITE_STATUS_PAGECACHE_OVERFLOW   2
    +-#define SQLITE_STATUS_SCRATCH_USED         3
    +-#define SQLITE_STATUS_SCRATCH_OVERFLOW     4
    ++#define SQLITE_STATUS_SCRATCH_USED         3  /* NOT USED */
    ++#define SQLITE_STATUS_SCRATCH_OVERFLOW     4  /* NOT USED */
    + #define SQLITE_STATUS_MALLOC_SIZE          5
    + #define SQLITE_STATUS_PARSER_STACK         6
    + #define SQLITE_STATUS_PAGECACHE_SIZE       7
    +-#define SQLITE_STATUS_SCRATCH_SIZE         8
    ++#define SQLITE_STATUS_SCRATCH_SIZE         8  /* NOT USED */
    + #define SQLITE_STATUS_MALLOC_COUNT         9
    + 
    + /*
    +@@ -6826,7 +8221,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_status64(
    + **
    + ** See also: [sqlite3_status()] and [sqlite3_stmt_status()].
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_db_status(sqlite3*, int op, int *pCur, int *pHiwtr, int resetFlg);
    ++SQLITE_API int sqlite3_db_status(sqlite3*, int op, int *pCur, int *pHiwtr, int resetFlg);
    + 
    + /*
    + ** CAPI3REF: Status Parameters for database connections
    +@@ -6872,6 +8267,18 @@ SQLITE_API int SQLITE_STDCALL sqlite3_db_status(sqlite3*, int op, int *pCur, int
    + ** memory used by all pager caches associated with the database connection.)^
    + ** ^The highwater mark associated with SQLITE_DBSTATUS_CACHE_USED is always 0.
    + **
    ++** [[SQLITE_DBSTATUS_CACHE_USED_SHARED]] 
    ++** ^(<dt>SQLITE_DBSTATUS_CACHE_USED_SHARED</dt>
    ++** <dd>This parameter is similar to DBSTATUS_CACHE_USED, except that if a
    ++** pager cache is shared between two or more connections the bytes of heap
    ++** memory used by that pager cache is divided evenly between the attached
    ++** connections.)^  In other words, if none of the pager caches associated
    ++** with the database connection are shared, this request returns the same
    ++** value as DBSTATUS_CACHE_USED. Or, if one or more or the pager caches are
    ++** shared, the value returned by this call will be smaller than that returned
    ++** by DBSTATUS_CACHE_USED. ^The highwater mark associated with
    ++** SQLITE_DBSTATUS_CACHE_USED_SHARED is always 0.
    ++**
    + ** [[SQLITE_DBSTATUS_SCHEMA_USED]] ^(<dt>SQLITE_DBSTATUS_SCHEMA_USED</dt>
    + ** <dd>This parameter returns the approximate number of bytes of heap
    + ** memory used to store the schema for all databases associated
    +@@ -6929,7 +8336,8 @@ SQLITE_API int SQLITE_STDCALL sqlite3_db_status(sqlite3*, int op, int *pCur, int
    + #define SQLITE_DBSTATUS_CACHE_MISS           8
    + #define SQLITE_DBSTATUS_CACHE_WRITE          9
    + #define SQLITE_DBSTATUS_DEFERRED_FKS        10
    +-#define SQLITE_DBSTATUS_MAX                 10   /* Largest defined DBSTATUS */
    ++#define SQLITE_DBSTATUS_CACHE_USED_SHARED   11
    ++#define SQLITE_DBSTATUS_MAX                 11   /* Largest defined DBSTATUS */
    + 
    + 
    + /*
    +@@ -6956,7 +8364,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_db_status(sqlite3*, int op, int *pCur, int
    + **
    + ** See also: [sqlite3_status()] and [sqlite3_db_status()].
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_stmt_status(sqlite3_stmt*, int op,int resetFlg);
    ++SQLITE_API int sqlite3_stmt_status(sqlite3_stmt*, int op,int resetFlg);
    + 
    + /*
    + ** CAPI3REF: Status Parameters for prepared statements
    +@@ -6992,6 +8400,24 @@ SQLITE_API int SQLITE_STDCALL sqlite3_stmt_status(sqlite3_stmt*, int op,int rese
    + ** used as a proxy for the total work done by the prepared statement.
    + ** If the number of virtual machine operations exceeds 2147483647
    + ** then the value returned by this statement status code is undefined.
    ++**
    ++** [[SQLITE_STMTSTATUS_REPREPARE]] <dt>SQLITE_STMTSTATUS_REPREPARE</dt>
    ++** <dd>^This is the number of times that the prepare statement has been
    ++** automatically regenerated due to schema changes or change to 
    ++** [bound parameters] that might affect the query plan.
    ++**
    ++** [[SQLITE_STMTSTATUS_RUN]] <dt>SQLITE_STMTSTATUS_RUN</dt>
    ++** <dd>^This is the number of times that the prepared statement has
    ++** been run.  A single "run" for the purposes of this counter is one
    ++** or more calls to [sqlite3_step()] followed by a call to [sqlite3_reset()].
    ++** The counter is incremented on the first [sqlite3_step()] call of each
    ++** cycle.
    ++**
    ++** [[SQLITE_STMTSTATUS_MEMUSED]] <dt>SQLITE_STMTSTATUS_MEMUSED</dt>
    ++** <dd>^This is the approximate number of bytes of heap memory
    ++** used to store the prepared statement.  ^This value is not actually
    ++** a counter, and so the resetFlg parameter to sqlite3_stmt_status()
    ++** is ignored when the opcode is SQLITE_STMTSTATUS_MEMUSED.
    + ** </dd>
    + ** </dl>
    + */
    +@@ -6999,6 +8425,9 @@ SQLITE_API int SQLITE_STDCALL sqlite3_stmt_status(sqlite3_stmt*, int op,int rese
    + #define SQLITE_STMTSTATUS_SORT              2
    + #define SQLITE_STMTSTATUS_AUTOINDEX         3
    + #define SQLITE_STMTSTATUS_VM_STEP           4
    ++#define SQLITE_STMTSTATUS_REPREPARE         5
    ++#define SQLITE_STMTSTATUS_RUN               6
    ++#define SQLITE_STMTSTATUS_MEMUSED           99
    + 
    + /*
    + ** CAPI3REF: Custom Page Cache Object
    +@@ -7283,7 +8712,7 @@ typedef struct sqlite3_backup sqlite3_backup;
    + ** must be different or else sqlite3_backup_init(D,N,S,M) will fail with
    + ** an error.
    + **
    +-** ^A call to sqlite3_backup_init() will fail, returning SQLITE_ERROR, if 
    ++** ^A call to sqlite3_backup_init() will fail, returning NULL, if 
    + ** there is already a read or read-write transaction open on the 
    + ** destination database.
    + **
    +@@ -7425,16 +8854,16 @@ typedef struct sqlite3_backup sqlite3_backup;
    + ** same time as another thread is invoking sqlite3_backup_step() it is
    + ** possible that they return invalid values.
    + */
    +-SQLITE_API sqlite3_backup *SQLITE_STDCALL sqlite3_backup_init(
    ++SQLITE_API sqlite3_backup *sqlite3_backup_init(
    +   sqlite3 *pDest,                        /* Destination database handle */
    +   const char *zDestName,                 /* Destination database name */
    +   sqlite3 *pSource,                      /* Source database handle */
    +   const char *zSourceName                /* Source database name */
    + );
    +-SQLITE_API int SQLITE_STDCALL sqlite3_backup_step(sqlite3_backup *p, int nPage);
    +-SQLITE_API int SQLITE_STDCALL sqlite3_backup_finish(sqlite3_backup *p);
    +-SQLITE_API int SQLITE_STDCALL sqlite3_backup_remaining(sqlite3_backup *p);
    +-SQLITE_API int SQLITE_STDCALL sqlite3_backup_pagecount(sqlite3_backup *p);
    ++SQLITE_API int sqlite3_backup_step(sqlite3_backup *p, int nPage);
    ++SQLITE_API int sqlite3_backup_finish(sqlite3_backup *p);
    ++SQLITE_API int sqlite3_backup_remaining(sqlite3_backup *p);
    ++SQLITE_API int sqlite3_backup_pagecount(sqlite3_backup *p);
    + 
    + /*
    + ** CAPI3REF: Unlock Notification
    +@@ -7551,7 +8980,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_backup_pagecount(sqlite3_backup *p);
    + ** the special "DROP TABLE/INDEX" case, the extended error code is just 
    + ** SQLITE_LOCKED.)^
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_unlock_notify(
    ++SQLITE_API int sqlite3_unlock_notify(
    +   sqlite3 *pBlocked,                          /* Waiting connection */
    +   void (*xNotify)(void **apArg, int nArg),    /* Callback function to invoke */
    +   void *pNotifyArg                            /* Argument to pass to xNotify */
    +@@ -7566,23 +8995,48 @@ SQLITE_API int SQLITE_STDCALL sqlite3_unlock_notify(
    + ** strings in a case-independent fashion, using the same definition of "case
    + ** independence" that SQLite uses internally when comparing identifiers.
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_stricmp(const char *, const char *);
    +-SQLITE_API int SQLITE_STDCALL sqlite3_strnicmp(const char *, const char *, int);
    ++SQLITE_API int sqlite3_stricmp(const char *, const char *);
    ++SQLITE_API int sqlite3_strnicmp(const char *, const char *, int);
    + 
    + /*
    + ** CAPI3REF: String Globbing
    + *
    +-** ^The [sqlite3_strglob(P,X)] interface returns zero if string X matches
    +-** the glob pattern P, and it returns non-zero if string X does not match
    +-** the glob pattern P.  ^The definition of glob pattern matching used in
    ++** ^The [sqlite3_strglob(P,X)] interface returns zero if and only if
    ++** string X matches the [GLOB] pattern P.
    ++** ^The definition of [GLOB] pattern matching used in
    + ** [sqlite3_strglob(P,X)] is the same as for the "X GLOB P" operator in the
    +-** SQL dialect used by SQLite.  ^The sqlite3_strglob(P,X) function is case
    +-** sensitive.
    ++** SQL dialect understood by SQLite.  ^The [sqlite3_strglob(P,X)] function
    ++** is case sensitive.
    ++**
    ++** Note that this routine returns zero on a match and non-zero if the strings
    ++** do not match, the same as [sqlite3_stricmp()] and [sqlite3_strnicmp()].
    ++**
    ++** See also: [sqlite3_strlike()].
    ++*/
    ++SQLITE_API int sqlite3_strglob(const char *zGlob, const char *zStr);
    ++
    ++/*
    ++** CAPI3REF: String LIKE Matching
    ++*
    ++** ^The [sqlite3_strlike(P,X,E)] interface returns zero if and only if
    ++** string X matches the [LIKE] pattern P with escape character E.
    ++** ^The definition of [LIKE] pattern matching used in
    ++** [sqlite3_strlike(P,X,E)] is the same as for the "X LIKE P ESCAPE E"
    ++** operator in the SQL dialect understood by SQLite.  ^For "X LIKE P" without
    ++** the ESCAPE clause, set the E parameter of [sqlite3_strlike(P,X,E)] to 0.
    ++** ^As with the LIKE operator, the [sqlite3_strlike(P,X,E)] function is case
    ++** insensitive - equivalent upper and lower case ASCII characters match
    ++** one another.
    ++**
    ++** ^The [sqlite3_strlike(P,X,E)] function matches Unicode characters, though
    ++** only ASCII characters are case folded.
    + **
    + ** Note that this routine returns zero on a match and non-zero if the strings
    + ** do not match, the same as [sqlite3_stricmp()] and [sqlite3_strnicmp()].
    ++**
    ++** See also: [sqlite3_strglob()].
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_strglob(const char *zGlob, const char *zStr);
    ++SQLITE_API int sqlite3_strlike(const char *zGlob, const char *zStr, unsigned int cEsc);
    + 
    + /*
    + ** CAPI3REF: Error Logging Interface
    +@@ -7605,7 +9059,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_strglob(const char *zGlob, const char *zSt
    + ** a few hundred characters, it will be truncated to the length of the
    + ** buffer.
    + */
    +-SQLITE_API void SQLITE_CDECL sqlite3_log(int iErrCode, const char *zFormat, ...);
    ++SQLITE_API void sqlite3_log(int iErrCode, const char *zFormat, ...);
    + 
    + /*
    + ** CAPI3REF: Write-Ahead Log Commit Hook
    +@@ -7639,9 +9093,9 @@ SQLITE_API void SQLITE_CDECL sqlite3_log(int iErrCode, const char *zFormat, ...)
    + ** previously registered write-ahead log callback. ^Note that the
    + ** [sqlite3_wal_autocheckpoint()] interface and the
    + ** [wal_autocheckpoint pragma] both invoke [sqlite3_wal_hook()] and will
    +-** those overwrite any prior [sqlite3_wal_hook()] settings.
    ++** overwrite any prior [sqlite3_wal_hook()] settings.
    + */
    +-SQLITE_API void *SQLITE_STDCALL sqlite3_wal_hook(
    ++SQLITE_API void *sqlite3_wal_hook(
    +   sqlite3*, 
    +   int(*)(void *,sqlite3*,const char*,int),
    +   void*
    +@@ -7676,7 +9130,7 @@ SQLITE_API void *SQLITE_STDCALL sqlite3_wal_hook(
    + ** is only necessary if the default setting is found to be suboptimal
    + ** for a particular application.
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_wal_autocheckpoint(sqlite3 *db, int N);
    ++SQLITE_API int sqlite3_wal_autocheckpoint(sqlite3 *db, int N);
    + 
    + /*
    + ** CAPI3REF: Checkpoint a database
    +@@ -7698,7 +9152,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_wal_autocheckpoint(sqlite3 *db, int N);
    + ** start a callback but which do not need the full power (and corresponding
    + ** complication) of [sqlite3_wal_checkpoint_v2()].
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_wal_checkpoint(sqlite3 *db, const char *zDb);
    ++SQLITE_API int sqlite3_wal_checkpoint(sqlite3 *db, const char *zDb);
    + 
    + /*
    + ** CAPI3REF: Checkpoint a database
    +@@ -7792,7 +9246,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_wal_checkpoint(sqlite3 *db, const char *zD
    + ** ^The [PRAGMA wal_checkpoint] command can be used to invoke this interface
    + ** from SQL.
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_wal_checkpoint_v2(
    ++SQLITE_API int sqlite3_wal_checkpoint_v2(
    +   sqlite3 *db,                    /* Database handle */
    +   const char *zDb,                /* Name of attached database (or NULL) */
    +   int eMode,                      /* SQLITE_CHECKPOINT_* value */
    +@@ -7828,7 +9282,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_wal_checkpoint_v2(
    + ** this function. (See [SQLITE_VTAB_CONSTRAINT_SUPPORT].)  Further options
    + ** may be added in the future.
    + */
    +-SQLITE_API int SQLITE_CDECL sqlite3_vtab_config(sqlite3*, int op, ...);
    ++SQLITE_API int sqlite3_vtab_config(sqlite3*, int op, ...);
    + 
    + /*
    + ** CAPI3REF: Virtual Table Configuration Options
    +@@ -7881,7 +9335,41 @@ SQLITE_API int SQLITE_CDECL sqlite3_vtab_config(sqlite3*, int op, ...);
    + ** of the SQL statement that triggered the call to the [xUpdate] method of the
    + ** [virtual table].
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_vtab_on_conflict(sqlite3 *);
    ++SQLITE_API int sqlite3_vtab_on_conflict(sqlite3 *);
    ++
    ++/*
    ++** CAPI3REF: Determine If Virtual Table Column Access Is For UPDATE
    ++**
    ++** If the sqlite3_vtab_nochange(X) routine is called within the [xColumn]
    ++** method of a [virtual table], then it returns true if and only if the
    ++** column is being fetched as part of an UPDATE operation during which the
    ++** column value will not change.  Applications might use this to substitute
    ++** a lighter-weight value to return that the corresponding [xUpdate] method
    ++** understands as a "no-change" value.
    ++**
    ++** If the [xColumn] method calls sqlite3_vtab_nochange() and finds that
    ++** the column is not changed by the UPDATE statement, they the xColumn
    ++** method can optionally return without setting a result, without calling
    ++** any of the [sqlite3_result_int|sqlite3_result_xxxxx() interfaces].
    ++** In that case, [sqlite3_value_nochange(X)] will return true for the
    ++** same column in the [xUpdate] method.
    ++*/
    ++SQLITE_API int sqlite3_vtab_nochange(sqlite3_context*);
    ++
    ++/*
    ++** CAPI3REF: Determine The Collation For a Virtual Table Constraint
    ++**
    ++** This function may only be called from within a call to the [xBestIndex]
    ++** method of a [virtual table]. 
    ++**
    ++** The first argument must be the sqlite3_index_info object that is the
    ++** first parameter to the xBestIndex() method. The second argument must be
    ++** an index into the aConstraint[] array belonging to the sqlite3_index_info
    ++** structure passed to xBestIndex. This function returns a pointer to a buffer 
    ++** containing the name of the collation sequence for the corresponding
    ++** constraint.
    ++*/
    ++SQLITE_API SQLITE_EXPERIMENTAL const char *sqlite3_vtab_collation(sqlite3_index_info*,int);
    + 
    + /*
    + ** CAPI3REF: Conflict resolution modes
    +@@ -7986,7 +9474,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_vtab_on_conflict(sqlite3 *);
    + **
    + ** See also: [sqlite3_stmt_scanstatus_reset()]
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_stmt_scanstatus(
    ++SQLITE_API int sqlite3_stmt_scanstatus(
    +   sqlite3_stmt *pStmt,      /* Prepared statement for which info desired */
    +   int idx,                  /* Index of loop to report on */
    +   int iScanStatusOp,        /* Information desired.  SQLITE_SCANSTAT_* */
    +@@ -8002,8 +9490,332 @@ SQLITE_API int SQLITE_STDCALL sqlite3_stmt_scanstatus(
    + ** This API is only available if the library is built with pre-processor
    + ** symbol [SQLITE_ENABLE_STMT_SCANSTATUS] defined.
    + */
    +-SQLITE_API void SQLITE_STDCALL sqlite3_stmt_scanstatus_reset(sqlite3_stmt*);
    ++SQLITE_API void sqlite3_stmt_scanstatus_reset(sqlite3_stmt*);
    ++
    ++/*
    ++** CAPI3REF: Flush caches to disk mid-transaction
    ++**
    ++** ^If a write-transaction is open on [database connection] D when the
    ++** [sqlite3_db_cacheflush(D)] interface invoked, any dirty
    ++** pages in the pager-cache that are not currently in use are written out 
    ++** to disk. A dirty page may be in use if a database cursor created by an
    ++** active SQL statement is reading from it, or if it is page 1 of a database
    ++** file (page 1 is always "in use").  ^The [sqlite3_db_cacheflush(D)]
    ++** interface flushes caches for all schemas - "main", "temp", and
    ++** any [attached] databases.
    ++**
    ++** ^If this function needs to obtain extra database locks before dirty pages 
    ++** can be flushed to disk, it does so. ^If those locks cannot be obtained 
    ++** immediately and there is a busy-handler callback configured, it is invoked
    ++** in the usual manner. ^If the required lock still cannot be obtained, then
    ++** the database is skipped and an attempt made to flush any dirty pages
    ++** belonging to the next (if any) database. ^If any databases are skipped
    ++** because locks cannot be obtained, but no other error occurs, this
    ++** function returns SQLITE_BUSY.
    ++**
    ++** ^If any other error occurs while flushing dirty pages to disk (for
    ++** example an IO error or out-of-memory condition), then processing is
    ++** abandoned and an SQLite [error code] is returned to the caller immediately.
    ++**
    ++** ^Otherwise, if no error occurs, [sqlite3_db_cacheflush()] returns SQLITE_OK.
    ++**
    ++** ^This function does not set the database handle error code or message
    ++** returned by the [sqlite3_errcode()] and [sqlite3_errmsg()] functions.
    ++*/
    ++SQLITE_API int sqlite3_db_cacheflush(sqlite3*);
    ++
    ++/*
    ++** CAPI3REF: The pre-update hook.
    ++**
    ++** ^These interfaces are only available if SQLite is compiled using the
    ++** [SQLITE_ENABLE_PREUPDATE_HOOK] compile-time option.
    ++**
    ++** ^The [sqlite3_preupdate_hook()] interface registers a callback function
    ++** that is invoked prior to each [INSERT], [UPDATE], and [DELETE] operation
    ++** on a database table.
    ++** ^At most one preupdate hook may be registered at a time on a single
    ++** [database connection]; each call to [sqlite3_preupdate_hook()] overrides
    ++** the previous setting.
    ++** ^The preupdate hook is disabled by invoking [sqlite3_preupdate_hook()]
    ++** with a NULL pointer as the second parameter.
    ++** ^The third parameter to [sqlite3_preupdate_hook()] is passed through as
    ++** the first parameter to callbacks.
    ++**
    ++** ^The preupdate hook only fires for changes to real database tables; the
    ++** preupdate hook is not invoked for changes to [virtual tables] or to
    ++** system tables like sqlite_master or sqlite_stat1.
    ++**
    ++** ^The second parameter to the preupdate callback is a pointer to
    ++** the [database connection] that registered the preupdate hook.
    ++** ^The third parameter to the preupdate callback is one of the constants
    ++** [SQLITE_INSERT], [SQLITE_DELETE], or [SQLITE_UPDATE] to identify the
    ++** kind of update operation that is about to occur.
    ++** ^(The fourth parameter to the preupdate callback is the name of the
    ++** database within the database connection that is being modified.  This
    ++** will be "main" for the main database or "temp" for TEMP tables or 
    ++** the name given after the AS keyword in the [ATTACH] statement for attached
    ++** databases.)^
    ++** ^The fifth parameter to the preupdate callback is the name of the
    ++** table that is being modified.
    ++**
    ++** For an UPDATE or DELETE operation on a [rowid table], the sixth
    ++** parameter passed to the preupdate callback is the initial [rowid] of the 
    ++** row being modified or deleted. For an INSERT operation on a rowid table,
    ++** or any operation on a WITHOUT ROWID table, the value of the sixth 
    ++** parameter is undefined. For an INSERT or UPDATE on a rowid table the
    ++** seventh parameter is the final rowid value of the row being inserted
    ++** or updated. The value of the seventh parameter passed to the callback
    ++** function is not defined for operations on WITHOUT ROWID tables, or for
    ++** INSERT operations on rowid tables.
    ++**
    ++** The [sqlite3_preupdate_old()], [sqlite3_preupdate_new()],
    ++** [sqlite3_preupdate_count()], and [sqlite3_preupdate_depth()] interfaces
    ++** provide additional information about a preupdate event. These routines
    ++** may only be called from within a preupdate callback.  Invoking any of
    ++** these routines from outside of a preupdate callback or with a
    ++** [database connection] pointer that is different from the one supplied
    ++** to the preupdate callback results in undefined and probably undesirable
    ++** behavior.
    ++**
    ++** ^The [sqlite3_preupdate_count(D)] interface returns the number of columns
    ++** in the row that is being inserted, updated, or deleted.
    ++**
    ++** ^The [sqlite3_preupdate_old(D,N,P)] interface writes into P a pointer to
    ++** a [protected sqlite3_value] that contains the value of the Nth column of
    ++** the table row before it is updated.  The N parameter must be between 0
    ++** and one less than the number of columns or the behavior will be
    ++** undefined. This must only be used within SQLITE_UPDATE and SQLITE_DELETE
    ++** preupdate callbacks; if it is used by an SQLITE_INSERT callback then the
    ++** behavior is undefined.  The [sqlite3_value] that P points to
    ++** will be destroyed when the preupdate callback returns.
    ++**
    ++** ^The [sqlite3_preupdate_new(D,N,P)] interface writes into P a pointer to
    ++** a [protected sqlite3_value] that contains the value of the Nth column of
    ++** the table row after it is updated.  The N parameter must be between 0
    ++** and one less than the number of columns or the behavior will be
    ++** undefined. This must only be used within SQLITE_INSERT and SQLITE_UPDATE
    ++** preupdate callbacks; if it is used by an SQLITE_DELETE callback then the
    ++** behavior is undefined.  The [sqlite3_value] that P points to
    ++** will be destroyed when the preupdate callback returns.
    ++**
    ++** ^The [sqlite3_preupdate_depth(D)] interface returns 0 if the preupdate
    ++** callback was invoked as a result of a direct insert, update, or delete
    ++** operation; or 1 for inserts, updates, or deletes invoked by top-level 
    ++** triggers; or 2 for changes resulting from triggers called by top-level
    ++** triggers; and so forth.
    ++**
    ++** See also:  [sqlite3_update_hook()]
    ++*/
    ++#if defined(SQLITE_ENABLE_PREUPDATE_HOOK)
    ++SQLITE_API void *sqlite3_preupdate_hook(
    ++  sqlite3 *db,
    ++  void(*xPreUpdate)(
    ++    void *pCtx,                   /* Copy of third arg to preupdate_hook() */
    ++    sqlite3 *db,                  /* Database handle */
    ++    int op,                       /* SQLITE_UPDATE, DELETE or INSERT */
    ++    char const *zDb,              /* Database name */
    ++    char const *zName,            /* Table name */
    ++    sqlite3_int64 iKey1,          /* Rowid of row about to be deleted/updated */
    ++    sqlite3_int64 iKey2           /* New rowid value (for a rowid UPDATE) */
    ++  ),
    ++  void*
    ++);
    ++SQLITE_API int sqlite3_preupdate_old(sqlite3 *, int, sqlite3_value **);
    ++SQLITE_API int sqlite3_preupdate_count(sqlite3 *);
    ++SQLITE_API int sqlite3_preupdate_depth(sqlite3 *);
    ++SQLITE_API int sqlite3_preupdate_new(sqlite3 *, int, sqlite3_value **);
    ++#endif
    ++
    ++/*
    ++** CAPI3REF: Low-level system error code
    ++**
    ++** ^Attempt to return the underlying operating system error code or error
    ++** number that caused the most recent I/O error or failure to open a file.
    ++** The return value is OS-dependent.  For example, on unix systems, after
    ++** [sqlite3_open_v2()] returns [SQLITE_CANTOPEN], this interface could be
    ++** called to get back the underlying "errno" that caused the problem, such
    ++** as ENOSPC, EAUTH, EISDIR, and so forth.  
    ++*/
    ++SQLITE_API int sqlite3_system_errno(sqlite3*);
    + 
    ++/*
    ++** CAPI3REF: Database Snapshot
    ++** KEYWORDS: {snapshot} {sqlite3_snapshot}
    ++** EXPERIMENTAL
    ++**
    ++** An instance of the snapshot object records the state of a [WAL mode]
    ++** database for some specific point in history.
    ++**
    ++** In [WAL mode], multiple [database connections] that are open on the
    ++** same database file can each be reading a different historical version
    ++** of the database file.  When a [database connection] begins a read
    ++** transaction, that connection sees an unchanging copy of the database
    ++** as it existed for the point in time when the transaction first started.
    ++** Subsequent changes to the database from other connections are not seen
    ++** by the reader until a new read transaction is started.
    ++**
    ++** The sqlite3_snapshot object records state information about an historical
    ++** version of the database file so that it is possible to later open a new read
    ++** transaction that sees that historical version of the database rather than
    ++** the most recent version.
    ++**
    ++** The constructor for this object is [sqlite3_snapshot_get()].  The
    ++** [sqlite3_snapshot_open()] method causes a fresh read transaction to refer
    ++** to an historical snapshot (if possible).  The destructor for 
    ++** sqlite3_snapshot objects is [sqlite3_snapshot_free()].
    ++*/
    ++typedef struct sqlite3_snapshot {
    ++  unsigned char hidden[48];
    ++} sqlite3_snapshot;
    ++
    ++/*
    ++** CAPI3REF: Record A Database Snapshot
    ++** EXPERIMENTAL
    ++**
    ++** ^The [sqlite3_snapshot_get(D,S,P)] interface attempts to make a
    ++** new [sqlite3_snapshot] object that records the current state of
    ++** schema S in database connection D.  ^On success, the
    ++** [sqlite3_snapshot_get(D,S,P)] interface writes a pointer to the newly
    ++** created [sqlite3_snapshot] object into *P and returns SQLITE_OK.
    ++** If there is not already a read-transaction open on schema S when
    ++** this function is called, one is opened automatically. 
    ++**
    ++** The following must be true for this function to succeed. If any of
    ++** the following statements are false when sqlite3_snapshot_get() is
    ++** called, SQLITE_ERROR is returned. The final value of *P is undefined
    ++** in this case. 
    ++**
    ++** <ul>
    ++**   <li> The database handle must be in [autocommit mode].
    ++**
    ++**   <li> Schema S of [database connection] D must be a [WAL mode] database.
    ++**
    ++**   <li> There must not be a write transaction open on schema S of database
    ++**        connection D.
    ++**
    ++**   <li> One or more transactions must have been written to the current wal
    ++**        file since it was created on disk (by any connection). This means
    ++**        that a snapshot cannot be taken on a wal mode database with no wal 
    ++**        file immediately after it is first opened. At least one transaction
    ++**        must be written to it first.
    ++** </ul>
    ++**
    ++** This function may also return SQLITE_NOMEM.  If it is called with the
    ++** database handle in autocommit mode but fails for some other reason, 
    ++** whether or not a read transaction is opened on schema S is undefined.
    ++**
    ++** The [sqlite3_snapshot] object returned from a successful call to
    ++** [sqlite3_snapshot_get()] must be freed using [sqlite3_snapshot_free()]
    ++** to avoid a memory leak.
    ++**
    ++** The [sqlite3_snapshot_get()] interface is only available when the
    ++** SQLITE_ENABLE_SNAPSHOT compile-time option is used.
    ++*/
    ++SQLITE_API SQLITE_EXPERIMENTAL int sqlite3_snapshot_get(
    ++  sqlite3 *db,
    ++  const char *zSchema,
    ++  sqlite3_snapshot **ppSnapshot
    ++);
    ++
    ++/*
    ++** CAPI3REF: Start a read transaction on an historical snapshot
    ++** EXPERIMENTAL
    ++**
    ++** ^The [sqlite3_snapshot_open(D,S,P)] interface starts a
    ++** read transaction for schema S of
    ++** [database connection] D such that the read transaction
    ++** refers to historical [snapshot] P, rather than the most
    ++** recent change to the database.
    ++** ^The [sqlite3_snapshot_open()] interface returns SQLITE_OK on success
    ++** or an appropriate [error code] if it fails.
    ++**
    ++** ^In order to succeed, a call to [sqlite3_snapshot_open(D,S,P)] must be
    ++** the first operation following the [BEGIN] that takes the schema S
    ++** out of [autocommit mode].
    ++** ^In other words, schema S must not currently be in
    ++** a transaction for [sqlite3_snapshot_open(D,S,P)] to work, but the
    ++** database connection D must be out of [autocommit mode].
    ++** ^A [snapshot] will fail to open if it has been overwritten by a
    ++** [checkpoint].
    ++** ^(A call to [sqlite3_snapshot_open(D,S,P)] will fail if the
    ++** database connection D does not know that the database file for
    ++** schema S is in [WAL mode].  A database connection might not know
    ++** that the database file is in [WAL mode] if there has been no prior
    ++** I/O on that database connection, or if the database entered [WAL mode] 
    ++** after the most recent I/O on the database connection.)^
    ++** (Hint: Run "[PRAGMA application_id]" against a newly opened
    ++** database connection in order to make it ready to use snapshots.)
    ++**
    ++** The [sqlite3_snapshot_open()] interface is only available when the
    ++** SQLITE_ENABLE_SNAPSHOT compile-time option is used.
    ++*/
    ++SQLITE_API SQLITE_EXPERIMENTAL int sqlite3_snapshot_open(
    ++  sqlite3 *db,
    ++  const char *zSchema,
    ++  sqlite3_snapshot *pSnapshot
    ++);
    ++
    ++/*
    ++** CAPI3REF: Destroy a snapshot
    ++** EXPERIMENTAL
    ++**
    ++** ^The [sqlite3_snapshot_free(P)] interface destroys [sqlite3_snapshot] P.
    ++** The application must eventually free every [sqlite3_snapshot] object
    ++** using this routine to avoid a memory leak.
    ++**
    ++** The [sqlite3_snapshot_free()] interface is only available when the
    ++** SQLITE_ENABLE_SNAPSHOT compile-time option is used.
    ++*/
    ++SQLITE_API SQLITE_EXPERIMENTAL void sqlite3_snapshot_free(sqlite3_snapshot*);
    ++
    ++/*
    ++** CAPI3REF: Compare the ages of two snapshot handles.
    ++** EXPERIMENTAL
    ++**
    ++** The sqlite3_snapshot_cmp(P1, P2) interface is used to compare the ages
    ++** of two valid snapshot handles. 
    ++**
    ++** If the two snapshot handles are not associated with the same database 
    ++** file, the result of the comparison is undefined. 
    ++**
    ++** Additionally, the result of the comparison is only valid if both of the
    ++** snapshot handles were obtained by calling sqlite3_snapshot_get() since the
    ++** last time the wal file was deleted. The wal file is deleted when the
    ++** database is changed back to rollback mode or when the number of database
    ++** clients drops to zero. If either snapshot handle was obtained before the 
    ++** wal file was last deleted, the value returned by this function 
    ++** is undefined.
    ++**
    ++** Otherwise, this API returns a negative value if P1 refers to an older
    ++** snapshot than P2, zero if the two handles refer to the same database
    ++** snapshot, and a positive value if P1 is a newer snapshot than P2.
    ++*/
    ++SQLITE_API SQLITE_EXPERIMENTAL int sqlite3_snapshot_cmp(
    ++  sqlite3_snapshot *p1,
    ++  sqlite3_snapshot *p2
    ++);
    ++
    ++/*
    ++** CAPI3REF: Recover snapshots from a wal file
    ++** EXPERIMENTAL
    ++**
    ++** If all connections disconnect from a database file but do not perform
    ++** a checkpoint, the existing wal file is opened along with the database
    ++** file the next time the database is opened. At this point it is only
    ++** possible to successfully call sqlite3_snapshot_open() to open the most
    ++** recent snapshot of the database (the one at the head of the wal file),
    ++** even though the wal file may contain other valid snapshots for which
    ++** clients have sqlite3_snapshot handles.
    ++**
    ++** This function attempts to scan the wal file associated with database zDb
    ++** of database handle db and make all valid snapshots available to
    ++** sqlite3_snapshot_open(). It is an error if there is already a read
    ++** transaction open on the database, or if the database is not a wal mode
    ++** database.
    ++**
    ++** SQLITE_OK is returned if successful, or an SQLite error code otherwise.
    ++*/
    ++SQLITE_API SQLITE_EXPERIMENTAL int sqlite3_snapshot_recover(sqlite3 *db, const char *zDb);
    + 
    + /*
    + ** Undo the hack that converts floating point types to integer for
    +@@ -8016,8 +9828,9 @@ SQLITE_API void SQLITE_STDCALL sqlite3_stmt_scanstatus_reset(sqlite3_stmt*);
    + #if 0
    + }  /* End of the 'extern "C"' block */
    + #endif
    +-#endif /* _SQLITE3_H_ */
    ++#endif /* SQLITE3_H */
    + 
    ++/******** Begin file sqlite3rtree.h *********/
    + /*
    + ** 2010 August 30
    + **
    +@@ -8057,7 +9870,7 @@ typedef struct sqlite3_rtree_query_info sqlite3_rtree_query_info;
    + **
    + **   SELECT ... FROM <rtree> WHERE <rtree col> MATCH $zGeom(... params ...)
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_rtree_geometry_callback(
    ++SQLITE_API int sqlite3_rtree_geometry_callback(
    +   sqlite3 *db,
    +   const char *zGeom,
    +   int (*xGeom)(sqlite3_rtree_geometry*, int, sqlite3_rtree_dbl*,int*),
    +@@ -8083,7 +9896,7 @@ struct sqlite3_rtree_geometry {
    + **
    + **   SELECT ... FROM <rtree> WHERE <rtree col> MATCH $zQueryFunc(... params ...)
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_rtree_query_callback(
    ++SQLITE_API int sqlite3_rtree_query_callback(
    +   sqlite3 *db,
    +   const char *zQueryFunc,
    +   int (*xQueryFunc)(sqlite3_rtree_query_info*),
    +@@ -8135,6 +9948,1327 @@ struct sqlite3_rtree_query_info {
    + 
    + #endif  /* ifndef _SQLITE3RTREE_H_ */
    + 
    ++/******** End of sqlite3rtree.h *********/
    ++/******** Begin file sqlite3session.h *********/
    ++
    ++#if !defined(__SQLITESESSION_H_) && defined(SQLITE_ENABLE_SESSION)
    ++#define __SQLITESESSION_H_ 1
    ++
    ++/*
    ++** Make sure we can call this stuff from C++.
    ++*/
    ++#if 0
    ++extern "C" {
    ++#endif
    ++
    ++
    ++/*
    ++** CAPI3REF: Session Object Handle
    ++*/
    ++typedef struct sqlite3_session sqlite3_session;
    ++
    ++/*
    ++** CAPI3REF: Changeset Iterator Handle
    ++*/
    ++typedef struct sqlite3_changeset_iter sqlite3_changeset_iter;
    ++
    ++/*
    ++** CAPI3REF: Create A New Session Object
    ++**
    ++** Create a new session object attached to database handle db. If successful,
    ++** a pointer to the new object is written to *ppSession and SQLITE_OK is
    ++** returned. If an error occurs, *ppSession is set to NULL and an SQLite
    ++** error code (e.g. SQLITE_NOMEM) is returned.
    ++**
    ++** It is possible to create multiple session objects attached to a single
    ++** database handle.
    ++**
    ++** Session objects created using this function should be deleted using the
    ++** [sqlite3session_delete()] function before the database handle that they
    ++** are attached to is itself closed. If the database handle is closed before
    ++** the session object is deleted, then the results of calling any session
    ++** module function, including [sqlite3session_delete()] on the session object
    ++** are undefined.
    ++**
    ++** Because the session module uses the [sqlite3_preupdate_hook()] API, it
    ++** is not possible for an application to register a pre-update hook on a
    ++** database handle that has one or more session objects attached. Nor is
    ++** it possible to create a session object attached to a database handle for
    ++** which a pre-update hook is already defined. The results of attempting 
    ++** either of these things are undefined.
    ++**
    ++** The session object will be used to create changesets for tables in
    ++** database zDb, where zDb is either "main", or "temp", or the name of an
    ++** attached database. It is not an error if database zDb is not attached
    ++** to the database when the session object is created.
    ++*/
    ++SQLITE_API int sqlite3session_create(
    ++  sqlite3 *db,                    /* Database handle */
    ++  const char *zDb,                /* Name of db (e.g. "main") */
    ++  sqlite3_session **ppSession     /* OUT: New session object */
    ++);
    ++
    ++/*
    ++** CAPI3REF: Delete A Session Object
    ++**
    ++** Delete a session object previously allocated using 
    ++** [sqlite3session_create()]. Once a session object has been deleted, the
    ++** results of attempting to use pSession with any other session module
    ++** function are undefined.
    ++**
    ++** Session objects must be deleted before the database handle to which they
    ++** are attached is closed. Refer to the documentation for 
    ++** [sqlite3session_create()] for details.
    ++*/
    ++SQLITE_API void sqlite3session_delete(sqlite3_session *pSession);
    ++
    ++
    ++/*
    ++** CAPI3REF: Enable Or Disable A Session Object
    ++**
    ++** Enable or disable the recording of changes by a session object. When
    ++** enabled, a session object records changes made to the database. When
    ++** disabled - it does not. A newly created session object is enabled.
    ++** Refer to the documentation for [sqlite3session_changeset()] for further
    ++** details regarding how enabling and disabling a session object affects
    ++** the eventual changesets.
    ++**
    ++** Passing zero to this function disables the session. Passing a value
    ++** greater than zero enables it. Passing a value less than zero is a 
    ++** no-op, and may be used to query the current state of the session.
    ++**
    ++** The return value indicates the final state of the session object: 0 if 
    ++** the session is disabled, or 1 if it is enabled.
    ++*/
    ++SQLITE_API int sqlite3session_enable(sqlite3_session *pSession, int bEnable);
    ++
    ++/*
    ++** CAPI3REF: Set Or Clear the Indirect Change Flag
    ++**
    ++** Each change recorded by a session object is marked as either direct or
    ++** indirect. A change is marked as indirect if either:
    ++**
    ++** <ul>
    ++**   <li> The session object "indirect" flag is set when the change is
    ++**        made, or
    ++**   <li> The change is made by an SQL trigger or foreign key action 
    ++**        instead of directly as a result of a users SQL statement.
    ++** </ul>
    ++**
    ++** If a single row is affected by more than one operation within a session,
    ++** then the change is considered indirect if all operations meet the criteria
    ++** for an indirect change above, or direct otherwise.
    ++**
    ++** This function is used to set, clear or query the session object indirect
    ++** flag.  If the second argument passed to this function is zero, then the
    ++** indirect flag is cleared. If it is greater than zero, the indirect flag
    ++** is set. Passing a value less than zero does not modify the current value
    ++** of the indirect flag, and may be used to query the current state of the 
    ++** indirect flag for the specified session object.
    ++**
    ++** The return value indicates the final state of the indirect flag: 0 if 
    ++** it is clear, or 1 if it is set.
    ++*/
    ++SQLITE_API int sqlite3session_indirect(sqlite3_session *pSession, int bIndirect);
    ++
    ++/*
    ++** CAPI3REF: Attach A Table To A Session Object
    ++**
    ++** If argument zTab is not NULL, then it is the name of a table to attach
    ++** to the session object passed as the first argument. All subsequent changes 
    ++** made to the table while the session object is enabled will be recorded. See 
    ++** documentation for [sqlite3session_changeset()] for further details.
    ++**
    ++** Or, if argument zTab is NULL, then changes are recorded for all tables
    ++** in the database. If additional tables are added to the database (by 
    ++** executing "CREATE TABLE" statements) after this call is made, changes for 
    ++** the new tables are also recorded.
    ++**
    ++** Changes can only be recorded for tables that have a PRIMARY KEY explicitly
    ++** defined as part of their CREATE TABLE statement. It does not matter if the 
    ++** PRIMARY KEY is an "INTEGER PRIMARY KEY" (rowid alias) or not. The PRIMARY
    ++** KEY may consist of a single column, or may be a composite key.
    ++** 
    ++** It is not an error if the named table does not exist in the database. Nor
    ++** is it an error if the named table does not have a PRIMARY KEY. However,
    ++** no changes will be recorded in either of these scenarios.
    ++**
    ++** Changes are not recorded for individual rows that have NULL values stored
    ++** in one or more of their PRIMARY KEY columns.
    ++**
    ++** SQLITE_OK is returned if the call completes without error. Or, if an error 
    ++** occurs, an SQLite error code (e.g. SQLITE_NOMEM) is returned.
    ++**
    ++** <h3>Special sqlite_stat1 Handling</h3>
    ++**
    ++** As of SQLite version 3.22.0, the "sqlite_stat1" table is an exception to 
    ++** some of the rules above. In SQLite, the schema of sqlite_stat1 is:
    ++**  <pre>
    ++**  &nbsp;     CREATE TABLE sqlite_stat1(tbl,idx,stat)  
    ++**  </pre>
    ++**
    ++** Even though sqlite_stat1 does not have a PRIMARY KEY, changes are 
    ++** recorded for it as if the PRIMARY KEY is (tbl,idx). Additionally, changes 
    ++** are recorded for rows for which (idx IS NULL) is true. However, for such
    ++** rows a zero-length blob (SQL value X'') is stored in the changeset or
    ++** patchset instead of a NULL value. This allows such changesets to be
    ++** manipulated by legacy implementations of sqlite3changeset_invert(),
    ++** concat() and similar.
    ++**
    ++** The sqlite3changeset_apply() function automatically converts the 
    ++** zero-length blob back to a NULL value when updating the sqlite_stat1
    ++** table. However, if the application calls sqlite3changeset_new(),
    ++** sqlite3changeset_old() or sqlite3changeset_conflict on a changeset 
    ++** iterator directly (including on a changeset iterator passed to a
    ++** conflict-handler callback) then the X'' value is returned. The application
    ++** must translate X'' to NULL itself if required.
    ++**
    ++** Legacy (older than 3.22.0) versions of the sessions module cannot capture
    ++** changes made to the sqlite_stat1 table. Legacy versions of the
    ++** sqlite3changeset_apply() function silently ignore any modifications to the
    ++** sqlite_stat1 table that are part of a changeset or patchset.
    ++*/
    ++SQLITE_API int sqlite3session_attach(
    ++  sqlite3_session *pSession,      /* Session object */
    ++  const char *zTab                /* Table name */
    ++);
    ++
    ++/*
    ++** CAPI3REF: Set a table filter on a Session Object.
    ++**
    ++** The second argument (xFilter) is the "filter callback". For changes to rows 
    ++** in tables that are not attached to the Session object, the filter is called
    ++** to determine whether changes to the table's rows should be tracked or not. 
    ++** If xFilter returns 0, changes is not tracked. Note that once a table is 
    ++** attached, xFilter will not be called again.
    ++*/
    ++SQLITE_API void sqlite3session_table_filter(
    ++  sqlite3_session *pSession,      /* Session object */
    ++  int(*xFilter)(
    ++    void *pCtx,                   /* Copy of third arg to _filter_table() */
    ++    const char *zTab              /* Table name */
    ++  ),
    ++  void *pCtx                      /* First argument passed to xFilter */
    ++);
    ++
    ++/*
    ++** CAPI3REF: Generate A Changeset From A Session Object
    ++**
    ++** Obtain a changeset containing changes to the tables attached to the 
    ++** session object passed as the first argument. If successful, 
    ++** set *ppChangeset to point to a buffer containing the changeset 
    ++** and *pnChangeset to the size of the changeset in bytes before returning
    ++** SQLITE_OK. If an error occurs, set both *ppChangeset and *pnChangeset to
    ++** zero and return an SQLite error code.
    ++**
    ++** A changeset consists of zero or more INSERT, UPDATE and/or DELETE changes,
    ++** each representing a change to a single row of an attached table. An INSERT
    ++** change contains the values of each field of a new database row. A DELETE
    ++** contains the original values of each field of a deleted database row. An
    ++** UPDATE change contains the original values of each field of an updated
    ++** database row along with the updated values for each updated non-primary-key
    ++** column. It is not possible for an UPDATE change to represent a change that
    ++** modifies the values of primary key columns. If such a change is made, it
    ++** is represented in a changeset as a DELETE followed by an INSERT.
    ++**
    ++** Changes are not recorded for rows that have NULL values stored in one or 
    ++** more of their PRIMARY KEY columns. If such a row is inserted or deleted,
    ++** no corresponding change is present in the changesets returned by this
    ++** function. If an existing row with one or more NULL values stored in
    ++** PRIMARY KEY columns is updated so that all PRIMARY KEY columns are non-NULL,
    ++** only an INSERT is appears in the changeset. Similarly, if an existing row
    ++** with non-NULL PRIMARY KEY values is updated so that one or more of its
    ++** PRIMARY KEY columns are set to NULL, the resulting changeset contains a
    ++** DELETE change only.
    ++**
    ++** The contents of a changeset may be traversed using an iterator created
    ++** using the [sqlite3changeset_start()] API. A changeset may be applied to
    ++** a database with a compatible schema using the [sqlite3changeset_apply()]
    ++** API.
    ++**
    ++** Within a changeset generated by this function, all changes related to a
    ++** single table are grouped together. In other words, when iterating through
    ++** a changeset or when applying a changeset to a database, all changes related
    ++** to a single table are processed before moving on to the next table. Tables
    ++** are sorted in the same order in which they were attached (or auto-attached)
    ++** to the sqlite3_session object. The order in which the changes related to
    ++** a single table are stored is undefined.
    ++**
    ++** Following a successful call to this function, it is the responsibility of
    ++** the caller to eventually free the buffer that *ppChangeset points to using
    ++** [sqlite3_free()].
    ++**
    ++** <h3>Changeset Generation</h3>
    ++**
    ++** Once a table has been attached to a session object, the session object
    ++** records the primary key values of all new rows inserted into the table.
    ++** It also records the original primary key and other column values of any
    ++** deleted or updated rows. For each unique primary key value, data is only
    ++** recorded once - the first time a row with said primary key is inserted,
    ++** updated or deleted in the lifetime of the session.
    ++**
    ++** There is one exception to the previous paragraph: when a row is inserted,
    ++** updated or deleted, if one or more of its primary key columns contain a
    ++** NULL value, no record of the change is made.
    ++**
    ++** The session object therefore accumulates two types of records - those
    ++** that consist of primary key values only (created when the user inserts
    ++** a new record) and those that consist of the primary key values and the
    ++** original values of other table columns (created when the users deletes
    ++** or updates a record).
    ++**
    ++** When this function is called, the requested changeset is created using
    ++** both the accumulated records and the current contents of the database
    ++** file. Specifically:
    ++**
    ++** <ul>
    ++**   <li> For each record generated by an insert, the database is queried
    ++**        for a row with a matching primary key. If one is found, an INSERT
    ++**        change is added to the changeset. If no such row is found, no change 
    ++**        is added to the changeset.
    ++**
    ++**   <li> For each record generated by an update or delete, the database is 
    ++**        queried for a row with a matching primary key. If such a row is
    ++**        found and one or more of the non-primary key fields have been
    ++**        modified from their original values, an UPDATE change is added to 
    ++**        the changeset. Or, if no such row is found in the table, a DELETE 
    ++**        change is added to the changeset. If there is a row with a matching
    ++**        primary key in the database, but all fields contain their original
    ++**        values, no change is added to the changeset.
    ++** </ul>
    ++**
    ++** This means, amongst other things, that if a row is inserted and then later
    ++** deleted while a session object is active, neither the insert nor the delete
    ++** will be present in the changeset. Or if a row is deleted and then later a 
    ++** row with the same primary key values inserted while a session object is
    ++** active, the resulting changeset will contain an UPDATE change instead of
    ++** a DELETE and an INSERT.
    ++**
    ++** When a session object is disabled (see the [sqlite3session_enable()] API),
    ++** it does not accumulate records when rows are inserted, updated or deleted.
    ++** This may appear to have some counter-intuitive effects if a single row
    ++** is written to more than once during a session. For example, if a row
    ++** is inserted while a session object is enabled, then later deleted while 
    ++** the same session object is disabled, no INSERT record will appear in the
    ++** changeset, even though the delete took place while the session was disabled.
    ++** Or, if one field of a row is updated while a session is disabled, and 
    ++** another field of the same row is updated while the session is enabled, the
    ++** resulting changeset will contain an UPDATE change that updates both fields.
    ++*/
    ++SQLITE_API int sqlite3session_changeset(
    ++  sqlite3_session *pSession,      /* Session object */
    ++  int *pnChangeset,               /* OUT: Size of buffer at *ppChangeset */
    ++  void **ppChangeset              /* OUT: Buffer containing changeset */
    ++);
    ++
    ++/*
    ++** CAPI3REF: Load The Difference Between Tables Into A Session 
    ++**
    ++** If it is not already attached to the session object passed as the first
    ++** argument, this function attaches table zTbl in the same manner as the
    ++** [sqlite3session_attach()] function. If zTbl does not exist, or if it
    ++** does not have a primary key, this function is a no-op (but does not return
    ++** an error).
    ++**
    ++** Argument zFromDb must be the name of a database ("main", "temp" etc.)
    ++** attached to the same database handle as the session object that contains 
    ++** a table compatible with the table attached to the session by this function.
    ++** A table is considered compatible if it:
    ++**
    ++** <ul>
    ++**   <li> Has the same name,
    ++**   <li> Has the same set of columns declared in the same order, and
    ++**   <li> Has the same PRIMARY KEY definition.
    ++** </ul>
    ++**
    ++** If the tables are not compatible, SQLITE_SCHEMA is returned. If the tables
    ++** are compatible but do not have any PRIMARY KEY columns, it is not an error
    ++** but no changes are added to the session object. As with other session
    ++** APIs, tables without PRIMARY KEYs are simply ignored.
    ++**
    ++** This function adds a set of changes to the session object that could be
    ++** used to update the table in database zFrom (call this the "from-table") 
    ++** so that its content is the same as the table attached to the session 
    ++** object (call this the "to-table"). Specifically:
    ++**
    ++** <ul>
    ++**   <li> For each row (primary key) that exists in the to-table but not in 
    ++**     the from-table, an INSERT record is added to the session object.
    ++**
    ++**   <li> For each row (primary key) that exists in the to-table but not in 
    ++**     the from-table, a DELETE record is added to the session object.
    ++**
    ++**   <li> For each row (primary key) that exists in both tables, but features 
    ++**     different non-PK values in each, an UPDATE record is added to the
    ++**     session.  
    ++** </ul>
    ++**
    ++** To clarify, if this function is called and then a changeset constructed
    ++** using [sqlite3session_changeset()], then after applying that changeset to 
    ++** database zFrom the contents of the two compatible tables would be 
    ++** identical.
    ++**
    ++** It an error if database zFrom does not exist or does not contain the
    ++** required compatible table.
    ++**
    ++** If the operation successful, SQLITE_OK is returned. Otherwise, an SQLite
    ++** error code. In this case, if argument pzErrMsg is not NULL, *pzErrMsg
    ++** may be set to point to a buffer containing an English language error 
    ++** message. It is the responsibility of the caller to free this buffer using
    ++** sqlite3_free().
    ++*/
    ++SQLITE_API int sqlite3session_diff(
    ++  sqlite3_session *pSession,
    ++  const char *zFromDb,
    ++  const char *zTbl,
    ++  char **pzErrMsg
    ++);
    ++
    ++
    ++/*
    ++** CAPI3REF: Generate A Patchset From A Session Object
    ++**
    ++** The differences between a patchset and a changeset are that:
    ++**
    ++** <ul>
    ++**   <li> DELETE records consist of the primary key fields only. The 
    ++**        original values of other fields are omitted.
    ++**   <li> The original values of any modified fields are omitted from 
    ++**        UPDATE records.
    ++** </ul>
    ++**
    ++** A patchset blob may be used with up to date versions of all 
    ++** sqlite3changeset_xxx API functions except for sqlite3changeset_invert(), 
    ++** which returns SQLITE_CORRUPT if it is passed a patchset. Similarly,
    ++** attempting to use a patchset blob with old versions of the
    ++** sqlite3changeset_xxx APIs also provokes an SQLITE_CORRUPT error. 
    ++**
    ++** Because the non-primary key "old.*" fields are omitted, no 
    ++** SQLITE_CHANGESET_DATA conflicts can be detected or reported if a patchset
    ++** is passed to the sqlite3changeset_apply() API. Other conflict types work
    ++** in the same way as for changesets.
    ++**
    ++** Changes within a patchset are ordered in the same way as for changesets
    ++** generated by the sqlite3session_changeset() function (i.e. all changes for
    ++** a single table are grouped together, tables appear in the order in which
    ++** they were attached to the session object).
    ++*/
    ++SQLITE_API int sqlite3session_patchset(
    ++  sqlite3_session *pSession,      /* Session object */
    ++  int *pnPatchset,                /* OUT: Size of buffer at *ppPatchset */
    ++  void **ppPatchset               /* OUT: Buffer containing patchset */
    ++);
    ++
    ++/*
    ++** CAPI3REF: Test if a changeset has recorded any changes.
    ++**
    ++** Return non-zero if no changes to attached tables have been recorded by 
    ++** the session object passed as the first argument. Otherwise, if one or 
    ++** more changes have been recorded, return zero.
    ++**
    ++** Even if this function returns zero, it is possible that calling
    ++** [sqlite3session_changeset()] on the session handle may still return a
    ++** changeset that contains no changes. This can happen when a row in 
    ++** an attached table is modified and then later on the original values 
    ++** are restored. However, if this function returns non-zero, then it is
    ++** guaranteed that a call to sqlite3session_changeset() will return a 
    ++** changeset containing zero changes.
    ++*/
    ++SQLITE_API int sqlite3session_isempty(sqlite3_session *pSession);
    ++
    ++/*
    ++** CAPI3REF: Create An Iterator To Traverse A Changeset 
    ++**
    ++** Create an iterator used to iterate through the contents of a changeset.
    ++** If successful, *pp is set to point to the iterator handle and SQLITE_OK
    ++** is returned. Otherwise, if an error occurs, *pp is set to zero and an
    ++** SQLite error code is returned.
    ++**
    ++** The following functions can be used to advance and query a changeset 
    ++** iterator created by this function:
    ++**
    ++** <ul>
    ++**   <li> [sqlite3changeset_next()]
    ++**   <li> [sqlite3changeset_op()]
    ++**   <li> [sqlite3changeset_new()]
    ++**   <li> [sqlite3changeset_old()]
    ++** </ul>
    ++**
    ++** It is the responsibility of the caller to eventually destroy the iterator
    ++** by passing it to [sqlite3changeset_finalize()]. The buffer containing the
    ++** changeset (pChangeset) must remain valid until after the iterator is
    ++** destroyed.
    ++**
    ++** Assuming the changeset blob was created by one of the
    ++** [sqlite3session_changeset()], [sqlite3changeset_concat()] or
    ++** [sqlite3changeset_invert()] functions, all changes within the changeset 
    ++** that apply to a single table are grouped together. This means that when 
    ++** an application iterates through a changeset using an iterator created by 
    ++** this function, all changes that relate to a single table are visited 
    ++** consecutively. There is no chance that the iterator will visit a change 
    ++** the applies to table X, then one for table Y, and then later on visit 
    ++** another change for table X.
    ++*/
    ++SQLITE_API int sqlite3changeset_start(
    ++  sqlite3_changeset_iter **pp,    /* OUT: New changeset iterator handle */
    ++  int nChangeset,                 /* Size of changeset blob in bytes */
    ++  void *pChangeset                /* Pointer to blob containing changeset */
    ++);
    ++
    ++
    ++/*
    ++** CAPI3REF: Advance A Changeset Iterator
    ++**
    ++** This function may only be used with iterators created by function
    ++** [sqlite3changeset_start()]. If it is called on an iterator passed to
    ++** a conflict-handler callback by [sqlite3changeset_apply()], SQLITE_MISUSE
    ++** is returned and the call has no effect.
    ++**
    ++** Immediately after an iterator is created by sqlite3changeset_start(), it
    ++** does not point to any change in the changeset. Assuming the changeset
    ++** is not empty, the first call to this function advances the iterator to
    ++** point to the first change in the changeset. Each subsequent call advances
    ++** the iterator to point to the next change in the changeset (if any). If
    ++** no error occurs and the iterator points to a valid change after a call
    ++** to sqlite3changeset_next() has advanced it, SQLITE_ROW is returned. 
    ++** Otherwise, if all changes in the changeset have already been visited,
    ++** SQLITE_DONE is returned.
    ++**
    ++** If an error occurs, an SQLite error code is returned. Possible error 
    ++** codes include SQLITE_CORRUPT (if the changeset buffer is corrupt) or 
    ++** SQLITE_NOMEM.
    ++*/
    ++SQLITE_API int sqlite3changeset_next(sqlite3_changeset_iter *pIter);
    ++
    ++/*
    ++** CAPI3REF: Obtain The Current Operation From A Changeset Iterator
    ++**
    ++** The pIter argument passed to this function may either be an iterator
    ++** passed to a conflict-handler by [sqlite3changeset_apply()], or an iterator
    ++** created by [sqlite3changeset_start()]. In the latter case, the most recent
    ++** call to [sqlite3changeset_next()] must have returned [SQLITE_ROW]. If this
    ++** is not the case, this function returns [SQLITE_MISUSE].
    ++**
    ++** If argument pzTab is not NULL, then *pzTab is set to point to a
    ++** nul-terminated utf-8 encoded string containing the name of the table
    ++** affected by the current change. The buffer remains valid until either
    ++** sqlite3changeset_next() is called on the iterator or until the 
    ++** conflict-handler function returns. If pnCol is not NULL, then *pnCol is 
    ++** set to the number of columns in the table affected by the change. If
    ++** pbIncorrect is not NULL, then *pbIndirect is set to true (1) if the change
    ++** is an indirect change, or false (0) otherwise. See the documentation for
    ++** [sqlite3session_indirect()] for a description of direct and indirect
    ++** changes. Finally, if pOp is not NULL, then *pOp is set to one of 
    ++** [SQLITE_INSERT], [SQLITE_DELETE] or [SQLITE_UPDATE], depending on the 
    ++** type of change that the iterator currently points to.
    ++**
    ++** If no error occurs, SQLITE_OK is returned. If an error does occur, an
    ++** SQLite error code is returned. The values of the output variables may not
    ++** be trusted in this case.
    ++*/
    ++SQLITE_API int sqlite3changeset_op(
    ++  sqlite3_changeset_iter *pIter,  /* Iterator object */
    ++  const char **pzTab,             /* OUT: Pointer to table name */
    ++  int *pnCol,                     /* OUT: Number of columns in table */
    ++  int *pOp,                       /* OUT: SQLITE_INSERT, DELETE or UPDATE */
    ++  int *pbIndirect                 /* OUT: True for an 'indirect' change */
    ++);
    ++
    ++/*
    ++** CAPI3REF: Obtain The Primary Key Definition Of A Table
    ++**
    ++** For each modified table, a changeset includes the following:
    ++**
    ++** <ul>
    ++**   <li> The number of columns in the table, and
    ++**   <li> Which of those columns make up the tables PRIMARY KEY.
    ++** </ul>
    ++**
    ++** This function is used to find which columns comprise the PRIMARY KEY of
    ++** the table modified by the change that iterator pIter currently points to.
    ++** If successful, *pabPK is set to point to an array of nCol entries, where
    ++** nCol is the number of columns in the table. Elements of *pabPK are set to
    ++** 0x01 if the corresponding column is part of the tables primary key, or
    ++** 0x00 if it is not.
    ++**
    ++** If argument pnCol is not NULL, then *pnCol is set to the number of columns
    ++** in the table.
    ++**
    ++** If this function is called when the iterator does not point to a valid
    ++** entry, SQLITE_MISUSE is returned and the output variables zeroed. Otherwise,
    ++** SQLITE_OK is returned and the output variables populated as described
    ++** above.
    ++*/
    ++SQLITE_API int sqlite3changeset_pk(
    ++  sqlite3_changeset_iter *pIter,  /* Iterator object */
    ++  unsigned char **pabPK,          /* OUT: Array of boolean - true for PK cols */
    ++  int *pnCol                      /* OUT: Number of entries in output array */
    ++);
    ++
    ++/*
    ++** CAPI3REF: Obtain old.* Values From A Changeset Iterator
    ++**
    ++** The pIter argument passed to this function may either be an iterator
    ++** passed to a conflict-handler by [sqlite3changeset_apply()], or an iterator
    ++** created by [sqlite3changeset_start()]. In the latter case, the most recent
    ++** call to [sqlite3changeset_next()] must have returned SQLITE_ROW. 
    ++** Furthermore, it may only be called if the type of change that the iterator
    ++** currently points to is either [SQLITE_DELETE] or [SQLITE_UPDATE]. Otherwise,
    ++** this function returns [SQLITE_MISUSE] and sets *ppValue to NULL.
    ++**
    ++** Argument iVal must be greater than or equal to 0, and less than the number
    ++** of columns in the table affected by the current change. Otherwise,
    ++** [SQLITE_RANGE] is returned and *ppValue is set to NULL.
    ++**
    ++** If successful, this function sets *ppValue to point to a protected
    ++** sqlite3_value object containing the iVal'th value from the vector of 
    ++** original row values stored as part of the UPDATE or DELETE change and
    ++** returns SQLITE_OK. The name of the function comes from the fact that this 
    ++** is similar to the "old.*" columns available to update or delete triggers.
    ++**
    ++** If some other error occurs (e.g. an OOM condition), an SQLite error code
    ++** is returned and *ppValue is set to NULL.
    ++*/
    ++SQLITE_API int sqlite3changeset_old(
    ++  sqlite3_changeset_iter *pIter,  /* Changeset iterator */
    ++  int iVal,                       /* Column number */
    ++  sqlite3_value **ppValue         /* OUT: Old value (or NULL pointer) */
    ++);
    ++
    ++/*
    ++** CAPI3REF: Obtain new.* Values From A Changeset Iterator
    ++**
    ++** The pIter argument passed to this function may either be an iterator
    ++** passed to a conflict-handler by [sqlite3changeset_apply()], or an iterator
    ++** created by [sqlite3changeset_start()]. In the latter case, the most recent
    ++** call to [sqlite3changeset_next()] must have returned SQLITE_ROW. 
    ++** Furthermore, it may only be called if the type of change that the iterator
    ++** currently points to is either [SQLITE_UPDATE] or [SQLITE_INSERT]. Otherwise,
    ++** this function returns [SQLITE_MISUSE] and sets *ppValue to NULL.
    ++**
    ++** Argument iVal must be greater than or equal to 0, and less than the number
    ++** of columns in the table affected by the current change. Otherwise,
    ++** [SQLITE_RANGE] is returned and *ppValue is set to NULL.
    ++**
    ++** If successful, this function sets *ppValue to point to a protected
    ++** sqlite3_value object containing the iVal'th value from the vector of 
    ++** new row values stored as part of the UPDATE or INSERT change and
    ++** returns SQLITE_OK. If the change is an UPDATE and does not include
    ++** a new value for the requested column, *ppValue is set to NULL and 
    ++** SQLITE_OK returned. The name of the function comes from the fact that 
    ++** this is similar to the "new.*" columns available to update or delete 
    ++** triggers.
    ++**
    ++** If some other error occurs (e.g. an OOM condition), an SQLite error code
    ++** is returned and *ppValue is set to NULL.
    ++*/
    ++SQLITE_API int sqlite3changeset_new(
    ++  sqlite3_changeset_iter *pIter,  /* Changeset iterator */
    ++  int iVal,                       /* Column number */
    ++  sqlite3_value **ppValue         /* OUT: New value (or NULL pointer) */
    ++);
    ++
    ++/*
    ++** CAPI3REF: Obtain Conflicting Row Values From A Changeset Iterator
    ++**
    ++** This function should only be used with iterator objects passed to a
    ++** conflict-handler callback by [sqlite3changeset_apply()] with either
    ++** [SQLITE_CHANGESET_DATA] or [SQLITE_CHANGESET_CONFLICT]. If this function
    ++** is called on any other iterator, [SQLITE_MISUSE] is returned and *ppValue
    ++** is set to NULL.
    ++**
    ++** Argument iVal must be greater than or equal to 0, and less than the number
    ++** of columns in the table affected by the current change. Otherwise,
    ++** [SQLITE_RANGE] is returned and *ppValue is set to NULL.
    ++**
    ++** If successful, this function sets *ppValue to point to a protected
    ++** sqlite3_value object containing the iVal'th value from the 
    ++** "conflicting row" associated with the current conflict-handler callback
    ++** and returns SQLITE_OK.
    ++**
    ++** If some other error occurs (e.g. an OOM condition), an SQLite error code
    ++** is returned and *ppValue is set to NULL.
    ++*/
    ++SQLITE_API int sqlite3changeset_conflict(
    ++  sqlite3_changeset_iter *pIter,  /* Changeset iterator */
    ++  int iVal,                       /* Column number */
    ++  sqlite3_value **ppValue         /* OUT: Value from conflicting row */
    ++);
    ++
    ++/*
    ++** CAPI3REF: Determine The Number Of Foreign Key Constraint Violations
    ++**
    ++** This function may only be called with an iterator passed to an
    ++** SQLITE_CHANGESET_FOREIGN_KEY conflict handler callback. In this case
    ++** it sets the output variable to the total number of known foreign key
    ++** violations in the destination database and returns SQLITE_OK.
    ++**
    ++** In all other cases this function returns SQLITE_MISUSE.
    ++*/
    ++SQLITE_API int sqlite3changeset_fk_conflicts(
    ++  sqlite3_changeset_iter *pIter,  /* Changeset iterator */
    ++  int *pnOut                      /* OUT: Number of FK violations */
    ++);
    ++
    ++
    ++/*
    ++** CAPI3REF: Finalize A Changeset Iterator
    ++**
    ++** This function is used to finalize an iterator allocated with
    ++** [sqlite3changeset_start()].
    ++**
    ++** This function should only be called on iterators created using the
    ++** [sqlite3changeset_start()] function. If an application calls this
    ++** function with an iterator passed to a conflict-handler by
    ++** [sqlite3changeset_apply()], [SQLITE_MISUSE] is immediately returned and the
    ++** call has no effect.
    ++**
    ++** If an error was encountered within a call to an sqlite3changeset_xxx()
    ++** function (for example an [SQLITE_CORRUPT] in [sqlite3changeset_next()] or an 
    ++** [SQLITE_NOMEM] in [sqlite3changeset_new()]) then an error code corresponding
    ++** to that error is returned by this function. Otherwise, SQLITE_OK is
    ++** returned. This is to allow the following pattern (pseudo-code):
    ++**
    ++**   sqlite3changeset_start();
    ++**   while( SQLITE_ROW==sqlite3changeset_next() ){
    ++**     // Do something with change.
    ++**   }
    ++**   rc = sqlite3changeset_finalize();
    ++**   if( rc!=SQLITE_OK ){
    ++**     // An error has occurred 
    ++**   }
    ++*/
    ++SQLITE_API int sqlite3changeset_finalize(sqlite3_changeset_iter *pIter);
    ++
    ++/*
    ++** CAPI3REF: Invert A Changeset
    ++**
    ++** This function is used to "invert" a changeset object. Applying an inverted
    ++** changeset to a database reverses the effects of applying the uninverted
    ++** changeset. Specifically:
    ++**
    ++** <ul>
    ++**   <li> Each DELETE change is changed to an INSERT, and
    ++**   <li> Each INSERT change is changed to a DELETE, and
    ++**   <li> For each UPDATE change, the old.* and new.* values are exchanged.
    ++** </ul>
    ++**
    ++** This function does not change the order in which changes appear within
    ++** the changeset. It merely reverses the sense of each individual change.
    ++**
    ++** If successful, a pointer to a buffer containing the inverted changeset
    ++** is stored in *ppOut, the size of the same buffer is stored in *pnOut, and
    ++** SQLITE_OK is returned. If an error occurs, both *pnOut and *ppOut are
    ++** zeroed and an SQLite error code returned.
    ++**
    ++** It is the responsibility of the caller to eventually call sqlite3_free()
    ++** on the *ppOut pointer to free the buffer allocation following a successful 
    ++** call to this function.
    ++**
    ++** WARNING/TODO: This function currently assumes that the input is a valid
    ++** changeset. If it is not, the results are undefined.
    ++*/
    ++SQLITE_API int sqlite3changeset_invert(
    ++  int nIn, const void *pIn,       /* Input changeset */
    ++  int *pnOut, void **ppOut        /* OUT: Inverse of input */
    ++);
    ++
    ++/*
    ++** CAPI3REF: Concatenate Two Changeset Objects
    ++**
    ++** This function is used to concatenate two changesets, A and B, into a 
    ++** single changeset. The result is a changeset equivalent to applying
    ++** changeset A followed by changeset B. 
    ++**
    ++** This function combines the two input changesets using an 
    ++** sqlite3_changegroup object. Calling it produces similar results as the
    ++** following code fragment:
    ++**
    ++**   sqlite3_changegroup *pGrp;
    ++**   rc = sqlite3_changegroup_new(&pGrp);
    ++**   if( rc==SQLITE_OK ) rc = sqlite3changegroup_add(pGrp, nA, pA);
    ++**   if( rc==SQLITE_OK ) rc = sqlite3changegroup_add(pGrp, nB, pB);
    ++**   if( rc==SQLITE_OK ){
    ++**     rc = sqlite3changegroup_output(pGrp, pnOut, ppOut);
    ++**   }else{
    ++**     *ppOut = 0;
    ++**     *pnOut = 0;
    ++**   }
    ++**
    ++** Refer to the sqlite3_changegroup documentation below for details.
    ++*/
    ++SQLITE_API int sqlite3changeset_concat(
    ++  int nA,                         /* Number of bytes in buffer pA */
    ++  void *pA,                       /* Pointer to buffer containing changeset A */
    ++  int nB,                         /* Number of bytes in buffer pB */
    ++  void *pB,                       /* Pointer to buffer containing changeset B */
    ++  int *pnOut,                     /* OUT: Number of bytes in output changeset */
    ++  void **ppOut                    /* OUT: Buffer containing output changeset */
    ++);
    ++
    ++
    ++/*
    ++** CAPI3REF: Changegroup Handle
    ++*/
    ++typedef struct sqlite3_changegroup sqlite3_changegroup;
    ++
    ++/*
    ++** CAPI3REF: Create A New Changegroup Object
    ++**
    ++** An sqlite3_changegroup object is used to combine two or more changesets
    ++** (or patchsets) into a single changeset (or patchset). A single changegroup
    ++** object may combine changesets or patchsets, but not both. The output is
    ++** always in the same format as the input.
    ++**
    ++** If successful, this function returns SQLITE_OK and populates (*pp) with
    ++** a pointer to a new sqlite3_changegroup object before returning. The caller
    ++** should eventually free the returned object using a call to 
    ++** sqlite3changegroup_delete(). If an error occurs, an SQLite error code
    ++** (i.e. SQLITE_NOMEM) is returned and *pp is set to NULL.
    ++**
    ++** The usual usage pattern for an sqlite3_changegroup object is as follows:
    ++**
    ++** <ul>
    ++**   <li> It is created using a call to sqlite3changegroup_new().
    ++**
    ++**   <li> Zero or more changesets (or patchsets) are added to the object
    ++**        by calling sqlite3changegroup_add().
    ++**
    ++**   <li> The result of combining all input changesets together is obtained 
    ++**        by the application via a call to sqlite3changegroup_output().
    ++**
    ++**   <li> The object is deleted using a call to sqlite3changegroup_delete().
    ++** </ul>
    ++**
    ++** Any number of calls to add() and output() may be made between the calls to
    ++** new() and delete(), and in any order.
    ++**
    ++** As well as the regular sqlite3changegroup_add() and 
    ++** sqlite3changegroup_output() functions, also available are the streaming
    ++** versions sqlite3changegroup_add_strm() and sqlite3changegroup_output_strm().
    ++*/
    ++SQLITE_API int sqlite3changegroup_new(sqlite3_changegroup **pp);
    ++
    ++/*
    ++** CAPI3REF: Add A Changeset To A Changegroup
    ++**
    ++** Add all changes within the changeset (or patchset) in buffer pData (size
    ++** nData bytes) to the changegroup. 
    ++**
    ++** If the buffer contains a patchset, then all prior calls to this function
    ++** on the same changegroup object must also have specified patchsets. Or, if
    ++** the buffer contains a changeset, so must have the earlier calls to this
    ++** function. Otherwise, SQLITE_ERROR is returned and no changes are added
    ++** to the changegroup.
    ++**
    ++** Rows within the changeset and changegroup are identified by the values in
    ++** their PRIMARY KEY columns. A change in the changeset is considered to
    ++** apply to the same row as a change already present in the changegroup if
    ++** the two rows have the same primary key.
    ++**
    ++** Changes to rows that do not already appear in the changegroup are
    ++** simply copied into it. Or, if both the new changeset and the changegroup
    ++** contain changes that apply to a single row, the final contents of the
    ++** changegroup depends on the type of each change, as follows:
    ++**
    ++** <table border=1 style="margin-left:8ex;margin-right:8ex">
    ++**   <tr><th style="white-space:pre">Existing Change  </th>
    ++**       <th style="white-space:pre">New Change       </th>
    ++**       <th>Output Change
    ++**   <tr><td>INSERT <td>INSERT <td>
    ++**       The new change is ignored. This case does not occur if the new
    ++**       changeset was recorded immediately after the changesets already
    ++**       added to the changegroup.
    ++**   <tr><td>INSERT <td>UPDATE <td>
    ++**       The INSERT change remains in the changegroup. The values in the 
    ++**       INSERT change are modified as if the row was inserted by the
    ++**       existing change and then updated according to the new change.
    ++**   <tr><td>INSERT <td>DELETE <td>
    ++**       The existing INSERT is removed from the changegroup. The DELETE is
    ++**       not added.
    ++**   <tr><td>UPDATE <td>INSERT <td>
    ++**       The new change is ignored. This case does not occur if the new
    ++**       changeset was recorded immediately after the changesets already
    ++**       added to the changegroup.
    ++**   <tr><td>UPDATE <td>UPDATE <td>
    ++**       The existing UPDATE remains within the changegroup. It is amended 
    ++**       so that the accompanying values are as if the row was updated once 
    ++**       by the existing change and then again by the new change.
    ++**   <tr><td>UPDATE <td>DELETE <td>
    ++**       The existing UPDATE is replaced by the new DELETE within the
    ++**       changegroup.
    ++**   <tr><td>DELETE <td>INSERT <td>
    ++**       If one or more of the column values in the row inserted by the
    ++**       new change differ from those in the row deleted by the existing 
    ++**       change, the existing DELETE is replaced by an UPDATE within the
    ++**       changegroup. Otherwise, if the inserted row is exactly the same 
    ++**       as the deleted row, the existing DELETE is simply discarded.
    ++**   <tr><td>DELETE <td>UPDATE <td>
    ++**       The new change is ignored. This case does not occur if the new
    ++**       changeset was recorded immediately after the changesets already
    ++**       added to the changegroup.
    ++**   <tr><td>DELETE <td>DELETE <td>
    ++**       The new change is ignored. This case does not occur if the new
    ++**       changeset was recorded immediately after the changesets already
    ++**       added to the changegroup.
    ++** </table>
    ++**
    ++** If the new changeset contains changes to a table that is already present
    ++** in the changegroup, then the number of columns and the position of the
    ++** primary key columns for the table must be consistent. If this is not the
    ++** case, this function fails with SQLITE_SCHEMA. If the input changeset
    ++** appears to be corrupt and the corruption is detected, SQLITE_CORRUPT is
    ++** returned. Or, if an out-of-memory condition occurs during processing, this
    ++** function returns SQLITE_NOMEM. In all cases, if an error occurs the
    ++** final contents of the changegroup is undefined.
    ++**
    ++** If no error occurs, SQLITE_OK is returned.
    ++*/
    ++SQLITE_API int sqlite3changegroup_add(sqlite3_changegroup*, int nData, void *pData);
    ++
    ++/*
    ++** CAPI3REF: Obtain A Composite Changeset From A Changegroup
    ++**
    ++** Obtain a buffer containing a changeset (or patchset) representing the
    ++** current contents of the changegroup. If the inputs to the changegroup
    ++** were themselves changesets, the output is a changeset. Or, if the
    ++** inputs were patchsets, the output is also a patchset.
    ++**
    ++** As with the output of the sqlite3session_changeset() and
    ++** sqlite3session_patchset() functions, all changes related to a single
    ++** table are grouped together in the output of this function. Tables appear
    ++** in the same order as for the very first changeset added to the changegroup.
    ++** If the second or subsequent changesets added to the changegroup contain
    ++** changes for tables that do not appear in the first changeset, they are
    ++** appended onto the end of the output changeset, again in the order in
    ++** which they are first encountered.
    ++**
    ++** If an error occurs, an SQLite error code is returned and the output
    ++** variables (*pnData) and (*ppData) are set to 0. Otherwise, SQLITE_OK
    ++** is returned and the output variables are set to the size of and a 
    ++** pointer to the output buffer, respectively. In this case it is the
    ++** responsibility of the caller to eventually free the buffer using a
    ++** call to sqlite3_free().
    ++*/
    ++SQLITE_API int sqlite3changegroup_output(
    ++  sqlite3_changegroup*,
    ++  int *pnData,                    /* OUT: Size of output buffer in bytes */
    ++  void **ppData                   /* OUT: Pointer to output buffer */
    ++);
    ++
    ++/*
    ++** CAPI3REF: Delete A Changegroup Object
    ++*/
    ++SQLITE_API void sqlite3changegroup_delete(sqlite3_changegroup*);
    ++
    ++/*
    ++** CAPI3REF: Apply A Changeset To A Database
    ++**
    ++** Apply a changeset to a database. This function attempts to update the
    ++** "main" database attached to handle db with the changes found in the
    ++** changeset passed via the second and third arguments.
    ++**
    ++** The fourth argument (xFilter) passed to this function is the "filter
    ++** callback". If it is not NULL, then for each table affected by at least one
    ++** change in the changeset, the filter callback is invoked with
    ++** the table name as the second argument, and a copy of the context pointer
    ++** passed as the sixth argument to this function as the first. If the "filter
    ++** callback" returns zero, then no attempt is made to apply any changes to 
    ++** the table. Otherwise, if the return value is non-zero or the xFilter
    ++** argument to this function is NULL, all changes related to the table are
    ++** attempted.
    ++**
    ++** For each table that is not excluded by the filter callback, this function 
    ++** tests that the target database contains a compatible table. A table is 
    ++** considered compatible if all of the following are true:
    ++**
    ++** <ul>
    ++**   <li> The table has the same name as the name recorded in the 
    ++**        changeset, and
    ++**   <li> The table has at least as many columns as recorded in the 
    ++**        changeset, and
    ++**   <li> The table has primary key columns in the same position as 
    ++**        recorded in the changeset.
    ++** </ul>
    ++**
    ++** If there is no compatible table, it is not an error, but none of the
    ++** changes associated with the table are applied. A warning message is issued
    ++** via the sqlite3_log() mechanism with the error code SQLITE_SCHEMA. At most
    ++** one such warning is issued for each table in the changeset.
    ++**
    ++** For each change for which there is a compatible table, an attempt is made 
    ++** to modify the table contents according to the UPDATE, INSERT or DELETE 
    ++** change. If a change cannot be applied cleanly, the conflict handler 
    ++** function passed as the fifth argument to sqlite3changeset_apply() may be 
    ++** invoked. A description of exactly when the conflict handler is invoked for 
    ++** each type of change is below.
    ++**
    ++** Unlike the xFilter argument, xConflict may not be passed NULL. The results
    ++** of passing anything other than a valid function pointer as the xConflict
    ++** argument are undefined.
    ++**
    ++** Each time the conflict handler function is invoked, it must return one
    ++** of [SQLITE_CHANGESET_OMIT], [SQLITE_CHANGESET_ABORT] or 
    ++** [SQLITE_CHANGESET_REPLACE]. SQLITE_CHANGESET_REPLACE may only be returned
    ++** if the second argument passed to the conflict handler is either
    ++** SQLITE_CHANGESET_DATA or SQLITE_CHANGESET_CONFLICT. If the conflict-handler
    ++** returns an illegal value, any changes already made are rolled back and
    ++** the call to sqlite3changeset_apply() returns SQLITE_MISUSE. Different 
    ++** actions are taken by sqlite3changeset_apply() depending on the value
    ++** returned by each invocation of the conflict-handler function. Refer to
    ++** the documentation for the three 
    ++** [SQLITE_CHANGESET_OMIT|available return values] for details.
    ++**
    ++** <dl>
    ++** <dt>DELETE Changes<dd>
    ++**   For each DELETE change, this function checks if the target database 
    ++**   contains a row with the same primary key value (or values) as the 
    ++**   original row values stored in the changeset. If it does, and the values 
    ++**   stored in all non-primary key columns also match the values stored in 
    ++**   the changeset the row is deleted from the target database.
    ++**
    ++**   If a row with matching primary key values is found, but one or more of
    ++**   the non-primary key fields contains a value different from the original
    ++**   row value stored in the changeset, the conflict-handler function is
    ++**   invoked with [SQLITE_CHANGESET_DATA] as the second argument. If the
    ++**   database table has more columns than are recorded in the changeset,
    ++**   only the values of those non-primary key fields are compared against
    ++**   the current database contents - any trailing database table columns
    ++**   are ignored.
    ++**
    ++**   If no row with matching primary key values is found in the database,
    ++**   the conflict-handler function is invoked with [SQLITE_CHANGESET_NOTFOUND]
    ++**   passed as the second argument.
    ++**
    ++**   If the DELETE operation is attempted, but SQLite returns SQLITE_CONSTRAINT
    ++**   (which can only happen if a foreign key constraint is violated), the
    ++**   conflict-handler function is invoked with [SQLITE_CHANGESET_CONSTRAINT]
    ++**   passed as the second argument. This includes the case where the DELETE
    ++**   operation is attempted because an earlier call to the conflict handler
    ++**   function returned [SQLITE_CHANGESET_REPLACE].
    ++**
    ++** <dt>INSERT Changes<dd>
    ++**   For each INSERT change, an attempt is made to insert the new row into
    ++**   the database. If the changeset row contains fewer fields than the
    ++**   database table, the trailing fields are populated with their default
    ++**   values.
    ++**
    ++**   If the attempt to insert the row fails because the database already 
    ++**   contains a row with the same primary key values, the conflict handler
    ++**   function is invoked with the second argument set to 
    ++**   [SQLITE_CHANGESET_CONFLICT].
    ++**
    ++**   If the attempt to insert the row fails because of some other constraint
    ++**   violation (e.g. NOT NULL or UNIQUE), the conflict handler function is 
    ++**   invoked with the second argument set to [SQLITE_CHANGESET_CONSTRAINT].
    ++**   This includes the case where the INSERT operation is re-attempted because 
    ++**   an earlier call to the conflict handler function returned 
    ++**   [SQLITE_CHANGESET_REPLACE].
    ++**
    ++** <dt>UPDATE Changes<dd>
    ++**   For each UPDATE change, this function checks if the target database 
    ++**   contains a row with the same primary key value (or values) as the 
    ++**   original row values stored in the changeset. If it does, and the values 
    ++**   stored in all modified non-primary key columns also match the values
    ++**   stored in the changeset the row is updated within the target database.
    ++**
    ++**   If a row with matching primary key values is found, but one or more of
    ++**   the modified non-primary key fields contains a value different from an
    ++**   original row value stored in the changeset, the conflict-handler function
    ++**   is invoked with [SQLITE_CHANGESET_DATA] as the second argument. Since
    ++**   UPDATE changes only contain values for non-primary key fields that are
    ++**   to be modified, only those fields need to match the original values to
    ++**   avoid the SQLITE_CHANGESET_DATA conflict-handler callback.
    ++**
    ++**   If no row with matching primary key values is found in the database,
    ++**   the conflict-handler function is invoked with [SQLITE_CHANGESET_NOTFOUND]
    ++**   passed as the second argument.
    ++**
    ++**   If the UPDATE operation is attempted, but SQLite returns 
    ++**   SQLITE_CONSTRAINT, the conflict-handler function is invoked with 
    ++**   [SQLITE_CHANGESET_CONSTRAINT] passed as the second argument.
    ++**   This includes the case where the UPDATE operation is attempted after 
    ++**   an earlier call to the conflict handler function returned
    ++**   [SQLITE_CHANGESET_REPLACE].  
    ++** </dl>
    ++**
    ++** It is safe to execute SQL statements, including those that write to the
    ++** table that the callback related to, from within the xConflict callback.
    ++** This can be used to further customize the applications conflict
    ++** resolution strategy.
    ++**
    ++** All changes made by this function are enclosed in a savepoint transaction.
    ++** If any other error (aside from a constraint failure when attempting to
    ++** write to the target database) occurs, then the savepoint transaction is
    ++** rolled back, restoring the target database to its original state, and an 
    ++** SQLite error code returned.
    ++*/
    ++SQLITE_API int sqlite3changeset_apply(
    ++  sqlite3 *db,                    /* Apply change to "main" db of this handle */
    ++  int nChangeset,                 /* Size of changeset in bytes */
    ++  void *pChangeset,               /* Changeset blob */
    ++  int(*xFilter)(
    ++    void *pCtx,                   /* Copy of sixth arg to _apply() */
    ++    const char *zTab              /* Table name */
    ++  ),
    ++  int(*xConflict)(
    ++    void *pCtx,                   /* Copy of sixth arg to _apply() */
    ++    int eConflict,                /* DATA, MISSING, CONFLICT, CONSTRAINT */
    ++    sqlite3_changeset_iter *p     /* Handle describing change and conflict */
    ++  ),
    ++  void *pCtx                      /* First argument passed to xConflict */
    ++);
    ++
    ++/* 
    ++** CAPI3REF: Constants Passed To The Conflict Handler
    ++**
    ++** Values that may be passed as the second argument to a conflict-handler.
    ++**
    ++** <dl>
    ++** <dt>SQLITE_CHANGESET_DATA<dd>
    ++**   The conflict handler is invoked with CHANGESET_DATA as the second argument
    ++**   when processing a DELETE or UPDATE change if a row with the required
    ++**   PRIMARY KEY fields is present in the database, but one or more other 
    ++**   (non primary-key) fields modified by the update do not contain the 
    ++**   expected "before" values.
    ++** 
    ++**   The conflicting row, in this case, is the database row with the matching
    ++**   primary key.
    ++** 
    ++** <dt>SQLITE_CHANGESET_NOTFOUND<dd>
    ++**   The conflict handler is invoked with CHANGESET_NOTFOUND as the second
    ++**   argument when processing a DELETE or UPDATE change if a row with the
    ++**   required PRIMARY KEY fields is not present in the database.
    ++** 
    ++**   There is no conflicting row in this case. The results of invoking the
    ++**   sqlite3changeset_conflict() API are undefined.
    ++** 
    ++** <dt>SQLITE_CHANGESET_CONFLICT<dd>
    ++**   CHANGESET_CONFLICT is passed as the second argument to the conflict
    ++**   handler while processing an INSERT change if the operation would result 
    ++**   in duplicate primary key values.
    ++** 
    ++**   The conflicting row in this case is the database row with the matching
    ++**   primary key.
    ++**
    ++** <dt>SQLITE_CHANGESET_FOREIGN_KEY<dd>
    ++**   If foreign key handling is enabled, and applying a changeset leaves the
    ++**   database in a state containing foreign key violations, the conflict 
    ++**   handler is invoked with CHANGESET_FOREIGN_KEY as the second argument
    ++**   exactly once before the changeset is committed. If the conflict handler
    ++**   returns CHANGESET_OMIT, the changes, including those that caused the
    ++**   foreign key constraint violation, are committed. Or, if it returns
    ++**   CHANGESET_ABORT, the changeset is rolled back.
    ++**
    ++**   No current or conflicting row information is provided. The only function
    ++**   it is possible to call on the supplied sqlite3_changeset_iter handle
    ++**   is sqlite3changeset_fk_conflicts().
    ++** 
    ++** <dt>SQLITE_CHANGESET_CONSTRAINT<dd>
    ++**   If any other constraint violation occurs while applying a change (i.e. 
    ++**   a UNIQUE, CHECK or NOT NULL constraint), the conflict handler is 
    ++**   invoked with CHANGESET_CONSTRAINT as the second argument.
    ++** 
    ++**   There is no conflicting row in this case. The results of invoking the
    ++**   sqlite3changeset_conflict() API are undefined.
    ++**
    ++** </dl>
    ++*/
    ++#define SQLITE_CHANGESET_DATA        1
    ++#define SQLITE_CHANGESET_NOTFOUND    2
    ++#define SQLITE_CHANGESET_CONFLICT    3
    ++#define SQLITE_CHANGESET_CONSTRAINT  4
    ++#define SQLITE_CHANGESET_FOREIGN_KEY 5
    ++
    ++/* 
    ++** CAPI3REF: Constants Returned By The Conflict Handler
    ++**
    ++** A conflict handler callback must return one of the following three values.
    ++**
    ++** <dl>
    ++** <dt>SQLITE_CHANGESET_OMIT<dd>
    ++**   If a conflict handler returns this value no special action is taken. The
    ++**   change that caused the conflict is not applied. The session module 
    ++**   continues to the next change in the changeset.
    ++**
    ++** <dt>SQLITE_CHANGESET_REPLACE<dd>
    ++**   This value may only be returned if the second argument to the conflict
    ++**   handler was SQLITE_CHANGESET_DATA or SQLITE_CHANGESET_CONFLICT. If this
    ++**   is not the case, any changes applied so far are rolled back and the 
    ++**   call to sqlite3changeset_apply() returns SQLITE_MISUSE.
    ++**
    ++**   If CHANGESET_REPLACE is returned by an SQLITE_CHANGESET_DATA conflict
    ++**   handler, then the conflicting row is either updated or deleted, depending
    ++**   on the type of change.
    ++**
    ++**   If CHANGESET_REPLACE is returned by an SQLITE_CHANGESET_CONFLICT conflict
    ++**   handler, then the conflicting row is removed from the database and a
    ++**   second attempt to apply the change is made. If this second attempt fails,
    ++**   the original row is restored to the database before continuing.
    ++**
    ++** <dt>SQLITE_CHANGESET_ABORT<dd>
    ++**   If this value is returned, any changes applied so far are rolled back 
    ++**   and the call to sqlite3changeset_apply() returns SQLITE_ABORT.
    ++** </dl>
    ++*/
    ++#define SQLITE_CHANGESET_OMIT       0
    ++#define SQLITE_CHANGESET_REPLACE    1
    ++#define SQLITE_CHANGESET_ABORT      2
    ++
    ++/*
    ++** CAPI3REF: Streaming Versions of API functions.
    ++**
    ++** The six streaming API xxx_strm() functions serve similar purposes to the 
    ++** corresponding non-streaming API functions:
    ++**
    ++** <table border=1 style="margin-left:8ex;margin-right:8ex">
    ++**   <tr><th>Streaming function<th>Non-streaming equivalent</th>
    ++**   <tr><td>sqlite3changeset_apply_strm<td>[sqlite3changeset_apply] 
    ++**   <tr><td>sqlite3changeset_concat_strm<td>[sqlite3changeset_concat] 
    ++**   <tr><td>sqlite3changeset_invert_strm<td>[sqlite3changeset_invert] 
    ++**   <tr><td>sqlite3changeset_start_strm<td>[sqlite3changeset_start] 
    ++**   <tr><td>sqlite3session_changeset_strm<td>[sqlite3session_changeset] 
    ++**   <tr><td>sqlite3session_patchset_strm<td>[sqlite3session_patchset] 
    ++** </table>
    ++**
    ++** Non-streaming functions that accept changesets (or patchsets) as input
    ++** require that the entire changeset be stored in a single buffer in memory. 
    ++** Similarly, those that return a changeset or patchset do so by returning 
    ++** a pointer to a single large buffer allocated using sqlite3_malloc(). 
    ++** Normally this is convenient. However, if an application running in a 
    ++** low-memory environment is required to handle very large changesets, the
    ++** large contiguous memory allocations required can become onerous.
    ++**
    ++** In order to avoid this problem, instead of a single large buffer, input
    ++** is passed to a streaming API functions by way of a callback function that
    ++** the sessions module invokes to incrementally request input data as it is
    ++** required. In all cases, a pair of API function parameters such as
    ++**
    ++**  <pre>
    ++**  &nbsp;     int nChangeset,
    ++**  &nbsp;     void *pChangeset,
    ++**  </pre>
    ++**
    ++** Is replaced by:
    ++**
    ++**  <pre>
    ++**  &nbsp;     int (*xInput)(void *pIn, void *pData, int *pnData),
    ++**  &nbsp;     void *pIn,
    ++**  </pre>
    ++**
    ++** Each time the xInput callback is invoked by the sessions module, the first
    ++** argument passed is a copy of the supplied pIn context pointer. The second 
    ++** argument, pData, points to a buffer (*pnData) bytes in size. Assuming no 
    ++** error occurs the xInput method should copy up to (*pnData) bytes of data 
    ++** into the buffer and set (*pnData) to the actual number of bytes copied 
    ++** before returning SQLITE_OK. If the input is completely exhausted, (*pnData) 
    ++** should be set to zero to indicate this. Or, if an error occurs, an SQLite 
    ++** error code should be returned. In all cases, if an xInput callback returns
    ++** an error, all processing is abandoned and the streaming API function
    ++** returns a copy of the error code to the caller.
    ++**
    ++** In the case of sqlite3changeset_start_strm(), the xInput callback may be
    ++** invoked by the sessions module at any point during the lifetime of the
    ++** iterator. If such an xInput callback returns an error, the iterator enters
    ++** an error state, whereby all subsequent calls to iterator functions 
    ++** immediately fail with the same error code as returned by xInput.
    ++**
    ++** Similarly, streaming API functions that return changesets (or patchsets)
    ++** return them in chunks by way of a callback function instead of via a
    ++** pointer to a single large buffer. In this case, a pair of parameters such
    ++** as:
    ++**
    ++**  <pre>
    ++**  &nbsp;     int *pnChangeset,
    ++**  &nbsp;     void **ppChangeset,
    ++**  </pre>
    ++**
    ++** Is replaced by:
    ++**
    ++**  <pre>
    ++**  &nbsp;     int (*xOutput)(void *pOut, const void *pData, int nData),
    ++**  &nbsp;     void *pOut
    ++**  </pre>
    ++**
    ++** The xOutput callback is invoked zero or more times to return data to
    ++** the application. The first parameter passed to each call is a copy of the
    ++** pOut pointer supplied by the application. The second parameter, pData,
    ++** points to a buffer nData bytes in size containing the chunk of output
    ++** data being returned. If the xOutput callback successfully processes the
    ++** supplied data, it should return SQLITE_OK to indicate success. Otherwise,
    ++** it should return some other SQLite error code. In this case processing
    ++** is immediately abandoned and the streaming API function returns a copy
    ++** of the xOutput error code to the application.
    ++**
    ++** The sessions module never invokes an xOutput callback with the third 
    ++** parameter set to a value less than or equal to zero. Other than this,
    ++** no guarantees are made as to the size of the chunks of data returned.
    ++*/
    ++SQLITE_API int sqlite3changeset_apply_strm(
    ++  sqlite3 *db,                    /* Apply change to "main" db of this handle */
    ++  int (*xInput)(void *pIn, void *pData, int *pnData), /* Input function */
    ++  void *pIn,                                          /* First arg for xInput */
    ++  int(*xFilter)(
    ++    void *pCtx,                   /* Copy of sixth arg to _apply() */
    ++    const char *zTab              /* Table name */
    ++  ),
    ++  int(*xConflict)(
    ++    void *pCtx,                   /* Copy of sixth arg to _apply() */
    ++    int eConflict,                /* DATA, MISSING, CONFLICT, CONSTRAINT */
    ++    sqlite3_changeset_iter *p     /* Handle describing change and conflict */
    ++  ),
    ++  void *pCtx                      /* First argument passed to xConflict */
    ++);
    ++SQLITE_API int sqlite3changeset_concat_strm(
    ++  int (*xInputA)(void *pIn, void *pData, int *pnData),
    ++  void *pInA,
    ++  int (*xInputB)(void *pIn, void *pData, int *pnData),
    ++  void *pInB,
    ++  int (*xOutput)(void *pOut, const void *pData, int nData),
    ++  void *pOut
    ++);
    ++SQLITE_API int sqlite3changeset_invert_strm(
    ++  int (*xInput)(void *pIn, void *pData, int *pnData),
    ++  void *pIn,
    ++  int (*xOutput)(void *pOut, const void *pData, int nData),
    ++  void *pOut
    ++);
    ++SQLITE_API int sqlite3changeset_start_strm(
    ++  sqlite3_changeset_iter **pp,
    ++  int (*xInput)(void *pIn, void *pData, int *pnData),
    ++  void *pIn
    ++);
    ++SQLITE_API int sqlite3session_changeset_strm(
    ++  sqlite3_session *pSession,
    ++  int (*xOutput)(void *pOut, const void *pData, int nData),
    ++  void *pOut
    ++);
    ++SQLITE_API int sqlite3session_patchset_strm(
    ++  sqlite3_session *pSession,
    ++  int (*xOutput)(void *pOut, const void *pData, int nData),
    ++  void *pOut
    ++);
    ++SQLITE_API int sqlite3changegroup_add_strm(sqlite3_changegroup*, 
    ++    int (*xInput)(void *pIn, void *pData, int *pnData),
    ++    void *pIn
    ++);
    ++SQLITE_API int sqlite3changegroup_output_strm(sqlite3_changegroup*,
    ++    int (*xOutput)(void *pOut, const void *pData, int nData), 
    ++    void *pOut
    ++);
    ++
    ++
    ++/*
    ++** Make sure we can call this stuff from C++.
    ++*/
    ++#if 0
    ++}
    ++#endif
    ++
    ++#endif  /* !defined(__SQLITESESSION_H_) && defined(SQLITE_ENABLE_SESSION) */
    ++
    ++/******** End of sqlite3session.h *********/
    ++/******** Begin file fts5.h *********/
    + /*
    + ** 2014 May 31
    + **
    +@@ -8220,6 +11354,9 @@ struct Fts5PhraseIter {
    + **   an OOM condition or IO error), an appropriate SQLite error code is 
    + **   returned.
    + **
    ++**   This function may be quite inefficient if used with an FTS5 table
    ++**   created with the "columnsize=0" option.
    ++**
    + ** xColumnText:
    + **   This function attempts to retrieve the text of column iCol of the
    + **   current document. If successful, (*pz) is set to point to a buffer
    +@@ -8240,15 +11377,29 @@ struct Fts5PhraseIter {
    + **   the query within the current row. Return SQLITE_OK if successful, or
    + **   an error code (i.e. SQLITE_NOMEM) if an error occurs.
    + **
    ++**   This API can be quite slow if used with an FTS5 table created with the
    ++**   "detail=none" or "detail=column" option. If the FTS5 table is created 
    ++**   with either "detail=none" or "detail=column" and "content=" option 
    ++**   (i.e. if it is a contentless table), then this API always returns 0.
    ++**
    + ** xInst:
    + **   Query for the details of phrase match iIdx within the current row.
    + **   Phrase matches are numbered starting from zero, so the iIdx argument
    + **   should be greater than or equal to zero and smaller than the value
    + **   output by xInstCount().
    + **
    ++**   Usually, output parameter *piPhrase is set to the phrase number, *piCol
    ++**   to the column in which it occurs and *piOff the token offset of the
    ++**   first token of the phrase. The exception is if the table was created
    ++**   with the offsets=0 option specified. In this case *piOff is always
    ++**   set to -1.
    ++**
    + **   Returns SQLITE_OK if successful, or an error code (i.e. SQLITE_NOMEM) 
    + **   if an error occurs.
    + **
    ++**   This API can be quite slow if used with an FTS5 table created with the
    ++**   "detail=none" or "detail=column" option. 
    ++**
    + ** xRowid:
    + **   Returns the rowid of the current row.
    + **
    +@@ -8262,11 +11413,13 @@ struct Fts5PhraseIter {
    + **       ... FROM ftstable WHERE ftstable MATCH $p ORDER BY rowid
    + **
    + **   with $p set to a phrase equivalent to the phrase iPhrase of the
    +-**   current query is executed. For each row visited, the callback function
    +-**   passed as the fourth argument is invoked. The context and API objects 
    +-**   passed to the callback function may be used to access the properties of
    +-**   each matched row. Invoking Api.xUserData() returns a copy of the pointer
    +-**   passed as the third argument to pUserData.
    ++**   current query is executed. Any column filter that applies to
    ++**   phrase iPhrase of the current query is included in $p. For each 
    ++**   row visited, the callback function passed as the fourth argument 
    ++**   is invoked. The context and API objects passed to the callback 
    ++**   function may be used to access the properties of each matched row.
    ++**   Invoking Api.xUserData() returns a copy of the pointer passed as 
    ++**   the third argument to pUserData.
    + **
    + **   If the callback function returns any value other than SQLITE_OK, the
    + **   query is abandoned and the xQueryPhrase function returns immediately.
    +@@ -8332,7 +11485,7 @@ struct Fts5PhraseIter {
    + **       Fts5PhraseIter iter;
    + **       int iCol, iOff;
    + **       for(pApi->xPhraseFirst(pFts, iPhrase, &iter, &iCol, &iOff);
    +-**           iOff>=0;
    ++**           iCol>=0;
    + **           pApi->xPhraseNext(pFts, &iter, &iCol, &iOff)
    + **       ){
    + **         // An instance of phrase iPhrase at offset iOff of column iCol
    +@@ -8340,13 +11493,51 @@ struct Fts5PhraseIter {
    + **
    + **   The Fts5PhraseIter structure is defined above. Applications should not
    + **   modify this structure directly - it should only be used as shown above
    +-**   with the xPhraseFirst() and xPhraseNext() API methods.
    ++**   with the xPhraseFirst() and xPhraseNext() API methods (and by
    ++**   xPhraseFirstColumn() and xPhraseNextColumn() as illustrated below).
    ++**
    ++**   This API can be quite slow if used with an FTS5 table created with the
    ++**   "detail=none" or "detail=column" option. If the FTS5 table is created 
    ++**   with either "detail=none" or "detail=column" and "content=" option 
    ++**   (i.e. if it is a contentless table), then this API always iterates
    ++**   through an empty set (all calls to xPhraseFirst() set iCol to -1).
    + **
    + ** xPhraseNext()
    + **   See xPhraseFirst above.
    ++**
    ++** xPhraseFirstColumn()
    ++**   This function and xPhraseNextColumn() are similar to the xPhraseFirst()
    ++**   and xPhraseNext() APIs described above. The difference is that instead
    ++**   of iterating through all instances of a phrase in the current row, these
    ++**   APIs are used to iterate through the set of columns in the current row
    ++**   that contain one or more instances of a specified phrase. For example:
    ++**
    ++**       Fts5PhraseIter iter;
    ++**       int iCol;
    ++**       for(pApi->xPhraseFirstColumn(pFts, iPhrase, &iter, &iCol);
    ++**           iCol>=0;
    ++**           pApi->xPhraseNextColumn(pFts, &iter, &iCol)
    ++**       ){
    ++**         // Column iCol contains at least one instance of phrase iPhrase
    ++**       }
    ++**
    ++**   This API can be quite slow if used with an FTS5 table created with the
    ++**   "detail=none" option. If the FTS5 table is created with either 
    ++**   "detail=none" "content=" option (i.e. if it is a contentless table), 
    ++**   then this API always iterates through an empty set (all calls to 
    ++**   xPhraseFirstColumn() set iCol to -1).
    ++**
    ++**   The information accessed using this API and its companion
    ++**   xPhraseFirstColumn() may also be obtained using xPhraseFirst/xPhraseNext
    ++**   (or xInst/xInstCount). The chief advantage of this API is that it is
    ++**   significantly more efficient than those alternatives when used with
    ++**   "detail=column" tables.  
    ++**
    ++** xPhraseNextColumn()
    ++**   See xPhraseFirstColumn above.
    + */
    + struct Fts5ExtensionApi {
    +-  int iVersion;                   /* Currently always set to 1 */
    ++  int iVersion;                   /* Currently always set to 3 */
    + 
    +   void *(*xUserData)(Fts5Context*);
    + 
    +@@ -8376,8 +11567,11 @@ struct Fts5ExtensionApi {
    +   int (*xSetAuxdata)(Fts5Context*, void *pAux, void(*xDelete)(void*));
    +   void *(*xGetAuxdata)(Fts5Context*, int bClear);
    + 
    +-  void (*xPhraseFirst)(Fts5Context*, int iPhrase, Fts5PhraseIter*, int*, int*);
    ++  int (*xPhraseFirst)(Fts5Context*, int iPhrase, Fts5PhraseIter*, int*, int*);
    +   void (*xPhraseNext)(Fts5Context*, Fts5PhraseIter*, int *piCol, int *piOff);
    ++
    ++  int (*xPhraseFirstColumn)(Fts5Context*, int iPhrase, Fts5PhraseIter*, int*);
    ++  void (*xPhraseNextColumn)(Fts5Context*, Fts5PhraseIter*, int *piCol);
    + };
    + 
    + /* 
    +@@ -8394,7 +11588,7 @@ struct Fts5ExtensionApi {
    + ** behaviour. The structure methods are expected to function as follows:
    + **
    + ** xCreate:
    +-**   This function is used to allocate and inititalize a tokenizer instance.
    ++**   This function is used to allocate and initialize a tokenizer instance.
    + **   A tokenizer instance is required to actually tokenize text.
    + **
    + **   The first argument passed to this function is a copy of the (void*)
    +@@ -8654,7 +11848,7 @@ struct fts5_api {
    + 
    + #endif /* _FTS5_H */
    + 
    +-
    ++/******** End of fts5.h *********/
    + 
    + /************** End of sqlite3.h *********************************************/
    + /************** Continuing where we left off in sqliteInt.h ******************/
    +@@ -8663,8 +11857,9 @@ struct fts5_api {
    + ** Include the configuration header output by 'configure' if we're using the
    + ** autoconf-based build
    + */
    +-#ifdef _HAVE_SQLITE_CONFIG_H
    +-#include "config.h"
    ++#if defined(_HAVE_SQLITE_CONFIG_H) && !defined(SQLITECONFIG_H)
    ++/* #include "config.h" */
    ++#define SQLITECONFIG_H 1
    + #endif
    + 
    + /************** Include sqliteLimit.h in the middle of sqliteInt.h ***********/
    +@@ -8758,7 +11953,7 @@ struct fts5_api {
    + ** Not currently enforced.
    + */
    + #ifndef SQLITE_MAX_VDBE_OP
    +-# define SQLITE_MAX_VDBE_OP 25000
    ++# define SQLITE_MAX_VDBE_OP 250000000
    + #endif
    + 
    + /*
    +@@ -8772,13 +11967,13 @@ struct fts5_api {
    + ** The suggested maximum number of in-memory pages to use for
    + ** the main database table and for temporary tables.
    + **
    +-** IMPLEMENTATION-OF: R-31093-59126 The default suggested cache size
    +-** is 2000 pages.
    ++** IMPLEMENTATION-OF: R-30185-15359 The default suggested cache size is -2000,
    ++** which means the cache size is limited to 2048000 bytes of memory.
    + ** IMPLEMENTATION-OF: R-48205-43578 The default suggested cache size can be
    + ** altered using the SQLITE_DEFAULT_CACHE_SIZE compile-time options.
    + */
    + #ifndef SQLITE_DEFAULT_CACHE_SIZE
    +-# define SQLITE_DEFAULT_CACHE_SIZE  2000
    ++# define SQLITE_DEFAULT_CACHE_SIZE  -2000
    + #endif
    + 
    + /*
    +@@ -8791,8 +11986,9 @@ struct fts5_api {
    + 
    + /*
    + ** The maximum number of attached databases.  This must be between 0
    +-** and 62.  The upper bound on 62 is because a 64-bit integer bitmap
    +-** is used internally to track attached databases.
    ++** and 125.  The upper bound of 125 is because the attached databases are
    ++** counted using a signed 8-bit integer which has a maximum value of 127
    ++** and we have to allow 2 extra counts for the "main" and "temp" databases.
    + */
    + #ifndef SQLITE_MAX_ATTACHED
    + # define SQLITE_MAX_ATTACHED 10
    +@@ -8827,7 +12023,7 @@ struct fts5_api {
    + ** The default size of a database page.
    + */
    + #ifndef SQLITE_DEFAULT_PAGE_SIZE
    +-# define SQLITE_DEFAULT_PAGE_SIZE 1024
    ++# define SQLITE_DEFAULT_PAGE_SIZE 4096
    + #endif
    + #if SQLITE_DEFAULT_PAGE_SIZE>SQLITE_MAX_PAGE_SIZE
    + # undef SQLITE_DEFAULT_PAGE_SIZE
    +@@ -8908,7 +12104,7 @@ struct fts5_api {
    + ** to the next, so we have developed the following set of #if statements
    + ** to generate appropriate macros for a wide range of compilers.
    + **
    +-** The correct "ANSI" way to do this is to use the intptr_t type. 
    ++** The correct "ANSI" way to do this is to use the intptr_t type.
    + ** Unfortunately, that typedef is not available on all compilers, or
    + ** if it is available, it requires an #include of specific headers
    + ** that vary from one machine to the next.
    +@@ -8950,11 +12146,12 @@ struct fts5_api {
    + ** the SQLITE_DISABLE_INTRINSIC define.
    + */
    + #if !defined(SQLITE_DISABLE_INTRINSIC)
    +-#  if defined(_MSC_VER) && _MSC_VER>=1300
    ++#  if defined(_MSC_VER) && _MSC_VER>=1400
    + #    if !defined(_WIN32_WCE)
    + #      include <intrin.h>
    + #      pragma intrinsic(_byteswap_ushort)
    + #      pragma intrinsic(_byteswap_ulong)
    ++#      pragma intrinsic(_byteswap_uint64)
    + #      pragma intrinsic(_ReadWriteBarrier)
    + #    else
    + #      include <cmnintrin.h>
    +@@ -8972,6 +12169,11 @@ struct fts5_api {
    + **
    + ** Older versions of SQLite used an optional THREADSAFE macro.
    + ** We support that for legacy.
    ++**
    ++** To ensure that the correct value of "THREADSAFE" is reported when querying
    ++** for compile-time options at runtime (e.g. "PRAGMA compile_options"), this
    ++** logic is partially replicated in ctime.c. If it is updated here, it should
    ++** also be updated there.
    + */
    + #if !defined(SQLITE_THREADSAFE)
    + # if defined(THREADSAFE)
    +@@ -9060,7 +12262,7 @@ struct fts5_api {
    + ** is set.  Thus NDEBUG becomes an opt-in rather than an opt-out
    + ** feature.
    + */
    +-#if !defined(NDEBUG) && !defined(SQLITE_DEBUG) 
    ++#if !defined(NDEBUG) && !defined(SQLITE_DEBUG)
    + # define NDEBUG 1
    + #endif
    + #if defined(NDEBUG) && defined(SQLITE_DEBUG)
    +@@ -9075,7 +12277,7 @@ struct fts5_api {
    + #endif
    + 
    + /*
    +-** The testcase() macro is used to aid in coverage testing.  When 
    ++** The testcase() macro is used to aid in coverage testing.  When
    + ** doing coverage testing, the condition inside the argument to
    + ** testcase() must be evaluated both true and false in order to
    + ** get full branch coverage.  The testcase() macro is inserted
    +@@ -9121,7 +12323,7 @@ SQLITE_PRIVATE   void sqlite3Coverage(int);
    + #endif
    + 
    + /*
    +-** The ALWAYS and NEVER macros surround boolean expressions which 
    ++** The ALWAYS and NEVER macros surround boolean expressions which
    + ** are intended to always be true or false, respectively.  Such
    + ** expressions could be omitted from the code completely.  But they
    + ** are included in a few cases in order to enhance the resilience
    +@@ -9135,7 +12337,7 @@ SQLITE_PRIVATE   void sqlite3Coverage(int);
    + ** be true and false so that the unreachable code they specify will
    + ** not be counted as untested code.
    + */
    +-#if defined(SQLITE_COVERAGE_TEST)
    ++#if defined(SQLITE_COVERAGE_TEST) || defined(SQLITE_MUTATION_TEST)
    + # define ALWAYS(X)      (1)
    + # define NEVER(X)       (0)
    + #elif !defined(NDEBUG)
    +@@ -9146,6 +12348,36 @@ SQLITE_PRIVATE   void sqlite3Coverage(int);
    + # define NEVER(X)       (X)
    + #endif
    + 
    ++/*
    ++** Some conditionals are optimizations only.  In other words, if the
    ++** conditionals are replaced with a constant 1 (true) or 0 (false) then
    ++** the correct answer is still obtained, though perhaps not as quickly.
    ++**
    ++** The following macros mark these optimizations conditionals.
    ++*/
    ++#if defined(SQLITE_MUTATION_TEST)
    ++# define OK_IF_ALWAYS_TRUE(X)  (1)
    ++# define OK_IF_ALWAYS_FALSE(X) (0)
    ++#else
    ++# define OK_IF_ALWAYS_TRUE(X)  (X)
    ++# define OK_IF_ALWAYS_FALSE(X) (X)
    ++#endif
    ++
    ++/*
    ++** Some malloc failures are only possible if SQLITE_TEST_REALLOC_STRESS is
    ++** defined.  We need to defend against those failures when testing with
    ++** SQLITE_TEST_REALLOC_STRESS, but we don't want the unreachable branches
    ++** during a normal build.  The following macro can be used to disable tests
    ++** that are always false except when SQLITE_TEST_REALLOC_STRESS is set.
    ++*/
    ++#if defined(SQLITE_TEST_REALLOC_STRESS)
    ++# define ONLY_IF_REALLOC_STRESS(X)  (X)
    ++#elif !defined(NDEBUG)
    ++# define ONLY_IF_REALLOC_STRESS(X)  ((X)?(assert(0),1):0)
    ++#else
    ++# define ONLY_IF_REALLOC_STRESS(X)  (0)
    ++#endif
    ++
    + /*
    + ** Declarations used for tracing the operating system interfaces.
    + */
    +@@ -9172,6 +12404,13 @@ SQLITE_PRIVATE   void sqlite3Coverage(int);
    + # undef  SQLITE_NEED_ERR_NAME
    + #endif
    + 
    ++/*
    ++** SQLITE_ENABLE_EXPLAIN_COMMENTS is incompatible with SQLITE_OMIT_EXPLAIN
    ++*/
    ++#ifdef SQLITE_OMIT_EXPLAIN
    ++# undef SQLITE_ENABLE_EXPLAIN_COMMENTS
    ++#endif
    ++
    + /*
    + ** Return true (non-zero) if the input is an integer that is too large
    + ** to fit in 32-bits.  This macro is used inside of various testcase()
    +@@ -9205,8 +12444,8 @@ SQLITE_PRIVATE   void sqlite3Coverage(int);
    + ** This is the header file for the generic hash-table implementation
    + ** used in SQLite.
    + */
    +-#ifndef _SQLITE_HASH_H_
    +-#define _SQLITE_HASH_H_
    ++#ifndef SQLITE_HASH_H
    ++#define SQLITE_HASH_H
    + 
    + /* Forward declarations of structures. */
    + typedef struct Hash Hash;
    +@@ -9286,7 +12525,7 @@ SQLITE_PRIVATE void sqlite3HashClear(Hash*);
    + */
    + /* #define sqliteHashCount(H)  ((H)->count) // NOT USED */
    + 
    +-#endif /* _SQLITE_HASH_H_ */
    ++#endif /* SQLITE_HASH_H */
    + 
    + /************** End of hash.h ************************************************/
    + /************** Continuing where we left off in sqliteInt.h ******************/
    +@@ -9318,76 +12557,76 @@ SQLITE_PRIVATE void sqlite3HashClear(Hash*);
    + #define TK_AS                              24
    + #define TK_WITHOUT                         25
    + #define TK_COMMA                           26
    +-#define TK_ID                              27
    +-#define TK_INDEXED                         28
    +-#define TK_ABORT                           29
    +-#define TK_ACTION                          30
    +-#define TK_AFTER                           31
    +-#define TK_ANALYZE                         32
    +-#define TK_ASC                             33
    +-#define TK_ATTACH                          34
    +-#define TK_BEFORE                          35
    +-#define TK_BY                              36
    +-#define TK_CASCADE                         37
    +-#define TK_CAST                            38
    +-#define TK_COLUMNKW                        39
    +-#define TK_CONFLICT                        40
    +-#define TK_DATABASE                        41
    +-#define TK_DESC                            42
    +-#define TK_DETACH                          43
    +-#define TK_EACH                            44
    +-#define TK_FAIL                            45
    +-#define TK_FOR                             46
    +-#define TK_IGNORE                          47
    +-#define TK_INITIALLY                       48
    +-#define TK_INSTEAD                         49
    +-#define TK_LIKE_KW                         50
    +-#define TK_MATCH                           51
    +-#define TK_NO                              52
    +-#define TK_KEY                             53
    +-#define TK_OF                              54
    +-#define TK_OFFSET                          55
    +-#define TK_PRAGMA                          56
    +-#define TK_RAISE                           57
    +-#define TK_RECURSIVE                       58
    +-#define TK_REPLACE                         59
    +-#define TK_RESTRICT                        60
    +-#define TK_ROW                             61
    +-#define TK_TRIGGER                         62
    +-#define TK_VACUUM                          63
    +-#define TK_VIEW                            64
    +-#define TK_VIRTUAL                         65
    +-#define TK_WITH                            66
    +-#define TK_REINDEX                         67
    +-#define TK_RENAME                          68
    +-#define TK_CTIME_KW                        69
    +-#define TK_ANY                             70
    +-#define TK_OR                              71
    +-#define TK_AND                             72
    +-#define TK_IS                              73
    +-#define TK_BETWEEN                         74
    +-#define TK_IN                              75
    +-#define TK_ISNULL                          76
    +-#define TK_NOTNULL                         77
    +-#define TK_NE                              78
    +-#define TK_EQ                              79
    +-#define TK_GT                              80
    +-#define TK_LE                              81
    +-#define TK_LT                              82
    +-#define TK_GE                              83
    +-#define TK_ESCAPE                          84
    +-#define TK_BITAND                          85
    +-#define TK_BITOR                           86
    +-#define TK_LSHIFT                          87
    +-#define TK_RSHIFT                          88
    +-#define TK_PLUS                            89
    +-#define TK_MINUS                           90
    +-#define TK_STAR                            91
    +-#define TK_SLASH                           92
    +-#define TK_REM                             93
    +-#define TK_CONCAT                          94
    +-#define TK_COLLATE                         95
    +-#define TK_BITNOT                          96
    ++#define TK_ABORT                           27
    ++#define TK_ACTION                          28
    ++#define TK_AFTER                           29
    ++#define TK_ANALYZE                         30
    ++#define TK_ASC                             31
    ++#define TK_ATTACH                          32
    ++#define TK_BEFORE                          33
    ++#define TK_BY                              34
    ++#define TK_CASCADE                         35
    ++#define TK_CAST                            36
    ++#define TK_CONFLICT                        37
    ++#define TK_DATABASE                        38
    ++#define TK_DESC                            39
    ++#define TK_DETACH                          40
    ++#define TK_EACH                            41
    ++#define TK_FAIL                            42
    ++#define TK_OR                              43
    ++#define TK_AND                             44
    ++#define TK_IS                              45
    ++#define TK_MATCH                           46
    ++#define TK_LIKE_KW                         47
    ++#define TK_BETWEEN                         48
    ++#define TK_IN                              49
    ++#define TK_ISNULL                          50
    ++#define TK_NOTNULL                         51
    ++#define TK_NE                              52
    ++#define TK_EQ                              53
    ++#define TK_GT                              54
    ++#define TK_LE                              55
    ++#define TK_LT                              56
    ++#define TK_GE                              57
    ++#define TK_ESCAPE                          58
    ++#define TK_ID                              59
    ++#define TK_COLUMNKW                        60
    ++#define TK_FOR                             61
    ++#define TK_IGNORE                          62
    ++#define TK_INITIALLY                       63
    ++#define TK_INSTEAD                         64
    ++#define TK_NO                              65
    ++#define TK_KEY                             66
    ++#define TK_OF                              67
    ++#define TK_OFFSET                          68
    ++#define TK_PRAGMA                          69
    ++#define TK_RAISE                           70
    ++#define TK_RECURSIVE                       71
    ++#define TK_REPLACE                         72
    ++#define TK_RESTRICT                        73
    ++#define TK_ROW                             74
    ++#define TK_TRIGGER                         75
    ++#define TK_VACUUM                          76
    ++#define TK_VIEW                            77
    ++#define TK_VIRTUAL                         78
    ++#define TK_WITH                            79
    ++#define TK_REINDEX                         80
    ++#define TK_RENAME                          81
    ++#define TK_CTIME_KW                        82
    ++#define TK_ANY                             83
    ++#define TK_BITAND                          84
    ++#define TK_BITOR                           85
    ++#define TK_LSHIFT                          86
    ++#define TK_RSHIFT                          87
    ++#define TK_PLUS                            88
    ++#define TK_MINUS                           89
    ++#define TK_STAR                            90
    ++#define TK_SLASH                           91
    ++#define TK_REM                             92
    ++#define TK_CONCAT                          93
    ++#define TK_COLLATE                         94
    ++#define TK_BITNOT                          95
    ++#define TK_INDEXED                         96
    + #define TK_STRING                          97
    + #define TK_JOIN_KW                         98
    + #define TK_CONSTRAINT                      99
    +@@ -9423,9 +12662,9 @@ SQLITE_PRIVATE void sqlite3HashClear(Hash*);
    + #define TK_LIMIT                          129
    + #define TK_WHERE                          130
    + #define TK_INTO                           131
    +-#define TK_INTEGER                        132
    +-#define TK_FLOAT                          133
    +-#define TK_BLOB                           134
    ++#define TK_FLOAT                          132
    ++#define TK_BLOB                           133
    ++#define TK_INTEGER                        134
    + #define TK_VARIABLE                       135
    + #define TK_CASE                           136
    + #define TK_WHEN                           137
    +@@ -9434,23 +12673,30 @@ SQLITE_PRIVATE void sqlite3HashClear(Hash*);
    + #define TK_INDEX                          140
    + #define TK_ALTER                          141
    + #define TK_ADD                            142
    +-#define TK_TO_TEXT                        143
    +-#define TK_TO_BLOB                        144
    +-#define TK_TO_NUMERIC                     145
    +-#define TK_TO_INT                         146
    +-#define TK_TO_REAL                        147
    +-#define TK_ISNOT                          148
    +-#define TK_END_OF_FILE                    149
    +-#define TK_ILLEGAL                        150
    +-#define TK_SPACE                          151
    +-#define TK_UNCLOSED_STRING                152
    +-#define TK_FUNCTION                       153
    +-#define TK_COLUMN                         154
    +-#define TK_AGG_FUNCTION                   155
    +-#define TK_AGG_COLUMN                     156
    +-#define TK_UMINUS                         157
    +-#define TK_UPLUS                          158
    +-#define TK_REGISTER                       159
    ++#define TK_ISNOT                          143
    ++#define TK_FUNCTION                       144
    ++#define TK_COLUMN                         145
    ++#define TK_AGG_FUNCTION                   146
    ++#define TK_AGG_COLUMN                     147
    ++#define TK_UMINUS                         148
    ++#define TK_UPLUS                          149
    ++#define TK_REGISTER                       150
    ++#define TK_VECTOR                         151
    ++#define TK_SELECT_COLUMN                  152
    ++#define TK_IF_NULL_ROW                    153
    ++#define TK_ASTERISK                       154
    ++#define TK_SPAN                           155
    ++#define TK_END_OF_FILE                    156
    ++#define TK_UNCLOSED_STRING                157
    ++#define TK_SPACE                          158
    ++#define TK_ILLEGAL                        159
    ++
    ++/* The token codes above must all fit in 8 bits */
    ++#define TKFLG_MASK           0xff  
    ++
    ++/* Flags that can be added to a token code when it is not
    ++** being stored in a u8: */
    ++#define TKFLG_DONTFOLD       0x100  /* Omit constant folding optimizations */
    + 
    + /************** End of parse.h ***********************************************/
    + /************** Continuing where we left off in sqliteInt.h ******************/
    +@@ -9460,6 +12706,18 @@ SQLITE_PRIVATE void sqlite3HashClear(Hash*);
    + #include <assert.h>
    + #include <stddef.h>
    + 
    ++/*
    ++** Use a macro to replace memcpy() if compiled with SQLITE_INLINE_MEMCPY.
    ++** This allows better measurements of where memcpy() is used when running
    ++** cachegrind.  But this macro version of memcpy() is very slow so it
    ++** should not be used in production.  This is a performance measurement
    ++** hack only.
    ++*/
    ++#ifdef SQLITE_INLINE_MEMCPY
    ++# define memcpy(D,S,N) {char*xxd=(char*)(D);const char*xxs=(const char*)(S);\
    ++                        int xxn=(N);while(xxn-->0)*(xxd++)=*(xxs++);}
    ++#endif
    ++
    + /*
    + ** If compiling for a processor that lacks floating point support,
    + ** substitute integer for floating-point
    +@@ -9482,7 +12740,7 @@ SQLITE_PRIVATE void sqlite3HashClear(Hash*);
    + 
    + /*
    + ** OMIT_TEMPDB is set to 1 if SQLITE_OMIT_TEMPDB is defined, or 0
    +-** afterward. Having this macro allows us to cause the C compiler 
    ++** afterward. Having this macro allows us to cause the C compiler
    + ** to omit code used by TEMP tables without messy #ifndef statements.
    + */
    + #ifdef SQLITE_OMIT_TEMPDB
    +@@ -9516,12 +12774,11 @@ SQLITE_PRIVATE void sqlite3HashClear(Hash*);
    + */
    + #ifndef SQLITE_TEMP_STORE
    + # define SQLITE_TEMP_STORE 1
    +-# define SQLITE_TEMP_STORE_xc 1  /* Exclude from ctime.c */
    + #endif
    + 
    + /*
    + ** If no value has been provided for SQLITE_MAX_WORKER_THREADS, or if
    +-** SQLITE_TEMP_STORE is set to 3 (never use temporary files), set it 
    ++** SQLITE_TEMP_STORE is set to 3 (never use temporary files), set it
    + ** to zero.
    + */
    + #if SQLITE_TEMP_STORE==3 || SQLITE_THREADSAFE==0
    +@@ -9544,11 +12801,22 @@ SQLITE_PRIVATE void sqlite3HashClear(Hash*);
    + ** pagecaches for each database connection.  A positive number is the
    + ** number of pages.  A negative number N translations means that a buffer
    + ** of -1024*N bytes is allocated and used for as many pages as it will hold.
    ++**
    ++** The default value of "20" was choosen to minimize the run-time of the
    ++** speedtest1 test program with options: --shrink-memory --reprepare
    + */
    + #ifndef SQLITE_DEFAULT_PCACHE_INITSZ
    +-# define SQLITE_DEFAULT_PCACHE_INITSZ 100
    ++# define SQLITE_DEFAULT_PCACHE_INITSZ 20
    + #endif
    + 
    ++/*
    ++** The compile-time options SQLITE_MMAP_READWRITE and 
    ++** SQLITE_ENABLE_BATCH_ATOMIC_WRITE are not compatible with one another.
    ++** You must choose one or the other (or neither) but not both.
    ++*/
    ++#if defined(SQLITE_MMAP_READWRITE) && defined(SQLITE_ENABLE_BATCH_ATOMIC_WRITE)
    ++#error Cannot use both SQLITE_MMAP_READWRITE and SQLITE_ENABLE_BATCH_ATOMIC_WRITE
    ++#endif
    + 
    + /*
    + ** GCC does not define the offsetof() macro so we'll have to do it
    +@@ -9561,8 +12829,12 @@ SQLITE_PRIVATE void sqlite3HashClear(Hash*);
    + /*
    + ** Macros to compute minimum and maximum of two numbers.
    + */
    +-#define MIN(A,B) ((A)<(B)?(A):(B))
    +-#define MAX(A,B) ((A)>(B)?(A):(B))
    ++#ifndef MIN
    ++# define MIN(A,B) ((A)<(B)?(A):(B))
    ++#endif
    ++#ifndef MAX
    ++# define MAX(A,B) ((A)>(B)?(A):(B))
    ++#endif
    + 
    + /*
    + ** Swap two objects of type TYPE.
    +@@ -9670,7 +12942,7 @@ typedef INT8_TYPE i8;              /* 1-byte signed integer */
    + **      4 -> 20           1000 -> 99        1048576 -> 200
    + **     10 -> 33           1024 -> 100    4294967296 -> 320
    + **
    +-** The LogEst can be negative to indicate fractional values. 
    ++** The LogEst can be negative to indicate fractional values.
    + ** Examples:
    + **
    + **    0.5 -> -10           0.1 -> -33        0.0625 -> -40
    +@@ -9691,38 +12963,62 @@ typedef INT16_TYPE LogEst;
    + # endif
    + #endif
    + 
    ++/* The uptr type is an unsigned integer large enough to hold a pointer
    ++*/
    ++#if defined(HAVE_STDINT_H)
    ++  typedef uintptr_t uptr;
    ++#elif SQLITE_PTRSIZE==4
    ++  typedef u32 uptr;
    ++#else
    ++  typedef u64 uptr;
    ++#endif
    ++
    ++/*
    ++** The SQLITE_WITHIN(P,S,E) macro checks to see if pointer P points to
    ++** something between S (inclusive) and E (exclusive).
    ++**
    ++** In other words, S is a buffer and E is a pointer to the first byte after
    ++** the end of buffer S.  This macro returns true if P points to something
    ++** contained within the buffer S.
    ++*/
    ++#define SQLITE_WITHIN(P,S,E) (((uptr)(P)>=(uptr)(S))&&((uptr)(P)<(uptr)(E)))
    ++
    ++
    + /*
    + ** Macros to determine whether the machine is big or little endian,
    + ** 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
    ++** -DSQLITE_BYTEORDER=0 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) ||    \
    ++#ifndef SQLITE_BYTEORDER
    ++# 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
    ++     defined(__arm__)
    ++#   define SQLITE_BYTEORDER    1234
    ++# elif defined(sparc)    || defined(__ppc__)
    ++#   define SQLITE_BYTEORDER    4321
    ++# else
    ++#   define SQLITE_BYTEORDER 0
    ++# endif
    + #endif
    +-#if (defined(sparc)    || defined(__ppc__))  \
    +-    && !defined(SQLITE_RUNTIME_BYTEORDER)
    +-# define SQLITE_BYTEORDER    4321
    ++#if 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" */
    ++#elif SQLITE_BYTEORDER==1234
    ++# define SQLITE_BIGENDIAN    0
    ++# define SQLITE_LITTLEENDIAN 1
    ++# define SQLITE_UTF16NATIVE  SQLITE_UTF16LE
    ++#else
    ++# ifdef SQLITE_AMALGAMATION
    ++  const int sqlite3one = 1;
    ++# else
    ++  extern const int sqlite3one;
    ++# endif
    + # define SQLITE_BIGENDIAN    (*(char *)(&sqlite3one)==0)
    + # define SQLITE_LITTLEENDIAN (*(char *)(&sqlite3one)==1)
    + # define SQLITE_UTF16NATIVE  (SQLITE_BIGENDIAN?SQLITE_UTF16BE:SQLITE_UTF16LE)
    +@@ -9736,7 +13032,7 @@ SQLITE_PRIVATE const int sqlite3one;
    + #define LARGEST_INT64  (0xffffffff|(((i64)0x7fffffff)<<32))
    + #define SMALLEST_INT64 (((i64)-1) - LARGEST_INT64)
    + 
    +-/* 
    ++/*
    + ** Round up a number to the next larger multiple of 8.  This is used
    + ** to force 8-byte alignment on 64-bit architectures.
    + */
    +@@ -9775,10 +13071,6 @@ SQLITE_PRIVATE const int sqlite3one;
    + */
    + #ifdef __APPLE__
    + # include <TargetConditionals.h>
    +-# if TARGET_OS_IPHONE
    +-#   undef SQLITE_MAX_MMAP_SIZE
    +-#   define SQLITE_MAX_MMAP_SIZE 0
    +-# endif
    + #endif
    + #ifndef SQLITE_MAX_MMAP_SIZE
    + # if defined(__linux__) \
    +@@ -9791,7 +13083,6 @@ SQLITE_PRIVATE const int sqlite3one;
    + # else
    + #   define SQLITE_MAX_MMAP_SIZE 0
    + # endif
    +-# define SQLITE_MAX_MMAP_SIZE_xc 1 /* exclude from ctime.c */
    + #endif
    + 
    + /*
    +@@ -9801,7 +13092,6 @@ SQLITE_PRIVATE const int sqlite3one;
    + */
    + #ifndef SQLITE_DEFAULT_MMAP_SIZE
    + # define SQLITE_DEFAULT_MMAP_SIZE 0
    +-# define SQLITE_DEFAULT_MMAP_SIZE_xc 1  /* Exclude from ctime.c */
    + #endif
    + #if SQLITE_DEFAULT_MMAP_SIZE>SQLITE_MAX_MMAP_SIZE
    + # undef SQLITE_DEFAULT_MMAP_SIZE
    +@@ -9826,7 +13116,7 @@ SQLITE_PRIVATE const int sqlite3one;
    + ** SELECTTRACE_ENABLED will be either 1 or 0 depending on whether or not
    + ** the Select query generator tracing logic is turned on.
    + */
    +-#if defined(SQLITE_DEBUG) || defined(SQLITE_ENABLE_SELECTTRACE)
    ++#if defined(SQLITE_ENABLE_SELECTTRACE)
    + # define SELECTTRACE_ENABLED 1
    + #else
    + # define SELECTTRACE_ENABLED 0
    +@@ -9834,7 +13124,7 @@ SQLITE_PRIVATE const int sqlite3one;
    + 
    + /*
    + ** An instance of the following structure is used to store the busy-handler
    +-** callback for a given sqlite handle. 
    ++** callback for a given sqlite handle.
    + **
    + ** The sqlite.busyHandler member of the sqlite struct contains the busy
    + ** callback for the database handle. Each pager opened via the sqlite
    +@@ -9879,9 +13169,9 @@ struct BusyHandler {
    + 
    + /*
    + ** The following value as a destructor means to use sqlite3DbFree().
    +-** The sqlite3DbFree() routine requires two parameters instead of the 
    +-** one parameter that destructors normally want.  So we have to introduce 
    +-** this magic value that the code knows to handle differently.  Any 
    ++** The sqlite3DbFree() routine requires two parameters instead of the
    ++** one parameter that destructors normally want.  So we have to introduce
    ++** this magic value that the code knows to handle differently.  Any
    + ** pointer will work here as long as it is distinct from SQLITE_STATIC
    + ** and SQLITE_TRANSIENT.
    + */
    +@@ -9905,19 +13195,19 @@ struct BusyHandler {
    +   #define SQLITE_WSD const
    +   #define GLOBAL(t,v) (*(t*)sqlite3_wsd_find((void*)&(v), sizeof(v)))
    +   #define sqlite3GlobalConfig GLOBAL(struct Sqlite3Config, sqlite3Config)
    +-SQLITE_API int SQLITE_STDCALL sqlite3_wsd_init(int N, int J);
    +-SQLITE_API void *SQLITE_STDCALL sqlite3_wsd_find(void *K, int L);
    ++SQLITE_API int sqlite3_wsd_init(int N, int J);
    ++SQLITE_API void *sqlite3_wsd_find(void *K, int L);
    + #else
    +-  #define SQLITE_WSD 
    ++  #define SQLITE_WSD
    +   #define GLOBAL(t,v) v
    +   #define sqlite3GlobalConfig sqlite3Config
    + #endif
    + 
    + /*
    + ** The following macros are used to suppress compiler warnings and to
    +-** make it clear to human readers when a function parameter is deliberately 
    ++** make it clear to human readers when a function parameter is deliberately
    + ** left unused within the body of a function. This usually happens when
    +-** a function is called via a function pointer. For example the 
    ++** a function is called via a function pointer. For example the
    + ** implementation of an SQL aggregate step callback may not use the
    + ** parameter indicating the number of arguments passed to the aggregate,
    + ** if it knows that this is enforced elsewhere.
    +@@ -9945,7 +13235,6 @@ typedef struct Db Db;
    + typedef struct Schema Schema;
    + typedef struct Expr Expr;
    + typedef struct ExprList ExprList;
    +-typedef struct ExprSpan ExprSpan;
    + typedef struct FKey FKey;
    + typedef struct FuncDestructor FuncDestructor;
    + typedef struct FuncDef FuncDef;
    +@@ -9960,6 +13249,7 @@ typedef struct LookasideSlot LookasideSlot;
    + typedef struct Module Module;
    + typedef struct NameContext NameContext;
    + typedef struct Parse Parse;
    ++typedef struct PreUpdate PreUpdate;
    + typedef struct PrintfArguments PrintfArguments;
    + typedef struct RowSet RowSet;
    + typedef struct Savepoint Savepoint;
    +@@ -9982,8 +13272,16 @@ typedef struct Walker Walker;
    + typedef struct WhereInfo WhereInfo;
    + typedef struct With With;
    + 
    ++/* A VList object records a mapping between parameters/variables/wildcards
    ++** in the SQL statement (such as $abc, @pqr, or :xyz) and the integer
    ++** variable number associated with that parameter.  See the format description
    ++** on the sqlite3VListAdd() routine for more information.  A VList is really
    ++** just an array of integers.
    ++*/
    ++typedef int VList;
    ++
    + /*
    +-** Defer sourcing vdbe.h and btree.h until after the "u8" and 
    ++** Defer sourcing vdbe.h and btree.h until after the "u8" and
    + ** "BusyHandler" typedefs. vdbe.h also requires a few of the opaque
    + ** pointer types (i.e. FuncDef) defined above.
    + */
    +@@ -10004,8 +13302,8 @@ typedef struct With With;
    + ** subsystem.  See comments in the source code for a detailed description
    + ** of what each interface routine does.
    + */
    +-#ifndef _BTREE_H_
    +-#define _BTREE_H_
    ++#ifndef SQLITE_BTREE_H
    ++#define SQLITE_BTREE_H
    + 
    + /* TODO: This definition is just included so other modules compile. It
    + ** needs to be revisited.
    +@@ -10030,6 +13328,7 @@ typedef struct With With;
    + typedef struct Btree Btree;
    + typedef struct BtCursor BtCursor;
    + typedef struct BtShared BtShared;
    ++typedef struct BtreePayload BtreePayload;
    + 
    + 
    + SQLITE_PRIVATE int sqlite3BtreeOpen(
    +@@ -10054,11 +13353,11 @@ SQLITE_PRIVATE int sqlite3BtreeOpen(
    + 
    + SQLITE_PRIVATE int sqlite3BtreeClose(Btree*);
    + SQLITE_PRIVATE int sqlite3BtreeSetCacheSize(Btree*,int);
    ++SQLITE_PRIVATE int sqlite3BtreeSetSpillSize(Btree*,int);
    + #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);
    + SQLITE_PRIVATE int sqlite3BtreeGetPageSize(Btree*);
    + SQLITE_PRIVATE int sqlite3BtreeMaxPageCount(Btree*,int);
    +@@ -10080,7 +13379,9 @@ SQLITE_PRIVATE int sqlite3BtreeIsInReadTrans(Btree*);
    + SQLITE_PRIVATE int sqlite3BtreeIsInBackup(Btree*);
    + SQLITE_PRIVATE void *sqlite3BtreeSchema(Btree *, int, void(*)(void *));
    + SQLITE_PRIVATE int sqlite3BtreeSchemaLocked(Btree *pBtree);
    ++#ifndef SQLITE_OMIT_SHARED_CACHE
    + SQLITE_PRIVATE int sqlite3BtreeLockTable(Btree *pBtree, int iTab, u8 isWriteLock);
    ++#endif
    + SQLITE_PRIVATE int sqlite3BtreeSavepoint(Btree *, int, int);
    + 
    + SQLITE_PRIVATE const char *sqlite3BtreeGetFilename(Btree *);
    +@@ -10141,8 +13442,37 @@ SQLITE_PRIVATE int sqlite3BtreeNewDb(Btree *p);
    + #define BTREE_DATA_VERSION        15  /* A virtual meta-value */
    + 
    + /*
    +-** Values that may be OR'd together to form the second argument of an
    +-** sqlite3BtreeCursorHints() call.
    ++** Kinds of hints that can be passed into the sqlite3BtreeCursorHint()
    ++** interface.
    ++**
    ++** BTREE_HINT_RANGE  (arguments: Expr*, Mem*)
    ++**
    ++**     The first argument is an Expr* (which is guaranteed to be constant for
    ++**     the lifetime of the cursor) that defines constraints on which rows
    ++**     might be fetched with this cursor.  The Expr* tree may contain
    ++**     TK_REGISTER nodes that refer to values stored in the array of registers
    ++**     passed as the second parameter.  In other words, if Expr.op==TK_REGISTER
    ++**     then the value of the node is the value in Mem[pExpr.iTable].  Any
    ++**     TK_COLUMN node in the expression tree refers to the Expr.iColumn-th
    ++**     column of the b-tree of the cursor.  The Expr tree will not contain
    ++**     any function calls nor subqueries nor references to b-trees other than
    ++**     the cursor being hinted.
    ++**
    ++**     The design of the _RANGE hint is aid b-tree implementations that try
    ++**     to prefetch content from remote machines - to provide those
    ++**     implementations with limits on what needs to be prefetched and thereby
    ++**     reduce network bandwidth.
    ++**
    ++** Note that BTREE_HINT_FLAGS with BTREE_BULKLOAD is the only hint used by
    ++** standard SQLite.  The other hints are provided for extentions that use
    ++** the SQLite parser and code generator but substitute their own storage
    ++** engine.
    ++*/
    ++#define BTREE_HINT_RANGE 0       /* Range constraints on queries */
    ++
    ++/*
    ++** Values that may be OR'd together to form the argument to the
    ++** BTREE_HINT_FLAGS hint for sqlite3BtreeCursorHint():
    + **
    + ** The BTREE_BULKLOAD flag is set on index cursors when the index is going
    + ** to be filled with content that is already in sorted order.
    +@@ -10156,6 +13486,32 @@ SQLITE_PRIVATE int sqlite3BtreeNewDb(Btree *p);
    + #define BTREE_BULKLOAD 0x00000001  /* Used to full index in sorted order */
    + #define BTREE_SEEK_EQ  0x00000002  /* EQ seeks only - no range seeks */
    + 
    ++/* 
    ++** Flags passed as the third argument to sqlite3BtreeCursor().
    ++**
    ++** For read-only cursors the wrFlag argument is always zero. For read-write
    ++** cursors it may be set to either (BTREE_WRCSR|BTREE_FORDELETE) or just
    ++** (BTREE_WRCSR). If the BTREE_FORDELETE bit is set, then the cursor will
    ++** only be used by SQLite for the following:
    ++**
    ++**   * to seek to and then delete specific entries, and/or
    ++**
    ++**   * to read values that will be used to create keys that other
    ++**     BTREE_FORDELETE cursors will seek to and delete.
    ++**
    ++** The BTREE_FORDELETE flag is an optimization hint.  It is not used by
    ++** by this, the native b-tree engine of SQLite, but it is available to
    ++** alternative storage engines that might be substituted in place of this
    ++** b-tree system.  For alternative storage engines in which a delete of
    ++** the main table row automatically deletes corresponding index rows,
    ++** the FORDELETE flag hint allows those alternative storage engines to
    ++** skip a lot of work.  Namely:  FORDELETE cursors may treat all SEEK
    ++** and DELETE operations as no-ops, and any READ operation against a
    ++** FORDELETE cursor may return a null row: 0x01 0x00.
    ++*/
    ++#define BTREE_WRCSR     0x00000004     /* read-write cursor */
    ++#define BTREE_FORDELETE 0x00000008     /* Cursor is for seek/delete only */
    ++
    + SQLITE_PRIVATE int sqlite3BtreeCursor(
    +   Btree*,                              /* BTree containing table to open */
    +   int iTable,                          /* Index of root page */
    +@@ -10163,8 +13519,13 @@ SQLITE_PRIVATE int sqlite3BtreeCursor(
    +   struct KeyInfo*,                     /* First argument to compare function */
    +   BtCursor *pCursor                    /* Space to write cursor structure */
    + );
    ++SQLITE_PRIVATE BtCursor *sqlite3BtreeFakeValidCursor(void);
    + SQLITE_PRIVATE int sqlite3BtreeCursorSize(void);
    + SQLITE_PRIVATE void sqlite3BtreeCursorZero(BtCursor*);
    ++SQLITE_PRIVATE void sqlite3BtreeCursorHintFlags(BtCursor*, unsigned);
    ++#ifdef SQLITE_ENABLE_CURSOR_HINTS
    ++SQLITE_PRIVATE void sqlite3BtreeCursorHint(BtCursor*, int, ...);
    ++#endif
    + 
    + SQLITE_PRIVATE int sqlite3BtreeCloseCursor(BtCursor*);
    + SQLITE_PRIVATE int sqlite3BtreeMovetoUnpacked(
    +@@ -10176,39 +13537,75 @@ SQLITE_PRIVATE int sqlite3BtreeMovetoUnpacked(
    + );
    + SQLITE_PRIVATE int sqlite3BtreeCursorHasMoved(BtCursor*);
    + SQLITE_PRIVATE int sqlite3BtreeCursorRestore(BtCursor*, int*);
    +-SQLITE_PRIVATE int sqlite3BtreeDelete(BtCursor*, int);
    +-SQLITE_PRIVATE int sqlite3BtreeInsert(BtCursor*, const void *pKey, i64 nKey,
    +-                                  const void *pData, int nData,
    +-                                  int nZero, int bias, int seekResult);
    ++SQLITE_PRIVATE int sqlite3BtreeDelete(BtCursor*, u8 flags);
    ++
    ++/* Allowed flags for sqlite3BtreeDelete() and sqlite3BtreeInsert() */
    ++#define BTREE_SAVEPOSITION 0x02  /* Leave cursor pointing at NEXT or PREV */
    ++#define BTREE_AUXDELETE    0x04  /* not the primary delete operation */
    ++#define BTREE_APPEND       0x08  /* Insert is likely an append */
    ++
    ++/* An instance of the BtreePayload object describes the content of a single
    ++** entry in either an index or table btree.
    ++**
    ++** Index btrees (used for indexes and also WITHOUT ROWID tables) contain
    ++** an arbitrary key and no data.  These btrees have pKey,nKey set to their
    ++** key and pData,nData,nZero set to zero.
    ++**
    ++** Table btrees (used for rowid tables) contain an integer rowid used as
    ++** the key and passed in the nKey field.  The pKey field is zero.  
    ++** pData,nData hold the content of the new entry.  nZero extra zero bytes
    ++** are appended to the end of the content when constructing the entry.
    ++**
    ++** This object is used to pass information into sqlite3BtreeInsert().  The
    ++** same information used to be passed as five separate parameters.  But placing
    ++** the information into this object helps to keep the interface more 
    ++** organized and understandable, and it also helps the resulting code to
    ++** run a little faster by using fewer registers for parameter passing.
    ++*/
    ++struct BtreePayload {
    ++  const void *pKey;       /* Key content for indexes.  NULL for tables */
    ++  sqlite3_int64 nKey;     /* Size of pKey for indexes.  PRIMARY KEY for tabs */
    ++  const void *pData;      /* Data for tables.  NULL for indexes */
    ++  sqlite3_value *aMem;    /* First of nMem value in the unpacked pKey */
    ++  u16 nMem;               /* Number of aMem[] value.  Might be zero */
    ++  int nData;              /* Size of pData.  0 if none. */
    ++  int nZero;              /* Extra zero data appended after pData,nData */
    ++};
    ++
    ++SQLITE_PRIVATE int sqlite3BtreeInsert(BtCursor*, const BtreePayload *pPayload,
    ++                       int flags, int seekResult);
    + SQLITE_PRIVATE int sqlite3BtreeFirst(BtCursor*, int *pRes);
    + SQLITE_PRIVATE int sqlite3BtreeLast(BtCursor*, int *pRes);
    +-SQLITE_PRIVATE int sqlite3BtreeNext(BtCursor*, int *pRes);
    ++SQLITE_PRIVATE int sqlite3BtreeNext(BtCursor*, int flags);
    + SQLITE_PRIVATE int sqlite3BtreeEof(BtCursor*);
    +-SQLITE_PRIVATE int sqlite3BtreePrevious(BtCursor*, int *pRes);
    +-SQLITE_PRIVATE int sqlite3BtreeKeySize(BtCursor*, i64 *pSize);
    +-SQLITE_PRIVATE int sqlite3BtreeKey(BtCursor*, u32 offset, u32 amt, void*);
    +-SQLITE_PRIVATE const void *sqlite3BtreeKeyFetch(BtCursor*, u32 *pAmt);
    +-SQLITE_PRIVATE const void *sqlite3BtreeDataFetch(BtCursor*, u32 *pAmt);
    +-SQLITE_PRIVATE int sqlite3BtreeDataSize(BtCursor*, u32 *pSize);
    +-SQLITE_PRIVATE int sqlite3BtreeData(BtCursor*, u32 offset, u32 amt, void*);
    ++SQLITE_PRIVATE int sqlite3BtreePrevious(BtCursor*, int flags);
    ++SQLITE_PRIVATE i64 sqlite3BtreeIntegerKey(BtCursor*);
    ++#ifdef SQLITE_ENABLE_OFFSET_SQL_FUNC
    ++SQLITE_PRIVATE i64 sqlite3BtreeOffset(BtCursor*);
    ++#endif
    ++SQLITE_PRIVATE int sqlite3BtreePayload(BtCursor*, u32 offset, u32 amt, void*);
    ++SQLITE_PRIVATE const void *sqlite3BtreePayloadFetch(BtCursor*, u32 *pAmt);
    ++SQLITE_PRIVATE u32 sqlite3BtreePayloadSize(BtCursor*);
    + 
    + SQLITE_PRIVATE char *sqlite3BtreeIntegrityCheck(Btree*, int *aRoot, int nRoot, int, int*);
    + SQLITE_PRIVATE struct Pager *sqlite3BtreePager(Btree*);
    ++SQLITE_PRIVATE i64 sqlite3BtreeRowCountEst(BtCursor*);
    + 
    ++#ifndef SQLITE_OMIT_INCRBLOB
    ++SQLITE_PRIVATE int sqlite3BtreePayloadChecked(BtCursor*, u32 offset, u32 amt, void*);
    + SQLITE_PRIVATE int sqlite3BtreePutData(BtCursor*, u32 offset, u32 amt, void*);
    + SQLITE_PRIVATE void sqlite3BtreeIncrblobCursor(BtCursor *);
    ++#endif
    + SQLITE_PRIVATE void sqlite3BtreeClearCursor(BtCursor *);
    + SQLITE_PRIVATE int sqlite3BtreeSetVersion(Btree *pBt, int iVersion);
    +-SQLITE_PRIVATE void sqlite3BtreeCursorHints(BtCursor *, unsigned int mask);
    +-#ifdef SQLITE_DEBUG
    + SQLITE_PRIVATE int sqlite3BtreeCursorHasHint(BtCursor*, unsigned int mask);
    +-#endif
    + SQLITE_PRIVATE int sqlite3BtreeIsReadonly(Btree *pBt);
    + SQLITE_PRIVATE int sqlite3HeaderSizeBtree(void);
    + 
    + #ifndef NDEBUG
    + SQLITE_PRIVATE int sqlite3BtreeCursorIsValid(BtCursor*);
    + #endif
    ++SQLITE_PRIVATE int sqlite3BtreeCursorIsValidNN(BtCursor*);
    + 
    + #ifndef SQLITE_OMIT_BTREECOUNT
    + SQLITE_PRIVATE int sqlite3BtreeCount(BtCursor *, i64 *);
    +@@ -10231,15 +13628,19 @@ SQLITE_PRIVATE   int sqlite3BtreeCheckpoint(Btree*, int, int *, int *);
    + #ifndef SQLITE_OMIT_SHARED_CACHE
    + SQLITE_PRIVATE   void sqlite3BtreeEnter(Btree*);
    + SQLITE_PRIVATE   void sqlite3BtreeEnterAll(sqlite3*);
    ++SQLITE_PRIVATE   int sqlite3BtreeSharable(Btree*);
    ++SQLITE_PRIVATE   void sqlite3BtreeEnterCursor(BtCursor*);
    ++SQLITE_PRIVATE   int sqlite3BtreeConnectionCount(Btree*);
    + #else
    + # define sqlite3BtreeEnter(X) 
    + # define sqlite3BtreeEnterAll(X)
    ++# define sqlite3BtreeSharable(X) 0
    ++# define sqlite3BtreeEnterCursor(X)
    ++# define sqlite3BtreeConnectionCount(X) 1
    + #endif
    + 
    + #if !defined(SQLITE_OMIT_SHARED_CACHE) && SQLITE_THREADSAFE
    +-SQLITE_PRIVATE   int sqlite3BtreeSharable(Btree*);
    + SQLITE_PRIVATE   void sqlite3BtreeLeave(Btree*);
    +-SQLITE_PRIVATE   void sqlite3BtreeEnterCursor(BtCursor*);
    + SQLITE_PRIVATE   void sqlite3BtreeLeaveCursor(BtCursor*);
    + SQLITE_PRIVATE   void sqlite3BtreeLeaveAll(sqlite3*);
    + #ifndef NDEBUG
    +@@ -10250,9 +13651,7 @@ SQLITE_PRIVATE   int sqlite3SchemaMutexHeld(sqlite3*,int,Schema*);
    + #endif
    + #else
    + 
    +-# define sqlite3BtreeSharable(X) 0
    + # define sqlite3BtreeLeave(X)
    +-# define sqlite3BtreeEnterCursor(X)
    + # define sqlite3BtreeLeaveCursor(X)
    + # define sqlite3BtreeLeaveAll(X)
    + 
    +@@ -10262,7 +13661,7 @@ SQLITE_PRIVATE   int sqlite3SchemaMutexHeld(sqlite3*,int,Schema*);
    + #endif
    + 
    + 
    +-#endif /* _BTREE_H_ */
    ++#endif /* SQLITE_BTREE_H */
    + 
    + /************** End of btree.h ***********************************************/
    + /************** Continuing where we left off in sqliteInt.h ******************/
    +@@ -10285,8 +13684,8 @@ SQLITE_PRIVATE   int sqlite3SchemaMutexHeld(sqlite3*,int,Schema*);
    + ** or VDBE.  The VDBE implements an abstract machine that runs a
    + ** simple program to access and modify the underlying database.
    + */
    +-#ifndef _SQLITE_VDBE_H_
    +-#define _SQLITE_VDBE_H_
    ++#ifndef SQLITE_VDBE_H
    ++#define SQLITE_VDBE_H
    + /* #include <stdio.h> */
    + 
    + /*
    +@@ -10300,7 +13699,7 @@ typedef struct Vdbe Vdbe;
    + ** The names of the following types declared in vdbeInt.h are required
    + ** for the VdbeOp definition.
    + */
    +-typedef struct Mem Mem;
    ++typedef struct sqlite3_value Mem;
    + typedef struct SubProgram SubProgram;
    + 
    + /*
    +@@ -10311,8 +13710,7 @@ typedef struct SubProgram SubProgram;
    + struct VdbeOp {
    +   u8 opcode;          /* What operation to perform */
    +   signed char p4type; /* One of the P4_xxx constants for p4 */
    +-  u8 opflags;         /* Mask of the OPFLG_* flags in opcodes.h */
    +-  u8 p5;              /* Fifth parameter is an unsigned character */
    ++  u16 p5;             /* Fifth parameter is an unsigned 16-bit integer */
    +   int p1;             /* First operand */
    +   int p2;             /* Second parameter (often the jump destination) */
    +   int p3;             /* The third parameter */
    +@@ -10330,7 +13728,11 @@ struct VdbeOp {
    +     KeyInfo *pKeyInfo;     /* Used when p4type is P4_KEYINFO */
    +     int *ai;               /* Used when p4type is P4_INTARRAY */
    +     SubProgram *pProgram;  /* Used when p4type is P4_SUBPROGRAM */
    +-    int (*xAdvance)(BtCursor *, int *);
    ++    Table *pTab;           /* Used when p4type is P4_TABLE */
    ++#ifdef SQLITE_ENABLE_CURSOR_HINTS
    ++    Expr *pExpr;           /* Used when p4type is P4_EXPR */
    ++#endif
    ++    int (*xAdvance)(BtCursor *, int);
    +   } p4;
    + #ifdef SQLITE_ENABLE_EXPLAIN_COMMENTS
    +   char *zComment;          /* Comment to improve readability */
    +@@ -10354,7 +13756,7 @@ struct SubProgram {
    +   int nOp;                      /* Elements in aOp[] */
    +   int nMem;                     /* Number of memory cells required */
    +   int nCsr;                     /* Number of cursors required */
    +-  int nOnce;                    /* Number of OP_Once instructions */
    ++  u8 *aOnce;                    /* Array of OP_Once flags */
    +   void *token;                  /* id that may be used to recursive triggers */
    +   SubProgram *pNext;            /* Next sub-program already visited */
    + };
    +@@ -10374,23 +13776,27 @@ typedef struct VdbeOpList VdbeOpList;
    + /*
    + ** Allowed values of VdbeOp.p4type
    + */
    +-#define P4_NOTUSED    0   /* The P4 parameter is not used */
    +-#define P4_DYNAMIC  (-1)  /* Pointer to a string obtained from sqliteMalloc() */
    +-#define P4_STATIC   (-2)  /* Pointer to a static string */
    +-#define P4_COLLSEQ  (-4)  /* P4 is a pointer to a CollSeq structure */
    +-#define P4_FUNCDEF  (-5)  /* P4 is a pointer to a FuncDef structure */
    +-#define P4_KEYINFO  (-6)  /* P4 is a pointer to a KeyInfo structure */
    +-#define P4_MEM      (-8)  /* P4 is a pointer to a Mem*    structure */
    +-#define P4_TRANSIENT  0   /* P4 is a pointer to a transient string */
    +-#define P4_VTAB     (-10) /* P4 is a pointer to an sqlite3_vtab structure */
    +-#define P4_MPRINTF  (-11) /* P4 is a string obtained from sqlite3_mprintf() */
    +-#define P4_REAL     (-12) /* P4 is a 64-bit floating point value */
    +-#define P4_INT64    (-13) /* P4 is a 64-bit signed integer */
    +-#define P4_INT32    (-14) /* P4 is a 32-bit signed integer */
    +-#define P4_INTARRAY (-15) /* P4 is a vector of 32-bit integers */
    +-#define P4_SUBPROGRAM  (-18) /* P4 is a pointer to a SubProgram structure */
    +-#define P4_ADVANCE  (-19) /* P4 is a pointer to BtreeNext() or BtreePrev() */
    +-#define P4_FUNCCTX  (-20) /* P4 is a pointer to an sqlite3_context object */
    ++#define P4_NOTUSED      0   /* The P4 parameter is not used */
    ++#define P4_TRANSIENT    0   /* P4 is a pointer to a transient string */
    ++#define P4_STATIC     (-1)  /* Pointer to a static string */
    ++#define P4_COLLSEQ    (-2)  /* P4 is a pointer to a CollSeq structure */
    ++#define P4_INT32      (-3)  /* P4 is a 32-bit signed integer */
    ++#define P4_SUBPROGRAM (-4)  /* P4 is a pointer to a SubProgram structure */
    ++#define P4_ADVANCE    (-5)  /* P4 is a pointer to BtreeNext() or BtreePrev() */
    ++#define P4_TABLE      (-6)  /* P4 is a pointer to a Table structure */
    ++/* Above do not own any resources.  Must free those below */
    ++#define P4_FREE_IF_LE (-7)
    ++#define P4_DYNAMIC    (-7)  /* Pointer to memory from sqliteMalloc() */
    ++#define P4_FUNCDEF    (-8)  /* P4 is a pointer to a FuncDef structure */
    ++#define P4_KEYINFO    (-9)  /* P4 is a pointer to a KeyInfo structure */
    ++#define P4_EXPR       (-10) /* P4 is a pointer to an Expr tree */
    ++#define P4_MEM        (-11) /* P4 is a pointer to a Mem*    structure */
    ++#define P4_VTAB       (-12) /* P4 is a pointer to an sqlite3_vtab structure */
    ++#define P4_REAL       (-13) /* P4 is a 64-bit floating point value */
    ++#define P4_INT64      (-14) /* P4 is a 64-bit signed integer */
    ++#define P4_INTARRAY   (-15) /* P4 is a vector of 32-bit integers */
    ++#define P4_FUNCCTX    (-16) /* P4 is a pointer to an sqlite3_context object */
    ++#define P4_DYNBLOB    (-17) /* Pointer to memory from sqliteMalloc() */
    + 
    + /* Error message codes for OP_Halt */
    + #define P5_ConstraintNotNull 1
    +@@ -10432,205 +13838,229 @@ typedef struct VdbeOpList VdbeOpList;
    + /************** Include opcodes.h in the middle of vdbe.h ********************/
    + /************** Begin file opcodes.h *****************************************/
    + /* Automatically generated.  Do not edit */
    +-/* See the mkopcodeh.awk script for details */
    +-#define OP_Savepoint       1
    +-#define OP_AutoCommit      2
    +-#define OP_Transaction     3
    +-#define OP_SorterNext      4
    +-#define OP_PrevIfOpen      5
    +-#define OP_NextIfOpen      6
    +-#define OP_Prev            7
    +-#define OP_Next            8
    +-#define OP_Checkpoint      9
    +-#define OP_JournalMode    10
    +-#define OP_Vacuum         11
    +-#define OP_VFilter        12 /* synopsis: iplan=r[P3] zplan='P4'           */
    +-#define OP_VUpdate        13 /* synopsis: data=r[P3@P2]                    */
    +-#define OP_Goto           14
    +-#define OP_Gosub          15
    +-#define OP_Return         16
    +-#define OP_InitCoroutine  17
    +-#define OP_EndCoroutine   18
    ++/* See the tool/mkopcodeh.tcl script for details */
    ++#define OP_Savepoint       0
    ++#define OP_AutoCommit      1
    ++#define OP_Transaction     2
    ++#define OP_SorterNext      3 /* jump                                       */
    ++#define OP_PrevIfOpen      4 /* jump                                       */
    ++#define OP_NextIfOpen      5 /* jump                                       */
    ++#define OP_Prev            6 /* jump                                       */
    ++#define OP_Next            7 /* jump                                       */
    ++#define OP_Checkpoint      8
    ++#define OP_JournalMode     9
    ++#define OP_Vacuum         10
    ++#define OP_VFilter        11 /* jump, synopsis: iplan=r[P3] zplan='P4'     */
    ++#define OP_VUpdate        12 /* synopsis: data=r[P3@P2]                    */
    ++#define OP_Goto           13 /* jump                                       */
    ++#define OP_Gosub          14 /* jump                                       */
    ++#define OP_InitCoroutine  15 /* jump                                       */
    ++#define OP_Yield          16 /* jump                                       */
    ++#define OP_MustBeInt      17 /* jump                                       */
    ++#define OP_Jump           18 /* jump                                       */
    + #define OP_Not            19 /* same as TK_NOT, synopsis: r[P2]= !r[P1]    */
    +-#define OP_Yield          20
    +-#define OP_HaltIfNull     21 /* synopsis: if r[P3]=null halt               */
    +-#define OP_Halt           22
    +-#define OP_Integer        23 /* synopsis: r[P2]=P1                         */
    +-#define OP_Int64          24 /* synopsis: r[P2]=P4                         */
    +-#define OP_String         25 /* synopsis: r[P2]='P4' (len=P1)              */
    +-#define OP_Null           26 /* synopsis: r[P2..P3]=NULL                   */
    +-#define OP_SoftNull       27 /* synopsis: r[P1]=NULL                       */
    +-#define OP_Blob           28 /* synopsis: r[P2]=P4 (len=P1)                */
    +-#define OP_Variable       29 /* synopsis: r[P2]=parameter(P1,P4)           */
    +-#define OP_Move           30 /* synopsis: r[P2@P3]=r[P1@P3]                */
    +-#define OP_Copy           31 /* synopsis: r[P2@P3+1]=r[P1@P3+1]            */
    +-#define OP_SCopy          32 /* synopsis: r[P2]=r[P1]                      */
    +-#define OP_ResultRow      33 /* synopsis: output=r[P1@P2]                  */
    +-#define OP_CollSeq        34
    +-#define OP_Function0      35 /* synopsis: r[P3]=func(r[P2@P5])             */
    +-#define OP_Function       36 /* synopsis: r[P3]=func(r[P2@P5])             */
    +-#define OP_AddImm         37 /* synopsis: r[P1]=r[P1]+P2                   */
    +-#define OP_MustBeInt      38
    +-#define OP_RealAffinity   39
    +-#define OP_Cast           40 /* synopsis: affinity(r[P1])                  */
    +-#define OP_Permutation    41
    +-#define OP_Compare        42 /* synopsis: r[P1@P3] <-> r[P2@P3]            */
    +-#define OP_Jump           43
    +-#define OP_Once           44
    +-#define OP_If             45
    +-#define OP_IfNot          46
    +-#define OP_Column         47 /* synopsis: r[P3]=PX                         */
    +-#define OP_Affinity       48 /* synopsis: affinity(r[P1@P2])               */
    +-#define OP_MakeRecord     49 /* synopsis: r[P3]=mkrec(r[P1@P2])            */
    +-#define OP_Count          50 /* synopsis: r[P2]=count()                    */
    +-#define OP_ReadCookie     51
    +-#define OP_SetCookie      52
    +-#define OP_ReopenIdx      53 /* synopsis: root=P2 iDb=P3                   */
    +-#define OP_OpenRead       54 /* synopsis: root=P2 iDb=P3                   */
    +-#define OP_OpenWrite      55 /* synopsis: root=P2 iDb=P3                   */
    +-#define OP_OpenAutoindex  56 /* synopsis: nColumn=P2                       */
    +-#define OP_OpenEphemeral  57 /* synopsis: nColumn=P2                       */
    +-#define OP_SorterOpen     58
    +-#define OP_SequenceTest   59 /* synopsis: if( cursor[P1].ctr++ ) pc = P2   */
    +-#define OP_OpenPseudo     60 /* synopsis: P3 columns in r[P2]              */
    +-#define OP_Close          61
    +-#define OP_ColumnsUsed    62
    +-#define OP_SeekLT         63 /* synopsis: key=r[P3@P4]                     */
    +-#define OP_SeekLE         64 /* synopsis: key=r[P3@P4]                     */
    +-#define OP_SeekGE         65 /* synopsis: key=r[P3@P4]                     */
    +-#define OP_SeekGT         66 /* synopsis: key=r[P3@P4]                     */
    +-#define OP_Seek           67 /* synopsis: intkey=r[P2]                     */
    +-#define OP_NoConflict     68 /* synopsis: key=r[P3@P4]                     */
    +-#define OP_NotFound       69 /* synopsis: key=r[P3@P4]                     */
    +-#define OP_Found          70 /* synopsis: key=r[P3@P4]                     */
    +-#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_NotExists      73 /* synopsis: intkey=r[P3]                     */
    +-#define OP_Sequence       74 /* synopsis: r[P2]=cursor[P1].ctr++           */
    +-#define OP_NewRowid       75 /* synopsis: r[P2]=rowid                      */
    +-#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 */
    +-#define OP_Eq             79 /* same as TK_EQ, synopsis: if r[P1]==r[P3] goto P2 */
    +-#define OP_Gt             80 /* same as TK_GT, synopsis: if r[P1]>r[P3] goto P2 */
    +-#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_Ge             83 /* same as TK_GE, synopsis: if r[P1]>=r[P3] goto P2 */
    +-#define OP_Insert         84 /* synopsis: intkey=r[P3] data=r[P2]          */
    +-#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]<<r[P1] */
    +-#define OP_ShiftRight     88 /* same as TK_RSHIFT, synopsis: r[P3]=r[P2]>>r[P1] */
    +-#define OP_Add            89 /* same as TK_PLUS, synopsis: r[P3]=r[P1]+r[P2] */
    +-#define OP_Subtract       90 /* same as TK_MINUS, synopsis: r[P3]=r[P2]-r[P1] */
    +-#define OP_Multiply       91 /* same as TK_STAR, synopsis: r[P3]=r[P1]*r[P2] */
    +-#define OP_Divide         92 /* same as TK_SLASH, synopsis: r[P3]=r[P2]/r[P1] */
    +-#define OP_Remainder      93 /* same as TK_REM, synopsis: r[P3]=r[P2]%r[P1] */
    +-#define OP_Concat         94 /* same as TK_CONCAT, synopsis: r[P3]=r[P2]+r[P1] */
    +-#define OP_InsertInt      95 /* synopsis: intkey=P3 data=r[P2]             */
    +-#define OP_BitNot         96 /* same as TK_BITNOT, synopsis: r[P1]= ~r[P1] */
    ++#define OP_Once           20 /* jump                                       */
    ++#define OP_If             21 /* jump                                       */
    ++#define OP_IfNot          22 /* jump                                       */
    ++#define OP_IfNullRow      23 /* jump, synopsis: if P1.nullRow then r[P3]=NULL, goto P2 */
    ++#define OP_SeekLT         24 /* jump, synopsis: key=r[P3@P4]               */
    ++#define OP_SeekLE         25 /* jump, synopsis: key=r[P3@P4]               */
    ++#define OP_SeekGE         26 /* jump, synopsis: key=r[P3@P4]               */
    ++#define OP_SeekGT         27 /* jump, synopsis: key=r[P3@P4]               */
    ++#define OP_NoConflict     28 /* jump, synopsis: key=r[P3@P4]               */
    ++#define OP_NotFound       29 /* jump, synopsis: key=r[P3@P4]               */
    ++#define OP_Found          30 /* jump, synopsis: key=r[P3@P4]               */
    ++#define OP_SeekRowid      31 /* jump, synopsis: intkey=r[P3]               */
    ++#define OP_NotExists      32 /* jump, synopsis: intkey=r[P3]               */
    ++#define OP_Last           33 /* jump                                       */
    ++#define OP_IfSmaller      34 /* jump                                       */
    ++#define OP_SorterSort     35 /* jump                                       */
    ++#define OP_Sort           36 /* jump                                       */
    ++#define OP_Rewind         37 /* jump                                       */
    ++#define OP_IdxLE          38 /* jump, synopsis: key=r[P3@P4]               */
    ++#define OP_IdxGT          39 /* jump, synopsis: key=r[P3@P4]               */
    ++#define OP_IdxLT          40 /* jump, synopsis: key=r[P3@P4]               */
    ++#define OP_IdxGE          41 /* jump, synopsis: key=r[P3@P4]               */
    ++#define OP_RowSetRead     42 /* jump, synopsis: r[P3]=rowset(P1)           */
    ++#define OP_Or             43 /* same as TK_OR, synopsis: r[P3]=(r[P1] || r[P2]) */
    ++#define OP_And            44 /* same as TK_AND, synopsis: r[P3]=(r[P1] && r[P2]) */
    ++#define OP_RowSetTest     45 /* jump, synopsis: if r[P3] in rowset(P1) goto P2 */
    ++#define OP_Program        46 /* jump                                       */
    ++#define OP_FkIfZero       47 /* jump, synopsis: if fkctr[P1]==0 goto P2    */
    ++#define OP_IfPos          48 /* jump, synopsis: if r[P1]>0 then r[P1]-=P3, goto P2 */
    ++#define OP_IfNotZero      49 /* jump, synopsis: if r[P1]!=0 then r[P1]--, goto P2 */
    ++#define OP_IsNull         50 /* jump, same as TK_ISNULL, synopsis: if r[P1]==NULL goto P2 */
    ++#define OP_NotNull        51 /* jump, same as TK_NOTNULL, synopsis: if r[P1]!=NULL goto P2 */
    ++#define OP_Ne             52 /* jump, same as TK_NE, synopsis: IF r[P3]!=r[P1] */
    ++#define OP_Eq             53 /* jump, same as TK_EQ, synopsis: IF r[P3]==r[P1] */
    ++#define OP_Gt             54 /* jump, same as TK_GT, synopsis: IF r[P3]>r[P1] */
    ++#define OP_Le             55 /* jump, same as TK_LE, synopsis: IF r[P3]<=r[P1] */
    ++#define OP_Lt             56 /* jump, same as TK_LT, synopsis: IF r[P3]<r[P1] */
    ++#define OP_Ge             57 /* jump, same as TK_GE, synopsis: IF r[P3]>=r[P1] */
    ++#define OP_ElseNotEq      58 /* jump, same as TK_ESCAPE                    */
    ++#define OP_DecrJumpZero   59 /* jump, synopsis: if (--r[P1])==0 goto P2    */
    ++#define OP_IncrVacuum     60 /* jump                                       */
    ++#define OP_VNext          61 /* jump                                       */
    ++#define OP_Init           62 /* jump, synopsis: Start at P2                */
    ++#define OP_Return         63
    ++#define OP_EndCoroutine   64
    ++#define OP_HaltIfNull     65 /* synopsis: if r[P3]=null halt               */
    ++#define OP_Halt           66
    ++#define OP_Integer        67 /* synopsis: r[P2]=P1                         */
    ++#define OP_Int64          68 /* synopsis: r[P2]=P4                         */
    ++#define OP_String         69 /* synopsis: r[P2]='P4' (len=P1)              */
    ++#define OP_Null           70 /* synopsis: r[P2..P3]=NULL                   */
    ++#define OP_SoftNull       71 /* synopsis: r[P1]=NULL                       */
    ++#define OP_Blob           72 /* synopsis: r[P2]=P4 (len=P1)                */
    ++#define OP_Variable       73 /* synopsis: r[P2]=parameter(P1,P4)           */
    ++#define OP_Move           74 /* synopsis: r[P2@P3]=r[P1@P3]                */
    ++#define OP_Copy           75 /* synopsis: r[P2@P3+1]=r[P1@P3+1]            */
    ++#define OP_SCopy          76 /* synopsis: r[P2]=r[P1]                      */
    ++#define OP_IntCopy        77 /* synopsis: r[P2]=r[P1]                      */
    ++#define OP_ResultRow      78 /* synopsis: output=r[P1@P2]                  */
    ++#define OP_CollSeq        79
    ++#define OP_AddImm         80 /* synopsis: r[P1]=r[P1]+P2                   */
    ++#define OP_RealAffinity   81
    ++#define OP_Cast           82 /* synopsis: affinity(r[P1])                  */
    ++#define OP_Permutation    83
    ++#define OP_BitAnd         84 /* same as TK_BITAND, synopsis: r[P3]=r[P1]&r[P2] */
    ++#define OP_BitOr          85 /* same as TK_BITOR, synopsis: r[P3]=r[P1]|r[P2] */
    ++#define OP_ShiftLeft      86 /* same as TK_LSHIFT, synopsis: r[P3]=r[P2]<<r[P1] */
    ++#define OP_ShiftRight     87 /* same as TK_RSHIFT, synopsis: r[P3]=r[P2]>>r[P1] */
    ++#define OP_Add            88 /* same as TK_PLUS, synopsis: r[P3]=r[P1]+r[P2] */
    ++#define OP_Subtract       89 /* same as TK_MINUS, synopsis: r[P3]=r[P2]-r[P1] */
    ++#define OP_Multiply       90 /* same as TK_STAR, synopsis: r[P3]=r[P1]*r[P2] */
    ++#define OP_Divide         91 /* same as TK_SLASH, synopsis: r[P3]=r[P2]/r[P1] */
    ++#define OP_Remainder      92 /* same as TK_REM, synopsis: r[P3]=r[P2]%r[P1] */
    ++#define OP_Concat         93 /* same as TK_CONCAT, synopsis: r[P3]=r[P2]+r[P1] */
    ++#define OP_Compare        94 /* synopsis: r[P1@P3] <-> r[P2@P3]            */
    ++#define OP_BitNot         95 /* same as TK_BITNOT, synopsis: r[P1]= ~r[P1] */
    ++#define OP_Offset         96 /* synopsis: r[P3] = sqlite_offset(P1)        */
    + #define OP_String8        97 /* same as TK_STRING, synopsis: r[P2]='P4'    */
    +-#define OP_Delete         98
    +-#define OP_ResetCount     99
    +-#define OP_SorterCompare 100 /* synopsis: if key(P1)!=trim(r[P3],P4) goto P2 */
    +-#define OP_SorterData    101 /* synopsis: r[P2]=data                       */
    +-#define OP_RowKey        102 /* synopsis: r[P2]=key                        */
    +-#define OP_RowData       103 /* synopsis: r[P2]=data                       */
    +-#define OP_Rowid         104 /* synopsis: r[P2]=rowid                      */
    +-#define OP_NullRow       105
    +-#define OP_Last          106
    +-#define OP_SorterSort    107
    +-#define OP_Sort          108
    +-#define OP_Rewind        109
    +-#define OP_SorterInsert  110
    +-#define OP_IdxInsert     111 /* synopsis: key=r[P2]                        */
    +-#define OP_IdxDelete     112 /* synopsis: key=r[P2@P3]                     */
    +-#define OP_IdxRowid      113 /* synopsis: r[P2]=rowid                      */
    +-#define OP_IdxLE         114 /* synopsis: key=r[P3@P4]                     */
    +-#define OP_IdxGT         115 /* synopsis: key=r[P3@P4]                     */
    +-#define OP_IdxLT         116 /* synopsis: key=r[P3@P4]                     */
    +-#define OP_IdxGE         117 /* synopsis: key=r[P3@P4]                     */
    +-#define OP_Destroy       118
    +-#define OP_Clear         119
    +-#define OP_ResetSorter   120
    +-#define OP_CreateIndex   121 /* synopsis: r[P2]=root iDb=P1                */
    +-#define OP_CreateTable   122 /* synopsis: r[P2]=root iDb=P1                */
    +-#define OP_ParseSchema   123
    +-#define OP_LoadAnalysis  124
    +-#define OP_DropTable     125
    +-#define OP_DropIndex     126
    +-#define OP_DropTrigger   127
    +-#define OP_IntegrityCk   128
    +-#define OP_RowSetAdd     129 /* synopsis: rowset(P1)=r[P2]                 */
    +-#define OP_RowSetRead    130 /* synopsis: r[P3]=rowset(P1)                 */
    +-#define OP_RowSetTest    131 /* synopsis: if r[P3] in rowset(P1) goto P2   */
    +-#define OP_Program       132
    +-#define OP_Real          133 /* same as TK_FLOAT, synopsis: r[P2]=P4       */
    +-#define OP_Param         134
    +-#define OP_FkCounter     135 /* synopsis: fkctr[P1]+=P2                    */
    +-#define OP_FkIfZero      136 /* synopsis: if fkctr[P1]==0 goto P2          */
    +-#define OP_MemMax        137 /* synopsis: r[P1]=max(r[P1],r[P2])           */
    +-#define OP_IfPos         138 /* synopsis: if r[P1]>0 then r[P1]-=P3, goto P2 */
    +-#define OP_SetIfNotPos   139 /* synopsis: if r[P1]<=0 then r[P2]=P3        */
    +-#define OP_IfNotZero     140 /* synopsis: if r[P1]!=0 then r[P1]-=P3, goto P2 */
    +-#define OP_DecrJumpZero  141 /* synopsis: if (--r[P1])==0 goto P2          */
    +-#define OP_JumpZeroIncr  142 /* synopsis: if (r[P1]++)==0 ) goto P2        */
    +-#define OP_AggStep0      143 /* synopsis: accum=r[P3] step(r[P2@P5])       */
    +-#define OP_AggStep       144 /* synopsis: accum=r[P3] step(r[P2@P5])       */
    +-#define OP_AggFinal      145 /* synopsis: accum=r[P1] N=P2                 */
    +-#define OP_IncrVacuum    146
    +-#define OP_Expire        147
    +-#define OP_TableLock     148 /* synopsis: iDb=P1 root=P2 write=P3          */
    +-#define OP_VBegin        149
    +-#define OP_VCreate       150
    +-#define OP_VDestroy      151
    +-#define OP_VOpen         152
    +-#define OP_VColumn       153 /* synopsis: r[P3]=vcolumn(P2)                */
    +-#define OP_VNext         154
    +-#define OP_VRename       155
    +-#define OP_Pagecount     156
    +-#define OP_MaxPgcnt      157
    +-#define OP_Init          158 /* synopsis: Start at P2                      */
    +-#define OP_Noop          159
    +-#define OP_Explain       160
    +-
    ++#define OP_Column         98 /* synopsis: r[P3]=PX                         */
    ++#define OP_Affinity       99 /* synopsis: affinity(r[P1@P2])               */
    ++#define OP_MakeRecord    100 /* synopsis: r[P3]=mkrec(r[P1@P2])            */
    ++#define OP_Count         101 /* synopsis: r[P2]=count()                    */
    ++#define OP_ReadCookie    102
    ++#define OP_SetCookie     103
    ++#define OP_ReopenIdx     104 /* synopsis: root=P2 iDb=P3                   */
    ++#define OP_OpenRead      105 /* synopsis: root=P2 iDb=P3                   */
    ++#define OP_OpenWrite     106 /* synopsis: root=P2 iDb=P3                   */
    ++#define OP_OpenDup       107
    ++#define OP_OpenAutoindex 108 /* synopsis: nColumn=P2                       */
    ++#define OP_OpenEphemeral 109 /* synopsis: nColumn=P2                       */
    ++#define OP_SorterOpen    110
    ++#define OP_SequenceTest  111 /* synopsis: if( cursor[P1].ctr++ ) pc = P2   */
    ++#define OP_OpenPseudo    112 /* synopsis: P3 columns in r[P2]              */
    ++#define OP_Close         113
    ++#define OP_ColumnsUsed   114
    ++#define OP_Sequence      115 /* synopsis: r[P2]=cursor[P1].ctr++           */
    ++#define OP_NewRowid      116 /* synopsis: r[P2]=rowid                      */
    ++#define OP_Insert        117 /* synopsis: intkey=r[P3] data=r[P2]          */
    ++#define OP_InsertInt     118 /* synopsis: intkey=P3 data=r[P2]             */
    ++#define OP_Delete        119
    ++#define OP_ResetCount    120
    ++#define OP_SorterCompare 121 /* synopsis: if key(P1)!=trim(r[P3],P4) goto P2 */
    ++#define OP_SorterData    122 /* synopsis: r[P2]=data                       */
    ++#define OP_RowData       123 /* synopsis: r[P2]=data                       */
    ++#define OP_Rowid         124 /* synopsis: r[P2]=rowid                      */
    ++#define OP_NullRow       125
    ++#define OP_SeekEnd       126
    ++#define OP_SorterInsert  127 /* synopsis: key=r[P2]                        */
    ++#define OP_IdxInsert     128 /* synopsis: key=r[P2]                        */
    ++#define OP_IdxDelete     129 /* synopsis: key=r[P2@P3]                     */
    ++#define OP_DeferredSeek  130 /* synopsis: Move P3 to P1.rowid if needed    */
    ++#define OP_IdxRowid      131 /* synopsis: r[P2]=rowid                      */
    ++#define OP_Real          132 /* same as TK_FLOAT, synopsis: r[P2]=P4       */
    ++#define OP_Destroy       133
    ++#define OP_Clear         134
    ++#define OP_ResetSorter   135
    ++#define OP_CreateBtree   136 /* synopsis: r[P2]=root iDb=P1 flags=P3       */
    ++#define OP_SqlExec       137
    ++#define OP_ParseSchema   138
    ++#define OP_LoadAnalysis  139
    ++#define OP_DropTable     140
    ++#define OP_DropIndex     141
    ++#define OP_DropTrigger   142
    ++#define OP_IntegrityCk   143
    ++#define OP_RowSetAdd     144 /* synopsis: rowset(P1)=r[P2]                 */
    ++#define OP_Param         145
    ++#define OP_FkCounter     146 /* synopsis: fkctr[P1]+=P2                    */
    ++#define OP_MemMax        147 /* synopsis: r[P1]=max(r[P1],r[P2])           */
    ++#define OP_OffsetLimit   148 /* synopsis: if r[P1]>0 then r[P2]=r[P1]+max(0,r[P3]) else r[P2]=(-1) */
    ++#define OP_AggStep0      149 /* synopsis: accum=r[P3] step(r[P2@P5])       */
    ++#define OP_AggStep       150 /* synopsis: accum=r[P3] step(r[P2@P5])       */
    ++#define OP_AggFinal      151 /* synopsis: accum=r[P1] N=P2                 */
    ++#define OP_Expire        152
    ++#define OP_TableLock     153 /* synopsis: iDb=P1 root=P2 write=P3          */
    ++#define OP_VBegin        154
    ++#define OP_VCreate       155
    ++#define OP_VDestroy      156
    ++#define OP_VOpen         157
    ++#define OP_VColumn       158 /* synopsis: r[P3]=vcolumn(P2)                */
    ++#define OP_VRename       159
    ++#define OP_Pagecount     160
    ++#define OP_MaxPgcnt      161
    ++#define OP_PureFunc0     162
    ++#define OP_Function0     163 /* synopsis: r[P3]=func(r[P2@P5])             */
    ++#define OP_PureFunc      164
    ++#define OP_Function      165 /* synopsis: r[P3]=func(r[P2@P5])             */
    ++#define OP_Trace         166
    ++#define OP_CursorHint    167
    ++#define OP_Noop          168
    ++#define OP_Explain       169
    + 
    + /* Properties such as "out2" or "jump" that are specified in
    + ** comments following the "case" for each opcode in the vdbe.c
    + ** are encoded into bitvectors as follows:
    + */
    +-#define OPFLG_JUMP            0x0001  /* jump:  P2 holds jmp target */
    +-#define OPFLG_IN1             0x0002  /* in1:   P1 is an input */
    +-#define OPFLG_IN2             0x0004  /* in2:   P2 is an input */
    +-#define OPFLG_IN3             0x0008  /* in3:   P3 is an input */
    +-#define OPFLG_OUT2            0x0010  /* out2:  P2 is an output */
    +-#define OPFLG_OUT3            0x0020  /* out3:  P3 is an output */
    ++#define OPFLG_JUMP        0x01  /* jump:  P2 holds jmp target */
    ++#define OPFLG_IN1         0x02  /* in1:   P1 is an input */
    ++#define OPFLG_IN2         0x04  /* in2:   P2 is an input */
    ++#define OPFLG_IN3         0x08  /* in3:   P3 is an input */
    ++#define OPFLG_OUT2        0x10  /* out2:  P2 is an output */
    ++#define OPFLG_OUT3        0x20  /* out3:  P3 is an output */
    + #define OPFLG_INITIALIZER {\
    +-/*   0 */ 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x01,\
    +-/*   8 */ 0x01, 0x00, 0x10, 0x00, 0x01, 0x00, 0x01, 0x01,\
    +-/*  16 */ 0x02, 0x01, 0x02, 0x12, 0x03, 0x08, 0x00, 0x10,\
    +-/*  24 */ 0x10, 0x10, 0x10, 0x00, 0x10, 0x10, 0x00, 0x00,\
    +-/*  32 */ 0x10, 0x00, 0x00, 0x00, 0x00, 0x02, 0x03, 0x02,\
    +-/*  40 */ 0x02, 0x00, 0x00, 0x01, 0x01, 0x03, 0x03, 0x00,\
    +-/*  48 */ 0x00, 0x00, 0x10, 0x10, 0x08, 0x00, 0x00, 0x00,\
    +-/*  56 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09,\
    +-/*  64 */ 0x09, 0x09, 0x09, 0x04, 0x09, 0x09, 0x09, 0x26,\
    +-/*  72 */ 0x26, 0x09, 0x10, 0x10, 0x03, 0x03, 0x0b, 0x0b,\
    +-/*  80 */ 0x0b, 0x0b, 0x0b, 0x0b, 0x00, 0x26, 0x26, 0x26,\
    +-/*  88 */ 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x00,\
    +-/*  96 */ 0x12, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\
    +-/* 104 */ 0x10, 0x00, 0x01, 0x01, 0x01, 0x01, 0x04, 0x04,\
    +-/* 112 */ 0x00, 0x10, 0x01, 0x01, 0x01, 0x01, 0x10, 0x00,\
    +-/* 120 */ 0x00, 0x10, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00,\
    +-/* 128 */ 0x00, 0x06, 0x23, 0x0b, 0x01, 0x10, 0x10, 0x00,\
    +-/* 136 */ 0x01, 0x04, 0x03, 0x06, 0x03, 0x03, 0x03, 0x00,\
    +-/* 144 */ 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,\
    +-/* 152 */ 0x00, 0x00, 0x01, 0x00, 0x10, 0x10, 0x01, 0x00,\
    +-/* 160 */ 0x00,}
    ++/*   0 */ 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x01, 0x01,\
    ++/*   8 */ 0x00, 0x10, 0x00, 0x01, 0x00, 0x01, 0x01, 0x01,\
    ++/*  16 */ 0x03, 0x03, 0x01, 0x12, 0x01, 0x03, 0x03, 0x01,\
    ++/*  24 */ 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09,\
    ++/*  32 */ 0x09, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,\
    ++/*  40 */ 0x01, 0x01, 0x23, 0x26, 0x26, 0x0b, 0x01, 0x01,\
    ++/*  48 */ 0x03, 0x03, 0x03, 0x03, 0x0b, 0x0b, 0x0b, 0x0b,\
    ++/*  56 */ 0x0b, 0x0b, 0x01, 0x03, 0x01, 0x01, 0x01, 0x02,\
    ++/*  64 */ 0x02, 0x08, 0x00, 0x10, 0x10, 0x10, 0x10, 0x00,\
    ++/*  72 */ 0x10, 0x10, 0x00, 0x00, 0x10, 0x10, 0x00, 0x00,\
    ++/*  80 */ 0x02, 0x02, 0x02, 0x00, 0x26, 0x26, 0x26, 0x26,\
    ++/*  88 */ 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x00, 0x12,\
    ++/*  96 */ 0x20, 0x10, 0x00, 0x00, 0x00, 0x10, 0x10, 0x00,\
    ++/* 104 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\
    ++/* 112 */ 0x00, 0x00, 0x00, 0x10, 0x10, 0x00, 0x00, 0x00,\
    ++/* 120 */ 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x04,\
    ++/* 128 */ 0x04, 0x00, 0x00, 0x10, 0x10, 0x10, 0x00, 0x00,\
    ++/* 136 */ 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\
    ++/* 144 */ 0x06, 0x10, 0x00, 0x04, 0x1a, 0x00, 0x00, 0x00,\
    ++/* 152 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\
    ++/* 160 */ 0x10, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\
    ++/* 168 */ 0x00, 0x00,}
    ++
    ++/* The sqlite3P2Values() routine is able to run faster if it knows
    ++** the value of the largest JUMP opcode.  The smaller the maximum
    ++** JUMP opcode the better, so the mkopcodeh.tcl script that
    ++** generated this include file strives to group all JUMP opcodes
    ++** together near the beginning of the list.
    ++*/
    ++#define SQLITE_MX_JUMP_OPCODE  62  /* Maximum JUMP opcode */
    + 
    + /************** End of opcodes.h *********************************************/
    + /************** Continuing where we left off in vdbe.h ***********************/
    + 
    ++/*
    ++** Additional non-public SQLITE_PREPARE_* flags
    ++*/
    ++#define SQLITE_PREPARE_SAVESQL  0x80  /* Preserve SQL text */
    ++#define SQLITE_PREPARE_MASK     0x0f  /* Mask of public flags */
    ++
    + /*
    + ** Prototypes for the VDBE interface.  See comments on the implementation
    + ** for a description of what each of these routines does.
    +@@ -10646,22 +14076,32 @@ SQLITE_PRIVATE int sqlite3VdbeAddOp3(Vdbe*,int,int,int,int);
    + SQLITE_PRIVATE int sqlite3VdbeAddOp4(Vdbe*,int,int,int,int,const char *zP4,int);
    + SQLITE_PRIVATE int sqlite3VdbeAddOp4Dup8(Vdbe*,int,int,int,int,const u8*,int);
    + SQLITE_PRIVATE int sqlite3VdbeAddOp4Int(Vdbe*,int,int,int,int,int);
    +-SQLITE_PRIVATE int sqlite3VdbeAddOpList(Vdbe*, int nOp, VdbeOpList const *aOp, int iLineno);
    ++SQLITE_PRIVATE void sqlite3VdbeEndCoroutine(Vdbe*,int);
    ++#if defined(SQLITE_DEBUG) && !defined(SQLITE_TEST_REALLOC_STRESS)
    ++SQLITE_PRIVATE   void sqlite3VdbeVerifyNoMallocRequired(Vdbe *p, int N);
    ++SQLITE_PRIVATE   void sqlite3VdbeVerifyNoResultRow(Vdbe *p);
    ++#else
    ++# define sqlite3VdbeVerifyNoMallocRequired(A,B)
    ++# define sqlite3VdbeVerifyNoResultRow(A)
    ++#endif
    ++SQLITE_PRIVATE VdbeOp *sqlite3VdbeAddOpList(Vdbe*, int nOp, VdbeOpList const *aOp, int iLineno);
    + SQLITE_PRIVATE void sqlite3VdbeAddParseSchemaOp(Vdbe*,int,char*);
    + SQLITE_PRIVATE void sqlite3VdbeChangeOpcode(Vdbe*, u32 addr, u8);
    + SQLITE_PRIVATE void sqlite3VdbeChangeP1(Vdbe*, u32 addr, int P1);
    + SQLITE_PRIVATE void sqlite3VdbeChangeP2(Vdbe*, u32 addr, int P2);
    + SQLITE_PRIVATE void sqlite3VdbeChangeP3(Vdbe*, u32 addr, int P3);
    +-SQLITE_PRIVATE void sqlite3VdbeChangeP5(Vdbe*, u8 P5);
    ++SQLITE_PRIVATE void sqlite3VdbeChangeP5(Vdbe*, u16 P5);
    + SQLITE_PRIVATE void sqlite3VdbeJumpHere(Vdbe*, int addr);
    +-SQLITE_PRIVATE void sqlite3VdbeChangeToNoop(Vdbe*, int addr);
    ++SQLITE_PRIVATE int sqlite3VdbeChangeToNoop(Vdbe*, int addr);
    + SQLITE_PRIVATE int sqlite3VdbeDeletePriorOpcode(Vdbe*, u8 op);
    + SQLITE_PRIVATE void sqlite3VdbeChangeP4(Vdbe*, int addr, const char *zP4, int N);
    ++SQLITE_PRIVATE void sqlite3VdbeAppendP4(Vdbe*, void *pP4, int p4type);
    + SQLITE_PRIVATE void sqlite3VdbeSetP4KeyInfo(Parse*, Index*);
    + SQLITE_PRIVATE void sqlite3VdbeUsesBtree(Vdbe*, int);
    + SQLITE_PRIVATE VdbeOp *sqlite3VdbeGetOp(Vdbe*, int);
    + SQLITE_PRIVATE int sqlite3VdbeMakeLabel(Vdbe*);
    + SQLITE_PRIVATE void sqlite3VdbeRunOnlyOnce(Vdbe*);
    ++SQLITE_PRIVATE void sqlite3VdbeReusable(Vdbe*);
    + SQLITE_PRIVATE void sqlite3VdbeDelete(Vdbe*);
    + SQLITE_PRIVATE void sqlite3VdbeClearObject(sqlite3*,Vdbe*);
    + SQLITE_PRIVATE void sqlite3VdbeMakeReady(Vdbe*,Parse*);
    +@@ -10678,7 +14118,8 @@ SQLITE_PRIVATE void sqlite3VdbeSetNumCols(Vdbe*,int);
    + SQLITE_PRIVATE int sqlite3VdbeSetColName(Vdbe*, int, int, const char *, void(*)(void*));
    + SQLITE_PRIVATE void sqlite3VdbeCountChanges(Vdbe*);
    + SQLITE_PRIVATE sqlite3 *sqlite3VdbeDb(Vdbe*);
    +-SQLITE_PRIVATE void sqlite3VdbeSetSql(Vdbe*, const char *z, int n, int);
    ++SQLITE_PRIVATE u8 sqlite3VdbePrepareFlags(Vdbe*);
    ++SQLITE_PRIVATE void sqlite3VdbeSetSql(Vdbe*, const char *z, int n, u8);
    + SQLITE_PRIVATE void sqlite3VdbeSwap(Vdbe*,Vdbe*);
    + SQLITE_PRIVATE VdbeOp *sqlite3VdbeTakeOpArray(Vdbe*, int*, int*);
    + SQLITE_PRIVATE sqlite3_value *sqlite3VdbeGetBoundValue(Vdbe*, int, u8);
    +@@ -10691,7 +14132,7 @@ 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*,UnpackedRecord*);
    + SQLITE_PRIVATE int sqlite3VdbeRecordCompareWithSkip(int, const void *, UnpackedRecord *, int);
    +-SQLITE_PRIVATE UnpackedRecord *sqlite3VdbeAllocUnpackedRecord(KeyInfo *, char *, int, char **);
    ++SQLITE_PRIVATE UnpackedRecord *sqlite3VdbeAllocUnpackedRecord(KeyInfo*);
    + 
    + typedef int (*RecordCompare)(int,const void*,UnpackedRecord*);
    + SQLITE_PRIVATE RecordCompare sqlite3VdbeFindCompare(UnpackedRecord*);
    +@@ -10700,6 +14141,8 @@ SQLITE_PRIVATE RecordCompare sqlite3VdbeFindCompare(UnpackedRecord*);
    + SQLITE_PRIVATE void sqlite3VdbeLinkSubProgram(Vdbe *, SubProgram *);
    + #endif
    + 
    ++SQLITE_PRIVATE int sqlite3NotPureFunc(sqlite3_context*);
    ++
    + /* Use SQLITE_ENABLE_COMMENTS to enable generation of extra comments on
    + ** each VDBE opcode.
    + **
    +@@ -10766,7 +14209,7 @@ SQLITE_PRIVATE void sqlite3VdbeScanStatus(Vdbe*, int, int, int, LogEst, const ch
    + # define sqlite3VdbeScanStatus(a,b,c,d,e)
    + #endif
    + 
    +-#endif
    ++#endif /* SQLITE_VDBE_H */
    + 
    + /************** End of vdbe.h ************************************************/
    + /************** Continuing where we left off in sqliteInt.h ******************/
    +@@ -10788,8 +14231,8 @@ SQLITE_PRIVATE void sqlite3VdbeScanStatus(Vdbe*, int, int, int, LogEst, const ch
    + ** at a time and provides a journal for rollback.
    + */
    + 
    +-#ifndef _PAGER_H_
    +-#define _PAGER_H_
    ++#ifndef SQLITE_PAGER_H
    ++#define SQLITE_PAGER_H
    + 
    + /*
    + ** Default maximum size for persistent journal files. A negative 
    +@@ -10842,7 +14285,11 @@ typedef struct PgHdr DbPage;
    + #define PAGER_LOCKINGMODE_EXCLUSIVE   1
    + 
    + /*
    +-** Numeric constants that encode the journalmode.  
    ++** Numeric constants that encode the journalmode.
    ++**
    ++** The numeric values encoded here (other than PAGER_JOURNALMODE_QUERY)
    ++** are exposed in the API via the "PRAGMA journal_mode" command and
    ++** therefore cannot be changed without a compatibility break.
    + */
    + #define PAGER_JOURNALMODE_QUERY     (-1)  /* Query the value of journalmode */
    + #define PAGER_JOURNALMODE_DELETE      0   /* Commit by deleting journal file */
    +@@ -10853,22 +14300,28 @@ typedef struct PgHdr DbPage;
    + #define PAGER_JOURNALMODE_WAL         5   /* Use write-ahead logging */
    + 
    + /*
    +-** Flags that make up the mask passed to sqlite3PagerAcquire().
    ++** Flags that make up the mask passed to sqlite3PagerGet().
    + */
    + #define PAGER_GET_NOCONTENT     0x01  /* Do not load data from disk */
    + #define PAGER_GET_READONLY      0x02  /* Read-only page is acceptable */
    + 
    + /*
    + ** Flags for sqlite3PagerSetFlags()
    ++**
    ++** Value constraints (enforced via assert()):
    ++**    PAGER_FULLFSYNC      == SQLITE_FullFSync
    ++**    PAGER_CKPT_FULLFSYNC == SQLITE_CkptFullFSync
    ++**    PAGER_CACHE_SPILL    == SQLITE_CacheSpill
    + */
    + #define PAGER_SYNCHRONOUS_OFF       0x01  /* PRAGMA synchronous=OFF */
    + #define PAGER_SYNCHRONOUS_NORMAL    0x02  /* PRAGMA synchronous=NORMAL */
    + #define PAGER_SYNCHRONOUS_FULL      0x03  /* PRAGMA synchronous=FULL */
    +-#define PAGER_SYNCHRONOUS_MASK      0x03  /* Mask for three values above */
    +-#define PAGER_FULLFSYNC             0x04  /* PRAGMA fullfsync=ON */
    +-#define PAGER_CKPT_FULLFSYNC        0x08  /* PRAGMA checkpoint_fullfsync=ON */
    +-#define PAGER_CACHESPILL            0x10  /* PRAGMA cache_spill=ON */
    +-#define PAGER_FLAGS_MASK            0x1c  /* All above except SYNCHRONOUS */
    ++#define PAGER_SYNCHRONOUS_EXTRA     0x04  /* PRAGMA synchronous=EXTRA */
    ++#define PAGER_SYNCHRONOUS_MASK      0x07  /* Mask for four values above */
    ++#define PAGER_FULLFSYNC             0x08  /* PRAGMA fullfsync=ON */
    ++#define PAGER_CKPT_FULLFSYNC        0x10  /* PRAGMA checkpoint_fullfsync=ON */
    ++#define PAGER_CACHESPILL            0x20  /* PRAGMA cache_spill=ON */
    ++#define PAGER_FLAGS_MASK            0x38  /* All above except SYNCHRONOUS */
    + 
    + /*
    + ** The remainder of this file contains the declarations of the functions
    +@@ -10886,7 +14339,7 @@ SQLITE_PRIVATE int sqlite3PagerOpen(
    +   int,
    +   void(*)(DbPage*)
    + );
    +-SQLITE_PRIVATE int sqlite3PagerClose(Pager *pPager);
    ++SQLITE_PRIVATE int sqlite3PagerClose(Pager *pPager, sqlite3*);
    + SQLITE_PRIVATE int sqlite3PagerReadFileheader(Pager*, int, unsigned char*);
    + 
    + /* Functions used to configure a Pager object. */
    +@@ -10897,6 +14350,7 @@ SQLITE_PRIVATE void sqlite3PagerAlignReserve(Pager*,Pager*);
    + #endif
    + SQLITE_PRIVATE int sqlite3PagerMaxPageCount(Pager*, int);
    + SQLITE_PRIVATE void sqlite3PagerSetCachesize(Pager*, int);
    ++SQLITE_PRIVATE int sqlite3PagerSetSpillsize(Pager*, int);
    + SQLITE_PRIVATE void sqlite3PagerSetMmapLimit(Pager *, sqlite3_int64);
    + SQLITE_PRIVATE void sqlite3PagerShrink(Pager*);
    + SQLITE_PRIVATE void sqlite3PagerSetFlags(Pager*,unsigned);
    +@@ -10906,14 +14360,15 @@ SQLITE_PRIVATE int sqlite3PagerGetJournalMode(Pager*);
    + SQLITE_PRIVATE int sqlite3PagerOkToChangeJournalMode(Pager*);
    + SQLITE_PRIVATE i64 sqlite3PagerJournalSizeLimit(Pager *, i64);
    + SQLITE_PRIVATE sqlite3_backup **sqlite3PagerBackupPtr(Pager*);
    ++SQLITE_PRIVATE int sqlite3PagerFlush(Pager*);
    + 
    + /* Functions used to obtain and release page references. */ 
    +-SQLITE_PRIVATE int sqlite3PagerAcquire(Pager *pPager, Pgno pgno, DbPage **ppPage, int clrFlag);
    +-#define sqlite3PagerGet(A,B,C) sqlite3PagerAcquire(A,B,C,0)
    ++SQLITE_PRIVATE int sqlite3PagerGet(Pager *pPager, Pgno pgno, DbPage **ppPage, int clrFlag);
    + SQLITE_PRIVATE DbPage *sqlite3PagerLookup(Pager *pPager, Pgno pgno);
    + SQLITE_PRIVATE void sqlite3PagerRef(DbPage*);
    + SQLITE_PRIVATE void sqlite3PagerUnref(DbPage*);
    + SQLITE_PRIVATE void sqlite3PagerUnrefNotNull(DbPage*);
    ++SQLITE_PRIVATE void sqlite3PagerUnrefPageOne(DbPage*);
    + 
    + /* Operations on page references. */
    + SQLITE_PRIVATE int sqlite3PagerWrite(DbPage*);
    +@@ -10936,11 +14391,21 @@ SQLITE_PRIVATE int sqlite3PagerSavepoint(Pager *pPager, int op, int iSavepoint);
    + SQLITE_PRIVATE int sqlite3PagerSharedLock(Pager *pPager);
    + 
    + #ifndef SQLITE_OMIT_WAL
    +-SQLITE_PRIVATE   int sqlite3PagerCheckpoint(Pager *pPager, int, int*, int*);
    ++SQLITE_PRIVATE   int sqlite3PagerCheckpoint(Pager *pPager, sqlite3*, int, int*, int*);
    + SQLITE_PRIVATE   int sqlite3PagerWalSupported(Pager *pPager);
    + SQLITE_PRIVATE   int sqlite3PagerWalCallback(Pager *pPager);
    + SQLITE_PRIVATE   int sqlite3PagerOpenWal(Pager *pPager, int *pisOpen);
    +-SQLITE_PRIVATE   int sqlite3PagerCloseWal(Pager *pPager);
    ++SQLITE_PRIVATE   int sqlite3PagerCloseWal(Pager *pPager, sqlite3*);
    ++# ifdef SQLITE_DIRECT_OVERFLOW_READ
    ++SQLITE_PRIVATE   int sqlite3PagerUseWal(Pager *pPager, Pgno);
    ++# endif
    ++# ifdef SQLITE_ENABLE_SNAPSHOT
    ++SQLITE_PRIVATE   int sqlite3PagerSnapshotGet(Pager *pPager, sqlite3_snapshot **ppSnapshot);
    ++SQLITE_PRIVATE   int sqlite3PagerSnapshotOpen(Pager *pPager, sqlite3_snapshot *pSnapshot);
    ++SQLITE_PRIVATE   int sqlite3PagerSnapshotRecover(Pager *pPager);
    ++# endif
    ++#else
    ++# define sqlite3PagerUseWal(x,y) 0
    + #endif
    + 
    + #ifdef SQLITE_ENABLE_ZIPVFS
    +@@ -10955,14 +14420,14 @@ SQLITE_PRIVATE   int sqlite3PagerRefcount(Pager*);
    + #endif
    + SQLITE_PRIVATE int sqlite3PagerMemUsed(Pager*);
    + SQLITE_PRIVATE const char *sqlite3PagerFilename(Pager*, int);
    +-SQLITE_PRIVATE const sqlite3_vfs *sqlite3PagerVfs(Pager*);
    ++SQLITE_PRIVATE sqlite3_vfs *sqlite3PagerVfs(Pager*);
    + SQLITE_PRIVATE sqlite3_file *sqlite3PagerFile(Pager*);
    ++SQLITE_PRIVATE sqlite3_file *sqlite3PagerJrnlFile(Pager*);
    + SQLITE_PRIVATE const char *sqlite3PagerJournalname(Pager*);
    +-SQLITE_PRIVATE int sqlite3PagerNosync(Pager*);
    + SQLITE_PRIVATE void *sqlite3PagerTempSpace(Pager*);
    + SQLITE_PRIVATE int sqlite3PagerIsMemdb(Pager*);
    + SQLITE_PRIVATE void sqlite3PagerCacheStat(Pager *, int, int, int *);
    +-SQLITE_PRIVATE void sqlite3PagerClearCache(Pager *);
    ++SQLITE_PRIVATE void sqlite3PagerClearCache(Pager*);
    + SQLITE_PRIVATE int sqlite3SectorSize(sqlite3_file *);
    + 
    + /* Functions used to truncate the database file. */
    +@@ -10989,7 +14454,7 @@ SQLITE_PRIVATE   void sqlite3PagerRefdump(Pager*);
    + # define enable_simulated_io_errors()
    + #endif
    + 
    +-#endif /* _PAGER_H_ */
    ++#endif /* SQLITE_PAGER_H */
    + 
    + /************** End of pager.h ***********************************************/
    + /************** Continuing where we left off in sqliteInt.h ******************/
    +@@ -11023,7 +14488,8 @@ struct PgHdr {
    +   sqlite3_pcache_page *pPage;    /* Pcache object page handle */
    +   void *pData;                   /* Page data */
    +   void *pExtra;                  /* Extra content */
    +-  PgHdr *pDirty;                 /* Transient list of dirty pages */
    ++  PCache *pCache;                /* PRIVATE: Cache that owns this page */
    ++  PgHdr *pDirty;                 /* Transient list of dirty sorted by pgno */
    +   Pager *pPager;                 /* The pager this page is part of */
    +   Pgno pgno;                     /* Page number for this page */
    + #ifdef SQLITE_CHECK_PAGES
    +@@ -11032,14 +14498,15 @@ struct PgHdr {
    +   u16 flags;                     /* PGHDR flags defined below */
    + 
    +   /**********************************************************************
    +-  ** Elements above are public.  All that follows is private to pcache.c
    +-  ** and should not be accessed by other modules.
    ++  ** Elements above, except pCache, are public.  All that follow are 
    ++  ** private to pcache.c and should not be accessed by other modules.
    ++  ** pCache is grouped with the public elements for efficiency.
    +   */
    +   i16 nRef;                      /* Number of users of this page */
    +-  PCache *pCache;                /* Cache that owns this page */
    +-
    +   PgHdr *pDirtyNext;             /* Next element in list of dirty pages */
    +   PgHdr *pDirtyPrev;             /* Previous element in list of dirty pages */
    ++                          /* NB: pDirtyNext and pDirtyPrev are undefined if the
    ++                          ** PgHdr object is not dirty */
    + };
    + 
    + /* Bit values for PgHdr.flags */
    +@@ -11048,9 +14515,10 @@ struct PgHdr {
    + #define PGHDR_WRITEABLE       0x004  /* Journaled and ready to modify */
    + #define PGHDR_NEED_SYNC       0x008  /* Fsync the rollback journal before
    +                                      ** writing this page to the database */
    +-#define PGHDR_NEED_READ       0x010  /* Content is unread */
    +-#define PGHDR_DONT_WRITE      0x020  /* Do not write content to disk */
    +-#define PGHDR_MMAP            0x040  /* This is an mmap page object */
    ++#define PGHDR_DONT_WRITE      0x010  /* Do not write content to disk */
    ++#define PGHDR_MMAP            0x020  /* This is an mmap page object */
    ++
    ++#define PGHDR_WAL_APPEND      0x040  /* Appended to wal file */
    + 
    + /* Initialize and shutdown the page cache subsystem */
    + SQLITE_PRIVATE int sqlite3PcacheInitialize(void);
    +@@ -11094,6 +14562,7 @@ SQLITE_PRIVATE void sqlite3PcacheDrop(PgHdr*);         /* Remove page from cache
    + SQLITE_PRIVATE void sqlite3PcacheMakeDirty(PgHdr*);    /* Make sure page is marked dirty */
    + SQLITE_PRIVATE void sqlite3PcacheMakeClean(PgHdr*);    /* Mark a single page as clean */
    + SQLITE_PRIVATE void sqlite3PcacheCleanAll(PCache*);    /* Mark all dirty list pages as clean */
    ++SQLITE_PRIVATE void sqlite3PcacheClearWritable(PCache*);
    + 
    + /* Change a page number.  Used by incr-vacuum. */
    + SQLITE_PRIVATE void sqlite3PcacheMove(PgHdr*, Pgno);
    +@@ -11132,6 +14601,11 @@ SQLITE_PRIVATE int sqlite3PcachePagecount(PCache*);
    + SQLITE_PRIVATE void sqlite3PcacheIterateDirty(PCache *pCache, void (*xIter)(PgHdr *));
    + #endif
    + 
    ++#if defined(SQLITE_DEBUG)
    ++/* Check invariants on a PgHdr object */
    ++SQLITE_PRIVATE int sqlite3PcachePageSanity(PgHdr*);
    ++#endif
    ++
    + /* Set and get the suggested cache-size for the specified pager-cache.
    + **
    + ** If no global maximum is configured, then the system attempts to limit
    +@@ -11143,6 +14617,13 @@ SQLITE_PRIVATE void sqlite3PcacheSetCachesize(PCache *, int);
    + SQLITE_PRIVATE int sqlite3PcacheGetCachesize(PCache *);
    + #endif
    + 
    ++/* Set or get the suggested spill-size for the specified pager-cache.
    ++**
    ++** The spill-size is the minimum number of pages in cache before the cache
    ++** will attempt to spill dirty pages by calling xStress.
    ++*/
    ++SQLITE_PRIVATE int sqlite3PcacheSetSpillsize(PCache *, int);
    ++
    + /* Free up as much memory as possible from the page cache */
    + SQLITE_PRIVATE void sqlite3PcacheShrink(PCache*);
    + 
    +@@ -11161,11 +14642,13 @@ SQLITE_PRIVATE void sqlite3PCacheSetDefault(void);
    + SQLITE_PRIVATE int sqlite3HeaderSizePcache(void);
    + SQLITE_PRIVATE int sqlite3HeaderSizePcache1(void);
    + 
    ++/* Number of dirty pages as a percentage of the configured cache size */
    ++SQLITE_PRIVATE int sqlite3PCachePercentDirty(PCache*);
    ++
    + #endif /* _PCACHE_H_ */
    + 
    + /************** End of pcache.h **********************************************/
    + /************** Continuing where we left off in sqliteInt.h ******************/
    +-
    + /************** Include os.h in the middle of sqliteInt.h ********************/
    + /************** Begin file os.h **********************************************/
    + /*
    +@@ -11211,8 +14694,8 @@ SQLITE_PRIVATE int sqlite3HeaderSizePcache1(void);
    + ** This file contains pre-processor directives related to operating system
    + ** detection and/or setup.
    + */
    +-#ifndef _OS_SETUP_H_
    +-#define _OS_SETUP_H_
    ++#ifndef SQLITE_OS_SETUP_H
    ++#define SQLITE_OS_SETUP_H
    + 
    + /*
    + ** Figure out if we are dealing with Unix, Windows, or some other operating
    +@@ -11252,7 +14735,7 @@ SQLITE_PRIVATE int sqlite3HeaderSizePcache1(void);
    + #  endif
    + #endif
    + 
    +-#endif /* _OS_SETUP_H_ */
    ++#endif /* SQLITE_OS_SETUP_H */
    + 
    + /************** End of os_setup.h ********************************************/
    + /************** Continuing where we left off in os.h *************************/
    +@@ -11391,7 +14874,7 @@ SQLITE_PRIVATE int sqlite3OsInit(void);
    + /* 
    + ** Functions for accessing sqlite3_file methods 
    + */
    +-SQLITE_PRIVATE int sqlite3OsClose(sqlite3_file*);
    ++SQLITE_PRIVATE void sqlite3OsClose(sqlite3_file*);
    + SQLITE_PRIVATE int sqlite3OsRead(sqlite3_file*, void*, int amt, i64 offset);
    + SQLITE_PRIVATE int sqlite3OsWrite(sqlite3_file*, const void*, int amt, i64 offset);
    + SQLITE_PRIVATE int sqlite3OsTruncate(sqlite3_file*, i64 size);
    +@@ -11405,10 +14888,12 @@ SQLITE_PRIVATE void sqlite3OsFileControlHint(sqlite3_file*,int,void*);
    + #define SQLITE_FCNTL_DB_UNCHANGED 0xca093fa0
    + SQLITE_PRIVATE int sqlite3OsSectorSize(sqlite3_file *id);
    + SQLITE_PRIVATE int sqlite3OsDeviceCharacteristics(sqlite3_file *id);
    ++#ifndef SQLITE_OMIT_WAL
    + SQLITE_PRIVATE int sqlite3OsShmMap(sqlite3_file *,int,int,int,void volatile **);
    + SQLITE_PRIVATE int sqlite3OsShmLock(sqlite3_file *id, int, int, int);
    + SQLITE_PRIVATE void sqlite3OsShmBarrier(sqlite3_file *id);
    + SQLITE_PRIVATE int sqlite3OsShmUnmap(sqlite3_file *id, int);
    ++#endif /* SQLITE_OMIT_WAL */
    + SQLITE_PRIVATE int sqlite3OsFetch(sqlite3_file *id, i64, int, void **);
    + SQLITE_PRIVATE int sqlite3OsUnfetch(sqlite3_file *, i64, void *);
    + 
    +@@ -11428,6 +14913,7 @@ SQLITE_PRIVATE void sqlite3OsDlClose(sqlite3_vfs *, void *);
    + #endif /* SQLITE_OMIT_LOAD_EXTENSION */
    + SQLITE_PRIVATE int sqlite3OsRandomness(sqlite3_vfs *, int, char *);
    + SQLITE_PRIVATE int sqlite3OsSleep(sqlite3_vfs *, int);
    ++SQLITE_PRIVATE int sqlite3OsGetLastError(sqlite3_vfs*);
    + SQLITE_PRIVATE int sqlite3OsCurrentTimeInt64(sqlite3_vfs *, sqlite3_int64*);
    + 
    + /*
    +@@ -11435,7 +14921,7 @@ SQLITE_PRIVATE int sqlite3OsCurrentTimeInt64(sqlite3_vfs *, sqlite3_int64*);
    + ** sqlite3_malloc() to obtain space for the file-handle structure.
    + */
    + SQLITE_PRIVATE int sqlite3OsOpenMalloc(sqlite3_vfs *, const char *, sqlite3_file **, int,int*);
    +-SQLITE_PRIVATE int sqlite3OsCloseFree(sqlite3_file *);
    ++SQLITE_PRIVATE void sqlite3OsCloseFree(sqlite3_file *);
    + 
    + #endif /* _SQLITE_OS_H_ */
    + 
    +@@ -11517,6 +15003,36 @@ SQLITE_PRIVATE int sqlite3OsCloseFree(sqlite3_file *);
    + /************** End of mutex.h ***********************************************/
    + /************** Continuing where we left off in sqliteInt.h ******************/
    + 
    ++/* The SQLITE_EXTRA_DURABLE compile-time option used to set the default
    ++** synchronous setting to EXTRA.  It is no longer supported.
    ++*/
    ++#ifdef SQLITE_EXTRA_DURABLE
    ++# warning Use SQLITE_DEFAULT_SYNCHRONOUS=3 instead of SQLITE_EXTRA_DURABLE
    ++# define SQLITE_DEFAULT_SYNCHRONOUS 3
    ++#endif
    ++
    ++/*
    ++** Default synchronous levels.
    ++**
    ++** Note that (for historcal reasons) the PAGER_SYNCHRONOUS_* macros differ
    ++** from the SQLITE_DEFAULT_SYNCHRONOUS value by 1.
    ++**
    ++**           PAGER_SYNCHRONOUS       DEFAULT_SYNCHRONOUS
    ++**   OFF           1                         0
    ++**   NORMAL        2                         1
    ++**   FULL          3                         2
    ++**   EXTRA         4                         3
    ++**
    ++** The "PRAGMA synchronous" statement also uses the zero-based numbers.
    ++** In other words, the zero-based numbers are used for all external interfaces
    ++** and the one-based values are used internally.
    ++*/
    ++#ifndef SQLITE_DEFAULT_SYNCHRONOUS
    ++# define SQLITE_DEFAULT_SYNCHRONOUS 2
    ++#endif
    ++#ifndef SQLITE_DEFAULT_WAL_SYNCHRONOUS
    ++# define SQLITE_DEFAULT_WAL_SYNCHRONOUS SQLITE_DEFAULT_SYNCHRONOUS
    ++#endif
    + 
    + /*
    + ** Each database file to be accessed by the system is an instance
    +@@ -11526,9 +15042,10 @@ SQLITE_PRIVATE int sqlite3OsCloseFree(sqlite3_file *);
    + ** databases may be attached.
    + */
    + struct Db {
    +-  char *zName;         /* Name of this database */
    ++  char *zDbSName;      /* Name of this database. (schema name, not filename) */
    +   Btree *pBt;          /* The B*Tree structure for this database file */
    +   u8 safety_level;     /* How aggressive at syncing data to disk */
    ++  u8 bSyncSet;         /* True if "PRAGMA synchronous=N" has been run */
    +   Schema *pSchema;     /* Pointer to database schema (possibly shared) */
    + };
    + 
    +@@ -11539,7 +15056,7 @@ struct Db {
    + ** the Schema for the TEMP databaes (sqlite3.aDb[1]) which is free-standing.
    + ** In shared cache mode, a single Schema object can be shared by multiple
    + ** Btrees that refer to the same underlying BtShared object.
    +-** 
    ++**
    + ** Schema objects are automatically deallocated when the last Btree that
    + ** references them is destroyed.   The TEMP Schema is manually freed by
    + ** sqlite3_close().
    +@@ -11564,7 +15081,7 @@ struct Schema {
    + };
    + 
    + /*
    +-** These macros can be used to test, set, or clear bits in the 
    ++** 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->schemaFlags&(P))==(P))
    +@@ -11585,6 +15102,7 @@ struct Schema {
    + #define DB_SchemaLoaded    0x0001  /* The schema has been loaded */
    + #define DB_UnresetViews    0x0002  /* Some views have defined column names */
    + #define DB_Empty           0x0004  /* The file is empty (length 0 bytes) */
    ++#define DB_ResetWanted     0x0008  /* Reset the schema when nSchemaLock==0 */
    + 
    + /*
    + ** The number of different kinds of things that can be limited
    +@@ -11613,12 +15131,12 @@ struct Schema {
    + ** lookaside allocations are not used to construct the schema objects.
    + */
    + struct Lookaside {
    ++  u32 bDisable;           /* Only operate the lookaside when zero */
    +   u16 sz;                 /* Size of each buffer in bytes */
    +-  u8 bEnabled;            /* False to disable new lookaside allocations */
    +   u8 bMalloced;           /* True if pStart obtained from sqlite3_malloc() */
    +-  int nOut;               /* Number of buffers currently checked out */
    +-  int mxOut;              /* Highwater mark for nOut */
    +-  int anStat[3];          /* 0: hits.  1: size misses.  2: full misses */
    ++  u32 nSlot;              /* Number of lookaside slots allocated */
    ++  u32 anStat[3];          /* 0: hits.  1: size misses.  2: full misses */
    ++  LookasideSlot *pInit;   /* List of buffers not previously used */
    +   LookasideSlot *pFree;   /* List of available buffers */
    +   void *pStart;           /* First byte of available memory space */
    +   void *pEnd;             /* First byte past end of available space */
    +@@ -11628,13 +15146,15 @@ struct LookasideSlot {
    + };
    + 
    + /*
    +-** A hash table for function definitions.
    ++** A hash table for built-in function definitions.  (Application-defined
    ++** functions use a regular table table from hash.h.)
    + **
    + ** Hash each FuncDef structure into one of the FuncDefHash.a[] slots.
    +-** Collisions are on the FuncDef.pHash chain.
    ++** Collisions are on the FuncDef.u.pHash chain.
    + */
    ++#define SQLITE_FUNC_HASH_SZ 23
    + struct FuncDefHash {
    +-  FuncDef *a[23];       /* Hash table for functions */
    ++  FuncDef *a[SQLITE_FUNC_HASH_SZ];       /* Hash table for functions */
    + };
    + 
    + #ifdef SQLITE_USER_AUTHENTICATION
    +@@ -11675,6 +15195,15 @@ SQLITE_PRIVATE void sqlite3CryptFunc(sqlite3_context*,int,sqlite3_value**);
    +                                const char*);
    + #endif
    + 
    ++#ifndef SQLITE_OMIT_DEPRECATED
    ++/* This is an extra SQLITE_TRACE macro that indicates "legacy" tracing
    ++** in the style of sqlite3_trace()
    ++*/
    ++#define SQLITE_TRACE_LEGACY  0x80
    ++#else
    ++#define SQLITE_TRACE_LEGACY  0
    ++#endif /* SQLITE_OMIT_DEPRECATED */
    ++
    + 
    + /*
    + ** Each database connection is an instance of the following structure.
    +@@ -11686,22 +15215,29 @@ struct sqlite3 {
    +   sqlite3_mutex *mutex;         /* Connection mutex */
    +   Db *aDb;                      /* All backends */
    +   int nDb;                      /* Number of backends currently in use */
    +-  int flags;                    /* Miscellaneous flags. See below */
    ++  u32 mDbFlags;                 /* flags recording internal state */
    ++  u32 flags;                    /* flags settable by pragmas. See below */
    +   i64 lastRowid;                /* ROWID of most recent insert (see above) */
    +   i64 szMmap;                   /* Default mmap_size setting */
    ++  u32 nSchemaLock;              /* Do not reset the schema when non-zero */
    +   unsigned int openFlags;       /* Flags passed to sqlite3_vfs.xOpen() */
    +   int errCode;                  /* Most recent error code (SQLITE_*) */
    +   int errMask;                  /* & result codes with this before returning */
    ++  int iSysErrno;                /* Errno value from last system error */
    +   u16 dbOptFlags;               /* Flags to enable/disable optimizations */
    +   u8 enc;                       /* Text encoding */
    +   u8 autoCommit;                /* The auto-commit flag. */
    +   u8 temp_store;                /* 1: file 2: memory 0: default */
    +   u8 mallocFailed;              /* True if we have seen a malloc failure */
    ++  u8 bBenignMalloc;             /* Do not require OOMs if true */
    +   u8 dfltLockMode;              /* Default locking-mode for attached dbs */
    +   signed char nextAutovac;      /* Autovac setting after VACUUM if >=0 */
    +   u8 suppressErr;               /* Do not issue error messages if true */
    +   u8 vtabOnConflict;            /* Value to return for s3_vtab_on_conflict() */
    +   u8 isTransactionSavepoint;    /* True if the outermost savepoint is a TS */
    ++  u8 mTrace;                    /* zero or more SQLITE_TRACE flags */
    ++  u8 skipBtreeMutex;            /* True if no shared-cache backends */
    ++  u8 nSqlExec;                  /* Number of pending OP_SqlExec opcodes */
    +   int nextPagesize;             /* Pagesize after VACUUM if >0 */
    +   u32 magic;                    /* Magic number for detect library misuse */
    +   int nChange;                  /* Value returned by sqlite3_changes() */
    +@@ -11722,16 +15258,23 @@ struct sqlite3 {
    +   int nVDestroy;                /* Number of active OP_VDestroy operations */
    +   int nExtension;               /* Number of loaded extensions */
    +   void **aExtension;            /* Array of shared library handles */
    +-  void (*xTrace)(void*,const char*);        /* Trace function */
    ++  int (*xTrace)(u32,void*,void*,void*);     /* Trace function */
    +   void *pTraceArg;                          /* Argument to the trace function */
    +   void (*xProfile)(void*,const char*,u64);  /* Profiling function */
    +   void *pProfileArg;                        /* Argument to profile function */
    +-  void *pCommitArg;                 /* Argument to xCommitCallback() */   
    ++  void *pCommitArg;                 /* Argument to xCommitCallback() */
    +   int (*xCommitCallback)(void*);    /* Invoked at every commit. */
    +-  void *pRollbackArg;               /* Argument to xRollbackCallback() */   
    ++  void *pRollbackArg;               /* Argument to xRollbackCallback() */
    +   void (*xRollbackCallback)(void*); /* Invoked at every commit. */
    +   void *pUpdateArg;
    +   void (*xUpdateCallback)(void*,int, const char*,const char*,sqlite_int64);
    ++#ifdef SQLITE_ENABLE_PREUPDATE_HOOK
    ++  void *pPreUpdateArg;          /* First argument to xPreUpdateCallback */
    ++  void (*xPreUpdateCallback)(   /* Registered using sqlite3_preupdate_hook() */
    ++    void*,sqlite3*,int,char const*,char const*,sqlite3_int64,sqlite3_int64
    ++  );
    ++  PreUpdate *pPreUpdate;        /* Context for active pre-update callback */
    ++#endif /* SQLITE_ENABLE_PREUPDATE_HOOK */
    + #ifndef SQLITE_OMIT_WAL
    +   int (*xWalCallback)(void *, sqlite3 *, const char *, int);
    +   void *pWalArg;
    +@@ -11759,9 +15302,9 @@ struct sqlite3 {
    +   Hash aModule;                 /* populated by sqlite3_create_module() */
    +   VtabCtx *pVtabCtx;            /* Context for active vtab connect/create */
    +   VTable **aVTrans;             /* Virtual tables with open transactions */
    +-  VTable *pDisconnect;    /* Disconnect these in next sqlite3_prepare() */
    ++  VTable *pDisconnect;          /* Disconnect these in next sqlite3_prepare() */
    + #endif
    +-  FuncDefHash aFunc;            /* Hash table of connection functions */
    ++  Hash aFunc;                   /* Hash table of connection functions */
    +   Hash aCollSeq;                /* All collating sequences */
    +   BusyHandler busyHandler;      /* Busy callback */
    +   Db aDbStatic[2];              /* Static space for the 2 default backends */
    +@@ -11773,8 +15316,8 @@ struct sqlite3 {
    +   i64 nDeferredImmCons;         /* Net deferred immediate constraints */
    +   int *pnBytesFreed;            /* If not NULL, increment this in DbFree() */
    + #ifdef SQLITE_ENABLE_UNLOCK_NOTIFY
    +-  /* The following variables are all protected by the STATIC_MASTER 
    +-  ** mutex, not by sqlite3.mutex. They are used by code in notify.c. 
    ++  /* The following variables are all protected by the STATIC_MASTER
    ++  ** mutex, not by sqlite3.mutex. They are used by code in notify.c.
    +   **
    +   ** When X.pUnlockConnection==Y, that means that X is waiting for Y to
    +   ** unlock so that it can proceed.
    +@@ -11802,40 +15345,56 @@ struct sqlite3 {
    + 
    + /*
    + ** Possible values for the sqlite3.flags.
    +-*/
    +-#define SQLITE_VdbeTrace      0x00000001  /* True to trace VDBE execution */
    +-#define SQLITE_InternChanges  0x00000002  /* Uncommitted Hash table changes */
    +-#define SQLITE_FullFSync      0x00000004  /* Use full fsync on the backend */
    +-#define SQLITE_CkptFullFSync  0x00000008  /* Use full fsync for checkpoint */
    +-#define SQLITE_CacheSpill     0x00000010  /* OK to spill pager cache */
    +-#define SQLITE_FullColNames   0x00000020  /* Show full column names on SELECT */
    ++**
    ++** Value constraints (enforced via assert()):
    ++**      SQLITE_FullFSync     == PAGER_FULLFSYNC
    ++**      SQLITE_CkptFullFSync == PAGER_CKPT_FULLFSYNC
    ++**      SQLITE_CacheSpill    == PAGER_CACHE_SPILL
    ++*/
    ++#define SQLITE_WriteSchema    0x00000001  /* OK to update SQLITE_MASTER */
    ++#define SQLITE_LegacyFileFmt  0x00000002  /* Create new databases in format 1 */
    ++#define SQLITE_FullColNames   0x00000004  /* Show full column names on SELECT */
    ++#define SQLITE_FullFSync      0x00000008  /* Use full fsync on the backend */
    ++#define SQLITE_CkptFullFSync  0x00000010  /* Use full fsync for checkpoint */
    ++#define SQLITE_CacheSpill     0x00000020  /* OK to spill pager cache */
    + #define SQLITE_ShortColNames  0x00000040  /* Show short columns names */
    + #define SQLITE_CountRows      0x00000080  /* Count rows changed by INSERT, */
    +                                           /*   DELETE, or UPDATE and return */
    +                                           /*   the count using a callback. */
    + #define SQLITE_NullCallback   0x00000100  /* Invoke the callback once if the */
    +                                           /*   result set is empty */
    +-#define SQLITE_SqlTrace       0x00000200  /* Debug print SQL as it executes */
    +-#define SQLITE_VdbeListing    0x00000400  /* Debug listings of VDBE programs */
    +-#define SQLITE_WriteSchema    0x00000800  /* OK to update SQLITE_MASTER */
    +-#define SQLITE_VdbeAddopTrace 0x00001000  /* Trace sqlite3VdbeAddOp() calls */
    +-#define SQLITE_IgnoreChecks   0x00002000  /* Do not enforce check constraints */
    +-#define SQLITE_ReadUncommitted 0x0004000  /* For shared-cache mode */
    +-#define SQLITE_LegacyFileFmt  0x00008000  /* Create new databases in format 1 */
    +-#define SQLITE_RecoveryMode   0x00010000  /* Ignore schema errors */
    +-#define SQLITE_ReverseOrder   0x00020000  /* Reverse unordered SELECTs */
    +-#define SQLITE_RecTriggers    0x00040000  /* Enable recursive triggers */
    +-#define SQLITE_ForeignKeys    0x00080000  /* Enforce foreign key constraints  */
    +-#define SQLITE_AutoIndex      0x00100000  /* Enable automatic indexes */
    +-#define SQLITE_PreferBuiltin  0x00200000  /* Preference to built-in funcs */
    +-#define SQLITE_LoadExtension  0x00400000  /* Enable load_extension */
    +-#define SQLITE_EnableTrigger  0x00800000  /* True to enable triggers */
    +-#define SQLITE_DeferFKs       0x01000000  /* Defer all FK constraints */
    +-#define SQLITE_QueryOnly      0x02000000  /* Disable database changes */
    +-#define SQLITE_VdbeEQP        0x04000000  /* Debug EXPLAIN QUERY PLAN */
    +-#define SQLITE_Vacuum         0x08000000  /* Currently in a VACUUM */
    +-#define SQLITE_CellSizeCk     0x10000000  /* Check btree cell sizes on load */
    ++#define SQLITE_IgnoreChecks   0x00000200  /* Do not enforce check constraints */
    ++#define SQLITE_ReadUncommit   0x00000400  /* READ UNCOMMITTED in shared-cache */
    ++#define SQLITE_NoCkptOnClose  0x00000800  /* No checkpoint on close()/DETACH */
    ++#define SQLITE_ReverseOrder   0x00001000  /* Reverse unordered SELECTs */
    ++#define SQLITE_RecTriggers    0x00002000  /* Enable recursive triggers */
    ++#define SQLITE_ForeignKeys    0x00004000  /* Enforce foreign key constraints  */
    ++#define SQLITE_AutoIndex      0x00008000  /* Enable automatic indexes */
    ++#define SQLITE_LoadExtension  0x00010000  /* Enable load_extension */
    ++#define SQLITE_LoadExtFunc    0x00020000  /* Enable load_extension() SQL func */
    ++#define SQLITE_EnableTrigger  0x00040000  /* True to enable triggers */
    ++#define SQLITE_DeferFKs       0x00080000  /* Defer all FK constraints */
    ++#define SQLITE_QueryOnly      0x00100000  /* Disable database changes */
    ++#define SQLITE_CellSizeCk     0x00200000  /* Check btree cell sizes on load */
    ++#define SQLITE_Fts3Tokenizer  0x00400000  /* Enable fts3_tokenizer(2) */
    ++#define SQLITE_EnableQPSG     0x00800000  /* Query Planner Stability Guarantee*/
    ++#define SQLITE_TriggerEQP     0x01000000  /* Show trigger EXPLAIN QUERY PLAN */
    ++
    ++/* Flags used only if debugging */
    ++#ifdef SQLITE_DEBUG
    ++#define SQLITE_SqlTrace       0x08000000  /* Debug print SQL as it executes */
    ++#define SQLITE_VdbeListing    0x10000000  /* Debug listings of VDBE programs */
    ++#define SQLITE_VdbeTrace      0x20000000  /* True to trace VDBE execution */
    ++#define SQLITE_VdbeAddopTrace 0x40000000  /* Trace sqlite3VdbeAddOp() calls */
    ++#define SQLITE_VdbeEQP        0x80000000  /* Debug EXPLAIN QUERY PLAN */
    ++#endif
    + 
    ++/*
    ++** Allowed values for sqlite3.mDbFlags
    ++*/
    ++#define DBFLAG_SchemaChange   0x0001  /* Uncommitted Hash table changes */
    ++#define DBFLAG_PreferBuiltin  0x0002  /* Preference to built-in funcs */
    ++#define DBFLAG_Vacuum         0x0004  /* Currently in a VACUUM */
    + 
    + /*
    + ** Bits of the sqlite3.dbOptFlags field that are used by the
    +@@ -11846,26 +15405,22 @@ struct sqlite3 {
    + #define SQLITE_ColumnCache    0x0002   /* Column cache */
    + #define SQLITE_GroupByOrder   0x0004   /* GROUPBY cover of ORDERBY */
    + #define SQLITE_FactorOutConst 0x0008   /* Constant factoring */
    +-/*                not used    0x0010   // Was: SQLITE_IdxRealAsInt */
    +-#define SQLITE_DistinctOpt    0x0020   /* DISTINCT using indexes */
    +-#define SQLITE_CoverIdxScan   0x0040   /* Covering index scans */
    +-#define SQLITE_OrderByIdxJoin 0x0080   /* ORDER BY of joins via index */
    +-#define SQLITE_SubqCoroutine  0x0100   /* Evaluate subqueries as coroutines */
    +-#define SQLITE_Transitive     0x0200   /* Transitive constraints */
    +-#define SQLITE_OmitNoopJoin   0x0400   /* Omit unused tables in joins */
    ++#define SQLITE_DistinctOpt    0x0010   /* DISTINCT using indexes */
    ++#define SQLITE_CoverIdxScan   0x0020   /* Covering index scans */
    ++#define SQLITE_OrderByIdxJoin 0x0040   /* ORDER BY of joins via index */
    ++#define SQLITE_Transitive     0x0080   /* Transitive constraints */
    ++#define SQLITE_OmitNoopJoin   0x0100   /* Omit unused tables in joins */
    ++#define SQLITE_CountOfView    0x0200   /* The count-of-view optimization */
    ++#define SQLITE_CursorHints    0x0400   /* Add OP_CursorHint opcodes */
    + #define SQLITE_Stat34         0x0800   /* Use STAT3 or STAT4 data */
    ++   /* TH3 expects the Stat34  ^^^^^^ value to be 0x0800.  Don't change it */
    + #define SQLITE_AllOpts        0xffff   /* All optimizations */
    + 
    + /*
    + ** Macros for testing whether or not optimizations are enabled or disabled.
    + */
    +-#ifndef SQLITE_OMIT_BUILTIN_TEST
    + #define OptimizationDisabled(db, mask)  (((db)->dbOptFlags&(mask))!=0)
    + #define OptimizationEnabled(db, mask)   (((db)->dbOptFlags&(mask))==0)
    +-#else
    +-#define OptimizationDisabled(db, mask)  0
    +-#define OptimizationEnabled(db, mask)   1
    +-#endif
    + 
    + /*
    + ** Return true if it OK to factor constant expressions into the initialization
    +@@ -11887,28 +15442,33 @@ struct sqlite3 {
    + 
    + /*
    + ** Each SQL function is defined by an instance of the following
    +-** structure.  A pointer to this structure is stored in the sqlite.aFunc
    +-** hash table.  When multiple functions have the same name, the hash table
    +-** points to a linked list of these structures.
    ++** structure.  For global built-in functions (ex: substr(), max(), count())
    ++** a pointer to this structure is held in the sqlite3BuiltinFunctions object.
    ++** For per-connection application-defined functions, a pointer to this
    ++** structure is held in the db->aHash hash table.
    ++**
    ++** The u.pHash field is used by the global built-ins.  The u.pDestructor
    ++** field is used by per-connection app-def functions.
    + */
    + struct FuncDef {
    +-  i16 nArg;            /* Number of arguments.  -1 means unlimited */
    ++  i8 nArg;             /* Number of arguments.  -1 means unlimited */
    +   u16 funcFlags;       /* Some combination of SQLITE_FUNC_* */
    +   void *pUserData;     /* User data parameter */
    +   FuncDef *pNext;      /* Next function with same name */
    +-  void (*xFunc)(sqlite3_context*,int,sqlite3_value**); /* Regular function */
    +-  void (*xStep)(sqlite3_context*,int,sqlite3_value**); /* Aggregate step */
    +-  void (*xFinalize)(sqlite3_context*);                /* Aggregate finalizer */
    +-  char *zName;         /* SQL name of the function. */
    +-  FuncDef *pHash;      /* Next with a different name but the same hash */
    +-  FuncDestructor *pDestructor;   /* Reference counted destructor function */
    ++  void (*xSFunc)(sqlite3_context*,int,sqlite3_value**); /* func or agg-step */
    ++  void (*xFinalize)(sqlite3_context*);                  /* Agg finalizer */
    ++  const char *zName;   /* SQL name of the function. */
    ++  union {
    ++    FuncDef *pHash;      /* Next with a different name but the same hash */
    ++    FuncDestructor *pDestructor;   /* Reference counted destructor function */
    ++  } u;
    + };
    + 
    + /*
    + ** This structure encapsulates a user-function destructor callback (as
    + ** configured using create_function_v2()) and a reference counter. When
    + ** create_function_v2() is called to create a function with a destructor,
    +-** a single object of this type is allocated. FuncDestructor.nRef is set to 
    ++** a single object of this type is allocated. FuncDestructor.nRef is set to
    + ** the number of FuncDef objects created (either 1 or 3, depending on whether
    + ** or not the specified encoding is SQLITE_ANY). The FuncDef.pDestructor
    + ** member of each of the new FuncDef objects is set to point to the allocated
    +@@ -11926,8 +15486,16 @@ struct FuncDestructor {
    + 
    + /*
    + ** Possible values for FuncDef.flags.  Note that the _LENGTH and _TYPEOF
    +-** values must correspond to OPFLAG_LENGTHARG and OPFLAG_TYPEOFARG.  There
    ++** values must correspond to OPFLAG_LENGTHARG and OPFLAG_TYPEOFARG.  And
    ++** SQLITE_FUNC_CONSTANT must be the same as SQLITE_DETERMINISTIC.  There
    + ** are assert() statements in the code to verify this.
    ++**
    ++** Value constraints (enforced via assert()):
    ++**     SQLITE_FUNC_MINMAX    ==  NC_MinMaxAgg      == SF_MinMaxAgg
    ++**     SQLITE_FUNC_LENGTH    ==  OPFLAG_LENGTHARG
    ++**     SQLITE_FUNC_TYPEOF    ==  OPFLAG_TYPEOFARG
    ++**     SQLITE_FUNC_CONSTANT  ==  SQLITE_DETERMINISTIC from the API
    ++**     SQLITE_FUNC_ENCMASK   depends on SQLITE_UTF* macros in the API
    + */
    + #define SQLITE_FUNC_ENCMASK  0x0003 /* SQLITE_UTF8, SQLITE_UTF16BE or UTF16LE */
    + #define SQLITE_FUNC_LIKE     0x0004 /* Candidate for the LIKE optimization */
    +@@ -11943,16 +15511,18 @@ struct FuncDestructor {
    + #define SQLITE_FUNC_MINMAX   0x1000 /* True for min() and max() aggregates */
    + #define SQLITE_FUNC_SLOCHNG  0x2000 /* "Slow Change". Value constant during a
    +                                     ** single query - might change over time */
    ++#define SQLITE_FUNC_AFFINITY 0x4000 /* Built-in affinity() function */
    ++#define SQLITE_FUNC_OFFSET   0x8000 /* Built-in sqlite_offset() function */
    + 
    + /*
    + ** The following three macros, FUNCTION(), LIKEFUNC() and AGGREGATE() are
    + ** used to create the initializers for the FuncDef structures.
    + **
    + **   FUNCTION(zName, nArg, iArg, bNC, xFunc)
    +-**     Used to create a scalar function definition of a function zName 
    ++**     Used to create a scalar function definition of a function zName
    + **     implemented by C function xFunc that accepts nArg arguments. The
    + **     value passed as iArg is cast to a (void*) and made available
    +-**     as the user-data (sqlite3_user_data()) for the function. If 
    ++**     as the user-data (sqlite3_user_data()) for the function. If
    + **     argument bNC is true, then the SQLITE_FUNC_NEEDCOLL flag is set.
    + **
    + **   VFUNCTION(zName, nArg, iArg, bNC, xFunc)
    +@@ -11962,7 +15532,14 @@ struct FuncDestructor {
    + **     Like FUNCTION except it omits the SQLITE_FUNC_CONSTANT flag and
    + **     adds the SQLITE_FUNC_SLOCHNG flag.  Used for date & time functions
    + **     and functions like sqlite_version() that can change, but not during
    +-**     a single query.
    ++**     a single query.  The iArg is ignored.  The user-data is always set
    ++**     to a NULL pointer.  The bNC parameter is not used.
    ++**
    ++**   PURE_DATE(zName, nArg, iArg, bNC, xFunc)
    ++**     Used for "pure" date/time functions, this macro is like DFUNCTION
    ++**     except that it does set the SQLITE_FUNC_CONSTANT flags.  iArg is
    ++**     ignored and the user-data for these functions is set to an 
    ++**     arbitrary non-NULL pointer.  The bNC parameter is not used.
    + **
    + **   AGGREGATE(zName, nArg, iArg, bNC, xStep, xFinal)
    + **     Used to create an aggregate function definition implemented by
    +@@ -11971,8 +15548,8 @@ struct FuncDestructor {
    + **     FUNCTION().
    + **
    + **   LIKEFUNC(zName, nArg, pArg, flags)
    +-**     Used to create a scalar function definition of a function zName 
    +-**     that accepts nArg arguments and is implemented by a call to C 
    ++**     Used to create a scalar function definition of a function zName
    ++**     that accepts nArg arguments and is implemented by a call to C
    + **     function likeFunc. Argument pArg is cast to a (void *) and made
    + **     available as the function user-data (sqlite3_user_data()). The
    + **     FuncDef.flags variable is set to the value passed as the flags
    +@@ -11980,28 +15557,31 @@ struct FuncDestructor {
    + */
    + #define FUNCTION(zName, nArg, iArg, bNC, xFunc) \
    +   {nArg, SQLITE_FUNC_CONSTANT|SQLITE_UTF8|(bNC*SQLITE_FUNC_NEEDCOLL), \
    +-   SQLITE_INT_TO_PTR(iArg), 0, xFunc, 0, 0, #zName, 0, 0}
    ++   SQLITE_INT_TO_PTR(iArg), 0, xFunc, 0, #zName, {0} }
    + #define VFUNCTION(zName, nArg, iArg, bNC, xFunc) \
    +   {nArg, SQLITE_UTF8|(bNC*SQLITE_FUNC_NEEDCOLL), \
    +-   SQLITE_INT_TO_PTR(iArg), 0, xFunc, 0, 0, #zName, 0, 0}
    ++   SQLITE_INT_TO_PTR(iArg), 0, xFunc, 0, #zName, {0} }
    + #define DFUNCTION(zName, nArg, iArg, bNC, xFunc) \
    +-  {nArg, SQLITE_FUNC_SLOCHNG|SQLITE_UTF8|(bNC*SQLITE_FUNC_NEEDCOLL), \
    +-   SQLITE_INT_TO_PTR(iArg), 0, xFunc, 0, 0, #zName, 0, 0}
    ++  {nArg, SQLITE_FUNC_SLOCHNG|SQLITE_UTF8, \
    ++   0, 0, xFunc, 0, #zName, {0} }
    ++#define PURE_DATE(zName, nArg, iArg, bNC, xFunc) \
    ++  {nArg, SQLITE_FUNC_SLOCHNG|SQLITE_UTF8|SQLITE_FUNC_CONSTANT, \
    ++   (void*)&sqlite3Config, 0, xFunc, 0, #zName, {0} }
    + #define FUNCTION2(zName, nArg, iArg, bNC, xFunc, extraFlags) \
    +   {nArg,SQLITE_FUNC_CONSTANT|SQLITE_UTF8|(bNC*SQLITE_FUNC_NEEDCOLL)|extraFlags,\
    +-   SQLITE_INT_TO_PTR(iArg), 0, xFunc, 0, 0, #zName, 0, 0}
    ++   SQLITE_INT_TO_PTR(iArg), 0, xFunc, 0, #zName, {0} }
    + #define STR_FUNCTION(zName, nArg, pArg, bNC, xFunc) \
    +   {nArg, SQLITE_FUNC_SLOCHNG|SQLITE_UTF8|(bNC*SQLITE_FUNC_NEEDCOLL), \
    +-   pArg, 0, xFunc, 0, 0, #zName, 0, 0}
    ++   pArg, 0, xFunc, 0, #zName, }
    + #define LIKEFUNC(zName, nArg, arg, flags) \
    +   {nArg, SQLITE_FUNC_CONSTANT|SQLITE_UTF8|flags, \
    +-   (void *)arg, 0, likeFunc, 0, 0, #zName, 0, 0}
    ++   (void *)arg, 0, likeFunc, 0, #zName, {0} }
    + #define AGGREGATE(zName, nArg, arg, nc, xStep, xFinal) \
    +   {nArg, SQLITE_UTF8|(nc*SQLITE_FUNC_NEEDCOLL), \
    +-   SQLITE_INT_TO_PTR(arg), 0, 0, xStep,xFinal,#zName,0,0}
    ++   SQLITE_INT_TO_PTR(arg), 0, xStep,xFinal,#zName, {0}}
    + #define AGGREGATE2(zName, nArg, arg, nc, xStep, xFinal, extraFlags) \
    +   {nArg, SQLITE_UTF8|(nc*SQLITE_FUNC_NEEDCOLL)|extraFlags, \
    +-   SQLITE_INT_TO_PTR(arg), 0, 0, xStep,xFinal,#zName,0,0}
    ++   SQLITE_INT_TO_PTR(arg), 0, xStep,xFinal,#zName, {0}}
    + 
    + /*
    + ** All current savepoints are stored in a linked list starting at
    +@@ -12043,14 +15623,12 @@ struct Module {
    + ** of this structure.
    + */
    + struct Column {
    +-  char *zName;     /* Name of this column */
    ++  char *zName;     /* Name of this column, \000, then the type */
    +   Expr *pDflt;     /* Default value of this column */
    +-  char *zDflt;     /* Original text of the default value */
    +-  char *zType;     /* Data type for this column */
    +   char *zColl;     /* Collating sequence.  If NULL, use the default */
    +   u8 notNull;      /* An OE_ code for handling a NOT NULL constraint */
    +   char affinity;   /* One of the SQLITE_AFF_... values */
    +-  u8 szEst;        /* Estimated size of this column.  INT==1 */
    ++  u8 szEst;        /* Estimated size of value in this column. sizeof(INT)==1 */
    +   u8 colFlags;     /* Boolean properties.  See COLFLAG_ defines below */
    + };
    + 
    +@@ -12058,6 +15636,7 @@ struct Column {
    + */
    + #define COLFLAG_PRIMKEY  0x0001    /* Column is part of the primary key */
    + #define COLFLAG_HIDDEN   0x0002    /* A hidden column in a virtual table */
    ++#define COLFLAG_HASTYPE  0x0004    /* Type name follows column name */
    + 
    + /*
    + ** A "Collating Sequence" is defined by an instance of the following
    +@@ -12088,7 +15667,7 @@ struct CollSeq {
    + **
    + ** These used to have mnemonic name like 'i' for SQLITE_AFF_INTEGER and
    + ** 't' for SQLITE_AFF_TEXT.  But we can save a little space and improve
    +-** the speed a little by numbering the values consecutively.  
    ++** the speed a little by numbering the values consecutively.
    + **
    + ** But rather than start with 0 or 1, we begin with 'A'.  That way,
    + ** when multiple affinity types are concatenated into a string and
    +@@ -12107,7 +15686,7 @@ struct CollSeq {
    + 
    + /*
    + ** The SQLITE_AFF_MASK values masks off the significant bits of an
    +-** affinity value. 
    ++** affinity value.
    + */
    + #define SQLITE_AFF_MASK     0x47
    + 
    +@@ -12120,6 +15699,7 @@ struct CollSeq {
    + ** operator is NULL.  It is added to certain comparison operators to
    + ** prove that the operands are always NOT NULL.
    + */
    ++#define SQLITE_KEEPNULL     0x08  /* Used by vector == or <> */
    + #define SQLITE_JUMPIFNULL   0x10  /* jumps if either operand is NULL */
    + #define SQLITE_STOREP2      0x20  /* Store result in reg[P2] rather than jump */
    + #define SQLITE_NULLEQ       0x80  /* NULL=NULL */
    +@@ -12127,20 +15707,20 @@ struct CollSeq {
    + 
    + /*
    + ** An object of this type is created for each virtual table present in
    +-** the database schema. 
    ++** the database schema.
    + **
    + ** If the database schema is shared, then there is one instance of this
    + ** structure for each database connection (sqlite3*) that uses the shared
    + ** schema. This is because each database connection requires its own unique
    +-** instance of the sqlite3_vtab* handle used to access the virtual table 
    +-** implementation. sqlite3_vtab* handles can not be shared between 
    +-** database connections, even when the rest of the in-memory database 
    ++** instance of the sqlite3_vtab* handle used to access the virtual table
    ++** implementation. sqlite3_vtab* handles can not be shared between
    ++** database connections, even when the rest of the in-memory database
    + ** schema is shared, as the implementation often stores the database
    + ** connection handle passed to it via the xConnect() or xCreate() method
    + ** during initialization internally. This database connection handle may
    +-** then be used by the virtual table implementation to access real tables 
    +-** within the database. So that they appear as part of the callers 
    +-** transaction, these accesses need to be made via the same database 
    ++** then be used by the virtual table implementation to access real tables
    ++** within the database. So that they appear as part of the callers
    ++** transaction, these accesses need to be made via the same database
    + ** connection as that used to execute SQL operations on the virtual table.
    + **
    + ** All VTable objects that correspond to a single table in a shared
    +@@ -12152,19 +15732,19 @@ struct CollSeq {
    + ** sqlite3_vtab* handle in the compiled query.
    + **
    + ** When an in-memory Table object is deleted (for example when the
    +-** schema is being reloaded for some reason), the VTable objects are not 
    +-** deleted and the sqlite3_vtab* handles are not xDisconnect()ed 
    ++** schema is being reloaded for some reason), the VTable objects are not
    ++** deleted and the sqlite3_vtab* handles are not xDisconnect()ed
    + ** immediately. Instead, they are moved from the Table.pVTable list to
    + ** another linked list headed by the sqlite3.pDisconnect member of the
    +-** corresponding sqlite3 structure. They are then deleted/xDisconnected 
    ++** corresponding sqlite3 structure. They are then deleted/xDisconnected
    + ** next time a statement is prepared using said sqlite3*. This is done
    + ** to avoid deadlock issues involving multiple sqlite3.mutex mutexes.
    + ** Refer to comments above function sqlite3VtabUnlockList() for an
    + ** explanation as to why it is safe to add an entry to an sqlite3.pDisconnect
    + ** list without holding the corresponding sqlite3.mutex mutex.
    + **
    +-** The memory for objects of this type is always allocated by 
    +-** sqlite3DbMalloc(), using the connection handle stored in VTable.db as 
    ++** The memory for objects of this type is always allocated by
    ++** sqlite3DbMalloc(), using the connection handle stored in VTable.db as
    + ** the first argument.
    + */
    + struct VTable {
    +@@ -12191,15 +15771,15 @@ struct Table {
    +   ExprList *pCheck;    /* All CHECK constraints */
    +                        /*   ... also used as column name list in a VIEW */
    +   int tnum;            /* Root BTree page for this table */
    ++  u32 nTabRef;         /* Number of pointers to this Table */
    ++  u32 tabFlags;        /* Mask of TF_* values */
    +   i16 iPKey;           /* If not negative, use aCol[iPKey] as the rowid */
    +   i16 nCol;            /* Number of columns in this table */
    +-  u16 nRef;            /* Number of pointers to this Table */
    +   LogEst nRowLogEst;   /* Estimated rows in table - from sqlite_stat1 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
    +   int addColOffset;    /* Offset in CREATE TABLE stmt to add a new column */
    +@@ -12217,21 +15797,23 @@ struct Table {
    + /*
    + ** Allowed values for Table.tabFlags.
    + **
    +-** TF_OOOHidden applies to virtual tables that have hidden columns that are
    ++** TF_OOOHidden applies to tables or view that have hidden columns that are
    + ** followed by non-hidden columns.  Example:  "CREATE VIRTUAL TABLE x USING
    + ** vtab1(a HIDDEN, b);".  Since "b" is a non-hidden column but "a" is hidden,
    + ** the TF_OOOHidden attribute would apply in this case.  Such tables require
    + ** special handling during INSERT processing.
    + */
    +-#define TF_Readonly        0x01    /* Read-only system table */
    +-#define TF_Ephemeral       0x02    /* An ephemeral table */
    +-#define TF_HasPrimaryKey   0x04    /* Table has a primary key */
    +-#define TF_Autoincrement   0x08    /* Integer primary key is autoincrement */
    +-#define TF_Virtual         0x10    /* Is a virtual table */
    +-#define TF_WithoutRowid    0x20    /* No rowid.  PRIMARY KEY is the key */
    +-#define TF_NoVisibleRowid  0x40    /* No user-visible "rowid" column */
    +-#define TF_OOOHidden       0x80    /* Out-of-Order hidden columns */
    +-
    ++#define TF_Readonly        0x0001    /* Read-only system table */
    ++#define TF_Ephemeral       0x0002    /* An ephemeral table */
    ++#define TF_HasPrimaryKey   0x0004    /* Table has a primary key */
    ++#define TF_Autoincrement   0x0008    /* Integer primary key is autoincrement */
    ++#define TF_HasStat1        0x0010    /* nRowLogEst set from sqlite_stat1 */
    ++#define TF_WithoutRowid    0x0020    /* No rowid.  PRIMARY KEY is the key */
    ++#define TF_NoVisibleRowid  0x0040    /* No user-visible "rowid" column */
    ++#define TF_OOOHidden       0x0080    /* Out-of-Order hidden columns */
    ++#define TF_StatsUsed       0x0100    /* Query planner decisions affected by
    ++                                     ** Index.aiRowLogEst[] values */
    ++#define TF_HasNotNull      0x0200    /* Contains NOT NULL constraints */
    + 
    + /*
    + ** Test to see whether or not a table is a virtual table.  This is
    +@@ -12239,13 +15821,29 @@ struct Table {
    + ** table support is omitted from the build.
    + */
    + #ifndef SQLITE_OMIT_VIRTUALTABLE
    +-#  define IsVirtual(X)      (((X)->tabFlags & TF_Virtual)!=0)
    +-#  define IsHiddenColumn(X) (((X)->colFlags & COLFLAG_HIDDEN)!=0)
    ++#  define IsVirtual(X)      ((X)->nModuleArg)
    + #else
    + #  define IsVirtual(X)      0
    +-#  define IsHiddenColumn(X) 0
    + #endif
    + 
    ++/*
    ++** Macros to determine if a column is hidden.  IsOrdinaryHiddenColumn()
    ++** only works for non-virtual tables (ordinary tables and views) and is
    ++** always false unless SQLITE_ENABLE_HIDDEN_COLUMNS is defined.  The
    ++** IsHiddenColumn() macro is general purpose.
    ++*/
    ++#if defined(SQLITE_ENABLE_HIDDEN_COLUMNS)
    ++#  define IsHiddenColumn(X)         (((X)->colFlags & COLFLAG_HIDDEN)!=0)
    ++#  define IsOrdinaryHiddenColumn(X) (((X)->colFlags & COLFLAG_HIDDEN)!=0)
    ++#elif !defined(SQLITE_OMIT_VIRTUALTABLE)
    ++#  define IsHiddenColumn(X)         (((X)->colFlags & COLFLAG_HIDDEN)!=0)
    ++#  define IsOrdinaryHiddenColumn(X) 0
    ++#else
    ++#  define IsHiddenColumn(X)         0
    ++#  define IsOrdinaryHiddenColumn(X) 0
    ++#endif
    ++
    ++
    + /* Does the table have a rowid */
    + #define HasRowid(X)     (((X)->tabFlags & TF_WithoutRowid)==0)
    + #define VisibleRowid(X) (((X)->tabFlags & TF_NoVisibleRowid)==0)
    +@@ -12316,7 +15914,7 @@ struct FKey {
    + ** key is set to NULL.  CASCADE means that a DELETE or UPDATE of the
    + ** referenced table row is propagated into the row that holds the
    + ** foreign key.
    +-** 
    ++**
    + ** The following symbolic values are used to record which type
    + ** of action to take.
    + */
    +@@ -12337,7 +15935,7 @@ struct FKey {
    + 
    + /*
    + ** An instance of the following structure is passed as the first
    +-** argument to sqlite3VdbeKeyCompare and is used to control the 
    ++** argument to sqlite3VdbeKeyCompare and is used to control the
    + ** comparison of the two index keys.
    + **
    + ** Note that aSortOrder[] and aColl[] have nField+1 slots.  There
    +@@ -12347,17 +15945,16 @@ struct FKey {
    + struct KeyInfo {
    +   u32 nRef;           /* Number of references to this KeyInfo object */
    +   u8 enc;             /* Text encoding - one of the SQLITE_UTF* values */
    +-  u16 nField;         /* Number of key columns in the index */
    +-  u16 nXField;        /* Number of columns beyond the key columns */
    ++  u16 nKeyField;      /* Number of key columns in the index */
    ++  u16 nAllField;      /* Total columns, including key plus others */
    +   sqlite3 *db;        /* The database connection */
    +   u8 *aSortOrder;     /* Sort order for each column. */
    +   CollSeq *aColl[1];  /* Collating sequence for each term of the key */
    + };
    + 
    + /*
    +-** An instance of the following structure holds information about a
    +-** single index record that has already been parsed out into individual
    +-** values.
    ++** This object holds a record which has been parsed out into individual
    ++** fields, for the purposes of doing a comparison.
    + **
    + ** A record is an object that contains one or more fields of data.
    + ** Records are used to store the content of a table row and to store
    +@@ -12365,20 +15962,40 @@ struct KeyInfo {
    + ** the OP_MakeRecord opcode of the VDBE and is disassembled by the
    + ** OP_Column opcode.
    + **
    +-** This structure holds a record that has already been disassembled
    +-** into its constituent fields.
    +-**
    +-** The r1 and r2 member variables are only used by the optimized comparison
    +-** functions vdbeRecordCompareInt() and vdbeRecordCompareString().
    ++** An instance of this object serves as a "key" for doing a search on
    ++** an index b+tree. The goal of the search is to find the entry that
    ++** is closed to the key described by this object.  This object might hold
    ++** just a prefix of the key.  The number of fields is given by
    ++** pKeyInfo->nField.
    ++**
    ++** The r1 and r2 fields are the values to return if this key is less than
    ++** or greater than a key in the btree, respectively.  These are normally
    ++** -1 and +1 respectively, but might be inverted to +1 and -1 if the b-tree
    ++** is in DESC order.
    ++**
    ++** The key comparison functions actually return default_rc when they find
    ++** an equals comparison.  default_rc can be -1, 0, or +1.  If there are
    ++** multiple entries in the b-tree with the same key (when only looking
    ++** at the first pKeyInfo->nFields,) then default_rc can be set to -1 to
    ++** cause the search to find the last match, or +1 to cause the search to
    ++** find the first match.
    ++**
    ++** The key comparison functions will set eqSeen to true if they ever
    ++** get and equal results when comparing this structure to a b-tree record.
    ++** When default_rc!=0, the search might end up on the record immediately
    ++** before the first match or immediately after the last match.  The
    ++** eqSeen field will indicate whether or not an exact match exists in the
    ++** b-tree.
    + */
    + struct UnpackedRecord {
    +   KeyInfo *pKeyInfo;  /* Collation and sort-order information */
    ++  Mem *aMem;          /* Values */
    +   u16 nField;         /* Number of entries in apMem[] */
    +   i8 default_rc;      /* Comparison result if keys are equal */
    +   u8 errCode;         /* Error detected by xRecordCompare (CORRUPT or NOMEM) */
    +-  Mem *aMem;          /* Values */
    +-  int r1;             /* Value to return if (lhs > rhs) */
    +-  int r2;             /* Value to return if (rhs < lhs) */
    ++  i8 r1;              /* Value to return if (lhs < rhs) */
    ++  i8 r2;              /* Value to return if (lhs > rhs) */
    ++  u8 eqSeen;          /* True if an equality comparison has been seen */
    + };
    + 
    + 
    +@@ -12396,7 +16013,7 @@ struct UnpackedRecord {
    + ** In the Table structure describing Ex1, nCol==3 because there are
    + ** three columns in the table.  In the Index structure describing
    + ** Ex2, nColumn==2 since 2 of the 3 columns of Ex1 are indexed.
    +-** The value of aiColumn is {2, 0}.  aiColumn[0]==2 because the 
    ++** The value of aiColumn is {2, 0}.  aiColumn[0]==2 because the
    + ** first column to be indexed (c3) has an index of 2 in Ex1.aCol[].
    + ** The second column to be indexed (c1) has an index of 0 in
    + ** Ex1.aCol[], hence Ex2.aiColumn[1]==0.
    +@@ -12404,7 +16021,7 @@ struct UnpackedRecord {
    + ** The Index.onError field determines whether or not the indexed columns
    + ** must be unique and what to do if they are not.  When Index.onError=OE_None,
    + ** it means this is not a unique index.  Otherwise it is a unique index
    +-** and the value of Index.onError indicate the which conflict resolution 
    ++** and the value of Index.onError indicate the which conflict resolution
    + ** algorithm to employ whenever an attempt is made to insert a non-unique
    + ** element.
    + **
    +@@ -12425,7 +16042,7 @@ struct Index {
    +   Index *pNext;            /* The next index associated with the same table */
    +   Schema *pSchema;         /* Schema containing this index */
    +   u8 *aSortOrder;          /* for each column: True==DESC, False==ASC */
    +-  char **azColl;           /* Array of collation sequence names for index */
    ++  const char **azColl;     /* Array of collation sequence names for index */
    +   Expr *pPartIdxWhere;     /* WHERE clause for partial indices */
    +   ExprList *aColExpr;      /* Column expressions */
    +   int tnum;                /* DB Page containing root of this index */
    +@@ -12439,6 +16056,8 @@ struct Index {
    +   unsigned isResized:1;    /* True if resizeIndexObject() has been called */
    +   unsigned isCovering:1;   /* True if this is a covering index */
    +   unsigned noSkipScan:1;   /* Do not try to use skip-scan if true */
    ++  unsigned hasStat1:1;     /* aiRowLogEst values come from sqlite_stat1 */
    ++  unsigned bNoQuery:1;     /* Do not use this index to optimize queries */
    + #ifdef SQLITE_ENABLE_STAT3_OR_STAT4
    +   int nSample;             /* Number of elements in aSample[] */
    +   int nSampleCol;          /* Size of IndexSample.anEq[] and so on */
    +@@ -12469,7 +16088,7 @@ struct Index {
    + #define XN_EXPR      (-2)     /* Indexed column is an expression */
    + 
    + /*
    +-** Each sample stored in the sqlite_stat3 table is represented in memory 
    ++** 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
    + ** analyze.c source file for additional information.
    + */
    +@@ -12564,9 +16183,9 @@ typedef int ynVar;
    + ** to represent the greater-than-or-equal-to operator in the expression
    + ** tree.
    + **
    +-** If the expression is an SQL literal (TK_INTEGER, TK_FLOAT, TK_BLOB, 
    ++** If the expression is an SQL literal (TK_INTEGER, TK_FLOAT, TK_BLOB,
    + ** or TK_STRING), then Expr.token contains the text of the SQL literal. If
    +-** the expression is a variable (TK_VARIABLE), then Expr.token contains the 
    ++** the expression is a variable (TK_VARIABLE), then Expr.token contains the
    + ** variable name. Finally, if the expression is an SQL function (TK_FUNCTION),
    + ** then Expr.token contains the name of the function.
    + **
    +@@ -12577,7 +16196,7 @@ typedef int ynVar;
    + ** a CASE expression or an IN expression of the form "<lhs> IN (<y>, <z>...)".
    + ** Expr.x.pSelect is used if the expression is a sub-select or an expression of
    + ** the form "<lhs> IN (SELECT ...)". If the EP_xIsSelect bit is set in the
    +-** Expr.flags mask, then Expr.x.pSelect is valid. Otherwise, Expr.x.pList is 
    ++** Expr.flags mask, then Expr.x.pSelect is valid. Otherwise, Expr.x.pList is
    + ** valid.
    + **
    + ** An expression of the form ID or ID.ID refers to a column in a table.
    +@@ -12588,8 +16207,8 @@ typedef int ynVar;
    + ** value is also stored in the Expr.iAgg column in the aggregate so that
    + ** it can be accessed after all aggregates are computed.
    + **
    +-** If the expression is an unbound variable marker (a question mark 
    +-** character '?' in the original SQL) then the Expr.iTable holds the index 
    ++** If the expression is an unbound variable marker (a question mark
    ++** character '?' in the original SQL) then the Expr.iTable holds the index
    + ** number for that variable.
    + **
    + ** If the expression is a subquery then Expr.iColumn holds an integer
    +@@ -12628,7 +16247,7 @@ struct Expr {
    + 
    +   /* If the EP_TokenOnly flag is set in the Expr.flags mask, then no
    +   ** space is allocated for the fields below this point. An attempt to
    +-  ** access them will result in a segfault or malfunction. 
    ++  ** access them will result in a segfault or malfunction.
    +   *********************************************************************/
    + 
    +   Expr *pLeft;           /* Left subnode */
    +@@ -12649,16 +16268,19 @@ struct Expr {
    +   int iTable;            /* TK_COLUMN: cursor number of table holding column
    +                          ** TK_REGISTER: register number
    +                          ** TK_TRIGGER: 1 -> new, 0 -> old
    +-                         ** EP_Unlikely:  134217728 times likelihood */
    ++                         ** EP_Unlikely:  134217728 times likelihood
    ++                         ** TK_SELECT: 1st register of result vector */
    +   ynVar iColumn;         /* TK_COLUMN: column index.  -1 for rowid.
    +-                         ** TK_VARIABLE: variable number (always >= 1). */
    ++                         ** TK_VARIABLE: variable number (always >= 1).
    ++                         ** TK_SELECT_COLUMN: column of the result vector */
    +   i16 iAgg;              /* Which entry in pAggInfo->aCol[] or ->aFunc[] */
    +   i16 iRightJoinTable;   /* If EP_FromJoin, the right table of the join */
    +   u8 op2;                /* TK_REGISTER: original value of Expr.op
    +                          ** TK_COLUMN: the value of p5 for OP_Column
    +                          ** TK_AGG_FUNCTION: nesting depth */
    +   AggInfo *pAggInfo;     /* Used by TK_AGG_COLUMN and TK_AGG_FUNCTION */
    +-  Table *pTab;           /* Table for TK_COLUMN expressions. */
    ++  Table *pTab;           /* Table for TK_COLUMN expressions.  Can be NULL
    ++                         ** for a column of an index on an expression */
    + };
    + 
    + /*
    +@@ -12666,8 +16288,8 @@ struct Expr {
    + */
    + #define EP_FromJoin  0x000001 /* Originates in ON/USING clause of outer join */
    + #define EP_Agg       0x000002 /* Contains one or more aggregate functions */
    +-#define EP_Resolved  0x000004 /* IDs have been resolved to COLUMNs */
    +-#define EP_Error     0x000008 /* Expression contains one or more errors */
    ++#define EP_HasFunc   0x000004 /* Contains one or more functions of any kind */
    ++                  /* 0x000008 // available for use */
    + #define EP_Distinct  0x000010 /* Aggregate function with DISTINCT keyword */
    + #define EP_VarSelect 0x000020 /* pSelect is correlated, not constant */
    + #define EP_DblQuoted 0x000040 /* token.z was originally in "..." */
    +@@ -12687,14 +16309,16 @@ struct Expr {
    + #define EP_CanBeNull 0x100000 /* Can be null despite NOT NULL constraint */
    + #define EP_Subquery  0x200000 /* Tree contains a TK_SELECT operator */
    + #define EP_Alias     0x400000 /* Is an alias for a result set column */
    ++#define EP_Leaf      0x800000 /* Expr.pLeft, .pRight, .u.pSelect all NULL */
    + 
    + /*
    +-** Combinations of two or more EP_* flags
    ++** The EP_Propagate mask is a set of properties that automatically propagate
    ++** upwards into parent nodes.
    + */
    +-#define EP_Propagate (EP_Collate|EP_Subquery) /* Propagate these bits up tree */
    ++#define EP_Propagate (EP_Collate|EP_Subquery|EP_HasFunc)
    + 
    + /*
    +-** These macros can be used to test, set, or clear bits in the 
    ++** These macros can be used to test, set, or clear bits in the
    + ** Expr.flags field.
    + */
    + #define ExprHasProperty(E,P)     (((E)->flags&(P))!=0)
    +@@ -12713,8 +16337,8 @@ struct Expr {
    + #endif
    + 
    + /*
    +-** Macros to determine the number of bytes required by a normal Expr 
    +-** struct, an Expr struct with the EP_Reduced flag set in Expr.flags 
    ++** Macros to determine the number of bytes required by a normal Expr
    ++** struct, an Expr struct with the EP_Reduced flag set in Expr.flags
    + ** and an Expr struct with the EP_TokenOnly flag set.
    + */
    + #define EXPR_FULLSIZE           sizeof(Expr)           /* Full size */
    +@@ -12722,7 +16346,7 @@ struct Expr {
    + #define EXPR_TOKENONLYSIZE      offsetof(Expr,pLeft)   /* Fewer features */
    + 
    + /*
    +-** Flags passed to the sqlite3ExprDup() function. See the header comment 
    ++** Flags passed to the sqlite3ExprDup() function. See the header comment
    + ** above sqlite3ExprDup() for details.
    + */
    + #define EXPRDUP_REDUCE         0x0001  /* Used reduced-size Expr nodes */
    +@@ -12746,7 +16370,7 @@ struct Expr {
    + struct ExprList {
    +   int nExpr;             /* Number of expressions on the list */
    +   struct ExprList_item { /* For each expression in the list */
    +-    Expr *pExpr;            /* The list of expressions */
    ++    Expr *pExpr;            /* The parse tree for this expression */
    +     char *zName;            /* Token associated with this expression */
    +     char *zSpan;            /* Original text of the expression */
    +     u8 sortOrder;           /* 1 for DESC or 0 for ASC */
    +@@ -12760,18 +16384,7 @@ struct ExprList {
    +       } x;
    +       int iConstExprReg;      /* Register in which Expr value is cached */
    +     } u;
    +-  } *a;                  /* Alloc a power of two greater or equal to nExpr */
    +-};
    +-
    +-/*
    +-** An instance of this structure is used by the parser to record both
    +-** the parse tree for an expression and the span of input text for an
    +-** expression.
    +-*/
    +-struct ExprSpan {
    +-  Expr *pExpr;          /* The expression parse tree */
    +-  const char *zStart;   /* First character of input text */
    +-  const char *zEnd;     /* One character past the end of input text */
    ++  } a[1];                  /* One slot for each expression in the list */
    + };
    + 
    + /*
    +@@ -12804,7 +16417,11 @@ struct IdList {
    + ** tables in a join to 32 instead of 64.  But it also reduces the size
    + ** of the library by 738 bytes on ix86.
    + */
    +-typedef u64 Bitmask;
    ++#ifdef SQLITE_BITMASK_TYPE
    ++  typedef SQLITE_BITMASK_TYPE Bitmask;
    ++#else
    ++  typedef u64 Bitmask;
    ++#endif
    + 
    + /*
    + ** The number of bits in a Bitmask.  "BMS" means "BitMask Size".
    +@@ -12816,6 +16433,7 @@ typedef u64 Bitmask;
    + */
    + #define MASKBIT(n)   (((Bitmask)1)<<(n))
    + #define MASKBIT32(n) (((unsigned int)1)<<(n))
    ++#define ALLBITS      ((Bitmask)-1)
    + 
    + /*
    + ** The following structure describes the FROM clause of a SELECT statement.
    +@@ -12850,7 +16468,7 @@ struct SrcList {
    +     int regReturn;    /* Register holding return address of addrFillSub */
    +     int regResult;    /* Registers holding results of a co-routine */
    +     struct {
    +-      u8 jointype;      /* Type of join between this able and the previous */
    ++      u8 jointype;      /* Type of join between this table and the previous */
    +       unsigned notIndexed :1;    /* True if there is a NOT INDEXED clause */
    +       unsigned isIndexedBy :1;   /* True if there is an INDEXED BY clause */
    +       unsigned isTabFunc :1;     /* True if table-valued-function syntax */
    +@@ -12888,22 +16506,28 @@ struct SrcList {
    + /*
    + ** Flags appropriate for the wctrlFlags parameter of sqlite3WhereBegin()
    + ** and the WhereInfo.wctrlFlags member.
    ++**
    ++** Value constraints (enforced via assert()):
    ++**     WHERE_USE_LIMIT  == SF_FixedLimit
    + */
    + #define WHERE_ORDERBY_NORMAL   0x0000 /* No-op */
    + #define WHERE_ORDERBY_MIN      0x0001 /* ORDER BY processing for min() func */
    + #define WHERE_ORDERBY_MAX      0x0002 /* ORDER BY processing for max() func */
    + #define WHERE_ONEPASS_DESIRED  0x0004 /* Want to do one-pass UPDATE/DELETE */
    +-#define WHERE_DUPLICATES_OK    0x0008 /* Ok to return a row more than once */
    +-#define WHERE_OMIT_OPEN_CLOSE  0x0010 /* Table cursors are already open */
    +-#define WHERE_FORCE_TABLE      0x0020 /* Do not use an index-only search */
    +-#define WHERE_ONETABLE_ONLY    0x0040 /* Only code the 1st table in pTabList */
    +-#define WHERE_NO_AUTOINDEX     0x0080 /* Disallow automatic indexes */
    +-#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 */
    +-#define WHERE_ONEPASS_MULTIROW 0x2000 /* ONEPASS is ok with multiple rows */
    ++#define WHERE_ONEPASS_MULTIROW 0x0008 /* ONEPASS is ok with multiple rows */
    ++#define WHERE_DUPLICATES_OK    0x0010 /* Ok to return a row more than once */
    ++#define WHERE_OR_SUBCLAUSE     0x0020 /* Processing a sub-WHERE as part of
    ++                                      ** the OR optimization  */
    ++#define WHERE_GROUPBY          0x0040 /* pOrderBy is really a GROUP BY */
    ++#define WHERE_DISTINCTBY       0x0080 /* pOrderby is really a DISTINCT clause */
    ++#define WHERE_WANT_DISTINCT    0x0100 /* All output needs to be distinct */
    ++#define WHERE_SORTBYGROUP      0x0200 /* Support sqlite3WhereIsSorted() */
    ++#define WHERE_SEEK_TABLE       0x0400 /* Do not defer seeks on main table */
    ++#define WHERE_ORDERBY_LIMIT    0x0800 /* ORDERBY+LIMIT on the inner loop */
    ++#define WHERE_SEEK_UNIQ_TABLE  0x1000 /* Do not defer seeks if unique */
    ++                        /*     0x2000    not currently used */
    ++#define WHERE_USE_LIMIT        0x4000 /* Use the LIMIT in cost estimates */
    ++                        /*     0x8000    not currently used */
    + 
    + /* Allowed return values from sqlite3WhereIsDistinct()
    + */
    +@@ -12921,12 +16545,12 @@ struct SrcList {
    + ** pEList corresponds to the result set of a SELECT and is NULL for
    + ** other statements.
    + **
    +-** NameContexts can be nested.  When resolving names, the inner-most 
    ++** NameContexts can be nested.  When resolving names, the inner-most
    + ** context is searched first.  If no match is found, the next outer
    + ** context is checked.  If there is still no match, the next context
    + ** is checked.  This process continues until either a match is found
    + ** or all contexts are check.  When a match is found, the nRef member of
    +-** the context containing the match is incremented. 
    ++** the context containing the match is incremented.
    + **
    + ** Each subquery gets a new NameContext.  The pNext field points to the
    + ** NameContext in the parent query.  Thus the process of scanning the
    +@@ -12947,17 +16571,20 @@ struct NameContext {
    + /*
    + ** Allowed values for the NameContext, ncFlags field.
    + **
    +-** Note:  NC_MinMaxAgg must have the same value as SF_MinMaxAgg and
    +-** SQLITE_FUNC_MINMAX.
    +-** 
    ++** Value constraints (all checked via assert()):
    ++**    NC_HasAgg    == SF_HasAgg
    ++**    NC_MinMaxAgg == SF_MinMaxAgg == SQLITE_FUNC_MINMAX
    ++**
    + */
    + #define NC_AllowAgg  0x0001  /* Aggregate functions are allowed here */
    +-#define NC_HasAgg    0x0002  /* One or more aggregate functions seen */
    ++#define NC_PartIdx   0x0002  /* True if resolving a partial index WHERE */
    + #define NC_IsCheck   0x0004  /* True if resolving names in a CHECK constraint */
    + #define NC_InAggFunc 0x0008  /* True if analyzing arguments to an agg func */
    +-#define NC_PartIdx   0x0010  /* True if resolving a partial index WHERE */
    ++#define NC_HasAgg    0x0010  /* One or more aggregate functions seen */
    + #define NC_IdxExpr   0x0020  /* True if resolving columns of CREATE INDEX */
    ++#define NC_VarSelect 0x0040  /* A correlated subquery has been seen */
    + #define NC_MinMaxAgg 0x1000  /* min/max aggregates seen.  See note above */
    ++#define NC_Complex   0x2000  /* True if a function or subquery seen */
    + 
    + /*
    + ** An instance of the following structure contains all information
    +@@ -12982,13 +16609,13 @@ struct NameContext {
    + struct Select {
    +   ExprList *pEList;      /* The fields of the result */
    +   u8 op;                 /* One of: TK_UNION TK_ALL TK_INTERSECT TK_EXCEPT */
    +-  u16 selFlags;          /* Various SF_* values */
    ++  LogEst nSelectRow;     /* Estimated number of result rows */
    ++  u32 selFlags;          /* Various SF_* values */
    +   int iLimit, iOffset;   /* Memory registers holding LIMIT & OFFSET counters */
    + #if SELECTTRACE_ENABLED
    +   char zSelName[12];     /* Symbolic name of this SELECT use for debugging */
    + #endif
    +   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 */
    +   ExprList *pGroupBy;    /* The GROUP BY clause */
    +@@ -12997,29 +16624,37 @@ struct Select {
    +   Select *pPrior;        /* Prior select in a compound select statement */
    +   Select *pNext;         /* Next select to the left in a compound */
    +   Expr *pLimit;          /* LIMIT expression. NULL means not used. */
    +-  Expr *pOffset;         /* OFFSET expression. NULL means not used. */
    +   With *pWith;           /* WITH clause attached to this select. Or NULL. */
    + };
    + 
    + /*
    + ** Allowed values for Select.selFlags.  The "SF" prefix stands for
    + ** "Select Flag".
    +-*/
    +-#define SF_Distinct        0x0001  /* Output should be DISTINCT */
    +-#define SF_All             0x0002  /* Includes the ALL keyword */
    +-#define SF_Resolved        0x0004  /* Identifiers have been resolved */
    +-#define SF_Aggregate       0x0008  /* Contains aggregate functions */
    +-#define SF_UsesEphemeral   0x0010  /* Uses the OpenEphemeral opcode */
    +-#define SF_Expanded        0x0020  /* sqlite3SelectExpand() called on this */
    +-#define SF_HasTypeInfo     0x0040  /* FROM subqueries have Table metadata */
    +-#define SF_Compound        0x0080  /* Part of a compound query */
    +-#define SF_Values          0x0100  /* Synthesized from VALUES clause */
    +-#define SF_MultiValue      0x0200  /* Single VALUES term with multiple rows */
    +-#define SF_NestedFrom      0x0400  /* Part of a parenthesized FROM clause */
    +-#define SF_MaybeConvert    0x0800  /* Need convertCompoundSelectToSubquery() */
    +-#define SF_MinMaxAgg       0x1000  /* Aggregate containing min() or max() */
    +-#define SF_Recursive       0x2000  /* The recursive part of a recursive CTE */
    +-#define SF_Converted       0x4000  /* By convertCompoundSelectToSubquery() */
    ++**
    ++** Value constraints (all checked via assert())
    ++**     SF_HasAgg     == NC_HasAgg
    ++**     SF_MinMaxAgg  == NC_MinMaxAgg     == SQLITE_FUNC_MINMAX
    ++**     SF_FixedLimit == WHERE_USE_LIMIT
    ++*/
    ++#define SF_Distinct       0x00001  /* Output should be DISTINCT */
    ++#define SF_All            0x00002  /* Includes the ALL keyword */
    ++#define SF_Resolved       0x00004  /* Identifiers have been resolved */
    ++#define SF_Aggregate      0x00008  /* Contains agg functions or a GROUP BY */
    ++#define SF_HasAgg         0x00010  /* Contains aggregate functions */
    ++#define SF_UsesEphemeral  0x00020  /* Uses the OpenEphemeral opcode */
    ++#define SF_Expanded       0x00040  /* sqlite3SelectExpand() called on this */
    ++#define SF_HasTypeInfo    0x00080  /* FROM subqueries have Table metadata */
    ++#define SF_Compound       0x00100  /* Part of a compound query */
    ++#define SF_Values         0x00200  /* Synthesized from VALUES clause */
    ++#define SF_MultiValue     0x00400  /* Single VALUES term with multiple rows */
    ++#define SF_NestedFrom     0x00800  /* Part of a parenthesized FROM clause */
    ++#define SF_MinMaxAgg      0x01000  /* Aggregate containing min() or max() */
    ++#define SF_Recursive      0x02000  /* The recursive part of a recursive CTE */
    ++#define SF_FixedLimit     0x04000  /* nSelectRow set by a constant LIMIT */
    ++#define SF_MaybeConvert   0x08000  /* Need convertCompoundSelectToSubquery() */
    ++#define SF_Converted      0x10000  /* By convertCompoundSelectToSubquery() */
    ++#define SF_IncludeHidden  0x20000  /* Include hidden columns in output */
    ++#define SF_ComplexResult  0x40000  /* Result set contains subquery or function */
    + 
    + 
    + /*
    +@@ -13027,7 +16662,7 @@ struct Select {
    + ** by one of the following macros.  The "SRT" prefix means "SELECT Result
    + ** Type".
    + **
    +-**     SRT_Union       Store results as a key in a temporary index 
    ++**     SRT_Union       Store results as a key in a temporary index
    + **                     identified by pDest->iSDParm.
    + **
    + **     SRT_Except      Remove results from the temporary index pDest->iSDParm.
    +@@ -13051,7 +16686,7 @@ struct Select {
    + **                     of the query.  This destination implies "LIMIT 1".
    + **
    + **     SRT_Set         The result must be a single column.  Store each
    +-**                     row of result as the key in table pDest->iSDParm. 
    ++**                     row of result as the key in table pDest->iSDParm.
    + **                     Apply the affinity pDest->affSdst before storing
    + **                     results.  Used to implement "IN (SELECT ...)".
    + **
    +@@ -13111,19 +16746,19 @@ struct Select {
    + */
    + struct SelectDest {
    +   u8 eDest;            /* How to dispose of the results.  On of SRT_* above. */
    +-  char affSdst;        /* Affinity used when eDest==SRT_Set */
    +   int iSDParm;         /* A parameter used by the eDest disposal method */
    +   int iSdst;           /* Base register where results are written */
    +   int nSdst;           /* Number of registers allocated */
    ++  char *zAffSdst;      /* Affinity used when eDest==SRT_Set */
    +   ExprList *pOrderBy;  /* Key columns for SRT_Queue and SRT_DistQueue */
    + };
    + 
    + /*
    +-** During code generation of statements that do inserts into AUTOINCREMENT 
    ++** During code generation of statements that do inserts into AUTOINCREMENT
    + ** tables, the following information is attached to the Table.u.autoInc.p
    + ** pointer of each autoincrement table to record some side information that
    + ** the code generator needs.  We have to keep per-table autoincrement
    +-** information in case inserts are down within triggers.  Triggers do not
    ++** information in case inserts are done within triggers.  Triggers do not
    + ** normally coordinate their activities, but we do need to coordinate the
    + ** loading and saving of autoincrement information.
    + */
    +@@ -13142,7 +16777,7 @@ struct AutoincInfo {
    + #endif
    + 
    + /*
    +-** At least one instance of the following structure is created for each 
    ++** At least one instance of the following structure is created for each
    + ** trigger that may be fired while parsing an INSERT, UPDATE or DELETE
    + ** statement. All such objects are stored in the linked list headed at
    + ** Parse.pTriggerPrg and deleted once statement compilation has been
    +@@ -13155,7 +16790,7 @@ struct AutoincInfo {
    + ** values for both pTrigger and orconf.
    + **
    + ** The TriggerPrg.aColmask[0] variable is set to a mask of old.* columns
    +-** accessed (or set to 0 for triggers fired as a result of INSERT 
    ++** accessed (or set to 0 for triggers fired as a result of INSERT
    + ** statements). Similarly, the TriggerPrg.aColmask[1] variable is set to
    + ** a mask of new.* columns used by the program.
    + */
    +@@ -13196,7 +16831,7 @@ struct TriggerPrg {
    + ** is constant but the second part is reset at the beginning and end of
    + ** each recursion.
    + **
    +-** The nTableLock and aTableLock variables are only used if the shared-cache 
    ++** The nTableLock and aTableLock variables are only used if the shared-cache
    + ** feature is enabled (if sqlite3Tsd()->useSharedData is true). They are
    + ** used to store the set of table-locks required by the statement being
    + ** compiled. Function sqlite3TableLock() is used to add entries to the
    +@@ -13215,35 +16850,25 @@ struct Parse {
    +   u8 mayAbort;         /* True if statement may throw an ABORT exception */
    +   u8 hasCompound;      /* Need to invoke convertCompoundSelectToSubquery() */
    +   u8 okConstFactor;    /* OK to factor out constants */
    +-  int aTempReg[8];     /* Holding area for temporary registers */
    ++  u8 disableLookaside; /* Number of times lookaside has been disabled */
    ++  u8 nColCache;        /* Number of entries in aColCache[] */
    +   int nRangeReg;       /* Size of the temporary register block */
    +   int iRangeReg;       /* First register in temporary register block */
    +   int nErr;            /* Number of errors seen */
    +   int nTab;            /* Number of previously allocated VDBE cursors */
    +   int nMem;            /* Number of memory cells used so far */
    +-  int nSet;            /* Number of sets used so far */
    +-  int nOnce;           /* Number of OP_Once instructions so far */
    +   int nOpAlloc;        /* Number of slots allocated for Vdbe.aOp[] */
    +-  int iFixedOp;        /* Never back out opcodes iFixedOp-1 or earlier */
    +-  int ckBase;          /* Base register of data during check constraints */
    +-  int iSelfTab;        /* Table of an index whose exprs are being coded */
    ++  int szOpAlloc;       /* Bytes of memory space allocated for Vdbe.aOp[] */
    ++  int iSelfTab;        /* Table associated with an index on expr, or negative
    ++                       ** of the base register during check-constraint eval */
    +   int iCacheLevel;     /* ColCache valid when aColCache[].iLevel<=iCacheLevel */
    +   int iCacheCnt;       /* Counter used to generate aColCache[].lru values */
    +   int nLabel;          /* Number of labels used */
    +   int *aLabel;         /* Space to hold the labels */
    +-  struct yColCache {
    +-    int iTable;           /* Table cursor number */
    +-    i16 iColumn;          /* Table column number */
    +-    u8 tempReg;           /* iReg is a temp register that needs to be freed */
    +-    int iLevel;           /* Nesting level */
    +-    int iReg;             /* Reg with value of this column. 0 means none. */
    +-    int lru;              /* Least recently used entry has the smallest value */
    +-  } aColCache[SQLITE_N_COLCACHE];  /* One for each column cache entry */
    +   ExprList *pConstExpr;/* Constant expressions */
    +   Token constraintName;/* Name of the constraint currently being parsed */
    +   yDbMask writeMask;   /* Start a write transaction on these databases */
    +   yDbMask cookieMask;  /* Bitmask of schema verified databases */
    +-  int cookieValue[SQLITE_MAX_ATTACHED+2];  /* Values of cookies to verify */
    +   int regRowid;        /* Register holding rowid of CREATE TABLE entry */
    +   int regRoot;         /* Register holding root page number for new objects */
    +   int nMaxArg;         /* Max args passed to user function by sub-program */
    +@@ -13256,11 +16881,9 @@ struct Parse {
    +   TableLock *aTableLock; /* Required table locks for shared-cache mode */
    + #endif
    +   AutoincInfo *pAinc;  /* Information about AUTOINCREMENT counters */
    +-
    +-  /* Information used while coding trigger programs. */
    +   Parse *pToplevel;    /* Parse structure for main program (or NULL) */
    +   Table *pTriggerTab;  /* Table triggers are being coded for */
    +-  int addrCrTab;       /* Address of OP_CreateTable opcode on CREATE TABLE */
    ++  int addrCrTab;       /* Address of OP_CreateBtree opcode on CREATE TABLE */
    +   u32 nQueryLoop;      /* Est number of iterations of a query (10*log2(N)) */
    +   u32 oldmask;         /* Mask of old.* columns referenced */
    +   u32 newmask;         /* Mask of new.* columns referenced */
    +@@ -13268,36 +16891,50 @@ struct Parse {
    +   u8 eOrconf;          /* Default ON CONFLICT policy for trigger steps */
    +   u8 disableTriggers;  /* True to disable triggers */
    + 
    ++  /**************************************************************************
    ++  ** Fields above must be initialized to zero.  The fields that follow,
    ++  ** down to the beginning of the recursive section, do not need to be
    ++  ** initialized as they will be set before being used.  The boundary is
    ++  ** determined by offsetof(Parse,aColCache).
    ++  **************************************************************************/
    ++
    ++  struct yColCache {
    ++    int iTable;           /* Table cursor number */
    ++    i16 iColumn;          /* Table column number */
    ++    u8 tempReg;           /* iReg is a temp register that needs to be freed */
    ++    int iLevel;           /* Nesting level */
    ++    int iReg;             /* Reg with value of this column. 0 means none. */
    ++    int lru;              /* Least recently used entry has the smallest value */
    ++  } aColCache[SQLITE_N_COLCACHE];  /* One for each column cache entry */
    ++  int aTempReg[8];        /* Holding area for temporary registers */
    ++  Token sNameToken;       /* Token with unqualified schema object name */
    ++
    +   /************************************************************************
    +   ** Above is constant between recursions.  Below is reset before and after
    +   ** each recursion.  The boundary between these two regions is determined
    +-  ** using offsetof(Parse,nVar) so the nVar field must be the first field
    +-  ** in the recursive region.
    ++  ** using offsetof(Parse,sLastToken) so the sLastToken field must be the
    ++  ** first field in the recursive region.
    +   ************************************************************************/
    + 
    +-  int nVar;                 /* Number of '?' variables seen in the SQL so far */
    +-  int nzVar;                /* Number of available slots in azVar[] */
    ++  Token sLastToken;       /* The last token parsed */
    ++  ynVar nVar;               /* Number of '?' variables seen in the SQL so far */
    +   u8 iPkSortOrder;          /* ASC or DESC for INTEGER PRIMARY KEY */
    +-  u8 bFreeWith;             /* True if pWith should be freed with parser */
    +   u8 explain;               /* True if the EXPLAIN flag is found on the query */
    + #ifndef SQLITE_OMIT_VIRTUALTABLE
    +   u8 declareVtab;           /* True if inside sqlite3_declare_vtab() */
    +   int nVtabLock;            /* Number of virtual tables to lock */
    + #endif
    +-  int nAlias;               /* Number of aliased result set columns */
    +   int nHeight;              /* Expression tree height of current sub-select */
    + #ifndef SQLITE_OMIT_EXPLAIN
    +   int iSelectId;            /* ID of current select for EXPLAIN output */
    +   int iNextSelectId;        /* Next available select ID for EXPLAIN output */
    + #endif
    +-  char **azVar;             /* Pointers to names of parameters */
    ++  VList *pVList;            /* Mapping between variable names and numbers */
    +   Vdbe *pReprepare;         /* VM being reprepared (sqlite3Reprepare()) */
    +   const char *zTail;        /* All SQL text past the last semicolon parsed */
    +   Table *pNewTable;         /* A table being constructed by CREATE TABLE */
    +   Trigger *pNewTrigger;     /* Trigger under construct by a CREATE TRIGGER */
    +   const char *zAuthContext; /* The 6th parameter to db->xAuth callbacks */
    +-  Token sNameToken;         /* Token with unqualified schema object name */
    +-  Token sLastToken;         /* The last token parsed */
    + #ifndef SQLITE_OMIT_VIRTUALTABLE
    +   Token sArg;               /* Complete text of a module argument */
    +   Table **apVtabLock;       /* Pointer to virtual tables needing locking */
    +@@ -13305,8 +16942,17 @@ struct Parse {
    +   Table *pZombieTab;        /* List of Table objects to delete after code gen */
    +   TriggerPrg *pTriggerPrg;  /* Linked list of coded triggers */
    +   With *pWith;              /* Current WITH clause, or NULL */
    ++  With *pWithToFree;        /* Free this WITH object at the end of the parse */
    + };
    + 
    ++/*
    ++** Sizes and pointers of various parts of the Parse object.
    ++*/
    ++#define PARSE_HDR_SZ offsetof(Parse,aColCache) /* Recursive part w/o aColCache*/
    ++#define PARSE_RECURSE_SZ offsetof(Parse,sLastToken)    /* Recursive part */
    ++#define PARSE_TAIL_SZ (sizeof(Parse)-PARSE_RECURSE_SZ) /* Non-recursive part */
    ++#define PARSE_TAIL(X) (((char*)(X))+PARSE_RECURSE_SZ)  /* Pointer to tail */
    ++
    + /*
    + ** Return true if currently inside an sqlite3_declare_vtab() call.
    + */
    +@@ -13327,26 +16973,41 @@ struct AuthContext {
    + 
    + /*
    + ** Bitfield flags for P5 value in various opcodes.
    +-*/
    +-#define OPFLAG_NCHANGE       0x01    /* Set to update db->nChange */
    ++**
    ++** Value constraints (enforced via assert()):
    ++**    OPFLAG_LENGTHARG    == SQLITE_FUNC_LENGTH
    ++**    OPFLAG_TYPEOFARG    == SQLITE_FUNC_TYPEOF
    ++**    OPFLAG_BULKCSR      == BTREE_BULKLOAD
    ++**    OPFLAG_SEEKEQ       == BTREE_SEEK_EQ
    ++**    OPFLAG_FORDELETE    == BTREE_FORDELETE
    ++**    OPFLAG_SAVEPOSITION == BTREE_SAVEPOSITION
    ++**    OPFLAG_AUXDELETE    == BTREE_AUXDELETE
    ++*/
    ++#define OPFLAG_NCHANGE       0x01    /* OP_Insert: Set to update db->nChange */
    ++                                     /* Also used in P2 (not P5) of OP_Delete */
    + #define OPFLAG_EPHEM         0x01    /* OP_Column: Ephemeral output is ok */
    +-#define OPFLAG_LASTROWID     0x02    /* Set to update db->lastRowid */
    ++#define OPFLAG_LASTROWID     0x20    /* Set to update db->lastRowid */
    + #define OPFLAG_ISUPDATE      0x04    /* This OP_Insert is an sql UPDATE */
    + #define OPFLAG_APPEND        0x08    /* This is likely to be an append */
    + #define OPFLAG_USESEEKRESULT 0x10    /* Try to avoid a seek in BtreeInsert() */
    ++#define OPFLAG_ISNOOP        0x40    /* OP_Delete does pre-update-hook only */
    + #define OPFLAG_LENGTHARG     0x40    /* OP_Column only used for length() */
    + #define OPFLAG_TYPEOFARG     0x80    /* OP_Column only used for typeof() */
    + #define OPFLAG_BULKCSR       0x01    /* OP_Open** used to open bulk cursor */
    + #define OPFLAG_SEEKEQ        0x02    /* OP_Open** cursor uses EQ seek only */
    +-#define OPFLAG_P2ISREG       0x04    /* P2 to OP_Open** is a register number */
    ++#define OPFLAG_FORDELETE     0x08    /* OP_Open should use BTREE_FORDELETE */
    ++#define OPFLAG_P2ISREG       0x10    /* P2 to OP_Open** is a register number */
    + #define OPFLAG_PERMUTE       0x01    /* OP_Compare: use the permutation */
    ++#define OPFLAG_SAVEPOSITION  0x02    /* OP_Delete/Insert: save cursor pos */
    ++#define OPFLAG_AUXDELETE     0x04    /* OP_Delete: index in a DELETE op */
    ++#define OPFLAG_NOCHNG_MAGIC  0x6d    /* OP_MakeRecord: serialtype 10 is ok */
    + 
    + /*
    +  * Each trigger present in the database schema is stored as an instance of
    +- * struct Trigger. 
    ++ * struct Trigger.
    +  *
    +  * Pointers to instances of struct Trigger are stored in two ways.
    +- * 1. In the "trigHash" hash table (part of the sqlite3* that represents the 
    ++ * 1. In the "trigHash" hash table (part of the sqlite3* that represents the
    +  *    database). This allows Trigger structures to be retrieved by name.
    +  * 2. All triggers associated with a single table form a linked list, using the
    +  *    pNext member of struct Trigger. A pointer to the first element of the
    +@@ -13372,7 +17033,7 @@ struct Trigger {
    + 
    + /*
    + ** A trigger is either a BEFORE or an AFTER trigger.  The following constants
    +-** determine which. 
    ++** determine which.
    + **
    + ** If there are multiple triggers, you might of some BEFORE and some AFTER.
    + ** In that cases, the constants below can be ORed together.
    +@@ -13382,15 +17043,15 @@ struct Trigger {
    + 
    + /*
    +  * An instance of struct TriggerStep is used to store a single SQL statement
    +- * that is a part of a trigger-program. 
    ++ * that is a part of a trigger-program.
    +  *
    +  * Instances of struct TriggerStep are stored in a singly linked list (linked
    +- * using the "pNext" member) referenced by the "step_list" member of the 
    ++ * using the "pNext" member) referenced by the "step_list" member of the
    +  * associated struct Trigger instance. The first element of the linked list is
    +  * the first step of the trigger-program.
    +- * 
    ++ *
    +  * The "op" member indicates whether this is a "DELETE", "INSERT", "UPDATE" or
    +- * "SELECT" statement. The meanings of the other members is determined by the 
    ++ * "SELECT" statement. The meanings of the other members is determined by the
    +  * value of "op" as follows:
    +  *
    +  * (op == TK_INSERT)
    +@@ -13400,7 +17061,7 @@ struct Trigger {
    +  * zTarget   -> Dequoted name of the table to insert into.
    +  * pExprList -> If this is an INSERT INTO ... VALUES ... statement, then
    +  *              this stores values to be inserted. Otherwise NULL.
    +- * pIdList   -> If this is an INSERT INTO ... (<column-names>) VALUES ... 
    ++ * pIdList   -> If this is an INSERT INTO ... (<column-names>) VALUES ...
    +  *              statement, then this stores the column-names to be
    +  *              inserted into.
    +  *
    +@@ -13408,7 +17069,7 @@ struct Trigger {
    +  * zTarget   -> Dequoted name of the table to delete from.
    +  * pWhere    -> The WHERE clause of the DELETE statement if one is specified.
    +  *              Otherwise NULL.
    +- * 
    ++ *
    +  * (op == TK_UPDATE)
    +  * zTarget   -> Dequoted name of the table to update.
    +  * pWhere    -> The WHERE clause of the UPDATE statement if one is specified.
    +@@ -13416,7 +17077,7 @@ struct Trigger {
    +  * pExprList -> A list of the columns to update and the expressions to update
    +  *              them to. See sqlite3Update() documentation of "pChanges"
    +  *              argument.
    +- * 
    ++ *
    +  */
    + struct TriggerStep {
    +   u8 op;               /* One of TK_DELETE, TK_UPDATE, TK_INSERT, TK_SELECT */
    +@@ -13427,6 +17088,7 @@ struct TriggerStep {
    +   Expr *pWhere;        /* The WHERE clause for DELETE or UPDATE steps */
    +   ExprList *pExprList; /* SET clause for UPDATE. */
    +   IdList *pIdList;     /* Column names for INSERT */
    ++  char *zSpan;         /* Original SQL text of this command */
    +   TriggerStep *pNext;  /* Next in the link-list */
    +   TriggerStep *pLast;  /* Last element in link-list. Valid for 1st elem only */
    + };
    +@@ -13434,7 +17096,7 @@ struct TriggerStep {
    + /*
    + ** The following structure contains information used by the sqliteFix...
    + ** routines as they walk the parse tree to make database references
    +-** explicit.  
    ++** explicit.
    + */
    + typedef struct DbFixer DbFixer;
    + struct DbFixer {
    +@@ -13452,15 +17114,21 @@ struct DbFixer {
    + */
    + struct StrAccum {
    +   sqlite3 *db;         /* Optional database for lookaside.  Can be NULL */
    +-  char *zBase;         /* A base allocation.  Not from malloc. */
    +   char *zText;         /* The string collected so far */
    +-  int  nChar;          /* Length of the string so far */
    +-  int  nAlloc;         /* Amount of space allocated in zText */
    +-  int  mxAlloc;        /* Maximum allowed allocation.  0 for no malloc usage */
    ++  u32  nAlloc;         /* Amount of space allocated in zText */
    ++  u32  mxAlloc;        /* Maximum allowed allocation.  0 for no malloc usage */
    ++  u32  nChar;          /* Length of the string so far */
    +   u8   accError;       /* STRACCUM_NOMEM or STRACCUM_TOOBIG */
    ++  u8   printfFlags;    /* SQLITE_PRINTF flags below */
    + };
    + #define STRACCUM_NOMEM   1
    + #define STRACCUM_TOOBIG  2
    ++#define SQLITE_PRINTF_INTERNAL 0x01  /* Internal-use-only converters allowed */
    ++#define SQLITE_PRINTF_SQLFUNC  0x02  /* SQL function arguments to VXPrintf */
    ++#define SQLITE_PRINTF_MALLOCED 0x04  /* True if xText is allocated space */
    ++
    ++#define isMalloced(X)  (((X)->printfFlags & SQLITE_PRINTF_MALLOCED)!=0)
    ++
    + 
    + /*
    + ** A pointer to this structure is used to communicate information
    +@@ -13484,10 +17152,12 @@ struct Sqlite3Config {
    +   int bFullMutex;                   /* True to enable full mutexing */
    +   int bOpenUri;                     /* True to interpret filenames as URIs */
    +   int bUseCis;                      /* Use covering indices for full-scans */
    ++  int bSmallMalloc;                 /* Avoid large memory allocations if true */
    +   int mxStrlen;                     /* Maximum string length */
    +   int neverCorrupt;                 /* Database is always well-formed */
    +   int szLookaside;                  /* Default lookaside buffer size */
    +   int nLookaside;                   /* Default lookaside buffer count */
    ++  int nStmtSpill;                   /* Stmt-journal spill-to-disk threshold */
    +   sqlite3_mem_methods m;            /* Low-level memory allocation interface */
    +   sqlite3_mutex_methods mutex;      /* Low-level mutex interface */
    +   sqlite3_pcache_methods2 pcache2;  /* Low-level page-cache interface */
    +@@ -13496,9 +17166,6 @@ struct Sqlite3Config {
    +   int mnReq, mxReq;                 /* Min and max heap requests sizes */
    +   sqlite3_int64 szMmap;             /* mmap() space per open file */
    +   sqlite3_int64 mxMmap;             /* Maximum value for szMmap */
    +-  void *pScratch;                   /* Scratch memory */
    +-  int szScratch;                    /* Size of each scratch buffer */
    +-  int nScratch;                     /* Number of scratch buffers */
    +   void *pPage;                      /* Page cache memory */
    +   int szPage;                       /* Size of each page in pPage[] */
    +   int nPage;                        /* Number of pages in pPage[] */
    +@@ -13527,10 +17194,11 @@ struct Sqlite3Config {
    +   void (*xVdbeBranch)(void*,int iSrcLine,u8 eThis,u8 eMx);  /* Callback */
    +   void *pVdbeBranchArg;                                     /* 1st argument */
    + #endif
    +-#ifndef SQLITE_OMIT_BUILTIN_TEST
    ++#ifndef SQLITE_UNTESTABLE
    +   int (*xTestCallback)(int);        /* Invoked by sqlite3FaultSim() */
    + #endif
    +   int bLocaltimeFault;              /* True to fail localtime() calls */
    ++  int iOnceResetThreshold;          /* When to reset OP_Once counters */
    + };
    + 
    + /*
    +@@ -13555,18 +17223,24 @@ struct Sqlite3Config {
    + ** Context pointer passed down through the tree-walk.
    + */
    + struct Walker {
    ++  Parse *pParse;                            /* Parser context.  */
    +   int (*xExprCallback)(Walker*, Expr*);     /* Callback for expressions */
    +   int (*xSelectCallback)(Walker*,Select*);  /* Callback for SELECTs */
    +   void (*xSelectCallback2)(Walker*,Select*);/* Second callback for SELECTs */
    +-  Parse *pParse;                            /* Parser context.  */
    +   int walkerDepth;                          /* Number of subqueries */
    +   u8 eCode;                                 /* A small processing code */
    +   union {                                   /* Extra data for callback */
    +-    NameContext *pNC;                          /* Naming context */
    +-    int n;                                     /* A counter */
    +-    int iCur;                                  /* A cursor number */
    +-    SrcList *pSrcList;                         /* FROM clause */
    +-    struct SrcCount *pSrcCount;                /* Counting column references */
    ++    NameContext *pNC;                         /* Naming context */
    ++    int n;                                    /* A counter */
    ++    int iCur;                                 /* A cursor number */
    ++    SrcList *pSrcList;                        /* FROM clause */
    ++    struct SrcCount *pSrcCount;               /* Counting column references */
    ++    struct CCurHint *pCCurHint;               /* Used by codeCursorHint() */
    ++    int *aiCol;                               /* array of column indexes */
    ++    struct IdxCover *pIdxCover;               /* Check for index coverage */
    ++    struct IdxExprTrans *pIdxTrans;           /* Convert indexed expr to column */
    ++    ExprList *pGroupBy;                       /* GROUP BY clause */
    ++    struct HavingToWhereCtx *pHavingCtx;      /* HAVING to WHERE clause ctx */
    +   } u;
    + };
    + 
    +@@ -13576,6 +17250,12 @@ SQLITE_PRIVATE int sqlite3WalkExprList(Walker*, ExprList*);
    + SQLITE_PRIVATE int sqlite3WalkSelect(Walker*, Select*);
    + SQLITE_PRIVATE int sqlite3WalkSelectExpr(Walker*, Select*);
    + SQLITE_PRIVATE int sqlite3WalkSelectFrom(Walker*, Select*);
    ++SQLITE_PRIVATE int sqlite3ExprWalkNoop(Walker*, Expr*);
    ++SQLITE_PRIVATE int sqlite3SelectWalkNoop(Walker*, Select*);
    ++SQLITE_PRIVATE int sqlite3SelectWalkFail(Walker*, Select*);
    ++#ifdef SQLITE_DEBUG
    ++SQLITE_PRIVATE void sqlite3SelectWalkAssert2(Walker*, Select*);
    ++#endif
    + 
    + /*
    + ** Return code from the parse-tree walking primitives and their
    +@@ -13628,13 +17308,33 @@ struct TreeView {
    + ** using sqlite3_log().  The routines also provide a convenient place
    + ** to set a debugger breakpoint.
    + */
    ++SQLITE_PRIVATE int sqlite3ReportError(int iErr, int lineno, const char *zType);
    + SQLITE_PRIVATE int sqlite3CorruptError(int);
    + SQLITE_PRIVATE int sqlite3MisuseError(int);
    + SQLITE_PRIVATE int sqlite3CantopenError(int);
    + #define SQLITE_CORRUPT_BKPT sqlite3CorruptError(__LINE__)
    + #define SQLITE_MISUSE_BKPT sqlite3MisuseError(__LINE__)
    + #define SQLITE_CANTOPEN_BKPT sqlite3CantopenError(__LINE__)
    ++#ifdef SQLITE_DEBUG
    ++SQLITE_PRIVATE   int sqlite3NomemError(int);
    ++SQLITE_PRIVATE   int sqlite3IoerrnomemError(int);
    ++SQLITE_PRIVATE   int sqlite3CorruptPgnoError(int,Pgno);
    ++# define SQLITE_NOMEM_BKPT sqlite3NomemError(__LINE__)
    ++# define SQLITE_IOERR_NOMEM_BKPT sqlite3IoerrnomemError(__LINE__)
    ++# define SQLITE_CORRUPT_PGNO(P) sqlite3CorruptPgnoError(__LINE__,(P))
    ++#else
    ++# define SQLITE_NOMEM_BKPT SQLITE_NOMEM
    ++# define SQLITE_IOERR_NOMEM_BKPT SQLITE_IOERR_NOMEM
    ++# define SQLITE_CORRUPT_PGNO(P) sqlite3CorruptError(__LINE__)
    ++#endif
    + 
    ++/*
    ++** FTS3 and FTS4 both require virtual table support
    ++*/
    ++#if defined(SQLITE_OMIT_VIRTUALTABLE)
    ++# undef SQLITE_ENABLE_FTS3
    ++# undef SQLITE_ENABLE_FTS4
    ++#endif
    + 
    + /*
    + ** FTS4 is really an extension for FTS3.  It is enabled using the
    +@@ -13667,6 +17367,7 @@ SQLITE_PRIVATE int sqlite3CantopenError(int);
    + # define sqlite3Isdigit(x)   (sqlite3CtypeMap[(unsigned char)(x)]&0x04)
    + # define sqlite3Isxdigit(x)  (sqlite3CtypeMap[(unsigned char)(x)]&0x08)
    + # define sqlite3Tolower(x)   (sqlite3UpperToLower[(unsigned char)(x)])
    ++# define sqlite3Isquote(x)   (sqlite3CtypeMap[(unsigned char)(x)]&0x80)
    + #else
    + # define sqlite3Toupper(x)   toupper((unsigned char)(x))
    + # define sqlite3Isspace(x)   isspace((unsigned char)(x))
    +@@ -13675,6 +17376,7 @@ SQLITE_PRIVATE int sqlite3CantopenError(int);
    + # define sqlite3Isdigit(x)   isdigit((unsigned char)(x))
    + # define sqlite3Isxdigit(x)  isxdigit((unsigned char)(x))
    + # define sqlite3Tolower(x)   tolower((unsigned char)(x))
    ++# define sqlite3Isquote(x)   ((x)=='"'||(x)=='\''||(x)=='['||(x)=='`')
    + #endif
    + #ifndef SQLITE_OMIT_COMPILEOPTION_DIAGS
    + SQLITE_PRIVATE int sqlite3IsIdChar(u8);
    +@@ -13683,8 +17385,9 @@ SQLITE_PRIVATE int sqlite3IsIdChar(u8);
    + /*
    + ** Internal function prototypes
    + */
    +-#define sqlite3StrICmp sqlite3_stricmp
    ++SQLITE_PRIVATE int sqlite3StrICmp(const char*,const char*);
    + SQLITE_PRIVATE int sqlite3Strlen30(const char*);
    ++SQLITE_PRIVATE char *sqlite3ColumnType(Column*,char*);
    + #define sqlite3StrNICmp sqlite3_strnicmp
    + 
    + SQLITE_PRIVATE int sqlite3MallocInit(void);
    +@@ -13693,20 +17396,21 @@ SQLITE_PRIVATE void *sqlite3Malloc(u64);
    + SQLITE_PRIVATE void *sqlite3MallocZero(u64);
    + SQLITE_PRIVATE void *sqlite3DbMallocZero(sqlite3*, u64);
    + SQLITE_PRIVATE void *sqlite3DbMallocRaw(sqlite3*, u64);
    ++SQLITE_PRIVATE void *sqlite3DbMallocRawNN(sqlite3*, u64);
    + SQLITE_PRIVATE char *sqlite3DbStrDup(sqlite3*,const char*);
    + SQLITE_PRIVATE char *sqlite3DbStrNDup(sqlite3*,const char*, u64);
    ++SQLITE_PRIVATE char *sqlite3DbSpanDup(sqlite3*,const char*,const char*);
    + SQLITE_PRIVATE void *sqlite3Realloc(void*, u64);
    + SQLITE_PRIVATE void *sqlite3DbReallocOrFree(sqlite3 *, void *, u64);
    + SQLITE_PRIVATE void *sqlite3DbRealloc(sqlite3 *, void *, u64);
    + SQLITE_PRIVATE void sqlite3DbFree(sqlite3*, void*);
    ++SQLITE_PRIVATE void sqlite3DbFreeNN(sqlite3*, void*);
    + SQLITE_PRIVATE int sqlite3MallocSize(void*);
    + SQLITE_PRIVATE int sqlite3DbMallocSize(sqlite3*, void*);
    +-SQLITE_PRIVATE void *sqlite3ScratchMalloc(int);
    +-SQLITE_PRIVATE void sqlite3ScratchFree(void*);
    + SQLITE_PRIVATE void *sqlite3PageMalloc(int);
    + SQLITE_PRIVATE void sqlite3PageFree(void*);
    + SQLITE_PRIVATE void sqlite3MemSetDefault(void);
    +-#ifndef SQLITE_OMIT_BUILTIN_TEST
    ++#ifndef SQLITE_UNTESTABLE
    + SQLITE_PRIVATE void sqlite3BenignMallocHooks(void (*)(void), void (*)(void));
    + #endif
    + SQLITE_PRIVATE int sqlite3HeapNearlyFull(void);
    +@@ -13722,18 +17426,22 @@ SQLITE_PRIVATE int sqlite3HeapNearlyFull(void);
    + #ifdef SQLITE_USE_ALLOCA
    + # define sqlite3StackAllocRaw(D,N)   alloca(N)
    + # define sqlite3StackAllocZero(D,N)  memset(alloca(N), 0, N)
    +-# define sqlite3StackFree(D,P)       
    ++# define sqlite3StackFree(D,P)
    + #else
    + # define sqlite3StackAllocRaw(D,N)   sqlite3DbMallocRaw(D,N)
    + # define sqlite3StackAllocZero(D,N)  sqlite3DbMallocZero(D,N)
    + # define sqlite3StackFree(D,P)       sqlite3DbFree(D,P)
    + #endif
    + 
    +-#ifdef SQLITE_ENABLE_MEMSYS3
    +-SQLITE_PRIVATE const sqlite3_mem_methods *sqlite3MemGetMemsys3(void);
    +-#endif
    ++/* Do not allow both MEMSYS5 and MEMSYS3 to be defined together.  If they
    ++** are, disable MEMSYS3
    ++*/
    + #ifdef SQLITE_ENABLE_MEMSYS5
    + SQLITE_PRIVATE const sqlite3_mem_methods *sqlite3MemGetMemsys5(void);
    ++#undef SQLITE_ENABLE_MEMSYS3
    ++#endif
    ++#ifdef SQLITE_ENABLE_MEMSYS3
    ++SQLITE_PRIVATE const sqlite3_mem_methods *sqlite3MemGetMemsys3(void);
    + #endif
    + 
    + 
    +@@ -13753,12 +17461,19 @@ SQLITE_PRIVATE   void sqlite3MemoryBarrier(void);
    + SQLITE_PRIVATE sqlite3_int64 sqlite3StatusValue(int);
    + SQLITE_PRIVATE void sqlite3StatusUp(int, int);
    + SQLITE_PRIVATE void sqlite3StatusDown(int, int);
    +-SQLITE_PRIVATE void sqlite3StatusSet(int, int);
    ++SQLITE_PRIVATE void sqlite3StatusHighwater(int, int);
    ++SQLITE_PRIVATE int sqlite3LookasideUsed(sqlite3*,int*);
    + 
    + /* Access to mutexes used by sqlite3_status() */
    + SQLITE_PRIVATE sqlite3_mutex *sqlite3Pcache1Mutex(void);
    + SQLITE_PRIVATE sqlite3_mutex *sqlite3MallocMutex(void);
    + 
    ++#if defined(SQLITE_ENABLE_MULTITHREADED_CHECKS) && !defined(SQLITE_MUTEX_OMIT)
    ++SQLITE_PRIVATE void sqlite3MutexWarnOnContention(sqlite3_mutex*);
    ++#else
    ++# define sqlite3MutexWarnOnContention(x)
    ++#endif
    ++
    + #ifndef SQLITE_OMIT_FLOATING_POINT
    + SQLITE_PRIVATE   int sqlite3IsNaN(double);
    + #else
    +@@ -13775,10 +17490,8 @@ struct PrintfArguments {
    +   sqlite3_value **apArg;   /* The argument values */
    + };
    + 
    +-#define SQLITE_PRINTF_INTERNAL 0x01
    +-#define SQLITE_PRINTF_SQLFUNC  0x02
    +-SQLITE_PRIVATE void sqlite3VXPrintf(StrAccum*, u32, const char*, va_list);
    +-SQLITE_PRIVATE void sqlite3XPrintf(StrAccum*, u32, const char*, ...);
    ++SQLITE_PRIVATE void sqlite3VXPrintf(StrAccum*, const char*, va_list);
    ++SQLITE_PRIVATE void sqlite3XPrintf(StrAccum*, const char*, ...);
    + SQLITE_PRIVATE char *sqlite3MPrintf(sqlite3*,const char*, ...);
    + SQLITE_PRIVATE char *sqlite3VMPrintf(sqlite3*,const char*, va_list);
    + #if defined(SQLITE_DEBUG) || defined(SQLITE_HAVE_OS_TRACE)
    +@@ -13790,14 +17503,17 @@ SQLITE_PRIVATE   void *sqlite3TestTextToPtr(const char*);
    + 
    + #if defined(SQLITE_DEBUG)
    + SQLITE_PRIVATE   void sqlite3TreeViewExpr(TreeView*, const Expr*, u8);
    ++SQLITE_PRIVATE   void sqlite3TreeViewBareExprList(TreeView*, const ExprList*, const char*);
    + SQLITE_PRIVATE   void sqlite3TreeViewExprList(TreeView*, const ExprList*, u8, const char*);
    + SQLITE_PRIVATE   void sqlite3TreeViewSelect(TreeView*, const Select*, u8);
    ++SQLITE_PRIVATE   void sqlite3TreeViewWith(TreeView*, const With*, u8);
    + #endif
    + 
    + 
    + SQLITE_PRIVATE void sqlite3SetString(char **, sqlite3*, const char*);
    + SQLITE_PRIVATE void sqlite3ErrorMsg(Parse*, const char*, ...);
    +-SQLITE_PRIVATE int sqlite3Dequote(char*);
    ++SQLITE_PRIVATE void sqlite3Dequote(char*);
    ++SQLITE_PRIVATE void sqlite3TokenInit(Token*,char*);
    + SQLITE_PRIVATE int sqlite3KeywordCode(const unsigned char*, int);
    + SQLITE_PRIVATE int sqlite3RunParser(Parse*, const char*, char **);
    + SQLITE_PRIVATE void sqlite3FinishCoding(Parse*);
    +@@ -13806,49 +17522,60 @@ SQLITE_PRIVATE void sqlite3ReleaseTempReg(Parse*,int);
    + SQLITE_PRIVATE int sqlite3GetTempRange(Parse*,int);
    + SQLITE_PRIVATE void sqlite3ReleaseTempRange(Parse*,int,int);
    + SQLITE_PRIVATE void sqlite3ClearTempRegCache(Parse*);
    ++#ifdef SQLITE_DEBUG
    ++SQLITE_PRIVATE int sqlite3NoTempsInRange(Parse*,int,int);
    ++#endif
    + SQLITE_PRIVATE Expr *sqlite3ExprAlloc(sqlite3*,int,const Token*,int);
    + SQLITE_PRIVATE Expr *sqlite3Expr(sqlite3*,int,const char*);
    + SQLITE_PRIVATE void sqlite3ExprAttachSubtrees(sqlite3*,Expr*,Expr*,Expr*);
    +-SQLITE_PRIVATE Expr *sqlite3PExpr(Parse*, int, Expr*, Expr*, const Token*);
    ++SQLITE_PRIVATE Expr *sqlite3PExpr(Parse*, int, Expr*, Expr*);
    ++SQLITE_PRIVATE void sqlite3PExprAddSelect(Parse*, Expr*, Select*);
    + SQLITE_PRIVATE Expr *sqlite3ExprAnd(sqlite3*,Expr*, Expr*);
    + SQLITE_PRIVATE Expr *sqlite3ExprFunction(Parse*,ExprList*, Token*);
    +-SQLITE_PRIVATE void sqlite3ExprAssignVarNumber(Parse*, Expr*);
    ++SQLITE_PRIVATE void sqlite3ExprAssignVarNumber(Parse*, Expr*, u32);
    + SQLITE_PRIVATE void sqlite3ExprDelete(sqlite3*, Expr*);
    + SQLITE_PRIVATE ExprList *sqlite3ExprListAppend(Parse*,ExprList*,Expr*);
    ++SQLITE_PRIVATE ExprList *sqlite3ExprListAppendVector(Parse*,ExprList*,IdList*,Expr*);
    + SQLITE_PRIVATE void sqlite3ExprListSetSortOrder(ExprList*,int);
    + SQLITE_PRIVATE void sqlite3ExprListSetName(Parse*,ExprList*,Token*,int);
    +-SQLITE_PRIVATE void sqlite3ExprListSetSpan(Parse*,ExprList*,ExprSpan*);
    ++SQLITE_PRIVATE void sqlite3ExprListSetSpan(Parse*,ExprList*,const char*,const char*);
    + SQLITE_PRIVATE void sqlite3ExprListDelete(sqlite3*, ExprList*);
    + SQLITE_PRIVATE u32 sqlite3ExprListFlags(const ExprList*);
    + SQLITE_PRIVATE int sqlite3Init(sqlite3*, char**);
    + SQLITE_PRIVATE int sqlite3InitCallback(void*, int, char**, char**);
    + SQLITE_PRIVATE void sqlite3Pragma(Parse*,Token*,Token*,Token*,int);
    ++#ifndef SQLITE_OMIT_VIRTUALTABLE
    ++SQLITE_PRIVATE Module *sqlite3PragmaVtabRegister(sqlite3*,const char *zName);
    ++#endif
    + SQLITE_PRIVATE void sqlite3ResetAllSchemasOfConnection(sqlite3*);
    + SQLITE_PRIVATE void sqlite3ResetOneSchema(sqlite3*,int);
    + SQLITE_PRIVATE void sqlite3CollapseDatabaseArray(sqlite3*);
    +-SQLITE_PRIVATE void sqlite3BeginParse(Parse*,int);
    + SQLITE_PRIVATE void sqlite3CommitInternalChanges(sqlite3*);
    + SQLITE_PRIVATE void sqlite3DeleteColumnNames(sqlite3*,Table*);
    + SQLITE_PRIVATE int sqlite3ColumnsFromExprList(Parse*,ExprList*,i16*,Column**);
    ++SQLITE_PRIVATE void sqlite3SelectAddColumnTypeAndCollation(Parse*,Table*,Select*);
    + SQLITE_PRIVATE Table *sqlite3ResultSetOfSelect(Parse*,Select*);
    + SQLITE_PRIVATE void sqlite3OpenMasterTable(Parse *, int);
    + SQLITE_PRIVATE Index *sqlite3PrimaryKeyIndex(Table*);
    + SQLITE_PRIVATE i16 sqlite3ColumnOfIndex(Index*, i16);
    + SQLITE_PRIVATE void sqlite3StartTable(Parse*,Token*,Token*,int,int,int,int);
    +-SQLITE_PRIVATE void sqlite3AddColumn(Parse*,Token*);
    ++#if SQLITE_ENABLE_HIDDEN_COLUMNS
    ++SQLITE_PRIVATE   void sqlite3ColumnPropertiesFromName(Table*, Column*);
    ++#else
    ++# define sqlite3ColumnPropertiesFromName(T,C) /* no-op */
    ++#endif
    ++SQLITE_PRIVATE void sqlite3AddColumn(Parse*,Token*,Token*);
    + SQLITE_PRIVATE void sqlite3AddNotNull(Parse*, int);
    + SQLITE_PRIVATE void sqlite3AddPrimaryKey(Parse*, ExprList*, int, int, int);
    + SQLITE_PRIVATE void sqlite3AddCheckConstraint(Parse*, Expr*);
    +-SQLITE_PRIVATE void sqlite3AddColumnType(Parse*,Token*);
    +-SQLITE_PRIVATE void sqlite3AddDefaultValue(Parse*,ExprSpan*);
    ++SQLITE_PRIVATE void sqlite3AddDefaultValue(Parse*,Expr*,const char*,const char*);
    + SQLITE_PRIVATE void sqlite3AddCollateType(Parse*, Token*);
    + SQLITE_PRIVATE void sqlite3EndTable(Parse*,Token*,Token*,u8,Select*);
    + SQLITE_PRIVATE int sqlite3ParseUri(const char*,const char*,unsigned int*,
    +                     sqlite3_vfs**,char**,char **);
    + SQLITE_PRIVATE Btree *sqlite3DbNameToBtree(sqlite3*,const char*);
    +-SQLITE_PRIVATE int sqlite3CodeOnce(Parse *);
    + 
    +-#ifdef SQLITE_OMIT_BUILTIN_TEST
    ++#ifdef SQLITE_UNTESTABLE
    + # define sqlite3FaultSim(X) SQLITE_OK
    + #else
    + SQLITE_PRIVATE   int sqlite3FaultSim(int);
    +@@ -13861,7 +17588,7 @@ SQLITE_PRIVATE int sqlite3BitvecSet(Bitvec*, u32);
    + SQLITE_PRIVATE void sqlite3BitvecClear(Bitvec*, u32, void*);
    + SQLITE_PRIVATE void sqlite3BitvecDestroy(Bitvec*);
    + SQLITE_PRIVATE u32 sqlite3BitvecSize(Bitvec*);
    +-#ifndef SQLITE_OMIT_BUILTIN_TEST
    ++#ifndef SQLITE_UNTESTABLE
    + SQLITE_PRIVATE int sqlite3BitvecBuiltinTest(int,int*);
    + #endif
    + 
    +@@ -13908,26 +17635,27 @@ SQLITE_PRIVATE void sqlite3SrcListAssignCursors(Parse*, SrcList*);
    + SQLITE_PRIVATE void sqlite3IdListDelete(sqlite3*, IdList*);
    + SQLITE_PRIVATE void sqlite3SrcListDelete(sqlite3*, SrcList*);
    + SQLITE_PRIVATE Index *sqlite3AllocateIndexObject(sqlite3*,i16,int,char**);
    +-SQLITE_PRIVATE Index *sqlite3CreateIndex(Parse*,Token*,Token*,SrcList*,ExprList*,int,Token*,
    +-                          Expr*, int, int);
    ++SQLITE_PRIVATE void sqlite3CreateIndex(Parse*,Token*,Token*,SrcList*,ExprList*,int,Token*,
    ++                          Expr*, int, int, u8);
    + SQLITE_PRIVATE void sqlite3DropIndex(Parse*, SrcList*, int);
    + SQLITE_PRIVATE int sqlite3Select(Parse*, Select*, SelectDest*);
    + SQLITE_PRIVATE Select *sqlite3SelectNew(Parse*,ExprList*,SrcList*,Expr*,ExprList*,
    +-                         Expr*,ExprList*,u16,Expr*,Expr*);
    ++                         Expr*,ExprList*,u32,Expr*);
    + SQLITE_PRIVATE void sqlite3SelectDelete(sqlite3*, Select*);
    + SQLITE_PRIVATE Table *sqlite3SrcListLookup(Parse*, SrcList*);
    + SQLITE_PRIVATE int sqlite3IsReadOnly(Parse*, Table*, int);
    + SQLITE_PRIVATE void sqlite3OpenTable(Parse*, int iCur, int iDb, Table*, int);
    + #if defined(SQLITE_ENABLE_UPDATE_DELETE_LIMIT) && !defined(SQLITE_OMIT_SUBQUERY)
    +-SQLITE_PRIVATE Expr *sqlite3LimitWhere(Parse*,SrcList*,Expr*,ExprList*,Expr*,Expr*,char*);
    ++SQLITE_PRIVATE Expr *sqlite3LimitWhere(Parse*,SrcList*,Expr*,ExprList*,Expr*,char*);
    + #endif
    +-SQLITE_PRIVATE void sqlite3DeleteFrom(Parse*, SrcList*, Expr*);
    +-SQLITE_PRIVATE void sqlite3Update(Parse*, SrcList*, ExprList*, Expr*, int);
    ++SQLITE_PRIVATE void sqlite3DeleteFrom(Parse*, SrcList*, Expr*, ExprList*, Expr*);
    ++SQLITE_PRIVATE void sqlite3Update(Parse*, SrcList*, ExprList*,Expr*,int,ExprList*,Expr*);
    + SQLITE_PRIVATE WhereInfo *sqlite3WhereBegin(Parse*,SrcList*,Expr*,ExprList*,ExprList*,u16,int);
    + SQLITE_PRIVATE void sqlite3WhereEnd(WhereInfo*);
    +-SQLITE_PRIVATE u64 sqlite3WhereOutputRowCount(WhereInfo*);
    ++SQLITE_PRIVATE LogEst sqlite3WhereOutputRowCount(WhereInfo*);
    + SQLITE_PRIVATE int sqlite3WhereIsDistinct(WhereInfo*);
    + SQLITE_PRIVATE int sqlite3WhereIsOrdered(WhereInfo*);
    ++SQLITE_PRIVATE int sqlite3WhereOrderedInnerLoop(WhereInfo*);
    + SQLITE_PRIVATE int sqlite3WhereIsSorted(WhereInfo*);
    + SQLITE_PRIVATE int sqlite3WhereContinueLabel(WhereInfo*);
    + SQLITE_PRIVATE int sqlite3WhereBreakLabel(WhereInfo*);
    +@@ -13937,6 +17665,7 @@ SQLITE_PRIVATE int sqlite3WhereOkOnePass(WhereInfo*, int*);
    + #define ONEPASS_MULTI    2        /* ONEPASS is valid for multiple rows */
    + SQLITE_PRIVATE void sqlite3ExprCodeLoadIndexColumn(Parse*, Index*, int, int, int);
    + SQLITE_PRIVATE int sqlite3ExprCodeGetColumn(Parse*, Table*, int, int, int, u8);
    ++SQLITE_PRIVATE void sqlite3ExprCodeGetColumnToReg(Parse*, Table*, int, int, int);
    + 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);
    +@@ -13946,8 +17675,9 @@ SQLITE_PRIVATE void sqlite3ExprCacheRemove(Parse*, int, int);
    + SQLITE_PRIVATE void sqlite3ExprCacheClear(Parse*);
    + SQLITE_PRIVATE void sqlite3ExprCacheAffinityChange(Parse*, int, int);
    + SQLITE_PRIVATE void sqlite3ExprCode(Parse*, Expr*, int);
    ++SQLITE_PRIVATE void sqlite3ExprCodeCopy(Parse*, Expr*, int);
    + SQLITE_PRIVATE void sqlite3ExprCodeFactorable(Parse*, Expr*, int);
    +-SQLITE_PRIVATE void sqlite3ExprCodeAtInit(Parse*, Expr*, int, u8);
    ++SQLITE_PRIVATE int sqlite3ExprCodeAtInit(Parse*, Expr*, int);
    + SQLITE_PRIVATE int sqlite3ExprCodeTemp(Parse*, Expr*, int*);
    + SQLITE_PRIVATE int sqlite3ExprCodeTarget(Parse*, Expr*, int);
    + SQLITE_PRIVATE void sqlite3ExprCodeAndCache(Parse*, Expr*, int);
    +@@ -13955,26 +17685,31 @@ SQLITE_PRIVATE int sqlite3ExprCodeExprList(Parse*, ExprList*, int, int, u8);
    + #define SQLITE_ECEL_DUP      0x01  /* Deep, not shallow copies */
    + #define SQLITE_ECEL_FACTOR   0x02  /* Factor out constant terms */
    + #define SQLITE_ECEL_REF      0x04  /* Use ExprList.u.x.iOrderByCol */
    ++#define SQLITE_ECEL_OMITREF  0x08  /* Omit if ExprList.u.x.iOrderByCol */
    + SQLITE_PRIVATE void sqlite3ExprIfTrue(Parse*, Expr*, int, int);
    + SQLITE_PRIVATE void sqlite3ExprIfFalse(Parse*, Expr*, int, int);
    + SQLITE_PRIVATE void sqlite3ExprIfFalseDup(Parse*, Expr*, int, int);
    + SQLITE_PRIVATE Table *sqlite3FindTable(sqlite3*,const char*, const char*);
    +-SQLITE_PRIVATE Table *sqlite3LocateTable(Parse*,int isView,const char*, const char*);
    +-SQLITE_PRIVATE Table *sqlite3LocateTableItem(Parse*,int isView,struct SrcList_item *);
    ++#define LOCATE_VIEW    0x01
    ++#define LOCATE_NOERR   0x02
    ++SQLITE_PRIVATE Table *sqlite3LocateTable(Parse*,u32 flags,const char*, const char*);
    ++SQLITE_PRIVATE Table *sqlite3LocateTableItem(Parse*,u32 flags,struct SrcList_item *);
    + SQLITE_PRIVATE Index *sqlite3FindIndex(sqlite3*,const char*, const char*);
    + SQLITE_PRIVATE void sqlite3UnlinkAndDeleteTable(sqlite3*,int,const char*);
    + SQLITE_PRIVATE void sqlite3UnlinkAndDeleteIndex(sqlite3*,int,const char*);
    +-SQLITE_PRIVATE void sqlite3Vacuum(Parse*);
    +-SQLITE_PRIVATE int sqlite3RunVacuum(char**, sqlite3*);
    ++SQLITE_PRIVATE void sqlite3Vacuum(Parse*,Token*);
    ++SQLITE_PRIVATE int sqlite3RunVacuum(char**, sqlite3*, int);
    + SQLITE_PRIVATE char *sqlite3NameFromToken(sqlite3*, Token*);
    +-SQLITE_PRIVATE int sqlite3ExprCompare(Expr*, Expr*, int);
    ++SQLITE_PRIVATE int sqlite3ExprCompare(Parse*,Expr*, Expr*, int);
    ++SQLITE_PRIVATE int sqlite3ExprCompareSkip(Expr*, Expr*, int);
    + SQLITE_PRIVATE int sqlite3ExprListCompare(ExprList*, ExprList*, int);
    +-SQLITE_PRIVATE int sqlite3ExprImpliesExpr(Expr*, Expr*, int);
    ++SQLITE_PRIVATE int sqlite3ExprImpliesExpr(Parse*,Expr*, Expr*, int);
    + SQLITE_PRIVATE void sqlite3ExprAnalyzeAggregates(NameContext*, Expr*);
    + SQLITE_PRIVATE void sqlite3ExprAnalyzeAggList(NameContext*,ExprList*);
    ++SQLITE_PRIVATE int sqlite3ExprCoveredByIndex(Expr*, int iCur, Index *pIdx);
    + SQLITE_PRIVATE int sqlite3FunctionUsesThisSrc(Expr*, SrcList*);
    + SQLITE_PRIVATE Vdbe *sqlite3GetVdbe(Parse*);
    +-#ifndef SQLITE_OMIT_BUILTIN_TEST
    ++#ifndef SQLITE_UNTESTABLE
    + SQLITE_PRIVATE void sqlite3PrngSaveState(void);
    + SQLITE_PRIVATE void sqlite3PrngRestoreState(void);
    + #endif
    +@@ -13982,15 +17717,18 @@ SQLITE_PRIVATE void sqlite3RollbackAll(sqlite3*,int);
    + SQLITE_PRIVATE void sqlite3CodeVerifySchema(Parse*, int);
    + SQLITE_PRIVATE void sqlite3CodeVerifyNamedSchema(Parse*, const char *zDb);
    + SQLITE_PRIVATE void sqlite3BeginTransaction(Parse*, int);
    +-SQLITE_PRIVATE void sqlite3CommitTransaction(Parse*);
    +-SQLITE_PRIVATE void sqlite3RollbackTransaction(Parse*);
    ++SQLITE_PRIVATE void sqlite3EndTransaction(Parse*,int);
    + SQLITE_PRIVATE void sqlite3Savepoint(Parse*, int, Token*);
    + SQLITE_PRIVATE void sqlite3CloseSavepoints(sqlite3 *);
    + SQLITE_PRIVATE void sqlite3LeaveMutexAndCloseZombie(sqlite3*);
    + SQLITE_PRIVATE int sqlite3ExprIsConstant(Expr*);
    + SQLITE_PRIVATE int sqlite3ExprIsConstantNotJoin(Expr*);
    + SQLITE_PRIVATE int sqlite3ExprIsConstantOrFunction(Expr*, u8);
    ++SQLITE_PRIVATE int sqlite3ExprIsConstantOrGroupBy(Parse*, Expr*, ExprList*);
    + SQLITE_PRIVATE int sqlite3ExprIsTableConstant(Expr*,int);
    ++#ifdef SQLITE_ENABLE_CURSOR_HINTS
    ++SQLITE_PRIVATE int sqlite3ExprContainsSubquery(Expr*);
    ++#endif
    + SQLITE_PRIVATE int sqlite3ExprIsInteger(Expr*, int*);
    + SQLITE_PRIVATE int sqlite3ExprCanBeNull(const Expr*);
    + SQLITE_PRIVATE int sqlite3ExprNeedsNoAffinityChange(const Expr*, char);
    +@@ -14001,9 +17739,14 @@ 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*);
    ++                                     u8,u8,int,int*,int*);
    ++#ifdef SQLITE_ENABLE_NULL_TRIM
    ++SQLITE_PRIVATE   void sqlite3SetMakeRecordP5(Vdbe*,Table*);
    ++#else
    ++# define sqlite3SetMakeRecordP5(A,B)
    ++#endif
    + SQLITE_PRIVATE void sqlite3CompleteInsertion(Parse*,Table*,int,int,int,int*,int,int,int);
    +-SQLITE_PRIVATE int sqlite3OpenTableAndIndices(Parse*, Table*, int, int, u8*, int*, int*);
    ++SQLITE_PRIVATE int sqlite3OpenTableAndIndices(Parse*, Table*, int, u8, int, u8*, int*, int*);
    + SQLITE_PRIVATE void sqlite3BeginWriteOperation(Parse*, int, int);
    + SQLITE_PRIVATE void sqlite3MultiWrite(Parse*);
    + SQLITE_PRIVATE void sqlite3MayAbort(Parse*);
    +@@ -14020,17 +17763,17 @@ SQLITE_PRIVATE void sqlite3SelectSetName(Select*,const char*);
    + #else
    + # define sqlite3SelectSetName(A,B)
    + #endif
    +-SQLITE_PRIVATE void sqlite3FuncDefInsert(FuncDefHash*, FuncDef*);
    +-SQLITE_PRIVATE FuncDef *sqlite3FindFunction(sqlite3*,const char*,int,int,u8,u8);
    +-SQLITE_PRIVATE void sqlite3RegisterBuiltinFunctions(sqlite3*);
    ++SQLITE_PRIVATE void sqlite3InsertBuiltinFuncs(FuncDef*,int);
    ++SQLITE_PRIVATE FuncDef *sqlite3FindFunction(sqlite3*,const char*,int,u8,u8);
    ++SQLITE_PRIVATE void sqlite3RegisterBuiltinFunctions(void);
    + SQLITE_PRIVATE void sqlite3RegisterDateTimeFunctions(void);
    +-SQLITE_PRIVATE void sqlite3RegisterGlobalFunctions(void);
    ++SQLITE_PRIVATE void sqlite3RegisterPerConnectionBuiltinFunctions(sqlite3*);
    + SQLITE_PRIVATE int sqlite3SafetyCheckOk(sqlite3*);
    + SQLITE_PRIVATE int sqlite3SafetyCheckSickOrOk(sqlite3*);
    + SQLITE_PRIVATE void sqlite3ChangeCookie(Parse*, int);
    + 
    + #if !defined(SQLITE_OMIT_VIEW) && !defined(SQLITE_OMIT_TRIGGER)
    +-SQLITE_PRIVATE void sqlite3MaterializeView(Parse*, Table*, Expr*, int);
    ++SQLITE_PRIVATE void sqlite3MaterializeView(Parse*, Table*, Expr*, ExprList*,Expr*,int);
    + #endif
    + 
    + #ifndef SQLITE_OMIT_TRIGGER
    +@@ -14046,11 +17789,14 @@ SQLITE_PRIVATE   void sqlite3CodeRowTrigger(Parse*, Trigger *, int, ExprList*, i
    + SQLITE_PRIVATE   void sqlite3CodeRowTriggerDirect(Parse *, Trigger *, Table *, int, int, int);
    +   void sqliteViewTriggers(Parse*, Table*, Expr*, int, ExprList*);
    + SQLITE_PRIVATE   void sqlite3DeleteTriggerStep(sqlite3*, TriggerStep*);
    +-SQLITE_PRIVATE   TriggerStep *sqlite3TriggerSelectStep(sqlite3*,Select*);
    ++SQLITE_PRIVATE   TriggerStep *sqlite3TriggerSelectStep(sqlite3*,Select*,
    ++                                        const char*,const char*);
    + SQLITE_PRIVATE   TriggerStep *sqlite3TriggerInsertStep(sqlite3*,Token*, IdList*,
    +-                                        Select*,u8);
    +-SQLITE_PRIVATE   TriggerStep *sqlite3TriggerUpdateStep(sqlite3*,Token*,ExprList*, Expr*, u8);
    +-SQLITE_PRIVATE   TriggerStep *sqlite3TriggerDeleteStep(sqlite3*,Token*, Expr*);
    ++                                        Select*,u8,const char*,const char*);
    ++SQLITE_PRIVATE   TriggerStep *sqlite3TriggerUpdateStep(sqlite3*,Token*,ExprList*, Expr*, u8,
    ++                                        const char*,const char*);
    ++SQLITE_PRIVATE   TriggerStep *sqlite3TriggerDeleteStep(sqlite3*,Token*, Expr*,
    ++                                        const char*,const char*);
    + SQLITE_PRIVATE   void sqlite3DeleteTrigger(sqlite3*, Trigger*);
    + SQLITE_PRIVATE   void sqlite3UnlinkAndDeleteTrigger(sqlite3*,int,const char*);
    + SQLITE_PRIVATE   u32 sqlite3TriggerColmask(Parse*,Trigger*,ExprList*,int,int,Table*,int);
    +@@ -14095,7 +17841,9 @@ SQLITE_PRIVATE int sqlite3FixTriggerStep(DbFixer*, TriggerStep*);
    + SQLITE_PRIVATE int sqlite3AtoF(const char *z, double*, int, u8);
    + SQLITE_PRIVATE int sqlite3GetInt32(const char *, int*);
    + SQLITE_PRIVATE int sqlite3Atoi(const char*);
    ++#ifndef SQLITE_OMIT_UTF16
    + SQLITE_PRIVATE int sqlite3Utf16ByteLen(const void *pData, int nChar);
    ++#endif
    + SQLITE_PRIVATE int sqlite3Utf8CharLen(const char *pData, int nByte);
    + SQLITE_PRIVATE u32 sqlite3Utf8Read(const u8**);
    + SQLITE_PRIVATE LogEst sqlite3LogEst(u64);
    +@@ -14103,7 +17851,14 @@ SQLITE_PRIVATE LogEst sqlite3LogEstAdd(LogEst,LogEst);
    + #ifndef SQLITE_OMIT_VIRTUALTABLE
    + SQLITE_PRIVATE LogEst sqlite3LogEstFromDouble(double);
    + #endif
    ++#if defined(SQLITE_ENABLE_STMT_SCANSTATUS) || \
    ++    defined(SQLITE_ENABLE_STAT3_OR_STAT4) || \
    ++    defined(SQLITE_EXPLAIN_ESTIMATED_ROWS)
    + SQLITE_PRIVATE u64 sqlite3LogEstToInt(LogEst);
    ++#endif
    ++SQLITE_PRIVATE VList *sqlite3VListAdd(sqlite3*,VList*,const char*,int,int);
    ++SQLITE_PRIVATE const char *sqlite3VListNumToName(VList*,int);
    ++SQLITE_PRIVATE int sqlite3VListNameToNum(VList*,const char*,int);
    + 
    + /*
    + ** Routines to read and write variable-length integers.  These used to
    +@@ -14133,11 +17888,13 @@ SQLITE_PRIVATE const char *sqlite3IndexAffinityStr(sqlite3*, Index*);
    + SQLITE_PRIVATE void sqlite3TableAffinity(Vdbe*, Table*, int);
    + SQLITE_PRIVATE char sqlite3CompareAffinity(Expr *pExpr, char aff2);
    + SQLITE_PRIVATE int sqlite3IndexAffinityOk(Expr *pExpr, char idx_affinity);
    ++SQLITE_PRIVATE char sqlite3TableColumnAffinity(Table*,int);
    + 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 sqlite3ErrorWithMsg(sqlite3*, int, const char*,...);
    + SQLITE_PRIVATE void sqlite3Error(sqlite3*,int);
    ++SQLITE_PRIVATE void sqlite3SystemError(sqlite3*,int);
    + SQLITE_PRIVATE void *sqlite3HexToBlob(sqlite3*, const char *z, int n);
    + SQLITE_PRIVATE u8 sqlite3HexToInt(int h);
    + SQLITE_PRIVATE int sqlite3TwoPartName(Parse *, Token *, Token *, Token **);
    +@@ -14151,6 +17908,8 @@ 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 CollSeq *sqlite3ExprNNCollSeq(Parse *pParse, Expr *pExpr);
    ++SQLITE_PRIVATE int sqlite3ExprCollSeqMatch(Parse*,Expr*,Expr*);
    + SQLITE_PRIVATE Expr *sqlite3ExprAddCollateToken(Parse *pParse, Expr*, const Token*, int);
    + SQLITE_PRIVATE Expr *sqlite3ExprAddCollateString(Parse*,Expr*,const char*);
    + SQLITE_PRIVATE Expr *sqlite3ExprSkipCollate(Expr*);
    +@@ -14170,21 +17929,24 @@ SQLITE_PRIVATE u8 sqlite3GetBoolean(const char *z,u8);
    + 
    + SQLITE_PRIVATE const void *sqlite3ValueText(sqlite3_value*, u8);
    + SQLITE_PRIVATE int sqlite3ValueBytes(sqlite3_value*, u8);
    +-SQLITE_PRIVATE void sqlite3ValueSetStr(sqlite3_value*, int, const void *,u8, 
    ++SQLITE_PRIVATE void sqlite3ValueSetStr(sqlite3_value*, int, const void *,u8,
    +                         void(*)(void*));
    + SQLITE_PRIVATE void sqlite3ValueSetNull(sqlite3_value*);
    + SQLITE_PRIVATE void sqlite3ValueFree(sqlite3_value*);
    + SQLITE_PRIVATE sqlite3_value *sqlite3ValueNew(sqlite3 *);
    ++#ifndef SQLITE_OMIT_UTF16
    + SQLITE_PRIVATE char *sqlite3Utf16to8(sqlite3 *, const void*, int, u8);
    ++#endif
    + SQLITE_PRIVATE int sqlite3ValueFromExpr(sqlite3 *, Expr *, u8, u8, sqlite3_value **);
    + SQLITE_PRIVATE void sqlite3ValueApplyAffinity(sqlite3_value *, u8, u8);
    + #ifndef SQLITE_AMALGAMATION
    + SQLITE_PRIVATE const unsigned char sqlite3OpcodeProperty[];
    ++SQLITE_PRIVATE const char sqlite3StrBINARY[];
    + SQLITE_PRIVATE const unsigned char sqlite3UpperToLower[];
    + SQLITE_PRIVATE const unsigned char sqlite3CtypeMap[];
    + SQLITE_PRIVATE const Token sqlite3IntTokens[];
    + SQLITE_PRIVATE SQLITE_WSD struct Sqlite3Config sqlite3Config;
    +-SQLITE_PRIVATE SQLITE_WSD FuncDefHash sqlite3GlobalFunctions;
    ++SQLITE_PRIVATE FuncDefHash sqlite3BuiltinFunctions;
    + #ifndef SQLITE_OMIT_WSD
    + SQLITE_PRIVATE int sqlite3PendingByte;
    + #endif
    +@@ -14196,7 +17958,7 @@ SQLITE_PRIVATE void sqlite3AlterRenameTable(Parse*, SrcList*, Token*);
    + SQLITE_PRIVATE int sqlite3GetToken(const unsigned char *, int *);
    + SQLITE_PRIVATE void sqlite3NestedParse(Parse*, const char*, ...);
    + SQLITE_PRIVATE void sqlite3ExpirePreparedStatements(sqlite3*);
    +-SQLITE_PRIVATE int sqlite3CodeSubselect(Parse *, Expr *, int, int);
    ++SQLITE_PRIVATE int sqlite3CodeSubselect(Parse*, Expr *, int, int);
    + SQLITE_PRIVATE void sqlite3SelectPrep(Parse*, Select*, NameContext*);
    + SQLITE_PRIVATE void sqlite3SelectWrongNumTermsError(Parse *pParse, Select *p);
    + SQLITE_PRIVATE int sqlite3MatchSpanName(const char*, const char*, const char*, const char*);
    +@@ -14219,7 +17981,6 @@ SQLITE_PRIVATE void sqlite3DeleteIndexSamples(sqlite3*,Index*);
    + SQLITE_PRIVATE void sqlite3DefaultRowEst(Index*);
    + SQLITE_PRIVATE void sqlite3RegisterLikeFunctions(sqlite3*, int);
    + SQLITE_PRIVATE int sqlite3IsLikeFunction(sqlite3*,Expr*,int*,char*);
    +-SQLITE_PRIVATE void sqlite3MinimumFileFormat(Parse*, int, int);
    + SQLITE_PRIVATE void sqlite3SchemaClear(void *);
    + SQLITE_PRIVATE Schema *sqlite3SchemaGet(sqlite3 *, Btree *);
    + SQLITE_PRIVATE int sqlite3SchemaToIndex(sqlite3 *db, Schema *);
    +@@ -14230,11 +17991,13 @@ SQLITE_PRIVATE KeyInfo *sqlite3KeyInfoOfIndex(Parse*, Index*);
    + #ifdef SQLITE_DEBUG
    + SQLITE_PRIVATE int sqlite3KeyInfoIsWriteable(KeyInfo*);
    + #endif
    +-SQLITE_PRIVATE int sqlite3CreateFunc(sqlite3 *, const char *, int, int, void *, 
    ++SQLITE_PRIVATE int sqlite3CreateFunc(sqlite3 *, const char *, int, int, void *,
    +   void (*)(sqlite3_context*,int,sqlite3_value **),
    +   void (*)(sqlite3_context*,int,sqlite3_value **), void (*)(sqlite3_context*),
    +   FuncDestructor *pDestructor
    + );
    ++SQLITE_PRIVATE void sqlite3OomFault(sqlite3*);
    ++SQLITE_PRIVATE void sqlite3OomClear(sqlite3*);
    + SQLITE_PRIVATE int sqlite3ApiExit(sqlite3 *db, int);
    + SQLITE_PRIVATE int sqlite3OpenTempDatabase(Parse *);
    + 
    +@@ -14250,19 +18013,29 @@ SQLITE_PRIVATE Expr *sqlite3CreateColumnExpr(sqlite3 *, SrcList *, int, int);
    + SQLITE_PRIVATE void sqlite3BackupRestart(sqlite3_backup *);
    + SQLITE_PRIVATE void sqlite3BackupUpdate(sqlite3_backup *, Pgno, const u8 *);
    + 
    ++#ifndef SQLITE_OMIT_SUBQUERY
    ++SQLITE_PRIVATE int sqlite3ExprCheckIN(Parse*, Expr*);
    ++#else
    ++# define sqlite3ExprCheckIN(x,y) SQLITE_OK
    ++#endif
    ++
    + #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 sqlite3Stat4ProbeSetValue(
    ++    Parse*,Index*,UnpackedRecord**,Expr*,int,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**);
    ++SQLITE_PRIVATE char sqlite3IndexColumnAffinity(sqlite3*, Index*, int);
    + #endif
    + 
    + /*
    + ** The interface to the LEMON-generated parser
    + */
    +-SQLITE_PRIVATE void *sqlite3ParserAlloc(void*(*)(u64));
    +-SQLITE_PRIVATE void sqlite3ParserFree(void*, void(*)(void*));
    ++#ifndef SQLITE_AMALGAMATION
    ++SQLITE_PRIVATE   void *sqlite3ParserAlloc(void*(*)(u64));
    ++SQLITE_PRIVATE   void sqlite3ParserFree(void*, void(*)(void*));
    ++#endif
    + SQLITE_PRIVATE void sqlite3Parser(void*, int, Token, Parse*);
    + #ifdef YYTRACKMAXSTACKDEPTH
    + SQLITE_PRIVATE   int sqlite3ParserStackPeak(void*);
    +@@ -14291,7 +18064,7 @@ SQLITE_PRIVATE   int sqlite3Utf8To8(unsigned char*);
    + #  define sqlite3VtabRollback(X)
    + #  define sqlite3VtabCommit(X)
    + #  define sqlite3VtabInSync(db) 0
    +-#  define sqlite3VtabLock(X) 
    ++#  define sqlite3VtabLock(X)
    + #  define sqlite3VtabUnlock(X)
    + #  define sqlite3VtabUnlockList(X)
    + #  define sqlite3VtabSavepoint(X, Y, Z) SQLITE_OK
    +@@ -14308,6 +18081,13 @@ SQLITE_PRIVATE    void sqlite3VtabUnlockList(sqlite3*);
    + SQLITE_PRIVATE    int sqlite3VtabSavepoint(sqlite3 *, int, int);
    + SQLITE_PRIVATE    void sqlite3VtabImportErrmsg(Vdbe*, sqlite3_vtab*);
    + SQLITE_PRIVATE    VTable *sqlite3GetVTable(sqlite3*, Table*);
    ++SQLITE_PRIVATE    Module *sqlite3VtabCreateModule(
    ++     sqlite3*,
    ++     const char*,
    ++     const sqlite3_module*,
    ++     void*,
    ++     void(*)(void*)
    ++   );
    + #  define sqlite3VtabInSync(db) ((db)->nVTrans>0 && (db)->aVTrans==0)
    + #endif
    + SQLITE_PRIVATE int sqlite3VtabEponymousTableInit(Parse*,Module*);
    +@@ -14349,7 +18129,7 @@ SQLITE_PRIVATE   void sqlite3WithPush(Parse*, With*, u8);
    + ** no-op macros if OMIT_FOREIGN_KEY is defined. In this case no foreign
    + ** key functionality is available. If OMIT_TRIGGER is defined but
    + ** OMIT_FOREIGN_KEY is not, only some of the functions are no-oped. In
    +-** this case foreign keys are parsed, but no other functionality is 
    ++** this case foreign keys are parsed, but no other functionality is
    + ** provided (enforcement of FK constraints requires the triggers sub-system).
    + */
    + #if !defined(SQLITE_OMIT_FOREIGN_KEY) && !defined(SQLITE_OMIT_TRIGGER)
    +@@ -14365,6 +18145,7 @@ SQLITE_PRIVATE   FKey *sqlite3FkReferences(Table *);
    +   #define sqlite3FkDropTable(a,b,c)
    +   #define sqlite3FkOldmask(a,b)         0
    +   #define sqlite3FkRequired(a,b,c,d)    0
    ++  #define sqlite3FkReferences(a)        0
    + #endif
    + #ifndef SQLITE_OMIT_FOREIGN_KEY
    + SQLITE_PRIVATE   void sqlite3FkDelete(sqlite3 *, Table*);
    +@@ -14383,10 +18164,10 @@ SQLITE_PRIVATE   int sqlite3FkLocateIndex(Parse*,Table*,FKey*,Index**,int**);
    + 
    + /*
    + ** The interface to the code in fault.c used for identifying "benign"
    +-** malloc failures. This is only present if SQLITE_OMIT_BUILTIN_TEST
    ++** malloc failures. This is only present if SQLITE_UNTESTABLE
    + ** is not defined.
    + */
    +-#ifndef SQLITE_OMIT_BUILTIN_TEST
    ++#ifndef SQLITE_UNTESTABLE
    + SQLITE_PRIVATE   void sqlite3BeginBenignMalloc(void);
    + SQLITE_PRIVATE   void sqlite3EndBenignMalloc(void);
    + #else
    +@@ -14408,21 +18189,17 @@ SQLITE_PRIVATE   void sqlite3EndBenignMalloc(void);
    + #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*);
    ++SQLITE_PRIVATE int sqlite3FindInIndex(Parse *, Expr *, u32, int*, int*);
    + 
    +-#ifdef SQLITE_ENABLE_ATOMIC_WRITE
    +-SQLITE_PRIVATE   int sqlite3JournalOpen(sqlite3_vfs *, const char *, sqlite3_file *, int, int);
    +-SQLITE_PRIVATE   int sqlite3JournalSize(sqlite3_vfs *);
    ++SQLITE_PRIVATE int sqlite3JournalOpen(sqlite3_vfs *, const char *, sqlite3_file *, int, int);
    ++SQLITE_PRIVATE int sqlite3JournalSize(sqlite3_vfs *);
    ++#if defined(SQLITE_ENABLE_ATOMIC_WRITE) \
    ++ || defined(SQLITE_ENABLE_BATCH_ATOMIC_WRITE)
    + SQLITE_PRIVATE   int sqlite3JournalCreate(sqlite3_file *);
    +-SQLITE_PRIVATE   int sqlite3JournalExists(sqlite3_file *p);
    +-#else
    +-  #define sqlite3JournalSize(pVfs) ((pVfs)->szOsFile)
    +-  #define sqlite3JournalExists(p) 1
    + #endif
    + 
    ++SQLITE_PRIVATE int sqlite3JournalIsInMemory(sqlite3_file *p);
    + SQLITE_PRIVATE void sqlite3MemJournalOpen(sqlite3_file *);
    +-SQLITE_PRIVATE int sqlite3MemJournalSize(void);
    +-SQLITE_PRIVATE int sqlite3IsMemJournal(sqlite3_file *);
    + 
    + SQLITE_PRIVATE void sqlite3ExprSetHeightAndFlags(Parse *pParse, Expr *p);
    + #if SQLITE_MAX_EXPR_DEPTH>0
    +@@ -14449,11 +18226,14 @@ SQLITE_PRIVATE   void sqlite3ConnectionClosed(sqlite3 *db);
    + #ifdef SQLITE_DEBUG
    + SQLITE_PRIVATE   void sqlite3ParserTrace(FILE*, char *);
    + #endif
    ++#if defined(YYCOVERAGE)
    ++SQLITE_PRIVATE   int sqlite3ParserCoverage(FILE*);
    ++#endif
    + 
    + /*
    + ** If the SQLITE_ENABLE IOTRACE exists then the global variable
    + ** sqlite3IoTrace is a pointer to a printf-like routine used to
    +-** print I/O tracing messages. 
    ++** print I/O tracing messages.
    + */
    + #ifdef SQLITE_ENABLE_IOTRACE
    + # define IOTRACE(A)  if( sqlite3IoTrace ){ sqlite3IoTrace A; }
    +@@ -14487,7 +18267,7 @@ SQLITE_API SQLITE_EXTERN void (SQLITE_CDECL *sqlite3IoTrace)(const char*,...);
    + ** that allocations that might have been satisfied by lookaside are not
    + ** passed back to non-lookaside free() routines.  Asserts such as the
    + ** example above are placed on the non-lookaside free() routines to verify
    +-** this constraint. 
    ++** this constraint.
    + **
    + ** All of this is no-op for a production build.  It only comes into
    + ** play when the SQLITE_MEMDEBUG compile-time option is used.
    +@@ -14503,8 +18283,7 @@ SQLITE_PRIVATE   int sqlite3MemdebugNoType(void*,u8);
    + #endif
    + #define MEMTYPE_HEAP       0x01  /* General heap allocations */
    + #define MEMTYPE_LOOKASIDE  0x02  /* Heap that might have been lookaside */
    +-#define MEMTYPE_SCRATCH    0x04  /* Scratch allocations */
    +-#define MEMTYPE_PCACHE     0x08  /* Page cache allocations */
    ++#define MEMTYPE_PCACHE     0x04  /* Page cache allocations */
    + 
    + /*
    + ** Threading interface
    +@@ -14514,11 +18293,24 @@ SQLITE_PRIVATE int sqlite3ThreadCreate(SQLiteThread**,void*(*)(void*),void*);
    + SQLITE_PRIVATE int sqlite3ThreadJoin(SQLiteThread*, void**);
    + #endif
    + 
    ++#if defined(SQLITE_ENABLE_DBPAGE_VTAB) || defined(SQLITE_TEST)
    ++SQLITE_PRIVATE int sqlite3DbpageRegister(sqlite3*);
    ++#endif
    + #if defined(SQLITE_ENABLE_DBSTAT_VTAB) || defined(SQLITE_TEST)
    + SQLITE_PRIVATE int sqlite3DbstatRegister(sqlite3*);
    + #endif
    + 
    +-#endif /* _SQLITEINT_H_ */
    ++SQLITE_PRIVATE int sqlite3ExprVectorSize(Expr *pExpr);
    ++SQLITE_PRIVATE int sqlite3ExprIsVector(Expr *pExpr);
    ++SQLITE_PRIVATE Expr *sqlite3VectorFieldSubexpr(Expr*, int);
    ++SQLITE_PRIVATE Expr *sqlite3ExprForVectorField(Parse*,Expr*,int);
    ++SQLITE_PRIVATE void sqlite3VectorErrorMsg(Parse*, Expr*);
    ++
    ++#ifndef SQLITE_OMIT_COMPILEOPTION_DIAGS
    ++SQLITE_PRIVATE const char **sqlite3CompileOptions(int *pnOpt);
    ++#endif
    ++
    ++#endif /* SQLITEINT_H */
    + 
    + /************** End of sqliteInt.h *******************************************/
    + /************** Begin file global.c ******************************************/
    +@@ -14594,6 +18386,7 @@ SQLITE_PRIVATE const unsigned char sqlite3UpperToLower[] = {
    + **   isxdigit()                       0x08
    + **   toupper()                        0x20
    + **   SQLite identifier character      0x40
    ++**   Quote character                  0x80
    + **
    + ** Bit 0x20 is set if the mapped character requires translation to upper
    + ** case. i.e. if the character is a lower-case ASCII character.
    +@@ -14602,16 +18395,13 @@ SQLITE_PRIVATE const unsigned char sqlite3UpperToLower[] = {
    + **
    + **   (x & ~(map[x]&0x20))
    + **
    +-** Standard function tolower() is implemented using the sqlite3UpperToLower[]
    ++** The equivalent of tolower() is implemented using the sqlite3UpperToLower[]
    + ** array. tolower() is used more often than toupper() by SQLite.
    + **
    +-** Bit 0x40 is set if the character non-alphanumeric and can be used in an 
    ++** Bit 0x40 is set if the character is non-alphanumeric and can be used in an 
    + ** SQLite identifier.  Identifiers are alphanumerics, "_", "$", and any
    + ** non-ASCII UTF character. Hence the test for whether or not a character is
    + ** part of an identifier is 0x46.
    +-**
    +-** SQLite's versions are identical to the standard versions assuming a
    +-** locale of "C". They are implemented as macros in sqliteInt.h.
    + */
    + #ifdef SQLITE_ASCII
    + SQLITE_PRIVATE const unsigned char sqlite3CtypeMap[256] = {
    +@@ -14619,7 +18409,7 @@ SQLITE_PRIVATE const unsigned char sqlite3CtypeMap[256] = {
    +   0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00,  /* 08..0f    ........ */
    +   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,  /* 10..17    ........ */
    +   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,  /* 18..1f    ........ */
    +-  0x01, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00,  /* 20..27     !"#$%&' */
    ++  0x01, 0x00, 0x80, 0x00, 0x40, 0x00, 0x00, 0x80,  /* 20..27     !"#$%&' */
    +   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,  /* 28..2f    ()*+,-./ */
    +   0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c,  /* 30..37    01234567 */
    +   0x0c, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,  /* 38..3f    89:;<=>? */
    +@@ -14627,8 +18417,8 @@ SQLITE_PRIVATE const unsigned char sqlite3CtypeMap[256] = {
    +   0x00, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x02,  /* 40..47    @ABCDEFG */
    +   0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02,  /* 48..4f    HIJKLMNO */
    +   0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02,  /* 50..57    PQRSTUVW */
    +-  0x02, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00, 0x40,  /* 58..5f    XYZ[\]^_ */
    +-  0x00, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x22,  /* 60..67    `abcdefg */
    ++  0x02, 0x02, 0x02, 0x80, 0x00, 0x00, 0x00, 0x40,  /* 58..5f    XYZ[\]^_ */
    ++  0x80, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x22,  /* 60..67    `abcdefg */
    +   0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22,  /* 68..6f    hijklmno */
    +   0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22,  /* 70..77    pqrstuvw */
    +   0x22, 0x22, 0x22, 0x00, 0x00, 0x00, 0x00, 0x00,  /* 78..7f    xyz{|}~. */
    +@@ -14663,9 +18453,16 @@ SQLITE_PRIVATE const unsigned char sqlite3CtypeMap[256] = {
    + ** EVIDENCE-OF: R-43642-56306 By default, URI handling is globally
    + ** disabled. The default value may be changed by compiling with the
    + ** SQLITE_USE_URI symbol defined.
    ++**
    ++** URI filenames are enabled by default if SQLITE_HAS_CODEC is
    ++** enabled.
    + */
    + #ifndef SQLITE_USE_URI
    +-# define  SQLITE_USE_URI 0
    ++# ifdef SQLITE_HAS_CODEC
    ++#  define SQLITE_USE_URI 1
    ++# else
    ++#  define SQLITE_USE_URI 0
    ++# endif
    + #endif
    + 
    + /* EVIDENCE-OF: R-38720-18127 The default setting is determined by the
    +@@ -14683,6 +18480,31 @@ SQLITE_PRIVATE const unsigned char sqlite3CtypeMap[256] = {
    + # define SQLITE_SORTER_PMASZ 250
    + #endif
    + 
    ++/* Statement journals spill to disk when their size exceeds the following
    ++** threshold (in bytes). 0 means that statement journals are created and
    ++** written to disk immediately (the default behavior for SQLite versions
    ++** before 3.12.0).  -1 means always keep the entire statement journal in
    ++** memory.  (The statement journal is also always held entirely in memory
    ++** if journal_mode=MEMORY or if temp_store=MEMORY, regardless of this
    ++** setting.)
    ++*/
    ++#ifndef SQLITE_STMTJRNL_SPILL 
    ++# define SQLITE_STMTJRNL_SPILL (64*1024)
    ++#endif
    ++
    ++/*
    ++** The default lookaside-configuration, the format "SZ,N".  SZ is the
    ++** number of bytes in each lookaside slot (should be a multiple of 8)
    ++** and N is the number of slots.  The lookaside-configuration can be
    ++** changed as start-time using sqlite3_config(SQLITE_CONFIG_LOOKASIDE)
    ++** or at run-time for an individual database connection using
    ++** sqlite3_db_config(db, SQLITE_DBCONFIG_LOOKASIDE);
    ++*/
    ++#ifndef SQLITE_DEFAULT_LOOKASIDE
    ++# define SQLITE_DEFAULT_LOOKASIDE 1200,100
    ++#endif
    ++
    ++
    + /*
    + ** The following singleton contains the global configuration for
    + ** the SQLite library.
    +@@ -14693,10 +18515,11 @@ SQLITE_PRIVATE SQLITE_WSD struct Sqlite3Config sqlite3Config = {
    +    SQLITE_THREADSAFE==1,      /* bFullMutex */
    +    SQLITE_USE_URI,            /* bOpenUri */
    +    SQLITE_ALLOW_COVERING_INDEX_SCAN,   /* bUseCis */
    ++   0,                         /* bSmallMalloc */
    +    0x7ffffffe,                /* mxStrlen */
    +    0,                         /* neverCorrupt */
    +-   128,                       /* szLookaside */
    +-   500,                       /* nLookaside */
    ++   SQLITE_DEFAULT_LOOKASIDE,  /* szLookaside, nLookaside */
    ++   SQLITE_STMTJRNL_SPILL,     /* nStmtSpill */
    +    {0,0,0,0,0,0,0,0},         /* m */
    +    {0,0,0,0,0,0,0,0,0},       /* mutex */
    +    {0,0,0,0,0,0,0,0,0,0,0,0,0},/* pcache2 */
    +@@ -14705,9 +18528,6 @@ SQLITE_PRIVATE SQLITE_WSD struct Sqlite3Config sqlite3Config = {
    +    0, 0,                      /* mnHeap, mxHeap */
    +    SQLITE_DEFAULT_MMAP_SIZE,  /* szMmap */
    +    SQLITE_MAX_MMAP_SIZE,      /* mxMmap */
    +-   (void*)0,                  /* pScratch */
    +-   0,                         /* szScratch */
    +-   0,                         /* nScratch */
    +    (void*)0,                  /* pPage */
    +    0,                         /* szPage */
    +    SQLITE_DEFAULT_PCACHE_INITSZ, /* nPage */
    +@@ -14732,10 +18552,11 @@ SQLITE_PRIVATE SQLITE_WSD struct Sqlite3Config sqlite3Config = {
    +    0,                         /* xVdbeBranch */
    +    0,                         /* pVbeBranchArg */
    + #endif
    +-#ifndef SQLITE_OMIT_BUILTIN_TEST
    ++#ifndef SQLITE_UNTESTABLE
    +    0,                         /* xTestCallback */
    + #endif
    +-   0                          /* bLocaltimeFault */
    ++   0,                         /* bLocaltimeFault */
    ++   0x7ffffffe                 /* iOnceResetThreshold */
    + };
    + 
    + /*
    +@@ -14743,7 +18564,7 @@ SQLITE_PRIVATE SQLITE_WSD struct Sqlite3Config sqlite3Config = {
    + ** database connections.  After initialization, this table is
    + ** read-only.
    + */
    +-SQLITE_PRIVATE SQLITE_WSD FuncDefHash sqlite3GlobalFunctions;
    ++SQLITE_PRIVATE FuncDefHash sqlite3BuiltinFunctions;
    + 
    + /*
    + ** Constant tokens for values 0 and 1.
    +@@ -14758,7 +18579,7 @@ SQLITE_PRIVATE const Token sqlite3IntTokens[] = {
    + ** The value of the "pending" byte must be 0x40000000 (1 byte past the
    + ** 1-gibabyte boundary) in a compatible database.  SQLite never uses
    + ** the database page that contains the pending byte.  It never attempts
    +-** to read or write that page.  The pending byte page is set assign
    ++** to read or write that page.  The pending byte page is set aside
    + ** for use by the VFS layers as space for managing file locks.
    + **
    + ** During testing, it is often desirable to move the pending byte to
    +@@ -14785,446 +18606,12 @@ SQLITE_PRIVATE int sqlite3PendingByte = 0x40000000;
    + */
    + SQLITE_PRIVATE const unsigned char sqlite3OpcodeProperty[] = OPFLG_INITIALIZER;
    + 
    +-/************** End of global.c **********************************************/
    +-/************** Begin file ctime.c *******************************************/
    +-/*
    +-** 2010 February 23
    +-**
    +-** 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 implements routines used to report what compile-time options
    +-** SQLite was built with.
    +-*/
    +-
    +-#ifndef SQLITE_OMIT_COMPILEOPTION_DIAGS
    +-
    +-/* #include "sqliteInt.h" */
    +-
    +-/*
    +-** An array of names of all compile-time options.  This array should 
    +-** be sorted A-Z.
    +-**
    +-** This array looks large, but in a typical installation actually uses
    +-** only a handful of compile-time options, so most times this array is usually
    +-** rather short and uses little memory space.
    +-*/
    +-static const char * const azCompileOpt[] = {
    +-
    +-/* These macros are provided to "stringify" the value of the define
    +-** for those options in which the value is meaningful. */
    +-#define CTIMEOPT_VAL_(opt) #opt
    +-#define CTIMEOPT_VAL(opt) CTIMEOPT_VAL_(opt)
    +-
    +-#if SQLITE_32BIT_ROWID
    +-  "32BIT_ROWID",
    +-#endif
    +-#if SQLITE_4_BYTE_ALIGNED_MALLOC
    +-  "4_BYTE_ALIGNED_MALLOC",
    +-#endif
    +-#if SQLITE_CASE_SENSITIVE_LIKE
    +-  "CASE_SENSITIVE_LIKE",
    +-#endif
    +-#if SQLITE_CHECK_PAGES
    +-  "CHECK_PAGES",
    +-#endif
    +-#if SQLITE_COVERAGE_TEST
    +-  "COVERAGE_TEST",
    +-#endif
    +-#if SQLITE_DEBUG
    +-  "DEBUG",
    +-#endif
    +-#if SQLITE_DEFAULT_LOCKING_MODE
    +-  "DEFAULT_LOCKING_MODE=" CTIMEOPT_VAL(SQLITE_DEFAULT_LOCKING_MODE),
    +-#endif
    +-#if defined(SQLITE_DEFAULT_MMAP_SIZE) && !defined(SQLITE_DEFAULT_MMAP_SIZE_xc)
    +-  "DEFAULT_MMAP_SIZE=" CTIMEOPT_VAL(SQLITE_DEFAULT_MMAP_SIZE),
    +-#endif
    +-#if SQLITE_DISABLE_DIRSYNC
    +-  "DISABLE_DIRSYNC",
    +-#endif
    +-#if SQLITE_DISABLE_LFS
    +-  "DISABLE_LFS",
    +-#endif
    +-#if SQLITE_ENABLE_API_ARMOR
    +-  "ENABLE_API_ARMOR",
    +-#endif
    +-#if SQLITE_ENABLE_ATOMIC_WRITE
    +-  "ENABLE_ATOMIC_WRITE",
    +-#endif
    +-#if SQLITE_ENABLE_CEROD
    +-  "ENABLE_CEROD",
    +-#endif
    +-#if SQLITE_ENABLE_COLUMN_METADATA
    +-  "ENABLE_COLUMN_METADATA",
    +-#endif
    +-#if SQLITE_ENABLE_DBSTAT_VTAB
    +-  "ENABLE_DBSTAT_VTAB",
    +-#endif
    +-#if SQLITE_ENABLE_EXPENSIVE_ASSERT
    +-  "ENABLE_EXPENSIVE_ASSERT",
    +-#endif
    +-#if SQLITE_ENABLE_FTS1
    +-  "ENABLE_FTS1",
    +-#endif
    +-#if SQLITE_ENABLE_FTS2
    +-  "ENABLE_FTS2",
    +-#endif
    +-#if SQLITE_ENABLE_FTS3
    +-  "ENABLE_FTS3",
    +-#endif
    +-#if SQLITE_ENABLE_FTS3_PARENTHESIS
    +-  "ENABLE_FTS3_PARENTHESIS",
    +-#endif
    +-#if SQLITE_ENABLE_FTS4
    +-  "ENABLE_FTS4",
    +-#endif
    +-#if SQLITE_ENABLE_FTS5
    +-  "ENABLE_FTS5",
    +-#endif
    +-#if SQLITE_ENABLE_ICU
    +-  "ENABLE_ICU",
    +-#endif
    +-#if SQLITE_ENABLE_IOTRACE
    +-  "ENABLE_IOTRACE",
    +-#endif
    +-#if SQLITE_ENABLE_JSON1
    +-  "ENABLE_JSON1",
    +-#endif
    +-#if SQLITE_ENABLE_LOAD_EXTENSION
    +-  "ENABLE_LOAD_EXTENSION",
    +-#endif
    +-#if SQLITE_ENABLE_LOCKING_STYLE
    +-  "ENABLE_LOCKING_STYLE=" CTIMEOPT_VAL(SQLITE_ENABLE_LOCKING_STYLE),
    +-#endif
    +-#if SQLITE_ENABLE_MEMORY_MANAGEMENT
    +-  "ENABLE_MEMORY_MANAGEMENT",
    +-#endif
    +-#if SQLITE_ENABLE_MEMSYS3
    +-  "ENABLE_MEMSYS3",
    +-#endif
    +-#if SQLITE_ENABLE_MEMSYS5
    +-  "ENABLE_MEMSYS5",
    +-#endif
    +-#if SQLITE_ENABLE_OVERSIZE_CELL_CHECK
    +-  "ENABLE_OVERSIZE_CELL_CHECK",
    +-#endif
    +-#if SQLITE_ENABLE_RTREE
    +-  "ENABLE_RTREE",
    +-#endif
    +-#if defined(SQLITE_ENABLE_STAT4)
    +-  "ENABLE_STAT4",
    +-#elif defined(SQLITE_ENABLE_STAT3)
    +-  "ENABLE_STAT3",
    +-#endif
    +-#if SQLITE_ENABLE_UNLOCK_NOTIFY
    +-  "ENABLE_UNLOCK_NOTIFY",
    +-#endif
    +-#if SQLITE_ENABLE_UPDATE_DELETE_LIMIT
    +-  "ENABLE_UPDATE_DELETE_LIMIT",
    +-#endif
    +-#if SQLITE_HAS_CODEC
    +-  "HAS_CODEC",
    +-#endif
    +-#if HAVE_ISNAN || SQLITE_HAVE_ISNAN
    +-  "HAVE_ISNAN",
    +-#endif
    +-#if SQLITE_HOMEGROWN_RECURSIVE_MUTEX
    +-  "HOMEGROWN_RECURSIVE_MUTEX",
    +-#endif
    +-#if SQLITE_IGNORE_AFP_LOCK_ERRORS
    +-  "IGNORE_AFP_LOCK_ERRORS",
    +-#endif
    +-#if SQLITE_IGNORE_FLOCK_LOCK_ERRORS
    +-  "IGNORE_FLOCK_LOCK_ERRORS",
    +-#endif
    +-#ifdef SQLITE_INT64_TYPE
    +-  "INT64_TYPE",
    +-#endif
    +-#if SQLITE_LOCK_TRACE
    +-  "LOCK_TRACE",
    +-#endif
    +-#if defined(SQLITE_MAX_MMAP_SIZE) && !defined(SQLITE_MAX_MMAP_SIZE_xc)
    +-  "MAX_MMAP_SIZE=" CTIMEOPT_VAL(SQLITE_MAX_MMAP_SIZE),
    +-#endif
    +-#ifdef SQLITE_MAX_SCHEMA_RETRY
    +-  "MAX_SCHEMA_RETRY=" CTIMEOPT_VAL(SQLITE_MAX_SCHEMA_RETRY),
    +-#endif
    +-#if SQLITE_MEMDEBUG
    +-  "MEMDEBUG",
    +-#endif
    +-#if SQLITE_MIXED_ENDIAN_64BIT_FLOAT
    +-  "MIXED_ENDIAN_64BIT_FLOAT",
    +-#endif
    +-#if SQLITE_NO_SYNC
    +-  "NO_SYNC",
    +-#endif
    +-#if SQLITE_OMIT_ALTERTABLE
    +-  "OMIT_ALTERTABLE",
    +-#endif
    +-#if SQLITE_OMIT_ANALYZE
    +-  "OMIT_ANALYZE",
    +-#endif
    +-#if SQLITE_OMIT_ATTACH
    +-  "OMIT_ATTACH",
    +-#endif
    +-#if SQLITE_OMIT_AUTHORIZATION
    +-  "OMIT_AUTHORIZATION",
    +-#endif
    +-#if SQLITE_OMIT_AUTOINCREMENT
    +-  "OMIT_AUTOINCREMENT",
    +-#endif
    +-#if SQLITE_OMIT_AUTOINIT
    +-  "OMIT_AUTOINIT",
    +-#endif
    +-#if SQLITE_OMIT_AUTOMATIC_INDEX
    +-  "OMIT_AUTOMATIC_INDEX",
    +-#endif
    +-#if SQLITE_OMIT_AUTORESET
    +-  "OMIT_AUTORESET",
    +-#endif
    +-#if SQLITE_OMIT_AUTOVACUUM
    +-  "OMIT_AUTOVACUUM",
    +-#endif
    +-#if SQLITE_OMIT_BETWEEN_OPTIMIZATION
    +-  "OMIT_BETWEEN_OPTIMIZATION",
    +-#endif
    +-#if SQLITE_OMIT_BLOB_LITERAL
    +-  "OMIT_BLOB_LITERAL",
    +-#endif
    +-#if SQLITE_OMIT_BTREECOUNT
    +-  "OMIT_BTREECOUNT",
    +-#endif
    +-#if SQLITE_OMIT_BUILTIN_TEST
    +-  "OMIT_BUILTIN_TEST",
    +-#endif
    +-#if SQLITE_OMIT_CAST
    +-  "OMIT_CAST",
    +-#endif
    +-#if SQLITE_OMIT_CHECK
    +-  "OMIT_CHECK",
    +-#endif
    +-#if SQLITE_OMIT_COMPLETE
    +-  "OMIT_COMPLETE",
    +-#endif
    +-#if SQLITE_OMIT_COMPOUND_SELECT
    +-  "OMIT_COMPOUND_SELECT",
    +-#endif
    +-#if SQLITE_OMIT_CTE
    +-  "OMIT_CTE",
    +-#endif
    +-#if SQLITE_OMIT_DATETIME_FUNCS
    +-  "OMIT_DATETIME_FUNCS",
    +-#endif
    +-#if SQLITE_OMIT_DECLTYPE
    +-  "OMIT_DECLTYPE",
    +-#endif
    +-#if SQLITE_OMIT_DEPRECATED
    +-  "OMIT_DEPRECATED",
    +-#endif
    +-#if SQLITE_OMIT_DISKIO
    +-  "OMIT_DISKIO",
    +-#endif
    +-#if SQLITE_OMIT_EXPLAIN
    +-  "OMIT_EXPLAIN",
    +-#endif
    +-#if SQLITE_OMIT_FLAG_PRAGMAS
    +-  "OMIT_FLAG_PRAGMAS",
    +-#endif
    +-#if SQLITE_OMIT_FLOATING_POINT
    +-  "OMIT_FLOATING_POINT",
    +-#endif
    +-#if SQLITE_OMIT_FOREIGN_KEY
    +-  "OMIT_FOREIGN_KEY",
    +-#endif
    +-#if SQLITE_OMIT_GET_TABLE
    +-  "OMIT_GET_TABLE",
    +-#endif
    +-#if SQLITE_OMIT_INCRBLOB
    +-  "OMIT_INCRBLOB",
    +-#endif
    +-#if SQLITE_OMIT_INTEGRITY_CHECK
    +-  "OMIT_INTEGRITY_CHECK",
    +-#endif
    +-#if SQLITE_OMIT_LIKE_OPTIMIZATION
    +-  "OMIT_LIKE_OPTIMIZATION",
    +-#endif
    +-#if SQLITE_OMIT_LOAD_EXTENSION
    +-  "OMIT_LOAD_EXTENSION",
    +-#endif
    +-#if SQLITE_OMIT_LOCALTIME
    +-  "OMIT_LOCALTIME",
    +-#endif
    +-#if SQLITE_OMIT_LOOKASIDE
    +-  "OMIT_LOOKASIDE",
    +-#endif
    +-#if SQLITE_OMIT_MEMORYDB
    +-  "OMIT_MEMORYDB",
    +-#endif
    +-#if SQLITE_OMIT_OR_OPTIMIZATION
    +-  "OMIT_OR_OPTIMIZATION",
    +-#endif
    +-#if SQLITE_OMIT_PAGER_PRAGMAS
    +-  "OMIT_PAGER_PRAGMAS",
    +-#endif
    +-#if SQLITE_OMIT_PRAGMA
    +-  "OMIT_PRAGMA",
    +-#endif
    +-#if SQLITE_OMIT_PROGRESS_CALLBACK
    +-  "OMIT_PROGRESS_CALLBACK",
    +-#endif
    +-#if SQLITE_OMIT_QUICKBALANCE
    +-  "OMIT_QUICKBALANCE",
    +-#endif
    +-#if SQLITE_OMIT_REINDEX
    +-  "OMIT_REINDEX",
    +-#endif
    +-#if SQLITE_OMIT_SCHEMA_PRAGMAS
    +-  "OMIT_SCHEMA_PRAGMAS",
    +-#endif
    +-#if SQLITE_OMIT_SCHEMA_VERSION_PRAGMAS
    +-  "OMIT_SCHEMA_VERSION_PRAGMAS",
    +-#endif
    +-#if SQLITE_OMIT_SHARED_CACHE
    +-  "OMIT_SHARED_CACHE",
    +-#endif
    +-#if SQLITE_OMIT_SUBQUERY
    +-  "OMIT_SUBQUERY",
    +-#endif
    +-#if SQLITE_OMIT_TCL_VARIABLE
    +-  "OMIT_TCL_VARIABLE",
    +-#endif
    +-#if SQLITE_OMIT_TEMPDB
    +-  "OMIT_TEMPDB",
    +-#endif
    +-#if SQLITE_OMIT_TRACE
    +-  "OMIT_TRACE",
    +-#endif
    +-#if SQLITE_OMIT_TRIGGER
    +-  "OMIT_TRIGGER",
    +-#endif
    +-#if SQLITE_OMIT_TRUNCATE_OPTIMIZATION
    +-  "OMIT_TRUNCATE_OPTIMIZATION",
    +-#endif
    +-#if SQLITE_OMIT_UTF16
    +-  "OMIT_UTF16",
    +-#endif
    +-#if SQLITE_OMIT_VACUUM
    +-  "OMIT_VACUUM",
    +-#endif
    +-#if SQLITE_OMIT_VIEW
    +-  "OMIT_VIEW",
    +-#endif
    +-#if SQLITE_OMIT_VIRTUALTABLE
    +-  "OMIT_VIRTUALTABLE",
    +-#endif
    +-#if SQLITE_OMIT_WAL
    +-  "OMIT_WAL",
    +-#endif
    +-#if SQLITE_OMIT_WSD
    +-  "OMIT_WSD",
    +-#endif
    +-#if SQLITE_OMIT_XFER_OPT
    +-  "OMIT_XFER_OPT",
    +-#endif
    +-#if SQLITE_PERFORMANCE_TRACE
    +-  "PERFORMANCE_TRACE",
    +-#endif
    +-#if SQLITE_PROXY_DEBUG
    +-  "PROXY_DEBUG",
    +-#endif
    +-#if SQLITE_RTREE_INT_ONLY
    +-  "RTREE_INT_ONLY",
    +-#endif
    +-#if SQLITE_SECURE_DELETE
    +-  "SECURE_DELETE",
    +-#endif
    +-#if SQLITE_SMALL_STACK
    +-  "SMALL_STACK",
    +-#endif
    +-#if SQLITE_SOUNDEX
    +-  "SOUNDEX",
    +-#endif
    +-#if SQLITE_SYSTEM_MALLOC
    +-  "SYSTEM_MALLOC",
    +-#endif
    +-#if SQLITE_TCL
    +-  "TCL",
    +-#endif
    +-#if defined(SQLITE_TEMP_STORE) && !defined(SQLITE_TEMP_STORE_xc)
    +-  "TEMP_STORE=" CTIMEOPT_VAL(SQLITE_TEMP_STORE),
    +-#endif
    +-#if SQLITE_TEST
    +-  "TEST",
    +-#endif
    +-#if defined(SQLITE_THREADSAFE)
    +-  "THREADSAFE=" CTIMEOPT_VAL(SQLITE_THREADSAFE),
    +-#endif
    +-#if SQLITE_USE_ALLOCA
    +-  "USE_ALLOCA",
    +-#endif
    +-#if SQLITE_USER_AUTHENTICATION
    +-  "USER_AUTHENTICATION",
    +-#endif
    +-#if SQLITE_WIN32_MALLOC
    +-  "WIN32_MALLOC",
    +-#endif
    +-#if SQLITE_ZERO_MALLOC
    +-  "ZERO_MALLOC"
    +-#endif
    +-};
    +-
    + /*
    +-** Given the name of a compile-time option, return true if that option
    +-** was used and false if not.
    +-**
    +-** The name can optionally begin with "SQLITE_" but the "SQLITE_" prefix
    +-** is not required for a match.
    ++** Name of the default collating sequence
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_compileoption_used(const char *zOptName){
    +-  int i, n;
    +-
    +-#if SQLITE_ENABLE_API_ARMOR
    +-  if( zOptName==0 ){
    +-    (void)SQLITE_MISUSE_BKPT;
    +-    return 0;
    +-  }
    +-#endif
    +-  if( sqlite3StrNICmp(zOptName, "SQLITE_", 7)==0 ) zOptName += 7;
    +-  n = sqlite3Strlen30(zOptName);
    +-
    +-  /* Since ArraySize(azCompileOpt) is normally in single digits, a
    +-  ** linear search is adequate.  No need for a binary search. */
    +-  for(i=0; i<ArraySize(azCompileOpt); i++){
    +-    if( sqlite3StrNICmp(zOptName, azCompileOpt[i], n)==0
    +-     && sqlite3IsIdChar((unsigned char)azCompileOpt[i][n])==0
    +-    ){
    +-      return 1;
    +-    }
    +-  }
    +-  return 0;
    +-}
    +-
    +-/*
    +-** Return the N-th compile-time option string.  If N is out of range,
    +-** return a NULL pointer.
    +-*/
    +-SQLITE_API const char *SQLITE_STDCALL sqlite3_compileoption_get(int N){
    +-  if( N>=0 && N<ArraySize(azCompileOpt) ){
    +-    return azCompileOpt[N];
    +-  }
    +-  return 0;
    +-}
    +-
    +-#endif /* SQLITE_OMIT_COMPILEOPTION_DIAGS */
    ++SQLITE_PRIVATE const char sqlite3StrBINARY[] = "BINARY";
    + 
    +-/************** End of ctime.c ***********************************************/
    ++/************** End of global.c **********************************************/
    + /************** Begin file status.c ******************************************/
    + /*
    + ** 2008 June 18
    +@@ -15261,8 +18648,8 @@ SQLITE_API const char *SQLITE_STDCALL sqlite3_compileoption_get(int N){
    + ** 6000 lines long) it was split up into several smaller files and
    + ** this header information was factored out.
    + */
    +-#ifndef _VDBEINT_H_
    +-#define _VDBEINT_H_
    ++#ifndef SQLITE_VDBEINT_H
    ++#define SQLITE_VDBEINT_H
    + 
    + /*
    + ** The maximum number of times that a statement will try to reparse
    +@@ -15272,6 +18659,17 @@ SQLITE_API const char *SQLITE_STDCALL sqlite3_compileoption_get(int N){
    + # define SQLITE_MAX_SCHEMA_RETRY 50
    + #endif
    + 
    ++/*
    ++** VDBE_DISPLAY_P4 is true or false depending on whether or not the
    ++** "explain" P4 display logic is enabled.
    ++*/
    ++#if !defined(SQLITE_OMIT_EXPLAIN) || !defined(NDEBUG) \
    ++     || defined(VDBE_PROFILE) || defined(SQLITE_DEBUG)
    ++# define VDBE_DISPLAY_P4 1
    ++#else
    ++# define VDBE_DISPLAY_P4 0
    ++#endif
    ++
    + /*
    + ** SQL is translated into a sequence of instructions to be
    + ** executed by a virtual machine.  Each instruction is an instance
    +@@ -15287,73 +18685,88 @@ typedef unsigned Bool;
    + /* Opaque type used by code in vdbesort.c */
    + typedef struct VdbeSorter VdbeSorter;
    + 
    +-/* Opaque type used by the explainer */
    +-typedef struct Explain Explain;
    +-
    + /* Elements of the linked list at Vdbe.pAuxData */
    + typedef struct AuxData AuxData;
    + 
    ++/* Types of VDBE cursors */
    ++#define CURTYPE_BTREE       0
    ++#define CURTYPE_SORTER      1
    ++#define CURTYPE_VTAB        2
    ++#define CURTYPE_PSEUDO      3
    ++
    + /*
    +-** A cursor is a pointer into a single BTree within a database file.
    +-** The cursor can seek to a BTree entry with a particular key, or
    +-** loop over all entries of the Btree.  You can also insert new BTree
    +-** entries or retrieve the key or data from the entry that the cursor
    +-** is currently pointing to.
    ++** A VdbeCursor is an superclass (a wrapper) for various cursor objects:
    + **
    +-** Cursors can also point to virtual tables, sorters, or "pseudo-tables".
    +-** A pseudo-table is a single-row table implemented by registers.
    +-** 
    +-** Every cursor that the virtual machine has open is represented by an
    +-** instance of the following structure.
    ++**      * A b-tree cursor
    ++**          -  In the main database or in an ephemeral database
    ++**          -  On either an index or a table
    ++**      * A sorter
    ++**      * A virtual table
    ++**      * A one-row "pseudotable" stored in a single register
    + */
    ++typedef struct VdbeCursor VdbeCursor;
    + struct VdbeCursor {
    +-  BtCursor *pCursor;    /* The cursor structure of the backend */
    +-  Btree *pBt;           /* Separate file holding temporary table */
    +-  KeyInfo *pKeyInfo;    /* Info about index keys needed by index cursors */
    +-  int seekResult;       /* Result of previous sqlite3BtreeMoveto() */
    +-  int pseudoTableReg;   /* Register holding pseudotable content. */
    +-  i16 nField;           /* Number of fields in the header */
    +-  u16 nHdrParsed;       /* Number of header fields parsed so far */
    ++  u8 eCurType;            /* One of the CURTYPE_* values above */
    ++  i8 iDb;                 /* Index of cursor database in db->aDb[] (or -1) */
    ++  u8 nullRow;             /* True if pointing to a row with no data */
    ++  u8 deferredMoveto;      /* A call to sqlite3BtreeMoveto() is needed */
    ++  u8 isTable;             /* True for rowid tables.  False for indexes */
    + #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 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() */
    +-  VdbeSorter *pSorter;  /* Sorter object for OP_SorterOpen cursors */
    +-#ifdef SQLITE_ENABLE_COLUMN_USED_MASK
    +-  u64 maskUsed;         /* Mask of columns used by this cursor */
    ++  u8 seekOp;              /* Most recent seek operation on this cursor */
    ++  u8 wrFlag;              /* The wrFlag argument to sqlite3BtreeCursor() */
    + #endif
    ++  Bool isEphemeral:1;     /* True for an ephemeral table */
    ++  Bool useRandomRowid:1;  /* Generate new record numbers semi-randomly */
    ++  Bool isOrdered:1;       /* True if the table is not BTREE_UNORDERED */
    ++  Btree *pBtx;            /* Separate file holding temporary table */
    ++  i64 seqCount;           /* Sequence counter */
    ++  int *aAltMap;           /* Mapping from table to index column numbers */
    + 
    +-  /* Cached information about the header for the data record that the
    +-  ** cursor is currently pointing to.  Only valid if cacheStatus matches
    ++  /* Cached OP_Column parse information is only valid if cacheStatus matches
    +   ** Vdbe.cacheCtr.  Vdbe.cacheCtr will never take on the value of
    +-  ** CACHE_STALE and so setting cacheStatus=CACHE_STALE guarantees that
    +-  ** the cache is out of date.
    +-  **
    +-  ** aRow might point to (ephemeral) data for the current row, or it might
    +-  ** be NULL.
    +-  */
    +-  u32 cacheStatus;      /* Cache is valid if this matches Vdbe.cacheCtr */
    +-  u32 payloadSize;      /* Total number of bytes in the record */
    +-  u32 szRow;            /* Byte available in aRow */
    +-  u32 iHdrOffset;       /* Offset to next unparsed byte of the header */
    +-  const u8 *aRow;       /* Data for the current row, if all on one page */
    +-  u32 *aOffset;         /* Pointer to aType[nField] */
    +-  u32 aType[1];         /* Type values for all entries in the record */
    ++  ** CACHE_STALE (0) and so setting cacheStatus=CACHE_STALE guarantees that
    ++  ** the cache is out of date. */
    ++  u32 cacheStatus;        /* Cache is valid if this matches Vdbe.cacheCtr */
    ++  int seekResult;         /* Result of previous sqlite3BtreeMoveto() or 0
    ++                          ** if there have been no prior seeks on the cursor. */
    ++  /* seekResult does not distinguish between "no seeks have ever occurred
    ++  ** on this cursor" and "the most recent seek was an exact match".
    ++  ** For CURTYPE_PSEUDO, seekResult is the register holding the record */
    ++
    ++  /* When a new VdbeCursor is allocated, only the fields above are zeroed.
    ++  ** The fields that follow are uninitialized, and must be individually
    ++  ** initialized prior to first use. */
    ++  VdbeCursor *pAltCursor; /* Associated index cursor from which to read */
    ++  union {
    ++    BtCursor *pCursor;          /* CURTYPE_BTREE or _PSEUDO.  Btree cursor */
    ++    sqlite3_vtab_cursor *pVCur; /* CURTYPE_VTAB.              Vtab cursor */
    ++    VdbeSorter *pSorter;        /* CURTYPE_SORTER.            Sorter object */
    ++  } uc;
    ++  KeyInfo *pKeyInfo;      /* Info about index keys needed by index cursors */
    ++  u32 iHdrOffset;         /* Offset to next unparsed byte of the header */
    ++  Pgno pgnoRoot;          /* Root page of the open btree cursor */
    ++  i16 nField;             /* Number of fields in the header */
    ++  u16 nHdrParsed;         /* Number of header fields parsed so far */
    ++  i64 movetoTarget;       /* Argument to the deferred sqlite3BtreeMoveto() */
    ++  u32 *aOffset;           /* Pointer to aType[nField] */
    ++  const u8 *aRow;         /* Data for the current row, if all on one page */
    ++  u32 payloadSize;        /* Total number of bytes in the record */
    ++  u32 szRow;              /* Byte available in aRow */
    ++#ifdef SQLITE_ENABLE_COLUMN_USED_MASK
    ++  u64 maskUsed;           /* Mask of columns used by this cursor */
    ++#endif
    ++
    +   /* 2*nField extra array elements allocated for aType[], beyond the one
    +   ** static element declared in the structure.  nField total array slots for
    +   ** aType[] and nField+1 array slots for aOffset[] */
    ++  u32 aType[1];           /* Type values record decode.  MUST BE LAST */
    + };
    +-typedef struct VdbeCursor VdbeCursor;
    ++
    ++
    ++/*
    ++** A value for VdbeCursor.cacheStatus that means the cache is always invalid.
    ++*/
    ++#define CACHE_STALE 0
    + 
    + /*
    + ** When a sub-program is executed (OP_Program), a structure of this type
    +@@ -15383,15 +18796,15 @@ struct VdbeFrame {
    +   Op *aOp;                /* Program instructions for parent frame */
    +   i64 *anExec;            /* Event counters from parent frame */
    +   Mem *aMem;              /* Array of memory cells for parent frame */
    +-  u8 *aOnceFlag;          /* Array of OP_Once flags for parent frame */
    +   VdbeCursor **apCsr;     /* Array of Vdbe cursors for parent frame */
    ++  u8 *aOnce;              /* Bitmask used by OP_Once */
    +   void *token;            /* Copy of SubProgram.token */
    +   i64 lastRowid;          /* Last insert rowid (sqlite3.lastRowid) */
    ++  AuxData *pAuxData;      /* Linked list of auxdata allocations */
    +   int nCursor;            /* Number of entries in apCsr */
    +   int pc;                 /* Program Counter in parent (calling) frame */
    +   int nOp;                /* Size of aOp array */
    +   int nMem;               /* Number of entries in aMem */
    +-  int nOnceFlag;          /* Number of entries in aOnceFlag */
    +   int nChildMem;          /* Number of memory cells for child frame */
    +   int nChildCsr;          /* Number of cursors for child frame */
    +   int nChange;            /* Statement changes (Vdbe.nChange)     */
    +@@ -15400,21 +18813,17 @@ struct VdbeFrame {
    + 
    + #define VdbeFrameMem(p) ((Mem *)&((u8 *)p)[ROUND8(sizeof(VdbeFrame))])
    + 
    +-/*
    +-** A value for VdbeCursor.cacheValid that means the cache is always invalid.
    +-*/
    +-#define CACHE_STALE 0
    +-
    + /*
    + ** Internally, the vdbe manipulates nearly all SQL values as Mem
    + ** structures. Each Mem struct may cache multiple representations (string,
    + ** integer etc.) of the same value.
    + */
    +-struct Mem {
    ++struct sqlite3_value {
    +   union MemValue {
    +     double r;           /* Real value used when MEM_Real is set in flags */
    +     i64 i;              /* Integer value used when MEM_Int is set in flags */
    +-    int nZero;          /* Used when bit MEM_Zero is set in flags */
    ++    int nZero;          /* Extra zero bytes when MEM_Zero and MEM_Blob set */
    ++    const char *zPType; /* Pointer type when MEM_Term|MEM_Subtype|MEM_Null */
    +     FuncDef *pDef;      /* Used only when flags==MEM_Agg */
    +     RowSet *pRowSet;    /* Used only when flags==MEM_RowSet */
    +     VdbeFrame *pFrame;  /* Used when flags==MEM_Frame */
    +@@ -15446,7 +18855,10 @@ struct Mem {
    + ** representations of the value stored in the Mem struct.
    + **
    + ** If the MEM_Null flag is set, then the value is an SQL NULL value.
    +-** No other flags may be set in this case.
    ++** For a pointer type created using sqlite3_bind_pointer() or
    ++** sqlite3_result_pointer() the MEM_Term and MEM_Subtype flags are also set.
    ++** If both MEM_Null and MEM_Zero are set, that means that the value is
    ++** an unchanging column value from VColumn.
    + **
    + ** If the MEM_Str flag is set then Mem.z points at a string representation.
    + ** Usually this is encoded in the same unicode encoding as the main
    +@@ -15454,7 +18866,7 @@ struct Mem {
    + ** set, then the string is nul terminated. The MEM_Int and MEM_Real 
    + ** flags may coexist with the MEM_Str flag.
    + */
    +-#define MEM_Null      0x0001   /* Value is NULL */
    ++#define MEM_Null      0x0001   /* Value is NULL (or a pointer) */
    + #define MEM_Str       0x0002   /* Value is a string */
    + #define MEM_Int       0x0004   /* Value is an integer */
    + #define MEM_Real      0x0008   /* Value is a real number */
    +@@ -15464,7 +18876,7 @@ struct Mem {
    + #define MEM_Frame     0x0040   /* Value is a VdbeFrame object */
    + #define MEM_Undefined 0x0080   /* Value is undefined */
    + #define MEM_Cleared   0x0100   /* NULL set by OP_Null, not from data */
    +-#define MEM_TypeMask  0x01ff   /* Mask of type bits */
    ++#define MEM_TypeMask  0xc1ff   /* Mask of type bits */
    + 
    + 
    + /* Whenever Mem contains a valid string or blob representation, one of
    +@@ -15472,17 +18884,24 @@ struct Mem {
    + ** policy for Mem.z.  The MEM_Term flag tells us whether or not the
    + ** string is \000 or \u0000 terminated
    + */
    +-#define MEM_Term      0x0200   /* String rep is nul terminated */
    ++#define MEM_Term      0x0200   /* String in Mem.z is zero terminated */
    + #define MEM_Dyn       0x0400   /* Need to call Mem.xDel() on Mem.z */
    + #define MEM_Static    0x0800   /* Mem.z points to a static string */
    + #define MEM_Ephem     0x1000   /* Mem.z points to an ephemeral string */
    + #define MEM_Agg       0x2000   /* Mem.z points to an agg function context */
    + #define MEM_Zero      0x4000   /* Mem.i contains count of 0s appended to blob */
    ++#define MEM_Subtype   0x8000   /* Mem.eSubtype is valid */
    + #ifdef SQLITE_OMIT_INCRBLOB
    +   #undef MEM_Zero
    +   #define MEM_Zero 0x0000
    + #endif
    + 
    ++/* Return TRUE if Mem X contains dynamically allocated content - anything
    ++** that needs to be deallocated to avoid a leak.
    ++*/
    ++#define VdbeMemDynamic(X)  \
    ++  (((X)->flags&(MEM_Agg|MEM_Dyn|MEM_RowSet|MEM_Frame))!=0)
    ++
    + /*
    + ** Clear any existing type flags from a Mem and replace them with f
    + */
    +@@ -15505,11 +18924,11 @@ struct Mem {
    + ** when the VM is halted (if not before).
    + */
    + struct AuxData {
    +-  int iOp;                        /* Instruction number of OP_Function opcode */
    +-  int iArg;                       /* Index of function argument. */
    ++  int iAuxOp;                     /* Instruction number of OP_Function opcode */
    ++  int iAuxArg;                    /* Index of function argument. */
    +   void *pAux;                     /* Aux data pointer */
    +-  void (*xDelete)(void *);        /* Destructor for the aux data */
    +-  AuxData *pNext;                 /* Next element in list */
    ++  void (*xDeleteAux)(void*);      /* Destructor for the aux data */
    ++  AuxData *pNextAux;              /* Next element in list */
    + };
    + 
    + /*
    +@@ -15538,18 +18957,6 @@ struct sqlite3_context {
    +   sqlite3_value *argv[1]; /* Argument set */
    + };
    + 
    +-/*
    +-** An Explain object accumulates indented output which is helpful
    +-** in describing recursive data structures.
    +-*/
    +-struct Explain {
    +-  Vdbe *pVdbe;       /* Attach the explanation to this Vdbe */
    +-  StrAccum str;      /* The string being accumulated */
    +-  int nIndent;       /* Number of elements in aIndent */
    +-  u16 aIndent[100];  /* Levels of indentation */
    +-  char zBase[100];   /* Initial space */
    +-};
    +-
    + /* A bitfield type for use inside of structures.  Always follow with :N where
    + ** N is the number of bits.
    + */
    +@@ -15574,53 +18981,56 @@ struct ScanStatus {
    + */
    + struct Vdbe {
    +   sqlite3 *db;            /* The database connection that owns this statement */
    ++  Vdbe *pPrev,*pNext;     /* Linked list of VDBEs with the same Vdbe.db */
    ++  Parse *pParse;          /* Parsing context used to create this Vdbe */
    ++  ynVar nVar;             /* Number of entries in aVar[] */
    ++  u32 magic;              /* Magic number for sanity checking */
    ++  int nMem;               /* Number of memory locations currently allocated */
    ++  int nCursor;            /* Number of slots in apCsr[] */
    ++  u32 cacheCtr;           /* VdbeCursor row cache generation counter */
    ++  int pc;                 /* The program counter */
    ++  int rc;                 /* Value to return */
    ++  int nChange;            /* Number of db changes made since last reset */
    ++  int iStatement;         /* Statement number (or 0 if has not opened stmt) */
    ++  i64 iCurrentTime;       /* Value of julianday('now') for this statement */
    ++  i64 nFkConstraint;      /* Number of imm. FK constraints this VM */
    ++  i64 nStmtDefCons;       /* Number of def. constraints when stmt started */
    ++  i64 nStmtDefImmCons;    /* Number of def. imm constraints when stmt started */
    ++
    ++  /* When allocating a new Vdbe object, all of the fields below should be
    ++  ** initialized to zero or NULL */
    ++
    +   Op *aOp;                /* Space to hold the virtual machine's program */
    +   Mem *aMem;              /* The memory locations */
    +   Mem **apArg;            /* Arguments to currently executing user function */
    +   Mem *aColName;          /* Column names to return */
    +   Mem *pResultSet;        /* Pointer to an array of results */
    +-  Parse *pParse;          /* Parsing context used to create this Vdbe */
    +-  int nMem;               /* Number of memory locations currently allocated */
    +-  int nOp;                /* Number of instructions in the program */
    +-  int nCursor;            /* Number of slots in apCsr[] */
    +-  u32 magic;              /* Magic number for sanity checking */
    +   char *zErrMsg;          /* Error message written here */
    +-  Vdbe *pPrev,*pNext;     /* Linked list of VDBEs with the same Vdbe.db */
    +   VdbeCursor **apCsr;     /* One element of this array for each open cursor */
    +   Mem *aVar;              /* Values for the OP_Variable opcode. */
    +-  char **azVar;           /* Name of variables */
    +-  ynVar nVar;             /* Number of entries in aVar[] */
    +-  ynVar nzVar;            /* Number of entries in azVar[] */
    +-  u32 cacheCtr;           /* VdbeCursor row cache generation counter */
    +-  int pc;                 /* The program counter */
    +-  int rc;                 /* Value to return */
    ++  VList *pVList;          /* Name of variables */
    ++#ifndef SQLITE_OMIT_TRACE
    ++  i64 startTime;          /* Time when query started - used for profiling */
    ++#endif
    ++  int nOp;                /* Number of instructions in the program */
    + #ifdef SQLITE_DEBUG
    +   int rcApp;              /* errcode set by sqlite3_result_error_code() */
    + #endif
    +   u16 nResColumn;         /* Number of columns in one row of the result set */
    +   u8 errorAction;         /* Recovery action to do in case of an error */
    +   u8 minWriteFileFormat;  /* Minimum file format for writable database files */
    ++  u8 prepFlags;           /* SQLITE_PREPARE_* flags */
    ++  bft expired:1;          /* True if the VM needs to be recompiled */
    ++  bft doingRerun:1;       /* True if rerunning after an auto-reprepare */
    +   bft explain:2;          /* True if EXPLAIN present on SQL command */
    +   bft changeCntOn:1;      /* True to update the change-counter */
    +-  bft expired:1;          /* True if the VM needs to be recompiled */
    +   bft runOnlyOnce:1;      /* Automatically expire on reset */
    +   bft usesStmtJournal:1;  /* True if uses a statement journal */
    +   bft readOnly:1;         /* True for statements that do not write */
    +   bft bIsReader:1;        /* True for statements that read */
    +-  bft isPrepareV2:1;      /* True if prepared with prepare_v2() */
    +-  bft doingRerun:1;       /* True if rerunning after an auto-reprepare */
    +-  int nChange;            /* Number of db changes made since last reset */
    +   yDbMask btreeMask;      /* Bitmask of db->aDb[] entries referenced */
    +   yDbMask lockMask;       /* Subset of btreeMask that requires a lock */
    +-  int iStatement;         /* Statement number (or 0 if has not opened stmt) */
    +-  u32 aCounter[5];        /* Counters used by sqlite3_stmt_status() */
    +-#ifndef SQLITE_OMIT_TRACE
    +-  i64 startTime;          /* Time when query started - used for profiling */
    +-#endif
    +-  i64 iCurrentTime;       /* Value of julianday('now') for this statement */
    +-  i64 nFkConstraint;      /* Number of imm. FK constraints this VM */
    +-  i64 nStmtDefCons;       /* Number of def. constraints when stmt started */
    +-  i64 nStmtDefImmCons;    /* Number of def. imm constraints when stmt started */
    ++  u32 aCounter[7];        /* Counters used by sqlite3_stmt_status() */
    +   char *zSql;             /* Text of the SQL statement that generated this */
    +   void *pFree;            /* Free this when deleting the vdbe */
    +   VdbeFrame *pFrame;      /* Parent frame */
    +@@ -15628,8 +19038,6 @@ struct Vdbe {
    +   int nFrame;             /* Number of frames in pFrame list */
    +   u32 expmask;            /* Binding to these vars invalidates VM */
    +   SubProgram *pProgram;   /* Linked list of all sub-programs used by VM */
    +-  int nOnceFlag;          /* Size of array aOnceFlag[] */
    +-  u8 *aOnceFlag;          /* Flags for OP_Once */
    +   AuxData *pAuxData;      /* Linked list of auxdata allocations */
    + #ifdef SQLITE_ENABLE_STMT_SCANSTATUS
    +   i64 *anExec;            /* Number of times each op has been executed */
    +@@ -15641,10 +19049,31 @@ struct Vdbe {
    + /*
    + ** The following are allowed values for Vdbe.magic
    + */
    +-#define VDBE_MAGIC_INIT     0x26bceaa5    /* Building a VDBE program */
    +-#define VDBE_MAGIC_RUN      0xbdf20da3    /* VDBE is ready to execute */
    +-#define VDBE_MAGIC_HALT     0x519c2973    /* VDBE has completed execution */
    +-#define VDBE_MAGIC_DEAD     0xb606c3c8    /* The VDBE has been deallocated */
    ++#define VDBE_MAGIC_INIT     0x16bceaa5    /* Building a VDBE program */
    ++#define VDBE_MAGIC_RUN      0x2df20da3    /* VDBE is ready to execute */
    ++#define VDBE_MAGIC_HALT     0x319c2973    /* VDBE has completed execution */
    ++#define VDBE_MAGIC_RESET    0x48fa9f76    /* Reset and ready to run again */
    ++#define VDBE_MAGIC_DEAD     0x5606c3c8    /* The VDBE has been deallocated */
    ++
    ++/*
    ++** Structure used to store the context required by the 
    ++** sqlite3_preupdate_*() API functions.
    ++*/
    ++struct PreUpdate {
    ++  Vdbe *v;
    ++  VdbeCursor *pCsr;               /* Cursor to read old values from */
    ++  int op;                         /* One of SQLITE_INSERT, UPDATE, DELETE */
    ++  u8 *aRecord;                    /* old.* database record */
    ++  KeyInfo keyinfo;
    ++  UnpackedRecord *pUnpacked;      /* Unpacked version of aRecord[] */
    ++  UnpackedRecord *pNewUnpacked;   /* Unpacked version of new.* record */
    ++  int iNewReg;                    /* Register for new.* values */
    ++  i64 iKey1;                      /* First key value passed to hook */
    ++  i64 iKey2;                      /* Second key value passed to hook */
    ++  Mem *aNew;                      /* Array of new.* values */
    ++  Table *pTab;                    /* Schema object being upated */          
    ++  Index *pPk;                     /* PK index if pTab is WITHOUT ROWID */
    ++};
    + 
    + /*
    + ** Function prototypes
    +@@ -15652,16 +19081,17 @@ struct Vdbe {
    + SQLITE_PRIVATE void sqlite3VdbeError(Vdbe*, const char *, ...);
    + SQLITE_PRIVATE void sqlite3VdbeFreeCursor(Vdbe *, VdbeCursor*);
    + void sqliteVdbePopStack(Vdbe*,int);
    +-SQLITE_PRIVATE int sqlite3VdbeCursorMoveto(VdbeCursor*);
    ++SQLITE_PRIVATE int sqlite3VdbeCursorMoveto(VdbeCursor**, int*);
    + SQLITE_PRIVATE int sqlite3VdbeCursorRestore(VdbeCursor*);
    + #if defined(SQLITE_DEBUG) || defined(VDBE_PROFILE)
    + SQLITE_PRIVATE void sqlite3VdbePrintOp(FILE*, int, Op*);
    + #endif
    + SQLITE_PRIVATE u32 sqlite3VdbeSerialTypeLen(u32);
    +-SQLITE_PRIVATE u32 sqlite3VdbeSerialType(Mem*, int);
    ++SQLITE_PRIVATE u8 sqlite3VdbeOneByteSerialTypeLen(u8);
    ++SQLITE_PRIVATE u32 sqlite3VdbeSerialType(Mem*, int, u32*);
    + SQLITE_PRIVATE u32 sqlite3VdbeSerialPut(unsigned char*, Mem*, u32);
    + SQLITE_PRIVATE u32 sqlite3VdbeSerialGet(const unsigned char*, u32, Mem*);
    +-SQLITE_PRIVATE void sqlite3VdbeDeleteAuxData(Vdbe*, int, int);
    ++SQLITE_PRIVATE void sqlite3VdbeDeleteAuxData(sqlite3*, AuxData**, int, int);
    + 
    + int sqlite2BtreeKeyCompare(BtCursor *, const void *, int, int, int *);
    + SQLITE_PRIVATE int sqlite3VdbeIdxKeyCompare(sqlite3*,VdbeCursor*,UnpackedRecord*,int*);
    +@@ -15682,6 +19112,7 @@ SQLITE_PRIVATE void sqlite3VdbeMemSetInt64(Mem*, i64);
    + #else
    + SQLITE_PRIVATE   void sqlite3VdbeMemSetDouble(Mem*, double);
    + #endif
    ++SQLITE_PRIVATE void sqlite3VdbeMemSetPointer(Mem*, void*, const char*, void(*)(void*));
    + SQLITE_PRIVATE void sqlite3VdbeMemInit(Mem*,sqlite3*,u16);
    + SQLITE_PRIVATE void sqlite3VdbeMemSetNull(Mem*);
    + SQLITE_PRIVATE void sqlite3VdbeMemSetZeroBlob(Mem*,int);
    +@@ -15695,10 +19126,8 @@ SQLITE_PRIVATE void sqlite3VdbeIntegerAffinity(Mem*);
    + SQLITE_PRIVATE int sqlite3VdbeMemRealify(Mem*);
    + SQLITE_PRIVATE int sqlite3VdbeMemNumerify(Mem*);
    + SQLITE_PRIVATE void sqlite3VdbeMemCast(Mem*,u8,u8);
    +-SQLITE_PRIVATE int sqlite3VdbeMemFromBtree(BtCursor*,u32,u32,int,Mem*);
    ++SQLITE_PRIVATE int sqlite3VdbeMemFromBtree(BtCursor*,u32,u32,Mem*);
    + SQLITE_PRIVATE void sqlite3VdbeMemRelease(Mem *p);
    +-#define VdbeMemDynamic(X)  \
    +-  (((X)->flags&(MEM_Agg|MEM_Dyn|MEM_RowSet|MEM_Frame))!=0)
    + SQLITE_PRIVATE int sqlite3VdbeMemFinalize(Mem*, FuncDef*);
    + SQLITE_PRIVATE const char *sqlite3OpcodeName(int);
    + SQLITE_PRIVATE int sqlite3VdbeMemGrow(Mem *pMem, int n, int preserve);
    +@@ -15706,22 +19135,29 @@ SQLITE_PRIVATE int sqlite3VdbeMemClearAndResize(Mem *pMem, int n);
    + SQLITE_PRIVATE int sqlite3VdbeCloseStatement(Vdbe *, int);
    + SQLITE_PRIVATE void sqlite3VdbeFrameDelete(VdbeFrame*);
    + SQLITE_PRIVATE int sqlite3VdbeFrameRestore(VdbeFrame *);
    ++#ifdef SQLITE_ENABLE_PREUPDATE_HOOK
    ++SQLITE_PRIVATE void sqlite3VdbePreUpdateHook(Vdbe*,VdbeCursor*,int,const char*,Table*,i64,int);
    ++#endif
    + SQLITE_PRIVATE int sqlite3VdbeTransferError(Vdbe *p);
    + 
    + SQLITE_PRIVATE int sqlite3VdbeSorterInit(sqlite3 *, int, 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 *);
    ++SQLITE_PRIVATE int sqlite3VdbeSorterNext(sqlite3 *, const VdbeCursor *);
    + SQLITE_PRIVATE int sqlite3VdbeSorterRewind(const VdbeCursor *, int *);
    + SQLITE_PRIVATE int sqlite3VdbeSorterWrite(const VdbeCursor *, Mem *);
    + SQLITE_PRIVATE int sqlite3VdbeSorterCompare(const VdbeCursor *, Mem *, int, int *);
    + 
    +-#if !defined(SQLITE_OMIT_SHARED_CACHE) && SQLITE_THREADSAFE>0
    ++#if !defined(SQLITE_OMIT_SHARED_CACHE) 
    + SQLITE_PRIVATE   void sqlite3VdbeEnter(Vdbe*);
    +-SQLITE_PRIVATE   void sqlite3VdbeLeave(Vdbe*);
    + #else
    + # define sqlite3VdbeEnter(X)
    ++#endif
    ++
    ++#if !defined(SQLITE_OMIT_SHARED_CACHE) && SQLITE_THREADSAFE>0
    ++SQLITE_PRIVATE   void sqlite3VdbeLeave(Vdbe*);
    ++#else
    + # define sqlite3VdbeLeave(X)
    + #endif
    + 
    +@@ -15736,12 +19172,14 @@ SQLITE_PRIVATE int sqlite3VdbeCheckFk(Vdbe *, int);
    + # define sqlite3VdbeCheckFk(p,i) 0
    + #endif
    + 
    +-SQLITE_PRIVATE int sqlite3VdbeMemTranslate(Mem*, u8);
    + #ifdef SQLITE_DEBUG
    + SQLITE_PRIVATE   void sqlite3VdbePrintSql(Vdbe*);
    + SQLITE_PRIVATE   void sqlite3VdbeMemPrettyPrint(Mem *pMem, char *zBuf);
    + #endif
    +-SQLITE_PRIVATE int sqlite3VdbeMemHandleBom(Mem *pMem);
    ++#ifndef SQLITE_OMIT_UTF16
    ++SQLITE_PRIVATE   int sqlite3VdbeMemTranslate(Mem*, u8);
    ++SQLITE_PRIVATE   int sqlite3VdbeMemHandleBom(Mem *pMem);
    ++#endif
    + 
    + #ifndef SQLITE_OMIT_INCRBLOB
    + SQLITE_PRIVATE   int sqlite3VdbeMemExpandBlob(Mem *);
    +@@ -15751,7 +19189,7 @@ SQLITE_PRIVATE   int sqlite3VdbeMemExpandBlob(Mem *);
    +   #define ExpandBlob(P) SQLITE_OK
    + #endif
    + 
    +-#endif /* !defined(_VDBEINT_H_) */
    ++#endif /* !defined(SQLITE_VDBEINT_H) */
    + 
    + /************** End of vdbeInt.h *********************************************/
    + /************** Continuing where we left off in status.c *********************/
    +@@ -15759,15 +19197,15 @@ SQLITE_PRIVATE   int sqlite3VdbeMemExpandBlob(Mem *);
    + /*
    + ** Variables in which to record status information.
    + */
    +-typedef struct sqlite3StatType sqlite3StatType;
    +-static SQLITE_WSD struct sqlite3StatType {
    + #if SQLITE_PTRSIZE>4
    +-  sqlite3_int64 nowValue[10];         /* Current value */
    +-  sqlite3_int64 mxValue[10];          /* Maximum value */
    ++typedef sqlite3_int64 sqlite3StatValueType;
    + #else
    +-  u32 nowValue[10];                   /* Current value */
    +-  u32 mxValue[10];                    /* Maximum value */
    ++typedef u32 sqlite3StatValueType;
    + #endif
    ++typedef struct sqlite3StatType sqlite3StatType;
    ++static SQLITE_WSD struct sqlite3StatType {
    ++  sqlite3StatValueType nowValue[10];  /* Current value */
    ++  sqlite3StatValueType mxValue[10];   /* Maximum value */
    + } sqlite3Stat = { {0,}, {0,} };
    + 
    + /*
    +@@ -15848,25 +19286,30 @@ SQLITE_PRIVATE void sqlite3StatusDown(int op, int N){
    + }
    + 
    + /*
    +-** Set the value of a status to X.  The highwater mark is adjusted if
    +-** necessary.  The caller must hold the appropriate mutex.
    ++** Adjust the highwater mark if necessary.
    ++** The caller must hold the appropriate mutex.
    + */
    +-SQLITE_PRIVATE void sqlite3StatusSet(int op, int X){
    ++SQLITE_PRIVATE void sqlite3StatusHighwater(int op, int X){
    ++  sqlite3StatValueType newValue;
    +   wsdStatInit;
    ++  assert( X>=0 );
    ++  newValue = (sqlite3StatValueType)X;
    +   assert( op>=0 && op<ArraySize(wsdStat.nowValue) );
    +   assert( op>=0 && op<ArraySize(statMutex) );
    +   assert( sqlite3_mutex_held(statMutex[op] ? sqlite3Pcache1Mutex()
    +                                            : sqlite3MallocMutex()) );
    +-  wsdStat.nowValue[op] = X;
    +-  if( wsdStat.nowValue[op]>wsdStat.mxValue[op] ){
    +-    wsdStat.mxValue[op] = wsdStat.nowValue[op];
    ++  assert( op==SQLITE_STATUS_MALLOC_SIZE
    ++          || op==SQLITE_STATUS_PAGECACHE_SIZE
    ++          || op==SQLITE_STATUS_PARSER_STACK );
    ++  if( newValue>wsdStat.mxValue[op] ){
    ++    wsdStat.mxValue[op] = newValue;
    +   }
    + }
    + 
    + /*
    + ** Query status information.
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_status64(
    ++SQLITE_API int sqlite3_status64(
    +   int op,
    +   sqlite3_int64 *pCurrent,
    +   sqlite3_int64 *pHighwater,
    +@@ -15891,8 +19334,8 @@ SQLITE_API int SQLITE_STDCALL sqlite3_status64(
    +   (void)pMutex;  /* Prevent warning when SQLITE_THREADSAFE=0 */
    +   return SQLITE_OK;
    + }
    +-SQLITE_API int SQLITE_STDCALL sqlite3_status(int op, int *pCurrent, int *pHighwater, int resetFlag){
    +-  sqlite3_int64 iCur, iHwtr;
    ++SQLITE_API int sqlite3_status(int op, int *pCurrent, int *pHighwater, int resetFlag){
    ++  sqlite3_int64 iCur = 0, iHwtr = 0;
    +   int rc;
    + #ifdef SQLITE_ENABLE_API_ARMOR
    +   if( pCurrent==0 || pHighwater==0 ) return SQLITE_MISUSE_BKPT;
    +@@ -15905,10 +19348,32 @@ SQLITE_API int SQLITE_STDCALL sqlite3_status(int op, int *pCurrent, int *pHighwa
    +   return rc;
    + }
    + 
    ++/*
    ++** Return the number of LookasideSlot elements on the linked list
    ++*/
    ++static u32 countLookasideSlots(LookasideSlot *p){
    ++  u32 cnt = 0;
    ++  while( p ){
    ++    p = p->pNext;
    ++    cnt++;
    ++  }
    ++  return cnt;
    ++}
    ++
    ++/*
    ++** Count the number of slots of lookaside memory that are outstanding
    ++*/
    ++SQLITE_PRIVATE int sqlite3LookasideUsed(sqlite3 *db, int *pHighwater){
    ++  u32 nInit = countLookasideSlots(db->lookaside.pInit);
    ++  u32 nFree = countLookasideSlots(db->lookaside.pFree);
    ++  if( pHighwater ) *pHighwater = db->lookaside.nSlot - nInit;
    ++  return db->lookaside.nSlot - (nInit+nFree);
    ++}
    ++
    + /*
    + ** Query status information for a single database connection
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_db_status(
    ++SQLITE_API int sqlite3_db_status(
    +   sqlite3 *db,          /* The database connection whose status is desired */
    +   int op,               /* Status verb */
    +   int *pCurrent,        /* Write current value here */
    +@@ -15924,10 +19389,15 @@ SQLITE_API int SQLITE_STDCALL sqlite3_db_status(
    +   sqlite3_mutex_enter(db->mutex);
    +   switch( op ){
    +     case SQLITE_DBSTATUS_LOOKASIDE_USED: {
    +-      *pCurrent = db->lookaside.nOut;
    +-      *pHighwater = db->lookaside.mxOut;
    ++      *pCurrent = sqlite3LookasideUsed(db, pHighwater);
    +       if( resetFlag ){
    +-        db->lookaside.mxOut = db->lookaside.nOut;
    ++        LookasideSlot *p = db->lookaside.pFree;
    ++        if( p ){
    ++          while( p->pNext ) p = p->pNext;
    ++          p->pNext = db->lookaside.pInit;
    ++          db->lookaside.pInit = db->lookaside.pFree;
    ++          db->lookaside.pFree = 0;
    ++        }
    +       }
    +       break;
    +     }
    +@@ -15953,6 +19423,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_db_status(
    +     ** by all pagers associated with the given database connection.  The
    +     ** highwater mark is meaningless and is returned as zero.
    +     */
    ++    case SQLITE_DBSTATUS_CACHE_USED_SHARED:
    +     case SQLITE_DBSTATUS_CACHE_USED: {
    +       int totalUsed = 0;
    +       int i;
    +@@ -15961,7 +19432,11 @@ SQLITE_API int SQLITE_STDCALL sqlite3_db_status(
    +         Btree *pBt = db->aDb[i].pBt;
    +         if( pBt ){
    +           Pager *pPager = sqlite3BtreePager(pBt);
    +-          totalUsed += sqlite3PagerMemUsed(pPager);
    ++          int nByte = sqlite3PagerMemUsed(pPager);
    ++          if( op==SQLITE_DBSTATUS_CACHE_USED_SHARED ){
    ++            nByte = nByte / sqlite3BtreeConnectionCount(pBt);
    ++          }
    ++          totalUsed += nByte;
    +         }
    +       }
    +       sqlite3BtreeLeaveAll(db);
    +@@ -15992,10 +19467,10 @@ SQLITE_API int SQLITE_STDCALL sqlite3_db_status(
    +             + pSchema->idxHash.count
    +             + pSchema->fkeyHash.count
    +           );
    +-          nByte += sqlite3MallocSize(pSchema->tblHash.ht);
    +-          nByte += sqlite3MallocSize(pSchema->trigHash.ht);
    +-          nByte += sqlite3MallocSize(pSchema->idxHash.ht);
    +-          nByte += sqlite3MallocSize(pSchema->fkeyHash.ht);
    ++          nByte += sqlite3_msize(pSchema->tblHash.ht);
    ++          nByte += sqlite3_msize(pSchema->trigHash.ht);
    ++          nByte += sqlite3_msize(pSchema->idxHash.ht);
    ++          nByte += sqlite3_msize(pSchema->fkeyHash.ht);
    + 
    +           for(p=sqliteHashFirst(&pSchema->trigHash); p; p=sqliteHashNext(p)){
    +             sqlite3DeleteTrigger(db, (Trigger*)sqliteHashData(p));
    +@@ -16122,7 +19597,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_db_status(
    + **
    + **      Jean Meeus
    + **      Astronomical Algorithms, 2nd Edition, 1998
    +-**      ISBM 0-943396-61-1
    ++**      ISBN 0-943396-61-1
    + **      Willmann-Bell, Inc
    + **      Richmond, Virginia (USA)
    + */
    +@@ -16133,53 +19608,80 @@ SQLITE_API int SQLITE_STDCALL sqlite3_db_status(
    + 
    + #ifndef SQLITE_OMIT_DATETIME_FUNCS
    + 
    ++/*
    ++** The MSVC CRT on Windows CE may not have a localtime() function.
    ++** So declare a substitute.  The substitute function itself is
    ++** defined in "os_win.c".
    ++*/
    ++#if !defined(SQLITE_OMIT_LOCALTIME) && defined(_WIN32_WCE) && \
    ++    (!defined(SQLITE_MSVC_LOCALTIME_API) || !SQLITE_MSVC_LOCALTIME_API)
    ++struct tm *__cdecl localtime(const time_t *);
    ++#endif
    + 
    + /*
    + ** A structure for holding a single date and time.
    + */
    + typedef struct DateTime DateTime;
    + struct DateTime {
    +-  sqlite3_int64 iJD; /* The julian day number times 86400000 */
    +-  int Y, M, D;       /* Year, month, and day */
    +-  int h, m;          /* Hour and minutes */
    +-  int tz;            /* Timezone offset in minutes */
    +-  double s;          /* Seconds */
    +-  char validYMD;     /* True (1) if Y,M,D are valid */
    +-  char validHMS;     /* True (1) if h,m,s are valid */
    +-  char validJD;      /* True (1) if iJD is valid */
    +-  char validTZ;      /* True (1) if tz is valid */
    ++  sqlite3_int64 iJD;  /* The julian day number times 86400000 */
    ++  int Y, M, D;        /* Year, month, and day */
    ++  int h, m;           /* Hour and minutes */
    ++  int tz;             /* Timezone offset in minutes */
    ++  double s;           /* Seconds */
    ++  char validJD;       /* True (1) if iJD is valid */
    ++  char rawS;          /* Raw numeric value stored in s */
    ++  char validYMD;      /* True (1) if Y,M,D are valid */
    ++  char validHMS;      /* True (1) if h,m,s are valid */
    ++  char validTZ;       /* True (1) if tz is valid */
    ++  char tzSet;         /* Timezone was set explicitly */
    ++  char isError;       /* An overflow has occurred */
    + };
    + 
    + 
    + /*
    +-** Convert zDate into one or more integers.  Additional arguments
    +-** come in groups of 5 as follows:
    ++** Convert zDate into one or more integers according to the conversion
    ++** specifier zFormat.
    ++**
    ++** zFormat[] contains 4 characters for each integer converted, except for
    ++** the last integer which is specified by three characters.  The meaning
    ++** of a four-character format specifiers ABCD is:
    + **
    +-**       N       number of digits in the integer
    +-**       min     minimum allowed value of the integer
    +-**       max     maximum allowed value of the integer
    +-**       nextC   first character after the integer
    +-**       pVal    where to write the integers value.
    ++**    A:   number of digits to convert.  Always "2" or "4".
    ++**    B:   minimum value.  Always "0" or "1".
    ++**    C:   maximum value, decoded as:
    ++**           a:  12
    ++**           b:  14
    ++**           c:  24
    ++**           d:  31
    ++**           e:  59
    ++**           f:  9999
    ++**    D:   the separator character, or \000 to indicate this is the
    ++**         last number to convert.
    ++**
    ++** Example:  To translate an ISO-8601 date YYYY-MM-DD, the format would
    ++** be "40f-21a-20c".  The "40f-" indicates the 4-digit year followed by "-".
    ++** The "21a-" indicates the 2-digit month followed by "-".  The "20c" indicates
    ++** the 2-digit day which is the last integer in the set.
    + **
    +-** Conversions continue until one with nextC==0 is encountered.
    + ** The function returns the number of successful conversions.
    + */
    +-static int getDigits(const char *zDate, ...){
    ++static int getDigits(const char *zDate, const char *zFormat, ...){
    ++  /* The aMx[] array translates the 3rd character of each format
    ++  ** spec into a max size:    a   b   c   d   e     f */
    ++  static const u16 aMx[] = { 12, 14, 24, 31, 59, 9999 };
    +   va_list ap;
    +-  int val;
    +-  int N;
    +-  int min;
    +-  int max;
    +-  int nextC;
    +-  int *pVal;
    +   int cnt = 0;
    +-  va_start(ap, zDate);
    ++  char nextC;
    ++  va_start(ap, zFormat);
    +   do{
    +-    N = va_arg(ap, int);
    +-    min = va_arg(ap, int);
    +-    max = va_arg(ap, int);
    +-    nextC = va_arg(ap, int);
    +-    pVal = va_arg(ap, int*);
    ++    char N = zFormat[0] - '0';
    ++    char min = zFormat[1] - '0';
    ++    int val = 0;
    ++    u16 max;
    ++
    ++    assert( zFormat[2]>='a' && zFormat[2]<='f' );
    ++    max = aMx[zFormat[2] - 'a'];
    ++    nextC = zFormat[3];
    +     val = 0;
    +     while( N-- ){
    +       if( !sqlite3Isdigit(*zDate) ){
    +@@ -16188,12 +19690,13 @@ static int getDigits(const char *zDate, ...){
    +       val = val*10 + *zDate - '0';
    +       zDate++;
    +     }
    +-    if( val<min || val>max || (nextC!=0 && nextC!=*zDate) ){
    ++    if( val<(int)min || val>(int)max || (nextC!=0 && nextC!=*zDate) ){
    +       goto end_getDigits;
    +     }
    +-    *pVal = val;
    ++    *va_arg(ap,int*) = val;
    +     zDate++;
    +     cnt++;
    ++    zFormat += 4;
    +   }while( nextC );
    + end_getDigits:
    +   va_end(ap);
    +@@ -16234,13 +19737,14 @@ static int parseTimezone(const char *zDate, DateTime *p){
    +     return c!=0;
    +   }
    +   zDate++;
    +-  if( getDigits(zDate, 2, 0, 14, ':', &nHr, 2, 0, 59, 0, &nMn)!=2 ){
    ++  if( getDigits(zDate, "20b:20e", &nHr, &nMn)!=2 ){
    +     return 1;
    +   }
    +   zDate += 5;
    +   p->tz = sgn*(nMn + nHr*60);
    + zulu_time:
    +   while( sqlite3Isspace(*zDate) ){ zDate++; }
    ++  p->tzSet = 1;
    +   return *zDate!=0;
    + }
    + 
    +@@ -16254,13 +19758,13 @@ zulu_time:
    + static int parseHhMmSs(const char *zDate, DateTime *p){
    +   int h, m, s;
    +   double ms = 0.0;
    +-  if( getDigits(zDate, 2, 0, 24, ':', &h, 2, 0, 59, 0, &m)!=2 ){
    ++  if( getDigits(zDate, "20c:20e", &h, &m)!=2 ){
    +     return 1;
    +   }
    +   zDate += 5;
    +   if( *zDate==':' ){
    +     zDate++;
    +-    if( getDigits(zDate, 2, 0, 59, 0, &s)!=1 ){
    ++    if( getDigits(zDate, "20e", &s)!=1 ){
    +       return 1;
    +     }
    +     zDate += 2;
    +@@ -16278,6 +19782,7 @@ static int parseHhMmSs(const char *zDate, DateTime *p){
    +     s = 0;
    +   }
    +   p->validJD = 0;
    ++  p->rawS = 0;
    +   p->validHMS = 1;
    +   p->h = h;
    +   p->m = m;
    +@@ -16287,6 +19792,14 @@ static int parseHhMmSs(const char *zDate, DateTime *p){
    +   return 0;
    + }
    + 
    ++/*
    ++** Put the DateTime object into its error state.
    ++*/
    ++static void datetimeError(DateTime *p){
    ++  memset(p, 0, sizeof(*p));
    ++  p->isError = 1;
    ++}
    ++
    + /*
    + ** Convert from YYYY-MM-DD HH:MM:SS to julian day.  We always assume
    + ** that the YYYY-MM-DD is according to the Gregorian calendar.
    +@@ -16306,6 +19819,10 @@ static void computeJD(DateTime *p){
    +     M = 1;
    +     D = 1;
    +   }
    ++  if( Y<-4713 || Y>9999 || p->rawS ){
    ++    datetimeError(p);
    ++    return;
    ++  }
    +   if( M<=2 ){
    +     Y--;
    +     M += 12;
    +@@ -16348,7 +19865,7 @@ static int parseYyyyMmDd(const char *zDate, DateTime *p){
    +   }else{
    +     neg = 0;
    +   }
    +-  if( getDigits(zDate,4,0,9999,'-',&Y,2,1,12,'-',&M,2,1,31,0,&D)!=3 ){
    ++  if( getDigits(zDate, "40f-21a-21d", &Y, &M, &D)!=3 ){
    +     return 1;
    +   }
    +   zDate += 10;
    +@@ -16386,6 +19903,21 @@ static int setDateTimeToCurrent(sqlite3_context *context, DateTime *p){
    +   }
    + }
    + 
    ++/*
    ++** Input "r" is a numeric quantity which might be a julian day number,
    ++** or the number of seconds since 1970.  If the value if r is within
    ++** range of a julian day number, install it as such and set validJD.
    ++** If the value is a valid unix timestamp, put it in p->s and set p->rawS.
    ++*/
    ++static void setRawDateNumber(DateTime *p, double r){
    ++  p->s = r;
    ++  p->rawS = 1;
    ++  if( r>=0.0 && r<5373484.5 ){
    ++    p->iJD = (sqlite3_int64)(r*86400000.0 + 0.5);
    ++    p->validJD = 1;
    ++  }
    ++}
    ++
    + /*
    + ** Attempt to parse the given string into a julian day number.  Return
    + ** the number of errors.
    +@@ -16412,16 +19944,33 @@ static int parseDateOrTime(
    +     return 0;
    +   }else if( parseHhMmSs(zDate, p)==0 ){
    +     return 0;
    +-  }else if( sqlite3StrICmp(zDate,"now")==0){
    ++  }else if( sqlite3StrICmp(zDate,"now")==0 && sqlite3NotPureFunc(context) ){
    +     return setDateTimeToCurrent(context, p);
    +   }else if( sqlite3AtoF(zDate, &r, sqlite3Strlen30(zDate), SQLITE_UTF8) ){
    +-    p->iJD = (sqlite3_int64)(r*86400000.0 + 0.5);
    +-    p->validJD = 1;
    ++    setRawDateNumber(p, r);
    +     return 0;
    +   }
    +   return 1;
    + }
    + 
    ++/* The julian day number for 9999-12-31 23:59:59.999 is 5373484.4999999.
    ++** Multiplying this by 86400000 gives 464269060799999 as the maximum value
    ++** for DateTime.iJD.
    ++**
    ++** But some older compilers (ex: gcc 4.2.1 on older Macs) cannot deal with 
    ++** such a large integer literal, so we have to encode it.
    ++*/
    ++#define INT_464269060799999  ((((i64)0x1a640)<<32)|0x1072fdff)
    ++
    ++/*
    ++** Return TRUE if the given julian day number is within range.
    ++**
    ++** The input is the JulianDay times 86400000.
    ++*/
    ++static int validJulianDay(sqlite3_int64 iJD){
    ++  return iJD>=0 && iJD<=INT_464269060799999;
    ++}
    ++
    + /*
    + ** Compute the Year, Month, and Day from the julian day number.
    + */
    +@@ -16432,6 +19981,9 @@ static void computeYMD(DateTime *p){
    +     p->Y = 2000;
    +     p->M = 1;
    +     p->D = 1;
    ++  }else if( !validJulianDay(p->iJD) ){
    ++    datetimeError(p);
    ++    return;
    +   }else{
    +     Z = (int)((p->iJD + 43200000)/86400000);
    +     A = (int)((Z - 1867216.25)/36524.25);
    +@@ -16463,6 +20015,7 @@ static void computeHMS(DateTime *p){
    +   s -= p->h*3600;
    +   p->m = s/60;
    +   p->s += s - p->m*60;
    ++  p->rawS = 0;
    +   p->validHMS = 1;
    + }
    + 
    +@@ -16483,6 +20036,7 @@ static void clearYMD_HMS_TZ(DateTime *p){
    +   p->validTZ = 0;
    + }
    + 
    ++#ifndef SQLITE_OMIT_LOCALTIME
    + /*
    + ** On recent Windows platforms, the localtime_s() function is available
    + ** as part of the "Secure CRT". It is essentially equivalent to 
    +@@ -16501,7 +20055,6 @@ static void clearYMD_HMS_TZ(DateTime *p){
    + #define HAVE_LOCALTIME_S 1
    + #endif
    + 
    +-#ifndef SQLITE_OMIT_LOCALTIME
    + /*
    + ** The following routine implements the rough equivalent of localtime_r()
    + ** using whatever operating-system specific localtime facility that
    +@@ -16524,14 +20077,14 @@ static int osLocaltime(time_t *t, struct tm *pTm){
    + #endif
    +   sqlite3_mutex_enter(mutex);
    +   pX = localtime(t);
    +-#ifndef SQLITE_OMIT_BUILTIN_TEST
    ++#ifndef SQLITE_UNTESTABLE
    +   if( sqlite3GlobalConfig.bLocaltimeFault ) pX = 0;
    + #endif
    +   if( pX ) *pTm = *pX;
    +   sqlite3_mutex_leave(mutex);
    +   rc = pX==0;
    + #else
    +-#ifndef SQLITE_OMIT_BUILTIN_TEST
    ++#ifndef SQLITE_UNTESTABLE
    +   if( sqlite3GlobalConfig.bLocaltimeFault ) return 1;
    + #endif
    + #if HAVE_LOCALTIME_R
    +@@ -16602,13 +20155,38 @@ static sqlite3_int64 localtimeOffset(
    +   y.validYMD = 1;
    +   y.validHMS = 1;
    +   y.validJD = 0;
    ++  y.rawS = 0;
    +   y.validTZ = 0;
    ++  y.isError = 0;
    +   computeJD(&y);
    +   *pRc = SQLITE_OK;
    +   return y.iJD - x.iJD;
    + }
    + #endif /* SQLITE_OMIT_LOCALTIME */
    + 
    ++/*
    ++** The following table defines various date transformations of the form
    ++**
    ++**            'NNN days'
    ++**
    ++** Where NNN is an arbitrary floating-point number and "days" can be one
    ++** of several units of time.
    ++*/
    ++static const struct {
    ++  u8 eType;           /* Transformation type code */
    ++  u8 nName;           /* Length of th name */
    ++  char *zName;        /* Name of the transformation */
    ++  double rLimit;      /* Maximum NNN value for this transform */
    ++  double rXform;      /* Constant used for this transform */
    ++} aXformType[] = {
    ++  { 0, 6, "second", 464269060800.0, 86400000.0/(24.0*60.0*60.0) },
    ++  { 0, 6, "minute", 7737817680.0,   86400000.0/(24.0*60.0)      },
    ++  { 0, 4, "hour",   128963628.0,    86400000.0/24.0             },
    ++  { 0, 3, "day",    5373485.0,      86400000.0                  },
    ++  { 1, 5, "month",  176546.0,       30.0*86400000.0             },
    ++  { 2, 4, "year",   14713.0,        365.0*86400000.0            },
    ++};
    ++
    + /*
    + ** Process a modifier to a date-time stamp.  The modifiers are
    + ** as follows:
    +@@ -16633,17 +20211,15 @@ static sqlite3_int64 localtimeOffset(
    + ** to context pCtx. If the error is an unrecognized modifier, no error is
    + ** written to pCtx.
    + */
    +-static int parseModifier(sqlite3_context *pCtx, const char *zMod, DateTime *p){
    ++static int parseModifier(
    ++  sqlite3_context *pCtx,      /* Function context */
    ++  const char *z,              /* The text of the modifier */
    ++  int n,                      /* Length of zMod in bytes */
    ++  DateTime *p                 /* The date/time value to be modified */
    ++){
    +   int rc = 1;
    +-  int n;
    +   double r;
    +-  char *z, zBuf[30];
    +-  z = zBuf;
    +-  for(n=0; n<ArraySize(zBuf)-1 && zMod[n]; n++){
    +-    z[n] = (char)sqlite3UpperToLower[(u8)zMod[n]];
    +-  }
    +-  z[n] = 0;
    +-  switch( z[0] ){
    ++  switch(sqlite3UpperToLower[(u8)z[0]] ){
    + #ifndef SQLITE_OMIT_LOCALTIME
    +     case 'l': {
    +       /*    localtime
    +@@ -16651,7 +20227,7 @@ static int parseModifier(sqlite3_context *pCtx, const char *zMod, DateTime *p){
    +       ** Assuming the current time value is UTC (a.k.a. GMT), shift it to
    +       ** show local time.
    +       */
    +-      if( strcmp(z, "localtime")==0 ){
    ++      if( sqlite3_stricmp(z, "localtime")==0 && sqlite3NotPureFunc(pCtx) ){
    +         computeJD(p);
    +         p->iJD += localtimeOffset(p, pCtx, &rc);
    +         clearYMD_HMS_TZ(p);
    +@@ -16663,23 +20239,33 @@ static int parseModifier(sqlite3_context *pCtx, const char *zMod, DateTime *p){
    +       /*
    +       **    unixepoch
    +       **
    +-      ** Treat the current value of p->iJD as the number of
    ++      ** Treat the current value of p->s as the number of
    +       ** seconds since 1970.  Convert to a real julian day number.
    +       */
    +-      if( strcmp(z, "unixepoch")==0 && p->validJD ){
    +-        p->iJD = (p->iJD + 43200)/86400 + 21086676*(i64)10000000;
    +-        clearYMD_HMS_TZ(p);
    +-        rc = 0;
    ++      if( sqlite3_stricmp(z, "unixepoch")==0 && p->rawS ){
    ++        r = p->s*1000.0 + 210866760000000.0;
    ++        if( r>=0.0 && r<464269060800000.0 ){
    ++          clearYMD_HMS_TZ(p);
    ++          p->iJD = (sqlite3_int64)r;
    ++          p->validJD = 1;
    ++          p->rawS = 0;
    ++          rc = 0;
    ++        }
    +       }
    + #ifndef SQLITE_OMIT_LOCALTIME
    +-      else if( strcmp(z, "utc")==0 ){
    +-        sqlite3_int64 c1;
    +-        computeJD(p);
    +-        c1 = localtimeOffset(p, pCtx, &rc);
    +-        if( rc==SQLITE_OK ){
    +-          p->iJD -= c1;
    +-          clearYMD_HMS_TZ(p);
    +-          p->iJD += c1 - localtimeOffset(p, pCtx, &rc);
    ++      else if( sqlite3_stricmp(z, "utc")==0 && sqlite3NotPureFunc(pCtx) ){
    ++        if( p->tzSet==0 ){
    ++          sqlite3_int64 c1;
    ++          computeJD(p);
    ++          c1 = localtimeOffset(p, pCtx, &rc);
    ++          if( rc==SQLITE_OK ){
    ++            p->iJD -= c1;
    ++            clearYMD_HMS_TZ(p);
    ++            p->iJD += c1 - localtimeOffset(p, pCtx, &rc);
    ++          }
    ++          p->tzSet = 1;
    ++        }else{
    ++          rc = SQLITE_OK;
    +         }
    +       }
    + #endif
    +@@ -16693,7 +20279,7 @@ static int parseModifier(sqlite3_context *pCtx, const char *zMod, DateTime *p){
    +       ** weekday N where 0==Sunday, 1==Monday, and so forth.  If the
    +       ** date is already on the appropriate weekday, this is a no-op.
    +       */
    +-      if( strncmp(z, "weekday ", 8)==0
    ++      if( sqlite3_strnicmp(z, "weekday ", 8)==0
    +                && sqlite3AtoF(&z[8], &r, sqlite3Strlen30(&z[8]), SQLITE_UTF8)
    +                && (n=(int)r)==r && n>=0 && r<7 ){
    +         sqlite3_int64 Z;
    +@@ -16716,23 +20302,24 @@ static int parseModifier(sqlite3_context *pCtx, const char *zMod, DateTime *p){
    +       ** Move the date backwards to the beginning of the current day,
    +       ** or month or year.
    +       */
    +-      if( strncmp(z, "start of ", 9)!=0 ) break;
    ++      if( sqlite3_strnicmp(z, "start of ", 9)!=0 ) break;
    ++      if( !p->validJD && !p->validYMD && !p->validHMS ) break;
    +       z += 9;
    +       computeYMD(p);
    +       p->validHMS = 1;
    +       p->h = p->m = 0;
    +       p->s = 0.0;
    ++      p->rawS = 0;
    +       p->validTZ = 0;
    +       p->validJD = 0;
    +-      if( strcmp(z,"month")==0 ){
    ++      if( sqlite3_stricmp(z,"month")==0 ){
    +         p->D = 1;
    +         rc = 0;
    +-      }else if( strcmp(z,"year")==0 ){
    +-        computeYMD(p);
    ++      }else if( sqlite3_stricmp(z,"year")==0 ){
    +         p->M = 1;
    +         p->D = 1;
    +         rc = 0;
    +-      }else if( strcmp(z,"day")==0 ){
    ++      }else if( sqlite3_stricmp(z,"day")==0 ){
    +         rc = 0;
    +       }
    +       break;
    +@@ -16750,6 +20337,7 @@ static int parseModifier(sqlite3_context *pCtx, const char *zMod, DateTime *p){
    +     case '8':
    +     case '9': {
    +       double rRounder;
    ++      int i;
    +       for(n=1; z[n] && z[n]!=':' && !sqlite3Isspace(z[n]); n++){}
    +       if( !sqlite3AtoF(z, &r, n, SQLITE_UTF8) ){
    +         rc = 1;
    +@@ -16778,46 +20366,48 @@ static int parseModifier(sqlite3_context *pCtx, const char *zMod, DateTime *p){
    +         rc = 0;
    +         break;
    +       }
    ++
    ++      /* If control reaches this point, it means the transformation is
    ++      ** one of the forms like "+NNN days".  */
    +       z += n;
    +       while( sqlite3Isspace(*z) ) z++;
    +       n = sqlite3Strlen30(z);
    +       if( n>10 || n<3 ) break;
    +-      if( z[n-1]=='s' ){ z[n-1] = 0; n--; }
    ++      if( sqlite3UpperToLower[(u8)z[n-1]]=='s' ) n--;
    +       computeJD(p);
    +-      rc = 0;
    ++      rc = 1;
    +       rRounder = r<0 ? -0.5 : +0.5;
    +-      if( n==3 && strcmp(z,"day")==0 ){
    +-        p->iJD += (sqlite3_int64)(r*86400000.0 + rRounder);
    +-      }else if( n==4 && strcmp(z,"hour")==0 ){
    +-        p->iJD += (sqlite3_int64)(r*(86400000.0/24.0) + rRounder);
    +-      }else if( n==6 && strcmp(z,"minute")==0 ){
    +-        p->iJD += (sqlite3_int64)(r*(86400000.0/(24.0*60.0)) + rRounder);
    +-      }else if( n==6 && strcmp(z,"second")==0 ){
    +-        p->iJD += (sqlite3_int64)(r*(86400000.0/(24.0*60.0*60.0)) + rRounder);
    +-      }else if( n==5 && strcmp(z,"month")==0 ){
    +-        int x, y;
    +-        computeYMD_HMS(p);
    +-        p->M += (int)r;
    +-        x = p->M>0 ? (p->M-1)/12 : (p->M-12)/12;
    +-        p->Y += x;
    +-        p->M -= x*12;
    +-        p->validJD = 0;
    +-        computeJD(p);
    +-        y = (int)r;
    +-        if( y!=r ){
    +-          p->iJD += (sqlite3_int64)((r - y)*30.0*86400000.0 + rRounder);
    +-        }
    +-      }else if( n==4 && strcmp(z,"year")==0 ){
    +-        int y = (int)r;
    +-        computeYMD_HMS(p);
    +-        p->Y += y;
    +-        p->validJD = 0;
    +-        computeJD(p);
    +-        if( y!=r ){
    +-          p->iJD += (sqlite3_int64)((r - y)*365.0*86400000.0 + rRounder);
    ++      for(i=0; i<ArraySize(aXformType); i++){
    ++        if( aXformType[i].nName==n
    ++         && sqlite3_strnicmp(aXformType[i].zName, z, n)==0
    ++         && r>-aXformType[i].rLimit && r<aXformType[i].rLimit
    ++        ){
    ++          switch( aXformType[i].eType ){
    ++            case 1: { /* Special processing to add months */
    ++              int x;
    ++              computeYMD_HMS(p);
    ++              p->M += (int)r;
    ++              x = p->M>0 ? (p->M-1)/12 : (p->M-12)/12;
    ++              p->Y += x;
    ++              p->M -= x*12;
    ++              p->validJD = 0;
    ++              r -= (int)r;
    ++              break;
    ++            }
    ++            case 2: { /* Special processing to add years */
    ++              int y = (int)r;
    ++              computeYMD_HMS(p);
    ++              p->Y += y;
    ++              p->validJD = 0;
    ++              r -= (int)r;
    ++              break;
    ++            }
    ++          }
    ++          computeJD(p);
    ++          p->iJD += (sqlite3_int64)(r*aXformType[i].rXform + rRounder);
    ++          rc = 0;
    ++          break;
    +         }
    +-      }else{
    +-        rc = 1;
    +       }
    +       clearYMD_HMS_TZ(p);
    +       break;
    +@@ -16844,7 +20434,7 @@ static int isDate(
    +   sqlite3_value **argv, 
    +   DateTime *p
    + ){
    +-  int i;
    ++  int i, n;
    +   const unsigned char *z;
    +   int eType;
    +   memset(p, 0, sizeof(*p));
    +@@ -16853,8 +20443,7 @@ static int isDate(
    +   }
    +   if( (eType = sqlite3_value_type(argv[0]))==SQLITE_FLOAT
    +                    || eType==SQLITE_INTEGER ){
    +-    p->iJD = (sqlite3_int64)(sqlite3_value_double(argv[0])*86400000.0 + 0.5);
    +-    p->validJD = 1;
    ++    setRawDateNumber(p, sqlite3_value_double(argv[0]));
    +   }else{
    +     z = sqlite3_value_text(argv[0]);
    +     if( !z || parseDateOrTime(context, (char*)z, p) ){
    +@@ -16863,8 +20452,11 @@ static int isDate(
    +   }
    +   for(i=1; i<argc; i++){
    +     z = sqlite3_value_text(argv[i]);
    +-    if( z==0 || parseModifier(context, (char*)z, p) ) return 1;
    ++    n = sqlite3_value_bytes(argv[i]);
    ++    if( z==0 || parseModifier(context, (char*)z, n, p) ) return 1;
    +   }
    ++  computeJD(p);
    ++  if( p->isError || !validJulianDay(p->iJD) ) return 1;
    +   return 0;
    + }
    + 
    +@@ -17027,7 +20619,7 @@ static void strftimeFunc(
    +     sqlite3_result_error_toobig(context);
    +     return;
    +   }else{
    +-    z = sqlite3DbMallocRaw(db, (int)n);
    ++    z = sqlite3DbMallocRawNN(db, (int)n);
    +     if( z==0 ){
    +       sqlite3_result_error_nomem(context);
    +       return;
    +@@ -17163,7 +20755,6 @@ static void currentTimeFunc(
    + ){
    +   time_t t;
    +   char *zFormat = (char *)sqlite3_user_data(context);
    +-  sqlite3 *db;
    +   sqlite3_int64 iT;
    +   struct tm *pTm;
    +   struct tm sNow;
    +@@ -17196,13 +20787,13 @@ static void currentTimeFunc(
    + ** external linkage.
    + */
    + SQLITE_PRIVATE void sqlite3RegisterDateTimeFunctions(void){
    +-  static SQLITE_WSD FuncDef aDateTimeFuncs[] = {
    ++  static FuncDef aDateTimeFuncs[] = {
    + #ifndef SQLITE_OMIT_DATETIME_FUNCS
    +-    DFUNCTION(julianday,        -1, 0, 0, juliandayFunc ),
    +-    DFUNCTION(date,             -1, 0, 0, dateFunc      ),
    +-    DFUNCTION(time,             -1, 0, 0, timeFunc      ),
    +-    DFUNCTION(datetime,         -1, 0, 0, datetimeFunc  ),
    +-    DFUNCTION(strftime,         -1, 0, 0, strftimeFunc  ),
    ++    PURE_DATE(julianday,        -1, 0, 0, juliandayFunc ),
    ++    PURE_DATE(date,             -1, 0, 0, dateFunc      ),
    ++    PURE_DATE(time,             -1, 0, 0, timeFunc      ),
    ++    PURE_DATE(datetime,         -1, 0, 0, datetimeFunc  ),
    ++    PURE_DATE(strftime,         -1, 0, 0, strftimeFunc  ),
    +     DFUNCTION(current_time,      0, 0, 0, ctimeFunc     ),
    +     DFUNCTION(current_timestamp, 0, 0, 0, ctimestampFunc),
    +     DFUNCTION(current_date,      0, 0, 0, cdateFunc     ),
    +@@ -17212,13 +20803,7 @@ SQLITE_PRIVATE void sqlite3RegisterDateTimeFunctions(void){
    +     STR_FUNCTION(current_timestamp, 0, "%Y-%m-%d %H:%M:%S", 0, currentTimeFunc),
    + #endif
    +   };
    +-  int i;
    +-  FuncDefHash *pHash = &GLOBAL(FuncDefHash, sqlite3GlobalFunctions);
    +-  FuncDef *aFunc = (FuncDef*)&GLOBAL(FuncDef, aDateTimeFuncs);
    +-
    +-  for(i=0; i<ArraySize(aDateTimeFuncs); i++){
    +-    sqlite3FuncDefInsert(pHash, &aFunc[i]);
    +-  }
    ++  sqlite3InsertBuiltinFuncs(aDateTimeFuncs, ArraySize(aDateTimeFuncs));
    + }
    + 
    + /************** End of date.c ************************************************/
    +@@ -17238,9 +20823,29 @@ SQLITE_PRIVATE void sqlite3RegisterDateTimeFunctions(void){
    + ** This file contains OS interface code that is common to all
    + ** architectures.
    + */
    +-#define _SQLITE_OS_C_ 1
    + /* #include "sqliteInt.h" */
    +-#undef _SQLITE_OS_C_
    ++
    ++/*
    ++** 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.
    ++*/
    ++#if defined(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;
    ++#endif /* defined(SQLITE_TEST) */
    ++
    ++/*
    ++** When testing, also keep a count of the number of open files.
    ++*/
    ++#if defined(SQLITE_TEST)
    ++SQLITE_API int sqlite3_open_file_count = 0;
    ++#endif /* defined(SQLITE_TEST) */
    + 
    + /*
    + ** The default SQLite sqlite3_vfs implementations do not allocate
    +@@ -17249,7 +20854,7 @@ SQLITE_PRIVATE void sqlite3RegisterDateTimeFunctions(void){
    + ** So we test the effects of a malloc() failing and the sqlite3OsXXX()
    + ** function returning SQLITE_IOERR_NOMEM using the DO_OS_MALLOC_TEST macro.
    + **
    +-** The following functions are instrumented for malloc() failure 
    ++** The following functions are instrumented for malloc() failure
    + ** testing:
    + **
    + **     sqlite3OsRead()
    +@@ -17269,9 +20874,9 @@ SQLITE_PRIVATE void sqlite3RegisterDateTimeFunctions(void){
    + #if defined(SQLITE_TEST)
    + SQLITE_API int sqlite3_memdebug_vfs_oom_test = 1;
    +   #define DO_OS_MALLOC_TEST(x)                                       \
    +-  if (sqlite3_memdebug_vfs_oom_test && (!x || !sqlite3IsMemJournal(x))) {  \
    ++  if (sqlite3_memdebug_vfs_oom_test && (!x || !sqlite3JournalIsInMemory(x))) { \
    +     void *pTstAlloc = sqlite3Malloc(10);                             \
    +-    if (!pTstAlloc) return SQLITE_IOERR_NOMEM;                       \
    ++    if (!pTstAlloc) return SQLITE_IOERR_NOMEM_BKPT;                  \
    +     sqlite3_free(pTstAlloc);                                         \
    +   }
    + #else
    +@@ -17284,13 +20889,11 @@ SQLITE_API int sqlite3_memdebug_vfs_oom_test = 1;
    + ** of this would be completely automatic if SQLite were coded using
    + ** C++ instead of plain old C.
    + */
    +-SQLITE_PRIVATE int sqlite3OsClose(sqlite3_file *pId){
    +-  int rc = SQLITE_OK;
    ++SQLITE_PRIVATE void sqlite3OsClose(sqlite3_file *pId){
    +   if( pId->pMethods ){
    +-    rc = pId->pMethods->xClose(pId);
    ++    pId->pMethods->xClose(pId);
    +     pId->pMethods = 0;
    +   }
    +-  return rc;
    + }
    + SQLITE_PRIVATE int sqlite3OsRead(sqlite3_file *id, void *pBuf, int amt, i64 offset){
    +   DO_OS_MALLOC_TEST(id);
    +@@ -17305,7 +20908,7 @@ SQLITE_PRIVATE int sqlite3OsTruncate(sqlite3_file *id, i64 size){
    + }
    + SQLITE_PRIVATE int sqlite3OsSync(sqlite3_file *id, int flags){
    +   DO_OS_MALLOC_TEST(id);
    +-  return id->pMethods->xSync(id, flags);
    ++  return flags ? id->pMethods->xSync(id, flags) : SQLITE_OK;
    + }
    + SQLITE_PRIVATE int sqlite3OsFileSize(sqlite3_file *id, i64 *pSize){
    +   DO_OS_MALLOC_TEST(id);
    +@@ -17335,8 +20938,8 @@ SQLITE_PRIVATE int sqlite3OsFileControl(sqlite3_file *id, int op, void *pArg){
    + #ifdef SQLITE_TEST
    +   if( op!=SQLITE_FCNTL_COMMIT_PHASETWO ){
    +     /* Faults are not injected into COMMIT_PHASETWO because, assuming SQLite
    +-    ** is using a regular VFS, it is called after the corresponding 
    +-    ** transaction has been committed. Injecting a fault at this point 
    ++    ** is using a regular VFS, it is called after the corresponding
    ++    ** transaction has been committed. Injecting a fault at this point
    +     ** confuses the test scripts - the COMMIT comand returns SQLITE_NOMEM
    +     ** but the transaction is committed anyway.
    +     **
    +@@ -17360,6 +20963,7 @@ SQLITE_PRIVATE int sqlite3OsSectorSize(sqlite3_file *id){
    + SQLITE_PRIVATE int sqlite3OsDeviceCharacteristics(sqlite3_file *id){
    +   return id->pMethods->xDeviceCharacteristics(id);
    + }
    ++#ifndef SQLITE_OMIT_WAL
    + SQLITE_PRIVATE int sqlite3OsShmLock(sqlite3_file *id, int offset, int n, int flags){
    +   return id->pMethods->xShmLock(id, offset, n, flags);
    + }
    +@@ -17379,6 +20983,7 @@ SQLITE_PRIVATE int sqlite3OsShmMap(
    +   DO_OS_MALLOC_TEST(id);
    +   return id->pMethods->xShmMap(id, iPage, pgsz, bExtend, pp);
    + }
    ++#endif /* SQLITE_OMIT_WAL */
    + 
    + #if SQLITE_MAX_MMAP_SIZE>0
    + /* The real implementation of xFetch and xUnfetch */
    +@@ -17405,10 +21010,10 @@ SQLITE_PRIVATE int sqlite3OsUnfetch(sqlite3_file *id, i64 iOff, void *p){
    + ** VFS methods.
    + */
    + SQLITE_PRIVATE int sqlite3OsOpen(
    +-  sqlite3_vfs *pVfs, 
    +-  const char *zPath, 
    +-  sqlite3_file *pFile, 
    +-  int flags, 
    ++  sqlite3_vfs *pVfs,
    ++  const char *zPath,
    ++  sqlite3_file *pFile,
    ++  int flags,
    +   int *pFlagsOut
    + ){
    +   int rc;
    +@@ -17427,18 +21032,18 @@ SQLITE_PRIVATE int sqlite3OsDelete(sqlite3_vfs *pVfs, const char *zPath, int dir
    +   return pVfs->xDelete(pVfs, zPath, dirSync);
    + }
    + SQLITE_PRIVATE int sqlite3OsAccess(
    +-  sqlite3_vfs *pVfs, 
    +-  const char *zPath, 
    +-  int flags, 
    ++  sqlite3_vfs *pVfs,
    ++  const char *zPath,
    ++  int flags,
    +   int *pResOut
    + ){
    +   DO_OS_MALLOC_TEST(0);
    +   return pVfs->xAccess(pVfs, zPath, flags, pResOut);
    + }
    + SQLITE_PRIVATE int sqlite3OsFullPathname(
    +-  sqlite3_vfs *pVfs, 
    +-  const char *zPath, 
    +-  int nPathOut, 
    ++  sqlite3_vfs *pVfs,
    ++  const char *zPath,
    ++  int nPathOut,
    +   char *zPathOut
    + ){
    +   DO_OS_MALLOC_TEST(0);
    +@@ -17465,6 +21070,9 @@ SQLITE_PRIVATE int sqlite3OsRandomness(sqlite3_vfs *pVfs, int nByte, char *zBufO
    + SQLITE_PRIVATE int sqlite3OsSleep(sqlite3_vfs *pVfs, int nMicro){
    +   return pVfs->xSleep(pVfs, nMicro);
    + }
    ++SQLITE_PRIVATE int sqlite3OsGetLastError(sqlite3_vfs *pVfs){
    ++  return pVfs->xGetLastError ? pVfs->xGetLastError(pVfs, 0, 0) : 0;
    ++}
    + SQLITE_PRIVATE int sqlite3OsCurrentTimeInt64(sqlite3_vfs *pVfs, sqlite3_int64 *pTimeOut){
    +   int rc;
    +   /* IMPLEMENTATION-OF: R-49045-42493 SQLite will use the xCurrentTimeInt64()
    +@@ -17484,13 +21092,13 @@ SQLITE_PRIVATE int sqlite3OsCurrentTimeInt64(sqlite3_vfs *pVfs, sqlite3_int64 *p
    + }
    + 
    + SQLITE_PRIVATE int sqlite3OsOpenMalloc(
    +-  sqlite3_vfs *pVfs, 
    +-  const char *zFile, 
    +-  sqlite3_file **ppFile, 
    ++  sqlite3_vfs *pVfs,
    ++  const char *zFile,
    ++  sqlite3_file **ppFile,
    +   int flags,
    +   int *pOutFlags
    + ){
    +-  int rc = SQLITE_NOMEM;
    ++  int rc;
    +   sqlite3_file *pFile;
    +   pFile = (sqlite3_file *)sqlite3MallocZero(pVfs->szOsFile);
    +   if( pFile ){
    +@@ -17500,15 +21108,15 @@ SQLITE_PRIVATE int sqlite3OsOpenMalloc(
    +     }else{
    +       *ppFile = pFile;
    +     }
    ++  }else{
    ++    rc = SQLITE_NOMEM_BKPT;
    +   }
    +   return rc;
    + }
    +-SQLITE_PRIVATE int sqlite3OsCloseFree(sqlite3_file *pFile){
    +-  int rc = SQLITE_OK;
    ++SQLITE_PRIVATE void sqlite3OsCloseFree(sqlite3_file *pFile){
    +   assert( pFile );
    +-  rc = sqlite3OsClose(pFile);
    ++  sqlite3OsClose(pFile);
    +   sqlite3_free(pFile);
    +-  return rc;
    + }
    + 
    + /*
    +@@ -17519,7 +21127,7 @@ SQLITE_PRIVATE int sqlite3OsCloseFree(sqlite3_file *pFile){
    + */
    + SQLITE_PRIVATE int sqlite3OsInit(void){
    +   void *p = sqlite3_malloc(10);
    +-  if( p==0 ) return SQLITE_NOMEM;
    ++  if( p==0 ) return SQLITE_NOMEM_BKPT;
    +   sqlite3_free(p);
    +   return sqlite3_os_init();
    + }
    +@@ -17534,7 +21142,7 @@ static sqlite3_vfs * SQLITE_WSD vfsList = 0;
    + ** Locate a VFS by name.  If no name is given, simply return the
    + ** first VFS on the list.
    + */
    +-SQLITE_API sqlite3_vfs *SQLITE_STDCALL sqlite3_vfs_find(const char *zVfs){
    ++SQLITE_API sqlite3_vfs *sqlite3_vfs_find(const char *zVfs){
    +   sqlite3_vfs *pVfs = 0;
    + #if SQLITE_THREADSAFE
    +   sqlite3_mutex *mutex;
    +@@ -17580,7 +21188,7 @@ static void vfsUnlink(sqlite3_vfs *pVfs){
    + ** VFS multiple times.  The new VFS becomes the default if makeDflt is
    + ** true.
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_vfs_register(sqlite3_vfs *pVfs, int makeDflt){
    ++SQLITE_API int sqlite3_vfs_register(sqlite3_vfs *pVfs, int makeDflt){
    +   MUTEX_LOGIC(sqlite3_mutex *mutex;)
    + #ifndef SQLITE_OMIT_AUTOINIT
    +   int rc = sqlite3_initialize();
    +@@ -17608,7 +21216,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_vfs_register(sqlite3_vfs *pVfs, int makeDf
    + /*
    + ** Unregister a VFS so that it is no longer accessible.
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_vfs_unregister(sqlite3_vfs *pVfs){
    ++SQLITE_API int sqlite3_vfs_unregister(sqlite3_vfs *pVfs){
    + #if SQLITE_THREADSAFE
    +   sqlite3_mutex *mutex = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MASTER);
    + #endif
    +@@ -17648,7 +21256,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_vfs_unregister(sqlite3_vfs *pVfs){
    + 
    + /* #include "sqliteInt.h" */
    + 
    +-#ifndef SQLITE_OMIT_BUILTIN_TEST
    ++#ifndef SQLITE_UNTESTABLE
    + 
    + /*
    + ** Global variables.
    +@@ -17706,7 +21314,7 @@ SQLITE_PRIVATE void sqlite3EndBenignMalloc(void){
    +   }
    + }
    + 
    +-#endif   /* #ifndef SQLITE_OMIT_BUILTIN_TEST */
    ++#endif   /* #ifndef SQLITE_UNTESTABLE */
    + 
    + /************** End of fault.c ***********************************************/
    + /************** Begin file mem0.c ********************************************/
    +@@ -17831,7 +21439,9 @@ SQLITE_PRIVATE void sqlite3MemSetDefault(void){
    + */
    + #include <sys/sysctl.h>
    + #include <malloc/malloc.h>
    ++#ifdef SQLITE_MIGHT_BE_SINGLE_CORE
    + #include <libkern/OSAtomic.h>
    ++#endif /* SQLITE_MIGHT_BE_SINGLE_CORE */
    + static malloc_zone_t* _sqliteZone_;
    + #define SQLITE_MALLOC(x) malloc_zone_malloc(_sqliteZone_, (x))
    + #define SQLITE_FREE(x) malloc_zone_free(_sqliteZone_, (x));
    +@@ -17899,7 +21509,9 @@ static malloc_zone_t* _sqliteZone_;
    + */
    + static void *sqlite3MemMalloc(int nByte){
    + #ifdef SQLITE_MALLOCSIZE
    +-  void *p = SQLITE_MALLOC( nByte );
    ++  void *p;
    ++  testcase( ROUND8(nByte)==nByte );
    ++  p = SQLITE_MALLOC( nByte );
    +   if( p==0 ){
    +     testcase( sqlite3GlobalConfig.xLog!=0 );
    +     sqlite3_log(SQLITE_NOMEM, "failed to allocate %u bytes of memory", nByte);
    +@@ -17908,7 +21520,7 @@ static void *sqlite3MemMalloc(int nByte){
    + #else
    +   sqlite3_int64 *p;
    +   assert( nByte>0 );
    +-  nByte = ROUND8(nByte);
    ++  testcase( ROUND8(nByte)!=nByte );
    +   p = SQLITE_MALLOC( nByte+8 );
    +   if( p ){
    +     p[0] = nByte;
    +@@ -17946,10 +21558,11 @@ static void sqlite3MemFree(void *pPrior){
    + */
    + static int sqlite3MemSize(void *pPrior){
    + #ifdef SQLITE_MALLOCSIZE
    +-  return pPrior ? (int)SQLITE_MALLOCSIZE(pPrior) : 0;
    ++  assert( pPrior!=0 );
    ++  return (int)SQLITE_MALLOCSIZE(pPrior);
    + #else
    +   sqlite3_int64 *p;
    +-  if( pPrior==0 ) return 0;
    ++  assert( pPrior!=0 );
    +   p = (sqlite3_int64*)pPrior;
    +   p--;
    +   return (int)p[0];
    +@@ -18021,19 +21634,10 @@ static int sqlite3MemInit(void *NotUsed){
    +   }else{
    +     /* only 1 core, use our own zone to contention over global locks, 
    +     ** e.g. we have our own dedicated locks */
    +-    bool success;
    +-    malloc_zone_t* newzone = malloc_create_zone(4096, 0);
    +-    malloc_set_zone_name(newzone, "Sqlite_Heap");
    +-    do{
    +-      success = OSAtomicCompareAndSwapPtrBarrier(NULL, newzone, 
    +-                                 (void * volatile *)&_sqliteZone_);
    +-    }while(!_sqliteZone_);
    +-    if( !success ){
    +-      /* somebody registered a zone first */
    +-      malloc_destroy_zone(newzone);
    +-    }
    ++    _sqliteZone_ = malloc_create_zone(4096, 0);
    ++    malloc_set_zone_name(_sqliteZone_, "Sqlite_Heap");
    +   }
    +-#endif
    ++#endif /*  defined(__APPLE__) && !defined(SQLITE_WITHOUT_ZONEMALLOC) */
    +   UNUSED_PARAMETER(NotUsed);
    +   return SQLITE_OK;
    + }
    +@@ -19079,7 +22683,7 @@ static void memsys3FreeUnsafe(void *pOld){
    + */
    + static int memsys3Size(void *p){
    +   Mem3Block *pBlock;
    +-  if( p==0 ) return 0;
    ++  assert( p!=0 );
    +   pBlock = (Mem3Block*)p;
    +   assert( (pBlock[-1].u.hdr.size4x&1)!=0 );
    +   return (pBlock[-1].u.hdr.size4x&~3)*2 - 4;
    +@@ -19318,7 +22922,7 @@ SQLITE_PRIVATE const sqlite3_mem_methods *sqlite3MemGetMemsys3(void){
    + **
    + ** This memory allocator uses the following algorithm:
    + **
    +-**   1.  All memory allocations sizes are rounded up to a power of 2.
    ++**   1.  All memory allocation sizes are rounded up to a power of 2.
    + **
    + **   2.  If two adjacent free blocks are the halves of a larger block,
    + **       then the two blocks are coalesced into the single larger block.
    +@@ -19395,6 +22999,7 @@ static SQLITE_WSD struct Mem5Global {
    +   */
    +   sqlite3_mutex *mutex;
    + 
    ++#if defined(SQLITE_DEBUG) || defined(SQLITE_TEST)
    +   /*
    +   ** Performance statistics
    +   */
    +@@ -19406,11 +23011,12 @@ static SQLITE_WSD struct Mem5Global {
    +   u32 maxOut;         /* Maximum instantaneous currentOut */
    +   u32 maxCount;       /* Maximum instantaneous currentCount */
    +   u32 maxRequest;     /* Largest allocation (exclusive of internal frag) */
    ++#endif
    +   
    +   /*
    +   ** Lists of free blocks.  aiFreelist[0] is a list of free blocks of
    +   ** size mem5.szAtom.  aiFreelist[1] holds blocks of size szAtom*2.
    +-  ** and so forth.
    ++  ** aiFreelist[2] holds free blocks of size szAtom*4.  And so forth.
    +   */
    +   int aiFreelist[LOGMAX+1];
    + 
    +@@ -19476,9 +23082,7 @@ static void memsys5Link(int i, int iLogsize){
    + }
    + 
    + /*
    +-** If the STATIC_MEM mutex is not already held, obtain it now. The mutex
    +-** will already be held (obtained by code in malloc.c) if
    +-** sqlite3GlobalConfig.bMemStat is true.
    ++** Obtain or release the mutex needed to access global data structures.
    + */
    + static void memsys5Enter(void){
    +   sqlite3_mutex_enter(mem5.mutex);
    +@@ -19488,17 +23092,15 @@ static void memsys5Leave(void){
    + }
    + 
    + /*
    +-** Return the size of an outstanding allocation, in bytes.  The
    +-** size returned omits the 8-byte header overhead.  This only
    +-** works for chunks that are currently checked out.
    ++** Return the size of an outstanding allocation, in bytes.
    ++** This only works for chunks that are currently checked out.
    + */
    + static int memsys5Size(void *p){
    +-  int iSize = 0;
    +-  if( p ){
    +-    int i = (int)(((u8 *)p-mem5.zPool)/mem5.szAtom);
    +-    assert( i>=0 && i<mem5.nBlock );
    +-    iSize = mem5.szAtom * (1 << (mem5.aCtrl[i]&CTRL_LOGSIZE));
    +-  }
    ++  int iSize, i;
    ++  assert( p!=0 );
    ++  i = (int)(((u8 *)p-mem5.zPool)/mem5.szAtom);
    ++  assert( i>=0 && i<mem5.nBlock );
    ++  iSize = mem5.szAtom * (1 << (mem5.aCtrl[i]&CTRL_LOGSIZE));
    +   return iSize;
    + }
    + 
    +@@ -19521,21 +23123,20 @@ static void *memsys5MallocUnsafe(int nByte){
    +   /* nByte must be a positive */
    +   assert( nByte>0 );
    + 
    ++  /* No more than 1GiB per allocation */
    ++  if( nByte > 0x40000000 ) return 0;
    ++
    ++#if defined(SQLITE_DEBUG) || defined(SQLITE_TEST)
    +   /* Keep track of the maximum allocation request.  Even unfulfilled
    +   ** requests are counted */
    +   if( (u32)nByte>mem5.maxRequest ){
    +     mem5.maxRequest = nByte;
    +   }
    ++#endif
    + 
    +-  /* Abort if the requested allocation size is larger than the largest
    +-  ** power of two that we can represent using 32-bit signed integers.
    +-  */
    +-  if( nByte > 0x40000000 ){
    +-    return 0;
    +-  }
    + 
    +   /* Round nByte up to the next valid power of two */
    +-  for(iFullSz=mem5.szAtom, iLogsize=0; iFullSz<nByte; iFullSz *= 2, iLogsize++){}
    ++  for(iFullSz=mem5.szAtom,iLogsize=0; iFullSz<nByte; iFullSz*=2,iLogsize++){}
    + 
    +   /* Make sure mem5.aiFreelist[iLogsize] contains at least one free
    +   ** block.  If not, then split a block of the next larger power of
    +@@ -19559,6 +23160,7 @@ static void *memsys5MallocUnsafe(int nByte){
    +   }
    +   mem5.aCtrl[i] = iLogsize;
    + 
    ++#if defined(SQLITE_DEBUG) || defined(SQLITE_TEST)
    +   /* Update allocator performance statistics. */
    +   mem5.nAlloc++;
    +   mem5.totalAlloc += iFullSz;
    +@@ -19567,6 +23169,7 @@ static void *memsys5MallocUnsafe(int nByte){
    +   mem5.currentOut += iFullSz;
    +   if( mem5.maxCount<mem5.currentCount ) mem5.maxCount = mem5.currentCount;
    +   if( mem5.maxOut<mem5.currentOut ) mem5.maxOut = mem5.currentOut;
    ++#endif
    + 
    + #ifdef SQLITE_DEBUG
    +   /* Make sure the allocated memory does not assume that it is set to zero
    +@@ -19601,23 +23204,26 @@ static void memsys5FreeUnsafe(void *pOld){
    + 
    +   mem5.aCtrl[iBlock] |= CTRL_FREE;
    +   mem5.aCtrl[iBlock+size-1] |= CTRL_FREE;
    ++
    ++#if defined(SQLITE_DEBUG) || defined(SQLITE_TEST)
    +   assert( mem5.currentCount>0 );
    +   assert( mem5.currentOut>=(size*mem5.szAtom) );
    +   mem5.currentCount--;
    +   mem5.currentOut -= size*mem5.szAtom;
    +   assert( mem5.currentOut>0 || mem5.currentCount==0 );
    +   assert( mem5.currentCount>0 || mem5.currentOut==0 );
    ++#endif
    + 
    +   mem5.aCtrl[iBlock] = CTRL_FREE | iLogsize;
    +   while( ALWAYS(iLogsize<LOGMAX) ){
    +     int iBuddy;
    +     if( (iBlock>>iLogsize) & 1 ){
    +       iBuddy = iBlock - size;
    ++      assert( iBuddy>=0 );
    +     }else{
    +       iBuddy = iBlock + size;
    ++      if( iBuddy>=mem5.nBlock ) break;
    +     }
    +-    assert( iBuddy>=0 );
    +-    if( (iBuddy+(1<<iLogsize))>mem5.nBlock ) break;
    +     if( mem5.aCtrl[iBuddy]!=(CTRL_FREE | iLogsize) ) break;
    +     memsys5Unlink(iBuddy, iLogsize);
    +     iLogsize++;
    +@@ -19692,13 +23298,11 @@ static void *memsys5Realloc(void *pPrior, int nBytes){
    +   if( nBytes<=nOld ){
    +     return pPrior;
    +   }
    +-  memsys5Enter();
    +-  p = memsys5MallocUnsafe(nBytes);
    ++  p = memsys5Malloc(nBytes);
    +   if( p ){
    +     memcpy(p, pPrior, nOld);
    +-    memsys5FreeUnsafe(pPrior);
    ++    memsys5Free(pPrior);
    +   }
    +-  memsys5Leave();
    +   return p;
    + }
    + 
    +@@ -19898,6 +23502,193 @@ static SQLITE_WSD int mutexIsInit = 0;
    + 
    + 
    + #ifndef SQLITE_MUTEX_OMIT
    ++
    ++#ifdef SQLITE_ENABLE_MULTITHREADED_CHECKS
    ++/*
    ++** This block (enclosed by SQLITE_ENABLE_MULTITHREADED_CHECKS) contains
    ++** the implementation of a wrapper around the system default mutex
    ++** implementation (sqlite3DefaultMutex()). 
    ++**
    ++** Most calls are passed directly through to the underlying default
    ++** mutex implementation. Except, if a mutex is configured by calling
    ++** sqlite3MutexWarnOnContention() on it, then if contention is ever
    ++** encountered within xMutexEnter() a warning is emitted via sqlite3_log().
    ++**
    ++** This type of mutex is used as the database handle mutex when testing
    ++** apps that usually use SQLITE_CONFIG_MULTITHREAD mode.
    ++*/
    ++
    ++/* 
    ++** Type for all mutexes used when SQLITE_ENABLE_MULTITHREADED_CHECKS
    ++** is defined. Variable CheckMutex.mutex is a pointer to the real mutex
    ++** allocated by the system mutex implementation. Variable iType is usually set
    ++** to the type of mutex requested - SQLITE_MUTEX_RECURSIVE, SQLITE_MUTEX_FAST
    ++** or one of the static mutex identifiers. Or, if this is a recursive mutex
    ++** that has been configured using sqlite3MutexWarnOnContention(), it is
    ++** set to SQLITE_MUTEX_WARNONCONTENTION.
    ++*/
    ++typedef struct CheckMutex CheckMutex;
    ++struct CheckMutex {
    ++  int iType;
    ++  sqlite3_mutex *mutex;
    ++};
    ++
    ++#define SQLITE_MUTEX_WARNONCONTENTION  (-1)
    ++
    ++/* 
    ++** Pointer to real mutex methods object used by the CheckMutex
    ++** implementation. Set by checkMutexInit(). 
    ++*/
    ++static SQLITE_WSD const sqlite3_mutex_methods *pGlobalMutexMethods;
    ++
    ++#ifdef SQLITE_DEBUG
    ++static int checkMutexHeld(sqlite3_mutex *p){
    ++  return pGlobalMutexMethods->xMutexHeld(((CheckMutex*)p)->mutex);
    ++}
    ++static int checkMutexNotheld(sqlite3_mutex *p){
    ++  return pGlobalMutexMethods->xMutexNotheld(((CheckMutex*)p)->mutex);
    ++}
    ++#endif
    ++
    ++/*
    ++** Initialize and deinitialize the mutex subsystem.
    ++*/
    ++static int checkMutexInit(void){ 
    ++  pGlobalMutexMethods = sqlite3DefaultMutex();
    ++  return SQLITE_OK; 
    ++}
    ++static int checkMutexEnd(void){ 
    ++  pGlobalMutexMethods = 0;
    ++  return SQLITE_OK; 
    ++}
    ++
    ++/*
    ++** Allocate a mutex.
    ++*/
    ++static sqlite3_mutex *checkMutexAlloc(int iType){
    ++  static CheckMutex staticMutexes[] = {
    ++    {2, 0}, {3, 0}, {4, 0}, {5, 0},
    ++    {6, 0}, {7, 0}, {8, 0}, {9, 0},
    ++    {10, 0}, {11, 0}, {12, 0}, {13, 0}
    ++  };
    ++  CheckMutex *p = 0;
    ++
    ++  assert( SQLITE_MUTEX_RECURSIVE==1 && SQLITE_MUTEX_FAST==0 );
    ++  if( iType<2 ){
    ++    p = sqlite3MallocZero(sizeof(CheckMutex));
    ++    if( p==0 ) return 0;
    ++    p->iType = iType;
    ++  }else{
    ++#ifdef SQLITE_ENABLE_API_ARMOR
    ++    if( iType-2>=ArraySize(staticMutexes) ){
    ++      (void)SQLITE_MISUSE_BKPT;
    ++      return 0;
    ++    }
    ++#endif
    ++    p = &staticMutexes[iType-2];
    ++  }
    ++
    ++  if( p->mutex==0 ){
    ++    p->mutex = pGlobalMutexMethods->xMutexAlloc(iType);
    ++    if( p->mutex==0 ){
    ++      if( iType<2 ){
    ++        sqlite3_free(p);
    ++      }
    ++      p = 0;
    ++    }
    ++  }
    ++
    ++  return (sqlite3_mutex*)p;
    ++}
    ++
    ++/*
    ++** Free a mutex.
    ++*/
    ++static void checkMutexFree(sqlite3_mutex *p){
    ++  assert( SQLITE_MUTEX_RECURSIVE<2 );
    ++  assert( SQLITE_MUTEX_FAST<2 );
    ++  assert( SQLITE_MUTEX_WARNONCONTENTION<2 );
    ++
    ++#if SQLITE_ENABLE_API_ARMOR
    ++  if( ((CheckMutex*)p)->iType<2 )
    ++#endif
    ++  {
    ++    CheckMutex *pCheck = (CheckMutex*)p;
    ++    pGlobalMutexMethods->xMutexFree(pCheck->mutex);
    ++    sqlite3_free(pCheck);
    ++  }
    ++#ifdef SQLITE_ENABLE_API_ARMOR
    ++  else{
    ++    (void)SQLITE_MISUSE_BKPT;
    ++  }
    ++#endif
    ++}
    ++
    ++/*
    ++** Enter the mutex.
    ++*/
    ++static void checkMutexEnter(sqlite3_mutex *p){
    ++  CheckMutex *pCheck = (CheckMutex*)p;
    ++  if( pCheck->iType==SQLITE_MUTEX_WARNONCONTENTION ){
    ++    if( SQLITE_OK==pGlobalMutexMethods->xMutexTry(pCheck->mutex) ){
    ++      return;
    ++    }
    ++    sqlite3_log(SQLITE_MISUSE, 
    ++        "illegal multi-threaded access to database connection"
    ++    );
    ++  }
    ++  pGlobalMutexMethods->xMutexEnter(pCheck->mutex);
    ++}
    ++
    ++/*
    ++** Enter the mutex (do not block).
    ++*/
    ++static int checkMutexTry(sqlite3_mutex *p){
    ++  CheckMutex *pCheck = (CheckMutex*)p;
    ++  return pGlobalMutexMethods->xMutexTry(pCheck->mutex);
    ++}
    ++
    ++/*
    ++** Leave the mutex.
    ++*/
    ++static void checkMutexLeave(sqlite3_mutex *p){
    ++  CheckMutex *pCheck = (CheckMutex*)p;
    ++  pGlobalMutexMethods->xMutexLeave(pCheck->mutex);
    ++}
    ++
    ++sqlite3_mutex_methods const *multiThreadedCheckMutex(void){
    ++  static const sqlite3_mutex_methods sMutex = {
    ++    checkMutexInit,
    ++    checkMutexEnd,
    ++    checkMutexAlloc,
    ++    checkMutexFree,
    ++    checkMutexEnter,
    ++    checkMutexTry,
    ++    checkMutexLeave,
    ++#ifdef SQLITE_DEBUG
    ++    checkMutexHeld,
    ++    checkMutexNotheld
    ++#else
    ++    0,
    ++    0
    ++#endif
    ++  };
    ++  return &sMutex;
    ++}
    ++
    ++/*
    ++** Mark the SQLITE_MUTEX_RECURSIVE mutex passed as the only argument as
    ++** one on which there should be no contention.
    ++*/
    ++SQLITE_PRIVATE void sqlite3MutexWarnOnContention(sqlite3_mutex *p){
    ++  if( sqlite3GlobalConfig.mutex.xMutexAlloc==checkMutexAlloc ){
    ++    CheckMutex *pCheck = (CheckMutex*)p;
    ++    assert( pCheck->iType==SQLITE_MUTEX_RECURSIVE );
    ++    pCheck->iType = SQLITE_MUTEX_WARNONCONTENTION;
    ++  }
    ++}
    ++#endif   /* ifdef SQLITE_ENABLE_MULTITHREADED_CHECKS */
    ++
    + /*
    + ** Initialize the mutex system.
    + */
    +@@ -19913,7 +23704,11 @@ SQLITE_PRIVATE int sqlite3MutexInit(void){
    +     sqlite3_mutex_methods *pTo = &sqlite3GlobalConfig.mutex;
    + 
    +     if( sqlite3GlobalConfig.bCoreMutex ){
    ++#ifdef SQLITE_ENABLE_MULTITHREADED_CHECKS
    ++      pFrom = multiThreadedCheckMutex();
    ++#else
    +       pFrom = sqlite3DefaultMutex();
    ++#endif
    +     }else{
    +       pFrom = sqlite3NoopMutex();
    +     }
    +@@ -19958,7 +23753,7 @@ SQLITE_PRIVATE int sqlite3MutexEnd(void){
    + /*
    + ** Retrieve a pointer to a static mutex or allocate a new dynamic one.
    + */
    +-SQLITE_API sqlite3_mutex *SQLITE_STDCALL sqlite3_mutex_alloc(int id){
    ++SQLITE_API sqlite3_mutex *sqlite3_mutex_alloc(int id){
    + #ifndef SQLITE_OMIT_AUTOINIT
    +   if( id<=SQLITE_MUTEX_RECURSIVE && sqlite3_initialize() ) return 0;
    +   if( id>SQLITE_MUTEX_RECURSIVE && sqlite3MutexInit() ) return 0;
    +@@ -19979,7 +23774,7 @@ SQLITE_PRIVATE sqlite3_mutex *sqlite3MutexAlloc(int id){
    + /*
    + ** Free a dynamic mutex.
    + */
    +-SQLITE_API void SQLITE_STDCALL sqlite3_mutex_free(sqlite3_mutex *p){
    ++SQLITE_API void sqlite3_mutex_free(sqlite3_mutex *p){
    +   if( p ){
    +     assert( sqlite3GlobalConfig.mutex.xMutexFree );
    +     sqlite3GlobalConfig.mutex.xMutexFree(p);
    +@@ -19990,7 +23785,7 @@ SQLITE_API void SQLITE_STDCALL sqlite3_mutex_free(sqlite3_mutex *p){
    + ** Obtain the mutex p. If some other thread already has the mutex, block
    + ** until it can be obtained.
    + */
    +-SQLITE_API void SQLITE_STDCALL sqlite3_mutex_enter(sqlite3_mutex *p){
    ++SQLITE_API void sqlite3_mutex_enter(sqlite3_mutex *p){
    +   if( p ){
    +     assert( sqlite3GlobalConfig.mutex.xMutexEnter );
    +     sqlite3GlobalConfig.mutex.xMutexEnter(p);
    +@@ -20001,7 +23796,7 @@ SQLITE_API void SQLITE_STDCALL sqlite3_mutex_enter(sqlite3_mutex *p){
    + ** Obtain the mutex p. If successful, return SQLITE_OK. Otherwise, if another
    + ** thread holds the mutex and it cannot be obtained, return SQLITE_BUSY.
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_mutex_try(sqlite3_mutex *p){
    ++SQLITE_API int sqlite3_mutex_try(sqlite3_mutex *p){
    +   int rc = SQLITE_OK;
    +   if( p ){
    +     assert( sqlite3GlobalConfig.mutex.xMutexTry );
    +@@ -20016,7 +23811,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_mutex_try(sqlite3_mutex *p){
    + ** is not currently entered. If a NULL pointer is passed as an argument
    + ** this function is a no-op.
    + */
    +-SQLITE_API void SQLITE_STDCALL sqlite3_mutex_leave(sqlite3_mutex *p){
    ++SQLITE_API void sqlite3_mutex_leave(sqlite3_mutex *p){
    +   if( p ){
    +     assert( sqlite3GlobalConfig.mutex.xMutexLeave );
    +     sqlite3GlobalConfig.mutex.xMutexLeave(p);
    +@@ -20028,11 +23823,11 @@ SQLITE_API void SQLITE_STDCALL sqlite3_mutex_leave(sqlite3_mutex *p){
    + ** The sqlite3_mutex_held() and sqlite3_mutex_notheld() routine are
    + ** intended for use inside assert() statements.
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_mutex_held(sqlite3_mutex *p){
    ++SQLITE_API int sqlite3_mutex_held(sqlite3_mutex *p){
    +   assert( p==0 || sqlite3GlobalConfig.mutex.xMutexHeld );
    +   return p==0 || sqlite3GlobalConfig.mutex.xMutexHeld(p);
    + }
    +-SQLITE_API int SQLITE_STDCALL sqlite3_mutex_notheld(sqlite3_mutex *p){
    ++SQLITE_API int sqlite3_mutex_notheld(sqlite3_mutex *p){
    +   assert( p==0 || sqlite3GlobalConfig.mutex.xMutexNotheld );
    +   return p==0 || sqlite3GlobalConfig.mutex.xMutexNotheld(p);
    + }
    +@@ -20040,6 +23835,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_mutex_notheld(sqlite3_mutex *p){
    + 
    + #endif /* !defined(SQLITE_MUTEX_OMIT) */
    + 
    ++
    + /************** End of mutex.c ***********************************************/
    + /************** Begin file mutex_noop.c **************************************/
    + /*
    +@@ -20312,7 +24108,9 @@ struct sqlite3_mutex {
    + #endif
    + };
    + #if SQLITE_MUTEX_NREF
    +-#define SQLITE3_MUTEX_INITIALIZER { PTHREAD_MUTEX_INITIALIZER, 0, 0, (pthread_t)0, 0 }
    ++#define SQLITE3_MUTEX_INITIALIZER {PTHREAD_MUTEX_INITIALIZER,0,0,(pthread_t)0,0}
    ++#elif defined(SQLITE_ENABLE_API_ARMOR)
    ++#define SQLITE3_MUTEX_INITIALIZER { PTHREAD_MUTEX_INITIALIZER, 0 }
    + #else
    + #define SQLITE3_MUTEX_INITIALIZER { PTHREAD_MUTEX_INITIALIZER }
    + #endif
    +@@ -20706,8 +24504,8 @@ SQLITE_PRIVATE sqlite3_mutex_methods const *sqlite3DefaultMutex(void){
    + */
    + #ifdef SQLITE_PERFORMANCE_TRACE
    + 
    +-/* 
    +-** hwtime.h contains inline assembler code for implementing 
    ++/*
    ++** hwtime.h contains inline assembler code for implementing
    + ** high-performance timing routines.
    + */
    + /************** Include hwtime.h in the middle of os_common.h ****************/
    +@@ -20727,8 +24525,8 @@ SQLITE_PRIVATE sqlite3_mutex_methods const *sqlite3DefaultMutex(void){
    + ** This file contains inline asm code for retrieving "high-performance"
    + ** counters for x86 class CPUs.
    + */
    +-#ifndef _HWTIME_H_
    +-#define _HWTIME_H_
    ++#ifndef SQLITE_HWTIME_H
    ++#define SQLITE_HWTIME_H
    + 
    + /*
    + ** The following routine only works on pentium-class (or newer) processors.
    +@@ -20796,7 +24594,7 @@ SQLITE_PRIVATE   sqlite_uint64 sqlite3Hwtime(void){ return ((sqlite_uint64)0); }
    + 
    + #endif
    + 
    +-#endif /* !defined(_HWTIME_H_) */
    ++#endif /* !defined(SQLITE_HWTIME_H) */
    + 
    + /************** End of hwtime.h **********************************************/
    + /************** Continuing where we left off in os_common.h ******************/
    +@@ -20817,14 +24615,14 @@ static sqlite_uint64 g_elapsed;
    + ** 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;
    ++#if defined(SQLITE_TEST)
    ++SQLITE_API extern int sqlite3_io_error_hit;
    ++SQLITE_API extern int sqlite3_io_error_hardhit;
    ++SQLITE_API extern int sqlite3_io_error_pending;
    ++SQLITE_API extern int sqlite3_io_error_persist;
    ++SQLITE_API extern int sqlite3_io_error_benign;
    ++SQLITE_API extern int sqlite3_diskfull_pending;
    ++SQLITE_API extern int sqlite3_diskfull;
    + #define SimulateIOErrorBenign(X) sqlite3_io_error_benign=(X)
    + #define SimulateIOError(CODE)  \
    +   if( (sqlite3_io_error_persist && sqlite3_io_error_hit) \
    +@@ -20850,17 +24648,17 @@ static void local_ioerr(){
    + #define SimulateIOErrorBenign(X)
    + #define SimulateIOError(A)
    + #define SimulateDiskfullError(A)
    +-#endif
    ++#endif /* defined(SQLITE_TEST) */
    + 
    + /*
    + ** When testing, keep a count of the number of open files.
    + */
    +-#ifdef SQLITE_TEST
    +-SQLITE_API int sqlite3_open_file_count = 0;
    ++#if defined(SQLITE_TEST)
    ++SQLITE_API extern int sqlite3_open_file_count;
    + #define OpenCounter(X)  sqlite3_open_file_count+=(X)
    + #else
    + #define OpenCounter(X)
    +-#endif
    ++#endif /* defined(SQLITE_TEST) */
    + 
    + #endif /* !defined(_OS_COMMON_H_) */
    + 
    +@@ -20886,8 +24684,8 @@ SQLITE_API int sqlite3_open_file_count = 0;
    + **
    + ** This file contains code that is specific to Windows.
    + */
    +-#ifndef _OS_WIN_H_
    +-#define _OS_WIN_H_
    ++#ifndef SQLITE_OS_WIN_H
    ++#define SQLITE_OS_WIN_H
    + 
    + /*
    + ** Include the primary Windows SDK header file.
    +@@ -20959,7 +24757,7 @@ SQLITE_API int sqlite3_open_file_count = 0;
    + # define SQLITE_OS_WIN_THREADS 0
    + #endif
    + 
    +-#endif /* _OS_WIN_H_ */
    ++#endif /* SQLITE_OS_WIN_H */
    + 
    + /************** End of os_win.h **********************************************/
    + /************** Continuing where we left off in mutex_w32.c ******************/
    +@@ -21027,8 +24825,7 @@ SQLITE_PRIVATE void sqlite3MemoryBarrier(void){
    +   SQLITE_MEMORY_BARRIER;
    + #elif defined(__GNUC__)
    +   __sync_synchronize();
    +-#elif !defined(SQLITE_DISABLE_INTRINSIC) && \
    +-      defined(_MSC_VER) && _MSC_VER>=1300
    ++#elif MSVC_VERSION>=1300
    +   _ReadWriteBarrier();
    + #elif defined(MemoryBarrier)
    +   MemoryBarrier();
    +@@ -21062,8 +24859,8 @@ static int winMutex_isNt = -1; /* <0 means "need to query" */
    + */
    + static LONG SQLITE_WIN32_VOLATILE winMutex_lock = 0;
    + 
    +-SQLITE_API int SQLITE_STDCALL sqlite3_win32_is_nt(void); /* os_win.c */
    +-SQLITE_API void SQLITE_STDCALL sqlite3_win32_sleep(DWORD milliseconds); /* os_win.c */
    ++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){
    +   /* The first to increment to 1 does actual initialization */
    +@@ -21239,8 +25036,8 @@ static void winMutexEnter(sqlite3_mutex *p){
    +   p->owner = tid;
    +   p->nRef++;
    +   if( p->trace ){
    +-    OSTRACE(("ENTER-MUTEX tid=%lu, mutex=%p (%d), nRef=%d\n",
    +-             tid, p, p->trace, p->nRef));
    ++    OSTRACE(("ENTER-MUTEX tid=%lu, mutex(%d)=%p (%d), nRef=%d\n",
    ++             tid, p->id, p, p->trace, p->nRef));
    +   }
    + #endif
    + }
    +@@ -21282,8 +25079,8 @@ static int winMutexTry(sqlite3_mutex *p){
    + #endif
    + #ifdef SQLITE_DEBUG
    +   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)));
    ++    OSTRACE(("TRY-MUTEX tid=%lu, mutex(%d)=%p (%d), owner=%lu, nRef=%d, rc=%s\n",
    ++             tid, p->id, p, p->trace, p->owner, p->nRef, sqlite3ErrName(rc)));
    +   }
    + #endif
    +   return rc;
    +@@ -21311,8 +25108,8 @@ static void winMutexLeave(sqlite3_mutex *p){
    +   LeaveCriticalSection(&p->mutex);
    + #ifdef SQLITE_DEBUG
    +   if( p->trace ){
    +-    OSTRACE(("LEAVE-MUTEX tid=%lu, mutex=%p (%d), nRef=%d\n",
    +-             tid, p, p->trace, p->nRef));
    ++    OSTRACE(("LEAVE-MUTEX tid=%lu, mutex(%d)=%p (%d), nRef=%d\n",
    ++             tid, p->id, p, p->trace, p->nRef));
    +   }
    + #endif
    + }
    +@@ -21363,7 +25160,7 @@ SQLITE_PRIVATE sqlite3_mutex_methods const *sqlite3DefaultMutex(void){
    + ** held by SQLite. An example of non-essential memory is memory used to
    + ** cache database pages that are not currently in use.
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_release_memory(int n){
    ++SQLITE_API int sqlite3_release_memory(int n){
    + #ifdef SQLITE_ENABLE_MEMORY_MANAGEMENT
    +   return sqlite3PcacheReleaseMemory(n);
    + #else
    +@@ -21375,14 +25172,6 @@ SQLITE_API int SQLITE_STDCALL sqlite3_release_memory(int n){
    + #endif
    + }
    + 
    +-/*
    +-** An instance of the following object records the location of
    +-** each unused scratch buffer.
    +-*/
    +-typedef struct ScratchFreeslot {
    +-  struct ScratchFreeslot *pNext;   /* Next unused scratch buffer */
    +-} ScratchFreeslot;
    +-
    + /*
    + ** State information local to the memory allocation subsystem.
    + */
    +@@ -21390,22 +25179,12 @@ static SQLITE_WSD struct Mem0Global {
    +   sqlite3_mutex *mutex;         /* Mutex to serialize access */
    +   sqlite3_int64 alarmThreshold; /* The soft heap limit */
    + 
    +-  /*
    +-  ** Pointers to the end of sqlite3GlobalConfig.pScratch memory
    +-  ** (so that a range test can be used to determine if an allocation
    +-  ** being freed came from pScratch) and a pointer to the list of
    +-  ** unused scratch allocations.
    +-  */
    +-  void *pScratchEnd;
    +-  ScratchFreeslot *pScratchFree;
    +-  u32 nScratchFree;
    +-
    +   /*
    +   ** True if heap is nearly "full" where "full" is defined by the
    +   ** sqlite3_soft_heap_limit() setting.
    +   */
    +   int nearlyFull;
    +-} mem0 = { 0, 0, 0, 0, 0, 0 };
    ++} mem0 = { 0, 0, 0 };
    + 
    + #define mem0 GLOBAL(struct Mem0Global, mem0)
    + 
    +@@ -21422,7 +25201,7 @@ SQLITE_PRIVATE sqlite3_mutex *sqlite3MallocMutex(void){
    + ** that was invoked when memory usage grew too large.  Now it is a
    + ** no-op.
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_memory_alarm(
    ++SQLITE_API int sqlite3_memory_alarm(
    +   void(*xCallback)(void *pArg, sqlite3_int64 used,int N),
    +   void *pArg,
    +   sqlite3_int64 iThreshold
    +@@ -21438,7 +25217,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_memory_alarm(
    + ** Set the soft heap-size limit for the library. Passing a zero or 
    + ** negative value indicates no limit.
    + */
    +-SQLITE_API sqlite3_int64 SQLITE_STDCALL sqlite3_soft_heap_limit64(sqlite3_int64 n){
    ++SQLITE_API sqlite3_int64 sqlite3_soft_heap_limit64(sqlite3_int64 n){
    +   sqlite3_int64 priorLimit;
    +   sqlite3_int64 excess;
    +   sqlite3_int64 nUsed;
    +@@ -21460,7 +25239,7 @@ SQLITE_API sqlite3_int64 SQLITE_STDCALL sqlite3_soft_heap_limit64(sqlite3_int64
    +   if( excess>0 ) sqlite3_release_memory((int)(excess & 0x7fffffff));
    +   return priorLimit;
    + }
    +-SQLITE_API void SQLITE_STDCALL sqlite3_soft_heap_limit(int n){
    ++SQLITE_API void sqlite3_soft_heap_limit(int n){
    +   if( n<0 ) n = 0;
    +   sqlite3_soft_heap_limit64(n);
    + }
    +@@ -21474,31 +25253,7 @@ SQLITE_PRIVATE int sqlite3MallocInit(void){
    +     sqlite3MemSetDefault();
    +   }
    +   memset(&mem0, 0, sizeof(mem0));
    +-  if( sqlite3GlobalConfig.bCoreMutex ){
    +-    mem0.mutex = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MEM);
    +-  }
    +-  if( sqlite3GlobalConfig.pScratch && sqlite3GlobalConfig.szScratch>=100
    +-      && sqlite3GlobalConfig.nScratch>0 ){
    +-    int i, n, sz;
    +-    ScratchFreeslot *pSlot;
    +-    sz = ROUNDDOWN8(sqlite3GlobalConfig.szScratch);
    +-    sqlite3GlobalConfig.szScratch = sz;
    +-    pSlot = (ScratchFreeslot*)sqlite3GlobalConfig.pScratch;
    +-    n = sqlite3GlobalConfig.nScratch;
    +-    mem0.pScratchFree = pSlot;
    +-    mem0.nScratchFree = n;
    +-    for(i=0; i<n-1; i++){
    +-      pSlot->pNext = (ScratchFreeslot*)(sz+(char*)pSlot);
    +-      pSlot = pSlot->pNext;
    +-    }
    +-    pSlot->pNext = 0;
    +-    mem0.pScratchEnd = (void*)&pSlot[1];
    +-  }else{
    +-    mem0.pScratchEnd = 0;
    +-    sqlite3GlobalConfig.pScratch = 0;
    +-    sqlite3GlobalConfig.szScratch = 0;
    +-    sqlite3GlobalConfig.nScratch = 0;
    +-  }
    ++  mem0.mutex = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MEM);
    +   if( sqlite3GlobalConfig.pPage==0 || sqlite3GlobalConfig.szPage<512
    +       || sqlite3GlobalConfig.nPage<=0 ){
    +     sqlite3GlobalConfig.pPage = 0;
    +@@ -21531,7 +25286,7 @@ SQLITE_PRIVATE void sqlite3MallocEnd(void){
    + /*
    + ** Return the amount of memory currently checked out.
    + */
    +-SQLITE_API sqlite3_int64 SQLITE_STDCALL sqlite3_memory_used(void){
    ++SQLITE_API sqlite3_int64 sqlite3_memory_used(void){
    +   sqlite3_int64 res, mx;
    +   sqlite3_status64(SQLITE_STATUS_MEMORY_USED, &res, &mx, 0);
    +   return res;
    +@@ -21542,7 +25297,7 @@ SQLITE_API sqlite3_int64 SQLITE_STDCALL sqlite3_memory_used(void){
    + ** checked out since either the beginning of this process
    + ** or since the most recent reset.
    + */
    +-SQLITE_API sqlite3_int64 SQLITE_STDCALL sqlite3_memory_highwater(int resetFlag){
    ++SQLITE_API sqlite3_int64 sqlite3_memory_highwater(int resetFlag){
    +   sqlite3_int64 res, mx;
    +   sqlite3_status64(SQLITE_STATUS_MEMORY_USED, &res, &mx, resetFlag);
    +   return mx;
    +@@ -21562,12 +25317,27 @@ static void sqlite3MallocAlarm(int nByte){
    + ** Do a memory allocation with statistics and alarms.  Assume the
    + ** lock is already held.
    + */
    +-static int mallocWithAlarm(int n, void **pp){
    +-  int nFull;
    ++static void mallocWithAlarm(int n, void **pp){
    +   void *p;
    ++  int nFull;
    +   assert( sqlite3_mutex_held(mem0.mutex) );
    ++  assert( n>0 );
    ++
    ++  /* In Firefox (circa 2017-02-08), xRoundup() is remapped to an internal
    ++  ** implementation of malloc_good_size(), which must be called in debug
    ++  ** mode and specifically when the DMD "Dark Matter Detector" is enabled
    ++  ** or else a crash results.  Hence, do not attempt to optimize out the
    ++  ** following xRoundup() call. */
    +   nFull = sqlite3GlobalConfig.m.xRoundup(n);
    +-  sqlite3StatusSet(SQLITE_STATUS_MALLOC_SIZE, n);
    ++
    ++#ifdef SQLITE_MAX_MEMORY
    ++  if( sqlite3StatusValue(SQLITE_STATUS_MEMORY_USED)+nFull>SQLITE_MAX_MEMORY ){
    ++    *pp = 0;
    ++    return;
    ++  }
    ++#endif
    ++
    ++  sqlite3StatusHighwater(SQLITE_STATUS_MALLOC_SIZE, n);
    +   if( mem0.alarmThreshold>0 ){
    +     sqlite3_int64 nUsed = sqlite3StatusValue(SQLITE_STATUS_MEMORY_USED);
    +     if( nUsed >= mem0.alarmThreshold - nFull ){
    +@@ -21590,7 +25360,6 @@ static int mallocWithAlarm(int n, void **pp){
    +     sqlite3StatusUp(SQLITE_STATUS_MALLOC_COUNT, 1);
    +   }
    +   *pp = p;
    +-  return nFull;
    + }
    + 
    + /*
    +@@ -21622,124 +25391,25 @@ SQLITE_PRIVATE void *sqlite3Malloc(u64 n){
    + ** First make sure the memory subsystem is initialized, then do the
    + ** allocation.
    + */
    +-SQLITE_API void *SQLITE_STDCALL sqlite3_malloc(int n){
    ++SQLITE_API void *sqlite3_malloc(int n){
    + #ifndef SQLITE_OMIT_AUTOINIT
    +   if( sqlite3_initialize() ) return 0;
    + #endif
    +   return n<=0 ? 0 : sqlite3Malloc(n);
    + }
    +-SQLITE_API void *SQLITE_STDCALL sqlite3_malloc64(sqlite3_uint64 n){
    ++SQLITE_API void *sqlite3_malloc64(sqlite3_uint64 n){
    + #ifndef SQLITE_OMIT_AUTOINIT
    +   if( sqlite3_initialize() ) return 0;
    + #endif
    +   return sqlite3Malloc(n);
    + }
    + 
    +-/*
    +-** Each thread may only have a single outstanding allocation from
    +-** xScratchMalloc().  We verify this constraint in the single-threaded
    +-** case by setting scratchAllocOut to 1 when an allocation
    +-** is outstanding clearing it when the allocation is freed.
    +-*/
    +-#if SQLITE_THREADSAFE==0 && !defined(NDEBUG)
    +-static int scratchAllocOut = 0;
    +-#endif
    +-
    +-
    +-/*
    +-** Allocate memory that is to be used and released right away.
    +-** This routine is similar to alloca() in that it is not intended
    +-** for situations where the memory might be held long-term.  This
    +-** routine is intended to get memory to old large transient data
    +-** structures that would not normally fit on the stack of an
    +-** embedded processor.
    +-*/
    +-SQLITE_PRIVATE void *sqlite3ScratchMalloc(int n){
    +-  void *p;
    +-  assert( n>0 );
    +-
    +-  sqlite3_mutex_enter(mem0.mutex);
    +-  sqlite3StatusSet(SQLITE_STATUS_SCRATCH_SIZE, n);
    +-  if( mem0.nScratchFree && sqlite3GlobalConfig.szScratch>=n ){
    +-    p = mem0.pScratchFree;
    +-    mem0.pScratchFree = mem0.pScratchFree->pNext;
    +-    mem0.nScratchFree--;
    +-    sqlite3StatusUp(SQLITE_STATUS_SCRATCH_USED, 1);
    +-    sqlite3_mutex_leave(mem0.mutex);
    +-  }else{
    +-    sqlite3_mutex_leave(mem0.mutex);
    +-    p = sqlite3Malloc(n);
    +-    if( sqlite3GlobalConfig.bMemstat && p ){
    +-      sqlite3_mutex_enter(mem0.mutex);
    +-      sqlite3StatusUp(SQLITE_STATUS_SCRATCH_OVERFLOW, sqlite3MallocSize(p));
    +-      sqlite3_mutex_leave(mem0.mutex);
    +-    }
    +-    sqlite3MemdebugSetType(p, MEMTYPE_SCRATCH);
    +-  }
    +-  assert( sqlite3_mutex_notheld(mem0.mutex) );
    +-
    +-
    +-#if SQLITE_THREADSAFE==0 && !defined(NDEBUG)
    +-  /* EVIDENCE-OF: R-12970-05880 SQLite will not use more than one scratch
    +-  ** buffers per thread.
    +-  **
    +-  ** This can only be checked in single-threaded mode.
    +-  */
    +-  assert( scratchAllocOut==0 );
    +-  if( p ) scratchAllocOut++;
    +-#endif
    +-
    +-  return p;
    +-}
    +-SQLITE_PRIVATE void sqlite3ScratchFree(void *p){
    +-  if( p ){
    +-
    +-#if SQLITE_THREADSAFE==0 && !defined(NDEBUG)
    +-    /* Verify that no more than two scratch allocation per thread
    +-    ** is outstanding at one time.  (This is only checked in the
    +-    ** single-threaded case since checking in the multi-threaded case
    +-    ** would be much more complicated.) */
    +-    assert( scratchAllocOut>=1 && scratchAllocOut<=2 );
    +-    scratchAllocOut--;
    +-#endif
    +-
    +-    if( p>=sqlite3GlobalConfig.pScratch && p<mem0.pScratchEnd ){
    +-      /* Release memory from the SQLITE_CONFIG_SCRATCH allocation */
    +-      ScratchFreeslot *pSlot;
    +-      pSlot = (ScratchFreeslot*)p;
    +-      sqlite3_mutex_enter(mem0.mutex);
    +-      pSlot->pNext = mem0.pScratchFree;
    +-      mem0.pScratchFree = pSlot;
    +-      mem0.nScratchFree++;
    +-      assert( mem0.nScratchFree <= (u32)sqlite3GlobalConfig.nScratch );
    +-      sqlite3StatusDown(SQLITE_STATUS_SCRATCH_USED, 1);
    +-      sqlite3_mutex_leave(mem0.mutex);
    +-    }else{
    +-      /* Release memory back to the heap */
    +-      assert( sqlite3MemdebugHasType(p, MEMTYPE_SCRATCH) );
    +-      assert( sqlite3MemdebugNoType(p, (u8)~MEMTYPE_SCRATCH) );
    +-      sqlite3MemdebugSetType(p, MEMTYPE_HEAP);
    +-      if( sqlite3GlobalConfig.bMemstat ){
    +-        int iSize = sqlite3MallocSize(p);
    +-        sqlite3_mutex_enter(mem0.mutex);
    +-        sqlite3StatusDown(SQLITE_STATUS_SCRATCH_OVERFLOW, iSize);
    +-        sqlite3StatusDown(SQLITE_STATUS_MEMORY_USED, iSize);
    +-        sqlite3StatusDown(SQLITE_STATUS_MALLOC_COUNT, 1);
    +-        sqlite3GlobalConfig.m.xFree(p);
    +-        sqlite3_mutex_leave(mem0.mutex);
    +-      }else{
    +-        sqlite3GlobalConfig.m.xFree(p);
    +-      }
    +-    }
    +-  }
    +-}
    +-
    + /*
    + ** TRUE if p is a lookaside memory allocation from db
    + */
    + #ifndef SQLITE_OMIT_LOOKASIDE
    + static int isLookaside(sqlite3 *db, void *p){
    +-  return p>=db->lookaside.pStart && p<db->lookaside.pEnd;
    ++  return SQLITE_WITHIN(p, db->lookaside.pStart, db->lookaside.pEnd);
    + }
    + #else
    + #define isLookaside(A,B) 0
    +@@ -21754,8 +25424,9 @@ SQLITE_PRIVATE int sqlite3MallocSize(void *p){
    +   return sqlite3GlobalConfig.m.xSize(p);
    + }
    + SQLITE_PRIVATE int sqlite3DbMallocSize(sqlite3 *db, void *p){
    ++  assert( p!=0 );
    +   if( db==0 || !isLookaside(db,p) ){
    +-#if SQLITE_DEBUG
    ++#ifdef SQLITE_DEBUG
    +     if( db==0 ){
    +       assert( sqlite3MemdebugNoType(p, (u8)~MEMTYPE_HEAP) );
    +       assert( sqlite3MemdebugHasType(p, MEMTYPE_HEAP) );
    +@@ -21770,16 +25441,16 @@ SQLITE_PRIVATE int sqlite3DbMallocSize(sqlite3 *db, void *p){
    +     return db->lookaside.sz;
    +   }
    + }
    +-SQLITE_API sqlite3_uint64 SQLITE_STDCALL sqlite3_msize(void *p){
    ++SQLITE_API sqlite3_uint64 sqlite3_msize(void *p){
    +   assert( sqlite3MemdebugNoType(p, (u8)~MEMTYPE_HEAP) );
    +   assert( sqlite3MemdebugHasType(p, MEMTYPE_HEAP) );
    +-  return (sqlite3_uint64)sqlite3GlobalConfig.m.xSize(p);
    ++  return p ? sqlite3GlobalConfig.m.xSize(p) : 0;
    + }
    + 
    + /*
    + ** Free memory previously obtained from sqlite3Malloc().
    + */
    +-SQLITE_API void SQLITE_STDCALL sqlite3_free(void *p){
    ++SQLITE_API void sqlite3_free(void *p){
    +   if( p==0 ) return;  /* IMP: R-49053-54554 */
    +   assert( sqlite3MemdebugHasType(p, MEMTYPE_HEAP) );
    +   assert( sqlite3MemdebugNoType(p, (u8)~MEMTYPE_HEAP) );
    +@@ -21804,11 +25475,12 @@ static SQLITE_NOINLINE void measureAllocationSize(sqlite3 *db, void *p){
    + 
    + /*
    + ** Free memory that might be associated with a particular database
    +-** connection.
    ++** connection.  Calling sqlite3DbFree(D,X) for X==0 is a harmless no-op.
    ++** The sqlite3DbFreeNN(D,X) version requires that X be non-NULL.
    + */
    +-SQLITE_PRIVATE void sqlite3DbFree(sqlite3 *db, void *p){
    ++SQLITE_PRIVATE void sqlite3DbFreeNN(sqlite3 *db, void *p){
    +   assert( db==0 || sqlite3_mutex_held(db->mutex) );
    +-  if( p==0 ) return;
    ++  assert( p!=0 );
    +   if( db ){
    +     if( db->pnBytesFreed ){
    +       measureAllocationSize(db, p);
    +@@ -21816,13 +25488,12 @@ SQLITE_PRIVATE void sqlite3DbFree(sqlite3 *db, void *p){
    +     }
    +     if( isLookaside(db, p) ){
    +       LookasideSlot *pBuf = (LookasideSlot*)p;
    +-#if SQLITE_DEBUG
    ++#ifdef SQLITE_DEBUG
    +       /* Trash all content in the buffer being freed */
    +       memset(p, 0xaa, db->lookaside.sz);
    + #endif
    +       pBuf->pNext = db->lookaside.pFree;
    +       db->lookaside.pFree = pBuf;
    +-      db->lookaside.nOut--;
    +       return;
    +     }
    +   }
    +@@ -21832,6 +25503,10 @@ SQLITE_PRIVATE void sqlite3DbFree(sqlite3 *db, void *p){
    +   sqlite3MemdebugSetType(p, MEMTYPE_HEAP);
    +   sqlite3_free(p);
    + }
    ++SQLITE_PRIVATE void sqlite3DbFree(sqlite3 *db, void *p){
    ++  assert( db==0 || sqlite3_mutex_held(db->mutex) );
    ++  if( p ) sqlite3DbFreeNN(db, p);
    ++}
    + 
    + /*
    + ** Change the size of an existing memory allocation
    +@@ -21861,9 +25536,9 @@ SQLITE_PRIVATE void *sqlite3Realloc(void *pOld, u64 nBytes){
    +     pNew = pOld;
    +   }else if( sqlite3GlobalConfig.bMemstat ){
    +     sqlite3_mutex_enter(mem0.mutex);
    +-    sqlite3StatusSet(SQLITE_STATUS_MALLOC_SIZE, (int)nBytes);
    ++    sqlite3StatusHighwater(SQLITE_STATUS_MALLOC_SIZE, (int)nBytes);
    +     nDiff = nNew - nOld;
    +-    if( sqlite3StatusValue(SQLITE_STATUS_MEMORY_USED) >= 
    ++    if( nDiff>0 && sqlite3StatusValue(SQLITE_STATUS_MEMORY_USED) >= 
    +           mem0.alarmThreshold-nDiff ){
    +       sqlite3MallocAlarm(nDiff);
    +     }
    +@@ -21888,14 +25563,14 @@ SQLITE_PRIVATE void *sqlite3Realloc(void *pOld, u64 nBytes){
    + ** The public interface to sqlite3Realloc.  Make sure that the memory
    + ** subsystem is initialized prior to invoking sqliteRealloc.
    + */
    +-SQLITE_API void *SQLITE_STDCALL sqlite3_realloc(void *pOld, int n){
    ++SQLITE_API void *sqlite3_realloc(void *pOld, int n){
    + #ifndef SQLITE_OMIT_AUTOINIT
    +   if( sqlite3_initialize() ) return 0;
    + #endif
    +   if( n<0 ) n = 0;  /* IMP: R-26507-47431 */
    +   return sqlite3Realloc(pOld, n);
    + }
    +-SQLITE_API void *SQLITE_STDCALL sqlite3_realloc64(void *pOld, sqlite3_uint64 n){
    ++SQLITE_API void *sqlite3_realloc64(void *pOld, sqlite3_uint64 n){
    + #ifndef SQLITE_OMIT_AUTOINIT
    +   if( sqlite3_initialize() ) return 0;
    + #endif
    +@@ -21919,16 +25594,31 @@ SQLITE_PRIVATE void *sqlite3MallocZero(u64 n){
    + ** the mallocFailed flag in the connection pointer.
    + */
    + SQLITE_PRIVATE void *sqlite3DbMallocZero(sqlite3 *db, u64 n){
    +-  void *p = sqlite3DbMallocRaw(db, n);
    +-  if( p ){
    +-    memset(p, 0, (size_t)n);
    +-  }
    ++  void *p;
    ++  testcase( db==0 );
    ++  p = sqlite3DbMallocRaw(db, n);
    ++  if( p ) memset(p, 0, (size_t)n);
    ++  return p;
    ++}
    ++
    ++
    ++/* Finish the work of sqlite3DbMallocRawNN for the unusual and
    ++** slower case when the allocation cannot be fulfilled using lookaside.
    ++*/
    ++static SQLITE_NOINLINE void *dbMallocRawFinish(sqlite3 *db, u64 n){
    ++  void *p;
    ++  assert( db!=0 );
    ++  p = sqlite3Malloc(n);
    ++  if( !p ) sqlite3OomFault(db);
    ++  sqlite3MemdebugSetType(p, 
    ++         (db->lookaside.bDisable==0) ? MEMTYPE_LOOKASIDE : MEMTYPE_HEAP);
    +   return p;
    + }
    + 
    + /*
    +-** Allocate and zero memory.  If the allocation fails, make
    +-** the mallocFailed flag in the connection pointer.
    ++** Allocate memory, either lookaside (if possible) or heap.  
    ++** If the allocation fails, set the mallocFailed flag in
    ++** the connection pointer.
    + **
    + ** If db!=0 and db->mallocFailed is true (indicating a prior malloc
    + ** failure on the same database connection) then always return 0.
    +@@ -21943,64 +25633,73 @@ SQLITE_PRIVATE void *sqlite3DbMallocZero(sqlite3 *db, u64 n){
    + **
    + ** In other words, if a subsequent malloc (ex: "b") worked, it is assumed
    + ** that all prior mallocs (ex: "a") worked too.
    ++**
    ++** The sqlite3MallocRawNN() variant guarantees that the "db" parameter is
    ++** not a NULL pointer.
    + */
    + SQLITE_PRIVATE void *sqlite3DbMallocRaw(sqlite3 *db, u64 n){
    +   void *p;
    +-  assert( db==0 || sqlite3_mutex_held(db->mutex) );
    +-  assert( db==0 || db->pnBytesFreed==0 );
    ++  if( db ) return sqlite3DbMallocRawNN(db, n);
    ++  p = sqlite3Malloc(n);
    ++  sqlite3MemdebugSetType(p, MEMTYPE_HEAP);
    ++  return p;
    ++}
    ++SQLITE_PRIVATE void *sqlite3DbMallocRawNN(sqlite3 *db, u64 n){
    + #ifndef SQLITE_OMIT_LOOKASIDE
    +-  if( db ){
    +-    LookasideSlot *pBuf;
    +-    if( db->mallocFailed ){
    +-      return 0;
    +-    }
    +-    if( db->lookaside.bEnabled ){
    +-      if( n>db->lookaside.sz ){
    +-        db->lookaside.anStat[1]++;
    +-      }else if( (pBuf = db->lookaside.pFree)==0 ){
    +-        db->lookaside.anStat[2]++;
    +-      }else{
    +-        db->lookaside.pFree = pBuf->pNext;
    +-        db->lookaside.nOut++;
    +-        db->lookaside.anStat[0]++;
    +-        if( db->lookaside.nOut>db->lookaside.mxOut ){
    +-          db->lookaside.mxOut = db->lookaside.nOut;
    +-        }
    +-        return (void*)pBuf;
    +-      }
    +-    }
    ++  LookasideSlot *pBuf;
    ++  assert( db!=0 );
    ++  assert( sqlite3_mutex_held(db->mutex) );
    ++  assert( db->pnBytesFreed==0 );
    ++  if( db->lookaside.bDisable==0 ){
    ++    assert( db->mallocFailed==0 );
    ++    if( n>db->lookaside.sz ){
    ++      db->lookaside.anStat[1]++;
    ++    }else if( (pBuf = db->lookaside.pFree)!=0 ){
    ++      db->lookaside.pFree = pBuf->pNext;
    ++      db->lookaside.anStat[0]++;
    ++      return (void*)pBuf;
    ++    }else if( (pBuf = db->lookaside.pInit)!=0 ){
    ++      db->lookaside.pInit = pBuf->pNext;
    ++      db->lookaside.anStat[0]++;
    ++      return (void*)pBuf;
    ++    }else{
    ++      db->lookaside.anStat[2]++;
    ++    }
    ++  }else if( db->mallocFailed ){
    ++    return 0;
    +   }
    + #else
    +-  if( db && db->mallocFailed ){
    ++  assert( db!=0 );
    ++  assert( sqlite3_mutex_held(db->mutex) );
    ++  assert( db->pnBytesFreed==0 );
    ++  if( db->mallocFailed ){
    +     return 0;
    +   }
    + #endif
    +-  p = sqlite3Malloc(n);
    +-  if( !p && db ){
    +-    db->mallocFailed = 1;
    +-  }
    +-  sqlite3MemdebugSetType(p, 
    +-         (db && db->lookaside.bEnabled) ? MEMTYPE_LOOKASIDE : MEMTYPE_HEAP);
    +-  return p;
    ++  return dbMallocRawFinish(db, n);
    + }
    + 
    ++/* Forward declaration */
    ++static SQLITE_NOINLINE void *dbReallocFinish(sqlite3 *db, void *p, u64 n);
    ++
    + /*
    + ** Resize the block of memory pointed to by p to n bytes. If the
    + ** resize fails, set the mallocFailed flag in the connection object.
    + */
    + SQLITE_PRIVATE void *sqlite3DbRealloc(sqlite3 *db, void *p, u64 n){
    +-  void *pNew = 0;
    +   assert( db!=0 );
    ++  if( p==0 ) return sqlite3DbMallocRawNN(db, n);
    +   assert( sqlite3_mutex_held(db->mutex) );
    ++  if( isLookaside(db,p) && n<=db->lookaside.sz ) return p;
    ++  return dbReallocFinish(db, p, n);
    ++}
    ++static SQLITE_NOINLINE void *dbReallocFinish(sqlite3 *db, void *p, u64 n){
    ++  void *pNew = 0;
    ++  assert( db!=0 );
    ++  assert( p!=0 );
    +   if( db->mallocFailed==0 ){
    +-    if( p==0 ){
    +-      return sqlite3DbMallocRaw(db, n);
    +-    }
    +     if( isLookaside(db, p) ){
    +-      if( n<=db->lookaside.sz ){
    +-        return p;
    +-      }
    +-      pNew = sqlite3DbMallocRaw(db, n);
    ++      pNew = sqlite3DbMallocRawNN(db, n);
    +       if( pNew ){
    +         memcpy(pNew, p, db->lookaside.sz);
    +         sqlite3DbFree(db, p);
    +@@ -22011,10 +25710,10 @@ SQLITE_PRIVATE void *sqlite3DbRealloc(sqlite3 *db, void *p, u64 n){
    +       sqlite3MemdebugSetType(p, MEMTYPE_HEAP);
    +       pNew = sqlite3_realloc64(p, n);
    +       if( !pNew ){
    +-        db->mallocFailed = 1;
    ++        sqlite3OomFault(db);
    +       }
    +       sqlite3MemdebugSetType(pNew,
    +-            (db->lookaside.bEnabled ? MEMTYPE_LOOKASIDE : MEMTYPE_HEAP));
    ++            (db->lookaside.bDisable==0 ? MEMTYPE_LOOKASIDE : MEMTYPE_HEAP));
    +     }
    +   }
    +   return pNew;
    +@@ -22046,9 +25745,8 @@ SQLITE_PRIVATE char *sqlite3DbStrDup(sqlite3 *db, const char *z){
    +   if( z==0 ){
    +     return 0;
    +   }
    +-  n = sqlite3Strlen30(z) + 1;
    +-  assert( (n&0x7fffffff)==n );
    +-  zNew = sqlite3DbMallocRaw(db, (int)n);
    ++  n = strlen(z) + 1;
    ++  zNew = sqlite3DbMallocRaw(db, n);
    +   if( zNew ){
    +     memcpy(zNew, z, n);
    +   }
    +@@ -22056,11 +25754,12 @@ SQLITE_PRIVATE char *sqlite3DbStrDup(sqlite3 *db, const char *z){
    + }
    + SQLITE_PRIVATE char *sqlite3DbStrNDup(sqlite3 *db, const char *z, u64 n){
    +   char *zNew;
    ++  assert( db!=0 );
    +   if( z==0 ){
    +     return 0;
    +   }
    +   assert( (n&0x7fffffff)==n );
    +-  zNew = sqlite3DbMallocRaw(db, n+1);
    ++  zNew = sqlite3DbMallocRawNN(db, n+1);
    +   if( zNew ){
    +     memcpy(zNew, z, (size_t)n);
    +     zNew[n] = 0;
    +@@ -22068,6 +25767,19 @@ SQLITE_PRIVATE char *sqlite3DbStrNDup(sqlite3 *db, const char *z, u64 n){
    +   return zNew;
    + }
    + 
    ++/*
    ++** The text between zStart and zEnd represents a phrase within a larger
    ++** SQL statement.  Make a copy of this phrase in space obtained form
    ++** sqlite3DbMalloc().  Omit leading and trailing whitespace.
    ++*/
    ++SQLITE_PRIVATE char *sqlite3DbSpanDup(sqlite3 *db, const char *zStart, const char *zEnd){
    ++  int n;
    ++  while( sqlite3Isspace(zStart[0]) ) zStart++;
    ++  n = (int)(zEnd - zStart);
    ++  while( ALWAYS(n>0) && sqlite3Isspace(zStart[n-1]) ) n--;
    ++  return sqlite3DbStrNDup(db, zStart, n);
    ++}
    ++
    + /*
    + ** Free any prior content in *pz and replace it with a copy of zNew.
    + */
    +@@ -22076,13 +25788,45 @@ SQLITE_PRIVATE void sqlite3SetString(char **pz, sqlite3 *db, const char *zNew){
    +   *pz = sqlite3DbStrDup(db, zNew);
    + }
    + 
    ++/*
    ++** Call this routine to record the fact that an OOM (out-of-memory) error
    ++** has happened.  This routine will set db->mallocFailed, and also
    ++** temporarily disable the lookaside memory allocator and interrupt
    ++** any running VDBEs.
    ++*/
    ++SQLITE_PRIVATE void sqlite3OomFault(sqlite3 *db){
    ++  if( db->mallocFailed==0 && db->bBenignMalloc==0 ){
    ++    db->mallocFailed = 1;
    ++    if( db->nVdbeExec>0 ){
    ++      db->u1.isInterrupted = 1;
    ++    }
    ++    db->lookaside.bDisable++;
    ++  }
    ++}
    ++
    ++/*
    ++** This routine reactivates the memory allocator and clears the
    ++** db->mallocFailed flag as necessary.
    ++**
    ++** The memory allocator is not restarted if there are running
    ++** VDBEs.
    ++*/
    ++SQLITE_PRIVATE void sqlite3OomClear(sqlite3 *db){
    ++  if( db->mallocFailed && db->nVdbeExec==0 ){
    ++    db->mallocFailed = 0;
    ++    db->u1.isInterrupted = 0;
    ++    assert( db->lookaside.bDisable>0 );
    ++    db->lookaside.bDisable--;
    ++  }
    ++}
    ++
    + /*
    + ** Take actions at the end of an API call to indicate an OOM error
    + */
    + static SQLITE_NOINLINE int apiOomError(sqlite3 *db){
    +-  db->mallocFailed = 0;
    ++  sqlite3OomClear(db);
    +   sqlite3Error(db, SQLITE_NOMEM);
    +-  return SQLITE_NOMEM;
    ++  return SQLITE_NOMEM_BKPT;
    + }
    + 
    + /*
    +@@ -22129,26 +25873,27 @@ SQLITE_PRIVATE int sqlite3ApiExit(sqlite3* db, int rc){
    + ** Conversion types fall into various categories as defined by the
    + ** following enumeration.
    + */
    +-#define etRADIX       1 /* Integer types.  %d, %x, %o, and so forth */
    +-#define etFLOAT       2 /* Floating point.  %f */
    +-#define etEXP         3 /* Exponentional notation. %e and %E */
    +-#define etGENERIC     4 /* Floating or exponential, depending on exponent. %g */
    +-#define etSIZE        5 /* Return number of characters processed so far. %n */
    +-#define etSTRING      6 /* Strings. %s */
    +-#define etDYNSTRING   7 /* Dynamically allocated strings. %z */
    +-#define etPERCENT     8 /* Percent symbol. %% */
    +-#define etCHARX       9 /* Characters. %c */
    ++#define etRADIX       0 /* non-decimal integer types.  %x %o */
    ++#define etFLOAT       1 /* Floating point.  %f */
    ++#define etEXP         2 /* Exponentional notation. %e and %E */
    ++#define etGENERIC     3 /* Floating or exponential, depending on exponent. %g */
    ++#define etSIZE        4 /* Return number of characters processed so far. %n */
    ++#define etSTRING      5 /* Strings. %s */
    ++#define etDYNSTRING   6 /* Dynamically allocated strings. %z */
    ++#define etPERCENT     7 /* Percent symbol. %% */
    ++#define etCHARX       8 /* Characters. %c */
    + /* The rest are extensions, not normally found in printf() */
    +-#define etSQLESCAPE  10 /* Strings with '\'' doubled.  %q */
    +-#define etSQLESCAPE2 11 /* Strings with '\'' doubled and enclosed in '',
    ++#define etSQLESCAPE   9 /* Strings with '\'' doubled.  %q */
    ++#define etSQLESCAPE2 10 /* Strings with '\'' doubled and enclosed in '',
    +                           NULL pointers replaced by SQL NULL.  %Q */
    +-#define etTOKEN      12 /* a pointer to a Token structure */
    +-#define etSRCLIST    13 /* a pointer to a SrcList */
    +-#define etPOINTER    14 /* The %p conversion */
    +-#define etSQLESCAPE3 15 /* %w -> Strings with '\"' doubled */
    +-#define etORDINAL    16 /* %r -> 1st, 2nd, 3rd, 4th, etc.  English only */
    ++#define etTOKEN      11 /* a pointer to a Token structure */
    ++#define etSRCLIST    12 /* a pointer to a SrcList */
    ++#define etPOINTER    13 /* The %p conversion */
    ++#define etSQLESCAPE3 14 /* %w -> Strings with '\"' doubled */
    ++#define etORDINAL    15 /* %r -> 1st, 2nd, 3rd, 4th, etc.  English only */
    ++#define etDECIMAL    16 /* %d or %u, but not %x, %o */
    + 
    +-#define etINVALID     0 /* Any unrecognized conversion type */
    ++#define etINVALID    17 /* Any unrecognized conversion type */
    + 
    + 
    + /*
    +@@ -22172,9 +25917,8 @@ typedef struct et_info {   /* Information about each format field */
    + /*
    + ** Allowed values for et_info.flags
    + */
    +-#define FLAG_SIGNED  1     /* True if the value to convert is signed */
    +-#define FLAG_INTERN  2     /* True if for internal use only */
    +-#define FLAG_STRING  4     /* Allow infinity precision */
    ++#define FLAG_SIGNED    1     /* True if the value to convert is signed */
    ++#define FLAG_STRING    4     /* Allow infinite precision */
    + 
    + 
    + /*
    +@@ -22184,7 +25928,7 @@ typedef struct et_info {   /* Information about each format field */
    + static const char aDigits[] = "0123456789ABCDEF0123456789abcdef";
    + static const char aPrefix[] = "-x0\000X0";
    + static const et_info fmtinfo[] = {
    +-  {  'd', 10, 1, etRADIX,      0,  0 },
    ++  {  'd', 10, 1, etDECIMAL,    0,  0 },
    +   {  's',  0, 4, etSTRING,     0,  0 },
    +   {  'g',  0, 1, etGENERIC,    30, 0 },
    +   {  'z',  0, 4, etDYNSTRING,  0,  0 },
    +@@ -22193,7 +25937,7 @@ static const et_info fmtinfo[] = {
    +   {  'w',  0, 4, etSQLESCAPE3, 0,  0 },
    +   {  'c',  0, 0, etCHARX,      0,  0 },
    +   {  'o',  8, 0, etRADIX,      0,  2 },
    +-  {  'u', 10, 0, etRADIX,      0,  0 },
    ++  {  'u', 10, 0, etDECIMAL,    0,  0 },
    +   {  'x', 16, 0, etRADIX,      16, 1 },
    +   {  'X', 16, 0, etRADIX,      0,  4 },
    + #ifndef SQLITE_OMIT_FLOATING_POINT
    +@@ -22202,16 +25946,15 @@ static const et_info fmtinfo[] = {
    +   {  'E',  0, 1, etEXP,        14, 0 },
    +   {  'G',  0, 1, etGENERIC,    14, 0 },
    + #endif
    +-  {  'i', 10, 1, etRADIX,      0,  0 },
    ++  {  'i', 10, 1, etDECIMAL,    0,  0 },
    +   {  'n',  0, 0, etSIZE,       0,  0 },
    +   {  '%',  0, 0, etPERCENT,    0,  0 },
    +   {  'p', 16, 0, etPOINTER,    0,  1 },
    + 
    +-/* All the rest have the FLAG_INTERN bit set and are thus for internal
    +-** use only */
    +-  {  'T',  0, 2, etTOKEN,      0,  0 },
    +-  {  'S',  0, 2, etSRCLIST,    0,  0 },
    +-  {  'r', 10, 3, etORDINAL,    0,  0 },
    ++  /* All the rest are undocumented and are for internal use only */
    ++  {  'T',  0, 0, etTOKEN,      0,  0 },
    ++  {  'S',  0, 0, etSRCLIST,    0,  0 },
    ++  {  'r', 10, 1, etORDINAL,    0,  0 },
    + };
    + 
    + /*
    +@@ -22285,7 +26028,6 @@ static char *getTextArg(PrintfArguments *p){
    + */
    + SQLITE_PRIVATE void sqlite3VXPrintf(
    +   StrAccum *pAccum,          /* Accumulate results here */
    +-  u32 bFlags,                /* SQLITE_PRINTF_* flags */
    +   const char *fmt,           /* Format string */
    +   va_list ap                 /* arguments */
    + ){
    +@@ -22296,17 +26038,15 @@ SQLITE_PRIVATE void sqlite3VXPrintf(
    +   int idx;                   /* A general purpose loop counter */
    +   int width;                 /* Width of the current field */
    +   etByte flag_leftjustify;   /* True if "-" flag is present */
    +-  etByte flag_plussign;      /* True if "+" flag is present */
    +-  etByte flag_blanksign;     /* True if " " flag is present */
    ++  etByte flag_prefix;        /* '+' or ' ' or 0 for prefix */
    +   etByte flag_alternateform; /* True if "#" flag is present */
    +   etByte flag_altform2;      /* True if "!" flag is present */
    +   etByte flag_zeropad;       /* True if field width constant starts with zero */
    +-  etByte flag_long;          /* True if "l" flag is present */
    +-  etByte flag_longlong;      /* True if the "ll" flag is present */
    ++  etByte flag_long;          /* 1 for the "l" flag, 2 for "ll", 0 by default */
    +   etByte done;               /* Loop termination flag */
    +-  etByte xtype = 0;          /* Conversion paradigm */
    ++  etByte cThousand;          /* Thousands separator for %d and %u */
    ++  etByte xtype = etINVALID;  /* Conversion paradigm */
    +   u8 bArgList;               /* True for SQLITE_PRINTF_SQLFUNC */
    +-  u8 useIntern;              /* Ok to use internal conversions (ex: %T) */
    +   char prefix;               /* Prefix character.  "+" or "-" or " " or '\0'. */
    +   sqlite_uint64 longvalue;   /* Value for integer types */
    +   LONGDOUBLE_TYPE realvalue; /* Value for real types */
    +@@ -22325,13 +26065,11 @@ SQLITE_PRIVATE void sqlite3VXPrintf(
    +   char buf[etBUFSIZE];       /* Conversion buffer */
    + 
    +   bufpt = 0;
    +-  if( bFlags ){
    +-    if( (bArgList = (bFlags & SQLITE_PRINTF_SQLFUNC))!=0 ){
    +-      pArgList = va_arg(ap, PrintfArguments*);
    +-    }
    +-    useIntern = bFlags & SQLITE_PRINTF_INTERNAL;
    ++  if( (pAccum->printfFlags & SQLITE_PRINTF_SQLFUNC)!=0 ){
    ++    pArgList = va_arg(ap, PrintfArguments*);
    ++    bArgList = 1;
    +   }else{
    +-    bArgList = useIntern = 0;
    ++    bArgList = 0;
    +   }
    +   for(; (c=(*fmt))!=0; ++fmt){
    +     if( c!='%' ){
    +@@ -22349,17 +26087,18 @@ SQLITE_PRIVATE void sqlite3VXPrintf(
    +       break;
    +     }
    +     /* Find out what flags are present */
    +-    flag_leftjustify = flag_plussign = flag_blanksign = 
    ++    flag_leftjustify = flag_prefix = cThousand =
    +      flag_alternateform = flag_altform2 = flag_zeropad = 0;
    +     done = 0;
    +     do{
    +       switch( c ){
    +         case '-':   flag_leftjustify = 1;     break;
    +-        case '+':   flag_plussign = 1;        break;
    +-        case ' ':   flag_blanksign = 1;       break;
    ++        case '+':   flag_prefix = '+';        break;
    ++        case ' ':   flag_prefix = ' ';        break;
    +         case '#':   flag_alternateform = 1;   break;
    +         case '!':   flag_altform2 = 1;        break;
    +         case '0':   flag_zeropad = 1;         break;
    ++        case ',':   cThousand = ',';          break;
    +         default:    done = 1;                 break;
    +       }
    +     }while( !done && (c=(*++fmt))!=0 );
    +@@ -22384,6 +26123,12 @@ SQLITE_PRIVATE void sqlite3VXPrintf(
    +       testcase( wx>0x7fffffff );
    +       width = wx & 0x7fffffff;
    +     }
    ++    assert( width>=0 );
    ++#ifdef SQLITE_PRINTF_PRECISION_LIMIT
    ++    if( width>SQLITE_PRINTF_PRECISION_LIMIT ){
    ++      width = SQLITE_PRINTF_PRECISION_LIMIT;
    ++    }
    ++#endif
    + 
    +     /* Get the precision */
    +     if( c=='.' ){
    +@@ -22410,18 +26155,24 @@ SQLITE_PRIVATE void sqlite3VXPrintf(
    +     }else{
    +       precision = -1;
    +     }
    ++    assert( precision>=(-1) );
    ++#ifdef SQLITE_PRINTF_PRECISION_LIMIT
    ++    if( precision>SQLITE_PRINTF_PRECISION_LIMIT ){
    ++      precision = SQLITE_PRINTF_PRECISION_LIMIT;
    ++    }
    ++#endif
    ++
    ++
    +     /* Get the conversion type modifier */
    +     if( c=='l' ){
    +       flag_long = 1;
    +       c = *++fmt;
    +       if( c=='l' ){
    +-        flag_longlong = 1;
    ++        flag_long = 2;
    +         c = *++fmt;
    +-      }else{
    +-        flag_longlong = 0;
    +       }
    +     }else{
    +-      flag_long = flag_longlong = 0;
    ++      flag_long = 0;
    +     }
    +     /* Fetch the info entry for the field */
    +     infop = &fmtinfo[0];
    +@@ -22429,11 +26180,7 @@ SQLITE_PRIVATE void sqlite3VXPrintf(
    +     for(idx=0; idx<ArraySize(fmtinfo); idx++){
    +       if( c==fmtinfo[idx].fmttype ){
    +         infop = &fmtinfo[idx];
    +-        if( useIntern || (infop->flags & FLAG_INTERN)==0 ){
    +-          xtype = infop->type;
    +-        }else{
    +-          return;
    +-        }
    ++        xtype = infop->type;
    +         break;
    +       }
    +     }
    +@@ -22443,15 +26190,11 @@ SQLITE_PRIVATE void sqlite3VXPrintf(
    +     **
    +     **   flag_alternateform          TRUE if a '#' is present.
    +     **   flag_altform2               TRUE if a '!' is present.
    +-    **   flag_plussign               TRUE if a '+' is present.
    ++    **   flag_prefix                 '+' or ' ' or zero
    +     **   flag_leftjustify            TRUE if a '-' is present or if the
    +     **                               field width was negative.
    +     **   flag_zeropad                TRUE if the width began with 0.
    +-    **   flag_long                   TRUE if the letter 'l' (ell) prefixed
    +-    **                               the conversion character.
    +-    **   flag_longlong               TRUE if the letter 'll' (ell ell) prefixed
    +-    **                               the conversion character.
    +-    **   flag_blanksign              TRUE if a ' ' is present.
    ++    **   flag_long                   1 for "l", 2 for "ll"
    +     **   width                       The specified field width.  This is
    +     **                               always non-negative.  Zero is the default.
    +     **   precision                   The specified precision.  The default
    +@@ -22461,19 +26204,24 @@ SQLITE_PRIVATE void sqlite3VXPrintf(
    +     */
    +     switch( xtype ){
    +       case etPOINTER:
    +-        flag_longlong = sizeof(char*)==sizeof(i64);
    +-        flag_long = sizeof(char*)==sizeof(long int);
    ++        flag_long = sizeof(char*)==sizeof(i64) ? 2 :
    ++                     sizeof(char*)==sizeof(long int) ? 1 : 0;
    +         /* Fall through into the next case */
    +       case etORDINAL:
    +-      case etRADIX:
    ++      case etRADIX:      
    ++        cThousand = 0;
    ++        /* Fall through into the next case */
    ++      case etDECIMAL:
    +         if( infop->flags & FLAG_SIGNED ){
    +           i64 v;
    +           if( bArgList ){
    +             v = getIntArg(pArgList);
    +-          }else if( flag_longlong ){
    +-            v = va_arg(ap,i64);
    +           }else if( flag_long ){
    +-            v = va_arg(ap,long int);
    ++            if( flag_long==2 ){
    ++              v = va_arg(ap,i64) ;
    ++            }else{
    ++              v = va_arg(ap,long int);
    ++            }
    +           }else{
    +             v = va_arg(ap,int);
    +           }
    +@@ -22486,17 +26234,17 @@ SQLITE_PRIVATE void sqlite3VXPrintf(
    +             prefix = '-';
    +           }else{
    +             longvalue = v;
    +-            if( flag_plussign )        prefix = '+';
    +-            else if( flag_blanksign )  prefix = ' ';
    +-            else                       prefix = 0;
    ++            prefix = flag_prefix;
    +           }
    +         }else{
    +           if( bArgList ){
    +             longvalue = (u64)getIntArg(pArgList);
    +-          }else if( flag_longlong ){
    +-            longvalue = va_arg(ap,u64);
    +           }else if( flag_long ){
    +-            longvalue = va_arg(ap,unsigned long int);
    ++            if( flag_long==2 ){
    ++              longvalue = va_arg(ap,u64);
    ++            }else{
    ++              longvalue = va_arg(ap,unsigned long int);
    ++            }
    +           }else{
    +             longvalue = va_arg(ap,unsigned int);
    +           }
    +@@ -22506,16 +26254,17 @@ SQLITE_PRIVATE void sqlite3VXPrintf(
    +         if( flag_zeropad && precision<width-(prefix!=0) ){
    +           precision = width-(prefix!=0);
    +         }
    +-        if( precision<etBUFSIZE-10 ){
    ++        if( precision<etBUFSIZE-10-etBUFSIZE/3 ){
    +           nOut = etBUFSIZE;
    +           zOut = buf;
    +         }else{
    +-          nOut = precision + 10;
    +-          zOut = zExtra = sqlite3Malloc( nOut );
    ++          u64 n = (u64)precision + 10 + precision/3;
    ++          zOut = zExtra = sqlite3Malloc( n );
    +           if( zOut==0 ){
    +             setStrAccumError(pAccum, STRACCUM_NOMEM);
    +             return;
    +           }
    ++          nOut = (int)n;
    +         }
    +         bufpt = &zOut[nOut-1];
    +         if( xtype==etORDINAL ){
    +@@ -22536,8 +26285,23 @@ SQLITE_PRIVATE void sqlite3VXPrintf(
    +           }while( longvalue>0 );
    +         }
    +         length = (int)(&zOut[nOut-1]-bufpt);
    +-        for(idx=precision-length; idx>0; idx--){
    ++        while( precision>length ){
    +           *(--bufpt) = '0';                             /* Zero pad */
    ++          length++;
    ++        }
    ++        if( cThousand ){
    ++          int nn = (length - 1)/3;  /* Number of "," to insert */
    ++          int ix = (length - 1)%3 + 1;
    ++          bufpt -= nn;
    ++          for(idx=0; nn>0; idx++){
    ++            bufpt[idx] = bufpt[idx+nn];
    ++            ix--;
    ++            if( ix==0 ){
    ++              bufpt[++idx] = cThousand;
    ++              nn--;
    ++              ix = 3;
    ++            }
    ++          }
    +         }
    +         if( prefix ) *(--bufpt) = prefix;               /* Add sign */
    +         if( flag_alternateform && infop->prefix ){      /* Add "0" or "0x" */
    +@@ -22564,9 +26328,7 @@ SQLITE_PRIVATE void sqlite3VXPrintf(
    +           realvalue = -realvalue;
    +           prefix = '-';
    +         }else{
    +-          if( flag_plussign )          prefix = '+';
    +-          else if( flag_blanksign )    prefix = ' ';
    +-          else                         prefix = 0;
    ++          prefix = flag_prefix;
    +         }
    +         if( xtype==etGENERIC && precision>0 ) precision--;
    +         testcase( precision>0xfff );
    +@@ -22752,7 +26514,7 @@ SQLITE_PRIVATE void sqlite3VXPrintf(
    +         if( precision>=0 ){
    +           for(length=0; length<precision && bufpt[length]; length++){}
    +         }else{
    +-          length = sqlite3Strlen30(bufpt);
    ++          length = 0x7fffffff & (int)strlen(bufpt);
    +         }
    +         break;
    +       case etSQLESCAPE:           /* Escape ' characters */
    +@@ -22802,7 +26564,9 @@ SQLITE_PRIVATE void sqlite3VXPrintf(
    +         break;
    +       }
    +       case etTOKEN: {
    +-        Token *pToken = va_arg(ap, Token*);
    ++        Token *pToken;
    ++        if( (pAccum->printfFlags & SQLITE_PRINTF_INTERNAL)==0 ) return;
    ++        pToken = va_arg(ap, Token*);
    +         assert( bArgList==0 );
    +         if( pToken && pToken->n ){
    +           sqlite3StrAccumAppend(pAccum, (const char*)pToken->z, pToken->n);
    +@@ -22811,9 +26575,13 @@ SQLITE_PRIVATE void sqlite3VXPrintf(
    +         break;
    +       }
    +       case etSRCLIST: {
    +-        SrcList *pSrc = va_arg(ap, SrcList*);
    +-        int k = va_arg(ap, int);
    +-        struct SrcList_item *pItem = &pSrc->a[k];
    ++        SrcList *pSrc;
    ++        int k;
    ++        struct SrcList_item *pItem;
    ++        if( (pAccum->printfFlags & SQLITE_PRINTF_INTERNAL)==0 ) return;
    ++        pSrc = va_arg(ap, SrcList*);
    ++        k = va_arg(ap, int);
    ++        pItem = &pSrc->a[k];
    +         assert( bArgList==0 );
    +         assert( k>=0 && k<pSrc->nSrc );
    +         if( pItem->zDatabase ){
    +@@ -22835,12 +26603,16 @@ SQLITE_PRIVATE void sqlite3VXPrintf(
    +     ** the output.
    +     */
    +     width -= length;
    +-    if( width>0 && !flag_leftjustify ) sqlite3AppendChar(pAccum, width, ' ');
    +-    sqlite3StrAccumAppend(pAccum, bufpt, length);
    +-    if( width>0 && flag_leftjustify ) sqlite3AppendChar(pAccum, width, ' ');
    ++    if( width>0 ){
    ++      if( !flag_leftjustify ) sqlite3AppendChar(pAccum, width, ' ');
    ++      sqlite3StrAccumAppend(pAccum, bufpt, length);
    ++      if( flag_leftjustify ) sqlite3AppendChar(pAccum, width, ' ');
    ++    }else{
    ++      sqlite3StrAccumAppend(pAccum, bufpt, length);
    ++    }
    + 
    +     if( zExtra ){
    +-      sqlite3_free(zExtra);
    ++      sqlite3DbFree(pAccum->db, zExtra);
    +       zExtra = 0;
    +     }
    +   }/* End for loop over the format string */
    +@@ -22866,7 +26638,7 @@ static int sqlite3StrAccumEnlarge(StrAccum *p, int N){
    +     setStrAccumError(p, STRACCUM_TOOBIG);
    +     return N;
    +   }else{
    +-    char *zOld = (p->zText==p->zBase ? 0 : p->zText);
    ++    char *zOld = isMalloced(p) ? p->zText : 0;
    +     i64 szNew = p->nChar;
    +     szNew += N + 1;
    +     if( szNew+p->nChar<=p->mxAlloc ){
    +@@ -22888,9 +26660,10 @@ static int sqlite3StrAccumEnlarge(StrAccum *p, int N){
    +     }
    +     if( zNew ){
    +       assert( p->zText!=0 || p->nChar==0 );
    +-      if( zOld==0 && p->nChar>0 ) memcpy(zNew, p->zText, p->nChar);
    ++      if( !isMalloced(p) && p->nChar>0 ) memcpy(zNew, p->zText, p->nChar);
    +       p->zText = zNew;
    +       p->nAlloc = sqlite3DbMallocSize(p->db, zNew);
    ++      p->printfFlags |= SQLITE_PRINTF_MALLOCED;
    +     }else{
    +       sqlite3StrAccumReset(p);
    +       setStrAccumError(p, STRACCUM_NOMEM);
    +@@ -22938,7 +26711,7 @@ SQLITE_PRIVATE void sqlite3StrAccumAppend(StrAccum *p, const char *z, int N){
    +   assert( p->accError==0 || p->nAlloc==0 );
    +   if( p->nChar+N >= p->nAlloc ){
    +     enlargeAndAppend(p,z,N);
    +-  }else{
    ++  }else if( N ){
    +     assert( p->zText );
    +     p->nChar += N;
    +     memcpy(&p->zText[p->nChar-N], z, N);
    +@@ -22958,16 +26731,24 @@ SQLITE_PRIVATE void sqlite3StrAccumAppendAll(StrAccum *p, const char *z){
    + ** Return a pointer to the resulting string.  Return a NULL
    + ** pointer if any kind of error was encountered.
    + */
    ++static SQLITE_NOINLINE char *strAccumFinishRealloc(StrAccum *p){
    ++  char *zText;
    ++  assert( p->mxAlloc>0 && !isMalloced(p) );
    ++  zText = sqlite3DbMallocRaw(p->db, p->nChar+1 );
    ++  if( zText ){
    ++    memcpy(zText, p->zText, p->nChar+1);
    ++    p->printfFlags |= SQLITE_PRINTF_MALLOCED;
    ++  }else{
    ++    setStrAccumError(p, STRACCUM_NOMEM);
    ++  }
    ++  p->zText = zText;
    ++  return zText;
    ++}
    + SQLITE_PRIVATE char *sqlite3StrAccumFinish(StrAccum *p){
    +   if( p->zText ){
    +     p->zText[p->nChar] = 0;
    +-    if( p->mxAlloc>0 && p->zText==p->zBase ){
    +-      p->zText = sqlite3DbMallocRaw(p->db, p->nChar+1 );
    +-      if( p->zText ){
    +-        memcpy(p->zText, p->zBase, p->nChar+1);
    +-      }else{
    +-        setStrAccumError(p, STRACCUM_NOMEM);
    +-      }
    ++    if( p->mxAlloc>0 && !isMalloced(p) ){
    ++      return strAccumFinishRealloc(p);
    +     }
    +   }
    +   return p->zText;
    +@@ -22977,8 +26758,9 @@ SQLITE_PRIVATE char *sqlite3StrAccumFinish(StrAccum *p){
    + ** Reset an StrAccum string.  Reclaim all malloced memory.
    + */
    + SQLITE_PRIVATE void sqlite3StrAccumReset(StrAccum *p){
    +-  if( p->zText!=p->zBase ){
    ++  if( isMalloced(p) ){
    +     sqlite3DbFree(p->db, p->zText);
    ++    p->printfFlags &= ~SQLITE_PRINTF_MALLOCED;
    +   }
    +   p->zText = 0;
    + }
    +@@ -22998,12 +26780,13 @@ SQLITE_PRIVATE void sqlite3StrAccumReset(StrAccum *p){
    + **        allocations will ever occur.
    + */
    + SQLITE_PRIVATE void sqlite3StrAccumInit(StrAccum *p, sqlite3 *db, char *zBase, int n, int mx){
    +-  p->zText = p->zBase = zBase;
    ++  p->zText = zBase;
    +   p->db = db;
    +-  p->nChar = 0;
    +   p->nAlloc = n;
    +   p->mxAlloc = mx;
    ++  p->nChar = 0;
    +   p->accError = 0;
    ++  p->printfFlags = 0;
    + }
    + 
    + /*
    +@@ -23017,10 +26800,11 @@ SQLITE_PRIVATE char *sqlite3VMPrintf(sqlite3 *db, const char *zFormat, va_list a
    +   assert( db!=0 );
    +   sqlite3StrAccumInit(&acc, db, zBase, sizeof(zBase),
    +                       db->aLimit[SQLITE_LIMIT_LENGTH]);
    +-  sqlite3VXPrintf(&acc, SQLITE_PRINTF_INTERNAL, zFormat, ap);
    ++  acc.printfFlags = SQLITE_PRINTF_INTERNAL;
    ++  sqlite3VXPrintf(&acc, zFormat, ap);
    +   z = sqlite3StrAccumFinish(&acc);
    +   if( acc.accError==STRACCUM_NOMEM ){
    +-    db->mallocFailed = 1;
    ++    sqlite3OomFault(db);
    +   }
    +   return z;
    + }
    +@@ -23042,7 +26826,7 @@ SQLITE_PRIVATE char *sqlite3MPrintf(sqlite3 *db, const char *zFormat, ...){
    + ** Print into memory obtained from sqlite3_malloc().  Omit the internal
    + ** %-conversion extensions.
    + */
    +-SQLITE_API char *SQLITE_STDCALL sqlite3_vmprintf(const char *zFormat, va_list ap){
    ++SQLITE_API char *sqlite3_vmprintf(const char *zFormat, va_list ap){
    +   char *z;
    +   char zBase[SQLITE_PRINT_BUF_SIZE];
    +   StrAccum acc;
    +@@ -23057,7 +26841,7 @@ SQLITE_API char *SQLITE_STDCALL sqlite3_vmprintf(const char *zFormat, va_list ap
    +   if( sqlite3_initialize() ) return 0;
    + #endif
    +   sqlite3StrAccumInit(&acc, 0, zBase, sizeof(zBase), SQLITE_MAX_LENGTH);
    +-  sqlite3VXPrintf(&acc, 0, zFormat, ap);
    ++  sqlite3VXPrintf(&acc, zFormat, ap);
    +   z = sqlite3StrAccumFinish(&acc);
    +   return z;
    + }
    +@@ -23066,7 +26850,7 @@ SQLITE_API char *SQLITE_STDCALL sqlite3_vmprintf(const char *zFormat, va_list ap
    + ** Print into memory obtained from sqlite3_malloc()().  Omit the internal
    + ** %-conversion extensions.
    + */
    +-SQLITE_API char *SQLITE_CDECL sqlite3_mprintf(const char *zFormat, ...){
    ++SQLITE_API char *sqlite3_mprintf(const char *zFormat, ...){
    +   va_list ap;
    +   char *z;
    + #ifndef SQLITE_OMIT_AUTOINIT
    +@@ -23091,7 +26875,7 @@ SQLITE_API char *SQLITE_CDECL sqlite3_mprintf(const char *zFormat, ...){
    + **
    + ** sqlite3_vsnprintf() is the varargs version.
    + */
    +-SQLITE_API char *SQLITE_STDCALL sqlite3_vsnprintf(int n, char *zBuf, const char *zFormat, va_list ap){
    ++SQLITE_API char *sqlite3_vsnprintf(int n, char *zBuf, const char *zFormat, va_list ap){
    +   StrAccum acc;
    +   if( n<=0 ) return zBuf;
    + #ifdef SQLITE_ENABLE_API_ARMOR
    +@@ -23102,10 +26886,11 @@ SQLITE_API char *SQLITE_STDCALL sqlite3_vsnprintf(int n, char *zBuf, const char
    +   }
    + #endif
    +   sqlite3StrAccumInit(&acc, 0, zBuf, n, 0);
    +-  sqlite3VXPrintf(&acc, 0, zFormat, ap);
    +-  return sqlite3StrAccumFinish(&acc);
    ++  sqlite3VXPrintf(&acc, zFormat, ap);
    ++  zBuf[acc.nChar] = 0;
    ++  return zBuf;
    + }
    +-SQLITE_API char *SQLITE_CDECL sqlite3_snprintf(int n, char *zBuf, const char *zFormat, ...){
    ++SQLITE_API char *sqlite3_snprintf(int n, char *zBuf, const char *zFormat, ...){
    +   char *z;
    +   va_list ap;
    +   va_start(ap,zFormat);
    +@@ -23133,7 +26918,7 @@ static void renderLogMsg(int iErrCode, const char *zFormat, va_list ap){
    +   char zMsg[SQLITE_PRINT_BUF_SIZE*3];    /* Complete log message */
    + 
    +   sqlite3StrAccumInit(&acc, 0, zMsg, sizeof(zMsg), 0);
    +-  sqlite3VXPrintf(&acc, 0, zFormat, ap);
    ++  sqlite3VXPrintf(&acc, zFormat, ap);
    +   sqlite3GlobalConfig.xLog(sqlite3GlobalConfig.pLogArg, iErrCode,
    +                            sqlite3StrAccumFinish(&acc));
    + }
    +@@ -23141,7 +26926,7 @@ static void renderLogMsg(int iErrCode, const char *zFormat, va_list ap){
    + /*
    + ** Format and write a message to the log if logging is enabled.
    + */
    +-SQLITE_API void SQLITE_CDECL sqlite3_log(int iErrCode, const char *zFormat, ...){
    ++SQLITE_API void sqlite3_log(int iErrCode, const char *zFormat, ...){
    +   va_list ap;                             /* Vararg list */
    +   if( sqlite3GlobalConfig.xLog ){
    +     va_start(ap, zFormat);
    +@@ -23162,11 +26947,18 @@ SQLITE_PRIVATE void sqlite3DebugPrintf(const char *zFormat, ...){
    +   char zBuf[500];
    +   sqlite3StrAccumInit(&acc, 0, zBuf, sizeof(zBuf), 0);
    +   va_start(ap,zFormat);
    +-  sqlite3VXPrintf(&acc, 0, zFormat, ap);
    ++  sqlite3VXPrintf(&acc, zFormat, ap);
    +   va_end(ap);
    +   sqlite3StrAccumFinish(&acc);
    ++#ifdef SQLITE_OS_TRACE_PROC
    ++  {
    ++    extern void SQLITE_OS_TRACE_PROC(const char *zBuf, int nBuf);
    ++    SQLITE_OS_TRACE_PROC(zBuf, sizeof(zBuf));
    ++  }
    ++#else
    +   fprintf(stdout,"%s", zBuf);
    +   fflush(stdout);
    ++#endif
    + }
    + #endif
    + 
    +@@ -23175,10 +26967,10 @@ SQLITE_PRIVATE void sqlite3DebugPrintf(const char *zFormat, ...){
    + ** variable-argument wrapper around sqlite3VXPrintf().  The bFlags argument
    + ** can contain the bit SQLITE_PRINTF_INTERNAL enable internal formats.
    + */
    +-SQLITE_PRIVATE void sqlite3XPrintf(StrAccum *p, u32 bFlags, const char *zFormat, ...){
    ++SQLITE_PRIVATE void sqlite3XPrintf(StrAccum *p, const char *zFormat, ...){
    +   va_list ap;
    +   va_start(ap,zFormat);
    +-  sqlite3VXPrintf(p, bFlags, zFormat, ap);
    ++  sqlite3VXPrintf(p, zFormat, ap);
    +   va_end(ap);
    + }
    + 
    +@@ -23249,8 +27041,9 @@ static void sqlite3TreeViewLine(TreeView *p, const char *zFormat, ...){
    +     sqlite3StrAccumAppend(&acc, p->bLine[i] ? "|-- " : "'-- ", 4);
    +   }
    +   va_start(ap, zFormat);
    +-  sqlite3VXPrintf(&acc, 0, zFormat, ap);
    ++  sqlite3VXPrintf(&acc, zFormat, ap);
    +   va_end(ap);
    ++  assert( acc.nChar>0 );
    +   if( zBuf[acc.nChar-1]!='\n' ) sqlite3StrAccumAppend(&acc, "\n", 1);
    +   sqlite3StrAccumFinish(&acc);
    +   fprintf(stdout,"%s", zBuf);
    +@@ -23265,18 +27058,67 @@ static void sqlite3TreeViewItem(TreeView *p, const char *zLabel,u8 moreFollows){
    +   sqlite3TreeViewLine(p, "%s", zLabel);
    + }
    + 
    ++/*
    ++** Generate a human-readable description of a WITH clause.
    ++*/
    ++SQLITE_PRIVATE void sqlite3TreeViewWith(TreeView *pView, const With *pWith, u8 moreToFollow){
    ++  int i;
    ++  if( pWith==0 ) return;
    ++  if( pWith->nCte==0 ) return;
    ++  if( pWith->pOuter ){
    ++    sqlite3TreeViewLine(pView, "WITH (0x%p, pOuter=0x%p)",pWith,pWith->pOuter);
    ++  }else{
    ++    sqlite3TreeViewLine(pView, "WITH (0x%p)", pWith);
    ++  }
    ++  if( pWith->nCte>0 ){
    ++    pView = sqlite3TreeViewPush(pView, 1);
    ++    for(i=0; i<pWith->nCte; i++){
    ++      StrAccum x;
    ++      char zLine[1000];
    ++      const struct Cte *pCte = &pWith->a[i];
    ++      sqlite3StrAccumInit(&x, 0, zLine, sizeof(zLine), 0);
    ++      sqlite3XPrintf(&x, "%s", pCte->zName);
    ++      if( pCte->pCols && pCte->pCols->nExpr>0 ){
    ++        char cSep = '(';
    ++        int j;
    ++        for(j=0; j<pCte->pCols->nExpr; j++){
    ++          sqlite3XPrintf(&x, "%c%s", cSep, pCte->pCols->a[j].zName);
    ++          cSep = ',';
    ++        }
    ++        sqlite3XPrintf(&x, ")");
    ++      }
    ++      sqlite3XPrintf(&x, " AS");
    ++      sqlite3StrAccumFinish(&x);
    ++      sqlite3TreeViewItem(pView, zLine, i<pWith->nCte-1);
    ++      sqlite3TreeViewSelect(pView, pCte->pSelect, 0);
    ++      sqlite3TreeViewPop(pView);
    ++    }
    ++    sqlite3TreeViewPop(pView);
    ++  }
    ++}
    ++
    + 
    + /*
    +-** Generate a human-readable description of a the Select object.
    ++** Generate a human-readable description of a Select object.
    + */
    + SQLITE_PRIVATE void sqlite3TreeViewSelect(TreeView *pView, const Select *p, u8 moreToFollow){
    +   int n = 0;
    +   int cnt = 0;
    ++  if( p==0 ){
    ++    sqlite3TreeViewLine(pView, "nil-SELECT");
    ++    return;
    ++  } 
    +   pView = sqlite3TreeViewPush(pView, moreToFollow);
    ++  if( p->pWith ){
    ++    sqlite3TreeViewWith(pView, p->pWith, 1);
    ++    cnt = 1;
    ++    sqlite3TreeViewPush(pView, 1);
    ++  }
    +   do{
    +-    sqlite3TreeViewLine(pView, "SELECT%s%s (0x%p) selFlags=0x%x",
    ++    sqlite3TreeViewLine(pView, "SELECT%s%s (0x%p) selFlags=0x%x nSelectRow=%d",
    +       ((p->selFlags & SF_Distinct) ? " DISTINCT" : ""),
    +-      ((p->selFlags & SF_Aggregate) ? " agg_flag" : ""), p, p->selFlags
    ++      ((p->selFlags & SF_Aggregate) ? " agg_flag" : ""), p, p->selFlags,
    ++      (int)p->nSelectRow
    +     );
    +     if( cnt++ ) sqlite3TreeViewPop(pView);
    +     if( p->pPrior ){
    +@@ -23289,7 +27131,6 @@ SQLITE_PRIVATE void sqlite3TreeViewSelect(TreeView *pView, const Select *p, u8 m
    +       if( p->pHaving ) n++;
    +       if( p->pOrderBy ) n++;
    +       if( p->pLimit ) n++;
    +-      if( p->pOffset ) n++;
    +     }
    +     sqlite3TreeViewExprList(pView, p->pEList, (n--)>0, "result-set");
    +     if( p->pSrc && p->pSrc->nSrc ){
    +@@ -23301,20 +27142,20 @@ SQLITE_PRIVATE void sqlite3TreeViewSelect(TreeView *pView, const Select *p, u8 m
    +         StrAccum x;
    +         char zLine[100];
    +         sqlite3StrAccumInit(&x, 0, zLine, sizeof(zLine), 0);
    +-        sqlite3XPrintf(&x, 0, "{%d,*}", pItem->iCursor);
    ++        sqlite3XPrintf(&x, "{%d,*}", pItem->iCursor);
    +         if( pItem->zDatabase ){
    +-          sqlite3XPrintf(&x, 0, " %s.%s", pItem->zDatabase, pItem->zName);
    ++          sqlite3XPrintf(&x, " %s.%s", pItem->zDatabase, pItem->zName);
    +         }else if( pItem->zName ){
    +-          sqlite3XPrintf(&x, 0, " %s", pItem->zName);
    ++          sqlite3XPrintf(&x, " %s", pItem->zName);
    +         }
    +         if( pItem->pTab ){
    +-          sqlite3XPrintf(&x, 0, " tabname=%Q", pItem->pTab->zName);
    ++          sqlite3XPrintf(&x, " tabname=%Q", pItem->pTab->zName);
    +         }
    +         if( pItem->zAlias ){
    +-          sqlite3XPrintf(&x, 0, " (AS %s)", pItem->zAlias);
    ++          sqlite3XPrintf(&x, " (AS %s)", pItem->zAlias);
    +         }
    +         if( pItem->fg.jointype & JT_LEFT ){
    +-          sqlite3XPrintf(&x, 0, " LEFT-JOIN");
    ++          sqlite3XPrintf(&x, " LEFT-JOIN");
    +         }
    +         sqlite3StrAccumFinish(&x);
    +         sqlite3TreeViewItem(pView, zLine, i<p->pSrc->nSrc-1); 
    +@@ -23346,12 +27187,12 @@ SQLITE_PRIVATE void sqlite3TreeViewSelect(TreeView *pView, const Select *p, u8 m
    +     }
    +     if( p->pLimit ){
    +       sqlite3TreeViewItem(pView, "LIMIT", (n--)>0);
    +-      sqlite3TreeViewExpr(pView, p->pLimit, 0);
    +-      sqlite3TreeViewPop(pView);
    +-    }
    +-    if( p->pOffset ){
    +-      sqlite3TreeViewItem(pView, "OFFSET", (n--)>0);
    +-      sqlite3TreeViewExpr(pView, p->pOffset, 0);
    ++      sqlite3TreeViewExpr(pView, p->pLimit->pLeft, p->pLimit->pRight!=0);
    ++      if( p->pLimit->pRight ){
    ++        sqlite3TreeViewItem(pView, "OFFSET", (n--)>0);
    ++        sqlite3TreeViewExpr(pView, p->pLimit->pRight, 0);
    ++        sqlite3TreeViewPop(pView);
    ++      }
    +       sqlite3TreeViewPop(pView);
    +     }
    +     if( p->pPrior ){
    +@@ -23374,7 +27215,7 @@ SQLITE_PRIVATE void sqlite3TreeViewSelect(TreeView *pView, const Select *p, u8 m
    + SQLITE_PRIVATE void sqlite3TreeViewExpr(TreeView *pView, const Expr *pExpr, u8 moreToFollow){
    +   const char *zBinOp = 0;   /* Binary operator */
    +   const char *zUniOp = 0;   /* Unary operator */
    +-  char zFlgs[30];
    ++  char zFlgs[60];
    +   pView = sqlite3TreeViewPush(pView, moreToFollow);
    +   if( pExpr==0 ){
    +     sqlite3TreeViewLine(pView, "nil");
    +@@ -23382,7 +27223,12 @@ SQLITE_PRIVATE void sqlite3TreeViewExpr(TreeView *pView, const Expr *pExpr, u8 m
    +     return;
    +   }
    +   if( pExpr->flags ){
    +-    sqlite3_snprintf(sizeof(zFlgs),zFlgs,"  flags=0x%x",pExpr->flags);
    ++    if( ExprHasProperty(pExpr, EP_FromJoin) ){
    ++      sqlite3_snprintf(sizeof(zFlgs),zFlgs,"  flags=0x%x iRJT=%d",
    ++                       pExpr->flags, pExpr->iRightJoinTable);
    ++    }else{
    ++      sqlite3_snprintf(sizeof(zFlgs),zFlgs,"  flags=0x%x",pExpr->flags);
    ++    }
    +   }else{
    +     zFlgs[0] = 0;
    +   }
    +@@ -23480,6 +27326,12 @@ SQLITE_PRIVATE void sqlite3TreeViewExpr(TreeView *pView, const Expr *pExpr, u8 m
    +     case TK_ISNULL:  zUniOp = "ISNULL"; break;
    +     case TK_NOTNULL: zUniOp = "NOTNULL"; break;
    + 
    ++    case TK_SPAN: {
    ++      sqlite3TreeViewLine(pView, "SPAN %Q", pExpr->u.zToken);
    ++      sqlite3TreeViewExpr(pView, pExpr->pLeft, 0);
    ++      break;
    ++    }
    ++
    +     case TK_COLLATE: {
    +       sqlite3TreeViewLine(pView, "COLLATE %Q", pExpr->u.zToken);
    +       sqlite3TreeViewExpr(pView, pExpr->pLeft, 0);
    +@@ -23507,17 +27359,17 @@ SQLITE_PRIVATE void sqlite3TreeViewExpr(TreeView *pView, const Expr *pExpr, u8 m
    +     }
    + #ifndef SQLITE_OMIT_SUBQUERY
    +     case TK_EXISTS: {
    +-      sqlite3TreeViewLine(pView, "EXISTS-expr");
    ++      sqlite3TreeViewLine(pView, "EXISTS-expr flags=0x%x", pExpr->flags);
    +       sqlite3TreeViewSelect(pView, pExpr->x.pSelect, 0);
    +       break;
    +     }
    +     case TK_SELECT: {
    +-      sqlite3TreeViewLine(pView, "SELECT-expr");
    ++      sqlite3TreeViewLine(pView, "SELECT-expr flags=0x%x", pExpr->flags);
    +       sqlite3TreeViewSelect(pView, pExpr->x.pSelect, 0);
    +       break;
    +     }
    +     case TK_IN: {
    +-      sqlite3TreeViewLine(pView, "IN");
    ++      sqlite3TreeViewLine(pView, "IN flags=0x%x", pExpr->flags);
    +       sqlite3TreeViewExpr(pView, pExpr->pLeft, 1);
    +       if( ExprHasProperty(pExpr, EP_xIsSelect) ){
    +         sqlite3TreeViewSelect(pView, pExpr->x.pSelect, 0);
    +@@ -23580,6 +27432,26 @@ SQLITE_PRIVATE void sqlite3TreeViewExpr(TreeView *pView, const Expr *pExpr, u8 m
    +       break;
    +     }
    + #endif
    ++    case TK_MATCH: {
    ++      sqlite3TreeViewLine(pView, "MATCH {%d:%d}%s",
    ++                          pExpr->iTable, pExpr->iColumn, zFlgs);
    ++      sqlite3TreeViewExpr(pView, pExpr->pRight, 0);
    ++      break;
    ++    }
    ++    case TK_VECTOR: {
    ++      sqlite3TreeViewBareExprList(pView, pExpr->x.pList, "VECTOR");
    ++      break;
    ++    }
    ++    case TK_SELECT_COLUMN: {
    ++      sqlite3TreeViewLine(pView, "SELECT-COLUMN %d", pExpr->iColumn);
    ++      sqlite3TreeViewSelect(pView, pExpr->pLeft->x.pSelect, 0);
    ++      break;
    ++    }
    ++    case TK_IF_NULL_ROW: {
    ++      sqlite3TreeViewLine(pView, "IF-NULL-ROW %d", pExpr->iTable);
    ++      sqlite3TreeViewExpr(pView, pExpr->pLeft, 0);
    ++      break;
    ++    }
    +     default: {
    +       sqlite3TreeViewLine(pView, "op=%d", pExpr->op);
    +       break;
    +@@ -23596,32 +27468,48 @@ SQLITE_PRIVATE void sqlite3TreeViewExpr(TreeView *pView, const Expr *pExpr, u8 m
    +   sqlite3TreeViewPop(pView);
    + }
    + 
    ++
    + /*
    + ** Generate a human-readable explanation of an expression list.
    + */
    +-SQLITE_PRIVATE void sqlite3TreeViewExprList(
    ++SQLITE_PRIVATE void sqlite3TreeViewBareExprList(
    +   TreeView *pView,
    +   const ExprList *pList,
    +-  u8 moreToFollow,
    +   const char *zLabel
    + ){
    +-  int i;
    +-  pView = sqlite3TreeViewPush(pView, moreToFollow);
    +   if( zLabel==0 || zLabel[0]==0 ) zLabel = "LIST";
    +   if( pList==0 ){
    +     sqlite3TreeViewLine(pView, "%s (empty)", zLabel);
    +   }else{
    ++    int i;
    +     sqlite3TreeViewLine(pView, "%s", zLabel);
    +     for(i=0; i<pList->nExpr; i++){
    +       int j = pList->a[i].u.x.iOrderByCol;
    +-      if( j ){
    ++      char *zName = pList->a[i].zName;
    ++      if( j || zName ){
    +         sqlite3TreeViewPush(pView, 0);
    ++      }
    ++      if( zName ){
    ++        sqlite3TreeViewLine(pView, "AS %s", zName);
    ++      }
    ++      if( j ){
    +         sqlite3TreeViewLine(pView, "iOrderByCol=%d", j);
    +       }
    +       sqlite3TreeViewExpr(pView, pList->a[i].pExpr, i<pList->nExpr-1);
    +-      if( j ) sqlite3TreeViewPop(pView);
    ++      if( j || zName ){
    ++        sqlite3TreeViewPop(pView);
    ++      }
    +     }
    +   }
    ++}
    ++SQLITE_PRIVATE void sqlite3TreeViewExprList(
    ++  TreeView *pView,
    ++  const ExprList *pList,
    ++  u8 moreToFollow,
    ++  const char *zLabel
    ++){
    ++  pView = sqlite3TreeViewPush(pView, moreToFollow);
    ++  sqlite3TreeViewBareExprList(pView, pList, zLabel);
    +   sqlite3TreeViewPop(pView);
    + }
    + 
    +@@ -23661,7 +27549,7 @@ static SQLITE_WSD struct sqlite3PrngType {
    + /*
    + ** Return N random bytes.
    + */
    +-SQLITE_API void SQLITE_STDCALL sqlite3_randomness(int N, void *pBuf){
    ++SQLITE_API void sqlite3_randomness(int N, void *pBuf){
    +   unsigned char t;
    +   unsigned char *zBuf = pBuf;
    + 
    +@@ -23737,7 +27625,7 @@ SQLITE_API void SQLITE_STDCALL sqlite3_randomness(int N, void *pBuf){
    +   sqlite3_mutex_leave(mutex);
    + }
    + 
    +-#ifndef SQLITE_OMIT_BUILTIN_TEST
    ++#ifndef SQLITE_UNTESTABLE
    + /*
    + ** For testing purposes, we sometimes want to preserve the state of
    + ** PRNG and restore the PRNG to its saved state at a later time, or
    +@@ -23762,7 +27650,7 @@ SQLITE_PRIVATE void sqlite3PrngRestoreState(void){
    +     sizeof(sqlite3Prng)
    +   );
    + }
    +-#endif /* SQLITE_OMIT_BUILTIN_TEST */
    ++#endif /* SQLITE_UNTESTABLE */
    + 
    + /************** End of random.c **********************************************/
    + /************** Begin file threads.c *****************************************/
    +@@ -23831,7 +27719,7 @@ SQLITE_PRIVATE int sqlite3ThreadCreate(
    + 
    +   *ppThread = 0;
    +   p = sqlite3Malloc(sizeof(*p));
    +-  if( p==0 ) return SQLITE_NOMEM;
    ++  if( p==0 ) return SQLITE_NOMEM_BKPT;
    +   memset(p, 0, sizeof(*p));
    +   p->xTask = xTask;
    +   p->pIn = pIn;
    +@@ -23857,7 +27745,7 @@ SQLITE_PRIVATE int sqlite3ThreadJoin(SQLiteThread *p, void **ppOut){
    +   int rc;
    + 
    +   assert( ppOut!=0 );
    +-  if( NEVER(p==0) ) return SQLITE_NOMEM;
    ++  if( NEVER(p==0) ) return SQLITE_NOMEM_BKPT;
    +   if( p->done ){
    +     *ppOut = p->pOut;
    +     rc = SQLITE_OK;
    +@@ -23922,7 +27810,7 @@ SQLITE_PRIVATE int sqlite3ThreadCreate(
    +   assert( xTask!=0 );
    +   *ppThread = 0;
    +   p = sqlite3Malloc(sizeof(*p));
    +-  if( p==0 ) return SQLITE_NOMEM;
    ++  if( p==0 ) return SQLITE_NOMEM_BKPT;
    +   /* If the SQLITE_TESTCTRL_FAULT_INSTALL callback is registered to a 
    +   ** function that returns SQLITE_ERROR when passed the argument 200, that
    +   ** forces worker threads to run sequentially and deterministically 
    +@@ -23954,7 +27842,7 @@ SQLITE_PRIVATE int sqlite3ThreadJoin(SQLiteThread *p, void **ppOut){
    +   BOOL bRc;
    + 
    +   assert( ppOut!=0 );
    +-  if( NEVER(p==0) ) return SQLITE_NOMEM;
    ++  if( NEVER(p==0) ) return SQLITE_NOMEM_BKPT;
    +   if( p->xTask==0 ){
    +     /* assert( p->id==GetCurrentThreadId() ); */
    +     rc = WAIT_OBJECT_0;
    +@@ -24002,7 +27890,7 @@ SQLITE_PRIVATE int sqlite3ThreadCreate(
    +   assert( xTask!=0 );
    +   *ppThread = 0;
    +   p = sqlite3Malloc(sizeof(*p));
    +-  if( p==0 ) return SQLITE_NOMEM;
    ++  if( p==0 ) return SQLITE_NOMEM_BKPT;
    +   if( (SQLITE_PTR_TO_INT(p)/17)&1 ){
    +     p->xTask = xTask;
    +     p->pIn = pIn;
    +@@ -24018,7 +27906,7 @@ SQLITE_PRIVATE int sqlite3ThreadCreate(
    + SQLITE_PRIVATE int sqlite3ThreadJoin(SQLiteThread *p, void **ppOut){
    + 
    +   assert( ppOut!=0 );
    +-  if( NEVER(p==0) ) return SQLITE_NOMEM;
    ++  if( NEVER(p==0) ) return SQLITE_NOMEM_BKPT;
    +   if( p->xTask ){
    +     *ppOut = p->xTask(p->pIn);
    +   }else{
    +@@ -24029,7 +27917,7 @@ SQLITE_PRIVATE int sqlite3ThreadJoin(SQLiteThread *p, void **ppOut){
    + #if defined(SQLITE_TEST)
    +   {
    +     void *pTstAlloc = sqlite3Malloc(10);
    +-    if (!pTstAlloc) return SQLITE_NOMEM;
    ++    if (!pTstAlloc) return SQLITE_NOMEM_BKPT;
    +     sqlite3_free(pTstAlloc);
    +   }
    + #endif
    +@@ -24082,13 +27970,13 @@ SQLITE_PRIVATE int sqlite3ThreadJoin(SQLiteThread *p, void **ppOut){
    + /* #include <assert.h> */
    + /* #include "vdbeInt.h" */
    + 
    +-#ifndef SQLITE_AMALGAMATION
    ++#if !defined(SQLITE_AMALGAMATION) && SQLITE_BYTEORDER==0
    + /*
    + ** The following constant value is used by the SQLITE_BIGENDIAN and
    + ** SQLITE_LITTLEENDIAN macros.
    + */
    + SQLITE_PRIVATE const int sqlite3one = 1;
    +-#endif /* SQLITE_AMALGAMATION */
    ++#endif /* SQLITE_AMALGAMATION && SQLITE_BYTEORDER==0 */
    + 
    + /*
    + ** This lookup table is used to help decode the first byte of
    +@@ -24276,7 +28164,7 @@ SQLITE_PRIVATE SQLITE_NOINLINE int sqlite3VdbeMemTranslate(Mem *pMem, u8 desired
    +     rc = sqlite3VdbeMemMakeWriteable(pMem);
    +     if( rc!=SQLITE_OK ){
    +       assert( rc==SQLITE_NOMEM );
    +-      return SQLITE_NOMEM;
    ++      return SQLITE_NOMEM_BKPT;
    +     }
    +     zIn = (u8*)pMem->z;
    +     zTerm = &zIn[pMem->n&~1];
    +@@ -24318,7 +28206,7 @@ SQLITE_PRIVATE SQLITE_NOINLINE int sqlite3VdbeMemTranslate(Mem *pMem, u8 desired
    +   zTerm = &zIn[pMem->n];
    +   zOut = sqlite3DbMallocRaw(pMem->db, len);
    +   if( !zOut ){
    +-    return SQLITE_NOMEM;
    ++    return SQLITE_NOMEM_BKPT;
    +   }
    +   z = zOut;
    + 
    +@@ -24361,7 +28249,7 @@ SQLITE_PRIVATE SQLITE_NOINLINE int sqlite3VdbeMemTranslate(Mem *pMem, u8 desired
    + 
    +   c = pMem->flags;
    +   sqlite3VdbeMemRelease(pMem);
    +-  pMem->flags = MEM_Str|MEM_Term|(c&MEM_AffMask);
    ++  pMem->flags = MEM_Str|MEM_Term|(c&(MEM_AffMask|MEM_Subtype));
    +   pMem->enc = desiredEnc;
    +   pMem->z = (char*)zOut;
    +   pMem->zMalloc = pMem->z;
    +@@ -24377,7 +28265,9 @@ translate_out:
    + #endif
    +   return SQLITE_OK;
    + }
    ++#endif /* SQLITE_OMIT_UTF16 */
    + 
    ++#ifndef SQLITE_OMIT_UTF16
    + /*
    + ** This routine checks for a byte-order mark at the beginning of the 
    + ** UTF-16 string stored in *pMem. If one is present, it is removed and
    +@@ -24620,7 +28510,7 @@ SQLITE_PRIVATE void sqlite3Coverage(int x){
    + ** Return whatever integer value the test callback returns, or return
    + ** SQLITE_OK if no test callback is installed.
    + */
    +-#ifndef SQLITE_OMIT_BUILTIN_TEST
    ++#ifndef SQLITE_UNTESTABLE
    + SQLITE_PRIVATE int sqlite3FaultSim(int iTest){
    +   int (*xCallback)(int) = sqlite3GlobalConfig.xTestCallback;
    +   return xCallback ? xCallback(iTest) : SQLITE_OK;
    +@@ -24687,13 +28577,49 @@ SQLITE_PRIVATE int sqlite3Strlen30(const char *z){
    +   return 0x3fffffff & (int)strlen(z);
    + }
    + 
    ++/*
    ++** Return the declared type of a column.  Or return zDflt if the column 
    ++** has no declared type.
    ++**
    ++** The column type is an extra string stored after the zero-terminator on
    ++** the column name if and only if the COLFLAG_HASTYPE flag is set.
    ++*/
    ++SQLITE_PRIVATE char *sqlite3ColumnType(Column *pCol, char *zDflt){
    ++  if( (pCol->colFlags & COLFLAG_HASTYPE)==0 ) return zDflt;
    ++  return pCol->zName + strlen(pCol->zName) + 1;
    ++}
    ++
    ++/*
    ++** Helper function for sqlite3Error() - called rarely.  Broken out into
    ++** a separate routine to avoid unnecessary register saves on entry to
    ++** sqlite3Error().
    ++*/
    ++static SQLITE_NOINLINE void  sqlite3ErrorFinish(sqlite3 *db, int err_code){
    ++  if( db->pErr ) sqlite3ValueSetNull(db->pErr);
    ++  sqlite3SystemError(db, err_code);
    ++}
    ++
    + /*
    + ** Set the current error code to err_code and clear any prior error message.
    ++** Also set iSysErrno (by calling sqlite3System) if the err_code indicates
    ++** that would be appropriate.
    + */
    + SQLITE_PRIVATE void sqlite3Error(sqlite3 *db, int err_code){
    +   assert( db!=0 );
    +   db->errCode = err_code;
    +-  if( db->pErr ) sqlite3ValueSetNull(db->pErr);
    ++  if( err_code || db->pErr ) sqlite3ErrorFinish(db, err_code);
    ++}
    ++
    ++/*
    ++** Load the sqlite3.iSysErrno field if that is an appropriate thing
    ++** to do based on the SQLite error code in rc.
    ++*/
    ++SQLITE_PRIVATE void sqlite3SystemError(sqlite3 *db, int rc){
    ++  if( rc==SQLITE_IOERR_NOMEM ) return;
    ++  rc &= 0xff;
    ++  if( rc==SQLITE_CANTOPEN || rc==SQLITE_IOERR ){
    ++    db->iSysErrno = sqlite3OsGetLastError(db->pVfs);
    ++  }
    + }
    + 
    + /*
    +@@ -24720,6 +28646,7 @@ SQLITE_PRIVATE void sqlite3Error(sqlite3 *db, int err_code){
    + SQLITE_PRIVATE void sqlite3ErrorWithMsg(sqlite3 *db, int err_code, const char *zFormat, ...){
    +   assert( db!=0 );
    +   db->errCode = err_code;
    ++  sqlite3SystemError(db, err_code);
    +   if( zFormat==0 ){
    +     sqlite3Error(db, err_code);
    +   }else if( db->pErr || (db->pErr = sqlite3ValueNew(db))!=0 ){
    +@@ -24783,18 +28710,13 @@ SQLITE_PRIVATE void sqlite3ErrorMsg(Parse *pParse, const char *zFormat, ...){
    + ** brackets from around identifiers.  For example:  "[a-b-c]" becomes
    + ** "a-b-c".
    + */
    +-SQLITE_PRIVATE int sqlite3Dequote(char *z){
    ++SQLITE_PRIVATE void sqlite3Dequote(char *z){
    +   char quote;
    +   int i, j;
    +-  if( z==0 ) return -1;
    ++  if( z==0 ) return;
    +   quote = z[0];
    +-  switch( quote ){
    +-    case '\'':  break;
    +-    case '"':   break;
    +-    case '`':   break;                /* For MySQL compatibility */
    +-    case '[':   quote = ']';  break;  /* For MS SqlServer compatibility */
    +-    default:    return -1;
    +-  }
    ++  if( !sqlite3Isquote(quote) ) return;
    ++  if( quote=='[' ) quote = ']';
    +   for(i=1, j=0;; i++){
    +     assert( z[i] );
    +     if( z[i]==quote ){
    +@@ -24809,7 +28731,14 @@ SQLITE_PRIVATE int sqlite3Dequote(char *z){
    +     }
    +   }
    +   z[j] = 0;
    +-  return j;
    ++}
    ++
    ++/*
    ++** Generate a Token object from a string
    ++*/
    ++SQLITE_PRIVATE void sqlite3TokenInit(Token *p, char *z){
    ++  p->z = z;
    ++  p->n = sqlite3Strlen30(z);
    + }
    + 
    + /* Convenient short-hand */
    +@@ -24825,19 +28754,28 @@ SQLITE_PRIVATE int sqlite3Dequote(char *z){
    + ** case-independent fashion, using the same definition of "case
    + ** independence" that SQLite uses internally when comparing identifiers.
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_stricmp(const char *zLeft, const char *zRight){
    +-  register unsigned char *a, *b;
    ++SQLITE_API int sqlite3_stricmp(const char *zLeft, const char *zRight){
    +   if( zLeft==0 ){
    +     return zRight ? -1 : 0;
    +   }else if( zRight==0 ){
    +     return 1;
    +   }
    ++  return sqlite3StrICmp(zLeft, zRight);
    ++}
    ++SQLITE_PRIVATE int sqlite3StrICmp(const char *zLeft, const char *zRight){
    ++  unsigned char *a, *b;
    ++  int c;
    +   a = (unsigned char *)zLeft;
    +   b = (unsigned char *)zRight;
    +-  while( *a!=0 && UpperToLower[*a]==UpperToLower[*b]){ a++; b++; }
    +-  return UpperToLower[*a] - UpperToLower[*b];
    ++  for(;;){
    ++    c = (int)UpperToLower[*a] - (int)UpperToLower[*b];
    ++    if( c || *a==0 ) break;
    ++    a++;
    ++    b++;
    ++  }
    ++  return c;
    + }
    +-SQLITE_API int SQLITE_STDCALL sqlite3_strnicmp(const char *zLeft, const char *zRight, int N){
    ++SQLITE_API int sqlite3_strnicmp(const char *zLeft, const char *zRight, int N){
    +   register unsigned char *a, *b;
    +   if( zLeft==0 ){
    +     return zRight ? -1 : 0;
    +@@ -24850,6 +28788,45 @@ SQLITE_API int SQLITE_STDCALL sqlite3_strnicmp(const char *zLeft, const char *zR
    +   return N<0 ? 0 : UpperToLower[*a] - UpperToLower[*b];
    + }
    + 
    ++/*
    ++** Compute 10 to the E-th power.  Examples:  E==1 results in 10.
    ++** E==2 results in 100.  E==50 results in 1.0e50.
    ++**
    ++** This routine only works for values of E between 1 and 341.
    ++*/
    ++static LONGDOUBLE_TYPE sqlite3Pow10(int E){
    ++#if defined(_MSC_VER)
    ++  static const LONGDOUBLE_TYPE x[] = {
    ++    1.0e+001,
    ++    1.0e+002,
    ++    1.0e+004,
    ++    1.0e+008,
    ++    1.0e+016,
    ++    1.0e+032,
    ++    1.0e+064,
    ++    1.0e+128,
    ++    1.0e+256
    ++  };
    ++  LONGDOUBLE_TYPE r = 1.0;
    ++  int i;
    ++  assert( E>=0 && E<=307 );
    ++  for(i=0; E!=0; i++, E >>=1){
    ++    if( E & 1 ) r *= x[i];
    ++  }
    ++  return r;
    ++#else
    ++  LONGDOUBLE_TYPE x = 10.0;
    ++  LONGDOUBLE_TYPE r = 1.0;
    ++  while(1){
    ++    if( E & 1 ) r *= x;
    ++    E >>= 1;
    ++    if( E==0 ) break;
    ++    x *= x;
    ++  }
    ++  return r; 
    ++#endif
    ++}
    ++
    + /*
    + ** The string z[] is an text representation of a real number.
    + ** Convert this string to a double and write it into *pResult.
    +@@ -24885,7 +28862,7 @@ SQLITE_PRIVATE int sqlite3AtoF(const char *z, double *pResult, int length, u8 en
    +   int eValid = 1;  /* True exponent is either not used or is well-formed */
    +   double result;
    +   int nDigits = 0;
    +-  int nonNum = 0;
    ++  int nonNum = 0;  /* True if input contains UTF16 with high byte non-zero */
    + 
    +   assert( enc==SQLITE_UTF8 || enc==SQLITE_UTF16LE || enc==SQLITE_UTF16BE );
    +   *pResult = 0.0;   /* Default return value, in case of an error */
    +@@ -24898,7 +28875,7 @@ SQLITE_PRIVATE int sqlite3AtoF(const char *z, double *pResult, int length, u8 en
    +     assert( SQLITE_UTF16LE==2 && SQLITE_UTF16BE==3 );
    +     for(i=3-enc; i<length && z[i]==0; i+=2){}
    +     nonNum = i<length;
    +-    zEnd = z+i+enc-3;
    ++    zEnd = &z[i^1];
    +     z += (enc&1);
    +   }
    + 
    +@@ -24914,18 +28891,15 @@ SQLITE_PRIVATE int sqlite3AtoF(const char *z, double *pResult, int length, u8 en
    +     z+=incr;
    +   }
    + 
    +-  /* skip leading zeroes */
    +-  while( z<zEnd && z[0]=='0' ) z+=incr, nDigits++;
    +-
    +   /* copy max significant digits to significand */
    +   while( z<zEnd && sqlite3Isdigit(*z) && s<((LARGEST_INT64-9)/10) ){
    +     s = s*10 + (*z - '0');
    +-    z+=incr, nDigits++;
    ++    z+=incr; nDigits++;
    +   }
    + 
    +   /* skip non-significant significand digits
    +   ** (increase exponent by d to shift decimal left) */
    +-  while( z<zEnd && sqlite3Isdigit(*z) ) z+=incr, nDigits++, d++;
    ++  while( z<zEnd && sqlite3Isdigit(*z) ){ z+=incr; nDigits++; d++; }
    +   if( z>=zEnd ) goto do_atof_calc;
    + 
    +   /* if decimal point is present */
    +@@ -24933,12 +28907,13 @@ SQLITE_PRIVATE int sqlite3AtoF(const char *z, double *pResult, int length, u8 en
    +     z+=incr;
    +     /* copy digits from after decimal to significand
    +     ** (decrease exponent by d to shift decimal right) */
    +-    while( z<zEnd && sqlite3Isdigit(*z) && s<((LARGEST_INT64-9)/10) ){
    +-      s = s*10 + (*z - '0');
    +-      z+=incr, nDigits++, d--;
    ++    while( z<zEnd && sqlite3Isdigit(*z) ){
    ++      if( s<((LARGEST_INT64-9)/10) ){
    ++        s = s*10 + (*z - '0');
    ++        d--;
    ++      }
    ++      z+=incr; nDigits++;
    +     }
    +-    /* skip non-significant digits */
    +-    while( z<zEnd && sqlite3Isdigit(*z) ) z+=incr, nDigits++;
    +   }
    +   if( z>=zEnd ) goto do_atof_calc;
    + 
    +@@ -24946,7 +28921,12 @@ SQLITE_PRIVATE int sqlite3AtoF(const char *z, double *pResult, int length, u8 en
    +   if( *z=='e' || *z=='E' ){
    +     z+=incr;
    +     eValid = 0;
    +-    if( z>=zEnd ) goto do_atof_calc;
    ++
    ++    /* This branch is needed to avoid a (harmless) buffer overread.  The 
    ++    ** special comment alerts the mutation tester that the correct answer
    ++    ** is obtained even if the branch is omitted */
    ++    if( z>=zEnd ) goto do_atof_calc;              /*PREVENTS-HARMLESS-OVERREAD*/
    ++
    +     /* get sign of exponent */
    +     if( *z=='-' ){
    +       esign = -1;
    +@@ -24963,9 +28943,7 @@ SQLITE_PRIVATE int sqlite3AtoF(const char *z, double *pResult, int length, u8 en
    +   }
    + 
    +   /* skip trailing spaces */
    +-  if( nDigits && eValid ){
    +-    while( z<zEnd && sqlite3Isspace(*z) ) z+=incr;
    +-  }
    ++  while( z<zEnd && sqlite3Isspace(*z) ) z+=incr;
    + 
    + do_atof_calc:
    +   /* adjust exponent by d, and update sign */
    +@@ -24977,55 +28955,63 @@ do_atof_calc:
    +     esign = 1;
    +   }
    + 
    +-  /* if 0 significand */
    +-  if( !s ) {
    +-    /* In the IEEE 754 standard, zero is signed.
    +-    ** Add the sign if we've seen at least one digit */
    +-    result = (sign<0 && nDigits) ? -(double)0 : (double)0;
    ++  if( s==0 ) {
    ++    /* In the IEEE 754 standard, zero is signed. */
    ++    result = sign<0 ? -(double)0 : (double)0;
    +   } else {
    +-    /* attempt to reduce exponent */
    +-    if( esign>0 ){
    +-      while( s<(LARGEST_INT64/10) && e>0 ) e--,s*=10;
    +-    }else{
    +-      while( !(s%10) && e>0 ) e--,s/=10;
    ++    /* Attempt to reduce exponent.
    ++    **
    ++    ** Branches that are not required for the correct answer but which only
    ++    ** help to obtain the correct answer faster are marked with special
    ++    ** comments, as a hint to the mutation tester.
    ++    */
    ++    while( e>0 ){                                       /*OPTIMIZATION-IF-TRUE*/
    ++      if( esign>0 ){
    ++        if( s>=(LARGEST_INT64/10) ) break;             /*OPTIMIZATION-IF-FALSE*/
    ++        s *= 10;
    ++      }else{
    ++        if( s%10!=0 ) break;                           /*OPTIMIZATION-IF-FALSE*/
    ++        s /= 10;
    ++      }
    ++      e--;
    +     }
    + 
    +     /* adjust the sign of significand */
    +     s = sign<0 ? -s : s;
    + 
    +-    /* if exponent, scale significand as appropriate
    +-    ** and store in result. */
    +-    if( e ){
    +-      LONGDOUBLE_TYPE scale = 1.0;
    ++    if( e==0 ){                                         /*OPTIMIZATION-IF-TRUE*/
    ++      result = (double)s;
    ++    }else{
    +       /* attempt to handle extremely small/large numbers better */
    +-      if( e>307 && e<342 ){
    +-        while( e%308 ) { scale *= 1.0e+1; e -= 1; }
    +-        if( esign<0 ){
    +-          result = s / scale;
    +-          result /= 1.0e+308;
    +-        }else{
    +-          result = s * scale;
    +-          result *= 1.0e+308;
    +-        }
    +-      }else if( e>=342 ){
    +-        if( esign<0 ){
    +-          result = 0.0*s;
    +-        }else{
    +-          result = 1e308*1e308*s;  /* Infinity */
    ++      if( e>307 ){                                      /*OPTIMIZATION-IF-TRUE*/
    ++        if( e<342 ){                                    /*OPTIMIZATION-IF-TRUE*/
    ++          LONGDOUBLE_TYPE scale = sqlite3Pow10(e-308);
    ++          if( esign<0 ){
    ++            result = s / scale;
    ++            result /= 1.0e+308;
    ++          }else{
    ++            result = s * scale;
    ++            result *= 1.0e+308;
    ++          }
    ++        }else{ assert( e>=342 );
    ++          if( esign<0 ){
    ++            result = 0.0*s;
    ++          }else{
    ++#ifdef INFINITY
    ++            result = INFINITY*s;
    ++#else
    ++            result = 1e308*1e308*s;  /* Infinity */
    ++#endif
    ++          }
    +         }
    +       }else{
    +-        /* 1.0e+22 is the largest power of 10 than can be 
    +-        ** represented exactly. */
    +-        while( e%22 ) { scale *= 1.0e+1; e -= 1; }
    +-        while( e>0 ) { scale *= 1.0e+22; e -= 22; }
    ++        LONGDOUBLE_TYPE scale = sqlite3Pow10(e);
    +         if( esign<0 ){
    +           result = s / scale;
    +         }else{
    +           result = s * scale;
    +         }
    +       }
    +-    } else {
    +-      result = (double)s;
    +     }
    +   }
    + 
    +@@ -25033,7 +29019,7 @@ do_atof_calc:
    +   *pResult = result;
    + 
    +   /* return true if number and no extra non-whitespace chracters after */
    +-  return z>=zEnd && nDigits>0 && eValid && nonNum==0;
    ++  return z==zEnd && nDigits>0 && eValid && nonNum==0;
    + #else
    +   return !sqlite3Atoi64(z, pResult, length, enc);
    + #endif /* SQLITE_OMIT_FLOATING_POINT */
    +@@ -25074,16 +29060,12 @@ static int compare2pow63(const char *zNum, int incr){
    + ** 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.
    +-**
    +-** If zNum is exactly 9223372036854775808, return 2.  This special
    +-** case is broken out because while 9223372036854775808 cannot be a 
    +-** signed 64-bit integer, its negative -9223372036854775808 can be.
    ++** Returns:
    + **
    +-** If zNum is too big for a 64-bit integer and is not
    +-** 9223372036854775808  or if zNum contains any non-numeric text,
    +-** then return 1.
    ++**     0    Successful transformation.  Fits in a 64-bit signed integer.
    ++**     1    Excess text after the integer value
    ++**     2    Integer too large for a 64-bit signed integer or is malformed
    ++**     3    Special case of 9223372036854775808
    + **
    + ** length is the number of bytes in the string (bytes, not characters).
    + ** The string is not necessarily zero-terminated.  The encoding is
    +@@ -25095,7 +29077,8 @@ SQLITE_PRIVATE int sqlite3Atoi64(const char *zNum, i64 *pNum, int length, u8 enc
    +   int neg = 0; /* assume positive */
    +   int i;
    +   int c = 0;
    +-  int nonNum = 0;
    ++  int nonNum = 0;  /* True if input contains UTF16 with high byte non-zero */
    ++  int rc;          /* Baseline return code */
    +   const char *zStart;
    +   const char *zEnd = zNum + length;
    +   assert( enc==SQLITE_UTF8 || enc==SQLITE_UTF16LE || enc==SQLITE_UTF16BE );
    +@@ -25106,7 +29089,7 @@ SQLITE_PRIVATE int sqlite3Atoi64(const char *zNum, i64 *pNum, int length, u8 enc
    +     assert( SQLITE_UTF16LE==2 && SQLITE_UTF16BE==3 );
    +     for(i=3-enc; i<length && zNum[i]==0; i+=2){}
    +     nonNum = i<length;
    +-    zEnd = zNum+i+enc-3;
    ++    zEnd = &zNum[i^1];
    +     zNum += (enc&1);
    +   }
    +   while( zNum<zEnd && sqlite3Isspace(*zNum) ) zNum+=incr;
    +@@ -25133,29 +29116,37 @@ SQLITE_PRIVATE int sqlite3Atoi64(const char *zNum, i64 *pNum, int length, u8 enc
    +   testcase( i==18 );
    +   testcase( i==19 );
    +   testcase( i==20 );
    +-  if( (c!=0 && &zNum[i]<zEnd) || (i==0 && zStart==zNum) || i>19*incr || nonNum ){
    ++  if( &zNum[i]<zEnd              /* Extra bytes at the end */
    ++   || (i==0 && zStart==zNum)     /* No digits */
    ++   || nonNum                     /* UTF16 with high-order bytes non-zero */
    ++  ){
    ++    rc = 1;
    ++  }else{
    ++    rc = 0;
    ++  }
    ++  if( i>19*incr ){                /* Too many digits */
    +     /* zNum is empty or contains non-numeric text or is longer
    +     ** than 19 digits (thus guaranteeing that it is too large) */
    +-    return 1;
    ++    return 2;
    +   }else if( i<19*incr ){
    +     /* Less than 19 digits, so we know that it fits in 64 bits */
    +     assert( u<=LARGEST_INT64 );
    +-    return 0;
    ++    return rc;
    +   }else{
    +     /* zNum is a 19-digit numbers.  Compare it against 9223372036854775808. */
    +     c = compare2pow63(zNum, incr);
    +     if( c<0 ){
    +       /* zNum is less than 9223372036854775808 so it fits */
    +       assert( u<=LARGEST_INT64 );
    +-      return 0;
    ++      return rc;
    +     }else if( c>0 ){
    +       /* zNum is greater than 9223372036854775808 so it overflows */
    +-      return 1;
    ++      return 2;
    +     }else{
    +       /* zNum is exactly 9223372036854775808.  Fits if negative.  The
    +       ** special case 2 overflow if positive */
    +       assert( u-1==LARGEST_INT64 );
    +-      return neg ? 0 : 2;
    ++      return neg ? rc : 3;
    +     }
    +   }
    + }
    +@@ -25168,14 +29159,14 @@ SQLITE_PRIVATE int sqlite3Atoi64(const char *zNum, i64 *pNum, int length, u8 enc
    + ** 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
    ++**     1    Excess text after the integer value
    ++**     2    Integer too large for a 64-bit signed integer or is malformed
    ++**     3    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;
    +@@ -25184,7 +29175,7 @@ SQLITE_PRIVATE int sqlite3DecOrHexToI64(const char *z, i64 *pOut){
    +       u = u*16 + sqlite3HexToInt(z[k]);
    +     }
    +     memcpy(pOut, &u, 8);
    +-    return (z[k]==0 && k-i<=16) ? 0 : 1;
    ++    return (z[k]==0 && k-i<=16) ? 0 : 2;
    +   }else
    + #endif /* SQLITE_OMIT_HEX_INTEGER */
    +   {
    +@@ -25231,6 +29222,7 @@ SQLITE_PRIVATE int sqlite3GetInt32(const char *zNum, int *pValue){
    +     }
    +   }
    + #endif
    ++  if( !sqlite3Isdigit(zNum[0]) ) return 0;
    +   while( zNum[0]=='0' ) zNum++;
    +   for(i=0; i<11 && (c = zNum[i] - '0')>=0 && c<=9; i++){
    +     v = v*10 + c;
    +@@ -25422,7 +29414,8 @@ SQLITE_PRIVATE u8 sqlite3GetVarint(const unsigned char *p, u64 *v){
    +   /* a: p0<<28 | p2<<14 | p4 (unmasked) */
    +   if (!(a&0x80))
    +   {
    +-    /* we can skip these cause they were (effectively) done above in calc'ing s */
    ++    /* we can skip these cause they were (effectively) done above
    ++    ** while calculating s */
    +     /* a &= (0x7f<<28)|(0x7f<<14)|(0x7f); */
    +     /* b &= (0x7f<<14)|(0x7f); */
    +     b = b<<7;
    +@@ -25644,7 +29637,7 @@ SQLITE_PRIVATE u8 sqlite3GetVarint32(const unsigned char *p, u32 *v){
    + */
    + SQLITE_PRIVATE int sqlite3VarintLen(u64 v){
    +   int i;
    +-  for(i=1; (v >>= 7)!=0; i++){ assert( i<9 ); }
    ++  for(i=1; (v >>= 7)!=0; i++){ assert( i<10 ); }
    +   return i;
    + }
    + 
    +@@ -25657,13 +29650,11 @@ SQLITE_PRIVATE u32 sqlite3Get4byte(const u8 *p){
    +   u32 x;
    +   memcpy(&x,p,4);
    +   return x;
    +-#elif SQLITE_BYTEORDER==1234 && !defined(SQLITE_DISABLE_INTRINSIC) \
    +-    && defined(__GNUC__) && GCC_VERSION>=4003000
    ++#elif SQLITE_BYTEORDER==1234 && GCC_VERSION>=4003000
    +   u32 x;
    +   memcpy(&x,p,4);
    +   return __builtin_bswap32(x);
    +-#elif SQLITE_BYTEORDER==1234 && !defined(SQLITE_DISABLE_INTRINSIC) \
    +-    && defined(_MSC_VER) && _MSC_VER>=1300
    ++#elif SQLITE_BYTEORDER==1234 && MSVC_VERSION>=1300
    +   u32 x;
    +   memcpy(&x,p,4);
    +   return _byteswap_ulong(x);
    +@@ -25675,10 +29666,10 @@ SQLITE_PRIVATE u32 sqlite3Get4byte(const u8 *p){
    + SQLITE_PRIVATE void sqlite3Put4byte(unsigned char *p, u32 v){
    + #if SQLITE_BYTEORDER==4321
    +   memcpy(p,&v,4);
    +-#elif SQLITE_BYTEORDER==1234 && defined(__GNUC__) && GCC_VERSION>=4003000
    ++#elif SQLITE_BYTEORDER==1234 && GCC_VERSION>=4003000
    +   u32 x = __builtin_bswap32(v);
    +   memcpy(p,&x,4);
    +-#elif SQLITE_BYTEORDER==1234 && defined(_MSC_VER) && _MSC_VER>=1300
    ++#elif SQLITE_BYTEORDER==1234 && MSVC_VERSION>=1300
    +   u32 x = _byteswap_ulong(v);
    +   memcpy(p,&x,4);
    + #else
    +@@ -25718,7 +29709,7 @@ SQLITE_PRIVATE void *sqlite3HexToBlob(sqlite3 *db, const char *z, int n){
    +   char *zBlob;
    +   int i;
    + 
    +-  zBlob = (char *)sqlite3DbMallocRaw(db, n/2 + 1);
    ++  zBlob = (char *)sqlite3DbMallocRawNN(db, n/2 + 1);
    +   n--;
    +   if( zBlob ){
    +     for(i=0; i<n; i+=2){
    +@@ -25794,6 +29785,9 @@ SQLITE_PRIVATE int sqlite3SafetyCheckSickOrOk(sqlite3 *db){
    + ** overflow, leave *pA unchanged and return 1.
    + */
    + SQLITE_PRIVATE int sqlite3AddInt64(i64 *pA, i64 iB){
    ++#if GCC_VERSION>=5004000 && !defined(__INTEL_COMPILER)
    ++  return __builtin_add_overflow(*pA, iB, pA);
    ++#else
    +   i64 iA = *pA;
    +   testcase( iA==0 ); testcase( iA==1 );
    +   testcase( iB==-1 ); testcase( iB==0 );
    +@@ -25808,8 +29802,12 @@ SQLITE_PRIVATE int sqlite3AddInt64(i64 *pA, i64 iB){
    +   }
    +   *pA += iB;
    +   return 0; 
    ++#endif
    + }
    + SQLITE_PRIVATE int sqlite3SubInt64(i64 *pA, i64 iB){
    ++#if GCC_VERSION>=5004000 && !defined(__INTEL_COMPILER)
    ++  return __builtin_sub_overflow(*pA, iB, pA);
    ++#else
    +   testcase( iB==SMALLEST_INT64+1 );
    +   if( iB==SMALLEST_INT64 ){
    +     testcase( (*pA)==(-1) ); testcase( (*pA)==0 );
    +@@ -25819,38 +29817,28 @@ SQLITE_PRIVATE int sqlite3SubInt64(i64 *pA, i64 iB){
    +   }else{
    +     return sqlite3AddInt64(pA, -iB);
    +   }
    ++#endif
    + }
    +-#define TWOPOWER32 (((i64)1)<<32)
    +-#define TWOPOWER31 (((i64)1)<<31)
    + SQLITE_PRIVATE int sqlite3MulInt64(i64 *pA, i64 iB){
    ++#if GCC_VERSION>=5004000 && !defined(__INTEL_COMPILER)
    ++  return __builtin_mul_overflow(*pA, iB, pA);
    ++#else
    +   i64 iA = *pA;
    +-  i64 iA1, iA0, iB1, iB0, r;
    +-
    +-  iA1 = iA/TWOPOWER32;
    +-  iA0 = iA % TWOPOWER32;
    +-  iB1 = iB/TWOPOWER32;
    +-  iB0 = iB % TWOPOWER32;
    +-  if( iA1==0 ){
    +-    if( iB1==0 ){
    +-      *pA *= iB;
    +-      return 0;
    +-    }
    +-    r = iA0*iB1;
    +-  }else if( iB1==0 ){
    +-    r = iA1*iB0;
    +-  }else{
    +-    /* If both iA1 and iB1 are non-zero, overflow will result */
    +-    return 1;
    +-  }
    +-  testcase( r==(-TWOPOWER31)-1 );
    +-  testcase( r==(-TWOPOWER31) );
    +-  testcase( r==TWOPOWER31 );
    +-  testcase( r==TWOPOWER31-1 );
    +-  if( r<(-TWOPOWER31) || r>=TWOPOWER31 ) return 1;
    +-  r *= TWOPOWER32;
    +-  if( sqlite3AddInt64(&r, iA0*iB0) ) return 1;
    +-  *pA = r;
    ++  if( iB>0 ){
    ++    if( iA>LARGEST_INT64/iB ) return 1;
    ++    if( iA<SMALLEST_INT64/iB ) return 1;
    ++  }else if( iB<0 ){
    ++    if( iA>0 ){
    ++      if( iB<SMALLEST_INT64/iA ) return 1;
    ++    }else if( iA<0 ){
    ++      if( iB==SMALLEST_INT64 ) return 1;
    ++      if( iA==SMALLEST_INT64 ) return 1;
    ++      if( -iA>LARGEST_INT64/-iB ) return 1;
    ++    }
    ++  }
    ++  *pA = iA*iB;
    +   return 0;
    ++#endif
    + }
    + 
    + /*
    +@@ -25934,8 +29922,14 @@ SQLITE_PRIVATE LogEst sqlite3LogEst(u64 x){
    +     if( x<2 ) return 0;
    +     while( x<8 ){  y -= 10; x <<= 1; }
    +   }else{
    +-    while( x>255 ){ y += 40; x >>= 4; }
    ++#if GCC_VERSION>=5004000
    ++    int i = 60 - __builtin_clzll(x);
    ++    y += i*10;
    ++    x >>= i;
    ++#else
    ++    while( x>255 ){ y += 40; x >>= 4; }  /*OPTIMIZATION-IF-TRUE*/
    +     while( x>15 ){  y += 10; x >>= 1; }
    ++#endif
    +   }
    +   return a[x&7] + y - 10;
    + }
    +@@ -25957,20 +29951,134 @@ SQLITE_PRIVATE LogEst sqlite3LogEstFromDouble(double x){
    + }
    + #endif /* SQLITE_OMIT_VIRTUALTABLE */
    + 
    ++#if defined(SQLITE_ENABLE_STMT_SCANSTATUS) || \
    ++    defined(SQLITE_ENABLE_STAT3_OR_STAT4) || \
    ++    defined(SQLITE_EXPLAIN_ESTIMATED_ROWS)
    + /*
    + ** Convert a LogEst into an integer.
    ++**
    ++** Note that this routine is only used when one or more of various
    ++** non-standard compile-time options is enabled.
    + */
    + SQLITE_PRIVATE u64 sqlite3LogEstToInt(LogEst x){
    +   u64 n;
    +-  if( x<10 ) return 1;
    +   n = x%10;
    +   x /= 10;
    +   if( n>=5 ) n -= 2;
    +   else if( n>=1 ) n -= 1;
    +-  if( x>=3 ){
    +-    return x>60 ? (u64)LARGEST_INT64 : (n+8)<<(x-3);
    +-  }
    +-  return (n+8)>>(3-x);
    ++#if defined(SQLITE_ENABLE_STMT_SCANSTATUS) || \
    ++    defined(SQLITE_EXPLAIN_ESTIMATED_ROWS)
    ++  if( x>60 ) return (u64)LARGEST_INT64;
    ++#else
    ++  /* If only SQLITE_ENABLE_STAT3_OR_STAT4 is on, then the largest input
    ++  ** possible to this routine is 310, resulting in a maximum x of 31 */
    ++  assert( x<=60 );
    ++#endif
    ++  return x>=3 ? (n+8)<<(x-3) : (n+8)>>(3-x);
    ++}
    ++#endif /* defined SCANSTAT or STAT4 or ESTIMATED_ROWS */
    ++
    ++/*
    ++** Add a new name/number pair to a VList.  This might require that the
    ++** VList object be reallocated, so return the new VList.  If an OOM
    ++** error occurs, the original VList returned and the
    ++** db->mallocFailed flag is set.
    ++**
    ++** A VList is really just an array of integers.  To destroy a VList,
    ++** simply pass it to sqlite3DbFree().
    ++**
    ++** The first integer is the number of integers allocated for the whole
    ++** VList.  The second integer is the number of integers actually used.
    ++** Each name/number pair is encoded by subsequent groups of 3 or more
    ++** integers.
    ++**
    ++** Each name/number pair starts with two integers which are the numeric
    ++** value for the pair and the size of the name/number pair, respectively.
    ++** The text name overlays one or more following integers.  The text name
    ++** is always zero-terminated.
    ++**
    ++** Conceptually:
    ++**
    ++**    struct VList {
    ++**      int nAlloc;   // Number of allocated slots 
    ++**      int nUsed;    // Number of used slots 
    ++**      struct VListEntry {
    ++**        int iValue;    // Value for this entry
    ++**        int nSlot;     // Slots used by this entry
    ++**        // ... variable name goes here
    ++**      } a[0];
    ++**    }
    ++**
    ++** During code generation, pointers to the variable names within the
    ++** VList are taken.  When that happens, nAlloc is set to zero as an 
    ++** indication that the VList may never again be enlarged, since the
    ++** accompanying realloc() would invalidate the pointers.
    ++*/
    ++SQLITE_PRIVATE VList *sqlite3VListAdd(
    ++  sqlite3 *db,           /* The database connection used for malloc() */
    ++  VList *pIn,            /* The input VList.  Might be NULL */
    ++  const char *zName,     /* Name of symbol to add */
    ++  int nName,             /* Bytes of text in zName */
    ++  int iVal               /* Value to associate with zName */
    ++){
    ++  int nInt;              /* number of sizeof(int) objects needed for zName */
    ++  char *z;               /* Pointer to where zName will be stored */
    ++  int i;                 /* Index in pIn[] where zName is stored */
    ++
    ++  nInt = nName/4 + 3;
    ++  assert( pIn==0 || pIn[0]>=3 );  /* Verify ok to add new elements */
    ++  if( pIn==0 || pIn[1]+nInt > pIn[0] ){
    ++    /* Enlarge the allocation */
    ++    int nAlloc = (pIn ? pIn[0]*2 : 10) + nInt;
    ++    VList *pOut = sqlite3DbRealloc(db, pIn, nAlloc*sizeof(int));
    ++    if( pOut==0 ) return pIn;
    ++    if( pIn==0 ) pOut[1] = 2;
    ++    pIn = pOut;
    ++    pIn[0] = nAlloc;
    ++  }
    ++  i = pIn[1];
    ++  pIn[i] = iVal;
    ++  pIn[i+1] = nInt;
    ++  z = (char*)&pIn[i+2];
    ++  pIn[1] = i+nInt;
    ++  assert( pIn[1]<=pIn[0] );
    ++  memcpy(z, zName, nName);
    ++  z[nName] = 0;
    ++  return pIn;
    ++}
    ++
    ++/*
    ++** Return a pointer to the name of a variable in the given VList that
    ++** has the value iVal.  Or return a NULL if there is no such variable in
    ++** the list
    ++*/
    ++SQLITE_PRIVATE const char *sqlite3VListNumToName(VList *pIn, int iVal){
    ++  int i, mx;
    ++  if( pIn==0 ) return 0;
    ++  mx = pIn[1];
    ++  i = 2;
    ++  do{
    ++    if( pIn[i]==iVal ) return (char*)&pIn[i+2];
    ++    i += pIn[i+1];
    ++  }while( i<mx );
    ++  return 0;
    ++}
    ++
    ++/*
    ++** Return the number of the variable named zName, if it is in VList.
    ++** or return 0 if there is no such variable.
    ++*/
    ++SQLITE_PRIVATE int sqlite3VListNameToNum(VList *pIn, const char *zName, int nName){
    ++  int i, mx;
    ++  if( pIn==0 ) return 0;
    ++  mx = pIn[1];
    ++  i = 2;
    ++  do{
    ++    const char *z = (const char*)&pIn[i+2];
    ++    if( strncmp(z,zName,nName)==0 && z[nName]==0 ) return pIn[i];
    ++    i += pIn[i+1];
    ++  }while( i<mx );
    ++  return 0;
    + }
    + 
    + /************** End of util.c ************************************************/
    +@@ -26032,8 +30140,12 @@ SQLITE_PRIVATE void sqlite3HashClear(Hash *pH){
    + static unsigned int strHash(const char *z){
    +   unsigned int h = 0;
    +   unsigned char c;
    +-  while( (c = (unsigned char)*z++)!=0 ){
    +-    h = (h<<3) ^ h ^ sqlite3UpperToLower[c];
    ++  while( (c = (unsigned char)*z++)!=0 ){     /*OPTIMIZATION-IF-TRUE*/
    ++    /* Knuth multiplicative hashing.  (Sorting & Searching, p. 510).
    ++    ** 0x9e3779b1 is 2654435761 which is the closest prime number to
    ++    ** (2**32)*golden_ratio, where golden_ratio = (sqrt(5) - 1)/2. */
    ++    h += sqlite3UpperToLower[c];
    ++    h *= 0x9e3779b1;
    +   }
    +   return h;
    + }
    +@@ -26113,8 +30225,9 @@ static int rehash(Hash *pH, unsigned int new_size){
    + }
    + 
    + /* This function (for internal use only) locates an element in an
    +-** hash table that matches the given key.  The hash for this key is
    +-** also computed and returned in the *pH parameter.
    ++** hash table that matches the given key.  If no element is found,
    ++** a pointer to a static null element with HashElem.data==0 is returned.
    ++** If pH is not NULL, then the hash for this key is written to *pH.
    + */
    + static HashElem *findElementWithHash(
    +   const Hash *pH,     /* The pH to be searched */
    +@@ -26124,8 +30237,9 @@ static HashElem *findElementWithHash(
    +   HashElem *elem;                /* Used to loop thru the element list */
    +   int count;                     /* Number of elements left to test */
    +   unsigned int h;                /* The computed hash */
    ++  static HashElem nullElement = { 0, 0, 0, 0 };
    + 
    +-  if( pH->ht ){
    ++  if( pH->ht ){   /*OPTIMIZATION-IF-TRUE*/
    +     struct _ht *pEntry;
    +     h = strHash(pKey) % pH->htsize;
    +     pEntry = &pH->ht[h];
    +@@ -26136,7 +30250,7 @@ static HashElem *findElementWithHash(
    +     elem = pH->first;
    +     count = pH->count;
    +   }
    +-  *pHash = h;
    ++  if( pHash ) *pHash = h;
    +   while( count-- ){
    +     assert( elem!=0 );
    +     if( sqlite3StrICmp(elem->pKey,pKey)==0 ){ 
    +@@ -26144,7 +30258,7 @@ static HashElem *findElementWithHash(
    +     }
    +     elem = elem->next;
    +   }
    +-  return 0;
    ++  return &nullElement;
    + }
    + 
    + /* Remove a single entry from the hash table given a pointer to that
    +@@ -26186,13 +30300,9 @@ static void removeElementGivenHash(
    + ** found, or NULL if there is no match.
    + */
    + SQLITE_PRIVATE void *sqlite3HashFind(const Hash *pH, const char *pKey){
    +-  HashElem *elem;    /* The element that matches key */
    +-  unsigned int h;    /* A hash on key */
    +-
    +   assert( pH!=0 );
    +   assert( pKey!=0 );
    +-  elem = findElementWithHash(pH, pKey, &h);
    +-  return elem ? elem->data : 0;
    ++  return findElementWithHash(pH, pKey, 0)->data;
    + }
    + 
    + /* Insert an element into the hash table pH.  The key is pKey
    +@@ -26217,7 +30327,7 @@ SQLITE_PRIVATE void *sqlite3HashInsert(Hash *pH, const char *pKey, void *data){
    +   assert( pH!=0 );
    +   assert( pKey!=0 );
    +   elem = findElementWithHash(pH,pKey,&h);
    +-  if( elem ){
    ++  if( elem->data ){
    +     void *old_data = elem->data;
    +     if( data==0 ){
    +       removeElementGivenHash(pH,elem,h);
    +@@ -26246,175 +30356,187 @@ SQLITE_PRIVATE void *sqlite3HashInsert(Hash *pH, const char *pKey, void *data){
    + /************** End of hash.c ************************************************/
    + /************** Begin file opcodes.c *****************************************/
    + /* Automatically generated.  Do not edit */
    +-/* See the mkopcodec.awk script for details. */
    +-#if !defined(SQLITE_OMIT_EXPLAIN) || defined(VDBE_PROFILE) || defined(SQLITE_DEBUG)
    ++/* See the tool/mkopcodec.tcl script for details. */
    ++#if !defined(SQLITE_OMIT_EXPLAIN) \
    ++ || defined(VDBE_PROFILE) \
    ++ || defined(SQLITE_DEBUG)
    + #if defined(SQLITE_ENABLE_EXPLAIN_COMMENTS) || defined(SQLITE_DEBUG)
    + # define OpHelp(X) "\0" X
    + #else
    + # define OpHelp(X)
    + #endif
    + SQLITE_PRIVATE const char *sqlite3OpcodeName(int i){
    +- static const char *const azName[] = { "?",
    +-     /*   1 */ "Savepoint"        OpHelp(""),
    +-     /*   2 */ "AutoCommit"       OpHelp(""),
    +-     /*   3 */ "Transaction"      OpHelp(""),
    +-     /*   4 */ "SorterNext"       OpHelp(""),
    +-     /*   5 */ "PrevIfOpen"       OpHelp(""),
    +-     /*   6 */ "NextIfOpen"       OpHelp(""),
    +-     /*   7 */ "Prev"             OpHelp(""),
    +-     /*   8 */ "Next"             OpHelp(""),
    +-     /*   9 */ "Checkpoint"       OpHelp(""),
    +-     /*  10 */ "JournalMode"      OpHelp(""),
    +-     /*  11 */ "Vacuum"           OpHelp(""),
    +-     /*  12 */ "VFilter"          OpHelp("iplan=r[P3] zplan='P4'"),
    +-     /*  13 */ "VUpdate"          OpHelp("data=r[P3@P2]"),
    +-     /*  14 */ "Goto"             OpHelp(""),
    +-     /*  15 */ "Gosub"            OpHelp(""),
    +-     /*  16 */ "Return"           OpHelp(""),
    +-     /*  17 */ "InitCoroutine"    OpHelp(""),
    +-     /*  18 */ "EndCoroutine"     OpHelp(""),
    +-     /*  19 */ "Not"              OpHelp("r[P2]= !r[P1]"),
    +-     /*  20 */ "Yield"            OpHelp(""),
    +-     /*  21 */ "HaltIfNull"       OpHelp("if r[P3]=null halt"),
    +-     /*  22 */ "Halt"             OpHelp(""),
    +-     /*  23 */ "Integer"          OpHelp("r[P2]=P1"),
    +-     /*  24 */ "Int64"            OpHelp("r[P2]=P4"),
    +-     /*  25 */ "String"           OpHelp("r[P2]='P4' (len=P1)"),
    +-     /*  26 */ "Null"             OpHelp("r[P2..P3]=NULL"),
    +-     /*  27 */ "SoftNull"         OpHelp("r[P1]=NULL"),
    +-     /*  28 */ "Blob"             OpHelp("r[P2]=P4 (len=P1)"),
    +-     /*  29 */ "Variable"         OpHelp("r[P2]=parameter(P1,P4)"),
    +-     /*  30 */ "Move"             OpHelp("r[P2@P3]=r[P1@P3]"),
    +-     /*  31 */ "Copy"             OpHelp("r[P2@P3+1]=r[P1@P3+1]"),
    +-     /*  32 */ "SCopy"            OpHelp("r[P2]=r[P1]"),
    +-     /*  33 */ "ResultRow"        OpHelp("output=r[P1@P2]"),
    +-     /*  34 */ "CollSeq"          OpHelp(""),
    +-     /*  35 */ "Function0"        OpHelp("r[P3]=func(r[P2@P5])"),
    +-     /*  36 */ "Function"         OpHelp("r[P3]=func(r[P2@P5])"),
    +-     /*  37 */ "AddImm"           OpHelp("r[P1]=r[P1]+P2"),
    +-     /*  38 */ "MustBeInt"        OpHelp(""),
    +-     /*  39 */ "RealAffinity"     OpHelp(""),
    +-     /*  40 */ "Cast"             OpHelp("affinity(r[P1])"),
    +-     /*  41 */ "Permutation"      OpHelp(""),
    +-     /*  42 */ "Compare"          OpHelp("r[P1@P3] <-> r[P2@P3]"),
    +-     /*  43 */ "Jump"             OpHelp(""),
    +-     /*  44 */ "Once"             OpHelp(""),
    +-     /*  45 */ "If"               OpHelp(""),
    +-     /*  46 */ "IfNot"            OpHelp(""),
    +-     /*  47 */ "Column"           OpHelp("r[P3]=PX"),
    +-     /*  48 */ "Affinity"         OpHelp("affinity(r[P1@P2])"),
    +-     /*  49 */ "MakeRecord"       OpHelp("r[P3]=mkrec(r[P1@P2])"),
    +-     /*  50 */ "Count"            OpHelp("r[P2]=count()"),
    +-     /*  51 */ "ReadCookie"       OpHelp(""),
    +-     /*  52 */ "SetCookie"        OpHelp(""),
    +-     /*  53 */ "ReopenIdx"        OpHelp("root=P2 iDb=P3"),
    +-     /*  54 */ "OpenRead"         OpHelp("root=P2 iDb=P3"),
    +-     /*  55 */ "OpenWrite"        OpHelp("root=P2 iDb=P3"),
    +-     /*  56 */ "OpenAutoindex"    OpHelp("nColumn=P2"),
    +-     /*  57 */ "OpenEphemeral"    OpHelp("nColumn=P2"),
    +-     /*  58 */ "SorterOpen"       OpHelp(""),
    +-     /*  59 */ "SequenceTest"     OpHelp("if( cursor[P1].ctr++ ) pc = P2"),
    +-     /*  60 */ "OpenPseudo"       OpHelp("P3 columns in r[P2]"),
    +-     /*  61 */ "Close"            OpHelp(""),
    +-     /*  62 */ "ColumnsUsed"      OpHelp(""),
    +-     /*  63 */ "SeekLT"           OpHelp("key=r[P3@P4]"),
    +-     /*  64 */ "SeekLE"           OpHelp("key=r[P3@P4]"),
    +-     /*  65 */ "SeekGE"           OpHelp("key=r[P3@P4]"),
    +-     /*  66 */ "SeekGT"           OpHelp("key=r[P3@P4]"),
    +-     /*  67 */ "Seek"             OpHelp("intkey=r[P2]"),
    +-     /*  68 */ "NoConflict"       OpHelp("key=r[P3@P4]"),
    +-     /*  69 */ "NotFound"         OpHelp("key=r[P3@P4]"),
    +-     /*  70 */ "Found"            OpHelp("key=r[P3@P4]"),
    +-     /*  71 */ "Or"               OpHelp("r[P3]=(r[P1] || r[P2])"),
    +-     /*  72 */ "And"              OpHelp("r[P3]=(r[P1] && r[P2])"),
    +-     /*  73 */ "NotExists"        OpHelp("intkey=r[P3]"),
    +-     /*  74 */ "Sequence"         OpHelp("r[P2]=cursor[P1].ctr++"),
    +-     /*  75 */ "NewRowid"         OpHelp("r[P2]=rowid"),
    +-     /*  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"),
    +-     /*  79 */ "Eq"               OpHelp("if r[P1]==r[P3] goto P2"),
    +-     /*  80 */ "Gt"               OpHelp("if r[P1]>r[P3] goto P2"),
    +-     /*  81 */ "Le"               OpHelp("if r[P1]<=r[P3] goto P2"),
    +-     /*  82 */ "Lt"               OpHelp("if r[P1]<r[P3] goto P2"),
    +-     /*  83 */ "Ge"               OpHelp("if r[P1]>=r[P3] goto P2"),
    +-     /*  84 */ "Insert"           OpHelp("intkey=r[P3] data=r[P2]"),
    +-     /*  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]<<r[P1]"),
    +-     /*  88 */ "ShiftRight"       OpHelp("r[P3]=r[P2]>>r[P1]"),
    +-     /*  89 */ "Add"              OpHelp("r[P3]=r[P1]+r[P2]"),
    +-     /*  90 */ "Subtract"         OpHelp("r[P3]=r[P2]-r[P1]"),
    +-     /*  91 */ "Multiply"         OpHelp("r[P3]=r[P1]*r[P2]"),
    +-     /*  92 */ "Divide"           OpHelp("r[P3]=r[P2]/r[P1]"),
    +-     /*  93 */ "Remainder"        OpHelp("r[P3]=r[P2]%r[P1]"),
    +-     /*  94 */ "Concat"           OpHelp("r[P3]=r[P2]+r[P1]"),
    +-     /*  95 */ "InsertInt"        OpHelp("intkey=P3 data=r[P2]"),
    +-     /*  96 */ "BitNot"           OpHelp("r[P1]= ~r[P1]"),
    +-     /*  97 */ "String8"          OpHelp("r[P2]='P4'"),
    +-     /*  98 */ "Delete"           OpHelp(""),
    +-     /*  99 */ "ResetCount"       OpHelp(""),
    +-     /* 100 */ "SorterCompare"    OpHelp("if key(P1)!=trim(r[P3],P4) goto P2"),
    +-     /* 101 */ "SorterData"       OpHelp("r[P2]=data"),
    +-     /* 102 */ "RowKey"           OpHelp("r[P2]=key"),
    +-     /* 103 */ "RowData"          OpHelp("r[P2]=data"),
    +-     /* 104 */ "Rowid"            OpHelp("r[P2]=rowid"),
    +-     /* 105 */ "NullRow"          OpHelp(""),
    +-     /* 106 */ "Last"             OpHelp(""),
    +-     /* 107 */ "SorterSort"       OpHelp(""),
    +-     /* 108 */ "Sort"             OpHelp(""),
    +-     /* 109 */ "Rewind"           OpHelp(""),
    +-     /* 110 */ "SorterInsert"     OpHelp(""),
    +-     /* 111 */ "IdxInsert"        OpHelp("key=r[P2]"),
    +-     /* 112 */ "IdxDelete"        OpHelp("key=r[P2@P3]"),
    +-     /* 113 */ "IdxRowid"         OpHelp("r[P2]=rowid"),
    +-     /* 114 */ "IdxLE"            OpHelp("key=r[P3@P4]"),
    +-     /* 115 */ "IdxGT"            OpHelp("key=r[P3@P4]"),
    +-     /* 116 */ "IdxLT"            OpHelp("key=r[P3@P4]"),
    +-     /* 117 */ "IdxGE"            OpHelp("key=r[P3@P4]"),
    +-     /* 118 */ "Destroy"          OpHelp(""),
    +-     /* 119 */ "Clear"            OpHelp(""),
    +-     /* 120 */ "ResetSorter"      OpHelp(""),
    +-     /* 121 */ "CreateIndex"      OpHelp("r[P2]=root iDb=P1"),
    +-     /* 122 */ "CreateTable"      OpHelp("r[P2]=root iDb=P1"),
    +-     /* 123 */ "ParseSchema"      OpHelp(""),
    +-     /* 124 */ "LoadAnalysis"     OpHelp(""),
    +-     /* 125 */ "DropTable"        OpHelp(""),
    +-     /* 126 */ "DropIndex"        OpHelp(""),
    +-     /* 127 */ "DropTrigger"      OpHelp(""),
    +-     /* 128 */ "IntegrityCk"      OpHelp(""),
    +-     /* 129 */ "RowSetAdd"        OpHelp("rowset(P1)=r[P2]"),
    +-     /* 130 */ "RowSetRead"       OpHelp("r[P3]=rowset(P1)"),
    +-     /* 131 */ "RowSetTest"       OpHelp("if r[P3] in rowset(P1) goto P2"),
    +-     /* 132 */ "Program"          OpHelp(""),
    +-     /* 133 */ "Real"             OpHelp("r[P2]=P4"),
    +-     /* 134 */ "Param"            OpHelp(""),
    +-     /* 135 */ "FkCounter"        OpHelp("fkctr[P1]+=P2"),
    +-     /* 136 */ "FkIfZero"         OpHelp("if fkctr[P1]==0 goto P2"),
    +-     /* 137 */ "MemMax"           OpHelp("r[P1]=max(r[P1],r[P2])"),
    +-     /* 138 */ "IfPos"            OpHelp("if r[P1]>0 then r[P1]-=P3, goto P2"),
    +-     /* 139 */ "SetIfNotPos"      OpHelp("if r[P1]<=0 then r[P2]=P3"),
    +-     /* 140 */ "IfNotZero"        OpHelp("if r[P1]!=0 then r[P1]-=P3, goto P2"),
    +-     /* 141 */ "DecrJumpZero"     OpHelp("if (--r[P1])==0 goto P2"),
    +-     /* 142 */ "JumpZeroIncr"     OpHelp("if (r[P1]++)==0 ) goto P2"),
    +-     /* 143 */ "AggStep0"         OpHelp("accum=r[P3] step(r[P2@P5])"),
    +-     /* 144 */ "AggStep"          OpHelp("accum=r[P3] step(r[P2@P5])"),
    +-     /* 145 */ "AggFinal"         OpHelp("accum=r[P1] N=P2"),
    +-     /* 146 */ "IncrVacuum"       OpHelp(""),
    +-     /* 147 */ "Expire"           OpHelp(""),
    +-     /* 148 */ "TableLock"        OpHelp("iDb=P1 root=P2 write=P3"),
    +-     /* 149 */ "VBegin"           OpHelp(""),
    +-     /* 150 */ "VCreate"          OpHelp(""),
    +-     /* 151 */ "VDestroy"         OpHelp(""),
    +-     /* 152 */ "VOpen"            OpHelp(""),
    +-     /* 153 */ "VColumn"          OpHelp("r[P3]=vcolumn(P2)"),
    +-     /* 154 */ "VNext"            OpHelp(""),
    +-     /* 155 */ "VRename"          OpHelp(""),
    +-     /* 156 */ "Pagecount"        OpHelp(""),
    +-     /* 157 */ "MaxPgcnt"         OpHelp(""),
    +-     /* 158 */ "Init"             OpHelp("Start at P2"),
    +-     /* 159 */ "Noop"             OpHelp(""),
    +-     /* 160 */ "Explain"          OpHelp(""),
    ++ static const char *const azName[] = {
    ++    /*   0 */ "Savepoint"        OpHelp(""),
    ++    /*   1 */ "AutoCommit"       OpHelp(""),
    ++    /*   2 */ "Transaction"      OpHelp(""),
    ++    /*   3 */ "SorterNext"       OpHelp(""),
    ++    /*   4 */ "PrevIfOpen"       OpHelp(""),
    ++    /*   5 */ "NextIfOpen"       OpHelp(""),
    ++    /*   6 */ "Prev"             OpHelp(""),
    ++    /*   7 */ "Next"             OpHelp(""),
    ++    /*   8 */ "Checkpoint"       OpHelp(""),
    ++    /*   9 */ "JournalMode"      OpHelp(""),
    ++    /*  10 */ "Vacuum"           OpHelp(""),
    ++    /*  11 */ "VFilter"          OpHelp("iplan=r[P3] zplan='P4'"),
    ++    /*  12 */ "VUpdate"          OpHelp("data=r[P3@P2]"),
    ++    /*  13 */ "Goto"             OpHelp(""),
    ++    /*  14 */ "Gosub"            OpHelp(""),
    ++    /*  15 */ "InitCoroutine"    OpHelp(""),
    ++    /*  16 */ "Yield"            OpHelp(""),
    ++    /*  17 */ "MustBeInt"        OpHelp(""),
    ++    /*  18 */ "Jump"             OpHelp(""),
    ++    /*  19 */ "Not"              OpHelp("r[P2]= !r[P1]"),
    ++    /*  20 */ "Once"             OpHelp(""),
    ++    /*  21 */ "If"               OpHelp(""),
    ++    /*  22 */ "IfNot"            OpHelp(""),
    ++    /*  23 */ "IfNullRow"        OpHelp("if P1.nullRow then r[P3]=NULL, goto P2"),
    ++    /*  24 */ "SeekLT"           OpHelp("key=r[P3@P4]"),
    ++    /*  25 */ "SeekLE"           OpHelp("key=r[P3@P4]"),
    ++    /*  26 */ "SeekGE"           OpHelp("key=r[P3@P4]"),
    ++    /*  27 */ "SeekGT"           OpHelp("key=r[P3@P4]"),
    ++    /*  28 */ "NoConflict"       OpHelp("key=r[P3@P4]"),
    ++    /*  29 */ "NotFound"         OpHelp("key=r[P3@P4]"),
    ++    /*  30 */ "Found"            OpHelp("key=r[P3@P4]"),
    ++    /*  31 */ "SeekRowid"        OpHelp("intkey=r[P3]"),
    ++    /*  32 */ "NotExists"        OpHelp("intkey=r[P3]"),
    ++    /*  33 */ "Last"             OpHelp(""),
    ++    /*  34 */ "IfSmaller"        OpHelp(""),
    ++    /*  35 */ "SorterSort"       OpHelp(""),
    ++    /*  36 */ "Sort"             OpHelp(""),
    ++    /*  37 */ "Rewind"           OpHelp(""),
    ++    /*  38 */ "IdxLE"            OpHelp("key=r[P3@P4]"),
    ++    /*  39 */ "IdxGT"            OpHelp("key=r[P3@P4]"),
    ++    /*  40 */ "IdxLT"            OpHelp("key=r[P3@P4]"),
    ++    /*  41 */ "IdxGE"            OpHelp("key=r[P3@P4]"),
    ++    /*  42 */ "RowSetRead"       OpHelp("r[P3]=rowset(P1)"),
    ++    /*  43 */ "Or"               OpHelp("r[P3]=(r[P1] || r[P2])"),
    ++    /*  44 */ "And"              OpHelp("r[P3]=(r[P1] && r[P2])"),
    ++    /*  45 */ "RowSetTest"       OpHelp("if r[P3] in rowset(P1) goto P2"),
    ++    /*  46 */ "Program"          OpHelp(""),
    ++    /*  47 */ "FkIfZero"         OpHelp("if fkctr[P1]==0 goto P2"),
    ++    /*  48 */ "IfPos"            OpHelp("if r[P1]>0 then r[P1]-=P3, goto P2"),
    ++    /*  49 */ "IfNotZero"        OpHelp("if r[P1]!=0 then r[P1]--, goto P2"),
    ++    /*  50 */ "IsNull"           OpHelp("if r[P1]==NULL goto P2"),
    ++    /*  51 */ "NotNull"          OpHelp("if r[P1]!=NULL goto P2"),
    ++    /*  52 */ "Ne"               OpHelp("IF r[P3]!=r[P1]"),
    ++    /*  53 */ "Eq"               OpHelp("IF r[P3]==r[P1]"),
    ++    /*  54 */ "Gt"               OpHelp("IF r[P3]>r[P1]"),
    ++    /*  55 */ "Le"               OpHelp("IF r[P3]<=r[P1]"),
    ++    /*  56 */ "Lt"               OpHelp("IF r[P3]<r[P1]"),
    ++    /*  57 */ "Ge"               OpHelp("IF r[P3]>=r[P1]"),
    ++    /*  58 */ "ElseNotEq"        OpHelp(""),
    ++    /*  59 */ "DecrJumpZero"     OpHelp("if (--r[P1])==0 goto P2"),
    ++    /*  60 */ "IncrVacuum"       OpHelp(""),
    ++    /*  61 */ "VNext"            OpHelp(""),
    ++    /*  62 */ "Init"             OpHelp("Start at P2"),
    ++    /*  63 */ "Return"           OpHelp(""),
    ++    /*  64 */ "EndCoroutine"     OpHelp(""),
    ++    /*  65 */ "HaltIfNull"       OpHelp("if r[P3]=null halt"),
    ++    /*  66 */ "Halt"             OpHelp(""),
    ++    /*  67 */ "Integer"          OpHelp("r[P2]=P1"),
    ++    /*  68 */ "Int64"            OpHelp("r[P2]=P4"),
    ++    /*  69 */ "String"           OpHelp("r[P2]='P4' (len=P1)"),
    ++    /*  70 */ "Null"             OpHelp("r[P2..P3]=NULL"),
    ++    /*  71 */ "SoftNull"         OpHelp("r[P1]=NULL"),
    ++    /*  72 */ "Blob"             OpHelp("r[P2]=P4 (len=P1)"),
    ++    /*  73 */ "Variable"         OpHelp("r[P2]=parameter(P1,P4)"),
    ++    /*  74 */ "Move"             OpHelp("r[P2@P3]=r[P1@P3]"),
    ++    /*  75 */ "Copy"             OpHelp("r[P2@P3+1]=r[P1@P3+1]"),
    ++    /*  76 */ "SCopy"            OpHelp("r[P2]=r[P1]"),
    ++    /*  77 */ "IntCopy"          OpHelp("r[P2]=r[P1]"),
    ++    /*  78 */ "ResultRow"        OpHelp("output=r[P1@P2]"),
    ++    /*  79 */ "CollSeq"          OpHelp(""),
    ++    /*  80 */ "AddImm"           OpHelp("r[P1]=r[P1]+P2"),
    ++    /*  81 */ "RealAffinity"     OpHelp(""),
    ++    /*  82 */ "Cast"             OpHelp("affinity(r[P1])"),
    ++    /*  83 */ "Permutation"      OpHelp(""),
    ++    /*  84 */ "BitAnd"           OpHelp("r[P3]=r[P1]&r[P2]"),
    ++    /*  85 */ "BitOr"            OpHelp("r[P3]=r[P1]|r[P2]"),
    ++    /*  86 */ "ShiftLeft"        OpHelp("r[P3]=r[P2]<<r[P1]"),
    ++    /*  87 */ "ShiftRight"       OpHelp("r[P3]=r[P2]>>r[P1]"),
    ++    /*  88 */ "Add"              OpHelp("r[P3]=r[P1]+r[P2]"),
    ++    /*  89 */ "Subtract"         OpHelp("r[P3]=r[P2]-r[P1]"),
    ++    /*  90 */ "Multiply"         OpHelp("r[P3]=r[P1]*r[P2]"),
    ++    /*  91 */ "Divide"           OpHelp("r[P3]=r[P2]/r[P1]"),
    ++    /*  92 */ "Remainder"        OpHelp("r[P3]=r[P2]%r[P1]"),
    ++    /*  93 */ "Concat"           OpHelp("r[P3]=r[P2]+r[P1]"),
    ++    /*  94 */ "Compare"          OpHelp("r[P1@P3] <-> r[P2@P3]"),
    ++    /*  95 */ "BitNot"           OpHelp("r[P1]= ~r[P1]"),
    ++    /*  96 */ "Offset"           OpHelp("r[P3] = sqlite_offset(P1)"),
    ++    /*  97 */ "String8"          OpHelp("r[P2]='P4'"),
    ++    /*  98 */ "Column"           OpHelp("r[P3]=PX"),
    ++    /*  99 */ "Affinity"         OpHelp("affinity(r[P1@P2])"),
    ++    /* 100 */ "MakeRecord"       OpHelp("r[P3]=mkrec(r[P1@P2])"),
    ++    /* 101 */ "Count"            OpHelp("r[P2]=count()"),
    ++    /* 102 */ "ReadCookie"       OpHelp(""),
    ++    /* 103 */ "SetCookie"        OpHelp(""),
    ++    /* 104 */ "ReopenIdx"        OpHelp("root=P2 iDb=P3"),
    ++    /* 105 */ "OpenRead"         OpHelp("root=P2 iDb=P3"),
    ++    /* 106 */ "OpenWrite"        OpHelp("root=P2 iDb=P3"),
    ++    /* 107 */ "OpenDup"          OpHelp(""),
    ++    /* 108 */ "OpenAutoindex"    OpHelp("nColumn=P2"),
    ++    /* 109 */ "OpenEphemeral"    OpHelp("nColumn=P2"),
    ++    /* 110 */ "SorterOpen"       OpHelp(""),
    ++    /* 111 */ "SequenceTest"     OpHelp("if( cursor[P1].ctr++ ) pc = P2"),
    ++    /* 112 */ "OpenPseudo"       OpHelp("P3 columns in r[P2]"),
    ++    /* 113 */ "Close"            OpHelp(""),
    ++    /* 114 */ "ColumnsUsed"      OpHelp(""),
    ++    /* 115 */ "Sequence"         OpHelp("r[P2]=cursor[P1].ctr++"),
    ++    /* 116 */ "NewRowid"         OpHelp("r[P2]=rowid"),
    ++    /* 117 */ "Insert"           OpHelp("intkey=r[P3] data=r[P2]"),
    ++    /* 118 */ "InsertInt"        OpHelp("intkey=P3 data=r[P2]"),
    ++    /* 119 */ "Delete"           OpHelp(""),
    ++    /* 120 */ "ResetCount"       OpHelp(""),
    ++    /* 121 */ "SorterCompare"    OpHelp("if key(P1)!=trim(r[P3],P4) goto P2"),
    ++    /* 122 */ "SorterData"       OpHelp("r[P2]=data"),
    ++    /* 123 */ "RowData"          OpHelp("r[P2]=data"),
    ++    /* 124 */ "Rowid"            OpHelp("r[P2]=rowid"),
    ++    /* 125 */ "NullRow"          OpHelp(""),
    ++    /* 126 */ "SeekEnd"          OpHelp(""),
    ++    /* 127 */ "SorterInsert"     OpHelp("key=r[P2]"),
    ++    /* 128 */ "IdxInsert"        OpHelp("key=r[P2]"),
    ++    /* 129 */ "IdxDelete"        OpHelp("key=r[P2@P3]"),
    ++    /* 130 */ "DeferredSeek"     OpHelp("Move P3 to P1.rowid if needed"),
    ++    /* 131 */ "IdxRowid"         OpHelp("r[P2]=rowid"),
    ++    /* 132 */ "Real"             OpHelp("r[P2]=P4"),
    ++    /* 133 */ "Destroy"          OpHelp(""),
    ++    /* 134 */ "Clear"            OpHelp(""),
    ++    /* 135 */ "ResetSorter"      OpHelp(""),
    ++    /* 136 */ "CreateBtree"      OpHelp("r[P2]=root iDb=P1 flags=P3"),
    ++    /* 137 */ "SqlExec"          OpHelp(""),
    ++    /* 138 */ "ParseSchema"      OpHelp(""),
    ++    /* 139 */ "LoadAnalysis"     OpHelp(""),
    ++    /* 140 */ "DropTable"        OpHelp(""),
    ++    /* 141 */ "DropIndex"        OpHelp(""),
    ++    /* 142 */ "DropTrigger"      OpHelp(""),
    ++    /* 143 */ "IntegrityCk"      OpHelp(""),
    ++    /* 144 */ "RowSetAdd"        OpHelp("rowset(P1)=r[P2]"),
    ++    /* 145 */ "Param"            OpHelp(""),
    ++    /* 146 */ "FkCounter"        OpHelp("fkctr[P1]+=P2"),
    ++    /* 147 */ "MemMax"           OpHelp("r[P1]=max(r[P1],r[P2])"),
    ++    /* 148 */ "OffsetLimit"      OpHelp("if r[P1]>0 then r[P2]=r[P1]+max(0,r[P3]) else r[P2]=(-1)"),
    ++    /* 149 */ "AggStep0"         OpHelp("accum=r[P3] step(r[P2@P5])"),
    ++    /* 150 */ "AggStep"          OpHelp("accum=r[P3] step(r[P2@P5])"),
    ++    /* 151 */ "AggFinal"         OpHelp("accum=r[P1] N=P2"),
    ++    /* 152 */ "Expire"           OpHelp(""),
    ++    /* 153 */ "TableLock"        OpHelp("iDb=P1 root=P2 write=P3"),
    ++    /* 154 */ "VBegin"           OpHelp(""),
    ++    /* 155 */ "VCreate"          OpHelp(""),
    ++    /* 156 */ "VDestroy"         OpHelp(""),
    ++    /* 157 */ "VOpen"            OpHelp(""),
    ++    /* 158 */ "VColumn"          OpHelp("r[P3]=vcolumn(P2)"),
    ++    /* 159 */ "VRename"          OpHelp(""),
    ++    /* 160 */ "Pagecount"        OpHelp(""),
    ++    /* 161 */ "MaxPgcnt"         OpHelp(""),
    ++    /* 162 */ "PureFunc0"        OpHelp(""),
    ++    /* 163 */ "Function0"        OpHelp("r[P3]=func(r[P2@P5])"),
    ++    /* 164 */ "PureFunc"         OpHelp(""),
    ++    /* 165 */ "Function"         OpHelp("r[P3]=func(r[P2@P5])"),
    ++    /* 166 */ "Trace"            OpHelp(""),
    ++    /* 167 */ "CursorHint"       OpHelp(""),
    ++    /* 168 */ "Noop"             OpHelp(""),
    ++    /* 169 */ "Explain"          OpHelp(""),
    +   };
    +   return azName[i];
    + }
    +@@ -26495,12 +30617,26 @@ SQLITE_PRIVATE const char *sqlite3OpcodeName(int i){
    + #  endif
    + #endif
    + 
    ++/* Use pread() and pwrite() if they are available */
    ++#if defined(__APPLE__)
    ++# define HAVE_PREAD 1
    ++# define HAVE_PWRITE 1
    ++#endif
    ++#if defined(HAVE_PREAD64) && defined(HAVE_PWRITE64)
    ++# undef USE_PREAD
    ++# define USE_PREAD64 1
    ++#elif defined(HAVE_PREAD) && defined(HAVE_PWRITE)
    ++# undef USE_PREAD64
    ++# define USE_PREAD 1
    ++#endif
    ++
    + /*
    + ** standard include files.
    + */
    + #include <sys/types.h>
    + #include <sys/stat.h>
    + #include <fcntl.h>
    ++#include <sys/ioctl.h>
    + #include <unistd.h>
    + /* #include <time.h> */
    + #include <sys/time.h>
    +@@ -26510,7 +30646,7 @@ SQLITE_PRIVATE const char *sqlite3OpcodeName(int i){
    + #endif
    + 
    + #if SQLITE_ENABLE_LOCKING_STYLE
    +-# include <sys/ioctl.h>
    ++/* # include <sys/ioctl.h> */
    + # include <sys/file.h>
    + # include <sys/param.h>
    + #endif /* SQLITE_ENABLE_LOCKING_STYLE */
    +@@ -26573,6 +30709,11 @@ SQLITE_PRIVATE const char *sqlite3OpcodeName(int i){
    + */
    + #define MAX_PATHNAME 512
    + 
    ++/*
    ++** Maximum supported symbolic links
    ++*/
    ++#define SQLITE_MAX_SYMLINKS 100
    ++
    + /* Always cast the getpid() return type for compatibility with
    + ** kernel modules in VxWorks. */
    + #define osGetpid(X) (pid_t)getpid()
    +@@ -26615,7 +30756,7 @@ struct unixFile {
    +   unsigned short int ctrlFlags;       /* Behavioral bits.  UNIXFILE_* flags */
    +   int lastErrno;                      /* The unix errno from last I/O error */
    +   void *lockingContext;               /* Locking style specific state */
    +-  UnixUnusedFd *pUnused;              /* Pre-allocated UnixUnusedFd */
    ++  UnixUnusedFd *pPreallocatedUnused;  /* Pre-allocated UnixUnusedFd */
    +   const char *zPath;                  /* Name of the file */
    +   unixShm *pShm;                      /* Shared memory segment information */
    +   int szChunk;                        /* Configured by FCNTL_CHUNK_SIZE */
    +@@ -26626,10 +30767,8 @@ struct unixFile {
    +   sqlite3_int64 mmapSizeMax;          /* Configured FCNTL_MMAP_SIZE value */
    +   void *pMapRegion;                   /* Memory mapped region */
    + #endif
    +-#ifdef __QNXNTO__
    +   int sectorSize;                     /* Device sector size */
    +   int deviceCharacteristics;          /* Precomputed device characteristics */
    +-#endif
    + #if SQLITE_ENABLE_LOCKING_STYLE
    +   int openFlags;                      /* The flags specified at open() */
    + #endif
    +@@ -26682,8 +30821,6 @@ static pid_t randomnessPid = 0;
    + #define UNIXFILE_DELETE      0x20     /* Delete on close */
    + #define UNIXFILE_URI         0x40     /* Filename might have query parameters */
    + #define UNIXFILE_NOLOCK      0x80     /* Do no file locking */
    +-#define UNIXFILE_WARNED    0x0100     /* verifyDbFile() warnings issued */
    +-#define UNIXFILE_BLOCK     0x0200     /* Next SHM lock might block */
    + 
    + /*
    + ** Include code that is common to all os_*.c files
    +@@ -26727,8 +30864,8 @@ static pid_t randomnessPid = 0;
    + */
    + #ifdef SQLITE_PERFORMANCE_TRACE
    + 
    +-/* 
    +-** hwtime.h contains inline assembler code for implementing 
    ++/*
    ++** hwtime.h contains inline assembler code for implementing
    + ** high-performance timing routines.
    + */
    + /************** Include hwtime.h in the middle of os_common.h ****************/
    +@@ -26748,8 +30885,8 @@ static pid_t randomnessPid = 0;
    + ** This file contains inline asm code for retrieving "high-performance"
    + ** counters for x86 class CPUs.
    + */
    +-#ifndef _HWTIME_H_
    +-#define _HWTIME_H_
    ++#ifndef SQLITE_HWTIME_H
    ++#define SQLITE_HWTIME_H
    + 
    + /*
    + ** The following routine only works on pentium-class (or newer) processors.
    +@@ -26817,7 +30954,7 @@ SQLITE_PRIVATE   sqlite_uint64 sqlite3Hwtime(void){ return ((sqlite_uint64)0); }
    + 
    + #endif
    + 
    +-#endif /* !defined(_HWTIME_H_) */
    ++#endif /* !defined(SQLITE_HWTIME_H) */
    + 
    + /************** End of hwtime.h **********************************************/
    + /************** Continuing where we left off in os_common.h ******************/
    +@@ -26838,14 +30975,14 @@ static sqlite_uint64 g_elapsed;
    + ** 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;
    ++#if defined(SQLITE_TEST)
    ++SQLITE_API extern int sqlite3_io_error_hit;
    ++SQLITE_API extern int sqlite3_io_error_hardhit;
    ++SQLITE_API extern int sqlite3_io_error_pending;
    ++SQLITE_API extern int sqlite3_io_error_persist;
    ++SQLITE_API extern int sqlite3_io_error_benign;
    ++SQLITE_API extern int sqlite3_diskfull_pending;
    ++SQLITE_API extern int sqlite3_diskfull;
    + #define SimulateIOErrorBenign(X) sqlite3_io_error_benign=(X)
    + #define SimulateIOError(CODE)  \
    +   if( (sqlite3_io_error_persist && sqlite3_io_error_hit) \
    +@@ -26871,17 +31008,17 @@ static void local_ioerr(){
    + #define SimulateIOErrorBenign(X)
    + #define SimulateIOError(A)
    + #define SimulateDiskfullError(A)
    +-#endif
    ++#endif /* defined(SQLITE_TEST) */
    + 
    + /*
    + ** When testing, keep a count of the number of open files.
    + */
    +-#ifdef SQLITE_TEST
    +-SQLITE_API int sqlite3_open_file_count = 0;
    ++#if defined(SQLITE_TEST)
    ++SQLITE_API extern int sqlite3_open_file_count;
    + #define OpenCounter(X)  sqlite3_open_file_count+=(X)
    + #else
    + #define OpenCounter(X)
    +-#endif
    ++#endif /* defined(SQLITE_TEST) */
    + 
    + #endif /* !defined(_OS_COMMON_H_) */
    + 
    +@@ -26934,6 +31071,20 @@ SQLITE_API int sqlite3_open_file_count = 0;
    + # define lseek lseek64
    + #endif
    + 
    ++#ifdef __linux__
    ++/*
    ++** Linux-specific IOCTL magic numbers used for controlling F2FS
    ++*/
    ++#define F2FS_IOCTL_MAGIC        0xf5
    ++#define F2FS_IOC_START_ATOMIC_WRITE     _IO(F2FS_IOCTL_MAGIC, 1)
    ++#define F2FS_IOC_COMMIT_ATOMIC_WRITE    _IO(F2FS_IOCTL_MAGIC, 2)
    ++#define F2FS_IOC_START_VOLATILE_WRITE   _IO(F2FS_IOCTL_MAGIC, 3)
    ++#define F2FS_IOC_ABORT_VOLATILE_WRITE   _IO(F2FS_IOCTL_MAGIC, 5)
    ++#define F2FS_IOC_GET_FEATURES           _IOR(F2FS_IOCTL_MAGIC, 12, u32)
    ++#define F2FS_FEATURE_ATOMIC_WRITE 0x0004
    ++#endif /* __linux__ */
    ++
    ++
    + /*
    + ** Different Unix systems declare open() in different ways.  Same use
    + ** open(const char*,int,mode_t).  Others use open(const char*,int,...).
    +@@ -26946,19 +31097,6 @@ static int posixOpen(const char *zFile, int flags, int mode){
    +   return open(zFile, flags, mode);
    + }
    + 
    +-/*
    +-** On some systems, calls to fchown() will trigger a message in a security
    +-** log if they come from non-root processes.  So avoid calling fchown() if
    +-** 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);
    +@@ -27024,7 +31162,7 @@ static struct unix_syscall {
    + #else
    +   { "pread64",      (sqlite3_syscall_ptr)0,          0  },
    + #endif
    +-#define osPread64   ((ssize_t(*)(int,void*,size_t,off_t))aSyscall[10].pCurrent)
    ++#define osPread64 ((ssize_t(*)(int,void*,size_t,off64_t))aSyscall[10].pCurrent)
    + 
    +   { "write",        (sqlite3_syscall_ptr)write,      0  },
    + #define osWrite     ((ssize_t(*)(int,const void*,size_t))aSyscall[11].pCurrent)
    +@@ -27042,10 +31180,10 @@ static struct unix_syscall {
    + #else
    +   { "pwrite64",     (sqlite3_syscall_ptr)0,          0  },
    + #endif
    +-#define osPwrite64  ((ssize_t(*)(int,const void*,size_t,off_t))\
    ++#define osPwrite64  ((ssize_t(*)(int,const void*,size_t,off64_t))\
    +                     aSyscall[13].pCurrent)
    + 
    +-  { "fchmod",       (sqlite3_syscall_ptr)fchmod,     0  },
    ++  { "fchmod",       (sqlite3_syscall_ptr)fchmod,          0  },
    + #define osFchmod    ((int(*)(int,mode_t))aSyscall[14].pCurrent)
    + 
    + #if defined(HAVE_POSIX_FALLOCATE) && HAVE_POSIX_FALLOCATE
    +@@ -27067,29 +31205,81 @@ static struct unix_syscall {
    +   { "rmdir",        (sqlite3_syscall_ptr)rmdir,           0 },
    + #define osRmdir     ((int(*)(const char*))aSyscall[19].pCurrent)
    + 
    +-  { "fchown",       (sqlite3_syscall_ptr)posixFchown,     0 },
    ++#if defined(HAVE_FCHOWN)
    ++  { "fchown",       (sqlite3_syscall_ptr)fchown,          0 },
    ++#else
    ++  { "fchown",       (sqlite3_syscall_ptr)0,               0 },
    ++#endif
    + #define osFchown    ((int(*)(int,uid_t,gid_t))aSyscall[20].pCurrent)
    + 
    ++  { "geteuid",      (sqlite3_syscall_ptr)geteuid,         0 },
    ++#define osGeteuid   ((uid_t(*)(void))aSyscall[21].pCurrent)
    ++
    + #if !defined(SQLITE_OMIT_WAL) || SQLITE_MAX_MMAP_SIZE>0
    +-  { "mmap",       (sqlite3_syscall_ptr)mmap,     0 },
    +-#define osMmap ((void*(*)(void*,size_t,int,int,int,off_t))aSyscall[21].pCurrent)
    ++  { "mmap",         (sqlite3_syscall_ptr)mmap,            0 },
    ++#else
    ++  { "mmap",         (sqlite3_syscall_ptr)0,               0 },
    ++#endif
    ++#define osMmap ((void*(*)(void*,size_t,int,int,int,off_t))aSyscall[22].pCurrent)
    + 
    ++#if !defined(SQLITE_OMIT_WAL) || SQLITE_MAX_MMAP_SIZE>0
    +   { "munmap",       (sqlite3_syscall_ptr)munmap,          0 },
    +-#define osMunmap ((void*(*)(void*,size_t))aSyscall[22].pCurrent)
    ++#else
    ++  { "munmap",       (sqlite3_syscall_ptr)0,               0 },
    ++#endif
    ++#define osMunmap ((int(*)(void*,size_t))aSyscall[23].pCurrent)
    + 
    +-#if HAVE_MREMAP
    ++#if HAVE_MREMAP && (!defined(SQLITE_OMIT_WAL) || SQLITE_MAX_MMAP_SIZE>0)
    +   { "mremap",       (sqlite3_syscall_ptr)mremap,          0 },
    + #else
    +   { "mremap",       (sqlite3_syscall_ptr)0,               0 },
    + #endif
    +-#define osMremap ((void*(*)(void*,size_t,size_t,int,...))aSyscall[23].pCurrent)
    ++#define osMremap ((void*(*)(void*,size_t,size_t,int,...))aSyscall[24].pCurrent)
    ++
    ++#if !defined(SQLITE_OMIT_WAL) || SQLITE_MAX_MMAP_SIZE>0
    +   { "getpagesize",  (sqlite3_syscall_ptr)unixGetpagesize, 0 },
    +-#define osGetpagesize ((int(*)(void))aSyscall[24].pCurrent)
    ++#else
    ++  { "getpagesize",  (sqlite3_syscall_ptr)0,               0 },
    ++#endif
    ++#define osGetpagesize ((int(*)(void))aSyscall[25].pCurrent)
    ++
    ++#if defined(HAVE_READLINK)
    ++  { "readlink",     (sqlite3_syscall_ptr)readlink,        0 },
    ++#else
    ++  { "readlink",     (sqlite3_syscall_ptr)0,               0 },
    ++#endif
    ++#define osReadlink ((ssize_t(*)(const char*,char*,size_t))aSyscall[26].pCurrent)
    + 
    ++#if defined(HAVE_LSTAT)
    ++  { "lstat",         (sqlite3_syscall_ptr)lstat,          0 },
    ++#else
    ++  { "lstat",         (sqlite3_syscall_ptr)0,              0 },
    + #endif
    ++#define osLstat      ((int(*)(const char*,struct stat*))aSyscall[27].pCurrent)
    ++
    ++#if defined(__linux__) && defined(SQLITE_ENABLE_BATCH_ATOMIC_WRITE)
    ++  { "ioctl",         (sqlite3_syscall_ptr)ioctl,          0 },
    ++#else
    ++  { "ioctl",         (sqlite3_syscall_ptr)0,              0 },
    ++#endif
    ++#define osIoctl ((int(*)(int,int,...))aSyscall[28].pCurrent)
    + 
    + }; /* End of the overrideable system calls */
    + 
    ++
    ++/*
    ++** On some systems, calls to fchown() will trigger a message in a security
    ++** log if they come from non-root processes.  So avoid calling fchown() if
    ++** we are not running as root.
    ++*/
    ++static int robustFchown(int fd, uid_t uid, gid_t gid){
    ++#if defined(HAVE_FCHOWN)
    ++  return osGeteuid() ? 0 : osFchown(fd,uid,gid);
    ++#else
    ++  return 0;
    ++#endif
    ++}
    ++
    + /*
    + ** This is the xSetSystemCall() method of sqlite3_vfs for all of the
    + ** "unix" VFSes.  Return SQLITE_OK opon successfully updating the
    +@@ -27374,23 +31564,12 @@ static int robust_ftruncate(int h, sqlite3_int64 sz){
    + ** should handle ENOLCK, ENOTSUP, EOPNOTSUPP separately.
    + */
    + static int sqliteErrorFromPosixError(int posixError, int sqliteIOErr) {
    ++  assert( (sqliteIOErr == SQLITE_IOERR_LOCK) || 
    ++          (sqliteIOErr == SQLITE_IOERR_UNLOCK) || 
    ++          (sqliteIOErr == SQLITE_IOERR_RDLOCK) ||
    ++          (sqliteIOErr == SQLITE_IOERR_CHECKRESERVEDLOCK) );
    +   switch (posixError) {
    +-#if 0
    +-  /* At one point this code was not commented out. In theory, this branch
    +-  ** should never be hit, as this function should only be called after
    +-  ** a locking-related function (i.e. fcntl()) has returned non-zero with
    +-  ** the value of errno as the first argument. Since a system call has failed,
    +-  ** errno should be non-zero.
    +-  **
    +-  ** Despite this, if errno really is zero, we still don't want to return
    +-  ** SQLITE_OK. The system call failed, and *some* SQLite error should be
    +-  ** propagated back to the caller. Commenting this branch out means errno==0
    +-  ** will be handled by the "default:" case below.
    +-  */
    +-  case 0: 
    +-    return SQLITE_OK;
    +-#endif
    +-
    ++  case EACCES: 
    +   case EAGAIN:
    +   case ETIMEDOUT:
    +   case EBUSY:
    +@@ -27400,41 +31579,9 @@ static int sqliteErrorFromPosixError(int posixError, int sqliteIOErr) {
    +      * introspection, in which it actually means what it says */
    +     return SQLITE_BUSY;
    +     
    +-  case EACCES: 
    +-    /* EACCES is like EAGAIN during locking operations, but not any other time*/
    +-    if( (sqliteIOErr == SQLITE_IOERR_LOCK) || 
    +-        (sqliteIOErr == SQLITE_IOERR_UNLOCK) || 
    +-        (sqliteIOErr == SQLITE_IOERR_RDLOCK) ||
    +-        (sqliteIOErr == SQLITE_IOERR_CHECKRESERVEDLOCK) ){
    +-      return SQLITE_BUSY;
    +-    }
    +-    /* else fall through */
    +   case EPERM: 
    +     return SQLITE_PERM;
    +     
    +-#if EOPNOTSUPP!=ENOTSUP
    +-  case EOPNOTSUPP: 
    +-    /* something went terribly awry, unless during file system support 
    +-     * introspection, in which it actually means what it says */
    +-#endif
    +-#ifdef ENOTSUP
    +-  case ENOTSUP: 
    +-    /* invalid fd, unless during file system support introspection, in which 
    +-     * it actually means what it says */
    +-#endif
    +-  case EIO:
    +-  case EBADF:
    +-  case EINVAL:
    +-  case ENOTCONN:
    +-  case ENODEV:
    +-  case ENXIO:
    +-  case ENOENT:
    +-#ifdef ESTALE                     /* ESTALE is not defined on Interix systems */
    +-  case ESTALE:
    +-#endif
    +-  case ENOSYS:
    +-    /* these should force the client to close the file and reconnect */
    +-    
    +   default: 
    +     return sqliteIOErr;
    +   }
    +@@ -27678,7 +31825,14 @@ struct unixFileId {
    + #if OS_VXWORKS
    +   struct vxworksFileId *pId;  /* Unique file ID for vxworks. */
    + #else
    +-  ino_t ino;                  /* Inode number */
    ++  /* We are told that some versions of Android contain a bug that
    ++  ** sizes ino_t at only 32-bits instead of 64-bits. (See
    ++  ** https://android-review.googlesource.com/#/c/115351/3/dist/sqlite3.c)
    ++  ** To work around this, always allocate 64-bits for the inode number.  
    ++  ** On small machines that only have 32-bit inodes, this wastes 4 bytes,
    ++  ** but that should not be a big deal. */
    ++  /* WAS:  ino_t ino;   */
    ++  u64 ino;                   /* Inode number */
    + #endif
    + };
    + 
    +@@ -27714,11 +31868,12 @@ struct unixInodeInfo {
    + /*
    + ** A lists of all unixInodeInfo objects.
    + */
    +-static unixInodeInfo *inodeList = 0;
    ++static unixInodeInfo *inodeList = 0;  /* All unixInodeInfo objects */
    ++static unsigned int nUnusedFd = 0;    /* Total unused file descriptors */
    + 
    + /*
    + **
    +-** This function - unixLogError_x(), is only ever called via the macro
    ++** This function - unixLogErrorAtLine(), is only ever called via the macro
    + ** unixLogError().
    + **
    + ** It is invoked after an error occurs in an OS function and errno has been
    +@@ -27824,6 +31979,7 @@ static void closePendingFds(unixFile *pFile){
    +     pNext = p->pNext;
    +     robust_close(pFile, p->fd, __LINE__);
    +     sqlite3_free(p);
    ++    nUnusedFd--;
    +   }
    +   pInode->pUnused = 0;
    + }
    +@@ -27856,6 +32012,7 @@ static void releaseInodeInfo(unixFile *pFile){
    +       sqlite3_free(pInode);
    +     }
    +   }
    ++  assert( inodeList!=0 || nUnusedFd==0 );
    + }
    + 
    + /*
    +@@ -27887,7 +32044,7 @@ static int findInodeInfo(
    +   rc = osFstat(fd, &statbuf);
    +   if( rc!=0 ){
    +     storeLastErrno(pFile, errno);
    +-#ifdef EOVERFLOW
    ++#if defined(EOVERFLOW) && defined(SQLITE_DISABLE_LFS)
    +     if( pFile->lastErrno==EOVERFLOW ) return SQLITE_NOLFS;
    + #endif
    +     return SQLITE_IOERR;
    +@@ -27923,8 +32080,9 @@ static int findInodeInfo(
    + #if OS_VXWORKS
    +   fileId.pId = pFile->pId;
    + #else
    +-  fileId.ino = statbuf.st_ino;
    ++  fileId.ino = (u64)statbuf.st_ino;
    + #endif
    ++  assert( inodeList!=0 || nUnusedFd==0 );
    +   pInode = inodeList;
    +   while( pInode && memcmp(&fileId, &pInode->fileId, sizeof(fileId)) ){
    +     pInode = pInode->pNext;
    +@@ -27932,7 +32090,7 @@ static int findInodeInfo(
    +   if( pInode==0 ){
    +     pInode = sqlite3_malloc64( sizeof(*pInode) );
    +     if( pInode==0 ){
    +-      return SQLITE_NOMEM;
    ++      return SQLITE_NOMEM_BKPT;
    +     }
    +     memset(pInode, 0, sizeof(*pInode));
    +     memcpy(&pInode->fileId, &fileId, sizeof(fileId));
    +@@ -27957,7 +32115,8 @@ static int fileHasMoved(unixFile *pFile){
    + #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 
    ++         || (u64)buf.st_ino!=pFile->pInode->fileId.ino);
    + #endif
    + }
    + 
    +@@ -27974,30 +32133,25 @@ static int fileHasMoved(unixFile *pFile){
    + static void verifyDbFile(unixFile *pFile){
    +   struct stat buf;
    +   int rc;
    +-  if( pFile->ctrlFlags & UNIXFILE_WARNED ){
    +-    /* One or more of the following warnings have already been issued.  Do not
    +-    ** repeat them so as not to clutter the error log */
    +-    return;
    +-  }
    ++
    ++  /* These verifications occurs for the main database only */
    ++  if( pFile->ctrlFlags & UNIXFILE_NOLOCK ) return;
    ++
    +   rc = osFstat(pFile->h, &buf);
    +   if( rc!=0 ){
    +     sqlite3_log(SQLITE_WARNING, "cannot fstat db file %s", pFile->zPath);
    +-    pFile->ctrlFlags |= UNIXFILE_WARNED;
    +     return;
    +   }
    +-  if( buf.st_nlink==0 && (pFile->ctrlFlags & UNIXFILE_DELETE)==0 ){
    ++  if( buf.st_nlink==0 ){
    +     sqlite3_log(SQLITE_WARNING, "file unlinked while open: %s", pFile->zPath);
    +-    pFile->ctrlFlags |= UNIXFILE_WARNED;
    +     return;
    +   }
    +   if( buf.st_nlink>1 ){
    +     sqlite3_log(SQLITE_WARNING, "multiple links to file: %s", pFile->zPath);
    +-    pFile->ctrlFlags |= UNIXFILE_WARNED;
    +     return;
    +   }
    +   if( fileHasMoved(pFile) ){
    +     sqlite3_log(SQLITE_WARNING, "file renamed while open: %s", pFile->zPath);
    +-    pFile->ctrlFlags |= UNIXFILE_WARNED;
    +     return;
    +   }
    + }
    +@@ -28017,6 +32171,7 @@ static int unixCheckReservedLock(sqlite3_file *id, int *pResOut){
    +   SimulateIOError( return SQLITE_IOERR_CHECKRESERVEDLOCK; );
    + 
    +   assert( pFile );
    ++  assert( pFile->eFileLock<=SHARED_LOCK );
    +   unixEnterMutex(); /* Because pFile->pInode is shared across threads */
    + 
    +   /* Check if a thread in this process holds such a lock */
    +@@ -28073,9 +32228,7 @@ static int unixFileLock(unixFile *pFile, struct flock *pLock){
    +   unixInodeInfo *pInode = pFile->pInode;
    +   assert( unixMutexHeld() );
    +   assert( pInode!=0 );
    +-  if( ((pFile->ctrlFlags & UNIXFILE_EXCL)!=0 || pInode->bProcessLock)
    +-   && ((pFile->ctrlFlags & UNIXFILE_RDONLY)==0)
    +-  ){
    ++  if( (pFile->ctrlFlags & (UNIXFILE_EXCL|UNIXFILE_RDONLY))==UNIXFILE_EXCL ){
    +     if( pInode->bProcessLock==0 ){
    +       struct flock lock;
    +       assert( pInode->nLock==0 );
    +@@ -28125,7 +32278,7 @@ static int unixLock(sqlite3_file *id, int eFileLock){
    +   ** lock transitions in terms of the POSIX advisory shared and exclusive
    +   ** lock primitives (called read-locks and write-locks below, to avoid
    +   ** confusion with SQLite lock names). The algorithms are complicated
    +-  ** slightly in order to be compatible with windows systems simultaneously
    ++  ** slightly in order to be compatible with Windows95 systems simultaneously
    +   ** accessing the same database file, in case that is ever required.
    +   **
    +   ** Symbols defined in os.h indentify the 'pending byte' and the 'reserved
    +@@ -28133,8 +32286,14 @@ static int unixLock(sqlite3_file *id, int eFileLock){
    +   ** range', a range of 510 bytes at a well known offset.
    +   **
    +   ** To obtain a SHARED lock, a read-lock is obtained on the 'pending
    +-  ** byte'.  If this is successful, a random byte from the 'shared byte
    +-  ** range' is read-locked and the lock on the 'pending byte' released.
    ++  ** byte'.  If this is successful, 'shared byte range' is read-locked
    ++  ** and the lock on the 'pending byte' released.  (Legacy note:  When
    ++  ** SQLite was first developed, Windows95 systems were still very common,
    ++  ** and Widnows95 lacks a shared-lock capability.  So on Windows95, a
    ++  ** single randomly selected by from the 'shared byte range' is locked.
    ++  ** Windows95 is now pretty much extinct, but this work-around for the
    ++  ** lack of shared-locks on Windows95 lives on, for backwards
    ++  ** compatibility.)
    +   **
    +   ** A process may only obtain a RESERVED lock after it has a SHARED lock.
    +   ** A RESERVED lock is implemented by grabbing a write-lock on the
    +@@ -28153,11 +32312,6 @@ static int unixLock(sqlite3_file *id, int eFileLock){
    +   ** range'. Since all other locks require a read-lock on one of the bytes
    +   ** within this range, this ensures that no other locks are held on the
    +   ** database. 
    +-  **
    +-  ** The reason a single byte cannot be used instead of the 'shared byte
    +-  ** range' is that some versions of windows do not support read-locks. By
    +-  ** locking a random byte from a range, concurrent SHARED locks may exist
    +-  ** even if the locking primitive used is always a write-lock.
    +   */
    +   int rc = SQLITE_OK;
    +   unixFile *pFile = (unixFile*)id;
    +@@ -28348,11 +32502,12 @@ end_lock:
    + */
    + static void setPendingFd(unixFile *pFile){
    +   unixInodeInfo *pInode = pFile->pInode;
    +-  UnixUnusedFd *p = pFile->pUnused;
    ++  UnixUnusedFd *p = pFile->pPreallocatedUnused;
    +   p->pNext = pInode->pUnused;
    +   pInode->pUnused = p;
    +   pFile->h = -1;
    +-  pFile->pUnused = 0;
    ++  pFile->pPreallocatedUnused = 0;
    ++  nUnusedFd++;
    + }
    + 
    + /*
    +@@ -28427,9 +32582,7 @@ static int posixUnlock(sqlite3_file *id, int eFileLock, int handleNFSUnlock){
    +         if( unixFileLock(pFile, &lock)==(-1) ){
    +           tErrno = errno;
    +           rc = SQLITE_IOERR_UNLOCK;
    +-          if( IS_LOCK_ERROR(rc) ){
    +-            storeLastErrno(pFile, tErrno);
    +-          }
    ++          storeLastErrno(pFile, tErrno);
    +           goto end_unlock;
    +         }
    +         lock.l_type = F_RDLCK;
    +@@ -28451,9 +32604,7 @@ static int posixUnlock(sqlite3_file *id, int eFileLock, int handleNFSUnlock){
    +         if( unixFileLock(pFile, &lock)==(-1) ){
    +           tErrno = errno;
    +           rc = SQLITE_IOERR_UNLOCK;
    +-          if( IS_LOCK_ERROR(rc) ){
    +-            storeLastErrno(pFile, tErrno);
    +-          }
    ++          storeLastErrno(pFile, tErrno);
    +           goto end_unlock;
    +         }
    +       }else
    +@@ -28581,7 +32732,7 @@ static int closeUnixFile(sqlite3_file *id){
    + #endif
    +   OSTRACE(("CLOSE   %-3d\n", pFile->h));
    +   OpenCounter(-1);
    +-  sqlite3_free(pFile->pUnused);
    ++  sqlite3_free(pFile->pPreallocatedUnused);
    +   memset(pFile, 0, sizeof(unixFile));
    +   return SQLITE_OK;
    + }
    +@@ -28704,17 +32855,7 @@ static int dotlockCheckReservedLock(sqlite3_file *id, int *pResOut) {
    +   SimulateIOError( return SQLITE_IOERR_CHECKRESERVEDLOCK; );
    +   
    +   assert( pFile );
    +-
    +-  /* Check if a thread in this process holds such a lock */
    +-  if( pFile->eFileLock>SHARED_LOCK ){
    +-    /* Either this connection or some other connection in the same process
    +-    ** holds a lock on the file.  No need to check further. */
    +-    reserved = 1;
    +-  }else{
    +-    /* The lock is held if and only if the lockfile exists */
    +-    const char *zLockFile = (const char*)pFile->lockingContext;
    +-    reserved = osAccess(zLockFile, 0)==0;
    +-  }
    ++  reserved = osAccess((const char*)pFile->lockingContext, 0)==0;
    +   OSTRACE(("TEST WR-LOCK %d %d %d (dotlock)\n", pFile->h, rc, reserved));
    +   *pResOut = reserved;
    +   return rc;
    +@@ -28776,7 +32917,7 @@ static int dotlockLock(sqlite3_file *id, int eFileLock) {
    +       rc = SQLITE_BUSY;
    +     } else {
    +       rc = sqliteErrorFromPosixError(tErrno, SQLITE_IOERR_LOCK);
    +-      if( IS_LOCK_ERROR(rc) ){
    ++      if( rc!=SQLITE_BUSY ){
    +         storeLastErrno(pFile, tErrno);
    +       }
    +     }
    +@@ -28823,14 +32964,12 @@ static int dotlockUnlock(sqlite3_file *id, int eFileLock) {
    +   /* To fully unlock the database, delete the lock file */
    +   assert( eFileLock==NO_LOCK );
    +   rc = osRmdir(zLockFile);
    +-  if( rc<0 && errno==ENOTDIR ) rc = osUnlink(zLockFile);
    +   if( rc<0 ){
    +     int tErrno = errno;
    +-    rc = 0;
    +-    if( ENOENT != tErrno ){
    ++    if( tErrno==ENOENT ){
    ++      rc = SQLITE_OK;
    ++    }else{
    +       rc = SQLITE_IOERR_UNLOCK;
    +-    }
    +-    if( IS_LOCK_ERROR(rc) ){
    +       storeLastErrno(pFile, tErrno);
    +     }
    +     return rc; 
    +@@ -28843,14 +32982,11 @@ static int dotlockUnlock(sqlite3_file *id, int eFileLock) {
    + ** Close a file.  Make sure the lock has been released before closing.
    + */
    + static int dotlockClose(sqlite3_file *id) {
    +-  int rc = SQLITE_OK;
    +-  if( id ){
    +-    unixFile *pFile = (unixFile*)id;
    +-    dotlockUnlock(id, NO_LOCK);
    +-    sqlite3_free(pFile->lockingContext);
    +-    rc = closeUnixFile(id);
    +-  }
    +-  return rc;
    ++  unixFile *pFile = (unixFile*)id;
    ++  assert( id!=0 );
    ++  dotlockUnlock(id, NO_LOCK);
    ++  sqlite3_free(pFile->lockingContext);
    ++  return closeUnixFile(id);
    + }
    + /****************** End of the dot-file lock implementation *******************
    + ******************************************************************************/
    +@@ -28916,10 +33052,8 @@ static int flockCheckReservedLock(sqlite3_file *id, int *pResOut){
    +         int tErrno = errno;
    +         /* unlock failed with an error */
    +         lrc = SQLITE_IOERR_UNLOCK; 
    +-        if( IS_LOCK_ERROR(lrc) ){
    +-          storeLastErrno(pFile, tErrno);
    +-          rc = lrc;
    +-        }
    ++        storeLastErrno(pFile, tErrno);
    ++        rc = lrc;
    +       }
    +     } else {
    +       int tErrno = errno;
    +@@ -28935,7 +33069,7 @@ static int flockCheckReservedLock(sqlite3_file *id, int *pResOut){
    +   OSTRACE(("TEST WR-LOCK %d %d %d (flock)\n", pFile->h, rc, reserved));
    + 
    + #ifdef SQLITE_IGNORE_FLOCK_LOCK_ERRORS
    +-  if( (rc & SQLITE_IOERR) == SQLITE_IOERR ){
    ++  if( (rc & 0xff) == SQLITE_IOERR ){
    +     rc = SQLITE_OK;
    +     reserved=1;
    +   }
    +@@ -29002,7 +33136,7 @@ static int flockLock(sqlite3_file *id, int eFileLock) {
    +   OSTRACE(("LOCK    %d %s %s (flock)\n", pFile->h, azFileLock(eFileLock), 
    +            rc==SQLITE_OK ? "ok" : "failed"));
    + #ifdef SQLITE_IGNORE_FLOCK_LOCK_ERRORS
    +-  if( (rc & SQLITE_IOERR) == SQLITE_IOERR ){
    ++  if( (rc & 0xff) == SQLITE_IOERR ){
    +     rc = SQLITE_BUSY;
    +   }
    + #endif /* SQLITE_IGNORE_FLOCK_LOCK_ERRORS */
    +@@ -29052,12 +33186,9 @@ static int flockUnlock(sqlite3_file *id, int eFileLock) {
    + ** Close a file.
    + */
    + static int flockClose(sqlite3_file *id) {
    +-  int rc = SQLITE_OK;
    +-  if( id ){
    +-    flockUnlock(id, NO_LOCK);
    +-    rc = closeUnixFile(id);
    +-  }
    +-  return rc;
    ++  assert( id!=0 );
    ++  flockUnlock(id, NO_LOCK);
    ++  return closeUnixFile(id);
    + }
    + 
    + #endif /* SQLITE_ENABLE_LOCKING_STYLE && !OS_VXWORK */
    +@@ -29542,7 +33673,7 @@ static int afpLock(sqlite3_file *id, int eFileLock){
    +           /* Can't reestablish the shared lock.  Sqlite can't deal, this is
    +           ** a critical I/O error
    +           */
    +-          rc = ((failed & SQLITE_IOERR) == SQLITE_IOERR) ? failed2 : 
    ++          rc = ((failed & 0xff) == SQLITE_IOERR) ? failed2 : 
    +                SQLITE_IOERR_LOCK;
    +           goto afp_end_lock;
    +         } 
    +@@ -29682,23 +33813,22 @@ static int afpUnlock(sqlite3_file *id, int eFileLock) {
    + */
    + static int afpClose(sqlite3_file *id) {
    +   int rc = SQLITE_OK;
    +-  if( id ){
    +-    unixFile *pFile = (unixFile*)id;
    +-    afpUnlock(id, NO_LOCK);
    +-    unixEnterMutex();
    +-    if( pFile->pInode && pFile->pInode->nLock ){
    +-      /* If there are outstanding locks, do not actually close the file just
    +-      ** yet because that would clear those locks.  Instead, add the file
    +-      ** descriptor to pInode->aPending.  It will be automatically closed when
    +-      ** the last lock is cleared.
    +-      */
    +-      setPendingFd(pFile);
    +-    }
    +-    releaseInodeInfo(pFile);
    +-    sqlite3_free(pFile->lockingContext);
    +-    rc = closeUnixFile(id);
    +-    unixLeaveMutex();
    ++  unixFile *pFile = (unixFile*)id;
    ++  assert( id!=0 );
    ++  afpUnlock(id, NO_LOCK);
    ++  unixEnterMutex();
    ++  if( pFile->pInode && pFile->pInode->nLock ){
    ++    /* If there are outstanding locks, do not actually close the file just
    ++    ** yet because that would clear those locks.  Instead, add the file
    ++    ** descriptor to pInode->aPending.  It will be automatically closed when
    ++    ** the last lock is cleared.
    ++    */
    ++    setPendingFd(pFile);
    +   }
    ++  releaseInodeInfo(pFile);
    ++  sqlite3_free(pFile->lockingContext);
    ++  rc = closeUnixFile(id);
    ++  unixLeaveMutex();
    +   return rc;
    + }
    + 
    +@@ -29777,13 +33907,9 @@ static int seekAndRead(unixFile *id, sqlite3_int64 offset, void *pBuf, int cnt){
    +     SimulateIOError( got = -1 );
    + #else
    +     newOffset = lseek(id->h, offset, SEEK_SET);
    +-    SimulateIOError( newOffset-- );
    +-    if( newOffset!=offset ){
    +-      if( newOffset == -1 ){
    +-        storeLastErrno((unixFile*)id, errno);
    +-      }else{
    +-        storeLastErrno((unixFile*)id, 0);
    +-      }
    ++    SimulateIOError( newOffset = -1 );
    ++    if( newOffset<0 ){
    ++      storeLastErrno((unixFile*)id, errno);
    +       return -1;
    +     }
    +     got = osRead(id->h, pBuf, cnt);
    +@@ -29827,7 +33953,7 @@ static int unixRead(
    +   /* If this is a database file (not a journal, master-journal or temp
    +   ** file), the bytes in the locking range should never be read or written. */
    + #if 0
    +-  assert( pFile->pUnused==0
    ++  assert( pFile->pPreallocatedUnused==0
    +        || offset>=PENDING_BYTE+512
    +        || offset+amt<=PENDING_BYTE 
    +   );
    +@@ -29882,6 +34008,7 @@ static int seekAndWriteFd(
    + 
    +   assert( nBuf==(nBuf&0x1ffff) );
    +   assert( fd>2 );
    ++  assert( piErrno!=0 );
    +   nBuf &= 0x1ffff;
    +   TIMER_START;
    + 
    +@@ -29892,11 +34019,10 @@ static int seekAndWriteFd(
    + #else
    +   do{
    +     i64 iSeek = lseek(fd, iOff, SEEK_SET);
    +-    SimulateIOError( iSeek-- );
    +-
    +-    if( iSeek!=iOff ){
    +-      if( piErrno ) *piErrno = (iSeek==-1 ? errno : 0);
    +-      return -1;
    ++    SimulateIOError( iSeek = -1 );
    ++    if( iSeek<0 ){
    ++      rc = -1;
    ++      break;
    +     }
    +     rc = osWrite(fd, pBuf, nBuf);
    +   }while( rc<0 && errno==EINTR );
    +@@ -29905,7 +34031,7 @@ static int seekAndWriteFd(
    +   TIMER_END;
    +   OSTRACE(("WRITE   %-3d %5d %7lld %llu\n", fd, rc, iOff, TIMER_ELAPSED));
    + 
    +-  if( rc<0 && piErrno ) *piErrno = errno;
    ++  if( rc<0 ) *piErrno = errno;
    +   return rc;
    + }
    + 
    +@@ -29940,7 +34066,7 @@ static int unixWrite(
    +   /* If this is a database file (not a journal, master-journal or temp
    +   ** file), the bytes in the locking range should never be read or written. */
    + #if 0
    +-  assert( pFile->pUnused==0
    ++  assert( pFile->pPreallocatedUnused==0
    +        || offset>=PENDING_BYTE+512
    +        || offset+amt<=PENDING_BYTE 
    +   );
    +@@ -29968,7 +34094,7 @@ static int unixWrite(
    +   }
    + #endif
    + 
    +-#if SQLITE_MAX_MMAP_SIZE>0
    ++#if defined(SQLITE_MMAP_READWRITE) && SQLITE_MAX_MMAP_SIZE>0
    +   /* Deal with as much of this write request as possible by transfering
    +   ** data from the memory mapping using memcpy().  */
    +   if( offset<pFile->mmapSize ){
    +@@ -30089,10 +34215,15 @@ static int full_fsync(int fd, int fullSync, int dataOnly){
    + #endif
    + 
    +   /* If we compiled with the SQLITE_NO_SYNC flag, then syncing is a
    +-  ** no-op
    ++  ** no-op.  But go ahead and call fstat() to validate the file
    ++  ** descriptor as we need a method to provoke a failure during
    ++  ** coverate testing.
    +   */
    + #ifdef SQLITE_NO_SYNC
    +-  rc = SQLITE_OK;
    ++  {
    ++    struct stat buf;
    ++    rc = osFstat(fd, &buf);
    ++  }
    + #elif HAVE_FULLFSYNC
    +   if( fullSync ){
    +     rc = osFcntl(fd, F_FULLFSYNC, 0);
    +@@ -30158,16 +34289,20 @@ static int openDirectory(const char *zFilename, int *pFd){
    +   char zDirname[MAX_PATHNAME+1];
    + 
    +   sqlite3_snprintf(MAX_PATHNAME, zDirname, "%s", zFilename);
    +-  for(ii=(int)strlen(zDirname); ii>1 && zDirname[ii]!='/'; ii--);
    ++  for(ii=(int)strlen(zDirname); ii>0 && zDirname[ii]!='/'; ii--);
    +   if( ii>0 ){
    +     zDirname[ii] = '\0';
    +-    fd = robust_open(zDirname, O_RDONLY|O_BINARY, 0);
    +-    if( fd>=0 ){
    +-      OSTRACE(("OPENDIR %-3d %s\n", fd, zDirname));
    +-    }
    ++  }else{
    ++    if( zDirname[0]!='/' ) zDirname[0] = '.';
    ++    zDirname[1] = 0;
    ++  }
    ++  fd = robust_open(zDirname, O_RDONLY|O_BINARY, 0);
    ++  if( fd>=0 ){
    ++    OSTRACE(("OPENDIR %-3d %s\n", fd, zDirname));
    +   }
    +   *pFd = fd;
    +-  return (fd>=0?SQLITE_OK:unixLogError(SQLITE_CANTOPEN_BKPT, "open", zDirname));
    ++  if( fd>=0 ) return SQLITE_OK;
    ++  return unixLogError(SQLITE_CANTOPEN_BKPT, "openDirectory", zDirname);
    + }
    + 
    + /*
    +@@ -30220,10 +34355,11 @@ static int unixSync(sqlite3_file *id, int flags){
    +     OSTRACE(("DIRSYNC %s (have_fullfsync=%d fullsync=%d)\n", pFile->zPath,
    +             HAVE_FULLFSYNC, isFullsync));
    +     rc = osOpenDirectory(pFile->zPath, &dirfd);
    +-    if( rc==SQLITE_OK && dirfd>=0 ){
    ++    if( rc==SQLITE_OK ){
    +       full_fsync(dirfd, 0, 0);
    +       robust_close(pFile, dirfd, __LINE__);
    +-    }else if( rc==SQLITE_CANTOPEN ){
    ++    }else{
    ++      assert( rc==SQLITE_CANTOPEN );
    +       rc = SQLITE_OK;
    +     }
    +     pFile->ctrlFlags &= ~UNIXFILE_DIRSYNC;
    +@@ -30355,18 +34491,14 @@ static int fcntlSizeHint(unixFile *pFile, i64 nByte){
    +       int nWrite = 0;             /* Number of bytes written by seekAndWrite */
    +       i64 iWrite;                 /* Next offset to write to */
    + 
    +-      iWrite = ((buf.st_size + 2*nBlk - 1)/nBlk)*nBlk-1;
    ++      iWrite = (buf.st_size/nBlk)*nBlk + nBlk - 1;
    +       assert( iWrite>=buf.st_size );
    +-      assert( (iWrite/nBlk)==((buf.st_size+nBlk-1)/nBlk) );
    +       assert( ((iWrite+1)%nBlk)==0 );
    +-      for(/*no-op*/; iWrite<nSize; iWrite+=nBlk ){
    ++      for(/*no-op*/; iWrite<nSize+nBlk-1; iWrite+=nBlk ){
    ++        if( iWrite>=nSize ) iWrite = nSize - 1;
    +         nWrite = seekAndWrite(pFile, iWrite, "", 1);
    +         if( nWrite!=1 ) return SQLITE_IOERR_WRITE;
    +       }
    +-      if( nWrite==0 || (nSize%nBlk) ){
    +-        nWrite = seekAndWrite(pFile, nSize-1, "", 1);
    +-        if( nWrite!=1 ) return SQLITE_IOERR_WRITE;
    +-      }
    + #endif
    +     }
    +   }
    +@@ -30414,10 +34546,21 @@ static int unixGetTempname(int nBuf, char *zBuf);
    + static int unixFileControl(sqlite3_file *id, int op, void *pArg){
    +   unixFile *pFile = (unixFile*)id;
    +   switch( op ){
    +-    case SQLITE_FCNTL_WAL_BLOCK: {
    +-      /* pFile->ctrlFlags |= UNIXFILE_BLOCK; // Deferred feature */
    +-      return SQLITE_OK;
    ++#if defined(__linux__) && defined(SQLITE_ENABLE_BATCH_ATOMIC_WRITE)
    ++    case SQLITE_FCNTL_BEGIN_ATOMIC_WRITE: {
    ++      int rc = osIoctl(pFile->h, F2FS_IOC_START_ATOMIC_WRITE);
    ++      return rc ? SQLITE_IOERR_BEGIN_ATOMIC : SQLITE_OK;
    ++    }
    ++    case SQLITE_FCNTL_COMMIT_ATOMIC_WRITE: {
    ++      int rc = osIoctl(pFile->h, F2FS_IOC_COMMIT_ATOMIC_WRITE);
    ++      return rc ? SQLITE_IOERR_COMMIT_ATOMIC : SQLITE_OK;
    +     }
    ++    case SQLITE_FCNTL_ROLLBACK_ATOMIC_WRITE: {
    ++      int rc = osIoctl(pFile->h, F2FS_IOC_ABORT_VOLATILE_WRITE);
    ++      return rc ? SQLITE_IOERR_ROLLBACK_ATOMIC : SQLITE_OK;
    ++    }
    ++#endif /* __linux__ && SQLITE_ENABLE_BATCH_ATOMIC_WRITE */
    ++
    +     case SQLITE_FCNTL_LOCKSTATE: {
    +       *(int*)pArg = pFile->eFileLock;
    +       return SQLITE_OK;
    +@@ -30468,6 +34611,14 @@ static int unixFileControl(sqlite3_file *id, int op, void *pArg){
    +       if( newLimit>sqlite3GlobalConfig.mxMmap ){
    +         newLimit = sqlite3GlobalConfig.mxMmap;
    +       }
    ++
    ++      /* The value of newLimit may be eventually cast to (size_t) and passed
    ++      ** to mmap(). Restrict its value to 2GB if (size_t) is not at least a
    ++      ** 64-bit type. */
    ++      if( newLimit>0 && sizeof(size_t)<8 ){
    ++        newLimit = (newLimit & 0x7FFFFFFF);
    ++      }
    ++
    +       *(i64*)pArg = pFile->mmapSizeMax;
    +       if( newLimit>=0 && newLimit!=pFile->mmapSizeMax && pFile->nFetchOut==0 ){
    +         pFile->mmapSizeMax = newLimit;
    +@@ -30501,30 +34652,41 @@ static int unixFileControl(sqlite3_file *id, int op, void *pArg){
    + }
    + 
    + /*
    +-** Return the sector size in bytes of the underlying block device for
    +-** the specified file. This is almost always 512 bytes, but may be
    +-** larger for some devices.
    ++** If pFd->sectorSize is non-zero when this function is called, it is a
    ++** no-op. Otherwise, the values of pFd->sectorSize and 
    ++** pFd->deviceCharacteristics are set according to the file-system 
    ++** characteristics. 
    + **
    +-** SQLite code assumes this function cannot fail. It also assumes that
    +-** if two files are created in the same file-system directory (i.e.
    +-** a database and its journal file) that the sector size will be the
    +-** same for both.
    ++** There are two versions of this function. One for QNX and one for all
    ++** other systems.
    + */
    +-#ifndef __QNXNTO__ 
    +-static int unixSectorSize(sqlite3_file *NotUsed){
    +-  UNUSED_PARAMETER(NotUsed);
    +-  return SQLITE_DEFAULT_SECTOR_SIZE;
    +-}
    +-#endif
    ++#ifndef __QNXNTO__
    ++static void setDeviceCharacteristics(unixFile *pFd){
    ++  assert( pFd->deviceCharacteristics==0 || pFd->sectorSize!=0 );
    ++  if( pFd->sectorSize==0 ){
    ++#if defined(__linux__) && defined(SQLITE_ENABLE_BATCH_ATOMIC_WRITE)
    ++    int res;
    ++    u32 f = 0;
    + 
    +-/*
    +-** The following version of unixSectorSize() is optimized for QNX.
    +-*/
    +-#ifdef __QNXNTO__
    ++    /* Check for support for F2FS atomic batch writes. */
    ++    res = osIoctl(pFd->h, F2FS_IOC_GET_FEATURES, &f);
    ++    if( res==0 && (f & F2FS_FEATURE_ATOMIC_WRITE) ){
    ++      pFd->deviceCharacteristics = SQLITE_IOCAP_BATCH_ATOMIC;
    ++    }
    ++#endif /* __linux__ && SQLITE_ENABLE_BATCH_ATOMIC_WRITE */
    ++
    ++    /* Set the POWERSAFE_OVERWRITE flag if requested. */
    ++    if( pFd->ctrlFlags & UNIXFILE_PSOW ){
    ++      pFd->deviceCharacteristics |= SQLITE_IOCAP_POWERSAFE_OVERWRITE;
    ++    }
    ++
    ++    pFd->sectorSize = SQLITE_DEFAULT_SECTOR_SIZE;
    ++  }
    ++}
    ++#else
    + #include <sys/dcmd_blk.h>
    + #include <sys/statvfs.h>
    +-static int unixSectorSize(sqlite3_file *id){
    +-  unixFile *pFile = (unixFile*)id;
    ++static void setDeviceCharacteristics(unixFile *pFile){
    +   if( pFile->sectorSize == 0 ){
    +     struct statvfs fsInfo;
    +        
    +@@ -30532,7 +34694,7 @@ static int unixSectorSize(sqlite3_file *id){
    +     pFile->sectorSize = SQLITE_DEFAULT_SECTOR_SIZE;
    +     pFile->deviceCharacteristics = 0;
    +     if( fstatvfs(pFile->h, &fsInfo) == -1 ) {
    +-      return pFile->sectorSize;
    ++      return;
    +     }
    + 
    +     if( !strcmp(fsInfo.f_basetype, "tmp") ) {
    +@@ -30593,9 +34755,24 @@ static int unixSectorSize(sqlite3_file *id){
    +     pFile->deviceCharacteristics = 0;
    +     pFile->sectorSize = SQLITE_DEFAULT_SECTOR_SIZE;
    +   }
    +-  return pFile->sectorSize;
    + }
    +-#endif /* __QNXNTO__ */
    ++#endif
    ++
    ++/*
    ++** Return the sector size in bytes of the underlying block device for
    ++** the specified file. This is almost always 512 bytes, but may be
    ++** larger for some devices.
    ++**
    ++** SQLite code assumes this function cannot fail. It also assumes that
    ++** if two files are created in the same file-system directory (i.e.
    ++** a database and its journal file) that the sector size will be the
    ++** same for both.
    ++*/
    ++static int unixSectorSize(sqlite3_file *id){
    ++  unixFile *pFd = (unixFile*)id;
    ++  setDeviceCharacteristics(pFd);
    ++  return pFd->sectorSize;
    ++}
    + 
    + /*
    + ** Return the device characteristics for the file.
    +@@ -30611,16 +34788,9 @@ static int unixSectorSize(sqlite3_file *id){
    + ** available to turn it off and URI query parameter available to turn it off.
    + */
    + static int unixDeviceCharacteristics(sqlite3_file *id){
    +-  unixFile *p = (unixFile*)id;
    +-  int rc = 0;
    +-#ifdef __QNXNTO__
    +-  if( p->sectorSize==0 ) unixSectorSize(id);
    +-  rc = p->deviceCharacteristics;
    +-#endif
    +-  if( p->ctrlFlags & UNIXFILE_PSOW ){
    +-    rc |= SQLITE_IOCAP_POWERSAFE_OVERWRITE;
    +-  }
    +-  return rc;
    ++  unixFile *pFd = (unixFile*)id;
    ++  setDeviceCharacteristics(pFd);
    ++  return pFd->deviceCharacteristics;
    + }
    + 
    + #if !defined(SQLITE_OMIT_WAL) || SQLITE_MAX_MMAP_SIZE>0
    +@@ -30682,6 +34852,7 @@ struct unixShmNode {
    +   int szRegion;              /* Size of shared-memory regions */
    +   u16 nRegion;               /* Size of array apRegion */
    +   u8 isReadonly;             /* True if read-only */
    ++  u8 isUnlocked;             /* True if no DMS lock held */
    +   char **apRegion;           /* Array of mapped shared-memory regions */
    +   int nRef;                  /* Number of unixShm objects pointing to this */
    +   unixShm *pFirst;           /* All unixShm objects pointing to this */
    +@@ -30738,16 +34909,15 @@ static int unixShmSystemLock(
    + 
    +   /* Access to the unixShmNode object is serialized by the caller */
    +   pShmNode = pFile->pInode->pShmNode;
    +-  assert( sqlite3_mutex_held(pShmNode->mutex) || pShmNode->nRef==0 );
    ++  assert( pShmNode->nRef==0 || sqlite3_mutex_held(pShmNode->mutex) );
    + 
    +   /* Shared locks never span more than one byte */
    +   assert( n==1 || lockType!=F_RDLCK );
    + 
    +   /* Locks are within range */
    +-  assert( n>=1 && n<SQLITE_SHM_NLOCK );
    ++  assert( n>=1 && n<=SQLITE_SHM_NLOCK );
    + 
    +   if( pShmNode->h>=0 ){
    +-    int lkType;
    +     /* Initialize the locking parameters */
    +     memset(&f, 0, sizeof(f));
    +     f.l_type = lockType;
    +@@ -30755,10 +34925,8 @@ static int unixShmSystemLock(
    +     f.l_start = ofst;
    +     f.l_len = n;
    + 
    +-    lkType = (pFile->ctrlFlags & UNIXFILE_BLOCK)!=0 ? F_SETLKW : F_SETLK;
    +-    rc = osFcntl(pShmNode->h, lkType, &f);
    ++    rc = osFcntl(pShmNode->h, F_SETLK, &f);
    +     rc = (rc!=(-1)) ? SQLITE_OK : SQLITE_BUSY;
    +-    pFile->ctrlFlags &= ~UNIXFILE_BLOCK;
    +   }
    + 
    +   /* Update the global lock state and do debug tracing */
    +@@ -30825,7 +34993,7 @@ static int unixShmRegionPerMap(void){
    + static void unixShmPurge(unixFile *pFd){
    +   unixShmNode *p = pFd->pInode->pShmNode;
    +   assert( unixMutexHeld() );
    +-  if( p && p->nRef==0 ){
    ++  if( p && ALWAYS(p->nRef==0) ){
    +     int nShmPerMap = unixShmRegionPerMap();
    +     int i;
    +     assert( p->pInode==pFd->pInode );
    +@@ -30847,6 +35015,64 @@ static void unixShmPurge(unixFile *pFd){
    +   }
    + }
    + 
    ++/*
    ++** The DMS lock has not yet been taken on shm file pShmNode. Attempt to
    ++** take it now. Return SQLITE_OK if successful, or an SQLite error
    ++** code otherwise.
    ++**
    ++** If the DMS cannot be locked because this is a readonly_shm=1 
    ++** connection and no other process already holds a lock, return
    ++** SQLITE_READONLY_CANTINIT and set pShmNode->isUnlocked=1.
    ++*/
    ++static int unixLockSharedMemory(unixFile *pDbFd, unixShmNode *pShmNode){
    ++  struct flock lock;
    ++  int rc = SQLITE_OK;
    ++
    ++  /* Use F_GETLK to determine the locks other processes are holding
    ++  ** on the DMS byte. If it indicates that another process is holding
    ++  ** a SHARED lock, then this process may also take a SHARED lock
    ++  ** and proceed with opening the *-shm file. 
    ++  **
    ++  ** Or, if no other process is holding any lock, then this process
    ++  ** is the first to open it. In this case take an EXCLUSIVE lock on the
    ++  ** DMS byte and truncate the *-shm file to zero bytes in size. Then
    ++  ** downgrade to a SHARED lock on the DMS byte.
    ++  **
    ++  ** If another process is holding an EXCLUSIVE lock on the DMS byte,
    ++  ** return SQLITE_BUSY to the caller (it will try again). An earlier
    ++  ** version of this code attempted the SHARED lock at this point. But
    ++  ** this introduced a subtle race condition: if the process holding
    ++  ** EXCLUSIVE failed just before truncating the *-shm file, then this
    ++  ** process might open and use the *-shm file without truncating it.
    ++  ** And if the *-shm file has been corrupted by a power failure or
    ++  ** system crash, the database itself may also become corrupt.  */
    ++  lock.l_whence = SEEK_SET;
    ++  lock.l_start = UNIX_SHM_DMS;
    ++  lock.l_len = 1;
    ++  lock.l_type = F_WRLCK;
    ++  if( osFcntl(pShmNode->h, F_GETLK, &lock)!=0 ) {
    ++    rc = SQLITE_IOERR_LOCK;
    ++  }else if( lock.l_type==F_UNLCK ){
    ++    if( pShmNode->isReadonly ){
    ++      pShmNode->isUnlocked = 1;
    ++      rc = SQLITE_READONLY_CANTINIT;
    ++    }else{
    ++      rc = unixShmSystemLock(pDbFd, F_WRLCK, UNIX_SHM_DMS, 1);
    ++      if( rc==SQLITE_OK && robust_ftruncate(pShmNode->h, 0) ){
    ++        rc = unixLogError(SQLITE_IOERR_SHMOPEN,"ftruncate",pShmNode->zFilename);
    ++      }
    ++    }
    ++  }else if( lock.l_type==F_WRLCK ){
    ++    rc = SQLITE_BUSY;
    ++  }
    ++
    ++  if( rc==SQLITE_OK ){
    ++    assert( lock.l_type==F_UNLCK || lock.l_type==F_RDLCK );
    ++    rc = unixShmSystemLock(pDbFd, F_RDLCK, UNIX_SHM_DMS, 1);
    ++  }
    ++  return rc;
    ++}
    ++
    + /*
    + ** Open a shared-memory area associated with open database file pDbFd.  
    + ** This particular implementation uses mmapped files.
    +@@ -30885,14 +35111,14 @@ static void unixShmPurge(unixFile *pFd){
    + static int unixOpenSharedMemory(unixFile *pDbFd){
    +   struct unixShm *p = 0;          /* The connection to be opened */
    +   struct unixShmNode *pShmNode;   /* The underlying mmapped file */
    +-  int rc;                         /* Result code */
    ++  int rc = SQLITE_OK;             /* Result code */
    +   unixInodeInfo *pInode;          /* The inode of fd */
    +-  char *zShmFilename;             /* Name of the file used for SHM */
    ++  char *zShm;             /* Name of the file used for SHM */
    +   int nShmFilename;               /* Size of the SHM filename in bytes */
    + 
    +   /* Allocate space for the new unixShm object. */
    +   p = sqlite3_malloc64( sizeof(*p) );
    +-  if( p==0 ) return SQLITE_NOMEM;
    ++  if( p==0 ) return SQLITE_NOMEM_BKPT;
    +   memset(p, 0, sizeof(*p));
    +   assert( pDbFd->pShm==0 );
    + 
    +@@ -30912,7 +35138,7 @@ static int unixOpenSharedMemory(unixFile *pDbFd){
    +     ** a new *-shm file is created, an attempt will be made to create it
    +     ** with the same permissions.
    +     */
    +-    if( osFstat(pDbFd->h, &sStat) && pInode->bProcessLock==0 ){
    ++    if( osFstat(pDbFd->h, &sStat) ){
    +       rc = SQLITE_IOERR_FSTAT;
    +       goto shm_open_err;
    +     }
    +@@ -30924,59 +35150,51 @@ static int unixOpenSharedMemory(unixFile *pDbFd){
    + #endif
    +     pShmNode = sqlite3_malloc64( sizeof(*pShmNode) + nShmFilename );
    +     if( pShmNode==0 ){
    +-      rc = SQLITE_NOMEM;
    ++      rc = SQLITE_NOMEM_BKPT;
    +       goto shm_open_err;
    +     }
    +     memset(pShmNode, 0, sizeof(*pShmNode)+nShmFilename);
    +-    zShmFilename = pShmNode->zFilename = (char*)&pShmNode[1];
    ++    zShm = pShmNode->zFilename = (char*)&pShmNode[1];
    + #ifdef SQLITE_SHM_DIRECTORY
    +-    sqlite3_snprintf(nShmFilename, zShmFilename, 
    ++    sqlite3_snprintf(nShmFilename, zShm, 
    +                      SQLITE_SHM_DIRECTORY "/sqlite-shm-%x-%x",
    +                      (u32)sStat.st_ino, (u32)sStat.st_dev);
    + #else
    +-    sqlite3_snprintf(nShmFilename, zShmFilename, "%s-shm", zBasePath);
    +-    sqlite3FileSuffix3(pDbFd->zPath, zShmFilename);
    ++    sqlite3_snprintf(nShmFilename, zShm, "%s-shm", zBasePath);
    ++    sqlite3FileSuffix3(pDbFd->zPath, zShm);
    + #endif
    +     pShmNode->h = -1;
    +     pDbFd->pInode->pShmNode = pShmNode;
    +     pShmNode->pInode = pDbFd->pInode;
    +-    pShmNode->mutex = sqlite3_mutex_alloc(SQLITE_MUTEX_FAST);
    +-    if( pShmNode->mutex==0 ){
    +-      rc = SQLITE_NOMEM;
    +-      goto shm_open_err;
    ++    if( sqlite3GlobalConfig.bCoreMutex ){
    ++      pShmNode->mutex = sqlite3_mutex_alloc(SQLITE_MUTEX_FAST);
    ++      if( pShmNode->mutex==0 ){
    ++        rc = SQLITE_NOMEM_BKPT;
    ++        goto shm_open_err;
    ++      }
    +     }
    + 
    +     if( pInode->bProcessLock==0 ){
    +-      int openFlags = O_RDWR | O_CREAT;
    +-      if( sqlite3_uri_boolean(pDbFd->zPath, "readonly_shm", 0) ){
    +-        openFlags = O_RDONLY;
    +-        pShmNode->isReadonly = 1;
    ++      if( 0==sqlite3_uri_boolean(pDbFd->zPath, "readonly_shm", 0) ){
    ++        pShmNode->h = robust_open(zShm, O_RDWR|O_CREAT, (sStat.st_mode&0777));
    +       }
    +-      pShmNode->h = robust_open(zShmFilename, openFlags, (sStat.st_mode&0777));
    +       if( pShmNode->h<0 ){
    +-        rc = unixLogError(SQLITE_CANTOPEN_BKPT, "open", zShmFilename);
    +-        goto shm_open_err;
    ++        pShmNode->h = robust_open(zShm, O_RDONLY, (sStat.st_mode&0777));
    ++        if( pShmNode->h<0 ){
    ++          rc = unixLogError(SQLITE_CANTOPEN_BKPT, "open", zShm);
    ++          goto shm_open_err;
    ++        }
    ++        pShmNode->isReadonly = 1;
    +       }
    + 
    +       /* If this process is running as root, make sure that the SHM file
    +       ** is owned by the same user that owns the original database.  Otherwise,
    +       ** the original owner will not be able to connect.
    +       */
    +-      osFchown(pShmNode->h, sStat.st_uid, sStat.st_gid);
    +-  
    +-      /* Check to see if another process is holding the dead-man switch.
    +-      ** If not, truncate the file to zero length. 
    +-      */
    +-      rc = SQLITE_OK;
    +-      if( unixShmSystemLock(pDbFd, F_WRLCK, UNIX_SHM_DMS, 1)==SQLITE_OK ){
    +-        if( robust_ftruncate(pShmNode->h, 0) ){
    +-          rc = unixLogError(SQLITE_IOERR_SHMOPEN, "ftruncate", zShmFilename);
    +-        }
    +-      }
    +-      if( rc==SQLITE_OK ){
    +-        rc = unixShmSystemLock(pDbFd, F_RDLCK, UNIX_SHM_DMS, 1);
    +-      }
    +-      if( rc ) goto shm_open_err;
    ++      robustFchown(pShmNode->h, sStat.st_uid, sStat.st_gid);
    ++
    ++      rc = unixLockSharedMemory(pDbFd, pShmNode);
    ++      if( rc!=SQLITE_OK && rc!=SQLITE_READONLY_CANTINIT ) goto shm_open_err;
    +     }
    +   }
    + 
    +@@ -31000,7 +35218,7 @@ static int unixOpenSharedMemory(unixFile *pDbFd){
    +   p->pNext = pShmNode->pFirst;
    +   pShmNode->pFirst = p;
    +   sqlite3_mutex_leave(pShmNode->mutex);
    +-  return SQLITE_OK;
    ++  return rc;
    + 
    +   /* Jump here on any error */
    + shm_open_err:
    +@@ -31052,6 +35270,11 @@ static int unixShmMap(
    +   p = pDbFd->pShm;
    +   pShmNode = p->pShmNode;
    +   sqlite3_mutex_enter(pShmNode->mutex);
    ++  if( pShmNode->isUnlocked ){
    ++    rc = unixLockSharedMemory(pDbFd, pShmNode);
    ++    if( rc!=SQLITE_OK ) goto shmpage_out;
    ++    pShmNode->isUnlocked = 0;
    ++  }
    +   assert( szRegion==pShmNode->szRegion || pShmNode->nRegion==0 );
    +   assert( pShmNode->pInode==pDbFd->pInode );
    +   assert( pShmNode->h>=0 || pDbFd->pInode->bProcessLock==1 );
    +@@ -31099,7 +35322,8 @@ static int unixShmMap(
    +           /* Write to the last byte of each newly allocated or extended page */
    +           assert( (nByte % pgsz)==0 );
    +           for(iPg=(sStat.st_size/pgsz); iPg<(nByte/pgsz); iPg++){
    +-            if( seekAndWriteFd(pShmNode->h, iPg*pgsz + pgsz-1, "", 1, 0)!=1 ){
    ++            int x = 0;
    ++            if( seekAndWriteFd(pShmNode->h, iPg*pgsz + pgsz-1, "", 1, &x)!=1 ){
    +               const char *zFile = pShmNode->zFilename;
    +               rc = unixLogError(SQLITE_IOERR_SHMSIZE, "write", zFile);
    +               goto shmpage_out;
    +@@ -31114,7 +35338,7 @@ static int unixShmMap(
    +         pShmNode->apRegion, nReqRegion*sizeof(char *)
    +     );
    +     if( !apNew ){
    +-      rc = SQLITE_IOERR_NOMEM;
    ++      rc = SQLITE_IOERR_NOMEM_BKPT;
    +       goto shmpage_out;
    +     }
    +     pShmNode->apRegion = apNew;
    +@@ -31134,7 +35358,7 @@ static int unixShmMap(
    +       }else{
    +         pMem = sqlite3_malloc64(szRegion);
    +         if( pMem==0 ){
    +-          rc = SQLITE_NOMEM;
    ++          rc = SQLITE_NOMEM_BKPT;
    +           goto shmpage_out;
    +         }
    +         memset(pMem, 0, szRegion);
    +@@ -31393,7 +35617,9 @@ static void unixRemapfile(
    +   assert( pFd->mmapSizeActual>=pFd->mmapSize );
    +   assert( MAP_FAILED!=0 );
    + 
    ++#ifdef SQLITE_MMAP_READWRITE
    +   if( (pFd->ctrlFlags & UNIXFILE_RDONLY)==0 ) flags |= PROT_WRITE;
    ++#endif
    + 
    +   if( pOrig ){
    + #if HAVE_MREMAP
    +@@ -31465,17 +35691,14 @@ static void unixRemapfile(
    + ** recreated as a result of outstanding references) or an SQLite error
    + ** code otherwise.
    + */
    +-static int unixMapfile(unixFile *pFd, i64 nByte){
    +-  i64 nMap = nByte;
    +-  int rc;
    +-
    ++static int unixMapfile(unixFile *pFd, i64 nMap){
    +   assert( nMap>=0 || pFd->nFetchOut==0 );
    ++  assert( nMap>0 || (pFd->mmapSize==0 && pFd->pMapRegion==0) );
    +   if( pFd->nFetchOut>0 ) return SQLITE_OK;
    + 
    +   if( nMap<0 ){
    +     struct stat statbuf;          /* Low-level file information */
    +-    rc = osFstat(pFd->h, &statbuf);
    +-    if( rc!=SQLITE_OK ){
    ++    if( osFstat(pFd->h, &statbuf) ){
    +       return SQLITE_IOERR_FSTAT;
    +     }
    +     nMap = statbuf.st_size;
    +@@ -31484,12 +35707,9 @@ static int unixMapfile(unixFile *pFd, i64 nByte){
    +     nMap = pFd->mmapSizeMax;
    +   }
    + 
    ++  assert( nMap>0 || (pFd->mmapSize==0 && pFd->pMapRegion==0) );
    +   if( nMap!=pFd->mmapSize ){
    +-    if( nMap>0 ){
    +-      unixRemapfile(pFd, nMap);
    +-    }else{
    +-      unixUnmapfile(pFd);
    +-    }
    ++    unixRemapfile(pFd, nMap);
    +   }
    + 
    +   return SQLITE_OK;
    +@@ -31882,17 +36102,6 @@ static int fillInUnixFile(
    + 
    +   assert( pNew->pInode==NULL );
    + 
    +-  /* Usually the path zFilename should not be a relative pathname. The
    +-  ** exception is when opening the proxy "conch" file in builds that
    +-  ** include the special Apple locking styles.
    +-  */
    +-#if defined(__APPLE__) && SQLITE_ENABLE_LOCKING_STYLE
    +-  assert( zFilename==0 || zFilename[0]=='/' 
    +-    || pVfs->pAppData==(void*)&autolockIoFinder );
    +-#else
    +-  assert( zFilename==0 || zFilename[0]=='/' );
    +-#endif
    +-
    +   /* No locking occurs in temporary files */
    +   assert( zFilename!=0 || (ctrlFlags & UNIXFILE_NOLOCK)!=0 );
    + 
    +@@ -31916,7 +36125,7 @@ static int fillInUnixFile(
    +   pNew->pId = vxworksFindFileId(zFilename);
    +   if( pNew->pId==0 ){
    +     ctrlFlags |= UNIXFILE_NOLOCK;
    +-    rc = SQLITE_NOMEM;
    ++    rc = SQLITE_NOMEM_BKPT;
    +   }
    + #endif
    + 
    +@@ -31972,7 +36181,7 @@ static int fillInUnixFile(
    +     afpLockingContext *pCtx;
    +     pNew->lockingContext = pCtx = sqlite3_malloc64( sizeof(*pCtx) );
    +     if( pCtx==0 ){
    +-      rc = SQLITE_NOMEM;
    ++      rc = SQLITE_NOMEM_BKPT;
    +     }else{
    +       /* NB: zFilename exists and remains valid until the file is closed
    +       ** according to requirement F11141.  So we do not need to make a
    +@@ -32002,7 +36211,7 @@ static int fillInUnixFile(
    +     nFilename = (int)strlen(zFilename) + 6;
    +     zLockFile = (char *)sqlite3_malloc64(nFilename);
    +     if( zLockFile==0 ){
    +-      rc = SQLITE_NOMEM;
    ++      rc = SQLITE_NOMEM_BKPT;
    +     }else{
    +       sqlite3_snprintf(nFilename, zLockFile, "%s" DOTLOCK_SUFFIX, zFilename);
    +     }
    +@@ -32025,7 +36234,7 @@ static int fillInUnixFile(
    +         if( zSemName[n]=='/' ) zSemName[n] = '_';
    +       pNew->pInode->pSem = sem_open(zSemName, O_CREAT, 0666, 1);
    +       if( pNew->pInode->pSem == SEM_FAILED ){
    +-        rc = SQLITE_NOMEM;
    ++        rc = SQLITE_NOMEM_BKPT;
    +         pNew->pInode->aSemName[0] = '\0';
    +       }
    +     }
    +@@ -32058,29 +36267,31 @@ static int fillInUnixFile(
    + */
    + static const char *unixTempFileDir(void){
    +   static const char *azDirs[] = {
    +-     0,
    +      0,
    +      0,
    +      "/var/tmp",
    +      "/usr/tmp",
    +      "/tmp",
    +-     0        /* List terminator */
    ++     "."
    +   };
    +-  unsigned int i;
    ++  unsigned int i = 0;
    +   struct stat buf;
    +-  const char *zDir = 0;
    +-
    +-  azDirs[0] = sqlite3_temp_directory;
    +-  if( !azDirs[1] ) azDirs[1] = getenv("SQLITE_TMPDIR");
    +-  if( !azDirs[2] ) azDirs[2] = getenv("TMPDIR");
    +-  for(i=0; i<sizeof(azDirs)/sizeof(azDirs[0]); zDir=azDirs[i++]){
    +-    if( zDir==0 ) continue;
    +-    if( osStat(zDir, &buf) ) continue;
    +-    if( !S_ISDIR(buf.st_mode) ) continue;
    +-    if( osAccess(zDir, 07) ) continue;
    +-    break;
    ++  const char *zDir = sqlite3_temp_directory;
    ++
    ++  if( !azDirs[0] ) azDirs[0] = getenv("SQLITE_TMPDIR");
    ++  if( !azDirs[1] ) azDirs[1] = getenv("TMPDIR");
    ++  while(1){
    ++    if( zDir!=0
    ++     && osStat(zDir, &buf)==0
    ++     && S_ISDIR(buf.st_mode)
    ++     && osAccess(zDir, 03)==0
    ++    ){
    ++      return zDir;
    ++    }
    ++    if( i>=sizeof(azDirs)/sizeof(azDirs[0]) ) break;
    ++    zDir = azDirs[i++];
    +   }
    +-  return zDir;
    ++  return 0;
    + }
    + 
    + /*
    +@@ -32089,38 +36300,26 @@ static const char *unixTempFileDir(void){
    + ** pVfs->mxPathname bytes.
    + */
    + static int unixGetTempname(int nBuf, char *zBuf){
    +-  static const unsigned char zChars[] =
    +-    "abcdefghijklmnopqrstuvwxyz"
    +-    "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
    +-    "0123456789";
    +-  unsigned int i, j;
    +   const char *zDir;
    ++  int iLimit = 0;
    + 
    +   /* 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. 
    +   */
    ++  zBuf[0] = 0;
    +   SimulateIOError( return SQLITE_IOERR );
    + 
    +   zDir = unixTempFileDir();
    +-  if( zDir==0 ) zDir = ".";
    +-
    +-  /* Check that the output buffer is large enough for the temporary file 
    +-  ** name. If it is not, return SQLITE_ERROR.
    +-  */
    +-  if( (strlen(zDir) + strlen(SQLITE_TEMP_FILE_PREFIX) + 18) >= (size_t)nBuf ){
    +-    return SQLITE_ERROR;
    +-  }
    +-
    ++  if( zDir==0 ) return SQLITE_IOERR_GETTEMPPATH;
    +   do{
    +-    sqlite3_snprintf(nBuf-18, zBuf, "%s/"SQLITE_TEMP_FILE_PREFIX, zDir);
    +-    j = (int)strlen(zBuf);
    +-    sqlite3_randomness(15, &zBuf[j]);
    +-    for(i=0; i<15; i++, j++){
    +-      zBuf[j] = (char)zChars[ ((unsigned char)zBuf[j])%(sizeof(zChars)-1) ];
    +-    }
    +-    zBuf[j] = 0;
    +-    zBuf[j+1] = 0;
    ++    u64 r;
    ++    sqlite3_randomness(sizeof(r), &r);
    ++    assert( nBuf>2 );
    ++    zBuf[nBuf-2] = 0;
    ++    sqlite3_snprintf(nBuf, zBuf, "%s/"SQLITE_TEMP_FILE_PREFIX"%llx%c",
    ++                     zDir, r, 0);
    ++    if( zBuf[nBuf-2]!=0 || (iLimit++)>10 ) return SQLITE_ERROR;
    +   }while( osAccess(zBuf,0)==0 );
    +   return SQLITE_OK;
    + }
    +@@ -32161,6 +36360,8 @@ static UnixUnusedFd *findReusableFd(const char *zPath, int flags){
    + #if !OS_VXWORKS
    +   struct stat sStat;                   /* Results of stat() call */
    + 
    ++  unixEnterMutex();
    ++
    +   /* A stat() call may fail for various reasons. If this happens, it is
    +   ** almost certain that an open() call on the same path will also fail.
    +   ** For this reason, if an error occurs in the stat() call here, it is
    +@@ -32169,13 +36370,12 @@ static UnixUnusedFd *findReusableFd(const char *zPath, int flags){
    +   **
    +   ** Even if a subsequent open() call does succeed, the consequences of
    +   ** not searching for a reusable file descriptor are not dire.  */
    +-  if( 0==osStat(zPath, &sStat) ){
    ++  if( nUnusedFd>0 && 0==osStat(zPath, &sStat) ){
    +     unixInodeInfo *pInode;
    + 
    +-    unixEnterMutex();
    +     pInode = inodeList;
    +     while( pInode && (pInode->fileId.dev!=sStat.st_dev
    +-                     || pInode->fileId.ino!=sStat.st_ino) ){
    ++                     || pInode->fileId.ino!=(u64)sStat.st_ino) ){
    +        pInode = pInode->pNext;
    +     }
    +     if( pInode ){
    +@@ -32183,15 +36383,37 @@ static UnixUnusedFd *findReusableFd(const char *zPath, int flags){
    +       for(pp=&pInode->pUnused; *pp && (*pp)->flags!=flags; pp=&((*pp)->pNext));
    +       pUnused = *pp;
    +       if( pUnused ){
    ++        nUnusedFd--;
    +         *pp = pUnused->pNext;
    +       }
    +     }
    +-    unixLeaveMutex();
    +   }
    ++  unixLeaveMutex();
    + #endif    /* if !OS_VXWORKS */
    +   return pUnused;
    + }
    + 
    ++/*
    ++** Find the mode, uid and gid of file zFile. 
    ++*/
    ++static int getFileMode(
    ++  const char *zFile,              /* File name */
    ++  mode_t *pMode,                  /* OUT: Permissions of zFile */
    ++  uid_t *pUid,                    /* OUT: uid of zFile. */
    ++  gid_t *pGid                     /* OUT: gid of zFile. */
    ++){
    ++  struct stat sStat;              /* Output of stat() on database file */
    ++  int rc = SQLITE_OK;
    ++  if( 0==osStat(zFile, &sStat) ){
    ++    *pMode = sStat.st_mode & 0777;
    ++    *pUid = sStat.st_uid;
    ++    *pGid = sStat.st_gid;
    ++  }else{
    ++    rc = SQLITE_IOERR_FSTAT;
    ++  }
    ++  return rc;
    ++}
    ++
    + /*
    + ** This function is called by unixOpen() to determine the unix permissions
    + ** to create new files with. If no error occurs, then SQLITE_OK is returned
    +@@ -32227,7 +36449,6 @@ static int findCreateFileMode(
    +   if( flags & (SQLITE_OPEN_WAL|SQLITE_OPEN_MAIN_JOURNAL) ){
    +     char zDb[MAX_PATHNAME+1];     /* Database file path */
    +     int nDb;                      /* Number of valid bytes in zDb */
    +-    struct stat sStat;            /* Output of stat() on database file */
    + 
    +     /* zPath is a path to a WAL or journal file. The following block derives
    +     ** the path to the associated database file from zPath. This block handles
    +@@ -32242,28 +36463,29 @@ static int findCreateFileMode(
    +     ** used by the test_multiplex.c module.
    +     */
    +     nDb = sqlite3Strlen30(zPath) - 1; 
    +-#ifdef SQLITE_ENABLE_8_3_NAMES
    +-    while( nDb>0 && sqlite3Isalnum(zPath[nDb]) ) nDb--;
    +-    if( nDb==0 || zPath[nDb]!='-' ) return SQLITE_OK;
    +-#else
    +     while( zPath[nDb]!='-' ){
    +-      assert( nDb>0 );
    +-      assert( zPath[nDb]!='\n' );
    ++      /* In normal operation, the journal file name will always contain
    ++      ** a '-' character.  However in 8+3 filename mode, or if a corrupt
    ++      ** rollback journal specifies a master journal with a goofy name, then
    ++      ** the '-' might be missing. */
    ++      if( nDb==0 || zPath[nDb]=='.' ) return SQLITE_OK;
    +       nDb--;
    +     }
    +-#endif
    +     memcpy(zDb, zPath, nDb);
    +     zDb[nDb] = '\0';
    + 
    +-    if( 0==osStat(zDb, &sStat) ){
    +-      *pMode = sStat.st_mode & 0777;
    +-      *pUid = sStat.st_uid;
    +-      *pGid = sStat.st_gid;
    +-    }else{
    +-      rc = SQLITE_IOERR_FSTAT;
    +-    }
    ++    rc = getFileMode(zDb, pMode, pUid, pGid);
    +   }else if( flags & SQLITE_OPEN_DELETEONCLOSE ){
    +     *pMode = 0600;
    ++  }else if( flags & SQLITE_OPEN_URI ){
    ++    /* If this is a main database file and the file was opened using a URI
    ++    ** filename, check for the "modeof" parameter. If present, interpret
    ++    ** its value as a filename and try to copy the mode, uid and gid from
    ++    ** that file.  */
    ++    const char *z = sqlite3_uri_parameter(zPath, "modeof");
    ++    if( z ){
    ++      rc = getFileMode(z, pMode, pUid, pGid);
    ++    }
    +   }
    +   return rc;
    + }
    +@@ -32321,7 +36543,7 @@ static int unixOpen(
    +   ** a file-descriptor on the directory too. The first time unixSync()
    +   ** is called the directory file descriptor will be fsync()ed and close()d.
    +   */
    +-  int syncDir = (isCreate && (
    ++  int isNewJrnl = (isCreate && (
    +         eType==SQLITE_OPEN_MASTER_JOURNAL 
    +      || eType==SQLITE_OPEN_MAIN_JOURNAL 
    +      || eType==SQLITE_OPEN_WAL
    +@@ -32379,10 +36601,10 @@ static int unixOpen(
    +     }else{
    +       pUnused = sqlite3_malloc64(sizeof(*pUnused));
    +       if( !pUnused ){
    +-        return SQLITE_NOMEM;
    ++        return SQLITE_NOMEM_BKPT;
    +       }
    +     }
    +-    p->pUnused = pUnused;
    ++    p->pPreallocatedUnused = pUnused;
    + 
    +     /* Database filenames are double-zero terminated if they are not
    +     ** URIs with parameters.  Hence, they can always be passed into
    +@@ -32391,8 +36613,8 @@ static int unixOpen(
    + 
    +   }else if( !zName ){
    +     /* If zName is NULL, the upper layer is requesting a temp file. */
    +-    assert(isDelete && !syncDir);
    +-    rc = unixGetTempname(MAX_PATHNAME+2, zTmpname);
    ++    assert(isDelete && !isNewJrnl);
    ++    rc = unixGetTempname(pVfs->mxPathname, zTmpname);
    +     if( rc!=SQLITE_OK ){
    +       return rc;
    +     }
    +@@ -32419,23 +36641,31 @@ static int unixOpen(
    +     gid_t gid;                    /* Groupid for the file */
    +     rc = findCreateFileMode(zName, flags, &openMode, &uid, &gid);
    +     if( rc!=SQLITE_OK ){
    +-      assert( !p->pUnused );
    ++      assert( !p->pPreallocatedUnused );
    +       assert( eType==SQLITE_OPEN_WAL || eType==SQLITE_OPEN_MAIN_JOURNAL );
    +       return rc;
    +     }
    +     fd = robust_open(zName, openFlags, openMode);
    +     OSTRACE(("OPENX   %-3d %s 0%o\n", fd, zName, openFlags));
    +-    if( fd<0 && errno!=EISDIR && isReadWrite && !isExclusive ){
    +-      /* Failed to open the file for read/write access. Try read-only. */
    +-      flags &= ~(SQLITE_OPEN_READWRITE|SQLITE_OPEN_CREATE);
    +-      openFlags &= ~(O_RDWR|O_CREAT);
    +-      flags |= SQLITE_OPEN_READONLY;
    +-      openFlags |= O_RDONLY;
    +-      isReadonly = 1;
    +-      fd = robust_open(zName, openFlags, openMode);
    ++    assert( !isExclusive || (openFlags & O_CREAT)!=0 );
    ++    if( fd<0 ){
    ++      if( isNewJrnl && errno==EACCES && osAccess(zName, F_OK) ){
    ++        /* If unable to create a journal because the directory is not
    ++        ** writable, change the error code to indicate that. */
    ++        rc = SQLITE_READONLY_DIRECTORY;
    ++      }else if( errno!=EISDIR && isReadWrite ){
    ++        /* Failed to open the file for read/write access. Try read-only. */
    ++        flags &= ~(SQLITE_OPEN_READWRITE|SQLITE_OPEN_CREATE);
    ++        openFlags &= ~(O_RDWR|O_CREAT);
    ++        flags |= SQLITE_OPEN_READONLY;
    ++        openFlags |= O_RDONLY;
    ++        isReadonly = 1;
    ++        fd = robust_open(zName, openFlags, openMode);
    ++      }
    +     }
    +     if( fd<0 ){
    +-      rc = unixLogError(SQLITE_CANTOPEN_BKPT, "open", zName);
    ++      int rc2 = unixLogError(SQLITE_CANTOPEN_BKPT, "open", zName);
    ++      if( rc==SQLITE_OK ) rc = rc2;
    +       goto open_finished;
    +     }
    + 
    +@@ -32444,7 +36674,7 @@ static int unixOpen(
    +     ** the same as the original database.
    +     */
    +     if( flags & (SQLITE_OPEN_WAL|SQLITE_OPEN_MAIN_JOURNAL) ){
    +-      osFchown(fd, uid, gid);
    ++      robustFchown(fd, uid, gid);
    +     }
    +   }
    +   assert( fd>=0 );
    +@@ -32452,9 +36682,9 @@ static int unixOpen(
    +     *pOutFlags = flags;
    +   }
    + 
    +-  if( p->pUnused ){
    +-    p->pUnused->fd = fd;
    +-    p->pUnused->flags = flags;
    ++  if( p->pPreallocatedUnused ){
    ++    p->pPreallocatedUnused->fd = fd;
    ++    p->pPreallocatedUnused->flags = flags;
    +   }
    + 
    +   if( isDelete ){
    +@@ -32464,7 +36694,7 @@ static int unixOpen(
    +     zPath = sqlite3_mprintf("%s", zName);
    +     if( zPath==0 ){
    +       robust_close(p, fd, __LINE__);
    +-      return SQLITE_NOMEM;
    ++      return SQLITE_NOMEM_BKPT;
    +     }
    + #else
    +     osUnlink(zName);
    +@@ -32475,9 +36705,6 @@ static int unixOpen(
    +     p->openFlags = openFlags;
    +   }
    + #endif
    +-
    +-  noLock = eType!=SQLITE_OPEN_MAIN_DB;
    +-
    +   
    + #if defined(__APPLE__) || SQLITE_ENABLE_LOCKING_STYLE
    +   if( fstatfs(fd, &fsInfo) == -1 ){
    +@@ -32496,8 +36723,9 @@ static int unixOpen(
    +   /* Set up appropriate ctrlFlags */
    +   if( isDelete )                ctrlFlags |= UNIXFILE_DELETE;
    +   if( isReadonly )              ctrlFlags |= UNIXFILE_RDONLY;
    ++  noLock = eType!=SQLITE_OPEN_MAIN_DB;
    +   if( noLock )                  ctrlFlags |= UNIXFILE_NOLOCK;
    +-  if( syncDir )                 ctrlFlags |= UNIXFILE_DIRSYNC;
    ++  if( isNewJrnl )               ctrlFlags |= UNIXFILE_DIRSYNC;
    +   if( flags & SQLITE_OPEN_URI ) ctrlFlags |= UNIXFILE_URI;
    + 
    + #if SQLITE_ENABLE_LOCKING_STYLE
    +@@ -32533,11 +36761,14 @@ static int unixOpen(
    +   }
    + #endif
    +   
    ++  assert( zPath==0 || zPath[0]=='/' 
    ++      || eType==SQLITE_OPEN_MASTER_JOURNAL || eType==SQLITE_OPEN_MAIN_JOURNAL 
    ++  );
    +   rc = fillInUnixFile(pVfs, fd, pFile, zPath, ctrlFlags);
    + 
    + open_finished:
    +   if( rc!=SQLITE_OK ){
    +-    sqlite3_free(p->pUnused);
    ++    sqlite3_free(p->pPreallocatedUnused);
    +   }
    +   return rc;
    + }
    +@@ -32572,16 +36803,12 @@ static int unixDelete(
    +     int fd;
    +     rc = osOpenDirectory(zPath, &fd);
    +     if( rc==SQLITE_OK ){
    +-#if OS_VXWORKS
    +-      if( fsync(fd)==-1 )
    +-#else
    +-      if( fsync(fd) )
    +-#endif
    +-      {
    ++      if( full_fsync(fd,0,0) ){
    +         rc = unixLogError(SQLITE_IOERR_DIR_FSYNC, "fsync", zPath);
    +       }
    +       robust_close(0, fd, __LINE__);
    +-    }else if( rc==SQLITE_CANTOPEN ){
    ++    }else{
    ++      assert( rc==SQLITE_CANTOPEN );
    +       rc = SQLITE_OK;
    +     }
    +   }
    +@@ -32605,33 +36832,49 @@ static int unixAccess(
    +   int flags,              /* What do we want to learn about the zPath file? */
    +   int *pResOut            /* Write result boolean here */
    + ){
    +-  int amode = 0;
    +   UNUSED_PARAMETER(NotUsed);
    +   SimulateIOError( return SQLITE_IOERR_ACCESS; );
    +-  switch( flags ){
    +-    case SQLITE_ACCESS_EXISTS:
    +-      amode = F_OK;
    +-      break;
    +-    case SQLITE_ACCESS_READWRITE:
    +-      amode = W_OK|R_OK;
    +-      break;
    +-    case SQLITE_ACCESS_READ:
    +-      amode = R_OK;
    +-      break;
    ++  assert( pResOut!=0 );
    + 
    +-    default:
    +-      assert(!"Invalid flags argument");
    +-  }
    +-  *pResOut = (osAccess(zPath, amode)==0);
    +-  if( flags==SQLITE_ACCESS_EXISTS && *pResOut ){
    ++  /* The spec says there are three possible values for flags.  But only
    ++  ** two of them are actually used */
    ++  assert( flags==SQLITE_ACCESS_EXISTS || flags==SQLITE_ACCESS_READWRITE );
    ++
    ++  if( flags==SQLITE_ACCESS_EXISTS ){
    +     struct stat buf;
    +-    if( 0==osStat(zPath, &buf) && buf.st_size==0 ){
    +-      *pResOut = 0;
    +-    }
    ++    *pResOut = (0==osStat(zPath, &buf) && buf.st_size>0);
    ++  }else{
    ++    *pResOut = osAccess(zPath, W_OK|R_OK)==0;
    +   }
    +   return SQLITE_OK;
    + }
    + 
    ++/*
    ++**
    ++*/
    ++static int mkFullPathname(
    ++  const char *zPath,              /* Input path */
    ++  char *zOut,                     /* Output buffer */
    ++  int nOut                        /* Allocated size of buffer zOut */
    ++){
    ++  int nPath = sqlite3Strlen30(zPath);
    ++  int iOff = 0;
    ++  if( zPath[0]!='/' ){
    ++    if( osGetcwd(zOut, nOut-2)==0 ){
    ++      return unixLogError(SQLITE_CANTOPEN_BKPT, "getcwd", zPath);
    ++    }
    ++    iOff = sqlite3Strlen30(zOut);
    ++    zOut[iOff++] = '/';
    ++  }
    ++  if( (iOff+nPath+1)>nOut ){
    ++    /* SQLite assumes that xFullPathname() nul-terminates the output buffer
    ++    ** even if it returns an error.  */
    ++    zOut[iOff] = '\0';
    ++    return SQLITE_CANTOPEN_BKPT;
    ++  }
    ++  sqlite3_snprintf(nOut-iOff, &zOut[iOff], "%s", zPath);
    ++  return SQLITE_OK;
    ++}
    + 
    + /*
    + ** Turn a relative pathname into a full pathname. The relative path
    +@@ -32648,6 +36891,17 @@ static int unixFullPathname(
    +   int nOut,                     /* Size of output buffer in bytes */
    +   char *zOut                    /* Output buffer */
    + ){
    ++#if !defined(HAVE_READLINK) || !defined(HAVE_LSTAT)
    ++  return mkFullPathname(zPath, zOut, nOut);
    ++#else
    ++  int rc = SQLITE_OK;
    ++  int nByte;
    ++  int nLink = 1;                /* Number of symbolic links followed so far */
    ++  const char *zIn = zPath;      /* Input path for each iteration of loop */
    ++  char *zDel = 0;
    ++
    ++  assert( pVfs->mxPathname==MAX_PATHNAME );
    ++  UNUSED_PARAMETER(pVfs);
    + 
    +   /* 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
    +@@ -32656,21 +36910,62 @@ static int unixFullPathname(
    +   */
    +   SimulateIOError( return SQLITE_ERROR );
    + 
    +-  assert( pVfs->mxPathname==MAX_PATHNAME );
    +-  UNUSED_PARAMETER(pVfs);
    ++  do {
    + 
    +-  zOut[nOut-1] = '\0';
    +-  if( zPath[0]=='/' ){
    +-    sqlite3_snprintf(nOut, zOut, "%s", zPath);
    +-  }else{
    +-    int nCwd;
    +-    if( osGetcwd(zOut, nOut-1)==0 ){
    +-      return unixLogError(SQLITE_CANTOPEN_BKPT, "getcwd", zPath);
    ++    /* Call stat() on path zIn. Set bLink to true if the path is a symbolic
    ++    ** link, or false otherwise.  */
    ++    int bLink = 0;
    ++    struct stat buf;
    ++    if( osLstat(zIn, &buf)!=0 ){
    ++      if( errno!=ENOENT ){
    ++        rc = unixLogError(SQLITE_CANTOPEN_BKPT, "lstat", zIn);
    ++      }
    ++    }else{
    ++      bLink = S_ISLNK(buf.st_mode);
    +     }
    +-    nCwd = (int)strlen(zOut);
    +-    sqlite3_snprintf(nOut-nCwd, &zOut[nCwd], "/%s", zPath);
    +-  }
    +-  return SQLITE_OK;
    ++
    ++    if( bLink ){
    ++      if( zDel==0 ){
    ++        zDel = sqlite3_malloc(nOut);
    ++        if( zDel==0 ) rc = SQLITE_NOMEM_BKPT;
    ++      }else if( ++nLink>SQLITE_MAX_SYMLINKS ){
    ++        rc = SQLITE_CANTOPEN_BKPT;
    ++      }
    ++
    ++      if( rc==SQLITE_OK ){
    ++        nByte = osReadlink(zIn, zDel, nOut-1);
    ++        if( nByte<0 ){
    ++          rc = unixLogError(SQLITE_CANTOPEN_BKPT, "readlink", zIn);
    ++        }else{
    ++          if( zDel[0]!='/' ){
    ++            int n;
    ++            for(n = sqlite3Strlen30(zIn); n>0 && zIn[n-1]!='/'; n--);
    ++            if( nByte+n+1>nOut ){
    ++              rc = SQLITE_CANTOPEN_BKPT;
    ++            }else{
    ++              memmove(&zDel[n], zDel, nByte+1);
    ++              memcpy(zDel, zIn, n);
    ++              nByte += n;
    ++            }
    ++          }
    ++          zDel[nByte] = '\0';
    ++        }
    ++      }
    ++
    ++      zIn = zDel;
    ++    }
    ++
    ++    assert( rc!=SQLITE_OK || zIn!=zOut || zIn[0]=='/' );
    ++    if( rc==SQLITE_OK && zIn!=zOut ){
    ++      rc = mkFullPathname(zIn, zOut, nOut);
    ++    }
    ++    if( bLink==0 ) break;
    ++    zIn = zOut;
    ++  }while( rc==SQLITE_OK );
    ++
    ++  sqlite3_free(zDel);
    ++  return rc;
    ++#endif   /* HAVE_READLINK && HAVE_LSTAT */
    + }
    + 
    + 
    +@@ -32839,11 +37134,8 @@ static int unixCurrentTimeInt64(sqlite3_vfs *NotUsed, sqlite3_int64 *piNow){
    +   *piNow = unixEpoch + 1000*(sqlite3_int64)sNow.tv_sec + sNow.tv_nsec/1000000;
    + #else
    +   struct timeval sNow;
    +-  if( gettimeofday(&sNow, 0)==0 ){
    +-    *piNow = unixEpoch + 1000*(sqlite3_int64)sNow.tv_sec + sNow.tv_usec/1000;
    +-  }else{
    +-    rc = SQLITE_ERROR;
    +-  }
    ++  (void)gettimeofday(&sNow, 0);  /* Cannot fail given valid arguments */
    ++  *piNow = unixEpoch + 1000*(sqlite3_int64)sNow.tv_sec + sNow.tv_usec/1000;
    + #endif
    + 
    + #ifdef SQLITE_TEST
    +@@ -32855,6 +37147,7 @@ static int unixCurrentTimeInt64(sqlite3_vfs *NotUsed, sqlite3_int64 *piNow){
    +   return rc;
    + }
    + 
    ++#ifndef SQLITE_OMIT_DEPRECATED
    + /*
    + ** Find the current time (in Universal Coordinated Time).  Write the
    + ** current time and date as a Julian Day number into *prNow and
    +@@ -32868,19 +37161,21 @@ static int unixCurrentTime(sqlite3_vfs *NotUsed, double *prNow){
    +   *prNow = i/86400000.0;
    +   return rc;
    + }
    ++#else
    ++# define unixCurrentTime 0
    ++#endif
    + 
    + /*
    +-** We added the xGetLastError() method with the intention of providing
    +-** better low-level error messages when operating-system problems come up
    +-** during SQLite operation.  But so far, none of that has been implemented
    +-** in the core.  So this routine is never called.  For now, it is merely
    +-** a place-holder.
    ++** The xGetLastError() method is designed to return a better
    ++** low-level error message when operating-system problems come up
    ++** during SQLite operation.  Only the integer return code is currently
    ++** used.
    + */
    + static int unixGetLastError(sqlite3_vfs *NotUsed, int NotUsed2, char *NotUsed3){
    +   UNUSED_PARAMETER(NotUsed);
    +   UNUSED_PARAMETER(NotUsed2);
    +   UNUSED_PARAMETER(NotUsed3);
    +-  return 0;
    ++  return errno;
    + }
    + 
    + 
    +@@ -33135,7 +37430,7 @@ static int proxyCreateLockPath(const char *lockPath){
    +     }
    +     buf[i] = lockPath[i];
    +   }
    +-  OSTRACE(("CREATELOCKPATH  proxy lock path=%s pid=%d\n", lockPath, osGetpid(0)));
    ++  OSTRACE(("CREATELOCKPATH  proxy lock path=%s pid=%d\n",lockPath,osGetpid(0)));
    +   return 0;
    + }
    + 
    +@@ -33171,7 +37466,7 @@ static int proxyCreateUnixFile(
    +   }else{
    +     pUnused = sqlite3_malloc64(sizeof(*pUnused));
    +     if( !pUnused ){
    +-      return SQLITE_NOMEM;
    ++      return SQLITE_NOMEM_BKPT;
    +     }
    +   }
    +   if( fd<0 ){
    +@@ -33204,7 +37499,7 @@ static int proxyCreateUnixFile(
    +   
    +   pNew = (unixFile *)sqlite3_malloc64(sizeof(*pNew));
    +   if( pNew==NULL ){
    +-    rc = SQLITE_NOMEM;
    ++    rc = SQLITE_NOMEM_BKPT;
    +     goto end_create_proxy;
    +   }
    +   memset(pNew, 0, sizeof(unixFile));
    +@@ -33214,7 +37509,7 @@ static int proxyCreateUnixFile(
    +   dummyVfs.zName = "dummy";
    +   pUnused->fd = fd;
    +   pUnused->flags = openFlags;
    +-  pNew->pUnused = pUnused;
    ++  pNew->pPreallocatedUnused = pUnused;
    +   
    +   rc = fillInUnixFile(&dummyVfs, fd, (sqlite3_file*)pNew, path, 0);
    +   if( rc==SQLITE_OK ){
    +@@ -33547,7 +37842,7 @@ static int proxyTakeConch(unixFile *pFile){
    +         writeSize = PROXY_PATHINDEX + strlen(&writeBuffer[PROXY_PATHINDEX]);
    +         robust_ftruncate(conchFile->h, writeSize);
    +         rc = unixWrite((sqlite3_file *)conchFile, writeBuffer, writeSize, 0);
    +-        fsync(conchFile->h);
    ++        full_fsync(conchFile->h,0,0);
    +         /* If we created a new conch file (not just updated the contents of a 
    +          ** valid conch file), try to match the permissions of the database 
    +          */
    +@@ -33617,7 +37912,7 @@ static int proxyTakeConch(unixFile *pFile){
    +         if( tempLockPath ){
    +           pCtx->lockProxyPath = sqlite3DbStrDup(0, tempLockPath);
    +           if( !pCtx->lockProxyPath ){
    +-            rc = SQLITE_NOMEM;
    ++            rc = SQLITE_NOMEM_BKPT;
    +           }
    +         }
    +       }
    +@@ -33682,7 +37977,7 @@ static int proxyCreateConchPathname(char *dbPath, char **pConchPath){
    +   ** the name of the original database file. */  
    +   *pConchPath = conchPath = (char *)sqlite3_malloc64(len + 8);
    +   if( conchPath==0 ){
    +-    return SQLITE_NOMEM;
    ++    return SQLITE_NOMEM_BKPT;
    +   }
    +   memcpy(conchPath, dbPath, len+1);
    +   
    +@@ -33798,7 +38093,7 @@ static int proxyTransformUnixFile(unixFile *pFile, const char *path) {
    + 
    +   pCtx = sqlite3_malloc64( sizeof(*pCtx) );
    +   if( pCtx==0 ){
    +-    return SQLITE_NOMEM;
    ++    return SQLITE_NOMEM_BKPT;
    +   }
    +   memset(pCtx, 0, sizeof(*pCtx));
    + 
    +@@ -33834,7 +38129,7 @@ static int proxyTransformUnixFile(unixFile *pFile, const char *path) {
    +   if( rc==SQLITE_OK ){
    +     pCtx->dbPath = sqlite3DbStrDup(0, dbPath);
    +     if( pCtx->dbPath==NULL ){
    +-      rc = SQLITE_NOMEM;
    ++      rc = SQLITE_NOMEM_BKPT;
    +     }
    +   }
    +   if( rc==SQLITE_OK ){
    +@@ -34020,7 +38315,7 @@ static int proxyUnlock(sqlite3_file *id, int eFileLock) {
    + ** Close a file that uses proxy locks.
    + */
    + static int proxyClose(sqlite3_file *id) {
    +-  if( id ){
    ++  if( ALWAYS(id) ){
    +     unixFile *pFile = (unixFile*)id;
    +     proxyLockingContext *pCtx = (proxyLockingContext *)pFile->lockingContext;
    +     unixFile *lockProxy = pCtx->lockProxy;
    +@@ -34081,7 +38376,7 @@ static int proxyClose(sqlite3_file *id) {
    + ** necessarily been initialized when this routine is called, and so they
    + ** should not be used.
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_os_init(void){ 
    ++SQLITE_API int sqlite3_os_init(void){ 
    +   /* 
    +   ** The following macro defines an initializer for an sqlite3_vfs object.
    +   ** The name of the VFS is NAME.  The pAppData is a pointer to a pointer
    +@@ -34164,7 +38459,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_os_init(void){
    + 
    +   /* Double-check that the aSyscall[] array has been constructed
    +   ** correctly.  See ticket [bb3a86e890c8e96ab] */
    +-  assert( ArraySize(aSyscall)==25 );
    ++  assert( ArraySize(aSyscall)==29 );
    + 
    +   /* Register all VFSes defined in the aVfs[] array */
    +   for(i=0; i<(sizeof(aVfs)/sizeof(sqlite3_vfs)); i++){
    +@@ -34180,7 +38475,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_os_init(void){
    + ** to release dynamically allocated objects.  But not on unix.
    + ** This routine is a no-op for unix.
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_os_end(void){ 
    ++SQLITE_API int sqlite3_os_end(void){ 
    +   return SQLITE_OK; 
    + }
    +  
    +@@ -34247,8 +38542,8 @@ SQLITE_API int SQLITE_STDCALL sqlite3_os_end(void){
    + */
    + #ifdef SQLITE_PERFORMANCE_TRACE
    + 
    +-/* 
    +-** hwtime.h contains inline assembler code for implementing 
    ++/*
    ++** hwtime.h contains inline assembler code for implementing
    + ** high-performance timing routines.
    + */
    + /************** Include hwtime.h in the middle of os_common.h ****************/
    +@@ -34268,8 +38563,8 @@ SQLITE_API int SQLITE_STDCALL sqlite3_os_end(void){
    + ** This file contains inline asm code for retrieving "high-performance"
    + ** counters for x86 class CPUs.
    + */
    +-#ifndef _HWTIME_H_
    +-#define _HWTIME_H_
    ++#ifndef SQLITE_HWTIME_H
    ++#define SQLITE_HWTIME_H
    + 
    + /*
    + ** The following routine only works on pentium-class (or newer) processors.
    +@@ -34337,7 +38632,7 @@ SQLITE_PRIVATE   sqlite_uint64 sqlite3Hwtime(void){ return ((sqlite_uint64)0); }
    + 
    + #endif
    + 
    +-#endif /* !defined(_HWTIME_H_) */
    ++#endif /* !defined(SQLITE_HWTIME_H) */
    + 
    + /************** End of hwtime.h **********************************************/
    + /************** Continuing where we left off in os_common.h ******************/
    +@@ -34358,14 +38653,14 @@ static sqlite_uint64 g_elapsed;
    + ** 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;
    ++#if defined(SQLITE_TEST)
    ++SQLITE_API extern int sqlite3_io_error_hit;
    ++SQLITE_API extern int sqlite3_io_error_hardhit;
    ++SQLITE_API extern int sqlite3_io_error_pending;
    ++SQLITE_API extern int sqlite3_io_error_persist;
    ++SQLITE_API extern int sqlite3_io_error_benign;
    ++SQLITE_API extern int sqlite3_diskfull_pending;
    ++SQLITE_API extern int sqlite3_diskfull;
    + #define SimulateIOErrorBenign(X) sqlite3_io_error_benign=(X)
    + #define SimulateIOError(CODE)  \
    +   if( (sqlite3_io_error_persist && sqlite3_io_error_hit) \
    +@@ -34391,17 +38686,17 @@ static void local_ioerr(){
    + #define SimulateIOErrorBenign(X)
    + #define SimulateIOError(A)
    + #define SimulateDiskfullError(A)
    +-#endif
    ++#endif /* defined(SQLITE_TEST) */
    + 
    + /*
    + ** When testing, keep a count of the number of open files.
    + */
    +-#ifdef SQLITE_TEST
    +-SQLITE_API int sqlite3_open_file_count = 0;
    ++#if defined(SQLITE_TEST)
    ++SQLITE_API extern int sqlite3_open_file_count;
    + #define OpenCounter(X)  sqlite3_open_file_count+=(X)
    + #else
    + #define OpenCounter(X)
    +-#endif
    ++#endif /* defined(SQLITE_TEST) */
    + 
    + #endif /* !defined(_OS_COMMON_H_) */
    + 
    +@@ -34464,6 +38759,10 @@ SQLITE_API int sqlite3_open_file_count = 0;
    + #  define NTDDI_WINBLUE                     0x06030000
    + #endif
    + 
    ++#ifndef NTDDI_WINTHRESHOLD
    ++#  define NTDDI_WINTHRESHOLD                0x06040000
    ++#endif
    ++
    + /*
    + ** Check to see if the GetVersionEx[AW] functions are deprecated on the
    + ** target system.  GetVersionEx was first deprecated in Win8.1.
    +@@ -34476,6 +38775,19 @@ SQLITE_API int sqlite3_open_file_count = 0;
    + #  endif
    + #endif
    + 
    ++/*
    ++** Check to see if the CreateFileMappingA function is supported on the
    ++** target system.  It is unavailable when using "mincore.lib" on Win10.
    ++** When compiling for Windows 10, always assume "mincore.lib" is in use.
    ++*/
    ++#ifndef SQLITE_WIN32_CREATEFILEMAPPINGA
    ++#  if defined(NTDDI_VERSION) && NTDDI_VERSION >= NTDDI_WINTHRESHOLD
    ++#    define SQLITE_WIN32_CREATEFILEMAPPINGA   0
    ++#  else
    ++#    define SQLITE_WIN32_CREATEFILEMAPPINGA   1
    ++#  endif
    ++#endif
    ++
    + /*
    + ** This constant should already be defined (in the "WinDef.h" SDK file).
    + */
    +@@ -34661,6 +38973,17 @@ struct winFile {
    + #endif
    + };
    + 
    ++/*
    ++** The winVfsAppData structure is used for the pAppData member for all of the
    ++** Win32 VFS variants.
    ++*/
    ++typedef struct winVfsAppData winVfsAppData;
    ++struct winVfsAppData {
    ++  const sqlite3_io_methods *pMethod; /* The file I/O methods to use. */
    ++  void *pAppData;                    /* The extra pAppData, if any. */
    ++  BOOL bNoLock;                      /* Non-zero if locking is disabled. */
    ++};
    ++
    + /*
    + ** Allowed values for winFile.ctrlFlags
    + */
    +@@ -34712,22 +39035,72 @@ struct winFile {
    +  ******************************************************************************
    +  */
    + #ifndef SQLITE_WIN32_HEAP_CREATE
    +-#  define SQLITE_WIN32_HEAP_CREATE    (TRUE)
    ++#  define SQLITE_WIN32_HEAP_CREATE        (TRUE)
    ++#endif
    ++
    ++/*
    ++ * This is the maximum possible initial size of the Win32-specific heap, in
    ++ * bytes.
    ++ */
    ++#ifndef SQLITE_WIN32_HEAP_MAX_INIT_SIZE
    ++#  define SQLITE_WIN32_HEAP_MAX_INIT_SIZE (4294967295U)
    ++#endif
    ++
    ++/*
    ++ * This is the extra space for the initial size of the Win32-specific heap,
    ++ * in bytes.  This value may be zero.
    ++ */
    ++#ifndef SQLITE_WIN32_HEAP_INIT_EXTRA
    ++#  define SQLITE_WIN32_HEAP_INIT_EXTRA  (4194304)
    ++#endif
    ++
    ++/*
    ++ * Calculate the maximum legal cache size, in pages, based on the maximum
    ++ * possible initial heap size and the default page size, setting aside the
    ++ * needed extra space.
    ++ */
    ++#ifndef SQLITE_WIN32_MAX_CACHE_SIZE
    ++#  define SQLITE_WIN32_MAX_CACHE_SIZE   (((SQLITE_WIN32_HEAP_MAX_INIT_SIZE) - \
    ++                                          (SQLITE_WIN32_HEAP_INIT_EXTRA)) / \
    ++                                         (SQLITE_DEFAULT_PAGE_SIZE))
    ++#endif
    ++
    ++/*
    ++ * This is cache size used in the calculation of the initial size of the
    ++ * Win32-specific heap.  It cannot be negative.
    ++ */
    ++#ifndef SQLITE_WIN32_CACHE_SIZE
    ++#  if SQLITE_DEFAULT_CACHE_SIZE>=0
    ++#    define SQLITE_WIN32_CACHE_SIZE     (SQLITE_DEFAULT_CACHE_SIZE)
    ++#  else
    ++#    define SQLITE_WIN32_CACHE_SIZE     (-(SQLITE_DEFAULT_CACHE_SIZE))
    ++#  endif
    ++#endif
    ++
    ++/*
    ++ * Make sure that the calculated cache size, in pages, cannot cause the
    ++ * initial size of the Win32-specific heap to exceed the maximum amount
    ++ * of memory that can be specified in the call to HeapCreate.
    ++ */
    ++#if SQLITE_WIN32_CACHE_SIZE>SQLITE_WIN32_MAX_CACHE_SIZE
    ++#  undef SQLITE_WIN32_CACHE_SIZE
    ++#  define SQLITE_WIN32_CACHE_SIZE       (2000)
    + #endif
    + 
    + /*
    +  * The initial size of the Win32-specific heap.  This value may be zero.
    +  */
    + #ifndef SQLITE_WIN32_HEAP_INIT_SIZE
    +-#  define SQLITE_WIN32_HEAP_INIT_SIZE ((SQLITE_DEFAULT_CACHE_SIZE) * \
    +-                                       (SQLITE_DEFAULT_PAGE_SIZE) + 4194304)
    ++#  define SQLITE_WIN32_HEAP_INIT_SIZE   ((SQLITE_WIN32_CACHE_SIZE) * \
    ++                                         (SQLITE_DEFAULT_PAGE_SIZE) + \
    ++                                         (SQLITE_WIN32_HEAP_INIT_EXTRA))
    + #endif
    + 
    + /*
    +  * The maximum size of the Win32-specific heap.  This value may be zero.
    +  */
    + #ifndef SQLITE_WIN32_HEAP_MAX_SIZE
    +-#  define SQLITE_WIN32_HEAP_MAX_SIZE  (0)
    ++#  define SQLITE_WIN32_HEAP_MAX_SIZE    (0)
    + #endif
    + 
    + /*
    +@@ -34735,7 +39108,7 @@ struct winFile {
    +  * zero for the default behavior.
    +  */
    + #ifndef SQLITE_WIN32_HEAP_FLAGS
    +-#  define SQLITE_WIN32_HEAP_FLAGS     (0)
    ++#  define SQLITE_WIN32_HEAP_FLAGS       (0)
    + #endif
    + 
    + 
    +@@ -34882,8 +39255,9 @@ static struct win_syscall {
    + #define osCreateFileW ((HANDLE(WINAPI*)(LPCWSTR,DWORD,DWORD, \
    +         LPSECURITY_ATTRIBUTES,DWORD,DWORD,HANDLE))aSyscall[5].pCurrent)
    + 
    +-#if (!SQLITE_OS_WINRT && defined(SQLITE_WIN32_HAS_ANSI) && \
    +-        (!defined(SQLITE_OMIT_WAL) || SQLITE_MAX_MMAP_SIZE>0))
    ++#if !SQLITE_OS_WINRT && defined(SQLITE_WIN32_HAS_ANSI) && \
    ++        (!defined(SQLITE_OMIT_WAL) || SQLITE_MAX_MMAP_SIZE>0) && \
    ++        SQLITE_WIN32_CREATEFILEMAPPINGA
    +   { "CreateFileMappingA",      (SYSCALL)CreateFileMappingA,      0 },
    + #else
    +   { "CreateFileMappingA",      (SYSCALL)0,                       0 },
    +@@ -35113,8 +39487,7 @@ static struct win_syscall {
    + 
    + #define osGetTickCount ((DWORD(WINAPI*)(VOID))aSyscall[33].pCurrent)
    + 
    +-#if defined(SQLITE_WIN32_HAS_ANSI) && defined(SQLITE_WIN32_GETVERSIONEX) && \
    +-        SQLITE_WIN32_GETVERSIONEX
    ++#if defined(SQLITE_WIN32_HAS_ANSI) && SQLITE_WIN32_GETVERSIONEX
    +   { "GetVersionExA",           (SYSCALL)GetVersionExA,           0 },
    + #else
    +   { "GetVersionExA",           (SYSCALL)0,                       0 },
    +@@ -35124,7 +39497,7 @@ static struct win_syscall {
    +         LPOSVERSIONINFOA))aSyscall[34].pCurrent)
    + 
    + #if !SQLITE_OS_WINRT && defined(SQLITE_WIN32_HAS_WIDE) && \
    +-        defined(SQLITE_WIN32_GETVERSIONEX) && SQLITE_WIN32_GETVERSIONEX
    ++        SQLITE_WIN32_GETVERSIONEX
    +   { "GetVersionExW",           (SYSCALL)GetVersionExW,           0 },
    + #else
    +   { "GetVersionExW",           (SYSCALL)0,                       0 },
    +@@ -35575,7 +39948,7 @@ static const char *winNextSystemCall(sqlite3_vfs *p, const char *zName){
    + ** "pnLargest" argument, if non-zero, will be used to return the size of the
    + ** largest committed free block in the heap, in bytes.
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_win32_compact_heap(LPUINT pnLargest){
    ++SQLITE_API int sqlite3_win32_compact_heap(LPUINT pnLargest){
    +   int rc = SQLITE_OK;
    +   UINT nLargest = 0;
    +   HANDLE hHeap;
    +@@ -35593,7 +39966,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_win32_compact_heap(LPUINT pnLargest){
    +     if( lastErrno==NO_ERROR ){
    +       sqlite3_log(SQLITE_NOMEM, "failed to HeapCompact (no space), heap=%p",
    +                   (void*)hHeap);
    +-      rc = SQLITE_NOMEM;
    ++      rc = SQLITE_NOMEM_BKPT;
    +     }else{
    +       sqlite3_log(SQLITE_ERROR, "failed to HeapCompact (%lu), heap=%p",
    +                   osGetLastError(), (void*)hHeap);
    +@@ -35615,12 +39988,12 @@ SQLITE_API int SQLITE_STDCALL sqlite3_win32_compact_heap(LPUINT pnLargest){
    + ** the sqlite3_memory_used() function does not return zero, SQLITE_BUSY will
    + ** be returned and no changes will be made to the Win32 native heap.
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_win32_reset_heap(){
    ++SQLITE_API int sqlite3_win32_reset_heap(){
    +   int rc;
    +   MUTEX_LOGIC( sqlite3_mutex *pMaster; ) /* The main static mutex */
    +   MUTEX_LOGIC( sqlite3_mutex *pMem; )    /* The memsys static mutex */
    +-  MUTEX_LOGIC( pMaster = sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_MASTER); )
    +-  MUTEX_LOGIC( pMem = sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_MEM); )
    ++  MUTEX_LOGIC( pMaster = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MASTER); )
    ++  MUTEX_LOGIC( pMem = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MEM); )
    +   sqlite3_mutex_enter(pMaster);
    +   sqlite3_mutex_enter(pMem);
    +   winMemAssertMagic();
    +@@ -35660,11 +40033,17 @@ SQLITE_API int SQLITE_STDCALL sqlite3_win32_reset_heap(){
    + ** (if available).
    + */
    + 
    +-SQLITE_API void SQLITE_STDCALL sqlite3_win32_write_debug(const char *zBuf, int nBuf){
    ++SQLITE_API void sqlite3_win32_write_debug(const char *zBuf, int nBuf){
    +   char zDbgBuf[SQLITE_WIN32_DBG_BUF_SIZE];
    +   int nMin = MIN(nBuf, (SQLITE_WIN32_DBG_BUF_SIZE - 1)); /* may be negative. */
    +   if( nMin<-1 ) nMin = -1; /* all negative values become -1. */
    +   assert( nMin==-1 || nMin==0 || nMin<SQLITE_WIN32_DBG_BUF_SIZE );
    ++#ifdef SQLITE_ENABLE_API_ARMOR
    ++  if( !zBuf ){
    ++    (void)SQLITE_MISUSE_BKPT;
    ++    return;
    ++  }
    ++#endif
    + #if defined(SQLITE_WIN32_HAS_ANSI)
    +   if( nMin>0 ){
    +     memset(zDbgBuf, 0, SQLITE_WIN32_DBG_BUF_SIZE);
    +@@ -35700,7 +40079,7 @@ SQLITE_API void SQLITE_STDCALL sqlite3_win32_write_debug(const char *zBuf, int n
    + static HANDLE sleepObj = NULL;
    + #endif
    + 
    +-SQLITE_API void SQLITE_STDCALL sqlite3_win32_sleep(DWORD milliseconds){
    ++SQLITE_API void sqlite3_win32_sleep(DWORD milliseconds){
    + #if SQLITE_OS_WINRT
    +   if ( sleepObj==NULL ){
    +     sleepObj = osCreateEventExW(NULL, NULL, CREATE_EVENT_MANUAL_RESET,
    +@@ -35735,7 +40114,7 @@ SQLITE_PRIVATE DWORD sqlite3Win32Wait(HANDLE hObject){
    + ** the LockFileEx() API.
    + */
    + 
    +-#if !defined(SQLITE_WIN32_GETVERSIONEX) || !SQLITE_WIN32_GETVERSIONEX
    ++#if !SQLITE_WIN32_GETVERSIONEX
    + # define osIsNT()  (1)
    + #elif SQLITE_OS_WINCE || SQLITE_OS_WINRT || !defined(SQLITE_WIN32_HAS_ANSI)
    + # define osIsNT()  (1)
    +@@ -35749,14 +40128,14 @@ SQLITE_PRIVATE DWORD sqlite3Win32Wait(HANDLE hObject){
    + ** This function determines if the machine is running a version of Windows
    + ** based on the NT kernel.
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_win32_is_nt(void){
    ++SQLITE_API int sqlite3_win32_is_nt(void){
    + #if SQLITE_OS_WINRT
    +   /*
    +   ** NOTE: The WinRT sub-platform is always assumed to be based on the NT
    +   **       kernel.
    +   */
    +   return 1;
    +-#elif defined(SQLITE_WIN32_GETVERSIONEX) && SQLITE_WIN32_GETVERSIONEX
    ++#elif SQLITE_WIN32_GETVERSIONEX
    +   if( osInterlockedCompareExchange(&sqlite3_os_type, 0, 0)==0 ){
    + #if defined(SQLITE_WIN32_HAS_ANSI)
    +     OSVERSIONINFOA sInfo;
    +@@ -35913,7 +40292,7 @@ static int winMemInit(void *pAppData){
    +           "failed to HeapCreate (%lu), flags=%u, initSize=%lu, maxSize=%lu",
    +           osGetLastError(), SQLITE_WIN32_HEAP_FLAGS, dwInitialSize,
    +           dwMaximumSize);
    +-      return SQLITE_NOMEM;
    ++      return SQLITE_NOMEM_BKPT;
    +     }
    +     pWinMemData->bOwned = TRUE;
    +     assert( pWinMemData->bOwned );
    +@@ -35923,7 +40302,7 @@ static int winMemInit(void *pAppData){
    +   if( !pWinMemData->hHeap ){
    +     sqlite3_log(SQLITE_NOMEM,
    +         "failed to GetProcessHeap (%lu)", osGetLastError());
    +-    return SQLITE_NOMEM;
    ++    return SQLITE_NOMEM_BKPT;
    +   }
    +   pWinMemData->bOwned = FALSE;
    +   assert( !pWinMemData->bOwned );
    +@@ -35990,147 +40369,244 @@ 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.
    + **
    +-** Space to hold the returned string is obtained from malloc.
    ++** Space to hold the returned string is obtained from sqlite3_malloc().
    + */
    +-static LPWSTR winUtf8ToUnicode(const char *zFilename){
    ++static LPWSTR winUtf8ToUnicode(const char *zText){
    +   int nChar;
    +-  LPWSTR zWideFilename;
    ++  LPWSTR zWideText;
    + 
    +-  nChar = osMultiByteToWideChar(CP_UTF8, 0, zFilename, -1, NULL, 0);
    ++  nChar = osMultiByteToWideChar(CP_UTF8, 0, zText, -1, NULL, 0);
    +   if( nChar==0 ){
    +     return 0;
    +   }
    +-  zWideFilename = sqlite3MallocZero( nChar*sizeof(zWideFilename[0]) );
    +-  if( zWideFilename==0 ){
    ++  zWideText = sqlite3MallocZero( nChar*sizeof(WCHAR) );
    ++  if( zWideText==0 ){
    +     return 0;
    +   }
    +-  nChar = osMultiByteToWideChar(CP_UTF8, 0, zFilename, -1, zWideFilename,
    ++  nChar = osMultiByteToWideChar(CP_UTF8, 0, zText, -1, zWideText,
    +                                 nChar);
    +   if( nChar==0 ){
    +-    sqlite3_free(zWideFilename);
    +-    zWideFilename = 0;
    ++    sqlite3_free(zWideText);
    ++    zWideText = 0;
    +   }
    +-  return zWideFilename;
    ++  return zWideText;
    + }
    + 
    + /*
    +-** Convert Microsoft Unicode to UTF-8.  Space to hold the returned string is
    +-** obtained from sqlite3_malloc().
    ++** Convert a Microsoft Unicode string to UTF-8.
    ++**
    ++** Space to hold the returned string is obtained from sqlite3_malloc().
    + */
    +-static char *winUnicodeToUtf8(LPCWSTR zWideFilename){
    ++static char *winUnicodeToUtf8(LPCWSTR zWideText){
    +   int nByte;
    +-  char *zFilename;
    ++  char *zText;
    + 
    +-  nByte = osWideCharToMultiByte(CP_UTF8, 0, zWideFilename, -1, 0, 0, 0, 0);
    ++  nByte = osWideCharToMultiByte(CP_UTF8, 0, zWideText, -1, 0, 0, 0, 0);
    +   if( nByte == 0 ){
    +     return 0;
    +   }
    +-  zFilename = sqlite3MallocZero( nByte );
    +-  if( zFilename==0 ){
    ++  zText = sqlite3MallocZero( nByte );
    ++  if( zText==0 ){
    +     return 0;
    +   }
    +-  nByte = osWideCharToMultiByte(CP_UTF8, 0, zWideFilename, -1, zFilename, nByte,
    ++  nByte = osWideCharToMultiByte(CP_UTF8, 0, zWideText, -1, zText, nByte,
    +                                 0, 0);
    +   if( nByte == 0 ){
    +-    sqlite3_free(zFilename);
    +-    zFilename = 0;
    ++    sqlite3_free(zText);
    ++    zText = 0;
    +   }
    +-  return zFilename;
    ++  return zText;
    + }
    + 
    + /*
    +-** Convert an ANSI string to Microsoft Unicode, based on the
    +-** current codepage settings for file apis.
    ++** Convert an ANSI string to Microsoft Unicode, using the ANSI or OEM
    ++** code page.
    + **
    +-** Space to hold the returned string is obtained
    +-** from sqlite3_malloc.
    ++** Space to hold the returned string is obtained from sqlite3_malloc().
    + */
    +-static LPWSTR winMbcsToUnicode(const char *zFilename){
    ++static LPWSTR winMbcsToUnicode(const char *zText, int useAnsi){
    +   int nByte;
    +-  LPWSTR zMbcsFilename;
    +-  int codepage = osAreFileApisANSI() ? CP_ACP : CP_OEMCP;
    ++  LPWSTR zMbcsText;
    ++  int codepage = useAnsi ? CP_ACP : CP_OEMCP;
    + 
    +-  nByte = osMultiByteToWideChar(codepage, 0, zFilename, -1, NULL,
    ++  nByte = osMultiByteToWideChar(codepage, 0, zText, -1, NULL,
    +                                 0)*sizeof(WCHAR);
    +   if( nByte==0 ){
    +     return 0;
    +   }
    +-  zMbcsFilename = sqlite3MallocZero( nByte*sizeof(zMbcsFilename[0]) );
    +-  if( zMbcsFilename==0 ){
    ++  zMbcsText = sqlite3MallocZero( nByte*sizeof(WCHAR) );
    ++  if( zMbcsText==0 ){
    +     return 0;
    +   }
    +-  nByte = osMultiByteToWideChar(codepage, 0, zFilename, -1, zMbcsFilename,
    ++  nByte = osMultiByteToWideChar(codepage, 0, zText, -1, zMbcsText,
    +                                 nByte);
    +   if( nByte==0 ){
    +-    sqlite3_free(zMbcsFilename);
    +-    zMbcsFilename = 0;
    ++    sqlite3_free(zMbcsText);
    ++    zMbcsText = 0;
    +   }
    +-  return zMbcsFilename;
    ++  return zMbcsText;
    + }
    + 
    + /*
    +-** Convert Microsoft Unicode to multi-byte character string, based on the
    +-** user's ANSI codepage.
    ++** Convert a Microsoft Unicode string to a multi-byte character string,
    ++** using the ANSI or OEM code page.
    + **
    +-** Space to hold the returned string is obtained from
    +-** sqlite3_malloc().
    ++** Space to hold the returned string is obtained from sqlite3_malloc().
    + */
    +-static char *winUnicodeToMbcs(LPCWSTR zWideFilename){
    ++static char *winUnicodeToMbcs(LPCWSTR zWideText, int useAnsi){
    +   int nByte;
    +-  char *zFilename;
    +-  int codepage = osAreFileApisANSI() ? CP_ACP : CP_OEMCP;
    ++  char *zText;
    ++  int codepage = useAnsi ? CP_ACP : CP_OEMCP;
    + 
    +-  nByte = osWideCharToMultiByte(codepage, 0, zWideFilename, -1, 0, 0, 0, 0);
    ++  nByte = osWideCharToMultiByte(codepage, 0, zWideText, -1, 0, 0, 0, 0);
    +   if( nByte == 0 ){
    +     return 0;
    +   }
    +-  zFilename = sqlite3MallocZero( nByte );
    +-  if( zFilename==0 ){
    ++  zText = sqlite3MallocZero( nByte );
    ++  if( zText==0 ){
    +     return 0;
    +   }
    +-  nByte = osWideCharToMultiByte(codepage, 0, zWideFilename, -1, zFilename,
    ++  nByte = osWideCharToMultiByte(codepage, 0, zWideText, -1, zText,
    +                                 nByte, 0, 0);
    +   if( nByte == 0 ){
    +-    sqlite3_free(zFilename);
    +-    zFilename = 0;
    ++    sqlite3_free(zText);
    ++    zText = 0;
    +   }
    +-  return zFilename;
    ++  return zText;
    + }
    + 
    + /*
    +-** Convert multibyte character string to UTF-8.  Space to hold the
    +-** returned string is obtained from sqlite3_malloc().
    ++** Convert a multi-byte character string to UTF-8.
    ++**
    ++** Space to hold the returned string is obtained from sqlite3_malloc().
    + */
    +-SQLITE_API char *SQLITE_STDCALL sqlite3_win32_mbcs_to_utf8(const char *zFilename){
    +-  char *zFilenameUtf8;
    ++static char *winMbcsToUtf8(const char *zText, int useAnsi){
    ++  char *zTextUtf8;
    +   LPWSTR zTmpWide;
    + 
    +-  zTmpWide = winMbcsToUnicode(zFilename);
    ++  zTmpWide = winMbcsToUnicode(zText, useAnsi);
    +   if( zTmpWide==0 ){
    +     return 0;
    +   }
    +-  zFilenameUtf8 = winUnicodeToUtf8(zTmpWide);
    ++  zTextUtf8 = winUnicodeToUtf8(zTmpWide);
    +   sqlite3_free(zTmpWide);
    +-  return zFilenameUtf8;
    ++  return zTextUtf8;
    + }
    + 
    + /*
    +-** Convert UTF-8 to multibyte character string.  Space to hold the
    +-** returned string is obtained from sqlite3_malloc().
    ++** Convert a UTF-8 string to a multi-byte character string.
    ++**
    ++** Space to hold the returned string is obtained from sqlite3_malloc().
    + */
    +-SQLITE_API char *SQLITE_STDCALL sqlite3_win32_utf8_to_mbcs(const char *zFilename){
    +-  char *zFilenameMbcs;
    ++static char *winUtf8ToMbcs(const char *zText, int useAnsi){
    ++  char *zTextMbcs;
    +   LPWSTR zTmpWide;
    + 
    +-  zTmpWide = winUtf8ToUnicode(zFilename);
    ++  zTmpWide = winUtf8ToUnicode(zText);
    +   if( zTmpWide==0 ){
    +     return 0;
    +   }
    +-  zFilenameMbcs = winUnicodeToMbcs(zTmpWide);
    ++  zTextMbcs = winUnicodeToMbcs(zTmpWide, useAnsi);
    +   sqlite3_free(zTmpWide);
    +-  return zFilenameMbcs;
    ++  return zTextMbcs;
    ++}
    ++
    ++/*
    ++** This is a public wrapper for the winUtf8ToUnicode() function.
    ++*/
    ++SQLITE_API LPWSTR sqlite3_win32_utf8_to_unicode(const char *zText){
    ++#ifdef SQLITE_ENABLE_API_ARMOR
    ++  if( !zText ){
    ++    (void)SQLITE_MISUSE_BKPT;
    ++    return 0;
    ++  }
    ++#endif
    ++#ifndef SQLITE_OMIT_AUTOINIT
    ++  if( sqlite3_initialize() ) return 0;
    ++#endif
    ++  return winUtf8ToUnicode(zText);
    ++}
    ++
    ++/*
    ++** This is a public wrapper for the winUnicodeToUtf8() function.
    ++*/
    ++SQLITE_API char *sqlite3_win32_unicode_to_utf8(LPCWSTR zWideText){
    ++#ifdef SQLITE_ENABLE_API_ARMOR
    ++  if( !zWideText ){
    ++    (void)SQLITE_MISUSE_BKPT;
    ++    return 0;
    ++  }
    ++#endif
    ++#ifndef SQLITE_OMIT_AUTOINIT
    ++  if( sqlite3_initialize() ) return 0;
    ++#endif
    ++  return winUnicodeToUtf8(zWideText);
    ++}
    ++
    ++/*
    ++** This is a public wrapper for the winMbcsToUtf8() function.
    ++*/
    ++SQLITE_API char *sqlite3_win32_mbcs_to_utf8(const char *zText){
    ++#ifdef SQLITE_ENABLE_API_ARMOR
    ++  if( !zText ){
    ++    (void)SQLITE_MISUSE_BKPT;
    ++    return 0;
    ++  }
    ++#endif
    ++#ifndef SQLITE_OMIT_AUTOINIT
    ++  if( sqlite3_initialize() ) return 0;
    ++#endif
    ++  return winMbcsToUtf8(zText, osAreFileApisANSI());
    ++}
    ++
    ++/*
    ++** This is a public wrapper for the winMbcsToUtf8() function.
    ++*/
    ++SQLITE_API char *sqlite3_win32_mbcs_to_utf8_v2(const char *zText, int useAnsi){
    ++#ifdef SQLITE_ENABLE_API_ARMOR
    ++  if( !zText ){
    ++    (void)SQLITE_MISUSE_BKPT;
    ++    return 0;
    ++  }
    ++#endif
    ++#ifndef SQLITE_OMIT_AUTOINIT
    ++  if( sqlite3_initialize() ) return 0;
    ++#endif
    ++  return winMbcsToUtf8(zText, useAnsi);
    ++}
    ++
    ++/*
    ++** This is a public wrapper for the winUtf8ToMbcs() function.
    ++*/
    ++SQLITE_API char *sqlite3_win32_utf8_to_mbcs(const char *zText){
    ++#ifdef SQLITE_ENABLE_API_ARMOR
    ++  if( !zText ){
    ++    (void)SQLITE_MISUSE_BKPT;
    ++    return 0;
    ++  }
    ++#endif
    ++#ifndef SQLITE_OMIT_AUTOINIT
    ++  if( sqlite3_initialize() ) return 0;
    ++#endif
    ++  return winUtf8ToMbcs(zText, osAreFileApisANSI());
    ++}
    ++
    ++/*
    ++** This is a public wrapper for the winUtf8ToMbcs() function.
    ++*/
    ++SQLITE_API char *sqlite3_win32_utf8_to_mbcs_v2(const char *zText, int useAnsi){
    ++#ifdef SQLITE_ENABLE_API_ARMOR
    ++  if( !zText ){
    ++    (void)SQLITE_MISUSE_BKPT;
    ++    return 0;
    ++  }
    ++#endif
    ++#ifndef SQLITE_OMIT_AUTOINIT
    ++  if( sqlite3_initialize() ) return 0;
    ++#endif
    ++  return winUtf8ToMbcs(zText, useAnsi);
    + }
    + 
    + /*
    +@@ -36140,7 +40616,7 @@ SQLITE_API char *SQLITE_STDCALL sqlite3_win32_utf8_to_mbcs(const char *zFilename
    + ** argument is the name of the directory to use.  The return value will be
    + ** SQLITE_OK if successful.
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_win32_set_directory(DWORD type, LPCWSTR zValue){
    ++SQLITE_API int sqlite3_win32_set_directory(DWORD type, LPCWSTR zValue){
    +   char **ppDirectory = 0;
    + #ifndef SQLITE_OMIT_AUTOINIT
    +   int rc = sqlite3_initialize();
    +@@ -36160,7 +40636,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_win32_set_directory(DWORD type, LPCWSTR zV
    +     if( zValue && zValue[0] ){
    +       zValueUtf8 = winUnicodeToUtf8(zValue);
    +       if ( zValueUtf8==0 ){
    +-        return SQLITE_NOMEM;
    ++        return SQLITE_NOMEM_BKPT;
    +       }
    +     }
    +     sqlite3_free(*ppDirectory);
    +@@ -36232,7 +40708,7 @@ static int winGetLastErrorMsg(DWORD lastErrno, int nBuf, char *zBuf){
    +     if( dwLen > 0 ){
    +       /* allocate a buffer and convert to UTF8 */
    +       sqlite3BeginBenignMalloc();
    +-      zOut = sqlite3_win32_mbcs_to_utf8(zTemp);
    ++      zOut = winMbcsToUtf8(zTemp, osAreFileApisANSI());
    +       sqlite3EndBenignMalloc();
    +       /* free the system buffer allocated by FormatMessage */
    +       osLocalFree(zTemp);
    +@@ -36374,16 +40850,17 @@ static void winLogIoerr(int nRetry, int lineno){
    +   }
    + }
    + 
    +-#if SQLITE_OS_WINCE
    +-/*************************************************************************
    +-** This section contains code for WinCE only.
    ++/*
    ++** This #if does not rely on the SQLITE_OS_WINCE define because the
    ++** corresponding section in "date.c" cannot use it.
    + */
    +-#if !defined(SQLITE_MSVC_LOCALTIME_API) || !SQLITE_MSVC_LOCALTIME_API
    ++#if !defined(SQLITE_OMIT_LOCALTIME) && defined(_WIN32_WCE) && \
    ++    (!defined(SQLITE_MSVC_LOCALTIME_API) || !SQLITE_MSVC_LOCALTIME_API)
    + /*
    +-** The MSVC CRT on Windows CE may not have a localtime() function.  So
    +-** create a substitute.
    ++** The MSVC CRT on Windows CE may not have a localtime() function.
    ++** So define a substitute.
    + */
    +-/* #include <time.h> */
    ++/* #  include <time.h> */
    + struct tm *__cdecl localtime(const time_t *t)
    + {
    +   static struct tm y;
    +@@ -36407,6 +40884,10 @@ struct tm *__cdecl localtime(const time_t *t)
    + }
    + #endif
    + 
    ++#if SQLITE_OS_WINCE
    ++/*************************************************************************
    ++** This section contains code for WinCE only.
    ++*/
    + #define HANDLE_TO_WINFILE(a) (winFile*)&((char*)a)[-(int)offsetof(winFile,h)]
    + 
    + /*
    +@@ -36437,7 +40918,7 @@ static int winceCreateLock(const char *zFilename, winFile *pFile){
    +   zName = winUtf8ToUnicode(zFilename);
    +   if( zName==0 ){
    +     /* out of memory */
    +-    return SQLITE_IOERR_NOMEM;
    ++    return SQLITE_IOERR_NOMEM_BKPT;
    +   }
    + 
    +   /* Initialize the local lockdata */
    +@@ -36862,7 +41343,12 @@ static int winClose(sqlite3_file *id){
    +   }while( rc==0 && ++cnt < MX_CLOSE_ATTEMPT && (sqlite3_win32_sleep(100), 1) );
    + #if SQLITE_OS_WINCE
    + #define WINCE_DELETION_ATTEMPTS 3
    +-  winceDestroyLock(pFile);
    ++  {
    ++    winVfsAppData *pAppData = (winVfsAppData*)pFile->pVfs->pAppData;
    ++    if( pAppData==NULL || !pAppData->bNoLock ){
    ++      winceDestroyLock(pFile);
    ++    }
    ++  }
    +   if( pFile->zDeleteOnClose ){
    +     int cnt = 0;
    +     while(
    +@@ -36990,7 +41476,7 @@ static int winWrite(
    +            "offset=%lld, lock=%d\n", osGetCurrentProcessId(), pFile,
    +            pFile->h, pBuf, amt, offset, pFile->locktype));
    + 
    +-#if SQLITE_MAX_MMAP_SIZE>0
    ++#if defined(SQLITE_MMAP_READWRITE) && SQLITE_MAX_MMAP_SIZE>0
    +   /* Deal with as much of this write request as possible by transfering
    +   ** data from the memory mapping using memcpy().  */
    +   if( offset<pFile->mmapSize ){
    +@@ -37420,9 +41906,8 @@ static int winLock(sqlite3_file *id, int locktype){
    +   ** the PENDING_LOCK byte is temporary.
    +   */
    +   newLocktype = pFile->locktype;
    +-  if(   (pFile->locktype==NO_LOCK)
    +-     || (   (locktype==EXCLUSIVE_LOCK)
    +-         && (pFile->locktype==RESERVED_LOCK))
    ++  if( pFile->locktype==NO_LOCK
    ++   || (locktype==EXCLUSIVE_LOCK && pFile->locktype<=RESERVED_LOCK)
    +   ){
    +     int cnt = 3;
    +     while( cnt-->0 && (res = winLockFile(&pFile->h, SQLITE_LOCKFILE_FLAGS,
    +@@ -37538,7 +42023,7 @@ static int winCheckReservedLock(sqlite3_file *id, int *pResOut){
    +     res = 1;
    +     OSTRACE(("TEST-WR-LOCK file=%p, result=%d (local)\n", pFile->h, res));
    +   }else{
    +-    res = winLockFile(&pFile->h, SQLITE_LOCKFILEEX_FLAGS,RESERVED_BYTE, 0, 1, 0);
    ++    res = winLockFile(&pFile->h, SQLITE_LOCKFILEEX_FLAGS,RESERVED_BYTE,0,1,0);
    +     if( res ){
    +       winUnlockFile(&pFile->h, RESERVED_BYTE, 0, 1, 0);
    +     }
    +@@ -37595,6 +42080,44 @@ static int winUnlock(sqlite3_file *id, int locktype){
    +   return rc;
    + }
    + 
    ++/******************************************************************************
    ++****************************** No-op Locking **********************************
    ++**
    ++** Of the various locking implementations available, this is by far the
    ++** simplest:  locking is ignored.  No attempt is made to lock the database
    ++** file for reading or writing.
    ++**
    ++** This locking mode is appropriate for use on read-only databases
    ++** (ex: databases that are burned into CD-ROM, for example.)  It can
    ++** also be used if the application employs some external mechanism to
    ++** prevent simultaneous access of the same database by two or more
    ++** database connections.  But there is a serious risk of database
    ++** corruption if this locking mode is used in situations where multiple
    ++** database connections are accessing the same database file at the same
    ++** time and one or more of those connections are writing.
    ++*/
    ++
    ++static int winNolockLock(sqlite3_file *id, int locktype){
    ++  UNUSED_PARAMETER(id);
    ++  UNUSED_PARAMETER(locktype);
    ++  return SQLITE_OK;
    ++}
    ++
    ++static int winNolockCheckReservedLock(sqlite3_file *id, int *pResOut){
    ++  UNUSED_PARAMETER(id);
    ++  UNUSED_PARAMETER(pResOut);
    ++  return SQLITE_OK;
    ++}
    ++
    ++static int winNolockUnlock(sqlite3_file *id, int locktype){
    ++  UNUSED_PARAMETER(id);
    ++  UNUSED_PARAMETER(locktype);
    ++  return SQLITE_OK;
    ++}
    ++
    ++/******************* End of the no-op lock implementation *********************
    ++******************************************************************************/
    ++
    + /*
    + ** If *pArg is initially negative then this is a query.  Set *pArg to
    + ** 1 or 0 depending on whether or not bit mask of pFile->ctrlFlags is set.
    +@@ -37628,7 +42151,7 @@ static int winFileControl(sqlite3_file *id, int op, void *pArg){
    +       OSTRACE(("FCNTL file=%p, rc=SQLITE_OK\n", pFile->h));
    +       return SQLITE_OK;
    +     }
    +-    case SQLITE_LAST_ERRNO: {
    ++    case SQLITE_FCNTL_LAST_ERRNO: {
    +       *(int*)pArg = (int)pFile->lastErrno;
    +       OSTRACE(("FCNTL file=%p, rc=SQLITE_OK\n", pFile->h));
    +       return SQLITE_OK;
    +@@ -37686,6 +42209,12 @@ static int winFileControl(sqlite3_file *id, int op, void *pArg){
    +       OSTRACE(("FCNTL file=%p, rc=SQLITE_OK\n", pFile->h));
    +       return SQLITE_OK;
    +     }
    ++    case SQLITE_FCNTL_WIN32_GET_HANDLE: {
    ++      LPHANDLE phFile = (LPHANDLE)pArg;
    ++      *phFile = pFile->h;
    ++      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;
    +@@ -37713,6 +42242,14 @@ static int winFileControl(sqlite3_file *id, int op, void *pArg){
    +       if( newLimit>sqlite3GlobalConfig.mxMmap ){
    +         newLimit = sqlite3GlobalConfig.mxMmap;
    +       }
    ++
    ++      /* The value of newLimit may be eventually cast to (SIZE_T) and passed
    ++      ** to MapViewOfFile(). Restrict its value to 2GB if (SIZE_T) is not at
    ++      ** least a 64-bit type. */
    ++      if( newLimit>0 && sizeof(SIZE_T)<8 ){
    ++        newLimit = (newLimit & 0x7FFFFFFF);
    ++      }
    ++
    +       *(i64*)pArg = pFile->mmapSizeMax;
    +       if( newLimit>=0 && newLimit!=pFile->mmapSizeMax && pFile->nFetchOut==0 ){
    +         pFile->mmapSizeMax = newLimit;
    +@@ -37819,6 +42356,9 @@ struct winShmNode {
    + 
    +   int szRegion;              /* Size of shared-memory regions */
    +   int nRegion;               /* Size of array apRegion */
    ++  u8 isReadonly;             /* True if read-only */
    ++  u8 isUnlocked;             /* True if no DMS lock held */
    ++
    +   struct ShmRegion {
    +     HANDLE hMap;             /* File handle from CreateFileMapping */
    +     void *pMap;
    +@@ -37873,30 +42413,30 @@ struct winShm {
    + /*
    + ** Apply advisory locks for all n bytes beginning at ofst.
    + */
    +-#define _SHM_UNLCK  1
    +-#define _SHM_RDLCK  2
    +-#define _SHM_WRLCK  3
    ++#define WINSHM_UNLCK  1
    ++#define WINSHM_RDLCK  2
    ++#define WINSHM_WRLCK  3
    + static int winShmSystemLock(
    +   winShmNode *pFile,    /* Apply locks to this open shared-memory segment */
    +-  int lockType,         /* _SHM_UNLCK, _SHM_RDLCK, or _SHM_WRLCK */
    ++  int lockType,         /* WINSHM_UNLCK, WINSHM_RDLCK, or WINSHM_WRLCK */
    +   int ofst,             /* Offset to first byte to be locked/unlocked */
    +   int nByte             /* Number of bytes to lock or unlock */
    + ){
    +   int rc = 0;           /* Result code form Lock/UnlockFileEx() */
    + 
    +   /* Access to the winShmNode object is serialized by the caller */
    +-  assert( sqlite3_mutex_held(pFile->mutex) || pFile->nRef==0 );
    ++  assert( pFile->nRef==0 || sqlite3_mutex_held(pFile->mutex) );
    + 
    +   OSTRACE(("SHM-LOCK file=%p, lock=%d, offset=%d, size=%d\n",
    +            pFile->hFile.h, lockType, ofst, nByte));
    + 
    +   /* Release/Acquire the system-level lock */
    +-  if( lockType==_SHM_UNLCK ){
    ++  if( lockType==WINSHM_UNLCK ){
    +     rc = winUnlockFile(&pFile->hFile.h, ofst, 0, nByte, 0);
    +   }else{
    +     /* Initialize the locking parameters */
    +     DWORD dwFlags = LOCKFILE_FAIL_IMMEDIATELY;
    +-    if( lockType == _SHM_WRLCK ) dwFlags |= LOCKFILE_EXCLUSIVE_LOCK;
    ++    if( lockType == WINSHM_WRLCK ) dwFlags |= LOCKFILE_EXCLUSIVE_LOCK;
    +     rc = winLockFile(&pFile->hFile.h, dwFlags, ofst, 0, nByte, 0);
    +   }
    + 
    +@@ -37908,7 +42448,7 @@ static int winShmSystemLock(
    +   }
    + 
    +   OSTRACE(("SHM-LOCK file=%p, func=%s, errno=%lu, rc=%s\n",
    +-           pFile->hFile.h, (lockType == _SHM_UNLCK) ? "winUnlockFile" :
    ++           pFile->hFile.h, (lockType == WINSHM_UNLCK) ? "winUnlockFile" :
    +            "winLockFile", pFile->lastErrno, sqlite3ErrName(rc)));
    + 
    +   return rc;
    +@@ -37966,6 +42506,37 @@ static void winShmPurge(sqlite3_vfs *pVfs, int deleteFlag){
    +   }
    + }
    + 
    ++/*
    ++** The DMS lock has not yet been taken on shm file pShmNode. Attempt to
    ++** take it now. Return SQLITE_OK if successful, or an SQLite error
    ++** code otherwise.
    ++**
    ++** If the DMS cannot be locked because this is a readonly_shm=1
    ++** connection and no other process already holds a lock, return
    ++** SQLITE_READONLY_CANTINIT and set pShmNode->isUnlocked=1.
    ++*/
    ++static int winLockSharedMemory(winShmNode *pShmNode){
    ++  int rc = winShmSystemLock(pShmNode, WINSHM_WRLCK, WIN_SHM_DMS, 1);
    ++
    ++  if( rc==SQLITE_OK ){
    ++    if( pShmNode->isReadonly ){
    ++      pShmNode->isUnlocked = 1;
    ++      winShmSystemLock(pShmNode, WINSHM_UNLCK, WIN_SHM_DMS, 1);
    ++      return SQLITE_READONLY_CANTINIT;
    ++    }else if( winTruncate((sqlite3_file*)&pShmNode->hFile, 0) ){
    ++      winShmSystemLock(pShmNode, WINSHM_UNLCK, WIN_SHM_DMS, 1);
    ++      return winLogError(SQLITE_IOERR_SHMOPEN, osGetLastError(),
    ++                         "winLockSharedMemory", pShmNode->zFilename);
    ++    }
    ++  }
    ++
    ++  if( rc==SQLITE_OK ){
    ++    winShmSystemLock(pShmNode, WINSHM_UNLCK, WIN_SHM_DMS, 1);
    ++  }
    ++
    ++  return winShmSystemLock(pShmNode, WINSHM_RDLCK, WIN_SHM_DMS, 1);
    ++}
    ++
    + /*
    + ** Open the shared-memory area associated with database file pDbFd.
    + **
    +@@ -37975,9 +42546,9 @@ static void winShmPurge(sqlite3_vfs *pVfs, int deleteFlag){
    + */
    + static int winOpenSharedMemory(winFile *pDbFd){
    +   struct winShm *p;                  /* The connection to be opened */
    +-  struct winShmNode *pShmNode = 0;   /* The underlying mmapped file */
    +-  int rc;                            /* Result code */
    +-  struct winShmNode *pNew;           /* Newly allocated winShmNode */
    ++  winShmNode *pShmNode = 0;          /* The underlying mmapped file */
    ++  int rc = SQLITE_OK;                /* Result code */
    ++  winShmNode *pNew;                  /* Newly allocated winShmNode */
    +   int nName;                         /* Size of zName in bytes */
    + 
    +   assert( pDbFd->pShm==0 );    /* Not previously opened */
    +@@ -37986,12 +42557,12 @@ static int winOpenSharedMemory(winFile *pDbFd){
    +   ** allocate space for a new winShmNode and filename.
    +   */
    +   p = sqlite3MallocZero( sizeof(*p) );
    +-  if( p==0 ) return SQLITE_IOERR_NOMEM;
    ++  if( p==0 ) return SQLITE_IOERR_NOMEM_BKPT;
    +   nName = sqlite3Strlen30(pDbFd->zPath);
    +   pNew = sqlite3MallocZero( sizeof(*pShmNode) + nName + 17 );
    +   if( pNew==0 ){
    +     sqlite3_free(p);
    +-    return SQLITE_IOERR_NOMEM;
    ++    return SQLITE_IOERR_NOMEM_BKPT;
    +   }
    +   pNew->zFilename = (char*)&pNew[1];
    +   sqlite3_snprintf(nName+15, pNew->zFilename, "%s-shm", pDbFd->zPath);
    +@@ -38010,42 +42581,40 @@ static int winOpenSharedMemory(winFile *pDbFd){
    +   if( pShmNode ){
    +     sqlite3_free(pNew);
    +   }else{
    ++    int inFlags = SQLITE_OPEN_WAL;
    ++    int outFlags = 0;
    ++
    +     pShmNode = pNew;
    +     pNew = 0;
    +     ((winFile*)(&pShmNode->hFile))->h = INVALID_HANDLE_VALUE;
    +     pShmNode->pNext = winShmNodeList;
    +     winShmNodeList = pShmNode;
    + 
    +-    pShmNode->mutex = sqlite3_mutex_alloc(SQLITE_MUTEX_FAST);
    +-    if( pShmNode->mutex==0 ){
    +-      rc = SQLITE_IOERR_NOMEM;
    +-      goto shm_open_err;
    ++    if( sqlite3GlobalConfig.bCoreMutex ){
    ++      pShmNode->mutex = sqlite3_mutex_alloc(SQLITE_MUTEX_FAST);
    ++      if( pShmNode->mutex==0 ){
    ++        rc = SQLITE_IOERR_NOMEM_BKPT;
    ++        goto shm_open_err;
    ++      }
    +     }
    + 
    +-    rc = winOpen(pDbFd->pVfs,
    +-                 pShmNode->zFilename,             /* Name of the file (UTF-8) */
    +-                 (sqlite3_file*)&pShmNode->hFile,  /* File handle here */
    +-                 SQLITE_OPEN_WAL | SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE,
    +-                 0);
    +-    if( SQLITE_OK!=rc ){
    ++    if( 0==sqlite3_uri_boolean(pDbFd->zPath, "readonly_shm", 0) ){
    ++      inFlags |= SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE;
    ++    }else{
    ++      inFlags |= SQLITE_OPEN_READONLY;
    ++    }
    ++    rc = winOpen(pDbFd->pVfs, pShmNode->zFilename,
    ++                 (sqlite3_file*)&pShmNode->hFile,
    ++                 inFlags, &outFlags);
    ++    if( rc!=SQLITE_OK ){
    ++      rc = winLogError(rc, osGetLastError(), "winOpenShm",
    ++                       pShmNode->zFilename);
    +       goto shm_open_err;
    +     }
    ++    if( outFlags==SQLITE_OPEN_READONLY ) pShmNode->isReadonly = 1;
    + 
    +-    /* Check to see if another process is holding the dead-man switch.
    +-    ** 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);
    +-      if( rc!=SQLITE_OK ){
    +-        rc = winLogError(SQLITE_IOERR_SHMOPEN, osGetLastError(),
    +-                         "winOpenShm", pDbFd->zPath);
    +-      }
    +-    }
    +-    if( rc==SQLITE_OK ){
    +-      winShmSystemLock(pShmNode, _SHM_UNLCK, WIN_SHM_DMS, 1);
    +-      rc = winShmSystemLock(pShmNode, _SHM_RDLCK, WIN_SHM_DMS, 1);
    +-    }
    +-    if( rc ) goto shm_open_err;
    ++    rc = winLockSharedMemory(pShmNode);
    ++    if( rc!=SQLITE_OK && rc!=SQLITE_READONLY_CANTINIT ) goto shm_open_err;
    +   }
    + 
    +   /* Make the new connection a child of the winShmNode */
    +@@ -38068,11 +42637,11 @@ static int winOpenSharedMemory(winFile *pDbFd){
    +   p->pNext = pShmNode->pFirst;
    +   pShmNode->pFirst = p;
    +   sqlite3_mutex_leave(pShmNode->mutex);
    +-  return SQLITE_OK;
    ++  return rc;
    + 
    +   /* Jump here on any error */
    + shm_open_err:
    +-  winShmSystemLock(pShmNode, _SHM_UNLCK, WIN_SHM_DMS, 1);
    ++  winShmSystemLock(pShmNode, WINSHM_UNLCK, WIN_SHM_DMS, 1);
    +   winShmPurge(pDbFd->pVfs, 0);      /* This call frees pShmNode if required */
    +   sqlite3_free(p);
    +   sqlite3_free(pNew);
    +@@ -38161,7 +42730,7 @@ static int winShmLock(
    + 
    +     /* Unlock the system-level locks */
    +     if( (mask & allMask)==0 ){
    +-      rc = winShmSystemLock(pShmNode, _SHM_UNLCK, ofst+WIN_SHM_BASE, n);
    ++      rc = winShmSystemLock(pShmNode, WINSHM_UNLCK, ofst+WIN_SHM_BASE, n);
    +     }else{
    +       rc = SQLITE_OK;
    +     }
    +@@ -38189,7 +42758,7 @@ static int winShmLock(
    +     /* Get shared locks at the system level, if necessary */
    +     if( rc==SQLITE_OK ){
    +       if( (allShared & mask)==0 ){
    +-        rc = winShmSystemLock(pShmNode, _SHM_RDLCK, ofst+WIN_SHM_BASE, n);
    ++        rc = winShmSystemLock(pShmNode, WINSHM_RDLCK, ofst+WIN_SHM_BASE, n);
    +       }else{
    +         rc = SQLITE_OK;
    +       }
    +@@ -38214,7 +42783,7 @@ static int winShmLock(
    +     ** also mark the local connection as being locked.
    +     */
    +     if( rc==SQLITE_OK ){
    +-      rc = winShmSystemLock(pShmNode, _SHM_WRLCK, ofst+WIN_SHM_BASE, n);
    ++      rc = winShmSystemLock(pShmNode, WINSHM_WRLCK, ofst+WIN_SHM_BASE, n);
    +       if( rc==SQLITE_OK ){
    +         assert( (p->sharedMask & mask)==0 );
    +         p->exclMask |= mask;
    +@@ -38272,6 +42841,8 @@ static int winShmMap(
    +   winFile *pDbFd = (winFile*)fd;
    +   winShm *pShm = pDbFd->pShm;
    +   winShmNode *pShmNode;
    ++  DWORD protect = PAGE_READWRITE;
    ++  DWORD flags = FILE_MAP_WRITE | FILE_MAP_READ;
    +   int rc = SQLITE_OK;
    + 
    +   if( !pShm ){
    +@@ -38282,6 +42853,11 @@ static int winShmMap(
    +   pShmNode = pShm->pShmNode;
    + 
    +   sqlite3_mutex_enter(pShmNode->mutex);
    ++  if( pShmNode->isUnlocked ){
    ++    rc = winLockSharedMemory(pShmNode);
    ++    if( rc!=SQLITE_OK ) goto shmpage_out;
    ++    pShmNode->isUnlocked = 0;
    ++  }
    +   assert( szRegion==pShmNode->szRegion || pShmNode->nRegion==0 );
    + 
    +   if( pShmNode->nRegion<=iRegion ){
    +@@ -38323,26 +42899,31 @@ static int winShmMap(
    +         pShmNode->aRegion, (iRegion+1)*sizeof(apNew[0])
    +     );
    +     if( !apNew ){
    +-      rc = SQLITE_IOERR_NOMEM;
    ++      rc = SQLITE_IOERR_NOMEM_BKPT;
    +       goto shmpage_out;
    +     }
    +     pShmNode->aRegion = apNew;
    + 
    ++    if( pShmNode->isReadonly ){
    ++      protect = PAGE_READONLY;
    ++      flags = FILE_MAP_READ;
    ++    }
    ++
    +     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
    ++          NULL, protect, nByte, NULL
    +       );
    + #elif defined(SQLITE_WIN32_HAS_WIDE)
    +       hMap = osCreateFileMappingW(pShmNode->hFile.h,
    +-          NULL, PAGE_READWRITE, 0, nByte, NULL
    ++          NULL, protect, 0, nByte, NULL
    +       );
    +-#elif defined(SQLITE_WIN32_HAS_ANSI)
    ++#elif defined(SQLITE_WIN32_HAS_ANSI) && SQLITE_WIN32_CREATEFILEMAPPINGA
    +       hMap = osCreateFileMappingA(pShmNode->hFile.h,
    +-          NULL, PAGE_READWRITE, 0, nByte, NULL
    ++          NULL, protect, 0, nByte, NULL
    +       );
    + #endif
    +       OSTRACE(("SHM-MAP-CREATE pid=%lu, region=%d, size=%d, rc=%s\n",
    +@@ -38352,11 +42933,11 @@ static int winShmMap(
    +         int iOffset = pShmNode->nRegion*szRegion;
    +         int iOffsetShift = iOffset % winSysInfo.dwAllocationGranularity;
    + #if SQLITE_OS_WINRT
    +-        pMap = osMapViewOfFileFromApp(hMap, FILE_MAP_WRITE | FILE_MAP_READ,
    ++        pMap = osMapViewOfFileFromApp(hMap, flags,
    +             iOffset - iOffsetShift, szRegion + iOffsetShift
    +         );
    + #else
    +-        pMap = osMapViewOfFile(hMap, FILE_MAP_WRITE | FILE_MAP_READ,
    ++        pMap = osMapViewOfFile(hMap, flags,
    +             0, iOffset - iOffsetShift, szRegion + iOffsetShift
    +         );
    + #endif
    +@@ -38387,6 +42968,7 @@ shmpage_out:
    +   }else{
    +     *pp = 0;
    +   }
    ++  if( pShmNode->isReadonly && rc==SQLITE_OK ) rc = SQLITE_READONLY;
    +   sqlite3_mutex_leave(pShmNode->mutex);
    +   return rc;
    + }
    +@@ -38484,17 +43066,19 @@ static int winMapfile(winFile *pFd, sqlite3_int64 nByte){
    +     DWORD flags = FILE_MAP_READ;
    + 
    +     winUnmapfile(pFd);
    ++#ifdef SQLITE_MMAP_READWRITE
    +     if( (pFd->ctrlFlags & WINFILE_RDONLY)==0 ){
    +       protect = PAGE_READWRITE;
    +       flags |= FILE_MAP_WRITE;
    +     }
    ++#endif
    + #if SQLITE_OS_WINRT
    +     pFd->hMap = osCreateFileMappingFromApp(pFd->h, NULL, protect, nMap, NULL);
    + #elif defined(SQLITE_WIN32_HAS_WIDE)
    +     pFd->hMap = osCreateFileMappingW(pFd->h, NULL, protect,
    +                                 (DWORD)((nMap>>32) & 0xffffffff),
    +                                 (DWORD)(nMap & 0xffffffff), NULL);
    +-#elif defined(SQLITE_WIN32_HAS_ANSI)
    ++#elif defined(SQLITE_WIN32_HAS_ANSI) && SQLITE_WIN32_CREATEFILEMAPPINGA
    +     pFd->hMap = osCreateFileMappingA(pFd->h, NULL, protect,
    +                                 (DWORD)((nMap>>32) & 0xffffffff),
    +                                 (DWORD)(nMap & 0xffffffff), NULL);
    +@@ -38655,6 +43239,44 @@ static const sqlite3_io_methods winIoMethod = {
    +   winUnfetch                      /* xUnfetch */
    + };
    + 
    ++/*
    ++** This vector defines all the methods that can operate on an
    ++** sqlite3_file for win32 without performing any locking.
    ++*/
    ++static const sqlite3_io_methods winIoNolockMethod = {
    ++  3,                              /* iVersion */
    ++  winClose,                       /* xClose */
    ++  winRead,                        /* xRead */
    ++  winWrite,                       /* xWrite */
    ++  winTruncate,                    /* xTruncate */
    ++  winSync,                        /* xSync */
    ++  winFileSize,                    /* xFileSize */
    ++  winNolockLock,                  /* xLock */
    ++  winNolockUnlock,                /* xUnlock */
    ++  winNolockCheckReservedLock,     /* xCheckReservedLock */
    ++  winFileControl,                 /* xFileControl */
    ++  winSectorSize,                  /* xSectorSize */
    ++  winDeviceCharacteristics,       /* xDeviceCharacteristics */
    ++  winShmMap,                      /* xShmMap */
    ++  winShmLock,                     /* xShmLock */
    ++  winShmBarrier,                  /* xShmBarrier */
    ++  winShmUnmap,                    /* xShmUnmap */
    ++  winFetch,                       /* xFetch */
    ++  winUnfetch                      /* xUnfetch */
    ++};
    ++
    ++static winVfsAppData winAppData = {
    ++  &winIoMethod,       /* pMethod */
    ++  0,                  /* pAppData */
    ++  0                   /* bNoLock */
    ++};
    ++
    ++static winVfsAppData winNolockAppData = {
    ++  &winIoNolockMethod, /* pMethod */
    ++  0,                  /* pAppData */
    ++  1                   /* bNoLock */
    ++};
    ++
    + /****************************************************************************
    + **************************** sqlite3_vfs methods ****************************
    + **
    +@@ -38675,7 +43297,7 @@ static char *winConvertToUtf8Filename(const void *zFilename){
    +   }
    + #ifdef SQLITE_WIN32_HAS_ANSI
    +   else{
    +-    zConverted = sqlite3_win32_mbcs_to_utf8(zFilename);
    ++    zConverted = winMbcsToUtf8(zFilename, osAreFileApisANSI());
    +   }
    + #endif
    +   /* caller will handle out of memory */
    +@@ -38696,7 +43318,7 @@ static void *winConvertFromUtf8Filename(const char *zFilename){
    +   }
    + #ifdef SQLITE_WIN32_HAS_ANSI
    +   else{
    +-    zConverted = sqlite3_win32_utf8_to_mbcs(zFilename);
    ++    zConverted = winUtf8ToMbcs(zFilename, osAreFileApisANSI());
    +   }
    + #endif
    +   /* caller will handle out of memory */
    +@@ -38751,7 +43373,7 @@ static int winGetTempname(sqlite3_vfs *pVfs, char **pzBuf){
    +   zBuf = sqlite3MallocZero( nBuf );
    +   if( !zBuf ){
    +     OSTRACE(("TEMP-FILENAME rc=SQLITE_IOERR_NOMEM\n"));
    +-    return SQLITE_IOERR_NOMEM;
    ++    return SQLITE_IOERR_NOMEM_BKPT;
    +   }
    + 
    +   /* Figure out the effective temporary directory.  First, check if one
    +@@ -38809,7 +43431,7 @@ static int winGetTempname(sqlite3_vfs *pVfs, char **pzBuf){
    +         if( !zConverted ){
    +           sqlite3_free(zBuf);
    +           OSTRACE(("TEMP-FILENAME rc=SQLITE_IOERR_NOMEM\n"));
    +-          return SQLITE_IOERR_NOMEM;
    ++          return SQLITE_IOERR_NOMEM_BKPT;
    +         }
    +         if( winIsDir(zConverted) ){
    +           sqlite3_snprintf(nMax, zBuf, "%s", zDir);
    +@@ -38822,7 +43444,7 @@ static int winGetTempname(sqlite3_vfs *pVfs, char **pzBuf){
    +         if( !zConverted ){
    +           sqlite3_free(zBuf);
    +           OSTRACE(("TEMP-FILENAME rc=SQLITE_IOERR_NOMEM\n"));
    +-          return SQLITE_IOERR_NOMEM;
    ++          return SQLITE_IOERR_NOMEM_BKPT;
    +         }
    +         if( cygwin_conv_path(
    +                 osIsNT() ? CCP_POSIX_TO_WIN_W : CCP_POSIX_TO_WIN_A, zDir,
    +@@ -38843,7 +43465,7 @@ static int winGetTempname(sqlite3_vfs *pVfs, char **pzBuf){
    +             sqlite3_free(zConverted);
    +             sqlite3_free(zBuf);
    +             OSTRACE(("TEMP-FILENAME rc=SQLITE_IOERR_NOMEM\n"));
    +-            return SQLITE_IOERR_NOMEM;
    ++            return SQLITE_IOERR_NOMEM_BKPT;
    +           }
    +           sqlite3_snprintf(nMax, zBuf, "%s", zUtf8);
    +           sqlite3_free(zUtf8);
    +@@ -38861,7 +43483,7 @@ static int winGetTempname(sqlite3_vfs *pVfs, char **pzBuf){
    +     if( !zWidePath ){
    +       sqlite3_free(zBuf);
    +       OSTRACE(("TEMP-FILENAME rc=SQLITE_IOERR_NOMEM\n"));
    +-      return SQLITE_IOERR_NOMEM;
    ++      return SQLITE_IOERR_NOMEM_BKPT;
    +     }
    +     if( osGetTempPathW(nMax, zWidePath)==0 ){
    +       sqlite3_free(zWidePath);
    +@@ -38879,7 +43501,7 @@ static int winGetTempname(sqlite3_vfs *pVfs, char **pzBuf){
    +       sqlite3_free(zWidePath);
    +       sqlite3_free(zBuf);
    +       OSTRACE(("TEMP-FILENAME rc=SQLITE_IOERR_NOMEM\n"));
    +-      return SQLITE_IOERR_NOMEM;
    ++      return SQLITE_IOERR_NOMEM_BKPT;
    +     }
    +   }
    + #ifdef SQLITE_WIN32_HAS_ANSI
    +@@ -38889,7 +43511,7 @@ static int winGetTempname(sqlite3_vfs *pVfs, char **pzBuf){
    +     if( !zMbcsPath ){
    +       sqlite3_free(zBuf);
    +       OSTRACE(("TEMP-FILENAME rc=SQLITE_IOERR_NOMEM\n"));
    +-      return SQLITE_IOERR_NOMEM;
    ++      return SQLITE_IOERR_NOMEM_BKPT;
    +     }
    +     if( osGetTempPathA(nMax, zMbcsPath)==0 ){
    +       sqlite3_free(zBuf);
    +@@ -38897,14 +43519,14 @@ static int winGetTempname(sqlite3_vfs *pVfs, char **pzBuf){
    +       return winLogError(SQLITE_IOERR_GETTEMPPATH, osGetLastError(),
    +                          "winGetTempname3", 0);
    +     }
    +-    zUtf8 = sqlite3_win32_mbcs_to_utf8(zMbcsPath);
    ++    zUtf8 = winMbcsToUtf8(zMbcsPath, osAreFileApisANSI());
    +     if( zUtf8 ){
    +       sqlite3_snprintf(nMax, zBuf, "%s", zUtf8);
    +       sqlite3_free(zUtf8);
    +     }else{
    +       sqlite3_free(zBuf);
    +       OSTRACE(("TEMP-FILENAME rc=SQLITE_IOERR_NOMEM\n"));
    +-      return SQLITE_IOERR_NOMEM;
    ++      return SQLITE_IOERR_NOMEM_BKPT;
    +     }
    +   }
    + #endif /* SQLITE_WIN32_HAS_ANSI */
    +@@ -38983,11 +43605,19 @@ static int winIsDir(const void *zConverted){
    +   return (attr!=INVALID_FILE_ATTRIBUTES) && (attr&FILE_ATTRIBUTE_DIRECTORY);
    + }
    + 
    ++/* forward reference */
    ++static int winAccess(
    ++  sqlite3_vfs *pVfs,         /* Not used on win32 */
    ++  const char *zFilename,     /* Name of file to check */
    ++  int flags,                 /* Type of test to make on this file */
    ++  int *pResOut               /* OUT: Result */
    ++);
    ++
    + /*
    + ** Open a file.
    + */
    + static int winOpen(
    +-  sqlite3_vfs *pVfs,        /* Used to get maximum path name length */
    ++  sqlite3_vfs *pVfs,        /* Used to get maximum path length and AppData */
    +   const char *zName,        /* Name of the file (UTF-8) */
    +   sqlite3_file *id,         /* Write the SQLite file handle here */
    +   int flags,                /* Open mode flags */
    +@@ -39002,6 +43632,7 @@ static int winOpen(
    + #if SQLITE_OS_WINCE
    +   int isTemp = 0;
    + #endif
    ++  winVfsAppData *pAppData;
    +   winFile *pFile = (winFile*)id;
    +   void *zConverted;              /* Filename in OS encoding */
    +   const char *zUtf8Name = zName; /* Filename in UTF-8 encoding */
    +@@ -39096,7 +43727,7 @@ static int winOpen(
    +   if( zConverted==0 ){
    +     sqlite3_free(zTmpname);
    +     OSTRACE(("OPEN name=%s, rc=SQLITE_IOERR_NOMEM", zUtf8Name));
    +-    return SQLITE_IOERR_NOMEM;
    ++    return SQLITE_IOERR_NOMEM_BKPT;
    +   }
    + 
    +   if( winIsDir(zConverted) ){
    +@@ -39158,37 +43789,58 @@ static int winOpen(
    +     extendedParameters.dwSecurityQosFlags = SECURITY_ANONYMOUS;
    +     extendedParameters.lpSecurityAttributes = NULL;
    +     extendedParameters.hTemplateFile = NULL;
    +-    while( (h = osCreateFile2((LPCWSTR)zConverted,
    +-                              dwDesiredAccess,
    +-                              dwShareMode,
    +-                              dwCreationDisposition,
    +-                              &extendedParameters))==INVALID_HANDLE_VALUE &&
    +-                              winRetryIoerr(&cnt, &lastErrno) ){
    +-               /* Noop */
    +-    }
    ++    do{
    ++      h = osCreateFile2((LPCWSTR)zConverted,
    ++                        dwDesiredAccess,
    ++                        dwShareMode,
    ++                        dwCreationDisposition,
    ++                        &extendedParameters);
    ++      if( h!=INVALID_HANDLE_VALUE ) break;
    ++      if( isReadWrite ){
    ++        int rc2, isRO = 0;
    ++        sqlite3BeginBenignMalloc();
    ++        rc2 = winAccess(pVfs, zName, SQLITE_ACCESS_READ, &isRO);
    ++        sqlite3EndBenignMalloc();
    ++        if( rc2==SQLITE_OK && isRO ) break;
    ++      }
    ++    }while( winRetryIoerr(&cnt, &lastErrno) );
    + #else
    +-    while( (h = osCreateFileW((LPCWSTR)zConverted,
    +-                              dwDesiredAccess,
    +-                              dwShareMode, NULL,
    +-                              dwCreationDisposition,
    +-                              dwFlagsAndAttributes,
    +-                              NULL))==INVALID_HANDLE_VALUE &&
    +-                              winRetryIoerr(&cnt, &lastErrno) ){
    +-               /* Noop */
    +-    }
    ++    do{
    ++      h = osCreateFileW((LPCWSTR)zConverted,
    ++                        dwDesiredAccess,
    ++                        dwShareMode, NULL,
    ++                        dwCreationDisposition,
    ++                        dwFlagsAndAttributes,
    ++                        NULL);
    ++      if( h!=INVALID_HANDLE_VALUE ) break;
    ++      if( isReadWrite ){
    ++        int rc2, isRO = 0;
    ++        sqlite3BeginBenignMalloc();
    ++        rc2 = winAccess(pVfs, zName, SQLITE_ACCESS_READ, &isRO);
    ++        sqlite3EndBenignMalloc();
    ++        if( rc2==SQLITE_OK && isRO ) break;
    ++      }
    ++    }while( winRetryIoerr(&cnt, &lastErrno) );
    + #endif
    +   }
    + #ifdef SQLITE_WIN32_HAS_ANSI
    +   else{
    +-    while( (h = osCreateFileA((LPCSTR)zConverted,
    +-                              dwDesiredAccess,
    +-                              dwShareMode, NULL,
    +-                              dwCreationDisposition,
    +-                              dwFlagsAndAttributes,
    +-                              NULL))==INVALID_HANDLE_VALUE &&
    +-                              winRetryIoerr(&cnt, &lastErrno) ){
    +-               /* Noop */
    +-    }
    ++    do{
    ++      h = osCreateFileA((LPCSTR)zConverted,
    ++                        dwDesiredAccess,
    ++                        dwShareMode, NULL,
    ++                        dwCreationDisposition,
    ++                        dwFlagsAndAttributes,
    ++                        NULL);
    ++      if( h!=INVALID_HANDLE_VALUE ) break;
    ++      if( isReadWrite ){
    ++        int rc2, isRO = 0;
    ++        sqlite3BeginBenignMalloc();
    ++        rc2 = winAccess(pVfs, zName, SQLITE_ACCESS_READ, &isRO);
    ++        sqlite3EndBenignMalloc();
    ++        if( rc2==SQLITE_OK && isRO ) break;
    ++      }
    ++    }while( winRetryIoerr(&cnt, &lastErrno) );
    +   }
    + #endif
    +   winLogIoerr(cnt, __LINE__);
    +@@ -39197,8 +43849,6 @@ static int winOpen(
    +            dwDesiredAccess, (h==INVALID_HANDLE_VALUE) ? "failed" : "ok"));
    + 
    +   if( h==INVALID_HANDLE_VALUE ){
    +-    pFile->lastErrno = lastErrno;
    +-    winLogError(SQLITE_CANTOPEN, pFile->lastErrno, "winOpen", zUtf8Name);
    +     sqlite3_free(zConverted);
    +     sqlite3_free(zTmpname);
    +     if( isReadWrite && !isExclusive ){
    +@@ -39207,6 +43857,8 @@ static int winOpen(
    +                      ~(SQLITE_OPEN_CREATE|SQLITE_OPEN_READWRITE)),
    +          pOutFlags);
    +     }else{
    ++      pFile->lastErrno = lastErrno;
    ++      winLogError(SQLITE_CANTOPEN, pFile->lastErrno, "winOpen", zUtf8Name);
    +       return SQLITE_CANTOPEN_BKPT;
    +     }
    +   }
    +@@ -39223,15 +43875,20 @@ static int winOpen(
    +            "rc=%s\n", h, zUtf8Name, dwDesiredAccess, pOutFlags, pOutFlags ?
    +            *pOutFlags : 0, (h==INVALID_HANDLE_VALUE) ? "failed" : "ok"));
    + 
    ++  pAppData = (winVfsAppData*)pVfs->pAppData;
    ++
    + #if SQLITE_OS_WINCE
    +-  if( isReadWrite && eType==SQLITE_OPEN_MAIN_DB
    +-       && (rc = winceCreateLock(zName, pFile))!=SQLITE_OK
    +-  ){
    +-    osCloseHandle(h);
    +-    sqlite3_free(zConverted);
    +-    sqlite3_free(zTmpname);
    +-    OSTRACE(("OPEN-CE-LOCK name=%s, rc=%s\n", zName, sqlite3ErrName(rc)));
    +-    return rc;
    ++  {
    ++    if( isReadWrite && eType==SQLITE_OPEN_MAIN_DB
    ++         && ((pAppData==NULL) || !pAppData->bNoLock)
    ++         && (rc = winceCreateLock(zName, pFile))!=SQLITE_OK
    ++    ){
    ++      osCloseHandle(h);
    ++      sqlite3_free(zConverted);
    ++      sqlite3_free(zTmpname);
    ++      OSTRACE(("OPEN-CE-LOCK name=%s, rc=%s\n", zName, sqlite3ErrName(rc)));
    ++      return rc;
    ++    }
    +   }
    +   if( isTemp ){
    +     pFile->zDeleteOnClose = zConverted;
    +@@ -39242,7 +43899,7 @@ static int winOpen(
    +   }
    + 
    +   sqlite3_free(zTmpname);
    +-  pFile->pMethod = &winIoMethod;
    ++  pFile->pMethod = pAppData ? pAppData->pMethod : &winIoMethod;
    +   pFile->pVfs = pVfs;
    +   pFile->h = h;
    +   if( isReadonly ){
    +@@ -39296,7 +43953,7 @@ static int winDelete(
    +   zConverted = winConvertFromUtf8Filename(zFilename);
    +   if( zConverted==0 ){
    +     OSTRACE(("DELETE name=%s, rc=SQLITE_IOERR_NOMEM\n", zFilename));
    +-    return SQLITE_IOERR_NOMEM;
    ++    return SQLITE_IOERR_NOMEM_BKPT;
    +   }
    +   if( osIsNT() ){
    +     do {
    +@@ -39404,7 +44061,7 @@ static int winAccess(
    +   zConverted = winConvertFromUtf8Filename(zFilename);
    +   if( zConverted==0 ){
    +     OSTRACE(("ACCESS name=%s, rc=SQLITE_IOERR_NOMEM\n", zFilename));
    +-    return SQLITE_IOERR_NOMEM;
    ++    return SQLITE_IOERR_NOMEM_BKPT;
    +   }
    +   if( osIsNT() ){
    +     int cnt = 0;
    +@@ -39517,6 +44174,18 @@ static int winFullPathname(
    +   int nFull,                    /* Size of output buffer in bytes */
    +   char *zFull                   /* Output buffer */
    + ){
    ++#if !SQLITE_OS_WINCE && !SQLITE_OS_WINRT && !defined(__CYGWIN__)
    ++  DWORD nByte;
    ++  void *zConverted;
    ++  char *zOut;
    ++#endif
    ++
    ++  /* If this path name begins with "/X:", where "X" is any alphabetic
    ++  ** character, discard the initial "/" from the pathname.
    ++  */
    ++  if( zRelative[0]=='/' && winIsDriveLetterAndColon(zRelative+1) ){
    ++    zRelative++;
    ++  }
    + 
    + #if defined(__CYGWIN__)
    +   SimulateIOError( return SQLITE_ERROR );
    +@@ -39531,7 +44200,7 @@ static int winFullPathname(
    +     */
    +     char *zOut = sqlite3MallocZero( pVfs->mxPathname+1 );
    +     if( !zOut ){
    +-      return SQLITE_IOERR_NOMEM;
    ++      return SQLITE_IOERR_NOMEM_BKPT;
    +     }
    +     if( cygwin_conv_path(
    +             (osIsNT() ? CCP_POSIX_TO_WIN_W : CCP_POSIX_TO_WIN_A) |
    +@@ -39543,7 +44212,7 @@ static int winFullPathname(
    +       char *zUtf8 = winConvertToUtf8Filename(zOut);
    +       if( !zUtf8 ){
    +         sqlite3_free(zOut);
    +-        return SQLITE_IOERR_NOMEM;
    ++        return SQLITE_IOERR_NOMEM_BKPT;
    +       }
    +       sqlite3_snprintf(MIN(nFull, pVfs->mxPathname), zFull, "%s%c%s",
    +                        sqlite3_data_directory, winGetDirSep(), zUtf8);
    +@@ -39553,7 +44222,7 @@ static int winFullPathname(
    +   }else{
    +     char *zOut = sqlite3MallocZero( pVfs->mxPathname+1 );
    +     if( !zOut ){
    +-      return SQLITE_IOERR_NOMEM;
    ++      return SQLITE_IOERR_NOMEM_BKPT;
    +     }
    +     if( cygwin_conv_path(
    +             (osIsNT() ? CCP_POSIX_TO_WIN_W : CCP_POSIX_TO_WIN_A),
    +@@ -39565,7 +44234,7 @@ static int winFullPathname(
    +       char *zUtf8 = winConvertToUtf8Filename(zOut);
    +       if( !zUtf8 ){
    +         sqlite3_free(zOut);
    +-        return SQLITE_IOERR_NOMEM;
    ++        return SQLITE_IOERR_NOMEM_BKPT;
    +       }
    +       sqlite3_snprintf(MIN(nFull, pVfs->mxPathname), zFull, "%s", zUtf8);
    +       sqlite3_free(zUtf8);
    +@@ -39595,17 +44264,6 @@ static int winFullPathname(
    + #endif
    + 
    + #if !SQLITE_OS_WINCE && !SQLITE_OS_WINRT && !defined(__CYGWIN__)
    +-  DWORD nByte;
    +-  void *zConverted;
    +-  char *zOut;
    +-
    +-  /* If this path name begins with "/X:", where "X" is any alphabetic
    +-  ** character, discard the initial "/" from the pathname.
    +-  */
    +-  if( zRelative[0]=='/' && winIsDriveLetterAndColon(zRelative+1) ){
    +-    zRelative++;
    +-  }
    +-
    +   /* 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. This function could fail if, for example, the
    +@@ -39625,7 +44283,7 @@ static int winFullPathname(
    +   }
    +   zConverted = winConvertFromUtf8Filename(zRelative);
    +   if( zConverted==0 ){
    +-    return SQLITE_IOERR_NOMEM;
    ++    return SQLITE_IOERR_NOMEM_BKPT;
    +   }
    +   if( osIsNT() ){
    +     LPWSTR zTemp;
    +@@ -39639,7 +44297,7 @@ static int winFullPathname(
    +     zTemp = sqlite3MallocZero( nByte*sizeof(zTemp[0]) );
    +     if( zTemp==0 ){
    +       sqlite3_free(zConverted);
    +-      return SQLITE_IOERR_NOMEM;
    ++      return SQLITE_IOERR_NOMEM_BKPT;
    +     }
    +     nByte = osGetFullPathNameW((LPCWSTR)zConverted, nByte, zTemp, 0);
    +     if( nByte==0 ){
    +@@ -39665,7 +44323,7 @@ static int winFullPathname(
    +     zTemp = sqlite3MallocZero( nByte*sizeof(zTemp[0]) );
    +     if( zTemp==0 ){
    +       sqlite3_free(zConverted);
    +-      return SQLITE_IOERR_NOMEM;
    ++      return SQLITE_IOERR_NOMEM_BKPT;
    +     }
    +     nByte = osGetFullPathNameA((char*)zConverted, nByte, zTemp, 0);
    +     if( nByte==0 ){
    +@@ -39675,7 +44333,7 @@ static int winFullPathname(
    +                          "winFullPathname4", zRelative);
    +     }
    +     sqlite3_free(zConverted);
    +-    zOut = sqlite3_win32_mbcs_to_utf8(zTemp);
    ++    zOut = winMbcsToUtf8(zTemp, osAreFileApisANSI());
    +     sqlite3_free(zTemp);
    +   }
    + #endif
    +@@ -39684,7 +44342,7 @@ static int winFullPathname(
    +     sqlite3_free(zOut);
    +     return SQLITE_OK;
    +   }else{
    +-    return SQLITE_IOERR_NOMEM;
    ++    return SQLITE_IOERR_NOMEM_BKPT;
    +   }
    + #endif
    + }
    +@@ -39759,65 +44417,82 @@ static void winDlClose(sqlite3_vfs *pVfs, void *pHandle){
    +   #define winDlClose 0
    + #endif
    + 
    ++/* State information for the randomness gatherer. */
    ++typedef struct EntropyGatherer EntropyGatherer;
    ++struct EntropyGatherer {
    ++  unsigned char *a;   /* Gather entropy into this buffer */
    ++  int na;             /* Size of a[] in bytes */
    ++  int i;              /* XOR next input into a[i] */
    ++  int nXor;           /* Number of XOR operations done */
    ++};
    ++
    ++#if !defined(SQLITE_TEST) && !defined(SQLITE_OMIT_RANDOMNESS)
    ++/* Mix sz bytes of entropy into p. */
    ++static void xorMemory(EntropyGatherer *p, unsigned char *x, int sz){
    ++  int j, k;
    ++  for(j=0, k=p->i; j<sz; j++){
    ++    p->a[k++] ^= x[j];
    ++    if( k>=p->na ) k = 0;
    ++  }
    ++  p->i = k;
    ++  p->nXor += sz;
    ++}
    ++#endif /* !defined(SQLITE_TEST) && !defined(SQLITE_OMIT_RANDOMNESS) */
    + 
    + /*
    + ** Write up to nBuf bytes of randomness into zBuf.
    + */
    + static int winRandomness(sqlite3_vfs *pVfs, int nBuf, char *zBuf){
    +-  int n = 0;
    +-  UNUSED_PARAMETER(pVfs);
    + #if defined(SQLITE_TEST) || defined(SQLITE_OMIT_RANDOMNESS)
    +-  n = nBuf;
    ++  UNUSED_PARAMETER(pVfs);
    +   memset(zBuf, 0, nBuf);
    ++  return nBuf;
    + #else
    +-  if( sizeof(SYSTEMTIME)<=nBuf-n ){
    ++  EntropyGatherer e;
    ++  UNUSED_PARAMETER(pVfs);
    ++  memset(zBuf, 0, nBuf);
    ++  e.a = (unsigned char*)zBuf;
    ++  e.na = nBuf;
    ++  e.nXor = 0;
    ++  e.i = 0;
    ++  {
    +     SYSTEMTIME x;
    +     osGetSystemTime(&x);
    +-    memcpy(&zBuf[n], &x, sizeof(x));
    +-    n += sizeof(x);
    ++    xorMemory(&e, (unsigned char*)&x, sizeof(SYSTEMTIME));
    +   }
    +-  if( sizeof(DWORD)<=nBuf-n ){
    ++  {
    +     DWORD pid = osGetCurrentProcessId();
    +-    memcpy(&zBuf[n], &pid, sizeof(pid));
    +-    n += sizeof(pid);
    ++    xorMemory(&e, (unsigned char*)&pid, sizeof(DWORD));
    +   }
    + #if SQLITE_OS_WINRT
    +-  if( sizeof(ULONGLONG)<=nBuf-n ){
    ++  {
    +     ULONGLONG cnt = osGetTickCount64();
    +-    memcpy(&zBuf[n], &cnt, sizeof(cnt));
    +-    n += sizeof(cnt);
    ++    xorMemory(&e, (unsigned char*)&cnt, sizeof(ULONGLONG));
    +   }
    + #else
    +-  if( sizeof(DWORD)<=nBuf-n ){
    ++  {
    +     DWORD cnt = osGetTickCount();
    +-    memcpy(&zBuf[n], &cnt, sizeof(cnt));
    +-    n += sizeof(cnt);
    ++    xorMemory(&e, (unsigned char*)&cnt, sizeof(DWORD));
    +   }
    +-#endif
    +-  if( sizeof(LARGE_INTEGER)<=nBuf-n ){
    ++#endif /* SQLITE_OS_WINRT */
    ++  {
    +     LARGE_INTEGER i;
    +     osQueryPerformanceCounter(&i);
    +-    memcpy(&zBuf[n], &i, sizeof(i));
    +-    n += sizeof(i);
    ++    xorMemory(&e, (unsigned char*)&i, sizeof(LARGE_INTEGER));
    +   }
    + #if !SQLITE_OS_WINCE && !SQLITE_OS_WINRT && SQLITE_WIN32_USE_UUID
    +-  if( sizeof(UUID)<=nBuf-n ){
    ++  {
    +     UUID id;
    +     memset(&id, 0, sizeof(UUID));
    +     osUuidCreate(&id);
    +-    memcpy(&zBuf[n], &id, sizeof(UUID));
    +-    n += sizeof(UUID);
    +-  }
    +-  if( sizeof(UUID)<=nBuf-n ){
    +-    UUID id;
    ++    xorMemory(&e, (unsigned char*)&id, sizeof(UUID));
    +     memset(&id, 0, sizeof(UUID));
    +     osUuidCreateSequential(&id);
    +-    memcpy(&zBuf[n], &id, sizeof(UUID));
    +-    n += sizeof(UUID);
    ++    xorMemory(&e, (unsigned char*)&id, sizeof(UUID));
    +   }
    +-#endif
    +-#endif /* defined(SQLITE_TEST) || defined(SQLITE_ZERO_PRNG_SEED) */
    +-  return n;
    ++#endif /* !SQLITE_OS_WINCE && !SQLITE_OS_WINRT && SQLITE_WIN32_USE_UUID */
    ++  return e.nXor>nBuf ? nBuf : e.nXor;
    ++#endif /* defined(SQLITE_TEST) || defined(SQLITE_OMIT_RANDOMNESS) */
    + }
    + 
    + 
    +@@ -39933,62 +44608,114 @@ static int winCurrentTime(sqlite3_vfs *pVfs, double *prNow){
    + ** sqlite3_errmsg(), possibly making IO errors easier to debug.
    + */
    + static int winGetLastError(sqlite3_vfs *pVfs, int nBuf, char *zBuf){
    ++  DWORD e = osGetLastError();
    +   UNUSED_PARAMETER(pVfs);
    +-  return winGetLastErrorMsg(osGetLastError(), nBuf, zBuf);
    ++  if( nBuf>0 ) winGetLastErrorMsg(e, nBuf, zBuf);
    ++  return e;
    + }
    + 
    + /*
    + ** Initialize and deinitialize the operating system interface.
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_os_init(void){
    ++SQLITE_API int sqlite3_os_init(void){
    +   static sqlite3_vfs winVfs = {
    +-    3,                   /* iVersion */
    +-    sizeof(winFile),     /* szOsFile */
    ++    3,                     /* iVersion */
    ++    sizeof(winFile),       /* szOsFile */
    +     SQLITE_WIN32_MAX_PATH_BYTES, /* mxPathname */
    +-    0,                   /* pNext */
    +-    "win32",             /* zName */
    +-    0,                   /* pAppData */
    +-    winOpen,             /* xOpen */
    +-    winDelete,           /* xDelete */
    +-    winAccess,           /* xAccess */
    +-    winFullPathname,     /* xFullPathname */
    +-    winDlOpen,           /* xDlOpen */
    +-    winDlError,          /* xDlError */
    +-    winDlSym,            /* xDlSym */
    +-    winDlClose,          /* xDlClose */
    +-    winRandomness,       /* xRandomness */
    +-    winSleep,            /* xSleep */
    +-    winCurrentTime,      /* xCurrentTime */
    +-    winGetLastError,     /* xGetLastError */
    +-    winCurrentTimeInt64, /* xCurrentTimeInt64 */
    +-    winSetSystemCall,    /* xSetSystemCall */
    +-    winGetSystemCall,    /* xGetSystemCall */
    +-    winNextSystemCall,   /* xNextSystemCall */
    ++    0,                     /* pNext */
    ++    "win32",               /* zName */
    ++    &winAppData,           /* pAppData */
    ++    winOpen,               /* xOpen */
    ++    winDelete,             /* xDelete */
    ++    winAccess,             /* xAccess */
    ++    winFullPathname,       /* xFullPathname */
    ++    winDlOpen,             /* xDlOpen */
    ++    winDlError,            /* xDlError */
    ++    winDlSym,              /* xDlSym */
    ++    winDlClose,            /* xDlClose */
    ++    winRandomness,         /* xRandomness */
    ++    winSleep,              /* xSleep */
    ++    winCurrentTime,        /* xCurrentTime */
    ++    winGetLastError,       /* xGetLastError */
    ++    winCurrentTimeInt64,   /* xCurrentTimeInt64 */
    ++    winSetSystemCall,      /* xSetSystemCall */
    ++    winGetSystemCall,      /* xGetSystemCall */
    ++    winNextSystemCall,     /* xNextSystemCall */
    +   };
    + #if defined(SQLITE_WIN32_HAS_WIDE)
    +   static sqlite3_vfs winLongPathVfs = {
    +-    3,                   /* iVersion */
    +-    sizeof(winFile),     /* szOsFile */
    ++    3,                     /* iVersion */
    ++    sizeof(winFile),       /* szOsFile */
    +     SQLITE_WINNT_MAX_PATH_BYTES, /* mxPathname */
    +-    0,                   /* pNext */
    +-    "win32-longpath",    /* zName */
    +-    0,                   /* pAppData */
    +-    winOpen,             /* xOpen */
    +-    winDelete,           /* xDelete */
    +-    winAccess,           /* xAccess */
    +-    winFullPathname,     /* xFullPathname */
    +-    winDlOpen,           /* xDlOpen */
    +-    winDlError,          /* xDlError */
    +-    winDlSym,            /* xDlSym */
    +-    winDlClose,          /* xDlClose */
    +-    winRandomness,       /* xRandomness */
    +-    winSleep,            /* xSleep */
    +-    winCurrentTime,      /* xCurrentTime */
    +-    winGetLastError,     /* xGetLastError */
    +-    winCurrentTimeInt64, /* xCurrentTimeInt64 */
    +-    winSetSystemCall,    /* xSetSystemCall */
    +-    winGetSystemCall,    /* xGetSystemCall */
    +-    winNextSystemCall,   /* xNextSystemCall */
    ++    0,                     /* pNext */
    ++    "win32-longpath",      /* zName */
    ++    &winAppData,           /* pAppData */
    ++    winOpen,               /* xOpen */
    ++    winDelete,             /* xDelete */
    ++    winAccess,             /* xAccess */
    ++    winFullPathname,       /* xFullPathname */
    ++    winDlOpen,             /* xDlOpen */
    ++    winDlError,            /* xDlError */
    ++    winDlSym,              /* xDlSym */
    ++    winDlClose,            /* xDlClose */
    ++    winRandomness,         /* xRandomness */
    ++    winSleep,              /* xSleep */
    ++    winCurrentTime,        /* xCurrentTime */
    ++    winGetLastError,       /* xGetLastError */
    ++    winCurrentTimeInt64,   /* xCurrentTimeInt64 */
    ++    winSetSystemCall,      /* xSetSystemCall */
    ++    winGetSystemCall,      /* xGetSystemCall */
    ++    winNextSystemCall,     /* xNextSystemCall */
    ++  };
    ++#endif
    ++  static sqlite3_vfs winNolockVfs = {
    ++    3,                     /* iVersion */
    ++    sizeof(winFile),       /* szOsFile */
    ++    SQLITE_WIN32_MAX_PATH_BYTES, /* mxPathname */
    ++    0,                     /* pNext */
    ++    "win32-none",          /* zName */
    ++    &winNolockAppData,     /* pAppData */
    ++    winOpen,               /* xOpen */
    ++    winDelete,             /* xDelete */
    ++    winAccess,             /* xAccess */
    ++    winFullPathname,       /* xFullPathname */
    ++    winDlOpen,             /* xDlOpen */
    ++    winDlError,            /* xDlError */
    ++    winDlSym,              /* xDlSym */
    ++    winDlClose,            /* xDlClose */
    ++    winRandomness,         /* xRandomness */
    ++    winSleep,              /* xSleep */
    ++    winCurrentTime,        /* xCurrentTime */
    ++    winGetLastError,       /* xGetLastError */
    ++    winCurrentTimeInt64,   /* xCurrentTimeInt64 */
    ++    winSetSystemCall,      /* xSetSystemCall */
    ++    winGetSystemCall,      /* xGetSystemCall */
    ++    winNextSystemCall,     /* xNextSystemCall */
    ++  };
    ++#if defined(SQLITE_WIN32_HAS_WIDE)
    ++  static sqlite3_vfs winLongPathNolockVfs = {
    ++    3,                     /* iVersion */
    ++    sizeof(winFile),       /* szOsFile */
    ++    SQLITE_WINNT_MAX_PATH_BYTES, /* mxPathname */
    ++    0,                     /* pNext */
    ++    "win32-longpath-none", /* zName */
    ++    &winNolockAppData,     /* pAppData */
    ++    winOpen,               /* xOpen */
    ++    winDelete,             /* xDelete */
    ++    winAccess,             /* xAccess */
    ++    winFullPathname,       /* xFullPathname */
    ++    winDlOpen,             /* xDlOpen */
    ++    winDlError,            /* xDlError */
    ++    winDlSym,              /* xDlSym */
    ++    winDlClose,            /* xDlClose */
    ++    winRandomness,         /* xRandomness */
    ++    winSleep,              /* xSleep */
    ++    winCurrentTime,        /* xCurrentTime */
    ++    winGetLastError,       /* xGetLastError */
    ++    winCurrentTimeInt64,   /* xCurrentTimeInt64 */
    ++    winSetSystemCall,      /* xSetSystemCall */
    ++    winGetSystemCall,      /* xGetSystemCall */
    ++    winNextSystemCall,     /* xNextSystemCall */
    +   };
    + #endif
    + 
    +@@ -40012,10 +44739,16 @@ SQLITE_API int SQLITE_STDCALL sqlite3_os_init(void){
    +   sqlite3_vfs_register(&winLongPathVfs, 0);
    + #endif
    + 
    ++  sqlite3_vfs_register(&winNolockVfs, 0);
    ++
    ++#if defined(SQLITE_WIN32_HAS_WIDE)
    ++  sqlite3_vfs_register(&winLongPathNolockVfs, 0);
    ++#endif
    ++
    +   return SQLITE_OK;
    + }
    + 
    +-SQLITE_API int SQLITE_STDCALL sqlite3_os_end(void){
    ++SQLITE_API int sqlite3_os_end(void){
    + #if SQLITE_OS_WINRT
    +   if( sleepObj!=NULL ){
    +     osCloseHandle(sleepObj);
    +@@ -40072,7 +44805,8 @@ SQLITE_API int SQLITE_STDCALL sqlite3_os_end(void){
    + 
    + /* Round the union size down to the nearest pointer boundary, since that's how 
    + ** it will be aligned within the Bitvec struct. */
    +-#define BITVEC_USIZE     (((BITVEC_SZ-(3*sizeof(u32)))/sizeof(Bitvec*))*sizeof(Bitvec*))
    ++#define BITVEC_USIZE \
    ++    (((BITVEC_SZ-(3*sizeof(u32)))/sizeof(Bitvec*))*sizeof(Bitvec*))
    + 
    + /* Type of the array "element" for the bitmap representation. 
    + ** Should be a power of 2, and ideally, evenly divide into BITVEC_USIZE. 
    +@@ -40207,7 +44941,7 @@ SQLITE_PRIVATE int sqlite3BitvecSet(Bitvec *p, u32 i){
    +     i = i%p->iDivisor;
    +     if( p->u.apSub[bin]==0 ){
    +       p->u.apSub[bin] = sqlite3BitvecCreate( p->iDivisor );
    +-      if( p->u.apSub[bin]==0 ) return SQLITE_NOMEM;
    ++      if( p->u.apSub[bin]==0 ) return SQLITE_NOMEM_BKPT;
    +     }
    +     p = p->u.apSub[bin];
    +   }
    +@@ -40242,7 +44976,7 @@ bitvec_set_rehash:
    +     int rc;
    +     u32 *aiValues = sqlite3StackAllocRaw(0, sizeof(p->u.aHash));
    +     if( aiValues==0 ){
    +-      return SQLITE_NOMEM;
    ++      return SQLITE_NOMEM_BKPT;
    +     }else{
    +       memcpy(aiValues, p->u.aHash, sizeof(p->u.aHash));
    +       memset(p->u.apSub, 0, sizeof(p->u.apSub));
    +@@ -40323,7 +45057,7 @@ SQLITE_PRIVATE u32 sqlite3BitvecSize(Bitvec *p){
    +   return p->iSize;
    + }
    + 
    +-#ifndef SQLITE_OMIT_BUILTIN_TEST
    ++#ifndef SQLITE_UNTESTABLE
    + /*
    + ** Let V[] be an array of unsigned characters sufficient to hold
    + ** up to N bits.  Let I be an integer between 0 and N.  0<=I<N.
    +@@ -40438,7 +45172,7 @@ bitvec_end:
    +   sqlite3BitvecDestroy(pBitvec);
    +   return rc;
    + }
    +-#endif /* SQLITE_OMIT_BUILTIN_TEST */
    ++#endif /* SQLITE_UNTESTABLE */
    + 
    + /************** End of bitvec.c **********************************************/
    + /************** Begin file pcache.c ******************************************/
    +@@ -40458,13 +45192,36 @@ bitvec_end:
    + /* #include "sqliteInt.h" */
    + 
    + /*
    +-** A complete page cache is an instance of this structure.
    ++** A complete page cache is an instance of this structure.  Every
    ++** entry in the cache holds a single page of the database file.  The
    ++** btree layer only operates on the cached copy of the database pages.
    ++**
    ++** A page cache entry is "clean" if it exactly matches what is currently
    ++** on disk.  A page is "dirty" if it has been modified and needs to be
    ++** persisted to disk.
    ++**
    ++** pDirty, pDirtyTail, pSynced:
    ++**   All dirty pages are linked into the doubly linked list using
    ++**   PgHdr.pDirtyNext and pDirtyPrev. The list is maintained in LRU order
    ++**   such that p was added to the list more recently than p->pDirtyNext.
    ++**   PCache.pDirty points to the first (newest) element in the list and
    ++**   pDirtyTail to the last (oldest).
    ++**
    ++**   The PCache.pSynced variable is used to optimize searching for a dirty
    ++**   page to eject from the cache mid-transaction. It is better to eject
    ++**   a page that does not require a journal sync than one that does. 
    ++**   Therefore, pSynced is maintained to that it *almost* always points
    ++**   to either the oldest page in the pDirty/pDirtyTail list that has a
    ++**   clear PGHDR_NEED_SYNC flag or to a page that is older than this one
    ++**   (so that the right page to eject can be found by following pDirtyPrev
    ++**   pointers).
    + */
    + struct PCache {
    +   PgHdr *pDirty, *pDirtyTail;         /* List of dirty pages in LRU order */
    +   PgHdr *pSynced;                     /* Last synced page in dirty page list */
    +   int nRefSum;                        /* Sum of ref counts over all pages */
    +   int szCache;                        /* Configured cache size */
    ++  int szSpill;                        /* Size before spilling occurs */
    +   int szPage;                         /* Size of every page in this cache */
    +   int szExtra;                        /* Size of extra space for each page */
    +   u8 bPurgeable;                      /* True if pages are on backing store */
    +@@ -40474,6 +45231,95 @@ struct PCache {
    +   sqlite3_pcache *pCache;             /* Pluggable cache module */
    + };
    + 
    ++/********************************** Test and Debug Logic **********************/
    ++/*
    ++** Debug tracing macros.  Enable by by changing the "0" to "1" and
    ++** recompiling.
    ++**
    ++** When sqlite3PcacheTrace is 1, single line trace messages are issued.
    ++** When sqlite3PcacheTrace is 2, a dump of the pcache showing all cache entries
    ++** is displayed for many operations, resulting in a lot of output.
    ++*/
    ++#if defined(SQLITE_DEBUG) && 0
    ++  int sqlite3PcacheTrace = 2;       /* 0: off  1: simple  2: cache dumps */
    ++  int sqlite3PcacheMxDump = 9999;   /* Max cache entries for pcacheDump() */
    ++# define pcacheTrace(X) if(sqlite3PcacheTrace){sqlite3DebugPrintf X;}
    ++  void pcacheDump(PCache *pCache){
    ++    int N;
    ++    int i, j;
    ++    sqlite3_pcache_page *pLower;
    ++    PgHdr *pPg;
    ++    unsigned char *a;
    ++  
    ++    if( sqlite3PcacheTrace<2 ) return;
    ++    if( pCache->pCache==0 ) return;
    ++    N = sqlite3PcachePagecount(pCache);
    ++    if( N>sqlite3PcacheMxDump ) N = sqlite3PcacheMxDump;
    ++    for(i=1; i<=N; i++){
    ++       pLower = sqlite3GlobalConfig.pcache2.xFetch(pCache->pCache, i, 0);
    ++       if( pLower==0 ) continue;
    ++       pPg = (PgHdr*)pLower->pExtra;
    ++       printf("%3d: nRef %2d flgs %02x data ", i, pPg->nRef, pPg->flags);
    ++       a = (unsigned char *)pLower->pBuf;
    ++       for(j=0; j<12; j++) printf("%02x", a[j]);
    ++       printf("\n");
    ++       if( pPg->pPage==0 ){
    ++         sqlite3GlobalConfig.pcache2.xUnpin(pCache->pCache, pLower, 0);
    ++       }
    ++    }
    ++  }
    ++  #else
    ++# define pcacheTrace(X)
    ++# define pcacheDump(X)
    ++#endif
    ++
    ++/*
    ++** Check invariants on a PgHdr entry.  Return true if everything is OK.
    ++** Return false if any invariant is violated.
    ++**
    ++** This routine is for use inside of assert() statements only.  For
    ++** example:
    ++**
    ++**          assert( sqlite3PcachePageSanity(pPg) );
    ++*/
    ++#ifdef SQLITE_DEBUG
    ++SQLITE_PRIVATE int sqlite3PcachePageSanity(PgHdr *pPg){
    ++  PCache *pCache;
    ++  assert( pPg!=0 );
    ++  assert( pPg->pgno>0 || pPg->pPager==0 );    /* Page number is 1 or more */
    ++  pCache = pPg->pCache;
    ++  assert( pCache!=0 );      /* Every page has an associated PCache */
    ++  if( pPg->flags & PGHDR_CLEAN ){
    ++    assert( (pPg->flags & PGHDR_DIRTY)==0 );/* Cannot be both CLEAN and DIRTY */
    ++    assert( pCache->pDirty!=pPg );          /* CLEAN pages not on dirty list */
    ++    assert( pCache->pDirtyTail!=pPg );
    ++  }
    ++  /* WRITEABLE pages must also be DIRTY */
    ++  if( pPg->flags & PGHDR_WRITEABLE ){
    ++    assert( pPg->flags & PGHDR_DIRTY );     /* WRITEABLE implies DIRTY */
    ++  }
    ++  /* NEED_SYNC can be set independently of WRITEABLE.  This can happen,
    ++  ** for example, when using the sqlite3PagerDontWrite() optimization:
    ++  **    (1)  Page X is journalled, and gets WRITEABLE and NEED_SEEK.
    ++  **    (2)  Page X moved to freelist, WRITEABLE is cleared
    ++  **    (3)  Page X reused, WRITEABLE is set again
    ++  ** If NEED_SYNC had been cleared in step 2, then it would not be reset
    ++  ** in step 3, and page might be written into the database without first
    ++  ** syncing the rollback journal, which might cause corruption on a power
    ++  ** loss.
    ++  **
    ++  ** Another example is when the database page size is smaller than the
    ++  ** disk sector size.  When any page of a sector is journalled, all pages
    ++  ** in that sector are marked NEED_SYNC even if they are still CLEAN, just
    ++  ** in case they are later modified, since all pages in the same sector
    ++  ** must be journalled and synced before any of those pages can be safely
    ++  ** written.
    ++  */
    ++  return 1;
    ++}
    ++#endif /* SQLITE_DEBUG */
    ++
    ++
    + /********************************** Linked List Management ********************/
    + 
    + /* Allowed values for second argument to pcacheManageDirtyList() */
    +@@ -40490,17 +45336,16 @@ struct PCache {
    + static void pcacheManageDirtyList(PgHdr *pPage, u8 addRemove){
    +   PCache *p = pPage->pCache;
    + 
    ++  pcacheTrace(("%p.DIRTYLIST.%s %d\n", p,
    ++                addRemove==1 ? "REMOVE" : addRemove==2 ? "ADD" : "FRONT",
    ++                pPage->pgno));
    +   if( addRemove & PCACHE_DIRTYLIST_REMOVE ){
    +     assert( pPage->pDirtyNext || pPage==p->pDirtyTail );
    +     assert( pPage->pDirtyPrev || pPage==p->pDirty );
    +   
    +     /* Update the PCache1.pSynced variable if necessary. */
    +     if( p->pSynced==pPage ){
    +-      PgHdr *pSynced = pPage->pDirtyPrev;
    +-      while( pSynced && (pSynced->flags&PGHDR_NEED_SYNC) ){
    +-        pSynced = pSynced->pDirtyPrev;
    +-      }
    +-      p->pSynced = pSynced;
    ++      p->pSynced = pPage->pDirtyPrev;
    +     }
    +   
    +     if( pPage->pDirtyNext ){
    +@@ -40512,19 +45357,21 @@ static void pcacheManageDirtyList(PgHdr *pPage, u8 addRemove){
    +     if( pPage->pDirtyPrev ){
    +       pPage->pDirtyPrev->pDirtyNext = pPage->pDirtyNext;
    +     }else{
    ++      /* If there are now no dirty pages in the cache, set eCreate to 2. 
    ++      ** This is an optimization that allows sqlite3PcacheFetch() to skip
    ++      ** searching for a dirty page to eject from the cache when it might
    ++      ** otherwise have to.  */
    +       assert( pPage==p->pDirty );
    +       p->pDirty = pPage->pDirtyNext;
    +-      if( p->pDirty==0 && p->bPurgeable ){
    +-        assert( p->eCreate==1 );
    ++      assert( p->bPurgeable || p->eCreate==2 );
    ++      if( p->pDirty==0 ){         /*OPTIMIZATION-IF-TRUE*/
    ++        assert( p->bPurgeable==0 || p->eCreate==1 );
    +         p->eCreate = 2;
    +       }
    +     }
    +-    pPage->pDirtyNext = 0;
    +-    pPage->pDirtyPrev = 0;
    +   }
    +   if( addRemove & PCACHE_DIRTYLIST_ADD ){
    +-    assert( pPage->pDirtyNext==0 && pPage->pDirtyPrev==0 && p->pDirty!=pPage );
    +-  
    ++    pPage->pDirtyPrev = 0;
    +     pPage->pDirtyNext = p->pDirty;
    +     if( pPage->pDirtyNext ){
    +       assert( pPage->pDirtyNext->pDirtyPrev==0 );
    +@@ -40537,10 +45384,19 @@ static void pcacheManageDirtyList(PgHdr *pPage, u8 addRemove){
    +       }
    +     }
    +     p->pDirty = pPage;
    +-    if( !p->pSynced && 0==(pPage->flags&PGHDR_NEED_SYNC) ){
    ++
    ++    /* If pSynced is NULL and this page has a clear NEED_SYNC flag, set
    ++    ** pSynced to point to it. Checking the NEED_SYNC flag is an 
    ++    ** optimization, as if pSynced points to a page with the NEED_SYNC
    ++    ** flag set sqlite3PcacheFetchStress() searches through all newer 
    ++    ** entries of the dirty-list for a page with NEED_SYNC clear anyway.  */
    ++    if( !p->pSynced 
    ++     && 0==(pPage->flags&PGHDR_NEED_SYNC)   /*OPTIMIZATION-IF-FALSE*/
    ++    ){
    +       p->pSynced = pPage;
    +     }
    +   }
    ++  pcacheDump(p);
    + }
    + 
    + /*
    +@@ -40549,15 +45405,15 @@ static void pcacheManageDirtyList(PgHdr *pPage, u8 addRemove){
    + */
    + static void pcacheUnpin(PgHdr *p){
    +   if( p->pCache->bPurgeable ){
    ++    pcacheTrace(("%p.UNPIN %d\n", p->pCache, p->pgno));
    +     sqlite3GlobalConfig.pcache2.xUnpin(p->pCache->pCache, p->pPage, 0);
    ++    pcacheDump(p->pCache);
    +   }
    + }
    + 
    + /*
    +-** Compute the number of pages of cache requested.  p->szCache is the
    ++** Compute the number of pages of cache requested.   p->szCache is the
    + ** cache size requested by the "PRAGMA cache_size" statement.
    +-**
    +-**
    + */
    + static int numberOfCachePages(PCache *p){
    +   if( p->szCache>=0 ){
    +@@ -40603,6 +45459,12 @@ SQLITE_PRIVATE int sqlite3PcacheSize(void){ return sizeof(PCache); }
    + ** has already been allocated and is passed in as the p pointer. 
    + ** The caller discovers how much space needs to be allocated by 
    + ** calling sqlite3PcacheSize().
    ++**
    ++** szExtra is some extra space allocated for each page.  The first
    ++** 8 bytes of the extra space will be zeroed as the page is allocated,
    ++** but remaining content will be uninitialized.  Though it is opaque
    ++** to this module, the extra space really ends up being the MemPage
    ++** structure in the pager.
    + */
    + SQLITE_PRIVATE int sqlite3PcacheOpen(
    +   int szPage,                  /* Size of every page */
    +@@ -40615,11 +45477,14 @@ SQLITE_PRIVATE int sqlite3PcacheOpen(
    +   memset(p, 0, sizeof(PCache));
    +   p->szPage = 1;
    +   p->szExtra = szExtra;
    ++  assert( szExtra>=8 );  /* First 8 bytes will be zeroed */
    +   p->bPurgeable = bPurgeable;
    +   p->eCreate = 2;
    +   p->xStress = xStress;
    +   p->pStress = pStress;
    +   p->szCache = 100;
    ++  p->szSpill = 1;
    ++  pcacheTrace(("%p.OPEN szPage %d bPurgeable %d\n",p,szPage,bPurgeable));
    +   return sqlite3PcacheSetPageSize(p, szPage);
    + }
    + 
    +@@ -40635,13 +45500,14 @@ SQLITE_PRIVATE int sqlite3PcacheSetPageSize(PCache *pCache, int szPage){
    +                 szPage, pCache->szExtra + ROUND8(sizeof(PgHdr)),
    +                 pCache->bPurgeable
    +     );
    +-    if( pNew==0 ) return SQLITE_NOMEM;
    ++    if( pNew==0 ) return SQLITE_NOMEM_BKPT;
    +     sqlite3GlobalConfig.pcache2.xCachesize(pNew, numberOfCachePages(pCache));
    +     if( pCache->pCache ){
    +       sqlite3GlobalConfig.pcache2.xDestroy(pCache->pCache);
    +     }
    +     pCache->pCache = pNew;
    +     pCache->szPage = szPage;
    ++    pcacheTrace(("%p.PAGESIZE %d\n",pCache,szPage));
    +   }
    +   return SQLITE_OK;
    + }
    +@@ -40676,11 +45542,12 @@ SQLITE_PRIVATE sqlite3_pcache_page *sqlite3PcacheFetch(
    +   int createFlag        /* If true, create page if it does not exist already */
    + ){
    +   int eCreate;
    ++  sqlite3_pcache_page *pRes;
    + 
    +   assert( pCache!=0 );
    +   assert( pCache->pCache!=0 );
    +   assert( createFlag==3 || createFlag==0 );
    +-  assert( pgno>0 );
    ++  assert( pCache->eCreate==((pCache->bPurgeable && pCache->pDirty) ? 1 : 2) );
    + 
    +   /* eCreate defines what to do if the page does not exist.
    +   **    0     Do not allocate a new page.  (createFlag==0)
    +@@ -40693,12 +45560,15 @@ SQLITE_PRIVATE sqlite3_pcache_page *sqlite3PcacheFetch(
    +   assert( eCreate==0 || eCreate==1 || eCreate==2 );
    +   assert( createFlag==0 || pCache->eCreate==eCreate );
    +   assert( createFlag==0 || eCreate==1+(!pCache->bPurgeable||!pCache->pDirty) );
    +-  return sqlite3GlobalConfig.pcache2.xFetch(pCache->pCache, pgno, eCreate);
    ++  pRes = sqlite3GlobalConfig.pcache2.xFetch(pCache->pCache, pgno, eCreate);
    ++  pcacheTrace(("%p.FETCH %d%s (result: %p)\n",pCache,pgno,
    ++               createFlag?" create":"",pRes));
    ++  return pRes;
    + }
    + 
    + /*
    + ** If the sqlite3PcacheFetch() routine is unable to allocate a new
    +-** page because new clean pages are available for reuse and the cache
    ++** page because no clean pages are available for reuse and the cache
    + ** size limit has been reached, then this routine can be invoked to 
    + ** try harder to allocate a page.  This routine might invoke the stress
    + ** callback to spill dirty pages to the journal.  It will then try to
    +@@ -40715,36 +45585,43 @@ SQLITE_PRIVATE int sqlite3PcacheFetchStress(
    +   PgHdr *pPg;
    +   if( pCache->eCreate==2 ) return 0;
    + 
    +-
    +-  /* Find a dirty page to write-out and recycle. First try to find a 
    +-  ** page that does not require a journal-sync (one with PGHDR_NEED_SYNC
    +-  ** cleared), but if that is not possible settle for any other 
    +-  ** unreferenced dirty page.
    +-  */
    +-  for(pPg=pCache->pSynced; 
    +-      pPg && (pPg->nRef || (pPg->flags&PGHDR_NEED_SYNC)); 
    +-      pPg=pPg->pDirtyPrev
    +-  );
    +-  pCache->pSynced = pPg;
    +-  if( !pPg ){
    +-    for(pPg=pCache->pDirtyTail; pPg && pPg->nRef; pPg=pPg->pDirtyPrev);
    +-  }
    +-  if( pPg ){
    +-    int rc;
    ++  if( sqlite3PcachePagecount(pCache)>pCache->szSpill ){
    ++    /* Find a dirty page to write-out and recycle. First try to find a 
    ++    ** page that does not require a journal-sync (one with PGHDR_NEED_SYNC
    ++    ** cleared), but if that is not possible settle for any other 
    ++    ** unreferenced dirty page.
    ++    **
    ++    ** If the LRU page in the dirty list that has a clear PGHDR_NEED_SYNC
    ++    ** flag is currently referenced, then the following may leave pSynced
    ++    ** set incorrectly (pointing to other than the LRU page with NEED_SYNC
    ++    ** cleared). This is Ok, as pSynced is just an optimization.  */
    ++    for(pPg=pCache->pSynced; 
    ++        pPg && (pPg->nRef || (pPg->flags&PGHDR_NEED_SYNC)); 
    ++        pPg=pPg->pDirtyPrev
    ++    );
    ++    pCache->pSynced = pPg;
    ++    if( !pPg ){
    ++      for(pPg=pCache->pDirtyTail; pPg && pPg->nRef; pPg=pPg->pDirtyPrev);
    ++    }
    ++    if( pPg ){
    ++      int rc;
    + #ifdef SQLITE_LOG_CACHE_SPILL
    +-    sqlite3_log(SQLITE_FULL, 
    +-                "spill page %d making room for %d - cache used: %d/%d",
    +-                pPg->pgno, pgno,
    +-                sqlite3GlobalConfig.pcache.xPagecount(pCache->pCache),
    ++      sqlite3_log(SQLITE_FULL, 
    ++                  "spill page %d making room for %d - cache used: %d/%d",
    ++                  pPg->pgno, pgno,
    ++                  sqlite3GlobalConfig.pcache.xPagecount(pCache->pCache),
    +                 numberOfCachePages(pCache));
    + #endif
    +-    rc = pCache->xStress(pCache->pStress, pPg);
    +-    if( rc!=SQLITE_OK && rc!=SQLITE_BUSY ){
    +-      return rc;
    ++      pcacheTrace(("%p.SPILL %d\n",pCache,pPg->pgno));
    ++      rc = pCache->xStress(pCache->pStress, pPg);
    ++      pcacheDump(pCache);
    ++      if( rc!=SQLITE_OK && rc!=SQLITE_BUSY ){
    ++        return rc;
    ++      }
    +     }
    +   }
    +   *ppPage = sqlite3GlobalConfig.pcache2.xFetch(pCache->pCache, pgno, 2);
    +-  return *ppPage==0 ? SQLITE_NOMEM : SQLITE_OK;
    ++  return *ppPage==0 ? SQLITE_NOMEM_BKPT : SQLITE_OK;
    + }
    + 
    + /*
    +@@ -40765,11 +45642,11 @@ static SQLITE_NOINLINE PgHdr *pcacheFetchFinishWithInit(
    +   assert( pPage!=0 );
    +   pPgHdr = (PgHdr*)pPage->pExtra;
    +   assert( pPgHdr->pPage==0 );
    +-  memset(pPgHdr, 0, sizeof(PgHdr));
    ++  memset(&pPgHdr->pDirty, 0, sizeof(PgHdr) - offsetof(PgHdr,pDirty));
    +   pPgHdr->pPage = pPage;
    +   pPgHdr->pData = pPage->pBuf;
    +   pPgHdr->pExtra = (void *)&pPgHdr[1];
    +-  memset(pPgHdr->pExtra, 0, pCache->szExtra);
    ++  memset(pPgHdr->pExtra, 0, 8);
    +   pPgHdr->pCache = pCache;
    +   pPgHdr->pgno = pgno;
    +   pPgHdr->flags = PGHDR_CLEAN;
    +@@ -40797,6 +45674,7 @@ SQLITE_PRIVATE PgHdr *sqlite3PcacheFetchFinish(
    +   }
    +   pCache->nRefSum++;
    +   pPgHdr->nRef++;
    ++  assert( sqlite3PcachePageSanity(pPgHdr) );
    +   return pPgHdr;
    + }
    + 
    +@@ -40810,8 +45688,7 @@ SQLITE_PRIVATE void SQLITE_NOINLINE sqlite3PcacheRelease(PgHdr *p){
    +   if( (--p->nRef)==0 ){
    +     if( p->flags&PGHDR_CLEAN ){
    +       pcacheUnpin(p);
    +-    }else if( p->pDirtyPrev!=0 ){
    +-      /* Move the page to the head of the dirty list. */
    ++    }else{
    +       pcacheManageDirtyList(p, PCACHE_DIRTYLIST_FRONT);
    +     }
    +   }
    +@@ -40822,6 +45699,7 @@ SQLITE_PRIVATE void SQLITE_NOINLINE sqlite3PcacheRelease(PgHdr *p){
    + */
    + SQLITE_PRIVATE void sqlite3PcacheRef(PgHdr *p){
    +   assert(p->nRef>0);
    ++  assert( sqlite3PcachePageSanity(p) );
    +   p->nRef++;
    +   p->pCache->nRefSum++;
    + }
    +@@ -40833,6 +45711,7 @@ SQLITE_PRIVATE void sqlite3PcacheRef(PgHdr *p){
    + */
    + SQLITE_PRIVATE void sqlite3PcacheDrop(PgHdr *p){
    +   assert( p->nRef==1 );
    ++  assert( sqlite3PcachePageSanity(p) );
    +   if( p->flags&PGHDR_DIRTY ){
    +     pcacheManageDirtyList(p, PCACHE_DIRTYLIST_REMOVE);
    +   }
    +@@ -40846,13 +45725,16 @@ SQLITE_PRIVATE void sqlite3PcacheDrop(PgHdr *p){
    + */
    + SQLITE_PRIVATE void sqlite3PcacheMakeDirty(PgHdr *p){
    +   assert( p->nRef>0 );
    +-  if( p->flags & (PGHDR_CLEAN|PGHDR_DONT_WRITE) ){
    ++  assert( sqlite3PcachePageSanity(p) );
    ++  if( p->flags & (PGHDR_CLEAN|PGHDR_DONT_WRITE) ){    /*OPTIMIZATION-IF-FALSE*/
    +     p->flags &= ~PGHDR_DONT_WRITE;
    +     if( p->flags & PGHDR_CLEAN ){
    +       p->flags ^= (PGHDR_DIRTY|PGHDR_CLEAN);
    ++      pcacheTrace(("%p.DIRTY %d\n",p->pCache,p->pgno));
    +       assert( (p->flags & (PGHDR_DIRTY|PGHDR_CLEAN))==PGHDR_DIRTY );
    +       pcacheManageDirtyList(p, PCACHE_DIRTYLIST_ADD);
    +     }
    ++    assert( sqlite3PcachePageSanity(p) );
    +   }
    + }
    + 
    +@@ -40861,14 +45743,16 @@ SQLITE_PRIVATE void sqlite3PcacheMakeDirty(PgHdr *p){
    + ** make it so.
    + */
    + SQLITE_PRIVATE void sqlite3PcacheMakeClean(PgHdr *p){
    +-  if( (p->flags & PGHDR_DIRTY) ){
    +-    assert( (p->flags & PGHDR_CLEAN)==0 );
    +-    pcacheManageDirtyList(p, PCACHE_DIRTYLIST_REMOVE);
    +-    p->flags &= ~(PGHDR_DIRTY|PGHDR_NEED_SYNC|PGHDR_WRITEABLE);
    +-    p->flags |= PGHDR_CLEAN;
    +-    if( p->nRef==0 ){
    +-      pcacheUnpin(p);
    +-    }
    ++  assert( sqlite3PcachePageSanity(p) );
    ++  assert( (p->flags & PGHDR_DIRTY)!=0 );
    ++  assert( (p->flags & PGHDR_CLEAN)==0 );
    ++  pcacheManageDirtyList(p, PCACHE_DIRTYLIST_REMOVE);
    ++  p->flags &= ~(PGHDR_DIRTY|PGHDR_NEED_SYNC|PGHDR_WRITEABLE);
    ++  p->flags |= PGHDR_CLEAN;
    ++  pcacheTrace(("%p.CLEAN %d\n",p->pCache,p->pgno));
    ++  assert( sqlite3PcachePageSanity(p) );
    ++  if( p->nRef==0 ){
    ++    pcacheUnpin(p);
    +   }
    + }
    + 
    +@@ -40877,11 +45761,24 @@ SQLITE_PRIVATE void sqlite3PcacheMakeClean(PgHdr *p){
    + */
    + SQLITE_PRIVATE void sqlite3PcacheCleanAll(PCache *pCache){
    +   PgHdr *p;
    ++  pcacheTrace(("%p.CLEAN-ALL\n",pCache));
    +   while( (p = pCache->pDirty)!=0 ){
    +     sqlite3PcacheMakeClean(p);
    +   }
    + }
    + 
    ++/*
    ++** Clear the PGHDR_NEED_SYNC and PGHDR_WRITEABLE flag from all dirty pages.
    ++*/
    ++SQLITE_PRIVATE void sqlite3PcacheClearWritable(PCache *pCache){
    ++  PgHdr *p;
    ++  pcacheTrace(("%p.CLEAR-WRITEABLE\n",pCache));
    ++  for(p=pCache->pDirty; p; p=p->pDirtyNext){
    ++    p->flags &= ~(PGHDR_NEED_SYNC|PGHDR_WRITEABLE);
    ++  }
    ++  pCache->pSynced = pCache->pDirtyTail;
    ++}
    ++
    + /*
    + ** Clear the PGHDR_NEED_SYNC flag from all dirty pages.
    + */
    +@@ -40900,6 +45797,8 @@ SQLITE_PRIVATE void sqlite3PcacheMove(PgHdr *p, Pgno newPgno){
    +   PCache *pCache = p->pCache;
    +   assert( p->nRef>0 );
    +   assert( newPgno>0 );
    ++  assert( sqlite3PcachePageSanity(p) );
    ++  pcacheTrace(("%p.MOVE %d -> %d\n",pCache,p->pgno,newPgno));
    +   sqlite3GlobalConfig.pcache2.xRekey(pCache->pCache, p->pPage, p->pgno,newPgno);
    +   p->pgno = newPgno;
    +   if( (p->flags&PGHDR_DIRTY) && (p->flags&PGHDR_NEED_SYNC) ){
    +@@ -40920,6 +45819,7 @@ SQLITE_PRIVATE void sqlite3PcacheTruncate(PCache *pCache, Pgno pgno){
    +   if( pCache->pCache ){
    +     PgHdr *p;
    +     PgHdr *pNext;
    ++    pcacheTrace(("%p.TRUNCATE %d\n",pCache,pgno));
    +     for(p=pCache->pDirty; p; p=pNext){
    +       pNext = p->pDirtyNext;
    +       /* This routine never gets call with a positive pgno except right
    +@@ -40927,7 +45827,7 @@ SQLITE_PRIVATE void sqlite3PcacheTruncate(PCache *pCache, Pgno pgno){
    +       ** it must be that pgno==0.
    +       */
    +       assert( p->pgno>0 );
    +-      if( ALWAYS(p->pgno>pgno) ){
    ++      if( p->pgno>pgno ){
    +         assert( p->flags&PGHDR_DIRTY );
    +         sqlite3PcacheMakeClean(p);
    +       }
    +@@ -40950,6 +45850,7 @@ SQLITE_PRIVATE void sqlite3PcacheTruncate(PCache *pCache, Pgno pgno){
    + */
    + SQLITE_PRIVATE void sqlite3PcacheClose(PCache *pCache){
    +   assert( pCache->pCache!=0 );
    ++  pcacheTrace(("%p.CLOSE\n",pCache));
    +   sqlite3GlobalConfig.pcache2.xDestroy(pCache->pCache);
    + }
    + 
    +@@ -40962,29 +45863,31 @@ SQLITE_PRIVATE void sqlite3PcacheClear(PCache *pCache){
    + 
    + /*
    + ** Merge two lists of pages connected by pDirty and in pgno order.
    +-** Do not both fixing the pDirtyPrev pointers.
    ++** Do not bother fixing the pDirtyPrev pointers.
    + */
    + static PgHdr *pcacheMergeDirtyList(PgHdr *pA, PgHdr *pB){
    +   PgHdr result, *pTail;
    +   pTail = &result;
    +-  while( pA && pB ){
    ++  assert( pA!=0 && pB!=0 );
    ++  for(;;){
    +     if( pA->pgno<pB->pgno ){
    +       pTail->pDirty = pA;
    +       pTail = pA;
    +       pA = pA->pDirty;
    ++      if( pA==0 ){
    ++        pTail->pDirty = pB;
    ++        break;
    ++      }
    +     }else{
    +       pTail->pDirty = pB;
    +       pTail = pB;
    +       pB = pB->pDirty;
    ++      if( pB==0 ){
    ++        pTail->pDirty = pA;
    ++        break;
    ++      }
    +     }
    +   }
    +-  if( pA ){
    +-    pTail->pDirty = pA;
    +-  }else if( pB ){
    +-    pTail->pDirty = pB;
    +-  }else{
    +-    pTail->pDirty = 0;
    +-  }
    +   return result.pDirty;
    + }
    + 
    +@@ -41025,7 +45928,8 @@ static PgHdr *pcacheSortDirtyList(PgHdr *pIn){
    +   }
    +   p = a[0];
    +   for(i=1; i<N_SORT_BUCKET; i++){
    +-    p = pcacheMergeDirtyList(p, a[i]);
    ++    if( a[i]==0 ) continue;
    ++    p = p ? pcacheMergeDirtyList(p, a[i]) : a[i];
    +   }
    +   return p;
    + }
    +@@ -41085,6 +45989,25 @@ SQLITE_PRIVATE void sqlite3PcacheSetCachesize(PCache *pCache, int mxPage){
    +                                          numberOfCachePages(pCache));
    + }
    + 
    ++/*
    ++** Set the suggested cache-spill value.  Make no changes if if the
    ++** argument is zero.  Return the effective cache-spill size, which will
    ++** be the larger of the szSpill and szCache.
    ++*/
    ++SQLITE_PRIVATE int sqlite3PcacheSetSpillsize(PCache *p, int mxPage){
    ++  int res;
    ++  assert( p->pCache!=0 );
    ++  if( mxPage ){
    ++    if( mxPage<0 ){
    ++      mxPage = (int)((-1024*(i64)mxPage)/(p->szPage+p->szExtra));
    ++    }
    ++    p->szSpill = mxPage;
    ++  }
    ++  res = numberOfCachePages(p);
    ++  if( res<p->szSpill ) res = p->szSpill; 
    ++  return res;
    ++}
    ++
    + /*
    + ** Free up as much memory as possible from the page cache.
    + */
    +@@ -41099,6 +46022,17 @@ SQLITE_PRIVATE void sqlite3PcacheShrink(PCache *pCache){
    + */
    + SQLITE_PRIVATE int sqlite3HeaderSizePcache(void){ return ROUND8(sizeof(PgHdr)); }
    + 
    ++/*
    ++** Return the number of dirty pages currently in the cache, as a percentage
    ++** of the configured cache size.
    ++*/
    ++SQLITE_PRIVATE int sqlite3PCachePercentDirty(PCache *pCache){
    ++  PgHdr *pDirty;
    ++  int nDirty = 0;
    ++  int nCache = numberOfCachePages(pCache);
    ++  for(pDirty=pCache->pDirty; pDirty; pDirty=pDirty->pDirtyNext) nDirty++;
    ++  return nCache ? (int)(((i64)nDirty * 100) / nCache) : 0;
    ++}
    + 
    + #if defined(SQLITE_CHECK_PAGES) || defined(SQLITE_DEBUG)
    + /*
    +@@ -41183,7 +46117,7 @@ SQLITE_PRIVATE void sqlite3PcacheIterateDirty(PCache *pCache, void (*xIter)(PgHd
    + ** that is allocated when the page cache is created.  The size of the local
    + ** bulk allocation can be adjusted using 
    + **
    +-**     sqlite3_config(SQLITE_CONFIG_PAGECACHE, 0, 0, N).
    ++**     sqlite3_config(SQLITE_CONFIG_PAGECACHE, (void*)0, 0, N).
    + **
    + ** If N is positive, then N pages worth of memory are allocated using a single
    + ** sqlite3Malloc() call and that memory is used for the first N pages allocated.
    +@@ -41214,7 +46148,6 @@ typedef struct PGroup PGroup;
    + struct PgHdr1 {
    +   sqlite3_pcache_page page;      /* Base class. Must be first. pBuf & pExtra */
    +   unsigned int iKey;             /* Key value (page number) */
    +-  u8 isPinned;                   /* Page in use, not on the LRU list */
    +   u8 isBulkLocal;                /* This page from bulk local storage */
    +   u8 isAnchor;                   /* This is the PGroup.lru element */
    +   PgHdr1 *pNext;                 /* Next in hash table chain */
    +@@ -41223,6 +46156,12 @@ struct PgHdr1 {
    +   PgHdr1 *pLruPrev;              /* Previous in LRU list of unpinned pages */
    + };
    + 
    ++/*
    ++** A page is pinned if it is no on the LRU list
    ++*/
    ++#define PAGE_IS_PINNED(p)    ((p)->pLruNext==0)
    ++#define PAGE_IS_UNPINNED(p)  ((p)->pLruNext!=0)
    ++
    + /* Each page cache (or PCache) belongs to a PGroup.  A PGroup is a set 
    + ** of one or more PCaches that are able to recycle each other's unpinned
    + ** pages when they are under memory pressure.  A PGroup is an instance of
    +@@ -41250,7 +46189,7 @@ struct PGroup {
    +   unsigned int nMaxPage;         /* Sum of nMax for purgeable caches */
    +   unsigned int nMinPage;         /* Sum of nMin for purgeable caches */
    +   unsigned int mxPinned;         /* nMaxpage + 10 - nMinPage */
    +-  unsigned int nCurrentPage;     /* Number of purgeable pages allocated */
    ++  unsigned int nPurgeable;       /* Number of purgeable pages allocated */
    +   PgHdr1 lru;                    /* The beginning and end of the LRU list */
    + };
    + 
    +@@ -41264,11 +46203,13 @@ struct PGroup {
    + */
    + struct PCache1 {
    +   /* Cache configuration parameters. Page size (szPage) and the purgeable
    +-  ** flag (bPurgeable) are set when the cache is created. nMax may be 
    ++  ** flag (bPurgeable) and the pnPurgeable pointer are all set when the
    ++  ** cache is created and are never changed thereafter. nMax may be 
    +   ** modified at any time by a call to the pcache1Cachesize() method.
    +   ** The PGroup mutex must be held when accessing nMax.
    +   */
    +   PGroup *pGroup;                     /* PGroup this cache belongs to */
    ++  unsigned int *pnPurgeable;          /* Pointer to pGroup->nPurgeable */
    +   int szPage;                         /* Size of database content section */
    +   int szExtra;                        /* sizeof(MemPage)+sizeof(PgHdr) */
    +   int szAlloc;                        /* Total size of one pcache line */
    +@@ -41363,6 +46304,7 @@ SQLITE_PRIVATE void sqlite3PCacheBufferSetup(void *pBuf, int sz, int n){
    +   if( pcache1.isInit ){
    +     PgFreeslot *p;
    +     if( pBuf==0 ) sz = n = 0;
    ++    if( n==0 ) sz = 0;
    +     sz = ROUNDDOWN8(sz);
    +     pcache1.szSlot = sz;
    +     pcache1.nSlot = pcache1.nFreeSlot = n;
    +@@ -41397,14 +46339,13 @@ static int pcache1InitBulk(PCache1 *pCache){
    +     szBulk = -1024 * (i64)pcache1.nInitPage;
    +   }
    +   if( szBulk > pCache->szAlloc*(i64)pCache->nMax ){
    +-    szBulk = pCache->szAlloc*pCache->nMax;
    ++    szBulk = pCache->szAlloc*(i64)pCache->nMax;
    +   }
    +   zBulk = pCache->pBulk = sqlite3Malloc( szBulk );
    +   sqlite3EndBenignMalloc();
    +   if( zBulk ){
    +     int nBulk = sqlite3MallocSize(zBulk)/pCache->szAlloc;
    +-    int i;
    +-    for(i=0; i<nBulk; i++){
    ++    do{
    +       PgHdr1 *pX = (PgHdr1*)&zBulk[pCache->szPage];
    +       pX->page.pBuf = zBulk;
    +       pX->page.pExtra = &pX[1];
    +@@ -41413,7 +46354,7 @@ static int pcache1InitBulk(PCache1 *pCache){
    +       pX->pNext = pCache->pFree;
    +       pCache->pFree = pX;
    +       zBulk += pCache->szAlloc;
    +-    }
    ++    }while( --nBulk );
    +   }
    +   return pCache->pFree!=0;
    + }
    +@@ -41438,7 +46379,7 @@ static void *pcache1Alloc(int nByte){
    +       pcache1.nFreeSlot--;
    +       pcache1.bUnderPressure = pcache1.nFreeSlot<pcache1.nReserve;
    +       assert( pcache1.nFreeSlot>=0 );
    +-      sqlite3StatusSet(SQLITE_STATUS_PAGECACHE_SIZE, nByte);
    ++      sqlite3StatusHighwater(SQLITE_STATUS_PAGECACHE_SIZE, nByte);
    +       sqlite3StatusUp(SQLITE_STATUS_PAGECACHE_USED, 1);
    +     }
    +     sqlite3_mutex_leave(pcache1.mutex);
    +@@ -41452,7 +46393,7 @@ static void *pcache1Alloc(int nByte){
    +     if( p ){
    +       int sz = sqlite3MallocSize(p);
    +       sqlite3_mutex_enter(pcache1.mutex);
    +-      sqlite3StatusSet(SQLITE_STATUS_PAGECACHE_SIZE, nByte);
    ++      sqlite3StatusHighwater(SQLITE_STATUS_PAGECACHE_SIZE, nByte);
    +       sqlite3StatusUp(SQLITE_STATUS_PAGECACHE_OVERFLOW, sz);
    +       sqlite3_mutex_leave(pcache1.mutex);
    +     }
    +@@ -41466,9 +46407,8 @@ static void *pcache1Alloc(int nByte){
    + ** Free an allocated buffer obtained from pcache1Alloc().
    + */
    + static void pcache1Free(void *p){
    +-  int nFreed = 0;
    +   if( p==0 ) return;
    +-  if( p>=pcache1.pStart && p<pcache1.pEnd ){
    ++  if( SQLITE_WITHIN(p, pcache1.pStart, pcache1.pEnd) ){
    +     PgFreeslot *pSlot;
    +     sqlite3_mutex_enter(pcache1.mutex);
    +     sqlite3StatusDown(SQLITE_STATUS_PAGECACHE_USED, 1);
    +@@ -41483,10 +46423,13 @@ static void pcache1Free(void *p){
    +     assert( sqlite3MemdebugHasType(p, MEMTYPE_PCACHE) );
    +     sqlite3MemdebugSetType(p, MEMTYPE_HEAP);
    + #ifndef SQLITE_DISABLE_PAGECACHE_OVERFLOW_STATS
    +-    nFreed = sqlite3MallocSize(p);
    +-    sqlite3_mutex_enter(pcache1.mutex);
    +-    sqlite3StatusDown(SQLITE_STATUS_PAGECACHE_OVERFLOW, nFreed);
    +-    sqlite3_mutex_leave(pcache1.mutex);
    ++    {
    ++      int nFreed = 0;
    ++      nFreed = sqlite3MallocSize(p);
    ++      sqlite3_mutex_enter(pcache1.mutex);
    ++      sqlite3StatusDown(SQLITE_STATUS_PAGECACHE_OVERFLOW, nFreed);
    ++      sqlite3_mutex_leave(pcache1.mutex);
    ++    }
    + #endif
    +     sqlite3_free(p);
    +   }
    +@@ -41554,9 +46497,7 @@ static PgHdr1 *pcache1AllocPage(PCache1 *pCache, int benignMalloc){
    +     p->isBulkLocal = 0;
    +     p->isAnchor = 0;
    +   }
    +-  if( pCache->bPurgeable ){
    +-    pCache->pGroup->nCurrentPage++;
    +-  }
    ++  (*pCache->pnPurgeable)++;
    +   return p;
    + }
    + 
    +@@ -41577,9 +46518,7 @@ static void pcache1FreePage(PgHdr1 *p){
    +     sqlite3_free(p);
    + #endif
    +   }
    +-  if( pCache->bPurgeable ){
    +-    pCache->pGroup->nCurrentPage--;
    +-  }
    ++  (*pCache->pnPurgeable)--;
    + }
    + 
    + /*
    +@@ -41674,22 +46613,18 @@ static void pcache1ResizeHash(PCache1 *p){
    + ** The PGroup mutex must be held when this function is called.
    + */
    + static PgHdr1 *pcache1PinPage(PgHdr1 *pPage){
    +-  PCache1 *pCache;
    +-
    +   assert( pPage!=0 );
    +-  assert( pPage->isPinned==0 );
    +-  pCache = pPage->pCache;
    ++  assert( PAGE_IS_UNPINNED(pPage) );
    +   assert( pPage->pLruNext );
    +   assert( pPage->pLruPrev );
    +-  assert( sqlite3_mutex_held(pCache->pGroup->mutex) );
    ++  assert( sqlite3_mutex_held(pPage->pCache->pGroup->mutex) );
    +   pPage->pLruPrev->pLruNext = pPage->pLruNext;
    +   pPage->pLruNext->pLruPrev = pPage->pLruPrev;
    +   pPage->pLruNext = 0;
    +   pPage->pLruPrev = 0;
    +-  pPage->isPinned = 1;
    +   assert( pPage->isAnchor==0 );
    +-  assert( pCache->pGroup->lru.isAnchor==1 );
    +-  pCache->nRecyclable--;
    ++  assert( pPage->pCache->pGroup->lru.isAnchor==1 );
    ++  pPage->pCache->nRecyclable--;
    +   return pPage;
    + }
    + 
    +@@ -41723,11 +46658,11 @@ static void pcache1EnforceMaxPage(PCache1 *pCache){
    +   PGroup *pGroup = pCache->pGroup;
    +   PgHdr1 *p;
    +   assert( sqlite3_mutex_held(pGroup->mutex) );
    +-  while( pGroup->nCurrentPage>pGroup->nMaxPage
    ++  while( pGroup->nPurgeable>pGroup->nMaxPage
    +       && (p=pGroup->lru.pLruPrev)->isAnchor==0
    +   ){
    +     assert( p->pCache->pGroup==pGroup );
    +-    assert( p->isPinned==0 );
    ++    assert( PAGE_IS_UNPINNED(p) );
    +     pcache1PinPage(p);
    +     pcache1RemoveFromHash(p, 1);
    +   }
    +@@ -41748,25 +46683,45 @@ static void pcache1TruncateUnsafe(
    +   PCache1 *pCache,             /* The cache to truncate */
    +   unsigned int iLimit          /* Drop pages with this pgno or larger */
    + ){
    +-  TESTONLY( unsigned int nPage = 0; )  /* To assert pCache->nPage is correct */
    +-  unsigned int h;
    ++  TESTONLY( int nPage = 0; )  /* To assert pCache->nPage is correct */
    ++  unsigned int h, iStop;
    +   assert( sqlite3_mutex_held(pCache->pGroup->mutex) );
    +-  for(h=0; h<pCache->nHash; h++){
    +-    PgHdr1 **pp = &pCache->apHash[h]; 
    ++  assert( pCache->iMaxKey >= iLimit );
    ++  assert( pCache->nHash > 0 );
    ++  if( pCache->iMaxKey - iLimit < pCache->nHash ){
    ++    /* If we are just shaving the last few pages off the end of the
    ++    ** cache, then there is no point in scanning the entire hash table.
    ++    ** Only scan those hash slots that might contain pages that need to
    ++    ** be removed. */
    ++    h = iLimit % pCache->nHash;
    ++    iStop = pCache->iMaxKey % pCache->nHash;
    ++    TESTONLY( nPage = -10; )  /* Disable the pCache->nPage validity check */
    ++  }else{
    ++    /* This is the general case where many pages are being removed.
    ++    ** It is necessary to scan the entire hash table */
    ++    h = pCache->nHash/2;
    ++    iStop = h - 1;
    ++  }
    ++  for(;;){
    ++    PgHdr1 **pp;
    +     PgHdr1 *pPage;
    ++    assert( h<pCache->nHash );
    ++    pp = &pCache->apHash[h]; 
    +     while( (pPage = *pp)!=0 ){
    +       if( pPage->iKey>=iLimit ){
    +         pCache->nPage--;
    +         *pp = pPage->pNext;
    +-        if( !pPage->isPinned ) pcache1PinPage(pPage);
    ++        if( PAGE_IS_UNPINNED(pPage) ) pcache1PinPage(pPage);
    +         pcache1FreePage(pPage);
    +       }else{
    +         pp = &pPage->pNext;
    +-        TESTONLY( nPage++; )
    ++        TESTONLY( if( nPage>=0 ) nPage++; )
    +       }
    +     }
    ++    if( h==iStop ) break;
    ++    h = (h+1) % pCache->nHash;
    +   }
    +-  assert( pCache->nPage==nPage );
    ++  assert( nPage<0 || pCache->nPage==(unsigned)nPage );
    + }
    + 
    + /******************************************************************************/
    +@@ -41806,8 +46761,8 @@ static int pcache1Init(void *NotUsed){
    + 
    + #if SQLITE_THREADSAFE
    +   if( sqlite3GlobalConfig.bCoreMutex ){
    +-    pcache1.grp.mutex = sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_LRU);
    +-    pcache1.mutex = sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_PMEM);
    ++    pcache1.grp.mutex = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_LRU);
    ++    pcache1.mutex = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_PMEM);
    +   }
    + #endif
    +   if( pcache1.separateCache
    +@@ -41874,6 +46829,10 @@ static sqlite3_pcache *pcache1Create(int szPage, int szExtra, int bPurgeable){
    +       pCache->nMin = 10;
    +       pGroup->nMinPage += pCache->nMin;
    +       pGroup->mxPinned = pGroup->nMaxPage + 10 - pGroup->nMinPage;
    ++      pCache->pnPurgeable = &pGroup->nPurgeable;
    ++    }else{
    ++      static unsigned int dummyCurrentPage;
    ++      pCache->pnPurgeable = &dummyCurrentPage;
    +     }
    +     pcache1LeaveMutex(pGroup);
    +     if( pCache->nHash==0 ){
    +@@ -41975,7 +46934,7 @@ static SQLITE_NOINLINE PgHdr1 *pcache1FetchStage2(
    +   ){
    +     PCache1 *pOther;
    +     pPage = pGroup->lru.pLruPrev;
    +-    assert( pPage->isPinned==0 );
    ++    assert( PAGE_IS_UNPINNED(pPage) );
    +     pcache1RemoveFromHash(pPage, 0);
    +     pcache1PinPage(pPage);
    +     pOther = pPage->pCache;
    +@@ -41983,7 +46942,7 @@ static SQLITE_NOINLINE PgHdr1 *pcache1FetchStage2(
    +       pcache1FreePage(pPage);
    +       pPage = 0;
    +     }else{
    +-      pGroup->nCurrentPage -= (pOther->bPurgeable - pCache->bPurgeable);
    ++      pGroup->nPurgeable -= (pOther->bPurgeable - pCache->bPurgeable);
    +     }
    +   }
    + 
    +@@ -42002,7 +46961,6 @@ static SQLITE_NOINLINE PgHdr1 *pcache1FetchStage2(
    +     pPage->pCache = pCache;
    +     pPage->pLruPrev = 0;
    +     pPage->pLruNext = 0;
    +-    pPage->isPinned = 1;
    +     *(void **)pPage->page.pExtra = 0;
    +     pCache->apHash[h] = pPage;
    +     if( iKey>pCache->iMaxKey ){
    +@@ -42088,7 +47046,7 @@ static PgHdr1 *pcache1FetchNoMutex(
    +   ** Otherwise (page not in hash and createFlag!=0) continue with
    +   ** subsequent steps to try to create the page. */
    +   if( pPage ){
    +-    if( !pPage->isPinned ){
    ++    if( PAGE_IS_UNPINNED(pPage) ){
    +       return pcache1PinPage(pPage);
    +     }else{
    +       return pPage;
    +@@ -42163,9 +47121,9 @@ static void pcache1Unpin(
    +   ** part of the PGroup LRU list.
    +   */
    +   assert( pPage->pLruPrev==0 && pPage->pLruNext==0 );
    +-  assert( pPage->isPinned==1 );
    ++  assert( PAGE_IS_PINNED(pPage) );
    + 
    +-  if( reuseUnlikely || pGroup->nCurrentPage>pGroup->nMaxPage ){
    ++  if( reuseUnlikely || pGroup->nPurgeable>pGroup->nMaxPage ){
    +     pcache1RemoveFromHash(pPage, 1);
    +   }else{
    +     /* Add the page to the PGroup LRU list. */
    +@@ -42174,7 +47132,6 @@ static void pcache1Unpin(
    +     (pPage->pLruNext = *ppFirst)->pLruPrev = pPage;
    +     *ppFirst = pPage;
    +     pCache->nRecyclable++;
    +-    pPage->isPinned = 0;
    +   }
    + 
    +   pcache1LeaveMutex(pCache->pGroup);
    +@@ -42243,7 +47200,7 @@ static void pcache1Destroy(sqlite3_pcache *p){
    +   PGroup *pGroup = pCache->pGroup;
    +   assert( pCache->bPurgeable || (pCache->nMax==0 && pCache->nMin==0) );
    +   pcache1EnterMutex(pGroup);
    +-  pcache1TruncateUnsafe(pCache, 0);
    ++  if( pCache->nPage ) pcache1TruncateUnsafe(pCache, 0);
    +   assert( pGroup->nMaxPage >= pCache->nMax );
    +   pGroup->nMaxPage -= pCache->nMax;
    +   assert( pGroup->nMinPage >= pCache->nMin );
    +@@ -42307,7 +47264,7 @@ SQLITE_PRIVATE int sqlite3PcacheReleaseMemory(int nReq){
    +   int nFree = 0;
    +   assert( sqlite3_mutex_notheld(pcache1.grp.mutex) );
    +   assert( sqlite3_mutex_notheld(pcache1.mutex) );
    +-  if( sqlite3GlobalConfig.nPage==0 ){
    ++  if( sqlite3GlobalConfig.pPage==0 ){
    +     PgHdr1 *p;
    +     pcache1EnterMutex(&pcache1.grp);
    +     while( (nReq<0 || nFree<nReq)
    +@@ -42318,7 +47275,7 @@ SQLITE_PRIVATE int sqlite3PcacheReleaseMemory(int nReq){
    + #ifdef SQLITE_PCACHE_SEPARATE_HEADER
    +       nFree += sqlite3MemSize(p);
    + #endif
    +-      assert( p->isPinned==0 );
    ++      assert( PAGE_IS_UNPINNED(p) );
    +       pcache1PinPage(p);
    +       pcache1RemoveFromHash(p, 1);
    +     }
    +@@ -42342,10 +47299,10 @@ SQLITE_PRIVATE void sqlite3PcacheStats(
    +   PgHdr1 *p;
    +   int nRecyclable = 0;
    +   for(p=pcache1.grp.lru.pLruNext; p && !p->isAnchor; p=p->pLruNext){
    +-    assert( p->isPinned==0 );
    ++    assert( PAGE_IS_UNPINNED(p) );
    +     nRecyclable++;
    +   }
    +-  *pnCurrent = pcache1.grp.nCurrentPage;
    ++  *pnCurrent = pcache1.grp.nPurgeable;
    +   *pnMax = (int)pcache1.grp.nMaxPage;
    +   *pnMin = (int)pcache1.grp.nMinPage;
    +   *pnRecyclable = nRecyclable;
    +@@ -42413,8 +47370,9 @@ SQLITE_PRIVATE void sqlite3PcacheStats(
    + ** of the first SMALLEST is O(NlogN).  Second and subsequent SMALLEST
    + ** primitives are constant time.  The cost of DESTROY is O(N).
    + **
    +-** There is an added cost of O(N) when switching between TEST and
    +-** SMALLEST primitives.
    ++** TEST and SMALLEST may not be used by the same RowSet.  This used to
    ++** be possible, but the feature was not used, so it was removed in order
    ++** to simplify the code.
    + */
    + /* #include "sqliteInt.h" */
    + 
    +@@ -42535,9 +47493,11 @@ SQLITE_PRIVATE void sqlite3RowSetClear(RowSet *p){
    + */
    + static struct RowSetEntry *rowSetEntryAlloc(RowSet *p){
    +   assert( p!=0 );
    +-  if( p->nFresh==0 ){
    ++  if( p->nFresh==0 ){  /*OPTIMIZATION-IF-FALSE*/
    ++    /* We could allocate a fresh RowSetEntry each time one is needed, but it
    ++    ** is more efficient to pull a preallocated entry from the pool */
    +     struct RowSetChunk *pNew;
    +-    pNew = sqlite3DbMallocRaw(p->db, sizeof(*pNew));
    ++    pNew = sqlite3DbMallocRawNN(p->db, sizeof(*pNew));
    +     if( pNew==0 ){
    +       return 0;
    +     }
    +@@ -42569,7 +47529,9 @@ SQLITE_PRIVATE void sqlite3RowSetInsert(RowSet *p, i64 rowid){
    +   pEntry->pRight = 0;
    +   pLast = p->pLast;
    +   if( pLast ){
    +-    if( (p->rsFlags & ROWSET_SORTED)!=0 && rowid<=pLast->v ){
    ++    if( rowid<=pLast->v ){  /*OPTIMIZATION-IF-FALSE*/
    ++      /* Avoid unnecessary sorts by preserving the ROWSET_SORTED flags
    ++      ** where possible */
    +       p->rsFlags &= ~ROWSET_SORTED;
    +     }
    +     pLast->pRight = pEntry;
    +@@ -42593,28 +47555,26 @@ static struct RowSetEntry *rowSetEntryMerge(
    +   struct RowSetEntry *pTail;
    + 
    +   pTail = &head;
    +-  while( pA && pB ){
    ++  assert( pA!=0 && pB!=0 );
    ++  for(;;){
    +     assert( pA->pRight==0 || pA->v<=pA->pRight->v );
    +     assert( pB->pRight==0 || pB->v<=pB->pRight->v );
    +-    if( pA->v<pB->v ){
    +-      pTail->pRight = pA;
    ++    if( pA->v<=pB->v ){
    ++      if( pA->v<pB->v ) pTail = pTail->pRight = pA;
    +       pA = pA->pRight;
    +-      pTail = pTail->pRight;
    +-    }else if( pB->v<pA->v ){
    +-      pTail->pRight = pB;
    +-      pB = pB->pRight;
    +-      pTail = pTail->pRight;
    ++      if( pA==0 ){
    ++        pTail->pRight = pB;
    ++        break;
    ++      }
    +     }else{
    +-      pA = pA->pRight;
    ++      pTail = pTail->pRight = pB;
    ++      pB = pB->pRight;
    ++      if( pB==0 ){
    ++        pTail->pRight = pA;
    ++        break;
    ++      }
    +     }
    +   }
    +-  if( pA ){
    +-    assert( pA->pRight==0 || pA->v<=pA->pRight->v );
    +-    pTail->pRight = pA;
    +-  }else{
    +-    assert( pB==0 || pB->pRight==0 || pB->v<=pB->pRight->v );
    +-    pTail->pRight = pB;
    +-  }
    +   return head.pRight;
    + }
    + 
    +@@ -42637,9 +47597,10 @@ static struct RowSetEntry *rowSetEntrySort(struct RowSetEntry *pIn){
    +     aBucket[i] = pIn;
    +     pIn = pNext;
    +   }
    +-  pIn = 0;
    +-  for(i=0; i<sizeof(aBucket)/sizeof(aBucket[0]); i++){
    +-    pIn = rowSetEntryMerge(pIn, aBucket[i]);
    ++  pIn = aBucket[0];
    ++  for(i=1; i<sizeof(aBucket)/sizeof(aBucket[0]); i++){
    ++    if( aBucket[i]==0 ) continue;
    ++    pIn = pIn ? rowSetEntryMerge(pIn, aBucket[i]) : aBucket[i];
    +   }
    +   return pIn;
    + }
    +@@ -42691,23 +47652,29 @@ static struct RowSetEntry *rowSetNDeepTree(
    + ){
    +   struct RowSetEntry *p;         /* Root of the new tree */
    +   struct RowSetEntry *pLeft;     /* Left subtree */
    +-  if( *ppList==0 ){
    +-    return 0;
    +-  }
    +-  if( iDepth==1 ){
    ++  if( *ppList==0 ){ /*OPTIMIZATION-IF-TRUE*/
    ++    /* Prevent unnecessary deep recursion when we run out of entries */
    ++    return 0; 
    ++  }
    ++  if( iDepth>1 ){   /*OPTIMIZATION-IF-TRUE*/
    ++    /* This branch causes a *balanced* tree to be generated.  A valid tree
    ++    ** is still generated without this branch, but the tree is wildly
    ++    ** unbalanced and inefficient. */
    ++    pLeft = rowSetNDeepTree(ppList, iDepth-1);
    ++    p = *ppList;
    ++    if( p==0 ){     /*OPTIMIZATION-IF-FALSE*/
    ++      /* It is safe to always return here, but the resulting tree
    ++      ** would be unbalanced */
    ++      return pLeft;
    ++    }
    ++    p->pLeft = pLeft;
    ++    *ppList = p->pRight;
    ++    p->pRight = rowSetNDeepTree(ppList, iDepth-1);
    ++  }else{
    +     p = *ppList;
    +     *ppList = p->pRight;
    +     p->pLeft = p->pRight = 0;
    +-    return p;
    +-  }
    +-  pLeft = rowSetNDeepTree(ppList, iDepth-1);
    +-  p = *ppList;
    +-  if( p==0 ){
    +-    return pLeft;
    +   }
    +-  p->pLeft = pLeft;
    +-  *ppList = p->pRight;
    +-  p->pRight = rowSetNDeepTree(ppList, iDepth-1);
    +   return p;
    + }
    + 
    +@@ -42734,59 +47701,37 @@ static struct RowSetEntry *rowSetListToTree(struct RowSetEntry *pList){
    +   return p;
    + }
    + 
    +-/*
    +-** Take all the entries on p->pEntry and on the trees in p->pForest and
    +-** sort them all together into one big ordered list on p->pEntry.
    +-**
    +-** This routine should only be called once in the life of a RowSet.
    +-*/
    +-static void rowSetToList(RowSet *p){
    +-
    +-  /* This routine is called only once */
    +-  assert( p!=0 && (p->rsFlags & ROWSET_NEXT)==0 );
    +-
    +-  if( (p->rsFlags & ROWSET_SORTED)==0 ){
    +-    p->pEntry = rowSetEntrySort(p->pEntry);
    +-  }
    +-
    +-  /* While this module could theoretically support it, sqlite3RowSetNext()
    +-  ** is never called after sqlite3RowSetText() for the same RowSet.  So
    +-  ** there is never a forest to deal with.  Should this change, simply
    +-  ** remove the assert() and the #if 0. */
    +-  assert( p->pForest==0 );
    +-#if 0
    +-  while( p->pForest ){
    +-    struct RowSetEntry *pTree = p->pForest->pLeft;
    +-    if( pTree ){
    +-      struct RowSetEntry *pHead, *pTail;
    +-      rowSetTreeToList(pTree, &pHead, &pTail);
    +-      p->pEntry = rowSetEntryMerge(p->pEntry, pHead);
    +-    }
    +-    p->pForest = p->pForest->pRight;
    +-  }
    +-#endif
    +-  p->rsFlags |= ROWSET_NEXT;  /* Verify this routine is never called again */
    +-}
    +-
    + /*
    + ** Extract the smallest element from the RowSet.
    + ** Write the element into *pRowid.  Return 1 on success.  Return
    + ** 0 if the RowSet is already empty.
    + **
    + ** After this routine has been called, the sqlite3RowSetInsert()
    +-** routine may not be called again.  
    ++** routine may not be called again.
    ++**
    ++** This routine may not be called after sqlite3RowSetTest() has
    ++** been used.  Older versions of RowSet allowed that, but as the
    ++** capability was not used by the code generator, it was removed
    ++** for code economy.
    + */
    + SQLITE_PRIVATE int sqlite3RowSetNext(RowSet *p, i64 *pRowid){
    +   assert( p!=0 );
    ++  assert( p->pForest==0 );  /* Cannot be used with sqlite3RowSetText() */
    + 
    +   /* Merge the forest into a single sorted list on first call */
    +-  if( (p->rsFlags & ROWSET_NEXT)==0 ) rowSetToList(p);
    ++  if( (p->rsFlags & ROWSET_NEXT)==0 ){  /*OPTIMIZATION-IF-FALSE*/
    ++    if( (p->rsFlags & ROWSET_SORTED)==0 ){  /*OPTIMIZATION-IF-FALSE*/
    ++      p->pEntry = rowSetEntrySort(p->pEntry);
    ++    }
    ++    p->rsFlags |= ROWSET_SORTED|ROWSET_NEXT;
    ++  }
    + 
    +   /* Return the next entry on the list */
    +   if( p->pEntry ){
    +     *pRowid = p->pEntry->v;
    +     p->pEntry = p->pEntry->pRight;
    +-    if( p->pEntry==0 ){
    ++    if( p->pEntry==0 ){ /*OPTIMIZATION-IF-TRUE*/
    ++      /* Free memory immediately, rather than waiting on sqlite3_finalize() */
    +       sqlite3RowSetClear(p);
    +     }
    +     return 1;
    +@@ -42809,13 +47754,15 @@ SQLITE_PRIVATE int sqlite3RowSetTest(RowSet *pRowSet, int iBatch, sqlite3_int64
    +   /* This routine is never called after sqlite3RowSetNext() */
    +   assert( pRowSet!=0 && (pRowSet->rsFlags & ROWSET_NEXT)==0 );
    + 
    +-  /* Sort entries into the forest on the first test of a new batch 
    ++  /* Sort entries into the forest on the first test of a new batch.
    ++  ** To save unnecessary work, only do this when the batch number changes.
    +   */
    +-  if( iBatch!=pRowSet->iBatch ){
    ++  if( iBatch!=pRowSet->iBatch ){  /*OPTIMIZATION-IF-FALSE*/
    +     p = pRowSet->pEntry;
    +     if( p ){
    +       struct RowSetEntry **ppPrevTree = &pRowSet->pForest;
    +-      if( (pRowSet->rsFlags & ROWSET_SORTED)==0 ){
    ++      if( (pRowSet->rsFlags & ROWSET_SORTED)==0 ){ /*OPTIMIZATION-IF-FALSE*/
    ++        /* Only sort the current set of entiries if they need it */
    +         p = rowSetEntrySort(p);
    +       }
    +       for(pTree = pRowSet->pForest; pTree; pTree=pTree->pRight){
    +@@ -42905,21 +47852,21 @@ SQLITE_PRIVATE int sqlite3RowSetTest(RowSet *pRowSet, int iBatch, sqlite3_int64
    + ** the implementation of each function in log.c for further details.
    + */
    + 
    +-#ifndef _WAL_H_
    +-#define _WAL_H_
    ++#ifndef SQLITE_WAL_H
    ++#define SQLITE_WAL_H
    + 
    + /* #include "sqliteInt.h" */
    + 
    +-/* Additional values that can be added to the sync_flags argument of
    +-** sqlite3WalFrames():
    ++/* Macros for extracting appropriate sync flags for either transaction
    ++** commits (WAL_SYNC_FLAGS(X)) or for checkpoint ops (CKPT_SYNC_FLAGS(X)):
    + */
    +-#define WAL_SYNC_TRANSACTIONS  0x20   /* Sync at the end of each transaction */
    +-#define SQLITE_SYNC_MASK       0x13   /* Mask off the SQLITE_SYNC_* values */
    ++#define WAL_SYNC_FLAGS(X)   ((X)&0x03)
    ++#define CKPT_SYNC_FLAGS(X)  (((X)>>2)&0x03)
    + 
    + #ifdef SQLITE_OMIT_WAL
    + # define sqlite3WalOpen(x,y,z)                   0
    + # define sqlite3WalLimit(x,y)
    +-# define sqlite3WalClose(w,x,y,z)                0
    ++# define sqlite3WalClose(v,w,x,y,z)              0
    + # define sqlite3WalBeginReadTransaction(y,z)     0
    + # define sqlite3WalEndReadTransaction(z)
    + # define sqlite3WalDbsize(y)                     0
    +@@ -42929,12 +47876,13 @@ SQLITE_PRIVATE int sqlite3RowSetTest(RowSet *pRowSet, int iBatch, sqlite3_int64
    + # define sqlite3WalSavepoint(y,z)
    + # define sqlite3WalSavepointUndo(y,z)            0
    + # define sqlite3WalFrames(u,v,w,x,y,z)           0
    +-# define sqlite3WalCheckpoint(r,s,t,u,v,w,x,y,z) 0
    ++# define sqlite3WalCheckpoint(q,r,s,t,u,v,w,x,y,z) 0
    + # define sqlite3WalCallback(z)                   0
    + # define sqlite3WalExclusiveMode(y,z)            0
    + # define sqlite3WalHeapMemory(z)                 0
    + # define sqlite3WalFramesize(z)                  0
    + # define sqlite3WalFindFrame(x,y,z)              0
    ++# define sqlite3WalFile(x)                       0
    + #else
    + 
    + #define WAL_SAVEPOINT_NDATA 4
    +@@ -42946,7 +47894,7 @@ typedef struct Wal Wal;
    + 
    + /* Open and close a connection to a write-ahead log. */
    + SQLITE_PRIVATE int sqlite3WalOpen(sqlite3_vfs*, sqlite3_file*, const char *, int, i64, Wal**);
    +-SQLITE_PRIVATE int sqlite3WalClose(Wal *pWal, int sync_flags, int, u8 *);
    ++SQLITE_PRIVATE int sqlite3WalClose(Wal *pWal, sqlite3*, int sync_flags, int, u8 *);
    + 
    + /* Set the limiting size of a WAL file. */
    + SQLITE_PRIVATE void sqlite3WalLimit(Wal*, i64);
    +@@ -42989,6 +47937,7 @@ SQLITE_PRIVATE int sqlite3WalFrames(Wal *pWal, int, PgHdr *, Pgno, int, int);
    + /* Copy pages from the log to the database file */ 
    + SQLITE_PRIVATE int sqlite3WalCheckpoint(
    +   Wal *pWal,                      /* Write-ahead log connection */
    ++  sqlite3 *db,                    /* Check this handle's interrupt flag */
    +   int eMode,                      /* One of PASSIVE, FULL and RESTART */
    +   int (*xBusy)(void*),            /* Function to call when busy */
    +   void *pBusyArg,                 /* Context argument for xBusyHandler */
    +@@ -43017,6 +47966,12 @@ SQLITE_PRIVATE int sqlite3WalExclusiveMode(Wal *pWal, int op);
    + */
    + SQLITE_PRIVATE int sqlite3WalHeapMemory(Wal *pWal);
    + 
    ++#ifdef SQLITE_ENABLE_SNAPSHOT
    ++SQLITE_PRIVATE int sqlite3WalSnapshotGet(Wal *pWal, sqlite3_snapshot **ppSnapshot);
    ++SQLITE_PRIVATE void sqlite3WalSnapshotOpen(Wal *pWal, sqlite3_snapshot *pSnapshot);
    ++SQLITE_PRIVATE int sqlite3WalSnapshotRecover(Wal *pWal);
    ++#endif
    ++
    + #ifdef SQLITE_ENABLE_ZIPVFS
    + /* If the WAL file is not empty, return the number of bytes of content
    + ** stored in each frame (i.e. the db page-size when the WAL was created).
    +@@ -43024,8 +47979,11 @@ SQLITE_PRIVATE int sqlite3WalHeapMemory(Wal *pWal);
    + SQLITE_PRIVATE int sqlite3WalFramesize(Wal *pWal);
    + #endif
    + 
    ++/* Return the sqlite3_file object for the WAL file */
    ++SQLITE_PRIVATE sqlite3_file *sqlite3WalFile(Wal *pWal);
    ++
    + #endif /* ifndef SQLITE_OMIT_WAL */
    +-#endif /* _WAL_H_ */
    ++#endif /* SQLITE_WAL_H */
    + 
    + /************** End of wal.h *************************************************/
    + /************** Continuing where we left off in pager.c **********************/
    +@@ -43136,8 +48094,8 @@ int sqlite3PagerTrace=1;  /* True to enable tracing */
    + ** associated file-descriptor is returned. FILEHANDLEID() takes an sqlite3_file
    + ** struct as its argument.
    + */
    +-#define PAGERID(p) ((int)(p->fd))
    +-#define FILEHANDLEID(fd) ((int)fd)
    ++#define PAGERID(p) (SQLITE_PTR_TO_INT(p->fd))
    ++#define FILEHANDLEID(fd) (SQLITE_PTR_TO_INT(fd))
    + 
    + /*
    + ** The Pager.eState variable stores the current 'state' of a pager. A
    +@@ -43436,6 +48394,7 @@ int sqlite3PagerTrace=1;  /* True to enable tracing */
    + */
    + #define MAX_SECTOR_SIZE 0x10000
    + 
    ++
    + /*
    + ** An instance of the following structure is allocated for each active
    + ** savepoint and statement transaction in the system. All such structures
    +@@ -43623,6 +48582,18 @@ struct PagerSavepoint {
    + **   is set to zero in all other states. In PAGER_ERROR state, Pager.errCode 
    + **   is always set to SQLITE_FULL, SQLITE_IOERR or one of the SQLITE_IOERR_XXX 
    + **   sub-codes.
    ++**
    ++** syncFlags, walSyncFlags
    ++**
    ++**   syncFlags is either SQLITE_SYNC_NORMAL (0x02) or SQLITE_SYNC_FULL (0x03).
    ++**   syncFlags is used for rollback mode.  walSyncFlags is used for WAL mode
    ++**   and contains the flags used to sync the checkpoint operations in the
    ++**   lower two bits, and sync flags used for transaction commits in the WAL
    ++**   file in bits 0x04 and 0x08.  In other words, to get the correct sync flags
    ++**   for checkpoint operations, use (walSyncFlags&0x03) and to get the correct
    ++**   sync flags for transaction commit, use ((walSyncFlags>>2)&0x03).  Note
    ++**   that with synchronous=NORMAL in WAL mode, transaction commit is not synced
    ++**   meaning that the 0x04 and 0x08 bits are both zero.
    + */
    + struct Pager {
    +   sqlite3_vfs *pVfs;          /* OS functions to use for IO */
    +@@ -43631,9 +48602,9 @@ struct Pager {
    +   u8 useJournal;              /* Use a rollback journal on this file */
    +   u8 noSync;                  /* Do not sync the journal if true */
    +   u8 fullSync;                /* Do extra syncs of the journal for robustness */
    +-  u8 ckptSyncFlags;           /* SYNC_NORMAL or SYNC_FULL for checkpoint */
    +-  u8 walSyncFlags;            /* SYNC_NORMAL or SYNC_FULL for wal writes */
    ++  u8 extraSync;               /* sync directory after journal delete */
    +   u8 syncFlags;               /* SYNC_NORMAL or SYNC_FULL otherwise */
    ++  u8 walSyncFlags;            /* See description above */
    +   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 */
    +@@ -43699,6 +48670,7 @@ struct Pager {
    +   int nRead;                  /* Database pages read */
    + #endif
    +   void (*xReiniter)(DbPage*); /* Call this routine when reloading pages */
    ++  int (*xGet)(Pager*,Pgno,DbPage**,int); /* Routine to fetch a patch */
    + #ifdef SQLITE_HAS_CODEC
    +   void *(*xCodec)(void*,void*,Pgno,int); /* Routine for en/decoding data */
    +   void (*xCodecSizeChng)(void*,int,int); /* Notify of page size changes */
    +@@ -43819,13 +48791,20 @@ static const unsigned char aJournalMagic[] = {
    + #define isOpen(pFd) ((pFd)->pMethods!=0)
    + 
    + /*
    +-** Return true if this pager uses a write-ahead log instead of the usual
    +-** rollback journal. Otherwise false.
    ++** Return true if this pager uses a write-ahead log to read page pgno.
    ++** Return false if the pager reads pgno directly from the database.
    + */
    +-#ifndef SQLITE_OMIT_WAL
    +-static int pagerUseWal(Pager *pPager){
    +-  return (pPager->pWal!=0);
    ++#if !defined(SQLITE_OMIT_WAL) && defined(SQLITE_DIRECT_OVERFLOW_READ)
    ++SQLITE_PRIVATE int sqlite3PagerUseWal(Pager *pPager, Pgno pgno){
    ++  u32 iRead = 0;
    ++  int rc;
    ++  if( pPager->pWal==0 ) return 0;
    ++  rc = sqlite3WalFindFrame(pPager->pWal, pgno, &iRead);
    ++  return rc || iRead;
    + }
    ++#endif
    ++#ifndef SQLITE_OMIT_WAL
    ++# define pagerUseWal(x) ((x)->pWal!=0)
    + #else
    + # define pagerUseWal(x) 0
    + # define pagerRollbackWal(x) 0
    +@@ -43878,6 +48857,7 @@ static int assert_pager_state(Pager *p){
    +   ** state.
    +   */
    +   if( MEMDB ){
    ++    assert( !isOpen(p->fd) );
    +     assert( p->noSync );
    +     assert( p->journalMode==PAGER_JOURNALMODE_OFF 
    +          || p->journalMode==PAGER_JOURNALMODE_MEMORY 
    +@@ -43944,6 +48924,7 @@ static int assert_pager_state(Pager *p){
    +       assert( isOpen(p->jfd) 
    +            || p->journalMode==PAGER_JOURNALMODE_OFF 
    +            || p->journalMode==PAGER_JOURNALMODE_WAL 
    ++           || (sqlite3OsDeviceCharacteristics(p->fd)&SQLITE_IOCAP_BATCH_ATOMIC)
    +       );
    +       assert( pPager->dbOrigSize<=pPager->dbHintSize );
    +       break;
    +@@ -43955,6 +48936,7 @@ static int assert_pager_state(Pager *p){
    +       assert( isOpen(p->jfd) 
    +            || p->journalMode==PAGER_JOURNALMODE_OFF 
    +            || p->journalMode==PAGER_JOURNALMODE_WAL 
    ++           || (sqlite3OsDeviceCharacteristics(p->fd)&SQLITE_IOCAP_BATCH_ATOMIC)
    +       );
    +       break;
    + 
    +@@ -43964,7 +48946,7 @@ static int assert_pager_state(Pager *p){
    +       ** back to OPEN state.
    +       */
    +       assert( pPager->errCode!=SQLITE_OK );
    +-      assert( sqlite3PcacheRefCount(pPager->pPCache)>0 );
    ++      assert( sqlite3PcacheRefCount(pPager->pPCache)>0 || pPager->tempFile );
    +       break;
    +   }
    + 
    +@@ -44023,6 +49005,33 @@ static char *print_pager_state(Pager *p){
    + }
    + #endif
    + 
    ++/* Forward references to the various page getters */
    ++static int getPageNormal(Pager*,Pgno,DbPage**,int);
    ++static int getPageError(Pager*,Pgno,DbPage**,int);
    ++#if SQLITE_MAX_MMAP_SIZE>0
    ++static int getPageMMap(Pager*,Pgno,DbPage**,int);
    ++#endif
    ++
    ++/*
    ++** Set the Pager.xGet method for the appropriate routine used to fetch
    ++** content from the pager.
    ++*/
    ++static void setGetterMethod(Pager *pPager){
    ++  if( pPager->errCode ){
    ++    pPager->xGet = getPageError;
    ++#if SQLITE_MAX_MMAP_SIZE>0
    ++  }else if( USEFETCH(pPager)
    ++#ifdef SQLITE_HAS_CODEC
    ++   && pPager->xCodec==0
    ++#endif
    ++  ){
    ++    pPager->xGet = getPageMMap;
    ++#endif /* SQLITE_MAX_MMAP_SIZE>0 */
    ++  }else{
    ++    pPager->xGet = getPageNormal;
    ++  }
    ++}
    ++
    + /*
    + ** Return true if it is necessary to write page *pPg into the sub-journal.
    + ** A page needs to be written into the sub-journal if there exists one
    +@@ -44138,34 +49147,47 @@ static int pagerLockDb(Pager *pPager, int eLock){
    + }
    + 
    + /*
    +-** This function determines whether or not the atomic-write optimization
    +-** can be used with this pager. The optimization can be used if:
    ++** This function determines whether or not the atomic-write or
    ++** atomic-batch-write optimizations can be used with this pager. The
    ++** atomic-write optimization can be used if:
    + **
    + **  (a) the value returned by OsDeviceCharacteristics() indicates that
    + **      a database page may be written atomically, and
    + **  (b) the value returned by OsSectorSize() is less than or equal
    + **      to the page size.
    + **
    +-** The optimization is also always enabled for temporary files. It is
    +-** an error to call this function if pPager is opened on an in-memory
    +-** database.
    ++** If it can be used, then the value returned is the size of the journal 
    ++** file when it contains rollback data for exactly one page.
    ++**
    ++** The atomic-batch-write optimization can be used if OsDeviceCharacteristics()
    ++** returns a value with the SQLITE_IOCAP_BATCH_ATOMIC bit set. -1 is
    ++** returned in this case.
    + **
    +-** If the optimization cannot be used, 0 is returned. If it can be used,
    +-** then the value returned is the size of the journal file when it
    +-** contains rollback data for exactly one page.
    ++** If neither optimization can be used, 0 is returned.
    + */
    +-#ifdef SQLITE_ENABLE_ATOMIC_WRITE
    + static int jrnlBufferSize(Pager *pPager){
    +   assert( !MEMDB );
    +-  if( !pPager->tempFile ){
    +-    int dc;                           /* Device characteristics */
    +-    int nSector;                      /* Sector size */
    +-    int szPage;                       /* Page size */
    + 
    +-    assert( isOpen(pPager->fd) );
    +-    dc = sqlite3OsDeviceCharacteristics(pPager->fd);
    +-    nSector = pPager->sectorSize;
    +-    szPage = pPager->pageSize;
    ++#if defined(SQLITE_ENABLE_ATOMIC_WRITE) \
    ++ || defined(SQLITE_ENABLE_BATCH_ATOMIC_WRITE)
    ++  int dc;                           /* Device characteristics */
    ++
    ++  assert( isOpen(pPager->fd) );
    ++  dc = sqlite3OsDeviceCharacteristics(pPager->fd);
    ++#else
    ++  UNUSED_PARAMETER(pPager);
    ++#endif
    ++
    ++#ifdef SQLITE_ENABLE_BATCH_ATOMIC_WRITE
    ++  if( dc&SQLITE_IOCAP_BATCH_ATOMIC ){
    ++    return -1;
    ++  }
    ++#endif
    ++
    ++#ifdef SQLITE_ENABLE_ATOMIC_WRITE
    ++  {
    ++    int nSector = pPager->sectorSize;
    ++    int szPage = pPager->pageSize;
    + 
    +     assert(SQLITE_IOCAP_ATOMIC512==(512>>8));
    +     assert(SQLITE_IOCAP_ATOMIC64K==(65536>>8));
    +@@ -44175,9 +49197,11 @@ static int jrnlBufferSize(Pager *pPager){
    +   }
    + 
    +   return JOURNAL_HDR_SZ(pPager) + JOURNAL_PG_SZ(pPager);
    +-}
    + #endif
    + 
    ++  return 0;
    ++}
    ++
    + /*
    + ** If SQLITE_CHECK_PAGES is defined then we do some sanity checking
    + ** on the cache using a hash function.  This is used for testing
    +@@ -44259,6 +49283,7 @@ static int readMasterJournal(sqlite3_file *pJrnl, char *zMaster, u32 nMaster){
    +    || szJ<16
    +    || SQLITE_OK!=(rc = read32bits(pJrnl, szJ-16, &len))
    +    || len>=nMaster 
    ++   || len>szJ-16
    +    || len==0 
    +    || SQLITE_OK!=(rc = read32bits(pJrnl, szJ-12, &cksum))
    +    || SQLITE_OK!=(rc = sqlite3OsRead(pJrnl, aMagic, 8, szJ-8))
    +@@ -44336,6 +49361,7 @@ static i64 journalHdrOffset(Pager *pPager){
    + static int zeroJournalHdr(Pager *pPager, int doTruncate){
    +   int rc = SQLITE_OK;                               /* Return code */
    +   assert( isOpen(pPager->jfd) );
    ++  assert( !sqlite3JournalIsInMemory(pPager->jfd) );
    +   if( pPager->journalOff ){
    +     const i64 iLimit = pPager->journalSizeLimit;    /* Local cache of jsl */
    + 
    +@@ -44717,7 +49743,7 @@ static void releaseAllSavepoints(Pager *pPager){
    +   for(ii=0; ii<pPager->nSavepoint; ii++){
    +     sqlite3BitvecDestroy(pPager->aSavepoint[ii].pInSavepoint);
    +   }
    +-  if( !pPager->exclusiveMode || sqlite3IsMemJournal(pPager->sjfd) ){
    ++  if( !pPager->exclusiveMode || sqlite3JournalIsInMemory(pPager->sjfd) ){
    +     sqlite3OsClose(pPager->sjfd);
    +   }
    +   sqlite3_free(pPager->aSavepoint);
    +@@ -44823,13 +49849,18 @@ static void pager_unlock(Pager *pPager){
    +   ** it can safely move back to PAGER_OPEN state. This happens in both
    +   ** normal and exclusive-locking mode.
    +   */
    ++  assert( pPager->errCode==SQLITE_OK || !MEMDB );
    +   if( pPager->errCode ){
    +-    assert( !MEMDB );
    +-    pager_reset(pPager);
    +-    pPager->changeCountDone = pPager->tempFile;
    +-    pPager->eState = PAGER_OPEN;
    +-    pPager->errCode = SQLITE_OK;
    ++    if( pPager->tempFile==0 ){
    ++      pager_reset(pPager);
    ++      pPager->changeCountDone = 0;
    ++      pPager->eState = PAGER_OPEN;
    ++    }else{
    ++      pPager->eState = (isOpen(pPager->jfd) ? PAGER_OPEN : PAGER_READER);
    ++    }
    +     if( USEFETCH(pPager) ) sqlite3OsUnfetch(pPager->fd, 0, 0);
    ++    pPager->errCode = SQLITE_OK;
    ++    setGetterMethod(pPager);
    +   }
    + 
    +   pPager->journalOff = 0;
    +@@ -44867,12 +49898,36 @@ static int pager_error(Pager *pPager, int rc){
    +   if( rc2==SQLITE_FULL || rc2==SQLITE_IOERR ){
    +     pPager->errCode = rc;
    +     pPager->eState = PAGER_ERROR;
    ++    setGetterMethod(pPager);
    +   }
    +   return rc;
    + }
    + 
    + static int pager_truncate(Pager *pPager, Pgno nPage);
    + 
    ++/*
    ++** The write transaction open on pPager is being committed (bCommit==1)
    ++** or rolled back (bCommit==0).
    ++**
    ++** Return TRUE if and only if all dirty pages should be flushed to disk.
    ++**
    ++** Rules:
    ++**
    ++**   *  For non-TEMP databases, always sync to disk.  This is necessary
    ++**      for transactions to be durable.
    ++**
    ++**   *  Sync TEMP database only on a COMMIT (not a ROLLBACK) when the backing
    ++**      file has been created already (via a spill on pagerStress()) and
    ++**      when the number of dirty pages in memory exceeds 25% of the total
    ++**      cache size.
    ++*/
    ++static int pagerFlushOnCommit(Pager *pPager, int bCommit){
    ++  if( pPager->tempFile==0 ) return 1;
    ++  if( !bCommit ) return 0;
    ++  if( !isOpen(pPager->fd) ) return 0;
    ++  return (sqlite3PCachePercentDirty(pPager->pPCache)>=25);
    ++}
    ++
    + /*
    + ** This routine ends a transaction. A transaction is usually ended by 
    + ** either a COMMIT or a ROLLBACK operation. This routine may be called 
    +@@ -44950,13 +50005,15 @@ static int pager_end_transaction(Pager *pPager, int hasMaster, int bCommit){
    +   }
    + 
    +   releaseAllSavepoints(pPager);
    +-  assert( isOpen(pPager->jfd) || pPager->pInJournal==0 );
    ++  assert( isOpen(pPager->jfd) || pPager->pInJournal==0 
    ++      || (sqlite3OsDeviceCharacteristics(pPager->fd)&SQLITE_IOCAP_BATCH_ATOMIC)
    ++  );
    +   if( isOpen(pPager->jfd) ){
    +     assert( !pagerUseWal(pPager) );
    + 
    +     /* Finalize the journal file. */
    +-    if( sqlite3IsMemJournal(pPager->jfd) ){
    +-      assert( pPager->journalMode==PAGER_JOURNALMODE_MEMORY );
    ++    if( sqlite3JournalIsInMemory(pPager->jfd) ){
    ++      /* assert( pPager->journalMode==PAGER_JOURNALMODE_MEMORY ); */
    +       sqlite3OsClose(pPager->jfd);
    +     }else if( pPager->journalMode==PAGER_JOURNALMODE_TRUNCATE ){
    +       if( pPager->journalOff==0 ){
    +@@ -44976,22 +50033,23 @@ static int pager_end_transaction(Pager *pPager, int hasMaster, int bCommit){
    +     }else if( pPager->journalMode==PAGER_JOURNALMODE_PERSIST
    +       || (pPager->exclusiveMode && pPager->journalMode!=PAGER_JOURNALMODE_WAL)
    +     ){
    +-      rc = zeroJournalHdr(pPager, hasMaster);
    ++      rc = zeroJournalHdr(pPager, hasMaster||pPager->tempFile);
    +       pPager->journalOff = 0;
    +     }else{
    +       /* This branch may be executed with Pager.journalMode==MEMORY if
    +       ** a hot-journal was just rolled back. In this case the journal
    +       ** file should be closed and deleted. If this connection writes to
    +-      ** the database file, it will do so using an in-memory journal. 
    ++      ** the database file, it will do so using an in-memory journal.
    +       */
    +-      int bDelete = (!pPager->tempFile && sqlite3JournalExists(pPager->jfd));
    ++      int bDelete = !pPager->tempFile;
    ++      assert( sqlite3JournalIsInMemory(pPager->jfd)==0 );
    +       assert( pPager->journalMode==PAGER_JOURNALMODE_DELETE 
    +            || pPager->journalMode==PAGER_JOURNALMODE_MEMORY 
    +            || pPager->journalMode==PAGER_JOURNALMODE_WAL 
    +       );
    +       sqlite3OsClose(pPager->jfd);
    +       if( bDelete ){
    +-        rc = sqlite3OsDelete(pPager->pVfs, pPager->zJournal, 0);
    ++        rc = sqlite3OsDelete(pPager->pVfs, pPager->zJournal, pPager->extraSync);
    +       }
    +     }
    +   }
    +@@ -45010,8 +50068,14 @@ static int pager_end_transaction(Pager *pPager, int hasMaster, int bCommit){
    +   sqlite3BitvecDestroy(pPager->pInJournal);
    +   pPager->pInJournal = 0;
    +   pPager->nRec = 0;
    +-  sqlite3PcacheCleanAll(pPager->pPCache);
    +-  sqlite3PcacheTruncate(pPager->pPCache, pPager->dbSize);
    ++  if( rc==SQLITE_OK ){
    ++    if( MEMDB || pagerFlushOnCommit(pPager, bCommit) ){
    ++      sqlite3PcacheCleanAll(pPager->pPCache);
    ++    }else{
    ++      sqlite3PcacheClearWritable(pPager->pPCache);
    ++    }
    ++    sqlite3PcacheTruncate(pPager->pPCache, pPager->dbSize);
    ++  }
    + 
    +   if( pagerUseWal(pPager) ){
    +     /* Drop the WAL write-lock, if any. Also, if the connection was in 
    +@@ -45189,6 +50253,11 @@ static int pager_playback_one_page(
    +   char *aData;                  /* Temporary storage for the page */
    +   sqlite3_file *jfd;            /* The file descriptor for the journal file */
    +   int isSynced;                 /* True if journal page is synced */
    ++#ifdef SQLITE_HAS_CODEC
    ++  /* The jrnlEnc flag is true if Journal pages should be passed through
    ++  ** the codec.  It is false for pure in-memory journals. */
    ++  const int jrnlEnc = (isMainJrnl || pPager->subjInMemory==0);
    ++#endif
    + 
    +   assert( (isMainJrnl&~1)==0 );      /* isMainJrnl is 0 or 1 */
    +   assert( (isSavepnt&~1)==0 );       /* isSavepnt is 0 or 1 */
    +@@ -45295,7 +50364,7 @@ static int pager_playback_one_page(
    +     pPg = sqlite3PagerLookup(pPager, pgno);
    +   }
    +   assert( pPg || !MEMDB );
    +-  assert( pPager->eState!=PAGER_OPEN || pPg==0 );
    ++  assert( pPager->eState!=PAGER_OPEN || pPg==0 || pPager->tempFile );
    +   PAGERTRACE(("PLAYBACK %d page %d hash(%08x) %s\n",
    +            PAGERID(pPager), pgno, pager_datahash(pPager->pageSize, (u8*)aData),
    +            (isMainJrnl?"main-journal":"sub-journal")
    +@@ -45312,14 +50381,34 @@ static int pager_playback_one_page(
    +     i64 ofst = (pgno-1)*(i64)pPager->pageSize;
    +     testcase( !isSavepnt && pPg!=0 && (pPg->flags&PGHDR_NEED_SYNC)!=0 );
    +     assert( !pagerUseWal(pPager) );
    ++
    ++    /* Write the data read from the journal back into the database file.
    ++    ** This is usually safe even for an encrypted database - as the data
    ++    ** was encrypted before it was written to the journal file. The exception
    ++    ** is if the data was just read from an in-memory sub-journal. In that
    ++    ** case it must be encrypted here before it is copied into the database
    ++    ** file.  */
    ++#ifdef SQLITE_HAS_CODEC
    ++    if( !jrnlEnc ){
    ++      CODEC2(pPager, aData, pgno, 7, rc=SQLITE_NOMEM_BKPT, aData);
    ++      rc = sqlite3OsWrite(pPager->fd, (u8 *)aData, pPager->pageSize, ofst);
    ++      CODEC1(pPager, aData, pgno, 3, rc=SQLITE_NOMEM_BKPT);
    ++    }else
    ++#endif
    +     rc = sqlite3OsWrite(pPager->fd, (u8 *)aData, pPager->pageSize, ofst);
    ++
    +     if( pgno>pPager->dbFileSize ){
    +       pPager->dbFileSize = pgno;
    +     }
    +     if( pPager->pBackup ){
    +-      CODEC1(pPager, aData, pgno, 3, rc=SQLITE_NOMEM);
    ++#ifdef SQLITE_HAS_CODEC
    ++      if( jrnlEnc ){
    ++        CODEC1(pPager, aData, pgno, 3, rc=SQLITE_NOMEM_BKPT);
    ++        sqlite3BackupUpdate(pPager->pBackup, pgno, (u8*)aData);
    ++        CODEC2(pPager, aData, pgno, 7, rc=SQLITE_NOMEM_BKPT,aData);
    ++      }else
    ++#endif
    +       sqlite3BackupUpdate(pPager->pBackup, pgno, (u8*)aData);
    +-      CODEC2(pPager, aData, pgno, 7, rc=SQLITE_NOMEM, aData);
    +     }
    +   }else if( !isMainJrnl && pPg==0 ){
    +     /* If this is a rollback of a savepoint and data was not written to
    +@@ -45341,11 +50430,10 @@ static int pager_playback_one_page(
    +     assert( isSavepnt );
    +     assert( (pPager->doNotSpill & SPILLFLAG_ROLLBACK)==0 );
    +     pPager->doNotSpill |= SPILLFLAG_ROLLBACK;
    +-    rc = sqlite3PagerAcquire(pPager, pgno, &pPg, 1);
    ++    rc = sqlite3PagerGet(pPager, pgno, &pPg, 1);
    +     assert( (pPager->doNotSpill & SPILLFLAG_ROLLBACK)!=0 );
    +     pPager->doNotSpill &= ~SPILLFLAG_ROLLBACK;
    +     if( rc!=SQLITE_OK ) return rc;
    +-    pPg->flags &= ~PGHDR_NEED_READ;
    +     sqlite3PcacheMakeDirty(pPg);
    +   }
    +   if( pPg ){
    +@@ -45359,29 +50447,10 @@ static int pager_playback_one_page(
    +     pData = pPg->pData;
    +     memcpy(pData, (u8*)aData, pPager->pageSize);
    +     pPager->xReiniter(pPg);
    +-    if( isMainJrnl && (!isSavepnt || *pOffset<=pPager->journalHdr) ){
    +-      /* If the contents of this page were just restored from the main 
    +-      ** journal file, then its content must be as they were when the 
    +-      ** transaction was first opened. In this case we can mark the page
    +-      ** as clean, since there will be no need to write it out to the
    +-      ** database.
    +-      **
    +-      ** There is one exception to this rule. If the page is being rolled
    +-      ** back as part of a savepoint (or statement) rollback from an 
    +-      ** unsynced portion of the main journal file, then it is not safe
    +-      ** to mark the page as clean. This is because marking the page as
    +-      ** clean will clear the PGHDR_NEED_SYNC flag. Since the page is
    +-      ** already in the journal file (recorded in Pager.pInJournal) and
    +-      ** the PGHDR_NEED_SYNC flag is cleared, if the page is written to
    +-      ** again within this transaction, it will be marked as dirty but
    +-      ** the PGHDR_NEED_SYNC flag will not be set. It could then potentially
    +-      ** be written out into the database file before its journal file
    +-      ** segment is synced. If a crash occurs during or following this,
    +-      ** database corruption may ensue.
    +-      */
    +-      assert( !pagerUseWal(pPager) );
    +-      sqlite3PcacheMakeClean(pPg);
    +-    }
    ++    /* It used to be that sqlite3PcacheMakeClean(pPg) was called here.  But
    ++    ** that call was dangerous and had no detectable benefit since the cache
    ++    ** is normally cleaned by sqlite3PcacheCleanAll() after rollback and so
    ++    ** has been removed. */
    +     pager_set_pagehash(pPg);
    + 
    +     /* If this was page 1, then restore the value of Pager.dbFileVers.
    +@@ -45391,7 +50460,9 @@ static int pager_playback_one_page(
    +     }
    + 
    +     /* Decode the page just read from disk */
    +-    CODEC1(pPager, pData, pPg->pgno, 3, rc=SQLITE_NOMEM);
    ++#if SQLITE_HAS_CODEC
    ++    if( jrnlEnc ){ CODEC1(pPager, pData, pPg->pgno, 3, rc=SQLITE_NOMEM_BKPT); }
    ++#endif
    +     sqlite3PcacheRelease(pPg);
    +   }
    +   return rc;
    +@@ -45457,7 +50528,7 @@ static int pager_delmaster(Pager *pPager, const char *zMaster){
    +   pMaster = (sqlite3_file *)sqlite3MallocZero(pVfs->szOsFile * 2);
    +   pJournal = (sqlite3_file *)(((u8 *)pMaster) + pVfs->szOsFile);
    +   if( !pMaster ){
    +-    rc = SQLITE_NOMEM;
    ++    rc = SQLITE_NOMEM_BKPT;
    +   }else{
    +     const int flags = (SQLITE_OPEN_READONLY|SQLITE_OPEN_MASTER_JOURNAL);
    +     rc = sqlite3OsOpen(pVfs, zMaster, pMaster, flags, 0);
    +@@ -45474,7 +50545,7 @@ static int pager_delmaster(Pager *pPager, const char *zMaster){
    +   nMasterPtr = pVfs->mxPathname+1;
    +   zMasterJournal = sqlite3Malloc(nMasterJournal + nMasterPtr + 1);
    +   if( !zMasterJournal ){
    +-    rc = SQLITE_NOMEM;
    ++    rc = SQLITE_NOMEM_BKPT;
    +     goto delmaster_out;
    +   }
    +   zMasterPtr = &zMasterJournal[nMasterJournal+1];
    +@@ -45704,6 +50775,7 @@ static int pager_playback(Pager *pPager, int isHot){
    +   char *zMaster = 0;       /* Name of master journal file if any */
    +   int needPagerReset;      /* True to reset page prior to first page rollback */
    +   int nPlayback = 0;       /* Total number of pages restored from journal */
    ++  u32 savedPageSize = pPager->pageSize;
    + 
    +   /* Figure out how many records are in the journal.  Abort early if
    +   ** the journal is empty.
    +@@ -45722,7 +50794,7 @@ static int pager_playback(Pager *pPager, int isHot){
    +   ** TODO: Technically the following is an error because it assumes that
    +   ** buffer Pager.pTmpSpace is (mxPathname+1) bytes or larger. i.e. that
    +   ** (pPager->pageSize >= pPager->pVfs->mxPathname+1). Using os_unix.c,
    +-  **  mxPathname is 512, which is the same as the minimum allowable value
    ++  ** mxPathname is 512, which is the same as the minimum allowable value
    +   ** for pageSize.
    +   */
    +   zMaster = pPager->pTmpSpace;
    +@@ -45833,6 +50905,9 @@ static int pager_playback(Pager *pPager, int isHot){
    +   assert( 0 );
    + 
    + end_playback:
    ++  if( rc==SQLITE_OK ){
    ++    rc = sqlite3PagerSetPagesize(pPager, &savedPageSize, -1);
    ++  }
    +   /* Following a rollback, the database file should be back in its original
    +   ** state prior to the start of the transaction, so invoke the
    +   ** SQLITE_FCNTL_DB_UNCHANGED file-control method to disable the
    +@@ -45891,7 +50966,8 @@ end_playback:
    + 
    + 
    + /*
    +-** Read the content for page pPg out of the database file and into 
    ++** Read the content for page pPg out of the database file (or out of
    ++** the WAL if that is where the most recent copy if found) into 
    + ** pPg->pData. A shared lock or greater must be held on the database
    + ** file before this function is called.
    + **
    +@@ -45901,30 +50977,33 @@ end_playback:
    + ** If an IO error occurs, then the IO error is returned to the caller.
    + ** Otherwise, SQLITE_OK is returned.
    + */
    +-static int readDbPage(PgHdr *pPg, u32 iFrame){
    ++static int readDbPage(PgHdr *pPg){
    +   Pager *pPager = pPg->pPager; /* Pager object associated with page pPg */
    +-  Pgno pgno = pPg->pgno;       /* Page number to read */
    +   int rc = SQLITE_OK;          /* Return code */
    +-  int pgsz = pPager->pageSize; /* Number of bytes to read */
    ++
    ++#ifndef SQLITE_OMIT_WAL
    ++  u32 iFrame = 0;              /* Frame of WAL containing pgno */
    + 
    +   assert( pPager->eState>=PAGER_READER && !MEMDB );
    +   assert( isOpen(pPager->fd) );
    + 
    +-#ifndef SQLITE_OMIT_WAL
    ++  if( pagerUseWal(pPager) ){
    ++    rc = sqlite3WalFindFrame(pPager->pWal, pPg->pgno, &iFrame);
    ++    if( rc ) return rc;
    ++  }
    +   if( iFrame ){
    +-    /* Try to pull the page from the write-ahead log. */
    +-    rc = sqlite3WalReadFrame(pPager->pWal, iFrame, pgsz, pPg->pData);
    ++    rc = sqlite3WalReadFrame(pPager->pWal, iFrame,pPager->pageSize,pPg->pData);
    +   }else
    + #endif
    +   {
    +-    i64 iOffset = (pgno-1)*(i64)pPager->pageSize;
    +-    rc = sqlite3OsRead(pPager->fd, pPg->pData, pgsz, iOffset);
    ++    i64 iOffset = (pPg->pgno-1)*(i64)pPager->pageSize;
    ++    rc = sqlite3OsRead(pPager->fd, pPg->pData, pPager->pageSize, iOffset);
    +     if( rc==SQLITE_IOERR_SHORT_READ ){
    +       rc = SQLITE_OK;
    +     }
    +   }
    + 
    +-  if( pgno==1 ){
    ++  if( pPg->pgno==1 ){
    +     if( rc ){
    +       /* If the read is unsuccessful, set the dbFileVers[] to something
    +       ** that will never be a valid file version.  dbFileVers[] is a copy
    +@@ -45944,13 +51023,13 @@ static int readDbPage(PgHdr *pPg, u32 iFrame){
    +       memcpy(&pPager->dbFileVers, dbFileVers, sizeof(pPager->dbFileVers));
    +     }
    +   }
    +-  CODEC1(pPager, pPg->pData, pgno, 3, rc = SQLITE_NOMEM);
    ++  CODEC1(pPager, pPg->pData, pPg->pgno, 3, rc = SQLITE_NOMEM_BKPT);
    + 
    +   PAGER_INCR(sqlite3_pager_readdb_count);
    +   PAGER_INCR(pPager->nRead);
    +-  IOTRACE(("PGIN %p %d\n", pPager, pgno));
    ++  IOTRACE(("PGIN %p %d\n", pPager, pPg->pgno));
    +   PAGERTRACE(("FETCH %d page %d hash(%08x)\n",
    +-               PAGERID(pPager), pgno, pager_pagehash(pPg)));
    ++               PAGERID(pPager), pPg->pgno, pager_pagehash(pPg)));
    + 
    +   return rc;
    + }
    +@@ -46001,11 +51080,7 @@ static int pagerUndoCallback(void *pCtx, Pgno iPg){
    +     if( sqlite3PcachePageRefcount(pPg)==1 ){
    +       sqlite3PcacheDrop(pPg);
    +     }else{
    +-      u32 iFrame = 0;
    +-      rc = sqlite3WalFindFrame(pPager->pWal, pPg->pgno, &iFrame);
    +-      if( rc==SQLITE_OK ){
    +-        rc = readDbPage(pPg, iFrame);
    +-      }
    ++      rc = readDbPage(pPg);
    +       if( rc==SQLITE_OK ){
    +         pPager->xReiniter(pPg);
    +       }
    +@@ -46172,21 +51247,20 @@ static int pagerPagecount(Pager *pPager, Pgno *pnPage){
    +   */
    +   assert( pPager->eState==PAGER_OPEN );
    +   assert( pPager->eLock>=SHARED_LOCK );
    ++  assert( isOpen(pPager->fd) );
    ++  assert( pPager->tempFile==0 );
    +   nPage = sqlite3WalDbsize(pPager->pWal);
    + 
    +   /* If the number of pages in the database is not available from the
    +-  ** WAL sub-system, determine the page counte based on the size of
    ++  ** WAL sub-system, determine the page count based on the size of
    +   ** the database file.  If the size of the database file is not an
    +   ** integer multiple of the page-size, round up the result.
    +   */
    +-  if( nPage==0 ){
    ++  if( nPage==0 && ALWAYS(isOpen(pPager->fd)) ){
    +     i64 n = 0;                    /* Size of db file in bytes */
    +-    assert( isOpen(pPager->fd) || pPager->tempFile );
    +-    if( isOpen(pPager->fd) ){
    +-      int rc = sqlite3OsFileSize(pPager->fd, &n);
    +-      if( rc!=SQLITE_OK ){
    +-        return rc;
    +-      }
    ++    int rc = sqlite3OsFileSize(pPager->fd, &n);
    ++    if( rc!=SQLITE_OK ){
    ++      return rc;
    +     }
    +     nPage = (Pgno)((n+pPager->pageSize-1) / pPager->pageSize);
    +   }
    +@@ -46229,23 +51303,21 @@ static int pagerOpenWalIfPresent(Pager *pPager){
    + 
    +   if( !pPager->tempFile ){
    +     int isWal;                    /* True if WAL file exists */
    +-    Pgno nPage;                   /* Size of the database file */
    +-
    +-    rc = pagerPagecount(pPager, &nPage);
    +-    if( rc ) return rc;
    +-    if( nPage==0 ){
    +-      rc = sqlite3OsDelete(pPager->pVfs, pPager->zWal, 0);
    +-      if( rc==SQLITE_IOERR_DELETE_NOENT ) rc = SQLITE_OK;
    +-      isWal = 0;
    +-    }else{
    +-      rc = sqlite3OsAccess(
    +-          pPager->pVfs, pPager->zWal, SQLITE_ACCESS_EXISTS, &isWal
    +-      );
    +-    }
    ++    rc = sqlite3OsAccess(
    ++        pPager->pVfs, pPager->zWal, SQLITE_ACCESS_EXISTS, &isWal
    ++    );
    +     if( rc==SQLITE_OK ){
    +       if( isWal ){
    +-        testcase( sqlite3PcachePagecount(pPager->pPCache)==0 );
    +-        rc = sqlite3PagerOpenWal(pPager, 0);
    ++        Pgno nPage;                   /* Size of the database file */
    ++
    ++        rc = pagerPagecount(pPager, &nPage);
    ++        if( rc ) return rc;
    ++        if( nPage==0 ){
    ++          rc = sqlite3OsDelete(pPager->pVfs, pPager->zWal, 0);
    ++        }else{
    ++          testcase( sqlite3PcachePagecount(pPager->pPCache)==0 );
    ++          rc = sqlite3PagerOpenWal(pPager, 0);
    ++        }
    +       }else if( pPager->journalMode==PAGER_JOURNALMODE_WAL ){
    +         pPager->journalMode = PAGER_JOURNALMODE_DELETE;
    +       }
    +@@ -46304,7 +51376,7 @@ static int pagerPlaybackSavepoint(Pager *pPager, PagerSavepoint *pSavepoint){
    +   if( pSavepoint ){
    +     pDone = sqlite3BitvecCreate(pSavepoint->nOrig);
    +     if( !pDone ){
    +-      return SQLITE_NOMEM;
    ++      return SQLITE_NOMEM_BKPT;
    +     }
    +   }
    + 
    +@@ -46400,12 +51472,21 @@ static int pagerPlaybackSavepoint(Pager *pPager, PagerSavepoint *pSavepoint){
    + }
    + 
    + /*
    +-** Change the maximum number of in-memory pages that are allowed.
    ++** Change the maximum number of in-memory pages that are allowed
    ++** before attempting to recycle clean and unused pages.
    + */
    + SQLITE_PRIVATE void sqlite3PagerSetCachesize(Pager *pPager, int mxPage){
    +   sqlite3PcacheSetCachesize(pPager->pPCache, mxPage);
    + }
    + 
    ++/*
    ++** Change the maximum number of in-memory pages that are allowed
    ++** before attempting to spill pages to journal.
    ++*/
    ++SQLITE_PRIVATE int sqlite3PagerSetSpillsize(Pager *pPager, int mxPage){
    ++  return sqlite3PcacheSetSpillsize(pPager->pPCache, mxPage);
    ++}
    ++
    + /*
    + ** Invoke SQLITE_FCNTL_MMAP_SIZE based on the current value of szMmap.
    + */
    +@@ -46416,6 +51497,7 @@ static void pagerFixMaplimit(Pager *pPager){
    +     sqlite3_int64 sz;
    +     sz = pPager->szMmap;
    +     pPager->bUseFetch = (sz>0);
    ++    setGetterMethod(pPager);
    +     sqlite3OsFileControlHint(pPager->fd, SQLITE_FCNTL_MMAP_SIZE, &sz);
    +   }
    + #endif
    +@@ -46442,7 +51524,7 @@ SQLITE_PRIVATE void sqlite3PagerShrink(Pager *pPager){
    + ** The "level" in pgFlags & PAGER_SYNCHRONOUS_MASK sets the robustness
    + ** of the database to damage due to OS crashes or power failures by
    + ** changing the number of syncs()s when writing the journals.
    +-** There are three levels:
    ++** There are four levels:
    + **
    + **    OFF       sqlite3OsSync() is never called.  This is the default
    + **              for temporary and transient files.
    +@@ -46462,6 +51544,10 @@ SQLITE_PRIVATE void sqlite3PagerShrink(Pager *pPager){
    + **              assurance that the journal will not be corrupted to the
    + **              point of causing damage to the database during rollback.
    + **
    ++**    EXTRA     This is like FULL except that is also syncs the directory
    ++**              that contains the rollback journal after the rollback
    ++**              journal is unlinked.
    ++**
    + ** The above is for a rollback-journal mode.  For WAL mode, OFF continues
    + ** to mean that no syncs ever occur.  NORMAL means that the WAL is synced
    + ** prior to the start of checkpoint and that the database file is synced
    +@@ -46469,7 +51555,8 @@ SQLITE_PRIVATE void sqlite3PagerShrink(Pager *pPager){
    + ** was written back into the database.  But no sync operations occur for
    + ** an ordinary commit in NORMAL mode with WAL.  FULL means that the WAL
    + ** file is synced following each commit operation, in addition to the
    +-** syncs associated with NORMAL.
    ++** syncs associated with NORMAL.  There is no difference between FULL
    ++** and EXTRA for WAL mode.
    + **
    + ** Do not confuse synchronous=FULL with SQLITE_SYNC_FULL.  The
    + ** SQLITE_SYNC_FULL macro means to use the MacOSX-style full-fsync
    +@@ -46488,25 +51575,28 @@ SQLITE_PRIVATE void sqlite3PagerSetFlags(
    +   unsigned pgFlags      /* Various flags */
    + ){
    +   unsigned level = pgFlags & PAGER_SYNCHRONOUS_MASK;
    +-  assert( level>=1 && level<=3 );
    +-  pPager->noSync =  (level==1 || pPager->tempFile) ?1:0;
    +-  pPager->fullSync = (level==3 && !pPager->tempFile) ?1:0;
    ++  if( pPager->tempFile ){
    ++    pPager->noSync = 1;
    ++    pPager->fullSync = 0;
    ++    pPager->extraSync = 0;
    ++  }else{
    ++    pPager->noSync =  level==PAGER_SYNCHRONOUS_OFF ?1:0;
    ++    pPager->fullSync = level>=PAGER_SYNCHRONOUS_FULL ?1:0;
    ++    pPager->extraSync = level==PAGER_SYNCHRONOUS_EXTRA ?1:0;
    ++  }
    +   if( pPager->noSync ){
    +     pPager->syncFlags = 0;
    +-    pPager->ckptSyncFlags = 0;
    +   }else if( pgFlags & PAGER_FULLFSYNC ){
    +     pPager->syncFlags = SQLITE_SYNC_FULL;
    +-    pPager->ckptSyncFlags = SQLITE_SYNC_FULL;
    +-  }else if( pgFlags & PAGER_CKPT_FULLFSYNC ){
    +-    pPager->syncFlags = SQLITE_SYNC_NORMAL;
    +-    pPager->ckptSyncFlags = SQLITE_SYNC_FULL;
    +   }else{
    +     pPager->syncFlags = SQLITE_SYNC_NORMAL;
    +-    pPager->ckptSyncFlags = SQLITE_SYNC_NORMAL;
    +   }
    +-  pPager->walSyncFlags = pPager->syncFlags;
    ++  pPager->walSyncFlags = (pPager->syncFlags<<2);
    +   if( pPager->fullSync ){
    +-    pPager->walSyncFlags |= WAL_SYNC_TRANSACTIONS;
    ++    pPager->walSyncFlags |= pPager->syncFlags;
    ++  }
    ++  if( (pgFlags & PAGER_CKPT_FULLFSYNC) && !pPager->noSync ){
    ++    pPager->walSyncFlags |= (SQLITE_SYNC_FULL<<2);
    +   }
    +   if( pgFlags & PAGER_CACHESPILL ){
    +     pPager->doNotSpill &= ~SPILLFLAG_OFF;
    +@@ -46652,7 +51742,7 @@ SQLITE_PRIVATE int sqlite3PagerSetPagesize(Pager *pPager, u32 *pPageSize, int nR
    +     }
    +     if( rc==SQLITE_OK ){
    +       pNew = (char *)sqlite3PageMalloc(pageSize);
    +-      if( !pNew ) rc = SQLITE_NOMEM;
    ++      if( !pNew ) rc = SQLITE_NOMEM_BKPT;
    +     }
    + 
    +     if( rc==SQLITE_OK ){
    +@@ -46901,6 +51991,7 @@ static int pagerSyncHotJournal(Pager *pPager){
    +   return rc;
    + }
    + 
    ++#if SQLITE_MAX_MMAP_SIZE>0
    + /*
    + ** Obtain a reference to a memory mapped page object for page number pgno. 
    + ** The new object will use the pointer pData, obtained from xFetch().
    +@@ -46923,12 +52014,13 @@ static int pagerAcquireMapPage(
    +     *ppPage = p = pPager->pMmapFreelist;
    +     pPager->pMmapFreelist = p->pDirty;
    +     p->pDirty = 0;
    +-    memset(p->pExtra, 0, pPager->nExtra);
    ++    assert( pPager->nExtra>=8 );
    ++    memset(p->pExtra, 0, 8);
    +   }else{
    +     *ppPage = p = (PgHdr *)sqlite3MallocZero(sizeof(PgHdr) + pPager->nExtra);
    +     if( p==0 ){
    +       sqlite3OsUnfetch(pPager->fd, (i64)(pgno-1) * pPager->pageSize, pData);
    +-      return SQLITE_NOMEM;
    ++      return SQLITE_NOMEM_BKPT;
    +     }
    +     p->pExtra = (void *)&p[1];
    +     p->flags = PGHDR_MMAP;
    +@@ -46948,6 +52040,7 @@ static int pagerAcquireMapPage(
    + 
    +   return SQLITE_OK;
    + }
    ++#endif
    + 
    + /*
    + ** Release a reference to page pPg. pPg must have been returned by an 
    +@@ -46990,9 +52083,10 @@ static void pagerFreeMapHdrs(Pager *pPager){
    + ** a hot journal may be left in the filesystem but no error is returned
    + ** to the caller.
    + */
    +-SQLITE_PRIVATE int sqlite3PagerClose(Pager *pPager){
    ++SQLITE_PRIVATE int sqlite3PagerClose(Pager *pPager, sqlite3 *db){
    +   u8 *pTmp = (u8 *)pPager->pTmpSpace;
    + 
    ++  assert( db || pagerUseWal(pPager)==0 );
    +   assert( assert_pager_state(pPager) );
    +   disable_simulated_io_errors();
    +   sqlite3BeginBenignMalloc();
    +@@ -47000,7 +52094,10 @@ SQLITE_PRIVATE int sqlite3PagerClose(Pager *pPager){
    +   /* pPager->errCode = 0; */
    +   pPager->exclusiveMode = 0;
    + #ifndef SQLITE_OMIT_WAL
    +-  sqlite3WalClose(pPager->pWal, pPager->ckptSyncFlags, pPager->pageSize, pTmp);
    ++  assert( db || pPager->pWal==0 );
    ++  sqlite3WalClose(pPager->pWal, db, pPager->walSyncFlags, pPager->pageSize,
    ++      (db && (db->flags & SQLITE_NoCkptOnClose) ? 0 : pTmp)
    ++  );
    +   pPager->pWal = 0;
    + #endif
    +   pager_reset(pPager);
    +@@ -47242,8 +52339,9 @@ static int pager_write_pagelist(Pager *pPager, PgHdr *pList){
    + 
    +   /* This function is only called for rollback pagers in WRITER_DBMOD state. */
    +   assert( !pagerUseWal(pPager) );
    +-  assert( pPager->eState==PAGER_WRITER_DBMOD );
    ++  assert( pPager->tempFile || pPager->eState==PAGER_WRITER_DBMOD );
    +   assert( pPager->eLock==EXCLUSIVE_LOCK );
    ++  assert( isOpen(pPager->fd) || pList->pDirty==0 );
    + 
    +   /* If the file is a temp-file has not yet been opened, open it now. It
    +   ** is not possible for rc to be other than SQLITE_OK if this branch
    +@@ -47286,7 +52384,7 @@ static int pager_write_pagelist(Pager *pPager, PgHdr *pList){
    +       if( pList->pgno==1 ) pager_write_changecounter(pList);
    + 
    +       /* Encode the database */
    +-      CODEC2(pPager, pList->pData, pgno, 6, return SQLITE_NOMEM, pData);
    ++      CODEC2(pPager, pList->pData, pgno, 6, return SQLITE_NOMEM_BKPT, pData);
    + 
    +       /* Write out the page data. */
    +       rc = sqlite3OsWrite(pPager->fd, pData, pPager->pageSize, offset);
    +@@ -47331,11 +52429,14 @@ static int pager_write_pagelist(Pager *pPager, PgHdr *pList){
    + static int openSubJournal(Pager *pPager){
    +   int rc = SQLITE_OK;
    +   if( !isOpen(pPager->sjfd) ){
    ++    const int flags =  SQLITE_OPEN_SUBJOURNAL | SQLITE_OPEN_READWRITE 
    ++      | SQLITE_OPEN_CREATE | SQLITE_OPEN_EXCLUSIVE 
    ++      | SQLITE_OPEN_DELETEONCLOSE;
    ++    int nStmtSpill = sqlite3Config.nStmtSpill;
    +     if( pPager->journalMode==PAGER_JOURNALMODE_MEMORY || pPager->subjInMemory ){
    +-      sqlite3MemJournalOpen(pPager->sjfd);
    +-    }else{
    +-      rc = pagerOpentemp(pPager, pPager->sjfd, SQLITE_OPEN_SUBJOURNAL);
    ++      nStmtSpill = -1;
    +     }
    ++    rc = sqlite3JournalOpen(pPager->pVfs, 0, pPager->sjfd, flags, nStmtSpill);
    +   }
    +   return rc;
    + }
    +@@ -47372,8 +52473,13 @@ static int subjournalPage(PgHdr *pPg){
    +       void *pData = pPg->pData;
    +       i64 offset = (i64)pPager->nSubRec*(4+pPager->pageSize);
    +       char *pData2;
    +-  
    +-      CODEC2(pPager, pData, pPg->pgno, 7, return SQLITE_NOMEM, pData2);
    ++
    ++#if SQLITE_HAS_CODEC   
    ++      if( !pPager->subjInMemory ){
    ++        CODEC2(pPager, pData, pPg->pgno, 7, return SQLITE_NOMEM_BKPT, pData2);
    ++      }else
    ++#endif
    ++      pData2 = pData;
    +       PAGERTRACE(("STMT-JOURNAL %d page %d\n", PAGERID(pPager), pPg->pgno));
    +       rc = write32bits(pPager->sjfd, offset, pPg->pgno);
    +       if( rc==SQLITE_OK ){
    +@@ -47457,6 +52563,13 @@ static int pagerStress(void *p, PgHdr *pPg){
    +       rc = pagerWalFrames(pPager, pPg, 0, 0);
    +     }
    +   }else{
    ++    
    ++#ifdef SQLITE_ENABLE_BATCH_ATOMIC_WRITE
    ++    if( pPager->tempFile==0 ){
    ++      rc = sqlite3JournalCreate(pPager->jfd);
    ++      if( rc!=SQLITE_OK ) return pager_error(pPager, rc);
    ++    }
    ++#endif
    +   
    +     /* Sync the journal file if required. */
    +     if( pPg->flags&PGHDR_NEED_SYNC 
    +@@ -47481,6 +52594,25 @@ static int pagerStress(void *p, PgHdr *pPg){
    +   return pager_error(pPager, rc); 
    + }
    + 
    ++/*
    ++** Flush all unreferenced dirty pages to disk.
    ++*/
    ++SQLITE_PRIVATE int sqlite3PagerFlush(Pager *pPager){
    ++  int rc = pPager->errCode;
    ++  if( !MEMDB ){
    ++    PgHdr *pList = sqlite3PcacheDirtyList(pPager->pPCache);
    ++    assert( assert_pager_state(pPager) );
    ++    while( rc==SQLITE_OK && pList ){
    ++      PgHdr *pNext = pList->pDirty;
    ++      if( pList->nRef==0 ){
    ++        rc = pagerStress((void*)pPager, pList);
    ++      }
    ++      pList = pNext;
    ++    }
    ++  }
    ++
    ++  return rc;
    ++}
    + 
    + /*
    + ** Allocate and initialize a new Pager object and put a pointer to it
    +@@ -47496,7 +52628,9 @@ static int pagerStress(void *p, PgHdr *pPg){
    + **
    + ** The nExtra parameter specifies the number of bytes of space allocated
    + ** along with each page reference. This space is available to the user
    +-** via the sqlite3PagerGetExtra() API.
    ++** via the sqlite3PagerGetExtra() API.  When a new page is allocated, the
    ++** first 8 bytes of this space are zeroed but the remainder is uninitialized.
    ++** (The extra space is used by btree as the MemPage object.)
    + **
    + ** The flags argument is used to specify properties that affect the
    + ** operation of the pager. It should be passed some bitwise combination
    +@@ -47537,18 +52671,8 @@ SQLITE_PRIVATE int sqlite3PagerOpen(
    +   int nUri = 0;            /* Number of bytes of URI args at *zUri */
    + 
    +   /* Figure out how much space is required for each journal file-handle
    +-  ** (there are two of them, the main journal and the sub-journal). This
    +-  ** is the maximum space required for an in-memory journal file handle 
    +-  ** and a regular journal file-handle. Note that a "regular journal-handle"
    +-  ** may be a wrapper capable of caching the first portion of the journal
    +-  ** file in memory to implement the atomic-write optimization (see 
    +-  ** source file journal.c).
    +-  */
    +-  if( sqlite3JournalSize(pVfs)>sqlite3MemJournalSize() ){
    +-    journalFileSize = ROUND8(sqlite3JournalSize(pVfs));
    +-  }else{
    +-    journalFileSize = ROUND8(sqlite3MemJournalSize());
    +-  }
    ++  ** (there are two of them, the main journal and the sub-journal).  */
    ++  journalFileSize = ROUND8(sqlite3JournalSize(pVfs));
    + 
    +   /* Set the output variable to NULL in case an error occurs. */
    +   *ppPager = 0;
    +@@ -47558,7 +52682,7 @@ SQLITE_PRIVATE int sqlite3PagerOpen(
    +     memDb = 1;
    +     if( zFilename && zFilename[0] ){
    +       zPathname = sqlite3DbStrDup(0, zFilename);
    +-      if( zPathname==0  ) return SQLITE_NOMEM;
    ++      if( zPathname==0  ) return SQLITE_NOMEM_BKPT;
    +       nPathname = sqlite3Strlen30(zPathname);
    +       zFilename = 0;
    +     }
    +@@ -47574,7 +52698,7 @@ SQLITE_PRIVATE int sqlite3PagerOpen(
    +     nPathname = pVfs->mxPathname+1;
    +     zPathname = sqlite3DbMallocRaw(0, nPathname*2);
    +     if( zPathname==0 ){
    +-      return SQLITE_NOMEM;
    ++      return SQLITE_NOMEM_BKPT;
    +     }
    +     zPathname[0] = 0; /* Make sure initialized even if FullPathname() fails */
    +     rc = sqlite3OsFullPathname(pVfs, zFilename, nPathname, zPathname);
    +@@ -47627,7 +52751,7 @@ SQLITE_PRIVATE int sqlite3PagerOpen(
    +   assert( EIGHT_BYTE_ALIGNMENT(SQLITE_INT_TO_PTR(journalFileSize)) );
    +   if( !pPtr ){
    +     sqlite3DbFree(0, zPathname);
    +-    return SQLITE_NOMEM;
    ++    return SQLITE_NOMEM_BKPT;
    +   }
    +   pPager =              (Pager*)(pPtr);
    +   pPager->pPCache =    (PCache*)(pPtr += ROUND8(sizeof(*pPager)));
    +@@ -47736,8 +52860,8 @@ act_like_temp_file:
    + 
    +   /* Initialize the PCache object. */
    +   if( rc==SQLITE_OK ){
    +-    assert( nExtra<1000 );
    +     nExtra = ROUND8(nExtra);
    ++    assert( nExtra>=8 && nExtra<1000 );
    +     rc = sqlite3PcacheOpen(szPageDflt, nExtra, !memDb,
    +                        !memDb?pagerStress:0, (void *)pPager, pPager->pPCache);
    +   }
    +@@ -47776,14 +52900,14 @@ act_like_temp_file:
    +   pPager->noSync = pPager->tempFile;
    +   if( pPager->noSync ){
    +     assert( pPager->fullSync==0 );
    ++    assert( pPager->extraSync==0 );
    +     assert( pPager->syncFlags==0 );
    +     assert( pPager->walSyncFlags==0 );
    +-    assert( pPager->ckptSyncFlags==0 );
    +   }else{
    +     pPager->fullSync = 1;
    ++    pPager->extraSync = 0;
    +     pPager->syncFlags = SQLITE_SYNC_NORMAL;
    +-    pPager->walSyncFlags = SQLITE_SYNC_NORMAL | WAL_SYNC_TRANSACTIONS;
    +-    pPager->ckptSyncFlags = SQLITE_SYNC_NORMAL;
    ++    pPager->walSyncFlags = SQLITE_SYNC_NORMAL | (SQLITE_SYNC_NORMAL<<2);
    +   }
    +   /* pPager->pFirst = 0; */
    +   /* pPager->pFirstSynced = 0; */
    +@@ -47800,6 +52924,7 @@ act_like_temp_file:
    +   /* pPager->xBusyHandler = 0; */
    +   /* pPager->pBusyHandlerArg = 0; */
    +   pPager->xReiniter = xReinit;
    ++  setGetterMethod(pPager);
    +   /* memset(pPager->aHash, 0, sizeof(pPager->aHash)); */
    +   /* pPager->szMmap = SQLITE_DEFAULT_MMAP_SIZE // will be set by btree.c */
    + 
    +@@ -47897,6 +53022,7 @@ static int hasHotJournal(Pager *pPager, int *pExists){
    +     if( rc==SQLITE_OK && !locked ){
    +       Pgno nPage;                 /* Number of pages in database file */
    + 
    ++      assert( pPager->tempFile==0 );
    +       rc = pagerPagecount(pPager, &nPage);
    +       if( rc==SQLITE_OK ){
    +         /* If the database is zero pages in size, that means that either (1) the
    +@@ -47958,7 +53084,7 @@ static int hasHotJournal(Pager *pPager, int *pExists){
    + 
    + /*
    + ** This function is called to obtain a shared lock on the database file.
    +-** It is illegal to call sqlite3PagerAcquire() until after this function
    ++** It is illegal to call sqlite3PagerGet() until after this function
    + ** has been successfully called. If a shared-lock is already held when
    + ** this function is called, it is a no-op.
    + **
    +@@ -47989,17 +53115,17 @@ SQLITE_PRIVATE int sqlite3PagerSharedLock(Pager *pPager){
    +   /* This routine is only called from b-tree and only when there are no
    +   ** outstanding pages. This implies that the pager state should either
    +   ** be OPEN or READER. READER is only possible if the pager is or was in 
    +-  ** exclusive access mode.
    +-  */
    ++  ** exclusive access mode.  */
    +   assert( sqlite3PcacheRefCount(pPager->pPCache)==0 );
    +   assert( assert_pager_state(pPager) );
    +   assert( pPager->eState==PAGER_OPEN || pPager->eState==PAGER_READER );
    +-  if( NEVER(MEMDB && pPager->errCode) ){ return pPager->errCode; }
    ++  assert( pPager->errCode==SQLITE_OK );
    + 
    +   if( !pagerUseWal(pPager) && pPager->eState==PAGER_OPEN ){
    +     int bHotJournal = 1;          /* True if there exists a hot journal-file */
    + 
    +     assert( !MEMDB );
    ++    assert( pPager->tempFile==0 || pPager->eLock==EXCLUSIVE_LOCK );
    + 
    +     rc = pager_wait_on_lock(pPager, SHARED_LOCK);
    +     if( rc!=SQLITE_OK ){
    +@@ -48085,7 +53211,7 @@ SQLITE_PRIVATE int sqlite3PagerSharedLock(Pager *pPager){
    +         assert( rc==SQLITE_OK );
    +         rc = pagerSyncHotJournal(pPager);
    +         if( rc==SQLITE_OK ){
    +-          rc = pager_playback(pPager, 1);
    ++          rc = pager_playback(pPager, !pPager->tempFile);
    +           pPager->eState = PAGER_OPEN;
    +         }
    +       }else if( !pPager->exclusiveMode ){
    +@@ -48136,19 +53262,14 @@ SQLITE_PRIVATE int sqlite3PagerSharedLock(Pager *pPager){
    +       ** detected.  The chance of an undetected change is so small that
    +       ** it can be neglected.
    +       */
    +-      Pgno nPage = 0;
    +       char dbFileVers[sizeof(pPager->dbFileVers)];
    + 
    +-      rc = pagerPagecount(pPager, &nPage);
    +-      if( rc ) goto failed;
    +-
    +-      if( nPage>0 ){
    +-        IOTRACE(("CKVERS %p %d\n", pPager, sizeof(dbFileVers)));
    +-        rc = sqlite3OsRead(pPager->fd, &dbFileVers, sizeof(dbFileVers), 24);
    +-        if( rc!=SQLITE_OK && rc!=SQLITE_IOERR_SHORT_READ ){
    ++      IOTRACE(("CKVERS %p %d\n", pPager, sizeof(dbFileVers)));
    ++      rc = sqlite3OsRead(pPager->fd, &dbFileVers, sizeof(dbFileVers), 24);
    ++      if( rc!=SQLITE_OK ){
    ++        if( rc!=SQLITE_IOERR_SHORT_READ ){
    +           goto failed;
    +         }
    +-      }else{
    +         memset(dbFileVers, 0, sizeof(dbFileVers));
    +       }
    + 
    +@@ -48181,7 +53302,7 @@ SQLITE_PRIVATE int sqlite3PagerSharedLock(Pager *pPager){
    +     rc = pagerBeginReadTransaction(pPager);
    +   }
    + 
    +-  if( pPager->eState==PAGER_OPEN && rc==SQLITE_OK ){
    ++  if( pPager->tempFile==0 && pPager->eState==PAGER_OPEN && rc==SQLITE_OK ){
    +     rc = pagerPagecount(pPager, &pPager->dbSize);
    +   }
    + 
    +@@ -48206,16 +53327,24 @@ SQLITE_PRIVATE int sqlite3PagerSharedLock(Pager *pPager){
    + ** nothing to rollback, so this routine is a no-op.
    + */ 
    + static void pagerUnlockIfUnused(Pager *pPager){
    +-  if( pPager->nMmapOut==0 && (sqlite3PcacheRefCount(pPager->pPCache)==0) ){
    ++  if( sqlite3PcacheRefCount(pPager->pPCache)==0 ){
    ++    assert( pPager->nMmapOut==0 ); /* because page1 is never memory mapped */
    +     pagerUnlockAndRollback(pPager);
    +   }
    + }
    + 
    + /*
    +-** Acquire a reference to page number pgno in pager pPager (a page
    +-** reference has type DbPage*). If the requested reference is 
    ++** The page getter methods each try to acquire a reference to a
    ++** page with page number pgno. If the requested reference is 
    + ** successfully obtained, it is copied to *ppPage and SQLITE_OK returned.
    + **
    ++** There are different implementations of the getter method depending
    ++** on the current state of the pager.
    ++**
    ++**     getPageNormal()         --  The normal getter
    ++**     getPageError()          --  Used if the pager is in an error state
    ++**     getPageMmap()           --  Used if memory-mapped I/O is enabled
    ++**
    + ** If the requested page is already in the cache, it is returned. 
    + ** Otherwise, a new page object is allocated and populated with data
    + ** read from the database file. In some cases, the pcache module may
    +@@ -48227,14 +53356,14 @@ static void pagerUnlockIfUnused(Pager *pPager){
    + ** already in the cache when this function is called, then the extra
    + ** data is left as it was when the page object was last used.
    + **
    +-** If the database image is smaller than the requested page or if a 
    +-** non-zero value is passed as the noContent parameter and the 
    ++** If the database image is smaller than the requested page or if 
    ++** the flags parameter contains the PAGER_GET_NOCONTENT bit and the 
    + ** requested page is not already stored in the cache, then no 
    + ** actual disk read occurs. In this case the memory image of the 
    + ** page is initialized to all zeros. 
    + **
    +-** If noContent is true, it means that we do not care about the contents
    +-** of the page. This occurs in two scenarios:
    ++** If PAGER_GET_NOCONTENT is true, it means that we do not care about
    ++** the contents of the page. This occurs in two scenarios:
    + **
    + **   a) When reading a free-list leaf page from the database, and
    + **
    +@@ -48242,8 +53371,8 @@ static void pagerUnlockIfUnused(Pager *pPager){
    + **      a new page into the cache to be filled with the data read
    + **      from the savepoint journal.
    + **
    +-** If noContent is true, then the data returned is zeroed instead of
    +-** being read from the database. Additionally, the bits corresponding
    ++** If PAGER_GET_NOCONTENT is true, then the data returned is zeroed instead
    ++** of being read from the database. Additionally, the bits corresponding
    + ** to pgno in Pager.pInJournal (bitvec of pages already written to the
    + ** journal file) and the PagerSavepoint.pInSavepoint bitvecs of any open
    + ** savepoints are set. This means if the page is made writable at any
    +@@ -48261,106 +53390,39 @@ static void pagerUnlockIfUnused(Pager *pPager){
    + ** Since Lookup() never goes to disk, it never has to deal with locks
    + ** or journal files.
    + */
    +-SQLITE_PRIVATE int sqlite3PagerAcquire(
    ++static int getPageNormal(
    +   Pager *pPager,      /* The pager open on the database file */
    +   Pgno pgno,          /* Page number to fetch */
    +   DbPage **ppPage,    /* Write a pointer to the page here */
    +   int flags           /* PAGER_GET_XXX flags */
    + ){
    +   int rc = SQLITE_OK;
    +-  PgHdr *pPg = 0;
    +-  u32 iFrame = 0;                 /* Frame to read from WAL file */
    +-  const int noContent = (flags & PAGER_GET_NOCONTENT);
    +-
    +-  /* It is acceptable to use a read-only (mmap) page for any page except
    +-  ** page 1 if there is no write-transaction open or the ACQUIRE_READONLY
    +-  ** flag was specified by the caller. And so long as the db is not a 
    +-  ** temporary or in-memory database.  */
    +-  const int bMmapOk = (pgno>1 && USEFETCH(pPager)
    +-   && (pPager->eState==PAGER_READER || (flags & PAGER_GET_READONLY))
    +-#ifdef SQLITE_HAS_CODEC
    +-   && pPager->xCodec==0
    +-#endif
    +-  );
    ++  PgHdr *pPg;
    ++  u8 noContent;                   /* True if PAGER_GET_NOCONTENT is set */
    ++  sqlite3_pcache_page *pBase;
    + 
    +-  /* Optimization note:  Adding the "pgno<=1" term before "pgno==0" here
    +-  ** allows the compiler optimizer to reuse the results of the "pgno>1"
    +-  ** test in the previous statement, and avoid testing pgno==0 in the
    +-  ** common case where pgno is large. */
    +-  if( pgno<=1 && pgno==0 ){
    +-    return SQLITE_CORRUPT_BKPT;
    +-  }
    ++  assert( pPager->errCode==SQLITE_OK );
    +   assert( pPager->eState>=PAGER_READER );
    +   assert( assert_pager_state(pPager) );
    +-  assert( noContent==0 || bMmapOk==0 );
    +-
    +   assert( pPager->hasHeldSharedLock==1 );
    + 
    +-  /* If the pager is in the error state, return an error immediately. 
    +-  ** Otherwise, request the page from the PCache layer. */
    +-  if( pPager->errCode!=SQLITE_OK ){
    +-    rc = pPager->errCode;
    +-  }else{
    +-    if( bMmapOk && pagerUseWal(pPager) ){
    +-      rc = sqlite3WalFindFrame(pPager->pWal, pgno, &iFrame);
    +-      if( rc!=SQLITE_OK ) goto pager_acquire_err;
    +-    }
    +-
    +-    if( bMmapOk && iFrame==0 ){
    +-      void *pData = 0;
    +-
    +-      rc = sqlite3OsFetch(pPager->fd, 
    +-          (i64)(pgno-1) * pPager->pageSize, pPager->pageSize, &pData
    +-      );
    +-
    +-      if( rc==SQLITE_OK && pData ){
    +-        if( pPager->eState>PAGER_READER ){
    +-          pPg = sqlite3PagerLookup(pPager, pgno);
    +-        }
    +-        if( pPg==0 ){
    +-          rc = pagerAcquireMapPage(pPager, pgno, pData, &pPg);
    +-        }else{
    +-          sqlite3OsUnfetch(pPager->fd, (i64)(pgno-1)*pPager->pageSize, pData);
    +-        }
    +-        if( pPg ){
    +-          assert( rc==SQLITE_OK );
    +-          *ppPage = pPg;
    +-          return SQLITE_OK;
    +-        }
    +-      }
    +-      if( rc!=SQLITE_OK ){
    +-        goto pager_acquire_err;
    +-      }
    +-    }
    +-
    +-    {
    +-      sqlite3_pcache_page *pBase;
    +-      pBase = sqlite3PcacheFetch(pPager->pPCache, pgno, 3);
    +-      if( pBase==0 ){
    +-        rc = sqlite3PcacheFetchStress(pPager->pPCache, pgno, &pBase);
    +-        if( rc!=SQLITE_OK ) goto pager_acquire_err;
    +-        if( pBase==0 ){
    +-          pPg = *ppPage = 0;
    +-          rc = SQLITE_NOMEM;
    +-          goto pager_acquire_err;
    +-        }
    +-      }
    +-      pPg = *ppPage = sqlite3PcacheFetchFinish(pPager->pPCache, pgno, pBase);
    +-      assert( pPg!=0 );
    +-    }
    +-  }
    +-
    +-  if( rc!=SQLITE_OK ){
    +-    /* Either the call to sqlite3PcacheFetch() returned an error or the
    +-    ** pager was already in the error-state when this function was called.
    +-    ** Set pPg to 0 and jump to the exception handler.  */
    ++  if( pgno==0 ) return SQLITE_CORRUPT_BKPT;
    ++  pBase = sqlite3PcacheFetch(pPager->pPCache, pgno, 3);
    ++  if( pBase==0 ){
    +     pPg = 0;
    +-    goto pager_acquire_err;
    ++    rc = sqlite3PcacheFetchStress(pPager->pPCache, pgno, &pBase);
    ++    if( rc!=SQLITE_OK ) goto pager_acquire_err;
    ++    if( pBase==0 ){
    ++      rc = SQLITE_NOMEM_BKPT;
    ++      goto pager_acquire_err;
    ++    }
    +   }
    ++  pPg = *ppPage = sqlite3PcacheFetchFinish(pPager->pPCache, pgno, pBase);
    +   assert( pPg==(*ppPage) );
    +   assert( pPg->pgno==pgno );
    +   assert( pPg->pPager==pPager || pPg->pPager==0 );
    + 
    ++  noContent = (flags & PAGER_GET_NOCONTENT)!=0;
    +   if( pPg->pPager && !noContent ){
    +     /* In this case the pcache already contains an initialized copy of
    +     ** the page. Return without further ado.  */
    +@@ -48370,18 +53432,20 @@ SQLITE_PRIVATE int sqlite3PagerAcquire(
    + 
    +   }else{
    +     /* The pager cache has created a new page. Its content needs to 
    +-    ** be initialized.  */
    +-
    +-    pPg->pPager = pPager;
    +-
    +-    /* The maximum page number is 2^31. Return SQLITE_CORRUPT if a page
    +-    ** number greater than this, or the unused locking-page, is requested. */
    ++    ** be initialized. But first some error checks:
    ++    **
    ++    ** (1) The maximum page number is 2^31
    ++    ** (2) Never try to fetch the locking page
    ++    */
    +     if( pgno>PAGER_MAX_PGNO || pgno==PAGER_MJ_PGNO(pPager) ){
    +       rc = SQLITE_CORRUPT_BKPT;
    +       goto pager_acquire_err;
    +     }
    + 
    +-    if( MEMDB || pPager->dbSize<pgno || noContent || !isOpen(pPager->fd) ){
    ++    pPg->pPager = pPager;
    ++
    ++    assert( !isOpen(pPager->fd) || !MEMDB );
    ++    if( !isOpen(pPager->fd) || pPager->dbSize<pgno || noContent ){
    +       if( pgno>pPager->mxPgno ){
    +         rc = SQLITE_FULL;
    +         goto pager_acquire_err;
    +@@ -48405,20 +53469,15 @@ SQLITE_PRIVATE int sqlite3PagerAcquire(
    +       memset(pPg->pData, 0, pPager->pageSize);
    +       IOTRACE(("ZERO %p %d\n", pPager, pgno));
    +     }else{
    +-      if( pagerUseWal(pPager) && bMmapOk==0 ){
    +-        rc = sqlite3WalFindFrame(pPager->pWal, pgno, &iFrame);
    +-        if( rc!=SQLITE_OK ) goto pager_acquire_err;
    +-      }
    +       assert( pPg->pPager==pPager );
    +       pPager->aStat[PAGER_STAT_MISS]++;
    +-      rc = readDbPage(pPg, iFrame);
    ++      rc = readDbPage(pPg);
    +       if( rc!=SQLITE_OK ){
    +         goto pager_acquire_err;
    +       }
    +     }
    +     pager_set_pagehash(pPg);
    +   }
    +-
    +   return SQLITE_OK;
    + 
    + pager_acquire_err:
    +@@ -48427,11 +53486,109 @@ pager_acquire_err:
    +     sqlite3PcacheDrop(pPg);
    +   }
    +   pagerUnlockIfUnused(pPager);
    +-
    +   *ppPage = 0;
    +   return rc;
    + }
    + 
    ++#if SQLITE_MAX_MMAP_SIZE>0
    ++/* The page getter for when memory-mapped I/O is enabled */
    ++static int getPageMMap(
    ++  Pager *pPager,      /* The pager open on the database file */
    ++  Pgno pgno,          /* Page number to fetch */
    ++  DbPage **ppPage,    /* Write a pointer to the page here */
    ++  int flags           /* PAGER_GET_XXX flags */
    ++){
    ++  int rc = SQLITE_OK;
    ++  PgHdr *pPg = 0;
    ++  u32 iFrame = 0;                 /* Frame to read from WAL file */
    ++
    ++  /* It is acceptable to use a read-only (mmap) page for any page except
    ++  ** page 1 if there is no write-transaction open or the ACQUIRE_READONLY
    ++  ** flag was specified by the caller. And so long as the db is not a 
    ++  ** temporary or in-memory database.  */
    ++  const int bMmapOk = (pgno>1
    ++   && (pPager->eState==PAGER_READER || (flags & PAGER_GET_READONLY))
    ++  );
    ++
    ++  assert( USEFETCH(pPager) );
    ++#ifdef SQLITE_HAS_CODEC
    ++  assert( pPager->xCodec==0 );
    ++#endif
    ++
    ++  /* Optimization note:  Adding the "pgno<=1" term before "pgno==0" here
    ++  ** allows the compiler optimizer to reuse the results of the "pgno>1"
    ++  ** test in the previous statement, and avoid testing pgno==0 in the
    ++  ** common case where pgno is large. */
    ++  if( pgno<=1 && pgno==0 ){
    ++    return SQLITE_CORRUPT_BKPT;
    ++  }
    ++  assert( pPager->eState>=PAGER_READER );
    ++  assert( assert_pager_state(pPager) );
    ++  assert( pPager->hasHeldSharedLock==1 );
    ++  assert( pPager->errCode==SQLITE_OK );
    ++
    ++  if( bMmapOk && pagerUseWal(pPager) ){
    ++    rc = sqlite3WalFindFrame(pPager->pWal, pgno, &iFrame);
    ++    if( rc!=SQLITE_OK ){
    ++      *ppPage = 0;
    ++      return rc;
    ++    }
    ++  }
    ++  if( bMmapOk && iFrame==0 ){
    ++    void *pData = 0;
    ++    rc = sqlite3OsFetch(pPager->fd, 
    ++        (i64)(pgno-1) * pPager->pageSize, pPager->pageSize, &pData
    ++    );
    ++    if( rc==SQLITE_OK && pData ){
    ++      if( pPager->eState>PAGER_READER || pPager->tempFile ){
    ++        pPg = sqlite3PagerLookup(pPager, pgno);
    ++      }
    ++      if( pPg==0 ){
    ++        rc = pagerAcquireMapPage(pPager, pgno, pData, &pPg);
    ++      }else{
    ++        sqlite3OsUnfetch(pPager->fd, (i64)(pgno-1)*pPager->pageSize, pData);
    ++      }
    ++      if( pPg ){
    ++        assert( rc==SQLITE_OK );
    ++        *ppPage = pPg;
    ++        return SQLITE_OK;
    ++      }
    ++    }
    ++    if( rc!=SQLITE_OK ){
    ++      *ppPage = 0;
    ++      return rc;
    ++    }
    ++  }
    ++  return getPageNormal(pPager, pgno, ppPage, flags);
    ++}
    ++#endif /* SQLITE_MAX_MMAP_SIZE>0 */
    ++
    ++/* The page getter method for when the pager is an error state */
    ++static int getPageError(
    ++  Pager *pPager,      /* The pager open on the database file */
    ++  Pgno pgno,          /* Page number to fetch */
    ++  DbPage **ppPage,    /* Write a pointer to the page here */
    ++  int flags           /* PAGER_GET_XXX flags */
    ++){
    ++  UNUSED_PARAMETER(pgno);
    ++  UNUSED_PARAMETER(flags);
    ++  assert( pPager->errCode!=SQLITE_OK );
    ++  *ppPage = 0;
    ++  return pPager->errCode;
    ++}
    ++
    ++
    ++/* Dispatch all page fetch requests to the appropriate getter method.
    ++*/
    ++SQLITE_PRIVATE int sqlite3PagerGet(
    ++  Pager *pPager,      /* The pager open on the database file */
    ++  Pgno pgno,          /* Page number to fetch */
    ++  DbPage **ppPage,    /* Write a pointer to the page here */
    ++  int flags           /* PAGER_GET_XXX flags */
    ++){
    ++  return pPager->xGet(pPager, pgno, ppPage, flags);
    ++}
    ++
    + /*
    + ** Acquire a page if it is already in the in-memory cache.  Do
    + ** not read the page from disk.  Return a pointer to the page,
    +@@ -48457,25 +53614,39 @@ SQLITE_PRIVATE DbPage *sqlite3PagerLookup(Pager *pPager, Pgno pgno){
    + /*
    + ** Release a page reference.
    + **
    +-** If the number of references to the page drop to zero, then the
    +-** page is added to the LRU list.  When all references to all pages
    +-** are released, a rollback occurs and the lock on the database is
    +-** removed.
    ++** The sqlite3PagerUnref() and sqlite3PagerUnrefNotNull() may only be
    ++** used if we know that the page being released is not the last page.
    ++** The btree layer always holds page1 open until the end, so these first
    ++** to routines can be used to release any page other than BtShared.pPage1.
    ++**
    ++** Use sqlite3PagerUnrefPageOne() to release page1.  This latter routine
    ++** checks the total number of outstanding pages and if the number of
    ++** pages reaches zero it drops the database lock.
    + */
    + SQLITE_PRIVATE void sqlite3PagerUnrefNotNull(DbPage *pPg){
    +-  Pager *pPager;
    ++  TESTONLY( Pager *pPager = pPg->pPager; )
    +   assert( pPg!=0 );
    +-  pPager = pPg->pPager;
    +   if( pPg->flags & PGHDR_MMAP ){
    ++    assert( pPg->pgno!=1 );  /* Page1 is never memory mapped */
    +     pagerReleaseMapPage(pPg);
    +   }else{
    +     sqlite3PcacheRelease(pPg);
    +   }
    +-  pagerUnlockIfUnused(pPager);
    ++  /* Do not use this routine to release the last reference to page1 */
    ++  assert( sqlite3PcacheRefCount(pPager->pPCache)>0 );
    + }
    + SQLITE_PRIVATE void sqlite3PagerUnref(DbPage *pPg){
    +   if( pPg ) sqlite3PagerUnrefNotNull(pPg);
    + }
    ++SQLITE_PRIVATE void sqlite3PagerUnrefPageOne(DbPage *pPg){
    ++  Pager *pPager;
    ++  assert( pPg!=0 );
    ++  assert( pPg->pgno==1 );
    ++  assert( (pPg->flags & PGHDR_MMAP)==0 ); /* Page1 is never memory mapped */
    ++  pPager = pPg->pPager;
    ++  sqlite3PcacheRelease(pPg);
    ++  pagerUnlockIfUnused(pPager);
    ++}
    + 
    + /*
    + ** This function is called at the start of every write transaction.
    +@@ -48515,7 +53686,7 @@ static int pager_open_journal(Pager *pPager){
    +   if( !pagerUseWal(pPager) && pPager->journalMode!=PAGER_JOURNALMODE_OFF ){
    +     pPager->pInJournal = sqlite3BitvecCreate(pPager->dbSize);
    +     if( pPager->pInJournal==0 ){
    +-      return SQLITE_NOMEM;
    ++      return SQLITE_NOMEM_BKPT;
    +     }
    +   
    +     /* Open the journal file if it is not already open. */
    +@@ -48523,24 +53694,24 @@ static int pager_open_journal(Pager *pPager){
    +       if( pPager->journalMode==PAGER_JOURNALMODE_MEMORY ){
    +         sqlite3MemJournalOpen(pPager->jfd);
    +       }else{
    +-        const int flags =                   /* VFS flags to open journal file */
    +-          SQLITE_OPEN_READWRITE|SQLITE_OPEN_CREATE|
    +-          (pPager->tempFile ? 
    +-            (SQLITE_OPEN_DELETEONCLOSE|SQLITE_OPEN_TEMP_JOURNAL):
    +-            (SQLITE_OPEN_MAIN_JOURNAL)
    +-          );
    ++        int flags = SQLITE_OPEN_READWRITE|SQLITE_OPEN_CREATE;
    ++        int nSpill;
    + 
    ++        if( pPager->tempFile ){
    ++          flags |= (SQLITE_OPEN_DELETEONCLOSE|SQLITE_OPEN_TEMP_JOURNAL);
    ++          nSpill = sqlite3Config.nStmtSpill;
    ++        }else{
    ++          flags |= SQLITE_OPEN_MAIN_JOURNAL;
    ++          nSpill = jrnlBufferSize(pPager);
    ++        }
    ++          
    +         /* Verify that the database still has the same name as it did when
    +         ** it was originally opened. */
    +         rc = databaseIsUnmoved(pPager);
    +         if( rc==SQLITE_OK ){
    +-#ifdef SQLITE_ENABLE_ATOMIC_WRITE
    +-          rc = sqlite3JournalOpen(
    +-              pVfs, pPager->zJournal, pPager->jfd, flags, jrnlBufferSize(pPager)
    ++          rc = sqlite3JournalOpen (
    ++              pVfs, pPager->zJournal, pPager->jfd, flags, nSpill
    +           );
    +-#else
    +-          rc = sqlite3OsOpen(pVfs, pPager->zJournal, pPager->jfd, flags, 0);
    +-#endif
    +         }
    +       }
    +       assert( rc!=SQLITE_OK || isOpen(pPager->jfd) );
    +@@ -48607,7 +53778,7 @@ SQLITE_PRIVATE int sqlite3PagerBegin(Pager *pPager, int exFlag, int subjInMemory
    +         if( rc!=SQLITE_OK ){
    +           return rc;
    +         }
    +-        sqlite3WalExclusiveMode(pPager->pWal, 1);
    ++        (void)sqlite3WalExclusiveMode(pPager->pWal, 1);
    +       }
    + 
    +       /* Grab the write lock on the log file. If successful, upgrade to
    +@@ -48670,7 +53841,7 @@ static SQLITE_NOINLINE int pagerAddPageToRollbackJournal(PgHdr *pPg){
    +   assert( pPg->pgno!=PAGER_MJ_PGNO(pPager) );
    + 
    +   assert( pPager->journalHdr<=pPager->journalOff );
    +-  CODEC2(pPager, pPg->pData, pPg->pgno, 7, return SQLITE_NOMEM, pData2);
    ++  CODEC2(pPager, pPg->pData, pPg->pgno, 7, return SQLITE_NOMEM_BKPT, pData2);
    +   cksum = pager_cksum(pPager, (u8*)pData2);
    + 
    +   /* Even if an IO or diskfull error occurs while journalling the
    +@@ -48847,7 +54018,7 @@ static SQLITE_NOINLINE int pagerWriteLargeSector(PgHdr *pPg){
    +     PgHdr *pPage;
    +     if( pg==pPg->pgno || !sqlite3BitvecTest(pPager->pInJournal, pg) ){
    +       if( pg!=PAGER_MJ_PGNO(pPager) ){
    +-        rc = sqlite3PagerGet(pPager, pg, &pPage);
    ++        rc = sqlite3PagerGet(pPager, pg, &pPage, 0);
    +         if( rc==SQLITE_OK ){
    +           rc = pager_write(pPage);
    +           if( pPage->flags&PGHDR_NEED_SYNC ){
    +@@ -48904,12 +54075,14 @@ SQLITE_PRIVATE int sqlite3PagerWrite(PgHdr *pPg){
    +   Pager *pPager = pPg->pPager;
    +   assert( (pPg->flags & PGHDR_MMAP)==0 );
    +   assert( pPager->eState>=PAGER_WRITER_LOCKED );
    +-  assert( pPager->eState!=PAGER_ERROR );
    +   assert( assert_pager_state(pPager) );
    +   if( (pPg->flags & PGHDR_WRITEABLE)!=0 && pPager->dbSize>=pPg->pgno ){
    +     if( pPager->nSavepoint ) return subjournalPageIfRequired(pPg);
    +     return SQLITE_OK;
    ++  }else if( pPager->errCode ){
    ++    return pPager->errCode;
    +   }else if( pPager->sectorSize > (u32)pPager->pageSize ){
    ++    assert( pPager->tempFile==0 );
    +     return pagerWriteLargeSector(pPg);
    +   }else{
    +     return pager_write(pPg);
    +@@ -48940,14 +54113,21 @@ SQLITE_PRIVATE int sqlite3PagerIswriteable(DbPage *pPg){
    + **
    + ** Tests show that this optimization can quadruple the speed of large 
    + ** DELETE operations.
    ++**
    ++** This optimization cannot be used with a temp-file, as the page may
    ++** have been dirty at the start of the transaction. In that case, if
    ++** memory pressure forces page pPg out of the cache, the data does need 
    ++** to be written out to disk so that it may be read back in if the 
    ++** current transaction is rolled back.
    + */
    + SQLITE_PRIVATE void sqlite3PagerDontWrite(PgHdr *pPg){
    +   Pager *pPager = pPg->pPager;
    +-  if( (pPg->flags&PGHDR_DIRTY) && pPager->nSavepoint==0 ){
    ++  if( !pPager->tempFile && (pPg->flags&PGHDR_DIRTY) && pPager->nSavepoint==0 ){
    +     PAGERTRACE(("DONT_WRITE page %d of %d\n", pPg->pgno, PAGERID(pPager)));
    +     IOTRACE(("CLEAN %p %d\n", pPager, pPg->pgno))
    +     pPg->flags |= PGHDR_DONT_WRITE;
    +     pPg->flags &= ~PGHDR_WRITEABLE;
    ++    testcase( pPg->flags & PGHDR_NEED_SYNC );
    +     pager_set_pagehash(pPg);
    +   }
    + }
    +@@ -49006,7 +54186,7 @@ static int pager_incr_changecounter(Pager *pPager, int isDirectMode){
    +     assert( !pPager->tempFile && isOpen(pPager->fd) );
    + 
    +     /* Open page 1 of the file for writing. */
    +-    rc = sqlite3PagerGet(pPager, 1, &pPgHdr);
    ++    rc = sqlite3PagerGet(pPager, 1, &pPgHdr, 0);
    +     assert( pPgHdr==0 || rc==SQLITE_OK );
    + 
    +     /* If page one was fetched successfully, and this function is not
    +@@ -49026,7 +54206,7 @@ static int pager_incr_changecounter(Pager *pPager, int isDirectMode){
    +       if( DIRECT_MODE ){
    +         const void *zBuf;
    +         assert( pPager->dbFileSize>0 );
    +-        CODEC2(pPager, pPgHdr->pData, 1, 6, rc=SQLITE_NOMEM, zBuf);
    ++        CODEC2(pPager, pPgHdr->pData, 1, 6, rc=SQLITE_NOMEM_BKPT, zBuf);
    +         if( rc==SQLITE_OK ){
    +           rc = sqlite3OsWrite(pPager->fd, zBuf, pPager->pageSize, 0);
    +           pPager->aStat[PAGER_STAT_WRITE]++;
    +@@ -49084,14 +54264,17 @@ SQLITE_PRIVATE int sqlite3PagerSync(Pager *pPager, const char *zMaster){
    + ** returned.
    + */
    + SQLITE_PRIVATE int sqlite3PagerExclusiveLock(Pager *pPager){
    +-  int rc = SQLITE_OK;
    +-  assert( pPager->eState==PAGER_WRITER_CACHEMOD 
    +-       || pPager->eState==PAGER_WRITER_DBMOD 
    +-       || pPager->eState==PAGER_WRITER_LOCKED 
    +-  );
    ++  int rc = pPager->errCode;
    +   assert( assert_pager_state(pPager) );
    +-  if( 0==pagerUseWal(pPager) ){
    +-    rc = pager_wait_on_lock(pPager, EXCLUSIVE_LOCK);
    ++  if( rc==SQLITE_OK ){
    ++    assert( pPager->eState==PAGER_WRITER_CACHEMOD 
    ++         || pPager->eState==PAGER_WRITER_DBMOD 
    ++         || pPager->eState==PAGER_WRITER_LOCKED 
    ++    );
    ++    assert( assert_pager_state(pPager) );
    ++    if( 0==pagerUseWal(pPager) ){
    ++      rc = pager_wait_on_lock(pPager, EXCLUSIVE_LOCK);
    ++    }
    +   }
    +   return rc;
    + }
    +@@ -49139,17 +54322,21 @@ SQLITE_PRIVATE int sqlite3PagerCommitPhaseOne(
    +   /* If a prior error occurred, report that error again. */
    +   if( NEVER(pPager->errCode) ) return pPager->errCode;
    + 
    ++  /* Provide the ability to easily simulate an I/O error during testing */
    ++  if( sqlite3FaultSim(400) ) return SQLITE_IOERR;
    ++
    +   PAGERTRACE(("DATABASE SYNC: File=%s zMaster=%s nSize=%d\n", 
    +       pPager->zFilename, zMaster, pPager->dbSize));
    + 
    +   /* If no database changes have been made, return early. */
    +   if( pPager->eState<PAGER_WRITER_CACHEMOD ) return SQLITE_OK;
    + 
    +-  if( MEMDB ){
    ++  assert( MEMDB==0 || pPager->tempFile );
    ++  assert( isOpen(pPager->fd) || pPager->tempFile );
    ++  if( 0==pagerFlushOnCommit(pPager, 1) ){
    +     /* If this is an in-memory db, or no pages have been written to, or this
    +     ** function has already been called, it is mostly a no-op.  However, any
    +-    ** backup in progress needs to be restarted.
    +-    */
    ++    ** backup in progress needs to be restarted.  */
    +     sqlite3BackupRestart(pPager->pBackup);
    +   }else{
    +     if( pagerUseWal(pPager) ){
    +@@ -49158,7 +54345,7 @@ SQLITE_PRIVATE int sqlite3PagerCommitPhaseOne(
    +       if( pList==0 ){
    +         /* Must have at least one page for the WAL commit flag.
    +         ** Ticket [2d1a5c67dfc2363e44f29d9bbd57f] 2011-05-18 */
    +-        rc = sqlite3PagerGet(pPager, 1, &pPageOne);
    ++        rc = sqlite3PagerGet(pPager, 1, &pPageOne, 0);
    +         pList = pPageOne;
    +         pList->pDirty = 0;
    +       }
    +@@ -49171,6 +54358,21 @@ SQLITE_PRIVATE int sqlite3PagerCommitPhaseOne(
    +         sqlite3PcacheCleanAll(pPager->pPCache);
    +       }
    +     }else{
    ++      /* The bBatch boolean is true if the batch-atomic-write commit method
    ++      ** should be used.  No rollback journal is created if batch-atomic-write
    ++      ** is enabled.
    ++      */
    ++      sqlite3_file *fd = pPager->fd;
    ++#ifdef SQLITE_ENABLE_BATCH_ATOMIC_WRITE
    ++      const int bBatch = zMaster==0    /* An SQLITE_IOCAP_BATCH_ATOMIC commit */
    ++        && (sqlite3OsDeviceCharacteristics(fd) & SQLITE_IOCAP_BATCH_ATOMIC)
    ++        && !pPager->noSync
    ++        && sqlite3JournalIsInMemory(pPager->jfd);
    ++#else
    ++# define bBatch 0
    ++#endif
    ++
    ++#ifdef SQLITE_ENABLE_ATOMIC_WRITE
    +       /* The following block updates the change-counter. Exactly how it
    +       ** does this depends on whether or not the atomic-update optimization
    +       ** was enabled at compile time, and if this transaction meets the 
    +@@ -49194,33 +54396,40 @@ SQLITE_PRIVATE int sqlite3PagerCommitPhaseOne(
    +       ** in 'direct' mode. In this case the journal file will never be
    +       ** created for this transaction.
    +       */
    +-  #ifdef SQLITE_ENABLE_ATOMIC_WRITE
    +-      PgHdr *pPg;
    +-      assert( isOpen(pPager->jfd) 
    +-           || pPager->journalMode==PAGER_JOURNALMODE_OFF 
    +-           || pPager->journalMode==PAGER_JOURNALMODE_WAL 
    +-      );
    +-      if( !zMaster && isOpen(pPager->jfd) 
    +-       && pPager->journalOff==jrnlBufferSize(pPager) 
    +-       && pPager->dbSize>=pPager->dbOrigSize
    +-       && (0==(pPg = sqlite3PcacheDirtyList(pPager->pPCache)) || 0==pPg->pDirty)
    +-      ){
    +-        /* Update the db file change counter via the direct-write method. The 
    +-        ** following call will modify the in-memory representation of page 1 
    +-        ** to include the updated change counter and then write page 1 
    +-        ** directly to the database file. Because of the atomic-write 
    +-        ** property of the host file-system, this is safe.
    +-        */
    +-        rc = pager_incr_changecounter(pPager, 1);
    +-      }else{
    +-        rc = sqlite3JournalCreate(pPager->jfd);
    +-        if( rc==SQLITE_OK ){
    +-          rc = pager_incr_changecounter(pPager, 0);
    ++      if( bBatch==0 ){
    ++        PgHdr *pPg;
    ++        assert( isOpen(pPager->jfd) 
    ++            || pPager->journalMode==PAGER_JOURNALMODE_OFF 
    ++            || pPager->journalMode==PAGER_JOURNALMODE_WAL 
    ++            );
    ++        if( !zMaster && isOpen(pPager->jfd) 
    ++         && pPager->journalOff==jrnlBufferSize(pPager) 
    ++         && pPager->dbSize>=pPager->dbOrigSize
    ++         && (!(pPg = sqlite3PcacheDirtyList(pPager->pPCache)) || 0==pPg->pDirty)
    ++        ){
    ++          /* Update the db file change counter via the direct-write method. The 
    ++          ** following call will modify the in-memory representation of page 1 
    ++          ** to include the updated change counter and then write page 1 
    ++          ** directly to the database file. Because of the atomic-write 
    ++          ** property of the host file-system, this is safe.
    ++          */
    ++          rc = pager_incr_changecounter(pPager, 1);
    ++        }else{
    ++          rc = sqlite3JournalCreate(pPager->jfd);
    ++          if( rc==SQLITE_OK ){
    ++            rc = pager_incr_changecounter(pPager, 0);
    ++          }
    +         }
    +       }
    +-  #else
    ++#else 
    ++#ifdef SQLITE_ENABLE_BATCH_ATOMIC_WRITE
    ++      if( zMaster ){
    ++        rc = sqlite3JournalCreate(pPager->jfd);
    ++        if( rc!=SQLITE_OK ) goto commit_phase_one_exit;
    ++      }
    ++#endif
    +       rc = pager_incr_changecounter(pPager, 0);
    +-  #endif
    ++#endif
    +       if( rc!=SQLITE_OK ) goto commit_phase_one_exit;
    +   
    +       /* Write the master journal name into the journal file. If a master 
    +@@ -49243,8 +54452,24 @@ SQLITE_PRIVATE int sqlite3PagerCommitPhaseOne(
    +       */
    +       rc = syncJournal(pPager, 0);
    +       if( rc!=SQLITE_OK ) goto commit_phase_one_exit;
    +-  
    ++
    ++      if( bBatch ){
    ++        /* The pager is now in DBMOD state. But regardless of what happens
    ++        ** next, attempting to play the journal back into the database would
    ++        ** be unsafe. Close it now to make sure that does not happen.  */
    ++        sqlite3OsClose(pPager->jfd);
    ++        rc = sqlite3OsFileControl(fd, SQLITE_FCNTL_BEGIN_ATOMIC_WRITE, 0);
    ++        if( rc!=SQLITE_OK ) goto commit_phase_one_exit;
    ++      }
    +       rc = pager_write_pagelist(pPager,sqlite3PcacheDirtyList(pPager->pPCache));
    ++      if( bBatch ){
    ++        if( rc==SQLITE_OK ){
    ++          rc = sqlite3OsFileControl(fd, SQLITE_FCNTL_COMMIT_ATOMIC_WRITE, 0);
    ++        }else{
    ++          sqlite3OsFileControl(fd, SQLITE_FCNTL_ROLLBACK_ATOMIC_WRITE, 0);
    ++        }
    ++      }
    ++
    +       if( rc!=SQLITE_OK ){
    +         assert( rc!=SQLITE_IOERR_BLOCKED );
    +         goto commit_phase_one_exit;
    +@@ -49388,6 +54613,7 @@ SQLITE_PRIVATE int sqlite3PagerRollback(Pager *pPager){
    +       */
    +       pPager->errCode = SQLITE_ABORT;
    +       pPager->eState = PAGER_ERROR;
    ++      setGetterMethod(pPager);
    +       return rc;
    +     }
    +   }else{
    +@@ -49488,10 +54714,10 @@ SQLITE_PRIVATE void sqlite3PagerCacheStat(Pager *pPager, int eStat, int reset, i
    + }
    + 
    + /*
    +-** Return true if this is an in-memory pager.
    ++** Return true if this is an in-memory or temp-file backed pager.
    + */
    + SQLITE_PRIVATE int sqlite3PagerIsMemdb(Pager *pPager){
    +-  return MEMDB;
    ++  return pPager->tempFile;
    + }
    + 
    + /*
    +@@ -49522,7 +54748,7 @@ static SQLITE_NOINLINE int pagerOpenSavepoint(Pager *pPager, int nSavepoint){
    +       pPager->aSavepoint, sizeof(PagerSavepoint)*nSavepoint
    +   );
    +   if( !aNew ){
    +-    return SQLITE_NOMEM;
    ++    return SQLITE_NOMEM_BKPT;
    +   }
    +   memset(&aNew[nCurrent], 0, (nSavepoint-nCurrent) * sizeof(PagerSavepoint));
    +   pPager->aSavepoint = aNew;
    +@@ -49538,7 +54764,7 @@ static SQLITE_NOINLINE int pagerOpenSavepoint(Pager *pPager, int nSavepoint){
    +     aNew[ii].iSubRec = pPager->nSubRec;
    +     aNew[ii].pInSavepoint = sqlite3BitvecCreate(pPager->dbSize);
    +     if( !aNew[ii].pInSavepoint ){
    +-      return SQLITE_NOMEM;
    ++      return SQLITE_NOMEM_BKPT;
    +     }
    +     if( pagerUseWal(pPager) ){
    +       sqlite3WalSavepoint(pPager->pWal, aNew[ii].aWalData);
    +@@ -49592,7 +54818,11 @@ SQLITE_PRIVATE int sqlite3PagerOpenSavepoint(Pager *pPager, int nSavepoint){
    + ** savepoint. If no errors occur, SQLITE_OK is returned.
    + */ 
    + SQLITE_PRIVATE int sqlite3PagerSavepoint(Pager *pPager, int op, int iSavepoint){
    +-  int rc = pPager->errCode;       /* Return code */
    ++  int rc = pPager->errCode;
    ++  
    ++#ifdef SQLITE_ENABLE_ZIPVFS
    ++  if( op==SAVEPOINT_RELEASE ) rc = SQLITE_OK;
    ++#endif
    + 
    +   assert( op==SAVEPOINT_RELEASE || op==SAVEPOINT_ROLLBACK );
    +   assert( iSavepoint>=0 || op==SAVEPOINT_ROLLBACK );
    +@@ -49616,7 +54846,7 @@ SQLITE_PRIVATE int sqlite3PagerSavepoint(Pager *pPager, int op, int iSavepoint){
    +     if( op==SAVEPOINT_RELEASE ){
    +       if( nNew==0 && isOpen(pPager->sjfd) ){
    +         /* Only truncate if it is an in-memory sub-journal. */
    +-        if( sqlite3IsMemJournal(pPager->sjfd) ){
    ++        if( sqlite3JournalIsInMemory(pPager->sjfd) ){
    +           rc = sqlite3OsTruncate(pPager->sjfd, 0);
    +           assert( rc==SQLITE_OK );
    +         }
    +@@ -49633,6 +54863,21 @@ SQLITE_PRIVATE int sqlite3PagerSavepoint(Pager *pPager, int op, int iSavepoint){
    +       rc = pagerPlaybackSavepoint(pPager, pSavepoint);
    +       assert(rc!=SQLITE_DONE);
    +     }
    ++    
    ++#ifdef SQLITE_ENABLE_ZIPVFS
    ++    /* If the cache has been modified but the savepoint cannot be rolled 
    ++    ** back journal_mode=off, put the pager in the error state. This way,
    ++    ** if the VFS used by this pager includes ZipVFS, the entire transaction
    ++    ** can be rolled back at the ZipVFS level.  */
    ++    else if( 
    ++        pPager->journalMode==PAGER_JOURNALMODE_OFF 
    ++     && pPager->eState>=PAGER_WRITER_CACHEMOD
    ++    ){
    ++      pPager->errCode = SQLITE_ABORT;
    ++      pPager->eState = PAGER_ERROR;
    ++      setGetterMethod(pPager);
    ++    }
    ++#endif
    +   }
    + 
    +   return rc;
    +@@ -49655,7 +54900,7 @@ SQLITE_PRIVATE const char *sqlite3PagerFilename(Pager *pPager, int nullIfMemDb){
    + /*
    + ** Return the VFS structure for the pager.
    + */
    +-SQLITE_PRIVATE const sqlite3_vfs *sqlite3PagerVfs(Pager *pPager){
    ++SQLITE_PRIVATE sqlite3_vfs *sqlite3PagerVfs(Pager *pPager){
    +   return pPager->pVfs;
    + }
    + 
    +@@ -49669,18 +54914,22 @@ SQLITE_PRIVATE sqlite3_file *sqlite3PagerFile(Pager *pPager){
    + }
    + 
    + /*
    +-** Return the full pathname of the journal file.
    ++** Return the file handle for the journal file (if it exists).
    ++** This will be either the rollback journal or the WAL file.
    + */
    +-SQLITE_PRIVATE const char *sqlite3PagerJournalname(Pager *pPager){
    +-  return pPager->zJournal;
    ++SQLITE_PRIVATE sqlite3_file *sqlite3PagerJrnlFile(Pager *pPager){
    ++#if SQLITE_OMIT_WAL
    ++  return pPager->jfd;
    ++#else
    ++  return pPager->pWal ? sqlite3WalFile(pPager->pWal) : pPager->jfd;
    ++#endif
    + }
    + 
    + /*
    +-** Return true if fsync() calls are disabled for this pager.  Return FALSE
    +-** if fsync()s are executed normally.
    ++** Return the full pathname of the journal file.
    + */
    +-SQLITE_PRIVATE int sqlite3PagerNosync(Pager *pPager){
    +-  return pPager->noSync;
    ++SQLITE_PRIVATE const char *sqlite3PagerJournalname(Pager *pPager){
    ++  return pPager->zJournal;
    + }
    + 
    + #ifdef SQLITE_HAS_CODEC
    +@@ -49699,6 +54948,7 @@ SQLITE_PRIVATE void sqlite3PagerSetCodec(
    +   pPager->xCodecSizeChng = xCodecSizeChng;
    +   pPager->xCodecFree = xCodecFree;
    +   pPager->pCodec = pCodec;
    ++  setGetterMethod(pPager);
    +   pagerReportSize(pPager);
    + }
    + SQLITE_PRIVATE void *sqlite3PagerGetCodec(Pager *pPager){
    +@@ -49767,7 +55017,8 @@ SQLITE_PRIVATE int sqlite3PagerMovepage(Pager *pPager, DbPage *pPg, Pgno pgno, i
    +   /* In order to be able to rollback, an in-memory database must journal
    +   ** the page we are moving from.
    +   */
    +-  if( MEMDB ){
    ++  assert( pPager->tempFile || !MEMDB );
    ++  if( pPager->tempFile ){
    +     rc = sqlite3PagerWrite(pPg);
    +     if( rc ) return rc;
    +   }
    +@@ -49824,7 +55075,7 @@ SQLITE_PRIVATE int sqlite3PagerMovepage(Pager *pPager, DbPage *pPg, Pgno pgno, i
    +   assert( !pPgOld || pPgOld->nRef==1 );
    +   if( pPgOld ){
    +     pPg->flags |= (pPgOld->flags&PGHDR_NEED_SYNC);
    +-    if( MEMDB ){
    ++    if( pPager->tempFile ){
    +       /* Do not discard pages from an in-memory database since we might
    +       ** need to rollback later.  Just move the page out of the way. */
    +       sqlite3PcacheMove(pPgOld, pPager->dbSize+1);
    +@@ -49841,8 +55092,7 @@ SQLITE_PRIVATE int sqlite3PagerMovepage(Pager *pPager, DbPage *pPg, Pgno pgno, i
    +   ** to exist, in case the transaction needs to roll back.  Use pPgOld
    +   ** as the original page since it has already been allocated.
    +   */
    +-  if( MEMDB ){
    +-    assert( pPgOld );
    ++  if( pPager->tempFile && pPgOld ){
    +     sqlite3PcacheMove(pPgOld, origPgno);
    +     sqlite3PagerUnrefNotNull(pPgOld);
    +   }
    +@@ -49863,7 +55113,7 @@ SQLITE_PRIVATE int sqlite3PagerMovepage(Pager *pPager, DbPage *pPg, Pgno pgno, i
    +     ** the journal file twice, but that is not a problem.
    +     */
    +     PgHdr *pPgHdr;
    +-    rc = sqlite3PagerGet(pPager, needSyncPgno, &pPgHdr);
    ++    rc = sqlite3PagerGet(pPager, needSyncPgno, &pPgHdr, 0);
    +     if( rc!=SQLITE_OK ){
    +       if( needSyncPgno<=pPager->dbOrigSize ){
    +         assert( pPager->pTmpSpace!=0 );
    +@@ -50094,10 +55344,12 @@ SQLITE_PRIVATE sqlite3_backup **sqlite3PagerBackupPtr(Pager *pPager){
    + ** Unless this is an in-memory or temporary database, clear the pager cache.
    + */
    + SQLITE_PRIVATE void sqlite3PagerClearCache(Pager *pPager){
    +-  if( !MEMDB && pPager->tempFile==0 ) pager_reset(pPager);
    ++  assert( MEMDB==0 || pPager->tempFile );
    ++  if( pPager->tempFile==0 ) pager_reset(pPager);
    + }
    + #endif
    + 
    ++
    + #ifndef SQLITE_OMIT_WAL
    + /*
    + ** This function is called when the user invokes "PRAGMA wal_checkpoint",
    +@@ -50106,13 +55358,19 @@ SQLITE_PRIVATE void sqlite3PagerClearCache(Pager *pPager){
    + **
    + ** Parameter eMode is one of SQLITE_CHECKPOINT_PASSIVE, FULL or RESTART.
    + */
    +-SQLITE_PRIVATE int sqlite3PagerCheckpoint(Pager *pPager, int eMode, int *pnLog, int *pnCkpt){
    ++SQLITE_PRIVATE int sqlite3PagerCheckpoint(
    ++  Pager *pPager,                  /* Checkpoint on this pager */
    ++  sqlite3 *db,                    /* Db handle used to check for interrupts */
    ++  int eMode,                      /* Type of checkpoint */
    ++  int *pnLog,                     /* OUT: Final number of frames in log */
    ++  int *pnCkpt                     /* OUT: Final number of checkpointed frames */
    ++){
    +   int rc = SQLITE_OK;
    +   if( pPager->pWal ){
    +-    rc = sqlite3WalCheckpoint(pPager->pWal, eMode,
    ++    rc = sqlite3WalCheckpoint(pPager->pWal, db, eMode,
    +         (eMode==SQLITE_CHECKPOINT_PASSIVE ? 0 : pPager->xBusyHandler),
    +         pPager->pBusyHandlerArg,
    +-        pPager->ckptSyncFlags, pPager->pageSize, (u8 *)pPager->pTmpSpace,
    ++        pPager->walSyncFlags, pPager->pageSize, (u8 *)pPager->pTmpSpace,
    +         pnLog, pnCkpt
    +     );
    +   }
    +@@ -50129,6 +55387,7 @@ SQLITE_PRIVATE int sqlite3PagerWalCallback(Pager *pPager){
    + */
    + SQLITE_PRIVATE int sqlite3PagerWalSupported(Pager *pPager){
    +   const sqlite3_io_methods *pMethods = pPager->fd->pMethods;
    ++  if( pPager->noLock ) return 0;
    +   return pPager->exclusiveMode || (pMethods->iVersion>=2 && pMethods->xShmMap);
    + }
    + 
    +@@ -50240,7 +55499,7 @@ SQLITE_PRIVATE int sqlite3PagerOpenWal(
    + ** error (SQLITE_BUSY) is returned and the log connection is not closed.
    + ** If successful, the EXCLUSIVE lock is not released before returning.
    + */
    +-SQLITE_PRIVATE int sqlite3PagerCloseWal(Pager *pPager){
    ++SQLITE_PRIVATE int sqlite3PagerCloseWal(Pager *pPager, sqlite3 *db){
    +   int rc = SQLITE_OK;
    + 
    +   assert( pPager->journalMode==PAGER_JOURNALMODE_WAL );
    +@@ -50268,15 +55527,58 @@ SQLITE_PRIVATE int sqlite3PagerCloseWal(Pager *pPager){
    +   if( rc==SQLITE_OK && pPager->pWal ){
    +     rc = pagerExclusiveLock(pPager);
    +     if( rc==SQLITE_OK ){
    +-      rc = sqlite3WalClose(pPager->pWal, pPager->ckptSyncFlags,
    ++      rc = sqlite3WalClose(pPager->pWal, db, pPager->walSyncFlags,
    +                            pPager->pageSize, (u8*)pPager->pTmpSpace);
    +       pPager->pWal = 0;
    +       pagerFixMaplimit(pPager);
    ++      if( rc && !pPager->exclusiveMode ) pagerUnlockDb(pPager, SHARED_LOCK);
    +     }
    +   }
    +   return rc;
    + }
    + 
    ++#ifdef SQLITE_ENABLE_SNAPSHOT
    ++/*
    ++** If this is a WAL database, obtain a snapshot handle for the snapshot
    ++** currently open. Otherwise, return an error.
    ++*/
    ++SQLITE_PRIVATE int sqlite3PagerSnapshotGet(Pager *pPager, sqlite3_snapshot **ppSnapshot){
    ++  int rc = SQLITE_ERROR;
    ++  if( pPager->pWal ){
    ++    rc = sqlite3WalSnapshotGet(pPager->pWal, ppSnapshot);
    ++  }
    ++  return rc;
    ++}
    ++
    ++/*
    ++** If this is a WAL database, store a pointer to pSnapshot. Next time a
    ++** read transaction is opened, attempt to read from the snapshot it 
    ++** identifies. If this is not a WAL database, return an error.
    ++*/
    ++SQLITE_PRIVATE int sqlite3PagerSnapshotOpen(Pager *pPager, sqlite3_snapshot *pSnapshot){
    ++  int rc = SQLITE_OK;
    ++  if( pPager->pWal ){
    ++    sqlite3WalSnapshotOpen(pPager->pWal, pSnapshot);
    ++  }else{
    ++    rc = SQLITE_ERROR;
    ++  }
    ++  return rc;
    ++}
    ++
    ++/*
    ++** If this is a WAL database, call sqlite3WalSnapshotRecover(). If this 
    ++** is not a WAL database, return an error.
    ++*/
    ++SQLITE_PRIVATE int sqlite3PagerSnapshotRecover(Pager *pPager){
    ++  int rc;
    ++  if( pPager->pWal ){
    ++    rc = sqlite3WalSnapshotRecover(pPager->pWal);
    ++  }else{
    ++    rc = SQLITE_ERROR;
    ++  }
    ++  return rc;
    ++}
    ++#endif /* SQLITE_ENABLE_SNAPSHOT */
    + #endif /* !SQLITE_OMIT_WAL */
    + 
    + #ifdef SQLITE_ENABLE_ZIPVFS
    +@@ -50293,7 +55595,6 @@ SQLITE_PRIVATE int sqlite3PagerWalFramesize(Pager *pPager){
    + }
    + #endif
    + 
    +-
    + #endif /* SQLITE_OMIT_DISKIO */
    + 
    + /************** End of pager.c ***********************************************/
    +@@ -50432,6 +55733,10 @@ SQLITE_PRIVATE int sqlite3PagerWalFramesize(Pager *pPager){
    + ** on a network filesystem.  All users of the database must be able to
    + ** share memory.
    + **
    ++** In the default unix and windows implementation, the wal-index is a mmapped
    ++** file whose name is the database name with a "-shm" suffix added.  For that
    ++** reason, the wal-index is sometimes called the "shm" file.
    ++**
    + ** The wal-index is transient.  After a crash, the wal-index can (and should
    + ** be) reconstructed from the original WAL file.  In fact, the VFS is required
    + ** to either truncate or zero the header of the wal-index when the last
    +@@ -50571,8 +55876,18 @@ SQLITE_PRIVATE int sqlite3WalTrace = 0;
    + #define WALINDEX_MAX_VERSION 3007000
    + 
    + /*
    +-** Indices of various locking bytes.   WAL_NREADER is the number
    +-** of available reader locks and should be at least 3.
    ++** Index numbers for various locking bytes.   WAL_NREADER is the number
    ++** of available reader locks and should be at least 3.  The default
    ++** is SQLITE_SHM_NLOCK==8 and  WAL_NREADER==5.
    ++**
    ++** Technically, the various VFSes are free to implement these locks however
    ++** they see fit.  However, compatibility is encouraged so that VFSes can
    ++** interoperate.  The standard implemention used on both unix and windows
    ++** is for the index number to indicate a byte offset into the
    ++** WalCkptInfo.aLock[] array in the wal-index header.  In other words, all
    ++** locks are on the shm file.  The WALINDEX_LOCK_OFFSET constant (which
    ++** should be 120) is the location in the shm file for the first locking
    ++** byte.
    + */
    + #define WAL_WRITE_LOCK         0
    + #define WAL_ALL_BUT_WRITE      1
    +@@ -50592,7 +55907,10 @@ typedef struct WalCkptInfo WalCkptInfo;
    + ** The following object holds a copy of the wal-index header content.
    + **
    + ** The actual header in the wal-index consists of two copies of this
    +-** object.
    ++** object followed by one instance of the WalCkptInfo object.
    ++** For all versions of SQLite through 3.10.0 and probably beyond,
    ++** the locking bytes (WalCkptInfo.aLock) start at offset 120 and
    ++** the total header size is 136 bytes.
    + **
    + ** The szPage value can be any power of 2 between 512 and 32768, inclusive.
    + ** Or it can be 1 to represent a 65536-byte page.  The latter case was
    +@@ -50625,6 +55943,16 @@ struct WalIndexHdr {
    + ** However, a WAL_WRITE_LOCK thread can move the value of nBackfill from
    + ** mxFrame back to zero when the WAL is reset.
    + **
    ++** nBackfillAttempted is the largest value of nBackfill that a checkpoint
    ++** has attempted to achieve.  Normally nBackfill==nBackfillAtempted, however
    ++** the nBackfillAttempted is set before any backfilling is done and the
    ++** nBackfill is only set after all backfilling completes.  So if a checkpoint
    ++** crashes, nBackfillAttempted might be larger than nBackfill.  The
    ++** WalIndexHdr.mxFrame must never be less than nBackfillAttempted.
    ++**
    ++** The aLock[] field is a set of bytes used for locking.  These bytes should
    ++** never be read or written.
    ++**
    + ** There is one entry in aReadMark[] for each reader lock.  If a reader
    + ** holds read-lock K, then the value in aReadMark[K] is no greater than
    + ** the mxFrame for that reader.  The value READMARK_NOT_USED (0xffffffff)
    +@@ -50664,6 +55992,9 @@ struct WalIndexHdr {
    + struct WalCkptInfo {
    +   u32 nBackfill;                  /* Number of WAL frames backfilled into DB */
    +   u32 aReadMark[WAL_NREADER];     /* Reader marks */
    ++  u8 aLock[SQLITE_SHM_NLOCK];     /* Reserved space for locks */
    ++  u32 nBackfillAttempted;         /* WAL frames perhaps written, or maybe not */
    ++  u32 notUsed0;                   /* Available for future enhancements */
    + };
    + #define READMARK_NOT_USED  0xffffffff
    + 
    +@@ -50673,15 +56004,13 @@ struct WalCkptInfo {
    + ** only support mandatory file-locks, we do not read or write data
    + ** from the region of the file on which locks are applied.
    + */
    +-#define WALINDEX_LOCK_OFFSET   (sizeof(WalIndexHdr)*2 + sizeof(WalCkptInfo))
    +-#define WALINDEX_LOCK_RESERVED 16
    +-#define WALINDEX_HDR_SIZE      (WALINDEX_LOCK_OFFSET+WALINDEX_LOCK_RESERVED)
    ++#define WALINDEX_LOCK_OFFSET (sizeof(WalIndexHdr)*2+offsetof(WalCkptInfo,aLock))
    ++#define WALINDEX_HDR_SIZE    (sizeof(WalIndexHdr)*2+sizeof(WalCkptInfo))
    + 
    + /* Size of header before each frame in wal */
    + #define WAL_FRAME_HDRSIZE 24
    + 
    + /* Size of write ahead log header, including checksum. */
    +-/* #define WAL_HDRSIZE 24 */
    + #define WAL_HDRSIZE 32
    + 
    + /* WAL magic value. Either this value, or the same value with the least
    +@@ -50727,13 +56056,18 @@ struct Wal {
    +   u8 truncateOnCommit;       /* True to truncate WAL file on commit */
    +   u8 syncHeader;             /* Fsync the WAL header if true */
    +   u8 padToSectorBoundary;    /* Pad transactions out to the next sector */
    ++  u8 bShmUnreliable;         /* SHM content is read-only and unreliable */
    +   WalIndexHdr hdr;           /* Wal-index header for current transaction */
    +   u32 minFrame;              /* Ignore wal frames before this one */
    ++  u32 iReCksum;              /* On commit, recalculate checksums from here */
    +   const char *zWalName;      /* Name of WAL file */
    +   u32 nCkpt;                 /* Checkpoint sequence counter in the wal-header */
    + #ifdef SQLITE_DEBUG
    +   u8 lockError;              /* True if a locking error has occurred */
    + #endif
    ++#ifdef SQLITE_ENABLE_SNAPSHOT
    ++  WalIndexHdr *pSnapshot;    /* Start transaction here if not NULL */
    ++#endif
    + };
    + 
    + /*
    +@@ -50812,6 +56146,11 @@ struct WalIterator {
    + ** is broken into pages of WALINDEX_PGSZ bytes. Wal-index pages are
    + ** numbered from zero.
    + **
    ++** If the wal-index is currently smaller the iPage pages then the size
    ++** of the wal-index might be increased, but only if it is safe to do
    ++** so.  It is safe to enlarge the wal-index if pWal->writeLock is true
    ++** or pWal->exclusiveMode==WAL_HEAPMEMORY_MODE.
    ++**
    + ** If this call is successful, *ppPage is set to point to the wal-index
    + ** page and SQLITE_OK is returned. If an error (an OOM or VFS error) occurs,
    + ** then an SQLite error code is returned and *ppPage is set to 0.
    +@@ -50826,7 +56165,7 @@ static int walIndexPage(Wal *pWal, int iPage, volatile u32 **ppPage){
    +     apNew = (volatile u32 **)sqlite3_realloc64((void *)pWal->apWiData, nByte);
    +     if( !apNew ){
    +       *ppPage = 0;
    +-      return SQLITE_NOMEM;
    ++      return SQLITE_NOMEM_BKPT;
    +     }
    +     memset((void*)&apNew[pWal->nWiData], 0,
    +            sizeof(u32*)*(iPage+1-pWal->nWiData));
    +@@ -50838,14 +56177,18 @@ static int walIndexPage(Wal *pWal, int iPage, volatile u32 **ppPage){
    +   if( pWal->apWiData[iPage]==0 ){
    +     if( pWal->exclusiveMode==WAL_HEAPMEMORY_MODE ){
    +       pWal->apWiData[iPage] = (u32 volatile *)sqlite3MallocZero(WALINDEX_PGSZ);
    +-      if( !pWal->apWiData[iPage] ) rc = SQLITE_NOMEM;
    ++      if( !pWal->apWiData[iPage] ) rc = SQLITE_NOMEM_BKPT;
    +     }else{
    +       rc = sqlite3OsShmMap(pWal->pDbFd, iPage, WALINDEX_PGSZ, 
    +           pWal->writeLock, (void volatile **)&pWal->apWiData[iPage]
    +       );
    +-      if( rc==SQLITE_READONLY ){
    ++      assert( pWal->apWiData[iPage]!=0 || rc!=SQLITE_OK || pWal->writeLock==0 );
    ++      testcase( pWal->apWiData[iPage]==0 && rc==SQLITE_OK );
    ++      if( (rc&0xff)==SQLITE_READONLY ){
    +         pWal->readOnly |= WAL_SHM_RDONLY;
    +-        rc = SQLITE_OK;
    ++        if( rc==SQLITE_READONLY ){
    ++          rc = SQLITE_OK;
    ++        }
    +       }
    +     }
    +   }
    +@@ -50979,14 +56322,18 @@ static void walEncodeFrame(
    +   assert( WAL_FRAME_HDRSIZE==24 );
    +   sqlite3Put4byte(&aFrame[0], iPage);
    +   sqlite3Put4byte(&aFrame[4], nTruncate);
    +-  memcpy(&aFrame[8], pWal->hdr.aSalt, 8);
    ++  if( pWal->iReCksum==0 ){
    ++    memcpy(&aFrame[8], pWal->hdr.aSalt, 8);
    + 
    +-  nativeCksum = (pWal->hdr.bigEndCksum==SQLITE_BIGENDIAN);
    +-  walChecksumBytes(nativeCksum, aFrame, 8, aCksum, aCksum);
    +-  walChecksumBytes(nativeCksum, aData, pWal->szPage, aCksum, aCksum);
    ++    nativeCksum = (pWal->hdr.bigEndCksum==SQLITE_BIGENDIAN);
    ++    walChecksumBytes(nativeCksum, aFrame, 8, aCksum, aCksum);
    ++    walChecksumBytes(nativeCksum, aData, pWal->szPage, aCksum, aCksum);
    + 
    +-  sqlite3Put4byte(&aFrame[16], aCksum[0]);
    +-  sqlite3Put4byte(&aFrame[20], aCksum[1]);
    ++    sqlite3Put4byte(&aFrame[16], aCksum[0]);
    ++    sqlite3Put4byte(&aFrame[20], aCksum[1]);
    ++  }else{
    ++    memset(&aFrame[8], 0, 16);
    ++  }
    + }
    + 
    + /*
    +@@ -51089,10 +56436,9 @@ static void walUnlockShared(Wal *pWal, int lockIdx){
    +                          SQLITE_SHM_UNLOCK | SQLITE_SHM_SHARED);
    +   WALTRACE(("WAL%p: release SHARED-%s\n", pWal, walLockName(lockIdx)));
    + }
    +-static int walLockExclusive(Wal *pWal, int lockIdx, int n, int fBlock){
    ++static int walLockExclusive(Wal *pWal, int lockIdx, int n){
    +   int rc;
    +   if( pWal->exclusiveMode ) return SQLITE_OK;
    +-  if( fBlock ) sqlite3OsFileControl(pWal->pDbFd, SQLITE_FCNTL_WAL_BLOCK, 0);
    +   rc = sqlite3OsShmLock(pWal->pDbFd, lockIdx, n,
    +                         SQLITE_SHM_LOCK | SQLITE_SHM_EXCLUSIVE);
    +   WALTRACE(("WAL%p: acquire EXCLUSIVE-%s cnt=%d %s\n", pWal,
    +@@ -51364,7 +56710,6 @@ static int walIndexRecover(Wal *pWal){
    +   i64 nSize;                      /* Size of log file */
    +   u32 aFrameCksum[2] = {0, 0};
    +   int iLock;                      /* Lock offset to lock for checkpoint */
    +-  int nLock;                      /* Number of locks to hold */
    + 
    +   /* Obtain an exclusive lock on all byte in the locking range not already
    +   ** locked by the caller. The caller is guaranteed to have locked the
    +@@ -51377,11 +56722,17 @@ static int walIndexRecover(Wal *pWal){
    +   assert( WAL_CKPT_LOCK==WAL_ALL_BUT_WRITE );
    +   assert( pWal->writeLock );
    +   iLock = WAL_ALL_BUT_WRITE + pWal->ckptLock;
    +-  nLock = SQLITE_SHM_NLOCK - iLock;
    +-  rc = walLockExclusive(pWal, iLock, nLock, 0);
    ++  rc = walLockExclusive(pWal, iLock, WAL_READ_LOCK(0)-iLock);
    ++  if( rc==SQLITE_OK ){
    ++    rc = walLockExclusive(pWal, WAL_READ_LOCK(1), WAL_NREADER-1);
    ++    if( rc!=SQLITE_OK ){
    ++      walUnlockExclusive(pWal, iLock, WAL_READ_LOCK(0)-iLock);
    ++    }
    ++  }
    +   if( rc ){
    +     return rc;
    +   }
    ++
    +   WALTRACE(("WAL%p: recovery begin...\n", pWal));
    + 
    +   memset(&pWal->hdr, 0, sizeof(WalIndexHdr));
    +@@ -51450,7 +56801,7 @@ static int walIndexRecover(Wal *pWal){
    +     szFrame = szPage + WAL_FRAME_HDRSIZE;
    +     aFrame = (u8 *)sqlite3_malloc64(szFrame);
    +     if( !aFrame ){
    +-      rc = SQLITE_NOMEM;
    ++      rc = SQLITE_NOMEM_BKPT;
    +       goto recovery_error;
    +     }
    +     aData = &aFrame[WAL_FRAME_HDRSIZE];
    +@@ -51499,6 +56850,7 @@ finished:
    +     */
    +     pInfo = walCkptInfo(pWal);
    +     pInfo->nBackfill = 0;
    ++    pInfo->nBackfillAttempted = pWal->hdr.mxFrame;
    +     pInfo->aReadMark[0] = 0;
    +     for(i=1; i<WAL_NREADER; i++) pInfo->aReadMark[i] = READMARK_NOT_USED;
    +     if( pWal->hdr.mxFrame ) pInfo->aReadMark[1] = pWal->hdr.mxFrame;
    +@@ -51518,7 +56870,8 @@ finished:
    + 
    + recovery_error:
    +   WALTRACE(("WAL%p: recovery %s\n", pWal, rc ? "failed" : "ok"));
    +-  walUnlockExclusive(pWal, iLock, nLock);
    ++  walUnlockExclusive(pWal, iLock, WAL_READ_LOCK(0)-iLock);
    ++  walUnlockExclusive(pWal, WAL_READ_LOCK(1), WAL_NREADER-1);
    +   return rc;
    + }
    + 
    +@@ -51526,13 +56879,14 @@ recovery_error:
    + ** Close an open wal-index.
    + */
    + static void walIndexClose(Wal *pWal, int isDelete){
    +-  if( pWal->exclusiveMode==WAL_HEAPMEMORY_MODE ){
    ++  if( pWal->exclusiveMode==WAL_HEAPMEMORY_MODE || pWal->bShmUnreliable ){
    +     int i;
    +     for(i=0; i<pWal->nWiData; i++){
    +       sqlite3_free((void *)pWal->apWiData[i]);
    +       pWal->apWiData[i] = 0;
    +     }
    +-  }else{
    ++  }
    ++  if( pWal->exclusiveMode!=WAL_HEAPMEMORY_MODE ){
    +     sqlite3OsShmUnmap(pWal->pDbFd, isDelete);
    +   }
    + }
    +@@ -51570,7 +56924,11 @@ SQLITE_PRIVATE int sqlite3WalOpen(
    +   /* In the amalgamation, the os_unix.c and os_win.c source files come before
    +   ** this source file.  Verify that the #defines of the locking byte offsets
    +   ** in os_unix.c and os_win.c agree with the WALINDEX_LOCK_OFFSET value.
    ++  ** For that matter, if the lock offset ever changes from its initial design
    ++  ** value of 120, we need to know that so there is an assert() to check it.
    +   */
    ++  assert( 120==WALINDEX_LOCK_OFFSET );
    ++  assert( 136==WALINDEX_HDR_SIZE );
    + #ifdef WIN_SHM_BASE
    +   assert( WIN_SHM_BASE==WALINDEX_LOCK_OFFSET );
    + #endif
    +@@ -51583,7 +56941,7 @@ SQLITE_PRIVATE int sqlite3WalOpen(
    +   *ppWal = 0;
    +   pRet = (Wal*)sqlite3MallocZero(sizeof(Wal) + pVfs->szOsFile);
    +   if( !pRet ){
    +-    return SQLITE_NOMEM;
    ++    return SQLITE_NOMEM_BKPT;
    +   }
    + 
    +   pRet->pVfs = pVfs;
    +@@ -51847,7 +57205,7 @@ static int walIteratorInit(Wal *pWal, WalIterator **pp){
    +         + iLast*sizeof(ht_slot);
    +   p = (WalIterator *)sqlite3_malloc64(nByte);
    +   if( !p ){
    +-    return SQLITE_NOMEM;
    ++    return SQLITE_NOMEM_BKPT;
    +   }
    +   memset(p, 0, nByte);
    +   p->nSegment = nSegment;
    +@@ -51859,7 +57217,7 @@ static int walIteratorInit(Wal *pWal, WalIterator **pp){
    +       sizeof(ht_slot) * (iLast>HASHTABLE_NPAGE?HASHTABLE_NPAGE:iLast)
    +   );
    +   if( !aTmp ){
    +-    rc = SQLITE_NOMEM;
    ++    rc = SQLITE_NOMEM_BKPT;
    +   }
    + 
    +   for(i=0; rc==SQLITE_OK && i<nSegment; i++){
    +@@ -51916,7 +57274,7 @@ static int walBusyLock(
    + ){
    +   int rc;
    +   do {
    +-    rc = walLockExclusive(pWal, lockIdx, n, 0);
    ++    rc = walLockExclusive(pWal, lockIdx, n);
    +   }while( xBusy && rc==SQLITE_BUSY && xBusy(pBusyArg) );
    +   return rc;
    + }
    +@@ -51956,6 +57314,7 @@ static void walRestartHdr(Wal *pWal, u32 salt1){
    +   memcpy(&pWal->hdr.aSalt[1], &salt1, 4);
    +   walIndexWriteHdr(pWal);
    +   pInfo->nBackfill = 0;
    ++  pInfo->nBackfillAttempted = 0;
    +   pInfo->aReadMark[1] = 0;
    +   for(i=2; i<WAL_NREADER; i++) pInfo->aReadMark[i] = READMARK_NOT_USED;
    +   assert( pInfo->aReadMark[0]==0 );
    +@@ -51994,6 +57353,7 @@ static void walRestartHdr(Wal *pWal, u32 salt1){
    + */
    + static int walCheckpoint(
    +   Wal *pWal,                      /* Wal connection */
    ++  sqlite3 *db,                    /* Check for interrupts on this handle */
    +   int eMode,                      /* One of PASSIVE, FULL or RESTART */
    +   int (*xBusy)(void*),            /* Function to call when busy */
    +   void *pBusyArg,                 /* Context argument for xBusyHandler */
    +@@ -52065,10 +57425,10 @@ static int walCheckpoint(
    +       i64 nSize;                    /* Current size of database file */
    +       u32 nBackfill = pInfo->nBackfill;
    + 
    ++      pInfo->nBackfillAttempted = mxSafeFrame;
    ++
    +       /* Sync the WAL to disk */
    +-      if( sync_flags ){
    +-        rc = sqlite3OsSync(pWal->pWalFd, sync_flags);
    +-      }
    ++      rc = sqlite3OsSync(pWal->pWalFd, CKPT_SYNC_FLAGS(sync_flags));
    + 
    +       /* If the database may grow as a result of this checkpoint, hint
    +       ** about the eventual size of the db file to the VFS layer.
    +@@ -52086,6 +57446,10 @@ static int walCheckpoint(
    +       while( rc==SQLITE_OK && 0==walIteratorNext(pIter, &iDbpage, &iFrame) ){
    +         i64 iOffset;
    +         assert( walFramePgno(pWal, iFrame)==iDbpage );
    ++        if( db->u1.isInterrupted ){
    ++          rc = db->mallocFailed ? SQLITE_NOMEM_BKPT : SQLITE_INTERRUPT;
    ++          break;
    ++        }
    +         if( iFrame<=nBackfill || iFrame>mxSafeFrame || iDbpage>mxPage ){
    +           continue;
    +         }
    +@@ -52105,8 +57469,8 @@ static int walCheckpoint(
    +           i64 szDb = pWal->hdr.nPage*(i64)szPage;
    +           testcase( IS_BIG_INT(szDb) );
    +           rc = sqlite3OsTruncate(pWal->pDbFd, szDb);
    +-          if( rc==SQLITE_OK && sync_flags ){
    +-            rc = sqlite3OsSync(pWal->pDbFd, sync_flags);
    ++          if( rc==SQLITE_OK ){
    ++            rc = sqlite3OsSync(pWal->pDbFd, CKPT_SYNC_FLAGS(sync_flags));
    +           }
    +         }
    +         if( rc==SQLITE_OK ){
    +@@ -52190,6 +57554,7 @@ static void walLimitSize(Wal *pWal, i64 nMax){
    + */
    + SQLITE_PRIVATE int sqlite3WalClose(
    +   Wal *pWal,                      /* Wal to close */
    ++  sqlite3 *db,                    /* For interrupt flag */
    +   int sync_flags,                 /* Flags to pass to OsSync() (or 0) */
    +   int nBuf,
    +   u8 *zBuf                        /* Buffer of at least nBuf bytes */
    +@@ -52206,13 +57571,14 @@ SQLITE_PRIVATE int sqlite3WalClose(
    +     **
    +     ** The EXCLUSIVE lock is not released before returning.
    +     */
    +-    rc = sqlite3OsLock(pWal->pDbFd, SQLITE_LOCK_EXCLUSIVE);
    +-    if( rc==SQLITE_OK ){
    ++    if( zBuf!=0
    ++     && SQLITE_OK==(rc = sqlite3OsLock(pWal->pDbFd, SQLITE_LOCK_EXCLUSIVE))
    ++    ){
    +       if( pWal->exclusiveMode==WAL_NORMAL_MODE ){
    +         pWal->exclusiveMode = WAL_EXCLUSIVE_MODE;
    +       }
    +-      rc = sqlite3WalCheckpoint(
    +-          pWal, SQLITE_CHECKPOINT_PASSIVE, 0, 0, sync_flags, nBuf, zBuf, 0, 0
    ++      rc = sqlite3WalCheckpoint(pWal, db, 
    ++          SQLITE_CHECKPOINT_PASSIVE, 0, 0, sync_flags, nBuf, zBuf, 0, 0
    +       );
    +       if( rc==SQLITE_OK ){
    +         int bPersist = -1;
    +@@ -52313,6 +57679,12 @@ static int walIndexTryHdr(Wal *pWal, int *pChanged){
    +   return 0;
    + }
    + 
    ++/*
    ++** This is the value that walTryBeginRead returns when it needs to
    ++** be retried.
    ++*/
    ++#define WAL_RETRY  (-1)
    ++
    + /*
    + ** Read the wal-index header from the wal-index and into pWal->hdr.
    + ** If the wal-header appears to be corrupt, try to reconstruct the
    +@@ -52336,9 +57708,29 @@ static int walIndexReadHdr(Wal *pWal, int *pChanged){
    +   assert( pChanged );
    +   rc = walIndexPage(pWal, 0, &page0);
    +   if( rc!=SQLITE_OK ){
    +-    return rc;
    +-  };
    +-  assert( page0 || pWal->writeLock==0 );
    ++    assert( rc!=SQLITE_READONLY ); /* READONLY changed to OK in walIndexPage */
    ++    if( rc==SQLITE_READONLY_CANTINIT ){
    ++      /* The SQLITE_READONLY_CANTINIT return means that the shared-memory
    ++      ** was openable but is not writable, and this thread is unable to
    ++      ** confirm that another write-capable connection has the shared-memory
    ++      ** open, and hence the content of the shared-memory is unreliable,
    ++      ** since the shared-memory might be inconsistent with the WAL file
    ++      ** and there is no writer on hand to fix it. */
    ++      assert( page0==0 );
    ++      assert( pWal->writeLock==0 );
    ++      assert( pWal->readOnly & WAL_SHM_RDONLY );
    ++      pWal->bShmUnreliable = 1;
    ++      pWal->exclusiveMode = WAL_HEAPMEMORY_MODE;
    ++      *pChanged = 1;
    ++    }else{
    ++      return rc; /* Any other non-OK return is just an error */
    ++    }
    ++  }else{
    ++    /* page0 can be NULL if the SHM is zero bytes in size and pWal->writeLock
    ++    ** is zero, which prevents the SHM from growing */
    ++    testcase( page0!=0 );
    ++  }
    ++  assert( page0!=0 || pWal->writeLock==0 );
    + 
    +   /* If the first page of the wal-index has been mapped, try to read the
    +   ** wal-index header immediately, without holding any lock. This usually
    +@@ -52352,12 +57744,12 @@ static int walIndexReadHdr(Wal *pWal, int *pChanged){
    +   */
    +   assert( badHdr==0 || pWal->writeLock==0 );
    +   if( badHdr ){
    +-    if( pWal->readOnly & WAL_SHM_RDONLY ){
    ++    if( pWal->bShmUnreliable==0 && (pWal->readOnly & WAL_SHM_RDONLY) ){
    +       if( SQLITE_OK==(rc = walLockShared(pWal, WAL_WRITE_LOCK)) ){
    +         walUnlockShared(pWal, WAL_WRITE_LOCK);
    +         rc = SQLITE_READONLY_RECOVERY;
    +       }
    +-    }else if( SQLITE_OK==(rc = walLockExclusive(pWal, WAL_WRITE_LOCK, 1, 1)) ){
    ++    }else if( SQLITE_OK==(rc = walLockExclusive(pWal, WAL_WRITE_LOCK, 1)) ){
    +       pWal->writeLock = 1;
    +       if( SQLITE_OK==(rc = walIndexPage(pWal, 0, &page0)) ){
    +         badHdr = walIndexTryHdr(pWal, pChanged);
    +@@ -52382,15 +57774,193 @@ static int walIndexReadHdr(Wal *pWal, int *pChanged){
    +   if( badHdr==0 && pWal->hdr.iVersion!=WALINDEX_MAX_VERSION ){
    +     rc = SQLITE_CANTOPEN_BKPT;
    +   }
    ++  if( pWal->bShmUnreliable ){
    ++    if( rc!=SQLITE_OK ){
    ++      walIndexClose(pWal, 0);
    ++      pWal->bShmUnreliable = 0;
    ++      assert( pWal->nWiData>0 && pWal->apWiData[0]==0 );
    ++      /* walIndexRecover() might have returned SHORT_READ if a concurrent
    ++      ** writer truncated the WAL out from under it.  If that happens, it
    ++      ** indicates that a writer has fixed the SHM file for us, so retry */
    ++      if( rc==SQLITE_IOERR_SHORT_READ ) rc = WAL_RETRY;
    ++    }
    ++    pWal->exclusiveMode = WAL_NORMAL_MODE;
    ++  }
    + 
    +   return rc;
    + }
    + 
    + /*
    +-** This is the value that walTryBeginRead returns when it needs to
    +-** be retried.
    ++** Open a transaction in a connection where the shared-memory is read-only
    ++** and where we cannot verify that there is a separate write-capable connection
    ++** on hand to keep the shared-memory up-to-date with the WAL file.
    ++**
    ++** This can happen, for example, when the shared-memory is implemented by
    ++** memory-mapping a *-shm file, where a prior writer has shut down and
    ++** left the *-shm file on disk, and now the present connection is trying
    ++** to use that database but lacks write permission on the *-shm file.
    ++** Other scenarios are also possible, depending on the VFS implementation.
    ++**
    ++** Precondition:
    ++**
    ++**    The *-wal file has been read and an appropriate wal-index has been
    ++**    constructed in pWal->apWiData[] using heap memory instead of shared
    ++**    memory. 
    ++**
    ++** If this function returns SQLITE_OK, then the read transaction has
    ++** been successfully opened. In this case output variable (*pChanged) 
    ++** is set to true before returning if the caller should discard the
    ++** contents of the page cache before proceeding. Or, if it returns 
    ++** WAL_RETRY, then the heap memory wal-index has been discarded and 
    ++** the caller should retry opening the read transaction from the 
    ++** beginning (including attempting to map the *-shm file). 
    ++**
    ++** If an error occurs, an SQLite error code is returned.
    + */
    +-#define WAL_RETRY  (-1)
    ++static int walBeginShmUnreliable(Wal *pWal, int *pChanged){
    ++  i64 szWal;                      /* Size of wal file on disk in bytes */
    ++  i64 iOffset;                    /* Current offset when reading wal file */
    ++  u8 aBuf[WAL_HDRSIZE];           /* Buffer to load WAL header into */
    ++  u8 *aFrame = 0;                 /* Malloc'd buffer to load entire frame */
    ++  int szFrame;                    /* Number of bytes in buffer aFrame[] */
    ++  u8 *aData;                      /* Pointer to data part of aFrame buffer */
    ++  volatile void *pDummy;          /* Dummy argument for xShmMap */
    ++  int rc;                         /* Return code */
    ++  u32 aSaveCksum[2];              /* Saved copy of pWal->hdr.aFrameCksum */
    ++
    ++  assert( pWal->bShmUnreliable );
    ++  assert( pWal->readOnly & WAL_SHM_RDONLY );
    ++  assert( pWal->nWiData>0 && pWal->apWiData[0] );
    ++
    ++  /* Take WAL_READ_LOCK(0). This has the effect of preventing any
    ++  ** writers from running a checkpoint, but does not stop them
    ++  ** from running recovery.  */
    ++  rc = walLockShared(pWal, WAL_READ_LOCK(0));
    ++  if( rc!=SQLITE_OK ){
    ++    if( rc==SQLITE_BUSY ) rc = WAL_RETRY;
    ++    goto begin_unreliable_shm_out;
    ++  }
    ++  pWal->readLock = 0;
    ++
    ++  /* Check to see if a separate writer has attached to the shared-memory area,
    ++  ** thus making the shared-memory "reliable" again.  Do this by invoking
    ++  ** the xShmMap() routine of the VFS and looking to see if the return
    ++  ** is SQLITE_READONLY instead of SQLITE_READONLY_CANTINIT.
    ++  **
    ++  ** If the shared-memory is now "reliable" return WAL_RETRY, which will
    ++  ** cause the heap-memory WAL-index to be discarded and the actual
    ++  ** shared memory to be used in its place.
    ++  **
    ++  ** This step is important because, even though this connection is holding
    ++  ** the WAL_READ_LOCK(0) which prevents a checkpoint, a writer might
    ++  ** have already checkpointed the WAL file and, while the current
    ++  ** is active, wrap the WAL and start overwriting frames that this
    ++  ** process wants to use.
    ++  **
    ++  ** Once sqlite3OsShmMap() has been called for an sqlite3_file and has
    ++  ** returned any SQLITE_READONLY value, it must return only SQLITE_READONLY
    ++  ** or SQLITE_READONLY_CANTINIT or some error for all subsequent invocations,
    ++  ** even if some external agent does a "chmod" to make the shared-memory
    ++  ** writable by us, until sqlite3OsShmUnmap() has been called.
    ++  ** This is a requirement on the VFS implementation.
    ++   */
    ++  rc = sqlite3OsShmMap(pWal->pDbFd, 0, WALINDEX_PGSZ, 0, &pDummy);
    ++  assert( rc!=SQLITE_OK ); /* SQLITE_OK not possible for read-only connection */
    ++  if( rc!=SQLITE_READONLY_CANTINIT ){
    ++    rc = (rc==SQLITE_READONLY ? WAL_RETRY : rc);
    ++    goto begin_unreliable_shm_out;
    ++  }
    ++
    ++  /* We reach this point only if the real shared-memory is still unreliable.
    ++  ** Assume the in-memory WAL-index substitute is correct and load it
    ++  ** into pWal->hdr.
    ++  */
    ++  memcpy(&pWal->hdr, (void*)walIndexHdr(pWal), sizeof(WalIndexHdr));
    ++
    ++  /* Make sure some writer hasn't come in and changed the WAL file out
    ++  ** from under us, then disconnected, while we were not looking.
    ++  */
    ++  rc = sqlite3OsFileSize(pWal->pWalFd, &szWal);
    ++  if( rc!=SQLITE_OK ){
    ++    goto begin_unreliable_shm_out;
    ++  }
    ++  if( szWal<WAL_HDRSIZE ){
    ++    /* If the wal file is too small to contain a wal-header and the
    ++    ** wal-index header has mxFrame==0, then it must be safe to proceed
    ++    ** reading the database file only. However, the page cache cannot
    ++    ** be trusted, as a read/write connection may have connected, written
    ++    ** the db, run a checkpoint, truncated the wal file and disconnected
    ++    ** since this client's last read transaction.  */
    ++    *pChanged = 1;
    ++    rc = (pWal->hdr.mxFrame==0 ? SQLITE_OK : WAL_RETRY);
    ++    goto begin_unreliable_shm_out;
    ++  }
    ++
    ++  /* Check the salt keys at the start of the wal file still match. */
    ++  rc = sqlite3OsRead(pWal->pWalFd, aBuf, WAL_HDRSIZE, 0);
    ++  if( rc!=SQLITE_OK ){
    ++    goto begin_unreliable_shm_out;
    ++  }
    ++  if( memcmp(&pWal->hdr.aSalt, &aBuf[16], 8) ){
    ++    /* Some writer has wrapped the WAL file while we were not looking.
    ++    ** Return WAL_RETRY which will cause the in-memory WAL-index to be
    ++    ** rebuilt. */
    ++    rc = WAL_RETRY;
    ++    goto begin_unreliable_shm_out;
    ++  }
    ++
    ++  /* Allocate a buffer to read frames into */
    ++  szFrame = pWal->hdr.szPage + WAL_FRAME_HDRSIZE;
    ++  aFrame = (u8 *)sqlite3_malloc64(szFrame);
    ++  if( aFrame==0 ){
    ++    rc = SQLITE_NOMEM_BKPT;
    ++    goto begin_unreliable_shm_out;
    ++  }
    ++  aData = &aFrame[WAL_FRAME_HDRSIZE];
    ++
    ++  /* Check to see if a complete transaction has been appended to the
    ++  ** wal file since the heap-memory wal-index was created. If so, the
    ++  ** heap-memory wal-index is discarded and WAL_RETRY returned to
    ++  ** the caller.  */
    ++  aSaveCksum[0] = pWal->hdr.aFrameCksum[0];
    ++  aSaveCksum[1] = pWal->hdr.aFrameCksum[1];
    ++  for(iOffset=walFrameOffset(pWal->hdr.mxFrame+1, pWal->hdr.szPage); 
    ++      iOffset+szFrame<=szWal; 
    ++      iOffset+=szFrame
    ++  ){
    ++    u32 pgno;                   /* Database page number for frame */
    ++    u32 nTruncate;              /* dbsize field from frame header */
    ++
    ++    /* Read and decode the next log frame. */
    ++    rc = sqlite3OsRead(pWal->pWalFd, aFrame, szFrame, iOffset);
    ++    if( rc!=SQLITE_OK ) break;
    ++    if( !walDecodeFrame(pWal, &pgno, &nTruncate, aData, aFrame) ) break;
    ++
    ++    /* If nTruncate is non-zero, then a complete transaction has been
    ++    ** appended to this wal file. Set rc to WAL_RETRY and break out of
    ++    ** the loop.  */
    ++    if( nTruncate ){
    ++      rc = WAL_RETRY;
    ++      break;
    ++    }
    ++  }
    ++  pWal->hdr.aFrameCksum[0] = aSaveCksum[0];
    ++  pWal->hdr.aFrameCksum[1] = aSaveCksum[1];
    ++
    ++ begin_unreliable_shm_out:
    ++  sqlite3_free(aFrame);
    ++  if( rc!=SQLITE_OK ){
    ++    int i;
    ++    for(i=0; i<pWal->nWiData; i++){
    ++      sqlite3_free((void*)pWal->apWiData[i]);
    ++      pWal->apWiData[i] = 0;
    ++    }
    ++    pWal->bShmUnreliable = 0;
    ++    sqlite3WalEndReadTransaction(pWal);
    ++    *pChanged = 1;
    ++  }
    ++  return rc;
    ++}
    + 
    + /*
    + ** Attempt to start a read transaction.  This might fail due to a race or
    +@@ -52406,7 +57976,7 @@ static int walIndexReadHdr(Wal *pWal, int *pChanged){
    + ** checkpointed.  If useWal==0 then this routine calls walIndexReadHdr() 
    + ** to make a copy of the wal-index header into pWal->hdr.  If the 
    + ** wal-index header has changed, *pChanged is set to 1 (as an indication 
    +-** to the caller that the local paget cache is obsolete and needs to be 
    ++** to the caller that the local page cache is obsolete and needs to be 
    + ** flushed.)  When useWal==1, the wal-index header is assumed to already
    + ** be loaded and the pChanged parameter is unused.
    + **
    +@@ -52448,9 +58018,13 @@ static int walTryBeginRead(Wal *pWal, int *pChanged, int useWal, int cnt){
    +   int mxI;                        /* Index of largest aReadMark[] value */
    +   int i;                          /* Loop counter */
    +   int rc = SQLITE_OK;             /* Return code  */
    ++  u32 mxFrame;                    /* Wal frame to lock to */
    + 
    +   assert( pWal->readLock<0 );     /* Not currently locked */
    + 
    ++  /* useWal may only be set for read/write connections */
    ++  assert( (pWal->readOnly & WAL_SHM_RDONLY)==0 || useWal==0 );
    ++
    +   /* Take steps to avoid spinning forever if there is a protocol error.
    +   **
    +   ** Circumstances that cause a RETRY should only last for the briefest
    +@@ -52479,7 +58053,10 @@ static int walTryBeginRead(Wal *pWal, int *pChanged, int useWal, int cnt){
    +   }
    + 
    +   if( !useWal ){
    +-    rc = walIndexReadHdr(pWal, pChanged);
    ++    assert( rc==SQLITE_OK );
    ++    if( pWal->bShmUnreliable==0 ){
    ++      rc = walIndexReadHdr(pWal, pChanged);
    ++    }
    +     if( rc==SQLITE_BUSY ){
    +       /* If there is not a recovery running in another thread or process
    +       ** then convert BUSY errors to WAL_RETRY.  If recovery is known to
    +@@ -52508,10 +58085,19 @@ static int walTryBeginRead(Wal *pWal, int *pChanged, int useWal, int cnt){
    +     if( rc!=SQLITE_OK ){
    +       return rc;
    +     }
    ++    else if( pWal->bShmUnreliable ){
    ++      return walBeginShmUnreliable(pWal, pChanged);
    ++    }
    +   }
    + 
    ++  assert( pWal->nWiData>0 );
    ++  assert( pWal->apWiData[0]!=0 );
    +   pInfo = walCkptInfo(pWal);
    +-  if( !useWal && pInfo->nBackfill==pWal->hdr.mxFrame ){
    ++  if( !useWal && pInfo->nBackfill==pWal->hdr.mxFrame
    ++#ifdef SQLITE_ENABLE_SNAPSHOT
    ++   && (pWal->pSnapshot==0 || pWal->hdr.mxFrame==0)
    ++#endif
    ++  ){
    +     /* The WAL has been completely backfilled (or it is empty).
    +     ** and can be safely ignored.
    +     */
    +@@ -52549,88 +58135,169 @@ static int walTryBeginRead(Wal *pWal, int *pChanged, int useWal, int cnt){
    +   */
    +   mxReadMark = 0;
    +   mxI = 0;
    ++  mxFrame = pWal->hdr.mxFrame;
    ++#ifdef SQLITE_ENABLE_SNAPSHOT
    ++  if( pWal->pSnapshot && pWal->pSnapshot->mxFrame<mxFrame ){
    ++    mxFrame = pWal->pSnapshot->mxFrame;
    ++  }
    ++#endif
    +   for(i=1; i<WAL_NREADER; i++){
    +     u32 thisMark = pInfo->aReadMark[i];
    +-    if( mxReadMark<=thisMark && thisMark<=pWal->hdr.mxFrame ){
    ++    if( mxReadMark<=thisMark && thisMark<=mxFrame ){
    +       assert( thisMark!=READMARK_NOT_USED );
    +       mxReadMark = thisMark;
    +       mxI = i;
    +     }
    +   }
    +-  /* There was once an "if" here. The extra "{" is to preserve indentation. */
    +-  {
    +-    if( (pWal->readOnly & WAL_SHM_RDONLY)==0
    +-     && (mxReadMark<pWal->hdr.mxFrame || mxI==0)
    +-    ){
    +-      for(i=1; i<WAL_NREADER; i++){
    +-        rc = walLockExclusive(pWal, WAL_READ_LOCK(i), 1, 0);
    +-        if( rc==SQLITE_OK ){
    +-          mxReadMark = pInfo->aReadMark[i] = pWal->hdr.mxFrame;
    +-          mxI = i;
    +-          walUnlockExclusive(pWal, WAL_READ_LOCK(i), 1);
    +-          break;
    +-        }else if( rc!=SQLITE_BUSY ){
    +-          return rc;
    +-        }
    ++  if( (pWal->readOnly & WAL_SHM_RDONLY)==0
    ++   && (mxReadMark<mxFrame || mxI==0)
    ++  ){
    ++    for(i=1; i<WAL_NREADER; i++){
    ++      rc = walLockExclusive(pWal, WAL_READ_LOCK(i), 1);
    ++      if( rc==SQLITE_OK ){
    ++        mxReadMark = pInfo->aReadMark[i] = mxFrame;
    ++        mxI = i;
    ++        walUnlockExclusive(pWal, WAL_READ_LOCK(i), 1);
    ++        break;
    ++      }else if( rc!=SQLITE_BUSY ){
    ++        return rc;
    +       }
    +     }
    +-    if( mxI==0 ){
    +-      assert( rc==SQLITE_BUSY || (pWal->readOnly & WAL_SHM_RDONLY)!=0 );
    +-      return rc==SQLITE_BUSY ? WAL_RETRY : SQLITE_READONLY_CANTLOCK;
    +-    }
    ++  }
    ++  if( mxI==0 ){
    ++    assert( rc==SQLITE_BUSY || (pWal->readOnly & WAL_SHM_RDONLY)!=0 );
    ++    return rc==SQLITE_BUSY ? WAL_RETRY : SQLITE_READONLY_CANTINIT;
    ++  }
    + 
    +-    rc = walLockShared(pWal, WAL_READ_LOCK(mxI));
    +-    if( rc ){
    +-      return rc==SQLITE_BUSY ? WAL_RETRY : rc;
    +-    }
    +-    /* Now that the read-lock has been obtained, check that neither the
    +-    ** value in the aReadMark[] array or the contents of the wal-index
    +-    ** header have changed.
    +-    **
    +-    ** It is necessary to check that the wal-index header did not change
    +-    ** between the time it was read and when the shared-lock was obtained
    +-    ** on WAL_READ_LOCK(mxI) was obtained to account for the possibility
    +-    ** that the log file may have been wrapped by a writer, or that frames
    +-    ** that occur later in the log than pWal->hdr.mxFrame may have been
    +-    ** copied into the database by a checkpointer. If either of these things
    +-    ** happened, then reading the database with the current value of
    +-    ** pWal->hdr.mxFrame risks reading a corrupted snapshot. So, retry
    +-    ** instead.
    +-    **
    +-    ** Before checking that the live wal-index header has not changed
    +-    ** since it was read, set Wal.minFrame to the first frame in the wal
    +-    ** file that has not yet been checkpointed. This client will not need
    +-    ** to read any frames earlier than minFrame from the wal file - they
    +-    ** can be safely read directly from the database file.
    +-    **
    +-    ** Because a ShmBarrier() call is made between taking the copy of 
    +-    ** nBackfill and checking that the wal-header in shared-memory still
    +-    ** matches the one cached in pWal->hdr, it is guaranteed that the 
    +-    ** checkpointer that set nBackfill was not working with a wal-index
    +-    ** header newer than that cached in pWal->hdr. If it were, that could
    +-    ** cause a problem. The checkpointer could omit to checkpoint
    +-    ** a version of page X that lies before pWal->minFrame (call that version
    +-    ** A) on the basis that there is a newer version (version B) of the same
    +-    ** page later in the wal file. But if version B happens to like past
    +-    ** frame pWal->hdr.mxFrame - then the client would incorrectly assume
    +-    ** that it can read version A from the database file. However, since
    +-    ** we can guarantee that the checkpointer that set nBackfill could not
    +-    ** see any pages past pWal->hdr.mxFrame, this problem does not come up.
    +-    */
    +-    pWal->minFrame = pInfo->nBackfill+1;
    +-    walShmBarrier(pWal);
    +-    if( pInfo->aReadMark[mxI]!=mxReadMark
    +-     || memcmp((void *)walIndexHdr(pWal), &pWal->hdr, sizeof(WalIndexHdr))
    +-    ){
    +-      walUnlockShared(pWal, WAL_READ_LOCK(mxI));
    +-      return WAL_RETRY;
    +-    }else{
    +-      assert( mxReadMark<=pWal->hdr.mxFrame );
    +-      pWal->readLock = (i16)mxI;
    ++  rc = walLockShared(pWal, WAL_READ_LOCK(mxI));
    ++  if( rc ){
    ++    return rc==SQLITE_BUSY ? WAL_RETRY : rc;
    ++  }
    ++  /* Now that the read-lock has been obtained, check that neither the
    ++  ** value in the aReadMark[] array or the contents of the wal-index
    ++  ** header have changed.
    ++  **
    ++  ** It is necessary to check that the wal-index header did not change
    ++  ** between the time it was read and when the shared-lock was obtained
    ++  ** on WAL_READ_LOCK(mxI) was obtained to account for the possibility
    ++  ** that the log file may have been wrapped by a writer, or that frames
    ++  ** that occur later in the log than pWal->hdr.mxFrame may have been
    ++  ** copied into the database by a checkpointer. If either of these things
    ++  ** happened, then reading the database with the current value of
    ++  ** pWal->hdr.mxFrame risks reading a corrupted snapshot. So, retry
    ++  ** instead.
    ++  **
    ++  ** Before checking that the live wal-index header has not changed
    ++  ** since it was read, set Wal.minFrame to the first frame in the wal
    ++  ** file that has not yet been checkpointed. This client will not need
    ++  ** to read any frames earlier than minFrame from the wal file - they
    ++  ** can be safely read directly from the database file.
    ++  **
    ++  ** Because a ShmBarrier() call is made between taking the copy of 
    ++  ** nBackfill and checking that the wal-header in shared-memory still
    ++  ** matches the one cached in pWal->hdr, it is guaranteed that the 
    ++  ** checkpointer that set nBackfill was not working with a wal-index
    ++  ** header newer than that cached in pWal->hdr. If it were, that could
    ++  ** cause a problem. The checkpointer could omit to checkpoint
    ++  ** a version of page X that lies before pWal->minFrame (call that version
    ++  ** A) on the basis that there is a newer version (version B) of the same
    ++  ** page later in the wal file. But if version B happens to like past
    ++  ** frame pWal->hdr.mxFrame - then the client would incorrectly assume
    ++  ** that it can read version A from the database file. However, since
    ++  ** we can guarantee that the checkpointer that set nBackfill could not
    ++  ** see any pages past pWal->hdr.mxFrame, this problem does not come up.
    ++  */
    ++  pWal->minFrame = pInfo->nBackfill+1;
    ++  walShmBarrier(pWal);
    ++  if( pInfo->aReadMark[mxI]!=mxReadMark
    ++   || memcmp((void *)walIndexHdr(pWal), &pWal->hdr, sizeof(WalIndexHdr))
    ++  ){
    ++    walUnlockShared(pWal, WAL_READ_LOCK(mxI));
    ++    return WAL_RETRY;
    ++  }else{
    ++    assert( mxReadMark<=pWal->hdr.mxFrame );
    ++    pWal->readLock = (i16)mxI;
    ++  }
    ++  return rc;
    ++}
    ++
    ++#ifdef SQLITE_ENABLE_SNAPSHOT
    ++/*
    ++** Attempt to reduce the value of the WalCkptInfo.nBackfillAttempted 
    ++** variable so that older snapshots can be accessed. To do this, loop
    ++** through all wal frames from nBackfillAttempted to (nBackfill+1), 
    ++** comparing their content to the corresponding page with the database
    ++** file, if any. Set nBackfillAttempted to the frame number of the
    ++** first frame for which the wal file content matches the db file.
    ++**
    ++** This is only really safe if the file-system is such that any page 
    ++** writes made by earlier checkpointers were atomic operations, which 
    ++** is not always true. It is also possible that nBackfillAttempted
    ++** may be left set to a value larger than expected, if a wal frame
    ++** contains content that duplicate of an earlier version of the same
    ++** page.
    ++**
    ++** SQLITE_OK is returned if successful, or an SQLite error code if an
    ++** error occurs. It is not an error if nBackfillAttempted cannot be
    ++** decreased at all.
    ++*/
    ++SQLITE_PRIVATE int sqlite3WalSnapshotRecover(Wal *pWal){
    ++  int rc;
    ++
    ++  assert( pWal->readLock>=0 );
    ++  rc = walLockExclusive(pWal, WAL_CKPT_LOCK, 1);
    ++  if( rc==SQLITE_OK ){
    ++    volatile WalCkptInfo *pInfo = walCkptInfo(pWal);
    ++    int szPage = (int)pWal->szPage;
    ++    i64 szDb;                   /* Size of db file in bytes */
    ++
    ++    rc = sqlite3OsFileSize(pWal->pDbFd, &szDb);
    ++    if( rc==SQLITE_OK ){
    ++      void *pBuf1 = sqlite3_malloc(szPage);
    ++      void *pBuf2 = sqlite3_malloc(szPage);
    ++      if( pBuf1==0 || pBuf2==0 ){
    ++        rc = SQLITE_NOMEM;
    ++      }else{
    ++        u32 i = pInfo->nBackfillAttempted;
    ++        for(i=pInfo->nBackfillAttempted; i>pInfo->nBackfill; i--){
    ++          volatile ht_slot *dummy;
    ++          volatile u32 *aPgno;      /* Array of page numbers */
    ++          u32 iZero;                /* Frame corresponding to aPgno[0] */
    ++          u32 pgno;                 /* Page number in db file */
    ++          i64 iDbOff;               /* Offset of db file entry */
    ++          i64 iWalOff;              /* Offset of wal file entry */
    ++
    ++          rc = walHashGet(pWal, walFramePage(i), &dummy, &aPgno, &iZero);
    ++          if( rc!=SQLITE_OK ) break;
    ++          pgno = aPgno[i-iZero];
    ++          iDbOff = (i64)(pgno-1) * szPage;
    ++
    ++          if( iDbOff+szPage<=szDb ){
    ++            iWalOff = walFrameOffset(i, szPage) + WAL_FRAME_HDRSIZE;
    ++            rc = sqlite3OsRead(pWal->pWalFd, pBuf1, szPage, iWalOff);
    ++
    ++            if( rc==SQLITE_OK ){
    ++              rc = sqlite3OsRead(pWal->pDbFd, pBuf2, szPage, iDbOff);
    ++            }
    ++
    ++            if( rc!=SQLITE_OK || 0==memcmp(pBuf1, pBuf2, szPage) ){
    ++              break;
    ++            }
    ++          }
    ++
    ++          pInfo->nBackfillAttempted = i-1;
    ++        }
    ++      }
    ++
    ++      sqlite3_free(pBuf1);
    ++      sqlite3_free(pBuf2);
    +     }
    ++    walUnlockExclusive(pWal, WAL_CKPT_LOCK, 1);
    +   }
    ++
    +   return rc;
    + }
    ++#endif /* SQLITE_ENABLE_SNAPSHOT */
    + 
    + /*
    + ** Begin a read transaction on the database.
    +@@ -52650,6 +58317,14 @@ SQLITE_PRIVATE int sqlite3WalBeginReadTransaction(Wal *pWal, int *pChanged){
    +   int rc;                         /* Return code */
    +   int cnt = 0;                    /* Number of TryBeginRead attempts */
    + 
    ++#ifdef SQLITE_ENABLE_SNAPSHOT
    ++  int bChanged = 0;
    ++  WalIndexHdr *pSnapshot = pWal->pSnapshot;
    ++  if( pSnapshot && memcmp(pSnapshot, &pWal->hdr, sizeof(WalIndexHdr))!=0 ){
    ++    bChanged = 1;
    ++  }
    ++#endif
    ++
    +   do{
    +     rc = walTryBeginRead(pWal, pChanged, 0, ++cnt);
    +   }while( rc==WAL_RETRY );
    +@@ -52657,6 +58332,70 @@ SQLITE_PRIVATE int sqlite3WalBeginReadTransaction(Wal *pWal, int *pChanged){
    +   testcase( (rc&0xff)==SQLITE_IOERR );
    +   testcase( rc==SQLITE_PROTOCOL );
    +   testcase( rc==SQLITE_OK );
    ++
    ++#ifdef SQLITE_ENABLE_SNAPSHOT
    ++  if( rc==SQLITE_OK ){
    ++    if( pSnapshot && memcmp(pSnapshot, &pWal->hdr, sizeof(WalIndexHdr))!=0 ){
    ++      /* At this point the client has a lock on an aReadMark[] slot holding
    ++      ** a value equal to or smaller than pSnapshot->mxFrame, but pWal->hdr
    ++      ** is populated with the wal-index header corresponding to the head
    ++      ** of the wal file. Verify that pSnapshot is still valid before
    ++      ** continuing.  Reasons why pSnapshot might no longer be valid:
    ++      **
    ++      **    (1)  The WAL file has been reset since the snapshot was taken.
    ++      **         In this case, the salt will have changed.
    ++      **
    ++      **    (2)  A checkpoint as been attempted that wrote frames past
    ++      **         pSnapshot->mxFrame into the database file.  Note that the
    ++      **         checkpoint need not have completed for this to cause problems.
    ++      */
    ++      volatile WalCkptInfo *pInfo = walCkptInfo(pWal);
    ++
    ++      assert( pWal->readLock>0 || pWal->hdr.mxFrame==0 );
    ++      assert( pInfo->aReadMark[pWal->readLock]<=pSnapshot->mxFrame );
    ++
    ++      /* It is possible that there is a checkpointer thread running 
    ++      ** concurrent with this code. If this is the case, it may be that the
    ++      ** checkpointer has already determined that it will checkpoint 
    ++      ** snapshot X, where X is later in the wal file than pSnapshot, but 
    ++      ** has not yet set the pInfo->nBackfillAttempted variable to indicate 
    ++      ** its intent. To avoid the race condition this leads to, ensure that
    ++      ** there is no checkpointer process by taking a shared CKPT lock 
    ++      ** before checking pInfo->nBackfillAttempted.  
    ++      **
    ++      ** TODO: Does the aReadMark[] lock prevent a checkpointer from doing
    ++      **       this already?
    ++      */
    ++      rc = walLockShared(pWal, WAL_CKPT_LOCK);
    ++
    ++      if( rc==SQLITE_OK ){
    ++        /* Check that the wal file has not been wrapped. Assuming that it has
    ++        ** not, also check that no checkpointer has attempted to checkpoint any
    ++        ** frames beyond pSnapshot->mxFrame. If either of these conditions are
    ++        ** true, return SQLITE_BUSY_SNAPSHOT. Otherwise, overwrite pWal->hdr
    ++        ** with *pSnapshot and set *pChanged as appropriate for opening the
    ++        ** snapshot.  */
    ++        if( !memcmp(pSnapshot->aSalt, pWal->hdr.aSalt, sizeof(pWal->hdr.aSalt))
    ++         && pSnapshot->mxFrame>=pInfo->nBackfillAttempted
    ++        ){
    ++          assert( pWal->readLock>0 );
    ++          memcpy(&pWal->hdr, pSnapshot, sizeof(WalIndexHdr));
    ++          *pChanged = bChanged;
    ++        }else{
    ++          rc = SQLITE_BUSY_SNAPSHOT;
    ++        }
    ++
    ++        /* Release the shared CKPT lock obtained above. */
    ++        walUnlockShared(pWal, WAL_CKPT_LOCK);
    ++      }
    ++
    ++
    ++      if( rc!=SQLITE_OK ){
    ++        sqlite3WalEndReadTransaction(pWal);
    ++      }
    ++    }
    ++  }
    ++#endif
    +   return rc;
    + }
    + 
    +@@ -52699,7 +58438,7 @@ SQLITE_PRIVATE int sqlite3WalFindFrame(
    +   ** then the WAL is ignored by the reader so return early, as if the 
    +   ** WAL were empty.
    +   */
    +-  if( iLast==0 || pWal->readLock==0 ){
    ++  if( iLast==0 || (pWal->readLock==0 && pWal->bShmUnreliable==0) ){
    +     *piRead = 0;
    +     return SQLITE_OK;
    +   }
    +@@ -52762,8 +58501,8 @@ SQLITE_PRIVATE int sqlite3WalFindFrame(
    +   {
    +     u32 iRead2 = 0;
    +     u32 iTest;
    +-    assert( pWal->minFrame>0 );
    +-    for(iTest=iLast; iTest>=pWal->minFrame; iTest--){
    ++    assert( pWal->bShmUnreliable || pWal->minFrame>0 );
    ++    for(iTest=iLast; iTest>=pWal->minFrame && iTest>0; iTest--){
    +       if( walFramePgno(pWal, iTest)==pgno ){
    +         iRead2 = iTest;
    +         break;
    +@@ -52829,6 +58568,7 @@ SQLITE_PRIVATE int sqlite3WalBeginWriteTransaction(Wal *pWal){
    +   /* Cannot start a write transaction without first holding a read
    +   ** transaction. */
    +   assert( pWal->readLock>=0 );
    ++  assert( pWal->writeLock==0 && pWal->iReCksum==0 );
    + 
    +   if( pWal->readOnly ){
    +     return SQLITE_READONLY;
    +@@ -52837,7 +58577,7 @@ SQLITE_PRIVATE int sqlite3WalBeginWriteTransaction(Wal *pWal){
    +   /* Only one writer allowed at a time.  Get the write lock.  Return
    +   ** SQLITE_BUSY if unable.
    +   */
    +-  rc = walLockExclusive(pWal, WAL_WRITE_LOCK, 1, 0);
    ++  rc = walLockExclusive(pWal, WAL_WRITE_LOCK, 1);
    +   if( rc ){
    +     return rc;
    +   }
    +@@ -52864,6 +58604,7 @@ SQLITE_PRIVATE int sqlite3WalEndWriteTransaction(Wal *pWal){
    +   if( pWal->writeLock ){
    +     walUnlockExclusive(pWal, WAL_WRITE_LOCK, 1);
    +     pWal->writeLock = 0;
    ++    pWal->iReCksum = 0;
    +     pWal->truncateOnCommit = 0;
    +   }
    +   return SQLITE_OK;
    +@@ -52982,7 +58723,7 @@ static int walRestartLog(Wal *pWal){
    +     if( pInfo->nBackfill>0 ){
    +       u32 salt1;
    +       sqlite3_randomness(4, &salt1);
    +-      rc = walLockExclusive(pWal, WAL_READ_LOCK(1), WAL_NREADER-1, 0);
    ++      rc = walLockExclusive(pWal, WAL_READ_LOCK(1), WAL_NREADER-1);
    +       if( rc==SQLITE_OK ){
    +         /* If all readers are using WAL_READ_LOCK(0) (in other words if no
    +         ** readers are currently using the WAL), then the transactions
    +@@ -53049,8 +58790,8 @@ static int walWriteToLog(
    +     iOffset += iFirstAmt;
    +     iAmt -= iFirstAmt;
    +     pContent = (void*)(iFirstAmt + (char*)pContent);
    +-    assert( p->syncFlags & (SQLITE_SYNC_NORMAL|SQLITE_SYNC_FULL) );
    +-    rc = sqlite3OsSync(p->pFd, p->syncFlags & SQLITE_SYNC_MASK);
    ++    assert( WAL_SYNC_FLAGS(p->syncFlags)!=0 );
    ++    rc = sqlite3OsSync(p->pFd, WAL_SYNC_FLAGS(p->syncFlags));
    +     if( iAmt==0 || rc ) return rc;
    +   }
    +   rc = sqlite3OsWrite(p->pFd, pContent, iAmt, iOffset);
    +@@ -53070,7 +58811,7 @@ static int walWriteOneFrame(
    +   void *pData;                    /* Data actually written */
    +   u8 aFrame[WAL_FRAME_HDRSIZE];   /* Buffer to assemble frame-header in */
    + #if defined(SQLITE_HAS_CODEC)
    +-  if( (pData = sqlite3PagerCodec(pPage))==0 ) return SQLITE_NOMEM;
    ++  if( (pData = sqlite3PagerCodec(pPage))==0 ) return SQLITE_NOMEM_BKPT;
    + #else
    +   pData = pPage->pData;
    + #endif
    +@@ -53082,6 +58823,59 @@ static int walWriteOneFrame(
    +   return rc;
    + }
    + 
    ++/*
    ++** This function is called as part of committing a transaction within which
    ++** one or more frames have been overwritten. It updates the checksums for
    ++** all frames written to the wal file by the current transaction starting
    ++** with the earliest to have been overwritten.
    ++**
    ++** SQLITE_OK is returned if successful, or an SQLite error code otherwise.
    ++*/
    ++static int walRewriteChecksums(Wal *pWal, u32 iLast){
    ++  const int szPage = pWal->szPage;/* Database page size */
    ++  int rc = SQLITE_OK;             /* Return code */
    ++  u8 *aBuf;                       /* Buffer to load data from wal file into */
    ++  u8 aFrame[WAL_FRAME_HDRSIZE];   /* Buffer to assemble frame-headers in */
    ++  u32 iRead;                      /* Next frame to read from wal file */
    ++  i64 iCksumOff;
    ++
    ++  aBuf = sqlite3_malloc(szPage + WAL_FRAME_HDRSIZE);
    ++  if( aBuf==0 ) return SQLITE_NOMEM_BKPT;
    ++
    ++  /* Find the checksum values to use as input for the recalculating the
    ++  ** first checksum. If the first frame is frame 1 (implying that the current
    ++  ** transaction restarted the wal file), these values must be read from the
    ++  ** wal-file header. Otherwise, read them from the frame header of the
    ++  ** previous frame.  */
    ++  assert( pWal->iReCksum>0 );
    ++  if( pWal->iReCksum==1 ){
    ++    iCksumOff = 24;
    ++  }else{
    ++    iCksumOff = walFrameOffset(pWal->iReCksum-1, szPage) + 16;
    ++  }
    ++  rc = sqlite3OsRead(pWal->pWalFd, aBuf, sizeof(u32)*2, iCksumOff);
    ++  pWal->hdr.aFrameCksum[0] = sqlite3Get4byte(aBuf);
    ++  pWal->hdr.aFrameCksum[1] = sqlite3Get4byte(&aBuf[sizeof(u32)]);
    ++
    ++  iRead = pWal->iReCksum;
    ++  pWal->iReCksum = 0;
    ++  for(; rc==SQLITE_OK && iRead<=iLast; iRead++){
    ++    i64 iOff = walFrameOffset(iRead, szPage);
    ++    rc = sqlite3OsRead(pWal->pWalFd, aBuf, szPage+WAL_FRAME_HDRSIZE, iOff);
    ++    if( rc==SQLITE_OK ){
    ++      u32 iPgno, nDbSize;
    ++      iPgno = sqlite3Get4byte(aBuf);
    ++      nDbSize = sqlite3Get4byte(&aBuf[4]);
    ++
    ++      walEncodeFrame(pWal, iPgno, nDbSize, &aBuf[WAL_FRAME_HDRSIZE], aFrame);
    ++      rc = sqlite3OsWrite(pWal->pWalFd, aFrame, sizeof(aFrame), iOff);
    ++    }
    ++  }
    ++
    ++  sqlite3_free(aBuf);
    ++  return rc;
    ++}
    ++
    + /* 
    + ** Write a set of frames to the log. The caller must hold the write-lock
    + ** on the log file (obtained using sqlite3WalBeginWriteTransaction()).
    +@@ -53102,6 +58896,8 @@ SQLITE_PRIVATE int sqlite3WalFrames(
    +   int szFrame;                    /* The size of a single frame */
    +   i64 iOffset;                    /* Next byte to write in WAL file */
    +   WalWriter w;                    /* The writer */
    ++  u32 iFirst = 0;                 /* First frame that may be overwritten */
    ++  WalIndexHdr *pLive;             /* Pointer to shared header */
    + 
    +   assert( pList );
    +   assert( pWal->writeLock );
    +@@ -53117,6 +58913,11 @@ SQLITE_PRIVATE int sqlite3WalFrames(
    +   }
    + #endif
    + 
    ++  pLive = (WalIndexHdr*)walIndexHdr(pWal);
    ++  if( memcmp(&pWal->hdr, (void *)pLive, sizeof(WalIndexHdr))!=0 ){
    ++    iFirst = pLive->mxFrame+1;
    ++  }
    ++
    +   /* See if it is possible to write these frames into the start of the
    +   ** log file, instead of appending to it at pWal->hdr.mxFrame.
    +   */
    +@@ -53160,10 +58961,10 @@ SQLITE_PRIVATE int sqlite3WalFrames(
    +     ** an out-of-order write following a WAL restart could result in
    +     ** database corruption.  See the ticket:
    +     **
    +-    **     http://localhost:591/sqlite/info/ff5be73dee
    ++    **     https://sqlite.org/src/info/ff5be73dee
    +     */
    +-    if( pWal->syncHeader && sync_flags ){
    +-      rc = sqlite3OsSync(pWal->pWalFd, sync_flags & SQLITE_SYNC_MASK);
    ++    if( pWal->syncHeader ){
    ++      rc = sqlite3OsSync(pWal->pWalFd, CKPT_SYNC_FLAGS(sync_flags));
    +       if( rc ) return rc;
    +     }
    +   }
    +@@ -53181,6 +58982,33 @@ SQLITE_PRIVATE int sqlite3WalFrames(
    +   /* Write all frames into the log file exactly once */
    +   for(p=pList; p; p=p->pDirty){
    +     int nDbSize;   /* 0 normally.  Positive == commit flag */
    ++
    ++    /* Check if this page has already been written into the wal file by
    ++    ** the current transaction. If so, overwrite the existing frame and
    ++    ** set Wal.writeLock to WAL_WRITELOCK_RECKSUM - indicating that 
    ++    ** checksums must be recomputed when the transaction is committed.  */
    ++    if( iFirst && (p->pDirty || isCommit==0) ){
    ++      u32 iWrite = 0;
    ++      VVA_ONLY(rc =) sqlite3WalFindFrame(pWal, p->pgno, &iWrite);
    ++      assert( rc==SQLITE_OK || iWrite==0 );
    ++      if( iWrite>=iFirst ){
    ++        i64 iOff = walFrameOffset(iWrite, szPage) + WAL_FRAME_HDRSIZE;
    ++        void *pData;
    ++        if( pWal->iReCksum==0 || iWrite<pWal->iReCksum ){
    ++          pWal->iReCksum = iWrite;
    ++        }
    ++#if defined(SQLITE_HAS_CODEC)
    ++        if( (pData = sqlite3PagerCodec(p))==0 ) return SQLITE_NOMEM;
    ++#else
    ++        pData = p->pData;
    ++#endif
    ++        rc = sqlite3OsWrite(pWal->pWalFd, pData, szPage, iOff);
    ++        if( rc ) return rc;
    ++        p->flags &= ~PGHDR_WAL_APPEND;
    ++        continue;
    ++      }
    ++    }
    ++
    +     iFrame++;
    +     assert( iOffset==walFrameOffset(iFrame, szPage) );
    +     nDbSize = (isCommit && p->pDirty==0) ? nTruncate : 0;
    +@@ -53188,6 +59016,13 @@ SQLITE_PRIVATE int sqlite3WalFrames(
    +     if( rc ) return rc;
    +     pLast = p;
    +     iOffset += szFrame;
    ++    p->flags |= PGHDR_WAL_APPEND;
    ++  }
    ++
    ++  /* Recalculate checksums within the wal file if required. */
    ++  if( isCommit && pWal->iReCksum ){
    ++    rc = walRewriteChecksums(pWal, iFrame);
    ++    if( rc ) return rc;
    +   }
    + 
    +   /* If this is the end of a transaction, then we might need to pad
    +@@ -53204,18 +59039,23 @@ SQLITE_PRIVATE int sqlite3WalFrames(
    +   ** sector boundary is synced; the part of the last frame that extends
    +   ** past the sector boundary is written after the sync.
    +   */
    +-  if( isCommit && (sync_flags & WAL_SYNC_TRANSACTIONS)!=0 ){
    ++  if( isCommit && WAL_SYNC_FLAGS(sync_flags)!=0 ){
    ++    int bSync = 1;
    +     if( pWal->padToSectorBoundary ){
    +       int sectorSize = sqlite3SectorSize(pWal->pWalFd);
    +       w.iSyncPoint = ((iOffset+sectorSize-1)/sectorSize)*sectorSize;
    ++      bSync = (w.iSyncPoint==iOffset);
    ++      testcase( bSync );
    +       while( iOffset<w.iSyncPoint ){
    +         rc = walWriteOneFrame(&w, pLast, nTruncate, iOffset);
    +         if( rc ) return rc;
    +         iOffset += szFrame;
    +         nExtra++;
    +       }
    +-    }else{
    +-      rc = sqlite3OsSync(w.pFd, sync_flags & SQLITE_SYNC_MASK);
    ++    }
    ++    if( bSync ){
    ++      assert( rc==SQLITE_OK );
    ++      rc = sqlite3OsSync(w.pFd, WAL_SYNC_FLAGS(sync_flags));
    +     }
    +   }
    + 
    +@@ -53239,6 +59079,7 @@ SQLITE_PRIVATE int sqlite3WalFrames(
    +   */
    +   iFrame = pWal->hdr.mxFrame;
    +   for(p=pList; p && rc==SQLITE_OK; p=p->pDirty){
    ++    if( (p->flags & PGHDR_WAL_APPEND)==0 ) continue;
    +     iFrame++;
    +     rc = walIndexAppend(pWal, iFrame, p->pgno);
    +   }
    +@@ -53281,6 +59122,7 @@ SQLITE_PRIVATE int sqlite3WalFrames(
    + */
    + SQLITE_PRIVATE int sqlite3WalCheckpoint(
    +   Wal *pWal,                      /* Wal connection */
    ++  sqlite3 *db,                    /* Check this handle's interrupt flag */
    +   int eMode,                      /* PASSIVE, FULL, RESTART, or TRUNCATE */
    +   int (*xBusy)(void*),            /* Function to call when busy */
    +   void *pBusyArg,                 /* Context argument for xBusyHandler */
    +@@ -53307,7 +59149,7 @@ SQLITE_PRIVATE int sqlite3WalCheckpoint(
    + 
    +   /* IMPLEMENTATION-OF: R-62028-47212 All calls obtain an exclusive 
    +   ** "checkpoint" lock on the database file. */
    +-  rc = walLockExclusive(pWal, WAL_CKPT_LOCK, 1, 0);
    ++  rc = walLockExclusive(pWal, WAL_CKPT_LOCK, 1);
    +   if( rc ){
    +     /* EVIDENCE-OF: R-10421-19736 If any other process is running a
    +     ** checkpoint operation at the same time, the lock cannot be obtained and
    +@@ -53351,10 +59193,11 @@ SQLITE_PRIVATE int sqlite3WalCheckpoint(
    + 
    +   /* Copy data from the log to the database file. */
    +   if( rc==SQLITE_OK ){
    ++
    +     if( pWal->hdr.mxFrame && walPagesize(pWal)!=nBuf ){
    +       rc = SQLITE_CORRUPT_BKPT;
    +     }else{
    +-      rc = walCheckpoint(pWal, eMode2, xBusy2, pBusyArg, sync_flags, zBuf);
    ++      rc = walCheckpoint(pWal, db, eMode2, xBusy2, pBusyArg, sync_flags, zBuf);
    +     }
    + 
    +     /* If no error occurred, set the output variables. */
    +@@ -53435,24 +59278,24 @@ SQLITE_PRIVATE int sqlite3WalExclusiveMode(Wal *pWal, int op){
    +   assert( pWal->readLock>=0 || (op<=0 && pWal->exclusiveMode==0) );
    + 
    +   if( op==0 ){
    +-    if( pWal->exclusiveMode ){
    +-      pWal->exclusiveMode = 0;
    ++    if( pWal->exclusiveMode!=WAL_NORMAL_MODE ){
    ++      pWal->exclusiveMode = WAL_NORMAL_MODE;
    +       if( walLockShared(pWal, WAL_READ_LOCK(pWal->readLock))!=SQLITE_OK ){
    +-        pWal->exclusiveMode = 1;
    ++        pWal->exclusiveMode = WAL_EXCLUSIVE_MODE;
    +       }
    +-      rc = pWal->exclusiveMode==0;
    ++      rc = pWal->exclusiveMode==WAL_NORMAL_MODE;
    +     }else{
    +       /* Already in locking_mode=NORMAL */
    +       rc = 0;
    +     }
    +   }else if( op>0 ){
    +-    assert( pWal->exclusiveMode==0 );
    ++    assert( pWal->exclusiveMode==WAL_NORMAL_MODE );
    +     assert( pWal->readLock>=0 );
    +     walUnlockShared(pWal, WAL_READ_LOCK(pWal->readLock));
    +-    pWal->exclusiveMode = 1;
    ++    pWal->exclusiveMode = WAL_EXCLUSIVE_MODE;
    +     rc = 1;
    +   }else{
    +-    rc = pWal->exclusiveMode==0;
    ++    rc = pWal->exclusiveMode==WAL_NORMAL_MODE;
    +   }
    +   return rc;
    + }
    +@@ -53466,6 +59309,57 @@ SQLITE_PRIVATE int sqlite3WalHeapMemory(Wal *pWal){
    +   return (pWal && pWal->exclusiveMode==WAL_HEAPMEMORY_MODE );
    + }
    + 
    ++#ifdef SQLITE_ENABLE_SNAPSHOT
    ++/* Create a snapshot object.  The content of a snapshot is opaque to
    ++** every other subsystem, so the WAL module can put whatever it needs
    ++** in the object.
    ++*/
    ++SQLITE_PRIVATE int sqlite3WalSnapshotGet(Wal *pWal, sqlite3_snapshot **ppSnapshot){
    ++  int rc = SQLITE_OK;
    ++  WalIndexHdr *pRet;
    ++  static const u32 aZero[4] = { 0, 0, 0, 0 };
    ++
    ++  assert( pWal->readLock>=0 && pWal->writeLock==0 );
    ++
    ++  if( memcmp(&pWal->hdr.aFrameCksum[0],aZero,16)==0 ){
    ++    *ppSnapshot = 0;
    ++    return SQLITE_ERROR;
    ++  }
    ++  pRet = (WalIndexHdr*)sqlite3_malloc(sizeof(WalIndexHdr));
    ++  if( pRet==0 ){
    ++    rc = SQLITE_NOMEM_BKPT;
    ++  }else{
    ++    memcpy(pRet, &pWal->hdr, sizeof(WalIndexHdr));
    ++    *ppSnapshot = (sqlite3_snapshot*)pRet;
    ++  }
    ++
    ++  return rc;
    ++}
    ++
    ++/* Try to open on pSnapshot when the next read-transaction starts
    ++*/
    ++SQLITE_PRIVATE void sqlite3WalSnapshotOpen(Wal *pWal, sqlite3_snapshot *pSnapshot){
    ++  pWal->pSnapshot = (WalIndexHdr*)pSnapshot;
    ++}
    ++
    ++/* 
    ++** Return a +ve value if snapshot p1 is newer than p2. A -ve value if
    ++** p1 is older than p2 and zero if p1 and p2 are the same snapshot.
    ++*/
    ++SQLITE_API int sqlite3_snapshot_cmp(sqlite3_snapshot *p1, sqlite3_snapshot *p2){
    ++  WalIndexHdr *pHdr1 = (WalIndexHdr*)p1;
    ++  WalIndexHdr *pHdr2 = (WalIndexHdr*)p2;
    ++
    ++  /* aSalt[0] is a copy of the value stored in the wal file header. It
    ++  ** is incremented each time the wal file is restarted.  */
    ++  if( pHdr1->aSalt[0]<pHdr2->aSalt[0] ) return -1;
    ++  if( pHdr1->aSalt[0]>pHdr2->aSalt[0] ) return +1;
    ++  if( pHdr1->mxFrame<pHdr2->mxFrame ) return -1;
    ++  if( pHdr1->mxFrame>pHdr2->mxFrame ) return +1;
    ++  return 0;
    ++}
    ++#endif /* SQLITE_ENABLE_SNAPSHOT */
    ++
    + #ifdef SQLITE_ENABLE_ZIPVFS
    + /*
    + ** If the argument is not NULL, it points to a Wal object that holds a
    +@@ -53478,6 +59372,12 @@ SQLITE_PRIVATE int sqlite3WalFramesize(Wal *pWal){
    + }
    + #endif
    + 
    ++/* Return the sqlite3_file object for the WAL file
    ++*/
    ++SQLITE_PRIVATE sqlite3_file *sqlite3WalFile(Wal *pWal){
    ++  return pWal->pWalFd;
    ++}
    ++
    + #endif /* #ifndef SQLITE_OMIT_WAL */
    + 
    + /************** End of wal.c *************************************************/
    +@@ -53762,38 +59662,39 @@ typedef struct CellInfo CellInfo;
    + #define PTF_LEAF      0x08
    + 
    + /*
    +-** As each page of the file is loaded into memory, an instance of the following
    +-** structure is appended and initialized to zero.  This structure stores
    +-** information about the page that is decoded from the raw file page.
    ++** An instance of this object stores information about each a single database
    ++** page that has been loaded into memory.  The information in this object
    ++** is derived from the raw on-disk page content.
    + **
    +-** The pParent field points back to the parent page.  This allows us to
    +-** walk up the BTree from any leaf to the root.  Care must be taken to
    +-** unref() the parent page pointer when this page is no longer referenced.
    +-** The pageDestructor() routine handles that chore.
    ++** As each database page is loaded into memory, the pager allocats an
    ++** instance of this object and zeros the first 8 bytes.  (This is the
    ++** "extra" information associated with each page of the pager.)
    + **
    + ** Access to all fields of this structure is controlled by the mutex
    + ** stored in MemPage.pBt->mutex.
    + */
    + struct MemPage {
    +   u8 isInit;           /* True if previously initialized. MUST BE FIRST! */
    +-  u8 nOverflow;        /* Number of overflow cell bodies in aCell[] */
    ++  u8 bBusy;            /* Prevent endless loops on corrupt database files */
    +   u8 intKey;           /* True if table b-trees.  False for index b-trees */
    +   u8 intKeyLeaf;       /* True if the leaf of an intKey table */
    +-  u8 noPayload;        /* True if internal intKey page (thus w/o data) */
    ++  Pgno pgno;           /* Page number for this page */
    ++  /* Only the first 8 bytes (above) are zeroed by pager.c when a new page
    ++  ** is allocated. All fields that follow must be initialized before use */
    +   u8 leaf;             /* True if a leaf page */
    +   u8 hdrOffset;        /* 100 for page 1.  0 otherwise */
    +   u8 childPtrSize;     /* 0 if leaf==1.  4 if leaf==0 */
    +   u8 max1bytePayload;  /* min(maxLocal,127) */
    +-  u8 bBusy;            /* Prevent endless loops on corrupt database files */
    ++  u8 nOverflow;        /* Number of overflow cell bodies in aCell[] */
    +   u16 maxLocal;        /* Copy of BtShared.maxLocal or BtShared.maxLeaf */
    +   u16 minLocal;        /* Copy of BtShared.minLocal or BtShared.minLeaf */
    +   u16 cellOffset;      /* Index in aData of first cell pointer */
    +   u16 nFree;           /* Number of free bytes on the page */
    +   u16 nCell;           /* Number of cells on this page, local and ovfl */
    +   u16 maskPage;        /* Mask for page offset */
    +-  u16 aiOvfl[5];       /* Insert the i-th overflow cell before the aiOvfl-th
    ++  u16 aiOvfl[4];       /* Insert the i-th overflow cell before the aiOvfl-th
    +                        ** non-overflow cell */
    +-  u8 *apOvfl[5];       /* Pointers to the body of overflow cells */
    ++  u8 *apOvfl[4];       /* Pointers to the body of overflow cells */
    +   BtShared *pBt;       /* Pointer to BtShared that this page is part of */
    +   u8 *aData;           /* Pointer to disk image of the page data */
    +   u8 *aDataEnd;        /* One byte past the end of usable data */
    +@@ -53802,16 +59703,8 @@ struct MemPage {
    +   DbPage *pDbPage;     /* Pager page handle */
    +   u16 (*xCellSize)(MemPage*,u8*);             /* cellSizePtr method */
    +   void (*xParseCell)(MemPage*,u8*,CellInfo*); /* btreeParseCell method */
    +-  Pgno pgno;           /* Page number for this page */
    + };
    + 
    +-/*
    +-** The in-memory image of a disk page has the auxiliary information appended
    +-** to the end.  EXTRA_SIZE is the number of bytes of space needed to hold
    +-** that extra information.
    +-*/
    +-#define EXTRA_SIZE sizeof(MemPage)
    +-
    + /*
    + ** A linked list of the following structures is stored at BtShared.pLock.
    + ** Locks are added (or upgraded from READ_LOCK to WRITE_LOCK) when a cursor 
    +@@ -53958,10 +59851,12 @@ struct BtShared {
    + #define BTS_READ_ONLY        0x0001   /* Underlying file is readonly */
    + #define BTS_PAGESIZE_FIXED   0x0002   /* Page size can no longer be changed */
    + #define BTS_SECURE_DELETE    0x0004   /* PRAGMA secure_delete is enabled */
    +-#define BTS_INITIALLY_EMPTY  0x0008   /* Database was empty at trans start */
    +-#define BTS_NO_WAL           0x0010   /* Do not open write-ahead-log files */
    +-#define BTS_EXCLUSIVE        0x0020   /* pWriter has an exclusive lock */
    +-#define BTS_PENDING          0x0040   /* Waiting for read-locks to clear */
    ++#define BTS_OVERWRITE        0x0008   /* Overwrite deleted content with zeros */
    ++#define BTS_FAST_SECURE      0x000c   /* Combination of the previous two */
    ++#define BTS_INITIALLY_EMPTY  0x0010   /* Database was empty at trans start */
    ++#define BTS_NO_WAL           0x0020   /* Do not open write-ahead-log files */
    ++#define BTS_EXCLUSIVE        0x0040   /* pWriter has an exclusive lock */
    ++#define BTS_PENDING          0x0080   /* Waiting for read-locks to clear */
    + 
    + /*
    + ** An instance of the following structure is used to hold information
    +@@ -53973,7 +59868,6 @@ struct CellInfo {
    +   u8 *pPayload;  /* Pointer to the start of payload */
    +   u32 nPayload;  /* Bytes of payload */
    +   u16 nLocal;    /* Amount of payload held locally, not on overflow */
    +-  u16 iOverflow; /* Offset to overflow page number.  Zero if no overflow */
    +   u16 nSize;     /* Size of the cell content on the main b-tree page */
    + };
    + 
    +@@ -54008,6 +59902,11 @@ struct CellInfo {
    + **    eState==FAULT:                   Cursor fault with skipNext as error code.
    + */
    + struct BtCursor {
    ++  u8 eState;                /* One of the CURSOR_XXX constants (see below) */
    ++  u8 curFlags;              /* zero or more BTCF_* flags defined below */
    ++  u8 curPagerFlags;         /* Flags to send to sqlite3PagerGet() */
    ++  u8 hints;                 /* As configured by CursorSetHints() */
    ++  int nOvflAlloc;           /* Allocated size of aOverflow[] array */
    +   Btree *pBtree;            /* The Btree to which this cursor belongs */
    +   BtShared *pBt;            /* The BtShared this cursor points to */
    +   BtCursor *pNext;          /* Forms a linked list of all cursors */
    +@@ -54016,22 +59915,18 @@ struct BtCursor {
    +   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.
    +                    ** Error code if eState==CURSOR_FAULT */
    +-  u8 curFlags;              /* zero or more BTCF_* flags defined below */
    +-  u8 curPagerFlags;         /* Flags to send to sqlite3PagerAcquire() */
    +-  u8 eState;                /* One of the CURSOR_XXX constants (see below) */
    +-  u8 hints;                 /* As configured by CursorSetHints() */
    +   /* All fields above are zeroed when the cursor is allocated.  See
    +   ** sqlite3BtreeCursorZero().  Fields that follow must be manually
    +   ** initialized. */
    +   i8 iPage;                 /* Index of current page in apPage */
    +   u8 curIntKey;             /* Value of apPage[0]->intKey */
    +-  struct KeyInfo *pKeyInfo; /* Argument passed to comparison function */
    +-  void *padding1;           /* Make object size a multiple of 16 */
    +-  u16 aiIdx[BTCURSOR_MAX_DEPTH];        /* Current index in apPage[i] */
    +-  MemPage *apPage[BTCURSOR_MAX_DEPTH];  /* Pages from root to current page */
    ++  u16 ix;                   /* Current index for apPage[iPage] */
    ++  u16 aiIdx[BTCURSOR_MAX_DEPTH-1];     /* Current index in apPage[i] */
    ++  struct KeyInfo *pKeyInfo;            /* Arg passed to comparison function */
    ++  MemPage *pPage;                        /* Current page */
    ++  MemPage *apPage[BTCURSOR_MAX_DEPTH-1]; /* Stack of parents of current page */
    + };
    + 
    + /*
    +@@ -54203,11 +60098,9 @@ struct IntegrityCk {
    + */
    + #if SQLITE_BYTEORDER==4321
    + # define get2byteAligned(x)  (*(u16*)(x))
    +-#elif SQLITE_BYTEORDER==1234 && !defined(SQLITE_DISABLE_INTRINSIC) \
    +-    && GCC_VERSION>=4008000
    ++#elif SQLITE_BYTEORDER==1234 && GCC_VERSION>=4008000
    + # define get2byteAligned(x)  __builtin_bswap16(*(u16*)(x))
    +-#elif SQLITE_BYTEORDER==1234 && !defined(SQLITE_DISABLE_INTRINSIC) \
    +-    && defined(_MSC_VER) && _MSC_VER>=1300
    ++#elif SQLITE_BYTEORDER==1234 && MSVC_VERSION>=1300
    + # define get2byteAligned(x)  _byteswap_ushort(*(u16*)(x))
    + #else
    + # define get2byteAligned(x)  ((x)[0]<<8 | (x)[1])
    +@@ -54368,21 +60261,6 @@ SQLITE_PRIVATE int sqlite3BtreeHoldsMutex(Btree *p){
    + #endif
    + 
    + 
    +-#ifndef SQLITE_OMIT_INCRBLOB
    +-/*
    +-** Enter and leave a mutex on a Btree given a cursor owned by that
    +-** Btree.  These entry points are used by incremental I/O and can be
    +-** omitted if that module is not used.
    +-*/
    +-SQLITE_PRIVATE void sqlite3BtreeEnterCursor(BtCursor *pCur){
    +-  sqlite3BtreeEnter(pCur->pBtree);
    +-}
    +-SQLITE_PRIVATE void sqlite3BtreeLeaveCursor(BtCursor *pCur){
    +-  sqlite3BtreeLeave(pCur->pBtree);
    +-}
    +-#endif /* SQLITE_OMIT_INCRBLOB */
    +-
    +-
    + /*
    + ** Enter the mutex on every Btree associated with a database
    + ** connection.  This is needed (for example) prior to parsing
    +@@ -54397,16 +60275,24 @@ SQLITE_PRIVATE void sqlite3BtreeLeaveCursor(BtCursor *pCur){
    + ** two or more btrees in common both try to lock all their btrees
    + ** at the same instant.
    + */
    +-SQLITE_PRIVATE void sqlite3BtreeEnterAll(sqlite3 *db){
    ++static void SQLITE_NOINLINE btreeEnterAll(sqlite3 *db){
    +   int i;
    ++  int skipOk = 1;
    +   Btree *p;
    +   assert( sqlite3_mutex_held(db->mutex) );
    +   for(i=0; i<db->nDb; i++){
    +     p = db->aDb[i].pBt;
    +-    if( p ) sqlite3BtreeEnter(p);
    ++    if( p && p->sharable ){
    ++      sqlite3BtreeEnter(p);
    ++      skipOk = 0;
    ++    }
    +   }
    ++  db->skipBtreeMutex = skipOk;
    + }
    +-SQLITE_PRIVATE void sqlite3BtreeLeaveAll(sqlite3 *db){
    ++SQLITE_PRIVATE void sqlite3BtreeEnterAll(sqlite3 *db){
    ++  if( db->skipBtreeMutex==0 ) btreeEnterAll(db);
    ++}
    ++static void SQLITE_NOINLINE btreeLeaveAll(sqlite3 *db){
    +   int i;
    +   Btree *p;
    +   assert( sqlite3_mutex_held(db->mutex) );
    +@@ -54415,13 +60301,8 @@ SQLITE_PRIVATE void sqlite3BtreeLeaveAll(sqlite3 *db){
    +     if( p ) sqlite3BtreeLeave(p);
    +   }
    + }
    +-
    +-/*
    +-** Return true if a particular Btree requires a lock.  Return FALSE if
    +-** no lock is ever required since it is not sharable.
    +-*/
    +-SQLITE_PRIVATE int sqlite3BtreeSharable(Btree *p){
    +-  return p->sharable;
    ++SQLITE_PRIVATE void sqlite3BtreeLeaveAll(sqlite3 *db){
    ++  if( db->skipBtreeMutex==0 ) btreeLeaveAll(db);
    + }
    + 
    + #ifndef NDEBUG
    +@@ -54497,6 +60378,25 @@ SQLITE_PRIVATE void sqlite3BtreeEnterAll(sqlite3 *db){
    +   }
    + }
    + #endif /* if SQLITE_THREADSAFE */
    ++
    ++#ifndef SQLITE_OMIT_INCRBLOB
    ++/*
    ++** Enter a mutex on a Btree given a cursor owned by that Btree. 
    ++**
    ++** These entry points are used by incremental I/O only. Enter() is required 
    ++** any time OMIT_SHARED_CACHE is not defined, regardless of whether or not 
    ++** the build is threadsafe. Leave() is only required by threadsafe builds.
    ++*/
    ++SQLITE_PRIVATE void sqlite3BtreeEnterCursor(BtCursor *pCur){
    ++  sqlite3BtreeEnter(pCur->pBtree);
    ++}
    ++# if SQLITE_THREADSAFE
    ++SQLITE_PRIVATE void sqlite3BtreeLeaveCursor(BtCursor *pCur){
    ++  sqlite3BtreeLeave(pCur->pBtree);
    ++}
    ++# endif
    ++#endif /* ifndef SQLITE_OMIT_INCRBLOB */
    ++
    + #endif /* ifndef SQLITE_OMIT_SHARED_CACHE */
    + 
    + /************** End of btmutex.c *********************************************/
    +@@ -54589,7 +60489,7 @@ static BtShared *SQLITE_WSD sqlite3SharedCacheList = 0;
    + ** The shared cache setting effects only future calls to
    + ** sqlite3_open(), sqlite3_open16(), or sqlite3_open_v2().
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_enable_shared_cache(int enable){
    ++SQLITE_API int sqlite3_enable_shared_cache(int enable){
    +   sqlite3GlobalConfig.sharedCacheEnabled = enable;
    +   return SQLITE_OK;
    + }
    +@@ -54615,6 +60515,34 @@ SQLITE_API int SQLITE_STDCALL sqlite3_enable_shared_cache(int enable){
    +   #define hasReadConflicts(a, b) 0
    + #endif
    + 
    ++/*
    ++** Implementation of the SQLITE_CORRUPT_PAGE() macro. Takes a single
    ++** (MemPage*) as an argument. The (MemPage*) must not be NULL.
    ++**
    ++** If SQLITE_DEBUG is not defined, then this macro is equivalent to
    ++** SQLITE_CORRUPT_BKPT. Or, if SQLITE_DEBUG is set, then the log message
    ++** normally produced as a side-effect of SQLITE_CORRUPT_BKPT is augmented
    ++** with the page number and filename associated with the (MemPage*).
    ++*/
    ++#ifdef SQLITE_DEBUG
    ++int corruptPageError(int lineno, MemPage *p){
    ++  char *zMsg;
    ++  sqlite3BeginBenignMalloc();
    ++  zMsg = sqlite3_mprintf("database corruption page %d of %s",
    ++      (int)p->pgno, sqlite3PagerFilename(p->pBt->pPager, 0)
    ++  );
    ++  sqlite3EndBenignMalloc();
    ++  if( zMsg ){
    ++    sqlite3ReportError(SQLITE_CORRUPT, lineno, zMsg);
    ++  }
    ++  sqlite3_free(zMsg);
    ++  return SQLITE_CORRUPT_BKPT;
    ++}
    ++# define SQLITE_CORRUPT_PAGE(pMemPage) corruptPageError(__LINE__, pMemPage)
    ++#else
    ++# define SQLITE_CORRUPT_PAGE(pMemPage) SQLITE_CORRUPT_PGNO(pMemPage->pgno)
    ++#endif
    ++
    + #ifndef SQLITE_OMIT_SHARED_CACHE
    + 
    + #ifdef SQLITE_DEBUG
    +@@ -54655,7 +60583,7 @@ static int hasSharedCacheTableLock(
    +   ** Return true immediately.
    +   */
    +   if( (pBtree->sharable==0)
    +-   || (eLockType==READ_LOCK && (pBtree->db->flags & SQLITE_ReadUncommitted))
    ++   || (eLockType==READ_LOCK && (pBtree->db->flags & SQLITE_ReadUncommit))
    +   ){
    +     return 1;
    +   }
    +@@ -54732,7 +60660,7 @@ static int hasReadConflicts(Btree *pBtree, Pgno iRoot){
    +   for(p=pBtree->pBt->pCursor; p; p=p->pNext){
    +     if( p->pgnoRoot==iRoot 
    +      && p->pBtree!=pBtree
    +-     && 0==(p->pBtree->db->flags & SQLITE_ReadUncommitted)
    ++     && 0==(p->pBtree->db->flags & SQLITE_ReadUncommit)
    +     ){
    +       return 1;
    +     }
    +@@ -54754,7 +60682,7 @@ static int querySharedCacheTableLock(Btree *p, Pgno iTab, u8 eLock){
    +   assert( sqlite3BtreeHoldsMutex(p) );
    +   assert( eLock==READ_LOCK || eLock==WRITE_LOCK );
    +   assert( p->db!=0 );
    +-  assert( !(p->db->flags&SQLITE_ReadUncommitted)||eLock==WRITE_LOCK||iTab==1 );
    ++  assert( !(p->db->flags&SQLITE_ReadUncommit)||eLock==WRITE_LOCK||iTab==1 );
    +   
    +   /* If requesting a write-lock, then the Btree must have an open write
    +   ** transaction on this file. And, obviously, for this to be so there 
    +@@ -54832,7 +60760,7 @@ static int setSharedCacheTableLock(Btree *p, Pgno iTable, u8 eLock){
    +   ** obtain a read-lock using this function. The only read-lock obtained
    +   ** by a connection in read-uncommitted mode is on the sqlite_master 
    +   ** table, and that lock is obtained in BtreeBeginTrans().  */
    +-  assert( 0==(p->db->flags&SQLITE_ReadUncommitted) || eLock==WRITE_LOCK );
    ++  assert( 0==(p->db->flags&SQLITE_ReadUncommit) || eLock==WRITE_LOCK );
    + 
    +   /* This function should only be called on a sharable b-tree after it 
    +   ** has been determined that no other b-tree holds a conflicting lock.  */
    +@@ -54853,7 +60781,7 @@ static int setSharedCacheTableLock(Btree *p, Pgno iTable, u8 eLock){
    +   if( !pLock ){
    +     pLock = (BtLock *)sqlite3MallocZero(sizeof(BtLock));
    +     if( !pLock ){
    +-      return SQLITE_NOMEM;
    ++      return SQLITE_NOMEM_BKPT;
    +     }
    +     pLock->iTable = iTable;
    +     pLock->pBtree = p;
    +@@ -54942,7 +60870,9 @@ static void downgradeAllSharedCacheTableLocks(Btree *p){
    + 
    + #endif /* SQLITE_OMIT_SHARED_CACHE */
    + 
    +-static void releasePage(MemPage *pPage);  /* Forward reference */
    ++static void releasePage(MemPage *pPage);         /* Forward reference */
    ++static void releasePageOne(MemPage *pPage);      /* Forward reference */
    ++static void releasePageNotNull(MemPage *pPage);  /* Forward reference */
    + 
    + /*
    + ***** This routine is used inside of assert() only ****
    +@@ -54953,6 +60883,19 @@ static void releasePage(MemPage *pPage);  /* Forward reference */
    + static int cursorHoldsMutex(BtCursor *p){
    +   return sqlite3_mutex_held(p->pBt->mutex);
    + }
    ++
    ++/* Verify that the cursor and the BtShared agree about what is the current
    ++** database connetion. This is important in shared-cache mode. If the database 
    ++** connection pointers get out-of-sync, it is possible for routines like
    ++** btreeInitPage() to reference an stale connection pointer that references a
    ++** a connection that has already closed.  This routine is used inside assert()
    ++** statements only and for the purpose of double-checking that the btree code
    ++** does keep the database connection pointers up-to-date.
    ++*/
    ++static int cursorOwnsBtShared(BtCursor *p){
    ++  assert( cursorHoldsMutex(p) );
    ++  return (p->pBtree->db==p->pBt->db);
    ++}
    + #endif
    + 
    + /*
    +@@ -54989,6 +60932,7 @@ static void invalidateAllOverflowCache(BtShared *pBt){
    + */
    + static void invalidateIncrblobCursors(
    +   Btree *pBtree,          /* The database file to check */
    ++  Pgno pgnoRoot,          /* The table that might be changing */
    +   i64 iRow,               /* The rowid that might be changing */
    +   int isClearTable        /* True if all rows are being deleted */
    + ){
    +@@ -54999,7 +60943,7 @@ static void invalidateIncrblobCursors(
    +   for(p=pBtree->pBt->pCursor; p; p=p->pNext){
    +     if( (p->curFlags & BTCF_Incrblob)!=0 ){
    +       pBtree->hasIncrblobCur = 1;
    +-      if( isClearTable || p->info.nKey==iRow ){
    ++      if( p->pgnoRoot==pgnoRoot && (isClearTable || p->info.nKey==iRow) ){
    +         p->eState = CURSOR_INVALID;
    +       }
    +     }
    +@@ -55008,7 +60952,7 @@ static void invalidateIncrblobCursors(
    + 
    + #else
    +   /* Stub function when INCRBLOB is omitted */
    +-  #define invalidateIncrblobCursors(x,y,z)
    ++  #define invalidateIncrblobCursors(w,x,y,z)
    + #endif /* SQLITE_OMIT_INCRBLOB */
    + 
    + /*
    +@@ -55052,7 +60996,7 @@ static int btreeSetHasContent(BtShared *pBt, Pgno pgno){
    +     assert( pgno<=pBt->nPage );
    +     pBt->pHasContent = sqlite3BitvecCreate(pBt->nPage);
    +     if( !pBt->pHasContent ){
    +-      rc = SQLITE_NOMEM;
    ++      rc = SQLITE_NOMEM_BKPT;
    +     }
    +   }
    +   if( rc==SQLITE_OK && pgno<=sqlite3BitvecSize(pBt->pHasContent) ){
    +@@ -55087,11 +61031,13 @@ static void btreeClearHasContent(BtShared *pBt){
    + */
    + static void btreeReleaseAllCursorPages(BtCursor *pCur){
    +   int i;
    +-  for(i=0; i<=pCur->iPage; i++){
    +-    releasePage(pCur->apPage[i]);
    +-    pCur->apPage[i] = 0;
    ++  if( pCur->iPage>=0 ){
    ++    for(i=0; i<pCur->iPage; i++){
    ++      releasePageNotNull(pCur->apPage[i]);
    ++    }
    ++    releasePageNotNull(pCur->pPage);
    ++    pCur->iPage = -1;
    +   }
    +-  pCur->iPage = -1;
    + }
    + 
    + /*
    +@@ -55108,30 +61054,28 @@ static void btreeReleaseAllCursorPages(BtCursor *pCur){
    + ** the key.
    + */
    + static int saveCursorKey(BtCursor *pCur){
    +-  int rc;
    ++  int rc = SQLITE_OK;
    +   assert( CURSOR_VALID==pCur->eState );
    +   assert( 0==pCur->pKey );
    +   assert( cursorHoldsMutex(pCur) );
    + 
    +-  rc = sqlite3BtreeKeySize(pCur, &pCur->nKey);
    +-  assert( rc==SQLITE_OK );  /* KeySize() cannot fail */
    +-
    +-  /* If this is an intKey table, then the above call to BtreeKeySize()
    +-  ** stores the integer key in pCur->nKey. In this case this value is
    +-  ** all that is required. Otherwise, if pCur is not open on an intKey
    +-  ** table, then malloc space for and store the pCur->nKey bytes of key 
    +-  ** data.  */
    +-  if( 0==pCur->curIntKey ){
    +-    void *pKey = sqlite3Malloc( pCur->nKey );
    ++  if( pCur->curIntKey ){
    ++    /* Only the rowid is required for a table btree */
    ++    pCur->nKey = sqlite3BtreeIntegerKey(pCur);
    ++  }else{
    ++    /* For an index btree, save the complete key content */
    ++    void *pKey;
    ++    pCur->nKey = sqlite3BtreePayloadSize(pCur);
    ++    pKey = sqlite3Malloc( pCur->nKey );
    +     if( pKey ){
    +-      rc = sqlite3BtreeKey(pCur, 0, (int)pCur->nKey, pKey);
    ++      rc = sqlite3BtreePayload(pCur, 0, (int)pCur->nKey, pKey);
    +       if( rc==SQLITE_OK ){
    +         pCur->pKey = pKey;
    +       }else{
    +         sqlite3_free(pKey);
    +       }
    +     }else{
    +-      rc = SQLITE_NOMEM;
    ++      rc = SQLITE_NOMEM_BKPT;
    +     }
    +   }
    +   assert( !pCur->curIntKey || !pCur->pKey );
    +@@ -55222,7 +61166,7 @@ static int SQLITE_NOINLINE saveCursorsOnList(
    +           return rc;
    +         }
    +       }else{
    +-        testcase( p->iPage>0 );
    ++        testcase( p->iPage>=0 );
    +         btreeReleaseAllCursorPages(p);
    +       }
    +     }
    +@@ -55255,26 +61199,23 @@ static int btreeMoveto(
    + ){
    +   int rc;                    /* Status code */
    +   UnpackedRecord *pIdxKey;   /* Unpacked index key */
    +-  char aSpace[200];          /* Temp space for pIdxKey - to avoid a malloc */
    +-  char *pFree = 0;
    + 
    +   if( pKey ){
    +     assert( nKey==(i64)(int)nKey );
    +-    pIdxKey = sqlite3VdbeAllocUnpackedRecord(
    +-        pCur->pKeyInfo, aSpace, sizeof(aSpace), &pFree
    +-    );
    +-    if( pIdxKey==0 ) return SQLITE_NOMEM;
    ++    pIdxKey = sqlite3VdbeAllocUnpackedRecord(pCur->pKeyInfo);
    ++    if( pIdxKey==0 ) return SQLITE_NOMEM_BKPT;
    +     sqlite3VdbeRecordUnpack(pCur->pKeyInfo, (int)nKey, pKey, pIdxKey);
    +     if( pIdxKey->nField==0 ){
    +-      sqlite3DbFree(pCur->pKeyInfo->db, pFree);
    +-      return SQLITE_CORRUPT_BKPT;
    ++      rc = SQLITE_CORRUPT_BKPT;
    ++      goto moveto_done;
    +     }
    +   }else{
    +     pIdxKey = 0;
    +   }
    +   rc = sqlite3BtreeMovetoUnpacked(pCur, pIdxKey, nKey, bias, pRes);
    +-  if( pFree ){
    +-    sqlite3DbFree(pCur->pKeyInfo->db, pFree);
    ++moveto_done:
    ++  if( pIdxKey ){
    ++    sqlite3DbFree(pCur->pKeyInfo->db, pIdxKey);
    +   }
    +   return rc;
    + }
    +@@ -55289,7 +61230,7 @@ static int btreeMoveto(
    + static int btreeRestoreCursorPosition(BtCursor *pCur){
    +   int rc;
    +   int skipNext;
    +-  assert( cursorHoldsMutex(pCur) );
    ++  assert( cursorOwnsBtShared(pCur) );
    +   assert( pCur->eState>=CURSOR_REQUIRESEEK );
    +   if( pCur->eState==CURSOR_FAULT ){
    +     return pCur->skipNext;
    +@@ -55329,6 +61270,17 @@ SQLITE_PRIVATE int sqlite3BtreeCursorHasMoved(BtCursor *pCur){
    +   return pCur->eState!=CURSOR_VALID;
    + }
    + 
    ++/*
    ++** Return a pointer to a fake BtCursor object that will always answer
    ++** false to the sqlite3BtreeCursorHasMoved() routine above.  The fake
    ++** cursor returned must not be used with any other Btree interface.
    ++*/
    ++SQLITE_PRIVATE BtCursor *sqlite3BtreeFakeValidCursor(void){
    ++  static u8 fakeCursor = CURSOR_VALID;
    ++  assert( offsetof(BtCursor, eState)==0 );
    ++  return (BtCursor*)&fakeCursor;
    ++}
    ++
    + /*
    + ** This routine restores a cursor back to its original position after it
    + ** has been moved by some outside activity (such as a btree rebalance or
    +@@ -55361,6 +61313,26 @@ SQLITE_PRIVATE int sqlite3BtreeCursorRestore(BtCursor *pCur, int *pDifferentRow)
    +   return SQLITE_OK;
    + }
    + 
    ++#ifdef SQLITE_ENABLE_CURSOR_HINTS
    ++/*
    ++** Provide hints to the cursor.  The particular hint given (and the type
    ++** and number of the varargs parameters) is determined by the eHintType
    ++** parameter.  See the definitions of the BTREE_HINT_* macros for details.
    ++*/
    ++SQLITE_PRIVATE void sqlite3BtreeCursorHint(BtCursor *pCur, int eHintType, ...){
    ++  /* Used only by system that substitute their own storage engine */
    ++}
    ++#endif
    ++
    ++/*
    ++** Provide flag hints to the cursor.
    ++*/
    ++SQLITE_PRIVATE void sqlite3BtreeCursorHintFlags(BtCursor *pCur, unsigned x){
    ++  assert( x==BTREE_SEEK_EQ || x==BTREE_BULKLOAD || x==0 );
    ++  pCur->hints = x;
    ++}
    ++
    ++
    + #ifndef SQLITE_OMIT_AUTOVACUUM
    + /*
    + ** Given a page number of a regular database page, return the page
    +@@ -55414,7 +61386,7 @@ static void ptrmapPut(BtShared *pBt, Pgno key, u8 eType, Pgno parent, int *pRC){
    +     return;
    +   }
    +   iPtrmap = PTRMAP_PAGENO(pBt, key);
    +-  rc = sqlite3PagerGet(pBt->pPager, iPtrmap, &pDbPage);
    ++  rc = sqlite3PagerGet(pBt->pPager, iPtrmap, &pDbPage, 0);
    +   if( rc!=SQLITE_OK ){
    +     *pRC = rc;
    +     return;
    +@@ -55457,7 +61429,7 @@ static int ptrmapGet(BtShared *pBt, Pgno key, u8 *pEType, Pgno *pPgno){
    +   assert( sqlite3_mutex_held(pBt->mutex) );
    + 
    +   iPtrmap = PTRMAP_PAGENO(pBt, key);
    +-  rc = sqlite3PagerGet(pBt->pPager, iPtrmap, &pDbPage);
    ++  rc = sqlite3PagerGet(pBt->pPager, iPtrmap, &pDbPage, 0);
    +   if( rc!=0 ){
    +     return rc;
    +   }
    +@@ -55474,7 +61446,7 @@ static int ptrmapGet(BtShared *pBt, Pgno key, u8 *pEType, Pgno *pPgno){
    +   if( pPgno ) *pPgno = get4byte(&pPtrmap[offset+1]);
    + 
    +   sqlite3PagerUnref(pDbPage);
    +-  if( *pEType<1 || *pEType>5 ) return SQLITE_CORRUPT_BKPT;
    ++  if( *pEType<1 || *pEType>5 ) return SQLITE_CORRUPT_PGNO(iPtrmap);
    +   return SQLITE_OK;
    + }
    + 
    +@@ -55534,8 +61506,7 @@ static SQLITE_NOINLINE void btreeParseCellAdjustSizeForOverflow(
    +   }else{
    +     pInfo->nLocal = (u16)minLocal;
    +   }
    +-  pInfo->iOverflow = (u16)(&pInfo->pPayload[pInfo->nLocal] - pCell);
    +-  pInfo->nSize = pInfo->iOverflow + 4;
    ++  pInfo->nSize = (u16)(&pInfo->pPayload[pInfo->nLocal] - pCell) + 4;
    + }
    + 
    + /*
    +@@ -55559,7 +61530,6 @@ static void btreeParseCellPtrNoPayload(
    + ){
    +   assert( sqlite3_mutex_held(pPage->pBt->mutex) );
    +   assert( pPage->leaf==0 );
    +-  assert( pPage->noPayload );
    +   assert( pPage->childPtrSize==4 );
    + #ifndef SQLITE_DEBUG
    +   UNUSED_PARAMETER(pPage);
    +@@ -55567,7 +61537,6 @@ static void btreeParseCellPtrNoPayload(
    +   pInfo->nSize = 4 + getVarint(&pCell[4], (u64*)&pInfo->nKey);
    +   pInfo->nPayload = 0;
    +   pInfo->nLocal = 0;
    +-  pInfo->iOverflow = 0;
    +   pInfo->pPayload = 0;
    +   return;
    + }
    +@@ -55582,8 +61551,6 @@ static void btreeParseCellPtr(
    + 
    +   assert( sqlite3_mutex_held(pPage->pBt->mutex) );
    +   assert( pPage->leaf==0 || pPage->leaf==1 );
    +-  assert( pPage->intKeyLeaf || pPage->noPayload );
    +-  assert( pPage->noPayload==0 );
    +   assert( pPage->intKeyLeaf );
    +   assert( pPage->childPtrSize==0 );
    +   pIter = pCell;
    +@@ -55637,7 +61604,6 @@ static void btreeParseCellPtr(
    +     pInfo->nSize = nPayload + (u16)(pIter - pCell);
    +     if( pInfo->nSize<4 ) pInfo->nSize = 4;
    +     pInfo->nLocal = (u16)nPayload;
    +-    pInfo->iOverflow = 0;
    +   }else{
    +     btreeParseCellAdjustSizeForOverflow(pPage, pCell, pInfo);
    +   }
    +@@ -55653,7 +61619,6 @@ static void btreeParseCellPtrIndex(
    +   assert( sqlite3_mutex_held(pPage->pBt->mutex) );
    +   assert( pPage->leaf==0 || pPage->leaf==1 );
    +   assert( pPage->intKeyLeaf==0 );
    +-  assert( pPage->noPayload==0 );
    +   pIter = pCell + pPage->childPtrSize;
    +   nPayload = *pIter;
    +   if( nPayload>=0x80 ){
    +@@ -55676,7 +61641,6 @@ static void btreeParseCellPtrIndex(
    +     pInfo->nSize = nPayload + (u16)(pIter - pCell);
    +     if( pInfo->nSize<4 ) pInfo->nSize = 4;
    +     pInfo->nLocal = (u16)nPayload;
    +-    pInfo->iOverflow = 0;
    +   }else{
    +     btreeParseCellAdjustSizeForOverflow(pPage, pCell, pInfo);
    +   }
    +@@ -55715,7 +61679,6 @@ static u16 cellSizePtr(MemPage *pPage, u8 *pCell){
    +   pPage->xParseCell(pPage, pCell, &debuginfo);
    + #endif
    + 
    +-  assert( pPage->noPayload==0 );
    +   nSize = *pIter;
    +   if( nSize>=0x80 ){
    +     pEnd = &pIter[8];
    +@@ -55792,8 +61755,8 @@ static void ptrmapPutOvflPtr(MemPage *pPage, u8 *pCell, int *pRC){
    +   if( *pRC ) return;
    +   assert( pCell!=0 );
    +   pPage->xParseCell(pPage, pCell, &info);
    +-  if( info.iOverflow ){
    +-    Pgno ovfl = get4byte(&pCell[info.iOverflow]);
    ++  if( info.nLocal<info.nPayload ){
    ++    Pgno ovfl = get4byte(&pCell[info.nSize-4]);
    +     ptrmapPut(pPage->pBt, ovfl, PTRMAP_OVERFLOW1, pPage->pgno, pRC);
    +   }
    + }
    +@@ -55801,17 +61764,18 @@ static void ptrmapPutOvflPtr(MemPage *pPage, u8 *pCell, int *pRC){
    + 
    + 
    + /*
    +-** Defragment the page given.  All Cells are moved to the
    +-** end of the page and all free space is collected into one
    +-** big FreeBlk that occurs in between the header and cell
    +-** pointer array and the cell content area.
    ++** Defragment the page given. This routine reorganizes cells within the
    ++** page so that there are no free-blocks on the free-block list.
    ++**
    ++** Parameter nMaxFrag is the maximum amount of fragmented space that may be
    ++** present in the page after this routine returns.
    + **
    + ** EVIDENCE-OF: R-44582-60138 SQLite may from time to time reorganize a
    + ** b-tree page so that there are no freeblocks or fragment bytes, all
    + ** unused bytes are contained in the unallocated space region, and all
    + ** cells are packed tightly at the end of the page.
    + */
    +-static int defragmentPage(MemPage *pPage){
    ++static int defragmentPage(MemPage *pPage, int nMaxFrag){
    +   int i;                     /* Loop counter */
    +   int pc;                    /* Address of the i-th cell */
    +   int hdr;                   /* Offset to the page header */
    +@@ -55826,7 +61790,6 @@ static int defragmentPage(MemPage *pPage){
    +   int iCellFirst;            /* First allowable cell index */
    +   int iCellLast;             /* Last possible cell index */
    + 
    +-
    +   assert( sqlite3PagerIswriteable(pPage->pDbPage) );
    +   assert( pPage->pBt!=0 );
    +   assert( pPage->pBt->usableSize <= SQLITE_MAX_PAGE_SIZE );
    +@@ -55838,9 +61801,59 @@ static int defragmentPage(MemPage *pPage){
    +   cellOffset = pPage->cellOffset;
    +   nCell = pPage->nCell;
    +   assert( nCell==get2byte(&data[hdr+3]) );
    ++  iCellFirst = cellOffset + 2*nCell;
    +   usableSize = pPage->pBt->usableSize;
    ++
    ++  /* This block handles pages with two or fewer free blocks and nMaxFrag
    ++  ** or fewer fragmented bytes. In this case it is faster to move the
    ++  ** two (or one) blocks of cells using memmove() and add the required
    ++  ** offsets to each pointer in the cell-pointer array than it is to 
    ++  ** reconstruct the entire page.  */
    ++  if( (int)data[hdr+7]<=nMaxFrag ){
    ++    int iFree = get2byte(&data[hdr+1]);
    ++    if( iFree ){
    ++      int iFree2 = get2byte(&data[iFree]);
    ++
    ++      /* pageFindSlot() has already verified that free blocks are sorted
    ++      ** in order of offset within the page, and that no block extends
    ++      ** past the end of the page. Provided the two free slots do not 
    ++      ** overlap, this guarantees that the memmove() calls below will not
    ++      ** overwrite the usableSize byte buffer, even if the database page
    ++      ** is corrupt.  */
    ++      assert( iFree2==0 || iFree2>iFree );
    ++      assert( iFree+get2byte(&data[iFree+2]) <= usableSize );
    ++      assert( iFree2==0 || iFree2+get2byte(&data[iFree2+2]) <= usableSize );
    ++
    ++      if( 0==iFree2 || (data[iFree2]==0 && data[iFree2+1]==0) ){
    ++        u8 *pEnd = &data[cellOffset + nCell*2];
    ++        u8 *pAddr;
    ++        int sz2 = 0;
    ++        int sz = get2byte(&data[iFree+2]);
    ++        int top = get2byte(&data[hdr+5]);
    ++        if( top>=iFree ){
    ++          return SQLITE_CORRUPT_PAGE(pPage);
    ++        }
    ++        if( iFree2 ){
    ++          assert( iFree+sz<=iFree2 ); /* Verified by pageFindSlot() */
    ++          sz2 = get2byte(&data[iFree2+2]);
    ++          assert( iFree+sz+sz2+iFree2-(iFree+sz) <= usableSize );
    ++          memmove(&data[iFree+sz+sz2], &data[iFree+sz], iFree2-(iFree+sz));
    ++          sz += sz2;
    ++        }
    ++        cbrk = top+sz;
    ++        assert( cbrk+(iFree-top) <= usableSize );
    ++        memmove(&data[cbrk], &data[top], iFree-top);
    ++        for(pAddr=&data[cellOffset]; pAddr<pEnd; pAddr+=2){
    ++          pc = get2byte(pAddr);
    ++          if( pc<iFree ){ put2byte(pAddr, pc+sz); }
    ++          else if( pc<iFree2 ){ put2byte(pAddr, pc+sz2); }
    ++        }
    ++        goto defragment_out;
    ++      }
    ++    }
    ++  }
    ++
    +   cbrk = usableSize;
    +-  iCellFirst = cellOffset + 2*nCell;
    +   iCellLast = usableSize - 4;
    +   for(i=0; i<nCell; i++){
    +     u8 *pAddr;     /* The i-th cell pointer */
    +@@ -55852,13 +61865,13 @@ static int defragmentPage(MemPage *pPage){
    +     ** if PRAGMA cell_size_check=ON.
    +     */
    +     if( pc<iCellFirst || pc>iCellLast ){
    +-      return SQLITE_CORRUPT_BKPT;
    ++      return SQLITE_CORRUPT_PAGE(pPage);
    +     }
    +     assert( pc>=iCellFirst && pc<=iCellLast );
    +     size = pPage->xCellSize(pPage, &src[pc]);
    +     cbrk -= size;
    +     if( cbrk<iCellFirst || pc+size>usableSize ){
    +-      return SQLITE_CORRUPT_BKPT;
    ++      return SQLITE_CORRUPT_PAGE(pPage);
    +     }
    +     assert( cbrk+size<=usableSize && cbrk>=iCellFirst );
    +     testcase( cbrk+size==usableSize );
    +@@ -55874,16 +61887,18 @@ static int defragmentPage(MemPage *pPage){
    +     }
    +     memcpy(&data[cbrk], &src[pc], size);
    +   }
    ++  data[hdr+7] = 0;
    ++
    ++ defragment_out:
    ++  if( data[hdr+7]+cbrk-iCellFirst!=pPage->nFree ){
    ++    return SQLITE_CORRUPT_PAGE(pPage);
    ++  }
    +   assert( cbrk>=iCellFirst );
    +   put2byte(&data[hdr+5], cbrk);
    +   data[hdr+1] = 0;
    +   data[hdr+2] = 0;
    +-  data[hdr+7] = 0;
    +   memset(&data[iCellFirst], 0, cbrk-iCellFirst);
    +   assert( sqlite3PagerIswriteable(pPage->pDbPage) );
    +-  if( cbrk-iCellFirst!=pPage->nFree ){
    +-    return SQLITE_CORRUPT_BKPT;
    +-  }
    +   return SQLITE_OK;
    + }
    + 
    +@@ -55908,16 +61923,10 @@ static u8 *pageFindSlot(MemPage *pPg, int nByte, int *pRc){
    +   int pc = get2byte(&aData[iAddr]);
    +   int x;
    +   int usableSize = pPg->pBt->usableSize;
    ++  int size;            /* Size of the free slot */
    + 
    +   assert( pc>0 );
    +-  do{
    +-    int size;            /* Size of the free slot */
    +-    /* EVIDENCE-OF: R-06866-39125 Freeblocks are always connected in order of
    +-    ** increasing offset. */
    +-    if( pc>usableSize-4 || pc<iAddr+4 ){
    +-      *pRc = SQLITE_CORRUPT_BKPT;
    +-      return 0;
    +-    }
    ++  while( pc<=usableSize-4 ){
    +     /* EVIDENCE-OF: R-22710-53328 The third and fourth bytes of each
    +     ** freeblock form a big-endian integer which is the size of the freeblock
    +     ** in bytes, including the 4-byte header. */
    +@@ -55925,8 +61934,8 @@ static u8 *pageFindSlot(MemPage *pPg, int nByte, int *pRc){
    +     if( (x = size - nByte)>=0 ){
    +       testcase( x==4 );
    +       testcase( x==3 );
    +-      if( pc < pPg->cellOffset+2*pPg->nCell || size+pc > usableSize ){
    +-        *pRc = SQLITE_CORRUPT_BKPT;
    ++      if( size+pc > usableSize ){
    ++        *pRc = SQLITE_CORRUPT_PAGE(pPg);
    +         return 0;
    +       }else if( x<4 ){
    +         /* EVIDENCE-OF: R-11498-58022 In a well-formed b-tree page, the total
    +@@ -55946,7 +61955,11 @@ static u8 *pageFindSlot(MemPage *pPg, int nByte, int *pRc){
    +     }
    +     iAddr = pc;
    +     pc = get2byte(&aData[pc]);
    +-  }while( pc );
    ++    if( pc<iAddr+size ) break;
    ++  }
    ++  if( pc ){
    ++    *pRc = SQLITE_CORRUPT_PAGE(pPg);
    ++  }
    + 
    +   return 0;
    + }
    +@@ -55993,7 +62006,7 @@ static int allocateSpace(MemPage *pPage, int nByte, int *pIdx){
    +     if( top==0 && pPage->pBt->usableSize==65536 ){
    +       top = 65536;
    +     }else{
    +-      return SQLITE_CORRUPT_BKPT;
    ++      return SQLITE_CORRUPT_PAGE(pPage);
    +     }
    +   }
    + 
    +@@ -56021,10 +62034,10 @@ static int allocateSpace(MemPage *pPage, int nByte, int *pIdx){
    +   testcase( gap+2+nByte==top );
    +   if( gap+2+nByte>top ){
    +     assert( pPage->nCell>0 || CORRUPT_DB );
    +-    rc = defragmentPage(pPage);
    ++    rc = defragmentPage(pPage, MIN(4, pPage->nFree - (2+nByte)));
    +     if( rc ) return rc;
    +     top = get2byteNotZero(&data[hdr+5]);
    +-    assert( gap+nByte<=top );
    ++    assert( gap+2+nByte<=top );
    +   }
    + 
    + 
    +@@ -56060,7 +62073,7 @@ static int freeSpace(MemPage *pPage, u16 iStart, u16 iSize){
    +   u8 hdr;                               /* Page header size.  0 or 100 */
    +   u8 nFrag = 0;                         /* Reduction in fragmentation */
    +   u16 iOrigSize = iSize;                /* Original value of iSize */
    +-  u32 iLast = pPage->pBt->usableSize-4; /* Largest possible freeblock offset */
    ++  u16 x;                                /* Offset to cell content area */
    +   u32 iEnd = iStart + iSize;            /* First byte past the iStart buffer */
    +   unsigned char *data = pPage->aData;   /* Page content */
    + 
    +@@ -56070,13 +62083,7 @@ static int freeSpace(MemPage *pPage, u16 iStart, u16 iSize){
    +   assert( CORRUPT_DB || iEnd <= pPage->pBt->usableSize );
    +   assert( sqlite3_mutex_held(pPage->pBt->mutex) );
    +   assert( iSize>=4 );   /* Minimum cell size is 4 */
    +-  assert( iStart<=iLast );
    +-
    +-  /* Overwrite deleted information with zeros when the secure_delete
    +-  ** option is enabled */
    +-  if( pPage->pBt->btsFlags & BTS_SECURE_DELETE ){
    +-    memset(&data[iStart], 0, iSize);
    +-  }
    ++  assert( iStart<=pPage->pBt->usableSize-4 );
    + 
    +   /* The list of freeblocks must be in ascending order.  Find the 
    +   ** spot on the list where iStart should be inserted.
    +@@ -56086,11 +62093,16 @@ static int freeSpace(MemPage *pPage, u16 iStart, u16 iSize){
    +   if( data[iPtr+1]==0 && data[iPtr]==0 ){
    +     iFreeBlk = 0;  /* Shortcut for the case when the freelist is empty */
    +   }else{
    +-    while( (iFreeBlk = get2byte(&data[iPtr]))>0 && iFreeBlk<iStart ){
    +-      if( iFreeBlk<iPtr+4 ) return SQLITE_CORRUPT_BKPT;
    ++    while( (iFreeBlk = get2byte(&data[iPtr]))<iStart ){
    ++      if( iFreeBlk<iPtr+4 ){
    ++        if( iFreeBlk==0 ) break;
    ++        return SQLITE_CORRUPT_PAGE(pPage);
    ++      }
    +       iPtr = iFreeBlk;
    +     }
    +-    if( iFreeBlk>iLast ) return SQLITE_CORRUPT_BKPT;
    ++    if( iFreeBlk>pPage->pBt->usableSize-4 ){
    ++      return SQLITE_CORRUPT_PAGE(pPage);
    ++    }
    +     assert( iFreeBlk>iPtr || iFreeBlk==0 );
    +   
    +     /* At this point:
    +@@ -56101,9 +62113,11 @@ static int freeSpace(MemPage *pPage, u16 iStart, u16 iSize){
    +     */
    +     if( iFreeBlk && iEnd+3>=iFreeBlk ){
    +       nFrag = iFreeBlk - iEnd;
    +-      if( iEnd>iFreeBlk ) return SQLITE_CORRUPT_BKPT;
    ++      if( iEnd>iFreeBlk ) return SQLITE_CORRUPT_PAGE(pPage);
    +       iEnd = iFreeBlk + get2byte(&data[iFreeBlk+2]);
    +-      if( iEnd > pPage->pBt->usableSize ) return SQLITE_CORRUPT_BKPT;
    ++      if( iEnd > pPage->pBt->usableSize ){
    ++        return SQLITE_CORRUPT_PAGE(pPage);
    ++      }
    +       iSize = iEnd - iStart;
    +       iFreeBlk = get2byte(&data[iFreeBlk]);
    +     }
    +@@ -56115,28 +62129,34 @@ static int freeSpace(MemPage *pPage, u16 iStart, u16 iSize){
    +     if( iPtr>hdr+1 ){
    +       int iPtrEnd = iPtr + get2byte(&data[iPtr+2]);
    +       if( iPtrEnd+3>=iStart ){
    +-        if( iPtrEnd>iStart ) return SQLITE_CORRUPT_BKPT;
    ++        if( iPtrEnd>iStart ) return SQLITE_CORRUPT_PAGE(pPage);
    +         nFrag += iStart - iPtrEnd;
    +         iSize = iEnd - iPtr;
    +         iStart = iPtr;
    +       }
    +     }
    +-    if( nFrag>data[hdr+7] ) return SQLITE_CORRUPT_BKPT;
    ++    if( nFrag>data[hdr+7] ) return SQLITE_CORRUPT_PAGE(pPage);
    +     data[hdr+7] -= nFrag;
    +   }
    +-  if( iStart==get2byte(&data[hdr+5]) ){
    ++  x = get2byte(&data[hdr+5]);
    ++  if( iStart<=x ){
    +     /* The new freeblock is at the beginning of the cell content area,
    +     ** so just extend the cell content area rather than create another
    +     ** freelist entry */
    +-    if( iPtr!=hdr+1 ) return SQLITE_CORRUPT_BKPT;
    ++    if( iStart<x || iPtr!=hdr+1 ) return SQLITE_CORRUPT_PAGE(pPage);
    +     put2byte(&data[hdr+1], iFreeBlk);
    +     put2byte(&data[hdr+5], iEnd);
    +   }else{
    +     /* Insert the new freeblock into the freelist */
    +     put2byte(&data[iPtr], iStart);
    +-    put2byte(&data[iStart], iFreeBlk);
    +-    put2byte(&data[iStart+2], iSize);
    +   }
    ++  if( pPage->pBt->btsFlags & BTS_FAST_SECURE ){
    ++    /* Overwrite deleted information with zeros when the secure_delete
    ++    ** option is enabled */
    ++    memset(&data[iStart], 0, iSize);
    ++  }
    ++  put2byte(&data[iStart], iFreeBlk);
    ++  put2byte(&data[iStart+2], iSize);
    +   pPage->nFree += iOrigSize;
    +   return SQLITE_OK;
    + }
    +@@ -56164,42 +62184,39 @@ static int decodeFlags(MemPage *pPage, int flagByte){
    +   pPage->xCellSize = cellSizePtr;
    +   pBt = pPage->pBt;
    +   if( flagByte==(PTF_LEAFDATA | PTF_INTKEY) ){
    +-    /* EVIDENCE-OF: R-03640-13415 A value of 5 means the page is an interior
    +-    ** table b-tree page. */
    ++    /* EVIDENCE-OF: R-07291-35328 A value of 5 (0x05) means the page is an
    ++    ** interior table b-tree page. */
    +     assert( (PTF_LEAFDATA|PTF_INTKEY)==5 );
    +-    /* EVIDENCE-OF: R-20501-61796 A value of 13 means the page is a leaf
    +-    ** table b-tree page. */
    ++    /* EVIDENCE-OF: R-26900-09176 A value of 13 (0x0d) means the page is a
    ++    ** leaf table b-tree page. */
    +     assert( (PTF_LEAFDATA|PTF_INTKEY|PTF_LEAF)==13 );
    +     pPage->intKey = 1;
    +     if( pPage->leaf ){
    +       pPage->intKeyLeaf = 1;
    +-      pPage->noPayload = 0;
    +       pPage->xParseCell = btreeParseCellPtr;
    +     }else{
    +       pPage->intKeyLeaf = 0;
    +-      pPage->noPayload = 1;
    +       pPage->xCellSize = cellSizePtrNoPayload;
    +       pPage->xParseCell = btreeParseCellPtrNoPayload;
    +     }
    +     pPage->maxLocal = pBt->maxLeaf;
    +     pPage->minLocal = pBt->minLeaf;
    +   }else if( flagByte==PTF_ZERODATA ){
    +-    /* EVIDENCE-OF: R-27225-53936 A value of 2 means the page is an interior
    +-    ** index b-tree page. */
    ++    /* EVIDENCE-OF: R-43316-37308 A value of 2 (0x02) means the page is an
    ++    ** interior index b-tree page. */
    +     assert( (PTF_ZERODATA)==2 );
    +-    /* EVIDENCE-OF: R-16571-11615 A value of 10 means the page is a leaf
    +-    ** index b-tree page. */
    ++    /* EVIDENCE-OF: R-59615-42828 A value of 10 (0x0a) means the page is a
    ++    ** leaf index b-tree page. */
    +     assert( (PTF_ZERODATA|PTF_LEAF)==10 );
    +     pPage->intKey = 0;
    +     pPage->intKeyLeaf = 0;
    +-    pPage->noPayload = 0;
    +     pPage->xParseCell = btreeParseCellPtrIndex;
    +     pPage->maxLocal = pBt->maxLocal;
    +     pPage->minLocal = pBt->minLocal;
    +   }else{
    +     /* EVIDENCE-OF: R-47608-56469 Any other value for the b-tree page type is
    +     ** an error. */
    +-    return SQLITE_CORRUPT_BKPT;
    ++    return SQLITE_CORRUPT_PAGE(pPage);
    +   }
    +   pPage->max1bytePayload = pBt->max1bytePayload;
    +   return SQLITE_OK;
    +@@ -56215,6 +62232,16 @@ static int decodeFlags(MemPage *pPage, int flagByte){
    + ** we failed to detect any corruption.
    + */
    + static int btreeInitPage(MemPage *pPage){
    ++  int pc;            /* Address of a freeblock within pPage->aData[] */
    ++  u8 hdr;            /* Offset to beginning of page header */
    ++  u8 *data;          /* Equal to pPage->aData */
    ++  BtShared *pBt;        /* The main btree structure */
    ++  int usableSize;    /* Amount of usable space on each page */
    ++  u16 cellOffset;    /* Offset from start of page to first cell pointer */
    ++  int nFree;         /* Number of unused bytes on the page */
    ++  int top;           /* First byte of the cell content area */
    ++  int iCellFirst;    /* First allowable cell or freeblock offset */
    ++  int iCellLast;     /* Last possible cell or freeblock offset */
    + 
    +   assert( pPage->pBt!=0 );
    +   assert( pPage->pBt->db!=0 );
    +@@ -56222,122 +62249,119 @@ static int btreeInitPage(MemPage *pPage){
    +   assert( pPage->pgno==sqlite3PagerPagenumber(pPage->pDbPage) );
    +   assert( pPage == sqlite3PagerGetExtra(pPage->pDbPage) );
    +   assert( pPage->aData == sqlite3PagerGetData(pPage->pDbPage) );
    ++  assert( pPage->isInit==0 );
    + 
    +-  if( !pPage->isInit ){
    +-    u16 pc;            /* Address of a freeblock within pPage->aData[] */
    +-    u8 hdr;            /* Offset to beginning of page header */
    +-    u8 *data;          /* Equal to pPage->aData */
    +-    BtShared *pBt;        /* The main btree structure */
    +-    int usableSize;    /* Amount of usable space on each page */
    +-    u16 cellOffset;    /* Offset from start of page to first cell pointer */
    +-    int nFree;         /* Number of unused bytes on the page */
    +-    int top;           /* First byte of the cell content area */
    +-    int iCellFirst;    /* First allowable cell or freeblock offset */
    +-    int iCellLast;     /* Last possible cell or freeblock offset */
    +-
    +-    pBt = pPage->pBt;
    +-
    +-    hdr = pPage->hdrOffset;
    +-    data = pPage->aData;
    +-    /* EVIDENCE-OF: R-28594-02890 The one-byte flag at offset 0 indicating
    +-    ** the b-tree page type. */
    +-    if( decodeFlags(pPage, data[hdr]) ) return SQLITE_CORRUPT_BKPT;
    +-    assert( pBt->pageSize>=512 && pBt->pageSize<=65536 );
    +-    pPage->maskPage = (u16)(pBt->pageSize - 1);
    +-    pPage->nOverflow = 0;
    +-    usableSize = pBt->usableSize;
    +-    pPage->cellOffset = cellOffset = hdr + 8 + pPage->childPtrSize;
    +-    pPage->aDataEnd = &data[usableSize];
    +-    pPage->aCellIdx = &data[cellOffset];
    +-    pPage->aDataOfst = &data[pPage->childPtrSize];
    +-    /* EVIDENCE-OF: R-58015-48175 The two-byte integer at offset 5 designates
    +-    ** the start of the cell content area. A zero value for this integer is
    +-    ** interpreted as 65536. */
    +-    top = get2byteNotZero(&data[hdr+5]);
    +-    /* EVIDENCE-OF: R-37002-32774 The two-byte integer at offset 3 gives the
    +-    ** number of cells on the page. */
    +-    pPage->nCell = get2byte(&data[hdr+3]);
    +-    if( pPage->nCell>MX_CELL(pBt) ){
    +-      /* To many cells for a single page.  The page must be corrupt */
    +-      return SQLITE_CORRUPT_BKPT;
    ++  pBt = pPage->pBt;
    ++  hdr = pPage->hdrOffset;
    ++  data = pPage->aData;
    ++  /* EVIDENCE-OF: R-28594-02890 The one-byte flag at offset 0 indicating
    ++  ** the b-tree page type. */
    ++  if( decodeFlags(pPage, data[hdr]) ){
    ++    return SQLITE_CORRUPT_PAGE(pPage);
    ++  }
    ++  assert( pBt->pageSize>=512 && pBt->pageSize<=65536 );
    ++  pPage->maskPage = (u16)(pBt->pageSize - 1);
    ++  pPage->nOverflow = 0;
    ++  usableSize = pBt->usableSize;
    ++  pPage->cellOffset = cellOffset = hdr + 8 + pPage->childPtrSize;
    ++  pPage->aDataEnd = &data[usableSize];
    ++  pPage->aCellIdx = &data[cellOffset];
    ++  pPage->aDataOfst = &data[pPage->childPtrSize];
    ++  /* EVIDENCE-OF: R-58015-48175 The two-byte integer at offset 5 designates
    ++  ** the start of the cell content area. A zero value for this integer is
    ++  ** interpreted as 65536. */
    ++  top = get2byteNotZero(&data[hdr+5]);
    ++  /* EVIDENCE-OF: R-37002-32774 The two-byte integer at offset 3 gives the
    ++  ** number of cells on the page. */
    ++  pPage->nCell = get2byte(&data[hdr+3]);
    ++  if( pPage->nCell>MX_CELL(pBt) ){
    ++    /* To many cells for a single page.  The page must be corrupt */
    ++    return SQLITE_CORRUPT_PAGE(pPage);
    ++  }
    ++  testcase( pPage->nCell==MX_CELL(pBt) );
    ++  /* EVIDENCE-OF: R-24089-57979 If a page contains no cells (which is only
    ++  ** possible for a root page of a table that contains no rows) then the
    ++  ** offset to the cell content area will equal the page size minus the
    ++  ** bytes of reserved space. */
    ++  assert( pPage->nCell>0 || top==usableSize || CORRUPT_DB );
    ++
    ++  /* A malformed database page might cause us to read past the end
    ++  ** of page when parsing a cell.  
    ++  **
    ++  ** The following block of code checks early to see if a cell extends
    ++  ** past the end of a page boundary and causes SQLITE_CORRUPT to be 
    ++  ** returned if it does.
    ++  */
    ++  iCellFirst = cellOffset + 2*pPage->nCell;
    ++  iCellLast = usableSize - 4;
    ++  if( pBt->db->flags & SQLITE_CellSizeCk ){
    ++    int i;            /* Index into the cell pointer array */
    ++    int sz;           /* Size of a cell */
    ++
    ++    if( !pPage->leaf ) iCellLast--;
    ++    for(i=0; i<pPage->nCell; i++){
    ++      pc = get2byteAligned(&data[cellOffset+i*2]);
    ++      testcase( pc==iCellFirst );
    ++      testcase( pc==iCellLast );
    ++      if( pc<iCellFirst || pc>iCellLast ){
    ++        return SQLITE_CORRUPT_PAGE(pPage);
    ++      }
    ++      sz = pPage->xCellSize(pPage, &data[pc]);
    ++      testcase( pc+sz==usableSize );
    ++      if( pc+sz>usableSize ){
    ++        return SQLITE_CORRUPT_PAGE(pPage);
    ++      }
    +     }
    +-    testcase( pPage->nCell==MX_CELL(pBt) );
    +-    /* EVIDENCE-OF: R-24089-57979 If a page contains no cells (which is only
    +-    ** possible for a root page of a table that contains no rows) then the
    +-    ** offset to the cell content area will equal the page size minus the
    +-    ** bytes of reserved space. */
    +-    assert( pPage->nCell>0 || top==usableSize || CORRUPT_DB );
    +-
    +-    /* A malformed database page might cause us to read past the end
    +-    ** of page when parsing a cell.  
    +-    **
    +-    ** The following block of code checks early to see if a cell extends
    +-    ** past the end of a page boundary and causes SQLITE_CORRUPT to be 
    +-    ** returned if it does.
    +-    */
    +-    iCellFirst = cellOffset + 2*pPage->nCell;
    +-    iCellLast = usableSize - 4;
    +-    if( pBt->db->flags & SQLITE_CellSizeCk ){
    +-      int i;            /* Index into the cell pointer array */
    +-      int sz;           /* Size of a cell */
    +-
    +-      if( !pPage->leaf ) iCellLast--;
    +-      for(i=0; i<pPage->nCell; i++){
    +-        pc = get2byteAligned(&data[cellOffset+i*2]);
    +-        testcase( pc==iCellFirst );
    +-        testcase( pc==iCellLast );
    +-        if( pc<iCellFirst || pc>iCellLast ){
    +-          return SQLITE_CORRUPT_BKPT;
    +-        }
    +-        sz = pPage->xCellSize(pPage, &data[pc]);
    +-        testcase( pc+sz==usableSize );
    +-        if( pc+sz>usableSize ){
    +-          return SQLITE_CORRUPT_BKPT;
    +-        }
    +-      }
    +-      if( !pPage->leaf ) iCellLast++;
    +-    }  
    ++    if( !pPage->leaf ) iCellLast++;
    ++  }  
    + 
    +-    /* Compute the total free space on the page
    +-    ** EVIDENCE-OF: R-23588-34450 The two-byte integer at offset 1 gives the
    +-    ** start of the first freeblock on the page, or is zero if there are no
    +-    ** freeblocks. */
    +-    pc = get2byte(&data[hdr+1]);
    +-    nFree = data[hdr+7] + top;  /* Init nFree to non-freeblock free space */
    +-    while( pc>0 ){
    +-      u16 next, size;
    +-      if( pc<iCellFirst || pc>iCellLast ){
    +-        /* EVIDENCE-OF: R-55530-52930 In a well-formed b-tree page, there will
    +-        ** always be at least one cell before the first freeblock.
    +-        **
    +-        ** Or, the freeblock is off the end of the page
    +-        */
    +-        return SQLITE_CORRUPT_BKPT; 
    ++  /* Compute the total free space on the page
    ++  ** EVIDENCE-OF: R-23588-34450 The two-byte integer at offset 1 gives the
    ++  ** start of the first freeblock on the page, or is zero if there are no
    ++  ** freeblocks. */
    ++  pc = get2byte(&data[hdr+1]);
    ++  nFree = data[hdr+7] + top;  /* Init nFree to non-freeblock free space */
    ++  if( pc>0 ){
    ++    u32 next, size;
    ++    if( pc<iCellFirst ){
    ++      /* EVIDENCE-OF: R-55530-52930 In a well-formed b-tree page, there will
    ++      ** always be at least one cell before the first freeblock.
    ++      */
    ++      return SQLITE_CORRUPT_PAGE(pPage); 
    ++    }
    ++    while( 1 ){
    ++      if( pc>iCellLast ){
    ++        /* Freeblock off the end of the page */
    ++        return SQLITE_CORRUPT_PAGE(pPage);
    +       }
    +       next = get2byte(&data[pc]);
    +       size = get2byte(&data[pc+2]);
    +-      if( (next>0 && next<=pc+size+3) || pc+size>usableSize ){
    +-        /* Free blocks must be in ascending order. And the last byte of
    +-        ** the free-block must lie on the database page.  */
    +-        return SQLITE_CORRUPT_BKPT; 
    +-      }
    +       nFree = nFree + size;
    ++      if( next<=pc+size+3 ) break;
    +       pc = next;
    +     }
    +-
    +-    /* At this point, nFree contains the sum of the offset to the start
    +-    ** of the cell-content area plus the number of free bytes within
    +-    ** the cell-content area. If this is greater than the usable-size
    +-    ** of the page, then the page must be corrupted. This check also
    +-    ** serves to verify that the offset to the start of the cell-content
    +-    ** area, according to the page header, lies within the page.
    +-    */
    +-    if( nFree>usableSize ){
    +-      return SQLITE_CORRUPT_BKPT; 
    ++    if( next>0 ){
    ++      /* Freeblock not in ascending order */
    ++      return SQLITE_CORRUPT_PAGE(pPage);
    ++    }
    ++    if( pc+size>(unsigned int)usableSize ){
    ++      /* Last freeblock extends past page end */
    ++      return SQLITE_CORRUPT_PAGE(pPage);
    +     }
    +-    pPage->nFree = (u16)(nFree - iCellFirst);
    +-    pPage->isInit = 1;
    +   }
    ++
    ++  /* At this point, nFree contains the sum of the offset to the start
    ++  ** of the cell-content area plus the number of free bytes within
    ++  ** the cell-content area. If this is greater than the usable-size
    ++  ** of the page, then the page must be corrupted. This check also
    ++  ** serves to verify that the offset to the start of the cell-content
    ++  ** area, according to the page header, lies within the page.
    ++  */
    ++  if( nFree>usableSize ){
    ++    return SQLITE_CORRUPT_PAGE(pPage);
    ++  }
    ++  pPage->nFree = (u16)(nFree - iCellFirst);
    ++  pPage->isInit = 1;
    +   return SQLITE_OK;
    + }
    + 
    +@@ -56356,7 +62380,7 @@ static void zeroPage(MemPage *pPage, int flags){
    +   assert( sqlite3PagerGetData(pPage->pDbPage) == data );
    +   assert( sqlite3PagerIswriteable(pPage->pDbPage) );
    +   assert( sqlite3_mutex_held(pBt->mutex) );
    +-  if( pBt->btsFlags & BTS_SECURE_DELETE ){
    ++  if( pBt->btsFlags & BTS_FAST_SECURE ){
    +     memset(&data[hdr], 0, pBt->usableSize - hdr);
    +   }
    +   data[hdr] = (char)flags;
    +@@ -56384,11 +62408,14 @@ static void zeroPage(MemPage *pPage, int flags){
    + */
    + static MemPage *btreePageFromDbPage(DbPage *pDbPage, Pgno pgno, BtShared *pBt){
    +   MemPage *pPage = (MemPage*)sqlite3PagerGetExtra(pDbPage);
    +-  pPage->aData = sqlite3PagerGetData(pDbPage);
    +-  pPage->pDbPage = pDbPage;
    +-  pPage->pBt = pBt;
    +-  pPage->pgno = pgno;
    +-  pPage->hdrOffset = pgno==1 ? 100 : 0;
    ++  if( pgno!=pPage->pgno ){
    ++    pPage->aData = sqlite3PagerGetData(pDbPage);
    ++    pPage->pDbPage = pDbPage;
    ++    pPage->pBt = pBt;
    ++    pPage->pgno = pgno;
    ++    pPage->hdrOffset = pgno==1 ? 100 : 0;
    ++  }
    ++  assert( pPage->aData==sqlite3PagerGetData(pDbPage) );
    +   return pPage; 
    + }
    + 
    +@@ -56414,7 +62441,7 @@ static int btreeGetPage(
    + 
    +   assert( flags==0 || flags==PAGER_GET_NOCONTENT || flags==PAGER_GET_READONLY );
    +   assert( sqlite3_mutex_held(pBt->mutex) );
    +-  rc = sqlite3PagerAcquire(pBt->pPager, pgno, (DbPage**)&pDbPage, flags);
    ++  rc = sqlite3PagerGet(pBt->pPager, pgno, (DbPage**)&pDbPage, flags);
    +   if( rc ) return rc;
    +   *ppPage = btreePageFromDbPage(pDbPage, pgno, pBt);
    +   return SQLITE_OK;
    +@@ -56444,7 +62471,7 @@ static Pgno btreePagecount(BtShared *pBt){
    + }
    + SQLITE_PRIVATE u32 sqlite3BtreeLastPage(Btree *p){
    +   assert( sqlite3BtreeHoldsMutex(p) );
    +-  assert( ((p->pBt->nPage)&0x8000000)==0 );
    ++  assert( ((p->pBt->nPage)&0x80000000)==0 );
    +   return btreePagecount(p->pBt);
    + }
    + 
    +@@ -56471,7 +62498,7 @@ static int getAndInitPage(
    +   int rc;
    +   DbPage *pDbPage;
    +   assert( sqlite3_mutex_held(pBt->mutex) );
    +-  assert( pCur==0 || ppPage==&pCur->apPage[pCur->iPage] );
    ++  assert( pCur==0 || ppPage==&pCur->pPage );
    +   assert( pCur==0 || bReadOnly==pCur->curPagerFlags );
    +   assert( pCur==0 || pCur->iPage>0 );
    + 
    +@@ -56479,32 +62506,36 @@ static int getAndInitPage(
    +     rc = SQLITE_CORRUPT_BKPT;
    +     goto getAndInitPage_error;
    +   }
    +-  rc = sqlite3PagerAcquire(pBt->pPager, pgno, (DbPage**)&pDbPage, bReadOnly);
    ++  rc = sqlite3PagerGet(pBt->pPager, pgno, (DbPage**)&pDbPage, bReadOnly);
    +   if( rc ){
    +     goto getAndInitPage_error;
    +   }
    +-  *ppPage = btreePageFromDbPage(pDbPage, pgno, pBt);
    ++  *ppPage = (MemPage*)sqlite3PagerGetExtra(pDbPage);
    +   if( (*ppPage)->isInit==0 ){
    ++    btreePageFromDbPage(pDbPage, pgno, pBt);
    +     rc = btreeInitPage(*ppPage);
    +     if( rc!=SQLITE_OK ){
    +       releasePage(*ppPage);
    +       goto getAndInitPage_error;
    +     }
    +   }
    ++  assert( (*ppPage)->pgno==pgno );
    ++  assert( (*ppPage)->aData==sqlite3PagerGetData(pDbPage) );
    + 
    +   /* If obtaining a child page for a cursor, we must verify that the page is
    +   ** compatible with the root page. */
    +-  if( pCur
    +-   && ((*ppPage)->nCell<1 || (*ppPage)->intKey!=pCur->curIntKey)
    +-  ){
    +-    rc = SQLITE_CORRUPT_BKPT;
    ++  if( pCur && ((*ppPage)->nCell<1 || (*ppPage)->intKey!=pCur->curIntKey) ){
    ++    rc = SQLITE_CORRUPT_PGNO(pgno);
    +     releasePage(*ppPage);
    +     goto getAndInitPage_error;
    +   }
    +   return SQLITE_OK;
    + 
    + getAndInitPage_error:
    +-  if( pCur ) pCur->iPage--;
    ++  if( pCur ){
    ++    pCur->iPage--;
    ++    pCur->pPage = pCur->apPage[pCur->iPage];
    ++  }
    +   testcase( pgno==0 );
    +   assert( pgno!=0 || rc==SQLITE_CORRUPT );
    +   return rc;
    +@@ -56513,6 +62544,8 @@ getAndInitPage_error:
    + /*
    + ** Release a MemPage.  This should be called once for each prior
    + ** call to btreeGetPage.
    ++**
    ++** Page1 is a special case and must be released using releasePageOne().
    + */
    + static void releasePageNotNull(MemPage *pPage){
    +   assert( pPage->aData );
    +@@ -56526,6 +62559,16 @@ static void releasePageNotNull(MemPage *pPage){
    + static void releasePage(MemPage *pPage){
    +   if( pPage ) releasePageNotNull(pPage);
    + }
    ++static void releasePageOne(MemPage *pPage){
    ++  assert( pPage!=0 );
    ++  assert( pPage->aData );
    ++  assert( pPage->pBt );
    ++  assert( pPage->pDbPage!=0 );
    ++  assert( sqlite3PagerGetExtra(pPage->pDbPage) == (void*)pPage );
    ++  assert( sqlite3PagerGetData(pPage->pDbPage)==pPage->aData );
    ++  assert( sqlite3_mutex_held(pPage->pBt->mutex) );
    ++  sqlite3PagerUnrefPageOne(pPage->pDbPage);
    ++}
    + 
    + /*
    + ** Get an unused page.
    +@@ -56663,7 +62706,7 @@ SQLITE_PRIVATE int sqlite3BtreeOpen(
    +   }
    +   p = sqlite3MallocZero(sizeof(Btree));
    +   if( !p ){
    +-    return SQLITE_NOMEM;
    ++    return SQLITE_NOMEM_BKPT;
    +   }
    +   p->inTrans = TRANS_NONE;
    +   p->db = db;
    +@@ -56687,7 +62730,7 @@ SQLITE_PRIVATE int sqlite3BtreeOpen(
    +       p->sharable = 1;
    +       if( !zFullPathname ){
    +         sqlite3_free(p);
    +-        return SQLITE_NOMEM;
    ++        return SQLITE_NOMEM_BKPT;
    +       }
    +       if( isMemdb ){
    +         memcpy(zFullPathname, zFilename, nFilename);
    +@@ -56755,11 +62798,11 @@ SQLITE_PRIVATE int sqlite3BtreeOpen(
    +   
    +     pBt = sqlite3MallocZero( sizeof(*pBt) );
    +     if( pBt==0 ){
    +-      rc = SQLITE_NOMEM;
    ++      rc = SQLITE_NOMEM_BKPT;
    +       goto btree_open_out;
    +     }
    +     rc = sqlite3PagerOpen(pVfs, &pBt->pPager, zFilename,
    +-                          EXTRA_SIZE, flags, vfsFlags, pageReinit);
    ++                          sizeof(MemPage), flags, vfsFlags, pageReinit);
    +     if( rc==SQLITE_OK ){
    +       sqlite3PagerSetMmapLimit(pBt->pPager, db->szMmap);
    +       rc = sqlite3PagerReadFileheader(pBt->pPager,sizeof(zDbHeader),zDbHeader);
    +@@ -56775,8 +62818,10 @@ SQLITE_PRIVATE int sqlite3BtreeOpen(
    +     pBt->pCursor = 0;
    +     pBt->pPage1 = 0;
    +     if( sqlite3PagerIsreadonly(pBt->pPager) ) pBt->btsFlags |= BTS_READ_ONLY;
    +-#ifdef SQLITE_SECURE_DELETE
    ++#if defined(SQLITE_SECURE_DELETE)
    +     pBt->btsFlags |= BTS_SECURE_DELETE;
    ++#elif defined(SQLITE_FAST_SECURE_DELETE)
    ++    pBt->btsFlags |= BTS_OVERWRITE;
    + #endif
    +     /* EVIDENCE-OF: R-51873-39618 The page size for a database file is
    +     ** determined by the 2-byte integer located at an offset of 16 bytes from
    +@@ -56817,15 +62862,14 @@ SQLITE_PRIVATE int sqlite3BtreeOpen(
    + #if !defined(SQLITE_OMIT_SHARED_CACHE) && !defined(SQLITE_OMIT_DISKIO)
    +     /* Add the new BtShared object to the linked list sharable BtShareds.
    +     */
    ++    pBt->nRef = 1;
    +     if( p->sharable ){
    +       MUTEX_LOGIC( sqlite3_mutex *mutexShared; )
    +-      pBt->nRef = 1;
    +       MUTEX_LOGIC( mutexShared = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MASTER);)
    +       if( SQLITE_THREADSAFE && sqlite3GlobalConfig.bCoreMutex ){
    +         pBt->mutex = sqlite3MutexAlloc(SQLITE_MUTEX_FAST);
    +         if( pBt->mutex==0 ){
    +-          rc = SQLITE_NOMEM;
    +-          db->mallocFailed = 0;
    ++          rc = SQLITE_NOMEM_BKPT;
    +           goto btree_open_out;
    +         }
    +       }
    +@@ -56848,12 +62892,12 @@ SQLITE_PRIVATE int sqlite3BtreeOpen(
    +     for(i=0; i<db->nDb; i++){
    +       if( (pSib = db->aDb[i].pBt)!=0 && pSib->sharable ){
    +         while( pSib->pPrev ){ pSib = pSib->pPrev; }
    +-        if( p->pBt<pSib->pBt ){
    ++        if( (uptr)p->pBt<(uptr)pSib->pBt ){
    +           p->pNext = pSib;
    +           p->pPrev = 0;
    +           pSib->pPrev = p;
    +         }else{
    +-          while( pSib->pNext && pSib->pNext->pBt<p->pBt ){
    ++          while( pSib->pNext && (uptr)pSib->pNext->pBt<(uptr)p->pBt ){
    +             pSib = pSib->pNext;
    +           }
    +           p->pNext = pSib->pNext;
    +@@ -56873,12 +62917,14 @@ SQLITE_PRIVATE int sqlite3BtreeOpen(
    + btree_open_out:
    +   if( rc!=SQLITE_OK ){
    +     if( pBt && pBt->pPager ){
    +-      sqlite3PagerClose(pBt->pPager);
    ++      sqlite3PagerClose(pBt->pPager, 0);
    +     }
    +     sqlite3_free(pBt);
    +     sqlite3_free(p);
    +     *ppBtree = 0;
    +   }else{
    ++    sqlite3_file *pFile;
    ++
    +     /* If the B-Tree was successfully opened, set the pager-cache size to the
    +     ** default value. Except, when opening on an existing shared pager-cache,
    +     ** do not change the pager-cache size.
    +@@ -56886,11 +62932,17 @@ btree_open_out:
    +     if( sqlite3BtreeSchema(p, 0, 0)==0 ){
    +       sqlite3PagerSetCachesize(p->pBt->pPager, SQLITE_DEFAULT_CACHE_SIZE);
    +     }
    ++
    ++    pFile = sqlite3PagerFile(pBt->pPager);
    ++    if( pFile->pMethods ){
    ++      sqlite3OsFileControlHint(pFile, SQLITE_FCNTL_PDB, (void*)&pBt->db);
    ++    }
    +   }
    +   if( mutexOpen ){
    +     assert( sqlite3_mutex_held(mutexOpen) );
    +     sqlite3_mutex_leave(mutexOpen);
    +   }
    ++  assert( rc!=SQLITE_OK || sqlite3BtreeConnectionCount(*ppBtree)>0 );
    +   return rc;
    + }
    + 
    +@@ -57014,7 +63066,7 @@ SQLITE_PRIVATE int sqlite3BtreeClose(Btree *p){
    +     ** Clean out and delete the BtShared object.
    +     */
    +     assert( !pBt->pCursor );
    +-    sqlite3PagerClose(pBt->pPager);
    ++    sqlite3PagerClose(pBt->pPager, p->db);
    +     if( pBt->xFreeSchema && pBt->pSchema ){
    +       pBt->xFreeSchema(pBt->pSchema);
    +     }
    +@@ -57035,19 +63087,11 @@ SQLITE_PRIVATE int sqlite3BtreeClose(Btree *p){
    + }
    + 
    + /*
    +-** Change the limit on the number of pages allowed in the cache.
    +-**
    +-** The maximum number of cache pages is set to the absolute
    +-** value of mxPage.  If mxPage is negative, the pager will
    +-** operate asynchronously - it will not stop to do fsync()s
    +-** to insure data is written to the disk surface before
    +-** continuing.  Transactions still work if synchronous is off,
    +-** and the database cannot be corrupted if this program
    +-** crashes.  But if the operating system crashes or there is
    +-** an abrupt power failure when synchronous is off, the database
    +-** could be left in an inconsistent and unrecoverable state.
    +-** Synchronous is on by default so database corruption is not
    +-** normally a worry.
    ++** Change the "soft" limit on the number of pages in the cache.
    ++** Unused and unmodified pages will be recycled when the number of
    ++** pages in the cache exceeds this soft limit.  But the size of the
    ++** cache is allowed to grow larger than this limit if it contains
    ++** dirty pages or pages still in active use.
    + */
    + SQLITE_PRIVATE int sqlite3BtreeSetCacheSize(Btree *p, int mxPage){
    +   BtShared *pBt = p->pBt;
    +@@ -57058,6 +63102,26 @@ SQLITE_PRIVATE int sqlite3BtreeSetCacheSize(Btree *p, int mxPage){
    +   return SQLITE_OK;
    + }
    + 
    ++/*
    ++** Change the "spill" limit on the number of pages in the cache.
    ++** If the number of pages exceeds this limit during a write transaction,
    ++** the pager might attempt to "spill" pages to the journal early in
    ++** order to free up memory.
    ++**
    ++** The value returned is the current spill size.  If zero is passed
    ++** as an argument, no changes are made to the spill size setting, so
    ++** using mxPage of 0 is a way to query the current spill size.
    ++*/
    ++SQLITE_PRIVATE int sqlite3BtreeSetSpillSize(Btree *p, int mxPage){
    ++  BtShared *pBt = p->pBt;
    ++  int res;
    ++  assert( sqlite3_mutex_held(p->db->mutex) );
    ++  sqlite3BtreeEnter(p);
    ++  res = sqlite3PagerSetSpillsize(pBt->pPager, mxPage);
    ++  sqlite3BtreeLeave(p);
    ++  return res;
    ++}
    ++
    + #if SQLITE_MAX_MMAP_SIZE>0
    + /*
    + ** Change the limit on the amount of the database file that may be
    +@@ -57095,21 +63159,6 @@ SQLITE_PRIVATE int sqlite3BtreeSetPagerFlags(
    + }
    + #endif
    + 
    +-/*
    +-** Return TRUE if the given btree is set to safety level 1.  In other
    +-** words, return TRUE if no sync() occurs on the disk files.
    +-*/
    +-SQLITE_PRIVATE int sqlite3BtreeSyncDisabled(Btree *p){
    +-  BtShared *pBt = p->pBt;
    +-  int rc;
    +-  assert( sqlite3_mutex_held(p->db->mutex) );  
    +-  sqlite3BtreeEnter(p);
    +-  assert( pBt && pBt->pPager );
    +-  rc = sqlite3PagerNosync(pBt->pPager);
    +-  sqlite3BtreeLeave(p);
    +-  return rc;
    +-}
    +-
    + /*
    + ** Change the default pages size and the number of reserved bytes per page.
    + ** Or, if the page size has already been fixed, return SQLITE_READONLY 
    +@@ -57220,19 +63269,34 @@ SQLITE_PRIVATE int sqlite3BtreeMaxPageCount(Btree *p, int mxPage){
    + }
    + 
    + /*
    +-** Set the BTS_SECURE_DELETE flag if newFlag is 0 or 1.  If newFlag is -1,
    +-** then make no changes.  Always return the value of the BTS_SECURE_DELETE
    +-** setting after the change.
    ++** Change the values for the BTS_SECURE_DELETE and BTS_OVERWRITE flags:
    ++**
    ++**    newFlag==0       Both BTS_SECURE_DELETE and BTS_OVERWRITE are cleared
    ++**    newFlag==1       BTS_SECURE_DELETE set and BTS_OVERWRITE is cleared
    ++**    newFlag==2       BTS_SECURE_DELETE cleared and BTS_OVERWRITE is set
    ++**    newFlag==(-1)    No changes
    ++**
    ++** This routine acts as a query if newFlag is less than zero
    ++**
    ++** With BTS_OVERWRITE set, deleted content is overwritten by zeros, but
    ++** freelist leaf pages are not written back to the database.  Thus in-page
    ++** deleted content is cleared, but freelist deleted content is not.
    ++**
    ++** With BTS_SECURE_DELETE, operation is like BTS_OVERWRITE with the addition
    ++** that freelist leaf pages are written back into the database, increasing
    ++** the amount of disk I/O.
    + */
    + SQLITE_PRIVATE int sqlite3BtreeSecureDelete(Btree *p, int newFlag){
    +   int b;
    +   if( p==0 ) return 0;
    +   sqlite3BtreeEnter(p);
    ++  assert( BTS_OVERWRITE==BTS_SECURE_DELETE*2 );
    ++  assert( BTS_FAST_SECURE==(BTS_OVERWRITE|BTS_SECURE_DELETE) );
    +   if( newFlag>=0 ){
    +-    p->pBt->btsFlags &= ~BTS_SECURE_DELETE;
    +-    if( newFlag ) p->pBt->btsFlags |= BTS_SECURE_DELETE;
    +-  } 
    +-  b = (p->pBt->btsFlags & BTS_SECURE_DELETE)!=0;
    ++    p->pBt->btsFlags &= ~BTS_FAST_SECURE;
    ++    p->pBt->btsFlags |= BTS_SECURE_DELETE*newFlag;
    ++  }
    ++  b = (p->pBt->btsFlags & BTS_FAST_SECURE)/BTS_SECURE_DELETE;
    +   sqlite3BtreeLeave(p);
    +   return b;
    + }
    +@@ -57283,6 +63347,32 @@ SQLITE_PRIVATE int sqlite3BtreeGetAutoVacuum(Btree *p){
    + #endif
    + }
    + 
    ++/*
    ++** If the user has not set the safety-level for this database connection
    ++** using "PRAGMA synchronous", and if the safety-level is not already
    ++** set to the value passed to this function as the second parameter,
    ++** set it so.
    ++*/
    ++#if SQLITE_DEFAULT_SYNCHRONOUS!=SQLITE_DEFAULT_WAL_SYNCHRONOUS \
    ++    && !defined(SQLITE_OMIT_WAL)
    ++static void setDefaultSyncFlag(BtShared *pBt, u8 safety_level){
    ++  sqlite3 *db;
    ++  Db *pDb;
    ++  if( (db=pBt->db)!=0 && (pDb=db->aDb)!=0 ){
    ++    while( pDb->pBt==0 || pDb->pBt->pBt!=pBt ){ pDb++; }
    ++    if( pDb->bSyncSet==0 
    ++     && pDb->safety_level!=safety_level 
    ++     && pDb!=&db->aDb[1] 
    ++    ){
    ++      pDb->safety_level = safety_level;
    ++      sqlite3PagerSetFlags(pBt->pPager,
    ++          pDb->safety_level | (db->flags & PAGER_FLAGS_MASK));
    ++    }
    ++  }
    ++}
    ++#else
    ++# define setDefaultSyncFlag(pBt,safety_level)
    ++#endif
    + 
    + /*
    + ** Get a reference to pPage1 of the database file.  This will
    +@@ -57355,11 +63445,16 @@ static int lockBtree(BtShared *pBt){
    +       rc = sqlite3PagerOpenWal(pBt->pPager, &isOpen);
    +       if( rc!=SQLITE_OK ){
    +         goto page1_init_failed;
    +-      }else if( isOpen==0 ){
    +-        releasePage(pPage1);
    +-        return SQLITE_OK;
    ++      }else{
    ++        setDefaultSyncFlag(pBt, SQLITE_DEFAULT_WAL_SYNCHRONOUS+1);
    ++        if( isOpen==0 ){
    ++          releasePageOne(pPage1);
    ++          return SQLITE_OK;
    ++        }
    +       }
    +       rc = SQLITE_NOTADB;
    ++    }else{
    ++      setDefaultSyncFlag(pBt, SQLITE_DEFAULT_SYNCHRONOUS+1);
    +     }
    + #endif
    + 
    +@@ -57400,7 +63495,7 @@ static int lockBtree(BtShared *pBt){
    +       ** zero and return SQLITE_OK. The caller will call this function
    +       ** again with the correct page-size.
    +       */
    +-      releasePage(pPage1);
    ++      releasePageOne(pPage1);
    +       pBt->usableSize = usableSize;
    +       pBt->pageSize = pageSize;
    +       freeTempSpace(pBt);
    +@@ -57408,7 +63503,7 @@ static int lockBtree(BtShared *pBt){
    +                                    pageSize-usableSize);
    +       return rc;
    +     }
    +-    if( (pBt->db->flags & SQLITE_RecoveryMode)==0 && nPage>nPageFile ){
    ++    if( (pBt->db->flags & SQLITE_WriteSchema)==0 && nPage>nPageFile ){
    +       rc = SQLITE_CORRUPT_BKPT;
    +       goto page1_init_failed;
    +     }
    +@@ -57454,7 +63549,7 @@ static int lockBtree(BtShared *pBt){
    +   return SQLITE_OK;
    + 
    + page1_init_failed:
    +-  releasePage(pPage1);
    ++  releasePageOne(pPage1);
    +   pBt->pPage1 = 0;
    +   return rc;
    + }
    +@@ -57499,7 +63594,7 @@ static void unlockBtreeIfUnused(BtShared *pBt){
    +     assert( pPage1->aData );
    +     assert( sqlite3PagerRefcount(pBt->pPager)==1 );
    +     pBt->pPage1 = 0;
    +-    releasePageNotNull(pPage1);
    ++    releasePageOne(pPage1);
    +   }
    + }
    + 
    +@@ -57597,7 +63692,6 @@ SQLITE_PRIVATE int sqlite3BtreeNewDb(Btree *p){
    + ** proceed.
    + */
    + SQLITE_PRIVATE int sqlite3BtreeBeginTrans(Btree *p, int wrflag){
    +-  sqlite3 *pBlock = 0;
    +   BtShared *pBt = p->pBt;
    +   int rc = SQLITE_OK;
    + 
    +@@ -57620,27 +63714,30 @@ SQLITE_PRIVATE int sqlite3BtreeBeginTrans(Btree *p, int wrflag){
    +   }
    + 
    + #ifndef SQLITE_OMIT_SHARED_CACHE
    +-  /* If another database handle has already opened a write transaction 
    +-  ** on this shared-btree structure and a second write transaction is
    +-  ** requested, return SQLITE_LOCKED.
    +-  */
    +-  if( (wrflag && pBt->inTransaction==TRANS_WRITE)
    +-   || (pBt->btsFlags & BTS_PENDING)!=0
    +-  ){
    +-    pBlock = pBt->pWriter->db;
    +-  }else if( wrflag>1 ){
    +-    BtLock *pIter;
    +-    for(pIter=pBt->pLock; pIter; pIter=pIter->pNext){
    +-      if( pIter->pBtree!=p ){
    +-        pBlock = pIter->pBtree->db;
    +-        break;
    ++  {
    ++    sqlite3 *pBlock = 0;
    ++    /* If another database handle has already opened a write transaction 
    ++    ** on this shared-btree structure and a second write transaction is
    ++    ** requested, return SQLITE_LOCKED.
    ++    */
    ++    if( (wrflag && pBt->inTransaction==TRANS_WRITE)
    ++     || (pBt->btsFlags & BTS_PENDING)!=0
    ++    ){
    ++      pBlock = pBt->pWriter->db;
    ++    }else if( wrflag>1 ){
    ++      BtLock *pIter;
    ++      for(pIter=pBt->pLock; pIter; pIter=pIter->pNext){
    ++        if( pIter->pBtree!=p ){
    ++          pBlock = pIter->pBtree->db;
    ++          break;
    ++        }
    +       }
    +     }
    +-  }
    +-  if( pBlock ){
    +-    sqlite3ConnectionBlocked(p->db, pBlock);
    +-    rc = SQLITE_LOCKED_SHAREDCACHE;
    +-    goto trans_begun;
    ++    if( pBlock ){
    ++      sqlite3ConnectionBlocked(p->db, pBlock);
    ++      rc = SQLITE_LOCKED_SHAREDCACHE;
    ++      goto trans_begun;
    ++    }
    +   }
    + #endif
    + 
    +@@ -57746,14 +63843,11 @@ static int setChildPtrmaps(MemPage *pPage){
    +   int nCell;                         /* Number of cells in page pPage */
    +   int rc;                            /* Return code */
    +   BtShared *pBt = pPage->pBt;
    +-  u8 isInitOrig = pPage->isInit;
    +   Pgno pgno = pPage->pgno;
    + 
    +   assert( sqlite3_mutex_held(pPage->pBt->mutex) );
    +-  rc = btreeInitPage(pPage);
    +-  if( rc!=SQLITE_OK ){
    +-    goto set_child_ptrmaps_out;
    +-  }
    ++  rc = pPage->isInit ? SQLITE_OK : btreeInitPage(pPage);
    ++  if( rc!=SQLITE_OK ) return rc;
    +   nCell = pPage->nCell;
    + 
    +   for(i=0; i<nCell; i++){
    +@@ -57772,8 +63866,6 @@ static int setChildPtrmaps(MemPage *pPage){
    +     ptrmapPut(pBt, childPgno, PTRMAP_BTREE, pgno, &rc);
    +   }
    + 
    +-set_child_ptrmaps_out:
    +-  pPage->isInit = isInitOrig;
    +   return rc;
    + }
    + 
    +@@ -57797,16 +63889,15 @@ static int modifyPagePointer(MemPage *pPage, Pgno iFrom, Pgno iTo, u8 eType){
    +   if( eType==PTRMAP_OVERFLOW2 ){
    +     /* The pointer is always the first 4 bytes of the page in this case.  */
    +     if( get4byte(pPage->aData)!=iFrom ){
    +-      return SQLITE_CORRUPT_BKPT;
    ++      return SQLITE_CORRUPT_PAGE(pPage);
    +     }
    +     put4byte(pPage->aData, iTo);
    +   }else{
    +-    u8 isInitOrig = pPage->isInit;
    +     int i;
    +     int nCell;
    +     int rc;
    + 
    +-    rc = btreeInitPage(pPage);
    ++    rc = pPage->isInit ? SQLITE_OK : btreeInitPage(pPage);
    +     if( rc ) return rc;
    +     nCell = pPage->nCell;
    + 
    +@@ -57815,12 +63906,14 @@ static int modifyPagePointer(MemPage *pPage, Pgno iFrom, Pgno iTo, u8 eType){
    +       if( eType==PTRMAP_OVERFLOW1 ){
    +         CellInfo info;
    +         pPage->xParseCell(pPage, pCell, &info);
    +-        if( info.iOverflow
    +-         && pCell+info.iOverflow+3<=pPage->aData+pPage->maskPage
    +-         && iFrom==get4byte(&pCell[info.iOverflow])
    +-        ){
    +-          put4byte(&pCell[info.iOverflow], iTo);
    +-          break;
    ++        if( info.nLocal<info.nPayload ){
    ++          if( pCell+info.nSize > pPage->aData+pPage->pBt->usableSize ){
    ++            return SQLITE_CORRUPT_PAGE(pPage);
    ++          }
    ++          if( iFrom==get4byte(pCell+info.nSize-4) ){
    ++            put4byte(pCell+info.nSize-4, iTo);
    ++            break;
    ++          }
    +         }
    +       }else{
    +         if( get4byte(pCell)==iFrom ){
    +@@ -57833,12 +63926,10 @@ static int modifyPagePointer(MemPage *pPage, Pgno iFrom, Pgno iTo, u8 eType){
    +     if( i==nCell ){
    +       if( eType!=PTRMAP_BTREE || 
    +           get4byte(&pPage->aData[pPage->hdrOffset+8])!=iFrom ){
    +-        return SQLITE_CORRUPT_BKPT;
    ++        return SQLITE_CORRUPT_PAGE(pPage);
    +       }
    +       put4byte(&pPage->aData[pPage->hdrOffset+8], iTo);
    +     }
    +-
    +-    pPage->isInit = isInitOrig;
    +   }
    +   return SQLITE_OK;
    + }
    +@@ -58355,7 +64446,6 @@ SQLITE_PRIVATE int sqlite3BtreeTripAllCursors(Btree *pBtree, int errCode, int wr
    +   if( pBtree ){
    +     sqlite3BtreeEnter(pBtree);
    +     for(p=pBtree->pBt->pCursor; p; p=p->pNext){
    +-      int i;
    +       if( writeOnly && (p->curFlags & BTCF_WriteFlag)==0 ){
    +         if( p->eState==CURSOR_VALID || p->eState==CURSOR_SKIPNEXT ){
    +           rc = saveCursorPosition(p);
    +@@ -58369,10 +64459,7 @@ SQLITE_PRIVATE int sqlite3BtreeTripAllCursors(Btree *pBtree, int errCode, int wr
    +         p->eState = CURSOR_FAULT;
    +         p->skipNext = errCode;
    +       }
    +-      for(i=0; i<=p->iPage; i++){
    +-        releasePage(p->apPage[i]);
    +-        p->apPage[i] = 0;
    +-      }
    ++      btreeReleaseAllCursorPages(p);
    +     }
    +     sqlite3BtreeLeave(pBtree);
    +   }
    +@@ -58429,7 +64516,7 @@ SQLITE_PRIVATE int sqlite3BtreeRollback(Btree *p, int tripCode, int writeOnly){
    +       if( nPage==0 ) sqlite3PagerPagecount(pBt->pPager, &nPage);
    +       testcase( pBt->nPage!=nPage );
    +       pBt->nPage = nPage;
    +-      releasePage(pPage1);
    ++      releasePageOne(pPage1);
    +     }
    +     assert( countValidCursors(pBt, 1)==0 );
    +     pBt->inTransaction = TRANS_READ;
    +@@ -58497,7 +64584,12 @@ SQLITE_PRIVATE int sqlite3BtreeSavepoint(Btree *p, int op, int iSavepoint){
    +     assert( op==SAVEPOINT_RELEASE || op==SAVEPOINT_ROLLBACK );
    +     assert( iSavepoint>=0 || (iSavepoint==-1 && op==SAVEPOINT_ROLLBACK) );
    +     sqlite3BtreeEnter(p);
    +-    rc = sqlite3PagerSavepoint(pBt->pPager, op, iSavepoint);
    ++    if( op==SAVEPOINT_ROLLBACK ){
    ++      rc = saveAllCursors(pBt, 0, 0);
    ++    }
    ++    if( rc==SQLITE_OK ){
    ++      rc = sqlite3PagerSavepoint(pBt->pPager, op, iSavepoint);
    ++    }
    +     if( rc==SQLITE_OK ){
    +       if( iSavepoint<0 && (pBt->btsFlags & BTS_INITIALLY_EMPTY)!=0 ){
    +         pBt->nPage = 0;
    +@@ -58522,13 +64614,13 @@ SQLITE_PRIVATE int sqlite3BtreeSavepoint(Btree *p, int op, int iSavepoint){
    + ** on the database already. If a write-cursor is requested, then
    + ** the caller is assumed to have an open write transaction.
    + **
    +-** If wrFlag==0, then the cursor can only be used for reading.
    +-** If wrFlag==1, then the cursor can be used for reading or for
    +-** writing if other conditions for writing are also met.  These
    +-** are the conditions that must be met in order for writing to
    +-** be allowed:
    ++** If the BTREE_WRCSR bit of wrFlag is clear, then the cursor can only
    ++** be used for reading.  If the BTREE_WRCSR bit is set, then the cursor
    ++** can be used for reading or for writing if other conditions for writing
    ++** are also met.  These are the conditions that must be met in order
    ++** for writing to be allowed:
    + **
    +-** 1:  The cursor must have been opened with wrFlag==1
    ++** 1:  The cursor must have been opened with wrFlag containing BTREE_WRCSR
    + **
    + ** 2:  Other database connections that share the same pager cache
    + **     but which are not in the READ_UNCOMMITTED state may not have
    +@@ -58540,6 +64632,16 @@ SQLITE_PRIVATE int sqlite3BtreeSavepoint(Btree *p, int op, int iSavepoint){
    + **
    + ** 4:  There must be an active transaction.
    + **
    ++** The BTREE_FORDELETE bit of wrFlag may optionally be set if BTREE_WRCSR
    ++** is set.  If FORDELETE is set, that is a hint to the implementation that
    ++** this cursor will only be used to seek to and delete entries of an index
    ++** as part of a larger DELETE statement.  The FORDELETE hint is not used by
    ++** this implementation.  But in a hypothetical alternative storage engine 
    ++** in which index entries are automatically deleted when corresponding table
    ++** rows are deleted, the FORDELETE flag is a hint that all SEEK and DELETE
    ++** operations on this cursor can be no-ops and all READ operations can 
    ++** return a null row (2-bytes: 0x01 0x00).
    ++**
    + ** No checking is done to make sure that page iTable really is the
    + ** root page of a b-tree.  If it is not, then the cursor acquired
    + ** will not work correctly.
    +@@ -58558,13 +64660,16 @@ static int btreeCursor(
    +   BtCursor *pX;                          /* Looping over other all cursors */
    + 
    +   assert( sqlite3BtreeHoldsMutex(p) );
    +-  assert( wrFlag==0 || wrFlag==1 );
    ++  assert( wrFlag==0 
    ++       || wrFlag==BTREE_WRCSR 
    ++       || wrFlag==(BTREE_WRCSR|BTREE_FORDELETE) 
    ++  );
    + 
    +   /* The following assert statements verify that if this is a sharable 
    +   ** b-tree database, the connection is holding the required table locks, 
    +   ** and that no other connection has any open cursor that conflicts with 
    +   ** this lock.  */
    +-  assert( hasSharedCacheTableLock(p, iTable, pKeyInfo!=0, wrFlag+1) );
    ++  assert( hasSharedCacheTableLock(p, iTable, pKeyInfo!=0, (wrFlag?2:1)) );
    +   assert( wrFlag==0 || !hasReadConflicts(p, iTable) );
    + 
    +   /* Assert that the caller has opened the required transaction. */
    +@@ -58575,7 +64680,7 @@ static int btreeCursor(
    + 
    +   if( wrFlag ){
    +     allocateTempSpace(pBt);
    +-    if( pBt->pTmpSpace==0 ) return SQLITE_NOMEM;
    ++    if( pBt->pTmpSpace==0 ) return SQLITE_NOMEM_BKPT;
    +   }
    +   if( iTable==1 && btreePagecount(pBt)==0 ){
    +     assert( wrFlag==0 );
    +@@ -58589,8 +64694,7 @@ static int btreeCursor(
    +   pCur->pKeyInfo = pKeyInfo;
    +   pCur->pBtree = p;
    +   pCur->pBt = pBt;
    +-  assert( wrFlag==0 || wrFlag==BTCF_WriteFlag );
    +-  pCur->curFlags = wrFlag;
    ++  pCur->curFlags = wrFlag ? BTCF_WriteFlag : 0;
    +   pCur->curPagerFlags = wrFlag ? 0 : PAGER_GET_READONLY;
    +   /* If there are two or more cursors on the same btree, then all such
    +   ** cursors *must* have the BTCF_Multiple flag set. */
    +@@ -58654,10 +64758,8 @@ SQLITE_PRIVATE void sqlite3BtreeCursorZero(BtCursor *p){
    + SQLITE_PRIVATE int sqlite3BtreeCloseCursor(BtCursor *pCur){
    +   Btree *pBtree = pCur->pBtree;
    +   if( pBtree ){
    +-    int i;
    +     BtShared *pBt = pCur->pBt;
    +     sqlite3BtreeEnter(pBtree);
    +-    sqlite3BtreeClearCursor(pCur);
    +     assert( pBt->pCursor!=0 );
    +     if( pBt->pCursor==pCur ){
    +       pBt->pCursor = pCur->pNext;
    +@@ -58671,12 +64773,10 @@ SQLITE_PRIVATE int sqlite3BtreeCloseCursor(BtCursor *pCur){
    +         pPrev = pPrev->pNext;
    +       }while( ALWAYS(pPrev) );
    +     }
    +-    for(i=0; i<=pCur->iPage; i++){
    +-      releasePage(pCur->apPage[i]);
    +-    }
    ++    btreeReleaseAllCursorPages(pCur);
    +     unlockBtreeIfUnused(pBt);
    +     sqlite3_free(pCur->aOverflow);
    +-    /* sqlite3_free(pCur); */
    ++    sqlite3_free(pCur->pKey);
    +     sqlite3BtreeLeave(pBtree);
    +   }
    +   return SQLITE_OK;
    +@@ -58693,9 +64793,8 @@ SQLITE_PRIVATE int sqlite3BtreeCloseCursor(BtCursor *pCur){
    + #ifndef NDEBUG
    +   static void assertCellInfo(BtCursor *pCur){
    +     CellInfo info;
    +-    int iPage = pCur->iPage;
    +     memset(&info, 0, sizeof(info));
    +-    btreeParseCell(pCur->apPage[iPage], pCur->aiIdx[iPage], &info);
    ++    btreeParseCell(pCur->pPage, pCur->ix, &info);
    +     assert( CORRUPT_DB || memcmp(&info, &pCur->info, sizeof(info))==0 );
    +   }
    + #else
    +@@ -58703,9 +64802,8 @@ SQLITE_PRIVATE int sqlite3BtreeCloseCursor(BtCursor *pCur){
    + #endif
    + static SQLITE_NOINLINE void getCellInfo(BtCursor *pCur){
    +   if( pCur->info.nSize==0 ){
    +-    int iPage = pCur->iPage;
    +     pCur->curFlags |= BTCF_ValidNKey;
    +-    btreeParseCell(pCur->apPage[iPage],pCur->aiIdx[iPage],&pCur->info);
    ++    btreeParseCell(pCur->pPage,pCur->ix,&pCur->info);
    +   }else{
    +     assertCellInfo(pCur);
    +   }
    +@@ -58721,48 +64819,53 @@ SQLITE_PRIVATE int sqlite3BtreeCursorIsValid(BtCursor *pCur){
    +   return pCur && pCur->eState==CURSOR_VALID;
    + }
    + #endif /* NDEBUG */
    ++SQLITE_PRIVATE int sqlite3BtreeCursorIsValidNN(BtCursor *pCur){
    ++  assert( pCur!=0 );
    ++  return pCur->eState==CURSOR_VALID;
    ++}
    + 
    + /*
    +-** Set *pSize to the size of the buffer needed to hold the value of
    +-** the key for the current entry.  If the cursor is not pointing
    +-** to a valid entry, *pSize is set to 0. 
    +-**
    +-** For a table with the INTKEY flag set, this routine returns the key
    +-** itself, not the number of bytes in the key.
    +-**
    +-** The caller must position the cursor prior to invoking this routine.
    +-** 
    +-** This routine cannot fail.  It always returns SQLITE_OK.  
    ++** Return the value of the integer key or "rowid" for a table btree.
    ++** This routine is only valid for a cursor that is pointing into a
    ++** ordinary table btree.  If the cursor points to an index btree or
    ++** is invalid, the result of this routine is undefined.
    + */
    +-SQLITE_PRIVATE int sqlite3BtreeKeySize(BtCursor *pCur, i64 *pSize){
    ++SQLITE_PRIVATE i64 sqlite3BtreeIntegerKey(BtCursor *pCur){
    +   assert( cursorHoldsMutex(pCur) );
    +   assert( pCur->eState==CURSOR_VALID );
    ++  assert( pCur->curIntKey );
    +   getCellInfo(pCur);
    +-  *pSize = pCur->info.nKey;
    +-  return SQLITE_OK;
    ++  return pCur->info.nKey;
    ++}
    ++
    ++#ifdef SQLITE_ENABLE_OFFSET_SQL_FUNC
    ++/*
    ++** Return the offset into the database file for the start of the
    ++** payload to which the cursor is pointing.
    ++*/
    ++SQLITE_PRIVATE i64 sqlite3BtreeOffset(BtCursor *pCur){
    ++  assert( cursorHoldsMutex(pCur) );
    ++  assert( pCur->eState==CURSOR_VALID );
    ++  getCellInfo(pCur);
    ++  return (i64)pCur->pBt->pageSize*((i64)pCur->pPage->pgno - 1) +
    ++         (i64)(pCur->info.pPayload - pCur->pPage->aData);
    + }
    ++#endif /* SQLITE_ENABLE_OFFSET_SQL_FUNC */
    + 
    + /*
    +-** Set *pSize to the number of bytes of data in the entry the
    +-** cursor currently points to.
    ++** Return the number of bytes of payload for the entry that pCur is
    ++** currently pointing to.  For table btrees, this will be the amount
    ++** of data.  For index btrees, this will be the size of the key.
    + **
    + ** The caller must guarantee that the cursor is pointing to a non-NULL
    + ** valid entry.  In other words, the calling procedure must guarantee
    + ** that the cursor has Cursor.eState==CURSOR_VALID.
    +-**
    +-** Failure is not possible.  This function always returns SQLITE_OK.
    +-** It might just as well be a procedure (returning void) but we continue
    +-** to return an integer result code for historical reasons.
    + */
    +-SQLITE_PRIVATE int sqlite3BtreeDataSize(BtCursor *pCur, u32 *pSize){
    ++SQLITE_PRIVATE u32 sqlite3BtreePayloadSize(BtCursor *pCur){
    +   assert( cursorHoldsMutex(pCur) );
    +   assert( pCur->eState==CURSOR_VALID );
    +-  assert( pCur->iPage>=0 );
    +-  assert( pCur->iPage<BTCURSOR_MAX_DEPTH );
    +-  assert( pCur->apPage[pCur->iPage]->intKeyLeaf==1 );
    +   getCellInfo(pCur);
    +-  *pSize = pCur->info.nPayload;
    +-  return SQLITE_OK;
    ++  return pCur->info.nPayload;
    + }
    + 
    + /*
    +@@ -58880,7 +64983,6 @@ static int copyPayload(
    + **
    + **   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.
    +@@ -58888,13 +64990,13 @@ 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 current cursor entry uses one or more overflow pages and the
    +-** eOp argument is not 2, this function may allocate space for and lazily 
    +-** populates the overflow page-list cache array (BtCursor.aOverflow). 
    ++** If the current cursor entry uses one or more overflow pages
    ++** this function may allocate space for and lazily populate
    ++** 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
    ++** Once an overflow page-list cache has been allocated, it must be
    + ** invalidated if some other cursor writes to the same table, or if
    + ** the cursor is moved to a different row. Additionally, in auto-vacuum
    + ** mode, the following events may invalidate an overflow page-list cache.
    +@@ -58913,29 +65015,30 @@ static int accessPayload(
    +   unsigned char *aPayload;
    +   int rc = SQLITE_OK;
    +   int iIdx = 0;
    +-  MemPage *pPage = pCur->apPage[pCur->iPage]; /* Btree page of current entry */
    ++  MemPage *pPage = pCur->pPage;               /* Btree page of current entry */
    +   BtShared *pBt = pCur->pBt;                  /* Btree this cursor belongs to */
    + #ifdef SQLITE_DIRECT_OVERFLOW_READ
    +-  unsigned char * const pBufStart = pBuf;
    +-  int bEnd;                                 /* True if reading to end of data */
    ++  unsigned char * const pBufStart = pBuf;     /* Start of original out buffer */
    + #endif
    + 
    +   assert( pPage );
    ++  assert( eOp==0 || eOp==1 );
    +   assert( pCur->eState==CURSOR_VALID );
    +-  assert( pCur->aiIdx[pCur->iPage]<pPage->nCell );
    ++  assert( pCur->ix<pPage->nCell );
    +   assert( cursorHoldsMutex(pCur) );
    +-  assert( eOp!=2 || offset==0 );    /* Always start from beginning for eOp==2 */
    + 
    +   getCellInfo(pCur);
    +   aPayload = pCur->info.pPayload;
    +-#ifdef SQLITE_DIRECT_OVERFLOW_READ
    +-  bEnd = offset+amt==pCur->info.nPayload;
    +-#endif
    +   assert( offset+amt <= pCur->info.nPayload );
    + 
    +-  if( &aPayload[pCur->info.nLocal] > &pPage->aData[pBt->usableSize] ){
    +-    /* Trying to read or write past the end of the data is an error */
    +-    return SQLITE_CORRUPT_BKPT;
    ++  assert( aPayload > pPage->aData );
    ++  if( (uptr)(aPayload - pPage->aData) > (pBt->usableSize - pCur->info.nLocal) ){
    ++    /* Trying to read or write past the end of the data is an error.  The
    ++    ** conditional above is really:
    ++    **    &aPayload[pCur->info.nLocal] > &pPage->aData[pBt->usableSize]
    ++    ** but is recast into its current form to avoid integer overflow problems
    ++    */
    ++    return SQLITE_CORRUPT_PAGE(pPage);
    +   }
    + 
    +   /* Check if data must be read/written to/from the btree page itself. */
    +@@ -58944,7 +65047,7 @@ static int accessPayload(
    +     if( a+offset>pCur->info.nLocal ){
    +       a = pCur->info.nLocal - offset;
    +     }
    +-    rc = copyPayload(&aPayload[offset], pBuf, a, (eOp & 0x01), pPage->pDbPage);
    ++    rc = copyPayload(&aPayload[offset], pBuf, a, eOp, pPage->pDbPage);
    +     offset = 0;
    +     pBuf += a;
    +     amt -= a;
    +@@ -58960,51 +65063,46 @@ static int accessPayload(
    +     nextPage = get4byte(&aPayload[pCur->info.nLocal]);
    + 
    +     /* 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( eOp!=2 && (pCur->curFlags & BTCF_ValidOvfl)==0 ){
    ++    if( (pCur->curFlags & BTCF_ValidOvfl)==0 ){
    +       int nOvfl = (pCur->info.nPayload-pCur->info.nLocal+ovflSize-1)/ovflSize;
    +       if( nOvfl>pCur->nOvflAlloc ){
    +         Pgno *aNew = (Pgno*)sqlite3Realloc(
    +             pCur->aOverflow, nOvfl*2*sizeof(Pgno)
    +         );
    +         if( aNew==0 ){
    +-          rc = SQLITE_NOMEM;
    ++          return SQLITE_NOMEM_BKPT;
    +         }else{
    +           pCur->nOvflAlloc = nOvfl*2;
    +           pCur->aOverflow = aNew;
    +         }
    +       }
    +-      if( rc==SQLITE_OK ){
    +-        memset(pCur->aOverflow, 0, nOvfl*sizeof(Pgno));
    +-        pCur->curFlags |= BTCF_ValidOvfl;
    ++      memset(pCur->aOverflow, 0, nOvfl*sizeof(Pgno));
    ++      pCur->curFlags |= BTCF_ValidOvfl;
    ++    }else{
    ++      /* If the overflow page-list cache has been allocated and the
    ++      ** entry for the first required overflow page is valid, skip
    ++      ** directly to it.
    ++      */
    ++      if( pCur->aOverflow[offset/ovflSize] ){
    ++        iIdx = (offset/ovflSize);
    ++        nextPage = pCur->aOverflow[iIdx];
    ++        offset = (offset%ovflSize);
    +       }
    +     }
    + 
    +-    /* If the overflow page-list cache has been allocated and the
    +-    ** entry for the first required overflow page is valid, skip
    +-    ** directly to it.
    +-    */
    +-    if( (pCur->curFlags & BTCF_ValidOvfl)!=0
    +-     && pCur->aOverflow[offset/ovflSize]
    +-    ){
    +-      iIdx = (offset/ovflSize);
    +-      nextPage = pCur->aOverflow[iIdx];
    +-      offset = (offset%ovflSize);
    +-    }
    +-
    +-    for( ; rc==SQLITE_OK && amt>0 && nextPage; iIdx++){
    +-
    ++    assert( rc==SQLITE_OK && amt>0 );
    ++    while( nextPage ){
    +       /* If required, populate the overflow page-list cache. */
    +-      if( (pCur->curFlags & BTCF_ValidOvfl)!=0 ){
    +-        assert(!pCur->aOverflow[iIdx] || pCur->aOverflow[iIdx]==nextPage);
    +-        pCur->aOverflow[iIdx] = nextPage;
    +-      }
    ++      assert( pCur->aOverflow[iIdx]==0
    ++              || pCur->aOverflow[iIdx]==nextPage
    ++              || CORRUPT_DB );
    ++      pCur->aOverflow[iIdx] = nextPage;
    + 
    +       if( offset>=ovflSize ){
    +         /* The only reason to read this page is to obtain the page
    +@@ -59012,11 +65110,7 @@ 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.
    +         */
    +-        assert( eOp!=2 );
    +         assert( pCur->curFlags & BTCF_ValidOvfl );
    +         assert( pCur->pBtree->db==pBt->db );
    +         if( pCur->aOverflow[iIdx+1] ){
    +@@ -59030,7 +65124,7 @@ static int accessPayload(
    +         ** range of data that is being read (eOp==0) or written (eOp!=0).
    +         */
    + #ifdef SQLITE_DIRECT_OVERFLOW_READ
    +-        sqlite3_file *fd;
    ++        sqlite3_file *fd;      /* File from which to do direct overflow read */
    + #endif
    +         int a = amt;
    +         if( a + offset > ovflSize ){
    +@@ -59042,27 +65136,25 @@ static int accessPayload(
    +         **
    +         **   1) this is a read operation, and 
    +         **   2) data is required from the start of this overflow page, and
    +-        **   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.
    +-        **   7) at least 4 bytes have already been read into the output buffer 
    ++        **   3) there is no open write-transaction, and
    ++        **   4) the database is file-backed, and
    ++        **   5) the page is not in the WAL file
    ++        **   6) at least 4 bytes have already been read into the output buffer 
    +         **
    +         ** 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&0x01)==0                                      /* (1) */
    ++        if( eOp==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) */
    +-         && &pBuf[-4]>=pBufStart                               /* (7) */
    ++         && pBt->inTransaction==TRANS_READ                     /* (3) */
    ++         && (fd = sqlite3PagerFile(pBt->pPager))->pMethods     /* (4) */
    ++         && 0==sqlite3PagerUseWal(pBt->pPager, nextPage)       /* (5) */
    ++         && &pBuf[-4]>=pBufStart                               /* (6) */
    +         ){
    +           u8 aSave[4];
    +           u8 *aWrite = &pBuf[-4];
    +-          assert( aWrite>=pBufStart );                         /* hence (7) */
    ++          assert( aWrite>=pBufStart );                         /* due to (6) */
    +           memcpy(aSave, aWrite, 4);
    +           rc = sqlite3OsRead(fd, aWrite, a+4, (i64)pBt->pageSize*(nextPage-1));
    +           nextPage = get4byte(aWrite);
    +@@ -59072,77 +65164,87 @@ static int accessPayload(
    + 
    +         {
    +           DbPage *pDbPage;
    +-          rc = sqlite3PagerAcquire(pBt->pPager, nextPage, &pDbPage,
    +-              ((eOp&0x01)==0 ? PAGER_GET_READONLY : 0)
    ++          rc = sqlite3PagerGet(pBt->pPager, nextPage, &pDbPage,
    ++              (eOp==0 ? PAGER_GET_READONLY : 0)
    +           );
    +           if( rc==SQLITE_OK ){
    +             aPayload = sqlite3PagerGetData(pDbPage);
    +             nextPage = get4byte(aPayload);
    +-            rc = copyPayload(&aPayload[offset+4], pBuf, a, (eOp&0x01), pDbPage);
    ++            rc = copyPayload(&aPayload[offset+4], pBuf, a, eOp, pDbPage);
    +             sqlite3PagerUnref(pDbPage);
    +             offset = 0;
    +           }
    +         }
    +         amt -= a;
    ++        if( amt==0 ) return rc;
    +         pBuf += a;
    +       }
    ++      if( rc ) break;
    ++      iIdx++;
    +     }
    +   }
    + 
    +   if( rc==SQLITE_OK && amt>0 ){
    +-    return SQLITE_CORRUPT_BKPT;
    ++    /* Overflow chain ends prematurely */
    ++    return SQLITE_CORRUPT_PAGE(pPage);
    +   }
    +   return rc;
    + }
    + 
    + /*
    +-** Read part of the key associated with cursor pCur.  Exactly
    +-** "amt" bytes will be transferred into pBuf[].  The transfer
    ++** Read part of the payload for the row at which that cursor pCur is currently
    ++** pointing.  "amt" bytes will be transferred into pBuf[].  The transfer
    + ** begins at "offset".
    + **
    +-** The caller must ensure that pCur is pointing to a valid row
    +-** in the table.
    ++** pCur can be pointing to either a table or an index b-tree.
    ++** If pointing to a table btree, then the content section is read.  If
    ++** pCur is pointing to an index b-tree then the key section is read.
    ++**
    ++** For sqlite3BtreePayload(), the caller must ensure that pCur is pointing
    ++** to a valid row in the table.  For sqlite3BtreePayloadChecked(), the
    ++** cursor might be invalid or might need to be restored before being read.
    + **
    + ** Return SQLITE_OK on success or an error code if anything goes
    + ** wrong.  An error is returned if "offset+amt" is larger than
    + ** the available payload.
    + */
    +-SQLITE_PRIVATE int sqlite3BtreeKey(BtCursor *pCur, u32 offset, u32 amt, void *pBuf){
    ++SQLITE_PRIVATE int sqlite3BtreePayload(BtCursor *pCur, u32 offset, u32 amt, void *pBuf){
    +   assert( cursorHoldsMutex(pCur) );
    +   assert( pCur->eState==CURSOR_VALID );
    +-  assert( pCur->iPage>=0 && pCur->apPage[pCur->iPage] );
    +-  assert( pCur->aiIdx[pCur->iPage]<pCur->apPage[pCur->iPage]->nCell );
    ++  assert( pCur->iPage>=0 && pCur->pPage );
    ++  assert( pCur->ix<pCur->pPage->nCell );
    +   return accessPayload(pCur, offset, amt, (unsigned char*)pBuf, 0);
    + }
    + 
    + /*
    +-** Read part of the data associated with cursor pCur.  Exactly
    +-** "amt" bytes will be transfered into pBuf[].  The transfer
    +-** begins at "offset".
    +-**
    +-** Return SQLITE_OK on success or an error code if anything goes
    +-** wrong.  An error is returned if "offset+amt" is larger than
    +-** the available payload.
    ++** This variant of sqlite3BtreePayload() works even if the cursor has not
    ++** in the CURSOR_VALID state.  It is only used by the sqlite3_blob_read()
    ++** interface.
    + */
    +-SQLITE_PRIVATE int sqlite3BtreeData(BtCursor *pCur, u32 offset, u32 amt, void *pBuf){
    +-  int rc;
    +-
    + #ifndef SQLITE_OMIT_INCRBLOB
    ++static SQLITE_NOINLINE int accessPayloadChecked(
    ++  BtCursor *pCur,
    ++  u32 offset,
    ++  u32 amt,
    ++  void *pBuf
    ++){
    ++  int rc;
    +   if ( pCur->eState==CURSOR_INVALID ){
    +     return SQLITE_ABORT;
    +   }
    +-#endif
    +-
    +-  assert( cursorHoldsMutex(pCur) );
    +-  rc = restoreCursorPosition(pCur);
    +-  if( rc==SQLITE_OK ){
    +-    assert( pCur->eState==CURSOR_VALID );
    +-    assert( pCur->iPage>=0 && pCur->apPage[pCur->iPage] );
    +-    assert( pCur->aiIdx[pCur->iPage]<pCur->apPage[pCur->iPage]->nCell );
    +-    rc = accessPayload(pCur, offset, amt, pBuf, 0);
    ++  assert( cursorOwnsBtShared(pCur) );
    ++  rc = btreeRestoreCursorPosition(pCur);
    ++  return rc ? rc : accessPayload(pCur, offset, amt, pBuf, 0);
    ++}
    ++SQLITE_PRIVATE int sqlite3BtreePayloadChecked(BtCursor *pCur, u32 offset, u32 amt, void *pBuf){
    ++  if( pCur->eState==CURSOR_VALID ){
    ++    assert( cursorOwnsBtShared(pCur) );
    ++    return accessPayload(pCur, offset, amt, pBuf, 0);
    ++  }else{
    ++    return accessPayloadChecked(pCur, offset, amt, pBuf);
    +   }
    +-  return rc;
    + }
    ++#endif /* SQLITE_OMIT_INCRBLOB */
    + 
    + /*
    + ** Return a pointer to payload information from the entry that the 
    +@@ -59167,18 +65269,23 @@ static const void *fetchPayload(
    +   BtCursor *pCur,      /* Cursor pointing to entry to read from */
    +   u32 *pAmt            /* Write the number of available bytes here */
    + ){
    +-  u32 amt;
    +-  assert( pCur!=0 && pCur->iPage>=0 && pCur->apPage[pCur->iPage]);
    ++  int amt;
    ++  assert( pCur!=0 && pCur->iPage>=0 && pCur->pPage);
    +   assert( pCur->eState==CURSOR_VALID );
    +   assert( sqlite3_mutex_held(pCur->pBtree->db->mutex) );
    +-  assert( cursorHoldsMutex(pCur) );
    +-  assert( pCur->aiIdx[pCur->iPage]<pCur->apPage[pCur->iPage]->nCell );
    ++  assert( cursorOwnsBtShared(pCur) );
    ++  assert( pCur->ix<pCur->pPage->nCell );
    +   assert( pCur->info.nSize>0 );
    +-  assert( pCur->info.pPayload>pCur->apPage[pCur->iPage]->aData || CORRUPT_DB );
    +-  assert( pCur->info.pPayload<pCur->apPage[pCur->iPage]->aDataEnd ||CORRUPT_DB);
    +-  amt = (int)(pCur->apPage[pCur->iPage]->aDataEnd - pCur->info.pPayload);
    +-  if( pCur->info.nLocal<amt ) amt = pCur->info.nLocal;
    +-  *pAmt = amt;
    ++  assert( pCur->info.pPayload>pCur->pPage->aData || CORRUPT_DB );
    ++  assert( pCur->info.pPayload<pCur->pPage->aDataEnd ||CORRUPT_DB);
    ++  amt = pCur->info.nLocal;
    ++  if( amt>(int)(pCur->pPage->aDataEnd - pCur->info.pPayload) ){
    ++    /* There is too little space on the page for the expected amount
    ++    ** of local content. Database must be corrupt. */
    ++    assert( CORRUPT_DB );
    ++    amt = MAX(0, (int)(pCur->pPage->aDataEnd - pCur->info.pPayload));
    ++  }
    ++  *pAmt = (u32)amt;
    +   return (void*)pCur->info.pPayload;
    + }
    + 
    +@@ -59197,10 +65304,7 @@ static const void *fetchPayload(
    + ** These routines is used to get quick access to key and data
    + ** in the common case where no overflow pages are used.
    + */
    +-SQLITE_PRIVATE const void *sqlite3BtreeKeyFetch(BtCursor *pCur, u32 *pAmt){
    +-  return fetchPayload(pCur, pAmt);
    +-}
    +-SQLITE_PRIVATE const void *sqlite3BtreeDataFetch(BtCursor *pCur, u32 *pAmt){
    ++SQLITE_PRIVATE const void *sqlite3BtreePayloadFetch(BtCursor *pCur, u32 *pAmt){
    +   return fetchPayload(pCur, pAmt);
    + }
    + 
    +@@ -59217,7 +65321,7 @@ SQLITE_PRIVATE const void *sqlite3BtreeDataFetch(BtCursor *pCur, u32 *pAmt){
    + static int moveToChild(BtCursor *pCur, u32 newPgno){
    +   BtShared *pBt = pCur->pBt;
    + 
    +-  assert( cursorHoldsMutex(pCur) );
    ++  assert( cursorOwnsBtShared(pCur) );
    +   assert( pCur->eState==CURSOR_VALID );
    +   assert( pCur->iPage<BTCURSOR_MAX_DEPTH );
    +   assert( pCur->iPage>=0 );
    +@@ -59226,13 +65330,14 @@ static int moveToChild(BtCursor *pCur, u32 newPgno){
    +   }
    +   pCur->info.nSize = 0;
    +   pCur->curFlags &= ~(BTCF_ValidNKey|BTCF_ValidOvfl);
    ++  pCur->aiIdx[pCur->iPage] = pCur->ix;
    ++  pCur->apPage[pCur->iPage] = pCur->pPage;
    ++  pCur->ix = 0;
    +   pCur->iPage++;
    +-  pCur->aiIdx[pCur->iPage] = 0;
    +-  return getAndInitPage(pBt, newPgno, &pCur->apPage[pCur->iPage],
    +-                        pCur, pCur->curPagerFlags);
    ++  return getAndInitPage(pBt, newPgno, &pCur->pPage, pCur, pCur->curPagerFlags);
    + }
    + 
    +-#if SQLITE_DEBUG
    ++#ifdef SQLITE_DEBUG
    + /*
    + ** Page pParent is an internal (non-leaf) tree page. This function 
    + ** asserts that page number iChild is the left-child if the iIdx'th
    +@@ -59263,19 +65368,23 @@ static void assertParentIndex(MemPage *pParent, int iIdx, Pgno iChild){
    + ** the largest cell index.
    + */
    + static void moveToParent(BtCursor *pCur){
    +-  assert( cursorHoldsMutex(pCur) );
    ++  MemPage *pLeaf;
    ++  assert( cursorOwnsBtShared(pCur) );
    +   assert( pCur->eState==CURSOR_VALID );
    +   assert( pCur->iPage>0 );
    +-  assert( pCur->apPage[pCur->iPage] );
    ++  assert( pCur->pPage );
    +   assertParentIndex(
    +     pCur->apPage[pCur->iPage-1], 
    +     pCur->aiIdx[pCur->iPage-1], 
    +-    pCur->apPage[pCur->iPage]->pgno
    ++    pCur->pPage->pgno
    +   );
    +   testcase( pCur->aiIdx[pCur->iPage-1] > pCur->apPage[pCur->iPage-1]->nCell );
    +   pCur->info.nSize = 0;
    +   pCur->curFlags &= ~(BTCF_ValidNKey|BTCF_ValidOvfl);
    +-  releasePageNotNull(pCur->apPage[pCur->iPage--]);
    ++  pCur->ix = pCur->aiIdx[pCur->iPage-1];
    ++  pLeaf = pCur->pPage;
    ++  pCur->pPage = pCur->apPage[--pCur->iPage];
    ++  releasePageNotNull(pLeaf);
    + }
    + 
    + /*
    +@@ -59287,9 +65396,9 @@ static void moveToParent(BtCursor *pCur){
    + ** single child page. This can only happen with the table rooted at page 1.
    + **
    + ** If the b-tree structure is empty, the cursor state is set to 
    +-** CURSOR_INVALID. Otherwise, the cursor is set to point to the first
    +-** cell located on the root (or virtual root) page and the cursor state
    +-** is set to CURSOR_VALID.
    ++** CURSOR_INVALID and this routine returns SQLITE_EMPTY. Otherwise,
    ++** the cursor is set to point to the first cell located on the root
    ++** (or virtual root) page and the cursor state is set to CURSOR_VALID.
    + **
    + ** If this function returns successfully, it may be assumed that the
    + ** page-header flags indicate that the [virtual] root-page is the expected 
    +@@ -59303,38 +65412,44 @@ static int moveToRoot(BtCursor *pCur){
    +   MemPage *pRoot;
    +   int rc = SQLITE_OK;
    + 
    +-  assert( cursorHoldsMutex(pCur) );
    ++  assert( cursorOwnsBtShared(pCur) );
    +   assert( CURSOR_INVALID < CURSOR_REQUIRESEEK );
    +   assert( CURSOR_VALID   < CURSOR_REQUIRESEEK );
    +   assert( CURSOR_FAULT   > CURSOR_REQUIRESEEK );
    +-  if( pCur->eState>=CURSOR_REQUIRESEEK ){
    +-    if( pCur->eState==CURSOR_FAULT ){
    +-      assert( pCur->skipNext!=SQLITE_OK );
    +-      return pCur->skipNext;
    +-    }
    +-    sqlite3BtreeClearCursor(pCur);
    +-  }
    ++  assert( pCur->eState < CURSOR_REQUIRESEEK || pCur->iPage<0 );
    ++  assert( pCur->pgnoRoot>0 || pCur->iPage<0 );
    + 
    +   if( pCur->iPage>=0 ){
    +-    while( pCur->iPage ){
    +-      assert( pCur->apPage[pCur->iPage]!=0 );
    +-      releasePageNotNull(pCur->apPage[pCur->iPage--]);
    ++    if( pCur->iPage ){
    ++      releasePageNotNull(pCur->pPage);
    ++      while( --pCur->iPage ){
    ++        releasePageNotNull(pCur->apPage[pCur->iPage]);
    ++      }
    ++      pCur->pPage = pCur->apPage[0];
    ++      goto skip_init;
    +     }
    +   }else if( pCur->pgnoRoot==0 ){
    +     pCur->eState = CURSOR_INVALID;
    +-    return SQLITE_OK;
    ++    return SQLITE_EMPTY;
    +   }else{
    +     assert( pCur->iPage==(-1) );
    +-    rc = getAndInitPage(pCur->pBtree->pBt, pCur->pgnoRoot, &pCur->apPage[0],
    ++    if( pCur->eState>=CURSOR_REQUIRESEEK ){
    ++      if( pCur->eState==CURSOR_FAULT ){
    ++        assert( pCur->skipNext!=SQLITE_OK );
    ++        return pCur->skipNext;
    ++      }
    ++      sqlite3BtreeClearCursor(pCur);
    ++    }
    ++    rc = getAndInitPage(pCur->pBtree->pBt, pCur->pgnoRoot, &pCur->pPage,
    +                         0, pCur->curPagerFlags);
    +     if( rc!=SQLITE_OK ){
    +       pCur->eState = CURSOR_INVALID;
    +       return rc;
    +     }
    +     pCur->iPage = 0;
    +-    pCur->curIntKey = pCur->apPage[0]->intKey;
    ++    pCur->curIntKey = pCur->pPage->intKey;
    +   }
    +-  pRoot = pCur->apPage[0];
    ++  pRoot = pCur->pPage;
    +   assert( pRoot->pgno==pCur->pgnoRoot );
    + 
    +   /* If pCur->pKeyInfo is not NULL, then the caller that opened this cursor
    +@@ -59349,13 +65464,15 @@ static int moveToRoot(BtCursor *pCur){
    +   ** (or the freelist).  */
    +   assert( pRoot->intKey==1 || pRoot->intKey==0 );
    +   if( pRoot->isInit==0 || (pCur->pKeyInfo==0)!=pRoot->intKey ){
    +-    return SQLITE_CORRUPT_BKPT;
    ++    return SQLITE_CORRUPT_PAGE(pCur->pPage);
    +   }
    + 
    +-  pCur->aiIdx[0] = 0;
    ++skip_init:  
    ++  pCur->ix = 0;
    +   pCur->info.nSize = 0;
    +   pCur->curFlags &= ~(BTCF_AtLast|BTCF_ValidNKey|BTCF_ValidOvfl);
    + 
    ++  pRoot = pCur->pPage;
    +   if( pRoot->nCell>0 ){
    +     pCur->eState = CURSOR_VALID;
    +   }else if( !pRoot->leaf ){
    +@@ -59366,6 +65483,7 @@ static int moveToRoot(BtCursor *pCur){
    +     rc = moveToChild(pCur, subpage);
    +   }else{
    +     pCur->eState = CURSOR_INVALID;
    ++    rc = SQLITE_EMPTY;
    +   }
    +   return rc;
    + }
    +@@ -59382,11 +65500,11 @@ static int moveToLeftmost(BtCursor *pCur){
    +   int rc = SQLITE_OK;
    +   MemPage *pPage;
    + 
    +-  assert( cursorHoldsMutex(pCur) );
    ++  assert( cursorOwnsBtShared(pCur) );
    +   assert( pCur->eState==CURSOR_VALID );
    +-  while( rc==SQLITE_OK && !(pPage = pCur->apPage[pCur->iPage])->leaf ){
    +-    assert( pCur->aiIdx[pCur->iPage]<pPage->nCell );
    +-    pgno = get4byte(findCell(pPage, pCur->aiIdx[pCur->iPage]));
    ++  while( rc==SQLITE_OK && !(pPage = pCur->pPage)->leaf ){
    ++    assert( pCur->ix<pPage->nCell );
    ++    pgno = get4byte(findCell(pPage, pCur->ix));
    +     rc = moveToChild(pCur, pgno);
    +   }
    +   return rc;
    +@@ -59407,15 +65525,15 @@ static int moveToRightmost(BtCursor *pCur){
    +   int rc = SQLITE_OK;
    +   MemPage *pPage = 0;
    + 
    +-  assert( cursorHoldsMutex(pCur) );
    ++  assert( cursorOwnsBtShared(pCur) );
    +   assert( pCur->eState==CURSOR_VALID );
    +-  while( !(pPage = pCur->apPage[pCur->iPage])->leaf ){
    ++  while( !(pPage = pCur->pPage)->leaf ){
    +     pgno = get4byte(&pPage->aData[pPage->hdrOffset+8]);
    +-    pCur->aiIdx[pCur->iPage] = pPage->nCell;
    ++    pCur->ix = pPage->nCell;
    +     rc = moveToChild(pCur, pgno);
    +     if( rc ) return rc;
    +   }
    +-  pCur->aiIdx[pCur->iPage] = pPage->nCell-1;
    ++  pCur->ix = pPage->nCell-1;
    +   assert( pCur->info.nSize==0 );
    +   assert( (pCur->curFlags & BTCF_ValidNKey)==0 );
    +   return SQLITE_OK;
    +@@ -59428,18 +65546,17 @@ static int moveToRightmost(BtCursor *pCur){
    + SQLITE_PRIVATE int sqlite3BtreeFirst(BtCursor *pCur, int *pRes){
    +   int rc;
    + 
    +-  assert( cursorHoldsMutex(pCur) );
    ++  assert( cursorOwnsBtShared(pCur) );
    +   assert( sqlite3_mutex_held(pCur->pBtree->db->mutex) );
    +   rc = moveToRoot(pCur);
    +   if( rc==SQLITE_OK ){
    +-    if( pCur->eState==CURSOR_INVALID ){
    +-      assert( pCur->pgnoRoot==0 || pCur->apPage[pCur->iPage]->nCell==0 );
    +-      *pRes = 1;
    +-    }else{
    +-      assert( pCur->apPage[pCur->iPage]->nCell>0 );
    +-      *pRes = 0;
    +-      rc = moveToLeftmost(pCur);
    +-    }
    ++    assert( pCur->pPage->nCell>0 );
    ++    *pRes = 0;
    ++    rc = moveToLeftmost(pCur);
    ++  }else if( rc==SQLITE_EMPTY ){
    ++    assert( pCur->pgnoRoot==0 || pCur->pPage->nCell==0 );
    ++    *pRes = 1;
    ++    rc = SQLITE_OK;
    +   }
    +   return rc;
    + }
    +@@ -59451,7 +65568,7 @@ SQLITE_PRIVATE int sqlite3BtreeFirst(BtCursor *pCur, int *pRes){
    + SQLITE_PRIVATE int sqlite3BtreeLast(BtCursor *pCur, int *pRes){
    +   int rc;
    +  
    +-  assert( cursorHoldsMutex(pCur) );
    ++  assert( cursorOwnsBtShared(pCur) );
    +   assert( sqlite3_mutex_held(pCur->pBtree->db->mutex) );
    + 
    +   /* If the cursor already points to the last entry, this is a no-op. */
    +@@ -59463,28 +65580,26 @@ SQLITE_PRIVATE int sqlite3BtreeLast(BtCursor *pCur, int *pRes){
    +     for(ii=0; ii<pCur->iPage; ii++){
    +       assert( pCur->aiIdx[ii]==pCur->apPage[ii]->nCell );
    +     }
    +-    assert( pCur->aiIdx[pCur->iPage]==pCur->apPage[pCur->iPage]->nCell-1 );
    +-    assert( pCur->apPage[pCur->iPage]->leaf );
    ++    assert( pCur->ix==pCur->pPage->nCell-1 );
    ++    assert( pCur->pPage->leaf );
    + #endif
    +     return SQLITE_OK;
    +   }
    + 
    +   rc = moveToRoot(pCur);
    +   if( rc==SQLITE_OK ){
    +-    if( CURSOR_INVALID==pCur->eState ){
    +-      assert( pCur->pgnoRoot==0 || pCur->apPage[pCur->iPage]->nCell==0 );
    +-      *pRes = 1;
    ++    assert( pCur->eState==CURSOR_VALID );
    ++    *pRes = 0;
    ++    rc = moveToRightmost(pCur);
    ++    if( rc==SQLITE_OK ){
    ++      pCur->curFlags |= BTCF_AtLast;
    +     }else{
    +-      assert( pCur->eState==CURSOR_VALID );
    +-      *pRes = 0;
    +-      rc = moveToRightmost(pCur);
    +-      if( rc==SQLITE_OK ){
    +-        pCur->curFlags |= BTCF_AtLast;
    +-      }else{
    +-        pCur->curFlags &= ~BTCF_AtLast;
    +-      }
    +-   
    ++      pCur->curFlags &= ~BTCF_AtLast;
    +     }
    ++  }else if( rc==SQLITE_EMPTY ){
    ++    assert( pCur->pgnoRoot==0 || pCur->pPage->nCell==0 );
    ++    *pRes = 1;
    ++    rc = SQLITE_OK;
    +   }
    +   return rc;
    + }
    +@@ -59516,6 +65631,8 @@ SQLITE_PRIVATE int sqlite3BtreeLast(BtCursor *pCur, int *pRes){
    + **     *pRes>0      The cursor is left pointing at an entry that
    + **                  is larger than intKey/pIdxKey.
    + **
    ++** For index tables, the pIdxKey->eqSeen field is set to 1 if there
    ++** exists an entry in the table that exactly matches pIdxKey.  
    + */
    + SQLITE_PRIVATE int sqlite3BtreeMovetoUnpacked(
    +   BtCursor *pCur,          /* The cursor to be moved */
    +@@ -59527,23 +65644,44 @@ SQLITE_PRIVATE int sqlite3BtreeMovetoUnpacked(
    +   int rc;
    +   RecordCompare xRecordCompare;
    + 
    +-  assert( cursorHoldsMutex(pCur) );
    ++  assert( cursorOwnsBtShared(pCur) );
    +   assert( sqlite3_mutex_held(pCur->pBtree->db->mutex) );
    +   assert( pRes );
    +   assert( (pIdxKey==0)==(pCur->pKeyInfo==0) );
    ++  assert( pCur->eState!=CURSOR_VALID || (pIdxKey==0)==(pCur->curIntKey!=0) );
    + 
    +   /* 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->curFlags & BTCF_ValidNKey)!=0
    +-   && pCur->curIntKey 
    ++  if( pIdxKey==0
    ++   && pCur->eState==CURSOR_VALID && (pCur->curFlags & BTCF_ValidNKey)!=0
    +   ){
    +     if( pCur->info.nKey==intKey ){
    +       *pRes = 0;
    +       return SQLITE_OK;
    +     }
    +-    if( (pCur->curFlags & BTCF_AtLast)!=0 && pCur->info.nKey<intKey ){
    +-      *pRes = -1;
    +-      return SQLITE_OK;
    ++    if( pCur->info.nKey<intKey ){
    ++      if( (pCur->curFlags & BTCF_AtLast)!=0 ){
    ++        *pRes = -1;
    ++        return SQLITE_OK;
    ++      }
    ++      /* If the requested key is one more than the previous key, then
    ++      ** try to get there using sqlite3BtreeNext() rather than a full
    ++      ** binary search.  This is an optimization only.  The correct answer
    ++      ** is still obtained without this case, only a little more slowely */
    ++      if( pCur->info.nKey+1==intKey && !pCur->skipNext ){
    ++        *pRes = 0;
    ++        rc = sqlite3BtreeNext(pCur, 0);
    ++        if( rc==SQLITE_OK ){
    ++          getCellInfo(pCur);
    ++          if( pCur->info.nKey==intKey ){
    ++            return SQLITE_OK;
    ++          }
    ++        }else if( rc==SQLITE_DONE ){
    ++          rc = SQLITE_OK;
    ++        }else{
    ++          return rc;
    ++        }
    ++      }
    +     }
    +   }
    + 
    +@@ -59560,22 +65698,23 @@ SQLITE_PRIVATE int sqlite3BtreeMovetoUnpacked(
    + 
    +   rc = moveToRoot(pCur);
    +   if( rc ){
    ++    if( rc==SQLITE_EMPTY ){
    ++      assert( pCur->pgnoRoot==0 || pCur->pPage->nCell==0 );
    ++      *pRes = -1;
    ++      return SQLITE_OK;
    ++    }
    +     return rc;
    +   }
    +-  assert( pCur->pgnoRoot==0 || pCur->apPage[pCur->iPage] );
    +-  assert( pCur->pgnoRoot==0 || pCur->apPage[pCur->iPage]->isInit );
    +-  assert( pCur->eState==CURSOR_INVALID || pCur->apPage[pCur->iPage]->nCell>0 );
    +-  if( pCur->eState==CURSOR_INVALID ){
    +-    *pRes = -1;
    +-    assert( pCur->pgnoRoot==0 || pCur->apPage[pCur->iPage]->nCell==0 );
    +-    return SQLITE_OK;
    +-  }
    +-  assert( pCur->apPage[0]->intKey==pCur->curIntKey );
    ++  assert( pCur->pPage );
    ++  assert( pCur->pPage->isInit );
    ++  assert( pCur->eState==CURSOR_VALID );
    ++  assert( pCur->pPage->nCell > 0 );
    ++  assert( pCur->iPage==0 || pCur->apPage[0]->intKey==pCur->curIntKey );
    +   assert( pCur->curIntKey || pIdxKey );
    +   for(;;){
    +     int lwr, upr, idx, c;
    +     Pgno chldPg;
    +-    MemPage *pPage = pCur->apPage[pCur->iPage];
    ++    MemPage *pPage = pCur->pPage;
    +     u8 *pCell;                          /* Pointer to current cell in pPage */
    + 
    +     /* pPage->nCell must be greater than zero. If this is the root-page
    +@@ -59590,14 +65729,16 @@ SQLITE_PRIVATE int sqlite3BtreeMovetoUnpacked(
    +     upr = pPage->nCell-1;
    +     assert( biasRight==0 || biasRight==1 );
    +     idx = upr>>(1-biasRight); /* idx = biasRight ? upr : (lwr+upr)/2; */
    +-    pCur->aiIdx[pCur->iPage] = (u16)idx;
    ++    pCur->ix = (u16)idx;
    +     if( xRecordCompare==0 ){
    +       for(;;){
    +         i64 nCellKey;
    +         pCell = findCellPastPtr(pPage, idx);
    +         if( pPage->intKeyLeaf ){
    +           while( 0x80 <= *(pCell++) ){
    +-            if( pCell>=pPage->aDataEnd ) return SQLITE_CORRUPT_BKPT;
    ++            if( pCell>=pPage->aDataEnd ){
    ++              return SQLITE_CORRUPT_PAGE(pPage);
    ++            }
    +           }
    +         }
    +         getVarint(pCell, (u64*)&nCellKey);
    +@@ -59609,16 +65750,16 @@ SQLITE_PRIVATE int sqlite3BtreeMovetoUnpacked(
    +           if( lwr>upr ){ c = +1; break; }
    +         }else{
    +           assert( nCellKey==intKey );
    +-          pCur->curFlags |= BTCF_ValidNKey;
    +-          pCur->info.nKey = nCellKey;
    +-          pCur->aiIdx[pCur->iPage] = (u16)idx;
    ++          pCur->ix = (u16)idx;
    +           if( !pPage->leaf ){
    +             lwr = idx;
    +             goto moveto_next_layer;
    +           }else{
    ++            pCur->curFlags |= BTCF_ValidNKey;
    ++            pCur->info.nKey = nCellKey;
    ++            pCur->info.nSize = 0;
    +             *pRes = 0;
    +-            rc = SQLITE_OK;
    +-            goto moveto_finish;
    ++            return SQLITE_OK;
    +           }
    +         }
    +         assert( lwr+upr>=0 );
    +@@ -59670,16 +65811,17 @@ SQLITE_PRIVATE int sqlite3BtreeMovetoUnpacked(
    +           testcase( nCell==1 );  /* Invalid key size:  0x80 0x80 0x01 */
    +           testcase( nCell==2 );  /* Minimum legal index key size */
    +           if( nCell<2 ){
    +-            rc = SQLITE_CORRUPT_BKPT;
    ++            rc = SQLITE_CORRUPT_PAGE(pPage);
    +             goto moveto_finish;
    +           }
    +           pCellKey = sqlite3Malloc( nCell+18 );
    +           if( pCellKey==0 ){
    +-            rc = SQLITE_NOMEM;
    ++            rc = SQLITE_NOMEM_BKPT;
    +             goto moveto_finish;
    +           }
    +-          pCur->aiIdx[pCur->iPage] = (u16)idx;
    +-          rc = accessPayload(pCur, 0, nCell, (unsigned char*)pCellKey, 2);
    ++          pCur->ix = (u16)idx;
    ++          rc = accessPayload(pCur, 0, nCell, (unsigned char*)pCellKey, 0);
    ++          pCur->curFlags &= ~BTCF_ValidOvfl;
    +           if( rc ){
    +             sqlite3_free(pCellKey);
    +             goto moveto_finish;
    +@@ -59699,8 +65841,8 @@ SQLITE_PRIVATE int sqlite3BtreeMovetoUnpacked(
    +           assert( c==0 );
    +           *pRes = 0;
    +           rc = SQLITE_OK;
    +-          pCur->aiIdx[pCur->iPage] = (u16)idx;
    +-          if( pIdxKey->errCode ) rc = SQLITE_CORRUPT;
    ++          pCur->ix = (u16)idx;
    ++          if( pIdxKey->errCode ) rc = SQLITE_CORRUPT_BKPT;
    +           goto moveto_finish;
    +         }
    +         if( lwr>upr ) break;
    +@@ -59711,8 +65853,8 @@ SQLITE_PRIVATE int sqlite3BtreeMovetoUnpacked(
    +     assert( lwr==upr+1 || (pPage->intKey && !pPage->leaf) );
    +     assert( pPage->isInit );
    +     if( pPage->leaf ){
    +-      assert( pCur->aiIdx[pCur->iPage]<pCur->apPage[pCur->iPage]->nCell );
    +-      pCur->aiIdx[pCur->iPage] = (u16)idx;
    ++      assert( pCur->ix<pCur->pPage->nCell );
    ++      pCur->ix = (u16)idx;
    +       *pRes = c;
    +       rc = SQLITE_OK;
    +       goto moveto_finish;
    +@@ -59723,13 +65865,13 @@ moveto_next_layer:
    +     }else{
    +       chldPg = get4byte(findCell(pPage, lwr));
    +     }
    +-    pCur->aiIdx[pCur->iPage] = (u16)lwr;
    ++    pCur->ix = (u16)lwr;
    +     rc = moveToChild(pCur, chldPg);
    +     if( rc ) break;
    +   }
    + moveto_finish:
    +   pCur->info.nSize = 0;
    +-  pCur->curFlags &= ~(BTCF_ValidNKey|BTCF_ValidOvfl);
    ++  assert( (pCur->curFlags & BTCF_ValidOvfl)==0 );
    +   return rc;
    + }
    + 
    +@@ -59750,10 +65892,37 @@ SQLITE_PRIVATE int sqlite3BtreeEof(BtCursor *pCur){
    + }
    + 
    + /*
    +-** Advance the cursor to the next entry in the database.  If
    +-** successful then set *pRes=0.  If the cursor
    +-** was already pointing to the last entry in the database before
    +-** this routine was called, then set *pRes=1.
    ++** Return an estimate for the number of rows in the table that pCur is
    ++** pointing to.  Return a negative number if no estimate is currently 
    ++** available.
    ++*/
    ++SQLITE_PRIVATE i64 sqlite3BtreeRowCountEst(BtCursor *pCur){
    ++  i64 n;
    ++  u8 i;
    ++
    ++  assert( cursorOwnsBtShared(pCur) );
    ++  assert( sqlite3_mutex_held(pCur->pBtree->db->mutex) );
    ++
    ++  /* Currently this interface is only called by the OP_IfSmaller
    ++  ** opcode, and it that case the cursor will always be valid and
    ++  ** will always point to a leaf node. */
    ++  if( NEVER(pCur->eState!=CURSOR_VALID) ) return -1;
    ++  if( NEVER(pCur->pPage->leaf==0) ) return -1;
    ++
    ++  n = pCur->pPage->nCell;
    ++  for(i=0; i<pCur->iPage; i++){
    ++    n *= pCur->apPage[i]->nCell;
    ++  }
    ++  return n;
    ++}
    ++
    ++/*
    ++** Advance the cursor to the next entry in the database. 
    ++** Return value:
    ++**
    ++**    SQLITE_OK        success
    ++**    SQLITE_DONE      cursor is already pointing at the last element
    ++**    otherwise        some kind of error occurred
    + **
    + ** The main entry point is sqlite3BtreeNext().  That routine is optimized
    + ** for the common case of merely incrementing the cell counter BtCursor.aiIdx
    +@@ -59761,23 +65930,19 @@ SQLITE_PRIVATE int sqlite3BtreeEof(BtCursor *pCur){
    + ** routine is called when it is necessary to move to a different page or
    + ** to restore the cursor.
    + **
    +-** The calling function will set *pRes to 0 or 1.  The initial *pRes value
    +-** will be 1 if the cursor being stepped corresponds to an SQL index and
    +-** if this routine could have been skipped if that SQL index had been
    +-** a unique index.  Otherwise the caller will have set *pRes to zero.
    +-** Zero is the common case. The btree implementation is free to use the
    +-** initial *pRes value as a hint to improve performance, but the current
    +-** SQLite btree implementation does not. (Note that the comdb2 btree
    +-** implementation does use this hint, however.)
    ++** If bit 0x01 of the F argument in sqlite3BtreeNext(C,F) is 1, then the
    ++** cursor corresponds to an SQL index and this routine could have been
    ++** skipped if the SQL index had been a unique index.  The F argument
    ++** is a hint to the implement.  SQLite btree implementation does not use
    ++** this hint, but COMDB2 does.
    + */
    +-static SQLITE_NOINLINE int btreeNext(BtCursor *pCur, int *pRes){
    ++static SQLITE_NOINLINE int btreeNext(BtCursor *pCur){
    +   int rc;
    +   int idx;
    +   MemPage *pPage;
    + 
    +-  assert( cursorHoldsMutex(pCur) );
    ++  assert( cursorOwnsBtShared(pCur) );
    +   assert( pCur->skipNext==0 || pCur->eState!=CURSOR_VALID );
    +-  assert( *pRes==0 );
    +   if( pCur->eState!=CURSOR_VALID ){
    +     assert( (pCur->curFlags & BTCF_ValidOvfl)==0 );
    +     rc = restoreCursorPosition(pCur);
    +@@ -59785,8 +65950,7 @@ static SQLITE_NOINLINE int btreeNext(BtCursor *pCur, int *pRes){
    +       return rc;
    +     }
    +     if( CURSOR_INVALID==pCur->eState ){
    +-      *pRes = 1;
    +-      return SQLITE_OK;
    ++      return SQLITE_DONE;
    +     }
    +     if( pCur->skipNext ){
    +       assert( pCur->eState==CURSOR_VALID || pCur->eState==CURSOR_SKIPNEXT );
    +@@ -59799,8 +65963,8 @@ static SQLITE_NOINLINE int btreeNext(BtCursor *pCur, int *pRes){
    +     }
    +   }
    + 
    +-  pPage = pCur->apPage[pCur->iPage];
    +-  idx = ++pCur->aiIdx[pCur->iPage];
    ++  pPage = pCur->pPage;
    ++  idx = ++pCur->ix;
    +   assert( pPage->isInit );
    + 
    +   /* If the database file is corrupt, it is possible for the value of idx 
    +@@ -59818,15 +65982,14 @@ static SQLITE_NOINLINE int btreeNext(BtCursor *pCur, int *pRes){
    +     }
    +     do{
    +       if( pCur->iPage==0 ){
    +-        *pRes = 1;
    +         pCur->eState = CURSOR_INVALID;
    +-        return SQLITE_OK;
    ++        return SQLITE_DONE;
    +       }
    +       moveToParent(pCur);
    +-      pPage = pCur->apPage[pCur->iPage];
    +-    }while( pCur->aiIdx[pCur->iPage]>=pPage->nCell );
    ++      pPage = pCur->pPage;
    ++    }while( pCur->ix>=pPage->nCell );
    +     if( pPage->intKey ){
    +-      return sqlite3BtreeNext(pCur, pRes);
    ++      return sqlite3BtreeNext(pCur, 0);
    +     }else{
    +       return SQLITE_OK;
    +     }
    +@@ -59837,20 +66000,19 @@ static SQLITE_NOINLINE int btreeNext(BtCursor *pCur, int *pRes){
    +     return moveToLeftmost(pCur);
    +   }
    + }
    +-SQLITE_PRIVATE int sqlite3BtreeNext(BtCursor *pCur, int *pRes){
    ++SQLITE_PRIVATE int sqlite3BtreeNext(BtCursor *pCur, int flags){
    +   MemPage *pPage;
    +-  assert( cursorHoldsMutex(pCur) );
    +-  assert( pRes!=0 );
    +-  assert( *pRes==0 || *pRes==1 );
    ++  UNUSED_PARAMETER( flags );  /* Used in COMDB2 but not native SQLite */
    ++  assert( cursorOwnsBtShared(pCur) );
    ++  assert( flags==0 || flags==1 );
    +   assert( pCur->skipNext==0 || pCur->eState!=CURSOR_VALID );
    +   pCur->info.nSize = 0;
    +   pCur->curFlags &= ~(BTCF_ValidNKey|BTCF_ValidOvfl);
    +-  *pRes = 0;
    +-  if( pCur->eState!=CURSOR_VALID ) return btreeNext(pCur, pRes);
    +-  pPage = pCur->apPage[pCur->iPage];
    +-  if( (++pCur->aiIdx[pCur->iPage])>=pPage->nCell ){
    +-    pCur->aiIdx[pCur->iPage]--;
    +-    return btreeNext(pCur, pRes);
    ++  if( pCur->eState!=CURSOR_VALID ) return btreeNext(pCur);
    ++  pPage = pCur->pPage;
    ++  if( (++pCur->ix)>=pPage->nCell ){
    ++    pCur->ix--;
    ++    return btreeNext(pCur);
    +   }
    +   if( pPage->leaf ){
    +     return SQLITE_OK;
    +@@ -59860,10 +66022,12 @@ SQLITE_PRIVATE int sqlite3BtreeNext(BtCursor *pCur, int *pRes){
    + }
    + 
    + /*
    +-** Step the cursor to the back to the previous entry in the database.  If
    +-** successful then set *pRes=0.  If the cursor
    +-** was already pointing to the first entry in the database before
    +-** this routine was called, then set *pRes=1.
    ++** Step the cursor to the back to the previous entry in the database.
    ++** Return values:
    ++**
    ++**     SQLITE_OK     success
    ++**     SQLITE_DONE   the cursor is already on the first element of the table
    ++**     otherwise     some kind of error occurred
    + **
    + ** The main entry point is sqlite3BtreePrevious().  That routine is optimized
    + ** for the common case of merely decrementing the cell counter BtCursor.aiIdx
    +@@ -59871,22 +66035,17 @@ SQLITE_PRIVATE int sqlite3BtreeNext(BtCursor *pCur, int *pRes){
    + ** helper routine is called when it is necessary to move to a different page
    + ** or to restore the cursor.
    + **
    +-** The calling function will set *pRes to 0 or 1.  The initial *pRes value
    +-** will be 1 if the cursor being stepped corresponds to an SQL index and
    +-** if this routine could have been skipped if that SQL index had been
    +-** a unique index.  Otherwise the caller will have set *pRes to zero.
    +-** Zero is the common case. The btree implementation is free to use the
    +-** initial *pRes value as a hint to improve performance, but the current
    +-** SQLite btree implementation does not. (Note that the comdb2 btree
    +-** implementation does use this hint, however.)
    ++** If bit 0x01 of the F argument to sqlite3BtreePrevious(C,F) is 1, then
    ++** the cursor corresponds to an SQL index and this routine could have been
    ++** skipped if the SQL index had been a unique index.  The F argument is a
    ++** hint to the implement.  The native SQLite btree implementation does not
    ++** use this hint, but COMDB2 does.
    + */
    +-static SQLITE_NOINLINE int btreePrevious(BtCursor *pCur, int *pRes){
    ++static SQLITE_NOINLINE int btreePrevious(BtCursor *pCur){
    +   int rc;
    +   MemPage *pPage;
    + 
    +-  assert( cursorHoldsMutex(pCur) );
    +-  assert( pRes!=0 );
    +-  assert( *pRes==0 );
    ++  assert( cursorOwnsBtShared(pCur) );
    +   assert( pCur->skipNext==0 || pCur->eState!=CURSOR_VALID );
    +   assert( (pCur->curFlags & (BTCF_AtLast|BTCF_ValidOvfl|BTCF_ValidNKey))==0 );
    +   assert( pCur->info.nSize==0 );
    +@@ -59896,8 +66055,7 @@ static SQLITE_NOINLINE int btreePrevious(BtCursor *pCur, int *pRes){
    +       return rc;
    +     }
    +     if( CURSOR_INVALID==pCur->eState ){
    +-      *pRes = 1;
    +-      return SQLITE_OK;
    ++      return SQLITE_DONE;
    +     }
    +     if( pCur->skipNext ){
    +       assert( pCur->eState==CURSOR_VALID || pCur->eState==CURSOR_SKIPNEXT );
    +@@ -59910,50 +66068,48 @@ static SQLITE_NOINLINE int btreePrevious(BtCursor *pCur, int *pRes){
    +     }
    +   }
    + 
    +-  pPage = pCur->apPage[pCur->iPage];
    ++  pPage = pCur->pPage;
    +   assert( pPage->isInit );
    +   if( !pPage->leaf ){
    +-    int idx = pCur->aiIdx[pCur->iPage];
    ++    int idx = pCur->ix;
    +     rc = moveToChild(pCur, get4byte(findCell(pPage, idx)));
    +     if( rc ) return rc;
    +     rc = moveToRightmost(pCur);
    +   }else{
    +-    while( pCur->aiIdx[pCur->iPage]==0 ){
    ++    while( pCur->ix==0 ){
    +       if( pCur->iPage==0 ){
    +         pCur->eState = CURSOR_INVALID;
    +-        *pRes = 1;
    +-        return SQLITE_OK;
    ++        return SQLITE_DONE;
    +       }
    +       moveToParent(pCur);
    +     }
    +     assert( pCur->info.nSize==0 );
    +-    assert( (pCur->curFlags & (BTCF_ValidNKey|BTCF_ValidOvfl))==0 );
    ++    assert( (pCur->curFlags & (BTCF_ValidOvfl))==0 );
    + 
    +-    pCur->aiIdx[pCur->iPage]--;
    +-    pPage = pCur->apPage[pCur->iPage];
    ++    pCur->ix--;
    ++    pPage = pCur->pPage;
    +     if( pPage->intKey && !pPage->leaf ){
    +-      rc = sqlite3BtreePrevious(pCur, pRes);
    ++      rc = sqlite3BtreePrevious(pCur, 0);
    +     }else{
    +       rc = SQLITE_OK;
    +     }
    +   }
    +   return rc;
    + }
    +-SQLITE_PRIVATE int sqlite3BtreePrevious(BtCursor *pCur, int *pRes){
    +-  assert( cursorHoldsMutex(pCur) );
    +-  assert( pRes!=0 );
    +-  assert( *pRes==0 || *pRes==1 );
    ++SQLITE_PRIVATE int sqlite3BtreePrevious(BtCursor *pCur, int flags){
    ++  assert( cursorOwnsBtShared(pCur) );
    ++  assert( flags==0 || flags==1 );
    +   assert( pCur->skipNext==0 || pCur->eState!=CURSOR_VALID );
    +-  *pRes = 0;
    ++  UNUSED_PARAMETER( flags );  /* Used in COMDB2 but not native SQLite */
    +   pCur->curFlags &= ~(BTCF_AtLast|BTCF_ValidOvfl|BTCF_ValidNKey);
    +   pCur->info.nSize = 0;
    +   if( pCur->eState!=CURSOR_VALID
    +-   || pCur->aiIdx[pCur->iPage]==0
    +-   || pCur->apPage[pCur->iPage]->leaf==0
    ++   || pCur->ix==0
    ++   || pCur->pPage->leaf==0
    +   ){
    +-    return btreePrevious(pCur, pRes);
    ++    return btreePrevious(pCur);
    +   }
    +-  pCur->aiIdx[pCur->iPage]--;
    ++  pCur->ix--;
    +   return SQLITE_OK;
    + }
    + 
    +@@ -60059,7 +66215,7 @@ static int allocateBtreePage(
    +       }
    +       testcase( iTrunk==mxPage );
    +       if( iTrunk>mxPage || nSearch++ > n ){
    +-        rc = SQLITE_CORRUPT_BKPT;
    ++        rc = SQLITE_CORRUPT_PGNO(pPrevTrunk ? pPrevTrunk->pgno : 1);
    +       }else{
    +         rc = btreeGetUnusedPage(pBt, iTrunk, &pTrunk, 0);
    +       }
    +@@ -60088,7 +66244,7 @@ static int allocateBtreePage(
    +         TRACE(("ALLOCATE: %d trunk - %d free pages left\n", *pPgno, n-1));
    +       }else if( k>(u32)(pBt->usableSize/4 - 2) ){
    +         /* Value of k is out of range.  Database corruption */
    +-        rc = SQLITE_CORRUPT_BKPT;
    ++        rc = SQLITE_CORRUPT_PGNO(iTrunk);
    +         goto end_allocate_page;
    + #ifndef SQLITE_OMIT_AUTOVACUUM
    +       }else if( searchList 
    +@@ -60122,7 +66278,7 @@ static int allocateBtreePage(
    +           MemPage *pNewTrunk;
    +           Pgno iNewTrunk = get4byte(&pTrunk->aData[8]);
    +           if( iNewTrunk>mxPage ){ 
    +-            rc = SQLITE_CORRUPT_BKPT;
    ++            rc = SQLITE_CORRUPT_PGNO(iTrunk);
    +             goto end_allocate_page;
    +           }
    +           testcase( iNewTrunk==mxPage );
    +@@ -60187,7 +66343,7 @@ static int allocateBtreePage(
    +         iPage = get4byte(&aData[8+closest*4]);
    +         testcase( iPage==mxPage );
    +         if( iPage>mxPage ){
    +-          rc = SQLITE_CORRUPT_BKPT;
    ++          rc = SQLITE_CORRUPT_PGNO(iTrunk);
    +           goto end_allocate_page;
    +         }
    +         testcase( iPage==mxPage );
    +@@ -60443,30 +66599,30 @@ static void freePage(MemPage *pPage, int *pRC){
    + static int clearCell(
    +   MemPage *pPage,          /* The page that contains the Cell */
    +   unsigned char *pCell,    /* First byte of the Cell */
    +-  u16 *pnSize              /* Write the size of the Cell here */
    ++  CellInfo *pInfo          /* Size information about the cell */
    + ){
    +-  BtShared *pBt = pPage->pBt;
    +-  CellInfo info;
    ++  BtShared *pBt;
    +   Pgno ovflPgno;
    +   int rc;
    +   int nOvfl;
    +   u32 ovflPageSize;
    + 
    +   assert( sqlite3_mutex_held(pPage->pBt->mutex) );
    +-  pPage->xParseCell(pPage, pCell, &info);
    +-  *pnSize = info.nSize;
    +-  if( info.iOverflow==0 ){
    ++  pPage->xParseCell(pPage, pCell, pInfo);
    ++  if( pInfo->nLocal==pInfo->nPayload ){
    +     return SQLITE_OK;  /* No overflow pages. Return without doing anything */
    +   }
    +-  if( pCell+info.iOverflow+3 > pPage->aData+pPage->maskPage ){
    +-    return SQLITE_CORRUPT_BKPT;  /* Cell extends past end of page */
    ++  if( pCell+pInfo->nSize-1 > pPage->aData+pPage->maskPage ){
    ++    /* Cell extends past end of page */
    ++    return SQLITE_CORRUPT_PAGE(pPage);
    +   }
    +-  ovflPgno = get4byte(&pCell[info.iOverflow]);
    ++  ovflPgno = get4byte(pCell + pInfo->nSize - 4);
    ++  pBt = pPage->pBt;
    +   assert( pBt->usableSize > 4 );
    +   ovflPageSize = pBt->usableSize - 4;
    +-  nOvfl = (info.nPayload - info.nLocal + ovflPageSize - 1)/ovflPageSize;
    ++  nOvfl = (pInfo->nPayload - pInfo->nLocal + ovflPageSize - 1)/ovflPageSize;
    +   assert( nOvfl>0 || 
    +-    (CORRUPT_DB && (info.nPayload + ovflPageSize)<ovflPageSize)
    ++    (CORRUPT_DB && (pInfo->nPayload + ovflPageSize)<ovflPageSize)
    +   );
    +   while( nOvfl-- ){
    +     Pgno iNext = 0;
    +@@ -60524,71 +66680,74 @@ static int clearCell(
    + static int fillInCell(
    +   MemPage *pPage,                /* The page that contains the cell */
    +   unsigned char *pCell,          /* Complete text of the cell */
    +-  const void *pKey, i64 nKey,    /* The key */
    +-  const void *pData,int nData,   /* The data */
    +-  int nZero,                     /* Extra zero bytes to append to pData */
    ++  const BtreePayload *pX,        /* Payload with which to construct the cell */
    +   int *pnSize                    /* Write cell size here */
    + ){
    +   int nPayload;
    +   const u8 *pSrc;
    +-  int nSrc, n, rc;
    ++  int nSrc, n, rc, mn;
    +   int spaceLeft;
    +-  MemPage *pOvfl = 0;
    +-  MemPage *pToRelease = 0;
    ++  MemPage *pToRelease;
    +   unsigned char *pPrior;
    +   unsigned char *pPayload;
    +-  BtShared *pBt = pPage->pBt;
    +-  Pgno pgnoOvfl = 0;
    ++  BtShared *pBt;
    ++  Pgno pgnoOvfl;
    +   int nHeader;
    + 
    +   assert( sqlite3_mutex_held(pPage->pBt->mutex) );
    + 
    +   /* pPage is not necessarily writeable since pCell might be auxiliary
    +   ** buffer space that is separate from the pPage buffer area */
    +-  assert( pCell<pPage->aData || pCell>=&pPage->aData[pBt->pageSize]
    ++  assert( pCell<pPage->aData || pCell>=&pPage->aData[pPage->pBt->pageSize]
    +             || sqlite3PagerIswriteable(pPage->pDbPage) );
    + 
    +   /* Fill in the header. */
    +   nHeader = pPage->childPtrSize;
    +-  nPayload = nData + nZero;
    +-  if( pPage->intKeyLeaf ){
    ++  if( pPage->intKey ){
    ++    nPayload = pX->nData + pX->nZero;
    ++    pSrc = pX->pData;
    ++    nSrc = pX->nData;
    ++    assert( pPage->intKeyLeaf ); /* fillInCell() only called for leaves */
    +     nHeader += putVarint32(&pCell[nHeader], nPayload);
    ++    nHeader += putVarint(&pCell[nHeader], *(u64*)&pX->nKey);
    +   }else{
    +-    assert( nData==0 );
    +-    assert( nZero==0 );
    ++    assert( pX->nKey<=0x7fffffff && pX->pKey!=0 );
    ++    nSrc = nPayload = (int)pX->nKey;
    ++    pSrc = pX->pKey;
    ++    nHeader += putVarint32(&pCell[nHeader], nPayload);
    +   }
    +-  nHeader += putVarint(&pCell[nHeader], *(u64*)&nKey);
    +   
    +-  /* Fill in the payload size */
    +-  if( pPage->intKey ){
    +-    pSrc = pData;
    +-    nSrc = nData;
    +-    nData = 0;
    +-  }else{ 
    +-    assert( nKey<=0x7fffffff && pKey!=0 );
    +-    nPayload = (int)nKey;
    +-    pSrc = pKey;
    +-    nSrc = (int)nKey;
    +-  }
    ++  /* Fill in the payload */
    ++  pPayload = &pCell[nHeader];
    +   if( nPayload<=pPage->maxLocal ){
    ++    /* This is the common case where everything fits on the btree page
    ++    ** and no overflow pages are required. */
    +     n = nHeader + nPayload;
    +     testcase( n==3 );
    +     testcase( n==4 );
    +     if( n<4 ) n = 4;
    +     *pnSize = n;
    +-    spaceLeft = nPayload;
    +-    pPrior = pCell;
    +-  }else{
    +-    int mn = pPage->minLocal;
    +-    n = mn + (nPayload - mn) % (pPage->pBt->usableSize - 4);
    +-    testcase( n==pPage->maxLocal );
    +-    testcase( n==pPage->maxLocal+1 );
    +-    if( n > pPage->maxLocal ) n = mn;
    +-    spaceLeft = n;
    +-    *pnSize = n + nHeader + 4;
    +-    pPrior = &pCell[nHeader+n];
    ++    assert( nSrc<=nPayload );
    ++    testcase( nSrc<nPayload );
    ++    memcpy(pPayload, pSrc, nSrc);
    ++    memset(pPayload+nSrc, 0, nPayload-nSrc);
    ++    return SQLITE_OK;
    +   }
    +-  pPayload = &pCell[nHeader];
    ++
    ++  /* If we reach this point, it means that some of the content will need
    ++  ** to spill onto overflow pages.
    ++  */
    ++  mn = pPage->minLocal;
    ++  n = mn + (nPayload - mn) % (pPage->pBt->usableSize - 4);
    ++  testcase( n==pPage->maxLocal );
    ++  testcase( n==pPage->maxLocal+1 );
    ++  if( n > pPage->maxLocal ) n = mn;
    ++  spaceLeft = n;
    ++  *pnSize = n + nHeader + 4;
    ++  pPrior = &pCell[nHeader+n];
    ++  pToRelease = 0;
    ++  pgnoOvfl = 0;
    ++  pBt = pPage->pBt;
    + 
    +   /* At this point variables should be set as follows:
    +   **
    +@@ -60602,21 +66761,47 @@ static int fillInCell(
    +   ** Use a call to btreeParseCellPtr() to verify that the values above
    +   ** were computed correctly.
    +   */
    +-#if SQLITE_DEBUG
    ++#ifdef SQLITE_DEBUG
    +   {
    +     CellInfo info;
    +     pPage->xParseCell(pPage, pCell, &info);
    +-    assert( nHeader=(int)(info.pPayload - pCell) );
    +-    assert( info.nKey==nKey );
    ++    assert( nHeader==(int)(info.pPayload - pCell) );
    ++    assert( info.nKey==pX->nKey );
    +     assert( *pnSize == info.nSize );
    +     assert( spaceLeft == info.nLocal );
    +-    assert( pPrior == &pCell[info.iOverflow] );
    +   }
    + #endif
    + 
    +   /* Write the payload into the local Cell and any extra into overflow pages */
    +-  while( nPayload>0 ){
    ++  while( 1 ){
    ++    n = nPayload;
    ++    if( n>spaceLeft ) n = spaceLeft;
    ++
    ++    /* If pToRelease is not zero than pPayload points into the data area
    ++    ** of pToRelease.  Make sure pToRelease is still writeable. */
    ++    assert( pToRelease==0 || sqlite3PagerIswriteable(pToRelease->pDbPage) );
    ++
    ++    /* If pPayload is part of the data area of pPage, then make sure pPage
    ++    ** is still writeable */
    ++    assert( pPayload<pPage->aData || pPayload>=&pPage->aData[pBt->pageSize]
    ++            || sqlite3PagerIswriteable(pPage->pDbPage) );
    ++
    ++    if( nSrc>=n ){
    ++      memcpy(pPayload, pSrc, n);
    ++    }else if( nSrc>0 ){
    ++      n = nSrc;
    ++      memcpy(pPayload, pSrc, n);
    ++    }else{
    ++      memset(pPayload, 0, n);
    ++    }
    ++    nPayload -= n;
    ++    if( nPayload<=0 ) break;
    ++    pPayload += n;
    ++    pSrc += n;
    ++    nSrc -= n;
    ++    spaceLeft -= n;
    +     if( spaceLeft==0 ){
    ++      MemPage *pOvfl = 0;
    + #ifndef SQLITE_OMIT_AUTOVACUUM
    +       Pgno pgnoPtrmap = pgnoOvfl; /* Overflow page pointer-map entry page */
    +       if( pBt->autoVacuum ){
    +@@ -60669,34 +66854,6 @@ static int fillInCell(
    +       pPayload = &pOvfl->aData[4];
    +       spaceLeft = pBt->usableSize - 4;
    +     }
    +-    n = nPayload;
    +-    if( n>spaceLeft ) n = spaceLeft;
    +-
    +-    /* If pToRelease is not zero than pPayload points into the data area
    +-    ** of pToRelease.  Make sure pToRelease is still writeable. */
    +-    assert( pToRelease==0 || sqlite3PagerIswriteable(pToRelease->pDbPage) );
    +-
    +-    /* If pPayload is part of the data area of pPage, then make sure pPage
    +-    ** is still writeable */
    +-    assert( pPayload<pPage->aData || pPayload>=&pPage->aData[pBt->pageSize]
    +-            || sqlite3PagerIswriteable(pPage->pDbPage) );
    +-
    +-    if( nSrc>0 ){
    +-      if( n>nSrc ) n = nSrc;
    +-      assert( pSrc );
    +-      memcpy(pPayload, pSrc, n);
    +-    }else{
    +-      memset(pPayload, 0, n);
    +-    }
    +-    nPayload -= n;
    +-    pPayload += n;
    +-    pSrc += n;
    +-    nSrc -= n;
    +-    spaceLeft -= n;
    +-    if( nSrc==0 ){
    +-      nSrc = nData;
    +-      pSrc = pData;
    +-    }
    +   }
    +   releasePage(pToRelease);
    +   return SQLITE_OK;
    +@@ -60718,7 +66875,6 @@ static void dropCell(MemPage *pPage, int idx, int sz, int *pRC){
    +   int hdr;        /* Beginning of the header.  0 most pages.  100 page 1 */
    + 
    +   if( *pRC ) return;
    +-
    +   assert( idx>=0 && idx<pPage->nCell );
    +   assert( CORRUPT_DB || sz==cellSize(pPage, idx) );
    +   assert( sqlite3PagerIswriteable(pPage->pDbPage) );
    +@@ -60729,7 +66885,7 @@ static void dropCell(MemPage *pPage, int idx, int sz, int *pRC){
    +   hdr = pPage->hdrOffset;
    +   testcase( pc==get2byte(&data[hdr+5]) );
    +   testcase( pc+sz==pPage->pBt->usableSize );
    +-  if( pc < (u32)get2byte(&data[hdr+5]) || pc+sz > pPage->pBt->usableSize ){
    ++  if( pc+sz > pPage->pBt->usableSize ){
    +     *pRC = SQLITE_CORRUPT_BKPT;
    +     return;
    +   }
    +@@ -60763,6 +66919,8 @@ static void dropCell(MemPage *pPage, int idx, int sz, int *pRC){
    + ** in pTemp or the original pCell) and also record its index. 
    + ** Allocating a new entry in pPage->aCell[] implies that 
    + ** pPage->nOverflow is incremented.
    ++**
    ++** *pRC must be SQLITE_OK when this routine is called.
    + */
    + static void insertCell(
    +   MemPage *pPage,   /* Page into which we are copying */
    +@@ -60778,8 +66936,7 @@ static void insertCell(
    +   u8 *data;         /* The content of the whole page */
    +   u8 *pIns;         /* The point in pPage->aCellIdx[] where no cell inserted */
    + 
    +-  if( *pRC ) return;
    +-
    ++  assert( *pRC==SQLITE_OK );
    +   assert( i>=0 && i<=pPage->nCell+pPage->nOverflow );
    +   assert( MX_CELL(pPage->pBt)<=10921 );
    +   assert( pPage->nCell<=MX_CELL(pPage->pBt) || CORRUPT_DB );
    +@@ -60801,7 +66958,10 @@ static void insertCell(
    +       put4byte(pCell, iChild);
    +     }
    +     j = pPage->nOverflow++;
    +-    assert( j<(int)(sizeof(pPage->apOvfl)/sizeof(pPage->apOvfl[0])) );
    ++    /* Comparison against ArraySize-1 since we hold back one extra slot
    ++    ** as a contingency.  In other words, never need more than 3 overflow
    ++    ** slots but 4 are allocated, just to be safe. */
    ++    assert( j < ArraySize(pPage->apOvfl)-1 );
    +     pPage->apOvfl[j] = pCell;
    +     pPage->aiOvfl[j] = (u16)i;
    + 
    +@@ -60853,7 +67013,7 @@ static void insertCell(
    + 
    + /*
    + ** A CellArray object contains a cache of pointers and sizes for a
    +-** consecutive sequence of cells that might be held multiple pages.
    ++** consecutive sequence of cells that might be held on multiple pages.
    + */
    + typedef struct CellArray CellArray;
    + struct CellArray {
    +@@ -60931,7 +67091,7 @@ static int rebuildPage(
    +   pData = pEnd;
    +   for(i=0; i<nCell; i++){
    +     u8 *pCell = apCell[i];
    +-    if( pCell>aData && pCell<pEnd ){
    ++    if( SQLITE_WITHIN(pCell,aData,pEnd) ){
    +       pCell = &pTmp[pCell - aData];
    +     }
    +     pData -= szCell[i];
    +@@ -60998,8 +67158,8 @@ static int pageInsertArray(
    +     u8 *pSlot;
    +     sz = cachedCellSize(pCArray, i);
    +     if( (aData[1]==0 && aData[2]==0) || (pSlot = pageFindSlot(pPg,sz,&rc))==0 ){
    ++      if( (pData - pBegin)<sz ) return 1;
    +       pData -= sz;
    +-      if( pData<pBegin ) return 1;
    +       pSlot = pData;
    +     }
    +     /* pSlot and pCArray->apCell[i] will never overlap on a well-formed
    +@@ -61042,7 +67202,7 @@ static int pageFreeArray(
    + 
    +   for(i=iFirst; i<iEnd; i++){
    +     u8 *pCell = pCArray->apCell[i];
    +-    if( pCell>=pStart && pCell<pEnd ){
    ++    if( SQLITE_WITHIN(pCell, pStart, pEnd) ){
    +       int sz;
    +       /* No need to use cachedCellSize() here.  The sizes of all cells that
    +       ** are to be freed have already been computing while deciding which
    +@@ -61161,7 +67321,7 @@ static int editPage(
    +   for(i=0; i<nNew && !CORRUPT_DB; i++){
    +     u8 *pCell = pCArray->apCell[i+iNew];
    +     int iOff = get2byteAligned(&pPg->aCellIdx[i*2]);
    +-    if( pCell>=aData && pCell<&aData[pPg->pBt->usableSize] ){
    ++    if( SQLITE_WITHIN(pCell, aData, &aData[pPg->pBt->usableSize]) ){
    +       pCell = &pTmp[pCell - aData];
    +     }
    +     assert( 0==memcmp(pCell, &aData[iOff],
    +@@ -61285,8 +67445,10 @@ static int balance_quick(MemPage *pParent, MemPage *pPage, u8 *pSpace){
    +     while( ((*(pOut++) = *(pCell++))&0x80) && pCell<pStop );
    + 
    +     /* Insert the new divider cell into pParent. */
    +-    insertCell(pParent, pParent->nCell, pSpace, (int)(pOut-pSpace),
    +-               0, pPage->pgno, &rc);
    ++    if( rc==SQLITE_OK ){
    ++      insertCell(pParent, pParent->nCell, pSpace, (int)(pOut-pSpace),
    ++                   0, pPage->pgno, &rc);
    ++    }
    + 
    +     /* Set the right-child pointer of pParent to point to the new page. */
    +     put4byte(&pParent->aData[pParent->hdrOffset+8], pgnoNew);
    +@@ -61320,8 +67482,8 @@ static int ptrmapCheckPages(MemPage **apPage, int nPage){
    +      
    +       z = findCell(pPage, j);
    +       pPage->xParseCell(pPage, z, &info);
    +-      if( info.iOverflow ){
    +-        Pgno ovfl = get4byte(&z[info.iOverflow]);
    ++      if( info.nLocal<info.nPayload ){
    ++        Pgno ovfl = get4byte(&z[info.nSize-4]);
    +         ptrmapGet(pBt, ovfl, &e, &n);
    +         assert( n==pPage->pgno && e==PTRMAP_OVERFLOW1 );
    +       }
    +@@ -61439,9 +67601,6 @@ static void copyNodeContent(MemPage *pFrom, MemPage *pTo, int *pRC){
    + ** If aOvflSpace is set to a null pointer, this function returns 
    + ** SQLITE_NOMEM.
    + */
    +-#if defined(_MSC_VER) && _MSC_VER >= 1700 && defined(_M_ARM)
    +-#pragma optimize("", off)
    +-#endif
    + static int balance_nonroot(
    +   MemPage *pParent,               /* Parent page of siblings being balanced */
    +   int iParentIdx,                 /* Index of "the page" in pParent */
    +@@ -61498,7 +67657,7 @@ static int balance_nonroot(
    +   assert( pParent->nOverflow==0 || pParent->aiOvfl[0]==iParentIdx );
    + 
    +   if( !aOvflSpace ){
    +-    return SQLITE_NOMEM;
    ++    return SQLITE_NOMEM_BKPT;
    +   }
    + 
    +   /* Find the sibling pages to balance. Also locate the cells in pParent 
    +@@ -61542,7 +67701,7 @@ static int balance_nonroot(
    +     nMaxCells += 1+apOld[i]->nCell+apOld[i]->nOverflow;
    +     if( (i--)==0 ) break;
    + 
    +-    if( i+nxDiv==pParent->aiOvfl[0] && pParent->nOverflow ){
    ++    if( pParent->nOverflow && i+nxDiv==pParent->aiOvfl[0] ){
    +       apDiv[i] = pParent->apOvfl[0];
    +       pgno = get4byte(apDiv[i]);
    +       szNew[i] = pParent->xCellSize(pParent, apDiv[i]);
    +@@ -61564,7 +67723,7 @@ static int balance_nonroot(
    +       ** In this case, temporarily copy the cell into the aOvflSpace[]
    +       ** buffer. It will be copied out again as soon as the aSpace[] buffer
    +       ** is allocated.  */
    +-      if( pBt->btsFlags & BTS_SECURE_DELETE ){
    ++      if( pBt->btsFlags & BTS_FAST_SECURE ){
    +         int iOff;
    + 
    +         iOff = SQLITE_PTR_TO_INT(apDiv[i]) - SQLITE_PTR_TO_INT(pParent->aData);
    +@@ -61593,12 +67752,10 @@ static int balance_nonroot(
    +      + nMaxCells*sizeof(u16)                       /* b.szCell */
    +      + pBt->pageSize;                              /* aSpace1 */
    + 
    +-  /* EVIDENCE-OF: R-28375-38319 SQLite will never request a scratch buffer
    +-  ** that is more than 6 times the database page size. */
    +   assert( szScratch<=6*(int)pBt->pageSize );
    +-  b.apCell = sqlite3ScratchMalloc( szScratch ); 
    ++  b.apCell = sqlite3StackAllocRaw(0, szScratch );
    +   if( b.apCell==0 ){
    +-    rc = SQLITE_NOMEM;
    ++    rc = SQLITE_NOMEM_BKPT;
    +     goto balance_cleanup;
    +   }
    +   b.szCell = (u16*)&b.apCell[nMaxCells];
    +@@ -61657,9 +67814,8 @@ static int balance_nonroot(
    +     ** long be able to find the cells if a pointer to each cell is not saved
    +     ** first.
    +     */
    +-    memset(&b.szCell[b.nCell], 0, sizeof(b.szCell[0])*limit);
    ++    memset(&b.szCell[b.nCell], 0, sizeof(b.szCell[0])*(limit+pOld->nOverflow));
    +     if( pOld->nOverflow>0 ){
    +-      memset(&b.szCell[b.nCell+limit], 0, sizeof(b.szCell[0])*pOld->nOverflow);
    +       limit = pOld->aiOvfl[0];
    +       for(j=0; j<limit; j++){
    +         b.apCell[b.nCell] = aData + (maskPage & get2byteAligned(piCell));
    +@@ -61735,7 +67891,6 @@ static int balance_nonroot(
    +   for(i=0; i<nOld; i++){
    +     MemPage *p = apOld[i];
    +     szNew[i] = usableSpace - p->nFree;
    +-    if( szNew[i]<0 ){ rc = SQLITE_CORRUPT_BKPT; goto balance_cleanup; }
    +     for(j=0; j<p->nOverflow; j++){
    +       szNew[i] += 2 + p->xCellSize(p, p->apOvfl[j]);
    +     }
    +@@ -61810,7 +67965,7 @@ static int balance_nonroot(
    +       assert( r<nMaxCells );
    +       (void)cachedCellSize(&b, r);
    +       if( szRight!=0
    +-       && (bBulk || szRight+b.szCell[d]+2 > szLeft-(b.szCell[r]+2)) ){
    ++       && (bBulk || szRight+b.szCell[d]+2 > szLeft-(b.szCell[r]+(i==k-1?0:2)))){
    +         break;
    +       }
    +       szRight += b.szCell[d] + 2;
    +@@ -61985,8 +68140,7 @@ static int balance_nonroot(
    +       ** overflow cell), we can skip updating the pointer map entries.  */
    +       if( iOld>=nNew
    +        || pNew->pgno!=aPgno[iOld]
    +-       || pCell<aOld
    +-       || pCell>=&aOld[usableSize]
    ++       || !SQLITE_WITHIN(pCell,aOld,&aOld[usableSize])
    +       ){
    +         if( !leafCorrection ){
    +           ptrmapPut(pBt, get4byte(pCell), PTRMAP_BTREE, pNew->pgno, &rc);
    +@@ -62035,9 +68189,9 @@ static int balance_nonroot(
    +       ** any cell). But it is important to pass the correct size to 
    +       ** insertCell(), so reparse the cell now.
    +       **
    +-      ** Note that this can never happen in an SQLite data file, as all
    +-      ** cells are at least 4 bytes. It only happens in b-trees used
    +-      ** to evaluate "IN (SELECT ...)" and similar clauses.
    ++      ** This can only happen for b-trees used to evaluate "IN (SELECT ...)"
    ++      ** and WITHOUT ROWID tables with exactly one column which is the
    ++      ** primary key.
    +       */
    +       if( b.szCell[j]==4 ){
    +         assert(leafCorrection==4);
    +@@ -62134,7 +68288,7 @@ static int balance_nonroot(
    +     ** free space needs to be up front.
    +     */
    +     assert( nNew==1 || CORRUPT_DB );
    +-    rc = defragmentPage(apNew[0]);
    ++    rc = defragmentPage(apNew[0], -1);
    +     testcase( rc!=SQLITE_OK );
    +     assert( apNew[0]->nFree == 
    +         (get2byte(&apNew[0]->aData[5])-apNew[0]->cellOffset-apNew[0]->nCell*2)
    +@@ -62177,7 +68331,7 @@ static int balance_nonroot(
    +   ** Cleanup before returning.
    +   */
    + balance_cleanup:
    +-  sqlite3ScratchFree(b.apCell);
    ++  sqlite3StackFree(0, b.apCell);
    +   for(i=0; i<nOld; i++){
    +     releasePage(apOld[i]);
    +   }
    +@@ -62187,9 +68341,6 @@ balance_cleanup:
    + 
    +   return rc;
    + }
    +-#if defined(_MSC_VER) && _MSC_VER >= 1700 && defined(_M_ARM)
    +-#pragma optimize("", on)
    +-#endif
    + 
    + 
    + /*
    +@@ -62274,12 +68425,12 @@ static int balance(BtCursor *pCur){
    +   u8 aBalanceQuickSpace[13];
    +   u8 *pFree = 0;
    + 
    +-  TESTONLY( int balance_quick_called = 0 );
    +-  TESTONLY( int balance_deeper_called = 0 );
    ++  VVA_ONLY( int balance_quick_called = 0 );
    ++  VVA_ONLY( int balance_deeper_called = 0 );
    + 
    +   do {
    +     int iPage = pCur->iPage;
    +-    MemPage *pPage = pCur->apPage[iPage];
    ++    MemPage *pPage = pCur->pPage;
    + 
    +     if( iPage==0 ){
    +       if( pPage->nOverflow ){
    +@@ -62288,13 +68439,16 @@ static int balance(BtCursor *pCur){
    +         ** and copy the current contents of the root-page to it. The
    +         ** next iteration of the do-loop will balance the child page.
    +         */ 
    +-        assert( (balance_deeper_called++)==0 );
    ++        assert( balance_deeper_called==0 );
    ++        VVA_ONLY( balance_deeper_called++ );
    +         rc = balance_deeper(pPage, &pCur->apPage[1]);
    +         if( rc==SQLITE_OK ){
    +           pCur->iPage = 1;
    ++          pCur->ix = 0;
    +           pCur->aiIdx[0] = 0;
    +-          pCur->aiIdx[1] = 0;
    +-          assert( pCur->apPage[1]->nOverflow );
    ++          pCur->apPage[0] = pPage;
    ++          pCur->pPage = pCur->apPage[1];
    ++          assert( pCur->pPage->nOverflow );
    +         }
    +       }else{
    +         break;
    +@@ -62327,7 +68481,8 @@ static int balance(BtCursor *pCur){
    +           ** function. If this were not verified, a subtle bug involving reuse
    +           ** of the aBalanceQuickSpace[] might sneak in.
    +           */
    +-          assert( (balance_quick_called++)==0 );
    ++          assert( balance_quick_called==0 ); 
    ++          VVA_ONLY( balance_quick_called++ );
    +           rc = balance_quick(pParent, pPage, aBalanceQuickSpace);
    +         }else
    + #endif
    +@@ -62373,6 +68528,7 @@ static int balance(BtCursor *pCur){
    +       releasePage(pPage);
    +       pCur->iPage--;
    +       assert( pCur->iPage>=0 );
    ++      pCur->pPage = pCur->apPage[pCur->iPage];
    +     }
    +   }while( rc==SQLITE_OK );
    + 
    +@@ -62384,33 +68540,39 @@ static int balance(BtCursor *pCur){
    + 
    + 
    + /*
    +-** Insert a new record into the BTree.  The key is given by (pKey,nKey)
    +-** and the data is given by (pData,nData).  The cursor is used only to
    +-** define what table the record should be inserted into.  The cursor
    +-** is left pointing at a random location.
    ++** Insert a new record into the BTree.  The content of the new record
    ++** is described by the pX object.  The pCur cursor is used only to
    ++** define what table the record should be inserted into, and is left
    ++** pointing at a random location.
    ++**
    ++** For a table btree (used for rowid tables), only the pX.nKey value of
    ++** the key is used. The pX.pKey value must be NULL.  The pX.nKey is the
    ++** rowid or INTEGER PRIMARY KEY of the row.  The pX.nData,pData,nZero fields
    ++** hold the content of the row.
    + **
    +-** For an INTKEY table, only the nKey value of the key is used.  pKey is
    +-** ignored.  For a ZERODATA table, the pData and nData are both ignored.
    ++** For an index btree (used for indexes and WITHOUT ROWID tables), the
    ++** key is an arbitrary byte sequence stored in pX.pKey,nKey.  The 
    ++** pX.pData,nData,nZero fields must be zero.
    + **
    + ** If the seekResult parameter is non-zero, then a successful call to
    +-** MovetoUnpacked() to seek cursor pCur to (pKey, nKey) has already
    +-** been performed. seekResult is the search result returned (a negative
    +-** number if pCur points at an entry that is smaller than (pKey, nKey), or
    +-** a positive value if pCur points at an entry that is larger than 
    +-** (pKey, nKey)). 
    +-**
    +-** If the seekResult parameter is non-zero, then the caller guarantees that
    +-** cursor pCur is pointing at the existing copy of a row that is to be
    +-** overwritten.  If the seekResult parameter is 0, then cursor pCur may
    +-** point to any entry or to no entry at all and so this function has to seek
    +-** the cursor before the new key can be inserted.
    ++** MovetoUnpacked() to seek cursor pCur to (pKey,nKey) has already
    ++** been performed.  In other words, if seekResult!=0 then the cursor
    ++** is currently pointing to a cell that will be adjacent to the cell
    ++** to be inserted.  If seekResult<0 then pCur points to a cell that is
    ++** smaller then (pKey,nKey).  If seekResult>0 then pCur points to a cell
    ++** that is larger than (pKey,nKey).
    ++**
    ++** If seekResult==0, that means pCur is pointing at some unknown location.
    ++** In that case, this routine must seek the cursor to the correct insertion
    ++** point for (pKey,nKey) before doing the insertion.  For index btrees,
    ++** if pX->nMem is non-zero, then pX->aMem contains pointers to the unpacked
    ++** key values and pX->aMem can be used instead of pX->pKey to avoid having
    ++** to decode the key.
    + */
    + SQLITE_PRIVATE int sqlite3BtreeInsert(
    +   BtCursor *pCur,                /* Insert data into the table of this cursor */
    +-  const void *pKey, i64 nKey,    /* The key of the new record */
    +-  const void *pData, int nData,  /* The data of the new record */
    +-  int nZero,                     /* Number of extra 0 bytes to append to data */
    +-  int appendBias,                /* True if this is likely an append */
    ++  const BtreePayload *pX,        /* Content of the row to be inserted */
    ++  int flags,                     /* True if this is likely an append */
    +   int seekResult                 /* Result of prior MovetoUnpacked() call */
    + ){
    +   int rc;
    +@@ -62423,12 +68585,14 @@ SQLITE_PRIVATE int sqlite3BtreeInsert(
    +   unsigned char *oldCell;
    +   unsigned char *newCell = 0;
    + 
    ++  assert( (flags & (BTREE_SAVEPOSITION|BTREE_APPEND))==flags );
    ++
    +   if( pCur->eState==CURSOR_FAULT ){
    +     assert( pCur->skipNext!=SQLITE_OK );
    +     return pCur->skipNext;
    +   }
    + 
    +-  assert( cursorHoldsMutex(pCur) );
    ++  assert( cursorOwnsBtShared(pCur) );
    +   assert( (pCur->curFlags & BTCF_WriteFlag)!=0
    +               && pBt->inTransaction==TRANS_WRITE
    +               && (pBt->btsFlags & BTS_READ_ONLY)==0 );
    +@@ -62439,7 +68603,7 @@ SQLITE_PRIVATE int sqlite3BtreeInsert(
    +   ** keys with no associated data. If the cursor was opened expecting an
    +   ** intkey table, the caller should be inserting integer keys with a
    +   ** blob of associated data.  */
    +-  assert( (pKey==0)==(pCur->pKeyInfo==0) );
    ++  assert( (pX->pKey==0)==(pCur->pKeyInfo==0) );
    + 
    +   /* Save the positions of any other cursors open on this table.
    +   **
    +@@ -62458,44 +68622,61 @@ SQLITE_PRIVATE int sqlite3BtreeInsert(
    +   }
    + 
    +   if( pCur->pKeyInfo==0 ){
    +-    assert( pKey==0 );
    ++    assert( pX->pKey==0 );
    +     /* If this is an insert into a table b-tree, invalidate any incrblob 
    +     ** cursors open on the row being replaced */
    +-    invalidateIncrblobCursors(p, nKey, 0);
    ++    invalidateIncrblobCursors(p, pCur->pgnoRoot, pX->nKey, 0);
    ++
    ++    /* If BTREE_SAVEPOSITION is set, the cursor must already be pointing 
    ++    ** to a row with the same key as the new entry being inserted.  */
    ++    assert( (flags & BTREE_SAVEPOSITION)==0 || 
    ++            ((pCur->curFlags&BTCF_ValidNKey)!=0 && pX->nKey==pCur->info.nKey) );
    + 
    +     /* 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->curFlags&BTCF_ValidNKey)!=0 && nKey>0
    +-      && pCur->info.nKey==nKey-1 ){
    +-       loc = -1;
    ++    if( (pCur->curFlags&BTCF_ValidNKey)!=0 && pX->nKey==pCur->info.nKey ){
    ++      loc = 0;
    +     }else if( loc==0 ){
    +-      rc = sqlite3BtreeMovetoUnpacked(pCur, 0, nKey, appendBias, &loc);
    ++      rc = sqlite3BtreeMovetoUnpacked(pCur, 0, pX->nKey, flags!=0, &loc);
    +       if( rc ) return rc;
    +     }
    +-  }else if( loc==0 ){
    +-    rc = btreeMoveto(pCur, pKey, nKey, appendBias, &loc);
    ++  }else if( loc==0 && (flags & BTREE_SAVEPOSITION)==0 ){
    ++    if( pX->nMem ){
    ++      UnpackedRecord r;
    ++      r.pKeyInfo = pCur->pKeyInfo;
    ++      r.aMem = pX->aMem;
    ++      r.nField = pX->nMem;
    ++      r.default_rc = 0;
    ++      r.errCode = 0;
    ++      r.r1 = 0;
    ++      r.r2 = 0;
    ++      r.eqSeen = 0;
    ++      rc = sqlite3BtreeMovetoUnpacked(pCur, &r, 0, flags!=0, &loc);
    ++    }else{
    ++      rc = btreeMoveto(pCur, pX->pKey, pX->nKey, flags!=0, &loc);
    ++    }
    +     if( rc ) return rc;
    +   }
    +   assert( pCur->eState==CURSOR_VALID || (pCur->eState==CURSOR_INVALID && loc) );
    + 
    +-  pPage = pCur->apPage[pCur->iPage];
    +-  assert( pPage->intKey || nKey>=0 );
    ++  pPage = pCur->pPage;
    ++  assert( pPage->intKey || pX->nKey>=0 );
    +   assert( pPage->leaf || !pPage->intKey );
    + 
    +   TRACE(("INSERT: table=%d nkey=%lld ndata=%d page=%d %s\n",
    +-          pCur->pgnoRoot, nKey, nData, pPage->pgno,
    ++          pCur->pgnoRoot, pX->nKey, pX->nData, pPage->pgno,
    +           loc==0 ? "overwrite" : "new entry"));
    +   assert( pPage->isInit );
    +   newCell = pBt->pTmpSpace;
    +   assert( newCell!=0 );
    +-  rc = fillInCell(pPage, newCell, pKey, nKey, pData, nData, nZero, &szNew);
    ++  rc = fillInCell(pPage, newCell, pX, &szNew);
    +   if( rc ) goto end_insert;
    +   assert( szNew==pPage->xCellSize(pPage, newCell) );
    +   assert( szNew <= MX_CELL_SIZE(pBt) );
    +-  idx = pCur->aiIdx[pCur->iPage];
    ++  idx = pCur->ix;
    +   if( loc==0 ){
    +-    u16 szOld;
    ++    CellInfo info;
    +     assert( idx<pPage->nCell );
    +     rc = sqlite3PagerWrite(pPage->pDbPage);
    +     if( rc ){
    +@@ -62505,16 +68686,35 @@ SQLITE_PRIVATE int sqlite3BtreeInsert(
    +     if( !pPage->leaf ){
    +       memcpy(newCell, oldCell, 4);
    +     }
    +-    rc = clearCell(pPage, oldCell, &szOld);
    +-    dropCell(pPage, idx, szOld, &rc);
    ++    rc = clearCell(pPage, oldCell, &info);
    ++    if( info.nSize==szNew && info.nLocal==info.nPayload 
    ++     && (!ISAUTOVACUUM || szNew<pPage->minLocal)
    ++    ){
    ++      /* Overwrite the old cell with the new if they are the same size.
    ++      ** We could also try to do this if the old cell is smaller, then add
    ++      ** the leftover space to the free list.  But experiments show that
    ++      ** doing that is no faster then skipping this optimization and just
    ++      ** calling dropCell() and insertCell(). 
    ++      **
    ++      ** This optimization cannot be used on an autovacuum database if the
    ++      ** new entry uses overflow pages, as the insertCell() call below is
    ++      ** necessary to add the PTRMAP_OVERFLOW1 pointer-map entry.  */
    ++      assert( rc==SQLITE_OK ); /* clearCell never fails when nLocal==nPayload */
    ++      if( oldCell+szNew > pPage->aDataEnd ) return SQLITE_CORRUPT_BKPT;
    ++      memcpy(oldCell, newCell, szNew);
    ++      return SQLITE_OK;
    ++    }
    ++    dropCell(pPage, idx, info.nSize, &rc);
    +     if( rc ) goto end_insert;
    +   }else if( loc<0 && pPage->nCell>0 ){
    +     assert( pPage->leaf );
    +-    idx = ++pCur->aiIdx[pCur->iPage];
    ++    idx = ++pCur->ix;
    ++    pCur->curFlags &= ~BTCF_ValidNKey;
    +   }else{
    +     assert( pPage->leaf );
    +   }
    +   insertCell(pPage, idx, newCell, szNew, 0, 0, &rc);
    ++  assert( pPage->nOverflow==0 || rc==SQLITE_OK );
    +   assert( rc!=SQLITE_OK || pPage->nCell>0 || pPage->nOverflow>0 );
    + 
    +   /* If no error has occurred and pPage has an overflow cell, call balance() 
    +@@ -62538,7 +68738,8 @@ SQLITE_PRIVATE int sqlite3BtreeInsert(
    +   ** row without seeking the cursor. This can be a big performance boost.
    +   */
    +   pCur->info.nSize = 0;
    +-  if( rc==SQLITE_OK && pPage->nOverflow ){
    ++  if( pPage->nOverflow ){
    ++    assert( rc==SQLITE_OK );
    +     pCur->curFlags &= ~(BTCF_ValidNKey);
    +     rc = balance(pCur);
    + 
    +@@ -62546,10 +68747,24 @@ SQLITE_PRIVATE int sqlite3BtreeInsert(
    +     ** fails. Internal data structure corruption will result otherwise. 
    +     ** Also, set the cursor state to invalid. This stops saveCursorPosition()
    +     ** from trying to save the current position of the cursor.  */
    +-    pCur->apPage[pCur->iPage]->nOverflow = 0;
    ++    pCur->pPage->nOverflow = 0;
    +     pCur->eState = CURSOR_INVALID;
    ++    if( (flags & BTREE_SAVEPOSITION) && rc==SQLITE_OK ){
    ++      btreeReleaseAllCursorPages(pCur);
    ++      if( pCur->pKeyInfo ){
    ++        assert( pCur->pKey==0 );
    ++        pCur->pKey = sqlite3Malloc( pX->nKey );
    ++        if( pCur->pKey==0 ){
    ++          rc = SQLITE_NOMEM;
    ++        }else{
    ++          memcpy(pCur->pKey, pX->pKey, pX->nKey);
    ++        }
    ++      }
    ++      pCur->eState = CURSOR_REQUIRESEEK;
    ++      pCur->nKey = pX->nKey;
    ++    }
    +   }
    +-  assert( pCur->apPage[pCur->iPage]->nOverflow==0 );
    ++  assert( pCur->iPage<0 || pCur->pPage->nOverflow==0 );
    + 
    + end_insert:
    +   return rc;
    +@@ -62558,13 +68773,21 @@ end_insert:
    + /*
    + ** Delete the entry that the cursor is pointing to. 
    + **
    +-** If the second parameter is zero, then the cursor is left pointing at an
    +-** arbitrary location after the delete. If it is non-zero, then the cursor 
    +-** is left in a state such that the next call to BtreeNext() or BtreePrev()
    +-** moves it to the same row as it would if the call to BtreeDelete() had
    +-** been omitted.
    +-*/
    +-SQLITE_PRIVATE int sqlite3BtreeDelete(BtCursor *pCur, int bPreserve){
    ++** If the BTREE_SAVEPOSITION bit of the flags parameter is zero, then
    ++** the cursor is left pointing at an arbitrary location after the delete.
    ++** But if that bit is set, then the cursor is left in a state such that
    ++** the next call to BtreeNext() or BtreePrev() moves it to the same row
    ++** as it would have been on if the call to BtreeDelete() had been omitted.
    ++**
    ++** The BTREE_AUXDELETE bit of flags indicates that is one of several deletes
    ++** associated with a single table entry and its indexes.  Only one of those
    ++** deletes is considered the "primary" delete.  The primary delete occurs
    ++** on a cursor that is not a BTREE_FORDELETE cursor.  All but one delete
    ++** operation on non-FORDELETE cursors is tagged with the AUXDELETE flag.
    ++** The BTREE_AUXDELETE bit is a hint that is not used by this implementation,
    ++** but which might be used by alternative storage engines.
    ++*/
    ++SQLITE_PRIVATE int sqlite3BtreeDelete(BtCursor *pCur, u8 flags){
    +   Btree *p = pCur->pBtree;
    +   BtShared *pBt = p->pBt;              
    +   int rc;                              /* Return code */
    +@@ -62572,23 +68795,47 @@ SQLITE_PRIVATE int sqlite3BtreeDelete(BtCursor *pCur, int bPreserve){
    +   unsigned char *pCell;                /* Pointer to cell to delete */
    +   int iCellIdx;                        /* Index of cell to delete */
    +   int iCellDepth;                      /* Depth of node containing pCell */ 
    +-  u16 szCell;                          /* Size of the cell being deleted */
    ++  CellInfo info;                       /* Size of the cell being deleted */
    +   int bSkipnext = 0;                   /* Leaf cursor in SKIPNEXT state */
    ++  u8 bPreserve = flags & BTREE_SAVEPOSITION;  /* Keep cursor valid */
    + 
    +-  assert( cursorHoldsMutex(pCur) );
    ++  assert( cursorOwnsBtShared(pCur) );
    +   assert( pBt->inTransaction==TRANS_WRITE );
    +   assert( (pBt->btsFlags & BTS_READ_ONLY)==0 );
    +   assert( pCur->curFlags & BTCF_WriteFlag );
    +   assert( hasSharedCacheTableLock(p, pCur->pgnoRoot, pCur->pKeyInfo!=0, 2) );
    +   assert( !hasReadConflicts(p, pCur->pgnoRoot) );
    +-  assert( pCur->aiIdx[pCur->iPage]<pCur->apPage[pCur->iPage]->nCell );
    ++  assert( pCur->ix<pCur->pPage->nCell );
    +   assert( pCur->eState==CURSOR_VALID );
    ++  assert( (flags & ~(BTREE_SAVEPOSITION | BTREE_AUXDELETE))==0 );
    + 
    +   iCellDepth = pCur->iPage;
    +-  iCellIdx = pCur->aiIdx[iCellDepth];
    +-  pPage = pCur->apPage[iCellDepth];
    ++  iCellIdx = pCur->ix;
    ++  pPage = pCur->pPage;
    +   pCell = findCell(pPage, iCellIdx);
    + 
    ++  /* If the bPreserve flag is set to true, then the cursor position must
    ++  ** be preserved following this delete operation. If the current delete
    ++  ** will cause a b-tree rebalance, then this is done by saving the cursor
    ++  ** key and leaving the cursor in CURSOR_REQUIRESEEK state before 
    ++  ** returning. 
    ++  **
    ++  ** Or, if the current delete will not cause a rebalance, then the cursor
    ++  ** will be left in CURSOR_SKIPNEXT state pointing to the entry immediately
    ++  ** before or after the deleted entry. In this case set bSkipnext to true.  */
    ++  if( bPreserve ){
    ++    if( !pPage->leaf 
    ++     || (pPage->nFree+cellSizePtr(pPage,pCell)+2)>(int)(pBt->usableSize*2/3)
    ++    ){
    ++      /* A b-tree rebalance will be required after deleting this entry.
    ++      ** Save the cursor key.  */
    ++      rc = saveCursorKey(pCur);
    ++      if( rc ) return rc;
    ++    }else{
    ++      bSkipnext = 1;
    ++    }
    ++  }
    ++
    +   /* If the page containing the entry to delete is not a leaf page, move
    +   ** the cursor to the largest entry in the tree that is smaller than
    +   ** the entry being deleted. This cell will replace the cell being deleted
    +@@ -62597,8 +68844,8 @@ SQLITE_PRIVATE int sqlite3BtreeDelete(BtCursor *pCur, int bPreserve){
    +   ** sub-tree headed by the child page of the cell being deleted. This makes
    +   ** balancing the tree following the delete operation easier.  */
    +   if( !pPage->leaf ){
    +-    int notUsed = 0;
    +-    rc = sqlite3BtreePrevious(pCur, &notUsed);
    ++    rc = sqlite3BtreePrevious(pCur, 0);
    ++    assert( rc!=SQLITE_DONE );
    +     if( rc ) return rc;
    +   }
    + 
    +@@ -62612,29 +68859,7 @@ SQLITE_PRIVATE int sqlite3BtreeDelete(BtCursor *pCur, int bPreserve){
    +   /* If this is a delete operation to remove a row from a table b-tree,
    +   ** invalidate any incrblob cursors open on the row being deleted.  */
    +   if( pCur->pKeyInfo==0 ){
    +-    invalidateIncrblobCursors(p, pCur->info.nKey, 0);
    +-  }
    +-
    +-  /* If the bPreserve flag is set to true, then the cursor position must
    +-  ** be preserved following this delete operation. If the current delete
    +-  ** will cause a b-tree rebalance, then this is done by saving the cursor
    +-  ** key and leaving the cursor in CURSOR_REQUIRESEEK state before 
    +-  ** returning. 
    +-  **
    +-  ** Or, if the current delete will not cause a rebalance, then the cursor
    +-  ** will be left in CURSOR_SKIPNEXT state pointing to the entry immediately
    +-  ** before or after the deleted entry. In this case set bSkipnext to true.  */
    +-  if( bPreserve ){
    +-    if( !pPage->leaf 
    +-     || (pPage->nFree+cellSizePtr(pPage,pCell)+2)>(int)(pBt->usableSize*2/3)
    +-    ){
    +-      /* A b-tree rebalance will be required after deleting this entry.
    +-      ** Save the cursor key.  */
    +-      rc = saveCursorKey(pCur);
    +-      if( rc ) return rc;
    +-    }else{
    +-      bSkipnext = 1;
    +-    }
    ++    invalidateIncrblobCursors(p, pCur->pgnoRoot, pCur->info.nKey, 0);
    +   }
    + 
    +   /* Make the page containing the entry to be deleted writable. Then free any
    +@@ -62642,8 +68867,8 @@ SQLITE_PRIVATE int sqlite3BtreeDelete(BtCursor *pCur, int bPreserve){
    +   ** itself from within the page.  */
    +   rc = sqlite3PagerWrite(pPage->pDbPage);
    +   if( rc ) return rc;
    +-  rc = clearCell(pPage, pCell, &szCell);
    +-  dropCell(pPage, iCellIdx, szCell, &rc);
    ++  rc = clearCell(pPage, pCell, &info);
    ++  dropCell(pPage, iCellIdx, info.nSize, &rc);
    +   if( rc ) return rc;
    + 
    +   /* If the cell deleted was not located on a leaf page, then the cursor
    +@@ -62652,11 +68877,16 @@ SQLITE_PRIVATE int sqlite3BtreeDelete(BtCursor *pCur, int bPreserve){
    +   ** node. The cell from the leaf node needs to be moved to the internal
    +   ** node to replace the deleted cell.  */
    +   if( !pPage->leaf ){
    +-    MemPage *pLeaf = pCur->apPage[pCur->iPage];
    ++    MemPage *pLeaf = pCur->pPage;
    +     int nCell;
    +-    Pgno n = pCur->apPage[iCellDepth+1]->pgno;
    ++    Pgno n;
    +     unsigned char *pTmp;
    + 
    ++    if( iCellDepth<pCur->iPage-1 ){
    ++      n = pCur->apPage[iCellDepth+1]->pgno;
    ++    }else{
    ++      n = pCur->pPage->pgno;
    ++    }
    +     pCell = findCell(pLeaf, pLeaf->nCell-1);
    +     if( pCell<&pLeaf->aData[4] ) return SQLITE_CORRUPT_BKPT;
    +     nCell = pLeaf->xCellSize(pLeaf, pCell);
    +@@ -62664,7 +68894,9 @@ SQLITE_PRIVATE int sqlite3BtreeDelete(BtCursor *pCur, int bPreserve){
    +     pTmp = pBt->pTmpSpace;
    +     assert( pTmp!=0 );
    +     rc = sqlite3PagerWrite(pLeaf->pDbPage);
    +-    insertCell(pPage, iCellIdx, pCell-4, nCell+4, pTmp, n, &rc);
    ++    if( rc==SQLITE_OK ){
    ++      insertCell(pPage, iCellIdx, pCell-4, nCell+4, pTmp, n, &rc);
    ++    }
    +     dropCell(pLeaf, pLeaf->nCell-1, nCell, &rc);
    +     if( rc ) return rc;
    +   }
    +@@ -62686,29 +68918,34 @@ SQLITE_PRIVATE int sqlite3BtreeDelete(BtCursor *pCur, int bPreserve){
    +   ** well.  */
    +   rc = balance(pCur);
    +   if( rc==SQLITE_OK && pCur->iPage>iCellDepth ){
    ++    releasePageNotNull(pCur->pPage);
    ++    pCur->iPage--;
    +     while( pCur->iPage>iCellDepth ){
    +       releasePage(pCur->apPage[pCur->iPage--]);
    +     }
    ++    pCur->pPage = pCur->apPage[pCur->iPage];
    +     rc = balance(pCur);
    +   }
    + 
    +   if( rc==SQLITE_OK ){
    +     if( bSkipnext ){
    +-      assert( bPreserve && pCur->iPage==iCellDepth );
    +-      assert( pPage==pCur->apPage[pCur->iPage] );
    ++      assert( bPreserve && (pCur->iPage==iCellDepth || CORRUPT_DB) );
    ++      assert( pPage==pCur->pPage || CORRUPT_DB );
    +       assert( (pPage->nCell>0 || CORRUPT_DB) && iCellIdx<=pPage->nCell );
    +       pCur->eState = CURSOR_SKIPNEXT;
    +       if( iCellIdx>=pPage->nCell ){
    +         pCur->skipNext = -1;
    +-        pCur->aiIdx[iCellDepth] = pPage->nCell-1;
    ++        pCur->ix = pPage->nCell-1;
    +       }else{
    +         pCur->skipNext = 1;
    +       }
    +     }else{
    +       rc = moveToRoot(pCur);
    +       if( bPreserve ){
    ++        btreeReleaseAllCursorPages(pCur);
    +         pCur->eState = CURSOR_REQUIRESEEK;
    +       }
    ++      if( rc==SQLITE_EMPTY ) rc = SQLITE_OK;
    +     }
    +   }
    +   return rc;
    +@@ -62891,7 +69128,7 @@ static int clearDatabasePage(
    +   unsigned char *pCell;
    +   int i;
    +   int hdr;
    +-  u16 szCell;
    ++  CellInfo info;
    + 
    +   assert( sqlite3_mutex_held(pBt->mutex) );
    +   if( pgno>btreePagecount(pBt) ){
    +@@ -62911,7 +69148,7 @@ static int clearDatabasePage(
    +       rc = clearDatabasePage(pBt, get4byte(pCell), 1, pnChange);
    +       if( rc ) goto cleardatabasepage_out;
    +     }
    +-    rc = clearCell(pPage, pCell, &szCell);
    ++    rc = clearCell(pPage, pCell, &info);
    +     if( rc ) goto cleardatabasepage_out;
    +   }
    +   if( !pPage->leaf ){
    +@@ -62959,7 +69196,7 @@ SQLITE_PRIVATE int sqlite3BtreeClearTable(Btree *p, int iTable, int *pnChange){
    +     /* Invalidate all incrblob cursors open on table iTable (assuming iTable
    +     ** is the root of a table b-tree - if it is not, the following call is
    +     ** a no-op).  */
    +-    invalidateIncrblobCursors(p, 0, 1);
    ++    invalidateIncrblobCursors(p, (Pgno)iTable, 0, 1);
    +     rc = clearDatabasePage(pBt, (Pgno)iTable, 0, pnChange);
    +   }
    +   sqlite3BtreeLeave(p);
    +@@ -63002,19 +69239,7 @@ static int btreeDropTable(Btree *p, Pgno iTable, int *piMoved){
    + 
    +   assert( sqlite3BtreeHoldsMutex(p) );
    +   assert( p->inTrans==TRANS_WRITE );
    +-
    +-  /* It is illegal to drop a table if any cursors are open on the
    +-  ** database. This is because in auto-vacuum mode the backend may
    +-  ** need to move another root-page to fill a gap left by the deleted
    +-  ** root page. If an open cursor was using this page a problem would 
    +-  ** occur.
    +-  **
    +-  ** This error is caught long before control reaches this point.
    +-  */
    +-  if( NEVER(pBt->pCursor) ){
    +-    sqlite3ConnectionBlocked(p->db, pBt->pCursor->pBtree->db);
    +-    return SQLITE_LOCKED_SHAREDCACHE;
    +-  }
    ++  assert( iTable>=2 );
    + 
    +   rc = btreeGetPage(pBt, (Pgno)iTable, &pPage, 0);
    +   if( rc ) return rc;
    +@@ -63026,76 +69251,67 @@ static int btreeDropTable(Btree *p, Pgno iTable, int *piMoved){
    + 
    +   *piMoved = 0;
    + 
    +-  if( iTable>1 ){
    + #ifdef SQLITE_OMIT_AUTOVACUUM
    +-    freePage(pPage, &rc);
    +-    releasePage(pPage);
    ++  freePage(pPage, &rc);
    ++  releasePage(pPage);
    + #else
    +-    if( pBt->autoVacuum ){
    +-      Pgno maxRootPgno;
    +-      sqlite3BtreeGetMeta(p, BTREE_LARGEST_ROOT_PAGE, &maxRootPgno);
    +-
    +-      if( iTable==maxRootPgno ){
    +-        /* If the table being dropped is the table with the largest root-page
    +-        ** number in the database, put the root page on the free list. 
    +-        */
    +-        freePage(pPage, &rc);
    +-        releasePage(pPage);
    +-        if( rc!=SQLITE_OK ){
    +-          return rc;
    +-        }
    +-      }else{
    +-        /* The table being dropped does not have the largest root-page
    +-        ** number in the database. So move the page that does into the 
    +-        ** gap left by the deleted root-page.
    +-        */
    +-        MemPage *pMove;
    +-        releasePage(pPage);
    +-        rc = btreeGetPage(pBt, maxRootPgno, &pMove, 0);
    +-        if( rc!=SQLITE_OK ){
    +-          return rc;
    +-        }
    +-        rc = relocatePage(pBt, pMove, PTRMAP_ROOTPAGE, 0, iTable, 0);
    +-        releasePage(pMove);
    +-        if( rc!=SQLITE_OK ){
    +-          return rc;
    +-        }
    +-        pMove = 0;
    +-        rc = btreeGetPage(pBt, maxRootPgno, &pMove, 0);
    +-        freePage(pMove, &rc);
    +-        releasePage(pMove);
    +-        if( rc!=SQLITE_OK ){
    +-          return rc;
    +-        }
    +-        *piMoved = maxRootPgno;
    +-      }
    ++  if( pBt->autoVacuum ){
    ++    Pgno maxRootPgno;
    ++    sqlite3BtreeGetMeta(p, BTREE_LARGEST_ROOT_PAGE, &maxRootPgno);
    + 
    +-      /* Set the new 'max-root-page' value in the database header. This
    +-      ** is the old value less one, less one more if that happens to
    +-      ** be a root-page number, less one again if that is the
    +-      ** PENDING_BYTE_PAGE.
    ++    if( iTable==maxRootPgno ){
    ++      /* If the table being dropped is the table with the largest root-page
    ++      ** number in the database, put the root page on the free list. 
    +       */
    +-      maxRootPgno--;
    +-      while( maxRootPgno==PENDING_BYTE_PAGE(pBt)
    +-             || PTRMAP_ISPAGE(pBt, maxRootPgno) ){
    +-        maxRootPgno--;
    ++      freePage(pPage, &rc);
    ++      releasePage(pPage);
    ++      if( rc!=SQLITE_OK ){
    ++        return rc;
    +       }
    +-      assert( maxRootPgno!=PENDING_BYTE_PAGE(pBt) );
    +-
    +-      rc = sqlite3BtreeUpdateMeta(p, 4, maxRootPgno);
    +     }else{
    +-      freePage(pPage, &rc);
    ++      /* The table being dropped does not have the largest root-page
    ++      ** number in the database. So move the page that does into the 
    ++      ** gap left by the deleted root-page.
    ++      */
    ++      MemPage *pMove;
    +       releasePage(pPage);
    ++      rc = btreeGetPage(pBt, maxRootPgno, &pMove, 0);
    ++      if( rc!=SQLITE_OK ){
    ++        return rc;
    ++      }
    ++      rc = relocatePage(pBt, pMove, PTRMAP_ROOTPAGE, 0, iTable, 0);
    ++      releasePage(pMove);
    ++      if( rc!=SQLITE_OK ){
    ++        return rc;
    ++      }
    ++      pMove = 0;
    ++      rc = btreeGetPage(pBt, maxRootPgno, &pMove, 0);
    ++      freePage(pMove, &rc);
    ++      releasePage(pMove);
    ++      if( rc!=SQLITE_OK ){
    ++        return rc;
    ++      }
    ++      *piMoved = maxRootPgno;
    +     }
    +-#endif
    +-  }else{
    +-    /* If sqlite3BtreeDropTable was called on page 1.
    +-    ** This really never should happen except in a corrupt
    +-    ** database. 
    ++
    ++    /* Set the new 'max-root-page' value in the database header. This
    ++    ** is the old value less one, less one more if that happens to
    ++    ** be a root-page number, less one again if that is the
    ++    ** PENDING_BYTE_PAGE.
    +     */
    +-    zeroPage(pPage, PTF_INTKEY|PTF_LEAF );
    ++    maxRootPgno--;
    ++    while( maxRootPgno==PENDING_BYTE_PAGE(pBt)
    ++           || PTRMAP_ISPAGE(pBt, maxRootPgno) ){
    ++      maxRootPgno--;
    ++    }
    ++    assert( maxRootPgno!=PENDING_BYTE_PAGE(pBt) );
    ++
    ++    rc = sqlite3BtreeUpdateMeta(p, 4, maxRootPgno);
    ++  }else{
    ++    freePage(pPage, &rc);
    +     releasePage(pPage);
    +   }
    ++#endif
    +   return rc;  
    + }
    + SQLITE_PRIVATE int sqlite3BtreeDropTable(Btree *p, int iTable, int *piMoved){
    +@@ -63194,11 +69410,11 @@ SQLITE_PRIVATE int sqlite3BtreeCount(BtCursor *pCur, i64 *pnEntry){
    +   i64 nEntry = 0;                      /* Value to return in *pnEntry */
    +   int rc;                              /* Return code */
    + 
    +-  if( pCur->pgnoRoot==0 ){
    ++  rc = moveToRoot(pCur);
    ++  if( rc==SQLITE_EMPTY ){
    +     *pnEntry = 0;
    +     return SQLITE_OK;
    +   }
    +-  rc = moveToRoot(pCur);
    + 
    +   /* Unless an error occurs, the following loop runs one iteration for each
    +   ** page in the B-Tree structure (not including overflow pages). 
    +@@ -63211,7 +69427,7 @@ SQLITE_PRIVATE int sqlite3BtreeCount(BtCursor *pCur, i64 *pnEntry){
    +     ** this page contains countable entries. Increment the entry counter
    +     ** accordingly.
    +     */
    +-    pPage = pCur->apPage[pCur->iPage];
    ++    pPage = pCur->pPage;
    +     if( pPage->leaf || !pPage->intKey ){
    +       nEntry += pPage->nCell;
    +     }
    +@@ -63234,16 +69450,16 @@ SQLITE_PRIVATE int sqlite3BtreeCount(BtCursor *pCur, i64 *pnEntry){
    +           return moveToRoot(pCur);
    +         }
    +         moveToParent(pCur);
    +-      }while ( pCur->aiIdx[pCur->iPage]>=pCur->apPage[pCur->iPage]->nCell );
    ++      }while ( pCur->ix>=pCur->pPage->nCell );
    + 
    +-      pCur->aiIdx[pCur->iPage]++;
    +-      pPage = pCur->apPage[pCur->iPage];
    ++      pCur->ix++;
    ++      pPage = pCur->pPage;
    +     }
    + 
    +     /* Descend to the child node of the cell that the cursor currently 
    +     ** points at. This is the right-child if (iIdx==pPage->nCell).
    +     */
    +-    iIdx = pCur->aiIdx[pCur->iPage];
    ++    iIdx = pCur->ix;
    +     if( iIdx==pPage->nCell ){
    +       rc = moveToChild(pCur, get4byte(&pPage->aData[pPage->hdrOffset+8]));
    +     }else{
    +@@ -63282,9 +69498,9 @@ static void checkAppendMsg(
    +     sqlite3StrAccumAppend(&pCheck->errMsg, "\n", 1);
    +   }
    +   if( pCheck->zPfx ){
    +-    sqlite3XPrintf(&pCheck->errMsg, 0, pCheck->zPfx, pCheck->v1, pCheck->v2);
    ++    sqlite3XPrintf(&pCheck->errMsg, pCheck->zPfx, pCheck->v1, pCheck->v2);
    +   }
    +-  sqlite3VXPrintf(&pCheck->errMsg, 1, zFormat, ap);
    ++  sqlite3VXPrintf(&pCheck->errMsg, zFormat, ap);
    +   va_end(ap);
    +   if( pCheck->errMsg.accError==STRACCUM_NOMEM ){
    +     pCheck->mallocFailed = 1;
    +@@ -63388,7 +69604,7 @@ static void checkList(
    +       break;
    +     }
    +     if( checkRef(pCheck, iPage) ) break;
    +-    if( sqlite3PagerGet(pCheck->pPager, (Pgno)iPage, &pOvflPage) ){
    ++    if( sqlite3PagerGet(pCheck->pPager, (Pgno)iPage, &pOvflPage, 0) ){
    +       checkAppendMsg(pCheck, "failed to get page %d", iPage);
    +       break;
    +     }
    +@@ -63628,15 +69844,16 @@ static int checkTreePage(
    +         checkAppendMsg(pCheck, "Rowid %lld out of order", info.nKey);
    +       }
    +       maxKey = info.nKey;
    ++      keyCanBeEqual = 0;     /* Only the first key on the page may ==maxKey */
    +     }
    + 
    +     /* Check the content overflow list */
    +     if( info.nPayload>info.nLocal ){
    +       int nPage;       /* Number of pages on the overflow chain */
    +       Pgno pgnoOvfl;   /* First page of the overflow chain */
    +-      assert( pc + info.iOverflow <= usableSize );
    ++      assert( pc + info.nSize - 4 <= usableSize );
    +       nPage = (info.nPayload - info.nLocal + usableSize - 5)/(usableSize - 4);
    +-      pgnoOvfl = get4byte(&pCell[info.iOverflow]);
    ++      pgnoOvfl = get4byte(&pCell[info.nSize - 4]);
    + #ifndef SQLITE_OMIT_AUTOVACUUM
    +       if( pBt->autoVacuum ){
    +         checkPtrmap(pCheck, pgnoOvfl, PTRMAP_OVERFLOW1, iPage);
    +@@ -63785,7 +70002,8 @@ SQLITE_PRIVATE char *sqlite3BtreeIntegrityCheck(
    + 
    +   sqlite3BtreeEnter(p);
    +   assert( p->inTrans>TRANS_NONE && pBt->inTransaction>TRANS_NONE );
    +-  assert( (nRef = sqlite3PagerRefcount(pBt->pPager))>=0 );
    ++  VVA_ONLY( nRef = sqlite3PagerRefcount(pBt->pPager) );
    ++  assert( nRef>=0 );
    +   sCheck.pBt = pBt;
    +   sCheck.pPager = pBt->pPager;
    +   sCheck.nPage = btreePagecount(sCheck.pBt);
    +@@ -63798,6 +70016,7 @@ SQLITE_PRIVATE char *sqlite3BtreeIntegrityCheck(
    +   sCheck.aPgRef = 0;
    +   sCheck.heap = 0;
    +   sqlite3StrAccumInit(&sCheck.errMsg, 0, zErr, sizeof(zErr), SQLITE_MAX_LENGTH);
    ++  sCheck.errMsg.printfFlags = SQLITE_PRINTF_INTERNAL;
    +   if( sCheck.nPage==0 ){
    +     goto integrity_ck_cleanup;
    +   }
    +@@ -63929,7 +70148,7 @@ SQLITE_PRIVATE int sqlite3BtreeCheckpoint(Btree *p, int eMode, int *pnLog, int *
    +     if( pBt->inTransaction!=TRANS_NONE ){
    +       rc = SQLITE_LOCKED;
    +     }else{
    +-      rc = sqlite3PagerCheckpoint(pBt->pPager, eMode, pnLog, pnCkpt);
    ++      rc = sqlite3PagerCheckpoint(pBt->pPager, p->db, eMode, pnLog, pnCkpt);
    +     }
    +     sqlite3BtreeLeave(p);
    +   }
    +@@ -64037,7 +70256,7 @@ SQLITE_PRIVATE int sqlite3BtreeLockTable(Btree *p, int iTab, u8 isWriteLock){
    + */
    + SQLITE_PRIVATE int sqlite3BtreePutData(BtCursor *pCsr, u32 offset, u32 amt, void *z){
    +   int rc;
    +-  assert( cursorHoldsMutex(pCsr) );
    ++  assert( cursorOwnsBtShared(pCsr) );
    +   assert( sqlite3_mutex_held(pCsr->pBtree->db->mutex) );
    +   assert( pCsr->curFlags & BTCF_Incrblob );
    + 
    +@@ -64075,7 +70294,7 @@ SQLITE_PRIVATE int sqlite3BtreePutData(BtCursor *pCsr, u32 offset, u32 amt, void
    +               && pCsr->pBt->inTransaction==TRANS_WRITE );
    +   assert( hasSharedCacheTableLock(pCsr->pBtree, pCsr->pgnoRoot, 0, 2) );
    +   assert( !hasReadConflicts(pCsr->pBtree, pCsr->pgnoRoot) );
    +-  assert( pCsr->apPage[pCsr->iPage]->intKey );
    ++  assert( pCsr->pPage->intKey );
    + 
    +   return accessPayload(pCsr, offset, amt, (unsigned char *)z, 1);
    + }
    +@@ -64125,15 +70344,6 @@ SQLITE_PRIVATE int sqlite3BtreeSetVersion(Btree *pBtree, int iVersion){
    +   return rc;
    + }
    + 
    +-/*
    +-** set the mask of hint flags for cursor pCsr.
    +-*/
    +-SQLITE_PRIVATE void sqlite3BtreeCursorHints(BtCursor *pCsr, unsigned int mask){
    +-  assert( mask==BTREE_BULKLOAD || mask==BTREE_SEEK_EQ || mask==0 );
    +-  pCsr->hints = mask;
    +-}
    +-
    +-#ifdef SQLITE_DEBUG
    + /*
    + ** Return true if the cursor has a hint specified.  This routine is
    + ** only used from within assert() statements
    +@@ -64141,7 +70351,6 @@ SQLITE_PRIVATE void sqlite3BtreeCursorHints(BtCursor *pCsr, unsigned int mask){
    + SQLITE_PRIVATE int sqlite3BtreeCursorHasHint(BtCursor *pCsr, unsigned int mask){
    +   return (pCsr->hints & mask)!=0;
    + }
    +-#endif
    + 
    + /*
    + ** Return true if the given Btree is read-only.
    +@@ -64155,6 +70364,25 @@ SQLITE_PRIVATE int sqlite3BtreeIsReadonly(Btree *p){
    + */
    + SQLITE_PRIVATE int sqlite3HeaderSizeBtree(void){ return ROUND8(sizeof(MemPage)); }
    + 
    ++#if !defined(SQLITE_OMIT_SHARED_CACHE)
    ++/*
    ++** Return true if the Btree passed as the only argument is sharable.
    ++*/
    ++SQLITE_PRIVATE int sqlite3BtreeSharable(Btree *p){
    ++  return p->sharable;
    ++}
    ++
    ++/*
    ++** Return the number of connections to the BtShared object accessed by
    ++** the Btree handle passed as the only argument. For private caches 
    ++** this is always 1. For shared caches it may be 1 or greater.
    ++*/
    ++SQLITE_PRIVATE int sqlite3BtreeConnectionCount(Btree *p){
    ++  testcase( p->sharable );
    ++  return p->pBt->nRef;
    ++}
    ++#endif
    ++
    + /************** End of btree.c ***********************************************/
    + /************** Begin file backup.c ******************************************/
    + /*
    +@@ -64242,22 +70470,16 @@ static Btree *findBtree(sqlite3 *pErrorDb, sqlite3 *pDb, const char *zDb){
    +   int i = sqlite3FindDbName(pDb, zDb);
    + 
    +   if( i==1 ){
    +-    Parse *pParse;
    ++    Parse sParse;
    +     int rc = 0;
    +-    pParse = sqlite3StackAllocZero(pErrorDb, sizeof(*pParse));
    +-    if( pParse==0 ){
    +-      sqlite3ErrorWithMsg(pErrorDb, SQLITE_NOMEM, "out of memory");
    +-      rc = SQLITE_NOMEM;
    +-    }else{
    +-      pParse->db = pDb;
    +-      if( sqlite3OpenTempDatabase(pParse) ){
    +-        sqlite3ErrorWithMsg(pErrorDb, pParse->rc, "%s", pParse->zErrMsg);
    +-        rc = SQLITE_ERROR;
    +-      }
    +-      sqlite3DbFree(pErrorDb, pParse->zErrMsg);
    +-      sqlite3ParserReset(pParse);
    +-      sqlite3StackFree(pErrorDb, pParse);
    ++    memset(&sParse, 0, sizeof(sParse));
    ++    sParse.db = pDb;
    ++    if( sqlite3OpenTempDatabase(&sParse) ){
    ++      sqlite3ErrorWithMsg(pErrorDb, sParse.rc, "%s", sParse.zErrMsg);
    ++      rc = SQLITE_ERROR;
    +     }
    ++    sqlite3DbFree(pErrorDb, sParse.zErrMsg);
    ++    sqlite3ParserReset(&sParse);
    +     if( rc ){
    +       return 0;
    +     }
    +@@ -64303,7 +70525,7 @@ static int checkReadTransaction(sqlite3 *db, Btree *p){
    + ** If an error occurs, NULL is returned and an error code and error message
    + ** stored in database handle pDestDb.
    + */
    +-SQLITE_API sqlite3_backup *SQLITE_STDCALL sqlite3_backup_init(
    ++SQLITE_API sqlite3_backup *sqlite3_backup_init(
    +   sqlite3* pDestDb,                     /* Database to write to */
    +   const char *zDestDb,                  /* Name of database within pDestDb */
    +   sqlite3* pSrcDb,                      /* Database connection to read from */
    +@@ -64341,7 +70563,7 @@ SQLITE_API sqlite3_backup *SQLITE_STDCALL sqlite3_backup_init(
    +     ** sqlite3_backup_finish(). */
    +     p = (sqlite3_backup *)sqlite3MallocZero(sizeof(sqlite3_backup));
    +     if( !p ){
    +-      sqlite3Error(pDestDb, SQLITE_NOMEM);
    ++      sqlite3Error(pDestDb, SQLITE_NOMEM_BKPT);
    +     }
    +   }
    + 
    +@@ -64355,7 +70577,6 @@ SQLITE_API sqlite3_backup *SQLITE_STDCALL sqlite3_backup_init(
    +     p->isAttached = 0;
    + 
    +     if( 0==p->pSrc || 0==p->pDest 
    +-     || setDestPgsz(p)==SQLITE_NOMEM 
    +      || checkReadTransaction(pDestDb, p->pDest)!=SQLITE_OK 
    +      ){
    +       /* One (or both) of the named databases did not exist or an OOM
    +@@ -64452,7 +70673,7 @@ static int backupOnePage(
    +     DbPage *pDestPg = 0;
    +     Pgno iDest = (Pgno)(iOff/nDestPgsz)+1;
    +     if( iDest==PENDING_BYTE_PAGE(p->pDest->pBt) ) continue;
    +-    if( SQLITE_OK==(rc = sqlite3PagerGet(pDestPager, iDest, &pDestPg))
    ++    if( SQLITE_OK==(rc = sqlite3PagerGet(pDestPager, iDest, &pDestPg, 0))
    +      && SQLITE_OK==(rc = sqlite3PagerWrite(pDestPg))
    +     ){
    +       const u8 *zIn = &zSrcData[iOff%nSrcPgsz];
    +@@ -64511,7 +70732,7 @@ static void attachBackupObject(sqlite3_backup *p){
    + /*
    + ** Copy nPage pages from the source b-tree to the destination.
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_backup_step(sqlite3_backup *p, int nPage){
    ++SQLITE_API int sqlite3_backup_step(sqlite3_backup *p, int nPage){
    +   int rc;
    +   int destMode;       /* Destination journal mode */
    +   int pgszSrc = 0;    /* Source page size */
    +@@ -64543,14 +70764,6 @@ SQLITE_API int SQLITE_STDCALL sqlite3_backup_step(sqlite3_backup *p, int nPage){
    +       rc = SQLITE_OK;
    +     }
    + 
    +-    /* Lock the destination database, if it is not locked already. */
    +-    if( SQLITE_OK==rc && p->bDestLocked==0
    +-     && SQLITE_OK==(rc = sqlite3BtreeBeginTrans(p->pDest, 2)) 
    +-    ){
    +-      p->bDestLocked = 1;
    +-      sqlite3BtreeGetMeta(p->pDest, BTREE_SCHEMA_VERSION, &p->iDestSchema);
    +-    }
    +-
    +     /* If there is no open read-transaction on the source database, open
    +     ** one now. If a transaction is opened here, then it will be closed
    +     ** before this function exits.
    +@@ -64560,6 +70773,24 @@ SQLITE_API int SQLITE_STDCALL sqlite3_backup_step(sqlite3_backup *p, int nPage){
    +       bCloseTrans = 1;
    +     }
    + 
    ++    /* If the destination database has not yet been locked (i.e. if this
    ++    ** is the first call to backup_step() for the current backup operation),
    ++    ** try to set its page size to the same as the source database. This
    ++    ** is especially important on ZipVFS systems, as in that case it is
    ++    ** not possible to create a database file that uses one page size by
    ++    ** writing to it with another.  */
    ++    if( p->bDestLocked==0 && rc==SQLITE_OK && setDestPgsz(p)==SQLITE_NOMEM ){
    ++      rc = SQLITE_NOMEM;
    ++    }
    ++
    ++    /* Lock the destination database, if it is not locked already. */
    ++    if( SQLITE_OK==rc && p->bDestLocked==0
    ++     && SQLITE_OK==(rc = sqlite3BtreeBeginTrans(p->pDest, 2)) 
    ++    ){
    ++      p->bDestLocked = 1;
    ++      sqlite3BtreeGetMeta(p->pDest, BTREE_SCHEMA_VERSION, &p->iDestSchema);
    ++    }
    ++
    +     /* Do not allow backup if the destination database is in WAL mode
    +     ** and the page sizes are different between source and destination */
    +     pgszSrc = sqlite3BtreeGetPageSize(p->pSrc);
    +@@ -64578,8 +70809,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_backup_step(sqlite3_backup *p, int nPage){
    +       const Pgno iSrcPg = p->iNext;                 /* Source page number */
    +       if( iSrcPg!=PENDING_BYTE_PAGE(p->pSrc->pBt) ){
    +         DbPage *pSrcPg;                             /* Source page object */
    +-        rc = sqlite3PagerAcquire(pSrcPager, iSrcPg, &pSrcPg,
    +-                                 PAGER_GET_READONLY);
    ++        rc = sqlite3PagerGet(pSrcPager, iSrcPg, &pSrcPg,PAGER_GET_READONLY);
    +         if( rc==SQLITE_OK ){
    +           rc = backupOnePage(p, iSrcPg, sqlite3PagerGetData(pSrcPg), 0);
    +           sqlite3PagerUnref(pSrcPg);
    +@@ -64679,7 +70909,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_backup_step(sqlite3_backup *p, int nPage){
    +           for(iPg=nDestTruncate; rc==SQLITE_OK && iPg<=(Pgno)nDstPage; iPg++){
    +             if( iPg!=PENDING_BYTE_PAGE(p->pDest->pBt) ){
    +               DbPage *pPg;
    +-              rc = sqlite3PagerGet(pDestPager, iPg, &pPg);
    ++              rc = sqlite3PagerGet(pDestPager, iPg, &pPg, 0);
    +               if( rc==SQLITE_OK ){
    +                 rc = sqlite3PagerWrite(pPg);
    +                 sqlite3PagerUnref(pPg);
    +@@ -64699,7 +70929,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_backup_step(sqlite3_backup *p, int nPage){
    +           ){
    +             PgHdr *pSrcPg = 0;
    +             const Pgno iSrcPg = (Pgno)((iOff/pgszSrc)+1);
    +-            rc = sqlite3PagerGet(pSrcPager, iSrcPg, &pSrcPg);
    ++            rc = sqlite3PagerGet(pSrcPager, iSrcPg, &pSrcPg, 0);
    +             if( rc==SQLITE_OK ){
    +               u8 *zData = sqlite3PagerGetData(pSrcPg);
    +               rc = sqlite3OsWrite(pFile, zData, pgszSrc, iOff);
    +@@ -64741,7 +70971,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_backup_step(sqlite3_backup *p, int nPage){
    +     }
    +   
    +     if( rc==SQLITE_IOERR_NOMEM ){
    +-      rc = SQLITE_NOMEM;
    ++      rc = SQLITE_NOMEM_BKPT;
    +     }
    +     p->rc = rc;
    +   }
    +@@ -64756,7 +70986,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_backup_step(sqlite3_backup *p, int nPage){
    + /*
    + ** Release all resources associated with an sqlite3_backup* handle.
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_backup_finish(sqlite3_backup *p){
    ++SQLITE_API int sqlite3_backup_finish(sqlite3_backup *p){
    +   sqlite3_backup **pp;                 /* Ptr to head of pagers backup list */
    +   sqlite3 *pSrcDb;                     /* Source database connection */
    +   int rc;                              /* Value to return */
    +@@ -64808,7 +71038,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_backup_finish(sqlite3_backup *p){
    + ** Return the number of pages still to be backed up as of the most recent
    + ** call to sqlite3_backup_step().
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_backup_remaining(sqlite3_backup *p){
    ++SQLITE_API int sqlite3_backup_remaining(sqlite3_backup *p){
    + #ifdef SQLITE_ENABLE_API_ARMOR
    +   if( p==0 ){
    +     (void)SQLITE_MISUSE_BKPT;
    +@@ -64822,7 +71052,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_backup_remaining(sqlite3_backup *p){
    + ** Return the total number of pages in the source database as of the most 
    + ** recent call to sqlite3_backup_step().
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_backup_pagecount(sqlite3_backup *p){
    ++SQLITE_API int sqlite3_backup_pagecount(sqlite3_backup *p){
    + #ifdef SQLITE_ENABLE_API_ARMOR
    +   if( p==0 ){
    +     (void)SQLITE_MISUSE_BKPT;
    +@@ -64937,10 +71167,10 @@ SQLITE_PRIVATE int sqlite3BtreeCopyFile(Btree *pTo, Btree *pFrom){
    +   ** sqlite3_backup_step(), we can guarantee that the copy finishes 
    +   ** within a single call (unless an error occurs). The assert() statement
    +   ** checks this assumption - (p->rc) should be set to either SQLITE_DONE 
    +-  ** or an error code.
    +-  */
    ++  ** or an error code.  */
    +   sqlite3_backup_step(&b, 0x7FFFFFFF);
    +   assert( b.rc!=SQLITE_OK );
    ++
    +   rc = sqlite3_backup_finish(&b);
    +   if( rc==SQLITE_OK ){
    +     pTo->pBt->btsFlags &= ~BTS_PAGESIZE_FIXED;
    +@@ -64987,7 +71217,7 @@ copy_finished:
    + */
    + SQLITE_PRIVATE int sqlite3VdbeCheckMemInvariants(Mem *p){
    +   /* If MEM_Dyn is set then Mem.xDel!=0.  
    +-  ** Mem.xDel is might not be initialized if MEM_Dyn is clear.
    ++  ** Mem.xDel might not be initialized if MEM_Dyn is clear.
    +   */
    +   assert( (p->flags & MEM_Dyn)==0 || p->xDel!=0 );
    + 
    +@@ -65000,6 +71230,35 @@ SQLITE_PRIVATE int sqlite3VdbeCheckMemInvariants(Mem *p){
    +   /* Cannot be both MEM_Int and MEM_Real at the same time */
    +   assert( (p->flags & (MEM_Int|MEM_Real))!=(MEM_Int|MEM_Real) );
    + 
    ++  if( p->flags & MEM_Null ){
    ++    /* Cannot be both MEM_Null and some other type */
    ++    assert( (p->flags & (MEM_Int|MEM_Real|MEM_Str|MEM_Blob
    ++                         |MEM_RowSet|MEM_Frame|MEM_Agg))==0 );
    ++
    ++    /* If MEM_Null is set, then either the value is a pure NULL (the usual
    ++    ** case) or it is a pointer set using sqlite3_bind_pointer() or
    ++    ** sqlite3_result_pointer().  If a pointer, then MEM_Term must also be
    ++    ** set.
    ++    */
    ++    if( (p->flags & (MEM_Term|MEM_Subtype))==(MEM_Term|MEM_Subtype) ){
    ++      /* This is a pointer type.  There may be a flag to indicate what to
    ++      ** do with the pointer. */
    ++      assert( ((p->flags&MEM_Dyn)!=0 ? 1 : 0) +
    ++              ((p->flags&MEM_Ephem)!=0 ? 1 : 0) +
    ++              ((p->flags&MEM_Static)!=0 ? 1 : 0) <= 1 );
    ++
    ++      /* No other bits set */
    ++      assert( (p->flags & ~(MEM_Null|MEM_Term|MEM_Subtype
    ++                           |MEM_Dyn|MEM_Ephem|MEM_Static))==0 );
    ++    }else{
    ++      /* A pure NULL might have other flags, such as MEM_Static, MEM_Dyn,
    ++      ** MEM_Ephem, MEM_Cleared, or MEM_Subtype */
    ++    }
    ++  }else{
    ++    /* The MEM_Cleared bit is only allowed on NULLs */
    ++    assert( (p->flags & MEM_Cleared)==0 );
    ++  }
    ++
    +   /* The szMalloc field holds the correct memory allocation size */
    +   assert( p->szMalloc==0
    +        || p->szMalloc==sqlite3DbMallocSize(p->db,p->zMalloc) );
    +@@ -65076,6 +71335,7 @@ SQLITE_PRIVATE int sqlite3VdbeChangeEncoding(Mem *pMem, int desiredEnc){
    + SQLITE_PRIVATE SQLITE_NOINLINE int sqlite3VdbeMemGrow(Mem *pMem, int n, int bPreserve){
    +   assert( sqlite3VdbeCheckMemInvariants(pMem) );
    +   assert( (pMem->flags&MEM_RowSet)==0 );
    ++  testcase( pMem->db==0 );
    + 
    +   /* If the bPreserve flag is set to true, then the memory cell must already
    +   ** contain a valid string or blob value.  */
    +@@ -65084,26 +71344,25 @@ SQLITE_PRIVATE SQLITE_NOINLINE int sqlite3VdbeMemGrow(Mem *pMem, int n, int bPre
    + 
    +   assert( pMem->szMalloc==0
    +        || pMem->szMalloc==sqlite3DbMallocSize(pMem->db, pMem->zMalloc) );
    +-  if( pMem->szMalloc<n ){
    +-    if( n<32 ) n = 32;
    +-    if( bPreserve && pMem->szMalloc>0 && pMem->z==pMem->zMalloc ){
    +-      pMem->z = pMem->zMalloc = sqlite3DbReallocOrFree(pMem->db, pMem->z, n);
    +-      bPreserve = 0;
    +-    }else{
    +-      if( pMem->szMalloc>0 ) sqlite3DbFree(pMem->db, pMem->zMalloc);
    +-      pMem->zMalloc = sqlite3DbMallocRaw(pMem->db, n);
    +-    }
    +-    if( pMem->zMalloc==0 ){
    +-      sqlite3VdbeMemSetNull(pMem);
    +-      pMem->z = 0;
    +-      pMem->szMalloc = 0;
    +-      return SQLITE_NOMEM;
    +-    }else{
    +-      pMem->szMalloc = sqlite3DbMallocSize(pMem->db, pMem->zMalloc);
    +-    }
    ++  if( n<32 ) n = 32;
    ++  if( pMem->szMalloc>0 && bPreserve && pMem->z==pMem->zMalloc ){
    ++    pMem->z = pMem->zMalloc = sqlite3DbReallocOrFree(pMem->db, pMem->z, n);
    ++    bPreserve = 0;
    ++  }else{
    ++    if( pMem->szMalloc>0 ) sqlite3DbFreeNN(pMem->db, pMem->zMalloc);
    ++    pMem->zMalloc = sqlite3DbMallocRaw(pMem->db, n);
    ++  }
    ++  if( pMem->zMalloc==0 ){
    ++    sqlite3VdbeMemSetNull(pMem);
    ++    pMem->z = 0;
    ++    pMem->szMalloc = 0;
    ++    return SQLITE_NOMEM_BKPT;
    ++  }else{
    ++    pMem->szMalloc = sqlite3DbMallocSize(pMem->db, pMem->zMalloc);
    +   }
    + 
    +-  if( bPreserve && pMem->z && pMem->z!=pMem->zMalloc ){
    ++  if( bPreserve && pMem->z ){
    ++    assert( pMem->z!=pMem->zMalloc );
    +     memcpy(pMem->zMalloc, pMem->z, pMem->n);
    +   }
    +   if( (pMem->flags&MEM_Dyn)!=0 ){
    +@@ -65141,6 +71400,20 @@ SQLITE_PRIVATE int sqlite3VdbeMemClearAndResize(Mem *pMem, int szNew){
    +   return SQLITE_OK;
    + }
    + 
    ++/*
    ++** It is already known that pMem contains an unterminated string.
    ++** Add the zero terminator.
    ++*/
    ++static SQLITE_NOINLINE int vdbeMemAddTerminator(Mem *pMem){
    ++  if( sqlite3VdbeMemGrow(pMem, pMem->n+2, 1) ){
    ++    return SQLITE_NOMEM_BKPT;
    ++  }
    ++  pMem->z[pMem->n] = 0;
    ++  pMem->z[pMem->n+1] = 0;
    ++  pMem->flags |= MEM_Term;
    ++  return SQLITE_OK;
    ++}
    ++
    + /*
    + ** Change pMem so that its MEM_Str or MEM_Blob value is stored in
    + ** MEM.zMalloc, where it can be safely written.
    +@@ -65148,18 +71421,14 @@ SQLITE_PRIVATE int sqlite3VdbeMemClearAndResize(Mem *pMem, int szNew){
    + ** Return SQLITE_OK on success or SQLITE_NOMEM if malloc fails.
    + */
    + SQLITE_PRIVATE int sqlite3VdbeMemMakeWriteable(Mem *pMem){
    +-  int f;
    +   assert( pMem->db==0 || sqlite3_mutex_held(pMem->db->mutex) );
    +   assert( (pMem->flags&MEM_RowSet)==0 );
    +-  ExpandBlob(pMem);
    +-  f = pMem->flags;
    +-  if( (f&(MEM_Str|MEM_Blob)) && (pMem->szMalloc==0 || pMem->z!=pMem->zMalloc) ){
    +-    if( sqlite3VdbeMemGrow(pMem, pMem->n + 2, 1) ){
    +-      return SQLITE_NOMEM;
    ++  if( (pMem->flags & (MEM_Str|MEM_Blob))!=0 ){
    ++    if( ExpandBlob(pMem) ) return SQLITE_NOMEM;
    ++    if( pMem->szMalloc==0 || pMem->z!=pMem->zMalloc ){
    ++      int rc = vdbeMemAddTerminator(pMem);
    ++      if( rc ) return rc;
    +     }
    +-    pMem->z[pMem->n] = 0;
    +-    pMem->z[pMem->n+1] = 0;
    +-    pMem->flags |= MEM_Term;
    +   }
    +   pMem->flags &= ~MEM_Ephem;
    + #ifdef SQLITE_DEBUG
    +@@ -65175,42 +71444,27 @@ SQLITE_PRIVATE int sqlite3VdbeMemMakeWriteable(Mem *pMem){
    + */
    + #ifndef SQLITE_OMIT_INCRBLOB
    + SQLITE_PRIVATE int sqlite3VdbeMemExpandBlob(Mem *pMem){
    +-  if( pMem->flags & MEM_Zero ){
    +-    int nByte;
    +-    assert( pMem->flags&MEM_Blob );
    +-    assert( (pMem->flags&MEM_RowSet)==0 );
    +-    assert( pMem->db==0 || sqlite3_mutex_held(pMem->db->mutex) );
    +-
    +-    /* Set nByte to the number of bytes required to store the expanded blob. */
    +-    nByte = pMem->n + pMem->u.nZero;
    +-    if( nByte<=0 ){
    +-      nByte = 1;
    +-    }
    +-    if( sqlite3VdbeMemGrow(pMem, nByte, 1) ){
    +-      return SQLITE_NOMEM;
    +-    }
    ++  int nByte;
    ++  assert( pMem->flags & MEM_Zero );
    ++  assert( pMem->flags&MEM_Blob );
    ++  assert( (pMem->flags&MEM_RowSet)==0 );
    ++  assert( pMem->db==0 || sqlite3_mutex_held(pMem->db->mutex) );
    + 
    +-    memset(&pMem->z[pMem->n], 0, pMem->u.nZero);
    +-    pMem->n += pMem->u.nZero;
    +-    pMem->flags &= ~(MEM_Zero|MEM_Term);
    ++  /* Set nByte to the number of bytes required to store the expanded blob. */
    ++  nByte = pMem->n + pMem->u.nZero;
    ++  if( nByte<=0 ){
    ++    nByte = 1;
    +   }
    +-  return SQLITE_OK;
    +-}
    +-#endif
    +-
    +-/*
    +-** It is already known that pMem contains an unterminated string.
    +-** Add the zero terminator.
    +-*/
    +-static SQLITE_NOINLINE int vdbeMemAddTerminator(Mem *pMem){
    +-  if( sqlite3VdbeMemGrow(pMem, pMem->n+2, 1) ){
    +-    return SQLITE_NOMEM;
    ++  if( sqlite3VdbeMemGrow(pMem, nByte, 1) ){
    ++    return SQLITE_NOMEM_BKPT;
    +   }
    +-  pMem->z[pMem->n] = 0;
    +-  pMem->z[pMem->n+1] = 0;
    +-  pMem->flags |= MEM_Term;
    ++
    ++  memset(&pMem->z[pMem->n], 0, pMem->u.nZero);
    ++  pMem->n += pMem->u.nZero;
    ++  pMem->flags &= ~(MEM_Zero|MEM_Term);
    +   return SQLITE_OK;
    + }
    ++#endif
    + 
    + /*
    + ** Make sure the given Mem is \u0000 terminated.
    +@@ -65253,7 +71507,8 @@ SQLITE_PRIVATE int sqlite3VdbeMemStringify(Mem *pMem, u8 enc, u8 bForce){
    + 
    + 
    +   if( sqlite3VdbeMemClearAndResize(pMem, nByte) ){
    +-    return SQLITE_NOMEM;
    ++    pMem->enc = 0;
    ++    return SQLITE_NOMEM_BKPT;
    +   }
    + 
    +   /* For a Real or Integer, use sqlite3_snprintf() to produce the UTF-8
    +@@ -65285,26 +71540,24 @@ SQLITE_PRIVATE int sqlite3VdbeMemStringify(Mem *pMem, u8 enc, u8 bForce){
    + ** otherwise.
    + */
    + SQLITE_PRIVATE int sqlite3VdbeMemFinalize(Mem *pMem, FuncDef *pFunc){
    +-  int rc = SQLITE_OK;
    +-  if( ALWAYS(pFunc && pFunc->xFinalize) ){
    +-    sqlite3_context ctx;
    +-    Mem t;
    +-    assert( (pMem->flags & MEM_Null)!=0 || pFunc==pMem->u.pDef );
    +-    assert( pMem->db==0 || sqlite3_mutex_held(pMem->db->mutex) );
    +-    memset(&ctx, 0, sizeof(ctx));
    +-    memset(&t, 0, sizeof(t));
    +-    t.flags = MEM_Null;
    +-    t.db = pMem->db;
    +-    ctx.pOut = &t;
    +-    ctx.pMem = pMem;
    +-    ctx.pFunc = pFunc;
    +-    pFunc->xFinalize(&ctx); /* IMP: R-24505-23230 */
    +-    assert( (pMem->flags & MEM_Dyn)==0 );
    +-    if( pMem->szMalloc>0 ) sqlite3DbFree(pMem->db, pMem->zMalloc);
    +-    memcpy(pMem, &t, sizeof(t));
    +-    rc = ctx.isError;
    +-  }
    +-  return rc;
    ++  sqlite3_context ctx;
    ++  Mem t;
    ++  assert( pFunc!=0 );
    ++  assert( pFunc->xFinalize!=0 );
    ++  assert( (pMem->flags & MEM_Null)!=0 || pFunc==pMem->u.pDef );
    ++  assert( pMem->db==0 || sqlite3_mutex_held(pMem->db->mutex) );
    ++  memset(&ctx, 0, sizeof(ctx));
    ++  memset(&t, 0, sizeof(t));
    ++  t.flags = MEM_Null;
    ++  t.db = pMem->db;
    ++  ctx.pOut = &t;
    ++  ctx.pMem = pMem;
    ++  ctx.pFunc = pFunc;
    ++  pFunc->xFinalize(&ctx); /* IMP: R-24505-23230 */
    ++  assert( (pMem->flags & MEM_Dyn)==0 );
    ++  if( pMem->szMalloc>0 ) sqlite3DbFreeNN(pMem->db, pMem->zMalloc);
    ++  memcpy(pMem, &t, sizeof(t));
    ++  return ctx.isError;
    + }
    + 
    + /*
    +@@ -65351,7 +71604,7 @@ static SQLITE_NOINLINE void vdbeMemClear(Mem *p){
    +     vdbeMemClearExternAndSetNull(p);
    +   }
    +   if( p->szMalloc ){
    +-    sqlite3DbFree(p->db, p->zMalloc);
    ++    sqlite3DbFreeNN(p->db, p->zMalloc);
    +     p->szMalloc = 0;
    +   }
    +   p->z = 0;
    +@@ -65379,7 +71632,7 @@ SQLITE_PRIVATE void sqlite3VdbeMemRelease(Mem *p){
    + ** If the double is out of range of a 64-bit signed integer then
    + ** return the closest available 64-bit signed integer.
    + */
    +-static i64 doubleToInt64(double r){
    ++static SQLITE_NOINLINE i64 doubleToInt64(double r){
    + #ifdef SQLITE_OMIT_FLOATING_POINT
    +   /* When floating-point is omitted, double and int64 are the same thing */
    +   return r;
    +@@ -65415,6 +71668,11 @@ static i64 doubleToInt64(double r){
    + **
    + ** If pMem represents a string value, its encoding might be changed.
    + */
    ++static SQLITE_NOINLINE i64 memIntValue(Mem *pMem){
    ++  i64 value = 0;
    ++  sqlite3Atoi64(pMem->z, &value, pMem->n, pMem->enc);
    ++  return value;
    ++}
    + SQLITE_PRIVATE i64 sqlite3VdbeIntValue(Mem *pMem){
    +   int flags;
    +   assert( pMem->db==0 || sqlite3_mutex_held(pMem->db->mutex) );
    +@@ -65425,10 +71683,8 @@ SQLITE_PRIVATE i64 sqlite3VdbeIntValue(Mem *pMem){
    +   }else if( flags & MEM_Real ){
    +     return doubleToInt64(pMem->u.r);
    +   }else if( flags & (MEM_Str|MEM_Blob) ){
    +-    i64 value = 0;
    +     assert( pMem->z || pMem->n==0 );
    +-    sqlite3Atoi64(pMem->z, &value, pMem->n, pMem->enc);
    +-    return value;
    ++    return memIntValue(pMem);
    +   }else{
    +     return 0;
    +   }
    +@@ -65440,6 +71696,12 @@ SQLITE_PRIVATE i64 sqlite3VdbeIntValue(Mem *pMem){
    + ** value.  If it is a string or blob, try to convert it to a double.
    + ** If it is a NULL, return 0.0.
    + */
    ++static SQLITE_NOINLINE double memRealValue(Mem *pMem){
    ++  /* (double)0 In case of SQLITE_OMIT_FLOATING_POINT... */
    ++  double val = (double)0;
    ++  sqlite3AtoF(pMem->z, &val, pMem->n, pMem->enc);
    ++  return val;
    ++}
    + SQLITE_PRIVATE double sqlite3VdbeRealValue(Mem *pMem){
    +   assert( pMem->db==0 || sqlite3_mutex_held(pMem->db->mutex) );
    +   assert( EIGHT_BYTE_ALIGNMENT(pMem) );
    +@@ -65448,10 +71710,7 @@ SQLITE_PRIVATE double sqlite3VdbeRealValue(Mem *pMem){
    +   }else if( pMem->flags & MEM_Int ){
    +     return (double)pMem->u.i;
    +   }else if( pMem->flags & (MEM_Str|MEM_Blob) ){
    +-    /* (double)0 In case of SQLITE_OMIT_FLOATING_POINT... */
    +-    double val = (double)0;
    +-    sqlite3AtoF(pMem->z, &val, pMem->n, pMem->enc);
    +-    return val;
    ++    return memRealValue(pMem);
    +   }else{
    +     /* (double)0 In case of SQLITE_OMIT_FLOATING_POINT... */
    +     return (double)0;
    +@@ -65523,18 +71782,25 @@ SQLITE_PRIVATE int sqlite3VdbeMemRealify(Mem *pMem){
    + */
    + SQLITE_PRIVATE int sqlite3VdbeMemNumerify(Mem *pMem){
    +   if( (pMem->flags & (MEM_Int|MEM_Real|MEM_Null))==0 ){
    ++    int rc;
    +     assert( (pMem->flags & (MEM_Blob|MEM_Str))!=0 );
    +     assert( pMem->db==0 || sqlite3_mutex_held(pMem->db->mutex) );
    +-    if( 0==sqlite3Atoi64(pMem->z, &pMem->u.i, pMem->n, pMem->enc) ){
    ++    rc = sqlite3Atoi64(pMem->z, &pMem->u.i, pMem->n, pMem->enc);
    ++    if( rc==0 ){
    +       MemSetTypeFlag(pMem, MEM_Int);
    +     }else{
    +-      pMem->u.r = sqlite3VdbeRealValue(pMem);
    +-      MemSetTypeFlag(pMem, MEM_Real);
    +-      sqlite3VdbeIntegerAffinity(pMem);
    ++      i64 i = pMem->u.i;
    ++      sqlite3AtoF(pMem->z, &pMem->u.r, pMem->n, pMem->enc);
    ++      if( rc==1 && pMem->u.r==(double)i ){
    ++        pMem->u.i = i;
    ++        MemSetTypeFlag(pMem, MEM_Int);
    ++      }else{
    ++        MemSetTypeFlag(pMem, MEM_Real);
    ++      }
    +     }
    +   }
    +   assert( (pMem->flags & (MEM_Int|MEM_Real|MEM_Null))!=0 );
    +-  pMem->flags &= ~(MEM_Str|MEM_Blob);
    ++  pMem->flags &= ~(MEM_Str|MEM_Blob|MEM_Zero);
    +   return SQLITE_OK;
    + }
    + 
    +@@ -65552,7 +71818,7 @@ SQLITE_PRIVATE void sqlite3VdbeMemCast(Mem *pMem, u8 aff, u8 encoding){
    +       if( (pMem->flags & MEM_Blob)==0 ){
    +         sqlite3ValueApplyAffinity(pMem, SQLITE_AFF_TEXT, encoding);
    +         assert( pMem->flags & MEM_Str || pMem->db->mallocFailed );
    +-        MemSetTypeFlag(pMem, MEM_Blob);
    ++        if( pMem->flags & MEM_Str ) MemSetTypeFlag(pMem, MEM_Blob);
    +       }else{
    +         pMem->flags &= ~(MEM_TypeMask&~MEM_Blob);
    +       }
    +@@ -65656,6 +71922,27 @@ SQLITE_PRIVATE void sqlite3VdbeMemSetInt64(Mem *pMem, i64 val){
    +   }
    + }
    + 
    ++/* A no-op destructor */
    ++static void sqlite3NoopDestructor(void *p){ UNUSED_PARAMETER(p); }
    ++
    ++/*
    ++** Set the value stored in *pMem should already be a NULL.
    ++** Also store a pointer to go with it.
    ++*/
    ++SQLITE_PRIVATE void sqlite3VdbeMemSetPointer(
    ++  Mem *pMem,
    ++  void *pPtr,
    ++  const char *zPType,
    ++  void (*xDestructor)(void*)
    ++){
    ++  assert( pMem->flags==MEM_Null );
    ++  pMem->u.zPType = zPType ? zPType : "";
    ++  pMem->z = pPtr;
    ++  pMem->flags = MEM_Null|MEM_Dyn|MEM_Subtype|MEM_Term;
    ++  pMem->eSubtype = 'p';
    ++  pMem->xDel = xDestructor ? xDestructor : sqlite3NoopDestructor;
    ++}
    ++
    + #ifndef SQLITE_OMIT_FLOATING_POINT
    + /*
    + ** Delete any previous value and set the value stored in *pMem to val,
    +@@ -65679,7 +71966,7 @@ SQLITE_PRIVATE void sqlite3VdbeMemSetRowSet(Mem *pMem){
    +   assert( db!=0 );
    +   assert( (pMem->flags & MEM_RowSet)==0 );
    +   sqlite3VdbeMemRelease(pMem);
    +-  pMem->zMalloc = sqlite3DbMallocRaw(db, 64);
    ++  pMem->zMalloc = sqlite3DbMallocRawNN(db, 64);
    +   if( db->mallocFailed ){
    +     pMem->flags = MEM_Null;
    +     pMem->szMalloc = 0;
    +@@ -65720,7 +72007,7 @@ SQLITE_PRIVATE int sqlite3VdbeMemTooBig(Mem *p){
    + SQLITE_PRIVATE void sqlite3VdbeMemAboutToChange(Vdbe *pVdbe, Mem *pMem){
    +   int i;
    +   Mem *pX;
    +-  for(i=1, pX=&pVdbe->aMem[1]; i<=pVdbe->nMem; i++, pX++){
    ++  for(i=0, pX=pVdbe->aMem; i<pVdbe->nMem; i++, pX++){
    +     if( pX->pScopyFrom==pMem ){
    +       pX->flags |= MEM_Undefined;
    +       pX->pScopyFrom = 0;
    +@@ -65761,10 +72048,6 @@ SQLITE_PRIVATE void sqlite3VdbeMemShallowCopy(Mem *pTo, const Mem *pFrom, int sr
    + SQLITE_PRIVATE int sqlite3VdbeMemCopy(Mem *pTo, const Mem *pFrom){
    +   int rc = SQLITE_OK;
    + 
    +-  /* The pFrom==0 case in the following assert() is when an sqlite3_value
    +-  ** from sqlite3_value_dup() is used as the argument
    +-  ** to sqlite3_result_value(). */
    +-  assert( pTo->db==pFrom->db || pFrom->db==0 );
    +   assert( (pFrom->flags & MEM_RowSet)==0 );
    +   if( VdbeMemDynamic(pTo) ) vdbeMemClearExternAndSetNull(pTo);
    +   memcpy(pTo, pFrom, MEMCELLSIZE);
    +@@ -65840,7 +72123,7 @@ SQLITE_PRIVATE int sqlite3VdbeMemSetStr(
    +   if( nByte<0 ){
    +     assert( enc!=0 );
    +     if( enc==SQLITE_UTF8 ){
    +-      nByte = sqlite3Strlen30(z);
    ++      nByte = 0x7fffffff & (int)strlen(z);
    +       if( nByte>iLimit ) nByte = iLimit+1;
    +     }else{
    +       for(nByte=0; nByte<=iLimit && (z[nByte] | z[nByte+1]); nByte+=2){}
    +@@ -65864,7 +72147,7 @@ SQLITE_PRIVATE int sqlite3VdbeMemSetStr(
    +     testcase( nAlloc==31 );
    +     testcase( nAlloc==32 );
    +     if( sqlite3VdbeMemClearAndResize(pMem, MAX(nAlloc,32)) ){
    +-      return SQLITE_NOMEM;
    ++      return SQLITE_NOMEM_BKPT;
    +     }
    +     memcpy(pMem->z, z, nAlloc);
    +   }else if( xDel==SQLITE_DYNAMIC ){
    +@@ -65884,7 +72167,7 @@ SQLITE_PRIVATE int sqlite3VdbeMemSetStr(
    + 
    + #ifndef SQLITE_OMIT_UTF16
    +   if( pMem->enc!=SQLITE_UTF8 && sqlite3VdbeMemHandleBom(pMem) ){
    +-    return SQLITE_NOMEM;
    ++    return SQLITE_NOMEM_BKPT;
    +   }
    + #endif
    + 
    +@@ -65897,10 +72180,9 @@ SQLITE_PRIVATE int sqlite3VdbeMemSetStr(
    + 
    + /*
    + ** Move data out of a btree key or data field and into a Mem structure.
    +-** The data or key is taken from the entry that pCur is currently pointing
    ++** The data is payload from the entry that pCur is currently pointing
    + ** to.  offset and amt determine what portion of the data or key to retrieve.
    +-** key is true to get the key or false to get data.  The result is written
    +-** into the pMem element.
    ++** The result is written into the pMem element.
    + **
    + ** The pMem object must have been initialized.  This routine will use
    + ** pMem->zMalloc to hold the content from the btree, if possible.  New
    +@@ -65915,21 +72197,15 @@ static SQLITE_NOINLINE int vdbeMemFromBtreeResize(
    +   BtCursor *pCur,   /* Cursor pointing at record to retrieve. */
    +   u32 offset,       /* Offset from the start of data to return bytes from. */
    +   u32 amt,          /* Number of bytes to return. */
    +-  int key,          /* If true, retrieve from the btree key, not data. */
    +   Mem *pMem         /* OUT: Return data in this Mem structure. */
    + ){
    +   int rc;
    +   pMem->flags = MEM_Null;
    +-  if( SQLITE_OK==(rc = sqlite3VdbeMemClearAndResize(pMem, amt+2)) ){
    +-    if( key ){
    +-      rc = sqlite3BtreeKey(pCur, offset, amt, pMem->z);
    +-    }else{
    +-      rc = sqlite3BtreeData(pCur, offset, amt, pMem->z);
    +-    }
    ++  if( SQLITE_OK==(rc = sqlite3VdbeMemClearAndResize(pMem, amt+1)) ){
    ++    rc = sqlite3BtreePayload(pCur, offset, amt, pMem->z);
    +     if( rc==SQLITE_OK ){
    +-      pMem->z[amt] = 0;
    +-      pMem->z[amt+1] = 0;
    +-      pMem->flags = MEM_Blob|MEM_Term;
    ++      pMem->z[amt] = 0;   /* Overrun area used when reading malformed records */
    ++      pMem->flags = MEM_Blob;
    +       pMem->n = (int)amt;
    +     }else{
    +       sqlite3VdbeMemRelease(pMem);
    +@@ -65941,7 +72217,6 @@ SQLITE_PRIVATE int sqlite3VdbeMemFromBtree(
    +   BtCursor *pCur,   /* Cursor pointing at record to retrieve. */
    +   u32 offset,       /* Offset from the start of data to return bytes from. */
    +   u32 amt,          /* Number of bytes to return. */
    +-  int key,          /* If true, retrieve from the btree key, not data. */
    +   Mem *pMem         /* OUT: Return data in this Mem structure. */
    + ){
    +   char *zData;        /* Data from the btree layer */
    +@@ -65954,11 +72229,7 @@ SQLITE_PRIVATE int sqlite3VdbeMemFromBtree(
    +   /* Note: the calls to BtreeKeyFetch() and DataFetch() below assert() 
    +   ** that both the BtShared and database handle mutexes are held. */
    +   assert( (pMem->flags & MEM_RowSet)==0 );
    +-  if( key ){
    +-    zData = (char *)sqlite3BtreeKeyFetch(pCur, &available);
    +-  }else{
    +-    zData = (char *)sqlite3BtreeDataFetch(pCur, &available);
    +-  }
    ++  zData = (char *)sqlite3BtreePayloadFetch(pCur, &available);
    +   assert( zData!=0 );
    + 
    +   if( offset+amt<=available ){
    +@@ -65966,7 +72237,7 @@ SQLITE_PRIVATE int sqlite3VdbeMemFromBtree(
    +     pMem->flags = MEM_Blob|MEM_Ephem;
    +     pMem->n = (int)amt;
    +   }else{
    +-    rc = vdbeMemFromBtreeResize(pCur, offset, amt, key, pMem);
    ++    rc = vdbeMemFromBtreeResize(pCur, offset, amt, pMem);
    +   }
    + 
    +   return rc;
    +@@ -65984,10 +72255,8 @@ static SQLITE_NOINLINE const void *valueToText(sqlite3_value* pVal, u8 enc){
    +   assert( (pVal->flags & MEM_RowSet)==0 );
    +   assert( (pVal->flags & (MEM_Null))==0 );
    +   if( pVal->flags & (MEM_Blob|MEM_Str) ){
    ++    if( ExpandBlob(pVal) ) return 0;
    +     pVal->flags |= MEM_Str;
    +-    if( pVal->flags & MEM_Zero ){
    +-      sqlite3VdbeMemExpandBlob(pVal);
    +-    }
    +     if( pVal->enc != (enc & ~SQLITE_UTF16_ALIGNED) ){
    +       sqlite3VdbeChangeEncoding(pVal, enc & ~SQLITE_UTF16_ALIGNED);
    +     }
    +@@ -66085,7 +72354,7 @@ static sqlite3_value *valueNew(sqlite3 *db, struct ValueNewStat4Ctx *p){
    +       if( pRec ){
    +         pRec->pKeyInfo = sqlite3KeyInfoOfIndex(p->pParse, pIdx);
    +         if( pRec->pKeyInfo ){
    +-          assert( pRec->pKeyInfo->nField+pRec->pKeyInfo->nXField==nCol );
    ++          assert( pRec->pKeyInfo->nAllField==nCol );
    +           assert( pRec->pKeyInfo->enc==ENC(db) );
    +           pRec->aMem = (Mem *)((u8*)pRec + ROUND8(sizeof(UnpackedRecord)));
    +           for(i=0; i<nCol; i++){
    +@@ -66093,7 +72362,7 @@ static sqlite3_value *valueNew(sqlite3 *db, struct ValueNewStat4Ctx *p){
    +             pRec->aMem[i].db = db;
    +           }
    +         }else{
    +-          sqlite3DbFree(db, pRec);
    ++          sqlite3DbFreeNN(db, pRec);
    +           pRec = 0;
    +         }
    +       }
    +@@ -66145,7 +72414,6 @@ static int valueFromFunction(
    +   FuncDef *pFunc = 0;             /* Function definition */
    +   sqlite3_value *pVal = 0;        /* New value */
    +   int rc = SQLITE_OK;             /* Return code */
    +-  int nName;                      /* Size of function name in bytes */
    +   ExprList *pList = 0;            /* Function arguments */
    +   int i;                          /* Iterator variable */
    + 
    +@@ -66153,8 +72421,7 @@ static int valueFromFunction(
    +   assert( (p->flags & EP_TokenOnly)==0 );
    +   pList = p->x.pList;
    +   if( pList ) nVal = pList->nExpr;
    +-  nName = sqlite3Strlen30(p->u.zToken);
    +-  pFunc = sqlite3FindFunction(db, p->u.zToken, nName, nVal, enc, 0);
    ++  pFunc = sqlite3FindFunction(db, p->u.zToken, nVal, enc, 0);
    +   assert( pFunc );
    +   if( (pFunc->funcFlags & (SQLITE_FUNC_CONSTANT|SQLITE_FUNC_SLOCHNG))==0 
    +    || (pFunc->funcFlags & SQLITE_FUNC_NEEDCOLL)
    +@@ -66165,7 +72432,7 @@ static int valueFromFunction(
    +   if( pList ){
    +     apVal = (sqlite3_value**)sqlite3DbMallocZero(db, sizeof(apVal[0]) * nVal);
    +     if( apVal==0 ){
    +-      rc = SQLITE_NOMEM;
    ++      rc = SQLITE_NOMEM_BKPT;
    +       goto value_from_function_out;
    +     }
    +     for(i=0; i<nVal; i++){
    +@@ -66176,7 +72443,7 @@ static int valueFromFunction(
    + 
    +   pVal = valueNew(db, pCtx);
    +   if( pVal==0 ){
    +-    rc = SQLITE_NOMEM;
    ++    rc = SQLITE_NOMEM_BKPT;
    +     goto value_from_function_out;
    +   }
    + 
    +@@ -66184,7 +72451,7 @@ static int valueFromFunction(
    +   memset(&ctx, 0, sizeof(ctx));
    +   ctx.pOut = pVal;
    +   ctx.pFunc = pFunc;
    +-  pFunc->xFunc(&ctx, nVal, apVal);
    ++  pFunc->xSFunc(&ctx, nVal, apVal);
    +   if( ctx.isError ){
    +     rc = ctx.isError;
    +     sqlite3ErrorMsg(pCtx->pParse, "%s", sqlite3_value_text(pVal));
    +@@ -66207,7 +72474,7 @@ static int valueFromFunction(
    +     for(i=0; i<nVal; i++){
    +       sqlite3ValueFree(apVal[i]);
    +     }
    +-    sqlite3DbFree(db, apVal);
    ++    sqlite3DbFreeNN(db, apVal);
    +   }
    + 
    +   *ppVal = pVal;
    +@@ -66242,12 +72509,13 @@ static int valueFromExpr(
    +   const char *zNeg = "";
    +   int rc = SQLITE_OK;
    + 
    +-  if( !pExpr ){
    +-    *ppVal = 0;
    +-    return SQLITE_OK;
    +-  }
    +-  while( (op = pExpr->op)==TK_UPLUS ) pExpr = pExpr->pLeft;
    ++  assert( pExpr!=0 );
    ++  while( (op = pExpr->op)==TK_UPLUS || op==TK_SPAN ) pExpr = pExpr->pLeft;
    ++#if defined(SQLITE_ENABLE_STAT3_OR_STAT4)
    ++  if( op==TK_REGISTER ) op = pExpr->op2;
    ++#else
    +   if( NEVER(op==TK_REGISTER) ) op = pExpr->op2;
    ++#endif
    + 
    +   /* Compressed expressions only appear when parsing the DEFAULT clause
    +   ** on a table column definition, and hence only when pCtx==0.  This
    +@@ -66298,7 +72566,7 @@ static int valueFromExpr(
    +     }
    +   }else if( op==TK_UMINUS ) {
    +     /* This branch happens for multiple negative signs.  Ex: -(-5) */
    +-    if( SQLITE_OK==sqlite3ValueFromExpr(db,pExpr->pLeft,enc,affinity,&pVal) 
    ++    if( SQLITE_OK==valueFromExpr(db,pExpr->pLeft,enc,affinity,&pVal,pCtx) 
    +      && pVal!=0
    +     ){
    +       sqlite3VdbeMemNumerify(pVal);
    +@@ -66315,6 +72583,7 @@ static int valueFromExpr(
    +   }else if( op==TK_NULL ){
    +     pVal = valueNew(db, pCtx);
    +     if( pVal==0 ) goto no_mem;
    ++    sqlite3VdbeMemNumerify(pVal);
    +   }
    + #ifndef SQLITE_OMIT_BLOB_LITERAL
    +   else if( op==TK_BLOB ){
    +@@ -66341,7 +72610,10 @@ static int valueFromExpr(
    +   return rc;
    + 
    + no_mem:
    +-  db->mallocFailed = 1;
    ++#ifdef SQLITE_ENABLE_STAT3_OR_STAT4
    ++  if( pCtx==0 || pCtx->pParse->nErr==0 )
    ++#endif
    ++    sqlite3OomFault(db);
    +   sqlite3DbFree(db, zVal);
    +   assert( *ppVal==0 );
    + #ifdef SQLITE_ENABLE_STAT3_OR_STAT4
    +@@ -66349,7 +72621,7 @@ no_mem:
    + #else
    +   assert( pCtx==0 ); sqlite3ValueFree(pVal);
    + #endif
    +-  return SQLITE_NOMEM;
    ++  return SQLITE_NOMEM_BKPT;
    + }
    + 
    + /*
    +@@ -66369,7 +72641,7 @@ SQLITE_PRIVATE int sqlite3ValueFromExpr(
    +   u8 affinity,              /* Affinity to use */
    +   sqlite3_value **ppVal     /* Write the new value here */
    + ){
    +-  return valueFromExpr(db, pExpr, enc, affinity, ppVal, 0);
    ++  return pExpr ? valueFromExpr(db, pExpr, enc, affinity, ppVal, 0) : 0;
    + }
    + 
    + #ifdef SQLITE_ENABLE_STAT3_OR_STAT4
    +@@ -66387,21 +72659,20 @@ static void recordFunc(
    +   sqlite3_value **argv
    + ){
    +   const int file_format = 1;
    +-  int iSerial;                    /* Serial type */
    ++  u32 iSerial;                    /* Serial type */
    +   int nSerial;                    /* Bytes of space for iSerial as varint */
    +-  int nVal;                       /* Bytes of space required for argv[0] */
    ++  u32 nVal;                       /* Bytes of space required for argv[0] */
    +   int nRet;
    +   sqlite3 *db;
    +   u8 *aRet;
    + 
    +   UNUSED_PARAMETER( argc );
    +-  iSerial = sqlite3VdbeSerialType(argv[0], file_format);
    ++  iSerial = sqlite3VdbeSerialType(argv[0], file_format, &nVal);
    +   nSerial = sqlite3VarintLen(iSerial);
    +-  nVal = sqlite3VdbeSerialTypeLen(iSerial);
    +   db = sqlite3_context_db_handle(context);
    + 
    +   nRet = 1 + nSerial + nVal;
    +-  aRet = sqlite3DbMallocRaw(db, nRet);
    ++  aRet = sqlite3DbMallocRawNN(db, nRet);
    +   if( aRet==0 ){
    +     sqlite3_result_error_nomem(context);
    +   }else{
    +@@ -66409,7 +72680,7 @@ static void recordFunc(
    +     putVarint32(&aRet[1], iSerial);
    +     sqlite3VdbeSerialPut(&aRet[1+nSerial], argv[0], iSerial);
    +     sqlite3_result_blob(context, aRet, nRet, SQLITE_TRANSIENT);
    +-    sqlite3DbFree(db, aRet);
    ++    sqlite3DbFreeNN(db, aRet);
    +   }
    + }
    + 
    +@@ -66417,15 +72688,10 @@ static void recordFunc(
    + ** Register built-in functions used to help read ANALYZE data.
    + */
    + SQLITE_PRIVATE void sqlite3AnalyzeFunctions(void){
    +-  static SQLITE_WSD FuncDef aAnalyzeTableFuncs[] = {
    ++  static FuncDef aAnalyzeTableFuncs[] = {
    +     FUNCTION(sqlite_record,   1, 0, 0, recordFunc),
    +   };
    +-  int i;
    +-  FuncDefHash *pHash = &GLOBAL(FuncDefHash, sqlite3GlobalFunctions);
    +-  FuncDef *aFunc = (FuncDef*)&GLOBAL(FuncDef, aAnalyzeTableFuncs);
    +-  for(i=0; i<ArraySize(aAnalyzeTableFuncs); i++){
    +-    sqlite3FuncDefInsert(pHash, &aFunc[i]);
    +-  }
    ++  sqlite3InsertBuiltinFuncs(aAnalyzeTableFuncs, ArraySize(aAnalyzeTableFuncs));
    + }
    + 
    + /*
    +@@ -66460,14 +72726,13 @@ static int stat4ValueFromExpr(
    +   /* Skip over any TK_COLLATE nodes */
    +   pExpr = sqlite3ExprSkipCollate(pExpr);
    + 
    ++  assert( pExpr==0 || pExpr->op!=TK_REGISTER || pExpr->op2!=TK_VARIABLE );
    +   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)
    +-  ){
    ++  }else if( pExpr->op==TK_VARIABLE && (db->flags & SQLITE_EnableQPSG)==0 ){
    +     Vdbe *v;
    +     int iBindVar = pExpr->iColumn;
    +     sqlite3VdbeSetVarmask(pParse->pVdbe, iBindVar);
    +@@ -66475,9 +72740,7 @@ static int stat4ValueFromExpr(
    +       pVal = valueNew(db, pAlloc);
    +       if( pVal ){
    +         rc = sqlite3VdbeMemCopy((Mem*)pVal, &v->aVar[iBindVar-1]);
    +-        if( rc==SQLITE_OK ){
    +-          sqlite3ValueApplyAffinity(pVal, affinity, ENC(db));
    +-        }
    ++        sqlite3ValueApplyAffinity(pVal, affinity, ENC(db));
    +         pVal->db = pParse->db;
    +       }
    +     }
    +@@ -66495,9 +72758,9 @@ static int stat4ValueFromExpr(
    + ** structures intended to be compared against sample index keys stored 
    + ** in the sqlite_stat4 table.
    + **
    +-** A single call to this function attempts to populates field iVal (leftmost 
    +-** is 0 etc.) of the unpacked record with a value extracted from expression
    +-** pExpr. Extraction of values is possible if:
    ++** A single call to this function populates zero or more fields of the
    ++** record starting with field iVal (fields are numbered from left to
    ++** right starting with 0). A single field is populated if:
    + **
    + **  * (pExpr==0). In this case the value is assumed to be an SQL NULL,
    + **
    +@@ -66506,10 +72769,14 @@ static int stat4ValueFromExpr(
    + **  * The sqlite3ValueFromExpr() function is able to extract a value 
    + **    from the expression (i.e. the expression is a literal value).
    + **
    +-** If a value can be extracted, the affinity passed as the 5th argument
    +-** is applied to it before it is copied into the UnpackedRecord. Output
    +-** parameter *pbOk is set to true if a value is extracted, or false 
    +-** otherwise.
    ++** Or, if pExpr is a TK_VECTOR, one field is populated for each of the
    ++** vector components that match either of the two latter criteria listed
    ++** above.
    ++**
    ++** Before any value is appended to the record, the affinity of the 
    ++** corresponding column within index pIdx is applied to it. Before
    ++** this function returns, output parameter *pnExtract is set to the
    ++** number of values appended to the record.
    + **
    + ** When this function is called, *ppRec must either point to an object
    + ** allocated by an earlier call to this function, or must be NULL. If it
    +@@ -66525,22 +72792,33 @@ SQLITE_PRIVATE int sqlite3Stat4ProbeSetValue(
    +   Index *pIdx,                    /* Index being probed */
    +   UnpackedRecord **ppRec,         /* IN/OUT: Probe record */
    +   Expr *pExpr,                    /* The expression to extract a value from */
    +-  u8 affinity,                    /* Affinity to use */
    ++  int nElem,                      /* Maximum number of values to append */
    +   int iVal,                       /* Array element to populate */
    +-  int *pbOk                       /* OUT: True if value was extracted */
    ++  int *pnExtract                  /* OUT: Values appended to the record */
    + ){
    +-  int rc;
    +-  sqlite3_value *pVal = 0;
    +-  struct ValueNewStat4Ctx alloc;
    ++  int rc = SQLITE_OK;
    ++  int nExtract = 0;
    ++
    ++  if( pExpr==0 || pExpr->op!=TK_SELECT ){
    ++    int i;
    ++    struct ValueNewStat4Ctx alloc;
    + 
    +-  alloc.pParse = pParse;
    +-  alloc.pIdx = pIdx;
    +-  alloc.ppRec = ppRec;
    +-  alloc.iVal = iVal;
    ++    alloc.pParse = pParse;
    ++    alloc.pIdx = pIdx;
    ++    alloc.ppRec = ppRec;
    + 
    +-  rc = stat4ValueFromExpr(pParse, pExpr, affinity, &alloc, &pVal);
    +-  assert( pVal==0 || pVal->db==pParse->db );
    +-  *pbOk = (pVal!=0);
    ++    for(i=0; i<nElem; i++){
    ++      sqlite3_value *pVal = 0;
    ++      Expr *pElem = (pExpr ? sqlite3VectorFieldSubexpr(pExpr, i) : 0);
    ++      u8 aff = sqlite3IndexColumnAffinity(pParse->db, pIdx, iVal+i);
    ++      alloc.iVal = iVal+i;
    ++      rc = stat4ValueFromExpr(pParse, pElem, aff, &alloc, &pVal);
    ++      if( !pVal ) break;
    ++      nExtract++;
    ++    }
    ++  }
    ++
    ++  *pnExtract = nExtract;
    +   return rc;
    + }
    + 
    +@@ -66604,7 +72882,7 @@ SQLITE_PRIVATE int sqlite3Stat4Column(
    +   if( iField>nRec ) return SQLITE_CORRUPT_BKPT;
    +   if( pMem==0 ){
    +     pMem = *ppVal = sqlite3ValueNew(db);
    +-    if( pMem==0 ) return SQLITE_NOMEM;
    ++    if( pMem==0 ) return SQLITE_NOMEM_BKPT;
    +   }
    +   sqlite3VdbeSerialGet(&a[iField-szField], t, pMem);
    +   pMem->enc = ENC(db);
    +@@ -66619,14 +72897,14 @@ SQLITE_PRIVATE int sqlite3Stat4Column(
    + SQLITE_PRIVATE void sqlite3Stat4ProbeFree(UnpackedRecord *pRec){
    +   if( pRec ){
    +     int i;
    +-    int nCol = pRec->pKeyInfo->nField+pRec->pKeyInfo->nXField;
    ++    int nCol = pRec->pKeyInfo->nAllField;
    +     Mem *aMem = pRec->aMem;
    +     sqlite3 *db = aMem[0].db;
    +     for(i=0; i<nCol; i++){
    +       sqlite3VdbeMemRelease(&aMem[i]);
    +     }
    +     sqlite3KeyInfoUnref(pRec->pKeyInfo);
    +-    sqlite3DbFree(db, pRec);
    ++    sqlite3DbFreeNN(db, pRec);
    +   }
    + }
    + #endif /* ifdef SQLITE_ENABLE_STAT4 */
    +@@ -66650,7 +72928,7 @@ SQLITE_PRIVATE void sqlite3ValueSetStr(
    + SQLITE_PRIVATE void sqlite3ValueFree(sqlite3_value *v){
    +   if( !v ) return;
    +   sqlite3VdbeMemRelease((Mem *)v);
    +-  sqlite3DbFree(((Mem*)v)->db, v);
    ++  sqlite3DbFreeNN(((Mem*)v)->db, v);
    + }
    + 
    + /*
    +@@ -66703,8 +72981,9 @@ SQLITE_PRIVATE int sqlite3ValueBytes(sqlite3_value *pVal, u8 enc){
    + SQLITE_PRIVATE Vdbe *sqlite3VdbeCreate(Parse *pParse){
    +   sqlite3 *db = pParse->db;
    +   Vdbe *p;
    +-  p = sqlite3DbMallocZero(db, sizeof(Vdbe) );
    ++  p = sqlite3DbMallocRawNN(db, sizeof(Vdbe) );
    +   if( p==0 ) return 0;
    ++  memset(&p->aOp, 0, sizeof(Vdbe)-offsetof(Vdbe,aOp));
    +   p->db = db;
    +   if( db->pVdbe ){
    +     db->pVdbe->pPrev = p;
    +@@ -66714,9 +72993,12 @@ SQLITE_PRIVATE Vdbe *sqlite3VdbeCreate(Parse *pParse){
    +   db->pVdbe = p;
    +   p->magic = VDBE_MAGIC_INIT;
    +   p->pParse = pParse;
    ++  pParse->pVdbe = p;
    +   assert( pParse->aLabel==0 );
    +   assert( pParse->nLabel==0 );
    +   assert( pParse->nOpAlloc==0 );
    ++  assert( pParse->szOpAlloc==0 );
    ++  sqlite3VdbeAddOp2(p, OP_Init, 0, 1);
    +   return p;
    + }
    + 
    +@@ -66734,23 +73016,14 @@ SQLITE_PRIVATE void sqlite3VdbeError(Vdbe *p, const char *zFormat, ...){
    + /*
    + ** Remember the SQL string for a prepared statement.
    + */
    +-SQLITE_PRIVATE void sqlite3VdbeSetSql(Vdbe *p, const char *z, int n, int isPrepareV2){
    +-  assert( isPrepareV2==1 || isPrepareV2==0 );
    ++SQLITE_PRIVATE void sqlite3VdbeSetSql(Vdbe *p, const char *z, int n, u8 prepFlags){
    +   if( p==0 ) return;
    +-#if defined(SQLITE_OMIT_TRACE) && !defined(SQLITE_ENABLE_SQLLOG)
    +-  if( !isPrepareV2 ) return;
    +-#endif
    ++  p->prepFlags = prepFlags;
    ++  if( (prepFlags & SQLITE_PREPARE_SAVESQL)==0 ){
    ++    p->expmask = 0;
    ++  }
    +   assert( p->zSql==0 );
    +   p->zSql = sqlite3DbStrNDup(p->db, z, n);
    +-  p->isPrepareV2 = (u8)isPrepareV2;
    +-}
    +-
    +-/*
    +-** Return the SQL associated with a prepared statement
    +-*/
    +-SQLITE_API const char *SQLITE_STDCALL sqlite3_sql(sqlite3_stmt *pStmt){
    +-  Vdbe *p = (Vdbe *)pStmt;
    +-  return p ? p->zSql : 0;
    + }
    + 
    + /*
    +@@ -66759,6 +73032,7 @@ SQLITE_API const char *SQLITE_STDCALL sqlite3_sql(sqlite3_stmt *pStmt){
    + SQLITE_PRIVATE void sqlite3VdbeSwap(Vdbe *pA, Vdbe *pB){
    +   Vdbe tmp, *pTmp;
    +   char *zTmp;
    ++  assert( pA->db==pB->db );
    +   tmp = *pA;
    +   *pA = *pB;
    +   *pB = tmp;
    +@@ -66771,7 +73045,10 @@ SQLITE_PRIVATE void sqlite3VdbeSwap(Vdbe *pA, Vdbe *pB){
    +   zTmp = pA->zSql;
    +   pA->zSql = pB->zSql;
    +   pB->zSql = zTmp;
    +-  pB->isPrepareV2 = pA->isPrepareV2;
    ++  pB->expmask = pA->expmask;
    ++  pB->prepFlags = pA->prepFlags;
    ++  memcpy(pB->aCounter, pA->aCounter, sizeof(pB->aCounter));
    ++  pB->aCounter[SQLITE_STMTSTATUS_REPREPARE]++;
    + }
    + 
    + /*
    +@@ -66802,14 +73079,21 @@ static int growOpArray(Vdbe *v, int nOp){
    +   UNUSED_PARAMETER(nOp);
    + #endif
    + 
    ++  /* Ensure that the size of a VDBE does not grow too large */
    ++  if( nNew > p->db->aLimit[SQLITE_LIMIT_VDBE_OP] ){
    ++    sqlite3OomFault(p->db);
    ++    return SQLITE_NOMEM;
    ++  }
    ++
    +   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);
    ++    p->szOpAlloc = sqlite3DbMallocSize(p->db, pNew);
    ++    p->nOpAlloc = p->szOpAlloc/sizeof(Op);
    +     v->aOp = pNew;
    +   }
    +-  return (pNew ? SQLITE_OK : SQLITE_NOMEM);
    ++  return (pNew ? SQLITE_OK : SQLITE_NOMEM_BKPT);
    + }
    + 
    + #ifdef SQLITE_DEBUG
    +@@ -66839,17 +73123,21 @@ static void test_addop_breakpoint(void){
    + ** the sqlite3VdbeChangeP4() function to change the value of the P4
    + ** operand.
    + */
    ++static SQLITE_NOINLINE int growOp3(Vdbe *p, int op, int p1, int p2, int p3){
    ++  assert( p->pParse->nOpAlloc<=p->nOp );
    ++  if( growOpArray(p, 1) ) return 1;
    ++  assert( p->pParse->nOpAlloc>p->nOp );
    ++  return sqlite3VdbeAddOp3(p, op, p1, p2, p3);
    ++}
    + SQLITE_PRIVATE int sqlite3VdbeAddOp3(Vdbe *p, int op, int p1, int p2, int p3){
    +   int i;
    +   VdbeOp *pOp;
    + 
    +   i = p->nOp;
    +   assert( p->magic==VDBE_MAGIC_INIT );
    +-  assert( op>0 && op<0xff );
    ++  assert( op>=0 && op<0xff );
    +   if( p->pParse->nOpAlloc<=i ){
    +-    if( growOpArray(p, 1) ){
    +-      return 1;
    +-    }
    ++    return growOp3(p, op, p1, p2, p3);
    +   }
    +   p->nOp++;
    +   pOp = &p->aOp[i];
    +@@ -66867,9 +73155,8 @@ SQLITE_PRIVATE int sqlite3VdbeAddOp3(Vdbe *p, int op, int p1, int p2, int p3){
    +   if( p->db->flags & SQLITE_VdbeAddopTrace ){
    +     int jj, kk;
    +     Parse *pParse = p->pParse;
    +-    for(jj=kk=0; jj<SQLITE_N_COLCACHE; jj++){
    ++    for(jj=kk=0; jj<pParse->nColCache; jj++){
    +       struct yColCache *x = pParse->aColCache + jj;
    +-      if( x->iLevel>pParse->iCacheLevel || x->iReg==0 ) continue;
    +       printf(" r[%d]={%d:%d}", x->iReg, x->iTable, x->iColumn);
    +       kk++;
    +     }
    +@@ -66917,6 +73204,9 @@ SQLITE_PRIVATE int sqlite3VdbeLoadString(Vdbe *p, int iDest, const char *zStr){
    + ** "s" character in zTypes[], the register is a string if the argument is
    + ** not NULL, or OP_Null if the value is a null pointer.  For each "i" character
    + ** in zTypes[], the register is initialized to an integer.
    ++**
    ++** If the input string does not end with "X" then an OP_ResultRow instruction
    ++** is generated for the values inserted.
    + */
    + SQLITE_PRIVATE void sqlite3VdbeMultiLoad(Vdbe *p, int iDest, const char *zTypes, ...){
    +   va_list ap;
    +@@ -66926,13 +73216,15 @@ SQLITE_PRIVATE void sqlite3VdbeMultiLoad(Vdbe *p, int iDest, const char *zTypes,
    +   for(i=0; (c = zTypes[i])!=0; i++){
    +     if( c=='s' ){
    +       const char *z = va_arg(ap, const char*);
    +-      int addr = sqlite3VdbeAddOp2(p, z==0 ? OP_Null : OP_String8, 0, iDest++);
    +-      if( z ) sqlite3VdbeChangeP4(p, addr, z, 0);
    ++      sqlite3VdbeAddOp4(p, z==0 ? OP_Null : OP_String8, 0, iDest+i, 0, z, 0);
    ++    }else if( c=='i' ){
    ++      sqlite3VdbeAddOp2(p, OP_Integer, va_arg(ap, int), iDest+i);
    +     }else{
    +-      assert( c=='i' );
    +-      sqlite3VdbeAddOp2(p, OP_Integer, va_arg(ap, int), iDest++);
    ++      goto skip_op_resultrow;
    +     }
    +   }
    ++  sqlite3VdbeAddOp2(p, OP_ResultRow, iDest, i);
    ++skip_op_resultrow:
    +   va_end(ap);
    + }
    + 
    +@@ -66966,7 +73258,7 @@ SQLITE_PRIVATE int sqlite3VdbeAddOp4Dup8(
    +   const u8 *zP4,      /* The P4 operand */
    +   int p4type          /* P4 operand type */
    + ){
    +-  char *p4copy = sqlite3DbMallocRaw(sqlite3VdbeDb(p), 8);
    ++  char *p4copy = sqlite3DbMallocRawNN(sqlite3VdbeDb(p), 8);
    +   if( p4copy ) memcpy(p4copy, zP4, 8);
    +   return sqlite3VdbeAddOp4(p, op, p1, p2, p3, p4copy, p4type);
    + }
    +@@ -66981,8 +73273,7 @@ SQLITE_PRIVATE int sqlite3VdbeAddOp4Dup8(
    + */
    + SQLITE_PRIVATE void sqlite3VdbeAddParseSchemaOp(Vdbe *p, int iDb, char *zWhere){
    +   int j;
    +-  int addr = sqlite3VdbeAddOp3(p, OP_ParseSchema, iDb, 0, 0);
    +-  sqlite3VdbeChangeP4(p, addr, zWhere, P4_DYNAMIC);
    ++  sqlite3VdbeAddOp4(p, OP_ParseSchema, iDb, 0, 0, zWhere, P4_DYNAMIC);
    +   for(j=0; j<p->db->nDb; j++) sqlite3VdbeUsesBtree(p, j);
    + }
    + 
    +@@ -66998,10 +73289,29 @@ SQLITE_PRIVATE int sqlite3VdbeAddOp4Int(
    +   int p4              /* The P4 operand as an integer */
    + ){
    +   int addr = sqlite3VdbeAddOp3(p, op, p1, p2, p3);
    +-  sqlite3VdbeChangeP4(p, addr, SQLITE_INT_TO_PTR(p4), P4_INT32);
    ++  if( p->db->mallocFailed==0 ){
    ++    VdbeOp *pOp = &p->aOp[addr];
    ++    pOp->p4type = P4_INT32;
    ++    pOp->p4.i = p4;
    ++  }
    +   return addr;
    + }
    + 
    ++/* Insert the end of a co-routine
    ++*/
    ++SQLITE_PRIVATE void sqlite3VdbeEndCoroutine(Vdbe *v, int regYield){
    ++  sqlite3VdbeAddOp1(v, OP_EndCoroutine, regYield);
    ++
    ++  /* Clear the temporary register cache, thereby ensuring that each
    ++  ** co-routine has its own independent set of registers, because co-routines
    ++  ** might expect their registers to be preserved across an OP_Yield, and
    ++  ** that could cause problems if two or more co-routines are using the same
    ++  ** temporary register.
    ++  */
    ++  v->pParse->nTempReg = 0;
    ++  v->pParse->nRangeReg = 0;
    ++}
    ++
    + /*
    + ** Create a new symbolic label for an instruction that has yet to be
    + ** coded.  The symbolic label is really just a negative number.  The
    +@@ -67027,7 +73337,7 @@ SQLITE_PRIVATE int sqlite3VdbeMakeLabel(Vdbe *v){
    +   if( p->aLabel ){
    +     p->aLabel[i] = -1;
    +   }
    +-  return -1-i;
    ++  return ADDR(i);
    + }
    + 
    + /*
    +@@ -67037,14 +73347,13 @@ SQLITE_PRIVATE int sqlite3VdbeMakeLabel(Vdbe *v){
    + */
    + SQLITE_PRIVATE void sqlite3VdbeResolveLabel(Vdbe *v, int x){
    +   Parse *p = v->pParse;
    +-  int j = -1-x;
    ++  int j = ADDR(x);
    +   assert( v->magic==VDBE_MAGIC_INIT );
    +   assert( j<p->nLabel );
    +   assert( j>=0 );
    +   if( p->aLabel ){
    +     p->aLabel[j] = v->nOp;
    +   }
    +-  p->iFixedOp = v->nOp - 1;
    + }
    + 
    + /*
    +@@ -67054,6 +73363,13 @@ SQLITE_PRIVATE void sqlite3VdbeRunOnlyOnce(Vdbe *p){
    +   p->runOnlyOnce = 1;
    + }
    + 
    ++/*
    ++** Mark the VDBE as one that can only be run multiple times.
    ++*/
    ++SQLITE_PRIVATE void sqlite3VdbeReusable(Vdbe *p){
    ++  p->runOnlyOnce = 0;
    ++}
    ++
    + #ifdef SQLITE_DEBUG /* sqlite3AssertMayAbort() logic */
    + 
    + /*
    +@@ -67136,7 +73452,8 @@ static Op *opIterNext(VdbeOpIter *p){
    + **   *  OP_VUpdate
    + **   *  OP_VRename
    + **   *  OP_FkCounter with P2==0 (immediate foreign key constraint)
    +-**   *  OP_CreateTable and OP_InitCoroutine (for CREATE TABLE AS SELECT ...)
    ++**   *  OP_CreateBtree/BTREE_INTKEY and OP_InitCoroutine 
    ++**      (for CREATE TABLE AS SELECT ...)
    + **
    + ** Then check that the value of Parse.mayAbort is true if an
    + ** ABORT may be thrown, or false otherwise. Return true if it does
    +@@ -67164,7 +73481,7 @@ SQLITE_PRIVATE int sqlite3VdbeAssertMayAbort(Vdbe *v, int mayAbort){
    +       hasAbort = 1;
    +       break;
    +     }
    +-    if( opcode==OP_CreateTable ) hasCreateTable = 1;
    ++    if( opcode==OP_CreateBtree && pOp->p3==BTREE_INTKEY ) hasCreateTable = 1;
    +     if( opcode==OP_InitCoroutine ) hasInitCoroutine = 1;
    + #ifndef SQLITE_OMIT_FOREIGN_KEY
    +     if( opcode==OP_FkCounter && pOp->p1==0 && pOp->p2==1 ){
    +@@ -67200,73 +73517,103 @@ SQLITE_PRIVATE int sqlite3VdbeAssertMayAbort(Vdbe *v, int mayAbort){
    + ** (4) Initialize the p4.xAdvance pointer on opcodes that use it.
    + **
    + ** (5) Reclaim the memory allocated for storing labels.
    ++**
    ++** This routine will only function correctly if the mkopcodeh.tcl generator
    ++** script numbers the opcodes correctly.  Changes to this routine must be
    ++** coordinated with changes to mkopcodeh.tcl.
    + */
    + static void resolveP2Values(Vdbe *p, int *pMaxFuncArgs){
    +-  int i;
    +   int nMaxArgs = *pMaxFuncArgs;
    +   Op *pOp;
    +   Parse *pParse = p->pParse;
    +   int *aLabel = pParse->aLabel;
    +   p->readOnly = 1;
    +   p->bIsReader = 0;
    +-  for(pOp=p->aOp, i=p->nOp-1; i>=0; i--, pOp++){
    +-    u8 opcode = pOp->opcode;
    +-
    +-    /* NOTE: Be sure to update mkopcodeh.awk when adding or removing
    +-    ** cases from this switch! */
    +-    switch( opcode ){
    +-      case OP_Transaction: {
    +-        if( pOp->p2!=0 ) p->readOnly = 0;
    +-        /* fall thru */
    +-      }
    +-      case OP_AutoCommit:
    +-      case OP_Savepoint: {
    +-        p->bIsReader = 1;
    +-        break;
    +-      }
    ++  pOp = &p->aOp[p->nOp-1];
    ++  while(1){
    ++
    ++    /* Only JUMP opcodes and the short list of special opcodes in the switch
    ++    ** below need to be considered.  The mkopcodeh.tcl generator script groups
    ++    ** all these opcodes together near the front of the opcode list.  Skip
    ++    ** any opcode that does not need processing by virtual of the fact that
    ++    ** it is larger than SQLITE_MX_JUMP_OPCODE, as a performance optimization.
    ++    */
    ++    if( pOp->opcode<=SQLITE_MX_JUMP_OPCODE ){
    ++      /* NOTE: Be sure to update mkopcodeh.tcl when adding or removing
    ++      ** cases from this switch! */
    ++      switch( pOp->opcode ){
    ++        case OP_Transaction: {
    ++          if( pOp->p2!=0 ) p->readOnly = 0;
    ++          /* fall thru */
    ++        }
    ++        case OP_AutoCommit:
    ++        case OP_Savepoint: {
    ++          p->bIsReader = 1;
    ++          break;
    ++        }
    + #ifndef SQLITE_OMIT_WAL
    +-      case OP_Checkpoint:
    ++        case OP_Checkpoint:
    + #endif
    +-      case OP_Vacuum:
    +-      case OP_JournalMode: {
    +-        p->readOnly = 0;
    +-        p->bIsReader = 1;
    +-        break;
    +-      }
    ++        case OP_Vacuum:
    ++        case OP_JournalMode: {
    ++          p->readOnly = 0;
    ++          p->bIsReader = 1;
    ++          break;
    ++        }
    ++        case OP_Next:
    ++        case OP_NextIfOpen:
    ++        case OP_SorterNext: {
    ++          pOp->p4.xAdvance = sqlite3BtreeNext;
    ++          pOp->p4type = P4_ADVANCE;
    ++          /* The code generator never codes any of these opcodes as a jump
    ++          ** to a label.  They are always coded as a jump backwards to a 
    ++          ** known address */
    ++          assert( pOp->p2>=0 );
    ++          break;
    ++        }
    ++        case OP_Prev:
    ++        case OP_PrevIfOpen: {
    ++          pOp->p4.xAdvance = sqlite3BtreePrevious;
    ++          pOp->p4type = P4_ADVANCE;
    ++          /* The code generator never codes any of these opcodes as a jump
    ++          ** to a label.  They are always coded as a jump backwards to a 
    ++          ** known address */
    ++          assert( pOp->p2>=0 );
    ++          break;
    ++        }
    + #ifndef SQLITE_OMIT_VIRTUALTABLE
    +-      case OP_VUpdate: {
    +-        if( pOp->p2>nMaxArgs ) nMaxArgs = pOp->p2;
    +-        break;
    +-      }
    +-      case OP_VFilter: {
    +-        int n;
    +-        assert( p->nOp - i >= 3 );
    +-        assert( pOp[-1].opcode==OP_Integer );
    +-        n = pOp[-1].p1;
    +-        if( n>nMaxArgs ) nMaxArgs = n;
    +-        break;
    +-      }
    +-#endif
    +-      case OP_Next:
    +-      case OP_NextIfOpen:
    +-      case OP_SorterNext: {
    +-        pOp->p4.xAdvance = sqlite3BtreeNext;
    +-        pOp->p4type = P4_ADVANCE;
    +-        break;
    +-      }
    +-      case OP_Prev:
    +-      case OP_PrevIfOpen: {
    +-        pOp->p4.xAdvance = sqlite3BtreePrevious;
    +-        pOp->p4type = P4_ADVANCE;
    +-        break;
    ++        case OP_VUpdate: {
    ++          if( pOp->p2>nMaxArgs ) nMaxArgs = pOp->p2;
    ++          break;
    ++        }
    ++        case OP_VFilter: {
    ++          int n;
    ++          assert( (pOp - p->aOp) >= 3 );
    ++          assert( pOp[-1].opcode==OP_Integer );
    ++          n = pOp[-1].p1;
    ++          if( n>nMaxArgs ) nMaxArgs = n;
    ++          /* Fall through into the default case */
    ++        }
    ++#endif
    ++        default: {
    ++          if( pOp->p2<0 ){
    ++            /* The mkopcodeh.tcl script has so arranged things that the only
    ++            ** non-jump opcodes less than SQLITE_MX_JUMP_CODE are guaranteed to
    ++            ** have non-negative values for P2. */
    ++            assert( (sqlite3OpcodeProperty[pOp->opcode] & OPFLG_JUMP)!=0 );
    ++            assert( ADDR(pOp->p2)<pParse->nLabel );
    ++            pOp->p2 = aLabel[ADDR(pOp->p2)];
    ++          }
    ++          break;
    ++        }
    +       }
    ++      /* The mkopcodeh.tcl script has so arranged things that the only
    ++      ** non-jump opcodes less than SQLITE_MX_JUMP_CODE are guaranteed to
    ++      ** have non-negative values for P2. */
    ++      assert( (sqlite3OpcodeProperty[pOp->opcode]&OPFLG_JUMP)==0 || pOp->p2>=0);
    +     }
    +-
    +-    pOp->opflags = sqlite3OpcodeProperty[opcode];
    +-    if( (pOp->opflags & OPFLG_JUMP)!=0 && pOp->p2<0 ){
    +-      assert( -1-pOp->p2<pParse->nLabel );
    +-      pOp->p2 = aLabel[-1-pOp->p2];
    +-    }
    ++    if( pOp==p->aOp ) break;
    ++    pOp--;
    +   }
    +   sqlite3DbFree(p->db, pParse->aLabel);
    +   pParse->aLabel = 0;
    +@@ -67283,6 +73630,36 @@ SQLITE_PRIVATE int sqlite3VdbeCurrentAddr(Vdbe *p){
    +   return p->nOp;
    + }
    + 
    ++/*
    ++** Verify that at least N opcode slots are available in p without
    ++** having to malloc for more space (except when compiled using
    ++** SQLITE_TEST_REALLOC_STRESS).  This interface is used during testing
    ++** to verify that certain calls to sqlite3VdbeAddOpList() can never
    ++** fail due to a OOM fault and hence that the return value from
    ++** sqlite3VdbeAddOpList() will always be non-NULL.
    ++*/
    ++#if defined(SQLITE_DEBUG) && !defined(SQLITE_TEST_REALLOC_STRESS)
    ++SQLITE_PRIVATE void sqlite3VdbeVerifyNoMallocRequired(Vdbe *p, int N){
    ++  assert( p->nOp + N <= p->pParse->nOpAlloc );
    ++}
    ++#endif
    ++
    ++/*
    ++** Verify that the VM passed as the only argument does not contain
    ++** an OP_ResultRow opcode. Fail an assert() if it does. This is used
    ++** by code in pragma.c to ensure that the implementation of certain
    ++** pragmas comports with the flags specified in the mkpragmatab.tcl
    ++** script.
    ++*/
    ++#if defined(SQLITE_DEBUG) && !defined(SQLITE_TEST_REALLOC_STRESS)
    ++SQLITE_PRIVATE void sqlite3VdbeVerifyNoResultRow(Vdbe *p){
    ++  int i;
    ++  for(i=0; i<p->nOp; i++){
    ++    assert( p->aOp[i].opcode!=OP_ResultRow );
    ++  }
    ++}
    ++#endif
    ++
    + /*
    + ** This function returns a pointer to the array of opcodes associated with
    + ** the Vdbe passed as the first argument. It is the callers responsibility
    +@@ -67308,28 +73685,33 @@ SQLITE_PRIVATE VdbeOp *sqlite3VdbeTakeOpArray(Vdbe *p, int *pnOp, int *pnMaxArg)
    + }
    + 
    + /*
    +-** Add a whole list of operations to the operation stack.  Return the
    +-** address of the first operation added.
    ++** Add a whole list of operations to the operation stack.  Return a
    ++** pointer to the first operation inserted.
    ++**
    ++** Non-zero P2 arguments to jump instructions are automatically adjusted
    ++** so that the jump target is relative to the first operation inserted.
    + */
    +-SQLITE_PRIVATE int sqlite3VdbeAddOpList(Vdbe *p, int nOp, VdbeOpList const *aOp, int iLineno){
    +-  int addr, i;
    +-  VdbeOp *pOut;
    ++SQLITE_PRIVATE VdbeOp *sqlite3VdbeAddOpList(
    ++  Vdbe *p,                     /* Add opcodes to the prepared statement */
    ++  int nOp,                     /* Number of opcodes to add */
    ++  VdbeOpList const *aOp,       /* The opcodes to be added */
    ++  int iLineno                  /* Source-file line number of first opcode */
    ++){
    ++  int i;
    ++  VdbeOp *pOut, *pFirst;
    +   assert( nOp>0 );
    +   assert( p->magic==VDBE_MAGIC_INIT );
    +   if( p->nOp + nOp > p->pParse->nOpAlloc && growOpArray(p, nOp) ){
    +     return 0;
    +   }
    +-  addr = p->nOp;
    +-  pOut = &p->aOp[addr];
    ++  pFirst = pOut = &p->aOp[p->nOp];
    +   for(i=0; i<nOp; i++, aOp++, pOut++){
    +-    int p2 = aOp->p2;
    +     pOut->opcode = aOp->opcode;
    +     pOut->p1 = aOp->p1;
    +-    if( p2<0 ){
    +-      assert( sqlite3OpcodeProperty[pOut->opcode] & OPFLG_JUMP );
    +-      pOut->p2 = addr + ADDR(p2);
    +-    }else{
    +-      pOut->p2 = p2;
    ++    pOut->p2 = aOp->p2;
    ++    assert( aOp->p2>=0 );
    ++    if( (sqlite3OpcodeProperty[aOp->opcode] & OPFLG_JUMP)!=0 && aOp->p2>0 ){
    ++      pOut->p2 += p->nOp;
    +     }
    +     pOut->p3 = aOp->p3;
    +     pOut->p4type = P4_NOTUSED;
    +@@ -67345,12 +73727,12 @@ SQLITE_PRIVATE int sqlite3VdbeAddOpList(Vdbe *p, int nOp, VdbeOpList const *aOp,
    + #endif
    + #ifdef SQLITE_DEBUG
    +     if( p->db->flags & SQLITE_VdbeAddopTrace ){
    +-      sqlite3VdbePrintOp(0, i+addr, &p->aOp[i+addr]);
    ++      sqlite3VdbePrintOp(0, i+p->nOp, &p->aOp[i+p->nOp]);
    +     }
    + #endif
    +   }
    +   p->nOp += nOp;
    +-  return addr;
    ++  return pFirst;
    + }
    + 
    + #if defined(SQLITE_ENABLE_STMT_SCANSTATUS)
    +@@ -67397,8 +73779,9 @@ SQLITE_PRIVATE void sqlite3VdbeChangeP2(Vdbe *p, u32 addr, int val){
    + SQLITE_PRIVATE void sqlite3VdbeChangeP3(Vdbe *p, u32 addr, int val){
    +   sqlite3VdbeGetOp(p,addr)->p3 = val;
    + }
    +-SQLITE_PRIVATE void sqlite3VdbeChangeP5(Vdbe *p, u8 p5){
    +-  sqlite3VdbeGetOp(p,-1)->p5 = p5;
    ++SQLITE_PRIVATE void sqlite3VdbeChangeP5(Vdbe *p, u16 p5){
    ++  assert( p->nOp>0 || p->db->mallocFailed );
    ++  if( p->nOp>0 ) p->aOp[p->nOp-1].p5 = p5;
    + }
    + 
    + /*
    +@@ -67406,7 +73789,6 @@ SQLITE_PRIVATE void sqlite3VdbeChangeP5(Vdbe *p, u8 p5){
    + ** the address of the next instruction to be coded.
    + */
    + SQLITE_PRIVATE void sqlite3VdbeJumpHere(Vdbe *p, int addr){
    +-  p->pParse->iFixedOp = p->nOp - 1;
    +   sqlite3VdbeChangeP2(p, addr, p->nOp);
    + }
    + 
    +@@ -67416,8 +73798,8 @@ SQLITE_PRIVATE void sqlite3VdbeJumpHere(Vdbe *p, int addr){
    + ** the FuncDef is not ephermal, then do nothing.
    + */
    + static void freeEphemeralFunction(sqlite3 *db, FuncDef *pDef){
    +-  if( ALWAYS(pDef) && (pDef->funcFlags & SQLITE_FUNC_EPHEM)!=0 ){
    +-    sqlite3DbFree(db, pDef);
    ++  if( (pDef->funcFlags & SQLITE_FUNC_EPHEM)!=0 ){
    ++    sqlite3DbFreeNN(db, pDef);
    +   }
    + }
    + 
    +@@ -67426,47 +73808,54 @@ static void vdbeFreeOpArray(sqlite3 *, Op *, int);
    + /*
    + ** Delete a P4 value if necessary.
    + */
    ++static SQLITE_NOINLINE void freeP4Mem(sqlite3 *db, Mem *p){
    ++  if( p->szMalloc ) sqlite3DbFree(db, p->zMalloc);
    ++  sqlite3DbFreeNN(db, p);
    ++}
    ++static SQLITE_NOINLINE void freeP4FuncCtx(sqlite3 *db, sqlite3_context *p){
    ++  freeEphemeralFunction(db, p->pFunc);
    ++ sqlite3DbFreeNN(db, p);
    ++}
    + static void freeP4(sqlite3 *db, int p4type, void *p4){
    +-  if( p4 ){
    +-    assert( db );
    +-    switch( p4type ){
    +-      case P4_FUNCCTX: {
    +-        freeEphemeralFunction(db, ((sqlite3_context*)p4)->pFunc);
    +-        /* Fall through into the next case */
    +-      }
    +-      case P4_REAL:
    +-      case P4_INT64:
    +-      case P4_DYNAMIC:
    +-      case P4_INTARRAY: {
    +-        sqlite3DbFree(db, p4);
    +-        break;
    +-      }
    +-      case P4_KEYINFO: {
    +-        if( db->pnBytesFreed==0 ) sqlite3KeyInfoUnref((KeyInfo*)p4);
    +-        break;
    +-      }
    +-      case P4_MPRINTF: {
    +-        if( db->pnBytesFreed==0 ) sqlite3_free(p4);
    +-        break;
    +-      }
    +-      case P4_FUNCDEF: {
    +-        freeEphemeralFunction(db, (FuncDef*)p4);
    +-        break;
    +-      }
    +-      case P4_MEM: {
    +-        if( db->pnBytesFreed==0 ){
    +-          sqlite3ValueFree((sqlite3_value*)p4);
    +-        }else{
    +-          Mem *p = (Mem*)p4;
    +-          if( p->szMalloc ) sqlite3DbFree(db, p->zMalloc);
    +-          sqlite3DbFree(db, p);
    +-        }
    +-        break;
    +-      }
    +-      case P4_VTAB : {
    +-        if( db->pnBytesFreed==0 ) sqlite3VtabUnlock((VTable *)p4);
    +-        break;
    ++  assert( db );
    ++  switch( p4type ){
    ++    case P4_FUNCCTX: {
    ++      freeP4FuncCtx(db, (sqlite3_context*)p4);
    ++      break;
    ++    }
    ++    case P4_REAL:
    ++    case P4_INT64:
    ++    case P4_DYNAMIC:
    ++    case P4_DYNBLOB:
    ++    case P4_INTARRAY: {
    ++      sqlite3DbFree(db, p4);
    ++      break;
    ++    }
    ++    case P4_KEYINFO: {
    ++      if( db->pnBytesFreed==0 ) sqlite3KeyInfoUnref((KeyInfo*)p4);
    ++      break;
    ++    }
    ++#ifdef SQLITE_ENABLE_CURSOR_HINTS
    ++    case P4_EXPR: {
    ++      sqlite3ExprDelete(db, (Expr*)p4);
    ++      break;
    ++    }
    ++#endif
    ++    case P4_FUNCDEF: {
    ++      freeEphemeralFunction(db, (FuncDef*)p4);
    ++      break;
    ++    }
    ++    case P4_MEM: {
    ++      if( db->pnBytesFreed==0 ){
    ++        sqlite3ValueFree((sqlite3_value*)p4);
    ++      }else{
    ++        freeP4Mem(db, (Mem*)p4);
    +       }
    ++      break;
    ++    }
    ++    case P4_VTAB : {
    ++      if( db->pnBytesFreed==0 ) sqlite3VtabUnlock((VTable *)p4);
    ++      break;
    +     }
    +   }
    + }
    +@@ -67479,14 +73868,14 @@ static void freeP4(sqlite3 *db, int p4type, void *p4){
    + static void vdbeFreeOpArray(sqlite3 *db, Op *aOp, int nOp){
    +   if( aOp ){
    +     Op *pOp;
    +-    for(pOp=aOp; pOp<&aOp[nOp]; pOp++){
    +-      freeP4(db, pOp->p4type, pOp->p4.p);
    ++    for(pOp=&aOp[nOp-1]; pOp>=aOp; pOp--){
    ++      if( pOp->p4type <= P4_FREE_IF_LE ) freeP4(db, pOp->p4type, pOp->p4.p);
    + #ifdef SQLITE_ENABLE_EXPLAIN_COMMENTS
    +       sqlite3DbFree(db, pOp->zComment);
    + #endif     
    +     }
    ++    sqlite3DbFreeNN(db, aOp);
    +   }
    +-  sqlite3DbFree(db, aOp);
    + }
    + 
    + /*
    +@@ -67502,15 +73891,16 @@ 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( addr<p->nOp ){
    +-    VdbeOp *pOp = &p->aOp[addr];
    +-    sqlite3 *db = p->db;
    +-    freeP4(db, pOp->p4type, pOp->p4.p);
    +-    memset(pOp, 0, sizeof(pOp[0]));
    +-    pOp->opcode = OP_Noop;
    +-    if( addr==p->nOp-1 ) p->nOp--;
    +-  }
    ++SQLITE_PRIVATE int sqlite3VdbeChangeToNoop(Vdbe *p, int addr){
    ++  VdbeOp *pOp;
    ++  if( p->db->mallocFailed ) return 0;
    ++  assert( addr>=0 && addr<p->nOp );
    ++  pOp = &p->aOp[addr];
    ++  freeP4(p->db, pOp->p4type, pOp->p4.p);
    ++  pOp->p4type = P4_NOTUSED;
    ++  pOp->p4.z = 0;
    ++  pOp->opcode = OP_Noop;
    ++  return 1;
    + }
    + 
    + /*
    +@@ -67518,9 +73908,8 @@ SQLITE_PRIVATE void sqlite3VdbeChangeToNoop(Vdbe *p, int addr){
    + ** then remove it.  Return true if and only if an opcode was removed.
    + */
    + SQLITE_PRIVATE int sqlite3VdbeDeletePriorOpcode(Vdbe *p, u8 op){
    +-  if( (p->nOp-1)>(p->pParse->iFixedOp) && p->aOp[p->nOp-1].opcode==op ){
    +-    sqlite3VdbeChangeToNoop(p, p->nOp-1);
    +-    return 1;
    ++  if( p->nOp>0 && p->aOp[p->nOp-1].opcode==op ){
    ++    return sqlite3VdbeChangeToNoop(p, p->nOp-1);
    +   }else{
    +     return 0;
    +   }
    +@@ -67543,16 +73932,34 @@ SQLITE_PRIVATE int sqlite3VdbeDeletePriorOpcode(Vdbe *p, u8 op){
    + **
    + ** If addr<0 then change P4 on the most recently inserted instruction.
    + */
    ++static void SQLITE_NOINLINE vdbeChangeP4Full(
    ++  Vdbe *p,
    ++  Op *pOp,
    ++  const char *zP4,
    ++  int n
    ++){
    ++  if( pOp->p4type ){
    ++    freeP4(p->db, pOp->p4type, pOp->p4.p);
    ++    pOp->p4type = 0;
    ++    pOp->p4.p = 0;
    ++  }
    ++  if( n<0 ){
    ++    sqlite3VdbeChangeP4(p, (int)(pOp - p->aOp), zP4, n);
    ++  }else{
    ++    if( n==0 ) n = sqlite3Strlen30(zP4);
    ++    pOp->p4.z = sqlite3DbStrNDup(p->db, zP4, n);
    ++    pOp->p4type = P4_DYNAMIC;
    ++  }
    ++}
    + SQLITE_PRIVATE void sqlite3VdbeChangeP4(Vdbe *p, int addr, const char *zP4, int n){
    +   Op *pOp;
    +   sqlite3 *db;
    +   assert( p!=0 );
    +   db = p->db;
    +   assert( p->magic==VDBE_MAGIC_INIT );
    +-  if( p->aOp==0 || db->mallocFailed ){
    +-    if( n!=P4_VTAB ){
    +-      freeP4(db, n, (void*)*(char**)&zP4);
    +-    }
    ++  assert( p->aOp!=0 || db->mallocFailed );
    ++  if( db->mallocFailed ){
    ++    if( n!=P4_VTAB ) freeP4(db, n, (void*)*(char**)&zP4);
    +     return;
    +   }
    +   assert( p->nOp>0 );
    +@@ -67561,34 +73968,45 @@ 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
    +-       || pOp->p4type==P4_KEYINFO );
    +-  freeP4(db, pOp->p4type, pOp->p4.p);
    +-  pOp->p4.p = 0;
    ++  if( n>=0 || pOp->p4type ){
    ++    vdbeChangeP4Full(p, pOp, zP4, n);
    ++    return;
    ++  }
    +   if( n==P4_INT32 ){
    +     /* Note: this cast is safe, because the origin data point was an int
    +     ** that was cast to a (const char *). */
    +     pOp->p4.i = SQLITE_PTR_TO_INT(zP4);
    +     pOp->p4type = P4_INT32;
    +-  }else if( zP4==0 ){
    +-    pOp->p4.p = 0;
    +-    pOp->p4type = P4_NOTUSED;
    +-  }else if( n==P4_KEYINFO ){
    +-    pOp->p4.p = (void*)zP4;
    +-    pOp->p4type = P4_KEYINFO;
    +-  }else if( n==P4_VTAB ){
    +-    pOp->p4.p = (void*)zP4;
    +-    pOp->p4type = P4_VTAB;
    +-    sqlite3VtabLock((VTable *)zP4);
    +-    assert( ((VTable *)zP4)->db==p->db );
    +-  }else if( n<0 ){
    ++  }else if( zP4!=0 ){
    ++    assert( n<0 );
    +     pOp->p4.p = (void*)zP4;
    +     pOp->p4type = (signed char)n;
    ++    if( n==P4_VTAB ) sqlite3VtabLock((VTable*)zP4);
    ++  }
    ++}
    ++
    ++/*
    ++** Change the P4 operand of the most recently coded instruction 
    ++** to the value defined by the arguments.  This is a high-speed
    ++** version of sqlite3VdbeChangeP4().
    ++**
    ++** The P4 operand must not have been previously defined.  And the new
    ++** P4 must not be P4_INT32.  Use sqlite3VdbeChangeP4() in either of
    ++** those cases.
    ++*/
    ++SQLITE_PRIVATE void sqlite3VdbeAppendP4(Vdbe *p, void *pP4, int n){
    ++  VdbeOp *pOp;
    ++  assert( n!=P4_INT32 && n!=P4_VTAB );
    ++  assert( n<=0 );
    ++  if( p->db->mallocFailed ){
    ++    freeP4(p->db, n, pP4);
    +   }else{
    +-    if( n==0 ) n = sqlite3Strlen30(zP4);
    +-    pOp->p4.z = sqlite3DbStrNDup(p->db, zP4, n);
    +-    pOp->p4type = P4_DYNAMIC;
    ++    assert( pP4!=0 );
    ++    assert( p->nOp>0 );
    ++    pOp = &p->aOp[p->nOp-1];
    ++    assert( pOp->p4type==P4_NOTUSED );
    ++    pOp->p4type = n;
    ++    pOp->p4.p = pP4;
    +   }
    + }
    + 
    +@@ -67598,10 +74016,11 @@ SQLITE_PRIVATE void sqlite3VdbeChangeP4(Vdbe *p, int addr, const char *zP4, int
    + */
    + SQLITE_PRIVATE void sqlite3VdbeSetP4KeyInfo(Parse *pParse, Index *pIdx){
    +   Vdbe *v = pParse->pVdbe;
    ++  KeyInfo *pKeyInfo;
    +   assert( v!=0 );
    +   assert( pIdx!=0 );
    +-  sqlite3VdbeChangeP4(v, -1, (char*)sqlite3KeyInfoOfIndex(pParse, pIdx),
    +-                      P4_KEYINFO);
    ++  pKeyInfo = sqlite3KeyInfoOfIndex(pParse, pIdx);
    ++  if( pKeyInfo ) sqlite3VdbeAppendP4(v, pKeyInfo, P4_KEYINFO);
    + }
    + 
    + #ifdef SQLITE_ENABLE_EXPLAIN_COMMENTS
    +@@ -67713,12 +74132,21 @@ static int displayComment(
    +   const char *zSynopsis;
    +   int nOpName;
    +   int ii, jj;
    ++  char zAlt[50];
    +   zOpName = sqlite3OpcodeName(pOp->opcode);
    +   nOpName = sqlite3Strlen30(zOpName);
    +   if( zOpName[nOpName+1] ){
    +     int seenCom = 0;
    +     char c;
    +     zSynopsis = zOpName += nOpName + 1;
    ++    if( strncmp(zSynopsis,"IF ",3)==0 ){
    ++      if( pOp->p5 & SQLITE_STOREP2 ){
    ++        sqlite3_snprintf(sizeof(zAlt), zAlt, "r[P2] = (%s)", zSynopsis+3);
    ++      }else{
    ++        sqlite3_snprintf(sizeof(zAlt), zAlt, "if %s goto P2", zSynopsis+3);
    ++      }
    ++      zSynopsis = zAlt;
    ++    }
    +     for(ii=jj=0; jj<nTemp-1 && (c = zSynopsis[ii])!=0; ii++){
    +       if( c=='P' ){
    +         c = zSynopsis[++ii];
    +@@ -67767,75 +74195,138 @@ static int displayComment(
    + }
    + #endif /* SQLITE_DEBUG */
    + 
    ++#if VDBE_DISPLAY_P4 && defined(SQLITE_ENABLE_CURSOR_HINTS)
    ++/*
    ++** Translate the P4.pExpr value for an OP_CursorHint opcode into text
    ++** that can be displayed in the P4 column of EXPLAIN output.
    ++*/
    ++static void displayP4Expr(StrAccum *p, Expr *pExpr){
    ++  const char *zOp = 0;
    ++  switch( pExpr->op ){
    ++    case TK_STRING:
    ++      sqlite3XPrintf(p, "%Q", pExpr->u.zToken);
    ++      break;
    ++    case TK_INTEGER:
    ++      sqlite3XPrintf(p, "%d", pExpr->u.iValue);
    ++      break;
    ++    case TK_NULL:
    ++      sqlite3XPrintf(p, "NULL");
    ++      break;
    ++    case TK_REGISTER: {
    ++      sqlite3XPrintf(p, "r[%d]", pExpr->iTable);
    ++      break;
    ++    }
    ++    case TK_COLUMN: {
    ++      if( pExpr->iColumn<0 ){
    ++        sqlite3XPrintf(p, "rowid");
    ++      }else{
    ++        sqlite3XPrintf(p, "c%d", (int)pExpr->iColumn);
    ++      }
    ++      break;
    ++    }
    ++    case TK_LT:      zOp = "LT";      break;
    ++    case TK_LE:      zOp = "LE";      break;
    ++    case TK_GT:      zOp = "GT";      break;
    ++    case TK_GE:      zOp = "GE";      break;
    ++    case TK_NE:      zOp = "NE";      break;
    ++    case TK_EQ:      zOp = "EQ";      break;
    ++    case TK_IS:      zOp = "IS";      break;
    ++    case TK_ISNOT:   zOp = "ISNOT";   break;
    ++    case TK_AND:     zOp = "AND";     break;
    ++    case TK_OR:      zOp = "OR";      break;
    ++    case TK_PLUS:    zOp = "ADD";     break;
    ++    case TK_STAR:    zOp = "MUL";     break;
    ++    case TK_MINUS:   zOp = "SUB";     break;
    ++    case TK_REM:     zOp = "REM";     break;
    ++    case TK_BITAND:  zOp = "BITAND";  break;
    ++    case TK_BITOR:   zOp = "BITOR";   break;
    ++    case TK_SLASH:   zOp = "DIV";     break;
    ++    case TK_LSHIFT:  zOp = "LSHIFT";  break;
    ++    case TK_RSHIFT:  zOp = "RSHIFT";  break;
    ++    case TK_CONCAT:  zOp = "CONCAT";  break;
    ++    case TK_UMINUS:  zOp = "MINUS";   break;
    ++    case TK_UPLUS:   zOp = "PLUS";    break;
    ++    case TK_BITNOT:  zOp = "BITNOT";  break;
    ++    case TK_NOT:     zOp = "NOT";     break;
    ++    case TK_ISNULL:  zOp = "ISNULL";  break;
    ++    case TK_NOTNULL: zOp = "NOTNULL"; break;
    + 
    +-#if !defined(SQLITE_OMIT_EXPLAIN) || !defined(NDEBUG) \
    +-     || defined(VDBE_PROFILE) || defined(SQLITE_DEBUG)
    ++    default:
    ++      sqlite3XPrintf(p, "%s", "expr");
    ++      break;
    ++  }
    ++
    ++  if( zOp ){
    ++    sqlite3XPrintf(p, "%s(", zOp);
    ++    displayP4Expr(p, pExpr->pLeft);
    ++    if( pExpr->pRight ){
    ++      sqlite3StrAccumAppend(p, ",", 1);
    ++      displayP4Expr(p, pExpr->pRight);
    ++    }
    ++    sqlite3StrAccumAppend(p, ")", 1);
    ++  }
    ++}
    ++#endif /* VDBE_DISPLAY_P4 && defined(SQLITE_ENABLE_CURSOR_HINTS) */
    ++
    ++
    ++#if VDBE_DISPLAY_P4
    + /*
    + ** Compute a string that describes the P4 parameter for an opcode.
    + ** Use zTemp for any required temporary buffer space.
    + */
    + static char *displayP4(Op *pOp, char *zTemp, int nTemp){
    +   char *zP4 = zTemp;
    ++  StrAccum x;
    +   assert( nTemp>=20 );
    ++  sqlite3StrAccumInit(&x, 0, zTemp, nTemp, 0);
    +   switch( pOp->p4type ){
    +     case P4_KEYINFO: {
    +-      int i, j;
    ++      int j;
    +       KeyInfo *pKeyInfo = pOp->p4.pKeyInfo;
    +       assert( pKeyInfo->aSortOrder!=0 );
    +-      sqlite3_snprintf(nTemp, zTemp, "k(%d", pKeyInfo->nField);
    +-      i = sqlite3Strlen30(zTemp);
    +-      for(j=0; j<pKeyInfo->nField; j++){
    ++      sqlite3XPrintf(&x, "k(%d", pKeyInfo->nKeyField);
    ++      for(j=0; j<pKeyInfo->nKeyField; j++){
    +         CollSeq *pColl = pKeyInfo->aColl[j];
    +-        const char *zColl = pColl ? pColl->zName : "nil";
    +-        int n = sqlite3Strlen30(zColl);
    +-        if( n==6 && memcmp(zColl,"BINARY",6)==0 ){
    +-          zColl = "B";
    +-          n = 1;
    +-        }
    +-        if( i+n>nTemp-7 ){
    +-          memcpy(&zTemp[i],",...",4);
    +-          i += 4;
    +-          break;
    +-        }
    +-        zTemp[i++] = ',';
    +-        if( pKeyInfo->aSortOrder[j] ){
    +-          zTemp[i++] = '-';
    +-        }
    +-        memcpy(&zTemp[i], zColl, n+1);
    +-        i += n;
    ++        const char *zColl = pColl ? pColl->zName : "";
    ++        if( strcmp(zColl, "BINARY")==0 ) zColl = "B";
    ++        sqlite3XPrintf(&x, ",%s%s", pKeyInfo->aSortOrder[j] ? "-" : "", zColl);
    +       }
    +-      zTemp[i++] = ')';
    +-      zTemp[i] = 0;
    +-      assert( i<nTemp );
    ++      sqlite3StrAccumAppend(&x, ")", 1);
    ++      break;
    ++    }
    ++#ifdef SQLITE_ENABLE_CURSOR_HINTS
    ++    case P4_EXPR: {
    ++      displayP4Expr(&x, pOp->p4.pExpr);
    +       break;
    +     }
    ++#endif
    +     case P4_COLLSEQ: {
    +       CollSeq *pColl = pOp->p4.pColl;
    +-      sqlite3_snprintf(nTemp, zTemp, "(%.20s)", pColl->zName);
    ++      sqlite3XPrintf(&x, "(%.20s)", pColl->zName);
    +       break;
    +     }
    +     case P4_FUNCDEF: {
    +       FuncDef *pDef = pOp->p4.pFunc;
    +-      sqlite3_snprintf(nTemp, zTemp, "%s(%d)", pDef->zName, pDef->nArg);
    ++      sqlite3XPrintf(&x, "%s(%d)", pDef->zName, pDef->nArg);
    +       break;
    +     }
    +-#ifdef SQLITE_DEBUG
    ++#if defined(SQLITE_DEBUG) || defined(VDBE_PROFILE)
    +     case P4_FUNCCTX: {
    +       FuncDef *pDef = pOp->p4.pCtx->pFunc;
    +-      sqlite3_snprintf(nTemp, zTemp, "%s(%d)", pDef->zName, pDef->nArg);
    ++      sqlite3XPrintf(&x, "%s(%d)", pDef->zName, pDef->nArg);
    +       break;
    +     }
    + #endif
    +     case P4_INT64: {
    +-      sqlite3_snprintf(nTemp, zTemp, "%lld", *pOp->p4.pI64);
    ++      sqlite3XPrintf(&x, "%lld", *pOp->p4.pI64);
    +       break;
    +     }
    +     case P4_INT32: {
    +-      sqlite3_snprintf(nTemp, zTemp, "%d", pOp->p4.i);
    ++      sqlite3XPrintf(&x, "%d", pOp->p4.i);
    +       break;
    +     }
    +     case P4_REAL: {
    +-      sqlite3_snprintf(nTemp, zTemp, "%.16g", *pOp->p4.pReal);
    ++      sqlite3XPrintf(&x, "%.16g", *pOp->p4.pReal);
    +       break;
    +     }
    +     case P4_MEM: {
    +@@ -67843,11 +74334,11 @@ static char *displayP4(Op *pOp, char *zTemp, int nTemp){
    +       if( pMem->flags & MEM_Str ){
    +         zP4 = pMem->z;
    +       }else if( pMem->flags & MEM_Int ){
    +-        sqlite3_snprintf(nTemp, zTemp, "%lld", pMem->u.i);
    ++        sqlite3XPrintf(&x, "%lld", pMem->u.i);
    +       }else if( pMem->flags & MEM_Real ){
    +-        sqlite3_snprintf(nTemp, zTemp, "%.16g", pMem->u.r);
    ++        sqlite3XPrintf(&x, "%.16g", pMem->u.r);
    +       }else if( pMem->flags & MEM_Null ){
    +-        sqlite3_snprintf(nTemp, zTemp, "NULL");
    ++        zP4 = "NULL";
    +       }else{
    +         assert( pMem->flags & MEM_Blob );
    +         zP4 = "(blob)";
    +@@ -67857,22 +74348,35 @@ static char *displayP4(Op *pOp, char *zTemp, int nTemp){
    + #ifndef SQLITE_OMIT_VIRTUALTABLE
    +     case P4_VTAB: {
    +       sqlite3_vtab *pVtab = pOp->p4.pVtab->pVtab;
    +-      sqlite3_snprintf(nTemp, zTemp, "vtab:%p", pVtab);
    ++      sqlite3XPrintf(&x, "vtab:%p", pVtab);
    +       break;
    +     }
    + #endif
    +     case P4_INTARRAY: {
    +-      sqlite3_snprintf(nTemp, zTemp, "intarray");
    ++      int i;
    ++      int *ai = pOp->p4.ai;
    ++      int n = ai[0];   /* The first element of an INTARRAY is always the
    ++                       ** count of the number of elements to follow */
    ++      for(i=1; i<=n; i++){
    ++        sqlite3XPrintf(&x, ",%d", ai[i]);
    ++      }
    ++      zTemp[0] = '[';
    ++      sqlite3StrAccumAppend(&x, "]", 1);
    +       break;
    +     }
    +     case P4_SUBPROGRAM: {
    +-      sqlite3_snprintf(nTemp, zTemp, "program");
    ++      sqlite3XPrintf(&x, "program");
    +       break;
    +     }
    ++    case P4_DYNBLOB:
    +     case P4_ADVANCE: {
    +       zTemp[0] = 0;
    +       break;
    +     }
    ++    case P4_TABLE: {
    ++      sqlite3XPrintf(&x, "%s", pOp->p4.pTab->zName);
    ++      break;
    ++    }
    +     default: {
    +       zP4 = pOp->p4.z;
    +       if( zP4==0 ){
    +@@ -67881,10 +74385,11 @@ static char *displayP4(Op *pOp, char *zTemp, int nTemp){
    +       }
    +     }
    +   }
    ++  sqlite3StrAccumFinish(&x);
    +   assert( zP4!=0 );
    +   return zP4;
    + }
    +-#endif
    ++#endif /* VDBE_DISPLAY_P4 */
    + 
    + /*
    + ** Declare to the Vdbe that the BTree object at db->aDb[i] is used.
    +@@ -67903,7 +74408,7 @@ SQLITE_PRIVATE void sqlite3VdbeUsesBtree(Vdbe *p, int i){
    +   }
    + }
    + 
    +-#if !defined(SQLITE_OMIT_SHARED_CACHE) && SQLITE_THREADSAFE>0
    ++#if !defined(SQLITE_OMIT_SHARED_CACHE)
    + /*
    + ** If SQLite is compiled to support shared-cache mode and to be threadsafe,
    + ** this routine obtains the mutex associated with each BtShared structure
    +@@ -67993,6 +74498,21 @@ SQLITE_PRIVATE void sqlite3VdbePrintOp(FILE *pOut, int pc, Op *pOp){
    + }
    + #endif
    + 
    ++/*
    ++** Initialize an array of N Mem element.
    ++*/
    ++static void initMemArray(Mem *p, int N, sqlite3 *db, u16 flags){
    ++  while( (N--)>0 ){
    ++    p->db = db;
    ++    p->flags = flags;
    ++    p->szMalloc = 0;
    ++#ifdef SQLITE_DEBUG
    ++    p->pScopyFrom = 0;
    ++#endif
    ++    p++;
    ++  }
    ++}
    ++
    + /*
    + ** Release an array of N Mem elements
    + */
    +@@ -68000,7 +74520,6 @@ static void releaseMemArray(Mem *p, int N){
    +   if( p && N ){
    +     Mem *pEnd = &p[N];
    +     sqlite3 *db = p->db;
    +-    u8 malloc_failed = db->mallocFailed;
    +     if( db->pnBytesFreed ){
    +       do{
    +         if( p->szMalloc ) sqlite3DbFree(db, p->zMalloc);
    +@@ -68030,13 +74549,12 @@ static void releaseMemArray(Mem *p, int N){
    +       if( p->flags&(MEM_Agg|MEM_Dyn|MEM_Frame|MEM_RowSet) ){
    +         sqlite3VdbeMemRelease(p);
    +       }else if( p->szMalloc ){
    +-        sqlite3DbFree(db, p->zMalloc);
    ++        sqlite3DbFreeNN(db, p->zMalloc);
    +         p->szMalloc = 0;
    +       }
    + 
    +       p->flags = MEM_Undefined;
    +     }while( (++p)<pEnd );
    +-    db->mallocFailed = malloc_failed;
    +   }
    + }
    + 
    +@@ -68052,6 +74570,7 @@ SQLITE_PRIVATE void sqlite3VdbeFrameDelete(VdbeFrame *p){
    +     sqlite3VdbeFreeCursor(p->v, apCsr[i]);
    +   }
    +   releaseMemArray(aMem, p->nChildMem);
    ++  sqlite3VdbeDeleteAuxData(p->v->db, &p->pAuxData, -1, 0);
    +   sqlite3DbFree(p->v->db, p);
    + }
    + 
    +@@ -68082,6 +74601,8 @@ SQLITE_PRIVATE int sqlite3VdbeList(
    +   int i;                               /* Loop counter */
    +   int rc = SQLITE_OK;                  /* Return code */
    +   Mem *pMem = &p->aMem[1];             /* First Mem of result set */
    ++  int bListSubprogs = (p->explain==1 || (db->flags & SQLITE_TriggerEQP)!=0);
    ++  Op *pOp = 0;
    + 
    +   assert( p->explain );
    +   assert( p->magic==VDBE_MAGIC_RUN );
    +@@ -68097,7 +74618,7 @@ SQLITE_PRIVATE int sqlite3VdbeList(
    +   if( p->rc==SQLITE_NOMEM ){
    +     /* This happens if a malloc() inside a call to sqlite3_column_text() or
    +     ** sqlite3_column_text16() failed.  */
    +-    db->mallocFailed = 1;
    ++    sqlite3OomFault(db);
    +     return SQLITE_ERROR;
    +   }
    + 
    +@@ -68109,7 +74630,7 @@ SQLITE_PRIVATE int sqlite3VdbeList(
    +   ** encountered, but p->pc will eventually catch up to nRow.
    +   */
    +   nRow = p->nOp;
    +-  if( p->explain==1 ){
    ++  if( bListSubprogs ){
    +     /* The first 8 memory cells are used for the result set.  So we will
    +     ** commandeer the 9th cell to use as storage for an array of pointers
    +     ** to trigger subprograms.  The VDBE is guaranteed to have at least 9
    +@@ -68129,17 +74650,11 @@ SQLITE_PRIVATE int sqlite3VdbeList(
    + 
    +   do{
    +     i = p->pc++;
    +-  }while( i<nRow && p->explain==2 && p->aOp[i].opcode!=OP_Explain );
    +-  if( i>=nRow ){
    +-    p->rc = SQLITE_OK;
    +-    rc = SQLITE_DONE;
    +-  }else if( db->u1.isInterrupted ){
    +-    p->rc = SQLITE_INTERRUPT;
    +-    rc = SQLITE_ERROR;
    +-    sqlite3VdbeError(p, sqlite3ErrStr(p->rc));
    +-  }else{
    +-    char *zP4;
    +-    Op *pOp;
    ++    if( i>=nRow ){
    ++      p->rc = SQLITE_OK;
    ++      rc = SQLITE_DONE;
    ++      break;
    ++    }
    +     if( i<p->nOp ){
    +       /* The output line number is small enough that we are still in the
    +       ** main program. */
    +@@ -68154,93 +74669,110 @@ SQLITE_PRIVATE int sqlite3VdbeList(
    +       }
    +       pOp = &apSub[j]->aOp[i];
    +     }
    +-    if( p->explain==1 ){
    +-      pMem->flags = MEM_Int;
    +-      pMem->u.i = i;                                /* Program counter */
    +-      pMem++;
    +-  
    +-      pMem->flags = MEM_Static|MEM_Str|MEM_Term;
    +-      pMem->z = (char*)sqlite3OpcodeName(pOp->opcode); /* Opcode */
    +-      assert( pMem->z!=0 );
    +-      pMem->n = sqlite3Strlen30(pMem->z);
    +-      pMem->enc = SQLITE_UTF8;
    +-      pMem++;
    + 
    +-      /* When an OP_Program opcode is encounter (the only opcode that has
    +-      ** a P4_SUBPROGRAM argument), expand the size of the array of subprograms
    +-      ** kept in p->aMem[9].z to hold the new program - assuming this subprogram
    +-      ** has not already been seen.
    +-      */
    +-      if( pOp->p4type==P4_SUBPROGRAM ){
    +-        int nByte = (nSub+1)*sizeof(SubProgram*);
    +-        int j;
    +-        for(j=0; j<nSub; j++){
    +-          if( apSub[j]==pOp->p4.pProgram ) break;
    +-        }
    +-        if( j==nSub && SQLITE_OK==sqlite3VdbeMemGrow(pSub, nByte, nSub!=0) ){
    +-          apSub = (SubProgram **)pSub->z;
    +-          apSub[nSub++] = pOp->p4.pProgram;
    +-          pSub->flags |= MEM_Blob;
    +-          pSub->n = nSub*sizeof(SubProgram*);
    ++    /* When an OP_Program opcode is encounter (the only opcode that has
    ++    ** a P4_SUBPROGRAM argument), expand the size of the array of subprograms
    ++    ** kept in p->aMem[9].z to hold the new program - assuming this subprogram
    ++    ** has not already been seen.
    ++    */
    ++    if( bListSubprogs && pOp->p4type==P4_SUBPROGRAM ){
    ++      int nByte = (nSub+1)*sizeof(SubProgram*);
    ++      int j;
    ++      for(j=0; j<nSub; j++){
    ++        if( apSub[j]==pOp->p4.pProgram ) break;
    ++      }
    ++      if( j==nSub ){
    ++        p->rc = sqlite3VdbeMemGrow(pSub, nByte, nSub!=0);
    ++        if( p->rc!=SQLITE_OK ){
    ++          rc = SQLITE_ERROR;
    ++          break;
    +         }
    ++        apSub = (SubProgram **)pSub->z;
    ++        apSub[nSub++] = pOp->p4.pProgram;
    ++        pSub->flags |= MEM_Blob;
    ++        pSub->n = nSub*sizeof(SubProgram*);
    ++        nRow += pOp->p4.pProgram->nOp;
    +       }
    +     }
    ++  }while( p->explain==2 && pOp->opcode!=OP_Explain );
    + 
    +-    pMem->flags = MEM_Int;
    +-    pMem->u.i = pOp->p1;                          /* P1 */
    +-    pMem++;
    ++  if( rc==SQLITE_OK ){
    ++    if( db->u1.isInterrupted ){
    ++      p->rc = SQLITE_INTERRUPT;
    ++      rc = SQLITE_ERROR;
    ++      sqlite3VdbeError(p, sqlite3ErrStr(p->rc));
    ++    }else{
    ++      char *zP4;
    ++      if( p->explain==1 ){
    ++        pMem->flags = MEM_Int;
    ++        pMem->u.i = i;                                /* Program counter */
    ++        pMem++;
    ++    
    ++        pMem->flags = MEM_Static|MEM_Str|MEM_Term;
    ++        pMem->z = (char*)sqlite3OpcodeName(pOp->opcode); /* Opcode */
    ++        assert( pMem->z!=0 );
    ++        pMem->n = sqlite3Strlen30(pMem->z);
    ++        pMem->enc = SQLITE_UTF8;
    ++        pMem++;
    ++      }
    + 
    +-    pMem->flags = MEM_Int;
    +-    pMem->u.i = pOp->p2;                          /* P2 */
    +-    pMem++;
    ++      pMem->flags = MEM_Int;
    ++      pMem->u.i = pOp->p1;                          /* P1 */
    ++      pMem++;
    + 
    +-    pMem->flags = MEM_Int;
    +-    pMem->u.i = pOp->p3;                          /* P3 */
    +-    pMem++;
    ++      pMem->flags = MEM_Int;
    ++      pMem->u.i = pOp->p2;                          /* P2 */
    ++      pMem++;
    + 
    +-    if( sqlite3VdbeMemClearAndResize(pMem, 32) ){ /* P4 */
    +-      assert( p->db->mallocFailed );
    +-      return SQLITE_ERROR;
    +-    }
    +-    pMem->flags = MEM_Str|MEM_Term;
    +-    zP4 = displayP4(pOp, pMem->z, 32);
    +-    if( zP4!=pMem->z ){
    +-      sqlite3VdbeMemSetStr(pMem, zP4, -1, SQLITE_UTF8, 0);
    +-    }else{
    +-      assert( pMem->z!=0 );
    +-      pMem->n = sqlite3Strlen30(pMem->z);
    +-      pMem->enc = SQLITE_UTF8;
    +-    }
    +-    pMem++;
    ++      pMem->flags = MEM_Int;
    ++      pMem->u.i = pOp->p3;                          /* P3 */
    ++      pMem++;
    + 
    +-    if( p->explain==1 ){
    +-      if( sqlite3VdbeMemClearAndResize(pMem, 4) ){
    ++      if( sqlite3VdbeMemClearAndResize(pMem, 100) ){ /* P4 */
    +         assert( p->db->mallocFailed );
    +         return SQLITE_ERROR;
    +       }
    +       pMem->flags = MEM_Str|MEM_Term;
    +-      pMem->n = 2;
    +-      sqlite3_snprintf(3, pMem->z, "%.2x", pOp->p5);   /* P5 */
    +-      pMem->enc = SQLITE_UTF8;
    ++      zP4 = displayP4(pOp, pMem->z, pMem->szMalloc);
    ++      if( zP4!=pMem->z ){
    ++        pMem->n = 0;
    ++        sqlite3VdbeMemSetStr(pMem, zP4, -1, SQLITE_UTF8, 0);
    ++      }else{
    ++        assert( pMem->z!=0 );
    ++        pMem->n = sqlite3Strlen30(pMem->z);
    ++        pMem->enc = SQLITE_UTF8;
    ++      }
    +       pMem++;
    +-  
    ++
    ++      if( p->explain==1 ){
    ++        if( sqlite3VdbeMemClearAndResize(pMem, 4) ){
    ++          assert( p->db->mallocFailed );
    ++          return SQLITE_ERROR;
    ++        }
    ++        pMem->flags = MEM_Str|MEM_Term;
    ++        pMem->n = 2;
    ++        sqlite3_snprintf(3, pMem->z, "%.2x", pOp->p5);   /* P5 */
    ++        pMem->enc = SQLITE_UTF8;
    ++        pMem++;
    ++    
    + #ifdef SQLITE_ENABLE_EXPLAIN_COMMENTS
    +-      if( sqlite3VdbeMemClearAndResize(pMem, 500) ){
    +-        assert( p->db->mallocFailed );
    +-        return SQLITE_ERROR;
    +-      }
    +-      pMem->flags = MEM_Str|MEM_Term;
    +-      pMem->n = displayComment(pOp, zP4, pMem->z, 500);
    +-      pMem->enc = SQLITE_UTF8;
    ++        if( sqlite3VdbeMemClearAndResize(pMem, 500) ){
    ++          assert( p->db->mallocFailed );
    ++          return SQLITE_ERROR;
    ++        }
    ++        pMem->flags = MEM_Str|MEM_Term;
    ++        pMem->n = displayComment(pOp, zP4, pMem->z, 500);
    ++        pMem->enc = SQLITE_UTF8;
    + #else
    +-      pMem->flags = MEM_Null;                       /* Comment */
    ++        pMem->flags = MEM_Null;                       /* Comment */
    + #endif
    +-    }
    ++      }
    + 
    +-    p->nResColumn = 8 - 4*(p->explain-1);
    +-    p->pResultSet = &p->aMem[1];
    +-    p->rc = SQLITE_OK;
    +-    rc = SQLITE_ROW;
    ++      p->nResColumn = 8 - 4*(p->explain-1);
    ++      p->pResultSet = &p->aMem[1];
    ++      p->rc = SQLITE_OK;
    ++      rc = SQLITE_ROW;
    ++    }
    +   }
    +   return rc;
    + }
    +@@ -68295,43 +74827,46 @@ SQLITE_PRIVATE void sqlite3VdbeIOTraceSql(Vdbe *p){
    + }
    + #endif /* !SQLITE_OMIT_TRACE && SQLITE_ENABLE_IOTRACE */
    + 
    +-/*
    +-** Allocate space from a fixed size buffer and return a pointer to
    +-** that space.  If insufficient space is available, return NULL.
    +-**
    +-** The pBuf parameter is the initial value of a pointer which will
    +-** receive the new memory.  pBuf is normally NULL.  If pBuf is not
    +-** NULL, it means that memory space has already been allocated and that
    +-** this routine should not allocate any new memory.  When pBuf is not
    +-** NULL simply return pBuf.  Only allocate new memory space when pBuf
    +-** is NULL.
    +-**
    +-** nByte is the number of bytes of space needed.
    ++/* An instance of this object describes bulk memory available for use
    ++** by subcomponents of a prepared statement.  Space is allocated out
    ++** of a ReusableSpace object by the allocSpace() routine below.
    ++*/
    ++struct ReusableSpace {
    ++  u8 *pSpace;          /* Available memory */
    ++  int nFree;           /* Bytes of available memory */
    ++  int nNeeded;         /* Total bytes that could not be allocated */
    ++};
    ++
    ++/* Try to allocate nByte bytes of 8-byte aligned bulk memory for pBuf
    ++** from the ReusableSpace object.  Return a pointer to the allocated
    ++** memory on success.  If insufficient memory is available in the
    ++** ReusableSpace object, increase the ReusableSpace.nNeeded
    ++** value by the amount needed and return NULL.
    + **
    +-** *ppFrom points to available space and pEnd points to the end of the
    +-** available space.  When space is allocated, *ppFrom is advanced past
    +-** the end of the allocated space.
    ++** If pBuf is not initially NULL, that means that the memory has already
    ++** been allocated by a prior call to this routine, so just return a copy
    ++** of pBuf and leave ReusableSpace unchanged.
    + **
    +-** *pnByte is a counter of the number of bytes of space that have failed
    +-** to allocate.  If there is insufficient space in *ppFrom to satisfy the
    +-** request, then increment *pnByte by the amount of the request.
    ++** This allocator is employed to repurpose unused slots at the end of the
    ++** opcode array of prepared state for other memory needs of the prepared
    ++** statement.
    + */
    + static void *allocSpace(
    +-  void *pBuf,          /* Where return pointer will be stored */
    +-  int nByte,           /* Number of bytes to allocate */
    +-  u8 **ppFrom,         /* IN/OUT: Allocate from *ppFrom */
    +-  u8 *pEnd,            /* Pointer to 1 byte past the end of *ppFrom buffer */
    +-  int *pnByte          /* If allocation cannot be made, increment *pnByte */
    +-){
    +-  assert( EIGHT_BYTE_ALIGNMENT(*ppFrom) );
    +-  if( pBuf ) return pBuf;
    +-  nByte = ROUND8(nByte);
    +-  if( &(*ppFrom)[nByte] <= pEnd ){
    +-    pBuf = (void*)*ppFrom;
    +-    *ppFrom += nByte;
    +-  }else{
    +-    *pnByte += nByte;
    ++  struct ReusableSpace *p,  /* Bulk memory available for allocation */
    ++  void *pBuf,               /* Pointer to a prior allocation */
    ++  int nByte                 /* Bytes of memory needed */
    ++){
    ++  assert( EIGHT_BYTE_ALIGNMENT(p->pSpace) );
    ++  if( pBuf==0 ){
    ++    nByte = ROUND8(nByte);
    ++    if( nByte <= p->nFree ){
    ++      p->nFree -= nByte;
    ++      pBuf = &p->pSpace[p->nFree];
    ++    }else{
    ++      p->nNeeded += nByte;
    ++    }
    +   }
    ++  assert( EIGHT_BYTE_ALIGNMENT(pBuf) );
    +   return pBuf;
    + }
    + 
    +@@ -68344,7 +74879,7 @@ SQLITE_PRIVATE void sqlite3VdbeRewind(Vdbe *p){
    +   int i;
    + #endif
    +   assert( p!=0 );
    +-  assert( p->magic==VDBE_MAGIC_INIT );
    ++  assert( p->magic==VDBE_MAGIC_INIT || p->magic==VDBE_MAGIC_RESET );
    + 
    +   /* There should be at least one opcode.
    +   */
    +@@ -68354,14 +74889,13 @@ SQLITE_PRIVATE void sqlite3VdbeRewind(Vdbe *p){
    +   p->magic = VDBE_MAGIC_RUN;
    + 
    + #ifdef SQLITE_DEBUG
    +-  for(i=1; i<p->nMem; i++){
    ++  for(i=0; i<p->nMem; i++){
    +     assert( p->aMem[i].db==p->db );
    +   }
    + #endif
    +   p->pc = -1;
    +   p->rc = SQLITE_OK;
    +   p->errorAction = OE_Abort;
    +-  p->magic = VDBE_MAGIC_RUN;
    +   p->nChange = 0;
    +   p->cacheCtr = 1;
    +   p->minWriteFileFormat = 255;
    +@@ -68402,11 +74936,8 @@ SQLITE_PRIVATE void sqlite3VdbeMakeReady(
    +   int nMem;                      /* Number of VM memory registers */
    +   int nCursor;                   /* Number of cursors required */
    +   int nArg;                      /* Number of arguments in subprograms */
    +-  int nOnce;                     /* Number of OP_Once instructions */
    +   int n;                         /* Loop counter */
    +-  u8 *zCsr;                      /* Memory available for allocation */
    +-  u8 *zEnd;                      /* First byte past allocated memory */
    +-  int nByte;                     /* How much extra memory is needed */
    ++  struct ReusableSpace x;        /* Reusable bulk memory */
    + 
    +   assert( p!=0 );
    +   assert( p->nOp>0 );
    +@@ -68419,88 +74950,75 @@ SQLITE_PRIVATE void sqlite3VdbeMakeReady(
    +   nMem = pParse->nMem;
    +   nCursor = pParse->nTab;
    +   nArg = pParse->nMaxArg;
    +-  nOnce = pParse->nOnce;
    +-  if( nOnce==0 ) nOnce = 1; /* Ensure at least one byte in p->aOnceFlag[] */
    +   
    +-  /* For each cursor required, also allocate a memory cell. Memory
    +-  ** cells (nMem+1-nCursor)..nMem, inclusive, will never be used by
    +-  ** the vdbe program. Instead they are used to allocate space for
    +-  ** VdbeCursor/BtCursor structures. The blob of memory associated with 
    +-  ** cursor 0 is stored in memory cell nMem. Memory cell (nMem-1)
    +-  ** stores the blob of memory associated with cursor 1, etc.
    +-  **
    ++  /* Each cursor uses a memory cell.  The first cursor (cursor 0) can
    ++  ** use aMem[0] which is not otherwise used by the VDBE program.  Allocate
    ++  ** space at the end of aMem[] for cursors 1 and greater.
    +   ** See also: allocateCursor().
    +   */
    +   nMem += nCursor;
    ++  if( nCursor==0 && nMem>0 ) nMem++;  /* Space for aMem[0] even if not used */
    + 
    +-  /* Allocate space for memory registers, SQL variables, VDBE cursors and 
    +-  ** an array to marshal SQL function arguments in.
    ++  /* Figure out how much reusable memory is available at the end of the
    ++  ** opcode array.  This extra memory will be reallocated for other elements
    ++  ** of the prepared statement.
    +   */
    +-  zCsr = (u8*)&p->aOp[p->nOp];            /* Memory avaliable for allocation */
    +-  zEnd = (u8*)&p->aOp[pParse->nOpAlloc];  /* First byte past end of zCsr[] */
    ++  n = ROUND8(sizeof(Op)*p->nOp);              /* Bytes of opcode memory used */
    ++  x.pSpace = &((u8*)p->aOp)[n];               /* Unused opcode memory */
    ++  assert( EIGHT_BYTE_ALIGNMENT(x.pSpace) );
    ++  x.nFree = ROUNDDOWN8(pParse->szOpAlloc - n);  /* Bytes of unused memory */
    ++  assert( x.nFree>=0 );
    ++  assert( EIGHT_BYTE_ALIGNMENT(&x.pSpace[x.nFree]) );
    + 
    +   resolveP2Values(p, &nArg);
    +   p->usesStmtJournal = (u8)(pParse->isMultiWrite && pParse->mayAbort);
    +   if( pParse->explain && nMem<10 ){
    +     nMem = 10;
    +   }
    +-  memset(zCsr, 0, zEnd-zCsr);
    +-  zCsr += (zCsr - (u8*)0)&7;
    +-  assert( EIGHT_BYTE_ALIGNMENT(zCsr) );
    +   p->expired = 0;
    + 
    +-  /* Memory for registers, parameters, cursor, etc, is allocated in two
    +-  ** passes.  On the first pass, we try to reuse unused space at the 
    ++  /* Memory for registers, parameters, cursor, etc, is allocated in one or two
    ++  ** passes.  On the first pass, we try to reuse unused memory at the 
    +   ** end of the opcode array.  If we are unable to satisfy all memory
    +   ** requirements by reusing the opcode array tail, then the second
    +-  ** pass will fill in the rest using a fresh allocation.  
    ++  ** pass will fill in the remainder using a fresh memory allocation.  
    +   **
    +   ** This two-pass approach that reuses as much memory as possible from
    +-  ** the leftover space at the end of the opcode array can significantly
    ++  ** the leftover memory at the end of the opcode array.  This can significantly
    +   ** reduce the amount of memory held by a prepared statement.
    +   */
    +   do {
    +-    nByte = 0;
    +-    p->aMem = allocSpace(p->aMem, nMem*sizeof(Mem), &zCsr, zEnd, &nByte);
    +-    p->aVar = allocSpace(p->aVar, nVar*sizeof(Mem), &zCsr, zEnd, &nByte);
    +-    p->apArg = allocSpace(p->apArg, nArg*sizeof(Mem*), &zCsr, zEnd, &nByte);
    +-    p->azVar = allocSpace(p->azVar, nVar*sizeof(char*), &zCsr, zEnd, &nByte);
    +-    p->apCsr = allocSpace(p->apCsr, nCursor*sizeof(VdbeCursor*),
    +-                          &zCsr, zEnd, &nByte);
    +-    p->aOnceFlag = allocSpace(p->aOnceFlag, nOnce, &zCsr, zEnd, &nByte);
    ++    x.nNeeded = 0;
    ++    p->aMem = allocSpace(&x, p->aMem, nMem*sizeof(Mem));
    ++    p->aVar = allocSpace(&x, p->aVar, nVar*sizeof(Mem));
    ++    p->apArg = allocSpace(&x, p->apArg, nArg*sizeof(Mem*));
    ++    p->apCsr = allocSpace(&x, p->apCsr, nCursor*sizeof(VdbeCursor*));
    + #ifdef SQLITE_ENABLE_STMT_SCANSTATUS
    +-    p->anExec = allocSpace(p->anExec, p->nOp*sizeof(i64), &zCsr, zEnd, &nByte);
    ++    p->anExec = allocSpace(&x, p->anExec, p->nOp*sizeof(i64));
    + #endif
    +-    if( nByte ){
    +-      p->pFree = sqlite3DbMallocZero(db, nByte);
    +-    }
    +-    zCsr = p->pFree;
    +-    zEnd = &zCsr[nByte];
    +-  }while( nByte && !db->mallocFailed );
    ++    if( x.nNeeded==0 ) break;
    ++    x.pSpace = p->pFree = sqlite3DbMallocRawNN(db, x.nNeeded);
    ++    x.nFree = x.nNeeded;
    ++  }while( !db->mallocFailed );
    + 
    +-  p->nCursor = nCursor;
    +-  p->nOnceFlag = nOnce;
    +-  if( p->aVar ){
    ++  p->pVList = pParse->pVList;
    ++  pParse->pVList =  0;
    ++  p->explain = pParse->explain;
    ++  if( db->mallocFailed ){
    ++    p->nVar = 0;
    ++    p->nCursor = 0;
    ++    p->nMem = 0;
    ++  }else{
    ++    p->nCursor = nCursor;
    +     p->nVar = (ynVar)nVar;
    +-    for(n=0; n<nVar; n++){
    +-      p->aVar[n].flags = MEM_Null;
    +-      p->aVar[n].db = db;
    +-    }
    +-  }
    +-  if( p->azVar && pParse->nzVar>0 ){
    +-    p->nzVar = pParse->nzVar;
    +-    memcpy(p->azVar, pParse->azVar, p->nzVar*sizeof(p->azVar[0]));
    +-    memset(pParse->azVar, 0, pParse->nzVar*sizeof(pParse->azVar[0]));
    +-  }
    +-  if( p->aMem ){
    +-    p->aMem--;                      /* aMem[] goes from 1..nMem */
    +-    p->nMem = nMem;                 /*       not from 0..nMem-1 */
    +-    for(n=1; n<=nMem; n++){
    +-      p->aMem[n].flags = MEM_Undefined;
    +-      p->aMem[n].db = db;
    +-    }
    ++    initMemArray(p->aVar, nVar, db, MEM_Null);
    ++    p->nMem = nMem;
    ++    initMemArray(p->aMem, nMem, db, MEM_Undefined);
    ++    memset(p->apCsr, 0, nCursor*sizeof(VdbeCursor*));
    ++#ifdef SQLITE_ENABLE_STMT_SCANSTATUS
    ++    memset(p->anExec, 0, p->nOp*sizeof(i64));
    ++#endif
    +   }
    +-  p->explain = pParse->explain;
    +   sqlite3VdbeRewind(p);
    + }
    + 
    +@@ -68512,23 +75030,34 @@ SQLITE_PRIVATE void sqlite3VdbeFreeCursor(Vdbe *p, VdbeCursor *pCx){
    +   if( pCx==0 ){
    +     return;
    +   }
    +-  sqlite3VdbeSorterClose(p->db, pCx);
    +-  if( pCx->pBt ){
    +-    sqlite3BtreeClose(pCx->pBt);
    +-    /* The pCx->pCursor will be close automatically, if it exists, by
    +-    ** the call above. */
    +-  }else if( pCx->pCursor ){
    +-    sqlite3BtreeCloseCursor(pCx->pCursor);
    +-  }
    ++  assert( pCx->pBtx==0 || pCx->eCurType==CURTYPE_BTREE );
    ++  switch( pCx->eCurType ){
    ++    case CURTYPE_SORTER: {
    ++      sqlite3VdbeSorterClose(p->db, pCx);
    ++      break;
    ++    }
    ++    case CURTYPE_BTREE: {
    ++      if( pCx->isEphemeral ){
    ++        if( pCx->pBtx ) sqlite3BtreeClose(pCx->pBtx);
    ++        /* The pCx->pCursor will be close automatically, if it exists, by
    ++        ** the call above. */
    ++      }else{
    ++        assert( pCx->uc.pCursor!=0 );
    ++        sqlite3BtreeCloseCursor(pCx->uc.pCursor);
    ++      }
    ++      break;
    ++    }
    + #ifndef SQLITE_OMIT_VIRTUALTABLE
    +-  else if( pCx->pVtabCursor ){
    +-    sqlite3_vtab_cursor *pVtabCursor = pCx->pVtabCursor;
    +-    const sqlite3_module *pModule = pVtabCursor->pVtab->pModule;
    +-    assert( pVtabCursor->pVtab->nRef>0 );
    +-    pVtabCursor->pVtab->nRef--;
    +-    pModule->xClose(pVtabCursor);
    +-  }
    ++    case CURTYPE_VTAB: {
    ++      sqlite3_vtab_cursor *pVCur = pCx->uc.pVCur;
    ++      const sqlite3_module *pModule = pVCur->pVtab->pModule;
    ++      assert( pVCur->pVtab->nRef>0 );
    ++      pVCur->pVtab->nRef--;
    ++      pModule->xClose(pVCur);
    ++      break;
    ++    }
    + #endif
    ++  }
    + }
    + 
    + /*
    +@@ -68558,8 +75087,6 @@ SQLITE_PRIVATE int sqlite3VdbeFrameRestore(VdbeFrame *pFrame){
    + #ifdef SQLITE_ENABLE_STMT_SCANSTATUS
    +   v->anExec = pFrame->anExec;
    + #endif
    +-  v->aOnceFlag = pFrame->aOnceFlag;
    +-  v->nOnceFlag = pFrame->nOnceFlag;
    +   v->aOp = pFrame->aOp;
    +   v->nOp = pFrame->nOp;
    +   v->aMem = pFrame->aMem;
    +@@ -68569,6 +75096,9 @@ SQLITE_PRIVATE int sqlite3VdbeFrameRestore(VdbeFrame *pFrame){
    +   v->db->lastRowid = pFrame->lastRowid;
    +   v->nChange = pFrame->nChange;
    +   v->db->nChange = pFrame->nDbChange;
    ++  sqlite3VdbeDeleteAuxData(v->db, &v->pAuxData, -1, 0);
    ++  v->pAuxData = pFrame->pAuxData;
    ++  pFrame->pAuxData = 0;
    +   return pFrame->pc;
    + }
    + 
    +@@ -68591,7 +75121,7 @@ static void closeAllCursors(Vdbe *p){
    +   assert( p->nFrame==0 );
    +   closeCursorsInFrame(p);
    +   if( p->aMem ){
    +-    releaseMemArray(&p->aMem[1], p->nMem);
    ++    releaseMemArray(p->aMem, p->nMem);
    +   }
    +   while( p->pDelFrame ){
    +     VdbeFrame *pDel = p->pDelFrame;
    +@@ -68600,31 +75130,10 @@ static void closeAllCursors(Vdbe *p){
    +   }
    + 
    +   /* Delete any auxdata allocations made by the VM */
    +-  if( p->pAuxData ) sqlite3VdbeDeleteAuxData(p, -1, 0);
    ++  if( p->pAuxData ) sqlite3VdbeDeleteAuxData(p->db, &p->pAuxData, -1, 0);
    +   assert( p->pAuxData==0 );
    + }
    + 
    +-/*
    +-** Clean up the VM after a single run.
    +-*/
    +-static void Cleanup(Vdbe *p){
    +-  sqlite3 *db = p->db;
    +-
    +-#ifdef SQLITE_DEBUG
    +-  /* Execute assert() statements to ensure that the Vdbe.apCsr[] and 
    +-  ** Vdbe.aMem[] arrays have already been cleaned up.  */
    +-  int i;
    +-  if( p->apCsr ) for(i=0; i<p->nCursor; i++) assert( p->apCsr[i]==0 );
    +-  if( p->aMem ){
    +-    for(i=1; i<=p->nMem; i++) assert( p->aMem[i].flags==MEM_Undefined );
    +-  }
    +-#endif
    +-
    +-  sqlite3DbFree(db, p->zErrMsg);
    +-  p->zErrMsg = 0;
    +-  p->pResultSet = 0;
    +-}
    +-
    + /*
    + ** Set the number of result columns that will be returned by this SQL
    + ** statement. This is now set at compile time, rather than during
    +@@ -68632,21 +75141,18 @@ static void Cleanup(Vdbe *p){
    + ** be called on an SQL statement before sqlite3_step().
    + */
    + SQLITE_PRIVATE void sqlite3VdbeSetNumCols(Vdbe *p, int nResColumn){
    +-  Mem *pColName;
    +   int n;
    +   sqlite3 *db = p->db;
    + 
    +-  releaseMemArray(p->aColName, p->nResColumn*COLNAME_N);
    +-  sqlite3DbFree(db, p->aColName);
    ++  if( p->nResColumn ){
    ++    releaseMemArray(p->aColName, p->nResColumn*COLNAME_N);
    ++    sqlite3DbFree(db, p->aColName);
    ++  }
    +   n = nResColumn*COLNAME_N;
    +   p->nResColumn = (u16)nResColumn;
    +-  p->aColName = pColName = (Mem*)sqlite3DbMallocZero(db, sizeof(Mem)*n );
    ++  p->aColName = (Mem*)sqlite3DbMallocRawNN(db, sizeof(Mem)*n );
    +   if( p->aColName==0 ) return;
    +-  while( n-- > 0 ){
    +-    pColName->flags = MEM_Null;
    +-    pColName->db = p->db;
    +-    pColName++;
    +-  }
    ++  initMemArray(p->aColName, n, db, MEM_Null);
    + }
    + 
    + /*
    +@@ -68672,7 +75178,7 @@ SQLITE_PRIVATE int sqlite3VdbeSetColName(
    +   assert( var<COLNAME_N );
    +   if( p->db->mallocFailed ){
    +     assert( !zName || xDel!=SQLITE_DYNAMIC );
    +-    return SQLITE_NOMEM;
    ++    return SQLITE_NOMEM_BKPT;
    +   }
    +   assert( p->aColName!=0 );
    +   pColName = &(p->aColName[idx+var*p->nResColumn]);
    +@@ -68689,7 +75195,9 @@ SQLITE_PRIVATE int sqlite3VdbeSetColName(
    + */
    + static int vdbeCommit(sqlite3 *db, Vdbe *p){
    +   int i;
    +-  int nTrans = 0;  /* Number of databases with an active write-transaction */
    ++  int nTrans = 0;  /* Number of databases with an active write-transaction
    ++                   ** that are candidates for a two-phase commit using a
    ++                   ** master-journal */
    +   int rc = SQLITE_OK;
    +   int needXcommit = 0;
    + 
    +@@ -68717,10 +75225,29 @@ static int vdbeCommit(sqlite3 *db, Vdbe *p){
    +   for(i=0; rc==SQLITE_OK && i<db->nDb; i++){ 
    +     Btree *pBt = db->aDb[i].pBt;
    +     if( sqlite3BtreeIsInTrans(pBt) ){
    ++      /* Whether or not a database might need a master journal depends upon
    ++      ** its journal mode (among other things).  This matrix determines which
    ++      ** journal modes use a master journal and which do not */
    ++      static const u8 aMJNeeded[] = {
    ++        /* DELETE   */  1,
    ++        /* PERSIST   */ 1,
    ++        /* OFF       */ 0,
    ++        /* TRUNCATE  */ 1,
    ++        /* MEMORY    */ 0,
    ++        /* WAL       */ 0
    ++      };
    ++      Pager *pPager;   /* Pager associated with pBt */
    +       needXcommit = 1;
    +-      if( i!=1 ) nTrans++;
    +       sqlite3BtreeEnter(pBt);
    +-      rc = sqlite3PagerExclusiveLock(sqlite3BtreePager(pBt));
    ++      pPager = sqlite3BtreePager(pBt);
    ++      if( db->aDb[i].safety_level!=PAGER_SYNCHRONOUS_OFF
    ++       && aMJNeeded[sqlite3PagerGetJournalMode(pPager)]
    ++       && sqlite3PagerIsMemdb(pPager)==0
    ++      ){ 
    ++        assert( i!=1 );
    ++        nTrans++;
    ++      }
    ++      rc = sqlite3PagerExclusiveLock(pPager);
    +       sqlite3BtreeLeave(pBt);
    +     }
    +   }
    +@@ -68778,7 +75305,6 @@ static int vdbeCommit(sqlite3 *db, Vdbe *p){
    + #ifndef SQLITE_OMIT_DISKIO
    +   else{
    +     sqlite3_vfs *pVfs = db->pVfs;
    +-    int needSync = 0;
    +     char *zMaster = 0;   /* File-name for the master journal */
    +     char const *zMainFile = sqlite3BtreeGetFilename(db->aDb[0].pBt);
    +     sqlite3_file *pMaster = 0;
    +@@ -68790,7 +75316,7 @@ static int vdbeCommit(sqlite3 *db, Vdbe *p){
    +     /* Select a master journal file name */
    +     nMainFile = sqlite3Strlen30(zMainFile);
    +     zMaster = sqlite3MPrintf(db, "%s-mjXXXXXX9XXz", zMainFile);
    +-    if( zMaster==0 ) return SQLITE_NOMEM;
    ++    if( zMaster==0 ) return SQLITE_NOMEM_BKPT;
    +     do {
    +       u32 iRandom;
    +       if( retryCount ){
    +@@ -68838,9 +75364,6 @@ static int vdbeCommit(sqlite3 *db, Vdbe *p){
    +           continue;  /* Ignore TEMP and :memory: databases */
    +         }
    +         assert( zFile[0]!=0 );
    +-        if( !needSync && !sqlite3BtreeSyncDisabled(pBt) ){
    +-          needSync = 1;
    +-        }
    +         rc = sqlite3OsWrite(pMaster, zFile, sqlite3Strlen30(zFile)+1, offset);
    +         offset += sqlite3Strlen30(zFile)+1;
    +         if( rc!=SQLITE_OK ){
    +@@ -68855,8 +75378,7 @@ static int vdbeCommit(sqlite3 *db, Vdbe *p){
    +     /* Sync the master journal file. If the IOCAP_SEQUENTIAL device
    +     ** flag is set this is not required.
    +     */
    +-    if( needSync 
    +-     && 0==(sqlite3OsDeviceCharacteristics(pMaster)&SQLITE_IOCAP_SEQUENTIAL)
    ++    if( 0==(sqlite3OsDeviceCharacteristics(pMaster)&SQLITE_IOCAP_SEQUENTIAL)
    +      && SQLITE_OK!=(rc = sqlite3OsSync(pMaster, SQLITE_SYNC_NORMAL))
    +     ){
    +       sqlite3OsCloseFree(pMaster);
    +@@ -68892,7 +75414,7 @@ static int vdbeCommit(sqlite3 *db, Vdbe *p){
    +     ** doing this the directory is synced again before any individual
    +     ** transaction files are deleted.
    +     */
    +-    rc = sqlite3OsDelete(pVfs, zMaster, needSync);
    ++    rc = sqlite3OsDelete(pVfs, zMaster, 1);
    +     sqlite3DbFree(db, zMaster);
    +     zMaster = 0;
    +     if( rc ){
    +@@ -68966,60 +75488,59 @@ static void checkActiveVdbeCnt(sqlite3 *db){
    + ** If an IO error occurs, an SQLITE_IOERR_XXX error code is returned. 
    + ** Otherwise SQLITE_OK.
    + */
    +-SQLITE_PRIVATE int sqlite3VdbeCloseStatement(Vdbe *p, int eOp){
    ++static SQLITE_NOINLINE int vdbeCloseStatement(Vdbe *p, int eOp){
    +   sqlite3 *const db = p->db;
    +   int rc = SQLITE_OK;
    ++  int i;
    ++  const int iSavepoint = p->iStatement-1;
    + 
    +-  /* If p->iStatement is greater than zero, then this Vdbe opened a 
    +-  ** statement transaction that should be closed here. The only exception
    +-  ** is that an IO error may have occurred, causing an emergency rollback.
    +-  ** In this case (db->nStatement==0), and there is nothing to do.
    +-  */
    +-  if( db->nStatement && p->iStatement ){
    +-    int i;
    +-    const int iSavepoint = p->iStatement-1;
    +-
    +-    assert( eOp==SAVEPOINT_ROLLBACK || eOp==SAVEPOINT_RELEASE);
    +-    assert( db->nStatement>0 );
    +-    assert( p->iStatement==(db->nStatement+db->nSavepoint) );
    +-
    +-    for(i=0; i<db->nDb; i++){ 
    +-      int rc2 = SQLITE_OK;
    +-      Btree *pBt = db->aDb[i].pBt;
    +-      if( pBt ){
    +-        if( eOp==SAVEPOINT_ROLLBACK ){
    +-          rc2 = sqlite3BtreeSavepoint(pBt, SAVEPOINT_ROLLBACK, iSavepoint);
    +-        }
    +-        if( rc2==SQLITE_OK ){
    +-          rc2 = sqlite3BtreeSavepoint(pBt, SAVEPOINT_RELEASE, iSavepoint);
    +-        }
    +-        if( rc==SQLITE_OK ){
    +-          rc = rc2;
    +-        }
    +-      }
    +-    }
    +-    db->nStatement--;
    +-    p->iStatement = 0;
    ++  assert( eOp==SAVEPOINT_ROLLBACK || eOp==SAVEPOINT_RELEASE);
    ++  assert( db->nStatement>0 );
    ++  assert( p->iStatement==(db->nStatement+db->nSavepoint) );
    + 
    +-    if( rc==SQLITE_OK ){
    ++  for(i=0; i<db->nDb; i++){ 
    ++    int rc2 = SQLITE_OK;
    ++    Btree *pBt = db->aDb[i].pBt;
    ++    if( pBt ){
    +       if( eOp==SAVEPOINT_ROLLBACK ){
    +-        rc = sqlite3VtabSavepoint(db, SAVEPOINT_ROLLBACK, iSavepoint);
    ++        rc2 = sqlite3BtreeSavepoint(pBt, SAVEPOINT_ROLLBACK, iSavepoint);
    ++      }
    ++      if( rc2==SQLITE_OK ){
    ++        rc2 = sqlite3BtreeSavepoint(pBt, SAVEPOINT_RELEASE, iSavepoint);
    +       }
    +       if( rc==SQLITE_OK ){
    +-        rc = sqlite3VtabSavepoint(db, SAVEPOINT_RELEASE, iSavepoint);
    ++        rc = rc2;
    +       }
    +     }
    ++  }
    ++  db->nStatement--;
    ++  p->iStatement = 0;
    + 
    +-    /* If the statement transaction is being rolled back, also restore the 
    +-    ** database handles deferred constraint counter to the value it had when 
    +-    ** the statement transaction was opened.  */
    ++  if( rc==SQLITE_OK ){
    +     if( eOp==SAVEPOINT_ROLLBACK ){
    +-      db->nDeferredCons = p->nStmtDefCons;
    +-      db->nDeferredImmCons = p->nStmtDefImmCons;
    ++      rc = sqlite3VtabSavepoint(db, SAVEPOINT_ROLLBACK, iSavepoint);
    +     }
    ++    if( rc==SQLITE_OK ){
    ++      rc = sqlite3VtabSavepoint(db, SAVEPOINT_RELEASE, iSavepoint);
    ++    }
    ++  }
    ++
    ++  /* If the statement transaction is being rolled back, also restore the 
    ++  ** database handles deferred constraint counter to the value it had when 
    ++  ** the statement transaction was opened.  */
    ++  if( eOp==SAVEPOINT_ROLLBACK ){
    ++    db->nDeferredCons = p->nStmtDefCons;
    ++    db->nDeferredImmCons = p->nStmtDefImmCons;
    +   }
    +   return rc;
    + }
    ++SQLITE_PRIVATE int sqlite3VdbeCloseStatement(Vdbe *p, int eOp){
    ++  if( p->db->nStatement && p->iStatement ){
    ++    return vdbeCloseStatement(p, eOp);
    ++  }
    ++  return SQLITE_OK;
    ++}
    ++
    + 
    + /*
    + ** This function is called when a transaction opened by the database 
    +@@ -69079,14 +75600,13 @@ SQLITE_PRIVATE int sqlite3VdbeHalt(Vdbe *p){
    +   ** one, or the complete transaction if there is no statement transaction.
    +   */
    + 
    +-  if( p->db->mallocFailed ){
    +-    p->rc = SQLITE_NOMEM;
    +-  }
    +-  if( p->aOnceFlag ) memset(p->aOnceFlag, 0, p->nOnceFlag);
    +-  closeAllCursors(p);
    +   if( p->magic!=VDBE_MAGIC_RUN ){
    +     return SQLITE_OK;
    +   }
    ++  if( db->mallocFailed ){
    ++    p->rc = SQLITE_NOMEM_BKPT;
    ++  }
    ++  closeAllCursors(p);
    +   checkActiveVdbeCnt(db);
    + 
    +   /* No commit or rollback needed if the program never started or if the
    +@@ -69240,8 +75760,8 @@ SQLITE_PRIVATE int sqlite3VdbeHalt(Vdbe *p){
    +   }
    +   p->magic = VDBE_MAGIC_HALT;
    +   checkActiveVdbeCnt(db);
    +-  if( p->db->mallocFailed ){
    +-    p->rc = SQLITE_NOMEM;
    ++  if( db->mallocFailed ){
    ++    p->rc = SQLITE_NOMEM_BKPT;
    +   }
    + 
    +   /* If the auto-commit flag is set to true, then any locks that were held
    +@@ -69277,16 +75797,16 @@ SQLITE_PRIVATE int sqlite3VdbeTransferError(Vdbe *p){
    +   sqlite3 *db = p->db;
    +   int rc = p->rc;
    +   if( p->zErrMsg ){
    +-    u8 mallocFailed = db->mallocFailed;
    ++    db->bBenignMalloc++;
    +     sqlite3BeginBenignMalloc();
    +     if( db->pErr==0 ) db->pErr = sqlite3ValueNew(db);
    +     sqlite3ValueSetStr(db->pErr, -1, p->zErrMsg, SQLITE_UTF8, SQLITE_TRANSIENT);
    +     sqlite3EndBenignMalloc();
    +-    db->mallocFailed = mallocFailed;
    +-    db->errCode = rc;
    +-  }else{
    +-    sqlite3Error(db, rc);
    ++    db->bBenignMalloc--;
    ++  }else if( db->pErr ){
    ++    sqlite3ValueSetNull(db->pErr);
    +   }
    ++  db->errCode = rc;
    +   return rc;
    + }
    + 
    +@@ -69323,6 +75843,10 @@ static void vdbeInvokeSqllog(Vdbe *v){
    + ** VDBE_MAGIC_INIT.
    + */
    + SQLITE_PRIVATE int sqlite3VdbeReset(Vdbe *p){
    ++#if defined(SQLITE_DEBUG) || defined(VDBE_PROFILE)
    ++  int i;
    ++#endif
    ++
    +   sqlite3 *db;
    +   db = p->db;
    + 
    +@@ -69340,8 +75864,6 @@ SQLITE_PRIVATE int sqlite3VdbeReset(Vdbe *p){
    +   if( p->pc>=0 ){
    +     vdbeInvokeSqllog(p);
    +     sqlite3VdbeTransferError(p);
    +-    sqlite3DbFree(db, p->zErrMsg);
    +-    p->zErrMsg = 0;
    +     if( p->runOnlyOnce ) p->expired = 1;
    +   }else if( p->rc && p->expired ){
    +     /* The expired flag was set on the VDBE before the first call
    +@@ -69349,13 +75871,21 @@ SQLITE_PRIVATE int sqlite3VdbeReset(Vdbe *p){
    +     ** called), set the database error in this case as well.
    +     */
    +     sqlite3ErrorWithMsg(db, p->rc, p->zErrMsg ? "%s" : 0, p->zErrMsg);
    +-    sqlite3DbFree(db, p->zErrMsg);
    +-    p->zErrMsg = 0;
    +   }
    + 
    +-  /* Reclaim all memory used by the VDBE
    ++  /* Reset register contents and reclaim error message memory.
    +   */
    +-  Cleanup(p);
    ++#ifdef SQLITE_DEBUG
    ++  /* Execute assert() statements to ensure that the Vdbe.apCsr[] and 
    ++  ** Vdbe.aMem[] arrays have already been cleaned up.  */
    ++  if( p->apCsr ) for(i=0; i<p->nCursor; i++) assert( p->apCsr[i]==0 );
    ++  if( p->aMem ){
    ++    for(i=0; i<p->nMem; i++) assert( p->aMem[i].flags==MEM_Undefined );
    ++  }
    ++#endif
    ++  sqlite3DbFree(db, p->zErrMsg);
    ++  p->zErrMsg = 0;
    ++  p->pResultSet = 0;
    + 
    +   /* Save profiling information from this VDBE run.
    +   */
    +@@ -69363,7 +75893,6 @@ SQLITE_PRIVATE int sqlite3VdbeReset(Vdbe *p){
    +   {
    +     FILE *out = fopen("vdbe_profile.out", "a");
    +     if( out ){
    +-      int i;
    +       fprintf(out, "---- ");
    +       for(i=0; i<p->nOp; i++){
    +         fprintf(out, "%02x", p->aOp[i].opcode);
    +@@ -69393,8 +75922,7 @@ SQLITE_PRIVATE int sqlite3VdbeReset(Vdbe *p){
    +     }
    +   }
    + #endif
    +-  p->iCurrentTime = 0;
    +-  p->magic = VDBE_MAGIC_INIT;
    ++  p->magic = VDBE_MAGIC_RESET;
    +   return p->rc & db->errMask;
    + }
    +  
    +@@ -69428,21 +75956,22 @@ SQLITE_PRIVATE int sqlite3VdbeFinalize(Vdbe *p){
    + **    * the corresponding bit in argument mask is clear (where the first
    + **      function parameter corresponds to bit 0 etc.).
    + */
    +-SQLITE_PRIVATE void sqlite3VdbeDeleteAuxData(Vdbe *pVdbe, int iOp, int mask){
    +-  AuxData **pp = &pVdbe->pAuxData;
    ++SQLITE_PRIVATE void sqlite3VdbeDeleteAuxData(sqlite3 *db, AuxData **pp, int iOp, int mask){
    +   while( *pp ){
    +     AuxData *pAux = *pp;
    +     if( (iOp<0)
    +-     || (pAux->iOp==iOp && (pAux->iArg>31 || !(mask & MASKBIT32(pAux->iArg))))
    ++     || (pAux->iAuxOp==iOp
    ++          && pAux->iAuxArg>=0
    ++          && (pAux->iAuxArg>31 || !(mask & MASKBIT32(pAux->iAuxArg))))
    +     ){
    +-      testcase( pAux->iArg==31 );
    +-      if( pAux->xDelete ){
    +-        pAux->xDelete(pAux->pAux);
    ++      testcase( pAux->iAuxArg==31 );
    ++      if( pAux->xDeleteAux ){
    ++        pAux->xDeleteAux(pAux->pAux);
    +       }
    +-      *pp = pAux->pNext;
    +-      sqlite3DbFree(pVdbe->db, pAux);
    ++      *pp = pAux->pNextAux;
    ++      sqlite3DbFree(db, pAux);
    +     }else{
    +-      pp= &pAux->pNext;
    ++      pp= &pAux->pNextAux;
    +     }
    +   }
    + }
    +@@ -69457,25 +75986,29 @@ SQLITE_PRIVATE void sqlite3VdbeDeleteAuxData(Vdbe *pVdbe, int iOp, int mask){
    + */
    + SQLITE_PRIVATE void sqlite3VdbeClearObject(sqlite3 *db, Vdbe *p){
    +   SubProgram *pSub, *pNext;
    +-  int i;
    +   assert( p->db==0 || p->db==db );
    +-  releaseMemArray(p->aVar, p->nVar);
    +   releaseMemArray(p->aColName, p->nResColumn*COLNAME_N);
    +   for(pSub=p->pProgram; pSub; pSub=pNext){
    +     pNext = pSub->pNext;
    +     vdbeFreeOpArray(db, pSub->aOp, pSub->nOp);
    +     sqlite3DbFree(db, pSub);
    +   }
    +-  for(i=p->nzVar-1; i>=0; i--) sqlite3DbFree(db, p->azVar[i]);
    ++  if( p->magic!=VDBE_MAGIC_INIT ){
    ++    releaseMemArray(p->aVar, p->nVar);
    ++    sqlite3DbFree(db, p->pVList);
    ++    sqlite3DbFree(db, p->pFree);
    ++  }
    +   vdbeFreeOpArray(db, p->aOp, p->nOp);
    +   sqlite3DbFree(db, p->aColName);
    +   sqlite3DbFree(db, p->zSql);
    +-  sqlite3DbFree(db, p->pFree);
    + #ifdef SQLITE_ENABLE_STMT_SCANSTATUS
    +-  for(i=0; i<p->nScan; i++){
    +-    sqlite3DbFree(db, p->aScan[i].zName);
    ++  {
    ++    int i;
    ++    for(i=0; i<p->nScan; i++){
    ++      sqlite3DbFree(db, p->aScan[i].zName);
    ++    }
    ++    sqlite3DbFree(db, p->aScan);
    +   }
    +-  sqlite3DbFree(db, p->aScan);
    + #endif
    + }
    + 
    +@@ -69485,7 +76018,7 @@ SQLITE_PRIVATE void sqlite3VdbeClearObject(sqlite3 *db, Vdbe *p){
    + SQLITE_PRIVATE void sqlite3VdbeDelete(Vdbe *p){
    +   sqlite3 *db;
    + 
    +-  if( NEVER(p==0) ) return;
    ++  assert( p!=0 );
    +   db = p->db;
    +   assert( sqlite3_mutex_held(db->mutex) );
    +   sqlite3VdbeClearObject(db, p);
    +@@ -69500,7 +76033,7 @@ SQLITE_PRIVATE void sqlite3VdbeDelete(Vdbe *p){
    +   }
    +   p->magic = VDBE_MAGIC_DEAD;
    +   p->db = 0;
    +-  sqlite3DbFree(db, p);
    ++  sqlite3DbFreeNN(db, p);
    + }
    + 
    + /*
    +@@ -69515,7 +76048,8 @@ static int SQLITE_NOINLINE handleDeferredMoveto(VdbeCursor *p){
    + #endif
    +   assert( p->deferredMoveto );
    +   assert( p->isTable );
    +-  rc = sqlite3BtreeMovetoUnpacked(p->pCursor, 0, p->movetoTarget, 0, &res);
    ++  assert( p->eCurType==CURTYPE_BTREE );
    ++  rc = sqlite3BtreeMovetoUnpacked(p->uc.pCursor, 0, p->movetoTarget, 0, &res);
    +   if( rc ) return rc;
    +   if( res!=0 ) return SQLITE_CORRUPT_BKPT;
    + #ifdef SQLITE_TEST
    +@@ -69535,9 +76069,10 @@ static int SQLITE_NOINLINE handleDeferredMoveto(VdbeCursor *p){
    + */
    + static int SQLITE_NOINLINE handleMovedCursor(VdbeCursor *p){
    +   int isDifferentRow, rc;
    +-  assert( p->pCursor!=0 );
    +-  assert( sqlite3BtreeCursorHasMoved(p->pCursor) );
    +-  rc = sqlite3BtreeCursorRestore(p->pCursor, &isDifferentRow);
    ++  assert( p->eCurType==CURTYPE_BTREE );
    ++  assert( p->uc.pCursor!=0 );
    ++  assert( sqlite3BtreeCursorHasMoved(p->uc.pCursor) );
    ++  rc = sqlite3BtreeCursorRestore(p->uc.pCursor, &isDifferentRow);
    +   p->cacheStatus = CACHE_STALE;
    +   if( isDifferentRow ) p->nullRow = 1;
    +   return rc;
    +@@ -69548,7 +76083,8 @@ static int SQLITE_NOINLINE handleMovedCursor(VdbeCursor *p){
    + ** if need be.  Return any I/O error from the restore operation.
    + */
    + SQLITE_PRIVATE int sqlite3VdbeCursorRestore(VdbeCursor *p){
    +-  if( sqlite3BtreeCursorHasMoved(p->pCursor) ){
    ++  assert( p->eCurType==CURTYPE_BTREE );
    ++  if( sqlite3BtreeCursorHasMoved(p->uc.pCursor) ){
    +     return handleMovedCursor(p);
    +   }
    +   return SQLITE_OK;
    +@@ -69567,11 +76103,19 @@ SQLITE_PRIVATE int sqlite3VdbeCursorRestore(VdbeCursor *p){
    + ** If the cursor is already pointing to the correct row and that row has
    + ** not been deleted out from under the cursor, then this routine is a no-op.
    + */
    +-SQLITE_PRIVATE int sqlite3VdbeCursorMoveto(VdbeCursor *p){
    ++SQLITE_PRIVATE int sqlite3VdbeCursorMoveto(VdbeCursor **pp, int *piCol){
    ++  VdbeCursor *p = *pp;
    ++  assert( p->eCurType==CURTYPE_BTREE || p->eCurType==CURTYPE_PSEUDO );
    +   if( p->deferredMoveto ){
    ++    int iMap;
    ++    if( p->aAltMap && (iMap = p->aAltMap[1+*piCol])>0 ){
    ++      *pp = p->pAltCursor;
    ++      *piCol = iMap - 1;
    ++      return SQLITE_OK;
    ++    }
    +     return handleDeferredMoveto(p);
    +   }
    +-  if( p->pCursor && sqlite3BtreeCursorHasMoved(p->pCursor) ){
    ++  if( sqlite3BtreeCursorHasMoved(p->uc.pCursor) ){
    +     return handleMovedCursor(p);
    +   }
    +   return SQLITE_OK;
    +@@ -69622,11 +76166,13 @@ SQLITE_PRIVATE int sqlite3VdbeCursorMoveto(VdbeCursor *p){
    + /*
    + ** Return the serial-type for the value stored in pMem.
    + */
    +-SQLITE_PRIVATE u32 sqlite3VdbeSerialType(Mem *pMem, int file_format){
    ++SQLITE_PRIVATE u32 sqlite3VdbeSerialType(Mem *pMem, int file_format, u32 *pLen){
    +   int flags = pMem->flags;
    +   u32 n;
    + 
    ++  assert( pLen!=0 );
    +   if( flags&MEM_Null ){
    ++    *pLen = 0;
    +     return 0;
    +   }
    +   if( flags&MEM_Int ){
    +@@ -69640,15 +76186,23 @@ SQLITE_PRIVATE u32 sqlite3VdbeSerialType(Mem *pMem, int file_format){
    +       u = i;
    +     }
    +     if( u<=127 ){
    +-      return ((i&1)==i && file_format>=4) ? 8+(u32)u : 1;
    ++      if( (i&1)==i && file_format>=4 ){
    ++        *pLen = 0;
    ++        return 8+(u32)u;
    ++      }else{
    ++        *pLen = 1;
    ++        return 1;
    ++      }
    +     }
    +-    if( u<=32767 ) return 2;
    +-    if( u<=8388607 ) return 3;
    +-    if( u<=2147483647 ) return 4;
    +-    if( u<=MAX_6BYTE ) return 5;
    ++    if( u<=32767 ){ *pLen = 2; return 2; }
    ++    if( u<=8388607 ){ *pLen = 3; return 3; }
    ++    if( u<=2147483647 ){ *pLen = 4; return 4; }
    ++    if( u<=MAX_6BYTE ){ *pLen = 6; return 5; }
    ++    *pLen = 8;
    +     return 6;
    +   }
    +   if( flags&MEM_Real ){
    ++    *pLen = 8;
    +     return 7;
    +   }
    +   assert( pMem->db->mallocFailed || flags&(MEM_Str|MEM_Blob) );
    +@@ -69657,26 +76211,46 @@ SQLITE_PRIVATE u32 sqlite3VdbeSerialType(Mem *pMem, int file_format){
    +   if( flags & MEM_Zero ){
    +     n += pMem->u.nZero;
    +   }
    ++  *pLen = n;
    +   return ((n*2) + 12 + ((flags&MEM_Str)!=0));
    + }
    + 
    + /*
    +-** The sizes for serial types less than 12
    ++** The sizes for serial types less than 128
    + */
    + static const u8 sqlite3SmallTypeSizes[] = {
    +-  0, 1, 2, 3, 4, 6, 8, 8, 0, 0, 0, 0
    ++        /*  0   1   2   3   4   5   6   7   8   9 */   
    ++/*   0 */   0,  1,  2,  3,  4,  6,  8,  8,  0,  0,
    ++/*  10 */   0,  0,  0,  0,  1,  1,  2,  2,  3,  3,
    ++/*  20 */   4,  4,  5,  5,  6,  6,  7,  7,  8,  8,
    ++/*  30 */   9,  9, 10, 10, 11, 11, 12, 12, 13, 13,
    ++/*  40 */  14, 14, 15, 15, 16, 16, 17, 17, 18, 18,
    ++/*  50 */  19, 19, 20, 20, 21, 21, 22, 22, 23, 23,
    ++/*  60 */  24, 24, 25, 25, 26, 26, 27, 27, 28, 28,
    ++/*  70 */  29, 29, 30, 30, 31, 31, 32, 32, 33, 33,
    ++/*  80 */  34, 34, 35, 35, 36, 36, 37, 37, 38, 38,
    ++/*  90 */  39, 39, 40, 40, 41, 41, 42, 42, 43, 43,
    ++/* 100 */  44, 44, 45, 45, 46, 46, 47, 47, 48, 48,
    ++/* 110 */  49, 49, 50, 50, 51, 51, 52, 52, 53, 53,
    ++/* 120 */  54, 54, 55, 55, 56, 56, 57, 57
    + };
    + 
    + /*
    + ** Return the length of the data corresponding to the supplied serial-type.
    + */
    + SQLITE_PRIVATE u32 sqlite3VdbeSerialTypeLen(u32 serial_type){
    +-  if( serial_type>=12 ){
    ++  if( serial_type>=128 ){
    +     return (serial_type-12)/2;
    +   }else{
    ++    assert( serial_type<12 
    ++            || sqlite3SmallTypeSizes[serial_type]==(serial_type - 12)/2 );
    +     return sqlite3SmallTypeSizes[serial_type];
    +   }
    + }
    ++SQLITE_PRIVATE u8 sqlite3VdbeOneByteSerialTypeLen(u8 serial_type){
    ++  assert( serial_type<128 );
    ++  return sqlite3SmallTypeSizes[serial_type];  
    ++}
    + 
    + /*
    + ** If we are on an architecture with mixed-endian floating 
    +@@ -69772,7 +76346,7 @@ SQLITE_PRIVATE u32 sqlite3VdbeSerialPut(u8 *buf, Mem *pMem, u32 serial_type){
    +     assert( pMem->n + ((pMem->flags & MEM_Zero)?pMem->u.nZero:0)
    +              == (int)sqlite3VdbeSerialTypeLen(serial_type) );
    +     len = pMem->n;
    +-    memcpy(buf, pMem->z, len);
    ++    if( len>0 ) memcpy(buf, pMem->z, len);
    +     return len;
    +   }
    + 
    +@@ -69840,7 +76414,13 @@ SQLITE_PRIVATE u32 sqlite3VdbeSerialGet(
    +   Mem *pMem                     /* Memory cell to write value into */
    + ){
    +   switch( serial_type ){
    +-    case 10:   /* Reserved for future use */
    ++    case 10: { /* Internal use only: NULL with virtual table
    ++               ** UPDATE no-change flag set */
    ++      pMem->flags = MEM_Null|MEM_Zero;
    ++      pMem->n = 0;
    ++      pMem->u.nZero = 0;
    ++      break;
    ++    }
    +     case 11:   /* Reserved for future use */
    +     case 0: {  /* Null */
    +       /* EVIDENCE-OF: R-24078-09375 Value is a NULL. */
    +@@ -69875,6 +76455,10 @@ SQLITE_PRIVATE u32 sqlite3VdbeSerialGet(
    +       /* EVIDENCE-OF: R-01849-26079 Value is a big-endian 32-bit
    +       ** twos-complement integer. */
    +       pMem->u.i = FOUR_BYTE_INT(buf);
    ++#ifdef __HP_cc 
    ++      /* Work around a sign-extension bug in the HP compiler for HP/UX */
    ++      if( buf[0]&0x80 ) pMem->u.i |= 0xffffffff80000000LL;
    ++#endif
    +       pMem->flags = MEM_Int;
    +       testcase( pMem->u.i<0 );
    +       return 4;
    +@@ -69930,34 +76514,17 @@ SQLITE_PRIVATE u32 sqlite3VdbeSerialGet(
    + ** If an OOM error occurs, NULL is returned.
    + */
    + SQLITE_PRIVATE UnpackedRecord *sqlite3VdbeAllocUnpackedRecord(
    +-  KeyInfo *pKeyInfo,              /* Description of the record */
    +-  char *pSpace,                   /* Unaligned space available */
    +-  int szSpace,                    /* Size of pSpace[] in bytes */
    +-  char **ppFree                   /* OUT: Caller should free this pointer */
    ++  KeyInfo *pKeyInfo               /* Description of the record */
    + ){
    +   UnpackedRecord *p;              /* Unpacked record to return */
    +-  int nOff;                       /* Increment pSpace by nOff to align it */
    +   int nByte;                      /* Number of bytes required for *p */
    +-
    +-  /* We want to shift the pointer pSpace up such that it is 8-byte aligned.
    +-  ** Thus, we need to calculate a value, nOff, between 0 and 7, to shift 
    +-  ** it by.  If pSpace is already 8-byte aligned, nOff should be zero.
    +-  */
    +-  nOff = (8 - (SQLITE_PTR_TO_INT(pSpace) & 7)) & 7;
    +-  nByte = ROUND8(sizeof(UnpackedRecord)) + sizeof(Mem)*(pKeyInfo->nField+1);
    +-  if( nByte>szSpace+nOff ){
    +-    p = (UnpackedRecord *)sqlite3DbMallocRaw(pKeyInfo->db, nByte);
    +-    *ppFree = (char *)p;
    +-    if( !p ) return 0;
    +-  }else{
    +-    p = (UnpackedRecord*)&pSpace[nOff];
    +-    *ppFree = 0;
    +-  }
    +-
    ++  nByte = ROUND8(sizeof(UnpackedRecord)) + sizeof(Mem)*(pKeyInfo->nKeyField+1);
    ++  p = (UnpackedRecord *)sqlite3DbMallocRaw(pKeyInfo->db, nByte);
    ++  if( !p ) return 0;
    +   p->aMem = (Mem*)&((char*)p)[ROUND8(sizeof(UnpackedRecord))];
    +   assert( pKeyInfo->aSortOrder!=0 );
    +   p->pKeyInfo = pKeyInfo;
    +-  p->nField = pKeyInfo->nField + 1;
    ++  p->nField = pKeyInfo->nKeyField + 1;
    +   return p;
    + }
    + 
    +@@ -69992,15 +76559,16 @@ SQLITE_PRIVATE void sqlite3VdbeRecordUnpack(
    +     pMem->db = pKeyInfo->db;
    +     /* pMem->flags = 0; // sqlite3VdbeSerialGet() will set this for us */
    +     pMem->szMalloc = 0;
    ++    pMem->z = 0;
    +     d += sqlite3VdbeSerialGet(&aKey[d], serial_type, pMem);
    +     pMem++;
    +     if( (++u)>=p->nField ) break;
    +   }
    +-  assert( u<=pKeyInfo->nField + 1 );
    ++  assert( u<=pKeyInfo->nKeyField + 1 );
    +   p->nField = u;
    + }
    + 
    +-#if SQLITE_DEBUG
    ++#ifdef SQLITE_DEBUG
    + /*
    + ** This function compares two index or table record keys in the same way
    + ** as the sqlite3VdbeRecordCompare() routine. Unlike VdbeRecordCompare(),
    +@@ -70045,9 +76613,9 @@ static int vdbeRecordCompareDebug(
    +   idx1 = getVarint32(aKey1, szHdr1);
    +   if( szHdr1>98307 ) return SQLITE_CORRUPT;
    +   d1 = szHdr1;
    +-  assert( pKeyInfo->nField+pKeyInfo->nXField>=pPKey2->nField || CORRUPT_DB );
    ++  assert( pKeyInfo->nAllField>=pPKey2->nField || CORRUPT_DB );
    +   assert( pKeyInfo->aSortOrder!=0 );
    +-  assert( pKeyInfo->nField>0 );
    ++  assert( pKeyInfo->nKeyField>0 );
    +   assert( idx1<=szHdr1 || CORRUPT_DB );
    +   do{
    +     u32 serial_type1;
    +@@ -70105,16 +76673,16 @@ debugCompareEnd:
    + }
    + #endif
    + 
    +-#if SQLITE_DEBUG
    ++#ifdef SQLITE_DEBUG
    + /*
    + ** Count the number of fields (a.k.a. columns) in the record given by
    + ** pKey,nKey.  The verify that this count is less than or equal to the
    +-** limit given by pKeyInfo->nField + pKeyInfo->nXField.
    ++** limit given by pKeyInfo->nAllField.
    + **
    + ** If this constraint is not satisfied, it means that the high-speed
    + ** vdbeRecordCompareInt() and vdbeRecordCompareString() routines will
    + ** not work correctly.  If this assert() ever fires, it probably means
    +-** that the KeyInfo.nField or KeyInfo.nXField values were computed
    ++** that the KeyInfo.nKeyField or KeyInfo.nAllField values were computed
    + ** incorrectly.
    + */
    + static void vdbeAssertFieldCountWithinLimits(
    +@@ -70135,7 +76703,7 @@ static void vdbeAssertFieldCountWithinLimits(
    +     idx += getVarint32(aKey+idx, notUsed);
    +     nField++;
    +   }
    +-  assert( nField <= pKeyInfo->nField+pKeyInfo->nXField );
    ++  assert( nField <= pKeyInfo->nAllField );
    + }
    + #else
    + # define vdbeAssertFieldCountWithinLimits(A,B,C)
    +@@ -70160,7 +76728,6 @@ static int vdbeCompareMemString(
    +   }else{
    +     int rc;
    +     const void *v1, *v2;
    +-    int n1, n2;
    +     Mem c1;
    +     Mem c2;
    +     sqlite3VdbeMemInit(&c1, pMem1->db, MEM_Null);
    +@@ -70168,28 +76735,92 @@ static int vdbeCompareMemString(
    +     sqlite3VdbeMemShallowCopy(&c1, pMem1, MEM_Ephem);
    +     sqlite3VdbeMemShallowCopy(&c2, pMem2, MEM_Ephem);
    +     v1 = sqlite3ValueText((sqlite3_value*)&c1, pColl->enc);
    +-    n1 = v1==0 ? 0 : c1.n;
    +     v2 = sqlite3ValueText((sqlite3_value*)&c2, pColl->enc);
    +-    n2 = v2==0 ? 0 : c2.n;
    +-    rc = pColl->xCmp(pColl->pUser, n1, v1, n2, v2);
    ++    if( (v1==0 || v2==0) ){
    ++      if( prcErr ) *prcErr = SQLITE_NOMEM_BKPT;
    ++      rc = 0;
    ++    }else{
    ++      rc = pColl->xCmp(pColl->pUser, c1.n, v1, c2.n, v2);
    ++    }
    +     sqlite3VdbeMemRelease(&c1);
    +     sqlite3VdbeMemRelease(&c2);
    +-    if( (v1==0 || v2==0) && prcErr ) *prcErr = SQLITE_NOMEM;
    +     return rc;
    +   }
    + }
    + 
    ++/*
    ++** The input pBlob is guaranteed to be a Blob that is not marked
    ++** with MEM_Zero.  Return true if it could be a zero-blob.
    ++*/
    ++static int isAllZero(const char *z, int n){
    ++  int i;
    ++  for(i=0; i<n; i++){
    ++    if( z[i] ) return 0;
    ++  }
    ++  return 1;
    ++}
    ++
    + /*
    + ** Compare two blobs.  Return negative, zero, or positive if the first
    + ** is less than, equal to, or greater than the second, respectively.
    + ** If one blob is a prefix of the other, then the shorter is the lessor.
    + */
    + static SQLITE_NOINLINE int sqlite3BlobCompare(const Mem *pB1, const Mem *pB2){
    +-  int c = memcmp(pB1->z, pB2->z, pB1->n>pB2->n ? pB2->n : pB1->n);
    ++  int c;
    ++  int n1 = pB1->n;
    ++  int n2 = pB2->n;
    ++
    ++  /* It is possible to have a Blob value that has some non-zero content
    ++  ** followed by zero content.  But that only comes up for Blobs formed
    ++  ** by the OP_MakeRecord opcode, and such Blobs never get passed into
    ++  ** sqlite3MemCompare(). */
    ++  assert( (pB1->flags & MEM_Zero)==0 || n1==0 );
    ++  assert( (pB2->flags & MEM_Zero)==0 || n2==0 );
    ++
    ++  if( (pB1->flags|pB2->flags) & MEM_Zero ){
    ++    if( pB1->flags & pB2->flags & MEM_Zero ){
    ++      return pB1->u.nZero - pB2->u.nZero;
    ++    }else if( pB1->flags & MEM_Zero ){
    ++      if( !isAllZero(pB2->z, pB2->n) ) return -1;
    ++      return pB1->u.nZero - n2;
    ++    }else{
    ++      if( !isAllZero(pB1->z, pB1->n) ) return +1;
    ++      return n1 - pB2->u.nZero;
    ++    }
    ++  }
    ++  c = memcmp(pB1->z, pB2->z, n1>n2 ? n2 : n1);
    +   if( c ) return c;
    +-  return pB1->n - pB2->n;
    ++  return n1 - n2;
    + }
    + 
    ++/*
    ++** Do a comparison between a 64-bit signed integer and a 64-bit floating-point
    ++** number.  Return negative, zero, or positive if the first (i64) is less than,
    ++** equal to, or greater than the second (double).
    ++*/
    ++static int sqlite3IntFloatCompare(i64 i, double r){
    ++  if( sizeof(LONGDOUBLE_TYPE)>8 ){
    ++    LONGDOUBLE_TYPE x = (LONGDOUBLE_TYPE)i;
    ++    if( x<r ) return -1;
    ++    if( x>r ) return +1;
    ++    return 0;
    ++  }else{
    ++    i64 y;
    ++    double s;
    ++    if( r<-9223372036854775808.0 ) return +1;
    ++    if( r>9223372036854775807.0 ) return -1;
    ++    y = (i64)r;
    ++    if( i<y ) return -1;
    ++    if( i>y ){
    ++      if( y==SMALLEST_INT64 && r>0.0 ) return -1;
    ++      return +1;
    ++    }
    ++    s = (double)i;
    ++    if( s<r ) return -1;
    ++    if( s>r ) return +1;
    ++    return 0;
    ++  }
    ++}
    + 
    + /*
    + ** Compare the values contained by the two memory cells, returning
    +@@ -70216,34 +76847,34 @@ SQLITE_PRIVATE int sqlite3MemCompare(const Mem *pMem1, const Mem *pMem2, const C
    +     return (f2&MEM_Null) - (f1&MEM_Null);
    +   }
    + 
    +-  /* If one value is a number and the other is not, the number is less.
    +-  ** If both are numbers, compare as reals if one is a real, or as integers
    +-  ** if both values are integers.
    ++  /* At least one of the two values is a number
    +   */
    +   if( combined_flags&(MEM_Int|MEM_Real) ){
    +-    double r1, r2;
    +     if( (f1 & f2 & MEM_Int)!=0 ){
    +       if( pMem1->u.i < pMem2->u.i ) return -1;
    +-      if( pMem1->u.i > pMem2->u.i ) return 1;
    ++      if( pMem1->u.i > pMem2->u.i ) return +1;
    +       return 0;
    +     }
    +-    if( (f1&MEM_Real)!=0 ){
    +-      r1 = pMem1->u.r;
    +-    }else if( (f1&MEM_Int)!=0 ){
    +-      r1 = (double)pMem1->u.i;
    +-    }else{
    +-      return 1;
    ++    if( (f1 & f2 & MEM_Real)!=0 ){
    ++      if( pMem1->u.r < pMem2->u.r ) return -1;
    ++      if( pMem1->u.r > pMem2->u.r ) return +1;
    ++      return 0;
    +     }
    +-    if( (f2&MEM_Real)!=0 ){
    +-      r2 = pMem2->u.r;
    +-    }else if( (f2&MEM_Int)!=0 ){
    +-      r2 = (double)pMem2->u.i;
    +-    }else{
    +-      return -1;
    ++    if( (f1&MEM_Int)!=0 ){
    ++      if( (f2&MEM_Real)!=0 ){
    ++        return sqlite3IntFloatCompare(pMem1->u.i, pMem2->u.r);
    ++      }else{
    ++        return -1;
    ++      }
    +     }
    +-    if( r1<r2 ) return -1;
    +-    if( r1>r2 ) return 1;
    +-    return 0;
    ++    if( (f1&MEM_Real)!=0 ){
    ++      if( (f2&MEM_Int)!=0 ){
    ++        return -sqlite3IntFloatCompare(pMem2->u.i, pMem1->u.r);
    ++      }else{
    ++        return -1;
    ++      }
    ++    }
    ++    return +1;
    +   }
    + 
    +   /* If one value is a string and the other is a blob, the string is less.
    +@@ -70257,7 +76888,7 @@ SQLITE_PRIVATE int sqlite3MemCompare(const Mem *pMem1, const Mem *pMem2, const C
    +       return -1;
    +     }
    + 
    +-    assert( pMem1->enc==pMem2->enc );
    ++    assert( pMem1->enc==pMem2->enc || pMem1->db->mallocFailed );
    +     assert( pMem1->enc==SQLITE_UTF8 || 
    +             pMem1->enc==SQLITE_UTF16LE || pMem1->enc==SQLITE_UTF16BE );
    + 
    +@@ -70377,10 +77008,10 @@ SQLITE_PRIVATE int sqlite3VdbeRecordCompareWithSkip(
    +   }
    + 
    +   VVA_ONLY( mem1.szMalloc = 0; ) /* Only needed by assert() statements */
    +-  assert( pPKey2->pKeyInfo->nField+pPKey2->pKeyInfo->nXField>=pPKey2->nField 
    ++  assert( pPKey2->pKeyInfo->nAllField>=pPKey2->nField 
    +        || CORRUPT_DB );
    +   assert( pPKey2->pKeyInfo->aSortOrder!=0 );
    +-  assert( pPKey2->pKeyInfo->nField>0 );
    ++  assert( pPKey2->pKeyInfo->nKeyField>0 );
    +   assert( idx1<=szHdr1 || CORRUPT_DB );
    +   do{
    +     u32 serial_type;
    +@@ -70394,13 +77025,8 @@ SQLITE_PRIVATE int sqlite3VdbeRecordCompareWithSkip(
    +       }else if( serial_type==0 ){
    +         rc = -1;
    +       }else if( serial_type==7 ){
    +-        double rhs = (double)pRhs->u.i;
    +         sqlite3VdbeSerialGet(&aKey1[d1], serial_type, &mem1);
    +-        if( mem1.u.r<rhs ){
    +-          rc = -1;
    +-        }else if( mem1.u.r>rhs ){
    +-          rc = +1;
    +-        }
    ++        rc = -sqlite3IntFloatCompare(pRhs->u.i, mem1.u.r);
    +       }else{
    +         i64 lhs = vdbeRecordDecodeInt(serial_type, &aKey1[d1]);
    +         i64 rhs = pRhs->u.i;
    +@@ -70424,18 +77050,15 @@ SQLITE_PRIVATE int sqlite3VdbeRecordCompareWithSkip(
    +       }else if( serial_type==0 ){
    +         rc = -1;
    +       }else{
    +-        double rhs = pRhs->u.r;
    +-        double lhs;
    +         sqlite3VdbeSerialGet(&aKey1[d1], serial_type, &mem1);
    +         if( serial_type==7 ){
    +-          lhs = mem1.u.r;
    ++          if( mem1.u.r<pRhs->u.r ){
    ++            rc = -1;
    ++          }else if( mem1.u.r>pRhs->u.r ){
    ++            rc = +1;
    ++          }
    +         }else{
    +-          lhs = (double)mem1.u.i;
    +-        }
    +-        if( lhs<rhs ){
    +-          rc = -1;
    +-        }else if( lhs>rhs ){
    +-          rc = +1;
    ++          rc = sqlite3IntFloatCompare(mem1.u.i, pRhs->u.r);
    +         }
    +       }
    +     }
    +@@ -70473,6 +77096,7 @@ SQLITE_PRIVATE int sqlite3VdbeRecordCompareWithSkip(
    + 
    +     /* RHS is a blob */
    +     else if( pRhs->flags & MEM_Blob ){
    ++      assert( (pRhs->flags & MEM_Zero)==0 || pRhs->n==0 );
    +       getVarint32(&aKey1[idx1], serial_type);
    +       testcase( serial_type==12 );
    +       if( serial_type<12 || (serial_type & 0x01) ){
    +@@ -70484,6 +77108,12 @@ SQLITE_PRIVATE int sqlite3VdbeRecordCompareWithSkip(
    +         if( (d1+nStr) > (unsigned)nKey1 ){
    +           pPKey2->errCode = (u8)SQLITE_CORRUPT_BKPT;
    +           return 0;                /* Corruption */
    ++        }else if( pRhs->flags & MEM_Zero ){
    ++          if( !isAllZero((const char*)&aKey1[d1],nStr) ){
    ++            rc = 1;
    ++          }else{
    ++            rc = nStr - pRhs->u.nZero;
    ++          }
    +         }else{
    +           int nCmp = MIN(nStr, pRhs->n);
    +           rc = memcmp(&aKey1[d1], pRhs->z, nCmp);
    +@@ -70525,6 +77155,7 @@ SQLITE_PRIVATE int sqlite3VdbeRecordCompareWithSkip(
    +        || vdbeRecordCompareDebug(nKey1, pKey1, pPKey2, pPKey2->default_rc) 
    +        || pKeyInfo->db->mallocFailed
    +   );
    ++  pPKey2->eqSeen = 1;
    +   return pPKey2->default_rc;
    + }
    + SQLITE_PRIVATE int sqlite3VdbeRecordCompare(
    +@@ -70553,7 +77184,7 @@ static int vdbeRecordCompareInt(
    +   int res;
    +   u32 y;
    +   u64 x;
    +-  i64 v = pPKey2->aMem[0].u.i;
    ++  i64 v;
    +   i64 lhs;
    + 
    +   vdbeAssertFieldCountWithinLimits(nKey1, pKey1, pPKey2->pKeyInfo);
    +@@ -70612,6 +77243,7 @@ static int vdbeRecordCompareInt(
    +       return sqlite3VdbeRecordCompare(nKey1, pKey1, pPKey2);
    +   }
    + 
    ++  v = pPKey2->aMem[0].u.i;
    +   if( v>lhs ){
    +     res = pPKey2->r1;
    +   }else if( v<lhs ){
    +@@ -70624,6 +77256,7 @@ static int vdbeRecordCompareInt(
    +     /* The first fields of the two keys are equal and there are no trailing
    +     ** fields. Return pPKey2->default_rc in this case. */
    +     res = pPKey2->default_rc;
    ++    pPKey2->eqSeen = 1;
    +   }
    + 
    +   assert( vdbeRecordCompareDebug(nKey1, pKey1, pPKey2, res) );
    +@@ -70644,6 +77277,7 @@ static int vdbeRecordCompareString(
    +   int serial_type;
    +   int res;
    + 
    ++  assert( pPKey2->aMem[0].flags & MEM_Str );
    +   vdbeAssertFieldCountWithinLimits(nKey1, pKey1, pPKey2->pKeyInfo);
    +   getVarint32(&aKey1[1], serial_type);
    +   if( serial_type<12 ){
    +@@ -70670,6 +77304,7 @@ static int vdbeRecordCompareString(
    +           res = sqlite3VdbeRecordCompareWithSkip(nKey1, pKey1, pPKey2, 1);
    +         }else{
    +           res = pPKey2->default_rc;
    ++          pPKey2->eqSeen = 1;
    +         }
    +       }else if( res>0 ){
    +         res = pPKey2->r2;
    +@@ -70709,7 +77344,7 @@ SQLITE_PRIVATE RecordCompare sqlite3VdbeFindCompare(UnpackedRecord *p){
    +   ** The easiest way to enforce this limit is to consider only records with
    +   ** 13 fields or less. If the first field is an integer, the maximum legal
    +   ** header size is (12*5 + 1 + 1) bytes.  */
    +-  if( (p->pKeyInfo->nField + p->pKeyInfo->nXField)<=13 ){
    ++  if( p->pKeyInfo->nAllField<=13 ){
    +     int flags = p->aMem[0].flags;
    +     if( p->pKeyInfo->aSortOrder[0] ){
    +       p->r1 = 1;
    +@@ -70755,13 +77390,12 @@ SQLITE_PRIVATE int sqlite3VdbeIdxRowid(sqlite3 *db, BtCursor *pCur, i64 *rowid){
    +   ** this code can safely assume that nCellKey is 32-bits  
    +   */
    +   assert( sqlite3BtreeCursorIsValid(pCur) );
    +-  VVA_ONLY(rc =) sqlite3BtreeKeySize(pCur, &nCellKey);
    +-  assert( rc==SQLITE_OK );     /* pCur is always valid so KeySize cannot fail */
    ++  nCellKey = sqlite3BtreePayloadSize(pCur);
    +   assert( (nCellKey & SQLITE_MAX_U32)==(u64)nCellKey );
    + 
    +   /* Read in the complete content of the index entry */
    +   sqlite3VdbeMemInit(&m, db, 0);
    +-  rc = sqlite3VdbeMemFromBtree(pCur, 0, (u32)nCellKey, 1, &m);
    ++  rc = sqlite3VdbeMemFromBtree(pCur, 0, (u32)nCellKey, &m);
    +   if( rc ){
    +     return rc;
    +   }
    +@@ -70827,12 +77461,13 @@ SQLITE_PRIVATE int sqlite3VdbeIdxKeyCompare(
    + ){
    +   i64 nCellKey = 0;
    +   int rc;
    +-  BtCursor *pCur = pC->pCursor;
    ++  BtCursor *pCur;
    +   Mem m;
    + 
    ++  assert( pC->eCurType==CURTYPE_BTREE );
    ++  pCur = pC->uc.pCursor;
    +   assert( sqlite3BtreeCursorIsValid(pCur) );
    +-  VVA_ONLY(rc =) sqlite3BtreeKeySize(pCur, &nCellKey);
    +-  assert( rc==SQLITE_OK );    /* pCur is always valid so KeySize cannot fail */
    ++  nCellKey = sqlite3BtreePayloadSize(pCur);
    +   /* nCellKey will always be between 0 and 0xffffffff because of the way
    +   ** that btreeParseCellPtr() and sqlite3GetVarint32() are implemented */
    +   if( nCellKey<=0 || nCellKey>0x7fffffff ){
    +@@ -70840,7 +77475,7 @@ SQLITE_PRIVATE int sqlite3VdbeIdxKeyCompare(
    +     return SQLITE_CORRUPT_BKPT;
    +   }
    +   sqlite3VdbeMemInit(&m, db, 0);
    +-  rc = sqlite3VdbeMemFromBtree(pC->pCursor, 0, (u32)nCellKey, 1, &m);
    ++  rc = sqlite3VdbeMemFromBtree(pCur, 0, (u32)nCellKey, &m);
    +   if( rc ){
    +     return rc;
    +   }
    +@@ -70891,6 +77526,13 @@ SQLITE_PRIVATE sqlite3 *sqlite3VdbeDb(Vdbe *v){
    +   return v->db;
    + }
    + 
    ++/*
    ++** Return the SQLITE_PREPARE flags for a Vdbe.
    ++*/
    ++SQLITE_PRIVATE u8 sqlite3VdbePrepareFlags(Vdbe *v){
    ++  return v->prepFlags;
    ++}
    ++
    + /*
    + ** Return a pointer to an sqlite3_value structure containing the value bound
    + ** parameter iVar of VM v. Except, if the value is an SQL NULL, return 
    +@@ -70903,6 +77545,7 @@ SQLITE_PRIVATE sqlite3_value *sqlite3VdbeGetBoundValue(Vdbe *v, int iVar, u8 aff
    +   assert( iVar>0 );
    +   if( v ){
    +     Mem *pMem = &v->aVar[iVar-1];
    ++    assert( (v->db->flags & SQLITE_EnableQPSG)==0 );
    +     if( 0==(pMem->flags & MEM_Null) ){
    +       sqlite3_value *pRet = sqlite3ValueNew(v->db);
    +       if( pRet ){
    +@@ -70922,13 +77565,36 @@ SQLITE_PRIVATE sqlite3_value *sqlite3VdbeGetBoundValue(Vdbe *v, int iVar, u8 aff
    + */
    + SQLITE_PRIVATE void sqlite3VdbeSetVarmask(Vdbe *v, int iVar){
    +   assert( iVar>0 );
    +-  if( iVar>32 ){
    +-    v->expmask = 0xffffffff;
    ++  assert( (v->db->flags & SQLITE_EnableQPSG)==0 );
    ++  if( iVar>=32 ){
    ++    v->expmask |= 0x80000000;
    +   }else{
    +     v->expmask |= ((u32)1 << (iVar-1));
    +   }
    + }
    + 
    ++/*
    ++** Cause a function to throw an error if it was call from OP_PureFunc
    ++** rather than OP_Function.
    ++**
    ++** OP_PureFunc means that the function must be deterministic, and should
    ++** throw an error if it is given inputs that would make it non-deterministic.
    ++** This routine is invoked by date/time functions that use non-deterministic
    ++** features such as 'now'.
    ++*/
    ++SQLITE_PRIVATE int sqlite3NotPureFunc(sqlite3_context *pCtx){
    ++#ifdef SQLITE_ENABLE_STAT3_OR_STAT4
    ++  if( pCtx->pVdbe==0 ) return 1;
    ++#endif
    ++  if( pCtx->pVdbe->aOp[pCtx->iOp].opcode==OP_PureFunc ){
    ++    sqlite3_result_error(pCtx, 
    ++       "non-deterministic function in index expression or CHECK constraint",
    ++       -1);
    ++    return 0;
    ++  }
    ++  return 1;
    ++}
    ++
    + #ifndef SQLITE_OMIT_VIRTUALTABLE
    + /*
    + ** Transfer error message text from an sqlite3_vtab.zErrMsg (text stored
    +@@ -70936,14 +77602,105 @@ SQLITE_PRIVATE void sqlite3VdbeSetVarmask(Vdbe *v, int iVar){
    + ** in memory obtained from sqlite3DbMalloc).
    + */
    + SQLITE_PRIVATE void sqlite3VtabImportErrmsg(Vdbe *p, sqlite3_vtab *pVtab){
    +-  sqlite3 *db = p->db;
    +-  sqlite3DbFree(db, p->zErrMsg);
    +-  p->zErrMsg = sqlite3DbStrDup(db, pVtab->zErrMsg);
    +-  sqlite3_free(pVtab->zErrMsg);
    +-  pVtab->zErrMsg = 0;
    ++  if( pVtab->zErrMsg ){
    ++    sqlite3 *db = p->db;
    ++    sqlite3DbFree(db, p->zErrMsg);
    ++    p->zErrMsg = sqlite3DbStrDup(db, pVtab->zErrMsg);
    ++    sqlite3_free(pVtab->zErrMsg);
    ++    pVtab->zErrMsg = 0;
    ++  }
    + }
    + #endif /* SQLITE_OMIT_VIRTUALTABLE */
    + 
    ++#ifdef SQLITE_ENABLE_PREUPDATE_HOOK
    ++
    ++/*
    ++** If the second argument is not NULL, release any allocations associated 
    ++** with the memory cells in the p->aMem[] array. Also free the UnpackedRecord
    ++** structure itself, using sqlite3DbFree().
    ++**
    ++** This function is used to free UnpackedRecord structures allocated by
    ++** the vdbeUnpackRecord() function found in vdbeapi.c.
    ++*/
    ++static void vdbeFreeUnpacked(sqlite3 *db, int nField, UnpackedRecord *p){
    ++  if( p ){
    ++    int i;
    ++    for(i=0; i<nField; i++){
    ++      Mem *pMem = &p->aMem[i];
    ++      if( pMem->zMalloc ) sqlite3VdbeMemRelease(pMem);
    ++    }
    ++    sqlite3DbFreeNN(db, p);
    ++  }
    ++}
    ++#endif /* SQLITE_ENABLE_PREUPDATE_HOOK */
    ++
    ++#ifdef SQLITE_ENABLE_PREUPDATE_HOOK
    ++/*
    ++** Invoke the pre-update hook. If this is an UPDATE or DELETE pre-update call,
    ++** then cursor passed as the second argument should point to the row about
    ++** to be update or deleted. If the application calls sqlite3_preupdate_old(),
    ++** the required value will be read from the row the cursor points to.
    ++*/
    ++SQLITE_PRIVATE void sqlite3VdbePreUpdateHook(
    ++  Vdbe *v,                        /* Vdbe pre-update hook is invoked by */
    ++  VdbeCursor *pCsr,               /* Cursor to grab old.* values from */
    ++  int op,                         /* SQLITE_INSERT, UPDATE or DELETE */
    ++  const char *zDb,                /* Database name */
    ++  Table *pTab,                    /* Modified table */
    ++  i64 iKey1,                      /* Initial key value */
    ++  int iReg                        /* Register for new.* record */
    ++){
    ++  sqlite3 *db = v->db;
    ++  i64 iKey2;
    ++  PreUpdate preupdate;
    ++  const char *zTbl = pTab->zName;
    ++  static const u8 fakeSortOrder = 0;
    ++
    ++  assert( db->pPreUpdate==0 );
    ++  memset(&preupdate, 0, sizeof(PreUpdate));
    ++  if( HasRowid(pTab)==0 ){
    ++    iKey1 = iKey2 = 0;
    ++    preupdate.pPk = sqlite3PrimaryKeyIndex(pTab);
    ++  }else{
    ++    if( op==SQLITE_UPDATE ){
    ++      iKey2 = v->aMem[iReg].u.i;
    ++    }else{
    ++      iKey2 = iKey1;
    ++    }
    ++  }
    ++
    ++  assert( pCsr->nField==pTab->nCol 
    ++       || (pCsr->nField==pTab->nCol+1 && op==SQLITE_DELETE && iReg==-1)
    ++  );
    ++
    ++  preupdate.v = v;
    ++  preupdate.pCsr = pCsr;
    ++  preupdate.op = op;
    ++  preupdate.iNewReg = iReg;
    ++  preupdate.keyinfo.db = db;
    ++  preupdate.keyinfo.enc = ENC(db);
    ++  preupdate.keyinfo.nKeyField = pTab->nCol;
    ++  preupdate.keyinfo.aSortOrder = (u8*)&fakeSortOrder;
    ++  preupdate.iKey1 = iKey1;
    ++  preupdate.iKey2 = iKey2;
    ++  preupdate.pTab = pTab;
    ++
    ++  db->pPreUpdate = &preupdate;
    ++  db->xPreUpdateCallback(db->pPreUpdateArg, db, op, zDb, zTbl, iKey1, iKey2);
    ++  db->pPreUpdate = 0;
    ++  sqlite3DbFree(db, preupdate.aRecord);
    ++  vdbeFreeUnpacked(db, preupdate.keyinfo.nKeyField+1, preupdate.pUnpacked);
    ++  vdbeFreeUnpacked(db, preupdate.keyinfo.nKeyField+1, preupdate.pNewUnpacked);
    ++  if( preupdate.aNew ){
    ++    int i;
    ++    for(i=0; i<pCsr->nField; i++){
    ++      sqlite3VdbeMemRelease(&preupdate.aNew[i]);
    ++    }
    ++    sqlite3DbFreeNN(db, preupdate.aNew);
    ++  }
    ++}
    ++#endif /* SQLITE_ENABLE_PREUPDATE_HOOK */
    ++
    + /************** End of vdbeaux.c *********************************************/
    + /************** Begin file vdbeapi.c *****************************************/
    + /*
    +@@ -70973,7 +77730,7 @@ SQLITE_PRIVATE void sqlite3VtabImportErrmsg(Vdbe *p, sqlite3_vtab *pVtab){
    + ** collating sequences are registered or if an authorizer function is
    + ** added or changed.
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_expired(sqlite3_stmt *pStmt){
    ++SQLITE_API int sqlite3_expired(sqlite3_stmt *pStmt){
    +   Vdbe *p = (Vdbe*)pStmt;
    +   return p==0 || p->expired;
    + }
    +@@ -71008,12 +77765,19 @@ static int vdbeSafetyNotNull(Vdbe *p){
    + */
    + static SQLITE_NOINLINE void invokeProfileCallback(sqlite3 *db, Vdbe *p){
    +   sqlite3_int64 iNow;
    ++  sqlite3_int64 iElapse;
    +   assert( p->startTime>0 );
    +-  assert( db->xProfile!=0 );
    ++  assert( db->xProfile!=0 || (db->mTrace & SQLITE_TRACE_PROFILE)!=0 );
    +   assert( db->init.busy==0 );
    +   assert( p->zSql!=0 );
    +   sqlite3OsCurrentTimeInt64(db->pVfs, &iNow);
    +-  db->xProfile(db->pProfileArg, p->zSql, (iNow - p->startTime)*1000000);
    ++  iElapse = (iNow - p->startTime)*1000000;
    ++  if( db->xProfile ){
    ++    db->xProfile(db->pProfileArg, p->zSql, iElapse);
    ++  }
    ++  if( db->mTrace & SQLITE_TRACE_PROFILE ){
    ++    db->xTrace(SQLITE_TRACE_PROFILE, db->pTraceArg, p, (void*)&iElapse);
    ++  }
    +   p->startTime = 0;
    + }
    + /*
    +@@ -71035,7 +77799,7 @@ static SQLITE_NOINLINE void invokeProfileCallback(sqlite3 *db, Vdbe *p){
    + ** This routine sets the error code and string returned by
    + ** sqlite3_errcode(), sqlite3_errmsg() and sqlite3_errmsg16().
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_finalize(sqlite3_stmt *pStmt){
    ++SQLITE_API int sqlite3_finalize(sqlite3_stmt *pStmt){
    +   int rc;
    +   if( pStmt==0 ){
    +     /* IMPLEMENTATION-OF: R-57228-12904 Invoking sqlite3_finalize() on a NULL
    +@@ -71062,7 +77826,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_finalize(sqlite3_stmt *pStmt){
    + ** This routine sets the error code and string returned by
    + ** sqlite3_errcode(), sqlite3_errmsg() and sqlite3_errmsg16().
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_reset(sqlite3_stmt *pStmt){
    ++SQLITE_API int sqlite3_reset(sqlite3_stmt *pStmt){
    +   int rc;
    +   if( pStmt==0 ){
    +     rc = SQLITE_OK;
    +@@ -71083,7 +77847,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_reset(sqlite3_stmt *pStmt){
    + /*
    + ** Set all the parameters in the compiled SQL statement to NULL.
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_clear_bindings(sqlite3_stmt *pStmt){
    ++SQLITE_API int sqlite3_clear_bindings(sqlite3_stmt *pStmt){
    +   int i;
    +   int rc = SQLITE_OK;
    +   Vdbe *p = (Vdbe*)pStmt;
    +@@ -71095,7 +77859,8 @@ SQLITE_API int SQLITE_STDCALL sqlite3_clear_bindings(sqlite3_stmt *pStmt){
    +     sqlite3VdbeMemRelease(&p->aVar[i]);
    +     p->aVar[i].flags = MEM_Null;
    +   }
    +-  if( p->isPrepareV2 && p->expmask ){
    ++  assert( (p->prepFlags & SQLITE_PREPARE_SAVESQL)!=0 || p->expmask==0 );
    ++  if( p->expmask ){
    +     p->expired = 1;
    +   }
    +   sqlite3_mutex_leave(mutex);
    +@@ -71107,10 +77872,10 @@ SQLITE_API int SQLITE_STDCALL sqlite3_clear_bindings(sqlite3_stmt *pStmt){
    + ** The following routines extract information from a Mem or sqlite3_value
    + ** structure.
    + */
    +-SQLITE_API const void *SQLITE_STDCALL sqlite3_value_blob(sqlite3_value *pVal){
    ++SQLITE_API const void *sqlite3_value_blob(sqlite3_value *pVal){
    +   Mem *p = (Mem*)pVal;
    +   if( p->flags & (MEM_Blob|MEM_Str) ){
    +-    if( sqlite3VdbeMemExpandBlob(p)!=SQLITE_OK ){
    ++    if( ExpandBlob(p)!=SQLITE_OK ){
    +       assert( p->flags==MEM_Null && p->z==0 );
    +       return 0;
    +     }
    +@@ -71120,35 +77885,49 @@ SQLITE_API const void *SQLITE_STDCALL sqlite3_value_blob(sqlite3_value *pVal){
    +     return sqlite3_value_text(pVal);
    +   }
    + }
    +-SQLITE_API int SQLITE_STDCALL sqlite3_value_bytes(sqlite3_value *pVal){
    ++SQLITE_API int sqlite3_value_bytes(sqlite3_value *pVal){
    +   return sqlite3ValueBytes(pVal, SQLITE_UTF8);
    + }
    +-SQLITE_API int SQLITE_STDCALL sqlite3_value_bytes16(sqlite3_value *pVal){
    ++SQLITE_API int sqlite3_value_bytes16(sqlite3_value *pVal){
    +   return sqlite3ValueBytes(pVal, SQLITE_UTF16NATIVE);
    + }
    +-SQLITE_API double SQLITE_STDCALL sqlite3_value_double(sqlite3_value *pVal){
    ++SQLITE_API double sqlite3_value_double(sqlite3_value *pVal){
    +   return sqlite3VdbeRealValue((Mem*)pVal);
    + }
    +-SQLITE_API int SQLITE_STDCALL sqlite3_value_int(sqlite3_value *pVal){
    ++SQLITE_API int sqlite3_value_int(sqlite3_value *pVal){
    +   return (int)sqlite3VdbeIntValue((Mem*)pVal);
    + }
    +-SQLITE_API sqlite_int64 SQLITE_STDCALL sqlite3_value_int64(sqlite3_value *pVal){
    ++SQLITE_API sqlite_int64 sqlite3_value_int64(sqlite3_value *pVal){
    +   return sqlite3VdbeIntValue((Mem*)pVal);
    + }
    +-SQLITE_API unsigned int SQLITE_STDCALL sqlite3_value_subtype(sqlite3_value *pVal){
    +-  return ((Mem*)pVal)->eSubtype;
    ++SQLITE_API unsigned int sqlite3_value_subtype(sqlite3_value *pVal){
    ++  Mem *pMem = (Mem*)pVal;
    ++  return ((pMem->flags & MEM_Subtype) ? pMem->eSubtype : 0);
    + }
    +-SQLITE_API const unsigned char *SQLITE_STDCALL sqlite3_value_text(sqlite3_value *pVal){
    ++SQLITE_API void *sqlite3_value_pointer(sqlite3_value *pVal, const char *zPType){
    ++  Mem *p = (Mem*)pVal;
    ++  if( (p->flags&(MEM_TypeMask|MEM_Term|MEM_Subtype)) ==
    ++                 (MEM_Null|MEM_Term|MEM_Subtype)
    ++   && zPType!=0
    ++   && p->eSubtype=='p'
    ++   && strcmp(p->u.zPType, zPType)==0
    ++  ){
    ++    return (void*)p->z;
    ++  }else{
    ++    return 0;
    ++  }
    ++}
    ++SQLITE_API const unsigned char *sqlite3_value_text(sqlite3_value *pVal){
    +   return (const unsigned char *)sqlite3ValueText(pVal, SQLITE_UTF8);
    + }
    + #ifndef SQLITE_OMIT_UTF16
    +-SQLITE_API const void *SQLITE_STDCALL sqlite3_value_text16(sqlite3_value* pVal){
    ++SQLITE_API const void *sqlite3_value_text16(sqlite3_value* pVal){
    +   return sqlite3ValueText(pVal, SQLITE_UTF16NATIVE);
    + }
    +-SQLITE_API const void *SQLITE_STDCALL sqlite3_value_text16be(sqlite3_value *pVal){
    ++SQLITE_API const void *sqlite3_value_text16be(sqlite3_value *pVal){
    +   return sqlite3ValueText(pVal, SQLITE_UTF16BE);
    + }
    +-SQLITE_API const void *SQLITE_STDCALL sqlite3_value_text16le(sqlite3_value *pVal){
    ++SQLITE_API const void *sqlite3_value_text16le(sqlite3_value *pVal){
    +   return sqlite3ValueText(pVal, SQLITE_UTF16LE);
    + }
    + #endif /* SQLITE_OMIT_UTF16 */
    +@@ -71156,7 +77935,7 @@ SQLITE_API const void *SQLITE_STDCALL sqlite3_value_text16le(sqlite3_value *pVal
    + ** fundamental datatypes: 64-bit signed integer 64-bit IEEE floating
    + ** point number string BLOB NULL
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_value_type(sqlite3_value* pVal){
    ++SQLITE_API int sqlite3_value_type(sqlite3_value* pVal){
    +   static const u8 aType[] = {
    +      SQLITE_BLOB,     /* 0x00 */
    +      SQLITE_NULL,     /* 0x01 */
    +@@ -71194,9 +77973,14 @@ SQLITE_API int SQLITE_STDCALL sqlite3_value_type(sqlite3_value* pVal){
    +   return aType[pVal->flags&MEM_AffMask];
    + }
    + 
    ++/* Return true if a parameter to xUpdate represents an unchanged column */
    ++SQLITE_API int sqlite3_value_nochange(sqlite3_value *pVal){
    ++  return (pVal->flags&(MEM_Null|MEM_Zero))==(MEM_Null|MEM_Zero);
    ++}
    ++
    + /* Make a copy of an sqlite3_value object
    + */
    +-SQLITE_API sqlite3_value *SQLITE_STDCALL sqlite3_value_dup(const sqlite3_value *pOrig){
    ++SQLITE_API sqlite3_value *sqlite3_value_dup(const sqlite3_value *pOrig){
    +   sqlite3_value *pNew;
    +   if( pOrig==0 ) return 0;
    +   pNew = sqlite3_malloc( sizeof(*pNew) );
    +@@ -71219,7 +78003,7 @@ SQLITE_API sqlite3_value *SQLITE_STDCALL sqlite3_value_dup(const sqlite3_value *
    + /* Destroy an sqlite3_value object previously obtained from
    + ** sqlite3_value_dup().
    + */
    +-SQLITE_API void SQLITE_STDCALL sqlite3_value_free(sqlite3_value *pOld){
    ++SQLITE_API void sqlite3_value_free(sqlite3_value *pOld){
    +   sqlite3ValueFree(pOld);
    + }
    +   
    +@@ -71262,7 +78046,7 @@ static int invokeValueDestructor(
    +   if( pCtx ) sqlite3_result_error_toobig(pCtx);
    +   return SQLITE_TOOBIG;
    + }
    +-SQLITE_API void SQLITE_STDCALL sqlite3_result_blob(
    ++SQLITE_API void sqlite3_result_blob(
    +   sqlite3_context *pCtx, 
    +   const void *z, 
    +   int n, 
    +@@ -71272,7 +78056,7 @@ SQLITE_API void SQLITE_STDCALL sqlite3_result_blob(
    +   assert( sqlite3_mutex_held(pCtx->pOut->db->mutex) );
    +   setResultStrOrError(pCtx, z, n, 0, xDel);
    + }
    +-SQLITE_API void SQLITE_STDCALL sqlite3_result_blob64(
    ++SQLITE_API void sqlite3_result_blob64(
    +   sqlite3_context *pCtx, 
    +   const void *z, 
    +   sqlite3_uint64 n,
    +@@ -71286,41 +78070,55 @@ SQLITE_API void SQLITE_STDCALL sqlite3_result_blob64(
    +     setResultStrOrError(pCtx, z, (int)n, 0, xDel);
    +   }
    + }
    +-SQLITE_API void SQLITE_STDCALL sqlite3_result_double(sqlite3_context *pCtx, double rVal){
    ++SQLITE_API void sqlite3_result_double(sqlite3_context *pCtx, double rVal){
    +   assert( sqlite3_mutex_held(pCtx->pOut->db->mutex) );
    +   sqlite3VdbeMemSetDouble(pCtx->pOut, rVal);
    + }
    +-SQLITE_API void SQLITE_STDCALL sqlite3_result_error(sqlite3_context *pCtx, const char *z, int n){
    ++SQLITE_API void sqlite3_result_error(sqlite3_context *pCtx, const char *z, int n){
    +   assert( sqlite3_mutex_held(pCtx->pOut->db->mutex) );
    +   pCtx->isError = SQLITE_ERROR;
    +   pCtx->fErrorOrAux = 1;
    +   sqlite3VdbeMemSetStr(pCtx->pOut, z, n, SQLITE_UTF8, SQLITE_TRANSIENT);
    + }
    + #ifndef SQLITE_OMIT_UTF16
    +-SQLITE_API void SQLITE_STDCALL sqlite3_result_error16(sqlite3_context *pCtx, const void *z, int n){
    ++SQLITE_API void sqlite3_result_error16(sqlite3_context *pCtx, const void *z, int n){
    +   assert( sqlite3_mutex_held(pCtx->pOut->db->mutex) );
    +   pCtx->isError = SQLITE_ERROR;
    +   pCtx->fErrorOrAux = 1;
    +   sqlite3VdbeMemSetStr(pCtx->pOut, z, n, SQLITE_UTF16NATIVE, SQLITE_TRANSIENT);
    + }
    + #endif
    +-SQLITE_API void SQLITE_STDCALL sqlite3_result_int(sqlite3_context *pCtx, int iVal){
    ++SQLITE_API void sqlite3_result_int(sqlite3_context *pCtx, int iVal){
    +   assert( sqlite3_mutex_held(pCtx->pOut->db->mutex) );
    +   sqlite3VdbeMemSetInt64(pCtx->pOut, (i64)iVal);
    + }
    +-SQLITE_API void SQLITE_STDCALL sqlite3_result_int64(sqlite3_context *pCtx, i64 iVal){
    ++SQLITE_API void sqlite3_result_int64(sqlite3_context *pCtx, i64 iVal){
    +   assert( sqlite3_mutex_held(pCtx->pOut->db->mutex) );
    +   sqlite3VdbeMemSetInt64(pCtx->pOut, iVal);
    + }
    +-SQLITE_API void SQLITE_STDCALL sqlite3_result_null(sqlite3_context *pCtx){
    ++SQLITE_API void sqlite3_result_null(sqlite3_context *pCtx){
    +   assert( sqlite3_mutex_held(pCtx->pOut->db->mutex) );
    +   sqlite3VdbeMemSetNull(pCtx->pOut);
    + }
    +-SQLITE_API void SQLITE_STDCALL sqlite3_result_subtype(sqlite3_context *pCtx, unsigned int eSubtype){
    +-  assert( sqlite3_mutex_held(pCtx->pOut->db->mutex) );
    +-  pCtx->pOut->eSubtype = eSubtype & 0xff;
    ++SQLITE_API void sqlite3_result_pointer(
    ++  sqlite3_context *pCtx,
    ++  void *pPtr,
    ++  const char *zPType,
    ++  void (*xDestructor)(void*)
    ++){
    ++  Mem *pOut = pCtx->pOut;
    ++  assert( sqlite3_mutex_held(pOut->db->mutex) );
    ++  sqlite3VdbeMemRelease(pOut);
    ++  pOut->flags = MEM_Null;
    ++  sqlite3VdbeMemSetPointer(pOut, pPtr, zPType, xDestructor);
    ++}
    ++SQLITE_API void sqlite3_result_subtype(sqlite3_context *pCtx, unsigned int eSubtype){
    ++  Mem *pOut = pCtx->pOut;
    ++  assert( sqlite3_mutex_held(pOut->db->mutex) );
    ++  pOut->eSubtype = eSubtype & 0xff;
    ++  pOut->flags |= MEM_Subtype;
    + }
    +-SQLITE_API void SQLITE_STDCALL sqlite3_result_text(
    ++SQLITE_API void sqlite3_result_text(
    +   sqlite3_context *pCtx, 
    +   const char *z, 
    +   int n,
    +@@ -71329,7 +78127,7 @@ SQLITE_API void SQLITE_STDCALL sqlite3_result_text(
    +   assert( sqlite3_mutex_held(pCtx->pOut->db->mutex) );
    +   setResultStrOrError(pCtx, z, n, SQLITE_UTF8, xDel);
    + }
    +-SQLITE_API void SQLITE_STDCALL sqlite3_result_text64(
    ++SQLITE_API void sqlite3_result_text64(
    +   sqlite3_context *pCtx, 
    +   const char *z, 
    +   sqlite3_uint64 n,
    +@@ -71346,7 +78144,7 @@ SQLITE_API void SQLITE_STDCALL sqlite3_result_text64(
    +   }
    + }
    + #ifndef SQLITE_OMIT_UTF16
    +-SQLITE_API void SQLITE_STDCALL sqlite3_result_text16(
    ++SQLITE_API void sqlite3_result_text16(
    +   sqlite3_context *pCtx, 
    +   const void *z, 
    +   int n, 
    +@@ -71355,7 +78153,7 @@ SQLITE_API void SQLITE_STDCALL sqlite3_result_text16(
    +   assert( sqlite3_mutex_held(pCtx->pOut->db->mutex) );
    +   setResultStrOrError(pCtx, z, n, SQLITE_UTF16NATIVE, xDel);
    + }
    +-SQLITE_API void SQLITE_STDCALL sqlite3_result_text16be(
    ++SQLITE_API void sqlite3_result_text16be(
    +   sqlite3_context *pCtx, 
    +   const void *z, 
    +   int n, 
    +@@ -71364,7 +78162,7 @@ SQLITE_API void SQLITE_STDCALL sqlite3_result_text16be(
    +   assert( sqlite3_mutex_held(pCtx->pOut->db->mutex) );
    +   setResultStrOrError(pCtx, z, n, SQLITE_UTF16BE, xDel);
    + }
    +-SQLITE_API void SQLITE_STDCALL sqlite3_result_text16le(
    ++SQLITE_API void sqlite3_result_text16le(
    +   sqlite3_context *pCtx, 
    +   const void *z, 
    +   int n, 
    +@@ -71374,15 +78172,15 @@ SQLITE_API void SQLITE_STDCALL sqlite3_result_text16le(
    +   setResultStrOrError(pCtx, z, n, SQLITE_UTF16LE, xDel);
    + }
    + #endif /* SQLITE_OMIT_UTF16 */
    +-SQLITE_API void SQLITE_STDCALL sqlite3_result_value(sqlite3_context *pCtx, sqlite3_value *pValue){
    ++SQLITE_API void sqlite3_result_value(sqlite3_context *pCtx, sqlite3_value *pValue){
    +   assert( sqlite3_mutex_held(pCtx->pOut->db->mutex) );
    +   sqlite3VdbeMemCopy(pCtx->pOut, pValue);
    + }
    +-SQLITE_API void SQLITE_STDCALL sqlite3_result_zeroblob(sqlite3_context *pCtx, int n){
    ++SQLITE_API void sqlite3_result_zeroblob(sqlite3_context *pCtx, int n){
    +   assert( sqlite3_mutex_held(pCtx->pOut->db->mutex) );
    +   sqlite3VdbeMemSetZeroBlob(pCtx->pOut, n);
    + }
    +-SQLITE_API int SQLITE_STDCALL sqlite3_result_zeroblob64(sqlite3_context *pCtx, u64 n){
    ++SQLITE_API int sqlite3_result_zeroblob64(sqlite3_context *pCtx, u64 n){
    +   Mem *pOut = pCtx->pOut;
    +   assert( sqlite3_mutex_held(pOut->db->mutex) );
    +   if( n>(u64)pOut->db->aLimit[SQLITE_LIMIT_LENGTH] ){
    +@@ -71391,7 +78189,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_result_zeroblob64(sqlite3_context *pCtx, u
    +   sqlite3VdbeMemSetZeroBlob(pCtx->pOut, (int)n);
    +   return SQLITE_OK;
    + }
    +-SQLITE_API void SQLITE_STDCALL sqlite3_result_error_code(sqlite3_context *pCtx, int errCode){
    ++SQLITE_API void sqlite3_result_error_code(sqlite3_context *pCtx, int errCode){
    +   pCtx->isError = errCode;
    +   pCtx->fErrorOrAux = 1;
    + #ifdef SQLITE_DEBUG
    +@@ -71404,7 +78202,7 @@ SQLITE_API void SQLITE_STDCALL sqlite3_result_error_code(sqlite3_context *pCtx,
    + }
    + 
    + /* Force an SQLITE_TOOBIG error. */
    +-SQLITE_API void SQLITE_STDCALL sqlite3_result_error_toobig(sqlite3_context *pCtx){
    ++SQLITE_API void sqlite3_result_error_toobig(sqlite3_context *pCtx){
    +   assert( sqlite3_mutex_held(pCtx->pOut->db->mutex) );
    +   pCtx->isError = SQLITE_TOOBIG;
    +   pCtx->fErrorOrAux = 1;
    +@@ -71413,12 +78211,12 @@ SQLITE_API void SQLITE_STDCALL sqlite3_result_error_toobig(sqlite3_context *pCtx
    + }
    + 
    + /* An SQLITE_NOMEM error. */
    +-SQLITE_API void SQLITE_STDCALL sqlite3_result_error_nomem(sqlite3_context *pCtx){
    ++SQLITE_API void sqlite3_result_error_nomem(sqlite3_context *pCtx){
    +   assert( sqlite3_mutex_held(pCtx->pOut->db->mutex) );
    +   sqlite3VdbeMemSetNull(pCtx->pOut);
    +-  pCtx->isError = SQLITE_NOMEM;
    ++  pCtx->isError = SQLITE_NOMEM_BKPT;
    +   pCtx->fErrorOrAux = 1;
    +-  pCtx->pOut->db->mallocFailed = 1;
    ++  sqlite3OomFault(pCtx->pOut->db);
    + }
    + 
    + /*
    +@@ -71436,8 +78234,8 @@ static int doWalCallbacks(sqlite3 *db){
    +       sqlite3BtreeEnter(pBt);
    +       nEntry = sqlite3PagerWalCallback(sqlite3BtreePager(pBt));
    +       sqlite3BtreeLeave(pBt);
    +-      if( db->xWalCallback && nEntry>0 && rc==SQLITE_OK ){
    +-        rc = db->xWalCallback(db->pWalArg, db, db->aDb[i].zName, nEntry);
    ++      if( nEntry>0 && db->xWalCallback && rc==SQLITE_OK ){
    ++        rc = db->xWalCallback(db->pWalArg, db, db->aDb[i].zDbSName, nEntry);
    +       }
    +     }
    +   }
    +@@ -71492,7 +78290,7 @@ static int sqlite3Step(Vdbe *p){
    +   db = p->db;
    +   if( db->mallocFailed ){
    +     p->rc = SQLITE_NOMEM;
    +-    return SQLITE_NOMEM;
    ++    return SQLITE_NOMEM_BKPT;
    +   }
    + 
    +   if( p->pc<=0 && p->expired ){
    +@@ -71514,7 +78312,8 @@ static int sqlite3Step(Vdbe *p){
    +     );
    + 
    + #ifndef SQLITE_OMIT_TRACE
    +-    if( db->xProfile && !db->init.busy && p->zSql ){
    ++    if( (db->xProfile || (db->mTrace & SQLITE_TRACE_PROFILE)!=0)
    ++        && !db->init.busy && p->zSql ){
    +       sqlite3OsCurrentTimeInt64(db->pVfs, &p->startTime);
    +     }else{
    +       assert( p->startTime==0 );
    +@@ -71545,7 +78344,7 @@ static int sqlite3Step(Vdbe *p){
    +   if( rc!=SQLITE_ROW ) checkProfileCallback(db, p);
    + #endif
    + 
    +-  if( rc==SQLITE_DONE ){
    ++  if( rc==SQLITE_DONE && db->autoCommit ){
    +     assert( p->rc==SQLITE_OK );
    +     p->rc = doWalCallbacks(db);
    +     if( p->rc!=SQLITE_OK ){
    +@@ -71555,7 +78354,7 @@ static int sqlite3Step(Vdbe *p){
    + 
    +   db->errCode = rc;
    +   if( SQLITE_NOMEM==sqlite3ApiExit(p->db, p->rc) ){
    +-    p->rc = SQLITE_NOMEM;
    ++    p->rc = SQLITE_NOMEM_BKPT;
    +   }
    + end_of_step:
    +   /* At this point local variable rc holds the value that should be 
    +@@ -71569,8 +78368,11 @@ end_of_step:
    +        || (rc&0xff)==SQLITE_BUSY || rc==SQLITE_MISUSE
    +   );
    +   assert( (p->rc!=SQLITE_ROW && p->rc!=SQLITE_DONE) || p->rc==p->rcApp );
    +-  if( p->isPrepareV2 && rc!=SQLITE_ROW && rc!=SQLITE_DONE ){
    +-    /* If this statement was prepared using sqlite3_prepare_v2(), and an
    ++  if( (p->prepFlags & SQLITE_PREPARE_SAVESQL)!=0 
    ++   && rc!=SQLITE_ROW 
    ++   && rc!=SQLITE_DONE 
    ++  ){
    ++    /* If this statement was prepared using saved SQL and an 
    +     ** error has occurred, then return the error code in p->rc to the
    +     ** caller. Set the error code in the database handle to the same value.
    +     */ 
    +@@ -71584,9 +78386,8 @@ end_of_step:
    + ** sqlite3Step() to do most of the work.  If a schema error occurs,
    + ** call sqlite3Reprepare() and try again.
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_step(sqlite3_stmt *pStmt){
    ++SQLITE_API int sqlite3_step(sqlite3_stmt *pStmt){
    +   int rc = SQLITE_OK;      /* Result from sqlite3Step() */
    +-  int rc2 = SQLITE_OK;     /* Result from sqlite3Reprepare() */
    +   Vdbe *v = (Vdbe*)pStmt;  /* the prepared statement */
    +   int cnt = 0;             /* Counter to prevent infinite loop of reprepares */
    +   sqlite3 *db;             /* The database connection */
    +@@ -71600,32 +78401,31 @@ SQLITE_API int SQLITE_STDCALL sqlite3_step(sqlite3_stmt *pStmt){
    +   while( (rc = sqlite3Step(v))==SQLITE_SCHEMA
    +          && cnt++ < SQLITE_MAX_SCHEMA_RETRY ){
    +     int savedPc = v->pc;
    +-    rc2 = rc = sqlite3Reprepare(v);
    +-    if( rc!=SQLITE_OK) break;
    ++    rc = sqlite3Reprepare(v);
    ++    if( rc!=SQLITE_OK ){
    ++      /* This case occurs after failing to recompile an sql statement. 
    ++      ** The error message from the SQL compiler has already been loaded 
    ++      ** into the database handle. This block copies the error message 
    ++      ** from the database handle into the statement and sets the statement
    ++      ** program counter to 0 to ensure that when the statement is 
    ++      ** finalized or reset the parser error message is available via
    ++      ** sqlite3_errmsg() and sqlite3_errcode().
    ++      */
    ++      const char *zErr = (const char *)sqlite3_value_text(db->pErr); 
    ++      sqlite3DbFree(db, v->zErrMsg);
    ++      if( !db->mallocFailed ){
    ++        v->zErrMsg = sqlite3DbStrDup(db, zErr);
    ++        v->rc = rc = sqlite3ApiExit(db, rc);
    ++      } else {
    ++        v->zErrMsg = 0;
    ++        v->rc = rc = SQLITE_NOMEM_BKPT;
    ++      }
    ++      break;
    ++    }
    +     sqlite3_reset(pStmt);
    +     if( savedPc>=0 ) v->doingRerun = 1;
    +     assert( v->expired==0 );
    +   }
    +-  if( rc2!=SQLITE_OK ){
    +-    /* This case occurs after failing to recompile an sql statement. 
    +-    ** The error message from the SQL compiler has already been loaded 
    +-    ** into the database handle. This block copies the error message 
    +-    ** from the database handle into the statement and sets the statement
    +-    ** program counter to 0 to ensure that when the statement is 
    +-    ** finalized or reset the parser error message is available via
    +-    ** sqlite3_errmsg() and sqlite3_errcode().
    +-    */
    +-    const char *zErr = (const char *)sqlite3_value_text(db->pErr); 
    +-    sqlite3DbFree(db, v->zErrMsg);
    +-    if( !db->mallocFailed ){
    +-      v->zErrMsg = sqlite3DbStrDup(db, zErr);
    +-      v->rc = rc2;
    +-    } else {
    +-      v->zErrMsg = 0;
    +-      v->rc = rc = SQLITE_NOMEM;
    +-    }
    +-  }
    +-  rc = sqlite3ApiExit(db, rc);
    +   sqlite3_mutex_leave(db->mutex);
    +   return rc;
    + }
    +@@ -71635,7 +78435,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_step(sqlite3_stmt *pStmt){
    + ** Extract the user data from a sqlite3_context structure and return a
    + ** pointer to it.
    + */
    +-SQLITE_API void *SQLITE_STDCALL sqlite3_user_data(sqlite3_context *p){
    ++SQLITE_API void *sqlite3_user_data(sqlite3_context *p){
    +   assert( p && p->pFunc );
    +   return p->pFunc->pUserData;
    + }
    +@@ -71650,11 +78450,30 @@ SQLITE_API void *SQLITE_STDCALL sqlite3_user_data(sqlite3_context *p){
    + ** sqlite3_create_function16() routines that originally registered the
    + ** application defined function.
    + */
    +-SQLITE_API sqlite3 *SQLITE_STDCALL sqlite3_context_db_handle(sqlite3_context *p){
    ++SQLITE_API sqlite3 *sqlite3_context_db_handle(sqlite3_context *p){
    +   assert( p && p->pOut );
    +   return p->pOut->db;
    + }
    + 
    ++/*
    ++** If this routine is invoked from within an xColumn method of a virtual
    ++** table, then it returns true if and only if the the call is during an
    ++** UPDATE operation and the value of the column will not be modified
    ++** by the UPDATE.
    ++**
    ++** If this routine is called from any context other than within the
    ++** xColumn method of a virtual table, then the return value is meaningless
    ++** and arbitrary.
    ++**
    ++** Virtual table implements might use this routine to optimize their
    ++** performance by substituting a NULL result, or some other light-weight
    ++** value, as a signal to the xUpdate routine that the column is unchanged.
    ++*/
    ++SQLITE_API int sqlite3_vtab_nochange(sqlite3_context *p){
    ++  assert( p );
    ++  return sqlite3_value_nochange(p->pOut);
    ++}
    ++
    + /*
    + ** Return the current time for a statement.  If the current time
    + ** is requested more than once within the same run of a single prepared
    +@@ -71726,8 +78545,8 @@ static SQLITE_NOINLINE void *createAggContext(sqlite3_context *p, int nByte){
    + ** context is allocated on the first call.  Subsequent calls return the
    + ** same context that was returned on prior calls.
    + */
    +-SQLITE_API void *SQLITE_STDCALL sqlite3_aggregate_context(sqlite3_context *p, int nByte){
    +-  assert( p && p->pFunc && p->pFunc->xStep );
    ++SQLITE_API void *sqlite3_aggregate_context(sqlite3_context *p, int nByte){
    ++  assert( p && p->pFunc && p->pFunc->xFinalize );
    +   assert( sqlite3_mutex_held(p->pOut->db->mutex) );
    +   testcase( nByte<0 );
    +   if( (p->pMem->flags & MEM_Agg)==0 ){
    +@@ -71740,8 +78559,14 @@ SQLITE_API void *SQLITE_STDCALL sqlite3_aggregate_context(sqlite3_context *p, in
    + /*
    + ** Return the auxiliary data pointer, if any, for the iArg'th argument to
    + ** the user-function defined by pCtx.
    ++**
    ++** The left-most argument is 0.
    ++**
    ++** Undocumented behavior:  If iArg is negative then access a cache of
    ++** auxiliary data pointers that is available to all functions within a
    ++** single prepared statement.  The iArg values must match.
    + */
    +-SQLITE_API void *SQLITE_STDCALL sqlite3_get_auxdata(sqlite3_context *pCtx, int iArg){
    ++SQLITE_API void *sqlite3_get_auxdata(sqlite3_context *pCtx, int iArg){
    +   AuxData *pAuxData;
    + 
    +   assert( sqlite3_mutex_held(pCtx->pOut->db->mutex) );
    +@@ -71750,19 +78575,26 @@ SQLITE_API void *SQLITE_STDCALL sqlite3_get_auxdata(sqlite3_context *pCtx, int i
    + #else
    +   assert( pCtx->pVdbe!=0 );
    + #endif
    +-  for(pAuxData=pCtx->pVdbe->pAuxData; pAuxData; pAuxData=pAuxData->pNext){
    +-    if( pAuxData->iOp==pCtx->iOp && pAuxData->iArg==iArg ) break;
    ++  for(pAuxData=pCtx->pVdbe->pAuxData; pAuxData; pAuxData=pAuxData->pNextAux){
    ++    if(  pAuxData->iAuxArg==iArg && (pAuxData->iAuxOp==pCtx->iOp || iArg<0) ){
    ++      return pAuxData->pAux;
    ++    }
    +   }
    +-
    +-  return (pAuxData ? pAuxData->pAux : 0);
    ++  return 0;
    + }
    + 
    + /*
    + ** Set the auxiliary data pointer and delete function, for the iArg'th
    + ** argument to the user-function defined by pCtx. Any previous value is
    + ** deleted by calling the delete function specified when it was set.
    ++**
    ++** The left-most argument is 0.
    ++**
    ++** Undocumented behavior:  If iArg is negative then make the data available
    ++** to all functions within the current prepared statement using iArg as an
    ++** access code.
    + */
    +-SQLITE_API void SQLITE_STDCALL sqlite3_set_auxdata(
    ++SQLITE_API void sqlite3_set_auxdata(
    +   sqlite3_context *pCtx, 
    +   int iArg, 
    +   void *pAux, 
    +@@ -71772,33 +78604,34 @@ SQLITE_API void SQLITE_STDCALL sqlite3_set_auxdata(
    +   Vdbe *pVdbe = pCtx->pVdbe;
    + 
    +   assert( sqlite3_mutex_held(pCtx->pOut->db->mutex) );
    +-  if( iArg<0 ) goto failed;
    + #ifdef SQLITE_ENABLE_STAT3_OR_STAT4
    +   if( pVdbe==0 ) goto failed;
    + #else
    +   assert( pVdbe!=0 );
    + #endif
    + 
    +-  for(pAuxData=pVdbe->pAuxData; pAuxData; pAuxData=pAuxData->pNext){
    +-    if( pAuxData->iOp==pCtx->iOp && pAuxData->iArg==iArg ) break;
    ++  for(pAuxData=pVdbe->pAuxData; pAuxData; pAuxData=pAuxData->pNextAux){
    ++    if( pAuxData->iAuxArg==iArg && (pAuxData->iAuxOp==pCtx->iOp || iArg<0) ){
    ++      break;
    ++    }
    +   }
    +   if( pAuxData==0 ){
    +     pAuxData = sqlite3DbMallocZero(pVdbe->db, sizeof(AuxData));
    +     if( !pAuxData ) goto failed;
    +-    pAuxData->iOp = pCtx->iOp;
    +-    pAuxData->iArg = iArg;
    +-    pAuxData->pNext = pVdbe->pAuxData;
    ++    pAuxData->iAuxOp = pCtx->iOp;
    ++    pAuxData->iAuxArg = iArg;
    ++    pAuxData->pNextAux = pVdbe->pAuxData;
    +     pVdbe->pAuxData = pAuxData;
    +     if( pCtx->fErrorOrAux==0 ){
    +       pCtx->isError = 0;
    +       pCtx->fErrorOrAux = 1;
    +     }
    +-  }else if( pAuxData->xDelete ){
    +-    pAuxData->xDelete(pAuxData->pAux);
    ++  }else if( pAuxData->xDeleteAux ){
    ++    pAuxData->xDeleteAux(pAuxData->pAux);
    +   }
    + 
    +   pAuxData->pAux = pAux;
    +-  pAuxData->xDelete = xDelete;
    ++  pAuxData->xDeleteAux = xDelete;
    +   return;
    + 
    + failed:
    +@@ -71817,8 +78650,8 @@ failed:
    + ** implementations should keep their own counts within their aggregate
    + ** context.
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_aggregate_count(sqlite3_context *p){
    +-  assert( p && p->pMem && p->pFunc && p->pFunc->xStep );
    ++SQLITE_API int sqlite3_aggregate_count(sqlite3_context *p){
    ++  assert( p && p->pMem && p->pFunc && p->pFunc->xFinalize );
    +   return p->pMem->n;
    + }
    + #endif
    +@@ -71826,7 +78659,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_aggregate_count(sqlite3_context *p){
    + /*
    + ** Return the number of columns in the result set for the statement pStmt.
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_column_count(sqlite3_stmt *pStmt){
    ++SQLITE_API int sqlite3_column_count(sqlite3_stmt *pStmt){
    +   Vdbe *pVm = (Vdbe *)pStmt;
    +   return pVm ? pVm->nResColumn : 0;
    + }
    +@@ -71835,7 +78668,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_column_count(sqlite3_stmt *pStmt){
    + ** Return the number of values available from the current row of the
    + ** currently executing statement pStmt.
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_data_count(sqlite3_stmt *pStmt){
    ++SQLITE_API int sqlite3_data_count(sqlite3_stmt *pStmt){
    +   Vdbe *pVm = (Vdbe *)pStmt;
    +   if( pVm==0 || pVm->pResultSet==0 ) return 0;
    +   return pVm->nResColumn;
    +@@ -71889,14 +78722,13 @@ static Mem *columnMem(sqlite3_stmt *pStmt, int i){
    +   Mem *pOut;
    + 
    +   pVm = (Vdbe *)pStmt;
    +-  if( pVm && pVm->pResultSet!=0 && i<pVm->nResColumn && i>=0 ){
    +-    sqlite3_mutex_enter(pVm->db->mutex);
    ++  if( pVm==0 ) return (Mem*)columnNullValue();
    ++  assert( pVm->db );
    ++  sqlite3_mutex_enter(pVm->db->mutex);
    ++  if( pVm->pResultSet!=0 && i<pVm->nResColumn && i>=0 ){
    +     pOut = &pVm->pResultSet[i];
    +   }else{
    +-    if( pVm && ALWAYS(pVm->db) ){
    +-      sqlite3_mutex_enter(pVm->db->mutex);
    +-      sqlite3Error(pVm->db, SQLITE_RANGE);
    +-    }
    ++    sqlite3Error(pVm->db, SQLITE_RANGE);
    +     pOut = (Mem*)columnNullValue();
    +   }
    +   return pOut;
    +@@ -71929,6 +78761,8 @@ static void columnMallocFailure(sqlite3_stmt *pStmt)
    +   */
    +   Vdbe *p = (Vdbe *)pStmt;
    +   if( p ){
    ++    assert( p->db!=0 );
    ++    assert( sqlite3_mutex_held(p->db->mutex) );
    +     p->rc = sqlite3ApiExit(p->db, p->rc);
    +     sqlite3_mutex_leave(p->db->mutex);
    +   }
    +@@ -71938,7 +78772,7 @@ static void columnMallocFailure(sqlite3_stmt *pStmt)
    + ** The following routines are used to access elements of the current row
    + ** in the result set.
    + */
    +-SQLITE_API const void *SQLITE_STDCALL sqlite3_column_blob(sqlite3_stmt *pStmt, int i){
    ++SQLITE_API const void *sqlite3_column_blob(sqlite3_stmt *pStmt, int i){
    +   const void *val;
    +   val = sqlite3_value_blob( columnMem(pStmt,i) );
    +   /* Even though there is no encoding conversion, value_blob() might
    +@@ -71948,37 +78782,37 @@ SQLITE_API const void *SQLITE_STDCALL sqlite3_column_blob(sqlite3_stmt *pStmt, i
    +   columnMallocFailure(pStmt);
    +   return val;
    + }
    +-SQLITE_API int SQLITE_STDCALL sqlite3_column_bytes(sqlite3_stmt *pStmt, int i){
    ++SQLITE_API int sqlite3_column_bytes(sqlite3_stmt *pStmt, int i){
    +   int val = sqlite3_value_bytes( columnMem(pStmt,i) );
    +   columnMallocFailure(pStmt);
    +   return val;
    + }
    +-SQLITE_API int SQLITE_STDCALL sqlite3_column_bytes16(sqlite3_stmt *pStmt, int i){
    ++SQLITE_API int sqlite3_column_bytes16(sqlite3_stmt *pStmt, int i){
    +   int val = sqlite3_value_bytes16( columnMem(pStmt,i) );
    +   columnMallocFailure(pStmt);
    +   return val;
    + }
    +-SQLITE_API double SQLITE_STDCALL sqlite3_column_double(sqlite3_stmt *pStmt, int i){
    ++SQLITE_API double sqlite3_column_double(sqlite3_stmt *pStmt, int i){
    +   double val = sqlite3_value_double( columnMem(pStmt,i) );
    +   columnMallocFailure(pStmt);
    +   return val;
    + }
    +-SQLITE_API int SQLITE_STDCALL sqlite3_column_int(sqlite3_stmt *pStmt, int i){
    ++SQLITE_API int sqlite3_column_int(sqlite3_stmt *pStmt, int i){
    +   int val = sqlite3_value_int( columnMem(pStmt,i) );
    +   columnMallocFailure(pStmt);
    +   return val;
    + }
    +-SQLITE_API sqlite_int64 SQLITE_STDCALL sqlite3_column_int64(sqlite3_stmt *pStmt, int i){
    ++SQLITE_API sqlite_int64 sqlite3_column_int64(sqlite3_stmt *pStmt, int i){
    +   sqlite_int64 val = sqlite3_value_int64( columnMem(pStmt,i) );
    +   columnMallocFailure(pStmt);
    +   return val;
    + }
    +-SQLITE_API const unsigned char *SQLITE_STDCALL sqlite3_column_text(sqlite3_stmt *pStmt, int i){
    ++SQLITE_API const unsigned char *sqlite3_column_text(sqlite3_stmt *pStmt, int i){
    +   const unsigned char *val = sqlite3_value_text( columnMem(pStmt,i) );
    +   columnMallocFailure(pStmt);
    +   return val;
    + }
    +-SQLITE_API sqlite3_value *SQLITE_STDCALL sqlite3_column_value(sqlite3_stmt *pStmt, int i){
    ++SQLITE_API sqlite3_value *sqlite3_column_value(sqlite3_stmt *pStmt, int i){
    +   Mem *pOut = columnMem(pStmt, i);
    +   if( pOut->flags&MEM_Static ){
    +     pOut->flags &= ~MEM_Static;
    +@@ -71988,13 +78822,13 @@ SQLITE_API sqlite3_value *SQLITE_STDCALL sqlite3_column_value(sqlite3_stmt *pStm
    +   return (sqlite3_value *)pOut;
    + }
    + #ifndef SQLITE_OMIT_UTF16
    +-SQLITE_API const void *SQLITE_STDCALL sqlite3_column_text16(sqlite3_stmt *pStmt, int i){
    ++SQLITE_API const void *sqlite3_column_text16(sqlite3_stmt *pStmt, int i){
    +   const void *val = sqlite3_value_text16( columnMem(pStmt,i) );
    +   columnMallocFailure(pStmt);
    +   return val;
    + }
    + #endif /* SQLITE_OMIT_UTF16 */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_column_type(sqlite3_stmt *pStmt, int i){
    ++SQLITE_API int sqlite3_column_type(sqlite3_stmt *pStmt, int i){
    +   int iType = sqlite3_value_type( columnMem(pStmt,i) );
    +   columnMallocFailure(pStmt);
    +   return iType;
    +@@ -72046,7 +78880,7 @@ static const void *columnName(
    +     ** is the case, clear the mallocFailed flag and return NULL.
    +     */
    +     if( db->mallocFailed ){
    +-      db->mallocFailed = 0;
    ++      sqlite3OomClear(db);
    +       ret = 0;
    +     }
    +     sqlite3_mutex_leave(db->mutex);
    +@@ -72058,12 +78892,12 @@ static const void *columnName(
    + ** Return the name of the Nth column of the result set returned by SQL
    + ** statement pStmt.
    + */
    +-SQLITE_API const char *SQLITE_STDCALL sqlite3_column_name(sqlite3_stmt *pStmt, int N){
    ++SQLITE_API const char *sqlite3_column_name(sqlite3_stmt *pStmt, int N){
    +   return columnName(
    +       pStmt, N, (const void*(*)(Mem*))sqlite3_value_text, COLNAME_NAME);
    + }
    + #ifndef SQLITE_OMIT_UTF16
    +-SQLITE_API const void *SQLITE_STDCALL sqlite3_column_name16(sqlite3_stmt *pStmt, int N){
    ++SQLITE_API const void *sqlite3_column_name16(sqlite3_stmt *pStmt, int N){
    +   return columnName(
    +       pStmt, N, (const void*(*)(Mem*))sqlite3_value_text16, COLNAME_NAME);
    + }
    +@@ -72083,12 +78917,12 @@ SQLITE_API const void *SQLITE_STDCALL sqlite3_column_name16(sqlite3_stmt *pStmt,
    + ** Return the column declaration type (if applicable) of the 'i'th column
    + ** of the result set of SQL statement pStmt.
    + */
    +-SQLITE_API const char *SQLITE_STDCALL sqlite3_column_decltype(sqlite3_stmt *pStmt, int N){
    ++SQLITE_API const char *sqlite3_column_decltype(sqlite3_stmt *pStmt, int N){
    +   return columnName(
    +       pStmt, N, (const void*(*)(Mem*))sqlite3_value_text, COLNAME_DECLTYPE);
    + }
    + #ifndef SQLITE_OMIT_UTF16
    +-SQLITE_API const void *SQLITE_STDCALL sqlite3_column_decltype16(sqlite3_stmt *pStmt, int N){
    ++SQLITE_API const void *sqlite3_column_decltype16(sqlite3_stmt *pStmt, int N){
    +   return columnName(
    +       pStmt, N, (const void*(*)(Mem*))sqlite3_value_text16, COLNAME_DECLTYPE);
    + }
    +@@ -72101,12 +78935,12 @@ SQLITE_API const void *SQLITE_STDCALL sqlite3_column_decltype16(sqlite3_stmt *pS
    + ** NULL is returned if the result column is an expression or constant or
    + ** anything else which is not an unambiguous reference to a database column.
    + */
    +-SQLITE_API const char *SQLITE_STDCALL sqlite3_column_database_name(sqlite3_stmt *pStmt, int N){
    ++SQLITE_API const char *sqlite3_column_database_name(sqlite3_stmt *pStmt, int N){
    +   return columnName(
    +       pStmt, N, (const void*(*)(Mem*))sqlite3_value_text, COLNAME_DATABASE);
    + }
    + #ifndef SQLITE_OMIT_UTF16
    +-SQLITE_API const void *SQLITE_STDCALL sqlite3_column_database_name16(sqlite3_stmt *pStmt, int N){
    ++SQLITE_API const void *sqlite3_column_database_name16(sqlite3_stmt *pStmt, int N){
    +   return columnName(
    +       pStmt, N, (const void*(*)(Mem*))sqlite3_value_text16, COLNAME_DATABASE);
    + }
    +@@ -72117,12 +78951,12 @@ SQLITE_API const void *SQLITE_STDCALL sqlite3_column_database_name16(sqlite3_stm
    + ** NULL is returned if the result column is an expression or constant or
    + ** anything else which is not an unambiguous reference to a database column.
    + */
    +-SQLITE_API const char *SQLITE_STDCALL sqlite3_column_table_name(sqlite3_stmt *pStmt, int N){
    ++SQLITE_API const char *sqlite3_column_table_name(sqlite3_stmt *pStmt, int N){
    +   return columnName(
    +       pStmt, N, (const void*(*)(Mem*))sqlite3_value_text, COLNAME_TABLE);
    + }
    + #ifndef SQLITE_OMIT_UTF16
    +-SQLITE_API const void *SQLITE_STDCALL sqlite3_column_table_name16(sqlite3_stmt *pStmt, int N){
    ++SQLITE_API const void *sqlite3_column_table_name16(sqlite3_stmt *pStmt, int N){
    +   return columnName(
    +       pStmt, N, (const void*(*)(Mem*))sqlite3_value_text16, COLNAME_TABLE);
    + }
    +@@ -72133,12 +78967,12 @@ SQLITE_API const void *SQLITE_STDCALL sqlite3_column_table_name16(sqlite3_stmt *
    + ** NULL is returned if the result column is an expression or constant or
    + ** anything else which is not an unambiguous reference to a database column.
    + */
    +-SQLITE_API const char *SQLITE_STDCALL sqlite3_column_origin_name(sqlite3_stmt *pStmt, int N){
    ++SQLITE_API const char *sqlite3_column_origin_name(sqlite3_stmt *pStmt, int N){
    +   return columnName(
    +       pStmt, N, (const void*(*)(Mem*))sqlite3_value_text, COLNAME_COLUMN);
    + }
    + #ifndef SQLITE_OMIT_UTF16
    +-SQLITE_API const void *SQLITE_STDCALL sqlite3_column_origin_name16(sqlite3_stmt *pStmt, int N){
    ++SQLITE_API const void *sqlite3_column_origin_name16(sqlite3_stmt *pStmt, int N){
    +   return columnName(
    +       pStmt, N, (const void*(*)(Mem*))sqlite3_value_text16, COLNAME_COLUMN);
    + }
    +@@ -72194,9 +79028,8 @@ static int vdbeUnbind(Vdbe *p, int i){
    +   ** as if there had been a schema change, on the first sqlite3_step() call
    +   ** following any change to the bindings of that parameter.
    +   */
    +-  if( p->isPrepareV2 &&
    +-     ((i<32 && p->expmask & ((u32)1 << i)) || p->expmask==0xffffffff)
    +-  ){
    ++  assert( (p->prepFlags & SQLITE_PREPARE_SAVESQL)!=0 || p->expmask==0 );
    ++  if( p->expmask!=0 && (p->expmask & (i>=31 ? 0x80000000 : (u32)1<<i))!=0 ){
    +     p->expired = 1;
    +   }
    +   return SQLITE_OK;
    +@@ -72225,8 +79058,10 @@ static int bindText(
    +       if( rc==SQLITE_OK && encoding!=0 ){
    +         rc = sqlite3VdbeChangeEncoding(pVar, ENC(p->db));
    +       }
    +-      sqlite3Error(p->db, rc);
    +-      rc = sqlite3ApiExit(p->db, rc);
    ++      if( rc ){
    ++        sqlite3Error(p->db, rc);
    ++        rc = sqlite3ApiExit(p->db, rc);
    ++      }
    +     }
    +     sqlite3_mutex_leave(p->db->mutex);
    +   }else if( xDel!=SQLITE_STATIC && xDel!=SQLITE_TRANSIENT ){
    +@@ -72239,16 +79074,19 @@ static int bindText(
    + /*
    + ** Bind a blob value to an SQL statement variable.
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_bind_blob(
    ++SQLITE_API int sqlite3_bind_blob(
    +   sqlite3_stmt *pStmt, 
    +   int i, 
    +   const void *zData, 
    +   int nData, 
    +   void (*xDel)(void*)
    + ){
    ++#ifdef SQLITE_ENABLE_API_ARMOR
    ++  if( nData<0 ) return SQLITE_MISUSE_BKPT;
    ++#endif
    +   return bindText(pStmt, i, zData, nData, xDel, 0);
    + }
    +-SQLITE_API int SQLITE_STDCALL sqlite3_bind_blob64(
    ++SQLITE_API int sqlite3_bind_blob64(
    +   sqlite3_stmt *pStmt, 
    +   int i, 
    +   const void *zData, 
    +@@ -72262,7 +79100,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_bind_blob64(
    +     return bindText(pStmt, i, zData, (int)nData, xDel, 0);
    +   }
    + }
    +-SQLITE_API int SQLITE_STDCALL sqlite3_bind_double(sqlite3_stmt *pStmt, int i, double rValue){
    ++SQLITE_API int sqlite3_bind_double(sqlite3_stmt *pStmt, int i, double rValue){
    +   int rc;
    +   Vdbe *p = (Vdbe *)pStmt;
    +   rc = vdbeUnbind(p, i);
    +@@ -72272,10 +79110,10 @@ SQLITE_API int SQLITE_STDCALL sqlite3_bind_double(sqlite3_stmt *pStmt, int i, do
    +   }
    +   return rc;
    + }
    +-SQLITE_API int SQLITE_STDCALL sqlite3_bind_int(sqlite3_stmt *p, int i, int iValue){
    ++SQLITE_API int sqlite3_bind_int(sqlite3_stmt *p, int i, int iValue){
    +   return sqlite3_bind_int64(p, i, (i64)iValue);
    + }
    +-SQLITE_API int SQLITE_STDCALL sqlite3_bind_int64(sqlite3_stmt *pStmt, int i, sqlite_int64 iValue){
    ++SQLITE_API int sqlite3_bind_int64(sqlite3_stmt *pStmt, int i, sqlite_int64 iValue){
    +   int rc;
    +   Vdbe *p = (Vdbe *)pStmt;
    +   rc = vdbeUnbind(p, i);
    +@@ -72285,16 +79123,34 @@ SQLITE_API int SQLITE_STDCALL sqlite3_bind_int64(sqlite3_stmt *pStmt, int i, sql
    +   }
    +   return rc;
    + }
    +-SQLITE_API int SQLITE_STDCALL sqlite3_bind_null(sqlite3_stmt *pStmt, int i){
    ++SQLITE_API int sqlite3_bind_null(sqlite3_stmt *pStmt, int i){
    ++  int rc;
    ++  Vdbe *p = (Vdbe*)pStmt;
    ++  rc = vdbeUnbind(p, i);
    ++  if( rc==SQLITE_OK ){
    ++    sqlite3_mutex_leave(p->db->mutex);
    ++  }
    ++  return rc;
    ++}
    ++SQLITE_API int sqlite3_bind_pointer(
    ++  sqlite3_stmt *pStmt,
    ++  int i,
    ++  void *pPtr,
    ++  const char *zPTtype,
    ++  void (*xDestructor)(void*)
    ++){
    +   int rc;
    +   Vdbe *p = (Vdbe*)pStmt;
    +   rc = vdbeUnbind(p, i);
    +   if( rc==SQLITE_OK ){
    ++    sqlite3VdbeMemSetPointer(&p->aVar[i-1], pPtr, zPTtype, xDestructor);
    +     sqlite3_mutex_leave(p->db->mutex);
    ++  }else if( xDestructor ){
    ++    xDestructor(pPtr);
    +   }
    +   return rc;
    + }
    +-SQLITE_API int SQLITE_STDCALL sqlite3_bind_text( 
    ++SQLITE_API int sqlite3_bind_text( 
    +   sqlite3_stmt *pStmt, 
    +   int i, 
    +   const char *zData, 
    +@@ -72303,7 +79159,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_bind_text(
    + ){
    +   return bindText(pStmt, i, zData, nData, xDel, SQLITE_UTF8);
    + }
    +-SQLITE_API int SQLITE_STDCALL sqlite3_bind_text64( 
    ++SQLITE_API int sqlite3_bind_text64( 
    +   sqlite3_stmt *pStmt, 
    +   int i, 
    +   const char *zData, 
    +@@ -72320,7 +79176,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_bind_text64(
    +   }
    + }
    + #ifndef SQLITE_OMIT_UTF16
    +-SQLITE_API int SQLITE_STDCALL sqlite3_bind_text16(
    ++SQLITE_API int sqlite3_bind_text16(
    +   sqlite3_stmt *pStmt, 
    +   int i, 
    +   const void *zData, 
    +@@ -72330,7 +79186,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_bind_text16(
    +   return bindText(pStmt, i, zData, nData, xDel, SQLITE_UTF16NATIVE);
    + }
    + #endif /* SQLITE_OMIT_UTF16 */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_bind_value(sqlite3_stmt *pStmt, int i, const sqlite3_value *pValue){
    ++SQLITE_API int sqlite3_bind_value(sqlite3_stmt *pStmt, int i, const sqlite3_value *pValue){
    +   int rc;
    +   switch( sqlite3_value_type((sqlite3_value*)pValue) ){
    +     case SQLITE_INTEGER: {
    +@@ -72361,7 +79217,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_bind_value(sqlite3_stmt *pStmt, int i, con
    +   }
    +   return rc;
    + }
    +-SQLITE_API int SQLITE_STDCALL sqlite3_bind_zeroblob(sqlite3_stmt *pStmt, int i, int n){
    ++SQLITE_API int sqlite3_bind_zeroblob(sqlite3_stmt *pStmt, int i, int n){
    +   int rc;
    +   Vdbe *p = (Vdbe *)pStmt;
    +   rc = vdbeUnbind(p, i);
    +@@ -72371,7 +79227,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_bind_zeroblob(sqlite3_stmt *pStmt, int i,
    +   }
    +   return rc;
    + }
    +-SQLITE_API int SQLITE_STDCALL sqlite3_bind_zeroblob64(sqlite3_stmt *pStmt, int i, sqlite3_uint64 n){
    ++SQLITE_API int sqlite3_bind_zeroblob64(sqlite3_stmt *pStmt, int i, sqlite3_uint64 n){
    +   int rc;
    +   Vdbe *p = (Vdbe *)pStmt;
    +   sqlite3_mutex_enter(p->db->mutex);
    +@@ -72390,7 +79246,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_bind_zeroblob64(sqlite3_stmt *pStmt, int i
    + ** Return the number of wildcards that can be potentially bound to.
    + ** This routine is added to support DBD::SQLite.  
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_bind_parameter_count(sqlite3_stmt *pStmt){
    ++SQLITE_API int sqlite3_bind_parameter_count(sqlite3_stmt *pStmt){
    +   Vdbe *p = (Vdbe*)pStmt;
    +   return p ? p->nVar : 0;
    + }
    +@@ -72401,12 +79257,10 @@ SQLITE_API int SQLITE_STDCALL sqlite3_bind_parameter_count(sqlite3_stmt *pStmt){
    + **
    + ** The result is always UTF-8.
    + */
    +-SQLITE_API const char *SQLITE_STDCALL sqlite3_bind_parameter_name(sqlite3_stmt *pStmt, int i){
    ++SQLITE_API const char *sqlite3_bind_parameter_name(sqlite3_stmt *pStmt, int i){
    +   Vdbe *p = (Vdbe*)pStmt;
    +-  if( p==0 || i<1 || i>p->nzVar ){
    +-    return 0;
    +-  }
    +-  return p->azVar[i-1];
    ++  if( p==0 ) return 0;
    ++  return sqlite3VListNumToName(p->pVList, i);
    + }
    + 
    + /*
    +@@ -72415,21 +79269,10 @@ SQLITE_API const char *SQLITE_STDCALL sqlite3_bind_parameter_name(sqlite3_stmt *
    + ** return 0.
    + */
    + SQLITE_PRIVATE int sqlite3VdbeParameterIndex(Vdbe *p, const char *zName, int nName){
    +-  int i;
    +-  if( p==0 ){
    +-    return 0;
    +-  }
    +-  if( zName ){
    +-    for(i=0; i<p->nzVar; i++){
    +-      const char *z = p->azVar[i];
    +-      if( z && strncmp(z,zName,nName)==0 && z[nName]==0 ){
    +-        return i+1;
    +-      }
    +-    }
    +-  }
    +-  return 0;
    ++  if( p==0 || zName==0 ) return 0;
    ++  return sqlite3VListNameToNum(p->pVList, zName, nName);
    + }
    +-SQLITE_API int SQLITE_STDCALL sqlite3_bind_parameter_index(sqlite3_stmt *pStmt, const char *zName){
    ++SQLITE_API int sqlite3_bind_parameter_index(sqlite3_stmt *pStmt, const char *zName){
    +   return sqlite3VdbeParameterIndex((Vdbe*)pStmt, zName, sqlite3Strlen30(zName));
    + }
    + 
    +@@ -72463,16 +79306,18 @@ SQLITE_PRIVATE int sqlite3TransferBindings(sqlite3_stmt *pFromStmt, sqlite3_stmt
    + ** an SQLITE_ERROR is returned.  Nothing else can go wrong, so otherwise
    + ** SQLITE_OK is returned.
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_transfer_bindings(sqlite3_stmt *pFromStmt, sqlite3_stmt *pToStmt){
    ++SQLITE_API int sqlite3_transfer_bindings(sqlite3_stmt *pFromStmt, sqlite3_stmt *pToStmt){
    +   Vdbe *pFrom = (Vdbe*)pFromStmt;
    +   Vdbe *pTo = (Vdbe*)pToStmt;
    +   if( pFrom->nVar!=pTo->nVar ){
    +     return SQLITE_ERROR;
    +   }
    +-  if( pTo->isPrepareV2 && pTo->expmask ){
    ++  assert( (pTo->prepFlags & SQLITE_PREPARE_SAVESQL)!=0 || pTo->expmask==0 );
    ++  if( pTo->expmask ){
    +     pTo->expired = 1;
    +   }
    +-  if( pFrom->isPrepareV2 && pFrom->expmask ){
    ++  assert( (pFrom->prepFlags & SQLITE_PREPARE_SAVESQL)!=0 || pFrom->expmask==0 );
    ++  if( pFrom->expmask ){
    +     pFrom->expired = 1;
    +   }
    +   return sqlite3TransferBindings(pFromStmt, pToStmt);
    +@@ -72485,7 +79330,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_transfer_bindings(sqlite3_stmt *pFromStmt,
    + ** the first argument to the sqlite3_prepare() that was used to create
    + ** the statement in the first place.
    + */
    +-SQLITE_API sqlite3 *SQLITE_STDCALL sqlite3_db_handle(sqlite3_stmt *pStmt){
    ++SQLITE_API sqlite3 *sqlite3_db_handle(sqlite3_stmt *pStmt){
    +   return pStmt ? ((Vdbe*)pStmt)->db : 0;
    + }
    + 
    +@@ -72493,16 +79338,16 @@ SQLITE_API sqlite3 *SQLITE_STDCALL sqlite3_db_handle(sqlite3_stmt *pStmt){
    + ** Return true if the prepared statement is guaranteed to not modify the
    + ** database.
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_stmt_readonly(sqlite3_stmt *pStmt){
    ++SQLITE_API int sqlite3_stmt_readonly(sqlite3_stmt *pStmt){
    +   return pStmt ? ((Vdbe*)pStmt)->readOnly : 1;
    + }
    + 
    + /*
    + ** Return true if the prepared statement is in need of being reset.
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_stmt_busy(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->magic==VDBE_MAGIC_RUN && v->pc>=0;
    + }
    + 
    + /*
    +@@ -72511,7 +79356,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_stmt_busy(sqlite3_stmt *pStmt){
    + ** prepared statement for the database connection.  Return NULL if there
    + ** are no more.
    + */
    +-SQLITE_API sqlite3_stmt *SQLITE_STDCALL sqlite3_next_stmt(sqlite3 *pDb, sqlite3_stmt *pStmt){
    ++SQLITE_API sqlite3_stmt *sqlite3_next_stmt(sqlite3 *pDb, sqlite3_stmt *pStmt){
    +   sqlite3_stmt *pNext;
    + #ifdef SQLITE_ENABLE_API_ARMOR
    +   if( !sqlite3SafetyCheckOk(pDb) ){
    +@@ -72532,7 +79377,7 @@ SQLITE_API sqlite3_stmt *SQLITE_STDCALL sqlite3_next_stmt(sqlite3 *pDb, sqlite3_
    + /*
    + ** Return the value of a status counter for a prepared statement
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_stmt_status(sqlite3_stmt *pStmt, int op, int resetFlag){
    ++SQLITE_API int sqlite3_stmt_status(sqlite3_stmt *pStmt, int op, int resetFlag){
    +   Vdbe *pVdbe = (Vdbe*)pStmt;
    +   u32 v;
    + #ifdef SQLITE_ENABLE_API_ARMOR
    +@@ -72541,16 +79386,246 @@ SQLITE_API int SQLITE_STDCALL sqlite3_stmt_status(sqlite3_stmt *pStmt, int op, i
    +     return 0;
    +   }
    + #endif
    +-  v = pVdbe->aCounter[op];
    +-  if( resetFlag ) pVdbe->aCounter[op] = 0;
    ++  if( op==SQLITE_STMTSTATUS_MEMUSED ){
    ++    sqlite3 *db = pVdbe->db;
    ++    sqlite3_mutex_enter(db->mutex);
    ++    v = 0;
    ++    db->pnBytesFreed = (int*)&v;
    ++    sqlite3VdbeClearObject(db, pVdbe);
    ++    sqlite3DbFree(db, pVdbe);
    ++    db->pnBytesFreed = 0;
    ++    sqlite3_mutex_leave(db->mutex);
    ++  }else{
    ++    v = pVdbe->aCounter[op];
    ++    if( resetFlag ) pVdbe->aCounter[op] = 0;
    ++  }
    +   return (int)v;
    + }
    + 
    ++/*
    ++** Return the SQL associated with a prepared statement
    ++*/
    ++SQLITE_API const char *sqlite3_sql(sqlite3_stmt *pStmt){
    ++  Vdbe *p = (Vdbe *)pStmt;
    ++  return p ? p->zSql : 0;
    ++}
    ++
    ++/*
    ++** Return the SQL associated with a prepared statement with
    ++** bound parameters expanded.  Space to hold the returned string is
    ++** obtained from sqlite3_malloc().  The caller is responsible for
    ++** freeing the returned string by passing it to sqlite3_free().
    ++**
    ++** The SQLITE_TRACE_SIZE_LIMIT puts an upper bound on the size of
    ++** expanded bound parameters.
    ++*/
    ++SQLITE_API char *sqlite3_expanded_sql(sqlite3_stmt *pStmt){
    ++#ifdef SQLITE_OMIT_TRACE
    ++  return 0;
    ++#else
    ++  char *z = 0;
    ++  const char *zSql = sqlite3_sql(pStmt);
    ++  if( zSql ){
    ++    Vdbe *p = (Vdbe *)pStmt;
    ++    sqlite3_mutex_enter(p->db->mutex);
    ++    z = sqlite3VdbeExpandSql(p, zSql);
    ++    sqlite3_mutex_leave(p->db->mutex);
    ++  }
    ++  return z;
    ++#endif
    ++}
    ++
    ++#ifdef SQLITE_ENABLE_PREUPDATE_HOOK
    ++/*
    ++** Allocate and populate an UnpackedRecord structure based on the serialized
    ++** record in nKey/pKey. Return a pointer to the new UnpackedRecord structure
    ++** if successful, or a NULL pointer if an OOM error is encountered.
    ++*/
    ++static UnpackedRecord *vdbeUnpackRecord(
    ++  KeyInfo *pKeyInfo, 
    ++  int nKey, 
    ++  const void *pKey
    ++){
    ++  UnpackedRecord *pRet;           /* Return value */
    ++
    ++  pRet = sqlite3VdbeAllocUnpackedRecord(pKeyInfo);
    ++  if( pRet ){
    ++    memset(pRet->aMem, 0, sizeof(Mem)*(pKeyInfo->nKeyField+1));
    ++    sqlite3VdbeRecordUnpack(pKeyInfo, nKey, pKey, pRet);
    ++  }
    ++  return pRet;
    ++}
    ++
    ++/*
    ++** This function is called from within a pre-update callback to retrieve
    ++** a field of the row currently being updated or deleted.
    ++*/
    ++SQLITE_API int sqlite3_preupdate_old(sqlite3 *db, int iIdx, sqlite3_value **ppValue){
    ++  PreUpdate *p = db->pPreUpdate;
    ++  Mem *pMem;
    ++  int rc = SQLITE_OK;
    ++
    ++  /* Test that this call is being made from within an SQLITE_DELETE or
    ++  ** SQLITE_UPDATE pre-update callback, and that iIdx is within range. */
    ++  if( !p || p->op==SQLITE_INSERT ){
    ++    rc = SQLITE_MISUSE_BKPT;
    ++    goto preupdate_old_out;
    ++  }
    ++  if( p->pPk ){
    ++    iIdx = sqlite3ColumnOfIndex(p->pPk, iIdx);
    ++  }
    ++  if( iIdx>=p->pCsr->nField || iIdx<0 ){
    ++    rc = SQLITE_RANGE;
    ++    goto preupdate_old_out;
    ++  }
    ++
    ++  /* If the old.* record has not yet been loaded into memory, do so now. */
    ++  if( p->pUnpacked==0 ){
    ++    u32 nRec;
    ++    u8 *aRec;
    ++
    ++    nRec = sqlite3BtreePayloadSize(p->pCsr->uc.pCursor);
    ++    aRec = sqlite3DbMallocRaw(db, nRec);
    ++    if( !aRec ) goto preupdate_old_out;
    ++    rc = sqlite3BtreePayload(p->pCsr->uc.pCursor, 0, nRec, aRec);
    ++    if( rc==SQLITE_OK ){
    ++      p->pUnpacked = vdbeUnpackRecord(&p->keyinfo, nRec, aRec);
    ++      if( !p->pUnpacked ) rc = SQLITE_NOMEM;
    ++    }
    ++    if( rc!=SQLITE_OK ){
    ++      sqlite3DbFree(db, aRec);
    ++      goto preupdate_old_out;
    ++    }
    ++    p->aRecord = aRec;
    ++  }
    ++
    ++  pMem = *ppValue = &p->pUnpacked->aMem[iIdx];
    ++  if( iIdx==p->pTab->iPKey ){
    ++    sqlite3VdbeMemSetInt64(pMem, p->iKey1);
    ++  }else if( iIdx>=p->pUnpacked->nField ){
    ++    *ppValue = (sqlite3_value *)columnNullValue();
    ++  }else if( p->pTab->aCol[iIdx].affinity==SQLITE_AFF_REAL ){
    ++    if( pMem->flags & MEM_Int ){
    ++      sqlite3VdbeMemRealify(pMem);
    ++    }
    ++  }
    ++
    ++ preupdate_old_out:
    ++  sqlite3Error(db, rc);
    ++  return sqlite3ApiExit(db, rc);
    ++}
    ++#endif /* SQLITE_ENABLE_PREUPDATE_HOOK */
    ++
    ++#ifdef SQLITE_ENABLE_PREUPDATE_HOOK
    ++/*
    ++** This function is called from within a pre-update callback to retrieve
    ++** the number of columns in the row being updated, deleted or inserted.
    ++*/
    ++SQLITE_API int sqlite3_preupdate_count(sqlite3 *db){
    ++  PreUpdate *p = db->pPreUpdate;
    ++  return (p ? p->keyinfo.nKeyField : 0);
    ++}
    ++#endif /* SQLITE_ENABLE_PREUPDATE_HOOK */
    ++
    ++#ifdef SQLITE_ENABLE_PREUPDATE_HOOK
    ++/*
    ++** This function is designed to be called from within a pre-update callback
    ++** only. It returns zero if the change that caused the callback was made
    ++** immediately by a user SQL statement. Or, if the change was made by a
    ++** trigger program, it returns the number of trigger programs currently
    ++** on the stack (1 for a top-level trigger, 2 for a trigger fired by a 
    ++** top-level trigger etc.).
    ++**
    ++** For the purposes of the previous paragraph, a foreign key CASCADE, SET NULL
    ++** or SET DEFAULT action is considered a trigger.
    ++*/
    ++SQLITE_API int sqlite3_preupdate_depth(sqlite3 *db){
    ++  PreUpdate *p = db->pPreUpdate;
    ++  return (p ? p->v->nFrame : 0);
    ++}
    ++#endif /* SQLITE_ENABLE_PREUPDATE_HOOK */
    ++
    ++#ifdef SQLITE_ENABLE_PREUPDATE_HOOK
    ++/*
    ++** This function is called from within a pre-update callback to retrieve
    ++** a field of the row currently being updated or inserted.
    ++*/
    ++SQLITE_API int sqlite3_preupdate_new(sqlite3 *db, int iIdx, sqlite3_value **ppValue){
    ++  PreUpdate *p = db->pPreUpdate;
    ++  int rc = SQLITE_OK;
    ++  Mem *pMem;
    ++
    ++  if( !p || p->op==SQLITE_DELETE ){
    ++    rc = SQLITE_MISUSE_BKPT;
    ++    goto preupdate_new_out;
    ++  }
    ++  if( p->pPk && p->op!=SQLITE_UPDATE ){
    ++    iIdx = sqlite3ColumnOfIndex(p->pPk, iIdx);
    ++  }
    ++  if( iIdx>=p->pCsr->nField || iIdx<0 ){
    ++    rc = SQLITE_RANGE;
    ++    goto preupdate_new_out;
    ++  }
    ++
    ++  if( p->op==SQLITE_INSERT ){
    ++    /* For an INSERT, memory cell p->iNewReg contains the serialized record
    ++    ** that is being inserted. Deserialize it. */
    ++    UnpackedRecord *pUnpack = p->pNewUnpacked;
    ++    if( !pUnpack ){
    ++      Mem *pData = &p->v->aMem[p->iNewReg];
    ++      rc = ExpandBlob(pData);
    ++      if( rc!=SQLITE_OK ) goto preupdate_new_out;
    ++      pUnpack = vdbeUnpackRecord(&p->keyinfo, pData->n, pData->z);
    ++      if( !pUnpack ){
    ++        rc = SQLITE_NOMEM;
    ++        goto preupdate_new_out;
    ++      }
    ++      p->pNewUnpacked = pUnpack;
    ++    }
    ++    pMem = &pUnpack->aMem[iIdx];
    ++    if( iIdx==p->pTab->iPKey ){
    ++      sqlite3VdbeMemSetInt64(pMem, p->iKey2);
    ++    }else if( iIdx>=pUnpack->nField ){
    ++      pMem = (sqlite3_value *)columnNullValue();
    ++    }
    ++  }else{
    ++    /* For an UPDATE, memory cell (p->iNewReg+1+iIdx) contains the required
    ++    ** value. Make a copy of the cell contents and return a pointer to it.
    ++    ** It is not safe to return a pointer to the memory cell itself as the
    ++    ** caller may modify the value text encoding.
    ++    */
    ++    assert( p->op==SQLITE_UPDATE );
    ++    if( !p->aNew ){
    ++      p->aNew = (Mem *)sqlite3DbMallocZero(db, sizeof(Mem) * p->pCsr->nField);
    ++      if( !p->aNew ){
    ++        rc = SQLITE_NOMEM;
    ++        goto preupdate_new_out;
    ++      }
    ++    }
    ++    assert( iIdx>=0 && iIdx<p->pCsr->nField );
    ++    pMem = &p->aNew[iIdx];
    ++    if( pMem->flags==0 ){
    ++      if( iIdx==p->pTab->iPKey ){
    ++        sqlite3VdbeMemSetInt64(pMem, p->iKey2);
    ++      }else{
    ++        rc = sqlite3VdbeMemCopy(pMem, &p->v->aMem[p->iNewReg+1+iIdx]);
    ++        if( rc!=SQLITE_OK ) goto preupdate_new_out;
    ++      }
    ++    }
    ++  }
    ++  *ppValue = pMem;
    ++
    ++ preupdate_new_out:
    ++  sqlite3Error(db, rc);
    ++  return sqlite3ApiExit(db, rc);
    ++}
    ++#endif /* SQLITE_ENABLE_PREUPDATE_HOOK */
    ++
    + #ifdef SQLITE_ENABLE_STMT_SCANSTATUS
    + /*
    + ** Return status data for a single loop within query pStmt.
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_stmt_scanstatus(
    ++SQLITE_API int sqlite3_stmt_scanstatus(
    +   sqlite3_stmt *pStmt,            /* Prepared statement being queried */
    +   int idx,                        /* Index of loop to report on */
    +   int iScanStatusOp,              /* Which metric to return */
    +@@ -72609,7 +79684,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_stmt_scanstatus(
    + /*
    + ** Zero all counters associated with the sqlite3_stmt_scanstatus() data.
    + */
    +-SQLITE_API void SQLITE_STDCALL sqlite3_stmt_scanstatus_reset(sqlite3_stmt *pStmt){
    ++SQLITE_API void sqlite3_stmt_scanstatus_reset(sqlite3_stmt *pStmt){
    +   Vdbe *p = (Vdbe*)pStmt;
    +   memset(p->anExec, 0, p->nOp * sizeof(i64));
    + }
    +@@ -72700,10 +79775,13 @@ SQLITE_PRIVATE char *sqlite3VdbeExpandSql(
    +   int i;                   /* Loop counter */
    +   Mem *pVar;               /* Value of a host parameter */
    +   StrAccum out;            /* Accumulate the output here */
    ++#ifndef SQLITE_OMIT_UTF16
    ++  Mem utf8;                /* Used to convert UTF16 into UTF8 for display */
    ++#endif
    +   char zBase[100];         /* Initial working space */
    + 
    +   db = p->db;
    +-  sqlite3StrAccumInit(&out, db, zBase, sizeof(zBase), 
    ++  sqlite3StrAccumInit(&out, 0, zBase, sizeof(zBase), 
    +                       db->aLimit[SQLITE_LIMIT_LENGTH]);
    +   if( db->nVdbeExec>1 ){
    +     while( *zRawSql ){
    +@@ -72747,19 +79825,21 @@ SQLITE_PRIVATE char *sqlite3VdbeExpandSql(
    +       if( pVar->flags & MEM_Null ){
    +         sqlite3StrAccumAppend(&out, "NULL", 4);
    +       }else if( pVar->flags & MEM_Int ){
    +-        sqlite3XPrintf(&out, 0, "%lld", pVar->u.i);
    ++        sqlite3XPrintf(&out, "%lld", pVar->u.i);
    +       }else if( pVar->flags & MEM_Real ){
    +-        sqlite3XPrintf(&out, 0, "%!.15g", pVar->u.r);
    ++        sqlite3XPrintf(&out, "%!.15g", pVar->u.r);
    +       }else if( pVar->flags & MEM_Str ){
    +         int nOut;  /* Number of bytes of the string text to include in output */
    + #ifndef SQLITE_OMIT_UTF16
    +         u8 enc = ENC(db);
    +-        Mem utf8;
    +         if( enc!=SQLITE_UTF8 ){
    +           memset(&utf8, 0, sizeof(utf8));
    +           utf8.db = db;
    +           sqlite3VdbeMemSetStr(&utf8, pVar->z, pVar->n, enc, SQLITE_STATIC);
    +-          sqlite3VdbeChangeEncoding(&utf8, SQLITE_UTF8);
    ++          if( SQLITE_NOMEM==sqlite3VdbeChangeEncoding(&utf8, SQLITE_UTF8) ){
    ++            out.accError = STRACCUM_NOMEM;
    ++            out.nAlloc = 0;
    ++          }
    +           pVar = &utf8;
    +         }
    + #endif
    +@@ -72770,17 +79850,17 @@ SQLITE_PRIVATE char *sqlite3VdbeExpandSql(
    +           while( nOut<pVar->n && (pVar->z[nOut]&0xc0)==0x80 ){ nOut++; }
    +         }
    + #endif    
    +-        sqlite3XPrintf(&out, 0, "'%.*q'", nOut, pVar->z);
    ++        sqlite3XPrintf(&out, "'%.*q'", nOut, pVar->z);
    + #ifdef SQLITE_TRACE_SIZE_LIMIT
    +         if( nOut<pVar->n ){
    +-          sqlite3XPrintf(&out, 0, "/*+%d bytes*/", pVar->n-nOut);
    ++          sqlite3XPrintf(&out, "/*+%d bytes*/", pVar->n-nOut);
    +         }
    + #endif
    + #ifndef SQLITE_OMIT_UTF16
    +         if( enc!=SQLITE_UTF8 ) sqlite3VdbeMemRelease(&utf8);
    + #endif
    +       }else if( pVar->flags & MEM_Zero ){
    +-        sqlite3XPrintf(&out, 0, "zeroblob(%d)", pVar->u.nZero);
    ++        sqlite3XPrintf(&out, "zeroblob(%d)", pVar->u.nZero);
    +       }else{
    +         int nOut;  /* Number of bytes of the blob to include in output */
    +         assert( pVar->flags & MEM_Blob );
    +@@ -72790,17 +79870,18 @@ SQLITE_PRIVATE char *sqlite3VdbeExpandSql(
    +         if( nOut>SQLITE_TRACE_SIZE_LIMIT ) nOut = SQLITE_TRACE_SIZE_LIMIT;
    + #endif
    +         for(i=0; i<nOut; i++){
    +-          sqlite3XPrintf(&out, 0, "%02x", pVar->z[i]&0xff);
    ++          sqlite3XPrintf(&out, "%02x", pVar->z[i]&0xff);
    +         }
    +         sqlite3StrAccumAppend(&out, "'", 1);
    + #ifdef SQLITE_TRACE_SIZE_LIMIT
    +         if( nOut<pVar->n ){
    +-          sqlite3XPrintf(&out, 0, "/*+%d bytes*/", pVar->n-nOut);
    ++          sqlite3XPrintf(&out, "/*+%d bytes*/", pVar->n-nOut);
    +         }
    + #endif
    +       }
    +     }
    +   }
    ++  if( out.accError ) sqlite3StrAccumReset(&out);
    +   return sqlite3StrAccumFinish(&out);
    + }
    + 
    +@@ -72896,6 +79977,16 @@ static void updateMaxBlobsize(Mem *p){
    + }
    + #endif
    + 
    ++/*
    ++** This macro evaluates to true if either the update hook or the preupdate
    ++** hook are enabled for database connect DB.
    ++*/
    ++#ifdef SQLITE_ENABLE_PREUPDATE_HOOK
    ++# define HAS_UPDATE_HOOK(DB) ((DB)->xPreUpdateCallback||(DB)->xUpdateCallback)
    ++#else
    ++# define HAS_UPDATE_HOOK(DB) ((DB)->xUpdateCallback)
    ++#endif
    ++
    + /*
    + ** The next global variable is incremented each time the OP_Found opcode
    + ** is executed. This is used to test whether or not the foreign key
    +@@ -72911,7 +80002,7 @@ SQLITE_API int sqlite3_found_count = 0;
    + ** Test a register to see if it exceeds the current maximum blob size.
    + ** If it does, record the new maximum blob size.
    + */
    +-#if defined(SQLITE_TEST) && !defined(SQLITE_OMIT_BUILTIN_TEST)
    ++#if defined(SQLITE_TEST) && !defined(SQLITE_UNTESTABLE)
    + # define UPDATE_MAX_BLOBSIZE(P)  updateMaxBlobsize(P)
    + #else
    + # define UPDATE_MAX_BLOBSIZE(P)
    +@@ -72975,7 +80066,7 @@ SQLITE_API int sqlite3_found_count = 0;
    +        && sqlite3VdbeMemMakeWriteable(P) ){ goto no_mem;}
    + 
    + /* Return true if the cursor was opened using the OP_OpenSorter opcode. */
    +-#define isSorter(x) ((x)->pSorter!=0)
    ++#define isSorter(x) ((x)->eCurType==CURTYPE_SORTER)
    + 
    + /*
    + ** Allocate VdbeCursor number iCur.  Return a pointer to it.  Return NULL
    +@@ -72986,7 +80077,7 @@ static VdbeCursor *allocateCursor(
    +   int iCur,             /* Index of the new VdbeCursor */
    +   int nField,           /* Number of fields in the table or index */
    +   int iDb,              /* Database the cursor belongs to, or -1 */
    +-  int isBtreeCursor     /* True for B-Tree.  False for pseudo-table or vtab */
    ++  u8 eCurType           /* Type of the new cursor */
    + ){
    +   /* Find the memory cell that will be used to store the blob of memory
    +   ** required for this VdbeCursor structure. It is convenient to use a 
    +@@ -73002,33 +80093,34 @@ static VdbeCursor *allocateCursor(
    +   **     be freed lazily via the sqlite3_release_memory() API. This
    +   **     minimizes the number of malloc calls made by the system.
    +   **
    +-  ** Memory cells for cursors are allocated at the top of the address
    +-  ** space. Memory cell (p->nMem) corresponds to cursor 0. Space for
    +-  ** cursor 1 is managed by memory cell (p->nMem-1), etc.
    ++  ** The memory cell for cursor 0 is aMem[0]. The rest are allocated from
    ++  ** the top of the register space.  Cursor 1 is at Mem[p->nMem-1].
    ++  ** Cursor 2 is at Mem[p->nMem-2]. And so forth.
    +   */
    +-  Mem *pMem = &p->aMem[p->nMem-iCur];
    ++  Mem *pMem = iCur>0 ? &p->aMem[p->nMem-iCur] : p->aMem;
    + 
    +   int nByte;
    +   VdbeCursor *pCx = 0;
    +   nByte = 
    +       ROUND8(sizeof(VdbeCursor)) + 2*sizeof(u32)*nField + 
    +-      (isBtreeCursor?sqlite3BtreeCursorSize():0);
    ++      (eCurType==CURTYPE_BTREE?sqlite3BtreeCursorSize():0);
    + 
    +-  assert( iCur<p->nCursor );
    +-  if( p->apCsr[iCur] ){
    ++  assert( iCur>=0 && iCur<p->nCursor );
    ++  if( p->apCsr[iCur] ){ /*OPTIMIZATION-IF-FALSE*/
    +     sqlite3VdbeFreeCursor(p, p->apCsr[iCur]);
    +     p->apCsr[iCur] = 0;
    +   }
    +   if( SQLITE_OK==sqlite3VdbeMemClearAndResize(pMem, nByte) ){
    +     p->apCsr[iCur] = pCx = (VdbeCursor*)pMem->z;
    +-    memset(pCx, 0, sizeof(VdbeCursor));
    ++    memset(pCx, 0, offsetof(VdbeCursor,pAltCursor));
    ++    pCx->eCurType = eCurType;
    +     pCx->iDb = iDb;
    +     pCx->nField = nField;
    +     pCx->aOffset = &pCx->aType[nField];
    +-    if( isBtreeCursor ){
    +-      pCx->pCursor = (BtCursor*)
    ++    if( eCurType==CURTYPE_BTREE ){
    ++      pCx->uc.pCursor = (BtCursor*)
    +           &pMem->z[ROUND8(sizeof(VdbeCursor))+2*sizeof(u32)*nField];
    +-      sqlite3BtreeCursorZero(pCx->pCursor);
    ++      sqlite3BtreeCursorZero(pCx->uc.pCursor);
    +     }
    +   }
    +   return pCx;
    +@@ -73091,7 +80183,7 @@ static void applyAffinity(
    +   if( affinity>=SQLITE_AFF_NUMERIC ){
    +     assert( affinity==SQLITE_AFF_INTEGER || affinity==SQLITE_AFF_REAL
    +              || affinity==SQLITE_AFF_NUMERIC );
    +-    if( (pRec->flags & MEM_Int)==0 ){
    ++    if( (pRec->flags & MEM_Int)==0 ){ /*OPTIMIZATION-IF-FALSE*/
    +       if( (pRec->flags & MEM_Real)==0 ){
    +         if( pRec->flags & MEM_Str ) applyNumericAffinity(pRec,1);
    +       }else{
    +@@ -73101,10 +80193,13 @@ static void applyAffinity(
    +   }else if( affinity==SQLITE_AFF_TEXT ){
    +     /* Only attempt the conversion to TEXT if there is an integer or real
    +     ** representation (blob and NULL do not get converted) but no string
    +-    ** representation.
    +-    */
    +-    if( 0==(pRec->flags&MEM_Str) && (pRec->flags&(MEM_Real|MEM_Int)) ){
    +-      sqlite3VdbeMemStringify(pRec, enc, 1);
    ++    ** representation.  It would be harmless to repeat the conversion if 
    ++    ** there is already a string rep, but it is pointless to waste those
    ++    ** CPU cycles. */
    ++    if( 0==(pRec->flags&MEM_Str) ){ /*OPTIMIZATION-IF-FALSE*/
    ++      if( (pRec->flags&(MEM_Real|MEM_Int)) ){
    ++        sqlite3VdbeMemStringify(pRec, enc, 1);
    ++      }
    +     }
    +     pRec->flags &= ~(MEM_Real|MEM_Int);
    +   }
    +@@ -73116,7 +80211,7 @@ static void applyAffinity(
    + ** is appropriate.  But only do the conversion if it is possible without
    + ** loss of information and return the revised type of the argument.
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_value_numeric_type(sqlite3_value *pVal){
    ++SQLITE_API int sqlite3_value_numeric_type(sqlite3_value *pVal){
    +   int eType = sqlite3_value_type(pVal);
    +   if( eType==SQLITE_TEXT ){
    +     Mem *pMem = (Mem*)pVal;
    +@@ -73150,7 +80245,7 @@ static u16 SQLITE_NOINLINE computeNumericType(Mem *pMem){
    +   if( sqlite3AtoF(pMem->z, &pMem->u.r, pMem->n, pMem->enc)==0 ){
    +     return 0;
    +   }
    +-  if( sqlite3Atoi64(pMem->z, &pMem->u.i, pMem->n, pMem->enc)==SQLITE_OK ){
    ++  if( sqlite3Atoi64(pMem->z, &pMem->u.i, pMem->n, pMem->enc)==0 ){
    +     return MEM_Int;
    +   }
    +   return MEM_Real;
    +@@ -73199,9 +80294,7 @@ SQLITE_PRIVATE void sqlite3VdbeMemPrettyPrint(Mem *pMem, char *zBuf){
    +     }else{
    +       c = 's';
    +     }
    +-
    +-    sqlite3_snprintf(100, zCsr, "%c", c);
    +-    zCsr += sqlite3Strlen30(zCsr);
    ++    *(zCsr++) = c;
    +     sqlite3_snprintf(100, zCsr, "%d[", pMem->n);
    +     zCsr += sqlite3Strlen30(zCsr);
    +     for(i=0; i<16 && i<pMem->n; i++){
    +@@ -73213,9 +80306,7 @@ SQLITE_PRIVATE void sqlite3VdbeMemPrettyPrint(Mem *pMem, char *zBuf){
    +       if( z<32 || z>126 ) *zCsr++ = '.';
    +       else *zCsr++ = z;
    +     }
    +-
    +-    sqlite3_snprintf(100, zCsr, "]%s", encnames[pMem->enc]);
    +-    zCsr += sqlite3Strlen30(zCsr);
    ++    *(zCsr++) = ']';
    +     if( f & MEM_Zero ){
    +       sqlite3_snprintf(100, zCsr,"+%dz",pMem->u.nZero);
    +       zCsr += sqlite3Strlen30(zCsr);
    +@@ -73264,7 +80355,7 @@ static void memTracePrint(Mem *p){
    +   if( p->flags & MEM_Undefined ){
    +     printf(" undefined");
    +   }else if( p->flags & MEM_Null ){
    +-    printf(" NULL");
    ++    printf(p->flags & MEM_Zero ? " NULL-nochng" : " NULL");
    +   }else if( (p->flags & (MEM_Int|MEM_Str))==(MEM_Int|MEM_Str) ){
    +     printf(" si:%lld", p->u.i);
    +   }else if( p->flags & MEM_Int ){
    +@@ -73280,11 +80371,13 @@ static void memTracePrint(Mem *p){
    +     sqlite3VdbeMemPrettyPrint(p, zBuf);
    +     printf(" %s", zBuf);
    +   }
    ++  if( p->flags & MEM_Subtype ) printf(" subtype=0x%02x", p->eSubtype);
    + }
    + static void registerTrace(int iReg, Mem *p){
    +   printf("REG[%d] = ", iReg);
    +   memTracePrint(p);
    +   printf("\n");
    ++  sqlite3VdbeCheckMemInvariants(p);
    + }
    + #endif
    + 
    +@@ -73318,8 +80411,8 @@ static void registerTrace(int iReg, Mem *p){
    + ** This file contains inline asm code for retrieving "high-performance"
    + ** counters for x86 class CPUs.
    + */
    +-#ifndef _HWTIME_H_
    +-#define _HWTIME_H_
    ++#ifndef SQLITE_HWTIME_H
    ++#define SQLITE_HWTIME_H
    + 
    + /*
    + ** The following routine only works on pentium-class (or newer) processors.
    +@@ -73387,7 +80480,7 @@ SQLITE_PRIVATE   sqlite_uint64 sqlite3Hwtime(void){ return ((sqlite_uint64)0); }
    + 
    + #endif
    + 
    +-#endif /* !defined(_HWTIME_H_) */
    ++#endif /* !defined(SQLITE_HWTIME_H) */
    + 
    + /************** End of hwtime.h **********************************************/
    + /************** Continuing where we left off in vdbe.c ***********************/
    +@@ -73417,16 +80510,24 @@ static int checkSavepointCount(sqlite3 *db){
    + /*
    + ** Return the register of pOp->p2 after first preparing it to be
    + ** overwritten with an integer value.
    +-*/ 
    ++*/
    ++static SQLITE_NOINLINE Mem *out2PrereleaseWithClear(Mem *pOut){
    ++  sqlite3VdbeMemSetNull(pOut);
    ++  pOut->flags = MEM_Int;
    ++  return pOut;
    ++}
    + static Mem *out2Prerelease(Vdbe *p, VdbeOp *pOp){
    +   Mem *pOut;
    +   assert( pOp->p2>0 );
    +-  assert( pOp->p2<=(p->nMem-p->nCursor) );
    ++  assert( pOp->p2<=(p->nMem+1 - p->nCursor) );
    +   pOut = &p->aMem[pOp->p2];
    +   memAboutToChange(p, pOut);
    +-  if( VdbeMemDynamic(pOut) ) sqlite3VdbeMemSetNull(pOut);
    +-  pOut->flags = MEM_Int;
    +-  return pOut;
    ++  if( VdbeMemDynamic(pOut) ){ /*OPTIMIZATION-IF-FALSE*/
    ++    return out2PrereleaseWithClear(pOut);
    ++  }else{
    ++    pOut->flags = MEM_Int;
    ++    return pOut;
    ++  }
    + }
    + 
    + 
    +@@ -73441,23 +80542,24 @@ SQLITE_PRIVATE int sqlite3VdbeExec(
    +   Op *pOp = aOp;             /* Current operation */
    + #if defined(SQLITE_DEBUG) || defined(VDBE_PROFILE)
    +   Op *pOrigOp;               /* Value of pOp at the top of the loop */
    ++#endif
    ++#ifdef SQLITE_DEBUG
    ++  int nExtraDelete = 0;      /* Verifies FORDELETE and AUXDELETE flags */
    + #endif
    +   int rc = SQLITE_OK;        /* Value to return */
    +   sqlite3 *db = p->db;       /* The database */
    +   u8 resetSchemaOnFault = 0; /* Reset schema after an error if positive */
    +   u8 encoding = ENC(db);     /* The database encoding */
    +-  int iCompare = 0;          /* Result of last OP_Compare operation */
    ++  int iCompare = 0;          /* Result of last comparison */
    +   unsigned nVmStep = 0;      /* Number of virtual machine steps */
    + #ifndef SQLITE_OMIT_PROGRESS_CALLBACK
    +-  unsigned nProgressLimit = 0;/* Invoke xProgress() when nVmStep reaches this */
    ++  unsigned nProgressLimit;   /* Invoke xProgress() when nVmStep reaches this */
    + #endif
    +   Mem *aMem = p->aMem;       /* Copy of p->aMem */
    +   Mem *pIn1 = 0;             /* 1st input operand */
    +   Mem *pIn2 = 0;             /* 2nd input operand */
    +   Mem *pIn3 = 0;             /* 3rd input operand */
    +   Mem *pOut = 0;             /* Output operand */
    +-  int *aPermute = 0;         /* Permutation of columns for OP_Compare */
    +-  i64 lastRowid = db->lastRowid;  /* Saved value of the last insert ROWID */
    + #ifdef VDBE_PROFILE
    +   u64 start;                 /* CPU clock count at start of opcode */
    + #endif
    +@@ -73472,7 +80574,6 @@ SQLITE_PRIVATE int sqlite3VdbeExec(
    +   }
    +   assert( p->rc==SQLITE_OK || (p->rc&0xff)==SQLITE_BUSY );
    +   assert( p->bIsReader || p->readOnly!=0 );
    +-  p->rc = SQLITE_OK;
    +   p->iCurrentTime = 0;
    +   assert( p->explain==0 );
    +   p->pResultSet = 0;
    +@@ -73484,6 +80585,8 @@ SQLITE_PRIVATE int sqlite3VdbeExec(
    +     u32 iPrior = p->aCounter[SQLITE_STMTSTATUS_VM_STEP];
    +     assert( 0 < db->nProgressOps );
    +     nProgressLimit = db->nProgressOps - (iPrior % db->nProgressOps);
    ++  }else{
    ++    nProgressLimit = 0xffffffff;
    +   }
    + #endif
    + #ifdef SQLITE_DEBUG
    +@@ -73513,9 +80616,12 @@ SQLITE_PRIVATE int sqlite3VdbeExec(
    +   }
    +   sqlite3EndBenignMalloc();
    + #endif
    +-  for(pOp=&aOp[p->pc]; rc==SQLITE_OK; pOp++){
    ++  for(pOp=&aOp[p->pc]; 1; pOp++){
    ++    /* Errors are detected by individual opcodes, with an immediate
    ++    ** jumps to abort_due_to_error. */
    ++    assert( rc==SQLITE_OK );
    ++
    +     assert( pOp>=aOp && pOp<&aOp[p->nOp]);
    +-    if( db->mallocFailed ) goto no_mem;
    + #ifdef VDBE_PROFILE
    +     start = sqlite3Hwtime();
    + #endif
    +@@ -73547,37 +80653,39 @@ SQLITE_PRIVATE int sqlite3VdbeExec(
    + 
    +     /* Sanity checking on other operands */
    + #ifdef SQLITE_DEBUG
    +-    assert( pOp->opflags==sqlite3OpcodeProperty[pOp->opcode] );
    +-    if( (pOp->opflags & OPFLG_IN1)!=0 ){
    +-      assert( pOp->p1>0 );
    +-      assert( pOp->p1<=(p->nMem-p->nCursor) );
    +-      assert( memIsValid(&aMem[pOp->p1]) );
    +-      assert( sqlite3VdbeCheckMemInvariants(&aMem[pOp->p1]) );
    +-      REGISTER_TRACE(pOp->p1, &aMem[pOp->p1]);
    +-    }
    +-    if( (pOp->opflags & OPFLG_IN2)!=0 ){
    +-      assert( pOp->p2>0 );
    +-      assert( pOp->p2<=(p->nMem-p->nCursor) );
    +-      assert( memIsValid(&aMem[pOp->p2]) );
    +-      assert( sqlite3VdbeCheckMemInvariants(&aMem[pOp->p2]) );
    +-      REGISTER_TRACE(pOp->p2, &aMem[pOp->p2]);
    +-    }
    +-    if( (pOp->opflags & OPFLG_IN3)!=0 ){
    +-      assert( pOp->p3>0 );
    +-      assert( pOp->p3<=(p->nMem-p->nCursor) );
    +-      assert( memIsValid(&aMem[pOp->p3]) );
    +-      assert( sqlite3VdbeCheckMemInvariants(&aMem[pOp->p3]) );
    +-      REGISTER_TRACE(pOp->p3, &aMem[pOp->p3]);
    +-    }
    +-    if( (pOp->opflags & OPFLG_OUT2)!=0 ){
    +-      assert( pOp->p2>0 );
    +-      assert( pOp->p2<=(p->nMem-p->nCursor) );
    +-      memAboutToChange(p, &aMem[pOp->p2]);
    +-    }
    +-    if( (pOp->opflags & OPFLG_OUT3)!=0 ){
    +-      assert( pOp->p3>0 );
    +-      assert( pOp->p3<=(p->nMem-p->nCursor) );
    +-      memAboutToChange(p, &aMem[pOp->p3]);
    ++    {
    ++      u8 opProperty = sqlite3OpcodeProperty[pOp->opcode];
    ++      if( (opProperty & OPFLG_IN1)!=0 ){
    ++        assert( pOp->p1>0 );
    ++        assert( pOp->p1<=(p->nMem+1 - p->nCursor) );
    ++        assert( memIsValid(&aMem[pOp->p1]) );
    ++        assert( sqlite3VdbeCheckMemInvariants(&aMem[pOp->p1]) );
    ++        REGISTER_TRACE(pOp->p1, &aMem[pOp->p1]);
    ++      }
    ++      if( (opProperty & OPFLG_IN2)!=0 ){
    ++        assert( pOp->p2>0 );
    ++        assert( pOp->p2<=(p->nMem+1 - p->nCursor) );
    ++        assert( memIsValid(&aMem[pOp->p2]) );
    ++        assert( sqlite3VdbeCheckMemInvariants(&aMem[pOp->p2]) );
    ++        REGISTER_TRACE(pOp->p2, &aMem[pOp->p2]);
    ++      }
    ++      if( (opProperty & OPFLG_IN3)!=0 ){
    ++        assert( pOp->p3>0 );
    ++        assert( pOp->p3<=(p->nMem+1 - p->nCursor) );
    ++        assert( memIsValid(&aMem[pOp->p3]) );
    ++        assert( sqlite3VdbeCheckMemInvariants(&aMem[pOp->p3]) );
    ++        REGISTER_TRACE(pOp->p3, &aMem[pOp->p3]);
    ++      }
    ++      if( (opProperty & OPFLG_OUT2)!=0 ){
    ++        assert( pOp->p2>0 );
    ++        assert( pOp->p2<=(p->nMem+1 - p->nCursor) );
    ++        memAboutToChange(p, &aMem[pOp->p2]);
    ++      }
    ++      if( (opProperty & OPFLG_OUT3)!=0 ){
    ++        assert( pOp->p3>0 );
    ++        assert( pOp->p3<=(p->nMem+1 - p->nCursor) );
    ++        memAboutToChange(p, &aMem[pOp->p3]);
    ++      }
    +     }
    + #endif
    + #if defined(SQLITE_DEBUG) || defined(VDBE_PROFILE)
    +@@ -73638,7 +80746,7 @@ jump_to_p2_and_check_for_interrupt:
    +   pOp = &aOp[pOp->p2 - 1];
    + 
    +   /* Opcodes that are used as the bottom of a loop (OP_Next, OP_Prev,
    +-  ** OP_VNext, OP_RowSetNext, or OP_SorterNext) all jump here upon
    ++  ** OP_VNext, or OP_SorterNext) all jump here upon
    +   ** completion.  Check to see if sqlite3_interrupt() has been called
    +   ** or if the progress callback needs to be invoked. 
    +   **
    +@@ -73656,12 +80764,12 @@ check_for_interrupt:
    +   ** If the progress callback returns non-zero, exit the virtual machine with
    +   ** a return code SQLITE_ABORT.
    +   */
    +-  if( db->xProgress!=0 && nVmStep>=nProgressLimit ){
    ++  if( nVmStep>=nProgressLimit && db->xProgress!=0 ){
    +     assert( db->nProgressOps!=0 );
    +     nProgressLimit = nVmStep + db->nProgressOps - (nVmStep%db->nProgressOps);
    +     if( db->xProgress(db->pProgressArg) ){
    +       rc = SQLITE_INTERRUPT;
    +-      goto vdbe_error_halt;
    ++      goto abort_due_to_error;
    +     }
    +   }
    + #endif
    +@@ -73675,7 +80783,7 @@ check_for_interrupt:
    + ** and then jump to address P2.
    + */
    + case OP_Gosub: {            /* jump */
    +-  assert( pOp->p1>0 && pOp->p1<=(p->nMem-p->nCursor) );
    ++  assert( pOp->p1>0 && pOp->p1<=(p->nMem+1 - p->nCursor) );
    +   pIn1 = &aMem[pOp->p1];
    +   assert( VdbeMemDynamic(pIn1)==0 );
    +   memAboutToChange(p, pIn1);
    +@@ -73715,7 +80823,7 @@ case OP_Return: {           /* in1 */
    + ** See also: EndCoroutine
    + */
    + case OP_InitCoroutine: {     /* jump */
    +-  assert( pOp->p1>0 &&  pOp->p1<=(p->nMem-p->nCursor) );
    ++  assert( pOp->p1>0 &&  pOp->p1<=(p->nMem+1 - p->nCursor) );
    +   assert( pOp->p2>=0 && pOp->p2<p->nOp );
    +   assert( pOp->p3>=0 && pOp->p3<p->nOp );
    +   pOut = &aMem[pOp->p1];
    +@@ -73773,7 +80881,7 @@ case OP_Yield: {            /* in1, jump */
    + }
    + 
    + /* Opcode:  HaltIfNull  P1 P2 P3 P4 P5
    +-** Synopsis:  if r[P3]=null halt
    ++** Synopsis: if r[P3]=null halt
    + **
    + ** Check the value in register P3.  If it is NULL then Halt using
    + ** parameter P1, P2, and P4 as if this were a Halt instruction.  If the
    +@@ -73817,8 +80925,6 @@ case OP_HaltIfNull: {      /* in3 */
    + ** is the same as executing Halt.
    + */
    + case OP_Halt: {
    +-  const char *zType;
    +-  const char *zLogFmt;
    +   VdbeFrame *pFrame;
    +   int pcx;
    + 
    +@@ -73830,7 +80936,6 @@ case OP_Halt: {
    +     p->nFrame--;
    +     sqlite3VdbeSetChanges(db, p->nChange);
    +     pcx = sqlite3VdbeFrameRestore(pFrame);
    +-    lastRowid = db->lastRowid;
    +     if( pOp->p2==OE_Ignore ){
    +       /* Instruction pcx is the OP_Program that invoked the sub-program 
    +       ** currently being halted. If the p2 instruction of this OP_Halt
    +@@ -73847,34 +80952,28 @@ case OP_Halt: {
    +   p->rc = pOp->p1;
    +   p->errorAction = (u8)pOp->p2;
    +   p->pc = pcx;
    ++  assert( pOp->p5<=4 );
    +   if( p->rc ){
    +     if( pOp->p5 ){
    +       static const char * const azType[] = { "NOT NULL", "UNIQUE", "CHECK",
    +                                              "FOREIGN KEY" };
    +-      assert( pOp->p5>=1 && pOp->p5<=4 );
    +       testcase( pOp->p5==1 );
    +       testcase( pOp->p5==2 );
    +       testcase( pOp->p5==3 );
    +       testcase( pOp->p5==4 );
    +-      zType = azType[pOp->p5-1];
    ++      sqlite3VdbeError(p, "%s constraint failed", azType[pOp->p5-1]);
    ++      if( pOp->p4.z ){
    ++        p->zErrMsg = sqlite3MPrintf(db, "%z: %s", p->zErrMsg, pOp->p4.z);
    ++      }
    +     }else{
    +-      zType = 0;
    +-    }
    +-    assert( zType!=0 || pOp->p4.z!=0 );
    +-    zLogFmt = "abort at %d in [%s]: %s";
    +-    if( zType && pOp->p4.z ){
    +-      sqlite3VdbeError(p, "%s constraint failed: %s", zType, pOp->p4.z);
    +-    }else if( pOp->p4.z ){
    +       sqlite3VdbeError(p, "%s", pOp->p4.z);
    +-    }else{
    +-      sqlite3VdbeError(p, "%s constraint failed", zType);
    +     }
    +-    sqlite3_log(pOp->p1, zLogFmt, pcx, p->zSql, p->zErrMsg);
    ++    sqlite3_log(pOp->p1, "abort at %d in [%s]: %s", pcx, p->zSql, p->zErrMsg);
    +   }
    +   rc = sqlite3VdbeHalt(p);
    +   assert( rc==SQLITE_BUSY || rc==SQLITE_OK || rc==SQLITE_ERROR );
    +   if( rc==SQLITE_BUSY ){
    +-    p->rc = rc = SQLITE_BUSY;
    ++    p->rc = SQLITE_BUSY;
    +   }else{
    +     assert( rc==SQLITE_OK || (p->rc&0xff)==SQLITE_CONSTRAINT );
    +     assert( rc==SQLITE_OK || db->nDeferredCons>0 || db->nDeferredImmCons>0 );
    +@@ -73940,7 +81039,7 @@ case OP_String8: {         /* same as TK_STRING, out2 */
    + #ifndef SQLITE_OMIT_UTF16
    +   if( encoding!=SQLITE_UTF8 ){
    +     rc = sqlite3VdbeMemSetStr(pOut, pOp->p4.z, -1, SQLITE_UTF8, SQLITE_STATIC);
    +-    if( rc==SQLITE_TOOBIG ) goto too_big;
    ++    assert( rc==SQLITE_OK || rc==SQLITE_TOOBIG );
    +     if( SQLITE_OK!=sqlite3VdbeChangeEncoding(pOut, encoding) ) goto no_mem;
    +     assert( pOut->szMalloc>0 && pOut->zMalloc==pOut->z );
    +     assert( VdbeMemDynamic(pOut)==0 );
    +@@ -73953,10 +81052,12 @@ case OP_String8: {         /* same as TK_STRING, out2 */
    +     pOp->p4.z = pOut->z;
    +     pOp->p1 = pOut->n;
    +   }
    ++  testcase( rc==SQLITE_TOOBIG );
    + #endif
    +   if( pOp->p1>db->aLimit[SQLITE_LIMIT_LENGTH] ){
    +     goto too_big;
    +   }
    ++  assert( rc==SQLITE_OK );
    +   /* Fall through to the next case, OP_String */
    + }
    +   
    +@@ -73965,10 +81066,12 @@ case OP_String8: {         /* same as TK_STRING, out2 */
    + **
    + ** The string value P4 of length P1 (bytes) is stored in register P2.
    + **
    +-** If P5!=0 and the content of register P3 is greater than zero, then
    ++** If P3 is not zero and the content of register P3 is equal to P5, then
    + ** the datatype of the register P2 is converted to BLOB.  The content is
    + ** the same sequence of bytes, it is merely interpreted as a BLOB instead
    +-** of a string, as if it had been CAST.
    ++** of a string, as if it had been CAST.  In other words:
    ++**
    ++** if( P3!=0 and reg[P3]==P5 ) reg[P2] := CAST(reg[P2] as BLOB)
    + */
    + case OP_String: {          /* out2 */
    +   assert( pOp->p4.z!=0 );
    +@@ -73978,18 +81081,19 @@ case OP_String: {          /* out2 */
    +   pOut->n = pOp->p1;
    +   pOut->enc = encoding;
    +   UPDATE_MAX_BLOBSIZE(pOut);
    +-  if( pOp->p5 ){
    +-    assert( pOp->p3>0 );
    +-    assert( pOp->p3<=(p->nMem-p->nCursor) );
    ++#ifndef SQLITE_LIKE_DOESNT_MATCH_BLOBS
    ++  if( pOp->p3>0 ){
    ++    assert( pOp->p3<=(p->nMem+1 - p->nCursor) );
    +     pIn3 = &aMem[pOp->p3];
    +     assert( pIn3->flags & MEM_Int );
    +-    if( pIn3->u.i ) pOut->flags = MEM_Blob|MEM_Static|MEM_Term;
    ++    if( pIn3->u.i==pOp->p5 ) pOut->flags = MEM_Blob|MEM_Static|MEM_Term;
    +   }
    ++#endif
    +   break;
    + }
    + 
    + /* Opcode: Null P1 P2 P3 * *
    +-** Synopsis:  r[P2..P3]=NULL
    ++** Synopsis: r[P2..P3]=NULL
    + **
    + ** Write a NULL into registers P2.  If P3 greater than P2, then also write
    + ** NULL into register P3 and every register in between P2 and P3.  If P3
    +@@ -74005,20 +81109,22 @@ case OP_Null: {           /* out2 */
    +   u16 nullFlag;
    +   pOut = out2Prerelease(p, pOp);
    +   cnt = pOp->p3-pOp->p2;
    +-  assert( pOp->p3<=(p->nMem-p->nCursor) );
    ++  assert( pOp->p3<=(p->nMem+1 - p->nCursor) );
    +   pOut->flags = nullFlag = pOp->p1 ? (MEM_Null|MEM_Cleared) : MEM_Null;
    ++  pOut->n = 0;
    +   while( cnt>0 ){
    +     pOut++;
    +     memAboutToChange(p, pOut);
    +     sqlite3VdbeMemSetNull(pOut);
    +     pOut->flags = nullFlag;
    ++    pOut->n = 0;
    +     cnt--;
    +   }
    +   break;
    + }
    + 
    + /* Opcode: SoftNull P1 * * * *
    +-** Synopsis:  r[P1]=NULL
    ++** Synopsis: r[P1]=NULL
    + **
    + ** Set register P1 to have the value NULL as seen by the OP_MakeRecord
    + ** instruction, but do not free any string or blob memory associated with
    +@@ -74026,9 +81132,9 @@ case OP_Null: {           /* out2 */
    + ** previously copied using OP_SCopy, the copies will continue to be valid.
    + */
    + case OP_SoftNull: {
    +-  assert( pOp->p1>0 && pOp->p1<=(p->nMem-p->nCursor) );
    ++  assert( pOp->p1>0 && pOp->p1<=(p->nMem+1 - p->nCursor) );
    +   pOut = &aMem[pOp->p1];
    +-  pOut->flags = (pOut->flags|MEM_Null)&~MEM_Undefined;
    ++  pOut->flags = (pOut->flags&~(MEM_Undefined|MEM_AffMask))|MEM_Null;
    +   break;
    + }
    + 
    +@@ -74059,19 +81165,19 @@ case OP_Variable: {            /* out2 */
    +   Mem *pVar;       /* Value being transferred */
    + 
    +   assert( pOp->p1>0 && pOp->p1<=p->nVar );
    +-  assert( pOp->p4.z==0 || pOp->p4.z==p->azVar[pOp->p1-1] );
    ++  assert( pOp->p4.z==0 || pOp->p4.z==sqlite3VListNumToName(p->pVList,pOp->p1) );
    +   pVar = &p->aVar[pOp->p1 - 1];
    +   if( sqlite3VdbeMemTooBig(pVar) ){
    +     goto too_big;
    +   }
    +-  pOut = out2Prerelease(p, pOp);
    ++  pOut = &aMem[pOp->p2];
    +   sqlite3VdbeMemShallowCopy(pOut, pVar, MEM_Static);
    +   UPDATE_MAX_BLOBSIZE(pOut);
    +   break;
    + }
    + 
    + /* Opcode: Move P1 P2 P3 * *
    +-** Synopsis:  r[P2@P3]=r[P1@P3]
    ++** Synopsis: r[P2@P3]=r[P1@P3]
    + **
    + ** Move the P3 values in register P1..P1+P3-1 over into
    + ** registers P2..P2+P3-1.  Registers P1..P1+P3-1 are
    +@@ -74093,8 +81199,8 @@ case OP_Move: {
    +   pIn1 = &aMem[p1];
    +   pOut = &aMem[p2];
    +   do{
    +-    assert( pOut<=&aMem[(p->nMem-p->nCursor)] );
    +-    assert( pIn1<=&aMem[(p->nMem-p->nCursor)] );
    ++    assert( pOut<=&aMem[(p->nMem+1 - p->nCursor)] );
    ++    assert( pIn1<=&aMem[(p->nMem+1 - p->nCursor)] );
    +     assert( memIsValid(pIn1) );
    +     memAboutToChange(p, pOut);
    +     sqlite3VdbeMemMove(pOut, pIn1);
    +@@ -74164,8 +81270,24 @@ case OP_SCopy: {            /* out2 */
    +   break;
    + }
    + 
    ++/* Opcode: IntCopy P1 P2 * * *
    ++** Synopsis: r[P2]=r[P1]
    ++**
    ++** Transfer the integer value held in register P1 into register P2.
    ++**
    ++** This is an optimized version of SCopy that works only for integer
    ++** values.
    ++*/
    ++case OP_IntCopy: {            /* out2 */
    ++  pIn1 = &aMem[pOp->p1];
    ++  assert( (pIn1->flags & MEM_Int)!=0 );
    ++  pOut = &aMem[pOp->p2];
    ++  sqlite3VdbeMemSetInt64(pOut, pIn1->u.i);
    ++  break;
    ++}
    ++
    + /* Opcode: ResultRow P1 P2 * * *
    +-** Synopsis:  output=r[P1@P2]
    ++** Synopsis: output=r[P1@P2]
    + **
    + ** The registers P1 through P1+P2-1 contain a single row of
    + ** results. This opcode causes the sqlite3_step() call to terminate
    +@@ -74178,17 +81300,17 @@ case OP_ResultRow: {
    +   int i;
    +   assert( p->nResColumn==pOp->p2 );
    +   assert( pOp->p1>0 );
    +-  assert( pOp->p1+pOp->p2<=(p->nMem-p->nCursor)+1 );
    ++  assert( pOp->p1+pOp->p2<=(p->nMem+1 - p->nCursor)+1 );
    + 
    + #ifndef SQLITE_OMIT_PROGRESS_CALLBACK
    +   /* Run the progress counter just before returning.
    +   */
    +   if( db->xProgress!=0
    +-   && nVmStep>=nProgressLimit
    ++   && nVmStep>=nProgressLimit 
    +    && db->xProgress(db->pProgressArg)!=0
    +   ){
    +     rc = SQLITE_INTERRUPT;
    +-    goto vdbe_error_halt;
    ++    goto abort_due_to_error;
    +   }
    + #endif
    + 
    +@@ -74198,7 +81320,7 @@ case OP_ResultRow: {
    +   if( SQLITE_OK!=(rc = sqlite3VdbeCheckFk(p, 0)) ){
    +     assert( db->flags&SQLITE_CountRows );
    +     assert( p->usesStmtJournal );
    +-    break;
    ++    goto abort_due_to_error;
    +   }
    + 
    +   /* If the SQLITE_CountRows flag is set in sqlite3.flags mask, then 
    +@@ -74218,9 +81340,7 @@ case OP_ResultRow: {
    +   */
    +   assert( p->iStatement==0 || db->flags&SQLITE_CountRows );
    +   rc = sqlite3VdbeCloseStatement(p, SAVEPOINT_RELEASE);
    +-  if( NEVER(rc!=SQLITE_OK) ){
    +-    break;
    +-  }
    ++  assert( rc==SQLITE_OK );
    + 
    +   /* Invalidate all ephemeral cursor row caches */
    +   p->cacheCtr = (p->cacheCtr + 2)|1;
    +@@ -74240,6 +81360,10 @@ case OP_ResultRow: {
    +   }
    +   if( db->mallocFailed ) goto no_mem;
    + 
    ++  if( db->mTrace & SQLITE_TRACE_ROW ){
    ++    db->xTrace(SQLITE_TRACE_ROW, db->pTraceArg, p, 0);
    ++  }
    ++
    +   /* Return SQLITE_ROW
    +   */
    +   p->pc = (int)(pOp - aOp) + 1;
    +@@ -74296,14 +81420,14 @@ case OP_Concat: {           /* same as TK_CONCAT, in1, in2, out3 */
    + }
    + 
    + /* Opcode: Add P1 P2 P3 * *
    +-** Synopsis:  r[P3]=r[P1]+r[P2]
    ++** Synopsis: r[P3]=r[P1]+r[P2]
    + **
    + ** Add the value in register P1 to the value in register P2
    + ** and store the result in register P3.
    + ** If either input is NULL, the result is NULL.
    + */
    + /* Opcode: Multiply P1 P2 P3 * *
    +-** Synopsis:  r[P3]=r[P1]*r[P2]
    ++** Synopsis: r[P3]=r[P1]*r[P2]
    + **
    + **
    + ** Multiply the value in register P1 by the value in register P2
    +@@ -74311,14 +81435,14 @@ case OP_Concat: {           /* same as TK_CONCAT, in1, in2, out3 */
    + ** If either input is NULL, the result is NULL.
    + */
    + /* Opcode: Subtract P1 P2 P3 * *
    +-** Synopsis:  r[P3]=r[P2]-r[P1]
    ++** Synopsis: r[P3]=r[P2]-r[P1]
    + **
    + ** Subtract the value in register P1 from the value in register P2
    + ** and store the result in register P3.
    + ** If either input is NULL, the result is NULL.
    + */
    + /* Opcode: Divide P1 P2 P3 * *
    +-** Synopsis:  r[P3]=r[P2]/r[P1]
    ++** Synopsis: r[P3]=r[P2]/r[P1]
    + **
    + ** Divide the value in register P1 by the value in register P2
    + ** and store the result in register P3 (P3=P2/P1). If the value in 
    +@@ -74326,7 +81450,7 @@ case OP_Concat: {           /* same as TK_CONCAT, in1, in2, out3 */
    + ** NULL, the result is NULL.
    + */
    + /* Opcode: Remainder P1 P2 P3 * *
    +-** Synopsis:  r[P3]=r[P2]%r[P1]
    ++** Synopsis: r[P3]=r[P2]%r[P1]
    + **
    + ** Compute the remainder after integer register P2 is divided by 
    + ** register P1 and store the result in register P3. 
    +@@ -74353,7 +81477,6 @@ case OP_Remainder: {           /* same as TK_REM, in1, in2, out3 */
    +   type2 = numericType(pIn2);
    +   pOut = &aMem[pOp->p3];
    +   flags = pIn1->flags | pIn2->flags;
    +-  if( (flags & MEM_Null)!=0 ) goto arithmetic_result_is_null;
    +   if( (type1 & type2 & MEM_Int)!=0 ){
    +     iA = pIn1->u.i;
    +     iB = pIn2->u.i;
    +@@ -74377,6 +81500,8 @@ case OP_Remainder: {           /* same as TK_REM, in1, in2, out3 */
    +     }
    +     pOut->u.i = iB;
    +     MemSetTypeFlag(pOut, MEM_Int);
    ++  }else if( (flags & MEM_Null)!=0 ){
    ++    goto arithmetic_result_is_null;
    +   }else{
    +     bIntint = 0;
    + fp_math:
    +@@ -74424,7 +81549,7 @@ arithmetic_result_is_null:
    + 
    + /* Opcode: CollSeq P1 * * P4
    + **
    +-** P4 is a pointer to a CollSeq struct. If the next call to a user function
    ++** P4 is a pointer to a CollSeq object. If the next call to a user function
    + ** or aggregate calls sqlite3GetFuncCollSeq(), this collation sequence will
    + ** be returned. This is used by the built-in min(), max() and nullif()
    + ** functions.
    +@@ -74445,134 +81570,22 @@ case OP_CollSeq: {
    +   break;
    + }
    + 
    +-/* Opcode: Function0 P1 P2 P3 P4 P5
    +-** Synopsis: r[P3]=func(r[P2@P5])
    +-**
    +-** Invoke a user function (P4 is a pointer to a FuncDef object that
    +-** defines the function) with P5 arguments taken from register P2 and
    +-** successors.  The result of the function is stored in register P3.
    +-** Register P3 must not be one of the function inputs.
    +-**
    +-** P1 is a 32-bit bitmask indicating whether or not each argument to the 
    +-** function was determined to be constant at compile time. If the first
    +-** argument was constant then bit 0 of P1 is set. This is used to determine
    +-** whether meta data associated with a user function argument using the
    +-** sqlite3_set_auxdata() API may be safely retained until the next
    +-** invocation of this opcode.
    +-**
    +-** See also: Function, AggStep, AggFinal
    +-*/
    +-/* Opcode: Function P1 P2 P3 P4 P5
    +-** Synopsis: r[P3]=func(r[P2@P5])
    +-**
    +-** Invoke a user function (P4 is a pointer to an sqlite3_context object that
    +-** contains a pointer to the function to be run) with P5 arguments taken
    +-** from register P2 and successors.  The result of the function is stored
    +-** in register P3.  Register P3 must not be one of the function inputs.
    +-**
    +-** P1 is a 32-bit bitmask indicating whether or not each argument to the 
    +-** function was determined to be constant at compile time. If the first
    +-** argument was constant then bit 0 of P1 is set. This is used to determine
    +-** whether meta data associated with a user function argument using the
    +-** sqlite3_set_auxdata() API may be safely retained until the next
    +-** invocation of this opcode.
    +-**
    +-** SQL functions are initially coded as OP_Function0 with P4 pointing
    +-** to a FuncDef object.  But on first evaluation, the P4 operand is
    +-** automatically converted into an sqlite3_context object and the operation
    +-** changed to this OP_Function opcode.  In this way, the initialization of
    +-** the sqlite3_context object occurs only once, rather than once for each
    +-** evaluation of the function.
    +-**
    +-** See also: Function0, AggStep, AggFinal
    +-*/
    +-case OP_Function0: {
    +-  int n;
    +-  sqlite3_context *pCtx;
    +-
    +-  assert( pOp->p4type==P4_FUNCDEF );
    +-  n = pOp->p5;
    +-  assert( pOp->p3>0 && pOp->p3<=(p->nMem-p->nCursor) );
    +-  assert( n==0 || (pOp->p2>0 && pOp->p2+n<=(p->nMem-p->nCursor)+1) );
    +-  assert( pOp->p3<pOp->p2 || pOp->p3>=pOp->p2+n );
    +-  pCtx = sqlite3DbMallocRaw(db, sizeof(*pCtx) + (n-1)*sizeof(sqlite3_value*));
    +-  if( pCtx==0 ) goto no_mem;
    +-  pCtx->pOut = 0;
    +-  pCtx->pFunc = pOp->p4.pFunc;
    +-  pCtx->iOp = (int)(pOp - aOp);
    +-  pCtx->pVdbe = p;
    +-  pCtx->argc = n;
    +-  pOp->p4type = P4_FUNCCTX;
    +-  pOp->p4.pCtx = pCtx;
    +-  pOp->opcode = OP_Function;
    +-  /* Fall through into OP_Function */
    +-}
    +-case OP_Function: {
    +-  int i;
    +-  sqlite3_context *pCtx;
    +-
    +-  assert( pOp->p4type==P4_FUNCCTX );
    +-  pCtx = pOp->p4.pCtx;
    +-
    +-  /* If this function is inside of a trigger, the register array in aMem[]
    +-  ** might change from one evaluation to the next.  The next block of code
    +-  ** checks to see if the register array has changed, and if so it
    +-  ** reinitializes the relavant parts of the sqlite3_context object */
    +-  pOut = &aMem[pOp->p3];
    +-  if( pCtx->pOut != pOut ){
    +-    pCtx->pOut = pOut;
    +-    for(i=pCtx->argc-1; i>=0; i--) pCtx->argv[i] = &aMem[pOp->p2+i];
    +-  }
    +-
    +-  memAboutToChange(p, pCtx->pOut);
    +-#ifdef SQLITE_DEBUG
    +-  for(i=0; i<pCtx->argc; i++){
    +-    assert( memIsValid(pCtx->argv[i]) );
    +-    REGISTER_TRACE(pOp->p2+i, pCtx->argv[i]);
    +-  }
    +-#endif
    +-  MemSetTypeFlag(pCtx->pOut, MEM_Null);
    +-  pCtx->fErrorOrAux = 0;
    +-  db->lastRowid = lastRowid;
    +-  (*pCtx->pFunc->xFunc)(pCtx, pCtx->argc, pCtx->argv); /* IMP: R-24505-23230 */
    +-  lastRowid = db->lastRowid;  /* Remember rowid changes made by xFunc */
    +-
    +-  /* If the function returned an error, throw an exception */
    +-  if( pCtx->fErrorOrAux ){
    +-    if( pCtx->isError ){
    +-      sqlite3VdbeError(p, "%s", sqlite3_value_text(pCtx->pOut));
    +-      rc = pCtx->isError;
    +-    }
    +-    sqlite3VdbeDeleteAuxData(p, pCtx->iOp, pOp->p1);
    +-  }
    +-
    +-  /* Copy the result of the function into register P3 */
    +-  if( pOut->flags & (MEM_Str|MEM_Blob) ){
    +-    sqlite3VdbeChangeEncoding(pCtx->pOut, encoding);
    +-    if( sqlite3VdbeMemTooBig(pCtx->pOut) ) goto too_big;
    +-  }
    +-
    +-  REGISTER_TRACE(pOp->p3, pCtx->pOut);
    +-  UPDATE_MAX_BLOBSIZE(pCtx->pOut);
    +-  break;
    +-}
    +-
    + /* Opcode: BitAnd P1 P2 P3 * *
    +-** Synopsis:  r[P3]=r[P1]&r[P2]
    ++** Synopsis: r[P3]=r[P1]&r[P2]
    + **
    + ** Take the bit-wise AND of the values in register P1 and P2 and
    + ** store the result in register P3.
    + ** If either input is NULL, the result is NULL.
    + */
    + /* Opcode: BitOr P1 P2 P3 * *
    +-** Synopsis:  r[P3]=r[P1]|r[P2]
    ++** Synopsis: r[P3]=r[P1]|r[P2]
    + **
    + ** Take the bit-wise OR of the values in register P1 and P2 and
    + ** store the result in register P3.
    + ** If either input is NULL, the result is NULL.
    + */
    + /* Opcode: ShiftLeft P1 P2 P3 * *
    +-** Synopsis:  r[P3]=r[P2]<<r[P1]
    ++** Synopsis: r[P3]=r[P2]<<r[P1]
    + **
    + ** Shift the integer value in register P2 to the left by the
    + ** number of bits specified by the integer in register P1.
    +@@ -74580,7 +81593,7 @@ case OP_Function: {
    + ** If either input is NULL, the result is NULL.
    + */
    + /* Opcode: ShiftRight P1 P2 P3 * *
    +-** Synopsis:  r[P3]=r[P2]>>r[P1]
    ++** Synopsis: r[P3]=r[P2]>>r[P1]
    + **
    + ** Shift the integer value in register P2 to the right by the
    + ** number of bits specified by the integer in register P1.
    +@@ -74640,7 +81653,7 @@ case OP_ShiftRight: {           /* same as TK_RSHIFT, in1, in2, out3 */
    + }
    + 
    + /* Opcode: AddImm  P1 P2 * * *
    +-** Synopsis:  r[P1]=r[P1]+P2
    ++** Synopsis: r[P1]=r[P1]+P2
    + ** 
    + ** Add the constant P2 to the value in register P1.
    + ** The result is always an integer.
    +@@ -74706,11 +81719,11 @@ case OP_RealAffinity: {                  /* in1 */
    + ** Force the value in register P1 to be the type defined by P2.
    + ** 
    + ** <ul>
    +-** <li value="97"> TEXT
    +-** <li value="98"> BLOB
    +-** <li value="99"> NUMERIC
    +-** <li value="100"> INTEGER
    +-** <li value="101"> REAL
    ++** <li> P2=='A' &rarr; BLOB
    ++** <li> P2=='B' &rarr; TEXT
    ++** <li> P2=='C' &rarr; NUMERIC
    ++** <li> P2=='D' &rarr; INTEGER
    ++** <li> P2=='E' &rarr; REAL
    + ** </ul>
    + **
    + ** A NULL value is not changed by this routine.  It remains NULL.
    +@@ -74727,19 +81740,17 @@ case OP_Cast: {                  /* in1 */
    +   rc = ExpandBlob(pIn1);
    +   sqlite3VdbeMemCast(pIn1, pOp->p2, encoding);
    +   UPDATE_MAX_BLOBSIZE(pIn1);
    ++  if( rc ) goto abort_due_to_error;
    +   break;
    + }
    + #endif /* SQLITE_OMIT_CAST */
    + 
    +-/* Opcode: Lt P1 P2 P3 P4 P5
    +-** Synopsis: if r[P1]<r[P3] goto P2
    +-**
    +-** Compare the values in register P1 and P3.  If reg(P3)<reg(P1) then
    +-** jump to address P2.  
    ++/* Opcode: Eq P1 P2 P3 P4 P5
    ++** Synopsis: IF r[P3]==r[P1]
    + **
    +-** If the SQLITE_JUMPIFNULL bit of P5 is set and either reg(P1) or
    +-** reg(P3) is NULL then take the jump.  If the SQLITE_JUMPIFNULL 
    +-** bit is clear then fall through if either operand is NULL.
    ++** Compare the values in register P1 and P3.  If reg(P3)==reg(P1) then
    ++** jump to address P2.  Or if the SQLITE_STOREP2 flag is set in P5, then
    ++** store the result of comparison in register P2.
    + **
    + ** The SQLITE_AFF_MASK portion of P5 must be an affinity character -
    + ** SQLITE_AFF_TEXT, SQLITE_AFF_INTEGER, and so forth. An attempt is made 
    +@@ -74753,61 +81764,78 @@ case OP_Cast: {                  /* in1 */
    + ** the values are compared. If both values are blobs then memcmp() is
    + ** used to determine the results of the comparison.  If both values
    + ** are text, then the appropriate collating function specified in
    +-** P4 is  used to do the comparison.  If P4 is not specified then
    ++** P4 is used to do the comparison.  If P4 is not specified then
    + ** memcmp() is used to compare text string.  If both values are
    + ** numeric, then a numeric comparison is used. If the two values
    + ** are of different types, then numbers are considered less than
    + ** strings and strings are considered less than blobs.
    + **
    +-** If the SQLITE_STOREP2 bit of P5 is set, then do not jump.  Instead,
    +-** store a boolean result (either 0, or 1, or NULL) in register P2.
    ++** If SQLITE_NULLEQ is set in P5 then the result of comparison is always either
    ++** true or false and is never NULL.  If both operands are NULL then the result
    ++** of comparison is true.  If either operand is NULL then the result is false.
    ++** If neither operand is NULL the result is the same as it would be if
    ++** the SQLITE_NULLEQ flag were omitted from P5.
    + **
    +-** If the SQLITE_NULLEQ bit is set in P5, then NULL values are considered
    +-** equal to one another, provided that they do not have their MEM_Cleared
    +-** bit set.
    ++** If both SQLITE_STOREP2 and SQLITE_KEEPNULL flags are set then the
    ++** content of r[P2] is only changed if the new value is NULL or 0 (false).
    ++** In other words, a prior r[P2] value will not be overwritten by 1 (true).
    + */
    + /* Opcode: Ne P1 P2 P3 P4 P5
    +-** Synopsis: if r[P1]!=r[P3] goto P2
    ++** Synopsis: IF r[P3]!=r[P1]
    + **
    +-** This works just like the Lt opcode except that the jump is taken if
    +-** the operands in registers P1 and P3 are not equal.  See the Lt opcode for
    ++** This works just like the Eq opcode except that the jump is taken if
    ++** the operands in registers P1 and P3 are not equal.  See the Eq opcode for
    + ** additional information.
    + **
    +-** If SQLITE_NULLEQ is set in P5 then the result of comparison is always either
    +-** true or false and is never NULL.  If both operands are NULL then the result
    +-** of comparison is false.  If either operand is NULL then the result is true.
    +-** If neither operand is NULL the result is the same as it would be if
    +-** the SQLITE_NULLEQ flag were omitted from P5.
    ++** If both SQLITE_STOREP2 and SQLITE_KEEPNULL flags are set then the
    ++** content of r[P2] is only changed if the new value is NULL or 1 (true).
    ++** In other words, a prior r[P2] value will not be overwritten by 0 (false).
    + */
    +-/* Opcode: Eq P1 P2 P3 P4 P5
    +-** Synopsis: if r[P1]==r[P3] goto P2
    ++/* Opcode: Lt P1 P2 P3 P4 P5
    ++** Synopsis: IF r[P3]<r[P1]
    + **
    +-** This works just like the Lt opcode except that the jump is taken if
    +-** the operands in registers P1 and P3 are equal.
    +-** See the Lt opcode for additional information.
    ++** Compare the values in register P1 and P3.  If reg(P3)<reg(P1) then
    ++** jump to address P2.  Or if the SQLITE_STOREP2 flag is set in P5 store
    ++** the result of comparison (0 or 1 or NULL) into register P2.
    + **
    +-** If SQLITE_NULLEQ is set in P5 then the result of comparison is always either
    +-** true or false and is never NULL.  If both operands are NULL then the result
    +-** of comparison is true.  If either operand is NULL then the result is false.
    +-** If neither operand is NULL the result is the same as it would be if
    +-** the SQLITE_NULLEQ flag were omitted from P5.
    ++** If the SQLITE_JUMPIFNULL bit of P5 is set and either reg(P1) or
    ++** reg(P3) is NULL then the take the jump.  If the SQLITE_JUMPIFNULL 
    ++** bit is clear then fall through if either operand is NULL.
    ++**
    ++** The SQLITE_AFF_MASK portion of P5 must be an affinity character -
    ++** SQLITE_AFF_TEXT, SQLITE_AFF_INTEGER, and so forth. An attempt is made 
    ++** to coerce both inputs according to this affinity before the
    ++** comparison is made. If the SQLITE_AFF_MASK is 0x00, then numeric
    ++** affinity is used. Note that the affinity conversions are stored
    ++** back into the input registers P1 and P3.  So this opcode can cause
    ++** persistent changes to registers P1 and P3.
    ++**
    ++** Once any conversions have taken place, and neither value is NULL, 
    ++** the values are compared. If both values are blobs then memcmp() is
    ++** used to determine the results of the comparison.  If both values
    ++** are text, then the appropriate collating function specified in
    ++** P4 is  used to do the comparison.  If P4 is not specified then
    ++** memcmp() is used to compare text string.  If both values are
    ++** numeric, then a numeric comparison is used. If the two values
    ++** are of different types, then numbers are considered less than
    ++** strings and strings are considered less than blobs.
    + */
    + /* Opcode: Le P1 P2 P3 P4 P5
    +-** Synopsis: if r[P1]<=r[P3] goto P2
    ++** Synopsis: IF r[P3]<=r[P1]
    + **
    + ** This works just like the Lt opcode except that the jump is taken if
    + ** the content of register P3 is less than or equal to the content of
    + ** register P1.  See the Lt opcode for additional information.
    + */
    + /* Opcode: Gt P1 P2 P3 P4 P5
    +-** Synopsis: if r[P1]>r[P3] goto P2
    ++** Synopsis: IF r[P3]>r[P1]
    + **
    + ** This works just like the Lt opcode except that the jump is taken if
    + ** the content of register P3 is greater than the content of
    + ** register P1.  See the Lt opcode for additional information.
    + */
    + /* Opcode: Ge P1 P2 P3 P4 P5
    +-** Synopsis: if r[P1]>=r[P3] goto P2
    ++** Synopsis: IF r[P3]>=r[P1]
    + **
    + ** This works just like the Lt opcode except that the jump is taken if
    + ** the content of register P3 is greater than or equal to the content of
    +@@ -74819,7 +81847,7 @@ case OP_Lt:               /* same as TK_LT, jump, in1, in3 */
    + case OP_Le:               /* same as TK_LE, jump, in1, in3 */
    + case OP_Gt:               /* same as TK_GT, jump, in1, in3 */
    + case OP_Ge: {             /* same as TK_GE, jump, in1, in3 */
    +-  int res;            /* Result of the comparison of pIn1 against pIn3 */
    ++  int res, res2;      /* Result of the comparison of pIn1 against pIn3 */
    +   char affinity;      /* Affinity to use for comparison */
    +   u16 flags1;         /* Copy of initial value of pIn1->flags */
    +   u16 flags3;         /* Copy of initial value of pIn3->flags */
    +@@ -74838,13 +81866,12 @@ case OP_Ge: {             /* same as TK_GE, jump, in1, in3 */
    +       assert( pOp->opcode==OP_Eq || pOp->opcode==OP_Ne );
    +       assert( (flags1 & MEM_Cleared)==0 );
    +       assert( (pOp->p5 & SQLITE_JUMPIFNULL)==0 );
    +-      if( (flags1&MEM_Null)!=0
    +-       && (flags3&MEM_Null)!=0
    ++      if( (flags1&flags3&MEM_Null)!=0
    +        && (flags3&MEM_Cleared)==0
    +       ){
    +-        res = 0;  /* Results are equal */
    ++        res = 0;  /* Operands are equal */
    +       }else{
    +-        res = 1;  /* Results are not equal */
    ++        res = 1;  /* Operands are not equal */
    +       }
    +     }else{
    +       /* SQLITE_NULLEQ is clear and at least one operand is NULL,
    +@@ -74853,6 +81880,8 @@ case OP_Ge: {             /* same as TK_GE, jump, in1, in3 */
    +       */
    +       if( pOp->p5 & SQLITE_STOREP2 ){
    +         pOut = &aMem[pOp->p2];
    ++        iCompare = 1;    /* Operands are not equal */
    ++        memAboutToChange(p, pOut);
    +         MemSetTypeFlag(pOut, MEM_Null);
    +         REGISTER_TRACE(pOp->p2, pOut);
    +       }else{
    +@@ -74867,21 +81896,34 @@ case OP_Ge: {             /* same as TK_GE, jump, in1, in3 */
    +     /* Neither operand is NULL.  Do a comparison. */
    +     affinity = pOp->p5 & SQLITE_AFF_MASK;
    +     if( affinity>=SQLITE_AFF_NUMERIC ){
    +-      if( (pIn1->flags & (MEM_Int|MEM_Real|MEM_Str))==MEM_Str ){
    +-        applyNumericAffinity(pIn1,0);
    ++      if( (flags1 | flags3)&MEM_Str ){
    ++        if( (flags1 & (MEM_Int|MEM_Real|MEM_Str))==MEM_Str ){
    ++          applyNumericAffinity(pIn1,0);
    ++          testcase( flags3!=pIn3->flags ); /* Possible if pIn1==pIn3 */
    ++          flags3 = pIn3->flags;
    ++        }
    ++        if( (flags3 & (MEM_Int|MEM_Real|MEM_Str))==MEM_Str ){
    ++          applyNumericAffinity(pIn3,0);
    ++        }
    +       }
    +-      if( (pIn3->flags & (MEM_Int|MEM_Real|MEM_Str))==MEM_Str ){
    +-        applyNumericAffinity(pIn3,0);
    ++      /* Handle the common case of integer comparison here, as an
    ++      ** optimization, to avoid a call to sqlite3MemCompare() */
    ++      if( (pIn1->flags & pIn3->flags & MEM_Int)!=0 ){
    ++        if( pIn3->u.i > pIn1->u.i ){ res = +1; goto compare_op; }
    ++        if( pIn3->u.i < pIn1->u.i ){ res = -1; goto compare_op; }
    ++        res = 0;
    ++        goto compare_op;
    +       }
    +     }else if( affinity==SQLITE_AFF_TEXT ){
    +-      if( (pIn1->flags & MEM_Str)==0 && (pIn1->flags & (MEM_Int|MEM_Real))!=0 ){
    ++      if( (flags1 & MEM_Str)==0 && (flags1 & (MEM_Int|MEM_Real))!=0 ){
    +         testcase( pIn1->flags & MEM_Int );
    +         testcase( pIn1->flags & MEM_Real );
    +         sqlite3VdbeMemStringify(pIn1, encoding, 1);
    +         testcase( (flags1&MEM_Dyn) != (pIn1->flags&MEM_Dyn) );
    +         flags1 = (pIn1->flags & ~MEM_TypeMask) | (flags1 & MEM_TypeMask);
    ++        assert( pIn1!=pIn3 );
    +       }
    +-      if( (pIn3->flags & MEM_Str)==0 && (pIn3->flags & (MEM_Int|MEM_Real))!=0 ){
    ++      if( (flags3 & MEM_Str)==0 && (flags3 & (MEM_Int|MEM_Real))!=0 ){
    +         testcase( pIn3->flags & MEM_Int );
    +         testcase( pIn3->flags & MEM_Real );
    +         sqlite3VdbeMemStringify(pIn3, encoding, 1);
    +@@ -74890,24 +81932,26 @@ case OP_Ge: {             /* same as TK_GE, jump, in1, in3 */
    +       }
    +     }
    +     assert( pOp->p4type==P4_COLLSEQ || pOp->p4.pColl==0 );
    +-    if( pIn1->flags & MEM_Zero ){
    +-      sqlite3VdbeMemExpandBlob(pIn1);
    +-      flags1 &= ~MEM_Zero;
    +-    }
    +-    if( pIn3->flags & MEM_Zero ){
    +-      sqlite3VdbeMemExpandBlob(pIn3);
    +-      flags3 &= ~MEM_Zero;
    +-    }
    +-    if( db->mallocFailed ) goto no_mem;
    +     res = sqlite3MemCompare(pIn3, pIn1, pOp->p4.pColl);
    +   }
    +-  switch( pOp->opcode ){
    +-    case OP_Eq:    res = res==0;     break;
    +-    case OP_Ne:    res = res!=0;     break;
    +-    case OP_Lt:    res = res<0;      break;
    +-    case OP_Le:    res = res<=0;     break;
    +-    case OP_Gt:    res = res>0;      break;
    +-    default:       res = res>=0;     break;
    ++compare_op:
    ++  /* At this point, res is negative, zero, or positive if reg[P1] is
    ++  ** less than, equal to, or greater than reg[P3], respectively.  Compute
    ++  ** the answer to this operator in res2, depending on what the comparison
    ++  ** operator actually is.  The next block of code depends on the fact
    ++  ** that the 6 comparison operators are consecutive integers in this
    ++  ** order:  NE, EQ, GT, LE, LT, GE */
    ++  assert( OP_Eq==OP_Ne+1 ); assert( OP_Gt==OP_Ne+2 ); assert( OP_Le==OP_Ne+3 );
    ++  assert( OP_Lt==OP_Ne+4 ); assert( OP_Ge==OP_Ne+5 );
    ++  if( res<0 ){                        /* ne, eq, gt, le, lt, ge */
    ++    static const unsigned char aLTb[] = { 1,  0,  0,  1,  1,  0 };
    ++    res2 = aLTb[pOp->opcode - OP_Ne];
    ++  }else if( res==0 ){
    ++    static const unsigned char aEQb[] = { 0,  1,  0,  1,  0,  1 };
    ++    res2 = aEQb[pOp->opcode - OP_Ne];
    ++  }else{
    ++    static const unsigned char aGTb[] = { 1,  0,  1,  0,  0,  1 };
    ++    res2 = aGTb[pOp->opcode - OP_Ne];
    +   }
    + 
    +   /* Undo any changes made by applyAffinity() to the input registers. */
    +@@ -74918,32 +81962,71 @@ case OP_Ge: {             /* same as TK_GE, jump, in1, in3 */
    + 
    +   if( pOp->p5 & SQLITE_STOREP2 ){
    +     pOut = &aMem[pOp->p2];
    ++    iCompare = res;
    ++    if( (pOp->p5 & SQLITE_KEEPNULL)!=0 ){
    ++      /* The KEEPNULL flag prevents OP_Eq from overwriting a NULL with 1
    ++      ** and prevents OP_Ne from overwriting NULL with 0.  This flag
    ++      ** is only used in contexts where either:
    ++      **   (1) op==OP_Eq && (r[P2]==NULL || r[P2]==0)
    ++      **   (2) op==OP_Ne && (r[P2]==NULL || r[P2]==1)
    ++      ** Therefore it is not necessary to check the content of r[P2] for
    ++      ** NULL. */
    ++      assert( pOp->opcode==OP_Ne || pOp->opcode==OP_Eq );
    ++      assert( res2==0 || res2==1 );
    ++      testcase( res2==0 && pOp->opcode==OP_Eq );
    ++      testcase( res2==1 && pOp->opcode==OP_Eq );
    ++      testcase( res2==0 && pOp->opcode==OP_Ne );
    ++      testcase( res2==1 && pOp->opcode==OP_Ne );
    ++      if( (pOp->opcode==OP_Eq)==res2 ) break;
    ++    }
    +     memAboutToChange(p, pOut);
    +     MemSetTypeFlag(pOut, MEM_Int);
    +-    pOut->u.i = res;
    ++    pOut->u.i = res2;
    +     REGISTER_TRACE(pOp->p2, pOut);
    +   }else{
    +     VdbeBranchTaken(res!=0, (pOp->p5 & SQLITE_NULLEQ)?2:3);
    +-    if( res ){
    ++    if( res2 ){
    +       goto jump_to_p2;
    +     }
    +   }
    +   break;
    + }
    + 
    ++/* Opcode: ElseNotEq * P2 * * *
    ++**
    ++** This opcode must immediately follow an OP_Lt or OP_Gt comparison operator.
    ++** If result of an OP_Eq comparison on the same two operands
    ++** would have be NULL or false (0), then then jump to P2. 
    ++** If the result of an OP_Eq comparison on the two previous operands
    ++** would have been true (1), then fall through.
    ++*/
    ++case OP_ElseNotEq: {       /* same as TK_ESCAPE, jump */
    ++  assert( pOp>aOp );
    ++  assert( pOp[-1].opcode==OP_Lt || pOp[-1].opcode==OP_Gt );
    ++  assert( pOp[-1].p5 & SQLITE_STOREP2 );
    ++  VdbeBranchTaken(iCompare!=0, 2);
    ++  if( iCompare!=0 ) goto jump_to_p2;
    ++  break;
    ++}
    ++
    ++
    + /* Opcode: Permutation * * * P4 *
    + **
    +-** Set the permutation used by the OP_Compare operator to be the array
    +-** of integers in P4.
    ++** Set the permutation used by the OP_Compare operator in the next
    ++** instruction.  The permutation is stored in the P4 operand.
    + **
    + ** The permutation is only valid until the next OP_Compare that has
    + ** the OPFLAG_PERMUTE bit set in P5. Typically the OP_Permutation should 
    + ** occur immediately prior to the OP_Compare.
    ++**
    ++** The first integer in the P4 integer array is the length of the array
    ++** and does not become part of the permutation.
    + */
    + case OP_Permutation: {
    +   assert( pOp->p4type==P4_INTARRAY );
    +   assert( pOp->p4.ai );
    +-  aPermute = pOp->p4.ai;
    ++  assert( pOp[1].opcode==OP_Compare );
    ++  assert( pOp[1].p5 & OPFLAG_PERMUTE );
    +   break;
    + }
    + 
    +@@ -74976,23 +82059,32 @@ case OP_Compare: {
    +   int idx;
    +   CollSeq *pColl;    /* Collating sequence to use on this term */
    +   int bRev;          /* True for DESCENDING sort order */
    ++  int *aPermute;     /* The permutation */
    + 
    +-  if( (pOp->p5 & OPFLAG_PERMUTE)==0 ) aPermute = 0;
    ++  if( (pOp->p5 & OPFLAG_PERMUTE)==0 ){
    ++    aPermute = 0;
    ++  }else{
    ++    assert( pOp>aOp );
    ++    assert( pOp[-1].opcode==OP_Permutation );
    ++    assert( pOp[-1].p4type==P4_INTARRAY );
    ++    aPermute = pOp[-1].p4.ai + 1;
    ++    assert( aPermute!=0 );
    ++  }
    +   n = pOp->p3;
    +   pKeyInfo = pOp->p4.pKeyInfo;
    +   assert( n>0 );
    +   assert( pKeyInfo!=0 );
    +   p1 = pOp->p1;
    +   p2 = pOp->p2;
    +-#if SQLITE_DEBUG
    ++#ifdef SQLITE_DEBUG
    +   if( aPermute ){
    +     int k, mx = 0;
    +     for(k=0; k<n; k++) if( aPermute[k]>mx ) mx = aPermute[k];
    +-    assert( p1>0 && p1+mx<=(p->nMem-p->nCursor)+1 );
    +-    assert( p2>0 && p2+mx<=(p->nMem-p->nCursor)+1 );
    ++    assert( p1>0 && p1+mx<=(p->nMem+1 - p->nCursor)+1 );
    ++    assert( p2>0 && p2+mx<=(p->nMem+1 - p->nCursor)+1 );
    +   }else{
    +-    assert( p1>0 && p1+n<=(p->nMem-p->nCursor)+1 );
    +-    assert( p2>0 && p2+n<=(p->nMem-p->nCursor)+1 );
    ++    assert( p1>0 && p1+n<=(p->nMem+1 - p->nCursor)+1 );
    ++    assert( p2>0 && p2+n<=(p->nMem+1 - p->nCursor)+1 );
    +   }
    + #endif /* SQLITE_DEBUG */
    +   for(i=0; i<n; i++){
    +@@ -75001,7 +82093,7 @@ case OP_Compare: {
    +     assert( memIsValid(&aMem[p2+idx]) );
    +     REGISTER_TRACE(p1+idx, &aMem[p1+idx]);
    +     REGISTER_TRACE(p2+idx, &aMem[p2+idx]);
    +-    assert( i<pKeyInfo->nField );
    ++    assert( i<pKeyInfo->nKeyField );
    +     pColl = pKeyInfo->aColl[i];
    +     bRev = pKeyInfo->aSortOrder[i];
    +     iCompare = sqlite3MemCompare(&aMem[p1+idx], &aMem[p2+idx], pColl);
    +@@ -75010,7 +82102,6 @@ case OP_Compare: {
    +       break;
    +     }
    +   }
    +-  aPermute = 0;
    +   break;
    + }
    + 
    +@@ -75123,23 +82214,39 @@ case OP_BitNot: {             /* same as TK_BITNOT, in1, out2 */
    + 
    + /* Opcode: Once P1 P2 * * *
    + **
    +-** 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.
    ++** Fall through to the next instruction the first time this opcode is
    ++** encountered on each invocation of the byte-code program.  Jump to P2
    ++** on the second and all subsequent encounters during the same invocation.
    ++**
    ++** Top-level programs determine first invocation by comparing the P1
    ++** operand against the P1 operand on the OP_Init opcode at the beginning
    ++** of the program.  If the P1 values differ, then fall through and make
    ++** the P1 of this opcode equal to the P1 of OP_Init.  If P1 values are
    ++** the same then take the jump.
    + **
    +-** All "once" flags are initially cleared whenever a prepared statement
    +-** first begins to run.
    ++** For subprograms, there is a bitmask in the VdbeFrame that determines
    ++** whether or not the jump should be taken.  The bitmask is necessary
    ++** because the self-altering code trick does not work for recursive
    ++** triggers.
    + */
    + case OP_Once: {             /* jump */
    +-  assert( pOp->p1<p->nOnceFlag );
    +-  VdbeBranchTaken(p->aOnceFlag[pOp->p1]!=0, 2);
    +-  if( p->aOnceFlag[pOp->p1] ){
    +-    goto jump_to_p2;
    ++  u32 iAddr;                /* Address of this instruction */
    ++  assert( p->aOp[0].opcode==OP_Init );
    ++  if( p->pFrame ){
    ++    iAddr = (int)(pOp - p->aOp);
    ++    if( (p->pFrame->aOnce[iAddr/8] & (1<<(iAddr & 7)))!=0 ){
    ++      VdbeBranchTaken(1, 2);
    ++      goto jump_to_p2;
    ++    }
    ++    p->pFrame->aOnce[iAddr/8] |= 1<<(iAddr & 7);
    +   }else{
    +-    p->aOnceFlag[pOp->p1] = 1;
    ++    if( p->aOp[0].p1==pOp->p1 ){
    ++      VdbeBranchTaken(1, 2);
    ++      goto jump_to_p2;
    ++    }
    +   }
    ++  VdbeBranchTaken(0, 2);
    ++  pOp->p1 = p->aOp[0].p1;
    +   break;
    + }
    + 
    +@@ -75177,7 +82284,7 @@ case OP_IfNot: {            /* jump, in1 */
    + }
    + 
    + /* Opcode: IsNull P1 P2 * * *
    +-** Synopsis:  if r[P1]==NULL goto P2
    ++** Synopsis: if r[P1]==NULL goto P2
    + **
    + ** Jump to P2 if the value in register P1 is NULL.
    + */
    +@@ -75204,8 +82311,56 @@ case OP_NotNull: {            /* same as TK_NOTNULL, jump, in1 */
    +   break;
    + }
    + 
    ++/* Opcode: IfNullRow P1 P2 P3 * *
    ++** Synopsis: if P1.nullRow then r[P3]=NULL, goto P2
    ++**
    ++** Check the cursor P1 to see if it is currently pointing at a NULL row.
    ++** If it is, then set register P3 to NULL and jump immediately to P2.
    ++** If P1 is not on a NULL row, then fall through without making any
    ++** changes.
    ++*/
    ++case OP_IfNullRow: {         /* jump */
    ++  assert( pOp->p1>=0 && pOp->p1<p->nCursor );
    ++  assert( p->apCsr[pOp->p1]!=0 );
    ++  if( p->apCsr[pOp->p1]->nullRow ){
    ++    sqlite3VdbeMemSetNull(aMem + pOp->p3);
    ++    goto jump_to_p2;
    ++  }
    ++  break;
    ++}
    ++
    ++#ifdef SQLITE_ENABLE_OFFSET_SQL_FUNC
    ++/* Opcode: Offset P1 P2 P3 * *
    ++** Synopsis: r[P3] = sqlite_offset(P1)
    ++**
    ++** Store in register r[P3] the byte offset into the database file that is the
    ++** start of the payload for the record at which that cursor P1 is currently
    ++** pointing.
    ++**
    ++** P2 is the column number for the argument to the sqlite_offset() function.
    ++** This opcode does not use P2 itself, but the P2 value is used by the
    ++** code generator.  The P1, P2, and P3 operands to this opcode are the
    ++** as as for OP_Column.
    ++**
    ++** This opcode is only available if SQLite is compiled with the
    ++** -DSQLITE_ENABLE_OFFSET_SQL_FUNC option.
    ++*/
    ++case OP_Offset: {          /* out3 */
    ++  VdbeCursor *pC;    /* The VDBE cursor */
    ++  assert( pOp->p1>=0 && pOp->p1<p->nCursor );
    ++  pC = p->apCsr[pOp->p1];
    ++  pOut = &p->aMem[pOp->p3];
    ++  if( NEVER(pC==0) || pC->eCurType!=CURTYPE_BTREE ){
    ++    sqlite3VdbeMemSetNull(pOut);
    ++  }else{
    ++    sqlite3VdbeMemSetInt64(pOut, sqlite3BtreeOffset(pC->uc.pCursor));
    ++  }
    ++  break;
    ++}
    ++#endif /* SQLITE_ENABLE_OFFSET_SQL_FUNC */
    ++
    + /* Opcode: Column P1 P2 P3 P4 P5
    +-** Synopsis:  r[P3]=PX
    ++** Synopsis: r[P3]=PX
    + **
    + ** Interpret the data that cursor P1 points to as a structure built using
    + ** the MakeRecord instruction.  (See the MakeRecord opcode for additional
    +@@ -75215,7 +82370,7 @@ case OP_NotNull: {            /* same as TK_NOTNULL, jump, in1 */
    + **
    + ** The value extracted is stored in register P3.
    + **
    +-** If the column contains fewer than P2 fields, then extract a NULL.  Or,
    ++** If the record contains fewer than P2 fields, then extract a NULL.  Or,
    + ** if the P4 argument is a P4_MEM use the value of the P4 argument as
    + ** the result.
    + **
    +@@ -75224,13 +82379,12 @@ case OP_NotNull: {            /* same as TK_NOTNULL, jump, in1 */
    + ** The first OP_Column against a pseudo-table after the value of the content
    + ** register has changed should have this bit set.
    + **
    +-** If the OPFLAG_LENGTHARG and OPFLAG_TYPEOFARG bits are set on P5 when
    ++** If the OPFLAG_LENGTHARG and OPFLAG_TYPEOFARG bits are set on P5 then
    + ** the result is guaranteed to only be used as the argument of a length()
    + ** or typeof() function, respectively.  The loading of large blobs can be
    + ** skipped for length() and all content loading can be skipped for typeof().
    + */
    + case OP_Column: {
    +-  i64 payloadSize64; /* Number of bytes in the record */
    +   int p2;            /* column number to retrieve */
    +   VdbeCursor *pC;    /* The VDBE cursor */
    +   BtCursor *pCrsr;   /* The BTree cursor */
    +@@ -75242,107 +82396,102 @@ case OP_Column: {
    +   const u8 *zData;   /* Part of the record being decoded */
    +   const u8 *zHdr;    /* Next unparsed byte of the header */
    +   const u8 *zEndHdr; /* Pointer to first byte after the header */
    +-  u32 offset;        /* Offset into the data */
    +-  u32 szField;       /* Number of bytes in the content of a field */
    +-  u32 avail;         /* Number of bytes of available data */
    ++  u64 offset64;      /* 64-bit offset */
    +   u32 t;             /* A type code from the record header */
    +-  u16 fx;            /* pDest->flags value */
    +   Mem *pReg;         /* PseudoTable input register */
    + 
    ++  pC = p->apCsr[pOp->p1];
    +   p2 = pOp->p2;
    +-  assert( pOp->p3>0 && pOp->p3<=(p->nMem-p->nCursor) );
    ++
    ++  /* If the cursor cache is stale (meaning it is not currently point at
    ++  ** the correct row) then bring it up-to-date by doing the necessary 
    ++  ** B-Tree seek. */
    ++  rc = sqlite3VdbeCursorMoveto(&pC, &p2);
    ++  if( rc ) goto abort_due_to_error;
    ++
    ++  assert( pOp->p3>0 && pOp->p3<=(p->nMem+1 - p->nCursor) );
    +   pDest = &aMem[pOp->p3];
    +   memAboutToChange(p, pDest);
    +   assert( pOp->p1>=0 && pOp->p1<p->nCursor );
    +-  pC = p->apCsr[pOp->p1];
    +   assert( pC!=0 );
    +   assert( p2<pC->nField );
    +   aOffset = pC->aOffset;
    +-#ifndef SQLITE_OMIT_VIRTUALTABLE
    +-  assert( pC->pVtabCursor==0 ); /* OP_Column never called on virtual table */
    +-#endif
    +-  pCrsr = pC->pCursor;
    +-  assert( pCrsr!=0 || pC->pseudoTableReg>0 ); /* pCrsr NULL on PseudoTables */
    +-  assert( pCrsr!=0 || pC->nullRow );          /* pC->nullRow on PseudoTables */
    ++  assert( pC->eCurType!=CURTYPE_VTAB );
    ++  assert( pC->eCurType!=CURTYPE_PSEUDO || pC->nullRow );
    ++  assert( pC->eCurType!=CURTYPE_SORTER );
    + 
    +-  /* If the cursor cache is stale, bring it up-to-date */
    +-  rc = sqlite3VdbeCursorMoveto(pC);
    +-  if( rc ) goto abort_due_to_error;
    +-  if( pC->cacheStatus!=p->cacheCtr ){
    ++  if( pC->cacheStatus!=p->cacheCtr ){                /*OPTIMIZATION-IF-FALSE*/
    +     if( pC->nullRow ){
    +-      if( pCrsr==0 ){
    +-        assert( pC->pseudoTableReg>0 );
    +-        pReg = &aMem[pC->pseudoTableReg];
    ++      if( pC->eCurType==CURTYPE_PSEUDO ){
    ++        /* For the special case of as pseudo-cursor, the seekResult field
    ++        ** identifies the register that holds the record */
    ++        assert( pC->seekResult>0 );
    ++        pReg = &aMem[pC->seekResult];
    +         assert( pReg->flags & MEM_Blob );
    +         assert( memIsValid(pReg) );
    +-        pC->payloadSize = pC->szRow = avail = pReg->n;
    ++        pC->payloadSize = pC->szRow = pReg->n;
    +         pC->aRow = (u8*)pReg->z;
    +       }else{
    +         sqlite3VdbeMemSetNull(pDest);
    +         goto op_column_out;
    +       }
    +     }else{
    ++      pCrsr = pC->uc.pCursor;
    ++      assert( pC->eCurType==CURTYPE_BTREE );
    +       assert( pCrsr );
    +-      if( pC->isTable==0 ){
    +-        assert( sqlite3BtreeCursorIsValid(pCrsr) );
    +-        VVA_ONLY(rc =) sqlite3BtreeKeySize(pCrsr, &payloadSize64);
    +-        assert( rc==SQLITE_OK ); /* True because of CursorMoveto() call above */
    +-        /* sqlite3BtreeParseCellPtr() uses getVarint32() to extract the
    +-        ** payload size, so it is impossible for payloadSize64 to be
    +-        ** larger than 32 bits. */
    +-        assert( (payloadSize64 & SQLITE_MAX_U32)==(u64)payloadSize64 );
    +-        pC->aRow = sqlite3BtreeKeyFetch(pCrsr, &avail);
    +-        pC->payloadSize = (u32)payloadSize64;
    +-      }else{
    +-        assert( sqlite3BtreeCursorIsValid(pCrsr) );
    +-        VVA_ONLY(rc =) sqlite3BtreeDataSize(pCrsr, &pC->payloadSize);
    +-        assert( rc==SQLITE_OK );   /* DataSize() cannot fail */
    +-        pC->aRow = sqlite3BtreeDataFetch(pCrsr, &avail);
    +-      }
    +-      assert( avail<=65536 );  /* Maximum page size is 64KiB */
    +-      if( pC->payloadSize <= (u32)avail ){
    +-        pC->szRow = pC->payloadSize;
    +-      }else{
    +-        pC->szRow = avail;
    +-      }
    ++      assert( sqlite3BtreeCursorIsValid(pCrsr) );
    ++      pC->payloadSize = sqlite3BtreePayloadSize(pCrsr);
    ++      pC->aRow = sqlite3BtreePayloadFetch(pCrsr, &pC->szRow);
    ++      assert( pC->szRow<=pC->payloadSize );
    ++      assert( pC->szRow<=65536 );  /* Maximum page size is 64KiB */
    +       if( pC->payloadSize > (u32)db->aLimit[SQLITE_LIMIT_LENGTH] ){
    +         goto too_big;
    +       }
    +     }
    +     pC->cacheStatus = p->cacheCtr;
    +-    pC->iHdrOffset = getVarint32(pC->aRow, offset);
    ++    pC->iHdrOffset = getVarint32(pC->aRow, aOffset[0]);
    +     pC->nHdrParsed = 0;
    +-    aOffset[0] = offset;
    + 
    +-    /* Make sure a corrupt database has not given us an oversize header.
    +-    ** Do this now to avoid an oversize memory allocation.
    +-    **
    +-    ** Type entries can be between 1 and 5 bytes each.  But 4 and 5 byte
    +-    ** types use so much data space that there can only be 4096 and 32 of
    +-    ** them, respectively.  So the maximum header length results from a
    +-    ** 3-byte type for each of the maximum of 32768 columns plus three
    +-    ** extra bytes for the header length itself.  32768*3 + 3 = 98307.
    +-    */
    +-    if( offset > 98307 || offset > pC->payloadSize ){
    +-      rc = SQLITE_CORRUPT_BKPT;
    +-      goto op_column_error;
    +-    }
    + 
    +-    if( avail<offset ){
    ++    if( pC->szRow<aOffset[0] ){      /*OPTIMIZATION-IF-FALSE*/
    +       /* pC->aRow does not have to hold the entire row, but it does at least
    +       ** need to cover the header of the record.  If pC->aRow does not contain
    +       ** the complete header, then set it to zero, forcing the header to be
    +       ** dynamically allocated. */
    +       pC->aRow = 0;
    +       pC->szRow = 0;
    +-    }
    + 
    +-    /* The following goto is an optimization.  It can be omitted and
    +-    ** everything will still work.  But OP_Column is measurably faster
    +-    ** by skipping the subsequent conditional, which is always true.
    +-    */
    +-    assert( pC->nHdrParsed<=p2 );         /* Conditional skipped */
    +-    goto op_column_read_header;
    ++      /* Make sure a corrupt database has not given us an oversize header.
    ++      ** Do this now to avoid an oversize memory allocation.
    ++      **
    ++      ** Type entries can be between 1 and 5 bytes each.  But 4 and 5 byte
    ++      ** types use so much data space that there can only be 4096 and 32 of
    ++      ** them, respectively.  So the maximum header length results from a
    ++      ** 3-byte type for each of the maximum of 32768 columns plus three
    ++      ** extra bytes for the header length itself.  32768*3 + 3 = 98307.
    ++      */
    ++      if( aOffset[0] > 98307 || aOffset[0] > pC->payloadSize ){
    ++        goto op_column_corrupt;
    ++      }
    ++    }else{
    ++      /* This is an optimization.  By skipping over the first few tests
    ++      ** (ex: pC->nHdrParsed<=p2) in the next section, we achieve a
    ++      ** measurable performance gain.
    ++      **
    ++      ** This branch is taken even if aOffset[0]==0.  Such a record is never
    ++      ** generated by SQLite, and could be considered corruption, but we
    ++      ** accept it for historical reasons.  When aOffset[0]==0, the code this
    ++      ** branch jumps to reads past the end of the record, but never more
    ++      ** than a few bytes.  Even if the record occurs at the end of the page
    ++      ** content area, the "page header" comes after the page content and so
    ++      ** this overread is harmless.  Similar overreads can occur for a corrupt
    ++      ** database file.
    ++      */
    ++      zData = pC->aRow;
    ++      assert( pC->nHdrParsed<=p2 );         /* Conditional skipped */
    ++      testcase( aOffset[0]==0 );
    ++      goto op_column_read_header;
    ++    }
    +   }
    + 
    +   /* Make sure at least the first p2+1 entries of the header have been
    +@@ -75352,65 +82501,58 @@ case OP_Column: {
    +     /* If there is more header available for parsing in the record, try
    +     ** to extract additional fields up through the p2+1-th field 
    +     */
    +-    op_column_read_header:
    +     if( pC->iHdrOffset<aOffset[0] ){
    +       /* Make sure zData points to enough of the record to cover the header. */
    +       if( pC->aRow==0 ){
    +         memset(&sMem, 0, sizeof(sMem));
    +-        rc = sqlite3VdbeMemFromBtree(pCrsr, 0, aOffset[0], 
    +-                                     !pC->isTable, &sMem);
    +-        if( rc!=SQLITE_OK ){
    +-          goto op_column_error;
    +-        }
    ++        rc = sqlite3VdbeMemFromBtree(pC->uc.pCursor, 0, aOffset[0], &sMem);
    ++        if( rc!=SQLITE_OK ) goto abort_due_to_error;
    +         zData = (u8*)sMem.z;
    +       }else{
    +         zData = pC->aRow;
    +       }
    +   
    +       /* Fill in pC->aType[i] and aOffset[i] values through the p2-th field. */
    ++    op_column_read_header:
    +       i = pC->nHdrParsed;
    +-      offset = aOffset[i];
    ++      offset64 = aOffset[i];
    +       zHdr = zData + pC->iHdrOffset;
    +       zEndHdr = zData + aOffset[0];
    +-      assert( i<=p2 && zHdr<zEndHdr );
    ++      testcase( zHdr>=zEndHdr );
    +       do{
    +-        if( zHdr[0]<0x80 ){
    +-          t = zHdr[0];
    ++        if( (t = zHdr[0])<0x80 ){
    +           zHdr++;
    ++          offset64 += sqlite3VdbeOneByteSerialTypeLen(t);
    +         }else{
    +           zHdr += sqlite3GetVarint32(zHdr, &t);
    ++          offset64 += sqlite3VdbeSerialTypeLen(t);
    +         }
    +-        pC->aType[i] = t;
    +-        szField = sqlite3VdbeSerialTypeLen(t);
    +-        offset += szField;
    +-        if( offset<szField ){  /* True if offset overflows */
    +-          zHdr = &zEndHdr[1];  /* Forces SQLITE_CORRUPT return below */
    +-          break;
    +-        }
    +-        i++;
    +-        aOffset[i] = offset;
    ++        pC->aType[i++] = t;
    ++        aOffset[i] = (u32)(offset64 & 0xffffffff);
    +       }while( i<=p2 && zHdr<zEndHdr );
    +-      pC->nHdrParsed = i;
    +-      pC->iHdrOffset = (u32)(zHdr - zData);
    +-      if( pC->aRow==0 ){
    +-        sqlite3VdbeMemRelease(&sMem);
    +-        sMem.flags = MEM_Null;
    +-      }
    +-  
    ++
    +       /* The record is corrupt if any of the following are true:
    +       ** (1) the bytes of the header extend past the declared header size
    +-      **          (zHdr>zEndHdr)
    +       ** (2) the entire header was used but not all data was used
    +-      **          (zHdr==zEndHdr && offset!=pC->payloadSize)
    +       ** (3) the end of the data extends beyond the end of the record.
    +-      **          (offset > pC->payloadSize)
    +       */
    +-      if( (zHdr>=zEndHdr && (zHdr>zEndHdr || offset!=pC->payloadSize))
    +-       || (offset > pC->payloadSize)
    ++      if( (zHdr>=zEndHdr && (zHdr>zEndHdr || offset64!=pC->payloadSize))
    ++       || (offset64 > pC->payloadSize)
    +       ){
    +-        rc = SQLITE_CORRUPT_BKPT;
    +-        goto op_column_error;
    ++        if( aOffset[0]==0 ){
    ++          i = 0;
    ++          zHdr = zEndHdr;
    ++        }else{
    ++          if( pC->aRow==0 ) sqlite3VdbeMemRelease(&sMem);
    ++          goto op_column_corrupt;
    ++        }
    +       }
    ++
    ++      pC->nHdrParsed = i;
    ++      pC->iHdrOffset = (u32)(zHdr - zData);
    ++      if( pC->aRow==0 ) sqlite3VdbeMemRelease(&sMem);
    ++    }else{
    ++      t = 0;
    +     }
    + 
    +     /* If after trying to extract new entries from the header, nHdrParsed is
    +@@ -75425,6 +82567,8 @@ case OP_Column: {
    +       }
    +       goto op_column_out;
    +     }
    ++  }else{
    ++    t = pC->aType[p2];
    +   }
    + 
    +   /* Extract the content for the p2+1-th column.  Control can only
    +@@ -75434,13 +82578,37 @@ case OP_Column: {
    +   assert( p2<pC->nHdrParsed );
    +   assert( rc==SQLITE_OK );
    +   assert( sqlite3VdbeCheckMemInvariants(pDest) );
    +-  if( VdbeMemDynamic(pDest) ) sqlite3VdbeMemSetNull(pDest);
    +-  t = pC->aType[p2];
    ++  if( VdbeMemDynamic(pDest) ){
    ++    sqlite3VdbeMemSetNull(pDest);
    ++  }
    ++  assert( t==pC->aType[p2] );
    +   if( pC->szRow>=aOffset[p2+1] ){
    +     /* This is the common case where the desired content fits on the original
    +     ** page - where the content is not on an overflow page */
    +-    sqlite3VdbeSerialGet(pC->aRow+aOffset[p2], t, pDest);
    ++    zData = pC->aRow + aOffset[p2];
    ++    if( t<12 ){
    ++      sqlite3VdbeSerialGet(zData, t, pDest);
    ++    }else{
    ++      /* If the column value is a string, we need a persistent value, not
    ++      ** a MEM_Ephem value.  This branch is a fast short-cut that is equivalent
    ++      ** to calling sqlite3VdbeSerialGet() and sqlite3VdbeDeephemeralize().
    ++      */
    ++      static const u16 aFlag[] = { MEM_Blob, MEM_Str|MEM_Term };
    ++      pDest->n = len = (t-12)/2;
    ++      pDest->enc = encoding;
    ++      if( pDest->szMalloc < len+2 ){
    ++        pDest->flags = MEM_Null;
    ++        if( sqlite3VdbeMemGrow(pDest, len+2, 0) ) goto no_mem;
    ++      }else{
    ++        pDest->z = pDest->zMalloc;
    ++      }
    ++      memcpy(pDest->z, zData, len);
    ++      pDest->z[len] = 0;
    ++      pDest->z[len+1] = 0;
    ++      pDest->flags = aFlag[t&1];
    ++    }
    +   }else{
    ++    pDest->enc = encoding;
    +     /* This branch happens only when content is on overflow pages */
    +     if( ((pOp->p5 & (OPFLAG_LENGTHARG|OPFLAG_TYPEOFARG))!=0
    +           && ((t>=12 && (t&1)==0) || (pOp->p5 & OPFLAG_TYPEOFARG)!=0))
    +@@ -75451,42 +82619,35 @@ case OP_Column: {
    +       **    2. the length(X) function if X is a blob, and
    +       **    3. if the content length is zero.
    +       ** So we might as well use bogus content rather than reading
    +-      ** content from disk.  NULL will work for the value for strings
    +-      ** and blobs and whatever is in the payloadSize64 variable
    +-      ** will work for everything else. */
    +-      sqlite3VdbeSerialGet(t<=13 ? (u8*)&payloadSize64 : 0, t, pDest);
    ++      ** content from disk. 
    ++      **
    ++      ** Although sqlite3VdbeSerialGet() may read at most 8 bytes from the
    ++      ** buffer passed to it, debugging function VdbeMemPrettyPrint() may
    ++      ** read up to 16. So 16 bytes of bogus content is supplied.
    ++      */
    ++      static u8 aZero[16];  /* This is the bogus content */
    ++      sqlite3VdbeSerialGet(aZero, t, pDest);
    +     }else{
    +-      rc = sqlite3VdbeMemFromBtree(pCrsr, aOffset[p2], len, !pC->isTable,
    +-                                   pDest);
    +-      if( rc!=SQLITE_OK ){
    +-        goto op_column_error;
    +-      }
    ++      rc = sqlite3VdbeMemFromBtree(pC->uc.pCursor, aOffset[p2], len, pDest);
    ++      if( rc!=SQLITE_OK ) goto abort_due_to_error;
    +       sqlite3VdbeSerialGet((const u8*)pDest->z, t, pDest);
    +       pDest->flags &= ~MEM_Ephem;
    +     }
    +   }
    +-  pDest->enc = encoding;
    + 
    + op_column_out:
    +-  /* If the column value is an ephemeral string, go ahead and persist
    +-  ** that string in case the cursor moves before the column value is
    +-  ** used.  The following code does the equivalent of Deephemeralize()
    +-  ** but does it faster. */
    +-  if( (pDest->flags & MEM_Ephem)!=0 && pDest->z ){
    +-    fx = pDest->flags & (MEM_Str|MEM_Blob);
    +-    assert( fx!=0 );
    +-    zData = (const u8*)pDest->z;
    +-    len = pDest->n;
    +-    if( sqlite3VdbeMemClearAndResize(pDest, len+2) ) goto no_mem;
    +-    memcpy(pDest->z, zData, len);
    +-    pDest->z[len] = 0;
    +-    pDest->z[len+1] = 0;
    +-    pDest->flags = fx|MEM_Term;
    +-  }
    +-op_column_error:
    +   UPDATE_MAX_BLOBSIZE(pDest);
    +   REGISTER_TRACE(pOp->p3, pDest);
    +   break;
    ++
    ++op_column_corrupt:
    ++  if( aOp[0].p3>0 ){
    ++    pOp = &aOp[aOp[0].p3-1];
    ++    break;
    ++  }else{
    ++    rc = SQLITE_CORRUPT_BKPT;
    ++    goto abort_due_to_error;
    ++  }
    + }
    + 
    + /* Opcode: Affinity P1 P2 * P4 *
    +@@ -75494,24 +82655,24 @@ op_column_error:
    + **
    + ** Apply affinities to a range of P2 registers starting with P1.
    + **
    +-** P4 is a string that is P2 characters long. The nth character of the
    +-** string indicates the column affinity that should be used for the nth
    ++** P4 is a string that is P2 characters long. The N-th character of the
    ++** string indicates the column affinity that should be used for the N-th
    + ** memory cell in the range.
    + */
    + case OP_Affinity: {
    +   const char *zAffinity;   /* The affinity to be applied */
    +-  char cAff;               /* A single character of affinity */
    + 
    +   zAffinity = pOp->p4.z;
    +   assert( zAffinity!=0 );
    ++  assert( pOp->p2>0 );
    +   assert( zAffinity[pOp->p2]==0 );
    +   pIn1 = &aMem[pOp->p1];
    +-  while( (cAff = *(zAffinity++))!=0 ){
    +-    assert( pIn1 <= &p->aMem[(p->nMem-p->nCursor)] );
    ++  do{
    ++    assert( pIn1 <= &p->aMem[(p->nMem+1 - p->nCursor)] );
    +     assert( memIsValid(pIn1) );
    +-    applyAffinity(pIn1, cAff, encoding);
    ++    applyAffinity(pIn1, *(zAffinity++), encoding);
    +     pIn1++;
    +-  }
    ++  }while( zAffinity[0] );
    +   break;
    + }
    + 
    +@@ -75522,8 +82683,8 @@ case OP_Affinity: {
    + ** use as a data record in a database table or as a key
    + ** in an index.  The OP_Column opcode can decode the record later.
    + **
    +-** P4 may be a string that is P2 characters long.  The nth character of the
    +-** string indicates the column affinity that should be used for the nth
    ++** P4 may be a string that is P2 characters long.  The N-th character of the
    ++** string indicates the column affinity that should be used for the N-th
    + ** field of the index key.
    + **
    + ** The mapping from character to affinity is given by the SQLITE_AFF_
    +@@ -75547,7 +82708,7 @@ case OP_MakeRecord: {
    +   int file_format;       /* File format to use for encoding */
    +   int i;                 /* Space used in zNewRecord[] header */
    +   int j;                 /* Space used in zNewRecord[] content */
    +-  int len;               /* Length of a field */
    ++  u32 len;               /* Length of a field */
    + 
    +   /* Assuming the record contains N fields, the record format looks
    +   ** like this:
    +@@ -75569,7 +82730,7 @@ case OP_MakeRecord: {
    +   nZero = 0;         /* Number of zero bytes at the end of the record */
    +   nField = pOp->p1;
    +   zAffinity = pOp->p4.z;
    +-  assert( nField>0 && pOp->p2>0 && pOp->p2+nField<=(p->nMem-p->nCursor)+1 );
    ++  assert( nField>0 && pOp->p2>0 && pOp->p2+nField<=(p->nMem+1 - p->nCursor)+1 );
    +   pData0 = &aMem[nField];
    +   nField = pOp->p2;
    +   pLast = &pData0[nField-1];
    +@@ -75591,16 +82752,38 @@ case OP_MakeRecord: {
    +     }while( zAffinity[0] );
    +   }
    + 
    ++#ifdef SQLITE_ENABLE_NULL_TRIM
    ++  /* NULLs can be safely trimmed from the end of the record, as long as
    ++  ** as the schema format is 2 or more and none of the omitted columns
    ++  ** have a non-NULL default value.  Also, the record must be left with
    ++  ** at least one field.  If P5>0 then it will be one more than the
    ++  ** index of the right-most column with a non-NULL default value */
    ++  if( pOp->p5 ){
    ++    while( (pLast->flags & MEM_Null)!=0 && nField>pOp->p5 ){
    ++      pLast--;
    ++      nField--;
    ++    }
    ++  }
    ++#endif
    ++
    +   /* Loop through the elements that will make up the record to figure
    +   ** out how much space is required for the new record.
    +   */
    +   pRec = pLast;
    +   do{
    +     assert( memIsValid(pRec) );
    +-    pRec->uTemp = serial_type = sqlite3VdbeSerialType(pRec, file_format);
    +-    len = sqlite3VdbeSerialTypeLen(serial_type);
    ++    serial_type = sqlite3VdbeSerialType(pRec, file_format, &len);
    +     if( pRec->flags & MEM_Zero ){
    +-      if( nData ){
    ++      if( serial_type==0 ){
    ++        /* Values with MEM_Null and MEM_Zero are created by xColumn virtual
    ++        ** table methods that never invoke sqlite3_result_xxxxx() while
    ++        ** computing an unchanging column value in an UPDATE statement.
    ++        ** Give such values a special internal-use-only serial-type of 10
    ++        ** so that they can be passed through to xUpdate and have
    ++        ** a true sqlite3_value_nochange(). */
    ++        assert( pOp->p5==OPFLAG_NOCHNG_MAGIC || CORRUPT_DB );
    ++        serial_type = 10;
    ++      }else if( nData ){
    +         if( sqlite3VdbeMemExpandBlob(pRec) ) goto no_mem;
    +       }else{
    +         nZero += pRec->u.nZero;
    +@@ -75611,7 +82794,10 @@ case OP_MakeRecord: {
    +     testcase( serial_type==127 );
    +     testcase( serial_type==128 );
    +     nHdr += serial_type<=127 ? 1 : sqlite3VarintLen(serial_type);
    +-  }while( (--pRec)>=pData0 );
    ++    pRec->uTemp = serial_type;
    ++    if( pRec==pData0 ) break;
    ++    pRec--;
    ++  }while(1);
    + 
    +   /* EVIDENCE-OF: R-22564-11647 The header begins with a single varint
    +   ** which determines the total number of bytes in the header. The varint
    +@@ -75660,14 +82846,13 @@ case OP_MakeRecord: {
    +   assert( i==nHdr );
    +   assert( j==nByte );
    + 
    +-  assert( pOp->p3>0 && pOp->p3<=(p->nMem-p->nCursor) );
    ++  assert( pOp->p3>0 && pOp->p3<=(p->nMem+1 - p->nCursor) );
    +   pOut->n = (int)nByte;
    +   pOut->flags = MEM_Blob;
    +   if( nZero ){
    +     pOut->u.nZero = nZero;
    +     pOut->flags |= MEM_Zero;
    +   }
    +-  pOut->enc = SQLITE_UTF8;  /* In case the blob is ever converted to text */
    +   REGISTER_TRACE(pOp->p3, pOut);
    +   UPDATE_MAX_BLOBSIZE(pOut);
    +   break;
    +@@ -75684,10 +82869,12 @@ case OP_Count: {         /* out2 */
    +   i64 nEntry;
    +   BtCursor *pCrsr;
    + 
    +-  pCrsr = p->apCsr[pOp->p1]->pCursor;
    ++  assert( p->apCsr[pOp->p1]->eCurType==CURTYPE_BTREE );
    ++  pCrsr = p->apCsr[pOp->p1]->uc.pCursor;
    +   assert( pCrsr );
    +   nEntry = 0;  /* Not needed.  Only used to silence a warning. */
    +   rc = sqlite3BtreeCount(pCrsr, &nEntry);
    ++  if( rc ) goto abort_due_to_error;
    +   pOut = out2Prerelease(p, pOp);
    +   pOut->u.i = nEntry;
    +   break;
    +@@ -75744,7 +82931,7 @@ case OP_Savepoint: {
    + #endif
    + 
    +       /* Create a new savepoint structure. */
    +-      pNew = sqlite3DbMallocRaw(db, sizeof(Savepoint)+nName+1);
    ++      pNew = sqlite3DbMallocRawNN(db, sizeof(Savepoint)+nName+1);
    +       if( pNew ){
    +         pNew->zName = (char *)&pNew[1];
    +         memcpy(pNew->zName, zName, nName+1);
    +@@ -75757,7 +82944,7 @@ case OP_Savepoint: {
    +         }else{
    +           db->nSavepoint++;
    +         }
    +-    
    ++
    +         /* Link the new savepoint into the database handle's list. */
    +         pNew->pNext = db->pSavepoint;
    +         db->pSavepoint = pNew;
    +@@ -75811,7 +82998,7 @@ case OP_Savepoint: {
    +         int isSchemaChange;
    +         iSavepoint = db->nSavepoint - iSavepoint - 1;
    +         if( p1==SAVEPOINT_ROLLBACK ){
    +-          isSchemaChange = (db->flags & SQLITE_InternChanges)!=0;
    ++          isSchemaChange = (db->mDbFlags & DBFLAG_SchemaChange)!=0;
    +           for(ii=0; ii<db->nDb; ii++){
    +             rc = sqlite3BtreeTripAllCursors(db->aDb[ii].pBt,
    +                                        SQLITE_ABORT_ROLLBACK,
    +@@ -75830,7 +83017,7 @@ case OP_Savepoint: {
    +         if( isSchemaChange ){
    +           sqlite3ExpirePreparedStatements(db);
    +           sqlite3ResetAllSchemasOfConnection(db);
    +-          db->flags = (db->flags | SQLITE_InternChanges);
    ++          db->mDbFlags |= DBFLAG_SchemaChange;
    +         }
    +       }
    +   
    +@@ -75865,6 +83052,7 @@ case OP_Savepoint: {
    +       }
    +     }
    +   }
    ++  if( rc ) goto abort_due_to_error;
    + 
    +   break;
    + }
    +@@ -75881,28 +83069,27 @@ case OP_Savepoint: {
    + case OP_AutoCommit: {
    +   int desiredAutoCommit;
    +   int iRollback;
    +-  int turnOnAC;
    + 
    +   desiredAutoCommit = pOp->p1;
    +   iRollback = pOp->p2;
    +-  turnOnAC = desiredAutoCommit && !db->autoCommit;
    +   assert( desiredAutoCommit==1 || desiredAutoCommit==0 );
    +   assert( desiredAutoCommit==1 || iRollback==0 );
    +   assert( db->nVdbeActive>0 );  /* At least this one VM is active */
    +   assert( p->bIsReader );
    + 
    +-  if( turnOnAC && !iRollback && db->nVdbeWrite>0 ){
    +-    /* If this instruction implements a COMMIT and other VMs are writing
    +-    ** return an error indicating that the other VMs must complete first. 
    +-    */
    +-    sqlite3VdbeError(p, "cannot commit transaction - "
    +-                        "SQL statements in progress");
    +-    rc = SQLITE_BUSY;
    +-  }else if( desiredAutoCommit!=db->autoCommit ){
    ++  if( desiredAutoCommit!=db->autoCommit ){
    +     if( iRollback ){
    +       assert( desiredAutoCommit==1 );
    +       sqlite3RollbackAll(db, SQLITE_ABORT_ROLLBACK);
    +       db->autoCommit = 1;
    ++    }else if( desiredAutoCommit && db->nVdbeWrite>0 ){
    ++      /* If this instruction implements a COMMIT and other VMs are writing
    ++      ** return an error indicating that the other VMs must complete first. 
    ++      */
    ++      sqlite3VdbeError(p, "cannot commit transaction - "
    ++                          "SQL statements in progress");
    ++      rc = SQLITE_BUSY;
    ++      goto abort_due_to_error;
    +     }else if( (rc = sqlite3VdbeCheckFk(p, 1))!=SQLITE_OK ){
    +       goto vdbe_return;
    +     }else{
    +@@ -75929,6 +83116,7 @@ case OP_AutoCommit: {
    +                    "cannot commit - no transaction is active"));
    +          
    +     rc = SQLITE_ERROR;
    ++    goto abort_due_to_error;
    +   }
    +   break;
    + }
    +@@ -75986,12 +83174,12 @@ case OP_Transaction: {
    +     rc = sqlite3BtreeBeginTrans(pBt, pOp->p2);
    +     testcase( rc==SQLITE_BUSY_SNAPSHOT );
    +     testcase( rc==SQLITE_BUSY_RECOVERY );
    +-    if( (rc&0xff)==SQLITE_BUSY ){
    +-      p->pc = (int)(pOp - aOp);
    +-      p->rc = rc;
    +-      goto vdbe_return;
    +-    }
    +     if( rc!=SQLITE_OK ){
    ++      if( (rc&0xff)==SQLITE_BUSY ){
    ++        p->pc = (int)(pOp - aOp);
    ++        p->rc = rc;
    ++        goto vdbe_return;
    ++      }
    +       goto abort_due_to_error;
    +     }
    + 
    +@@ -76018,10 +83206,9 @@ case OP_Transaction: {
    +     }
    + 
    +     /* Gather the schema version number for checking:
    +-    ** IMPLEMENTATION-OF: R-32195-19465 The schema version is used by SQLite
    +-    ** each time a query is executed to ensure that the internal cache of the
    +-    ** schema used when compiling the SQL query matches the schema of the
    +-    ** database against which the compiled query is actually executed.
    ++    ** IMPLEMENTATION-OF: R-03189-51135 As each SQL statement runs, the schema
    ++    ** version is checked to ensure that the schema has not changed since the
    ++    ** SQL statement was prepared.
    +     */
    +     sqlite3BtreeGetMeta(pBt, BTREE_SCHEMA_VERSION, (u32 *)&iMeta);
    +     iGen = db->aDb[pOp->p1].pSchema->iGeneration;
    +@@ -76051,6 +83238,7 @@ case OP_Transaction: {
    +     p->expired = 1;
    +     rc = SQLITE_SCHEMA;
    +   }
    ++  if( rc ) goto abort_due_to_error;
    +   break;
    + }
    + 
    +@@ -76087,15 +83275,15 @@ case OP_ReadCookie: {               /* out2 */
    + 
    + /* Opcode: SetCookie P1 P2 P3 * *
    + **
    +-** Write the content of register P3 (interpreted as an integer)
    +-** into cookie number P2 of database P1.  P2==1 is the schema version.  
    +-** P2==2 is the database format. P2==3 is the recommended pager cache 
    ++** Write the integer value P3 into cookie number P2 of database P1.
    ++** P2==1 is the schema version.  P2==2 is the database format.
    ++** P2==3 is the recommended pager cache 
    + ** size, and so forth.  P1==0 is the main database file and P1==1 is the 
    + ** database file used to store temporary tables.
    + **
    + ** A transaction must be started before executing this opcode.
    + */
    +-case OP_SetCookie: {       /* in3 */
    ++case OP_SetCookie: {
    +   Db *pDb;
    +   assert( pOp->p2<SQLITE_N_BTREE_META );
    +   assert( pOp->p1>=0 && pOp->p1<db->nDb );
    +@@ -76104,17 +83292,15 @@ case OP_SetCookie: {       /* in3 */
    +   pDb = &db->aDb[pOp->p1];
    +   assert( pDb->pBt!=0 );
    +   assert( sqlite3SchemaMutexHeld(db, pOp->p1, 0) );
    +-  pIn3 = &aMem[pOp->p3];
    +-  sqlite3VdbeMemIntegerify(pIn3);
    +   /* See note about index shifting on OP_ReadCookie */
    +-  rc = sqlite3BtreeUpdateMeta(pDb->pBt, pOp->p2, (int)pIn3->u.i);
    ++  rc = sqlite3BtreeUpdateMeta(pDb->pBt, pOp->p2, pOp->p3);
    +   if( pOp->p2==BTREE_SCHEMA_VERSION ){
    +     /* When the schema cookie changes, record the new cookie internally */
    +-    pDb->pSchema->schema_cookie = (int)pIn3->u.i;
    +-    db->flags |= SQLITE_InternChanges;
    ++    pDb->pSchema->schema_cookie = pOp->p3;
    ++    db->mDbFlags |= DBFLAG_SchemaChange;
    +   }else if( pOp->p2==BTREE_FILE_FORMAT ){
    +     /* Record changes in the file format */
    +-    pDb->pSchema->file_format = (u8)pIn3->u.i;
    ++    pDb->pSchema->file_format = pOp->p3;
    +   }
    +   if( pOp->p1==1 ){
    +     /* Invalidate all prepared statements whenever the TEMP database
    +@@ -76122,6 +83308,7 @@ case OP_SetCookie: {       /* in3 */
    +     sqlite3ExpirePreparedStatements(db);
    +     p->expired = 0;
    +   }
    ++  if( rc ) goto abort_due_to_error;
    +   break;
    + }
    + 
    +@@ -76212,7 +83399,6 @@ case OP_ReopenIdx: {
    + case OP_OpenRead:
    + case OP_OpenWrite:
    + 
    +-  assert( (pOp->p5&(OPFLAG_P2ISREG|OPFLAG_BULKCSR|OPFLAG_SEEKEQ))==pOp->p5 );
    +   assert( pOp->opcode==OP_OpenWrite || pOp->p5==0 || pOp->p5==OPFLAG_SEEKEQ );
    +   assert( p->bIsReader );
    +   assert( pOp->opcode==OP_OpenRead || pOp->opcode==OP_ReopenIdx
    +@@ -76220,7 +83406,7 @@ case OP_OpenWrite:
    + 
    +   if( p->expired ){
    +     rc = SQLITE_ABORT_ROLLBACK;
    +-    break;
    ++    goto abort_due_to_error;
    +   }
    + 
    +   nField = 0;
    +@@ -76233,7 +83419,8 @@ case OP_OpenWrite:
    +   pX = pDb->pBt;
    +   assert( pX!=0 );
    +   if( pOp->opcode==OP_OpenWrite ){
    +-    wrFlag = 1;
    ++    assert( OPFLAG_FORDELETE==BTREE_FORDELETE );
    ++    wrFlag = BTREE_WRCSR | (pOp->p5 & OPFLAG_FORDELETE);
    +     assert( sqlite3SchemaMutexHeld(db, iDb, 0) );
    +     if( pDb->pSchema->file_format < p->minWriteFileFormat ){
    +       p->minWriteFileFormat = pDb->pSchema->file_format;
    +@@ -76243,38 +83430,38 @@ case OP_OpenWrite:
    +   }
    +   if( pOp->p5 & OPFLAG_P2ISREG ){
    +     assert( p2>0 );
    +-    assert( p2<=(p->nMem-p->nCursor) );
    ++    assert( p2<=(p->nMem+1 - p->nCursor) );
    +     pIn2 = &aMem[p2];
    +     assert( memIsValid(pIn2) );
    +     assert( (pIn2->flags & MEM_Int)!=0 );
    +     sqlite3VdbeMemIntegerify(pIn2);
    +     p2 = (int)pIn2->u.i;
    +-    /* The p2 value always comes from a prior OP_CreateTable opcode and
    ++    /* The p2 value always comes from a prior OP_CreateBtree opcode and
    +     ** that opcode will always set the p2 value to 2 or more or else fail.
    +     ** If there were a failure, the prepared statement would have halted
    +     ** before reaching this instruction. */
    +-    if( NEVER(p2<2) ) {
    +-      rc = SQLITE_CORRUPT_BKPT;
    +-      goto abort_due_to_error;
    +-    }
    ++    assert( p2>=2 );
    +   }
    +   if( pOp->p4type==P4_KEYINFO ){
    +     pKeyInfo = pOp->p4.pKeyInfo;
    +     assert( pKeyInfo->enc==ENC(db) );
    +     assert( pKeyInfo->db==db );
    +-    nField = pKeyInfo->nField+pKeyInfo->nXField;
    ++    nField = pKeyInfo->nAllField;
    +   }else if( pOp->p4type==P4_INT32 ){
    +     nField = pOp->p4.i;
    +   }
    +   assert( pOp->p1>=0 );
    +   assert( nField>=0 );
    +   testcase( nField==0 );  /* Table with INTEGER PRIMARY KEY and nothing else */
    +-  pCur = allocateCursor(p, pOp->p1, nField, iDb, 1);
    ++  pCur = allocateCursor(p, pOp->p1, nField, iDb, CURTYPE_BTREE);
    +   if( pCur==0 ) goto no_mem;
    +   pCur->nullRow = 1;
    +   pCur->isOrdered = 1;
    +   pCur->pgnoRoot = p2;
    +-  rc = sqlite3BtreeCursor(pX, p2, wrFlag, pKeyInfo, pCur->pCursor);
    ++#ifdef SQLITE_DEBUG
    ++  pCur->wrFlag = wrFlag;
    ++#endif
    ++  rc = sqlite3BtreeCursor(pX, p2, wrFlag, pKeyInfo, pCur->uc.pCursor);
    +   pCur->pKeyInfo = pKeyInfo;
    +   /* Set the VdbeCursor.isTable variable. Previous versions of
    +   ** SQLite used to check if the root-page flags were sane at this point
    +@@ -76285,11 +83472,47 @@ case OP_OpenWrite:
    + open_cursor_set_hints:
    +   assert( OPFLAG_BULKCSR==BTREE_BULKLOAD );
    +   assert( OPFLAG_SEEKEQ==BTREE_SEEK_EQ );
    +-  sqlite3BtreeCursorHints(pCur->pCursor,
    +-                          (pOp->p5 & (OPFLAG_BULKCSR|OPFLAG_SEEKEQ)));
    ++  testcase( pOp->p5 & OPFLAG_BULKCSR );
    ++#ifdef SQLITE_ENABLE_CURSOR_HINTS
    ++  testcase( pOp->p2 & OPFLAG_SEEKEQ );
    ++#endif
    ++  sqlite3BtreeCursorHintFlags(pCur->uc.pCursor,
    ++                               (pOp->p5 & (OPFLAG_BULKCSR|OPFLAG_SEEKEQ)));
    ++  if( rc ) goto abort_due_to_error;
    ++  break;
    ++}
    ++
    ++/* Opcode: OpenDup P1 P2 * * *
    ++**
    ++** Open a new cursor P1 that points to the same ephemeral table as
    ++** cursor P2.  The P2 cursor must have been opened by a prior OP_OpenEphemeral
    ++** opcode.  Only ephemeral cursors may be duplicated.
    ++**
    ++** Duplicate ephemeral cursors are used for self-joins of materialized views.
    ++*/
    ++case OP_OpenDup: {
    ++  VdbeCursor *pOrig;    /* The original cursor to be duplicated */
    ++  VdbeCursor *pCx;      /* The new cursor */
    ++
    ++  pOrig = p->apCsr[pOp->p2];
    ++  assert( pOrig->pBtx!=0 );  /* Only ephemeral cursors can be duplicated */
    ++
    ++  pCx = allocateCursor(p, pOp->p1, pOrig->nField, -1, CURTYPE_BTREE);
    ++  if( pCx==0 ) goto no_mem;
    ++  pCx->nullRow = 1;
    ++  pCx->isEphemeral = 1;
    ++  pCx->pKeyInfo = pOrig->pKeyInfo;
    ++  pCx->isTable = pOrig->isTable;
    ++  rc = sqlite3BtreeCursor(pOrig->pBtx, MASTER_ROOT, BTREE_WRCSR,
    ++                          pCx->pKeyInfo, pCx->uc.pCursor);
    ++  /* The sqlite3BtreeCursor() routine can only fail for the first cursor
    ++  ** opened for a database.  Since there is already an open cursor when this
    ++  ** opcode is run, the sqlite3BtreeCursor() cannot fail */
    ++  assert( rc==SQLITE_OK );
    +   break;
    + }
    + 
    ++
    + /* Opcode: OpenEphemeral P1 P2 * P4 P5
    + ** Synopsis: nColumn=P2
    + **
    +@@ -76329,14 +83552,14 @@ case OP_OpenEphemeral: {
    +       SQLITE_OPEN_TRANSIENT_DB;
    +   assert( pOp->p1>=0 );
    +   assert( pOp->p2>=0 );
    +-  pCx = allocateCursor(p, pOp->p1, pOp->p2, -1, 1);
    ++  pCx = allocateCursor(p, pOp->p1, pOp->p2, -1, CURTYPE_BTREE);
    +   if( pCx==0 ) goto no_mem;
    +   pCx->nullRow = 1;
    +   pCx->isEphemeral = 1;
    +-  rc = sqlite3BtreeOpen(db->pVfs, 0, db, &pCx->pBt, 
    ++  rc = sqlite3BtreeOpen(db->pVfs, 0, db, &pCx->pBtx, 
    +                         BTREE_OMIT_JOURNAL | BTREE_SINGLE | pOp->p5, vfsFlags);
    +   if( rc==SQLITE_OK ){
    +-    rc = sqlite3BtreeBeginTrans(pCx->pBt, 1);
    ++    rc = sqlite3BtreeBeginTrans(pCx->pBtx, 1);
    +   }
    +   if( rc==SQLITE_OK ){
    +     /* If a transient index is required, create it by calling
    +@@ -76344,23 +83567,25 @@ case OP_OpenEphemeral: {
    +     ** opening it. If a transient table is required, just use the
    +     ** automatically created table with root-page 1 (an BLOB_INTKEY table).
    +     */
    +-    if( (pKeyInfo = pOp->p4.pKeyInfo)!=0 ){
    ++    if( (pCx->pKeyInfo = pKeyInfo = pOp->p4.pKeyInfo)!=0 ){
    +       int pgno;
    +       assert( pOp->p4type==P4_KEYINFO );
    +-      rc = sqlite3BtreeCreateTable(pCx->pBt, &pgno, BTREE_BLOBKEY | pOp->p5); 
    ++      rc = sqlite3BtreeCreateTable(pCx->pBtx, &pgno, BTREE_BLOBKEY | pOp->p5); 
    +       if( rc==SQLITE_OK ){
    +         assert( pgno==MASTER_ROOT+1 );
    +         assert( pKeyInfo->db==db );
    +         assert( pKeyInfo->enc==ENC(db) );
    +-        pCx->pKeyInfo = pKeyInfo;
    +-        rc = sqlite3BtreeCursor(pCx->pBt, pgno, 1, pKeyInfo, pCx->pCursor);
    ++        rc = sqlite3BtreeCursor(pCx->pBtx, pgno, BTREE_WRCSR,
    ++                                pKeyInfo, pCx->uc.pCursor);
    +       }
    +       pCx->isTable = 0;
    +     }else{
    +-      rc = sqlite3BtreeCursor(pCx->pBt, MASTER_ROOT, 1, 0, pCx->pCursor);
    ++      rc = sqlite3BtreeCursor(pCx->pBtx, MASTER_ROOT, BTREE_WRCSR,
    ++                              0, pCx->uc.pCursor);
    +       pCx->isTable = 1;
    +     }
    +   }
    ++  if( rc ) goto abort_due_to_error;
    +   pCx->isOrdered = (pOp->p5!=BTREE_UNORDERED);
    +   break;
    + }
    +@@ -76380,12 +83605,13 @@ case OP_SorterOpen: {
    + 
    +   assert( pOp->p1>=0 );
    +   assert( pOp->p2>=0 );
    +-  pCx = allocateCursor(p, pOp->p1, pOp->p2, -1, 1);
    ++  pCx = allocateCursor(p, pOp->p1, pOp->p2, -1, CURTYPE_SORTER);
    +   if( pCx==0 ) goto no_mem;
    +   pCx->pKeyInfo = pOp->p4.pKeyInfo;
    +   assert( pCx->pKeyInfo->db==db );
    +   assert( pCx->pKeyInfo->enc==ENC(db) );
    +   rc = sqlite3VdbeSorterInit(db, pOp->p3, pCx);
    ++  if( rc ) goto abort_due_to_error;
    +   break;
    + }
    + 
    +@@ -76400,7 +83626,7 @@ case OP_SequenceTest: {
    +   VdbeCursor *pC;
    +   assert( pOp->p1>=0 && pOp->p1<p->nCursor );
    +   pC = p->apCsr[pOp->p1];
    +-  assert( pC->pSorter );
    ++  assert( isSorter(pC) );
    +   if( (pC->seqCount++)==0 ){
    +     goto jump_to_p2;
    +   }
    +@@ -76428,11 +83654,16 @@ case OP_OpenPseudo: {
    + 
    +   assert( pOp->p1>=0 );
    +   assert( pOp->p3>=0 );
    +-  pCx = allocateCursor(p, pOp->p1, pOp->p3, -1, 0);
    ++  pCx = allocateCursor(p, pOp->p1, pOp->p3, -1, CURTYPE_PSEUDO);
    +   if( pCx==0 ) goto no_mem;
    +   pCx->nullRow = 1;
    +-  pCx->pseudoTableReg = pOp->p2;
    ++  pCx->seekResult = pOp->p2;
    +   pCx->isTable = 1;
    ++  /* Give this pseudo-cursor a fake BtCursor pointer so that pCx
    ++  ** can be safely passed to sqlite3VdbeCursorMoveto().  This avoids a test
    ++  ** for pCx->eCurType==CURTYPE_BTREE inside of sqlite3VdbeCursorMoveto()
    ++  ** which is a performance optimization */
    ++  pCx->uc.pCursor = sqlite3BtreeFakeValidCursor();
    +   assert( pOp->p5==0 );
    +   break;
    + }
    +@@ -76463,7 +83694,7 @@ case OP_Close: {
    + case OP_ColumnsUsed: {
    +   VdbeCursor *pC;
    +   pC = p->apCsr[pOp->p1];
    +-  assert( pC->pCursor );
    ++  assert( pC->eCurType==CURTYPE_BTREE );
    +   pC->maskUsed = *(u64*)pOp->p4.pI64;
    +   break;
    + }
    +@@ -76481,6 +83712,13 @@ case OP_ColumnsUsed: {
    + ** 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.
    + **
    ++** If the cursor P1 was opened using the OPFLAG_SEEKEQ flag, then this
    ++** opcode will always land on a record that equally equals the key, or
    ++** else jump immediately to P2.  When the cursor is OPFLAG_SEEKEQ, this
    ++** opcode must be followed by an IdxLE opcode with the same arguments.
    ++** The IdxLE opcode will be skipped if this opcode succeeds, but the
    ++** IdxLE opcode will be used on subsequent loop iterations.
    ++**
    + ** 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.
    +@@ -76539,51 +83777,49 @@ case OP_ColumnsUsed: {
    + ** from the end toward the beginning.  In other words, the cursor is
    + ** configured to use Prev, not Next.
    + **
    ++** If the cursor P1 was opened using the OPFLAG_SEEKEQ flag, then this
    ++** opcode will always land on a record that equally equals the key, or
    ++** else jump immediately to P2.  When the cursor is OPFLAG_SEEKEQ, this
    ++** opcode must be followed by an IdxGE opcode with the same arguments.
    ++** The IdxGE opcode will be skipped if this opcode succeeds, but the
    ++** IdxGE opcode will be used on subsequent loop iterations.
    ++**
    + ** See also: Found, NotFound, SeekGt, SeekGe, SeekLt
    + */
    + case OP_SeekLT:         /* jump, in3 */
    + case OP_SeekLE:         /* jump, in3 */
    + case OP_SeekGE:         /* jump, in3 */
    + case OP_SeekGT: {       /* jump, in3 */
    +-  int res;
    +-  int oc;
    +-  VdbeCursor *pC;
    +-  UnpackedRecord r;
    +-  int nField;
    +-  i64 iKey;      /* The rowid we are to seek to */
    ++  int res;           /* Comparison result */
    ++  int oc;            /* Opcode */
    ++  VdbeCursor *pC;    /* The cursor to seek */
    ++  UnpackedRecord r;  /* The key to seek for */
    ++  int nField;        /* Number of columns or fields in the key */
    ++  i64 iKey;          /* The rowid we are to seek to */
    ++  int eqOnly;        /* Only interested in == results */
    + 
    +   assert( pOp->p1>=0 && pOp->p1<p->nCursor );
    +   assert( pOp->p2!=0 );
    +   pC = p->apCsr[pOp->p1];
    +   assert( pC!=0 );
    +-  assert( pC->pseudoTableReg==0 );
    ++  assert( pC->eCurType==CURTYPE_BTREE );
    +   assert( OP_SeekLE == OP_SeekLT+1 );
    +   assert( OP_SeekGE == OP_SeekLT+2 );
    +   assert( OP_SeekGT == OP_SeekLT+3 );
    +   assert( pC->isOrdered );
    +-  assert( pC->pCursor!=0 );
    ++  assert( pC->uc.pCursor!=0 );
    +   oc = pOp->opcode;
    ++  eqOnly = 0;
    +   pC->nullRow = 0;
    + #ifdef SQLITE_DEBUG
    +   pC->seekOp = pOp->opcode;
    + #endif
    + 
    +-  /* For a cursor with the BTREE_SEEK_EQ hint, only the OP_SeekGE and
    +-  ** OP_SeekLE opcodes are allowed, and these must be immediately followed
    +-  ** by an OP_IdxGT or OP_IdxLT opcode, respectively, with the same key.
    +-  */
    +-#ifdef SQLITE_DEBUG
    +-  if( sqlite3BtreeCursorHasHint(pC->pCursor, BTREE_SEEK_EQ) ){
    +-    assert( pOp->opcode==OP_SeekGE || pOp->opcode==OP_SeekLE );
    +-    assert( pOp[1].opcode==OP_IdxLT || pOp[1].opcode==OP_IdxGT );
    +-    assert( pOp[1].p1==pOp[0].p1 );
    +-    assert( pOp[1].p2==pOp[0].p2 );
    +-    assert( pOp[1].p3==pOp[0].p3 );
    +-    assert( pOp[1].p4.i==pOp[0].p4.i );
    +-  }
    +-#endif
    +- 
    +   if( pC->isTable ){
    ++    /* The BTREE_SEEK_EQ flag is only set on index cursors */
    ++    assert( sqlite3BtreeCursorHasHint(pC->uc.pCursor, BTREE_SEEK_EQ)==0
    ++              || CORRUPT_DB );
    ++
    +     /* 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 convert it. */
    +@@ -76626,12 +83862,26 @@ case OP_SeekGT: {       /* jump, in3 */
    +         if( (oc & 0x0001)==(OP_SeekLT & 0x0001) ) oc++;
    +       }
    +     } 
    +-    rc = sqlite3BtreeMovetoUnpacked(pC->pCursor, 0, (u64)iKey, 0, &res);
    ++    rc = sqlite3BtreeMovetoUnpacked(pC->uc.pCursor, 0, (u64)iKey, 0, &res);
    +     pC->movetoTarget = iKey;  /* Used by OP_Delete */
    +     if( rc!=SQLITE_OK ){
    +       goto abort_due_to_error;
    +     }
    +   }else{
    ++    /* For a cursor with the BTREE_SEEK_EQ hint, only the OP_SeekGE and
    ++    ** OP_SeekLE opcodes are allowed, and these must be immediately followed
    ++    ** by an OP_IdxGT or OP_IdxLT opcode, respectively, with the same key.
    ++    */
    ++    if( sqlite3BtreeCursorHasHint(pC->uc.pCursor, BTREE_SEEK_EQ) ){
    ++      eqOnly = 1;
    ++      assert( pOp->opcode==OP_SeekGE || pOp->opcode==OP_SeekLE );
    ++      assert( pOp[1].opcode==OP_IdxLT || pOp[1].opcode==OP_IdxGT );
    ++      assert( pOp[1].p1==pOp[0].p1 );
    ++      assert( pOp[1].p2==pOp[0].p2 );
    ++      assert( pOp[1].p3==pOp[0].p3 );
    ++      assert( pOp[1].p4.i==pOp[0].p4.i );
    ++    }
    ++
    +     nField = pOp->p4.i;
    +     assert( pOp->p4type==P4_INT32 );
    +     assert( nField>0 );
    +@@ -76655,11 +83905,15 @@ case OP_SeekGT: {       /* jump, in3 */
    + #ifdef SQLITE_DEBUG
    +     { int i; for(i=0; i<r.nField; i++) assert( memIsValid(&r.aMem[i]) ); }
    + #endif
    +-    ExpandBlob(r.aMem);
    +-    rc = sqlite3BtreeMovetoUnpacked(pC->pCursor, &r, 0, 0, &res);
    ++    r.eqSeen = 0;
    ++    rc = sqlite3BtreeMovetoUnpacked(pC->uc.pCursor, &r, 0, 0, &res);
    +     if( rc!=SQLITE_OK ){
    +       goto abort_due_to_error;
    +     }
    ++    if( eqOnly && r.eqSeen==0 ){
    ++      assert( res!=0 );
    ++      goto seek_not_found;
    ++    }
    +   }
    +   pC->deferredMoveto = 0;
    +   pC->cacheStatus = CACHE_STALE;
    +@@ -76669,8 +83923,15 @@ case OP_SeekGT: {       /* jump, in3 */
    +   if( oc>=OP_SeekGE ){  assert( oc==OP_SeekGE || oc==OP_SeekGT );
    +     if( res<0 || (res==0 && oc==OP_SeekGT) ){
    +       res = 0;
    +-      rc = sqlite3BtreeNext(pC->pCursor, &res);
    +-      if( rc!=SQLITE_OK ) goto abort_due_to_error;
    ++      rc = sqlite3BtreeNext(pC->uc.pCursor, 0);
    ++      if( rc!=SQLITE_OK ){
    ++        if( rc==SQLITE_DONE ){
    ++          rc = SQLITE_OK;
    ++          res = 1;
    ++        }else{
    ++          goto abort_due_to_error;
    ++        }
    ++      }
    +     }else{
    +       res = 0;
    +     }
    +@@ -76678,49 +83939,34 @@ case OP_SeekGT: {       /* jump, in3 */
    +     assert( oc==OP_SeekLT || oc==OP_SeekLE );
    +     if( res>0 || (res==0 && oc==OP_SeekLT) ){
    +       res = 0;
    +-      rc = sqlite3BtreePrevious(pC->pCursor, &res);
    +-      if( rc!=SQLITE_OK ) goto abort_due_to_error;
    ++      rc = sqlite3BtreePrevious(pC->uc.pCursor, 0);
    ++      if( rc!=SQLITE_OK ){
    ++        if( rc==SQLITE_DONE ){
    ++          rc = SQLITE_OK;
    ++          res = 1;
    ++        }else{
    ++          goto abort_due_to_error;
    ++        }
    ++      }
    +     }else{
    +       /* res might be negative because the table is empty.  Check to
    +       ** see if this is the case.
    +       */
    +-      res = sqlite3BtreeEof(pC->pCursor);
    ++      res = sqlite3BtreeEof(pC->uc.pCursor);
    +     }
    +   }
    ++seek_not_found:
    +   assert( pOp->p2>0 );
    +   VdbeBranchTaken(res!=0,2);
    +   if( res ){
    +     goto jump_to_p2;
    ++  }else if( eqOnly ){
    ++    assert( pOp[1].opcode==OP_IdxLT || pOp[1].opcode==OP_IdxGT );
    ++    pOp++; /* Skip the OP_IdxLt or OP_IdxGT that follows */
    +   }
    +   break;
    + }
    + 
    +-/* Opcode: Seek P1 P2 * * *
    +-** Synopsis:  intkey=r[P2]
    +-**
    +-** P1 is an open table cursor and P2 is a rowid integer.  Arrange
    +-** for P1 to move so that it points to the rowid given by P2.
    +-**
    +-** This is actually a deferred seek.  Nothing actually happens until
    +-** the cursor is used to read a record.  That way, if no reads
    +-** occur, no unnecessary I/O happens.
    +-*/
    +-case OP_Seek: {    /* in2 */
    +-  VdbeCursor *pC;
    +-
    +-  assert( pOp->p1>=0 && pOp->p1<p->nCursor );
    +-  pC = p->apCsr[pOp->p1];
    +-  assert( pC!=0 );
    +-  assert( pC->pCursor!=0 );
    +-  assert( pC->isTable );
    +-  pC->nullRow = 0;
    +-  pIn2 = &aMem[pOp->p2];
    +-  pC->movetoTarget = sqlite3VdbeIntValue(pIn2);
    +-  pC->deferredMoveto = 1;
    +-  break;
    +-}
    +-  
    +-
    + /* Opcode: Found P1 P2 P3 P4 *
    + ** Synopsis: key=r[P3@P4]
    + **
    +@@ -76788,10 +84034,9 @@ case OP_Found: {        /* jump, in3 */
    +   int ii;
    +   VdbeCursor *pC;
    +   int res;
    +-  char *pFree;
    ++  UnpackedRecord *pFree;
    +   UnpackedRecord *pIdxKey;
    +   UnpackedRecord r;
    +-  char aTempRec[ROUND8(sizeof(UnpackedRecord)) + sizeof(Mem)*4 + 7];
    + 
    + #ifdef SQLITE_TEST
    +   if( pOp->opcode!=OP_NoConflict ) sqlite3_found_count++;
    +@@ -76805,28 +84050,29 @@ case OP_Found: {        /* jump, in3 */
    +   pC->seekOp = pOp->opcode;
    + #endif
    +   pIn3 = &aMem[pOp->p3];
    +-  assert( pC->pCursor!=0 );
    ++  assert( pC->eCurType==CURTYPE_BTREE );
    ++  assert( pC->uc.pCursor!=0 );
    +   assert( pC->isTable==0 );
    +-  pFree = 0;
    +   if( pOp->p4.i>0 ){
    +     r.pKeyInfo = pC->pKeyInfo;
    +     r.nField = (u16)pOp->p4.i;
    +     r.aMem = pIn3;
    ++#ifdef SQLITE_DEBUG
    +     for(ii=0; ii<r.nField; ii++){
    +       assert( memIsValid(&r.aMem[ii]) );
    +-      ExpandBlob(&r.aMem[ii]);
    +-#ifdef SQLITE_DEBUG
    ++      assert( (r.aMem[ii].flags & MEM_Zero)==0 || r.aMem[ii].n==0 );
    +       if( ii ) REGISTER_TRACE(pOp->p3+ii, &r.aMem[ii]);
    +-#endif
    +     }
    ++#endif
    +     pIdxKey = &r;
    ++    pFree = 0;
    +   }else{
    +-    pIdxKey = sqlite3VdbeAllocUnpackedRecord(
    +-        pC->pKeyInfo, aTempRec, sizeof(aTempRec), &pFree
    +-    );
    +-    if( pIdxKey==0 ) goto no_mem;
    +     assert( pIn3->flags & MEM_Blob );
    +-    ExpandBlob(pIn3);
    ++    rc = ExpandBlob(pIn3);
    ++    assert( rc==SQLITE_OK || rc==SQLITE_NOMEM );
    ++    if( rc ) goto no_mem;
    ++    pFree = pIdxKey = sqlite3VdbeAllocUnpackedRecord(pC->pKeyInfo);
    ++    if( pIdxKey==0 ) goto no_mem;
    +     sqlite3VdbeRecordUnpack(pC->pKeyInfo, pIn3->n, pIn3->z, pIdxKey);
    +   }
    +   pIdxKey->default_rc = 0;
    +@@ -76842,10 +84088,10 @@ case OP_Found: {        /* jump, in3 */
    +       }
    +     }
    +   }
    +-  rc = sqlite3BtreeMovetoUnpacked(pC->pCursor, pIdxKey, 0, 0, &res);
    +-  sqlite3DbFree(db, pFree);
    ++  rc = sqlite3BtreeMovetoUnpacked(pC->uc.pCursor, pIdxKey, 0, 0, &res);
    ++  if( pFree ) sqlite3DbFreeNN(db, pFree);
    +   if( rc!=SQLITE_OK ){
    +-    break;
    ++    goto abort_due_to_error;
    +   }
    +   pC->seekResult = res;
    +   alreadyExists = (res==0);
    +@@ -76862,6 +84108,30 @@ case OP_Found: {        /* jump, in3 */
    +   break;
    + }
    + 
    ++/* Opcode: SeekRowid P1 P2 P3 * *
    ++** Synopsis: intkey=r[P3]
    ++**
    ++** P1 is the index of a cursor open on an SQL table btree (with integer
    ++** keys).  If register P3 does not contain an integer or if P1 does not
    ++** contain a record with rowid P3 then jump immediately to P2.  
    ++** Or, if P2 is 0, raise an SQLITE_CORRUPT error. If P1 does contain
    ++** a record with rowid P3 then 
    ++** leave the cursor pointing at that record and fall through to the next
    ++** instruction.
    ++**
    ++** The OP_NotExists opcode performs the same operation, but with OP_NotExists
    ++** the P3 register must be guaranteed to contain an integer value.  With this
    ++** opcode, register P3 might not contain an integer.
    ++**
    ++** 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, SeekRowid
    ++*/
    + /* Opcode: NotExists P1 P2 P3 * *
    + ** Synopsis: intkey=r[P3]
    + **
    +@@ -76872,6 +84142,10 @@ case OP_Found: {        /* jump, in3 */
    + ** leave the cursor pointing at that record and fall through to the next
    + ** instruction.
    + **
    ++** The OP_SeekRowid opcode performs the same operation but also allows the
    ++** P3 register to contain a non-integer value, in which case the jump is
    ++** always taken.  This opcode requires that P3 always contain an integer.
    ++**
    + ** The OP_NotFound opcode performs the same operation on index btrees
    + ** (with arbitrary multi-value keys).
    + **
    +@@ -76879,14 +84153,21 @@ case OP_Found: {        /* jump, in3 */
    + ** in either direction.  In other words, the Next and Prev opcodes will
    + ** not work following this opcode.
    + **
    +-** See also: Found, NotFound, NoConflict
    ++** See also: Found, NotFound, NoConflict, SeekRowid
    + */
    +-case OP_NotExists: {        /* jump, in3 */
    ++case OP_SeekRowid: {        /* jump, in3 */
    +   VdbeCursor *pC;
    +   BtCursor *pCrsr;
    +   int res;
    +   u64 iKey;
    + 
    ++  pIn3 = &aMem[pOp->p3];
    ++  if( (pIn3->flags & MEM_Int)==0 ){
    ++    applyAffinity(pIn3, SQLITE_AFF_NUMERIC, encoding);
    ++    if( (pIn3->flags & MEM_Int)==0 ) goto jump_to_p2;
    ++  }
    ++  /* Fall through into OP_NotExists */
    ++case OP_NotExists:          /* jump, in3 */
    +   pIn3 = &aMem[pOp->p3];
    +   assert( pIn3->flags & MEM_Int );
    +   assert( pOp->p1>=0 && pOp->p1<p->nCursor );
    +@@ -76896,8 +84177,8 @@ case OP_NotExists: {        /* jump, in3 */
    +   pC->seekOp = 0;
    + #endif
    +   assert( pC->isTable );
    +-  assert( pC->pseudoTableReg==0 );
    +-  pCrsr = pC->pCursor;
    ++  assert( pC->eCurType==CURTYPE_BTREE );
    ++  pCrsr = pC->uc.pCursor;
    +   assert( pCrsr!=0 );
    +   res = 0;
    +   iKey = pIn3->u.i;
    +@@ -76917,6 +84198,7 @@ case OP_NotExists: {        /* jump, in3 */
    +       goto jump_to_p2;
    +     }
    +   }
    ++  if( rc ) goto abort_due_to_error;
    +   break;
    + }
    + 
    +@@ -76931,6 +84213,7 @@ case OP_NotExists: {        /* jump, in3 */
    + case OP_Sequence: {           /* out2 */
    +   assert( pOp->p1>=0 && pOp->p1<p->nCursor );
    +   assert( p->apCsr[pOp->p1]!=0 );
    ++  assert( p->apCsr[pOp->p1]->eCurType!=CURTYPE_VTAB );
    +   pOut = out2Prerelease(p, pOp);
    +   pOut->u.i = p->apCsr[pOp->p1]->seqCount++;
    +   break;
    +@@ -76966,7 +84249,8 @@ case OP_NewRowid: {           /* out2 */
    +   assert( pOp->p1>=0 && pOp->p1<p->nCursor );
    +   pC = p->apCsr[pOp->p1];
    +   assert( pC!=0 );
    +-  assert( pC->pCursor!=0 );
    ++  assert( pC->eCurType==CURTYPE_BTREE );
    ++  assert( pC->uc.pCursor!=0 );
    +   {
    +     /* The next rowid or record number (different terms for the same
    +     ** thing) is obtained in a two-step algorithm.
    +@@ -76994,16 +84278,15 @@ case OP_NewRowid: {           /* out2 */
    + #endif
    + 
    +     if( !pC->useRandomRowid ){
    +-      rc = sqlite3BtreeLast(pC->pCursor, &res);
    ++      rc = sqlite3BtreeLast(pC->uc.pCursor, &res);
    +       if( rc!=SQLITE_OK ){
    +         goto abort_due_to_error;
    +       }
    +       if( res ){
    +         v = 1;   /* IMP: R-61914-48074 */
    +       }else{
    +-        assert( sqlite3BtreeCursorIsValid(pC->pCursor) );
    +-        rc = sqlite3BtreeKeySize(pC->pCursor, &v);
    +-        assert( rc==SQLITE_OK );   /* Cannot fail following BtreeLast() */
    ++        assert( sqlite3BtreeCursorIsValid(pC->uc.pCursor) );
    ++        v = sqlite3BtreeIntegerKey(pC->uc.pCursor);
    +         if( v>=MAX_ROWID ){
    +           pC->useRandomRowid = 1;
    +         }else{
    +@@ -77023,7 +84306,7 @@ case OP_NewRowid: {           /* out2 */
    +         pMem = &pFrame->aMem[pOp->p3];
    +       }else{
    +         /* Assert that P3 is a valid memory cell. */
    +-        assert( pOp->p3<=(p->nMem-p->nCursor) );
    ++        assert( pOp->p3<=(p->nMem+1 - p->nCursor) );
    +         pMem = &aMem[pOp->p3];
    +         memAboutToChange(p, pMem);
    +       }
    +@@ -77033,7 +84316,7 @@ case OP_NewRowid: {           /* out2 */
    +       sqlite3VdbeMemIntegerify(pMem);
    +       assert( (pMem->flags & MEM_Int)!=0 );  /* mem(P3) holds an integer */
    +       if( pMem->u.i==MAX_ROWID || pC->useRandomRowid ){
    +-        rc = SQLITE_FULL;   /* IMP: R-12275-61338 */
    ++        rc = SQLITE_FULL;   /* IMP: R-17817-00630 */
    +         goto abort_due_to_error;
    +       }
    +       if( v<pMem->u.i+1 ){
    +@@ -77053,11 +84336,12 @@ case OP_NewRowid: {           /* out2 */
    +       do{
    +         sqlite3_randomness(sizeof(v), &v);
    +         v &= (MAX_ROWID>>1); v++;  /* Ensure that v is greater than zero */
    +-      }while(  ((rc = sqlite3BtreeMovetoUnpacked(pC->pCursor, 0, (u64)v,
    ++      }while(  ((rc = sqlite3BtreeMovetoUnpacked(pC->uc.pCursor, 0, (u64)v,
    +                                                  0, &res))==SQLITE_OK)
    +             && (res==0)
    +             && (++cnt<100));
    +-      if( rc==SQLITE_OK && res==0 ){
    ++      if( rc ) goto abort_due_to_error;
    ++      if( res==0 ){
    +         rc = SQLITE_FULL;   /* IMP: R-38219-53002 */
    +         goto abort_due_to_error;
    +       }
    +@@ -77084,22 +84368,19 @@ case OP_NewRowid: {           /* out2 */
    + ** then rowid is stored for subsequent return by the
    + ** sqlite3_last_insert_rowid() function (otherwise it is unmodified).
    + **
    +-** If the OPFLAG_USESEEKRESULT flag of P5 is set and if the result of
    +-** the last seek operation (OP_NotExists) was a success, then this
    +-** operation will not attempt to find the appropriate row before doing
    +-** the insert but will instead overwrite the row that the cursor is
    +-** currently pointing to.  Presumably, the prior OP_NotExists opcode
    +-** has already positioned the cursor correctly.  This is an optimization
    +-** that boosts performance by avoiding redundant seeks.
    ++** If the OPFLAG_USESEEKRESULT flag of P5 is set, the implementation might
    ++** run faster by avoiding an unnecessary seek on cursor P1.  However,
    ++** the OPFLAG_USESEEKRESULT flag must only be set if there have been no prior
    ++** seeks on the cursor or if the most recent seek used a key equal to P3.
    + **
    + ** If the OPFLAG_ISUPDATE flag is set, then this opcode is part of an
    + ** UPDATE operation.  Otherwise (if the flag is clear) then this opcode
    + ** is part of an INSERT operation.  The difference is only important to
    + ** the update hook.
    + **
    +-** Parameter P4 may point to a string containing the table-name, or
    +-** may be NULL. If it is not NULL, then the update-hook 
    +-** (sqlite3.xUpdateCallback) is invoked following a successful insert.
    ++** Parameter P4 may point to a Table structure, or may be NULL. If it is 
    ++** not NULL, then the update-hook (sqlite3.xUpdateCallback) is invoked 
    ++** following a successful insert.
    + **
    + ** (WARNING/TODO: If P1 is a pseudo-cursor and P2 is dynamically
    + ** allocated, then ownership of P2 is transferred to the pseudo-cursor
    +@@ -77111,7 +84392,7 @@ case OP_NewRowid: {           /* out2 */
    + ** for indices is OP_IdxInsert.
    + */
    + /* Opcode: InsertInt P1 P2 P3 P4 P5
    +-** Synopsis:  intkey=P3 data=r[P2]
    ++** Synopsis: intkey=P3 data=r[P2]
    + **
    + ** This works exactly like OP_Insert except that the key is the
    + ** integer value P3, not the value of the integer stored in register P3.
    +@@ -77120,22 +84401,21 @@ case OP_Insert:
    + case OP_InsertInt: {
    +   Mem *pData;       /* MEM cell holding data for the record to be inserted */
    +   Mem *pKey;        /* MEM cell holding key  for the record */
    +-  i64 iKey;         /* The integer ROWID or key for the record to be inserted */
    +   VdbeCursor *pC;   /* Cursor to table into which insert is written */
    +-  int nZero;        /* Number of zero-bytes to append */
    +   int seekResult;   /* Result of prior seek or 0 if no USESEEKRESULT flag */
    +   const char *zDb;  /* database name - used by the update hook */
    +-  const char *zTbl; /* Table name - used by the opdate hook */
    +-  int op;           /* Opcode for update hook: SQLITE_UPDATE or SQLITE_INSERT */
    ++  Table *pTab;      /* Table structure - used by update and pre-update hooks */
    ++  BtreePayload x;   /* Payload to be inserted */
    + 
    +   pData = &aMem[pOp->p2];
    +   assert( pOp->p1>=0 && pOp->p1<p->nCursor );
    +   assert( memIsValid(pData) );
    +   pC = p->apCsr[pOp->p1];
    +   assert( pC!=0 );
    +-  assert( pC->pCursor!=0 );
    +-  assert( pC->pseudoTableReg==0 );
    +-  assert( pC->isTable );
    ++  assert( pC->eCurType==CURTYPE_BTREE );
    ++  assert( pC->uc.pCursor!=0 );
    ++  assert( (pOp->p5 & OPFLAG_ISNOOP) || pC->isTable );
    ++  assert( pOp->p4type==P4_TABLE || pOp->p4type>=P4_STATIC );
    +   REGISTER_TRACE(pOp->p2, pData);
    + 
    +   if( pOp->opcode==OP_Insert ){
    +@@ -77143,102 +84423,193 @@ case OP_InsertInt: {
    +     assert( pKey->flags & MEM_Int );
    +     assert( memIsValid(pKey) );
    +     REGISTER_TRACE(pOp->p3, pKey);
    +-    iKey = pKey->u.i;
    ++    x.nKey = pKey->u.i;
    +   }else{
    +     assert( pOp->opcode==OP_InsertInt );
    +-    iKey = pOp->p3;
    ++    x.nKey = pOp->p3;
    +   }
    + 
    +-  if( pOp->p5 & OPFLAG_NCHANGE ) p->nChange++;
    +-  if( pOp->p5 & OPFLAG_LASTROWID ) db->lastRowid = lastRowid = iKey;
    +-  if( pData->flags & MEM_Null ){
    +-    pData->z = 0;
    +-    pData->n = 0;
    ++  if( pOp->p4type==P4_TABLE && HAS_UPDATE_HOOK(db) ){
    ++    assert( pC->iDb>=0 );
    ++    zDb = db->aDb[pC->iDb].zDbSName;
    ++    pTab = pOp->p4.pTab;
    ++    assert( (pOp->p5 & OPFLAG_ISNOOP) || HasRowid(pTab) );
    +   }else{
    +-    assert( pData->flags & (MEM_Blob|MEM_Str) );
    ++    pTab = 0;
    ++    zDb = 0;  /* Not needed.  Silence a compiler warning. */
    ++  }
    ++
    ++#ifdef SQLITE_ENABLE_PREUPDATE_HOOK
    ++  /* Invoke the pre-update hook, if any */
    ++  if( pTab ){
    ++    if( db->xPreUpdateCallback && !(pOp->p5 & OPFLAG_ISUPDATE) ){
    ++      sqlite3VdbePreUpdateHook(p, pC, SQLITE_INSERT, zDb, pTab, x.nKey,pOp->p2);
    ++    }
    ++    if( db->xUpdateCallback==0 || pTab->aCol==0 ){
    ++      /* Prevent post-update hook from running in cases when it should not */
    ++      pTab = 0;
    ++    }
    +   }
    ++  if( pOp->p5 & OPFLAG_ISNOOP ) break;
    ++#endif
    ++
    ++  if( pOp->p5 & OPFLAG_NCHANGE ) p->nChange++;
    ++  if( pOp->p5 & OPFLAG_LASTROWID ) db->lastRowid = x.nKey;
    ++  assert( pData->flags & (MEM_Blob|MEM_Str) );
    ++  x.pData = pData->z;
    ++  x.nData = pData->n;
    +   seekResult = ((pOp->p5 & OPFLAG_USESEEKRESULT) ? pC->seekResult : 0);
    +   if( pData->flags & MEM_Zero ){
    +-    nZero = pData->u.nZero;
    ++    x.nZero = pData->u.nZero;
    +   }else{
    +-    nZero = 0;
    ++    x.nZero = 0;
    +   }
    +-  rc = sqlite3BtreeInsert(pC->pCursor, 0, iKey,
    +-                          pData->z, pData->n, nZero,
    +-                          (pOp->p5 & OPFLAG_APPEND)!=0, seekResult
    ++  x.pKey = 0;
    ++  rc = sqlite3BtreeInsert(pC->uc.pCursor, &x,
    ++      (pOp->p5 & (OPFLAG_APPEND|OPFLAG_SAVEPOSITION)), seekResult
    +   );
    +   pC->deferredMoveto = 0;
    +   pC->cacheStatus = CACHE_STALE;
    + 
    +   /* Invoke the update-hook if required. */
    +-  if( rc==SQLITE_OK && db->xUpdateCallback && pOp->p4.z ){
    +-    zDb = db->aDb[pC->iDb].zName;
    +-    zTbl = pOp->p4.z;
    +-    op = ((pOp->p5 & OPFLAG_ISUPDATE) ? SQLITE_UPDATE : SQLITE_INSERT);
    +-    assert( pC->isTable );
    +-    db->xUpdateCallback(db->pUpdateArg, op, zDb, zTbl, iKey);
    +-    assert( pC->iDb>=0 );
    ++  if( rc ) goto abort_due_to_error;
    ++  if( pTab ){
    ++    assert( db->xUpdateCallback!=0 );
    ++    assert( pTab->aCol!=0 );
    ++    db->xUpdateCallback(db->pUpdateArg,
    ++           (pOp->p5 & OPFLAG_ISUPDATE) ? SQLITE_UPDATE : SQLITE_INSERT,
    ++           zDb, pTab->zName, x.nKey);
    +   }
    +   break;
    + }
    + 
    +-/* Opcode: Delete P1 P2 * P4 P5
    ++/* Opcode: Delete P1 P2 P3 P4 P5
    + **
    + ** Delete the record at which the P1 cursor is currently pointing.
    + **
    +-** If the P5 parameter is non-zero, 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. As a result, in this case it is OK to delete a record from within a
    +-** Next loop. If P5 is zero, then the cursor is left in an undefined state.
    ++** If the OPFLAG_SAVEPOSITION bit of the P5 parameter is set, then
    ++** 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. As a result, in this case
    ++** it is ok to delete a record from within a Next loop. If 
    ++** OPFLAG_SAVEPOSITION bit of P5 is clear, then the cursor will be
    ++** left in an undefined state.
    ++**
    ++** If the OPFLAG_AUXDELETE bit is set on P5, that indicates that this
    ++** delete one of several associated with deleting a table row and all its
    ++** associated index entries.  Exactly one of those deletes is the "primary"
    ++** delete.  The others are all on OPFLAG_FORDELETE cursors or else are
    ++** marked with the AUXDELETE flag.
    + **
    +-** If the OPFLAG_NCHANGE flag of P2 is set, then the row change count is
    +-** incremented (otherwise not).
    ++** If the OPFLAG_NCHANGE flag of P2 (NB: P2 not P5) is set, then the row
    ++** change count is incremented (otherwise not).
    + **
    + ** P1 must not be pseudo-table.  It has to be a real table with
    + ** multiple rows.
    + **
    +-** If P4 is not NULL, then it is the name of the table that P1 is
    +-** pointing to.  The update hook will be invoked, if it exists.
    +-** If P4 is not NULL then the P1 cursor must have been positioned
    +-** using OP_NotFound prior to invoking this opcode.
    ++** If P4 is not NULL then it points to a Table object. In this case either 
    ++** the update or pre-update hook, or both, may be invoked. The P1 cursor must
    ++** have been positioned using OP_NotFound prior to invoking this opcode in 
    ++** this case. Specifically, if one is configured, the pre-update hook is 
    ++** invoked if P4 is not NULL. The update-hook is invoked if one is configured, 
    ++** P4 is not NULL, and the OPFLAG_NCHANGE flag is set in P2.
    ++**
    ++** If the OPFLAG_ISUPDATE flag is set in P2, then P3 contains the address
    ++** of the memory cell that contains the value that the rowid of the row will
    ++** be set to by the update.
    + */
    + case OP_Delete: {
    +   VdbeCursor *pC;
    +-  u8 hasUpdateCallback;
    ++  const char *zDb;
    ++  Table *pTab;
    ++  int opflags;
    + 
    ++  opflags = pOp->p2;
    +   assert( pOp->p1>=0 && pOp->p1<p->nCursor );
    +   pC = p->apCsr[pOp->p1];
    +   assert( pC!=0 );
    +-  assert( pC->pCursor!=0 );  /* Only valid for real tables, no pseudotables */
    ++  assert( pC->eCurType==CURTYPE_BTREE );
    ++  assert( pC->uc.pCursor!=0 );
    +   assert( pC->deferredMoveto==0 );
    + 
    +-  hasUpdateCallback = db->xUpdateCallback && pOp->p4.z && pC->isTable;
    +-  if( pOp->p5 && hasUpdateCallback ){
    +-    sqlite3BtreeKeySize(pC->pCursor, &pC->movetoTarget);
    ++#ifdef SQLITE_DEBUG
    ++  if( pOp->p4type==P4_TABLE && HasRowid(pOp->p4.pTab) && pOp->p5==0 ){
    ++    /* If p5 is zero, the seek operation that positioned the cursor prior to
    ++    ** OP_Delete will have also set the pC->movetoTarget field to the rowid of
    ++    ** the row that is being deleted */
    ++    i64 iKey = sqlite3BtreeIntegerKey(pC->uc.pCursor);
    ++    assert( pC->movetoTarget==iKey );
    ++  }
    ++#endif
    ++
    ++  /* If the update-hook or pre-update-hook will be invoked, set zDb to
    ++  ** the name of the db to pass as to it. Also set local pTab to a copy
    ++  ** of p4.pTab. Finally, if p5 is true, indicating that this cursor was
    ++  ** last moved with OP_Next or OP_Prev, not Seek or NotFound, set 
    ++  ** VdbeCursor.movetoTarget to the current rowid.  */
    ++  if( pOp->p4type==P4_TABLE && HAS_UPDATE_HOOK(db) ){
    ++    assert( pC->iDb>=0 );
    ++    assert( pOp->p4.pTab!=0 );
    ++    zDb = db->aDb[pC->iDb].zDbSName;
    ++    pTab = pOp->p4.pTab;
    ++    if( (pOp->p5 & OPFLAG_SAVEPOSITION)!=0 && pC->isTable ){
    ++      pC->movetoTarget = sqlite3BtreeIntegerKey(pC->uc.pCursor);
    ++    }
    ++  }else{
    ++    zDb = 0;   /* Not needed.  Silence a compiler warning. */
    ++    pTab = 0;  /* Not needed.  Silence a compiler warning. */
    +   }
    + 
    +-#ifdef SQLITE_DEBUG
    +-  /* The seek operation that positioned the cursor prior to OP_Delete will
    +-  ** have also set the pC->movetoTarget field to the rowid of the row that
    +-  ** is being deleted */
    +-  if( pOp->p4.z && pC->isTable && pOp->p5==0 ){
    +-    i64 iKey = 0;
    +-    sqlite3BtreeKeySize(pC->pCursor, &iKey);
    +-    assert( pC->movetoTarget==iKey ); 
    ++#ifdef SQLITE_ENABLE_PREUPDATE_HOOK
    ++  /* Invoke the pre-update-hook if required. */
    ++  if( db->xPreUpdateCallback && pOp->p4.pTab ){
    ++    assert( !(opflags & OPFLAG_ISUPDATE) 
    ++         || HasRowid(pTab)==0 
    ++         || (aMem[pOp->p3].flags & MEM_Int) 
    ++    );
    ++    sqlite3VdbePreUpdateHook(p, pC,
    ++        (opflags & OPFLAG_ISUPDATE) ? SQLITE_UPDATE : SQLITE_DELETE, 
    ++        zDb, pTab, pC->movetoTarget,
    ++        pOp->p3
    ++    );
    +   }
    ++  if( opflags & OPFLAG_ISNOOP ) break;
    + #endif
    +  
    +-  rc = sqlite3BtreeDelete(pC->pCursor, pOp->p5);
    ++  /* Only flags that can be set are SAVEPOISTION and AUXDELETE */ 
    ++  assert( (pOp->p5 & ~(OPFLAG_SAVEPOSITION|OPFLAG_AUXDELETE))==0 );
    ++  assert( OPFLAG_SAVEPOSITION==BTREE_SAVEPOSITION );
    ++  assert( OPFLAG_AUXDELETE==BTREE_AUXDELETE );
    ++
    ++#ifdef SQLITE_DEBUG
    ++  if( p->pFrame==0 ){
    ++    if( pC->isEphemeral==0
    ++        && (pOp->p5 & OPFLAG_AUXDELETE)==0
    ++        && (pC->wrFlag & OPFLAG_FORDELETE)==0
    ++      ){
    ++      nExtraDelete++;
    ++    }
    ++    if( pOp->p2 & OPFLAG_NCHANGE ){
    ++      nExtraDelete--;
    ++    }
    ++  }
    ++#endif
    ++
    ++  rc = sqlite3BtreeDelete(pC->uc.pCursor, pOp->p5);
    +   pC->cacheStatus = CACHE_STALE;
    ++  pC->seekResult = 0;
    ++  if( rc ) goto abort_due_to_error;
    + 
    +   /* Invoke the update-hook if required. */
    +-  if( rc==SQLITE_OK && hasUpdateCallback ){
    +-    db->xUpdateCallback(db->pUpdateArg, SQLITE_DELETE,
    +-                        db->aDb[pC->iDb].zName, pOp->p4.z, pC->movetoTarget);
    +-    assert( pC->iDb>=0 );
    ++  if( opflags & OPFLAG_NCHANGE ){
    ++    p->nChange++;
    ++    if( db->xUpdateCallback && HasRowid(pTab) ){
    ++      db->xUpdateCallback(db->pUpdateArg, SQLITE_DELETE, zDb, pTab->zName,
    ++          pC->movetoTarget);
    ++      assert( pC->iDb>=0 );
    ++    }
    +   }
    +-  if( pOp->p2 & OPFLAG_NCHANGE ) p->nChange++;
    ++
    +   break;
    + }
    + /* Opcode: ResetCount * * * * *
    +@@ -77255,7 +84626,7 @@ case OP_ResetCount: {
    + }
    + 
    + /* Opcode: SorterCompare P1 P2 P3 P4
    +-** Synopsis:  if key(P1)!=trim(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
    + ** record blob in register P3 against a prefix of the entry that 
    +@@ -77282,6 +84653,7 @@ case OP_SorterCompare: {
    +   res = 0;
    +   rc = sqlite3VdbeSorterCompare(pC, pIn3, nKeyCol, &res);
    +   VdbeBranchTaken(res!=0,2);
    ++  if( rc ) goto abort_due_to_error;
    +   if( res ) goto jump_to_p2;
    +   break;
    + };
    +@@ -77307,57 +84679,59 @@ case OP_SorterData: {
    +   rc = sqlite3VdbeSorterRowkey(pC, pOut);
    +   assert( rc!=SQLITE_OK || (pOut->flags & MEM_Blob) );
    +   assert( pOp->p1>=0 && pOp->p1<p->nCursor );
    ++  if( rc ) goto abort_due_to_error;
    +   p->apCsr[pOp->p3]->cacheStatus = CACHE_STALE;
    +   break;
    + }
    + 
    +-/* Opcode: RowData P1 P2 * * *
    ++/* Opcode: RowData P1 P2 P3 * *
    + ** Synopsis: r[P2]=data
    + **
    +-** Write into register P2 the complete row data for cursor P1.
    ++** Write into register P2 the complete row content for the row at 
    ++** which cursor P1 is currently pointing.
    + ** There is no interpretation of the data.  
    + ** It is just copied onto the P2 register exactly as 
    + ** it is found in the database file.
    + **
    ++** If cursor P1 is an index, then the content is the key of the row.
    ++** If cursor P2 is a table, then the content extracted is the data.
    ++**
    + ** If the P1 cursor must be pointing to a valid row (not a NULL row)
    + ** of a real table, not a pseudo-table.
    +-*/
    +-/* Opcode: RowKey P1 P2 * * *
    +-** Synopsis: r[P2]=key
    + **
    +-** Write into register P2 the complete row key for cursor P1.
    +-** There is no interpretation of the data.  
    +-** The key is copied onto the P2 register exactly as 
    +-** it is found in the database file.
    ++** If P3!=0 then this opcode is allowed to make an ephermeral pointer
    ++** into the database page.  That means that the content of the output
    ++** register will be invalidated as soon as the cursor moves - including
    ++** moves caused by other cursors that "save" the the current cursors
    ++** position in order that they can write to the same table.  If P3==0
    ++** then a copy of the data is made into memory.  P3!=0 is faster, but
    ++** P3==0 is safer.
    + **
    +-** If the P1 cursor must be pointing to a valid row (not a NULL row)
    +-** of a real table, not a pseudo-table.
    ++** If P3!=0 then the content of the P2 register is unsuitable for use
    ++** in OP_Result and any OP_Result will invalidate the P2 register content.
    ++** The P2 register content is invalidated by opcodes like OP_Function or
    ++** by any use of another cursor pointing to the same table.
    + */
    +-case OP_RowKey:
    + case OP_RowData: {
    +   VdbeCursor *pC;
    +   BtCursor *pCrsr;
    +   u32 n;
    +-  i64 n64;
    + 
    +-  pOut = &aMem[pOp->p2];
    +-  memAboutToChange(p, pOut);
    ++  pOut = out2Prerelease(p, pOp);
    + 
    +-  /* Note that RowKey and RowData are really exactly the same instruction */
    +   assert( pOp->p1>=0 && pOp->p1<p->nCursor );
    +   pC = p->apCsr[pOp->p1];
    +-  assert( isSorter(pC)==0 );
    +-  assert( pC->isTable || pOp->opcode!=OP_RowData );
    +-  assert( pC->isTable==0 || pOp->opcode==OP_RowData );
    +   assert( pC!=0 );
    ++  assert( pC->eCurType==CURTYPE_BTREE );
    ++  assert( isSorter(pC)==0 );
    +   assert( pC->nullRow==0 );
    +-  assert( pC->pseudoTableReg==0 );
    +-  assert( pC->pCursor!=0 );
    +-  pCrsr = pC->pCursor;
    ++  assert( pC->uc.pCursor!=0 );
    ++  pCrsr = pC->uc.pCursor;
    + 
    +-  /* The OP_RowKey and OP_RowData opcodes always follow OP_NotExists or
    +-  ** OP_Rewind/Op_Next with no intervening instructions that might invalidate
    +-  ** the cursor.  If this where not the case, on of the following assert()s
    ++  /* The OP_RowData opcodes always follow OP_NotExists or
    ++  ** OP_SeekRowid or OP_Rewind/Op_Next with no intervening instructions
    ++  ** that might invalidate the cursor.
    ++  ** If this where not the case, on of the following assert()s
    +   ** would fail.  Should this ever change (because of changes in the code
    +   ** generator) then the fix would be to insert a call to
    +   ** sqlite3VdbeCursorMoveto().
    +@@ -77369,33 +84743,14 @@ case OP_RowData: {
    +   if( rc!=SQLITE_OK ) goto abort_due_to_error;
    + #endif
    + 
    +-  if( pC->isTable==0 ){
    +-    assert( !pC->isTable );
    +-    VVA_ONLY(rc =) sqlite3BtreeKeySize(pCrsr, &n64);
    +-    assert( rc==SQLITE_OK );    /* True because of CursorMoveto() call above */
    +-    if( n64>db->aLimit[SQLITE_LIMIT_LENGTH] ){
    +-      goto too_big;
    +-    }
    +-    n = (u32)n64;
    +-  }else{
    +-    VVA_ONLY(rc =) sqlite3BtreeDataSize(pCrsr, &n);
    +-    assert( rc==SQLITE_OK );    /* DataSize() cannot fail */
    +-    if( n>(u32)db->aLimit[SQLITE_LIMIT_LENGTH] ){
    +-      goto too_big;
    +-    }
    ++  n = sqlite3BtreePayloadSize(pCrsr);
    ++  if( n>(u32)db->aLimit[SQLITE_LIMIT_LENGTH] ){
    ++    goto too_big;
    +   }
    +   testcase( n==0 );
    +-  if( sqlite3VdbeMemClearAndResize(pOut, MAX(n,32)) ){
    +-    goto no_mem;
    +-  }
    +-  pOut->n = n;
    +-  MemSetTypeFlag(pOut, MEM_Blob);
    +-  if( pC->isTable==0 ){
    +-    rc = sqlite3BtreeKey(pCrsr, 0, n, pOut->z);
    +-  }else{
    +-    rc = sqlite3BtreeData(pCrsr, 0, n, pOut->z);
    +-  }
    +-  pOut->enc = SQLITE_UTF8;  /* In case the blob is ever cast to text */
    ++  rc = sqlite3VdbeMemFromBtree(pCrsr, 0, n, pOut);
    ++  if( rc ) goto abort_due_to_error;
    ++  if( !pOp->p3 ) Deephemeralize(pOut);
    +   UPDATE_MAX_BLOBSIZE(pOut);
    +   REGISTER_TRACE(pOp->p2, pOut);
    +   break;
    +@@ -77421,30 +84776,32 @@ case OP_Rowid: {                 /* out2 */
    +   assert( pOp->p1>=0 && pOp->p1<p->nCursor );
    +   pC = p->apCsr[pOp->p1];
    +   assert( pC!=0 );
    +-  assert( pC->pseudoTableReg==0 || pC->nullRow );
    ++  assert( pC->eCurType!=CURTYPE_PSEUDO || pC->nullRow );
    +   if( pC->nullRow ){
    +     pOut->flags = MEM_Null;
    +     break;
    +   }else if( pC->deferredMoveto ){
    +     v = pC->movetoTarget;
    + #ifndef SQLITE_OMIT_VIRTUALTABLE
    +-  }else if( pC->pVtabCursor ){
    +-    pVtab = pC->pVtabCursor->pVtab;
    ++  }else if( pC->eCurType==CURTYPE_VTAB ){
    ++    assert( pC->uc.pVCur!=0 );
    ++    pVtab = pC->uc.pVCur->pVtab;
    +     pModule = pVtab->pModule;
    +     assert( pModule->xRowid );
    +-    rc = pModule->xRowid(pC->pVtabCursor, &v);
    ++    rc = pModule->xRowid(pC->uc.pVCur, &v);
    +     sqlite3VtabImportErrmsg(p, pVtab);
    ++    if( rc ) goto abort_due_to_error;
    + #endif /* SQLITE_OMIT_VIRTUALTABLE */
    +   }else{
    +-    assert( pC->pCursor!=0 );
    ++    assert( pC->eCurType==CURTYPE_BTREE );
    ++    assert( pC->uc.pCursor!=0 );
    +     rc = sqlite3VdbeCursorRestore(pC);
    +     if( rc ) goto abort_due_to_error;
    +     if( pC->nullRow ){
    +       pOut->flags = MEM_Null;
    +       break;
    +     }
    +-    rc = sqlite3BtreeKeySize(pC->pCursor, &v);
    +-    assert( rc==SQLITE_OK );  /* Always so because of CursorRestore() above */
    ++    v = sqlite3BtreeIntegerKey(pC->uc.pCursor);
    +   }
    +   pOut->u.i = v;
    +   break;
    +@@ -77464,13 +84821,24 @@ case OP_NullRow: {
    +   assert( pC!=0 );
    +   pC->nullRow = 1;
    +   pC->cacheStatus = CACHE_STALE;
    +-  if( pC->pCursor ){
    +-    sqlite3BtreeClearCursor(pC->pCursor);
    ++  if( pC->eCurType==CURTYPE_BTREE ){
    ++    assert( pC->uc.pCursor!=0 );
    ++    sqlite3BtreeClearCursor(pC->uc.pCursor);
    +   }
    +   break;
    + }
    + 
    +-/* Opcode: Last P1 P2 P3 * *
    ++/* Opcode: SeekEnd P1 * * * *
    ++**
    ++** Position cursor P1 at the end of the btree for the purpose of
    ++** appending a new entry onto the btree.
    ++**
    ++** It is assumed that the cursor is used only for appending and so
    ++** if the cursor is valid, then the cursor must already be pointing
    ++** at the end of the btree and so no changes are made to
    ++** the cursor.
    ++*/
    ++/* Opcode: Last P1 P2 * * *
    + **
    + ** 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.
    +@@ -77482,6 +84850,7 @@ case OP_NullRow: {
    + ** from the end toward the beginning.  In other words, the cursor is
    + ** configured to use Prev, not Next.
    + */
    ++case OP_SeekEnd:
    + case OP_Last: {        /* jump */
    +   VdbeCursor *pC;
    +   BtCursor *pCrsr;
    +@@ -77490,17 +84859,25 @@ case OP_Last: {        /* jump */
    +   assert( pOp->p1>=0 && pOp->p1<p->nCursor );
    +   pC = p->apCsr[pOp->p1];
    +   assert( pC!=0 );
    +-  pCrsr = pC->pCursor;
    ++  assert( pC->eCurType==CURTYPE_BTREE );
    ++  pCrsr = pC->uc.pCursor;
    +   res = 0;
    +   assert( pCrsr!=0 );
    ++#ifdef SQLITE_DEBUG
    ++  pC->seekOp = pOp->opcode;
    ++#endif
    ++  if( pOp->opcode==OP_SeekEnd ){
    ++    assert( pOp->p2==0 );
    ++    pC->seekResult = -1;
    ++    if( sqlite3BtreeCursorIsValidNN(pCrsr) ){
    ++      break;
    ++    }
    ++  }
    +   rc = sqlite3BtreeLast(pCrsr, &res);
    +   pC->nullRow = (u8)res;
    +   pC->deferredMoveto = 0;
    +   pC->cacheStatus = CACHE_STALE;
    +-  pC->seekResult = pOp->p3;
    +-#ifdef SQLITE_DEBUG
    +-  pC->seekOp = OP_Last;
    +-#endif
    ++  if( rc ) goto abort_due_to_error;
    +   if( pOp->p2>0 ){
    +     VdbeBranchTaken(res!=0,2);
    +     if( res ) goto jump_to_p2;
    +@@ -77508,7 +84885,43 @@ case OP_Last: {        /* jump */
    +   break;
    + }
    + 
    ++/* Opcode: IfSmaller P1 P2 P3 * *
    ++**
    ++** Estimate the number of rows in the table P1.  Jump to P2 if that
    ++** estimate is less than approximately 2**(0.1*P3).
    ++*/
    ++case OP_IfSmaller: {        /* jump */
    ++  VdbeCursor *pC;
    ++  BtCursor *pCrsr;
    ++  int res;
    ++  i64 sz;
    ++
    ++  assert( pOp->p1>=0 && pOp->p1<p->nCursor );
    ++  pC = p->apCsr[pOp->p1];
    ++  assert( pC!=0 );
    ++  pCrsr = pC->uc.pCursor;
    ++  assert( pCrsr );
    ++  rc = sqlite3BtreeFirst(pCrsr, &res);
    ++  if( rc ) goto abort_due_to_error;
    ++  if( res==0 ){
    ++    sz = sqlite3BtreeRowCountEst(pCrsr);
    ++    if( ALWAYS(sz>=0) && sqlite3LogEst((u64)sz)<pOp->p3 ) res = 1;
    ++  }
    ++  VdbeBranchTaken(res!=0,2);
    ++  if( res ) goto jump_to_p2;
    ++  break;
    ++}
    ++
    + 
    ++/* Opcode: SorterSort P1 P2 * * *
    ++**
    ++** After all records have been inserted into the Sorter object
    ++** identified by P1, invoke this opcode to actually do the sorting.
    ++** Jump to P2 if there are no records to be sorted.
    ++**
    ++** This opcode is an alias for OP_Sort and OP_Rewind that is used
    ++** for Sorter objects.
    ++*/
    + /* Opcode: Sort P1 P2 * * *
    + **
    + ** This opcode does exactly the same thing as OP_Rewind except that
    +@@ -77558,12 +84971,14 @@ case OP_Rewind: {        /* jump */
    +   if( isSorter(pC) ){
    +     rc = sqlite3VdbeSorterRewind(pC, &res);
    +   }else{
    +-    pCrsr = pC->pCursor;
    ++    assert( pC->eCurType==CURTYPE_BTREE );
    ++    pCrsr = pC->uc.pCursor;
    +     assert( pCrsr );
    +     rc = sqlite3BtreeFirst(pCrsr, &res);
    +     pC->deferredMoveto = 0;
    +     pC->cacheStatus = CACHE_STALE;
    +   }
    ++  if( rc ) goto abort_due_to_error;
    +   pC->nullRow = (u8)res;
    +   assert( pOp->p2>0 && pOp->p2<p->nOp );
    +   VdbeBranchTaken(res!=0,2);
    +@@ -77634,14 +85049,19 @@ case OP_Rewind: {        /* jump */
    + ** This opcode works just like Prev except that if cursor P1 is not
    + ** open it behaves a no-op.
    + */
    ++/* Opcode: SorterNext P1 P2 * * P5
    ++**
    ++** This opcode works just like OP_Next except that P1 must be a
    ++** sorter object for which the OP_SorterSort opcode has been
    ++** invoked.  This opcode advances the cursor to the next sorted
    ++** record, or jumps to P2 if there are no more sorted records.
    ++*/
    + case OP_SorterNext: {  /* jump */
    +   VdbeCursor *pC;
    +-  int res;
    + 
    +   pC = p->apCsr[pOp->p1];
    +   assert( isSorter(pC) );
    +-  res = 0;
    +-  rc = sqlite3VdbeSorterNext(db, pC, &res);
    ++  rc = sqlite3VdbeSorterNext(db, pC);
    +   goto next_tail;
    + case OP_PrevIfOpen:    /* jump */
    + case OP_NextIfOpen:    /* jump */
    +@@ -77652,12 +85072,9 @@ case OP_Next:          /* jump */
    +   assert( pOp->p1>=0 && pOp->p1<p->nCursor );
    +   assert( pOp->p5<ArraySize(p->aCounter) );
    +   pC = p->apCsr[pOp->p1];
    +-  res = pOp->p3;
    +   assert( pC!=0 );
    +   assert( pC->deferredMoveto==0 );
    +-  assert( pC->pCursor );
    +-  assert( res==0 || (res==1 && pC->isTable==0) );
    +-  testcase( res==1 );
    ++  assert( pC->eCurType==CURTYPE_BTREE );
    +   assert( pOp->opcode!=OP_Next || pOp->p4.xAdvance==sqlite3BtreeNext );
    +   assert( pOp->opcode!=OP_Prev || pOp->p4.xAdvance==sqlite3BtreePrevious );
    +   assert( pOp->opcode!=OP_NextIfOpen || pOp->p4.xAdvance==sqlite3BtreeNext );
    +@@ -77672,49 +85089,63 @@ case OP_Next:          /* jump */
    +        || pC->seekOp==OP_SeekLT || pC->seekOp==OP_SeekLE
    +        || pC->seekOp==OP_Last );
    + 
    +-  rc = pOp->p4.xAdvance(pC->pCursor, &res);
    ++  rc = pOp->p4.xAdvance(pC->uc.pCursor, pOp->p3);
    + next_tail:
    +   pC->cacheStatus = CACHE_STALE;
    +-  VdbeBranchTaken(res==0,2);
    +-  if( res==0 ){
    ++  VdbeBranchTaken(rc==SQLITE_OK,2);
    ++  if( rc==SQLITE_OK ){
    +     pC->nullRow = 0;
    +     p->aCounter[pOp->p5]++;
    + #ifdef SQLITE_TEST
    +     sqlite3_search_count++;
    + #endif
    +     goto jump_to_p2_and_check_for_interrupt;
    +-  }else{
    +-    pC->nullRow = 1;
    +   }
    ++  if( rc!=SQLITE_DONE ) goto abort_due_to_error;
    ++  rc = SQLITE_OK;
    ++  pC->nullRow = 1;
    +   goto check_for_interrupt;
    + }
    + 
    +-/* Opcode: IdxInsert P1 P2 P3 * P5
    ++/* Opcode: IdxInsert P1 P2 P3 P4 P5
    + ** Synopsis: key=r[P2]
    + **
    + ** Register P2 holds an SQL index key made using the
    + ** MakeRecord instructions.  This opcode writes that key
    + ** into the index P1.  Data for the entry is nil.
    + **
    +-** P3 is a flag that provides a hint to the b-tree layer that this
    +-** insert is likely to be an append.
    ++** If P4 is not zero, then it is the number of values in the unpacked
    ++** key of reg(P2).  In that case, P3 is the index of the first register
    ++** for the unpacked key.  The availability of the unpacked key can sometimes
    ++** be an optimization.
    ++**
    ++** If P5 has the OPFLAG_APPEND bit set, that is a hint to the b-tree layer
    ++** that this insert is likely to be an append.
    + **
    + ** If P5 has the OPFLAG_NCHANGE bit set, then the change counter is
    + ** incremented by this instruction.  If the OPFLAG_NCHANGE bit is clear,
    + ** then the change counter is unchanged.
    + **
    +-** If P5 has the OPFLAG_USESEEKRESULT bit set, then the cursor must have
    +-** just done a seek to the spot where the new entry is to be inserted.
    +-** This flag avoids doing an extra seek.
    ++** If the OPFLAG_USESEEKRESULT flag of P5 is set, the implementation might
    ++** run faster by avoiding an unnecessary seek on cursor P1.  However,
    ++** the OPFLAG_USESEEKRESULT flag must only be set if there have been no prior
    ++** seeks on the cursor or if the most recent seek used a key equivalent
    ++** to P2. 
    + **
    + ** This instruction only works for indices.  The equivalent instruction
    + ** for tables is OP_Insert.
    + */
    ++/* Opcode: SorterInsert P1 P2 * * *
    ++** Synopsis: key=r[P2]
    ++**
    ++** Register P2 holds an SQL index key made using the
    ++** MakeRecord instructions.  This opcode writes that key
    ++** into the sorter P1.  Data for the entry is nil.
    ++*/
    + case OP_SorterInsert:       /* in2 */
    + case OP_IdxInsert: {        /* in2 */
    +   VdbeCursor *pC;
    +-  int nKey;
    +-  const char *zKey;
    ++  BtreePayload x;
    + 
    +   assert( pOp->p1>=0 && pOp->p1<p->nCursor );
    +   pC = p->apCsr[pOp->p1];
    +@@ -77723,22 +85154,25 @@ case OP_IdxInsert: {        /* in2 */
    +   pIn2 = &aMem[pOp->p2];
    +   assert( pIn2->flags & MEM_Blob );
    +   if( pOp->p5 & OPFLAG_NCHANGE ) p->nChange++;
    +-  assert( pC->pCursor!=0 );
    ++  assert( pC->eCurType==CURTYPE_BTREE || pOp->opcode==OP_SorterInsert );
    +   assert( pC->isTable==0 );
    +   rc = ExpandBlob(pIn2);
    +-  if( rc==SQLITE_OK ){
    +-    if( pOp->opcode==OP_SorterInsert ){
    +-      rc = sqlite3VdbeSorterWrite(pC, pIn2);
    +-    }else{
    +-      nKey = pIn2->n;
    +-      zKey = pIn2->z;
    +-      rc = sqlite3BtreeInsert(pC->pCursor, zKey, nKey, "", 0, 0, pOp->p3, 
    +-          ((pOp->p5 & OPFLAG_USESEEKRESULT) ? pC->seekResult : 0)
    +-          );
    +-      assert( pC->deferredMoveto==0 );
    +-      pC->cacheStatus = CACHE_STALE;
    +-    }
    ++  if( rc ) goto abort_due_to_error;
    ++  if( pOp->opcode==OP_SorterInsert ){
    ++    rc = sqlite3VdbeSorterWrite(pC, pIn2);
    ++  }else{
    ++    x.nKey = pIn2->n;
    ++    x.pKey = pIn2->z;
    ++    x.aMem = aMem + pOp->p3;
    ++    x.nMem = (u16)pOp->p4.i;
    ++    rc = sqlite3BtreeInsert(pC->uc.pCursor, &x,
    ++         (pOp->p5 & (OPFLAG_APPEND|OPFLAG_SAVEPOSITION)), 
    ++        ((pOp->p5 & OPFLAG_USESEEKRESULT) ? pC->seekResult : 0)
    ++        );
    ++    assert( pC->deferredMoveto==0 );
    ++    pC->cacheStatus = CACHE_STALE;
    +   }
    ++  if( rc) goto abort_due_to_error;
    +   break;
    + }
    + 
    +@@ -77756,29 +85190,49 @@ case OP_IdxDelete: {
    +   UnpackedRecord r;
    + 
    +   assert( pOp->p3>0 );
    +-  assert( pOp->p2>0 && pOp->p2+pOp->p3<=(p->nMem-p->nCursor)+1 );
    ++  assert( pOp->p2>0 && pOp->p2+pOp->p3<=(p->nMem+1 - p->nCursor)+1 );
    +   assert( pOp->p1>=0 && pOp->p1<p->nCursor );
    +   pC = p->apCsr[pOp->p1];
    +   assert( pC!=0 );
    +-  pCrsr = pC->pCursor;
    ++  assert( pC->eCurType==CURTYPE_BTREE );
    ++  pCrsr = pC->uc.pCursor;
    +   assert( pCrsr!=0 );
    +   assert( pOp->p5==0 );
    +   r.pKeyInfo = pC->pKeyInfo;
    +   r.nField = (u16)pOp->p3;
    +   r.default_rc = 0;
    +   r.aMem = &aMem[pOp->p2];
    +-#ifdef SQLITE_DEBUG
    +-  { int i; for(i=0; i<r.nField; i++) assert( memIsValid(&r.aMem[i]) ); }
    +-#endif
    +   rc = sqlite3BtreeMovetoUnpacked(pCrsr, &r, 0, 0, &res);
    +-  if( rc==SQLITE_OK && res==0 ){
    +-    rc = sqlite3BtreeDelete(pCrsr, 0);
    ++  if( rc ) goto abort_due_to_error;
    ++  if( res==0 ){
    ++    rc = sqlite3BtreeDelete(pCrsr, BTREE_AUXDELETE);
    ++    if( rc ) goto abort_due_to_error;
    +   }
    +   assert( pC->deferredMoveto==0 );
    +   pC->cacheStatus = CACHE_STALE;
    ++  pC->seekResult = 0;
    +   break;
    + }
    + 
    ++/* Opcode: DeferredSeek P1 * P3 P4 *
    ++** Synopsis: Move P3 to P1.rowid if needed
    ++**
    ++** P1 is an open index cursor and P3 is a cursor on the corresponding
    ++** table.  This opcode does a deferred seek of the P3 table cursor
    ++** to the row that corresponds to the current row of P1.
    ++**
    ++** This is a deferred seek.  Nothing actually happens until
    ++** the cursor is used to read a record.  That way, if no reads
    ++** occur, no unnecessary I/O happens.
    ++**
    ++** P4 may be an array of integers (type P4_INTARRAY) containing
    ++** one entry for each column in the P3 table.  If array entry a(i)
    ++** is non-zero, then reading column a(i)-1 from cursor P3 is 
    ++** equivalent to performing the deferred seek and then reading column i 
    ++** from P1.  This information is stored in P3 and used to redirect
    ++** reads against P3 over to P1, thus possibly avoiding the need to
    ++** seek and read cursor P3.
    ++*/
    + /* Opcode: IdxRowid P1 P2 * * *
    + ** Synopsis: r[P2]=rowid
    + **
    +@@ -77788,36 +85242,56 @@ case OP_IdxDelete: {
    + **
    + ** See also: Rowid, MakeRecord.
    + */
    +-case OP_IdxRowid: {              /* out2 */
    +-  BtCursor *pCrsr;
    +-  VdbeCursor *pC;
    +-  i64 rowid;
    ++case OP_DeferredSeek:
    ++case OP_IdxRowid: {           /* out2 */
    ++  VdbeCursor *pC;             /* The P1 index cursor */
    ++  VdbeCursor *pTabCur;        /* The P2 table cursor (OP_DeferredSeek only) */
    ++  i64 rowid;                  /* Rowid that P1 current points to */
    + 
    +-  pOut = out2Prerelease(p, pOp);
    +   assert( pOp->p1>=0 && pOp->p1<p->nCursor );
    +   pC = p->apCsr[pOp->p1];
    +   assert( pC!=0 );
    +-  pCrsr = pC->pCursor;
    +-  assert( pCrsr!=0 );
    +-  pOut->flags = MEM_Null;
    ++  assert( pC->eCurType==CURTYPE_BTREE );
    ++  assert( pC->uc.pCursor!=0 );
    +   assert( pC->isTable==0 );
    +   assert( pC->deferredMoveto==0 );
    ++  assert( !pC->nullRow || pOp->opcode==OP_IdxRowid );
    + 
    +-  /* sqlite3VbeCursorRestore() can only fail if the record has been deleted
    +-  ** out from under the cursor.  That will never happend for an IdxRowid
    +-  ** opcode, hence the NEVER() arround the check of the return value.
    +-  */
    ++  /* The IdxRowid and Seek opcodes are combined because of the commonality
    ++  ** of sqlite3VdbeCursorRestore() and sqlite3VdbeIdxRowid(). */
    +   rc = sqlite3VdbeCursorRestore(pC);
    ++
    ++  /* sqlite3VbeCursorRestore() can only fail if the record has been deleted
    ++  ** out from under the cursor.  That will never happens for an IdxRowid
    ++  ** or Seek opcode */
    +   if( NEVER(rc!=SQLITE_OK) ) goto abort_due_to_error;
    + 
    +   if( !pC->nullRow ){
    +     rowid = 0;  /* Not needed.  Only used to silence a warning. */
    +-    rc = sqlite3VdbeIdxRowid(db, pCrsr, &rowid);
    ++    rc = sqlite3VdbeIdxRowid(db, pC->uc.pCursor, &rowid);
    +     if( rc!=SQLITE_OK ){
    +       goto abort_due_to_error;
    +     }
    +-    pOut->u.i = rowid;
    +-    pOut->flags = MEM_Int;
    ++    if( pOp->opcode==OP_DeferredSeek ){
    ++      assert( pOp->p3>=0 && pOp->p3<p->nCursor );
    ++      pTabCur = p->apCsr[pOp->p3];
    ++      assert( pTabCur!=0 );
    ++      assert( pTabCur->eCurType==CURTYPE_BTREE );
    ++      assert( pTabCur->uc.pCursor!=0 );
    ++      assert( pTabCur->isTable );
    ++      pTabCur->nullRow = 0;
    ++      pTabCur->movetoTarget = rowid;
    ++      pTabCur->deferredMoveto = 1;
    ++      assert( pOp->p4type==P4_INTARRAY || pOp->p4.ai==0 );
    ++      pTabCur->aAltMap = pOp->p4.ai;
    ++      pTabCur->pAltCursor = pC;
    ++    }else{
    ++      pOut = out2Prerelease(p, pOp);
    ++      pOut->u.i = rowid;
    ++    }
    ++  }else{
    ++    assert( pOp->opcode==OP_IdxRowid );
    ++    sqlite3VdbeMemSetNull(&aMem[pOp->p2]);
    +   }
    +   break;
    + }
    +@@ -77878,7 +85352,8 @@ case OP_IdxGE:  {       /* jump */
    +   pC = p->apCsr[pOp->p1];
    +   assert( pC!=0 );
    +   assert( pC->isOrdered );
    +-  assert( pC->pCursor!=0);
    ++  assert( pC->eCurType==CURTYPE_BTREE );
    ++  assert( pC->uc.pCursor!=0);
    +   assert( pC->deferredMoveto==0 );
    +   assert( pOp->p5==0 || pOp->p5==1 );
    +   assert( pOp->p4type==P4_INT32 );
    +@@ -77906,6 +85381,7 @@ case OP_IdxGE:  {       /* jump */
    +     res++;
    +   }
    +   VdbeBranchTaken(res>0,2);
    ++  if( rc ) goto abort_due_to_error;
    +   if( res>0 ) goto jump_to_p2;
    +   break;
    + }
    +@@ -77923,10 +85399,17 @@ case OP_IdxGE:  {       /* jump */
    + ** might be moved into the newly deleted root page in order to keep all
    + ** root pages contiguous at the beginning of the database.  The former
    + ** value of the root page that moved - its value before the move occurred -
    +-** is stored in register P2.  If no page 
    +-** movement was required (because the table being dropped was already 
    +-** the last one in the database) then a zero is stored in register P2.
    +-** If AUTOVACUUM is disabled then a zero is stored in register P2.
    ++** is stored in register P2. If no page movement was required (because the
    ++** table being dropped was already the last one in the database) then a 
    ++** zero is stored in register P2.  If AUTOVACUUM is disabled then a zero 
    ++** is stored in register P2.
    ++**
    ++** This opcode throws an error if there are any active reader VMs when
    ++** it is invoked. This is done to avoid the difficulty associated with 
    ++** updating existing cursors when a root page is moved in an AUTOVACUUM 
    ++** database. This error is thrown even if the database is not an AUTOVACUUM 
    ++** db in order to avoid introducing an incompatibility between autovacuum 
    ++** and non-autovacuum modes.
    + **
    + ** See also: Clear
    + */
    +@@ -77935,11 +85418,13 @@ case OP_Destroy: {     /* out2 */
    +   int iDb;
    + 
    +   assert( p->readOnly==0 );
    ++  assert( pOp->p1>1 );
    +   pOut = out2Prerelease(p, pOp);
    +   pOut->flags = MEM_Null;
    +   if( db->nVdbeRead > db->nVDestroy+1 ){
    +     rc = SQLITE_LOCKED;
    +     p->errorAction = OE_Abort;
    ++    goto abort_due_to_error;
    +   }else{
    +     iDb = pOp->p3;
    +     assert( DbMaskTest(p->btreeMask, iDb) );
    +@@ -77947,8 +85432,9 @@ case OP_Destroy: {     /* out2 */
    +     rc = sqlite3BtreeDropTable(db->aDb[iDb].pBt, pOp->p1, &iMoved);
    +     pOut->flags = MEM_Int;
    +     pOut->u.i = iMoved;
    ++    if( rc ) goto abort_due_to_error;
    + #ifndef SQLITE_OMIT_AUTOVACUUM
    +-    if( rc==SQLITE_OK && iMoved!=0 ){
    ++    if( iMoved!=0 ){
    +       sqlite3RootPageMoved(db, iDb, iMoved, pOp->p1);
    +       /* All OP_Destroy operations occur on the same btree */
    +       assert( resetSchemaOnFault==0 || resetSchemaOnFault==iDb+1 );
    +@@ -77994,6 +85480,7 @@ case OP_Clear: {
    +       aMem[pOp->p3].u.i += nChange;
    +     }
    +   }
    ++  if( rc ) goto abort_due_to_error;
    +   break;
    + }
    + 
    +@@ -78011,63 +85498,56 @@ case OP_ResetSorter: {
    +   assert( pOp->p1>=0 && pOp->p1<p->nCursor );
    +   pC = p->apCsr[pOp->p1];
    +   assert( pC!=0 );
    +-  if( pC->pSorter ){
    +-    sqlite3VdbeSorterReset(db, pC->pSorter);
    ++  if( isSorter(pC) ){
    ++    sqlite3VdbeSorterReset(db, pC->uc.pSorter);
    +   }else{
    ++    assert( pC->eCurType==CURTYPE_BTREE );
    +     assert( pC->isEphemeral );
    +-    rc = sqlite3BtreeClearTableOfCursor(pC->pCursor);
    ++    rc = sqlite3BtreeClearTableOfCursor(pC->uc.pCursor);
    ++    if( rc ) goto abort_due_to_error;
    +   }
    +   break;
    + }
    + 
    +-/* Opcode: CreateTable P1 P2 * * *
    +-** Synopsis: r[P2]=root iDb=P1
    +-**
    +-** Allocate a new table in the main database file if P1==0 or in the
    +-** auxiliary database file if P1==1 or in an attached database if
    +-** P1>1.  Write the root page number of the new table into
    +-** register P2
    ++/* Opcode: CreateBtree P1 P2 P3 * *
    ++** Synopsis: r[P2]=root iDb=P1 flags=P3
    + **
    +-** The difference between a table and an index is this:  A table must
    +-** have a 4-byte integer key and can have arbitrary data.  An index
    +-** has an arbitrary key but no data.
    +-**
    +-** See also: CreateIndex
    ++** Allocate a new b-tree in the main database file if P1==0 or in the
    ++** TEMP database file if P1==1 or in an attached database if
    ++** P1>1.  The P3 argument must be 1 (BTREE_INTKEY) for a rowid table
    ++** it must be 2 (BTREE_BLOBKEY) for a index or WITHOUT ROWID table.
    ++** The root page number of the new b-tree is stored in register P2.
    + */
    +-/* Opcode: CreateIndex P1 P2 * * *
    +-** Synopsis: r[P2]=root iDb=P1
    +-**
    +-** Allocate a new index in the main database file if P1==0 or in the
    +-** auxiliary database file if P1==1 or in an attached database if
    +-** P1>1.  Write the root page number of the new table into
    +-** register P2.
    +-**
    +-** See documentation on OP_CreateTable for additional information.
    +-*/
    +-case OP_CreateIndex:            /* out2 */
    +-case OP_CreateTable: {          /* out2 */
    ++case OP_CreateBtree: {          /* out2 */
    +   int pgno;
    +-  int flags;
    +   Db *pDb;
    + 
    +   pOut = out2Prerelease(p, pOp);
    +   pgno = 0;
    ++  assert( pOp->p3==BTREE_INTKEY || pOp->p3==BTREE_BLOBKEY );
    +   assert( pOp->p1>=0 && pOp->p1<db->nDb );
    +   assert( DbMaskTest(p->btreeMask, pOp->p1) );
    +   assert( p->readOnly==0 );
    +   pDb = &db->aDb[pOp->p1];
    +   assert( pDb->pBt!=0 );
    +-  if( pOp->opcode==OP_CreateTable ){
    +-    /* flags = BTREE_INTKEY; */
    +-    flags = BTREE_INTKEY;
    +-  }else{
    +-    flags = BTREE_BLOBKEY;
    +-  }
    +-  rc = sqlite3BtreeCreateTable(pDb->pBt, &pgno, flags);
    ++  rc = sqlite3BtreeCreateTable(pDb->pBt, &pgno, pOp->p3);
    ++  if( rc ) goto abort_due_to_error;
    +   pOut->u.i = pgno;
    +   break;
    + }
    + 
    ++/* Opcode: SqlExec * * * P4 *
    ++**
    ++** Run the SQL statement or statements specified in the P4 string.
    ++*/
    ++case OP_SqlExec: {
    ++  db->nSqlExec++;
    ++  rc = sqlite3_exec(db, pOp->p4.z, 0, 0, 0);
    ++  db->nSqlExec--;
    ++  if( rc ) goto abort_due_to_error;
    ++  break;
    ++}
    ++
    + /* Opcode: ParseSchema P1 * * P4 *
    + **
    + ** Read and parse all entries from the SQLITE_MASTER table of database P1
    +@@ -78096,15 +85576,15 @@ case OP_ParseSchema: {
    +   assert( iDb>=0 && iDb<db->nDb );
    +   assert( DbHasProperty(db, iDb, DB_SchemaLoaded) );
    +   /* Used to be a conditional */ {
    +-    zMaster = SCHEMA_TABLE(iDb);
    ++    zMaster = MASTER_NAME;
    +     initData.db = db;
    +     initData.iDb = pOp->p1;
    +     initData.pzErrMsg = &p->zErrMsg;
    +     zSql = sqlite3MPrintf(db,
    +        "SELECT name, rootpage, sql FROM '%q'.%s WHERE %s ORDER BY rowid",
    +-       db->aDb[iDb].zName, zMaster, pOp->p4.z);
    ++       db->aDb[iDb].zDbSName, zMaster, pOp->p4.z);
    +     if( zSql==0 ){
    +-      rc = SQLITE_NOMEM;
    ++      rc = SQLITE_NOMEM_BKPT;
    +     }else{
    +       assert( db->init.busy==0 );
    +       db->init.busy = 1;
    +@@ -78112,13 +85592,16 @@ case OP_ParseSchema: {
    +       assert( !db->mallocFailed );
    +       rc = sqlite3_exec(db, zSql, sqlite3InitCallback, &initData, 0);
    +       if( rc==SQLITE_OK ) rc = initData.rc;
    +-      sqlite3DbFree(db, zSql);
    ++      sqlite3DbFreeNN(db, zSql);
    +       db->init.busy = 0;
    +     }
    +   }
    +-  if( rc ) sqlite3ResetAllSchemasOfConnection(db);
    +-  if( rc==SQLITE_NOMEM ){
    +-    goto no_mem;
    ++  if( rc ){
    ++    sqlite3ResetAllSchemasOfConnection(db);
    ++    if( rc==SQLITE_NOMEM ){
    ++      goto no_mem;
    ++    }
    ++    goto abort_due_to_error;
    +   }
    +   break;  
    + }
    +@@ -78133,6 +85616,7 @@ case OP_ParseSchema: {
    + case OP_LoadAnalysis: {
    +   assert( pOp->p1>=0 && pOp->p1<db->nDb );
    +   rc = sqlite3AnalysisLoad(db, pOp->p1);
    ++  if( rc ) goto abort_due_to_error;
    +   break;  
    + }
    + #endif /* !defined(SQLITE_OMIT_ANALYZE) */
    +@@ -78178,20 +85662,19 @@ case OP_DropTrigger: {
    + 
    + 
    + #ifndef SQLITE_OMIT_INTEGRITY_CHECK
    +-/* Opcode: IntegrityCk P1 P2 P3 * P5
    ++/* Opcode: IntegrityCk P1 P2 P3 P4 P5
    + **
    + ** Do an analysis of the currently open database.  Store in
    + ** register P1 the text of an error message describing any problems.
    + ** If no problems are found, store a NULL in register P1.
    + **
    +-** The register P3 contains the maximum number of allowed errors.
    ++** The register P3 contains one less than the maximum number of allowed errors.
    + ** At most reg(P3) errors will be reported.
    + ** In other words, the analysis stops as soon as reg(P1) errors are 
    + ** seen.  Reg(P1) is updated with the number of errors remaining.
    + **
    +-** The root page numbers of all tables in the database are integer
    +-** stored in reg(P1), reg(P1+1), reg(P1+2), ....  There are P2 tables
    +-** total.
    ++** The root page numbers of all tables in the database are integers
    ++** stored in P4_INTARRAY argument.
    + **
    + ** If P5 is not zero, the check is done on the auxiliary database
    + ** file, not the main database file.
    +@@ -78201,37 +85684,31 @@ case OP_DropTrigger: {
    + case OP_IntegrityCk: {
    +   int nRoot;      /* Number of tables to check.  (Number of root pages.) */
    +   int *aRoot;     /* Array of rootpage numbers for tables to be checked */
    +-  int j;          /* Loop counter */
    +   int nErr;       /* Number of errors reported */
    +   char *z;        /* Text of the error report */
    +   Mem *pnErr;     /* Register keeping track of errors remaining */
    + 
    +   assert( p->bIsReader );
    +   nRoot = pOp->p2;
    ++  aRoot = pOp->p4.ai;
    +   assert( nRoot>0 );
    +-  aRoot = sqlite3DbMallocRaw(db, sizeof(int)*(nRoot+1) );
    +-  if( aRoot==0 ) goto no_mem;
    +-  assert( pOp->p3>0 && pOp->p3<=(p->nMem-p->nCursor) );
    ++  assert( aRoot[0]==nRoot );
    ++  assert( pOp->p3>0 && pOp->p3<=(p->nMem+1 - p->nCursor) );
    +   pnErr = &aMem[pOp->p3];
    +   assert( (pnErr->flags & MEM_Int)!=0 );
    +   assert( (pnErr->flags & (MEM_Str|MEM_Blob))==0 );
    +   pIn1 = &aMem[pOp->p1];
    +-  for(j=0; j<nRoot; j++){
    +-    aRoot[j] = (int)sqlite3VdbeIntValue(&pIn1[j]);
    +-  }
    +-  aRoot[j] = 0;
    +   assert( pOp->p5<db->nDb );
    +   assert( DbMaskTest(p->btreeMask, pOp->p5) );
    +-  z = sqlite3BtreeIntegrityCheck(db->aDb[pOp->p5].pBt, aRoot, nRoot,
    +-                                 (int)pnErr->u.i, &nErr);
    +-  sqlite3DbFree(db, aRoot);
    +-  pnErr->u.i -= nErr;
    ++  z = sqlite3BtreeIntegrityCheck(db->aDb[pOp->p5].pBt, &aRoot[1], nRoot,
    ++                                 (int)pnErr->u.i+1, &nErr);
    +   sqlite3VdbeMemSetNull(pIn1);
    +   if( nErr==0 ){
    +     assert( z==0 );
    +   }else if( z==0 ){
    +     goto no_mem;
    +   }else{
    ++    pnErr->u.i -= nErr-1;
    +     sqlite3VdbeMemSetStr(pIn1, z, -1, SQLITE_UTF8, sqlite3_free);
    +   }
    +   UPDATE_MAX_BLOBSIZE(pIn1);
    +@@ -78241,9 +85718,9 @@ case OP_IntegrityCk: {
    + #endif /* SQLITE_OMIT_INTEGRITY_CHECK */
    + 
    + /* Opcode: RowSetAdd P1 P2 * * *
    +-** Synopsis:  rowset(P1)=r[P2]
    ++** Synopsis: rowset(P1)=r[P2]
    + **
    +-** Insert the integer value held by register P2 into a boolean index
    ++** Insert the integer value held by register P2 into a RowSet object
    + ** held in register P1.
    + **
    + ** An assertion fails if P2 is not an integer.
    +@@ -78261,10 +85738,11 @@ case OP_RowSetAdd: {       /* in1, in2 */
    + }
    + 
    + /* Opcode: RowSetRead P1 P2 P3 * *
    +-** Synopsis:  r[P3]=rowset(P1)
    ++** Synopsis: r[P3]=rowset(P1)
    + **
    +-** Extract the smallest value from boolean index P1 and put that value into
    +-** register P3.  Or, if boolean index P1 is initially empty, leave P3
    ++** Extract the smallest value from the RowSet object in P1
    ++** and put that value into register P3.
    ++** Or, if RowSet object P1 is initially empty, leave P3
    + ** unchanged and jump to instruction P2.
    + */
    + case OP_RowSetRead: {       /* jump, in1, out3 */
    +@@ -78295,15 +85773,14 @@ case OP_RowSetRead: {       /* jump, in1, out3 */
    + ** integer in P3 into the RowSet and continue on to the
    + ** next opcode.
    + **
    +-** The RowSet object is optimized for the case where successive sets
    +-** of integers, where each set contains no duplicates. Each set
    +-** of values is identified by a unique P4 value. The first set
    +-** must have P4==0, the final set P4=-1.  P4 must be either -1 or
    +-** non-negative.  For non-negative values of P4 only the lower 4
    +-** bits are significant.
    ++** The RowSet object is optimized for the case where sets of integers
    ++** are inserted in distinct phases, which each set contains no duplicates.
    ++** Each set is identified by a unique P4 value. The first set
    ++** must have P4==0, the final set must have P4==-1, and for all other sets
    ++** must have P4>0.
    + **
    + ** This allows optimizations: (a) when P4==0 there is no need to test
    +-** the rowset object for P3, as it is guaranteed not to contain it,
    ++** the RowSet object for P3, as it is guaranteed not to contain it,
    + ** (b) when P4==-1 there is no need to insert the value, as it will
    + ** never be tested for, and (c) when a value that is part of set X is
    + ** inserted, there is no need to search to see if the same value was
    +@@ -78392,7 +85869,7 @@ case OP_Program: {        /* jump */
    +   if( p->nFrame>=db->aLimit[SQLITE_LIMIT_TRIGGER_DEPTH] ){
    +     rc = SQLITE_ERROR;
    +     sqlite3VdbeError(p, "too many levels of trigger recursion");
    +-    break;
    ++    goto abort_due_to_error;
    +   }
    + 
    +   /* Register pRt is used to store the memory required to save the state
    +@@ -78406,10 +85883,12 @@ case OP_Program: {        /* jump */
    +     ** variable nMem (and later, VdbeFrame.nChildMem) to this value.
    +     */
    +     nMem = pProgram->nMem + pProgram->nCsr;
    ++    assert( nMem>0 );
    ++    if( pProgram->nCsr==0 ) nMem++;
    +     nByte = ROUND8(sizeof(VdbeFrame))
    +               + nMem * sizeof(Mem)
    +-              + pProgram->nCsr * sizeof(VdbeCursor *)
    +-              + pProgram->nOnce * sizeof(u8);
    ++              + pProgram->nCsr * sizeof(VdbeCursor*)
    ++              + (pProgram->nOp + 7)/8;
    +     pFrame = sqlite3DbMallocZero(db, nByte);
    +     if( !pFrame ){
    +       goto no_mem;
    +@@ -78429,8 +85908,6 @@ case OP_Program: {        /* jump */
    +     pFrame->aOp = p->aOp;
    +     pFrame->nOp = p->nOp;
    +     pFrame->token = pProgram->token;
    +-    pFrame->aOnceFlag = p->aOnceFlag;
    +-    pFrame->nOnceFlag = p->nOnceFlag;
    + #ifdef SQLITE_ENABLE_STMT_SCANSTATUS
    +     pFrame->anExec = p->anExec;
    + #endif
    +@@ -78442,31 +85919,34 @@ case OP_Program: {        /* jump */
    +     }
    +   }else{
    +     pFrame = pRt->u.pFrame;
    +-    assert( pProgram->nMem+pProgram->nCsr==pFrame->nChildMem );
    ++    assert( pProgram->nMem+pProgram->nCsr==pFrame->nChildMem 
    ++        || (pProgram->nCsr==0 && pProgram->nMem+1==pFrame->nChildMem) );
    +     assert( pProgram->nCsr==pFrame->nChildCsr );
    +     assert( (int)(pOp - aOp)==pFrame->pc );
    +   }
    + 
    +   p->nFrame++;
    +   pFrame->pParent = p->pFrame;
    +-  pFrame->lastRowid = lastRowid;
    ++  pFrame->lastRowid = db->lastRowid;
    +   pFrame->nChange = p->nChange;
    +   pFrame->nDbChange = p->db->nChange;
    ++  assert( pFrame->pAuxData==0 );
    ++  pFrame->pAuxData = p->pAuxData;
    ++  p->pAuxData = 0;
    +   p->nChange = 0;
    +   p->pFrame = pFrame;
    +-  p->aMem = aMem = &VdbeFrameMem(pFrame)[-1];
    ++  p->aMem = aMem = VdbeFrameMem(pFrame);
    +   p->nMem = pFrame->nChildMem;
    +   p->nCursor = (u16)pFrame->nChildCsr;
    +-  p->apCsr = (VdbeCursor **)&aMem[p->nMem+1];
    ++  p->apCsr = (VdbeCursor **)&aMem[p->nMem];
    ++  pFrame->aOnce = (u8*)&p->apCsr[pProgram->nCsr];
    ++  memset(pFrame->aOnce, 0, (pProgram->nOp + 7)/8);
    +   p->aOp = aOp = pProgram->aOp;
    +   p->nOp = pProgram->nOp;
    +-  p->aOnceFlag = (u8 *)&p->apCsr[p->nCursor];
    +-  p->nOnceFlag = pProgram->nOnce;
    + #ifdef SQLITE_ENABLE_STMT_SCANSTATUS
    +   p->anExec = 0;
    + #endif
    +   pOp = &aOp[-1];
    +-  memset(p->aOnceFlag, 0, p->nOnceFlag);
    + 
    +   break;
    + }
    +@@ -78591,37 +86071,61 @@ case OP_IfPos: {        /* jump, in1 */
    +   break;
    + }
    + 
    +-/* Opcode: SetIfNotPos P1 P2 P3 * *
    +-** Synopsis: if r[P1]<=0 then r[P2]=P3
    ++/* Opcode: OffsetLimit P1 P2 P3 * *
    ++** Synopsis: if r[P1]>0 then r[P2]=r[P1]+max(0,r[P3]) else r[P2]=(-1)
    + **
    +-** Register P1 must contain an integer.
    +-** If the value of register P1 is not positive (if it is less than 1) then
    +-** set the value of register P2 to be the integer P3.
    ++** This opcode performs a commonly used computation associated with
    ++** LIMIT and OFFSET process.  r[P1] holds the limit counter.  r[P3]
    ++** holds the offset counter.  The opcode computes the combined value
    ++** of the LIMIT and OFFSET and stores that value in r[P2].  The r[P2]
    ++** value computed is the total number of rows that will need to be
    ++** visited in order to complete the query.
    ++**
    ++** If r[P3] is zero or negative, that means there is no OFFSET
    ++** and r[P2] is set to be the value of the LIMIT, r[P1].
    ++**
    ++** if r[P1] is zero or negative, that means there is no LIMIT
    ++** and r[P2] is set to -1. 
    ++**
    ++** Otherwise, r[P2] is set to the sum of r[P1] and r[P3].
    + */
    +-case OP_SetIfNotPos: {        /* in1, in2 */
    ++case OP_OffsetLimit: {    /* in1, out2, in3 */
    ++  i64 x;
    +   pIn1 = &aMem[pOp->p1];
    +-  assert( pIn1->flags&MEM_Int );
    +-  if( pIn1->u.i<=0 ){
    +-    pOut = out2Prerelease(p, pOp);
    +-    pOut->u.i = pOp->p3;
    ++  pIn3 = &aMem[pOp->p3];
    ++  pOut = out2Prerelease(p, pOp);
    ++  assert( pIn1->flags & MEM_Int );
    ++  assert( pIn3->flags & MEM_Int );
    ++  x = pIn1->u.i;
    ++  if( x<=0 || sqlite3AddInt64(&x, pIn3->u.i>0?pIn3->u.i:0) ){
    ++    /* If the LIMIT is less than or equal to zero, loop forever.  This
    ++    ** is documented.  But also, if the LIMIT+OFFSET exceeds 2^63 then
    ++    ** also loop forever.  This is undocumented.  In fact, one could argue
    ++    ** that the loop should terminate.  But assuming 1 billion iterations
    ++    ** per second (far exceeding the capabilities of any current hardware)
    ++    ** it would take nearly 300 years to actually reach the limit.  So
    ++    ** looping forever is a reasonable approximation. */
    ++    pOut->u.i = -1;
    ++  }else{
    ++    pOut->u.i = x;
    +   }
    +   break;
    + }
    + 
    +-/* Opcode: IfNotZero P1 P2 P3 * *
    +-** Synopsis: if r[P1]!=0 then r[P1]-=P3, goto P2
    ++/* Opcode: IfNotZero P1 P2 * * *
    ++** Synopsis: if r[P1]!=0 then r[P1]--, goto P2
    + **
    + ** Register P1 must contain an integer.  If the content of register P1 is
    +-** initially nonzero, then subtract P3 from the value in register P1 and
    +-** jump to P2.  If register P1 is initially zero, leave it unchanged
    +-** and fall through.
    ++** initially greater than zero, then decrement the value in register P1.
    ++** If it is non-zero (negative or positive) and then also jump to P2.  
    ++** If register P1 is initially zero, leave it unchanged and fall through.
    + */
    + case OP_IfNotZero: {        /* jump, in1 */
    +   pIn1 = &aMem[pOp->p1];
    +   assert( pIn1->flags&MEM_Int );
    +   VdbeBranchTaken(pIn1->u.i<0, 2);
    +   if( pIn1->u.i ){
    +-     pIn1->u.i -= pOp->p3;
    ++     if( pIn1->u.i>0 ) pIn1->u.i--;
    +      goto jump_to_p2;
    +   }
    +   break;
    +@@ -78630,34 +86134,19 @@ case OP_IfNotZero: {        /* jump, in1 */
    + /* Opcode: DecrJumpZero P1 P2 * * *
    + ** Synopsis: if (--r[P1])==0 goto P2
    + **
    +-** Register P1 must hold an integer.  Decrement the value in register P1
    +-** then jump to P2 if the new value is exactly zero.
    ++** Register P1 must hold an integer.  Decrement the value in P1
    ++** and jump to P2 if the new value is exactly zero.
    + */
    + case OP_DecrJumpZero: {      /* jump, in1 */
    +   pIn1 = &aMem[pOp->p1];
    +   assert( pIn1->flags&MEM_Int );
    +-  pIn1->u.i--;
    ++  if( pIn1->u.i>SMALLEST_INT64 ) pIn1->u.i--;
    +   VdbeBranchTaken(pIn1->u.i==0, 2);
    +   if( pIn1->u.i==0 ) goto jump_to_p2;
    +   break;
    + }
    + 
    + 
    +-/* Opcode: JumpZeroIncr P1 P2 * * *
    +-** Synopsis: if (r[P1]++)==0 ) goto P2
    +-**
    +-** The register P1 must contain an integer.  If register P1 is initially
    +-** zero, then jump to P2.  Increment register P1 regardless of whether or
    +-** not the jump is taken.
    +-*/
    +-case OP_JumpZeroIncr: {        /* jump, in1 */
    +-  pIn1 = &aMem[pOp->p1];
    +-  assert( pIn1->flags&MEM_Int );
    +-  VdbeBranchTaken(pIn1->u.i==0, 2);
    +-  if( (pIn1->u.i++)==0 ) goto jump_to_p2;
    +-  break;
    +-}
    +-
    + /* Opcode: AggStep0 * P2 P3 P4 P5
    + ** Synopsis: accum=r[P3] step(r[P2@P5])
    + **
    +@@ -78692,10 +86181,10 @@ case OP_AggStep0: {
    + 
    +   assert( pOp->p4type==P4_FUNCDEF );
    +   n = pOp->p5;
    +-  assert( pOp->p3>0 && pOp->p3<=(p->nMem-p->nCursor) );
    +-  assert( n==0 || (pOp->p2>0 && pOp->p2+n<=(p->nMem-p->nCursor)+1) );
    ++  assert( pOp->p3>0 && pOp->p3<=(p->nMem+1 - p->nCursor) );
    ++  assert( n==0 || (pOp->p2>0 && pOp->p2+n<=(p->nMem+1 - p->nCursor)+1) );
    +   assert( pOp->p3<pOp->p2 || pOp->p3>=pOp->p2+n );
    +-  pCtx = sqlite3DbMallocRaw(db, sizeof(*pCtx) + (n-1)*sizeof(sqlite3_value*));
    ++  pCtx = sqlite3DbMallocRawNN(db, sizeof(*pCtx) + (n-1)*sizeof(sqlite3_value*));
    +   if( pCtx==0 ) goto no_mem;
    +   pCtx->pMem = 0;
    +   pCtx->pFunc = pOp->p4.pFunc;
    +@@ -78738,13 +86227,14 @@ case OP_AggStep: {
    +   pCtx->pOut = &t;
    +   pCtx->fErrorOrAux = 0;
    +   pCtx->skipFlag = 0;
    +-  (pCtx->pFunc->xStep)(pCtx,pCtx->argc,pCtx->argv); /* IMP: R-24505-23230 */
    ++  (pCtx->pFunc->xSFunc)(pCtx,pCtx->argc,pCtx->argv); /* IMP: R-24505-23230 */
    +   if( pCtx->fErrorOrAux ){
    +     if( pCtx->isError ){
    +       sqlite3VdbeError(p, "%s", sqlite3_value_text(&t));
    +       rc = pCtx->isError;
    +     }
    +     sqlite3VdbeMemRelease(&t);
    ++    if( rc ) goto abort_due_to_error;
    +   }else{
    +     assert( t.flags==MEM_Null );
    +   }
    +@@ -78771,12 +86261,13 @@ case OP_AggStep: {
    + */
    + case OP_AggFinal: {
    +   Mem *pMem;
    +-  assert( pOp->p1>0 && pOp->p1<=(p->nMem-p->nCursor) );
    ++  assert( pOp->p1>0 && pOp->p1<=(p->nMem+1 - p->nCursor) );
    +   pMem = &aMem[pOp->p1];
    +   assert( (pMem->flags & ~(MEM_Null|MEM_Agg))==0 );
    +   rc = sqlite3VdbeMemFinalize(pMem, pOp->p4.pFunc);
    +   if( rc ){
    +     sqlite3VdbeError(p, "%s", sqlite3_value_text(pMem));
    ++    goto abort_due_to_error;
    +   }
    +   sqlite3VdbeChangeEncoding(pMem, encoding);
    +   UPDATE_MAX_BLOBSIZE(pMem);
    +@@ -78812,7 +86303,8 @@ case OP_Checkpoint: {
    +        || pOp->p2==SQLITE_CHECKPOINT_TRUNCATE
    +   );
    +   rc = sqlite3Checkpoint(db, pOp->p1, pOp->p2, &aRes[1], &aRes[2]);
    +-  if( rc==SQLITE_BUSY ){
    ++  if( rc ){
    ++    if( rc!=SQLITE_BUSY ) goto abort_due_to_error;
    +     rc = SQLITE_OK;
    +     aRes[0] = 1;
    +   }
    +@@ -78885,7 +86377,7 @@ case OP_JournalMode: {    /* out2 */
    +           "cannot change %s wal mode from within a transaction",
    +           (eNew==PAGER_JOURNALMODE_WAL ? "into" : "out of")
    +       );
    +-      break;
    ++      goto abort_due_to_error;
    +     }else{
    +  
    +       if( eOld==PAGER_JOURNALMODE_WAL ){
    +@@ -78894,7 +86386,7 @@ case OP_JournalMode: {    /* out2 */
    +         ** file. An EXCLUSIVE lock may still be held on the database file 
    +         ** after a successful return. 
    +         */
    +-        rc = sqlite3PagerCloseWal(pPager);
    ++        rc = sqlite3PagerCloseWal(pPager, db);
    +         if( rc==SQLITE_OK ){
    +           sqlite3PagerSetJournalMode(pPager, eNew);
    +         }
    +@@ -78915,9 +86407,7 @@ case OP_JournalMode: {    /* out2 */
    +   }
    + #endif /* ifndef SQLITE_OMIT_WAL */
    + 
    +-  if( rc ){
    +-    eNew = eOld;
    +-  }
    ++  if( rc ) eNew = eOld;
    +   eNew = sqlite3PagerSetJournalMode(pPager, eNew);
    + 
    +   pOut->flags = MEM_Str|MEM_Static|MEM_Term;
    +@@ -78925,20 +86415,21 @@ case OP_JournalMode: {    /* out2 */
    +   pOut->n = sqlite3Strlen30(pOut->z);
    +   pOut->enc = SQLITE_UTF8;
    +   sqlite3VdbeChangeEncoding(pOut, encoding);
    ++  if( rc ) goto abort_due_to_error;
    +   break;
    + };
    + #endif /* SQLITE_OMIT_PRAGMA */
    + 
    + #if !defined(SQLITE_OMIT_VACUUM) && !defined(SQLITE_OMIT_ATTACH)
    +-/* Opcode: Vacuum * * * * *
    ++/* Opcode: Vacuum P1 * * * *
    + **
    +-** Vacuum the entire database.  This opcode will cause other virtual
    +-** machines to be created and run.  It may not be called from within
    +-** a transaction.
    ++** Vacuum the entire database P1.  P1 is 0 for "main", and 2 or more
    ++** for an attached database.  The "temp" database may not be vacuumed.
    + */
    + case OP_Vacuum: {
    +   assert( p->readOnly==0 );
    +-  rc = sqlite3RunVacuum(&p->zErrMsg, db);
    ++  rc = sqlite3RunVacuum(&p->zErrMsg, db, pOp->p1);
    ++  if( rc ) goto abort_due_to_error;
    +   break;
    + }
    + #endif
    +@@ -78959,7 +86450,8 @@ case OP_IncrVacuum: {        /* jump */
    +   pBt = db->aDb[pOp->p1].pBt;
    +   rc = sqlite3BtreeIncrVacuum(pBt);
    +   VdbeBranchTaken(rc==SQLITE_DONE,2);
    +-  if( rc==SQLITE_DONE ){
    ++  if( rc ){
    ++    if( rc!=SQLITE_DONE ) goto abort_due_to_error;
    +     rc = SQLITE_OK;
    +     goto jump_to_p2;
    +   }
    +@@ -79004,15 +86496,18 @@ case OP_Expire: {
    + */
    + case OP_TableLock: {
    +   u8 isWriteLock = (u8)pOp->p3;
    +-  if( isWriteLock || 0==(db->flags&SQLITE_ReadUncommitted) ){
    ++  if( isWriteLock || 0==(db->flags&SQLITE_ReadUncommit) ){
    +     int p1 = pOp->p1; 
    +     assert( p1>=0 && p1<db->nDb );
    +     assert( DbMaskTest(p->btreeMask, p1) );
    +     assert( isWriteLock==0 || isWriteLock==1 );
    +     rc = sqlite3BtreeLockTable(db->aDb[p1].pBt, pOp->p2, isWriteLock);
    +-    if( (rc&0xFF)==SQLITE_LOCKED ){
    +-      const char *z = pOp->p4.z;
    +-      sqlite3VdbeError(p, "database table is locked: %s", z);
    ++    if( rc ){
    ++      if( (rc&0xFF)==SQLITE_LOCKED ){
    ++        const char *z = pOp->p4.z;
    ++        sqlite3VdbeError(p, "database table is locked: %s", z);
    ++      }
    ++      goto abort_due_to_error;
    +     }
    +   }
    +   break;
    +@@ -79034,6 +86529,7 @@ case OP_VBegin: {
    +   pVTab = pOp->p4.pVtab;
    +   rc = sqlite3VtabBegin(db, pVTab);
    +   if( pVTab ) sqlite3VtabImportErrmsg(p, pVTab->pVtab);
    ++  if( rc ) goto abort_due_to_error;
    +   break;
    + }
    + #endif /* SQLITE_OMIT_VIRTUALTABLE */
    +@@ -79062,6 +86558,7 @@ case OP_VCreate: {
    +     rc = sqlite3VtabCallCreate(db, pOp->p1, zTab, &p->zErrMsg);
    +   }
    +   sqlite3VdbeMemRelease(&sMem);
    ++  if( rc ) goto abort_due_to_error;
    +   break;
    + }
    + #endif /* SQLITE_OMIT_VIRTUALTABLE */
    +@@ -79076,6 +86573,7 @@ case OP_VDestroy: {
    +   db->nVDestroy++;
    +   rc = sqlite3VtabCallDestroy(db, pOp->p1, pOp->p4.z);
    +   db->nVDestroy--;
    ++  if( rc ) goto abort_due_to_error;
    +   break;
    + }
    + #endif /* SQLITE_OMIT_VIRTUALTABLE */
    +@@ -79089,35 +86587,35 @@ case OP_VDestroy: {
    + */
    + case OP_VOpen: {
    +   VdbeCursor *pCur;
    +-  sqlite3_vtab_cursor *pVtabCursor;
    ++  sqlite3_vtab_cursor *pVCur;
    +   sqlite3_vtab *pVtab;
    +   const sqlite3_module *pModule;
    + 
    +   assert( p->bIsReader );
    +   pCur = 0;
    +-  pVtabCursor = 0;
    ++  pVCur = 0;
    +   pVtab = pOp->p4.pVtab->pVtab;
    +   if( pVtab==0 || NEVER(pVtab->pModule==0) ){
    +     rc = SQLITE_LOCKED;
    +-    break;
    ++    goto abort_due_to_error;
    +   }
    +   pModule = pVtab->pModule;
    +-  rc = pModule->xOpen(pVtab, &pVtabCursor);
    ++  rc = pModule->xOpen(pVtab, &pVCur);
    +   sqlite3VtabImportErrmsg(p, pVtab);
    +-  if( SQLITE_OK==rc ){
    +-    /* Initialize sqlite3_vtab_cursor base class */
    +-    pVtabCursor->pVtab = pVtab;
    ++  if( rc ) goto abort_due_to_error;
    + 
    +-    /* Initialize vdbe cursor object */
    +-    pCur = allocateCursor(p, pOp->p1, 0, -1, 0);
    +-    if( pCur ){
    +-      pCur->pVtabCursor = pVtabCursor;
    +-      pVtab->nRef++;
    +-    }else{
    +-      assert( db->mallocFailed );
    +-      pModule->xClose(pVtabCursor);
    +-      goto no_mem;
    +-    }
    ++  /* Initialize sqlite3_vtab_cursor base class */
    ++  pVCur->pVtab = pVtab;
    ++
    ++  /* Initialize vdbe cursor object */
    ++  pCur = allocateCursor(p, pOp->p1, 0, -1, CURTYPE_VTAB);
    ++  if( pCur ){
    ++    pCur->uc.pVCur = pVCur;
    ++    pVtab->nRef++;
    ++  }else{
    ++    assert( db->mallocFailed );
    ++    pModule->xClose(pVCur);
    ++    goto no_mem;
    +   }
    +   break;
    + }
    +@@ -79149,7 +86647,7 @@ case OP_VFilter: {   /* jump */
    +   const sqlite3_module *pModule;
    +   Mem *pQuery;
    +   Mem *pArgc;
    +-  sqlite3_vtab_cursor *pVtabCursor;
    ++  sqlite3_vtab_cursor *pVCur;
    +   sqlite3_vtab *pVtab;
    +   VdbeCursor *pCur;
    +   int res;
    +@@ -79161,9 +86659,9 @@ case OP_VFilter: {   /* jump */
    +   pCur = p->apCsr[pOp->p1];
    +   assert( memIsValid(pQuery) );
    +   REGISTER_TRACE(pOp->p3, pQuery);
    +-  assert( pCur->pVtabCursor );
    +-  pVtabCursor = pCur->pVtabCursor;
    +-  pVtab = pVtabCursor->pVtab;
    ++  assert( pCur->eCurType==CURTYPE_VTAB );
    ++  pVCur = pCur->uc.pVCur;
    ++  pVtab = pVCur->pVtab;
    +   pModule = pVtab->pModule;
    + 
    +   /* Grab the index number and argc parameters */
    +@@ -79177,11 +86675,10 @@ case OP_VFilter: {   /* jump */
    +   for(i = 0; i<nArg; i++){
    +     apArg[i] = &pArgc[i+1];
    +   }
    +-  rc = pModule->xFilter(pVtabCursor, iQuery, pOp->p4.z, nArg, apArg);
    ++  rc = pModule->xFilter(pVCur, iQuery, pOp->p4.z, nArg, apArg);
    +   sqlite3VtabImportErrmsg(p, pVtab);
    +-  if( rc==SQLITE_OK ){
    +-    res = pModule->xEof(pVtabCursor);
    +-  }
    ++  if( rc ) goto abort_due_to_error;
    ++  res = pModule->xEof(pVCur);
    +   pCur->nullRow = 0;
    +   VdbeBranchTaken(res!=0,2);
    +   if( res ) goto jump_to_p2;
    +@@ -79190,12 +86687,18 @@ case OP_VFilter: {   /* jump */
    + #endif /* SQLITE_OMIT_VIRTUALTABLE */
    + 
    + #ifndef SQLITE_OMIT_VIRTUALTABLE
    +-/* Opcode: VColumn P1 P2 P3 * *
    ++/* Opcode: VColumn P1 P2 P3 * P5
    + ** Synopsis: r[P3]=vcolumn(P2)
    + **
    +-** Store the value of the P2-th column of
    +-** the row of the virtual-table that the 
    +-** P1 cursor is pointing to into register P3.
    ++** Store in register P3 the value of the P2-th column of
    ++** the current row of the virtual-table of cursor P1.
    ++**
    ++** If the VColumn opcode is being used to fetch the value of
    ++** an unchanging column during an UPDATE operation, then the P5
    ++** value is 1.  Otherwise, P5 is 0.  The P5 value is returned
    ++** by sqlite3_vtab_nochange() routine can can be used
    ++** by virtual table implementations to return special "no-change"
    ++** marks which can be more efficient, depending on the virtual table.
    + */
    + case OP_VColumn: {
    +   sqlite3_vtab *pVtab;
    +@@ -79204,21 +86707,27 @@ case OP_VColumn: {
    +   sqlite3_context sContext;
    + 
    +   VdbeCursor *pCur = p->apCsr[pOp->p1];
    +-  assert( pCur->pVtabCursor );
    +-  assert( pOp->p3>0 && pOp->p3<=(p->nMem-p->nCursor) );
    ++  assert( pCur->eCurType==CURTYPE_VTAB );
    ++  assert( pOp->p3>0 && pOp->p3<=(p->nMem+1 - p->nCursor) );
    +   pDest = &aMem[pOp->p3];
    +   memAboutToChange(p, pDest);
    +   if( pCur->nullRow ){
    +     sqlite3VdbeMemSetNull(pDest);
    +     break;
    +   }
    +-  pVtab = pCur->pVtabCursor->pVtab;
    ++  pVtab = pCur->uc.pVCur->pVtab;
    +   pModule = pVtab->pModule;
    +   assert( pModule->xColumn );
    +   memset(&sContext, 0, sizeof(sContext));
    +   sContext.pOut = pDest;
    +-  MemSetTypeFlag(pDest, MEM_Null);
    +-  rc = pModule->xColumn(pCur->pVtabCursor, &sContext, pOp->p2);
    ++  if( pOp->p5 ){
    ++    sqlite3VdbeMemSetNull(pDest);
    ++    pDest->flags = MEM_Null|MEM_Zero;
    ++    pDest->u.nZero = 0;
    ++  }else{
    ++    MemSetTypeFlag(pDest, MEM_Null);
    ++  }
    ++  rc = pModule->xColumn(pCur->uc.pVCur, &sContext, pOp->p2);
    +   sqlite3VtabImportErrmsg(p, pVtab);
    +   if( sContext.isError ){
    +     rc = sContext.isError;
    +@@ -79230,6 +86739,7 @@ case OP_VColumn: {
    +   if( sqlite3VdbeMemTooBig(pDest) ){
    +     goto too_big;
    +   }
    ++  if( rc ) goto abort_due_to_error;
    +   break;
    + }
    + #endif /* SQLITE_OMIT_VIRTUALTABLE */
    +@@ -79249,11 +86759,11 @@ case OP_VNext: {   /* jump */
    + 
    +   res = 0;
    +   pCur = p->apCsr[pOp->p1];
    +-  assert( pCur->pVtabCursor );
    ++  assert( pCur->eCurType==CURTYPE_VTAB );
    +   if( pCur->nullRow ){
    +     break;
    +   }
    +-  pVtab = pCur->pVtabCursor->pVtab;
    ++  pVtab = pCur->uc.pVCur->pVtab;
    +   pModule = pVtab->pModule;
    +   assert( pModule->xNext );
    + 
    +@@ -79263,11 +86773,10 @@ case OP_VNext: {   /* jump */
    +   ** data is available) and the error code returned when xColumn or
    +   ** some other method is next invoked on the save virtual table cursor.
    +   */
    +-  rc = pModule->xNext(pCur->pVtabCursor);
    ++  rc = pModule->xNext(pCur->uc.pVCur);
    +   sqlite3VtabImportErrmsg(p, pVtab);
    +-  if( rc==SQLITE_OK ){
    +-    res = pModule->xEof(pCur->pVtabCursor);
    +-  }
    ++  if( rc ) goto abort_due_to_error;
    ++  res = pModule->xEof(pCur->uc.pVCur);
    +   VdbeBranchTaken(!res,2);
    +   if( !res ){
    +     /* If there is data, jump to P2 */
    +@@ -79299,11 +86808,11 @@ case OP_VRename: {
    +   testcase( pName->enc==SQLITE_UTF16BE );
    +   testcase( pName->enc==SQLITE_UTF16LE );
    +   rc = sqlite3VdbeChangeEncoding(pName, SQLITE_UTF8);
    +-  if( rc==SQLITE_OK ){
    +-    rc = pVtab->pModule->xRename(pVtab, pName->z);
    +-    sqlite3VtabImportErrmsg(p, pVtab);
    +-    p->expired = 0;
    +-  }
    ++  if( rc ) goto abort_due_to_error;
    ++  rc = pVtab->pModule->xRename(pVtab, pName->z);
    ++  sqlite3VtabImportErrmsg(p, pVtab);
    ++  p->expired = 0;
    ++  if( rc ) goto abort_due_to_error;
    +   break;
    + }
    + #endif
    +@@ -79352,7 +86861,7 @@ case OP_VUpdate: {
    +   pVtab = pOp->p4.pVtab->pVtab;
    +   if( pVtab==0 || NEVER(pVtab->pModule==0) ){
    +     rc = SQLITE_LOCKED;
    +-    break;
    ++    goto abort_due_to_error;
    +   }
    +   pModule = pVtab->pModule;
    +   nArg = pOp->p2;
    +@@ -79373,7 +86882,7 @@ case OP_VUpdate: {
    +     sqlite3VtabImportErrmsg(p, pVtab);
    +     if( rc==SQLITE_OK && pOp->p1 ){
    +       assert( nArg>1 && apArg[0] && (apArg[0]->flags&MEM_Null) );
    +-      db->lastRowid = lastRowid = rowid;
    ++      db->lastRowid = rowid;
    +     }
    +     if( (rc&0xff)==SQLITE_CONSTRAINT && pOp->p4.pVtab->bConstraint ){
    +       if( pOp->p5==OE_Ignore ){
    +@@ -79384,6 +86893,7 @@ case OP_VUpdate: {
    +     }else{
    +       p->nChange++;
    +     }
    ++    if( rc ) goto abort_due_to_error;
    +   }
    +   break;
    + }
    +@@ -79427,9 +86937,130 @@ case OP_MaxPgcnt: {            /* out2 */
    + }
    + #endif
    + 
    ++/* Opcode: Function0 P1 P2 P3 P4 P5
    ++** Synopsis: r[P3]=func(r[P2@P5])
    ++**
    ++** Invoke a user function (P4 is a pointer to a FuncDef object that
    ++** defines the function) with P5 arguments taken from register P2 and
    ++** successors.  The result of the function is stored in register P3.
    ++** Register P3 must not be one of the function inputs.
    ++**
    ++** P1 is a 32-bit bitmask indicating whether or not each argument to the 
    ++** function was determined to be constant at compile time. If the first
    ++** argument was constant then bit 0 of P1 is set. This is used to determine
    ++** whether meta data associated with a user function argument using the
    ++** sqlite3_set_auxdata() API may be safely retained until the next
    ++** invocation of this opcode.
    ++**
    ++** See also: Function, AggStep, AggFinal
    ++*/
    ++/* Opcode: Function P1 P2 P3 P4 P5
    ++** Synopsis: r[P3]=func(r[P2@P5])
    ++**
    ++** Invoke a user function (P4 is a pointer to an sqlite3_context object that
    ++** contains a pointer to the function to be run) with P5 arguments taken
    ++** from register P2 and successors.  The result of the function is stored
    ++** in register P3.  Register P3 must not be one of the function inputs.
    ++**
    ++** P1 is a 32-bit bitmask indicating whether or not each argument to the 
    ++** function was determined to be constant at compile time. If the first
    ++** argument was constant then bit 0 of P1 is set. This is used to determine
    ++** whether meta data associated with a user function argument using the
    ++** sqlite3_set_auxdata() API may be safely retained until the next
    ++** invocation of this opcode.
    ++**
    ++** SQL functions are initially coded as OP_Function0 with P4 pointing
    ++** to a FuncDef object.  But on first evaluation, the P4 operand is
    ++** automatically converted into an sqlite3_context object and the operation
    ++** changed to this OP_Function opcode.  In this way, the initialization of
    ++** the sqlite3_context object occurs only once, rather than once for each
    ++** evaluation of the function.
    ++**
    ++** See also: Function0, AggStep, AggFinal
    ++*/
    ++case OP_PureFunc0:
    ++case OP_Function0: {
    ++  int n;
    ++  sqlite3_context *pCtx;
    ++
    ++  assert( pOp->p4type==P4_FUNCDEF );
    ++  n = pOp->p5;
    ++  assert( pOp->p3>0 && pOp->p3<=(p->nMem+1 - p->nCursor) );
    ++  assert( n==0 || (pOp->p2>0 && pOp->p2+n<=(p->nMem+1 - p->nCursor)+1) );
    ++  assert( pOp->p3<pOp->p2 || pOp->p3>=pOp->p2+n );
    ++  pCtx = sqlite3DbMallocRawNN(db, sizeof(*pCtx) + (n-1)*sizeof(sqlite3_value*));
    ++  if( pCtx==0 ) goto no_mem;
    ++  pCtx->pOut = 0;
    ++  pCtx->pFunc = pOp->p4.pFunc;
    ++  pCtx->iOp = (int)(pOp - aOp);
    ++  pCtx->pVdbe = p;
    ++  pCtx->argc = n;
    ++  pOp->p4type = P4_FUNCCTX;
    ++  pOp->p4.pCtx = pCtx;
    ++  assert( OP_PureFunc == OP_PureFunc0+2 );
    ++  assert( OP_Function == OP_Function0+2 );
    ++  pOp->opcode += 2;
    ++  /* Fall through into OP_Function */
    ++}
    ++case OP_PureFunc:
    ++case OP_Function: {
    ++  int i;
    ++  sqlite3_context *pCtx;
    ++
    ++  assert( pOp->p4type==P4_FUNCCTX );
    ++  pCtx = pOp->p4.pCtx;
    ++
    ++  /* If this function is inside of a trigger, the register array in aMem[]
    ++  ** might change from one evaluation to the next.  The next block of code
    ++  ** checks to see if the register array has changed, and if so it
    ++  ** reinitializes the relavant parts of the sqlite3_context object */
    ++  pOut = &aMem[pOp->p3];
    ++  if( pCtx->pOut != pOut ){
    ++    pCtx->pOut = pOut;
    ++    for(i=pCtx->argc-1; i>=0; i--) pCtx->argv[i] = &aMem[pOp->p2+i];
    ++  }
    ++
    ++  memAboutToChange(p, pOut);
    ++#ifdef SQLITE_DEBUG
    ++  for(i=0; i<pCtx->argc; i++){
    ++    assert( memIsValid(pCtx->argv[i]) );
    ++    REGISTER_TRACE(pOp->p2+i, pCtx->argv[i]);
    ++  }
    ++#endif
    ++  MemSetTypeFlag(pOut, MEM_Null);
    ++  pCtx->fErrorOrAux = 0;
    ++  (*pCtx->pFunc->xSFunc)(pCtx, pCtx->argc, pCtx->argv);/* IMP: R-24505-23230 */
    ++
    ++  /* If the function returned an error, throw an exception */
    ++  if( pCtx->fErrorOrAux ){
    ++    if( pCtx->isError ){
    ++      sqlite3VdbeError(p, "%s", sqlite3_value_text(pOut));
    ++      rc = pCtx->isError;
    ++    }
    ++    sqlite3VdbeDeleteAuxData(db, &p->pAuxData, pCtx->iOp, pOp->p1);
    ++    if( rc ) goto abort_due_to_error;
    ++  }
    ++
    ++  /* Copy the result of the function into register P3 */
    ++  if( pOut->flags & (MEM_Str|MEM_Blob) ){
    ++    sqlite3VdbeChangeEncoding(pOut, encoding);
    ++    if( sqlite3VdbeMemTooBig(pOut) ) goto too_big;
    ++  }
    + 
    +-/* Opcode: Init * P2 * P4 *
    +-** Synopsis:  Start at P2
    ++  REGISTER_TRACE(pOp->p3, pOut);
    ++  UPDATE_MAX_BLOBSIZE(pOut);
    ++  break;
    ++}
    ++
    ++/* Opcode: Trace P1 P2 * P4 *
    ++**
    ++** Write P4 on the statement trace output if statement tracing is
    ++** enabled.
    ++**
    ++** Operand P1 must be 0x7fffffff and P2 must positive.
    ++*/
    ++/* Opcode: Init P1 P2 P3 P4 *
    ++** Synopsis: Start at P2
    + **
    + ** Programs contain a single instance of this opcode as the very first
    + ** opcode.
    +@@ -79439,27 +87070,60 @@ case OP_MaxPgcnt: {            /* out2 */
    + ** Or if P4 is blank, use the string returned by sqlite3_sql().
    + **
    + ** If P2 is not zero, jump to instruction P2.
    ++**
    ++** Increment the value of P1 so that OP_Once opcodes will jump the
    ++** first time they are evaluated for this run.
    ++**
    ++** If P3 is not zero, then it is an address to jump to if an SQLITE_CORRUPT
    ++** error is encountered.
    + */
    ++case OP_Trace:
    + case OP_Init: {          /* jump */
    +   char *zTrace;
    +-  char *z;
    ++  int i;
    ++
    ++  /* If the P4 argument is not NULL, then it must be an SQL comment string.
    ++  ** The "--" string is broken up to prevent false-positives with srcck1.c.
    ++  **
    ++  ** This assert() provides evidence for:
    ++  ** EVIDENCE-OF: R-50676-09860 The callback can compute the same text that
    ++  ** would have been returned by the legacy sqlite3_trace() interface by
    ++  ** using the X argument when X begins with "--" and invoking
    ++  ** sqlite3_expanded_sql(P) otherwise.
    ++  */
    ++  assert( pOp->p4.z==0 || strncmp(pOp->p4.z, "-" "- ", 3)==0 );
    ++
    ++  /* OP_Init is always instruction 0 */
    ++  assert( pOp==p->aOp || pOp->opcode==OP_Trace );
    + 
    + #ifndef SQLITE_OMIT_TRACE
    +-  if( db->xTrace
    ++  if( (db->mTrace & (SQLITE_TRACE_STMT|SQLITE_TRACE_LEGACY))!=0
    +    && !p->doingRerun
    +    && (zTrace = (pOp->p4.z ? pOp->p4.z : p->zSql))!=0
    +   ){
    +-    z = sqlite3VdbeExpandSql(p, zTrace);
    +-    db->xTrace(db->pTraceArg, z);
    +-    sqlite3DbFree(db, z);
    ++#ifndef SQLITE_OMIT_DEPRECATED
    ++    if( db->mTrace & SQLITE_TRACE_LEGACY ){
    ++      void (*x)(void*,const char*) = (void(*)(void*,const char*))db->xTrace;
    ++      char *z = sqlite3VdbeExpandSql(p, zTrace);
    ++      x(db->pTraceArg, z);
    ++      sqlite3_free(z);
    ++    }else
    ++#endif
    ++    if( db->nVdbeExec>1 ){
    ++      char *z = sqlite3MPrintf(db, "-- %s", zTrace);
    ++      (void)db->xTrace(SQLITE_TRACE_STMT, db->pTraceArg, p, z);
    ++      sqlite3DbFree(db, z);
    ++    }else{
    ++      (void)db->xTrace(SQLITE_TRACE_STMT, db->pTraceArg, p, zTrace);
    ++    }
    +   }
    + #ifdef SQLITE_USE_FCNTL_TRACE
    +   zTrace = (pOp->p4.z ? pOp->p4.z : p->zSql);
    +   if( zTrace ){
    +-    int i;
    +-    for(i=0; i<db->nDb; i++){
    +-      if( DbMaskTest(p->btreeMask, i)==0 ) continue;
    +-      sqlite3_file_control(db, db->aDb[i].zName, SQLITE_FCNTL_TRACE, zTrace);
    ++    int j;
    ++    for(j=0; j<db->nDb; j++){
    ++      if( DbMaskTest(p->btreeMask, j)==0 ) continue;
    ++      sqlite3_file_control(db, db->aDb[j].zDbSName, SQLITE_FCNTL_TRACE, zTrace);
    +     }
    +   }
    + #endif /* SQLITE_USE_FCNTL_TRACE */
    +@@ -79471,10 +87135,41 @@ case OP_Init: {          /* jump */
    +   }
    + #endif /* SQLITE_DEBUG */
    + #endif /* SQLITE_OMIT_TRACE */
    +-  if( pOp->p2 ) goto jump_to_p2;
    +-  break;
    ++  assert( pOp->p2>0 );
    ++  if( pOp->p1>=sqlite3GlobalConfig.iOnceResetThreshold ){
    ++    if( pOp->opcode==OP_Trace ) break;
    ++    for(i=1; i<p->nOp; i++){
    ++      if( p->aOp[i].opcode==OP_Once ) p->aOp[i].p1 = 0;
    ++    }
    ++    pOp->p1 = 0;
    ++  }
    ++  pOp->p1++;
    ++  p->aCounter[SQLITE_STMTSTATUS_RUN]++;
    ++  goto jump_to_p2;
    + }
    + 
    ++#ifdef SQLITE_ENABLE_CURSOR_HINTS
    ++/* Opcode: CursorHint P1 * * P4 *
    ++**
    ++** Provide a hint to cursor P1 that it only needs to return rows that
    ++** satisfy the Expr in P4.  TK_REGISTER terms in the P4 expression refer
    ++** to values currently held in registers.  TK_COLUMN terms in the P4
    ++** expression refer to columns in the b-tree to which cursor P1 is pointing.
    ++*/
    ++case OP_CursorHint: {
    ++  VdbeCursor *pC;
    ++
    ++  assert( pOp->p1>=0 && pOp->p1<p->nCursor );
    ++  assert( pOp->p4type==P4_EXPR );
    ++  pC = p->apCsr[pOp->p1];
    ++  if( pC ){
    ++    assert( pC->eCurType==CURTYPE_BTREE );
    ++    sqlite3BtreeCursorHint(pC->uc.pCursor, BTREE_HINT_RANGE,
    ++                           pOp->p4.pExpr, aMem);
    ++  }
    ++  break;
    ++}
    ++#endif /* SQLITE_ENABLE_CURSOR_HINTS */
    + 
    + /* Opcode: Noop * * * * *
    + **
    +@@ -79518,11 +87213,12 @@ default: {          /* This is really OP_Noop and OP_Explain */
    + 
    + #ifdef SQLITE_DEBUG
    +     if( db->flags & SQLITE_VdbeTrace ){
    ++      u8 opProperty = sqlite3OpcodeProperty[pOrigOp->opcode];
    +       if( rc!=0 ) printf("rc=%d\n",rc);
    +-      if( pOrigOp->opflags & (OPFLG_OUT2) ){
    ++      if( opProperty & (OPFLG_OUT2) ){
    +         registerTrace(pOrigOp->p2, &aMem[pOrigOp->p2]);
    +       }
    +-      if( pOrigOp->opflags & OPFLG_OUT3 ){
    ++      if( opProperty & OPFLG_OUT3 ){
    +         registerTrace(pOrigOp->p3, &aMem[pOrigOp->p3]);
    +       }
    +     }
    +@@ -79533,14 +87229,19 @@ default: {          /* This is really OP_Noop and OP_Explain */
    +   /* If we reach this point, it means that execution is finished with
    +   ** an error of some kind.
    +   */
    +-vdbe_error_halt:
    ++abort_due_to_error:
    ++  if( db->mallocFailed ) rc = SQLITE_NOMEM_BKPT;
    +   assert( rc );
    ++  if( p->zErrMsg==0 && rc!=SQLITE_IOERR_NOMEM ){
    ++    sqlite3VdbeError(p, "%s", sqlite3ErrStr(rc));
    ++  }
    +   p->rc = rc;
    ++  sqlite3SystemError(db, rc);
    +   testcase( sqlite3GlobalConfig.xLog!=0 );
    +   sqlite3_log(rc, "statement aborts at %d: [%s] %s", 
    +                    (int)(pOp - aOp), p->zSql, p->zErrMsg);
    +   sqlite3VdbeHalt(p);
    +-  if( rc==SQLITE_IOERR_NOMEM ) db->mallocFailed = 1;
    ++  if( rc==SQLITE_IOERR_NOMEM ) sqlite3OomFault(db);
    +   rc = SQLITE_ERROR;
    +   if( resetSchemaOnFault>0 ){
    +     sqlite3ResetOneSchema(db, resetSchemaOnFault-1);
    +@@ -79550,10 +87251,12 @@ vdbe_error_halt:
    +   ** release the mutexes on btrees that were acquired at the
    +   ** top. */
    + vdbe_return:
    +-  db->lastRowid = lastRowid;
    +   testcase( nVmStep>0 );
    +   p->aCounter[SQLITE_STMTSTATUS_VM_STEP] += (int)nVmStep;
    +   sqlite3VdbeLeave(p);
    ++  assert( rc!=SQLITE_OK || nExtraDelete==0 
    ++       || sqlite3_strlike("DELETE%",p->zSql,0)!=0 
    ++  );
    +   return rc;
    + 
    +   /* Jump to here if a string or blob larger than SQLITE_MAX_LENGTH
    +@@ -79562,36 +87265,25 @@ vdbe_return:
    + too_big:
    +   sqlite3VdbeError(p, "string or blob too big");
    +   rc = SQLITE_TOOBIG;
    +-  goto vdbe_error_halt;
    ++  goto abort_due_to_error;
    + 
    +   /* Jump to here if a malloc() fails.
    +   */
    + no_mem:
    +-  db->mallocFailed = 1;
    ++  sqlite3OomFault(db);
    +   sqlite3VdbeError(p, "out of memory");
    +-  rc = SQLITE_NOMEM;
    +-  goto vdbe_error_halt;
    +-
    +-  /* Jump to here for any other kind of fatal error.  The "rc" variable
    +-  ** should hold the error number.
    +-  */
    +-abort_due_to_error:
    +-  assert( p->zErrMsg==0 );
    +-  if( db->mallocFailed ) rc = SQLITE_NOMEM;
    +-  if( rc!=SQLITE_IOERR_NOMEM ){
    +-    sqlite3VdbeError(p, "%s", sqlite3ErrStr(rc));
    +-  }
    +-  goto vdbe_error_halt;
    ++  rc = SQLITE_NOMEM_BKPT;
    ++  goto abort_due_to_error;
    + 
    +   /* Jump to here if the sqlite3_interrupt() API sets the interrupt
    +   ** flag.
    +   */
    + abort_due_to_interrupt:
    +   assert( db->u1.isInterrupted );
    +-  rc = SQLITE_INTERRUPT;
    ++  rc = db->mallocFailed ? SQLITE_NOMEM_BKPT : SQLITE_INTERRUPT;
    +   p->rc = rc;
    +   sqlite3VdbeError(p, "%s", sqlite3ErrStr(rc));
    +-  goto vdbe_error_halt;
    ++  goto abort_due_to_error;
    + }
    + 
    + 
    +@@ -79622,13 +87314,14 @@ abort_due_to_interrupt:
    + */
    + typedef struct Incrblob Incrblob;
    + struct Incrblob {
    +-  int flags;              /* Copy of "flags" passed to sqlite3_blob_open() */
    +   int nByte;              /* Size of open blob, in bytes */
    +   int iOffset;            /* Byte offset of blob in cursor data */
    +-  int iCol;               /* Table column this handle is open on */
    ++  u16 iCol;               /* Table column this handle is open on */
    +   BtCursor *pCsr;         /* Cursor pointing at blob row */
    +   sqlite3_stmt *pStmt;    /* Statement holding cursor open */
    +   sqlite3 *db;            /* The associated database */
    ++  char *zDb;              /* Database name */
    ++  Table *pTab;            /* Table object */
    + };
    + 
    + 
    +@@ -79654,17 +87347,28 @@ static int blobSeekToRow(Incrblob *p, sqlite3_int64 iRow, char **pzErr){
    +   char *zErr = 0;                 /* Error message */
    +   Vdbe *v = (Vdbe *)p->pStmt;
    + 
    +-  /* Set the value of the SQL statements only variable to integer iRow. 
    +-  ** This is done directly instead of using sqlite3_bind_int64() to avoid 
    +-  ** triggering asserts related to mutexes.
    ++  /* Set the value of register r[1] in the SQL statement to integer iRow. 
    ++  ** This is done directly as a performance optimization
    +   */
    +-  assert( v->aVar[0].flags&MEM_Int );
    +-  v->aVar[0].u.i = iRow;
    ++  v->aMem[1].flags = MEM_Int;
    ++  v->aMem[1].u.i = iRow;
    + 
    +-  rc = sqlite3_step(p->pStmt);
    ++  /* If the statement has been run before (and is paused at the OP_ResultRow)
    ++  ** then back it up to the point where it does the OP_NotExists.  This could
    ++  ** have been down with an extra OP_Goto, but simply setting the program
    ++  ** counter is faster. */
    ++  if( v->pc>4 ){
    ++    v->pc = 4;
    ++    assert( v->aOp[v->pc].opcode==OP_NotExists );
    ++    rc = sqlite3VdbeExec(v);
    ++  }else{
    ++    rc = sqlite3_step(p->pStmt);
    ++  }
    +   if( rc==SQLITE_ROW ){
    +     VdbeCursor *pC = v->apCsr[0];
    +-    u32 type = pC->aType[p->iCol];
    ++    u32 type = pC->nHdrParsed>p->iCol ? pC->aType[p->iCol] : 0;
    ++    testcase( pC->nHdrParsed==p->iCol );
    ++    testcase( pC->nHdrParsed==p->iCol+1 );
    +     if( type<12 ){
    +       zErr = sqlite3MPrintf(p->db, "cannot open value of type %s",
    +           type==0?"null": type==7?"real": "integer"
    +@@ -79675,7 +87379,7 @@ static int blobSeekToRow(Incrblob *p, sqlite3_int64 iRow, char **pzErr){
    +     }else{
    +       p->iOffset = pC->aType[p->iCol + pC->nField];
    +       p->nByte = sqlite3VdbeSerialTypeLen(type);
    +-      p->pCsr =  pC->pCursor;
    ++      p->pCsr =  pC->uc.pCursor;
    +       sqlite3BtreeIncrblobCursor(p->pCsr);
    +     }
    +   }
    +@@ -79703,54 +87407,22 @@ static int blobSeekToRow(Incrblob *p, sqlite3_int64 iRow, char **pzErr){
    + /*
    + ** Open a blob handle.
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_blob_open(
    ++SQLITE_API int sqlite3_blob_open(
    +   sqlite3* db,            /* The database connection */
    +   const char *zDb,        /* The attached database containing the blob */
    +   const char *zTable,     /* The table containing the blob */
    +   const char *zColumn,    /* The column containing the blob */
    +   sqlite_int64 iRow,      /* The row containing the glob */
    +-  int flags,              /* True -> read/write access, false -> read-only */
    ++  int wrFlag,             /* True -> read/write access, false -> read-only */
    +   sqlite3_blob **ppBlob   /* Handle for accessing the blob returned here */
    + ){
    +   int nAttempt = 0;
    +   int iCol;               /* Index of zColumn in row-record */
    +-
    +-  /* This VDBE program seeks a btree cursor to the identified 
    +-  ** db/table/row entry. The reason for using a vdbe program instead
    +-  ** of writing code to use the b-tree layer directly is that the
    +-  ** vdbe program will take advantage of the various transaction,
    +-  ** locking and error handling infrastructure built into the vdbe.
    +-  **
    +-  ** After seeking the cursor, the vdbe executes an OP_ResultRow.
    +-  ** Code external to the Vdbe then "borrows" the b-tree cursor and
    +-  ** uses it to implement the blob_read(), blob_write() and 
    +-  ** blob_bytes() functions.
    +-  **
    +-  ** The sqlite3_blob_close() function finalizes the vdbe program,
    +-  ** which closes the b-tree cursor and (possibly) commits the 
    +-  ** transaction.
    +-  */
    +-  static const int iLn = VDBE_OFFSET_LINENO(4);
    +-  static const VdbeOpList openBlob[] = {
    +-    /* {OP_Transaction, 0, 0, 0},  // 0: Inserted separately */
    +-    {OP_TableLock, 0, 0, 0},       /* 1: Acquire a read or write lock */
    +-    /* One of the following two instructions is replaced by an OP_Noop. */
    +-    {OP_OpenRead, 0, 0, 0},        /* 2: Open cursor 0 for reading */
    +-    {OP_OpenWrite, 0, 0, 0},       /* 3: Open cursor 0 for read/write */
    +-    {OP_Variable, 1, 1, 1},        /* 4: Push the rowid to the stack */
    +-    {OP_NotExists, 0, 10, 1},      /* 5: Seek the cursor */
    +-    {OP_Column, 0, 0, 1},          /* 6  */
    +-    {OP_ResultRow, 1, 0, 0},       /* 7  */
    +-    {OP_Goto, 0, 4, 0},            /* 8  */
    +-    {OP_Close, 0, 0, 0},           /* 9  */
    +-    {OP_Halt, 0, 0, 0},            /* 10 */
    +-  };
    +-
    +   int rc = SQLITE_OK;
    +   char *zErr = 0;
    +   Table *pTab;
    +-  Parse *pParse = 0;
    +   Incrblob *pBlob = 0;
    ++  Parse sParse;
    + 
    + #ifdef SQLITE_ENABLE_API_ARMOR
    +   if( ppBlob==0 ){
    +@@ -79763,47 +87435,46 @@ SQLITE_API int SQLITE_STDCALL sqlite3_blob_open(
    +     return SQLITE_MISUSE_BKPT;
    +   }
    + #endif
    +-  flags = !!flags;                /* flags = (flags ? 1 : 0); */
    ++  wrFlag = !!wrFlag;                /* wrFlag = (wrFlag ? 1 : 0); */
    + 
    +   sqlite3_mutex_enter(db->mutex);
    + 
    +   pBlob = (Incrblob *)sqlite3DbMallocZero(db, sizeof(Incrblob));
    +-  if( !pBlob ) goto blob_open_out;
    +-  pParse = sqlite3StackAllocRaw(db, sizeof(*pParse));
    +-  if( !pParse ) goto blob_open_out;
    +-
    +   do {
    +-    memset(pParse, 0, sizeof(Parse));
    +-    pParse->db = db;
    ++    memset(&sParse, 0, sizeof(Parse));
    ++    if( !pBlob ) goto blob_open_out;
    ++    sParse.db = db;
    +     sqlite3DbFree(db, zErr);
    +     zErr = 0;
    + 
    +     sqlite3BtreeEnterAll(db);
    +-    pTab = sqlite3LocateTable(pParse, 0, zTable, zDb);
    ++    pTab = sqlite3LocateTable(&sParse, 0, zTable, zDb);
    +     if( pTab && IsVirtual(pTab) ){
    +       pTab = 0;
    +-      sqlite3ErrorMsg(pParse, "cannot open virtual table: %s", zTable);
    ++      sqlite3ErrorMsg(&sParse, "cannot open virtual table: %s", zTable);
    +     }
    +     if( pTab && !HasRowid(pTab) ){
    +       pTab = 0;
    +-      sqlite3ErrorMsg(pParse, "cannot open table without rowid: %s", zTable);
    ++      sqlite3ErrorMsg(&sParse, "cannot open table without rowid: %s", zTable);
    +     }
    + #ifndef SQLITE_OMIT_VIEW
    +     if( pTab && pTab->pSelect ){
    +       pTab = 0;
    +-      sqlite3ErrorMsg(pParse, "cannot open view: %s", zTable);
    ++      sqlite3ErrorMsg(&sParse, "cannot open view: %s", zTable);
    +     }
    + #endif
    +     if( !pTab ){
    +-      if( pParse->zErrMsg ){
    ++      if( sParse.zErrMsg ){
    +         sqlite3DbFree(db, zErr);
    +-        zErr = pParse->zErrMsg;
    +-        pParse->zErrMsg = 0;
    ++        zErr = sParse.zErrMsg;
    ++        sParse.zErrMsg = 0;
    +       }
    +       rc = SQLITE_ERROR;
    +       sqlite3BtreeLeaveAll(db);
    +       goto blob_open_out;
    +     }
    ++    pBlob->pTab = pTab;
    ++    pBlob->zDb = db->aDb[sqlite3SchemaToIndex(db, pTab->pSchema)].zDbSName;
    + 
    +     /* Now search pTab for the exact column. */
    +     for(iCol=0; iCol<pTab->nCol; iCol++) {
    +@@ -79821,9 +87492,8 @@ SQLITE_API int SQLITE_STDCALL sqlite3_blob_open(
    + 
    +     /* If the value is being opened for writing, check that the
    +     ** column is not indexed, and that it is not part of a foreign key. 
    +-    ** It is against the rules to open a column to which either of these
    +-    ** descriptions applies for writing.  */
    +-    if( flags ){
    ++    */
    ++    if( wrFlag ){
    +       const char *zFault = 0;
    +       Index *pIdx;
    + #ifndef SQLITE_OMIT_FOREIGN_KEY
    +@@ -79861,63 +87531,93 @@ SQLITE_API int SQLITE_STDCALL sqlite3_blob_open(
    +       }
    +     }
    + 
    +-    pBlob->pStmt = (sqlite3_stmt *)sqlite3VdbeCreate(pParse);
    ++    pBlob->pStmt = (sqlite3_stmt *)sqlite3VdbeCreate(&sParse);
    +     assert( pBlob->pStmt || db->mallocFailed );
    +     if( pBlob->pStmt ){
    ++      
    ++      /* This VDBE program seeks a btree cursor to the identified 
    ++      ** db/table/row entry. The reason for using a vdbe program instead
    ++      ** of writing code to use the b-tree layer directly is that the
    ++      ** vdbe program will take advantage of the various transaction,
    ++      ** locking and error handling infrastructure built into the vdbe.
    ++      **
    ++      ** After seeking the cursor, the vdbe executes an OP_ResultRow.
    ++      ** Code external to the Vdbe then "borrows" the b-tree cursor and
    ++      ** uses it to implement the blob_read(), blob_write() and 
    ++      ** blob_bytes() functions.
    ++      **
    ++      ** The sqlite3_blob_close() function finalizes the vdbe program,
    ++      ** which closes the b-tree cursor and (possibly) commits the 
    ++      ** transaction.
    ++      */
    ++      static const int iLn = VDBE_OFFSET_LINENO(2);
    ++      static const VdbeOpList openBlob[] = {
    ++        {OP_TableLock,      0, 0, 0},  /* 0: Acquire a read or write lock */
    ++        {OP_OpenRead,       0, 0, 0},  /* 1: Open a cursor */
    ++        /* blobSeekToRow() will initialize r[1] to the desired rowid */
    ++        {OP_NotExists,      0, 5, 1},  /* 2: Seek the cursor to rowid=r[1] */
    ++        {OP_Column,         0, 0, 1},  /* 3  */
    ++        {OP_ResultRow,      1, 0, 0},  /* 4  */
    ++        {OP_Halt,           0, 0, 0},  /* 5  */
    ++      };
    +       Vdbe *v = (Vdbe *)pBlob->pStmt;
    +       int iDb = sqlite3SchemaToIndex(db, pTab->pSchema);
    ++      VdbeOp *aOp;
    + 
    +-
    +-      sqlite3VdbeAddOp4Int(v, OP_Transaction, iDb, flags, 
    ++      sqlite3VdbeAddOp4Int(v, OP_Transaction, iDb, wrFlag, 
    +                            pTab->pSchema->schema_cookie,
    +                            pTab->pSchema->iGeneration);
    +-      sqlite3VdbeChangeP5(v, 1);     
    +-      sqlite3VdbeAddOpList(v, ArraySize(openBlob), openBlob, iLn);
    ++      sqlite3VdbeChangeP5(v, 1);
    ++      assert( sqlite3VdbeCurrentAddr(v)==2 || db->mallocFailed );
    ++      aOp = sqlite3VdbeAddOpList(v, ArraySize(openBlob), openBlob, iLn);
    + 
    +       /* Make sure a mutex is held on the table to be accessed */
    +       sqlite3VdbeUsesBtree(v, iDb); 
    + 
    +-      /* Configure the OP_TableLock instruction */
    ++      if( db->mallocFailed==0 ){
    ++        assert( aOp!=0 );
    ++        /* Configure the OP_TableLock instruction */
    + #ifdef SQLITE_OMIT_SHARED_CACHE
    +-      sqlite3VdbeChangeToNoop(v, 1);
    ++        aOp[0].opcode = OP_Noop;
    + #else
    +-      sqlite3VdbeChangeP1(v, 1, iDb);
    +-      sqlite3VdbeChangeP2(v, 1, pTab->tnum);
    +-      sqlite3VdbeChangeP3(v, 1, flags);
    +-      sqlite3VdbeChangeP4(v, 1, pTab->zName, P4_TRANSIENT);
    +-#endif
    +-
    +-      /* Remove either the OP_OpenWrite or OpenRead. Set the P2 
    +-      ** parameter of the other to pTab->tnum.  */
    +-      sqlite3VdbeChangeToNoop(v, 3 - flags);
    +-      sqlite3VdbeChangeP2(v, 2 + flags, pTab->tnum);
    +-      sqlite3VdbeChangeP3(v, 2 + flags, iDb);
    +-
    +-      /* Configure the number of columns. Configure the cursor to
    +-      ** think that the table has one more column than it really
    +-      ** does. An OP_Column to retrieve this imaginary column will
    +-      ** always return an SQL NULL. This is useful because it means
    +-      ** we can invoke OP_Column to fill in the vdbe cursors type 
    +-      ** and offset cache without causing any IO.
    +-      */
    +-      sqlite3VdbeChangeP4(v, 2+flags, SQLITE_INT_TO_PTR(pTab->nCol+1),P4_INT32);
    +-      sqlite3VdbeChangeP2(v, 6, pTab->nCol);
    +-      if( !db->mallocFailed ){
    +-        pParse->nVar = 1;
    +-        pParse->nMem = 1;
    +-        pParse->nTab = 1;
    +-        sqlite3VdbeMakeReady(v, pParse);
    ++        aOp[0].p1 = iDb;
    ++        aOp[0].p2 = pTab->tnum;
    ++        aOp[0].p3 = wrFlag;
    ++        sqlite3VdbeChangeP4(v, 2, pTab->zName, P4_TRANSIENT);
    ++      }
    ++      if( db->mallocFailed==0 ){
    ++#endif
    ++
    ++        /* Remove either the OP_OpenWrite or OpenRead. Set the P2 
    ++        ** parameter of the other to pTab->tnum.  */
    ++        if( wrFlag ) aOp[1].opcode = OP_OpenWrite;
    ++        aOp[1].p2 = pTab->tnum;
    ++        aOp[1].p3 = iDb;   
    ++
    ++        /* Configure the number of columns. Configure the cursor to
    ++        ** think that the table has one more column than it really
    ++        ** does. An OP_Column to retrieve this imaginary column will
    ++        ** always return an SQL NULL. This is useful because it means
    ++        ** we can invoke OP_Column to fill in the vdbe cursors type 
    ++        ** and offset cache without causing any IO.
    ++        */
    ++        aOp[1].p4type = P4_INT32;
    ++        aOp[1].p4.i = pTab->nCol+1;
    ++        aOp[3].p2 = pTab->nCol;
    ++
    ++        sParse.nVar = 0;
    ++        sParse.nMem = 1;
    ++        sParse.nTab = 1;
    ++        sqlite3VdbeMakeReady(v, &sParse);
    +       }
    +     }
    +    
    +-    pBlob->flags = flags;
    +     pBlob->iCol = iCol;
    +     pBlob->db = db;
    +     sqlite3BtreeLeaveAll(db);
    +     if( db->mallocFailed ){
    +       goto blob_open_out;
    +     }
    +-    sqlite3_bind_int64(pBlob->pStmt, 1, iRow);
    +     rc = blobSeekToRow(pBlob, iRow, &zErr);
    +   } while( (++nAttempt)<SQLITE_MAX_SCHEMA_RETRY && rc==SQLITE_SCHEMA );
    + 
    +@@ -79930,8 +87630,7 @@ blob_open_out:
    +   }
    +   sqlite3ErrorWithMsg(db, rc, (zErr ? "%s" : 0), zErr);
    +   sqlite3DbFree(db, zErr);
    +-  sqlite3ParserReset(pParse);
    +-  sqlite3StackFree(db, pParse);
    ++  sqlite3ParserReset(&sParse);
    +   rc = sqlite3ApiExit(db, rc);
    +   sqlite3_mutex_leave(db->mutex);
    +   return rc;
    +@@ -79941,7 +87640,7 @@ blob_open_out:
    + ** Close a blob handle that was previously created using
    + ** sqlite3_blob_open().
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_blob_close(sqlite3_blob *pBlob){
    ++SQLITE_API int sqlite3_blob_close(sqlite3_blob *pBlob){
    +   Incrblob *p = (Incrblob *)pBlob;
    +   int rc;
    +   sqlite3 *db;
    +@@ -79992,6 +87691,30 @@ static int blobReadWrite(
    +     */
    +     assert( db == v->db );
    +     sqlite3BtreeEnterCursor(p->pCsr);
    ++
    ++#ifdef SQLITE_ENABLE_PREUPDATE_HOOK
    ++    if( xCall==sqlite3BtreePutData && db->xPreUpdateCallback ){
    ++      /* If a pre-update hook is registered and this is a write cursor, 
    ++      ** invoke it here. 
    ++      ** 
    ++      ** TODO: The preupdate-hook is passed SQLITE_DELETE, even though this
    ++      ** operation should really be an SQLITE_UPDATE. This is probably
    ++      ** incorrect, but is convenient because at this point the new.* values 
    ++      ** are not easily obtainable. And for the sessions module, an 
    ++      ** SQLITE_UPDATE where the PK columns do not change is handled in the 
    ++      ** same way as an SQLITE_DELETE (the SQLITE_DELETE code is actually
    ++      ** slightly more efficient). Since you cannot write to a PK column
    ++      ** using the incremental-blob API, this works. For the sessions module
    ++      ** anyhow.
    ++      */
    ++      sqlite3_int64 iKey;
    ++      iKey = sqlite3BtreeIntegerKey(p->pCsr);
    ++      sqlite3VdbePreUpdateHook(
    ++          v, v->apCsr[0], SQLITE_DELETE, p->zDb, p->pTab, iKey, -1
    ++      );
    ++    }
    ++#endif
    ++
    +     rc = xCall(p->pCsr, iOffset+p->iOffset, n, z);
    +     sqlite3BtreeLeaveCursor(p->pCsr);
    +     if( rc==SQLITE_ABORT ){
    +@@ -80010,14 +87733,14 @@ static int blobReadWrite(
    + /*
    + ** Read data from a blob handle.
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_blob_read(sqlite3_blob *pBlob, void *z, int n, int iOffset){
    +-  return blobReadWrite(pBlob, z, n, iOffset, sqlite3BtreeData);
    ++SQLITE_API int sqlite3_blob_read(sqlite3_blob *pBlob, void *z, int n, int iOffset){
    ++  return blobReadWrite(pBlob, z, n, iOffset, sqlite3BtreePayloadChecked);
    + }
    + 
    + /*
    + ** Write data to a blob handle.
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_blob_write(sqlite3_blob *pBlob, const void *z, int n, int iOffset){
    ++SQLITE_API int sqlite3_blob_write(sqlite3_blob *pBlob, const void *z, int n, int iOffset){
    +   return blobReadWrite(pBlob, (void *)z, n, iOffset, sqlite3BtreePutData);
    + }
    + 
    +@@ -80027,7 +87750,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_blob_write(sqlite3_blob *pBlob, const void
    + ** The Incrblob.nByte field is fixed for the lifetime of the Incrblob
    + ** so no mutex is required for access.
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_blob_bytes(sqlite3_blob *pBlob){
    ++SQLITE_API int sqlite3_blob_bytes(sqlite3_blob *pBlob){
    +   Incrblob *p = (Incrblob *)pBlob;
    +   return (p && p->pStmt) ? p->nByte : 0;
    + }
    +@@ -80042,7 +87765,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_blob_bytes(sqlite3_blob *pBlob){
    + ** subsequent calls to sqlite3_blob_xxx() functions (except blob_close()) 
    + ** immediately return SQLITE_ABORT.
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_blob_reopen(sqlite3_blob *pBlob, sqlite3_int64 iRow){
    ++SQLITE_API int sqlite3_blob_reopen(sqlite3_blob *pBlob, sqlite3_int64 iRow){
    +   int rc;
    +   Incrblob *p = (Incrblob *)pBlob;
    +   sqlite3 *db;
    +@@ -80618,7 +88341,7 @@ static int vdbePmaReadBlob(
    +       int nNew = MAX(128, p->nAlloc*2);
    +       while( nByte>nNew ) nNew = nNew*2;
    +       aNew = sqlite3Realloc(p->aAlloc, nNew);
    +-      if( !aNew ) return SQLITE_NOMEM;
    ++      if( !aNew ) return SQLITE_NOMEM_BKPT;
    +       p->nAlloc = nNew;
    +       p->aAlloc = aNew;
    +     }
    +@@ -80730,7 +88453,7 @@ static int vdbePmaReaderSeek(
    +     int iBuf = pReadr->iReadOff % pgsz;
    +     if( pReadr->aBuffer==0 ){
    +       pReadr->aBuffer = (u8*)sqlite3Malloc(pgsz);
    +-      if( pReadr->aBuffer==0 ) rc = SQLITE_NOMEM;
    ++      if( pReadr->aBuffer==0 ) rc = SQLITE_NOMEM_BKPT;
    +       pReadr->nBuffer = pgsz;
    +     }
    +     if( rc==SQLITE_OK && iBuf ){
    +@@ -80815,7 +88538,7 @@ static int vdbePmaReaderInit(
    + 
    +   rc = vdbePmaReaderSeek(pTask, pReadr, pFile, iStart);
    +   if( rc==SQLITE_OK ){
    +-    u64 nByte;                    /* Size of PMA in bytes */
    ++    u64 nByte = 0;                 /* Size of PMA in bytes */
    +     rc = vdbePmaReadVarint(pReadr, &nByte);
    +     pReadr->iEof = pReadr->iReadOff + nByte;
    +     *pnByte += nByte;
    +@@ -80893,15 +88616,15 @@ static int vdbeSorterCompareText(
    +   int n2;
    +   int res;
    + 
    +-  getVarint32(&p1[1], n1); n1 = (n1 - 13) / 2;
    +-  getVarint32(&p2[1], n2); n2 = (n2 - 13) / 2;
    +-  res = memcmp(v1, v2, MIN(n1, n2));
    ++  getVarint32(&p1[1], n1);
    ++  getVarint32(&p2[1], n2);
    ++  res = memcmp(v1, v2, (MIN(n1, n2) - 13)/2);
    +   if( res==0 ){
    +     res = n1 - n2;
    +   }
    + 
    +   if( res==0 ){
    +-    if( pTask->pSorter->pKeyInfo->nField>1 ){
    ++    if( pTask->pSorter->pKeyInfo->nKeyField>1 ){
    +       res = vdbeSorterCompareTail(
    +           pTask, pbKey2Cached, pKey1, nKey1, pKey2, nKey2
    +       );
    +@@ -80936,42 +88659,41 @@ static int vdbeSorterCompareInt(
    +   assert( (s1>0 && s1<7) || s1==8 || s1==9 );
    +   assert( (s2>0 && s2<7) || s2==8 || s2==9 );
    + 
    +-  if( s1>7 && s2>7 ){
    +-    res = s1 - s2;
    +-  }else{
    +-    if( s1==s2 ){
    +-      if( (*v1 ^ *v2) & 0x80 ){
    +-        /* The two values have different signs */
    +-        res = (*v1 & 0x80) ? -1 : +1;
    +-      }else{
    +-        /* The two values have the same sign. Compare using memcmp(). */
    +-        static const u8 aLen[] = {0, 1, 2, 3, 4, 6, 8 };
    +-        int i;
    +-        res = 0;
    +-        for(i=0; i<aLen[s1]; i++){
    +-          if( (res = v1[i] - v2[i]) ) break;
    ++  if( s1==s2 ){
    ++    /* The two values have the same sign. Compare using memcmp(). */
    ++    static const u8 aLen[] = {0, 1, 2, 3, 4, 6, 8, 0, 0, 0 };
    ++    const u8 n = aLen[s1];
    ++    int i;
    ++    res = 0;
    ++    for(i=0; i<n; i++){
    ++      if( (res = v1[i] - v2[i])!=0 ){
    ++        if( ((v1[0] ^ v2[0]) & 0x80)!=0 ){
    ++          res = v1[0] & 0x80 ? -1 : +1;
    +         }
    ++        break;
    +       }
    ++    }
    ++  }else if( s1>7 && s2>7 ){
    ++    res = s1 - s2;
    ++  }else{
    ++    if( s2>7 ){
    ++      res = +1;
    ++    }else if( s1>7 ){
    ++      res = -1;
    +     }else{
    +-      if( s2>7 ){
    +-        res = +1;
    +-      }else if( s1>7 ){
    +-        res = -1;
    +-      }else{
    +-        res = s1 - s2;
    +-      }
    +-      assert( res!=0 );
    ++      res = s1 - s2;
    ++    }
    ++    assert( res!=0 );
    + 
    +-      if( res>0 ){
    +-        if( *v1 & 0x80 ) res = -1;
    +-      }else{
    +-        if( *v2 & 0x80 ) res = +1;
    +-      }
    ++    if( res>0 ){
    ++      if( *v1 & 0x80 ) res = -1;
    ++    }else{
    ++      if( *v2 & 0x80 ) res = +1;
    +     }
    +   }
    + 
    +   if( res==0 ){
    +-    if( pTask->pSorter->pKeyInfo->nField>1 ){
    ++    if( pTask->pSorter->pKeyInfo->nKeyField>1 ){
    +       res = vdbeSorterCompareTail(
    +           pTask, pbKey2Cached, pKey1, nKey1, pKey2, nKey2
    +       );
    +@@ -80986,7 +88708,7 @@ static int vdbeSorterCompareInt(
    + /*
    + ** Initialize the temporary index cursor just opened as a sorter cursor.
    + **
    +-** Usually, the sorter module uses the value of (pCsr->pKeyInfo->nField)
    ++** Usually, the sorter module uses the value of (pCsr->pKeyInfo->nKeyField)
    + ** to determine the number of fields that should be compared from the
    + ** records being sorted. However, if the value passed as argument nField
    + ** is non-zero and the sorter is able to guarantee a stable sort, nField
    +@@ -81009,7 +88731,6 @@ SQLITE_PRIVATE int sqlite3VdbeSorterInit(
    + ){
    +   int pgsz;                       /* Page size of main database */
    +   int i;                          /* Used to iterate through aTask[] */
    +-  int mxCache;                    /* Cache size */
    +   VdbeSorter *pSorter;            /* The new sorter */
    +   KeyInfo *pKeyInfo;              /* Copy of pCsr->pKeyInfo with db==0 */
    +   int szKeyInfo;                  /* Size of pCsr->pKeyInfo in bytes */
    +@@ -81038,25 +88759,25 @@ SQLITE_PRIVATE int sqlite3VdbeSorterInit(
    +   }
    + #endif
    + 
    +-  assert( pCsr->pKeyInfo && pCsr->pBt==0 );
    +-  szKeyInfo = sizeof(KeyInfo) + (pCsr->pKeyInfo->nField-1)*sizeof(CollSeq*);
    ++  assert( pCsr->pKeyInfo && pCsr->pBtx==0 );
    ++  assert( pCsr->eCurType==CURTYPE_SORTER );
    ++  szKeyInfo = sizeof(KeyInfo) + (pCsr->pKeyInfo->nKeyField-1)*sizeof(CollSeq*);
    +   sz = sizeof(VdbeSorter) + nWorker * sizeof(SortSubtask);
    + 
    +   pSorter = (VdbeSorter*)sqlite3DbMallocZero(db, sz + szKeyInfo);
    +-  pCsr->pSorter = pSorter;
    ++  pCsr->uc.pSorter = pSorter;
    +   if( pSorter==0 ){
    +-    rc = SQLITE_NOMEM;
    ++    rc = SQLITE_NOMEM_BKPT;
    +   }else{
    +     pSorter->pKeyInfo = pKeyInfo = (KeyInfo*)((u8*)pSorter + sz);
    +     memcpy(pKeyInfo, pCsr->pKeyInfo, szKeyInfo);
    +     pKeyInfo->db = 0;
    +     if( nField && nWorker==0 ){
    +-      pKeyInfo->nXField += (pKeyInfo->nField - nField);
    +-      pKeyInfo->nField = nField;
    ++      pKeyInfo->nKeyField = nField;
    +     }
    +     pSorter->pgsz = pgsz = sqlite3BtreeGetPageSize(db->aDb[0].pBt);
    +     pSorter->nTask = nWorker + 1;
    +-    pSorter->iPrev = nWorker-1;
    ++    pSorter->iPrev = (u8)(nWorker - 1);
    +     pSorter->bUseThreads = (pSorter->nTask>1);
    +     pSorter->db = db;
    +     for(i=0; i<pSorter->nTask; i++){
    +@@ -81065,25 +88786,32 @@ SQLITE_PRIVATE int sqlite3VdbeSorterInit(
    +     }
    + 
    +     if( !sqlite3TempInMemory(db) ){
    ++      i64 mxCache;                /* Cache size in bytes*/
    +       u32 szPma = sqlite3GlobalConfig.szPma;
    +       pSorter->mnPmaSize = szPma * pgsz;
    ++
    +       mxCache = db->aDb[0].pSchema->cache_size;
    +-      if( mxCache<(int)szPma ) mxCache = (int)szPma;
    +-      pSorter->mxPmaSize = MIN((i64)mxCache*pgsz, SQLITE_MAX_PMASZ);
    ++      if( mxCache<0 ){
    ++        /* A negative cache-size value C indicates that the cache is abs(C)
    ++        ** KiB in size.  */
    ++        mxCache = mxCache * -1024;
    ++      }else{
    ++        mxCache = mxCache * pgsz;
    ++      }
    ++      mxCache = MIN(mxCache, SQLITE_MAX_PMASZ);
    ++      pSorter->mxPmaSize = MAX(pSorter->mnPmaSize, (int)mxCache);
    + 
    +-      /* EVIDENCE-OF: R-26747-61719 When the application provides any amount of
    +-      ** scratch memory using SQLITE_CONFIG_SCRATCH, SQLite avoids unnecessary
    +-      ** large heap allocations.
    +-      */
    +-      if( sqlite3GlobalConfig.pScratch==0 ){
    ++      /* Avoid large memory allocations if the application has requested
    ++      ** SQLITE_CONFIG_SMALL_MALLOC. */
    ++      if( sqlite3GlobalConfig.bSmallMalloc==0 ){
    +         assert( pSorter->iMemory==0 );
    +         pSorter->nMemory = pgsz;
    +         pSorter->list.aMemory = (u8*)sqlite3Malloc(pgsz);
    +-        if( !pSorter->list.aMemory ) rc = SQLITE_NOMEM;
    ++        if( !pSorter->list.aMemory ) rc = SQLITE_NOMEM_BKPT;
    +       }
    +     }
    + 
    +-    if( (pKeyInfo->nField+pKeyInfo->nXField)<13 
    ++    if( pKeyInfo->nAllField<13 
    +      && (pKeyInfo->aColl[0]==0 || pKeyInfo->aColl[0]==db->pDfltColl)
    +     ){
    +       pSorter->typeMask = SORTER_TYPE_INTEGER | SORTER_TYPE_TEXT;
    +@@ -81327,12 +89055,14 @@ SQLITE_PRIVATE void sqlite3VdbeSorterReset(sqlite3 *db, VdbeSorter *pSorter){
    + ** Free any cursor components allocated by sqlite3VdbeSorterXXX routines.
    + */
    + SQLITE_PRIVATE void sqlite3VdbeSorterClose(sqlite3 *db, VdbeCursor *pCsr){
    +-  VdbeSorter *pSorter = pCsr->pSorter;
    ++  VdbeSorter *pSorter;
    ++  assert( pCsr->eCurType==CURTYPE_SORTER );
    ++  pSorter = pCsr->uc.pSorter;
    +   if( pSorter ){
    +     sqlite3VdbeSorterReset(db, pSorter);
    +     sqlite3_free(pSorter->list.aMemory);
    +     sqlite3DbFree(db, pSorter);
    +-    pCsr->pSorter = 0;
    ++    pCsr->uc.pSorter = 0;
    +   }
    + }
    + 
    +@@ -81394,13 +89124,9 @@ static int vdbeSorterOpenTempFile(
    + */
    + static int vdbeSortAllocUnpacked(SortSubtask *pTask){
    +   if( pTask->pUnpacked==0 ){
    +-    char *pFree;
    +-    pTask->pUnpacked = sqlite3VdbeAllocUnpackedRecord(
    +-        pTask->pSorter->pKeyInfo, 0, 0, &pFree
    +-    );
    +-    assert( pTask->pUnpacked==(UnpackedRecord*)pFree );
    +-    if( pFree==0 ) return SQLITE_NOMEM;
    +-    pTask->pUnpacked->nField = pTask->pSorter->pKeyInfo->nField;
    ++    pTask->pUnpacked = sqlite3VdbeAllocUnpackedRecord(pTask->pSorter->pKeyInfo);
    ++    if( pTask->pUnpacked==0 ) return SQLITE_NOMEM_BKPT;
    ++    pTask->pUnpacked->nField = pTask->pSorter->pKeyInfo->nKeyField;
    +     pTask->pUnpacked->errCode = 0;
    +   }
    +   return SQLITE_OK;
    +@@ -81409,19 +89135,18 @@ static int vdbeSortAllocUnpacked(SortSubtask *pTask){
    + 
    + /*
    + ** Merge the two sorted lists p1 and p2 into a single list.
    +-** Set *ppOut to the head of the new list.
    + */
    +-static void vdbeSorterMerge(
    ++static SorterRecord *vdbeSorterMerge(
    +   SortSubtask *pTask,             /* Calling thread context */
    +   SorterRecord *p1,               /* First list to merge */
    +-  SorterRecord *p2,               /* Second list to merge */
    +-  SorterRecord **ppOut            /* OUT: Head of merged list */
    ++  SorterRecord *p2                /* Second list to merge */
    + ){
    +   SorterRecord *pFinal = 0;
    +   SorterRecord **pp = &pFinal;
    +   int bCached = 0;
    + 
    +-  while( p1 && p2 ){
    ++  assert( p1!=0 && p2!=0 );
    ++  for(;;){
    +     int res;
    +     res = pTask->xCompare(
    +         pTask, &bCached, SRVAL(p1), p1->nVal, SRVAL(p2), p2->nVal
    +@@ -81431,15 +89156,22 @@ static void vdbeSorterMerge(
    +       *pp = p1;
    +       pp = &p1->u.pNext;
    +       p1 = p1->u.pNext;
    ++      if( p1==0 ){
    ++        *pp = p2;
    ++        break;
    ++      }
    +     }else{
    +       *pp = p2;
    +       pp = &p2->u.pNext;
    +       p2 = p2->u.pNext;
    +       bCached = 0;
    ++      if( p2==0 ){
    ++        *pp = p1;
    ++        break;
    ++      }
    +     }
    +   }
    +-  *pp = p1 ? p1 : p2;
    +-  *ppOut = pFinal;
    ++  return pFinal;
    + }
    + 
    + /*
    +@@ -81474,7 +89206,7 @@ static int vdbeSorterSort(SortSubtask *pTask, SorterList *pList){
    + 
    +   aSlot = (SorterRecord **)sqlite3MallocZero(64 * sizeof(SorterRecord *));
    +   if( !aSlot ){
    +-    return SQLITE_NOMEM;
    ++    return SQLITE_NOMEM_BKPT;
    +   }
    + 
    +   while( p ){
    +@@ -81492,7 +89224,7 @@ static int vdbeSorterSort(SortSubtask *pTask, SorterList *pList){
    + 
    +     p->u.pNext = 0;
    +     for(i=0; aSlot[i]; i++){
    +-      vdbeSorterMerge(pTask, p, aSlot[i], &p);
    ++      p = vdbeSorterMerge(pTask, p, aSlot[i]);
    +       aSlot[i] = 0;
    +     }
    +     aSlot[i] = p;
    +@@ -81501,7 +89233,8 @@ static int vdbeSorterSort(SortSubtask *pTask, SorterList *pList){
    + 
    +   p = 0;
    +   for(i=0; i<64; i++){
    +-    vdbeSorterMerge(pTask, p, aSlot[i], &p);
    ++    if( aSlot[i]==0 ) continue;
    ++    p = p ? vdbeSorterMerge(pTask, p, aSlot[i]) : aSlot[i];
    +   }
    +   pList->pList = p;
    + 
    +@@ -81524,7 +89257,7 @@ static void vdbePmaWriterInit(
    +   memset(p, 0, sizeof(PmaWriter));
    +   p->aBuffer = (u8*)sqlite3Malloc(nBuf);
    +   if( !p->aBuffer ){
    +-    p->eFWErr = SQLITE_NOMEM;
    ++    p->eFWErr = SQLITE_NOMEM_BKPT;
    +   }else{
    +     p->iBufEnd = p->iBufStart = (iStart % nBuf);
    +     p->iWriteOff = iStart - p->iBufStart;
    +@@ -81812,7 +89545,7 @@ static int vdbeSorterFlushPMA(VdbeSorter *pSorter){
    +         pSorter->nMemory = sqlite3MallocSize(aMem);
    +       }else if( pSorter->list.aMemory ){
    +         pSorter->list.aMemory = sqlite3Malloc(pSorter->nMemory);
    +-        if( !pSorter->list.aMemory ) return SQLITE_NOMEM;
    ++        if( !pSorter->list.aMemory ) return SQLITE_NOMEM_BKPT;
    +       }
    + 
    +       rc = vdbeSorterCreateThread(pTask, vdbeSorterFlushThread, pCtx);
    +@@ -81830,15 +89563,16 @@ SQLITE_PRIVATE int sqlite3VdbeSorterWrite(
    +   const VdbeCursor *pCsr,         /* Sorter cursor */
    +   Mem *pVal                       /* Memory cell containing record */
    + ){
    +-  VdbeSorter *pSorter = pCsr->pSorter;
    ++  VdbeSorter *pSorter;
    +   int rc = SQLITE_OK;             /* Return Code */
    +   SorterRecord *pNew;             /* New list element */
    +-
    +   int bFlush;                     /* True to flush contents of memory to PMA */
    +   int nReq;                       /* Bytes of memory required */
    +   int nPMA;                       /* Bytes of PMA space required */
    +   int t;                          /* serial type of first record field */
    + 
    ++  assert( pCsr->eCurType==CURTYPE_SORTER );
    ++  pSorter = pCsr->uc.pSorter;
    +   getVarint32((const u8*)&pVal->z[1], t);
    +   if( t>0 && t<10 && t!=7 ){
    +     pSorter->typeMask &= SORTER_TYPE_INTEGER;
    +@@ -81895,27 +89629,28 @@ SQLITE_PRIVATE int sqlite3VdbeSorterWrite(
    + 
    +     if( nMin>pSorter->nMemory ){
    +       u8 *aNew;
    ++      int iListOff = (u8*)pSorter->list.pList - pSorter->list.aMemory;
    +       int nNew = pSorter->nMemory * 2;
    +       while( nNew < nMin ) nNew = nNew*2;
    +       if( nNew > pSorter->mxPmaSize ) nNew = pSorter->mxPmaSize;
    +       if( nNew < nMin ) nNew = nMin;
    + 
    +       aNew = sqlite3Realloc(pSorter->list.aMemory, nNew);
    +-      if( !aNew ) return SQLITE_NOMEM;
    +-      pSorter->list.pList = (SorterRecord*)(
    +-          aNew + ((u8*)pSorter->list.pList - pSorter->list.aMemory)
    +-      );
    ++      if( !aNew ) return SQLITE_NOMEM_BKPT;
    ++      pSorter->list.pList = (SorterRecord*)&aNew[iListOff];
    +       pSorter->list.aMemory = aNew;
    +       pSorter->nMemory = nNew;
    +     }
    + 
    +     pNew = (SorterRecord*)&pSorter->list.aMemory[pSorter->iMemory];
    +     pSorter->iMemory += ROUND8(nReq);
    +-    pNew->u.iNext = (int)((u8*)(pSorter->list.pList) - pSorter->list.aMemory);
    ++    if( pSorter->list.pList ){
    ++      pNew->u.iNext = (int)((u8*)(pSorter->list.pList) - pSorter->list.aMemory);
    ++    }
    +   }else{
    +     pNew = (SorterRecord *)sqlite3Malloc(nReq);
    +     if( pNew==0 ){
    +-      return SQLITE_NOMEM;
    ++      return SQLITE_NOMEM_BKPT;
    +     }
    +     pNew->u.pNext = pSorter->list.pList;
    +   }
    +@@ -82062,7 +89797,7 @@ static int vdbeIncrMergerNew(
    +     pTask->file2.iEof += pIncr->mxSz;
    +   }else{
    +     vdbeMergeEngineFree(pMerger);
    +-    rc = SQLITE_NOMEM;
    ++    rc = SQLITE_NOMEM_BKPT;
    +   }
    +   return rc;
    + }
    +@@ -82367,10 +90102,10 @@ static int vdbeMergeEngineLevel0(
    +   int rc = SQLITE_OK;
    + 
    +   *ppOut = pNew = vdbeMergeEngineNew(nPMA);
    +-  if( pNew==0 ) rc = SQLITE_NOMEM;
    ++  if( pNew==0 ) rc = SQLITE_NOMEM_BKPT;
    + 
    +   for(i=0; i<nPMA && rc==SQLITE_OK; i++){
    +-    i64 nDummy;
    ++    i64 nDummy = 0;
    +     PmaReader *pReadr = &pNew->aReadr[i];
    +     rc = vdbePmaReaderInit(pTask, &pTask->file, iOff, pReadr, &nDummy);
    +     iOff = pReadr->iEof;
    +@@ -82438,7 +90173,7 @@ static int vdbeSorterAddToTree(
    +     if( pReadr->pIncr==0 ){
    +       MergeEngine *pNew = vdbeMergeEngineNew(SORTER_MAX_MERGE_COUNT);
    +       if( pNew==0 ){
    +-        rc = SQLITE_NOMEM;
    ++        rc = SQLITE_NOMEM_BKPT;
    +       }else{
    +         rc = vdbeIncrMergerNew(pTask, pNew, &pReadr->pIncr);
    +       }
    +@@ -82483,7 +90218,7 @@ static int vdbeSorterMergeTreeBuild(
    +   assert( pSorter->bUseThreads || pSorter->nTask==1 );
    +   if( pSorter->nTask>1 ){
    +     pMain = vdbeMergeEngineNew(pSorter->nTask);
    +-    if( pMain==0 ) rc = SQLITE_NOMEM;
    ++    if( pMain==0 ) rc = SQLITE_NOMEM_BKPT;
    +   }
    + #endif
    + 
    +@@ -82501,7 +90236,7 @@ static int vdbeSorterMergeTreeBuild(
    +         int i;
    +         int iSeq = 0;
    +         pRoot = vdbeMergeEngineNew(SORTER_MAX_MERGE_COUNT);
    +-        if( pRoot==0 ) rc = SQLITE_NOMEM;
    ++        if( pRoot==0 ) rc = SQLITE_NOMEM_BKPT;
    +         for(i=0; i<pTask->nPMA && rc==SQLITE_OK; i += SORTER_MAX_MERGE_COUNT){
    +           MergeEngine *pMerger = 0; /* New level-0 PMA merger */
    +           int nReader;              /* Number of level-0 PMAs to merge */
    +@@ -82572,7 +90307,7 @@ static int vdbeSorterSetupMerge(VdbeSorter *pSorter){
    +       if( rc==SQLITE_OK ){
    +         pReadr = (PmaReader*)sqlite3DbMallocZero(db, sizeof(PmaReader));
    +         pSorter->pReader = pReadr;
    +-        if( pReadr==0 ) rc = SQLITE_NOMEM;
    ++        if( pReadr==0 ) rc = SQLITE_NOMEM_BKPT;
    +       }
    +       if( rc==SQLITE_OK ){
    +         rc = vdbeIncrMergerNew(pLast, pMain, &pReadr->pIncr);
    +@@ -82630,9 +90365,11 @@ static int vdbeSorterSetupMerge(VdbeSorter *pSorter){
    + ** in sorted order.
    + */
    + SQLITE_PRIVATE int sqlite3VdbeSorterRewind(const VdbeCursor *pCsr, int *pbEof){
    +-  VdbeSorter *pSorter = pCsr->pSorter;
    ++  VdbeSorter *pSorter;
    +   int rc = SQLITE_OK;             /* Return code */
    + 
    ++  assert( pCsr->eCurType==CURTYPE_SORTER );
    ++  pSorter = pCsr->uc.pSorter;
    +   assert( pSorter );
    + 
    +   /* If no data has been written to disk, then do not do so now. Instead,
    +@@ -82673,12 +90410,18 @@ SQLITE_PRIVATE int sqlite3VdbeSorterRewind(const VdbeCursor *pCsr, int *pbEof){
    + }
    + 
    + /*
    +-** Advance to the next element in the sorter.
    ++** Advance to the next element in the sorter.  Return value:
    ++**
    ++**    SQLITE_OK     success
    ++**    SQLITE_DONE   end of data
    ++**    otherwise     some kind of error.
    + */
    +-SQLITE_PRIVATE int sqlite3VdbeSorterNext(sqlite3 *db, const VdbeCursor *pCsr, int *pbEof){
    +-  VdbeSorter *pSorter = pCsr->pSorter;
    ++SQLITE_PRIVATE int sqlite3VdbeSorterNext(sqlite3 *db, const VdbeCursor *pCsr){
    ++  VdbeSorter *pSorter;
    +   int rc;                         /* Return code */
    + 
    ++  assert( pCsr->eCurType==CURTYPE_SORTER );
    ++  pSorter = pCsr->uc.pSorter;
    +   assert( pSorter->bUsePMA || (pSorter->pReader==0 && pSorter->pMerger==0) );
    +   if( pSorter->bUsePMA ){
    +     assert( pSorter->pReader==0 || pSorter->pMerger==0 );
    +@@ -82687,21 +90430,22 @@ SQLITE_PRIVATE int sqlite3VdbeSorterNext(sqlite3 *db, const VdbeCursor *pCsr, in
    + #if SQLITE_MAX_WORKER_THREADS>0
    +     if( pSorter->bUseThreads ){
    +       rc = vdbePmaReaderNext(pSorter->pReader);
    +-      *pbEof = (pSorter->pReader->pFd==0);
    ++      if( rc==SQLITE_OK && pSorter->pReader->pFd==0 ) rc = SQLITE_DONE;
    +     }else
    + #endif
    +     /*if( !pSorter->bUseThreads )*/ {
    ++      int res = 0;
    +       assert( pSorter->pMerger!=0 );
    +       assert( pSorter->pMerger->pTask==(&pSorter->aTask[0]) );
    +-      rc = vdbeMergeEngineStep(pSorter->pMerger, pbEof);
    ++      rc = vdbeMergeEngineStep(pSorter->pMerger, &res);
    ++      if( rc==SQLITE_OK && res ) rc = SQLITE_DONE;
    +     }
    +   }else{
    +     SorterRecord *pFree = pSorter->list.pList;
    +     pSorter->list.pList = pFree->u.pNext;
    +     pFree->u.pNext = 0;
    +     if( pSorter->list.aMemory==0 ) vdbeSorterRecordFree(db, pFree);
    +-    *pbEof = !pSorter->list.pList;
    +-    rc = SQLITE_OK;
    ++    rc = pSorter->list.pList ? SQLITE_OK : SQLITE_DONE;
    +   }
    +   return rc;
    + }
    +@@ -82738,12 +90482,14 @@ static void *vdbeSorterRowkey(
    + ** Copy the current sorter key into the memory cell pOut.
    + */
    + SQLITE_PRIVATE int sqlite3VdbeSorterRowkey(const VdbeCursor *pCsr, Mem *pOut){
    +-  VdbeSorter *pSorter = pCsr->pSorter;
    ++  VdbeSorter *pSorter;
    +   void *pKey; int nKey;           /* Sorter key to copy into pOut */
    + 
    ++  assert( pCsr->eCurType==CURTYPE_SORTER );
    ++  pSorter = pCsr->uc.pSorter;
    +   pKey = vdbeSorterRowkey(pSorter, &nKey);
    +   if( sqlite3VdbeMemClearAndResize(pOut, nKey) ){
    +-    return SQLITE_NOMEM;
    ++    return SQLITE_NOMEM_BKPT;
    +   }
    +   pOut->n = nKey;
    +   MemSetTypeFlag(pOut, MEM_Blob);
    +@@ -82774,17 +90520,19 @@ SQLITE_PRIVATE int sqlite3VdbeSorterCompare(
    +   int nKeyCol,                    /* Compare this many columns */
    +   int *pRes                       /* OUT: Result of comparison */
    + ){
    +-  VdbeSorter *pSorter = pCsr->pSorter;
    +-  UnpackedRecord *r2 = pSorter->pUnpacked;
    +-  KeyInfo *pKeyInfo = pCsr->pKeyInfo;
    ++  VdbeSorter *pSorter;
    ++  UnpackedRecord *r2;
    ++  KeyInfo *pKeyInfo;
    +   int i;
    +   void *pKey; int nKey;           /* Sorter key to compare pVal with */
    + 
    ++  assert( pCsr->eCurType==CURTYPE_SORTER );
    ++  pSorter = pCsr->uc.pSorter;
    ++  r2 = pSorter->pUnpacked;
    ++  pKeyInfo = pCsr->pKeyInfo;
    +   if( r2==0 ){
    +-    char *p;
    +-    r2 = pSorter->pUnpacked = sqlite3VdbeAllocUnpackedRecord(pKeyInfo,0,0,&p);
    +-    assert( pSorter->pUnpacked==(UnpackedRecord*)p );
    +-    if( r2==0 ) return SQLITE_NOMEM;
    ++    r2 = pSorter->pUnpacked = sqlite3VdbeAllocUnpackedRecord(pKeyInfo);
    ++    if( r2==0 ) return SQLITE_NOMEM_BKPT;
    +     r2->nField = nKeyCol;
    +   }
    +   assert( r2->nField==nKeyCol );
    +@@ -82803,265 +90551,6 @@ SQLITE_PRIVATE int sqlite3VdbeSorterCompare(
    + }
    + 
    + /************** End of vdbesort.c ********************************************/
    +-/************** Begin file journal.c *****************************************/
    +-/*
    +-** 2007 August 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 implements a special kind of sqlite3_file object used
    +-** by SQLite to create journal files if the atomic-write optimization
    +-** is enabled.
    +-**
    +-** The distinctive characteristic of this sqlite3_file is that the
    +-** actual on disk file is created lazily. When the file is created,
    +-** the caller specifies a buffer size for an in-memory buffer to
    +-** be used to service read() and write() requests. The actual file
    +-** on disk is not created or populated until either:
    +-**
    +-**   1) The in-memory representation grows too large for the allocated 
    +-**      buffer, or
    +-**   2) The sqlite3JournalCreate() function is called.
    +-*/
    +-#ifdef SQLITE_ENABLE_ATOMIC_WRITE
    +-/* #include "sqliteInt.h" */
    +-
    +-
    +-/*
    +-** A JournalFile object is a subclass of sqlite3_file used by
    +-** as an open file handle for journal files.
    +-*/
    +-struct JournalFile {
    +-  sqlite3_io_methods *pMethod;    /* I/O methods on journal files */
    +-  int nBuf;                       /* Size of zBuf[] in bytes */
    +-  char *zBuf;                     /* Space to buffer journal writes */
    +-  int iSize;                      /* Amount of zBuf[] currently used */
    +-  int flags;                      /* xOpen flags */
    +-  sqlite3_vfs *pVfs;              /* The "real" underlying VFS */
    +-  sqlite3_file *pReal;            /* The "real" underlying file descriptor */
    +-  const char *zJournal;           /* Name of the journal file */
    +-};
    +-typedef struct JournalFile JournalFile;
    +-
    +-/*
    +-** If it does not already exists, create and populate the on-disk file 
    +-** for JournalFile p.
    +-*/
    +-static int createFile(JournalFile *p){
    +-  int rc = SQLITE_OK;
    +-  if( !p->pReal ){
    +-    sqlite3_file *pReal = (sqlite3_file *)&p[1];
    +-    rc = sqlite3OsOpen(p->pVfs, p->zJournal, pReal, p->flags, 0);
    +-    if( rc==SQLITE_OK ){
    +-      p->pReal = pReal;
    +-      if( p->iSize>0 ){
    +-        assert(p->iSize<=p->nBuf);
    +-        rc = sqlite3OsWrite(p->pReal, p->zBuf, p->iSize, 0);
    +-      }
    +-      if( rc!=SQLITE_OK ){
    +-        /* If an error occurred while writing to the file, close it before
    +-        ** returning. This way, SQLite uses the in-memory journal data to 
    +-        ** roll back changes made to the internal page-cache before this
    +-        ** function was called.  */
    +-        sqlite3OsClose(pReal);
    +-        p->pReal = 0;
    +-      }
    +-    }
    +-  }
    +-  return rc;
    +-}
    +-
    +-/*
    +-** Close the file.
    +-*/
    +-static int jrnlClose(sqlite3_file *pJfd){
    +-  JournalFile *p = (JournalFile *)pJfd;
    +-  if( p->pReal ){
    +-    sqlite3OsClose(p->pReal);
    +-  }
    +-  sqlite3_free(p->zBuf);
    +-  return SQLITE_OK;
    +-}
    +-
    +-/*
    +-** Read data from the file.
    +-*/
    +-static int jrnlRead(
    +-  sqlite3_file *pJfd,    /* The journal file from which to read */
    +-  void *zBuf,            /* Put the results here */
    +-  int iAmt,              /* Number of bytes to read */
    +-  sqlite_int64 iOfst     /* Begin reading at this offset */
    +-){
    +-  int rc = SQLITE_OK;
    +-  JournalFile *p = (JournalFile *)pJfd;
    +-  if( p->pReal ){
    +-    rc = sqlite3OsRead(p->pReal, zBuf, iAmt, iOfst);
    +-  }else if( (iAmt+iOfst)>p->iSize ){
    +-    rc = SQLITE_IOERR_SHORT_READ;
    +-  }else{
    +-    memcpy(zBuf, &p->zBuf[iOfst], iAmt);
    +-  }
    +-  return rc;
    +-}
    +-
    +-/*
    +-** Write data to the file.
    +-*/
    +-static int jrnlWrite(
    +-  sqlite3_file *pJfd,    /* The journal file into which to write */
    +-  const void *zBuf,      /* Take data to be written from here */
    +-  int iAmt,              /* Number of bytes to write */
    +-  sqlite_int64 iOfst     /* Begin writing at this offset into the file */
    +-){
    +-  int rc = SQLITE_OK;
    +-  JournalFile *p = (JournalFile *)pJfd;
    +-  if( !p->pReal && (iOfst+iAmt)>p->nBuf ){
    +-    rc = createFile(p);
    +-  }
    +-  if( rc==SQLITE_OK ){
    +-    if( p->pReal ){
    +-      rc = sqlite3OsWrite(p->pReal, zBuf, iAmt, iOfst);
    +-    }else{
    +-      memcpy(&p->zBuf[iOfst], zBuf, iAmt);
    +-      if( p->iSize<(iOfst+iAmt) ){
    +-        p->iSize = (iOfst+iAmt);
    +-      }
    +-    }
    +-  }
    +-  return rc;
    +-}
    +-
    +-/*
    +-** Truncate the file.
    +-*/
    +-static int jrnlTruncate(sqlite3_file *pJfd, sqlite_int64 size){
    +-  int rc = SQLITE_OK;
    +-  JournalFile *p = (JournalFile *)pJfd;
    +-  if( p->pReal ){
    +-    rc = sqlite3OsTruncate(p->pReal, size);
    +-  }else if( size<p->iSize ){
    +-    p->iSize = size;
    +-  }
    +-  return rc;
    +-}
    +-
    +-/*
    +-** Sync the file.
    +-*/
    +-static int jrnlSync(sqlite3_file *pJfd, int flags){
    +-  int rc;
    +-  JournalFile *p = (JournalFile *)pJfd;
    +-  if( p->pReal ){
    +-    rc = sqlite3OsSync(p->pReal, flags);
    +-  }else{
    +-    rc = SQLITE_OK;
    +-  }
    +-  return rc;
    +-}
    +-
    +-/*
    +-** Query the size of the file in bytes.
    +-*/
    +-static int jrnlFileSize(sqlite3_file *pJfd, sqlite_int64 *pSize){
    +-  int rc = SQLITE_OK;
    +-  JournalFile *p = (JournalFile *)pJfd;
    +-  if( p->pReal ){
    +-    rc = sqlite3OsFileSize(p->pReal, pSize);
    +-  }else{
    +-    *pSize = (sqlite_int64) p->iSize;
    +-  }
    +-  return rc;
    +-}
    +-
    +-/*
    +-** Table of methods for JournalFile sqlite3_file object.
    +-*/
    +-static struct sqlite3_io_methods JournalFileMethods = {
    +-  1,             /* iVersion */
    +-  jrnlClose,     /* xClose */
    +-  jrnlRead,      /* xRead */
    +-  jrnlWrite,     /* xWrite */
    +-  jrnlTruncate,  /* xTruncate */
    +-  jrnlSync,      /* xSync */
    +-  jrnlFileSize,  /* xFileSize */
    +-  0,             /* xLock */
    +-  0,             /* xUnlock */
    +-  0,             /* xCheckReservedLock */
    +-  0,             /* xFileControl */
    +-  0,             /* xSectorSize */
    +-  0,             /* xDeviceCharacteristics */
    +-  0,             /* xShmMap */
    +-  0,             /* xShmLock */
    +-  0,             /* xShmBarrier */
    +-  0              /* xShmUnmap */
    +-};
    +-
    +-/* 
    +-** Open a journal file.
    +-*/
    +-SQLITE_PRIVATE int sqlite3JournalOpen(
    +-  sqlite3_vfs *pVfs,         /* The VFS to use for actual file I/O */
    +-  const char *zName,         /* Name of the journal file */
    +-  sqlite3_file *pJfd,        /* Preallocated, blank file handle */
    +-  int flags,                 /* Opening flags */
    +-  int nBuf                   /* Bytes buffered before opening the file */
    +-){
    +-  JournalFile *p = (JournalFile *)pJfd;
    +-  memset(p, 0, sqlite3JournalSize(pVfs));
    +-  if( nBuf>0 ){
    +-    p->zBuf = sqlite3MallocZero(nBuf);
    +-    if( !p->zBuf ){
    +-      return SQLITE_NOMEM;
    +-    }
    +-  }else{
    +-    return sqlite3OsOpen(pVfs, zName, pJfd, flags, 0);
    +-  }
    +-  p->pMethod = &JournalFileMethods;
    +-  p->nBuf = nBuf;
    +-  p->flags = flags;
    +-  p->zJournal = zName;
    +-  p->pVfs = pVfs;
    +-  return SQLITE_OK;
    +-}
    +-
    +-/*
    +-** If the argument p points to a JournalFile structure, and the underlying
    +-** file has not yet been created, create it now.
    +-*/
    +-SQLITE_PRIVATE int sqlite3JournalCreate(sqlite3_file *p){
    +-  if( p->pMethods!=&JournalFileMethods ){
    +-    return SQLITE_OK;
    +-  }
    +-  return createFile((JournalFile *)p);
    +-}
    +-
    +-/*
    +-** The file-handle passed as the only argument is guaranteed to be an open
    +-** file. It may or may not be of class JournalFile. If the file is a
    +-** JournalFile, and the underlying file on disk has not yet been opened,
    +-** return 0. Otherwise, return 1.
    +-*/
    +-SQLITE_PRIVATE int sqlite3JournalExists(sqlite3_file *p){
    +-  return (p->pMethods!=&JournalFileMethods || ((JournalFile *)p)->pReal!=0);
    +-}
    +-
    +-/* 
    +-** Return the number of bytes required to store a JournalFile that uses vfs
    +-** pVfs to create the underlying on-disk files.
    +-*/
    +-SQLITE_PRIVATE int sqlite3JournalSize(sqlite3_vfs *pVfs){
    +-  return (pVfs->szOsFile+sizeof(JournalFile));
    +-}
    +-#endif
    +-
    +-/************** End of journal.c *********************************************/
    + /************** Begin file memjournal.c **************************************/
    + /*
    + ** 2008 October 7
    +@@ -83078,6 +90567,15 @@ SQLITE_PRIVATE int sqlite3JournalSize(sqlite3_vfs *pVfs){
    + ** This file contains code use to implement an in-memory rollback journal.
    + ** The in-memory rollback journal is used to journal transactions for
    + ** ":memory:" databases and when the journal_mode=MEMORY pragma is used.
    ++**
    ++** Update:  The in-memory journal is also used to temporarily cache
    ++** smaller journals that are not critical for power-loss recovery.
    ++** For example, statement journals that are not too big will be held
    ++** entirely in memory, thus reducing the number of file I/O calls, and
    ++** more importantly, reducing temporary file creation events.  If these
    ++** journals become too large for memory, they are spilled to disk.  But
    ++** in the common case, they are usually small and no file I/O needs to
    ++** occur.
    + */
    + /* #include "sqliteInt.h" */
    + 
    +@@ -83086,24 +90584,28 @@ typedef struct MemJournal MemJournal;
    + typedef struct FilePoint FilePoint;
    + typedef struct FileChunk FileChunk;
    + 
    +-/* Space to hold the rollback journal is allocated in increments of
    +-** this many bytes.
    +-**
    +-** The size chosen is a little less than a power of two.  That way,
    +-** the FileChunk object will have a size that almost exactly fills
    +-** a power-of-two allocation.  This minimizes wasted space in power-of-two
    +-** memory allocators.
    +-*/
    +-#define JOURNAL_CHUNKSIZE ((int)(1024-sizeof(FileChunk*)))
    +-
    + /*
    + ** The rollback journal is composed of a linked list of these structures.
    ++**
    ++** The zChunk array is always at least 8 bytes in size - usually much more.
    ++** Its actual size is stored in the MemJournal.nChunkSize variable.
    + */
    + struct FileChunk {
    +   FileChunk *pNext;               /* Next chunk in the journal */
    +-  u8 zChunk[JOURNAL_CHUNKSIZE];   /* Content of this chunk */
    ++  u8 zChunk[8];                   /* Content of this chunk */
    + };
    + 
    ++/*
    ++** By default, allocate this many bytes of memory for each FileChunk object.
    ++*/
    ++#define MEMJOURNAL_DFLT_FILECHUNKSIZE 1024
    ++
    ++/*
    ++** For chunk size nChunkSize, return the number of bytes that should
    ++** be allocated for each FileChunk structure.
    ++*/
    ++#define fileChunkSize(nChunkSize) (sizeof(FileChunk) + ((nChunkSize)-8))
    ++
    + /*
    + ** An instance of this object serves as a cursor into the rollback journal.
    + ** The cursor can be either for reading or writing.
    +@@ -83114,14 +90616,22 @@ struct FilePoint {
    + };
    + 
    + /*
    +-** This subclass is a subclass of sqlite3_file.  Each open memory-journal
    ++** This structure is a subclass of sqlite3_file. Each open memory-journal
    + ** is an instance of this class.
    + */
    + struct MemJournal {
    +-  sqlite3_io_methods *pMethod;    /* Parent class. MUST BE FIRST */
    ++  const sqlite3_io_methods *pMethod; /* Parent class. MUST BE FIRST */
    ++  int nChunkSize;                 /* In-memory chunk-size */
    ++
    ++  int nSpill;                     /* Bytes of data before flushing */
    ++  int nSize;                      /* Bytes of data currently in memory */
    +   FileChunk *pFirst;              /* Head of in-memory chunk-list */
    +   FilePoint endpoint;             /* Pointer to the end of the file */
    +   FilePoint readpoint;            /* Pointer to the end of the last xRead() */
    ++
    ++  int flags;                      /* xOpen flags */
    ++  sqlite3_vfs *pVfs;              /* The "real" underlying VFS */
    ++  const char *zJournal;           /* Name of the journal file */
    + };
    + 
    + /*
    +@@ -83140,36 +90650,95 @@ static int memjrnlRead(
    +   int iChunkOffset;
    +   FileChunk *pChunk;
    + 
    +-  /* SQLite never tries to read past the end of a rollback journal file */
    +-  assert( iOfst+iAmt<=p->endpoint.iOffset );
    ++#if defined(SQLITE_ENABLE_ATOMIC_WRITE) \
    ++ || defined(SQLITE_ENABLE_BATCH_ATOMIC_WRITE)
    ++  if( (iAmt+iOfst)>p->endpoint.iOffset ){
    ++    return SQLITE_IOERR_SHORT_READ;
    ++  }
    ++#endif
    + 
    ++  assert( (iAmt+iOfst)<=p->endpoint.iOffset );
    ++  assert( p->readpoint.iOffset==0 || p->readpoint.pChunk!=0 );
    +   if( p->readpoint.iOffset!=iOfst || iOfst==0 ){
    +     sqlite3_int64 iOff = 0;
    +     for(pChunk=p->pFirst; 
    +-        ALWAYS(pChunk) && (iOff+JOURNAL_CHUNKSIZE)<=iOfst;
    ++        ALWAYS(pChunk) && (iOff+p->nChunkSize)<=iOfst;
    +         pChunk=pChunk->pNext
    +     ){
    +-      iOff += JOURNAL_CHUNKSIZE;
    ++      iOff += p->nChunkSize;
    +     }
    +   }else{
    +     pChunk = p->readpoint.pChunk;
    ++    assert( pChunk!=0 );
    +   }
    + 
    +-  iChunkOffset = (int)(iOfst%JOURNAL_CHUNKSIZE);
    ++  iChunkOffset = (int)(iOfst%p->nChunkSize);
    +   do {
    +-    int iSpace = JOURNAL_CHUNKSIZE - iChunkOffset;
    +-    int nCopy = MIN(nRead, (JOURNAL_CHUNKSIZE - iChunkOffset));
    +-    memcpy(zOut, &pChunk->zChunk[iChunkOffset], nCopy);
    ++    int iSpace = p->nChunkSize - iChunkOffset;
    ++    int nCopy = MIN(nRead, (p->nChunkSize - iChunkOffset));
    ++    memcpy(zOut, (u8*)pChunk->zChunk + iChunkOffset, nCopy);
    +     zOut += nCopy;
    +     nRead -= iSpace;
    +     iChunkOffset = 0;
    +   } while( nRead>=0 && (pChunk=pChunk->pNext)!=0 && nRead>0 );
    +-  p->readpoint.iOffset = iOfst+iAmt;
    ++  p->readpoint.iOffset = pChunk ? iOfst+iAmt : 0;
    +   p->readpoint.pChunk = pChunk;
    + 
    +   return SQLITE_OK;
    + }
    + 
    ++/*
    ++** Free the list of FileChunk structures headed at MemJournal.pFirst.
    ++*/
    ++static void memjrnlFreeChunks(MemJournal *p){
    ++  FileChunk *pIter;
    ++  FileChunk *pNext;
    ++  for(pIter=p->pFirst; pIter; pIter=pNext){
    ++    pNext = pIter->pNext;
    ++    sqlite3_free(pIter);
    ++  } 
    ++  p->pFirst = 0;
    ++}
    ++
    ++/*
    ++** Flush the contents of memory to a real file on disk.
    ++*/
    ++static int memjrnlCreateFile(MemJournal *p){
    ++  int rc;
    ++  sqlite3_file *pReal = (sqlite3_file*)p;
    ++  MemJournal copy = *p;
    ++
    ++  memset(p, 0, sizeof(MemJournal));
    ++  rc = sqlite3OsOpen(copy.pVfs, copy.zJournal, pReal, copy.flags, 0);
    ++  if( rc==SQLITE_OK ){
    ++    int nChunk = copy.nChunkSize;
    ++    i64 iOff = 0;
    ++    FileChunk *pIter;
    ++    for(pIter=copy.pFirst; pIter; pIter=pIter->pNext){
    ++      if( iOff + nChunk > copy.endpoint.iOffset ){
    ++        nChunk = copy.endpoint.iOffset - iOff;
    ++      }
    ++      rc = sqlite3OsWrite(pReal, (u8*)pIter->zChunk, nChunk, iOff);
    ++      if( rc ) break;
    ++      iOff += nChunk;
    ++    }
    ++    if( rc==SQLITE_OK ){
    ++      /* No error has occurred. Free the in-memory buffers. */
    ++      memjrnlFreeChunks(&copy);
    ++    }
    ++  }
    ++  if( rc!=SQLITE_OK ){
    ++    /* If an error occurred while creating or writing to the file, restore
    ++    ** the original before returning. This way, SQLite uses the in-memory
    ++    ** journal data to roll back changes made to the internal page-cache
    ++    ** before this function was called.  */
    ++    sqlite3OsClose(pReal);
    ++    *p = copy;
    ++  }
    ++  return rc;
    ++}
    ++
    ++
    + /*
    + ** Write data to the file.
    + */
    +@@ -83183,38 +90752,63 @@ static int memjrnlWrite(
    +   int nWrite = iAmt;
    +   u8 *zWrite = (u8 *)zBuf;
    + 
    +-  /* An in-memory journal file should only ever be appended to. Random
    +-  ** access writes are not required by sqlite.
    +-  */
    +-  assert( iOfst==p->endpoint.iOffset );
    +-  UNUSED_PARAMETER(iOfst);
    ++  /* If the file should be created now, create it and write the new data
    ++  ** into the file on disk. */
    ++  if( p->nSpill>0 && (iAmt+iOfst)>p->nSpill ){
    ++    int rc = memjrnlCreateFile(p);
    ++    if( rc==SQLITE_OK ){
    ++      rc = sqlite3OsWrite(pJfd, zBuf, iAmt, iOfst);
    ++    }
    ++    return rc;
    ++  }
    + 
    +-  while( nWrite>0 ){
    +-    FileChunk *pChunk = p->endpoint.pChunk;
    +-    int iChunkOffset = (int)(p->endpoint.iOffset%JOURNAL_CHUNKSIZE);
    +-    int iSpace = MIN(nWrite, JOURNAL_CHUNKSIZE - iChunkOffset);
    ++  /* If the contents of this write should be stored in memory */
    ++  else{
    ++    /* An in-memory journal file should only ever be appended to. Random
    ++    ** access writes are not required. The only exception to this is when
    ++    ** the in-memory journal is being used by a connection using the
    ++    ** atomic-write optimization. In this case the first 28 bytes of the
    ++    ** journal file may be written as part of committing the transaction. */ 
    ++    assert( iOfst==p->endpoint.iOffset || iOfst==0 );
    ++#if defined(SQLITE_ENABLE_ATOMIC_WRITE) \
    ++ || defined(SQLITE_ENABLE_BATCH_ATOMIC_WRITE)
    ++    if( iOfst==0 && p->pFirst ){
    ++      assert( p->nChunkSize>iAmt );
    ++      memcpy((u8*)p->pFirst->zChunk, zBuf, iAmt);
    ++    }else
    ++#else
    ++    assert( iOfst>0 || p->pFirst==0 );
    ++#endif
    ++    {
    ++      while( nWrite>0 ){
    ++        FileChunk *pChunk = p->endpoint.pChunk;
    ++        int iChunkOffset = (int)(p->endpoint.iOffset%p->nChunkSize);
    ++        int iSpace = MIN(nWrite, p->nChunkSize - iChunkOffset);
    ++
    ++        if( iChunkOffset==0 ){
    ++          /* New chunk is required to extend the file. */
    ++          FileChunk *pNew = sqlite3_malloc(fileChunkSize(p->nChunkSize));
    ++          if( !pNew ){
    ++            return SQLITE_IOERR_NOMEM_BKPT;
    ++          }
    ++          pNew->pNext = 0;
    ++          if( pChunk ){
    ++            assert( p->pFirst );
    ++            pChunk->pNext = pNew;
    ++          }else{
    ++            assert( !p->pFirst );
    ++            p->pFirst = pNew;
    ++          }
    ++          p->endpoint.pChunk = pNew;
    ++        }
    + 
    +-    if( iChunkOffset==0 ){
    +-      /* New chunk is required to extend the file. */
    +-      FileChunk *pNew = sqlite3_malloc(sizeof(FileChunk));
    +-      if( !pNew ){
    +-        return SQLITE_IOERR_NOMEM;
    ++        memcpy((u8*)p->endpoint.pChunk->zChunk + iChunkOffset, zWrite, iSpace);
    ++        zWrite += iSpace;
    ++        nWrite -= iSpace;
    ++        p->endpoint.iOffset += iSpace;
    +       }
    +-      pNew->pNext = 0;
    +-      if( pChunk ){
    +-        assert( p->pFirst );
    +-        pChunk->pNext = pNew;
    +-      }else{
    +-        assert( !p->pFirst );
    +-        p->pFirst = pNew;
    +-      }
    +-      p->endpoint.pChunk = pNew;
    ++      p->nSize = iAmt + iOfst;
    +     }
    +-
    +-    memcpy(&p->endpoint.pChunk->zChunk[iChunkOffset], zWrite, iSpace);
    +-    zWrite += iSpace;
    +-    nWrite -= iSpace;
    +-    p->endpoint.iOffset += iSpace;
    +   }
    + 
    +   return SQLITE_OK;
    +@@ -83222,19 +90816,21 @@ static int memjrnlWrite(
    + 
    + /*
    + ** Truncate the file.
    ++**
    ++** If the journal file is already on disk, truncate it there. Or, if it
    ++** is still in main memory but is being truncated to zero bytes in size,
    ++** ignore 
    + */
    + static int memjrnlTruncate(sqlite3_file *pJfd, sqlite_int64 size){
    +   MemJournal *p = (MemJournal *)pJfd;
    +-  FileChunk *pChunk;
    +-  assert(size==0);
    +-  UNUSED_PARAMETER(size);
    +-  pChunk = p->pFirst;
    +-  while( pChunk ){
    +-    FileChunk *pTmp = pChunk;
    +-    pChunk = pChunk->pNext;
    +-    sqlite3_free(pTmp);
    +-  }
    +-  sqlite3MemJournalOpen(pJfd);
    ++  if( ALWAYS(size==0) ){
    ++    memjrnlFreeChunks(p);
    ++    p->nSize = 0;
    ++    p->endpoint.pChunk = 0;
    ++    p->endpoint.iOffset = 0;
    ++    p->readpoint.pChunk = 0;
    ++    p->readpoint.iOffset = 0;
    ++  }
    +   return SQLITE_OK;
    + }
    + 
    +@@ -83242,21 +90838,19 @@ static int memjrnlTruncate(sqlite3_file *pJfd, sqlite_int64 size){
    + ** Close the file.
    + */
    + static int memjrnlClose(sqlite3_file *pJfd){
    +-  memjrnlTruncate(pJfd, 0);
    ++  MemJournal *p = (MemJournal *)pJfd;
    ++  memjrnlFreeChunks(p);
    +   return SQLITE_OK;
    + }
    + 
    +-
    + /*
    + ** Sync the file.
    + **
    +-** Syncing an in-memory journal is a no-op.  And, in fact, this routine
    +-** is never called in a working implementation.  This implementation
    +-** exists purely as a contingency, in case some malfunction in some other
    +-** part of SQLite causes Sync to be called by mistake.
    ++** If the real file has been created, call its xSync method. Otherwise, 
    ++** syncing an in-memory journal is a no-op. 
    + */
    +-static int memjrnlSync(sqlite3_file *NotUsed, int NotUsed2){
    +-  UNUSED_PARAMETER2(NotUsed, NotUsed2);
    ++static int memjrnlSync(sqlite3_file *pJfd, int flags){
    ++  UNUSED_PARAMETER2(pJfd, flags);
    +   return SQLITE_OK;
    + }
    + 
    +@@ -83295,28 +90889,102 @@ static const struct sqlite3_io_methods MemJournalMethods = {
    + };
    + 
    + /* 
    +-** Open a journal file.
    ++** Open a journal file. 
    ++**
    ++** The behaviour of the journal file depends on the value of parameter 
    ++** nSpill. If nSpill is 0, then the journal file is always create and 
    ++** accessed using the underlying VFS. If nSpill is less than zero, then
    ++** all content is always stored in main-memory. Finally, if nSpill is a
    ++** positive value, then the journal file is initially created in-memory
    ++** but may be flushed to disk later on. In this case the journal file is
    ++** flushed to disk either when it grows larger than nSpill bytes in size,
    ++** or when sqlite3JournalCreate() is called.
    ++*/
    ++SQLITE_PRIVATE int sqlite3JournalOpen(
    ++  sqlite3_vfs *pVfs,         /* The VFS to use for actual file I/O */
    ++  const char *zName,         /* Name of the journal file */
    ++  sqlite3_file *pJfd,        /* Preallocated, blank file handle */
    ++  int flags,                 /* Opening flags */
    ++  int nSpill                 /* Bytes buffered before opening the file */
    ++){
    ++  MemJournal *p = (MemJournal*)pJfd;
    ++
    ++  /* Zero the file-handle object. If nSpill was passed zero, initialize
    ++  ** it using the sqlite3OsOpen() function of the underlying VFS. In this
    ++  ** case none of the code in this module is executed as a result of calls
    ++  ** made on the journal file-handle.  */
    ++  memset(p, 0, sizeof(MemJournal));
    ++  if( nSpill==0 ){
    ++    return sqlite3OsOpen(pVfs, zName, pJfd, flags, 0);
    ++  }
    ++
    ++  if( nSpill>0 ){
    ++    p->nChunkSize = nSpill;
    ++  }else{
    ++    p->nChunkSize = 8 + MEMJOURNAL_DFLT_FILECHUNKSIZE - sizeof(FileChunk);
    ++    assert( MEMJOURNAL_DFLT_FILECHUNKSIZE==fileChunkSize(p->nChunkSize) );
    ++  }
    ++
    ++  p->pMethod = (const sqlite3_io_methods*)&MemJournalMethods;
    ++  p->nSpill = nSpill;
    ++  p->flags = flags;
    ++  p->zJournal = zName;
    ++  p->pVfs = pVfs;
    ++  return SQLITE_OK;
    ++}
    ++
    ++/*
    ++** Open an in-memory journal file.
    + */
    + SQLITE_PRIVATE void sqlite3MemJournalOpen(sqlite3_file *pJfd){
    +-  MemJournal *p = (MemJournal *)pJfd;
    +-  assert( EIGHT_BYTE_ALIGNMENT(p) );
    +-  memset(p, 0, sqlite3MemJournalSize());
    +-  p->pMethod = (sqlite3_io_methods*)&MemJournalMethods;
    ++  sqlite3JournalOpen(0, 0, pJfd, 0, -1);
    ++}
    ++
    ++#if defined(SQLITE_ENABLE_ATOMIC_WRITE) \
    ++ || defined(SQLITE_ENABLE_BATCH_ATOMIC_WRITE)
    ++/*
    ++** If the argument p points to a MemJournal structure that is not an 
    ++** in-memory-only journal file (i.e. is one that was opened with a +ve
    ++** nSpill parameter or as SQLITE_OPEN_MAIN_JOURNAL), and the underlying 
    ++** file has not yet been created, create it now.
    ++*/
    ++SQLITE_PRIVATE int sqlite3JournalCreate(sqlite3_file *pJfd){
    ++  int rc = SQLITE_OK;
    ++  MemJournal *p = (MemJournal*)pJfd;
    ++  if( p->pMethod==&MemJournalMethods && (
    ++#ifdef SQLITE_ENABLE_ATOMIC_WRITE
    ++     p->nSpill>0
    ++#else
    ++     /* While this appears to not be possible without ATOMIC_WRITE, the
    ++     ** paths are complex, so it seems prudent to leave the test in as
    ++     ** a NEVER(), in case our analysis is subtly flawed. */
    ++     NEVER(p->nSpill>0)
    ++#endif
    ++#ifdef SQLITE_ENABLE_BATCH_ATOMIC_WRITE
    ++     || (p->flags & SQLITE_OPEN_MAIN_JOURNAL)
    ++#endif
    ++  )){
    ++    rc = memjrnlCreateFile(p);
    ++  }
    ++  return rc;
    + }
    ++#endif
    + 
    + /*
    +-** Return true if the file-handle passed as an argument is 
    +-** an in-memory journal 
    ++** The file-handle passed as the only argument is open on a journal file.
    ++** Return true if this "journal file" is currently stored in heap memory,
    ++** or false otherwise.
    + */
    +-SQLITE_PRIVATE int sqlite3IsMemJournal(sqlite3_file *pJfd){
    +-  return pJfd->pMethods==&MemJournalMethods;
    ++SQLITE_PRIVATE int sqlite3JournalIsInMemory(sqlite3_file *p){
    ++  return p->pMethods==&MemJournalMethods;
    + }
    + 
    + /* 
    +-** Return the number of bytes required to store a MemJournal file descriptor.
    ++** Return the number of bytes required to store a JournalFile that uses vfs
    ++** pVfs to create the underlying on-disk files.
    + */
    +-SQLITE_PRIVATE int sqlite3MemJournalSize(void){
    +-  return sizeof(MemJournal);
    ++SQLITE_PRIVATE int sqlite3JournalSize(sqlite3_vfs *pVfs){
    ++  return MAX(pVfs->szOsFile, (int)sizeof(MemJournal));
    + }
    + 
    + /************** End of memjournal.c ******************************************/
    +@@ -83350,32 +91018,40 @@ SQLITE_PRIVATE int sqlite3MemJournalSize(void){
    + **
    + **    WRC_Continue      Continue descending down the tree.
    + **
    +-**    WRC_Prune         Do not descend into child nodes.  But allow
    ++**    WRC_Prune         Do not descend into child nodes, but allow
    + **                      the walk to continue with sibling nodes.
    + **
    + **    WRC_Abort         Do no more callbacks.  Unwind the stack and
    +-**                      return the top-level walk call.
    ++**                      return from the top-level walk call.
    + **
    + ** The return value from this routine is WRC_Abort to abandon the tree walk
    + ** and WRC_Continue to continue.
    + */
    +-SQLITE_PRIVATE int sqlite3WalkExpr(Walker *pWalker, Expr *pExpr){
    ++static SQLITE_NOINLINE int walkExpr(Walker *pWalker, Expr *pExpr){
    +   int rc;
    +-  if( pExpr==0 ) return WRC_Continue;
    +   testcase( ExprHasProperty(pExpr, EP_TokenOnly) );
    +   testcase( ExprHasProperty(pExpr, EP_Reduced) );
    +-  rc = pWalker->xExprCallback(pWalker, pExpr);
    +-  if( rc==WRC_Continue
    +-              && !ExprHasProperty(pExpr,EP_TokenOnly) ){
    +-    if( sqlite3WalkExpr(pWalker, pExpr->pLeft) ) return WRC_Abort;
    +-    if( sqlite3WalkExpr(pWalker, pExpr->pRight) ) return WRC_Abort;
    +-    if( ExprHasProperty(pExpr, EP_xIsSelect) ){
    +-      if( sqlite3WalkSelect(pWalker, pExpr->x.pSelect) ) return WRC_Abort;
    +-    }else{
    +-      if( sqlite3WalkExprList(pWalker, pExpr->x.pList) ) return WRC_Abort;
    ++  while(1){
    ++    rc = pWalker->xExprCallback(pWalker, pExpr);
    ++    if( rc ) return rc & WRC_Abort;
    ++    if( !ExprHasProperty(pExpr,(EP_TokenOnly|EP_Leaf)) ){
    ++      if( pExpr->pLeft && walkExpr(pWalker, pExpr->pLeft) ) return WRC_Abort;
    ++       assert( pExpr->x.pList==0 || pExpr->pRight==0 );
    ++      if( pExpr->pRight ){
    ++        pExpr = pExpr->pRight;
    ++        continue;
    ++      }else if( ExprHasProperty(pExpr, EP_xIsSelect) ){
    ++        if( sqlite3WalkSelect(pWalker, pExpr->x.pSelect) ) return WRC_Abort;
    ++      }else if( pExpr->x.pList ){
    ++        if( sqlite3WalkExprList(pWalker, pExpr->x.pList) ) return WRC_Abort;
    ++      }
    +     }
    ++    break;
    +   }
    +-  return rc & WRC_Abort;
    ++  return WRC_Continue;
    ++}
    ++SQLITE_PRIVATE int sqlite3WalkExpr(Walker *pWalker, Expr *pExpr){
    ++  return pExpr ? walkExpr(pWalker,pExpr) : WRC_Continue;
    + }
    + 
    + /*
    +@@ -83406,7 +91082,6 @@ SQLITE_PRIVATE int sqlite3WalkSelectExpr(Walker *pWalker, Select *p){
    +   if( sqlite3WalkExpr(pWalker, p->pHaving) ) return WRC_Abort;
    +   if( sqlite3WalkExprList(pWalker, p->pOrderBy) ) return WRC_Abort;
    +   if( sqlite3WalkExpr(pWalker, p->pLimit) ) return WRC_Abort;
    +-  if( sqlite3WalkExpr(pWalker, p->pOffset) ) return WRC_Abort;
    +   return WRC_Continue;
    + }
    + 
    +@@ -83423,16 +91098,15 @@ SQLITE_PRIVATE int sqlite3WalkSelectFrom(Walker *pWalker, Select *p){
    +   struct SrcList_item *pItem;
    + 
    +   pSrc = p->pSrc;
    +-  if( ALWAYS(pSrc) ){
    +-    for(i=pSrc->nSrc, pItem=pSrc->a; i>0; i--, pItem++){
    +-      if( sqlite3WalkSelect(pWalker, pItem->pSelect) ){
    +-        return WRC_Abort;
    +-      }
    +-      if( pItem->fg.isTabFunc
    +-       && sqlite3WalkExprList(pWalker, pItem->u1.pFuncArg)
    +-      ){
    +-        return WRC_Abort;
    +-      }
    ++  assert( pSrc!=0 );
    ++  for(i=pSrc->nSrc, pItem=pSrc->a; i>0; i--, pItem++){
    ++    if( pItem->pSelect && sqlite3WalkSelect(pWalker, pItem->pSelect) ){
    ++      return WRC_Abort;
    ++    }
    ++    if( pItem->fg.isTabFunc
    ++     && sqlite3WalkExprList(pWalker, pItem->u1.pFuncArg)
    ++    ){
    ++      return WRC_Abort;
    +     }
    +   }
    +   return WRC_Continue;
    +@@ -83445,8 +91119,9 @@ SQLITE_PRIVATE int sqlite3WalkSelectFrom(Walker *pWalker, Select *p){
    + **
    + ** If it is not NULL, the xSelectCallback() callback is invoked before
    + ** the walk of the expressions and FROM clause. The xSelectCallback2()
    +-** method, if it is not NULL, is invoked following the walk of the 
    +-** expressions and FROM clause.
    ++** method is invoked following the walk of the expressions and FROM clause,
    ++** but only if both xSelectCallback and xSelectCallback2 are both non-NULL
    ++** and if the expressions and FROM clause both return WRC_Continue;
    + **
    + ** Return WRC_Continue under normal conditions.  Return WRC_Abort if
    + ** there is an abort request.
    +@@ -83456,29 +91131,22 @@ SQLITE_PRIVATE int sqlite3WalkSelectFrom(Walker *pWalker, Select *p){
    + */
    + SQLITE_PRIVATE int sqlite3WalkSelect(Walker *pWalker, Select *p){
    +   int rc;
    +-  if( p==0 || (pWalker->xSelectCallback==0 && pWalker->xSelectCallback2==0) ){
    +-    return WRC_Continue;
    +-  }
    +-  rc = WRC_Continue;
    +-  pWalker->walkerDepth++;
    +-  while( p ){
    +-    if( pWalker->xSelectCallback ){
    +-       rc = pWalker->xSelectCallback(pWalker, p);
    +-       if( rc ) break;
    +-    }
    ++  if( p==0 ) return WRC_Continue;
    ++  if( pWalker->xSelectCallback==0 ) return WRC_Continue;
    ++  do{
    ++    rc = pWalker->xSelectCallback(pWalker, p);
    ++    if( rc ) return rc & WRC_Abort;
    +     if( sqlite3WalkSelectExpr(pWalker, p)
    +      || sqlite3WalkSelectFrom(pWalker, p)
    +     ){
    +-      pWalker->walkerDepth--;
    +       return WRC_Abort;
    +     }
    +     if( pWalker->xSelectCallback2 ){
    +       pWalker->xSelectCallback2(pWalker, p);
    +     }
    +     p = p->pPrior;
    +-  }
    +-  pWalker->walkerDepth--;
    +-  return rc & WRC_Abort;
    ++  }while( p!=0 );
    ++  return WRC_Continue;
    + }
    + 
    + /************** End of walker.c **********************************************/
    +@@ -83500,8 +91168,6 @@ SQLITE_PRIVATE int sqlite3WalkSelect(Walker *pWalker, Select *p){
    + ** table and column.
    + */
    + /* #include "sqliteInt.h" */
    +-/* #include <stdlib.h> */
    +-/* #include <string.h> */
    + 
    + /*
    + ** Walk the expression tree pExpr and increase the aggregate function
    +@@ -83706,8 +91372,8 @@ static int lookupName(
    +       zDb = 0;
    +     }else{
    +       for(i=0; i<db->nDb; i++){
    +-        assert( db->aDb[i].zName );
    +-        if( sqlite3StrICmp(db->aDb[i].zName,zDb)==0 ){
    ++        assert( db->aDb[i].zDbSName );
    ++        if( sqlite3StrICmp(db->aDb[i].zDbSName,zDb)==0 ){
    +           pSchema = db->aDb[i].pSchema;
    +           break;
    +         }
    +@@ -83716,7 +91382,8 @@ static int lookupName(
    +   }
    + 
    +   /* Start at the inner-most context and move outward until a match is found */
    +-  while( pNC && cnt==0 ){
    ++  assert( pNC && cnt==0 );
    ++  do{
    +     ExprList *pEList;
    +     SrcList *pSrcList = pNC->pSrcList;
    + 
    +@@ -83813,7 +91480,6 @@ static int lookupName(
    +         }
    +         if( iCol>=pTab->nCol && sqlite3IsRowid(zCol) && VisibleRowid(pTab) ){
    +           /* IMP: R-51414-32910 */
    +-          /* IMP: R-44911-55124 */
    +           iCol = -1;
    +         }
    +         if( iCol<pTab->nCol ){
    +@@ -83848,7 +91514,7 @@ static int lookupName(
    +      && VisibleRowid(pMatch->pTab)
    +     ){
    +       cnt = 1;
    +-      pExpr->iColumn = -1;     /* IMP: R-44911-55124 */
    ++      pExpr->iColumn = -1;
    +       pExpr->affinity = SQLITE_AFF_INTEGER;
    +     }
    + 
    +@@ -83886,6 +91552,10 @@ static int lookupName(
    +             sqlite3ErrorMsg(pParse, "misuse of aliased aggregate %s", zAs);
    +             return WRC_Abort;
    +           }
    ++          if( sqlite3ExprVectorSize(pOrig)!=1 ){
    ++            sqlite3ErrorMsg(pParse, "row value misused");
    ++            return WRC_Abort;
    ++          }
    +           resolveAlias(pParse, pEList, j, pExpr, "", nSubquery);
    +           cnt = 1;
    +           pMatch = 0;
    +@@ -83898,11 +91568,11 @@ static int lookupName(
    +     /* Advance to the next name context.  The loop will exit when either
    +     ** we have a match (cnt>0) or when we run out of name contexts.
    +     */
    +-    if( cnt==0 ){
    +-      pNC = pNC->pNext;
    +-      nSubquery++;
    +-    }
    +-  }
    ++    if( cnt ) break;
    ++    pNC = pNC->pNext;
    ++    nSubquery++;
    ++  }while( pNC );
    ++
    + 
    +   /*
    +   ** If X and Y are NULL (in other words if only the column name Z is
    +@@ -83961,6 +91631,7 @@ static int lookupName(
    +   sqlite3ExprDelete(db, pExpr->pRight);
    +   pExpr->pRight = 0;
    +   pExpr->op = (isTrigger ? TK_TRIGGER : TK_COLUMN);
    ++  ExprSetProperty(pExpr, EP_Leaf);
    + lookupname_end:
    +   if( cnt==1 ){
    +     assert( pNC!=0 );
    +@@ -83999,7 +91670,6 @@ SQLITE_PRIVATE Expr *sqlite3CreateColumnExpr(sqlite3 *db, SrcList *pSrc, int iSr
    +       testcase( iCol==BMS-1 );
    +       pItem->colUsed |= ((Bitmask)1)<<(iCol>=BMS ? BMS-1 : iCol);
    +     }
    +-    ExprSetProperty(p, EP_Resolved);
    +   }
    +   return p;
    + }
    +@@ -84059,8 +91729,6 @@ static int resolveExprStep(Walker *pWalker, Expr *pExpr){
    +   pParse = pNC->pParse;
    +   assert( pParse==pWalker->pParse );
    + 
    +-  if( ExprHasProperty(pExpr, EP_Resolved) ) return WRC_Prune;
    +-  ExprSetProperty(pExpr, EP_Resolved);
    + #ifndef NDEBUG
    +   if( pNC->pSrcList && pNC->pSrcList->nAlloc>0 ){
    +     SrcList *pSrcList = pNC->pSrcList;
    +@@ -84081,7 +91749,8 @@ static int resolveExprStep(Walker *pWalker, Expr *pExpr){
    +       SrcList *pSrcList = pNC->pSrcList;
    +       struct SrcList_item *pItem;
    +       assert( pSrcList && pSrcList->nSrc==1 );
    +-      pItem = pSrcList->a; 
    ++      pItem = pSrcList->a;
    ++      assert( HasRowid(pItem->pTab) && pItem->pTab->pSelect==0 );
    +       pExpr->op = TK_COLUMN;
    +       pExpr->pTab = pItem->pTab;
    +       pExpr->iTable = pItem->iCursor;
    +@@ -84092,34 +91761,38 @@ static int resolveExprStep(Walker *pWalker, Expr *pExpr){
    + #endif /* defined(SQLITE_ENABLE_UPDATE_DELETE_LIMIT)
    +           && !defined(SQLITE_OMIT_SUBQUERY) */
    + 
    +-    /* A lone identifier is the name of a column.
    +-    */
    +-    case TK_ID: {
    +-      return lookupName(pParse, 0, 0, pExpr->u.zToken, pNC, pExpr);
    +-    }
    +-  
    +-    /* A table name and column name:     ID.ID
    ++    /* A column name:                    ID
    ++    ** Or table name and column name:    ID.ID
    +     ** Or a database, table and column:  ID.ID.ID
    ++    **
    ++    ** The TK_ID and TK_OUT cases are combined so that there will only
    ++    ** be one call to lookupName().  Then the compiler will in-line 
    ++    ** lookupName() for a size reduction and performance increase.
    +     */
    ++    case TK_ID:
    +     case TK_DOT: {
    +       const char *zColumn;
    +       const char *zTable;
    +       const char *zDb;
    +       Expr *pRight;
    + 
    +-      /* if( pSrcList==0 ) break; */
    +-      notValid(pParse, pNC, "the \".\" operator", NC_IdxExpr);
    +-      /*notValid(pParse, pNC, "the \".\" operator", NC_PartIdx|NC_IsCheck, 1);*/
    +-      pRight = pExpr->pRight;
    +-      if( pRight->op==TK_ID ){
    ++      if( pExpr->op==TK_ID ){
    +         zDb = 0;
    +-        zTable = pExpr->pLeft->u.zToken;
    +-        zColumn = pRight->u.zToken;
    ++        zTable = 0;
    ++        zColumn = pExpr->u.zToken;
    +       }else{
    +-        assert( pRight->op==TK_DOT );
    +-        zDb = pExpr->pLeft->u.zToken;
    +-        zTable = pRight->pLeft->u.zToken;
    +-        zColumn = pRight->pRight->u.zToken;
    ++        notValid(pParse, pNC, "the \".\" operator", NC_IdxExpr);
    ++        pRight = pExpr->pRight;
    ++        if( pRight->op==TK_ID ){
    ++          zDb = 0;
    ++          zTable = pExpr->pLeft->u.zToken;
    ++          zColumn = pRight->u.zToken;
    ++        }else{
    ++          assert( pRight->op==TK_DOT );
    ++          zDb = pExpr->pLeft->u.zToken;
    ++          zTable = pRight->pLeft->u.zToken;
    ++          zColumn = pRight->pRight->u.zToken;
    ++        }
    +       }
    +       return lookupName(pParse, zDb, zTable, zColumn, pNC, pExpr);
    +     }
    +@@ -84132,26 +91805,24 @@ static int resolveExprStep(Walker *pWalker, Expr *pExpr){
    +       int no_such_func = 0;       /* True if no such function exists */
    +       int wrong_num_args = 0;     /* True if wrong number of arguments */
    +       int is_agg = 0;             /* True if is an aggregate function */
    +-      int auth;                   /* Authorization to use the function */
    +       int nId;                    /* Number of characters in function name */
    +       const char *zId;            /* The function name. */
    +       FuncDef *pDef;              /* Information about the function */
    +       u8 enc = ENC(pParse->db);   /* The database encoding */
    + 
    +       assert( !ExprHasProperty(pExpr, EP_xIsSelect) );
    +-      notValid(pParse, pNC, "functions", NC_PartIdx);
    +       zId = pExpr->u.zToken;
    +       nId = sqlite3Strlen30(zId);
    +-      pDef = sqlite3FindFunction(pParse->db, zId, nId, n, enc, 0);
    ++      pDef = sqlite3FindFunction(pParse->db, zId, n, enc, 0);
    +       if( pDef==0 ){
    +-        pDef = sqlite3FindFunction(pParse->db, zId, nId, -2, enc, 0);
    ++        pDef = sqlite3FindFunction(pParse->db, zId, -2, enc, 0);
    +         if( pDef==0 ){
    +           no_such_func = 1;
    +         }else{
    +           wrong_num_args = 1;
    +         }
    +       }else{
    +-        is_agg = pDef->xFunc==0;
    ++        is_agg = pDef->xFinalize!=0;
    +         if( pDef->funcFlags & SQLITE_FUNC_UNLIKELY ){
    +           ExprSetProperty(pExpr, EP_Unlikely|EP_Skip);
    +           if( n==2 ){
    +@@ -84176,15 +91847,17 @@ static int resolveExprStep(Walker *pWalker, Expr *pExpr){
    +           }             
    +         }
    + #ifndef SQLITE_OMIT_AUTHORIZATION
    +-        auth = sqlite3AuthCheck(pParse, SQLITE_FUNCTION, 0, pDef->zName, 0);
    +-        if( auth!=SQLITE_OK ){
    +-          if( auth==SQLITE_DENY ){
    +-            sqlite3ErrorMsg(pParse, "not authorized to use function: %s",
    +-                                    pDef->zName);
    +-            pNC->nErr++;
    ++        {
    ++          int auth = sqlite3AuthCheck(pParse, SQLITE_FUNCTION, 0,pDef->zName,0);
    ++          if( auth!=SQLITE_OK ){
    ++            if( auth==SQLITE_DENY ){
    ++              sqlite3ErrorMsg(pParse, "not authorized to use function: %s",
    ++                                      pDef->zName);
    ++              pNC->nErr++;
    ++            }
    ++            pExpr->op = TK_NULL;
    ++            return WRC_Prune;
    +           }
    +-          pExpr->op = TK_NULL;
    +-          return WRC_Prune;
    +         }
    + #endif
    +         if( pDef->funcFlags & (SQLITE_FUNC_CONSTANT|SQLITE_FUNC_SLOCHNG) ){
    +@@ -84197,14 +91870,19 @@ static int resolveExprStep(Walker *pWalker, Expr *pExpr){
    +           /* Date/time functions that use 'now', and other functions like
    +           ** sqlite_version() that might change over time cannot be used
    +           ** in an index. */
    +-          notValid(pParse, pNC, "non-deterministic functions", NC_IdxExpr);
    ++          notValid(pParse, pNC, "non-deterministic functions",
    ++                   NC_IdxExpr|NC_PartIdx);
    +         }
    +       }
    +       if( is_agg && (pNC->ncFlags & NC_AllowAgg)==0 ){
    +         sqlite3ErrorMsg(pParse, "misuse of aggregate function %.*s()", nId,zId);
    +         pNC->nErr++;
    +         is_agg = 0;
    +-      }else if( no_such_func && pParse->db->init.busy==0 ){
    ++      }else if( no_such_func && pParse->db->init.busy==0
    ++#ifdef SQLITE_ENABLE_UNKNOWN_SQL_FUNCTION
    ++                && pParse->explain==0
    ++#endif
    ++      ){
    +         sqlite3ErrorMsg(pParse, "no such function: %.*s", nId, zId);
    +         pNC->nErr++;
    +       }else if( wrong_num_args ){
    +@@ -84249,6 +91927,7 @@ static int resolveExprStep(Walker *pWalker, Expr *pExpr){
    +         assert( pNC->nRef>=nRef );
    +         if( nRef!=pNC->nRef ){
    +           ExprSetProperty(pExpr, EP_VarSelect);
    ++          pNC->ncFlags |= NC_VarSelect;
    +         }
    +       }
    +       break;
    +@@ -84257,6 +91936,42 @@ static int resolveExprStep(Walker *pWalker, Expr *pExpr){
    +       notValid(pParse, pNC, "parameters", NC_IsCheck|NC_PartIdx|NC_IdxExpr);
    +       break;
    +     }
    ++    case TK_BETWEEN:
    ++    case TK_EQ:
    ++    case TK_NE:
    ++    case TK_LT:
    ++    case TK_LE:
    ++    case TK_GT:
    ++    case TK_GE:
    ++    case TK_IS:
    ++    case TK_ISNOT: {
    ++      int nLeft, nRight;
    ++      if( pParse->db->mallocFailed ) break;
    ++      assert( pExpr->pLeft!=0 );
    ++      nLeft = sqlite3ExprVectorSize(pExpr->pLeft);
    ++      if( pExpr->op==TK_BETWEEN ){
    ++        nRight = sqlite3ExprVectorSize(pExpr->x.pList->a[0].pExpr);
    ++        if( nRight==nLeft ){
    ++          nRight = sqlite3ExprVectorSize(pExpr->x.pList->a[1].pExpr);
    ++        }
    ++      }else{
    ++        assert( pExpr->pRight!=0 );
    ++        nRight = sqlite3ExprVectorSize(pExpr->pRight);
    ++      }
    ++      if( nLeft!=nRight ){
    ++        testcase( pExpr->op==TK_EQ );
    ++        testcase( pExpr->op==TK_NE );
    ++        testcase( pExpr->op==TK_LT );
    ++        testcase( pExpr->op==TK_LE );
    ++        testcase( pExpr->op==TK_GT );
    ++        testcase( pExpr->op==TK_GE );
    ++        testcase( pExpr->op==TK_IS );
    ++        testcase( pExpr->op==TK_ISNOT );
    ++        testcase( pExpr->op==TK_BETWEEN );
    ++        sqlite3ErrorMsg(pParse, "row value misused");
    ++      }
    ++      break; 
    ++    }
    +   }
    +   return (pParse->nErr || pParse->db->mallocFailed) ? WRC_Abort : WRC_Continue;
    + }
    +@@ -84347,7 +92062,7 @@ static int resolveOrderByTermToExprList(
    +   ** result-set entry.
    +   */
    +   for(i=0; i<pEList->nExpr; i++){
    +-    if( sqlite3ExprCompare(pEList->a[i].pExpr, pE, -1)<2 ){
    ++    if( sqlite3ExprCompare(0, pEList->a[i].pExpr, pE, -1)<2 ){
    +       return i+1;
    +     }
    +   }
    +@@ -84398,12 +92113,10 @@ static int resolveCompoundOrderBy(
    +   pOrderBy = pSelect->pOrderBy;
    +   if( pOrderBy==0 ) return 0;
    +   db = pParse->db;
    +-#if SQLITE_MAX_COLUMN
    +   if( pOrderBy->nExpr>db->aLimit[SQLITE_LIMIT_COLUMN] ){
    +     sqlite3ErrorMsg(pParse, "too many terms in ORDER BY clause");
    +     return 1;
    +   }
    +-#endif
    +   for(i=0; i<pOrderBy->nExpr; i++){
    +     pOrderBy->a[i].done = 0;
    +   }
    +@@ -84495,12 +92208,10 @@ SQLITE_PRIVATE int sqlite3ResolveOrderGroupBy(
    +   struct ExprList_item *pItem;
    + 
    +   if( pOrderBy==0 || pParse->db->mallocFailed ) return 0;
    +-#if SQLITE_MAX_COLUMN
    +   if( pOrderBy->nExpr>db->aLimit[SQLITE_LIMIT_COLUMN] ){
    +     sqlite3ErrorMsg(pParse, "too many terms in %s BY clause", zType);
    +     return 1;
    +   }
    +-#endif
    +   pEList = pSelect->pEList;
    +   assert( pEList!=0 );  /* sqlite3SelectNew() guarantees this */
    +   for(i=0, pItem=pOrderBy->a; i<pOrderBy->nExpr; i++, pItem++){
    +@@ -84581,7 +92292,7 @@ static int resolveOrderGroupBy(
    +       return 1;
    +     }
    +     for(j=0; j<pSelect->pEList->nExpr; j++){
    +-      if( sqlite3ExprCompare(pE, pSelect->pEList->a[j].pExpr, -1)==0 ){
    ++      if( sqlite3ExprCompare(0, pE, pSelect->pEList->a[j].pExpr, -1)==0 ){
    +         pItem->u.x.iOrderByCol = j+1;
    +       }
    +     }
    +@@ -84638,8 +92349,7 @@ static int resolveSelectStep(Walker *pWalker, Select *p){
    +     */
    +     memset(&sNC, 0, sizeof(sNC));
    +     sNC.pParse = pParse;
    +-    if( sqlite3ResolveExprNames(&sNC, p->pLimit) ||
    +-        sqlite3ResolveExprNames(&sNC, p->pOffset) ){
    ++    if( sqlite3ResolveExprNames(&sNC, p->pLimit) ){
    +       return WRC_Abort;
    +     }
    + 
    +@@ -84867,35 +92577,29 @@ SQLITE_PRIVATE int sqlite3ResolveExprNames(
    +   u16 savedHasAgg;
    +   Walker w;
    + 
    +-  if( pExpr==0 ) return 0;
    +-#if SQLITE_MAX_EXPR_DEPTH>0
    +-  {
    +-    Parse *pParse = pNC->pParse;
    +-    if( sqlite3ExprCheckHeight(pParse, pExpr->nHeight+pNC->pParse->nHeight) ){
    +-      return 1;
    +-    }
    +-    pParse->nHeight += pExpr->nHeight;
    +-  }
    +-#endif
    ++  if( pExpr==0 ) return SQLITE_OK;
    +   savedHasAgg = pNC->ncFlags & (NC_HasAgg|NC_MinMaxAgg);
    +   pNC->ncFlags &= ~(NC_HasAgg|NC_MinMaxAgg);
    +-  memset(&w, 0, sizeof(w));
    ++  w.pParse = pNC->pParse;
    +   w.xExprCallback = resolveExprStep;
    +   w.xSelectCallback = resolveSelectStep;
    +-  w.pParse = pNC->pParse;
    ++  w.xSelectCallback2 = 0;
    +   w.u.pNC = pNC;
    ++#if SQLITE_MAX_EXPR_DEPTH>0
    ++  w.pParse->nHeight += pExpr->nHeight;
    ++  if( sqlite3ExprCheckHeight(w.pParse, w.pParse->nHeight) ){
    ++    return SQLITE_ERROR;
    ++  }
    ++#endif
    +   sqlite3WalkExpr(&w, pExpr);
    + #if SQLITE_MAX_EXPR_DEPTH>0
    +-  pNC->pParse->nHeight -= pExpr->nHeight;
    ++  w.pParse->nHeight -= pExpr->nHeight;
    + #endif
    +-  if( pNC->nErr>0 || w.pParse->nErr>0 ){
    +-    ExprSetProperty(pExpr, EP_Error);
    +-  }
    +   if( pNC->ncFlags & NC_HasAgg ){
    +     ExprSetProperty(pExpr, EP_Agg);
    +   }
    +   pNC->ncFlags |= savedHasAgg;
    +-  return ExprHasProperty(pExpr, EP_Error);
    ++  return pNC->nErr>0 || w.pParse->nErr>0;
    + }
    + 
    + /*
    +@@ -84908,9 +92612,10 @@ SQLITE_PRIVATE int sqlite3ResolveExprListNames(
    +   ExprList *pList         /* The expression list to be analyzed. */
    + ){
    +   int i;
    +-  assert( pList!=0 );
    +-  for(i=0; i<pList->nExpr; i++){
    +-    if( sqlite3ResolveExprNames(pNC, pList->a[i].pExpr) ) return WRC_Abort;
    ++  if( pList ){
    ++    for(i=0; i<pList->nExpr; i++){
    ++      if( sqlite3ResolveExprNames(pNC, pList->a[i].pExpr) ) return WRC_Abort;
    ++    }
    +   }
    +   return WRC_Continue;
    + }
    +@@ -84935,9 +92640,9 @@ SQLITE_PRIVATE void sqlite3ResolveSelectNames(
    +   Walker w;
    + 
    +   assert( p!=0 );
    +-  memset(&w, 0, sizeof(w));
    +   w.xExprCallback = resolveExprStep;
    +   w.xSelectCallback = resolveSelectStep;
    ++  w.xSelectCallback2 = 0;
    +   w.pParse = pParse;
    +   w.u.pNC = pOuterNC;
    +   sqlite3WalkSelect(&w, p);
    +@@ -84996,6 +92701,18 @@ SQLITE_PRIVATE void sqlite3ResolveSelfReference(
    + */
    + /* #include "sqliteInt.h" */
    + 
    ++/* Forward declarations */
    ++static void exprCodeBetween(Parse*,Expr*,int,void(*)(Parse*,Expr*,int,int),int);
    ++static int exprCodeVector(Parse *pParse, Expr *p, int *piToFree);
    ++
    ++/*
    ++** Return the affinity character for a single column of a table.
    ++*/
    ++SQLITE_PRIVATE char sqlite3TableColumnAffinity(Table *pTab, int iCol){
    ++  assert( iCol<pTab->nCol );
    ++  return iCol>=0 ? pTab->aCol[iCol].affinity : SQLITE_AFF_INTEGER;
    ++}
    ++
    + /*
    + ** Return the 'affinity' of the expression pExpr if any.
    + **
    +@@ -85021,21 +92738,21 @@ SQLITE_PRIVATE char sqlite3ExprAffinity(Expr *pExpr){
    +     assert( pExpr->flags&EP_xIsSelect );
    +     return sqlite3ExprAffinity(pExpr->x.pSelect->pEList->a[0].pExpr);
    +   }
    ++  if( op==TK_REGISTER ) op = pExpr->op2;
    + #ifndef SQLITE_OMIT_CAST
    +   if( op==TK_CAST ){
    +     assert( !ExprHasProperty(pExpr, EP_IntValue) );
    +     return sqlite3AffinityType(pExpr->u.zToken, 0);
    +   }
    + #endif
    +-  if( (op==TK_AGG_COLUMN || op==TK_COLUMN || op==TK_REGISTER) 
    +-   && pExpr->pTab!=0
    +-  ){
    +-    /* op==TK_REGISTER && pExpr->pTab!=0 happens when pExpr was originally
    +-    ** a TK_COLUMN but was previously evaluated and cached in a register */
    +-    int j = pExpr->iColumn;
    +-    if( j<0 ) return SQLITE_AFF_INTEGER;
    +-    assert( pExpr->pTab && j<pExpr->pTab->nCol );
    +-    return pExpr->pTab->aCol[j].affinity;
    ++  if( (op==TK_AGG_COLUMN || op==TK_COLUMN) && pExpr->pTab ){
    ++    return sqlite3TableColumnAffinity(pExpr->pTab, pExpr->iColumn);
    ++  }
    ++  if( op==TK_SELECT_COLUMN ){
    ++    assert( pExpr->pLeft->flags&EP_xIsSelect );
    ++    return sqlite3ExprAffinity(
    ++        pExpr->pLeft->x.pSelect->pEList->a[pExpr->iColumn].pExpr
    ++    );
    +   }
    +   return pExpr->affinity;
    + }
    +@@ -85067,8 +92784,7 @@ SQLITE_PRIVATE Expr *sqlite3ExprAddCollateToken(
    + SQLITE_PRIVATE Expr *sqlite3ExprAddCollateString(Parse *pParse, Expr *pExpr, const char *zC){
    +   Token s;
    +   assert( zC!=0 );
    +-  s.z = zC;
    +-  s.n = sqlite3Strlen30(s.z);
    ++  sqlite3TokenInit(&s, (char*)zC);
    +   return sqlite3ExprAddCollateToken(pParse, pExpr, &s, 0);
    + }
    + 
    +@@ -85095,6 +92811,11 @@ SQLITE_PRIVATE Expr *sqlite3ExprSkipCollate(Expr *pExpr){
    + ** Return the collation sequence for the expression pExpr. If
    + ** there is no defined collating sequence, return NULL.
    + **
    ++** See also: sqlite3ExprNNCollSeq()
    ++**
    ++** The sqlite3ExprNNCollSeq() works the same exact that it returns the
    ++** default collation if pExpr has no defined collation.
    ++**
    + ** The collating sequence might be determined by a COLLATE operator
    + ** or by the presence of a column with a defined collating sequence.
    + ** COLLATE operators take first precedence.  Left operands take
    +@@ -85159,6 +92880,32 @@ SQLITE_PRIVATE CollSeq *sqlite3ExprCollSeq(Parse *pParse, Expr *pExpr){
    +   return pColl;
    + }
    + 
    ++/*
    ++** Return the collation sequence for the expression pExpr. If
    ++** there is no defined collating sequence, return a pointer to the
    ++** defautl collation sequence.
    ++**
    ++** See also: sqlite3ExprCollSeq()
    ++**
    ++** The sqlite3ExprCollSeq() routine works the same except that it
    ++** returns NULL if there is no defined collation.
    ++*/
    ++SQLITE_PRIVATE CollSeq *sqlite3ExprNNCollSeq(Parse *pParse, Expr *pExpr){
    ++  CollSeq *p = sqlite3ExprCollSeq(pParse, pExpr);
    ++  if( p==0 ) p = pParse->db->pDfltColl;
    ++  assert( p!=0 );
    ++  return p;
    ++}
    ++
    ++/*
    ++** Return TRUE if the two expressions have equivalent collating sequences.
    ++*/
    ++SQLITE_PRIVATE int sqlite3ExprCollSeqMatch(Parse *pParse, Expr *pE1, Expr *pE2){
    ++  CollSeq *pColl1 = sqlite3ExprNNCollSeq(pParse, pE1);
    ++  CollSeq *pColl2 = sqlite3ExprNNCollSeq(pParse, pE2);
    ++  return sqlite3StrICmp(pColl1->zName, pColl2->zName)==0;
    ++}
    ++
    + /*
    + ** pExpr is an operand of a comparison operator.  aff2 is the
    + ** type affinity of the other operand.  This routine returns the
    +@@ -85202,7 +92949,7 @@ static char comparisonAffinity(Expr *pExpr){
    +     aff = sqlite3CompareAffinity(pExpr->pRight, aff);
    +   }else if( ExprHasProperty(pExpr, EP_xIsSelect) ){
    +     aff = sqlite3CompareAffinity(pExpr->x.pSelect->pEList->a[0].pExpr, aff);
    +-  }else if( !aff ){
    ++  }else if( aff==0 ){
    +     aff = SQLITE_AFF_BLOB;
    +   }
    +   return aff;
    +@@ -85292,6 +93039,270 @@ static int codeCompare(
    +   return addr;
    + }
    + 
    ++/*
    ++** Return true if expression pExpr is a vector, or false otherwise.
    ++**
    ++** A vector is defined as any expression that results in two or more
    ++** columns of result.  Every TK_VECTOR node is an vector because the
    ++** parser will not generate a TK_VECTOR with fewer than two entries.
    ++** But a TK_SELECT might be either a vector or a scalar. It is only
    ++** considered a vector if it has two or more result columns.
    ++*/
    ++SQLITE_PRIVATE int sqlite3ExprIsVector(Expr *pExpr){
    ++  return sqlite3ExprVectorSize(pExpr)>1;
    ++}
    ++
    ++/*
    ++** If the expression passed as the only argument is of type TK_VECTOR 
    ++** return the number of expressions in the vector. Or, if the expression
    ++** is a sub-select, return the number of columns in the sub-select. For
    ++** any other type of expression, return 1.
    ++*/
    ++SQLITE_PRIVATE int sqlite3ExprVectorSize(Expr *pExpr){
    ++  u8 op = pExpr->op;
    ++  if( op==TK_REGISTER ) op = pExpr->op2;
    ++  if( op==TK_VECTOR ){
    ++    return pExpr->x.pList->nExpr;
    ++  }else if( op==TK_SELECT ){
    ++    return pExpr->x.pSelect->pEList->nExpr;
    ++  }else{
    ++    return 1;
    ++  }
    ++}
    ++
    ++/*
    ++** Return a pointer to a subexpression of pVector that is the i-th
    ++** column of the vector (numbered starting with 0).  The caller must
    ++** ensure that i is within range.
    ++**
    ++** If pVector is really a scalar (and "scalar" here includes subqueries
    ++** that return a single column!) then return pVector unmodified.
    ++**
    ++** pVector retains ownership of the returned subexpression.
    ++**
    ++** If the vector is a (SELECT ...) then the expression returned is
    ++** just the expression for the i-th term of the result set, and may
    ++** not be ready for evaluation because the table cursor has not yet
    ++** been positioned.
    ++*/
    ++SQLITE_PRIVATE Expr *sqlite3VectorFieldSubexpr(Expr *pVector, int i){
    ++  assert( i<sqlite3ExprVectorSize(pVector) );
    ++  if( sqlite3ExprIsVector(pVector) ){
    ++    assert( pVector->op2==0 || pVector->op==TK_REGISTER );
    ++    if( pVector->op==TK_SELECT || pVector->op2==TK_SELECT ){
    ++      return pVector->x.pSelect->pEList->a[i].pExpr;
    ++    }else{
    ++      return pVector->x.pList->a[i].pExpr;
    ++    }
    ++  }
    ++  return pVector;
    ++}
    ++
    ++/*
    ++** Compute and return a new Expr object which when passed to
    ++** sqlite3ExprCode() will generate all necessary code to compute
    ++** the iField-th column of the vector expression pVector.
    ++**
    ++** It is ok for pVector to be a scalar (as long as iField==0).  
    ++** In that case, this routine works like sqlite3ExprDup().
    ++**
    ++** The caller owns the returned Expr object and is responsible for
    ++** ensuring that the returned value eventually gets freed.
    ++**
    ++** The caller retains ownership of pVector.  If pVector is a TK_SELECT,
    ++** then the returned object will reference pVector and so pVector must remain
    ++** valid for the life of the returned object.  If pVector is a TK_VECTOR
    ++** or a scalar expression, then it can be deleted as soon as this routine
    ++** returns.
    ++**
    ++** A trick to cause a TK_SELECT pVector to be deleted together with
    ++** the returned Expr object is to attach the pVector to the pRight field
    ++** of the returned TK_SELECT_COLUMN Expr object.
    ++*/
    ++SQLITE_PRIVATE Expr *sqlite3ExprForVectorField(
    ++  Parse *pParse,       /* Parsing context */
    ++  Expr *pVector,       /* The vector.  List of expressions or a sub-SELECT */
    ++  int iField           /* Which column of the vector to return */
    ++){
    ++  Expr *pRet;
    ++  if( pVector->op==TK_SELECT ){
    ++    assert( pVector->flags & EP_xIsSelect );
    ++    /* The TK_SELECT_COLUMN Expr node:
    ++    **
    ++    ** pLeft:           pVector containing TK_SELECT.  Not deleted.
    ++    ** pRight:          not used.  But recursively deleted.
    ++    ** iColumn:         Index of a column in pVector
    ++    ** iTable:          0 or the number of columns on the LHS of an assignment
    ++    ** pLeft->iTable:   First in an array of register holding result, or 0
    ++    **                  if the result is not yet computed.
    ++    **
    ++    ** sqlite3ExprDelete() specifically skips the recursive delete of
    ++    ** pLeft on TK_SELECT_COLUMN nodes.  But pRight is followed, so pVector
    ++    ** can be attached to pRight to cause this node to take ownership of
    ++    ** pVector.  Typically there will be multiple TK_SELECT_COLUMN nodes
    ++    ** with the same pLeft pointer to the pVector, but only one of them
    ++    ** will own the pVector.
    ++    */
    ++    pRet = sqlite3PExpr(pParse, TK_SELECT_COLUMN, 0, 0);
    ++    if( pRet ){
    ++      pRet->iColumn = iField;
    ++      pRet->pLeft = pVector;
    ++    }
    ++    assert( pRet==0 || pRet->iTable==0 );
    ++  }else{
    ++    if( pVector->op==TK_VECTOR ) pVector = pVector->x.pList->a[iField].pExpr;
    ++    pRet = sqlite3ExprDup(pParse->db, pVector, 0);
    ++  }
    ++  return pRet;
    ++}
    ++
    ++/*
    ++** If expression pExpr is of type TK_SELECT, generate code to evaluate
    ++** it. Return the register in which the result is stored (or, if the 
    ++** sub-select returns more than one column, the first in an array
    ++** of registers in which the result is stored).
    ++**
    ++** If pExpr is not a TK_SELECT expression, return 0.
    ++*/
    ++static int exprCodeSubselect(Parse *pParse, Expr *pExpr){
    ++  int reg = 0;
    ++#ifndef SQLITE_OMIT_SUBQUERY
    ++  if( pExpr->op==TK_SELECT ){
    ++    reg = sqlite3CodeSubselect(pParse, pExpr, 0, 0);
    ++  }
    ++#endif
    ++  return reg;
    ++}
    ++
    ++/*
    ++** Argument pVector points to a vector expression - either a TK_VECTOR
    ++** or TK_SELECT that returns more than one column. This function returns
    ++** the register number of a register that contains the value of
    ++** element iField of the vector.
    ++**
    ++** If pVector is a TK_SELECT expression, then code for it must have 
    ++** already been generated using the exprCodeSubselect() routine. In this
    ++** case parameter regSelect should be the first in an array of registers
    ++** containing the results of the sub-select. 
    ++**
    ++** If pVector is of type TK_VECTOR, then code for the requested field
    ++** is generated. In this case (*pRegFree) may be set to the number of
    ++** a temporary register to be freed by the caller before returning.
    ++**
    ++** Before returning, output parameter (*ppExpr) is set to point to the
    ++** Expr object corresponding to element iElem of the vector.
    ++*/
    ++static int exprVectorRegister(
    ++  Parse *pParse,                  /* Parse context */
    ++  Expr *pVector,                  /* Vector to extract element from */
    ++  int iField,                     /* Field to extract from pVector */
    ++  int regSelect,                  /* First in array of registers */
    ++  Expr **ppExpr,                  /* OUT: Expression element */
    ++  int *pRegFree                   /* OUT: Temp register to free */
    ++){
    ++  u8 op = pVector->op;
    ++  assert( op==TK_VECTOR || op==TK_REGISTER || op==TK_SELECT );
    ++  if( op==TK_REGISTER ){
    ++    *ppExpr = sqlite3VectorFieldSubexpr(pVector, iField);
    ++    return pVector->iTable+iField;
    ++  }
    ++  if( op==TK_SELECT ){
    ++    *ppExpr = pVector->x.pSelect->pEList->a[iField].pExpr;
    ++     return regSelect+iField;
    ++  }
    ++  *ppExpr = pVector->x.pList->a[iField].pExpr;
    ++  return sqlite3ExprCodeTemp(pParse, *ppExpr, pRegFree);
    ++}
    ++
    ++/*
    ++** Expression pExpr is a comparison between two vector values. Compute
    ++** the result of the comparison (1, 0, or NULL) and write that
    ++** result into register dest.
    ++**
    ++** The caller must satisfy the following preconditions:
    ++**
    ++**    if pExpr->op==TK_IS:      op==TK_EQ and p5==SQLITE_NULLEQ
    ++**    if pExpr->op==TK_ISNOT:   op==TK_NE and p5==SQLITE_NULLEQ
    ++**    otherwise:                op==pExpr->op and p5==0
    ++*/
    ++static void codeVectorCompare(
    ++  Parse *pParse,        /* Code generator context */
    ++  Expr *pExpr,          /* The comparison operation */
    ++  int dest,             /* Write results into this register */
    ++  u8 op,                /* Comparison operator */
    ++  u8 p5                 /* SQLITE_NULLEQ or zero */
    ++){
    ++  Vdbe *v = pParse->pVdbe;
    ++  Expr *pLeft = pExpr->pLeft;
    ++  Expr *pRight = pExpr->pRight;
    ++  int nLeft = sqlite3ExprVectorSize(pLeft);
    ++  int i;
    ++  int regLeft = 0;
    ++  int regRight = 0;
    ++  u8 opx = op;
    ++  int addrDone = sqlite3VdbeMakeLabel(v);
    ++
    ++  if( nLeft!=sqlite3ExprVectorSize(pRight) ){
    ++    sqlite3ErrorMsg(pParse, "row value misused");
    ++    return;
    ++  }
    ++  assert( pExpr->op==TK_EQ || pExpr->op==TK_NE 
    ++       || pExpr->op==TK_IS || pExpr->op==TK_ISNOT 
    ++       || pExpr->op==TK_LT || pExpr->op==TK_GT 
    ++       || pExpr->op==TK_LE || pExpr->op==TK_GE 
    ++  );
    ++  assert( pExpr->op==op || (pExpr->op==TK_IS && op==TK_EQ)
    ++            || (pExpr->op==TK_ISNOT && op==TK_NE) );
    ++  assert( p5==0 || pExpr->op!=op );
    ++  assert( p5==SQLITE_NULLEQ || pExpr->op==op );
    ++
    ++  p5 |= SQLITE_STOREP2;
    ++  if( opx==TK_LE ) opx = TK_LT;
    ++  if( opx==TK_GE ) opx = TK_GT;
    ++
    ++  regLeft = exprCodeSubselect(pParse, pLeft);
    ++  regRight = exprCodeSubselect(pParse, pRight);
    ++
    ++  for(i=0; 1 /*Loop exits by "break"*/; i++){
    ++    int regFree1 = 0, regFree2 = 0;
    ++    Expr *pL, *pR; 
    ++    int r1, r2;
    ++    assert( i>=0 && i<nLeft );
    ++    if( i>0 ) sqlite3ExprCachePush(pParse);
    ++    r1 = exprVectorRegister(pParse, pLeft, i, regLeft, &pL, &regFree1);
    ++    r2 = exprVectorRegister(pParse, pRight, i, regRight, &pR, &regFree2);
    ++    codeCompare(pParse, pL, pR, opx, r1, r2, dest, p5);
    ++    testcase(op==OP_Lt); VdbeCoverageIf(v,op==OP_Lt);
    ++    testcase(op==OP_Le); VdbeCoverageIf(v,op==OP_Le);
    ++    testcase(op==OP_Gt); VdbeCoverageIf(v,op==OP_Gt);
    ++    testcase(op==OP_Ge); VdbeCoverageIf(v,op==OP_Ge);
    ++    testcase(op==OP_Eq); VdbeCoverageIf(v,op==OP_Eq);
    ++    testcase(op==OP_Ne); VdbeCoverageIf(v,op==OP_Ne);
    ++    sqlite3ReleaseTempReg(pParse, regFree1);
    ++    sqlite3ReleaseTempReg(pParse, regFree2);
    ++    if( i>0 ) sqlite3ExprCachePop(pParse);
    ++    if( i==nLeft-1 ){
    ++      break;
    ++    }
    ++    if( opx==TK_EQ ){
    ++      sqlite3VdbeAddOp2(v, OP_IfNot, dest, addrDone); VdbeCoverage(v);
    ++      p5 |= SQLITE_KEEPNULL;
    ++    }else if( opx==TK_NE ){
    ++      sqlite3VdbeAddOp2(v, OP_If, dest, addrDone); VdbeCoverage(v);
    ++      p5 |= SQLITE_KEEPNULL;
    ++    }else{
    ++      assert( op==TK_LT || op==TK_GT || op==TK_LE || op==TK_GE );
    ++      sqlite3VdbeAddOp2(v, OP_ElseNotEq, 0, addrDone);
    ++      VdbeCoverageIf(v, op==TK_LT);
    ++      VdbeCoverageIf(v, op==TK_GT);
    ++      VdbeCoverageIf(v, op==TK_LE);
    ++      VdbeCoverageIf(v, op==TK_GE);
    ++      if( i==nLeft-2 ) opx = op;
    ++    }
    ++  }
    ++  sqlite3VdbeResolveLabel(v, addrDone);
    ++}
    ++
    + #if SQLITE_MAX_EXPR_DEPTH>0
    + /*
    + ** Check that argument nHeight is less than or equal to the maximum
    +@@ -85334,16 +93345,15 @@ static void heightOfExprList(ExprList *p, int *pnHeight){
    +     }
    +   }
    + }
    +-static void heightOfSelect(Select *p, int *pnHeight){
    +-  if( p ){
    ++static void heightOfSelect(Select *pSelect, int *pnHeight){
    ++  Select *p;
    ++  for(p=pSelect; p; p=p->pPrior){
    +     heightOfExpr(p->pWhere, pnHeight);
    +     heightOfExpr(p->pHaving, pnHeight);
    +     heightOfExpr(p->pLimit, pnHeight);
    +-    heightOfExpr(p->pOffset, pnHeight);
    +     heightOfExprList(p->pEList, pnHeight);
    +     heightOfExprList(p->pGroupBy, pnHeight);
    +     heightOfExprList(p->pOrderBy, pnHeight);
    +-    heightOfSelect(p->pPrior, pnHeight);
    +   }
    + }
    + 
    +@@ -85427,7 +93437,7 @@ SQLITE_PRIVATE void sqlite3ExprSetHeightAndFlags(Parse *pParse, Expr *p){
    + ** is allocated to hold the integer text and the dequote flag is ignored.
    + */
    + SQLITE_PRIVATE Expr *sqlite3ExprAlloc(
    +-  sqlite3 *db,            /* Handle for sqlite3DbMallocZero() (may be null) */
    ++  sqlite3 *db,            /* Handle for sqlite3DbMallocRawNN() */
    +   int op,                 /* Expression opcode */
    +   const Token *pToken,    /* Token argument.  Might be NULL */
    +   int dequote             /* True to dequote */
    +@@ -85436,6 +93446,7 @@ SQLITE_PRIVATE Expr *sqlite3ExprAlloc(
    +   int nExtra = 0;
    +   int iValue = 0;
    + 
    ++  assert( db!=0 );
    +   if( pToken ){
    +     if( op!=TK_INTEGER || pToken->z==0
    +           || sqlite3GetInt32(pToken->z, &iValue)==0 ){
    +@@ -85443,24 +93454,23 @@ SQLITE_PRIVATE Expr *sqlite3ExprAlloc(
    +       assert( iValue>=0 );
    +     }
    +   }
    +-  pNew = sqlite3DbMallocZero(db, sizeof(Expr)+nExtra);
    ++  pNew = sqlite3DbMallocRawNN(db, sizeof(Expr)+nExtra);
    +   if( pNew ){
    ++    memset(pNew, 0, sizeof(Expr));
    +     pNew->op = (u8)op;
    +     pNew->iAgg = -1;
    +     if( pToken ){
    +       if( nExtra==0 ){
    +-        pNew->flags |= EP_IntValue;
    ++        pNew->flags |= EP_IntValue|EP_Leaf;
    +         pNew->u.iValue = iValue;
    +       }else{
    +-        int c;
    +         pNew->u.zToken = (char*)&pNew[1];
    +         assert( pToken->z!=0 || pToken->n==0 );
    +         if( pToken->n ) memcpy(pNew->u.zToken, pToken->z, pToken->n);
    +         pNew->u.zToken[pToken->n] = 0;
    +-        if( dequote && nExtra>=3 
    +-             && ((c = pToken->z[0])=='\'' || c=='"' || c=='[' || c=='`') ){
    ++        if( dequote && sqlite3Isquote(pNew->u.zToken[0]) ){
    ++          if( pNew->u.zToken[0]=='"' ) pNew->flags |= EP_DblQuoted;
    +           sqlite3Dequote(pNew->u.zToken);
    +-          if( c=='"' ) pNew->flags |= EP_DblQuoted;
    +         }
    +       }
    +     }
    +@@ -85482,7 +93492,7 @@ SQLITE_PRIVATE Expr *sqlite3Expr(
    + ){
    +   Token x;
    +   x.z = zToken;
    +-  x.n = zToken ? sqlite3Strlen30(zToken) : 0;
    ++  x.n = sqlite3Strlen30(zToken);
    +   return sqlite3ExprAlloc(db, op, &x, 0);
    + }
    + 
    +@@ -85526,15 +93536,19 @@ SQLITE_PRIVATE Expr *sqlite3PExpr(
    +   Parse *pParse,          /* Parsing context */
    +   int op,                 /* Expression opcode */
    +   Expr *pLeft,            /* Left operand */
    +-  Expr *pRight,           /* Right operand */
    +-  const Token *pToken     /* Argument token */
    ++  Expr *pRight            /* Right operand */
    + ){
    +   Expr *p;
    +-  if( op==TK_AND && pLeft && pRight && pParse->nErr==0 ){
    ++  if( op==TK_AND && pParse->nErr==0 ){
    +     /* Take advantage of short-circuit false optimization for AND */
    +     p = sqlite3ExprAnd(pParse->db, pLeft, pRight);
    +   }else{
    +-    p = sqlite3ExprAlloc(pParse->db, op, pToken, 1);
    ++    p = sqlite3DbMallocRawNN(pParse->db, sizeof(Expr));
    ++    if( p ){
    ++      memset(p, 0, sizeof(Expr));
    ++      p->op = op & TKFLG_MASK;
    ++      p->iAgg = -1;
    ++    }
    +     sqlite3ExprAttachSubtrees(pParse->db, p, pLeft, pRight);
    +   }
    +   if( p ) {
    +@@ -85543,6 +93557,22 @@ SQLITE_PRIVATE Expr *sqlite3PExpr(
    +   return p;
    + }
    + 
    ++/*
    ++** Add pSelect to the Expr.x.pSelect field.  Or, if pExpr is NULL (due
    ++** do a memory allocation failure) then delete the pSelect object.
    ++*/
    ++SQLITE_PRIVATE void sqlite3PExprAddSelect(Parse *pParse, Expr *pExpr, Select *pSelect){
    ++  if( pExpr ){
    ++    pExpr->x.pSelect = pSelect;
    ++    ExprSetProperty(pExpr, EP_xIsSelect|EP_Subquery);
    ++    sqlite3ExprSetHeightAndFlags(pParse, pExpr);
    ++  }else{
    ++    assert( pParse->db->mallocFailed );
    ++    sqlite3SelectDelete(pParse->db, pSelect);
    ++  }
    ++}
    ++
    ++
    + /*
    + ** If the expression is always either TRUE or FALSE (respectively),
    + ** then return 1.  If one cannot determine the truth value of the
    +@@ -85608,6 +93638,7 @@ SQLITE_PRIVATE Expr *sqlite3ExprFunction(Parse *pParse, ExprList *pList, Token *
    +     return 0;
    +   }
    +   pNew->x.pList = pList;
    ++  ExprSetProperty(pNew, EP_HasFunc);
    +   assert( !ExprHasProperty(pNew, EP_xIsSelect) );
    +   sqlite3ExprSetHeightAndFlags(pParse, pNew);
    +   return pNew;
    +@@ -85621,7 +93652,7 @@ SQLITE_PRIVATE Expr *sqlite3ExprFunction(Parse *pParse, ExprList *pList, Token *
    + ** variable number.
    + **
    + ** Wildcards of the form "?nnn" are assigned the number "nnn".  We make
    +-** sure "nnn" is not too be to avoid a denial of service attack when
    ++** sure "nnn" is not too big to avoid a denial of service attack when
    + ** the SQL statement comes from an external source.
    + **
    + ** Wildcards of the form ":aaa", "@aaa", or "$aaa" are assigned the same number
    +@@ -85629,28 +93660,34 @@ SQLITE_PRIVATE Expr *sqlite3ExprFunction(Parse *pParse, ExprList *pList, Token *
    + ** instance of the wildcard, the next sequential variable number is
    + ** assigned.
    + */
    +-SQLITE_PRIVATE void sqlite3ExprAssignVarNumber(Parse *pParse, Expr *pExpr){
    ++SQLITE_PRIVATE void sqlite3ExprAssignVarNumber(Parse *pParse, Expr *pExpr, u32 n){
    +   sqlite3 *db = pParse->db;
    +   const char *z;
    ++  ynVar x;
    + 
    +   if( pExpr==0 ) return;
    +   assert( !ExprHasProperty(pExpr, EP_IntValue|EP_Reduced|EP_TokenOnly) );
    +   z = pExpr->u.zToken;
    +   assert( z!=0 );
    +   assert( z[0]!=0 );
    ++  assert( n==(u32)sqlite3Strlen30(z) );
    +   if( z[1]==0 ){
    +     /* Wildcard of the form "?".  Assign the next variable number */
    +     assert( z[0]=='?' );
    +-    pExpr->iColumn = (ynVar)(++pParse->nVar);
    ++    x = (ynVar)(++pParse->nVar);
    +   }else{
    +-    ynVar x = 0;
    +-    u32 n = sqlite3Strlen30(z);
    ++    int doAdd = 0;
    +     if( z[0]=='?' ){
    +       /* Wildcard of the form "?nnn".  Convert "nnn" to an integer and
    +       ** use it as the variable number */
    +       i64 i;
    +-      int bOk = 0==sqlite3Atoi64(&z[1], &i, n-1, SQLITE_UTF8);
    +-      pExpr->iColumn = x = (ynVar)i;
    ++      int bOk;
    ++      if( n==2 ){ /*OPTIMIZATION-IF-TRUE*/
    ++        i = z[1]-'0';  /* The common case of ?N for a single digit N */
    ++        bOk = 1;
    ++      }else{
    ++        bOk = 0==sqlite3Atoi64(&z[1], &i, n-1, SQLITE_UTF8);
    ++      }
    +       testcase( i==0 );
    +       testcase( i==1 );
    +       testcase( i==db->aLimit[SQLITE_LIMIT_VARIABLE_NUMBER]-1 );
    +@@ -85658,41 +93695,32 @@ SQLITE_PRIVATE void sqlite3ExprAssignVarNumber(Parse *pParse, Expr *pExpr){
    +       if( bOk==0 || i<1 || i>db->aLimit[SQLITE_LIMIT_VARIABLE_NUMBER] ){
    +         sqlite3ErrorMsg(pParse, "variable number must be between ?1 and ?%d",
    +             db->aLimit[SQLITE_LIMIT_VARIABLE_NUMBER]);
    +-        x = 0;
    ++        return;
    +       }
    +-      if( i>pParse->nVar ){
    +-        pParse->nVar = (int)i;
    ++      x = (ynVar)i;
    ++      if( x>pParse->nVar ){
    ++        pParse->nVar = (int)x;
    ++        doAdd = 1;
    ++      }else if( sqlite3VListNumToName(pParse->pVList, x)==0 ){
    ++        doAdd = 1;
    +       }
    +     }else{
    +       /* Wildcards like ":aaa", "$aaa" or "@aaa".  Reuse the same variable
    +       ** number as the prior appearance of the same name, or if the name
    +       ** has never appeared before, reuse the same variable number
    +       */
    +-      ynVar i;
    +-      for(i=0; i<pParse->nzVar; i++){
    +-        if( pParse->azVar[i] && strcmp(pParse->azVar[i],z)==0 ){
    +-          pExpr->iColumn = x = (ynVar)i+1;
    +-          break;
    +-        }
    ++      x = (ynVar)sqlite3VListNameToNum(pParse->pVList, z, n);
    ++      if( x==0 ){
    ++        x = (ynVar)(++pParse->nVar);
    ++        doAdd = 1;
    +       }
    +-      if( x==0 ) x = pExpr->iColumn = (ynVar)(++pParse->nVar);
    +     }
    +-    if( x>0 ){
    +-      if( x>pParse->nzVar ){
    +-        char **a;
    +-        a = sqlite3DbRealloc(db, pParse->azVar, x*sizeof(a[0]));
    +-        if( a==0 ) return;  /* Error reported through db->mallocFailed */
    +-        pParse->azVar = a;
    +-        memset(&a[pParse->nzVar], 0, (x-pParse->nzVar)*sizeof(a[0]));
    +-        pParse->nzVar = x;
    +-      }
    +-      if( z[0]!='?' || pParse->azVar[x-1]==0 ){
    +-        sqlite3DbFree(db, pParse->azVar[x-1]);
    +-        pParse->azVar[x-1] = sqlite3DbStrNDup(db, z, n);
    +-      }
    ++    if( doAdd ){
    ++      pParse->pVList = sqlite3VListAdd(db, pParse->pVList, z, n, x);
    +     }
    +-  } 
    +-  if( !pParse->nErr && pParse->nVar>db->aLimit[SQLITE_LIMIT_VARIABLE_NUMBER] ){
    ++  }
    ++  pExpr->iColumn = x;
    ++  if( x>db->aLimit[SQLITE_LIMIT_VARIABLE_NUMBER] ){
    +     sqlite3ErrorMsg(pParse, "too many SQL variables");
    +   }
    + }
    +@@ -85700,26 +93728,37 @@ SQLITE_PRIVATE void sqlite3ExprAssignVarNumber(Parse *pParse, Expr *pExpr){
    + /*
    + ** Recursively delete an expression tree.
    + */
    +-SQLITE_PRIVATE void sqlite3ExprDelete(sqlite3 *db, Expr *p){
    +-  if( p==0 ) return;
    ++static SQLITE_NOINLINE void sqlite3ExprDeleteNN(sqlite3 *db, Expr *p){
    ++  assert( p!=0 );
    +   /* Sanity check: Assert that the IntValue is non-negative if it exists */
    +   assert( !ExprHasProperty(p, EP_IntValue) || p->u.iValue>=0 );
    +-  if( !ExprHasProperty(p, EP_TokenOnly) ){
    ++#ifdef SQLITE_DEBUG
    ++  if( ExprHasProperty(p, EP_Leaf) && !ExprHasProperty(p, EP_TokenOnly) ){
    ++    assert( p->pLeft==0 );
    ++    assert( p->pRight==0 );
    ++    assert( p->x.pSelect==0 );
    ++  }
    ++#endif
    ++  if( !ExprHasProperty(p, (EP_TokenOnly|EP_Leaf)) ){
    +     /* The Expr.x union is never used at the same time as Expr.pRight */
    +     assert( p->x.pList==0 || p->pRight==0 );
    +-    sqlite3ExprDelete(db, p->pLeft);
    +-    sqlite3ExprDelete(db, p->pRight);
    +-    if( ExprHasProperty(p, EP_MemToken) ) sqlite3DbFree(db, p->u.zToken);
    +-    if( ExprHasProperty(p, EP_xIsSelect) ){
    ++    if( p->pLeft && p->op!=TK_SELECT_COLUMN ) sqlite3ExprDeleteNN(db, p->pLeft);
    ++    if( p->pRight ){
    ++      sqlite3ExprDeleteNN(db, p->pRight);
    ++    }else if( ExprHasProperty(p, EP_xIsSelect) ){
    +       sqlite3SelectDelete(db, p->x.pSelect);
    +     }else{
    +       sqlite3ExprListDelete(db, p->x.pList);
    +     }
    +   }
    ++  if( ExprHasProperty(p, EP_MemToken) ) sqlite3DbFree(db, p->u.zToken);
    +   if( !ExprHasProperty(p, EP_Static) ){
    +-    sqlite3DbFree(db, p);
    ++    sqlite3DbFreeNN(db, p);
    +   }
    + }
    ++SQLITE_PRIVATE void sqlite3ExprDelete(sqlite3 *db, Expr *p){
    ++  if( p ) sqlite3ExprDeleteNN(db, p);
    ++}
    + 
    + /*
    + ** Return the number of bytes allocated for the expression structure 
    +@@ -85771,7 +93810,7 @@ static int dupedExprStructSize(Expr *p, int flags){
    +   assert( flags==EXPRDUP_REDUCE || flags==0 ); /* Only one flag value allowed */
    +   assert( EXPR_FULLSIZE<=0xfff );
    +   assert( (0xfff & (EP_Reduced|EP_TokenOnly))==0 );
    +-  if( 0==(flags&EXPRDUP_REDUCE) ){
    ++  if( 0==flags || p->op==TK_SELECT_COLUMN ){
    +     nSize = EXPR_FULLSIZE;
    +   }else{
    +     assert( !ExprHasProperty(p, EP_TokenOnly|EP_Reduced) );
    +@@ -85833,84 +93872,94 @@ static int dupedExprSize(Expr *p, int flags){
    + ** if any. Before returning, *pzBuffer is set to the first byte past the
    + ** portion of the buffer copied into by this function.
    + */
    +-static Expr *exprDup(sqlite3 *db, Expr *p, int flags, u8 **pzBuffer){
    +-  Expr *pNew = 0;                      /* Value to return */
    +-  if( p ){
    +-    const int isReduced = (flags&EXPRDUP_REDUCE);
    +-    u8 *zAlloc;
    +-    u32 staticFlag = 0;
    ++static Expr *exprDup(sqlite3 *db, Expr *p, int dupFlags, u8 **pzBuffer){
    ++  Expr *pNew;           /* Value to return */
    ++  u8 *zAlloc;           /* Memory space from which to build Expr object */
    ++  u32 staticFlag;       /* EP_Static if space not obtained from malloc */
    + 
    +-    assert( pzBuffer==0 || isReduced );
    ++  assert( db!=0 );
    ++  assert( p );
    ++  assert( dupFlags==0 || dupFlags==EXPRDUP_REDUCE );
    ++  assert( pzBuffer==0 || dupFlags==EXPRDUP_REDUCE );
    + 
    +-    /* Figure out where to write the new Expr structure. */
    +-    if( pzBuffer ){
    +-      zAlloc = *pzBuffer;
    +-      staticFlag = EP_Static;
    ++  /* Figure out where to write the new Expr structure. */
    ++  if( pzBuffer ){
    ++    zAlloc = *pzBuffer;
    ++    staticFlag = EP_Static;
    ++  }else{
    ++    zAlloc = sqlite3DbMallocRawNN(db, dupedExprSize(p, dupFlags));
    ++    staticFlag = 0;
    ++  }
    ++  pNew = (Expr *)zAlloc;
    ++
    ++  if( pNew ){
    ++    /* Set nNewSize to the size allocated for the structure pointed to
    ++    ** by pNew. This is either EXPR_FULLSIZE, EXPR_REDUCEDSIZE or
    ++    ** EXPR_TOKENONLYSIZE. nToken is set to the number of bytes consumed
    ++    ** by the copy of the p->u.zToken string (if any).
    ++    */
    ++    const unsigned nStructSize = dupedExprStructSize(p, dupFlags);
    ++    const int nNewSize = nStructSize & 0xfff;
    ++    int nToken;
    ++    if( !ExprHasProperty(p, EP_IntValue) && p->u.zToken ){
    ++      nToken = sqlite3Strlen30(p->u.zToken) + 1;
    +     }else{
    +-      zAlloc = sqlite3DbMallocRaw(db, dupedExprSize(p, flags));
    ++      nToken = 0;
    +     }
    +-    pNew = (Expr *)zAlloc;
    +-
    +-    if( pNew ){
    +-      /* Set nNewSize to the size allocated for the structure pointed to
    +-      ** by pNew. This is either EXPR_FULLSIZE, EXPR_REDUCEDSIZE or
    +-      ** EXPR_TOKENONLYSIZE. nToken is set to the number of bytes consumed
    +-      ** by the copy of the p->u.zToken string (if any).
    +-      */
    +-      const unsigned nStructSize = dupedExprStructSize(p, flags);
    +-      const int nNewSize = nStructSize & 0xfff;
    +-      int nToken;
    +-      if( !ExprHasProperty(p, EP_IntValue) && p->u.zToken ){
    +-        nToken = sqlite3Strlen30(p->u.zToken) + 1;
    +-      }else{
    +-        nToken = 0;
    +-      }
    +-      if( isReduced ){
    +-        assert( ExprHasProperty(p, EP_Reduced)==0 );
    +-        memcpy(zAlloc, p, nNewSize);
    +-      }else{
    +-        int nSize = exprStructSize(p);
    +-        memcpy(zAlloc, p, nSize);
    ++    if( dupFlags ){
    ++      assert( ExprHasProperty(p, EP_Reduced)==0 );
    ++      memcpy(zAlloc, p, nNewSize);
    ++    }else{
    ++      u32 nSize = (u32)exprStructSize(p);
    ++      memcpy(zAlloc, p, nSize);
    ++      if( nSize<EXPR_FULLSIZE ){ 
    +         memset(&zAlloc[nSize], 0, EXPR_FULLSIZE-nSize);
    +       }
    ++    }
    + 
    +-      /* Set the EP_Reduced, EP_TokenOnly, and EP_Static flags appropriately. */
    +-      pNew->flags &= ~(EP_Reduced|EP_TokenOnly|EP_Static|EP_MemToken);
    +-      pNew->flags |= nStructSize & (EP_Reduced|EP_TokenOnly);
    +-      pNew->flags |= staticFlag;
    ++    /* Set the EP_Reduced, EP_TokenOnly, and EP_Static flags appropriately. */
    ++    pNew->flags &= ~(EP_Reduced|EP_TokenOnly|EP_Static|EP_MemToken);
    ++    pNew->flags |= nStructSize & (EP_Reduced|EP_TokenOnly);
    ++    pNew->flags |= staticFlag;
    + 
    +-      /* Copy the p->u.zToken string, if any. */
    +-      if( nToken ){
    +-        char *zToken = pNew->u.zToken = (char*)&zAlloc[nNewSize];
    +-        memcpy(zToken, p->u.zToken, nToken);
    +-      }
    ++    /* Copy the p->u.zToken string, if any. */
    ++    if( nToken ){
    ++      char *zToken = pNew->u.zToken = (char*)&zAlloc[nNewSize];
    ++      memcpy(zToken, p->u.zToken, nToken);
    ++    }
    + 
    +-      if( 0==((p->flags|pNew->flags) & EP_TokenOnly) ){
    +-        /* Fill in the pNew->x.pSelect or pNew->x.pList member. */
    +-        if( ExprHasProperty(p, EP_xIsSelect) ){
    +-          pNew->x.pSelect = sqlite3SelectDup(db, p->x.pSelect, isReduced);
    +-        }else{
    +-          pNew->x.pList = sqlite3ExprListDup(db, p->x.pList, isReduced);
    +-        }
    ++    if( 0==((p->flags|pNew->flags) & (EP_TokenOnly|EP_Leaf)) ){
    ++      /* Fill in the pNew->x.pSelect or pNew->x.pList member. */
    ++      if( ExprHasProperty(p, EP_xIsSelect) ){
    ++        pNew->x.pSelect = sqlite3SelectDup(db, p->x.pSelect, dupFlags);
    ++      }else{
    ++        pNew->x.pList = sqlite3ExprListDup(db, p->x.pList, dupFlags);
    +       }
    ++    }
    + 
    +-      /* Fill in pNew->pLeft and pNew->pRight. */
    +-      if( ExprHasProperty(pNew, EP_Reduced|EP_TokenOnly) ){
    +-        zAlloc += dupedExprNodeSize(p, flags);
    +-        if( ExprHasProperty(pNew, EP_Reduced) ){
    +-          pNew->pLeft = exprDup(db, p->pLeft, EXPRDUP_REDUCE, &zAlloc);
    +-          pNew->pRight = exprDup(db, p->pRight, EXPRDUP_REDUCE, &zAlloc);
    +-        }
    +-        if( pzBuffer ){
    +-          *pzBuffer = zAlloc;
    +-        }
    +-      }else{
    +-        if( !ExprHasProperty(p, EP_TokenOnly) ){
    ++    /* Fill in pNew->pLeft and pNew->pRight. */
    ++    if( ExprHasProperty(pNew, EP_Reduced|EP_TokenOnly) ){
    ++      zAlloc += dupedExprNodeSize(p, dupFlags);
    ++      if( !ExprHasProperty(pNew, EP_TokenOnly|EP_Leaf) ){
    ++        pNew->pLeft = p->pLeft ?
    ++                      exprDup(db, p->pLeft, EXPRDUP_REDUCE, &zAlloc) : 0;
    ++        pNew->pRight = p->pRight ?
    ++                       exprDup(db, p->pRight, EXPRDUP_REDUCE, &zAlloc) : 0;
    ++      }
    ++      if( pzBuffer ){
    ++        *pzBuffer = zAlloc;
    ++      }
    ++    }else{
    ++      if( !ExprHasProperty(p, EP_TokenOnly|EP_Leaf) ){
    ++        if( pNew->op==TK_SELECT_COLUMN ){
    ++          pNew->pLeft = p->pLeft;
    ++          assert( p->iColumn==0 || p->pRight==0 );
    ++          assert( p->pRight==0  || p->pRight==p->pLeft );
    ++        }else{
    +           pNew->pLeft = sqlite3ExprDup(db, p->pLeft, 0);
    +-          pNew->pRight = sqlite3ExprDup(db, p->pRight, 0);
    +         }
    ++        pNew->pRight = sqlite3ExprDup(db, p->pRight, 0);
    +       }
    +-
    +     }
    +   }
    +   return pNew;
    +@@ -85961,26 +94010,41 @@ static With *withDup(sqlite3 *db, With *p){
    + ** part of the in-memory representation of the database schema.
    + */
    + SQLITE_PRIVATE Expr *sqlite3ExprDup(sqlite3 *db, Expr *p, int flags){
    +-  return exprDup(db, p, flags, 0);
    ++  assert( flags==0 || flags==EXPRDUP_REDUCE );
    ++  return p ? exprDup(db, p, flags, 0) : 0;
    + }
    + SQLITE_PRIVATE ExprList *sqlite3ExprListDup(sqlite3 *db, ExprList *p, int flags){
    +   ExprList *pNew;
    +   struct ExprList_item *pItem, *pOldItem;
    +   int i;
    ++  Expr *pPriorSelectCol = 0;
    ++  assert( db!=0 );
    +   if( p==0 ) return 0;
    +-  pNew = sqlite3DbMallocRaw(db, sizeof(*pNew) );
    ++  pNew = sqlite3DbMallocRawNN(db, sqlite3DbMallocSize(db, p));
    +   if( pNew==0 ) return 0;
    +-  pNew->nExpr = i = p->nExpr;
    +-  if( (flags & EXPRDUP_REDUCE)==0 ) for(i=1; i<p->nExpr; i+=i){}
    +-  pNew->a = pItem = sqlite3DbMallocRaw(db,  i*sizeof(p->a[0]) );
    +-  if( pItem==0 ){
    +-    sqlite3DbFree(db, pNew);
    +-    return 0;
    +-  } 
    ++  pNew->nExpr = p->nExpr;
    ++  pItem = pNew->a;
    +   pOldItem = p->a;
    +   for(i=0; i<p->nExpr; i++, pItem++, pOldItem++){
    +     Expr *pOldExpr = pOldItem->pExpr;
    ++    Expr *pNewExpr;
    +     pItem->pExpr = sqlite3ExprDup(db, pOldExpr, flags);
    ++    if( pOldExpr 
    ++     && pOldExpr->op==TK_SELECT_COLUMN
    ++     && (pNewExpr = pItem->pExpr)!=0 
    ++    ){
    ++      assert( pNewExpr->iColumn==0 || i>0 );
    ++      if( pNewExpr->iColumn==0 ){
    ++        assert( pOldExpr->pLeft==pOldExpr->pRight );
    ++        pPriorSelectCol = pNewExpr->pLeft = pNewExpr->pRight;
    ++      }else{
    ++        assert( i>0 );
    ++        assert( pItem[-1].pExpr!=0 );
    ++        assert( pNewExpr->iColumn==pItem[-1].pExpr->iColumn+1 );
    ++        assert( pPriorSelectCol==pItem[-1].pExpr->pLeft );
    ++        pNewExpr->pLeft = pPriorSelectCol;
    ++      }
    ++    }
    +     pItem->zName = sqlite3DbStrDup(db, pOldItem->zName);
    +     pItem->zSpan = sqlite3DbStrDup(db, pOldItem->zSpan);
    +     pItem->sortOrder = pOldItem->sortOrder;
    +@@ -86003,9 +94067,10 @@ SQLITE_PRIVATE SrcList *sqlite3SrcListDup(sqlite3 *db, SrcList *p, int flags){
    +   SrcList *pNew;
    +   int i;
    +   int nByte;
    ++  assert( db!=0 );
    +   if( p==0 ) return 0;
    +   nByte = sizeof(*p) + (p->nSrc>0 ? sizeof(p->a[0]) * (p->nSrc-1) : 0);
    +-  pNew = sqlite3DbMallocRaw(db, nByte );
    ++  pNew = sqlite3DbMallocRawNN(db, nByte );
    +   if( pNew==0 ) return 0;
    +   pNew->nSrc = pNew->nAlloc = p->nSrc;
    +   for(i=0; i<p->nSrc; i++){
    +@@ -86030,7 +94095,7 @@ SQLITE_PRIVATE SrcList *sqlite3SrcListDup(sqlite3 *db, SrcList *p, int flags){
    +     }
    +     pTab = pNewItem->pTab = pOldItem->pTab;
    +     if( pTab ){
    +-      pTab->nRef++;
    ++      pTab->nTabRef++;
    +     }
    +     pNewItem->pSelect = sqlite3SelectDup(db, pOldItem->pSelect, flags);
    +     pNewItem->pOn = sqlite3ExprDup(db, pOldItem->pOn, flags);
    +@@ -86042,13 +94107,14 @@ SQLITE_PRIVATE SrcList *sqlite3SrcListDup(sqlite3 *db, SrcList *p, int flags){
    + SQLITE_PRIVATE IdList *sqlite3IdListDup(sqlite3 *db, IdList *p){
    +   IdList *pNew;
    +   int i;
    ++  assert( db!=0 );
    +   if( p==0 ) return 0;
    +-  pNew = sqlite3DbMallocRaw(db, sizeof(*pNew) );
    ++  pNew = sqlite3DbMallocRawNN(db, sizeof(*pNew) );
    +   if( pNew==0 ) return 0;
    +   pNew->nId = p->nId;
    +-  pNew->a = sqlite3DbMallocRaw(db, p->nId*sizeof(p->a[0]) );
    ++  pNew->a = sqlite3DbMallocRawNN(db, p->nId*sizeof(p->a[0]) );
    +   if( pNew->a==0 ){
    +-    sqlite3DbFree(db, pNew);
    ++    sqlite3DbFreeNN(db, pNew);
    +     return 0;
    +   }
    +   /* Note that because the size of the allocation for p->a[] is not
    +@@ -86062,32 +94128,40 @@ SQLITE_PRIVATE IdList *sqlite3IdListDup(sqlite3 *db, IdList *p){
    +   }
    +   return pNew;
    + }
    +-SQLITE_PRIVATE Select *sqlite3SelectDup(sqlite3 *db, Select *p, int flags){
    +-  Select *pNew, *pPrior;
    +-  if( p==0 ) return 0;
    +-  pNew = sqlite3DbMallocRaw(db, sizeof(*p) );
    +-  if( pNew==0 ) return 0;
    +-  pNew->pEList = sqlite3ExprListDup(db, p->pEList, flags);
    +-  pNew->pSrc = sqlite3SrcListDup(db, p->pSrc, flags);
    +-  pNew->pWhere = sqlite3ExprDup(db, p->pWhere, flags);
    +-  pNew->pGroupBy = sqlite3ExprListDup(db, p->pGroupBy, flags);
    +-  pNew->pHaving = sqlite3ExprDup(db, p->pHaving, flags);
    +-  pNew->pOrderBy = sqlite3ExprListDup(db, p->pOrderBy, flags);
    +-  pNew->op = p->op;
    +-  pNew->pPrior = pPrior = sqlite3SelectDup(db, p->pPrior, flags);
    +-  if( pPrior ) pPrior->pNext = pNew;
    +-  pNew->pNext = 0;
    +-  pNew->pLimit = sqlite3ExprDup(db, p->pLimit, flags);
    +-  pNew->pOffset = sqlite3ExprDup(db, p->pOffset, flags);
    +-  pNew->iLimit = 0;
    +-  pNew->iOffset = 0;
    +-  pNew->selFlags = p->selFlags & ~SF_UsesEphemeral;
    +-  pNew->addrOpenEphm[0] = -1;
    +-  pNew->addrOpenEphm[1] = -1;
    +-  pNew->nSelectRow = p->nSelectRow;
    +-  pNew->pWith = withDup(db, p->pWith);
    +-  sqlite3SelectSetName(pNew, p->zSelName);
    +-  return pNew;
    ++SQLITE_PRIVATE Select *sqlite3SelectDup(sqlite3 *db, Select *pDup, int flags){
    ++  Select *pRet = 0;
    ++  Select *pNext = 0;
    ++  Select **pp = &pRet;
    ++  Select *p;
    ++
    ++  assert( db!=0 );
    ++  for(p=pDup; p; p=p->pPrior){
    ++    Select *pNew = sqlite3DbMallocRawNN(db, sizeof(*p) );
    ++    if( pNew==0 ) break;
    ++    pNew->pEList = sqlite3ExprListDup(db, p->pEList, flags);
    ++    pNew->pSrc = sqlite3SrcListDup(db, p->pSrc, flags);
    ++    pNew->pWhere = sqlite3ExprDup(db, p->pWhere, flags);
    ++    pNew->pGroupBy = sqlite3ExprListDup(db, p->pGroupBy, flags);
    ++    pNew->pHaving = sqlite3ExprDup(db, p->pHaving, flags);
    ++    pNew->pOrderBy = sqlite3ExprListDup(db, p->pOrderBy, flags);
    ++    pNew->op = p->op;
    ++    pNew->pNext = pNext;
    ++    pNew->pPrior = 0;
    ++    pNew->pLimit = sqlite3ExprDup(db, p->pLimit, flags);
    ++    pNew->iLimit = 0;
    ++    pNew->iOffset = 0;
    ++    pNew->selFlags = p->selFlags & ~SF_UsesEphemeral;
    ++    pNew->addrOpenEphm[0] = -1;
    ++    pNew->addrOpenEphm[1] = -1;
    ++    pNew->nSelectRow = p->nSelectRow;
    ++    pNew->pWith = withDup(db, p->pWith);
    ++    sqlite3SelectSetName(pNew, p->zSelName);
    ++    *pp = pNew;
    ++    pp = &pNew->pPrior;
    ++    pNext = pNew;
    ++  }
    ++
    ++  return pRet;
    + }
    + #else
    + SQLITE_PRIVATE Select *sqlite3SelectDup(sqlite3 *db, Select *p, int flags){
    +@@ -86101,6 +94175,13 @@ SQLITE_PRIVATE Select *sqlite3SelectDup(sqlite3 *db, Select *p, int flags){
    + ** Add a new element to the end of an expression list.  If pList is
    + ** initially NULL, then create a new expression list.
    + **
    ++** The pList argument must be either NULL or a pointer to an ExprList
    ++** obtained from a prior call to sqlite3ExprListAppend().  This routine
    ++** may not be used with an ExprList obtained from sqlite3ExprListDup().
    ++** Reason:  This routine assumes that the number of slots in pList->a[]
    ++** is a power of two.  That is true for sqlite3ExprListAppend() returns
    ++** but is not necessarily true from the return value of sqlite3ExprListDup().
    ++**
    + ** If a memory allocation error occurs, the entire list is freed and
    + ** NULL is returned.  If non-NULL is returned, then it is guaranteed
    + ** that the new entry was successfully appended.
    +@@ -86110,29 +94191,29 @@ SQLITE_PRIVATE ExprList *sqlite3ExprListAppend(
    +   ExprList *pList,        /* List to which to append. Might be NULL */
    +   Expr *pExpr             /* Expression to be appended. Might be NULL */
    + ){
    ++  struct ExprList_item *pItem;
    +   sqlite3 *db = pParse->db;
    ++  assert( db!=0 );
    +   if( pList==0 ){
    +-    pList = sqlite3DbMallocZero(db, sizeof(ExprList) );
    ++    pList = sqlite3DbMallocRawNN(db, sizeof(ExprList) );
    +     if( pList==0 ){
    +       goto no_mem;
    +     }
    +-    pList->a = sqlite3DbMallocRaw(db, sizeof(pList->a[0]));
    +-    if( pList->a==0 ) goto no_mem;
    ++    pList->nExpr = 0;
    +   }else if( (pList->nExpr & (pList->nExpr-1))==0 ){
    +-    struct ExprList_item *a;
    +-    assert( pList->nExpr>0 );
    +-    a = sqlite3DbRealloc(db, pList->a, pList->nExpr*2*sizeof(pList->a[0]));
    +-    if( a==0 ){
    ++    ExprList *pNew;
    ++    pNew = sqlite3DbRealloc(db, pList, 
    ++             sizeof(*pList)+(2*pList->nExpr - 1)*sizeof(pList->a[0]));
    ++    if( pNew==0 ){
    +       goto no_mem;
    +     }
    +-    pList->a = a;
    +-  }
    +-  assert( pList->a!=0 );
    +-  if( 1 ){
    +-    struct ExprList_item *pItem = &pList->a[pList->nExpr++];
    +-    memset(pItem, 0, sizeof(*pItem));
    +-    pItem->pExpr = pExpr;
    ++    pList = pNew;
    +   }
    ++  pItem = &pList->a[pList->nExpr++];
    ++  assert( offsetof(struct ExprList_item,zName)==sizeof(pItem->pExpr) );
    ++  assert( offsetof(struct ExprList_item,pExpr)==0 );
    ++  memset(&pItem->zName,0,sizeof(*pItem)-offsetof(struct ExprList_item,zName));
    ++  pItem->pExpr = pExpr;
    +   return pList;
    + 
    + no_mem:     
    +@@ -86142,6 +94223,74 @@ no_mem:
    +   return 0;
    + }
    + 
    ++/*
    ++** pColumns and pExpr form a vector assignment which is part of the SET
    ++** clause of an UPDATE statement.  Like this:
    ++**
    ++**        (a,b,c) = (expr1,expr2,expr3)
    ++** Or:    (a,b,c) = (SELECT x,y,z FROM ....)
    ++**
    ++** For each term of the vector assignment, append new entries to the
    ++** expression list pList.  In the case of a subquery on the RHS, append
    ++** TK_SELECT_COLUMN expressions.
    ++*/
    ++SQLITE_PRIVATE ExprList *sqlite3ExprListAppendVector(
    ++  Parse *pParse,         /* Parsing context */
    ++  ExprList *pList,       /* List to which to append. Might be NULL */
    ++  IdList *pColumns,      /* List of names of LHS of the assignment */
    ++  Expr *pExpr            /* Vector expression to be appended. Might be NULL */
    ++){
    ++  sqlite3 *db = pParse->db;
    ++  int n;
    ++  int i;
    ++  int iFirst = pList ? pList->nExpr : 0;
    ++  /* pColumns can only be NULL due to an OOM but an OOM will cause an
    ++  ** exit prior to this routine being invoked */
    ++  if( NEVER(pColumns==0) ) goto vector_append_error;
    ++  if( pExpr==0 ) goto vector_append_error;
    ++
    ++  /* If the RHS is a vector, then we can immediately check to see that 
    ++  ** the size of the RHS and LHS match.  But if the RHS is a SELECT, 
    ++  ** wildcards ("*") in the result set of the SELECT must be expanded before
    ++  ** we can do the size check, so defer the size check until code generation.
    ++  */
    ++  if( pExpr->op!=TK_SELECT && pColumns->nId!=(n=sqlite3ExprVectorSize(pExpr)) ){
    ++    sqlite3ErrorMsg(pParse, "%d columns assigned %d values",
    ++                    pColumns->nId, n);
    ++    goto vector_append_error;
    ++  }
    ++
    ++  for(i=0; i<pColumns->nId; i++){
    ++    Expr *pSubExpr = sqlite3ExprForVectorField(pParse, pExpr, i);
    ++    pList = sqlite3ExprListAppend(pParse, pList, pSubExpr);
    ++    if( pList ){
    ++      assert( pList->nExpr==iFirst+i+1 );
    ++      pList->a[pList->nExpr-1].zName = pColumns->a[i].zName;
    ++      pColumns->a[i].zName = 0;
    ++    }
    ++  }
    ++
    ++  if( !db->mallocFailed && pExpr->op==TK_SELECT && ALWAYS(pList!=0) ){
    ++    Expr *pFirst = pList->a[iFirst].pExpr;
    ++    assert( pFirst!=0 );
    ++    assert( pFirst->op==TK_SELECT_COLUMN );
    ++     
    ++    /* Store the SELECT statement in pRight so it will be deleted when
    ++    ** sqlite3ExprListDelete() is called */
    ++    pFirst->pRight = pExpr;
    ++    pExpr = 0;
    ++
    ++    /* Remember the size of the LHS in iTable so that we can check that
    ++    ** the RHS and LHS sizes match during code generation. */
    ++    pFirst->iTable = pColumns->nId;
    ++  }
    ++
    ++vector_append_error:
    ++  sqlite3ExprDelete(db, pExpr);
    ++  sqlite3IdListDelete(db, pColumns);
    ++  return pList;
    ++}
    ++
    + /*
    + ** Set the sort order for the last element on the given ExprList.
    + */
    +@@ -86177,7 +94326,7 @@ SQLITE_PRIVATE void sqlite3ExprListSetName(
    +     pItem = &pList->a[pList->nExpr-1];
    +     assert( pItem->zName==0 );
    +     pItem->zName = sqlite3DbStrNDup(pParse->db, pName->z, pName->n);
    +-    if( dequote && pItem->zName ) sqlite3Dequote(pItem->zName);
    ++    if( dequote ) sqlite3Dequote(pItem->zName);
    +   }
    + }
    + 
    +@@ -86192,17 +94341,16 @@ SQLITE_PRIVATE void sqlite3ExprListSetName(
    + SQLITE_PRIVATE void sqlite3ExprListSetSpan(
    +   Parse *pParse,          /* Parsing context */
    +   ExprList *pList,        /* List to which to add the span. */
    +-  ExprSpan *pSpan         /* The span to be added */
    ++  const char *zStart,     /* Start of the span */
    ++  const char *zEnd        /* End of the span */
    + ){
    +   sqlite3 *db = pParse->db;
    +   assert( pList!=0 || db->mallocFailed!=0 );
    +   if( pList ){
    +     struct ExprList_item *pItem = &pList->a[pList->nExpr-1];
    +     assert( pList->nExpr>0 );
    +-    assert( db->mallocFailed || pItem->pExpr==pSpan->pExpr );
    +     sqlite3DbFree(db, pItem->zSpan);
    +-    pItem->zSpan = sqlite3DbStrNDup(db, (char*)pSpan->zStart,
    +-                                    (int)(pSpan->zEnd - pSpan->zStart));
    ++    pItem->zSpan = sqlite3DbSpanDup(db, zStart, zEnd);
    +   }
    + }
    + 
    +@@ -86226,18 +94374,20 @@ SQLITE_PRIVATE void sqlite3ExprListCheckLength(
    + /*
    + ** Delete an entire expression list.
    + */
    +-SQLITE_PRIVATE void sqlite3ExprListDelete(sqlite3 *db, ExprList *pList){
    +-  int i;
    +-  struct ExprList_item *pItem;
    +-  if( pList==0 ) return;
    +-  assert( pList->a!=0 || pList->nExpr==0 );
    +-  for(pItem=pList->a, i=0; i<pList->nExpr; i++, pItem++){
    ++static SQLITE_NOINLINE void exprListDeleteNN(sqlite3 *db, ExprList *pList){
    ++  int i = pList->nExpr;
    ++  struct ExprList_item *pItem =  pList->a;
    ++  assert( pList->nExpr>0 );
    ++  do{
    +     sqlite3ExprDelete(db, pItem->pExpr);
    +     sqlite3DbFree(db, pItem->zName);
    +     sqlite3DbFree(db, pItem->zSpan);
    +-  }
    +-  sqlite3DbFree(db, pList->a);
    +-  sqlite3DbFree(db, pList);
    ++    pItem++;
    ++  }while( --i>0 );
    ++  sqlite3DbFreeNN(db, pList);
    ++}
    ++SQLITE_PRIVATE void sqlite3ExprListDelete(sqlite3 *db, ExprList *pList){
    ++  if( pList ) exprListDeleteNN(db, pList);
    + }
    + 
    + /*
    +@@ -86247,15 +94397,28 @@ SQLITE_PRIVATE void sqlite3ExprListDelete(sqlite3 *db, ExprList *pList){
    + SQLITE_PRIVATE u32 sqlite3ExprListFlags(const ExprList *pList){
    +   int i;
    +   u32 m = 0;
    +-  if( pList ){
    +-    for(i=0; i<pList->nExpr; i++){
    +-       Expr *pExpr = pList->a[i].pExpr;
    +-       if( ALWAYS(pExpr) ) m |= pExpr->flags;
    +-    }
    ++  assert( pList!=0 );
    ++  for(i=0; i<pList->nExpr; i++){
    ++     Expr *pExpr = pList->a[i].pExpr;
    ++     assert( pExpr!=0 );
    ++     m |= pExpr->flags;
    +   }
    +   return m;
    + }
    + 
    ++/*
    ++** This is a SELECT-node callback for the expression walker that
    ++** always "fails".  By "fail" in this case, we mean set
    ++** pWalker->eCode to zero and abort.
    ++**
    ++** This callback is used by multiple expression walkers.
    ++*/
    ++SQLITE_PRIVATE int sqlite3SelectWalkFail(Walker *pWalker, Select *NotUsed){
    ++  UNUSED_PARAMETER(NotUsed);
    ++  pWalker->eCode = 0;
    ++  return WRC_Abort;
    ++}
    ++
    + /*
    + ** These routines are Walker callbacks used to check expressions to
    + ** see if they are "constant" for some definition of constant.  The
    +@@ -86312,10 +94475,12 @@ static int exprNodeIsConstant(Walker *pWalker, Expr *pExpr){
    +       testcase( pExpr->op==TK_AGG_COLUMN );
    +       if( pWalker->eCode==3 && pExpr->iTable==pWalker->u.iCur ){
    +         return WRC_Continue;
    +-      }else{
    +-        pWalker->eCode = 0;
    +-        return WRC_Abort;
    +       }
    ++      /* Fall through */
    ++    case TK_IF_NULL_ROW:
    ++      testcase( pExpr->op==TK_IF_NULL_ROW );
    ++      pWalker->eCode = 0;
    ++      return WRC_Abort;
    +     case TK_VARIABLE:
    +       if( pWalker->eCode==5 ){
    +         /* Silently convert bound parameters that appear inside of CREATE
    +@@ -86330,22 +94495,19 @@ static int exprNodeIsConstant(Walker *pWalker, Expr *pExpr){
    +       }
    +       /* Fall through */
    +     default:
    +-      testcase( pExpr->op==TK_SELECT ); /* selectNodeIsConstant will disallow */
    +-      testcase( pExpr->op==TK_EXISTS ); /* selectNodeIsConstant will disallow */
    ++      testcase( pExpr->op==TK_SELECT ); /* sqlite3SelectWalkFail will disallow */
    ++      testcase( pExpr->op==TK_EXISTS ); /* sqlite3SelectWalkFail will disallow */
    +       return WRC_Continue;
    +   }
    + }
    +-static int selectNodeIsConstant(Walker *pWalker, Select *NotUsed){
    +-  UNUSED_PARAMETER(NotUsed);
    +-  pWalker->eCode = 0;
    +-  return WRC_Abort;
    +-}
    + static int exprIsConst(Expr *p, int initFlag, int iCur){
    +   Walker w;
    +-  memset(&w, 0, sizeof(w));
    +   w.eCode = initFlag;
    +   w.xExprCallback = exprNodeIsConstant;
    +-  w.xSelectCallback = selectNodeIsConstant;
    ++  w.xSelectCallback = sqlite3SelectWalkFail;
    ++#ifdef SQLITE_DEBUG
    ++  w.xSelectCallback2 = sqlite3SelectWalkAssert2;
    ++#endif
    +   w.u.iCur = iCur;
    +   sqlite3WalkExpr(&w, p);
    +   return w.eCode;
    +@@ -86383,6 +94545,65 @@ SQLITE_PRIVATE int sqlite3ExprIsTableConstant(Expr *p, int iCur){
    +   return exprIsConst(p, 3, iCur);
    + }
    + 
    ++
    ++/*
    ++** sqlite3WalkExpr() callback used by sqlite3ExprIsConstantOrGroupBy().
    ++*/
    ++static int exprNodeIsConstantOrGroupBy(Walker *pWalker, Expr *pExpr){
    ++  ExprList *pGroupBy = pWalker->u.pGroupBy;
    ++  int i;
    ++
    ++  /* Check if pExpr is identical to any GROUP BY term. If so, consider
    ++  ** it constant.  */
    ++  for(i=0; i<pGroupBy->nExpr; i++){
    ++    Expr *p = pGroupBy->a[i].pExpr;
    ++    if( sqlite3ExprCompare(0, pExpr, p, -1)<2 ){
    ++      CollSeq *pColl = sqlite3ExprNNCollSeq(pWalker->pParse, p);
    ++      if( sqlite3_stricmp("BINARY", pColl->zName)==0 ){
    ++        return WRC_Prune;
    ++      }
    ++    }
    ++  }
    ++
    ++  /* Check if pExpr is a sub-select. If so, consider it variable. */
    ++  if( ExprHasProperty(pExpr, EP_xIsSelect) ){
    ++    pWalker->eCode = 0;
    ++    return WRC_Abort;
    ++  }
    ++
    ++  return exprNodeIsConstant(pWalker, pExpr);
    ++}
    ++
    ++/*
    ++** Walk the expression tree passed as the first argument. Return non-zero
    ++** if the expression consists entirely of constants or copies of terms 
    ++** in pGroupBy that sort with the BINARY collation sequence.
    ++**
    ++** This routine is used to determine if a term of the HAVING clause can
    ++** be promoted into the WHERE clause.  In order for such a promotion to work,
    ++** the value of the HAVING clause term must be the same for all members of
    ++** a "group".  The requirement that the GROUP BY term must be BINARY
    ++** assumes that no other collating sequence will have a finer-grained
    ++** grouping than binary.  In other words (A=B COLLATE binary) implies
    ++** A=B in every other collating sequence.  The requirement that the
    ++** GROUP BY be BINARY is stricter than necessary.  It would also work
    ++** to promote HAVING clauses that use the same alternative collating
    ++** sequence as the GROUP BY term, but that is much harder to check,
    ++** alternative collating sequences are uncommon, and this is only an
    ++** optimization, so we take the easy way out and simply require the
    ++** GROUP BY to use the BINARY collating sequence.
    ++*/
    ++SQLITE_PRIVATE int sqlite3ExprIsConstantOrGroupBy(Parse *pParse, Expr *p, ExprList *pGroupBy){
    ++  Walker w;
    ++  w.eCode = 1;
    ++  w.xExprCallback = exprNodeIsConstantOrGroupBy;
    ++  w.xSelectCallback = 0;
    ++  w.u.pGroupBy = pGroupBy;
    ++  w.pParse = pParse;
    ++  sqlite3WalkExpr(&w, p);
    ++  return w.eCode;
    ++}
    ++
    + /*
    + ** Walk an expression tree.  Return non-zero if the expression is constant
    + ** or a function call with constant arguments.  Return and 0 if there
    +@@ -86397,6 +94618,24 @@ SQLITE_PRIVATE int sqlite3ExprIsConstantOrFunction(Expr *p, u8 isInit){
    +   return exprIsConst(p, 4+isInit, 0);
    + }
    + 
    ++#ifdef SQLITE_ENABLE_CURSOR_HINTS
    ++/*
    ++** Walk an expression tree.  Return 1 if the expression contains a
    ++** subquery of some kind.  Return 0 if there are no subqueries.
    ++*/
    ++SQLITE_PRIVATE int sqlite3ExprContainsSubquery(Expr *p){
    ++  Walker w;
    ++  w.eCode = 1;
    ++  w.xExprCallback = sqlite3ExprWalkNoop;
    ++  w.xSelectCallback = sqlite3SelectWalkFail;
    ++#ifdef SQLITE_DEBUG
    ++  w.xSelectCallback2 = sqlite3SelectWalkAssert2;
    ++#endif
    ++  sqlite3WalkExpr(&w, p);
    ++  return w.eCode==0;
    ++}
    ++#endif
    ++
    + /*
    + ** If the expression p codes a constant integer that is small enough
    + ** to fit in a 32-bit integer, return 1 and put the value of the integer
    +@@ -86405,6 +94644,7 @@ SQLITE_PRIVATE int sqlite3ExprIsConstantOrFunction(Expr *p, u8 isInit){
    + */
    + SQLITE_PRIVATE int sqlite3ExprIsInteger(Expr *p, int *pValue){
    +   int rc = 0;
    ++  if( p==0 ) return 0;  /* Can only happen following on OOM */
    + 
    +   /* If an expression is an integer literal that fits in a signed 32-bit
    +   ** integer, then the EP_IntValue flag will have already been set */
    +@@ -86460,8 +94700,8 @@ SQLITE_PRIVATE int sqlite3ExprCanBeNull(const Expr *p){
    +     case TK_BLOB:
    +       return 0;
    +     case TK_COLUMN:
    +-      assert( p->pTab!=0 );
    +       return ExprHasProperty(p, EP_CanBeNull) ||
    ++             p->pTab==0 ||  /* Reference to column of index on expression */
    +              (p->iColumn>=0 && p->pTab->aCol[p->iColumn].notNull==0);
    +     default:
    +       return 1;
    +@@ -86519,23 +94759,22 @@ SQLITE_PRIVATE int sqlite3IsRowid(const char *z){
    + }
    + 
    + /*
    +-** Return true if we are able to the IN operator optimization on a
    +-** query of the form
    +-**
    +-**       x IN (SELECT ...)
    +-**
    +-** Where the SELECT... clause is as specified by the parameter to this
    +-** routine.
    +-**
    +-** The Select object passed in has already been preprocessed and no
    +-** errors have been found.
    ++** pX is the RHS of an IN operator.  If pX is a SELECT statement 
    ++** that can be simplified to a direct table access, then return
    ++** a pointer to the SELECT statement.  If pX is not a SELECT statement,
    ++** or if the SELECT statement needs to be manifested into a transient
    ++** table, then return NULL.
    + */
    + #ifndef SQLITE_OMIT_SUBQUERY
    +-static int isCandidateForInOpt(Select *p){
    ++static Select *isCandidateForInOpt(Expr *pX){
    ++  Select *p;
    +   SrcList *pSrc;
    +   ExprList *pEList;
    +   Table *pTab;
    +-  if( p==0 ) return 0;                   /* right-hand side of IN is SELECT */
    ++  int i;
    ++  if( !ExprHasProperty(pX, EP_xIsSelect) ) return 0;  /* Not a subquery */
    ++  if( ExprHasProperty(pX, EP_VarSelect)  ) return 0;  /* Correlated subq */
    ++  p = pX->x.pSelect;
    +   if( p->pPrior ) return 0;              /* Not a compound SELECT */
    +   if( p->selFlags & (SF_Distinct|SF_Aggregate) ){
    +     testcase( (p->selFlags & (SF_Distinct|SF_Aggregate))==SF_Distinct );
    +@@ -86544,32 +94783,28 @@ static int isCandidateForInOpt(Select *p){
    +   }
    +   assert( p->pGroupBy==0 );              /* Has no GROUP BY clause */
    +   if( p->pLimit ) return 0;              /* Has no LIMIT clause */
    +-  assert( p->pOffset==0 );               /* No LIMIT means no OFFSET */
    +   if( p->pWhere ) return 0;              /* Has no WHERE clause */
    +   pSrc = p->pSrc;
    +   assert( pSrc!=0 );
    +   if( pSrc->nSrc!=1 ) return 0;          /* Single term in FROM clause */
    +   if( pSrc->a[0].pSelect ) return 0;     /* FROM is not a subquery or view */
    +   pTab = pSrc->a[0].pTab;
    +-  if( NEVER(pTab==0) ) return 0;
    ++  assert( pTab!=0 );
    +   assert( pTab->pSelect==0 );            /* FROM clause is not a view */
    +   if( IsVirtual(pTab) ) return 0;        /* FROM clause not a virtual table */
    +   pEList = p->pEList;
    +-  if( pEList->nExpr!=1 ) return 0;       /* One column in the result set */
    +-  if( pEList->a[0].pExpr->op!=TK_COLUMN ) return 0; /* Result is a column */
    +-  return 1;
    ++  assert( pEList!=0 );
    ++  /* All SELECT results must be columns. */
    ++  for(i=0; i<pEList->nExpr; i++){
    ++    Expr *pRes = pEList->a[i].pExpr;
    ++    if( pRes->op!=TK_COLUMN ) return 0;
    ++    assert( pRes->iTable==pSrc->a[0].iCursor );  /* Not a correlated subquery */
    ++  }
    ++  return p;
    + }
    + #endif /* SQLITE_OMIT_SUBQUERY */
    + 
    +-/*
    +-** Code an OP_Once instruction and allocate space for its flag. Return the 
    +-** address of the new instruction.
    +-*/
    +-SQLITE_PRIVATE int sqlite3CodeOnce(Parse *pParse){
    +-  Vdbe *v = sqlite3GetVdbe(pParse);      /* Virtual machine being coded */
    +-  return sqlite3VdbeAddOp1(v, OP_Once, pParse->nOnce++);
    +-}
    +-
    ++#ifndef SQLITE_OMIT_SUBQUERY
    + /*
    + ** 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
    +@@ -86585,6 +94820,7 @@ static void sqlite3SetHasNullFlag(Vdbe *v, int iCur, int regHasNull){
    +   VdbeComment((v, "first_entry_in(%d)", iCur));
    +   sqlite3VdbeJumpHere(v, addr1);
    + }
    ++#endif
    + 
    + 
    + #ifndef SQLITE_OMIT_SUBQUERY
    +@@ -86629,30 +94865,29 @@ static int sqlite3InRhsIsConstant(Expr *pIn){
    + ** An existing b-tree might be used if the RHS expression pX is a simple
    + ** subquery such as:
    + **
    +-**     SELECT <column> FROM <table>
    ++**     SELECT <column1>, <column2>... FROM <table>
    + **
    + ** 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 ephemeral table instead of an
    + ** existing table.
    + **
    +-** 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.
    ++** The inFlags parameter must contain, at a minimum, one of the bits
    ++** IN_INDEX_MEMBERSHIP or IN_INDEX_LOOP but not both.  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 <column> is guaranteed
    +-** to be unique - either because it is an INTEGER PRIMARY KEY or it
    +-** has a UNIQUE constraint or UNIQUE index.
    ++** An epheremal table will be created unless the selected columns are guaranteed
    ++** to be unique - either because it is an INTEGER PRIMARY KEY or due to
    ++** a UNIQUE constraint or index.
    + **
    + ** 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 <column> is an INTEGER PRIMARY KEY or an index can 
    +-** be found with <column> as its left-most column.
    ++** be used unless <columns> is a single INTEGER PRIMARY KEY column or an 
    ++** index can be found with the specified <columns> as its left-most.
    + **
    + ** 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
    +@@ -86673,9 +94908,26 @@ static int sqlite3InRhsIsConstant(Expr *pIn){
    + ** 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.
    ++**
    ++** If the aiMap parameter is not NULL, it must point to an array containing
    ++** one element for each column returned by the SELECT statement on the RHS
    ++** of the IN(...) operator. The i'th entry of the array is populated with the
    ++** offset of the index column that matches the i'th column returned by the
    ++** SELECT. For example, if the expression and selected index are:
    ++**
    ++**   (?,?,?) IN (SELECT a, b, c FROM t1)
    ++**   CREATE INDEX i1 ON t1(b, c, a);
    ++**
    ++** then aiMap[] is populated with {2, 0, 1}.
    + */
    + #ifndef SQLITE_OMIT_SUBQUERY
    +-SQLITE_PRIVATE int sqlite3FindInIndex(Parse *pParse, Expr *pX, u32 inFlags, int *prRhsHasNull){
    ++SQLITE_PRIVATE int sqlite3FindInIndex(
    ++  Parse *pParse,             /* Parsing context */
    ++  Expr *pX,                  /* The right-hand side (RHS) of the IN operator */
    ++  u32 inFlags,               /* IN_INDEX_LOOP, _MEMBERSHIP, and/or _NOOP_OK */
    ++  int *prRhsHasNull,         /* Register holding NULL status.  See notes */
    ++  int *aiMap                 /* Mapping from Index fields to RHS fields */
    ++){
    +   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 */
    +@@ -86685,38 +94937,46 @@ SQLITE_PRIVATE int sqlite3FindInIndex(Parse *pParse, Expr *pX, u32 inFlags, int
    +   assert( pX->op==TK_IN );
    +   mustBeUnique = (inFlags & IN_INDEX_LOOP)!=0;
    + 
    ++  /* If the RHS of this IN(...) operator is a SELECT, and if it matters 
    ++  ** whether or not the SELECT result contains NULL values, check whether
    ++  ** or not NULL is actually possible (it may not be, for example, due 
    ++  ** to NOT NULL constraints in the schema). If no NULL values are possible,
    ++  ** set prRhsHasNull to 0 before continuing.  */
    ++  if( prRhsHasNull && (pX->flags & EP_xIsSelect) ){
    ++    int i;
    ++    ExprList *pEList = pX->x.pSelect->pEList;
    ++    for(i=0; i<pEList->nExpr; i++){
    ++      if( sqlite3ExprCanBeNull(pEList->a[i].pExpr) ) break;
    ++    }
    ++    if( i==pEList->nExpr ){
    ++      prRhsHasNull = 0;
    ++    }
    ++  }
    ++
    +   /* Check to see if an existing table or index can be used to
    +   ** satisfy the query.  This is preferable to generating a new 
    +-  ** ephemeral table.
    +-  */
    +-  p = (ExprHasProperty(pX, EP_xIsSelect) ? pX->x.pSelect : 0);
    +-  if( pParse->nErr==0 && isCandidateForInOpt(p) ){
    ++  ** ephemeral table.  */
    ++  if( pParse->nErr==0 && (p = isCandidateForInOpt(pX))!=0 ){
    +     sqlite3 *db = pParse->db;              /* Database connection */
    +     Table *pTab;                           /* Table <table>. */
    +-    Expr *pExpr;                           /* Expression <column> */
    +-    i16 iCol;                              /* Index of column <column> */
    +     i16 iDb;                               /* Database idx for pTab */
    ++    ExprList *pEList = p->pEList;
    ++    int nExpr = pEList->nExpr;
    + 
    +-    assert( p );                        /* Because of isCandidateForInOpt(p) */
    +     assert( p->pEList!=0 );             /* Because of isCandidateForInOpt(p) */
    +     assert( p->pEList->a[0].pExpr!=0 ); /* Because of isCandidateForInOpt(p) */
    +     assert( p->pSrc!=0 );               /* Because of isCandidateForInOpt(p) */
    +     pTab = p->pSrc->a[0].pTab;
    +-    pExpr = p->pEList->a[0].pExpr;
    +-    iCol = (i16)pExpr->iColumn;
    +-   
    ++
    +     /* Code an OP_Transaction and OP_TableLock for <table>. */
    +     iDb = sqlite3SchemaToIndex(db, pTab->pSchema);
    +     sqlite3CodeVerifySchema(pParse, iDb);
    +     sqlite3TableLock(pParse, iDb, pTab->tnum, 0, pTab->zName);
    + 
    +-    /* This function is only called from two places. In both cases the vdbe
    +-    ** has already been allocated. So assume sqlite3GetVdbe() is always
    +-    ** successful here.
    +-    */
    +-    assert(v);
    +-    if( iCol<0 ){
    +-      int iAddr = sqlite3CodeOnce(pParse);
    ++    assert(v);  /* sqlite3GetVdbe() has always been previously called */
    ++    if( nExpr==1 && pEList->a[0].pExpr->iColumn<0 ){
    ++      /* The "x IN (SELECT rowid FROM table)" case */
    ++      int iAddr = sqlite3VdbeAddOp0(v, OP_Once);
    +       VdbeCoverage(v);
    + 
    +       sqlite3OpenTable(pParse, iTab, iDb, pTab, OP_OpenRead);
    +@@ -86725,44 +94985,114 @@ SQLITE_PRIVATE int sqlite3FindInIndex(Parse *pParse, Expr *pX, u32 inFlags, int
    +       sqlite3VdbeJumpHere(v, iAddr);
    +     }else{
    +       Index *pIdx;                         /* Iterator variable */
    ++      int affinity_ok = 1;
    ++      int i;
    + 
    +-      /* The collation sequence used by the comparison. If an index is to
    +-      ** be used in place of a temp-table, it must be ordered according
    +-      ** to this collation sequence.  */
    +-      CollSeq *pReq = sqlite3BinaryCompareCollSeq(pParse, pX->pLeft, pExpr);
    +-
    +-      /* Check that the affinity that will be used to perform the 
    +-      ** comparison is the same as the affinity of the column. If
    +-      ** it is not, it is not possible to use any index.
    +-      */
    +-      int affinity_ok = sqlite3IndexAffinityOk(pX, pTab->aCol[iCol].affinity);
    +-
    +-      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 && IsUniqueIndex(pIdx)))
    +-        ){
    +-          int iAddr = sqlite3CodeOnce(pParse); VdbeCoverage(v);
    +-          sqlite3VdbeAddOp3(v, OP_OpenRead, iTab, pIdx->tnum, iDb);
    +-          sqlite3VdbeSetP4KeyInfo(pParse, pIdx);
    +-          VdbeComment((v, "%s", pIdx->zName));
    +-          assert( IN_INDEX_INDEX_DESC == IN_INDEX_INDEX_ASC+1 );
    +-          eType = IN_INDEX_INDEX_ASC + pIdx->aSortOrder[0];
    +-
    +-          if( prRhsHasNull && !pTab->aCol[iCol].notNull ){
    +-            *prRhsHasNull = ++pParse->nMem;
    +-            sqlite3SetHasNullFlag(v, iTab, *prRhsHasNull);
    ++      /* Check that the affinity that will be used to perform each 
    ++      ** comparison is the same as the affinity of each column in table
    ++      ** on the RHS of the IN operator.  If it not, it is not possible to
    ++      ** use any index of the RHS table.  */
    ++      for(i=0; i<nExpr && affinity_ok; i++){
    ++        Expr *pLhs = sqlite3VectorFieldSubexpr(pX->pLeft, i);
    ++        int iCol = pEList->a[i].pExpr->iColumn;
    ++        char idxaff = sqlite3TableColumnAffinity(pTab,iCol); /* RHS table */
    ++        char cmpaff = sqlite3CompareAffinity(pLhs, idxaff);
    ++        testcase( cmpaff==SQLITE_AFF_BLOB );
    ++        testcase( cmpaff==SQLITE_AFF_TEXT );
    ++        switch( cmpaff ){
    ++          case SQLITE_AFF_BLOB:
    ++            break;
    ++          case SQLITE_AFF_TEXT:
    ++            /* sqlite3CompareAffinity() only returns TEXT if one side or the
    ++            ** other has no affinity and the other side is TEXT.  Hence,
    ++            ** the only way for cmpaff to be TEXT is for idxaff to be TEXT
    ++            ** and for the term on the LHS of the IN to have no affinity. */
    ++            assert( idxaff==SQLITE_AFF_TEXT );
    ++            break;
    ++          default:
    ++            affinity_ok = sqlite3IsNumericAffinity(idxaff);
    ++        }
    ++      }
    ++
    ++      if( affinity_ok ){
    ++        /* Search for an existing index that will work for this IN operator */
    ++        for(pIdx=pTab->pIndex; pIdx && eType==0; pIdx=pIdx->pNext){
    ++          Bitmask colUsed;      /* Columns of the index used */
    ++          Bitmask mCol;         /* Mask for the current column */
    ++          if( pIdx->nColumn<nExpr ) continue;
    ++          /* Maximum nColumn is BMS-2, not BMS-1, so that we can compute
    ++          ** BITMASK(nExpr) without overflowing */
    ++          testcase( pIdx->nColumn==BMS-2 );
    ++          testcase( pIdx->nColumn==BMS-1 );
    ++          if( pIdx->nColumn>=BMS-1 ) continue;
    ++          if( mustBeUnique ){
    ++            if( pIdx->nKeyCol>nExpr
    ++             ||(pIdx->nColumn>nExpr && !IsUniqueIndex(pIdx))
    ++            ){
    ++              continue;  /* This index is not unique over the IN RHS columns */
    ++            }
    +           }
    +-          sqlite3VdbeJumpHere(v, iAddr);
    +-        }
    +-      }
    +-    }
    +-  }
    ++  
    ++          colUsed = 0;   /* Columns of index used so far */
    ++          for(i=0; i<nExpr; i++){
    ++            Expr *pLhs = sqlite3VectorFieldSubexpr(pX->pLeft, i);
    ++            Expr *pRhs = pEList->a[i].pExpr;
    ++            CollSeq *pReq = sqlite3BinaryCompareCollSeq(pParse, pLhs, pRhs);
    ++            int j;
    ++  
    ++            assert( pReq!=0 || pRhs->iColumn==XN_ROWID || pParse->nErr );
    ++            for(j=0; j<nExpr; j++){
    ++              if( pIdx->aiColumn[j]!=pRhs->iColumn ) continue;
    ++              assert( pIdx->azColl[j] );
    ++              if( pReq!=0 && sqlite3StrICmp(pReq->zName, pIdx->azColl[j])!=0 ){
    ++                continue;
    ++              }
    ++              break;
    ++            }
    ++            if( j==nExpr ) break;
    ++            mCol = MASKBIT(j);
    ++            if( mCol & colUsed ) break; /* Each column used only once */
    ++            colUsed |= mCol;
    ++            if( aiMap ) aiMap[i] = j;
    ++          }
    ++  
    ++          assert( i==nExpr || colUsed!=(MASKBIT(nExpr)-1) );
    ++          if( colUsed==(MASKBIT(nExpr)-1) ){
    ++            /* If we reach this point, that means the index pIdx is usable */
    ++            int iAddr = sqlite3VdbeAddOp0(v, OP_Once); VdbeCoverage(v);
    ++#ifndef SQLITE_OMIT_EXPLAIN
    ++            sqlite3VdbeAddOp4(v, OP_Explain, 0, 0, 0,
    ++              sqlite3MPrintf(db, "USING INDEX %s FOR IN-OPERATOR",pIdx->zName),
    ++              P4_DYNAMIC);
    ++#endif
    ++            sqlite3VdbeAddOp3(v, OP_OpenRead, iTab, pIdx->tnum, iDb);
    ++            sqlite3VdbeSetP4KeyInfo(pParse, pIdx);
    ++            VdbeComment((v, "%s", pIdx->zName));
    ++            assert( IN_INDEX_INDEX_DESC == IN_INDEX_INDEX_ASC+1 );
    ++            eType = IN_INDEX_INDEX_ASC + pIdx->aSortOrder[0];
    ++  
    ++            if( prRhsHasNull ){
    ++#ifdef SQLITE_ENABLE_COLUMN_USED_MASK
    ++              i64 mask = (1<<nExpr)-1;
    ++              sqlite3VdbeAddOp4Dup8(v, OP_ColumnsUsed, 
    ++                  iTab, 0, 0, (u8*)&mask, P4_INT64);
    ++#endif
    ++              *prRhsHasNull = ++pParse->nMem;
    ++              if( nExpr==1 ){
    ++                sqlite3SetHasNullFlag(v, iTab, *prRhsHasNull);
    ++              }
    ++            }
    ++            sqlite3VdbeJumpHere(v, iAddr);
    ++          }
    ++        } /* End loop over indexes */
    ++      } /* End if( affinity_ok ) */
    ++    } /* End if not an rowid index */
    ++  } /* End attempt to optimize using an index */
    + 
    +   /* 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,
    ++  ** and the RHS is not constant or has two or fewer terms,
    +   ** then it is not worth creating an ephemeral table to evaluate
    +   ** the IN operator so return IN_INDEX_NOOP.
    +   */
    +@@ -86773,7 +95103,6 @@ SQLITE_PRIVATE int sqlite3FindInIndex(Parse *pParse, Expr *pX, u32 inFlags, int
    +   ){
    +     eType = IN_INDEX_NOOP;
    +   }
    +-     
    + 
    +   if( eType==0 ){
    +     /* Could not find an existing table or index to use as the RHS b-tree.
    +@@ -86795,10 +95124,85 @@ SQLITE_PRIVATE int sqlite3FindInIndex(Parse *pParse, Expr *pX, u32 inFlags, int
    +   }else{
    +     pX->iTable = iTab;
    +   }
    ++
    ++  if( aiMap && eType!=IN_INDEX_INDEX_ASC && eType!=IN_INDEX_INDEX_DESC ){
    ++    int i, n;
    ++    n = sqlite3ExprVectorSize(pX->pLeft);
    ++    for(i=0; i<n; i++) aiMap[i] = i;
    ++  }
    +   return eType;
    + }
    + #endif
    + 
    ++#ifndef SQLITE_OMIT_SUBQUERY
    ++/*
    ++** Argument pExpr is an (?, ?...) IN(...) expression. This 
    ++** function allocates and returns a nul-terminated string containing 
    ++** the affinities to be used for each column of the comparison.
    ++**
    ++** It is the responsibility of the caller to ensure that the returned
    ++** string is eventually freed using sqlite3DbFree().
    ++*/
    ++static char *exprINAffinity(Parse *pParse, Expr *pExpr){
    ++  Expr *pLeft = pExpr->pLeft;
    ++  int nVal = sqlite3ExprVectorSize(pLeft);
    ++  Select *pSelect = (pExpr->flags & EP_xIsSelect) ? pExpr->x.pSelect : 0;
    ++  char *zRet;
    ++
    ++  assert( pExpr->op==TK_IN );
    ++  zRet = sqlite3DbMallocRaw(pParse->db, nVal+1);
    ++  if( zRet ){
    ++    int i;
    ++    for(i=0; i<nVal; i++){
    ++      Expr *pA = sqlite3VectorFieldSubexpr(pLeft, i);
    ++      char a = sqlite3ExprAffinity(pA);
    ++      if( pSelect ){
    ++        zRet[i] = sqlite3CompareAffinity(pSelect->pEList->a[i].pExpr, a);
    ++      }else{
    ++        zRet[i] = a;
    ++      }
    ++    }
    ++    zRet[nVal] = '\0';
    ++  }
    ++  return zRet;
    ++}
    ++#endif
    ++
    ++#ifndef SQLITE_OMIT_SUBQUERY
    ++/*
    ++** Load the Parse object passed as the first argument with an error 
    ++** message of the form:
    ++**
    ++**   "sub-select returns N columns - expected M"
    ++*/   
    ++SQLITE_PRIVATE void sqlite3SubselectError(Parse *pParse, int nActual, int nExpect){
    ++  const char *zFmt = "sub-select returns %d columns - expected %d";
    ++  sqlite3ErrorMsg(pParse, zFmt, nActual, nExpect);
    ++}
    ++#endif
    ++
    ++/*
    ++** Expression pExpr is a vector that has been used in a context where
    ++** it is not permitted. If pExpr is a sub-select vector, this routine 
    ++** loads the Parse object with a message of the form:
    ++**
    ++**   "sub-select returns N columns - expected 1"
    ++**
    ++** Or, if it is a regular scalar vector:
    ++**
    ++**   "row value misused"
    ++*/   
    ++SQLITE_PRIVATE void sqlite3VectorErrorMsg(Parse *pParse, Expr *pExpr){
    ++#ifndef SQLITE_OMIT_SUBQUERY
    ++  if( pExpr->flags & EP_xIsSelect ){
    ++    sqlite3SubselectError(pParse, pExpr->x.pSelect->pEList->nExpr, 1);
    ++  }else
    ++#endif
    ++  {
    ++    sqlite3ErrorMsg(pParse, "row value misused");
    ++  }
    ++}
    ++
    + /*
    + ** Generate code for scalar subqueries used as a subquery expression, EXISTS,
    + ** or IN operators.  Examples:
    +@@ -86824,7 +95228,9 @@ SQLITE_PRIVATE int sqlite3FindInIndex(Parse *pParse, Expr *pX, u32 inFlags, int
    + ** 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.
    ++** result.  For a multi-column SELECT, the result is stored in a contiguous
    ++** array of registers and the return value is the register of the left-most
    ++** result column.  Return 0 for IN operators or if an error occurs.
    + */
    + #ifndef SQLITE_OMIT_SUBQUERY
    + SQLITE_PRIVATE int sqlite3CodeSubselect(
    +@@ -86839,8 +95245,8 @@ SQLITE_PRIVATE int sqlite3CodeSubselect(
    +   if( NEVER(v==0) ) return 0;
    +   sqlite3ExprCachePush(pParse);
    + 
    +-  /* This code must be run in its entirety every time it is encountered
    +-  ** if any of the following is true:
    ++  /* The evaluation of the IN/EXISTS/SELECT must be repeated every time it
    ++  ** is encountered if any of the following is true:
    +   **
    +   **    *  The right-hand side is a correlated subquery
    +   **    *  The right-hand side is an expression list containing variables
    +@@ -86850,14 +95256,15 @@ SQLITE_PRIVATE int sqlite3CodeSubselect(
    +   ** save the results, and reuse the same result on subsequent invocations.
    +   */
    +   if( !ExprHasProperty(pExpr, EP_VarSelect) ){
    +-    jmpIfDynamic = sqlite3CodeOnce(pParse); VdbeCoverage(v);
    ++    jmpIfDynamic = sqlite3VdbeAddOp0(v, OP_Once); VdbeCoverage(v);
    +   }
    + 
    + #ifndef SQLITE_OMIT_EXPLAIN
    +   if( pParse->explain==2 ){
    +-    char *zMsg = sqlite3MPrintf(
    +-        pParse->db, "EXECUTE %s%s SUBQUERY %d", jmpIfDynamic>=0?"":"CORRELATED ",
    +-        pExpr->op==TK_IN?"LIST":"SCALAR", pParse->iNextSelectId
    ++    char *zMsg = sqlite3MPrintf(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);
    +   }
    +@@ -86865,17 +95272,18 @@ SQLITE_PRIVATE int sqlite3CodeSubselect(
    + 
    +   switch( pExpr->op ){
    +     case TK_IN: {
    +-      char affinity;              /* Affinity of the LHS of the IN */
    +       int addr;                   /* Address of OP_OpenEphemeral instruction */
    +       Expr *pLeft = pExpr->pLeft; /* the LHS of the IN operator */
    +       KeyInfo *pKeyInfo = 0;      /* Key information */
    +-
    +-      affinity = sqlite3ExprAffinity(pLeft);
    ++      int nVal;                   /* Size of vector pLeft */
    ++      
    ++      nVal = sqlite3ExprVectorSize(pLeft);
    ++      assert( !isRowid || nVal==1 );
    + 
    +       /* Whether this is an 'x IN(SELECT...)' or an 'x IN(<exprlist>)'
    +       ** expression it is handled the same way.  An ephemeral table is 
    +-      ** filled with single-field index keys representing the results
    +-      ** from the SELECT or the <exprlist>.
    ++      ** filled with index keys representing the results from the 
    ++      ** SELECT or the <exprlist>.
    +       **
    +       ** If the 'x' expression is a column value, or the SELECT...
    +       ** statement returns a column value, then the affinity of that
    +@@ -86886,8 +95294,9 @@ SQLITE_PRIVATE int sqlite3CodeSubselect(
    +       ** is used.
    +       */
    +       pExpr->iTable = pParse->nTab++;
    +-      addr = sqlite3VdbeAddOp2(v, OP_OpenEphemeral, pExpr->iTable, !isRowid);
    +-      pKeyInfo = isRowid ? 0 : sqlite3KeyInfoAlloc(pParse->db, 1, 1);
    ++      addr = sqlite3VdbeAddOp2(v, OP_OpenEphemeral, 
    ++          pExpr->iTable, (isRowid?0:nVal));
    ++      pKeyInfo = isRowid ? 0 : sqlite3KeyInfoAlloc(pParse->db, nVal, 1);
    + 
    +       if( ExprHasProperty(pExpr, EP_xIsSelect) ){
    +         /* Case 1:     expr IN (SELECT ...)
    +@@ -86896,27 +95305,36 @@ SQLITE_PRIVATE int sqlite3CodeSubselect(
    +         ** table allocated and opened above.
    +         */
    +         Select *pSelect = pExpr->x.pSelect;
    +-        SelectDest dest;
    +-        ExprList *pEList;
    ++        ExprList *pEList = pSelect->pEList;
    + 
    +         assert( !isRowid );
    +-        sqlite3SelectDestInit(&dest, SRT_Set, pExpr->iTable);
    +-        dest.affSdst = (u8)affinity;
    +-        assert( (pExpr->iTable&0x0000FFFF)==pExpr->iTable );
    +-        pSelect->iLimit = 0;
    +-        testcase( pSelect->selFlags & SF_Distinct );
    +-        testcase( pKeyInfo==0 ); /* Caused by OOM in sqlite3KeyInfoAlloc() */
    +-        if( sqlite3Select(pParse, pSelect, &dest) ){
    +-          sqlite3KeyInfoUnref(pKeyInfo);
    +-          return 0;
    ++        /* If the LHS and RHS of the IN operator do not match, that
    ++        ** error will have been caught long before we reach this point. */
    ++        if( ALWAYS(pEList->nExpr==nVal) ){
    ++          SelectDest dest;
    ++          int i;
    ++          sqlite3SelectDestInit(&dest, SRT_Set, pExpr->iTable);
    ++          dest.zAffSdst = exprINAffinity(pParse, pExpr);
    ++          pSelect->iLimit = 0;
    ++          testcase( pSelect->selFlags & SF_Distinct );
    ++          testcase( pKeyInfo==0 ); /* Caused by OOM in sqlite3KeyInfoAlloc() */
    ++          if( sqlite3Select(pParse, pSelect, &dest) ){
    ++            sqlite3DbFree(pParse->db, dest.zAffSdst);
    ++            sqlite3KeyInfoUnref(pKeyInfo);
    ++            return 0;
    ++          }
    ++          sqlite3DbFree(pParse->db, dest.zAffSdst);
    ++          assert( pKeyInfo!=0 ); /* OOM will cause exit after sqlite3Select() */
    ++          assert( pEList!=0 );
    ++          assert( pEList->nExpr>0 );
    ++          assert( sqlite3KeyInfoIsWriteable(pKeyInfo) );
    ++          for(i=0; i<nVal; i++){
    ++            Expr *p = sqlite3VectorFieldSubexpr(pLeft, i);
    ++            pKeyInfo->aColl[i] = sqlite3BinaryCompareCollSeq(
    ++                pParse, p, pEList->a[i].pExpr
    ++            );
    ++          }
    +         }
    +-        pEList = pSelect->pEList;
    +-        assert( pKeyInfo!=0 ); /* OOM will cause exit after sqlite3Select() */
    +-        assert( pEList!=0 );
    +-        assert( pEList->nExpr>0 );
    +-        assert( sqlite3KeyInfoIsWriteable(pKeyInfo) );
    +-        pKeyInfo->aColl[0] = sqlite3BinaryCompareCollSeq(pParse, pExpr->pLeft,
    +-                                                         pEList->a[0].pExpr);
    +       }else if( ALWAYS(pExpr->x.pList!=0) ){
    +         /* Case 2:     expr IN (exprlist)
    +         **
    +@@ -86925,11 +95343,13 @@ SQLITE_PRIVATE int sqlite3CodeSubselect(
    +         ** that columns affinity when building index keys. If <expr> is not
    +         ** a column, use numeric affinity.
    +         */
    ++        char affinity;            /* Affinity of the LHS of the IN */
    +         int i;
    +         ExprList *pList = pExpr->x.pList;
    +         struct ExprList_item *pItem;
    +         int r1, r2, r3;
    + 
    ++        affinity = sqlite3ExprAffinity(pLeft);
    +         if( !affinity ){
    +           affinity = SQLITE_AFF_BLOB;
    +         }
    +@@ -86941,7 +95361,7 @@ SQLITE_PRIVATE int sqlite3CodeSubselect(
    +         /* Loop through each expression in <exprlist>. */
    +         r1 = sqlite3GetTempReg(pParse);
    +         r2 = sqlite3GetTempReg(pParse);
    +-        if( isRowid ) sqlite3VdbeAddOp2(v, OP_Null, 0, r2);
    ++        if( isRowid ) sqlite3VdbeAddOp4(v, OP_Blob, 0, r2, 0, "", P4_STATIC);
    +         for(i=pList->nExpr, pItem=pList->a; i>0; i--, pItem++){
    +           Expr *pE2 = pItem->pExpr;
    +           int iValToIns;
    +@@ -86969,7 +95389,7 @@ SQLITE_PRIVATE int sqlite3CodeSubselect(
    +             }else{
    +               sqlite3VdbeAddOp4(v, OP_MakeRecord, r3, 1, r2, &affinity, 1);
    +               sqlite3ExprCacheAffinityChange(pParse, r3, 1);
    +-              sqlite3VdbeAddOp2(v, OP_IdxInsert, pExpr->iTable, r2);
    ++              sqlite3VdbeAddOp4Int(v, OP_IdxInsert, pExpr->iTable, r2, r3, 1);
    +             }
    +           }
    +         }
    +@@ -86985,37 +95405,52 @@ SQLITE_PRIVATE int sqlite3CodeSubselect(
    +     case TK_EXISTS:
    +     case TK_SELECT:
    +     default: {
    +-      /* If this has to be a scalar SELECT.  Generate code to put the
    +-      ** value of this select in a memory cell and record the number
    +-      ** of the memory cell in iColumn.  If this is an EXISTS, write
    +-      ** an integer 0 (not exists) or 1 (exists) into a memory cell
    +-      ** and record that memory cell in iColumn.
    ++      /* Case 3:    (SELECT ... FROM ...)
    ++      **     or:    EXISTS(SELECT ... FROM ...)
    ++      **
    ++      ** For a SELECT, generate code to put the values for all columns of
    ++      ** the first row into an array of registers and return the index of
    ++      ** the first register.
    ++      **
    ++      ** If this is an EXISTS, write an integer 0 (not exists) or 1 (exists)
    ++      ** into a register and return that register number.
    ++      **
    ++      ** In both cases, the query is augmented with "LIMIT 1".  Any 
    ++      ** preexisting limit is discarded in place of the new LIMIT 1.
    +       */
    +       Select *pSel;                         /* SELECT statement to encode */
    +-      SelectDest dest;                      /* How to deal with SELECt result */
    ++      SelectDest dest;                      /* How to deal with SELECT result */
    ++      int nReg;                             /* Registers to allocate */
    ++      Expr *pLimit;                         /* New limit expression */
    + 
    +       testcase( pExpr->op==TK_EXISTS );
    +       testcase( pExpr->op==TK_SELECT );
    +       assert( pExpr->op==TK_EXISTS || pExpr->op==TK_SELECT );
    +-
    +       assert( ExprHasProperty(pExpr, EP_xIsSelect) );
    ++
    +       pSel = pExpr->x.pSelect;
    +-      sqlite3SelectDestInit(&dest, 0, ++pParse->nMem);
    ++      nReg = pExpr->op==TK_SELECT ? pSel->pEList->nExpr : 1;
    ++      sqlite3SelectDestInit(&dest, 0, pParse->nMem+1);
    ++      pParse->nMem += nReg;
    +       if( pExpr->op==TK_SELECT ){
    +         dest.eDest = SRT_Mem;
    +         dest.iSdst = dest.iSDParm;
    +-        sqlite3VdbeAddOp2(v, OP_Null, 0, dest.iSDParm);
    ++        dest.nSdst = nReg;
    ++        sqlite3VdbeAddOp3(v, OP_Null, 0, dest.iSDParm, dest.iSDParm+nReg-1);
    +         VdbeComment((v, "Init subquery result"));
    +       }else{
    +         dest.eDest = SRT_Exists;
    +         sqlite3VdbeAddOp2(v, OP_Integer, 0, dest.iSDParm);
    +         VdbeComment((v, "Init EXISTS result"));
    +       }
    +-      sqlite3ExprDelete(pParse->db, pSel->pLimit);
    +-      pSel->pLimit = sqlite3PExpr(pParse, TK_INTEGER, 0, 0,
    +-                                  &sqlite3IntTokens[1]);
    ++      pLimit = sqlite3ExprAlloc(pParse->db, TK_INTEGER,&sqlite3IntTokens[1], 0);
    ++      if( pSel->pLimit ){
    ++        sqlite3ExprDelete(pParse->db, pSel->pLimit->pLeft);
    ++        pSel->pLimit->pLeft = pLimit;
    ++      }else{
    ++        pSel->pLimit = sqlite3PExpr(pParse, TK_LIMIT, pLimit, 0);
    ++      }
    +       pSel->iLimit = 0;
    +-      pSel->selFlags &= ~SF_MultiValue;
    +       if( sqlite3Select(pParse, pSel, &dest) ){
    +         return 0;
    +       }
    +@@ -87038,6 +95473,28 @@ SQLITE_PRIVATE int sqlite3CodeSubselect(
    + }
    + #endif /* SQLITE_OMIT_SUBQUERY */
    + 
    ++#ifndef SQLITE_OMIT_SUBQUERY
    ++/*
    ++** Expr pIn is an IN(...) expression. This function checks that the 
    ++** sub-select on the RHS of the IN() operator has the same number of 
    ++** columns as the vector on the LHS. Or, if the RHS of the IN() is not 
    ++** a sub-query, that the LHS is a vector of size 1.
    ++*/
    ++SQLITE_PRIVATE int sqlite3ExprCheckIN(Parse *pParse, Expr *pIn){
    ++  int nVector = sqlite3ExprVectorSize(pIn->pLeft);
    ++  if( (pIn->flags & EP_xIsSelect) ){
    ++    if( nVector!=pIn->x.pSelect->pEList->nExpr ){
    ++      sqlite3SubselectError(pParse, pIn->x.pSelect->pEList->nExpr, nVector);
    ++      return 1;
    ++    }
    ++  }else if( nVector!=1 ){
    ++    sqlite3VectorErrorMsg(pParse, pIn->pLeft);
    ++    return 1;
    ++  }
    ++  return 0;
    ++}
    ++#endif
    ++
    + #ifndef SQLITE_OMIT_SUBQUERY
    + /*
    + ** Generate code for an IN expression.
    +@@ -87045,16 +95502,24 @@ SQLITE_PRIVATE int sqlite3CodeSubselect(
    + **      x IN (SELECT ...)
    + **      x IN (value, value, ...)
    + **
    +-** The left-hand side (LHS) is a scalar expression.  The right-hand side (RHS)
    +-** is an array of zero or more values.  The expression is true if the LHS is
    +-** contained within the RHS.  The value of the expression is unknown (NULL)
    +-** if the LHS is NULL or if the LHS is not contained within the RHS and the
    +-** RHS contains one or more NULL values.
    ++** The left-hand side (LHS) is a scalar or vector expression.  The 
    ++** right-hand side (RHS) is an array of zero or more scalar values, or a
    ++** subquery.  If the RHS is a subquery, the number of result columns must
    ++** match the number of columns in the vector on the LHS.  If the RHS is
    ++** a list of values, the LHS must be a scalar. 
    ++**
    ++** The IN operator is true if the LHS value is contained within the RHS.
    ++** The result is false if the LHS is definitely not in the RHS.  The 
    ++** result is NULL if the presence of the LHS in the RHS cannot be 
    ++** determined due to NULLs.
    + **
    + ** 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.
    ++**
    ++** See the separate in-operator.md documentation file in the canonical
    ++** SQLite source tree for additional information.
    + */
    + static void sqlite3ExprCodeIN(
    +   Parse *pParse,        /* Parsing and code generating context */
    +@@ -87063,36 +95528,83 @@ static void sqlite3ExprCodeIN(
    +   int destIfNull        /* Jump here if the results are unknown due to NULLs */
    + ){
    +   int rRhsHasNull = 0;  /* Register that is true if RHS contains NULL values */
    +-  char affinity;        /* Comparison affinity to use */
    +   int eType;            /* Type of the RHS */
    +-  int r1;               /* Temporary use register */
    ++  int rLhs;             /* Register(s) holding the LHS values */
    ++  int rLhsOrig;         /* LHS values prior to reordering by aiMap[] */
    +   Vdbe *v;              /* Statement under construction */
    ++  int *aiMap = 0;       /* Map from vector field to index column */
    ++  char *zAff = 0;       /* Affinity string for comparisons */
    ++  int nVector;          /* Size of vectors for this IN operator */
    ++  int iDummy;           /* Dummy parameter to exprCodeVector() */
    ++  Expr *pLeft;          /* The LHS of the IN operator */
    ++  int i;                /* loop counter */
    ++  int destStep2;        /* Where to jump when NULLs seen in step 2 */
    ++  int destStep6 = 0;    /* Start of code for Step 6 */
    ++  int addrTruthOp;      /* Address of opcode that determines the IN is true */
    ++  int destNotNull;      /* Jump here if a comparison is not true in step 6 */
    ++  int addrTop;          /* Top of the step-6 loop */ 
    ++
    ++  pLeft = pExpr->pLeft;
    ++  if( sqlite3ExprCheckIN(pParse, pExpr) ) return;
    ++  zAff = exprINAffinity(pParse, pExpr);
    ++  nVector = sqlite3ExprVectorSize(pExpr->pLeft);
    ++  aiMap = (int*)sqlite3DbMallocZero(
    ++      pParse->db, nVector*(sizeof(int) + sizeof(char)) + 1
    ++  );
    ++  if( pParse->db->mallocFailed ) goto sqlite3ExprCodeIN_oom_error;
    + 
    +-  /* Compute the RHS.   After this step, the table with cursor
    +-  ** pExpr->iTable will contains the values that make up the RHS.
    +-  */
    ++  /* Attempt to compute the RHS. After this step, if anything other than
    ++  ** IN_INDEX_NOOP is returned, the table opened ith cursor pExpr->iTable 
    ++  ** contains the values that make up the RHS. If IN_INDEX_NOOP is returned,
    ++  ** the RHS has not yet been coded.  */
    +   v = pParse->pVdbe;
    +   assert( v!=0 );       /* OOM detected prior to this routine */
    +   VdbeNoopComment((v, "begin IN expr"));
    +   eType = sqlite3FindInIndex(pParse, pExpr,
    +                              IN_INDEX_MEMBERSHIP | IN_INDEX_NOOP_OK,
    +-                             destIfFalse==destIfNull ? 0 : &rRhsHasNull);
    ++                             destIfFalse==destIfNull ? 0 : &rRhsHasNull, aiMap);
    + 
    +-  /* Figure out the affinity to use to create a key from the results
    +-  ** of the expression. affinityStr stores a static string suitable for
    +-  ** P4 of OP_MakeRecord.
    +-  */
    +-  affinity = comparisonAffinity(pExpr);
    ++  assert( pParse->nErr || nVector==1 || eType==IN_INDEX_EPH
    ++       || eType==IN_INDEX_INDEX_ASC || eType==IN_INDEX_INDEX_DESC 
    ++  );
    ++#ifdef SQLITE_DEBUG
    ++  /* Confirm that aiMap[] contains nVector integer values between 0 and
    ++  ** nVector-1. */
    ++  for(i=0; i<nVector; i++){
    ++    int j, cnt;
    ++    for(cnt=j=0; j<nVector; j++) if( aiMap[j]==i ) cnt++;
    ++    assert( cnt==1 );
    ++  }
    ++#endif
    + 
    +-  /* Code the LHS, the <expr> from "<expr> IN (...)".
    ++  /* Code the LHS, the <expr> from "<expr> IN (...)". If the LHS is a 
    ++  ** vector, then it is stored in an array of nVector registers starting 
    ++  ** at r1.
    ++  **
    ++  ** sqlite3FindInIndex() might have reordered the fields of the LHS vector
    ++  ** so that the fields are in the same order as an existing index.   The
    ++  ** aiMap[] array contains a mapping from the original LHS field order to
    ++  ** the field order that matches the RHS index.
    +   */
    +   sqlite3ExprCachePush(pParse);
    +-  r1 = sqlite3GetTempReg(pParse);
    +-  sqlite3ExprCode(pParse, pExpr->pLeft, r1);
    ++  rLhsOrig = exprCodeVector(pParse, pLeft, &iDummy);
    ++  for(i=0; i<nVector && aiMap[i]==i; i++){} /* Are LHS fields reordered? */
    ++  if( i==nVector ){
    ++    /* LHS fields are not reordered */
    ++    rLhs = rLhsOrig;
    ++  }else{
    ++    /* Need to reorder the LHS fields according to aiMap */
    ++    rLhs = sqlite3GetTempRange(pParse, nVector);
    ++    for(i=0; i<nVector; i++){
    ++      sqlite3VdbeAddOp3(v, OP_Copy, rLhsOrig+i, rLhs+aiMap[i], 0);
    ++    }
    ++  }
    + 
    +   /* If sqlite3FindInIndex() did not find or create an index that is
    +   ** suitable for evaluating the IN operator, then evaluate using a
    +   ** sequence of comparisons.
    ++  **
    ++  ** This is step (1) in the in-operator.md optimized algorithm.
    +   */
    +   if( eType==IN_INDEX_NOOP ){
    +     ExprList *pList = pExpr->x.pList;
    +@@ -87104,7 +95616,7 @@ static void sqlite3ExprCodeIN(
    +     assert( !ExprHasProperty(pExpr, EP_xIsSelect) );
    +     if( destIfNull!=destIfFalse ){
    +       regCkNull = sqlite3GetTempReg(pParse);
    +-      sqlite3VdbeAddOp3(v, OP_BitAnd, r1, r1, regCkNull);
    ++      sqlite3VdbeAddOp3(v, OP_BitAnd, rLhs, rLhs, regCkNull);
    +     }
    +     for(ii=0; ii<pList->nExpr; ii++){
    +       r2 = sqlite3ExprCodeTemp(pParse, pList->a[ii].pExpr, &regToFree);
    +@@ -87112,16 +95624,16 @@ static void sqlite3ExprCodeIN(
    +         sqlite3VdbeAddOp3(v, OP_BitAnd, regCkNull, r2, regCkNull);
    +       }
    +       if( ii<pList->nExpr-1 || destIfNull!=destIfFalse ){
    +-        sqlite3VdbeAddOp4(v, OP_Eq, r1, labelOk, r2,
    ++        sqlite3VdbeAddOp4(v, OP_Eq, rLhs, labelOk, r2,
    +                           (void*)pColl, P4_COLLSEQ);
    +         VdbeCoverageIf(v, ii<pList->nExpr-1);
    +         VdbeCoverageIf(v, ii==pList->nExpr-1);
    +-        sqlite3VdbeChangeP5(v, affinity);
    ++        sqlite3VdbeChangeP5(v, zAff[0]);
    +       }else{
    +         assert( destIfNull==destIfFalse );
    +-        sqlite3VdbeAddOp4(v, OP_Ne, r1, destIfFalse, r2,
    ++        sqlite3VdbeAddOp4(v, OP_Ne, rLhs, destIfFalse, r2,
    +                           (void*)pColl, P4_COLLSEQ); VdbeCoverage(v);
    +-        sqlite3VdbeChangeP5(v, affinity | SQLITE_JUMPIFNULL);
    ++        sqlite3VdbeChangeP5(v, zAff[0] | SQLITE_JUMPIFNULL);
    +       }
    +       sqlite3ReleaseTempReg(pParse, regToFree);
    +     }
    +@@ -87131,78 +95643,113 @@ static void sqlite3ExprCodeIN(
    +     }
    +     sqlite3VdbeResolveLabel(v, labelOk);
    +     sqlite3ReleaseTempReg(pParse, regCkNull);
    ++    goto sqlite3ExprCodeIN_finished;
    ++  }
    ++
    ++  /* Step 2: Check to see if the LHS contains any NULL columns.  If the
    ++  ** LHS does contain NULLs then the result must be either FALSE or NULL.
    ++  ** We will then skip the binary search of the RHS.
    ++  */
    ++  if( destIfNull==destIfFalse ){
    ++    destStep2 = destIfFalse;
    +   }else{
    +-  
    +-    /* If the LHS is NULL, then the result is either false or NULL depending
    +-    ** on whether the RHS is empty or not, respectively.
    +-    */
    +-    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);
    +-        sqlite3VdbeGoto(v, destIfNull);
    +-        sqlite3VdbeJumpHere(v, addr1);
    +-      }
    +-    }
    +-  
    +-    if( eType==IN_INDEX_ROWID ){
    +-      /* In this case, the RHS is the ROWID of table b-tree
    +-      */
    +-      sqlite3VdbeAddOp2(v, OP_MustBeInt, r1, destIfFalse); VdbeCoverage(v);
    +-      sqlite3VdbeAddOp3(v, OP_NotExists, pExpr->iTable, destIfFalse, r1);
    ++    destStep2 = destStep6 = sqlite3VdbeMakeLabel(v);
    ++  }
    ++  for(i=0; i<nVector; i++){
    ++    Expr *p = sqlite3VectorFieldSubexpr(pExpr->pLeft, i);
    ++    if( sqlite3ExprCanBeNull(p) ){
    ++      sqlite3VdbeAddOp2(v, OP_IsNull, rLhs+i, destStep2);
    +       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.
    +-      */
    +-      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 addr1;
    +-  
    +-        /* 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.
    +-        */
    +-        addr1 = sqlite3VdbeAddOp4Int(v, OP_Found, pExpr->iTable, 0, r1, 1);
    +-        VdbeCoverage(v);
    +-        sqlite3VdbeAddOp2(v, OP_IsNull, rRhsHasNull, destIfNull);
    +-        VdbeCoverage(v);
    +-        sqlite3VdbeGoto(v, destIfFalse);
    +-        sqlite3VdbeJumpHere(v, addr1);
    +-      }
    +     }
    +   }
    +-  sqlite3ReleaseTempReg(pParse, r1);
    ++
    ++  /* Step 3.  The LHS is now known to be non-NULL.  Do the binary search
    ++  ** of the RHS using the LHS as a probe.  If found, the result is
    ++  ** true.
    ++  */
    ++  if( eType==IN_INDEX_ROWID ){
    ++    /* In this case, the RHS is the ROWID of table b-tree and so we also
    ++    ** know that the RHS is non-NULL.  Hence, we combine steps 3 and 4
    ++    ** into a single opcode. */
    ++    sqlite3VdbeAddOp3(v, OP_SeekRowid, pExpr->iTable, destIfFalse, rLhs);
    ++    VdbeCoverage(v);
    ++    addrTruthOp = sqlite3VdbeAddOp0(v, OP_Goto);  /* Return True */
    ++  }else{
    ++    sqlite3VdbeAddOp4(v, OP_Affinity, rLhs, nVector, 0, zAff, nVector);
    ++    if( destIfFalse==destIfNull ){
    ++      /* Combine Step 3 and Step 5 into a single opcode */
    ++      sqlite3VdbeAddOp4Int(v, OP_NotFound, pExpr->iTable, destIfFalse,
    ++                           rLhs, nVector); VdbeCoverage(v);
    ++      goto sqlite3ExprCodeIN_finished;
    ++    }
    ++    /* Ordinary Step 3, for the case where FALSE and NULL are distinct */
    ++    addrTruthOp = sqlite3VdbeAddOp4Int(v, OP_Found, pExpr->iTable, 0,
    ++                                      rLhs, nVector); VdbeCoverage(v);
    ++  }
    ++
    ++  /* Step 4.  If the RHS is known to be non-NULL and we did not find
    ++  ** an match on the search above, then the result must be FALSE.
    ++  */
    ++  if( rRhsHasNull && nVector==1 ){
    ++    sqlite3VdbeAddOp2(v, OP_NotNull, rRhsHasNull, destIfFalse);
    ++    VdbeCoverage(v);
    ++  }
    ++
    ++  /* Step 5.  If we do not care about the difference between NULL and
    ++  ** FALSE, then just return false. 
    ++  */
    ++  if( destIfFalse==destIfNull ) sqlite3VdbeGoto(v, destIfFalse);
    ++
    ++  /* Step 6: Loop through rows of the RHS.  Compare each row to the LHS.
    ++  ** If any comparison is NULL, then the result is NULL.  If all
    ++  ** comparisons are FALSE then the final result is FALSE.
    ++  **
    ++  ** For a scalar LHS, it is sufficient to check just the first row
    ++  ** of the RHS.
    ++  */
    ++  if( destStep6 ) sqlite3VdbeResolveLabel(v, destStep6);
    ++  addrTop = sqlite3VdbeAddOp2(v, OP_Rewind, pExpr->iTable, destIfFalse);
    ++  VdbeCoverage(v);
    ++  if( nVector>1 ){
    ++    destNotNull = sqlite3VdbeMakeLabel(v);
    ++  }else{
    ++    /* For nVector==1, combine steps 6 and 7 by immediately returning
    ++    ** FALSE if the first comparison is not NULL */
    ++    destNotNull = destIfFalse;
    ++  }
    ++  for(i=0; i<nVector; i++){
    ++    Expr *p;
    ++    CollSeq *pColl;
    ++    int r3 = sqlite3GetTempReg(pParse);
    ++    p = sqlite3VectorFieldSubexpr(pLeft, i);
    ++    pColl = sqlite3ExprCollSeq(pParse, p);
    ++    sqlite3VdbeAddOp3(v, OP_Column, pExpr->iTable, i, r3);
    ++    sqlite3VdbeAddOp4(v, OP_Ne, rLhs+i, destNotNull, r3,
    ++                      (void*)pColl, P4_COLLSEQ);
    ++    VdbeCoverage(v);
    ++    sqlite3ReleaseTempReg(pParse, r3);
    ++  }
    ++  sqlite3VdbeAddOp2(v, OP_Goto, 0, destIfNull);
    ++  if( nVector>1 ){
    ++    sqlite3VdbeResolveLabel(v, destNotNull);
    ++    sqlite3VdbeAddOp2(v, OP_Next, pExpr->iTable, addrTop+1);
    ++    VdbeCoverage(v);
    ++
    ++    /* Step 7:  If we reach this point, we know that the result must
    ++    ** be false. */
    ++    sqlite3VdbeAddOp2(v, OP_Goto, 0, destIfFalse);
    ++  }
    ++
    ++  /* Jumps here in order to return true. */
    ++  sqlite3VdbeJumpHere(v, addrTruthOp);
    ++
    ++sqlite3ExprCodeIN_finished:
    ++  if( rLhs!=rLhsOrig ) sqlite3ReleaseTempReg(pParse, rLhs);
    +   sqlite3ExprCachePop(pParse);
    +   VdbeComment((v, "end IN expr"));
    ++sqlite3ExprCodeIN_oom_error:
    ++  sqlite3DbFree(pParse->db, aiMap);
    ++  sqlite3DbFree(pParse->db, zAff);
    + }
    + #endif /* SQLITE_OMIT_SUBQUERY */
    + 
    +@@ -87246,35 +95793,38 @@ static void codeInteger(Parse *pParse, Expr *pExpr, int negFlag, int iMem){
    +     const char *z = pExpr->u.zToken;
    +     assert( z!=0 );
    +     c = sqlite3DecOrHexToI64(z, &value);
    +-    if( c==0 || (c==2 && negFlag) ){
    +-      if( negFlag ){ value = c==2 ? SMALLEST_INT64 : -value; }
    +-      sqlite3VdbeAddOp4Dup8(v, OP_Int64, 0, iMem, 0, (u8*)&value, P4_INT64);
    +-    }else{
    ++    if( (c==3 && !negFlag) || (c==2) || (negFlag && value==SMALLEST_INT64)){
    + #ifdef SQLITE_OMIT_FLOATING_POINT
    +       sqlite3ErrorMsg(pParse, "oversized integer: %s%s", negFlag ? "-" : "", z);
    + #else
    + #ifndef SQLITE_OMIT_HEX_INTEGER
    +       if( sqlite3_strnicmp(z,"0x",2)==0 ){
    +-        sqlite3ErrorMsg(pParse, "hex literal too big: %s", z);
    ++        sqlite3ErrorMsg(pParse, "hex literal too big: %s%s", negFlag?"-":"",z);
    +       }else
    + #endif
    +       {
    +         codeReal(v, z, negFlag, iMem);
    +       }
    + #endif
    ++    }else{
    ++      if( negFlag ){ value = c==3 ? SMALLEST_INT64 : -value; }
    ++      sqlite3VdbeAddOp4Dup8(v, OP_Int64, 0, iMem, 0, (u8*)&value, P4_INT64);
    +     }
    +   }
    + }
    + 
    + /*
    +-** Clear a cache entry.
    ++** Erase column-cache entry number i
    + */
    +-static void cacheEntryClear(Parse *pParse, struct yColCache *p){
    +-  if( p->tempReg ){
    ++static void cacheEntryClear(Parse *pParse, int i){
    ++  if( pParse->aColCache[i].tempReg ){
    +     if( pParse->nTempReg<ArraySize(pParse->aTempReg) ){
    +-      pParse->aTempReg[pParse->nTempReg++] = p->iReg;
    ++      pParse->aTempReg[pParse->nTempReg++] = pParse->aColCache[i].iReg;
    +     }
    +-    p->tempReg = 0;
    ++  }
    ++  pParse->nColCache--;
    ++  if( i<pParse->nColCache ){
    ++    pParse->aColCache[i] = pParse->aColCache[pParse->nColCache];
    +   }
    + }
    + 
    +@@ -87305,43 +95855,33 @@ SQLITE_PRIVATE void sqlite3ExprCacheStore(Parse *pParse, int iTab, int iCol, int
    +   ** that the object will never already be in cache.  Verify this guarantee.
    +   */
    + #ifndef NDEBUG
    +-  for(i=0, p=pParse->aColCache; i<SQLITE_N_COLCACHE; i++, p++){
    +-    assert( p->iReg==0 || p->iTable!=iTab || p->iColumn!=iCol );
    ++  for(i=0, p=pParse->aColCache; i<pParse->nColCache; i++, p++){
    ++    assert( p->iTable!=iTab || p->iColumn!=iCol );
    +   }
    + #endif
    + 
    +-  /* Find an empty slot and replace it */
    +-  for(i=0, p=pParse->aColCache; i<SQLITE_N_COLCACHE; i++, p++){
    +-    if( p->iReg==0 ){
    +-      p->iLevel = pParse->iCacheLevel;
    +-      p->iTable = iTab;
    +-      p->iColumn = iCol;
    +-      p->iReg = iReg;
    +-      p->tempReg = 0;
    +-      p->lru = pParse->iCacheCnt++;
    +-      return;
    +-    }
    +-  }
    +-
    +-  /* Replace the last recently used */
    +-  minLru = 0x7fffffff;
    +-  idxLru = -1;
    +-  for(i=0, p=pParse->aColCache; i<SQLITE_N_COLCACHE; i++, p++){
    +-    if( p->lru<minLru ){
    +-      idxLru = i;
    +-      minLru = p->lru;
    ++  /* If the cache is already full, delete the least recently used entry */
    ++  if( pParse->nColCache>=SQLITE_N_COLCACHE ){
    ++    minLru = 0x7fffffff;
    ++    idxLru = -1;
    ++    for(i=0, p=pParse->aColCache; i<SQLITE_N_COLCACHE; i++, p++){
    ++      if( p->lru<minLru ){
    ++        idxLru = i;
    ++        minLru = p->lru;
    ++      }
    +     }
    +-  }
    +-  if( ALWAYS(idxLru>=0) ){
    +     p = &pParse->aColCache[idxLru];
    +-    p->iLevel = pParse->iCacheLevel;
    +-    p->iTable = iTab;
    +-    p->iColumn = iCol;
    +-    p->iReg = iReg;
    +-    p->tempReg = 0;
    +-    p->lru = pParse->iCacheCnt++;
    +-    return;
    ++  }else{
    ++    p = &pParse->aColCache[pParse->nColCache++];
    +   }
    ++
    ++  /* Add the new entry to the end of the cache */
    ++  p->iLevel = pParse->iCacheLevel;
    ++  p->iTable = iTab;
    ++  p->iColumn = iCol;
    ++  p->iReg = iReg;
    ++  p->tempReg = 0;
    ++  p->lru = pParse->iCacheCnt++;
    + }
    + 
    + /*
    +@@ -87349,14 +95889,13 @@ SQLITE_PRIVATE void sqlite3ExprCacheStore(Parse *pParse, int iTab, int iCol, int
    + ** Purge the range of registers from the column cache.
    + */
    + SQLITE_PRIVATE void sqlite3ExprCacheRemove(Parse *pParse, int iReg, int nReg){
    +-  int i;
    +-  int iLast = iReg + nReg - 1;
    +-  struct yColCache *p;
    +-  for(i=0, p=pParse->aColCache; i<SQLITE_N_COLCACHE; i++, p++){
    +-    int r = p->iReg;
    +-    if( r>=iReg && r<=iLast ){
    +-      cacheEntryClear(pParse, p);
    +-      p->iReg = 0;
    ++  int i = 0;
    ++  while( i<pParse->nColCache ){
    ++    struct yColCache *p = &pParse->aColCache[i];
    ++    if( p->iReg >= iReg && p->iReg < iReg+nReg ){
    ++      cacheEntryClear(pParse, i);
    ++    }else{
    ++      i++;
    +     }
    +   }
    + }
    +@@ -87381,8 +95920,7 @@ SQLITE_PRIVATE void sqlite3ExprCachePush(Parse *pParse){
    + ** the cache to the state it was in prior the most recent Push.
    + */
    + SQLITE_PRIVATE void sqlite3ExprCachePop(Parse *pParse){
    +-  int i;
    +-  struct yColCache *p;
    ++  int i = 0;
    +   assert( pParse->iCacheLevel>=1 );
    +   pParse->iCacheLevel--;
    + #ifdef SQLITE_DEBUG
    +@@ -87390,10 +95928,11 @@ SQLITE_PRIVATE void sqlite3ExprCachePop(Parse *pParse){
    +     printf("POP  to %d\n", pParse->iCacheLevel);
    +   }
    + #endif
    +-  for(i=0, p=pParse->aColCache; i<SQLITE_N_COLCACHE; i++, p++){
    +-    if( p->iReg && p->iLevel>pParse->iCacheLevel ){
    +-      cacheEntryClear(pParse, p);
    +-      p->iReg = 0;
    ++  while( i<pParse->nColCache ){
    ++    if( pParse->aColCache[i].iLevel>pParse->iCacheLevel ){
    ++      cacheEntryClear(pParse, i);
    ++    }else{
    ++      i++;
    +     }
    +   }
    + }
    +@@ -87407,7 +95946,7 @@ SQLITE_PRIVATE void sqlite3ExprCachePop(Parse *pParse){
    + static void sqlite3ExprCachePinRegister(Parse *pParse, int iReg){
    +   int i;
    +   struct yColCache *p;
    +-  for(i=0, p=pParse->aColCache; i<SQLITE_N_COLCACHE; i++, p++){
    ++  for(i=0, p=pParse->aColCache; i<pParse->nColCache; i++, p++){
    +     if( p->iReg==iReg ){
    +       p->tempReg = 0;
    +     }
    +@@ -87428,8 +95967,9 @@ SQLITE_PRIVATE void sqlite3ExprCodeLoadIndexColumn(
    +   if( iTabCol==XN_EXPR ){
    +     assert( pIdx->aColExpr );
    +     assert( pIdx->aColExpr->nExpr>iIdxCol );
    +-    pParse->iSelfTab = iTabCur;
    +-    sqlite3ExprCode(pParse, pIdx->aColExpr->a[iIdxCol].pExpr, regOut);
    ++    pParse->iSelfTab = iTabCur + 1;
    ++    sqlite3ExprCodeCopy(pParse, pIdx->aColExpr->a[iIdxCol].pExpr, regOut);
    ++    pParse->iSelfTab = 0;
    +   }else{
    +     sqlite3ExprCodeGetColumnOfTable(pParse->pVdbe, pIdx->pTable, iTabCur,
    +                                     iTabCol, regOut);
    +@@ -87446,12 +95986,16 @@ SQLITE_PRIVATE void sqlite3ExprCodeGetColumnOfTable(
    +   int iCol,       /* Index of the column to extract */
    +   int regOut      /* Extract the value into this register */
    + ){
    ++  if( pTab==0 ){
    ++    sqlite3VdbeAddOp3(v, OP_Column, iTabCur, iCol, regOut);
    ++    return;
    ++  }
    +   if( iCol<0 || iCol==pTab->iPKey ){
    +     sqlite3VdbeAddOp2(v, OP_Rowid, iTabCur, regOut);
    +   }else{
    +     int op = IsVirtual(pTab) ? OP_VColumn : OP_Column;
    +     int x = iCol;
    +-    if( !HasRowid(pTab) ){
    ++    if( !HasRowid(pTab) && !IsVirtual(pTab) ){
    +       x = sqlite3ColumnOfIndex(sqlite3PrimaryKeyIndex(pTab), iCol);
    +     }
    +     sqlite3VdbeAddOp3(v, op, iTabCur, x, regOut);
    +@@ -87463,9 +96007,12 @@ SQLITE_PRIVATE void sqlite3ExprCodeGetColumnOfTable(
    + 
    + /*
    + ** Generate code that will extract the iColumn-th column from
    +-** table pTab and store the column value in a register.  An effort
    +-** is made to store the column value in register iReg, but this is
    +-** not guaranteed.  The location of the column value is returned.
    ++** table pTab and store the column value in a register. 
    ++**
    ++** An effort is made to store the column value in register iReg.  This
    ++** is not garanteeed for GetColumn() - the result can be stored in
    ++** any register.  But the result is guaranteed to land in register iReg
    ++** for GetColumnToReg().
    + **
    + ** There must be an open cursor to pTab in iTable when this routine
    + ** is called.  If iColumn<0 then code is generated that extracts the rowid.
    +@@ -87476,14 +96023,14 @@ SQLITE_PRIVATE int sqlite3ExprCodeGetColumn(
    +   int iColumn,     /* Index of the table column */
    +   int iTable,      /* The cursor pointing to the table */
    +   int iReg,        /* Store results here */
    +-  u8 p5            /* P5 value for OP_Column */
    ++  u8 p5            /* P5 value for OP_Column + FLAGS */
    + ){
    +   Vdbe *v = pParse->pVdbe;
    +   int i;
    +   struct yColCache *p;
    + 
    +-  for(i=0, p=pParse->aColCache; i<SQLITE_N_COLCACHE; i++, p++){
    +-    if( p->iReg>0 && p->iTable==iTable && p->iColumn==iColumn ){
    ++  for(i=0, p=pParse->aColCache; i<pParse->nColCache; i++, p++){
    ++    if( p->iTable==iTable && p->iColumn==iColumn ){
    +       p->lru = pParse->iCacheCnt++;
    +       sqlite3ExprCachePinRegister(pParse, p->iReg);
    +       return p->iReg;
    +@@ -87498,25 +96045,37 @@ SQLITE_PRIVATE int sqlite3ExprCodeGetColumn(
    +   }
    +   return iReg;
    + }
    ++SQLITE_PRIVATE void sqlite3ExprCodeGetColumnToReg(
    ++  Parse *pParse,   /* Parsing and code generating context */
    ++  Table *pTab,     /* Description of the table we are reading from */
    ++  int iColumn,     /* Index of the table column */
    ++  int iTable,      /* The cursor pointing to the table */
    ++  int iReg         /* Store results here */
    ++){
    ++  int r1 = sqlite3ExprCodeGetColumn(pParse, pTab, iColumn, iTable, iReg, 0);
    ++  if( r1!=iReg ) sqlite3VdbeAddOp2(pParse->pVdbe, OP_SCopy, r1, iReg);
    ++}
    ++
    + 
    + /*
    + ** Clear all column cache entries.
    + */
    + SQLITE_PRIVATE void sqlite3ExprCacheClear(Parse *pParse){
    +   int i;
    +-  struct yColCache *p;
    + 
    +-#if SQLITE_DEBUG
    ++#ifdef SQLITE_DEBUG
    +   if( pParse->db->flags & SQLITE_VdbeAddopTrace ){
    +     printf("CLEAR\n");
    +   }
    + #endif
    +-  for(i=0, p=pParse->aColCache; i<SQLITE_N_COLCACHE; i++, p++){
    +-    if( p->iReg ){
    +-      cacheEntryClear(pParse, p);
    +-      p->iReg = 0;
    ++  for(i=0; i<pParse->nColCache; i++){
    ++    if( pParse->aColCache[i].tempReg
    ++     && pParse->nTempReg<ArraySize(pParse->aTempReg)
    ++    ){
    ++       pParse->aTempReg[pParse->nTempReg++] = pParse->aColCache[i].iReg;
    +     }
    +   }
    ++  pParse->nColCache = 0;
    + }
    + 
    + /*
    +@@ -87548,7 +96107,7 @@ SQLITE_PRIVATE void sqlite3ExprCodeMove(Parse *pParse, int iFrom, int iTo, int n
    + static int usedAsColumnCache(Parse *pParse, int iFrom, int iTo){
    +   int i;
    +   struct yColCache *p;
    +-  for(i=0, p=pParse->aColCache; i<SQLITE_N_COLCACHE; i++, p++){
    ++  for(i=0, p=pParse->aColCache; i<pParse->nColCache; i++, p++){
    +     int r = p->iReg;
    +     if( r>=iFrom && r<=iTo ) return 1;    /*NO_TEST*/
    +   }
    +@@ -87556,8 +96115,11 @@ static int usedAsColumnCache(Parse *pParse, int iFrom, int iTo){
    + }
    + #endif /* SQLITE_DEBUG || SQLITE_COVERAGE_TEST */
    + 
    ++
    + /*
    +-** Convert an expression node to a TK_REGISTER
    ++** Convert a scalar expression node to a TK_REGISTER referencing
    ++** register iReg.  The caller must ensure that iReg already contains
    ++** the correct value for the expression.
    + */
    + static void exprToRegister(Expr *p, int iReg){
    +   p->op2 = p->op;
    +@@ -87566,6 +96128,42 @@ static void exprToRegister(Expr *p, int iReg){
    +   ExprClearProperty(p, EP_Skip);
    + }
    + 
    ++/*
    ++** Evaluate an expression (either a vector or a scalar expression) and store
    ++** the result in continguous temporary registers.  Return the index of
    ++** the first register used to store the result.
    ++**
    ++** If the returned result register is a temporary scalar, then also write
    ++** that register number into *piFreeable.  If the returned result register
    ++** is not a temporary or if the expression is a vector set *piFreeable
    ++** to 0.
    ++*/
    ++static int exprCodeVector(Parse *pParse, Expr *p, int *piFreeable){
    ++  int iResult;
    ++  int nResult = sqlite3ExprVectorSize(p);
    ++  if( nResult==1 ){
    ++    iResult = sqlite3ExprCodeTemp(pParse, p, piFreeable);
    ++  }else{
    ++    *piFreeable = 0;
    ++    if( p->op==TK_SELECT ){
    ++#if SQLITE_OMIT_SUBQUERY
    ++      iResult = 0;
    ++#else
    ++      iResult = sqlite3CodeSubselect(pParse, p, 0, 0);
    ++#endif
    ++    }else{
    ++      int i;
    ++      iResult = pParse->nMem+1;
    ++      pParse->nMem += nResult;
    ++      for(i=0; i<nResult; i++){
    ++        sqlite3ExprCodeFactorable(pParse, p->x.pList->a[i].pExpr, i+iResult);
    ++      }
    ++    }
    ++  }
    ++  return iResult;
    ++}
    ++
    ++
    + /*
    + ** Generate code into the current Vdbe to evaluate the given
    + ** expression.  Attempt to store the results in register "target".
    +@@ -87583,9 +96181,9 @@ SQLITE_PRIVATE int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target)
    +   int inReg = target;       /* Results stored in register inReg */
    +   int regFree1 = 0;         /* If non-zero free this temporary register */
    +   int regFree2 = 0;         /* If non-zero free this temporary register */
    +-  int r1, r2, r3, r4;       /* Various register numbers */
    +-  sqlite3 *db = pParse->db; /* The database connection */
    ++  int r1, r2;               /* Various register numbers */
    +   Expr tempX;               /* Temporary expression node */
    ++  int p5 = 0;
    + 
    +   assert( target>0 && target<=pParse->nMem );
    +   if( v==0 ){
    +@@ -87604,52 +96202,49 @@ SQLITE_PRIVATE int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target)
    +       struct AggInfo_col *pCol = &pAggInfo->aCol[pExpr->iAgg];
    +       if( !pAggInfo->directMode ){
    +         assert( pCol->iMem>0 );
    +-        inReg = pCol->iMem;
    +-        break;
    ++        return pCol->iMem;
    +       }else if( pAggInfo->useSortingIdx ){
    +         sqlite3VdbeAddOp3(v, OP_Column, pAggInfo->sortingIdxPTab,
    +                               pCol->iSorterColumn, target);
    +-        break;
    ++        return target;
    +       }
    +       /* Otherwise, fall thru into the TK_COLUMN case */
    +     }
    +     case TK_COLUMN: {
    +       int iTab = pExpr->iTable;
    +       if( iTab<0 ){
    +-        if( pParse->ckBase>0 ){
    ++        if( pParse->iSelfTab<0 ){
    +           /* Generating CHECK constraints or inserting into partial index */
    +-          inReg = pExpr->iColumn + pParse->ckBase;
    +-          break;
    ++          return pExpr->iColumn - pParse->iSelfTab;
    +         }else{
    +           /* Coding an expression that is part of an index where column names
    +           ** in the index refer to the table to which the index belongs */
    +-          iTab = pParse->iSelfTab;
    ++          iTab = pParse->iSelfTab - 1;
    +         }
    +       }
    +-      inReg = sqlite3ExprCodeGetColumn(pParse, pExpr->pTab,
    ++      return sqlite3ExprCodeGetColumn(pParse, pExpr->pTab,
    +                                pExpr->iColumn, iTab, target,
    +                                pExpr->op2);
    +-      break;
    +     }
    +     case TK_INTEGER: {
    +       codeInteger(pParse, pExpr, 0, target);
    +-      break;
    ++      return target;
    +     }
    + #ifndef SQLITE_OMIT_FLOATING_POINT
    +     case TK_FLOAT: {
    +       assert( !ExprHasProperty(pExpr, EP_IntValue) );
    +       codeReal(v, pExpr->u.zToken, 0, target);
    +-      break;
    ++      return target;
    +     }
    + #endif
    +     case TK_STRING: {
    +       assert( !ExprHasProperty(pExpr, EP_IntValue) );
    +       sqlite3VdbeLoadString(v, target, pExpr->u.zToken);
    +-      break;
    ++      return target;
    +     }
    +     case TK_NULL: {
    +       sqlite3VdbeAddOp2(v, OP_Null, 0, target);
    +-      break;
    ++      return target;
    +     }
    + #ifndef SQLITE_OMIT_BLOB_LITERAL
    +     case TK_BLOB: {
    +@@ -87664,7 +96259,7 @@ SQLITE_PRIVATE int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target)
    +       assert( z[n]=='\'' );
    +       zBlob = sqlite3HexToBlob(sqlite3VdbeDb(v), z, n);
    +       sqlite3VdbeAddOp4(v, OP_Blob, n/2, target, 0, zBlob, P4_DYNAMIC);
    +-      break;
    ++      return target;
    +     }
    + #endif
    +     case TK_VARIABLE: {
    +@@ -87673,15 +96268,15 @@ SQLITE_PRIVATE int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target)
    +       assert( pExpr->u.zToken[0]!=0 );
    +       sqlite3VdbeAddOp2(v, OP_Variable, pExpr->iColumn, target);
    +       if( pExpr->u.zToken[1]!=0 ){
    +-        assert( pExpr->u.zToken[0]=='?' 
    +-             || strcmp(pExpr->u.zToken, pParse->azVar[pExpr->iColumn-1])==0 );
    +-        sqlite3VdbeChangeP4(v, -1, pParse->azVar[pExpr->iColumn-1], P4_STATIC);
    ++        const char *z = sqlite3VListNumToName(pParse->pVList, pExpr->iColumn);
    ++        assert( pExpr->u.zToken[0]=='?' || strcmp(pExpr->u.zToken, z)==0 );
    ++        pParse->pVList[0] = 0; /* Indicate VList may no longer be enlarged */
    ++        sqlite3VdbeAppendP4(v, (char*)z, P4_STATIC);
    +       }
    +-      break;
    ++      return target;
    +     }
    +     case TK_REGISTER: {
    +-      inReg = pExpr->iTable;
    +-      break;
    ++      return pExpr->iTable;
    +     }
    + #ifndef SQLITE_OMIT_CAST
    +     case TK_CAST: {
    +@@ -87695,42 +96290,37 @@ SQLITE_PRIVATE int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target)
    +                         sqlite3AffinityType(pExpr->u.zToken, 0));
    +       testcase( usedAsColumnCache(pParse, inReg, inReg) );
    +       sqlite3ExprCacheAffinityChange(pParse, inReg, 1);
    +-      break;
    ++      return inReg;
    +     }
    + #endif /* SQLITE_OMIT_CAST */
    ++    case TK_IS:
    ++    case TK_ISNOT:
    ++      op = (op==TK_IS) ? TK_EQ : TK_NE;
    ++      p5 = SQLITE_NULLEQ;
    ++      /* fall-through */
    +     case TK_LT:
    +     case TK_LE:
    +     case TK_GT:
    +     case TK_GE:
    +     case TK_NE:
    +     case TK_EQ: {
    +-      r1 = sqlite3ExprCodeTemp(pParse, pExpr->pLeft, &regFree1);
    +-      r2 = sqlite3ExprCodeTemp(pParse, pExpr->pRight, &regFree2);
    +-      codeCompare(pParse, pExpr->pLeft, pExpr->pRight, op,
    +-                  r1, r2, inReg, SQLITE_STOREP2);
    +-      assert(TK_LT==OP_Lt); testcase(op==OP_Lt); VdbeCoverageIf(v,op==OP_Lt);
    +-      assert(TK_LE==OP_Le); testcase(op==OP_Le); VdbeCoverageIf(v,op==OP_Le);
    +-      assert(TK_GT==OP_Gt); testcase(op==OP_Gt); VdbeCoverageIf(v,op==OP_Gt);
    +-      assert(TK_GE==OP_Ge); testcase(op==OP_Ge); VdbeCoverageIf(v,op==OP_Ge);
    +-      assert(TK_EQ==OP_Eq); testcase(op==OP_Eq); VdbeCoverageIf(v,op==OP_Eq);
    +-      assert(TK_NE==OP_Ne); testcase(op==OP_Ne); VdbeCoverageIf(v,op==OP_Ne);
    +-      testcase( regFree1==0 );
    +-      testcase( regFree2==0 );
    +-      break;
    +-    }
    +-    case TK_IS:
    +-    case TK_ISNOT: {
    +-      testcase( op==TK_IS );
    +-      testcase( op==TK_ISNOT );
    +-      r1 = sqlite3ExprCodeTemp(pParse, pExpr->pLeft, &regFree1);
    +-      r2 = sqlite3ExprCodeTemp(pParse, pExpr->pRight, &regFree2);
    +-      op = (op==TK_IS) ? TK_EQ : TK_NE;
    +-      codeCompare(pParse, pExpr->pLeft, pExpr->pRight, op,
    +-                  r1, r2, inReg, SQLITE_STOREP2 | SQLITE_NULLEQ);
    +-      VdbeCoverageIf(v, op==TK_EQ);
    +-      VdbeCoverageIf(v, op==TK_NE);
    +-      testcase( regFree1==0 );
    +-      testcase( regFree2==0 );
    ++      Expr *pLeft = pExpr->pLeft;
    ++      if( sqlite3ExprIsVector(pLeft) ){
    ++        codeVectorCompare(pParse, pExpr, target, op, p5);
    ++      }else{
    ++        r1 = sqlite3ExprCodeTemp(pParse, pLeft, &regFree1);
    ++        r2 = sqlite3ExprCodeTemp(pParse, pExpr->pRight, &regFree2);
    ++        codeCompare(pParse, pLeft, pExpr->pRight, op,
    ++            r1, r2, inReg, SQLITE_STOREP2 | p5);
    ++        assert(TK_LT==OP_Lt); testcase(op==OP_Lt); VdbeCoverageIf(v,op==OP_Lt);
    ++        assert(TK_LE==OP_Le); testcase(op==OP_Le); VdbeCoverageIf(v,op==OP_Le);
    ++        assert(TK_GT==OP_Gt); testcase(op==OP_Gt); VdbeCoverageIf(v,op==OP_Gt);
    ++        assert(TK_GE==OP_Ge); testcase(op==OP_Ge); VdbeCoverageIf(v,op==OP_Ge);
    ++        assert(TK_EQ==OP_Eq); testcase(op==OP_Eq); VdbeCoverageIf(v,op==OP_Eq);
    ++        assert(TK_NE==OP_Ne); testcase(op==OP_Ne); VdbeCoverageIf(v,op==OP_Ne);
    ++        testcase( regFree1==0 );
    ++        testcase( regFree2==0 );
    ++      }
    +       break;
    +     }
    +     case TK_AND:
    +@@ -87768,10 +96358,12 @@ SQLITE_PRIVATE int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target)
    +       assert( pLeft );
    +       if( pLeft->op==TK_INTEGER ){
    +         codeInteger(pParse, pLeft, 1, target);
    ++        return target;
    + #ifndef SQLITE_OMIT_FLOATING_POINT
    +       }else if( pLeft->op==TK_FLOAT ){
    +         assert( !ExprHasProperty(pExpr, EP_IntValue) );
    +         codeReal(v, pLeft->u.zToken, 1, target);
    ++        return target;
    + #endif
    +       }else{
    +         tempX.op = TK_INTEGER;
    +@@ -87782,7 +96374,6 @@ SQLITE_PRIVATE int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target)
    +         sqlite3VdbeAddOp3(v, OP_Subtract, r2, r1, target);
    +         testcase( regFree2==0 );
    +       }
    +-      inReg = target;
    +       break;
    +     }
    +     case TK_BITNOT:
    +@@ -87791,7 +96382,6 @@ SQLITE_PRIVATE int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target)
    +       assert( TK_NOT==OP_Not );         testcase( op==TK_NOT );
    +       r1 = sqlite3ExprCodeTemp(pParse, pExpr->pLeft, &regFree1);
    +       testcase( regFree1==0 );
    +-      inReg = target;
    +       sqlite3VdbeAddOp2(v, op, r1, inReg);
    +       break;
    +     }
    +@@ -87816,7 +96406,7 @@ SQLITE_PRIVATE int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target)
    +         assert( !ExprHasProperty(pExpr, EP_IntValue) );
    +         sqlite3ErrorMsg(pParse, "misuse of aggregate: %s()", pExpr->u.zToken);
    +       }else{
    +-        inReg = pInfo->aFunc[pExpr->iAgg].iMem;
    ++        return pInfo->aFunc[pExpr->iAgg].iMem;
    +       }
    +       break;
    +     }
    +@@ -87824,13 +96414,18 @@ SQLITE_PRIVATE int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target)
    +       ExprList *pFarg;       /* List of function arguments */
    +       int nFarg;             /* Number of function arguments */
    +       FuncDef *pDef;         /* The function definition object */
    +-      int nId;               /* Length of the function name in bytes */
    +       const char *zId;       /* The function name */
    +       u32 constMask = 0;     /* Mask of function arguments that are constant */
    +       int i;                 /* Loop counter */
    ++      sqlite3 *db = pParse->db;  /* The database connection */
    +       u8 enc = ENC(db);      /* The text encoding used by this database */
    +       CollSeq *pColl = 0;    /* A collating sequence */
    + 
    ++      if( ConstFactorOk(pParse) && sqlite3ExprIsConstantNotJoin(pExpr) ){
    ++        /* SQL functions can be expensive. So try to move constant functions
    ++        ** out of the inner loop, even if that means an extra OP_Copy. */
    ++        return sqlite3ExprCodeAtInit(pParse, pExpr, -1);
    ++      }
    +       assert( !ExprHasProperty(pExpr, EP_xIsSelect) );
    +       if( ExprHasProperty(pExpr, EP_TokenOnly) ){
    +         pFarg = 0;
    +@@ -87840,10 +96435,14 @@ SQLITE_PRIVATE int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target)
    +       nFarg = pFarg ? pFarg->nExpr : 0;
    +       assert( !ExprHasProperty(pExpr, EP_IntValue) );
    +       zId = pExpr->u.zToken;
    +-      nId = sqlite3Strlen30(zId);
    +-      pDef = sqlite3FindFunction(db, zId, nId, nFarg, enc, 0);
    +-      if( pDef==0 || pDef->xFunc==0 ){
    +-        sqlite3ErrorMsg(pParse, "unknown function: %.*s()", nId, zId);
    ++      pDef = sqlite3FindFunction(db, zId, nFarg, enc, 0);
    ++#ifdef SQLITE_ENABLE_UNKNOWN_SQL_FUNCTION
    ++      if( pDef==0 && pParse->explain ){
    ++        pDef = sqlite3FindFunction(db, "unknown", nFarg, enc, 0);
    ++      }
    ++#endif
    ++      if( pDef==0 || pDef->xFinalize!=0 ){
    ++        sqlite3ErrorMsg(pParse, "unknown function: %s()", zId);
    +         break;
    +       }
    + 
    +@@ -87872,9 +96471,24 @@ SQLITE_PRIVATE int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target)
    +       */
    +       if( pDef->funcFlags & SQLITE_FUNC_UNLIKELY ){
    +         assert( nFarg>=1 );
    +-        inReg = sqlite3ExprCodeTarget(pParse, pFarg->a[0].pExpr, target);
    +-        break;
    ++        return sqlite3ExprCodeTarget(pParse, pFarg->a[0].pExpr, target);
    ++      }
    ++
    ++#ifdef SQLITE_DEBUG
    ++      /* The AFFINITY() function evaluates to a string that describes
    ++      ** the type affinity of the argument.  This is used for testing of
    ++      ** the SQLite type logic.
    ++      */
    ++      if( pDef->funcFlags & SQLITE_FUNC_AFFINITY ){
    ++        const char *azAff[] = { "blob", "text", "numeric", "integer", "real" };
    ++        char aff;
    ++        assert( nFarg==1 );
    ++        aff = sqlite3ExprAffinity(pFarg->a[0].pExpr);
    ++        sqlite3VdbeLoadString(v, target, 
    ++                              aff ? azAff[aff-SQLITE_AFF_BLOB] : "none");
    ++        return target;
    +       }
    ++#endif
    + 
    +       for(i=0; i<nFarg; i++){
    +         if( i<32 && sqlite3ExprIsConstant(pFarg->a[i].pExpr) ){
    +@@ -87942,22 +96556,53 @@ SQLITE_PRIVATE int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target)
    +         if( !pColl ) pColl = db->pDfltColl; 
    +         sqlite3VdbeAddOp4(v, OP_CollSeq, 0, 0, 0, (char *)pColl, P4_COLLSEQ);
    +       }
    +-      sqlite3VdbeAddOp4(v, OP_Function0, constMask, r1, target,
    +-                        (char*)pDef, P4_FUNCDEF);
    +-      sqlite3VdbeChangeP5(v, (u8)nFarg);
    ++#ifdef SQLITE_ENABLE_OFFSET_SQL_FUNC
    ++      if( pDef->funcFlags & SQLITE_FUNC_OFFSET ){
    ++        Expr *pArg = pFarg->a[0].pExpr;
    ++        if( pArg->op==TK_COLUMN ){
    ++          sqlite3VdbeAddOp3(v, OP_Offset, pArg->iTable, pArg->iColumn, target);
    ++        }else{
    ++          sqlite3VdbeAddOp2(v, OP_Null, 0, target);
    ++        }
    ++      }else
    ++#endif
    ++      {
    ++        sqlite3VdbeAddOp4(v, pParse->iSelfTab ? OP_PureFunc0 : OP_Function0,
    ++                          constMask, r1, target, (char*)pDef, P4_FUNCDEF);
    ++        sqlite3VdbeChangeP5(v, (u8)nFarg);
    ++      }
    +       if( nFarg && constMask==0 ){
    +         sqlite3ReleaseTempRange(pParse, r1, nFarg);
    +       }
    +-      break;
    ++      return target;
    +     }
    + #ifndef SQLITE_OMIT_SUBQUERY
    +     case TK_EXISTS:
    +     case TK_SELECT: {
    ++      int nCol;
    +       testcase( op==TK_EXISTS );
    +       testcase( op==TK_SELECT );
    +-      inReg = sqlite3CodeSubselect(pParse, pExpr, 0, 0);
    ++      if( op==TK_SELECT && (nCol = pExpr->x.pSelect->pEList->nExpr)!=1 ){
    ++        sqlite3SubselectError(pParse, nCol, 1);
    ++      }else{
    ++        return sqlite3CodeSubselect(pParse, pExpr, 0, 0);
    ++      }
    +       break;
    +     }
    ++    case TK_SELECT_COLUMN: {
    ++      int n;
    ++      if( pExpr->pLeft->iTable==0 ){
    ++        pExpr->pLeft->iTable = sqlite3CodeSubselect(pParse, pExpr->pLeft, 0, 0);
    ++      }
    ++      assert( pExpr->iTable==0 || pExpr->pLeft->op==TK_SELECT );
    ++      if( pExpr->iTable
    ++       && pExpr->iTable!=(n = sqlite3ExprVectorSize(pExpr->pLeft)) 
    ++      ){
    ++        sqlite3ErrorMsg(pParse, "%d columns assigned %d values",
    ++                                pExpr->iTable, n);
    ++      }
    ++      return pExpr->pLeft->iTable + pExpr->iColumn;
    ++    }
    +     case TK_IN: {
    +       int destIfFalse = sqlite3VdbeMakeLabel(v);
    +       int destIfNull = sqlite3VdbeMakeLabel(v);
    +@@ -87967,7 +96612,7 @@ SQLITE_PRIVATE int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target)
    +       sqlite3VdbeResolveLabel(v, destIfFalse);
    +       sqlite3VdbeAddOp2(v, OP_AddImm, target, 0);
    +       sqlite3VdbeResolveLabel(v, destIfNull);
    +-      break;
    ++      return target;
    +     }
    + #endif /* SQLITE_OMIT_SUBQUERY */
    + 
    +@@ -87984,34 +96629,13 @@ SQLITE_PRIVATE int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target)
    +     ** Z is stored in pExpr->pList->a[1].pExpr.
    +     */
    +     case TK_BETWEEN: {
    +-      Expr *pLeft = pExpr->pLeft;
    +-      struct ExprList_item *pLItem = pExpr->x.pList->a;
    +-      Expr *pRight = pLItem->pExpr;
    +-
    +-      r1 = sqlite3ExprCodeTemp(pParse, pLeft, &regFree1);
    +-      r2 = sqlite3ExprCodeTemp(pParse, pRight, &regFree2);
    +-      testcase( regFree1==0 );
    +-      testcase( regFree2==0 );
    +-      r3 = sqlite3GetTempReg(pParse);
    +-      r4 = sqlite3GetTempReg(pParse);
    +-      codeCompare(pParse, pLeft, pRight, OP_Ge,
    +-                  r1, r2, r3, SQLITE_STOREP2);  VdbeCoverage(v);
    +-      pLItem++;
    +-      pRight = pLItem->pExpr;
    +-      sqlite3ReleaseTempReg(pParse, regFree2);
    +-      r2 = sqlite3ExprCodeTemp(pParse, pRight, &regFree2);
    +-      testcase( regFree2==0 );
    +-      codeCompare(pParse, pLeft, pRight, OP_Le, r1, r2, r4, SQLITE_STOREP2);
    +-      VdbeCoverage(v);
    +-      sqlite3VdbeAddOp3(v, OP_And, r3, r4, target);
    +-      sqlite3ReleaseTempReg(pParse, r3);
    +-      sqlite3ReleaseTempReg(pParse, r4);
    +-      break;
    ++      exprCodeBetween(pParse, pExpr, target, 0, 0);
    ++      return target;
    +     }
    ++    case TK_SPAN:
    +     case TK_COLLATE: 
    +     case TK_UPLUS: {
    +-      inReg = sqlite3ExprCodeTarget(pParse, pExpr->pLeft, target);
    +-      break;
    ++      return sqlite3ExprCodeTarget(pParse, pExpr->pLeft, target);
    +     }
    + 
    +     case TK_TRIGGER: {
    +@@ -88070,6 +96694,21 @@ SQLITE_PRIVATE int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target)
    +       break;
    +     }
    + 
    ++    case TK_VECTOR: {
    ++      sqlite3ErrorMsg(pParse, "row value misused");
    ++      break;
    ++    }
    ++
    ++    case TK_IF_NULL_ROW: {
    ++      int addrINR;
    ++      addrINR = sqlite3VdbeAddOp1(v, OP_IfNullRow, pExpr->iTable);
    ++      sqlite3ExprCachePush(pParse);
    ++      inReg = sqlite3ExprCodeTarget(pParse, pExpr->pLeft, target);
    ++      sqlite3ExprCachePop(pParse);
    ++      sqlite3VdbeJumpHere(v, addrINR);
    ++      sqlite3VdbeChangeP3(v, addrINR, inReg);
    ++      break;
    ++    }
    + 
    +     /*
    +     ** Form A:
    +@@ -88113,8 +96752,9 @@ SQLITE_PRIVATE int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target)
    +       if( (pX = pExpr->pLeft)!=0 ){
    +         tempX = *pX;
    +         testcase( pX->op==TK_COLUMN );
    +-        exprToRegister(&tempX, sqlite3ExprCodeTemp(pParse, pX, &regFree1));
    ++        exprToRegister(&tempX, exprCodeVector(pParse, &tempX, &regFree1));
    +         testcase( regFree1==0 );
    ++        memset(&opCompare, 0, sizeof(opCompare));
    +         opCompare.op = TK_EQ;
    +         opCompare.pLeft = &tempX;
    +         pTest = &opCompare;
    +@@ -88148,7 +96788,7 @@ SQLITE_PRIVATE int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target)
    +       }else{
    +         sqlite3VdbeAddOp2(v, OP_Null, 0, target);
    +       }
    +-      assert( db->mallocFailed || pParse->nErr>0 
    ++      assert( pParse->db->mallocFailed || pParse->nErr>0 
    +            || pParse->iCacheLevel==iCacheLevel );
    +       sqlite3VdbeResolveLabel(v, endLabel);
    +       break;
    +@@ -88189,24 +96829,40 @@ SQLITE_PRIVATE int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target)
    + 
    + /*
    + ** Factor out the code of the given expression to initialization time.
    ++**
    ++** If regDest>=0 then the result is always stored in that register and the
    ++** result is not reusable.  If regDest<0 then this routine is free to 
    ++** store the value whereever it wants.  The register where the expression 
    ++** is stored is returned.  When regDest<0, two identical expressions will
    ++** code to the same register.
    + */
    +-SQLITE_PRIVATE void sqlite3ExprCodeAtInit(
    ++SQLITE_PRIVATE int sqlite3ExprCodeAtInit(
    +   Parse *pParse,    /* Parsing context */
    +   Expr *pExpr,      /* The expression to code when the VDBE initializes */
    +-  int regDest,      /* Store the value in this register */
    +-  u8 reusable       /* True if this expression is reusable */
    ++  int regDest       /* Store the value in this register */
    + ){
    +   ExprList *p;
    +   assert( ConstFactorOk(pParse) );
    +   p = pParse->pConstExpr;
    ++  if( regDest<0 && p ){
    ++    struct ExprList_item *pItem;
    ++    int i;
    ++    for(pItem=p->a, i=p->nExpr; i>0; pItem++, i--){
    ++      if( pItem->reusable && sqlite3ExprCompare(0,pItem->pExpr,pExpr,-1)==0 ){
    ++        return pItem->u.iConstExprReg;
    ++      }
    ++    }
    ++  }
    +   pExpr = sqlite3ExprDup(pParse->db, pExpr, 0);
    +   p = sqlite3ExprListAppend(pParse, p, pExpr);
    +   if( p ){
    +      struct ExprList_item *pItem = &p->a[p->nExpr-1];
    ++     pItem->reusable = regDest<0;
    ++     if( regDest<0 ) regDest = ++pParse->nMem;
    +      pItem->u.iConstExprReg = regDest;
    +-     pItem->reusable = reusable;
    +   }
    +   pParse->pConstExpr = p;
    ++  return regDest;
    + }
    + 
    + /*
    +@@ -88229,19 +96885,8 @@ SQLITE_PRIVATE int sqlite3ExprCodeTemp(Parse *pParse, Expr *pExpr, int *pReg){
    +    && pExpr->op!=TK_REGISTER
    +    && sqlite3ExprIsConstantNotJoin(pExpr)
    +   ){
    +-    ExprList *p = pParse->pConstExpr;
    +-    int i;
    +     *pReg  = 0;
    +-    if( p ){
    +-      struct ExprList_item *pItem;
    +-      for(pItem=p->a, i=p->nExpr; i>0; pItem++, i--){
    +-        if( pItem->reusable && sqlite3ExprCompare(pItem->pExpr,pExpr,-1)==0 ){
    +-          return pItem->u.iConstExprReg;
    +-        }
    +-      }
    +-    }
    +-    r2 = ++pParse->nMem;
    +-    sqlite3ExprCodeAtInit(pParse, pExpr, r2, 1);
    ++    r2 = sqlite3ExprCodeAtInit(pParse, pExpr, -1);
    +   }else{
    +     int r1 = sqlite3GetTempReg(pParse);
    +     r2 = sqlite3ExprCodeTarget(pParse, pExpr, r1);
    +@@ -88268,13 +96913,25 @@ SQLITE_PRIVATE void sqlite3ExprCode(Parse *pParse, Expr *pExpr, int target){
    +     sqlite3VdbeAddOp2(pParse->pVdbe, OP_Copy, pExpr->iTable, target);
    +   }else{
    +     inReg = sqlite3ExprCodeTarget(pParse, pExpr, target);
    +-    assert( pParse->pVdbe || pParse->db->mallocFailed );
    ++    assert( pParse->pVdbe!=0 || pParse->db->mallocFailed );
    +     if( inReg!=target && pParse->pVdbe ){
    +       sqlite3VdbeAddOp2(pParse->pVdbe, OP_SCopy, inReg, target);
    +     }
    +   }
    + }
    + 
    ++/*
    ++** Make a transient copy of expression pExpr and then code it using
    ++** sqlite3ExprCode().  This routine works just like sqlite3ExprCode()
    ++** except that the input expression is guaranteed to be unchanged.
    ++*/
    ++SQLITE_PRIVATE void sqlite3ExprCodeCopy(Parse *pParse, Expr *pExpr, int target){
    ++  sqlite3 *db = pParse->db;
    ++  pExpr = sqlite3ExprDup(db, pExpr, 0);
    ++  if( !db->mallocFailed ) sqlite3ExprCode(pParse, pExpr, target);
    ++  sqlite3ExprDelete(db, pExpr);
    ++}
    ++
    + /*
    + ** Generate code that will evaluate expression pExpr and store the
    + ** results in register target.  The results are guaranteed to appear
    +@@ -88283,7 +96940,7 @@ SQLITE_PRIVATE void sqlite3ExprCode(Parse *pParse, Expr *pExpr, int target){
    + */
    + SQLITE_PRIVATE void sqlite3ExprCodeFactorable(Parse *pParse, Expr *pExpr, int target){
    +   if( pParse->okConstFactor && sqlite3ExprIsConstant(pExpr) ){
    +-    sqlite3ExprCodeAtInit(pParse, pExpr, target, 0);
    ++    sqlite3ExprCodeAtInit(pParse, pExpr, target);
    +   }else{
    +     sqlite3ExprCode(pParse, pExpr, target);
    +   }
    +@@ -88317,13 +96974,21 @@ SQLITE_PRIVATE void sqlite3ExprCodeAndCache(Parse *pParse, Expr *pExpr, int targ
    + ** Generate code that pushes the value of every element of the given
    + ** expression list into a sequence of registers beginning at target.
    + **
    +-** Return the number of elements evaluated.
    ++** Return the number of elements evaluated.  The number returned will
    ++** usually be pList->nExpr but might be reduced if SQLITE_ECEL_OMITREF
    ++** is defined.
    + **
    + ** The SQLITE_ECEL_DUP flag prevents the arguments from being
    + ** filled using OP_SCopy.  OP_Copy must be used instead.
    + **
    + ** The SQLITE_ECEL_FACTOR argument allows constant arguments to be
    + ** factored out into initialization code.
    ++**
    ++** The SQLITE_ECEL_REF flag means that expressions in the list with
    ++** ExprList.a[].u.x.iOrderByCol>0 have already been evaluated and stored
    ++** in registers at srcReg, and so the value can be copied from there.
    ++** If SQLITE_ECEL_OMITREF is also set, then the values with u.x.iOrderByCol>0
    ++** are simply omitted rather than being copied from srcReg.
    + */
    + SQLITE_PRIVATE int sqlite3ExprCodeExprList(
    +   Parse *pParse,     /* Parsing context */
    +@@ -88343,10 +97008,15 @@ SQLITE_PRIVATE int sqlite3ExprCodeExprList(
    +   if( !ConstFactorOk(pParse) ) flags &= ~SQLITE_ECEL_FACTOR;
    +   for(pItem=pList->a, i=0; i<n; i++, pItem++){
    +     Expr *pExpr = pItem->pExpr;
    +-    if( (flags & SQLITE_ECEL_REF)!=0 && (j = pList->a[i].u.x.iOrderByCol)>0 ){
    +-      sqlite3VdbeAddOp2(v, copyOp, j+srcReg-1, target+i);
    ++    if( (flags & SQLITE_ECEL_REF)!=0 && (j = pItem->u.x.iOrderByCol)>0 ){
    ++      if( flags & SQLITE_ECEL_OMITREF ){
    ++        i--;
    ++        n--;
    ++      }else{
    ++        sqlite3VdbeAddOp2(v, copyOp, j+srcReg-1, target+i);
    ++      }
    +     }else if( (flags & SQLITE_ECEL_FACTOR)!=0 && sqlite3ExprIsConstant(pExpr) ){
    +-      sqlite3ExprCodeAtInit(pParse, pExpr, target+i, 0);
    ++      sqlite3ExprCodeAtInit(pParse, pExpr, target+i);
    +     }else{
    +       int inReg = sqlite3ExprCodeTarget(pParse, pExpr, target+i);
    +       if( inReg!=target+i ){
    +@@ -88377,20 +97047,33 @@ SQLITE_PRIVATE int sqlite3ExprCodeExprList(
    + **
    + ** Code it as such, taking care to do the common subexpression
    + ** elimination of x.
    ++**
    ++** The xJumpIf parameter determines details:
    ++**
    ++**    NULL:                   Store the boolean result in reg[dest]
    ++**    sqlite3ExprIfTrue:      Jump to dest if true
    ++**    sqlite3ExprIfFalse:     Jump to dest if false
    ++**
    ++** The jumpIfNull parameter is ignored if xJumpIf is NULL.
    + */
    + static void exprCodeBetween(
    +   Parse *pParse,    /* Parsing and code generating context */
    +   Expr *pExpr,      /* The BETWEEN expression */
    +-  int dest,         /* Jump here if the jump is taken */
    +-  int jumpIfTrue,   /* Take the jump if the BETWEEN is true */
    ++  int dest,         /* Jump destination or storage location */
    ++  void (*xJump)(Parse*,Expr*,int,int), /* Action to take */
    +   int jumpIfNull    /* Take the jump if the BETWEEN is NULL */
    + ){
    +-  Expr exprAnd;     /* The AND operator in  x>=y AND x<=z  */
    ++ Expr exprAnd;     /* The AND operator in  x>=y AND x<=z  */
    +   Expr compLeft;    /* The  x>=y  term */
    +   Expr compRight;   /* The  x<=z  term */
    +   Expr exprX;       /* The  x  subexpression */
    +   int regFree1 = 0; /* Temporary use register */
    + 
    ++
    ++  memset(&compLeft, 0, sizeof(Expr));
    ++  memset(&compRight, 0, sizeof(Expr));
    ++  memset(&exprAnd, 0, sizeof(Expr));
    ++
    +   assert( !ExprHasProperty(pExpr, EP_xIsSelect) );
    +   exprX = *pExpr->pLeft;
    +   exprAnd.op = TK_AND;
    +@@ -88402,23 +97085,30 @@ static void exprCodeBetween(
    +   compRight.op = TK_LE;
    +   compRight.pLeft = &exprX;
    +   compRight.pRight = pExpr->x.pList->a[1].pExpr;
    +-  exprToRegister(&exprX, sqlite3ExprCodeTemp(pParse, &exprX, &regFree1));
    +-  if( jumpIfTrue ){
    +-    sqlite3ExprIfTrue(pParse, &exprAnd, dest, jumpIfNull);
    +-  }else{
    +-    sqlite3ExprIfFalse(pParse, &exprAnd, dest, jumpIfNull);
    ++  exprToRegister(&exprX, exprCodeVector(pParse, &exprX, &regFree1));
    ++  if( xJump ){
    ++    xJump(pParse, &exprAnd, dest, jumpIfNull);
    ++  }else{
    ++    /* Mark the expression is being from the ON or USING clause of a join
    ++    ** so that the sqlite3ExprCodeTarget() routine will not attempt to move
    ++    ** it into the Parse.pConstExpr list.  We should use a new bit for this,
    ++    ** for clarity, but we are out of bits in the Expr.flags field so we
    ++    ** have to reuse the EP_FromJoin bit.  Bummer. */
    ++    exprX.flags |= EP_FromJoin;
    ++    sqlite3ExprCodeTarget(pParse, &exprAnd, dest);
    +   }
    +   sqlite3ReleaseTempReg(pParse, regFree1);
    + 
    +   /* Ensure adequate test coverage */
    +-  testcase( jumpIfTrue==0 && jumpIfNull==0 && regFree1==0 );
    +-  testcase( jumpIfTrue==0 && jumpIfNull==0 && regFree1!=0 );
    +-  testcase( jumpIfTrue==0 && jumpIfNull!=0 && regFree1==0 );
    +-  testcase( jumpIfTrue==0 && jumpIfNull!=0 && regFree1!=0 );
    +-  testcase( jumpIfTrue!=0 && jumpIfNull==0 && regFree1==0 );
    +-  testcase( jumpIfTrue!=0 && jumpIfNull==0 && regFree1!=0 );
    +-  testcase( jumpIfTrue!=0 && jumpIfNull!=0 && regFree1==0 );
    +-  testcase( jumpIfTrue!=0 && jumpIfNull!=0 && regFree1!=0 );
    ++  testcase( xJump==sqlite3ExprIfTrue  && jumpIfNull==0 && regFree1==0 );
    ++  testcase( xJump==sqlite3ExprIfTrue  && jumpIfNull==0 && regFree1!=0 );
    ++  testcase( xJump==sqlite3ExprIfTrue  && jumpIfNull!=0 && regFree1==0 );
    ++  testcase( xJump==sqlite3ExprIfTrue  && jumpIfNull!=0 && regFree1!=0 );
    ++  testcase( xJump==sqlite3ExprIfFalse && jumpIfNull==0 && regFree1==0 );
    ++  testcase( xJump==sqlite3ExprIfFalse && jumpIfNull==0 && regFree1!=0 );
    ++  testcase( xJump==sqlite3ExprIfFalse && jumpIfNull!=0 && regFree1==0 );
    ++  testcase( xJump==sqlite3ExprIfFalse && jumpIfNull!=0 && regFree1!=0 );
    ++  testcase( xJump==0 );
    + }
    + 
    + /*
    +@@ -88470,12 +97160,20 @@ SQLITE_PRIVATE void sqlite3ExprIfTrue(Parse *pParse, Expr *pExpr, int dest, int
    +       sqlite3ExprIfFalse(pParse, pExpr->pLeft, dest, jumpIfNull);
    +       break;
    +     }
    ++    case TK_IS:
    ++    case TK_ISNOT:
    ++      testcase( op==TK_IS );
    ++      testcase( op==TK_ISNOT );
    ++      op = (op==TK_IS) ? TK_EQ : TK_NE;
    ++      jumpIfNull = SQLITE_NULLEQ;
    ++      /* Fall thru */
    +     case TK_LT:
    +     case TK_LE:
    +     case TK_GT:
    +     case TK_GE:
    +     case TK_NE:
    +     case TK_EQ: {
    ++      if( sqlite3ExprIsVector(pExpr->pLeft) ) goto default_expr;
    +       testcase( jumpIfNull==0 );
    +       r1 = sqlite3ExprCodeTemp(pParse, pExpr->pLeft, &regFree1);
    +       r2 = sqlite3ExprCodeTemp(pParse, pExpr->pRight, &regFree2);
    +@@ -88485,23 +97183,12 @@ SQLITE_PRIVATE void sqlite3ExprIfTrue(Parse *pParse, Expr *pExpr, int dest, int
    +       assert(TK_LE==OP_Le); testcase(op==OP_Le); VdbeCoverageIf(v,op==OP_Le);
    +       assert(TK_GT==OP_Gt); testcase(op==OP_Gt); VdbeCoverageIf(v,op==OP_Gt);
    +       assert(TK_GE==OP_Ge); testcase(op==OP_Ge); VdbeCoverageIf(v,op==OP_Ge);
    +-      assert(TK_EQ==OP_Eq); testcase(op==OP_Eq); VdbeCoverageIf(v,op==OP_Eq);
    +-      assert(TK_NE==OP_Ne); testcase(op==OP_Ne); VdbeCoverageIf(v,op==OP_Ne);
    +-      testcase( regFree1==0 );
    +-      testcase( regFree2==0 );
    +-      break;
    +-    }
    +-    case TK_IS:
    +-    case TK_ISNOT: {
    +-      testcase( op==TK_IS );
    +-      testcase( op==TK_ISNOT );
    +-      r1 = sqlite3ExprCodeTemp(pParse, pExpr->pLeft, &regFree1);
    +-      r2 = sqlite3ExprCodeTemp(pParse, pExpr->pRight, &regFree2);
    +-      op = (op==TK_IS) ? TK_EQ : TK_NE;
    +-      codeCompare(pParse, pExpr->pLeft, pExpr->pRight, op,
    +-                  r1, r2, dest, SQLITE_NULLEQ);
    +-      VdbeCoverageIf(v, op==TK_EQ);
    +-      VdbeCoverageIf(v, op==TK_NE);
    ++      assert(TK_EQ==OP_Eq); testcase(op==OP_Eq);
    ++      VdbeCoverageIf(v, op==OP_Eq && jumpIfNull==SQLITE_NULLEQ);
    ++      VdbeCoverageIf(v, op==OP_Eq && jumpIfNull!=SQLITE_NULLEQ);
    ++      assert(TK_NE==OP_Ne); testcase(op==OP_Ne);
    ++      VdbeCoverageIf(v, op==OP_Ne && jumpIfNull==SQLITE_NULLEQ);
    ++      VdbeCoverageIf(v, op==OP_Ne && jumpIfNull!=SQLITE_NULLEQ);
    +       testcase( regFree1==0 );
    +       testcase( regFree2==0 );
    +       break;
    +@@ -88519,7 +97206,7 @@ SQLITE_PRIVATE void sqlite3ExprIfTrue(Parse *pParse, Expr *pExpr, int dest, int
    +     }
    +     case TK_BETWEEN: {
    +       testcase( jumpIfNull==0 );
    +-      exprCodeBetween(pParse, pExpr, dest, 1, jumpIfNull);
    ++      exprCodeBetween(pParse, pExpr, dest, sqlite3ExprIfTrue, jumpIfNull);
    +       break;
    +     }
    + #ifndef SQLITE_OMIT_SUBQUERY
    +@@ -88533,6 +97220,7 @@ SQLITE_PRIVATE void sqlite3ExprIfTrue(Parse *pParse, Expr *pExpr, int dest, int
    +     }
    + #endif
    +     default: {
    ++    default_expr:
    +       if( exprAlwaysTrue(pExpr) ){
    +         sqlite3VdbeGoto(v, dest);
    +       }else if( exprAlwaysFalse(pExpr) ){
    +@@ -88626,12 +97314,20 @@ SQLITE_PRIVATE void sqlite3ExprIfFalse(Parse *pParse, Expr *pExpr, int dest, int
    +       sqlite3ExprIfTrue(pParse, pExpr->pLeft, dest, jumpIfNull);
    +       break;
    +     }
    ++    case TK_IS:
    ++    case TK_ISNOT:
    ++      testcase( pExpr->op==TK_IS );
    ++      testcase( pExpr->op==TK_ISNOT );
    ++      op = (pExpr->op==TK_IS) ? TK_NE : TK_EQ;
    ++      jumpIfNull = SQLITE_NULLEQ;
    ++      /* Fall thru */
    +     case TK_LT:
    +     case TK_LE:
    +     case TK_GT:
    +     case TK_GE:
    +     case TK_NE:
    +     case TK_EQ: {
    ++      if( sqlite3ExprIsVector(pExpr->pLeft) ) goto default_expr;
    +       testcase( jumpIfNull==0 );
    +       r1 = sqlite3ExprCodeTemp(pParse, pExpr->pLeft, &regFree1);
    +       r2 = sqlite3ExprCodeTemp(pParse, pExpr->pRight, &regFree2);
    +@@ -88641,23 +97337,12 @@ SQLITE_PRIVATE void sqlite3ExprIfFalse(Parse *pParse, Expr *pExpr, int dest, int
    +       assert(TK_LE==OP_Le); testcase(op==OP_Le); VdbeCoverageIf(v,op==OP_Le);
    +       assert(TK_GT==OP_Gt); testcase(op==OP_Gt); VdbeCoverageIf(v,op==OP_Gt);
    +       assert(TK_GE==OP_Ge); testcase(op==OP_Ge); VdbeCoverageIf(v,op==OP_Ge);
    +-      assert(TK_EQ==OP_Eq); testcase(op==OP_Eq); VdbeCoverageIf(v,op==OP_Eq);
    +-      assert(TK_NE==OP_Ne); testcase(op==OP_Ne); VdbeCoverageIf(v,op==OP_Ne);
    +-      testcase( regFree1==0 );
    +-      testcase( regFree2==0 );
    +-      break;
    +-    }
    +-    case TK_IS:
    +-    case TK_ISNOT: {
    +-      testcase( pExpr->op==TK_IS );
    +-      testcase( pExpr->op==TK_ISNOT );
    +-      r1 = sqlite3ExprCodeTemp(pParse, pExpr->pLeft, &regFree1);
    +-      r2 = sqlite3ExprCodeTemp(pParse, pExpr->pRight, &regFree2);
    +-      op = (pExpr->op==TK_IS) ? TK_NE : TK_EQ;
    +-      codeCompare(pParse, pExpr->pLeft, pExpr->pRight, op,
    +-                  r1, r2, dest, SQLITE_NULLEQ);
    +-      VdbeCoverageIf(v, op==TK_EQ);
    +-      VdbeCoverageIf(v, op==TK_NE);
    ++      assert(TK_EQ==OP_Eq); testcase(op==OP_Eq);
    ++      VdbeCoverageIf(v, op==OP_Eq && jumpIfNull!=SQLITE_NULLEQ);
    ++      VdbeCoverageIf(v, op==OP_Eq && jumpIfNull==SQLITE_NULLEQ);
    ++      assert(TK_NE==OP_Ne); testcase(op==OP_Ne);
    ++      VdbeCoverageIf(v, op==OP_Ne && jumpIfNull!=SQLITE_NULLEQ);
    ++      VdbeCoverageIf(v, op==OP_Ne && jumpIfNull==SQLITE_NULLEQ);
    +       testcase( regFree1==0 );
    +       testcase( regFree2==0 );
    +       break;
    +@@ -88673,7 +97358,7 @@ SQLITE_PRIVATE void sqlite3ExprIfFalse(Parse *pParse, Expr *pExpr, int dest, int
    +     }
    +     case TK_BETWEEN: {
    +       testcase( jumpIfNull==0 );
    +-      exprCodeBetween(pParse, pExpr, dest, 0, jumpIfNull);
    ++      exprCodeBetween(pParse, pExpr, dest, sqlite3ExprIfFalse, jumpIfNull);
    +       break;
    +     }
    + #ifndef SQLITE_OMIT_SUBQUERY
    +@@ -88689,6 +97374,7 @@ SQLITE_PRIVATE void sqlite3ExprIfFalse(Parse *pParse, Expr *pExpr, int dest, int
    +     }
    + #endif
    +     default: {
    ++    default_expr: 
    +       if( exprAlwaysFalse(pExpr) ){
    +         sqlite3VdbeGoto(v, dest);
    +       }else if( exprAlwaysTrue(pExpr) ){
    +@@ -88721,6 +97407,41 @@ SQLITE_PRIVATE void sqlite3ExprIfFalseDup(Parse *pParse, Expr *pExpr, int dest,i
    +   sqlite3ExprDelete(db, pCopy);
    + }
    + 
    ++/*
    ++** Expression pVar is guaranteed to be an SQL variable. pExpr may be any
    ++** type of expression.
    ++**
    ++** If pExpr is a simple SQL value - an integer, real, string, blob
    ++** or NULL value - then the VDBE currently being prepared is configured
    ++** to re-prepare each time a new value is bound to variable pVar.
    ++**
    ++** Additionally, if pExpr is a simple SQL value and the value is the
    ++** same as that currently bound to variable pVar, non-zero is returned.
    ++** Otherwise, if the values are not the same or if pExpr is not a simple
    ++** SQL value, zero is returned.
    ++*/
    ++static int exprCompareVariable(Parse *pParse, Expr *pVar, Expr *pExpr){
    ++  int res = 0;
    ++  int iVar;
    ++  sqlite3_value *pL, *pR = 0;
    ++  
    ++  sqlite3ValueFromExpr(pParse->db, pExpr, SQLITE_UTF8, SQLITE_AFF_BLOB, &pR);
    ++  if( pR ){
    ++    iVar = pVar->iColumn;
    ++    sqlite3VdbeSetVarmask(pParse->pVdbe, iVar);
    ++    pL = sqlite3VdbeGetBoundValue(pParse->pReprepare, iVar, SQLITE_AFF_BLOB);
    ++    if( pL ){
    ++      if( sqlite3_value_type(pL)==SQLITE_TEXT ){
    ++        sqlite3_value_text(pL); /* Make sure the encoding is UTF-8 */
    ++      }
    ++      res =  0==sqlite3MemCompare(pL, pR, 0);
    ++    }
    ++    sqlite3ValueFree(pR);
    ++    sqlite3ValueFree(pL);
    ++  }
    ++
    ++  return res;
    ++}
    + 
    + /*
    + ** Do a deep comparison of two expression trees.  Return 0 if the two
    +@@ -88743,12 +97464,22 @@ SQLITE_PRIVATE void sqlite3ExprIfFalseDup(Parse *pParse, Expr *pExpr, int dest,i
    + ** this routine is used, it does not hurt to get an extra 2 - that
    + ** just might result in some slightly slower code.  But returning
    + ** an incorrect 0 or 1 could lead to a malfunction.
    ++**
    ++** If pParse is not NULL then TK_VARIABLE terms in pA with bindings in
    ++** pParse->pReprepare can be matched against literals in pB.  The 
    ++** pParse->pVdbe->expmask bitmask is updated for each variable referenced.
    ++** If pParse is NULL (the normal case) then any TK_VARIABLE term in 
    ++** Argument pParse should normally be NULL. If it is not NULL and pA or
    ++** pB causes a return value of 2.
    + */
    +-SQLITE_PRIVATE int sqlite3ExprCompare(Expr *pA, Expr *pB, int iTab){
    ++SQLITE_PRIVATE int sqlite3ExprCompare(Parse *pParse, Expr *pA, Expr *pB, int iTab){
    +   u32 combinedFlags;
    +   if( pA==0 || pB==0 ){
    +     return pB==pA ? 0 : 2;
    +   }
    ++  if( pParse && pA->op==TK_VARIABLE && exprCompareVariable(pParse, pA, pB) ){
    ++    return 0;
    ++  }
    +   combinedFlags = pA->flags | pB->flags;
    +   if( combinedFlags & EP_IntValue ){
    +     if( (pA->flags&pB->flags&EP_IntValue)!=0 && pA->u.iValue==pB->u.iValue ){
    +@@ -88757,15 +97488,15 @@ SQLITE_PRIVATE int sqlite3ExprCompare(Expr *pA, Expr *pB, int iTab){
    +     return 2;
    +   }
    +   if( pA->op!=pB->op ){
    +-    if( pA->op==TK_COLLATE && sqlite3ExprCompare(pA->pLeft, pB, iTab)<2 ){
    ++    if( pA->op==TK_COLLATE && sqlite3ExprCompare(pParse, pA->pLeft,pB,iTab)<2 ){
    +       return 1;
    +     }
    +-    if( pB->op==TK_COLLATE && sqlite3ExprCompare(pA, pB->pLeft, iTab)<2 ){
    ++    if( pB->op==TK_COLLATE && sqlite3ExprCompare(pParse, pA,pB->pLeft,iTab)<2 ){
    +       return 1;
    +     }
    +     return 2;
    +   }
    +-  if( pA->op!=TK_COLUMN && ALWAYS(pA->op!=TK_AGG_COLUMN) && pA->u.zToken ){
    ++  if( pA->op!=TK_COLUMN && pA->op!=TK_AGG_COLUMN && pA->u.zToken ){
    +     if( pA->op==TK_FUNCTION ){
    +       if( sqlite3StrICmp(pA->u.zToken,pB->u.zToken)!=0 ) return 2;
    +     }else if( strcmp(pA->u.zToken,pB->u.zToken)!=0 ){
    +@@ -88775,8 +97506,8 @@ SQLITE_PRIVATE int sqlite3ExprCompare(Expr *pA, Expr *pB, int iTab){
    +   if( (pA->flags & EP_Distinct)!=(pB->flags & EP_Distinct) ) return 2;
    +   if( ALWAYS((combinedFlags & EP_TokenOnly)==0) ){
    +     if( combinedFlags & EP_xIsSelect ) return 2;
    +-    if( sqlite3ExprCompare(pA->pLeft, pB->pLeft, iTab) ) return 2;
    +-    if( sqlite3ExprCompare(pA->pRight, pB->pRight, iTab) ) return 2;
    ++    if( sqlite3ExprCompare(pParse, pA->pLeft, pB->pLeft, iTab) ) return 2;
    ++    if( sqlite3ExprCompare(pParse, pA->pRight, pB->pRight, iTab) ) return 2;
    +     if( sqlite3ExprListCompare(pA->x.pList, pB->x.pList, iTab) ) return 2;
    +     if( ALWAYS((combinedFlags & EP_Reduced)==0) && pA->op!=TK_STRING ){
    +       if( pA->iColumn!=pB->iColumn ) return 2;
    +@@ -88811,11 +97542,22 @@ SQLITE_PRIVATE int sqlite3ExprListCompare(ExprList *pA, ExprList *pB, int iTab){
    +     Expr *pExprA = pA->a[i].pExpr;
    +     Expr *pExprB = pB->a[i].pExpr;
    +     if( pA->a[i].sortOrder!=pB->a[i].sortOrder ) return 1;
    +-    if( sqlite3ExprCompare(pExprA, pExprB, iTab) ) return 1;
    ++    if( sqlite3ExprCompare(0, pExprA, pExprB, iTab) ) return 1;
    +   }
    +   return 0;
    + }
    + 
    ++/*
    ++** Like sqlite3ExprCompare() except COLLATE operators at the top-level
    ++** are ignored.
    ++*/
    ++SQLITE_PRIVATE int sqlite3ExprCompareSkip(Expr *pA, Expr *pB, int iTab){
    ++  return sqlite3ExprCompare(0,
    ++             sqlite3ExprSkipCollate(pA),
    ++             sqlite3ExprSkipCollate(pB),
    ++             iTab);
    ++}
    ++
    + /*
    + ** Return true if we can prove the pE2 will always be true if pE1 is
    + ** true.  Return false if we cannot complete the proof or if pE2 might
    +@@ -88832,29 +97574,88 @@ SQLITE_PRIVATE int sqlite3ExprListCompare(ExprList *pA, ExprList *pB, int iTab){
    + ** When comparing TK_COLUMN nodes between pE1 and pE2, if pE2 has
    + ** Expr.iTable<0 then assume a table number given by iTab.
    + **
    ++** If pParse is not NULL, then the values of bound variables in pE1 are 
    ++** compared against literal values in pE2 and pParse->pVdbe->expmask is
    ++** modified to record which bound variables are referenced.  If pParse 
    ++** is NULL, then false will be returned if pE1 contains any bound variables.
    ++**
    + ** When in doubt, return false.  Returning true might give a performance
    + ** improvement.  Returning false might cause a performance reduction, but
    + ** it will always give the correct answer and is hence always safe.
    + */
    +-SQLITE_PRIVATE int sqlite3ExprImpliesExpr(Expr *pE1, Expr *pE2, int iTab){
    +-  if( sqlite3ExprCompare(pE1, pE2, iTab)==0 ){
    ++SQLITE_PRIVATE int sqlite3ExprImpliesExpr(Parse *pParse, Expr *pE1, Expr *pE2, int iTab){
    ++  if( sqlite3ExprCompare(pParse, pE1, pE2, iTab)==0 ){
    +     return 1;
    +   }
    +   if( pE2->op==TK_OR
    +-   && (sqlite3ExprImpliesExpr(pE1, pE2->pLeft, iTab)
    +-             || sqlite3ExprImpliesExpr(pE1, pE2->pRight, iTab) )
    ++   && (sqlite3ExprImpliesExpr(pParse, pE1, pE2->pLeft, iTab)
    ++             || sqlite3ExprImpliesExpr(pParse, pE1, pE2->pRight, iTab) )
    +   ){
    +     return 1;
    +   }
    +-  if( pE2->op==TK_NOTNULL
    +-   && sqlite3ExprCompare(pE1->pLeft, pE2->pLeft, iTab)==0
    +-   && (pE1->op!=TK_ISNULL && pE1->op!=TK_IS)
    +-  ){
    +-    return 1;
    ++  if( pE2->op==TK_NOTNULL && pE1->op!=TK_ISNULL && pE1->op!=TK_IS ){
    ++    Expr *pX = sqlite3ExprSkipCollate(pE1->pLeft);
    ++    testcase( pX!=pE1->pLeft );
    ++    if( sqlite3ExprCompare(pParse, pX, pE2->pLeft, iTab)==0 ) return 1;
    +   }
    +   return 0;
    + }
    + 
    ++/*
    ++** An instance of the following structure is used by the tree walker
    ++** to determine if an expression can be evaluated by reference to the
    ++** index only, without having to do a search for the corresponding
    ++** table entry.  The IdxCover.pIdx field is the index.  IdxCover.iCur
    ++** is the cursor for the table.
    ++*/
    ++struct IdxCover {
    ++  Index *pIdx;     /* The index to be tested for coverage */
    ++  int iCur;        /* Cursor number for the table corresponding to the index */
    ++};
    ++
    ++/*
    ++** Check to see if there are references to columns in table 
    ++** pWalker->u.pIdxCover->iCur can be satisfied using the index
    ++** pWalker->u.pIdxCover->pIdx.
    ++*/
    ++static int exprIdxCover(Walker *pWalker, Expr *pExpr){
    ++  if( pExpr->op==TK_COLUMN
    ++   && pExpr->iTable==pWalker->u.pIdxCover->iCur
    ++   && sqlite3ColumnOfIndex(pWalker->u.pIdxCover->pIdx, pExpr->iColumn)<0
    ++  ){
    ++    pWalker->eCode = 1;
    ++    return WRC_Abort;
    ++  }
    ++  return WRC_Continue;
    ++}
    ++
    ++/*
    ++** Determine if an index pIdx on table with cursor iCur contains will
    ++** the expression pExpr.  Return true if the index does cover the
    ++** expression and false if the pExpr expression references table columns
    ++** that are not found in the index pIdx.
    ++**
    ++** An index covering an expression means that the expression can be
    ++** evaluated using only the index and without having to lookup the
    ++** corresponding table entry.
    ++*/
    ++SQLITE_PRIVATE int sqlite3ExprCoveredByIndex(
    ++  Expr *pExpr,        /* The index to be tested */
    ++  int iCur,           /* The cursor number for the corresponding table */
    ++  Index *pIdx         /* The index that might be used for coverage */
    ++){
    ++  Walker w;
    ++  struct IdxCover xcov;
    ++  memset(&w, 0, sizeof(w));
    ++  xcov.iCur = iCur;
    ++  xcov.pIdx = pIdx;
    ++  w.xExprCallback = exprIdxCover;
    ++  w.u.pIdxCover = &xcov;
    ++  sqlite3WalkExpr(&w, pExpr);
    ++  return !w.eCode;
    ++}
    ++
    ++
    + /*
    + ** An instance of the following structure is used by the tree walker
    + ** to count references to table columns in the arguments of an 
    +@@ -88903,8 +97704,8 @@ SQLITE_PRIVATE int sqlite3FunctionUsesThisSrc(Expr *pExpr, SrcList *pSrcList){
    +   Walker w;
    +   struct SrcCount cnt;
    +   assert( pExpr->op==TK_AGG_FUNCTION );
    +-  memset(&w, 0, sizeof(w));
    +   w.xExprCallback = exprSrcCount;
    ++  w.xSelectCallback = 0;
    +   w.u.pSrcCount = &cnt;
    +   cnt.pSrc = pSrcList;
    +   cnt.nThis = 0;
    +@@ -89036,7 +97837,7 @@ static int analyzeAggregate(Walker *pWalker, Expr *pExpr){
    +         */
    +         struct AggInfo_func *pItem = pAggInfo->aFunc;
    +         for(i=0; i<pAggInfo->nFunc; i++, pItem++){
    +-          if( sqlite3ExprCompare(pItem->pExpr, pExpr, -1)==0 ){
    ++          if( sqlite3ExprCompare(0, pItem->pExpr, pExpr, -1)==0 ){
    +             break;
    +           }
    +         }
    +@@ -89052,7 +97853,7 @@ static int analyzeAggregate(Walker *pWalker, Expr *pExpr){
    +             pItem->iMem = ++pParse->nMem;
    +             assert( !ExprHasProperty(pExpr, EP_IntValue) );
    +             pItem->pFunc = sqlite3FindFunction(pParse->db,
    +-                   pExpr->u.zToken, sqlite3Strlen30(pExpr->u.zToken),
    ++                   pExpr->u.zToken, 
    +                    pExpr->x.pList ? pExpr->x.pList->nExpr : 0, enc, 0);
    +             if( pExpr->flags & EP_Distinct ){
    +               pItem->iDistinct = pParse->nTab++;
    +@@ -89076,10 +97877,14 @@ static int analyzeAggregate(Walker *pWalker, Expr *pExpr){
    +   return WRC_Continue;
    + }
    + static int analyzeAggregatesInSelect(Walker *pWalker, Select *pSelect){
    +-  UNUSED_PARAMETER(pWalker);
    +   UNUSED_PARAMETER(pSelect);
    ++  pWalker->walkerDepth++;
    +   return WRC_Continue;
    + }
    ++static void analyzeAggregatesInSelectEnd(Walker *pWalker, Select *pSelect){
    ++  UNUSED_PARAMETER(pSelect);
    ++  pWalker->walkerDepth--;
    ++}
    + 
    + /*
    + ** Analyze the pExpr expression looking for aggregate functions and
    +@@ -89092,9 +97897,10 @@ static int analyzeAggregatesInSelect(Walker *pWalker, Select *pSelect){
    + */
    + SQLITE_PRIVATE void sqlite3ExprAnalyzeAggregates(NameContext *pNC, Expr *pExpr){
    +   Walker w;
    +-  memset(&w, 0, sizeof(w));
    +   w.xExprCallback = analyzeAggregate;
    +   w.xSelectCallback = analyzeAggregatesInSelect;
    ++  w.xSelectCallback2 = analyzeAggregatesInSelectEnd;
    ++  w.walkerDepth = 0;
    +   w.u.pNC = pNC;
    +   assert( pNC->pSrcList!=0 );
    +   sqlite3WalkExpr(&w, pExpr);
    +@@ -89138,7 +97944,7 @@ SQLITE_PRIVATE void sqlite3ReleaseTempReg(Parse *pParse, int iReg){
    +   if( iReg && pParse->nTempReg<ArraySize(pParse->aTempReg) ){
    +     int i;
    +     struct yColCache *p;
    +-    for(i=0, p=pParse->aColCache; i<SQLITE_N_COLCACHE; i++, p++){
    ++    for(i=0, p=pParse->aColCache; i<pParse->nColCache; i++, p++){
    +       if( p->iReg==iReg ){
    +         p->tempReg = 1;
    +         return;
    +@@ -89149,10 +97955,11 @@ SQLITE_PRIVATE void sqlite3ReleaseTempReg(Parse *pParse, int iReg){
    + }
    + 
    + /*
    +-** Allocate or deallocate a block of nReg consecutive registers
    ++** Allocate or deallocate a block of nReg consecutive registers.
    + */
    + SQLITE_PRIVATE int sqlite3GetTempRange(Parse *pParse, int nReg){
    +   int i, n;
    ++  if( nReg==1 ) return sqlite3GetTempReg(pParse);
    +   i = pParse->iRangeReg;
    +   n = pParse->nRangeReg;
    +   if( nReg<=n ){
    +@@ -89166,6 +97973,10 @@ SQLITE_PRIVATE int sqlite3GetTempRange(Parse *pParse, int nReg){
    +   return i;
    + }
    + SQLITE_PRIVATE void sqlite3ReleaseTempRange(Parse *pParse, int iReg, int nReg){
    ++  if( nReg==1 ){
    ++    sqlite3ReleaseTempReg(pParse, iReg);
    ++    return;
    ++  }
    +   sqlite3ExprCacheRemove(pParse, iReg, nReg);
    +   if( nReg>pParse->nRangeReg ){
    +     pParse->nRangeReg = nReg;
    +@@ -89181,6 +97992,29 @@ SQLITE_PRIVATE void sqlite3ClearTempRegCache(Parse *pParse){
    +   pParse->nRangeReg = 0;
    + }
    + 
    ++/*
    ++** Validate that no temporary register falls within the range of
    ++** iFirst..iLast, inclusive.  This routine is only call from within assert()
    ++** statements.
    ++*/
    ++#ifdef SQLITE_DEBUG
    ++SQLITE_PRIVATE int sqlite3NoTempsInRange(Parse *pParse, int iFirst, int iLast){
    ++  int i;
    ++  if( pParse->nRangeReg>0
    ++   && pParse->iRangeReg+pParse->nRangeReg > iFirst
    ++   && pParse->iRangeReg <= iLast
    ++  ){
    ++     return 0;
    ++  }
    ++  for(i=0; i<pParse->nTempReg; i++){
    ++    if( pParse->aTempReg[i]>=iFirst && pParse->aTempReg[i]<=iLast ){
    ++      return 0;
    ++    }
    ++  }
    ++  return 1;
    ++}
    ++#endif /* SQLITE_DEBUG */
    ++
    + /************** End of expr.c ************************************************/
    + /************** Begin file alter.c *******************************************/
    + /*
    +@@ -89414,7 +98248,7 @@ static void renameTriggerFunc(
    + ** Register built-in functions used to help implement ALTER TABLE
    + */
    + SQLITE_PRIVATE void sqlite3AlterFunctions(void){
    +-  static SQLITE_WSD FuncDef aAlterTableFuncs[] = {
    ++  static FuncDef aAlterTableFuncs[] = {
    +     FUNCTION(sqlite_rename_table,   2, 0, 0, renameTableFunc),
    + #ifndef SQLITE_OMIT_TRIGGER
    +     FUNCTION(sqlite_rename_trigger, 2, 0, 0, renameTriggerFunc),
    +@@ -89423,13 +98257,7 @@ SQLITE_PRIVATE void sqlite3AlterFunctions(void){
    +     FUNCTION(sqlite_rename_parent,  3, 0, 0, renameParentFunc),
    + #endif
    +   };
    +-  int i;
    +-  FuncDefHash *pHash = &GLOBAL(FuncDefHash, sqlite3GlobalFunctions);
    +-  FuncDef *aFunc = (FuncDef*)&GLOBAL(FuncDef, aAlterTableFuncs);
    +-
    +-  for(i=0; i<ArraySize(aAlterTableFuncs); i++){
    +-    sqlite3FuncDefInsert(pHash, &aFunc[i]);
    +-  }
    ++  sqlite3InsertBuiltinFuncs(aAlterTableFuncs, ArraySize(aAlterTableFuncs));
    + }
    + 
    + /*
    +@@ -89566,7 +98394,7 @@ static void reloadTableSchema(Parse *pParse, Table *pTab, const char *zName){
    + ** Or, if zName is not a system table, zero is returned.
    + */
    + static int isSystemTable(Parse *pParse, const char *zName){
    +-  if( sqlite3Strlen30(zName)>6 && 0==sqlite3StrNICmp(zName, "sqlite_", 7) ){
    ++  if( 0==sqlite3StrNICmp(zName, "sqlite_", 7) ){
    +     sqlite3ErrorMsg(pParse, "table %s may not be altered", zName);
    +     return 1;
    +   }
    +@@ -89594,9 +98422,9 @@ SQLITE_PRIVATE void sqlite3AlterRenameTable(
    +   char *zWhere = 0;         /* Where clause to locate temp triggers */
    + #endif
    +   VTable *pVTab = 0;        /* Non-zero if this is a v-tab with an xRename() */
    +-  int savedDbFlags;         /* Saved value of db->flags */
    ++  u32 savedDbFlags;         /* Saved value of db->mDbFlags */
    + 
    +-  savedDbFlags = db->flags;  
    ++  savedDbFlags = db->mDbFlags;  
    +   if( NEVER(db->mallocFailed) ) goto exit_rename_table;
    +   assert( pSrc->nSrc==1 );
    +   assert( sqlite3BtreeHoldsAllMutexes(pParse->db) );
    +@@ -89604,8 +98432,8 @@ SQLITE_PRIVATE void sqlite3AlterRenameTable(
    +   pTab = sqlite3LocateTableItem(pParse, 0, &pSrc->a[0]);
    +   if( !pTab ) goto exit_rename_table;
    +   iDb = sqlite3SchemaToIndex(pParse->db, pTab->pSchema);
    +-  zDb = db->aDb[iDb].zName;
    +-  db->flags |= SQLITE_PreferBuiltin;
    ++  zDb = db->aDb[iDb].zDbSName;
    ++  db->mDbFlags |= DBFLAG_PreferBuiltin;
    + 
    +   /* Get a NULL terminated version of the new table name. */
    +   zName = sqlite3NameFromToken(db, pName);
    +@@ -89695,7 +98523,7 @@ SQLITE_PRIVATE void sqlite3AlterRenameTable(
    +       sqlite3NestedParse(pParse, 
    +           "UPDATE \"%w\".%s SET "
    +               "sql = sqlite_rename_parent(sql, %Q, %Q) "
    +-              "WHERE %s;", zDb, SCHEMA_TABLE(iDb), zTabName, zName, zWhere);
    ++              "WHERE %s;", zDb, MASTER_NAME, zTabName, zName, zWhere);
    +       sqlite3DbFree(db, zWhere);
    +     }
    +   }
    +@@ -89719,7 +98547,7 @@ SQLITE_PRIVATE void sqlite3AlterRenameTable(
    +             "ELSE name END "
    +       "WHERE tbl_name=%Q COLLATE nocase AND "
    +           "(type='table' OR type='index' OR type='trigger');", 
    +-      zDb, SCHEMA_TABLE(iDb), zName, zName, zName, 
    ++      zDb, MASTER_NAME, zName, zName, zName, 
    + #ifndef SQLITE_OMIT_TRIGGER
    +       zName,
    + #endif
    +@@ -89770,34 +98598,7 @@ SQLITE_PRIVATE void sqlite3AlterRenameTable(
    + exit_rename_table:
    +   sqlite3SrcListDelete(db, pSrc);
    +   sqlite3DbFree(db, zName);
    +-  db->flags = savedDbFlags;
    +-}
    +-
    +-
    +-/*
    +-** Generate code to make sure the file format number is at least minFormat.
    +-** The generated code will increase the file format number if necessary.
    +-*/
    +-SQLITE_PRIVATE void sqlite3MinimumFileFormat(Parse *pParse, int iDb, int minFormat){
    +-  Vdbe *v;
    +-  v = sqlite3GetVdbe(pParse);
    +-  /* The VDBE should have been allocated before this routine is called.
    +-  ** If that allocation failed, we would have quit before reaching this
    +-  ** point */
    +-  if( ALWAYS(v) ){
    +-    int r1 = sqlite3GetTempReg(pParse);
    +-    int r2 = sqlite3GetTempReg(pParse);
    +-    int addr1;
    +-    sqlite3VdbeAddOp3(v, OP_ReadCookie, iDb, r1, BTREE_FILE_FORMAT);
    +-    sqlite3VdbeUsesBtree(v, iDb);
    +-    sqlite3VdbeAddOp2(v, OP_Integer, minFormat, r2);
    +-    addr1 = sqlite3VdbeAddOp3(v, OP_Ge, r2, 0, r1);
    +-    sqlite3VdbeChangeP5(v, SQLITE_NOTNULL); VdbeCoverage(v);
    +-    sqlite3VdbeAddOp3(v, OP_SetCookie, iDb, BTREE_FILE_FORMAT, r2);
    +-    sqlite3VdbeJumpHere(v, addr1);
    +-    sqlite3ReleaseTempReg(pParse, r1);
    +-    sqlite3ReleaseTempReg(pParse, r2);
    +-  }
    ++  db->mDbFlags = savedDbFlags;
    + }
    + 
    + /*
    +@@ -89818,15 +98619,18 @@ SQLITE_PRIVATE void sqlite3AlterFinishAddColumn(Parse *pParse, Token *pColDef){
    +   Column *pCol;             /* The new column */
    +   Expr *pDflt;              /* Default value for the new column */
    +   sqlite3 *db;              /* The database connection; */
    ++  Vdbe *v = pParse->pVdbe;  /* The prepared statement under construction */
    ++  int r1;                   /* Temporary registers */
    + 
    +   db = pParse->db;
    +   if( pParse->nErr || db->mallocFailed ) return;
    ++  assert( v!=0 );
    +   pNew = pParse->pNewTable;
    +   assert( pNew );
    + 
    +   assert( sqlite3BtreeHoldsAllMutexes(db) );
    +   iDb = sqlite3SchemaToIndex(db, pNew->pSchema);
    +-  zDb = db->aDb[iDb].zName;
    ++  zDb = db->aDb[iDb].zDbSName;
    +   zTab = &pNew->zName[16];  /* Skip the "sqlite_altertab_" prefix on the name */
    +   pCol = &pNew->aCol[pNew->nCol-1];
    +   pDflt = pCol->pDflt;
    +@@ -89844,7 +98648,8 @@ SQLITE_PRIVATE void sqlite3AlterFinishAddColumn(Parse *pParse, Token *pColDef){
    +   ** literal NULL, then set pDflt to 0. This simplifies checking
    +   ** for an SQL NULL default below.
    +   */
    +-  if( pDflt && pDflt->op==TK_NULL ){
    ++  assert( pDflt==0 || pDflt->op==TK_SPAN );
    ++  if( pDflt && pDflt->pLeft->op==TK_NULL ){
    +     pDflt = 0;
    +   }
    + 
    +@@ -89880,7 +98685,7 @@ SQLITE_PRIVATE void sqlite3AlterFinishAddColumn(Parse *pParse, Token *pColDef){
    +     rc = sqlite3ValueFromExpr(db, pDflt, SQLITE_UTF8, SQLITE_AFF_BLOB, &pVal);
    +     assert( rc==SQLITE_OK || rc==SQLITE_NOMEM );
    +     if( rc!=SQLITE_OK ){
    +-      db->mallocFailed = 1;
    ++      assert( db->mallocFailed == 1 );
    +       return;
    +     }
    +     if( !pVal ){
    +@@ -89894,27 +98699,34 @@ SQLITE_PRIVATE void sqlite3AlterFinishAddColumn(Parse *pParse, Token *pColDef){
    +   zCol = sqlite3DbStrNDup(db, (char*)pColDef->z, pColDef->n);
    +   if( zCol ){
    +     char *zEnd = &zCol[pColDef->n-1];
    +-    int savedDbFlags = db->flags;
    ++    u32 savedDbFlags = db->mDbFlags;
    +     while( zEnd>zCol && (*zEnd==';' || sqlite3Isspace(*zEnd)) ){
    +       *zEnd-- = '\0';
    +     }
    +-    db->flags |= SQLITE_PreferBuiltin;
    ++    db->mDbFlags |= DBFLAG_PreferBuiltin;
    +     sqlite3NestedParse(pParse, 
    +         "UPDATE \"%w\".%s SET "
    +           "sql = substr(sql,1,%d) || ', ' || %Q || substr(sql,%d) "
    +         "WHERE type = 'table' AND name = %Q", 
    +-      zDb, SCHEMA_TABLE(iDb), pNew->addColOffset, zCol, pNew->addColOffset+1,
    ++      zDb, MASTER_NAME, pNew->addColOffset, zCol, pNew->addColOffset+1,
    +       zTab
    +     );
    +     sqlite3DbFree(db, zCol);
    +-    db->flags = savedDbFlags;
    ++    db->mDbFlags = savedDbFlags;
    +   }
    + 
    +-  /* If the default value of the new column is NULL, then set the file
    +-  ** format to 2. If the default value of the new column is not NULL,
    +-  ** the file format becomes 3.
    ++  /* Make sure the schema version is at least 3.  But do not upgrade
    ++  ** from less than 3 to 4, as that will corrupt any preexisting DESC
    ++  ** index.
    +   */
    +-  sqlite3MinimumFileFormat(pParse, iDb, pDflt ? 3 : 2);
    ++  r1 = sqlite3GetTempReg(pParse);
    ++  sqlite3VdbeAddOp3(v, OP_ReadCookie, iDb, r1, BTREE_FILE_FORMAT);
    ++  sqlite3VdbeUsesBtree(v, iDb);
    ++  sqlite3VdbeAddOp2(v, OP_AddImm, r1, -2);
    ++  sqlite3VdbeAddOp2(v, OP_IfPos, r1, sqlite3VdbeCurrentAddr(v)+2);
    ++  VdbeCoverage(v);
    ++  sqlite3VdbeAddOp3(v, OP_SetCookie, iDb, BTREE_FILE_FORMAT, 3);
    ++  sqlite3ReleaseTempReg(pParse, r1);
    + 
    +   /* Reload the schema of the modified table. */
    +   reloadTableSchema(pParse, pTab, pTab->zName);
    +@@ -89980,7 +98792,7 @@ SQLITE_PRIVATE void sqlite3AlterBeginAddColumn(Parse *pParse, SrcList *pSrc){
    +   pNew = (Table*)sqlite3DbMallocZero(db, sizeof(Table));
    +   if( !pNew ) goto exit_begin_add_column;
    +   pParse->pNewTable = pNew;
    +-  pNew->nRef = 1;
    ++  pNew->nTabRef = 1;
    +   pNew->nCol = pTab->nCol;
    +   assert( pNew->nCol>0 );
    +   nAlloc = (((pNew->nCol-1)/8)*8)+8;
    +@@ -89988,7 +98800,7 @@ SQLITE_PRIVATE void sqlite3AlterBeginAddColumn(Parse *pParse, SrcList *pSrc){
    +   pNew->aCol = (Column*)sqlite3DbMallocZero(db, sizeof(Column)*nAlloc);
    +   pNew->zName = sqlite3MPrintf(db, "sqlite_altertab_%s", pTab->zName);
    +   if( !pNew->aCol || !pNew->zName ){
    +-    db->mallocFailed = 1;
    ++    assert( db->mallocFailed );
    +     goto exit_begin_add_column;
    +   }
    +   memcpy(pNew->aCol, pTab->aCol, sizeof(Column)*pNew->nCol);
    +@@ -89996,13 +98808,11 @@ SQLITE_PRIVATE void sqlite3AlterBeginAddColumn(Parse *pParse, SrcList *pSrc){
    +     Column *pCol = &pNew->aCol[i];
    +     pCol->zName = sqlite3DbStrDup(db, pCol->zName);
    +     pCol->zColl = 0;
    +-    pCol->zType = 0;
    +     pCol->pDflt = 0;
    +-    pCol->zDflt = 0;
    +   }
    +   pNew->pSchema = db->aDb[iDb].pSchema;
    +   pNew->addColOffset = pTab->addColOffset;
    +-  pNew->nRef = 1;
    ++  pNew->nTabRef = 1;
    + 
    +   /* Begin a transaction and increment the schema cookie.  */
    +   sqlite3BeginWriteOperation(pParse, 0, iDb);
    +@@ -90230,14 +99040,14 @@ static void openStatTable(
    +   for(i=0; i<ArraySize(aTable); i++){
    +     const char *zTab = aTable[i].zName;
    +     Table *pStat;
    +-    if( (pStat = sqlite3FindTable(db, zTab, pDb->zName))==0 ){
    ++    if( (pStat = sqlite3FindTable(db, zTab, pDb->zDbSName))==0 ){
    +       if( aTable[i].zCols ){
    +         /* The sqlite_statN table does not exist. Create it. Note that a 
    +         ** side-effect of the CREATE TABLE statement is to leave the rootpage 
    +         ** of the new table in register pParse->regRoot. This is important 
    +         ** because the OpenWrite opcode below will be needing it. */
    +         sqlite3NestedParse(pParse,
    +-            "CREATE TABLE %Q.%s(%s)", pDb->zName, zTab, aTable[i].zCols
    ++            "CREATE TABLE %Q.%s(%s)", pDb->zDbSName, zTab, aTable[i].zCols
    +         );
    +         aRoot[i] = pParse->regRoot;
    +         aCreateTbl[i] = OPFLAG_P2ISREG;
    +@@ -90252,8 +99062,12 @@ static void openStatTable(
    +       if( zWhere ){
    +         sqlite3NestedParse(pParse,
    +            "DELETE FROM %Q.%s WHERE %s=%Q",
    +-           pDb->zName, zTab, zWhereType, zWhere
    ++           pDb->zDbSName, zTab, zWhereType, zWhere
    +         );
    ++#ifdef SQLITE_ENABLE_PREUPDATE_HOOK
    ++      }else if( db->xPreUpdateCallback ){
    ++        sqlite3NestedParse(pParse, "DELETE FROM %Q.%s", pDb->zDbSName, zTab);
    ++#endif
    +       }else{
    +         /* The sqlite_stat[134] table already exists.  Delete all rows. */
    +         sqlite3VdbeAddOp2(v, OP_Clear, aRoot[i], iDb);
    +@@ -90310,6 +99124,7 @@ struct Stat4Accum {
    +   Stat4Sample *aBest;       /* Array of nCol best samples */
    +   int iMin;                 /* Index in a[] of entry with minimum score */
    +   int nSample;              /* Current number of samples */
    ++  int nMaxEqZero;           /* Max leading 0 in anEq[] for any a[] entry */
    +   int iGet;                 /* Index of current sample accessed by stat_get() */
    +   Stat4Sample *a;           /* Array of mxSample Stat4Sample objects */
    +   sqlite3 *db;              /* Database connection, for malloc() */
    +@@ -90333,7 +99148,7 @@ static void sampleClear(sqlite3 *db, Stat4Sample *p){
    + static void sampleSetRowid(sqlite3 *db, Stat4Sample *p, int n, const u8 *pData){
    +   assert( db!=0 );
    +   if( p->nRowid ) sqlite3DbFree(db, p->u.aRowid);
    +-  p->u.aRowid = sqlite3DbMallocRaw(db, n);
    ++  p->u.aRowid = sqlite3DbMallocRawNN(db, n);
    +   if( p->u.aRowid ){
    +     p->nRowid = n;
    +     memcpy(p->u.aRowid, pData, n);
    +@@ -90498,12 +99313,10 @@ static const FuncDef statInitFuncdef = {
    +   SQLITE_UTF8,     /* funcFlags */
    +   0,               /* pUserData */
    +   0,               /* pNext */
    +-  statInit,        /* xFunc */
    +-  0,               /* xStep */
    ++  statInit,        /* xSFunc */
    +   0,               /* xFinalize */
    +   "stat_init",     /* zName */
    +-  0,               /* pHash */
    +-  0                /* pDestructor */
    ++  {0}
    + };
    + 
    + #ifdef SQLITE_ENABLE_STAT4
    +@@ -90576,6 +99389,13 @@ static void sampleInsert(Stat4Accum *p, Stat4Sample *pNew, int nEqZero){
    +   assert( IsStat4 || nEqZero==0 );
    + 
    + #ifdef SQLITE_ENABLE_STAT4
    ++  /* Stat4Accum.nMaxEqZero is set to the maximum number of leading 0
    ++  ** values in the anEq[] array of any sample in Stat4Accum.a[]. In
    ++  ** other words, if nMaxEqZero is n, then it is guaranteed that there
    ++  ** are no samples with Stat4Sample.anEq[m]==0 for (m>=n). */
    ++  if( nEqZero>p->nMaxEqZero ){
    ++    p->nMaxEqZero = nEqZero;
    ++  }
    +   if( pNew->isPSample==0 ){
    +     Stat4Sample *pUpgrade = 0;
    +     assert( pNew->anEq[pNew->iCol]>0 );
    +@@ -90673,12 +99493,22 @@ static void samplePushPrevious(Stat4Accum *p, int iChng){
    +     }
    +   }
    + 
    +-  /* Update the anEq[] fields of any samples already collected. */
    ++  /* Check that no sample contains an anEq[] entry with an index of
    ++  ** p->nMaxEqZero or greater set to zero. */
    +   for(i=p->nSample-1; i>=0; i--){
    +     int j;
    +-    for(j=iChng; j<p->nCol; j++){
    +-      if( p->a[i].anEq[j]==0 ) p->a[i].anEq[j] = p->current.anEq[j];
    ++    for(j=p->nMaxEqZero; j<p->nCol; j++) assert( p->a[i].anEq[j]>0 );
    ++  }
    ++
    ++  /* Update the anEq[] fields of any samples already collected. */
    ++  if( iChng<p->nMaxEqZero ){
    ++    for(i=p->nSample-1; i>=0; i--){
    ++      int j;
    ++      for(j=iChng; j<p->nCol; j++){
    ++        if( p->a[i].anEq[j]==0 ) p->a[i].anEq[j] = p->current.anEq[j];
    ++      }
    +     }
    ++    p->nMaxEqZero = iChng;
    +   }
    + #endif
    + 
    +@@ -90799,12 +99629,10 @@ static const FuncDef statPushFuncdef = {
    +   SQLITE_UTF8,     /* funcFlags */
    +   0,               /* pUserData */
    +   0,               /* pNext */
    +-  statPush,        /* xFunc */
    +-  0,               /* xStep */
    ++  statPush,        /* xSFunc */
    +   0,               /* xFinalize */
    +   "stat_push",     /* zName */
    +-  0,               /* pHash */
    +-  0                /* pDestructor */
    ++  {0}
    + };
    + 
    + #define STAT_GET_STAT1 0          /* "stat" column of stat1 table */
    +@@ -90821,6 +99649,12 @@ static const FuncDef statPushFuncdef = {
    + ** The content to returned is determined by the parameter J
    + ** which is one of the STAT_GET_xxxx values defined above.
    + **
    ++** The stat_get(P,J) function is not available to generic SQL.  It is
    ++** inserted as part of a manually constructed bytecode program.  (See
    ++** the callStatGet() routine below.)  It is guaranteed that the P
    ++** parameter will always be a poiner to a Stat4Accum object, never a
    ++** NULL.
    ++**
    + ** If neither STAT3 nor STAT4 are enabled, then J is always
    + ** STAT_GET_STAT1 and is hence omitted and this routine becomes
    + ** a one-parameter function, stat_get(P), that always returns the
    +@@ -90946,12 +99780,10 @@ static const FuncDef statGetFuncdef = {
    +   SQLITE_UTF8,     /* funcFlags */
    +   0,               /* pUserData */
    +   0,               /* pNext */
    +-  statGet,         /* xFunc */
    +-  0,               /* xStep */
    ++  statGet,         /* xSFunc */
    +   0,               /* xFinalize */
    +   "stat_get",      /* zName */
    +-  0,               /* pHash */
    +-  0                /* pDestructor */
    ++  {0}
    + };
    + 
    + static void callStatGet(Vdbe *v, int regStat4, int iParam, int regOut){
    +@@ -90963,8 +99795,8 @@ static void callStatGet(Vdbe *v, int regStat4, int iParam, int regOut){
    + #else
    +   UNUSED_PARAMETER( iParam );
    + #endif
    +-  sqlite3VdbeAddOp3(v, OP_Function0, 0, regStat4, regOut);
    +-  sqlite3VdbeChangeP4(v, -1, (char*)&statGetFuncdef, P4_FUNCDEF);
    ++  sqlite3VdbeAddOp4(v, OP_Function0, 0, regStat4, regOut,
    ++                    (char*)&statGetFuncdef, P4_FUNCDEF);
    +   sqlite3VdbeChangeP5(v, 1 + IsStat34);
    + }
    + 
    +@@ -91000,6 +99832,9 @@ static void analyzeOneTable(
    +   int regIdxname = iMem++;     /* Register containing index name */
    +   int regStat1 = iMem++;       /* Value for the stat column of sqlite_stat1 */
    +   int regPrev = iMem;          /* MUST BE LAST (see below) */
    ++#ifdef SQLITE_ENABLE_PREUPDATE_HOOK
    ++  Table *pStat1 = 0; 
    ++#endif
    + 
    +   pParse->nMem = MAX(pParse->nMem, iMem);
    +   v = sqlite3GetVdbe(pParse);
    +@@ -91010,7 +99845,7 @@ static void analyzeOneTable(
    +     /* Do not gather statistics on views or virtual tables */
    +     return;
    +   }
    +-  if( sqlite3_strnicmp(pTab->zName, "sqlite_", 7)==0 ){
    ++  if( sqlite3_strlike("sqlite_%", pTab->zName, 0)==0 ){
    +     /* Do not gather statistics on system tables */
    +     return;
    +   }
    +@@ -91020,11 +99855,23 @@ static void analyzeOneTable(
    +   assert( sqlite3SchemaMutexHeld(db, iDb, 0) );
    + #ifndef SQLITE_OMIT_AUTHORIZATION
    +   if( sqlite3AuthCheck(pParse, SQLITE_ANALYZE, pTab->zName, 0,
    +-      db->aDb[iDb].zName ) ){
    ++      db->aDb[iDb].zDbSName ) ){
    +     return;
    +   }
    + #endif
    + 
    ++#ifdef SQLITE_ENABLE_PREUPDATE_HOOK
    ++  if( db->xPreUpdateCallback ){
    ++    pStat1 = (Table*)sqlite3DbMallocZero(db, sizeof(Table) + 13);
    ++    if( pStat1==0 ) return;
    ++    pStat1->zName = (char*)&pStat1[1];
    ++    memcpy(pStat1->zName, "sqlite_stat1", 13);
    ++    pStat1->nCol = 3;
    ++    pStat1->iPKey = -1;
    ++    sqlite3VdbeAddOp4(pParse->pVdbe, OP_Noop, 0, 0, 0,(char*)pStat1,P4_DYNBLOB);
    ++  }
    ++#endif
    ++
    +   /* Establish a read-lock on the table at the shared-cache level. 
    +   ** Open a read-only cursor on the table. Also allocate a cursor number
    +   ** to use for scanning indexes (iIdxCur). No index cursor is opened at
    +@@ -91118,8 +99965,8 @@ static void analyzeOneTable(
    + #endif
    +     sqlite3VdbeAddOp2(v, OP_Integer, nCol, regStat4+1);
    +     sqlite3VdbeAddOp2(v, OP_Integer, pIdx->nKeyCol, regStat4+2);
    +-    sqlite3VdbeAddOp3(v, OP_Function0, 0, regStat4+1, regStat4);
    +-    sqlite3VdbeChangeP4(v, -1, (char*)&statInitFuncdef, P4_FUNCDEF);
    ++    sqlite3VdbeAddOp4(v, OP_Function0, 0, regStat4+1, regStat4,
    ++                     (char*)&statInitFuncdef, P4_FUNCDEF);
    +     sqlite3VdbeChangeP5(v, 2+IsStat34);
    + 
    +     /* Implementation of the following:
    +@@ -91138,7 +99985,7 @@ static void analyzeOneTable(
    +     if( nColTest>0 ){
    +       int endDistinctTest = sqlite3VdbeMakeLabel(v);
    +       int *aGotoChng;               /* Array of jump instruction addresses */
    +-      aGotoChng = sqlite3DbMallocRaw(db, sizeof(int)*nColTest);
    ++      aGotoChng = sqlite3DbMallocRawNN(db, sizeof(int)*nColTest);
    +       if( aGotoChng==0 ) continue;
    + 
    +       /*
    +@@ -91206,7 +100053,7 @@ static void analyzeOneTable(
    +       regKey = sqlite3GetTempRange(pParse, pPk->nKeyCol);
    +       for(j=0; j<pPk->nKeyCol; j++){
    +         k = sqlite3ColumnOfIndex(pIdx, pPk->aiColumn[j]);
    +-        assert( k>=0 && k<pTab->nCol );
    ++        assert( k>=0 && k<pIdx->nColumn );
    +         sqlite3VdbeAddOp3(v, OP_Column, iIdxCur, k, regKey+j);
    +         VdbeComment((v, "%s", pTab->aCol[pPk->aiColumn[j]].zName));
    +       }
    +@@ -91215,8 +100062,8 @@ static void analyzeOneTable(
    +     }
    + #endif
    +     assert( regChng==(regStat4+1) );
    +-    sqlite3VdbeAddOp3(v, OP_Function0, 1, regStat4, regTemp);
    +-    sqlite3VdbeChangeP4(v, -1, (char*)&statPushFuncdef, P4_FUNCDEF);
    ++    sqlite3VdbeAddOp4(v, OP_Function0, 1, regStat4, regTemp,
    ++                     (char*)&statPushFuncdef, P4_FUNCDEF);
    +     sqlite3VdbeChangeP5(v, 2+IsStat34);
    +     sqlite3VdbeAddOp2(v, OP_Next, iIdxCur, addrNextRow); VdbeCoverage(v);
    + 
    +@@ -91226,6 +100073,9 @@ static void analyzeOneTable(
    +     sqlite3VdbeAddOp4(v, OP_MakeRecord, regTabname, 3, regTemp, "BBB", 0);
    +     sqlite3VdbeAddOp2(v, OP_NewRowid, iStatCur, regNewRowid);
    +     sqlite3VdbeAddOp3(v, OP_Insert, iStatCur, regTemp, regNewRowid);
    ++#ifdef SQLITE_ENABLE_PREUPDATE_HOOK
    ++    sqlite3VdbeChangeP4(v, -1, (char*)pStat1, P4_TABLE);
    ++#endif
    +     sqlite3VdbeChangeP5(v, OPFLAG_APPEND);
    + 
    +     /* Add the entries to the stat3 or stat4 table. */
    +@@ -91289,6 +100139,9 @@ static void analyzeOneTable(
    +     sqlite3VdbeAddOp2(v, OP_NewRowid, iStatCur, regNewRowid);
    +     sqlite3VdbeAddOp3(v, OP_Insert, iStatCur, regTemp, regNewRowid);
    +     sqlite3VdbeChangeP5(v, OPFLAG_APPEND);
    ++#ifdef SQLITE_ENABLE_PREUPDATE_HOOK
    ++    sqlite3VdbeChangeP4(v, -1, (char*)pStat1, P4_TABLE);
    ++#endif
    +     sqlite3VdbeJumpHere(v, jZeroRows);
    +   }
    + }
    +@@ -91390,27 +100243,14 @@ SQLITE_PRIVATE void sqlite3Analyze(Parse *pParse, Token *pName1, Token *pName2){
    +       if( i==1 ) continue;  /* Do not analyze the TEMP database */
    +       analyzeDatabase(pParse, i);
    +     }
    +-  }else if( pName2->n==0 ){
    +-    /* Form 2:  Analyze the database or table named */
    +-    iDb = sqlite3FindDb(db, pName1);
    +-    if( iDb>=0 ){
    +-      analyzeDatabase(pParse, iDb);
    +-    }else{
    +-      z = sqlite3NameFromToken(db, pName1);
    +-      if( z ){
    +-        if( (pIdx = sqlite3FindIndex(db, z, 0))!=0 ){
    +-          analyzeTable(pParse, pIdx->pTable, pIdx);
    +-        }else if( (pTab = sqlite3LocateTable(pParse, 0, z, 0))!=0 ){
    +-          analyzeTable(pParse, pTab, 0);
    +-        }
    +-        sqlite3DbFree(db, z);
    +-      }
    +-    }
    ++  }else if( pName2->n==0 && (iDb = sqlite3FindDb(db, pName1))>=0 ){
    ++    /* Analyze the schema named as the argument */
    ++    analyzeDatabase(pParse, iDb);
    +   }else{
    +-    /* Form 3: Analyze the fully qualified table name */
    ++    /* Form 3: Analyze the table or index named as an argument */
    +     iDb = sqlite3TwoPartName(pParse, pName1, pName2, &pTableName);
    +     if( iDb>=0 ){
    +-      zDb = db->aDb[iDb].zName;
    ++      zDb = pName2->n ? db->aDb[iDb].zDbSName : 0;
    +       z = sqlite3NameFromToken(db, pTableName);
    +       if( z ){
    +         if( (pIdx = sqlite3FindIndex(db, z, zDb))!=0 ){
    +@@ -91420,10 +100260,11 @@ SQLITE_PRIVATE void sqlite3Analyze(Parse *pParse, Token *pName1, Token *pName2){
    +         }
    +         sqlite3DbFree(db, z);
    +       }
    +-    }   
    ++    }
    ++  }
    ++  if( db->nSqlExec==0 && (v = sqlite3GetVdbe(pParse))!=0 ){
    ++    sqlite3VdbeAddOp0(v, OP_Expire);
    +   }
    +-  v = sqlite3GetVdbe(pParse);
    +-  if( v ) sqlite3VdbeAddOp0(v, OP_Expire);
    + }
    + 
    + /*
    +@@ -91546,13 +100387,17 @@ static int analysisLoader(void *pData, int argc, char **argv, char **NotUsed){
    +     ** the old data with the new instead of allocating a new array.  */
    +     if( pIndex->aiRowEst==0 ){
    +       pIndex->aiRowEst = (tRowcnt*)sqlite3MallocZero(sizeof(tRowcnt) * nCol);
    +-      if( pIndex->aiRowEst==0 ) pInfo->db->mallocFailed = 1;
    ++      if( pIndex->aiRowEst==0 ) sqlite3OomFault(pInfo->db);
    +     }
    +     aiRowEst = pIndex->aiRowEst;
    + #endif
    +     pIndex->bUnordered = 0;
    +     decodeIntArray((char*)z, nCol, aiRowEst, pIndex->aiRowLogEst, pIndex);
    +-    if( pIndex->pPartIdxWhere==0 ) pTable->nRowLogEst = pIndex->aiRowLogEst[0];
    ++    pIndex->hasStat1 = 1;
    ++    if( pIndex->pPartIdxWhere==0 ){
    ++      pTable->nRowLogEst = pIndex->aiRowLogEst[0];
    ++      pTable->tabFlags |= TF_HasStat1;
    ++    }
    +   }else{
    +     Index fakeIdx;
    +     fakeIdx.szIdxRow = pTable->szTabRow;
    +@@ -91561,6 +100406,7 @@ static int analysisLoader(void *pData, int argc, char **argv, char **NotUsed){
    + #endif
    +     decodeIntArray((char*)z, 1, 0, &pTable->nRowLogEst, &fakeIdx);
    +     pTable->szTabRow = fakeIdx.szIdxRow;
    ++    pTable->tabFlags |= TF_HasStat1;
    +   }
    + 
    +   return 0;
    +@@ -91641,7 +100487,7 @@ static void initAvgEq(Index *pIdx){
    +         }
    +       }
    + 
    +-      if( nDist100>nSum100 ){
    ++      if( nDist100>nSum100 && sumEq<nRow ){
    +         avgEq = ((i64)100 * (nRow - sumEq))/(nDist100 - nSum100);
    +       }
    +       if( avgEq==0 ) avgEq = 1;
    +@@ -91693,10 +100539,10 @@ static int loadStatTbl(
    +   Index *pPrevIdx = 0;          /* Previous index in the loop */
    +   IndexSample *pSample;         /* A slot in pIdx->aSample[] */
    + 
    +-  assert( db->lookaside.bEnabled==0 );
    ++  assert( db->lookaside.bDisable );
    +   zSql = sqlite3MPrintf(db, zSql1, zDb);
    +   if( !zSql ){
    +-    return SQLITE_NOMEM;
    ++    return SQLITE_NOMEM_BKPT;
    +   }
    +   rc = sqlite3_prepare(db, zSql, -1, &pStmt, 0);
    +   sqlite3DbFree(db, zSql);
    +@@ -91736,7 +100582,7 @@ static int loadStatTbl(
    +     pIdx->aSample = sqlite3DbMallocZero(db, nByte);
    +     if( pIdx->aSample==0 ){
    +       sqlite3_finalize(pStmt);
    +-      return SQLITE_NOMEM;
    ++      return SQLITE_NOMEM_BKPT;
    +     }
    +     pSpace = (tRowcnt*)&pIdx->aSample[nSample];
    +     pIdx->aAvgEq = pSpace; pSpace += nIdxCol;
    +@@ -91752,7 +100598,7 @@ static int loadStatTbl(
    + 
    +   zSql = sqlite3MPrintf(db, zSql2, zDb);
    +   if( !zSql ){
    +-    return SQLITE_NOMEM;
    ++    return SQLITE_NOMEM_BKPT;
    +   }
    +   rc = sqlite3_prepare(db, zSql, -1, &pStmt, 0);
    +   sqlite3DbFree(db, zSql);
    +@@ -91790,9 +100636,11 @@ static int loadStatTbl(
    +     pSample->p = sqlite3DbMallocZero(db, pSample->n + 2);
    +     if( pSample->p==0 ){
    +       sqlite3_finalize(pStmt);
    +-      return SQLITE_NOMEM;
    ++      return SQLITE_NOMEM_BKPT;
    ++    }
    ++    if( pSample->n ){
    ++      memcpy(pSample->p, sqlite3_column_blob(pStmt, 4), pSample->n);
    +     }
    +-    memcpy(pSample->p, sqlite3_column_blob(pStmt, 4), pSample->n);
    +     pIdx->nSample++;
    +   }
    +   rc = sqlite3_finalize(pStmt);
    +@@ -91807,7 +100655,7 @@ static int loadStatTbl(
    + static int loadStat4(sqlite3 *db, const char *zDb){
    +   int rc = SQLITE_OK;             /* Result codes from subroutines */
    + 
    +-  assert( db->lookaside.bEnabled==0 );
    ++  assert( db->lookaside.bDisable );
    +   if( sqlite3FindTable(db, "sqlite_stat4", zDb) ){
    +     rc = loadStatTbl(db, 0,
    +       "SELECT idx,count(*) FROM %Q.sqlite_stat4 GROUP BY idx", 
    +@@ -91852,49 +100700,56 @@ SQLITE_PRIVATE int sqlite3AnalysisLoad(sqlite3 *db, int iDb){
    +   analysisInfo sInfo;
    +   HashElem *i;
    +   char *zSql;
    +-  int rc;
    ++  int rc = SQLITE_OK;
    ++  Schema *pSchema = db->aDb[iDb].pSchema;
    + 
    +   assert( iDb>=0 && iDb<db->nDb );
    +   assert( db->aDb[iDb].pBt!=0 );
    + 
    +   /* Clear any prior statistics */
    +   assert( sqlite3SchemaMutexHeld(db, iDb, 0) );
    +-  for(i=sqliteHashFirst(&db->aDb[iDb].pSchema->idxHash);i;i=sqliteHashNext(i)){
    ++  for(i=sqliteHashFirst(&pSchema->tblHash); i; i=sqliteHashNext(i)){
    ++    Table *pTab = sqliteHashData(i);
    ++    pTab->tabFlags &= ~TF_HasStat1;
    ++  }
    ++  for(i=sqliteHashFirst(&pSchema->idxHash); i; i=sqliteHashNext(i)){
    +     Index *pIdx = sqliteHashData(i);
    +-    sqlite3DefaultRowEst(pIdx);
    ++    pIdx->hasStat1 = 0;
    + #ifdef SQLITE_ENABLE_STAT3_OR_STAT4
    +     sqlite3DeleteIndexSamples(db, pIdx);
    +     pIdx->aSample = 0;
    + #endif
    +   }
    + 
    +-  /* Check to make sure the sqlite_stat1 table exists */
    ++  /* Load new statistics out of the sqlite_stat1 table */
    +   sInfo.db = db;
    +-  sInfo.zDatabase = db->aDb[iDb].zName;
    +-  if( sqlite3FindTable(db, "sqlite_stat1", sInfo.zDatabase)==0 ){
    +-    return SQLITE_ERROR;
    ++  sInfo.zDatabase = db->aDb[iDb].zDbSName;
    ++  if( sqlite3FindTable(db, "sqlite_stat1", sInfo.zDatabase)!=0 ){
    ++    zSql = sqlite3MPrintf(db, 
    ++        "SELECT tbl,idx,stat FROM %Q.sqlite_stat1", sInfo.zDatabase);
    ++    if( zSql==0 ){
    ++      rc = SQLITE_NOMEM_BKPT;
    ++    }else{
    ++      rc = sqlite3_exec(db, zSql, analysisLoader, &sInfo, 0);
    ++      sqlite3DbFree(db, zSql);
    ++    }
    +   }
    + 
    +-  /* Load new statistics out of the sqlite_stat1 table */
    +-  zSql = sqlite3MPrintf(db, 
    +-      "SELECT tbl,idx,stat FROM %Q.sqlite_stat1", sInfo.zDatabase);
    +-  if( zSql==0 ){
    +-    rc = SQLITE_NOMEM;
    +-  }else{
    +-    rc = sqlite3_exec(db, zSql, analysisLoader, &sInfo, 0);
    +-    sqlite3DbFree(db, zSql);
    ++  /* Set appropriate defaults on all indexes not in the sqlite_stat1 table */
    ++  assert( sqlite3SchemaMutexHeld(db, iDb, 0) );
    ++  for(i=sqliteHashFirst(&pSchema->idxHash); i; i=sqliteHashNext(i)){
    ++    Index *pIdx = sqliteHashData(i);
    ++    if( !pIdx->hasStat1 ) sqlite3DefaultRowEst(pIdx);
    +   }
    + 
    +-
    +   /* Load the statistics from the sqlite_stat4 table. */
    + #ifdef SQLITE_ENABLE_STAT3_OR_STAT4
    +   if( rc==SQLITE_OK && OptimizationEnabled(db, SQLITE_Stat34) ){
    +-    int lookasideEnabled = db->lookaside.bEnabled;
    +-    db->lookaside.bEnabled = 0;
    ++    db->lookaside.bDisable++;
    +     rc = loadStat4(db, sInfo.zDatabase);
    +-    db->lookaside.bEnabled = lookasideEnabled;
    ++    db->lookaside.bDisable--;
    +   }
    +-  for(i=sqliteHashFirst(&db->aDb[iDb].pSchema->idxHash);i;i=sqliteHashNext(i)){
    ++  for(i=sqliteHashFirst(&pSchema->idxHash); i; i=sqliteHashNext(i)){
    +     Index *pIdx = sqliteHashData(i);
    +     sqlite3_free(pIdx->aiRowEst);
    +     pIdx->aiRowEst = 0;
    +@@ -91902,7 +100757,7 @@ SQLITE_PRIVATE int sqlite3AnalysisLoad(sqlite3 *db, int iDb){
    + #endif
    + 
    +   if( rc==SQLITE_NOMEM ){
    +-    db->mallocFailed = 1;
    ++    sqlite3OomFault(db);
    +   }
    +   return rc;
    + }
    +@@ -91983,7 +100838,8 @@ static void attachFunc(
    +   char *zPath = 0;
    +   char *zErr = 0;
    +   unsigned int flags;
    +-  Db *aNew;
    ++  Db *aNew;                 /* New array of Db pointers */
    ++  Db *pNew;                 /* Db object for the newly attached database */
    +   char *zErrDyn = 0;
    +   sqlite3_vfs *pVfs;
    + 
    +@@ -92006,12 +100862,8 @@ static void attachFunc(
    +     );
    +     goto attach_error;
    +   }
    +-  if( !db->autoCommit ){
    +-    zErrDyn = sqlite3MPrintf(db, "cannot ATTACH database within transaction");
    +-    goto attach_error;
    +-  }
    +   for(i=0; i<db->nDb; i++){
    +-    char *z = db->aDb[i].zName;
    ++    char *z = db->aDb[i].zDbSName;
    +     assert( z && zName );
    +     if( sqlite3StrICmp(z, zName)==0 ){
    +       zErrDyn = sqlite3MPrintf(db, "database %s is already in use", zName);
    +@@ -92023,7 +100875,7 @@ static void attachFunc(
    +   ** hash tables.
    +   */
    +   if( db->aDb==db->aDbStatic ){
    +-    aNew = sqlite3DbMallocRaw(db, sizeof(db->aDb[0])*3 );
    ++    aNew = sqlite3DbMallocRawNN(db, sizeof(db->aDb[0])*3 );
    +     if( aNew==0 ) return;
    +     memcpy(aNew, db->aDb, sizeof(db->aDb[0])*2);
    +   }else{
    +@@ -92031,8 +100883,8 @@ static void attachFunc(
    +     if( aNew==0 ) return;
    +   }
    +   db->aDb = aNew;
    +-  aNew = &db->aDb[db->nDb];
    +-  memset(aNew, 0, sizeof(*aNew));
    ++  pNew = &db->aDb[db->nDb];
    ++  memset(pNew, 0, sizeof(*pNew));
    + 
    +   /* Open the database file. If the btree is successfully opened, use
    +   ** it to obtain the database schema. At this point the schema may
    +@@ -92041,43 +100893,45 @@ static void attachFunc(
    +   flags = db->openFlags;
    +   rc = sqlite3ParseUri(db->pVfs->zName, zFile, &flags, &pVfs, &zPath, &zErr);
    +   if( rc!=SQLITE_OK ){
    +-    if( rc==SQLITE_NOMEM ) db->mallocFailed = 1;
    ++    if( rc==SQLITE_NOMEM ) sqlite3OomFault(db);
    +     sqlite3_result_error(context, zErr, -1);
    +     sqlite3_free(zErr);
    +     return;
    +   }
    +   assert( pVfs );
    +   flags |= SQLITE_OPEN_MAIN_DB;
    +-  rc = sqlite3BtreeOpen(pVfs, zPath, db, &aNew->pBt, 0, flags);
    ++  rc = sqlite3BtreeOpen(pVfs, zPath, db, &pNew->pBt, 0, flags);
    +   sqlite3_free( zPath );
    +   db->nDb++;
    ++  db->skipBtreeMutex = 0;
    +   if( rc==SQLITE_CONSTRAINT ){
    +     rc = SQLITE_ERROR;
    +     zErrDyn = sqlite3MPrintf(db, "database is already attached");
    +   }else if( rc==SQLITE_OK ){
    +     Pager *pPager;
    +-    aNew->pSchema = sqlite3SchemaGet(db, aNew->pBt);
    +-    if( !aNew->pSchema ){
    +-      rc = SQLITE_NOMEM;
    +-    }else if( aNew->pSchema->file_format && aNew->pSchema->enc!=ENC(db) ){
    ++    pNew->pSchema = sqlite3SchemaGet(db, pNew->pBt);
    ++    if( !pNew->pSchema ){
    ++      rc = SQLITE_NOMEM_BKPT;
    ++    }else if( pNew->pSchema->file_format && pNew->pSchema->enc!=ENC(db) ){
    +       zErrDyn = sqlite3MPrintf(db, 
    +         "attached databases must use the same text encoding as main database");
    +       rc = SQLITE_ERROR;
    +     }
    +-    sqlite3BtreeEnter(aNew->pBt);
    +-    pPager = sqlite3BtreePager(aNew->pBt);
    ++    sqlite3BtreeEnter(pNew->pBt);
    ++    pPager = sqlite3BtreePager(pNew->pBt);
    +     sqlite3PagerLockingMode(pPager, db->dfltLockMode);
    +-    sqlite3BtreeSecureDelete(aNew->pBt,
    ++    sqlite3BtreeSecureDelete(pNew->pBt,
    +                              sqlite3BtreeSecureDelete(db->aDb[0].pBt,-1) );
    + #ifndef SQLITE_OMIT_PAGER_PRAGMAS
    +-    sqlite3BtreeSetPagerFlags(aNew->pBt, 3 | (db->flags & PAGER_FLAGS_MASK));
    ++    sqlite3BtreeSetPagerFlags(pNew->pBt,
    ++                      PAGER_SYNCHRONOUS_FULL | (db->flags & PAGER_FLAGS_MASK));
    + #endif
    +-    sqlite3BtreeLeave(aNew->pBt);
    ++    sqlite3BtreeLeave(pNew->pBt);
    +   }
    +-  aNew->safety_level = 3;
    +-  aNew->zName = sqlite3DbStrDup(db, zName);
    +-  if( rc==SQLITE_OK && aNew->zName==0 ){
    +-    rc = SQLITE_NOMEM;
    ++  pNew->safety_level = SQLITE_DEFAULT_SYNCHRONOUS+1;
    ++  pNew->zDbSName = sqlite3DbStrDup(db, zName);
    ++  if( rc==SQLITE_OK && pNew->zDbSName==0 ){
    ++    rc = SQLITE_NOMEM_BKPT;
    +   }
    + 
    + 
    +@@ -92105,7 +100959,7 @@ static void attachFunc(
    +       case SQLITE_NULL:
    +         /* No key specified.  Use the key from the main database */
    +         sqlite3CodecGetKey(db, 0, (void**)&zKey, &nKey);
    +-        if( nKey>0 || sqlite3BtreeGetOptimalReserve(db->aDb[0].pBt)>0 ){
    ++        if( nKey || sqlite3BtreeGetOptimalReserve(db->aDb[0].pBt)>0 ){
    +           rc = sqlite3CodecAttach(db, db->nDb-1, zKey, nKey);
    +         }
    +         break;
    +@@ -92143,7 +100997,7 @@ static void attachFunc(
    +     sqlite3ResetAllSchemasOfConnection(db);
    +     db->nDb = iDb;
    +     if( rc==SQLITE_NOMEM || rc==SQLITE_IOERR_NOMEM ){
    +-      db->mallocFailed = 1;
    ++      sqlite3OomFault(db);
    +       sqlite3DbFree(db, zErrDyn);
    +       zErrDyn = sqlite3MPrintf(db, "out of memory");
    +     }else if( zErrDyn==0 ){
    +@@ -92188,7 +101042,7 @@ static void detachFunc(
    +   for(i=0; i<db->nDb; i++){
    +     pDb = &db->aDb[i];
    +     if( pDb->pBt==0 ) continue;
    +-    if( sqlite3StrICmp(pDb->zName, zName)==0 ) break;
    ++    if( sqlite3StrICmp(pDb->zDbSName, zName)==0 ) break;
    +   }
    + 
    +   if( i>=db->nDb ){
    +@@ -92199,11 +101053,6 @@ static void detachFunc(
    +     sqlite3_snprintf(sizeof(zErr),zErr, "cannot detach database %s", zName);
    +     goto detach_error;
    +   }
    +-  if( !db->autoCommit ){
    +-    sqlite3_snprintf(sizeof(zErr), zErr,
    +-                     "cannot DETACH database within transaction");
    +-    goto detach_error;
    +-  }
    +   if( sqlite3BtreeIsInReadTrans(pDb->pBt) || sqlite3BtreeIsInBackup(pDb->pBt) ){
    +     sqlite3_snprintf(sizeof(zErr),zErr, "database %s is locked", zName);
    +     goto detach_error;
    +@@ -92238,6 +101087,7 @@ static void codeAttach(
    +   sqlite3* db = pParse->db;
    +   int regArgs;
    + 
    ++  if( pParse->nErr ) goto attach_end;
    +   memset(&sName, 0, sizeof(NameContext));
    +   sName.pParse = pParse;
    + 
    +@@ -92273,11 +101123,11 @@ static void codeAttach(
    + 
    +   assert( v || db->mallocFailed );
    +   if( v ){
    +-    sqlite3VdbeAddOp3(v, OP_Function0, 0, regArgs+3-pFunc->nArg, regArgs+3);
    ++    sqlite3VdbeAddOp4(v, OP_Function0, 0, regArgs+3-pFunc->nArg, regArgs+3,
    ++                      (char *)pFunc, P4_FUNCDEF);
    +     assert( pFunc->nArg==-1 || (pFunc->nArg&0xff)==pFunc->nArg );
    +     sqlite3VdbeChangeP5(v, (u8)(pFunc->nArg));
    +-    sqlite3VdbeChangeP4(v, -1, (char *)pFunc, P4_FUNCDEF);
    +-
    ++ 
    +     /* Code an OP_Expire. For an ATTACH statement, set P1 to true (expire this
    +     ** statement only). For DETACH, set it to false (expire all existing
    +     ** statements).
    +@@ -92302,12 +101152,10 @@ SQLITE_PRIVATE void sqlite3Detach(Parse *pParse, Expr *pDbname){
    +     SQLITE_UTF8,      /* funcFlags */
    +     0,                /* pUserData */
    +     0,                /* pNext */
    +-    detachFunc,       /* xFunc */
    +-    0,                /* xStep */
    ++    detachFunc,       /* xSFunc */
    +     0,                /* xFinalize */
    +     "sqlite_detach",  /* zName */
    +-    0,                /* pHash */
    +-    0                 /* pDestructor */
    ++    {0}
    +   };
    +   codeAttach(pParse, SQLITE_DETACH, &detach_func, pDbname, 0, 0, pDbname);
    + }
    +@@ -92323,12 +101171,10 @@ SQLITE_PRIVATE void sqlite3Attach(Parse *pParse, Expr *p, Expr *pDbname, Expr *p
    +     SQLITE_UTF8,      /* funcFlags */
    +     0,                /* pUserData */
    +     0,                /* pNext */
    +-    attachFunc,       /* xFunc */
    +-    0,                /* xStep */
    ++    attachFunc,       /* xSFunc */
    +     0,                /* xFinalize */
    +     "sqlite_attach",  /* zName */
    +-    0,                /* pHash */
    +-    0                 /* pDestructor */
    ++    {0}
    +   };
    +   codeAttach(pParse, SQLITE_ATTACH, &attach_func, p, p, pDbname, pKey);
    + }
    +@@ -92350,7 +101196,7 @@ SQLITE_PRIVATE void sqlite3FixInit(
    +   db = pParse->db;
    +   assert( db->nDb>iDb );
    +   pFix->pParse = pParse;
    +-  pFix->zDb = db->aDb[iDb].zName;
    ++  pFix->zDb = db->aDb[iDb].zDbSName;
    +   pFix->pSchema = db->aDb[iDb].pSchema;
    +   pFix->zType = zType;
    +   pFix->pName = pName;
    +@@ -92427,9 +101273,6 @@ SQLITE_PRIVATE int sqlite3FixSelect(
    +     if( sqlite3FixExpr(pFix, pSelect->pLimit) ){
    +       return 1;
    +     }
    +-    if( sqlite3FixExpr(pFix, pSelect->pOffset) ){
    +-      return 1;
    +-    }
    +     pSelect = pSelect->pPrior;
    +   }
    +   return 0;
    +@@ -92447,7 +101290,7 @@ SQLITE_PRIVATE int sqlite3FixExpr(
    +         return 1;
    +       }
    +     }
    +-    if( ExprHasProperty(pExpr, EP_TokenOnly) ) break;
    ++    if( ExprHasProperty(pExpr, EP_TokenOnly|EP_Leaf) ) break;
    +     if( ExprHasProperty(pExpr, EP_xIsSelect) ){
    +       if( sqlite3FixSelect(pFix, pExpr->x.pSelect) ) return 1;
    +     }else{
    +@@ -92568,7 +101411,7 @@ SQLITE_PRIVATE int sqlite3FixTriggerStep(
    + ** Setting the auth function to NULL disables this hook.  The default
    + ** setting of the auth function is NULL.
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_set_authorizer(
    ++SQLITE_API int sqlite3_set_authorizer(
    +   sqlite3 *db,
    +   int (*xAuth)(void*,int,const char*,const char*,const char*,const char*),
    +   void *pArg
    +@@ -92608,21 +101451,20 @@ SQLITE_PRIVATE int sqlite3AuthReadCol(
    +   const char *zCol,               /* Column name */
    +   int iDb                         /* Index of containing database. */
    + ){
    +-  sqlite3 *db = pParse->db;       /* Database handle */
    +-  char *zDb = db->aDb[iDb].zName; /* Name of attached database */
    +-  int rc;                         /* Auth callback return code */
    ++  sqlite3 *db = pParse->db;          /* Database handle */
    ++  char *zDb = db->aDb[iDb].zDbSName; /* Schema name of attached database */
    ++  int rc;                            /* Auth callback return code */
    + 
    ++  if( db->init.busy ) return SQLITE_OK;
    +   rc = db->xAuth(db->pAuthArg, SQLITE_READ, zTab,zCol,zDb,pParse->zAuthContext
    + #ifdef SQLITE_USER_AUTHENTICATION
    +                  ,db->auth.zAuthUser
    + #endif
    +                 );
    +   if( rc==SQLITE_DENY ){
    +-    if( db->nDb>2 || iDb!=0 ){
    +-      sqlite3ErrorMsg(pParse, "access to %s.%s.%s is prohibited",zDb,zTab,zCol);
    +-    }else{
    +-      sqlite3ErrorMsg(pParse, "access to %s.%s is prohibited", zTab, zCol);
    +-    }
    ++    char *z = sqlite3_mprintf("%s.%s", zTab, zCol);
    ++    if( db->nDb>2 || iDb!=0 ) z = sqlite3_mprintf("%s.%z", zDb, z);
    ++    sqlite3ErrorMsg(pParse, "access to %z is prohibited", z);
    +     pParse->rc = SQLITE_AUTH;
    +   }else if( rc!=SQLITE_IGNORE && rc!=SQLITE_OK ){
    +     sqliteAuthBadReturnCode(pParse);
    +@@ -92716,6 +101558,18 @@ SQLITE_PRIVATE int sqlite3AuthCheck(
    +   if( db->xAuth==0 ){
    +     return SQLITE_OK;
    +   }
    ++
    ++  /* EVIDENCE-OF: R-43249-19882 The third through sixth parameters to the
    ++  ** callback are either NULL pointers or zero-terminated strings that
    ++  ** contain additional details about the action to be authorized.
    ++  **
    ++  ** The following testcase() macros show that any of the 3rd through 6th
    ++  ** parameters can be either NULL or a string. */
    ++  testcase( zArg1==0 );
    ++  testcase( zArg2==0 );
    ++  testcase( zArg3==0 );
    ++  testcase( pParse->zAuthContext==0 );
    ++
    +   rc = db->xAuth(db->pAuthArg, code, zArg1, zArg2, zArg3, pParse->zAuthContext
    + #ifdef SQLITE_USER_AUTHENTICATION
    +                  ,db->auth.zAuthUser
    +@@ -92788,25 +101642,16 @@ SQLITE_PRIVATE void sqlite3AuthContextPop(AuthContext *pContext){
    + */
    + /* #include "sqliteInt.h" */
    + 
    +-/*
    +-** This routine is called when a new SQL statement is beginning to
    +-** be parsed.  Initialize the pParse structure as needed.
    +-*/
    +-SQLITE_PRIVATE void sqlite3BeginParse(Parse *pParse, int explainFlag){
    +-  pParse->explain = (u8)explainFlag;
    +-  pParse->nVar = 0;
    +-}
    +-
    + #ifndef SQLITE_OMIT_SHARED_CACHE
    + /*
    + ** The TableLock structure is only used by the sqlite3TableLock() and
    + ** codeTableLocks() functions.
    + */
    + struct TableLock {
    +-  int iDb;             /* The database containing the table to be locked */
    +-  int iTab;            /* The root page of the table to be locked */
    +-  u8 isWriteLock;      /* True for write lock.  False for a read lock */
    +-  const char *zName;   /* Name of the table */
    ++  int iDb;               /* The database containing the table to be locked */
    ++  int iTab;              /* The root page of the table to be locked */
    ++  u8 isWriteLock;        /* True for write lock.  False for a read lock */
    ++  const char *zLockName; /* Name of the table */
    + };
    + 
    + /*
    +@@ -92832,6 +101677,8 @@ SQLITE_PRIVATE void sqlite3TableLock(
    +   TableLock *p;
    +   assert( iDb>=0 );
    + 
    ++  if( iDb==1 ) return;
    ++  if( !sqlite3BtreeSharable(pParse->db->aDb[iDb].pBt) ) return;
    +   for(i=0; i<pToplevel->nTableLock; i++){
    +     p = &pToplevel->aTableLock[i];
    +     if( p->iDb==iDb && p->iTab==iTab ){
    +@@ -92848,10 +101695,10 @@ SQLITE_PRIVATE void sqlite3TableLock(
    +     p->iDb = iDb;
    +     p->iTab = iTab;
    +     p->isWriteLock = isWriteLock;
    +-    p->zName = zName;
    ++    p->zLockName = zName;
    +   }else{
    +     pToplevel->nTableLock = 0;
    +-    pToplevel->db->mallocFailed = 1;
    ++    sqlite3OomFault(pToplevel->db);
    +   }
    + }
    + 
    +@@ -92870,7 +101717,7 @@ static void codeTableLocks(Parse *pParse){
    +     TableLock *p = &pParse->aTableLock[i];
    +     int p1 = p->iDb;
    +     sqlite3VdbeAddOp4(pVdbe, OP_TableLock, p1, p->iTab, p->isWriteLock,
    +-                      p->zName, P4_STATIC);
    ++                      p->zLockName, P4_STATIC);
    +   }
    + }
    + #else
    +@@ -92919,15 +101766,14 @@ SQLITE_PRIVATE void sqlite3FinishCoding(Parse *pParse){
    +   assert( !pParse->isMultiWrite 
    +        || sqlite3VdbeAssertMayAbort(v, pParse->mayAbort));
    +   if( v ){
    +-    while( sqlite3VdbeDeletePriorOpcode(v, OP_Close) ){}
    +     sqlite3VdbeAddOp0(v, OP_Halt);
    + 
    + #if SQLITE_USER_AUTHENTICATION
    +     if( pParse->nTableLock>0 && db->init.busy==0 ){
    +       sqlite3UserAuthInit(db);
    +       if( db->auth.authLevel<UAUTH_User ){
    +-        pParse->rc = SQLITE_AUTH_USER;
    +         sqlite3ErrorMsg(pParse, "user not authenticated");
    ++        pParse->rc = SQLITE_AUTH_USER;
    +         return;
    +       }
    +     }
    +@@ -92946,14 +101792,16 @@ SQLITE_PRIVATE void sqlite3FinishCoding(Parse *pParse){
    +       assert( sqlite3VdbeGetOp(v, 0)->opcode==OP_Init );
    +       sqlite3VdbeJumpHere(v, 0);
    +       for(iDb=0; iDb<db->nDb; iDb++){
    ++        Schema *pSchema;
    +         if( DbMaskTest(pParse->cookieMask, iDb)==0 ) continue;
    +         sqlite3VdbeUsesBtree(v, iDb);
    ++        pSchema = db->aDb[iDb].pSchema;
    +         sqlite3VdbeAddOp4Int(v,
    +           OP_Transaction,                    /* Opcode */
    +           iDb,                               /* P1 */
    +           DbMaskTest(pParse->writeMask,iDb), /* P2 */
    +-          pParse->cookieValue[iDb],          /* P3 */
    +-          db->aDb[iDb].pSchema->iGeneration  /* P4 */
    ++          pSchema->schema_cookie,            /* P3 */
    ++          pSchema->iGeneration               /* P4 */
    +         );
    +         if( db->init.busy==0 ) sqlite3VdbeChangeP5(v, 1);
    +         VdbeComment((v,
    +@@ -93001,15 +101849,9 @@ SQLITE_PRIVATE void sqlite3FinishCoding(Parse *pParse){
    +     if( pParse->pAinc!=0 && pParse->nTab==0 ) pParse->nTab = 1;
    +     sqlite3VdbeMakeReady(v, pParse);
    +     pParse->rc = SQLITE_DONE;
    +-    pParse->colNamesSet = 0;
    +   }else{
    +     pParse->rc = SQLITE_ERROR;
    +   }
    +-  pParse->nTab = 0;
    +-  pParse->nMem = 0;
    +-  pParse->nSet = 0;
    +-  pParse->nVar = 0;
    +-  DbMaskZero(pParse->cookieMask);
    + }
    + 
    + /*
    +@@ -93029,8 +101871,7 @@ SQLITE_PRIVATE void sqlite3NestedParse(Parse *pParse, const char *zFormat, ...){
    +   char *zSql;
    +   char *zErrMsg = 0;
    +   sqlite3 *db = pParse->db;
    +-# define SAVE_SZ  (sizeof(Parse) - offsetof(Parse,nVar))
    +-  char saveBuf[SAVE_SZ];
    ++  char saveBuf[PARSE_TAIL_SZ];
    + 
    +   if( pParse->nErr ) return;
    +   assert( pParse->nested<10 );  /* Nesting should only be of limited depth */
    +@@ -93041,12 +101882,12 @@ SQLITE_PRIVATE void sqlite3NestedParse(Parse *pParse, const char *zFormat, ...){
    +     return;   /* A malloc must have failed */
    +   }
    +   pParse->nested++;
    +-  memcpy(saveBuf, &pParse->nVar, SAVE_SZ);
    +-  memset(&pParse->nVar, 0, SAVE_SZ);
    ++  memcpy(saveBuf, PARSE_TAIL(pParse), PARSE_TAIL_SZ);
    ++  memset(PARSE_TAIL(pParse), 0, PARSE_TAIL_SZ);
    +   sqlite3RunParser(pParse, zSql, &zErrMsg);
    +   sqlite3DbFree(db, zErrMsg);
    +   sqlite3DbFree(db, zSql);
    +-  memcpy(&pParse->nVar, saveBuf, SAVE_SZ);
    ++  memcpy(PARSE_TAIL(pParse), saveBuf, PARSE_TAIL_SZ);
    +   pParse->nested--;
    + }
    + 
    +@@ -93085,14 +101926,22 @@ SQLITE_PRIVATE Table *sqlite3FindTable(sqlite3 *db, const char *zName, const cha
    +     return 0;
    +   }
    + #endif
    +-  for(i=OMIT_TEMPDB; i<db->nDb; i++){
    +-    int j = (i<2) ? i^1 : i;   /* Search TEMP before MAIN */
    +-    if( zDatabase!=0 && sqlite3StrICmp(zDatabase, db->aDb[j].zName) ) continue;
    +-    assert( sqlite3SchemaMutexHeld(db, j, 0) );
    +-    p = sqlite3HashFind(&db->aDb[j].pSchema->tblHash, zName);
    +-    if( p ) break;
    ++  while(1){
    ++    for(i=OMIT_TEMPDB; i<db->nDb; i++){
    ++      int j = (i<2) ? i^1 : i;   /* Search TEMP before MAIN */
    ++      if( zDatabase==0 || sqlite3StrICmp(zDatabase, db->aDb[j].zDbSName)==0 ){
    ++        assert( sqlite3SchemaMutexHeld(db, j, 0) );
    ++        p = sqlite3HashFind(&db->aDb[j].pSchema->tblHash, zName);
    ++        if( p ) return p;
    ++      }
    ++    }
    ++    /* Not found.  If the name we were looking for was temp.sqlite_master
    ++    ** then change the name to sqlite_temp_master and try again. */
    ++    if( sqlite3StrICmp(zName, MASTER_NAME)!=0 ) break;
    ++    if( sqlite3_stricmp(zDatabase, db->aDb[1].zDbSName)!=0 ) break;
    ++    zName = TEMP_MASTER_NAME;
    +   }
    +-  return p;
    ++  return 0;
    + }
    + 
    + /*
    +@@ -93107,7 +101956,7 @@ SQLITE_PRIVATE Table *sqlite3FindTable(sqlite3 *db, const char *zName, const cha
    + */
    + SQLITE_PRIVATE Table *sqlite3LocateTable(
    +   Parse *pParse,         /* context in which to report errors */
    +-  int isView,            /* True if looking for a VIEW rather than a TABLE */
    ++  u32 flags,             /* LOCATE_VIEW or LOCATE_NOERR */
    +   const char *zName,     /* Name of the table we are looking for */
    +   const char *zDbase     /* Name of the database.  Might be NULL */
    + ){
    +@@ -93121,31 +101970,31 @@ SQLITE_PRIVATE Table *sqlite3LocateTable(
    + 
    +   p = sqlite3FindTable(pParse->db, zName, zDbase);
    +   if( p==0 ){
    +-    const char *zMsg = isView ? "no such view" : "no such table";
    ++    const char *zMsg = flags & LOCATE_VIEW ? "no such view" : "no such table";
    + #ifndef SQLITE_OMIT_VIRTUALTABLE
    +     if( sqlite3FindDbName(pParse->db, zDbase)<1 ){
    +       /* If zName is the not the name of a table in the schema created using
    +       ** CREATE, then check to see if it is the name of an virtual table that
    +       ** can be an eponymous virtual table. */
    +       Module *pMod = (Module*)sqlite3HashFind(&pParse->db->aModule, zName);
    ++      if( pMod==0 && sqlite3_strnicmp(zName, "pragma_", 7)==0 ){
    ++        pMod = sqlite3PragmaVtabRegister(pParse->db, zName);
    ++      }
    +       if( pMod && sqlite3VtabEponymousTableInit(pParse, pMod) ){
    +         return pMod->pEpoTab;
    +       }
    +     }
    + #endif
    +-    if( zDbase ){
    +-      sqlite3ErrorMsg(pParse, "%s: %s.%s", zMsg, zDbase, zName);
    +-    }else{
    +-      sqlite3ErrorMsg(pParse, "%s: %s", zMsg, zName);
    ++    if( (flags & LOCATE_NOERR)==0 ){
    ++      if( zDbase ){
    ++        sqlite3ErrorMsg(pParse, "%s: %s.%s", zMsg, zDbase, zName);
    ++      }else{
    ++        sqlite3ErrorMsg(pParse, "%s: %s", zMsg, zName);
    ++      }
    ++      pParse->checkSchema = 1;
    +     }
    +-    pParse->checkSchema = 1;
    +   }
    +-#if SQLITE_USER_AUTHENTICATION
    +-  else if( pParse->db->auth.authLevel<UAUTH_User ){
    +-    sqlite3ErrorMsg(pParse, "user not authenticated");
    +-    p = 0;
    +-  }
    +-#endif
    ++
    +   return p;
    + }
    + 
    +@@ -93160,18 +102009,18 @@ SQLITE_PRIVATE Table *sqlite3LocateTable(
    + */
    + SQLITE_PRIVATE Table *sqlite3LocateTableItem(
    +   Parse *pParse, 
    +-  int isView, 
    ++  u32 flags,
    +   struct SrcList_item *p
    + ){
    +   const char *zDb;
    +   assert( p->pSchema==0 || p->zDatabase==0 );
    +   if( p->pSchema ){
    +     int iDb = sqlite3SchemaToIndex(pParse->db, p->pSchema);
    +-    zDb = pParse->db->aDb[iDb].zName;
    ++    zDb = pParse->db->aDb[iDb].zDbSName;
    +   }else{
    +     zDb = p->zDatabase;
    +   }
    +-  return sqlite3LocateTable(pParse, isView, p->zName, zDb);
    ++  return sqlite3LocateTable(pParse, flags, p->zName, zDb);
    + }
    + 
    + /*
    +@@ -93195,7 +102044,7 @@ SQLITE_PRIVATE Index *sqlite3FindIndex(sqlite3 *db, const char *zName, const cha
    +     int j = (i<2) ? i^1 : i;  /* Search TEMP before MAIN */
    +     Schema *pSchema = db->aDb[j].pSchema;
    +     assert( pSchema );
    +-    if( zDb && sqlite3StrICmp(zDb, db->aDb[j].zName) ) continue;
    ++    if( zDb && sqlite3StrICmp(zDb, db->aDb[j].zDbSName) ) continue;
    +     assert( sqlite3SchemaMutexHeld(db, j, 0) );
    +     p = sqlite3HashFind(&pSchema->idxHash, zName);
    +     if( p ) break;
    +@@ -93213,7 +102062,7 @@ static void freeIndex(sqlite3 *db, Index *p){
    +   sqlite3ExprDelete(db, p->pPartIdxWhere);
    +   sqlite3ExprListDelete(db, p->aColExpr);
    +   sqlite3DbFree(db, p->zColAff);
    +-  if( p->isResized ) sqlite3DbFree(db, p->azColl);
    ++  if( p->isResized ) sqlite3DbFree(db, (void *)p->azColl);
    + #ifdef SQLITE_ENABLE_STAT3_OR_STAT4
    +   sqlite3_free(p->aiRowEst);
    + #endif
    +@@ -93248,7 +102097,7 @@ SQLITE_PRIVATE void sqlite3UnlinkAndDeleteIndex(sqlite3 *db, int iDb, const char
    +     }
    +     freeIndex(db, pIndex);
    +   }
    +-  db->flags |= SQLITE_InternChanges;
    ++  db->mDbFlags |= DBFLAG_SchemaChange;
    + }
    + 
    + /*
    +@@ -93264,8 +102113,8 @@ SQLITE_PRIVATE void sqlite3CollapseDatabaseArray(sqlite3 *db){
    +   for(i=j=2; i<db->nDb; i++){
    +     struct Db *pDb = &db->aDb[i];
    +     if( pDb->pBt==0 ){
    +-      sqlite3DbFree(db, pDb->zName);
    +-      pDb->zName = 0;
    ++      sqlite3DbFree(db, pDb->zDbSName);
    ++      pDb->zDbSName = 0;
    +       continue;
    +     }
    +     if( j<i ){
    +@@ -93273,7 +102122,6 @@ SQLITE_PRIVATE void sqlite3CollapseDatabaseArray(sqlite3 *db){
    +     }
    +     j++;
    +   }
    +-  memset(&db->aDb[j], 0, (db->nDb-j)*sizeof(db->aDb[j]));
    +   db->nDb = j;
    +   if( db->nDb<=2 && db->aDb!=db->aDbStatic ){
    +     memcpy(db->aDbStatic, db->aDb, 2*sizeof(db->aDb[0]));
    +@@ -93284,28 +102132,26 @@ SQLITE_PRIVATE void sqlite3CollapseDatabaseArray(sqlite3 *db){
    + 
    + /*
    + ** Reset the schema for the database at index iDb.  Also reset the
    +-** TEMP schema.
    ++** TEMP schema.  The reset is deferred if db->nSchemaLock is not zero.
    ++** Deferred resets may be run by calling with iDb<0.
    + */
    + SQLITE_PRIVATE void sqlite3ResetOneSchema(sqlite3 *db, int iDb){
    +-  Db *pDb;
    ++  int i;
    +   assert( iDb<db->nDb );
    + 
    +-  /* Case 1:  Reset the single schema identified by iDb */
    +-  pDb = &db->aDb[iDb];
    +-  assert( sqlite3SchemaMutexHeld(db, iDb, 0) );
    +-  assert( pDb->pSchema!=0 );
    +-  sqlite3SchemaClear(pDb->pSchema);
    ++  if( iDb>=0 ){
    ++    assert( sqlite3SchemaMutexHeld(db, iDb, 0) );
    ++    DbSetProperty(db, iDb, DB_ResetWanted);
    ++    DbSetProperty(db, 1, DB_ResetWanted);
    ++  }
    + 
    +-  /* If any database other than TEMP is reset, then also reset TEMP
    +-  ** since TEMP might be holding triggers that reference tables in the
    +-  ** other database.
    +-  */
    +-  if( iDb!=1 ){
    +-    pDb = &db->aDb[1];
    +-    assert( pDb->pSchema!=0 );
    +-    sqlite3SchemaClear(pDb->pSchema);
    ++  if( db->nSchemaLock==0 ){
    ++    for(i=0; i<db->nDb; i++){
    ++      if( DbHasProperty(db, i, DB_ResetWanted) ){
    ++        sqlite3SchemaClear(db->aDb[i].pSchema);
    ++      }
    ++    }
    +   }
    +-  return;
    + }
    + 
    + /*
    +@@ -93315,13 +102161,14 @@ SQLITE_PRIVATE void sqlite3ResetOneSchema(sqlite3 *db, int iDb){
    + SQLITE_PRIVATE void sqlite3ResetAllSchemasOfConnection(sqlite3 *db){
    +   int i;
    +   sqlite3BtreeEnterAll(db);
    ++  assert( db->nSchemaLock==0 );
    +   for(i=0; i<db->nDb; i++){
    +     Db *pDb = &db->aDb[i];
    +     if( pDb->pSchema ){
    +       sqlite3SchemaClear(pDb->pSchema);
    +     }
    +   }
    +-  db->flags &= ~SQLITE_InternChanges;
    ++  db->mDbFlags &= ~DBFLAG_SchemaChange;
    +   sqlite3VtabUnlockList(db);
    +   sqlite3BtreeLeaveAll(db);
    +   sqlite3CollapseDatabaseArray(db);
    +@@ -93331,7 +102178,7 @@ SQLITE_PRIVATE void sqlite3ResetAllSchemasOfConnection(sqlite3 *db){
    + ** This routine is called when a commit occurs.
    + */
    + SQLITE_PRIVATE void sqlite3CommitInternalChanges(sqlite3 *db){
    +-  db->flags &= ~SQLITE_InternChanges;
    ++  db->mDbFlags &= ~DBFLAG_SchemaChange;
    + }
    + 
    + /*
    +@@ -93346,8 +102193,6 @@ SQLITE_PRIVATE void sqlite3DeleteColumnNames(sqlite3 *db, Table *pTable){
    +     for(i=0; i<pTable->nCol; i++, pCol++){
    +       sqlite3DbFree(db, pCol->zName);
    +       sqlite3ExprDelete(db, pCol->pDflt);
    +-      sqlite3DbFree(db, pCol->zDflt);
    +-      sqlite3DbFree(db, pCol->zType);
    +       sqlite3DbFree(db, pCol->zColl);
    +     }
    +     sqlite3DbFree(db, pTable->aCol);
    +@@ -93369,27 +102214,25 @@ SQLITE_PRIVATE void sqlite3DeleteColumnNames(sqlite3 *db, Table *pTable){
    + ** db parameter can be used with db->pnBytesFreed to measure the memory
    + ** used by the Table object.
    + */
    +-SQLITE_PRIVATE void sqlite3DeleteTable(sqlite3 *db, Table *pTable){
    ++static void SQLITE_NOINLINE deleteTable(sqlite3 *db, Table *pTable){
    +   Index *pIndex, *pNext;
    +-  TESTONLY( int nLookaside; ) /* Used to verify lookaside not used for schema */
    +-
    +-  assert( !pTable || pTable->nRef>0 );
    +-
    +-  /* Do not delete the table until the reference count reaches zero. */
    +-  if( !pTable ) return;
    +-  if( ((!db || db->pnBytesFreed==0) && (--pTable->nRef)>0) ) return;
    + 
    ++#ifdef SQLITE_DEBUG
    +   /* Record the number of outstanding lookaside allocations in schema Tables
    +   ** prior to doing any free() operations.  Since schema Tables do not use
    +   ** lookaside, this number should not change. */
    +-  TESTONLY( nLookaside = (db && (pTable->tabFlags & TF_Ephemeral)==0) ?
    +-                         db->lookaside.nOut : 0 );
    ++  int nLookaside = 0;
    ++  if( db && (pTable->tabFlags & TF_Ephemeral)==0 ){
    ++    nLookaside = sqlite3LookasideUsed(db, 0);
    ++  }
    ++#endif
    + 
    +   /* Delete all indices associated with this table. */
    +   for(pIndex = pTable->pIndex; pIndex; pIndex=pNext){
    +     pNext = pIndex->pNext;
    +-    assert( pIndex->pSchema==pTable->pSchema );
    +-    if( !db || db->pnBytesFreed==0 ){
    ++    assert( pIndex->pSchema==pTable->pSchema
    ++         || (IsVirtual(pTable) && pIndex->idxType!=SQLITE_IDXTYPE_APPDEF) );
    ++    if( (db==0 || db->pnBytesFreed==0) && !IsVirtual(pTable) ){
    +       char *zName = pIndex->zName; 
    +       TESTONLY ( Index *pOld = ) sqlite3HashInsert(
    +          &pIndex->pSchema->idxHash, zName, 0
    +@@ -93416,9 +102259,16 @@ SQLITE_PRIVATE void sqlite3DeleteTable(sqlite3 *db, Table *pTable){
    +   sqlite3DbFree(db, pTable);
    + 
    +   /* Verify that no lookaside memory was used by schema tables */
    +-  assert( nLookaside==0 || nLookaside==db->lookaside.nOut );
    ++  assert( nLookaside==0 || nLookaside==sqlite3LookasideUsed(db,0) );
    ++}
    ++SQLITE_PRIVATE void sqlite3DeleteTable(sqlite3 *db, Table *pTable){
    ++  /* Do not delete the table until the reference count reaches zero. */
    ++  if( !pTable ) return;
    ++  if( ((!db || db->pnBytesFreed==0) && (--pTable->nTabRef)>0) ) return;
    ++  deleteTable(db, pTable);
    + }
    + 
    ++
    + /*
    + ** Unlink the given table from the hash tables and the delete the
    + ** table structure with all its indices and foreign keys.
    +@@ -93435,7 +102285,7 @@ SQLITE_PRIVATE void sqlite3UnlinkAndDeleteTable(sqlite3 *db, int iDb, const char
    +   pDb = &db->aDb[iDb];
    +   p = sqlite3HashInsert(&pDb->pSchema->tblHash, zTabName, 0);
    +   sqlite3DeleteTable(db, p);
    +-  db->flags |= SQLITE_InternChanges;
    ++  db->mDbFlags |= DBFLAG_SchemaChange;
    + }
    + 
    + /*
    +@@ -93468,7 +102318,7 @@ SQLITE_PRIVATE char *sqlite3NameFromToken(sqlite3 *db, Token *pName){
    + */
    + SQLITE_PRIVATE void sqlite3OpenMasterTable(Parse *p, int iDb){
    +   Vdbe *v = sqlite3GetVdbe(p);
    +-  sqlite3TableLock(p, iDb, MASTER_ROOT, 1, SCHEMA_TABLE(iDb));
    ++  sqlite3TableLock(p, iDb, MASTER_ROOT, 1, MASTER_NAME);
    +   sqlite3VdbeAddOp4Int(v, OP_OpenWrite, 0, MASTER_ROOT, iDb, 5);
    +   if( p->nTab==0 ){
    +     p->nTab = 1;
    +@@ -93485,12 +102335,11 @@ SQLITE_PRIVATE int sqlite3FindDbName(sqlite3 *db, const char *zName){
    +   int i = -1;         /* Database number */
    +   if( zName ){
    +     Db *pDb;
    +-    int n = sqlite3Strlen30(zName);
    +     for(i=(db->nDb-1), pDb=&db->aDb[i]; i>=0; i--, pDb--){
    +-      if( (!OMIT_TEMPDB || i!=1 ) && n==sqlite3Strlen30(pDb->zName) && 
    +-          0==sqlite3StrICmp(pDb->zName, zName) ){
    +-        break;
    +-      }
    ++      if( 0==sqlite3_stricmp(pDb->zDbSName, zName) ) break;
    ++      /* "main" is always an acceptable alias for the primary database
    ++      ** even if it has been renamed using SQLITE_DBCONFIG_MAINDBNAME. */
    ++      if( i==0 && 0==sqlite3_stricmp("main", zName) ) break;
    +     }
    +   }
    +   return i;
    +@@ -93536,7 +102385,8 @@ SQLITE_PRIVATE int sqlite3TwoPartName(
    +   int iDb;                    /* Database holding the object */
    +   sqlite3 *db = pParse->db;
    + 
    +-  if( ALWAYS(pName2!=0) && pName2->n>0 ){
    ++  assert( pName2!=0 );
    ++  if( pName2->n>0 ){
    +     if( db->init.busy ) {
    +       sqlite3ErrorMsg(pParse, "corrupt database");
    +       return -1;
    +@@ -93548,7 +102398,8 @@ SQLITE_PRIVATE int sqlite3TwoPartName(
    +       return -1;
    +     }
    +   }else{
    +-    assert( db->init.iDb==0 || db->init.busy );
    ++    assert( db->init.iDb==0 || db->init.busy
    ++             || (db->mDbFlags & DBFLAG_Vacuum)!=0);
    +     iDb = db->init.iDb;
    +     *pUnqual = pName1;
    +   }
    +@@ -93625,62 +102476,46 @@ SQLITE_PRIVATE void sqlite3StartTable(
    +   int iDb;         /* Database number to create the table in */
    +   Token *pName;    /* Unqualified name of the table to create */
    + 
    +-  /* The table or view name to create is passed to this routine via tokens
    +-  ** pName1 and pName2. If the table name was fully qualified, for example:
    +-  **
    +-  ** CREATE TABLE xxx.yyy (...);
    +-  ** 
    +-  ** Then pName1 is set to "xxx" and pName2 "yyy". On the other hand if
    +-  ** the table name is not fully qualified, i.e.:
    +-  **
    +-  ** CREATE TABLE yyy(...);
    +-  **
    +-  ** Then pName1 is set to "yyy" and pName2 is "".
    +-  **
    +-  ** The call below sets the pName pointer to point at the token (pName1 or
    +-  ** pName2) that stores the unqualified table name. The variable iDb is
    +-  ** set to the index of the database that the table or view is to be
    +-  ** created in.
    +-  */
    +-  iDb = sqlite3TwoPartName(pParse, pName1, pName2, &pName);
    +-  if( iDb<0 ) return;
    +-  if( !OMIT_TEMPDB && isTemp && pName2->n>0 && iDb!=1 ){
    +-    /* If creating a temp table, the name may not be qualified. Unless 
    +-    ** the database name is "temp" anyway.  */
    +-    sqlite3ErrorMsg(pParse, "temporary table name must be unqualified");
    +-    return;
    ++  if( db->init.busy && db->init.newTnum==1 ){
    ++    /* Special case:  Parsing the sqlite_master or sqlite_temp_master schema */
    ++    iDb = db->init.iDb;
    ++    zName = sqlite3DbStrDup(db, SCHEMA_TABLE(iDb));
    ++    pName = pName1;
    ++  }else{
    ++    /* The common case */
    ++    iDb = sqlite3TwoPartName(pParse, pName1, pName2, &pName);
    ++    if( iDb<0 ) return;
    ++    if( !OMIT_TEMPDB && isTemp && pName2->n>0 && iDb!=1 ){
    ++      /* If creating a temp table, the name may not be qualified. Unless 
    ++      ** the database name is "temp" anyway.  */
    ++      sqlite3ErrorMsg(pParse, "temporary table name must be unqualified");
    ++      return;
    ++    }
    ++    if( !OMIT_TEMPDB && isTemp ) iDb = 1;
    ++    zName = sqlite3NameFromToken(db, pName);
    +   }
    +-  if( !OMIT_TEMPDB && isTemp ) iDb = 1;
    +-
    +   pParse->sNameToken = *pName;
    +-  zName = sqlite3NameFromToken(db, pName);
    +   if( zName==0 ) return;
    +   if( SQLITE_OK!=sqlite3CheckObjectName(pParse, zName) ){
    +     goto begin_table_error;
    +   }
    +   if( db->init.iDb==1 ) isTemp = 1;
    + #ifndef SQLITE_OMIT_AUTHORIZATION
    +-  assert( (isTemp & 1)==isTemp );
    ++  assert( isTemp==0 || isTemp==1 );
    ++  assert( isView==0 || isView==1 );
    +   {
    +-    int code;
    +-    char *zDb = db->aDb[iDb].zName;
    ++    static const u8 aCode[] = {
    ++       SQLITE_CREATE_TABLE,
    ++       SQLITE_CREATE_TEMP_TABLE,
    ++       SQLITE_CREATE_VIEW,
    ++       SQLITE_CREATE_TEMP_VIEW
    ++    };
    ++    char *zDb = db->aDb[iDb].zDbSName;
    +     if( sqlite3AuthCheck(pParse, SQLITE_INSERT, SCHEMA_TABLE(isTemp), 0, zDb) ){
    +       goto begin_table_error;
    +     }
    +-    if( isView ){
    +-      if( !OMIT_TEMPDB && isTemp ){
    +-        code = SQLITE_CREATE_TEMP_VIEW;
    +-      }else{
    +-        code = SQLITE_CREATE_VIEW;
    +-      }
    +-    }else{
    +-      if( !OMIT_TEMPDB && isTemp ){
    +-        code = SQLITE_CREATE_TEMP_TABLE;
    +-      }else{
    +-        code = SQLITE_CREATE_TABLE;
    +-      }
    +-    }
    +-    if( !isVirtual && sqlite3AuthCheck(pParse, code, zName, 0, zDb) ){
    ++    if( !isVirtual && sqlite3AuthCheck(pParse, (int)aCode[isTemp+2*isView],
    ++                                       zName, 0, zDb) ){
    +       goto begin_table_error;
    +     }
    +   }
    +@@ -93694,7 +102529,7 @@ SQLITE_PRIVATE void sqlite3StartTable(
    +   ** collisions.
    +   */
    +   if( !IN_DECLARE_VTAB ){
    +-    char *zDb = db->aDb[iDb].zName;
    ++    char *zDb = db->aDb[iDb].zDbSName;
    +     if( SQLITE_OK!=sqlite3ReadSchema(pParse) ){
    +       goto begin_table_error;
    +     }
    +@@ -93716,16 +102551,20 @@ SQLITE_PRIVATE void sqlite3StartTable(
    + 
    +   pTable = sqlite3DbMallocZero(db, sizeof(Table));
    +   if( pTable==0 ){
    +-    db->mallocFailed = 1;
    +-    pParse->rc = SQLITE_NOMEM;
    ++    assert( db->mallocFailed );
    ++    pParse->rc = SQLITE_NOMEM_BKPT;
    +     pParse->nErr++;
    +     goto begin_table_error;
    +   }
    +   pTable->zName = zName;
    +   pTable->iPKey = -1;
    +   pTable->pSchema = db->aDb[iDb].pSchema;
    +-  pTable->nRef = 1;
    ++  pTable->nTabRef = 1;
    ++#ifdef SQLITE_DEFAULT_ROWEST
    ++  pTable->nRowLogEst = sqlite3LogEst(SQLITE_DEFAULT_ROWEST);
    ++#else
    +   pTable->nRowLogEst = 200; assert( 200==sqlite3LogEst(1048576) );
    ++#endif
    +   assert( pParse->pNewTable==0 );
    +   pParse->pNewTable = pTable;
    + 
    +@@ -93773,10 +102612,8 @@ SQLITE_PRIVATE void sqlite3StartTable(
    +     addr1 = sqlite3VdbeAddOp1(v, OP_If, reg3); VdbeCoverage(v);
    +     fileFormat = (db->flags & SQLITE_LegacyFileFmt)!=0 ?
    +                   1 : SQLITE_MAX_FILE_FORMAT;
    +-    sqlite3VdbeAddOp2(v, OP_Integer, fileFormat, reg3);
    +-    sqlite3VdbeAddOp3(v, OP_SetCookie, iDb, BTREE_FILE_FORMAT, reg3);
    +-    sqlite3VdbeAddOp2(v, OP_Integer, ENC(db), reg3);
    +-    sqlite3VdbeAddOp3(v, OP_SetCookie, iDb, BTREE_TEXT_ENCODING, reg3);
    ++    sqlite3VdbeAddOp3(v, OP_SetCookie, iDb, BTREE_FILE_FORMAT, fileFormat);
    ++    sqlite3VdbeAddOp3(v, OP_SetCookie, iDb, BTREE_TEXT_ENCODING, ENC(db));
    +     sqlite3VdbeJumpHere(v, addr1);
    + 
    +     /* This just creates a place-holder record in the sqlite_master table.
    +@@ -93794,7 +102631,8 @@ SQLITE_PRIVATE void sqlite3StartTable(
    +     }else
    + #endif
    +     {
    +-      pParse->addrCrTab = sqlite3VdbeAddOp2(v, OP_CreateTable, iDb, reg2);
    ++      pParse->addrCrTab =
    ++         sqlite3VdbeAddOp3(v, OP_CreateBtree, iDb, reg2, BTREE_INTKEY);
    +     }
    +     sqlite3OpenMasterTable(pParse, iDb);
    +     sqlite3VdbeAddOp2(v, OP_NewRowid, 0, reg1);
    +@@ -93813,18 +102651,19 @@ begin_table_error:
    +   return;
    + }
    + 
    +-/*
    +-** This macro is used to compare two strings in a case-insensitive manner.
    +-** It is slightly faster than calling sqlite3StrICmp() directly, but
    +-** produces larger code.
    +-**
    +-** WARNING: This macro is not compatible with the strcmp() family. It
    +-** returns true if the two strings are equal, otherwise false.
    ++/* Set properties of a table column based on the (magical)
    ++** name of the column.
    + */
    +-#define STRICMP(x, y) (\
    +-sqlite3UpperToLower[*(unsigned char *)(x)]==   \
    +-sqlite3UpperToLower[*(unsigned char *)(y)]     \
    +-&& sqlite3StrICmp((x)+1,(y)+1)==0 )
    ++#if SQLITE_ENABLE_HIDDEN_COLUMNS
    ++SQLITE_PRIVATE void sqlite3ColumnPropertiesFromName(Table *pTab, Column *pCol){
    ++  if( sqlite3_strnicmp(pCol->zName, "__hidden__", 10)==0 ){
    ++    pCol->colFlags |= COLFLAG_HIDDEN;
    ++  }else if( pTab && pCol!=pTab->aCol && (pCol[-1].colFlags & COLFLAG_HIDDEN) ){
    ++    pTab->tabFlags |= TF_OOOHidden;
    ++  }
    ++}
    ++#endif
    ++
    + 
    + /*
    + ** Add a new column to the table currently being constructed.
    +@@ -93834,23 +102673,25 @@ sqlite3UpperToLower[*(unsigned char *)(y)]     \
    + ** first to get things going.  Then this routine is called for each
    + ** column.
    + */
    +-SQLITE_PRIVATE void sqlite3AddColumn(Parse *pParse, Token *pName){
    ++SQLITE_PRIVATE void sqlite3AddColumn(Parse *pParse, Token *pName, Token *pType){
    +   Table *p;
    +   int i;
    +   char *z;
    ++  char *zType;
    +   Column *pCol;
    +   sqlite3 *db = pParse->db;
    +   if( (p = pParse->pNewTable)==0 ) return;
    +-#if SQLITE_MAX_COLUMN
    +   if( p->nCol+1>db->aLimit[SQLITE_LIMIT_COLUMN] ){
    +     sqlite3ErrorMsg(pParse, "too many columns on %s", p->zName);
    +     return;
    +   }
    +-#endif
    +-  z = sqlite3NameFromToken(db, pName);
    ++  z = sqlite3DbMallocRaw(db, pName->n + pType->n + 2);
    +   if( z==0 ) return;
    ++  memcpy(z, pName->z, pName->n);
    ++  z[pName->n] = 0;
    ++  sqlite3Dequote(z);
    +   for(i=0; i<p->nCol; i++){
    +-    if( STRICMP(z, p->aCol[i].zName) ){
    ++    if( sqlite3_stricmp(z, p->aCol[i].zName)==0 ){
    +       sqlite3ErrorMsg(pParse, "duplicate column name: %s", z);
    +       sqlite3DbFree(db, z);
    +       return;
    +@@ -93868,14 +102709,23 @@ SQLITE_PRIVATE void sqlite3AddColumn(Parse *pParse, Token *pName){
    +   pCol = &p->aCol[p->nCol];
    +   memset(pCol, 0, sizeof(p->aCol[0]));
    +   pCol->zName = z;
    ++  sqlite3ColumnPropertiesFromName(p, pCol);
    +  
    +-  /* If there is no type specified, columns have the default affinity
    +-  ** 'BLOB'. If there is a type specified, then sqlite3AddColumnType() will
    +-  ** be called next to set pCol->affinity correctly.
    +-  */
    +-  pCol->affinity = SQLITE_AFF_BLOB;
    +-  pCol->szEst = 1;
    ++  if( pType->n==0 ){
    ++    /* If there is no type specified, columns have the default affinity
    ++    ** 'BLOB'. */
    ++    pCol->affinity = SQLITE_AFF_BLOB;
    ++    pCol->szEst = 1;
    ++  }else{
    ++    zType = z + sqlite3Strlen30(z) + 1;
    ++    memcpy(zType, pType->z, pType->n);
    ++    zType[pType->n] = 0;
    ++    sqlite3Dequote(zType);
    ++    pCol->affinity = sqlite3AffinityType(zType, &pCol->szEst);
    ++    pCol->colFlags |= COLFLAG_HASTYPE;
    ++  }
    +   p->nCol++;
    ++  pParse->constraintName.n = 0;
    + }
    + 
    + /*
    +@@ -93889,6 +102739,7 @@ SQLITE_PRIVATE void sqlite3AddNotNull(Parse *pParse, int onError){
    +   p = pParse->pNewTable;
    +   if( p==0 || NEVER(p->nCol<1) ) return;
    +   p->aCol[p->nCol-1].notNull = (u8)onError;
    ++  p->tabFlags |= TF_HasNotNull;
    + }
    + 
    + /*
    +@@ -93921,7 +102772,7 @@ SQLITE_PRIVATE char sqlite3AffinityType(const char *zIn, u8 *pszEst){
    +   char aff = SQLITE_AFF_NUMERIC;
    +   const char *zChar = 0;
    + 
    +-  if( zIn==0 ) return aff;
    ++  assert( zIn!=0 );
    +   while( zIn[0] ){
    +     h = (h<<8) + sqlite3UpperToLower[(*zIn)&0xff];
    +     zIn++;
    +@@ -93978,28 +102829,6 @@ SQLITE_PRIVATE char sqlite3AffinityType(const char *zIn, u8 *pszEst){
    +   return aff;
    + }
    + 
    +-/*
    +-** This routine is called by the parser while in the middle of
    +-** parsing a CREATE TABLE statement.  The pFirst token is the first
    +-** token in the sequence of tokens that describe the type of the
    +-** column currently under construction.   pLast is the last token
    +-** in the sequence.  Use this information to construct a string
    +-** that contains the typename of the column and store that string
    +-** in zType.
    +-*/ 
    +-SQLITE_PRIVATE void sqlite3AddColumnType(Parse *pParse, Token *pType){
    +-  Table *p;
    +-  Column *pCol;
    +-
    +-  p = pParse->pNewTable;
    +-  if( p==0 || NEVER(p->nCol<1) ) return;
    +-  pCol = &p->aCol[p->nCol-1];
    +-  assert( pCol->zType==0 || CORRUPT_DB );
    +-  sqlite3DbFree(pParse->db, pCol->zType);
    +-  pCol->zType = sqlite3NameFromToken(pParse->db, pType);
    +-  pCol->affinity = sqlite3AffinityType(pCol->zType, &pCol->szEst);
    +-}
    +-
    + /*
    + ** The expression is the default value for the most recently added column
    + ** of the table currently under construction.
    +@@ -94010,29 +102839,37 @@ SQLITE_PRIVATE void sqlite3AddColumnType(Parse *pParse, Token *pType){
    + ** This routine is called by the parser while in the middle of
    + ** parsing a CREATE TABLE statement.
    + */
    +-SQLITE_PRIVATE void sqlite3AddDefaultValue(Parse *pParse, ExprSpan *pSpan){
    ++SQLITE_PRIVATE void sqlite3AddDefaultValue(
    ++  Parse *pParse,           /* Parsing context */
    ++  Expr *pExpr,             /* The parsed expression of the default value */
    ++  const char *zStart,      /* Start of the default value text */
    ++  const char *zEnd         /* First character past end of defaut value text */
    ++){
    +   Table *p;
    +   Column *pCol;
    +   sqlite3 *db = pParse->db;
    +   p = pParse->pNewTable;
    +   if( p!=0 ){
    +     pCol = &(p->aCol[p->nCol-1]);
    +-    if( !sqlite3ExprIsConstantOrFunction(pSpan->pExpr, db->init.busy) ){
    ++    if( !sqlite3ExprIsConstantOrFunction(pExpr, db->init.busy) ){
    +       sqlite3ErrorMsg(pParse, "default value of column [%s] is not constant",
    +           pCol->zName);
    +     }else{
    +       /* A copy of pExpr is used instead of the original, as pExpr contains
    +-      ** tokens that point to volatile memory. The 'span' of the expression
    +-      ** is required by pragma table_info.
    ++      ** tokens that point to volatile memory.	
    +       */
    ++      Expr x;
    +       sqlite3ExprDelete(db, pCol->pDflt);
    +-      pCol->pDflt = sqlite3ExprDup(db, pSpan->pExpr, EXPRDUP_REDUCE);
    +-      sqlite3DbFree(db, pCol->zDflt);
    +-      pCol->zDflt = sqlite3DbStrNDup(db, (char*)pSpan->zStart,
    +-                                     (int)(pSpan->zEnd - pSpan->zStart));
    ++      memset(&x, 0, sizeof(x));
    ++      x.op = TK_SPAN;
    ++      x.u.zToken = sqlite3DbSpanDup(db, zStart, zEnd);
    ++      x.pLeft = pExpr;
    ++      x.flags = EP_Skip;
    ++      pCol->pDflt = sqlite3ExprDup(db, &x, EXPRDUP_REDUCE);
    ++      sqlite3DbFree(db, x.u.zToken);
    +     }
    +   }
    +-  sqlite3ExprDelete(db, pSpan->pExpr);
    ++  sqlite3ExprDelete(db, pExpr);
    + }
    + 
    + /*
    +@@ -94085,10 +102922,10 @@ SQLITE_PRIVATE void sqlite3AddPrimaryKey(
    +   int sortOrder     /* SQLITE_SO_ASC or SQLITE_SO_DESC */
    + ){
    +   Table *pTab = pParse->pNewTable;
    +-  char *zType = 0;
    ++  Column *pCol = 0;
    +   int iCol = -1, i;
    +   int nTerm;
    +-  if( pTab==0 || IN_DECLARE_VTAB ) goto primary_key_exit;
    ++  if( pTab==0 ) goto primary_key_exit;
    +   if( pTab->tabFlags & TF_HasPrimaryKey ){
    +     sqlite3ErrorMsg(pParse, 
    +       "table \"%s\" has more than one primary key", pTab->zName);
    +@@ -94097,8 +102934,8 @@ SQLITE_PRIVATE void sqlite3AddPrimaryKey(
    +   pTab->tabFlags |= TF_HasPrimaryKey;
    +   if( pList==0 ){
    +     iCol = pTab->nCol - 1;
    +-    pTab->aCol[iCol].colFlags |= COLFLAG_PRIMKEY;
    +-    zType = pTab->aCol[iCol].zType;
    ++    pCol = &pTab->aCol[iCol];
    ++    pCol->colFlags |= COLFLAG_PRIMKEY;
    +     nTerm = 1;
    +   }else{
    +     nTerm = pList->nExpr;
    +@@ -94110,8 +102947,8 @@ SQLITE_PRIVATE void sqlite3AddPrimaryKey(
    +         const char *zCName = pCExpr->u.zToken;
    +         for(iCol=0; iCol<pTab->nCol; iCol++){
    +           if( sqlite3StrICmp(zCName, pTab->aCol[iCol].zName)==0 ){
    +-            pTab->aCol[iCol].colFlags |= COLFLAG_PRIMKEY;
    +-            zType = pTab->aCol[iCol].zType;
    ++            pCol = &pTab->aCol[iCol];
    ++            pCol->colFlags |= COLFLAG_PRIMKEY;
    +             break;
    +           }
    +         }
    +@@ -94119,7 +102956,8 @@ SQLITE_PRIVATE void sqlite3AddPrimaryKey(
    +     }
    +   }
    +   if( nTerm==1
    +-   && zType && sqlite3StrICmp(zType, "INTEGER")==0
    ++   && pCol
    ++   && sqlite3StrICmp(sqlite3ColumnType(pCol,""), "INTEGER")==0
    +    && sortOrder!=SQLITE_SO_DESC
    +   ){
    +     pTab->iPKey = iCol;
    +@@ -94133,12 +102971,8 @@ SQLITE_PRIVATE void sqlite3AddPrimaryKey(
    +        "INTEGER PRIMARY KEY");
    + #endif
    +   }else{
    +-    Index *p;
    +-    p = sqlite3CreateIndex(pParse, 0, 0, 0, pList, onError, 0,
    +-                           0, sortOrder, 0);
    +-    if( p ){
    +-      p->idxType = SQLITE_IDXTYPE_PRIMARYKEY;
    +-    }
    ++    sqlite3CreateIndex(pParse, 0, 0, 0, pList, onError, 0,
    ++                           0, sortOrder, 0, SQLITE_IDXTYPE_PRIMARYKEY);
    +     pList = 0;
    +   }
    + 
    +@@ -94257,15 +103091,16 @@ SQLITE_PRIVATE CollSeq *sqlite3LocateCollSeq(Parse *pParse, const char *zName){
    + ** set back to prior value.  But schema changes are infrequent
    + ** and the probability of hitting the same cookie value is only
    + ** 1 chance in 2^32.  So we're safe enough.
    ++**
    ++** IMPLEMENTATION-OF: R-34230-56049 SQLite automatically increments
    ++** the schema-version whenever the schema changes.
    + */
    + SQLITE_PRIVATE void sqlite3ChangeCookie(Parse *pParse, int iDb){
    +-  int r1 = sqlite3GetTempReg(pParse);
    +   sqlite3 *db = pParse->db;
    +   Vdbe *v = pParse->pVdbe;
    +   assert( sqlite3SchemaMutexHeld(db, iDb, 0) );
    +-  sqlite3VdbeAddOp2(v, OP_Integer, db->aDb[iDb].pSchema->schema_cookie+1, r1);
    +-  sqlite3VdbeAddOp3(v, OP_SetCookie, iDb, BTREE_SCHEMA_VERSION, r1);
    +-  sqlite3ReleaseTempReg(pParse, r1);
    ++  sqlite3VdbeAddOp3(v, OP_SetCookie, iDb, BTREE_SCHEMA_VERSION, 
    ++                    db->aDb[iDb].pSchema->schema_cookie+1);
    + }
    + 
    + /*
    +@@ -94347,7 +103182,7 @@ static char *createTableStmt(sqlite3 *db, Table *p){
    +   n += 35 + 6*p->nCol;
    +   zStmt = sqlite3DbMallocRaw(0, n);
    +   if( zStmt==0 ){
    +-    db->mallocFailed = 1;
    ++    sqlite3OomFault(db);
    +     return 0;
    +   }
    +   sqlite3_snprintf(n, zStmt, "CREATE TABLE ");
    +@@ -94400,9 +103235,9 @@ static int resizeIndexObject(sqlite3 *db, Index *pIdx, int N){
    +   assert( pIdx->isResized==0 );
    +   nByte = (sizeof(char*) + sizeof(i16) + 1)*N;
    +   zExtra = sqlite3DbMallocZero(db, nByte);
    +-  if( zExtra==0 ) return SQLITE_NOMEM;
    ++  if( zExtra==0 ) return SQLITE_NOMEM_BKPT;
    +   memcpy(zExtra, pIdx->azColl, sizeof(char*)*pIdx->nColumn);
    +-  pIdx->azColl = (char**)zExtra;
    ++  pIdx->azColl = (const char**)zExtra;
    +   zExtra += sizeof(char*)*N;
    +   memcpy(zExtra, pIdx->aiColumn, sizeof(i16)*pIdx->nColumn);
    +   pIdx->aiColumn = (i16*)zExtra;
    +@@ -94457,21 +103292,22 @@ static int hasColumn(const i16 *aiCol, int nCol, int x){
    + ** are appropriate for a WITHOUT ROWID table instead of a rowid table.
    + ** Changes include:
    + **
    +-**     (1)  Convert the OP_CreateTable into an OP_CreateIndex.  There is
    +-**          no rowid btree for a WITHOUT ROWID.  Instead, the canonical
    +-**          data storage is a covering index btree.
    +-**     (2)  Bypass the creation of the sqlite_master table entry
    ++**     (1)  Set all columns of the PRIMARY KEY schema object to be NOT NULL.
    ++**     (2)  Convert P3 parameter of the OP_CreateBtree from BTREE_INTKEY 
    ++**          into BTREE_BLOBKEY.
    ++**     (3)  Bypass the creation of the sqlite_master table entry
    + **          for the PRIMARY KEY as the primary key index is now
    + **          identified by the sqlite_master table entry of the table itself.
    +-**     (3)  Set the Index.tnum of the PRIMARY KEY Index object in the
    ++**     (4)  Set the Index.tnum of the PRIMARY KEY Index object in the
    + **          schema to the rootpage from the main table.
    +-**     (4)  Set all columns of the PRIMARY KEY schema object to be NOT NULL.
    + **     (5)  Add all table columns to the PRIMARY KEY Index object
    + **          so that the PRIMARY KEY is a covering index.  The surplus
    +-**          columns are part of KeyInfo.nXField and are not used for
    ++**          columns are part of KeyInfo.nAllField and are not used for
    + **          sorting or lookup or uniqueness checks.
    + **     (6)  Replace the rowid tail on all automatically generated UNIQUE
    + **          indices with the PRIMARY KEY columns.
    ++**
    ++** For virtual tables, only (1) is performed.
    + */
    + static void convertToWithoutRowidTable(Parse *pParse, Table *pTab){
    +   Index *pIdx;
    +@@ -94481,13 +103317,26 @@ static void convertToWithoutRowidTable(Parse *pParse, Table *pTab){
    +   sqlite3 *db = pParse->db;
    +   Vdbe *v = pParse->pVdbe;
    + 
    +-  /* Convert the OP_CreateTable opcode that would normally create the
    +-  ** root-page for the table into an OP_CreateIndex opcode.  The index
    +-  ** created will become the PRIMARY KEY index.
    ++  /* Mark every PRIMARY KEY column as NOT NULL (except for imposter tables)
    ++  */
    ++  if( !db->init.imposterTable ){
    ++    for(i=0; i<pTab->nCol; i++){
    ++      if( (pTab->aCol[i].colFlags & COLFLAG_PRIMKEY)!=0 ){
    ++        pTab->aCol[i].notNull = OE_Abort;
    ++      }
    ++    }
    ++  }
    ++
    ++  /* The remaining transformations only apply to b-tree tables, not to
    ++  ** virtual tables */
    ++  if( IN_DECLARE_VTAB ) return;
    ++
    ++  /* Convert the P3 operand of the OP_CreateBtree opcode from BTREE_INTKEY
    ++  ** into BTREE_BLOBKEY.
    +   */
    +   if( pParse->addrCrTab ){
    +     assert( v );
    +-    sqlite3VdbeChangeOpcode(v, pParse->addrCrTab, OP_CreateIndex);
    ++    sqlite3VdbeChangeP3(v, pParse->addrCrTab, BTREE_BLOBKEY);
    +   }
    + 
    +   /* Locate the PRIMARY KEY index.  Or, if this table was originally
    +@@ -94496,29 +103345,20 @@ static void convertToWithoutRowidTable(Parse *pParse, Table *pTab){
    +   if( pTab->iPKey>=0 ){
    +     ExprList *pList;
    +     Token ipkToken;
    +-    ipkToken.z = pTab->aCol[pTab->iPKey].zName;
    +-    ipkToken.n = sqlite3Strlen30(ipkToken.z);
    ++    sqlite3TokenInit(&ipkToken, pTab->aCol[pTab->iPKey].zName);
    +     pList = sqlite3ExprListAppend(pParse, 0, 
    +                   sqlite3ExprAlloc(db, TK_ID, &ipkToken, 0));
    +     if( pList==0 ) return;
    +     pList->a[0].sortOrder = pParse->iPkSortOrder;
    +     assert( pParse->pNewTable==pTab );
    +-    pPk = sqlite3CreateIndex(pParse, 0, 0, 0, pList, pTab->keyConf, 0, 0, 0, 0);
    +-    if( pPk==0 ) return;
    +-    pPk->idxType = SQLITE_IDXTYPE_PRIMARYKEY;
    ++    sqlite3CreateIndex(pParse, 0, 0, 0, pList, pTab->keyConf, 0, 0, 0, 0,
    ++                       SQLITE_IDXTYPE_PRIMARYKEY);
    ++    if( db->mallocFailed ) return;
    ++    pPk = sqlite3PrimaryKeyIndex(pTab);
    +     pTab->iPKey = -1;
    +   }else{
    +     pPk = sqlite3PrimaryKeyIndex(pTab);
    + 
    +-    /* Bypass the creation of the PRIMARY KEY btree and the sqlite_master
    +-    ** table entry. This is only required if currently generating VDBE
    +-    ** code for a CREATE TABLE (not when parsing one as part of reading
    +-    ** a database schema).  */
    +-    if( v ){
    +-      assert( db->init.busy==0 );
    +-      sqlite3VdbeChangeOpcode(v, pPk->tnum, OP_Goto);
    +-    }
    +-
    +     /*
    +     ** Remove all redundant columns from the PRIMARY KEY.  For example, change
    +     ** "PRIMARY KEY(a,b,a,b,c,b,c,d)" into just "PRIMARY KEY(a,b,c,d)".  Later
    +@@ -94533,17 +103373,18 @@ static void convertToWithoutRowidTable(Parse *pParse, Table *pTab){
    +     }
    +     pPk->nKeyCol = j;
    +   }
    +-  pPk->isCovering = 1;
    +   assert( pPk!=0 );
    ++  pPk->isCovering = 1;
    ++  if( !db->init.imposterTable ) pPk->uniqNotNull = 1;
    +   nPk = pPk->nKeyCol;
    + 
    +-  /* Make sure every column of the PRIMARY KEY is NOT NULL.  (Except,
    +-  ** do not enforce this for imposter tables.) */
    +-  if( !db->init.imposterTable ){
    +-    for(i=0; i<nPk; i++){
    +-      pTab->aCol[pPk->aiColumn[i]].notNull = 1;
    +-    }
    +-    pPk->uniqNotNull = 1;
    ++  /* Bypass the creation of the PRIMARY KEY btree and the sqlite_master
    ++  ** table entry. This is only required if currently generating VDBE
    ++  ** code for a CREATE TABLE (not when parsing one as part of reading
    ++  ** a database schema).  */
    ++  if( v && pPk->tnum>0 ){
    ++    assert( db->init.busy==0 );
    ++    sqlite3VdbeChangeOpcode(v, pPk->tnum, OP_Goto);
    +   }
    + 
    +   /* The root page of the PRIMARY KEY is the table root page */
    +@@ -94583,7 +103424,7 @@ static void convertToWithoutRowidTable(Parse *pParse, Table *pTab){
    +       if( !hasColumn(pPk->aiColumn, j, i) ){
    +         assert( j<pPk->nColumn );
    +         pPk->aiColumn[j] = i;
    +-        pPk->azColl[j] = "BINARY";
    ++        pPk->azColl[j] = sqlite3StrBINARY;
    +         j++;
    +       }
    +     }
    +@@ -94640,9 +103481,13 @@ SQLITE_PRIVATE void sqlite3EndTable(
    +   ** So do not write to the disk again.  Extract the root page number
    +   ** for the table from the db->init.newTnum field.  (The page number
    +   ** should have been put there by the sqliteOpenCb routine.)
    ++  **
    ++  ** If the root page number is 1, that means this is the sqlite_master
    ++  ** table itself.  So mark it read-only.
    +   */
    +   if( db->init.busy ){
    +     p->tnum = db->init.newTnum;
    ++    if( p->tnum==1 ) p->tabFlags |= TF_Readonly;
    +   }
    + 
    +   /* Special processing for WITHOUT ROWID Tables */
    +@@ -94741,10 +103586,6 @@ SQLITE_PRIVATE void sqlite3EndTable(
    +       pParse->nTab = 2;
    +       addrTop = sqlite3VdbeCurrentAddr(v) + 1;
    +       sqlite3VdbeAddOp3(v, OP_InitCoroutine, regYield, 0, addrTop);
    +-      sqlite3SelectDestInit(&dest, SRT_Coroutine, regYield);
    +-      sqlite3Select(pParse, pSelect, &dest);
    +-      sqlite3VdbeAddOp1(v, OP_EndCoroutine, regYield);
    +-      sqlite3VdbeJumpHere(v, addrTop - 1);
    +       if( pParse->nErr ) return;
    +       pSelTab = sqlite3ResultSetOfSelect(pParse, pSelect);
    +       if( pSelTab==0 ) return;
    +@@ -94754,6 +103595,11 @@ SQLITE_PRIVATE void sqlite3EndTable(
    +       pSelTab->nCol = 0;
    +       pSelTab->aCol = 0;
    +       sqlite3DeleteTable(db, pSelTab);
    ++      sqlite3SelectDestInit(&dest, SRT_Coroutine, regYield);
    ++      sqlite3Select(pParse, pSelect, &dest);
    ++      if( pParse->nErr ) return;
    ++      sqlite3VdbeEndCoroutine(v, regYield);
    ++      sqlite3VdbeJumpHere(v, addrTop - 1);
    +       addrInsLoop = sqlite3VdbeAddOp1(v, OP_Yield, dest.iSDParm);
    +       VdbeCoverage(v);
    +       sqlite3VdbeAddOp3(v, OP_MakeRecord, dest.iSdst, dest.nSdst, regRec);
    +@@ -94785,7 +103631,7 @@ SQLITE_PRIVATE void sqlite3EndTable(
    +       "UPDATE %Q.%s "
    +          "SET type='%s', name=%Q, tbl_name=%Q, rootpage=#%d, sql=%Q "
    +        "WHERE rowid=#%d",
    +-      db->aDb[iDb].zName, SCHEMA_TABLE(iDb),
    ++      db->aDb[iDb].zDbSName, MASTER_NAME,
    +       zType,
    +       p->zName,
    +       p->zName,
    +@@ -94800,13 +103646,13 @@ SQLITE_PRIVATE void sqlite3EndTable(
    +     /* Check to see if we need to create an sqlite_sequence table for
    +     ** keeping track of autoincrement keys.
    +     */
    +-    if( p->tabFlags & TF_Autoincrement ){
    ++    if( (p->tabFlags & TF_Autoincrement)!=0 ){
    +       Db *pDb = &db->aDb[iDb];
    +       assert( sqlite3SchemaMutexHeld(db, iDb, 0) );
    +       if( pDb->pSchema->pSeqTab==0 ){
    +         sqlite3NestedParse(pParse,
    +           "CREATE TABLE %Q.sqlite_sequence(name,seq)",
    +-          pDb->zName
    ++          pDb->zDbSName
    +         );
    +       }
    +     }
    +@@ -94827,11 +103673,11 @@ SQLITE_PRIVATE void sqlite3EndTable(
    +     pOld = sqlite3HashInsert(&pSchema->tblHash, p->zName, p);
    +     if( pOld ){
    +       assert( p==pOld );  /* Malloc must have failed inside HashInsert() */
    +-      db->mallocFailed = 1;
    ++      sqlite3OomFault(db);
    +       return;
    +     }
    +     pParse->pNewTable = 0;
    +-    db->flags |= SQLITE_InternChanges;
    ++    db->mDbFlags |= DBFLAG_SchemaChange;
    + 
    + #ifndef SQLITE_OMIT_ALTERTABLE
    +     if( !p->pSelect ){
    +@@ -94896,7 +103742,7 @@ SQLITE_PRIVATE void sqlite3CreateView(
    +   ** the end.
    +   */
    +   sEnd = pParse->sLastToken;
    +-  assert( sEnd.z[0]!=0 );
    ++  assert( sEnd.z[0]!=0 || sEnd.n==0 );
    +   if( sEnd.z[0]!=';' ){
    +     sEnd.z += sEnd.n;
    +   }
    +@@ -94930,14 +103776,21 @@ SQLITE_PRIVATE int sqlite3ViewGetColumnNames(Parse *pParse, Table *pTable){
    +   int nErr = 0;     /* Number of errors encountered */
    +   int n;            /* Temporarily holds the number of cursors assigned */
    +   sqlite3 *db = pParse->db;  /* Database connection for malloc errors */
    ++#ifndef SQLITE_OMIT_VIRTUALTABLE	
    ++  int rc;
    ++#endif
    ++#ifndef SQLITE_OMIT_AUTHORIZATION
    +   sqlite3_xauth xAuth;       /* Saved xAuth pointer */
    +-  u8 bEnabledLA;             /* Saved db->lookaside.bEnabled state */
    ++#endif
    + 
    +   assert( pTable );
    + 
    + #ifndef SQLITE_OMIT_VIRTUALTABLE
    +-  if( sqlite3VtabCallConnect(pParse, pTable) ){
    +-    return SQLITE_ERROR;
    ++  db->nSchemaLock++;
    ++  rc = sqlite3VtabCallConnect(pParse, pTable);
    ++  db->nSchemaLock--;
    ++  if( rc ){
    ++    return 1;
    +   }
    +   if( IsVirtual(pTable) ) return 0;
    + #endif
    +@@ -94977,45 +103830,56 @@ SQLITE_PRIVATE int sqlite3ViewGetColumnNames(Parse *pParse, Table *pTable){
    +   ** statement that defines the view.
    +   */
    +   assert( pTable->pSelect );
    +-  bEnabledLA = db->lookaside.bEnabled;
    +-  if( pTable->pCheck ){
    +-    db->lookaside.bEnabled = 0;
    +-    sqlite3ColumnsFromExprList(pParse, pTable->pCheck, 
    +-                               &pTable->nCol, &pTable->aCol);
    +-  }else{
    +-    pSel = sqlite3SelectDup(db, pTable->pSelect, 0);
    +-    if( pSel ){
    +-      n = pParse->nTab;
    +-      sqlite3SrcListAssignCursors(pParse, pSel->pSrc);
    +-      pTable->nCol = -1;
    +-      db->lookaside.bEnabled = 0;
    ++  pSel = sqlite3SelectDup(db, pTable->pSelect, 0);
    ++  if( pSel ){
    ++    n = pParse->nTab;
    ++    sqlite3SrcListAssignCursors(pParse, pSel->pSrc);
    ++    pTable->nCol = -1;
    ++    db->lookaside.bDisable++;
    + #ifndef SQLITE_OMIT_AUTHORIZATION
    +-      xAuth = db->xAuth;
    +-      db->xAuth = 0;
    +-      pSelTab = sqlite3ResultSetOfSelect(pParse, pSel);
    +-      db->xAuth = xAuth;
    ++    xAuth = db->xAuth;
    ++    db->xAuth = 0;
    ++    pSelTab = sqlite3ResultSetOfSelect(pParse, pSel);
    ++    db->xAuth = xAuth;
    + #else
    +-      pSelTab = sqlite3ResultSetOfSelect(pParse, pSel);
    +-#endif
    +-      pParse->nTab = n;
    +-      if( pSelTab ){
    +-        assert( pTable->aCol==0 );
    +-        pTable->nCol = pSelTab->nCol;
    +-        pTable->aCol = pSelTab->aCol;
    +-        pSelTab->nCol = 0;
    +-        pSelTab->aCol = 0;
    +-        sqlite3DeleteTable(db, pSelTab);
    +-        assert( sqlite3SchemaMutexHeld(db, 0, pTable->pSchema) );
    +-      }else{
    +-        pTable->nCol = 0;
    +-        nErr++;
    ++    pSelTab = sqlite3ResultSetOfSelect(pParse, pSel);
    ++#endif
    ++    pParse->nTab = n;
    ++    if( pTable->pCheck ){
    ++      /* CREATE VIEW name(arglist) AS ...
    ++      ** The names of the columns in the table are taken from
    ++      ** arglist which is stored in pTable->pCheck.  The pCheck field
    ++      ** normally holds CHECK constraints on an ordinary table, but for
    ++      ** a VIEW it holds the list of column names.
    ++      */
    ++      sqlite3ColumnsFromExprList(pParse, pTable->pCheck, 
    ++                                 &pTable->nCol, &pTable->aCol);
    ++      if( db->mallocFailed==0 
    ++       && pParse->nErr==0
    ++       && pTable->nCol==pSel->pEList->nExpr
    ++      ){
    ++        sqlite3SelectAddColumnTypeAndCollation(pParse, pTable, pSel);
    +       }
    +-      sqlite3SelectDelete(db, pSel);
    +-    } else {
    ++    }else if( pSelTab ){
    ++      /* CREATE VIEW name AS...  without an argument list.  Construct
    ++      ** the column names from the SELECT statement that defines the view.
    ++      */
    ++      assert( pTable->aCol==0 );
    ++      pTable->nCol = pSelTab->nCol;
    ++      pTable->aCol = pSelTab->aCol;
    ++      pSelTab->nCol = 0;
    ++      pSelTab->aCol = 0;
    ++      assert( sqlite3SchemaMutexHeld(db, 0, pTable->pSchema) );
    ++    }else{
    ++      pTable->nCol = 0;
    +       nErr++;
    +     }
    ++    sqlite3DeleteTable(db, pSelTab);
    ++    sqlite3SelectDelete(db, pSel);
    ++    db->lookaside.bDisable--;
    ++  } else {
    ++    nErr++;
    +   }
    +-  db->lookaside.bEnabled = bEnabledLA;
    +   pTable->pSchema->schemaFlags |= DB_UnresetViews;
    + #endif /* SQLITE_OMIT_VIEW */
    +   return nErr;  
    +@@ -95095,6 +103959,7 @@ SQLITE_PRIVATE void sqlite3RootPageMoved(sqlite3 *db, int iDb, int iFrom, int iT
    + static void destroyRootPage(Parse *pParse, int iTable, int iDb){
    +   Vdbe *v = sqlite3GetVdbe(pParse);
    +   int r1 = sqlite3GetTempReg(pParse);
    ++  assert( iTable>1 );
    +   sqlite3VdbeAddOp3(v, OP_Destroy, iTable, r1, iDb);
    +   sqlite3MayAbort(pParse);
    + #ifndef SQLITE_OMIT_AUTOVACUUM
    +@@ -95109,7 +103974,7 @@ static void destroyRootPage(Parse *pParse, int iTable, int iDb){
    +   */
    +   sqlite3NestedParse(pParse, 
    +      "UPDATE %Q.%s SET rootpage=%d WHERE #%d AND rootpage=#%d",
    +-     pParse->db->aDb[iDb].zName, SCHEMA_TABLE(iDb), iTable, r1, r1);
    ++     pParse->db->aDb[iDb].zDbSName, MASTER_NAME, iTable, r1, r1);
    + #endif
    +   sqlite3ReleaseTempReg(pParse, r1);
    + }
    +@@ -95121,14 +103986,6 @@ static void destroyRootPage(Parse *pParse, int iTable, int iDb){
    + ** is also added (this can happen with an auto-vacuum database).
    + */
    + static void destroyTable(Parse *pParse, Table *pTab){
    +-#ifdef SQLITE_OMIT_AUTOVACUUM
    +-  Index *pIdx;
    +-  int iDb = sqlite3SchemaToIndex(pParse->db, pTab->pSchema);
    +-  destroyRootPage(pParse, pTab->tnum, iDb);
    +-  for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){
    +-    destroyRootPage(pParse, pIdx->tnum, iDb);
    +-  }
    +-#else
    +   /* If the database may be auto-vacuum capable (if SQLITE_OMIT_AUTOVACUUM
    +   ** is not defined), then it is important to call OP_Destroy on the
    +   ** table and index root-pages in order, starting with the numerically 
    +@@ -95171,7 +104028,6 @@ static void destroyTable(Parse *pParse, Table *pTab){
    +       iDestroyed = iLargest;
    +     }
    +   }
    +-#endif
    + }
    + 
    + /*
    +@@ -95185,7 +104041,7 @@ static void sqlite3ClearStatTables(
    +   const char *zName      /* Name of index or table */
    + ){
    +   int i;
    +-  const char *zDbName = pParse->db->aDb[iDb].zName;
    ++  const char *zDbName = pParse->db->aDb[iDb].zDbSName;
    +   for(i=1; i<=4; i++){
    +     char zTab[24];
    +     sqlite3_snprintf(sizeof(zTab),zTab,"sqlite_stat%d",i);
    +@@ -95238,7 +104094,7 @@ SQLITE_PRIVATE void sqlite3CodeDropTable(Parse *pParse, Table *pTab, int iDb, in
    +   if( pTab->tabFlags & TF_Autoincrement ){
    +     sqlite3NestedParse(pParse,
    +       "DELETE FROM %Q.sqlite_sequence WHERE name=%Q",
    +-      pDb->zName, pTab->zName
    ++      pDb->zDbSName, pTab->zName
    +     );
    +   }
    + #endif
    +@@ -95252,7 +104108,7 @@ SQLITE_PRIVATE void sqlite3CodeDropTable(Parse *pParse, Table *pTab, int iDb, in
    +   */
    +   sqlite3NestedParse(pParse, 
    +       "DELETE FROM %Q.%s WHERE tbl_name=%Q and type!='trigger'",
    +-      pDb->zName, SCHEMA_TABLE(iDb), pTab->zName);
    ++      pDb->zDbSName, MASTER_NAME, pTab->zName);
    +   if( !isView && !IsVirtual(pTab) ){
    +     destroyTable(pParse, pTab);
    +   }
    +@@ -95285,6 +104141,7 @@ SQLITE_PRIVATE void sqlite3DropTable(Parse *pParse, SrcList *pName, int isView,
    +   assert( pName->nSrc==1 );
    +   if( sqlite3ReadSchema(pParse) ) goto exit_drop_table;
    +   if( noErr ) db->suppressErr++;
    ++  assert( isView==0 || isView==LOCATE_VIEW );
    +   pTab = sqlite3LocateTableItem(pParse, isView, &pName->a[0]);
    +   if( noErr ) db->suppressErr--;
    + 
    +@@ -95305,7 +104162,7 @@ SQLITE_PRIVATE void sqlite3DropTable(Parse *pParse, SrcList *pName, int isView,
    +   {
    +     int code;
    +     const char *zTab = SCHEMA_TABLE(iDb);
    +-    const char *zDb = db->aDb[iDb].zName;
    ++    const char *zDb = db->aDb[iDb].zDbSName;
    +     const char *zArg2 = 0;
    +     if( sqlite3AuthCheck(pParse, SQLITE_DELETE, zTab, 0, zDb)){
    +       goto exit_drop_table;
    +@@ -95480,7 +104337,7 @@ SQLITE_PRIVATE void sqlite3CreateForeignKey(
    +       pFKey->zTo, (void *)pFKey
    +   );
    +   if( pNextTo==pFKey ){
    +-    db->mallocFailed = 1;
    ++    sqlite3OomFault(db);
    +     goto fk_end;
    +   }
    +   if( pNextTo ){
    +@@ -95546,7 +104403,7 @@ static void sqlite3RefillIndex(Parse *pParse, Index *pIndex, int memRootPage){
    + 
    + #ifndef SQLITE_OMIT_AUTHORIZATION
    +   if( sqlite3AuthCheck(pParse, SQLITE_REINDEX, pIndex->zName, 0,
    +-      db->aDb[iDb].zName ) ){
    ++      db->aDb[iDb].zDbSName ) ){
    +     return;
    +   }
    + #endif
    +@@ -95562,6 +104419,7 @@ static void sqlite3RefillIndex(Parse *pParse, Index *pIndex, int memRootPage){
    +     tnum = pIndex->tnum;
    +   }
    +   pKey = sqlite3KeyInfoOfIndex(pParse, pIndex);
    ++  assert( pKey!=0 || db->mallocFailed || pParse->nErr );
    + 
    +   /* Open the sorter cursor if we are to use one. */
    +   iSorter = pParse->nTab++;
    +@@ -95585,8 +104443,7 @@ static void sqlite3RefillIndex(Parse *pParse, Index *pIndex, int memRootPage){
    +   sqlite3VdbeChangeP5(v, OPFLAG_BULKCSR|((memRootPage>=0)?OPFLAG_P2ISREG:0));
    + 
    +   addr1 = sqlite3VdbeAddOp2(v, OP_SorterSort, iSorter, 0); VdbeCoverage(v);
    +-  assert( pKey!=0 || db->mallocFailed || pParse->nErr );
    +-  if( IsUniqueIndex(pIndex) && pKey!=0 ){
    ++  if( IsUniqueIndex(pIndex) ){
    +     int j2 = sqlite3VdbeCurrentAddr(v) + 3;
    +     sqlite3VdbeGoto(v, j2);
    +     addr2 = sqlite3VdbeCurrentAddr(v);
    +@@ -95597,8 +104454,8 @@ static void sqlite3RefillIndex(Parse *pParse, Index *pIndex, int memRootPage){
    +     addr2 = sqlite3VdbeCurrentAddr(v);
    +   }
    +   sqlite3VdbeAddOp3(v, OP_SorterData, iSorter, regRecord, iIdx);
    +-  sqlite3VdbeAddOp3(v, OP_Last, iIdx, 0, -1);
    +-  sqlite3VdbeAddOp3(v, OP_IdxInsert, iIdx, regRecord, 0);
    ++  sqlite3VdbeAddOp1(v, OP_SeekEnd, iIdx);
    ++  sqlite3VdbeAddOp2(v, OP_IdxInsert, iIdx, regRecord);
    +   sqlite3VdbeChangeP5(v, OPFLAG_USESEEKRESULT);
    +   sqlite3ReleaseTempReg(pParse, regRecord);
    +   sqlite3VdbeAddOp2(v, OP_SorterNext, iSorter, addr2); VdbeCoverage(v);
    +@@ -95633,7 +104490,7 @@ SQLITE_PRIVATE Index *sqlite3AllocateIndexObject(
    +   p = sqlite3DbMallocZero(db, nByte + nExtra);
    +   if( p ){
    +     char *pExtra = ((char*)p)+ROUND8(sizeof(Index));
    +-    p->azColl = (char**)pExtra;       pExtra += ROUND8(sizeof(char*)*nCol);
    ++    p->azColl = (const 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;
    +@@ -95655,12 +104512,8 @@ SQLITE_PRIVATE Index *sqlite3AllocateIndexObject(
    + ** pList is a list of columns to be indexed.  pList will be NULL if this
    + ** is a primary key or unique-constraint on the most recent column added
    + ** to the table currently under construction.  
    +-**
    +-** 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.idxType==SQLITE_IDXTYPE_PRIMARYKEY)
    + */
    +-SQLITE_PRIVATE Index *sqlite3CreateIndex(
    ++SQLITE_PRIVATE void sqlite3CreateIndex(
    +   Parse *pParse,     /* All information about this parse */
    +   Token *pName1,     /* First part of index name. May be NULL */
    +   Token *pName2,     /* Second part of index name. May be NULL */
    +@@ -95670,9 +104523,9 @@ SQLITE_PRIVATE Index *sqlite3CreateIndex(
    +   Token *pStart,     /* The CREATE token that begins this statement */
    +   Expr *pPIWhere,    /* WHERE clause for partial indices */
    +   int sortOrder,     /* Sort order of primary key when pList==NULL */
    +-  int ifNotExist     /* Omit error if index already exists */
    ++  int ifNotExist,    /* Omit error if index already exists */
    ++  u8 idxType         /* The index type */
    + ){
    +-  Index *pRet = 0;     /* Pointer to return */
    +   Table *pTab = 0;     /* Table to be indexed */
    +   Index *pIndex = 0;   /* The index to be created */
    +   char *zName = 0;     /* Name of the index */
    +@@ -95690,7 +104543,10 @@ SQLITE_PRIVATE Index *sqlite3CreateIndex(
    +   char *zExtra = 0;                /* Extra space after the Index object */
    +   Index *pPk = 0;      /* PRIMARY KEY index for WITHOUT ROWID tables */
    + 
    +-  if( db->mallocFailed || IN_DECLARE_VTAB || pParse->nErr>0 ){
    ++  if( db->mallocFailed || pParse->nErr>0 ){
    ++    goto exit_create_index;
    ++  }
    ++  if( IN_DECLARE_VTAB && idxType!=SQLITE_IDXTYPE_PRIMARYKEY ){
    +     goto exit_create_index;
    +   }
    +   if( SQLITE_OK!=sqlite3ReadSchema(pParse) ){
    +@@ -95799,7 +104655,7 @@ SQLITE_PRIVATE Index *sqlite3CreateIndex(
    +         goto exit_create_index;
    +       }
    +     }
    +-    if( sqlite3FindIndex(db, zName, pDb->zName)!=0 ){
    ++    if( sqlite3FindIndex(db, zName, pDb->zDbSName)!=0 ){
    +       if( !ifNotExist ){
    +         sqlite3ErrorMsg(pParse, "index %s already exists", zName);
    +       }else{
    +@@ -95816,13 +104672,20 @@ SQLITE_PRIVATE Index *sqlite3CreateIndex(
    +     if( zName==0 ){
    +       goto exit_create_index;
    +     }
    ++
    ++    /* Automatic index names generated from within sqlite3_declare_vtab()
    ++    ** must have names that are distinct from normal automatic index names.
    ++    ** The following statement converts "sqlite3_autoindex..." into
    ++    ** "sqlite3_butoindex..." in order to make the names distinct.
    ++    ** The "vtab_err.test" test demonstrates the need of this statement. */
    ++    if( IN_DECLARE_VTAB ) zName[7]++;
    +   }
    + 
    +   /* Check for authorization to create an index.
    +   */
    + #ifndef SQLITE_OMIT_AUTHORIZATION
    +   {
    +-    const char *zDb = pDb->zName;
    ++    const char *zDb = pDb->zDbSName;
    +     if( sqlite3AuthCheck(pParse, SQLITE_INSERT, SCHEMA_TABLE(iDb), 0, zDb) ){
    +       goto exit_create_index;
    +     }
    +@@ -95840,8 +104703,7 @@ SQLITE_PRIVATE Index *sqlite3CreateIndex(
    +   */
    +   if( pList==0 ){
    +     Token prevCol;
    +-    prevCol.z = pTab->aCol[pTab->nCol-1].zName;
    +-    prevCol.n = sqlite3Strlen30(prevCol.z);
    ++    sqlite3TokenInit(&prevCol, pTab->aCol[pTab->nCol-1].zName);
    +     pList = sqlite3ExprListAppend(pParse, 0,
    +               sqlite3ExprAlloc(db, TK_ID, &prevCol, 0));
    +     if( pList==0 ) goto exit_create_index;
    +@@ -95880,7 +104742,7 @@ SQLITE_PRIVATE Index *sqlite3CreateIndex(
    +   pIndex->pTable = pTab;
    +   pIndex->onError = (u8)onError;
    +   pIndex->uniqNotNull = onError!=OE_None;
    +-  pIndex->idxType = pName ? SQLITE_IDXTYPE_APPDEF : SQLITE_IDXTYPE_UNIQUE;
    ++  pIndex->idxType = idxType;
    +   pIndex->pSchema = db->aDb[iDb].pSchema;
    +   pIndex->nKeyCol = pList->nExpr;
    +   if( pPIWhere ){
    +@@ -95910,7 +104772,7 @@ SQLITE_PRIVATE Index *sqlite3CreateIndex(
    +   for(i=0, pListItem=pList->a; i<pList->nExpr; i++, pListItem++){
    +     Expr *pCExpr;                  /* The i-th index expression */
    +     int requestedSortOrder;        /* ASC or DESC on the i-th expression */
    +-    char *zColl;                   /* Collation sequence name */
    ++    const char *zColl;             /* Collation sequence name */
    + 
    +     sqlite3StringToId(pListItem->pExpr);
    +     sqlite3ResolveSelfReference(pParse, pTab, NC_IdxExpr, pListItem->pExpr, 0);
    +@@ -95956,7 +104818,7 @@ SQLITE_PRIVATE Index *sqlite3CreateIndex(
    +     }else if( j>=0 ){
    +       zColl = pTab->aCol[j].zColl;
    +     }
    +-    if( !zColl ) zColl = "BINARY";
    ++    if( !zColl ) zColl = sqlite3StrBINARY;
    +     if( !db->init.busy && !sqlite3LocateCollSeq(pParse, zColl) ){
    +       goto exit_create_index;
    +     }
    +@@ -95985,11 +104847,25 @@ SQLITE_PRIVATE Index *sqlite3CreateIndex(
    +     assert( i==pIndex->nColumn );
    +   }else{
    +     pIndex->aiColumn[i] = XN_ROWID;
    +-    pIndex->azColl[i] = "BINARY";
    ++    pIndex->azColl[i] = sqlite3StrBINARY;
    +   }
    +   sqlite3DefaultRowEst(pIndex);
    +   if( pParse->pNewTable==0 ) estimateIndexWidth(pIndex);
    + 
    ++  /* If this index contains every column of its table, then mark
    ++  ** it as a covering index */
    ++  assert( HasRowid(pTab) 
    ++      || pTab->iPKey<0 || sqlite3ColumnOfIndex(pIndex, pTab->iPKey)>=0 );
    ++  if( pTblName!=0 && pIndex->nColumn>=pTab->nCol ){
    ++    pIndex->isCovering = 1;
    ++    for(j=0; j<pTab->nCol; j++){
    ++      if( j==pTab->iPKey ) continue;
    ++      if( sqlite3ColumnOfIndex(pIndex,j)>=0 ) continue;
    ++      pIndex->isCovering = 0;
    ++      break;
    ++    }
    ++  }
    ++
    +   if( pTab==pParse->pNewTable ){
    +     /* This routine has been called to create an automatic index as a
    +     ** result of a PRIMARY KEY or UNIQUE clause on a column definition, or
    +@@ -96027,7 +104903,7 @@ SQLITE_PRIVATE Index *sqlite3CreateIndex(
    +         if( pIdx->aiColumn[k]!=pIndex->aiColumn[k] ) break;
    +         z1 = pIdx->azColl[k];
    +         z2 = pIndex->azColl[k];
    +-        if( z1!=z2 && sqlite3StrICmp(z1, z2) ) break;
    ++        if( sqlite3StrICmp(z1, z2) ) break;
    +       }
    +       if( k==pIdx->nKeyCol ){
    +         if( pIdx->onError!=pIndex->onError ){
    +@@ -96046,7 +104922,7 @@ SQLITE_PRIVATE Index *sqlite3CreateIndex(
    +             pIdx->onError = pIndex->onError;
    +           }
    +         }
    +-        pRet = pIdx;
    ++        if( idxType==SQLITE_IDXTYPE_PRIMARYKEY ) pIdx->idxType = idxType;
    +         goto exit_create_index;
    +       }
    +     }
    +@@ -96058,15 +104934,16 @@ SQLITE_PRIVATE Index *sqlite3CreateIndex(
    +   assert( pParse->nErr==0 );
    +   if( db->init.busy ){
    +     Index *p;
    ++    assert( !IN_DECLARE_VTAB );
    +     assert( sqlite3SchemaMutexHeld(db, 0, pIndex->pSchema) );
    +     p = sqlite3HashInsert(&pIndex->pSchema->idxHash, 
    +                           pIndex->zName, pIndex);
    +     if( p ){
    +       assert( p==pIndex );  /* Malloc must have failed */
    +-      db->mallocFailed = 1;
    ++      sqlite3OomFault(db);
    +       goto exit_create_index;
    +     }
    +-    db->flags |= SQLITE_InternChanges;
    ++    db->mDbFlags |= DBFLAG_SchemaChange;
    +     if( pTblName!=0 ){
    +       pIndex->tnum = db->init.newTnum;
    +     }
    +@@ -96102,7 +104979,7 @@ SQLITE_PRIVATE Index *sqlite3CreateIndex(
    +     ** that case the convertToWithoutRowidTable() routine will replace
    +     ** the Noop with a Goto to jump over the VDBE code generated below. */
    +     pIndex->tnum = sqlite3VdbeAddOp0(v, OP_Noop);
    +-    sqlite3VdbeAddOp2(v, OP_CreateIndex, iDb, iMem);
    ++    sqlite3VdbeAddOp3(v, OP_CreateBtree, iDb, iMem, BTREE_BLOBKEY);
    + 
    +     /* Gather the complete text of the CREATE INDEX statement into
    +     ** the zStmt variable
    +@@ -96123,7 +105000,7 @@ SQLITE_PRIVATE Index *sqlite3CreateIndex(
    +     */
    +     sqlite3NestedParse(pParse, 
    +         "INSERT INTO %Q.%s VALUES('index',%Q,%Q,#%d,%Q);",
    +-        db->aDb[iDb].zName, SCHEMA_TABLE(iDb),
    ++        db->aDb[iDb].zDbSName, MASTER_NAME,
    +         pIndex->zName,
    +         pTab->zName,
    +         iMem,
    +@@ -96139,7 +105016,7 @@ SQLITE_PRIVATE Index *sqlite3CreateIndex(
    +       sqlite3ChangeCookie(pParse, iDb);
    +       sqlite3VdbeAddParseSchemaOp(v, iDb,
    +          sqlite3MPrintf(db, "name='%q' AND type='index'", pIndex->zName));
    +-      sqlite3VdbeAddOp1(v, OP_Expire, 0);
    ++      sqlite3VdbeAddOp0(v, OP_Expire);
    +     }
    + 
    +     sqlite3VdbeJumpHere(v, pIndex->tnum);
    +@@ -96164,7 +105041,6 @@ SQLITE_PRIVATE Index *sqlite3CreateIndex(
    +       pIndex->pNext = pOther->pNext;
    +       pOther->pNext = pIndex;
    +     }
    +-    pRet = pIndex;
    +     pIndex = 0;
    +   }
    + 
    +@@ -96175,7 +105051,6 @@ exit_create_index:
    +   sqlite3ExprListDelete(db, pList);
    +   sqlite3SrcListDelete(db, pTblName);
    +   sqlite3DbFree(db, zName);
    +-  return pRet;
    + }
    + 
    + /*
    +@@ -96203,11 +105078,15 @@ SQLITE_PRIVATE void sqlite3DefaultRowEst(Index *pIdx){
    +   int nCopy = MIN(ArraySize(aVal), pIdx->nKeyCol);
    +   int i;
    + 
    ++  /* Indexes with default row estimates should not have stat1 data */
    ++  assert( !pIdx->hasStat1 );
    ++
    +   /* 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.  */
    ++  ** number of rows in the table, or half the number of rows in the table
    ++  ** for a partial index.   But do not let the estimate drop below 10. */
    +   a[0] = pIdx->pTable->nRowLogEst;
    +-  if( a[0]<33 ) a[0] = 33;        assert( 33==sqlite3LogEst(10) );
    ++  if( pIdx->pPartIdxWhere!=0 ) a[0] -= 10;  assert( 10==sqlite3LogEst(2) );
    ++  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.  */
    +@@ -96258,7 +105137,7 @@ SQLITE_PRIVATE void sqlite3DropIndex(Parse *pParse, SrcList *pName, int ifExists
    +   {
    +     int code = SQLITE_DROP_INDEX;
    +     Table *pTab = pIndex->pTable;
    +-    const char *zDb = db->aDb[iDb].zName;
    ++    const char *zDb = db->aDb[iDb].zDbSName;
    +     const char *zTab = SCHEMA_TABLE(iDb);
    +     if( sqlite3AuthCheck(pParse, SQLITE_DELETE, zTab, 0, zDb) ){
    +       goto exit_drop_index;
    +@@ -96276,7 +105155,7 @@ SQLITE_PRIVATE void sqlite3DropIndex(Parse *pParse, SrcList *pName, int ifExists
    +     sqlite3BeginWriteOperation(pParse, 1, iDb);
    +     sqlite3NestedParse(pParse,
    +        "DELETE FROM %Q.%s WHERE name=%Q AND type='index'",
    +-       db->aDb[iDb].zName, SCHEMA_TABLE(iDb), pIndex->zName
    ++       db->aDb[iDb].zDbSName, MASTER_NAME, pIndex->zName
    +     );
    +     sqlite3ClearStatTables(pParse, iDb, "idx", pIndex->zName);
    +     sqlite3ChangeCookie(pParse, iDb);
    +@@ -96367,7 +105246,7 @@ SQLITE_PRIVATE void sqlite3IdListDelete(sqlite3 *db, IdList *pList){
    +     sqlite3DbFree(db, pList->a[i].zName);
    +   }
    +   sqlite3DbFree(db, pList->a);
    +-  sqlite3DbFree(db, pList);
    ++  sqlite3DbFreeNN(db, pList);
    + }
    + 
    + /*
    +@@ -96419,7 +105298,7 @@ SQLITE_PRIVATE SrcList *sqlite3SrcListEnlarge(
    +   /* Allocate additional space if needed */
    +   if( (u32)pSrc->nSrc+nExtra>pSrc->nAlloc ){
    +     SrcList *pNew;
    +-    int nAlloc = pSrc->nSrc+nExtra;
    ++    int nAlloc = pSrc->nSrc*2+nExtra;
    +     int nGot;
    +     pNew = sqlite3DbRealloc(db, pSrc,
    +                sizeof(*pSrc) + (nAlloc-1)*sizeof(pSrc->a[0]) );
    +@@ -96492,12 +105371,17 @@ SQLITE_PRIVATE SrcList *sqlite3SrcListAppend(
    + ){
    +   struct SrcList_item *pItem;
    +   assert( pDatabase==0 || pTable!=0 );  /* Cannot have C without B */
    ++  assert( db!=0 );
    +   if( pList==0 ){
    +-    pList = sqlite3DbMallocZero(db, sizeof(SrcList) );
    ++    pList = sqlite3DbMallocRawNN(db, sizeof(SrcList) );
    +     if( pList==0 ) return 0;
    +     pList->nAlloc = 1;
    ++    pList->nSrc = 1;
    ++    memset(&pList->a[0], 0, sizeof(pList->a[0]));
    ++    pList->a[0].iCursor = -1;
    ++  }else{
    ++    pList = sqlite3SrcListEnlarge(db, pList, 1, pList->nSrc);
    +   }
    +-  pList = sqlite3SrcListEnlarge(db, pList, 1, pList->nSrc);
    +   if( db->mallocFailed ){
    +     sqlite3SrcListDelete(db, pList);
    +     return 0;
    +@@ -96507,12 +105391,12 @@ SQLITE_PRIVATE SrcList *sqlite3SrcListAppend(
    +     pDatabase = 0;
    +   }
    +   if( pDatabase ){
    +-    Token *pTemp = pDatabase;
    +-    pDatabase = pTable;
    +-    pTable = pTemp;
    ++    pItem->zName = sqlite3NameFromToken(db, pDatabase);
    ++    pItem->zDatabase = sqlite3NameFromToken(db, pTable);
    ++  }else{
    ++    pItem->zName = sqlite3NameFromToken(db, pTable);
    ++    pItem->zDatabase = 0;
    +   }
    +-  pItem->zName = sqlite3NameFromToken(db, pTable);
    +-  pItem->zDatabase = sqlite3NameFromToken(db, pDatabase);
    +   return pList;
    + }
    + 
    +@@ -96552,7 +105436,7 @@ SQLITE_PRIVATE void sqlite3SrcListDelete(sqlite3 *db, SrcList *pList){
    +     sqlite3ExprDelete(db, pItem->pOn);
    +     sqlite3IdListDelete(db, pItem->pUsing);
    +   }
    +-  sqlite3DbFree(db, pList);
    ++  sqlite3DbFreeNN(db, pList);
    + }
    + 
    + /*
    +@@ -96590,9 +105474,10 @@ SQLITE_PRIVATE SrcList *sqlite3SrcListAppendFromTerm(
    +     goto append_from_error;
    +   }
    +   p = sqlite3SrcListAppend(db, p, pTable, pDatabase);
    +-  if( p==0 || NEVER(p->nSrc==0) ){
    ++  if( p==0 ){
    +     goto append_from_error;
    +   }
    ++  assert( p->nSrc>0 );
    +   pItem = &p->a[p->nSrc-1];
    +   assert( pAlias!=0 );
    +   if( pAlias->n ){
    +@@ -96617,8 +105502,10 @@ SQLITE_PRIVATE SrcList *sqlite3SrcListAppendFromTerm(
    + */
    + SQLITE_PRIVATE void sqlite3SrcListIndexedBy(Parse *pParse, SrcList *p, Token *pIndexedBy){
    +   assert( pIndexedBy!=0 );
    +-  if( p && ALWAYS(p->nSrc>0) ){
    +-    struct SrcList_item *pItem = &p->a[p->nSrc-1];
    ++  if( p && pIndexedBy->n>0 ){
    ++    struct SrcList_item *pItem;
    ++    assert( p->nSrc>0 );
    ++    pItem = &p->a[p->nSrc-1];
    +     assert( pItem->fg.notIndexed==0 );
    +     assert( pItem->fg.isIndexedBy==0 );
    +     assert( pItem->fg.isTabFunc==0 );
    +@@ -96628,7 +105515,7 @@ SQLITE_PRIVATE void sqlite3SrcListIndexedBy(Parse *pParse, SrcList *p, Token *pI
    +       pItem->fg.notIndexed = 1;
    +     }else{
    +       pItem->u1.zIndexedBy = sqlite3NameFromToken(pParse->db, pIndexedBy);
    +-      pItem->fg.isIndexedBy = (pItem->u1.zIndexedBy!=0);
    ++      pItem->fg.isIndexedBy = 1;
    +     }
    +   }
    + }
    +@@ -96638,7 +105525,7 @@ SQLITE_PRIVATE void sqlite3SrcListIndexedBy(Parse *pParse, SrcList *p, Token *pI
    + ** table-valued-function.
    + */
    + SQLITE_PRIVATE void sqlite3SrcListFuncArgs(Parse *pParse, SrcList *p, ExprList *pList){
    +-  if( p && pList ){
    ++  if( p ){
    +     struct SrcList_item *pItem = &p->a[p->nSrc-1];
    +     assert( pItem->fg.notIndexed==0 );
    +     assert( pItem->fg.isIndexedBy==0 );
    +@@ -96676,7 +105563,7 @@ SQLITE_PRIVATE void sqlite3SrcListShiftJoinType(SrcList *p){
    + }
    + 
    + /*
    +-** Begin a transaction
    ++** Generate VDBE code for a BEGIN statement.
    + */
    + SQLITE_PRIVATE void sqlite3BeginTransaction(Parse *pParse, int type){
    +   sqlite3 *db;
    +@@ -96686,7 +105573,6 @@ SQLITE_PRIVATE void sqlite3BeginTransaction(Parse *pParse, int type){
    +   assert( pParse!=0 );
    +   db = pParse->db;
    +   assert( db!=0 );
    +-/*  if( db->aDb[0].pBt==0 ) return; */
    +   if( sqlite3AuthCheck(pParse, SQLITE_TRANSACTION, "BEGIN", 0, 0) ){
    +     return;
    +   }
    +@@ -96698,40 +105584,29 @@ SQLITE_PRIVATE void sqlite3BeginTransaction(Parse *pParse, int type){
    +       sqlite3VdbeUsesBtree(v, i);
    +     }
    +   }
    +-  sqlite3VdbeAddOp2(v, OP_AutoCommit, 0, 0);
    +-}
    +-
    +-/*
    +-** Commit a transaction
    +-*/
    +-SQLITE_PRIVATE void sqlite3CommitTransaction(Parse *pParse){
    +-  Vdbe *v;
    +-
    +-  assert( pParse!=0 );
    +-  assert( pParse->db!=0 );
    +-  if( sqlite3AuthCheck(pParse, SQLITE_TRANSACTION, "COMMIT", 0, 0) ){
    +-    return;
    +-  }
    +-  v = sqlite3GetVdbe(pParse);
    +-  if( v ){
    +-    sqlite3VdbeAddOp2(v, OP_AutoCommit, 1, 0);
    +-  }
    ++  sqlite3VdbeAddOp0(v, OP_AutoCommit);
    + }
    + 
    + /*
    +-** Rollback a transaction
    ++** Generate VDBE code for a COMMIT or ROLLBACK statement.
    ++** Code for ROLLBACK is generated if eType==TK_ROLLBACK.  Otherwise
    ++** code is generated for a COMMIT.
    + */
    +-SQLITE_PRIVATE void sqlite3RollbackTransaction(Parse *pParse){
    ++SQLITE_PRIVATE void sqlite3EndTransaction(Parse *pParse, int eType){
    +   Vdbe *v;
    ++  int isRollback;
    + 
    +   assert( pParse!=0 );
    +   assert( pParse->db!=0 );
    +-  if( sqlite3AuthCheck(pParse, SQLITE_TRANSACTION, "ROLLBACK", 0, 0) ){
    ++  assert( eType==TK_COMMIT || eType==TK_END || eType==TK_ROLLBACK );
    ++  isRollback = eType==TK_ROLLBACK;
    ++  if( sqlite3AuthCheck(pParse, SQLITE_TRANSACTION, 
    ++       isRollback ? "ROLLBACK" : "COMMIT", 0, 0) ){
    +     return;
    +   }
    +   v = sqlite3GetVdbe(pParse);
    +   if( v ){
    +-    sqlite3VdbeAddOp2(v, OP_AutoCommit, 1, 1);
    ++    sqlite3VdbeAddOp2(v, OP_AutoCommit, 1, isRollback);
    +   }
    + }
    + 
    +@@ -96781,7 +105656,7 @@ SQLITE_PRIVATE int sqlite3OpenTempDatabase(Parse *pParse){
    +     db->aDb[1].pBt = pBt;
    +     assert( db->aDb[1].pSchema );
    +     if( SQLITE_NOMEM==sqlite3BtreeSetPageSize(pBt, db->nextPagesize, -1, 0) ){
    +-      db->mallocFailed = 1;
    ++      sqlite3OomFault(db);
    +       return 1;
    +     }
    +   }
    +@@ -96796,15 +105671,13 @@ SQLITE_PRIVATE int sqlite3OpenTempDatabase(Parse *pParse){
    + */
    + SQLITE_PRIVATE void sqlite3CodeVerifySchema(Parse *pParse, int iDb){
    +   Parse *pToplevel = sqlite3ParseToplevel(pParse);
    +-  sqlite3 *db = pToplevel->db;
    + 
    +-  assert( iDb>=0 && iDb<db->nDb );
    +-  assert( db->aDb[iDb].pBt!=0 || iDb==1 );
    ++  assert( iDb>=0 && iDb<pParse->db->nDb );
    ++  assert( pParse->db->aDb[iDb].pBt!=0 || iDb==1 );
    +   assert( iDb<SQLITE_MAX_ATTACHED+2 );
    +-  assert( sqlite3SchemaMutexHeld(db, iDb, 0) );
    ++  assert( sqlite3SchemaMutexHeld(pParse->db, iDb, 0) );
    +   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);
    +     }
    +@@ -96820,7 +105693,7 @@ SQLITE_PRIVATE void sqlite3CodeVerifyNamedSchema(Parse *pParse, const char *zDb)
    +   int i;
    +   for(i=0; i<db->nDb; i++){
    +     Db *pDb = &db->aDb[i];
    +-    if( pDb->pBt && (!zDb || 0==sqlite3StrICmp(zDb, pDb->zName)) ){
    ++    if( pDb->pBt && (!zDb || 0==sqlite3StrICmp(zDb, pDb->zDbSName)) ){
    +       sqlite3CodeVerifySchema(pParse, i);
    +     }
    +   }
    +@@ -96898,7 +105771,7 @@ SQLITE_PRIVATE void sqlite3HaltConstraint(
    +     sqlite3MayAbort(pParse);
    +   }
    +   sqlite3VdbeAddOp4(v, OP_Halt, errCode, onError, 0, p4, p4type);
    +-  if( p5Errmsg ) sqlite3VdbeChangeP5(v, p5Errmsg);
    ++  sqlite3VdbeChangeP5(v, p5Errmsg);
    + }
    + 
    + /*
    +@@ -96916,14 +105789,16 @@ SQLITE_PRIVATE void sqlite3UniqueConstraint(
    + 
    +   sqlite3StrAccumInit(&errMsg, pParse->db, 0, 0, 200);
    +   if( pIdx->aColExpr ){
    +-    sqlite3XPrintf(&errMsg, 0, "index '%q'", pIdx->zName);
    ++    sqlite3XPrintf(&errMsg, "index '%q'", pIdx->zName);
    +   }else{
    +     for(j=0; j<pIdx->nKeyCol; j++){
    +       char *zCol;
    +       assert( pIdx->aiColumn[j]>=0 );
    +       zCol = pTab->aCol[pIdx->aiColumn[j]].zName;
    +       if( j ) sqlite3StrAccumAppend(&errMsg, ", ", 2);
    +-      sqlite3XPrintf(&errMsg, 0, "%s.%s", pTab->zName, zCol);
    ++      sqlite3StrAccumAppendAll(&errMsg, pTab->zName);
    ++      sqlite3StrAccumAppend(&errMsg, ".", 1);
    ++      sqlite3StrAccumAppendAll(&errMsg, zCol);
    +     }
    +   }
    +   zErr = sqlite3StrAccumFinish(&errMsg);
    +@@ -97067,7 +105942,7 @@ SQLITE_PRIVATE void sqlite3Reindex(Parse *pParse, Token *pName1, Token *pName2){
    +   if( iDb<0 ) return;
    +   z = sqlite3NameFromToken(db, pObjName);
    +   if( z==0 ) return;
    +-  zDb = db->aDb[iDb].zName;
    ++  zDb = db->aDb[iDb].zDbSName;
    +   pTab = sqlite3FindTable(db, z, zDb);
    +   if( pTab ){
    +     reindexTable(pParse, pTab, 0);
    +@@ -97088,10 +105963,6 @@ SQLITE_PRIVATE void sqlite3Reindex(Parse *pParse, Token *pName1, Token *pName2){
    + /*
    + ** Return a KeyInfo structure that is appropriate for the given Index.
    + **
    +-** The KeyInfo structure for an index is cached in the Index object.
    +-** So there might be multiple references to the returned pointer.  The
    +-** caller should not try to modify the KeyInfo object.
    +-**
    + ** The caller should invoke sqlite3KeyInfoUnref() on the returned object
    + ** when it has finished using it.
    + */
    +@@ -97109,13 +105980,24 @@ SQLITE_PRIVATE KeyInfo *sqlite3KeyInfoOfIndex(Parse *pParse, Index *pIdx){
    +   if( pKey ){
    +     assert( sqlite3KeyInfoIsWriteable(pKey) );
    +     for(i=0; i<nCol; i++){
    +-      char *zColl = pIdx->azColl[i];
    +-      assert( zColl!=0 );
    +-      pKey->aColl[i] = strcmp(zColl,"BINARY")==0 ? 0 :
    ++      const char *zColl = pIdx->azColl[i];
    ++      pKey->aColl[i] = zColl==sqlite3StrBINARY ? 0 :
    +                         sqlite3LocateCollSeq(pParse, zColl);
    +       pKey->aSortOrder[i] = pIdx->aSortOrder[i];
    +     }
    +     if( pParse->nErr ){
    ++      assert( pParse->rc==SQLITE_ERROR_MISSING_COLLSEQ );
    ++      if( pIdx->bNoQuery==0 ){
    ++        /* Deactivate the index because it contains an unknown collating
    ++        ** sequence.  The only way to reactive the index is to reload the
    ++        ** schema.  Adding the missing collating sequence later does not
    ++        ** reactive the index.  The application had the chance to register
    ++        ** the missing index using the collation-needed callback.  For
    ++        ** simplicity, SQLite will not give the application a second chance.
    ++        */
    ++        pIdx->bNoQuery = 1;
    ++        pParse->rc = SQLITE_ERROR_RETRY;
    ++      }
    +       sqlite3KeyInfoUnref(pKey);
    +       pKey = 0;
    +     }
    +@@ -97157,10 +106039,9 @@ SQLITE_PRIVATE With *sqlite3WithAdd(
    +   }else{
    +     pNew = sqlite3DbMallocZero(db, sizeof(*pWith));
    +   }
    +-  assert( zName!=0 || pNew==0 );
    +-  assert( db->mallocFailed==0 || pNew==0 );
    ++  assert( (pNew!=0 && zName!=0) || db->mallocFailed );
    + 
    +-  if( pNew==0 ){
    ++  if( db->mallocFailed ){
    +     sqlite3ExprListDelete(db, pArglist);
    +     sqlite3SelectDelete(db, pQuery);
    +     sqlite3DbFree(db, zName);
    +@@ -97302,6 +106183,7 @@ SQLITE_PRIVATE CollSeq *sqlite3GetCollSeq(
    +   assert( !p || p->xCmp );
    +   if( p==0 ){
    +     sqlite3ErrorMsg(pParse, "no such collation sequence: %s", zName);
    ++    pParse->rc = SQLITE_ERROR_MISSING_COLLSEQ;
    +   }
    +   return p;
    + }
    +@@ -97318,7 +106200,7 @@ SQLITE_PRIVATE CollSeq *sqlite3GetCollSeq(
    + ** from the main database is substituted, if one is available.
    + */
    + SQLITE_PRIVATE int sqlite3CheckCollSeq(Parse *pParse, CollSeq *pColl){
    +-  if( pColl ){
    ++  if( pColl && pColl->xCmp==0 ){
    +     const char *zName = pColl->zName;
    +     sqlite3 *db = pParse->db;
    +     CollSeq *p = sqlite3GetCollSeq(pParse, ENC(db), pColl, zName);
    +@@ -97354,8 +106236,8 @@ static CollSeq *findCollSeqEntry(
    +   pColl = sqlite3HashFind(&db->aCollSeq, zName);
    + 
    +   if( 0==pColl && create ){
    +-    int nName = sqlite3Strlen30(zName);
    +-    pColl = sqlite3DbMallocZero(db, 3*sizeof(*pColl) + nName + 1);
    ++    int nName = sqlite3Strlen30(zName) + 1;
    ++    pColl = sqlite3DbMallocZero(db, 3*sizeof(*pColl) + nName);
    +     if( pColl ){
    +       CollSeq *pDel = 0;
    +       pColl[0].zName = (char*)&pColl[3];
    +@@ -97365,7 +106247,6 @@ static CollSeq *findCollSeqEntry(
    +       pColl[2].zName = (char*)&pColl[3];
    +       pColl[2].enc = SQLITE_UTF16BE;
    +       memcpy(pColl[0].zName, zName, nName);
    +-      pColl[0].zName[nName] = 0;
    +       pDel = sqlite3HashInsert(&db->aCollSeq, pColl[0].zName, pColl);
    + 
    +       /* If a malloc() failure occurred in sqlite3HashInsert(), it will 
    +@@ -97374,7 +106255,7 @@ static CollSeq *findCollSeqEntry(
    +       */
    +       assert( pDel==0 || pDel==pColl );
    +       if( pDel!=0 ){
    +-        db->mallocFailed = 1;
    ++        sqlite3OomFault(db);
    +         sqlite3DbFree(db, pDel);
    +         pColl = 0;
    +       }
    +@@ -97440,8 +106321,8 @@ SQLITE_PRIVATE CollSeq *sqlite3FindCollSeq(
    + ** 5: UTF16 byte order conversion required - argument count matches exactly
    + ** 6: Perfect match:  encoding and argument count match exactly.
    + **
    +-** If nArg==(-2) then any function with a non-null xStep or xFunc is
    +-** a perfect match and any function with both xStep and xFunc NULL is
    ++** If nArg==(-2) then any function with a non-null xSFunc is
    ++** a perfect match and any function with xSFunc NULL is
    + ** a non-match.
    + */
    + #define FUNC_PERFECT_MATCH 6  /* The score for a perfect match */
    +@@ -97453,7 +106334,7 @@ static int matchQuality(
    +   int match;
    + 
    +   /* nArg of -2 is a special case */
    +-  if( nArg==(-2) ) return (p->xFunc==0 && p->xStep==0) ? 0 : FUNC_PERFECT_MATCH;
    ++  if( nArg==(-2) ) return (p->xSFunc==0) ? 0 : FUNC_PERFECT_MATCH;
    + 
    +   /* Wrong number of arguments means "no match" */
    +   if( p->nArg!=nArg && p->nArg>=0 ) return 0;
    +@@ -97481,14 +106362,12 @@ static int matchQuality(
    + ** a pointer to the matching FuncDef if found, or 0 if there is no match.
    + */
    + static FuncDef *functionSearch(
    +-  FuncDefHash *pHash,  /* Hash table to search */
    +   int h,               /* Hash of the name */
    +-  const char *zFunc,   /* Name of function */
    +-  int nFunc            /* Number of bytes in zFunc */
    ++  const char *zFunc    /* Name of function */
    + ){
    +   FuncDef *p;
    +-  for(p=pHash->a[h]; p; p=p->pHash){
    +-    if( sqlite3StrNICmp(p->zName, zFunc, nFunc)==0 && p->zName[nFunc]==0 ){
    ++  for(p=sqlite3BuiltinFunctions.a[h]; p; p=p->u.pHash){
    ++    if( sqlite3StrICmp(p->zName, zFunc)==0 ){
    +       return p;
    +     }
    +   }
    +@@ -97498,23 +106377,27 @@ static FuncDef *functionSearch(
    + /*
    + ** Insert a new FuncDef into a FuncDefHash hash table.
    + */
    +-SQLITE_PRIVATE void sqlite3FuncDefInsert(
    +-  FuncDefHash *pHash,  /* The hash table into which to insert */
    +-  FuncDef *pDef        /* The function definition to insert */
    ++SQLITE_PRIVATE void sqlite3InsertBuiltinFuncs(
    ++  FuncDef *aDef,      /* List of global functions to be inserted */
    ++  int nDef            /* Length of the apDef[] list */
    + ){
    +-  FuncDef *pOther;
    +-  int nName = sqlite3Strlen30(pDef->zName);
    +-  u8 c1 = (u8)pDef->zName[0];
    +-  int h = (sqlite3UpperToLower[c1] + nName) % ArraySize(pHash->a);
    +-  pOther = functionSearch(pHash, h, pDef->zName, nName);
    +-  if( pOther ){
    +-    assert( pOther!=pDef && pOther->pNext!=pDef );
    +-    pDef->pNext = pOther->pNext;
    +-    pOther->pNext = pDef;
    +-  }else{
    +-    pDef->pNext = 0;
    +-    pDef->pHash = pHash->a[h];
    +-    pHash->a[h] = pDef;
    ++  int i;
    ++  for(i=0; i<nDef; i++){
    ++    FuncDef *pOther;
    ++    const char *zName = aDef[i].zName;
    ++    int nName = sqlite3Strlen30(zName);
    ++    int h = (zName[0] + nName) % SQLITE_FUNC_HASH_SZ;
    ++    assert( zName[0]>='a' && zName[0]<='z' );
    ++    pOther = functionSearch(h, zName);
    ++    if( pOther ){
    ++      assert( pOther!=&aDef[i] && pOther->pNext!=&aDef[i] );
    ++      aDef[i].pNext = pOther->pNext;
    ++      pOther->pNext = &aDef[i];
    ++    }else{
    ++      aDef[i].pNext = 0;
    ++      aDef[i].u.pHash = sqlite3BuiltinFunctions.a[h];
    ++      sqlite3BuiltinFunctions.a[h] = &aDef[i];
    ++    }
    +   }
    + }
    +   
    +@@ -97531,7 +106414,7 @@ SQLITE_PRIVATE void sqlite3FuncDefInsert(
    + ** no matching function previously existed.
    + **
    + ** If nArg is -2, then the first valid function found is returned.  A
    +-** function is valid if either xFunc or xStep is non-zero.  The nArg==(-2)
    ++** function is valid if xSFunc is non-zero.  The nArg==(-2)
    + ** case is used to see if zName is a valid function name for some number
    + ** of arguments.  If nArg is -2, then createFlag must be 0.
    + **
    +@@ -97541,8 +106424,7 @@ SQLITE_PRIVATE void sqlite3FuncDefInsert(
    + */
    + SQLITE_PRIVATE FuncDef *sqlite3FindFunction(
    +   sqlite3 *db,       /* An open database */
    +-  const char *zName, /* Name of the function.  Not null-terminated */
    +-  int nName,         /* Number of characters in the name */
    ++  const char *zName, /* Name of the function.  zero-terminated */
    +   int nArg,          /* Number of arguments.  -1 means any number */
    +   u8 enc,            /* Preferred text encoding */
    +   u8 createFlag      /* Create new entry if true and does not otherwise exist */
    +@@ -97551,14 +106433,15 @@ SQLITE_PRIVATE FuncDef *sqlite3FindFunction(
    +   FuncDef *pBest = 0; /* Best match found so far */
    +   int bestScore = 0;  /* Score of best match */
    +   int h;              /* Hash value */
    ++  int nName;          /* Length of the name */
    + 
    +   assert( nArg>=(-2) );
    +   assert( nArg>=(-1) || createFlag==0 );
    +-  h = (sqlite3UpperToLower[(u8)zName[0]] + nName) % ArraySize(db->aFunc.a);
    ++  nName = sqlite3Strlen30(zName);
    + 
    +   /* First search for a match amongst the application-defined functions.
    +   */
    +-  p = functionSearch(&db->aFunc, h, zName, nName);
    ++  p = (FuncDef*)sqlite3HashFind(&db->aFunc, zName);
    +   while( p ){
    +     int score = matchQuality(p, nArg, enc);
    +     if( score>bestScore ){
    +@@ -97570,7 +106453,7 @@ SQLITE_PRIVATE FuncDef *sqlite3FindFunction(
    + 
    +   /* If no match is found, search the built-in functions.
    +   **
    +-  ** If the SQLITE_PreferBuiltin flag is set, then search the built-in
    ++  ** If the DBFLAG_PreferBuiltin flag is set, then search the built-in
    +   ** functions even if a prior app-defined function was found.  And give
    +   ** priority to built-in functions.
    +   **
    +@@ -97580,10 +106463,10 @@ SQLITE_PRIVATE FuncDef *sqlite3FindFunction(
    +   ** new function.  But the FuncDefs for built-in functions are read-only.
    +   ** So we must not search for built-ins when creating a new function.
    +   */ 
    +-  if( !createFlag && (pBest==0 || (db->flags & SQLITE_PreferBuiltin)!=0) ){
    +-    FuncDefHash *pHash = &GLOBAL(FuncDefHash, sqlite3GlobalFunctions);
    ++  if( !createFlag && (pBest==0 || (db->mDbFlags & DBFLAG_PreferBuiltin)!=0) ){
    +     bestScore = 0;
    +-    p = functionSearch(pHash, h, zName, nName);
    ++    h = (sqlite3UpperToLower[(u8)zName[0]] + nName) % SQLITE_FUNC_HASH_SZ;
    ++    p = functionSearch(h, zName);
    +     while( p ){
    +       int score = matchQuality(p, nArg, enc);
    +       if( score>bestScore ){
    +@@ -97600,15 +106483,22 @@ SQLITE_PRIVATE FuncDef *sqlite3FindFunction(
    +   */
    +   if( createFlag && bestScore<FUNC_PERFECT_MATCH && 
    +       (pBest = sqlite3DbMallocZero(db, sizeof(*pBest)+nName+1))!=0 ){
    +-    pBest->zName = (char *)&pBest[1];
    ++    FuncDef *pOther;
    ++    pBest->zName = (const char*)&pBest[1];
    +     pBest->nArg = (u16)nArg;
    +     pBest->funcFlags = enc;
    +-    memcpy(pBest->zName, zName, nName);
    +-    pBest->zName[nName] = 0;
    +-    sqlite3FuncDefInsert(&db->aFunc, pBest);
    ++    memcpy((char*)&pBest[1], zName, nName+1);
    ++    pOther = (FuncDef*)sqlite3HashInsert(&db->aFunc, pBest->zName, pBest);
    ++    if( pOther==pBest ){
    ++      sqlite3DbFree(db, pBest);
    ++      sqlite3OomFault(db);
    ++      return 0;
    ++    }else{
    ++      pBest->pNext = pOther;
    ++    }
    +   }
    + 
    +-  if( pBest && (pBest->xStep || pBest->xFunc || createFlag) ){
    ++  if( pBest && (pBest->xSFunc || createFlag) ){
    +     return pBest;
    +   }
    +   return 0;
    +@@ -97646,8 +106536,8 @@ SQLITE_PRIVATE void sqlite3SchemaClear(void *p){
    +   pSchema->pSeqTab = 0;
    +   if( pSchema->schemaFlags & DB_SchemaLoaded ){
    +     pSchema->iGeneration++;
    +-    pSchema->schemaFlags &= ~DB_SchemaLoaded;
    +   }
    ++  pSchema->schemaFlags &= ~(DB_SchemaLoaded|DB_ResetWanted);
    + }
    + 
    + /*
    +@@ -97662,7 +106552,7 @@ SQLITE_PRIVATE Schema *sqlite3SchemaGet(sqlite3 *db, Btree *pBt){
    +     p = (Schema *)sqlite3DbMallocZero(0, sizeof(Schema));
    +   }
    +   if( !p ){
    +-    db->mallocFailed = 1;
    ++    sqlite3OomFault(db);
    +   }else if ( 0==p->file_format ){
    +     sqlite3HashInit(&p->tblHash);
    +     sqlite3HashInit(&p->idxHash);
    +@@ -97713,7 +106603,7 @@ SQLITE_PRIVATE Table *sqlite3SrcListLookup(Parse *pParse, SrcList *pSrc){
    +   sqlite3DeleteTable(pParse->db, pItem->pTab);
    +   pItem->pTab = pTab;
    +   if( pTab ){
    +-    pTab->nRef++;
    ++    pTab->nTabRef++;
    +   }
    +   if( sqlite3IndexedByLookup(pParse, pItem) ){
    +     pTab = 0;
    +@@ -97767,6 +106657,8 @@ SQLITE_PRIVATE void sqlite3MaterializeView(
    +   Parse *pParse,       /* Parsing context */
    +   Table *pView,        /* View definition */
    +   Expr *pWhere,        /* Optional WHERE clause to be added */
    ++  ExprList *pOrderBy,  /* Optional ORDER BY clause */
    ++  Expr *pLimit,        /* Optional LIMIT clause */
    +   int iCur             /* Cursor number for ephemeral table */
    + ){
    +   SelectDest dest;
    +@@ -97779,11 +106671,12 @@ SQLITE_PRIVATE void sqlite3MaterializeView(
    +   if( pFrom ){
    +     assert( pFrom->nSrc==1 );
    +     pFrom->a[0].zName = sqlite3DbStrDup(db, pView->zName);
    +-    pFrom->a[0].zDatabase = sqlite3DbStrDup(db, db->aDb[iDb].zName);
    ++    pFrom->a[0].zDatabase = sqlite3DbStrDup(db, db->aDb[iDb].zDbSName);
    +     assert( pFrom->a[0].pOn==0 );
    +     assert( pFrom->a[0].pUsing==0 );
    +   }
    +-  pSel = sqlite3SelectNew(pParse, 0, pFrom, pWhere, 0, 0, 0, 0, 0, 0);
    ++  pSel = sqlite3SelectNew(pParse, 0, pFrom, pWhere, 0, 0, pOrderBy, 
    ++                          SF_IncludeHidden, pLimit);
    +   sqlite3SelectDestInit(&dest, SRT_EphemTab, iCur);
    +   sqlite3Select(pParse, pSel, &dest);
    +   sqlite3SelectDelete(db, pSel);
    +@@ -97805,29 +106698,29 @@ SQLITE_PRIVATE Expr *sqlite3LimitWhere(
    +   Expr *pWhere,                /* The WHERE clause.  May be null */
    +   ExprList *pOrderBy,          /* The ORDER BY clause.  May be null */
    +   Expr *pLimit,                /* The LIMIT clause.  May be null */
    +-  Expr *pOffset,               /* The OFFSET clause.  May be null */
    +   char *zStmtType              /* Either DELETE or UPDATE.  For err msgs. */
    + ){
    +-  Expr *pWhereRowid = NULL;    /* WHERE rowid .. */
    ++  sqlite3 *db = pParse->db;
    ++  Expr *pLhs = NULL;           /* LHS of IN(SELECT...) operator */
    +   Expr *pInClause = NULL;      /* WHERE rowid IN ( select ) */
    +-  Expr *pSelectRowid = NULL;   /* SELECT rowid ... */
    +   ExprList *pEList = NULL;     /* Expression list contaning only pSelectRowid */
    +   SrcList *pSelectSrc = NULL;  /* SELECT rowid FROM x ... (dup of pSrc) */
    +   Select *pSelect = NULL;      /* Complete SELECT tree */
    ++  Table *pTab;
    + 
    +   /* Check that there isn't an ORDER BY without a LIMIT clause.
    +   */
    +-  if( pOrderBy && (pLimit == 0) ) {
    ++  if( pOrderBy && pLimit==0 ) {
    +     sqlite3ErrorMsg(pParse, "ORDER BY without LIMIT on %s", zStmtType);
    +-    goto limit_where_cleanup_2;
    ++    sqlite3ExprDelete(pParse->db, pWhere);
    ++    sqlite3ExprListDelete(pParse->db, pOrderBy);
    ++    return 0;
    +   }
    + 
    +   /* We only need to generate a select expression if there
    +   ** is a limit/offset term to enforce.
    +   */
    +   if( pLimit == 0 ) {
    +-    /* if pLimit is null, pOffset will always be null as well. */
    +-    assert( pOffset == 0 );
    +     return pWhere;
    +   }
    + 
    +@@ -97840,46 +106733,47 @@ SQLITE_PRIVATE Expr *sqlite3LimitWhere(
    +   **   );
    +   */
    + 
    +-  pSelectRowid = sqlite3PExpr(pParse, TK_ROW, 0, 0, 0);
    +-  if( pSelectRowid == 0 ) goto limit_where_cleanup_2;
    +-  pEList = sqlite3ExprListAppend(pParse, 0, pSelectRowid);
    +-  if( pEList == 0 ) goto limit_where_cleanup_2;
    ++  pTab = pSrc->a[0].pTab;
    ++  if( HasRowid(pTab) ){
    ++    pLhs = sqlite3PExpr(pParse, TK_ROW, 0, 0);
    ++    pEList = sqlite3ExprListAppend(
    ++        pParse, 0, sqlite3PExpr(pParse, TK_ROW, 0, 0)
    ++    );
    ++  }else{
    ++    Index *pPk = sqlite3PrimaryKeyIndex(pTab);
    ++    if( pPk->nKeyCol==1 ){
    ++      const char *zName = pTab->aCol[pPk->aiColumn[0]].zName;
    ++      pLhs = sqlite3Expr(db, TK_ID, zName);
    ++      pEList = sqlite3ExprListAppend(pParse, 0, sqlite3Expr(db, TK_ID, zName));
    ++    }else{
    ++      int i;
    ++      for(i=0; i<pPk->nKeyCol; i++){
    ++        Expr *p = sqlite3Expr(db, TK_ID, pTab->aCol[pPk->aiColumn[i]].zName);
    ++        pEList = sqlite3ExprListAppend(pParse, pEList, p);
    ++      }
    ++      pLhs = sqlite3PExpr(pParse, TK_VECTOR, 0, 0);
    ++      if( pLhs ){
    ++        pLhs->x.pList = sqlite3ExprListDup(db, pEList, 0);
    ++      }
    ++    }
    ++  }
    + 
    +   /* duplicate the FROM clause as it is needed by both the DELETE/UPDATE tree
    +   ** and the SELECT subtree. */
    ++  pSrc->a[0].pTab = 0;
    +   pSelectSrc = sqlite3SrcListDup(pParse->db, pSrc, 0);
    +-  if( pSelectSrc == 0 ) {
    +-    sqlite3ExprListDelete(pParse->db, pEList);
    +-    goto limit_where_cleanup_2;
    +-  }
    ++  pSrc->a[0].pTab = pTab;
    ++  pSrc->a[0].pIBIndex = 0;
    + 
    +   /* generate the SELECT expression tree. */
    +-  pSelect = sqlite3SelectNew(pParse,pEList,pSelectSrc,pWhere,0,0,
    +-                             pOrderBy,0,pLimit,pOffset);
    +-  if( pSelect == 0 ) return 0;
    ++  pSelect = sqlite3SelectNew(pParse, pEList, pSelectSrc, pWhere, 0 ,0, 
    ++      pOrderBy,0,pLimit
    ++  );
    + 
    +   /* now generate the new WHERE rowid IN clause for the DELETE/UDPATE */
    +-  pWhereRowid = sqlite3PExpr(pParse, TK_ROW, 0, 0, 0);
    +-  if( pWhereRowid == 0 ) goto limit_where_cleanup_1;
    +-  pInClause = sqlite3PExpr(pParse, TK_IN, pWhereRowid, 0, 0);
    +-  if( pInClause == 0 ) goto limit_where_cleanup_1;
    +-
    +-  pInClause->x.pSelect = pSelect;
    +-  pInClause->flags |= EP_xIsSelect;
    +-  sqlite3ExprSetHeightAndFlags(pParse, pInClause);
    ++  pInClause = sqlite3PExpr(pParse, TK_IN, pLhs, 0);
    ++  sqlite3PExprAddSelect(pParse, pInClause, pSelect);
    +   return pInClause;
    +-
    +-  /* something went wrong. clean up anything allocated. */
    +-limit_where_cleanup_1:
    +-  sqlite3SelectDelete(pParse->db, pSelect);
    +-  return 0;
    +-
    +-limit_where_cleanup_2:
    +-  sqlite3ExprDelete(pParse->db, pWhere);
    +-  sqlite3ExprListDelete(pParse->db, pOrderBy);
    +-  sqlite3ExprDelete(pParse->db, pLimit);
    +-  sqlite3ExprDelete(pParse->db, pOffset);
    +-  return 0;
    + }
    + #endif /* defined(SQLITE_ENABLE_UPDATE_DELETE_LIMIT) */
    +        /*      && !defined(SQLITE_OMIT_SUBQUERY) */
    +@@ -97894,11 +106788,12 @@ limit_where_cleanup_2:
    + SQLITE_PRIVATE void sqlite3DeleteFrom(
    +   Parse *pParse,         /* The parser context */
    +   SrcList *pTabList,     /* The table from which we should delete things */
    +-  Expr *pWhere           /* The WHERE clause.  May be null */
    ++  Expr *pWhere,          /* The WHERE clause.  May be null */
    ++  ExprList *pOrderBy,    /* ORDER BY clause. May be null */
    ++  Expr *pLimit           /* LIMIT clause. May be null */
    + ){
    +   Vdbe *v;               /* The virtual database engine */
    +   Table *pTab;           /* The table from which records will be deleted */
    +-  const char *zDb;       /* Name of database holding pTab */
    +   int i;                 /* Loop counter */
    +   WhereInfo *pWInfo;     /* Information about the WHERE clause */
    +   Index *pIdx;           /* For looping over indices of the table */
    +@@ -97925,11 +106820,12 @@ SQLITE_PRIVATE void sqlite3DeleteFrom(
    +   int addrBypass = 0;    /* Address of jump over the delete logic */
    +   int addrLoop = 0;      /* Top of the delete loop */
    +   int addrEphOpen = 0;   /* Instruction to open the Ephemeral table */
    ++  int bComplex;          /* True if there are triggers or FKs or
    ++                         ** subqueries in the WHERE clause */
    +  
    + #ifndef SQLITE_OMIT_TRIGGER
    +   int isView;                  /* True if attempting to delete from a view */
    +   Trigger *pTrigger;           /* List of table triggers, if required */
    +-  int bComplex;                /* True if there are either triggers or FKs */
    + #endif
    + 
    +   memset(&sContext, 0, sizeof(sContext));
    +@@ -97939,6 +106835,7 @@ SQLITE_PRIVATE void sqlite3DeleteFrom(
    +   }
    +   assert( pTabList->nSrc==1 );
    + 
    ++
    +   /* Locate the table which we want to delete.  This table has to be
    +   ** put in an SrcList structure because some of the subroutines we
    +   ** will be calling are designed to work with multiple tables and expect
    +@@ -97953,17 +106850,26 @@ SQLITE_PRIVATE void sqlite3DeleteFrom(
    + #ifndef SQLITE_OMIT_TRIGGER
    +   pTrigger = sqlite3TriggersExist(pParse, pTab, TK_DELETE, 0, 0);
    +   isView = pTab->pSelect!=0;
    +-  bComplex = pTrigger || sqlite3FkRequired(pParse, pTab, 0, 0);
    + #else
    + # define pTrigger 0
    + # define isView 0
    +-# define bComplex 0
    + #endif
    ++  bComplex = pTrigger || sqlite3FkRequired(pParse, pTab, 0, 0);
    + #ifdef SQLITE_OMIT_VIEW
    + # undef isView
    + # define isView 0
    + #endif
    + 
    ++#ifdef SQLITE_ENABLE_UPDATE_DELETE_LIMIT
    ++  if( !isView ){
    ++    pWhere = sqlite3LimitWhere(
    ++        pParse, pTabList, pWhere, pOrderBy, pLimit, "DELETE"
    ++    );
    ++    pOrderBy = 0;
    ++    pLimit = 0;
    ++  }
    ++#endif
    ++
    +   /* If pTab is really a view, make sure it has been initialized.
    +   */
    +   if( sqlite3ViewGetColumnNames(pParse, pTab) ){
    +@@ -97975,8 +106881,8 @@ SQLITE_PRIVATE void sqlite3DeleteFrom(
    +   }
    +   iDb = sqlite3SchemaToIndex(db, pTab->pSchema);
    +   assert( iDb<db->nDb );
    +-  zDb = db->aDb[iDb].zName;
    +-  rcauth = sqlite3AuthCheck(pParse, SQLITE_DELETE, pTab->zName, 0, zDb);
    ++  rcauth = sqlite3AuthCheck(pParse, SQLITE_DELETE, pTab->zName, 0, 
    ++                            db->aDb[iDb].zDbSName);
    +   assert( rcauth==SQLITE_OK || rcauth==SQLITE_DENY || rcauth==SQLITE_IGNORE );
    +   if( rcauth==SQLITE_DENY ){
    +     goto delete_from_cleanup;
    +@@ -98011,8 +106917,12 @@ SQLITE_PRIVATE void sqlite3DeleteFrom(
    +   */
    + #if !defined(SQLITE_OMIT_VIEW) && !defined(SQLITE_OMIT_TRIGGER)
    +   if( isView ){
    +-    sqlite3MaterializeView(pParse, pTab, pWhere, iTabCur);
    ++    sqlite3MaterializeView(pParse, pTab, 
    ++        pWhere, pOrderBy, pLimit, iTabCur
    ++    );
    +     iDataCur = iIdxCur = iTabCur;
    ++    pOrderBy = 0;
    ++    pLimit = 0;
    +   }
    + #endif
    + 
    +@@ -98037,11 +106947,21 @@ SQLITE_PRIVATE void sqlite3DeleteFrom(
    +   /* Special case: A DELETE without a WHERE clause deletes everything.
    +   ** It is easier just to erase the whole table. Prior to version 3.6.5,
    +   ** this optimization caused the row change count (the value returned by 
    +-  ** API function sqlite3_count_changes) to be set incorrectly.  */
    ++  ** API function sqlite3_count_changes) to be set incorrectly.
    ++  **
    ++  ** The "rcauth==SQLITE_OK" terms is the
    ++  ** IMPLEMENTATION-OF: R-17228-37124 If the action code is SQLITE_DELETE and
    ++  ** the callback returns SQLITE_IGNORE then the DELETE operation proceeds but
    ++  ** the truncate optimization is disabled and all rows are deleted
    ++  ** individually.
    ++  */
    +   if( rcauth==SQLITE_OK
    +    && pWhere==0
    +    && !bComplex
    +    && !IsVirtual(pTab)
    ++#ifdef SQLITE_ENABLE_PREUPDATE_HOOK
    ++   && db->xPreUpdateCallback==0
    ++#endif
    +   ){
    +     assert( !isView );
    +     sqlite3TableLock(pParse, iDb, pTab->tnum, 1, pTab->zName);
    +@@ -98056,7 +106976,8 @@ SQLITE_PRIVATE void sqlite3DeleteFrom(
    +   }else
    + #endif /* SQLITE_OMIT_TRUNCATE_OPTIMIZATION */
    +   {
    +-    u16 wcf = WHERE_ONEPASS_DESIRED|WHERE_DUPLICATES_OK;
    ++    u16 wcf = WHERE_ONEPASS_DESIRED|WHERE_DUPLICATES_OK|WHERE_SEEK_TABLE;
    ++    if( sNC.ncFlags & NC_VarSelect ) bComplex = 1;
    +     wcf |= (bComplex ? 0 : WHERE_ONEPASS_MULTIROW);
    +     if( HasRowid(pTab) ){
    +       /* For a rowid table, initialize the RowSet to an empty set */
    +@@ -98115,7 +107036,7 @@ SQLITE_PRIVATE void sqlite3DeleteFrom(
    +       ** one, so just keep it in its register(s) and fall through to the
    +       ** delete code.  */
    +       nKey = nPk; /* OP_Found will use an unpacked key */
    +-      aToOpen = sqlite3DbMallocRaw(db, nIdx+2);
    ++      aToOpen = sqlite3DbMallocRawNN(db, nIdx+2);
    +       if( aToOpen==0 ){
    +         sqlite3WhereEnd(pWInfo);
    +         goto delete_from_cleanup;
    +@@ -98132,10 +107053,10 @@ SQLITE_PRIVATE void sqlite3DeleteFrom(
    +         nKey = 0;   /* Zero tells OP_Found to use a composite key */
    +         sqlite3VdbeAddOp4(v, OP_MakeRecord, iPk, nPk, iKey,
    +             sqlite3IndexAffinityStr(pParse->db, pPk), nPk);
    +-        sqlite3VdbeAddOp2(v, OP_IdxInsert, iEphCur, iKey);
    ++        sqlite3VdbeAddOp4Int(v, OP_IdxInsert, iEphCur, iKey, iPk, nPk);
    +       }else{
    +         /* Add the rowid of the row to be deleted to the RowSet */
    +-        nKey = 1;  /* OP_Seek always uses a single rowid */
    ++        nKey = 1;  /* OP_DeferredSeek always uses a single rowid */
    +         sqlite3VdbeAddOp2(v, OP_RowSetAdd, iRowSet, iKey);
    +       }
    +     }
    +@@ -98156,11 +107077,11 @@ SQLITE_PRIVATE void sqlite3DeleteFrom(
    +     if( !isView ){
    +       int iAddrOnce = 0;
    +       if( eOnePass==ONEPASS_MULTI ){
    +-        iAddrOnce = sqlite3CodeOnce(pParse); VdbeCoverage(v);
    ++        iAddrOnce = sqlite3VdbeAddOp0(v, OP_Once); VdbeCoverage(v);
    +       }
    +       testcase( IsVirtual(pTab) );
    +-      sqlite3OpenTableAndIndices(pParse, pTab, OP_OpenWrite, iTabCur, aToOpen,
    +-                                 &iDataCur, &iIdxCur);
    ++      sqlite3OpenTableAndIndices(pParse, pTab, OP_OpenWrite, OPFLAG_FORDELETE,
    ++                                 iTabCur, aToOpen, &iDataCur, &iIdxCur);
    +       assert( pPk || IsVirtual(pTab) || iDataCur==iTabCur );
    +       assert( pPk || IsVirtual(pTab) || iIdxCur==iDataCur+1 );
    +       if( eOnePass==ONEPASS_MULTI ) sqlite3VdbeJumpHere(v, iAddrOnce);
    +@@ -98178,7 +107099,11 @@ SQLITE_PRIVATE void sqlite3DeleteFrom(
    +       }
    +     }else if( pPk ){
    +       addrLoop = sqlite3VdbeAddOp1(v, OP_Rewind, iEphCur); VdbeCoverage(v);
    +-      sqlite3VdbeAddOp2(v, OP_RowKey, iEphCur, iKey);
    ++      if( IsVirtual(pTab) ){
    ++        sqlite3VdbeAddOp3(v, OP_Column, iEphCur, 0, iKey);
    ++      }else{
    ++        sqlite3VdbeAddOp2(v, OP_RowData, iEphCur, iKey);
    ++      }
    +       assert( nKey==0 );  /* OP_Found will use a composite key */
    +     }else{
    +       addrLoop = sqlite3VdbeAddOp3(v, OP_RowSetRead, iRowSet, 0, iKey);
    +@@ -98202,12 +107127,8 @@ SQLITE_PRIVATE void sqlite3DeleteFrom(
    + #endif
    +     {
    +       int count = (pParse->nested==0);    /* True to count changes */
    +-      int iIdxNoSeek = -1;
    +-      if( bComplex==0 && aiCurOnePass[1]!=iDataCur ){
    +-        iIdxNoSeek = aiCurOnePass[1];
    +-      }
    +       sqlite3GenerateRowDelete(pParse, pTab, pTrigger, iDataCur, iIdxCur,
    +-          iKey, nKey, count, OE_Default, eOnePass, iIdxNoSeek);
    ++          iKey, nKey, count, OE_Default, eOnePass, aiCurOnePass[1]);
    +     }
    +   
    +     /* End of the loop over all rowids/primary-keys. */
    +@@ -98221,14 +107142,6 @@ SQLITE_PRIVATE void sqlite3DeleteFrom(
    +       sqlite3VdbeGoto(v, addrLoop);
    +       sqlite3VdbeJumpHere(v, addrLoop);
    +     }     
    +-  
    +-    /* Close the cursors open on the table and its indexes. */
    +-    if( !isView && !IsVirtual(pTab) ){
    +-      if( !pPk ) sqlite3VdbeAddOp1(v, OP_Close, iDataCur);
    +-      for(i=0, pIdx=pTab->pIndex; pIdx; i++, pIdx=pIdx->pNext){
    +-        sqlite3VdbeAddOp1(v, OP_Close, iIdxCur + i);
    +-      }
    +-    }
    +   } /* End non-truncate path */
    + 
    +   /* Update the sqlite_sequence table by storing the content of the
    +@@ -98253,6 +107166,10 @@ delete_from_cleanup:
    +   sqlite3AuthContextPop(&sContext);
    +   sqlite3SrcListDelete(db, pTabList);
    +   sqlite3ExprDelete(db, pWhere);
    ++#if defined(SQLITE_ENABLE_UPDATE_DELETE_LIMIT) 
    ++  sqlite3ExprListDelete(db, pOrderBy);
    ++  sqlite3ExprDelete(db, pLimit);
    ++#endif
    +   sqlite3DbFree(db, aToOpen);
    +   return;
    + }
    +@@ -98295,15 +107212,17 @@ delete_from_cleanup:
    + **
    + **   If eMode is ONEPASS_MULTI, then this call is being made as part
    + **   of a ONEPASS delete that affects multiple rows. In this case, if 
    +-**   iIdxNoSeek is a valid cursor number (>=0), then its position should
    +-**   be preserved following the delete operation. Or, if iIdxNoSeek is not
    +-**   a valid cursor number, the position of iDataCur should be preserved
    +-**   instead.
    ++**   iIdxNoSeek is a valid cursor number (>=0) and is not the same as
    ++**   iDataCur, then its position should be preserved following the delete
    ++**   operation. Or, if iIdxNoSeek is not a valid cursor number, the
    ++**   position of iDataCur should be preserved instead.
    + **
    + ** iIdxNoSeek:
    +-**   If iIdxNoSeek is a valid cursor number (>=0), then it identifies an
    +-**   index cursor (from within array of cursors starting at iIdxCur) that
    +-**   already points to the index entry to be deleted.
    ++**   If iIdxNoSeek is a valid cursor number (>=0) not equal to iDataCur,
    ++**   then it identifies an index cursor (from within array of cursors
    ++**   starting at iIdxCur) that already points to the index entry to be deleted.
    ++**   Except, this optimization is disabled if there are BEFORE triggers since
    ++**   the trigger body might have moved the cursor.
    + */
    + SQLITE_PRIVATE void sqlite3GenerateRowDelete(
    +   Parse *pParse,     /* Parsing context */
    +@@ -98374,13 +107293,18 @@ SQLITE_PRIVATE void sqlite3GenerateRowDelete(
    + 
    +     /* If any BEFORE triggers were coded, then seek the cursor to the 
    +     ** row to be deleted again. It may be that the BEFORE triggers moved
    +-    ** the cursor or of already deleted the row that the cursor was
    ++    ** the cursor or already deleted the row that the cursor was
    +     ** pointing to.
    ++    **
    ++    ** Also disable the iIdxNoSeek optimization since the BEFORE trigger
    ++    ** may have moved that cursor.
    +     */
    +     if( addrStart<sqlite3VdbeCurrentAddr(v) ){
    +       sqlite3VdbeAddOp4Int(v, opSeek, iDataCur, iLabel, iPk, nPk);
    +       VdbeCoverageIf(v, opSeek==OP_NotExists);
    +       VdbeCoverageIf(v, opSeek==OP_NotFound);
    ++      testcase( iIdxNoSeek>=0 );
    ++      iIdxNoSeek = -1;
    +     }
    + 
    +     /* Do FK processing. This call checks that any FK constraints that
    +@@ -98391,17 +107315,29 @@ SQLITE_PRIVATE void sqlite3GenerateRowDelete(
    + 
    +   /* Delete the index and table entries. Skip this step if pTab is really
    +   ** a view (in which case the only effect of the DELETE statement is to
    +-  ** fire the INSTEAD OF triggers).  */ 
    ++  ** fire the INSTEAD OF triggers).  
    ++  **
    ++  ** If variable 'count' is non-zero, then this OP_Delete instruction should
    ++  ** invoke the update-hook. The pre-update-hook, on the other hand should
    ++  ** be invoked unless table pTab is a system table. The difference is that
    ++  ** the update-hook is not invoked for rows removed by REPLACE, but the 
    ++  ** pre-update-hook is.
    ++  */ 
    +   if( pTab->pSelect==0 ){
    ++    u8 p5 = 0;
    +     sqlite3GenerateRowIndexDelete(pParse, pTab, iDataCur, iIdxCur,0,iIdxNoSeek);
    +     sqlite3VdbeAddOp2(v, OP_Delete, iDataCur, (count?OPFLAG_NCHANGE:0));
    +-    if( count ){
    +-      sqlite3VdbeChangeP4(v, -1, pTab->zName, P4_TRANSIENT);
    ++    if( pParse->nested==0 || 0==sqlite3_stricmp(pTab->zName, "sqlite_stat1") ){
    ++      sqlite3VdbeAppendP4(v, (char*)pTab, P4_TABLE);
    +     }
    +-    if( iIdxNoSeek>=0 ){
    ++    if( eMode!=ONEPASS_OFF ){
    ++      sqlite3VdbeChangeP5(v, OPFLAG_AUXDELETE);
    ++    }
    ++    if( iIdxNoSeek>=0 && iIdxNoSeek!=iDataCur ){
    +       sqlite3VdbeAddOp1(v, OP_Delete, iIdxNoSeek);
    +     }
    +-    sqlite3VdbeChangeP5(v, eMode==ONEPASS_MULTI);
    ++    if( eMode==ONEPASS_MULTI ) p5 |= OPFLAG_SAVEPOSITION;
    ++    sqlite3VdbeChangeP5(v, p5);
    +   }
    + 
    +   /* Do any ON CASCADE, SET NULL or SET DEFAULT operations required to
    +@@ -98521,10 +107457,11 @@ SQLITE_PRIVATE int sqlite3GenerateIndexKey(
    +   if( piPartIdxLabel ){
    +     if( pIdx->pPartIdxWhere ){
    +       *piPartIdxLabel = sqlite3VdbeMakeLabel(v);
    +-      pParse->iSelfTab = iDataCur;
    ++      pParse->iSelfTab = iDataCur + 1;
    +       sqlite3ExprCachePush(pParse);
    +       sqlite3ExprIfFalseDup(pParse, pIdx->pPartIdxWhere, *piPartIdxLabel, 
    +                             SQLITE_JUMPIFNULL);
    ++      pParse->iSelfTab = 0;
    +     }else{
    +       *piPartIdxLabel = 0;
    +     }
    +@@ -98551,6 +107488,10 @@ SQLITE_PRIVATE int sqlite3GenerateIndexKey(
    +   }
    +   if( regOut ){
    +     sqlite3VdbeAddOp3(v, OP_MakeRecord, regBase, nCol, regOut);
    ++    if( pIdx->pTable->pSelect ){
    ++      const char *zAff = sqlite3IndexAffinityStr(pParse->db, pIdx);
    ++      sqlite3VdbeChangeP4(v, -1, zAff, P4_TRANSIENT);
    ++    }
    +   }
    +   sqlite3ReleaseTempRange(pParse, regBase, nCol);
    +   return regBase;
    +@@ -98648,16 +107589,20 @@ static void typeofFunc(
    +   int NotUsed,
    +   sqlite3_value **argv
    + ){
    +-  const char *z = 0;
    ++  static const char *azType[] = { "integer", "real", "text", "blob", "null" };
    ++  int i = sqlite3_value_type(argv[0]) - 1;
    +   UNUSED_PARAMETER(NotUsed);
    +-  switch( sqlite3_value_type(argv[0]) ){
    +-    case SQLITE_INTEGER: z = "integer"; break;
    +-    case SQLITE_TEXT:    z = "text";    break;
    +-    case SQLITE_FLOAT:   z = "real";    break;
    +-    case SQLITE_BLOB:    z = "blob";    break;
    +-    default:             z = "null";    break;
    +-  }
    +-  sqlite3_result_text(context, z, -1, SQLITE_STATIC);
    ++  assert( i>=0 && i<ArraySize(azType) );
    ++  assert( SQLITE_INTEGER==1 );
    ++  assert( SQLITE_FLOAT==2 );
    ++  assert( SQLITE_TEXT==3 );
    ++  assert( SQLITE_BLOB==4 );
    ++  assert( SQLITE_NULL==5 );
    ++  /* EVIDENCE-OF: R-01470-60482 The sqlite3_value_type(V) interface returns
    ++  ** the datatype code for the initial datatype of the sqlite3_value object
    ++  ** V. The returned value is one of SQLITE_INTEGER, SQLITE_FLOAT,
    ++  ** SQLITE_TEXT, SQLITE_BLOB, or SQLITE_NULL. */
    ++  sqlite3_result_text(context, azType[i], -1, SQLITE_STATIC);
    + }
    + 
    + 
    +@@ -98772,23 +107717,26 @@ static void instrFunc(
    +   if( typeHaystack==SQLITE_NULL || typeNeedle==SQLITE_NULL ) return;
    +   nHaystack = sqlite3_value_bytes(argv[0]);
    +   nNeedle = sqlite3_value_bytes(argv[1]);
    +-  if( typeHaystack==SQLITE_BLOB && typeNeedle==SQLITE_BLOB ){
    +-    zHaystack = sqlite3_value_blob(argv[0]);
    +-    zNeedle = sqlite3_value_blob(argv[1]);
    +-    isText = 0;
    +-  }else{
    +-    zHaystack = sqlite3_value_text(argv[0]);
    +-    zNeedle = sqlite3_value_text(argv[1]);
    +-    isText = 1;
    +-  }
    +-  while( nNeedle<=nHaystack && memcmp(zHaystack, zNeedle, nNeedle)!=0 ){
    +-    N++;
    +-    do{
    +-      nHaystack--;
    +-      zHaystack++;
    +-    }while( isText && (zHaystack[0]&0xc0)==0x80 );
    ++  if( nNeedle>0 ){
    ++    if( typeHaystack==SQLITE_BLOB && typeNeedle==SQLITE_BLOB ){
    ++      zHaystack = sqlite3_value_blob(argv[0]);
    ++      zNeedle = sqlite3_value_blob(argv[1]);
    ++      isText = 0;
    ++    }else{
    ++      zHaystack = sqlite3_value_text(argv[0]);
    ++      zNeedle = sqlite3_value_text(argv[1]);
    ++      isText = 1;
    ++    }
    ++    if( zNeedle==0 || (nHaystack && zHaystack==0) ) return;
    ++    while( nNeedle<=nHaystack && memcmp(zHaystack, zNeedle, nNeedle)!=0 ){
    ++      N++;
    ++      do{
    ++        nHaystack--;
    ++        zHaystack++;
    ++      }while( isText && (zHaystack[0]&0xc0)==0x80 );
    ++    }
    ++    if( nNeedle>nHaystack ) N = 0;
    +   }
    +-  if( nNeedle>nHaystack ) N = 0;
    +   sqlite3_result_int(context, N);
    + }
    + 
    +@@ -98811,7 +107759,8 @@ static void printfFunc(
    +     x.nUsed = 0;
    +     x.apArg = argv+1;
    +     sqlite3StrAccumInit(&str, db, 0, 0, db->aLimit[SQLITE_LIMIT_LENGTH]);
    +-    sqlite3XPrintf(&str, SQLITE_PRINTF_SQLFUNC, zFormat, &x);
    ++    str.printfFlags = SQLITE_PRINTF_SQLFUNC;
    ++    sqlite3XPrintf(&str, zFormat, &x);
    +     n = str.nChar;
    +     sqlite3_result_text(context, sqlite3StrAccumFinish(&str), n,
    +                         SQLITE_DYNAMIC);
    +@@ -99139,10 +108088,10 @@ static void total_changes(
    + ** A structure defining how to do GLOB-style comparisons.
    + */
    + struct compareInfo {
    +-  u8 matchAll;
    +-  u8 matchOne;
    +-  u8 matchSet;
    +-  u8 noCase;
    ++  u8 matchAll;          /* "*" or "%" */
    ++  u8 matchOne;          /* "?" or "_" */
    ++  u8 matchSet;          /* "[" or 0 */
    ++  u8 noCase;            /* true to ignore case differences */
    + };
    + 
    + /*
    +@@ -99167,9 +108116,19 @@ static const struct compareInfo likeInfoNorm = { '%', '_',   0, 1 };
    + static const struct compareInfo likeInfoAlt = { '%', '_',   0, 0 };
    + 
    + /*
    +-** Compare two UTF-8 strings for equality where the first string can
    +-** potentially be a "glob" or "like" expression.  Return true (1) if they
    +-** are the same and false (0) if they are different.
    ++** Possible error returns from patternMatch()
    ++*/
    ++#define SQLITE_MATCH             0
    ++#define SQLITE_NOMATCH           1
    ++#define SQLITE_NOWILDCARDMATCH   2
    ++
    ++/*
    ++** Compare two UTF-8 strings for equality where the first string is
    ++** a GLOB or LIKE expression.  Return values:
    ++**
    ++**    SQLITE_MATCH:            Match
    ++**    SQLITE_NOMATCH:          No match
    ++**    SQLITE_NOWILDCARDMATCH:  No match in spite of having * or % wildcards.
    + **
    + ** Globbing rules:
    + **
    +@@ -99205,22 +108164,14 @@ static int patternCompare(
    +   const u8 *zPattern,              /* The glob pattern */
    +   const u8 *zString,               /* The string to compare against the glob */
    +   const struct compareInfo *pInfo, /* Information about how to do the compare */
    +-  u32 esc                          /* The escape character */
    ++  u32 matchOther                   /* The escape char (LIKE) or '[' (GLOB) */
    + ){
    +   u32 c, c2;                       /* Next pattern and input string chars */
    +   u32 matchOne = pInfo->matchOne;  /* "?" or "_" */
    +   u32 matchAll = pInfo->matchAll;  /* "*" or "%" */
    +-  u32 matchOther;                  /* "[" or the escape character */
    +   u8 noCase = pInfo->noCase;       /* True if uppercase==lowercase */
    +   const u8 *zEscaped = 0;          /* One past the last escaped input char */
    +   
    +-  /* The GLOB operator does not have an ESCAPE clause.  And LIKE does not
    +-  ** have the matchSet operator.  So we either have to look for one or
    +-  ** the other, never both.  Hence the single variable matchOther is used
    +-  ** to store the one we have to look for.
    +-  */
    +-  matchOther = esc ? esc : pInfo->matchSet;
    +-
    +   while( (c = Utf8Read(zPattern))!=0 ){
    +     if( c==matchAll ){  /* Match "*" */
    +       /* Skip over multiple "*" characters in the pattern.  If there
    +@@ -99228,30 +108179,31 @@ static int patternCompare(
    +       ** single character of the input string for each "?" skipped */
    +       while( (c=Utf8Read(zPattern)) == matchAll || c == matchOne ){
    +         if( c==matchOne && sqlite3Utf8Read(&zString)==0 ){
    +-          return 0;
    ++          return SQLITE_NOWILDCARDMATCH;
    +         }
    +       }
    +       if( c==0 ){
    +-        return 1;   /* "*" at the end of the pattern matches */
    ++        return SQLITE_MATCH;   /* "*" at the end of the pattern matches */
    +       }else if( c==matchOther ){
    +-        if( esc ){
    ++        if( pInfo->matchSet==0 ){
    +           c = sqlite3Utf8Read(&zPattern);
    +-          if( c==0 ) return 0;
    ++          if( c==0 ) return SQLITE_NOWILDCARDMATCH;
    +         }else{
    +           /* "[...]" immediately follows the "*".  We have to do a slow
    +           ** recursive search in this case, but it is an unusual case. */
    +           assert( matchOther<0x80 );  /* '[' is a single-byte character */
    +-          while( *zString
    +-                 && patternCompare(&zPattern[-1],zString,pInfo,esc)==0 ){
    ++          while( *zString ){
    ++            int bMatch = patternCompare(&zPattern[-1],zString,pInfo,matchOther);
    ++            if( bMatch!=SQLITE_NOMATCH ) return bMatch;
    +             SQLITE_SKIP_UTF8(zString);
    +           }
    +-          return *zString!=0;
    ++          return SQLITE_NOWILDCARDMATCH;
    +         }
    +       }
    + 
    +       /* At this point variable c contains the first character of the
    +       ** pattern string past the "*".  Search in the input string for the
    +-      ** first matching character and recursively contine the match from
    ++      ** first matching character and recursively continue the match from
    +       ** that point.
    +       **
    +       ** For a case-insensitive search, set variable cx to be the same as
    +@@ -99259,36 +108211,44 @@ static int patternCompare(
    +       ** c or cx.
    +       */
    +       if( c<=0x80 ){
    +-        u32 cx;
    ++        char zStop[3];
    ++        int bMatch;
    +         if( noCase ){
    +-          cx = sqlite3Toupper(c);
    +-          c = sqlite3Tolower(c);
    ++          zStop[0] = sqlite3Toupper(c);
    ++          zStop[1] = sqlite3Tolower(c);
    ++          zStop[2] = 0;
    +         }else{
    +-          cx = c;
    ++          zStop[0] = c;
    ++          zStop[1] = 0;
    +         }
    +-        while( (c2 = *(zString++))!=0 ){
    +-          if( c2!=c && c2!=cx ) continue;
    +-          if( patternCompare(zPattern,zString,pInfo,esc) ) return 1;
    ++        while(1){
    ++          zString += strcspn((const char*)zString, zStop);
    ++          if( zString[0]==0 ) break;
    ++          zString++;
    ++          bMatch = patternCompare(zPattern,zString,pInfo,matchOther);
    ++          if( bMatch!=SQLITE_NOMATCH ) return bMatch;
    +         }
    +       }else{
    ++        int bMatch;
    +         while( (c2 = Utf8Read(zString))!=0 ){
    +           if( c2!=c ) continue;
    +-          if( patternCompare(zPattern,zString,pInfo,esc) ) return 1;
    ++          bMatch = patternCompare(zPattern,zString,pInfo,matchOther);
    ++          if( bMatch!=SQLITE_NOMATCH ) return bMatch;
    +         }
    +       }
    +-      return 0;
    ++      return SQLITE_NOWILDCARDMATCH;
    +     }
    +     if( c==matchOther ){
    +-      if( esc ){
    ++      if( pInfo->matchSet==0 ){
    +         c = sqlite3Utf8Read(&zPattern);
    +-        if( c==0 ) return 0;
    ++        if( c==0 ) return SQLITE_NOMATCH;
    +         zEscaped = zPattern;
    +       }else{
    +         u32 prior_c = 0;
    +         int seen = 0;
    +         int invert = 0;
    +         c = sqlite3Utf8Read(&zString);
    +-        if( c==0 ) return 0;
    ++        if( c==0 ) return SQLITE_NOMATCH;
    +         c2 = sqlite3Utf8Read(&zPattern);
    +         if( c2=='^' ){
    +           invert = 1;
    +@@ -99312,27 +108272,36 @@ static int patternCompare(
    +           c2 = sqlite3Utf8Read(&zPattern);
    +         }
    +         if( c2==0 || (seen ^ invert)==0 ){
    +-          return 0;
    ++          return SQLITE_NOMATCH;
    +         }
    +         continue;
    +       }
    +     }
    +     c2 = Utf8Read(zString);
    +     if( c==c2 ) continue;
    +-    if( noCase && c<0x80 && c2<0x80 && sqlite3Tolower(c)==sqlite3Tolower(c2) ){
    ++    if( noCase  && sqlite3Tolower(c)==sqlite3Tolower(c2) && c<0x80 && c2<0x80 ){
    +       continue;
    +     }
    +     if( c==matchOne && zPattern!=zEscaped && c2!=0 ) continue;
    +-    return 0;
    ++    return SQLITE_NOMATCH;
    +   }
    +-  return *zString==0;
    ++  return *zString==0 ? SQLITE_MATCH : SQLITE_NOMATCH;
    ++}
    ++
    ++/*
    ++** The sqlite3_strglob() interface.  Return 0 on a match (like strcmp()) and
    ++** non-zero if there is no match.
    ++*/
    ++SQLITE_API int sqlite3_strglob(const char *zGlobPattern, const char *zString){
    ++  return patternCompare((u8*)zGlobPattern, (u8*)zString, &globInfo, '[');
    + }
    + 
    + /*
    +-** The sqlite3_strglob() interface.
    ++** The sqlite3_strlike() interface.  Return 0 on a match and non-zero for
    ++** a miss - like strcmp().
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_strglob(const char *zGlobPattern, const char *zString){
    +-  return patternCompare((u8*)zGlobPattern, (u8*)zString, &globInfo, 0)==0;
    ++SQLITE_API int sqlite3_strlike(const char *zPattern, const char *zStr, unsigned int esc){
    ++  return patternCompare((u8*)zPattern, (u8*)zStr, &likeInfoNorm, esc);
    + }
    + 
    + /*
    +@@ -99363,10 +108332,22 @@ static void likeFunc(
    +   sqlite3_value **argv
    + ){
    +   const unsigned char *zA, *zB;
    +-  u32 escape = 0;
    ++  u32 escape;
    +   int nPat;
    +   sqlite3 *db = sqlite3_context_db_handle(context);
    ++  struct compareInfo *pInfo = sqlite3_user_data(context);
    + 
    ++#ifdef SQLITE_LIKE_DOESNT_MATCH_BLOBS
    ++  if( sqlite3_value_type(argv[0])==SQLITE_BLOB
    ++   || sqlite3_value_type(argv[1])==SQLITE_BLOB
    ++  ){
    ++#ifdef SQLITE_TEST
    ++    sqlite3_like_count++;
    ++#endif
    ++    sqlite3_result_int(context, 0);
    ++    return;
    ++  }
    ++#endif
    +   zB = sqlite3_value_text(argv[0]);
    +   zA = sqlite3_value_text(argv[1]);
    + 
    +@@ -99394,14 +108375,15 @@ static void likeFunc(
    +       return;
    +     }
    +     escape = sqlite3Utf8Read(&zEsc);
    ++  }else{
    ++    escape = pInfo->matchSet;
    +   }
    +   if( zA && zB ){
    +-    struct compareInfo *pInfo = sqlite3_user_data(context);
    + #ifdef SQLITE_TEST
    +     sqlite3_like_count++;
    + #endif
    +-    
    +-    sqlite3_result_int(context, patternCompare(zB, zA, pInfo, escape));
    ++    sqlite3_result_int(context,
    ++                      patternCompare(zB, zA, pInfo, escape)==SQLITE_MATCH);
    +   }
    + }
    + 
    +@@ -99876,6 +108858,26 @@ static void trimFunc(
    + }
    + 
    + 
    ++#ifdef SQLITE_ENABLE_UNKNOWN_SQL_FUNCTION
    ++/*
    ++** The "unknown" function is automatically substituted in place of
    ++** any unrecognized function name when doing an EXPLAIN or EXPLAIN QUERY PLAN
    ++** when the SQLITE_ENABLE_UNKNOWN_FUNCTION compile-time option is used.
    ++** When the "sqlite3" command-line shell is built using this functionality,
    ++** that allows an EXPLAIN or EXPLAIN QUERY PLAN for complex queries
    ++** involving application-defined functions to be examined in a generic
    ++** sqlite3 shell.
    ++*/
    ++static void unknownFunc(
    ++  sqlite3_context *context,
    ++  int argc,
    ++  sqlite3_value **argv
    ++){
    ++  /* no-op */
    ++}
    ++#endif /*SQLITE_ENABLE_UNKNOWN_SQL_FUNCTION*/
    ++
    ++
    + /* IMP: R-25361-16150 This function is omitted from SQLite by default. It
    + ** is only available if the SQLITE_SOUNDEX compile-time option is used
    + ** when SQLite is built.
    +@@ -99946,6 +108948,14 @@ static void loadExt(sqlite3_context *context, int argc, sqlite3_value **argv){
    +   sqlite3 *db = sqlite3_context_db_handle(context);
    +   char *zErrMsg = 0;
    + 
    ++  /* Disallow the load_extension() SQL function unless the SQLITE_LoadExtFunc
    ++  ** flag is set.  See the sqlite3_enable_load_extension() API.
    ++  */
    ++  if( (db->flags & SQLITE_LoadExtFunc)==0 ){
    ++    sqlite3_result_error(context, "not authorized", -1);
    ++    return;
    ++  }
    ++
    +   if( argc==2 ){
    +     zProc = (const char *)sqlite3_value_text(argv[1]);
    +   }else{
    +@@ -100144,7 +109154,7 @@ static void groupConcatStep(
    +         zSep = ",";
    +         nSep = 1;
    +       }
    +-      if( nSep ) sqlite3StrAccumAppend(pAccum, zSep, nSep);
    ++      if( zSep ) sqlite3StrAccumAppend(pAccum, zSep, nSep);
    +     }
    +     zVal = (char*)sqlite3_value_text(argv[0]);
    +     nVal = sqlite3_value_bytes(argv[0]);
    +@@ -100171,11 +109181,11 @@ static void groupConcatFinalize(sqlite3_context *context){
    + ** of the built-in functions above are part of the global function set.
    + ** This routine only deals with those that are not global.
    + */
    +-SQLITE_PRIVATE void sqlite3RegisterBuiltinFunctions(sqlite3 *db){
    ++SQLITE_PRIVATE void sqlite3RegisterPerConnectionBuiltinFunctions(sqlite3 *db){
    +   int rc = sqlite3_overload_function(db, "MATCH", 2);
    +   assert( rc==SQLITE_NOMEM || rc==SQLITE_OK );
    +   if( rc==SQLITE_NOMEM ){
    +-    db->mallocFailed = 1;
    ++    sqlite3OomFault(db);
    +   }
    + }
    + 
    +@@ -100184,8 +109194,7 @@ SQLITE_PRIVATE void sqlite3RegisterBuiltinFunctions(sqlite3 *db){
    + */
    + static void setLikeOptFlag(sqlite3 *db, const char *zName, u8 flagVal){
    +   FuncDef *pDef;
    +-  pDef = sqlite3FindFunction(db, zName, sqlite3Strlen30(zName),
    +-                             2, SQLITE_UTF8, 0);
    ++  pDef = sqlite3FindFunction(db, zName, 2, SQLITE_UTF8, 0);
    +   if( ALWAYS(pDef) ){
    +     pDef->funcFlags |= flagVal;
    +   }
    +@@ -100215,9 +109224,14 @@ SQLITE_PRIVATE void sqlite3RegisterLikeFunctions(sqlite3 *db, int caseSensitive)
    + /*
    + ** pExpr points to an expression which implements a function.  If
    + ** it is appropriate to apply the LIKE optimization to that function
    +-** then set aWc[0] through aWc[2] to the wildcard characters and
    +-** return TRUE.  If the function is not a LIKE-style function then
    +-** return FALSE.
    ++** then set aWc[0] through aWc[2] to the wildcard characters and the
    ++** escape character and then return TRUE.  If the function is not a 
    ++** LIKE-style function then return FALSE.
    ++**
    ++** The expression "a LIKE b ESCAPE c" is only considered a valid LIKE
    ++** operator if c is a string literal that is exactly one byte in length.
    ++** That one byte is stored in aWc[3].  aWc[3] is set to zero if there is
    ++** no ESCAPE clause.
    + **
    + ** *pIsNocase is set to true if uppercase and lowercase are equivalent for
    + ** the function (default for LIKE).  If the function makes the distinction
    +@@ -100226,19 +109240,26 @@ SQLITE_PRIVATE void sqlite3RegisterLikeFunctions(sqlite3 *db, int caseSensitive)
    + */
    + SQLITE_PRIVATE int sqlite3IsLikeFunction(sqlite3 *db, Expr *pExpr, int *pIsNocase, char *aWc){
    +   FuncDef *pDef;
    +-  if( pExpr->op!=TK_FUNCTION 
    +-   || !pExpr->x.pList 
    +-   || pExpr->x.pList->nExpr!=2
    +-  ){
    ++  int nExpr;
    ++  if( pExpr->op!=TK_FUNCTION || !pExpr->x.pList ){
    +     return 0;
    +   }
    +   assert( !ExprHasProperty(pExpr, EP_xIsSelect) );
    +-  pDef = sqlite3FindFunction(db, pExpr->u.zToken, 
    +-                             sqlite3Strlen30(pExpr->u.zToken),
    +-                             2, SQLITE_UTF8, 0);
    ++  nExpr = pExpr->x.pList->nExpr;
    ++  pDef = sqlite3FindFunction(db, pExpr->u.zToken, nExpr, SQLITE_UTF8, 0);
    +   if( NEVER(pDef==0) || (pDef->funcFlags & SQLITE_FUNC_LIKE)==0 ){
    +     return 0;
    +   }
    ++  if( nExpr<3 ){
    ++    aWc[3] = 0;
    ++  }else{
    ++    Expr *pEscape = pExpr->x.pList->a[2].pExpr;
    ++    char *zEscape;
    ++    if( pEscape->op!=TK_STRING ) return 0;
    ++    zEscape = pEscape->u.zToken;
    ++    if( zEscape[0]==0 || zEscape[1]!=0 ) return 0;
    ++    aWc[3] = zEscape[0];
    ++  }
    + 
    +   /* The memcpy() statement assumes that the wildcard characters are
    +   ** the first three statements in the compareInfo structure.  The
    +@@ -100259,7 +109280,7 @@ SQLITE_PRIVATE int sqlite3IsLikeFunction(sqlite3 *db, Expr *pExpr, int *pIsNocas
    + **
    + ** After this routine runs
    + */
    +-SQLITE_PRIVATE void sqlite3RegisterGlobalFunctions(void){
    ++SQLITE_PRIVATE void sqlite3RegisterBuiltinFunctions(void){
    +   /*
    +   ** The following array holds FuncDef structures for all of the functions
    +   ** defined in this file.
    +@@ -100267,8 +109288,34 @@ SQLITE_PRIVATE void sqlite3RegisterGlobalFunctions(void){
    +   ** The array cannot be constant since changes are made to the
    +   ** FuncDef.pHash elements at start-time.  The elements of this array
    +   ** are read-only after initialization is complete.
    ++  **
    ++  ** For peak efficiency, put the most frequently used function last.
    +   */
    +-  static SQLITE_WSD FuncDef aBuiltinFunc[] = {
    ++  static FuncDef aBuiltinFunc[] = {
    ++#ifdef SQLITE_SOUNDEX
    ++    FUNCTION(soundex,            1, 0, 0, soundexFunc      ),
    ++#endif
    ++#ifndef SQLITE_OMIT_LOAD_EXTENSION
    ++    VFUNCTION(load_extension,    1, 0, 0, loadExt          ),
    ++    VFUNCTION(load_extension,    2, 0, 0, loadExt          ),
    ++#endif
    ++#if SQLITE_USER_AUTHENTICATION
    ++    FUNCTION(sqlite_crypt,       2, 0, 0, sqlite3CryptFunc ),
    ++#endif
    ++#ifndef SQLITE_OMIT_COMPILEOPTION_DIAGS
    ++    DFUNCTION(sqlite_compileoption_used,1, 0, 0, compileoptionusedFunc  ),
    ++    DFUNCTION(sqlite_compileoption_get, 1, 0, 0, compileoptiongetFunc  ),
    ++#endif /* SQLITE_OMIT_COMPILEOPTION_DIAGS */
    ++    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),
    ++#ifdef SQLITE_DEBUG
    ++    FUNCTION2(affinity,          1, 0, 0, noopFunc,  SQLITE_FUNC_AFFINITY),
    ++#endif
    ++#ifdef SQLITE_ENABLE_OFFSET_SQL_FUNC
    ++    FUNCTION2(sqlite_offset,     1, 0, 0, noopFunc,  SQLITE_FUNC_OFFSET|
    ++                                                     SQLITE_FUNC_TYPEOF),
    ++#endif
    +     FUNCTION(ltrim,              1, 1, 0, trimFunc         ),
    +     FUNCTION(ltrim,              2, 1, 0, trimFunc         ),
    +     FUNCTION(rtrim,              1, 2, 0, trimFunc         ),
    +@@ -100286,8 +109333,6 @@ SQLITE_PRIVATE void sqlite3RegisterGlobalFunctions(void){
    +     FUNCTION2(typeof,            1, 0, 0, typeofFunc,  SQLITE_FUNC_TYPEOF),
    +     FUNCTION2(length,            1, 0, 0, lengthFunc,  SQLITE_FUNC_LENGTH),
    +     FUNCTION(instr,              2, 0, 0, instrFunc        ),
    +-    FUNCTION(substr,             2, 0, 0, substrFunc       ),
    +-    FUNCTION(substr,             3, 0, 0, substrFunc       ),
    +     FUNCTION(printf,            -1, 0, 0, printfFunc       ),
    +     FUNCTION(unicode,            1, 0, 0, unicodeFunc      ),
    +     FUNCTION(char,              -1, 0, 0, charFunc         ),
    +@@ -100298,40 +109343,22 @@ SQLITE_PRIVATE void sqlite3RegisterGlobalFunctions(void){
    + #endif
    +     FUNCTION(upper,              1, 0, 0, upperFunc        ),
    +     FUNCTION(lower,              1, 0, 0, lowerFunc        ),
    +-    FUNCTION(coalesce,           1, 0, 0, 0                ),
    +-    FUNCTION(coalesce,           0, 0, 0, 0                ),
    +-    FUNCTION2(coalesce,         -1, 0, 0, noopFunc,  SQLITE_FUNC_COALESCE),
    +     FUNCTION(hex,                1, 0, 0, hexFunc          ),
    +     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       ),
    +     DFUNCTION(sqlite_version,    0, 0, 0, versionFunc      ),
    +     DFUNCTION(sqlite_source_id,  0, 0, 0, sourceidFunc     ),
    +     FUNCTION(sqlite_log,         2, 0, 0, errlogFunc       ),
    +-#if SQLITE_USER_AUTHENTICATION
    +-    FUNCTION(sqlite_crypt,       2, 0, 0, sqlite3CryptFunc ),
    +-#endif
    +-#ifndef SQLITE_OMIT_COMPILEOPTION_DIAGS
    +-    DFUNCTION(sqlite_compileoption_used,1, 0, 0, compileoptionusedFunc  ),
    +-    DFUNCTION(sqlite_compileoption_get, 1, 0, 0, compileoptiongetFunc  ),
    +-#endif /* SQLITE_OMIT_COMPILEOPTION_DIAGS */
    +     FUNCTION(quote,              1, 0, 0, quoteFunc        ),
    +     VFUNCTION(last_insert_rowid, 0, 0, 0, last_insert_rowid),
    +     VFUNCTION(changes,           0, 0, 0, changes          ),
    +     VFUNCTION(total_changes,     0, 0, 0, total_changes    ),
    +     FUNCTION(replace,            3, 0, 0, replaceFunc      ),
    +     FUNCTION(zeroblob,           1, 0, 0, zeroblobFunc     ),
    +-  #ifdef SQLITE_SOUNDEX
    +-    FUNCTION(soundex,            1, 0, 0, soundexFunc      ),
    +-  #endif
    +-  #ifndef SQLITE_OMIT_LOAD_EXTENSION
    +-    VFUNCTION(load_extension,    1, 0, 0, loadExt          ),
    +-    VFUNCTION(load_extension,    2, 0, 0, loadExt          ),
    +-  #endif
    ++    FUNCTION(substr,             2, 0, 0, substrFunc       ),
    ++    FUNCTION(substr,             3, 0, 0, substrFunc       ),
    +     AGGREGATE(sum,               1, 0, 0, sumStep,         sumFinalize    ),
    +     AGGREGATE(total,             1, 0, 0, sumStep,         totalFinalize    ),
    +     AGGREGATE(avg,               1, 0, 0, sumStep,         avgFinalize    ),
    +@@ -100342,28 +109369,43 @@ SQLITE_PRIVATE void sqlite3RegisterGlobalFunctions(void){
    +     AGGREGATE(group_concat,      2, 0, 0, groupConcatStep, groupConcatFinalize),
    +   
    +     LIKEFUNC(glob, 2, &globInfo, SQLITE_FUNC_LIKE|SQLITE_FUNC_CASE),
    +-  #ifdef SQLITE_CASE_SENSITIVE_LIKE
    ++#ifdef SQLITE_CASE_SENSITIVE_LIKE
    +     LIKEFUNC(like, 2, &likeInfoAlt, SQLITE_FUNC_LIKE|SQLITE_FUNC_CASE),
    +     LIKEFUNC(like, 3, &likeInfoAlt, SQLITE_FUNC_LIKE|SQLITE_FUNC_CASE),
    +-  #else
    ++#else
    +     LIKEFUNC(like, 2, &likeInfoNorm, SQLITE_FUNC_LIKE),
    +     LIKEFUNC(like, 3, &likeInfoNorm, SQLITE_FUNC_LIKE),
    +-  #endif
    ++#endif
    ++#ifdef SQLITE_ENABLE_UNKNOWN_SQL_FUNCTION
    ++    FUNCTION(unknown,           -1, 0, 0, unknownFunc      ),
    ++#endif
    ++    FUNCTION(coalesce,           1, 0, 0, 0                ),
    ++    FUNCTION(coalesce,           0, 0, 0, 0                ),
    ++    FUNCTION2(coalesce,         -1, 0, 0, noopFunc,  SQLITE_FUNC_COALESCE),
    +   };
    +-
    +-  int i;
    +-  FuncDefHash *pHash = &GLOBAL(FuncDefHash, sqlite3GlobalFunctions);
    +-  FuncDef *aFunc = (FuncDef*)&GLOBAL(FuncDef, aBuiltinFunc);
    +-
    +-  for(i=0; i<ArraySize(aBuiltinFunc); i++){
    +-    sqlite3FuncDefInsert(pHash, &aFunc[i]);
    +-  }
    +-  sqlite3RegisterDateTimeFunctions();
    + #ifndef SQLITE_OMIT_ALTERTABLE
    +   sqlite3AlterFunctions();
    + #endif
    + #if defined(SQLITE_ENABLE_STAT3) || defined(SQLITE_ENABLE_STAT4)
    +   sqlite3AnalyzeFunctions();
    ++#endif
    ++  sqlite3RegisterDateTimeFunctions();
    ++  sqlite3InsertBuiltinFuncs(aBuiltinFunc, ArraySize(aBuiltinFunc));
    ++
    ++#if 0  /* Enable to print out how the built-in functions are hashed */
    ++  {
    ++    int i;
    ++    FuncDef *p;
    ++    for(i=0; i<SQLITE_FUNC_HASH_SZ; i++){
    ++      printf("FUNC-HASH %02d:", i);
    ++      for(p=sqlite3BuiltinFunctions.a[i]; p; p=p->u.pHash){
    ++        int n = sqlite3Strlen30(p->zName);
    ++        int h = p->zName[0] + n;
    ++        printf(" %s(%d)", p->zName, h);
    ++      }
    ++      printf("\n");
    ++    }
    ++  }
    + #endif
    + }
    + 
    +@@ -100590,13 +109632,13 @@ SQLITE_PRIVATE int sqlite3FkLocateIndex(
    +     }
    +   }else if( paiCol ){
    +     assert( nCol>1 );
    +-    aiCol = (int *)sqlite3DbMallocRaw(pParse->db, nCol*sizeof(int));
    ++    aiCol = (int *)sqlite3DbMallocRawNN(pParse->db, nCol*sizeof(int));
    +     if( !aiCol ) return 1;
    +     *paiCol = aiCol;
    +   }
    + 
    +   for(pIdx=pParent->pIndex; pIdx; pIdx=pIdx->pNext){
    +-    if( pIdx->nKeyCol==nCol && IsUniqueIndex(pIdx) ){ 
    ++    if( pIdx->nKeyCol==nCol && IsUniqueIndex(pIdx) && pIdx->pPartIdxWhere==0 ){ 
    +       /* 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.  */
    +@@ -100620,7 +109662,7 @@ SQLITE_PRIVATE int sqlite3FkLocateIndex(
    +         int i, j;
    +         for(i=0; i<nCol; i++){
    +           i16 iCol = pIdx->aiColumn[i];     /* Index of column in parent tbl */
    +-          char *zDfltColl;                  /* Def. collation for column */
    ++          const char *zDfltColl;            /* Def. collation for column */
    +           char *zIdxCol;                    /* Name of indexed column */
    + 
    +           if( iCol<0 ) break; /* No foreign keys against expression indexes */
    +@@ -100629,9 +109671,7 @@ SQLITE_PRIVATE int sqlite3FkLocateIndex(
    +           ** the default collation sequence for the column, this index is
    +           ** unusable. Bail out early in this case.  */
    +           zDfltColl = pParent->aCol[iCol].zColl;
    +-          if( !zDfltColl ){
    +-            zDfltColl = "BINARY";
    +-          }
    ++          if( !zDfltColl ) zDfltColl = sqlite3StrBINARY;
    +           if( sqlite3StrICmp(pIdx->azColl[i], zDfltColl) ) break;
    + 
    +           zIdxCol = pParent->aCol[iCol].zName;
    +@@ -100957,7 +109997,7 @@ static void fkScanChildren(
    +     assert( iCol>=0 );
    +     zCol = pFKey->pFrom->aCol[iCol].zName;
    +     pRight = sqlite3Expr(db, TK_ID, zCol);
    +-    pEq = sqlite3PExpr(pParse, TK_EQ, pLeft, pRight, 0);
    ++    pEq = sqlite3PExpr(pParse, TK_EQ, pLeft, pRight);
    +     pWhere = sqlite3ExprAnd(db, pWhere, pEq);
    +   }
    + 
    +@@ -100979,7 +110019,7 @@ static void fkScanChildren(
    +     if( HasRowid(pTab) ){
    +       pLeft = exprTableRegister(pParse, pTab, regData, -1);
    +       pRight = exprTableColumn(db, pTab, pSrc->a[0].iCursor, -1);
    +-      pNe = sqlite3PExpr(pParse, TK_NE, pLeft, pRight, 0);
    ++      pNe = sqlite3PExpr(pParse, TK_NE, pLeft, pRight);
    +     }else{
    +       Expr *pEq, *pAll = 0;
    +       Index *pPk = sqlite3PrimaryKeyIndex(pTab);
    +@@ -100989,10 +110029,10 @@ static void fkScanChildren(
    +         assert( iCol>=0 );
    +         pLeft = exprTableRegister(pParse, pTab, regData, iCol);
    +         pRight = exprTableColumn(db, pTab, pSrc->a[0].iCursor, iCol);
    +-        pEq = sqlite3PExpr(pParse, TK_EQ, pLeft, pRight, 0);
    ++        pEq = sqlite3PExpr(pParse, TK_EQ, pLeft, pRight);
    +         pAll = sqlite3ExprAnd(db, pAll, pEq);
    +       }
    +-      pNe = sqlite3PExpr(pParse, TK_NOT, pAll, 0, 0);
    ++      pNe = sqlite3PExpr(pParse, TK_NOT, pAll, 0);
    +     }
    +     pWhere = sqlite3ExprAnd(db, pWhere, pNe);
    +   }
    +@@ -101006,10 +110046,12 @@ static void fkScanChildren(
    +   /* Create VDBE to loop through the entries in pSrc that match the WHERE
    +   ** clause. For each row found, increment either the deferred or immediate
    +   ** foreign key constraint counter. */
    +-  pWInfo = sqlite3WhereBegin(pParse, pSrc, pWhere, 0, 0, 0, 0);
    +-  sqlite3VdbeAddOp2(v, OP_FkCounter, pFKey->isDeferred, nIncr);
    +-  if( pWInfo ){
    +-    sqlite3WhereEnd(pWInfo);
    ++  if( pParse->nErr==0 ){
    ++    pWInfo = sqlite3WhereBegin(pParse, pSrc, pWhere, 0, 0, 0, 0);
    ++    sqlite3VdbeAddOp2(v, OP_FkCounter, pFKey->isDeferred, nIncr);
    ++    if( pWInfo ){
    ++      sqlite3WhereEnd(pWInfo);
    ++    }
    +   }
    + 
    +   /* Clean up the WHERE clause constructed above. */
    +@@ -101096,7 +110138,7 @@ SQLITE_PRIVATE void sqlite3FkDropTable(Parse *pParse, SrcList *pName, Table *pTa
    +     }
    + 
    +     pParse->disableTriggers = 1;
    +-    sqlite3DeleteFrom(pParse, sqlite3SrcListDup(db, pName, 0), 0);
    ++    sqlite3DeleteFrom(pParse, sqlite3SrcListDup(db, pName, 0), 0, 0, 0);
    +     pParse->disableTriggers = 0;
    + 
    +     /* If the DELETE has generated immediate foreign key constraint 
    +@@ -101244,7 +110286,7 @@ SQLITE_PRIVATE void sqlite3FkCheck(
    +   if( (db->flags&SQLITE_ForeignKeys)==0 ) return;
    + 
    +   iDb = sqlite3SchemaToIndex(db, pTab->pSchema);
    +-  zDb = db->aDb[iDb].zName;
    ++  zDb = db->aDb[iDb].zDbSName;
    + 
    +   /* Loop through all the foreign key constraints for which pTab is the
    +   ** child table (the table that the foreign key definition is part of).  */
    +@@ -101380,7 +110422,7 @@ SQLITE_PRIVATE void sqlite3FkCheck(
    +       struct SrcList_item *pItem = pSrc->a;
    +       pItem->pTab = pFKey->pFrom;
    +       pItem->zName = pFKey->pFrom->zName;
    +-      pItem->pTab->nRef++;
    ++      pItem->pTab->nTabRef++;
    +       pItem->iCursor = pParse->nTab++;
    +   
    +       if( regNew!=0 ){
    +@@ -101460,8 +110502,16 @@ SQLITE_PRIVATE u32 sqlite3FkOldmask(
    + ** UPDATE statement modifies the rowid fields of the table.
    + **
    + ** If any foreign key processing will be required, this function returns
    +-** true. If there is no foreign key related processing, this function 
    +-** returns false.
    ++** non-zero. If there is no foreign key related processing, this function 
    ++** returns zero.
    ++**
    ++** For an UPDATE, this function returns 2 if:
    ++**
    ++**   * There are any FKs for which pTab is the child and the parent table, or
    ++**   * the UPDATE modifies one or more parent keys for which the action is
    ++**     not "NO ACTION" (i.e. is CASCADE, SET DEFAULT or SET NULL).
    ++**
    ++** Or, assuming some other foreign key processing is required, 1.
    + */
    + SQLITE_PRIVATE int sqlite3FkRequired(
    +   Parse *pParse,                  /* Parse context */
    +@@ -101469,12 +110519,13 @@ SQLITE_PRIVATE int sqlite3FkRequired(
    +   int *aChange,                   /* Non-NULL for UPDATE operations */
    +   int chngRowid                   /* True for UPDATE that affects rowid */
    + ){
    ++  int eRet = 0;
    +   if( pParse->db->flags&SQLITE_ForeignKeys ){
    +     if( !aChange ){
    +       /* A DELETE operation. Foreign key processing is required if the 
    +       ** table in question is either the child or parent table for any 
    +       ** foreign key constraint.  */
    +-      return (sqlite3FkReferences(pTab) || pTab->pFKey);
    ++      eRet = (sqlite3FkReferences(pTab) || pTab->pFKey);
    +     }else{
    +       /* This is an UPDATE. Foreign key processing is only required if the
    +       ** operation modifies one or more child or parent key columns. */
    +@@ -101482,16 +110533,22 @@ SQLITE_PRIVATE int sqlite3FkRequired(
    + 
    +       /* Check if any child key columns are being modified. */
    +       for(p=pTab->pFKey; p; p=p->pNextFrom){
    +-        if( fkChildIsModified(pTab, p, aChange, chngRowid) ) return 1;
    ++        if( 0==sqlite3_stricmp(pTab->zName, p->zTo) ) return 2;
    ++        if( fkChildIsModified(pTab, p, aChange, chngRowid) ){
    ++          eRet = 1;
    ++        }
    +       }
    + 
    +       /* Check if any parent key columns are being modified. */
    +       for(p=sqlite3FkReferences(pTab); p; p=p->pNextTo){
    +-        if( fkParentIsModified(pTab, p, aChange, chngRowid) ) return 1;
    ++        if( fkParentIsModified(pTab, p, aChange, chngRowid) ){
    ++          if( p->aAction[1]!=OE_None ) return 2;
    ++          eRet = 1;
    ++        }
    +       }
    +     }
    +   }
    +-  return 0;
    ++  return eRet;
    + }
    + 
    + /*
    +@@ -101535,10 +110592,12 @@ static Trigger *fkActionTrigger(
    +   int iAction = (pChanges!=0);    /* 1 for UPDATE, 0 for DELETE */
    + 
    +   action = pFKey->aAction[iAction];
    ++  if( action==OE_Restrict && (db->flags & SQLITE_DeferFKs) ){
    ++    return 0;
    ++  }
    +   pTrigger = pFKey->apTrigger[iAction];
    + 
    +   if( action!=OE_None && !pTrigger ){
    +-    u8 enableLookaside;           /* Copy of db->lookaside.bEnabled */
    +     char const *zFrom;            /* Name of child table */
    +     int nFrom;                    /* Length in bytes of zFrom */
    +     Index *pIdx = 0;              /* Parent key index for this FK */
    +@@ -101565,11 +110624,9 @@ static Trigger *fkActionTrigger(
    +       assert( iFromCol>=0 );
    +       assert( pIdx!=0 || (pTab->iPKey>=0 && pTab->iPKey<pTab->nCol) );
    +       assert( pIdx==0 || pIdx->aiColumn[i]>=0 );
    +-      tToCol.z = pTab->aCol[pIdx ? pIdx->aiColumn[i] : pTab->iPKey].zName;
    +-      tFromCol.z = pFKey->pFrom->aCol[iFromCol].zName;
    +-
    +-      tToCol.n = sqlite3Strlen30(tToCol.z);
    +-      tFromCol.n = sqlite3Strlen30(tFromCol.z);
    ++      sqlite3TokenInit(&tToCol,
    ++                   pTab->aCol[pIdx ? pIdx->aiColumn[i] : pTab->iPKey].zName);
    ++      sqlite3TokenInit(&tFromCol, pFKey->pFrom->aCol[iFromCol].zName);
    + 
    +       /* Create the expression "OLD.zToCol = zFromCol". It is important
    +       ** that the "OLD.zToCol" term is on the LHS of the = operator, so
    +@@ -101578,10 +110635,9 @@ static Trigger *fkActionTrigger(
    +       pEq = sqlite3PExpr(pParse, TK_EQ,
    +           sqlite3PExpr(pParse, TK_DOT, 
    +             sqlite3ExprAlloc(db, TK_ID, &tOld, 0),
    +-            sqlite3ExprAlloc(db, TK_ID, &tToCol, 0)
    +-          , 0),
    ++            sqlite3ExprAlloc(db, TK_ID, &tToCol, 0)),
    +           sqlite3ExprAlloc(db, TK_ID, &tFromCol, 0)
    +-      , 0);
    ++      );
    +       pWhere = sqlite3ExprAnd(db, pWhere, pEq);
    + 
    +       /* For ON UPDATE, construct the next term of the WHEN clause.
    +@@ -101593,13 +110649,11 @@ static Trigger *fkActionTrigger(
    +         pEq = sqlite3PExpr(pParse, TK_IS,
    +             sqlite3PExpr(pParse, TK_DOT, 
    +               sqlite3ExprAlloc(db, TK_ID, &tOld, 0),
    +-              sqlite3ExprAlloc(db, TK_ID, &tToCol, 0),
    +-              0),
    ++              sqlite3ExprAlloc(db, TK_ID, &tToCol, 0)),
    +             sqlite3PExpr(pParse, TK_DOT, 
    +               sqlite3ExprAlloc(db, TK_ID, &tNew, 0),
    +-              sqlite3ExprAlloc(db, TK_ID, &tToCol, 0),
    +-              0),
    +-            0);
    ++              sqlite3ExprAlloc(db, TK_ID, &tToCol, 0))
    ++            );
    +         pWhen = sqlite3ExprAnd(db, pWhen, pEq);
    +       }
    +   
    +@@ -101608,17 +110662,16 @@ static Trigger *fkActionTrigger(
    +         if( action==OE_Cascade ){
    +           pNew = sqlite3PExpr(pParse, TK_DOT, 
    +             sqlite3ExprAlloc(db, TK_ID, &tNew, 0),
    +-            sqlite3ExprAlloc(db, TK_ID, &tToCol, 0)
    +-          , 0);
    ++            sqlite3ExprAlloc(db, TK_ID, &tToCol, 0));
    +         }else if( action==OE_SetDflt ){
    +           Expr *pDflt = pFKey->pFrom->aCol[iFromCol].pDflt;
    +           if( pDflt ){
    +             pNew = sqlite3ExprDup(db, pDflt, 0);
    +           }else{
    +-            pNew = sqlite3PExpr(pParse, TK_NULL, 0, 0, 0);
    ++            pNew = sqlite3ExprAlloc(db, TK_NULL, 0, 0);
    +           }
    +         }else{
    +-          pNew = sqlite3PExpr(pParse, TK_NULL, 0, 0, 0);
    ++          pNew = sqlite3ExprAlloc(db, TK_NULL, 0, 0);
    +         }
    +         pList = sqlite3ExprListAppend(pParse, pList, pNew);
    +         sqlite3ExprListSetName(pParse, pList, &tFromCol, 0);
    +@@ -101643,14 +110696,13 @@ static Trigger *fkActionTrigger(
    +           sqlite3ExprListAppend(pParse, 0, pRaise),
    +           sqlite3SrcListAppend(db, 0, &tFrom, 0),
    +           pWhere,
    +-          0, 0, 0, 0, 0, 0
    ++          0, 0, 0, 0, 0
    +       );
    +       pWhere = 0;
    +     }
    + 
    +     /* Disable lookaside memory allocation */
    +-    enableLookaside = db->lookaside.bEnabled;
    +-    db->lookaside.bEnabled = 0;
    ++    db->lookaside.bDisable++;
    + 
    +     pTrigger = (Trigger *)sqlite3DbMallocZero(db, 
    +         sizeof(Trigger) +         /* struct Trigger */
    +@@ -101666,13 +110718,13 @@ static Trigger *fkActionTrigger(
    +       pStep->pExprList = sqlite3ExprListDup(db, pList, EXPRDUP_REDUCE);
    +       pStep->pSelect = sqlite3SelectDup(db, pSelect, EXPRDUP_REDUCE);
    +       if( pWhen ){
    +-        pWhen = sqlite3PExpr(pParse, TK_NOT, pWhen, 0, 0);
    ++        pWhen = sqlite3PExpr(pParse, TK_NOT, pWhen, 0);
    +         pTrigger->pWhen = sqlite3ExprDup(db, pWhen, EXPRDUP_REDUCE);
    +       }
    +     }
    + 
    +     /* Re-enable the lookaside buffer, if it was disabled earlier. */
    +-    db->lookaside.bEnabled = enableLookaside;
    ++    db->lookaside.bDisable--;
    + 
    +     sqlite3ExprDelete(db, pWhere);
    +     sqlite3ExprDelete(db, pWhen);
    +@@ -101746,7 +110798,8 @@ SQLITE_PRIVATE void sqlite3FkDelete(sqlite3 *db, Table *pTab){
    +   FKey *pFKey;                    /* Iterator variable */
    +   FKey *pNext;                    /* Copy of pFKey->pNextFrom */
    + 
    +-  assert( db==0 || sqlite3SchemaMutexHeld(db, 0, pTab->pSchema) );
    ++  assert( db==0 || IsVirtual(pTab)
    ++         || sqlite3SchemaMutexHeld(db, 0, pTab->pSchema) );
    +   for(pFKey=pTab->pFKey; pFKey; pFKey=pNext){
    + 
    +     /* Remove the FK from the fkeyHash hash table. */
    +@@ -101867,7 +110920,7 @@ SQLITE_PRIVATE const char *sqlite3IndexAffinityStr(sqlite3 *db, Index *pIdx){
    +     Table *pTab = pIdx->pTable;
    +     pIdx->zColAff = (char *)sqlite3DbMallocRaw(0, pIdx->nColumn+1);
    +     if( !pIdx->zColAff ){
    +-      db->mallocFailed = 1;
    ++      sqlite3OomFault(db);
    +       return 0;
    +     }
    +     for(n=0; n<pIdx->nColumn; n++){
    +@@ -101918,7 +110971,7 @@ SQLITE_PRIVATE void sqlite3TableAffinity(Vdbe *v, Table *pTab, int iReg){
    +     sqlite3 *db = sqlite3VdbeDb(v);
    +     zColAff = (char *)sqlite3DbMallocRaw(0, pTab->nCol+1);
    +     if( !zColAff ){
    +-      db->mallocFailed = 1;
    ++      sqlite3OomFault(db);
    +       return;
    +     }
    + 
    +@@ -101984,7 +111037,9 @@ static int readsTable(Parse *p, int iDb, Table *pTab){
    + /*
    + ** Locate or create an AutoincInfo structure associated with table pTab
    + ** which is in database iDb.  Return the register number for the register
    +-** that holds the maximum rowid.
    ++** that holds the maximum rowid.  Return zero if pTab is not an AUTOINCREMENT
    ++** table.  (Also return zero when doing a VACUUM since we do not want to
    ++** update the AUTOINCREMENT counters during a VACUUM.)
    + **
    + ** There is at most one AutoincInfo structure per table even if the
    + ** same table is autoincremented multiple times due to inserts within
    +@@ -102007,14 +111062,16 @@ static int autoIncBegin(
    +   Table *pTab         /* The table we are writing to */
    + ){
    +   int memId = 0;      /* Register holding maximum rowid */
    +-  if( pTab->tabFlags & TF_Autoincrement ){
    ++  if( (pTab->tabFlags & TF_Autoincrement)!=0
    ++   && (pParse->db->mDbFlags & DBFLAG_Vacuum)==0
    ++  ){
    +     Parse *pToplevel = sqlite3ParseToplevel(pParse);
    +     AutoincInfo *pInfo;
    + 
    +     pInfo = pToplevel->pAinc;
    +     while( pInfo && pInfo->pTab!=pTab ){ pInfo = pInfo->pNext; }
    +     if( pInfo==0 ){
    +-      pInfo = sqlite3DbMallocRaw(pParse->db, sizeof(*pInfo));
    ++      pInfo = sqlite3DbMallocRawNN(pParse->db, sizeof(*pInfo));
    +       if( pInfo==0 ) return 0;
    +       pInfo->pNext = pToplevel->pAinc;
    +       pToplevel->pAinc = pInfo;
    +@@ -102038,7 +111095,6 @@ SQLITE_PRIVATE void sqlite3AutoincrementBegin(Parse *pParse){
    +   sqlite3 *db = pParse->db;  /* The database connection */
    +   Db *pDb;                   /* Database only autoinc table */
    +   int memId;                 /* Register holding max rowid */
    +-  int addr;                  /* A VDBE address */
    +   Vdbe *v = pParse->pVdbe;   /* VDBE under construction */
    + 
    +   /* This routine is never called during trigger-generation.  It is
    +@@ -102048,33 +111104,46 @@ SQLITE_PRIVATE void sqlite3AutoincrementBegin(Parse *pParse){
    + 
    +   assert( v );   /* We failed long ago if this is not so */
    +   for(p = pParse->pAinc; p; p = p->pNext){
    ++    static const int iLn = VDBE_OFFSET_LINENO(2);
    ++    static const VdbeOpList autoInc[] = {
    ++      /* 0  */ {OP_Null,    0,  0, 0},
    ++      /* 1  */ {OP_Rewind,  0,  9, 0},
    ++      /* 2  */ {OP_Column,  0,  0, 0},
    ++      /* 3  */ {OP_Ne,      0,  7, 0},
    ++      /* 4  */ {OP_Rowid,   0,  0, 0},
    ++      /* 5  */ {OP_Column,  0,  1, 0},
    ++      /* 6  */ {OP_Goto,    0,  9, 0},
    ++      /* 7  */ {OP_Next,    0,  2, 0},
    ++      /* 8  */ {OP_Integer, 0,  0, 0},
    ++      /* 9  */ {OP_Close,   0,  0, 0} 
    ++    };
    ++    VdbeOp *aOp;
    +     pDb = &db->aDb[p->iDb];
    +     memId = p->regCtr;
    +     assert( sqlite3SchemaMutexHeld(db, 0, pDb->pSchema) );
    +     sqlite3OpenTable(pParse, 0, p->iDb, pDb->pSchema->pSeqTab, OP_OpenRead);
    +-    sqlite3VdbeAddOp3(v, OP_Null, 0, memId, memId+1);
    +-    addr = sqlite3VdbeCurrentAddr(v);
    +     sqlite3VdbeLoadString(v, memId-1, p->pTab->zName);
    +-    sqlite3VdbeAddOp2(v, OP_Rewind, 0, addr+9); VdbeCoverage(v);
    +-    sqlite3VdbeAddOp3(v, OP_Column, 0, 0, memId);
    +-    sqlite3VdbeAddOp3(v, OP_Ne, memId-1, addr+7, memId); VdbeCoverage(v);
    +-    sqlite3VdbeChangeP5(v, SQLITE_JUMPIFNULL);
    +-    sqlite3VdbeAddOp2(v, OP_Rowid, 0, memId+1);
    +-    sqlite3VdbeAddOp3(v, OP_Column, 0, 1, memId);
    +-    sqlite3VdbeGoto(v, addr+9);
    +-    sqlite3VdbeAddOp2(v, OP_Next, 0, addr+2); VdbeCoverage(v);
    +-    sqlite3VdbeAddOp2(v, OP_Integer, 0, memId);
    +-    sqlite3VdbeAddOp0(v, OP_Close);
    ++    aOp = sqlite3VdbeAddOpList(v, ArraySize(autoInc), autoInc, iLn);
    ++    if( aOp==0 ) break;
    ++    aOp[0].p2 = memId;
    ++    aOp[0].p3 = memId+1;
    ++    aOp[2].p3 = memId;
    ++    aOp[3].p1 = memId-1;
    ++    aOp[3].p3 = memId;
    ++    aOp[3].p5 = SQLITE_JUMPIFNULL;
    ++    aOp[4].p2 = memId+1;
    ++    aOp[5].p3 = memId;
    ++    aOp[8].p2 = memId;
    +   }
    + }
    + 
    + /*
    + ** Update the maximum rowid for an autoincrement calculation.
    + **
    +-** This routine should be called when the top of the stack holds a
    ++** This routine should be called when the regRowid register holds a
    + ** new rowid that is about to be inserted.  If that new rowid is
    + ** larger than the maximum rowid in the memId memory cell, then the
    +-** memory cell is updated.  The stack is unchanged.
    ++** memory cell is updated.
    + */
    + static void autoIncStep(Parse *pParse, int memId, int regRowid){
    +   if( memId>0 ){
    +@@ -102089,31 +111158,44 @@ static void autoIncStep(Parse *pParse, int memId, int regRowid){
    + ** table (either directly or through triggers) needs to call this
    + ** routine just before the "exit" code.
    + */
    +-SQLITE_PRIVATE void sqlite3AutoincrementEnd(Parse *pParse){
    ++static SQLITE_NOINLINE void autoIncrementEnd(Parse *pParse){
    +   AutoincInfo *p;
    +   Vdbe *v = pParse->pVdbe;
    +   sqlite3 *db = pParse->db;
    + 
    +   assert( v );
    +   for(p = pParse->pAinc; p; p = p->pNext){
    ++    static const int iLn = VDBE_OFFSET_LINENO(2);
    ++    static const VdbeOpList autoIncEnd[] = {
    ++      /* 0 */ {OP_NotNull,     0, 2, 0},
    ++      /* 1 */ {OP_NewRowid,    0, 0, 0},
    ++      /* 2 */ {OP_MakeRecord,  0, 2, 0},
    ++      /* 3 */ {OP_Insert,      0, 0, 0},
    ++      /* 4 */ {OP_Close,       0, 0, 0}
    ++    };
    ++    VdbeOp *aOp;
    +     Db *pDb = &db->aDb[p->iDb];
    +-    int addr1;
    +     int iRec;
    +     int memId = p->regCtr;
    + 
    +     iRec = sqlite3GetTempReg(pParse);
    +     assert( sqlite3SchemaMutexHeld(db, 0, pDb->pSchema) );
    +     sqlite3OpenTable(pParse, 0, p->iDb, pDb->pSchema->pSeqTab, OP_OpenWrite);
    +-    addr1 = sqlite3VdbeAddOp1(v, OP_NotNull, memId+1); VdbeCoverage(v);
    +-    sqlite3VdbeAddOp2(v, OP_NewRowid, 0, memId+1);
    +-    sqlite3VdbeJumpHere(v, addr1);
    +-    sqlite3VdbeAddOp3(v, OP_MakeRecord, memId-1, 2, iRec);
    +-    sqlite3VdbeAddOp3(v, OP_Insert, 0, iRec, memId+1);
    +-    sqlite3VdbeChangeP5(v, OPFLAG_APPEND);
    +-    sqlite3VdbeAddOp0(v, OP_Close);
    ++    aOp = sqlite3VdbeAddOpList(v, ArraySize(autoIncEnd), autoIncEnd, iLn);
    ++    if( aOp==0 ) break;
    ++    aOp[0].p1 = memId+1;
    ++    aOp[1].p2 = memId+1;
    ++    aOp[2].p1 = memId-1;
    ++    aOp[2].p3 = iRec;
    ++    aOp[3].p2 = iRec;
    ++    aOp[3].p3 = memId+1;
    ++    aOp[3].p5 = OPFLAG_APPEND;
    +     sqlite3ReleaseTempReg(pParse, iRec);
    +   }
    + }
    ++SQLITE_PRIVATE void sqlite3AutoincrementEnd(Parse *pParse){
    ++  if( pParse->pAinc ) autoIncrementEnd(pParse);
    ++}
    + #else
    + /*
    + ** If SQLITE_OMIT_AUTOINCREMENT is defined, then the three routines
    +@@ -102239,9 +111321,7 @@ SQLITE_PRIVATE void sqlite3Insert(
    + ){
    +   sqlite3 *db;          /* The main database structure */
    +   Table *pTab;          /* The table to insert into.  aka TABLE */
    +-  char *zTab;           /* Name of the table into which we are inserting */
    +-  const char *zDb;      /* Name of the database holding this table */
    +-  int i, j, idx;        /* Loop counters */
    ++  int i, j;             /* Loop counters */
    +   Vdbe *v;              /* Generate code into this virtual machine */
    +   Index *pIdx;          /* For looping over indices of the table */
    +   int nColumn;          /* Number of columns in the data */
    +@@ -102255,7 +111335,6 @@ SQLITE_PRIVATE void sqlite3Insert(
    +   int addrCont = 0;     /* Top of insert loop. Label "C" in templates 3 and 4 */
    +   SelectDest dest;      /* Destination for SELECT on rhs of INSERT */
    +   int iDb;              /* Index of database holding TABLE */
    +-  Db *pDb;              /* The database containing table being inserted into */
    +   u8 useTempTable = 0;  /* Store SELECT results in intermediate table */
    +   u8 appendFlag = 0;    /* True if the insert is likely to be an append */
    +   u8 withoutRowid;      /* 0 for normal table.  1 for WITHOUT ROWID table */
    +@@ -102278,10 +111357,10 @@ SQLITE_PRIVATE void sqlite3Insert(
    + #endif
    + 
    +   db = pParse->db;
    +-  memset(&dest, 0, sizeof(dest));
    +   if( pParse->nErr || db->mallocFailed ){
    +     goto insert_cleanup;
    +   }
    ++  dest.iSDParm = 0;  /* Suppress a harmless compiler warning */
    + 
    +   /* If the Select object is really just a simple VALUES() list with a
    +   ** single row (the common case) then keep that one row of values
    +@@ -102297,17 +111376,14 @@ SQLITE_PRIVATE void sqlite3Insert(
    +   /* Locate the table into which we will be inserting new information.
    +   */
    +   assert( pTabList->nSrc==1 );
    +-  zTab = pTabList->a[0].zName;
    +-  if( NEVER(zTab==0) ) goto insert_cleanup;
    +   pTab = sqlite3SrcListLookup(pParse, pTabList);
    +   if( pTab==0 ){
    +     goto insert_cleanup;
    +   }
    +   iDb = sqlite3SchemaToIndex(db, pTab->pSchema);
    +   assert( iDb<db->nDb );
    +-  pDb = &db->aDb[iDb];
    +-  zDb = pDb->zName;
    +-  if( sqlite3AuthCheck(pParse, SQLITE_INSERT, pTab->zName, 0, zDb) ){
    ++  if( sqlite3AuthCheck(pParse, SQLITE_INSERT, pTab->zName, 0,
    ++                       db->aDb[iDb].zDbSName) ){
    +     goto insert_cleanup;
    +   }
    +   withoutRowid = !HasRowid(pTab);
    +@@ -102444,7 +111520,7 @@ SQLITE_PRIVATE void sqlite3Insert(
    +     rc = sqlite3Select(pParse, pSelect, &dest);
    +     regFromSelect = dest.iSdst;
    +     if( rc || db->mallocFailed || pParse->nErr ) goto insert_cleanup;
    +-    sqlite3VdbeAddOp1(v, OP_EndCoroutine, regYield);
    ++    sqlite3VdbeEndCoroutine(v, regYield);
    +     sqlite3VdbeJumpHere(v, addrTop - 1);                       /* label B: */
    +     assert( pSelect->pEList );
    +     nColumn = pSelect->pEList->nExpr;
    +@@ -102520,10 +111596,8 @@ SQLITE_PRIVATE void sqlite3Insert(
    +   /* Make sure the number of columns in the source data matches the number
    +   ** of columns to be inserted into the table.
    +   */
    +-  if( IsVirtual(pTab) ){
    +-    for(i=0; i<pTab->nCol; i++){
    +-      nHidden += (IsHiddenColumn(&pTab->aCol[i]) ? 1 : 0);
    +-    }
    ++  for(i=0; i<pTab->nCol; i++){
    ++    nHidden += (IsHiddenColumn(&pTab->aCol[i]) ? 1 : 0);
    +   }
    +   if( pColumn==0 && nColumn && nColumn!=(pTab->nCol-nHidden) ){
    +     sqlite3ErrorMsg(pParse, 
    +@@ -102546,14 +111620,16 @@ SQLITE_PRIVATE void sqlite3Insert(
    +   /* If this is not a view, open the table and and all indices */
    +   if( !isView ){
    +     int nIdx;
    +-    nIdx = sqlite3OpenTableAndIndices(pParse, pTab, OP_OpenWrite, -1, 0,
    ++    nIdx = sqlite3OpenTableAndIndices(pParse, pTab, OP_OpenWrite, 0, -1, 0,
    +                                       &iDataCur, &iIdxCur);
    +-    aRegIdx = sqlite3DbMallocRaw(db, sizeof(int)*(nIdx+1));
    ++    aRegIdx = sqlite3DbMallocRawNN(db, sizeof(int)*(nIdx+1));
    +     if( aRegIdx==0 ){
    +       goto insert_cleanup;
    +     }
    +-    for(i=0; i<nIdx; i++){
    ++    for(i=0, pIdx=pTab->pIndex; i<nIdx; pIdx=pIdx->pNext, i++){
    ++      assert( pIdx );
    +       aRegIdx[i] = ++pParse->nMem;
    ++      pParse->nMem += pIdx->nColumn;
    +     }
    +   }
    + 
    +@@ -102619,15 +111695,14 @@ SQLITE_PRIVATE void sqlite3Insert(
    + 
    +     /* Create the new column data
    +     */
    +-    for(i=0; i<pTab->nCol; i++){
    +-      if( pColumn==0 ){
    +-        j = i;
    +-      }else{
    ++    for(i=j=0; i<pTab->nCol; i++){
    ++      if( pColumn ){
    +         for(j=0; j<pColumn->nId; j++){
    +           if( pColumn->a[j].idx==i ) break;
    +         }
    +       }
    +-      if( (!useTempTable && !pList) || (pColumn && j>=pColumn->nId) ){
    ++      if( (!useTempTable && !pList) || (pColumn && j>=pColumn->nId)
    ++            || (pColumn==0 && IsOrdinaryHiddenColumn(&pTab->aCol[i])) ){
    +         sqlite3ExprCode(pParse, pTab->aCol[i].pDflt, regCols+i+1);
    +       }else if( useTempTable ){
    +         sqlite3VdbeAddOp3(v, OP_Column, srcTab, j, regCols+i+1); 
    +@@ -102635,6 +111710,7 @@ SQLITE_PRIVATE void sqlite3Insert(
    +         assert( pSelect==0 ); /* Otherwise useTempTable is true */
    +         sqlite3ExprCodeAndCache(pParse, pList->a[j].pExpr, regCols+i+1);
    +       }
    ++      if( pColumn==0 && !IsOrdinaryHiddenColumn(&pTab->aCol[i]) ) j++;
    +     }
    + 
    +     /* If this is an INSERT on a view with an INSTEAD OF INSERT trigger,
    +@@ -102670,7 +111746,8 @@ SQLITE_PRIVATE void sqlite3Insert(
    +         VdbeOp *pOp;
    +         sqlite3ExprCode(pParse, pList->a[ipkColumn].pExpr, regRowid);
    +         pOp = sqlite3VdbeGetOp(v, -1);
    +-        if( ALWAYS(pOp) && pOp->opcode==OP_Null && !IsVirtual(pTab) ){
    ++        assert( pOp!=0 );
    ++        if( pOp->opcode==OP_Null && !IsVirtual(pTab) ){
    +           appendFlag = 1;
    +           pOp->opcode = OP_NewRowid;
    +           pOp->p1 = iDataCur;
    +@@ -102718,7 +111795,6 @@ SQLITE_PRIVATE void sqlite3Insert(
    +       }
    +       if( pColumn==0 ){
    +         if( IsHiddenColumn(&pTab->aCol[i]) ){
    +-          assert( IsVirtual(pTab) );
    +           j = -1;
    +           nHidden++;
    +         }else{
    +@@ -102756,12 +111832,26 @@ SQLITE_PRIVATE void sqlite3Insert(
    + #endif
    +     {
    +       int isReplace;    /* Set to true if constraints may cause a replace */
    ++      int bUseSeek;     /* True to use OPFLAG_SEEKRESULT */
    +       sqlite3GenerateConstraintChecks(pParse, pTab, aRegIdx, iDataCur, iIdxCur,
    +-          regIns, 0, ipkColumn>=0, onError, endOfLoop, &isReplace
    ++          regIns, 0, ipkColumn>=0, onError, endOfLoop, &isReplace, 0
    +       );
    +       sqlite3FkCheck(pParse, pTab, 0, regIns, 0, 0);
    ++
    ++      /* Set the OPFLAG_USESEEKRESULT flag if either (a) there are no REPLACE
    ++      ** constraints or (b) there are no triggers and this table is not a
    ++      ** parent table in a foreign key constraint. It is safe to set the
    ++      ** flag in the second case as if any REPLACE constraint is hit, an
    ++      ** OP_Delete or OP_IdxDelete instruction will be executed on each 
    ++      ** cursor that is disturbed. And these instructions both clear the
    ++      ** VdbeCursor.seekResult variable, disabling the OPFLAG_USESEEKRESULT
    ++      ** functionality.  */
    ++      bUseSeek = (isReplace==0 || (pTrigger==0 &&
    ++          ((db->flags & SQLITE_ForeignKeys)==0 || sqlite3FkReferences(pTab)==0)
    ++      ));
    +       sqlite3CompleteInsertion(pParse, pTab, iDataCur, iIdxCur,
    +-                               regIns, aRegIdx, 0, appendFlag, isReplace==0);
    ++          regIns, aRegIdx, 0, appendFlag, bUseSeek
    ++      );
    +     }
    +   }
    + 
    +@@ -102790,14 +111880,6 @@ SQLITE_PRIVATE void sqlite3Insert(
    +     sqlite3VdbeJumpHere(v, addrInsTop);
    +   }
    + 
    +-  if( !IsVirtual(pTab) && !isView ){
    +-    /* Close all tables opened */
    +-    if( iDataCur<iIdxCur ) sqlite3VdbeAddOp1(v, OP_Close, iDataCur);
    +-    for(idx=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, idx++){
    +-      sqlite3VdbeAddOp1(v, OP_Close, idx+iIdxCur);
    +-    }
    +-  }
    +-
    + insert_end:
    +   /* Update the sqlite_sequence table by storing the content of the
    +   ** maximum rowid counter values recorded while inserting into
    +@@ -102839,6 +111921,59 @@ insert_cleanup:
    +  #undef tmask
    + #endif
    + 
    ++/*
    ++** Meanings of bits in of pWalker->eCode for checkConstraintUnchanged()
    ++*/
    ++#define CKCNSTRNT_COLUMN   0x01    /* CHECK constraint uses a changing column */
    ++#define CKCNSTRNT_ROWID    0x02    /* CHECK constraint references the ROWID */
    ++
    ++/* This is the Walker callback from checkConstraintUnchanged().  Set
    ++** bit 0x01 of pWalker->eCode if
    ++** pWalker->eCode to 0 if this expression node references any of the
    ++** columns that are being modifed by an UPDATE statement.
    ++*/
    ++static int checkConstraintExprNode(Walker *pWalker, Expr *pExpr){
    ++  if( pExpr->op==TK_COLUMN ){
    ++    assert( pExpr->iColumn>=0 || pExpr->iColumn==-1 );
    ++    if( pExpr->iColumn>=0 ){
    ++      if( pWalker->u.aiCol[pExpr->iColumn]>=0 ){
    ++        pWalker->eCode |= CKCNSTRNT_COLUMN;
    ++      }
    ++    }else{
    ++      pWalker->eCode |= CKCNSTRNT_ROWID;
    ++    }
    ++  }
    ++  return WRC_Continue;
    ++}
    ++
    ++/*
    ++** pExpr is a CHECK constraint on a row that is being UPDATE-ed.  The
    ++** only columns that are modified by the UPDATE are those for which
    ++** aiChng[i]>=0, and also the ROWID is modified if chngRowid is true.
    ++**
    ++** Return true if CHECK constraint pExpr does not use any of the
    ++** changing columns (or the rowid if it is changing).  In other words,
    ++** return true if this CHECK constraint can be skipped when validating
    ++** the new row in the UPDATE statement.
    ++*/
    ++static int checkConstraintUnchanged(Expr *pExpr, int *aiChng, int chngRowid){
    ++  Walker w;
    ++  memset(&w, 0, sizeof(w));
    ++  w.eCode = 0;
    ++  w.xExprCallback = checkConstraintExprNode;
    ++  w.u.aiCol = aiChng;
    ++  sqlite3WalkExpr(&w, pExpr);
    ++  if( !chngRowid ){
    ++    testcase( (w.eCode & CKCNSTRNT_ROWID)!=0 );
    ++    w.eCode &= ~CKCNSTRNT_ROWID;
    ++  }
    ++  testcase( w.eCode==0 );
    ++  testcase( w.eCode==CKCNSTRNT_COLUMN );
    ++  testcase( w.eCode==CKCNSTRNT_ROWID );
    ++  testcase( w.eCode==(CKCNSTRNT_ROWID|CKCNSTRNT_COLUMN) );
    ++  return !w.eCode;
    ++}
    ++
    + /*
    + ** Generate code to do constraint checks prior to an INSERT or an UPDATE
    + ** on table pTab.
    +@@ -102933,7 +112068,8 @@ SQLITE_PRIVATE void sqlite3GenerateConstraintChecks(
    +   u8 pkChng,           /* Non-zero if the rowid or PRIMARY KEY changed */
    +   u8 overrideError,    /* Override onError to this if not OE_Default */
    +   int ignoreDest,      /* Jump to this label on an OE_Ignore resolution */
    +-  int *pbMayReplace    /* OUT: Set to true if constraint may cause a replace */
    ++  int *pbMayReplace,   /* OUT: Set to true if constraint may cause a replace */
    ++  int *aiChng          /* column i is unchanged if aiChng[i]<0 */
    + ){
    +   Vdbe *v;             /* VDBE under constrution */
    +   Index *pIdx;         /* Pointer to one of the indices */
    +@@ -102950,7 +112086,6 @@ SQLITE_PRIVATE void sqlite3GenerateConstraintChecks(
    +   int ipkBottom = 0;   /* Bottom of the rowid change constraint check */
    +   u8 isUpdate;         /* True if this is an UPDATE operation */
    +   u8 bAffinityDone = 0;  /* True if the OP_Affinity operation has been run */
    +-  int regRowid = -1;   /* Register holding ROWID value */
    + 
    +   isUpdate = regOldData!=0;
    +   db = pParse->db;
    +@@ -102979,10 +112114,14 @@ SQLITE_PRIVATE void sqlite3GenerateConstraintChecks(
    +   */
    +   for(i=0; i<nCol; i++){
    +     if( i==pTab->iPKey ){
    ++      continue;        /* ROWID is never NULL */
    ++    }
    ++    if( aiChng && aiChng[i]<0 ){
    ++      /* Don't bother checking for NOT NULL on columns that do not change */
    +       continue;
    +     }
    +     onError = pTab->aCol[i].notNull;
    +-    if( onError==OE_None ) continue;
    ++    if( onError==OE_None ) continue;  /* This column is allowed to be NULL */
    +     if( overrideError!=OE_Default ){
    +       onError = overrideError;
    +     }else if( onError==OE_Default ){
    +@@ -103001,8 +112140,9 @@ SQLITE_PRIVATE void sqlite3GenerateConstraintChecks(
    +       case OE_Fail: {
    +         char *zMsg = sqlite3MPrintf(db, "%s.%s", pTab->zName,
    +                                     pTab->aCol[i].zName);
    +-        sqlite3VdbeAddOp4(v, OP_HaltIfNull, SQLITE_CONSTRAINT_NOTNULL, onError,
    +-                          regNewData+1+i, zMsg, P4_DYNAMIC);
    ++        sqlite3VdbeAddOp3(v, OP_HaltIfNull, SQLITE_CONSTRAINT_NOTNULL, onError,
    ++                          regNewData+1+i);
    ++        sqlite3VdbeAppendP4(v, zMsg, P4_DYNAMIC);
    +         sqlite3VdbeChangeP5(v, P5_ConstraintNotNull);
    +         VdbeCoverage(v);
    +         break;
    +@@ -103028,11 +112168,14 @@ SQLITE_PRIVATE void sqlite3GenerateConstraintChecks(
    + #ifndef SQLITE_OMIT_CHECK
    +   if( pTab->pCheck && (db->flags & SQLITE_IgnoreChecks)==0 ){
    +     ExprList *pCheck = pTab->pCheck;
    +-    pParse->ckBase = regNewData+1;
    ++    pParse->iSelfTab = -(regNewData+1);
    +     onError = overrideError!=OE_Default ? overrideError : OE_Abort;
    +     for(i=0; i<pCheck->nExpr; i++){
    +-      int allOk = sqlite3VdbeMakeLabel(v);
    +-      sqlite3ExprIfTrue(pParse, pCheck->a[i].pExpr, allOk, SQLITE_JUMPIFNULL);
    ++      int allOk;
    ++      Expr *pExpr = pCheck->a[i].pExpr;
    ++      if( aiChng && checkConstraintUnchanged(pExpr, aiChng, pkChng) ) continue;
    ++      allOk = sqlite3VdbeMakeLabel(v);
    ++      sqlite3ExprIfTrue(pParse, pExpr, allOk, SQLITE_JUMPIFNULL);
    +       if( onError==OE_Ignore ){
    +         sqlite3VdbeGoto(v, ignoreDest);
    +       }else{
    +@@ -103045,6 +112188,7 @@ SQLITE_PRIVATE void sqlite3GenerateConstraintChecks(
    +       }
    +       sqlite3VdbeResolveLabel(v, allOk);
    +     }
    ++    pParse->iSelfTab = 0;
    +   }
    + #endif /* !defined(SQLITE_OMIT_CHECK) */
    + 
    +@@ -103063,7 +112207,7 @@ SQLITE_PRIVATE void sqlite3GenerateConstraintChecks(
    +     }
    + 
    +     if( isUpdate ){
    +-      /* pkChng!=0 does not mean that the rowid has change, only that
    ++      /* pkChng!=0 does not mean that the rowid has changed, only that
    +       ** it might have changed.  Skip the conflict logic below if the rowid
    +       ** is unchanged. */
    +       sqlite3VdbeAddOp3(v, OP_Eq, regNewData, addrRowidOk, regOldData);
    +@@ -103132,9 +112276,18 @@ SQLITE_PRIVATE void sqlite3GenerateConstraintChecks(
    +         if( pTrigger || sqlite3FkRequired(pParse, pTab, 0, 0) ){
    +           sqlite3MultiWrite(pParse);
    +           sqlite3GenerateRowDelete(pParse, pTab, pTrigger, iDataCur, iIdxCur,
    +-                                   regNewData, 1, 0, OE_Replace,
    +-                                   ONEPASS_SINGLE, -1);
    ++                                   regNewData, 1, 0, OE_Replace, 1, -1);
    +         }else{
    ++#ifdef SQLITE_ENABLE_PREUPDATE_HOOK
    ++          if( HasRowid(pTab) ){
    ++            /* This OP_Delete opcode fires the pre-update-hook only. It does
    ++            ** not modify the b-tree. It is more efficient to let the coming
    ++            ** OP_Insert replace the existing entry than it is to delete the
    ++            ** existing entry and then insert a new one. */
    ++            sqlite3VdbeAddOp2(v, OP_Delete, iDataCur, OPFLAG_ISNOOP);
    ++            sqlite3VdbeAppendP4(v, pTab, P4_TABLE);
    ++          }
    ++#endif /* SQLITE_ENABLE_PREUPDATE_HOOK */
    +           if( pTab->pIndex ){
    +             sqlite3MultiWrite(pParse);
    +             sqlite3GenerateRowIndexDelete(pParse, pTab, iDataCur, iIdxCur,0,-1);
    +@@ -103180,39 +112333,39 @@ SQLITE_PRIVATE void sqlite3GenerateConstraintChecks(
    +     /* Skip partial indices for which the WHERE clause is not true */
    +     if( pIdx->pPartIdxWhere ){
    +       sqlite3VdbeAddOp2(v, OP_Null, 0, aRegIdx[ix]);
    +-      pParse->ckBase = regNewData+1;
    ++      pParse->iSelfTab = -(regNewData+1);
    +       sqlite3ExprIfFalseDup(pParse, pIdx->pPartIdxWhere, addrUniqueOk,
    +                             SQLITE_JUMPIFNULL);
    +-      pParse->ckBase = 0;
    ++      pParse->iSelfTab = 0;
    +     }
    + 
    +     /* Create a record for this index entry as it should appear after
    +     ** the insert or update.  Store that record in the aRegIdx[ix] register
    +     */
    +-    regIdx = sqlite3GetTempRange(pParse, pIdx->nColumn);
    ++    regIdx = aRegIdx[ix]+1;
    +     for(i=0; i<pIdx->nColumn; i++){
    +       int iField = pIdx->aiColumn[i];
    +       int x;
    +       if( iField==XN_EXPR ){
    +-        pParse->ckBase = regNewData+1;
    +-        sqlite3ExprCode(pParse, pIdx->aColExpr->a[i].pExpr, regIdx+i);
    +-        pParse->ckBase = 0;
    ++        pParse->iSelfTab = -(regNewData+1);
    ++        sqlite3ExprCodeCopy(pParse, pIdx->aColExpr->a[i].pExpr, regIdx+i);
    ++        pParse->iSelfTab = 0;
    +         VdbeComment((v, "%s column %d", pIdx->zName, i));
    +       }else{
    +         if( iField==XN_ROWID || iField==pTab->iPKey ){
    +-          if( regRowid==regIdx+i ) continue; /* ROWID already in regIdx+i */
    +           x = regNewData;
    +-          regRowid =  pIdx->pPartIdxWhere ? -1 : regIdx+i;
    +         }else{
    +           x = iField + regNewData + 1;
    +         }
    +-        sqlite3VdbeAddOp2(v, OP_SCopy, x, regIdx+i);
    ++        sqlite3VdbeAddOp2(v, iField<0 ? OP_IntCopy : OP_SCopy, x, regIdx+i);
    +         VdbeComment((v, "%s", iField<0 ? "rowid" : pTab->aCol[iField].zName));
    +       }
    +     }
    +     sqlite3VdbeAddOp3(v, OP_MakeRecord, regIdx, pIdx->nColumn, aRegIdx[ix]);
    +     VdbeComment((v, "for %s", pIdx->zName));
    +-    sqlite3ExprCacheAffinityChange(pParse, regIdx, pIdx->nColumn);
    ++#ifdef SQLITE_ENABLE_NULL_TRIM
    ++    if( pIdx->idxType==2 ) sqlite3SetMakeRecordP5(v, pIdx->pTable);
    ++#endif
    + 
    +     /* In an UPDATE operation, if this index is the PRIMARY KEY index 
    +     ** of a WITHOUT ROWID table and there has been no change the
    +@@ -103226,7 +112379,6 @@ SQLITE_PRIVATE void sqlite3GenerateConstraintChecks(
    +     /* Find out what action to take in case there is a uniqueness conflict */
    +     onError = pIdx->onError;
    +     if( onError==OE_None ){ 
    +-      sqlite3ReleaseTempRange(pParse, regIdx, pIdx->nColumn);
    +       sqlite3VdbeResolveLabel(v, addrUniqueOk);
    +       continue;  /* pIdx is not a UNIQUE index */
    +     }
    +@@ -103235,8 +112387,28 @@ SQLITE_PRIVATE void sqlite3GenerateConstraintChecks(
    +     }else if( onError==OE_Default ){
    +       onError = OE_Abort;
    +     }
    +-    
    ++
    ++    /* Collision detection may be omitted if all of the following are true:
    ++    **   (1) The conflict resolution algorithm is REPLACE
    ++    **   (2) The table is a WITHOUT ROWID table
    ++    **   (3) There are no secondary indexes on the table
    ++    **   (4) No delete triggers need to be fired if there is a conflict
    ++    **   (5) No FK constraint counters need to be updated if a conflict occurs.
    ++    */ 
    ++    if( (ix==0 && pIdx->pNext==0)                   /* Condition 3 */
    ++     && pPk==pIdx                                   /* Condition 2 */
    ++     && onError==OE_Replace                         /* Condition 1 */
    ++     && ( 0==(db->flags&SQLITE_RecTriggers) ||      /* Condition 4 */
    ++          0==sqlite3TriggersExist(pParse, pTab, TK_DELETE, 0, 0))
    ++     && ( 0==(db->flags&SQLITE_ForeignKeys) ||      /* Condition 5 */
    ++         (0==pTab->pFKey && 0==sqlite3FkReferences(pTab)))
    ++    ){
    ++      sqlite3VdbeResolveLabel(v, addrUniqueOk);
    ++      continue;
    ++    }
    ++
    +     /* Check to see if the new index entry will be unique */
    ++    sqlite3ExprCachePush(pParse);
    +     sqlite3VdbeAddOp4Int(v, OP_NoConflict, iThisCur, addrUniqueOk,
    +                          regIdx, pIdx->nKeyCol); VdbeCoverage(v);
    + 
    +@@ -103319,13 +112491,13 @@ SQLITE_PRIVATE void sqlite3GenerateConstraintChecks(
    +         }
    +         sqlite3GenerateRowDelete(pParse, pTab, pTrigger, iDataCur, iIdxCur,
    +             regR, nPkField, 0, OE_Replace,
    +-            (pIdx==pPk ? ONEPASS_SINGLE : ONEPASS_OFF), -1);
    ++            (pIdx==pPk ? ONEPASS_SINGLE : ONEPASS_OFF), iThisCur);
    +         seenReplace = 1;
    +         break;
    +       }
    +     }
    +     sqlite3VdbeResolveLabel(v, addrUniqueOk);
    +-    sqlite3ReleaseTempRange(pParse, regIdx, pIdx->nColumn);
    ++    sqlite3ExprCachePop(pParse);
    +     if( regR!=regIdx ) sqlite3ReleaseTempRange(pParse, regR, nPkField);
    +   }
    +   if( ipkTop ){
    +@@ -103337,6 +112509,28 @@ SQLITE_PRIVATE void sqlite3GenerateConstraintChecks(
    +   VdbeModuleComment((v, "END: GenCnstCks(%d)", seenReplace));
    + }
    + 
    ++#ifdef SQLITE_ENABLE_NULL_TRIM
    ++/*
    ++** Change the P5 operand on the last opcode (which should be an OP_MakeRecord)
    ++** to be the number of columns in table pTab that must not be NULL-trimmed.
    ++**
    ++** Or if no columns of pTab may be NULL-trimmed, leave P5 at zero.
    ++*/
    ++SQLITE_PRIVATE void sqlite3SetMakeRecordP5(Vdbe *v, Table *pTab){
    ++  u16 i;
    ++
    ++  /* Records with omitted columns are only allowed for schema format
    ++  ** version 2 and later (SQLite version 3.1.4, 2005-02-20). */
    ++  if( pTab->pSchema->file_format<2 ) return;
    ++
    ++  for(i=pTab->nCol-1; i>0; i--){
    ++    if( pTab->aCol[i].pDflt!=0 ) break;
    ++    if( pTab->aCol[i].colFlags & COLFLAG_PRIMKEY ) break;
    ++  }
    ++  sqlite3VdbeChangeP5(v, i+1);
    ++}
    ++#endif
    ++
    + /*
    + ** This routine generates code to finish the INSERT or UPDATE operation
    + ** that was started by a prior call to sqlite3GenerateConstraintChecks.
    +@@ -103353,7 +112547,7 @@ SQLITE_PRIVATE void sqlite3CompleteInsertion(
    +   int iIdxCur,        /* First index cursor */
    +   int regNewData,     /* Range of content */
    +   int *aRegIdx,       /* Register used by each index.  0 for unused indices */
    +-  int isUpdate,       /* True for UPDATE, False for INSERT */
    ++  int update_flags,   /* True for UPDATE, False for INSERT */
    +   int appendBias,     /* True if this is likely to be an append */
    +   int useSeekResult   /* True to set the USESEEKRESULT flag on OP_[Idx]Insert */
    + ){
    +@@ -103365,6 +112559,11 @@ SQLITE_PRIVATE void sqlite3CompleteInsertion(
    +   int i;              /* Loop counter */
    +   u8 bAffinityDone = 0; /* True if OP_Affinity has been run already */
    + 
    ++  assert( update_flags==0
    ++       || update_flags==OPFLAG_ISUPDATE
    ++       || update_flags==(OPFLAG_ISUPDATE|OPFLAG_SAVEPOSITION)
    ++  );
    ++
    +   v = sqlite3GetVdbe(pParse);
    +   assert( v!=0 );
    +   assert( pTab->pSelect==0 );  /* This table is not a VIEW */
    +@@ -103375,26 +112574,39 @@ SQLITE_PRIVATE void sqlite3CompleteInsertion(
    +       sqlite3VdbeAddOp2(v, OP_IsNull, aRegIdx[i], sqlite3VdbeCurrentAddr(v)+2);
    +       VdbeCoverage(v);
    +     }
    +-    sqlite3VdbeAddOp2(v, OP_IdxInsert, iIdxCur+i, aRegIdx[i]);
    +-    pik_flags = 0;
    +-    if( useSeekResult ) pik_flags = OPFLAG_USESEEKRESULT;
    ++    pik_flags = (useSeekResult ? OPFLAG_USESEEKRESULT : 0);
    +     if( IsPrimaryKeyIndex(pIdx) && !HasRowid(pTab) ){
    +       assert( pParse->nested==0 );
    +       pik_flags |= OPFLAG_NCHANGE;
    ++      pik_flags |= (update_flags & OPFLAG_SAVEPOSITION);
    ++#ifdef SQLITE_ENABLE_PREUPDATE_HOOK
    ++      if( update_flags==0 ){
    ++        sqlite3VdbeAddOp4(v, OP_InsertInt, 
    ++            iIdxCur+i, aRegIdx[i], 0, (char*)pTab, P4_TABLE
    ++        );
    ++        sqlite3VdbeChangeP5(v, OPFLAG_ISNOOP);
    ++      }
    ++#endif
    +     }
    +-    if( pik_flags )  sqlite3VdbeChangeP5(v, pik_flags);
    ++    sqlite3VdbeAddOp4Int(v, OP_IdxInsert, iIdxCur+i, aRegIdx[i],
    ++                         aRegIdx[i]+1,
    ++                         pIdx->uniqNotNull ? pIdx->nKeyCol: pIdx->nColumn);
    ++    sqlite3VdbeChangeP5(v, pik_flags);
    +   }
    +   if( !HasRowid(pTab) ) return;
    +   regData = regNewData + 1;
    +   regRec = sqlite3GetTempReg(pParse);
    +   sqlite3VdbeAddOp3(v, OP_MakeRecord, regData, pTab->nCol, regRec);
    +-  if( !bAffinityDone ) sqlite3TableAffinity(v, pTab, 0);
    +-  sqlite3ExprCacheAffinityChange(pParse, regData, pTab->nCol);
    ++  sqlite3SetMakeRecordP5(v, pTab);
    ++  if( !bAffinityDone ){
    ++    sqlite3TableAffinity(v, pTab, 0);
    ++    sqlite3ExprCacheAffinityChange(pParse, regData, pTab->nCol);
    ++  }
    +   if( pParse->nested ){
    +     pik_flags = 0;
    +   }else{
    +     pik_flags = OPFLAG_NCHANGE;
    +-    pik_flags |= (isUpdate?OPFLAG_ISUPDATE:OPFLAG_LASTROWID);
    ++    pik_flags |= (update_flags?update_flags:OPFLAG_LASTROWID);
    +   }
    +   if( appendBias ){
    +     pik_flags |= OPFLAG_APPEND;
    +@@ -103404,7 +112616,7 @@ SQLITE_PRIVATE void sqlite3CompleteInsertion(
    +   }
    +   sqlite3VdbeAddOp3(v, OP_Insert, iDataCur, regRec, regNewData);
    +   if( !pParse->nested ){
    +-    sqlite3VdbeChangeP4(v, -1, pTab->zName, P4_TRANSIENT);
    ++    sqlite3VdbeAppendP4(v, pTab, P4_TABLE);
    +   }
    +   sqlite3VdbeChangeP5(v, pik_flags);
    + }
    +@@ -103434,6 +112646,7 @@ SQLITE_PRIVATE int sqlite3OpenTableAndIndices(
    +   Parse *pParse,   /* Parsing context */
    +   Table *pTab,     /* Table to be opened */
    +   int op,          /* OP_OpenRead or OP_OpenWrite */
    ++  u8 p5,           /* P5 value for OP_Open* opcodes (except on WITHOUT ROWID) */
    +   int iBase,       /* Use this for the table cursor, if there is one */
    +   u8 *aToOpen,     /* If not NULL: boolean for each table and index */
    +   int *piDataCur,  /* Write the database source cursor number here */
    +@@ -103446,6 +112659,7 @@ SQLITE_PRIVATE int sqlite3OpenTableAndIndices(
    +   Vdbe *v;
    + 
    +   assert( op==OP_OpenRead || op==OP_OpenWrite );
    ++  assert( op==OP_OpenWrite || p5==0 );
    +   if( IsVirtual(pTab) ){
    +     /* This routine is a no-op for virtual tables. Leave the output
    +     ** variables *piDataCur and *piIdxCur uninitialized so that valgrind
    +@@ -103467,12 +112681,14 @@ SQLITE_PRIVATE int sqlite3OpenTableAndIndices(
    +   for(i=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, i++){
    +     int iIdxCur = iBase++;
    +     assert( pIdx->pSchema==pTab->pSchema );
    +-    if( IsPrimaryKeyIndex(pIdx) && !HasRowid(pTab) && piDataCur ){
    +-      *piDataCur = iIdxCur;
    ++    if( IsPrimaryKeyIndex(pIdx) && !HasRowid(pTab) ){
    ++      if( piDataCur ) *piDataCur = iIdxCur;
    ++      p5 = 0;
    +     }
    +     if( aToOpen==0 || aToOpen[i+1] ){
    +       sqlite3VdbeAddOp3(v, op, iIdxCur, pIdx->tnum, iDb);
    +       sqlite3VdbeSetP4KeyInfo(pParse, pIdx);
    ++      sqlite3VdbeChangeP5(v, p5);
    +       VdbeComment((v, "%s", pIdx->zName));
    +     }
    +   }
    +@@ -103493,20 +112709,6 @@ SQLITE_API int sqlite3_xferopt_count;
    + 
    + 
    + #ifndef SQLITE_OMIT_XFER_OPT
    +-/*
    +-** Check to collation names to see if they are compatible.
    +-*/
    +-static int xferCompatibleCollation(const char *z1, const char *z2){
    +-  if( z1==0 ){
    +-    return z2==0;
    +-  }
    +-  if( z2==0 ){
    +-    return 0;
    +-  }
    +-  return sqlite3StrICmp(z1, z2)==0;
    +-}
    +-
    +-
    + /*
    + ** Check to see if index pSrc is compatible as a source of data
    + ** for index pDest in an insert transfer optimization.  The rules
    +@@ -103534,7 +112736,7 @@ static int xferCompatibleIndex(Index *pDest, Index *pSrc){
    +     }
    +     if( pSrc->aiColumn[i]==XN_EXPR ){
    +       assert( pSrc->aColExpr!=0 && pDest->aColExpr!=0 );
    +-      if( sqlite3ExprCompare(pSrc->aColExpr->a[i].pExpr,
    ++      if( sqlite3ExprCompare(0, pSrc->aColExpr->a[i].pExpr,
    +                              pDest->aColExpr->a[i].pExpr, -1)!=0 ){
    +         return 0;   /* Different expressions in the index */
    +       }
    +@@ -103542,11 +112744,11 @@ static int xferCompatibleIndex(Index *pDest, Index *pSrc){
    +     if( pSrc->aSortOrder[i]!=pDest->aSortOrder[i] ){
    +       return 0;   /* Different sort orders */
    +     }
    +-    if( !xferCompatibleCollation(pSrc->azColl[i],pDest->azColl[i]) ){
    ++    if( sqlite3_stricmp(pSrc->azColl[i],pDest->azColl[i])!=0 ){
    +       return 0;   /* Different collating sequences */
    +     }
    +   }
    +-  if( sqlite3ExprCompare(pSrc->pPartIdxWhere, pDest->pPartIdxWhere, -1) ){
    ++  if( sqlite3ExprCompare(0, pSrc->pPartIdxWhere, pDest->pPartIdxWhere, -1) ){
    +     return 0;     /* Different WHERE clauses */
    +   }
    + 
    +@@ -103615,7 +112817,7 @@ static int xferOptimization(
    +     return 0;   /* tab1 must not have triggers */
    +   }
    + #ifndef SQLITE_OMIT_VIRTUALTABLE
    +-  if( pDest->tabFlags & TF_Virtual ){
    ++  if( IsVirtual(pDest) ){
    +     return 0;   /* tab1 must not be a virtual table */
    +   }
    + #endif
    +@@ -103644,7 +112846,6 @@ static int xferOptimization(
    +   if( pSelect->pLimit ){
    +     return 0;   /* SELECT may not have a LIMIT clause */
    +   }
    +-  assert( pSelect->pOffset==0 );  /* Must be so if pLimit==0 */
    +   if( pSelect->pPrior ){
    +     return 0;   /* SELECT may not be a compound query */
    +   }
    +@@ -103657,7 +112858,7 @@ static int xferOptimization(
    +     return 0;   /* The result set must have exactly one column */
    +   }
    +   assert( pEList->a[0].pExpr );
    +-  if( pEList->a[0].pExpr->op!=TK_ALL ){
    ++  if( pEList->a[0].pExpr->op!=TK_ASTERISK ){
    +     return 0;   /* The result set must be the special operator "*" */
    +   }
    + 
    +@@ -103677,7 +112878,7 @@ static int xferOptimization(
    +     return 0;   /* source and destination must both be WITHOUT ROWID or not */
    +   }
    + #ifndef SQLITE_OMIT_VIRTUALTABLE
    +-  if( pSrc->tabFlags & TF_Virtual ){
    ++  if( IsVirtual(pSrc) ){
    +     return 0;   /* tab2 must not be a virtual table */
    +   }
    + #endif
    +@@ -103693,21 +112894,32 @@ static int xferOptimization(
    +   for(i=0; i<pDest->nCol; i++){
    +     Column *pDestCol = &pDest->aCol[i];
    +     Column *pSrcCol = &pSrc->aCol[i];
    ++#ifdef SQLITE_ENABLE_HIDDEN_COLUMNS
    ++    if( (db->mDbFlags & DBFLAG_Vacuum)==0 
    ++     && (pDestCol->colFlags | pSrcCol->colFlags) & COLFLAG_HIDDEN 
    ++    ){
    ++      return 0;    /* Neither table may have __hidden__ columns */
    ++    }
    ++#endif
    +     if( pDestCol->affinity!=pSrcCol->affinity ){
    +       return 0;    /* Affinity must be the same on all columns */
    +     }
    +-    if( !xferCompatibleCollation(pDestCol->zColl, pSrcCol->zColl) ){
    ++    if( sqlite3_stricmp(pDestCol->zColl, pSrcCol->zColl)!=0 ){
    +       return 0;    /* Collating sequence must be the same on all columns */
    +     }
    +     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 */
    ++    if( i>0 ){
    ++      assert( pDestCol->pDflt==0 || pDestCol->pDflt->op==TK_SPAN );
    ++      assert( pSrcCol->pDflt==0 || pSrcCol->pDflt->op==TK_SPAN );
    ++      if( (pDestCol->pDflt==0)!=(pSrcCol->pDflt==0) 
    ++       || (pDestCol->pDflt && strcmp(pDestCol->pDflt->u.zToken,
    ++                                       pSrcCol->pDflt->u.zToken)!=0)
    ++      ){
    ++        return 0;    /* Default values must be the same for all columns */
    ++      }
    +     }
    +   }
    +   for(pDestIdx=pDest->pIndex; pDestIdx; pDestIdx=pDestIdx->pNext){
    +@@ -103759,15 +112971,15 @@ static int xferOptimization(
    +   regRowid = sqlite3GetTempReg(pParse);
    +   sqlite3OpenTable(pParse, iDest, iDbDest, pDest, OP_OpenWrite);
    +   assert( HasRowid(pDest) || destHasUniqueIdx );
    +-  if( (db->flags & SQLITE_Vacuum)==0 && (
    ++  if( (db->mDbFlags & DBFLAG_Vacuum)==0 && (
    +       (pDest->iPKey<0 && pDest->pIndex!=0)          /* (1) */
    +    || destHasUniqueIdx                              /* (2) */
    +    || (onError!=OE_Abort && onError!=OE_Rollback)   /* (3) */
    +   )){
    +     /* In some circumstances, we are able to run the xfer optimization
    +     ** only if the destination table is initially empty. Unless the
    +-    ** SQLITE_Vacuum flag is set, this block generates code to make
    +-    ** that determination. If SQLITE_Vacuum is set, then the destination
    ++    ** DBFLAG_Vacuum flag is set, this block generates code to make
    ++    ** that determination. If DBFLAG_Vacuum is set, then the destination
    +     ** table is always empty.
    +     **
    +     ** Conditions under which the destination must be empty:
    +@@ -103786,6 +112998,7 @@ static int xferOptimization(
    +     sqlite3VdbeJumpHere(v, addr1);
    +   }
    +   if( HasRowid(pSrc) ){
    ++    u8 insFlags;
    +     sqlite3OpenTable(pParse, iSrc, iDbSrc, pSrc, OP_OpenRead);
    +     emptySrcTest = sqlite3VdbeAddOp2(v, OP_Rewind, iSrc, 0); VdbeCoverage(v);
    +     if( pDest->iPKey>=0 ){
    +@@ -103801,10 +113014,17 @@ static int xferOptimization(
    +       addr1 = sqlite3VdbeAddOp2(v, OP_Rowid, iSrc, regRowid);
    +       assert( (pDest->tabFlags & TF_Autoincrement)==0 );
    +     }
    +-    sqlite3VdbeAddOp2(v, OP_RowData, iSrc, regData);
    +-    sqlite3VdbeAddOp3(v, OP_Insert, iDest, regData, regRowid);
    +-    sqlite3VdbeChangeP5(v, OPFLAG_NCHANGE|OPFLAG_LASTROWID|OPFLAG_APPEND);
    +-    sqlite3VdbeChangeP4(v, -1, pDest->zName, 0);
    ++    sqlite3VdbeAddOp3(v, OP_RowData, iSrc, regData, 1);
    ++    if( db->mDbFlags & DBFLAG_Vacuum ){
    ++      sqlite3VdbeAddOp1(v, OP_SeekEnd, iDest);
    ++      insFlags = OPFLAG_NCHANGE|OPFLAG_LASTROWID|
    ++                           OPFLAG_APPEND|OPFLAG_USESEEKRESULT;
    ++    }else{
    ++      insFlags = OPFLAG_NCHANGE|OPFLAG_LASTROWID|OPFLAG_APPEND;
    ++    }
    ++    sqlite3VdbeAddOp4(v, OP_Insert, iDest, regData, regRowid,
    ++                      (char*)pDest, P4_TABLE);
    ++    sqlite3VdbeChangeP5(v, insFlags);
    +     sqlite3VdbeAddOp2(v, OP_Next, iSrc, addr1); VdbeCoverage(v);
    +     sqlite3VdbeAddOp2(v, OP_Close, iSrc, 0);
    +     sqlite3VdbeAddOp2(v, OP_Close, iDest, 0);
    +@@ -103826,14 +113046,14 @@ static int xferOptimization(
    +     sqlite3VdbeChangeP5(v, OPFLAG_BULKCSR);
    +     VdbeComment((v, "%s", pDestIdx->zName));
    +     addr1 = sqlite3VdbeAddOp2(v, OP_Rewind, iSrc, 0); VdbeCoverage(v);
    +-    sqlite3VdbeAddOp2(v, OP_RowKey, iSrc, regData);
    +-    if( db->flags & SQLITE_Vacuum ){
    ++    sqlite3VdbeAddOp3(v, OP_RowData, iSrc, regData, 1);
    ++    if( db->mDbFlags & DBFLAG_Vacuum ){
    +       /* This INSERT command is part of a VACUUM operation, which guarantees
    +       ** that the destination table is empty. If all indexed columns use
    +       ** collation sequence BINARY, then it can also be assumed that the
    +       ** index will be populated by inserting keys in strictly sorted 
    +       ** order. In this case, instead of seeking within the b-tree as part
    +-      ** of every OP_IdxInsert opcode, an OP_Last is added before the
    ++      ** of every OP_IdxInsert opcode, an OP_SeekEnd is added before the
    +       ** OP_IdxInsert to seek to the point within the b-tree where each key 
    +       ** should be inserted. This is faster.
    +       **
    +@@ -103843,20 +113063,19 @@ static int xferOptimization(
    +       ** a VACUUM command. In that case keys may not be written in strictly
    +       ** sorted order.  */
    +       for(i=0; i<pSrcIdx->nColumn; i++){
    +-        char *zColl = pSrcIdx->azColl[i];
    +-        assert( zColl!=0 );
    +-        if( sqlite3_stricmp("BINARY", zColl) ) break;
    ++        const char *zColl = pSrcIdx->azColl[i];
    ++        if( sqlite3_stricmp(sqlite3StrBINARY, zColl) ) break;
    +       }
    +       if( i==pSrcIdx->nColumn ){
    +         idxInsFlags = OPFLAG_USESEEKRESULT;
    +-        sqlite3VdbeAddOp3(v, OP_Last, iDest, 0, -1);
    ++        sqlite3VdbeAddOp1(v, OP_SeekEnd, iDest);
    +       }
    +     }
    +     if( !HasRowid(pSrc) && pDestIdx->idxType==2 ){
    +       idxInsFlags |= OPFLAG_NCHANGE;
    +     }
    +-    sqlite3VdbeAddOp3(v, OP_IdxInsert, iDest, regData, 1);
    +-    sqlite3VdbeChangeP5(v, idxInsFlags);
    ++    sqlite3VdbeAddOp2(v, OP_IdxInsert, iDest, regData);
    ++    sqlite3VdbeChangeP5(v, idxInsFlags|OPFLAG_APPEND);
    +     sqlite3VdbeAddOp2(v, OP_Next, iSrc, addr1+1); VdbeCoverage(v);
    +     sqlite3VdbeJumpHere(v, addr1);
    +     sqlite3VdbeAddOp2(v, OP_Close, iSrc, 0);
    +@@ -103866,6 +113085,7 @@ static int xferOptimization(
    +   sqlite3ReleaseTempReg(pParse, regRowid);
    +   sqlite3ReleaseTempReg(pParse, regData);
    +   if( emptyDestTest ){
    ++    sqlite3AutoincrementEnd(pParse);
    +     sqlite3VdbeAddOp2(v, OP_Halt, SQLITE_OK, 0);
    +     sqlite3VdbeJumpHere(v, emptyDestTest);
    +     sqlite3VdbeAddOp2(v, OP_Close, iDest, 0);
    +@@ -103907,7 +113127,7 @@ static int xferOptimization(
    + ** argument to xCallback().  If xCallback=NULL then no callback
    + ** is invoked, even for queries.
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_exec(
    ++SQLITE_API int sqlite3_exec(
    +   sqlite3 *db,                /* The database on which the SQL executes */
    +   const char *zSql,           /* The SQL to be executed */
    +   sqlite3_callback xCallback, /* Invoke this callback routine */
    +@@ -103953,7 +113173,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_exec(
    +           (SQLITE_DONE==rc && !callbackIsInit
    +                            && db->flags&SQLITE_NullCallback)) ){
    +         if( !callbackIsInit ){
    +-          azCols = sqlite3DbMallocZero(db, 2*nCol*sizeof(const char*) + 1);
    ++          azCols = sqlite3DbMallocRaw(db, (2*nCol+1)*sizeof(const char*));
    +           if( azCols==0 ){
    +             goto exec_out;
    +           }
    +@@ -103970,10 +113190,11 @@ SQLITE_API int SQLITE_STDCALL sqlite3_exec(
    +           for(i=0; i<nCol; i++){
    +             azVals[i] = (char *)sqlite3_column_text(pStmt, i);
    +             if( !azVals[i] && sqlite3_column_type(pStmt, i)!=SQLITE_NULL ){
    +-              db->mallocFailed = 1;
    ++              sqlite3OomFault(db);
    +               goto exec_out;
    +             }
    +           }
    ++          azVals[i] = 0;
    +         }
    +         if( xCallback(pArg, nCol, azVals, azCols) ){
    +           /* EVIDENCE-OF: R-38229-40159 If the callback function to
    +@@ -104006,12 +113227,9 @@ exec_out:
    + 
    +   rc = sqlite3ApiExit(db, rc);
    +   if( rc!=SQLITE_OK && pzErrMsg ){
    +-    int nErrMsg = 1 + sqlite3Strlen30(sqlite3_errmsg(db));
    +-    *pzErrMsg = sqlite3Malloc(nErrMsg);
    +-    if( *pzErrMsg ){
    +-      memcpy(*pzErrMsg, sqlite3_errmsg(db), nErrMsg);
    +-    }else{
    +-      rc = SQLITE_NOMEM;
    ++    *pzErrMsg = sqlite3DbStrDup(0, sqlite3_errmsg(db));
    ++    if( *pzErrMsg==0 ){
    ++      rc = SQLITE_NOMEM_BKPT;
    +       sqlite3Error(db, SQLITE_NOMEM);
    +     }
    +   }else if( pzErrMsg ){
    +@@ -104062,12 +113280,10 @@ exec_out:
    + ** as extensions by SQLite should #include this file instead of 
    + ** sqlite3.h.
    + */
    +-#ifndef _SQLITE3EXT_H_
    +-#define _SQLITE3EXT_H_
    ++#ifndef SQLITE3EXT_H
    ++#define SQLITE3EXT_H
    + /* #include "sqlite3.h" */
    + 
    +-typedef struct sqlite3_api_routines sqlite3_api_routines;
    +-
    + /*
    + ** The following structure holds pointers to all of the SQLite API
    + ** routines.
    +@@ -104183,7 +113399,7 @@ struct sqlite3_api_routines {
    +   int  (*set_authorizer)(sqlite3*,int(*)(void*,int,const char*,const char*,
    +                          const char*,const char*),void*);
    +   void  (*set_auxdata)(sqlite3_context*,int,void*,void (*)(void*));
    +-  char * (*snprintf)(int,char*,const char*,...);
    ++  char * (*xsnprintf)(int,char*,const char*,...);
    +   int  (*step)(sqlite3_stmt*);
    +   int  (*table_column_metadata)(sqlite3*,const char*,const char*,const char*,
    +                                 char const**,char const**,int*,int*,int*);
    +@@ -104295,7 +113511,7 @@ struct sqlite3_api_routines {
    +   int (*uri_boolean)(const char*,const char*,int);
    +   sqlite3_int64 (*uri_int64)(const char*,const char*,sqlite3_int64);
    +   const char *(*uri_parameter)(const char*,const char*);
    +-  char *(*vsnprintf)(int,char*,const char*,va_list);
    ++  char *(*xvsnprintf)(int,char*,const char*,va_list);
    +   int (*wal_checkpoint_v2)(sqlite3*,const char*,int,int*,int*);
    +   /* Version 3.8.7 and later */
    +   int (*auto_extension)(void(*)(void));
    +@@ -104322,8 +113538,40 @@ struct sqlite3_api_routines {
    +   /* Version 3.9.0 and later */
    +   unsigned int (*value_subtype)(sqlite3_value*);
    +   void (*result_subtype)(sqlite3_context*,unsigned int);
    ++  /* Version 3.10.0 and later */
    ++  int (*status64)(int,sqlite3_int64*,sqlite3_int64*,int);
    ++  int (*strlike)(const char*,const char*,unsigned int);
    ++  int (*db_cacheflush)(sqlite3*);
    ++  /* Version 3.12.0 and later */
    ++  int (*system_errno)(sqlite3*);
    ++  /* Version 3.14.0 and later */
    ++  int (*trace_v2)(sqlite3*,unsigned,int(*)(unsigned,void*,void*,void*),void*);
    ++  char *(*expanded_sql)(sqlite3_stmt*);
    ++  /* Version 3.18.0 and later */
    ++  void (*set_last_insert_rowid)(sqlite3*,sqlite3_int64);
    ++  /* Version 3.20.0 and later */
    ++  int (*prepare_v3)(sqlite3*,const char*,int,unsigned int,
    ++                    sqlite3_stmt**,const char**);
    ++  int (*prepare16_v3)(sqlite3*,const void*,int,unsigned int,
    ++                      sqlite3_stmt**,const void**);
    ++  int (*bind_pointer)(sqlite3_stmt*,int,void*,const char*,void(*)(void*));
    ++  void (*result_pointer)(sqlite3_context*,void*,const char*,void(*)(void*));
    ++  void *(*value_pointer)(sqlite3_value*,const char*);
    ++  int (*vtab_nochange)(sqlite3_context*);
    ++  int (*value_nochange)(sqlite3_value*);
    ++  const char *(*vtab_collation)(sqlite3_index_info*,int);
    + };
    + 
    ++/*
    ++** This is the function signature used for all extension entry points.  It
    ++** is also defined in the file "loadext.c".
    ++*/
    ++typedef int (*sqlite3_loadext_entry)(
    ++  sqlite3 *db,                       /* Handle to the database. */
    ++  char **pzErrMsg,                   /* Used to set error string on failure. */
    ++  const sqlite3_api_routines *pThunk /* Extension API function pointers. */
    ++);
    ++
    + /*
    + ** The following macros redefine the API routines so that they are
    + ** redirected through the global sqlite3_api structure.
    +@@ -104438,7 +113686,7 @@ struct sqlite3_api_routines {
    + #define sqlite3_rollback_hook          sqlite3_api->rollback_hook
    + #define sqlite3_set_authorizer         sqlite3_api->set_authorizer
    + #define sqlite3_set_auxdata            sqlite3_api->set_auxdata
    +-#define sqlite3_snprintf               sqlite3_api->snprintf
    ++#define sqlite3_snprintf               sqlite3_api->xsnprintf
    + #define sqlite3_step                   sqlite3_api->step
    + #define sqlite3_table_column_metadata  sqlite3_api->table_column_metadata
    + #define sqlite3_thread_cleanup         sqlite3_api->thread_cleanup
    +@@ -104462,7 +113710,7 @@ struct sqlite3_api_routines {
    + #define sqlite3_value_text16le         sqlite3_api->value_text16le
    + #define sqlite3_value_type             sqlite3_api->value_type
    + #define sqlite3_vmprintf               sqlite3_api->vmprintf
    +-#define sqlite3_vsnprintf              sqlite3_api->vsnprintf
    ++#define sqlite3_vsnprintf              sqlite3_api->xvsnprintf
    + #define sqlite3_overload_function      sqlite3_api->overload_function
    + #define sqlite3_prepare_v2             sqlite3_api->prepare_v2
    + #define sqlite3_prepare16_v2           sqlite3_api->prepare16_v2
    +@@ -104538,7 +113786,7 @@ struct sqlite3_api_routines {
    + #define sqlite3_uri_boolean            sqlite3_api->uri_boolean
    + #define sqlite3_uri_int64              sqlite3_api->uri_int64
    + #define sqlite3_uri_parameter          sqlite3_api->uri_parameter
    +-#define sqlite3_uri_vsnprintf          sqlite3_api->vsnprintf
    ++#define sqlite3_uri_vsnprintf          sqlite3_api->xvsnprintf
    + #define sqlite3_wal_checkpoint_v2      sqlite3_api->wal_checkpoint_v2
    + /* Version 3.8.7 and later */
    + #define sqlite3_auto_extension         sqlite3_api->auto_extension
    +@@ -104561,6 +113809,27 @@ struct sqlite3_api_routines {
    + /* Version 3.9.0 and later */
    + #define sqlite3_value_subtype          sqlite3_api->value_subtype
    + #define sqlite3_result_subtype         sqlite3_api->result_subtype
    ++/* Version 3.10.0 and later */
    ++#define sqlite3_status64               sqlite3_api->status64
    ++#define sqlite3_strlike                sqlite3_api->strlike
    ++#define sqlite3_db_cacheflush          sqlite3_api->db_cacheflush
    ++/* Version 3.12.0 and later */
    ++#define sqlite3_system_errno           sqlite3_api->system_errno
    ++/* Version 3.14.0 and later */
    ++#define sqlite3_trace_v2               sqlite3_api->trace_v2
    ++#define sqlite3_expanded_sql           sqlite3_api->expanded_sql
    ++/* Version 3.18.0 and later */
    ++#define sqlite3_set_last_insert_rowid  sqlite3_api->set_last_insert_rowid
    ++/* Version 3.20.0 and later */
    ++#define sqlite3_prepare_v3             sqlite3_api->prepare_v3
    ++#define sqlite3_prepare16_v3           sqlite3_api->prepare16_v3
    ++#define sqlite3_bind_pointer           sqlite3_api->bind_pointer
    ++#define sqlite3_result_pointer         sqlite3_api->result_pointer
    ++#define sqlite3_value_pointer          sqlite3_api->value_pointer
    ++/* Version 3.22.0 and later */
    ++#define sqlite3_vtab_nochange          sqlite3_api->vtab_nochange
    ++#define sqlite3_value_nochange         sqltie3_api->value_nochange
    ++#define sqlite3_vtab_collation         sqltie3_api->vtab_collation
    + #endif /* !defined(SQLITE_CORE) && !defined(SQLITE_OMIT_LOAD_EXTENSION) */
    + 
    + #if !defined(SQLITE_CORE) && !defined(SQLITE_OMIT_LOAD_EXTENSION)
    +@@ -104578,15 +113847,13 @@ struct sqlite3_api_routines {
    + # define SQLITE_EXTENSION_INIT3     /*no-op*/
    + #endif
    + 
    +-#endif /* _SQLITE3EXT_H_ */
    ++#endif /* SQLITE3EXT_H */
    + 
    + /************** End of sqlite3ext.h ******************************************/
    + /************** Continuing where we left off in loadext.c ********************/
    + /* #include "sqliteInt.h" */
    +-/* #include <string.h> */
    + 
    + #ifndef SQLITE_OMIT_LOAD_EXTENSION
    +-
    + /*
    + ** Some API routines are omitted when various features are
    + ** excluded from a build of SQLite.  Substitute a NULL pointer
    +@@ -104618,6 +113885,7 @@ struct sqlite3_api_routines {
    + # define sqlite3_open16                 0
    + # define sqlite3_prepare16              0
    + # define sqlite3_prepare16_v2           0
    ++# define sqlite3_prepare16_v3           0
    + # define sqlite3_result_error16         0
    + # define sqlite3_result_text16          0
    + # define sqlite3_result_text16be        0
    +@@ -104656,7 +113924,7 @@ struct sqlite3_api_routines {
    + # define sqlite3_enable_shared_cache 0
    + #endif
    + 
    +-#ifdef SQLITE_OMIT_TRACE
    ++#if defined(SQLITE_OMIT_TRACE) || defined(SQLITE_OMIT_DEPRECATED)
    + # define sqlite3_profile       0
    + # define sqlite3_trace         0
    + #endif
    +@@ -104676,6 +113944,10 @@ struct sqlite3_api_routines {
    + #define sqlite3_blob_reopen    0
    + #endif
    + 
    ++#if defined(SQLITE_OMIT_TRACE)
    ++# define sqlite3_trace_v2      0
    ++#endif
    ++
    + /*
    + ** The following structure contains pointers to all SQLite API routines.
    + ** A pointer to this structure is passed into extensions when they are
    +@@ -104975,7 +114247,28 @@ static const sqlite3_api_routines sqlite3Apis = {
    +   sqlite3_bind_zeroblob64,
    +   /* Version 3.9.0 and later */
    +   sqlite3_value_subtype,
    +-  sqlite3_result_subtype
    ++  sqlite3_result_subtype,
    ++  /* Version 3.10.0 and later */
    ++  sqlite3_status64,
    ++  sqlite3_strlike,
    ++  sqlite3_db_cacheflush,
    ++  /* Version 3.12.0 and later */
    ++  sqlite3_system_errno,
    ++  /* Version 3.14.0 and later */
    ++  sqlite3_trace_v2,
    ++  sqlite3_expanded_sql,
    ++  /* Version 3.18.0 and later */
    ++  sqlite3_set_last_insert_rowid,
    ++  /* Version 3.20.0 and later */
    ++  sqlite3_prepare_v3,
    ++  sqlite3_prepare16_v3,
    ++  sqlite3_bind_pointer,
    ++  sqlite3_result_pointer,
    ++  sqlite3_value_pointer,
    ++  /* Version 3.22.0 and later */
    ++  sqlite3_vtab_nochange,
    ++  sqlite3_value_nochange,
    ++  sqlite3_vtab_collation
    + };
    + 
    + /*
    +@@ -104998,13 +114291,14 @@ static int sqlite3LoadExtension(
    + ){
    +   sqlite3_vfs *pVfs = db->pVfs;
    +   void *handle;
    +-  int (*xInit)(sqlite3*,char**,const sqlite3_api_routines*);
    ++  sqlite3_loadext_entry xInit;
    +   char *zErrmsg = 0;
    +   const char *zEntry;
    +   char *zAltEntry = 0;
    +   void **aHandle;
    +   u64 nMsg = 300 + sqlite3Strlen30(zFile);
    +   int ii;
    ++  int rc;
    + 
    +   /* Shared library endings to try if zFile cannot be loaded as written */
    +   static const char *azEndings[] = {
    +@@ -105023,8 +114317,9 @@ static int sqlite3LoadExtension(
    +   /* Ticket #1863.  To avoid a creating security problems for older
    +   ** applications that relink against newer versions of SQLite, the
    +   ** ability to run load_extension is turned off by default.  One
    +-  ** must call sqlite3_enable_load_extension() to turn on extension
    +-  ** loading.  Otherwise you get the following error.
    ++  ** must call either sqlite3_enable_load_extension(db) or
    ++  ** sqlite3_db_config(db, SQLITE_DBCONFIG_ENABLE_LOAD_EXTENSION, 1, 0)
    ++  ** to turn on extension loading.
    +   */
    +   if( (db->flags & SQLITE_LoadExtension)==0 ){
    +     if( pzErrMsg ){
    +@@ -105039,8 +114334,10 @@ static int sqlite3LoadExtension(
    + #if SQLITE_OS_UNIX || SQLITE_OS_WIN
    +   for(ii=0; ii<ArraySize(azEndings) && handle==0; ii++){
    +     char *zAltFile = sqlite3_mprintf("%s.%s", zFile, azEndings[ii]);
    +-    if( zAltFile==0 ) return SQLITE_NOMEM;
    +-    handle = sqlite3OsDlOpen(pVfs, zAltFile);
    ++    int bExists = 0;
    ++    if( zAltFile==0 ) return SQLITE_NOMEM_BKPT;
    ++    sqlite3OsAccess(pVfs, zAltFile, SQLITE_ACCESS_EXISTS, &bExists);
    ++    if( bExists )  handle = sqlite3OsDlOpen(pVfs, zAltFile);
    +     sqlite3_free(zAltFile);
    +   }
    + #endif
    +@@ -105055,8 +114352,7 @@ static int sqlite3LoadExtension(
    +     }
    +     return SQLITE_ERROR;
    +   }
    +-  xInit = (int(*)(sqlite3*,char**,const sqlite3_api_routines*))
    +-                   sqlite3OsDlSym(pVfs, handle, zEntry);
    ++  xInit = (sqlite3_loadext_entry)sqlite3OsDlSym(pVfs, handle, zEntry);
    + 
    +   /* If no entry point was specified and the default legacy
    +   ** entry point name "sqlite3_extension_init" was not found, then
    +@@ -105075,7 +114371,7 @@ static int sqlite3LoadExtension(
    +     zAltEntry = sqlite3_malloc64(ncFile+30);
    +     if( zAltEntry==0 ){
    +       sqlite3OsDlClose(pVfs, handle);
    +-      return SQLITE_NOMEM;
    ++      return SQLITE_NOMEM_BKPT;
    +     }
    +     memcpy(zAltEntry, "sqlite3_", 8);
    +     for(iFile=ncFile-1; iFile>=0 && zFile[iFile]!='/'; iFile--){}
    +@@ -105088,8 +114384,7 @@ static int sqlite3LoadExtension(
    +     }
    +     memcpy(zAltEntry+iEntry, "_init", 6);
    +     zEntry = zAltEntry;
    +-    xInit = (int(*)(sqlite3*,char**,const sqlite3_api_routines*))
    +-                     sqlite3OsDlSym(pVfs, handle, zEntry);
    ++    xInit = (sqlite3_loadext_entry)sqlite3OsDlSym(pVfs, handle, zEntry);
    +   }
    +   if( xInit==0 ){
    +     if( pzErrMsg ){
    +@@ -105106,7 +114401,9 @@ static int sqlite3LoadExtension(
    +     return SQLITE_ERROR;
    +   }
    +   sqlite3_free(zAltEntry);
    +-  if( xInit(db, &zErrmsg, &sqlite3Apis) ){
    ++  rc = xInit(db, &zErrmsg, &sqlite3Apis);
    ++  if( rc ){
    ++    if( rc==SQLITE_OK_LOAD_PERMANENTLY ) return SQLITE_OK;
    +     if( pzErrMsg ){
    +       *pzErrMsg = sqlite3_mprintf("error during initialization: %s", zErrmsg);
    +     }
    +@@ -105118,7 +114415,7 @@ static int sqlite3LoadExtension(
    +   /* Append the new shared library handle to the db->aExtension array. */
    +   aHandle = sqlite3DbMallocZero(db, sizeof(handle)*(db->nExtension+1));
    +   if( aHandle==0 ){
    +-    return SQLITE_NOMEM;
    ++    return SQLITE_NOMEM_BKPT;
    +   }
    +   if( db->nExtension>0 ){
    +     memcpy(aHandle, db->aExtension, sizeof(handle)*db->nExtension);
    +@@ -105129,7 +114426,7 @@ static int sqlite3LoadExtension(
    +   db->aExtension[db->nExtension++] = handle;
    +   return SQLITE_OK;
    + }
    +-SQLITE_API int SQLITE_STDCALL sqlite3_load_extension(
    ++SQLITE_API int sqlite3_load_extension(
    +   sqlite3 *db,          /* Load the extension into this database connection */
    +   const char *zFile,    /* Name of the shared library containing extension */
    +   const char *zProc,    /* Entry point.  Use "sqlite3_extension_init" if 0 */
    +@@ -105160,29 +114457,18 @@ SQLITE_PRIVATE void sqlite3CloseExtensions(sqlite3 *db){
    + ** Enable or disable extension loading.  Extension loading is disabled by
    + ** default so as not to open security holes in older applications.
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_enable_load_extension(sqlite3 *db, int onoff){
    ++SQLITE_API int sqlite3_enable_load_extension(sqlite3 *db, int onoff){
    +   sqlite3_mutex_enter(db->mutex);
    +   if( onoff ){
    +-    db->flags |= SQLITE_LoadExtension;
    ++    db->flags |= SQLITE_LoadExtension|SQLITE_LoadExtFunc;
    +   }else{
    +-    db->flags &= ~SQLITE_LoadExtension;
    ++    db->flags &= ~(SQLITE_LoadExtension|SQLITE_LoadExtFunc);
    +   }
    +   sqlite3_mutex_leave(db->mutex);
    +   return SQLITE_OK;
    + }
    + 
    +-#endif /* SQLITE_OMIT_LOAD_EXTENSION */
    +-
    +-/*
    +-** The auto-extension code added regardless of whether or not extension
    +-** loading is supported.  We need a dummy sqlite3Apis pointer for that
    +-** code if regular extension loading is not available.  This is that
    +-** dummy pointer.
    +-*/
    +-#ifdef SQLITE_OMIT_LOAD_EXTENSION
    +-static const sqlite3_api_routines sqlite3Apis;
    +-#endif
    +-
    ++#endif /* !defined(SQLITE_OMIT_LOAD_EXTENSION) */
    + 
    + /*
    + ** The following object holds the list of automatically loaded
    +@@ -105217,7 +114503,9 @@ static SQLITE_WSD struct sqlite3AutoExtList {
    + ** Register a statically linked extension that is automatically
    + ** loaded by every new database connection.
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_auto_extension(void (*xInit)(void)){
    ++SQLITE_API int sqlite3_auto_extension(
    ++  void (*xInit)(void)
    ++){
    +   int rc = SQLITE_OK;
    + #ifndef SQLITE_OMIT_AUTOINIT
    +   rc = sqlite3_initialize();
    +@@ -105240,7 +114528,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_auto_extension(void (*xInit)(void)){
    +       void (**aNew)(void);
    +       aNew = sqlite3_realloc64(wsdAutoext.aExt, nByte);
    +       if( aNew==0 ){
    +-        rc = SQLITE_NOMEM;
    ++        rc = SQLITE_NOMEM_BKPT;
    +       }else{
    +         wsdAutoext.aExt = aNew;
    +         wsdAutoext.aExt[wsdAutoext.nExt] = xInit;
    +@@ -105262,7 +114550,9 @@ SQLITE_API int SQLITE_STDCALL sqlite3_auto_extension(void (*xInit)(void)){
    + ** Return 1 if xInit was found on the list and removed.  Return 0 if xInit
    + ** was not on the list.
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_cancel_auto_extension(void (*xInit)(void)){
    ++SQLITE_API int sqlite3_cancel_auto_extension(
    ++  void (*xInit)(void)
    ++){
    + #if SQLITE_THREADSAFE
    +   sqlite3_mutex *mutex = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MASTER);
    + #endif
    +@@ -105285,7 +114575,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_cancel_auto_extension(void (*xInit)(void))
    + /*
    + ** Reset the automatic extension loading mechanism.
    + */
    +-SQLITE_API void SQLITE_STDCALL sqlite3_reset_auto_extension(void){
    ++SQLITE_API void sqlite3_reset_auto_extension(void){
    + #ifndef SQLITE_OMIT_AUTOINIT
    +   if( sqlite3_initialize()==SQLITE_OK )
    + #endif
    +@@ -105311,7 +114601,7 @@ SQLITE_PRIVATE void sqlite3AutoLoadExtensions(sqlite3 *db){
    +   u32 i;
    +   int go = 1;
    +   int rc;
    +-  int (*xInit)(sqlite3*,char**,const sqlite3_api_routines*);
    ++  sqlite3_loadext_entry xInit;
    + 
    +   wsdAutoextInit;
    +   if( wsdAutoext.nExt==0 ){
    +@@ -105322,18 +114612,22 @@ SQLITE_PRIVATE void sqlite3AutoLoadExtensions(sqlite3 *db){
    +     char *zErrmsg;
    + #if SQLITE_THREADSAFE
    +     sqlite3_mutex *mutex = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MASTER);
    ++#endif
    ++#ifdef SQLITE_OMIT_LOAD_EXTENSION
    ++    const sqlite3_api_routines *pThunk = 0;
    ++#else
    ++    const sqlite3_api_routines *pThunk = &sqlite3Apis;
    + #endif
    +     sqlite3_mutex_enter(mutex);
    +     if( i>=wsdAutoext.nExt ){
    +       xInit = 0;
    +       go = 0;
    +     }else{
    +-      xInit = (int(*)(sqlite3*,char**,const sqlite3_api_routines*))
    +-              wsdAutoext.aExt[i];
    ++      xInit = (sqlite3_loadext_entry)wsdAutoext.aExt[i];
    +     }
    +     sqlite3_mutex_leave(mutex);
    +     zErrmsg = 0;
    +-    if( xInit && (rc = xInit(db, &zErrmsg, &sqlite3Apis))!=0 ){
    ++    if( xInit && (rc = xInit(db, &zErrmsg, pThunk))!=0 ){
    +       sqlite3ErrorWithMsg(db, rc,
    +             "automatic extension loading failed: %s", zErrmsg);
    +       go = 0;
    +@@ -105381,472 +114675,658 @@ SQLITE_PRIVATE void sqlite3AutoLoadExtensions(sqlite3 *db){
    + ** ../tool/mkpragmatab.tcl.  To update the set of pragmas, edit
    + ** that script and rerun it.
    + */
    ++
    ++/* The various pragma types */
    + #define PragTyp_HEADER_VALUE                   0
    + #define PragTyp_AUTO_VACUUM                    1
    + #define PragTyp_FLAG                           2
    + #define PragTyp_BUSY_TIMEOUT                   3
    + #define PragTyp_CACHE_SIZE                     4
    +-#define PragTyp_CASE_SENSITIVE_LIKE            5
    +-#define PragTyp_COLLATION_LIST                 6
    +-#define PragTyp_COMPILE_OPTIONS                7
    +-#define PragTyp_DATA_STORE_DIRECTORY           8
    +-#define PragTyp_DATABASE_LIST                  9
    +-#define PragTyp_DEFAULT_CACHE_SIZE            10
    +-#define PragTyp_ENCODING                      11
    +-#define PragTyp_FOREIGN_KEY_CHECK             12
    +-#define PragTyp_FOREIGN_KEY_LIST              13
    +-#define PragTyp_INCREMENTAL_VACUUM            14
    +-#define PragTyp_INDEX_INFO                    15
    +-#define PragTyp_INDEX_LIST                    16
    +-#define PragTyp_INTEGRITY_CHECK               17
    +-#define PragTyp_JOURNAL_MODE                  18
    +-#define PragTyp_JOURNAL_SIZE_LIMIT            19
    +-#define PragTyp_LOCK_PROXY_FILE               20
    +-#define PragTyp_LOCKING_MODE                  21
    +-#define PragTyp_PAGE_COUNT                    22
    +-#define PragTyp_MMAP_SIZE                     23
    +-#define PragTyp_PAGE_SIZE                     24
    +-#define PragTyp_SECURE_DELETE                 25
    +-#define PragTyp_SHRINK_MEMORY                 26
    +-#define PragTyp_SOFT_HEAP_LIMIT               27
    +-#define PragTyp_STATS                         28
    +-#define PragTyp_SYNCHRONOUS                   29
    +-#define PragTyp_TABLE_INFO                    30
    +-#define PragTyp_TEMP_STORE                    31
    +-#define PragTyp_TEMP_STORE_DIRECTORY          32
    +-#define PragTyp_THREADS                       33
    +-#define PragTyp_WAL_AUTOCHECKPOINT            34
    +-#define PragTyp_WAL_CHECKPOINT                35
    +-#define PragTyp_ACTIVATE_EXTENSIONS           36
    +-#define PragTyp_HEXKEY                        37
    +-#define PragTyp_KEY                           38
    +-#define PragTyp_REKEY                         39
    +-#define PragTyp_LOCK_STATUS                   40
    +-#define PragTyp_PARSER_TRACE                  41
    +-#define PragFlag_NeedSchema           0x01
    +-#define PragFlag_ReadOnly             0x02
    +-static const struct sPragmaNames {
    +-  const char *const zName;  /* Name of pragma */
    +-  u8 ePragTyp;              /* PragTyp_XXX value */
    +-  u8 mPragFlag;             /* Zero or more PragFlag_XXX values */
    +-  u32 iArg;                 /* Extra argument */
    +-} aPragmaNames[] = {
    ++#define PragTyp_CACHE_SPILL                    5
    ++#define PragTyp_CASE_SENSITIVE_LIKE            6
    ++#define PragTyp_COLLATION_LIST                 7
    ++#define PragTyp_COMPILE_OPTIONS                8
    ++#define PragTyp_DATA_STORE_DIRECTORY           9
    ++#define PragTyp_DATABASE_LIST                 10
    ++#define PragTyp_DEFAULT_CACHE_SIZE            11
    ++#define PragTyp_ENCODING                      12
    ++#define PragTyp_FOREIGN_KEY_CHECK             13
    ++#define PragTyp_FOREIGN_KEY_LIST              14
    ++#define PragTyp_FUNCTION_LIST                 15
    ++#define PragTyp_INCREMENTAL_VACUUM            16
    ++#define PragTyp_INDEX_INFO                    17
    ++#define PragTyp_INDEX_LIST                    18
    ++#define PragTyp_INTEGRITY_CHECK               19
    ++#define PragTyp_JOURNAL_MODE                  20
    ++#define PragTyp_JOURNAL_SIZE_LIMIT            21
    ++#define PragTyp_LOCK_PROXY_FILE               22
    ++#define PragTyp_LOCKING_MODE                  23
    ++#define PragTyp_PAGE_COUNT                    24
    ++#define PragTyp_MMAP_SIZE                     25
    ++#define PragTyp_MODULE_LIST                   26
    ++#define PragTyp_OPTIMIZE                      27
    ++#define PragTyp_PAGE_SIZE                     28
    ++#define PragTyp_PRAGMA_LIST                   29
    ++#define PragTyp_SECURE_DELETE                 30
    ++#define PragTyp_SHRINK_MEMORY                 31
    ++#define PragTyp_SOFT_HEAP_LIMIT               32
    ++#define PragTyp_SYNCHRONOUS                   33
    ++#define PragTyp_TABLE_INFO                    34
    ++#define PragTyp_TEMP_STORE                    35
    ++#define PragTyp_TEMP_STORE_DIRECTORY          36
    ++#define PragTyp_THREADS                       37
    ++#define PragTyp_WAL_AUTOCHECKPOINT            38
    ++#define PragTyp_WAL_CHECKPOINT                39
    ++#define PragTyp_ACTIVATE_EXTENSIONS           40
    ++#define PragTyp_HEXKEY                        41
    ++#define PragTyp_KEY                           42
    ++#define PragTyp_REKEY                         43
    ++#define PragTyp_LOCK_STATUS                   44
    ++#define PragTyp_PARSER_TRACE                  45
    ++#define PragTyp_STATS                         46
    ++
    ++/* Property flags associated with various pragma. */
    ++#define PragFlg_NeedSchema 0x01 /* Force schema load before running */
    ++#define PragFlg_NoColumns  0x02 /* OP_ResultRow called with zero columns */
    ++#define PragFlg_NoColumns1 0x04 /* zero columns if RHS argument is present */
    ++#define PragFlg_ReadOnly   0x08 /* Read-only HEADER_VALUE */
    ++#define PragFlg_Result0    0x10 /* Acts as query when no argument */
    ++#define PragFlg_Result1    0x20 /* Acts as query when has one argument */
    ++#define PragFlg_SchemaOpt  0x40 /* Schema restricts name search if present */
    ++#define PragFlg_SchemaReq  0x80 /* Schema required - "main" is default */
    ++
    ++/* Names of columns for pragmas that return multi-column result
    ++** or that return single-column results where the name of the
    ++** result column is different from the name of the pragma
    ++*/
    ++static const char *const pragCName[] = {
    ++  /*   0 */ "cache_size",  /* Used by: default_cache_size */
    ++  /*   1 */ "cid",         /* Used by: table_info */
    ++  /*   2 */ "name",       
    ++  /*   3 */ "type",       
    ++  /*   4 */ "notnull",    
    ++  /*   5 */ "dflt_value", 
    ++  /*   6 */ "pk",         
    ++  /*   7 */ "tbl",         /* Used by: stats */
    ++  /*   8 */ "idx",        
    ++  /*   9 */ "wdth",       
    ++  /*  10 */ "hght",       
    ++  /*  11 */ "flgs",       
    ++  /*  12 */ "seqno",       /* Used by: index_info */
    ++  /*  13 */ "cid",        
    ++  /*  14 */ "name",       
    ++  /*  15 */ "seqno",       /* Used by: index_xinfo */
    ++  /*  16 */ "cid",        
    ++  /*  17 */ "name",       
    ++  /*  18 */ "desc",       
    ++  /*  19 */ "coll",       
    ++  /*  20 */ "key",        
    ++  /*  21 */ "seq",         /* Used by: index_list */
    ++  /*  22 */ "name",       
    ++  /*  23 */ "unique",     
    ++  /*  24 */ "origin",     
    ++  /*  25 */ "partial",    
    ++  /*  26 */ "seq",         /* Used by: database_list */
    ++  /*  27 */ "name",       
    ++  /*  28 */ "file",       
    ++  /*  29 */ "name",        /* Used by: function_list */
    ++  /*  30 */ "builtin",    
    ++  /*  31 */ "name",        /* Used by: module_list pragma_list */
    ++  /*  32 */ "seq",         /* Used by: collation_list */
    ++  /*  33 */ "name",       
    ++  /*  34 */ "id",          /* Used by: foreign_key_list */
    ++  /*  35 */ "seq",        
    ++  /*  36 */ "table",      
    ++  /*  37 */ "from",       
    ++  /*  38 */ "to",         
    ++  /*  39 */ "on_update",  
    ++  /*  40 */ "on_delete",  
    ++  /*  41 */ "match",      
    ++  /*  42 */ "table",       /* Used by: foreign_key_check */
    ++  /*  43 */ "rowid",      
    ++  /*  44 */ "parent",     
    ++  /*  45 */ "fkid",       
    ++  /*  46 */ "busy",        /* Used by: wal_checkpoint */
    ++  /*  47 */ "log",        
    ++  /*  48 */ "checkpointed",
    ++  /*  49 */ "timeout",     /* Used by: busy_timeout */
    ++  /*  50 */ "database",    /* Used by: lock_status */
    ++  /*  51 */ "status",     
    ++};
    ++
    ++/* Definitions of all built-in pragmas */
    ++typedef struct PragmaName {
    ++  const char *const zName; /* Name of pragma */
    ++  u8 ePragTyp;             /* PragTyp_XXX value */
    ++  u8 mPragFlg;             /* Zero or more PragFlg_XXX values */
    ++  u8 iPragCName;           /* Start of column names in pragCName[] */
    ++  u8 nPragCName;           /* Num of col names. 0 means use pragma name */
    ++  u32 iArg;                /* Extra argument */
    ++} PragmaName;
    ++static const PragmaName aPragmaName[] = {
    + #if defined(SQLITE_HAS_CODEC) || defined(SQLITE_ENABLE_CEROD)
    +-  { /* zName:     */ "activate_extensions",
    +-    /* ePragTyp:  */ PragTyp_ACTIVATE_EXTENSIONS,
    +-    /* ePragFlag: */ 0,
    +-    /* iArg:      */ 0 },
    ++ {/* zName:     */ "activate_extensions",
    ++  /* ePragTyp:  */ PragTyp_ACTIVATE_EXTENSIONS,
    ++  /* ePragFlg:  */ 0,
    ++  /* ColNames:  */ 0, 0,
    ++  /* iArg:      */ 0 },
    + #endif
    + #if !defined(SQLITE_OMIT_SCHEMA_VERSION_PRAGMAS)
    +-  { /* zName:     */ "application_id",
    +-    /* ePragTyp:  */ PragTyp_HEADER_VALUE,
    +-    /* ePragFlag: */ 0,
    +-    /* iArg:      */ BTREE_APPLICATION_ID },
    ++ {/* zName:     */ "application_id",
    ++  /* ePragTyp:  */ PragTyp_HEADER_VALUE,
    ++  /* ePragFlg:  */ PragFlg_NoColumns1|PragFlg_Result0,
    ++  /* ColNames:  */ 0, 0,
    ++  /* iArg:      */ BTREE_APPLICATION_ID },
    + #endif
    + #if !defined(SQLITE_OMIT_AUTOVACUUM)
    +-  { /* zName:     */ "auto_vacuum",
    +-    /* ePragTyp:  */ PragTyp_AUTO_VACUUM,
    +-    /* ePragFlag: */ PragFlag_NeedSchema,
    +-    /* iArg:      */ 0 },
    ++ {/* zName:     */ "auto_vacuum",
    ++  /* ePragTyp:  */ PragTyp_AUTO_VACUUM,
    ++  /* ePragFlg:  */ PragFlg_NeedSchema|PragFlg_Result0|PragFlg_SchemaReq|PragFlg_NoColumns1,
    ++  /* ColNames:  */ 0, 0,
    ++  /* iArg:      */ 0 },
    + #endif
    + #if !defined(SQLITE_OMIT_FLAG_PRAGMAS)
    + #if !defined(SQLITE_OMIT_AUTOMATIC_INDEX)
    +-  { /* zName:     */ "automatic_index",
    +-    /* ePragTyp:  */ PragTyp_FLAG,
    +-    /* ePragFlag: */ 0,
    +-    /* iArg:      */ SQLITE_AutoIndex },
    +-#endif
    +-#endif
    +-  { /* zName:     */ "busy_timeout",
    +-    /* ePragTyp:  */ PragTyp_BUSY_TIMEOUT,
    +-    /* ePragFlag: */ 0,
    +-    /* iArg:      */ 0 },
    ++ {/* zName:     */ "automatic_index",
    ++  /* ePragTyp:  */ PragTyp_FLAG,
    ++  /* ePragFlg:  */ PragFlg_Result0|PragFlg_NoColumns1,
    ++  /* ColNames:  */ 0, 0,
    ++  /* iArg:      */ SQLITE_AutoIndex },
    ++#endif
    ++#endif
    ++ {/* zName:     */ "busy_timeout",
    ++  /* ePragTyp:  */ PragTyp_BUSY_TIMEOUT,
    ++  /* ePragFlg:  */ PragFlg_Result0,
    ++  /* ColNames:  */ 49, 1,
    ++  /* iArg:      */ 0 },
    + #if !defined(SQLITE_OMIT_PAGER_PRAGMAS)
    +-  { /* zName:     */ "cache_size",
    +-    /* ePragTyp:  */ PragTyp_CACHE_SIZE,
    +-    /* ePragFlag: */ 0,
    +-    /* iArg:      */ 0 },
    ++ {/* zName:     */ "cache_size",
    ++  /* ePragTyp:  */ PragTyp_CACHE_SIZE,
    ++  /* ePragFlg:  */ PragFlg_NeedSchema|PragFlg_Result0|PragFlg_SchemaReq|PragFlg_NoColumns1,
    ++  /* ColNames:  */ 0, 0,
    ++  /* iArg:      */ 0 },
    + #endif
    + #if !defined(SQLITE_OMIT_FLAG_PRAGMAS)
    +-  { /* zName:     */ "cache_spill",
    +-    /* ePragTyp:  */ PragTyp_FLAG,
    +-    /* ePragFlag: */ 0,
    +-    /* iArg:      */ SQLITE_CacheSpill },
    +-#endif
    +-  { /* zName:     */ "case_sensitive_like",
    +-    /* ePragTyp:  */ PragTyp_CASE_SENSITIVE_LIKE,
    +-    /* ePragFlag: */ 0,
    +-    /* iArg:      */ 0 },
    +-  { /* zName:     */ "cell_size_check",
    +-    /* ePragTyp:  */ PragTyp_FLAG,
    +-    /* ePragFlag: */ 0,
    +-    /* iArg:      */ SQLITE_CellSizeCk },
    ++ {/* zName:     */ "cache_spill",
    ++  /* ePragTyp:  */ PragTyp_CACHE_SPILL,
    ++  /* ePragFlg:  */ PragFlg_Result0|PragFlg_SchemaReq|PragFlg_NoColumns1,
    ++  /* ColNames:  */ 0, 0,
    ++  /* iArg:      */ 0 },
    ++#endif
    ++ {/* zName:     */ "case_sensitive_like",
    ++  /* ePragTyp:  */ PragTyp_CASE_SENSITIVE_LIKE,
    ++  /* ePragFlg:  */ PragFlg_NoColumns,
    ++  /* ColNames:  */ 0, 0,
    ++  /* iArg:      */ 0 },
    ++ {/* zName:     */ "cell_size_check",
    ++  /* ePragTyp:  */ PragTyp_FLAG,
    ++  /* ePragFlg:  */ PragFlg_Result0|PragFlg_NoColumns1,
    ++  /* ColNames:  */ 0, 0,
    ++  /* iArg:      */ SQLITE_CellSizeCk },
    + #if !defined(SQLITE_OMIT_FLAG_PRAGMAS)
    +-  { /* zName:     */ "checkpoint_fullfsync",
    +-    /* ePragTyp:  */ PragTyp_FLAG,
    +-    /* ePragFlag: */ 0,
    +-    /* iArg:      */ SQLITE_CkptFullFSync },
    ++ {/* zName:     */ "checkpoint_fullfsync",
    ++  /* ePragTyp:  */ PragTyp_FLAG,
    ++  /* ePragFlg:  */ PragFlg_Result0|PragFlg_NoColumns1,
    ++  /* ColNames:  */ 0, 0,
    ++  /* iArg:      */ SQLITE_CkptFullFSync },
    + #endif
    + #if !defined(SQLITE_OMIT_SCHEMA_PRAGMAS)
    +-  { /* zName:     */ "collation_list",
    +-    /* ePragTyp:  */ PragTyp_COLLATION_LIST,
    +-    /* ePragFlag: */ 0,
    +-    /* iArg:      */ 0 },
    ++ {/* zName:     */ "collation_list",
    ++  /* ePragTyp:  */ PragTyp_COLLATION_LIST,
    ++  /* ePragFlg:  */ PragFlg_Result0,
    ++  /* ColNames:  */ 32, 2,
    ++  /* iArg:      */ 0 },
    + #endif
    + #if !defined(SQLITE_OMIT_COMPILEOPTION_DIAGS)
    +-  { /* zName:     */ "compile_options",
    +-    /* ePragTyp:  */ PragTyp_COMPILE_OPTIONS,
    +-    /* ePragFlag: */ 0,
    +-    /* iArg:      */ 0 },
    ++ {/* zName:     */ "compile_options",
    ++  /* ePragTyp:  */ PragTyp_COMPILE_OPTIONS,
    ++  /* ePragFlg:  */ PragFlg_Result0,
    ++  /* ColNames:  */ 0, 0,
    ++  /* iArg:      */ 0 },
    + #endif
    + #if !defined(SQLITE_OMIT_FLAG_PRAGMAS)
    +-  { /* zName:     */ "count_changes",
    +-    /* ePragTyp:  */ PragTyp_FLAG,
    +-    /* ePragFlag: */ 0,
    +-    /* iArg:      */ SQLITE_CountRows },
    ++ {/* zName:     */ "count_changes",
    ++  /* ePragTyp:  */ PragTyp_FLAG,
    ++  /* ePragFlg:  */ PragFlg_Result0|PragFlg_NoColumns1,
    ++  /* ColNames:  */ 0, 0,
    ++  /* iArg:      */ SQLITE_CountRows },
    + #endif
    + #if !defined(SQLITE_OMIT_PAGER_PRAGMAS) && SQLITE_OS_WIN
    +-  { /* zName:     */ "data_store_directory",
    +-    /* ePragTyp:  */ PragTyp_DATA_STORE_DIRECTORY,
    +-    /* ePragFlag: */ 0,
    +-    /* iArg:      */ 0 },
    ++ {/* zName:     */ "data_store_directory",
    ++  /* ePragTyp:  */ PragTyp_DATA_STORE_DIRECTORY,
    ++  /* ePragFlg:  */ PragFlg_NoColumns1,
    ++  /* ColNames:  */ 0, 0,
    ++  /* iArg:      */ 0 },
    + #endif
    + #if !defined(SQLITE_OMIT_SCHEMA_VERSION_PRAGMAS)
    +-  { /* zName:     */ "data_version",
    +-    /* ePragTyp:  */ PragTyp_HEADER_VALUE,
    +-    /* ePragFlag: */ PragFlag_ReadOnly,
    +-    /* iArg:      */ BTREE_DATA_VERSION },
    ++ {/* zName:     */ "data_version",
    ++  /* ePragTyp:  */ PragTyp_HEADER_VALUE,
    ++  /* ePragFlg:  */ PragFlg_ReadOnly|PragFlg_Result0,
    ++  /* ColNames:  */ 0, 0,
    ++  /* iArg:      */ BTREE_DATA_VERSION },
    + #endif
    + #if !defined(SQLITE_OMIT_SCHEMA_PRAGMAS)
    +-  { /* zName:     */ "database_list",
    +-    /* ePragTyp:  */ PragTyp_DATABASE_LIST,
    +-    /* ePragFlag: */ PragFlag_NeedSchema,
    +-    /* iArg:      */ 0 },
    ++ {/* zName:     */ "database_list",
    ++  /* ePragTyp:  */ PragTyp_DATABASE_LIST,
    ++  /* ePragFlg:  */ PragFlg_NeedSchema|PragFlg_Result0,
    ++  /* ColNames:  */ 26, 3,
    ++  /* iArg:      */ 0 },
    + #endif
    + #if !defined(SQLITE_OMIT_PAGER_PRAGMAS) && !defined(SQLITE_OMIT_DEPRECATED)
    +-  { /* zName:     */ "default_cache_size",
    +-    /* ePragTyp:  */ PragTyp_DEFAULT_CACHE_SIZE,
    +-    /* ePragFlag: */ PragFlag_NeedSchema,
    +-    /* iArg:      */ 0 },
    ++ {/* zName:     */ "default_cache_size",
    ++  /* ePragTyp:  */ PragTyp_DEFAULT_CACHE_SIZE,
    ++  /* ePragFlg:  */ PragFlg_NeedSchema|PragFlg_Result0|PragFlg_SchemaReq|PragFlg_NoColumns1,
    ++  /* ColNames:  */ 0, 1,
    ++  /* iArg:      */ 0 },
    + #endif
    + #if !defined(SQLITE_OMIT_FLAG_PRAGMAS)
    + #if !defined(SQLITE_OMIT_FOREIGN_KEY) && !defined(SQLITE_OMIT_TRIGGER)
    +-  { /* zName:     */ "defer_foreign_keys",
    +-    /* ePragTyp:  */ PragTyp_FLAG,
    +-    /* ePragFlag: */ 0,
    +-    /* iArg:      */ SQLITE_DeferFKs },
    ++ {/* zName:     */ "defer_foreign_keys",
    ++  /* ePragTyp:  */ PragTyp_FLAG,
    ++  /* ePragFlg:  */ PragFlg_Result0|PragFlg_NoColumns1,
    ++  /* ColNames:  */ 0, 0,
    ++  /* iArg:      */ SQLITE_DeferFKs },
    + #endif
    + #endif
    + #if !defined(SQLITE_OMIT_FLAG_PRAGMAS)
    +-  { /* zName:     */ "empty_result_callbacks",
    +-    /* ePragTyp:  */ PragTyp_FLAG,
    +-    /* ePragFlag: */ 0,
    +-    /* iArg:      */ SQLITE_NullCallback },
    ++ {/* zName:     */ "empty_result_callbacks",
    ++  /* ePragTyp:  */ PragTyp_FLAG,
    ++  /* ePragFlg:  */ PragFlg_Result0|PragFlg_NoColumns1,
    ++  /* ColNames:  */ 0, 0,
    ++  /* iArg:      */ SQLITE_NullCallback },
    + #endif
    + #if !defined(SQLITE_OMIT_UTF16)
    +-  { /* zName:     */ "encoding",
    +-    /* ePragTyp:  */ PragTyp_ENCODING,
    +-    /* ePragFlag: */ 0,
    +-    /* iArg:      */ 0 },
    ++ {/* zName:     */ "encoding",
    ++  /* ePragTyp:  */ PragTyp_ENCODING,
    ++  /* ePragFlg:  */ PragFlg_Result0|PragFlg_NoColumns1,
    ++  /* ColNames:  */ 0, 0,
    ++  /* iArg:      */ 0 },
    + #endif
    + #if !defined(SQLITE_OMIT_FOREIGN_KEY) && !defined(SQLITE_OMIT_TRIGGER)
    +-  { /* zName:     */ "foreign_key_check",
    +-    /* ePragTyp:  */ PragTyp_FOREIGN_KEY_CHECK,
    +-    /* ePragFlag: */ PragFlag_NeedSchema,
    +-    /* iArg:      */ 0 },
    ++ {/* zName:     */ "foreign_key_check",
    ++  /* ePragTyp:  */ PragTyp_FOREIGN_KEY_CHECK,
    ++  /* ePragFlg:  */ PragFlg_NeedSchema|PragFlg_Result0,
    ++  /* ColNames:  */ 42, 4,
    ++  /* iArg:      */ 0 },
    + #endif
    + #if !defined(SQLITE_OMIT_FOREIGN_KEY)
    +-  { /* zName:     */ "foreign_key_list",
    +-    /* ePragTyp:  */ PragTyp_FOREIGN_KEY_LIST,
    +-    /* ePragFlag: */ PragFlag_NeedSchema,
    +-    /* iArg:      */ 0 },
    ++ {/* zName:     */ "foreign_key_list",
    ++  /* ePragTyp:  */ PragTyp_FOREIGN_KEY_LIST,
    ++  /* ePragFlg:  */ PragFlg_NeedSchema|PragFlg_Result1|PragFlg_SchemaOpt,
    ++  /* ColNames:  */ 34, 8,
    ++  /* iArg:      */ 0 },
    + #endif
    + #if !defined(SQLITE_OMIT_FLAG_PRAGMAS)
    + #if !defined(SQLITE_OMIT_FOREIGN_KEY) && !defined(SQLITE_OMIT_TRIGGER)
    +-  { /* zName:     */ "foreign_keys",
    +-    /* ePragTyp:  */ PragTyp_FLAG,
    +-    /* ePragFlag: */ 0,
    +-    /* iArg:      */ SQLITE_ForeignKeys },
    ++ {/* zName:     */ "foreign_keys",
    ++  /* ePragTyp:  */ PragTyp_FLAG,
    ++  /* ePragFlg:  */ PragFlg_Result0|PragFlg_NoColumns1,
    ++  /* ColNames:  */ 0, 0,
    ++  /* iArg:      */ SQLITE_ForeignKeys },
    + #endif
    + #endif
    + #if !defined(SQLITE_OMIT_SCHEMA_VERSION_PRAGMAS)
    +-  { /* zName:     */ "freelist_count",
    +-    /* ePragTyp:  */ PragTyp_HEADER_VALUE,
    +-    /* ePragFlag: */ PragFlag_ReadOnly,
    +-    /* iArg:      */ BTREE_FREE_PAGE_COUNT },
    ++ {/* zName:     */ "freelist_count",
    ++  /* ePragTyp:  */ PragTyp_HEADER_VALUE,
    ++  /* ePragFlg:  */ PragFlg_ReadOnly|PragFlg_Result0,
    ++  /* ColNames:  */ 0, 0,
    ++  /* iArg:      */ BTREE_FREE_PAGE_COUNT },
    + #endif
    + #if !defined(SQLITE_OMIT_FLAG_PRAGMAS)
    +-  { /* zName:     */ "full_column_names",
    +-    /* ePragTyp:  */ PragTyp_FLAG,
    +-    /* ePragFlag: */ 0,
    +-    /* iArg:      */ SQLITE_FullColNames },
    +-  { /* zName:     */ "fullfsync",
    +-    /* ePragTyp:  */ PragTyp_FLAG,
    +-    /* ePragFlag: */ 0,
    +-    /* iArg:      */ SQLITE_FullFSync },
    ++ {/* zName:     */ "full_column_names",
    ++  /* ePragTyp:  */ PragTyp_FLAG,
    ++  /* ePragFlg:  */ PragFlg_Result0|PragFlg_NoColumns1,
    ++  /* ColNames:  */ 0, 0,
    ++  /* iArg:      */ SQLITE_FullColNames },
    ++ {/* zName:     */ "fullfsync",
    ++  /* ePragTyp:  */ PragTyp_FLAG,
    ++  /* ePragFlg:  */ PragFlg_Result0|PragFlg_NoColumns1,
    ++  /* ColNames:  */ 0, 0,
    ++  /* iArg:      */ SQLITE_FullFSync },
    ++#endif
    ++#if !defined(SQLITE_OMIT_SCHEMA_PRAGMAS)
    ++#if defined(SQLITE_INTROSPECTION_PRAGMAS)
    ++ {/* zName:     */ "function_list",
    ++  /* ePragTyp:  */ PragTyp_FUNCTION_LIST,
    ++  /* ePragFlg:  */ PragFlg_Result0,
    ++  /* ColNames:  */ 29, 2,
    ++  /* iArg:      */ 0 },
    ++#endif
    + #endif
    + #if defined(SQLITE_HAS_CODEC)
    +-  { /* zName:     */ "hexkey",
    +-    /* ePragTyp:  */ PragTyp_HEXKEY,
    +-    /* ePragFlag: */ 0,
    +-    /* iArg:      */ 0 },
    +-  { /* zName:     */ "hexrekey",
    +-    /* ePragTyp:  */ PragTyp_HEXKEY,
    +-    /* ePragFlag: */ 0,
    +-    /* iArg:      */ 0 },
    ++ {/* zName:     */ "hexkey",
    ++  /* ePragTyp:  */ PragTyp_HEXKEY,
    ++  /* ePragFlg:  */ 0,
    ++  /* ColNames:  */ 0, 0,
    ++  /* iArg:      */ 0 },
    ++ {/* zName:     */ "hexrekey",
    ++  /* ePragTyp:  */ PragTyp_HEXKEY,
    ++  /* ePragFlg:  */ 0,
    ++  /* ColNames:  */ 0, 0,
    ++  /* iArg:      */ 0 },
    + #endif
    + #if !defined(SQLITE_OMIT_FLAG_PRAGMAS)
    + #if !defined(SQLITE_OMIT_CHECK)
    +-  { /* zName:     */ "ignore_check_constraints",
    +-    /* ePragTyp:  */ PragTyp_FLAG,
    +-    /* ePragFlag: */ 0,
    +-    /* iArg:      */ SQLITE_IgnoreChecks },
    ++ {/* zName:     */ "ignore_check_constraints",
    ++  /* ePragTyp:  */ PragTyp_FLAG,
    ++  /* ePragFlg:  */ PragFlg_Result0|PragFlg_NoColumns1,
    ++  /* ColNames:  */ 0, 0,
    ++  /* iArg:      */ SQLITE_IgnoreChecks },
    + #endif
    + #endif
    + #if !defined(SQLITE_OMIT_AUTOVACUUM)
    +-  { /* zName:     */ "incremental_vacuum",
    +-    /* ePragTyp:  */ PragTyp_INCREMENTAL_VACUUM,
    +-    /* ePragFlag: */ PragFlag_NeedSchema,
    +-    /* iArg:      */ 0 },
    ++ {/* zName:     */ "incremental_vacuum",
    ++  /* ePragTyp:  */ PragTyp_INCREMENTAL_VACUUM,
    ++  /* ePragFlg:  */ PragFlg_NeedSchema|PragFlg_NoColumns,
    ++  /* ColNames:  */ 0, 0,
    ++  /* iArg:      */ 0 },
    + #endif
    + #if !defined(SQLITE_OMIT_SCHEMA_PRAGMAS)
    +-  { /* zName:     */ "index_info",
    +-    /* ePragTyp:  */ PragTyp_INDEX_INFO,
    +-    /* ePragFlag: */ PragFlag_NeedSchema,
    +-    /* iArg:      */ 0 },
    +-  { /* zName:     */ "index_list",
    +-    /* ePragTyp:  */ PragTyp_INDEX_LIST,
    +-    /* ePragFlag: */ PragFlag_NeedSchema,
    +-    /* iArg:      */ 0 },
    +-  { /* zName:     */ "index_xinfo",
    +-    /* ePragTyp:  */ PragTyp_INDEX_INFO,
    +-    /* ePragFlag: */ PragFlag_NeedSchema,
    +-    /* iArg:      */ 1 },
    ++ {/* zName:     */ "index_info",
    ++  /* ePragTyp:  */ PragTyp_INDEX_INFO,
    ++  /* ePragFlg:  */ PragFlg_NeedSchema|PragFlg_Result1|PragFlg_SchemaOpt,
    ++  /* ColNames:  */ 12, 3,
    ++  /* iArg:      */ 0 },
    ++ {/* zName:     */ "index_list",
    ++  /* ePragTyp:  */ PragTyp_INDEX_LIST,
    ++  /* ePragFlg:  */ PragFlg_NeedSchema|PragFlg_Result1|PragFlg_SchemaOpt,
    ++  /* ColNames:  */ 21, 5,
    ++  /* iArg:      */ 0 },
    ++ {/* zName:     */ "index_xinfo",
    ++  /* ePragTyp:  */ PragTyp_INDEX_INFO,
    ++  /* ePragFlg:  */ PragFlg_NeedSchema|PragFlg_Result1|PragFlg_SchemaOpt,
    ++  /* ColNames:  */ 15, 6,
    ++  /* iArg:      */ 1 },
    + #endif
    + #if !defined(SQLITE_OMIT_INTEGRITY_CHECK)
    +-  { /* zName:     */ "integrity_check",
    +-    /* ePragTyp:  */ PragTyp_INTEGRITY_CHECK,
    +-    /* ePragFlag: */ PragFlag_NeedSchema,
    +-    /* iArg:      */ 0 },
    ++ {/* zName:     */ "integrity_check",
    ++  /* ePragTyp:  */ PragTyp_INTEGRITY_CHECK,
    ++  /* ePragFlg:  */ PragFlg_NeedSchema|PragFlg_Result0|PragFlg_Result1,
    ++  /* ColNames:  */ 0, 0,
    ++  /* iArg:      */ 0 },
    + #endif
    + #if !defined(SQLITE_OMIT_PAGER_PRAGMAS)
    +-  { /* zName:     */ "journal_mode",
    +-    /* ePragTyp:  */ PragTyp_JOURNAL_MODE,
    +-    /* ePragFlag: */ PragFlag_NeedSchema,
    +-    /* iArg:      */ 0 },
    +-  { /* zName:     */ "journal_size_limit",
    +-    /* ePragTyp:  */ PragTyp_JOURNAL_SIZE_LIMIT,
    +-    /* ePragFlag: */ 0,
    +-    /* iArg:      */ 0 },
    ++ {/* zName:     */ "journal_mode",
    ++  /* ePragTyp:  */ PragTyp_JOURNAL_MODE,
    ++  /* ePragFlg:  */ PragFlg_NeedSchema|PragFlg_Result0|PragFlg_SchemaReq,
    ++  /* ColNames:  */ 0, 0,
    ++  /* iArg:      */ 0 },
    ++ {/* zName:     */ "journal_size_limit",
    ++  /* ePragTyp:  */ PragTyp_JOURNAL_SIZE_LIMIT,
    ++  /* ePragFlg:  */ PragFlg_Result0|PragFlg_SchemaReq,
    ++  /* ColNames:  */ 0, 0,
    ++  /* iArg:      */ 0 },
    + #endif
    + #if defined(SQLITE_HAS_CODEC)
    +-  { /* zName:     */ "key",
    +-    /* ePragTyp:  */ PragTyp_KEY,
    +-    /* ePragFlag: */ 0,
    +-    /* iArg:      */ 0 },
    ++ {/* zName:     */ "key",
    ++  /* ePragTyp:  */ PragTyp_KEY,
    ++  /* ePragFlg:  */ 0,
    ++  /* ColNames:  */ 0, 0,
    ++  /* iArg:      */ 0 },
    + #endif
    + #if !defined(SQLITE_OMIT_FLAG_PRAGMAS)
    +-  { /* zName:     */ "legacy_file_format",
    +-    /* ePragTyp:  */ PragTyp_FLAG,
    +-    /* ePragFlag: */ 0,
    +-    /* iArg:      */ SQLITE_LegacyFileFmt },
    ++ {/* zName:     */ "legacy_file_format",
    ++  /* ePragTyp:  */ PragTyp_FLAG,
    ++  /* ePragFlg:  */ PragFlg_Result0|PragFlg_NoColumns1,
    ++  /* ColNames:  */ 0, 0,
    ++  /* iArg:      */ SQLITE_LegacyFileFmt },
    + #endif
    + #if !defined(SQLITE_OMIT_PAGER_PRAGMAS) && SQLITE_ENABLE_LOCKING_STYLE
    +-  { /* zName:     */ "lock_proxy_file",
    +-    /* ePragTyp:  */ PragTyp_LOCK_PROXY_FILE,
    +-    /* ePragFlag: */ 0,
    +-    /* iArg:      */ 0 },
    ++ {/* zName:     */ "lock_proxy_file",
    ++  /* ePragTyp:  */ PragTyp_LOCK_PROXY_FILE,
    ++  /* ePragFlg:  */ PragFlg_NoColumns1,
    ++  /* ColNames:  */ 0, 0,
    ++  /* iArg:      */ 0 },
    + #endif
    + #if defined(SQLITE_DEBUG) || defined(SQLITE_TEST)
    +-  { /* zName:     */ "lock_status",
    +-    /* ePragTyp:  */ PragTyp_LOCK_STATUS,
    +-    /* ePragFlag: */ 0,
    +-    /* iArg:      */ 0 },
    ++ {/* zName:     */ "lock_status",
    ++  /* ePragTyp:  */ PragTyp_LOCK_STATUS,
    ++  /* ePragFlg:  */ PragFlg_Result0,
    ++  /* ColNames:  */ 50, 2,
    ++  /* iArg:      */ 0 },
    + #endif
    + #if !defined(SQLITE_OMIT_PAGER_PRAGMAS)
    +-  { /* zName:     */ "locking_mode",
    +-    /* ePragTyp:  */ PragTyp_LOCKING_MODE,
    +-    /* ePragFlag: */ 0,
    +-    /* iArg:      */ 0 },
    +-  { /* zName:     */ "max_page_count",
    +-    /* ePragTyp:  */ PragTyp_PAGE_COUNT,
    +-    /* ePragFlag: */ PragFlag_NeedSchema,
    +-    /* iArg:      */ 0 },
    +-  { /* zName:     */ "mmap_size",
    +-    /* ePragTyp:  */ PragTyp_MMAP_SIZE,
    +-    /* ePragFlag: */ 0,
    +-    /* iArg:      */ 0 },
    +-  { /* zName:     */ "page_count",
    +-    /* ePragTyp:  */ PragTyp_PAGE_COUNT,
    +-    /* ePragFlag: */ PragFlag_NeedSchema,
    +-    /* iArg:      */ 0 },
    +-  { /* zName:     */ "page_size",
    +-    /* ePragTyp:  */ PragTyp_PAGE_SIZE,
    +-    /* ePragFlag: */ 0,
    +-    /* iArg:      */ 0 },
    ++ {/* zName:     */ "locking_mode",
    ++  /* ePragTyp:  */ PragTyp_LOCKING_MODE,
    ++  /* ePragFlg:  */ PragFlg_Result0|PragFlg_SchemaReq,
    ++  /* ColNames:  */ 0, 0,
    ++  /* iArg:      */ 0 },
    ++ {/* zName:     */ "max_page_count",
    ++  /* ePragTyp:  */ PragTyp_PAGE_COUNT,
    ++  /* ePragFlg:  */ PragFlg_NeedSchema|PragFlg_Result0|PragFlg_SchemaReq,
    ++  /* ColNames:  */ 0, 0,
    ++  /* iArg:      */ 0 },
    ++ {/* zName:     */ "mmap_size",
    ++  /* ePragTyp:  */ PragTyp_MMAP_SIZE,
    ++  /* ePragFlg:  */ 0,
    ++  /* ColNames:  */ 0, 0,
    ++  /* iArg:      */ 0 },
    + #endif
    +-#if defined(SQLITE_DEBUG)
    +-  { /* zName:     */ "parser_trace",
    +-    /* ePragTyp:  */ PragTyp_PARSER_TRACE,
    +-    /* ePragFlag: */ 0,
    +-    /* iArg:      */ 0 },
    ++#if !defined(SQLITE_OMIT_SCHEMA_PRAGMAS)
    ++#if !defined(SQLITE_OMIT_VIRTUALTABLE)
    ++#if defined(SQLITE_INTROSPECTION_PRAGMAS)
    ++ {/* zName:     */ "module_list",
    ++  /* ePragTyp:  */ PragTyp_MODULE_LIST,
    ++  /* ePragFlg:  */ PragFlg_Result0,
    ++  /* ColNames:  */ 31, 1,
    ++  /* iArg:      */ 0 },
    ++#endif
    ++#endif
    ++#endif
    ++ {/* zName:     */ "optimize",
    ++  /* ePragTyp:  */ PragTyp_OPTIMIZE,
    ++  /* ePragFlg:  */ PragFlg_Result1|PragFlg_NeedSchema,
    ++  /* ColNames:  */ 0, 0,
    ++  /* iArg:      */ 0 },
    ++#if !defined(SQLITE_OMIT_PAGER_PRAGMAS)
    ++ {/* zName:     */ "page_count",
    ++  /* ePragTyp:  */ PragTyp_PAGE_COUNT,
    ++  /* ePragFlg:  */ PragFlg_NeedSchema|PragFlg_Result0|PragFlg_SchemaReq,
    ++  /* ColNames:  */ 0, 0,
    ++  /* iArg:      */ 0 },
    ++ {/* zName:     */ "page_size",
    ++  /* ePragTyp:  */ PragTyp_PAGE_SIZE,
    ++  /* ePragFlg:  */ PragFlg_Result0|PragFlg_SchemaReq|PragFlg_NoColumns1,
    ++  /* ColNames:  */ 0, 0,
    ++  /* iArg:      */ 0 },
    ++#endif
    ++#if defined(SQLITE_DEBUG) && !defined(SQLITE_OMIT_PARSER_TRACE)
    ++ {/* zName:     */ "parser_trace",
    ++  /* ePragTyp:  */ PragTyp_PARSER_TRACE,
    ++  /* ePragFlg:  */ 0,
    ++  /* ColNames:  */ 0, 0,
    ++  /* iArg:      */ 0 },
    ++#endif
    ++#if defined(SQLITE_INTROSPECTION_PRAGMAS)
    ++ {/* zName:     */ "pragma_list",
    ++  /* ePragTyp:  */ PragTyp_PRAGMA_LIST,
    ++  /* ePragFlg:  */ PragFlg_Result0,
    ++  /* ColNames:  */ 31, 1,
    ++  /* iArg:      */ 0 },
    + #endif
    + #if !defined(SQLITE_OMIT_FLAG_PRAGMAS)
    +-  { /* zName:     */ "query_only",
    +-    /* ePragTyp:  */ PragTyp_FLAG,
    +-    /* ePragFlag: */ 0,
    +-    /* iArg:      */ SQLITE_QueryOnly },
    ++ {/* zName:     */ "query_only",
    ++  /* ePragTyp:  */ PragTyp_FLAG,
    ++  /* ePragFlg:  */ PragFlg_Result0|PragFlg_NoColumns1,
    ++  /* ColNames:  */ 0, 0,
    ++  /* iArg:      */ SQLITE_QueryOnly },
    + #endif
    + #if !defined(SQLITE_OMIT_INTEGRITY_CHECK)
    +-  { /* zName:     */ "quick_check",
    +-    /* ePragTyp:  */ PragTyp_INTEGRITY_CHECK,
    +-    /* ePragFlag: */ PragFlag_NeedSchema,
    +-    /* iArg:      */ 0 },
    ++ {/* zName:     */ "quick_check",
    ++  /* ePragTyp:  */ PragTyp_INTEGRITY_CHECK,
    ++  /* ePragFlg:  */ PragFlg_NeedSchema|PragFlg_Result0|PragFlg_Result1,
    ++  /* ColNames:  */ 0, 0,
    ++  /* iArg:      */ 0 },
    + #endif
    + #if !defined(SQLITE_OMIT_FLAG_PRAGMAS)
    +-  { /* zName:     */ "read_uncommitted",
    +-    /* ePragTyp:  */ PragTyp_FLAG,
    +-    /* ePragFlag: */ 0,
    +-    /* iArg:      */ SQLITE_ReadUncommitted },
    +-  { /* zName:     */ "recursive_triggers",
    +-    /* ePragTyp:  */ PragTyp_FLAG,
    +-    /* ePragFlag: */ 0,
    +-    /* iArg:      */ SQLITE_RecTriggers },
    ++ {/* zName:     */ "read_uncommitted",
    ++  /* ePragTyp:  */ PragTyp_FLAG,
    ++  /* ePragFlg:  */ PragFlg_Result0|PragFlg_NoColumns1,
    ++  /* ColNames:  */ 0, 0,
    ++  /* iArg:      */ SQLITE_ReadUncommit },
    ++ {/* zName:     */ "recursive_triggers",
    ++  /* ePragTyp:  */ PragTyp_FLAG,
    ++  /* ePragFlg:  */ PragFlg_Result0|PragFlg_NoColumns1,
    ++  /* ColNames:  */ 0, 0,
    ++  /* iArg:      */ SQLITE_RecTriggers },
    + #endif
    + #if defined(SQLITE_HAS_CODEC)
    +-  { /* zName:     */ "rekey",
    +-    /* ePragTyp:  */ PragTyp_REKEY,
    +-    /* ePragFlag: */ 0,
    +-    /* iArg:      */ 0 },
    ++ {/* zName:     */ "rekey",
    ++  /* ePragTyp:  */ PragTyp_REKEY,
    ++  /* ePragFlg:  */ 0,
    ++  /* ColNames:  */ 0, 0,
    ++  /* iArg:      */ 0 },
    + #endif
    + #if !defined(SQLITE_OMIT_FLAG_PRAGMAS)
    +-  { /* zName:     */ "reverse_unordered_selects",
    +-    /* ePragTyp:  */ PragTyp_FLAG,
    +-    /* ePragFlag: */ 0,
    +-    /* iArg:      */ SQLITE_ReverseOrder },
    ++ {/* zName:     */ "reverse_unordered_selects",
    ++  /* ePragTyp:  */ PragTyp_FLAG,
    ++  /* ePragFlg:  */ PragFlg_Result0|PragFlg_NoColumns1,
    ++  /* ColNames:  */ 0, 0,
    ++  /* iArg:      */ SQLITE_ReverseOrder },
    + #endif
    + #if !defined(SQLITE_OMIT_SCHEMA_VERSION_PRAGMAS)
    +-  { /* zName:     */ "schema_version",
    +-    /* ePragTyp:  */ PragTyp_HEADER_VALUE,
    +-    /* ePragFlag: */ 0,
    +-    /* iArg:      */ BTREE_SCHEMA_VERSION },
    ++ {/* zName:     */ "schema_version",
    ++  /* ePragTyp:  */ PragTyp_HEADER_VALUE,
    ++  /* ePragFlg:  */ PragFlg_NoColumns1|PragFlg_Result0,
    ++  /* ColNames:  */ 0, 0,
    ++  /* iArg:      */ BTREE_SCHEMA_VERSION },
    + #endif
    + #if !defined(SQLITE_OMIT_PAGER_PRAGMAS)
    +-  { /* zName:     */ "secure_delete",
    +-    /* ePragTyp:  */ PragTyp_SECURE_DELETE,
    +-    /* ePragFlag: */ 0,
    +-    /* iArg:      */ 0 },
    ++ {/* zName:     */ "secure_delete",
    ++  /* ePragTyp:  */ PragTyp_SECURE_DELETE,
    ++  /* ePragFlg:  */ PragFlg_Result0,
    ++  /* ColNames:  */ 0, 0,
    ++  /* iArg:      */ 0 },
    + #endif
    + #if !defined(SQLITE_OMIT_FLAG_PRAGMAS)
    +-  { /* zName:     */ "short_column_names",
    +-    /* ePragTyp:  */ PragTyp_FLAG,
    +-    /* ePragFlag: */ 0,
    +-    /* iArg:      */ SQLITE_ShortColNames },
    +-#endif
    +-  { /* zName:     */ "shrink_memory",
    +-    /* ePragTyp:  */ PragTyp_SHRINK_MEMORY,
    +-    /* ePragFlag: */ 0,
    +-    /* iArg:      */ 0 },
    +-  { /* zName:     */ "soft_heap_limit",
    +-    /* ePragTyp:  */ PragTyp_SOFT_HEAP_LIMIT,
    +-    /* ePragFlag: */ 0,
    +-    /* iArg:      */ 0 },
    ++ {/* zName:     */ "short_column_names",
    ++  /* ePragTyp:  */ PragTyp_FLAG,
    ++  /* ePragFlg:  */ PragFlg_Result0|PragFlg_NoColumns1,
    ++  /* ColNames:  */ 0, 0,
    ++  /* iArg:      */ SQLITE_ShortColNames },
    ++#endif
    ++ {/* zName:     */ "shrink_memory",
    ++  /* ePragTyp:  */ PragTyp_SHRINK_MEMORY,
    ++  /* ePragFlg:  */ PragFlg_NoColumns,
    ++  /* ColNames:  */ 0, 0,
    ++  /* iArg:      */ 0 },
    ++ {/* zName:     */ "soft_heap_limit",
    ++  /* ePragTyp:  */ PragTyp_SOFT_HEAP_LIMIT,
    ++  /* ePragFlg:  */ PragFlg_Result0,
    ++  /* ColNames:  */ 0, 0,
    ++  /* iArg:      */ 0 },
    + #if !defined(SQLITE_OMIT_FLAG_PRAGMAS)
    + #if defined(SQLITE_DEBUG)
    +-  { /* zName:     */ "sql_trace",
    +-    /* ePragTyp:  */ PragTyp_FLAG,
    +-    /* ePragFlag: */ 0,
    +-    /* iArg:      */ SQLITE_SqlTrace },
    ++ {/* zName:     */ "sql_trace",
    ++  /* ePragTyp:  */ PragTyp_FLAG,
    ++  /* ePragFlg:  */ PragFlg_Result0|PragFlg_NoColumns1,
    ++  /* ColNames:  */ 0, 0,
    ++  /* iArg:      */ SQLITE_SqlTrace },
    + #endif
    + #endif
    +-#if !defined(SQLITE_OMIT_SCHEMA_PRAGMAS)
    +-  { /* zName:     */ "stats",
    +-    /* ePragTyp:  */ PragTyp_STATS,
    +-    /* ePragFlag: */ PragFlag_NeedSchema,
    +-    /* iArg:      */ 0 },
    ++#if !defined(SQLITE_OMIT_SCHEMA_PRAGMAS) && defined(SQLITE_DEBUG)
    ++ {/* zName:     */ "stats",
    ++  /* ePragTyp:  */ PragTyp_STATS,
    ++  /* ePragFlg:  */ PragFlg_NeedSchema|PragFlg_Result0|PragFlg_SchemaReq,
    ++  /* ColNames:  */ 7, 5,
    ++  /* iArg:      */ 0 },
    + #endif
    + #if !defined(SQLITE_OMIT_PAGER_PRAGMAS)
    +-  { /* zName:     */ "synchronous",
    +-    /* ePragTyp:  */ PragTyp_SYNCHRONOUS,
    +-    /* ePragFlag: */ PragFlag_NeedSchema,
    +-    /* iArg:      */ 0 },
    ++ {/* zName:     */ "synchronous",
    ++  /* ePragTyp:  */ PragTyp_SYNCHRONOUS,
    ++  /* ePragFlg:  */ PragFlg_NeedSchema|PragFlg_Result0|PragFlg_SchemaReq|PragFlg_NoColumns1,
    ++  /* ColNames:  */ 0, 0,
    ++  /* iArg:      */ 0 },
    + #endif
    + #if !defined(SQLITE_OMIT_SCHEMA_PRAGMAS)
    +-  { /* zName:     */ "table_info",
    +-    /* ePragTyp:  */ PragTyp_TABLE_INFO,
    +-    /* ePragFlag: */ PragFlag_NeedSchema,
    +-    /* iArg:      */ 0 },
    ++ {/* zName:     */ "table_info",
    ++  /* ePragTyp:  */ PragTyp_TABLE_INFO,
    ++  /* ePragFlg:  */ PragFlg_NeedSchema|PragFlg_Result1|PragFlg_SchemaOpt,
    ++  /* ColNames:  */ 1, 6,
    ++  /* iArg:      */ 0 },
    + #endif
    + #if !defined(SQLITE_OMIT_PAGER_PRAGMAS)
    +-  { /* zName:     */ "temp_store",
    +-    /* ePragTyp:  */ PragTyp_TEMP_STORE,
    +-    /* ePragFlag: */ 0,
    +-    /* iArg:      */ 0 },
    +-  { /* zName:     */ "temp_store_directory",
    +-    /* ePragTyp:  */ PragTyp_TEMP_STORE_DIRECTORY,
    +-    /* ePragFlag: */ 0,
    +-    /* iArg:      */ 0 },
    +-#endif
    +-  { /* zName:     */ "threads",
    +-    /* ePragTyp:  */ PragTyp_THREADS,
    +-    /* ePragFlag: */ 0,
    +-    /* iArg:      */ 0 },
    ++ {/* zName:     */ "temp_store",
    ++  /* ePragTyp:  */ PragTyp_TEMP_STORE,
    ++  /* ePragFlg:  */ PragFlg_Result0|PragFlg_NoColumns1,
    ++  /* ColNames:  */ 0, 0,
    ++  /* iArg:      */ 0 },
    ++ {/* zName:     */ "temp_store_directory",
    ++  /* ePragTyp:  */ PragTyp_TEMP_STORE_DIRECTORY,
    ++  /* ePragFlg:  */ PragFlg_NoColumns1,
    ++  /* ColNames:  */ 0, 0,
    ++  /* iArg:      */ 0 },
    ++#endif
    ++ {/* zName:     */ "threads",
    ++  /* ePragTyp:  */ PragTyp_THREADS,
    ++  /* ePragFlg:  */ PragFlg_Result0,
    ++  /* ColNames:  */ 0, 0,
    ++  /* iArg:      */ 0 },
    + #if !defined(SQLITE_OMIT_SCHEMA_VERSION_PRAGMAS)
    +-  { /* zName:     */ "user_version",
    +-    /* ePragTyp:  */ PragTyp_HEADER_VALUE,
    +-    /* ePragFlag: */ 0,
    +-    /* iArg:      */ BTREE_USER_VERSION },
    ++ {/* zName:     */ "user_version",
    ++  /* ePragTyp:  */ PragTyp_HEADER_VALUE,
    ++  /* ePragFlg:  */ PragFlg_NoColumns1|PragFlg_Result0,
    ++  /* ColNames:  */ 0, 0,
    ++  /* iArg:      */ BTREE_USER_VERSION },
    + #endif
    + #if !defined(SQLITE_OMIT_FLAG_PRAGMAS)
    + #if defined(SQLITE_DEBUG)
    +-  { /* zName:     */ "vdbe_addoptrace",
    +-    /* ePragTyp:  */ PragTyp_FLAG,
    +-    /* ePragFlag: */ 0,
    +-    /* iArg:      */ SQLITE_VdbeAddopTrace },
    +-  { /* zName:     */ "vdbe_debug",
    +-    /* ePragTyp:  */ PragTyp_FLAG,
    +-    /* ePragFlag: */ 0,
    +-    /* iArg:      */ SQLITE_SqlTrace|SQLITE_VdbeListing|SQLITE_VdbeTrace },
    +-  { /* zName:     */ "vdbe_eqp",
    +-    /* ePragTyp:  */ PragTyp_FLAG,
    +-    /* ePragFlag: */ 0,
    +-    /* iArg:      */ SQLITE_VdbeEQP },
    +-  { /* zName:     */ "vdbe_listing",
    +-    /* ePragTyp:  */ PragTyp_FLAG,
    +-    /* ePragFlag: */ 0,
    +-    /* iArg:      */ SQLITE_VdbeListing },
    +-  { /* zName:     */ "vdbe_trace",
    +-    /* ePragTyp:  */ PragTyp_FLAG,
    +-    /* ePragFlag: */ 0,
    +-    /* iArg:      */ SQLITE_VdbeTrace },
    ++ {/* zName:     */ "vdbe_addoptrace",
    ++  /* ePragTyp:  */ PragTyp_FLAG,
    ++  /* ePragFlg:  */ PragFlg_Result0|PragFlg_NoColumns1,
    ++  /* ColNames:  */ 0, 0,
    ++  /* iArg:      */ SQLITE_VdbeAddopTrace },
    ++ {/* zName:     */ "vdbe_debug",
    ++  /* ePragTyp:  */ PragTyp_FLAG,
    ++  /* ePragFlg:  */ PragFlg_Result0|PragFlg_NoColumns1,
    ++  /* ColNames:  */ 0, 0,
    ++  /* iArg:      */ SQLITE_SqlTrace|SQLITE_VdbeListing|SQLITE_VdbeTrace },
    ++ {/* zName:     */ "vdbe_eqp",
    ++  /* ePragTyp:  */ PragTyp_FLAG,
    ++  /* ePragFlg:  */ PragFlg_Result0|PragFlg_NoColumns1,
    ++  /* ColNames:  */ 0, 0,
    ++  /* iArg:      */ SQLITE_VdbeEQP },
    ++ {/* zName:     */ "vdbe_listing",
    ++  /* ePragTyp:  */ PragTyp_FLAG,
    ++  /* ePragFlg:  */ PragFlg_Result0|PragFlg_NoColumns1,
    ++  /* ColNames:  */ 0, 0,
    ++  /* iArg:      */ SQLITE_VdbeListing },
    ++ {/* zName:     */ "vdbe_trace",
    ++  /* ePragTyp:  */ PragTyp_FLAG,
    ++  /* ePragFlg:  */ PragFlg_Result0|PragFlg_NoColumns1,
    ++  /* ColNames:  */ 0, 0,
    ++  /* iArg:      */ SQLITE_VdbeTrace },
    + #endif
    + #endif
    + #if !defined(SQLITE_OMIT_WAL)
    +-  { /* zName:     */ "wal_autocheckpoint",
    +-    /* ePragTyp:  */ PragTyp_WAL_AUTOCHECKPOINT,
    +-    /* ePragFlag: */ 0,
    +-    /* iArg:      */ 0 },
    +-  { /* zName:     */ "wal_checkpoint",
    +-    /* ePragTyp:  */ PragTyp_WAL_CHECKPOINT,
    +-    /* ePragFlag: */ PragFlag_NeedSchema,
    +-    /* iArg:      */ 0 },
    ++ {/* zName:     */ "wal_autocheckpoint",
    ++  /* ePragTyp:  */ PragTyp_WAL_AUTOCHECKPOINT,
    ++  /* ePragFlg:  */ 0,
    ++  /* ColNames:  */ 0, 0,
    ++  /* iArg:      */ 0 },
    ++ {/* zName:     */ "wal_checkpoint",
    ++  /* ePragTyp:  */ PragTyp_WAL_CHECKPOINT,
    ++  /* ePragFlg:  */ PragFlg_NeedSchema,
    ++  /* ColNames:  */ 46, 3,
    ++  /* iArg:      */ 0 },
    + #endif
    + #if !defined(SQLITE_OMIT_FLAG_PRAGMAS)
    +-  { /* zName:     */ "writable_schema",
    +-    /* ePragTyp:  */ PragTyp_FLAG,
    +-    /* ePragFlag: */ 0,
    +-    /* iArg:      */ SQLITE_WriteSchema|SQLITE_RecoveryMode },
    ++ {/* zName:     */ "writable_schema",
    ++  /* ePragTyp:  */ PragTyp_FLAG,
    ++  /* ePragFlg:  */ PragFlg_Result0|PragFlg_NoColumns1,
    ++  /* ColNames:  */ 0, 0,
    ++  /* iArg:      */ SQLITE_WriteSchema },
    + #endif
    + };
    +-/* Number of pragmas: 60 on by default, 73 total. */
    ++/* Number of pragmas: 60 on by default, 77 total. */
    + 
    + /************** End of pragma.h **********************************************/
    + /************** Continuing where we left off in pragma.c *********************/
    + 
    + /*
    + ** Interpret the given string as a safety level.  Return 0 for OFF,
    +-** 1 for ON or NORMAL and 2 for FULL.  Return 1 for an empty or 
    +-** unrecognized string argument.  The FULL option is disallowed
    ++** 1 for ON or NORMAL, 2 for FULL, and 3 for EXTRA.  Return 1 for an empty or 
    ++** unrecognized string argument.  The FULL and EXTRA option is disallowed
    + ** if the omitFull parameter it 1.
    + **
    + ** Note that the values returned are one less that the values that
    +@@ -105855,18 +115335,21 @@ static const struct sPragmaNames {
    + ** and older scripts may have used numbers 0 for OFF and 1 for ON.
    + */
    + 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};
    +-  static const u8 iLength[] = {2, 2, 3, 5, 3, 4, 4};
    +-  static const u8 iValue[] =  {1, 0, 0, 0, 1, 1, 2};
    ++                             /* 123456789 123456789 123 */
    ++  static const char zText[] = "onoffalseyestruextrafull";
    ++  static const u8 iOffset[] = {0, 1, 2,  4,    9,  12,  15,   20};
    ++  static const u8 iLength[] = {2, 2, 3,  5,    3,   4,   5,    4};
    ++  static const u8 iValue[] =  {1, 0, 0,  0,    1,   1,   3,    2};
    ++                            /* on no off false yes true extra full */
    +   int i, n;
    +   if( sqlite3Isdigit(*z) ){
    +     return (u8)sqlite3Atoi(z);
    +   }
    +   n = sqlite3Strlen30(z);
    +-  for(i=0; i<ArraySize(iLength)-omitFull; i++){
    +-    if( iLength[i]==n && sqlite3StrNICmp(&zText[iOffset[i]],z,n)==0 ){
    ++  for(i=0; i<ArraySize(iLength); i++){
    ++    if( iLength[i]==n && sqlite3StrNICmp(&zText[iOffset[i]],z,n)==0
    ++     && (!omitFull || iValue[i]<=1)
    ++    ){
    +       return iValue[i];
    +     }
    +   }
    +@@ -105973,29 +115456,29 @@ static int changeTempStorage(Parse *pParse, const char *zStorageType){
    + #endif /* SQLITE_PAGER_PRAGMAS */
    + 
    + /*
    +-** Set the names of the first N columns to the values in azCol[]
    ++** Set result column names for a pragma.
    + */
    +-static void setAllColumnNames(
    +-  Vdbe *v,               /* The query under construction */
    +-  int N,                 /* Number of columns */
    +-  const char **azCol     /* Names of columns */
    ++static void setPragmaResultColumnNames(
    ++  Vdbe *v,                     /* The query under construction */
    ++  const PragmaName *pPragma    /* The pragma */
    + ){
    +-  int i;
    +-  sqlite3VdbeSetNumCols(v, N);
    +-  for(i=0; i<N; i++){
    +-    sqlite3VdbeSetColName(v, i, COLNAME_NAME, azCol[i], SQLITE_STATIC);
    ++  u8 n = pPragma->nPragCName;
    ++  sqlite3VdbeSetNumCols(v, n==0 ? 1 : n);
    ++  if( n==0 ){
    ++    sqlite3VdbeSetColName(v, 0, COLNAME_NAME, pPragma->zName, SQLITE_STATIC);
    ++  }else{
    ++    int i, j;
    ++    for(i=0, j=pPragma->iPragCName; i<n; i++, j++){
    ++      sqlite3VdbeSetColName(v, i, COLNAME_NAME, pragCName[j], SQLITE_STATIC);
    ++    }
    +   }
    + }
    +-static void setOneColumnName(Vdbe *v, const char *z){
    +-  setAllColumnNames(v, 1, &z);
    +-}
    + 
    + /*
    + ** Generate code to return a single integer value.
    + */
    +-static void returnSingleInt(Vdbe *v, const char *zLabel, i64 value){
    ++static void returnSingleInt(Vdbe *v, i64 value){
    +   sqlite3VdbeAddOp4Dup8(v, OP_Int64, 0, 1, 0, (const u8*)&value, P4_INT64);
    +-  setOneColumnName(v, zLabel);
    +   sqlite3VdbeAddOp2(v, OP_ResultRow, 1, 1);
    + }
    + 
    +@@ -106004,12 +115487,10 @@ static void returnSingleInt(Vdbe *v, const char *zLabel, i64 value){
    + */
    + static void returnSingleText(
    +   Vdbe *v,                /* Prepared statement under construction */
    +-  const char *zLabel,     /* Name of the result column */
    +   const char *zValue      /* Value to be returned */
    + ){
    +   if( zValue ){
    +     sqlite3VdbeLoadString(v, 1, (const char*)zValue);
    +-    setOneColumnName(v, zLabel);
    +     sqlite3VdbeAddOp2(v, OP_ResultRow, 1, 1);
    +   }
    + }
    +@@ -106087,12 +115568,48 @@ SQLITE_PRIVATE const char *sqlite3JournalModename(int eMode){
    +   return azModeName[eMode];
    + }
    + 
    ++/*
    ++** Locate a pragma in the aPragmaName[] array.
    ++*/
    ++static const PragmaName *pragmaLocate(const char *zName){
    ++  int upr, lwr, mid = 0, rc;
    ++  lwr = 0;
    ++  upr = ArraySize(aPragmaName)-1;
    ++  while( lwr<=upr ){
    ++    mid = (lwr+upr)/2;
    ++    rc = sqlite3_stricmp(zName, aPragmaName[mid].zName);
    ++    if( rc==0 ) break;
    ++    if( rc<0 ){
    ++      upr = mid - 1;
    ++    }else{
    ++      lwr = mid + 1;
    ++    }
    ++  }
    ++  return lwr>upr ? 0 : &aPragmaName[mid];
    ++}
    ++
    ++/*
    ++** Helper subroutine for PRAGMA integrity_check:
    ++**
    ++** Generate code to output a single-column result row with a value of the
    ++** string held in register 3.  Decrement the result count in register 1
    ++** and halt if the maximum number of result rows have been issued.
    ++*/
    ++static int integrityCheckResultRow(Vdbe *v){
    ++  int addr;
    ++  sqlite3VdbeAddOp2(v, OP_ResultRow, 3, 1);
    ++  addr = sqlite3VdbeAddOp3(v, OP_IfPos, 1, sqlite3VdbeCurrentAddr(v)+2, 1);
    ++  VdbeCoverage(v);
    ++  sqlite3VdbeAddOp0(v, OP_Halt);
    ++  return addr;
    ++}
    ++
    + /*
    + ** Process a pragma statement.  
    + **
    + ** Pragmas are of this form:
    + **
    +-**      PRAGMA [database.]id [= value]
    ++**      PRAGMA [schema.]id [= value]
    + **
    + ** The identifier might also be a string.  The value is a string, and
    + ** identifier, or a number.  If minusFlag is true, then the value is
    +@@ -106104,8 +115621,8 @@ SQLITE_PRIVATE const char *sqlite3JournalModename(int eMode){
    + */
    + SQLITE_PRIVATE void sqlite3Pragma(
    +   Parse *pParse, 
    +-  Token *pId1,        /* First part of [database.]id field */
    +-  Token *pId2,        /* Second part of [database.]id field, or NULL */
    ++  Token *pId1,        /* First part of [schema.]id field */
    ++  Token *pId2,        /* Second part of [schema.]id field, or NULL */
    +   Token *pValue,      /* Token for <value>, or NULL */
    +   int minusFlag       /* True if a '-' sign preceded <value> */
    + ){
    +@@ -106115,18 +115632,17 @@ SQLITE_PRIVATE void sqlite3Pragma(
    +   Token *pId;            /* Pointer to <id> token */
    +   char *aFcntl[4];       /* Argument to SQLITE_FCNTL_PRAGMA */
    +   int iDb;               /* Database index for <database> */
    +-  int lwr, upr, mid = 0;       /* Binary search bounds */
    +   int rc;                      /* return value form SQLITE_FCNTL_PRAGMA */
    +   sqlite3 *db = pParse->db;    /* The database connection */
    +   Db *pDb;                     /* The specific database being pragmaed */
    +   Vdbe *v = sqlite3GetVdbe(pParse);  /* Prepared statement */
    +-  const struct sPragmaNames *pPragma;
    ++  const PragmaName *pPragma;   /* The pragma */
    + 
    +   if( v==0 ) return;
    +   sqlite3VdbeRunOnlyOnce(v);
    +   pParse->nMem = 2;
    + 
    +-  /* Interpret the [database.] part of the pragma statement. iDb is the
    ++  /* Interpret the [schema.] part of the pragma statement. iDb is the
    +   ** index of the database this pragma is being applied to in db.aDb[]. */
    +   iDb = sqlite3TwoPartName(pParse, pId1, pId2, &pId);
    +   if( iDb<0 ) return;
    +@@ -106148,7 +115664,7 @@ SQLITE_PRIVATE void sqlite3Pragma(
    +   }
    + 
    +   assert( pId2 );
    +-  zDb = pId2->n>0 ? pDb->zName : 0;
    ++  zDb = pId2->n>0 ? pDb->zDbSName : 0;
    +   if( sqlite3AuthCheck(pParse, SQLITE_PRAGMA, zLeft, zRight, zDb) ){
    +     goto pragma_out;
    +   }
    +@@ -106175,7 +115691,9 @@ SQLITE_PRIVATE void sqlite3Pragma(
    +   db->busyHandler.nBusy = 0;
    +   rc = sqlite3_file_control(db, zDb, SQLITE_FCNTL_PRAGMA, (void*)aFcntl);
    +   if( rc==SQLITE_OK ){
    +-    returnSingleText(v, "result", aFcntl[0]);
    ++    sqlite3VdbeSetNumCols(v, 1);
    ++    sqlite3VdbeSetColName(v, 0, COLNAME_NAME, aFcntl[0], SQLITE_TRANSIENT);
    ++    returnSingleText(v, aFcntl[0]);
    +     sqlite3_free(aFcntl[0]);
    +     goto pragma_out;
    +   }
    +@@ -106190,33 +115708,28 @@ SQLITE_PRIVATE void sqlite3Pragma(
    +   }
    + 
    +   /* Locate the pragma in the lookup table */
    +-  lwr = 0;
    +-  upr = ArraySize(aPragmaNames)-1;
    +-  while( lwr<=upr ){
    +-    mid = (lwr+upr)/2;
    +-    rc = sqlite3_stricmp(zLeft, aPragmaNames[mid].zName);
    +-    if( rc==0 ) break;
    +-    if( rc<0 ){
    +-      upr = mid - 1;
    +-    }else{
    +-      lwr = mid + 1;
    +-    }
    +-  }
    +-  if( lwr>upr ) goto pragma_out;
    +-  pPragma = &aPragmaNames[mid];
    ++  pPragma = pragmaLocate(zLeft);
    ++  if( pPragma==0 ) goto pragma_out;
    + 
    +   /* Make sure the database schema is loaded if the pragma requires that */
    +-  if( (pPragma->mPragFlag & PragFlag_NeedSchema)!=0 ){
    ++  if( (pPragma->mPragFlg & PragFlg_NeedSchema)!=0 ){
    +     if( sqlite3ReadSchema(pParse) ) goto pragma_out;
    +   }
    + 
    ++  /* Register the result column names for pragmas that return results */
    ++  if( (pPragma->mPragFlg & PragFlg_NoColumns)==0 
    ++   && ((pPragma->mPragFlg & PragFlg_NoColumns1)==0 || zRight==0)
    ++  ){
    ++    setPragmaResultColumnNames(v, pPragma);
    ++  }
    ++
    +   /* Jump to the appropriate pragma handler */
    +   switch( pPragma->ePragTyp ){
    +   
    + #if !defined(SQLITE_OMIT_PAGER_PRAGMAS) && !defined(SQLITE_OMIT_DEPRECATED)
    +   /*
    +-  **  PRAGMA [database.]default_cache_size
    +-  **  PRAGMA [database.]default_cache_size=N
    ++  **  PRAGMA [schema.]default_cache_size
    ++  **  PRAGMA [schema.]default_cache_size=N
    +   **
    +   ** The first form reports the current persistent setting for the
    +   ** page cache size.  The value returned is the maximum number of
    +@@ -106243,20 +115756,20 @@ SQLITE_PRIVATE void sqlite3Pragma(
    +       { OP_Noop,        0, 0,        0},
    +       { OP_ResultRow,   1, 1,        0},
    +     };
    +-    int addr;
    ++    VdbeOp *aOp;
    +     sqlite3VdbeUsesBtree(v, iDb);
    +     if( !zRight ){
    +-      setOneColumnName(v, "cache_size");
    +       pParse->nMem += 2;
    +-      addr = sqlite3VdbeAddOpList(v, ArraySize(getCacheSize), getCacheSize,iLn);
    +-      sqlite3VdbeChangeP1(v, addr, iDb);
    +-      sqlite3VdbeChangeP1(v, addr+1, iDb);
    +-      sqlite3VdbeChangeP1(v, addr+6, SQLITE_DEFAULT_CACHE_SIZE);
    ++      sqlite3VdbeVerifyNoMallocRequired(v, ArraySize(getCacheSize));
    ++      aOp = sqlite3VdbeAddOpList(v, ArraySize(getCacheSize), getCacheSize, iLn);
    ++      if( ONLY_IF_REALLOC_STRESS(aOp==0) ) break;
    ++      aOp[0].p1 = iDb;
    ++      aOp[1].p1 = iDb;
    ++      aOp[6].p1 = SQLITE_DEFAULT_CACHE_SIZE;
    +     }else{
    +       int size = sqlite3AbsInt32(sqlite3Atoi(zRight));
    +       sqlite3BeginWriteOperation(pParse, 0, iDb);
    +-      sqlite3VdbeAddOp2(v, OP_Integer, size, 1);
    +-      sqlite3VdbeAddOp3(v, OP_SetCookie, iDb, BTREE_DEFAULT_CACHE_SIZE, 1);
    ++      sqlite3VdbeAddOp3(v, OP_SetCookie, iDb, BTREE_DEFAULT_CACHE_SIZE, size);
    +       assert( sqlite3SchemaMutexHeld(db, iDb, 0) );
    +       pDb->pSchema->cache_size = size;
    +       sqlite3BtreeSetCacheSize(pDb->pBt, pDb->pSchema->cache_size);
    +@@ -106267,8 +115780,8 @@ SQLITE_PRIVATE void sqlite3Pragma(
    + 
    + #if !defined(SQLITE_OMIT_PAGER_PRAGMAS)
    +   /*
    +-  **  PRAGMA [database.]page_size
    +-  **  PRAGMA [database.]page_size=N
    ++  **  PRAGMA [schema.]page_size
    ++  **  PRAGMA [schema.]page_size=N
    +   **
    +   ** The first form reports the current setting for the
    +   ** database page size in bytes.  The second form sets the
    +@@ -106280,33 +115793,37 @@ SQLITE_PRIVATE void sqlite3Pragma(
    +     assert( pBt!=0 );
    +     if( !zRight ){
    +       int size = ALWAYS(pBt) ? sqlite3BtreeGetPageSize(pBt) : 0;
    +-      returnSingleInt(v, "page_size", size);
    ++      returnSingleInt(v, size);
    +     }else{
    +       /* Malloc may fail when setting the page-size, as there is an internal
    +       ** buffer that the pager module resizes using sqlite3_realloc().
    +       */
    +       db->nextPagesize = sqlite3Atoi(zRight);
    +       if( SQLITE_NOMEM==sqlite3BtreeSetPageSize(pBt, db->nextPagesize,-1,0) ){
    +-        db->mallocFailed = 1;
    ++        sqlite3OomFault(db);
    +       }
    +     }
    +     break;
    +   }
    + 
    +   /*
    +-  **  PRAGMA [database.]secure_delete
    +-  **  PRAGMA [database.]secure_delete=ON/OFF
    ++  **  PRAGMA [schema.]secure_delete
    ++  **  PRAGMA [schema.]secure_delete=ON/OFF/FAST
    +   **
    +   ** The first form reports the current setting for the
    +   ** secure_delete flag.  The second form changes the secure_delete
    +-  ** flag setting and reports thenew value.
    ++  ** flag setting and reports the new value.
    +   */
    +   case PragTyp_SECURE_DELETE: {
    +     Btree *pBt = pDb->pBt;
    +     int b = -1;
    +     assert( pBt!=0 );
    +     if( zRight ){
    +-      b = sqlite3GetBoolean(zRight, 0);
    ++      if( sqlite3_stricmp(zRight, "fast")==0 ){
    ++        b = 2;
    ++      }else{
    ++        b = sqlite3GetBoolean(zRight, 0);
    ++      }
    +     }
    +     if( pId2->n==0 && b>=0 ){
    +       int ii;
    +@@ -106315,13 +115832,13 @@ SQLITE_PRIVATE void sqlite3Pragma(
    +       }
    +     }
    +     b = sqlite3BtreeSecureDelete(pBt, b);
    +-    returnSingleInt(v, "secure_delete", b);
    ++    returnSingleInt(v, b);
    +     break;
    +   }
    + 
    +   /*
    +-  **  PRAGMA [database.]max_page_count
    +-  **  PRAGMA [database.]max_page_count=N
    ++  **  PRAGMA [schema.]max_page_count
    ++  **  PRAGMA [schema.]max_page_count=N
    +   **
    +   ** The first form reports the current setting for the
    +   ** maximum number of pages in the database file.  The 
    +@@ -106332,7 +115849,7 @@ SQLITE_PRIVATE void sqlite3Pragma(
    +   ** change.  The only purpose is to provide an easy way to test
    +   ** the sqlite3AbsInt32() function.
    +   **
    +-  **  PRAGMA [database.]page_count
    ++  **  PRAGMA [schema.]page_count
    +   **
    +   ** Return the number of pages in the specified database.
    +   */
    +@@ -106347,14 +115864,12 @@ SQLITE_PRIVATE void sqlite3Pragma(
    +                         sqlite3AbsInt32(sqlite3Atoi(zRight)));
    +     }
    +     sqlite3VdbeAddOp2(v, OP_ResultRow, iReg, 1);
    +-    sqlite3VdbeSetNumCols(v, 1);
    +-    sqlite3VdbeSetColName(v, 0, COLNAME_NAME, zLeft, SQLITE_TRANSIENT);
    +     break;
    +   }
    + 
    +   /*
    +-  **  PRAGMA [database.]locking_mode
    +-  **  PRAGMA [database.]locking_mode = (normal|exclusive)
    ++  **  PRAGMA [schema.]locking_mode
    ++  **  PRAGMA [schema.]locking_mode = (normal|exclusive)
    +   */
    +   case PragTyp_LOCKING_MODE: {
    +     const char *zRet = "normal";
    +@@ -106394,20 +115909,19 @@ SQLITE_PRIVATE void sqlite3Pragma(
    +     if( eMode==PAGER_LOCKINGMODE_EXCLUSIVE ){
    +       zRet = "exclusive";
    +     }
    +-    returnSingleText(v, "locking_mode", zRet);
    ++    returnSingleText(v, zRet);
    +     break;
    +   }
    + 
    +   /*
    +-  **  PRAGMA [database.]journal_mode
    +-  **  PRAGMA [database.]journal_mode =
    ++  **  PRAGMA [schema.]journal_mode
    ++  **  PRAGMA [schema.]journal_mode =
    +   **                      (delete|persist|off|truncate|memory|wal|off)
    +   */
    +   case PragTyp_JOURNAL_MODE: {
    +     int eMode;        /* One of the PAGER_JOURNALMODE_XXX symbols */
    +     int ii;           /* Loop counter */
    + 
    +-    setOneColumnName(v, "journal_mode");
    +     if( zRight==0 ){
    +       /* If there is no "=MODE" part of the pragma, do a query for the
    +       ** current mode */
    +@@ -106440,8 +115954,8 @@ SQLITE_PRIVATE void sqlite3Pragma(
    +   }
    + 
    +   /*
    +-  **  PRAGMA [database.]journal_size_limit
    +-  **  PRAGMA [database.]journal_size_limit=N
    ++  **  PRAGMA [schema.]journal_size_limit
    ++  **  PRAGMA [schema.]journal_size_limit=N
    +   **
    +   ** Get or set the size limit on rollback journal files.
    +   */
    +@@ -106453,15 +115967,15 @@ SQLITE_PRIVATE void sqlite3Pragma(
    +       if( iLimit<-1 ) iLimit = -1;
    +     }
    +     iLimit = sqlite3PagerJournalSizeLimit(pPager, iLimit);
    +-    returnSingleInt(v, "journal_size_limit", iLimit);
    ++    returnSingleInt(v, iLimit);
    +     break;
    +   }
    + 
    + #endif /* SQLITE_OMIT_PAGER_PRAGMAS */
    + 
    +   /*
    +-  **  PRAGMA [database.]auto_vacuum
    +-  **  PRAGMA [database.]auto_vacuum=N
    ++  **  PRAGMA [schema.]auto_vacuum
    ++  **  PRAGMA [schema.]auto_vacuum=N
    +   **
    +   ** Get or set the value of the database 'auto-vacuum' parameter.
    +   ** The value is one of:  0 NONE 1 FULL 2 INCREMENTAL
    +@@ -106471,7 +115985,7 @@ SQLITE_PRIVATE void sqlite3Pragma(
    +     Btree *pBt = pDb->pBt;
    +     assert( pBt!=0 );
    +     if( !zRight ){
    +-      returnSingleInt(v, "auto_vacuum", sqlite3BtreeGetAutoVacuum(pBt));
    ++      returnSingleInt(v, sqlite3BtreeGetAutoVacuum(pBt));
    +     }else{
    +       int eAuto = getAutoVacuum(zRight);
    +       assert( eAuto>=0 && eAuto<=2 );
    +@@ -106494,16 +116008,18 @@ SQLITE_PRIVATE void sqlite3Pragma(
    +           { OP_ReadCookie,     0,         1,         BTREE_LARGEST_ROOT_PAGE},
    +           { OP_If,             1,         0,                 0},    /* 2 */
    +           { OP_Halt,           SQLITE_OK, OE_Abort,          0},    /* 3 */
    +-          { OP_Integer,        0,         1,                 0},    /* 4 */
    +-          { OP_SetCookie,      0,         BTREE_INCR_VACUUM, 1},    /* 5 */
    ++          { OP_SetCookie,      0,         BTREE_INCR_VACUUM, 0},    /* 4 */
    +         };
    +-        int iAddr;
    +-        iAddr = sqlite3VdbeAddOpList(v, ArraySize(setMeta6), setMeta6, iLn);
    +-        sqlite3VdbeChangeP1(v, iAddr, iDb);
    +-        sqlite3VdbeChangeP1(v, iAddr+1, iDb);
    +-        sqlite3VdbeChangeP2(v, iAddr+2, iAddr+4);
    +-        sqlite3VdbeChangeP1(v, iAddr+4, eAuto-1);
    +-        sqlite3VdbeChangeP1(v, iAddr+5, iDb);
    ++        VdbeOp *aOp;
    ++        int iAddr = sqlite3VdbeCurrentAddr(v);
    ++        sqlite3VdbeVerifyNoMallocRequired(v, ArraySize(setMeta6));
    ++        aOp = sqlite3VdbeAddOpList(v, ArraySize(setMeta6), setMeta6, iLn);
    ++        if( ONLY_IF_REALLOC_STRESS(aOp==0) ) break;
    ++        aOp[0].p1 = iDb;
    ++        aOp[1].p1 = iDb;
    ++        aOp[2].p2 = iAddr+4;
    ++        aOp[4].p1 = iDb;
    ++        aOp[4].p3 = eAuto - 1;
    +         sqlite3VdbeUsesBtree(v, iDb);
    +       }
    +     }
    +@@ -106512,7 +116028,7 @@ SQLITE_PRIVATE void sqlite3Pragma(
    + #endif
    + 
    +   /*
    +-  **  PRAGMA [database.]incremental_vacuum(N)
    ++  **  PRAGMA [schema.]incremental_vacuum(N)
    +   **
    +   ** Do N steps of incremental vacuuming on a database.
    +   */
    +@@ -106535,8 +116051,8 @@ SQLITE_PRIVATE void sqlite3Pragma(
    + 
    + #ifndef SQLITE_OMIT_PAGER_PRAGMAS
    +   /*
    +-  **  PRAGMA [database.]cache_size
    +-  **  PRAGMA [database.]cache_size=N
    ++  **  PRAGMA [schema.]cache_size
    ++  **  PRAGMA [schema.]cache_size=N
    +   **
    +   ** The first form reports the current local setting for the
    +   ** page cache size. The second form sets the local
    +@@ -106548,19 +116064,60 @@ SQLITE_PRIVATE void sqlite3Pragma(
    +   case PragTyp_CACHE_SIZE: {
    +     assert( sqlite3SchemaMutexHeld(db, iDb, 0) );
    +     if( !zRight ){
    +-      if( sqlite3ReadSchema(pParse) ) goto pragma_out;
    +-      returnSingleInt(v, "cache_size", pDb->pSchema->cache_size);
    ++      returnSingleInt(v, pDb->pSchema->cache_size);
    +     }else{
    +       int size = sqlite3Atoi(zRight);
    +       pDb->pSchema->cache_size = size;
    +       sqlite3BtreeSetCacheSize(pDb->pBt, pDb->pSchema->cache_size);
    +-      if( sqlite3ReadSchema(pParse) ) goto pragma_out;
    +     }
    +     break;
    +   }
    + 
    +   /*
    +-  **  PRAGMA [database.]mmap_size(N)
    ++  **  PRAGMA [schema.]cache_spill
    ++  **  PRAGMA cache_spill=BOOLEAN
    ++  **  PRAGMA [schema.]cache_spill=N
    ++  **
    ++  ** The first form reports the current local setting for the
    ++  ** page cache spill size. The second form turns cache spill on
    ++  ** or off.  When turnning cache spill on, the size is set to the
    ++  ** current cache_size.  The third form sets a spill size that
    ++  ** may be different form the cache size.
    ++  ** If N is positive then that is the
    ++  ** number of pages in the cache.  If N is negative, then the
    ++  ** number of pages is adjusted so that the cache uses -N kibibytes
    ++  ** of memory.
    ++  **
    ++  ** If the number of cache_spill pages is less then the number of
    ++  ** cache_size pages, no spilling occurs until the page count exceeds
    ++  ** the number of cache_size pages.
    ++  **
    ++  ** The cache_spill=BOOLEAN setting applies to all attached schemas,
    ++  ** not just the schema specified.
    ++  */
    ++  case PragTyp_CACHE_SPILL: {
    ++    assert( sqlite3SchemaMutexHeld(db, iDb, 0) );
    ++    if( !zRight ){
    ++      returnSingleInt(v,
    ++         (db->flags & SQLITE_CacheSpill)==0 ? 0 : 
    ++            sqlite3BtreeSetSpillSize(pDb->pBt,0));
    ++    }else{
    ++      int size = 1;
    ++      if( sqlite3GetInt32(zRight, &size) ){
    ++        sqlite3BtreeSetSpillSize(pDb->pBt, size);
    ++      }
    ++      if( sqlite3GetBoolean(zRight, size!=0) ){
    ++        db->flags |= SQLITE_CacheSpill;
    ++      }else{
    ++        db->flags &= ~SQLITE_CacheSpill;
    ++      }
    ++      setAllPagerFlags(db);
    ++    }
    ++    break;
    ++  }
    ++
    ++  /*
    ++  **  PRAGMA [schema.]mmap_size(N)
    +   **
    +   ** Used to set mapping size limit. The mapping size limit is
    +   ** used to limit the aggregate size of all memory mapped regions of the
    +@@ -106595,7 +116152,7 @@ SQLITE_PRIVATE void sqlite3Pragma(
    +     rc = SQLITE_OK;
    + #endif
    +     if( rc==SQLITE_OK ){
    +-      returnSingleInt(v, "mmap_size", sz);
    ++      returnSingleInt(v, sz);
    +     }else if( rc!=SQLITE_NOTFOUND ){
    +       pParse->nErr++;
    +       pParse->rc = rc;
    +@@ -106616,7 +116173,7 @@ SQLITE_PRIVATE void sqlite3Pragma(
    +   */
    +   case PragTyp_TEMP_STORE: {
    +     if( !zRight ){
    +-      returnSingleInt(v, "temp_store", db->temp_store);
    ++      returnSingleInt(v, db->temp_store);
    +     }else{
    +       changeTempStorage(pParse, zRight);
    +     }
    +@@ -106635,7 +116192,7 @@ SQLITE_PRIVATE void sqlite3Pragma(
    +   */
    +   case PragTyp_TEMP_STORE_DIRECTORY: {
    +     if( !zRight ){
    +-      returnSingleText(v, "temp_store_directory", sqlite3_temp_directory);
    ++      returnSingleText(v, sqlite3_temp_directory);
    +     }else{
    + #ifndef SQLITE_OMIT_WSD
    +       if( zRight[0] ){
    +@@ -106679,7 +116236,7 @@ SQLITE_PRIVATE void sqlite3Pragma(
    +   */
    +   case PragTyp_DATA_STORE_DIRECTORY: {
    +     if( !zRight ){
    +-      returnSingleText(v, "data_store_directory", sqlite3_data_directory);
    ++      returnSingleText(v, sqlite3_data_directory);
    +     }else{
    + #ifndef SQLITE_OMIT_WSD
    +       if( zRight[0] ){
    +@@ -106704,8 +116261,8 @@ SQLITE_PRIVATE void sqlite3Pragma(
    + 
    + #if SQLITE_ENABLE_LOCKING_STYLE
    +   /*
    +-  **   PRAGMA [database.]lock_proxy_file
    +-  **   PRAGMA [database.]lock_proxy_file = ":auto:"|"lock_file_path"
    ++  **   PRAGMA [schema.]lock_proxy_file
    ++  **   PRAGMA [schema.]lock_proxy_file = ":auto:"|"lock_file_path"
    +   **
    +   ** Return or set the value of the lock_proxy_file flag.  Changing
    +   ** the value sets a specific file to be used for database access locks.
    +@@ -106718,7 +116275,7 @@ SQLITE_PRIVATE void sqlite3Pragma(
    +       sqlite3_file *pFile = sqlite3PagerFile(pPager);
    +       sqlite3OsFileControlHint(pFile, SQLITE_GET_LOCKPROXYFILE, 
    +                            &proxy_file_path);
    +-      returnSingleText(v, "lock_proxy_file", proxy_file_path);
    ++      returnSingleText(v, proxy_file_path);
    +     }else{
    +       Pager *pPager = sqlite3BtreePager(pDb->pBt);
    +       sqlite3_file *pFile = sqlite3PagerFile(pPager);
    +@@ -106740,8 +116297,8 @@ SQLITE_PRIVATE void sqlite3Pragma(
    + #endif /* SQLITE_ENABLE_LOCKING_STYLE */      
    +     
    +   /*
    +-  **   PRAGMA [database.]synchronous
    +-  **   PRAGMA [database.]synchronous=OFF|ON|NORMAL|FULL
    ++  **   PRAGMA [schema.]synchronous
    ++  **   PRAGMA [schema.]synchronous=OFF|ON|NORMAL|FULL|EXTRA
    +   **
    +   ** Return or set the local value of the synchronous flag.  Changing
    +   ** the local value does not make changes to the disk file and the
    +@@ -106750,15 +116307,16 @@ SQLITE_PRIVATE void sqlite3Pragma(
    +   */
    +   case PragTyp_SYNCHRONOUS: {
    +     if( !zRight ){
    +-      returnSingleInt(v, "synchronous", pDb->safety_level-1);
    ++      returnSingleInt(v, pDb->safety_level-1);
    +     }else{
    +       if( !db->autoCommit ){
    +         sqlite3ErrorMsg(pParse, 
    +             "Safety level may not be changed inside a transaction");
    +-      }else{
    ++      }else if( iDb!=1 ){
    +         int iLevel = (getSafetyLevel(zRight,0,1)+1) & PAGER_SYNCHRONOUS_MASK;
    +         if( iLevel==0 ) iLevel = 1;
    +         pDb->safety_level = iLevel;
    ++        pDb->bSyncSet = 1;
    +         setAllPagerFlags(db);
    +       }
    +     }
    +@@ -106769,7 +116327,8 @@ SQLITE_PRIVATE void sqlite3Pragma(
    + #ifndef SQLITE_OMIT_FLAG_PRAGMAS
    +   case PragTyp_FLAG: {
    +     if( zRight==0 ){
    +-      returnSingleInt(v, pPragma->zName, (db->flags & pPragma->iArg)!=0 );
    ++      setPragmaResultColumnNames(v, pPragma);
    ++      returnSingleInt(v, (db->flags & pPragma->iArg)!=0 );
    +     }else{
    +       int mask = pPragma->iArg;    /* Mask of bits to set or clear. */
    +       if( db->autoCommit==0 ){
    +@@ -106795,7 +116354,7 @@ SQLITE_PRIVATE void sqlite3Pragma(
    +       ** compiler (eg. count_changes). So add an opcode to expire all
    +       ** compiled SQL statements after modifying a pragma value.
    +       */
    +-      sqlite3VdbeAddOp2(v, OP_Expire, 0, 0);
    ++      sqlite3VdbeAddOp0(v, OP_Expire);
    +       setAllPagerFlags(db);
    +     }
    +     break;
    +@@ -106814,21 +116373,18 @@ SQLITE_PRIVATE void sqlite3Pragma(
    +   ** type:       Column declaration type.
    +   ** notnull:    True if 'NOT NULL' is part of column declaration
    +   ** dflt_value: The default value for the column, if any.
    ++  ** pk:         Non-zero for PK fields.
    +   */
    +   case PragTyp_TABLE_INFO: if( zRight ){
    +     Table *pTab;
    +-    pTab = sqlite3FindTable(db, zRight, zDb);
    ++    pTab = sqlite3LocateTable(pParse, LOCATE_NOERR, zRight, zDb);
    +     if( pTab ){
    +-      static const char *azCol[] = {
    +-         "cid", "name", "type", "notnull", "dflt_value", "pk"
    +-      };
    +       int i, k;
    +       int nHidden = 0;
    +       Column *pCol;
    +       Index *pPk = sqlite3PrimaryKeyIndex(pTab);
    +       pParse->nMem = 6;
    +       sqlite3CodeVerifySchema(pParse, iDb);
    +-      setAllColumnNames(v, 6, azCol); assert( 6==ArraySize(azCol) );
    +       sqlite3ViewGetColumnNames(pParse, pTab);
    +       for(i=0, pCol=pTab->aCol; i<pTab->nCol; i++, pCol++){
    +         if( IsHiddenColumn(pCol) ){
    +@@ -106842,54 +116398,51 @@ SQLITE_PRIVATE void sqlite3Pragma(
    +         }else{
    +           for(k=1; k<=pTab->nCol && pPk->aiColumn[k-1]!=i; k++){}
    +         }
    ++        assert( pCol->pDflt==0 || pCol->pDflt->op==TK_SPAN );
    +         sqlite3VdbeMultiLoad(v, 1, "issisi",
    +                i-nHidden,
    +                pCol->zName,
    +-               pCol->zType ? pCol->zType : "",
    ++               sqlite3ColumnType(pCol,""),
    +                pCol->notNull ? 1 : 0,
    +-               pCol->zDflt,
    ++               pCol->pDflt ? pCol->pDflt->u.zToken : 0,
    +                k);
    +-        sqlite3VdbeAddOp2(v, OP_ResultRow, 1, 6);
    +       }
    +     }
    +   }
    +   break;
    + 
    ++#ifdef SQLITE_DEBUG
    +   case PragTyp_STATS: {
    +-    static const char *azCol[] = { "table", "index", "width", "height" };
    +     Index *pIdx;
    +     HashElem *i;
    +-    v = sqlite3GetVdbe(pParse);
    +-    pParse->nMem = 4;
    ++    pParse->nMem = 5;
    +     sqlite3CodeVerifySchema(pParse, iDb);
    +-    setAllColumnNames(v, 4, azCol);  assert( 4==ArraySize(azCol) );
    +     for(i=sqliteHashFirst(&pDb->pSchema->tblHash); i; i=sqliteHashNext(i)){
    +       Table *pTab = sqliteHashData(i);
    +-      sqlite3VdbeMultiLoad(v, 1, "ssii",
    ++      sqlite3VdbeMultiLoad(v, 1, "ssiii",
    +            pTab->zName,
    +            0,
    +-           (int)sqlite3LogEstToInt(pTab->szTabRow),
    +-           (int)sqlite3LogEstToInt(pTab->nRowLogEst));
    +-      sqlite3VdbeAddOp2(v, OP_ResultRow, 1, 4);
    ++           pTab->szTabRow,
    ++           pTab->nRowLogEst,
    ++           pTab->tabFlags);
    +       for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){
    +-        sqlite3VdbeMultiLoad(v, 2, "sii",
    ++        sqlite3VdbeMultiLoad(v, 2, "siiiX",
    +            pIdx->zName,
    +-           (int)sqlite3LogEstToInt(pIdx->szIdxRow),
    +-           (int)sqlite3LogEstToInt(pIdx->aiRowLogEst[0]));
    +-        sqlite3VdbeAddOp2(v, OP_ResultRow, 1, 4);
    ++           pIdx->szIdxRow,
    ++           pIdx->aiRowLogEst[0],
    ++           pIdx->hasStat1);
    ++        sqlite3VdbeAddOp2(v, OP_ResultRow, 1, 5);
    +       }
    +     }
    +   }
    +   break;
    ++#endif
    + 
    +   case PragTyp_INDEX_INFO: if( zRight ){
    +     Index *pIdx;
    +     Table *pTab;
    +     pIdx = sqlite3FindIndex(db, zRight, zDb);
    +     if( pIdx ){
    +-      static const char *azCol[] = {
    +-         "seqno", "cid", "name", "desc", "coll", "key"
    +-      };
    +       int i;
    +       int mx;
    +       if( pPragma->iArg ){
    +@@ -106903,14 +116456,13 @@ SQLITE_PRIVATE void sqlite3Pragma(
    +       }
    +       pTab = pIdx->pTable;
    +       sqlite3CodeVerifySchema(pParse, iDb);
    +-      assert( pParse->nMem<=ArraySize(azCol) );
    +-      setAllColumnNames(v, pParse->nMem, azCol);
    ++      assert( pParse->nMem<=pPragma->nPragCName );
    +       for(i=0; i<mx; i++){
    +         i16 cnum = pIdx->aiColumn[i];
    +-        sqlite3VdbeMultiLoad(v, 1, "iis", i, cnum,
    ++        sqlite3VdbeMultiLoad(v, 1, "iisX", i, cnum,
    +                              cnum<0 ? 0 : pTab->aCol[cnum].zName);
    +         if( pPragma->iArg ){
    +-          sqlite3VdbeMultiLoad(v, 4, "isi",
    ++          sqlite3VdbeMultiLoad(v, 4, "isiX",
    +             pIdx->aSortOrder[i],
    +             pIdx->azColl[i],
    +             i<pIdx->nKeyCol);
    +@@ -106927,13 +116479,8 @@ SQLITE_PRIVATE void sqlite3Pragma(
    +     int i;
    +     pTab = sqlite3FindTable(db, zRight, zDb);
    +     if( pTab ){
    +-      static const char *azCol[] = {
    +-        "seq", "name", "unique", "origin", "partial"
    +-      };
    +-      v = sqlite3GetVdbe(pParse);
    +       pParse->nMem = 5;
    +       sqlite3CodeVerifySchema(pParse, iDb);
    +-      setAllColumnNames(v, 5, azCol);  assert( 5==ArraySize(azCol) );
    +       for(pIdx=pTab->pIndex, i=0; pIdx; pIdx=pIdx->pNext, i++){
    +         const char *azOrigin[] = { "c", "u", "pk" };
    +         sqlite3VdbeMultiLoad(v, 1, "isisi",
    +@@ -106942,42 +116489,75 @@ SQLITE_PRIVATE void sqlite3Pragma(
    +            IsUniqueIndex(pIdx),
    +            azOrigin[pIdx->idxType],
    +            pIdx->pPartIdxWhere!=0);
    +-        sqlite3VdbeAddOp2(v, OP_ResultRow, 1, 5);
    +       }
    +     }
    +   }
    +   break;
    + 
    +   case PragTyp_DATABASE_LIST: {
    +-    static const char *azCol[] = { "seq", "name", "file" };
    +     int i;
    +     pParse->nMem = 3;
    +-    setAllColumnNames(v, 3, azCol); assert( 3==ArraySize(azCol) );
    +     for(i=0; i<db->nDb; i++){
    +       if( db->aDb[i].pBt==0 ) continue;
    +-      assert( db->aDb[i].zName!=0 );
    ++      assert( db->aDb[i].zDbSName!=0 );
    +       sqlite3VdbeMultiLoad(v, 1, "iss",
    +          i,
    +-         db->aDb[i].zName,
    ++         db->aDb[i].zDbSName,
    +          sqlite3BtreeGetFilename(db->aDb[i].pBt));
    +-      sqlite3VdbeAddOp2(v, OP_ResultRow, 1, 3);
    +     }
    +   }
    +   break;
    + 
    +   case PragTyp_COLLATION_LIST: {
    +-    static const char *azCol[] = { "seq", "name" };
    +     int i = 0;
    +     HashElem *p;
    +     pParse->nMem = 2;
    +-    setAllColumnNames(v, 2, azCol); assert( 2==ArraySize(azCol) );
    +     for(p=sqliteHashFirst(&db->aCollSeq); p; p=sqliteHashNext(p)){
    +       CollSeq *pColl = (CollSeq *)sqliteHashData(p);
    +       sqlite3VdbeMultiLoad(v, 1, "is", i++, pColl->zName);
    +-      sqlite3VdbeAddOp2(v, OP_ResultRow, 1, 2);
    +     }
    +   }
    +   break;
    ++
    ++#ifdef SQLITE_INTROSPECTION_PRAGMAS
    ++  case PragTyp_FUNCTION_LIST: {
    ++    int i;
    ++    HashElem *j;
    ++    FuncDef *p;
    ++    pParse->nMem = 2;
    ++    for(i=0; i<SQLITE_FUNC_HASH_SZ; i++){
    ++      for(p=sqlite3BuiltinFunctions.a[i]; p; p=p->u.pHash ){
    ++        sqlite3VdbeMultiLoad(v, 1, "si", p->zName, 1);
    ++      }
    ++    }
    ++    for(j=sqliteHashFirst(&db->aFunc); j; j=sqliteHashNext(j)){
    ++      p = (FuncDef*)sqliteHashData(j);
    ++      sqlite3VdbeMultiLoad(v, 1, "si", p->zName, 0);
    ++    }
    ++  }
    ++  break;
    ++
    ++#ifndef SQLITE_OMIT_VIRTUALTABLE
    ++  case PragTyp_MODULE_LIST: {
    ++    HashElem *j;
    ++    pParse->nMem = 1;
    ++    for(j=sqliteHashFirst(&db->aModule); j; j=sqliteHashNext(j)){
    ++      Module *pMod = (Module*)sqliteHashData(j);
    ++      sqlite3VdbeMultiLoad(v, 1, "s", pMod->zName);
    ++    }
    ++  }
    ++  break;
    ++#endif /* SQLITE_OMIT_VIRTUALTABLE */
    ++
    ++  case PragTyp_PRAGMA_LIST: {
    ++    int i;
    ++    for(i=0; i<ArraySize(aPragmaName); i++){
    ++      sqlite3VdbeMultiLoad(v, 1, "s", aPragmaName[i].zName);
    ++    }
    ++  }
    ++  break;
    ++#endif /* SQLITE_INTROSPECTION_PRAGMAS */
    ++
    + #endif /* SQLITE_OMIT_SCHEMA_PRAGMAS */
    + 
    + #ifndef SQLITE_OMIT_FOREIGN_KEY
    +@@ -106986,17 +116566,11 @@ SQLITE_PRIVATE void sqlite3Pragma(
    +     Table *pTab;
    +     pTab = sqlite3FindTable(db, zRight, zDb);
    +     if( pTab ){
    +-      v = sqlite3GetVdbe(pParse);
    +       pFK = pTab->pFKey;
    +       if( pFK ){
    +-        static const char *azCol[] = {
    +-           "id", "seq", "table", "from", "to", "on_update", "on_delete",
    +-           "match"
    +-        };
    +         int i = 0; 
    +         pParse->nMem = 8;
    +         sqlite3CodeVerifySchema(pParse, iDb);
    +-        setAllColumnNames(v, 8, azCol); assert( 8==ArraySize(azCol) );
    +         while(pFK){
    +           int j;
    +           for(j=0; j<pFK->nCol; j++){
    +@@ -107009,7 +116583,6 @@ SQLITE_PRIVATE void sqlite3Pragma(
    +                    actionName(pFK->aAction[1]),  /* ON UPDATE */
    +                    actionName(pFK->aAction[0]),  /* ON DELETE */
    +                    "NONE");
    +-            sqlite3VdbeAddOp2(v, OP_ResultRow, 1, 8);
    +           }
    +           ++i;
    +           pFK = pFK->pNextFrom;
    +@@ -107037,14 +116610,11 @@ SQLITE_PRIVATE void sqlite3Pragma(
    +     int addrTop;           /* Top of a loop checking foreign keys */
    +     int addrOk;            /* Jump here if the key is OK */
    +     int *aiCols;           /* child to parent column mapping */
    +-    static const char *azCol[] = { "table", "rowid", "parent", "fkid" };
    + 
    +     regResult = pParse->nMem+1;
    +     pParse->nMem += 4;
    +     regKey = ++pParse->nMem;
    +     regRow = ++pParse->nMem;
    +-    v = sqlite3GetVdbe(pParse);
    +-    setAllColumnNames(v, 4, azCol); assert( 4==ArraySize(azCol) );
    +     sqlite3CodeVerifySchema(pParse, iDb);
    +     k = sqliteHashFirst(&db->aDb[iDb].pSchema->tblHash);
    +     while( k ){
    +@@ -107091,36 +116661,38 @@ SQLITE_PRIVATE void sqlite3Pragma(
    +           assert( x==0 );
    +         }
    +         addrOk = sqlite3VdbeMakeLabel(v);
    +-        if( pParent && pIdx==0 ){
    +-          int iKey = pFK->aCol[0].iFrom;
    +-          assert( iKey>=0 && iKey<pTab->nCol );
    +-          if( iKey!=pTab->iPKey ){
    +-            sqlite3VdbeAddOp3(v, OP_Column, 0, iKey, regRow);
    +-            sqlite3ColumnDefault(v, pTab, iKey, regRow);
    +-            sqlite3VdbeAddOp2(v, OP_IsNull, regRow, addrOk); VdbeCoverage(v);
    +-            sqlite3VdbeAddOp2(v, OP_MustBeInt, regRow, 
    +-               sqlite3VdbeCurrentAddr(v)+3); VdbeCoverage(v);
    +-          }else{
    +-            sqlite3VdbeAddOp2(v, OP_Rowid, 0, regRow);
    +-          }
    +-          sqlite3VdbeAddOp3(v, OP_NotExists, i, 0, regRow); VdbeCoverage(v);
    ++
    ++        /* Generate code to read the child key values into registers
    ++        ** regRow..regRow+n. If any of the child key values are NULL, this 
    ++        ** row cannot cause an FK violation. Jump directly to addrOk in 
    ++        ** this case. */
    ++        for(j=0; j<pFK->nCol; j++){
    ++          int iCol = aiCols ? aiCols[j] : pFK->aCol[j].iFrom;
    ++          sqlite3ExprCodeGetColumnOfTable(v, pTab, 0, iCol, regRow+j);
    ++          sqlite3VdbeAddOp2(v, OP_IsNull, regRow+j, addrOk); VdbeCoverage(v);
    ++        }
    ++
    ++        /* Generate code to query the parent index for a matching parent
    ++        ** key. If a match is found, jump to addrOk. */
    ++        if( pIdx ){
    ++          sqlite3VdbeAddOp4(v, OP_MakeRecord, regRow, pFK->nCol, regKey,
    ++              sqlite3IndexAffinityStr(db,pIdx), pFK->nCol);
    ++          sqlite3VdbeAddOp4Int(v, OP_Found, i, addrOk, regKey, 0);
    ++          VdbeCoverage(v);
    ++        }else if( pParent ){
    ++          int jmp = sqlite3VdbeCurrentAddr(v)+2;
    ++          sqlite3VdbeAddOp3(v, OP_SeekRowid, i, jmp, regRow); VdbeCoverage(v);
    +           sqlite3VdbeGoto(v, addrOk);
    +-          sqlite3VdbeJumpHere(v, sqlite3VdbeCurrentAddr(v)-2);
    ++          assert( pFK->nCol==1 );
    ++        }
    ++
    ++        /* Generate code to report an FK violation to the caller. */
    ++        if( HasRowid(pTab) ){
    ++          sqlite3VdbeAddOp2(v, OP_Rowid, 0, regResult+1);
    +         }else{
    +-          for(j=0; j<pFK->nCol; j++){
    +-            sqlite3ExprCodeGetColumnOfTable(v, pTab, 0,
    +-                            aiCols ? aiCols[j] : pFK->aCol[j].iFrom, regRow+j);
    +-            sqlite3VdbeAddOp2(v, OP_IsNull, regRow+j, addrOk); VdbeCoverage(v);
    +-          }
    +-          if( pParent ){
    +-            sqlite3VdbeAddOp4(v, OP_MakeRecord, regRow, pFK->nCol, regKey,
    +-                              sqlite3IndexAffinityStr(db,pIdx), pFK->nCol);
    +-            sqlite3VdbeAddOp4Int(v, OP_Found, i, addrOk, regKey, 0);
    +-            VdbeCoverage(v);
    +-          }
    ++          sqlite3VdbeAddOp2(v, OP_Null, 0, regResult+1);
    +         }
    +-        sqlite3VdbeAddOp2(v, OP_Rowid, 0, regResult+1);
    +-        sqlite3VdbeMultiLoad(v, regResult+2, "si", pFK->zTo, i-1);
    ++        sqlite3VdbeMultiLoad(v, regResult+2, "siX", pFK->zTo, i-1);
    +         sqlite3VdbeAddOp2(v, OP_ResultRow, regResult, 4);
    +         sqlite3VdbeResolveLabel(v, addrOk);
    +         sqlite3DbFree(db, aiCols);
    +@@ -107137,7 +116709,7 @@ SQLITE_PRIVATE void sqlite3Pragma(
    +   case PragTyp_PARSER_TRACE: {
    +     if( zRight ){
    +       if( sqlite3GetBoolean(zRight, 0) ){
    +-        sqlite3ParserTrace(stderr, "parser: ");
    ++        sqlite3ParserTrace(stdout, "parser: ");
    +       }else{
    +         sqlite3ParserTrace(0, 0);
    +       }
    +@@ -107161,25 +116733,21 @@ SQLITE_PRIVATE void sqlite3Pragma(
    + #endif
    + 
    + #ifndef SQLITE_OMIT_INTEGRITY_CHECK
    +-  /* Pragma "quick_check" is reduced version of 
    ++  /*    PRAGMA integrity_check
    ++  **    PRAGMA integrity_check(N)
    ++  **    PRAGMA quick_check
    ++  **    PRAGMA quick_check(N)
    ++  **
    ++  ** Verify the integrity of the database.
    ++  **
    ++  ** The "quick_check" is reduced version of 
    +   ** integrity_check designed to detect most database corruption
    +-  ** without most of the overhead of a full integrity-check.
    ++  ** without the overhead of cross-checking indexes.  Quick_check
    ++  ** is linear time wherease integrity_check is O(NlogN).
    +   */
    +   case PragTyp_INTEGRITY_CHECK: {
    +     int i, j, addr, mxErr;
    + 
    +-    /* Code that appears at the end of the integrity check.  If no error
    +-    ** messages have been generated, output OK.  Otherwise output the
    +-    ** error message
    +-    */
    +-    static const int iLn = VDBE_OFFSET_LINENO(2);
    +-    static const VdbeOpList endCode[] = {
    +-      { OP_AddImm,      1, 0,        0},    /* 0 */
    +-      { OP_If,          1, 0,        0},    /* 1 */
    +-      { OP_String8,     0, 3,        0},    /* 2 */
    +-      { OP_ResultRow,   3, 1,        0},
    +-    };
    +-
    +     int isQuick = (sqlite3Tolower(zLeft[0])=='q');
    + 
    +     /* If the PRAGMA command was of the form "PRAGMA <db>.integrity_check",
    +@@ -107197,7 +116765,6 @@ SQLITE_PRIVATE void sqlite3Pragma(
    + 
    +     /* Initialize the VDBE program */
    +     pParse->nMem = 6;
    +-    setOneColumnName(v, "integrity_check");
    + 
    +     /* Set the maximum error count */
    +     mxErr = SQLITE_INTEGRITY_CHECK_ERROR_MAX;
    +@@ -107207,63 +116774,66 @@ SQLITE_PRIVATE void sqlite3Pragma(
    +         mxErr = SQLITE_INTEGRITY_CHECK_ERROR_MAX;
    +       }
    +     }
    +-    sqlite3VdbeAddOp2(v, OP_Integer, mxErr, 1);  /* reg[1] holds errors left */
    ++    sqlite3VdbeAddOp2(v, OP_Integer, mxErr-1, 1); /* reg[1] holds errors left */
    + 
    +     /* Do an integrity check on each database file */
    +     for(i=0; i<db->nDb; i++){
    +-      HashElem *x;
    +-      Hash *pTbls;
    +-      int cnt = 0;
    ++      HashElem *x;     /* For looping over tables in the schema */
    ++      Hash *pTbls;     /* Set of all tables in the schema */
    ++      int *aRoot;      /* Array of root page numbers of all btrees */
    ++      int cnt = 0;     /* Number of entries in aRoot[] */
    ++      int mxIdx = 0;   /* Maximum number of indexes for any table */
    + 
    +       if( OMIT_TEMPDB && i==1 ) continue;
    +       if( iDb>=0 && i!=iDb ) continue;
    + 
    +       sqlite3CodeVerifySchema(pParse, i);
    +-      addr = sqlite3VdbeAddOp1(v, OP_IfPos, 1); /* Halt if out of errors */
    +-      VdbeCoverage(v);
    +-      sqlite3VdbeAddOp2(v, OP_Halt, 0, 0);
    +-      sqlite3VdbeJumpHere(v, addr);
    + 
    +       /* Do an integrity check of the B-Tree
    +       **
    +-      ** Begin by filling registers 2, 3, ... with the root pages numbers
    ++      ** Begin by finding the root pages numbers
    +       ** for all tables and indices in the database.
    +       */
    +       assert( sqlite3SchemaMutexHeld(db, i, 0) );
    +       pTbls = &db->aDb[i].pSchema->tblHash;
    +-      for(x=sqliteHashFirst(pTbls); x; x=sqliteHashNext(x)){
    ++      for(cnt=0, x=sqliteHashFirst(pTbls); x; x=sqliteHashNext(x)){
    ++        Table *pTab = sqliteHashData(x);  /* Current table */
    ++        Index *pIdx;                      /* An index on pTab */
    ++        int nIdx;                         /* Number of indexes on pTab */
    ++        if( HasRowid(pTab) ) cnt++;
    ++        for(nIdx=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, nIdx++){ cnt++; }
    ++        if( nIdx>mxIdx ) mxIdx = nIdx;
    ++      }
    ++      aRoot = sqlite3DbMallocRawNN(db, sizeof(int)*(cnt+1));
    ++      if( aRoot==0 ) break;
    ++      for(cnt=0, x=sqliteHashFirst(pTbls); x; x=sqliteHashNext(x)){
    +         Table *pTab = sqliteHashData(x);
    +         Index *pIdx;
    +-        if( HasRowid(pTab) ){
    +-          sqlite3VdbeAddOp2(v, OP_Integer, pTab->tnum, 2+cnt);
    +-          VdbeComment((v, "%s", pTab->zName));
    +-          cnt++;
    +-        }
    ++        if( HasRowid(pTab) ) aRoot[++cnt] = pTab->tnum;
    +         for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){
    +-          sqlite3VdbeAddOp2(v, OP_Integer, pIdx->tnum, 2+cnt);
    +-          VdbeComment((v, "%s", pIdx->zName));
    +-          cnt++;
    ++          aRoot[++cnt] = pIdx->tnum;
    +         }
    +       }
    ++      aRoot[0] = cnt;
    + 
    +       /* Make sure sufficient number of registers have been allocated */
    +-      pParse->nMem = MAX( pParse->nMem, cnt+8 );
    ++      pParse->nMem = MAX( pParse->nMem, 8+mxIdx );
    ++      sqlite3ClearTempRegCache(pParse);
    + 
    +       /* Do the b-tree integrity checks */
    +-      sqlite3VdbeAddOp3(v, OP_IntegrityCk, 2, cnt, 1);
    ++      sqlite3VdbeAddOp4(v, OP_IntegrityCk, 2, cnt, 1, (char*)aRoot,P4_INTARRAY);
    +       sqlite3VdbeChangeP5(v, (u8)i);
    +       addr = sqlite3VdbeAddOp1(v, OP_IsNull, 2); VdbeCoverage(v);
    +       sqlite3VdbeAddOp4(v, OP_String8, 0, 3, 0,
    +-         sqlite3MPrintf(db, "*** in database %s ***\n", db->aDb[i].zName),
    ++         sqlite3MPrintf(db, "*** in database %s ***\n", db->aDb[i].zDbSName),
    +          P4_DYNAMIC);
    +-      sqlite3VdbeAddOp3(v, OP_Move, 2, 4, 1);
    +-      sqlite3VdbeAddOp3(v, OP_Concat, 4, 3, 2);
    +-      sqlite3VdbeAddOp2(v, OP_ResultRow, 2, 1);
    ++      sqlite3VdbeAddOp3(v, OP_Concat, 2, 3, 3);
    ++      integrityCheckResultRow(v);
    +       sqlite3VdbeJumpHere(v, addr);
    + 
    +       /* Make sure all the indices are constructed correctly.
    +       */
    +-      for(x=sqliteHashFirst(pTbls); x && !isQuick; x=sqliteHashNext(x)){
    ++      for(x=sqliteHashFirst(pTbls); x; x=sqliteHashNext(x)){
    +         Table *pTab = sqliteHashData(x);
    +         Index *pIdx, *pPk;
    +         Index *pPrior = 0;
    +@@ -107271,115 +116841,156 @@ SQLITE_PRIVATE void sqlite3Pragma(
    +         int iDataCur, iIdxCur;
    +         int r1 = -1;
    + 
    +-        if( pTab->pIndex==0 ) continue;
    ++        if( pTab->tnum<1 ) continue;  /* Skip VIEWs or VIRTUAL TABLEs */
    +         pPk = HasRowid(pTab) ? 0 : sqlite3PrimaryKeyIndex(pTab);
    +-        addr = sqlite3VdbeAddOp1(v, OP_IfPos, 1);  /* Stop if out of errors */
    +-        VdbeCoverage(v);
    +-        sqlite3VdbeAddOp2(v, OP_Halt, 0, 0);
    +-        sqlite3VdbeJumpHere(v, addr);
    +         sqlite3ExprCacheClear(pParse);
    +-        sqlite3OpenTableAndIndices(pParse, pTab, OP_OpenRead,
    ++        sqlite3OpenTableAndIndices(pParse, pTab, OP_OpenRead, 0,
    +                                    1, 0, &iDataCur, &iIdxCur);
    ++        /* reg[7] counts the number of entries in the table.
    ++        ** reg[8+i] counts the number of entries in the i-th index 
    ++        */
    +         sqlite3VdbeAddOp2(v, OP_Integer, 0, 7);
    +         for(j=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, j++){
    +           sqlite3VdbeAddOp2(v, OP_Integer, 0, 8+j); /* index entries counter */
    +         }
    +-        pParse->nMem = MAX(pParse->nMem, 8+j);
    ++        assert( pParse->nMem>=8+j );
    ++        assert( sqlite3NoTempsInRange(pParse,1,7+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; j<pTab->nCol; j++){
    +           char *zErr;
    +-          int jmp2, jmp3;
    ++          int jmp2;
    +           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);
    ++          integrityCheckResultRow(v);
    +           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, 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 */
    +-          /* 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 */
    +-          sqlite3VdbeLoadString(v, 3, "row ");
    +-          sqlite3VdbeAddOp3(v, OP_Concat, 7, 3, 3);
    +-          sqlite3VdbeLoadString(v, 4, " missing from index ");
    +-          sqlite3VdbeAddOp3(v, OP_Concat, 4, 3, 3);
    +-          jmp5 = sqlite3VdbeLoadString(v, 4, pIdx->zName);
    +-          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, jmp2);
    +-          /* 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; kk<pIdx->nKeyCol; kk++){
    +-              int iCol = pIdx->aiColumn[kk];
    +-              assert( iCol!=XN_ROWID && iCol<pTab->nCol );
    +-              if( iCol>=0 && pTab->aCol[iCol].notNull ) continue;
    +-              sqlite3VdbeAddOp2(v, OP_IsNull, r1+kk, uniqOk);
    +-              VdbeCoverage(v);
    ++        /* Verify CHECK constraints */
    ++        if( pTab->pCheck && (db->flags & SQLITE_IgnoreChecks)==0 ){
    ++          ExprList *pCheck = sqlite3ExprListDup(db, pTab->pCheck, 0);
    ++          if( db->mallocFailed==0 ){
    ++            int addrCkFault = sqlite3VdbeMakeLabel(v);
    ++            int addrCkOk = sqlite3VdbeMakeLabel(v);
    ++            char *zErr;
    ++            int k;
    ++            pParse->iSelfTab = iDataCur + 1;
    ++            sqlite3ExprCachePush(pParse);
    ++            for(k=pCheck->nExpr-1; k>0; k--){
    ++              sqlite3ExprIfFalse(pParse, pCheck->a[k].pExpr, addrCkFault, 0);
    +             }
    +-            jmp6 = sqlite3VdbeAddOp1(v, OP_Next, iIdxCur+j); VdbeCoverage(v);
    +-            sqlite3VdbeGoto(v, 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 */
    +-            sqlite3VdbeLoadString(v, 3, "non-unique entry in index ");
    +-            sqlite3VdbeGoto(v, jmp5);
    +-            sqlite3VdbeResolveLabel(v, uniqOk);
    ++            sqlite3ExprIfTrue(pParse, pCheck->a[0].pExpr, addrCkOk, 
    ++                SQLITE_JUMPIFNULL);
    ++            sqlite3VdbeResolveLabel(v, addrCkFault);
    ++            pParse->iSelfTab = 0;
    ++            zErr = sqlite3MPrintf(db, "CHECK constraint failed in %s",
    ++                pTab->zName);
    ++            sqlite3VdbeAddOp4(v, OP_String8, 0, 3, 0, zErr, P4_DYNAMIC);
    ++            integrityCheckResultRow(v);
    ++            sqlite3VdbeResolveLabel(v, addrCkOk);
    ++            sqlite3ExprCachePop(pParse);
    ++          }
    ++          sqlite3ExprListDelete(db, pCheck);
    ++        }
    ++        if( !isQuick ){ /* Omit the remaining tests for quick_check */
    ++          /* Sanity check on record header decoding */
    ++          sqlite3VdbeAddOp3(v, OP_Column, iDataCur, pTab->nCol-1, 3);
    ++          sqlite3VdbeChangeP5(v, OPFLAG_TYPEOFARG);
    ++          /* Validate index entries for the current row */
    ++          for(j=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, j++){
    ++            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 */
    ++            /* Verify that an index entry exists for the current table row */
    ++            jmp2 = sqlite3VdbeAddOp4Int(v, OP_Found, iIdxCur+j, ckUniq, r1,
    ++                                        pIdx->nColumn); VdbeCoverage(v);
    ++            sqlite3VdbeLoadString(v, 3, "row ");
    ++            sqlite3VdbeAddOp3(v, OP_Concat, 7, 3, 3);
    ++            sqlite3VdbeLoadString(v, 4, " missing from index ");
    ++            sqlite3VdbeAddOp3(v, OP_Concat, 4, 3, 3);
    ++            jmp5 = sqlite3VdbeLoadString(v, 4, pIdx->zName);
    ++            sqlite3VdbeAddOp3(v, OP_Concat, 4, 3, 3);
    ++            jmp4 = integrityCheckResultRow(v);
    ++            sqlite3VdbeJumpHere(v, jmp2);
    ++            /* 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; kk<pIdx->nKeyCol; kk++){
    ++                int iCol = pIdx->aiColumn[kk];
    ++                assert( iCol!=XN_ROWID && iCol<pTab->nCol );
    ++                if( iCol>=0 && pTab->aCol[iCol].notNull ) continue;
    ++                sqlite3VdbeAddOp2(v, OP_IsNull, r1+kk, uniqOk);
    ++                VdbeCoverage(v);
    ++              }
    ++              jmp6 = sqlite3VdbeAddOp1(v, OP_Next, iIdxCur+j); VdbeCoverage(v);
    ++              sqlite3VdbeGoto(v, uniqOk);
    ++              sqlite3VdbeJumpHere(v, jmp6);
    ++              sqlite3VdbeAddOp4Int(v, OP_IdxGT, iIdxCur+j, uniqOk, r1,
    ++                                   pIdx->nKeyCol); VdbeCoverage(v);
    ++              sqlite3VdbeLoadString(v, 3, "non-unique entry in index ");
    ++              sqlite3VdbeGoto(v, jmp5);
    ++              sqlite3VdbeResolveLabel(v, uniqOk);
    ++            }
    ++            sqlite3VdbeJumpHere(v, jmp4);
    ++            sqlite3ResolvePartIdxLabel(pParse, jmp3);
    +           }
    +-          sqlite3VdbeJumpHere(v, jmp4);
    +-          sqlite3ResolvePartIdxLabel(pParse, jmp3);
    +         }
    +         sqlite3VdbeAddOp2(v, OP_Next, iDataCur, loopTop); VdbeCoverage(v);
    +         sqlite3VdbeJumpHere(v, loopTop-1);
    + #ifndef SQLITE_OMIT_BTREECOUNT
    +-        sqlite3VdbeLoadString(v, 2, "wrong # of entries in index ");
    +-        for(j=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, j++){
    +-          if( pPk==pIdx ) continue;
    +-          addr = sqlite3VdbeCurrentAddr(v);
    +-          sqlite3VdbeAddOp2(v, OP_IfPos, 1, addr+2); VdbeCoverage(v);
    +-          sqlite3VdbeAddOp2(v, OP_Halt, 0, 0);
    +-          sqlite3VdbeAddOp2(v, OP_Count, iIdxCur+j, 3);
    +-          sqlite3VdbeAddOp3(v, OP_Eq, 8+j, addr+8, 3); VdbeCoverage(v);
    +-          sqlite3VdbeChangeP5(v, SQLITE_NOTNULL);
    +-          sqlite3VdbeAddOp2(v, OP_AddImm, 1, -1);
    +-          sqlite3VdbeLoadString(v, 3, pIdx->zName);
    +-          sqlite3VdbeAddOp3(v, OP_Concat, 3, 2, 7);
    +-          sqlite3VdbeAddOp2(v, OP_ResultRow, 7, 1);
    ++        if( !isQuick ){
    ++          sqlite3VdbeLoadString(v, 2, "wrong # of entries in index ");
    ++          for(j=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, j++){
    ++            if( pPk==pIdx ) continue;
    ++            sqlite3VdbeAddOp2(v, OP_Count, iIdxCur+j, 3);
    ++            addr = sqlite3VdbeAddOp3(v, OP_Eq, 8+j, 0, 3); VdbeCoverage(v);
    ++            sqlite3VdbeChangeP5(v, SQLITE_NOTNULL);
    ++            sqlite3VdbeLoadString(v, 4, pIdx->zName);
    ++            sqlite3VdbeAddOp3(v, OP_Concat, 4, 2, 3);
    ++            integrityCheckResultRow(v);
    ++            sqlite3VdbeJumpHere(v, addr);
    ++          }
    +         }
    + #endif /* SQLITE_OMIT_BTREECOUNT */
    +       } 
    +     }
    +-    addr = sqlite3VdbeAddOpList(v, ArraySize(endCode), endCode, iLn);
    +-    sqlite3VdbeChangeP2(v, addr, -mxErr);
    +-    sqlite3VdbeJumpHere(v, addr+1);
    +-    sqlite3VdbeChangeP4(v, addr+2, "ok", P4_STATIC);
    ++    {
    ++      static const int iLn = VDBE_OFFSET_LINENO(2);
    ++      static const VdbeOpList endCode[] = {
    ++        { OP_AddImm,      1, 0,        0},    /* 0 */
    ++        { OP_IfNotZero,   1, 4,        0},    /* 1 */
    ++        { OP_String8,     0, 3,        0},    /* 2 */
    ++        { OP_ResultRow,   3, 1,        0},    /* 3 */
    ++        { OP_Halt,        0, 0,        0},    /* 4 */
    ++        { OP_String8,     0, 3,        0},    /* 5 */
    ++        { OP_Goto,        0, 3,        0},    /* 6 */
    ++      };
    ++      VdbeOp *aOp;
    ++
    ++      aOp = sqlite3VdbeAddOpList(v, ArraySize(endCode), endCode, iLn);
    ++      if( aOp ){
    ++        aOp[0].p2 = 1-mxErr;
    ++        aOp[2].p4type = P4_STATIC;
    ++        aOp[2].p4.z = "ok";
    ++        aOp[5].p4type = P4_STATIC;
    ++        aOp[5].p4.z = (char*)sqlite3ErrStr(SQLITE_CORRUPT);
    ++      }
    ++      sqlite3VdbeChangeP3(v, 0, sqlite3VdbeCurrentAddr(v)-2);
    ++    }
    +   }
    +   break;
    + #endif /* SQLITE_OMIT_INTEGRITY_CHECK */
    +@@ -107428,7 +117039,7 @@ SQLITE_PRIVATE void sqlite3Pragma(
    +       assert( encnames[SQLITE_UTF8].enc==SQLITE_UTF8 );
    +       assert( encnames[SQLITE_UTF16LE].enc==SQLITE_UTF16LE );
    +       assert( encnames[SQLITE_UTF16BE].enc==SQLITE_UTF16BE );
    +-      returnSingleText(v, "encoding", encnames[ENC(pParse->db)].zName);
    ++      returnSingleText(v, encnames[ENC(pParse->db)].zName);
    +     }else{                        /* "PRAGMA encoding = XXX" */
    +       /* Only change the value of sqlite.enc if the database handle is not
    +       ** initialized. If the main database exists, the new sqlite.enc value
    +@@ -107457,16 +117068,18 @@ SQLITE_PRIVATE void sqlite3Pragma(
    + 
    + #ifndef SQLITE_OMIT_SCHEMA_VERSION_PRAGMAS
    +   /*
    +-  **   PRAGMA [database.]schema_version
    +-  **   PRAGMA [database.]schema_version = <integer>
    ++  **   PRAGMA [schema.]schema_version
    ++  **   PRAGMA [schema.]schema_version = <integer>
    +   **
    +-  **   PRAGMA [database.]user_version
    +-  **   PRAGMA [database.]user_version = <integer>
    ++  **   PRAGMA [schema.]user_version
    ++  **   PRAGMA [schema.]user_version = <integer>
    +   **
    +-  **   PRAGMA [database.]freelist_count = <integer>
    ++  **   PRAGMA [schema.]freelist_count
    +   **
    +-  **   PRAGMA [database.]application_id
    +-  **   PRAGMA [database.]application_id = <integer>
    ++  **   PRAGMA [schema.]data_version
    ++  **
    ++  **   PRAGMA [schema.]application_id
    ++  **   PRAGMA [schema.]application_id = <integer>
    +   **
    +   ** The pragma's schema_version and user_version are used to set or get
    +   ** the value of the schema-version and user-version, respectively. Both
    +@@ -107489,18 +117102,20 @@ SQLITE_PRIVATE void sqlite3Pragma(
    +   case PragTyp_HEADER_VALUE: {
    +     int iCookie = pPragma->iArg;  /* Which cookie to read or write */
    +     sqlite3VdbeUsesBtree(v, iDb);
    +-    if( zRight && (pPragma->mPragFlag & PragFlag_ReadOnly)==0 ){
    ++    if( zRight && (pPragma->mPragFlg & PragFlg_ReadOnly)==0 ){
    +       /* Write the specified cookie value */
    +       static const VdbeOpList setCookie[] = {
    +         { OP_Transaction,    0,  1,  0},    /* 0 */
    +-        { OP_Integer,        0,  1,  0},    /* 1 */
    +-        { OP_SetCookie,      0,  0,  1},    /* 2 */
    ++        { OP_SetCookie,      0,  0,  0},    /* 1 */
    +       };
    +-      int addr = sqlite3VdbeAddOpList(v, ArraySize(setCookie), setCookie, 0);
    +-      sqlite3VdbeChangeP1(v, addr, iDb);
    +-      sqlite3VdbeChangeP1(v, addr+1, sqlite3Atoi(zRight));
    +-      sqlite3VdbeChangeP1(v, addr+2, iDb);
    +-      sqlite3VdbeChangeP2(v, addr+2, iCookie);
    ++      VdbeOp *aOp;
    ++      sqlite3VdbeVerifyNoMallocRequired(v, ArraySize(setCookie));
    ++      aOp = sqlite3VdbeAddOpList(v, ArraySize(setCookie), setCookie, 0);
    ++      if( ONLY_IF_REALLOC_STRESS(aOp==0) ) break;
    ++      aOp[0].p1 = iDb;
    ++      aOp[1].p1 = iDb;
    ++      aOp[1].p2 = iCookie;
    ++      aOp[1].p3 = sqlite3Atoi(zRight);
    +     }else{
    +       /* Read the specified cookie value */
    +       static const VdbeOpList readCookie[] = {
    +@@ -107508,12 +117123,14 @@ SQLITE_PRIVATE void sqlite3Pragma(
    +         { OP_ReadCookie,      0,  1,  0},    /* 1 */
    +         { OP_ResultRow,       1,  1,  0}
    +       };
    +-      int addr = sqlite3VdbeAddOpList(v, ArraySize(readCookie), readCookie, 0);
    +-      sqlite3VdbeChangeP1(v, addr, iDb);
    +-      sqlite3VdbeChangeP1(v, addr+1, iDb);
    +-      sqlite3VdbeChangeP3(v, addr+1, iCookie);
    +-      sqlite3VdbeSetNumCols(v, 1);
    +-      sqlite3VdbeSetColName(v, 0, COLNAME_NAME, zLeft, SQLITE_TRANSIENT);
    ++      VdbeOp *aOp;
    ++      sqlite3VdbeVerifyNoMallocRequired(v, ArraySize(readCookie));
    ++      aOp = sqlite3VdbeAddOpList(v, ArraySize(readCookie),readCookie,0);
    ++      if( ONLY_IF_REALLOC_STRESS(aOp==0) ) break;
    ++      aOp[0].p1 = iDb;
    ++      aOp[1].p1 = iDb;
    ++      aOp[1].p3 = iCookie;
    ++      sqlite3VdbeReusable(v);
    +     }
    +   }
    +   break;
    +@@ -107530,23 +117147,22 @@ SQLITE_PRIVATE void sqlite3Pragma(
    +     int i = 0;
    +     const char *zOpt;
    +     pParse->nMem = 1;
    +-    setOneColumnName(v, "compile_option");
    +     while( (zOpt = sqlite3_compileoption_get(i++))!=0 ){
    +       sqlite3VdbeLoadString(v, 1, zOpt);
    +       sqlite3VdbeAddOp2(v, OP_ResultRow, 1, 1);
    +     }
    ++    sqlite3VdbeReusable(v);
    +   }
    +   break;
    + #endif /* SQLITE_OMIT_COMPILEOPTION_DIAGS */
    + 
    + #ifndef SQLITE_OMIT_WAL
    +   /*
    +-  **   PRAGMA [database.]wal_checkpoint = passive|full|restart|truncate
    ++  **   PRAGMA [schema.]wal_checkpoint = passive|full|restart|truncate
    +   **
    +   ** Checkpoint the database.
    +   */
    +   case PragTyp_WAL_CHECKPOINT: {
    +-    static const char *azCol[] = { "busy", "log", "checkpointed" };
    +     int iBt = (pId2->z?iDb:SQLITE_MAX_ATTACHED);
    +     int eMode = SQLITE_CHECKPOINT_PASSIVE;
    +     if( zRight ){
    +@@ -107558,7 +117174,6 @@ SQLITE_PRIVATE void sqlite3Pragma(
    +         eMode = SQLITE_CHECKPOINT_TRUNCATE;
    +       }
    +     }
    +-    setAllColumnNames(v, 3, azCol);  assert( 3==ArraySize(azCol) );
    +     pParse->nMem = 3;
    +     sqlite3VdbeAddOp3(v, OP_Checkpoint, iBt, eMode, 1);
    +     sqlite3VdbeAddOp2(v, OP_ResultRow, 1, 3);
    +@@ -107577,7 +117192,7 @@ SQLITE_PRIVATE void sqlite3Pragma(
    +     if( zRight ){
    +       sqlite3_wal_autocheckpoint(db, sqlite3Atoi(zRight));
    +     }
    +-    returnSingleInt(v, "wal_autocheckpoint", 
    ++    returnSingleInt(v, 
    +        db->xWalCallback==sqlite3WalDefaultHook ? 
    +            SQLITE_PTR_TO_INT(db->pWalArg) : 0);
    +   }
    +@@ -107596,6 +117211,119 @@ SQLITE_PRIVATE void sqlite3Pragma(
    +     break;
    +   }
    + 
    ++  /*
    ++  **  PRAGMA optimize
    ++  **  PRAGMA optimize(MASK)
    ++  **  PRAGMA schema.optimize
    ++  **  PRAGMA schema.optimize(MASK)
    ++  **
    ++  ** Attempt to optimize the database.  All schemas are optimized in the first
    ++  ** two forms, and only the specified schema is optimized in the latter two.
    ++  **
    ++  ** The details of optimizations performed by this pragma are expected
    ++  ** to change and improve over time.  Applications should anticipate that
    ++  ** this pragma will perform new optimizations in future releases.
    ++  **
    ++  ** The optional argument is a bitmask of optimizations to perform:
    ++  **
    ++  **    0x0001    Debugging mode.  Do not actually perform any optimizations
    ++  **              but instead return one line of text for each optimization
    ++  **              that would have been done.  Off by default.
    ++  **
    ++  **    0x0002    Run ANALYZE on tables that might benefit.  On by default.
    ++  **              See below for additional information.
    ++  **
    ++  **    0x0004    (Not yet implemented) Record usage and performance 
    ++  **              information from the current session in the
    ++  **              database file so that it will be available to "optimize"
    ++  **              pragmas run by future database connections.
    ++  **
    ++  **    0x0008    (Not yet implemented) Create indexes that might have
    ++  **              been helpful to recent queries
    ++  **
    ++  ** The default MASK is and always shall be 0xfffe.  0xfffe means perform all
    ++  ** of the optimizations listed above except Debug Mode, including new
    ++  ** optimizations that have not yet been invented.  If new optimizations are
    ++  ** ever added that should be off by default, those off-by-default 
    ++  ** optimizations will have bitmasks of 0x10000 or larger.
    ++  **
    ++  ** DETERMINATION OF WHEN TO RUN ANALYZE
    ++  **
    ++  ** In the current implementation, a table is analyzed if only if all of
    ++  ** the following are true:
    ++  **
    ++  ** (1) MASK bit 0x02 is set.
    ++  **
    ++  ** (2) The query planner used sqlite_stat1-style statistics for one or
    ++  **     more indexes of the table at some point during the lifetime of
    ++  **     the current connection.
    ++  **
    ++  ** (3) One or more indexes of the table are currently unanalyzed OR
    ++  **     the number of rows in the table has increased by 25 times or more
    ++  **     since the last time ANALYZE was run.
    ++  **
    ++  ** The rules for when tables are analyzed are likely to change in
    ++  ** future releases.
    ++  */
    ++  case PragTyp_OPTIMIZE: {
    ++    int iDbLast;           /* Loop termination point for the schema loop */
    ++    int iTabCur;           /* Cursor for a table whose size needs checking */
    ++    HashElem *k;           /* Loop over tables of a schema */
    ++    Schema *pSchema;       /* The current schema */
    ++    Table *pTab;           /* A table in the schema */
    ++    Index *pIdx;           /* An index of the table */
    ++    LogEst szThreshold;    /* Size threshold above which reanalysis is needd */
    ++    char *zSubSql;         /* SQL statement for the OP_SqlExec opcode */
    ++    u32 opMask;            /* Mask of operations to perform */
    ++
    ++    if( zRight ){
    ++      opMask = (u32)sqlite3Atoi(zRight);
    ++      if( (opMask & 0x02)==0 ) break;
    ++    }else{
    ++      opMask = 0xfffe;
    ++    }
    ++    iTabCur = pParse->nTab++;
    ++    for(iDbLast = zDb?iDb:db->nDb-1; iDb<=iDbLast; iDb++){
    ++      if( iDb==1 ) continue;
    ++      sqlite3CodeVerifySchema(pParse, iDb);
    ++      pSchema = db->aDb[iDb].pSchema;
    ++      for(k=sqliteHashFirst(&pSchema->tblHash); k; k=sqliteHashNext(k)){
    ++        pTab = (Table*)sqliteHashData(k);
    ++
    ++        /* If table pTab has not been used in a way that would benefit from
    ++        ** having analysis statistics during the current session, then skip it.
    ++        ** This also has the effect of skipping virtual tables and views */
    ++        if( (pTab->tabFlags & TF_StatsUsed)==0 ) continue;
    ++
    ++        /* Reanalyze if the table is 25 times larger than the last analysis */
    ++        szThreshold = pTab->nRowLogEst + 46; assert( sqlite3LogEst(25)==46 );
    ++        for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){
    ++          if( !pIdx->hasStat1 ){
    ++            szThreshold = 0; /* Always analyze if any index lacks statistics */
    ++            break;
    ++          }
    ++        }
    ++        if( szThreshold ){
    ++          sqlite3OpenTable(pParse, iTabCur, iDb, pTab, OP_OpenRead);
    ++          sqlite3VdbeAddOp3(v, OP_IfSmaller, iTabCur, 
    ++                         sqlite3VdbeCurrentAddr(v)+2+(opMask&1), szThreshold);
    ++          VdbeCoverage(v);
    ++        }
    ++        zSubSql = sqlite3MPrintf(db, "ANALYZE \"%w\".\"%w\"",
    ++                                 db->aDb[iDb].zDbSName, pTab->zName);
    ++        if( opMask & 0x01 ){
    ++          int r1 = sqlite3GetTempReg(pParse);
    ++          sqlite3VdbeAddOp4(v, OP_String8, 0, r1, 0, zSubSql, P4_DYNAMIC);
    ++          sqlite3VdbeAddOp2(v, OP_ResultRow, r1, 1);
    ++        }else{
    ++          sqlite3VdbeAddOp4(v, OP_SqlExec, 0, 0, 0, zSubSql, P4_DYNAMIC);
    ++        }
    ++      }
    ++    }
    ++    sqlite3VdbeAddOp0(v, OP_Expire);
    ++    break;
    ++  }
    ++
    +   /*
    +   **   PRAGMA busy_timeout
    +   **   PRAGMA busy_timeout = N
    +@@ -107610,7 +117338,7 @@ SQLITE_PRIVATE void sqlite3Pragma(
    +     if( zRight ){
    +       sqlite3_busy_timeout(db, sqlite3Atoi(zRight));
    +     }
    +-    returnSingleInt(v, "timeout",  db->busyTimeout);
    ++    returnSingleInt(v, db->busyTimeout);
    +     break;
    +   }
    + 
    +@@ -107630,7 +117358,7 @@ SQLITE_PRIVATE void sqlite3Pragma(
    +     if( zRight && sqlite3DecOrHexToI64(zRight, &N)==SQLITE_OK ){
    +       sqlite3_soft_heap_limit64(N);
    +     }
    +-    returnSingleInt(v, "soft_heap_limit",  sqlite3_soft_heap_limit64(-1));
    ++    returnSingleInt(v, sqlite3_soft_heap_limit64(-1));
    +     break;
    +   }
    + 
    +@@ -107649,8 +117377,7 @@ SQLITE_PRIVATE void sqlite3Pragma(
    +     ){
    +       sqlite3_limit(db, SQLITE_LIMIT_WORKER_THREADS, (int)(N&0x7fffffff));
    +     }
    +-    returnSingleInt(v, "threads",
    +-                    sqlite3_limit(db, SQLITE_LIMIT_WORKER_THREADS, -1));
    ++    returnSingleInt(v, sqlite3_limit(db, SQLITE_LIMIT_WORKER_THREADS, -1));
    +     break;
    +   }
    + 
    +@@ -107662,24 +117389,21 @@ SQLITE_PRIVATE void sqlite3Pragma(
    +     static const char *const azLockName[] = {
    +       "unlocked", "shared", "reserved", "pending", "exclusive"
    +     };
    +-    static const char *azCol[] = { "database", "status" };
    +     int i;
    +-    setAllColumnNames(v, 2, azCol); assert( 2==ArraySize(azCol) );
    +     pParse->nMem = 2;
    +     for(i=0; i<db->nDb; i++){
    +       Btree *pBt;
    +       const char *zState = "unknown";
    +       int j;
    +-      if( db->aDb[i].zName==0 ) continue;
    ++      if( db->aDb[i].zDbSName==0 ) continue;
    +       pBt = db->aDb[i].pBt;
    +       if( pBt==0 || sqlite3BtreePager(pBt)==0 ){
    +         zState = "closed";
    +-      }else if( sqlite3_file_control(db, i ? db->aDb[i].zName : 0, 
    ++      }else if( sqlite3_file_control(db, i ? db->aDb[i].zDbSName : 0, 
    +                                      SQLITE_FCNTL_LOCKSTATE, &j)==SQLITE_OK ){
    +          zState = azLockName[j];
    +       }
    +-      sqlite3VdbeMultiLoad(v, 1, "ss", db->aDb[i].zName, zState);
    +-      sqlite3VdbeAddOp2(v, OP_ResultRow, 1, 2);
    ++      sqlite3VdbeMultiLoad(v, 1, "ss", db->aDb[i].zDbSName, zState);
    +     }
    +     break;
    +   }
    +@@ -107730,10 +117454,329 @@ SQLITE_PRIVATE void sqlite3Pragma(
    + 
    +   } /* End of the PRAGMA switch */
    + 
    ++  /* The following block is a no-op unless SQLITE_DEBUG is defined. Its only
    ++  ** purpose is to execute assert() statements to verify that if the
    ++  ** PragFlg_NoColumns1 flag is set and the caller specified an argument
    ++  ** to the PRAGMA, the implementation has not added any OP_ResultRow 
    ++  ** instructions to the VM.  */
    ++  if( (pPragma->mPragFlg & PragFlg_NoColumns1) && zRight ){
    ++    sqlite3VdbeVerifyNoResultRow(v);
    ++  }
    ++
    + pragma_out:
    +   sqlite3DbFree(db, zLeft);
    +   sqlite3DbFree(db, zRight);
    + }
    ++#ifndef SQLITE_OMIT_VIRTUALTABLE
    ++/*****************************************************************************
    ++** Implementation of an eponymous virtual table that runs a pragma.
    ++**
    ++*/
    ++typedef struct PragmaVtab PragmaVtab;
    ++typedef struct PragmaVtabCursor PragmaVtabCursor;
    ++struct PragmaVtab {
    ++  sqlite3_vtab base;        /* Base class.  Must be first */
    ++  sqlite3 *db;              /* The database connection to which it belongs */
    ++  const PragmaName *pName;  /* Name of the pragma */
    ++  u8 nHidden;               /* Number of hidden columns */
    ++  u8 iHidden;               /* Index of the first hidden column */
    ++};
    ++struct PragmaVtabCursor {
    ++  sqlite3_vtab_cursor base; /* Base class.  Must be first */
    ++  sqlite3_stmt *pPragma;    /* The pragma statement to run */
    ++  sqlite_int64 iRowid;      /* Current rowid */
    ++  char *azArg[2];           /* Value of the argument and schema */
    ++};
    ++
    ++/* 
    ++** Pragma virtual table module xConnect method.
    ++*/
    ++static int pragmaVtabConnect(
    ++  sqlite3 *db,
    ++  void *pAux,
    ++  int argc, const char *const*argv,
    ++  sqlite3_vtab **ppVtab,
    ++  char **pzErr
    ++){
    ++  const PragmaName *pPragma = (const PragmaName*)pAux;
    ++  PragmaVtab *pTab = 0;
    ++  int rc;
    ++  int i, j;
    ++  char cSep = '(';
    ++  StrAccum acc;
    ++  char zBuf[200];
    ++
    ++  UNUSED_PARAMETER(argc);
    ++  UNUSED_PARAMETER(argv);
    ++  sqlite3StrAccumInit(&acc, 0, zBuf, sizeof(zBuf), 0);
    ++  sqlite3StrAccumAppendAll(&acc, "CREATE TABLE x");
    ++  for(i=0, j=pPragma->iPragCName; i<pPragma->nPragCName; i++, j++){
    ++    sqlite3XPrintf(&acc, "%c\"%s\"", cSep, pragCName[j]);
    ++    cSep = ',';
    ++  }
    ++  if( i==0 ){
    ++    sqlite3XPrintf(&acc, "(\"%s\"", pPragma->zName);
    ++    cSep = ',';
    ++    i++;
    ++  }
    ++  j = 0;
    ++  if( pPragma->mPragFlg & PragFlg_Result1 ){
    ++    sqlite3StrAccumAppendAll(&acc, ",arg HIDDEN");
    ++    j++;
    ++  }
    ++  if( pPragma->mPragFlg & (PragFlg_SchemaOpt|PragFlg_SchemaReq) ){
    ++    sqlite3StrAccumAppendAll(&acc, ",schema HIDDEN");
    ++    j++;
    ++  }
    ++  sqlite3StrAccumAppend(&acc, ")", 1);
    ++  sqlite3StrAccumFinish(&acc);
    ++  assert( strlen(zBuf) < sizeof(zBuf)-1 );
    ++  rc = sqlite3_declare_vtab(db, zBuf);
    ++  if( rc==SQLITE_OK ){
    ++    pTab = (PragmaVtab*)sqlite3_malloc(sizeof(PragmaVtab));
    ++    if( pTab==0 ){
    ++      rc = SQLITE_NOMEM;
    ++    }else{
    ++      memset(pTab, 0, sizeof(PragmaVtab));
    ++      pTab->pName = pPragma;
    ++      pTab->db = db;
    ++      pTab->iHidden = i;
    ++      pTab->nHidden = j;
    ++    }
    ++  }else{
    ++    *pzErr = sqlite3_mprintf("%s", sqlite3_errmsg(db));
    ++  }
    ++
    ++  *ppVtab = (sqlite3_vtab*)pTab;
    ++  return rc;
    ++}
    ++
    ++/* 
    ++** Pragma virtual table module xDisconnect method.
    ++*/
    ++static int pragmaVtabDisconnect(sqlite3_vtab *pVtab){
    ++  PragmaVtab *pTab = (PragmaVtab*)pVtab;
    ++  sqlite3_free(pTab);
    ++  return SQLITE_OK;
    ++}
    ++
    ++/* Figure out the best index to use to search a pragma virtual table.
    ++**
    ++** There are not really any index choices.  But we want to encourage the
    ++** query planner to give == constraints on as many hidden parameters as
    ++** possible, and especially on the first hidden parameter.  So return a
    ++** high cost if hidden parameters are unconstrained.
    ++*/
    ++static int pragmaVtabBestIndex(sqlite3_vtab *tab, sqlite3_index_info *pIdxInfo){
    ++  PragmaVtab *pTab = (PragmaVtab*)tab;
    ++  const struct sqlite3_index_constraint *pConstraint;
    ++  int i, j;
    ++  int seen[2];
    ++
    ++  pIdxInfo->estimatedCost = (double)1;
    ++  if( pTab->nHidden==0 ){ return SQLITE_OK; }
    ++  pConstraint = pIdxInfo->aConstraint;
    ++  seen[0] = 0;
    ++  seen[1] = 0;
    ++  for(i=0; i<pIdxInfo->nConstraint; i++, pConstraint++){
    ++    if( pConstraint->usable==0 ) continue;
    ++    if( pConstraint->op!=SQLITE_INDEX_CONSTRAINT_EQ ) continue;
    ++    if( pConstraint->iColumn < pTab->iHidden ) continue;
    ++    j = pConstraint->iColumn - pTab->iHidden;
    ++    assert( j < 2 );
    ++    seen[j] = i+1;
    ++  }
    ++  if( seen[0]==0 ){
    ++    pIdxInfo->estimatedCost = (double)2147483647;
    ++    pIdxInfo->estimatedRows = 2147483647;
    ++    return SQLITE_OK;
    ++  }
    ++  j = seen[0]-1;
    ++  pIdxInfo->aConstraintUsage[j].argvIndex = 1;
    ++  pIdxInfo->aConstraintUsage[j].omit = 1;
    ++  if( seen[1]==0 ) return SQLITE_OK;
    ++  pIdxInfo->estimatedCost = (double)20;
    ++  pIdxInfo->estimatedRows = 20;
    ++  j = seen[1]-1;
    ++  pIdxInfo->aConstraintUsage[j].argvIndex = 2;
    ++  pIdxInfo->aConstraintUsage[j].omit = 1;
    ++  return SQLITE_OK;
    ++}
    ++
    ++/* Create a new cursor for the pragma virtual table */
    ++static int pragmaVtabOpen(sqlite3_vtab *pVtab, sqlite3_vtab_cursor **ppCursor){
    ++  PragmaVtabCursor *pCsr;
    ++  pCsr = (PragmaVtabCursor*)sqlite3_malloc(sizeof(*pCsr));
    ++  if( pCsr==0 ) return SQLITE_NOMEM;
    ++  memset(pCsr, 0, sizeof(PragmaVtabCursor));
    ++  pCsr->base.pVtab = pVtab;
    ++  *ppCursor = &pCsr->base;
    ++  return SQLITE_OK;
    ++}
    ++
    ++/* Clear all content from pragma virtual table cursor. */
    ++static void pragmaVtabCursorClear(PragmaVtabCursor *pCsr){
    ++  int i;
    ++  sqlite3_finalize(pCsr->pPragma);
    ++  pCsr->pPragma = 0;
    ++  for(i=0; i<ArraySize(pCsr->azArg); i++){
    ++    sqlite3_free(pCsr->azArg[i]);
    ++    pCsr->azArg[i] = 0;
    ++  }
    ++}
    ++
    ++/* Close a pragma virtual table cursor */
    ++static int pragmaVtabClose(sqlite3_vtab_cursor *cur){
    ++  PragmaVtabCursor *pCsr = (PragmaVtabCursor*)cur;
    ++  pragmaVtabCursorClear(pCsr);
    ++  sqlite3_free(pCsr);
    ++  return SQLITE_OK;
    ++}
    ++
    ++/* Advance the pragma virtual table cursor to the next row */
    ++static int pragmaVtabNext(sqlite3_vtab_cursor *pVtabCursor){
    ++  PragmaVtabCursor *pCsr = (PragmaVtabCursor*)pVtabCursor;
    ++  int rc = SQLITE_OK;
    ++
    ++  /* Increment the xRowid value */
    ++  pCsr->iRowid++;
    ++  assert( pCsr->pPragma );
    ++  if( SQLITE_ROW!=sqlite3_step(pCsr->pPragma) ){
    ++    rc = sqlite3_finalize(pCsr->pPragma);
    ++    pCsr->pPragma = 0;
    ++    pragmaVtabCursorClear(pCsr);
    ++  }
    ++  return rc;
    ++}
    ++
    ++/* 
    ++** Pragma virtual table module xFilter method.
    ++*/
    ++static int pragmaVtabFilter(
    ++  sqlite3_vtab_cursor *pVtabCursor, 
    ++  int idxNum, const char *idxStr,
    ++  int argc, sqlite3_value **argv
    ++){
    ++  PragmaVtabCursor *pCsr = (PragmaVtabCursor*)pVtabCursor;
    ++  PragmaVtab *pTab = (PragmaVtab*)(pVtabCursor->pVtab);
    ++  int rc;
    ++  int i, j;
    ++  StrAccum acc;
    ++  char *zSql;
    ++
    ++  UNUSED_PARAMETER(idxNum);
    ++  UNUSED_PARAMETER(idxStr);
    ++  pragmaVtabCursorClear(pCsr);
    ++  j = (pTab->pName->mPragFlg & PragFlg_Result1)!=0 ? 0 : 1;
    ++  for(i=0; i<argc; i++, j++){
    ++    const char *zText = (const char*)sqlite3_value_text(argv[i]);
    ++    assert( j<ArraySize(pCsr->azArg) );
    ++    assert( pCsr->azArg[j]==0 );
    ++    if( zText ){
    ++      pCsr->azArg[j] = sqlite3_mprintf("%s", zText);
    ++      if( pCsr->azArg[j]==0 ){
    ++        return SQLITE_NOMEM;
    ++      }
    ++    }
    ++  }
    ++  sqlite3StrAccumInit(&acc, 0, 0, 0, pTab->db->aLimit[SQLITE_LIMIT_SQL_LENGTH]);
    ++  sqlite3StrAccumAppendAll(&acc, "PRAGMA ");
    ++  if( pCsr->azArg[1] ){
    ++    sqlite3XPrintf(&acc, "%Q.", pCsr->azArg[1]);
    ++  }
    ++  sqlite3StrAccumAppendAll(&acc, pTab->pName->zName);
    ++  if( pCsr->azArg[0] ){
    ++    sqlite3XPrintf(&acc, "=%Q", pCsr->azArg[0]);
    ++  }
    ++  zSql = sqlite3StrAccumFinish(&acc);
    ++  if( zSql==0 ) return SQLITE_NOMEM;
    ++  rc = sqlite3_prepare_v2(pTab->db, zSql, -1, &pCsr->pPragma, 0);
    ++  sqlite3_free(zSql);
    ++  if( rc!=SQLITE_OK ){
    ++    pTab->base.zErrMsg = sqlite3_mprintf("%s", sqlite3_errmsg(pTab->db));
    ++    return rc;
    ++  }
    ++  return pragmaVtabNext(pVtabCursor);
    ++}
    ++
    ++/*
    ++** Pragma virtual table module xEof method.
    ++*/
    ++static int pragmaVtabEof(sqlite3_vtab_cursor *pVtabCursor){
    ++  PragmaVtabCursor *pCsr = (PragmaVtabCursor*)pVtabCursor;
    ++  return (pCsr->pPragma==0);
    ++}
    ++
    ++/* The xColumn method simply returns the corresponding column from
    ++** the PRAGMA.  
    ++*/
    ++static int pragmaVtabColumn(
    ++  sqlite3_vtab_cursor *pVtabCursor, 
    ++  sqlite3_context *ctx, 
    ++  int i
    ++){
    ++  PragmaVtabCursor *pCsr = (PragmaVtabCursor*)pVtabCursor;
    ++  PragmaVtab *pTab = (PragmaVtab*)(pVtabCursor->pVtab);
    ++  if( i<pTab->iHidden ){
    ++    sqlite3_result_value(ctx, sqlite3_column_value(pCsr->pPragma, i));
    ++  }else{
    ++    sqlite3_result_text(ctx, pCsr->azArg[i-pTab->iHidden],-1,SQLITE_TRANSIENT);
    ++  }
    ++  return SQLITE_OK;
    ++}
    ++
    ++/* 
    ++** Pragma virtual table module xRowid method.
    ++*/
    ++static int pragmaVtabRowid(sqlite3_vtab_cursor *pVtabCursor, sqlite_int64 *p){
    ++  PragmaVtabCursor *pCsr = (PragmaVtabCursor*)pVtabCursor;
    ++  *p = pCsr->iRowid;
    ++  return SQLITE_OK;
    ++}
    ++
    ++/* The pragma virtual table object */
    ++static const sqlite3_module pragmaVtabModule = {
    ++  0,                           /* iVersion */
    ++  0,                           /* xCreate - create a table */
    ++  pragmaVtabConnect,           /* xConnect - connect to an existing table */
    ++  pragmaVtabBestIndex,         /* xBestIndex - Determine search strategy */
    ++  pragmaVtabDisconnect,        /* xDisconnect - Disconnect from a table */
    ++  0,                           /* xDestroy - Drop a table */
    ++  pragmaVtabOpen,              /* xOpen - open a cursor */
    ++  pragmaVtabClose,             /* xClose - close a cursor */
    ++  pragmaVtabFilter,            /* xFilter - configure scan constraints */
    ++  pragmaVtabNext,              /* xNext - advance a cursor */
    ++  pragmaVtabEof,               /* xEof */
    ++  pragmaVtabColumn,            /* xColumn - read data */
    ++  pragmaVtabRowid,             /* xRowid - read data */
    ++  0,                           /* xUpdate - write data */
    ++  0,                           /* xBegin - begin transaction */
    ++  0,                           /* xSync - sync transaction */
    ++  0,                           /* xCommit - commit transaction */
    ++  0,                           /* xRollback - rollback transaction */
    ++  0,                           /* xFindFunction - function overloading */
    ++  0,                           /* xRename - rename the table */
    ++  0,                           /* xSavepoint */
    ++  0,                           /* xRelease */
    ++  0                            /* xRollbackTo */
    ++};
    ++
    ++/*
    ++** Check to see if zTabName is really the name of a pragma.  If it is,
    ++** then register an eponymous virtual table for that pragma and return
    ++** a pointer to the Module object for the new virtual table.
    ++*/
    ++SQLITE_PRIVATE Module *sqlite3PragmaVtabRegister(sqlite3 *db, const char *zName){
    ++  const PragmaName *pName;
    ++  assert( sqlite3_strnicmp(zName, "pragma_", 7)==0 );
    ++  pName = pragmaLocate(zName+7);
    ++  if( pName==0 ) return 0;
    ++  if( (pName->mPragFlg & (PragFlg_Result0|PragFlg_Result1))==0 ) return 0;
    ++  assert( sqlite3HashFind(&db->aModule, zName)==0 );
    ++  return sqlite3VtabCreateModule(db, zName, &pragmaVtabModule, (void*)pName, 0);
    ++}
    ++
    ++#endif /* SQLITE_OMIT_VIRTUALTABLE */
    + 
    + #endif /* SQLITE_OMIT_PRAGMA */
    + 
    +@@ -107766,16 +117809,15 @@ static void corruptSchema(
    +   const char *zExtra   /* Error information */
    + ){
    +   sqlite3 *db = pData->db;
    +-  if( !db->mallocFailed && (db->flags & SQLITE_RecoveryMode)==0 ){
    ++  if( !db->mallocFailed && (db->flags & SQLITE_WriteSchema)==0 ){
    +     char *z;
    +     if( zObj==0 ) zObj = "?";
    +-    z = sqlite3_mprintf("malformed database schema (%s)", zObj);
    +-    if( z && zExtra ) z = sqlite3_mprintf("%z - %s", z, zExtra);
    ++    z = sqlite3MPrintf(db, "malformed database schema (%s)", zObj);
    ++    if( zExtra ) z = sqlite3MPrintf(db, "%z - %s", z, zExtra);
    +     sqlite3DbFree(db, *pData->pzErrMsg);
    +     *pData->pzErrMsg = z;
    +-    if( z==0 ) db->mallocFailed = 1;
    +   }
    +-  pData->rc = db->mallocFailed ? SQLITE_NOMEM : SQLITE_CORRUPT_BKPT;
    ++  pData->rc = db->mallocFailed ? SQLITE_NOMEM_BKPT : SQLITE_CORRUPT_BKPT;
    + }
    + 
    + /*
    +@@ -107815,6 +117857,7 @@ SQLITE_PRIVATE int sqlite3InitCallback(void *pInit, int argc, char **argv, char
    +     ** structures that describe the table, index, or view.
    +     */
    +     int rc;
    ++    u8 saved_iDb = db->init.iDb;
    +     sqlite3_stmt *pStmt;
    +     TESTONLY(int rcp);            /* Return code from sqlite3_prepare() */
    + 
    +@@ -107825,14 +117868,15 @@ SQLITE_PRIVATE int sqlite3InitCallback(void *pInit, int argc, char **argv, char
    +     TESTONLY(rcp = ) sqlite3_prepare(db, argv[2], -1, &pStmt, 0);
    +     rc = db->errCode;
    +     assert( (rc&0xFF)==(rcp&0xFF) );
    +-    db->init.iDb = 0;
    ++    db->init.iDb = saved_iDb;
    ++    assert( saved_iDb==0 || (db->mDbFlags & DBFLAG_Vacuum)!=0 );
    +     if( SQLITE_OK!=rc ){
    +       if( db->init.orphanTrigger ){
    +         assert( iDb==1 );
    +       }else{
    +         pData->rc = rc;
    +         if( rc==SQLITE_NOMEM ){
    +-          db->mallocFailed = 1;
    ++          sqlite3OomFault(db);
    +         }else if( rc!=SQLITE_INTERRUPT && (rc&0xFF)!=SQLITE_LOCKED ){
    +           corruptSchema(pData, argv[0], sqlite3_errmsg(db));
    +         }
    +@@ -107849,7 +117893,7 @@ SQLITE_PRIVATE int sqlite3InitCallback(void *pInit, int argc, char **argv, char
    +     ** to do here is record the root page number for that index.
    +     */
    +     Index *pIndex;
    +-    pIndex = sqlite3FindIndex(db, argv[0], db->aDb[iDb].zName);
    ++    pIndex = sqlite3FindIndex(db, argv[0], db->aDb[iDb].zDbSName);
    +     if( pIndex==0 ){
    +       /* This can occur if there exists an index on a TEMP table which
    +       ** has the same name as another index on a permanent index.  Since
    +@@ -107878,61 +117922,29 @@ static int sqlite3InitOne(sqlite3 *db, int iDb, char **pzErrMsg){
    + #ifndef SQLITE_OMIT_DEPRECATED
    +   int size;
    + #endif
    +-  Table *pTab;
    +   Db *pDb;
    +   char const *azArg[4];
    +   int meta[5];
    +   InitData initData;
    +-  char const *zMasterSchema;
    +-  char const *zMasterName;
    ++  const char *zMasterName;
    +   int openedTransaction = 0;
    + 
    +-  /*
    +-  ** The master database table has a structure like this
    +-  */
    +-  static const char master_schema[] = 
    +-     "CREATE TABLE sqlite_master(\n"
    +-     "  type text,\n"
    +-     "  name text,\n"
    +-     "  tbl_name text,\n"
    +-     "  rootpage integer,\n"
    +-     "  sql text\n"
    +-     ")"
    +-  ;
    +-#ifndef SQLITE_OMIT_TEMPDB
    +-  static const char temp_master_schema[] = 
    +-     "CREATE TEMP TABLE sqlite_temp_master(\n"
    +-     "  type text,\n"
    +-     "  name text,\n"
    +-     "  tbl_name text,\n"
    +-     "  rootpage integer,\n"
    +-     "  sql text\n"
    +-     ")"
    +-  ;
    +-#else
    +-  #define temp_master_schema 0
    +-#endif
    +-
    +   assert( iDb>=0 && iDb<db->nDb );
    +   assert( db->aDb[iDb].pSchema );
    +   assert( sqlite3_mutex_held(db->mutex) );
    +   assert( iDb==1 || sqlite3BtreeHoldsMutex(db->aDb[iDb].pBt) );
    + 
    +-  /* zMasterSchema and zInitScript are set to point at the master schema
    +-  ** and initialisation script appropriate for the database being
    +-  ** initialized. zMasterName is the name of the master table.
    +-  */
    +-  if( !OMIT_TEMPDB && iDb==1 ){
    +-    zMasterSchema = temp_master_schema;
    +-  }else{
    +-    zMasterSchema = master_schema;
    +-  }
    +-  zMasterName = SCHEMA_TABLE(iDb);
    ++  db->init.busy = 1;
    + 
    +-  /* Construct the schema tables.  */
    +-  azArg[0] = zMasterName;
    ++  /* Construct the in-memory representation schema tables (sqlite_master or
    ++  ** sqlite_temp_master) by invoking the parser directly.  The appropriate
    ++  ** table name will be inserted automatically by the parser so we can just
    ++  ** use the abbreviation "x" here.  The parser will also automatically tag
    ++  ** the schema table as read-only. */
    ++  azArg[0] = zMasterName = SCHEMA_TABLE(iDb);
    +   azArg[1] = "1";
    +-  azArg[2] = zMasterSchema;
    ++  azArg[2] = "CREATE TABLE x(type text,name text,tbl_name text,"
    ++                            "rootpage int,sql text)";
    +   azArg[3] = 0;
    +   initData.db = db;
    +   initData.iDb = iDb;
    +@@ -107943,19 +117955,15 @@ static int sqlite3InitOne(sqlite3 *db, int iDb, char **pzErrMsg){
    +     rc = initData.rc;
    +     goto error_out;
    +   }
    +-  pTab = sqlite3FindTable(db, zMasterName, db->aDb[iDb].zName);
    +-  if( ALWAYS(pTab) ){
    +-    pTab->tabFlags |= TF_Readonly;
    +-  }
    + 
    +   /* Create a cursor to hold the database open
    +   */
    +   pDb = &db->aDb[iDb];
    +   if( pDb->pBt==0 ){
    +-    if( !OMIT_TEMPDB && ALWAYS(iDb==1) ){
    +-      DbSetProperty(db, 1, DB_SchemaLoaded);
    +-    }
    +-    return SQLITE_OK;
    ++    assert( iDb==1 );
    ++    DbSetProperty(db, 1, DB_SchemaLoaded);
    ++    rc = SQLITE_OK;
    ++    goto error_out;
    +   }
    + 
    +   /* If there is not already a read-only (or read-write) transaction opened
    +@@ -108065,8 +118073,8 @@ static int sqlite3InitOne(sqlite3 *db, int iDb, char **pzErrMsg){
    +   {
    +     char *zSql;
    +     zSql = sqlite3MPrintf(db, 
    +-        "SELECT name, rootpage, sql FROM '%q'.%s ORDER BY rowid",
    +-        db->aDb[iDb].zName, zMasterName);
    ++        "SELECT name, rootpage, sql FROM \"%w\".%s ORDER BY rowid",
    ++        db->aDb[iDb].zDbSName, zMasterName);
    + #ifndef SQLITE_OMIT_AUTHORIZATION
    +     {
    +       sqlite3_xauth xAuth;
    +@@ -108087,11 +118095,11 @@ static int sqlite3InitOne(sqlite3 *db, int iDb, char **pzErrMsg){
    + #endif
    +   }
    +   if( db->mallocFailed ){
    +-    rc = SQLITE_NOMEM;
    ++    rc = SQLITE_NOMEM_BKPT;
    +     sqlite3ResetAllSchemasOfConnection(db);
    +   }
    +-  if( rc==SQLITE_OK || (db->flags&SQLITE_RecoveryMode)){
    +-    /* Black magic: If the SQLITE_RecoveryMode flag is set, then consider
    ++  if( rc==SQLITE_OK || (db->flags&SQLITE_WriteSchema)){
    ++    /* Black magic: If the SQLITE_WriteSchema flag is set, then consider
    +     ** the schema loaded, even if errors occurred. In this situation the 
    +     ** current sqlite3_prepare() operation will fail, but the following one
    +     ** will attempt to compile the supplied statement against whatever subset
    +@@ -108114,9 +118122,13 @@ initone_error_out:
    +   sqlite3BtreeLeave(pDb->pBt);
    + 
    + error_out:
    +-  if( rc==SQLITE_NOMEM || rc==SQLITE_IOERR_NOMEM ){
    +-    db->mallocFailed = 1;
    ++  if( rc ){
    ++    if( rc==SQLITE_NOMEM || rc==SQLITE_IOERR_NOMEM ){
    ++      sqlite3OomFault(db);
    ++    }
    ++    sqlite3ResetOneSchema(db, iDb);
    +   }
    ++  db->init.busy = 0;
    +   return rc;
    + }
    + 
    +@@ -108132,42 +118144,29 @@ error_out:
    + */
    + SQLITE_PRIVATE int sqlite3Init(sqlite3 *db, char **pzErrMsg){
    +   int i, rc;
    +-  int commit_internal = !(db->flags&SQLITE_InternChanges);
    ++  int commit_internal = !(db->mDbFlags&DBFLAG_SchemaChange);
    +   
    +   assert( sqlite3_mutex_held(db->mutex) );
    +   assert( sqlite3BtreeHoldsMutex(db->aDb[0].pBt) );
    +   assert( db->init.busy==0 );
    +-  rc = SQLITE_OK;
    +-  db->init.busy = 1;
    +   ENC(db) = SCHEMA_ENC(db);
    +-  for(i=0; rc==SQLITE_OK && i<db->nDb; i++){
    +-    if( DbHasProperty(db, i, DB_SchemaLoaded) || i==1 ) continue;
    +-    rc = sqlite3InitOne(db, i, pzErrMsg);
    +-    if( rc ){
    +-      sqlite3ResetOneSchema(db, i);
    +-    }
    ++  assert( db->nDb>0 );
    ++  /* Do the main schema first */
    ++  if( !DbHasProperty(db, 0, DB_SchemaLoaded) ){
    ++    rc = sqlite3InitOne(db, 0, pzErrMsg);
    ++    if( rc ) return rc;
    +   }
    +-
    +-  /* Once all the other databases have been initialized, load the schema
    +-  ** for the TEMP database. This is loaded last, as the TEMP database
    +-  ** schema may contain references to objects in other databases.
    +-  */
    +-#ifndef SQLITE_OMIT_TEMPDB
    +-  assert( db->nDb>1 );
    +-  if( rc==SQLITE_OK && !DbHasProperty(db, 1, DB_SchemaLoaded) ){
    +-    rc = sqlite3InitOne(db, 1, pzErrMsg);
    +-    if( rc ){
    +-      sqlite3ResetOneSchema(db, 1);
    ++  /* All other schemas after the main schema. The "temp" schema must be last */
    ++  for(i=db->nDb-1; i>0; i--){
    ++    if( !DbHasProperty(db, i, DB_SchemaLoaded) ){
    ++      rc = sqlite3InitOne(db, i, pzErrMsg);
    ++      if( rc ) return rc;
    +     }
    +   }
    +-#endif
    +-
    +-  db->init.busy = 0;
    +-  if( rc==SQLITE_OK && commit_internal ){
    ++  if( commit_internal ){
    +     sqlite3CommitInternalChanges(db);
    +   }
    +-
    +-  return rc; 
    ++  return SQLITE_OK;
    + }
    + 
    + /*
    +@@ -108213,7 +118212,7 @@ static void schemaIsValid(Parse *pParse){
    +     if( !sqlite3BtreeIsInReadTrans(pBt) ){
    +       rc = sqlite3BtreeBeginTrans(pBt, 0);
    +       if( rc==SQLITE_NOMEM || rc==SQLITE_IOERR_NOMEM ){
    +-        db->mallocFailed = 1;
    ++        sqlite3OomFault(db);
    +       }
    +       if( rc!=SQLITE_OK ) return;
    +       openedTransaction = 1;
    +@@ -108258,7 +118257,8 @@ SQLITE_PRIVATE int sqlite3SchemaToIndex(sqlite3 *db, Schema *pSchema){
    +   */
    +   assert( sqlite3_mutex_held(db->mutex) );
    +   if( pSchema ){
    +-    for(i=0; ALWAYS(i<db->nDb); i++){
    ++    for(i=0; 1; i++){
    ++      assert( i<db->nDb );
    +       if( db->aDb[i].pSchema==pSchema ){
    +         break;
    +       }
    +@@ -108272,11 +118272,14 @@ SQLITE_PRIVATE int sqlite3SchemaToIndex(sqlite3 *db, Schema *pSchema){
    + ** Free all memory allocations in the pParse object
    + */
    + SQLITE_PRIVATE void sqlite3ParserReset(Parse *pParse){
    +-  if( pParse ){
    +-    sqlite3 *db = pParse->db;
    +-    sqlite3DbFree(db, pParse->aLabel);
    +-    sqlite3ExprListDelete(db, pParse->pConstExpr);
    ++  sqlite3 *db = pParse->db;
    ++  sqlite3DbFree(db, pParse->aLabel);
    ++  sqlite3ExprListDelete(db, pParse->pConstExpr);
    ++  if( db ){
    ++    assert( db->lookaside.bDisable >= pParse->disableLookaside );
    ++    db->lookaside.bDisable -= pParse->disableLookaside;
    +   }
    ++  pParse->disableLookaside = 0;
    + }
    + 
    + /*
    +@@ -108286,27 +118289,31 @@ static int sqlite3Prepare(
    +   sqlite3 *db,              /* Database handle. */
    +   const char *zSql,         /* UTF-8 encoded SQL statement. */
    +   int nBytes,               /* Length of zSql in bytes. */
    +-  int saveSqlFlag,          /* True to copy SQL text into the sqlite3_stmt */
    ++  u32 prepFlags,            /* Zero or more SQLITE_PREPARE_* flags */
    +   Vdbe *pReprepare,         /* VM being reprepared */
    +   sqlite3_stmt **ppStmt,    /* OUT: A pointer to the prepared statement */
    +   const char **pzTail       /* OUT: End of parsed string */
    + ){
    +-  Parse *pParse;            /* Parsing context */
    +   char *zErrMsg = 0;        /* Error message */
    +   int rc = SQLITE_OK;       /* Result code */
    +   int i;                    /* Loop counter */
    ++  Parse sParse;             /* Parsing context */
    + 
    +-  /* Allocate the parsing context */
    +-  pParse = sqlite3StackAllocZero(db, sizeof(*pParse));
    +-  if( pParse==0 ){
    +-    rc = SQLITE_NOMEM;
    +-    goto end_prepare;
    +-  }
    +-  pParse->pReprepare = pReprepare;
    ++  memset(&sParse, 0, PARSE_HDR_SZ);
    ++  memset(PARSE_TAIL(&sParse), 0, PARSE_TAIL_SZ);
    ++  sParse.pReprepare = pReprepare;
    +   assert( ppStmt && *ppStmt==0 );
    +-  assert( !db->mallocFailed );
    ++  /* assert( !db->mallocFailed ); // not true with SQLITE_USE_ALLOCA */
    +   assert( sqlite3_mutex_held(db->mutex) );
    + 
    ++  /* For a long-term use prepared statement avoid the use of
    ++  ** lookaside memory.
    ++  */
    ++  if( prepFlags & SQLITE_PREPARE_PERSISTENT ){
    ++    sParse.disableLookaside++;
    ++    db->lookaside.bDisable++;
    ++  }
    ++
    +   /* Check to verify that it is possible to get a read lock on all
    +   ** database schemas.  The inability to get a read lock indicates that
    +   ** some other database connection is holding a write-lock, which in
    +@@ -108336,9 +118343,9 @@ static int sqlite3Prepare(
    +       assert( sqlite3BtreeHoldsMutex(pBt) );
    +       rc = sqlite3BtreeSchemaLocked(pBt);
    +       if( rc ){
    +-        const char *zDb = db->aDb[i].zName;
    ++        const char *zDb = db->aDb[i].zDbSName;
    +         sqlite3ErrorWithMsg(db, rc, "database schema is locked: %s", zDb);
    +-        testcase( db->flags & SQLITE_ReadUncommitted );
    ++        testcase( db->flags & SQLITE_ReadUncommit );
    +         goto end_prepare;
    +       }
    +     }
    +@@ -108346,8 +118353,7 @@ static int sqlite3Prepare(
    + 
    +   sqlite3VtabUnlockList(db);
    + 
    +-  pParse->db = db;
    +-  pParse->nQueryLoop = 0;  /* Logarithmic, so 0 really means 1 */
    ++  sParse.db = db;
    +   if( nBytes>=0 && (nBytes==0 || zSql[nBytes-1]!=0) ){
    +     char *zSqlCopy;
    +     int mxLen = db->aLimit[SQLITE_LIMIT_SQL_LENGTH];
    +@@ -108360,64 +118366,60 @@ static int sqlite3Prepare(
    +     }
    +     zSqlCopy = sqlite3DbStrNDup(db, zSql, nBytes);
    +     if( zSqlCopy ){
    +-      sqlite3RunParser(pParse, zSqlCopy, &zErrMsg);
    ++      sqlite3RunParser(&sParse, zSqlCopy, &zErrMsg);
    ++      sParse.zTail = &zSql[sParse.zTail-zSqlCopy];
    +       sqlite3DbFree(db, zSqlCopy);
    +-      pParse->zTail = &zSql[pParse->zTail-zSqlCopy];
    +     }else{
    +-      pParse->zTail = &zSql[nBytes];
    ++      sParse.zTail = &zSql[nBytes];
    +     }
    +   }else{
    +-    sqlite3RunParser(pParse, zSql, &zErrMsg);
    ++    sqlite3RunParser(&sParse, zSql, &zErrMsg);
    +   }
    +-  assert( 0==pParse->nQueryLoop );
    ++  assert( 0==sParse.nQueryLoop );
    + 
    +-  if( db->mallocFailed ){
    +-    pParse->rc = SQLITE_NOMEM;
    +-  }
    +-  if( pParse->rc==SQLITE_DONE ) pParse->rc = SQLITE_OK;
    +-  if( pParse->checkSchema ){
    +-    schemaIsValid(pParse);
    ++  if( sParse.rc==SQLITE_DONE ) sParse.rc = SQLITE_OK;
    ++  if( sParse.checkSchema ){
    ++    schemaIsValid(&sParse);
    +   }
    +   if( db->mallocFailed ){
    +-    pParse->rc = SQLITE_NOMEM;
    ++    sParse.rc = SQLITE_NOMEM_BKPT;
    +   }
    +   if( pzTail ){
    +-    *pzTail = pParse->zTail;
    ++    *pzTail = sParse.zTail;
    +   }
    +-  rc = pParse->rc;
    ++  rc = sParse.rc;
    + 
    + #ifndef SQLITE_OMIT_EXPLAIN
    +-  if( rc==SQLITE_OK && pParse->pVdbe && pParse->explain ){
    ++  if( rc==SQLITE_OK && sParse.pVdbe && sParse.explain ){
    +     static const char * const azColName[] = {
    +        "addr", "opcode", "p1", "p2", "p3", "p4", "p5", "comment",
    +        "selectid", "order", "from", "detail"
    +     };
    +     int iFirst, mx;
    +-    if( pParse->explain==2 ){
    +-      sqlite3VdbeSetNumCols(pParse->pVdbe, 4);
    ++    if( sParse.explain==2 ){
    ++      sqlite3VdbeSetNumCols(sParse.pVdbe, 4);
    +       iFirst = 8;
    +       mx = 12;
    +     }else{
    +-      sqlite3VdbeSetNumCols(pParse->pVdbe, 8);
    ++      sqlite3VdbeSetNumCols(sParse.pVdbe, 8);
    +       iFirst = 0;
    +       mx = 8;
    +     }
    +     for(i=iFirst; i<mx; i++){
    +-      sqlite3VdbeSetColName(pParse->pVdbe, i-iFirst, COLNAME_NAME,
    ++      sqlite3VdbeSetColName(sParse.pVdbe, i-iFirst, COLNAME_NAME,
    +                             azColName[i], SQLITE_STATIC);
    +     }
    +   }
    + #endif
    + 
    +   if( db->init.busy==0 ){
    +-    Vdbe *pVdbe = pParse->pVdbe;
    +-    sqlite3VdbeSetSql(pVdbe, zSql, (int)(pParse->zTail-zSql), saveSqlFlag);
    ++    sqlite3VdbeSetSql(sParse.pVdbe, zSql, (int)(sParse.zTail-zSql), prepFlags);
    +   }
    +-  if( pParse->pVdbe && (rc!=SQLITE_OK || db->mallocFailed) ){
    +-    sqlite3VdbeFinalize(pParse->pVdbe);
    ++  if( sParse.pVdbe && (rc!=SQLITE_OK || db->mallocFailed) ){
    ++    sqlite3VdbeFinalize(sParse.pVdbe);
    +     assert(!(*ppStmt));
    +   }else{
    +-    *ppStmt = (sqlite3_stmt*)pParse->pVdbe;
    ++    *ppStmt = (sqlite3_stmt*)sParse.pVdbe;
    +   }
    + 
    +   if( zErrMsg ){
    +@@ -108428,30 +118430,28 @@ static int sqlite3Prepare(
    +   }
    + 
    +   /* Delete any TriggerPrg structures allocated while parsing this statement. */
    +-  while( pParse->pTriggerPrg ){
    +-    TriggerPrg *pT = pParse->pTriggerPrg;
    +-    pParse->pTriggerPrg = pT->pNext;
    ++  while( sParse.pTriggerPrg ){
    ++    TriggerPrg *pT = sParse.pTriggerPrg;
    ++    sParse.pTriggerPrg = pT->pNext;
    +     sqlite3DbFree(db, pT);
    +   }
    + 
    + end_prepare:
    + 
    +-  sqlite3ParserReset(pParse);
    +-  sqlite3StackFree(db, pParse);
    +-  rc = sqlite3ApiExit(db, rc);
    +-  assert( (rc&db->errMask)==rc );
    ++  sqlite3ParserReset(&sParse);
    +   return rc;
    + }
    + static int sqlite3LockAndPrepare(
    +   sqlite3 *db,              /* Database handle. */
    +   const char *zSql,         /* UTF-8 encoded SQL statement. */
    +   int nBytes,               /* Length of zSql in bytes. */
    +-  int saveSqlFlag,          /* True to copy SQL text into the sqlite3_stmt */
    ++  u32 prepFlags,            /* Zero or more SQLITE_PREPARE_* flags */
    +   Vdbe *pOld,               /* VM being reprepared */
    +   sqlite3_stmt **ppStmt,    /* OUT: A pointer to the prepared statement */
    +   const char **pzTail       /* OUT: End of parsed string */
    + ){
    +   int rc;
    ++  int cnt = 0;
    + 
    + #ifdef SQLITE_ENABLE_API_ARMOR
    +   if( ppStmt==0 ) return SQLITE_MISUSE_BKPT;
    +@@ -108462,14 +118462,18 @@ static int sqlite3LockAndPrepare(
    +   }
    +   sqlite3_mutex_enter(db->mutex);
    +   sqlite3BtreeEnterAll(db);
    +-  rc = sqlite3Prepare(db, zSql, nBytes, saveSqlFlag, pOld, ppStmt, pzTail);
    +-  if( rc==SQLITE_SCHEMA ){
    +-    sqlite3_finalize(*ppStmt);
    +-    rc = sqlite3Prepare(db, zSql, nBytes, saveSqlFlag, pOld, ppStmt, pzTail);
    +-  }
    ++  do{
    ++    /* Make multiple attempts to compile the SQL, until it either succeeds
    ++    ** or encounters a permanent error.  A schema problem after one schema
    ++    ** reset is considered a permanent error. */
    ++    rc = sqlite3Prepare(db, zSql, nBytes, prepFlags, pOld, ppStmt, pzTail);
    ++    assert( rc==SQLITE_OK || *ppStmt==0 );
    ++  }while( rc==SQLITE_ERROR_RETRY
    ++       || (rc==SQLITE_SCHEMA && (sqlite3ResetOneSchema(db,-1), cnt++)==0) );
    +   sqlite3BtreeLeaveAll(db);
    ++  rc = sqlite3ApiExit(db, rc);
    ++  assert( (rc&db->errMask)==rc );
    +   sqlite3_mutex_leave(db->mutex);
    +-  assert( rc==SQLITE_OK || *ppStmt==0 );
    +   return rc;
    + }
    + 
    +@@ -108486,16 +118490,18 @@ SQLITE_PRIVATE int sqlite3Reprepare(Vdbe *p){
    +   sqlite3_stmt *pNew;
    +   const char *zSql;
    +   sqlite3 *db;
    ++  u8 prepFlags;
    + 
    +   assert( sqlite3_mutex_held(sqlite3VdbeDb(p)->mutex) );
    +   zSql = sqlite3_sql((sqlite3_stmt *)p);
    +   assert( zSql!=0 );  /* Reprepare only called for prepare_v2() statements */
    +   db = sqlite3VdbeDb(p);
    +   assert( sqlite3_mutex_held(db->mutex) );
    +-  rc = sqlite3LockAndPrepare(db, zSql, -1, 0, p, &pNew, 0);
    ++  prepFlags = sqlite3VdbePrepareFlags(p);
    ++  rc = sqlite3LockAndPrepare(db, zSql, -1, prepFlags, p, &pNew, 0);
    +   if( rc ){
    +     if( rc==SQLITE_NOMEM ){
    +-      db->mallocFailed = 1;
    ++      sqlite3OomFault(db);
    +     }
    +     assert( pNew==0 );
    +     return rc;
    +@@ -108518,7 +118524,7 @@ SQLITE_PRIVATE int sqlite3Reprepare(Vdbe *p){
    + ** and the statement is automatically recompiled if an schema change
    + ** occurs.
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_prepare(
    ++SQLITE_API int sqlite3_prepare(
    +   sqlite3 *db,              /* Database handle. */
    +   const char *zSql,         /* UTF-8 encoded SQL statement. */
    +   int nBytes,               /* Length of zSql in bytes. */
    +@@ -108530,7 +118536,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_prepare(
    +   assert( rc==SQLITE_OK || ppStmt==0 || *ppStmt==0 );  /* VERIFY: F13021 */
    +   return rc;
    + }
    +-SQLITE_API int SQLITE_STDCALL sqlite3_prepare_v2(
    ++SQLITE_API int sqlite3_prepare_v2(
    +   sqlite3 *db,              /* Database handle. */
    +   const char *zSql,         /* UTF-8 encoded SQL statement. */
    +   int nBytes,               /* Length of zSql in bytes. */
    +@@ -108538,8 +118544,36 @@ SQLITE_API int SQLITE_STDCALL sqlite3_prepare_v2(
    +   const char **pzTail       /* OUT: End of parsed string */
    + ){
    +   int rc;
    +-  rc = sqlite3LockAndPrepare(db,zSql,nBytes,1,0,ppStmt,pzTail);
    +-  assert( rc==SQLITE_OK || ppStmt==0 || *ppStmt==0 );  /* VERIFY: F13021 */
    ++  /* EVIDENCE-OF: R-37923-12173 The sqlite3_prepare_v2() interface works
    ++  ** exactly the same as sqlite3_prepare_v3() with a zero prepFlags
    ++  ** parameter.
    ++  **
    ++  ** Proof in that the 5th parameter to sqlite3LockAndPrepare is 0 */
    ++  rc = sqlite3LockAndPrepare(db,zSql,nBytes,SQLITE_PREPARE_SAVESQL,0,
    ++                             ppStmt,pzTail);
    ++  assert( rc==SQLITE_OK || ppStmt==0 || *ppStmt==0 );
    ++  return rc;
    ++}
    ++SQLITE_API int sqlite3_prepare_v3(
    ++  sqlite3 *db,              /* Database handle. */
    ++  const char *zSql,         /* UTF-8 encoded SQL statement. */
    ++  int nBytes,               /* Length of zSql in bytes. */
    ++  unsigned int prepFlags,   /* Zero or more SQLITE_PREPARE_* flags */
    ++  sqlite3_stmt **ppStmt,    /* OUT: A pointer to the prepared statement */
    ++  const char **pzTail       /* OUT: End of parsed string */
    ++){
    ++  int rc;
    ++  /* EVIDENCE-OF: R-56861-42673 sqlite3_prepare_v3() differs from
    ++  ** sqlite3_prepare_v2() only in having the extra prepFlags parameter,
    ++  ** which is a bit array consisting of zero or more of the
    ++  ** SQLITE_PREPARE_* flags.
    ++  **
    ++  ** Proof by comparison to the implementation of sqlite3_prepare_v2()
    ++  ** directly above. */
    ++  rc = sqlite3LockAndPrepare(db,zSql,nBytes,
    ++                 SQLITE_PREPARE_SAVESQL|(prepFlags&SQLITE_PREPARE_MASK),
    ++                 0,ppStmt,pzTail);
    ++  assert( rc==SQLITE_OK || ppStmt==0 || *ppStmt==0 );
    +   return rc;
    + }
    + 
    +@@ -108552,7 +118586,7 @@ static int sqlite3Prepare16(
    +   sqlite3 *db,              /* Database handle. */ 
    +   const void *zSql,         /* UTF-16 encoded SQL statement. */
    +   int nBytes,               /* Length of zSql in bytes. */
    +-  int saveSqlFlag,          /* True to save SQL text into the sqlite3_stmt */
    ++  u32 prepFlags,            /* Zero or more SQLITE_PREPARE_* flags */
    +   sqlite3_stmt **ppStmt,    /* OUT: A pointer to the prepared statement */
    +   const void **pzTail       /* OUT: End of parsed string */
    + ){
    +@@ -108580,7 +118614,7 @@ static int sqlite3Prepare16(
    +   sqlite3_mutex_enter(db->mutex);
    +   zSql8 = sqlite3Utf16to8(db, zSql, nBytes, SQLITE_UTF16NATIVE);
    +   if( zSql8 ){
    +-    rc = sqlite3LockAndPrepare(db, zSql8, -1, saveSqlFlag, 0, ppStmt, &zTail8);
    ++    rc = sqlite3LockAndPrepare(db, zSql8, -1, prepFlags, 0, ppStmt, &zTail8);
    +   }
    + 
    +   if( zTail8 && pzTail ){
    +@@ -108606,7 +118640,7 @@ static int sqlite3Prepare16(
    + ** and the statement is automatically recompiled if an schema change
    + ** occurs.
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_prepare16(
    ++SQLITE_API int sqlite3_prepare16(
    +   sqlite3 *db,              /* Database handle. */ 
    +   const void *zSql,         /* UTF-16 encoded SQL statement. */
    +   int nBytes,               /* Length of zSql in bytes. */
    +@@ -108618,7 +118652,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_prepare16(
    +   assert( rc==SQLITE_OK || ppStmt==0 || *ppStmt==0 );  /* VERIFY: F13021 */
    +   return rc;
    + }
    +-SQLITE_API int SQLITE_STDCALL sqlite3_prepare16_v2(
    ++SQLITE_API int sqlite3_prepare16_v2(
    +   sqlite3 *db,              /* Database handle. */ 
    +   const void *zSql,         /* UTF-16 encoded SQL statement. */
    +   int nBytes,               /* Length of zSql in bytes. */
    +@@ -108626,7 +118660,22 @@ SQLITE_API int SQLITE_STDCALL sqlite3_prepare16_v2(
    +   const void **pzTail       /* OUT: End of parsed string */
    + ){
    +   int rc;
    +-  rc = sqlite3Prepare16(db,zSql,nBytes,1,ppStmt,pzTail);
    ++  rc = sqlite3Prepare16(db,zSql,nBytes,SQLITE_PREPARE_SAVESQL,ppStmt,pzTail);
    ++  assert( rc==SQLITE_OK || ppStmt==0 || *ppStmt==0 );  /* VERIFY: F13021 */
    ++  return rc;
    ++}
    ++SQLITE_API int sqlite3_prepare16_v3(
    ++  sqlite3 *db,              /* Database handle. */ 
    ++  const void *zSql,         /* UTF-16 encoded SQL statement. */
    ++  int nBytes,               /* Length of zSql in bytes. */
    ++  unsigned int prepFlags,   /* Zero or more SQLITE_PREPARE_* flags */
    ++  sqlite3_stmt **ppStmt,    /* OUT: A pointer to the prepared statement */
    ++  const void **pzTail       /* OUT: End of parsed string */
    ++){
    ++  int rc;
    ++  rc = sqlite3Prepare16(db,zSql,nBytes,
    ++         SQLITE_PREPARE_SAVESQL|(prepFlags&SQLITE_PREPARE_MASK),
    ++         ppStmt,pzTail);
    +   assert( rc==SQLITE_OK || ppStmt==0 || *ppStmt==0 );  /* VERIFY: F13021 */
    +   return rc;
    + }
    +@@ -108691,7 +118740,9 @@ struct SortCtx {
    +   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 */
    ++  int labelDone;        /* Jump here when done, ex: LIMIT reached */
    +   u8 sortFlags;         /* Zero or more SORTFLAG_* bits */
    ++  u8 bOrderedInnerLoop; /* ORDER BY correctly sorts the inner loop */
    + };
    + #define SORTFLAG_UseSorter  0x01   /* Use SorterOpen instead of OpenEphemeral */
    + 
    +@@ -108709,9 +118760,8 @@ static void clearSelect(sqlite3 *db, Select *p, int bFree){
    +     sqlite3ExprDelete(db, p->pHaving);
    +     sqlite3ExprListDelete(db, p->pOrderBy);
    +     sqlite3ExprDelete(db, p->pLimit);
    +-    sqlite3ExprDelete(db, p->pOffset);
    +-    sqlite3WithDelete(db, p->pWith);
    +-    if( bFree ) sqlite3DbFree(db, p);
    ++    if( OK_IF_ALWAYS_TRUE(p->pWith) ) sqlite3WithDelete(db, p->pWith);
    ++    if( bFree ) sqlite3DbFreeNN(db, p);
    +     p = pPrior;
    +     bFree = 1;
    +   }
    +@@ -108723,7 +118773,7 @@ static void clearSelect(sqlite3 *db, Select *p, int bFree){
    + SQLITE_PRIVATE void sqlite3SelectDestInit(SelectDest *pDest, int eDest, int iParm){
    +   pDest->eDest = (u8)eDest;
    +   pDest->iSDParm = iParm;
    +-  pDest->affSdst = 0;
    ++  pDest->zAffSdst = 0;
    +   pDest->iSdst = 0;
    +   pDest->nSdst = 0;
    + }
    +@@ -108741,38 +118791,43 @@ SQLITE_PRIVATE Select *sqlite3SelectNew(
    +   ExprList *pGroupBy,   /* the GROUP BY clause */
    +   Expr *pHaving,        /* the HAVING clause */
    +   ExprList *pOrderBy,   /* the ORDER BY clause */
    +-  u16 selFlags,         /* Flag parameters, such as SF_Distinct */
    +-  Expr *pLimit,         /* LIMIT value.  NULL means not used */
    +-  Expr *pOffset         /* OFFSET value.  NULL means no offset */
    ++  u32 selFlags,         /* Flag parameters, such as SF_Distinct */
    ++  Expr *pLimit          /* LIMIT value.  NULL means not used */
    + ){
    +   Select *pNew;
    +   Select standin;
    +-  sqlite3 *db = pParse->db;
    +-  pNew = sqlite3DbMallocZero(db, sizeof(*pNew) );
    ++  pNew = sqlite3DbMallocRawNN(pParse->db, sizeof(*pNew) );
    +   if( pNew==0 ){
    +-    assert( db->mallocFailed );
    ++    assert( pParse->db->mallocFailed );
    +     pNew = &standin;
    +-    memset(pNew, 0, sizeof(*pNew));
    +   }
    +   if( pEList==0 ){
    +-    pEList = sqlite3ExprListAppend(pParse, 0, sqlite3Expr(db,TK_ALL,0));
    ++    pEList = sqlite3ExprListAppend(pParse, 0,
    ++                                   sqlite3Expr(pParse->db,TK_ASTERISK,0));
    +   }
    +   pNew->pEList = pEList;
    +-  if( pSrc==0 ) pSrc = sqlite3DbMallocZero(db, sizeof(*pSrc));
    ++  pNew->op = TK_SELECT;
    ++  pNew->selFlags = selFlags;
    ++  pNew->iLimit = 0;
    ++  pNew->iOffset = 0;
    ++#if SELECTTRACE_ENABLED
    ++  pNew->zSelName[0] = 0;
    ++#endif
    ++  pNew->addrOpenEphm[0] = -1;
    ++  pNew->addrOpenEphm[1] = -1;
    ++  pNew->nSelectRow = 0;
    ++  if( pSrc==0 ) pSrc = sqlite3DbMallocZero(pParse->db, sizeof(*pSrc));
    +   pNew->pSrc = pSrc;
    +   pNew->pWhere = pWhere;
    +   pNew->pGroupBy = pGroupBy;
    +   pNew->pHaving = pHaving;
    +   pNew->pOrderBy = pOrderBy;
    +-  pNew->selFlags = selFlags;
    +-  pNew->op = TK_SELECT;
    ++  pNew->pPrior = 0;
    ++  pNew->pNext = 0;
    +   pNew->pLimit = pLimit;
    +-  pNew->pOffset = pOffset;
    +-  assert( pOffset==0 || pLimit!=0 || pParse->nErr>0 || db->mallocFailed!=0 );
    +-  pNew->addrOpenEphm[0] = -1;
    +-  pNew->addrOpenEphm[1] = -1;
    +-  if( db->mallocFailed ) {
    +-    clearSelect(db, pNew, pNew!=&standin);
    ++  pNew->pWith = 0;
    ++  if( pParse->db->mallocFailed ) {
    ++    clearSelect(pParse->db, pNew, pNew!=&standin);
    +     pNew = 0;
    +   }else{
    +     assert( pNew->pSrc!=0 || pParse->nErr>0 );
    +@@ -108797,7 +118852,7 @@ SQLITE_PRIVATE void sqlite3SelectSetName(Select *p, const char *zName){
    + ** Delete the given Select structure and all of its substructures.
    + */
    + SQLITE_PRIVATE void sqlite3SelectDelete(sqlite3 *db, Select *p){
    +-  clearSelect(db, p, 1);
    ++  if( OK_IF_ALWAYS_TRUE(p) ) clearSelect(db, p, 1);
    + }
    + 
    + /*
    +@@ -108961,7 +119016,7 @@ static void addWhereTerm(
    +   pE1 = sqlite3CreateColumnExpr(db, pSrc, iLeft, iColLeft);
    +   pE2 = sqlite3CreateColumnExpr(db, pSrc, iRight, iColRight);
    + 
    +-  pEq = sqlite3PExpr(pParse, TK_EQ, pE1, pE2, 0);
    ++  pEq = sqlite3PExpr(pParse, TK_EQ, pE1, pE2);
    +   if( pEq && isOuterJoin ){
    +     ExprSetProperty(pEq, EP_FromJoin);
    +     assert( !ExprHasProperty(pEq, EP_TokenOnly|EP_Reduced) );
    +@@ -109038,11 +119093,10 @@ static int sqliteProcessJoin(Parse *pParse, Select *p){
    +   pLeft = &pSrc->a[0];
    +   pRight = &pLeft[1];
    +   for(i=0; i<pSrc->nSrc-1; i++, pRight++, pLeft++){
    +-    Table *pLeftTab = pLeft->pTab;
    +     Table *pRightTab = pRight->pTab;
    +     int isOuter;
    + 
    +-    if( NEVER(pLeftTab==0 || pRightTab==0) ) continue;
    ++    if( NEVER(pLeft->pTab==0 || pRightTab==0) ) continue;
    +     isOuter = (pRight->fg.jointype & JT_OUTER)!=0;
    + 
    +     /* When the NATURAL keyword is present, add WHERE clause terms for
    +@@ -109145,9 +119199,10 @@ static void pushOntoSorter(
    +   int regRecord = ++pParse->nMem;                  /* Assembled sorter record */
    +   int nOBSat = pSort->nOBSat;                      /* ORDER BY terms to skip */
    +   int op;                            /* Opcode to add sorter record to sorter */
    ++  int iLimit;                        /* LIMIT counter */
    + 
    +   assert( bSeq==0 || bSeq==1 );
    +-  assert( nData==1 || regData==regOrigData );
    ++  assert( nData==1 || regData==regOrigData || regOrigData==0 );
    +   if( nPrefixReg ){
    +     assert( nPrefixReg==nExpr+bSeq );
    +     regBase = regData - nExpr - bSeq;
    +@@ -109155,15 +119210,17 @@ static void pushOntoSorter(
    +     regBase = pParse->nMem + 1;
    +     pParse->nMem += nBase;
    +   }
    ++  assert( pSelect->iOffset==0 || pSelect->iLimit!=0 );
    ++  iLimit = pSelect->iOffset ? pSelect->iOffset+1 : pSelect->iLimit;
    ++  pSort->labelDone = sqlite3VdbeMakeLabel(v);
    +   sqlite3ExprCodeExprList(pParse, pSort->pOrderBy, regBase, regOrigData,
    +-                          SQLITE_ECEL_DUP|SQLITE_ECEL_REF);
    ++                          SQLITE_ECEL_DUP | (regOrigData? SQLITE_ECEL_REF : 0));
    +   if( bSeq ){
    +     sqlite3VdbeAddOp2(v, OP_Sequence, pSort->iECursor, regBase+nExpr);
    +   }
    +-  if( nPrefixReg==0 ){
    ++  if( nPrefixReg==0 && nData>0 ){
    +     sqlite3ExprCodeMove(pParse, regData, regBase+nExpr+bSeq, nData);
    +   }
    +-
    +   sqlite3VdbeAddOp3(v, OP_MakeRecord, regBase+nOBSat, nBase-nOBSat, regRecord);
    +   if( nOBSat>0 ){
    +     int regPrevKey;   /* The first nOBSat columns of the previous row */
    +@@ -109187,17 +119244,21 @@ static void pushOntoSorter(
    +     if( pParse->db->mallocFailed ) return;
    +     pOp->p2 = nKey + nData;
    +     pKI = pOp->p4.pKeyInfo;
    +-    memset(pKI->aSortOrder, 0, pKI->nField); /* Makes OP_Jump below testable */
    ++    memset(pKI->aSortOrder, 0, pKI->nKeyField); /* Makes OP_Jump testable */
    +     sqlite3VdbeChangeP4(v, -1, (char*)pKI, P4_KEYINFO);
    +-    testcase( pKI->nXField>2 );
    ++    testcase( pKI->nAllField > pKI->nKeyField+2 );
    +     pOp->p4.pKeyInfo = keyInfoFromExprList(pParse, pSort->pOrderBy, nOBSat,
    +-                                           pKI->nXField-1);
    ++                                           pKI->nAllField-pKI->nKeyField-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);
    ++    if( iLimit ){
    ++      sqlite3VdbeAddOp2(v, OP_IfNot, iLimit, pSort->labelDone);
    ++      VdbeCoverage(v);
    ++    }
    +     sqlite3VdbeJumpHere(v, addrFirst);
    +     sqlite3ExprCodeMove(pParse, regBase, regPrevKey, pSort->nOBSat);
    +     sqlite3VdbeJumpHere(v, addrJmp);
    +@@ -109207,18 +119268,34 @@ static void pushOntoSorter(
    +   }else{
    +     op = OP_IdxInsert;
    +   }
    +-  sqlite3VdbeAddOp2(v, op, pSort->iECursor, regRecord);
    +-  if( pSelect->iLimit ){
    ++  sqlite3VdbeAddOp4Int(v, op, pSort->iECursor, regRecord,
    ++                       regBase+nOBSat, nBase-nOBSat);
    ++  if( iLimit ){
    +     int addr;
    +-    int iLimit;
    +-    if( pSelect->iOffset ){
    +-      iLimit = pSelect->iOffset+1;
    +-    }else{
    +-      iLimit = pSelect->iLimit;
    +-    }
    +-    addr = sqlite3VdbeAddOp3(v, OP_IfNotZero, iLimit, 0, 1); VdbeCoverage(v);
    ++    int r1 = 0;
    ++    /* Fill the sorter until it contains LIMIT+OFFSET entries.  (The iLimit
    ++    ** register is initialized with value of LIMIT+OFFSET.)  After the sorter
    ++    ** fills up, delete the least entry in the sorter after each insert.
    ++    ** Thus we never hold more than the LIMIT+OFFSET rows in memory at once */
    ++    addr = sqlite3VdbeAddOp1(v, OP_IfNotZero, iLimit); VdbeCoverage(v);
    +     sqlite3VdbeAddOp1(v, OP_Last, pSort->iECursor);
    ++    if( pSort->bOrderedInnerLoop ){
    ++      r1 = ++pParse->nMem;
    ++      sqlite3VdbeAddOp3(v, OP_Column, pSort->iECursor, nExpr, r1);
    ++      VdbeComment((v, "seq"));
    ++    }
    +     sqlite3VdbeAddOp1(v, OP_Delete, pSort->iECursor);
    ++    if( pSort->bOrderedInnerLoop ){
    ++      /* If the inner loop is driven by an index such that values from
    ++      ** the same iteration of the inner loop are in sorted order, then
    ++      ** immediately jump to the next iteration of an inner loop if the
    ++      ** entry from the current iteration does not fit into the top
    ++      ** LIMIT+OFFSET entries of the sorter. */
    ++      int iBrk = sqlite3VdbeCurrentAddr(v) + 2;
    ++      sqlite3VdbeAddOp3(v, OP_Eq, regBase+nExpr, iBrk, r1);
    ++      sqlite3VdbeChangeP5(v, SQLITE_NULLEQ);
    ++      VdbeCoverage(v);
    ++    }
    +     sqlite3VdbeJumpHere(v, addr);
    +   }
    + }
    +@@ -109260,48 +119337,24 @@ static void codeDistinct(
    +   r1 = sqlite3GetTempReg(pParse);
    +   sqlite3VdbeAddOp4Int(v, OP_Found, iTab, addrRepeat, iMem, N); VdbeCoverage(v);
    +   sqlite3VdbeAddOp3(v, OP_MakeRecord, iMem, N, r1);
    +-  sqlite3VdbeAddOp2(v, OP_IdxInsert, iTab, r1);
    ++  sqlite3VdbeAddOp4Int(v, OP_IdxInsert, iTab, r1, iMem, N);
    ++  sqlite3VdbeChangeP5(v, OPFLAG_USESEEKRESULT);
    +   sqlite3ReleaseTempReg(pParse, r1);
    + }
    + 
    +-#ifndef SQLITE_OMIT_SUBQUERY
    +-/*
    +-** Generate an error message when a SELECT is used within a subexpression
    +-** (example:  "a IN (SELECT * FROM table)") but it has more than 1 result
    +-** column.  We do this in a subroutine because the error used to occur
    +-** in multiple places.  (The error only occurs in one place now, but we
    +-** retain the subroutine to minimize code disruption.)
    +-*/
    +-static int checkForMultiColumnSelectError(
    +-  Parse *pParse,       /* Parse context. */
    +-  SelectDest *pDest,   /* Destination of SELECT results */
    +-  int nExpr            /* Number of result columns returned by SELECT */
    +-){
    +-  int eDest = pDest->eDest;
    +-  if( nExpr>1 && (eDest==SRT_Mem || eDest==SRT_Set) ){
    +-    sqlite3ErrorMsg(pParse, "only a single result allowed for "
    +-       "a SELECT that is part of an expression");
    +-    return 1;
    +-  }else{
    +-    return 0;
    +-  }
    +-}
    +-#endif
    +-
    + /*
    + ** This routine generates the code for the inside of the inner loop
    + ** of a SELECT.
    + **
    +-** If srcTab is negative, then the pEList expressions
    ++** If srcTab is negative, then the p->pEList expressions
    + ** are evaluated in order to get the data for this row.  If srcTab is
    +-** zero or more, then data is pulled from srcTab and pEList is used only 
    +-** to get number columns and the datatype for each column.
    ++** zero or more, then data is pulled from srcTab and p->pEList is used only 
    ++** to get the number of columns and the collation sequence for each column.
    + */
    + static void selectInnerLoop(
    +   Parse *pParse,          /* The parser context */
    +   Select *p,              /* The complete select statement being coded */
    +-  ExprList *pEList,       /* List of values being extracted */
    +-  int srcTab,             /* Pull data from this table */
    ++  int srcTab,             /* Pull data from this table if non-negative */
    +   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 */
    +@@ -109310,15 +119363,22 @@ static void selectInnerLoop(
    + ){
    +   Vdbe *v = pParse->pVdbe;
    +   int i;
    +-  int hasDistinct;        /* True if the DISTINCT keyword is present */
    +-  int regResult;              /* Start of memory holding result set */
    ++  int hasDistinct;            /* True if the DISTINCT keyword is present */
    +   int eDest = pDest->eDest;   /* How to dispose of results */
    +   int iParm = pDest->iSDParm; /* First argument to disposal method */
    +   int nResultCol;             /* Number of result columns */
    +   int nPrefixReg = 0;         /* Number of extra registers before regResult */
    + 
    ++  /* Usually, regResult is the first cell in an array of memory cells
    ++  ** containing the current result row. In this case regOrig is set to the
    ++  ** same value. However, if the results are being sent to the sorter, the
    ++  ** values for any expressions that are also part of the sort-key are omitted
    ++  ** from this array. In this case regOrig is set to zero.  */
    ++  int regResult;              /* Start of memory holding current results */
    ++  int regOrig;                /* Start of memory holding full result (or 0) */
    ++
    +   assert( v );
    +-  assert( pEList!=0 );
    ++  assert( p->pEList!=0 );
    +   hasDistinct = pDistinct ? pDistinct->eTnctType : WHERE_DISTINCT_NOOP;
    +   if( pSort && pSort->pOrderBy==0 ) pSort = 0;
    +   if( pSort==0 && !hasDistinct ){
    +@@ -109328,7 +119388,7 @@ static void selectInnerLoop(
    + 
    +   /* Pull the requested columns.
    +   */
    +-  nResultCol = pEList->nExpr;
    ++  nResultCol = p->pEList->nExpr;
    + 
    +   if( pDest->iSdst==0 ){
    +     if( pSort ){
    +@@ -109347,11 +119407,11 @@ static void selectInnerLoop(
    +     pParse->nMem += nResultCol;
    +   }
    +   pDest->nSdst = nResultCol;
    +-  regResult = pDest->iSdst;
    ++  regOrig = regResult = pDest->iSdst;
    +   if( srcTab>=0 ){
    +     for(i=0; i<nResultCol; i++){
    +       sqlite3VdbeAddOp3(v, OP_Column, srcTab, i, regResult+i);
    +-      VdbeComment((v, "%s", pEList->a[i].zName));
    ++      VdbeComment((v, "%s", p->pEList->a[i].zName));
    +     }
    +   }else if( eDest!=SRT_Exists ){
    +     /* If the destination is an EXISTS(...) expression, the actual
    +@@ -109363,7 +119423,26 @@ static void selectInnerLoop(
    +     }else{
    +       ecelFlags = 0;
    +     }
    +-    sqlite3ExprCodeExprList(pParse, pEList, regResult, 0, ecelFlags);
    ++    if( pSort && hasDistinct==0 && eDest!=SRT_EphemTab && eDest!=SRT_Table ){
    ++      /* For each expression in p->pEList that is a copy of an expression in
    ++      ** the ORDER BY clause (pSort->pOrderBy), set the associated 
    ++      ** iOrderByCol value to one more than the index of the ORDER BY 
    ++      ** expression within the sort-key that pushOntoSorter() will generate.
    ++      ** This allows the p->pEList field to be omitted from the sorted record,
    ++      ** saving space and CPU cycles.  */
    ++      ecelFlags |= (SQLITE_ECEL_OMITREF|SQLITE_ECEL_REF);
    ++      for(i=pSort->nOBSat; i<pSort->pOrderBy->nExpr; i++){
    ++        int j;
    ++        if( (j = pSort->pOrderBy->a[i].u.x.iOrderByCol)>0 ){
    ++          p->pEList->a[j-1].u.x.iOrderByCol = i+1-pSort->nOBSat;
    ++        }
    ++      }
    ++      regOrig = 0;
    ++      assert( eDest==SRT_Set || eDest==SRT_Mem 
    ++           || eDest==SRT_Coroutine || eDest==SRT_Output );
    ++    }
    ++    nResultCol = sqlite3ExprCodeExprList(pParse,p->pEList,regResult,
    ++                                         0,ecelFlags);
    +   }
    + 
    +   /* If the DISTINCT keyword was present on the SELECT statement
    +@@ -109395,7 +119474,7 @@ static void selectInnerLoop(
    + 
    +         iJump = sqlite3VdbeCurrentAddr(v) + nResultCol;
    +         for(i=0; i<nResultCol; i++){
    +-          CollSeq *pColl = sqlite3ExprCollSeq(pParse, pEList->a[i].pExpr);
    ++          CollSeq *pColl = sqlite3ExprCollSeq(pParse, p->pEList->a[i].pExpr);
    +           if( i<nResultCol-1 ){
    +             sqlite3VdbeAddOp3(v, OP_Ne, regResult+i, iJump, regPrev+i);
    +             VdbeCoverage(v);
    +@@ -109437,7 +119516,7 @@ static void selectInnerLoop(
    +       int r1;
    +       r1 = sqlite3GetTempReg(pParse);
    +       sqlite3VdbeAddOp3(v, OP_MakeRecord, regResult, nResultCol, r1);
    +-      sqlite3VdbeAddOp2(v, OP_IdxInsert, iParm, r1);
    ++      sqlite3VdbeAddOp4Int(v, OP_IdxInsert, iParm, r1, regResult, nResultCol);
    +       sqlite3ReleaseTempReg(pParse, r1);
    +       break;
    +     }
    +@@ -109474,7 +119553,7 @@ 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);
    ++        sqlite3VdbeAddOp4Int(v, OP_IdxInsert, iParm+1, r1,regResult,nResultCol);
    +         assert( pSort==0 );
    +       }
    + #endif
    +@@ -109497,20 +119576,20 @@ static void selectInnerLoop(
    +     ** item into the set table with bogus data.
    +     */
    +     case SRT_Set: {
    +-      assert( nResultCol==1 );
    +-      pDest->affSdst =
    +-                  sqlite3CompareAffinity(pEList->a[0].pExpr, pDest->affSdst);
    +       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, pSort, p, regResult, regResult, 1, nPrefixReg);
    ++        pushOntoSorter(
    ++            pParse, pSort, p, regResult, regOrig, nResultCol, nPrefixReg);
    +       }else{
    +         int r1 = sqlite3GetTempReg(pParse);
    +-        sqlite3VdbeAddOp4(v, OP_MakeRecord, regResult,1,r1, &pDest->affSdst, 1);
    +-        sqlite3ExprCacheAffinityChange(pParse, regResult, 1);
    +-        sqlite3VdbeAddOp2(v, OP_IdxInsert, iParm, r1);
    ++        assert( sqlite3Strlen30(pDest->zAffSdst)==nResultCol );
    ++        sqlite3VdbeAddOp4(v, OP_MakeRecord, regResult, nResultCol, 
    ++            r1, pDest->zAffSdst, nResultCol);
    ++        sqlite3ExprCacheAffinityChange(pParse, regResult, nResultCol);
    ++        sqlite3VdbeAddOp4Int(v, OP_IdxInsert, iParm, r1, regResult, nResultCol);
    +         sqlite3ReleaseTempReg(pParse, r1);
    +       }
    +       break;
    +@@ -109525,14 +119604,16 @@ static void selectInnerLoop(
    +     }
    + 
    +     /* If this is a scalar select that is part of an expression, then
    +-    ** store the results in the appropriate memory cell and break out
    +-    ** of the scan loop.
    ++    ** store the results in the appropriate memory cell or array of 
    ++    ** memory cells and break out of the scan loop.
    +     */
    +     case SRT_Mem: {
    +-      assert( nResultCol==1 );
    +       if( pSort ){
    +-        pushOntoSorter(pParse, pSort, p, regResult, regResult, 1, nPrefixReg);
    ++        assert( nResultCol<=pDest->nSdst );
    ++        pushOntoSorter(
    ++            pParse, pSort, p, regResult, regOrig, nResultCol, nPrefixReg);
    +       }else{
    ++        assert( nResultCol==pDest->nSdst );
    +         assert( regResult==iParm );
    +         /* The LIMIT clause will jump out of the loop for us */
    +       }
    +@@ -109545,7 +119626,7 @@ static void selectInnerLoop(
    +       testcase( eDest==SRT_Coroutine );
    +       testcase( eDest==SRT_Output );
    +       if( pSort ){
    +-        pushOntoSorter(pParse, pSort, p, regResult, regResult, nResultCol,
    ++        pushOntoSorter(pParse, pSort, p, regResult, regOrig, nResultCol,
    +                        nPrefixReg);
    +       }else if( eDest==SRT_Coroutine ){
    +         sqlite3VdbeAddOp1(v, OP_Yield, pDest->iSDParm);
    +@@ -109595,7 +119676,7 @@ static void selectInnerLoop(
    +       }
    +       sqlite3VdbeAddOp2(v, OP_Sequence, iParm, r2+nKey);
    +       sqlite3VdbeAddOp3(v, OP_MakeRecord, r2, nKey+2, r1);
    +-      sqlite3VdbeAddOp2(v, OP_IdxInsert, iParm, r1);
    ++      sqlite3VdbeAddOp4Int(v, OP_IdxInsert, iParm, r1, r2, nKey+2);
    +       if( addrTest ) sqlite3VdbeJumpHere(v, addrTest);
    +       sqlite3ReleaseTempReg(pParse, r1);
    +       sqlite3ReleaseTempRange(pParse, r2, nKey+2);
    +@@ -109632,17 +119713,18 @@ static void selectInnerLoop(
    + ** X extra columns.
    + */
    + SQLITE_PRIVATE KeyInfo *sqlite3KeyInfoAlloc(sqlite3 *db, int N, int X){
    +-  KeyInfo *p = sqlite3DbMallocZero(0, 
    +-                   sizeof(KeyInfo) + (N+X)*(sizeof(CollSeq*)+1));
    ++  int nExtra = (N+X)*(sizeof(CollSeq*)+1) - sizeof(CollSeq*);
    ++  KeyInfo *p = sqlite3DbMallocRawNN(db, sizeof(KeyInfo) + nExtra);
    +   if( p ){
    +     p->aSortOrder = (u8*)&p->aColl[N+X];
    +-    p->nField = (u16)N;
    +-    p->nXField = (u16)X;
    ++    p->nKeyField = (u16)N;
    ++    p->nAllField = (u16)(N+X);
    +     p->enc = ENC(db);
    +     p->db = db;
    +     p->nRef = 1;
    ++    memset(&p[1], 0, nExtra);
    +   }else{
    +-    db->mallocFailed = 1;
    ++    sqlite3OomFault(db);
    +   }
    +   return p;
    + }
    +@@ -109654,7 +119736,7 @@ SQLITE_PRIVATE void sqlite3KeyInfoUnref(KeyInfo *p){
    +   if( p ){
    +     assert( p->nRef>0 );
    +     p->nRef--;
    +-    if( p->nRef==0 ) sqlite3DbFree(0, p);
    ++    if( p->nRef==0 ) sqlite3DbFreeNN(p->db, p);
    +   }
    + }
    + 
    +@@ -109710,10 +119792,7 @@ static KeyInfo *keyInfoFromExprList(
    +   if( pInfo ){
    +     assert( sqlite3KeyInfoIsWriteable(pInfo) );
    +     for(i=iStart, pItem=pList->a+iStart; i<nExpr; i++, pItem++){
    +-      CollSeq *pColl;
    +-      pColl = sqlite3ExprCollSeq(pParse, pItem->pExpr);
    +-      if( !pColl ) pColl = db->pDfltColl;
    +-      pInfo->aColl[i-iStart] = pColl;
    ++      pInfo->aColl[i-iStart] = sqlite3ExprNNCollSeq(pParse, pItem->pExpr);
    +       pInfo->aSortOrder[i-iStart] = pItem->sortOrder;
    +     }
    +   }
    +@@ -109819,7 +119898,7 @@ static void generateSortTail(
    +   SelectDest *pDest /* Write the sorted results here */
    + ){
    +   Vdbe *v = pParse->pVdbe;                     /* The prepared statement */
    +-  int addrBreak = sqlite3VdbeMakeLabel(v);     /* Jump here to exit loop */
    ++  int addrBreak = pSort->labelDone;            /* Jump here to exit loop */
    +   int addrContinue = sqlite3VdbeMakeLabel(v);  /* Jump here for next cycle */
    +   int addr;
    +   int addrOnce = 0;
    +@@ -109829,36 +119908,36 @@ static void generateSortTail(
    +   int iParm = pDest->iSDParm;
    +   int regRow;
    +   int regRowid;
    ++  int iCol;
    +   int nKey;
    +   int iSortTab;                   /* Sorter cursor to read from */
    +   int nSortData;                  /* Trailing values to read from sorter */
    +   int i;
    +   int bSeq;                       /* True if sorter record includes seq. no. */
    +-#ifdef SQLITE_ENABLE_EXPLAIN_COMMENTS
    +   struct ExprList_item *aOutEx = p->pEList->a;
    +-#endif
    + 
    ++  assert( addrBreak<0 );
    +   if( pSort->labelBkOut ){
    +     sqlite3VdbeAddOp2(v, OP_Gosub, pSort->regReturn, pSort->labelBkOut);
    +     sqlite3VdbeGoto(v, addrBreak);
    +     sqlite3VdbeResolveLabel(v, pSort->labelBkOut);
    +   }
    +   iTab = pSort->iECursor;
    +-  if( eDest==SRT_Output || eDest==SRT_Coroutine ){
    ++  if( eDest==SRT_Output || eDest==SRT_Coroutine || eDest==SRT_Mem ){
    +     regRowid = 0;
    +     regRow = pDest->iSdst;
    +     nSortData = nColumn;
    +   }else{
    +     regRowid = sqlite3GetTempReg(pParse);
    +-    regRow = sqlite3GetTempReg(pParse);
    +-    nSortData = 1;
    ++    regRow = sqlite3GetTempRange(pParse, nColumn);
    ++    nSortData = nColumn;
    +   }
    +   nKey = pOrderBy->nExpr - pSort->nOBSat;
    +   if( pSort->sortFlags & SORTFLAG_UseSorter ){
    +     int regSortOut = ++pParse->nMem;
    +     iSortTab = pParse->nTab++;
    +     if( pSort->labelBkOut ){
    +-      addrOnce = sqlite3CodeOnce(pParse); VdbeCoverage(v);
    ++      addrOnce = sqlite3VdbeAddOp0(v, OP_Once); VdbeCoverage(v);
    +     }
    +     sqlite3VdbeAddOp3(v, OP_OpenPseudo, iSortTab, regSortOut, nKey+1+nSortData);
    +     if( addrOnce ) sqlite3VdbeJumpHere(v, addrOnce);
    +@@ -109873,11 +119952,18 @@ static void generateSortTail(
    +     iSortTab = iTab;
    +     bSeq = 1;
    +   }
    +-  for(i=0; i<nSortData; i++){
    +-    sqlite3VdbeAddOp3(v, OP_Column, iSortTab, nKey+bSeq+i, regRow+i);
    ++  for(i=0, iCol=nKey+bSeq; i<nSortData; i++){
    ++    int iRead;
    ++    if( aOutEx[i].u.x.iOrderByCol ){
    ++      iRead = aOutEx[i].u.x.iOrderByCol-1;
    ++    }else{
    ++      iRead = iCol++;
    ++    }
    ++    sqlite3VdbeAddOp3(v, OP_Column, iSortTab, iRead, regRow+i);
    +     VdbeComment((v, "%s", aOutEx[i].zName ? aOutEx[i].zName : aOutEx[i].zSpan));
    +   }
    +   switch( eDest ){
    ++    case SRT_Table:
    +     case SRT_EphemTab: {
    +       sqlite3VdbeAddOp2(v, OP_NewRowid, iParm, regRowid);
    +       sqlite3VdbeAddOp3(v, OP_Insert, iParm, regRow, regRowid);
    +@@ -109886,16 +119972,14 @@ static void generateSortTail(
    +     }
    + #ifndef SQLITE_OMIT_SUBQUERY
    +     case SRT_Set: {
    +-      assert( nColumn==1 );
    +-      sqlite3VdbeAddOp4(v, OP_MakeRecord, regRow, 1, regRowid,
    +-                        &pDest->affSdst, 1);
    +-      sqlite3ExprCacheAffinityChange(pParse, regRow, 1);
    +-      sqlite3VdbeAddOp2(v, OP_IdxInsert, iParm, regRowid);
    ++      assert( nColumn==sqlite3Strlen30(pDest->zAffSdst) );
    ++      sqlite3VdbeAddOp4(v, OP_MakeRecord, regRow, nColumn, regRowid,
    ++                        pDest->zAffSdst, nColumn);
    ++      sqlite3ExprCacheAffinityChange(pParse, regRow, nColumn);
    ++      sqlite3VdbeAddOp4Int(v, OP_IdxInsert, iParm, regRowid, regRow, nColumn);
    +       break;
    +     }
    +     case SRT_Mem: {
    +-      assert( nColumn==1 );
    +-      sqlite3ExprCodeMove(pParse, regRow, iParm, 1);
    +       /* The LIMIT clause will terminate the loop for us */
    +       break;
    +     }
    +@@ -109914,7 +119998,11 @@ static void generateSortTail(
    +     }
    +   }
    +   if( regRowid ){
    +-    sqlite3ReleaseTempReg(pParse, regRow);
    ++    if( eDest==SRT_Set ){
    ++      sqlite3ReleaseTempRange(pParse, regRow, nColumn);
    ++    }else{
    ++      sqlite3ReleaseTempReg(pParse, regRow);
    ++    }
    +     sqlite3ReleaseTempReg(pParse, regRowid);
    +   }
    +   /* The bottom of the loop
    +@@ -109954,32 +120042,34 @@ static void generateSortTail(
    + ** the SQLITE_ENABLE_COLUMN_METADATA compile-time option is used.
    + */
    + #ifdef SQLITE_ENABLE_COLUMN_METADATA
    +-# define columnType(A,B,C,D,E,F) columnTypeImpl(A,B,C,D,E,F)
    ++# define columnType(A,B,C,D,E) columnTypeImpl(A,B,C,D,E)
    + #else /* if !defined(SQLITE_ENABLE_COLUMN_METADATA) */
    +-# define columnType(A,B,C,D,E,F) columnTypeImpl(A,B,F)
    ++# define columnType(A,B,C,D,E) columnTypeImpl(A,B)
    + #endif
    + static const char *columnTypeImpl(
    +   NameContext *pNC, 
    ++#ifndef SQLITE_ENABLE_COLUMN_METADATA
    ++  Expr *pExpr
    ++#else
    +   Expr *pExpr,
    +-#ifdef SQLITE_ENABLE_COLUMN_METADATA
    +   const char **pzOrigDb,
    +   const char **pzOrigTab,
    +-  const char **pzOrigCol,
    ++  const char **pzOrigCol
    + #endif
    +-  u8 *pEstWidth
    + ){
    +   char const *zType = 0;
    +   int j;
    +-  u8 estWidth = 1;
    + #ifdef SQLITE_ENABLE_COLUMN_METADATA
    +   char const *zOrigDb = 0;
    +   char const *zOrigTab = 0;
    +   char const *zOrigCol = 0;
    + #endif
    + 
    +-  if( NEVER(pExpr==0) || pNC->pSrcList==0 ) return 0;
    ++  assert( pExpr!=0 );
    ++  assert( pNC->pSrcList!=0 );
    ++  assert( pExpr->op!=TK_AGG_COLUMN );  /* This routine runes before aggregates
    ++                                       ** are processed */
    +   switch( pExpr->op ){
    +-    case TK_AGG_COLUMN:
    +     case TK_COLUMN: {
    +       /* The expression is a column. Locate the table the column is being
    +       ** extracted from in NameContext.pSrcList. This table may be real
    +@@ -109988,8 +120078,6 @@ static const char *columnTypeImpl(
    +       Table *pTab = 0;            /* Table structure column is extracted from */
    +       Select *pS = 0;             /* Select the column is extracted from */
    +       int iCol = pExpr->iColumn;  /* Index of column in pTab */
    +-      testcase( pExpr->op==TK_AGG_COLUMN );
    +-      testcase( pExpr->op==TK_COLUMN );
    +       while( pNC && !pTab ){
    +         SrcList *pTabList = pNC->pSrcList;
    +         for(j=0;j<pTabList->nSrc && pTabList->a[j].iCursor!=pExpr->iTable;j++);
    +@@ -110028,46 +120116,42 @@ static const char *columnTypeImpl(
    +         ** of the SELECT statement. Return the declaration type and origin
    +         ** data for the result-set column of the sub-select.
    +         */
    +-        if( iCol>=0 && ALWAYS(iCol<pS->pEList->nExpr) ){
    ++        if( iCol>=0 && iCol<pS->pEList->nExpr ){
    +           /* If iCol is less than zero, then the expression requests the
    +           ** rowid of the sub-select or view. This expression is legal (see 
    +           ** test case misc2.2.2) - it always evaluates to NULL.
    +-          **
    +-          ** The ALWAYS() is because iCol>=pS->pEList->nExpr will have been
    +-          ** caught already by name resolution.
    +           */
    +           NameContext sNC;
    +           Expr *p = pS->pEList->a[iCol].pExpr;
    +           sNC.pSrcList = pS->pSrc;
    +           sNC.pNext = pNC;
    +           sNC.pParse = pNC->pParse;
    +-          zType = columnType(&sNC, p,&zOrigDb,&zOrigTab,&zOrigCol, &estWidth); 
    ++          zType = columnType(&sNC, p,&zOrigDb,&zOrigTab,&zOrigCol); 
    +         }
    +-      }else if( pTab->pSchema ){
    +-        /* A real table */
    ++      }else{
    ++        /* A real table or a CTE table */
    +         assert( !pS );
    +-        if( iCol<0 ) iCol = pTab->iPKey;
    +-        assert( iCol==-1 || (iCol>=0 && iCol<pTab->nCol) );
    + #ifdef SQLITE_ENABLE_COLUMN_METADATA
    ++        if( iCol<0 ) iCol = pTab->iPKey;
    ++        assert( iCol==XN_ROWID || (iCol>=0 && iCol<pTab->nCol) );
    +         if( iCol<0 ){
    +           zType = "INTEGER";
    +           zOrigCol = "rowid";
    +         }else{
    +-          zType = pTab->aCol[iCol].zType;
    +           zOrigCol = pTab->aCol[iCol].zName;
    +-          estWidth = pTab->aCol[iCol].szEst;
    ++          zType = sqlite3ColumnType(&pTab->aCol[iCol],0);
    +         }
    +         zOrigTab = pTab->zName;
    +-        if( pNC->pParse ){
    ++        if( pNC->pParse && pTab->pSchema ){
    +           int iDb = sqlite3SchemaToIndex(pNC->pParse->db, pTab->pSchema);
    +-          zOrigDb = pNC->pParse->db->aDb[iDb].zName;
    ++          zOrigDb = pNC->pParse->db->aDb[iDb].zDbSName;
    +         }
    + #else
    ++        assert( iCol==XN_ROWID || (iCol>=0 && iCol<pTab->nCol) );
    +         if( iCol<0 ){
    +           zType = "INTEGER";
    +         }else{
    +-          zType = pTab->aCol[iCol].zType;
    +-          estWidth = pTab->aCol[iCol].szEst;
    ++          zType = sqlite3ColumnType(&pTab->aCol[iCol],0);
    +         }
    + #endif
    +       }
    +@@ -110086,7 +120170,7 @@ static const char *columnTypeImpl(
    +       sNC.pSrcList = pS->pSrc;
    +       sNC.pNext = pNC;
    +       sNC.pParse = pNC->pParse;
    +-      zType = columnType(&sNC, p, &zOrigDb, &zOrigTab, &zOrigCol, &estWidth); 
    ++      zType = columnType(&sNC, p, &zOrigDb, &zOrigTab, &zOrigCol); 
    +       break;
    +     }
    + #endif
    +@@ -110100,7 +120184,6 @@ static const char *columnTypeImpl(
    +     *pzOrigCol = zOrigCol;
    +   }
    + #endif
    +-  if( pEstWidth ) *pEstWidth = estWidth;
    +   return zType;
    + }
    + 
    +@@ -110119,6 +120202,7 @@ static void generateColumnTypes(
    +   NameContext sNC;
    +   sNC.pSrcList = pTabList;
    +   sNC.pParse = pParse;
    ++  sNC.pNext = 0;
    +   for(i=0; i<pEList->nExpr; i++){
    +     Expr *p = pEList->a[i].pExpr;
    +     const char *zType;
    +@@ -110126,7 +120210,7 @@ static void generateColumnTypes(
    +     const char *zOrigDb = 0;
    +     const char *zOrigTab = 0;
    +     const char *zOrigCol = 0;
    +-    zType = columnType(&sNC, p, &zOrigDb, &zOrigTab, &zOrigCol, 0);
    ++    zType = columnType(&sNC, p, &zOrigDb, &zOrigTab, &zOrigCol);
    + 
    +     /* The vdbe must make its own copy of the column-type and other 
    +     ** column specific strings, in case the schema is reset before this
    +@@ -110136,27 +120220,56 @@ static void generateColumnTypes(
    +     sqlite3VdbeSetColName(v, i, COLNAME_TABLE, zOrigTab, SQLITE_TRANSIENT);
    +     sqlite3VdbeSetColName(v, i, COLNAME_COLUMN, zOrigCol, SQLITE_TRANSIENT);
    + #else
    +-    zType = columnType(&sNC, p, 0, 0, 0, 0);
    ++    zType = columnType(&sNC, p, 0, 0, 0);
    + #endif
    +     sqlite3VdbeSetColName(v, i, COLNAME_DECLTYPE, zType, SQLITE_TRANSIENT);
    +   }
    + #endif /* !defined(SQLITE_OMIT_DECLTYPE) */
    + }
    + 
    ++
    + /*
    +-** Generate code that will tell the VDBE the names of columns
    +-** in the result set.  This information is used to provide the
    +-** azCol[] values in the callback.
    ++** Compute the column names for a SELECT statement.
    ++**
    ++** The only guarantee that SQLite makes about column names is that if the
    ++** column has an AS clause assigning it a name, that will be the name used.
    ++** That is the only documented guarantee.  However, countless applications
    ++** developed over the years have made baseless assumptions about column names
    ++** and will break if those assumptions changes.  Hence, use extreme caution
    ++** when modifying this routine to avoid breaking legacy.
    ++**
    ++** See Also: sqlite3ColumnsFromExprList()
    ++**
    ++** The PRAGMA short_column_names and PRAGMA full_column_names settings are
    ++** deprecated.  The default setting is short=ON, full=OFF.  99.9% of all
    ++** applications should operate this way.  Nevertheless, we need to support the
    ++** other modes for legacy:
    ++**
    ++**    short=OFF, full=OFF:      Column name is the text of the expression has it
    ++**                              originally appears in the SELECT statement.  In
    ++**                              other words, the zSpan of the result expression.
    ++**
    ++**    short=ON, full=OFF:       (This is the default setting).  If the result
    ++**                              refers directly to a table column, then the
    ++**                              result column name is just the table column
    ++**                              name: COLUMN.  Otherwise use zSpan.
    ++**
    ++**    full=ON, short=ANY:       If the result refers directly to a table column,
    ++**                              then the result column name with the table name
    ++**                              prefix, ex: TABLE.COLUMN.  Otherwise use zSpan.
    + */
    + static void generateColumnNames(
    +   Parse *pParse,      /* Parser context */
    +-  SrcList *pTabList,  /* List of tables */
    +-  ExprList *pEList    /* Expressions defining the result set */
    ++  Select *pSelect     /* Generate column names for this SELECT statement */
    + ){
    +   Vdbe *v = pParse->pVdbe;
    +-  int i, j;
    ++  int i;
    ++  Table *pTab;
    ++  SrcList *pTabList;
    ++  ExprList *pEList;
    +   sqlite3 *db = pParse->db;
    +-  int fullNames, shortNames;
    ++  int fullName;    /* TABLE.COLUMN if no AS clause and is a direct table ref */
    ++  int srcName;     /* COLUMN or TABLE.COLUMN if no AS clause and is direct */
    + 
    + #ifndef SQLITE_OMIT_EXPLAIN
    +   /* If this is an EXPLAIN, skip this step */
    +@@ -110165,27 +120278,33 @@ static void generateColumnNames(
    +   }
    + #endif
    + 
    +-  if( pParse->colNamesSet || NEVER(v==0) || db->mallocFailed ) return;
    ++  if( pParse->colNamesSet || db->mallocFailed ) return;
    ++  /* Column names are determined by the left-most term of a compound select */
    ++  while( pSelect->pPrior ) pSelect = pSelect->pPrior;
    ++  SELECTTRACE(1,pParse,pSelect,("generating column names\n"));
    ++  pTabList = pSelect->pSrc;
    ++  pEList = pSelect->pEList;
    ++  assert( v!=0 );
    ++  assert( pTabList!=0 );
    +   pParse->colNamesSet = 1;
    +-  fullNames = (db->flags & SQLITE_FullColNames)!=0;
    +-  shortNames = (db->flags & SQLITE_ShortColNames)!=0;
    ++  fullName = (db->flags & SQLITE_FullColNames)!=0;
    ++  srcName = (db->flags & SQLITE_ShortColNames)!=0 || fullName;
    +   sqlite3VdbeSetNumCols(v, pEList->nExpr);
    +   for(i=0; i<pEList->nExpr; i++){
    +-    Expr *p;
    +-    p = pEList->a[i].pExpr;
    +-    if( NEVER(p==0) ) continue;
    ++    Expr *p = pEList->a[i].pExpr;
    ++
    ++    assert( p!=0 );
    ++    assert( p->op!=TK_AGG_COLUMN );  /* Agg processing has not run yet */
    ++    assert( p->op!=TK_COLUMN || p->pTab!=0 ); /* Covering idx not yet coded */
    +     if( pEList->a[i].zName ){
    ++      /* An AS clause always takes first priority */
    +       char *zName = pEList->a[i].zName;
    +       sqlite3VdbeSetColName(v, i, COLNAME_NAME, zName, SQLITE_TRANSIENT);
    +-    }else if( (p->op==TK_COLUMN || p->op==TK_AGG_COLUMN) && pTabList ){
    +-      Table *pTab;
    ++    }else if( srcName && p->op==TK_COLUMN ){
    +       char *zCol;
    +       int iCol = p->iColumn;
    +-      for(j=0; ALWAYS(j<pTabList->nSrc); j++){
    +-        if( pTabList->a[j].iCursor==p->iTable ) break;
    +-      }
    +-      assert( j<pTabList->nSrc );
    +-      pTab = pTabList->a[j].pTab;
    ++      pTab = p->pTab;
    ++      assert( pTab!=0 );
    +       if( iCol<0 ) iCol = pTab->iPKey;
    +       assert( iCol==-1 || (iCol>=0 && iCol<pTab->nCol) );
    +       if( iCol<0 ){
    +@@ -110193,10 +120312,7 @@ static void generateColumnNames(
    +       }else{
    +         zCol = pTab->aCol[iCol].zName;
    +       }
    +-      if( !shortNames && !fullNames ){
    +-        sqlite3VdbeSetColName(v, i, COLNAME_NAME, 
    +-            sqlite3DbStrDup(db, pEList->a[i].zSpan), SQLITE_DYNAMIC);
    +-      }else if( fullNames ){
    ++      if( fullName ){
    +         char *zName = 0;
    +         zName = sqlite3MPrintf(db, "%s.%s", pTab->zName, zCol);
    +         sqlite3VdbeSetColName(v, i, COLNAME_NAME, zName, SQLITE_DYNAMIC);
    +@@ -110224,6 +120340,15 @@ static void generateColumnNames(
    + **
    + ** Return SQLITE_OK on success.  If a memory allocation error occurs,
    + ** store NULL in *paCol and 0 in *pnCol and return SQLITE_NOMEM.
    ++**
    ++** The only guarantee that SQLite makes about column names is that if the
    ++** column has an AS clause assigning it a name, that will be the name used.
    ++** That is the only documented guarantee.  However, countless applications
    ++** developed over the years have made baseless assumptions about column names
    ++** and will break if those assumptions changes.  Hence, use extreme caution
    ++** when modifying this routine to avoid breaking legacy.
    ++**
    ++** See Also: generateColumnNames()
    + */
    + SQLITE_PRIVATE int sqlite3ColumnsFromExprList(
    +   Parse *pParse,          /* Parsing context */
    +@@ -110233,78 +120358,80 @@ SQLITE_PRIVATE int sqlite3ColumnsFromExprList(
    + ){
    +   sqlite3 *db = pParse->db;   /* Database connection */
    +   int i, j;                   /* Loop counters */
    +-  int cnt;                    /* Index added to make the name unique */
    ++  u32 cnt;                    /* Index added to make the name unique */
    +   Column *aCol, *pCol;        /* For looping over result columns */
    +   int nCol;                   /* Number of columns in the result set */
    +-  Expr *p;                    /* Expression for a single result column */
    +   char *zName;                /* Column name */
    +   int nName;                  /* Size of name in zName[] */
    ++  Hash ht;                    /* Hash table of column names */
    + 
    ++  sqlite3HashInit(&ht);
    +   if( pEList ){
    +     nCol = pEList->nExpr;
    +     aCol = sqlite3DbMallocZero(db, sizeof(aCol[0])*nCol);
    +     testcase( aCol==0 );
    ++    if( nCol>32767 ) nCol = 32767;
    +   }else{
    +     nCol = 0;
    +     aCol = 0;
    +   }
    ++  assert( nCol==(i16)nCol );
    +   *pnCol = nCol;
    +   *paCol = aCol;
    + 
    +-  for(i=0, pCol=aCol; i<nCol; i++, pCol++){
    ++  for(i=0, pCol=aCol; i<nCol && !db->mallocFailed; i++, pCol++){
    +     /* Get an appropriate name for the column
    +     */
    +-    p = sqlite3ExprSkipCollate(pEList->a[i].pExpr);
    +     if( (zName = pEList->a[i].zName)!=0 ){
    +       /* If the column contains an "AS <name>" phrase, use <name> as the name */
    +-      zName = sqlite3DbStrDup(db, zName);
    +     }else{
    +-      Expr *pColExpr = p;  /* The expression that is the result column name */
    +-      Table *pTab;         /* Table associated with this expression */
    ++      Expr *pColExpr = sqlite3ExprSkipCollate(pEList->a[i].pExpr);
    +       while( pColExpr->op==TK_DOT ){
    +         pColExpr = pColExpr->pRight;
    +         assert( pColExpr!=0 );
    +       }
    +-      if( pColExpr->op==TK_COLUMN && ALWAYS(pColExpr->pTab!=0) ){
    ++      assert( pColExpr->op!=TK_AGG_COLUMN );
    ++      if( pColExpr->op==TK_COLUMN ){
    +         /* For columns use the column name name */
    +         int iCol = pColExpr->iColumn;
    +-        pTab = pColExpr->pTab;
    ++        Table *pTab = pColExpr->pTab;
    ++        assert( pTab!=0 );
    +         if( iCol<0 ) iCol = pTab->iPKey;
    +-        zName = sqlite3MPrintf(db, "%s",
    +-                 iCol>=0 ? pTab->aCol[iCol].zName : "rowid");
    ++        zName = iCol>=0 ? pTab->aCol[iCol].zName : "rowid";
    +       }else if( pColExpr->op==TK_ID ){
    +         assert( !ExprHasProperty(pColExpr, EP_IntValue) );
    +-        zName = sqlite3MPrintf(db, "%s", pColExpr->u.zToken);
    ++        zName = pColExpr->u.zToken;
    +       }else{
    +         /* Use the original text of the column expression as its name */
    +-        zName = sqlite3MPrintf(db, "%s", pEList->a[i].zSpan);
    ++        zName = pEList->a[i].zSpan;
    +       }
    +     }
    +-    if( db->mallocFailed ){
    +-      sqlite3DbFree(db, zName);
    +-      break;
    ++    if( zName ){
    ++      zName = sqlite3DbStrDup(db, zName);
    ++    }else{
    ++      zName = sqlite3MPrintf(db,"column%d",i+1);
    +     }
    + 
    +     /* Make sure the column name is unique.  If the name is not unique,
    +     ** append an integer to the name so that it becomes unique.
    +     */
    +-    nName = sqlite3Strlen30(zName);
    +-    for(j=cnt=0; j<i; j++){
    +-      if( sqlite3StrICmp(aCol[j].zName, zName)==0 ){
    +-        char *zNewName;
    +-        int k;
    +-        for(k=nName-1; k>1 && sqlite3Isdigit(zName[k]); k--){}
    +-        if( k>=0 && zName[k]==':' ) nName = k;
    +-        zName[nName] = 0;
    +-        zNewName = sqlite3MPrintf(db, "%s:%d", zName, ++cnt);
    +-        sqlite3DbFree(db, zName);
    +-        zName = zNewName;
    +-        j = -1;
    +-        if( zName==0 ) break;
    ++    cnt = 0;
    ++    while( zName && sqlite3HashFind(&ht, zName)!=0 ){
    ++      nName = sqlite3Strlen30(zName);
    ++      if( nName>0 ){
    ++        for(j=nName-1; j>0 && sqlite3Isdigit(zName[j]); j--){}
    ++        if( zName[j]==':' ) nName = j;
    +       }
    ++      zName = sqlite3MPrintf(db, "%.*z:%u", nName, zName, ++cnt);
    ++      if( cnt>3 ) sqlite3_randomness(sizeof(cnt), &cnt);
    +     }
    +     pCol->zName = zName;
    ++    sqlite3ColumnPropertiesFromName(0, pCol);
    ++    if( zName && sqlite3HashInsert(&ht, zName, pCol)==pCol ){
    ++      sqlite3OomFault(db);
    ++    }
    +   }
    ++  sqlite3HashClear(&ht);
    +   if( db->mallocFailed ){
    +     for(j=0; j<i; j++){
    +       sqlite3DbFree(db, aCol[j].zName);
    +@@ -110312,7 +120439,7 @@ SQLITE_PRIVATE int sqlite3ColumnsFromExprList(
    +     sqlite3DbFree(db, aCol);
    +     *paCol = 0;
    +     *pnCol = 0;
    +-    return SQLITE_NOMEM;
    ++    return SQLITE_NOMEM_BKPT;
    +   }
    +   return SQLITE_OK;
    + }
    +@@ -110328,7 +120455,7 @@ SQLITE_PRIVATE int sqlite3ColumnsFromExprList(
    + ** This routine requires that all identifiers in the SELECT
    + ** statement be resolved.
    + */
    +-static void selectAddColumnTypeAndCollation(
    ++SQLITE_PRIVATE void sqlite3SelectAddColumnTypeAndCollation(
    +   Parse *pParse,        /* Parsing contexts */
    +   Table *pTab,          /* Add column type information to this table */
    +   Select *pSelect       /* SELECT used to determine types and collations */
    +@@ -110340,7 +120467,6 @@ static void selectAddColumnTypeAndCollation(
    +   int i;
    +   Expr *p;
    +   struct ExprList_item *a;
    +-  u64 szAll = 0;
    + 
    +   assert( pSelect!=0 );
    +   assert( (pSelect->selFlags & SF_Resolved)!=0 );
    +@@ -110350,20 +120476,28 @@ static void selectAddColumnTypeAndCollation(
    +   sNC.pSrcList = pSelect->pSrc;
    +   a = pSelect->pEList->a;
    +   for(i=0, pCol=pTab->aCol; i<pTab->nCol; i++, pCol++){
    ++    const char *zType;
    ++    int n, m;
    +     p = a[i].pExpr;
    +-    if( pCol->zType==0 ){
    +-      pCol->zType = sqlite3DbStrDup(db, 
    +-                        columnType(&sNC, p,0,0,0, &pCol->szEst));
    +-    }
    +-    szAll += pCol->szEst;
    ++    zType = columnType(&sNC, p, 0, 0, 0);
    ++    /* pCol->szEst = ... // Column size est for SELECT tables never used */
    +     pCol->affinity = sqlite3ExprAffinity(p);
    ++    if( zType ){
    ++      m = sqlite3Strlen30(zType);
    ++      n = sqlite3Strlen30(pCol->zName);
    ++      pCol->zName = sqlite3DbReallocOrFree(db, pCol->zName, n+m+2);
    ++      if( pCol->zName ){
    ++        memcpy(&pCol->zName[n+1], zType, m+1);
    ++        pCol->colFlags |= COLFLAG_HASTYPE;
    ++      }
    ++    }
    +     if( pCol->affinity==0 ) pCol->affinity = SQLITE_AFF_BLOB;
    +     pColl = sqlite3ExprCollSeq(pParse, p);
    +     if( pColl && pCol->zColl==0 ){
    +       pCol->zColl = sqlite3DbStrDup(db, pColl->zName);
    +     }
    +   }
    +-  pTab->szTabRow = sqlite3LogEst(szAll*4);
    ++  pTab->szTabRow = 1; /* Any non-zero value works */
    + }
    + 
    + /*
    +@@ -110388,12 +120522,12 @@ SQLITE_PRIVATE Table *sqlite3ResultSetOfSelect(Parse *pParse, Select *pSelect){
    +   }
    +   /* The sqlite3ResultSetOfSelect() is only used n contexts where lookaside
    +   ** is disabled */
    +-  assert( db->lookaside.bEnabled==0 );
    +-  pTab->nRef = 1;
    ++  assert( db->lookaside.bDisable );
    ++  pTab->nTabRef = 1;
    +   pTab->zName = 0;
    +   pTab->nRowLogEst = 200; assert( 200==sqlite3LogEst(1048576) );
    +   sqlite3ColumnsFromExprList(pParse, pSelect->pEList, &pTab->nCol, &pTab->aCol);
    +-  selectAddColumnTypeAndCollation(pParse, pTab, pSelect);
    ++  sqlite3SelectAddColumnTypeAndCollation(pParse, pTab, pSelect);
    +   pTab->iPKey = -1;
    +   if( db->mallocFailed ){
    +     sqlite3DeleteTable(db, pTab);
    +@@ -110407,24 +120541,21 @@ SQLITE_PRIVATE Table *sqlite3ResultSetOfSelect(Parse *pParse, Select *pSelect){
    + ** If an error occurs, return NULL and leave a message in pParse.
    + */
    + SQLITE_PRIVATE Vdbe *sqlite3GetVdbe(Parse *pParse){
    +-  Vdbe *v = pParse->pVdbe;
    +-  if( v==0 ){
    +-    v = pParse->pVdbe = sqlite3VdbeCreate(pParse);
    +-    if( v ) sqlite3VdbeAddOp0(v, OP_Init);
    +-    if( pParse->pToplevel==0
    +-     && OptimizationEnabled(pParse->db,SQLITE_FactorOutConst)
    +-    ){
    +-      pParse->okConstFactor = 1;
    +-    }
    +-
    ++  if( pParse->pVdbe ){
    ++    return pParse->pVdbe;
    +   }
    +-  return v;
    ++  if( pParse->pToplevel==0
    ++   && OptimizationEnabled(pParse->db,SQLITE_FactorOutConst)
    ++  ){
    ++    pParse->okConstFactor = 1;
    ++  }
    ++  return sqlite3VdbeCreate(pParse);
    + }
    + 
    + 
    + /*
    + ** Compute the iLimit and iOffset fields of the SELECT based on the
    +-** pLimit and pOffset expressions.  pLimit and pOffset hold the expressions
    ++** pLimit expressions.  pLimit->pLeft and pLimit->pRight hold the expressions
    + ** that appear in the original SQL statement after the LIMIT and OFFSET
    + ** keywords.  Or NULL if those keywords are omitted. iLimit and iOffset 
    + ** are the integer memory register numbers for counters used to compute 
    +@@ -110432,15 +120563,15 @@ SQLITE_PRIVATE Vdbe *sqlite3GetVdbe(Parse *pParse){
    + ** iLimit and iOffset are negative.
    + **
    + ** This routine changes the values of iLimit and iOffset only if
    +-** a limit or offset is defined by pLimit and pOffset.  iLimit and
    +-** iOffset should have been preset to appropriate default values (zero)
    ++** a limit or offset is defined by pLimit->pLeft and pLimit->pRight.  iLimit
    ++** and iOffset should have been preset to appropriate default values (zero)
    + ** prior to calling this routine.
    + **
    + ** The iOffset register (if it exists) is initialized to the value
    + ** of the OFFSET.  The iLimit register is initialized to LIMIT.  Register
    + ** iOffset+1 is initialized to LIMIT+OFFSET.
    + **
    +-** Only if pLimit!=0 or pOffset!=0 do the limit registers get
    ++** Only if pLimit->pLeft!=0 do the limit registers get
    + ** redefined.  The UNION ALL operator uses this property to force
    + ** the reuse of the same limit and offset registers across multiple
    + ** SELECT statements.
    +@@ -110450,6 +120581,8 @@ static void computeLimitRegisters(Parse *pParse, Select *p, int iBreak){
    +   int iLimit = 0;
    +   int iOffset;
    +   int n;
    ++  Expr *pLimit = p->pLimit;
    ++
    +   if( p->iLimit ) return;
    + 
    +   /* 
    +@@ -110459,35 +120592,35 @@ static void computeLimitRegisters(Parse *pParse, Select *p, int iBreak){
    +   ** no rows.
    +   */
    +   sqlite3ExprCacheClear(pParse);
    +-  assert( p->pOffset==0 || p->pLimit!=0 );
    +-  if( p->pLimit ){
    ++  if( pLimit ){
    ++    assert( pLimit->op==TK_LIMIT );
    ++    assert( pLimit->pLeft!=0 );
    +     p->iLimit = iLimit = ++pParse->nMem;
    +     v = sqlite3GetVdbe(pParse);
    +     assert( v!=0 );
    +-    if( sqlite3ExprIsInteger(p->pLimit, &n) ){
    ++    if( sqlite3ExprIsInteger(pLimit->pLeft, &n) ){
    +       sqlite3VdbeAddOp2(v, OP_Integer, n, iLimit);
    +       VdbeComment((v, "LIMIT counter"));
    +       if( n==0 ){
    +         sqlite3VdbeGoto(v, iBreak);
    +-      }else if( n>=0 && p->nSelectRow>(u64)n ){
    +-        p->nSelectRow = n;
    ++      }else if( n>=0 && p->nSelectRow>sqlite3LogEst((u64)n) ){
    ++        p->nSelectRow = sqlite3LogEst((u64)n);
    ++        p->selFlags |= SF_FixedLimit;
    +       }
    +     }else{
    +-      sqlite3ExprCode(pParse, p->pLimit, iLimit);
    ++      sqlite3ExprCode(pParse, pLimit->pLeft, iLimit);
    +       sqlite3VdbeAddOp1(v, OP_MustBeInt, iLimit); VdbeCoverage(v);
    +       VdbeComment((v, "LIMIT counter"));
    +       sqlite3VdbeAddOp2(v, OP_IfNot, iLimit, iBreak); VdbeCoverage(v);
    +     }
    +-    if( p->pOffset ){
    ++    if( pLimit->pRight ){
    +       p->iOffset = iOffset = ++pParse->nMem;
    +       pParse->nMem++;   /* Allocate an extra register for limit+offset */
    +-      sqlite3ExprCode(pParse, p->pOffset, iOffset);
    ++      sqlite3ExprCode(pParse, pLimit->pRight, iOffset);
    +       sqlite3VdbeAddOp1(v, OP_MustBeInt, iOffset); VdbeCoverage(v);
    +       VdbeComment((v, "OFFSET counter"));
    +-      sqlite3VdbeAddOp3(v, OP_SetIfNotPos, iOffset, iOffset, 0);
    +-      sqlite3VdbeAddOp3(v, OP_Add, iLimit, iOffset, iOffset+1);
    ++      sqlite3VdbeAddOp3(v, OP_OffsetLimit, iLimit, iOffset+1, iOffset);
    +       VdbeComment((v, "LIMIT+OFFSET"));
    +-      sqlite3VdbeAddOp3(v, OP_SetIfNotPos, iLimit, iOffset+1, -1);
    +     }
    +   }
    + }
    +@@ -110613,7 +120746,7 @@ static void generateWithRecursiveQuery(
    +   int i;                        /* Loop counter */
    +   int rc;                       /* Result code */
    +   ExprList *pOrderBy;           /* The ORDER BY clause */
    +-  Expr *pLimit, *pOffset;       /* Saved LIMIT and OFFSET */
    ++  Expr *pLimit;                 /* Saved LIMIT and OFFSET */
    +   int regLimit, regOffset;      /* Registers used by LIMIT and OFFSET */
    + 
    +   /* Obtain authorization to do a recursive query */
    +@@ -110621,12 +120754,12 @@ static void generateWithRecursiveQuery(
    + 
    +   /* Process the LIMIT and OFFSET clauses, if they exist */
    +   addrBreak = sqlite3VdbeMakeLabel(v);
    ++  p->nSelectRow = 320;  /* 4 billion rows */
    +   computeLimitRegisters(pParse, p, addrBreak);
    +   pLimit = p->pLimit;
    +-  pOffset = p->pOffset;
    +   regLimit = p->iLimit;
    +   regOffset = p->iOffset;
    +-  p->pLimit = p->pOffset = 0;
    ++  p->pLimit = 0;
    +   p->iLimit = p->iOffset = 0;
    +   pOrderBy = p->pOrderBy;
    + 
    +@@ -110691,7 +120824,7 @@ static void generateWithRecursiveQuery(
    +   /* Output the single row in Current */
    +   addrCont = sqlite3VdbeMakeLabel(v);
    +   codeOffset(v, regOffset, addrCont);
    +-  selectInnerLoop(pParse, p, p->pEList, iCurrent,
    ++  selectInnerLoop(pParse, p, iCurrent,
    +       0, 0, pDest, addrCont, addrBreak);
    +   if( regLimit ){
    +     sqlite3VdbeAddOp2(v, OP_DecrJumpZero, regLimit, addrBreak);
    +@@ -110719,7 +120852,6 @@ end_of_recursive_query:
    +   sqlite3ExprListDelete(pParse->db, p->pOrderBy);
    +   p->pOrderBy = pOrderBy;
    +   p->pLimit = pLimit;
    +-  p->pOffset = pOffset;
    +   return;
    + }
    + #endif /* SQLITE_OMIT_CTE */
    +@@ -110738,9 +120870,14 @@ static int multiSelectOrderBy(
    + ** on a VALUES clause.
    + **
    + ** Because the Select object originates from a VALUES clause:
    +-**   (1) It has no LIMIT or OFFSET
    ++**   (1) There is no LIMIT or OFFSET or else there is a LIMIT of exactly 1
    + **   (2) All terms are UNION ALL
    + **   (3) There is no ORDER BY clause
    ++**
    ++** The "LIMIT of exactly 1" case of condition (1) comes about when a VALUES
    ++** clause occurs within scalar expression (ex: "SELECT (VALUES(1),(2),(3))").
    ++** The sqlite3CodeSubselect will have added the LIMIT 1 clause in tht case.
    ++** Since the limit is exactly 1, we only need to evalutes the left-most VALUES.
    + */
    + static int multiSelectValues(
    +   Parse *pParse,        /* Parsing context */
    +@@ -110748,14 +120885,13 @@ static int multiSelectValues(
    +   SelectDest *pDest     /* What to do with query results */
    + ){
    +   Select *pPrior;
    ++  Select *pRightmost = p;
    +   int nRow = 1;
    +   int rc = 0;
    +   assert( p->selFlags & SF_MultiValue );
    +   do{
    +     assert( p->selFlags & SF_Values );
    +     assert( p->op==TK_ALL || (p->op==TK_SELECT && p->pPrior==0) );
    +-    assert( p->pLimit==0 );
    +-    assert( p->pOffset==0 );
    +     assert( p->pNext==0 || p->pEList->nExpr==p->pNext->pEList->nExpr );
    +     if( p->pPrior==0 ) break;
    +     assert( p->pPrior->pNext==p );
    +@@ -110767,7 +120903,7 @@ static int multiSelectValues(
    +     p->pPrior = 0;
    +     rc = sqlite3Select(pParse, p, pDest);
    +     p->pPrior = pPrior;
    +-    if( rc ) break;
    ++    if( rc || pRightmost->pLimit ) break;
    +     p->nSelectRow = nRow;
    +     p = p->pNext;
    +   }
    +@@ -110829,15 +120965,9 @@ static int multiSelect(
    +   db = pParse->db;
    +   pPrior = p->pPrior;
    +   dest = *pDest;
    +-  if( pPrior->pOrderBy ){
    +-    sqlite3ErrorMsg(pParse,"ORDER BY clause should come after %s not before",
    +-      selectOpName(p->op));
    +-    rc = 1;
    +-    goto multi_select_end;
    +-  }
    +-  if( pPrior->pLimit ){
    +-    sqlite3ErrorMsg(pParse,"LIMIT clause should come after %s not before",
    +-      selectOpName(p->op));
    ++  if( pPrior->pOrderBy || pPrior->pLimit ){
    ++    sqlite3ErrorMsg(pParse,"%s clause should come after %s not before",
    ++      pPrior->pOrderBy!=0 ? "ORDER BY" : "LIMIT", selectOpName(p->op));
    +     rc = 1;
    +     goto multi_select_end;
    +   }
    +@@ -110850,7 +120980,6 @@ static int multiSelect(
    +   if( dest.eDest==SRT_EphemTab ){
    +     assert( p->pEList );
    +     sqlite3VdbeAddOp2(v, OP_OpenEphemeral, dest.iSDParm, p->pEList->nExpr);
    +-    sqlite3VdbeChangeP5(v, BTREE_UNORDERED);
    +     dest.eDest = SRT_Table;
    +   }
    + 
    +@@ -110889,11 +121018,9 @@ static int multiSelect(
    +       pPrior->iLimit = p->iLimit;
    +       pPrior->iOffset = p->iOffset;
    +       pPrior->pLimit = p->pLimit;
    +-      pPrior->pOffset = p->pOffset;
    +       explainSetInteger(iSub1, pParse->iNextSelectId);
    +       rc = sqlite3Select(pParse, pPrior, &dest);
    +       p->pLimit = 0;
    +-      p->pOffset = 0;
    +       if( rc ){
    +         goto multi_select_end;
    +       }
    +@@ -110904,9 +121031,8 @@ static int multiSelect(
    +         addr = sqlite3VdbeAddOp1(v, OP_IfNot, p->iLimit); VdbeCoverage(v);
    +         VdbeComment((v, "Jump ahead if LIMIT reached"));
    +         if( p->iOffset ){
    +-          sqlite3VdbeAddOp3(v, OP_SetIfNotPos, p->iOffset, p->iOffset, 0);
    +-          sqlite3VdbeAddOp3(v, OP_Add, p->iLimit, p->iOffset, p->iOffset+1);
    +-          sqlite3VdbeAddOp3(v, OP_SetIfNotPos, p->iLimit, p->iOffset+1, -1);
    ++          sqlite3VdbeAddOp3(v, OP_OffsetLimit,
    ++                            p->iLimit, p->iOffset+1, p->iOffset);
    +         }
    +       }
    +       explainSetInteger(iSub2, pParse->iNextSelectId);
    +@@ -110914,12 +121040,12 @@ static int multiSelect(
    +       testcase( rc!=SQLITE_OK );
    +       pDelete = p->pPrior;
    +       p->pPrior = pPrior;
    +-      p->nSelectRow += pPrior->nSelectRow;
    ++      p->nSelectRow = sqlite3LogEstAdd(p->nSelectRow, pPrior->nSelectRow);
    +       if( pPrior->pLimit
    +-       && sqlite3ExprIsInteger(pPrior->pLimit, &nLimit)
    +-       && nLimit>0 && p->nSelectRow > (u64)nLimit 
    ++       && sqlite3ExprIsInteger(pPrior->pLimit->pLeft, &nLimit)
    ++       && nLimit>0 && p->nSelectRow > sqlite3LogEst((u64)nLimit) 
    +       ){
    +-        p->nSelectRow = nLimit;
    ++        p->nSelectRow = sqlite3LogEst((u64)nLimit);
    +       }
    +       if( addr ){
    +         sqlite3VdbeJumpHere(v, addr);
    +@@ -110931,7 +121057,7 @@ static int multiSelect(
    +       int unionTab;    /* Cursor number of the temporary table holding result */
    +       u8 op = 0;       /* One of the SRT_ operations to apply to self */
    +       int priorOp;     /* The SRT_ operation to apply to prior selects */
    +-      Expr *pLimit, *pOffset; /* Saved values of p->nLimit and p->nOffset */
    ++      Expr *pLimit;    /* Saved values of p->nLimit  */
    +       int addr;
    +       SelectDest uniondest;
    + 
    +@@ -110943,7 +121069,6 @@ static int multiSelect(
    +         ** right.
    +         */
    +         assert( p->pLimit==0 );      /* Not allowed on leftward elements */
    +-        assert( p->pOffset==0 );     /* Not allowed on leftward elements */
    +         unionTab = dest.iSDParm;
    +       }else{
    +         /* We will need to create our own temporary table to hold the
    +@@ -110979,8 +121104,6 @@ static int multiSelect(
    +       p->pPrior = 0;
    +       pLimit = p->pLimit;
    +       p->pLimit = 0;
    +-      pOffset = p->pOffset;
    +-      p->pOffset = 0;
    +       uniondest.eDest = op;
    +       explainSetInteger(iSub2, pParse->iNextSelectId);
    +       rc = sqlite3Select(pParse, p, &uniondest);
    +@@ -110991,10 +121114,11 @@ static int multiSelect(
    +       pDelete = p->pPrior;
    +       p->pPrior = pPrior;
    +       p->pOrderBy = 0;
    +-      if( p->op==TK_UNION ) p->nSelectRow += pPrior->nSelectRow;
    ++      if( p->op==TK_UNION ){
    ++        p->nSelectRow = sqlite3LogEstAdd(p->nSelectRow, pPrior->nSelectRow);
    ++      }
    +       sqlite3ExprDelete(db, p->pLimit);
    +       p->pLimit = pLimit;
    +-      p->pOffset = pOffset;
    +       p->iLimit = 0;
    +       p->iOffset = 0;
    + 
    +@@ -111005,17 +121129,12 @@ static int multiSelect(
    +       if( dest.eDest!=priorOp ){
    +         int iCont, iBreak, iStart;
    +         assert( p->pEList );
    +-        if( dest.eDest==SRT_Output ){
    +-          Select *pFirst = p;
    +-          while( pFirst->pPrior ) pFirst = pFirst->pPrior;
    +-          generateColumnNames(pParse, 0, pFirst->pEList);
    +-        }
    +         iBreak = sqlite3VdbeMakeLabel(v);
    +         iCont = sqlite3VdbeMakeLabel(v);
    +         computeLimitRegisters(pParse, p, iBreak);
    +         sqlite3VdbeAddOp2(v, OP_Rewind, unionTab, iBreak); VdbeCoverage(v);
    +         iStart = sqlite3VdbeCurrentAddr(v);
    +-        selectInnerLoop(pParse, p, p->pEList, unionTab,
    ++        selectInnerLoop(pParse, p, unionTab,
    +                         0, 0, &dest, iCont, iBreak);
    +         sqlite3VdbeResolveLabel(v, iCont);
    +         sqlite3VdbeAddOp2(v, OP_Next, unionTab, iStart); VdbeCoverage(v);
    +@@ -111027,7 +121146,7 @@ static int multiSelect(
    +     default: assert( p->op==TK_INTERSECT ); {
    +       int tab1, tab2;
    +       int iCont, iBreak, iStart;
    +-      Expr *pLimit, *pOffset;
    ++      Expr *pLimit;
    +       int addr;
    +       SelectDest intersectdest;
    +       int r1;
    +@@ -111063,8 +121182,6 @@ static int multiSelect(
    +       p->pPrior = 0;
    +       pLimit = p->pLimit;
    +       p->pLimit = 0;
    +-      pOffset = p->pOffset;
    +-      p->pOffset = 0;
    +       intersectdest.iSDParm = tab2;
    +       explainSetInteger(iSub2, pParse->iNextSelectId);
    +       rc = sqlite3Select(pParse, p, &intersectdest);
    +@@ -111074,26 +121191,20 @@ static int multiSelect(
    +       if( p->nSelectRow>pPrior->nSelectRow ) p->nSelectRow = pPrior->nSelectRow;
    +       sqlite3ExprDelete(db, p->pLimit);
    +       p->pLimit = pLimit;
    +-      p->pOffset = pOffset;
    + 
    +       /* Generate code to take the intersection of the two temporary
    +       ** tables.
    +       */
    +       assert( p->pEList );
    +-      if( dest.eDest==SRT_Output ){
    +-        Select *pFirst = p;
    +-        while( pFirst->pPrior ) pFirst = pFirst->pPrior;
    +-        generateColumnNames(pParse, 0, pFirst->pEList);
    +-      }
    +       iBreak = sqlite3VdbeMakeLabel(v);
    +       iCont = sqlite3VdbeMakeLabel(v);
    +       computeLimitRegisters(pParse, p, iBreak);
    +       sqlite3VdbeAddOp2(v, OP_Rewind, tab1, iBreak); VdbeCoverage(v);
    +       r1 = sqlite3GetTempReg(pParse);
    +-      iStart = sqlite3VdbeAddOp2(v, OP_RowKey, tab1, r1);
    ++      iStart = sqlite3VdbeAddOp2(v, OP_RowData, tab1, r1);
    +       sqlite3VdbeAddOp4Int(v, OP_NotFound, tab2, iCont, r1, 0); VdbeCoverage(v);
    +       sqlite3ReleaseTempReg(pParse, r1);
    +-      selectInnerLoop(pParse, p, p->pEList, tab1,
    ++      selectInnerLoop(pParse, p, tab1,
    +                       0, 0, &dest, iCont, iBreak);
    +       sqlite3VdbeResolveLabel(v, iCont);
    +       sqlite3VdbeAddOp2(v, OP_Next, tab1, iStart); VdbeCoverage(v);
    +@@ -111126,7 +121237,7 @@ static int multiSelect(
    +     nCol = p->pEList->nExpr;
    +     pKeyInfo = sqlite3KeyInfoAlloc(db, nCol, 1);
    +     if( !pKeyInfo ){
    +-      rc = SQLITE_NOMEM;
    ++      rc = SQLITE_NOMEM_BKPT;
    +       goto multi_select_end;
    +     }
    +     for(i=0, apColl=pKeyInfo->aColl; i<nCol; i++, apColl++){
    +@@ -111248,19 +121359,17 @@ static int generateOutputSubroutine(
    +     }
    + 
    + #ifndef SQLITE_OMIT_SUBQUERY
    +-    /* If we are creating a set for an "expr IN (SELECT ...)" construct,
    +-    ** then there should be a single item on the stack.  Write this
    +-    ** item into the set table with bogus data.
    ++    /* If we are creating a set for an "expr IN (SELECT ...)".
    +     */
    +     case SRT_Set: {
    +       int r1;
    +-      assert( pIn->nSdst==1 || pParse->nErr>0 );
    +-      pDest->affSdst = 
    +-         sqlite3CompareAffinity(p->pEList->a[0].pExpr, pDest->affSdst);
    ++      testcase( pIn->nSdst>1 );
    +       r1 = sqlite3GetTempReg(pParse);
    +-      sqlite3VdbeAddOp4(v, OP_MakeRecord, pIn->iSdst, 1, r1, &pDest->affSdst,1);
    +-      sqlite3ExprCacheAffinityChange(pParse, pIn->iSdst, 1);
    +-      sqlite3VdbeAddOp2(v, OP_IdxInsert, pDest->iSDParm, r1);
    ++      sqlite3VdbeAddOp4(v, OP_MakeRecord, pIn->iSdst, pIn->nSdst, 
    ++          r1, pDest->zAffSdst, pIn->nSdst);
    ++      sqlite3ExprCacheAffinityChange(pParse, pIn->iSdst, pIn->nSdst);
    ++      sqlite3VdbeAddOp4Int(v, OP_IdxInsert, pDest->iSDParm, r1,
    ++                           pIn->iSdst, pIn->nSdst);
    +       sqlite3ReleaseTempReg(pParse, r1);
    +       break;
    +     }
    +@@ -111481,10 +121590,10 @@ static int multiSelectOrderBy(
    +       }
    +       if( j==nOrderBy ){
    +         Expr *pNew = sqlite3Expr(db, TK_INTEGER, 0);
    +-        if( pNew==0 ) return SQLITE_NOMEM;
    ++        if( pNew==0 ) return SQLITE_NOMEM_BKPT;
    +         pNew->flags |= EP_IntValue;
    +         pNew->u.iValue = i;
    +-        pOrderBy = sqlite3ExprListAppend(pParse, pOrderBy, pNew);
    ++        p->pOrderBy = pOrderBy = sqlite3ExprListAppend(pParse, pOrderBy, pNew);
    +         if( pOrderBy ) pOrderBy->a[nOrderBy++].u.x.iOrderByCol = (u16)i;
    +       }
    +     }
    +@@ -111497,10 +121606,11 @@ static int multiSelectOrderBy(
    +   ** to the right and the left are evaluated, they use the correct
    +   ** collation.
    +   */
    +-  aPermute = sqlite3DbMallocRaw(db, sizeof(int)*nOrderBy);
    ++  aPermute = sqlite3DbMallocRawNN(db, sizeof(int)*(nOrderBy + 1));
    +   if( aPermute ){
    +     struct ExprList_item *pItem;
    +-    for(i=0, pItem=pOrderBy->a; i<nOrderBy; i++, pItem++){
    ++    aPermute[0] = nOrderBy;
    ++    for(i=1, pItem=pOrderBy->a; i<=nOrderBy; i++, pItem++){
    +       assert( pItem->u.x.iOrderByCol>0 );
    +       assert( pItem->u.x.iOrderByCol<=p->pEList->nExpr );
    +       aPermute[i] = pItem->u.x.iOrderByCol - 1;
    +@@ -111559,8 +121669,6 @@ static int multiSelectOrderBy(
    +   }
    +   sqlite3ExprDelete(db, p->pLimit);
    +   p->pLimit = 0;
    +-  sqlite3ExprDelete(db, p->pOffset);
    +-  p->pOffset = 0;
    + 
    +   regAddrA = ++pParse->nMem;
    +   regAddrB = ++pParse->nMem;
    +@@ -111578,7 +121686,7 @@ static int multiSelectOrderBy(
    +   pPrior->iLimit = regLimitA;
    +   explainSetInteger(iSub1, pParse->iNextSelectId);
    +   sqlite3Select(pParse, pPrior, &destA);
    +-  sqlite3VdbeAddOp1(v, OP_EndCoroutine, regAddrA);
    ++  sqlite3VdbeEndCoroutine(v, regAddrA);
    +   sqlite3VdbeJumpHere(v, addr1);
    + 
    +   /* Generate a coroutine to evaluate the SELECT statement on 
    +@@ -111595,7 +121703,7 @@ static int multiSelectOrderBy(
    +   sqlite3Select(pParse, p, &destB);
    +   p->iLimit = savedLimit;
    +   p->iOffset = savedOffset;
    +-  sqlite3VdbeAddOp1(v, OP_EndCoroutine, regAddrB);
    ++  sqlite3VdbeEndCoroutine(v, regAddrB);
    + 
    +   /* Generate a subroutine that outputs the current row of the A
    +   ** select as the next output row of the compound select.
    +@@ -111627,7 +121735,7 @@ static int multiSelectOrderBy(
    +     addrEofA_noB = sqlite3VdbeAddOp2(v, OP_Yield, regAddrB, labelEnd);
    +                                      VdbeCoverage(v);
    +     sqlite3VdbeGoto(v, addrEofA);
    +-    p->nSelectRow += pPrior->nSelectRow;
    ++    p->nSelectRow = sqlite3LogEstAdd(p->nSelectRow, pPrior->nSelectRow);
    +   }
    + 
    +   /* Generate a subroutine to run when the results from select B
    +@@ -111693,14 +121801,6 @@ static int multiSelectOrderBy(
    +   */
    +   sqlite3VdbeResolveLabel(v, labelEnd);
    + 
    +-  /* Set the number of output columns
    +-  */
    +-  if( pDest->eDest==SRT_Output ){
    +-    Select *pFirst = pPrior;
    +-    while( pFirst->pPrior ) pFirst = pFirst->pPrior;
    +-    generateColumnNames(pParse, 0, pFirst->pEList);
    +-  }
    +-
    +   /* Reassembly the compound query so that it will be freed correctly
    +   ** by the calling function */
    +   if( p->pPrior ){
    +@@ -111717,9 +121817,24 @@ static int multiSelectOrderBy(
    + #endif
    + 
    + #if !defined(SQLITE_OMIT_SUBQUERY) || !defined(SQLITE_OMIT_VIEW)
    ++
    ++/* An instance of the SubstContext object describes an substitution edit
    ++** to be performed on a parse tree.
    ++**
    ++** All references to columns in table iTable are to be replaced by corresponding
    ++** expressions in pEList.
    ++*/
    ++typedef struct SubstContext {
    ++  Parse *pParse;            /* The parsing context */
    ++  int iTable;               /* Replace references to this table */
    ++  int iNewTable;            /* New table number */
    ++  int isLeftJoin;           /* Add TK_IF_NULL_ROW opcodes on each replacement */
    ++  ExprList *pEList;         /* Replacement expressions */
    ++} SubstContext;
    ++
    + /* Forward Declarations */
    +-static void substExprList(sqlite3*, ExprList*, int, ExprList*);
    +-static void substSelect(sqlite3*, Select *, int, ExprList*, int);
    ++static void substExprList(SubstContext*, ExprList*);
    ++static void substSelect(SubstContext*, Select*, int);
    + 
    + /*
    + ** Scan through the expression pExpr.  Replace every reference to
    +@@ -111730,74 +121845,97 @@ static void substSelect(sqlite3*, Select *, int, ExprList*, int);
    + ** This routine is part of the flattening procedure.  A subquery
    + ** whose result set is defined by pEList appears as entry in the
    + ** FROM clause of a SELECT such that the VDBE cursor assigned to that
    +-** FORM clause entry is iTable.  This routine make the necessary 
    ++** FORM clause entry is iTable.  This routine makes the necessary 
    + ** changes to pExpr so that it refers directly to the source table
    + ** of the subquery rather the result set of the subquery.
    + */
    + static Expr *substExpr(
    +-  sqlite3 *db,        /* Report malloc errors to this connection */
    +-  Expr *pExpr,        /* Expr in which substitution occurs */
    +-  int iTable,         /* Table to be substituted */
    +-  ExprList *pEList    /* Substitute expressions */
    ++  SubstContext *pSubst,  /* Description of the substitution */
    ++  Expr *pExpr            /* Expr in which substitution occurs */
    + ){
    +   if( pExpr==0 ) return 0;
    +-  if( pExpr->op==TK_COLUMN && pExpr->iTable==iTable ){
    ++  if( ExprHasProperty(pExpr, EP_FromJoin)
    ++   && pExpr->iRightJoinTable==pSubst->iTable
    ++  ){
    ++    pExpr->iRightJoinTable = pSubst->iNewTable;
    ++  }
    ++  if( pExpr->op==TK_COLUMN && pExpr->iTable==pSubst->iTable ){
    +     if( pExpr->iColumn<0 ){
    +       pExpr->op = TK_NULL;
    +     }else{
    +       Expr *pNew;
    +-      assert( pEList!=0 && pExpr->iColumn<pEList->nExpr );
    ++      Expr *pCopy = pSubst->pEList->a[pExpr->iColumn].pExpr;
    ++      Expr ifNullRow;
    ++      assert( pSubst->pEList!=0 && pExpr->iColumn<pSubst->pEList->nExpr );
    +       assert( pExpr->pLeft==0 && pExpr->pRight==0 );
    +-      pNew = sqlite3ExprDup(db, pEList->a[pExpr->iColumn].pExpr, 0);
    +-      sqlite3ExprDelete(db, pExpr);
    +-      pExpr = pNew;
    ++      if( sqlite3ExprIsVector(pCopy) ){
    ++        sqlite3VectorErrorMsg(pSubst->pParse, pCopy);
    ++      }else{
    ++        sqlite3 *db = pSubst->pParse->db;
    ++        if( pSubst->isLeftJoin && pCopy->op!=TK_COLUMN ){
    ++          memset(&ifNullRow, 0, sizeof(ifNullRow));
    ++          ifNullRow.op = TK_IF_NULL_ROW;
    ++          ifNullRow.pLeft = pCopy;
    ++          ifNullRow.iTable = pSubst->iNewTable;
    ++          pCopy = &ifNullRow;
    ++        }
    ++        pNew = sqlite3ExprDup(db, pCopy, 0);
    ++        if( pNew && pSubst->isLeftJoin ){
    ++          ExprSetProperty(pNew, EP_CanBeNull);
    ++        }
    ++        if( pNew && ExprHasProperty(pExpr,EP_FromJoin) ){
    ++          pNew->iRightJoinTable = pExpr->iRightJoinTable;
    ++          ExprSetProperty(pNew, EP_FromJoin);
    ++        }
    ++        sqlite3ExprDelete(db, pExpr);
    ++        pExpr = pNew;
    ++      }
    +     }
    +   }else{
    +-    pExpr->pLeft = substExpr(db, pExpr->pLeft, iTable, pEList);
    +-    pExpr->pRight = substExpr(db, pExpr->pRight, iTable, pEList);
    ++    if( pExpr->op==TK_IF_NULL_ROW && pExpr->iTable==pSubst->iTable ){
    ++      pExpr->iTable = pSubst->iNewTable;
    ++    }
    ++    pExpr->pLeft = substExpr(pSubst, pExpr->pLeft);
    ++    pExpr->pRight = substExpr(pSubst, pExpr->pRight);
    +     if( ExprHasProperty(pExpr, EP_xIsSelect) ){
    +-      substSelect(db, pExpr->x.pSelect, iTable, pEList, 1);
    ++      substSelect(pSubst, pExpr->x.pSelect, 1);
    +     }else{
    +-      substExprList(db, pExpr->x.pList, iTable, pEList);
    ++      substExprList(pSubst, pExpr->x.pList);
    +     }
    +   }
    +   return pExpr;
    + }
    + static void substExprList(
    +-  sqlite3 *db,         /* Report malloc errors here */
    +-  ExprList *pList,     /* List to scan and in which to make substitutes */
    +-  int iTable,          /* Table to be substituted */
    +-  ExprList *pEList     /* Substitute values */
    ++  SubstContext *pSubst, /* Description of the substitution */
    ++  ExprList *pList       /* List to scan and in which to make substitutes */
    + ){
    +   int i;
    +   if( pList==0 ) return;
    +   for(i=0; i<pList->nExpr; i++){
    +-    pList->a[i].pExpr = substExpr(db, pList->a[i].pExpr, iTable, pEList);
    ++    pList->a[i].pExpr = substExpr(pSubst, pList->a[i].pExpr);
    +   }
    + }
    + static void substSelect(
    +-  sqlite3 *db,         /* Report malloc errors here */
    +-  Select *p,           /* SELECT statement in which to make substitutions */
    +-  int iTable,          /* Table to be replaced */
    +-  ExprList *pEList,    /* Substitute values */
    +-  int doPrior          /* Do substitutes on p->pPrior too */
    ++  SubstContext *pSubst, /* Description of the substitution */
    ++  Select *p,            /* SELECT statement in which to make substitutions */
    ++  int doPrior           /* Do substitutes on p->pPrior too */
    + ){
    +   SrcList *pSrc;
    +   struct SrcList_item *pItem;
    +   int i;
    +   if( !p ) return;
    +   do{
    +-    substExprList(db, p->pEList, iTable, pEList);
    +-    substExprList(db, p->pGroupBy, iTable, pEList);
    +-    substExprList(db, p->pOrderBy, iTable, pEList);
    +-    p->pHaving = substExpr(db, p->pHaving, iTable, pEList);
    +-    p->pWhere = substExpr(db, p->pWhere, iTable, pEList);
    ++    substExprList(pSubst, p->pEList);
    ++    substExprList(pSubst, p->pGroupBy);
    ++    substExprList(pSubst, p->pOrderBy);
    ++    p->pHaving = substExpr(pSubst, p->pHaving);
    ++    p->pWhere = substExpr(pSubst, p->pWhere);
    +     pSrc = p->pSrc;
    +     assert( pSrc!=0 );
    +     for(i=pSrc->nSrc, pItem=pSrc->a; i>0; i--, pItem++){
    +-      substSelect(db, pItem->pSelect, iTable, pEList, 1);
    ++      substSelect(pSubst, pItem->pSelect, 1);
    +       if( pItem->fg.isTabFunc ){
    +-        substExprList(db, pItem->u1.pFuncArg, iTable, pEList);
    ++        substExprList(pSubst, pItem->u1.pFuncArg);
    +       }
    +     }
    +   }while( doPrior && (p = p->pPrior)!=0 );
    +@@ -111831,66 +121969,74 @@ static void substSelect(
    + ** exist on the table t1, a complete scan of the data might be
    + ** avoided.
    + **
    +-** Flattening is only attempted if all of the following are true:
    ++** Flattening is subject to the following constraints:
    + **
    +-**   (1)  The subquery and the outer query do not both use aggregates.
    ++**  (**)  We no longer attempt to flatten aggregate subqueries. Was:
    ++**        The subquery and the outer query cannot both be aggregates.
    + **
    +-**   (2)  The subquery is not an aggregate or (2a) the outer query is not a join
    +-**        and (2b) the outer query does not use subqueries other than the one
    +-**        FROM-clause subquery that is a candidate for flattening.  (2b is
    +-**        due to ticket [2f7170d73bf9abf80] from 2015-02-09.)
    ++**  (**)  We no longer attempt to flatten aggregate subqueries. Was:
    ++**        (2) If the subquery is an aggregate then
    ++**        (2a) the outer query must not be a join and
    ++**        (2b) the outer query must not use subqueries
    ++**             other than the one FROM-clause subquery that is a candidate
    ++**             for flattening.  (This is due to ticket [2f7170d73bf9abf80]
    ++**             from 2015-02-09.)
    + **
    +-**   (3)  The subquery is not the right operand of a left outer join
    +-**        (Originally ticket #306.  Strengthened by ticket #3300)
    ++**   (3)  If the subquery is the right operand of a LEFT JOIN then
    ++**        (3a) the subquery may not be a join and
    ++**        (3b) the FROM clause of the subquery may not contain a virtual
    ++**             table and
    ++**        (3c) the outer query may not be an aggregate.
    + **
    +-**   (4)  The subquery is not DISTINCT.
    ++**   (4)  The subquery can not be DISTINCT.
    + **
    + **  (**)  At one point restrictions (4) and (5) defined a subset of DISTINCT
    + **        sub-queries that were excluded from this optimization. Restriction 
    + **        (4) has since been expanded to exclude all DISTINCT subqueries.
    + **
    +-**   (6)  The subquery does not use aggregates or the outer query is not
    +-**        DISTINCT.
    ++**  (**)  We no longer attempt to flatten aggregate subqueries.  Was:
    ++**        If the subquery is aggregate, the outer query may not be DISTINCT.
    + **
    +-**   (7)  The subquery has a FROM clause.  TODO:  For subqueries without
    +-**        A FROM clause, consider adding a FROM close with the special
    ++**   (7)  The subquery must have a FROM clause.  TODO:  For subqueries without
    ++**        A FROM clause, consider adding a FROM clause with the special
    + **        table sqlite_once that consists of a single row containing a
    + **        single NULL.
    + **
    +-**   (8)  The subquery does not use LIMIT or the outer query is not a join.
    ++**   (8)  If the subquery uses LIMIT then the outer query may not be a join.
    + **
    +-**   (9)  The subquery does not use LIMIT or the outer query does not use
    +-**        aggregates.
    ++**   (9)  If the subquery uses LIMIT then the outer query may not be aggregate.
    + **
    + **  (**)  Restriction (10) was removed from the code on 2005-02-05 but we
    + **        accidently carried the comment forward until 2014-09-15.  Original
    +-**        text: "The subquery does not use aggregates or the outer query 
    +-**        does not use LIMIT."
    ++**        constraint: "If the subquery is aggregate then the outer query 
    ++**        may not use LIMIT."
    + **
    +-**  (11)  The subquery and the outer query do not both have ORDER BY clauses.
    ++**  (11)  The subquery and the outer query may not both have ORDER BY clauses.
    + **
    + **  (**)  Not implemented.  Subsumed into restriction (3).  Was previously
    + **        a separate restriction deriving from ticket #350.
    + **
    +-**  (13)  The subquery and outer query do not both use LIMIT.
    ++**  (13)  The subquery and outer query may not both use LIMIT.
    + **
    +-**  (14)  The subquery does not use OFFSET.
    ++**  (14)  The subquery may not use OFFSET.
    + **
    +-**  (15)  The outer query is not part of a compound select or the
    +-**        subquery does not have a LIMIT clause.
    ++**  (15)  If the outer query is part of a compound select, then the
    ++**        subquery may not use LIMIT.
    + **        (See ticket #2339 and ticket [02a8e81d44]).
    + **
    +-**  (16)  The outer query is not an aggregate or the subquery does
    +-**        not contain ORDER BY.  (Ticket #2942)  This used to not matter
    ++**  (16)  If the outer query is aggregate, then the subquery may not
    ++**        use ORDER BY.  (Ticket #2942)  This used to not matter
    + **        until we introduced the group_concat() function.  
    + **
    +-**  (17)  The sub-query is not a compound select, or it is a UNION ALL 
    +-**        compound clause made up entirely of non-aggregate queries, and 
    +-**        the parent query:
    +-**
    +-**          * is not itself part of a compound select,
    +-**          * is not an aggregate or DISTINCT query, and
    +-**          * is not a join
    ++**  (17)  If the subquery is a compound select, then
    ++**        (17a) all compound operators must be a UNION ALL, and
    ++**        (17b) no terms within the subquery compound may be aggregate
    ++**              or DISTINCT, and
    ++**        (17c) every term within the subquery compound must have a FROM clause
    ++**        (17d) the outer query may not be
    ++**              (17d1) aggregate, or
    ++**              (17d2) DISTINCT, or
    ++**              (17d3) a join.
    + **
    + **        The parent and sub-query may contain WHERE clauses. Subject to
    + **        rules (11), (13) and (14), they may also contain ORDER BY,
    +@@ -111906,10 +122052,10 @@ static void substSelect(
    + **        syntax error and return a detailed message.
    + **
    + **  (18)  If the sub-query is a compound select, then all terms of the
    +-**        ORDER by clause of the parent must be simple references to 
    ++**        ORDER BY clause of the parent must be simple references to 
    + **        columns of the sub-query.
    + **
    +-**  (19)  The subquery does not use LIMIT or the outer query does not
    ++**  (19)  If the subquery uses LIMIT then the outer query may not
    + **        have a WHERE clause.
    + **
    + **  (20)  If the sub-query is a compound select, then it must not use
    +@@ -111918,17 +122064,19 @@ static void substSelect(
    + **        appear as unmodified result columns in the outer query.  But we
    + **        have other optimizations in mind to deal with that case.
    + **
    +-**  (21)  The subquery does not use LIMIT or the outer query is not
    ++**  (21)  If the subquery uses LIMIT then the outer query may not be
    + **        DISTINCT.  (See ticket [752e1646fc]).
    + **
    +-**  (22)  The subquery is not a recursive CTE.
    ++**  (22)  The subquery may not be a recursive CTE.
    + **
    +-**  (23)  The parent is not a recursive CTE, or the sub-query is not a
    +-**        compound query. This restriction is because transforming the
    ++**  (**)  Subsumed into restriction (17d3).  Was: If the outer query is
    ++**        a recursive CTE, then the sub-query may not be a compound query.
    ++**        This restriction is because transforming the
    + **        parent to a compound query confuses the code that handles
    + **        recursive queries in multiSelect().
    + **
    +-**  (24)  The subquery is not an aggregate that uses the built-in min() or 
    ++**  (**)  We no longer attempt to flatten aggregate subqueries.  Was:
    ++**        The subquery may not be an aggregate that uses the built-in min() or 
    + **        or max() functions.  (Without this restriction, a query like:
    + **        "SELECT x FROM (SELECT max(y), x FROM t1)" would not necessarily
    + **        return the value X for which Y was maximal.)
    +@@ -111936,7 +122084,7 @@ static void substSelect(
    + **
    + ** In this routine, the "p" parameter is a pointer to the outer query.
    + ** The subquery is p->pSrc->a[iFrom].  isAgg is true if the outer query
    +-** uses aggregates and subqueryIsAgg is true if the subquery uses aggregates.
    ++** uses aggregates.
    + **
    + ** If flattening is not attempted, this routine is a no-op and returns 0.
    + ** If flattening is attempted this routine returns 1.
    +@@ -111948,8 +122096,7 @@ static int flattenSubquery(
    +   Parse *pParse,       /* Parsing context */
    +   Select *p,           /* The parent or outer SELECT statement */
    +   int iFrom,           /* Index in p->pSrc->a[] of the inner subquery */
    +-  int isAgg,           /* True if outer SELECT uses aggregate functions */
    +-  int subqueryIsAgg    /* True if the subquery uses aggregate functions */
    ++  int isAgg            /* True if outer SELECT uses aggregate functions */
    + ){
    +   const char *zSavedAuthContext = pParse->zAuthContext;
    +   Select *pParent;    /* Current UNION ALL term of the other query */
    +@@ -111957,8 +122104,9 @@ static int flattenSubquery(
    +   Select *pSub1;      /* Pointer to the rightmost select in sub-query */
    +   SrcList *pSrc;      /* The FROM clause of the outer query */
    +   SrcList *pSubSrc;   /* The FROM clause of the subquery */
    +-  ExprList *pList;    /* The result set of the outer query */
    +   int iParent;        /* VDBE cursor number of the pSub result set temp table */
    ++  int iNewParent = -1;/* Replacement table for iParent */
    ++  int isLeftJoin = 0; /* True if pSub is the right side of a LEFT JOIN */    
    +   int i;              /* Loop counter */
    +   Expr *pWhere;                    /* The WHERE clause */
    +   struct SrcList_item *pSubitem;   /* The subquery */
    +@@ -111967,7 +122115,7 @@ static int flattenSubquery(
    +   /* Check to see if flattening is permitted.  Return 0 if not.
    +   */
    +   assert( p!=0 );
    +-  assert( p->pPrior==0 );  /* Unable to flatten compound queries */
    ++  assert( p->pPrior==0 );
    +   if( OptimizationDisabled(db, SQLITE_QueryFlattener) ) return 0;
    +   pSrc = p->pSrc;
    +   assert( pSrc && iFrom>=0 && iFrom<pSrc->nSrc );
    +@@ -111975,17 +122123,7 @@ static int flattenSubquery(
    +   iParent = pSubitem->iCursor;
    +   pSub = pSubitem->pSelect;
    +   assert( pSub!=0 );
    +-  if( subqueryIsAgg ){
    +-    if( isAgg ) return 0;                                /* Restriction (1)   */
    +-    if( pSrc->nSrc>1 ) return 0;                         /* Restriction (2a)  */
    +-    if( (p->pWhere && ExprHasProperty(p->pWhere,EP_Subquery))
    +-     || (sqlite3ExprListFlags(p->pEList) & EP_Subquery)!=0
    +-     || (sqlite3ExprListFlags(p->pOrderBy) & EP_Subquery)!=0
    +-    ){
    +-      return 0;                                          /* Restriction (2b)  */
    +-    }
    +-  }
    +-    
    ++
    +   pSubSrc = pSub->pSrc;
    +   assert( pSubSrc );
    +   /* Prior to version 3.1.2, when LIMIT and OFFSET had to be simple constants,
    +@@ -111994,18 +122132,15 @@ static int flattenSubquery(
    +   ** became arbitrary expressions, we were forced to add restrictions (13)
    +   ** and (14). */
    +   if( pSub->pLimit && p->pLimit ) return 0;              /* Restriction (13) */
    +-  if( pSub->pOffset ) return 0;                          /* Restriction (14) */
    ++  if( pSub->pLimit && pSub->pLimit->pRight ) return 0;   /* Restriction (14) */
    +   if( (p->selFlags & SF_Compound)!=0 && pSub->pLimit ){
    +     return 0;                                            /* Restriction (15) */
    +   }
    +   if( pSubSrc->nSrc==0 ) return 0;                       /* Restriction (7)  */
    +-  if( pSub->selFlags & SF_Distinct ) return 0;           /* Restriction (5)  */
    ++  if( pSub->selFlags & SF_Distinct ) return 0;           /* Restriction (4)  */
    +   if( pSub->pLimit && (pSrc->nSrc>1 || isAgg) ){
    +      return 0;         /* Restrictions (8)(9) */
    +   }
    +-  if( (p->selFlags & SF_Distinct)!=0 && subqueryIsAgg ){
    +-     return 0;         /* Restriction (6)  */
    +-  }
    +   if( p->pOrderBy && pSub->pOrderBy ){
    +      return 0;                                           /* Restriction (11) */
    +   }
    +@@ -112014,19 +122149,14 @@ static int flattenSubquery(
    +   if( pSub->pLimit && (p->selFlags & SF_Distinct)!=0 ){
    +      return 0;         /* Restriction (21) */
    +   }
    +-  testcase( pSub->selFlags & SF_Recursive );
    +-  testcase( pSub->selFlags & SF_MinMaxAgg );
    +-  if( pSub->selFlags & (SF_Recursive|SF_MinMaxAgg) ){
    +-    return 0; /* Restrictions (22) and (24) */
    +-  }
    +-  if( (p->selFlags & SF_Recursive) && pSub->pPrior ){
    +-    return 0; /* Restriction (23) */
    ++  if( pSub->selFlags & (SF_Recursive) ){
    ++    return 0; /* Restrictions (22) */
    +   }
    + 
    +-  /* OBSOLETE COMMENT 1:
    +-  ** Restriction 3:  If the subquery is a join, make sure the subquery is 
    +-  ** not used as the right operand of an outer join.  Examples of why this
    +-  ** is not allowed:
    ++  /*
    ++  ** If the subquery is the right operand of a LEFT JOIN, then the
    ++  ** subquery may not be a join itself (3a). Example of why this is not
    ++  ** allowed:
    +   **
    +   **         t1 LEFT OUTER JOIN (t2 JOIN t3)
    +   **
    +@@ -112036,56 +122166,57 @@ static int flattenSubquery(
    +   **
    +   ** which is not at all the same thing.
    +   **
    +-  ** OBSOLETE COMMENT 2:
    +-  ** Restriction 12:  If the subquery is the right operand of a left outer
    +-  ** join, make sure the subquery has no WHERE clause.
    +-  ** An examples of why this is not allowed:
    +-  **
    +-  **         t1 LEFT OUTER JOIN (SELECT * FROM t2 WHERE t2.x>0)
    +-  **
    +-  ** If we flatten the above, we would get
    +-  **
    +-  **         (t1 LEFT OUTER JOIN t2) WHERE t2.x>0
    ++  ** If the subquery is the right operand of a LEFT JOIN, then the outer
    ++  ** query cannot be an aggregate. (3c)  This is an artifact of the way
    ++  ** aggregates are processed - there is no mechanism to determine if
    ++  ** the LEFT JOIN table should be all-NULL.
    +   **
    +-  ** But the t2.x>0 test will always fail on a NULL row of t2, which
    +-  ** effectively converts the OUTER JOIN into an INNER JOIN.
    +-  **
    +-  ** THIS OVERRIDES OBSOLETE COMMENTS 1 AND 2 ABOVE:
    +-  ** Ticket #3300 shows that flattening the right term of a LEFT JOIN
    +-  ** is fraught with danger.  Best to avoid the whole thing.  If the
    +-  ** subquery is the right term of a LEFT JOIN, then do not flatten.
    ++  ** See also tickets #306, #350, and #3300.
    +   */
    +   if( (pSubitem->fg.jointype & JT_OUTER)!=0 ){
    +-    return 0;
    ++    isLeftJoin = 1;
    ++    if( pSubSrc->nSrc>1 || isAgg || IsVirtual(pSubSrc->a[0].pTab) ){
    ++      /*  (3a)             (3c)     (3b) */
    ++      return 0;
    ++    }
    +   }
    ++#ifdef SQLITE_EXTRA_IFNULLROW
    ++  else if( iFrom>0 && !isAgg ){
    ++    /* Setting isLeftJoin to -1 causes OP_IfNullRow opcodes to be generated for
    ++    ** every reference to any result column from subquery in a join, even
    ++    ** though they are not necessary.  This will stress-test the OP_IfNullRow 
    ++    ** opcode. */
    ++    isLeftJoin = -1;
    ++  }
    ++#endif
    + 
    +-  /* Restriction 17: If the sub-query is a compound SELECT, then it must
    ++  /* Restriction (17): If the sub-query is a compound SELECT, then it must
    +   ** use only the UNION ALL operator. And none of the simple select queries
    +   ** that make up the compound SELECT are allowed to be aggregate or distinct
    +   ** queries.
    +   */
    +   if( pSub->pPrior ){
    +     if( pSub->pOrderBy ){
    +-      return 0;  /* Restriction 20 */
    ++      return 0;  /* Restriction (20) */
    +     }
    +     if( isAgg || (p->selFlags & SF_Distinct)!=0 || pSrc->nSrc!=1 ){
    +-      return 0;
    ++      return 0; /* (17d1), (17d2), or (17d3) */
    +     }
    +     for(pSub1=pSub; pSub1; pSub1=pSub1->pPrior){
    +       testcase( (pSub1->selFlags & (SF_Distinct|SF_Aggregate))==SF_Distinct );
    +       testcase( (pSub1->selFlags & (SF_Distinct|SF_Aggregate))==SF_Aggregate );
    +       assert( pSub->pSrc!=0 );
    +       assert( pSub->pEList->nExpr==pSub1->pEList->nExpr );
    +-      if( (pSub1->selFlags & (SF_Distinct|SF_Aggregate))!=0
    +-       || (pSub1->pPrior && pSub1->op!=TK_ALL) 
    +-       || pSub1->pSrc->nSrc<1
    ++      if( (pSub1->selFlags & (SF_Distinct|SF_Aggregate))!=0    /* (17b) */
    ++       || (pSub1->pPrior && pSub1->op!=TK_ALL)                 /* (17a) */
    ++       || pSub1->pSrc->nSrc<1                                  /* (17c) */
    +       ){
    +         return 0;
    +       }
    +       testcase( pSub1->pSrc->nSrc>1 );
    +     }
    + 
    +-    /* Restriction 18. */
    ++    /* Restriction (18). */
    +     if( p->pOrderBy ){
    +       int ii;
    +       for(ii=0; ii<p->pOrderBy->nExpr; ii++){
    +@@ -112094,6 +122225,14 @@ static int flattenSubquery(
    +     }
    +   }
    + 
    ++  /* Ex-restriction (23):
    ++  ** The only way that the recursive part of a CTE can contain a compound
    ++  ** subquery is for the subquery to be one term of a join.  But if the
    ++  ** subquery is a join, then the flattening has already been stopped by
    ++  ** restriction (17d3)
    ++  */
    ++  assert( (p->selFlags & SF_Recursive)==0 || pSub->pPrior==0 );
    ++
    +   /***** If we reach this point, flattening is permitted. *****/
    +   SELECTTRACE(1,pParse,p,("flatten %s.%p from term %d\n",
    +                    pSub->zSelName, pSub, iFrom));
    +@@ -112141,16 +122280,13 @@ static int flattenSubquery(
    +     Select *pNew;
    +     ExprList *pOrderBy = p->pOrderBy;
    +     Expr *pLimit = p->pLimit;
    +-    Expr *pOffset = p->pOffset;
    +     Select *pPrior = p->pPrior;
    +     p->pOrderBy = 0;
    +     p->pSrc = 0;
    +     p->pPrior = 0;
    +     p->pLimit = 0;
    +-    p->pOffset = 0;
    +     pNew = sqlite3SelectDup(db, p, 0);
    +     sqlite3SelectSetName(pNew, pSub->zSelName);
    +-    p->pOffset = pOffset;
    +     p->pLimit = pLimit;
    +     p->pOrderBy = pOrderBy;
    +     p->pSrc = pSrc;
    +@@ -112194,12 +122330,12 @@ static int flattenSubquery(
    +   */
    +   if( ALWAYS(pSubitem->pTab!=0) ){
    +     Table *pTabToDel = pSubitem->pTab;
    +-    if( pTabToDel->nRef==1 ){
    ++    if( pTabToDel->nTabRef==1 ){
    +       Parse *pToplevel = sqlite3ParseToplevel(pParse);
    +       pTabToDel->pNextZombie = pToplevel->pZombieTab;
    +       pToplevel->pZombieTab = pTabToDel;
    +     }else{
    +-      pTabToDel->nRef--;
    ++      pTabToDel->nTabRef--;
    +     }
    +     pSubitem->pTab = 0;
    +   }
    +@@ -112263,7 +122399,9 @@ static int flattenSubquery(
    +     */
    +     for(i=0; i<nSubSrc; i++){
    +       sqlite3IdListDelete(db, pSrc->a[i+iFrom].pUsing);
    ++      assert( pSrc->a[i+iFrom].fg.isTabFunc==0 );
    +       pSrc->a[i+iFrom] = pSubSrc->a[i];
    ++      iNewParent = pSubSrc->a[i].iCursor;
    +       memset(&pSubSrc->a[i], 0, sizeof(pSubSrc->a[i]));
    +     }
    +     pSrc->a[iFrom].fg.jointype = jointype;
    +@@ -112280,14 +122418,6 @@ static int flattenSubquery(
    +     ** We look at every expression in the outer query and every place we see
    +     ** "a" we substitute "x*3" and every place we see "b" we substitute "y+10".
    +     */
    +-    pList = pParent->pEList;
    +-    for(i=0; i<pList->nExpr; i++){
    +-      if( pList->a[i].zName==0 ){
    +-        char *zName = sqlite3DbStrDup(db, pList->a[i].zSpan);
    +-        sqlite3Dequote(zName);
    +-        pList->a[i].zName = zName;
    +-      }
    +-    }
    +     if( pSub->pOrderBy ){
    +       /* At this point, any non-zero iOrderByCol values indicate that the
    +       ** ORDER BY column expression is identical to the iOrderByCol'th
    +@@ -112309,18 +122439,19 @@ static int flattenSubquery(
    +       pSub->pOrderBy = 0;
    +     }
    +     pWhere = sqlite3ExprDup(db, pSub->pWhere, 0);
    +-    if( subqueryIsAgg ){
    +-      assert( pParent->pHaving==0 );
    +-      pParent->pHaving = pParent->pWhere;
    +-      pParent->pWhere = pWhere;
    +-      pParent->pHaving = sqlite3ExprAnd(db, pParent->pHaving, 
    +-                                  sqlite3ExprDup(db, pSub->pHaving, 0));
    +-      assert( pParent->pGroupBy==0 );
    +-      pParent->pGroupBy = sqlite3ExprListDup(db, pSub->pGroupBy, 0);
    +-    }else{
    +-      pParent->pWhere = sqlite3ExprAnd(db, pParent->pWhere, pWhere);
    +-    }
    +-    substSelect(db, pParent, iParent, pSub->pEList, 0);
    ++    if( isLeftJoin>0 ){
    ++      setJoinExpr(pWhere, iNewParent);
    ++    }
    ++    pParent->pWhere = sqlite3ExprAnd(db, pWhere, pParent->pWhere);
    ++    if( db->mallocFailed==0 ){
    ++      SubstContext x;
    ++      x.pParse = pParse;
    ++      x.iTable = iParent;
    ++      x.iNewTable = iNewParent;
    ++      x.isLeftJoin = isLeftJoin;
    ++      x.pEList = pSub->pEList;
    ++      substSelect(&x, pParent, 0);
    ++    }
    +   
    +     /* The flattened query is distinct if either the inner or the
    +     ** outer query is distinct. 
    +@@ -112374,9 +122505,13 @@ static int flattenSubquery(
    + **
    + ** Do not attempt this optimization if:
    + **
    +-**   (1) The inner query is an aggregate.  (In that case, we'd really want
    +-**       to copy the outer WHERE-clause terms onto the HAVING clause of the
    +-**       inner query.  But they probably won't help there so do not bother.)
    ++**   (1) (** This restriction was removed on 2017-09-29.  We used to
    ++**           disallow this optimization for aggregate subqueries, but now
    ++**           it is allowed by putting the extra terms on the HAVING clause.
    ++**           The added HAVING clause is pointless if the subquery lacks
    ++**           a GROUP BY clause.  But such a HAVING clause is also harmless
    ++**           so there does not appear to be any reason to add extra logic
    ++**           to suppress it. **)
    + **
    + **   (2) The inner query is the recursive part of a common table expression.
    + **
    +@@ -112394,7 +122529,7 @@ static int flattenSubquery(
    + ** terms are duplicated into the subquery.
    + */
    + static int pushDownWhereTerms(
    +-  sqlite3 *db,          /* The database connection (for malloc()) */
    ++  Parse *pParse,        /* Parse context (for malloc() and error reporting) */
    +   Select *pSubq,        /* The subquery whose WHERE clause is to be augmented */
    +   Expr *pWhere,         /* The WHERE clause of the outer query */
    +   int iCursor           /* Cursor number of the subquery */
    +@@ -112402,23 +122537,45 @@ static int pushDownWhereTerms(
    +   Expr *pNew;
    +   int nChng = 0;
    +   if( pWhere==0 ) return 0;
    +-  if( (pSubq->selFlags & (SF_Aggregate|SF_Recursive))!=0 ){
    +-     return 0; /* restrictions (1) and (2) */
    ++  if( pSubq->selFlags & SF_Recursive ) return 0;  /* restriction (2) */
    ++
    ++#ifdef SQLITE_DEBUG
    ++  /* Only the first term of a compound can have a WITH clause.  But make
    ++  ** sure no other terms are marked SF_Recursive in case something changes
    ++  ** in the future.
    ++  */
    ++  {
    ++    Select *pX;  
    ++    for(pX=pSubq; pX; pX=pX->pPrior){
    ++      assert( (pX->selFlags & (SF_Recursive))==0 );
    ++    }
    +   }
    ++#endif
    ++
    +   if( pSubq->pLimit!=0 ){
    +-     return 0; /* restriction (3) */
    ++    return 0; /* restriction (3) */
    +   }
    +   while( pWhere->op==TK_AND ){
    +-    nChng += pushDownWhereTerms(db, pSubq, pWhere->pRight, iCursor);
    ++    nChng += pushDownWhereTerms(pParse, pSubq, pWhere->pRight, iCursor);
    +     pWhere = pWhere->pLeft;
    +   }
    +-  if( ExprHasProperty(pWhere,EP_FromJoin) ) return 0; /* restriction 5 */
    ++  if( ExprHasProperty(pWhere,EP_FromJoin) ) return 0; /* restriction (5) */
    +   if( sqlite3ExprIsTableConstant(pWhere, iCursor) ){
    +     nChng++;
    +     while( pSubq ){
    +-      pNew = sqlite3ExprDup(db, pWhere, 0);
    +-      pNew = substExpr(db, pNew, iCursor, pSubq->pEList);
    +-      pSubq->pWhere = sqlite3ExprAnd(db, pSubq->pWhere, pNew);
    ++      SubstContext x;
    ++      pNew = sqlite3ExprDup(pParse->db, pWhere, 0);
    ++      x.pParse = pParse;
    ++      x.iTable = iCursor;
    ++      x.iNewTable = iCursor;
    ++      x.isLeftJoin = 0;
    ++      x.pEList = pSubq->pEList;
    ++      pNew = substExpr(&x, pNew);
    ++      if( pSubq->selFlags & SF_Aggregate ){
    ++        pSubq->pHaving = sqlite3ExprAnd(pParse->db, pSubq->pHaving, pNew);
    ++      }else{
    ++        pSubq->pWhere = sqlite3ExprAnd(pParse->db, pSubq->pWhere, pNew);
    ++      }
    +       pSubq = pSubq->pPrior;
    +     }
    +   }
    +@@ -112427,42 +122584,44 @@ static int pushDownWhereTerms(
    + #endif /* !defined(SQLITE_OMIT_SUBQUERY) || !defined(SQLITE_OMIT_VIEW) */
    + 
    + /*
    +-** Based on the contents of the AggInfo structure indicated by the first
    +-** argument, this function checks if the following are true:
    ++** The pFunc is the only aggregate function in the query.  Check to see
    ++** if the query is a candidate for the min/max optimization. 
    + **
    +-**    * the query contains just a single aggregate function,
    +-**    * the aggregate function is either min() or max(), and
    +-**    * the argument to the aggregate function is a column value.
    ++** If the query is a candidate for the min/max optimization, then set
    ++** *ppMinMax to be an ORDER BY clause to be used for the optimization
    ++** and return either WHERE_ORDERBY_MIN or WHERE_ORDERBY_MAX depending on
    ++** whether pFunc is a min() or max() function.
    + **
    +-** If all of the above are true, then WHERE_ORDERBY_MIN or WHERE_ORDERBY_MAX
    +-** is returned as appropriate. Also, *ppMinMax is set to point to the 
    +-** list of arguments passed to the aggregate before returning.
    ++** If the query is not a candidate for the min/max optimization, return
    ++** WHERE_ORDERBY_NORMAL (which must be zero).
    + **
    +-** Or, if the conditions above are not met, *ppMinMax is set to 0 and
    +-** WHERE_ORDERBY_NORMAL is returned.
    ++** This routine must be called after aggregate functions have been
    ++** located but before their arguments have been subjected to aggregate
    ++** analysis.
    + */
    +-static u8 minMaxQuery(AggInfo *pAggInfo, ExprList **ppMinMax){
    +-  int eRet = WHERE_ORDERBY_NORMAL;          /* Return value */
    +-
    +-  *ppMinMax = 0;
    +-  if( pAggInfo->nFunc==1 ){
    +-    Expr *pExpr = pAggInfo->aFunc[0].pExpr; /* Aggregate function */
    +-    ExprList *pEList = pExpr->x.pList;      /* Arguments to agg function */
    +-
    +-    assert( pExpr->op==TK_AGG_FUNCTION );
    +-    if( pEList && pEList->nExpr==1 && pEList->a[0].pExpr->op==TK_AGG_COLUMN ){
    +-      const char *zFunc = pExpr->u.zToken;
    +-      if( sqlite3StrICmp(zFunc, "min")==0 ){
    +-        eRet = WHERE_ORDERBY_MIN;
    +-        *ppMinMax = pEList;
    +-      }else if( sqlite3StrICmp(zFunc, "max")==0 ){
    +-        eRet = WHERE_ORDERBY_MAX;
    +-        *ppMinMax = pEList;
    +-      }
    +-    }
    +-  }
    +-
    +-  assert( *ppMinMax==0 || (*ppMinMax)->nExpr==1 );
    ++static u8 minMaxQuery(sqlite3 *db, Expr *pFunc, ExprList **ppMinMax){
    ++  int eRet = WHERE_ORDERBY_NORMAL;      /* Return value */
    ++  ExprList *pEList = pFunc->x.pList;    /* Arguments to agg function */
    ++  const char *zFunc;                    /* Name of aggregate function pFunc */
    ++  ExprList *pOrderBy;
    ++  u8 sortOrder;
    ++
    ++  assert( *ppMinMax==0 );
    ++  assert( pFunc->op==TK_AGG_FUNCTION );
    ++  if( pEList==0 || pEList->nExpr!=1 ) return eRet;
    ++  zFunc = pFunc->u.zToken;
    ++  if( sqlite3StrICmp(zFunc, "min")==0 ){
    ++    eRet = WHERE_ORDERBY_MIN;
    ++    sortOrder = SQLITE_SO_ASC;
    ++  }else if( sqlite3StrICmp(zFunc, "max")==0 ){
    ++    eRet = WHERE_ORDERBY_MAX;
    ++    sortOrder = SQLITE_SO_DESC;
    ++  }else{
    ++    return eRet;
    ++  }
    ++  *ppMinMax = pOrderBy = sqlite3ExprListDup(db, pEList, 0);
    ++  assert( pOrderBy!=0 || db->mallocFailed );
    ++  if( pOrderBy ) pOrderBy->a[0].sortOrder = sortOrder;
    +   return eRet;
    + }
    + 
    +@@ -112578,7 +122737,7 @@ static int convertCompoundSelectToSubquery(Walker *pWalker, Select *p){
    +   if( pNewSrc==0 ) return WRC_Abort;
    +   *pNew = *p;
    +   p->pSrc = pNewSrc;
    +-  p->pEList = sqlite3ExprListAppend(pParse, 0, sqlite3Expr(db, TK_ALL, 0));
    ++  p->pEList = sqlite3ExprListAppend(pParse, 0, sqlite3Expr(db, TK_ASTERISK, 0));
    +   p->op = TK_SELECT;
    +   p->pWhere = 0;
    +   pNew->pGroupBy = 0;
    +@@ -112593,10 +122752,22 @@ static int convertCompoundSelectToSubquery(Walker *pWalker, Select *p){
    +   assert( pNew->pPrior!=0 );
    +   pNew->pPrior->pNext = pNew;
    +   pNew->pLimit = 0;
    +-  pNew->pOffset = 0;
    +   return WRC_Continue;
    + }
    + 
    ++/*
    ++** Check to see if the FROM clause term pFrom has table-valued function
    ++** arguments.  If it does, leave an error message in pParse and return
    ++** non-zero, since pFrom is not allowed to be a table-valued function.
    ++*/
    ++static int cannotBeFunction(Parse *pParse, struct SrcList_item *pFrom){
    ++  if( pFrom->fg.isTabFunc ){
    ++    sqlite3ErrorMsg(pParse, "'%s' is not a function", pFrom->zName);
    ++    return 1;
    ++  }
    ++  return 0;
    ++}
    ++
    + #ifndef SQLITE_OMIT_CTE
    + /*
    + ** Argument pWith (which may be NULL) points to a linked list of nested 
    +@@ -112609,7 +122780,7 @@ static int convertCompoundSelectToSubquery(Walker *pWalker, Select *p){
    + ** object that the returned CTE belongs to.
    + */
    + static struct Cte *searchWith(
    +-  With *pWith,                    /* Current outermost WITH clause */
    ++  With *pWith,                    /* Current innermost WITH clause */
    +   struct SrcList_item *pItem,     /* FROM clause element to resolve */
    +   With **ppContext                /* OUT: WITH clause return value belongs to */
    + ){
    +@@ -112640,11 +122811,12 @@ static struct Cte *searchWith(
    + ** statement with which it is associated.
    + */
    + SQLITE_PRIVATE void sqlite3WithPush(Parse *pParse, With *pWith, u8 bFree){
    +-  assert( bFree==0 || pParse->pWith==0 );
    ++  assert( bFree==0 || (pParse->pWith==0 && pParse->pWithToFree==0) );
    +   if( pWith ){
    ++    assert( pParse->pWith!=pWith );
    +     pWith->pOuter = pParse->pWith;
    +     pParse->pWith = pWith;
    +-    pParse->bFreeWith = bFree;
    ++    if( bFree ) pParse->pWithToFree = pWith;
    +   }
    + }
    + 
    +@@ -112691,17 +122863,18 @@ static int withExpand(
    +       sqlite3ErrorMsg(pParse, pCte->zCteErr, pCte->zName);
    +       return SQLITE_ERROR;
    +     }
    ++    if( cannotBeFunction(pParse, pFrom) ) return SQLITE_ERROR;
    + 
    +     assert( pFrom->pTab==0 );
    +     pFrom->pTab = pTab = sqlite3DbMallocZero(db, sizeof(Table));
    +     if( pTab==0 ) return WRC_Abort;
    +-    pTab->nRef = 1;
    ++    pTab->nTabRef = 1;
    +     pTab->zName = sqlite3DbStrDup(db, pCte->zName);
    +     pTab->iPKey = -1;
    +     pTab->nRowLogEst = 200; assert( 200==sqlite3LogEst(1048576) );
    +     pTab->tabFlags |= TF_Ephemeral | TF_NoVisibleRowid;
    +     pFrom->pSelect = sqlite3SelectDup(db, pCte->pSelect, 0);
    +-    if( db->mallocFailed ) return SQLITE_NOMEM;
    ++    if( db->mallocFailed ) return SQLITE_NOMEM_BKPT;
    +     assert( pFrom->pSelect );
    + 
    +     /* Check if this is a recursive CTE. */
    +@@ -112718,25 +122891,35 @@ static int withExpand(
    +           ){
    +           pItem->pTab = pTab;
    +           pItem->fg.isRecursive = 1;
    +-          pTab->nRef++;
    ++          pTab->nTabRef++;
    +           pSel->selFlags |= SF_Recursive;
    +         }
    +       }
    +     }
    + 
    +     /* Only one recursive reference is permitted. */ 
    +-    if( pTab->nRef>2 ){
    ++    if( pTab->nTabRef>2 ){
    +       sqlite3ErrorMsg(
    +           pParse, "multiple references to recursive table: %s", pCte->zName
    +       );
    +       return SQLITE_ERROR;
    +     }
    +-    assert( pTab->nRef==1 || ((pSel->selFlags&SF_Recursive) && pTab->nRef==2 ));
    ++    assert( pTab->nTabRef==1 || 
    ++            ((pSel->selFlags&SF_Recursive) && pTab->nTabRef==2 ));
    + 
    +     pCte->zCteErr = "circular reference: %s";
    +     pSavedWith = pParse->pWith;
    +     pParse->pWith = pWith;
    +-    sqlite3WalkSelect(pWalker, bMayRecursive ? pSel->pPrior : pSel);
    ++    if( bMayRecursive ){
    ++      Select *pPrior = pSel->pPrior;
    ++      assert( pPrior->pWith==0 );
    ++      pPrior->pWith = pSel->pWith;
    ++      sqlite3WalkSelect(pWalker, pPrior);
    ++      pPrior->pWith = 0;
    ++    }else{
    ++      sqlite3WalkSelect(pWalker, pSel);
    ++    }
    ++    pParse->pWith = pWith;
    + 
    +     for(pLeft=pSel; pLeft->pPrior; pLeft=pLeft->pPrior);
    +     pEList = pLeft->pEList;
    +@@ -112779,10 +122962,12 @@ static int withExpand(
    + */
    + static void selectPopWith(Walker *pWalker, Select *p){
    +   Parse *pParse = pWalker->pParse;
    +-  With *pWith = findRightmost(p)->pWith;
    +-  if( pWith!=0 ){
    +-    assert( pParse->pWith==pWith );
    +-    pParse->pWith = pWith->pOuter;
    ++  if( OK_IF_ALWAYS_TRUE(pParse->pWith) && p->pPrior==0 ){
    ++    With *pWith = findRightmost(p)->pWith;
    ++    if( pWith!=0 ){
    ++      assert( pParse->pWith==pWith );
    ++      pParse->pWith = pWith->pOuter;
    ++    }
    +   }
    + }
    + #else
    +@@ -112822,18 +123007,20 @@ static int selectExpander(Walker *pWalker, Select *p){
    +   sqlite3 *db = pParse->db;
    +   Expr *pE, *pRight, *pExpr;
    +   u16 selFlags = p->selFlags;
    ++  u32 elistFlags = 0;
    + 
    +   p->selFlags |= SF_Expanded;
    +   if( db->mallocFailed  ){
    +     return WRC_Abort;
    +   }
    +-  if( NEVER(p->pSrc==0) || (selFlags & SF_Expanded)!=0 ){
    ++  assert( p->pSrc!=0 );
    ++  if( (selFlags & SF_Expanded)!=0 ){
    +     return WRC_Prune;
    +   }
    +   pTabList = p->pSrc;
    +   pEList = p->pEList;
    +-  if( pWalker->xSelectCallback2==selectPopWith ){
    +-    sqlite3WithPush(pParse, findRightmost(p)->pWith, 0);
    ++  if( OK_IF_ALWAYS_TRUE(p->pWith) ){
    ++    sqlite3WithPush(pParse, p->pWith, 0);
    +   }
    + 
    +   /* Make sure cursor numbers have been assigned to all entries in
    +@@ -112863,8 +123050,12 @@ static int selectExpander(Walker *pWalker, Select *p){
    +       if( sqlite3WalkSelect(pWalker, pSel) ) return WRC_Abort;
    +       pFrom->pTab = pTab = sqlite3DbMallocZero(db, sizeof(Table));
    +       if( pTab==0 ) return WRC_Abort;
    +-      pTab->nRef = 1;
    +-      pTab->zName = sqlite3MPrintf(db, "sqlite_sq_%p", (void*)pTab);
    ++      pTab->nTabRef = 1;
    ++      if( pFrom->zAlias ){
    ++        pTab->zName = sqlite3DbStrDup(db, pFrom->zAlias);
    ++      }else{
    ++        pTab->zName = sqlite3MPrintf(db, "subquery_%p", (void*)pTab);
    ++      }
    +       while( pSel->pPrior ){ pSel = pSel->pPrior; }
    +       sqlite3ColumnsFromExprList(pParse, pSel->pEList,&pTab->nCol,&pTab->aCol);
    +       pTab->iPKey = -1;
    +@@ -112876,22 +123067,21 @@ static int selectExpander(Walker *pWalker, Select *p){
    +       assert( pFrom->pTab==0 );
    +       pFrom->pTab = pTab = sqlite3LocateTableItem(pParse, 0, pFrom);
    +       if( pTab==0 ) return WRC_Abort;
    +-      if( pTab->nRef==0xffff ){
    ++      if( pTab->nTabRef>=0xffff ){
    +         sqlite3ErrorMsg(pParse, "too many references to \"%s\": max 65535",
    +            pTab->zName);
    +         pFrom->pTab = 0;
    +         return WRC_Abort;
    +       }
    +-      pTab->nRef++;
    ++      pTab->nTabRef++;
    ++      if( !IsVirtual(pTab) && cannotBeFunction(pParse, pFrom) ){
    ++        return WRC_Abort;
    ++      }
    + #if !defined(SQLITE_OMIT_VIEW) || !defined (SQLITE_OMIT_VIRTUALTABLE)
    +-      if( pTab->pSelect || IsVirtual(pTab) ){
    ++      if( IsVirtual(pTab) || pTab->pSelect ){
    +         i16 nCol;
    +         if( sqlite3ViewGetColumnNames(pParse, pTab) ) return WRC_Abort;
    +         assert( pFrom->pSelect==0 );
    +-        if( pFrom->fg.isTabFunc && !IsVirtual(pTab) ){
    +-          sqlite3ErrorMsg(pParse, "'%s' is not a function", pTab->zName);
    +-          return WRC_Abort;
    +-        }
    +         pFrom->pSelect = sqlite3SelectDup(db, pTab->pSelect, 0);
    +         sqlite3SelectSetName(pFrom->pSelect, pTab->zName);
    +         nCol = pTab->nCol;
    +@@ -112917,19 +123107,21 @@ static int selectExpander(Walker *pWalker, Select *p){
    +   /* For every "*" that occurs in the column list, insert the names of
    +   ** all columns in all tables.  And for every TABLE.* insert the names
    +   ** of all columns in TABLE.  The parser inserted a special expression
    +-  ** with the TK_ALL operator for each "*" that it found in the column list.
    +-  ** The following code just has to locate the TK_ALL expressions and expand
    +-  ** each one to the list of all columns in all tables.
    ++  ** with the TK_ASTERISK operator for each "*" that it found in the column
    ++  ** list.  The following code just has to locate the TK_ASTERISK
    ++  ** expressions and expand each one to the list of all columns in
    ++  ** all tables.
    +   **
    +   ** The first loop just checks to see if there are any "*" operators
    +   ** that need expanding.
    +   */
    +   for(k=0; k<pEList->nExpr; k++){
    +     pE = pEList->a[k].pExpr;
    +-    if( pE->op==TK_ALL ) break;
    ++    if( pE->op==TK_ASTERISK ) break;
    +     assert( pE->op!=TK_DOT || pE->pRight!=0 );
    +     assert( pE->op!=TK_DOT || (pE->pLeft!=0 && pE->pLeft->op==TK_ID) );
    +-    if( pE->op==TK_DOT && pE->pRight->op==TK_ALL ) break;
    ++    if( pE->op==TK_DOT && pE->pRight->op==TK_ASTERISK ) break;
    ++    elistFlags |= pE->flags;
    +   }
    +   if( k<pEList->nExpr ){
    +     /*
    +@@ -112945,9 +123137,12 @@ static int selectExpander(Walker *pWalker, Select *p){
    + 
    +     for(k=0; k<pEList->nExpr; k++){
    +       pE = a[k].pExpr;
    ++      elistFlags |= pE->flags;
    +       pRight = pE->pRight;
    +       assert( pE->op!=TK_DOT || pRight!=0 );
    +-      if( pE->op!=TK_ALL && (pE->op!=TK_DOT || pRight->op!=TK_ALL) ){
    ++      if( pE->op!=TK_ASTERISK
    ++       && (pE->op!=TK_DOT || pRight->op!=TK_ASTERISK)
    ++      ){
    +         /* This particular expression does not need to be expanded.
    +         */
    +         pNew = sqlite3ExprListAppend(pParse, pNew, a[k].pExpr);
    +@@ -112984,7 +123179,7 @@ static int selectExpander(Walker *pWalker, Select *p){
    +               continue;
    +             }
    +             iDb = sqlite3SchemaToIndex(db, pTab->pSchema);
    +-            zSchemaName = iDb>=0 ? db->aDb[iDb].zName : "*";
    ++            zSchemaName = iDb>=0 ? db->aDb[iDb].zDbSName : "*";
    +           }
    +           for(j=0; j<pTab->nCol; j++){
    +             char *zName = pTab->aCol[j].zName;
    +@@ -112999,12 +123194,13 @@ static int selectExpander(Walker *pWalker, Select *p){
    +               continue;
    +             }
    + 
    +-            /* If a column is marked as 'hidden' (currently only possible
    +-            ** for virtual tables), do not include it in the expanded
    +-            ** result-set list.
    ++            /* If a column is marked as 'hidden', omit it from the expanded
    ++            ** result-set list unless the SELECT has the SF_IncludeHidden
    ++            ** bit set.
    +             */
    +-            if( IsHiddenColumn(&pTab->aCol[j]) ){
    +-              assert(IsVirtual(pTab));
    ++            if( (p->selFlags & SF_IncludeHidden)==0
    ++             && IsHiddenColumn(&pTab->aCol[j]) 
    ++            ){
    +               continue;
    +             }
    +             tableSeen = 1;
    +@@ -113029,10 +123225,10 @@ static int selectExpander(Walker *pWalker, Select *p){
    +             if( longNames || pTabList->nSrc>1 ){
    +               Expr *pLeft;
    +               pLeft = sqlite3Expr(db, TK_ID, zTabName);
    +-              pExpr = sqlite3PExpr(pParse, TK_DOT, pLeft, pRight, 0);
    ++              pExpr = sqlite3PExpr(pParse, TK_DOT, pLeft, pRight);
    +               if( zSchemaName ){
    +                 pLeft = sqlite3Expr(db, TK_ID, zSchemaName);
    +-                pExpr = sqlite3PExpr(pParse, TK_DOT, pLeft, pExpr, 0);
    ++                pExpr = sqlite3PExpr(pParse, TK_DOT, pLeft, pExpr);
    +               }
    +               if( longNames ){
    +                 zColname = sqlite3MPrintf(db, "%s.%s", zTabName, zName);
    +@@ -113042,8 +123238,7 @@ static int selectExpander(Walker *pWalker, Select *p){
    +               pExpr = pRight;
    +             }
    +             pNew = sqlite3ExprListAppend(pParse, pNew, pExpr);
    +-            sColname.z = zColname;
    +-            sColname.n = sqlite3Strlen30(zColname);
    ++            sqlite3TokenInit(&sColname, zColname);
    +             sqlite3ExprListSetName(pParse, pNew, &sColname, 0);
    +             if( pNew && (p->selFlags & SF_NestedFrom)!=0 ){
    +               struct ExprList_item *pX = &pNew->a[pNew->nExpr-1];
    +@@ -113072,11 +123267,15 @@ static int selectExpander(Walker *pWalker, Select *p){
    +     sqlite3ExprListDelete(db, pEList);
    +     p->pEList = pNew;
    +   }
    +-#if SQLITE_MAX_COLUMN
    +-  if( p->pEList && p->pEList->nExpr>db->aLimit[SQLITE_LIMIT_COLUMN] ){
    +-    sqlite3ErrorMsg(pParse, "too many columns in result set");
    ++  if( p->pEList ){
    ++    if( p->pEList->nExpr>db->aLimit[SQLITE_LIMIT_COLUMN] ){
    ++      sqlite3ErrorMsg(pParse, "too many columns in result set");
    ++      return WRC_Abort;
    ++    }
    ++    if( (elistFlags & (EP_HasFunc|EP_Subquery))!=0 ){
    ++      p->selFlags |= SF_ComplexResult;
    ++    }
    +   }
    +-#endif
    +   return WRC_Continue;
    + }
    + 
    +@@ -113089,11 +123288,30 @@ static int selectExpander(Walker *pWalker, Select *p){
    + ** Walker.xSelectCallback is set to do something useful for every 
    + ** subquery in the parser tree.
    + */
    +-static int exprWalkNoop(Walker *NotUsed, Expr *NotUsed2){
    ++SQLITE_PRIVATE int sqlite3ExprWalkNoop(Walker *NotUsed, Expr *NotUsed2){
    ++  UNUSED_PARAMETER2(NotUsed, NotUsed2);
    ++  return WRC_Continue;
    ++}
    ++
    ++/*
    ++** No-op routine for the parse-tree walker for SELECT statements.
    ++** subquery in the parser tree.
    ++*/
    ++SQLITE_PRIVATE int sqlite3SelectWalkNoop(Walker *NotUsed, Select *NotUsed2){
    +   UNUSED_PARAMETER2(NotUsed, NotUsed2);
    +   return WRC_Continue;
    + }
    + 
    ++#if SQLITE_DEBUG
    ++/*
    ++** Always assert.  This xSelectCallback2 implementation proves that the
    ++** xSelectCallback2 is never invoked.
    ++*/
    ++SQLITE_PRIVATE void sqlite3SelectWalkAssert2(Walker *NotUsed, Select *NotUsed2){
    ++  UNUSED_PARAMETER2(NotUsed, NotUsed2);
    ++  assert( 0 );
    ++}
    ++#endif
    + /*
    + ** This routine "expands" a SELECT statement and all of its subqueries.
    + ** For additional information on what it means to "expand" a SELECT
    +@@ -113109,17 +123327,15 @@ static int exprWalkNoop(Walker *NotUsed, Expr *NotUsed2){
    + */
    + static void sqlite3SelectExpand(Parse *pParse, Select *pSelect){
    +   Walker w;
    +-  memset(&w, 0, sizeof(w));
    +-  w.xExprCallback = exprWalkNoop;
    ++  w.xExprCallback = sqlite3ExprWalkNoop;
    +   w.pParse = pParse;
    +-  if( pParse->hasCompound ){
    ++  if( OK_IF_ALWAYS_TRUE(pParse->hasCompound) ){
    +     w.xSelectCallback = convertCompoundSelectToSubquery;
    ++    w.xSelectCallback2 = 0;
    +     sqlite3WalkSelect(&w, pSelect);
    +   }
    +   w.xSelectCallback = selectExpander;
    +-  if( (pSelect->selFlags & SF_MultiValue)==0 ){
    +-    w.xSelectCallback2 = selectPopWith;
    +-  }
    ++  w.xSelectCallback2 = selectPopWith;
    +   sqlite3WalkSelect(&w, pSelect);
    + }
    + 
    +@@ -113157,7 +123373,7 @@ static void selectAddSubqueryTypeInfo(Walker *pWalker, Select *p){
    +       Select *pSel = pFrom->pSelect;
    +       if( pSel ){
    +         while( pSel->pPrior ) pSel = pSel->pPrior;
    +-        selectAddColumnTypeAndCollation(pParse, pTab, pSel);
    ++        sqlite3SelectAddColumnTypeAndCollation(pParse, pTab, pSel);
    +       }
    +     }
    +   }
    +@@ -113175,9 +123391,9 @@ static void selectAddSubqueryTypeInfo(Walker *pWalker, Select *p){
    + static void sqlite3SelectAddTypeInfo(Parse *pParse, Select *pSelect){
    + #ifndef SQLITE_OMIT_SUBQUERY
    +   Walker w;
    +-  memset(&w, 0, sizeof(w));
    ++  w.xSelectCallback = sqlite3SelectWalkNoop;
    +   w.xSelectCallback2 = selectAddSubqueryTypeInfo;
    +-  w.xExprCallback = exprWalkNoop;
    ++  w.xExprCallback = sqlite3ExprWalkNoop;
    +   w.pParse = pParse;
    +   sqlite3WalkSelect(&w, pSelect);
    + #endif
    +@@ -113201,15 +123417,13 @@ SQLITE_PRIVATE void sqlite3SelectPrep(
    +   Select *p,             /* The SELECT statement being coded. */
    +   NameContext *pOuterNC  /* Name context for container */
    + ){
    +-  sqlite3 *db;
    +-  if( NEVER(p==0) ) return;
    +-  db = pParse->db;
    +-  if( db->mallocFailed ) return;
    ++  assert( p!=0 || pParse->db->mallocFailed );
    ++  if( pParse->db->mallocFailed ) return;
    +   if( p->selFlags & SF_HasTypeInfo ) return;
    +   sqlite3SelectExpand(pParse, p);
    +-  if( pParse->nErr || db->mallocFailed ) return;
    ++  if( pParse->nErr || pParse->db->mallocFailed ) return;
    +   sqlite3ResolveSelectNames(pParse, p, pOuterNC);
    +-  if( pParse->nErr || db->mallocFailed ) return;
    ++  if( pParse->nErr || pParse->db->mallocFailed ) return;
    +   sqlite3SelectAddTypeInfo(pParse, p);
    + }
    + 
    +@@ -113269,8 +123483,8 @@ static void finalizeAggFunctions(Parse *pParse, AggInfo *pAggInfo){
    +   for(i=0, pF=pAggInfo->aFunc; i<pAggInfo->nFunc; i++, pF++){
    +     ExprList *pList = pF->pExpr->x.pList;
    +     assert( !ExprHasProperty(pF->pExpr, EP_xIsSelect) );
    +-    sqlite3VdbeAddOp4(v, OP_AggFinal, pF->iMem, pList ? pList->nExpr : 0, 0,
    +-                      (void*)pF->pFunc, P4_FUNCDEF);
    ++    sqlite3VdbeAddOp2(v, OP_AggFinal, pF->iMem, pList ? pList->nExpr : 0);
    ++    sqlite3VdbeAppendP4(v, pF->pFunc, P4_FUNCDEF);
    +   }
    + }
    + 
    +@@ -113321,8 +123535,8 @@ static void updateAccumulator(Parse *pParse, AggInfo *pAggInfo){
    +       if( regHit==0 && pAggInfo->nAccumulator ) regHit = ++pParse->nMem;
    +       sqlite3VdbeAddOp4(v, OP_CollSeq, regHit, 0, 0, (char *)pColl, P4_COLLSEQ);
    +     }
    +-    sqlite3VdbeAddOp4(v, OP_AggStep0, 0, regAgg, pF->iMem,
    +-                      (void*)pF->pFunc, P4_FUNCDEF);
    ++    sqlite3VdbeAddOp3(v, OP_AggStep0, 0, regAgg, pF->iMem);
    ++    sqlite3VdbeAppendP4(v, pF->pFunc, P4_FUNCDEF);
    +     sqlite3VdbeChangeP5(v, (u8)nArg);
    +     sqlite3ExprCacheAffinityChange(pParse, regAgg, nArg);
    +     sqlite3ReleaseTempRange(pParse, regAgg, nArg);
    +@@ -113382,6 +123596,187 @@ static void explainSimpleCount(
    + # define explainSimpleCount(a,b,c)
    + #endif
    + 
    ++/*
    ++** Context object for havingToWhereExprCb().
    ++*/
    ++struct HavingToWhereCtx {
    ++  Expr **ppWhere;
    ++  ExprList *pGroupBy;
    ++};
    ++
    ++/*
    ++** sqlite3WalkExpr() callback used by havingToWhere().
    ++**
    ++** If the node passed to the callback is a TK_AND node, return 
    ++** WRC_Continue to tell sqlite3WalkExpr() to iterate through child nodes.
    ++**
    ++** Otherwise, return WRC_Prune. In this case, also check if the 
    ++** sub-expression matches the criteria for being moved to the WHERE
    ++** clause. If so, add it to the WHERE clause and replace the sub-expression
    ++** within the HAVING expression with a constant "1".
    ++*/
    ++static int havingToWhereExprCb(Walker *pWalker, Expr *pExpr){
    ++  if( pExpr->op!=TK_AND ){
    ++    struct HavingToWhereCtx *p = pWalker->u.pHavingCtx;
    ++    if( sqlite3ExprIsConstantOrGroupBy(pWalker->pParse, pExpr, p->pGroupBy) ){
    ++      sqlite3 *db = pWalker->pParse->db;
    ++      Expr *pNew = sqlite3ExprAlloc(db, TK_INTEGER, &sqlite3IntTokens[1], 0);
    ++      if( pNew ){
    ++        Expr *pWhere = *(p->ppWhere);
    ++        SWAP(Expr, *pNew, *pExpr);
    ++        pNew = sqlite3ExprAnd(db, pWhere, pNew);
    ++        *(p->ppWhere) = pNew;
    ++      }
    ++    }
    ++    return WRC_Prune;
    ++  }
    ++  return WRC_Continue;
    ++}
    ++
    ++/*
    ++** Transfer eligible terms from the HAVING clause of a query, which is
    ++** processed after grouping, to the WHERE clause, which is processed before
    ++** grouping. For example, the query:
    ++**
    ++**   SELECT * FROM <tables> WHERE a=? GROUP BY b HAVING b=? AND c=?
    ++**
    ++** can be rewritten as:
    ++**
    ++**   SELECT * FROM <tables> WHERE a=? AND b=? GROUP BY b HAVING c=?
    ++**
    ++** A term of the HAVING expression is eligible for transfer if it consists
    ++** entirely of constants and expressions that are also GROUP BY terms that
    ++** use the "BINARY" collation sequence.
    ++*/
    ++static void havingToWhere(
    ++  Parse *pParse,
    ++  ExprList *pGroupBy,
    ++  Expr *pHaving, 
    ++  Expr **ppWhere
    ++){
    ++  struct HavingToWhereCtx sCtx;
    ++  Walker sWalker;
    ++
    ++  sCtx.ppWhere = ppWhere;
    ++  sCtx.pGroupBy = pGroupBy;
    ++
    ++  memset(&sWalker, 0, sizeof(sWalker));
    ++  sWalker.pParse = pParse;
    ++  sWalker.xExprCallback = havingToWhereExprCb;
    ++  sWalker.u.pHavingCtx = &sCtx;
    ++  sqlite3WalkExpr(&sWalker, pHaving);
    ++}
    ++
    ++/*
    ++** Check to see if the pThis entry of pTabList is a self-join of a prior view.
    ++** If it is, then return the SrcList_item for the prior view.  If it is not,
    ++** then return 0.
    ++*/
    ++static struct SrcList_item *isSelfJoinView(
    ++  SrcList *pTabList,           /* Search for self-joins in this FROM clause */
    ++  struct SrcList_item *pThis   /* Search for prior reference to this subquery */
    ++){
    ++  struct SrcList_item *pItem;
    ++  for(pItem = pTabList->a; pItem<pThis; pItem++){
    ++    if( pItem->pSelect==0 ) continue;
    ++    if( pItem->fg.viaCoroutine ) continue;
    ++    if( pItem->zName==0 ) continue;
    ++    if( sqlite3_stricmp(pItem->zDatabase, pThis->zDatabase)!=0 ) continue;
    ++    if( sqlite3_stricmp(pItem->zName, pThis->zName)!=0 ) continue;
    ++    if( sqlite3ExprCompare(0, 
    ++          pThis->pSelect->pWhere, pItem->pSelect->pWhere, -1) 
    ++    ){
    ++      /* The view was modified by some other optimization such as
    ++      ** pushDownWhereTerms() */
    ++      continue;
    ++    }
    ++    return pItem;
    ++  }
    ++  return 0;
    ++}
    ++
    ++#ifdef SQLITE_COUNTOFVIEW_OPTIMIZATION
    ++/*
    ++** Attempt to transform a query of the form
    ++**
    ++**    SELECT count(*) FROM (SELECT x FROM t1 UNION ALL SELECT y FROM t2)
    ++**
    ++** Into this:
    ++**
    ++**    SELECT (SELECT count(*) FROM t1)+(SELECT count(*) FROM t2)
    ++**
    ++** The transformation only works if all of the following are true:
    ++**
    ++**   *  The subquery is a UNION ALL of two or more terms
    ++**   *  There is no WHERE or GROUP BY or HAVING clauses on the subqueries
    ++**   *  The outer query is a simple count(*)
    ++**
    ++** Return TRUE if the optimization is undertaken.
    ++*/
    ++static int countOfViewOptimization(Parse *pParse, Select *p){
    ++  Select *pSub, *pPrior;
    ++  Expr *pExpr;
    ++  Expr *pCount;
    ++  sqlite3 *db;
    ++  if( (p->selFlags & SF_Aggregate)==0 ) return 0;   /* This is an aggregate */
    ++  if( p->pEList->nExpr!=1 ) return 0;               /* Single result column */
    ++  pExpr = p->pEList->a[0].pExpr;
    ++  if( pExpr->op!=TK_AGG_FUNCTION ) return 0;        /* Result is an aggregate */
    ++  if( sqlite3_stricmp(pExpr->u.zToken,"count") ) return 0;  /* Is count() */
    ++  if( pExpr->x.pList!=0 ) return 0;                 /* Must be count(*) */
    ++  if( p->pSrc->nSrc!=1 ) return 0;                  /* One table in FROM  */
    ++  pSub = p->pSrc->a[0].pSelect;
    ++  if( pSub==0 ) return 0;                           /* The FROM is a subquery */
    ++  if( pSub->pPrior==0 ) return 0;                   /* Must be a compound ry */
    ++  do{
    ++    if( pSub->op!=TK_ALL && pSub->pPrior ) return 0;  /* Must be UNION ALL */
    ++    if( pSub->pWhere ) return 0;                      /* No WHERE clause */
    ++    if( pSub->selFlags & SF_Aggregate ) return 0;     /* Not an aggregate */
    ++    pSub = pSub->pPrior;                              /* Repeat over compound */
    ++  }while( pSub );
    ++
    ++  /* If we reach this point then it is OK to perform the transformation */
    ++
    ++  db = pParse->db;
    ++  pCount = pExpr;
    ++  pExpr = 0;
    ++  pSub = p->pSrc->a[0].pSelect;
    ++  p->pSrc->a[0].pSelect = 0;
    ++  sqlite3SrcListDelete(db, p->pSrc);
    ++  p->pSrc = sqlite3DbMallocZero(pParse->db, sizeof(*p->pSrc));
    ++  while( pSub ){
    ++    Expr *pTerm;
    ++    pPrior = pSub->pPrior;
    ++    pSub->pPrior = 0;
    ++    pSub->pNext = 0;
    ++    pSub->selFlags |= SF_Aggregate;
    ++    pSub->selFlags &= ~SF_Compound;
    ++    pSub->nSelectRow = 0;
    ++    sqlite3ExprListDelete(db, pSub->pEList);
    ++    pTerm = pPrior ? sqlite3ExprDup(db, pCount, 0) : pCount;
    ++    pSub->pEList = sqlite3ExprListAppend(pParse, 0, pTerm);
    ++    pTerm = sqlite3PExpr(pParse, TK_SELECT, 0, 0);
    ++    sqlite3PExprAddSelect(pParse, pTerm, pSub);
    ++    if( pExpr==0 ){
    ++      pExpr = pTerm;
    ++    }else{
    ++      pExpr = sqlite3PExpr(pParse, TK_PLUS, pTerm, pExpr);
    ++    }
    ++    pSub = pPrior;
    ++  }
    ++  p->pEList->a[0].pExpr = pExpr;
    ++  p->selFlags &= ~SF_Aggregate;
    ++
    ++#if SELECTTRACE_ENABLED
    ++  if( sqlite3SelectTrace & 0x400 ){
    ++    SELECTTRACE(0x400,pParse,p,("After count-of-view optimization:\n"));
    ++    sqlite3TreeViewSelect(0, p, 0);
    ++  }
    ++#endif
    ++  return 1;
    ++}
    ++#endif /* SQLITE_COUNTOFVIEW_OPTIMIZATION */
    ++
    + /*
    + ** Generate code for the SELECT statement given in the p argument.  
    + **
    +@@ -113415,6 +123810,8 @@ SQLITE_PRIVATE int sqlite3Select(
    +   AggInfo sAggInfo;      /* Information used by aggregate queries */
    +   int iEnd;              /* Address of the end of the query */
    +   sqlite3 *db;           /* The database connection */
    ++  ExprList *pMinMaxOrderBy = 0;  /* Added ORDER BY for min/max queries */
    ++  u8 minMaxFlag;                 /* Flag for min/max queries */
    + 
    + #ifndef SQLITE_OMIT_EXPLAIN
    +   int iRestoreSelectId = pParse->iSelectId;
    +@@ -113466,15 +123863,13 @@ SQLITE_PRIVATE int sqlite3Select(
    +   }
    + #endif
    + 
    +-
    +-  /* If writing to memory or generating a set
    +-  ** only a single column may be output.
    +-  */
    +-#ifndef SQLITE_OMIT_SUBQUERY
    +-  if( checkForMultiColumnSelectError(pParse, pDest, p->pEList->nExpr) ){
    +-    goto select_end;
    ++  /* Get a pointer the VDBE under construction, allocating a new VDBE if one
    ++  ** does not already exist */
    ++  v = sqlite3GetVdbe(pParse);
    ++  if( v==0 ) goto select_end;
    ++  if( pDest->eDest==SRT_Output ){
    ++    generateColumnNames(pParse, p);
    +   }
    +-#endif
    + 
    +   /* Try to flatten subqueries in the FROM clause up into the main query
    +   */
    +@@ -113482,7 +123877,6 @@ SQLITE_PRIVATE int sqlite3Select(
    +   for(i=0; !p->pPrior && i<pTabList->nSrc; i++){
    +     struct SrcList_item *pItem = &pTabList->a[i];
    +     Select *pSub = pItem->pSelect;
    +-    int isAggSub;
    +     Table *pTab = pItem->pTab;
    +     if( pSub==0 ) continue;
    + 
    +@@ -113494,13 +123888,45 @@ SQLITE_PRIVATE int sqlite3Select(
    +       goto select_end;
    +     }
    + 
    +-    isAggSub = (pSub->selFlags & SF_Aggregate)!=0;
    +-    if( flattenSubquery(pParse, p, i, isAgg, isAggSub) ){
    ++    /* Do not try to flatten an aggregate subquery.
    ++    **
    ++    ** Flattening an aggregate subquery is only possible if the outer query
    ++    ** is not a join.  But if the outer query is not a join, then the subquery
    ++    ** will be implemented as a co-routine and there is no advantage to
    ++    ** flattening in that case.
    ++    */
    ++    if( (pSub->selFlags & SF_Aggregate)!=0 ) continue;
    ++    assert( pSub->pGroupBy==0 );
    ++
    ++    /* If the outer query contains a "complex" result set (that is,
    ++    ** if the result set of the outer query uses functions or subqueries)
    ++    ** and if the subquery contains an ORDER BY clause and if
    ++    ** it will be implemented as a co-routine, then do not flatten.  This
    ++    ** restriction allows SQL constructs like this:
    ++    **
    ++    **  SELECT expensive_function(x)
    ++    **    FROM (SELECT x FROM tab ORDER BY y LIMIT 10);
    ++    **
    ++    ** The expensive_function() is only computed on the 10 rows that
    ++    ** are output, rather than every row of the table.
    ++    **
    ++    ** The requirement that the outer query have a complex result set
    ++    ** means that flattening does occur on simpler SQL constraints without
    ++    ** the expensive_function() like:
    ++    **
    ++    **  SELECT x FROM (SELECT x FROM tab ORDER BY y LIMIT 10);
    ++    */
    ++    if( pSub->pOrderBy!=0
    ++     && i==0
    ++     && (p->selFlags & SF_ComplexResult)!=0
    ++     && (pTabList->nSrc==1
    ++         || (pTabList->a[1].fg.jointype&(JT_LEFT|JT_CROSS))!=0)
    ++    ){
    ++      continue;
    ++    }
    ++
    ++    if( flattenSubquery(pParse, p, i, isAgg) ){
    +       /* This subquery can be absorbed into its parent. */
    +-      if( isAggSub ){
    +-        isAgg = 1;
    +-        p->selFlags |= SF_Aggregate;
    +-      }
    +       i = -1;
    +     }
    +     pTabList = p->pSrc;
    +@@ -113511,11 +123937,6 @@ SQLITE_PRIVATE int sqlite3Select(
    +   }
    + #endif
    + 
    +-  /* Get a pointer the VDBE under construction, allocating a new VDBE if one
    +-  ** does not already exist */
    +-  v = sqlite3GetVdbe(pParse);
    +-  if( v==0 ) goto select_end;
    +-
    + #ifndef SQLITE_OMIT_COMPOUND_SELECT
    +   /* Handle compound SELECT statements using the separate multiSelect()
    +   ** procedure.
    +@@ -113531,13 +123952,42 @@ SQLITE_PRIVATE int sqlite3Select(
    +   }
    + #endif
    + 
    +-  /* Generate code for all sub-queries in the FROM clause
    ++  /* For each term in the FROM clause, do two things:
    ++  ** (1) Authorized unreferenced tables
    ++  ** (2) Generate code for all sub-queries
    +   */
    +-#if !defined(SQLITE_OMIT_SUBQUERY) || !defined(SQLITE_OMIT_VIEW)
    +   for(i=0; i<pTabList->nSrc; i++){
    +     struct SrcList_item *pItem = &pTabList->a[i];
    +     SelectDest dest;
    +-    Select *pSub = pItem->pSelect;
    ++    Select *pSub;
    ++#if !defined(SQLITE_OMIT_SUBQUERY) || !defined(SQLITE_OMIT_VIEW)
    ++    const char *zSavedAuthContext;
    ++#endif
    ++
    ++    /* Issue SQLITE_READ authorizations with a fake column name for any
    ++    ** tables that are referenced but from which no values are extracted.
    ++    ** Examples of where these kinds of null SQLITE_READ authorizations
    ++    ** would occur:
    ++    **
    ++    **     SELECT count(*) FROM t1;   -- SQLITE_READ t1.""
    ++    **     SELECT t1.* FROM t1, t2;   -- SQLITE_READ t2.""
    ++    **
    ++    ** The fake column name is an empty string.  It is possible for a table to
    ++    ** have a column named by the empty string, in which case there is no way to
    ++    ** distinguish between an unreferenced table and an actual reference to the
    ++    ** "" column. The original design was for the fake column name to be a NULL,
    ++    ** which would be unambiguous.  But legacy authorization callbacks might
    ++    ** assume the column name is non-NULL and segfault.  The use of an empty
    ++    ** string for the fake column name seems safer.
    ++    */
    ++    if( pItem->colUsed==0 ){
    ++      sqlite3AuthCheck(pParse, SQLITE_READ, pItem->zName, "", pItem->zDatabase);
    ++    }
    ++
    ++#if !defined(SQLITE_OMIT_SUBQUERY) || !defined(SQLITE_OMIT_VIEW)
    ++    /* Generate code for all sub-queries in the FROM clause
    ++    */
    ++    pSub = pItem->pSelect;
    +     if( pSub==0 ) continue;
    + 
    +     /* Sometimes the code for a subquery will be generated more than
    +@@ -113548,6 +123998,10 @@ SQLITE_PRIVATE int sqlite3Select(
    +     ** to be invoked again. */
    +     if( pItem->addrFillSub ){
    +       if( pItem->fg.viaCoroutine==0 ){
    ++        /* The subroutine that manifests the view might be a one-time routine,
    ++        ** or it might need to be rerun on each iteration because it
    ++        ** encodes a correlated subquery. */
    ++        testcase( sqlite3VdbeGetOp(v, pItem->addrFillSub)->opcode==OP_Once );
    +         sqlite3VdbeAddOp2(v, OP_Gosub, pItem->regReturn, pItem->addrFillSub);
    +       }
    +       continue;
    +@@ -113566,7 +124020,7 @@ SQLITE_PRIVATE int sqlite3Select(
    +     ** inside the subquery.  This can help the subquery to run more efficiently.
    +     */
    +     if( (pItem->fg.jointype & JT_OUTER)==0
    +-     && pushDownWhereTerms(db, pSub, p->pWhere, pItem->iCursor)
    ++     && pushDownWhereTerms(pParse, pSub, p->pWhere, pItem->iCursor)
    +     ){
    + #if SELECTTRACE_ENABLED
    +       if( sqlite3SelectTrace & 0x100 ){
    +@@ -113576,16 +124030,27 @@ SQLITE_PRIVATE int sqlite3Select(
    + #endif
    +     }
    + 
    ++    zSavedAuthContext = pParse->zAuthContext;
    ++    pParse->zAuthContext = pItem->zName;
    ++
    +     /* Generate code to implement the subquery
    ++    **
    ++    ** The subquery is implemented as a co-routine if the subquery is
    ++    ** guaranteed to be the outer loop (so that it does not need to be
    ++    ** computed more than once)
    ++    **
    ++    ** TODO: Are there other reasons beside (1) to use a co-routine
    ++    ** implementation?
    +     */
    +-    if( pTabList->nSrc==1
    +-     && (p->selFlags & SF_All)==0
    +-     && OptimizationEnabled(db, SQLITE_SubqCoroutine)
    ++    if( i==0
    ++     && (pTabList->nSrc==1
    ++            || (pTabList->a[1].fg.jointype&(JT_LEFT|JT_CROSS))!=0)  /* (1) */
    +     ){
    +       /* Implement a co-routine that will return a single row of the result
    +       ** set on each invocation.
    +       */
    +       int addrTop = sqlite3VdbeCurrentAddr(v)+1;
    ++     
    +       pItem->regReturn = ++pParse->nMem;
    +       sqlite3VdbeAddOp3(v, OP_InitCoroutine, pItem->regReturn, 0, addrTop);
    +       VdbeComment((v, "%s", pItem->pTab->zName));
    +@@ -113593,10 +124058,10 @@ SQLITE_PRIVATE int sqlite3Select(
    +       sqlite3SelectDestInit(&dest, SRT_Coroutine, pItem->regReturn);
    +       explainSetInteger(pItem->iSelectId, (u8)pParse->iNextSelectId);
    +       sqlite3Select(pParse, pSub, &dest);
    +-      pItem->pTab->nRowLogEst = sqlite3LogEst(pSub->nSelectRow);
    ++      pItem->pTab->nRowLogEst = pSub->nSelectRow;
    +       pItem->fg.viaCoroutine = 1;
    +       pItem->regResult = dest.iSdst;
    +-      sqlite3VdbeAddOp1(v, OP_EndCoroutine, pItem->regReturn);
    ++      sqlite3VdbeEndCoroutine(v, pItem->regReturn);
    +       sqlite3VdbeJumpHere(v, addrTop-1);
    +       sqlite3ClearTempRegCache(pParse);
    +     }else{
    +@@ -113608,6 +124073,8 @@ SQLITE_PRIVATE int sqlite3Select(
    +       int topAddr;
    +       int onceAddr = 0;
    +       int retAddr;
    ++      struct SrcList_item *pPrior;
    ++
    +       assert( pItem->addrFillSub==0 );
    +       pItem->regReturn = ++pParse->nMem;
    +       topAddr = sqlite3VdbeAddOp2(v, OP_Integer, 0, pItem->regReturn);
    +@@ -113616,15 +124083,23 @@ SQLITE_PRIVATE int sqlite3Select(
    +         /* If the subquery is not correlated and if we are not inside of
    +         ** a trigger, then we only need to compute the value of the subquery
    +         ** once. */
    +-        onceAddr = sqlite3CodeOnce(pParse); VdbeCoverage(v);
    ++        onceAddr = sqlite3VdbeAddOp0(v, OP_Once); VdbeCoverage(v);
    +         VdbeComment((v, "materialize \"%s\"", pItem->pTab->zName));
    +       }else{
    +         VdbeNoopComment((v, "materialize \"%s\"", pItem->pTab->zName));
    +       }
    +-      sqlite3SelectDestInit(&dest, SRT_EphemTab, pItem->iCursor);
    +-      explainSetInteger(pItem->iSelectId, (u8)pParse->iNextSelectId);
    +-      sqlite3Select(pParse, pSub, &dest);
    +-      pItem->pTab->nRowLogEst = sqlite3LogEst(pSub->nSelectRow);
    ++      pPrior = isSelfJoinView(pTabList, pItem);
    ++      if( pPrior ){
    ++        sqlite3VdbeAddOp2(v, OP_OpenDup, pItem->iCursor, pPrior->iCursor);
    ++        explainSetInteger(pItem->iSelectId, pPrior->iSelectId);
    ++        assert( pPrior->pSelect!=0 );
    ++        pSub->nSelectRow = pPrior->pSelect->nSelectRow;
    ++      }else{
    ++        sqlite3SelectDestInit(&dest, SRT_EphemTab, pItem->iCursor);
    ++        explainSetInteger(pItem->iSelectId, (u8)pParse->iNextSelectId);
    ++        sqlite3Select(pParse, pSub, &dest);
    ++      }
    ++      pItem->pTab->nRowLogEst = pSub->nSelectRow;
    +       if( onceAddr ) sqlite3VdbeJumpHere(v, onceAddr);
    +       retAddr = sqlite3VdbeAddOp1(v, OP_Return, pItem->regReturn);
    +       VdbeComment((v, "end %s", pItem->pTab->zName));
    +@@ -113633,8 +124108,9 @@ SQLITE_PRIVATE int sqlite3Select(
    +     }
    +     if( db->mallocFailed ) goto select_end;
    +     pParse->nHeight -= sqlite3SelectExprHeight(p);
    +-  }
    ++    pParse->zAuthContext = zSavedAuthContext;
    + #endif
    ++  }
    + 
    +   /* Various elements of the SELECT copied into local variables for
    +   ** convenience */
    +@@ -113651,6 +124127,16 @@ SQLITE_PRIVATE int sqlite3Select(
    +   }
    + #endif
    + 
    ++#ifdef SQLITE_COUNTOFVIEW_OPTIMIZATION
    ++  if( OptimizationEnabled(db, SQLITE_QueryFlattener|SQLITE_CountOfView)
    ++   && countOfViewOptimization(pParse, p)
    ++  ){
    ++    if( db->mallocFailed ) goto select_end;
    ++    pEList = p->pEList;
    ++    pTabList = p->pSrc;
    ++  }
    ++#endif
    ++
    +   /* 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:
    +@@ -113675,6 +124161,13 @@ SQLITE_PRIVATE int sqlite3Select(
    +     ** the sDistinct.isTnct is still set.  Hence, isTnct represents the
    +     ** original setting of the SF_Distinct flag, not the current setting */
    +     assert( sDistinct.isTnct );
    ++
    ++#if SELECTTRACE_ENABLED
    ++    if( sqlite3SelectTrace & 0x400 ){
    ++      SELECTTRACE(0x400,pParse,p,("Transform DISTINCT into GROUP BY:\n"));
    ++      sqlite3TreeViewSelect(0, p, 0);
    ++    }
    ++#endif
    +   }
    + 
    +   /* If there is an ORDER BY clause, then create an ephemeral index to
    +@@ -113707,7 +124200,9 @@ SQLITE_PRIVATE int sqlite3Select(
    +   /* Set the limiter.
    +   */
    +   iEnd = sqlite3VdbeMakeLabel(v);
    +-  p->nSelectRow = LARGEST_INT64;
    ++  if( (p->selFlags & SF_FixedLimit)==0 ){
    ++    p->nSelectRow = 320;  /* 4 billion rows */
    ++  }
    +   computeLimitRegisters(pParse, p, iEnd);
    +   if( p->iLimit==0 && sSort.addrSortIndex>=0 ){
    +     sqlite3VdbeChangeOpcode(v, sSort.addrSortIndex, OP_SorterOpen);
    +@@ -113731,10 +124226,12 @@ SQLITE_PRIVATE int sqlite3Select(
    +   if( !isAgg && pGroupBy==0 ){
    +     /* No aggregate functions and no GROUP BY clause */
    +     u16 wctrlFlags = (sDistinct.isTnct ? WHERE_WANT_DISTINCT : 0);
    ++    assert( WHERE_USE_LIMIT==SF_FixedLimit );
    ++    wctrlFlags |= p->selFlags & SF_FixedLimit;
    + 
    +     /* Begin the database scan. */
    +     pWInfo = sqlite3WhereBegin(pParse, pTabList, pWhere, sSort.pOrderBy,
    +-                               p->pEList, wctrlFlags, 0);
    ++                               p->pEList, wctrlFlags, p->nSelectRow);
    +     if( pWInfo==0 ) goto select_end;
    +     if( sqlite3WhereOutputRowCount(pWInfo) < p->nSelectRow ){
    +       p->nSelectRow = sqlite3WhereOutputRowCount(pWInfo);
    +@@ -113744,6 +124241,7 @@ SQLITE_PRIVATE int sqlite3Select(
    +     }
    +     if( sSort.pOrderBy ){
    +       sSort.nOBSat = sqlite3WhereIsOrdered(pWInfo);
    ++      sSort.bOrderedInnerLoop = sqlite3WhereOrderedInnerLoop(pWInfo);
    +       if( sSort.nOBSat==sSort.pOrderBy->nExpr ){
    +         sSort.pOrderBy = 0;
    +       }
    +@@ -113758,7 +124256,8 @@ SQLITE_PRIVATE int sqlite3Select(
    +     }
    + 
    +     /* Use the standard inner loop. */
    +-    selectInnerLoop(pParse, p, pEList, -1, &sSort, &sDistinct, pDest,
    ++    assert( p->pEList==pEList );
    ++    selectInnerLoop(pParse, p, -1, &sSort, &sDistinct, pDest,
    +                     sqlite3WhereContinueLabel(pWInfo),
    +                     sqlite3WhereBreakLabel(pWInfo));
    + 
    +@@ -113794,9 +124293,11 @@ SQLITE_PRIVATE int sqlite3Select(
    +       for(k=pGroupBy->nExpr, pItem=pGroupBy->a; k>0; k--, pItem++){
    +         pItem->u.x.iAlias = 0;
    +       }
    +-      if( p->nSelectRow>100 ) p->nSelectRow = 100;
    ++      assert( 66==sqlite3LogEst(100) );
    ++      if( p->nSelectRow>66 ) p->nSelectRow = 66;
    +     }else{
    +-      p->nSelectRow = 1;
    ++      assert( 0==sqlite3LogEst(1) );
    ++      p->nSelectRow = 0;
    +     }
    + 
    +     /* If there is both a GROUP BY and an ORDER BY clause and they are
    +@@ -113828,9 +124329,19 @@ SQLITE_PRIVATE int sqlite3Select(
    +     sqlite3ExprAnalyzeAggList(&sNC, pEList);
    +     sqlite3ExprAnalyzeAggList(&sNC, sSort.pOrderBy);
    +     if( pHaving ){
    ++      if( pGroupBy ){
    ++        assert( pWhere==p->pWhere );
    ++        havingToWhere(pParse, pGroupBy, pHaving, &p->pWhere);
    ++        pWhere = p->pWhere;
    ++      }
    +       sqlite3ExprAnalyzeAggregates(&sNC, pHaving);
    +     }
    +     sAggInfo.nAccumulator = sAggInfo.nColumn;
    ++    if( p->pGroupBy==0 && p->pHaving==0 && sAggInfo.nFunc==1 ){
    ++      minMaxFlag = minMaxQuery(db, sAggInfo.aFunc[0].pExpr, &pMinMaxOrderBy);
    ++    }else{
    ++      minMaxFlag = WHERE_ORDERBY_NORMAL;
    ++    }
    +     for(i=0; i<sAggInfo.nFunc; i++){
    +       assert( !ExprHasProperty(sAggInfo.aFunc[i].pExpr, EP_xIsSelect) );
    +       sNC.ncFlags |= NC_InAggFunc;
    +@@ -113839,6 +124350,24 @@ SQLITE_PRIVATE int sqlite3Select(
    +     }
    +     sAggInfo.mxReg = pParse->nMem;
    +     if( db->mallocFailed ) goto select_end;
    ++#if SELECTTRACE_ENABLED
    ++    if( sqlite3SelectTrace & 0x400 ){
    ++      int ii;
    ++      SELECTTRACE(0x400,pParse,p,("After aggregate analysis:\n"));
    ++      sqlite3TreeViewSelect(0, p, 0);
    ++      for(ii=0; ii<sAggInfo.nColumn; ii++){
    ++        sqlite3DebugPrintf("agg-column[%d] iMem=%d\n",
    ++            ii, sAggInfo.aCol[ii].iMem);
    ++        sqlite3TreeViewExpr(0, sAggInfo.aCol[ii].pExpr, 0);
    ++      }
    ++      for(ii=0; ii<sAggInfo.nFunc; ii++){
    ++        sqlite3DebugPrintf("agg-func[%d]: iMem=%d\n",
    ++            ii, sAggInfo.aFunc[ii].iMem);
    ++        sqlite3TreeViewExpr(0, sAggInfo.aFunc[ii].pExpr, 0);
    ++      }
    ++    }
    ++#endif
    ++
    + 
    +     /* Processing for aggregates with GROUP BY is very different and
    +     ** much more complex than aggregates without a GROUP BY.
    +@@ -113932,13 +124461,8 @@ SQLITE_PRIVATE int sqlite3Select(
    +           struct AggInfo_col *pCol = &sAggInfo.aCol[i];
    +           if( pCol->iSorterColumn>=j ){
    +             int r1 = j + regBase;
    +-            int r2;
    +-
    +-            r2 = sqlite3ExprCodeGetColumn(pParse, 
    +-                               pCol->pTab, pCol->iColumn, pCol->iTable, r1, 0);
    +-            if( r1!=r2 ){
    +-              sqlite3VdbeAddOp2(v, OP_SCopy, r2, r1);
    +-            }
    ++            sqlite3ExprCodeGetColumnToReg(pParse, 
    ++                               pCol->pTab, pCol->iColumn, pCol->iTable, r1);
    +             j++;
    +           }
    +         }
    +@@ -114059,7 +124583,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, &sSort,
    ++      selectInnerLoop(pParse, p, -1, &sSort,
    +                       &sDistinct, pDest,
    +                       addrOutputRow+1, addrSetAbort);
    +       sqlite3VdbeAddOp1(v, OP_Return, regOutputRow);
    +@@ -114073,7 +124597,6 @@ SQLITE_PRIVATE int sqlite3Select(
    +      
    +     } /* endif pGroupBy.  Begin aggregate queries without GROUP BY: */
    +     else {
    +-      ExprList *pDel = 0;
    + #ifndef SQLITE_OMIT_BTREECOUNT
    +       Table *pTab;
    +       if( (pTab = isSimpleCount(p, &sAggInfo))!=0 ){
    +@@ -114135,66 +124658,31 @@ SQLITE_PRIVATE int sqlite3Select(
    +       }else
    + #endif /* SQLITE_OMIT_BTREECOUNT */
    +       {
    +-        /* Check if the query is of one of the following forms:
    +-        **
    +-        **   SELECT min(x) FROM ...
    +-        **   SELECT max(x) FROM ...
    +-        **
    +-        ** If it is, then ask the code in where.c to attempt to sort results
    +-        ** as if there was an "ORDER ON x" or "ORDER ON x DESC" clause. 
    +-        ** If where.c is able to produce results sorted in this order, then
    +-        ** add vdbe code to break out of the processing loop after the 
    +-        ** first iteration (since the first iteration of the loop is 
    +-        ** guaranteed to operate on the row with the minimum or maximum 
    +-        ** value of x, the only row required).
    +-        **
    +-        ** A special flag must be passed to sqlite3WhereBegin() to slightly
    +-        ** modify behavior as follows:
    +-        **
    +-        **   + If the query is a "SELECT min(x)", then the loop coded by
    +-        **     where.c should not iterate over any values with a NULL value
    +-        **     for x.
    +-        **
    +-        **   + The optimizer code in where.c (the thing that decides which
    +-        **     index or indices to use) should place a different priority on 
    +-        **     satisfying the 'ORDER BY' clause than it does in other cases.
    +-        **     Refer to code and comments in where.c for details.
    +-        */
    +-        ExprList *pMinMax = 0;
    +-        u8 flag = WHERE_ORDERBY_NORMAL;
    +-        
    +-        assert( p->pGroupBy==0 );
    +-        assert( flag==0 );
    +-        if( p->pHaving==0 ){
    +-          flag = minMaxQuery(&sAggInfo, &pMinMax);
    +-        }
    +-        assert( flag==0 || (pMinMax!=0 && pMinMax->nExpr==1) );
    +-
    +-        if( flag ){
    +-          pMinMax = sqlite3ExprListDup(db, pMinMax, 0);
    +-          pDel = pMinMax;
    +-          if( pMinMax && !db->mallocFailed ){
    +-            pMinMax->a[0].sortOrder = flag!=WHERE_ORDERBY_MIN ?1:0;
    +-            pMinMax->a[0].pExpr->op = TK_COLUMN;
    +-          }
    +-        }
    +-  
    +         /* This case runs if the aggregate has no GROUP BY clause.  The
    +         ** processing is much simpler since there is only a single row
    +         ** of output.
    +         */
    ++        assert( p->pGroupBy==0 );
    +         resetAccumulator(pParse, &sAggInfo);
    +-        pWInfo = sqlite3WhereBegin(pParse, pTabList, pWhere, pMinMax,0,flag,0);
    ++
    ++        /* If this query is a candidate for the min/max optimization, then
    ++        ** minMaxFlag will have been previously set to either
    ++        ** WHERE_ORDERBY_MIN or WHERE_ORDERBY_MAX and pMinMaxOrderBy will
    ++        ** be an appropriate ORDER BY expression for the optimization.
    ++        */
    ++        assert( minMaxFlag==WHERE_ORDERBY_NORMAL || pMinMaxOrderBy!=0 );
    ++        assert( pMinMaxOrderBy==0 || pMinMaxOrderBy->nExpr==1 );
    ++
    ++        pWInfo = sqlite3WhereBegin(pParse, pTabList, pWhere, pMinMaxOrderBy,
    ++                                   0, minMaxFlag, 0);
    +         if( pWInfo==0 ){
    +-          sqlite3ExprListDelete(db, pDel);
    +           goto select_end;
    +         }
    +         updateAccumulator(pParse, &sAggInfo);
    +-        assert( pMinMax==0 || pMinMax->nExpr==1 );
    +         if( sqlite3WhereIsOrdered(pWInfo)>0 ){
    +           sqlite3VdbeGoto(v, sqlite3WhereBreakLabel(pWInfo));
    +           VdbeComment((v, "%s() by index",
    +-                (flag==WHERE_ORDERBY_MIN?"min":"max")));
    ++                (minMaxFlag==WHERE_ORDERBY_MIN?"min":"max")));
    +         }
    +         sqlite3WhereEnd(pWInfo);
    +         finalizeAggFunctions(pParse, &sAggInfo);
    +@@ -114202,9 +124690,8 @@ SQLITE_PRIVATE int sqlite3Select(
    + 
    +       sSort.pOrderBy = 0;
    +       sqlite3ExprIfFalse(pParse, pHaving, addrEnd, SQLITE_JUMPIFNULL);
    +-      selectInnerLoop(pParse, p, p->pEList, -1, 0, 0, 
    ++      selectInnerLoop(pParse, p, -1, 0, 0, 
    +                       pDest, addrEnd, addrEnd);
    +-      sqlite3ExprListDelete(db, pDel);
    +     }
    +     sqlite3VdbeResolveLabel(v, addrEnd);
    +     
    +@@ -114236,13 +124723,7 @@ SQLITE_PRIVATE int sqlite3Select(
    +   */
    + select_end:
    +   explainSetInteger(pParse->iSelectId, iRestoreSelectId);
    +-
    +-  /* Identify column names if results of the SELECT are to be output.
    +-  */
    +-  if( rc==SQLITE_OK && pDest->eDest==SRT_Output ){
    +-    generateColumnNames(pParse, pTabList, pEList);
    +-  }
    +-
    ++  sqlite3ExprListDelete(db, pMinMaxOrderBy);
    +   sqlite3DbFree(db, sAggInfo.aCol);
    +   sqlite3DbFree(db, sAggInfo.aFunc);
    + #if SELECTTRACE_ENABLED
    +@@ -114273,8 +124754,6 @@ select_end:
    + ** if they are not used.
    + */
    + /* #include "sqliteInt.h" */
    +-/* #include <stdlib.h> */
    +-/* #include <string.h> */
    + 
    + #ifndef SQLITE_OMIT_GET_TABLE
    + 
    +@@ -114357,7 +124836,7 @@ static int sqlite3_get_table_cb(void *pArg, int nCol, char **argv, char **colv){
    +   return 0;
    + 
    + malloc_failed:
    +-  p->rc = SQLITE_NOMEM;
    ++  p->rc = SQLITE_NOMEM_BKPT;
    +   return 1;
    + }
    + 
    +@@ -114371,7 +124850,7 @@ malloc_failed:
    + ** Instead, the entire table should be passed to sqlite3_free_table() when
    + ** the calling procedure is finished using it.
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_get_table(
    ++SQLITE_API int sqlite3_get_table(
    +   sqlite3 *db,                /* The database on which the SQL executes */
    +   const char *zSql,           /* The SQL to be executed */
    +   char ***pazResult,          /* Write the result table here */
    +@@ -114398,7 +124877,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_get_table(
    +   res.azResult = sqlite3_malloc64(sizeof(char*)*res.nAlloc );
    +   if( res.azResult==0 ){
    +      db->errCode = SQLITE_NOMEM;
    +-     return SQLITE_NOMEM;
    ++     return SQLITE_NOMEM_BKPT;
    +   }
    +   res.azResult[0] = 0;
    +   rc = sqlite3_exec(db, zSql, sqlite3_get_table_cb, &res, pzErrMsg);
    +@@ -114427,7 +124906,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_get_table(
    +     if( azNew==0 ){
    +       sqlite3_free_table(&res.azResult[1]);
    +       db->errCode = SQLITE_NOMEM;
    +-      return SQLITE_NOMEM;
    ++      return SQLITE_NOMEM_BKPT;
    +     }
    +     res.azResult = azNew;
    +   }
    +@@ -114440,7 +124919,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_get_table(
    + /*
    + ** This routine frees the space the sqlite3_get_table() malloced.
    + */
    +-SQLITE_API void SQLITE_STDCALL sqlite3_free_table(
    ++SQLITE_API void sqlite3_free_table(
    +   char **azResult            /* Result returned from sqlite3_get_table() */
    + ){
    +   if( azResult ){
    +@@ -114484,6 +124963,7 @@ SQLITE_PRIVATE void sqlite3DeleteTriggerStep(sqlite3 *db, TriggerStep *pTriggerS
    +     sqlite3ExprListDelete(db, pTmp->pExprList);
    +     sqlite3SelectDelete(db, pTmp->pSelect);
    +     sqlite3IdListDelete(db, pTmp->pIdList);
    ++    sqlite3DbFree(db, pTmp->zSpan);
    + 
    +     sqlite3DbFree(db, pTmp);
    +   }
    +@@ -114555,7 +125035,6 @@ SQLITE_PRIVATE void sqlite3BeginTrigger(
    +   int iDb;                /* The database to store the trigger in */
    +   Token *pName;           /* The unqualified db name */
    +   DbFixer sFix;           /* State vector for the DB fixer */
    +-  int iTabDb;             /* Index of the database holding pTab */
    + 
    +   assert( pName1!=0 );   /* pName1->z might be NULL, but not pName1 itself */
    +   assert( pName2!=0 );
    +@@ -114668,13 +125147,13 @@ SQLITE_PRIVATE void sqlite3BeginTrigger(
    +         " trigger on table: %S", pTableName, 0);
    +     goto trigger_cleanup;
    +   }
    +-  iTabDb = sqlite3SchemaToIndex(db, pTab->pSchema);
    + 
    + #ifndef SQLITE_OMIT_AUTHORIZATION
    +   {
    ++    int iTabDb = sqlite3SchemaToIndex(db, pTab->pSchema);
    +     int code = SQLITE_CREATE_TRIGGER;
    +-    const char *zDb = db->aDb[iTabDb].zName;
    +-    const char *zDbTrig = isTemp ? db->aDb[1].zName : zDb;
    ++    const char *zDb = db->aDb[iTabDb].zDbSName;
    ++    const char *zDbTrig = isTemp ? db->aDb[1].zDbSName : zDb;
    +     if( iTabDb==1 || isTemp ) code = SQLITE_CREATE_TEMP_TRIGGER;
    +     if( sqlite3AuthCheck(pParse, code, zName, pTab->zName, zDbTrig) ){
    +       goto trigger_cleanup;
    +@@ -114746,8 +125225,7 @@ SQLITE_PRIVATE void sqlite3FinishTrigger(
    +     pStepList->pTrig = pTrig;
    +     pStepList = pStepList->pNext;
    +   }
    +-  nameToken.z = pTrig->zName;
    +-  nameToken.n = sqlite3Strlen30(nameToken.z);
    ++  sqlite3TokenInit(&nameToken, pTrig->zName);
    +   sqlite3FixInit(&sFix, pParse, iDb, "trigger", &nameToken);
    +   if( sqlite3FixTriggerStep(&sFix, pTrig->step_list) 
    +    || sqlite3FixExpr(&sFix, pTrig->pWhen) 
    +@@ -114767,9 +125245,10 @@ SQLITE_PRIVATE void sqlite3FinishTrigger(
    +     if( v==0 ) goto triggerfinish_cleanup;
    +     sqlite3BeginWriteOperation(pParse, 0, iDb);
    +     z = sqlite3DbStrNDup(db, (char*)pAll->z, pAll->n);
    ++    testcase( z==0 );
    +     sqlite3NestedParse(pParse,
    +        "INSERT INTO %Q.%s VALUES('trigger',%Q,%Q,0,'CREATE TRIGGER %q')",
    +-       db->aDb[iDb].zName, SCHEMA_TABLE(iDb), zName,
    ++       db->aDb[iDb].zDbSName, MASTER_NAME, zName,
    +        pTrig->table, z);
    +     sqlite3DbFree(db, z);
    +     sqlite3ChangeCookie(pParse, iDb);
    +@@ -114783,7 +125262,7 @@ SQLITE_PRIVATE void sqlite3FinishTrigger(
    +     assert( sqlite3SchemaMutexHeld(db, iDb, 0) );
    +     pTrig = sqlite3HashInsert(pHash, zName, pTrig);
    +     if( pTrig ){
    +-      db->mallocFailed = 1;
    ++      sqlite3OomFault(db);
    +     }else if( pLink->pSchema==pLink->pTabSchema ){
    +       Table *pTab;
    +       pTab = sqlite3HashFind(&pLink->pTabSchema->tblHash, pLink->table);
    +@@ -114799,6 +125278,17 @@ triggerfinish_cleanup:
    +   sqlite3DeleteTriggerStep(db, pStepList);
    + }
    + 
    ++/*
    ++** Duplicate a range of text from an SQL statement, then convert all
    ++** whitespace characters into ordinary space characters.
    ++*/
    ++static char *triggerSpanDup(sqlite3 *db, const char *zStart, const char *zEnd){
    ++  char *z = sqlite3DbSpanDup(db, zStart, zEnd);
    ++  int i;
    ++  if( z ) for(i=0; z[i]; i++) if( sqlite3Isspace(z[i]) ) z[i] = ' ';
    ++  return z;
    ++}    
    ++
    + /*
    + ** Turn a SELECT statement (that the pSelect parameter points to) into
    + ** a trigger step.  Return a pointer to a TriggerStep structure.
    +@@ -114806,7 +125296,12 @@ triggerfinish_cleanup:
    + ** The parser calls this routine when it finds a SELECT statement in
    + ** body of a TRIGGER.  
    + */
    +-SQLITE_PRIVATE TriggerStep *sqlite3TriggerSelectStep(sqlite3 *db, Select *pSelect){
    ++SQLITE_PRIVATE TriggerStep *sqlite3TriggerSelectStep(
    ++  sqlite3 *db,                /* Database connection */
    ++  Select *pSelect,            /* The SELECT statement */
    ++  const char *zStart,         /* Start of SQL text */
    ++  const char *zEnd            /* End of SQL text */
    ++){
    +   TriggerStep *pTriggerStep = sqlite3DbMallocZero(db, sizeof(TriggerStep));
    +   if( pTriggerStep==0 ) {
    +     sqlite3SelectDelete(db, pSelect);
    +@@ -114815,6 +125310,7 @@ SQLITE_PRIVATE TriggerStep *sqlite3TriggerSelectStep(sqlite3 *db, Select *pSelec
    +   pTriggerStep->op = TK_SELECT;
    +   pTriggerStep->pSelect = pSelect;
    +   pTriggerStep->orconf = OE_Default;
    ++  pTriggerStep->zSpan = triggerSpanDup(db, zStart, zEnd);
    +   return pTriggerStep;
    + }
    + 
    +@@ -114827,7 +125323,9 @@ SQLITE_PRIVATE TriggerStep *sqlite3TriggerSelectStep(sqlite3 *db, Select *pSelec
    + static TriggerStep *triggerStepAllocate(
    +   sqlite3 *db,                /* Database connection */
    +   u8 op,                      /* Trigger opcode */
    +-  Token *pName                /* The target name */
    ++  Token *pName,               /* The target name */
    ++  const char *zStart,         /* Start of SQL text */
    ++  const char *zEnd            /* End of SQL text */
    + ){
    +   TriggerStep *pTriggerStep;
    + 
    +@@ -114838,6 +125336,7 @@ static TriggerStep *triggerStepAllocate(
    +     sqlite3Dequote(z);
    +     pTriggerStep->zTarget = z;
    +     pTriggerStep->op = op;
    ++    pTriggerStep->zSpan = triggerSpanDup(db, zStart, zEnd);
    +   }
    +   return pTriggerStep;
    + }
    +@@ -114854,13 +125353,15 @@ SQLITE_PRIVATE TriggerStep *sqlite3TriggerInsertStep(
    +   Token *pTableName,  /* Name of the table into which we insert */
    +   IdList *pColumn,    /* List of columns in pTableName to insert into */
    +   Select *pSelect,    /* A SELECT statement that supplies values */
    +-  u8 orconf           /* The conflict algorithm (OE_Abort, OE_Replace, etc.) */
    ++  u8 orconf,          /* The conflict algorithm (OE_Abort, OE_Replace, etc.) */
    ++  const char *zStart, /* Start of SQL text */
    ++  const char *zEnd    /* End of SQL text */
    + ){
    +   TriggerStep *pTriggerStep;
    + 
    +   assert(pSelect != 0 || db->mallocFailed);
    + 
    +-  pTriggerStep = triggerStepAllocate(db, TK_INSERT, pTableName);
    ++  pTriggerStep = triggerStepAllocate(db, TK_INSERT, pTableName, zStart, zEnd);
    +   if( pTriggerStep ){
    +     pTriggerStep->pSelect = sqlite3SelectDup(db, pSelect, EXPRDUP_REDUCE);
    +     pTriggerStep->pIdList = pColumn;
    +@@ -114883,11 +125384,13 @@ SQLITE_PRIVATE TriggerStep *sqlite3TriggerUpdateStep(
    +   Token *pTableName,   /* Name of the table to be updated */
    +   ExprList *pEList,    /* The SET clause: list of column and new values */
    +   Expr *pWhere,        /* The WHERE clause */
    +-  u8 orconf            /* The conflict algorithm. (OE_Abort, OE_Ignore, etc) */
    ++  u8 orconf,           /* The conflict algorithm. (OE_Abort, OE_Ignore, etc) */
    ++  const char *zStart,  /* Start of SQL text */
    ++  const char *zEnd     /* End of SQL text */
    + ){
    +   TriggerStep *pTriggerStep;
    + 
    +-  pTriggerStep = triggerStepAllocate(db, TK_UPDATE, pTableName);
    ++  pTriggerStep = triggerStepAllocate(db, TK_UPDATE, pTableName, zStart, zEnd);
    +   if( pTriggerStep ){
    +     pTriggerStep->pExprList = sqlite3ExprListDup(db, pEList, EXPRDUP_REDUCE);
    +     pTriggerStep->pWhere = sqlite3ExprDup(db, pWhere, EXPRDUP_REDUCE);
    +@@ -114906,11 +125409,13 @@ SQLITE_PRIVATE TriggerStep *sqlite3TriggerUpdateStep(
    + SQLITE_PRIVATE TriggerStep *sqlite3TriggerDeleteStep(
    +   sqlite3 *db,            /* Database connection */
    +   Token *pTableName,      /* The table from which rows are deleted */
    +-  Expr *pWhere            /* The WHERE clause */
    ++  Expr *pWhere,           /* The WHERE clause */
    ++  const char *zStart,     /* Start of SQL text */
    ++  const char *zEnd        /* End of SQL text */
    + ){
    +   TriggerStep *pTriggerStep;
    + 
    +-  pTriggerStep = triggerStepAllocate(db, TK_DELETE, pTableName);
    ++  pTriggerStep = triggerStepAllocate(db, TK_DELETE, pTableName, zStart, zEnd);
    +   if( pTriggerStep ){
    +     pTriggerStep->pWhere = sqlite3ExprDup(db, pWhere, EXPRDUP_REDUCE);
    +     pTriggerStep->orconf = OE_Default;
    +@@ -114958,7 +125463,7 @@ SQLITE_PRIVATE void sqlite3DropTrigger(Parse *pParse, SrcList *pName, int noErr)
    +   assert( zDb!=0 || sqlite3BtreeHoldsAllMutexes(db) );
    +   for(i=OMIT_TEMPDB; i<db->nDb; i++){
    +     int j = (i<2) ? i^1 : i;  /* Search TEMP before MAIN */
    +-    if( zDb && sqlite3StrICmp(db->aDb[j].zName, zDb) ) continue;
    ++    if( zDb && sqlite3StrICmp(db->aDb[j].zDbSName, zDb) ) continue;
    +     assert( sqlite3SchemaMutexHeld(db, j, 0) );
    +     pTrigger = sqlite3HashFind(&(db->aDb[j].pSchema->trigHash), zName);
    +     if( pTrigger ) break;
    +@@ -115004,7 +125509,7 @@ SQLITE_PRIVATE void sqlite3DropTriggerPtr(Parse *pParse, Trigger *pTrigger){
    + #ifndef SQLITE_OMIT_AUTHORIZATION
    +   {
    +     int code = SQLITE_DROP_TRIGGER;
    +-    const char *zDb = db->aDb[iDb].zName;
    ++    const char *zDb = db->aDb[iDb].zDbSName;
    +     const char *zTab = SCHEMA_TABLE(iDb);
    +     if( iDb==1 ) code = SQLITE_DROP_TEMP_TRIGGER;
    +     if( sqlite3AuthCheck(pParse, code, pTrigger->zName, pTable->zName, zDb) ||
    +@@ -115018,31 +125523,12 @@ SQLITE_PRIVATE void sqlite3DropTriggerPtr(Parse *pParse, Trigger *pTrigger){
    +   */
    +   assert( pTable!=0 );
    +   if( (v = sqlite3GetVdbe(pParse))!=0 ){
    +-    int base;
    +-    static const int iLn = VDBE_OFFSET_LINENO(2);
    +-    static const VdbeOpList dropTrigger[] = {
    +-      { OP_Rewind,     0, ADDR(9),  0},
    +-      { OP_String8,    0, 1,        0}, /* 1 */
    +-      { OP_Column,     0, 1,        2},
    +-      { OP_Ne,         2, ADDR(8),  1},
    +-      { OP_String8,    0, 1,        0}, /* 4: "trigger" */
    +-      { OP_Column,     0, 0,        2},
    +-      { OP_Ne,         2, ADDR(8),  1},
    +-      { OP_Delete,     0, 0,        0},
    +-      { OP_Next,       0, ADDR(1),  0}, /* 8 */
    +-    };
    +-
    +-    sqlite3BeginWriteOperation(pParse, 0, iDb);
    +-    sqlite3OpenMasterTable(pParse, iDb);
    +-    base = sqlite3VdbeAddOpList(v,  ArraySize(dropTrigger), dropTrigger, iLn);
    +-    sqlite3VdbeChangeP4(v, base+1, pTrigger->zName, P4_TRANSIENT);
    +-    sqlite3VdbeChangeP4(v, base+4, "trigger", P4_STATIC);
    ++    sqlite3NestedParse(pParse,
    ++       "DELETE FROM %Q.%s WHERE name=%Q AND type='trigger'",
    ++       db->aDb[iDb].zDbSName, MASTER_NAME, pTrigger->zName
    ++    );
    +     sqlite3ChangeCookie(pParse, iDb);
    +-    sqlite3VdbeAddOp2(v, OP_Close, 0, 0);
    +     sqlite3VdbeAddOp4(v, OP_DropTrigger, iDb, 0, 0, pTrigger->zName, 0);
    +-    if( pParse->nMem<3 ){
    +-      pParse->nMem = 3;
    +-    }
    +   }
    + }
    + 
    +@@ -115064,7 +125550,7 @@ SQLITE_PRIVATE void sqlite3UnlinkAndDeleteTrigger(sqlite3 *db, int iDb, const ch
    +       *pp = (*pp)->pNext;
    +     }
    +     sqlite3DeleteTrigger(db, pTrigger);
    +-    db->flags |= SQLITE_InternChanges;
    ++    db->mDbFlags |= DBFLAG_SchemaChange;
    +   }
    + }
    + 
    +@@ -115142,8 +125628,10 @@ static SrcList *targetSrcList(
    +     pSrc->a[pSrc->nSrc-1].zName = sqlite3DbStrDup(db, pStep->zTarget);
    +     iDb = sqlite3SchemaToIndex(db, pStep->pTrig->pSchema);
    +     if( iDb==0 || iDb>=2 ){
    ++      const char *zDb;
    +       assert( iDb<db->nDb );
    +-      pSrc->a[pSrc->nSrc-1].zDatabase = sqlite3DbStrDup(db, db->aDb[iDb].zName);
    ++      zDb = db->aDb[iDb].zDbSName;
    ++      pSrc->a[pSrc->nSrc-1].zDatabase =  sqlite3DbStrDup(db, zDb);
    +     }
    +   }
    +   return pSrc;
    +@@ -115182,13 +125670,21 @@ static int codeTriggerProgram(
    +     pParse->eOrconf = (orconf==OE_Default)?pStep->orconf:(u8)orconf;
    +     assert( pParse->okConstFactor==0 );
    + 
    ++#ifndef SQLITE_OMIT_TRACE
    ++    if( pStep->zSpan ){
    ++      sqlite3VdbeAddOp4(v, OP_Trace, 0x7fffffff, 1, 0,
    ++                        sqlite3MPrintf(db, "-- %s", pStep->zSpan),
    ++                        P4_DYNAMIC);
    ++    }
    ++#endif
    ++
    +     switch( pStep->op ){
    +       case TK_UPDATE: {
    +         sqlite3Update(pParse, 
    +           targetSrcList(pParse, pStep),
    +           sqlite3ExprListDup(db, pStep->pExprList, 0), 
    +           sqlite3ExprDup(db, pStep->pWhere, 0), 
    +-          pParse->eOrconf
    ++          pParse->eOrconf, 0, 0
    +         );
    +         break;
    +       }
    +@@ -115204,7 +125700,7 @@ static int codeTriggerProgram(
    +       case TK_DELETE: {
    +         sqlite3DeleteFrom(pParse, 
    +           targetSrcList(pParse, pStep),
    +-          sqlite3ExprDup(db, pStep->pWhere, 0)
    ++          sqlite3ExprDup(db, pStep->pWhere, 0), 0, 0
    +         );
    +         break;
    +       }
    +@@ -115322,9 +125818,11 @@ static TriggerPrg *codeRowTrigger(
    +       pTab->zName
    +     ));
    + #ifndef SQLITE_OMIT_TRACE
    +-    sqlite3VdbeChangeP4(v, -1, 
    +-      sqlite3MPrintf(db, "-- TRIGGER %s", pTrigger->zName), P4_DYNAMIC
    +-    );
    ++    if( pTrigger->zName ){
    ++      sqlite3VdbeChangeP4(v, -1, 
    ++        sqlite3MPrintf(db, "-- TRIGGER %s", pTrigger->zName), P4_DYNAMIC
    ++      );
    ++    }
    + #endif
    + 
    +     /* If one was specified, code the WHEN clause. If it evaluates to false
    +@@ -115352,12 +125850,11 @@ static TriggerPrg *codeRowTrigger(
    +     VdbeComment((v, "End: %s.%s", pTrigger->zName, onErrorText(orconf)));
    + 
    +     transferParseError(pParse, pSubParse);
    +-    if( db->mallocFailed==0 ){
    ++    if( db->mallocFailed==0 && pParse->nErr==0 ){
    +       pProgram->aOp = sqlite3VdbeTakeOpArray(v, &pProgram->nOp, &pTop->nMaxArg);
    +     }
    +     pProgram->nMem = pSubParse->nMem;
    +     pProgram->nCsr = pSubParse->nTab;
    +-    pProgram->nOnce = pSubParse->nOnce;
    +     pProgram->token = (void *)pTrigger;
    +     pPrg->aColmask[0] = pSubParse->oldmask;
    +     pPrg->aColmask[1] = pSubParse->newmask;
    +@@ -115430,8 +125927,8 @@ SQLITE_PRIVATE void sqlite3CodeRowTriggerDirect(
    +   if( pPrg ){
    +     int bRecursive = (p->zName && 0==(pParse->db->flags&SQLITE_RecTriggers));
    + 
    +-    sqlite3VdbeAddOp3(v, OP_Program, reg, ignoreJump, ++pParse->nMem);
    +-    sqlite3VdbeChangeP4(v, -1, (const char *)pPrg->pProgram, P4_SUBPROGRAM);
    ++    sqlite3VdbeAddOp4(v, OP_Program, reg, ignoreJump, ++pParse->nMem,
    ++                      (const char *)pPrg->pProgram, P4_SUBPROGRAM);
    +     VdbeComment(
    +         (v, "Call: %s.%s", (p->zName?p->zName:"fkey"), onErrorText(orconf)));
    + 
    +@@ -115650,14 +126147,14 @@ SQLITE_PRIVATE void sqlite3ColumnDefault(Vdbe *v, Table *pTab, int i, int iReg){
    +     sqlite3ValueFromExpr(sqlite3VdbeDb(v), pCol->pDflt, enc, 
    +                          pCol->affinity, &pValue);
    +     if( pValue ){
    +-      sqlite3VdbeChangeP4(v, -1, (const char *)pValue, P4_MEM);
    ++      sqlite3VdbeAppendP4(v, pValue, P4_MEM);
    +     }
    ++  }
    + #ifndef SQLITE_OMIT_FLOATING_POINT
    +-    if( pTab->aCol[i].affinity==SQLITE_AFF_REAL ){
    +-      sqlite3VdbeAddOp1(v, OP_RealAffinity, iReg);
    +-    }
    +-#endif
    ++  if( pTab->aCol[i].affinity==SQLITE_AFF_REAL ){
    ++    sqlite3VdbeAddOp1(v, OP_RealAffinity, iReg);
    +   }
    ++#endif
    + }
    + 
    + /*
    +@@ -115672,7 +126169,9 @@ SQLITE_PRIVATE void sqlite3Update(
    +   SrcList *pTabList,     /* The table in which we should change things */
    +   ExprList *pChanges,    /* Things to be changed */
    +   Expr *pWhere,          /* The WHERE clause.  May be null */
    +-  int onError            /* How to handle constraint errors */
    ++  int onError,           /* How to handle constraint errors */
    ++  ExprList *pOrderBy,    /* ORDER BY clause. May be null */
    ++  Expr *pLimit           /* LIMIT clause. May be null */
    + ){
    +   int i, j;              /* Loop counters */
    +   Table *pTab;           /* The table to be updated */
    +@@ -115686,7 +126185,7 @@ SQLITE_PRIVATE void sqlite3Update(
    +   int iDataCur;          /* Cursor for the canonical data btree */
    +   int iIdxCur;           /* Cursor for the first index */
    +   sqlite3 *db;           /* The database structure */
    +-  int *aRegIdx = 0;      /* One register assigned to each index to be updated */
    ++  int *aRegIdx = 0;      /* First register in array assigned to each index */
    +   int *aXRef = 0;        /* aXRef[i] is the index in pChanges->a[] of the
    +                          ** an expression for the i-th column of the table.
    +                          ** aXRef[i]==-1 if the i-th column is not changed. */
    +@@ -115698,10 +126197,11 @@ SQLITE_PRIVATE void sqlite3Update(
    +   AuthContext sContext;  /* The authorization context */
    +   NameContext sNC;       /* The name-context to resolve expressions in */
    +   int iDb;               /* Database containing the table being updated */
    +-  int okOnePass;         /* True for one-pass algorithm without the FIFO */
    ++  int eOnePass;          /* ONEPASS_XXX value from where.c */
    +   int hasFK;             /* True if foreign key processing is required */
    +   int labelBreak;        /* Jump here to break out of UPDATE loop */
    +   int labelContinue;     /* Jump here to continue next step of UPDATE loop */
    ++  int flags;             /* Flags for sqlite3WhereBegin() */
    + 
    + #ifndef SQLITE_OMIT_TRIGGER
    +   int isView;            /* True when updating a view (INSTEAD OF trigger) */
    +@@ -115712,6 +126212,10 @@ SQLITE_PRIVATE void sqlite3Update(
    +   int iEph = 0;          /* Ephemeral table holding all primary key values */
    +   int nKey = 0;          /* Number of elements in regKey for WITHOUT ROWID */
    +   int aiCurOnePass[2];   /* The write cursors opened by WHERE_ONEPASS */
    ++  int addrOpen = 0;      /* Address of OP_OpenEphemeral */
    ++  int iPk = 0;           /* First of nPk cells holding PRIMARY KEY value */
    ++  i16 nPk = 0;           /* Number of components of the PRIMARY KEY */
    ++  int bReplace = 0;      /* True if REPLACE conflict resolution might happen */
    + 
    +   /* Register Allocations */
    +   int regRowCount = 0;   /* A count of rows changed */
    +@@ -115752,6 +126256,16 @@ SQLITE_PRIVATE void sqlite3Update(
    + # define isView 0
    + #endif
    + 
    ++#ifdef SQLITE_ENABLE_UPDATE_DELETE_LIMIT
    ++  if( !isView ){
    ++    pWhere = sqlite3LimitWhere(
    ++        pParse, pTabList, pWhere, pOrderBy, pLimit, "UPDATE"
    ++    );
    ++    pOrderBy = 0;
    ++    pLimit = 0;
    ++  }
    ++#endif
    ++
    +   if( sqlite3ViewGetColumnNames(pParse, pTab) ){
    +     goto update_cleanup;
    +   }
    +@@ -115778,7 +126292,7 @@ SQLITE_PRIVATE void sqlite3Update(
    +   /* Allocate space for aXRef[], aRegIdx[], and aToOpen[].  
    +   ** Initialize aXRef[] and aToOpen[] to their default values.
    +   */
    +-  aXRef = sqlite3DbMallocRaw(db, sizeof(int) * (pTab->nCol+nIdx) + nIdx+2 );
    ++  aXRef = sqlite3DbMallocRawNN(db, sizeof(int) * (pTab->nCol+nIdx) + nIdx+2 );
    +   if( aXRef==0 ) goto update_cleanup;
    +   aRegIdx = aXRef+pTab->nCol;
    +   aToOpen = (u8*)(aRegIdx+nIdx);
    +@@ -115830,7 +126344,7 @@ SQLITE_PRIVATE void sqlite3Update(
    +       int rc;
    +       rc = sqlite3AuthCheck(pParse, SQLITE_UPDATE, pTab->zName,
    +                             j<0 ? "ROWID" : pTab->aCol[j].zName,
    +-                            db->aDb[iDb].zName);
    ++                            db->aDb[iDb].zDbSName);
    +       if( rc==SQLITE_DENY ){
    +         goto update_cleanup;
    +       }else if( rc==SQLITE_IGNORE ){
    +@@ -115844,10 +126358,12 @@ SQLITE_PRIVATE void sqlite3Update(
    +   assert( chngPk==0 || chngPk==1 );
    +   chngKey = chngRowid + chngPk;
    + 
    +-  /* The SET expressions are not actually used inside the WHERE loop.
    +-  ** So reset the colUsed mask
    ++  /* The SET expressions are not actually used inside the WHERE loop.  
    ++  ** So reset the colUsed mask. Unless this is a virtual table. In that
    ++  ** case, set all bits of the colUsed mask (to ensure that the virtual
    ++  ** table implementation makes all columns available).
    +   */
    +-  pTabList->a[0].colUsed = 0;
    ++  pTabList->a[0].colUsed = IsVirtual(pTab) ? ALLBITS : 0;
    + 
    +   hasFK = sqlite3FkRequired(pParse, pTab, aXRef, chngKey);
    + 
    +@@ -115859,14 +126375,21 @@ SQLITE_PRIVATE void sqlite3Update(
    +   */
    +   for(j=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, j++){
    +     int reg;
    +-    if( chngKey || hasFK || pIdx->pPartIdxWhere || pIdx==pPk ){
    ++    if( chngKey || hasFK>1 || pIdx->pPartIdxWhere || pIdx==pPk ){
    +       reg = ++pParse->nMem;
    ++      pParse->nMem += pIdx->nColumn;
    +     }else{
    +       reg = 0;
    +       for(i=0; i<pIdx->nKeyCol; i++){
    +         i16 iIdxCol = pIdx->aiColumn[i];
    +         if( iIdxCol<0 || aXRef[iIdxCol]>=0 ){
    +           reg = ++pParse->nMem;
    ++          pParse->nMem += pIdx->nColumn;
    ++          if( (onError==OE_Replace)
    ++           || (onError==OE_Default && pIdx->onError==OE_Replace) 
    ++          ){
    ++            bReplace = 1;
    ++          }
    +           break;
    +         }
    +       }
    +@@ -115874,6 +126397,11 @@ SQLITE_PRIVATE void sqlite3Update(
    +     if( reg==0 ) aToOpen[j+1] = 0;
    +     aRegIdx[j] = reg;
    +   }
    ++  if( bReplace ){
    ++    /* If REPLACE conflict resolution might be invoked, open cursors on all 
    ++    ** indexes in case they are needed to delete records.  */
    ++    memset(aToOpen, 1, nIdx+1);
    ++  }
    + 
    +   /* Begin generating code. */
    +   v = sqlite3GetVdbe(pParse);
    +@@ -115906,7 +126434,11 @@ SQLITE_PRIVATE void sqlite3Update(
    +   */
    + #if !defined(SQLITE_OMIT_VIEW) && !defined(SQLITE_OMIT_TRIGGER)
    +   if( isView ){
    +-    sqlite3MaterializeView(pParse, pTab, pWhere, iDataCur);
    ++    sqlite3MaterializeView(pParse, pTab, 
    ++        pWhere, pOrderBy, pLimit, iDataCur
    ++    );
    ++    pOrderBy = 0;
    ++    pLimit = 0;
    +   }
    + #endif
    + 
    +@@ -115926,109 +126458,130 @@ SQLITE_PRIVATE void sqlite3Update(
    +   }
    + #endif
    + 
    +-  /* Begin the database scan
    +-  */
    ++  /* Initialize the count of updated rows */
    ++  if( (db->flags & SQLITE_CountRows) && !pParse->pTriggerTab ){
    ++    regRowCount = ++pParse->nMem;
    ++    sqlite3VdbeAddOp2(v, OP_Integer, 0, regRowCount);
    ++  }
    ++
    +   if( HasRowid(pTab) ){
    +     sqlite3VdbeAddOp3(v, OP_Null, 0, regRowSet, regOldRowid);
    +-    pWInfo = sqlite3WhereBegin(
    +-        pParse, pTabList, pWhere, 0, 0, WHERE_ONEPASS_DESIRED, iIdxCur
    +-    );
    +-    if( pWInfo==0 ) goto update_cleanup;
    +-    okOnePass = sqlite3WhereOkOnePass(pWInfo, aiCurOnePass);
    +-  
    +-    /* Remember the rowid of every item to be updated.
    +-    */
    +-    sqlite3VdbeAddOp2(v, OP_Rowid, iDataCur, regOldRowid);
    +-    if( !okOnePass ){
    +-      sqlite3VdbeAddOp2(v, OP_RowSetAdd, regRowSet, regOldRowid);
    +-    }
    +-  
    +-    /* End the database scan loop.
    +-    */
    +-    sqlite3WhereEnd(pWInfo);
    +   }else{
    +-    int iPk;         /* First of nPk memory cells holding PRIMARY KEY value */
    +-    i16 nPk;         /* Number of components of the PRIMARY KEY */
    +-    int addrOpen;    /* Address of the OpenEphemeral instruction */
    +-
    +     assert( pPk!=0 );
    +     nPk = pPk->nKeyCol;
    +     iPk = pParse->nMem+1;
    +     pParse->nMem += nPk;
    +     regKey = ++pParse->nMem;
    +     iEph = pParse->nTab++;
    ++
    +     sqlite3VdbeAddOp2(v, OP_Null, 0, iPk);
    +     addrOpen = sqlite3VdbeAddOp2(v, OP_OpenEphemeral, iEph, nPk);
    +     sqlite3VdbeSetP4KeyInfo(pParse, pPk);
    +-    pWInfo = sqlite3WhereBegin(pParse, pTabList, pWhere, 0, 0, 
    +-                               WHERE_ONEPASS_DESIRED, iIdxCur);
    +-    if( pWInfo==0 ) goto update_cleanup;
    +-    okOnePass = sqlite3WhereOkOnePass(pWInfo, aiCurOnePass);
    ++  }
    ++
    ++  /* Begin the database scan. 
    ++  **
    ++  ** Do not consider a single-pass strategy for a multi-row update if
    ++  ** there are any triggers or foreign keys to process, or rows may
    ++  ** be deleted as a result of REPLACE conflict handling. Any of these
    ++  ** things might disturb a cursor being used to scan through the table
    ++  ** or index, causing a single-pass approach to malfunction.  */
    ++  flags = WHERE_ONEPASS_DESIRED|WHERE_SEEK_UNIQ_TABLE;
    ++  if( !pParse->nested && !pTrigger && !hasFK && !chngKey && !bReplace ){
    ++    flags |= WHERE_ONEPASS_MULTIROW;
    ++  }
    ++  pWInfo = sqlite3WhereBegin(pParse, pTabList, pWhere, 0, 0, flags, iIdxCur);
    ++  if( pWInfo==0 ) goto update_cleanup;
    ++
    ++  /* A one-pass strategy that might update more than one row may not
    ++  ** be used if any column of the index used for the scan is being
    ++  ** updated. Otherwise, if there is an index on "b", statements like
    ++  ** the following could create an infinite loop:
    ++  **
    ++  **   UPDATE t1 SET b=b+1 WHERE b>?
    ++  **
    ++  ** Fall back to ONEPASS_OFF if where.c has selected a ONEPASS_MULTI
    ++  ** strategy that uses an index for which one or more columns are being
    ++  ** updated.  */
    ++  eOnePass = sqlite3WhereOkOnePass(pWInfo, aiCurOnePass);
    ++  if( eOnePass==ONEPASS_MULTI ){
    ++    int iCur = aiCurOnePass[1];
    ++    if( iCur>=0 && iCur!=iDataCur && aToOpen[iCur-iBaseCur] ){
    ++      eOnePass = ONEPASS_OFF;
    ++    }
    ++    assert( iCur!=iDataCur || !HasRowid(pTab) );
    ++  }
    ++  
    ++  if( HasRowid(pTab) ){
    ++    /* Read the rowid of the current row of the WHERE scan. In ONEPASS_OFF
    ++    ** mode, write the rowid into the FIFO. In either of the one-pass modes,
    ++    ** leave it in register regOldRowid.  */
    ++    sqlite3VdbeAddOp2(v, OP_Rowid, iDataCur, regOldRowid);
    ++    if( eOnePass==ONEPASS_OFF ){
    ++      sqlite3VdbeAddOp2(v, OP_RowSetAdd, regRowSet, regOldRowid);
    ++    }
    ++  }else{
    ++    /* Read the PK of the current row into an array of registers. In
    ++    ** ONEPASS_OFF mode, serialize the array into a record and store it in
    ++    ** the ephemeral table. Or, in ONEPASS_SINGLE or MULTI mode, change
    ++    ** the OP_OpenEphemeral instruction to a Noop (the ephemeral table 
    ++    ** is not required) and leave the PK fields in the array of registers.  */
    +     for(i=0; i<nPk; i++){
    +       assert( pPk->aiColumn[i]>=0 );
    +-      sqlite3ExprCodeGetColumnOfTable(v, pTab, iDataCur, pPk->aiColumn[i],
    +-                                      iPk+i);
    ++      sqlite3ExprCodeGetColumnOfTable(v, pTab, iDataCur,pPk->aiColumn[i],iPk+i);
    +     }
    +-    if( okOnePass ){
    ++    if( eOnePass ){
    +       sqlite3VdbeChangeToNoop(v, addrOpen);
    +       nKey = nPk;
    +       regKey = iPk;
    +     }else{
    +       sqlite3VdbeAddOp4(v, OP_MakeRecord, iPk, nPk, regKey,
    +                         sqlite3IndexAffinityStr(db, pPk), nPk);
    +-      sqlite3VdbeAddOp2(v, OP_IdxInsert, iEph, regKey);
    ++      sqlite3VdbeAddOp4Int(v, OP_IdxInsert, iEph, regKey, iPk, nPk);
    +     }
    +-    sqlite3WhereEnd(pWInfo);
    +   }
    + 
    +-  /* Initialize the count of updated rows
    +-  */
    +-  if( (db->flags & SQLITE_CountRows) && !pParse->pTriggerTab ){
    +-    regRowCount = ++pParse->nMem;
    +-    sqlite3VdbeAddOp2(v, OP_Integer, 0, regRowCount);
    ++  if( eOnePass!=ONEPASS_MULTI ){
    ++    sqlite3WhereEnd(pWInfo);
    +   }
    + 
    +   labelBreak = sqlite3VdbeMakeLabel(v);
    +   if( !isView ){
    +-    /* 
    +-    ** Open every index that needs updating.  Note that if any
    +-    ** index could potentially invoke a REPLACE conflict resolution 
    +-    ** action, then we need to open all indices because we might need
    +-    ** to be deleting some records.
    +-    */
    +-    if( onError==OE_Replace ){
    +-      memset(aToOpen, 1, nIdx+1);
    +-    }else{
    +-      for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){
    +-        if( pIdx->onError==OE_Replace ){
    +-          memset(aToOpen, 1, nIdx+1);
    +-          break;
    +-        }
    +-      }
    +-    }
    +-    if( okOnePass ){
    ++    int addrOnce = 0;
    ++
    ++    /* Open every index that needs updating. */
    ++    if( eOnePass!=ONEPASS_OFF ){
    +       if( aiCurOnePass[0]>=0 ) aToOpen[aiCurOnePass[0]-iBaseCur] = 0;
    +       if( aiCurOnePass[1]>=0 ) aToOpen[aiCurOnePass[1]-iBaseCur] = 0;
    +     }
    +-    sqlite3OpenTableAndIndices(pParse, pTab, OP_OpenWrite, iBaseCur, aToOpen,
    ++
    ++    if( eOnePass==ONEPASS_MULTI && (nIdx-(aiCurOnePass[1]>=0))>0 ){
    ++      addrOnce = sqlite3VdbeAddOp0(v, OP_Once); VdbeCoverage(v);
    ++    }
    ++    sqlite3OpenTableAndIndices(pParse, pTab, OP_OpenWrite, 0, iBaseCur, aToOpen,
    +                                0, 0);
    ++    if( addrOnce ) sqlite3VdbeJumpHere(v, addrOnce);
    +   }
    + 
    +   /* Top of the update loop */
    +-  if( okOnePass ){
    +-    if( aToOpen[iDataCur-iBaseCur] && !isView ){
    ++  if( eOnePass!=ONEPASS_OFF ){
    ++    if( !isView && aiCurOnePass[0]!=iDataCur && aiCurOnePass[1]!=iDataCur ){
    +       assert( pPk );
    +       sqlite3VdbeAddOp4Int(v, OP_NotFound, iDataCur, labelBreak, regKey, nKey);
    +       VdbeCoverageNeverTaken(v);
    +     }
    +-    labelContinue = labelBreak;
    ++    if( eOnePass==ONEPASS_SINGLE ){
    ++      labelContinue = labelBreak;
    ++    }else{
    ++      labelContinue = sqlite3VdbeMakeLabel(v);
    ++    }
    +     sqlite3VdbeAddOp2(v, OP_IsNull, pPk ? regKey : regOldRowid, labelBreak);
    +     VdbeCoverageIf(v, pPk==0);
    +     VdbeCoverageIf(v, pPk!=0);
    +   }else if( pPk ){
    +     labelContinue = sqlite3VdbeMakeLabel(v);
    +     sqlite3VdbeAddOp2(v, OP_Rewind, iEph, labelBreak); VdbeCoverage(v);
    +-    addrTop = sqlite3VdbeAddOp2(v, OP_RowKey, iEph, regKey);
    ++    addrTop = sqlite3VdbeAddOp2(v, OP_RowData, iEph, regKey);
    +     sqlite3VdbeAddOp4Int(v, OP_NotFound, iDataCur, labelContinue, regKey, 0);
    +     VdbeCoverage(v);
    +   }else{
    +@@ -116103,7 +126656,7 @@ SQLITE_PRIVATE void sqlite3Update(
    +         */
    +         testcase( i==31 );
    +         testcase( i==32 );
    +-        sqlite3ExprCodeGetColumnOfTable(v, pTab, iDataCur, i, regNew+i);
    ++        sqlite3ExprCodeGetColumnToReg(pParse, pTab, i, iDataCur, regNew+i);
    +       }else{
    +         sqlite3VdbeAddOp2(v, OP_Null, 0, regNew+i);
    +       }
    +@@ -116146,12 +126699,12 @@ SQLITE_PRIVATE void sqlite3Update(
    + 
    +   if( !isView ){
    +     int addr1 = 0;        /* Address of jump instruction */
    +-    int bReplace = 0;     /* True if REPLACE conflict resolution might happen */
    + 
    +     /* Do constraint checks. */
    +     assert( regOldRowid>0 );
    +     sqlite3GenerateConstraintChecks(pParse, pTab, aRegIdx, iDataCur, iIdxCur,
    +-        regNewRowid, regOldRowid, chngKey, onError, labelContinue, &bReplace);
    ++        regNewRowid, regOldRowid, chngKey, onError, labelContinue, &bReplace,
    ++        aXRef);
    + 
    +     /* Do FK constraint checks. */
    +     if( hasFK ){
    +@@ -116168,11 +126721,34 @@ SQLITE_PRIVATE void sqlite3Update(
    +       VdbeCoverageNeverTaken(v);
    +     }
    +     sqlite3GenerateRowIndexDelete(pParse, pTab, iDataCur, iIdxCur, aRegIdx, -1);
    +-  
    +-    /* If changing the record number, delete the old record.  */
    +-    if( hasFK || chngKey || pPk!=0 ){
    ++
    ++    /* If changing the rowid value, or if there are foreign key constraints
    ++    ** to process, delete the old record. Otherwise, add a noop OP_Delete
    ++    ** to invoke the pre-update hook.
    ++    **
    ++    ** That (regNew==regnewRowid+1) is true is also important for the 
    ++    ** pre-update hook. If the caller invokes preupdate_new(), the returned
    ++    ** value is copied from memory cell (regNewRowid+1+iCol), where iCol
    ++    ** is the column index supplied by the user.
    ++    */
    ++    assert( regNew==regNewRowid+1 );
    ++#ifdef SQLITE_ENABLE_PREUPDATE_HOOK
    ++    sqlite3VdbeAddOp3(v, OP_Delete, iDataCur,
    ++        OPFLAG_ISUPDATE | ((hasFK>1 || chngKey) ? 0 : OPFLAG_ISNOOP),
    ++        regNewRowid
    ++    );
    ++    if( eOnePass==ONEPASS_MULTI ){
    ++      assert( hasFK==0 && chngKey==0 );
    ++      sqlite3VdbeChangeP5(v, OPFLAG_SAVEPOSITION);
    ++    }
    ++    if( !pParse->nested ){
    ++      sqlite3VdbeAppendP4(v, pTab, P4_TABLE);
    ++    }
    ++#else
    ++    if( hasFK>1 || chngKey ){
    +       sqlite3VdbeAddOp2(v, OP_Delete, iDataCur, 0);
    +     }
    ++#endif
    +     if( bReplace || chngKey ){
    +       sqlite3VdbeJumpHere(v, addr1);
    +     }
    +@@ -116182,8 +126758,11 @@ SQLITE_PRIVATE void sqlite3Update(
    +     }
    +   
    +     /* Insert the new index entries and the new record. */
    +-    sqlite3CompleteInsertion(pParse, pTab, iDataCur, iIdxCur,
    +-                             regNewRowid, aRegIdx, 1, 0, 0);
    ++    sqlite3CompleteInsertion(
    ++        pParse, pTab, iDataCur, iIdxCur, regNewRowid, aRegIdx, 
    ++        OPFLAG_ISUPDATE | (eOnePass==ONEPASS_MULTI ? OPFLAG_SAVEPOSITION : 0), 
    ++        0, 0
    ++    );
    + 
    +     /* Do any ON CASCADE, SET NULL or SET DEFAULT operations required to
    +     ** handle rows (possibly in other tables) that refer via a foreign key
    +@@ -116205,8 +126784,11 @@ SQLITE_PRIVATE void sqlite3Update(
    +   /* Repeat the above with the next record to be updated, until
    +   ** all record selected by the WHERE clause have been updated.
    +   */
    +-  if( okOnePass ){
    ++  if( eOnePass==ONEPASS_SINGLE ){
    +     /* Nothing to do at end-of-loop for a single-pass */
    ++  }else if( eOnePass==ONEPASS_MULTI ){
    ++    sqlite3VdbeResolveLabel(v, labelContinue);
    ++    sqlite3WhereEnd(pWInfo);
    +   }else if( pPk ){
    +     sqlite3VdbeResolveLabel(v, labelContinue);
    +     sqlite3VdbeAddOp2(v, OP_Next, iEph, addrTop); VdbeCoverage(v);
    +@@ -116215,15 +126797,6 @@ SQLITE_PRIVATE void sqlite3Update(
    +   }
    +   sqlite3VdbeResolveLabel(v, labelBreak);
    + 
    +-  /* Close all tables */
    +-  for(i=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, i++){
    +-    assert( aRegIdx );
    +-    if( aToOpen[i+1] ){
    +-      sqlite3VdbeAddOp2(v, OP_Close, iIdxCur+i, 0);
    +-    }
    +-  }
    +-  if( iDataCur<iIdxCur ) sqlite3VdbeAddOp2(v, OP_Close, iDataCur, 0);
    +-
    +   /* Update the sqlite_sequence table by storing the content of the
    +   ** maximum rowid counter values recorded while inserting into
    +   ** autoincrement tables.
    +@@ -116249,6 +126822,10 @@ update_cleanup:
    +   sqlite3SrcListDelete(db, pTabList);
    +   sqlite3ExprListDelete(db, pChanges);
    +   sqlite3ExprDelete(db, pWhere);
    ++#if defined(SQLITE_ENABLE_UPDATE_DELETE_LIMIT) 
    ++  sqlite3ExprListDelete(db, pOrderBy);
    ++  sqlite3ExprDelete(db, pLimit);
    ++#endif
    +   return;
    + }
    + /* Make sure "isView" and other macros defined above are undefined. Otherwise
    +@@ -116308,7 +126885,7 @@ static void updateVirtualTable(
    +   int bOnePass;                   /* True to use onepass strategy */
    +   int addr;                       /* Address of OP_OpenEphemeral */
    + 
    +-  /* Allocate nArg registers to martial the arguments to VUpdate. Then
    ++  /* Allocate nArg registers in which to gather the arguments for VUpdate. Then
    +   ** create and open the ephemeral table in which the records created from
    +   ** these arguments will be temporarily stored. */
    +   assert( v );
    +@@ -116324,19 +126901,31 @@ static void updateVirtualTable(
    +   if( pWInfo==0 ) return;
    + 
    +   /* Populate the argument registers. */
    +-  sqlite3VdbeAddOp2(v, OP_Rowid, iCsr, regArg);
    +-  if( pRowid ){
    +-    sqlite3ExprCode(pParse, pRowid, regArg+1);
    +-  }else{
    +-    sqlite3VdbeAddOp2(v, OP_Rowid, iCsr, regArg+1);
    +-  }
    +   for(i=0; i<pTab->nCol; i++){
    +     if( aXRef[i]>=0 ){
    +       sqlite3ExprCode(pParse, pChanges->a[aXRef[i]].pExpr, regArg+2+i);
    +     }else{
    +       sqlite3VdbeAddOp3(v, OP_VColumn, iCsr, i, regArg+2+i);
    ++      sqlite3VdbeChangeP5(v, 1); /* Enable sqlite3_vtab_nochange() */
    +     }
    +   }
    ++  if( HasRowid(pTab) ){
    ++    sqlite3VdbeAddOp2(v, OP_Rowid, iCsr, regArg);
    ++    if( pRowid ){
    ++      sqlite3ExprCode(pParse, pRowid, regArg+1);
    ++    }else{
    ++      sqlite3VdbeAddOp2(v, OP_Rowid, iCsr, regArg+1);
    ++    }
    ++  }else{
    ++    Index *pPk;   /* PRIMARY KEY index */
    ++    i16 iPk;      /* PRIMARY KEY column */
    ++    pPk = sqlite3PrimaryKeyIndex(pTab);
    ++    assert( pPk!=0 );
    ++    assert( pPk->nKeyCol==1 );
    ++    iPk = pPk->aiColumn[0];
    ++    sqlite3VdbeAddOp3(v, OP_VColumn, iCsr, iPk, regArg);
    ++    sqlite3VdbeAddOp2(v, OP_SCopy, regArg+2+iPk, regArg+1);
    ++  }
    + 
    +   bOnePass = sqlite3WhereOkOnePass(pWInfo, aDummy);
    + 
    +@@ -116352,6 +126941,11 @@ static void updateVirtualTable(
    +     /* Create a record from the argument register contents and insert it into
    +     ** the ephemeral table. */
    +     sqlite3VdbeAddOp3(v, OP_MakeRecord, regArg, nArg, regRec);
    ++#ifdef SQLITE_DEBUG
    ++    /* Signal an assert() within OP_MakeRecord that it is allowed to
    ++    ** accept no-change records with serial_type 10 */
    ++    sqlite3VdbeChangeP5(v, OPFLAG_NOCHNG_MAGIC);
    ++#endif
    +     sqlite3VdbeAddOp2(v, OP_NewRowid, ephemTab, regRowid);
    +     sqlite3VdbeAddOp3(v, OP_Insert, ephemTab, regRec, regRowid);
    +   }
    +@@ -116409,57 +127003,52 @@ static void updateVirtualTable(
    + /* #include "vdbeInt.h" */
    + 
    + #if !defined(SQLITE_OMIT_VACUUM) && !defined(SQLITE_OMIT_ATTACH)
    +-/*
    +-** Finalize a prepared statement.  If there was an error, store the
    +-** text of the error message in *pzErrMsg.  Return the result code.
    +-*/
    +-static int vacuumFinalize(sqlite3 *db, sqlite3_stmt *pStmt, char **pzErrMsg){
    +-  int rc;
    +-  rc = sqlite3VdbeFinalize((Vdbe*)pStmt);
    +-  if( rc ){
    +-    sqlite3SetString(pzErrMsg, db, sqlite3_errmsg(db));
    +-  }
    +-  return rc;
    +-}
    + 
    + /*
    +-** Execute zSql on database db. Return an error code.
    ++** Execute zSql on database db.
    ++**
    ++** If zSql returns rows, then each row will have exactly one
    ++** column.  (This will only happen if zSql begins with "SELECT".)
    ++** Take each row of result and call execSql() again recursively.
    ++**
    ++** The execSqlF() routine does the same thing, except it accepts
    ++** a format string as its third argument
    + */
    + static int execSql(sqlite3 *db, char **pzErrMsg, const char *zSql){
    +-  sqlite3_stmt *pStmt;
    +-  VVA_ONLY( int rc; )
    +-  if( !zSql ){
    +-    return SQLITE_NOMEM;
    +-  }
    +-  if( SQLITE_OK!=sqlite3_prepare(db, zSql, -1, &pStmt, 0) ){
    +-    sqlite3SetString(pzErrMsg, db, sqlite3_errmsg(db));
    +-    return sqlite3_errcode(db);
    +-  }
    +-  VVA_ONLY( rc = ) sqlite3_step(pStmt);
    +-  assert( rc!=SQLITE_ROW || (db->flags&SQLITE_CountRows) );
    +-  return vacuumFinalize(db, pStmt, pzErrMsg);
    +-}
    +-
    +-/*
    +-** Execute zSql on database db. The statement returns exactly
    +-** one column. Execute this as SQL on the same database.
    +-*/
    +-static int execExecSql(sqlite3 *db, char **pzErrMsg, const char *zSql){
    +   sqlite3_stmt *pStmt;
    +   int rc;
    + 
    +-  rc = sqlite3_prepare(db, zSql, -1, &pStmt, 0);
    ++  /* printf("SQL: [%s]\n", zSql); fflush(stdout); */
    ++  rc = sqlite3_prepare_v2(db, zSql, -1, &pStmt, 0);
    +   if( rc!=SQLITE_OK ) return rc;
    +-
    +-  while( SQLITE_ROW==sqlite3_step(pStmt) ){
    +-    rc = execSql(db, pzErrMsg, (char*)sqlite3_column_text(pStmt, 0));
    +-    if( rc!=SQLITE_OK ){
    +-      vacuumFinalize(db, pStmt, pzErrMsg);
    +-      return rc;
    ++  while( SQLITE_ROW==(rc = sqlite3_step(pStmt)) ){
    ++    const char *zSubSql = (const char*)sqlite3_column_text(pStmt,0);
    ++    assert( sqlite3_strnicmp(zSql,"SELECT",6)==0 );
    ++    if( zSubSql ){
    ++      assert( zSubSql[0]!='S' );
    ++      rc = execSql(db, pzErrMsg, zSubSql);
    ++      if( rc!=SQLITE_OK ) break;
    +     }
    +   }
    +-
    +-  return vacuumFinalize(db, pStmt, pzErrMsg);
    ++  assert( rc!=SQLITE_ROW );
    ++  if( rc==SQLITE_DONE ) rc = SQLITE_OK;
    ++  if( rc ){
    ++    sqlite3SetString(pzErrMsg, db, sqlite3_errmsg(db));
    ++  }
    ++  (void)sqlite3_finalize(pStmt);
    ++  return rc;
    ++}
    ++static int execSqlF(sqlite3 *db, char **pzErrMsg, const char *zSql, ...){
    ++  char *z;
    ++  va_list ap;
    ++  int rc;
    ++  va_start(ap, zSql);
    ++  z = sqlite3VMPrintf(db, zSql, ap);
    ++  va_end(ap);
    ++  if( z==0 ) return SQLITE_NOMEM;
    ++  rc = execSql(db, pzErrMsg, z);
    ++  sqlite3DbFree(db, z);
    ++  return rc;
    + }
    + 
    + /*
    +@@ -116492,11 +127081,29 @@ static int execExecSql(sqlite3 *db, char **pzErrMsg, const char *zSql){
    + ** transient would cause the database file to appear to be deleted
    + ** following reboot.
    + */
    +-SQLITE_PRIVATE void sqlite3Vacuum(Parse *pParse){
    ++SQLITE_PRIVATE void sqlite3Vacuum(Parse *pParse, Token *pNm){
    +   Vdbe *v = sqlite3GetVdbe(pParse);
    +-  if( v ){
    +-    sqlite3VdbeAddOp2(v, OP_Vacuum, 0, 0);
    +-    sqlite3VdbeUsesBtree(v, 0);
    ++  int iDb = 0;
    ++  if( v==0 ) return;
    ++  if( pNm ){
    ++#ifndef SQLITE_BUG_COMPATIBLE_20160819
    ++    /* Default behavior:  Report an error if the argument to VACUUM is
    ++    ** not recognized */
    ++    iDb = sqlite3TwoPartName(pParse, pNm, pNm, &pNm);
    ++    if( iDb<0 ) return;
    ++#else
    ++    /* When SQLITE_BUG_COMPATIBLE_20160819 is defined, unrecognized arguments
    ++    ** to VACUUM are silently ignored.  This is a back-out of a bug fix that
    ++    ** occurred on 2016-08-19 (https://www.sqlite.org/src/info/083f9e6270).
    ++    ** The buggy behavior is required for binary compatibility with some
    ++    ** legacy applications. */
    ++    iDb = sqlite3FindDb(pParse->db, pNm);
    ++    if( iDb<0 ) iDb = 0;
    ++#endif
    ++  }
    ++  if( iDb!=1 ){
    ++    sqlite3VdbeAddOp1(v, OP_Vacuum, iDb);
    ++    sqlite3VdbeUsesBtree(v, iDb);
    +   }
    +   return;
    + }
    +@@ -116504,19 +127111,20 @@ SQLITE_PRIVATE void sqlite3Vacuum(Parse *pParse){
    + /*
    + ** This routine implements the OP_Vacuum opcode of the VDBE.
    + */
    +-SQLITE_PRIVATE int sqlite3RunVacuum(char **pzErrMsg, sqlite3 *db){
    ++SQLITE_PRIVATE int sqlite3RunVacuum(char **pzErrMsg, sqlite3 *db, int iDb){
    +   int rc = SQLITE_OK;     /* Return code from service routines */
    +   Btree *pMain;           /* The database being vacuumed */
    +   Btree *pTemp;           /* The temporary database we vacuum into */
    +-  char *zSql = 0;         /* SQL statements */
    +-  int saved_flags;        /* Saved value of the db->flags */
    ++  u16 saved_mDbFlags;     /* Saved value of db->mDbFlags */
    ++  u32 saved_flags;        /* Saved value of db->flags */
    +   int saved_nChange;      /* Saved value of db->nChange */
    +   int saved_nTotalChange; /* Saved value of db->nTotalChange */
    +-  void (*saved_xTrace)(void*,const char*);  /* Saved db->xTrace */
    ++  u8 saved_mTrace;        /* Saved trace settings */
    +   Db *pDb = 0;            /* Database to detach at end of vacuum */
    +   int isMemDb;            /* True if vacuuming a :memory: database */
    +   int nRes;               /* Bytes of reserved space at the end of each page */
    +   int nDb;                /* Number of attached databases */
    ++  const char *zDbMain;    /* Schema name of database to vacuum */
    + 
    +   if( !db->autoCommit ){
    +     sqlite3SetString(pzErrMsg, db, "cannot VACUUM from within a transaction");
    +@@ -116531,14 +127139,17 @@ SQLITE_PRIVATE int sqlite3RunVacuum(char **pzErrMsg, sqlite3 *db){
    +   ** restored before returning. Then set the writable-schema flag, and
    +   ** disable CHECK and foreign key constraints.  */
    +   saved_flags = db->flags;
    ++  saved_mDbFlags = db->mDbFlags;
    +   saved_nChange = db->nChange;
    +   saved_nTotalChange = db->nTotalChange;
    +-  saved_xTrace = db->xTrace;
    +-  db->flags |= SQLITE_WriteSchema | SQLITE_IgnoreChecks | SQLITE_PreferBuiltin;
    +-  db->flags &= ~(SQLITE_ForeignKeys | SQLITE_ReverseOrder);
    +-  db->xTrace = 0;
    +-
    +-  pMain = db->aDb[0].pBt;
    ++  saved_mTrace = db->mTrace;
    ++  db->flags |= SQLITE_WriteSchema | SQLITE_IgnoreChecks;
    ++  db->mDbFlags |= DBFLAG_PreferBuiltin | DBFLAG_Vacuum;
    ++  db->flags &= ~(SQLITE_ForeignKeys | SQLITE_ReverseOrder | SQLITE_CountRows);
    ++  db->mTrace = 0;
    ++
    ++  zDbMain = db->aDb[iDb].zDbSName;
    ++  pMain = db->aDb[iDb].pBt;
    +   isMemDb = sqlite3PagerIsMemdb(sqlite3BtreePager(pMain));
    + 
    +   /* Attach the temporary database as 'vacuum_db'. The synchronous pragma
    +@@ -116556,18 +127167,12 @@ SQLITE_PRIVATE int sqlite3RunVacuum(char **pzErrMsg, sqlite3 *db){
    +   ** to write the journal header file.
    +   */
    +   nDb = db->nDb;
    +-  if( sqlite3TempInMemory(db) ){
    +-    zSql = "ATTACH ':memory:' AS vacuum_db;";
    +-  }else{
    +-    zSql = "ATTACH '' AS vacuum_db;";
    +-  }
    +-  rc = execSql(db, pzErrMsg, zSql);
    +-  if( db->nDb>nDb ){
    +-    pDb = &db->aDb[db->nDb-1];
    +-    assert( strcmp(pDb->zName,"vacuum_db")==0 );
    +-  }
    ++  rc = execSql(db, pzErrMsg, "ATTACH''AS vacuum_db");
    +   if( rc!=SQLITE_OK ) goto end_of_vacuum;
    +-  pTemp = db->aDb[db->nDb-1].pBt;
    ++  assert( (db->nDb-1)==nDb );
    ++  pDb = &db->aDb[nDb];
    ++  assert( strcmp(pDb->zDbSName,"vacuum_db")==0 );
    ++  pTemp = pDb->pBt;
    + 
    +   /* The call to execSql() to attach the temp database has left the file
    +   ** locked (as there was more than one active statement when the transaction
    +@@ -116583,19 +127188,20 @@ SQLITE_PRIVATE int sqlite3RunVacuum(char **pzErrMsg, sqlite3 *db){
    +     extern void sqlite3CodecGetKey(sqlite3*, int, void**, int*);
    +     int nKey;
    +     char *zKey;
    +-    sqlite3CodecGetKey(db, 0, (void**)&zKey, &nKey);
    ++    sqlite3CodecGetKey(db, iDb, (void**)&zKey, &nKey);
    +     if( nKey ) db->nextPagesize = 0;
    +   }
    + #endif
    + 
    +-  rc = execSql(db, pzErrMsg, "PRAGMA vacuum_db.synchronous=OFF");
    +-  if( rc!=SQLITE_OK ) goto end_of_vacuum;
    ++  sqlite3BtreeSetCacheSize(pTemp, db->aDb[iDb].pSchema->cache_size);
    ++  sqlite3BtreeSetSpillSize(pTemp, sqlite3BtreeSetSpillSize(pMain,0));
    ++  sqlite3BtreeSetPagerFlags(pTemp, PAGER_SYNCHRONOUS_OFF|PAGER_CACHESPILL);
    + 
    +   /* Begin a transaction and take an exclusive lock on the main database
    +   ** file. This is done before the sqlite3BtreeGetPageSize(pMain) call below,
    +   ** to ensure that we do not try to change the page-size on a WAL database.
    +   */
    +-  rc = execSql(db, pzErrMsg, "BEGIN;");
    ++  rc = execSql(db, pzErrMsg, "BEGIN");
    +   if( rc!=SQLITE_OK ) goto end_of_vacuum;
    +   rc = sqlite3BtreeBeginTrans(pMain, 2);
    +   if( rc!=SQLITE_OK ) goto end_of_vacuum;
    +@@ -116610,7 +127216,7 @@ SQLITE_PRIVATE int sqlite3RunVacuum(char **pzErrMsg, sqlite3 *db){
    +    || (!isMemDb && sqlite3BtreeSetPageSize(pTemp, db->nextPagesize, nRes, 0))
    +    || NEVER(db->mallocFailed)
    +   ){
    +-    rc = SQLITE_NOMEM;
    ++    rc = SQLITE_NOMEM_BKPT;
    +     goto end_of_vacuum;
    +   }
    + 
    +@@ -116622,64 +127228,48 @@ SQLITE_PRIVATE int sqlite3RunVacuum(char **pzErrMsg, sqlite3 *db){
    +   /* Query the schema of the main database. Create a mirror schema
    +   ** in the temporary database.
    +   */
    +-  rc = execExecSql(db, pzErrMsg,
    +-      "SELECT 'CREATE TABLE vacuum_db.' || substr(sql,14) "
    +-      "  FROM sqlite_master WHERE type='table' AND name!='sqlite_sequence'"
    +-      "   AND coalesce(rootpage,1)>0"
    ++  db->init.iDb = nDb; /* force new CREATE statements into vacuum_db */
    ++  rc = execSqlF(db, pzErrMsg,
    ++      "SELECT sql FROM \"%w\".sqlite_master"
    ++      " WHERE type='table'AND name<>'sqlite_sequence'"
    ++      " AND coalesce(rootpage,1)>0",
    ++      zDbMain
    +   );
    +   if( rc!=SQLITE_OK ) goto end_of_vacuum;
    +-  rc = execExecSql(db, pzErrMsg,
    +-      "SELECT 'CREATE INDEX vacuum_db.' || substr(sql,14)"
    +-      "  FROM sqlite_master WHERE sql LIKE 'CREATE INDEX %' ");
    +-  if( rc!=SQLITE_OK ) goto end_of_vacuum;
    +-  rc = execExecSql(db, pzErrMsg,
    +-      "SELECT 'CREATE UNIQUE INDEX vacuum_db.' || substr(sql,21) "
    +-      "  FROM sqlite_master WHERE sql LIKE 'CREATE UNIQUE INDEX %'");
    ++  rc = execSqlF(db, pzErrMsg,
    ++      "SELECT sql FROM \"%w\".sqlite_master"
    ++      " WHERE type='index' AND length(sql)>10",
    ++      zDbMain
    ++  );
    +   if( rc!=SQLITE_OK ) goto end_of_vacuum;
    ++  db->init.iDb = 0;
    + 
    +   /* Loop through the tables in the main database. For each, do
    +   ** an "INSERT INTO vacuum_db.xxx SELECT * FROM main.xxx;" to copy
    +   ** the contents to the temporary database.
    +   */
    +-  assert( (db->flags & SQLITE_Vacuum)==0 );
    +-  db->flags |= SQLITE_Vacuum;
    +-  rc = execExecSql(db, pzErrMsg,
    +-      "SELECT 'INSERT INTO vacuum_db.' || quote(name) "
    +-      "|| ' SELECT * FROM main.' || quote(name) || ';'"
    +-      "FROM main.sqlite_master "
    +-      "WHERE type = 'table' AND name!='sqlite_sequence' "
    +-      "  AND coalesce(rootpage,1)>0"
    ++  rc = execSqlF(db, pzErrMsg,
    ++      "SELECT'INSERT INTO vacuum_db.'||quote(name)"
    ++      "||' SELECT*FROM\"%w\".'||quote(name)"
    ++      "FROM vacuum_db.sqlite_master "
    ++      "WHERE type='table'AND coalesce(rootpage,1)>0",
    ++      zDbMain
    +   );
    +-  assert( (db->flags & SQLITE_Vacuum)!=0 );
    +-  db->flags &= ~SQLITE_Vacuum;
    ++  assert( (db->mDbFlags & DBFLAG_Vacuum)!=0 );
    ++  db->mDbFlags &= ~DBFLAG_Vacuum;
    +   if( rc!=SQLITE_OK ) goto end_of_vacuum;
    + 
    +-  /* Copy over the sequence table
    +-  */
    +-  rc = execExecSql(db, pzErrMsg,
    +-      "SELECT 'DELETE FROM vacuum_db.' || quote(name) || ';' "
    +-      "FROM vacuum_db.sqlite_master WHERE name='sqlite_sequence' "
    +-  );
    +-  if( rc!=SQLITE_OK ) goto end_of_vacuum;
    +-  rc = execExecSql(db, pzErrMsg,
    +-      "SELECT 'INSERT INTO vacuum_db.' || quote(name) "
    +-      "|| ' SELECT * FROM main.' || quote(name) || ';' "
    +-      "FROM vacuum_db.sqlite_master WHERE name=='sqlite_sequence';"
    +-  );
    +-  if( rc!=SQLITE_OK ) goto end_of_vacuum;
    +-
    +-
    +   /* Copy the triggers, views, and virtual tables from the main database
    +   ** over to the temporary database.  None of these objects has any
    +   ** associated storage, so all we have to do is copy their entries
    +   ** from the SQLITE_MASTER table.
    +   */
    +-  rc = execSql(db, pzErrMsg,
    +-      "INSERT INTO vacuum_db.sqlite_master "
    +-      "  SELECT type, name, tbl_name, rootpage, sql"
    +-      "    FROM main.sqlite_master"
    +-      "   WHERE type='view' OR type='trigger'"
    +-      "      OR (type='table' AND rootpage=0)"
    ++  rc = execSqlF(db, pzErrMsg,
    ++      "INSERT INTO vacuum_db.sqlite_master"
    ++      " SELECT*FROM \"%w\".sqlite_master"
    ++      " WHERE type IN('view','trigger')"
    ++      " OR(type='table'AND rootpage=0)",
    ++      zDbMain
    +   );
    +   if( rc ) goto end_of_vacuum;
    + 
    +@@ -116733,10 +127323,12 @@ SQLITE_PRIVATE int sqlite3RunVacuum(char **pzErrMsg, sqlite3 *db){
    + 
    + end_of_vacuum:
    +   /* Restore the original value of db->flags */
    ++  db->init.iDb = 0;
    ++  db->mDbFlags = saved_mDbFlags;
    +   db->flags = saved_flags;
    +   db->nChange = saved_nChange;
    +   db->nTotalChange = saved_nTotalChange;
    +-  db->xTrace = saved_xTrace;
    ++  db->mTrace = saved_mTrace;
    +   sqlite3BtreeSetPageSize(pMain, -1, -1, 1);
    + 
    +   /* Currently there is an SQL level transaction open on the vacuum
    +@@ -116795,6 +127387,43 @@ struct VtabCtx {
    +   int bDeclared;      /* True after sqlite3_declare_vtab() is called */
    + };
    + 
    ++/*
    ++** Construct and install a Module object for a virtual table.  When this
    ++** routine is called, it is guaranteed that all appropriate locks are held
    ++** and the module is not already part of the connection.
    ++*/
    ++SQLITE_PRIVATE Module *sqlite3VtabCreateModule(
    ++  sqlite3 *db,                    /* Database in which module is registered */
    ++  const char *zName,              /* Name assigned to this module */
    ++  const sqlite3_module *pModule,  /* The definition of the module */
    ++  void *pAux,                     /* Context pointer for xCreate/xConnect */
    ++  void (*xDestroy)(void *)        /* Module destructor function */
    ++){
    ++  Module *pMod;
    ++  int nName = sqlite3Strlen30(zName);
    ++  pMod = (Module *)sqlite3Malloc(sizeof(Module) + nName + 1);
    ++  if( pMod==0 ){
    ++    sqlite3OomFault(db);
    ++  }else{
    ++    Module *pDel;
    ++    char *zCopy = (char *)(&pMod[1]);
    ++    memcpy(zCopy, zName, nName+1);
    ++    pMod->zName = zCopy;
    ++    pMod->pModule = pModule;
    ++    pMod->pAux = pAux;
    ++    pMod->xDestroy = xDestroy;
    ++    pMod->pEpoTab = 0;
    ++    pDel = (Module *)sqlite3HashInsert(&db->aModule,zCopy,(void*)pMod);
    ++    assert( pDel==0 || pDel==pMod );
    ++    if( pDel ){
    ++      sqlite3OomFault(db);
    ++      sqlite3DbFree(db, pDel);
    ++      pMod = 0;
    ++    }
    ++  }
    ++  return pMod;
    ++}
    ++
    + /*
    + ** The actual function that does the work of creating a new module.
    + ** This function implements the sqlite3_create_module() and
    +@@ -116808,35 +127437,15 @@ static int createModule(
    +   void (*xDestroy)(void *)        /* Module destructor function */
    + ){
    +   int rc = SQLITE_OK;
    +-  int nName;
    + 
    +   sqlite3_mutex_enter(db->mutex);
    +-  nName = sqlite3Strlen30(zName);
    +   if( sqlite3HashFind(&db->aModule, zName) ){
    +     rc = SQLITE_MISUSE_BKPT;
    +   }else{
    +-    Module *pMod;
    +-    pMod = (Module *)sqlite3DbMallocRaw(db, sizeof(Module) + nName + 1);
    +-    if( pMod ){
    +-      Module *pDel;
    +-      char *zCopy = (char *)(&pMod[1]);
    +-      memcpy(zCopy, zName, nName+1);
    +-      pMod->zName = zCopy;
    +-      pMod->pModule = pModule;
    +-      pMod->pAux = pAux;
    +-      pMod->xDestroy = xDestroy;
    +-      pMod->pEpoTab = 0;
    +-      pDel = (Module *)sqlite3HashInsert(&db->aModule,zCopy,(void*)pMod);
    +-      assert( pDel==0 || pDel==pMod );
    +-      if( pDel ){
    +-        db->mallocFailed = 1;
    +-        sqlite3DbFree(db, pDel);
    +-      }
    +-    }
    ++    (void)sqlite3VtabCreateModule(db, zName, pModule, pAux, xDestroy);
    +   }
    +   rc = sqlite3ApiExit(db, rc);
    +   if( rc!=SQLITE_OK && xDestroy ) xDestroy(pAux);
    +-
    +   sqlite3_mutex_leave(db->mutex);
    +   return rc;
    + }
    +@@ -116845,7 +127454,7 @@ static int createModule(
    + /*
    + ** External API function used to create a new virtual-table module.
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_create_module(
    ++SQLITE_API int sqlite3_create_module(
    +   sqlite3 *db,                    /* Database in which module is registered */
    +   const char *zName,              /* Name assigned to this module */
    +   const sqlite3_module *pModule,  /* The definition of the module */
    +@@ -116860,7 +127469,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_create_module(
    + /*
    + ** External API function used to create a new virtual-table module.
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_create_module_v2(
    ++SQLITE_API int sqlite3_create_module_v2(
    +   sqlite3 *db,                    /* Database in which module is registered */
    +   const char *zName,              /* Name assigned to this module */
    +   const sqlite3_module *pModule,  /* The definition of the module */
    +@@ -117091,8 +127700,7 @@ SQLITE_PRIVATE void sqlite3VtabBeginParse(
    +   iDb = sqlite3SchemaToIndex(db, pTable->pSchema);
    +   assert( iDb>=0 );
    + 
    +-  pTable->tabFlags |= TF_Virtual;
    +-  pTable->nModuleArg = 0;
    ++  assert( pTable->nModuleArg==0 );
    +   addModuleArgument(db, pTable, sqlite3NameFromToken(db, pModuleName));
    +   addModuleArgument(db, pTable, 0);
    +   addModuleArgument(db, pTable, sqlite3DbStrDup(db, pTable->zName));
    +@@ -117111,7 +127719,7 @@ SQLITE_PRIVATE void sqlite3VtabBeginParse(
    +   */
    +   if( pTable->azModuleArg ){
    +     sqlite3AuthCheck(pParse, SQLITE_CREATE_VTABLE, pTable->zName, 
    +-            pTable->azModuleArg[0], pParse->db->aDb[iDb].zName);
    ++            pTable->azModuleArg[0], pParse->db->aDb[iDb].zDbSName);
    +   }
    + #endif
    + }
    +@@ -117175,7 +127783,7 @@ SQLITE_PRIVATE void sqlite3VtabFinishParse(Parse *pParse, Token *pEnd){
    +       "UPDATE %Q.%s "
    +          "SET type='table', name=%Q, tbl_name=%Q, rootpage=0, sql=%Q "
    +        "WHERE rowid=#%d",
    +-      db->aDb[iDb].zName, SCHEMA_TABLE(iDb),
    ++      db->aDb[iDb].zDbSName, MASTER_NAME,
    +       pTab->zName,
    +       pTab->zName,
    +       zStmt,
    +@@ -117185,7 +127793,7 @@ SQLITE_PRIVATE void sqlite3VtabFinishParse(Parse *pParse, Token *pEnd){
    +     v = sqlite3GetVdbe(pParse);
    +     sqlite3ChangeCookie(pParse, iDb);
    + 
    +-    sqlite3VdbeAddOp2(v, OP_Expire, 0, 0);
    ++    sqlite3VdbeAddOp0(v, OP_Expire);
    +     zWhere = sqlite3MPrintf(db, "name='%q' AND type='table'", pTab->zName);
    +     sqlite3VdbeAddParseSchemaOp(v, iDb, zWhere);
    + 
    +@@ -117206,7 +127814,7 @@ SQLITE_PRIVATE void sqlite3VtabFinishParse(Parse *pParse, Token *pEnd){
    +     assert( sqlite3SchemaMutexHeld(db, 0, pSchema) );
    +     pOld = sqlite3HashInsert(&pSchema->tblHash, zName, pTab);
    +     if( pOld ){
    +-      db->mallocFailed = 1;
    ++      sqlite3OomFault(db);
    +       assert( pTab==pOld );  /* Malloc must have failed inside HashInsert() */
    +       return;
    +     }
    +@@ -117271,21 +127879,22 @@ static int vtabCallConstructor(
    +     }
    +   }
    + 
    +-  zModuleName = sqlite3MPrintf(db, "%s", pTab->zName);
    ++  zModuleName = sqlite3DbStrDup(db, pTab->zName);
    +   if( !zModuleName ){
    +-    return SQLITE_NOMEM;
    ++    return SQLITE_NOMEM_BKPT;
    +   }
    + 
    +-  pVTable = sqlite3DbMallocZero(db, sizeof(VTable));
    ++  pVTable = sqlite3MallocZero(sizeof(VTable));
    +   if( !pVTable ){
    ++    sqlite3OomFault(db);
    +     sqlite3DbFree(db, zModuleName);
    +-    return SQLITE_NOMEM;
    ++    return SQLITE_NOMEM_BKPT;
    +   }
    +   pVTable->db = db;
    +   pVTable->pMod = pMod;
    + 
    +   iDb = sqlite3SchemaToIndex(db, pTab->pSchema);
    +-  pTab->azModuleArg[1] = db->aDb[iDb].zName;
    ++  pTab->azModuleArg[1] = db->aDb[iDb].zDbSName;
    + 
    +   /* Invoke the virtual table constructor */
    +   assert( &db->pVtabCtx );
    +@@ -117297,7 +127906,7 @@ static int vtabCallConstructor(
    +   db->pVtabCtx = &sCtx;
    +   rc = xConstruct(db, pMod->pAux, nArg, azArg, &pVTable->pVtab, &zErr);
    +   db->pVtabCtx = sCtx.pPrior;
    +-  if( rc==SQLITE_NOMEM ) db->mallocFailed = 1;
    ++  if( rc==SQLITE_NOMEM ) sqlite3OomFault(db);
    +   assert( sCtx.pTab==pTab );
    + 
    +   if( SQLITE_OK!=rc ){
    +@@ -117331,22 +127940,16 @@ static int vtabCallConstructor(
    +       pTab->pVTable = pVTable;
    + 
    +       for(iCol=0; iCol<pTab->nCol; iCol++){
    +-        char *zType = pTab->aCol[iCol].zType;
    ++        char *zType = sqlite3ColumnType(&pTab->aCol[iCol], "");
    +         int nType;
    +         int i = 0;
    +-        if( !zType ){
    +-          pTab->tabFlags |= oooHidden;
    +-          continue;
    +-        }
    +         nType = sqlite3Strlen30(zType);
    +-        if( sqlite3StrNICmp("hidden", zType, 6)||(zType[6] && zType[6]!=' ') ){
    +-          for(i=0; i<nType; i++){
    +-            if( (0==sqlite3StrNICmp(" hidden", &zType[i], 7))
    +-             && (zType[i+7]=='\0' || zType[i+7]==' ')
    +-            ){
    +-              i++;
    +-              break;
    +-            }
    ++        for(i=0; i<nType; i++){
    ++          if( 0==sqlite3StrNICmp("hidden", &zType[i], 6)
    ++           && (i==0 || zType[i-1]==' ')
    ++           && (zType[i+6]=='\0' || zType[i+6]==' ')
    ++          ){
    ++            break;
    +           }
    +         }
    +         if( i<nType ){
    +@@ -117386,7 +127989,7 @@ SQLITE_PRIVATE int sqlite3VtabCallConnect(Parse *pParse, Table *pTab){
    +   int rc;
    + 
    +   assert( pTab );
    +-  if( (pTab->tabFlags & TF_Virtual)==0 || sqlite3GetVTable(db, pTab) ){
    ++  if( !IsVirtual(pTab) || sqlite3GetVTable(db, pTab) ){
    +     return SQLITE_OK;
    +   }
    + 
    +@@ -117403,6 +128006,7 @@ SQLITE_PRIVATE int sqlite3VtabCallConnect(Parse *pParse, Table *pTab){
    +     rc = vtabCallConstructor(db, pTab, pMod, pMod->pModule->xConnect, &zErr);
    +     if( rc!=SQLITE_OK ){
    +       sqlite3ErrorMsg(pParse, "%s", zErr);
    ++      pParse->rc = rc;
    +     }
    +     sqlite3DbFree(db, zErr);
    +   }
    +@@ -117422,7 +128026,7 @@ static int growVTrans(sqlite3 *db){
    +     int nBytes = sizeof(sqlite3_vtab *) * (db->nVTrans + ARRAY_INCR);
    +     aVTrans = sqlite3DbRealloc(db, (void *)db->aVTrans, nBytes);
    +     if( !aVTrans ){
    +-      return SQLITE_NOMEM;
    ++      return SQLITE_NOMEM_BKPT;
    +     }
    +     memset(&aVTrans[db->nVTrans], 0, sizeof(sqlite3_vtab *)*ARRAY_INCR);
    +     db->aVTrans = aVTrans;
    +@@ -117445,7 +128049,7 @@ static void addToVTrans(sqlite3 *db, VTable *pVTab){
    + ** This function is invoked by the vdbe to call the xCreate method
    + ** of the virtual table named zTab in database iDb. 
    + **
    +-** If an error occurs, *pzErr is set to point an an English language
    ++** If an error occurs, *pzErr is set to point to an English language
    + ** description of the error and an SQLITE_XXX error code is returned.
    + ** In this case the caller must call sqlite3DbFree(db, ) on *pzErr.
    + */
    +@@ -117455,8 +128059,8 @@ SQLITE_PRIVATE int sqlite3VtabCallCreate(sqlite3 *db, int iDb, const char *zTab,
    +   Module *pMod;
    +   const char *zMod;
    + 
    +-  pTab = sqlite3FindTable(db, zTab, db->aDb[iDb].zName);
    +-  assert( pTab && (pTab->tabFlags & TF_Virtual)!=0 && !pTab->pVTable );
    ++  pTab = sqlite3FindTable(db, zTab, db->aDb[iDb].zDbSName);
    ++  assert( pTab && IsVirtual(pTab) && !pTab->pVTable );
    + 
    +   /* Locate the required virtual table module */
    +   zMod = pTab->azModuleArg[0];
    +@@ -117490,12 +128094,12 @@ SQLITE_PRIVATE int sqlite3VtabCallCreate(sqlite3 *db, int iDb, const char *zTab,
    + ** valid to call this function from within the xCreate() or xConnect() of a
    + ** virtual table module.
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_declare_vtab(sqlite3 *db, const char *zCreateTable){
    ++SQLITE_API int sqlite3_declare_vtab(sqlite3 *db, const char *zCreateTable){
    +   VtabCtx *pCtx;
    +-  Parse *pParse;
    +   int rc = SQLITE_OK;
    +   Table *pTab;
    +   char *zErr = 0;
    ++  Parse sParse;
    + 
    + #ifdef SQLITE_ENABLE_API_ARMOR
    +   if( !sqlite3SafetyCheckOk(db) || zCreateTable==0 ){
    +@@ -117510,43 +128114,57 @@ SQLITE_API int SQLITE_STDCALL sqlite3_declare_vtab(sqlite3 *db, const char *zCre
    +     return SQLITE_MISUSE_BKPT;
    +   }
    +   pTab = pCtx->pTab;
    +-  assert( (pTab->tabFlags & TF_Virtual)!=0 );
    ++  assert( IsVirtual(pTab) );
    + 
    +-  pParse = sqlite3StackAllocZero(db, sizeof(*pParse));
    +-  if( pParse==0 ){
    +-    rc = SQLITE_NOMEM;
    +-  }else{
    +-    pParse->declareVtab = 1;
    +-    pParse->db = db;
    +-    pParse->nQueryLoop = 1;
    +-  
    +-    if( SQLITE_OK==sqlite3RunParser(pParse, zCreateTable, &zErr) 
    +-     && pParse->pNewTable
    +-     && !db->mallocFailed
    +-     && !pParse->pNewTable->pSelect
    +-     && (pParse->pNewTable->tabFlags & TF_Virtual)==0
    +-    ){
    +-      if( !pTab->aCol ){
    +-        pTab->aCol = pParse->pNewTable->aCol;
    +-        pTab->nCol = pParse->pNewTable->nCol;
    +-        pParse->pNewTable->nCol = 0;
    +-        pParse->pNewTable->aCol = 0;
    ++  memset(&sParse, 0, sizeof(sParse));
    ++  sParse.declareVtab = 1;
    ++  sParse.db = db;
    ++  sParse.nQueryLoop = 1;
    ++  if( SQLITE_OK==sqlite3RunParser(&sParse, zCreateTable, &zErr) 
    ++   && sParse.pNewTable
    ++   && !db->mallocFailed
    ++   && !sParse.pNewTable->pSelect
    ++   && !IsVirtual(sParse.pNewTable)
    ++  ){
    ++    if( !pTab->aCol ){
    ++      Table *pNew = sParse.pNewTable;
    ++      Index *pIdx;
    ++      pTab->aCol = pNew->aCol;
    ++      pTab->nCol = pNew->nCol;
    ++      pTab->tabFlags |= pNew->tabFlags & (TF_WithoutRowid|TF_NoVisibleRowid);
    ++      pNew->nCol = 0;
    ++      pNew->aCol = 0;
    ++      assert( pTab->pIndex==0 );
    ++      assert( HasRowid(pNew) || sqlite3PrimaryKeyIndex(pNew)!=0 );
    ++      if( !HasRowid(pNew)
    ++       && pCtx->pVTable->pMod->pModule->xUpdate!=0
    ++       && sqlite3PrimaryKeyIndex(pNew)->nKeyCol!=1
    ++      ){
    ++        /* WITHOUT ROWID virtual tables must either be read-only (xUpdate==0)
    ++        ** or else must have a single-column PRIMARY KEY */
    ++        rc = SQLITE_ERROR;
    ++      }
    ++      pIdx = pNew->pIndex;
    ++      if( pIdx ){
    ++        assert( pIdx->pNext==0 );
    ++        pTab->pIndex = pIdx;
    ++        pNew->pIndex = 0;
    ++        pIdx->pTable = pTab;
    +       }
    +-      pCtx->bDeclared = 1;
    +-    }else{
    +-      sqlite3ErrorWithMsg(db, SQLITE_ERROR, (zErr ? "%s" : 0), zErr);
    +-      sqlite3DbFree(db, zErr);
    +-      rc = SQLITE_ERROR;
    +-    }
    +-    pParse->declareVtab = 0;
    +-  
    +-    if( pParse->pVdbe ){
    +-      sqlite3VdbeFinalize(pParse->pVdbe);
    +     }
    +-    sqlite3DeleteTable(db, pParse->pNewTable);
    +-    sqlite3ParserReset(pParse);
    +-    sqlite3StackFree(db, pParse);
    ++    pCtx->bDeclared = 1;
    ++  }else{
    ++    sqlite3ErrorWithMsg(db, SQLITE_ERROR, (zErr ? "%s" : 0), zErr);
    ++    sqlite3DbFree(db, zErr);
    ++    rc = SQLITE_ERROR;
    +   }
    ++  sParse.declareVtab = 0;
    ++
    ++  if( sParse.pVdbe ){
    ++    sqlite3VdbeFinalize(sParse.pVdbe);
    ++  }
    ++  sqlite3DeleteTable(db, sParse.pNewTable);
    ++  sqlite3ParserReset(&sParse);
    + 
    +   assert( (rc&0xff)==rc );
    +   rc = sqlite3ApiExit(db, rc);
    +@@ -117565,8 +128183,8 @@ SQLITE_PRIVATE int sqlite3VtabCallDestroy(sqlite3 *db, int iDb, const char *zTab
    +   int rc = SQLITE_OK;
    +   Table *pTab;
    + 
    +-  pTab = sqlite3FindTable(db, zTab, db->aDb[iDb].zName);
    +-  if( ALWAYS(pTab!=0 && pTab->pVTable!=0) ){
    ++  pTab = sqlite3FindTable(db, zTab, db->aDb[iDb].zDbSName);
    ++  if( pTab!=0 && ALWAYS(pTab->pVTable!=0) ){
    +     VTable *p;
    +     int (*xDestroy)(sqlite3_vtab *);
    +     for(p=pTab->pVTable; p; p=p->pNext){
    +@@ -117706,7 +128324,10 @@ SQLITE_PRIVATE int sqlite3VtabBegin(sqlite3 *db, VTable *pVTab){
    +       if( rc==SQLITE_OK ){
    +         int iSvpt = db->nStatement + db->nSavepoint;
    +         addToVTrans(db, pVTab);
    +-        if( iSvpt ) rc = sqlite3VtabSavepoint(db, SAVEPOINT_BEGIN, iSvpt-1);
    ++        if( iSvpt && pModule->xSavepoint ){
    ++          pVTab->iSavepoint = iSvpt;
    ++          rc = pModule->xSavepoint(pVTab->pVtab, iSvpt-1);
    ++        }
    +       }
    +     }
    +   }
    +@@ -117783,7 +128404,7 @@ SQLITE_PRIVATE FuncDef *sqlite3VtabOverloadFunction(
    +   Table *pTab;
    +   sqlite3_vtab *pVtab;
    +   sqlite3_module *pMod;
    +-  void (*xFunc)(sqlite3_context*,int,sqlite3_value**) = 0;
    ++  void (*xSFunc)(sqlite3_context*,int,sqlite3_value**) = 0;
    +   void *pArg = 0;
    +   FuncDef *pNew;
    +   int rc = 0;
    +@@ -117795,8 +128416,8 @@ SQLITE_PRIVATE FuncDef *sqlite3VtabOverloadFunction(
    +   if( NEVER(pExpr==0) ) return pDef;
    +   if( pExpr->op!=TK_COLUMN ) return pDef;
    +   pTab = pExpr->pTab;
    +-  if( NEVER(pTab==0) ) return pDef;
    +-  if( (pTab->tabFlags & TF_Virtual)==0 ) return pDef;
    ++  if( pTab==0 ) return pDef;
    ++  if( !IsVirtual(pTab) ) return pDef;
    +   pVtab = sqlite3GetVTable(db, pTab)->pVtab;
    +   assert( pVtab!=0 );
    +   assert( pVtab->pModule!=0 );
    +@@ -117811,7 +128432,7 @@ SQLITE_PRIVATE FuncDef *sqlite3VtabOverloadFunction(
    +     for(z=(unsigned char*)zLowerName; *z; z++){
    +       *z = sqlite3UpperToLower[*z];
    +     }
    +-    rc = pMod->xFindFunction(pVtab, nArg, zLowerName, &xFunc, &pArg);
    ++    rc = pMod->xFindFunction(pVtab, nArg, zLowerName, &xSFunc, &pArg);
    +     sqlite3DbFree(db, zLowerName);
    +   }
    +   if( rc==0 ){
    +@@ -117826,9 +128447,9 @@ SQLITE_PRIVATE FuncDef *sqlite3VtabOverloadFunction(
    +     return pDef;
    +   }
    +   *pNew = *pDef;
    +-  pNew->zName = (char *)&pNew[1];
    +-  memcpy(pNew->zName, pDef->zName, sqlite3Strlen30(pDef->zName)+1);
    +-  pNew->xFunc = xFunc;
    ++  pNew->zName = (const char*)&pNew[1];
    ++  memcpy((char*)&pNew[1], pDef->zName, sqlite3Strlen30(pDef->zName)+1);
    ++  pNew->xSFunc = xSFunc;
    +   pNew->pUserData = pArg;
    +   pNew->funcFlags |= SQLITE_FUNC_EPHEM;
    +   return pNew;
    +@@ -117855,12 +128476,12 @@ SQLITE_PRIVATE void sqlite3VtabMakeWritable(Parse *pParse, Table *pTab){
    +     pToplevel->apVtabLock = apVtabLock;
    +     pToplevel->apVtabLock[pToplevel->nVtabLock++] = pTab;
    +   }else{
    +-    pToplevel->db->mallocFailed = 1;
    ++    sqlite3OomFault(pToplevel->db);
    +   }
    + }
    + 
    + /*
    +-** Check to see if virtual tale module pMod can be have an eponymous
    ++** Check to see if virtual table module pMod can be have an eponymous
    + ** virtual table instance.  If it can, create one if one does not already
    + ** exist. Return non-zero if the eponymous virtual table instance exists
    + ** when this routine returns, and return zero if it does not exist.
    +@@ -117877,21 +128498,21 @@ SQLITE_PRIVATE int sqlite3VtabEponymousTableInit(Parse *pParse, Module *pMod){
    +   const sqlite3_module *pModule = pMod->pModule;
    +   Table *pTab;
    +   char *zErr = 0;
    +-  int nName;
    +   int rc;
    +   sqlite3 *db = pParse->db;
    +   if( pMod->pEpoTab ) return 1;
    +   if( pModule->xCreate!=0 && pModule->xCreate!=pModule->xConnect ) return 0;
    +-  nName = sqlite3Strlen30(pMod->zName) + 1;
    +-  pTab = sqlite3DbMallocZero(db, sizeof(Table) + nName);
    ++  pTab = sqlite3DbMallocZero(db, sizeof(Table));
    +   if( pTab==0 ) return 0;
    ++  pTab->zName = sqlite3DbStrDup(db, pMod->zName);
    ++  if( pTab->zName==0 ){
    ++    sqlite3DbFree(db, pTab);
    ++    return 0;
    ++  }
    +   pMod->pEpoTab = pTab;
    +-  pTab->zName = (char*)&pTab[1];
    +-  memcpy(pTab->zName, pMod->zName, nName);
    +-  pTab->nRef = 1;
    ++  pTab->nTabRef = 1;
    +   pTab->pSchema = db->aDb[0].pSchema;
    +-  pTab->tabFlags |= TF_Virtual;
    +-  pTab->nModuleArg = 0;
    ++  assert( pTab->nModuleArg==0 );
    +   pTab->iPKey = -1;
    +   addModuleArgument(db, pTab, sqlite3DbStrDup(db, pTab->zName));
    +   addModuleArgument(db, pTab, 0);
    +@@ -117913,9 +128534,11 @@ SQLITE_PRIVATE int sqlite3VtabEponymousTableInit(Parse *pParse, Module *pMod){
    + SQLITE_PRIVATE void sqlite3VtabEponymousTableClear(sqlite3 *db, Module *pMod){
    +   Table *pTab = pMod->pEpoTab;
    +   if( pTab!=0 ){
    +-    sqlite3DeleteColumnNames(db, pTab);
    +-    sqlite3VtabClear(db, pTab);
    +-    sqlite3DbFree(db, pTab);
    ++    /* Mark the table as Ephemeral prior to deleting it, so that the
    ++    ** sqlite3DeleteTable() routine will know that it is not stored in 
    ++    ** the schema. */
    ++    pTab->tabFlags |= TF_Ephemeral;
    ++    sqlite3DeleteTable(db, pTab);
    +     pMod->pEpoTab = 0;
    +   }
    + }
    +@@ -117927,7 +128550,7 @@ SQLITE_PRIVATE void sqlite3VtabEponymousTableClear(sqlite3 *db, Module *pMod){
    + ** The results of this routine are undefined unless it is called from
    + ** within an xUpdate method.
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_vtab_on_conflict(sqlite3 *db){
    ++SQLITE_API int sqlite3_vtab_on_conflict(sqlite3 *db){
    +   static const unsigned char aMap[] = { 
    +     SQLITE_ROLLBACK, SQLITE_ABORT, SQLITE_FAIL, SQLITE_IGNORE, SQLITE_REPLACE 
    +   };
    +@@ -117945,7 +128568,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_vtab_on_conflict(sqlite3 *db){
    + ** the SQLite core with additional information about the behavior
    + ** of the virtual table being implemented.
    + */
    +-SQLITE_API int SQLITE_CDECL sqlite3_vtab_config(sqlite3 *db, int op, ...){
    ++SQLITE_API int sqlite3_vtab_config(sqlite3 *db, int op, ...){
    +   va_list ap;
    +   int rc = SQLITE_OK;
    + 
    +@@ -117960,7 +128583,7 @@ SQLITE_API int SQLITE_CDECL sqlite3_vtab_config(sqlite3 *db, int op, ...){
    +       if( !p ){
    +         rc = SQLITE_MISUSE_BKPT;
    +       }else{
    +-        assert( p->pTab==0 || (p->pTab->tabFlags & TF_Virtual)!=0 );
    ++        assert( p->pTab==0 || IsVirtual(p->pTab) );
    +         p->pVTable->bConstraint = (u8)va_arg(ap, int);
    +       }
    +       break;
    +@@ -118073,8 +128696,10 @@ struct WhereLevel {
    +   int addrCont;         /* Jump here to continue with the next loop cycle */
    +   int addrFirst;        /* First instruction of interior of the loop */
    +   int addrBody;         /* Beginning of the body of this loop */
    +-  int iLikeRepCntr;     /* LIKE range processing counter register */
    ++#ifndef SQLITE_LIKE_DOESNT_MATCH_BLOBS
    ++  u32 iLikeRepCntr;     /* LIKE range processing counter register (times 2) */
    +   int addrLikeRep;      /* LIKE range processing address */
    ++#endif
    +   u8 iFrom;             /* Which entry in the FROM clause */
    +   u8 op, p3, p5;        /* Opcode, P3 & P5 of the opcode that ends the loop */
    +   int p1, p2;           /* Operands of the opcode used to ends the loop */
    +@@ -118124,6 +128749,9 @@ struct WhereLoop {
    +   union {
    +     struct {               /* Information for internal btree tables */
    +       u16 nEq;               /* Number of equality constraints */
    ++      u16 nBtm;              /* Size of BTM vector */
    ++      u16 nTop;              /* Size of TOP vector */
    ++      u16 nIdxCol;           /* Index column used for ORDER BY */
    +       Index *pIndex;         /* Index used, or NULL */
    +     } btree;
    +     struct {               /* Information for virtual tables */
    +@@ -118246,18 +128874,20 @@ struct WherePath {
    + */
    + struct WhereTerm {
    +   Expr *pExpr;            /* Pointer to the subexpression that is this term */
    ++  WhereClause *pWC;       /* The clause this term is part of */
    ++  LogEst truthProb;       /* Probability of truth for this expression */
    ++  u16 wtFlags;            /* TERM_xxx bit flags.  See below */
    ++  u16 eOperator;          /* A WO_xx value describing <op> */
    ++  u8 nChild;              /* Number of children that must disable us */
    ++  u8 eMatchOp;            /* Op for vtab MATCH/LIKE/GLOB/REGEXP terms */
    +   int iParent;            /* Disable pWC->a[iParent] when this term disabled */
    +   int leftCursor;         /* Cursor number of X in "X <op> <expr>" */
    ++  int iField;             /* Field in (?,?,?) IN (SELECT...) vector */
    +   union {
    +     int leftColumn;         /* Column number of X in "X <op> <expr>" */
    +     WhereOrInfo *pOrInfo;   /* Extra information if (eOperator & WO_OR)!=0 */
    +     WhereAndInfo *pAndInfo; /* Extra information if (eOperator& WO_AND)!=0 */
    +   } u;
    +-  LogEst truthProb;       /* Probability of truth for this expression */
    +-  u16 eOperator;          /* A WO_xx value describing <op> */
    +-  u16 wtFlags;            /* TERM_xxx bit flags.  See below */
    +-  u8 nChild;              /* Number of children that must disable us */
    +-  WhereClause *pWC;       /* The clause this term is part of */
    +   Bitmask prereqRight;    /* Bitmask of tables used by pExpr->pRight */
    +   Bitmask prereqAll;      /* Bitmask of tables referenced by pExpr */
    + };
    +@@ -118281,6 +128911,7 @@ struct WhereTerm {
    + #define TERM_LIKECOND   0x200  /* Conditionally this LIKE operator term */
    + #define TERM_LIKE       0x400  /* The original LIKE operator */
    + #define TERM_IS         0x800  /* Term.pExpr is an IS operator */
    ++#define TERM_VARSELECT  0x1000 /* Term.pExpr contains a correlated sub-query */
    + 
    + /*
    + ** An instance of the WhereScan object is used as an iterator for locating
    +@@ -118289,7 +128920,7 @@ struct WhereTerm {
    + struct WhereScan {
    +   WhereClause *pOrigWC;      /* Original, innermost WhereClause */
    +   WhereClause *pWC;          /* WhereClause currently being scanned */
    +-  char *zCollName;           /* Required collating sequence, if not NULL */
    ++  const char *zCollName;     /* Required collating sequence, if not NULL */
    +   Expr *pIdxExpr;            /* Search for this index expression */
    +   char idxaff;               /* Must match this affinity, if zCollName!=NULL */
    +   unsigned char nEquiv;      /* Number of entries in aEquiv[] */
    +@@ -118370,6 +129001,7 @@ struct WhereAndInfo {
    + ** no gaps.
    + */
    + struct WhereMaskSet {
    ++  int bVarSelect;               /* Used by sqlite3WhereExprUsage() */
    +   int n;                        /* Number of assigned cursor values */
    +   int ix[BMS];                  /* Cursor assigned to each bit */
    + };
    +@@ -118393,8 +129025,13 @@ struct WhereLoopBuilder {
    +   UnpackedRecord *pRec;     /* Probe for stat4 (if required) */
    +   int nRecValid;            /* Number of valid fields currently in pRec */
    + #endif
    ++  unsigned int bldFlags;    /* SQLITE_BLDF_* flags */
    + };
    + 
    ++/* Allowed values for WhereLoopBuider.bldFlags */
    ++#define SQLITE_BLDF_INDEXED  0x0001   /* An index is used */
    ++#define SQLITE_BLDF_UNIQUE   0x0002   /* All keys of a UNIQUE index used */
    ++
    + /*
    + ** The WHERE clause processing routine has two halves.  The
    + ** first part does the start of the WHERE loop and the second
    +@@ -118409,24 +129046,27 @@ struct WhereInfo {
    +   Parse *pParse;            /* Parsing and code generating context */
    +   SrcList *pTabList;        /* List of tables in the join */
    +   ExprList *pOrderBy;       /* The ORDER BY clause or NULL */
    +-  ExprList *pResultSet;     /* Result set. DISTINCT operates on these */
    +-  WhereLoop *pLoops;        /* List of all WhereLoop objects */
    +-  Bitmask revMask;          /* Mask of ORDER BY terms that need reversing */
    +-  LogEst nRowOut;           /* Estimated number of output rows */
    ++  ExprList *pResultSet;     /* Result set of the query */
    ++  Expr *pWhere;             /* The complete WHERE clause */
    ++  LogEst iLimit;            /* LIMIT if wctrlFlags has WHERE_USE_LIMIT */
    ++  int aiCurOnePass[2];      /* OP_OpenWrite cursors for the ONEPASS opt */
    ++  int iContinue;            /* Jump here to continue with next record */
    ++  int iBreak;               /* Jump here to break out of the loop */
    ++  int savedNQueryLoop;      /* pParse->nQueryLoop outside the WHERE loop */
    +   u16 wctrlFlags;           /* Flags originally passed to sqlite3WhereBegin() */
    ++  u8 nLevel;                /* Number of nested loop */
    +   i8 nOBSat;                /* Number of ORDER BY terms satisfied by indices */
    +   u8 sorted;                /* True if really sorted (not just grouped) */
    +   u8 eOnePass;              /* ONEPASS_OFF, or _SINGLE, or _MULTI */
    +   u8 untestedTerms;         /* Not all WHERE terms resolved by outer loop */
    +-  u8 eDistinct;             /* One of the WHERE_DISTINCT_* values below */
    +-  u8 nLevel;                /* Number of nested loop */
    ++  u8 eDistinct;             /* One of the WHERE_DISTINCT_* values */
    ++  u8 bOrderedInnerLoop;     /* True if only the inner-most loop is ordered */
    +   int iTop;                 /* The very beginning of the WHERE loop */
    +-  int iContinue;            /* Jump here to continue with next record */
    +-  int iBreak;               /* Jump here to break out of the loop */
    +-  int savedNQueryLoop;      /* pParse->nQueryLoop outside the WHERE loop */
    +-  int aiCurOnePass[2];      /* OP_OpenWrite cursors for the ONEPASS opt */
    +-  WhereMaskSet sMaskSet;    /* Map cursor numbers to bitmasks */
    ++  WhereLoop *pLoops;        /* List of all WhereLoop objects */
    ++  Bitmask revMask;          /* Mask of ORDER BY terms that need reversing */
    ++  LogEst nRowOut;           /* Estimated number of output rows */
    +   WhereClause sWC;          /* Decomposition of the WHERE clause */
    ++  WhereMaskSet sMaskSet;    /* Map cursor numbers to bitmasks */
    +   WhereLevel a[1];          /* Information about each nest loop in WHERE */
    + };
    + 
    +@@ -118436,6 +129076,9 @@ struct WhereInfo {
    + ** where.c:
    + */
    + SQLITE_PRIVATE Bitmask sqlite3WhereGetMask(WhereMaskSet*,int);
    ++#ifdef WHERETRACE_ENABLED
    ++SQLITE_PRIVATE void sqlite3WhereClausePrint(WhereClause *pWC);
    ++#endif
    + SQLITE_PRIVATE WhereTerm *sqlite3WhereFindTerm(
    +   WhereClause *pWC,     /* The WHERE clause to be searched */
    +   int iCur,             /* Cursor number of LHS */
    +@@ -118492,6 +129135,13 @@ SQLITE_PRIVATE void sqlite3WhereTabFuncArgs(Parse*, struct SrcList_item*, WhereC
    + ** operators that are of interest to the query planner.  An
    + ** OR-ed combination of these values can be used when searching for
    + ** particular WhereTerms within a WhereClause.
    ++**
    ++** Value constraints:
    ++**     WO_EQ    == SQLITE_INDEX_CONSTRAINT_EQ
    ++**     WO_LT    == SQLITE_INDEX_CONSTRAINT_LT
    ++**     WO_LE    == SQLITE_INDEX_CONSTRAINT_LE
    ++**     WO_GT    == SQLITE_INDEX_CONSTRAINT_GT
    ++**     WO_GE    == SQLITE_INDEX_CONSTRAINT_GE
    + */
    + #define WO_IN     0x0001
    + #define WO_EQ     0x0002
    +@@ -118499,7 +129149,7 @@ SQLITE_PRIVATE void sqlite3WhereTabFuncArgs(Parse*, struct SrcList_item*, WhereC
    + #define WO_LE     (WO_EQ<<(TK_LE-TK_EQ))
    + #define WO_GT     (WO_EQ<<(TK_GT-TK_EQ))
    + #define WO_GE     (WO_EQ<<(TK_GE-TK_EQ))
    +-#define WO_MATCH  0x0040
    ++#define WO_AUX    0x0040       /* Op useful to virtual tables only */
    + #define WO_IS     0x0080
    + #define WO_ISNULL 0x0100
    + #define WO_OR     0x0200       /* Two or more OR-connected terms */
    +@@ -118539,6 +129189,17 @@ SQLITE_PRIVATE void sqlite3WhereTabFuncArgs(Parse*, struct SrcList_item*, WhereC
    + /************** Continuing where we left off in wherecode.c ******************/
    + 
    + #ifndef SQLITE_OMIT_EXPLAIN
    ++
    ++/*
    ++** Return the name of the i-th column of the pIdx index.
    ++*/
    ++static const char *explainIndexColumnName(Index *pIdx, int i){
    ++  i = pIdx->aiColumn[i];
    ++  if( i==XN_EXPR ) return "<expr>";
    ++  if( i==XN_ROWID ) return "rowid";
    ++  return pIdx->pTable->aCol[i].zName;
    ++}
    ++
    + /*
    + ** This routine is a helper for explainIndexRange() below
    + **
    +@@ -118549,24 +129210,32 @@ SQLITE_PRIVATE void sqlite3WhereTabFuncArgs(Parse*, struct SrcList_item*, WhereC
    + */
    + static void explainAppendTerm(
    +   StrAccum *pStr,             /* The text expression being built */
    +-  int iTerm,                  /* Index of this term.  First is zero */
    +-  const char *zColumn,        /* Name of the column */
    ++  Index *pIdx,                /* Index to read column names from */
    ++  int nTerm,                  /* Number of terms */
    ++  int iTerm,                  /* Zero-based index of first term. */
    ++  int bAnd,                   /* Non-zero to append " AND " */
    +   const char *zOp             /* Name of the operator */
    + ){
    +-  if( iTerm ) sqlite3StrAccumAppend(pStr, " AND ", 5);
    +-  sqlite3StrAccumAppendAll(pStr, zColumn);
    ++  int i;
    ++
    ++  assert( nTerm>=1 );
    ++  if( bAnd ) sqlite3StrAccumAppend(pStr, " AND ", 5);
    ++
    ++  if( nTerm>1 ) sqlite3StrAccumAppend(pStr, "(", 1);
    ++  for(i=0; i<nTerm; i++){
    ++    if( i ) sqlite3StrAccumAppend(pStr, ",", 1);
    ++    sqlite3StrAccumAppendAll(pStr, explainIndexColumnName(pIdx, iTerm+i));
    ++  }
    ++  if( nTerm>1 ) sqlite3StrAccumAppend(pStr, ")", 1);
    ++
    +   sqlite3StrAccumAppend(pStr, zOp, 1);
    +-  sqlite3StrAccumAppend(pStr, "?", 1);
    +-}
    + 
    +-/*
    +-** Return the name of the i-th column of the pIdx index.
    +-*/
    +-static const char *explainIndexColumnName(Index *pIdx, int i){
    +-  i = pIdx->aiColumn[i];
    +-  if( i==XN_EXPR ) return "<expr>";
    +-  if( i==XN_ROWID ) return "rowid";
    +-  return pIdx->pTable->aCol[i].zName;
    ++  if( nTerm>1 ) sqlite3StrAccumAppend(pStr, "(", 1);
    ++  for(i=0; i<nTerm; i++){
    ++    if( i ) sqlite3StrAccumAppend(pStr, ",", 1);
    ++    sqlite3StrAccumAppend(pStr, "?", 1);
    ++  }
    ++  if( nTerm>1 ) sqlite3StrAccumAppend(pStr, ")", 1);
    + }
    + 
    + /*
    +@@ -118594,17 +129263,16 @@ static void explainIndexRange(StrAccum *pStr, WhereLoop *pLoop){
    +   for(i=0; i<nEq; i++){
    +     const char *z = explainIndexColumnName(pIndex, i);
    +     if( i ) sqlite3StrAccumAppend(pStr, " AND ", 5);
    +-    sqlite3XPrintf(pStr, 0, i>=nSkip ? "%s=?" : "ANY(%s)", z);
    ++    sqlite3XPrintf(pStr, i>=nSkip ? "%s=?" : "ANY(%s)", z);
    +   }
    + 
    +   j = i;
    +   if( pLoop->wsFlags&WHERE_BTM_LIMIT ){
    +-    const char *z = explainIndexColumnName(pIndex, i);
    +-    explainAppendTerm(pStr, i++, z, ">");
    ++    explainAppendTerm(pStr, pIndex, pLoop->u.btree.nBtm, j, i, ">");
    ++    i = 1;
    +   }
    +   if( pLoop->wsFlags&WHERE_TOP_LIMIT ){
    +-    const char *z = explainIndexColumnName(pIndex, j);
    +-    explainAppendTerm(pStr, i, z, "<");
    ++    explainAppendTerm(pStr, pIndex, pLoop->u.btree.nTop, j, i, "<");
    +   }
    +   sqlite3StrAccumAppend(pStr, ")", 1);
    + }
    +@@ -118628,7 +129296,7 @@ SQLITE_PRIVATE int sqlite3WhereExplainOneScan(
    + ){
    +   int ret = 0;
    + #if !defined(SQLITE_DEBUG) && !defined(SQLITE_ENABLE_STMT_SCANSTATUS)
    +-  if( pParse->explain==2 )
    ++  if( sqlite3ParseToplevel(pParse)->explain==2 )
    + #endif
    +   {
    +     struct SrcList_item *pItem = &pTabList->a[pLevel->iFrom];
    +@@ -118644,7 +129312,7 @@ SQLITE_PRIVATE int sqlite3WhereExplainOneScan(
    + 
    +     pLoop = pLevel->pWLoop;
    +     flags = pLoop->wsFlags;
    +-    if( (flags&WHERE_MULTI_OR) || (wctrlFlags&WHERE_ONETABLE_ONLY) ) return 0;
    ++    if( (flags&WHERE_MULTI_OR) || (wctrlFlags&WHERE_OR_SUBCLAUSE) ) return 0;
    + 
    +     isSearch = (flags&(WHERE_BTM_LIMIT|WHERE_TOP_LIMIT))!=0
    +             || ((flags&WHERE_VIRTUALTABLE)==0 && (pLoop->u.btree.nEq>0))
    +@@ -118653,13 +129321,13 @@ SQLITE_PRIVATE int sqlite3WhereExplainOneScan(
    +     sqlite3StrAccumInit(&str, db, zBuf, sizeof(zBuf), SQLITE_MAX_LENGTH);
    +     sqlite3StrAccumAppendAll(&str, isSearch ? "SEARCH" : "SCAN");
    +     if( pItem->pSelect ){
    +-      sqlite3XPrintf(&str, 0, " SUBQUERY %d", pItem->iSelectId);
    ++      sqlite3XPrintf(&str, " SUBQUERY %d", pItem->iSelectId);
    +     }else{
    +-      sqlite3XPrintf(&str, 0, " TABLE %s", pItem->zName);
    ++      sqlite3XPrintf(&str, " TABLE %s", pItem->zName);
    +     }
    + 
    +     if( pItem->zAlias ){
    +-      sqlite3XPrintf(&str, 0, " AS %s", pItem->zAlias);
    ++      sqlite3XPrintf(&str, " AS %s", pItem->zAlias);
    +     }
    +     if( (flags & (WHERE_IPK|WHERE_VIRTUALTABLE))==0 ){
    +       const char *zFmt = 0;
    +@@ -118683,7 +129351,7 @@ SQLITE_PRIVATE int sqlite3WhereExplainOneScan(
    +       }
    +       if( zFmt ){
    +         sqlite3StrAccumAppend(&str, " USING ", 7);
    +-        sqlite3XPrintf(&str, 0, zFmt, pIdx->zName);
    ++        sqlite3XPrintf(&str, zFmt, pIdx->zName);
    +         explainIndexRange(&str, pLoop);
    +       }
    +     }else if( (flags & WHERE_IPK)!=0 && (flags & WHERE_CONSTRAINT)!=0 ){
    +@@ -118698,17 +129366,17 @@ SQLITE_PRIVATE int sqlite3WhereExplainOneScan(
    +         assert( flags&WHERE_TOP_LIMIT);
    +         zRangeOp = "<";
    +       }
    +-      sqlite3XPrintf(&str, 0, " USING INTEGER PRIMARY KEY (rowid%s?)",zRangeOp);
    ++      sqlite3XPrintf(&str, " USING INTEGER PRIMARY KEY (rowid%s?)",zRangeOp);
    +     }
    + #ifndef SQLITE_OMIT_VIRTUALTABLE
    +     else if( (flags & WHERE_VIRTUALTABLE)!=0 ){
    +-      sqlite3XPrintf(&str, 0, " VIRTUAL TABLE INDEX %d:%s",
    ++      sqlite3XPrintf(&str, " VIRTUAL TABLE INDEX %d:%s",
    +                   pLoop->u.vtab.idxNum, pLoop->u.vtab.idxStr);
    +     }
    + #endif
    + #ifdef SQLITE_EXPLAIN_ESTIMATED_ROWS
    +     if( pLoop->nOut>=10 ){
    +-      sqlite3XPrintf(&str, 0, " (~%llu rows)", sqlite3LogEstToInt(pLoop->nOut));
    ++      sqlite3XPrintf(&str, " (~%llu rows)", sqlite3LogEstToInt(pLoop->nOut));
    +     }else{
    +       sqlite3StrAccumAppend(&str, " (~1 row)", 9);
    +     }
    +@@ -118794,8 +129462,8 @@ SQLITE_PRIVATE void sqlite3WhereAddScanStatus(
    + */
    + static void disableTerm(WhereLevel *pLevel, WhereTerm *pTerm){
    +   int nLoop = 0;
    +-  while( pTerm
    +-      && (pTerm->wtFlags & TERM_CODED)==0
    ++  assert( pTerm!=0 );
    ++  while( (pTerm->wtFlags & TERM_CODED)==0
    +       && (pLevel->iLeftJoin==0 || ExprHasProperty(pTerm->pExpr, EP_FromJoin))
    +       && (pLevel->notReady & pTerm->prereqAll)==0
    +   ){
    +@@ -118806,6 +129474,7 @@ static void disableTerm(WhereLevel *pLevel, WhereTerm *pTerm){
    +     }
    +     if( pTerm->iParent<0 ) break;
    +     pTerm = &pTerm->pWC->a[pTerm->iParent];
    ++    assert( pTerm!=0 );
    +     pTerm->nChild--;
    +     if( pTerm->nChild!=0 ) break;
    +     nLoop++;
    +@@ -118845,22 +129514,146 @@ static void codeApplyAffinity(Parse *pParse, int base, int n, char *zAff){
    + 
    +   /* Code the OP_Affinity opcode if there is anything left to do. */
    +   if( n>0 ){
    +-    sqlite3VdbeAddOp2(v, OP_Affinity, base, n);
    +-    sqlite3VdbeChangeP4(v, -1, zAff, n);
    ++    sqlite3VdbeAddOp4(v, OP_Affinity, base, n, 0, zAff, n);
    +     sqlite3ExprCacheAffinityChange(pParse, base, n);
    +   }
    + }
    + 
    ++/*
    ++** Expression pRight, which is the RHS of a comparison operation, is 
    ++** either a vector of n elements or, if n==1, a scalar expression.
    ++** Before the comparison operation, affinity zAff is to be applied
    ++** to the pRight values. This function modifies characters within the
    ++** affinity string to SQLITE_AFF_BLOB if either:
    ++**
    ++**   * the comparison will be performed with no affinity, or
    ++**   * the affinity change in zAff is guaranteed not to change the value.
    ++*/
    ++static void updateRangeAffinityStr(
    ++  Expr *pRight,                   /* RHS of comparison */
    ++  int n,                          /* Number of vector elements in comparison */
    ++  char *zAff                      /* Affinity string to modify */
    ++){
    ++  int i;
    ++  for(i=0; i<n; i++){
    ++    Expr *p = sqlite3VectorFieldSubexpr(pRight, i);
    ++    if( sqlite3CompareAffinity(p, zAff[i])==SQLITE_AFF_BLOB
    ++     || sqlite3ExprNeedsNoAffinityChange(p, zAff[i])
    ++    ){
    ++      zAff[i] = SQLITE_AFF_BLOB;
    ++    }
    ++  }
    ++}
    ++
    ++
    ++/*
    ++** pX is an expression of the form:  (vector) IN (SELECT ...)
    ++** In other words, it is a vector IN operator with a SELECT clause on the
    ++** LHS.  But not all terms in the vector are indexable and the terms might
    ++** not be in the correct order for indexing.
    ++**
    ++** This routine makes a copy of the input pX expression and then adjusts
    ++** the vector on the LHS with corresponding changes to the SELECT so that
    ++** the vector contains only index terms and those terms are in the correct
    ++** order.  The modified IN expression is returned.  The caller is responsible
    ++** for deleting the returned expression.
    ++**
    ++** Example:
    ++**
    ++**    CREATE TABLE t1(a,b,c,d,e,f);
    ++**    CREATE INDEX t1x1 ON t1(e,c);
    ++**    SELECT * FROM t1 WHERE (a,b,c,d,e) IN (SELECT v,w,x,y,z FROM t2)
    ++**                           \_______________________________________/
    ++**                                     The pX expression
    ++**
    ++** Since only columns e and c can be used with the index, in that order,
    ++** the modified IN expression that is returned will be:
    ++**
    ++**        (e,c) IN (SELECT z,x FROM t2)
    ++**
    ++** The reduced pX is different from the original (obviously) and thus is
    ++** only used for indexing, to improve performance.  The original unaltered
    ++** IN expression must also be run on each output row for correctness.
    ++*/
    ++static Expr *removeUnindexableInClauseTerms(
    ++  Parse *pParse,        /* The parsing context */
    ++  int iEq,              /* Look at loop terms starting here */
    ++  WhereLoop *pLoop,     /* The current loop */
    ++  Expr *pX              /* The IN expression to be reduced */
    ++){
    ++  sqlite3 *db = pParse->db;
    ++  Expr *pNew = sqlite3ExprDup(db, pX, 0);
    ++  if( db->mallocFailed==0 ){
    ++    ExprList *pOrigRhs = pNew->x.pSelect->pEList;  /* Original unmodified RHS */
    ++    ExprList *pOrigLhs = pNew->pLeft->x.pList;     /* Original unmodified LHS */
    ++    ExprList *pRhs = 0;         /* New RHS after modifications */
    ++    ExprList *pLhs = 0;         /* New LHS after mods */
    ++    int i;                      /* Loop counter */
    ++    Select *pSelect;            /* Pointer to the SELECT on the RHS */
    ++
    ++    for(i=iEq; i<pLoop->nLTerm; i++){
    ++      if( pLoop->aLTerm[i]->pExpr==pX ){
    ++        int iField = pLoop->aLTerm[i]->iField - 1;
    ++        assert( pOrigRhs->a[iField].pExpr!=0 );
    ++        pRhs = sqlite3ExprListAppend(pParse, pRhs, pOrigRhs->a[iField].pExpr);
    ++        pOrigRhs->a[iField].pExpr = 0;
    ++        assert( pOrigLhs->a[iField].pExpr!=0 );
    ++        pLhs = sqlite3ExprListAppend(pParse, pLhs, pOrigLhs->a[iField].pExpr);
    ++        pOrigLhs->a[iField].pExpr = 0;
    ++      }
    ++    }
    ++    sqlite3ExprListDelete(db, pOrigRhs);
    ++    sqlite3ExprListDelete(db, pOrigLhs);
    ++    pNew->pLeft->x.pList = pLhs;
    ++    pNew->x.pSelect->pEList = pRhs;
    ++    if( pLhs && pLhs->nExpr==1 ){
    ++      /* Take care here not to generate a TK_VECTOR containing only a
    ++      ** single value. Since the parser never creates such a vector, some
    ++      ** of the subroutines do not handle this case.  */
    ++      Expr *p = pLhs->a[0].pExpr;
    ++      pLhs->a[0].pExpr = 0;
    ++      sqlite3ExprDelete(db, pNew->pLeft);
    ++      pNew->pLeft = p;
    ++    }
    ++    pSelect = pNew->x.pSelect;
    ++    if( pSelect->pOrderBy ){
    ++      /* If the SELECT statement has an ORDER BY clause, zero the 
    ++      ** iOrderByCol variables. These are set to non-zero when an 
    ++      ** ORDER BY term exactly matches one of the terms of the 
    ++      ** result-set. Since the result-set of the SELECT statement may
    ++      ** have been modified or reordered, these variables are no longer 
    ++      ** set correctly.  Since setting them is just an optimization, 
    ++      ** it's easiest just to zero them here.  */
    ++      ExprList *pOrderBy = pSelect->pOrderBy;
    ++      for(i=0; i<pOrderBy->nExpr; i++){
    ++        pOrderBy->a[i].u.x.iOrderByCol = 0;
    ++      }
    ++    }
    ++
    ++#if 0
    ++    printf("For indexing, change the IN expr:\n");
    ++    sqlite3TreeViewExpr(0, pX, 0);
    ++    printf("Into:\n");
    ++    sqlite3TreeViewExpr(0, pNew, 0);
    ++#endif
    ++  }
    ++  return pNew;
    ++}
    ++
    + 
    + /*
    + ** Generate code for a single equality term of the WHERE clause.  An equality
    + ** term can be either X=expr or X IN (...).   pTerm is the term to be 
    + ** coded.
    + **
    +-** The current value for the constraint is left in register iReg.
    ++** The current value for the constraint is left in a register, the index
    ++** of which is returned.  An attempt is made store the result in iTarget but
    ++** this is only guaranteed for TK_ISNULL and TK_IN constraints.  If the
    ++** constraint is a TK_EQ or TK_IS, then the current value might be left in
    ++** some other register and it is the caller's responsibility to compensate.
    + **
    +-** For a constraint of the form X=expr, the expression is evaluated and its
    +-** result is left on the stack.  For constraints of the form X IN (...)
    ++** For a constraint of the form X=expr, the expression is evaluated in
    ++** straight-line code.  For constraints of the form X IN (...)
    + ** this routine sets up a loop that will iterate over all values of X.
    + */
    + static int codeEqualityTerm(
    +@@ -118875,6 +129668,7 @@ static int codeEqualityTerm(
    +   Vdbe *v = pParse->pVdbe;
    +   int iReg;                  /* Register holding results */
    + 
    ++  assert( pLevel->pWLoop->aLTerm[iEq]==pTerm );
    +   assert( iTarget>0 );
    +   if( pX->op==TK_EQ || pX->op==TK_IS ){
    +     iReg = sqlite3ExprCodeTarget(pParse, pX->pRight, iTarget);
    +@@ -118883,10 +129677,13 @@ static int codeEqualityTerm(
    +     sqlite3VdbeAddOp2(v, OP_Null, 0, iReg);
    + #ifndef SQLITE_OMIT_SUBQUERY
    +   }else{
    +-    int eType;
    ++    int eType = IN_INDEX_NOOP;
    +     int iTab;
    +     struct InLoop *pIn;
    +     WhereLoop *pLoop = pLevel->pWLoop;
    ++    int i;
    ++    int nEq = 0;
    ++    int *aiMap = 0;
    + 
    +     if( (pLoop->wsFlags & WHERE_VIRTUALTABLE)==0
    +       && pLoop->u.btree.pIndex!=0
    +@@ -118898,7 +129695,33 @@ static int codeEqualityTerm(
    +     }
    +     assert( pX->op==TK_IN );
    +     iReg = iTarget;
    +-    eType = sqlite3FindInIndex(pParse, pX, IN_INDEX_LOOP, 0);
    ++
    ++    for(i=0; i<iEq; i++){
    ++      if( pLoop->aLTerm[i] && pLoop->aLTerm[i]->pExpr==pX ){
    ++        disableTerm(pLevel, pTerm);
    ++        return iTarget;
    ++      }
    ++    }
    ++    for(i=iEq;i<pLoop->nLTerm; i++){
    ++      assert( pLoop->aLTerm[i]!=0 );
    ++      if( pLoop->aLTerm[i]->pExpr==pX ) nEq++;
    ++    }
    ++
    ++    if( (pX->flags & EP_xIsSelect)==0 || pX->x.pSelect->pEList->nExpr==1 ){
    ++      eType = sqlite3FindInIndex(pParse, pX, IN_INDEX_LOOP, 0, 0);
    ++    }else{
    ++      sqlite3 *db = pParse->db;
    ++      pX = removeUnindexableInClauseTerms(pParse, iEq, pLoop, pX);
    ++
    ++      if( !db->mallocFailed ){
    ++        aiMap = (int*)sqlite3DbMallocZero(pParse->db, sizeof(int)*nEq);
    ++        eType = sqlite3FindInIndex(pParse, pX, IN_INDEX_LOOP, 0, aiMap);
    ++        pTerm->pExpr->iTable = pX->iTable;
    ++      }
    ++      sqlite3ExprDelete(db, pX);
    ++      pX = pTerm->pExpr;
    ++    }
    ++
    +     if( eType==IN_INDEX_INDEX_DESC ){
    +       testcase( bRev );
    +       bRev = !bRev;
    +@@ -118908,28 +129731,45 @@ static int codeEqualityTerm(
    +     VdbeCoverageIf(v, bRev);
    +     VdbeCoverageIf(v, !bRev);
    +     assert( (pLoop->wsFlags & WHERE_MULTI_OR)==0 );
    ++
    +     pLoop->wsFlags |= WHERE_IN_ABLE;
    +     if( pLevel->u.in.nIn==0 ){
    +       pLevel->addrNxt = sqlite3VdbeMakeLabel(v);
    +     }
    +-    pLevel->u.in.nIn++;
    ++
    ++    i = pLevel->u.in.nIn;
    ++    pLevel->u.in.nIn += nEq;
    +     pLevel->u.in.aInLoop =
    +        sqlite3DbReallocOrFree(pParse->db, pLevel->u.in.aInLoop,
    +                               sizeof(pLevel->u.in.aInLoop[0])*pLevel->u.in.nIn);
    +     pIn = pLevel->u.in.aInLoop;
    +     if( pIn ){
    +-      pIn += pLevel->u.in.nIn - 1;
    +-      pIn->iCur = iTab;
    +-      if( eType==IN_INDEX_ROWID ){
    +-        pIn->addrInTop = sqlite3VdbeAddOp2(v, OP_Rowid, iTab, iReg);
    +-      }else{
    +-        pIn->addrInTop = sqlite3VdbeAddOp3(v, OP_Column, iTab, 0, iReg);
    ++      int iMap = 0;               /* Index in aiMap[] */
    ++      pIn += i;
    ++      for(i=iEq;i<pLoop->nLTerm; i++){
    ++        if( pLoop->aLTerm[i]->pExpr==pX ){
    ++          int iOut = iReg + i - iEq;
    ++          if( eType==IN_INDEX_ROWID ){
    ++            testcase( nEq>1 );  /* Happens with a UNIQUE index on ROWID */
    ++            pIn->addrInTop = sqlite3VdbeAddOp2(v, OP_Rowid, iTab, iOut);
    ++          }else{
    ++            int iCol = aiMap ? aiMap[iMap++] : 0;
    ++            pIn->addrInTop = sqlite3VdbeAddOp3(v,OP_Column,iTab, iCol, iOut);
    ++          }
    ++          sqlite3VdbeAddOp1(v, OP_IsNull, iOut); VdbeCoverage(v);
    ++          if( i==iEq ){
    ++            pIn->iCur = iTab;
    ++            pIn->eEndLoopOp = bRev ? OP_PrevIfOpen : OP_NextIfOpen;
    ++          }else{
    ++            pIn->eEndLoopOp = OP_Noop;
    ++          }
    ++          pIn++;
    ++        }
    +       }
    +-      pIn->eEndLoopOp = bRev ? OP_PrevIfOpen : OP_NextIfOpen;
    +-      sqlite3VdbeAddOp1(v, OP_IsNull, iReg); VdbeCoverage(v);
    +     }else{
    +       pLevel->u.in.nIn = 0;
    +     }
    ++    sqlite3DbFree(pParse->db, aiMap);
    + #endif
    +   }
    +   disableTerm(pLevel, pTerm);
    +@@ -119014,9 +129854,7 @@ static int codeAllEqualityTerms(
    +   pParse->nMem += nReg;
    + 
    +   zAff = sqlite3DbStrDup(pParse->db,sqlite3IndexAffinityStr(pParse->db,pIdx));
    +-  if( !zAff ){
    +-    pParse->db->mallocFailed = 1;
    +-  }
    ++  assert( zAff!=0 || pParse->db->mallocFailed );
    + 
    +   if( nSkip ){
    +     int iIdxCur = pLevel->iIdxCur;
    +@@ -119057,9 +129895,15 @@ static int codeAllEqualityTerms(
    +         sqlite3VdbeAddOp2(v, OP_SCopy, r1, regBase+j);
    +       }
    +     }
    +-    testcase( pTerm->eOperator & WO_ISNULL );
    +-    testcase( pTerm->eOperator & WO_IN );
    +-    if( (pTerm->eOperator & (WO_ISNULL|WO_IN))==0 ){
    ++    if( pTerm->eOperator & WO_IN ){
    ++      if( pTerm->pExpr->flags & EP_xIsSelect ){
    ++        /* No affinity ever needs to be (or should be) applied to a value
    ++        ** from the RHS of an "? IN (SELECT ...)" expression. The 
    ++        ** sqlite3FindInIndex() routine has already ensured that the 
    ++        ** affinity of the comparison has been applied to the value.  */
    ++        if( zAff ) zAff[j] = SQLITE_AFF_BLOB;
    ++      }
    ++    }else if( (pTerm->eOperator & WO_ISNULL)==0 ){
    +       Expr *pRight = pTerm->pExpr->pRight;
    +       if( (pTerm->wtFlags & TERM_IS)==0 && sqlite3ExprCanBeNull(pRight) ){
    +         sqlite3VdbeAddOp2(v, OP_IsNull, regBase+j, pLevel->addrBrk);
    +@@ -119079,17 +129923,23 @@ static int codeAllEqualityTerms(
    +   return regBase;
    + }
    + 
    ++#ifndef SQLITE_LIKE_DOESNT_MATCH_BLOBS
    + /*
    +-** If the most recently coded instruction is a constant range contraint
    +-** that originated from the LIKE optimization, then change the P3 to be
    +-** pLoop->iLikeRepCntr and set P5.
    ++** If the most recently coded instruction is a constant range constraint
    ++** (a string literal) that originated from the LIKE optimization, then 
    ++** set P3 and P5 on the OP_String opcode so that the string will be cast
    ++** to a BLOB at appropriate times.
    + **
    + ** The LIKE optimization trys to evaluate "x LIKE 'abc%'" as a range
    + ** expression: "x>='ABC' AND x<'abd'".  But this requires that the range
    + ** scan loop run twice, once for strings and a second time for BLOBs.
    + ** The OP_String opcodes on the second pass convert the upper and lower
    +-** bound string contants to blobs.  This routine makes the necessary changes
    ++** bound string constants to blobs.  This routine makes the necessary changes
    + ** to the OP_String opcodes for that to happen.
    ++**
    ++** Except, of course, if SQLITE_LIKE_DOESNT_MATCH_BLOBS is defined, then
    ++** only the one pass through the string space is required, so this routine
    ++** becomes a no-op.
    + */
    + static void whereLikeOptimizationStringFixup(
    +   Vdbe *v,                /* prepared statement under construction */
    +@@ -119103,11 +129953,374 @@ static void whereLikeOptimizationStringFixup(
    +     assert( pOp!=0 );
    +     assert( pOp->opcode==OP_String8 
    +             || pTerm->pWC->pWInfo->pParse->db->mallocFailed );
    +-    pOp->p3 = pLevel->iLikeRepCntr;
    +-    pOp->p5 = 1;
    ++    pOp->p3 = (int)(pLevel->iLikeRepCntr>>1);  /* Register holding counter */
    ++    pOp->p5 = (u8)(pLevel->iLikeRepCntr&1);    /* ASC or DESC */
    ++  }
    ++}
    ++#else
    ++# define whereLikeOptimizationStringFixup(A,B,C)
    ++#endif
    ++
    ++#ifdef SQLITE_ENABLE_CURSOR_HINTS
    ++/*
    ++** Information is passed from codeCursorHint() down to individual nodes of
    ++** the expression tree (by sqlite3WalkExpr()) using an instance of this
    ++** structure.
    ++*/
    ++struct CCurHint {
    ++  int iTabCur;    /* Cursor for the main table */
    ++  int iIdxCur;    /* Cursor for the index, if pIdx!=0.  Unused otherwise */
    ++  Index *pIdx;    /* The index used to access the table */
    ++};
    ++
    ++/*
    ++** This function is called for every node of an expression that is a candidate
    ++** for a cursor hint on an index cursor.  For TK_COLUMN nodes that reference
    ++** the table CCurHint.iTabCur, verify that the same column can be
    ++** accessed through the index.  If it cannot, then set pWalker->eCode to 1.
    ++*/
    ++static int codeCursorHintCheckExpr(Walker *pWalker, Expr *pExpr){
    ++  struct CCurHint *pHint = pWalker->u.pCCurHint;
    ++  assert( pHint->pIdx!=0 );
    ++  if( pExpr->op==TK_COLUMN
    ++   && pExpr->iTable==pHint->iTabCur
    ++   && sqlite3ColumnOfIndex(pHint->pIdx, pExpr->iColumn)<0
    ++  ){
    ++    pWalker->eCode = 1;
    ++  }
    ++  return WRC_Continue;
    ++}
    ++
    ++/*
    ++** Test whether or not expression pExpr, which was part of a WHERE clause,
    ++** should be included in the cursor-hint for a table that is on the rhs
    ++** of a LEFT JOIN. Set Walker.eCode to non-zero before returning if the 
    ++** expression is not suitable.
    ++**
    ++** An expression is unsuitable if it might evaluate to non NULL even if
    ++** a TK_COLUMN node that does affect the value of the expression is set
    ++** to NULL. For example:
    ++**
    ++**   col IS NULL
    ++**   col IS NOT NULL
    ++**   coalesce(col, 1)
    ++**   CASE WHEN col THEN 0 ELSE 1 END
    ++*/
    ++static int codeCursorHintIsOrFunction(Walker *pWalker, Expr *pExpr){
    ++  if( pExpr->op==TK_IS 
    ++   || pExpr->op==TK_ISNULL || pExpr->op==TK_ISNOT 
    ++   || pExpr->op==TK_NOTNULL || pExpr->op==TK_CASE 
    ++  ){
    ++    pWalker->eCode = 1;
    ++  }else if( pExpr->op==TK_FUNCTION ){
    ++    int d1;
    ++    char d2[4];
    ++    if( 0==sqlite3IsLikeFunction(pWalker->pParse->db, pExpr, &d1, d2) ){
    ++      pWalker->eCode = 1;
    ++    }
    ++  }
    ++
    ++  return WRC_Continue;
    ++}
    ++
    ++
    ++/*
    ++** This function is called on every node of an expression tree used as an
    ++** argument to the OP_CursorHint instruction. If the node is a TK_COLUMN
    ++** that accesses any table other than the one identified by
    ++** CCurHint.iTabCur, then do the following:
    ++**
    ++**   1) allocate a register and code an OP_Column instruction to read 
    ++**      the specified column into the new register, and
    ++**
    ++**   2) transform the expression node to a TK_REGISTER node that reads 
    ++**      from the newly populated register.
    ++**
    ++** Also, if the node is a TK_COLUMN that does access the table idenified
    ++** by pCCurHint.iTabCur, and an index is being used (which we will
    ++** know because CCurHint.pIdx!=0) then transform the TK_COLUMN into
    ++** an access of the index rather than the original table.
    ++*/
    ++static int codeCursorHintFixExpr(Walker *pWalker, Expr *pExpr){
    ++  int rc = WRC_Continue;
    ++  struct CCurHint *pHint = pWalker->u.pCCurHint;
    ++  if( pExpr->op==TK_COLUMN ){
    ++    if( pExpr->iTable!=pHint->iTabCur ){
    ++      Vdbe *v = pWalker->pParse->pVdbe;
    ++      int reg = ++pWalker->pParse->nMem;   /* Register for column value */
    ++      sqlite3ExprCodeGetColumnOfTable(
    ++          v, pExpr->pTab, pExpr->iTable, pExpr->iColumn, reg
    ++      );
    ++      pExpr->op = TK_REGISTER;
    ++      pExpr->iTable = reg;
    ++    }else if( pHint->pIdx!=0 ){
    ++      pExpr->iTable = pHint->iIdxCur;
    ++      pExpr->iColumn = sqlite3ColumnOfIndex(pHint->pIdx, pExpr->iColumn);
    ++      assert( pExpr->iColumn>=0 );
    ++    }
    ++  }else if( pExpr->op==TK_AGG_FUNCTION ){
    ++    /* An aggregate function in the WHERE clause of a query means this must
    ++    ** be a correlated sub-query, and expression pExpr is an aggregate from
    ++    ** the parent context. Do not walk the function arguments in this case.
    ++    **
    ++    ** todo: It should be possible to replace this node with a TK_REGISTER
    ++    ** expression, as the result of the expression must be stored in a 
    ++    ** register at this point. The same holds for TK_AGG_COLUMN nodes. */
    ++    rc = WRC_Prune;
    ++  }
    ++  return rc;
    ++}
    ++
    ++/*
    ++** Insert an OP_CursorHint instruction if it is appropriate to do so.
    ++*/
    ++static void codeCursorHint(
    ++  struct SrcList_item *pTabItem,  /* FROM clause item */
    ++  WhereInfo *pWInfo,    /* The where clause */
    ++  WhereLevel *pLevel,   /* Which loop to provide hints for */
    ++  WhereTerm *pEndRange  /* Hint this end-of-scan boundary term if not NULL */
    ++){
    ++  Parse *pParse = pWInfo->pParse;
    ++  sqlite3 *db = pParse->db;
    ++  Vdbe *v = pParse->pVdbe;
    ++  Expr *pExpr = 0;
    ++  WhereLoop *pLoop = pLevel->pWLoop;
    ++  int iCur;
    ++  WhereClause *pWC;
    ++  WhereTerm *pTerm;
    ++  int i, j;
    ++  struct CCurHint sHint;
    ++  Walker sWalker;
    ++
    ++  if( OptimizationDisabled(db, SQLITE_CursorHints) ) return;
    ++  iCur = pLevel->iTabCur;
    ++  assert( iCur==pWInfo->pTabList->a[pLevel->iFrom].iCursor );
    ++  sHint.iTabCur = iCur;
    ++  sHint.iIdxCur = pLevel->iIdxCur;
    ++  sHint.pIdx = pLoop->u.btree.pIndex;
    ++  memset(&sWalker, 0, sizeof(sWalker));
    ++  sWalker.pParse = pParse;
    ++  sWalker.u.pCCurHint = &sHint;
    ++  pWC = &pWInfo->sWC;
    ++  for(i=0; i<pWC->nTerm; i++){
    ++    pTerm = &pWC->a[i];
    ++    if( pTerm->wtFlags & (TERM_VIRTUAL|TERM_CODED) ) continue;
    ++    if( pTerm->prereqAll & pLevel->notReady ) continue;
    ++
    ++    /* Any terms specified as part of the ON(...) clause for any LEFT 
    ++    ** JOIN for which the current table is not the rhs are omitted
    ++    ** from the cursor-hint. 
    ++    **
    ++    ** If this table is the rhs of a LEFT JOIN, "IS" or "IS NULL" terms 
    ++    ** that were specified as part of the WHERE clause must be excluded.
    ++    ** This is to address the following:
    ++    **
    ++    **   SELECT ... t1 LEFT JOIN t2 ON (t1.a=t2.b) WHERE t2.c IS NULL;
    ++    **
    ++    ** Say there is a single row in t2 that matches (t1.a=t2.b), but its
    ++    ** t2.c values is not NULL. If the (t2.c IS NULL) constraint is 
    ++    ** pushed down to the cursor, this row is filtered out, causing
    ++    ** SQLite to synthesize a row of NULL values. Which does match the
    ++    ** WHERE clause, and so the query returns a row. Which is incorrect.
    ++    **
    ++    ** For the same reason, WHERE terms such as:
    ++    **
    ++    **   WHERE 1 = (t2.c IS NULL)
    ++    **
    ++    ** are also excluded. See codeCursorHintIsOrFunction() for details.
    ++    */
    ++    if( pTabItem->fg.jointype & JT_LEFT ){
    ++      Expr *pExpr = pTerm->pExpr;
    ++      if( !ExprHasProperty(pExpr, EP_FromJoin) 
    ++       || pExpr->iRightJoinTable!=pTabItem->iCursor
    ++      ){
    ++        sWalker.eCode = 0;
    ++        sWalker.xExprCallback = codeCursorHintIsOrFunction;
    ++        sqlite3WalkExpr(&sWalker, pTerm->pExpr);
    ++        if( sWalker.eCode ) continue;
    ++      }
    ++    }else{
    ++      if( ExprHasProperty(pTerm->pExpr, EP_FromJoin) ) continue;
    ++    }
    ++
    ++    /* All terms in pWLoop->aLTerm[] except pEndRange are used to initialize
    ++    ** the cursor.  These terms are not needed as hints for a pure range
    ++    ** scan (that has no == terms) so omit them. */
    ++    if( pLoop->u.btree.nEq==0 && pTerm!=pEndRange ){
    ++      for(j=0; j<pLoop->nLTerm && pLoop->aLTerm[j]!=pTerm; j++){}
    ++      if( j<pLoop->nLTerm ) continue;
    ++    }
    ++
    ++    /* No subqueries or non-deterministic functions allowed */
    ++    if( sqlite3ExprContainsSubquery(pTerm->pExpr) ) continue;
    ++
    ++    /* For an index scan, make sure referenced columns are actually in
    ++    ** the index. */
    ++    if( sHint.pIdx!=0 ){
    ++      sWalker.eCode = 0;
    ++      sWalker.xExprCallback = codeCursorHintCheckExpr;
    ++      sqlite3WalkExpr(&sWalker, pTerm->pExpr);
    ++      if( sWalker.eCode ) continue;
    ++    }
    ++
    ++    /* If we survive all prior tests, that means this term is worth hinting */
    ++    pExpr = sqlite3ExprAnd(db, pExpr, sqlite3ExprDup(db, pTerm->pExpr, 0));
    ++  }
    ++  if( pExpr!=0 ){
    ++    sWalker.xExprCallback = codeCursorHintFixExpr;
    ++    sqlite3WalkExpr(&sWalker, pExpr);
    ++    sqlite3VdbeAddOp4(v, OP_CursorHint, 
    ++                      (sHint.pIdx ? sHint.iIdxCur : sHint.iTabCur), 0, 0,
    ++                      (const char*)pExpr, P4_EXPR);
    ++  }
    ++}
    ++#else
    ++# define codeCursorHint(A,B,C,D)  /* No-op */
    ++#endif /* SQLITE_ENABLE_CURSOR_HINTS */
    ++
    ++/*
    ++** Cursor iCur is open on an intkey b-tree (a table). Register iRowid contains
    ++** a rowid value just read from cursor iIdxCur, open on index pIdx. This
    ++** function generates code to do a deferred seek of cursor iCur to the 
    ++** rowid stored in register iRowid.
    ++**
    ++** Normally, this is just:
    ++**
    ++**   OP_DeferredSeek $iCur $iRowid
    ++**
    ++** However, if the scan currently being coded is a branch of an OR-loop and
    ++** the statement currently being coded is a SELECT, then P3 of OP_DeferredSeek
    ++** is set to iIdxCur and P4 is set to point to an array of integers
    ++** containing one entry for each column of the table cursor iCur is open 
    ++** on. For each table column, if the column is the i'th column of the 
    ++** index, then the corresponding array entry is set to (i+1). If the column
    ++** does not appear in the index at all, the array entry is set to 0.
    ++*/
    ++static void codeDeferredSeek(
    ++  WhereInfo *pWInfo,              /* Where clause context */
    ++  Index *pIdx,                    /* Index scan is using */
    ++  int iCur,                       /* Cursor for IPK b-tree */
    ++  int iIdxCur                     /* Index cursor */
    ++){
    ++  Parse *pParse = pWInfo->pParse; /* Parse context */
    ++  Vdbe *v = pParse->pVdbe;        /* Vdbe to generate code within */
    ++
    ++  assert( iIdxCur>0 );
    ++  assert( pIdx->aiColumn[pIdx->nColumn-1]==-1 );
    ++  
    ++  sqlite3VdbeAddOp3(v, OP_DeferredSeek, iIdxCur, 0, iCur);
    ++  if( (pWInfo->wctrlFlags & WHERE_OR_SUBCLAUSE)
    ++   && DbMaskAllZero(sqlite3ParseToplevel(pParse)->writeMask)
    ++  ){
    ++    int i;
    ++    Table *pTab = pIdx->pTable;
    ++    int *ai = (int*)sqlite3DbMallocZero(pParse->db, sizeof(int)*(pTab->nCol+1));
    ++    if( ai ){
    ++      ai[0] = pTab->nCol;
    ++      for(i=0; i<pIdx->nColumn-1; i++){
    ++        assert( pIdx->aiColumn[i]<pTab->nCol );
    ++        if( pIdx->aiColumn[i]>=0 ) ai[pIdx->aiColumn[i]+1] = i+1;
    ++      }
    ++      sqlite3VdbeChangeP4(v, -1, (char*)ai, P4_INTARRAY);
    ++    }
    ++  }
    ++}
    ++
    ++/*
    ++** If the expression passed as the second argument is a vector, generate
    ++** code to write the first nReg elements of the vector into an array
    ++** of registers starting with iReg.
    ++**
    ++** If the expression is not a vector, then nReg must be passed 1. In
    ++** this case, generate code to evaluate the expression and leave the
    ++** result in register iReg.
    ++*/
    ++static void codeExprOrVector(Parse *pParse, Expr *p, int iReg, int nReg){
    ++  assert( nReg>0 );
    ++  if( p && sqlite3ExprIsVector(p) ){
    ++#ifndef SQLITE_OMIT_SUBQUERY
    ++    if( (p->flags & EP_xIsSelect) ){
    ++      Vdbe *v = pParse->pVdbe;
    ++      int iSelect = sqlite3CodeSubselect(pParse, p, 0, 0);
    ++      sqlite3VdbeAddOp3(v, OP_Copy, iSelect, iReg, nReg-1);
    ++    }else
    ++#endif
    ++    {
    ++      int i;
    ++      ExprList *pList = p->x.pList;
    ++      assert( nReg<=pList->nExpr );
    ++      for(i=0; i<nReg; i++){
    ++        sqlite3ExprCode(pParse, pList->a[i].pExpr, iReg+i);
    ++      }
    ++    }
    ++  }else{
    ++    assert( nReg==1 );
    ++    sqlite3ExprCode(pParse, p, iReg);
    +   }
    + }
    + 
    ++/* An instance of the IdxExprTrans object carries information about a
    ++** mapping from an expression on table columns into a column in an index
    ++** down through the Walker.
    ++*/
    ++typedef struct IdxExprTrans {
    ++  Expr *pIdxExpr;    /* The index expression */
    ++  int iTabCur;       /* The cursor of the corresponding table */
    ++  int iIdxCur;       /* The cursor for the index */
    ++  int iIdxCol;       /* The column for the index */
    ++} IdxExprTrans;
    ++
    ++/* The walker node callback used to transform matching expressions into
    ++** a reference to an index column for an index on an expression.
    ++**
    ++** If pExpr matches, then transform it into a reference to the index column
    ++** that contains the value of pExpr.
    ++*/
    ++static int whereIndexExprTransNode(Walker *p, Expr *pExpr){
    ++  IdxExprTrans *pX = p->u.pIdxTrans;
    ++  if( sqlite3ExprCompare(0, pExpr, pX->pIdxExpr, pX->iTabCur)==0 ){
    ++    pExpr->op = TK_COLUMN;
    ++    pExpr->iTable = pX->iIdxCur;
    ++    pExpr->iColumn = pX->iIdxCol;
    ++    pExpr->pTab = 0;
    ++    return WRC_Prune;
    ++  }else{
    ++    return WRC_Continue;
    ++  }
    ++}
    ++
    ++/*
    ++** For an indexes on expression X, locate every instance of expression X
    ++** in pExpr and change that subexpression into a reference to the appropriate
    ++** column of the index.
    ++*/
    ++static void whereIndexExprTrans(
    ++  Index *pIdx,      /* The Index */
    ++  int iTabCur,      /* Cursor of the table that is being indexed */
    ++  int iIdxCur,      /* Cursor of the index itself */
    ++  WhereInfo *pWInfo /* Transform expressions in this WHERE clause */
    ++){
    ++  int iIdxCol;               /* Column number of the index */
    ++  ExprList *aColExpr;        /* Expressions that are indexed */
    ++  Walker w;
    ++  IdxExprTrans x;
    ++  aColExpr = pIdx->aColExpr;
    ++  if( aColExpr==0 ) return;  /* Not an index on expressions */
    ++  memset(&w, 0, sizeof(w));
    ++  w.xExprCallback = whereIndexExprTransNode;
    ++  w.u.pIdxTrans = &x;
    ++  x.iTabCur = iTabCur;
    ++  x.iIdxCur = iIdxCur;
    ++  for(iIdxCol=0; iIdxCol<aColExpr->nExpr; iIdxCol++){
    ++    if( pIdx->aiColumn[iIdxCol]!=XN_EXPR ) continue;
    ++    assert( aColExpr->a[iIdxCol].pExpr!=0 );
    ++    x.iIdxCol = iIdxCol;
    ++    x.pIdxExpr = aColExpr->a[iIdxCol].pExpr;
    ++    sqlite3WalkExpr(&w, pWInfo->pWhere);
    ++    sqlite3WalkExprList(&w, pWInfo->pOrderBy);
    ++    sqlite3WalkExprList(&w, pWInfo->pResultSet);
    ++  }
    ++}
    + 
    + /*
    + ** Generate code for the start of the iLevel-th loop in the WHERE clause
    +@@ -119132,9 +130345,12 @@ SQLITE_PRIVATE Bitmask sqlite3WhereCodeOneLoopStart(
    +   Vdbe *v;                        /* The prepared stmt under constructions */
    +   struct SrcList_item *pTabItem;  /* FROM clause term being coded */
    +   int addrBrk;                    /* Jump here to break out of the loop */
    ++  int addrHalt;                   /* addrBrk for the outermost loop */
    +   int addrCont;                   /* Jump here to continue with next cycle */
    +   int iRowidReg = 0;        /* Rowid is stored in this register, if not zero */
    +   int iReleaseReg = 0;      /* Temp register to free before returning */
    ++  Index *pIdx = 0;          /* Index used by loop (if any) */
    ++  int iLoop;                /* Iteration of constraint generator loop */
    + 
    +   pParse = pWInfo->pParse;
    +   v = pParse->pVdbe;
    +@@ -119147,7 +130363,7 @@ SQLITE_PRIVATE Bitmask sqlite3WhereCodeOneLoopStart(
    +   pLevel->notReady = notReady & ~sqlite3WhereGetMask(&pWInfo->sMaskSet, iCur);
    +   bRev = (pWInfo->revMask>>iLevel)&1;
    +   omitTable = (pLoop->wsFlags & WHERE_IDX_ONLY)!=0 
    +-           && (pWInfo->wctrlFlags & WHERE_FORCE_TABLE)==0;
    ++           && (pWInfo->wctrlFlags & WHERE_OR_SUBCLAUSE)==0;
    +   VdbeModuleComment((v, "Begin WHERE-loop%d: %s",iLevel,pTabItem->pTab->zName));
    + 
    +   /* Create labels for the "break" and "continue" instructions
    +@@ -119173,6 +130389,11 @@ SQLITE_PRIVATE Bitmask sqlite3WhereCodeOneLoopStart(
    +     VdbeComment((v, "init LEFT JOIN no-match flag"));
    +   }
    + 
    ++  /* Compute a safe address to jump to if we discover that the table for
    ++  ** this loop is empty and can never contribute content. */
    ++  for(j=iLevel; j>0 && pWInfo->a[j].iLeftJoin==0; j--){}
    ++  addrHalt = pWInfo->a[j].addrBrk;
    ++
    +   /* Special case of a FROM clause subquery implemented as a co-routine */
    +   if( pTabItem->fg.viaCoroutine ){
    +     int regYield = pTabItem->regReturn;
    +@@ -119191,6 +130412,7 @@ SQLITE_PRIVATE Bitmask sqlite3WhereCodeOneLoopStart(
    +     int iReg;   /* P3 Value for OP_VFilter */
    +     int addrNotFound;
    +     int nConstraint = pLoop->nLTerm;
    ++    int iIn;    /* Counter for IN constraints */
    + 
    +     sqlite3ExprCachePush(pParse);
    +     iReg = sqlite3GetTempRange(pParse, nConstraint+2);
    +@@ -119198,30 +130420,73 @@ SQLITE_PRIVATE Bitmask sqlite3WhereCodeOneLoopStart(
    +     for(j=0; j<nConstraint; j++){
    +       int iTarget = iReg+j+2;
    +       pTerm = pLoop->aLTerm[j];
    +-      if( pTerm==0 ) continue;
    ++      if( NEVER(pTerm==0) ) continue;
    +       if( pTerm->eOperator & WO_IN ){
    +         codeEqualityTerm(pParse, pTerm, pLevel, j, bRev, iTarget);
    +         addrNotFound = pLevel->addrNxt;
    +       }else{
    +-        sqlite3ExprCode(pParse, pTerm->pExpr->pRight, iTarget);
    ++        Expr *pRight = pTerm->pExpr->pRight;
    ++        codeExprOrVector(pParse, pRight, iTarget, 1);
    +       }
    +     }
    +     sqlite3VdbeAddOp2(v, OP_Integer, pLoop->u.vtab.idxNum, iReg);
    +     sqlite3VdbeAddOp2(v, OP_Integer, nConstraint, iReg+1);
    +     sqlite3VdbeAddOp4(v, OP_VFilter, iCur, addrNotFound, iReg,
    +                       pLoop->u.vtab.idxStr,
    +-                      pLoop->u.vtab.needFree ? P4_MPRINTF : P4_STATIC);
    ++                      pLoop->u.vtab.needFree ? P4_DYNAMIC : P4_STATIC);
    +     VdbeCoverage(v);
    +     pLoop->u.vtab.needFree = 0;
    +-    for(j=0; j<nConstraint && j<16; j++){
    +-      if( (pLoop->u.vtab.omitMask>>j)&1 ){
    +-        disableTerm(pLevel, pLoop->aLTerm[j]);
    +-      }
    +-    }
    +     pLevel->p1 = iCur;
    +     pLevel->op = pWInfo->eOnePass ? OP_Noop : OP_VNext;
    +     pLevel->p2 = sqlite3VdbeCurrentAddr(v);
    +-    sqlite3ReleaseTempRange(pParse, iReg, nConstraint+2);
    ++    iIn = pLevel->u.in.nIn;
    ++    for(j=nConstraint-1; j>=0; j--){
    ++      pTerm = pLoop->aLTerm[j];
    ++      if( j<16 && (pLoop->u.vtab.omitMask>>j)&1 ){
    ++        disableTerm(pLevel, pTerm);
    ++      }else if( (pTerm->eOperator & WO_IN)!=0 ){
    ++        Expr *pCompare;  /* The comparison operator */
    ++        Expr *pRight;    /* RHS of the comparison */
    ++        VdbeOp *pOp;     /* Opcode to access the value of the IN constraint */
    ++
    ++        /* Reload the constraint value into reg[iReg+j+2].  The same value
    ++        ** was loaded into the same register prior to the OP_VFilter, but
    ++        ** the xFilter implementation might have changed the datatype or
    ++        ** encoding of the value in the register, so it *must* be reloaded. */
    ++        assert( pLevel->u.in.aInLoop!=0 || db->mallocFailed );
    ++        if( !db->mallocFailed ){
    ++          assert( iIn>0 );
    ++          pOp = sqlite3VdbeGetOp(v, pLevel->u.in.aInLoop[--iIn].addrInTop);
    ++          assert( pOp->opcode==OP_Column || pOp->opcode==OP_Rowid );
    ++          assert( pOp->opcode!=OP_Column || pOp->p3==iReg+j+2 );
    ++          assert( pOp->opcode!=OP_Rowid || pOp->p2==iReg+j+2 );
    ++          testcase( pOp->opcode==OP_Rowid );
    ++          sqlite3VdbeAddOp3(v, pOp->opcode, pOp->p1, pOp->p2, pOp->p3);
    ++        }
    ++
    ++        /* Generate code that will continue to the next row if 
    ++        ** the IN constraint is not satisfied */
    ++        pCompare = sqlite3PExpr(pParse, TK_EQ, 0, 0);
    ++        assert( pCompare!=0 || db->mallocFailed );
    ++        if( pCompare ){
    ++          pCompare->pLeft = pTerm->pExpr->pLeft;
    ++          pCompare->pRight = pRight = sqlite3Expr(db, TK_REGISTER, 0);
    ++          if( pRight ){
    ++            pRight->iTable = iReg+j+2;
    ++            sqlite3ExprIfFalse(pParse, pCompare, pLevel->addrCont, 0);
    ++          }
    ++          pCompare->pLeft = 0;
    ++          sqlite3ExprDelete(db, pCompare);
    ++        }
    ++      }
    ++    }
    ++    /* These registers need to be preserved in case there is an IN operator
    ++    ** loop.  So we could deallocate the registers here (and potentially
    ++    ** reuse them later) if (pLoop->wsFlags & WHERE_IN_ABLE)==0.  But it seems
    ++    ** simpler and safer to simply not reuse the registers.
    ++    **
    ++    **    sqlite3ReleaseTempRange(pParse, iReg, nConstraint+2);
    ++    */
    +     sqlite3ExprCachePop(pParse);
    +   }else
    + #endif /* SQLITE_OMIT_VIRTUALTABLE */
    +@@ -119244,8 +130509,7 @@ SQLITE_PRIVATE Bitmask sqlite3WhereCodeOneLoopStart(
    +     iRowidReg = codeEqualityTerm(pParse, pTerm, pLevel, 0, bRev, iReleaseReg);
    +     if( iRowidReg!=iReleaseReg ) sqlite3ReleaseTempReg(pParse, iReleaseReg);
    +     addrNxt = pLevel->addrNxt;
    +-    sqlite3VdbeAddOp2(v, OP_MustBeInt, iRowidReg, addrNxt); VdbeCoverage(v);
    +-    sqlite3VdbeAddOp3(v, OP_NotExists, iCur, addrNxt, iRowidReg);
    ++    sqlite3VdbeAddOp3(v, OP_SeekRowid, iCur, addrNxt, iRowidReg);
    +     VdbeCoverage(v);
    +     sqlite3ExprCacheAffinityChange(pParse, iRowidReg, 1);
    +     sqlite3ExprCacheStore(pParse, iCur, -1, iRowidReg);
    +@@ -119272,9 +130536,11 @@ SQLITE_PRIVATE Bitmask sqlite3WhereCodeOneLoopStart(
    +       pStart = pEnd;
    +       pEnd = pTerm;
    +     }
    ++    codeCursorHint(pTabItem, pWInfo, pLevel, pEnd);
    +     if( pStart ){
    +       Expr *pX;             /* The expression that defines the start bound */
    +       int r1, rTemp;        /* Registers for holding the start boundary */
    ++      int op;               /* Cursor seek operation */
    + 
    +       /* The following constant maps TK_xx codes into corresponding 
    +       ** seek opcodes.  It depends on a particular ordering of TK_xx
    +@@ -119294,8 +130560,16 @@ SQLITE_PRIVATE Bitmask sqlite3WhereCodeOneLoopStart(
    +       pX = pStart->pExpr;
    +       assert( pX!=0 );
    +       testcase( pStart->leftCursor!=iCur ); /* transitive constraints */
    +-      r1 = sqlite3ExprCodeTemp(pParse, pX->pRight, &rTemp);
    +-      sqlite3VdbeAddOp3(v, aMoveOp[pX->op-TK_GT], iCur, addrBrk, r1);
    ++      if( sqlite3ExprIsVector(pX->pRight) ){
    ++        r1 = rTemp = sqlite3GetTempReg(pParse);
    ++        codeExprOrVector(pParse, pX->pRight, r1, 1);
    ++        op = aMoveOp[(pX->op - TK_GT) | 0x0001];
    ++      }else{
    ++        r1 = sqlite3ExprCodeTemp(pParse, pX->pRight, &rTemp);
    ++        disableTerm(pLevel, pStart);
    ++        op = aMoveOp[(pX->op - TK_GT)];
    ++      }
    ++      sqlite3VdbeAddOp3(v, op, iCur, addrBrk, r1);
    +       VdbeComment((v, "pk"));
    +       VdbeCoverageIf(v, pX->op==TK_GT);
    +       VdbeCoverageIf(v, pX->op==TK_LE);
    +@@ -119303,9 +130577,8 @@ SQLITE_PRIVATE Bitmask sqlite3WhereCodeOneLoopStart(
    +       VdbeCoverageIf(v, pX->op==TK_GE);
    +       sqlite3ExprCacheAffinityChange(pParse, r1, 1);
    +       sqlite3ReleaseTempReg(pParse, rTemp);
    +-      disableTerm(pLevel, pStart);
    +     }else{
    +-      sqlite3VdbeAddOp2(v, bRev ? OP_Last : OP_Rewind, iCur, addrBrk);
    ++      sqlite3VdbeAddOp2(v, bRev ? OP_Last : OP_Rewind, iCur, addrHalt);
    +       VdbeCoverageIf(v, bRev==0);
    +       VdbeCoverageIf(v, bRev!=0);
    +     }
    +@@ -119317,13 +130590,17 @@ SQLITE_PRIVATE Bitmask sqlite3WhereCodeOneLoopStart(
    +       testcase( pEnd->leftCursor!=iCur ); /* Transitive constraints */
    +       testcase( pEnd->wtFlags & TERM_VIRTUAL );
    +       memEndValue = ++pParse->nMem;
    +-      sqlite3ExprCode(pParse, pX->pRight, memEndValue);
    +-      if( pX->op==TK_LT || pX->op==TK_GT ){
    ++      codeExprOrVector(pParse, pX->pRight, memEndValue, 1);
    ++      if( 0==sqlite3ExprIsVector(pX->pRight) 
    ++       && (pX->op==TK_LT || pX->op==TK_GT) 
    ++      ){
    +         testOp = bRev ? OP_Le : OP_Ge;
    +       }else{
    +         testOp = bRev ? OP_Lt : OP_Gt;
    +       }
    +-      disableTerm(pLevel, pEnd);
    ++      if( 0==sqlite3ExprIsVector(pX->pRight) ){
    ++        disableTerm(pLevel, pEnd);
    ++      }
    +     }
    +     start = sqlite3VdbeCurrentAddr(v);
    +     pLevel->op = bRev ? OP_Prev : OP_Next;
    +@@ -119390,6 +130667,8 @@ SQLITE_PRIVATE Bitmask sqlite3WhereCodeOneLoopStart(
    +       OP_IdxLT,            /* 3: (end_constraints &&  bRev &&  endEq) */
    +     };
    +     u16 nEq = pLoop->u.btree.nEq;     /* Number of == or IN terms */
    ++    u16 nBtm = pLoop->u.btree.nBtm;   /* Length of BTM vector */
    ++    u16 nTop = pLoop->u.btree.nTop;   /* Length of TOP vector */
    +     int regBase;                 /* Base register holding constraint values */
    +     WhereTerm *pRangeStart = 0;  /* Inequality constraint at range start */
    +     WhereTerm *pRangeEnd = 0;    /* Inequality constraint at range end */
    +@@ -119397,12 +130676,11 @@ SQLITE_PRIVATE Bitmask sqlite3WhereCodeOneLoopStart(
    +     int endEq;                   /* True if range end uses ==, >= or <= */
    +     int start_constraints;       /* Start of range is constrained */
    +     int nConstraint;             /* Number of constraint terms */
    +-    Index *pIdx;                 /* The index we will be using */
    +     int iIdxCur;                 /* The VDBE cursor for the index */
    +     int nExtraReg = 0;           /* Number of extra registers needed */
    +     int op;                      /* Instruction opcode */
    +     char *zStartAff;             /* Affinity for start of range constraint */
    +-    char cEndAff = 0;            /* Affinity for end of range constraint */
    ++    char *zEndAff = 0;           /* Affinity for end of range constraint */
    +     u8 bSeekPastNull = 0;        /* True to seek past initial nulls */
    +     u8 bStopAtNull = 0;          /* Add condition to terminate at NULLs */
    + 
    +@@ -119436,44 +130714,40 @@ SQLITE_PRIVATE Bitmask sqlite3WhereCodeOneLoopStart(
    +     j = nEq;
    +     if( pLoop->wsFlags & WHERE_BTM_LIMIT ){
    +       pRangeStart = pLoop->aLTerm[j++];
    +-      nExtraReg = 1;
    ++      nExtraReg = MAX(nExtraReg, pLoop->u.btree.nBtm);
    +       /* Like optimization range constraints always occur in pairs */
    +       assert( (pRangeStart->wtFlags & TERM_LIKEOPT)==0 || 
    +               (pLoop->wsFlags & WHERE_TOP_LIMIT)!=0 );
    +     }
    +     if( pLoop->wsFlags & WHERE_TOP_LIMIT ){
    +       pRangeEnd = pLoop->aLTerm[j++];
    +-      nExtraReg = 1;
    ++      nExtraReg = MAX(nExtraReg, pLoop->u.btree.nTop);
    ++#ifndef SQLITE_LIKE_DOESNT_MATCH_BLOBS
    +       if( (pRangeEnd->wtFlags & TERM_LIKEOPT)!=0 ){
    +         assert( pRangeStart!=0 );                     /* LIKE opt constraints */
    +         assert( pRangeStart->wtFlags & TERM_LIKEOPT );   /* occur in pairs */
    +-        pLevel->iLikeRepCntr = ++pParse->nMem;
    +-        testcase( bRev );
    +-        testcase( pIdx->aSortOrder[nEq]==SQLITE_SO_DESC );
    +-        sqlite3VdbeAddOp2(v, OP_Integer,
    +-                          bRev ^ (pIdx->aSortOrder[nEq]==SQLITE_SO_DESC),
    +-                          pLevel->iLikeRepCntr);
    ++        pLevel->iLikeRepCntr = (u32)++pParse->nMem;
    ++        sqlite3VdbeAddOp2(v, OP_Integer, 1, (int)pLevel->iLikeRepCntr);
    +         VdbeComment((v, "LIKE loop counter"));
    +         pLevel->addrLikeRep = sqlite3VdbeCurrentAddr(v);
    ++        /* iLikeRepCntr actually stores 2x the counter register number.  The
    ++        ** bottom bit indicates whether the search order is ASC or DESC. */
    ++        testcase( bRev );
    ++        testcase( pIdx->aSortOrder[nEq]==SQLITE_SO_DESC );
    ++        assert( (bRev & ~1)==0 );
    ++        pLevel->iLikeRepCntr <<=1;
    ++        pLevel->iLikeRepCntr |= bRev ^ (pIdx->aSortOrder[nEq]==SQLITE_SO_DESC);
    +       }
    +-      if( pRangeStart==0
    +-       && (j = pIdx->aiColumn[nEq])>=0 
    +-       && pIdx->pTable->aCol[j].notNull==0
    +-      ){
    +-        bSeekPastNull = 1;
    ++#endif
    ++      if( pRangeStart==0 ){
    ++        j = pIdx->aiColumn[nEq];
    ++        if( (j>=0 && pIdx->pTable->aCol[j].notNull==0) || j==XN_EXPR ){
    ++          bSeekPastNull = 1;
    ++        }
    +       }
    +     }
    +     assert( pRangeEnd==0 || (pRangeEnd->wtFlags & TERM_VNULL)==0 );
    + 
    +-    /* Generate code to evaluate all constraint terms using == or IN
    +-    ** and store the values of those terms in an array of registers
    +-    ** starting at regBase.
    +-    */
    +-    regBase = codeAllEqualityTerms(pParse,pLevel,bRev,nExtraReg,&zStartAff);
    +-    assert( zStartAff==0 || sqlite3Strlen30(zStartAff)>=nEq );
    +-    if( zStartAff ) cEndAff = zStartAff[nEq];
    +-    addrNxt = pLevel->addrNxt;
    +-
    +     /* If we are doing a reverse order scan on an ascending index, or
    +     ** a forward order scan on a descending index, interchange the 
    +     ** start and end terms (pRangeStart and pRangeEnd).
    +@@ -119483,8 +130757,21 @@ SQLITE_PRIVATE Bitmask sqlite3WhereCodeOneLoopStart(
    +     ){
    +       SWAP(WhereTerm *, pRangeEnd, pRangeStart);
    +       SWAP(u8, bSeekPastNull, bStopAtNull);
    ++      SWAP(u8, nBtm, nTop);
    +     }
    + 
    ++    /* Generate code to evaluate all constraint terms using == or IN
    ++    ** and store the values of those terms in an array of registers
    ++    ** starting at regBase.
    ++    */
    ++    codeCursorHint(pTabItem, pWInfo, pLevel, pRangeEnd);
    ++    regBase = codeAllEqualityTerms(pParse,pLevel,bRev,nExtraReg,&zStartAff);
    ++    assert( zStartAff==0 || sqlite3Strlen30(zStartAff)>=nEq );
    ++    if( zStartAff && nTop ){
    ++      zEndAff = sqlite3DbStrDup(db, &zStartAff[nEq]);
    ++    }
    ++    addrNxt = pLevel->addrNxt;
    ++
    +     testcase( pRangeStart && (pRangeStart->eOperator & WO_LE)!=0 );
    +     testcase( pRangeStart && (pRangeStart->eOperator & WO_GE)!=0 );
    +     testcase( pRangeEnd && (pRangeEnd->eOperator & WO_LE)!=0 );
    +@@ -119497,7 +130784,7 @@ SQLITE_PRIVATE Bitmask sqlite3WhereCodeOneLoopStart(
    +     nConstraint = nEq;
    +     if( pRangeStart ){
    +       Expr *pRight = pRangeStart->pExpr->pRight;
    +-      sqlite3ExprCode(pParse, pRight, regBase+nEq);
    ++      codeExprOrVector(pParse, pRight, regBase+nEq, nBtm);
    +       whereLikeOptimizationStringFixup(v, pLevel, pRangeStart);
    +       if( (pRangeStart->wtFlags & TERM_VNULL)==0
    +        && sqlite3ExprCanBeNull(pRight)
    +@@ -119506,18 +130793,16 @@ SQLITE_PRIVATE Bitmask sqlite3WhereCodeOneLoopStart(
    +         VdbeCoverage(v);
    +       }
    +       if( zStartAff ){
    +-        if( sqlite3CompareAffinity(pRight, zStartAff[nEq])==SQLITE_AFF_BLOB){
    +-          /* Since the comparison is to be performed with no conversions
    +-          ** applied to the operands, set the affinity to apply to pRight to 
    +-          ** SQLITE_AFF_BLOB.  */
    +-          zStartAff[nEq] = SQLITE_AFF_BLOB;
    +-        }
    +-        if( sqlite3ExprNeedsNoAffinityChange(pRight, zStartAff[nEq]) ){
    +-          zStartAff[nEq] = SQLITE_AFF_BLOB;
    +-        }
    ++        updateRangeAffinityStr(pRight, nBtm, &zStartAff[nEq]);
    +       }  
    +-      nConstraint++;
    ++      nConstraint += nBtm;
    +       testcase( pRangeStart->wtFlags & TERM_VIRTUAL );
    ++      if( sqlite3ExprIsVector(pRight)==0 ){
    ++        disableTerm(pLevel, pRangeStart);
    ++      }else{
    ++        startEq = 1;
    ++      }
    ++      bSeekPastNull = 0;
    +     }else if( bSeekPastNull ){
    +       sqlite3VdbeAddOp2(v, OP_Null, 0, regBase+nEq);
    +       nConstraint++;
    +@@ -119525,16 +130810,22 @@ SQLITE_PRIVATE Bitmask sqlite3WhereCodeOneLoopStart(
    +       start_constraints = 1;
    +     }
    +     codeApplyAffinity(pParse, regBase, nConstraint - bSeekPastNull, zStartAff);
    +-    op = aStartOp[(start_constraints<<2) + (startEq<<1) + bRev];
    +-    assert( op!=0 );
    +-    sqlite3VdbeAddOp4Int(v, op, iIdxCur, addrNxt, regBase, nConstraint);
    +-    VdbeCoverage(v);
    +-    VdbeCoverageIf(v, op==OP_Rewind);  testcase( op==OP_Rewind );
    +-    VdbeCoverageIf(v, op==OP_Last);    testcase( op==OP_Last );
    +-    VdbeCoverageIf(v, op==OP_SeekGT);  testcase( op==OP_SeekGT );
    +-    VdbeCoverageIf(v, op==OP_SeekGE);  testcase( op==OP_SeekGE );
    +-    VdbeCoverageIf(v, op==OP_SeekLE);  testcase( op==OP_SeekLE );
    +-    VdbeCoverageIf(v, op==OP_SeekLT);  testcase( op==OP_SeekLT );
    ++    if( pLoop->nSkip>0 && nConstraint==pLoop->nSkip ){
    ++      /* The skip-scan logic inside the call to codeAllEqualityConstraints()
    ++      ** above has already left the cursor sitting on the correct row,
    ++      ** so no further seeking is needed */
    ++    }else{
    ++      op = aStartOp[(start_constraints<<2) + (startEq<<1) + bRev];
    ++      assert( op!=0 );
    ++      sqlite3VdbeAddOp4Int(v, op, iIdxCur, addrNxt, regBase, nConstraint);
    ++      VdbeCoverage(v);
    ++      VdbeCoverageIf(v, op==OP_Rewind);  testcase( op==OP_Rewind );
    ++      VdbeCoverageIf(v, op==OP_Last);    testcase( op==OP_Last );
    ++      VdbeCoverageIf(v, op==OP_SeekGT);  testcase( op==OP_SeekGT );
    ++      VdbeCoverageIf(v, op==OP_SeekGE);  testcase( op==OP_SeekGE );
    ++      VdbeCoverageIf(v, op==OP_SeekLE);  testcase( op==OP_SeekLE );
    ++      VdbeCoverageIf(v, op==OP_SeekLT);  testcase( op==OP_SeekLT );
    ++    }
    + 
    +     /* Load the value for the inequality constraint at the end of the
    +     ** range (if any).
    +@@ -119543,7 +130834,7 @@ SQLITE_PRIVATE Bitmask sqlite3WhereCodeOneLoopStart(
    +     if( pRangeEnd ){
    +       Expr *pRight = pRangeEnd->pExpr->pRight;
    +       sqlite3ExprCacheRemove(pParse, regBase+nEq, 1);
    +-      sqlite3ExprCode(pParse, pRight, regBase+nEq);
    ++      codeExprOrVector(pParse, pRight, regBase+nEq, nTop);
    +       whereLikeOptimizationStringFixup(v, pLevel, pRangeEnd);
    +       if( (pRangeEnd->wtFlags & TERM_VNULL)==0
    +        && sqlite3ExprCanBeNull(pRight)
    +@@ -119551,19 +130842,28 @@ SQLITE_PRIVATE Bitmask sqlite3WhereCodeOneLoopStart(
    +         sqlite3VdbeAddOp2(v, OP_IsNull, regBase+nEq, addrNxt);
    +         VdbeCoverage(v);
    +       }
    +-      if( sqlite3CompareAffinity(pRight, cEndAff)!=SQLITE_AFF_BLOB
    +-       && !sqlite3ExprNeedsNoAffinityChange(pRight, cEndAff)
    +-      ){
    +-        codeApplyAffinity(pParse, regBase+nEq, 1, &cEndAff);
    ++      if( zEndAff ){
    ++        updateRangeAffinityStr(pRight, nTop, zEndAff);
    ++        codeApplyAffinity(pParse, regBase+nEq, nTop, zEndAff);
    ++      }else{
    ++        assert( pParse->db->mallocFailed );
    +       }
    +-      nConstraint++;
    ++      nConstraint += nTop;
    +       testcase( pRangeEnd->wtFlags & TERM_VIRTUAL );
    ++
    ++      if( sqlite3ExprIsVector(pRight)==0 ){
    ++        disableTerm(pLevel, pRangeEnd);
    ++      }else{
    ++        endEq = 1;
    ++      }
    +     }else if( bStopAtNull ){
    +       sqlite3VdbeAddOp2(v, OP_Null, 0, regBase+nEq);
    ++      sqlite3ExprCacheRemove(pParse, regBase+nEq, 1);
    +       endEq = 0;
    +       nConstraint++;
    +     }
    +     sqlite3DbFree(db, zStartAff);
    ++    sqlite3DbFree(db, zEndAff);
    + 
    +     /* Top of the loop body */
    +     pLevel->p2 = sqlite3VdbeCurrentAddr(v);
    +@@ -119579,19 +130879,20 @@ SQLITE_PRIVATE Bitmask sqlite3WhereCodeOneLoopStart(
    +     }
    + 
    +     /* Seek the table cursor, if required */
    +-    disableTerm(pLevel, pRangeStart);
    +-    disableTerm(pLevel, pRangeEnd);
    +     if( omitTable ){
    +       /* pIdx is a covering index.  No need to access the main table. */
    +     }else if( HasRowid(pIdx->pTable) ){
    +-      iRowidReg = ++pParse->nMem;
    +-      sqlite3VdbeAddOp2(v, OP_IdxRowid, iIdxCur, iRowidReg);
    +-      sqlite3ExprCacheStore(pParse, iCur, -1, iRowidReg);
    +-      if( pWInfo->eOnePass!=ONEPASS_OFF ){
    ++      if( (pWInfo->wctrlFlags & WHERE_SEEK_TABLE) || (
    ++          (pWInfo->wctrlFlags & WHERE_SEEK_UNIQ_TABLE) 
    ++       && (pWInfo->eOnePass==ONEPASS_SINGLE)
    ++      )){
    ++        iRowidReg = ++pParse->nMem;
    ++        sqlite3VdbeAddOp2(v, OP_IdxRowid, iIdxCur, iRowidReg);
    ++        sqlite3ExprCacheStore(pParse, iCur, -1, iRowidReg);
    +         sqlite3VdbeAddOp3(v, OP_NotExists, iCur, 0, iRowidReg);
    +         VdbeCoverage(v);
    +       }else{
    +-        sqlite3VdbeAddOp2(v, OP_Seek, iCur, iRowidReg);  /* Deferred seek */
    ++        codeDeferredSeek(pWInfo, pIdx, iCur, iIdxCur);
    +       }
    +     }else if( iCur!=iIdxCur ){
    +       Index *pPk = sqlite3PrimaryKeyIndex(pIdx->pTable);
    +@@ -119604,9 +130905,14 @@ SQLITE_PRIVATE Bitmask sqlite3WhereCodeOneLoopStart(
    +                            iRowidReg, pPk->nKeyCol); VdbeCoverage(v);
    +     }
    + 
    +-    /* Record the instruction used to terminate the loop. Disable 
    +-    ** WHERE clause terms made redundant by the index range scan.
    ++    /* If pIdx is an index on one or more expressions, then look through
    ++    ** all the expressions in pWInfo and try to transform matching expressions
    ++    ** into reference to index columns.
    +     */
    ++    whereIndexExprTrans(pIdx, iCur, iIdxCur, pWInfo);
    ++
    ++
    ++    /* Record the instruction used to terminate the loop. */
    +     if( pLoop->wsFlags & WHERE_ONEROW ){
    +       pLevel->op = OP_Noop;
    +     }else if( bRev ){
    +@@ -119621,6 +130927,7 @@ SQLITE_PRIVATE Bitmask sqlite3WhereCodeOneLoopStart(
    +     }else{
    +       assert( pLevel->p5==0 );
    +     }
    ++    if( omitTable ) pIdx = 0;
    +   }else
    + 
    + #ifndef SQLITE_OMIT_OR_OPTIMIZATION
    +@@ -119683,7 +130990,7 @@ SQLITE_PRIVATE Bitmask sqlite3WhereCodeOneLoopStart(
    +     u16 wctrlFlags;                    /* Flags for sub-WHERE clause */
    +     Expr *pAndExpr = 0;                /* An ".. AND (...)" expression */
    +     Table *pTab = pTabItem->pTab;
    +-   
    ++
    +     pTerm = pLoop->aLTerm[0];
    +     assert( pTerm!=0 );
    +     assert( pTerm->eOperator & WO_OR );
    +@@ -119760,14 +131067,16 @@ SQLITE_PRIVATE Bitmask sqlite3WhereCodeOneLoopStart(
    +         Expr *pExpr = pWC->a[iTerm].pExpr;
    +         if( &pWC->a[iTerm] == pTerm ) continue;
    +         if( ExprHasProperty(pExpr, EP_FromJoin) ) continue;
    +-        if( (pWC->a[iTerm].wtFlags & TERM_VIRTUAL)!=0 ) continue;
    ++        testcase( pWC->a[iTerm].wtFlags & TERM_VIRTUAL );
    ++        testcase( pWC->a[iTerm].wtFlags & TERM_CODED );
    ++        if( (pWC->a[iTerm].wtFlags & (TERM_VIRTUAL|TERM_CODED))!=0 ) continue;
    +         if( (pWC->a[iTerm].eOperator & WO_ALL)==0 ) continue;
    +         testcase( pWC->a[iTerm].wtFlags & TERM_ORINFO );
    +         pExpr = sqlite3ExprDup(db, pExpr, 0);
    +         pAndExpr = sqlite3ExprAnd(db, pAndExpr, pExpr);
    +       }
    +       if( pAndExpr ){
    +-        pAndExpr = sqlite3PExpr(pParse, TK_AND, 0, pAndExpr, 0);
    ++        pAndExpr = sqlite3PExpr(pParse, TK_AND|TKFLG_DONTFOLD, 0, pAndExpr);
    +       }
    +     }
    + 
    +@@ -119775,10 +131084,7 @@ SQLITE_PRIVATE Bitmask sqlite3WhereCodeOneLoopStart(
    +     ** 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_FORCE_TABLE
    +-                | WHERE_ONETABLE_ONLY
    +-                | WHERE_NO_AUTOINDEX;
    ++    wctrlFlags =  WHERE_OR_SUBCLAUSE | (pWInfo->wctrlFlags & WHERE_SEEK_TABLE);
    +     for(ii=0; ii<pOrWc->nTerm; ii++){
    +       WhereTerm *pOrTerm = &pOrWc->a[ii];
    +       if( pOrTerm->leftCursor==iCur || (pOrTerm->eOperator & WO_AND)!=0 ){
    +@@ -119823,11 +131129,7 @@ SQLITE_PRIVATE Bitmask sqlite3WhereCodeOneLoopStart(
    +               r = sqlite3GetTempRange(pParse, nPk);
    +               for(iPk=0; iPk<nPk; iPk++){
    +                 int iCol = pPk->aiColumn[iPk];
    +-                int rx;
    +-                rx = sqlite3ExprCodeGetColumn(pParse, pTab, iCol, iCur,r+iPk,0);
    +-                if( rx!=r+iPk ){
    +-                  sqlite3VdbeAddOp2(v, OP_SCopy, rx, r+iPk);
    +-                }
    ++                sqlite3ExprCodeGetColumnToReg(pParse, pTab, iCol, iCur, r+iPk);
    +               }
    + 
    +               /* Check if the temp table already contains this key. If so,
    +@@ -119847,7 +131149,8 @@ SQLITE_PRIVATE Bitmask sqlite3WhereCodeOneLoopStart(
    +               }
    +               if( iSet>=0 ){
    +                 sqlite3VdbeAddOp3(v, OP_MakeRecord, r, nPk, regRowid);
    +-                sqlite3VdbeAddOp3(v, OP_IdxInsert, regRowset, regRowid, 0);
    ++                sqlite3VdbeAddOp4Int(v, OP_IdxInsert, regRowset, regRowid,
    ++                                     r, nPk);
    +                 if( iSet ) sqlite3VdbeChangeP5(v, OPFLAG_USESEEKRESULT);
    +               }
    + 
    +@@ -119890,7 +131193,6 @@ SQLITE_PRIVATE Bitmask sqlite3WhereCodeOneLoopStart(
    +           ){
    +             assert( pSubWInfo->a[0].iIdxCur==iCovCur );
    +             pCov = pSubLoop->u.btree.pIndex;
    +-            wctrlFlags |= WHERE_REOPEN_IDX;
    +           }else{
    +             pCov = 0;
    +           }
    +@@ -119927,9 +131229,10 @@ SQLITE_PRIVATE Bitmask sqlite3WhereCodeOneLoopStart(
    +       ** a pseudo-cursor.  No need to Rewind or Next such cursors. */
    +       pLevel->op = OP_Noop;
    +     }else{
    ++      codeCursorHint(pTabItem, pWInfo, pLevel, 0);
    +       pLevel->op = aStep[bRev];
    +       pLevel->p1 = iCur;
    +-      pLevel->p2 = 1 + sqlite3VdbeAddOp2(v, aStart[bRev], iCur, addrBrk);
    ++      pLevel->p2 = 1 + sqlite3VdbeAddOp2(v, aStart[bRev], iCur, addrHalt);
    +       VdbeCoverageIf(v, bRev==0);
    +       VdbeCoverageIf(v, bRev!=0);
    +       pLevel->p5 = SQLITE_STMTSTATUS_FULLSCAN_STEP;
    +@@ -119942,33 +131245,75 @@ SQLITE_PRIVATE Bitmask sqlite3WhereCodeOneLoopStart(
    + 
    +   /* Insert code to test every subexpression that can be completely
    +   ** computed using the current set of tables.
    ++  **
    ++  ** This loop may run between one and three times, depending on the
    ++  ** constraints to be generated. The value of stack variable iLoop
    ++  ** determines the constraints coded by each iteration, as follows:
    ++  **
    ++  ** iLoop==1: Code only expressions that are entirely covered by pIdx.
    ++  ** iLoop==2: Code remaining expressions that do not contain correlated
    ++  **           sub-queries.  
    ++  ** iLoop==3: Code all remaining expressions.
    ++  **
    ++  ** An effort is made to skip unnecessary iterations of the loop.
    +   */
    +-  for(pTerm=pWC->a, j=pWC->nTerm; j>0; j--, pTerm++){
    +-    Expr *pE;
    +-    int skipLikeAddr = 0;
    +-    testcase( pTerm->wtFlags & TERM_VIRTUAL );
    +-    testcase( pTerm->wtFlags & TERM_CODED );
    +-    if( pTerm->wtFlags & (TERM_VIRTUAL|TERM_CODED) ) continue;
    +-    if( (pTerm->prereqAll & pLevel->notReady)!=0 ){
    +-      testcase( pWInfo->untestedTerms==0
    +-               && (pWInfo->wctrlFlags & WHERE_ONETABLE_ONLY)!=0 );
    +-      pWInfo->untestedTerms = 1;
    +-      continue;
    +-    }
    +-    pE = pTerm->pExpr;
    +-    assert( pE!=0 );
    +-    if( pLevel->iLeftJoin && !ExprHasProperty(pE, EP_FromJoin) ){
    +-      continue;
    +-    }
    +-    if( pTerm->wtFlags & TERM_LIKECOND ){
    +-      assert( pLevel->iLikeRepCntr>0 );
    +-      skipLikeAddr = sqlite3VdbeAddOp1(v, OP_IfNot, pLevel->iLikeRepCntr);
    +-      VdbeCoverage(v);
    ++  iLoop = (pIdx ? 1 : 2);
    ++  do{
    ++    int iNext = 0;                /* Next value for iLoop */
    ++    for(pTerm=pWC->a, j=pWC->nTerm; j>0; j--, pTerm++){
    ++      Expr *pE;
    ++      int skipLikeAddr = 0;
    ++      testcase( pTerm->wtFlags & TERM_VIRTUAL );
    ++      testcase( pTerm->wtFlags & TERM_CODED );
    ++      if( pTerm->wtFlags & (TERM_VIRTUAL|TERM_CODED) ) continue;
    ++      if( (pTerm->prereqAll & pLevel->notReady)!=0 ){
    ++        testcase( pWInfo->untestedTerms==0
    ++            && (pWInfo->wctrlFlags & WHERE_OR_SUBCLAUSE)!=0 );
    ++        pWInfo->untestedTerms = 1;
    ++        continue;
    ++      }
    ++      pE = pTerm->pExpr;
    ++      assert( pE!=0 );
    ++      if( pLevel->iLeftJoin && !ExprHasProperty(pE, EP_FromJoin) ){
    ++        continue;
    ++      }
    ++      
    ++      if( iLoop==1 && !sqlite3ExprCoveredByIndex(pE, pLevel->iTabCur, pIdx) ){
    ++        iNext = 2;
    ++        continue;
    ++      }
    ++      if( iLoop<3 && (pTerm->wtFlags & TERM_VARSELECT) ){
    ++        if( iNext==0 ) iNext = 3;
    ++        continue;
    ++      }
    ++
    ++      if( pTerm->wtFlags & TERM_LIKECOND ){
    ++        /* If the TERM_LIKECOND flag is set, that means that the range search
    ++        ** is sufficient to guarantee that the LIKE operator is true, so we
    ++        ** can skip the call to the like(A,B) function.  But this only works
    ++        ** for strings.  So do not skip the call to the function on the pass
    ++        ** that compares BLOBs. */
    ++#ifdef SQLITE_LIKE_DOESNT_MATCH_BLOBS
    ++        continue;
    ++#else
    ++        u32 x = pLevel->iLikeRepCntr;
    ++        assert( x>0 );
    ++        skipLikeAddr = sqlite3VdbeAddOp1(v, (x&1)?OP_IfNot:OP_If, (int)(x>>1));
    ++        VdbeCoverage(v);
    ++#endif
    ++      }
    ++#ifdef WHERETRACE_ENABLED /* 0xffff */
    ++      if( sqlite3WhereTrace ){
    ++        VdbeNoopComment((v, "WhereTerm[%d] (%p) priority=%d",
    ++                         pWC->nTerm-j, pTerm, iLoop));
    ++      }
    ++#endif
    ++      sqlite3ExprIfFalse(pParse, pE, addrCont, SQLITE_JUMPIFNULL);
    ++      if( skipLikeAddr ) sqlite3VdbeJumpHere(v, skipLikeAddr);
    ++      pTerm->wtFlags |= TERM_CODED;
    +     }
    +-    sqlite3ExprIfFalse(pParse, pE, addrCont, SQLITE_JUMPIFNULL);
    +-    if( skipLikeAddr ) sqlite3VdbeJumpHere(v, skipLikeAddr);
    +-    pTerm->wtFlags |= TERM_CODED;
    +-  }
    ++    iLoop = iNext;
    ++  }while( iLoop>0 );
    + 
    +   /* Insert code to test for implied constraints based on transitivity
    +   ** of the "==" operator.
    +@@ -119979,7 +131324,7 @@ SQLITE_PRIVATE Bitmask sqlite3WhereCodeOneLoopStart(
    +   ** the implied "t1.a=123" constraint.
    +   */
    +   for(pTerm=pWC->a, j=pWC->nTerm; j>0; j--, pTerm++){
    +-    Expr *pE, *pEAlt;
    ++    Expr *pE, sEAlt;
    +     WhereTerm *pAlt;
    +     if( pTerm->wtFlags & (TERM_VIRTUAL|TERM_CODED) ) continue;
    +     if( (pTerm->eOperator & (WO_EQ|WO_IS))==0 ) continue;
    +@@ -119997,13 +131342,9 @@ SQLITE_PRIVATE Bitmask sqlite3WhereCodeOneLoopStart(
    +     testcase( pAlt->eOperator & WO_IS );
    +     testcase( pAlt->eOperator & WO_IN );
    +     VdbeModuleComment((v, "begin transitive constraint"));
    +-    pEAlt = sqlite3StackAllocRaw(db, sizeof(*pEAlt));
    +-    if( pEAlt ){
    +-      *pEAlt = *pAlt->pExpr;
    +-      pEAlt->pLeft = pE->pLeft;
    +-      sqlite3ExprIfFalse(pParse, pEAlt, addrCont, SQLITE_JUMPIFNULL);
    +-      sqlite3StackFree(db, pEAlt);
    +-    }
    ++    sEAlt = *pAlt->pExpr;
    ++    sEAlt.pLeft = pE->pLeft;
    ++    sqlite3ExprIfFalse(pParse, &sEAlt, addrCont, SQLITE_JUMPIFNULL);
    +   }
    + 
    +   /* For a LEFT OUTER JOIN, generate code that will record the fact that
    +@@ -120099,7 +131440,7 @@ static int whereClauseInsert(WhereClause *pWC, Expr *p, u16 wtFlags){
    +   if( pWC->nTerm>=pWC->nSlot ){
    +     WhereTerm *pOld = pWC->a;
    +     sqlite3 *db = pWC->pWInfo->pParse->db;
    +-    pWC->a = sqlite3DbMallocRaw(db, sizeof(pWC->a[0])*pWC->nSlot*2 );
    ++    pWC->a = sqlite3DbMallocRawNN(db, sizeof(pWC->a[0])*pWC->nSlot*2 );
    +     if( pWC->a==0 ){
    +       if( wtFlags & TERM_DYNAMIC ){
    +         sqlite3ExprDelete(db, p);
    +@@ -120112,7 +131453,6 @@ static int whereClauseInsert(WhereClause *pWC, Expr *p, u16 wtFlags){
    +       sqlite3DbFree(db, pOld);
    +     }
    +     pWC->nSlot = sqlite3DbMallocSize(db, pWC->a)/sizeof(pWC->a[0]);
    +-    memset(&pWC->a[pWC->nTerm], 0, sizeof(pWC->a[0])*(pWC->nSlot-pWC->nTerm));
    +   }
    +   pTerm = &pWC->a[idx = pWC->nTerm++];
    +   if( p && ExprHasProperty(p, EP_Unlikely) ){
    +@@ -120124,13 +131464,15 @@ static int whereClauseInsert(WhereClause *pWC, Expr *p, u16 wtFlags){
    +   pTerm->wtFlags = wtFlags;
    +   pTerm->pWC = pWC;
    +   pTerm->iParent = -1;
    ++  memset(&pTerm->eOperator, 0,
    ++         sizeof(WhereTerm) - offsetof(WhereTerm,eOperator));
    +   return idx;
    + }
    + 
    + /*
    + ** Return TRUE if the given operator is one of the operators that is
    + ** allowed for an indexable WHERE clause term.  The allowed operators are
    +-** "=", "<", ">", "<=", ">=", "IN", and "IS NULL"
    ++** "=", "<", ">", "<=", ">=", "IN", "IS", and "IS NULL"
    + */
    + static int allowedOp(int op){
    +   assert( TK_GT>TK_EQ && TK_GT<TK_GE );
    +@@ -120228,15 +131570,16 @@ static int isLikeOrGlob(
    +   int *pisComplete, /* True if the only wildcard is % in the last character */
    +   int *pnoCase      /* True if uppercase is equivalent to lowercase */
    + ){
    +-  const char *z = 0;         /* String on RHS of LIKE operator */
    ++  const u8 *z = 0;         /* String on RHS of LIKE operator */
    +   Expr *pRight, *pLeft;      /* Right and left size of LIKE operator */
    +   ExprList *pList;           /* List of operands to the LIKE operator */
    +   int c;                     /* One character in z[] */
    +   int cnt;                   /* Number of non-wildcard prefix characters */
    +-  char wc[3];                /* Wildcard characters */
    ++  char wc[4];                /* Wildcard characters */
    +   sqlite3 *db = pParse->db;  /* Database connection */
    +   sqlite3_value *pVal = 0;
    +   int op;                    /* Opcode of pRight */
    ++  int rc;                    /* Result code to return */
    + 
    +   if( !sqlite3IsLikeFunction(db, pExpr, pnoCase, wc) ){
    +     return 0;
    +@@ -120246,41 +131589,75 @@ static int isLikeOrGlob(
    + #endif
    +   pList = pExpr->x.pList;
    +   pLeft = pList->a[1].pExpr;
    +-  if( pLeft->op!=TK_COLUMN 
    +-   || sqlite3ExprAffinity(pLeft)!=SQLITE_AFF_TEXT 
    +-   || IsVirtual(pLeft->pTab)  /* Value might be numeric */
    +-  ){
    +-    /* IMP: R-02065-49465 The left-hand side of the LIKE or GLOB operator must
    +-    ** be the name of an indexed column with TEXT affinity. */
    +-    return 0;
    +-  }
    +-  assert( pLeft->iColumn!=(-1) ); /* Because IPK never has AFF_TEXT */
    + 
    +   pRight = sqlite3ExprSkipCollate(pList->a[0].pExpr);
    +   op = pRight->op;
    +-  if( op==TK_VARIABLE ){
    ++  if( op==TK_VARIABLE && (db->flags & SQLITE_EnableQPSG)==0 ){
    +     Vdbe *pReprepare = pParse->pReprepare;
    +     int iCol = pRight->iColumn;
    +     pVal = sqlite3VdbeGetBoundValue(pReprepare, iCol, SQLITE_AFF_BLOB);
    +     if( pVal && sqlite3_value_type(pVal)==SQLITE_TEXT ){
    +-      z = (char *)sqlite3_value_text(pVal);
    ++      z = sqlite3_value_text(pVal);
    +     }
    +     sqlite3VdbeSetVarmask(pParse->pVdbe, iCol);
    +     assert( pRight->op==TK_VARIABLE || pRight->op==TK_REGISTER );
    +   }else if( op==TK_STRING ){
    +-    z = pRight->u.zToken;
    ++    z = (u8*)pRight->u.zToken;
    +   }
    +   if( z ){
    ++
    ++    /* If the RHS begins with a digit or a minus sign, then the LHS must
    ++    ** be an ordinary column (not a virtual table column) with TEXT affinity.
    ++    ** Otherwise the LHS might be numeric and "lhs >= rhs" would be false
    ++    ** even though "lhs LIKE rhs" is true.  But if the RHS does not start
    ++    ** with a digit or '-', then "lhs LIKE rhs" will always be false if
    ++    ** the LHS is numeric and so the optimization still works.
    ++    */
    ++    if( sqlite3Isdigit(z[0]) || z[0]=='-' ){
    ++      if( pLeft->op!=TK_COLUMN 
    ++       || sqlite3ExprAffinity(pLeft)!=SQLITE_AFF_TEXT 
    ++       || IsVirtual(pLeft->pTab)  /* Value might be numeric */
    ++      ){
    ++        sqlite3ValueFree(pVal);
    ++        return 0;
    ++      }
    ++    }
    ++
    ++    /* Count the number of prefix characters prior to the first wildcard */
    +     cnt = 0;
    +     while( (c=z[cnt])!=0 && c!=wc[0] && c!=wc[1] && c!=wc[2] ){
    +       cnt++;
    ++      if( c==wc[3] && z[cnt]!=0 ) cnt++;
    +     }
    ++
    ++    /* The optimization is possible only if (1) the pattern does not begin
    ++    ** with a wildcard and if (2) the non-wildcard prefix does not end with
    ++    ** an (illegal 0xff) character.  The second condition is necessary so
    ++    ** that we can increment the prefix key to find an upper bound for the
    ++    ** range search. 
    ++    */
    +     if( cnt!=0 && 255!=(u8)z[cnt-1] ){
    +       Expr *pPrefix;
    ++
    ++      /* A "complete" match if the pattern ends with "*" or "%" */
    +       *pisComplete = c==wc[0] && z[cnt+1]==0;
    +-      pPrefix = sqlite3Expr(db, TK_STRING, z);
    +-      if( pPrefix ) pPrefix->u.zToken[cnt] = 0;
    ++
    ++      /* Get the pattern prefix.  Remove all escapes from the prefix. */
    ++      pPrefix = sqlite3Expr(db, TK_STRING, (char*)z);
    ++      if( pPrefix ){
    ++        int iFrom, iTo;
    ++        char *zNew = pPrefix->u.zToken;
    ++        zNew[cnt] = 0;
    ++        for(iFrom=iTo=0; iFrom<cnt; iFrom++){
    ++          if( zNew[iFrom]==wc[3] ) iFrom++;
    ++          zNew[iTo++] = zNew[iFrom];
    ++        }
    ++        zNew[iTo] = 0;
    ++      }
    +       *ppPrefix = pPrefix;
    ++
    ++      /* If the RHS pattern is a bound parameter, make arrangements to
    ++      ** reprepare the statement when that parameter is rebound */
    +       if( op==TK_VARIABLE ){
    +         Vdbe *v = pParse->pVdbe;
    +         sqlite3VdbeSetVarmask(v, pRight->iColumn);
    +@@ -120302,39 +131679,95 @@ static int isLikeOrGlob(
    +     }
    +   }
    + 
    ++  rc = (z!=0);
    +   sqlite3ValueFree(pVal);
    +-  return (z!=0);
    ++  return rc;
    + }
    + #endif /* SQLITE_OMIT_LIKE_OPTIMIZATION */
    + 
    + 
    + #ifndef SQLITE_OMIT_VIRTUALTABLE
    + /*
    +-** Check to see if the given expression is of the form
    +-**
    +-**         column MATCH expr
    +-**
    +-** If it is then return TRUE.  If not, return FALSE.
    +-*/
    +-static int isMatchOfColumn(
    +-  Expr *pExpr      /* Test this expression */
    +-){
    +-  ExprList *pList;
    ++** Check to see if the pExpr expression is a form that needs to be passed
    ++** to the xBestIndex method of virtual tables.  Forms of interest include:
    ++**
    ++**          Expression                   Virtual Table Operator
    ++**          -----------------------      ---------------------------------
    ++**      1.  column MATCH expr            SQLITE_INDEX_CONSTRAINT_MATCH
    ++**      2.  column GLOB expr             SQLITE_INDEX_CONSTRAINT_GLOB
    ++**      3.  column LIKE expr             SQLITE_INDEX_CONSTRAINT_LIKE
    ++**      4.  column REGEXP expr           SQLITE_INDEX_CONSTRAINT_REGEXP
    ++**      5.  column != expr               SQLITE_INDEX_CONSTRAINT_NE
    ++**      6.  expr != column               SQLITE_INDEX_CONSTRAINT_NE
    ++**      7.  column IS NOT expr           SQLITE_INDEX_CONSTRAINT_ISNOT
    ++**      8.  expr IS NOT column           SQLITE_INDEX_CONSTRAINT_ISNOT
    ++**      9.  column IS NOT NULL           SQLITE_INDEX_CONSTRAINT_ISNOTNULL
    ++**
    ++** In every case, "column" must be a column of a virtual table.  If there
    ++** is a match, set *ppLeft to the "column" expression, set *ppRight to the 
    ++** "expr" expression (even though in forms (6) and (8) the column is on the
    ++** right and the expression is on the left).  Also set *peOp2 to the
    ++** appropriate virtual table operator.  The return value is 1 or 2 if there
    ++** is a match.  The usual return is 1, but if the RHS is also a column
    ++** of virtual table in forms (5) or (7) then return 2.
    ++**
    ++** If the expression matches none of the patterns above, return 0.
    ++*/
    ++static int isAuxiliaryVtabOperator(
    ++  Expr *pExpr,                    /* Test this expression */
    ++  unsigned char *peOp2,           /* OUT: 0 for MATCH, or else an op2 value */
    ++  Expr **ppLeft,                  /* Column expression to left of MATCH/op2 */
    ++  Expr **ppRight                  /* Expression to left of MATCH/op2 */
    ++){
    ++  if( pExpr->op==TK_FUNCTION ){
    ++    static const struct Op2 {
    ++      const char *zOp;
    ++      unsigned char eOp2;
    ++    } aOp[] = {
    ++      { "match",  SQLITE_INDEX_CONSTRAINT_MATCH },
    ++      { "glob",   SQLITE_INDEX_CONSTRAINT_GLOB },
    ++      { "like",   SQLITE_INDEX_CONSTRAINT_LIKE },
    ++      { "regexp", SQLITE_INDEX_CONSTRAINT_REGEXP }
    ++    };
    ++    ExprList *pList;
    ++    Expr *pCol;                     /* Column reference */
    ++    int i;
    + 
    +-  if( pExpr->op!=TK_FUNCTION ){
    +-    return 0;
    +-  }
    +-  if( sqlite3StrICmp(pExpr->u.zToken,"match")!=0 ){
    +-    return 0;
    +-  }
    +-  pList = pExpr->x.pList;
    +-  if( pList->nExpr!=2 ){
    +-    return 0;
    +-  }
    +-  if( pList->a[1].pExpr->op != TK_COLUMN ){
    +-    return 0;
    ++    pList = pExpr->x.pList;
    ++    if( pList==0 || pList->nExpr!=2 ){
    ++      return 0;
    ++    }
    ++    pCol = pList->a[1].pExpr;
    ++    if( pCol->op!=TK_COLUMN || !IsVirtual(pCol->pTab) ){
    ++      return 0;
    ++    }
    ++    for(i=0; i<ArraySize(aOp); i++){
    ++      if( sqlite3StrICmp(pExpr->u.zToken, aOp[i].zOp)==0 ){
    ++        *peOp2 = aOp[i].eOp2;
    ++        *ppRight = pList->a[0].pExpr;
    ++        *ppLeft = pCol;
    ++        return 1;
    ++      }
    ++    }
    ++  }else if( pExpr->op==TK_NE || pExpr->op==TK_ISNOT || pExpr->op==TK_NOTNULL ){
    ++    int res = 0;
    ++    Expr *pLeft = pExpr->pLeft;
    ++    Expr *pRight = pExpr->pRight;
    ++    if( pLeft->op==TK_COLUMN && IsVirtual(pLeft->pTab) ){
    ++      res++;
    ++    }
    ++    if( pRight && pRight->op==TK_COLUMN && IsVirtual(pRight->pTab) ){
    ++      res++;
    ++      SWAP(Expr*, pLeft, pRight);
    ++    }
    ++    *ppLeft = pLeft;
    ++    *ppRight = pRight;
    ++    if( pExpr->op==TK_NE ) *peOp2 = SQLITE_INDEX_CONSTRAINT_NE;
    ++    if( pExpr->op==TK_ISNOT ) *peOp2 = SQLITE_INDEX_CONSTRAINT_ISNOT;
    ++    if( pExpr->op==TK_NOTNULL ) *peOp2 = SQLITE_INDEX_CONSTRAINT_ISNOTNULL;
    ++    return res;
    +   }
    +-  return 1;
    ++  return 0;
    + }
    + #endif /* SQLITE_OMIT_VIRTUALTABLE */
    + 
    +@@ -120411,8 +131844,8 @@ static void whereCombineDisjuncts(
    +    && (eOp & (WO_EQ|WO_GT|WO_GE))!=eOp ) return;
    +   assert( pOne->pExpr->pLeft!=0 && pOne->pExpr->pRight!=0 );
    +   assert( pTwo->pExpr->pLeft!=0 && pTwo->pExpr->pRight!=0 );
    +-  if( sqlite3ExprCompare(pOne->pExpr->pLeft, pTwo->pExpr->pLeft, -1) ) return;
    +-  if( sqlite3ExprCompare(pOne->pExpr->pRight, pTwo->pExpr->pRight, -1) )return;
    ++  if( sqlite3ExprCompare(0,pOne->pExpr->pLeft, pTwo->pExpr->pLeft, -1) ) return;
    ++  if( sqlite3ExprCompare(0,pOne->pExpr->pRight, pTwo->pExpr->pRight,-1) )return;
    +   /* If we reach this point, it means the two subterms can be combined */
    +   if( (eOp & (eOp-1))!=0 ){
    +     if( eOp & (WO_LT|WO_LE) ){
    +@@ -120547,6 +131980,7 @@ static void exprAnalyzeOrTerm(
    +   if( pOrInfo==0 ) return;
    +   pTerm->wtFlags |= TERM_ORINFO;
    +   pOrWc = &pOrInfo->wc;
    ++  memset(pOrWc->aStatic, 0, sizeof(pOrWc->aStatic));
    +   sqlite3WhereClauseInit(pOrWc, pWInfo);
    +   sqlite3WhereSplit(pOrWc, pExpr, TK_OR);
    +   sqlite3WhereExprAnalyze(pSrc, pOrWc);
    +@@ -120563,7 +131997,7 @@ static void exprAnalyzeOrTerm(
    +       WhereAndInfo *pAndInfo;
    +       assert( (pOrTerm->wtFlags & (TERM_ANDINFO|TERM_ORINFO))==0 );
    +       chngToIN = 0;
    +-      pAndInfo = sqlite3DbMallocRaw(db, sizeof(*pAndInfo));
    ++      pAndInfo = sqlite3DbMallocRawNN(db, sizeof(*pAndInfo));
    +       if( pAndInfo ){
    +         WhereClause *pAndWC;
    +         WhereTerm *pAndTerm;
    +@@ -120573,15 +132007,17 @@ static void exprAnalyzeOrTerm(
    +         pOrTerm->wtFlags |= TERM_ANDINFO;
    +         pOrTerm->eOperator = WO_AND;
    +         pAndWC = &pAndInfo->wc;
    ++        memset(pAndWC->aStatic, 0, sizeof(pAndWC->aStatic));
    +         sqlite3WhereClauseInit(pAndWC, pWC->pWInfo);
    +         sqlite3WhereSplit(pAndWC, pOrTerm->pExpr, TK_AND);
    +         sqlite3WhereExprAnalyze(pSrc, pAndWC);
    +         pAndWC->pOuter = pWC;
    +-        testcase( db->mallocFailed );
    +         if( !db->mallocFailed ){
    +           for(j=0, pAndTerm=pAndWC->a; j<pAndWC->nTerm; j++, pAndTerm++){
    +             assert( pAndTerm->pExpr );
    +-            if( allowedOp(pAndTerm->pExpr->op) ){
    ++            if( allowedOp(pAndTerm->pExpr->op) 
    ++             || pAndTerm->eOperator==WO_AUX
    ++            ){
    +               b |= sqlite3WhereGetMask(&pWInfo->sMaskSet, pAndTerm->leftCursor);
    +             }
    +           }
    +@@ -120744,7 +132180,7 @@ static void exprAnalyzeOrTerm(
    +       }
    +       assert( pLeft!=0 );
    +       pDup = sqlite3ExprDup(db, pLeft, 0);
    +-      pNew = sqlite3PExpr(pParse, TK_IN, pDup, 0, 0);
    ++      pNew = sqlite3PExpr(pParse, TK_IN, pDup, 0);
    +       if( pNew ){
    +         int idxNew;
    +         transferJoinMarkings(pNew, pExpr);
    +@@ -120782,7 +132218,6 @@ static void exprAnalyzeOrTerm(
    + static int termIsEquivalence(Parse *pParse, Expr *pExpr){
    +   char aff1, aff2;
    +   CollSeq *pColl;
    +-  const char *zColl1, *zColl2;
    +   if( !OptimizationEnabled(pParse->db, SQLITE_Transitive) ) return 0;
    +   if( pExpr->op!=TK_EQ && pExpr->op!=TK_IS ) return 0;
    +   if( ExprHasProperty(pExpr, EP_FromJoin) ) return 0;
    +@@ -120795,13 +132230,7 @@ static int termIsEquivalence(Parse *pParse, Expr *pExpr){
    +   }
    +   pColl = sqlite3BinaryCompareCollSeq(pParse, pExpr->pLeft, pExpr->pRight);
    +   if( pColl==0 || sqlite3StrICmp(pColl->zName, "BINARY")==0 ) return 1;
    +-  pColl = sqlite3ExprCollSeq(pParse, pExpr->pLeft);
    +-  /* Since pLeft and pRight are both a column references, their collating
    +-  ** sequence should always be defined. */
    +-  zColl1 = ALWAYS(pColl) ? pColl->zName : 0;
    +-  pColl = sqlite3ExprCollSeq(pParse, pExpr->pRight);
    +-  zColl2 = ALWAYS(pColl) ? pColl->zName : 0;
    +-  return sqlite3StrICmp(zColl1, zColl2)==0;
    ++  return sqlite3ExprCollSeqMatch(pParse, pExpr->pLeft, pExpr->pRight);
    + }
    + 
    + /*
    +@@ -120834,46 +132263,65 @@ static Bitmask exprSelectUsage(WhereMaskSet *pMaskSet, Select *pS){
    + ** Expression pExpr is one operand of a comparison operator that might
    + ** be useful for indexing.  This routine checks to see if pExpr appears
    + ** in any index.  Return TRUE (1) if pExpr is an indexed term and return
    +-** FALSE (0) if not.  If TRUE is returned, also set *piCur to the cursor
    +-** number of the table that is indexed and *piColumn to the column number
    +-** of the column that is indexed, or -2 if an expression is being indexed.
    ++** FALSE (0) if not.  If TRUE is returned, also set aiCurCol[0] to the cursor
    ++** number of the table that is indexed and aiCurCol[1] to the column number
    ++** of the column that is indexed, or XN_EXPR (-2) if an expression is being
    ++** indexed.
    + **
    + ** If pExpr is a TK_COLUMN column reference, then this routine always returns
    + ** true even if that particular column is not indexed, because the column
    + ** might be added to an automatic index later.
    + */
    +-static int exprMightBeIndexed(
    ++static SQLITE_NOINLINE int exprMightBeIndexed2(
    +   SrcList *pFrom,        /* The FROM clause */
    +   Bitmask mPrereq,       /* Bitmask of FROM clause terms referenced by pExpr */
    +-  Expr *pExpr,           /* An operand of a comparison operator */
    +-  int *piCur,            /* Write the referenced table cursor number here */
    +-  int *piColumn          /* Write the referenced table column number here */
    ++  int *aiCurCol,         /* Write the referenced table cursor and column here */
    ++  Expr *pExpr            /* An operand of a comparison operator */
    + ){
    +   Index *pIdx;
    +   int i;
    +   int iCur;
    +-  if( pExpr->op==TK_COLUMN ){
    +-    *piCur = pExpr->iTable;
    +-    *piColumn = pExpr->iColumn;
    +-    return 1;
    +-  }
    +-  if( mPrereq==0 ) return 0;                 /* No table references */
    +-  if( (mPrereq&(mPrereq-1))!=0 ) return 0;   /* Refs more than one table */
    +   for(i=0; mPrereq>1; i++, mPrereq>>=1){}
    +   iCur = pFrom->a[i].iCursor;
    +   for(pIdx=pFrom->a[i].pTab->pIndex; pIdx; pIdx=pIdx->pNext){
    +     if( pIdx->aColExpr==0 ) continue;
    +     for(i=0; i<pIdx->nKeyCol; i++){
    +-      if( pIdx->aiColumn[i]!=(-2) ) continue;
    +-      if( sqlite3ExprCompare(pExpr, pIdx->aColExpr->a[i].pExpr, iCur)==0 ){
    +-        *piCur = iCur;
    +-        *piColumn = -2;
    ++      if( pIdx->aiColumn[i]!=XN_EXPR ) continue;
    ++      if( sqlite3ExprCompareSkip(pExpr, pIdx->aColExpr->a[i].pExpr, iCur)==0 ){
    ++        aiCurCol[0] = iCur;
    ++        aiCurCol[1] = XN_EXPR;
    +         return 1;
    +       }
    +     }
    +   }
    +   return 0;
    + }
    ++static int exprMightBeIndexed(
    ++  SrcList *pFrom,        /* The FROM clause */
    ++  Bitmask mPrereq,       /* Bitmask of FROM clause terms referenced by pExpr */
    ++  int *aiCurCol,         /* Write the referenced table cursor & column here */
    ++  Expr *pExpr,           /* An operand of a comparison operator */
    ++  int op                 /* The specific comparison operator */
    ++){
    ++  /* If this expression is a vector to the left or right of a 
    ++  ** inequality constraint (>, <, >= or <=), perform the processing 
    ++  ** on the first element of the vector.  */
    ++  assert( TK_GT+1==TK_LE && TK_GT+2==TK_LT && TK_GT+3==TK_GE );
    ++  assert( TK_IS<TK_GE && TK_ISNULL<TK_GE && TK_IN<TK_GE );
    ++  assert( op<=TK_GE );
    ++  if( pExpr->op==TK_VECTOR && (op>=TK_GT && ALWAYS(op<=TK_GE)) ){
    ++    pExpr = pExpr->x.pList->a[0].pExpr;
    ++  }
    ++
    ++  if( pExpr->op==TK_COLUMN ){
    ++    aiCurCol[0] = pExpr->iTable;
    ++    aiCurCol[1] = pExpr->iColumn;
    ++    return 1;
    ++  }
    ++  if( mPrereq==0 ) return 0;                 /* No table references */
    ++  if( (mPrereq&(mPrereq-1))!=0 ) return 0;   /* Refs more than one table */
    ++  return exprMightBeIndexed2(pFrom,mPrereq,aiCurCol,pExpr);
    ++}
    + 
    + /*
    + ** The input to this routine is an WhereTerm structure with only the
    +@@ -120911,6 +132359,8 @@ static void exprAnalyze(
    +   int op;                          /* Top-level operator.  pExpr->op */
    +   Parse *pParse = pWInfo->pParse;  /* Parsing context */
    +   sqlite3 *db = pParse->db;        /* Database connection */
    ++  unsigned char eOp2 = 0;          /* op2 value for LIKE/REGEXP/GLOB */
    ++  int nLeft;                       /* Number of elements on left side vector */
    + 
    +   if( db->mallocFailed ){
    +     return;
    +@@ -120923,6 +132373,7 @@ static void exprAnalyze(
    +   op = pExpr->op;
    +   if( op==TK_IN ){
    +     assert( pExpr->pRight==0 );
    ++    if( sqlite3ExprCheckIN(pParse, pExpr) ) return;
    +     if( ExprHasProperty(pExpr, EP_xIsSelect) ){
    +       pTerm->prereqRight = exprSelectUsage(pMaskSet, pExpr->x.pSelect);
    +     }else{
    +@@ -120933,34 +132384,48 @@ static void exprAnalyze(
    +   }else{
    +     pTerm->prereqRight = sqlite3WhereExprUsage(pMaskSet, pExpr->pRight);
    +   }
    ++  pMaskSet->bVarSelect = 0;
    +   prereqAll = sqlite3WhereExprUsage(pMaskSet, pExpr);
    ++  if( pMaskSet->bVarSelect ) pTerm->wtFlags |= TERM_VARSELECT;
    +   if( ExprHasProperty(pExpr, EP_FromJoin) ){
    +     Bitmask x = sqlite3WhereGetMask(pMaskSet, pExpr->iRightJoinTable);
    +     prereqAll |= x;
    +     extraRight = x-1;  /* ON clause terms may not be used with an index
    +                        ** on left table of a LEFT JOIN.  Ticket #3015 */
    ++    if( (prereqAll>>1)>=x ){
    ++      sqlite3ErrorMsg(pParse, "ON clause references tables to its right");
    ++      return;
    ++    }
    +   }
    +   pTerm->prereqAll = prereqAll;
    +   pTerm->leftCursor = -1;
    +   pTerm->iParent = -1;
    +   pTerm->eOperator = 0;
    +   if( allowedOp(op) ){
    +-    int iCur, iColumn;
    ++    int aiCurCol[2];
    +     Expr *pLeft = sqlite3ExprSkipCollate(pExpr->pLeft);
    +     Expr *pRight = sqlite3ExprSkipCollate(pExpr->pRight);
    +     u16 opMask = (pTerm->prereqRight & prereqLeft)==0 ? WO_ALL : WO_EQUIV;
    +-    if( exprMightBeIndexed(pSrc, prereqLeft, pLeft, &iCur, &iColumn) ){
    +-      pTerm->leftCursor = iCur;
    +-      pTerm->u.leftColumn = iColumn;
    ++
    ++    if( pTerm->iField>0 ){
    ++      assert( op==TK_IN );
    ++      assert( pLeft->op==TK_VECTOR );
    ++      pLeft = pLeft->x.pList->a[pTerm->iField-1].pExpr;
    ++    }
    ++
    ++    if( exprMightBeIndexed(pSrc, prereqLeft, aiCurCol, pLeft, op) ){
    ++      pTerm->leftCursor = aiCurCol[0];
    ++      pTerm->u.leftColumn = aiCurCol[1];
    +       pTerm->eOperator = operatorMask(op) & opMask;
    +     }
    +     if( op==TK_IS ) pTerm->wtFlags |= TERM_IS;
    +     if( pRight 
    +-     && exprMightBeIndexed(pSrc, pTerm->prereqRight, pRight, &iCur, &iColumn)
    ++     && exprMightBeIndexed(pSrc, pTerm->prereqRight, aiCurCol, pRight, op)
    +     ){
    +       WhereTerm *pNew;
    +       Expr *pDup;
    +       u16 eExtraOp = 0;        /* Extra bits for pNew->eOperator */
    ++      assert( pTerm->iField==0 );
    +       if( pTerm->leftCursor>=0 ){
    +         int idxNew;
    +         pDup = sqlite3ExprDup(db, pExpr, 0);
    +@@ -120985,8 +132450,8 @@ static void exprAnalyze(
    +         pNew = pTerm;
    +       }
    +       exprCommute(pParse, pDup);
    +-      pNew->leftCursor = iCur;
    +-      pNew->u.leftColumn = iColumn;
    ++      pNew->leftCursor = aiCurCol[0];
    ++      pNew->u.leftColumn = aiCurCol[1];
    +       testcase( (prereqLeft | extraRight) != prereqLeft );
    +       pNew->prereqRight = prereqLeft | extraRight;
    +       pNew->prereqAll = prereqAll;
    +@@ -121021,7 +132486,7 @@ static void exprAnalyze(
    +       int idxNew;
    +       pNewExpr = sqlite3PExpr(pParse, ops[i], 
    +                              sqlite3ExprDup(db, pExpr->pLeft, 0),
    +-                             sqlite3ExprDup(db, pList->a[i].pExpr, 0), 0);
    ++                             sqlite3ExprDup(db, pList->a[i].pExpr, 0));
    +       transferJoinMarkings(pNewExpr, pExpr);
    +       idxNew = whereClauseInsert(pWC, pNewExpr, TERM_VIRTUAL|TERM_DYNAMIC);
    +       testcase( idxNew==0 );
    +@@ -121106,7 +132571,7 @@ static void exprAnalyze(
    +     pNewExpr1 = sqlite3ExprDup(db, pLeft, 0);
    +     pNewExpr1 = sqlite3PExpr(pParse, TK_GE,
    +            sqlite3ExprAddCollateString(pParse,pNewExpr1,zCollSeqName),
    +-           pStr1, 0);
    ++           pStr1);
    +     transferJoinMarkings(pNewExpr1, pExpr);
    +     idxNew1 = whereClauseInsert(pWC, pNewExpr1, wtFlags);
    +     testcase( idxNew1==0 );
    +@@ -121114,7 +132579,7 @@ static void exprAnalyze(
    +     pNewExpr2 = sqlite3ExprDup(db, pLeft, 0);
    +     pNewExpr2 = sqlite3PExpr(pParse, TK_LT,
    +            sqlite3ExprAddCollateString(pParse,pNewExpr2,zCollSeqName),
    +-           pStr2, 0);
    ++           pStr2);
    +     transferJoinMarkings(pNewExpr2, pExpr);
    +     idxNew2 = whereClauseInsert(pWC, pNewExpr2, wtFlags);
    +     testcase( idxNew2==0 );
    +@@ -121128,40 +132593,102 @@ static void exprAnalyze(
    + #endif /* SQLITE_OMIT_LIKE_OPTIMIZATION */
    + 
    + #ifndef SQLITE_OMIT_VIRTUALTABLE
    +-  /* Add a WO_MATCH auxiliary term to the constraint set if the
    +-  ** current expression is of the form:  column MATCH expr.
    ++  /* Add a WO_AUX auxiliary term to the constraint set if the
    ++  ** current expression is of the form "column OP expr" where OP
    ++  ** is an operator that gets passed into virtual tables but which is
    ++  ** not normally optimized for ordinary tables.  In other words, OP
    ++  ** is one of MATCH, LIKE, GLOB, REGEXP, !=, IS, IS NOT, or NOT NULL.
    +   ** This information is used by the xBestIndex methods of
    +   ** virtual tables.  The native query optimizer does not attempt
    +   ** to do anything with MATCH functions.
    +   */
    +-  if( isMatchOfColumn(pExpr) ){
    +-    int idxNew;
    +-    Expr *pRight, *pLeft;
    +-    WhereTerm *pNewTerm;
    +-    Bitmask prereqColumn, prereqExpr;
    ++  if( pWC->op==TK_AND ){
    ++    Expr *pRight = 0, *pLeft = 0;
    ++    int res = isAuxiliaryVtabOperator(pExpr, &eOp2, &pLeft, &pRight);
    ++    while( res-- > 0 ){
    ++      int idxNew;
    ++      WhereTerm *pNewTerm;
    ++      Bitmask prereqColumn, prereqExpr;
    ++
    ++      prereqExpr = sqlite3WhereExprUsage(pMaskSet, pRight);
    ++      prereqColumn = sqlite3WhereExprUsage(pMaskSet, pLeft);
    ++      if( (prereqExpr & prereqColumn)==0 ){
    ++        Expr *pNewExpr;
    ++        pNewExpr = sqlite3PExpr(pParse, TK_MATCH, 
    ++            0, sqlite3ExprDup(db, pRight, 0));
    ++        if( ExprHasProperty(pExpr, EP_FromJoin) && pNewExpr ){
    ++          ExprSetProperty(pNewExpr, EP_FromJoin);
    ++        }
    ++        idxNew = whereClauseInsert(pWC, pNewExpr, TERM_VIRTUAL|TERM_DYNAMIC);
    ++        testcase( idxNew==0 );
    ++        pNewTerm = &pWC->a[idxNew];
    ++        pNewTerm->prereqRight = prereqExpr;
    ++        pNewTerm->leftCursor = pLeft->iTable;
    ++        pNewTerm->u.leftColumn = pLeft->iColumn;
    ++        pNewTerm->eOperator = WO_AUX;
    ++        pNewTerm->eMatchOp = eOp2;
    ++        markTermAsChild(pWC, idxNew, idxTerm);
    ++        pTerm = &pWC->a[idxTerm];
    ++        pTerm->wtFlags |= TERM_COPIED;
    ++        pNewTerm->prereqAll = pTerm->prereqAll;
    ++      }
    ++      SWAP(Expr*, pLeft, pRight);
    ++    }
    ++  }
    ++#endif /* SQLITE_OMIT_VIRTUALTABLE */
    + 
    +-    pRight = pExpr->x.pList->a[0].pExpr;
    +-    pLeft = pExpr->x.pList->a[1].pExpr;
    +-    prereqExpr = sqlite3WhereExprUsage(pMaskSet, pRight);
    +-    prereqColumn = sqlite3WhereExprUsage(pMaskSet, pLeft);
    +-    if( (prereqExpr & prereqColumn)==0 ){
    +-      Expr *pNewExpr;
    +-      pNewExpr = sqlite3PExpr(pParse, TK_MATCH, 
    +-                              0, sqlite3ExprDup(db, pRight, 0), 0);
    +-      idxNew = whereClauseInsert(pWC, pNewExpr, TERM_VIRTUAL|TERM_DYNAMIC);
    +-      testcase( idxNew==0 );
    +-      pNewTerm = &pWC->a[idxNew];
    +-      pNewTerm->prereqRight = prereqExpr;
    +-      pNewTerm->leftCursor = pLeft->iTable;
    +-      pNewTerm->u.leftColumn = pLeft->iColumn;
    +-      pNewTerm->eOperator = WO_MATCH;
    ++  /* If there is a vector == or IS term - e.g. "(a, b) == (?, ?)" - create
    ++  ** new terms for each component comparison - "a = ?" and "b = ?".  The
    ++  ** new terms completely replace the original vector comparison, which is
    ++  ** no longer used.
    ++  **
    ++  ** This is only required if at least one side of the comparison operation
    ++  ** is not a sub-select.  */
    ++  if( pWC->op==TK_AND 
    ++  && (pExpr->op==TK_EQ || pExpr->op==TK_IS)
    ++  && (nLeft = sqlite3ExprVectorSize(pExpr->pLeft))>1
    ++  && sqlite3ExprVectorSize(pExpr->pRight)==nLeft
    ++  && ( (pExpr->pLeft->flags & EP_xIsSelect)==0 
    ++    || (pExpr->pRight->flags & EP_xIsSelect)==0)
    ++  ){
    ++    int i;
    ++    for(i=0; i<nLeft; i++){
    ++      int idxNew;
    ++      Expr *pNew;
    ++      Expr *pLeft = sqlite3ExprForVectorField(pParse, pExpr->pLeft, i);
    ++      Expr *pRight = sqlite3ExprForVectorField(pParse, pExpr->pRight, i);
    ++
    ++      pNew = sqlite3PExpr(pParse, pExpr->op, pLeft, pRight);
    ++      transferJoinMarkings(pNew, pExpr);
    ++      idxNew = whereClauseInsert(pWC, pNew, TERM_DYNAMIC);
    ++      exprAnalyze(pSrc, pWC, idxNew);
    ++    }
    ++    pTerm = &pWC->a[idxTerm];
    ++    pTerm->wtFlags = TERM_CODED|TERM_VIRTUAL;  /* Disable the original */
    ++    pTerm->eOperator = 0;
    ++  }
    ++
    ++  /* If there is a vector IN term - e.g. "(a, b) IN (SELECT ...)" - create
    ++  ** a virtual term for each vector component. The expression object
    ++  ** used by each such virtual term is pExpr (the full vector IN(...) 
    ++  ** expression). The WhereTerm.iField variable identifies the index within
    ++  ** the vector on the LHS that the virtual term represents.
    ++  **
    ++  ** This only works if the RHS is a simple SELECT, not a compound
    ++  */
    ++  if( pWC->op==TK_AND && pExpr->op==TK_IN && pTerm->iField==0
    ++   && pExpr->pLeft->op==TK_VECTOR
    ++   && pExpr->x.pSelect->pPrior==0
    ++  ){
    ++    int i;
    ++    for(i=0; i<sqlite3ExprVectorSize(pExpr->pLeft); i++){
    ++      int idxNew;
    ++      idxNew = whereClauseInsert(pWC, pExpr, TERM_VIRTUAL);
    ++      pWC->a[idxNew].iField = i+1;
    ++      exprAnalyze(pSrc, pWC, idxNew);
    +       markTermAsChild(pWC, idxNew, idxTerm);
    +-      pTerm = &pWC->a[idxTerm];
    +-      pTerm->wtFlags |= TERM_COPIED;
    +-      pNewTerm->prereqAll = pTerm->prereqAll;
    +     }
    +   }
    +-#endif /* SQLITE_OMIT_VIRTUALTABLE */
    + 
    + #ifdef SQLITE_ENABLE_STAT3_OR_STAT4
    +   /* When sqlite_stat3 histogram data is available an operator of the
    +@@ -121183,7 +132710,7 @@ static void exprAnalyze(
    + 
    +     pNewExpr = sqlite3PExpr(pParse, TK_GT,
    +                             sqlite3ExprDup(db, pLeft, 0),
    +-                            sqlite3PExpr(pParse, TK_NULL, 0, 0, 0), 0);
    ++                            sqlite3ExprAlloc(db, TK_NULL, 0, 0));
    + 
    +     idxNew = whereClauseInsert(pWC, pNewExpr,
    +                               TERM_VIRTUAL|TERM_DYNAMIC|TERM_VNULL);
    +@@ -121204,6 +132731,8 @@ static void exprAnalyze(
    +   /* Prevent ON clause terms of a LEFT JOIN from being used to drive
    +   ** an index for tables to the left of the join.
    +   */
    ++  testcase( pTerm!=&pWC->a[idxTerm] );
    ++  pTerm = &pWC->a[idxTerm];
    +   pTerm->prereqRight |= extraRight;
    + }
    + 
    +@@ -121257,7 +132786,8 @@ SQLITE_PRIVATE void sqlite3WhereClauseInit(
    + 
    + /*
    + ** Deallocate a WhereClause structure.  The WhereClause structure
    +-** itself is not freed.  This routine is the inverse of sqlite3WhereClauseInit().
    ++** itself is not freed.  This routine is the inverse of
    ++** sqlite3WhereClauseInit().
    + */
    + SQLITE_PRIVATE void sqlite3WhereClauseClear(WhereClause *pWC){
    +   int i;
    +@@ -121285,17 +132815,21 @@ SQLITE_PRIVATE void sqlite3WhereClauseClear(WhereClause *pWC){
    + ** tree.
    + */
    + SQLITE_PRIVATE Bitmask sqlite3WhereExprUsage(WhereMaskSet *pMaskSet, Expr *p){
    +-  Bitmask mask = 0;
    ++  Bitmask mask;
    +   if( p==0 ) return 0;
    +   if( p->op==TK_COLUMN ){
    +-    mask = sqlite3WhereGetMask(pMaskSet, p->iTable);
    +-    return mask;
    +-  }
    +-  mask = sqlite3WhereExprUsage(pMaskSet, p->pRight);
    +-  mask |= sqlite3WhereExprUsage(pMaskSet, p->pLeft);
    +-  if( ExprHasProperty(p, EP_xIsSelect) ){
    ++    return sqlite3WhereGetMask(pMaskSet, p->iTable);
    ++  }
    ++  mask = (p->op==TK_IF_NULL_ROW) ? sqlite3WhereGetMask(pMaskSet, p->iTable) : 0;
    ++  assert( !ExprHasProperty(p, EP_TokenOnly) );
    ++  if( p->pLeft ) mask |= sqlite3WhereExprUsage(pMaskSet, p->pLeft);
    ++  if( p->pRight ){
    ++    mask |= sqlite3WhereExprUsage(pMaskSet, p->pRight);
    ++    assert( p->x.pList==0 );
    ++  }else if( ExprHasProperty(p, EP_xIsSelect) ){
    ++    if( ExprHasProperty(p, EP_VarSelect) ) pMaskSet->bVarSelect = 1;
    +     mask |= exprSelectUsage(pMaskSet, p->x.pSelect);
    +-  }else{
    ++  }else if( p->x.pList ){
    +     mask |= sqlite3WhereExprListUsage(pMaskSet, p->x.pList);
    +   }
    +   return mask;
    +@@ -121351,21 +132885,21 @@ SQLITE_PRIVATE void sqlite3WhereTabFuncArgs(
    +   pTab = pItem->pTab;
    +   assert( pTab!=0 );
    +   pArgs = pItem->u1.pFuncArg;
    +-  assert( pArgs!=0 );
    ++  if( pArgs==0 ) return;
    +   for(j=k=0; j<pArgs->nExpr; j++){
    +-    while( k<pTab->nCol && (pTab->aCol[k].colFlags & COLFLAG_HIDDEN)==0 ){ k++; }
    ++    while( k<pTab->nCol && (pTab->aCol[k].colFlags & COLFLAG_HIDDEN)==0 ){k++;}
    +     if( k>=pTab->nCol ){
    +       sqlite3ErrorMsg(pParse, "too many arguments on %s() - max %d",
    +                       pTab->zName, j);
    +       return;
    +     }
    +-    pColRef = sqlite3PExpr(pParse, TK_COLUMN, 0, 0, 0);
    ++    pColRef = sqlite3ExprAlloc(pParse->db, TK_COLUMN, 0, 0);
    +     if( pColRef==0 ) return;
    +     pColRef->iTable = pItem->iCursor;
    +     pColRef->iColumn = k++;
    +     pColRef->pTab = pTab;
    +     pTerm = sqlite3PExpr(pParse, TK_EQ, pColRef,
    +-                         sqlite3ExprDup(pParse->db, pArgs->a[j].pExpr, 0), 0);
    ++                         sqlite3ExprDup(pParse->db, pArgs->a[j].pExpr, 0));
    +     whereClauseInsert(pWC, pTerm, TERM_DYNAMIC);
    +   }
    + }
    +@@ -121393,6 +132927,21 @@ SQLITE_PRIVATE void sqlite3WhereTabFuncArgs(
    + /* #include "sqliteInt.h" */
    + /* #include "whereInt.h" */
    + 
    ++/*
    ++** Extra information appended to the end of sqlite3_index_info but not
    ++** visible to the xBestIndex function, at least not directly.  The
    ++** sqlite3_vtab_collation() interface knows how to reach it, however.
    ++**
    ++** This object is not an API and can be changed from one release to the
    ++** next.  As long as allocateIndexInfo() and sqlite3_vtab_collation()
    ++** agree on the structure, all will be well.
    ++*/
    ++typedef struct HiddenIndexInfo HiddenIndexInfo;
    ++struct HiddenIndexInfo {
    ++  WhereClause *pWC;   /* The Where clause being analyzed */
    ++  Parse *pParse;      /* The parsing context */
    ++};
    ++
    + /* Forward declaration of methods */
    + static int whereLoopResize(sqlite3*, WhereLoop*, int);
    + 
    +@@ -121405,8 +132954,8 @@ static int whereLoopResize(sqlite3*, WhereLoop*, int);
    + /*
    + ** Return the estimated number of output rows from a WHERE clause
    + */
    +-SQLITE_PRIVATE u64 sqlite3WhereOutputRowCount(WhereInfo *pWInfo){
    +-  return sqlite3LogEstToInt(pWInfo->nRowOut);
    ++SQLITE_PRIVATE LogEst sqlite3WhereOutputRowCount(WhereInfo *pWInfo){
    ++  return pWInfo->nRowOut;
    + }
    + 
    + /*
    +@@ -121425,6 +132974,18 @@ SQLITE_PRIVATE int sqlite3WhereIsOrdered(WhereInfo *pWInfo){
    +   return pWInfo->nOBSat;
    + }
    + 
    ++/*
    ++** Return TRUE if the innermost loop of the WHERE clause implementation
    ++** returns rows in ORDER BY order for complete run of the inner loop.
    ++**
    ++** Across multiple iterations of outer loops, the output rows need not be
    ++** sorted.  As long as rows are sorted for just the innermost loop, this
    ++** routine can return TRUE.
    ++*/
    ++SQLITE_PRIVATE int sqlite3WhereOrderedInnerLoop(WhereInfo *pWInfo){
    ++  return pWInfo->bOrderedInnerLoop;
    ++}
    ++
    + /*
    + ** Return the VDBE address or label to jump to in order to continue
    + ** immediately with the next row of a WHERE clause.
    +@@ -121560,16 +133121,19 @@ static WhereTerm *whereScanNext(WhereScan *pScan){
    +   WhereTerm *pTerm;    /* The term being tested */
    +   int k = pScan->k;    /* Where to start scanning */
    + 
    +-  while( pScan->iEquiv<=pScan->nEquiv ){
    +-    iCur = pScan->aiCur[pScan->iEquiv-1];
    ++  assert( pScan->iEquiv<=pScan->nEquiv );
    ++  pWC = pScan->pWC;
    ++  while(1){
    +     iColumn = pScan->aiColumn[pScan->iEquiv-1];
    +-    if( iColumn==XN_EXPR && pScan->pIdxExpr==0 ) return 0;
    +-    while( (pWC = pScan->pWC)!=0 ){
    ++    iCur = pScan->aiCur[pScan->iEquiv-1];
    ++    assert( pWC!=0 );
    ++    do{
    +       for(pTerm=pWC->a+k; k<pWC->nTerm; k++, pTerm++){
    +         if( pTerm->leftCursor==iCur
    +          && pTerm->u.leftColumn==iColumn
    +          && (iColumn!=XN_EXPR
    +-             || sqlite3ExprCompare(pTerm->pExpr->pLeft,pScan->pIdxExpr,iCur)==0)
    ++             || sqlite3ExprCompareSkip(pTerm->pExpr->pLeft,
    ++                                       pScan->pIdxExpr,iCur)==0)
    +          && (pScan->iEquiv<=1 || !ExprHasProperty(pTerm->pExpr, EP_FromJoin))
    +         ){
    +           if( (pTerm->eOperator & WO_EQUIV)!=0
    +@@ -121614,15 +133178,17 @@ static WhereTerm *whereScanNext(WhereScan *pScan){
    +               testcase( pTerm->eOperator & WO_IS );
    +               continue;
    +             }
    ++            pScan->pWC = pWC;
    +             pScan->k = k+1;
    +             return pTerm;
    +           }
    +         }
    +       }
    +-      pScan->pWC = pScan->pWC->pOuter;
    ++      pWC = pWC->pOuter;
    +       k = 0;
    +-    }
    +-    pScan->pWC = pScan->pOrigWC;
    ++    }while( pWC!=0 );
    ++    if( pScan->iEquiv>=pScan->nEquiv ) break;
    ++    pWC = pScan->pOrigWC;
    +     k = 0;
    +     pScan->iEquiv++;
    +   }
    +@@ -121635,7 +133201,10 @@ static WhereTerm *whereScanNext(WhereScan *pScan){
    + **
    + ** The scanner will be searching the WHERE clause pWC.  It will look
    + ** for terms of the form "X <op> <expr>" where X is column iColumn of table
    +-** iCur.  The <op> must be one of the operators described by opMask.
    ++** iCur.   Or if pIdx!=0 then X is column iColumn of index pIdx.  pIdx
    ++** must be one of the indexes of table iCur.
    ++**
    ++** The <op> must be one of the operators described by opMask.
    + **
    + ** If the search is for X and the WHERE clause contains terms of the
    + ** form X=Y then this routine might also return terms of the form
    +@@ -121653,23 +133222,25 @@ static WhereTerm *whereScanInit(
    +   u32 opMask,             /* Operator(s) to scan for */
    +   Index *pIdx             /* Must be compatible with this index */
    + ){
    +-  int j = 0;
    +-
    +-  /* memset(pScan, 0, sizeof(*pScan)); */
    +   pScan->pOrigWC = pWC;
    +   pScan->pWC = pWC;
    +   pScan->pIdxExpr = 0;
    ++  pScan->idxaff = 0;
    ++  pScan->zCollName = 0;
    +   if( pIdx ){
    +-    j = iColumn;
    ++    int j = iColumn;
    +     iColumn = pIdx->aiColumn[j];
    +-    if( iColumn==XN_EXPR ) pScan->pIdxExpr = pIdx->aColExpr->a[j].pExpr;
    +-  }
    +-  if( pIdx && iColumn>=0 ){
    +-    pScan->idxaff = pIdx->pTable->aCol[iColumn].affinity;
    +-    pScan->zCollName = pIdx->azColl[j];
    +-  }else{
    +-    pScan->idxaff = 0;
    +-    pScan->zCollName = 0;
    ++    if( iColumn==XN_EXPR ){
    ++      pScan->pIdxExpr = pIdx->aColExpr->a[j].pExpr;
    ++      pScan->zCollName = pIdx->azColl[j];
    ++    }else if( iColumn==pIdx->pTable->iPKey ){
    ++      iColumn = XN_ROWID;
    ++    }else if( iColumn>=0 ){
    ++      pScan->idxaff = pIdx->pTable->aCol[iColumn].affinity;
    ++      pScan->zCollName = pIdx->azColl[j];
    ++    }
    ++  }else if( iColumn==XN_EXPR ){
    ++    return 0;
    +   }
    +   pScan->opMask = opMask;
    +   pScan->k = 0;
    +@@ -121682,11 +133253,12 @@ static WhereTerm *whereScanInit(
    + 
    + /*
    + ** Search for a term in the WHERE clause that is of the form "X <op> <expr>"
    +-** where X is a reference to the iColumn of table iCur and <op> is one of
    +-** the WO_xx operator codes specified by the op parameter.
    +-** Return a pointer to the term.  Return 0 if not found.
    ++** where X is a reference to the iColumn of table iCur or of index pIdx
    ++** if pIdx!=0 and <op> is one of the WO_xx operator codes specified by
    ++** the op parameter.  Return a pointer to the term.  Return 0 if not found.
    + **
    +-** If pIdx!=0 then search for terms matching the iColumn-th column of pIdx
    ++** If pIdx!=0 then it must be one of the indexes of table iCur.  
    ++** Search for terms matching the iColumn-th column of pIdx
    + ** rather than the iColumn-th column of table iCur.
    + **
    + ** The term returned might by Y=<expr> if there is another constraint in
    +@@ -121754,8 +133326,8 @@ static int findIndexCol(
    +      && p->iColumn==pIdx->aiColumn[iCol]
    +      && p->iTable==iBase
    +     ){
    +-      CollSeq *pColl = sqlite3ExprCollSeq(pParse, pList->a[i].pExpr);
    +-      if( pColl && 0==sqlite3StrICmp(pColl->zName, zColl) ){
    ++      CollSeq *pColl = sqlite3ExprNNCollSeq(pParse, pList->a[i].pExpr);
    ++      if( 0==sqlite3StrICmp(pColl->zName, zColl) ){
    +         return i;
    +       }
    +     }
    +@@ -121868,14 +133440,16 @@ static LogEst estLog(LogEst N){
    + ** value stored in its output register.
    + */
    + static void translateColumnToCopy(
    +-  Vdbe *v,            /* The VDBE containing code to translate */
    ++  Parse *pParse,      /* Parsing context */
    +   int iStart,         /* Translate from this opcode to the end */
    +   int iTabCur,        /* OP_Column/OP_Rowid references to this table */
    +   int iRegister,      /* The first column is in this register */
    +   int bIncrRowid      /* If non-zero, transform OP_rowid to OP_AddImm(1) */
    + ){
    ++  Vdbe *v = pParse->pVdbe;
    +   VdbeOp *pOp = sqlite3VdbeGetOp(v, iStart);
    +   int iEnd = sqlite3VdbeCurrentAddr(v);
    ++  if( pParse->db->mallocFailed ) return;
    +   for(; iStart<iEnd; iStart++, pOp++){
    +     if( pOp->p1!=iTabCur ) continue;
    +     if( pOp->opcode==OP_Column ){
    +@@ -121957,6 +133531,15 @@ static int termCanDriveIndex(
    +   char aff;
    +   if( pTerm->leftCursor!=pSrc->iCursor ) return 0;
    +   if( (pTerm->eOperator & (WO_EQ|WO_IS))==0 ) return 0;
    ++  if( (pSrc->fg.jointype & JT_LEFT) 
    ++   && !ExprHasProperty(pTerm->pExpr, EP_FromJoin)
    ++   && (pTerm->eOperator & WO_IS)
    ++  ){
    ++    /* Cannot use an IS term from the WHERE clause as an index driver for
    ++    ** the RHS of a LEFT JOIN. Such a term can only be used if it is from
    ++    ** the ON clause.  */
    ++    return 0;
    ++  }
    +   if( (pTerm->prereqRight & notReady)!=0 ) return 0;
    +   if( pTerm->u.leftColumn<0 ) return 0;
    +   aff = pSrc->pTab->aCol[pTerm->u.leftColumn].affinity;
    +@@ -122001,14 +133584,14 @@ static void constructAutomaticIndex(
    +   Expr *pPartial = 0;         /* Partial Index Expression */
    +   int iContinue = 0;          /* Jump here to skip excluded rows */
    +   struct SrcList_item *pTabItem;  /* FROM clause term being indexed */
    +-  int addrCounter;            /* Address where integer counter is initialized */
    ++  int addrCounter = 0;        /* Address where integer counter is initialized */
    +   int regBase;                /* Array of registers where record is assembled */
    + 
    +   /* Generate code to skip over the creation and initialization of the
    +   ** transient index on 2nd and subsequent iterations of the loop. */
    +   v = pParse->pVdbe;
    +   assert( v!=0 );
    +-  addrInit = sqlite3CodeOnce(pParse); VdbeCoverage(v);
    ++  addrInit = sqlite3VdbeAddOp0(v, OP_Once); VdbeCoverage(v);
    + 
    +   /* Count the number of columns that will be added to the index
    +   ** and used to match WHERE clause constraints */
    +@@ -122092,7 +133675,7 @@ static void constructAutomaticIndex(
    +         idxCols |= cMask;
    +         pIdx->aiColumn[n] = pTerm->u.leftColumn;
    +         pColl = sqlite3BinaryCompareCollSeq(pParse, pX->pLeft, pX->pRight);
    +-        pIdx->azColl[n] = pColl ? pColl->zName : "BINARY";
    ++        pIdx->azColl[n] = pColl ? pColl->zName : sqlite3StrBINARY;
    +         n++;
    +       }
    +     }
    +@@ -122104,20 +133687,20 @@ static void constructAutomaticIndex(
    +   for(i=0; i<mxBitCol; i++){
    +     if( extraCols & MASKBIT(i) ){
    +       pIdx->aiColumn[n] = i;
    +-      pIdx->azColl[n] = "BINARY";
    ++      pIdx->azColl[n] = sqlite3StrBINARY;
    +       n++;
    +     }
    +   }
    +   if( pSrc->colUsed & MASKBIT(BMS-1) ){
    +     for(i=BMS-1; i<pTable->nCol; i++){
    +       pIdx->aiColumn[n] = i;
    +-      pIdx->azColl[n] = "BINARY";
    ++      pIdx->azColl[n] = sqlite3StrBINARY;
    +       n++;
    +     }
    +   }
    +   assert( n==nKeyCol );
    +   pIdx->aiColumn[n] = XN_ROWID;
    +-  pIdx->azColl[n] = "BINARY";
    ++  pIdx->azColl[n] = sqlite3StrBINARY;
    + 
    +   /* Create the automatic index */
    +   assert( pLevel->iIdxCur>=0 );
    +@@ -122153,7 +133736,9 @@ static void constructAutomaticIndex(
    +   if( pPartial ) sqlite3VdbeResolveLabel(v, iContinue);
    +   if( pTabItem->fg.viaCoroutine ){
    +     sqlite3VdbeChangeP2(v, addrCounter, regBase+n);
    +-    translateColumnToCopy(v, addrTop, pLevel->iTabCur, pTabItem->regResult, 1);
    ++    testcase( pParse->db->mallocFailed );
    ++    translateColumnToCopy(pParse, addrTop, pLevel->iTabCur,
    ++                          pTabItem->regResult, 1);
    +     sqlite3VdbeGoto(v, addrTop);
    +     pTabItem->fg.viaCoroutine = 0;
    +   }else{
    +@@ -122179,20 +133764,23 @@ end_auto_index_create:
    + ** by passing the pointer returned by this function to sqlite3_free().
    + */
    + static sqlite3_index_info *allocateIndexInfo(
    +-  Parse *pParse,
    +-  WhereClause *pWC,
    ++  Parse *pParse,                  /* The parsing context */
    ++  WhereClause *pWC,               /* The WHERE clause being analyzed */
    +   Bitmask mUnusable,              /* Ignore terms with these prereqs */
    +-  struct SrcList_item *pSrc,
    +-  ExprList *pOrderBy
    ++  struct SrcList_item *pSrc,      /* The FROM clause term that is the vtab */
    ++  ExprList *pOrderBy,             /* The ORDER BY clause */
    ++  u16 *pmNoOmit                   /* Mask of terms not to omit */
    + ){
    +   int i, j;
    +   int nTerm;
    +   struct sqlite3_index_constraint *pIdxCons;
    +   struct sqlite3_index_orderby *pIdxOrderBy;
    +   struct sqlite3_index_constraint_usage *pUsage;
    ++  struct HiddenIndexInfo *pHidden;
    +   WhereTerm *pTerm;
    +   int nOrderBy;
    +   sqlite3_index_info *pIdxInfo;
    ++  u16 mNoOmit = 0;
    + 
    +   /* Count the number of possible WHERE clause constraints referring
    +   ** to this virtual table */
    +@@ -122204,7 +133792,7 @@ static sqlite3_index_info *allocateIndexInfo(
    +     testcase( pTerm->eOperator & WO_ISNULL );
    +     testcase( pTerm->eOperator & WO_IS );
    +     testcase( pTerm->eOperator & WO_ALL );
    +-    if( (pTerm->eOperator & ~(WO_ISNULL|WO_EQUIV|WO_IS))==0 ) continue;
    ++    if( (pTerm->eOperator & ~(WO_EQUIV))==0 ) continue;
    +     if( pTerm->wtFlags & TERM_VNULL ) continue;
    +     assert( pTerm->u.leftColumn>=(-1) );
    +     nTerm++;
    +@@ -122230,7 +133818,7 @@ static sqlite3_index_info *allocateIndexInfo(
    +   */
    +   pIdxInfo = sqlite3DbMallocZero(pParse->db, sizeof(*pIdxInfo)
    +                            + (sizeof(*pIdxCons) + sizeof(*pUsage))*nTerm
    +-                           + sizeof(*pIdxOrderBy)*nOrderBy );
    ++                           + sizeof(*pIdxOrderBy)*nOrderBy + sizeof(*pHidden) );
    +   if( pIdxInfo==0 ){
    +     sqlite3ErrorMsg(pParse, "out of memory");
    +     return 0;
    +@@ -122241,7 +133829,8 @@ static sqlite3_index_info *allocateIndexInfo(
    +   ** changing them.  We have to do some funky casting in order to
    +   ** initialize those fields.
    +   */
    +-  pIdxCons = (struct sqlite3_index_constraint*)&pIdxInfo[1];
    ++  pHidden = (struct HiddenIndexInfo*)&pIdxInfo[1];
    ++  pIdxCons = (struct sqlite3_index_constraint*)&pHidden[1];
    +   pIdxOrderBy = (struct sqlite3_index_orderby*)&pIdxCons[nTerm];
    +   pUsage = (struct sqlite3_index_constraint_usage*)&pIdxOrderBy[nOrderBy];
    +   *(int*)&pIdxInfo->nConstraint = nTerm;
    +@@ -122251,8 +133840,10 @@ static sqlite3_index_info *allocateIndexInfo(
    +   *(struct sqlite3_index_constraint_usage**)&pIdxInfo->aConstraintUsage =
    +                                                                    pUsage;
    + 
    ++  pHidden->pWC = pWC;
    ++  pHidden->pParse = pParse;
    +   for(i=j=0, pTerm=pWC->a; i<pWC->nTerm; i++, pTerm++){
    +-    u8 op;
    ++    u16 op;
    +     if( pTerm->leftCursor != pSrc->iCursor ) continue;
    +     if( pTerm->prereqRight & mUnusable ) continue;
    +     assert( IsPowerOfTwo(pTerm->eOperator & ~WO_EQUIV) );
    +@@ -122260,24 +133851,42 @@ static sqlite3_index_info *allocateIndexInfo(
    +     testcase( pTerm->eOperator & WO_IS );
    +     testcase( pTerm->eOperator & WO_ISNULL );
    +     testcase( pTerm->eOperator & WO_ALL );
    +-    if( (pTerm->eOperator & ~(WO_ISNULL|WO_EQUIV|WO_IS))==0 ) continue;
    ++    if( (pTerm->eOperator & ~(WO_EQUIV))==0 ) continue;
    +     if( pTerm->wtFlags & TERM_VNULL ) continue;
    +     assert( pTerm->u.leftColumn>=(-1) );
    +     pIdxCons[j].iColumn = pTerm->u.leftColumn;
    +     pIdxCons[j].iTermOffset = i;
    +-    op = (u8)pTerm->eOperator & WO_ALL;
    ++    op = pTerm->eOperator & WO_ALL;
    +     if( op==WO_IN ) op = WO_EQ;
    +-    pIdxCons[j].op = op;
    +-    /* The direct assignment in the previous line is possible only because
    +-    ** the WO_ and SQLITE_INDEX_CONSTRAINT_ codes are identical.  The
    +-    ** following asserts verify this fact. */
    +-    assert( WO_EQ==SQLITE_INDEX_CONSTRAINT_EQ );
    +-    assert( WO_LT==SQLITE_INDEX_CONSTRAINT_LT );
    +-    assert( WO_LE==SQLITE_INDEX_CONSTRAINT_LE );
    +-    assert( WO_GT==SQLITE_INDEX_CONSTRAINT_GT );
    +-    assert( WO_GE==SQLITE_INDEX_CONSTRAINT_GE );
    +-    assert( WO_MATCH==SQLITE_INDEX_CONSTRAINT_MATCH );
    +-    assert( pTerm->eOperator & (WO_IN|WO_EQ|WO_LT|WO_LE|WO_GT|WO_GE|WO_MATCH) );
    ++    if( op==WO_AUX ){
    ++      pIdxCons[j].op = pTerm->eMatchOp;
    ++    }else if( op & (WO_ISNULL|WO_IS) ){
    ++      if( op==WO_ISNULL ){
    ++        pIdxCons[j].op = SQLITE_INDEX_CONSTRAINT_ISNULL;
    ++      }else{
    ++        pIdxCons[j].op = SQLITE_INDEX_CONSTRAINT_IS;
    ++      }
    ++    }else{
    ++      pIdxCons[j].op = (u8)op;
    ++      /* The direct assignment in the previous line is possible only because
    ++      ** the WO_ and SQLITE_INDEX_CONSTRAINT_ codes are identical.  The
    ++      ** following asserts verify this fact. */
    ++      assert( WO_EQ==SQLITE_INDEX_CONSTRAINT_EQ );
    ++      assert( WO_LT==SQLITE_INDEX_CONSTRAINT_LT );
    ++      assert( WO_LE==SQLITE_INDEX_CONSTRAINT_LE );
    ++      assert( WO_GT==SQLITE_INDEX_CONSTRAINT_GT );
    ++      assert( WO_GE==SQLITE_INDEX_CONSTRAINT_GE );
    ++      assert( pTerm->eOperator&(WO_IN|WO_EQ|WO_LT|WO_LE|WO_GT|WO_GE|WO_AUX) );
    ++
    ++      if( op & (WO_LT|WO_LE|WO_GT|WO_GE)
    ++       && sqlite3ExprIsVector(pTerm->pExpr->pRight) 
    ++      ){
    ++        if( i<16 ) mNoOmit |= (1 << i);
    ++        if( op==WO_LT ) pIdxCons[j].op = WO_LE;
    ++        if( op==WO_GT ) pIdxCons[j].op = WO_GE;
    ++      }
    ++    }
    ++
    +     j++;
    +   }
    +   for(i=0; i<nOrderBy; i++){
    +@@ -122286,6 +133895,7 @@ static sqlite3_index_info *allocateIndexInfo(
    +     pIdxOrderBy[i].desc = pOrderBy->a[i].sortOrder;
    +   }
    + 
    ++  *pmNoOmit = mNoOmit;
    +   return pIdxInfo;
    + }
    + 
    +@@ -122305,7 +133915,6 @@ static sqlite3_index_info *allocateIndexInfo(
    + */
    + static int vtabBestIndex(Parse *pParse, Table *pTab, sqlite3_index_info *p){
    +   sqlite3_vtab *pVtab = sqlite3GetVTable(pParse->db, pTab)->pVtab;
    +-  int i;
    +   int rc;
    + 
    +   TRACE_IDX_INPUTS(p);
    +@@ -122314,7 +133923,7 @@ static int vtabBestIndex(Parse *pParse, Table *pTab, sqlite3_index_info *p){
    + 
    +   if( rc!=SQLITE_OK ){
    +     if( rc==SQLITE_NOMEM ){
    +-      pParse->db->mallocFailed = 1;
    ++      sqlite3OomFault(pParse->db);
    +     }else if( !pVtab->zErrMsg ){
    +       sqlite3ErrorMsg(pParse, "%s", sqlite3ErrStr(rc));
    +     }else{
    +@@ -122324,12 +133933,16 @@ static int vtabBestIndex(Parse *pParse, Table *pTab, sqlite3_index_info *p){
    +   sqlite3_free(pVtab->zErrMsg);
    +   pVtab->zErrMsg = 0;
    + 
    ++#if 0
    ++  /* This error is now caught by the caller.
    ++  ** Search for "xBestIndex malfunction" below */
    +   for(i=0; i<p->nConstraint; i++){
    +     if( !p->aConstraint[i].usable && p->aConstraintUsage[i].argvIndex>0 ){
    +       sqlite3ErrorMsg(pParse, 
    +           "table %s: xBestIndex returned an invalid plan", pTab->zName);
    +     }
    +   }
    ++#endif
    + 
    +   return pParse->nErr;
    + }
    +@@ -122521,7 +134134,7 @@ static int whereKeyStats(
    +       iGap = iGap/3;
    +     }
    +     aStat[0] = iLower + iGap;
    +-    aStat[1] = pIdx->aAvgEq[iCol];
    ++    aStat[1] = pIdx->aAvgEq[nField-1];
    +   }
    + 
    +   /* Restore the pRec->nField value before returning.  */
    +@@ -122558,7 +134171,7 @@ static LogEst whereRangeAdjust(WhereTerm *pTerm, LogEst nNew){
    + /*
    + ** Return the affinity for a single column of an index.
    + */
    +-static char sqlite3IndexColumnAffinity(sqlite3 *db, Index *pIdx, int iCol){
    ++SQLITE_PRIVATE char sqlite3IndexColumnAffinity(sqlite3 *db, Index *pIdx, int iCol){
    +   assert( iCol>=0 && iCol<pIdx->nColumn );
    +   if( !pIdx->zColAff ){
    +     if( sqlite3IndexAffinityStr(db, pIdx)==0 ) return SQLITE_AFF_BLOB;
    +@@ -122735,7 +134348,8 @@ static int whereRangeScanEst(
    +     if( nEq==pBuilder->nRecValid ){
    +       UnpackedRecord *pRec = pBuilder->pRec;
    +       tRowcnt a[2];
    +-      u8 aff;
    ++      int nBtm = pLoop->u.btree.nBtm;
    ++      int nTop = pLoop->u.btree.nTop;
    + 
    +       /* 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
    +@@ -122765,8 +134379,6 @@ static int whereRangeScanEst(
    +         testcase( pRec->nField!=pBuilder->nRecValid );
    +         pRec->nField = pBuilder->nRecValid;
    +       }
    +-      aff = sqlite3IndexColumnAffinity(pParse->db, p, nEq);
    +-      assert( nEq!=p->nKeyCol || aff==SQLITE_AFF_INTEGER );
    +       /* Determine iLower and iUpper using ($P) only. */
    +       if( nEq==0 ){
    +         iLower = 0;
    +@@ -122785,17 +134397,20 @@ static int whereRangeScanEst(
    +       if( p->aSortOrder[nEq] ){
    +         /* The roles of pLower and pUpper are swapped for a DESC index */
    +         SWAP(WhereTerm*, pLower, pUpper);
    ++        SWAP(int, nBtm, nTop);
    +       }
    + 
    +       /* If possible, improve on the iLower estimate using ($P:$L). */
    +       if( pLower ){
    +-        int bOk;                    /* True if value is extracted from pExpr */
    ++        int n;                    /* Values extracted from pExpr */
    +         Expr *pExpr = pLower->pExpr->pRight;
    +-        rc = sqlite3Stat4ProbeSetValue(pParse, p, &pRec, pExpr, aff, nEq, &bOk);
    +-        if( rc==SQLITE_OK && bOk ){
    ++        rc = sqlite3Stat4ProbeSetValue(pParse, p, &pRec, pExpr, nBtm, nEq, &n);
    ++        if( rc==SQLITE_OK && n ){
    +           tRowcnt iNew;
    ++          u16 mask = WO_GT|WO_LE;
    ++          if( sqlite3ExprVectorSize(pExpr)>n ) mask = (WO_LE|WO_LT);
    +           iLwrIdx = whereKeyStats(pParse, p, pRec, 0, a);
    +-          iNew = a[0] + ((pLower->eOperator & (WO_GT|WO_LE)) ? a[1] : 0);
    ++          iNew = a[0] + ((pLower->eOperator & mask) ? a[1] : 0);
    +           if( iNew>iLower ) iLower = iNew;
    +           nOut--;
    +           pLower = 0;
    +@@ -122804,13 +134419,15 @@ static int whereRangeScanEst(
    + 
    +       /* If possible, improve on the iUpper estimate using ($P:$U). */
    +       if( pUpper ){
    +-        int bOk;                    /* True if value is extracted from pExpr */
    ++        int n;                    /* Values extracted from pExpr */
    +         Expr *pExpr = pUpper->pExpr->pRight;
    +-        rc = sqlite3Stat4ProbeSetValue(pParse, p, &pRec, pExpr, aff, nEq, &bOk);
    +-        if( rc==SQLITE_OK && bOk ){
    ++        rc = sqlite3Stat4ProbeSetValue(pParse, p, &pRec, pExpr, nTop, nEq, &n);
    ++        if( rc==SQLITE_OK && n ){
    +           tRowcnt iNew;
    ++          u16 mask = WO_GT|WO_LE;
    ++          if( sqlite3ExprVectorSize(pExpr)>n ) mask = (WO_LE|WO_LT);
    +           iUprIdx = whereKeyStats(pParse, p, pRec, 1, a);
    +-          iNew = a[0] + ((pUpper->eOperator & (WO_GT|WO_LE)) ? a[1] : 0);
    ++          iNew = a[0] + ((pUpper->eOperator & mask) ? a[1] : 0);
    +           if( iNew<iUpper ) iUpper = iNew;
    +           nOut--;
    +           pUpper = 0;
    +@@ -122900,7 +134517,6 @@ static int whereEqualScanEst(
    +   Index *p = pBuilder->pNew->u.btree.pIndex;
    +   int nEq = pBuilder->pNew->u.btree.nEq;
    +   UnpackedRecord *pRec = pBuilder->pRec;
    +-  u8 aff;                   /* Column affinity */
    +   int rc;                   /* Subfunction return code */
    +   tRowcnt a[2];             /* Statistics */
    +   int bOk;
    +@@ -122924,15 +134540,15 @@ static int whereEqualScanEst(
    +     return SQLITE_OK;
    +   }
    + 
    +-  aff = sqlite3IndexColumnAffinity(pParse->db, p, nEq-1);
    +-  rc = sqlite3Stat4ProbeSetValue(pParse, p, &pRec, pExpr, aff, nEq-1, &bOk);
    ++  rc = sqlite3Stat4ProbeSetValue(pParse, p, &pRec, pExpr, 1, nEq-1, &bOk);
    +   pBuilder->pRec = pRec;
    +   if( rc!=SQLITE_OK ) return rc;
    +   if( bOk==0 ) return SQLITE_NOTFOUND;
    +   pBuilder->nRecValid = nEq;
    + 
    +   whereKeyStats(pParse, p, pRec, 0, a);
    +-  WHERETRACE(0x10,("equality scan regions: %d\n", (int)a[1]));
    ++  WHERETRACE(0x10,("equality scan regions %s(%d): %d\n",
    ++                   p->zName, nEq-1, (int)a[1]));
    +   *pnRow = a[1];
    +   
    +   return rc;
    +@@ -122998,30 +134614,58 @@ static void whereTermPrint(WhereTerm *pTerm, int iTerm){
    +     sqlite3DebugPrintf("TERM-%-3d NULL\n", iTerm);
    +   }else{
    +     char zType[4];
    ++    char zLeft[50];
    +     memcpy(zType, "...", 4);
    +     if( pTerm->wtFlags & TERM_VIRTUAL ) zType[0] = 'V';
    +     if( pTerm->eOperator & WO_EQUIV  ) zType[1] = 'E';
    +     if( ExprHasProperty(pTerm->pExpr, EP_FromJoin) ) zType[2] = 'L';
    ++    if( pTerm->eOperator & WO_SINGLE ){
    ++      sqlite3_snprintf(sizeof(zLeft),zLeft,"left={%d:%d}",
    ++                       pTerm->leftCursor, pTerm->u.leftColumn);
    ++    }else if( (pTerm->eOperator & WO_OR)!=0 && pTerm->u.pOrInfo!=0 ){
    ++      sqlite3_snprintf(sizeof(zLeft),zLeft,"indexable=0x%lld", 
    ++                       pTerm->u.pOrInfo->indexable);
    ++    }else{
    ++      sqlite3_snprintf(sizeof(zLeft),zLeft,"left=%d", pTerm->leftCursor);
    ++    }
    +     sqlite3DebugPrintf(
    +-       "TERM-%-3d %p %s cursor=%-3d prob=%-3d op=0x%03x wtFlags=0x%04x\n",
    +-       iTerm, pTerm, zType, pTerm->leftCursor, pTerm->truthProb,
    ++       "TERM-%-3d %p %s %-12s prob=%-3d op=0x%03x wtFlags=0x%04x",
    ++       iTerm, pTerm, zType, zLeft, pTerm->truthProb,
    +        pTerm->eOperator, pTerm->wtFlags);
    ++    if( pTerm->iField ){
    ++      sqlite3DebugPrintf(" iField=%d\n", pTerm->iField);
    ++    }else{
    ++      sqlite3DebugPrintf("\n");
    ++    }
    +     sqlite3TreeViewExpr(0, pTerm->pExpr, 0);
    +   }
    + }
    + #endif
    + 
    ++#ifdef WHERETRACE_ENABLED
    ++/*
    ++** Show the complete content of a WhereClause
    ++*/
    ++SQLITE_PRIVATE void sqlite3WhereClausePrint(WhereClause *pWC){
    ++  int i;
    ++  for(i=0; i<pWC->nTerm; i++){
    ++    whereTermPrint(&pWC->a[i], i);
    ++  }
    ++}
    ++#endif
    ++
    + #ifdef WHERETRACE_ENABLED
    + /*
    + ** Print a WhereLoop object for debugging purposes
    + */
    + static void whereLoopPrint(WhereLoop *p, WhereClause *pWC){
    +   WhereInfo *pWInfo = pWC->pWInfo;
    +-  int nb = 1+(pWInfo->pTabList->nSrc+7)/8;
    ++  int nb = 1+(pWInfo->pTabList->nSrc+3)/4;
    +   struct SrcList_item *pItem = pWInfo->pTabList->a + p->iTab;
    +   Table *pTab = pItem->pTab;
    ++  Bitmask mAll = (((Bitmask)1)<<(nb*4)) - 1;
    +   sqlite3DebugPrintf("%c%2d.%0*llx.%0*llx", p->cId,
    +-                     p->iTab, nb, p->maskSelf, nb, p->prereq);
    ++                     p->iTab, nb, p->maskSelf, nb, p->prereq & mAll);
    +   sqlite3DebugPrintf(" %12s",
    +                      pItem->zAlias ? pItem->zAlias : pTab->zName);
    +   if( (p->wsFlags & WHERE_VIRTUALTABLE)==0 ){
    +@@ -123084,7 +134728,7 @@ static void whereLoopClearUnion(sqlite3 *db, WhereLoop *p){
    +       p->u.vtab.idxStr = 0;
    +     }else if( (p->wsFlags & WHERE_AUTO_INDEX)!=0 && p->u.btree.pIndex!=0 ){
    +       sqlite3DbFree(db, p->u.btree.pIndex->zColAff);
    +-      sqlite3DbFree(db, p->u.btree.pIndex);
    ++      sqlite3DbFreeNN(db, p->u.btree.pIndex);
    +       p->u.btree.pIndex = 0;
    +     }
    +   }
    +@@ -123094,7 +134738,7 @@ static void whereLoopClearUnion(sqlite3 *db, WhereLoop *p){
    + ** Deallocate internal memory used by a WhereLoop object
    + */
    + static void whereLoopClear(sqlite3 *db, WhereLoop *p){
    +-  if( p->aLTerm!=p->aLTermSpace ) sqlite3DbFree(db, p->aLTerm);
    ++  if( p->aLTerm!=p->aLTermSpace ) sqlite3DbFreeNN(db, p->aLTerm);
    +   whereLoopClearUnion(db, p);
    +   whereLoopInit(p);
    + }
    +@@ -123106,10 +134750,10 @@ static int whereLoopResize(sqlite3 *db, WhereLoop *p, int n){
    +   WhereTerm **paNew;
    +   if( p->nLSlot>=n ) return SQLITE_OK;
    +   n = (n+7)&~7;
    +-  paNew = sqlite3DbMallocRaw(db, sizeof(p->aLTerm[0])*n);
    +-  if( paNew==0 ) return SQLITE_NOMEM;
    ++  paNew = sqlite3DbMallocRawNN(db, sizeof(p->aLTerm[0])*n);
    ++  if( paNew==0 ) return SQLITE_NOMEM_BKPT;
    +   memcpy(paNew, p->aLTerm, sizeof(p->aLTerm[0])*p->nLSlot);
    +-  if( p->aLTerm!=p->aLTermSpace ) sqlite3DbFree(db, p->aLTerm);
    ++  if( p->aLTerm!=p->aLTermSpace ) sqlite3DbFreeNN(db, p->aLTerm);
    +   p->aLTerm = paNew;
    +   p->nLSlot = n;
    +   return SQLITE_OK;
    +@@ -123122,7 +134766,7 @@ static int whereLoopXfer(sqlite3 *db, WhereLoop *pTo, WhereLoop *pFrom){
    +   whereLoopClearUnion(db, pTo);
    +   if( whereLoopResize(db, pTo, pFrom->nLTerm) ){
    +     memset(&pTo->u, 0, sizeof(pTo->u));
    +-    return SQLITE_NOMEM;
    ++    return SQLITE_NOMEM_BKPT;
    +   }
    +   memcpy(pTo, pFrom, WHERE_LOOP_XFER_SZ);
    +   memcpy(pTo->aLTerm, pFrom->aLTerm, pTo->nLTerm*sizeof(pTo->aLTerm[0]));
    +@@ -123139,47 +134783,47 @@ static int whereLoopXfer(sqlite3 *db, WhereLoop *pTo, WhereLoop *pFrom){
    + */
    + static void whereLoopDelete(sqlite3 *db, WhereLoop *p){
    +   whereLoopClear(db, p);
    +-  sqlite3DbFree(db, p);
    ++  sqlite3DbFreeNN(db, p);
    + }
    + 
    + /*
    + ** Free a WhereInfo structure
    + */
    + static void whereInfoFree(sqlite3 *db, WhereInfo *pWInfo){
    +-  if( ALWAYS(pWInfo) ){
    +-    int i;
    +-    for(i=0; i<pWInfo->nLevel; i++){
    +-      WhereLevel *pLevel = &pWInfo->a[i];
    +-      if( pLevel->pWLoop && (pLevel->pWLoop->wsFlags & WHERE_IN_ABLE) ){
    +-        sqlite3DbFree(db, pLevel->u.in.aInLoop);
    +-      }
    +-    }
    +-    sqlite3WhereClauseClear(&pWInfo->sWC);
    +-    while( pWInfo->pLoops ){
    +-      WhereLoop *p = pWInfo->pLoops;
    +-      pWInfo->pLoops = p->pNextLoop;
    +-      whereLoopDelete(db, p);
    ++  int i;
    ++  assert( pWInfo!=0 );
    ++  for(i=0; i<pWInfo->nLevel; i++){
    ++    WhereLevel *pLevel = &pWInfo->a[i];
    ++    if( pLevel->pWLoop && (pLevel->pWLoop->wsFlags & WHERE_IN_ABLE) ){
    ++      sqlite3DbFree(db, pLevel->u.in.aInLoop);
    +     }
    +-    sqlite3DbFree(db, pWInfo);
    +   }
    ++  sqlite3WhereClauseClear(&pWInfo->sWC);
    ++  while( pWInfo->pLoops ){
    ++    WhereLoop *p = pWInfo->pLoops;
    ++    pWInfo->pLoops = p->pNextLoop;
    ++    whereLoopDelete(db, p);
    ++  }
    ++  sqlite3DbFreeNN(db, pWInfo);
    + }
    + 
    + /*
    + ** Return TRUE if all of the following are true:
    + **
    + **   (1)  X has the same or lower cost that Y
    +-**   (2)  X is a proper subset of Y
    +-**   (3)  X skips at least as many columns as 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.
    ++**   (2)  X uses fewer WHERE clause terms than Y
    ++**   (3)  Every WHERE clause term used by X is also used by Y
    ++**   (4)  X skips at least as many columns as Y
    ++**   (5)  If X is a covering index, than Y is too
    + **
    ++** Conditions (2) and (3) mean that X is a "proper subset" of 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.  The third rule
    ++** relationship is inverted and needs to be adjusted.  Constraint (4)
    + ** was added because if X uses skip-scan less than Y it still might
    +-** deserve a lower cost even if it is a proper subset of Y.
    ++** deserve a lower cost even if it is a proper subset of Y.  Constraint (5)
    ++** was added because a covering index probably deserves to have a lower cost
    ++** than a non-covering index even if it is a proper subset.
    + */
    + static int whereLoopCheaperProperSubset(
    +   const WhereLoop *pX,       /* First WhereLoop to compare */
    +@@ -123201,6 +134845,10 @@ static int whereLoopCheaperProperSubset(
    +     }
    +     if( j<0 ) return 0;  /* X not a subset of Y since term X[i] not used by Y */
    +   }
    ++  if( (pX->wsFlags&WHERE_IDX_ONLY)!=0 
    ++   && (pY->wsFlags&WHERE_IDX_ONLY)==0 ){
    ++    return 0;  /* Constraint (5) */
    ++  }
    +   return 1;  /* All conditions meet */
    + }
    + 
    +@@ -123243,16 +134891,17 @@ static void whereLoopAdjustCost(const WhereLoop *p, WhereLoop *pTemplate){
    + 
    + /*
    + ** Search the list of WhereLoops in *ppPrev looking for one that can be
    +-** supplanted by pTemplate.
    ++** replaced 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.
    ++** Return NULL if pTemplate does not belong on the WhereLoop list.
    ++** In other words if pTemplate ought to be dropped from further consideration.
    + **
    +-** If pX is a WhereLoop that pTemplate can supplant, then return the
    ++** If pX is a WhereLoop that pTemplate can replace, 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.
    ++** If pTemplate cannot replace any existing element of the list but needs
    ++** to be added to the list as a new entry, then return a pointer to the
    ++** tail of the list.
    + */
    + static WhereLoop **whereLoopFindLesser(
    +   WhereLoop **ppPrev,
    +@@ -123346,6 +134995,7 @@ static int whereLoopInsert(WhereLoopBuilder *pBuilder, WhereLoop *pTemplate){
    +   WhereLoop **ppPrev, *p;
    +   WhereInfo *pWInfo = pBuilder->pWInfo;
    +   sqlite3 *db = pWInfo->pParse->db;
    ++  int rc;
    + 
    +   /* If pBuilder->pOrSet is defined, then only keep track of the costs
    +   ** and prereqs.
    +@@ -123396,15 +135046,17 @@ static int whereLoopInsert(WhereLoopBuilder *pBuilder, WhereLoop *pTemplate){
    +     if( p!=0 ){
    +       sqlite3DebugPrintf("replace: ");
    +       whereLoopPrint(p, pBuilder->pWC);
    ++      sqlite3DebugPrintf("   with: ");
    ++    }else{
    ++      sqlite3DebugPrintf("    add: ");
    +     }
    +-    sqlite3DebugPrintf("    add: ");
    +     whereLoopPrint(pTemplate, pBuilder->pWC);
    +   }
    + #endif
    +   if( p==0 ){
    +     /* Allocate a new WhereLoop to add to the end of the list */
    +-    *ppPrev = p = sqlite3DbMallocRaw(db, sizeof(WhereLoop));
    +-    if( p==0 ) return SQLITE_NOMEM;
    ++    *ppPrev = p = sqlite3DbMallocRawNN(db, sizeof(WhereLoop));
    ++    if( p==0 ) return SQLITE_NOMEM_BKPT;
    +     whereLoopInit(p);
    +     p->pNextLoop = 0;
    +   }else{
    +@@ -123428,14 +135080,14 @@ static int whereLoopInsert(WhereLoopBuilder *pBuilder, WhereLoop *pTemplate){
    +       whereLoopDelete(db, pToDel);
    +     }
    +   }
    +-  whereLoopXfer(db, p, pTemplate);
    ++  rc = whereLoopXfer(db, p, pTemplate);
    +   if( (p->wsFlags & WHERE_VIRTUALTABLE)==0 ){
    +     Index *pIndex = p->u.btree.pIndex;
    +     if( pIndex && pIndex->tnum==0 ){
    +       p->u.btree.pIndex = 0;
    +     }
    +   }
    +-  return SQLITE_OK;
    ++  return rc;
    + }
    + 
    + /*
    +@@ -123513,6 +135165,72 @@ static void whereLoopOutputAdjust(
    +   if( pLoop->nOut > nRow-iReduce )  pLoop->nOut = nRow - iReduce;
    + }
    + 
    ++/* 
    ++** Term pTerm is a vector range comparison operation. The first comparison
    ++** in the vector can be optimized using column nEq of the index. This
    ++** function returns the total number of vector elements that can be used
    ++** as part of the range comparison.
    ++**
    ++** For example, if the query is:
    ++**
    ++**   WHERE a = ? AND (b, c, d) > (?, ?, ?)
    ++**
    ++** and the index:
    ++**
    ++**   CREATE INDEX ... ON (a, b, c, d, e)
    ++**
    ++** then this function would be invoked with nEq=1. The value returned in
    ++** this case is 3.
    ++*/
    ++static int whereRangeVectorLen(
    ++  Parse *pParse,       /* Parsing context */
    ++  int iCur,            /* Cursor open on pIdx */
    ++  Index *pIdx,         /* The index to be used for a inequality constraint */
    ++  int nEq,             /* Number of prior equality constraints on same index */
    ++  WhereTerm *pTerm     /* The vector inequality constraint */
    ++){
    ++  int nCmp = sqlite3ExprVectorSize(pTerm->pExpr->pLeft);
    ++  int i;
    ++
    ++  nCmp = MIN(nCmp, (pIdx->nColumn - nEq));
    ++  for(i=1; i<nCmp; i++){
    ++    /* Test if comparison i of pTerm is compatible with column (i+nEq) 
    ++    ** of the index. If not, exit the loop.  */
    ++    char aff;                     /* Comparison affinity */
    ++    char idxaff = 0;              /* Indexed columns affinity */
    ++    CollSeq *pColl;               /* Comparison collation sequence */
    ++    Expr *pLhs = pTerm->pExpr->pLeft->x.pList->a[i].pExpr;
    ++    Expr *pRhs = pTerm->pExpr->pRight;
    ++    if( pRhs->flags & EP_xIsSelect ){
    ++      pRhs = pRhs->x.pSelect->pEList->a[i].pExpr;
    ++    }else{
    ++      pRhs = pRhs->x.pList->a[i].pExpr;
    ++    }
    ++
    ++    /* Check that the LHS of the comparison is a column reference to
    ++    ** the right column of the right source table. And that the sort
    ++    ** order of the index column is the same as the sort order of the
    ++    ** leftmost index column.  */
    ++    if( pLhs->op!=TK_COLUMN 
    ++     || pLhs->iTable!=iCur 
    ++     || pLhs->iColumn!=pIdx->aiColumn[i+nEq] 
    ++     || pIdx->aSortOrder[i+nEq]!=pIdx->aSortOrder[nEq]
    ++    ){
    ++      break;
    ++    }
    ++
    ++    testcase( pLhs->iColumn==XN_ROWID );
    ++    aff = sqlite3CompareAffinity(pRhs, sqlite3ExprAffinity(pLhs));
    ++    idxaff = sqlite3TableColumnAffinity(pIdx->pTable, pLhs->iColumn);
    ++    if( aff!=idxaff ) break;
    ++
    ++    pColl = sqlite3BinaryCompareCollSeq(pParse, pLhs, pRhs);
    ++    if( pColl==0 ) break;
    ++    if( sqlite3StrICmp(pColl->zName, pIdx->azColl[i+nEq]) ) break;
    ++  }
    ++  return i;
    ++}
    ++
    + /*
    + ** Adjust the cost C by the costMult facter T.  This only occurs if
    + ** compiled with -DSQLITE_ENABLE_COSTMULT
    +@@ -123551,6 +135269,8 @@ static int whereLoopAddBtreeIndex(
    +   Bitmask saved_prereq;           /* Original value of pNew->prereq */
    +   u16 saved_nLTerm;               /* Original value of pNew->nLTerm */
    +   u16 saved_nEq;                  /* Original value of pNew->u.btree.nEq */
    ++  u16 saved_nBtm;                 /* Original value of pNew->u.btree.nBtm */
    ++  u16 saved_nTop;                 /* Original value of pNew->u.btree.nTop */
    +   u16 saved_nSkip;                /* Original value of pNew->nSkip */
    +   u32 saved_wsFlags;              /* Original value of pNew->wsFlags */
    +   LogEst saved_nOut;              /* Original value of pNew->nOut */
    +@@ -123560,15 +135280,16 @@ static int whereLoopAddBtreeIndex(
    +   WhereTerm *pTop = 0, *pBtm = 0; /* Top and bottom range constraints */
    + 
    +   pNew = pBuilder->pNew;
    +-  if( db->mallocFailed ) return SQLITE_NOMEM;
    ++  if( db->mallocFailed ) return SQLITE_NOMEM_BKPT;
    ++  WHERETRACE(0x800, ("BEGIN addBtreeIdx(%s), nEq=%d\n",
    ++                     pProbe->zName, pNew->u.btree.nEq));
    + 
    +   assert( (pNew->wsFlags & WHERE_VIRTUALTABLE)==0 );
    +   assert( (pNew->wsFlags & WHERE_TOP_LIMIT)==0 );
    +   if( pNew->wsFlags & WHERE_BTM_LIMIT ){
    +     opMask = WO_LT|WO_LE;
    +-  }else if( /*pProbe->tnum<=0 ||*/ (pSrc->fg.jointype & JT_LEFT)!=0 ){
    +-    opMask = WO_EQ|WO_IN|WO_GT|WO_GE|WO_LT|WO_LE;
    +   }else{
    ++    assert( pNew->u.btree.nBtm==0 );
    +     opMask = WO_EQ|WO_IN|WO_GT|WO_GE|WO_LT|WO_LE|WO_ISNULL|WO_IS;
    +   }
    +   if( pProbe->bUnordered ) opMask &= ~(WO_GT|WO_GE|WO_LT|WO_LE);
    +@@ -123576,6 +135297,8 @@ static int whereLoopAddBtreeIndex(
    +   assert( pNew->u.btree.nEq<pProbe->nColumn );
    + 
    +   saved_nEq = pNew->u.btree.nEq;
    ++  saved_nBtm = pNew->u.btree.nBtm;
    ++  saved_nTop = pNew->u.btree.nTop;
    +   saved_nSkip = pNew->nSkip;
    +   saved_nLTerm = pNew->nLTerm;
    +   saved_wsFlags = pNew->wsFlags;
    +@@ -123605,8 +135328,27 @@ static int whereLoopAddBtreeIndex(
    +     ** to mix with a lower range bound from some other source */
    +     if( pTerm->wtFlags & TERM_LIKEOPT && pTerm->eOperator==WO_LT ) continue;
    + 
    ++    /* Do not allow IS constraints from the WHERE clause to be used by the
    ++    ** right table of a LEFT JOIN.  Only constraints in the ON clause are
    ++    ** allowed */
    ++    if( (pSrc->fg.jointype & JT_LEFT)!=0
    ++     && !ExprHasProperty(pTerm->pExpr, EP_FromJoin)
    ++     && (eOp & (WO_IS|WO_ISNULL))!=0
    ++    ){
    ++      testcase( eOp & WO_IS );
    ++      testcase( eOp & WO_ISNULL );
    ++      continue;
    ++    }
    ++
    ++    if( IsUniqueIndex(pProbe) && saved_nEq==pProbe->nKeyCol-1 ){
    ++      pBuilder->bldFlags |= SQLITE_BLDF_UNIQUE;
    ++    }else{
    ++      pBuilder->bldFlags |= SQLITE_BLDF_INDEXED;
    ++    }
    +     pNew->wsFlags = saved_wsFlags;
    +     pNew->u.btree.nEq = saved_nEq;
    ++    pNew->u.btree.nBtm = saved_nBtm;
    ++    pNew->u.btree.nTop = saved_nTop;
    +     pNew->nLTerm = saved_nLTerm;
    +     if( whereLoopResize(db, pNew, pNew->nLTerm+1) ) break; /* OOM */
    +     pNew->aLTerm[pNew->nLTerm++] = pTerm;
    +@@ -123623,20 +135365,29 @@ static int whereLoopAddBtreeIndex(
    +       pNew->wsFlags |= WHERE_COLUMN_IN;
    +       if( ExprHasProperty(pExpr, EP_xIsSelect) ){
    +         /* "x IN (SELECT ...)":  TUNING: the SELECT returns 25 rows */
    ++        int i;
    +         nIn = 46;  assert( 46==sqlite3LogEst(25) );
    ++
    ++        /* The expression may actually be of the form (x, y) IN (SELECT...).
    ++        ** In this case there is a separate term for each of (x) and (y).
    ++        ** However, the nIn multiplier should only be applied once, not once
    ++        ** for each such term. The following loop checks that pTerm is the
    ++        ** first such term in use, and sets nIn back to 0 if it is not. */
    ++        for(i=0; i<pNew->nLTerm-1; i++){
    ++          if( pNew->aLTerm[i] && pNew->aLTerm[i]->pExpr==pExpr ) nIn = 0;
    ++        }
    +       }else if( ALWAYS(pExpr->x.pList && pExpr->x.pList->nExpr) ){
    +         /* "x IN (value, value, ...)" */
    +         nIn = sqlite3LogEst(pExpr->x.pList->nExpr);
    ++        assert( nIn>0 );  /* RHS always has 2 or more terms...  The parser
    ++                          ** changes "x IN (?)" into "x=?". */
    +       }
    +-      assert( nIn>0 );  /* RHS always has 2 or more terms...  The parser
    +-                        ** changes "x IN (?)" into "x=?". */
    +-
    +     }else if( eOp & (WO_EQ|WO_IS) ){
    +       int iCol = pProbe->aiColumn[saved_nEq];
    +       pNew->wsFlags |= WHERE_COLUMN_EQ;
    +       assert( saved_nEq==pNew->u.btree.nEq );
    +       if( iCol==XN_ROWID 
    +-       || (iCol>0 && nInMul==0 && saved_nEq==pProbe->nKeyCol-1)
    ++       || (iCol>=0 && nInMul==0 && saved_nEq==pProbe->nKeyCol-1)
    +       ){
    +         if( iCol>=0 && pProbe->uniqNotNull==0 ){
    +           pNew->wsFlags |= WHERE_UNQ_WANTED;
    +@@ -123650,6 +135401,9 @@ static int whereLoopAddBtreeIndex(
    +       testcase( eOp & WO_GT );
    +       testcase( eOp & WO_GE );
    +       pNew->wsFlags |= WHERE_COLUMN_RANGE|WHERE_BTM_LIMIT;
    ++      pNew->u.btree.nBtm = whereRangeVectorLen(
    ++          pParse, pSrc->iCursor, pProbe, saved_nEq, pTerm
    ++      );
    +       pBtm = pTerm;
    +       pTop = 0;
    +       if( pTerm->wtFlags & TERM_LIKEOPT ){
    +@@ -123662,12 +135416,16 @@ static int whereLoopAddBtreeIndex(
    +         if( whereLoopResize(db, pNew, pNew->nLTerm+1) ) break; /* OOM */
    +         pNew->aLTerm[pNew->nLTerm++] = pTop;
    +         pNew->wsFlags |= WHERE_TOP_LIMIT;
    ++        pNew->u.btree.nTop = 1;
    +       }
    +     }else{
    +       assert( eOp & (WO_LT|WO_LE) );
    +       testcase( eOp & WO_LT );
    +       testcase( eOp & WO_LE );
    +       pNew->wsFlags |= WHERE_COLUMN_RANGE|WHERE_TOP_LIMIT;
    ++      pNew->u.btree.nTop = whereRangeVectorLen(
    ++          pParse, pSrc->iCursor, pProbe, saved_nEq, pTerm
    ++      );
    +       pTop = pTerm;
    +       pBtm = (pNew->wsFlags & WHERE_BTM_LIMIT)!=0 ?
    +                      pNew->aLTerm[pNew->nLTerm-2] : 0;
    +@@ -123767,6 +135525,8 @@ static int whereLoopAddBtreeIndex(
    +   }
    +   pNew->prereq = saved_prereq;
    +   pNew->u.btree.nEq = saved_nEq;
    ++  pNew->u.btree.nBtm = saved_nBtm;
    ++  pNew->u.btree.nTop = saved_nTop;
    +   pNew->nSkip = saved_nSkip;
    +   pNew->wsFlags = saved_wsFlags;
    +   pNew->nOut = saved_nOut;
    +@@ -123806,6 +135566,8 @@ static int whereLoopAddBtreeIndex(
    +     pNew->wsFlags = saved_wsFlags;
    +   }
    + 
    ++  WHERETRACE(0x800, ("END addBtreeIdx(%s), nEq=%d, rc=%d\n",
    ++                      pProbe->zName, saved_nEq, rc));
    +   return rc;
    + }
    + 
    +@@ -123838,7 +135600,7 @@ static int indexMightHelpWithOrderBy(
    +     }else if( (aColExpr = pIndex->aColExpr)!=0 ){
    +       for(jj=0; jj<pIndex->nKeyCol; jj++){
    +         if( pIndex->aiColumn[jj]!=XN_EXPR ) continue;
    +-        if( sqlite3ExprCompare(pExpr,aColExpr->a[jj].pExpr,iCursor)==0 ){
    ++        if( sqlite3ExprCompareSkip(pExpr,aColExpr->a[jj].pExpr,iCursor)==0 ){
    +           return 1;
    +         }
    +       }
    +@@ -123871,14 +135633,16 @@ static Bitmask columnsInIndex(Index *pIdx){
    + static int whereUsablePartialIndex(int iTab, WhereClause *pWC, Expr *pWhere){
    +   int i;
    +   WhereTerm *pTerm;
    ++  Parse *pParse = pWC->pWInfo->pParse;
    +   while( pWhere->op==TK_AND ){
    +     if( !whereUsablePartialIndex(iTab,pWC,pWhere->pLeft) ) return 0;
    +     pWhere = pWhere->pRight;
    +   }
    ++  if( pParse->db->flags & SQLITE_EnableQPSG ) pParse = 0;
    +   for(i=0, pTerm=pWC->a; i<pWC->nTerm; i++, pTerm++){
    +     Expr *pExpr = pTerm->pExpr;
    +-    if( sqlite3ExprImpliesExpr(pExpr, pWhere, iTab) 
    +-     && (!ExprHasProperty(pExpr, EP_FromJoin) || pExpr->iRightJoinTable==iTab)
    ++    if( (!ExprHasProperty(pExpr, EP_FromJoin) || pExpr->iRightJoinTable==iTab)
    ++     && sqlite3ExprImpliesExpr(pParse, pExpr, pWhere, iTab) 
    +     ){
    +       return 1;
    +     }
    +@@ -123888,7 +135652,7 @@ 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
    ++** is identified 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
    +@@ -123924,7 +135688,7 @@ static int whereUsablePartialIndex(int iTab, WhereClause *pWC, Expr *pWhere){
    + */
    + static int whereLoopAddBtree(
    +   WhereLoopBuilder *pBuilder, /* WHERE clause information */
    +-  Bitmask mExtra              /* Extra prerequesites for using this table */
    ++  Bitmask mPrereq             /* Extra prerequesites for using this table */
    + ){
    +   WhereInfo *pWInfo;          /* WHERE analysis context */
    +   Index *pProbe;              /* An index we are evaluating */
    +@@ -123985,7 +135749,7 @@ static int whereLoopAddBtree(
    + #ifndef SQLITE_OMIT_AUTOMATIC_INDEX
    +   /* Automatic indexes */
    +   if( !pBuilder->pOrSet      /* Not part of an OR optimization */
    +-   && (pWInfo->wctrlFlags & WHERE_NO_AUTOINDEX)==0
    ++   && (pWInfo->wctrlFlags & WHERE_OR_SUBCLAUSE)==0
    +    && (pWInfo->pParse->db->flags & SQLITE_AutoIndex)!=0
    +    && pSrc->pIBIndex==0      /* Has no INDEXED BY clause */
    +    && !pSrc->fg.notIndexed   /* Has no NOT INDEXED clause */
    +@@ -124017,6 +135781,7 @@ static int whereLoopAddBtree(
    +           pNew->rSetup += 24;
    +         }
    +         ApplyCostMultiplier(pNew->rSetup, pTab->costMult);
    ++        if( pNew->rSetup<0 ) pNew->rSetup = 0;
    +         /* 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 knowing how selective the index will ultimately be.  It would
    +@@ -124024,28 +135789,33 @@ static int whereLoopAddBtree(
    +         pNew->nOut = 43;  assert( 43==sqlite3LogEst(20) );
    +         pNew->rRun = sqlite3LogEstAdd(rLogSize,pNew->nOut);
    +         pNew->wsFlags = WHERE_AUTO_INDEX;
    +-        pNew->prereq = mExtra | pTerm->prereqRight;
    ++        pNew->prereq = mPrereq | pTerm->prereqRight;
    +         rc = whereLoopInsert(pBuilder, pNew);
    +       }
    +     }
    +   }
    + #endif /* SQLITE_OMIT_AUTOMATIC_INDEX */
    + 
    +-  /* Loop over all indices
    +-  */
    +-  for(; rc==SQLITE_OK && pProbe; pProbe=pProbe->pNext, iSortIdx++){
    ++  /* Loop over all indices. If there was an INDEXED BY clause, then only 
    ++  ** consider index pProbe.  */
    ++  for(; rc==SQLITE_OK && pProbe; 
    ++      pProbe=(pSrc->pIBIndex ? 0 : pProbe->pNext), iSortIdx++
    ++  ){
    +     if( pProbe->pPartIdxWhere!=0
    +      && !whereUsablePartialIndex(pSrc->iCursor, pWC, pProbe->pPartIdxWhere) ){
    +       testcase( pNew->iTab!=pSrc->iCursor );  /* See ticket [98d973b8f5] */
    +       continue;  /* Partial index inappropriate for this query */
    +     }
    ++    if( pProbe->bNoQuery ) continue;
    +     rSize = pProbe->aiRowLogEst[0];
    +     pNew->u.btree.nEq = 0;
    ++    pNew->u.btree.nBtm = 0;
    ++    pNew->u.btree.nTop = 0;
    +     pNew->nSkip = 0;
    +     pNew->nLTerm = 0;
    +     pNew->iSortIdx = 0;
    +     pNew->rSetup = 0;
    +-    pNew->prereq = mExtra;
    ++    pNew->prereq = mPrereq;
    +     pNew->nOut = rSize;
    +     pNew->u.btree.pIndex = pProbe;
    +     b = indexMightHelpWithOrderBy(pBuilder, pProbe, pSrc->iCursor);
    +@@ -124077,6 +135847,7 @@ static int whereLoopAddBtree(
    +       /* Full scan via index */
    +       if( b
    +        || !HasRowid(pTab)
    ++       || pProbe->pPartIdxWhere!=0
    +        || ( m==0
    +          && pProbe->bUnordered==0
    +          && (pProbe->szIdxRow<pTab->szTabRow)
    +@@ -124089,11 +135860,34 @@ static int whereLoopAddBtree(
    + 
    +         /* 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).  */
    ++        ** index and table rows. */
    +         pNew->rRun = rSize + 1 + (15*pProbe->szIdxRow)/pTab->szTabRow;
    +         if( m!=0 ){
    +-          pNew->rRun = sqlite3LogEstAdd(pNew->rRun, rSize+16);
    ++          /* If this is a non-covering index scan, add in the cost of
    ++          ** doing table lookups.  The cost will be 3x the number of
    ++          ** lookups.  Take into account WHERE clause terms that can be
    ++          ** satisfied using just the index, and that do not require a
    ++          ** table lookup. */
    ++          LogEst nLookup = rSize + 16;  /* Base cost:  N*3 */
    ++          int ii;
    ++          int iCur = pSrc->iCursor;
    ++          WhereClause *pWC2 = &pWInfo->sWC;
    ++          for(ii=0; ii<pWC2->nTerm; ii++){
    ++            WhereTerm *pTerm = &pWC2->a[ii];
    ++            if( !sqlite3ExprCoveredByIndex(pTerm->pExpr, iCur, pProbe) ){
    ++              break;
    ++            }
    ++            /* pTerm can be evaluated using just the index.  So reduce
    ++            ** the expected number of table lookups accordingly */
    ++            if( pTerm->truthProb<=0 ){
    ++              nLookup += pTerm->truthProb;
    ++            }else{
    ++              nLookup--;
    ++              if( pTerm->eOperator & (WO_EQ|WO_IS) ) nLookup -= 19;
    ++            }
    ++          }
    ++          
    ++          pNew->rRun = sqlite3LogEstAdd(pNew->rRun, nLookup);
    +         }
    +         ApplyCostMultiplier(pNew->rRun, pTab->costMult);
    +         whereLoopOutputAdjust(pWC, pNew, rSize);
    +@@ -124103,27 +135897,202 @@ static int whereLoopAddBtree(
    +       }
    +     }
    + 
    ++    pBuilder->bldFlags = 0;
    +     rc = whereLoopAddBtreeIndex(pBuilder, pSrc, pProbe, 0);
    ++    if( pBuilder->bldFlags==SQLITE_BLDF_INDEXED ){
    ++      /* If a non-unique index is used, or if a prefix of the key for
    ++      ** unique index is used (making the index functionally non-unique)
    ++      ** then the sqlite_stat1 data becomes important for scoring the
    ++      ** plan */
    ++      pTab->tabFlags |= TF_StatsUsed;
    ++    }
    + #ifdef SQLITE_ENABLE_STAT3_OR_STAT4
    +     sqlite3Stat4ProbeFree(pBuilder->pRec);
    +     pBuilder->nRecValid = 0;
    +     pBuilder->pRec = 0;
    + #endif
    +-
    +-    /* If there was an INDEXED BY clause, then only that one index is
    +-    ** considered. */
    +-    if( pSrc->pIBIndex ) break;
    +   }
    +   return rc;
    + }
    + 
    + #ifndef SQLITE_OMIT_VIRTUALTABLE
    ++
    ++/*
    ++** Argument pIdxInfo is already populated with all constraints that may
    ++** be used by the virtual table identified by pBuilder->pNew->iTab. This
    ++** function marks a subset of those constraints usable, invokes the
    ++** xBestIndex method and adds the returned plan to pBuilder.
    ++**
    ++** A constraint is marked usable if:
    ++**
    ++**   * Argument mUsable indicates that its prerequisites are available, and
    ++**
    ++**   * It is not one of the operators specified in the mExclude mask passed
    ++**     as the fourth argument (which in practice is either WO_IN or 0).
    ++**
    ++** Argument mPrereq is a mask of tables that must be scanned before the
    ++** virtual table in question. These are added to the plans prerequisites
    ++** before it is added to pBuilder.
    ++**
    ++** Output parameter *pbIn is set to true if the plan added to pBuilder
    ++** uses one or more WO_IN terms, or false otherwise.
    ++*/
    ++static int whereLoopAddVirtualOne(
    ++  WhereLoopBuilder *pBuilder,
    ++  Bitmask mPrereq,                /* Mask of tables that must be used. */
    ++  Bitmask mUsable,                /* Mask of usable tables */
    ++  u16 mExclude,                   /* Exclude terms using these operators */
    ++  sqlite3_index_info *pIdxInfo,   /* Populated object for xBestIndex */
    ++  u16 mNoOmit,                    /* Do not omit these constraints */
    ++  int *pbIn                       /* OUT: True if plan uses an IN(...) op */
    ++){
    ++  WhereClause *pWC = pBuilder->pWC;
    ++  struct sqlite3_index_constraint *pIdxCons;
    ++  struct sqlite3_index_constraint_usage *pUsage = pIdxInfo->aConstraintUsage;
    ++  int i;
    ++  int mxTerm;
    ++  int rc = SQLITE_OK;
    ++  WhereLoop *pNew = pBuilder->pNew;
    ++  Parse *pParse = pBuilder->pWInfo->pParse;
    ++  struct SrcList_item *pSrc = &pBuilder->pWInfo->pTabList->a[pNew->iTab];
    ++  int nConstraint = pIdxInfo->nConstraint;
    ++
    ++  assert( (mUsable & mPrereq)==mPrereq );
    ++  *pbIn = 0;
    ++  pNew->prereq = mPrereq;
    ++
    ++  /* Set the usable flag on the subset of constraints identified by 
    ++  ** arguments mUsable and mExclude. */
    ++  pIdxCons = *(struct sqlite3_index_constraint**)&pIdxInfo->aConstraint;
    ++  for(i=0; i<nConstraint; i++, pIdxCons++){
    ++    WhereTerm *pTerm = &pWC->a[pIdxCons->iTermOffset];
    ++    pIdxCons->usable = 0;
    ++    if( (pTerm->prereqRight & mUsable)==pTerm->prereqRight 
    ++     && (pTerm->eOperator & mExclude)==0
    ++    ){
    ++      pIdxCons->usable = 1;
    ++    }
    ++  }
    ++
    ++  /* Initialize the output fields of the sqlite3_index_info structure */
    ++  memset(pUsage, 0, sizeof(pUsage[0])*nConstraint);
    ++  assert( pIdxInfo->needToFreeIdxStr==0 );
    ++  pIdxInfo->idxStr = 0;
    ++  pIdxInfo->idxNum = 0;
    ++  pIdxInfo->orderByConsumed = 0;
    ++  pIdxInfo->estimatedCost = SQLITE_BIG_DBL / (double)2;
    ++  pIdxInfo->estimatedRows = 25;
    ++  pIdxInfo->idxFlags = 0;
    ++  pIdxInfo->colUsed = (sqlite3_int64)pSrc->colUsed;
    ++
    ++  /* Invoke the virtual table xBestIndex() method */
    ++  rc = vtabBestIndex(pParse, pSrc->pTab, pIdxInfo);
    ++  if( rc ) return rc;
    ++
    ++  mxTerm = -1;
    ++  assert( pNew->nLSlot>=nConstraint );
    ++  for(i=0; i<nConstraint; i++) pNew->aLTerm[i] = 0;
    ++  pNew->u.vtab.omitMask = 0;
    ++  pIdxCons = *(struct sqlite3_index_constraint**)&pIdxInfo->aConstraint;
    ++  for(i=0; i<nConstraint; i++, pIdxCons++){
    ++    int iTerm;
    ++    if( (iTerm = pUsage[i].argvIndex - 1)>=0 ){
    ++      WhereTerm *pTerm;
    ++      int j = pIdxCons->iTermOffset;
    ++      if( iTerm>=nConstraint
    ++       || j<0
    ++       || j>=pWC->nTerm
    ++       || pNew->aLTerm[iTerm]!=0
    ++       || pIdxCons->usable==0
    ++      ){
    ++        rc = SQLITE_ERROR;
    ++        sqlite3ErrorMsg(pParse,"%s.xBestIndex malfunction",pSrc->pTab->zName);
    ++        return rc;
    ++      }
    ++      testcase( iTerm==nConstraint-1 );
    ++      testcase( j==0 );
    ++      testcase( j==pWC->nTerm-1 );
    ++      pTerm = &pWC->a[j];
    ++      pNew->prereq |= pTerm->prereqRight;
    ++      assert( iTerm<pNew->nLSlot );
    ++      pNew->aLTerm[iTerm] = pTerm;
    ++      if( iTerm>mxTerm ) mxTerm = iTerm;
    ++      testcase( iTerm==15 );
    ++      testcase( iTerm==16 );
    ++      if( iTerm<16 && pUsage[i].omit ) pNew->u.vtab.omitMask |= 1<<iTerm;
    ++      if( (pTerm->eOperator & WO_IN)!=0 ){
    ++        /* A virtual table that is constrained by an IN clause may not
    ++        ** consume the ORDER BY clause because (1) the order of IN terms
    ++        ** is not necessarily related to the order of output terms and
    ++        ** (2) Multiple outputs from a single IN value will not merge
    ++        ** together.  */
    ++        pIdxInfo->orderByConsumed = 0;
    ++        pIdxInfo->idxFlags &= ~SQLITE_INDEX_SCAN_UNIQUE;
    ++        *pbIn = 1; assert( (mExclude & WO_IN)==0 );
    ++      }
    ++    }
    ++  }
    ++  pNew->u.vtab.omitMask &= ~mNoOmit;
    ++
    ++  pNew->nLTerm = mxTerm+1;
    ++  assert( pNew->nLTerm<=pNew->nLSlot );
    ++  pNew->u.vtab.idxNum = pIdxInfo->idxNum;
    ++  pNew->u.vtab.needFree = pIdxInfo->needToFreeIdxStr;
    ++  pIdxInfo->needToFreeIdxStr = 0;
    ++  pNew->u.vtab.idxStr = pIdxInfo->idxStr;
    ++  pNew->u.vtab.isOrdered = (i8)(pIdxInfo->orderByConsumed ?
    ++      pIdxInfo->nOrderBy : 0);
    ++  pNew->rSetup = 0;
    ++  pNew->rRun = sqlite3LogEstFromDouble(pIdxInfo->estimatedCost);
    ++  pNew->nOut = sqlite3LogEst(pIdxInfo->estimatedRows);
    ++
    ++  /* Set the WHERE_ONEROW flag if the xBestIndex() method indicated
    ++  ** that the scan will visit at most one row. Clear it otherwise. */
    ++  if( pIdxInfo->idxFlags & SQLITE_INDEX_SCAN_UNIQUE ){
    ++    pNew->wsFlags |= WHERE_ONEROW;
    ++  }else{
    ++    pNew->wsFlags &= ~WHERE_ONEROW;
    ++  }
    ++  rc = whereLoopInsert(pBuilder, pNew);
    ++  if( pNew->u.vtab.needFree ){
    ++    sqlite3_free(pNew->u.vtab.idxStr);
    ++    pNew->u.vtab.needFree = 0;
    ++  }
    ++  WHERETRACE(0xffff, ("  bIn=%d prereqIn=%04llx prereqOut=%04llx\n",
    ++                      *pbIn, (sqlite3_uint64)mPrereq,
    ++                      (sqlite3_uint64)(pNew->prereq & ~mPrereq)));
    ++
    ++  return rc;
    ++}
    ++
    ++/*
    ++** If this function is invoked from within an xBestIndex() callback, it
    ++** returns a pointer to a buffer containing the name of the collation
    ++** sequence associated with element iCons of the sqlite3_index_info.aConstraint
    ++** array. Or, if iCons is out of range or there is no active xBestIndex
    ++** call, return NULL.
    ++*/
    ++SQLITE_API const char *sqlite3_vtab_collation(sqlite3_index_info *pIdxInfo, int iCons){
    ++  HiddenIndexInfo *pHidden = (HiddenIndexInfo*)&pIdxInfo[1];
    ++  const char *zRet = 0;
    ++  if( iCons>=0 && iCons<pIdxInfo->nConstraint ){
    ++    CollSeq *pC = 0;
    ++    int iTerm = pIdxInfo->aConstraint[iCons].iTermOffset;
    ++    Expr *pX = pHidden->pWC->a[iTerm].pExpr;
    ++    if( pX->pLeft ){
    ++      pC = sqlite3BinaryCompareCollSeq(pHidden->pParse, pX->pLeft, pX->pRight);
    ++    }
    ++    zRet = (pC ? pC->zName : "BINARY");
    ++  }
    ++  return zRet;
    ++}
    ++
    + /*
    + ** Add all WhereLoop objects for a table of the join identified by
    + ** pBuilder->pNew->iTab.  That table is guaranteed to be a virtual table.
    + **
    +-** If there are no LEFT or CROSS JOIN joins in the query, both mExtra and
    +-** mUnusable are set to 0. Otherwise, mExtra is a mask of all FROM clause
    ++** If there are no LEFT or CROSS JOIN joins in the query, both mPrereq and
    ++** mUnusable are set to 0. Otherwise, mPrereq is a mask of all FROM clause
    + ** entries that occur before the virtual table in the FROM clause and are
    + ** separated from it by at least one LEFT or CROSS JOIN. Similarly, the
    + ** mUnusable mask contains all FROM clause entries that occur after the
    +@@ -124134,187 +136103,128 @@ static int whereLoopAddBtree(
    + **
    + **   ... FROM t1, t2 LEFT JOIN t3, t4, vt CROSS JOIN t5, t6;
    + **
    +-** then mExtra corresponds to (t1, t2) and mUnusable to (t5, t6).
    ++** then mPrereq corresponds to (t1, t2) and mUnusable to (t5, t6).
    + **
    +-** All the tables in mExtra must be scanned before the current virtual 
    ++** All the tables in mPrereq must be scanned before the current virtual 
    + ** table. So any terms for which all prerequisites are satisfied by 
    +-** mExtra may be specified as "usable" in all calls to xBestIndex. 
    ++** mPrereq may be specified as "usable" in all calls to xBestIndex. 
    + ** Conversely, all tables in mUnusable must be scanned after the current
    + ** virtual table, so any terms for which the prerequisites overlap with
    + ** mUnusable should always be configured as "not-usable" for xBestIndex.
    + */
    + static int whereLoopAddVirtual(
    +   WhereLoopBuilder *pBuilder,  /* WHERE clause information */
    +-  Bitmask mExtra,              /* Tables that must be scanned before this one */
    ++  Bitmask mPrereq,             /* Tables that must be scanned before this one */
    +   Bitmask mUnusable            /* Tables that must be scanned after this one */
    + ){
    ++  int rc = SQLITE_OK;          /* Return code */
    +   WhereInfo *pWInfo;           /* WHERE analysis context */
    +   Parse *pParse;               /* The parsing context */
    +   WhereClause *pWC;            /* The WHERE clause */
    +   struct SrcList_item *pSrc;   /* The FROM clause term to search */
    +-  Table *pTab;
    +-  sqlite3 *db;
    +-  sqlite3_index_info *pIdxInfo;
    +-  struct sqlite3_index_constraint *pIdxCons;
    +-  struct sqlite3_index_constraint_usage *pUsage;
    +-  WhereTerm *pTerm;
    +-  int i, j;
    +-  int iTerm, mxTerm;
    +-  int nConstraint;
    +-  int seenIn = 0;              /* True if an IN operator is seen */
    +-  int seenVar = 0;             /* True if a non-constant constraint is seen */
    +-  int iPhase;                  /* 0: const w/o IN, 1: const, 2: no IN,  2: IN */
    ++  sqlite3_index_info *p;       /* Object to pass to xBestIndex() */
    ++  int nConstraint;             /* Number of constraints in p */
    ++  int bIn;                     /* True if plan uses IN(...) operator */
    +   WhereLoop *pNew;
    +-  int rc = SQLITE_OK;
    ++  Bitmask mBest;               /* Tables used by best possible plan */
    ++  u16 mNoOmit;
    + 
    +-  assert( (mExtra & mUnusable)==0 );
    ++  assert( (mPrereq & mUnusable)==0 );
    +   pWInfo = pBuilder->pWInfo;
    +   pParse = pWInfo->pParse;
    +-  db = pParse->db;
    +   pWC = pBuilder->pWC;
    +   pNew = pBuilder->pNew;
    +   pSrc = &pWInfo->pTabList->a[pNew->iTab];
    +-  pTab = pSrc->pTab;
    +-  assert( IsVirtual(pTab) );
    +-  pIdxInfo = allocateIndexInfo(pParse, pWC, mUnusable, pSrc,pBuilder->pOrderBy);
    +-  if( pIdxInfo==0 ) return SQLITE_NOMEM;
    +-  pNew->prereq = 0;
    ++  assert( IsVirtual(pSrc->pTab) );
    ++  p = allocateIndexInfo(pParse, pWC, mUnusable, pSrc, pBuilder->pOrderBy, 
    ++      &mNoOmit);
    ++  if( p==0 ) return SQLITE_NOMEM_BKPT;
    +   pNew->rSetup = 0;
    +   pNew->wsFlags = WHERE_VIRTUALTABLE;
    +   pNew->nLTerm = 0;
    +   pNew->u.vtab.needFree = 0;
    +-  pUsage = pIdxInfo->aConstraintUsage;
    +-  nConstraint = pIdxInfo->nConstraint;
    +-  if( whereLoopResize(db, pNew, nConstraint) ){
    +-    sqlite3DbFree(db, pIdxInfo);
    +-    return SQLITE_NOMEM;
    +-  }
    +-
    +-  for(iPhase=0; iPhase<=3; iPhase++){
    +-    if( !seenIn && (iPhase&1)!=0 ){
    +-      iPhase++;
    +-      if( iPhase>3 ) break;
    +-    }
    +-    if( !seenVar && iPhase>1 ) break;
    +-    pIdxCons = *(struct sqlite3_index_constraint**)&pIdxInfo->aConstraint;
    +-    for(i=0; i<pIdxInfo->nConstraint; i++, pIdxCons++){
    +-      j = pIdxCons->iTermOffset;
    +-      pTerm = &pWC->a[j];
    +-      switch( iPhase ){
    +-        case 0:    /* Constants without IN operator */
    +-          pIdxCons->usable = 0;
    +-          if( (pTerm->eOperator & WO_IN)!=0 ){
    +-            seenIn = 1;
    +-          }
    +-          if( (pTerm->prereqRight & ~mExtra)!=0 ){
    +-            seenVar = 1;
    +-          }else if( (pTerm->eOperator & WO_IN)==0 ){
    +-            pIdxCons->usable = 1;
    +-          }
    +-          break;
    +-        case 1:    /* Constants with IN operators */
    +-          assert( seenIn );
    +-          pIdxCons->usable = (pTerm->prereqRight & ~mExtra)==0;
    +-          break;
    +-        case 2:    /* Variables without IN */
    +-          assert( seenVar );
    +-          pIdxCons->usable = (pTerm->eOperator & WO_IN)==0;
    +-          break;
    +-        default:   /* Variables with IN */
    +-          assert( seenVar && seenIn );
    +-          pIdxCons->usable = 1;
    +-          break;
    ++  nConstraint = p->nConstraint;
    ++  if( whereLoopResize(pParse->db, pNew, nConstraint) ){
    ++    sqlite3DbFree(pParse->db, p);
    ++    return SQLITE_NOMEM_BKPT;
    ++  }
    ++
    ++  /* First call xBestIndex() with all constraints usable. */
    ++  WHERETRACE(0x40, ("  VirtualOne: all usable\n"));
    ++  rc = whereLoopAddVirtualOne(pBuilder, mPrereq, ALLBITS, 0, p, mNoOmit, &bIn);
    ++
    ++  /* If the call to xBestIndex() with all terms enabled produced a plan
    ++  ** that does not require any source tables (IOW: a plan with mBest==0),
    ++  ** then there is no point in making any further calls to xBestIndex() 
    ++  ** since they will all return the same result (if the xBestIndex()
    ++  ** implementation is sane). */
    ++  if( rc==SQLITE_OK && (mBest = (pNew->prereq & ~mPrereq))!=0 ){
    ++    int seenZero = 0;             /* True if a plan with no prereqs seen */
    ++    int seenZeroNoIN = 0;         /* Plan with no prereqs and no IN(...) seen */
    ++    Bitmask mPrev = 0;
    ++    Bitmask mBestNoIn = 0;
    ++
    ++    /* If the plan produced by the earlier call uses an IN(...) term, call
    ++    ** xBestIndex again, this time with IN(...) terms disabled. */
    ++    if( bIn ){
    ++      WHERETRACE(0x40, ("  VirtualOne: all usable w/o IN\n"));
    ++      rc = whereLoopAddVirtualOne(
    ++          pBuilder, mPrereq, ALLBITS, WO_IN, p, mNoOmit, &bIn);
    ++      assert( bIn==0 );
    ++      mBestNoIn = pNew->prereq & ~mPrereq;
    ++      if( mBestNoIn==0 ){
    ++        seenZero = 1;
    ++        seenZeroNoIN = 1;
    ++      }
    ++    }
    ++
    ++    /* Call xBestIndex once for each distinct value of (prereqRight & ~mPrereq) 
    ++    ** in the set of terms that apply to the current virtual table.  */
    ++    while( rc==SQLITE_OK ){
    ++      int i;
    ++      Bitmask mNext = ALLBITS;
    ++      assert( mNext>0 );
    ++      for(i=0; i<nConstraint; i++){
    ++        Bitmask mThis = (
    ++            pWC->a[p->aConstraint[i].iTermOffset].prereqRight & ~mPrereq
    ++        );
    ++        if( mThis>mPrev && mThis<mNext ) mNext = mThis;
    ++      }
    ++      mPrev = mNext;
    ++      if( mNext==ALLBITS ) break;
    ++      if( mNext==mBest || mNext==mBestNoIn ) continue;
    ++      WHERETRACE(0x40, ("  VirtualOne: mPrev=%04llx mNext=%04llx\n",
    ++                       (sqlite3_uint64)mPrev, (sqlite3_uint64)mNext));
    ++      rc = whereLoopAddVirtualOne(
    ++          pBuilder, mPrereq, mNext|mPrereq, 0, p, mNoOmit, &bIn);
    ++      if( pNew->prereq==mPrereq ){
    ++        seenZero = 1;
    ++        if( bIn==0 ) seenZeroNoIN = 1;
    +       }
    +     }
    +-    memset(pUsage, 0, sizeof(pUsage[0])*pIdxInfo->nConstraint);
    +-    if( pIdxInfo->needToFreeIdxStr ) sqlite3_free(pIdxInfo->idxStr);
    +-    pIdxInfo->idxStr = 0;
    +-    pIdxInfo->idxNum = 0;
    +-    pIdxInfo->needToFreeIdxStr = 0;
    +-    pIdxInfo->orderByConsumed = 0;
    +-    pIdxInfo->estimatedCost = SQLITE_BIG_DBL / (double)2;
    +-    pIdxInfo->estimatedRows = 25;
    +-    pIdxInfo->idxFlags = 0;
    +-    rc = vtabBestIndex(pParse, pTab, pIdxInfo);
    +-    if( rc ) goto whereLoopAddVtab_exit;
    +-    pIdxCons = *(struct sqlite3_index_constraint**)&pIdxInfo->aConstraint;
    +-    pNew->prereq = mExtra;
    +-    mxTerm = -1;
    +-    assert( pNew->nLSlot>=nConstraint );
    +-    for(i=0; i<nConstraint; i++) pNew->aLTerm[i] = 0;
    +-    pNew->u.vtab.omitMask = 0;
    +-    for(i=0; i<nConstraint; i++, pIdxCons++){
    +-      if( (iTerm = pUsage[i].argvIndex - 1)>=0 ){
    +-        j = pIdxCons->iTermOffset;
    +-        if( iTerm>=nConstraint
    +-         || j<0
    +-         || j>=pWC->nTerm
    +-         || pNew->aLTerm[iTerm]!=0
    +-        ){
    +-          rc = SQLITE_ERROR;
    +-          sqlite3ErrorMsg(pParse, "%s.xBestIndex() malfunction", pTab->zName);
    +-          goto whereLoopAddVtab_exit;
    +-        }
    +-        testcase( iTerm==nConstraint-1 );
    +-        testcase( j==0 );
    +-        testcase( j==pWC->nTerm-1 );
    +-        pTerm = &pWC->a[j];
    +-        pNew->prereq |= pTerm->prereqRight;
    +-        assert( iTerm<pNew->nLSlot );
    +-        pNew->aLTerm[iTerm] = pTerm;
    +-        if( iTerm>mxTerm ) mxTerm = iTerm;
    +-        testcase( iTerm==15 );
    +-        testcase( iTerm==16 );
    +-        if( iTerm<16 && pUsage[i].omit ) pNew->u.vtab.omitMask |= 1<<iTerm;
    +-        if( (pTerm->eOperator & WO_IN)!=0 ){
    +-          if( pUsage[i].omit==0 ){
    +-            /* Do not attempt to use an IN constraint if the virtual table
    +-            ** says that the equivalent EQ constraint cannot be safely omitted.
    +-            ** If we do attempt to use such a constraint, some rows might be
    +-            ** repeated in the output. */
    +-            break;
    +-          }
    +-          /* A virtual table that is constrained by an IN clause may not
    +-          ** consume the ORDER BY clause because (1) the order of IN terms
    +-          ** is not necessarily related to the order of output terms and
    +-          ** (2) Multiple outputs from a single IN value will not merge
    +-          ** together.  */
    +-          pIdxInfo->orderByConsumed = 0;
    +-          pIdxInfo->idxFlags &= ~SQLITE_INDEX_SCAN_UNIQUE;
    +-        }
    +-      }
    +-    }
    +-    if( i>=nConstraint ){
    +-      pNew->nLTerm = mxTerm+1;
    +-      assert( pNew->nLTerm<=pNew->nLSlot );
    +-      pNew->u.vtab.idxNum = pIdxInfo->idxNum;
    +-      pNew->u.vtab.needFree = pIdxInfo->needToFreeIdxStr;
    +-      pIdxInfo->needToFreeIdxStr = 0;
    +-      pNew->u.vtab.idxStr = pIdxInfo->idxStr;
    +-      pNew->u.vtab.isOrdered = (i8)(pIdxInfo->orderByConsumed ?
    +-                                      pIdxInfo->nOrderBy : 0);
    +-      pNew->rSetup = 0;
    +-      pNew->rRun = sqlite3LogEstFromDouble(pIdxInfo->estimatedCost);
    +-      pNew->nOut = sqlite3LogEst(pIdxInfo->estimatedRows);
    + 
    +-      /* Set the WHERE_ONEROW flag if the xBestIndex() method indicated
    +-      ** that the scan will visit at most one row. Clear it otherwise. */
    +-      if( pIdxInfo->idxFlags & SQLITE_INDEX_SCAN_UNIQUE ){
    +-        pNew->wsFlags |= WHERE_ONEROW;
    +-      }else{
    +-        pNew->wsFlags &= ~WHERE_ONEROW;
    +-      }
    +-      whereLoopInsert(pBuilder, pNew);
    +-      if( pNew->u.vtab.needFree ){
    +-        sqlite3_free(pNew->u.vtab.idxStr);
    +-        pNew->u.vtab.needFree = 0;
    +-      }
    ++    /* If the calls to xBestIndex() in the above loop did not find a plan
    ++    ** that requires no source tables at all (i.e. one guaranteed to be
    ++    ** usable), make a call here with all source tables disabled */
    ++    if( rc==SQLITE_OK && seenZero==0 ){
    ++      WHERETRACE(0x40, ("  VirtualOne: all disabled\n"));
    ++      rc = whereLoopAddVirtualOne(
    ++          pBuilder, mPrereq, mPrereq, 0, p, mNoOmit, &bIn);
    ++      if( bIn==0 ) seenZeroNoIN = 1;
    +     }
    +-  }  
    + 
    +-whereLoopAddVtab_exit:
    +-  if( pIdxInfo->needToFreeIdxStr ) sqlite3_free(pIdxInfo->idxStr);
    +-  sqlite3DbFree(db, pIdxInfo);
    ++    /* If the calls to xBestIndex() have so far failed to find a plan
    ++    ** that requires no source tables at all and does not use an IN(...)
    ++    ** operator, make a final call to obtain one here.  */
    ++    if( rc==SQLITE_OK && seenZeroNoIN==0 ){
    ++      WHERETRACE(0x40, ("  VirtualOne: all disabled and w/o IN\n"));
    ++      rc = whereLoopAddVirtualOne(
    ++          pBuilder, mPrereq, mPrereq, WO_IN, p, mNoOmit, &bIn);
    ++    }
    ++  }
    ++
    ++  if( p->needToFreeIdxStr ) sqlite3_free(p->idxStr);
    ++  sqlite3DbFreeNN(pParse->db, p);
    +   return rc;
    + }
    + #endif /* SQLITE_OMIT_VIRTUALTABLE */
    +@@ -124325,7 +136235,7 @@ whereLoopAddVtab_exit:
    + */
    + static int whereLoopAddOr(
    +   WhereLoopBuilder *pBuilder, 
    +-  Bitmask mExtra, 
    ++  Bitmask mPrereq, 
    +   Bitmask mUnusable
    + ){
    +   WhereInfo *pWInfo = pBuilder->pWInfo;
    +@@ -124379,21 +136289,19 @@ static int whereLoopAddOr(
    +         WHERETRACE(0x200, ("OR-term %d of %p has %d subterms:\n", 
    +                    (int)(pOrTerm-pOrWC->a), pTerm, sSubBuild.pWC->nTerm));
    +         if( sqlite3WhereTrace & 0x400 ){
    +-          for(i=0; i<sSubBuild.pWC->nTerm; i++){
    +-            whereTermPrint(&sSubBuild.pWC->a[i], i);
    +-          }
    ++          sqlite3WhereClausePrint(sSubBuild.pWC);
    +         }
    + #endif
    + #ifndef SQLITE_OMIT_VIRTUALTABLE
    +         if( IsVirtual(pItem->pTab) ){
    +-          rc = whereLoopAddVirtual(&sSubBuild, mExtra, mUnusable);
    ++          rc = whereLoopAddVirtual(&sSubBuild, mPrereq, mUnusable);
    +         }else
    + #endif
    +         {
    +-          rc = whereLoopAddBtree(&sSubBuild, mExtra);
    ++          rc = whereLoopAddBtree(&sSubBuild, mPrereq);
    +         }
    +         if( rc==SQLITE_OK ){
    +-          rc = whereLoopAddOr(&sSubBuild, mExtra, mUnusable);
    ++          rc = whereLoopAddOr(&sSubBuild, mPrereq, mUnusable);
    +         }
    +         assert( rc==SQLITE_OK || sCur.n==0 );
    +         if( sCur.n==0 ){
    +@@ -124450,7 +136358,7 @@ static int whereLoopAddOr(
    + */
    + static int whereLoopAddAll(WhereLoopBuilder *pBuilder){
    +   WhereInfo *pWInfo = pBuilder->pWInfo;
    +-  Bitmask mExtra = 0;
    ++  Bitmask mPrereq = 0;
    +   Bitmask mPrior = 0;
    +   int iTab;
    +   SrcList *pTabList = pWInfo->pTabList;
    +@@ -124471,9 +136379,10 @@ static int whereLoopAddAll(WhereLoopBuilder *pBuilder){
    +     if( ((pItem->fg.jointype|priorJointype) & (JT_LEFT|JT_CROSS))!=0 ){
    +       /* This condition is true when pItem is the FROM clause term on the
    +       ** right-hand-side of a LEFT or CROSS JOIN.  */
    +-      mExtra = mPrior;
    ++      mPrereq = mPrior;
    +     }
    +     priorJointype = pItem->fg.jointype;
    ++#ifndef SQLITE_OMIT_VIRTUALTABLE
    +     if( IsVirtual(pItem->pTab) ){
    +       struct SrcList_item *p;
    +       for(p=&pItem[1]; p<pEnd; p++){
    +@@ -124481,12 +136390,14 @@ static int whereLoopAddAll(WhereLoopBuilder *pBuilder){
    +           mUnusable |= sqlite3WhereGetMask(&pWInfo->sMaskSet, p->iCursor);
    +         }
    +       }
    +-      rc = whereLoopAddVirtual(pBuilder, mExtra, mUnusable);
    +-    }else{
    +-      rc = whereLoopAddBtree(pBuilder, mExtra);
    ++      rc = whereLoopAddVirtual(pBuilder, mPrereq, mUnusable);
    ++    }else
    ++#endif /* SQLITE_OMIT_VIRTUALTABLE */
    ++    {
    ++      rc = whereLoopAddBtree(pBuilder, mPrereq);
    +     }
    +     if( rc==SQLITE_OK ){
    +-      rc = whereLoopAddOr(pBuilder, mExtra, mUnusable);
    ++      rc = whereLoopAddOr(pBuilder, mPrereq, mUnusable);
    +     }
    +     mPrior |= pNew->maskSelf;
    +     if( rc || db->mallocFailed ) break;
    +@@ -124497,7 +136408,7 @@ static int whereLoopAddAll(WhereLoopBuilder *pBuilder){
    + }
    + 
    + /*
    +-** Examine a WherePath (with the addition of the extra WhereLoop of the 5th
    ++** Examine a WherePath (with the addition of the extra WhereLoop of the 6th
    + ** parameters) to see if it outputs rows in the requested ORDER BY
    + ** (or GROUP BY) without requiring a separate sort operation.  Return N:
    + ** 
    +@@ -124517,7 +136428,7 @@ 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 */
    +-  u16 wctrlFlags,       /* Might contain WHERE_GROUPBY or WHERE_DISTINCTBY */
    ++  u16 wctrlFlags,       /* WHERE_GROUPBY or _DISTINCTBY or _ORDERBY_LIMIT */
    +   u16 nLoop,            /* Number of entries in pPath->aLoop[] */
    +   WhereLoop *pLast,     /* Add this WhereLoop to the end of pPath->aLoop[] */
    +   Bitmask *pRevMask     /* OUT: Mask of WhereLoops to run in reverse order */
    +@@ -124528,6 +136439,7 @@ static i8 wherePathSatisfiesOrderBy(
    +   u8 isOrderDistinct;   /* All prior WhereLoops are order-distinct */
    +   u8 distinctColumns;   /* True if the loop has UNIQUE NOT NULL columns */
    +   u8 isMatch;           /* iColumn matches a term of the ORDER BY clause */
    ++  u16 eqOpMask;         /* Allowed equality operators */
    +   u16 nKeyCol;          /* Number of key columns in pIndex */
    +   u16 nColumn;          /* Total number of ordered columns in the index */
    +   u16 nOrderBy;         /* Number terms in the ORDER BY clause */
    +@@ -124578,12 +136490,21 @@ static i8 wherePathSatisfiesOrderBy(
    +   obDone = MASKBIT(nOrderBy)-1;
    +   orderDistinctMask = 0;
    +   ready = 0;
    ++  eqOpMask = WO_EQ | WO_IS | WO_ISNULL;
    ++  if( wctrlFlags & WHERE_ORDERBY_LIMIT ) eqOpMask |= WO_IN;
    +   for(iLoop=0; isOrderDistinct && obSat<obDone && iLoop<=nLoop; iLoop++){
    +     if( iLoop>0 ) ready |= pLoop->maskSelf;
    +-    pLoop = iLoop<nLoop ? pPath->aLoop[iLoop] : pLast;
    ++    if( iLoop<nLoop ){
    ++      pLoop = pPath->aLoop[iLoop];
    ++      if( wctrlFlags & WHERE_ORDERBY_LIMIT ) continue;
    ++    }else{
    ++      pLoop = pLast;
    ++    }
    +     if( pLoop->wsFlags & WHERE_VIRTUALTABLE ){
    +       if( pLoop->u.vtab.isOrdered ) obSat = obDone;
    +       break;
    ++    }else{
    ++      pLoop->u.btree.nIdxCol = 0;
    +     }
    +     iCur = pWInfo->pTabList->a[pLoop->iTab].iCursor;
    + 
    +@@ -124598,17 +136519,21 @@ static i8 wherePathSatisfiesOrderBy(
    +       if( pOBExpr->op!=TK_COLUMN ) continue;
    +       if( pOBExpr->iTable!=iCur ) continue;
    +       pTerm = sqlite3WhereFindTerm(&pWInfo->sWC, iCur, pOBExpr->iColumn,
    +-                       ~ready, WO_EQ|WO_ISNULL|WO_IS, 0);
    ++                       ~ready, eqOpMask, 0);
    +       if( pTerm==0 ) continue;
    ++      if( pTerm->eOperator==WO_IN ){
    ++        /* IN terms are only valid for sorting in the ORDER BY LIMIT 
    ++        ** optimization, and then only if they are actually used
    ++        ** by the query plan */
    ++        assert( wctrlFlags & WHERE_ORDERBY_LIMIT );
    ++        for(j=0; j<pLoop->nLTerm && pTerm!=pLoop->aLTerm[j]; j++){}
    ++        if( j>=pLoop->nLTerm ) continue;
    ++      }
    +       if( (pTerm->eOperator&(WO_EQ|WO_IS))!=0 && pOBExpr->iColumn>=0 ){
    +-        const char *z1, *z2;
    +-        pColl = sqlite3ExprCollSeq(pWInfo->pParse, pOrderBy->a[i].pExpr);
    +-        if( !pColl ) pColl = db->pDfltColl;
    +-        z1 = pColl->zName;
    +-        pColl = sqlite3ExprCollSeq(pWInfo->pParse, pTerm->pExpr);
    +-        if( !pColl ) pColl = db->pDfltColl;
    +-        z2 = pColl->zName;
    +-        if( sqlite3StrICmp(z1, z2)!=0 ) continue;
    ++        if( sqlite3ExprCollSeqMatch(pWInfo->pParse, 
    ++                  pOrderBy->a[i].pExpr, pTerm->pExpr)==0 ){
    ++          continue;
    ++        }
    +         testcase( pTerm->pExpr->op==TK_IS );
    +       }
    +       obSat |= MASKBIT(i);
    +@@ -124636,18 +136561,42 @@ static i8 wherePathSatisfiesOrderBy(
    +       rev = revSet = 0;
    +       distinctColumns = 0;
    +       for(j=0; j<nColumn; j++){
    +-        u8 bOnce;   /* True to run the ORDER BY search loop */
    ++        u8 bOnce = 1; /* True to run the ORDER BY search loop */
    + 
    +-        /* Skip over == and IS NULL terms */
    +-        if( j<pLoop->u.btree.nEq
    +-         && pLoop->nSkip==0
    +-         && ((i = pLoop->aLTerm[j]->eOperator) & (WO_EQ|WO_ISNULL|WO_IS))!=0
    +-        ){
    +-          if( i & WO_ISNULL ){
    +-            testcase( isOrderDistinct );
    +-            isOrderDistinct = 0;
    ++        assert( j>=pLoop->u.btree.nEq 
    ++            || (pLoop->aLTerm[j]==0)==(j<pLoop->nSkip)
    ++        );
    ++        if( j<pLoop->u.btree.nEq && j>=pLoop->nSkip ){
    ++          u16 eOp = pLoop->aLTerm[j]->eOperator;
    ++
    ++          /* Skip over == and IS and ISNULL terms.  (Also skip IN terms when
    ++          ** doing WHERE_ORDERBY_LIMIT processing). 
    ++          **
    ++          ** If the current term is a column of an ((?,?) IN (SELECT...)) 
    ++          ** expression for which the SELECT returns more than one column,
    ++          ** check that it is the only column used by this loop. Otherwise,
    ++          ** if it is one of two or more, none of the columns can be
    ++          ** considered to match an ORDER BY term.  */
    ++          if( (eOp & eqOpMask)!=0 ){
    ++            if( eOp & WO_ISNULL ){
    ++              testcase( isOrderDistinct );
    ++              isOrderDistinct = 0;
    ++            }
    ++            continue;  
    ++          }else if( ALWAYS(eOp & WO_IN) ){
    ++            /* ALWAYS() justification: eOp is an equality operator due to the
    ++            ** j<pLoop->u.btree.nEq constraint above.  Any equality other
    ++            ** than WO_IN is captured by the previous "if".  So this one
    ++            ** always has to be WO_IN. */
    ++            Expr *pX = pLoop->aLTerm[j]->pExpr;
    ++            for(i=j+1; i<pLoop->u.btree.nEq; i++){
    ++              if( pLoop->aLTerm[i]->pExpr==pX ){
    ++                assert( (pLoop->aLTerm[i]->eOperator & WO_IN) );
    ++                bOnce = 0;
    ++                break;
    ++              }
    ++            }
    +           }
    +-          continue;  
    +         }
    + 
    +         /* Get the column number in the table (iColumn) and sort order
    +@@ -124656,7 +136605,7 @@ static i8 wherePathSatisfiesOrderBy(
    +         if( pIndex ){
    +           iColumn = pIndex->aiColumn[j];
    +           revIdx = pIndex->aSortOrder[j];
    +-          if( iColumn==pIndex->pTable->iPKey ) iColumn = -1;
    ++          if( iColumn==pIndex->pTable->iPKey ) iColumn = XN_ROWID;
    +         }else{
    +           iColumn = XN_ROWID;
    +           revIdx = 0;
    +@@ -124676,7 +136625,6 @@ static i8 wherePathSatisfiesOrderBy(
    +         /* Find the ORDER BY term that corresponds to the j-th column
    +         ** of the index and mark that ORDER BY term off 
    +         */
    +-        bOnce = 1;
    +         isMatch = 0;
    +         for(i=0; bOnce && i<nOrderBy; i++){
    +           if( MASKBIT(i) & obSat ) continue;
    +@@ -124684,20 +136632,21 @@ static i8 wherePathSatisfiesOrderBy(
    +           testcase( wctrlFlags & WHERE_GROUPBY );
    +           testcase( wctrlFlags & WHERE_DISTINCTBY );
    +           if( (wctrlFlags & (WHERE_GROUPBY|WHERE_DISTINCTBY))==0 ) bOnce = 0;
    +-          if( iColumn>=(-1) ){
    ++          if( iColumn>=XN_ROWID ){
    +             if( pOBExpr->op!=TK_COLUMN ) continue;
    +             if( pOBExpr->iTable!=iCur ) continue;
    +             if( pOBExpr->iColumn!=iColumn ) continue;
    +           }else{
    +-            if( sqlite3ExprCompare(pOBExpr,pIndex->aColExpr->a[j].pExpr,iCur) ){
    ++            Expr *pIdxExpr = pIndex->aColExpr->a[j].pExpr;
    ++            if( sqlite3ExprCompareSkip(pOBExpr, pIdxExpr, iCur) ){
    +               continue;
    +             }
    +           }
    +-          if( iColumn>=0 ){
    +-            pColl = sqlite3ExprCollSeq(pWInfo->pParse, pOrderBy->a[i].pExpr);
    +-            if( !pColl ) pColl = db->pDfltColl;
    ++          if( iColumn!=XN_ROWID ){
    ++            pColl = sqlite3ExprNNCollSeq(pWInfo->pParse, pOrderBy->a[i].pExpr);
    +             if( sqlite3StrICmp(pColl->zName, pIndex->azColl[j])!=0 ) continue;
    +           }
    ++          pLoop->u.btree.nIdxCol = j+1;
    +           isMatch = 1;
    +           break;
    +         }
    +@@ -124713,7 +136662,7 @@ static i8 wherePathSatisfiesOrderBy(
    +           }
    +         }
    +         if( isMatch ){
    +-          if( iColumn<0 ){
    ++          if( iColumn==XN_ROWID ){
    +             testcase( distinctColumns==0 );
    +             distinctColumns = 1;
    +           }
    +@@ -124829,15 +136778,14 @@ static LogEst whereSortingCost(
    +   LogEst rScale, rSortCost;
    +   assert( nOrderBy>0 && 66==sqlite3LogEst(100) );
    +   rScale = sqlite3LogEst((nOrderBy-nSorted)*100/nOrderBy) - 66;
    +-  rSortCost = nRow + estLog(nRow) + rScale + 16;
    ++  rSortCost = 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;
    ++  /* Multiple by log(M) where M is the number of output rows.
    ++  ** Use the LIMIT for M if it is smaller */
    ++  if( (pWInfo->wctrlFlags & WHERE_USE_LIMIT)!=0 && pWInfo->iLimit<nRow ){
    ++    nRow = pWInfo->iLimit;
    +   }
    +-
    ++  rSortCost += estLog(nRow);
    +   return rSortCost;
    + }
    + 
    +@@ -124899,8 +136847,8 @@ static int wherePathSolver(WhereInfo *pWInfo, LogEst nRowEst){
    +   /* 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;
    ++  pSpace = sqlite3DbMallocRawNN(db, nSpace);
    ++  if( pSpace==0 ) return SQLITE_NOMEM_BKPT;
    +   aTo = (WherePath*)pSpace;
    +   aFrom = aTo+mxChoice;
    +   memset(aFrom, 0, sizeof(aFrom[0]));
    +@@ -124955,6 +136903,12 @@ static int wherePathSolver(WhereInfo *pWInfo, LogEst nRowEst){
    + 
    +         if( (pWLoop->prereq & ~pFrom->maskLoop)!=0 ) continue;
    +         if( (pWLoop->maskSelf & pFrom->maskLoop)!=0 ) continue;
    ++        if( (pWLoop->wsFlags & WHERE_AUTO_INDEX)!=0 && pFrom->nRow<10 ){
    ++          /* Do not use an automatic index if the this loop is expected
    ++          ** to run less than 2 times. */
    ++          assert( 10==sqlite3LogEst(2) );
    ++          continue;
    ++        }
    +         /* At this point, pWLoop is a candidate to be the next loop. 
    +         ** Compute its cost */
    +         rUnsorted = sqlite3LogEstAdd(pWLoop->rSetup,pWLoop->rRun + pFrom->nRow);
    +@@ -124982,6 +136936,7 @@ static int wherePathSolver(WhereInfo *pWInfo, LogEst nRowEst){
    +                rUnsorted, rCost));
    +         }else{
    +           rCost = rUnsorted;
    ++          rUnsorted -= 2;  /* TUNING:  Slight bias in favor of no-sort plans */
    +         }
    + 
    +         /* Check to see if pWLoop should be added to the set of
    +@@ -125013,8 +136968,8 @@ static int wherePathSolver(WhereInfo *pWInfo, LogEst nRowEst){
    +             ** 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,
    ++              sqlite3DebugPrintf("Skip   %s cost=%-3d,%3d,%3d order=%c\n",
    ++                  wherePathName(pFrom, iLoop, pWLoop), rCost, nOut, rUnsorted,
    +                   isOrdered>=0 ? isOrdered+'0' : '?');
    +             }
    + #endif
    +@@ -125032,26 +136987,36 @@ static int wherePathSolver(WhereInfo *pWInfo, LogEst nRowEst){
    +           pTo = &aTo[jj];
    + #ifdef WHERETRACE_ENABLED /* 0x4 */
    +           if( sqlite3WhereTrace&0x4 ){
    +-            sqlite3DebugPrintf("New    %s cost=%-3d,%3d order=%c\n",
    +-                wherePathName(pFrom, iLoop, pWLoop), rCost, nOut,
    ++            sqlite3DebugPrintf("New    %s cost=%-3d,%3d,%3d order=%c\n",
    ++                wherePathName(pFrom, iLoop, pWLoop), rCost, nOut, rUnsorted,
    +                 isOrdered>=0 ? isOrdered+'0' : '?');
    +           }
    + #endif
    +         }else{
    +           /* 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
    ++          ** same set of loops and has the same isOrdered setting as the
    +           ** candidate path.  Check to see if the candidate should replace
    +-          ** pTo or if the candidate should be skipped */
    +-          if( pTo->rCost<rCost || (pTo->rCost==rCost && pTo->nRow<=nOut) ){
    ++          ** pTo or if the candidate should be skipped.
    ++          ** 
    ++          ** The conditional is an expanded vector comparison equivalent to:
    ++          **   (pTo->rCost,pTo->nRow,pTo->rUnsorted) <= (rCost,nOut,rUnsorted)
    ++          */
    ++          if( pTo->rCost<rCost 
    ++           || (pTo->rCost==rCost
    ++               && (pTo->nRow<nOut
    ++                   || (pTo->nRow==nOut && pTo->rUnsorted<=rUnsorted)
    ++                  )
    ++              )
    ++          ){
    + #ifdef WHERETRACE_ENABLED /* 0x4 */
    +             if( sqlite3WhereTrace&0x4 ){
    +               sqlite3DebugPrintf(
    +-                  "Skip   %s cost=%-3d,%3d order=%c",
    +-                  wherePathName(pFrom, iLoop, pWLoop), rCost, nOut,
    ++                  "Skip   %s cost=%-3d,%3d,%3d order=%c",
    ++                  wherePathName(pFrom, iLoop, pWLoop), rCost, nOut, rUnsorted,
    +                   isOrdered>=0 ? isOrdered+'0' : '?');
    +-              sqlite3DebugPrintf("   vs %s cost=%-3d,%d order=%c\n",
    ++              sqlite3DebugPrintf("   vs %s cost=%-3d,%3d,%3d order=%c\n",
    +                   wherePathName(pTo, iLoop+1, 0), pTo->rCost, pTo->nRow,
    +-                  pTo->isOrdered>=0 ? pTo->isOrdered+'0' : '?');
    ++                  pTo->rUnsorted, pTo->isOrdered>=0 ? pTo->isOrdered+'0' : '?');
    +             }
    + #endif
    +             /* Discard the candidate path from further consideration */
    +@@ -125064,12 +137029,12 @@ static int wherePathSolver(WhereInfo *pWInfo, LogEst nRowEst){
    + #ifdef WHERETRACE_ENABLED /* 0x4 */
    +           if( sqlite3WhereTrace&0x4 ){
    +             sqlite3DebugPrintf(
    +-                "Update %s cost=%-3d,%3d order=%c",
    +-                wherePathName(pFrom, iLoop, pWLoop), rCost, nOut,
    ++                "Update %s cost=%-3d,%3d,%3d order=%c",
    ++                wherePathName(pFrom, iLoop, pWLoop), rCost, nOut, rUnsorted,
    +                 isOrdered>=0 ? isOrdered+'0' : '?');
    +-            sqlite3DebugPrintf("  was %s cost=%-3d,%3d order=%c\n",
    ++            sqlite3DebugPrintf("  was %s cost=%-3d,%3d,%3d order=%c\n",
    +                 wherePathName(pTo, iLoop+1, 0), pTo->rCost, pTo->nRow,
    +-                pTo->isOrdered>=0 ? pTo->isOrdered+'0' : '?');
    ++                pTo->rUnsorted, pTo->isOrdered>=0 ? pTo->isOrdered+'0' : '?');
    +           }
    + #endif
    +         }
    +@@ -125124,7 +137089,7 @@ static int wherePathSolver(WhereInfo *pWInfo, LogEst nRowEst){
    + 
    +   if( nFrom==0 ){
    +     sqlite3ErrorMsg(pParse, "no query solution");
    +-    sqlite3DbFree(db, pSpace);
    ++    sqlite3DbFreeNN(db, pSpace);
    +     return SQLITE_ERROR;
    +   }
    +   
    +@@ -125160,8 +137125,26 @@ static int wherePathSolver(WhereInfo *pWInfo, LogEst nRowEst){
    +       }
    +     }else{
    +       pWInfo->nOBSat = pFrom->isOrdered;
    +-      if( pWInfo->nOBSat<0 ) pWInfo->nOBSat = 0;
    +       pWInfo->revMask = pFrom->revLoop;
    ++      if( pWInfo->nOBSat<=0 ){
    ++        pWInfo->nOBSat = 0;
    ++        if( nLoop>0 ){
    ++          u32 wsFlags = pFrom->aLoop[nLoop-1]->wsFlags;
    ++          if( (wsFlags & WHERE_ONEROW)==0 
    ++           && (wsFlags&(WHERE_IPK|WHERE_COLUMN_IN))!=(WHERE_IPK|WHERE_COLUMN_IN)
    ++          ){
    ++            Bitmask m = 0;
    ++            int rc = wherePathSatisfiesOrderBy(pWInfo, pWInfo->pOrderBy, pFrom,
    ++                      WHERE_ORDERBY_LIMIT, nLoop-1, pFrom->aLoop[nLoop-1], &m);
    ++            testcase( wsFlags & WHERE_IPK );
    ++            testcase( wsFlags & WHERE_COLUMN_IN );
    ++            if( rc==pWInfo->pOrderBy->nExpr ){
    ++              pWInfo->bOrderedInnerLoop = 1;
    ++              pWInfo->revMask = m;
    ++            }
    ++          }
    ++        }
    ++      }
    +     }
    +     if( (pWInfo->wctrlFlags & WHERE_SORTBYGROUP)
    +         && pWInfo->nOBSat==pWInfo->pOrderBy->nExpr && nLoop>0
    +@@ -125182,7 +137165,7 @@ static int wherePathSolver(WhereInfo *pWInfo, LogEst nRowEst){
    +   pWInfo->nRowOut = pFrom->nRow;
    + 
    +   /* Free temporary memory and return success */
    +-  sqlite3DbFree(db, pSpace);
    ++  sqlite3DbFreeNN(db, pSpace);
    +   return SQLITE_OK;
    + }
    + 
    +@@ -125207,9 +137190,9 @@ static int whereShortCut(WhereLoopBuilder *pBuilder){
    +   int j;
    +   Table *pTab;
    +   Index *pIdx;
    +-  
    ++
    +   pWInfo = pBuilder->pWInfo;
    +-  if( pWInfo->wctrlFlags & WHERE_FORCE_TABLE ) return 0;
    ++  if( pWInfo->wctrlFlags & WHERE_OR_SUBCLAUSE ) return 0;
    +   assert( pWInfo->pTabList->nSrc>=1 );
    +   pItem = pWInfo->pTabList->a;
    +   pTab = pItem->pTab;
    +@@ -125260,7 +137243,8 @@ static int whereShortCut(WhereLoopBuilder *pBuilder){
    +   if( pLoop->wsFlags ){
    +     pLoop->nOut = (LogEst)1;
    +     pWInfo->a[0].pWLoop = pLoop;
    +-    pLoop->maskSelf = sqlite3WhereGetMask(&pWInfo->sMaskSet, iCur);
    ++    assert( pWInfo->sMaskSet.n==1 && iCur==pWInfo->sMaskSet.ix[0] );
    ++    pLoop->maskSelf = 1; /* sqlite3WhereGetMask(&pWInfo->sMaskSet, iCur); */
    +     pWInfo->a[0].iTabCur = iCur;
    +     pWInfo->nRowOut = 1;
    +     if( pWInfo->pOrderBy ) pWInfo->nOBSat =  pWInfo->pOrderBy->nExpr;
    +@@ -125275,6 +137259,32 @@ static int whereShortCut(WhereLoopBuilder *pBuilder){
    +   return 0;
    + }
    + 
    ++/*
    ++** Helper function for exprIsDeterministic().
    ++*/
    ++static int exprNodeIsDeterministic(Walker *pWalker, Expr *pExpr){
    ++  if( pExpr->op==TK_FUNCTION && ExprHasProperty(pExpr, EP_ConstFunc)==0 ){
    ++    pWalker->eCode = 0;
    ++    return WRC_Abort;
    ++  }
    ++  return WRC_Continue;
    ++}
    ++
    ++/*
    ++** Return true if the expression contains no non-deterministic SQL 
    ++** functions. Do not consider non-deterministic SQL functions that are 
    ++** part of sub-select statements.
    ++*/
    ++static int exprIsDeterministic(Expr *p){
    ++  Walker w;
    ++  memset(&w, 0, sizeof(w));
    ++  w.eCode = 1;
    ++  w.xExprCallback = exprNodeIsDeterministic;
    ++  w.xSelectCallback = sqlite3SelectWalkFail;
    ++  sqlite3WalkExpr(&w, p);
    ++  return w.eCode;
    ++}
    ++
    + /*
    + ** Generate the beginning of the loop used for WHERE clause processing.
    + ** The return value is a pointer to an opaque structure that contains
    +@@ -125356,7 +137366,7 @@ static int whereShortCut(WhereLoopBuilder *pBuilder){
    + ** is called from an UPDATE or DELETE statement, then pOrderBy is NULL.
    + **
    + ** The iIdxCur parameter is the cursor number of an index.  If 
    +-** WHERE_ONETABLE_ONLY is set, iIdxCur is the cursor number of an index
    ++** WHERE_OR_SUBCLAUSE is set, iIdxCur is the cursor number of an index
    + ** to use for OR clause processing.  The WHERE clause should use this
    + ** specific cursor.  If WHERE_ONEPASS_DESIRED is set, then iIdxCur is
    + ** the first cursor in an array of cursors for all indices.  iIdxCur should
    +@@ -125364,13 +137374,14 @@ static int whereShortCut(WhereLoopBuilder *pBuilder){
    + ** used.
    + */
    + 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 (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 */
    ++  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 (or GROUP BY) clause, or NULL */
    ++  ExprList *pResultSet,   /* Query result set.  Req'd for DISTINCT */
    ++  u16 wctrlFlags,         /* The WHERE_* flags defined in sqliteInt.h */
    ++  int iAuxArg             /* If WHERE_OR_SUBCLAUSE is set, index cursor number
    ++                          ** If WHERE_USE_LIMIT, then the limit amount */
    + ){
    +   int nByteWInfo;            /* Num. bytes allocated for WhereInfo struct */
    +   int nTabList;              /* Number of elements in pTabList */
    +@@ -125384,12 +137395,17 @@ SQLITE_PRIVATE WhereInfo *sqlite3WhereBegin(
    +   int ii;                    /* Loop counter */
    +   sqlite3 *db;               /* Database connection */
    +   int rc;                    /* Return code */
    ++  u8 bFordelete = 0;         /* OPFLAG_FORDELETE or zero, as appropriate */
    + 
    +   assert( (wctrlFlags & WHERE_ONEPASS_MULTIROW)==0 || (
    +         (wctrlFlags & WHERE_ONEPASS_DESIRED)!=0 
    +-     && (wctrlFlags & WHERE_OMIT_OPEN_CLOSE)==0 
    ++     && (wctrlFlags & WHERE_OR_SUBCLAUSE)==0 
    +   ));
    + 
    ++  /* Only one of WHERE_OR_SUBCLAUSE or WHERE_USE_LIMIT */
    ++  assert( (wctrlFlags & WHERE_OR_SUBCLAUSE)==0
    ++            || (wctrlFlags & WHERE_USE_LIMIT)==0 );
    ++
    +   /* Variable initialization */
    +   db = pParse->db;
    +   memset(&sWLB, 0, sizeof(sWLB));
    +@@ -125415,11 +137431,11 @@ SQLITE_PRIVATE WhereInfo *sqlite3WhereBegin(
    +   }
    + 
    +   /* This function normally generates a nested loop for all tables in 
    +-  ** pTabList.  But if the WHERE_ONETABLE_ONLY flag is set, then we should
    ++  ** pTabList.  But if the WHERE_OR_SUBCLAUSE flag is set, then we should
    +   ** only generate code for the first table in pTabList and assume that
    +   ** any cursors associated with subsequent tables are uninitialized.
    +   */
    +-  nTabList = (wctrlFlags & WHERE_ONETABLE_ONLY) ? 1 : pTabList->nSrc;
    ++  nTabList = (wctrlFlags & WHERE_OR_SUBCLAUSE) ? 1 : pTabList->nSrc;
    + 
    +   /* Allocate and initialize the WhereInfo structure that will become the
    +   ** return value. A single allocation is used to store the WhereInfo
    +@@ -125429,21 +137445,26 @@ SQLITE_PRIVATE WhereInfo *sqlite3WhereBegin(
    +   ** some architectures. Hence the ROUND8() below.
    +   */
    +   nByteWInfo = ROUND8(sizeof(WhereInfo)+(nTabList-1)*sizeof(WhereLevel));
    +-  pWInfo = sqlite3DbMallocZero(db, nByteWInfo + sizeof(WhereLoop));
    ++  pWInfo = sqlite3DbMallocRawNN(db, nByteWInfo + sizeof(WhereLoop));
    +   if( db->mallocFailed ){
    +     sqlite3DbFree(db, pWInfo);
    +     pWInfo = 0;
    +     goto whereBeginError;
    +   }
    +-  pWInfo->aiCurOnePass[0] = pWInfo->aiCurOnePass[1] = -1;
    +-  pWInfo->nLevel = nTabList;
    +   pWInfo->pParse = pParse;
    +   pWInfo->pTabList = pTabList;
    +   pWInfo->pOrderBy = pOrderBy;
    ++  pWInfo->pWhere = pWhere;
    +   pWInfo->pResultSet = pResultSet;
    ++  pWInfo->aiCurOnePass[0] = pWInfo->aiCurOnePass[1] = -1;
    ++  pWInfo->nLevel = nTabList;
    +   pWInfo->iBreak = pWInfo->iContinue = sqlite3VdbeMakeLabel(v);
    +   pWInfo->wctrlFlags = wctrlFlags;
    ++  pWInfo->iLimit = iAuxArg;
    +   pWInfo->savedNQueryLoop = pParse->nQueryLoop;
    ++  memset(&pWInfo->nOBSat, 0, 
    ++         offsetof(WhereInfo,sWC) - offsetof(WhereInfo,nOBSat));
    ++  memset(&pWInfo->a[0], 0, sizeof(WhereLoop)+nTabList*sizeof(WhereLevel));
    +   assert( pWInfo->eOnePass==ONEPASS_OFF );  /* ONEPASS defaults to OFF */
    +   pMaskSet = &pWInfo->sMaskSet;
    +   sWLB.pWInfo = pWInfo;
    +@@ -125462,17 +137483,6 @@ SQLITE_PRIVATE WhereInfo *sqlite3WhereBegin(
    +   sqlite3WhereClauseInit(&pWInfo->sWC, pWInfo);
    +   sqlite3WhereSplit(&pWInfo->sWC, pWhere, TK_AND);
    +     
    +-  /* Special case: a WHERE clause that is constant.  Evaluate the
    +-  ** expression and either jump over all of the code or fall thru.
    +-  */
    +-  for(ii=0; ii<sWLB.pWC->nTerm; ii++){
    +-    if( nTabList==0 || sqlite3ExprIsConstantNotJoin(sWLB.pWC->a[ii].pExpr) ){
    +-      sqlite3ExprIfFalse(pParse, sWLB.pWC->a[ii].pExpr, pWInfo->iBreak,
    +-                         SQLITE_JUMPIFNULL);
    +-      sWLB.pWC->a[ii].wtFlags |= TERM_CODED;
    +-    }
    +-  }
    +-
    +   /* Special case: No FROM clause
    +   */
    +   if( nTabList==0 ){
    +@@ -125480,36 +137490,60 @@ SQLITE_PRIVATE WhereInfo *sqlite3WhereBegin(
    +     if( wctrlFlags & WHERE_WANT_DISTINCT ){
    +       pWInfo->eDistinct = WHERE_DISTINCT_UNIQUE;
    +     }
    ++  }else{
    ++    /* Assign a bit from the bitmask to every term in the FROM clause.
    ++    **
    ++    ** The N-th term of the FROM clause is assigned a bitmask of 1<<N.
    ++    **
    ++    ** The rule of the previous sentence ensures thta if X is the bitmask for
    ++    ** a table T, then X-1 is the bitmask for all other tables to the left of T.
    ++    ** Knowing the bitmask for all tables to the left of a left join is
    ++    ** important.  Ticket #3015.
    ++    **
    ++    ** Note that bitmasks are created for all pTabList->nSrc tables in
    ++    ** pTabList, not just the first nTabList tables.  nTabList is normally
    ++    ** equal to pTabList->nSrc but might be shortened to 1 if the
    ++    ** WHERE_OR_SUBCLAUSE flag is set.
    ++    */
    ++    ii = 0;
    ++    do{
    ++      createMask(pMaskSet, pTabList->a[ii].iCursor);
    ++      sqlite3WhereTabFuncArgs(pParse, &pTabList->a[ii], &pWInfo->sWC);
    ++    }while( (++ii)<pTabList->nSrc );
    ++  #ifdef SQLITE_DEBUG
    ++    {
    ++      Bitmask mx = 0;
    ++      for(ii=0; ii<pTabList->nSrc; ii++){
    ++        Bitmask m = sqlite3WhereGetMask(pMaskSet, pTabList->a[ii].iCursor);
    ++        assert( m>=mx );
    ++        mx = m;
    ++      }
    ++    }
    ++  #endif
    +   }
    ++  
    ++  /* Analyze all of the subexpressions. */
    ++  sqlite3WhereExprAnalyze(pTabList, &pWInfo->sWC);
    ++  if( db->mallocFailed ) goto whereBeginError;
    + 
    +-  /* Assign a bit from the bitmask to every term in the FROM clause.
    +-  **
    +-  ** The N-th term of the FROM clause is assigned a bitmask of 1<<N.
    ++  /* Special case: WHERE terms that do not refer to any tables in the join
    ++  ** (constant expressions). Evaluate each such term, and jump over all the
    ++  ** generated code if the result is not true.  
    +   **
    +-  ** The rule of the previous sentence ensures thta if X is the bitmask for
    +-  ** a table T, then X-1 is the bitmask for all other tables to the left of T.
    +-  ** Knowing the bitmask for all tables to the left of a left join is
    +-  ** important.  Ticket #3015.
    ++  ** Do not do this if the expression contains non-deterministic functions
    ++  ** that are not within a sub-select. This is not strictly required, but
    ++  ** preserves SQLite's legacy behaviour in the following two cases:
    +   **
    +-  ** Note that bitmasks are created for all pTabList->nSrc tables in
    +-  ** pTabList, not just the first nTabList tables.  nTabList is normally
    +-  ** equal to pTabList->nSrc but might be shortened to 1 if the
    +-  ** WHERE_ONETABLE_ONLY flag is set.
    ++  **   FROM ... WHERE random()>0;           -- eval random() once per row
    ++  **   FROM ... WHERE (SELECT random())>0;  -- eval random() once overall
    +   */
    +-  for(ii=0; ii<pTabList->nSrc; ii++){
    +-    createMask(pMaskSet, pTabList->a[ii].iCursor);
    +-    sqlite3WhereTabFuncArgs(pParse, &pTabList->a[ii], &pWInfo->sWC);
    +-  }
    +-#ifdef SQLITE_DEBUG
    +-  for(ii=0; ii<pTabList->nSrc; ii++){
    +-    Bitmask m = sqlite3WhereGetMask(pMaskSet, pTabList->a[ii].iCursor);
    +-    assert( m==MASKBIT(ii) );
    ++  for(ii=0; ii<sWLB.pWC->nTerm; ii++){
    ++    WhereTerm *pT = &sWLB.pWC->a[ii];
    ++    if( pT->prereqAll==0 && (nTabList==0 || exprIsDeterministic(pT->pExpr)) ){
    ++      sqlite3ExprIfFalse(pParse, pT->pExpr, pWInfo->iBreak, SQLITE_JUMPIFNULL);
    ++      pT->wtFlags |= TERM_CODED;
    ++    }
    +   }
    +-#endif
    +-
    +-  /* Analyze all of the subexpressions. */
    +-  sqlite3WhereExprAnalyze(pTabList, &pWInfo->sWC);
    +-  if( db->mallocFailed ) goto whereBeginError;
    + 
    +   if( wctrlFlags & WHERE_WANT_DISTINCT ){
    +     if( isDistinctRedundant(pParse, pTabList, &pWInfo->sWC, pResultSet) ){
    +@@ -125523,14 +137557,16 @@ SQLITE_PRIVATE WhereInfo *sqlite3WhereBegin(
    +   }
    + 
    +   /* Construct the WhereLoop objects */
    +-  WHERETRACE(0xffff,("*** Optimizer Start *** (wctrlFlags: 0x%x)\n",
    +-             wctrlFlags));
    + #if defined(WHERETRACE_ENABLED)
    +-  if( sqlite3WhereTrace & 0x100 ){ /* Display all terms of the WHERE clause */
    +-    int i;
    +-    for(i=0; i<sWLB.pWC->nTerm; i++){
    +-      whereTermPrint(&sWLB.pWC->a[i], i);
    ++  if( sqlite3WhereTrace & 0xffff ){
    ++    sqlite3DebugPrintf("*** Optimizer Start *** (wctrlFlags: 0x%x",wctrlFlags);
    ++    if( wctrlFlags & WHERE_USE_LIMIT ){
    ++      sqlite3DebugPrintf(", limit: %d", iAuxArg);
    +     }
    ++    sqlite3DebugPrintf(")\n");
    ++  }
    ++  if( sqlite3WhereTrace & 0x100 ){ /* Display all terms of the WHERE clause */
    ++    sqlite3WhereClausePrint(sWLB.pWC);
    +   }
    + #endif
    + 
    +@@ -125545,7 +137581,7 @@ SQLITE_PRIVATE WhereInfo *sqlite3WhereBegin(
    +       static const char zLabel[] = "0123456789abcdefghijklmnopqrstuvwyxz"
    +                                              "ABCDEFGHIJKLMNOPQRSTUVWYXZ";
    +       for(p=pWInfo->pLoops, i=0; p; p=p->pNextLoop, i++){
    +-        p->cId = zLabel[i%sizeof(zLabel)];
    ++        p->cId = zLabel[i%(sizeof(zLabel)-1)];
    +         whereLoopPrint(p, sWLB.pWC);
    +       }
    +     }
    +@@ -125559,7 +137595,7 @@ SQLITE_PRIVATE WhereInfo *sqlite3WhereBegin(
    +     }
    +   }
    +   if( pWInfo->pOrderBy==0 && (db->flags & SQLITE_ReverseOrder)!=0 ){
    +-     pWInfo->revMask = (Bitmask)(-1);
    ++     pWInfo->revMask = ALLBITS;
    +   }
    +   if( pParse->nErr || NEVER(db->mallocFailed) ){
    +     goto whereBeginError;
    +@@ -125590,35 +137626,80 @@ SQLITE_PRIVATE WhereInfo *sqlite3WhereBegin(
    +     }
    +   }
    + #endif
    +-  /* Attempt to omit tables from the join that do not effect the result */
    ++
    ++  /* Attempt to omit tables from the join that do not affect the result.
    ++  ** For a table to not affect the result, the following must be true:
    ++  **
    ++  **   1) The query must not be an aggregate.
    ++  **   2) The table must be the RHS of a LEFT JOIN.
    ++  **   3) Either the query must be DISTINCT, or else the ON or USING clause
    ++  **      must contain a constraint that limits the scan of the table to 
    ++  **      at most a single row.
    ++  **   4) The table must not be referenced by any part of the query apart
    ++  **      from its own USING or ON clause.
    ++  **
    ++  ** For example, given:
    ++  **
    ++  **     CREATE TABLE t1(ipk INTEGER PRIMARY KEY, v1);
    ++  **     CREATE TABLE t2(ipk INTEGER PRIMARY KEY, v2);
    ++  **     CREATE TABLE t3(ipk INTEGER PRIMARY KEY, v3);
    ++  **
    ++  ** then table t2 can be omitted from the following:
    ++  **
    ++  **     SELECT v1, v3 FROM t1 
    ++  **       LEFT JOIN t2 USING (t1.ipk=t2.ipk)
    ++  **       LEFT JOIN t3 USING (t1.ipk=t3.ipk)
    ++  **
    ++  ** or from:
    ++  **
    ++  **     SELECT DISTINCT v1, v3 FROM t1 
    ++  **       LEFT JOIN t2
    ++  **       LEFT JOIN t3 USING (t1.ipk=t3.ipk)
    ++  */
    ++  notReady = ~(Bitmask)0;
    +   if( pWInfo->nLevel>=2
    +-   && pResultSet!=0
    ++   && pResultSet!=0               /* guarantees condition (1) above */
    +    && OptimizationEnabled(db, SQLITE_OmitNoopJoin)
    +   ){
    ++    int i;
    +     Bitmask tabUsed = sqlite3WhereExprListUsage(pMaskSet, pResultSet);
    +     if( sWLB.pOrderBy ){
    +       tabUsed |= sqlite3WhereExprListUsage(pMaskSet, sWLB.pOrderBy);
    +     }
    +-    while( pWInfo->nLevel>=2 ){
    ++    for(i=pWInfo->nLevel-1; i>=1; i--){
    +       WhereTerm *pTerm, *pEnd;
    +-      pLoop = pWInfo->a[pWInfo->nLevel-1].pWLoop;
    +-      if( (pWInfo->pTabList->a[pLoop->iTab].fg.jointype & JT_LEFT)==0 ) break;
    ++      struct SrcList_item *pItem;
    ++      pLoop = pWInfo->a[i].pWLoop;
    ++      pItem = &pWInfo->pTabList->a[pLoop->iTab];
    ++      if( (pItem->fg.jointype & JT_LEFT)==0 ) continue;
    +       if( (wctrlFlags & WHERE_WANT_DISTINCT)==0
    +        && (pLoop->wsFlags & WHERE_ONEROW)==0
    +       ){
    +-        break;
    ++        continue;
    +       }
    +-      if( (tabUsed & pLoop->maskSelf)!=0 ) break;
    ++      if( (tabUsed & pLoop->maskSelf)!=0 ) continue;
    +       pEnd = sWLB.pWC->a + sWLB.pWC->nTerm;
    +       for(pTerm=sWLB.pWC->a; pTerm<pEnd; pTerm++){
    +-        if( (pTerm->prereqAll & pLoop->maskSelf)!=0
    +-         && !ExprHasProperty(pTerm->pExpr, EP_FromJoin)
    +-        ){
    +-          break;
    ++        if( (pTerm->prereqAll & pLoop->maskSelf)!=0 ){
    ++          if( !ExprHasProperty(pTerm->pExpr, EP_FromJoin)
    ++           || pTerm->pExpr->iRightJoinTable!=pItem->iCursor
    ++          ){
    ++            break;
    ++          }
    +         }
    +       }
    +-      if( pTerm<pEnd ) break;
    ++      if( pTerm<pEnd ) continue;
    +       WHERETRACE(0xffff, ("-> drop loop %c not used\n", pLoop->cId));
    ++      notReady &= ~pLoop->maskSelf;
    ++      for(pTerm=sWLB.pWC->a; pTerm<pEnd; pTerm++){
    ++        if( (pTerm->prereqAll & pLoop->maskSelf)!=0 ){
    ++          pTerm->wtFlags |= TERM_CODED;
    ++        }
    ++      }
    ++      if( i!=pWInfo->nLevel-1 ){
    ++        int nByte = (pWInfo->nLevel-1-i) * sizeof(WhereLevel);
    ++        memmove(&pWInfo->a[i], &pWInfo->a[i+1], nByte);
    ++      }
    +       pWInfo->nLevel--;
    +       nTabList--;
    +     }
    +@@ -125628,19 +137709,38 @@ SQLITE_PRIVATE WhereInfo *sqlite3WhereBegin(
    + 
    +   /* If the caller is an UPDATE or DELETE statement that is requesting
    +   ** to use a one-pass algorithm, determine if this is appropriate.
    +-  ** The one-pass algorithm only works if the WHERE clause constrains
    +-  ** the statement to update or delete a single row.
    ++  **
    ++  ** A one-pass approach can be used if the caller has requested one
    ++  ** and either (a) the scan visits at most one row or (b) each
    ++  ** of the following are true:
    ++  **
    ++  **   * the caller has indicated that a one-pass approach can be used
    ++  **     with multiple rows (by setting WHERE_ONEPASS_MULTIROW), and
    ++  **   * the table is not a virtual table, and
    ++  **   * either the scan does not use the OR optimization or the caller
    ++  **     is a DELETE operation (WHERE_DUPLICATES_OK is only specified
    ++  **     for DELETE).
    ++  **
    ++  ** The last qualification is because an UPDATE statement uses
    ++  ** WhereInfo.aiCurOnePass[1] to determine whether or not it really can
    ++  ** use a one-pass approach, and this is not set accurately for scans
    ++  ** that use the OR optimization.
    +   */
    +   assert( (wctrlFlags & WHERE_ONEPASS_DESIRED)==0 || pWInfo->nLevel==1 );
    +   if( (wctrlFlags & WHERE_ONEPASS_DESIRED)!=0 ){
    +     int wsFlags = pWInfo->a[0].pWLoop->wsFlags;
    +     int bOnerow = (wsFlags & WHERE_ONEROW)!=0;
    +-    if( bOnerow || ( (wctrlFlags & WHERE_ONEPASS_MULTIROW)
    +-       && 0==(wsFlags & WHERE_VIRTUALTABLE)
    ++    if( bOnerow || (
    ++        0!=(wctrlFlags & WHERE_ONEPASS_MULTIROW)
    ++     && 0==(wsFlags & WHERE_VIRTUALTABLE)
    ++     && (0==(wsFlags & WHERE_MULTI_OR) || (wctrlFlags & WHERE_DUPLICATES_OK))
    +     )){
    +       pWInfo->eOnePass = bOnerow ? ONEPASS_SINGLE : ONEPASS_MULTI;
    +-      if( HasRowid(pTabList->a[0].pTab) ){
    +-        pWInfo->a[0].pWLoop->wsFlags &= ~WHERE_IDX_ONLY;
    ++      if( HasRowid(pTabList->a[0].pTab) && (wsFlags & WHERE_IDX_ONLY) ){
    ++        if( wctrlFlags & WHERE_ONEPASS_MULTIROW ){
    ++          bFordelete = OPFLAG_FORDELETE;
    ++        }
    ++        pWInfo->a[0].pWLoop->wsFlags = (wsFlags & ~WHERE_IDX_ONLY);
    +       }
    +     }
    +   }
    +@@ -125670,7 +137770,7 @@ SQLITE_PRIVATE WhereInfo *sqlite3WhereBegin(
    +     }else
    + #endif
    +     if( (pLoop->wsFlags & WHERE_IDX_ONLY)==0
    +-         && (wctrlFlags & WHERE_OMIT_OPEN_CLOSE)==0 ){
    ++         && (wctrlFlags & WHERE_OR_SUBCLAUSE)==0 ){
    +       int op = OP_OpenRead;
    +       if( pWInfo->eOnePass!=ONEPASS_OFF ){
    +         op = OP_OpenWrite;
    +@@ -125684,10 +137784,17 @@ SQLITE_PRIVATE WhereInfo *sqlite3WhereBegin(
    +         Bitmask b = pTabItem->colUsed;
    +         int n = 0;
    +         for(; b; b=b>>1, n++){}
    +-        sqlite3VdbeChangeP4(v, sqlite3VdbeCurrentAddr(v)-1, 
    +-                            SQLITE_INT_TO_PTR(n), P4_INT32);
    ++        sqlite3VdbeChangeP4(v, -1, SQLITE_INT_TO_PTR(n), P4_INT32);
    +         assert( n<=pTab->nCol );
    +       }
    ++#ifdef SQLITE_ENABLE_CURSOR_HINTS
    ++      if( pLoop->u.btree.pIndex!=0 ){
    ++        sqlite3VdbeChangeP5(v, OPFLAG_SEEKEQ|bFordelete);
    ++      }else
    ++#endif
    ++      {
    ++        sqlite3VdbeChangeP5(v, bFordelete);
    ++      }
    + #ifdef SQLITE_ENABLE_COLUMN_USED_MASK
    +       sqlite3VdbeAddOp4Dup8(v, OP_ColumnsUsed, pTabItem->iCursor, 0, 0,
    +                             (const u8*)&pTabItem->colUsed, P4_INT64);
    +@@ -125699,10 +137806,10 @@ SQLITE_PRIVATE WhereInfo *sqlite3WhereBegin(
    +       Index *pIx = pLoop->u.btree.pIndex;
    +       int iIndexCur;
    +       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 );
    ++      /* iAuxArg is always set to a positive value if ONEPASS is possible */
    ++      assert( iAuxArg!=0 || (pWInfo->wctrlFlags & WHERE_ONEPASS_DESIRED)==0 );
    +       if( !HasRowid(pTab) && IsPrimaryKeyIndex(pIx)
    +-       && (wctrlFlags & WHERE_ONETABLE_ONLY)!=0
    ++       && (wctrlFlags & WHERE_OR_SUBCLAUSE)!=0
    +       ){
    +         /* This is one term of an OR-optimization using the PRIMARY KEY of a
    +         ** WITHOUT ROWID table.  No need for a separate index */
    +@@ -125710,7 +137817,7 @@ SQLITE_PRIVATE WhereInfo *sqlite3WhereBegin(
    +         op = 0;
    +       }else if( pWInfo->eOnePass!=ONEPASS_OFF ){
    +         Index *pJ = pTabItem->pTab->pIndex;
    +-        iIndexCur = iIdxCur;
    ++        iIndexCur = iAuxArg;
    +         assert( wctrlFlags & WHERE_ONEPASS_DESIRED );
    +         while( ALWAYS(pJ) && pJ!=pIx ){
    +           iIndexCur++;
    +@@ -125718,9 +137825,9 @@ SQLITE_PRIVATE WhereInfo *sqlite3WhereBegin(
    +         }
    +         op = OP_OpenWrite;
    +         pWInfo->aiCurOnePass[1] = iIndexCur;
    +-      }else if( iIdxCur && (wctrlFlags & WHERE_ONETABLE_ONLY)!=0 ){
    +-        iIndexCur = iIdxCur;
    +-        if( wctrlFlags & WHERE_REOPEN_IDX ) op = OP_ReopenIdx;
    ++      }else if( iAuxArg && (wctrlFlags & WHERE_OR_SUBCLAUSE)!=0 ){
    ++        iIndexCur = iAuxArg;
    ++        op = OP_ReopenIdx;
    +       }else{
    +         iIndexCur = pParse->nTab++;
    +       }
    +@@ -125733,6 +137840,7 @@ SQLITE_PRIVATE WhereInfo *sqlite3WhereBegin(
    +         if( (pLoop->wsFlags & WHERE_CONSTRAINT)!=0
    +          && (pLoop->wsFlags & (WHERE_COLUMN_RANGE|WHERE_SKIPSCAN))==0
    +          && (pWInfo->wctrlFlags&WHERE_ORDERBY_MIN)==0
    ++         && pWInfo->eDistinct!=WHERE_DISTINCT_ORDERED
    +         ){
    +           sqlite3VdbeChangeP5(v, OPFLAG_SEEKEQ); /* Hint to COMDB2 */
    +         }
    +@@ -125763,7 +137871,6 @@ SQLITE_PRIVATE WhereInfo *sqlite3WhereBegin(
    +   ** loop below generates code for a single nested loop of the VM
    +   ** program.
    +   */
    +-  notReady = ~(Bitmask)0;
    +   for(ii=0; ii<nTabList; ii++){
    +     int addrExplain;
    +     int wsFlags;
    +@@ -125782,7 +137889,7 @@ SQLITE_PRIVATE WhereInfo *sqlite3WhereBegin(
    +     pLevel->addrBody = sqlite3VdbeCurrentAddr(v);
    +     notReady = sqlite3WhereCodeOneLoopStart(pWInfo, ii, notReady);
    +     pWInfo->iContinue = pLevel->addrCont;
    +-    if( (wsFlags&WHERE_MULTI_OR)==0 && (wctrlFlags&WHERE_ONETABLE_ONLY)==0 ){
    ++    if( (wsFlags&WHERE_MULTI_OR)==0 && (wctrlFlags&WHERE_OR_SUBCLAUSE)==0 ){
    +       sqlite3WhereAddScanStatus(v, pTabList, pLevel, addrExplain);
    +     }
    +   }
    +@@ -125821,14 +137928,44 @@ SQLITE_PRIVATE void sqlite3WhereEnd(WhereInfo *pWInfo){
    +     int addr;
    +     pLevel = &pWInfo->a[i];
    +     pLoop = pLevel->pWLoop;
    +-    sqlite3VdbeResolveLabel(v, pLevel->addrCont);
    +     if( pLevel->op!=OP_Noop ){
    ++#ifndef SQLITE_DISABLE_SKIPAHEAD_DISTINCT
    ++      int addrSeek = 0;
    ++      Index *pIdx;
    ++      int n;
    ++      if( pWInfo->eDistinct==WHERE_DISTINCT_ORDERED
    ++       && i==pWInfo->nLevel-1  /* Ticket [ef9318757b152e3] 2017-10-21 */
    ++       && (pLoop->wsFlags & WHERE_INDEXED)!=0
    ++       && (pIdx = pLoop->u.btree.pIndex)->hasStat1
    ++       && (n = pLoop->u.btree.nIdxCol)>0
    ++       && pIdx->aiRowLogEst[n]>=36
    ++      ){
    ++        int r1 = pParse->nMem+1;
    ++        int j, op;
    ++        for(j=0; j<n; j++){
    ++          sqlite3VdbeAddOp3(v, OP_Column, pLevel->iIdxCur, j, r1+j);
    ++        }
    ++        pParse->nMem += n+1;
    ++        op = pLevel->op==OP_Prev ? OP_SeekLT : OP_SeekGT;
    ++        addrSeek = sqlite3VdbeAddOp4Int(v, op, pLevel->iIdxCur, 0, r1, n);
    ++        VdbeCoverageIf(v, op==OP_SeekLT);
    ++        VdbeCoverageIf(v, op==OP_SeekGT);
    ++        sqlite3VdbeAddOp2(v, OP_Goto, 1, pLevel->p2);
    ++      }
    ++#endif /* SQLITE_DISABLE_SKIPAHEAD_DISTINCT */
    ++      /* The common case: Advance to the next row */
    ++      sqlite3VdbeResolveLabel(v, pLevel->addrCont);
    +       sqlite3VdbeAddOp3(v, pLevel->op, pLevel->p1, pLevel->p2, pLevel->p3);
    +       sqlite3VdbeChangeP5(v, pLevel->p5);
    +       VdbeCoverage(v);
    +       VdbeCoverageIf(v, pLevel->op==OP_Next);
    +       VdbeCoverageIf(v, pLevel->op==OP_Prev);
    +       VdbeCoverageIf(v, pLevel->op==OP_VNext);
    ++#ifndef SQLITE_DISABLE_SKIPAHEAD_DISTINCT
    ++      if( addrSeek ) sqlite3VdbeJumpHere(v, addrSeek);
    ++#endif
    ++    }else{
    ++      sqlite3VdbeResolveLabel(v, pLevel->addrCont);
    +     }
    +     if( pLoop->wsFlags & WHERE_IN_ABLE && pLevel->u.in.nIn>0 ){
    +       struct InLoop *pIn;
    +@@ -125836,10 +137973,12 @@ SQLITE_PRIVATE void sqlite3WhereEnd(WhereInfo *pWInfo){
    +       sqlite3VdbeResolveLabel(v, pLevel->addrNxt);
    +       for(j=pLevel->u.in.nIn, pIn=&pLevel->u.in.aInLoop[j-1]; j>0; j--, pIn--){
    +         sqlite3VdbeJumpHere(v, pIn->addrInTop+1);
    +-        sqlite3VdbeAddOp2(v, pIn->eEndLoopOp, pIn->iCur, pIn->addrInTop);
    +-        VdbeCoverage(v);
    +-        VdbeCoverageIf(v, pIn->eEndLoopOp==OP_PrevIfOpen);
    +-        VdbeCoverageIf(v, pIn->eEndLoopOp==OP_NextIfOpen);
    ++        if( pIn->eEndLoopOp!=OP_Noop ){
    ++          sqlite3VdbeAddOp2(v, pIn->eEndLoopOp, pIn->iCur, pIn->addrInTop);
    ++          VdbeCoverage(v);
    ++          VdbeCoverageIf(v, pIn->eEndLoopOp==OP_PrevIfOpen);
    ++          VdbeCoverageIf(v, pIn->eEndLoopOp==OP_NextIfOpen);
    ++        }
    +         sqlite3VdbeJumpHere(v, pIn->addrInTop-1);
    +       }
    +     }
    +@@ -125850,24 +137989,24 @@ SQLITE_PRIVATE void sqlite3WhereEnd(WhereInfo *pWInfo){
    +       sqlite3VdbeJumpHere(v, pLevel->addrSkip);
    +       sqlite3VdbeJumpHere(v, pLevel->addrSkip-2);
    +     }
    ++#ifndef SQLITE_LIKE_DOESNT_MATCH_BLOBS
    +     if( pLevel->addrLikeRep ){
    +-      int op;
    +-      if( sqlite3VdbeGetOp(v, pLevel->addrLikeRep-1)->p1 ){
    +-        op = OP_DecrJumpZero;
    +-      }else{
    +-        op = OP_JumpZeroIncr;
    +-      }
    +-      sqlite3VdbeAddOp2(v, op, pLevel->iLikeRepCntr, pLevel->addrLikeRep);
    ++      sqlite3VdbeAddOp2(v, OP_DecrJumpZero, (int)(pLevel->iLikeRepCntr>>1),
    ++                        pLevel->addrLikeRep);
    +       VdbeCoverage(v);
    +     }
    ++#endif
    +     if( pLevel->iLeftJoin ){
    ++      int ws = pLoop->wsFlags;
    +       addr = sqlite3VdbeAddOp1(v, OP_IfPos, pLevel->iLeftJoin); VdbeCoverage(v);
    +-      assert( (pLoop->wsFlags & WHERE_IDX_ONLY)==0
    +-           || (pLoop->wsFlags & WHERE_INDEXED)!=0 );
    +-      if( (pLoop->wsFlags & WHERE_IDX_ONLY)==0 ){
    +-        sqlite3VdbeAddOp1(v, OP_NullRow, pTabList->a[i].iCursor);
    ++      assert( (ws & WHERE_IDX_ONLY)==0 || (ws & WHERE_INDEXED)!=0 );
    ++      if( (ws & WHERE_IDX_ONLY)==0 ){
    ++        assert( pLevel->iTabCur==pTabList->a[pLevel->iFrom].iCursor );
    ++        sqlite3VdbeAddOp1(v, OP_NullRow, pLevel->iTabCur);
    +       }
    +-      if( pLoop->wsFlags & WHERE_INDEXED ){
    ++      if( (ws & WHERE_INDEXED) 
    ++       || ((ws & WHERE_MULTI_OR) && pLevel->u.pCovidx) 
    ++      ){
    +         sqlite3VdbeAddOp1(v, OP_NullRow, pLevel->iIdxCur);
    +       }
    +       if( pLevel->op==OP_Return ){
    +@@ -125900,33 +138039,13 @@ SQLITE_PRIVATE void sqlite3WhereEnd(WhereInfo *pWInfo){
    +     ** the co-routine into OP_Copy of result contained in a register.
    +     ** OP_Rowid becomes OP_Null.
    +     */
    +-    if( pTabItem->fg.viaCoroutine && !db->mallocFailed ){
    +-      translateColumnToCopy(v, pLevel->addrBody, pLevel->iTabCur,
    ++    if( pTabItem->fg.viaCoroutine ){
    ++      testcase( pParse->db->mallocFailed );
    ++      translateColumnToCopy(pParse, pLevel->addrBody, pLevel->iTabCur,
    +                             pTabItem->regResult, 0);
    +       continue;
    +     }
    + 
    +-    /* Close all of the cursors that were opened by sqlite3WhereBegin.
    +-    ** Except, do not close cursors that will be reused by the OR optimization
    +-    ** (WHERE_OMIT_OPEN_CLOSE).  And do not close the OP_OpenWrite cursors
    +-    ** created for the ONEPASS optimization.
    +-    */
    +-    if( (pTab->tabFlags & TF_Ephemeral)==0
    +-     && pTab->pSelect==0
    +-     && (pWInfo->wctrlFlags & WHERE_OMIT_OPEN_CLOSE)==0
    +-    ){
    +-      int ws = pLoop->wsFlags;
    +-      if( pWInfo->eOnePass==ONEPASS_OFF && (ws & WHERE_IDX_ONLY)==0 ){
    +-        sqlite3VdbeAddOp1(v, OP_Close, pTabItem->iCursor);
    +-      }
    +-      if( (ws & WHERE_INDEXED)!=0
    +-       && (ws & (WHERE_IPK|WHERE_AUTO_INDEX))==0 
    +-       && pLevel->iIdxCur!=pWInfo->aiCurOnePass[1]
    +-      ){
    +-        sqlite3VdbeAddOp1(v, OP_Close, pLevel->iIdxCur);
    +-      }
    +-    }
    +-
    +     /* If this scan uses an index, make VDBE code substitutions to read data
    +     ** from the index instead of from the table where possible.  In some cases
    +     ** this optimization prevents the table from ever being read, which can
    +@@ -125952,7 +138071,11 @@ SQLITE_PRIVATE void sqlite3WhereEnd(WhereInfo *pWInfo){
    +       pOp = sqlite3VdbeGetOp(v, k);
    +       for(; k<last; k++, pOp++){
    +         if( pOp->p1!=pLevel->iTabCur ) continue;
    +-        if( pOp->opcode==OP_Column ){
    ++        if( pOp->opcode==OP_Column
    ++#ifdef SQLITE_ENABLE_OFFSET_SQL_FUNC
    ++         || pOp->opcode==OP_Offset
    ++#endif
    ++        ){
    +           int x = pOp->p2;
    +           assert( pIdx->pTable==pTab );
    +           if( !HasRowid(pTab) ){
    +@@ -125965,10 +138088,13 @@ SQLITE_PRIVATE void sqlite3WhereEnd(WhereInfo *pWInfo){
    +             pOp->p2 = x;
    +             pOp->p1 = pLevel->iIdxCur;
    +           }
    +-          assert( (pLoop->wsFlags & WHERE_IDX_ONLY)==0 || x>=0 );
    ++          assert( (pLoop->wsFlags & WHERE_IDX_ONLY)==0 || x>=0 
    ++              || pWInfo->eOnePass );
    +         }else if( pOp->opcode==OP_Rowid ){
    +           pOp->p1 = pLevel->iIdxCur;
    +           pOp->opcode = OP_IdxRowid;
    ++        }else if( pOp->opcode==OP_IfNullRow ){
    ++          pOp->p1 = pLevel->iIdxCur;
    +         }
    +       }
    +     }
    +@@ -125983,18 +138109,32 @@ SQLITE_PRIVATE void sqlite3WhereEnd(WhereInfo *pWInfo){
    + 
    + /************** End of where.c ***********************************************/
    + /************** Begin file parse.c *******************************************/
    +-/* Driver template for the LEMON parser generator.
    +-** The author disclaims copyright to this source code.
    ++/*
    ++** 2000-05-29
    ++**
    ++** 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.
    ++**
    ++*************************************************************************
    ++** Driver template for the LEMON parser generator.
    + **
    +-** This version of "lempar.c" is modified, slightly, for use by SQLite.
    +-** The only modifications are the addition of a couple of NEVER()
    +-** macros to disable tests that are needed in the case of a general
    +-** LALR(1) grammar but which are always false in the
    +-** specific grammar used by SQLite.
    ++** The "lemon" program processes an LALR(1) input grammar file, then uses
    ++** this template to construct a parser.  The "lemon" program inserts text
    ++** at each "%%" line.  Also, any "P-a-r-s-e" identifer prefix (without the
    ++** interstitial "-" characters) contained in this template is changed into
    ++** the value of the %name directive from the grammar.  Otherwise, the content
    ++** of this template is copied straight through into the generate parser
    ++** source file.
    ++**
    ++** The following is the concatenation of all %include directives from the
    ++** input grammar file:
    + */
    +-/* First off, code is included that follows the "include" declaration
    +-** in the input grammar file. */
    + /* #include <stdio.h> */
    ++/************ Begin %include sections from the grammar ************************/
    + 
    + /* #include "sqliteInt.h" */
    + 
    +@@ -126010,22 +138150,29 @@ SQLITE_PRIVATE void sqlite3WhereEnd(WhereInfo *pWInfo){
    + #define yytestcase(X) testcase(X)
    + 
    + /*
    +-** An instance of this structure holds information about the
    +-** LIMIT clause of a SELECT statement.
    ++** Indicate that sqlite3ParserFree() will never be called with a null
    ++** pointer.
    + */
    +-struct LimitVal {
    +-  Expr *pLimit;    /* The LIMIT expression.  NULL if there is no limit */
    +-  Expr *pOffset;   /* The OFFSET expression.  NULL if there is none */
    +-};
    ++#define YYPARSEFREENEVERNULL 1
    + 
    + /*
    +-** An instance of this structure is used to store the LIKE,
    +-** GLOB, NOT LIKE, and NOT GLOB operators.
    ++** In the amalgamation, the parse.c file generated by lemon and the
    ++** tokenize.c file are concatenated.  In that case, sqlite3RunParser()
    ++** has access to the the size of the yyParser object and so the parser
    ++** engine can be allocated from stack.  In that case, only the
    ++** sqlite3ParserInit() and sqlite3ParserFinalize() routines are invoked
    ++** and the sqlite3ParserAlloc() and sqlite3ParserFree() routines can be
    ++** omitted.
    + */
    +-struct LikeOp {
    +-  Token eOperator;  /* "like" or "glob" or "regexp" */
    +-  int bNot;         /* True if the NOT keyword is present */
    +-};
    ++#ifdef SQLITE_AMALGAMATION
    ++# define sqlite3Parser_ENGINEALWAYSONSTACK 1
    ++#endif
    ++
    ++/*
    ++** Alternative datatype for the argument to the malloc() routine passed
    ++** into sqlite3ParserAlloc().  The default is size_t.
    ++*/
    ++#define YYMALLOCARGTYPE  u64
    + 
    + /*
    + ** An instance of the following structure describes the event of a
    +@@ -126039,9 +138186,13 @@ struct LikeOp {
    + struct TrigEvent { int a; IdList * b; };
    + 
    + /*
    +-** An instance of this structure holds the ATTACH key and the key type.
    ++** Disable lookaside memory allocation for objects that might be
    ++** shared across database connections.
    + */
    +-struct AttachKey { int type;  Token key; };
    ++static void disableLookaside(Parse *pParse){
    ++  pParse->disableLookaside++;
    ++  pParse->db->lookaside.bDisable++;
    ++}
    + 
    + 
    +   /*
    +@@ -126066,79 +138217,43 @@ struct AttachKey { int type;  Token key; };
    +     }
    +   }
    + 
    +-  /* This is a utility routine used to set the ExprSpan.zStart and
    +-  ** ExprSpan.zEnd values of pOut so that the span covers the complete
    +-  ** range of text beginning with pStart and going to the end of pEnd.
    +-  */
    +-  static void spanSet(ExprSpan *pOut, Token *pStart, Token *pEnd){
    +-    pOut->zStart = pStart->z;
    +-    pOut->zEnd = &pEnd->z[pEnd->n];
    +-  }
    + 
    +   /* Construct a new Expr object from a single identifier.  Use the
    +   ** new Expr to populate pOut.  Set the span of pOut to be the identifier
    +   ** that created the expression.
    +   */
    +-  static void spanExpr(ExprSpan *pOut, Parse *pParse, int op, Token *pValue){
    +-    pOut->pExpr = sqlite3PExpr(pParse, op, 0, 0, pValue);
    +-    pOut->zStart = pValue->z;
    +-    pOut->zEnd = &pValue->z[pValue->n];
    +-  }
    +-
    +-  /* This routine constructs a binary expression node out of two ExprSpan
    +-  ** objects and uses the result to populate a new ExprSpan object.
    +-  */
    +-  static void spanBinaryExpr(
    +-    ExprSpan *pOut,     /* Write the result here */
    +-    Parse *pParse,      /* The parsing context.  Errors accumulate here */
    +-    int op,             /* The binary operation */
    +-    ExprSpan *pLeft,    /* The left operand */
    +-    ExprSpan *pRight    /* The right operand */
    +-  ){
    +-    pOut->pExpr = sqlite3PExpr(pParse, op, pLeft->pExpr, pRight->pExpr, 0);
    +-    pOut->zStart = pLeft->zStart;
    +-    pOut->zEnd = pRight->zEnd;
    ++  static Expr *tokenExpr(Parse *pParse, int op, Token t){
    ++    Expr *p = sqlite3DbMallocRawNN(pParse->db, sizeof(Expr)+t.n+1);
    ++    if( p ){
    ++      memset(p, 0, sizeof(Expr));
    ++      p->op = (u8)op;
    ++      p->flags = EP_Leaf;
    ++      p->iAgg = -1;
    ++      p->u.zToken = (char*)&p[1];
    ++      memcpy(p->u.zToken, t.z, t.n);
    ++      p->u.zToken[t.n] = 0;
    ++      if( sqlite3Isquote(p->u.zToken[0]) ){
    ++        if( p->u.zToken[0]=='"' ) p->flags |= EP_DblQuoted;
    ++        sqlite3Dequote(p->u.zToken);
    ++      }
    ++#if SQLITE_MAX_EXPR_DEPTH>0
    ++      p->nHeight = 1;
    ++#endif  
    ++    }
    ++    return p;
    +   }
    + 
    +-  /* Construct an expression node for a unary postfix operator
    +-  */
    +-  static void spanUnaryPostfix(
    +-    ExprSpan *pOut,        /* Write the new expression node here */
    +-    Parse *pParse,         /* Parsing context to record errors */
    +-    int op,                /* The operator */
    +-    ExprSpan *pOperand,    /* The operand */
    +-    Token *pPostOp         /* The operand token for setting the span */
    +-  ){
    +-    pOut->pExpr = sqlite3PExpr(pParse, op, pOperand->pExpr, 0, 0);
    +-    pOut->zStart = pOperand->zStart;
    +-    pOut->zEnd = &pPostOp->z[pPostOp->n];
    +-  }                           
    +-
    +   /* A routine to convert a binary TK_IS or TK_ISNOT expression into a
    +   ** unary TK_ISNULL or TK_NOTNULL expression. */
    +   static void binaryToUnaryIfNull(Parse *pParse, Expr *pY, Expr *pA, int op){
    +     sqlite3 *db = pParse->db;
    +-    if( pY && pA && pY->op==TK_NULL ){
    ++    if( pA && pY && pY->op==TK_NULL ){
    +       pA->op = (u8)op;
    +       sqlite3ExprDelete(db, pA->pRight);
    +       pA->pRight = 0;
    +     }
    +   }
    + 
    +-  /* Construct an expression node for a unary prefix operator
    +-  */
    +-  static void spanUnaryPrefix(
    +-    ExprSpan *pOut,        /* Write the new expression node here */
    +-    Parse *pParse,         /* Parsing context to record errors */
    +-    int op,                /* The operator */
    +-    ExprSpan *pOperand,    /* The operand */
    +-    Token *pPreOp         /* The operand token for setting the span */
    +-  ){
    +-    pOut->pExpr = sqlite3PExpr(pParse, op, pOperand->pExpr, 0, 0);
    +-    pOut->zStart = pPreOp->z;
    +-    pOut->zEnd = pOperand->zEnd;
    +-  }
    +-
    +   /* Add a single new term to an ExprList that is used to store a
    +   ** list of identifiers.  Report an error if the ID list contains
    +   ** a COLLATE clause or an ASC or DESC keyword, except ignore the
    +@@ -126161,44 +138276,42 @@ struct AttachKey { int type;  Token key; };
    +     sqlite3ExprListSetName(pParse, p, pIdToken, 1);
    +     return p;
    +   }
    +-/* Next is all token values, in a form suitable for use by makeheaders.
    +-** This section will be null unless lemon is run with the -m switch.
    +-*/
    +-/* 
    +-** These constants (all generated automatically by the parser generator)
    +-** specify the various kinds of tokens (terminals) that the parser
    +-** understands. 
    +-**
    +-** Each symbol here is a terminal symbol in the grammar.
    +-*/
    +-/* Make sure the INTERFACE macro is defined.
    +-*/
    +-#ifndef INTERFACE
    +-# define INTERFACE 1
    +-#endif
    +-/* The next thing included is series of defines which control
    ++/**************** End of %include directives **********************************/
    ++/* These constants specify the various numeric values for terminal symbols
    ++** in a format understandable to "makeheaders".  This section is blank unless
    ++** "lemon" is run with the "-m" command-line option.
    ++***************** Begin makeheaders token definitions *************************/
    ++/**************** End makeheaders token definitions ***************************/
    ++
    ++/* The next sections is a series of control #defines.
    + ** various aspects of the generated parser.
    +-**    YYCODETYPE         is the data type used for storing terminal
    +-**                       and nonterminal numbers.  "unsigned char" is
    +-**                       used if there are fewer than 250 terminals
    +-**                       and nonterminals.  "int" is used otherwise.
    +-**    YYNOCODE           is a number of type YYCODETYPE which corresponds
    +-**                       to no legal terminal or nonterminal number.  This
    +-**                       number is used to fill in empty slots of the hash 
    +-**                       table.
    ++**    YYCODETYPE         is the data type used to store the integer codes
    ++**                       that represent terminal and non-terminal symbols.
    ++**                       "unsigned char" is used if there are fewer than
    ++**                       256 symbols.  Larger types otherwise.
    ++**    YYNOCODE           is a number of type YYCODETYPE that is not used for
    ++**                       any terminal or nonterminal symbol.
    + **    YYFALLBACK         If defined, this indicates that one or more tokens
    +-**                       have fall-back values which should be used if the
    +-**                       original value of the token will not parse.
    +-**    YYACTIONTYPE       is the data type used for storing terminal
    +-**                       and nonterminal numbers.  "unsigned char" is
    +-**                       used if there are fewer than 250 rules and
    +-**                       states combined.  "int" is used otherwise.
    +-**    sqlite3ParserTOKENTYPE     is the data type used for minor tokens given 
    +-**                       directly to the parser from the tokenizer.
    +-**    YYMINORTYPE        is the data type used for all minor tokens.
    ++**                       (also known as: "terminal symbols") have fall-back
    ++**                       values which should be used if the original symbol
    ++**                       would not parse.  This permits keywords to sometimes
    ++**                       be used as identifiers, for example.
    ++**    YYACTIONTYPE       is the data type used for "action codes" - numbers
    ++**                       that indicate what to do in response to the next
    ++**                       token.
    ++**    sqlite3ParserTOKENTYPE     is the data type used for minor type for terminal
    ++**                       symbols.  Background: A "minor type" is a semantic
    ++**                       value associated with a terminal or non-terminal
    ++**                       symbols.  For example, for an "ID" terminal symbol,
    ++**                       the minor type might be the name of the identifier.
    ++**                       Each non-terminal can have a different minor type.
    ++**                       Terminal symbols all have the same minor type, though.
    ++**                       This macros defines the minor type for terminal 
    ++**                       symbols.
    ++**    YYMINORTYPE        is the data type used for all minor types.
    + **                       This is typically a union of many types, one of
    + **                       which is sqlite3ParserTOKENTYPE.  The entry in the union
    +-**                       for base tokens is called "yy0".
    ++**                       for terminal symbols is called "yy0".
    + **    YYSTACKDEPTH       is the maximum depth of the parser's stack.  If
    + **                       zero the stack is dynamically sized using realloc()
    + **    sqlite3ParserARG_SDECL     A static variable declaration for the %extra_argument
    +@@ -126209,37 +138322,39 @@ struct AttachKey { int type;  Token key; };
    + **                       defined, then do no error processing.
    + **    YYNSTATE           the combined number of states.
    + **    YYNRULE            the number of rules in the grammar
    ++**    YYNTOKEN           Number of terminal symbols
    + **    YY_MAX_SHIFT       Maximum value for shift actions
    + **    YY_MIN_SHIFTREDUCE Minimum value for shift-reduce actions
    + **    YY_MAX_SHIFTREDUCE Maximum value for shift-reduce actions
    +-**    YY_MIN_REDUCE      Maximum value for reduce actions
    + **    YY_ERROR_ACTION    The yy_action[] code for syntax error
    + **    YY_ACCEPT_ACTION   The yy_action[] code for accept
    + **    YY_NO_ACTION       The yy_action[] code for no-op
    ++**    YY_MIN_REDUCE      Minimum value for reduce actions
    ++**    YY_MAX_REDUCE      Maximum value for reduce actions
    + */
    ++#ifndef INTERFACE
    ++# define INTERFACE 1
    ++#endif
    ++/************* Begin control #defines *****************************************/
    + #define YYCODETYPE unsigned char
    +-#define YYNOCODE 254
    ++#define YYNOCODE 253
    + #define YYACTIONTYPE unsigned short int
    +-#define YYWILDCARD 70
    ++#define YYWILDCARD 83
    + #define sqlite3ParserTOKENTYPE Token
    + typedef union {
    +   int yyinit;
    +   sqlite3ParserTOKENTYPE yy0;
    +-  Select* yy3;
    +-  ExprList* yy14;
    +-  With* yy59;
    +-  SrcList* yy65;
    +-  struct LikeOp yy96;
    +-  Expr* yy132;
    +-  u8 yy186;
    +-  int yy328;
    +-  ExprSpan yy346;
    +-  struct TrigEvent yy378;
    +-  u16 yy381;
    +-  IdList* yy408;
    +-  struct {int value; int mask;} yy429;
    +-  TriggerStep* yy473;
    +-  struct LimitVal yy476;
    ++  int yy4;
    ++  struct TrigEvent yy90;
    ++  TriggerStep* yy203;
    ++  struct {int value; int mask;} yy215;
    ++  SrcList* yy259;
    ++  Expr* yy314;
    ++  ExprList* yy322;
    ++  const char* yy336;
    ++  IdList* yy384;
    ++  Select* yy387;
    ++  With* yy451;
    + } YYMINORTYPE;
    + #ifndef YYSTACKDEPTH
    + #define YYSTACKDEPTH 100
    +@@ -126249,20 +138364,18 @@ typedef union {
    + #define sqlite3ParserARG_FETCH Parse *pParse = yypParser->pParse
    + #define sqlite3ParserARG_STORE yypParser->pParse = pParse
    + #define YYFALLBACK 1
    +-#define YYNSTATE             436
    +-#define YYNRULE              328
    +-#define YY_MAX_SHIFT         435
    +-#define YY_MIN_SHIFTREDUCE   649
    +-#define YY_MAX_SHIFTREDUCE   976
    +-#define YY_MIN_REDUCE        977
    +-#define YY_MAX_REDUCE        1304
    +-#define YY_ERROR_ACTION      1305
    +-#define YY_ACCEPT_ACTION     1306
    +-#define YY_NO_ACTION         1307
    +-
    +-/* The yyzerominor constant is used to initialize instances of
    +-** YYMINORTYPE objects to zero. */
    +-static const YYMINORTYPE yyzerominor = { 0 };
    ++#define YYNSTATE             466
    ++#define YYNRULE              330
    ++#define YYNTOKEN             143
    ++#define YY_MAX_SHIFT         465
    ++#define YY_MIN_SHIFTREDUCE   675
    ++#define YY_MAX_SHIFTREDUCE   1004
    ++#define YY_ERROR_ACTION      1005
    ++#define YY_ACCEPT_ACTION     1006
    ++#define YY_NO_ACTION         1007
    ++#define YY_MIN_REDUCE        1008
    ++#define YY_MAX_REDUCE        1337
    ++/************* End control #defines *******************************************/
    + 
    + /* Define the yytestcase() macro to be a no-op if is not already defined
    + ** otherwise.
    +@@ -126291,9 +138404,6 @@ static const YYMINORTYPE yyzerominor = { 0 };
    + **   N between YY_MIN_SHIFTREDUCE       Shift to an arbitrary state then
    + **     and YY_MAX_SHIFTREDUCE           reduce by rule N-YY_MIN_SHIFTREDUCE.
    + **
    +-**   N between YY_MIN_REDUCE            Reduce by rule N-YY_MIN_REDUCE
    +-**     and YY_MAX_REDUCE
    +-
    + **   N == YY_ERROR_ACTION               A syntax error has occurred.
    + **
    + **   N == YY_ACCEPT_ACTION              The parser accepts its input.
    +@@ -126301,21 +138411,22 @@ static const YYMINORTYPE yyzerominor = { 0 };
    + **   N == YY_NO_ACTION                  No such action.  Denotes unused
    + **                                      slots in the yy_action[] table.
    + **
    ++**   N between YY_MIN_REDUCE            Reduce by rule N-YY_MIN_REDUCE
    ++**     and YY_MAX_REDUCE
    ++**
    + ** The action table is constructed as a single large table named yy_action[].
    +-** Given state S and lookahead X, the action is computed as
    ++** Given state S and lookahead X, the action is computed as either:
    + **
    +-**      yy_action[ yy_shift_ofst[S] + X ]
    ++**    (A)   N = yy_action[ yy_shift_ofst[S] + X ]
    ++**    (B)   N = yy_default[S]
    + **
    +-** If the index value yy_shift_ofst[S]+X is out of range or if the value
    +-** yy_lookahead[yy_shift_ofst[S]+X] is not equal to X or if yy_shift_ofst[S]
    +-** is equal to YY_SHIFT_USE_DFLT, it means that the action is not in the table
    +-** and that yy_default[S] should be used instead.  
    ++** The (A) formula is preferred.  The B formula is used instead if
    ++** yy_lookahead[yy_shift_ofst[S]+X] is not equal to X.
    + **
    +-** The formula above is for computing the action when the lookahead is
    ++** The formulas above are for computing the action when the lookahead is
    + ** a terminal symbol.  If the lookahead is a non-terminal (as occurs after
    + ** a reduce action) then the yy_reduce_ofst[] array is used in place of
    +-** the yy_shift_ofst[] array and YY_REDUCE_USE_DFLT is used in place of
    +-** YY_SHIFT_USE_DFLT.
    ++** the yy_shift_ofst[] array.
    + **
    + ** The following are the tables generated in this section:
    + **
    +@@ -126327,451 +138438,481 @@ static const YYMINORTYPE yyzerominor = { 0 };
    + **  yy_reduce_ofst[]   For each state, the offset into yy_action for
    + **                     shifting non-terminals after a reduce.
    + **  yy_default[]       Default action for each state.
    +-*/
    +-#define YY_ACTTAB_COUNT (1501)
    ++**
    ++*********** Begin parsing tables **********************************************/
    ++#define YY_ACTTAB_COUNT (1541)
    + static const YYACTIONTYPE yy_action[] = {
    +- /*     0 */   311, 1306,  145,  651,    2,  192,  652,  338,  780,   92,
    +- /*    10 */    92,   92,   92,   85,   90,   90,   90,   90,   89,   89,
    +- /*    20 */    88,   88,   88,   87,  335,   88,   88,   88,   87,  335,
    +- /*    30 */   327,  856,  856,   92,   92,   92,   92,  776,   90,   90,
    +- /*    40 */    90,   90,   89,   89,   88,   88,   88,   87,  335,   86,
    +- /*    50 */    83,  166,   93,   94,   84,  868,  871,  860,  860,   91,
    +- /*    60 */    91,   92,   92,   92,   92,  335,   90,   90,   90,   90,
    +- /*    70 */    89,   89,   88,   88,   88,   87,  335,  311,  780,   90,
    +- /*    80 */    90,   90,   90,   89,   89,   88,   88,   88,   87,  335,
    +- /*    90 */   123,  808,  689,  689,  689,  689,  112,  230,  430,  257,
    +- /*   100 */   809,  698,  430,   86,   83,  166,  324,   55,  856,  856,
    +- /*   110 */   201,  158,  276,  387,  271,  386,  188,  689,  689,  828,
    +- /*   120 */   833,   49,  944,  269,  833,   49,  123,   87,  335,   93,
    +- /*   130 */    94,   84,  868,  871,  860,  860,   91,   91,   92,   92,
    +- /*   140 */    92,   92,  342,   90,   90,   90,   90,   89,   89,   88,
    +- /*   150 */    88,   88,   87,  335,  311,  328,  333,  332,  701,  408,
    +- /*   160 */   394,   69,  690,  691,  690,  691,  715,  910,  251,  354,
    +- /*   170 */   250,  698,  704,  430,  908,  430,  909,   89,   89,   88,
    +- /*   180 */    88,   88,   87,  335,  391,  856,  856,  690,  691,  183,
    +- /*   190 */    95,  340,  384,  381,  380,  833,   31,  833,   49,  912,
    +- /*   200 */   912,  333,  332,  379,  123,  311,   93,   94,   84,  868,
    +- /*   210 */   871,  860,  860,   91,   91,   92,   92,   92,   92,  114,
    +- /*   220 */    90,   90,   90,   90,   89,   89,   88,   88,   88,   87,
    +- /*   230 */   335,  430,  408,  399,  435,  657,  856,  856,  346,   57,
    +- /*   240 */   232,  828,  109,   20,  912,  912,  231,  393,  937,  760,
    +- /*   250 */    97,  751,  752,  833,   49,  708,  708,   93,   94,   84,
    +- /*   260 */   868,  871,  860,  860,   91,   91,   92,   92,   92,   92,
    +- /*   270 */   707,   90,   90,   90,   90,   89,   89,   88,   88,   88,
    +- /*   280 */    87,  335,  311,  114,   22,  706,  688,   58,  408,  390,
    +- /*   290 */   251,  349,  240,  749,  752,  689,  689,  847,  685,  115,
    +- /*   300 */    21,  231,  393,  689,  689,  697,  183,  355,  430,  384,
    +- /*   310 */   381,  380,  192,  856,  856,  780,  123,  160,  159,  223,
    +- /*   320 */   379,  738,   25,  315,  362,  841,  143,  689,  689,  835,
    +- /*   330 */   833,   48,  339,  937,   93,   94,   84,  868,  871,  860,
    +- /*   340 */   860,   91,   91,   92,   92,   92,   92,  914,   90,   90,
    +- /*   350 */    90,   90,   89,   89,   88,   88,   88,   87,  335,  311,
    +- /*   360 */   840,  840,  840,  266,  430,  690,  691,  778,  114, 1300,
    +- /*   370 */  1300,  430,    1,  690,  691,  697,  688,  689,  689,  689,
    +- /*   380 */   689,  689,  689,  287,  298,  780,  833,   10,  686,  115,
    +- /*   390 */   856,  856,  355,  833,   10,  828,  366,  690,  691,  363,
    +- /*   400 */   321,   76,  123,   74,   23,  737,  807,  323,  356,  353,
    +- /*   410 */   847,   93,   94,   84,  868,  871,  860,  860,   91,   91,
    +- /*   420 */    92,   92,   92,   92,  940,   90,   90,   90,   90,   89,
    +- /*   430 */    89,   88,   88,   88,   87,  335,  311,  806,  841,  429,
    +- /*   440 */   713,  941,  835,  430,  251,  354,  250,  690,  691,  690,
    +- /*   450 */   691,  690,  691,   86,   83,  166,   24,  942,  151,  753,
    +- /*   460 */   285,  907,  403,  907,  164,  833,   10,  856,  856,  965,
    +- /*   470 */   306,  754,  679,  840,  840,  840,  795,  216,  794,  222,
    +- /*   480 */   906,  344,  906,  904,   86,   83,  166,  286,   93,   94,
    +- /*   490 */    84,  868,  871,  860,  860,   91,   91,   92,   92,   92,
    +- /*   500 */    92,  430,   90,   90,   90,   90,   89,   89,   88,   88,
    +- /*   510 */    88,   87,  335,  311,  430,  724,  352,  705,  427,  699,
    +- /*   520 */   700,  376,  210,  833,   49,  793,  397,  857,  857,  940,
    +- /*   530 */   213,  762,  727,  334,  699,  700,  833,   10,   86,   83,
    +- /*   540 */   166,  345,  396,  902,  856,  856,  941,  385,  833,    9,
    +- /*   550 */   406,  869,  872,  187,  890,  728,  347,  398,  404,  977,
    +- /*   560 */   652,  338,  942,  954,  413,   93,   94,   84,  868,  871,
    +- /*   570 */   860,  860,   91,   91,   92,   92,   92,   92,  861,   90,
    +- /*   580 */    90,   90,   90,   89,   89,   88,   88,   88,   87,  335,
    +- /*   590 */   311, 1219,  114,  430,  834,  430,    5,  165,  192,  688,
    +- /*   600 */   832,  780,  430,  723,  430,  234,  325,  189,  163,  316,
    +- /*   610 */   356,  955,  115,  235,  269,  833,   35,  833,   36,  747,
    +- /*   620 */   720,  856,  856,  793,  833,   12,  833,   27,  745,  174,
    +- /*   630 */   968, 1290,  968, 1291, 1290,  310, 1291,  693,  317,  245,
    +- /*   640 */   264,  311,   93,   94,   84,  868,  871,  860,  860,   91,
    +- /*   650 */    91,   92,   92,   92,   92,  832,   90,   90,   90,   90,
    +- /*   660 */    89,   89,   88,   88,   88,   87,  335,  430,  320,  213,
    +- /*   670 */   762,  780,  856,  856,  920,  920,  369,  257,  966,  220,
    +- /*   680 */   966,  396,  663,  664,  665,  242,  259,  244,  262,  833,
    +- /*   690 */    37,  650,    2,   93,   94,   84,  868,  871,  860,  860,
    +- /*   700 */    91,   91,   92,   92,   92,   92,  430,   90,   90,   90,
    +- /*   710 */    90,   89,   89,   88,   88,   88,   87,  335,  311,  430,
    +- /*   720 */   239,  430,  917,  368,  430,  238,  916,  793,  833,   38,
    +- /*   730 */   430,  825,  430,   66,  430,  392,  430,  766,  766,  430,
    +- /*   740 */   367,  833,   39,  833,   28,  430,  833,   29,   68,  856,
    +- /*   750 */   856,  900,  833,   40,  833,   41,  833,   42,  833,   11,
    +- /*   760 */    72,  833,   43,  243,  305,  970,  114,  833,   99,  961,
    +- /*   770 */    93,   94,   84,  868,  871,  860,  860,   91,   91,   92,
    +- /*   780 */    92,   92,   92,  430,   90,   90,   90,   90,   89,   89,
    +- /*   790 */    88,   88,   88,   87,  335,  311,  430,  361,  430,  165,
    +- /*   800 */   147,  430,  186,  185,  184,  833,   44,  430,  289,  430,
    +- /*   810 */   246,  430,  971,  430,  212,  163,  430,  357,  833,   45,
    +- /*   820 */   833,   32,  932,  833,   46,  793,  856,  856,  718,  833,
    +- /*   830 */    47,  833,   33,  833,  117,  833,  118,   75,  833,  119,
    +- /*   840 */   288,  305,  967,  214,  935,  322,  311,   93,   94,   84,
    +- /*   850 */   868,  871,  860,  860,   91,   91,   92,   92,   92,   92,
    +- /*   860 */   430,   90,   90,   90,   90,   89,   89,   88,   88,   88,
    +- /*   870 */    87,  335,  430,  832,  426,  317,  288,  856,  856,  114,
    +- /*   880 */   763,  257,  833,   53,  930,  219,  364,  257,  257,  971,
    +- /*   890 */   361,  396,  257,  257,  833,   34,  257,  311,   93,   94,
    +- /*   900 */    84,  868,  871,  860,  860,   91,   91,   92,   92,   92,
    +- /*   910 */    92,  430,   90,   90,   90,   90,   89,   89,   88,   88,
    +- /*   920 */    88,   87,  335,  430,  217,  318,  124,  253,  856,  856,
    +- /*   930 */   218,  943,  257,  833,  100,  898,  759,  774,  361,  755,
    +- /*   940 */   423,  329,  758, 1017,  289,  833,   50,  682,  311,   93,
    +- /*   950 */    82,   84,  868,  871,  860,  860,   91,   91,   92,   92,
    +- /*   960 */    92,   92,  430,   90,   90,   90,   90,   89,   89,   88,
    +- /*   970 */    88,   88,   87,  335,  430,  256,  419,  114,  249,  856,
    +- /*   980 */   856,  331,  114,  400,  833,  101,  359,  187, 1064,  726,
    +- /*   990 */   725,  739,  401,  416,  420,  360,  833,  102,  424,  311,
    +- /*  1000 */   258,   94,   84,  868,  871,  860,  860,   91,   91,   92,
    +- /*  1010 */    92,   92,   92,  430,   90,   90,   90,   90,   89,   89,
    +- /*  1020 */    88,   88,   88,   87,  335,  430,  221,  261,  114,  114,
    +- /*  1030 */   856,  856,  808,  114,  156,  833,   98,  772,  733,  734,
    +- /*  1040 */   275,  809,  771,  316,  263,  265,  960,  833,  116,  307,
    +- /*  1050 */   741,  274,  722,   84,  868,  871,  860,  860,   91,   91,
    +- /*  1060 */    92,   92,   92,   92,  430,   90,   90,   90,   90,   89,
    +- /*  1070 */    89,   88,   88,   88,   87,  335,   80,  425,  830,    3,
    +- /*  1080 */  1214,  191,  430,  721,  336,  336,  833,  113,  252,   80,
    +- /*  1090 */   425,   68,    3,  913,  913,  428,  270,  336,  336,  430,
    +- /*  1100 */   377,  784,  430,  197,  833,  106,  430,  716,  428,  430,
    +- /*  1110 */   267,  430,  897,   68,  414,  430,  769,  409,  430,   71,
    +- /*  1120 */   430,  833,  105,  123,  833,  103,  847,  414,  833,   49,
    +- /*  1130 */   843,  833,  104,  833,   52,  800,  123,  833,   54,  847,
    +- /*  1140 */   833,   51,  833,   26,  831,  802,   77,   78,  191,  389,
    +- /*  1150 */   430,  372,  114,   79,  432,  431,  911,  911,  835,   77,
    +- /*  1160 */    78,  779,  893,  408,  410,  197,   79,  432,  431,  791,
    +- /*  1170 */   226,  835,  833,   30,  772,   80,  425,  716,    3,  771,
    +- /*  1180 */   411,  412,  897,  336,  336,  290,  291,  839,  703,  840,
    +- /*  1190 */   840,  840,  842,   19,  428,  695,  684,  672,  111,  671,
    +- /*  1200 */   843,  673,  840,  840,  840,  842,   19,  207,  661,  278,
    +- /*  1210 */   148,  304,  280,  414,  282,    6,  822,  348,  248,  241,
    +- /*  1220 */   358,  934,  720,   80,  425,  847,    3,  161,  382,  273,
    +- /*  1230 */   284,  336,  336,  415,  296,  958,  895,  894,  157,  674,
    +- /*  1240 */   107,  194,  428,  948,  135,   77,   78,  777,  953,  951,
    +- /*  1250 */    56,  319,   79,  432,  431,  121,   66,  835,   59,  128,
    +- /*  1260 */   146,  414,  350,  130,  351,  819,  131,  132,  133,  375,
    +- /*  1270 */   173,  149,  138,  847,  936,  365,  178,   70,  425,  827,
    +- /*  1280 */     3,  889,   62,  371,  915,  336,  336,  792,  840,  840,
    +- /*  1290 */   840,  842,   19,   77,   78,  208,  428,  144,  179,  373,
    +- /*  1300 */    79,  432,  431,  255,  180,  835,  260,  675,  181,  308,
    +- /*  1310 */   388,  744,  326,  743,  742,  414,  731,  718,  712,  402,
    +- /*  1320 */   309,  711,  788,   65,  277,  272,  789,  847,  730,  710,
    +- /*  1330 */   709,  279,  193,  787,  281,  876,  840,  840,  840,  842,
    +- /*  1340 */    19,  786,  283,   73,  418,  330,  422,   77,   78,  227,
    +- /*  1350 */    96,  407,   67,  405,   79,  432,  431,  292,  228,  835,
    +- /*  1360 */   215,  202,  229,  293,  767,  303,  302,  301,  204,  299,
    +- /*  1370 */   294,  295,  676,    7,  681,  433,  669,  206,  110,  224,
    +- /*  1380 */   203,  205,  434,  667,  666,  658,  120,  168,  656,  237,
    +- /*  1390 */   840,  840,  840,  842,   19,  337,  155,  233,  236,  341,
    +- /*  1400 */   167,  905,  108,  313,  903,  826,  314,  125,  126,  127,
    +- /*  1410 */   129,  170,  247,  756,  172,  928,  134,  136,  171,   60,
    +- /*  1420 */    61,  123,  169,  137,  175,  933,  176,  927,    8,   13,
    +- /*  1430 */   177,  254,  191,  918,  139,  370,  924,  140,  678,  150,
    +- /*  1440 */   374,  274,  182,  378,  141,  122,   63,   14,  383,  729,
    +- /*  1450 */   268,   15,   64,  225,  846,  845,  874,   16,  765,  770,
    +- /*  1460 */     4,  162,  209,  395,  211,  142,  878,  796,  801,  312,
    +- /*  1470 */   190,   71,   68,  875,  873,  939,  199,  938,   17,  195,
    +- /*  1480 */    18,  196,  417,  975,  152,  653,  976,  198,  153,  421,
    +- /*  1490 */   877,  154,  200,  844,  696,   81,  343,  297, 1019, 1018,
    +- /*  1500 */   300,
    ++ /*     0 */  1006,  156,  156,    2, 1302,   90,   87,  179,   90,   87,
    ++ /*    10 */   179,  460, 1048,  460,  465, 1010,  460,  333, 1130,  335,
    ++ /*    20 */   246,  330,  112,  303,  439, 1258,  304,  419, 1129, 1087,
    ++ /*    30 */    72,  798,   50,   50,   50,   50,  331,   30,   30,  799,
    ++ /*    40 */   951,  364,  371,   97,   98,   88,  983,  983,  859,  862,
    ++ /*    50 */   851,  851,   95,   95,   96,   96,   96,   96,  120,  371,
    ++ /*    60 */   370,  120,  348,   22,   90,   87,  179,  438,  423,  438,
    ++ /*    70 */   440,  335,  420,  385,   90,   87,  179,  116,   73,  163,
    ++ /*    80 */   848,  848,  860,  863,   94,   94,   94,   94,   93,   93,
    ++ /*    90 */    92,   92,   92,   91,  361,   97,   98,   88,  983,  983,
    ++ /*   100 */   859,  862,  851,  851,   95,   95,   96,   96,   96,   96,
    ++ /*   110 */   718,  365,  339,   93,   93,   92,   92,   92,   91,  361,
    ++ /*   120 */    99,  371,  453,  335,   94,   94,   94,   94,   93,   93,
    ++ /*   130 */    92,   92,   92,   91,  361,  852,   94,   94,   94,   94,
    ++ /*   140 */    93,   93,   92,   92,   92,   91,  361,   97,   98,   88,
    ++ /*   150 */   983,  983,  859,  862,  851,  851,   95,   95,   96,   96,
    ++ /*   160 */    96,   96,   92,   92,   92,   91,  361,  838,  132,  195,
    ++ /*   170 */    58,  244,  412,  409,  408,  335,  457,  457,  457,  304,
    ++ /*   180 */    59,  332,  831,  407,  394,  962,  830,  391,   94,   94,
    ++ /*   190 */    94,   94,   93,   93,   92,   92,   92,   91,  361,   97,
    ++ /*   200 */    98,   88,  983,  983,  859,  862,  851,  851,   95,   95,
    ++ /*   210 */    96,   96,   96,   96,  426,  357,  460,  830,  830,  832,
    ++ /*   220 */    91,  361,  962,  963,  964,  195,  459,  335,  412,  409,
    ++ /*   230 */   408,  280,  361,  820,  132,   11,   11,   50,   50,  407,
    ++ /*   240 */    94,   94,   94,   94,   93,   93,   92,   92,   92,   91,
    ++ /*   250 */   361,   97,   98,   88,  983,  983,  859,  862,  851,  851,
    ++ /*   260 */    95,   95,   96,   96,   96,   96,  460,  221,  460,  264,
    ++ /*   270 */   375,  254,  438,  428, 1276, 1276,  383, 1074, 1053,  335,
    ++ /*   280 */   245,  422,  299,  713,  271,  271, 1074,   50,   50,   50,
    ++ /*   290 */    50,  962,   94,   94,   94,   94,   93,   93,   92,   92,
    ++ /*   300 */    92,   91,  361,   97,   98,   88,  983,  983,  859,  862,
    ++ /*   310 */   851,  851,   95,   95,   96,   96,   96,   96,   90,   87,
    ++ /*   320 */   179, 1306,  438,  437,  438,  418,  368,  253,  962,  963,
    ++ /*   330 */   964,  335,  360,  360,  360,  706,  359,  358,  324,  962,
    ++ /*   340 */  1281,  951,  364,  230,   94,   94,   94,   94,   93,   93,
    ++ /*   350 */    92,   92,   92,   91,  361,   97,   98,   88,  983,  983,
    ++ /*   360 */   859,  862,  851,  851,   95,   95,   96,   96,   96,   96,
    ++ /*   370 */   769,  460,  120,  226,  226,  366,  962,  963,  964, 1089,
    ++ /*   380 */   990,  900,  990,  335, 1057,  425,  421,  839,  759,  759,
    ++ /*   390 */   425,  427,   50,   50,  432,  381,   94,   94,   94,   94,
    ++ /*   400 */    93,   93,   92,   92,   92,   91,  361,   97,   98,   88,
    ++ /*   410 */   983,  983,  859,  862,  851,  851,   95,   95,   96,   96,
    ++ /*   420 */    96,   96,  460,  259,  460,  120,  117,  354,  942, 1332,
    ++ /*   430 */   942, 1333, 1332,  278, 1333,  335,  680,  681,  682,  825,
    ++ /*   440 */   201,  176,  303,   50,   50,   49,   49,  404,   94,   94,
    ++ /*   450 */    94,   94,   93,   93,   92,   92,   92,   91,  361,   97,
    ++ /*   460 */    98,   88,  983,  983,  859,  862,  851,  851,   95,   95,
    ++ /*   470 */    96,   96,   96,   96,  199,  460,  380,  265,  433,  380,
    ++ /*   480 */   265,  383,  256,  158,  258,  319, 1003,  335,  155,  940,
    ++ /*   490 */   177,  940,  273,  379,  276,  322,   34,   34,  302,  962,
    ++ /*   500 */    94,   94,   94,   94,   93,   93,   92,   92,   92,   91,
    ++ /*   510 */   361,   97,   98,   88,  983,  983,  859,  862,  851,  851,
    ++ /*   520 */    95,   95,   96,   96,   96,   96,  905,  905,  397,  460,
    ++ /*   530 */   301,  158,  101,  319,  941,  340,  962,  963,  964,  313,
    ++ /*   540 */   283,  449,  335,  327,  146, 1266, 1004,  257,  234,  248,
    ++ /*   550 */    35,   35,   94,   94,   94,   94,   93,   93,   92,   92,
    ++ /*   560 */    92,   91,  361,  709,  785, 1227,   97,   98,   88,  983,
    ++ /*   570 */   983,  859,  862,  851,  851,   95,   95,   96,   96,   96,
    ++ /*   580 */    96,  962, 1227, 1229,  245,  422,  838,  198,  197,  196,
    ++ /*   590 */  1079, 1079, 1077, 1077, 1004, 1334,  320,  335,  172,  171,
    ++ /*   600 */   709,  831,  159,  271,  271,  830,   76,   94,   94,   94,
    ++ /*   610 */    94,   93,   93,   92,   92,   92,   91,  361,  962,  963,
    ++ /*   620 */   964,   97,   98,   88,  983,  983,  859,  862,  851,  851,
    ++ /*   630 */    95,   95,   96,   96,   96,   96,  830,  830,  832, 1157,
    ++ /*   640 */  1157,  199, 1157,  173, 1227,  231,  232, 1282,    2,  335,
    ++ /*   650 */   271,  764,  271,  820,  271,  271,  763,  389,  389,  389,
    ++ /*   660 */   132,   79,   94,   94,   94,   94,   93,   93,   92,   92,
    ++ /*   670 */    92,   91,  361,   97,   98,   88,  983,  983,  859,  862,
    ++ /*   680 */   851,  851,   95,   95,   96,   96,   96,   96,  460,  264,
    ++ /*   690 */   223,  460, 1257,  783, 1223, 1157, 1086, 1082,   80,  271,
    ++ /*   700 */    78,  335,  340, 1031,  341,  344,  345,  902,  346,   10,
    ++ /*   710 */    10,  902,   25,   25,   94,   94,   94,   94,   93,   93,
    ++ /*   720 */    92,   92,   92,   91,  361,   97,   86,   88,  983,  983,
    ++ /*   730 */   859,  862,  851,  851,   95,   95,   96,   96,   96,   96,
    ++ /*   740 */  1157,  270,  395,  117,  233,  263,  235,   70,  456,  341,
    ++ /*   750 */   225,  176,  335, 1305,  342,  133,  736,  966,  980,  249,
    ++ /*   760 */  1150,  396,  325, 1085, 1028,  178,   94,   94,   94,   94,
    ++ /*   770 */    93,   93,   92,   92,   92,   91,  361,   98,   88,  983,
    ++ /*   780 */   983,  859,  862,  851,  851,   95,   95,   96,   96,   96,
    ++ /*   790 */    96,  783,  783,  132,  120,  966,  120,  120,  120,  798,
    ++ /*   800 */   252,  937,  335,  353,  321,  429,  355,  799,  822,  692,
    ++ /*   810 */   390,  203,  446,  450,  372,  716,  454,   94,   94,   94,
    ++ /*   820 */    94,   93,   93,   92,   92,   92,   91,  361,   88,  983,
    ++ /*   830 */   983,  859,  862,  851,  851,   95,   95,   96,   96,   96,
    ++ /*   840 */    96,   84,  455, 1225,    3, 1209,  120,  120,  382,  387,
    ++ /*   850 */   120,  203, 1271,  716,  384,  168,  266,  203,  458,   72,
    ++ /*   860 */   260, 1246,   84,  455,  178,    3,  378,   94,   94,   94,
    ++ /*   870 */    94,   93,   93,   92,   92,   92,   91,  361,  350,  458,
    ++ /*   880 */  1245,  362,  430,  213,  228,  290,  415,  285,  414,  200,
    ++ /*   890 */   783,  882,  444,  726,  725,  405,  283,  921,  209,  921,
    ++ /*   900 */   281,  132,  362,   72,  838,  289,  147,  733,  734,  392,
    ++ /*   910 */    81,   82,  922,  444,  922,  267,  288,   83,  362,  462,
    ++ /*   920 */   461,  272,  132,  830,   23,  838,  388,  923, 1216,  923,
    ++ /*   930 */  1056,   81,   82,   84,  455,  899,    3,  899,   83,  362,
    ++ /*   940 */   462,  461,  761,  962,  830,   75,    1,  443,  275,  747,
    ++ /*   950 */   458,    5,  962,  204,  830,  830,  832,  833,   18,  748,
    ++ /*   960 */   229,  962,  277,   19,  153,  317,  317,  316,  216,  314,
    ++ /*   970 */   279,  460,  689,  362, 1055,  830,  830,  832,  833,   18,
    ++ /*   980 */   962,  963,  964,  962,  444,  181,  460,  251,  981,  962,
    ++ /*   990 */   963,  964,    8,    8,   20,  250,  838, 1070,  962,  963,
    ++ /*  1000 */   964,  417,   81,   82,  768,  204,  347,   36,   36,   83,
    ++ /*  1010 */   362,  462,  461, 1054,  284,  830,   84,  455, 1123,    3,
    ++ /*  1020 */   962,  963,  964,  460,  183,  962,  981,  764,  889, 1107,
    ++ /*  1030 */   460,  184,  763,  458,  132,  182,   74,  455,  460,    3,
    ++ /*  1040 */   981,  898,  834,  898,    8,    8,  830,  830,  832,  833,
    ++ /*  1050 */    18,    8,    8,  458,  219, 1156,  362, 1103,  349,    8,
    ++ /*  1060 */     8,  240,  962,  963,  964,  236,  889,  444,  792,  336,
    ++ /*  1070 */   158,  203,  885,  435,  700,  209,  362,  114,  981,  838,
    ++ /*  1080 */   834,  227,  334, 1114,  441,   81,   82,  444,  442,  305,
    ++ /*  1090 */   784,  306,   83,  362,  462,  461,  369, 1162,  830,  838,
    ++ /*  1100 */   460, 1037,  237, 1030,  237,   81,   82,    7,   96,   96,
    ++ /*  1110 */    96,   96,   83,  362,  462,  461, 1019, 1018,  830, 1020,
    ++ /*  1120 */  1289,   37,   37,  400,   96,   96,   96,   96,   89,  830,
    ++ /*  1130 */   830,  832,  833,   18, 1100,  318,  962,  292,   94,   94,
    ++ /*  1140 */    94,   94,   93,   93,   92,   92,   92,   91,  361,  830,
    ++ /*  1150 */   830,  832,  833,   18,   94,   94,   94,   94,   93,   93,
    ++ /*  1160 */    92,   92,   92,   91,  361,  359,  358,  226,  226,  727,
    ++ /*  1170 */   294,  296,  460,  962,  963,  964,  460,  989,  160,  425,
    ++ /*  1180 */   170, 1295,  262,  460,  987,  374,  988,  386, 1145,  255,
    ++ /*  1190 */   326,  460,  373,   38,   38,  410,  174,   39,   39,  413,
    ++ /*  1200 */   460,  287,  460, 1053,   40,   40,  298,  728, 1220,  990,
    ++ /*  1210 */   445,  990,   26,   26, 1219,  460,  311,  460,  169, 1292,
    ++ /*  1220 */   460,   27,   27,   29,   29,  998,  460,  206,  135,  995,
    ++ /*  1230 */  1265, 1263,  460,   57,   60,  460,   41,   41,   42,   42,
    ++ /*  1240 */   460,   43,   43,  460,  343,  351,  460,    9,    9,  460,
    ++ /*  1250 */   144,  460,  130,   44,   44,  460,  103,  103,  460,  137,
    ++ /*  1260 */    70,   45,   45,  460,   46,   46,  460,   31,   31, 1142,
    ++ /*  1270 */    47,   47,   48,   48,  460,  376,   32,   32,  460,  122,
    ++ /*  1280 */   122,  460,  157,  460,  123,  123,  139,  124,  124,  460,
    ++ /*  1290 */   186,  460,  377,  460,  115,   54,   54,  460,  403,   33,
    ++ /*  1300 */    33,  460,  104,  104,   51,   51,  460,  161,  460,  140,
    ++ /*  1310 */   105,  105,  106,  106,  102,  102,  460,  141,  121,  121,
    ++ /*  1320 */   460,  142,  119,  119,  190,  460, 1152,  110,  110,  109,
    ++ /*  1330 */   109,  702,  460,  148,  393,   65,  460,  107,  107,  460,
    ++ /*  1340 */   323,  108,  108,  399,  460, 1234,   53,   53, 1214,  269,
    ++ /*  1350 */   154,  416, 1115,   55,   55,  220,  401,   52,   52,  191,
    ++ /*  1360 */    24,   24,  274,  192,  193,   28,   28, 1021,  328,  702,
    ++ /*  1370 */  1073,  352, 1072,  718, 1071,  431, 1111, 1064,  329, 1045,
    ++ /*  1380 */    69,  205,    6,  291, 1044,  286, 1112, 1043, 1304, 1110,
    ++ /*  1390 */   293,  300,  295,  297, 1063, 1200, 1109,   77,  241,  448,
    ++ /*  1400 */   356,  452,  436,  100,  214,   71,  434, 1027, 1093,   21,
    ++ /*  1410 */   463,  242,  243,  957,  215,  217,  218,  464,  309,  307,
    ++ /*  1420 */   308,  310, 1016,  125, 1250, 1251, 1011, 1249,  126,  127,
    ++ /*  1430 */  1248,  113,  676,  337,  238,  338,  134,  363,  167, 1041,
    ++ /*  1440 */  1040,   56,  247,  367,  180,  897,  111,  895,  136, 1038,
    ++ /*  1450 */   818,  128,  138,  750,  261,  911,  185,  143,  145,   61,
    ++ /*  1460 */    62,   63,   64,  129,  914,  187,  188,  910,  118,   12,
    ++ /*  1470 */   189,  903,  268,  992,  203,  162,  398,  150,  149,  691,
    ++ /*  1480 */   402,  288,  194,  406,  151,  411,   66,   13,  729,  239,
    ++ /*  1490 */   282,   14,   67,  131,  837,  836,  865,  758,   15,    4,
    ++ /*  1500 */    68,  762,  175,  222,  224,  424,  152,  869,  791,  202,
    ++ /*  1510 */   786,   75,   72,  880,  866,  864,   16,   17,  920,  207,
    ++ /*  1520 */   919,  208,  447,  946,  164,  211,  947,  210,  165,  451,
    ++ /*  1530 */   868,  166,  315,  835,  701,   85,  212, 1297,  312,  952,
    ++ /*  1540 */  1296,
    + };
    + static const YYCODETYPE yy_lookahead[] = {
    +- /*     0 */    19,  144,  145,  146,  147,   24,    1,    2,   27,   80,
    +- /*    10 */    81,   82,   83,   84,   85,   86,   87,   88,   89,   90,
    +- /*    20 */    91,   92,   93,   94,   95,   91,   92,   93,   94,   95,
    +- /*    30 */    19,   50,   51,   80,   81,   82,   83,  212,   85,   86,
    +- /*    40 */    87,   88,   89,   90,   91,   92,   93,   94,   95,  224,
    +- /*    50 */   225,  226,   71,   72,   73,   74,   75,   76,   77,   78,
    +- /*    60 */    79,   80,   81,   82,   83,   95,   85,   86,   87,   88,
    +- /*    70 */    89,   90,   91,   92,   93,   94,   95,   19,   97,   85,
    +- /*    80 */    86,   87,   88,   89,   90,   91,   92,   93,   94,   95,
    +- /*    90 */    66,   33,   27,   28,   27,   28,   22,  201,  152,  152,
    +- /*   100 */    42,   27,  152,  224,  225,  226,   95,  211,   50,   51,
    +- /*   110 */    99,  100,  101,  102,  103,  104,  105,   27,   28,   59,
    +- /*   120 */   174,  175,  243,  112,  174,  175,   66,   94,   95,   71,
    +- /*   130 */    72,   73,   74,   75,   76,   77,   78,   79,   80,   81,
    +- /*   140 */    82,   83,  195,   85,   86,   87,   88,   89,   90,   91,
    +- /*   150 */    92,   93,   94,   95,   19,  209,   89,   90,  173,  209,
    +- /*   160 */   210,   26,   97,   98,   97,   98,  181,  100,  108,  109,
    +- /*   170 */   110,   97,  174,  152,  107,  152,  109,   89,   90,   91,
    +- /*   180 */    92,   93,   94,   95,  163,   50,   51,   97,   98,   99,
    +- /*   190 */    55,  244,  102,  103,  104,  174,  175,  174,  175,  132,
    +- /*   200 */   133,   89,   90,  113,   66,   19,   71,   72,   73,   74,
    +- /*   210 */    75,   76,   77,   78,   79,   80,   81,   82,   83,  198,
    +- /*   220 */    85,   86,   87,   88,   89,   90,   91,   92,   93,   94,
    +- /*   230 */    95,  152,  209,  210,  148,  149,   50,   51,  100,   53,
    +- /*   240 */   154,   59,  156,   22,  132,  133,  119,  120,  163,  163,
    +- /*   250 */    22,  192,  193,  174,  175,   27,   28,   71,   72,   73,
    +- /*   260 */    74,   75,   76,   77,   78,   79,   80,   81,   82,   83,
    +- /*   270 */   174,   85,   86,   87,   88,   89,   90,   91,   92,   93,
    +- /*   280 */    94,   95,   19,  198,  198,  174,  152,   24,  209,  210,
    +- /*   290 */   108,  109,  110,  192,  193,   27,   28,   69,  164,  165,
    +- /*   300 */    79,  119,  120,   27,   28,   27,   99,  222,  152,  102,
    +- /*   310 */   103,  104,   24,   50,   51,   27,   66,   89,   90,  185,
    +- /*   320 */   113,  187,   22,  157,  239,   97,   58,   27,   28,  101,
    +- /*   330 */   174,  175,  246,  163,   71,   72,   73,   74,   75,   76,
    +- /*   340 */    77,   78,   79,   80,   81,   82,   83,   11,   85,   86,
    +- /*   350 */    87,   88,   89,   90,   91,   92,   93,   94,   95,   19,
    +- /*   360 */   132,  133,  134,   23,  152,   97,   98,   91,  198,  119,
    +- /*   370 */   120,  152,   22,   97,   98,   97,  152,   27,   28,   27,
    +- /*   380 */    28,   27,   28,  227,  160,   97,  174,  175,  164,  165,
    +- /*   390 */    50,   51,  222,  174,  175,   59,  230,   97,   98,  233,
    +- /*   400 */   188,  137,   66,  139,  234,  187,  177,  188,  152,  239,
    +- /*   410 */    69,   71,   72,   73,   74,   75,   76,   77,   78,   79,
    +- /*   420 */    80,   81,   82,   83,   12,   85,   86,   87,   88,   89,
    +- /*   430 */    90,   91,   92,   93,   94,   95,   19,  177,   97,  152,
    +- /*   440 */    23,   29,  101,  152,  108,  109,  110,   97,   98,   97,
    +- /*   450 */    98,   97,   98,  224,  225,  226,   22,   45,   24,   47,
    +- /*   460 */   152,  152,  152,  152,  152,  174,  175,   50,   51,  249,
    +- /*   470 */   250,   59,   21,  132,  133,  134,  124,  221,  124,  188,
    +- /*   480 */   171,  172,  171,  172,  224,  225,  226,  152,   71,   72,
    +- /*   490 */    73,   74,   75,   76,   77,   78,   79,   80,   81,   82,
    +- /*   500 */    83,  152,   85,   86,   87,   88,   89,   90,   91,   92,
    +- /*   510 */    93,   94,   95,   19,  152,  183,   65,   23,  170,  171,
    +- /*   520 */   172,   19,   23,  174,  175,   26,  152,   50,   51,   12,
    +- /*   530 */   196,  197,   37,  170,  171,  172,  174,  175,  224,  225,
    +- /*   540 */   226,  232,  208,  232,   50,   51,   29,   52,  174,  175,
    +- /*   550 */   188,   74,   75,   51,  103,   60,  222,  163,  209,    0,
    +- /*   560 */     1,    2,   45,  152,   47,   71,   72,   73,   74,   75,
    +- /*   570 */    76,   77,   78,   79,   80,   81,   82,   83,  101,   85,
    +- /*   580 */    86,   87,   88,   89,   90,   91,   92,   93,   94,   95,
    +- /*   590 */    19,  140,  198,  152,   23,  152,   22,   98,   24,  152,
    +- /*   600 */   152,   27,  152,  183,  152,  152,  111,  213,  214,  107,
    +- /*   610 */   152,  164,  165,  152,  112,  174,  175,  174,  175,  181,
    +- /*   620 */   182,   50,   51,  124,  174,  175,  174,  175,  190,   26,
    +- /*   630 */    22,   23,   22,   23,   26,  166,   26,  168,  169,   16,
    +- /*   640 */    16,   19,   71,   72,   73,   74,   75,   76,   77,   78,
    +- /*   650 */    79,   80,   81,   82,   83,  152,   85,   86,   87,   88,
    +- /*   660 */    89,   90,   91,   92,   93,   94,   95,  152,  220,  196,
    +- /*   670 */   197,   97,   50,   51,  108,  109,  110,  152,   70,  221,
    +- /*   680 */    70,  208,    7,    8,    9,   62,   62,   64,   64,  174,
    +- /*   690 */   175,  146,  147,   71,   72,   73,   74,   75,   76,   77,
    +- /*   700 */    78,   79,   80,   81,   82,   83,  152,   85,   86,   87,
    +- /*   710 */    88,   89,   90,   91,   92,   93,   94,   95,   19,  152,
    +- /*   720 */   195,  152,   31,  220,  152,  152,   35,   26,  174,  175,
    +- /*   730 */   152,  163,  152,  130,  152,  115,  152,  117,  118,  152,
    +- /*   740 */    49,  174,  175,  174,  175,  152,  174,  175,   26,   50,
    +- /*   750 */    51,  152,  174,  175,  174,  175,  174,  175,  174,  175,
    +- /*   760 */   138,  174,  175,  140,   22,   23,  198,  174,  175,  152,
    +- /*   770 */    71,   72,   73,   74,   75,   76,   77,   78,   79,   80,
    +- /*   780 */    81,   82,   83,  152,   85,   86,   87,   88,   89,   90,
    +- /*   790 */    91,   92,   93,   94,   95,   19,  152,  152,  152,   98,
    +- /*   800 */    24,  152,  108,  109,  110,  174,  175,  152,  152,  152,
    +- /*   810 */   152,  152,   70,  152,  213,  214,  152,  152,  174,  175,
    +- /*   820 */   174,  175,  152,  174,  175,  124,   50,   51,  106,  174,
    +- /*   830 */   175,  174,  175,  174,  175,  174,  175,  138,  174,  175,
    +- /*   840 */   152,   22,   23,   22,  163,  189,   19,   71,   72,   73,
    +- /*   850 */    74,   75,   76,   77,   78,   79,   80,   81,   82,   83,
    +- /*   860 */   152,   85,   86,   87,   88,   89,   90,   91,   92,   93,
    +- /*   870 */    94,   95,  152,  152,  168,  169,  152,   50,   51,  198,
    +- /*   880 */   197,  152,  174,  175,  152,  240,  152,  152,  152,   70,
    +- /*   890 */   152,  208,  152,  152,  174,  175,  152,   19,   71,   72,
    +- /*   900 */    73,   74,   75,   76,   77,   78,   79,   80,   81,   82,
    +- /*   910 */    83,  152,   85,   86,   87,   88,   89,   90,   91,   92,
    +- /*   920 */    93,   94,   95,  152,  195,  247,  248,  152,   50,   51,
    +- /*   930 */   195,  195,  152,  174,  175,  195,  195,   26,  152,  195,
    +- /*   940 */   252,  220,  163,  122,  152,  174,  175,  163,   19,   71,
    +- /*   950 */    72,   73,   74,   75,   76,   77,   78,   79,   80,   81,
    +- /*   960 */    82,   83,  152,   85,   86,   87,   88,   89,   90,   91,
    +- /*   970 */    92,   93,   94,   95,  152,  195,  252,  198,  240,   50,
    +- /*   980 */    51,  189,  198,   19,  174,  175,   19,   51,   23,  100,
    +- /*   990 */   101,   26,   28,  163,  163,   28,  174,  175,  163,   19,
    +- /*  1000 */   152,   72,   73,   74,   75,   76,   77,   78,   79,   80,
    +- /*  1010 */    81,   82,   83,  152,   85,   86,   87,   88,   89,   90,
    +- /*  1020 */    91,   92,   93,   94,   95,  152,  240,  152,  198,  198,
    +- /*  1030 */    50,   51,   33,  198,  123,  174,  175,  116,    7,    8,
    +- /*  1040 */   101,   42,  121,  107,  152,  152,   23,  174,  175,   26,
    +- /*  1050 */   152,  112,  183,   73,   74,   75,   76,   77,   78,   79,
    +- /*  1060 */    80,   81,   82,   83,  152,   85,   86,   87,   88,   89,
    +- /*  1070 */    90,   91,   92,   93,   94,   95,   19,   20,   23,   22,
    +- /*  1080 */    23,   26,  152,  152,   27,   28,  174,  175,   23,   19,
    +- /*  1090 */    20,   26,   22,  132,  133,   38,  152,   27,   28,  152,
    +- /*  1100 */    23,  215,  152,   26,  174,  175,  152,   27,   38,  152,
    +- /*  1110 */    23,  152,   27,   26,   57,  152,   23,  163,  152,   26,
    +- /*  1120 */   152,  174,  175,   66,  174,  175,   69,   57,  174,  175,
    +- /*  1130 */    27,  174,  175,  174,  175,  152,   66,  174,  175,   69,
    +- /*  1140 */   174,  175,  174,  175,  152,   23,   89,   90,   26,   91,
    +- /*  1150 */   152,  236,  198,   96,   97,   98,  132,  133,  101,   89,
    +- /*  1160 */    90,  152,   23,  209,  210,   26,   96,   97,   98,  152,
    +- /*  1170 */   212,  101,  174,  175,  116,   19,   20,   97,   22,  121,
    +- /*  1180 */   152,  193,   97,   27,   28,  152,  152,  152,  152,  132,
    +- /*  1190 */   133,  134,  135,  136,   38,   23,  152,  152,   26,  152,
    +- /*  1200 */    97,  152,  132,  133,  134,  135,  136,  235,  152,  212,
    +- /*  1210 */   199,  150,  212,   57,  212,  200,  203,  216,  241,  216,
    +- /*  1220 */   241,  203,  182,   19,   20,   69,   22,  186,  178,  177,
    +- /*  1230 */   216,   27,   28,  229,  202,   39,  177,  177,  200,  155,
    +- /*  1240 */   245,  122,   38,   41,   22,   89,   90,   91,  159,  159,
    +- /*  1250 */   242,  159,   96,   97,   98,   71,  130,  101,  242,  191,
    +- /*  1260 */   223,   57,   18,  194,  159,  203,  194,  194,  194,   18,
    +- /*  1270 */   158,  223,  191,   69,  203,  159,  158,   19,   20,  191,
    +- /*  1280 */    22,  203,  137,   46,  238,   27,   28,  159,  132,  133,
    +- /*  1290 */   134,  135,  136,   89,   90,  159,   38,   22,  158,  179,
    +- /*  1300 */    96,   97,   98,  237,  158,  101,  159,  159,  158,  179,
    +- /*  1310 */   107,  176,   48,  176,  176,   57,  184,  106,  176,  125,
    +- /*  1320 */   179,  178,  218,  107,  217,  176,  218,   69,  184,  176,
    +- /*  1330 */   176,  217,  159,  218,  217,  159,  132,  133,  134,  135,
    +- /*  1340 */   136,  218,  217,  137,  179,   95,  179,   89,   90,  228,
    +- /*  1350 */   129,  126,  128,  127,   96,   97,   98,  206,  231,  101,
    +- /*  1360 */     5,   25,  231,  205,  207,   10,   11,   12,   13,   14,
    +- /*  1370 */   204,  203,   17,   26,  162,  161,   13,    6,  180,  180,
    +- /*  1380 */   153,  153,  151,  151,  151,  151,  167,   32,    4,   34,
    +- /*  1390 */   132,  133,  134,  135,  136,    3,   22,  142,   43,   68,
    +- /*  1400 */    15,   23,   16,  251,   23,  120,  251,  248,  131,  111,
    +- /*  1410 */   123,   56,   16,   20,  125,    1,  123,  131,   63,   79,
    +- /*  1420 */    79,   66,   67,  111,   36,   28,  122,    1,    5,   22,
    +- /*  1430 */   107,  140,   26,   54,   54,   44,   61,  107,   20,   24,
    +- /*  1440 */    19,  112,  105,   53,   22,   40,   22,   22,   53,   30,
    +- /*  1450 */    23,   22,   22,   53,   23,   23,   23,   22,  116,   23,
    +- /*  1460 */    22,  122,   23,   26,   23,   22,   11,  124,   28,  114,
    +- /*  1470 */    36,   26,   26,   23,   23,   23,  122,   23,   36,   26,
    +- /*  1480 */    36,   22,   24,   23,   22,    1,   23,   26,   22,   24,
    +- /*  1490 */    23,   22,  122,   23,   23,   22,  141,   23,  122,  122,
    +- /*  1500 */    15,
    ++ /*     0 */   144,  145,  146,  147,  172,  222,  223,  224,  222,  223,
    ++ /*    10 */   224,  152,  180,  152,  148,  149,  152,  173,  176,   19,
    ++ /*    20 */   154,  173,  156,  152,  163,  242,  152,  163,  176,  163,
    ++ /*    30 */    26,   31,  173,  174,  173,  174,  173,  173,  174,   39,
    ++ /*    40 */     1,    2,  152,   43,   44,   45,   46,   47,   48,   49,
    ++ /*    50 */    50,   51,   52,   53,   54,   55,   56,   57,  197,  169,
    ++ /*    60 */   170,  197,  188,  197,  222,  223,  224,  208,  209,  208,
    ++ /*    70 */   209,   19,  208,  152,  222,  223,  224,   22,   26,   24,
    ++ /*    80 */    46,   47,   48,   49,   84,   85,   86,   87,   88,   89,
    ++ /*    90 */    90,   91,   92,   93,   94,   43,   44,   45,   46,   47,
    ++ /*   100 */    48,   49,   50,   51,   52,   53,   54,   55,   56,   57,
    ++ /*   110 */   106,  245,  157,   88,   89,   90,   91,   92,   93,   94,
    ++ /*   120 */    68,  231,  251,   19,   84,   85,   86,   87,   88,   89,
    ++ /*   130 */    90,   91,   92,   93,   94,  101,   84,   85,   86,   87,
    ++ /*   140 */    88,   89,   90,   91,   92,   93,   94,   43,   44,   45,
    ++ /*   150 */    46,   47,   48,   49,   50,   51,   52,   53,   54,   55,
    ++ /*   160 */    56,   57,   90,   91,   92,   93,   94,   82,   79,   99,
    ++ /*   170 */    66,  200,  102,  103,  104,   19,  168,  169,  170,  152,
    ++ /*   180 */    24,  210,   97,  113,  229,   59,  101,  232,   84,   85,
    ++ /*   190 */    86,   87,   88,   89,   90,   91,   92,   93,   94,   43,
    ++ /*   200 */    44,   45,   46,   47,   48,   49,   50,   51,   52,   53,
    ++ /*   210 */    54,   55,   56,   57,  152,  188,  152,  132,  133,  134,
    ++ /*   220 */    93,   94,   96,   97,   98,   99,  152,   19,  102,  103,
    ++ /*   230 */   104,   23,   94,   72,   79,  173,  174,  173,  174,  113,
    ++ /*   240 */    84,   85,   86,   87,   88,   89,   90,   91,   92,   93,
    ++ /*   250 */    94,   43,   44,   45,   46,   47,   48,   49,   50,   51,
    ++ /*   260 */    52,   53,   54,   55,   56,   57,  152,  171,  152,  108,
    ++ /*   270 */   109,  110,  208,  209,  119,  120,  152,  180,  181,   19,
    ++ /*   280 */   119,  120,  152,   23,  152,  152,  189,  173,  174,  173,
    ++ /*   290 */   174,   59,   84,   85,   86,   87,   88,   89,   90,   91,
    ++ /*   300 */    92,   93,   94,   43,   44,   45,   46,   47,   48,   49,
    ++ /*   310 */    50,   51,   52,   53,   54,   55,   56,   57,  222,  223,
    ++ /*   320 */   224,  186,  208,  209,  208,  209,  194,  194,   96,   97,
    ++ /*   330 */    98,   19,  168,  169,  170,   23,   88,   89,  163,   59,
    ++ /*   340 */     0,    1,    2,  219,   84,   85,   86,   87,   88,   89,
    ++ /*   350 */    90,   91,   92,   93,   94,   43,   44,   45,   46,   47,
    ++ /*   360 */    48,   49,   50,   51,   52,   53,   54,   55,   56,   57,
    ++ /*   370 */    90,  152,  197,  195,  196,  243,   96,   97,   98,  196,
    ++ /*   380 */   132,   11,  134,   19,  182,  207,  115,   23,  117,  118,
    ++ /*   390 */   207,  163,  173,  174,  152,  220,   84,   85,   86,   87,
    ++ /*   400 */    88,   89,   90,   91,   92,   93,   94,   43,   44,   45,
    ++ /*   410 */    46,   47,   48,   49,   50,   51,   52,   53,   54,   55,
    ++ /*   420 */    56,   57,  152,   16,  152,  197,  171,  208,   22,   23,
    ++ /*   430 */    22,   23,   26,   16,   26,   19,    7,    8,    9,   23,
    ++ /*   440 */   212,  213,  152,  173,  174,  173,  174,   19,   84,   85,
    ++ /*   450 */    86,   87,   88,   89,   90,   91,   92,   93,   94,   43,
    ++ /*   460 */    44,   45,   46,   47,   48,   49,   50,   51,   52,   53,
    ++ /*   470 */    54,   55,   56,   57,   46,  152,  109,  110,  208,  109,
    ++ /*   480 */   110,  152,   75,  152,   77,   22,   23,   19,  233,   83,
    ++ /*   490 */   152,   83,   75,  238,   77,  164,  173,  174,  226,   59,
    ++ /*   500 */    84,   85,   86,   87,   88,   89,   90,   91,   92,   93,
    ++ /*   510 */    94,   43,   44,   45,   46,   47,   48,   49,   50,   51,
    ++ /*   520 */    52,   53,   54,   55,   56,   57,  108,  109,  110,  152,
    ++ /*   530 */   152,  152,   22,   22,   23,  107,   96,   97,   98,  160,
    ++ /*   540 */   112,  251,   19,  164,   22,  152,   83,  140,  219,  152,
    ++ /*   550 */   173,  174,   84,   85,   86,   87,   88,   89,   90,   91,
    ++ /*   560 */    92,   93,   94,   59,  124,  152,   43,   44,   45,   46,
    ++ /*   570 */    47,   48,   49,   50,   51,   52,   53,   54,   55,   56,
    ++ /*   580 */    57,   59,  169,  170,  119,  120,   82,  108,  109,  110,
    ++ /*   590 */   191,  192,  191,  192,   83,  248,  249,   19,   88,   89,
    ++ /*   600 */    96,   97,   24,  152,  152,  101,  138,   84,   85,   86,
    ++ /*   610 */    87,   88,   89,   90,   91,   92,   93,   94,   96,   97,
    ++ /*   620 */    98,   43,   44,   45,   46,   47,   48,   49,   50,   51,
    ++ /*   630 */    52,   53,   54,   55,   56,   57,  132,  133,  134,  152,
    ++ /*   640 */   152,   46,  152,   26,  231,  194,  194,  146,  147,   19,
    ++ /*   650 */   152,  116,  152,   72,  152,  152,  121,  152,  152,  152,
    ++ /*   660 */    79,  138,   84,   85,   86,   87,   88,   89,   90,   91,
    ++ /*   670 */    92,   93,   94,   43,   44,   45,   46,   47,   48,   49,
    ++ /*   680 */    50,   51,   52,   53,   54,   55,   56,   57,  152,  108,
    ++ /*   690 */    23,  152,  194,   26,  194,  152,  194,  194,  137,  152,
    ++ /*   700 */   139,   19,  107,  166,  167,  218,  218,   29,  218,  173,
    ++ /*   710 */   174,   33,  173,  174,   84,   85,   86,   87,   88,   89,
    ++ /*   720 */    90,   91,   92,   93,   94,   43,   44,   45,   46,   47,
    ++ /*   730 */    48,   49,   50,   51,   52,   53,   54,   55,   56,   57,
    ++ /*   740 */   152,  194,   64,  171,  239,  239,  239,  130,  166,  167,
    ++ /*   750 */   212,  213,   19,   23,  246,  247,   26,   59,   26,  152,
    ++ /*   760 */   163,  218,  163,  163,  163,   98,   84,   85,   86,   87,
    ++ /*   770 */    88,   89,   90,   91,   92,   93,   94,   44,   45,   46,
    ++ /*   780 */    47,   48,   49,   50,   51,   52,   53,   54,   55,   56,
    ++ /*   790 */    57,  124,   26,   79,  197,   97,  197,  197,  197,   31,
    ++ /*   800 */   152,   23,   19,   19,   26,   19,  218,   39,   23,   21,
    ++ /*   810 */   238,   26,  163,  163,  100,   59,  163,   84,   85,   86,
    ++ /*   820 */    87,   88,   89,   90,   91,   92,   93,   94,   45,   46,
    ++ /*   830 */    47,   48,   49,   50,   51,   52,   53,   54,   55,   56,
    ++ /*   840 */    57,   19,   20,  152,   22,   23,  197,  197,   23,   19,
    ++ /*   850 */   197,   26,  152,   97,   23,  123,   23,   26,   36,   26,
    ++ /*   860 */   152,  152,   19,   20,   98,   22,   78,   84,   85,   86,
    ++ /*   870 */    87,   88,   89,   90,   91,   92,   93,   94,   94,   36,
    ++ /*   880 */   152,   59,   96,   99,  100,  101,  102,  103,  104,  105,
    ++ /*   890 */   124,  103,   70,  100,  101,   23,  112,   12,   26,   12,
    ++ /*   900 */    23,   79,   59,   26,   82,  101,   22,    7,    8,  152,
    ++ /*   910 */    88,   89,   27,   70,   27,  152,  112,   95,   96,   97,
    ++ /*   920 */    98,  152,   79,  101,   22,   82,   96,   42,  140,   42,
    ++ /*   930 */   182,   88,   89,   19,   20,  132,   22,  134,   95,   96,
    ++ /*   940 */    97,   98,   23,   59,  101,   26,   22,   62,  152,   62,
    ++ /*   950 */    36,   22,   59,   24,  132,  133,  134,  135,  136,   72,
    ++ /*   960 */     5,   59,  152,   22,   71,   10,   11,   12,   13,   14,
    ++ /*   970 */   152,  152,   17,   59,  182,  132,  133,  134,  135,  136,
    ++ /*   980 */    96,   97,   98,   59,   70,   30,  152,   32,   59,   96,
    ++ /*   990 */    97,   98,  173,  174,   53,   40,   82,  152,   96,   97,
    ++ /*  1000 */    98,   90,   88,   89,   90,   24,  187,  173,  174,   95,
    ++ /*  1010 */    96,   97,   98,  152,  152,  101,   19,   20,  152,   22,
    ++ /*  1020 */    96,   97,   98,  152,   69,   59,   97,  116,   59,  214,
    ++ /*  1030 */   152,   76,  121,   36,   79,   80,   19,   20,  152,   22,
    ++ /*  1040 */    59,  132,   59,  134,  173,  174,  132,  133,  134,  135,
    ++ /*  1050 */   136,  173,  174,   36,  234,  152,   59,  152,  187,  173,
    ++ /*  1060 */   174,  211,   96,   97,   98,  187,   97,   70,   23,  114,
    ++ /*  1070 */   152,   26,   23,  187,   23,   26,   59,   26,   97,   82,
    ++ /*  1080 */    97,   22,  164,  152,  152,   88,   89,   70,  192,  152,
    ++ /*  1090 */   124,  152,   95,   96,   97,   98,  141,  152,  101,   82,
    ++ /*  1100 */   152,  152,  184,  152,  186,   88,   89,  199,   54,   55,
    ++ /*  1110 */    56,   57,   95,   96,   97,   98,  152,  152,  101,  152,
    ++ /*  1120 */   152,  173,  174,  235,   54,   55,   56,   57,   58,  132,
    ++ /*  1130 */   133,  134,  135,  136,  211,  150,   59,  211,   84,   85,
    ++ /*  1140 */    86,   87,   88,   89,   90,   91,   92,   93,   94,  132,
    ++ /*  1150 */   133,  134,  135,  136,   84,   85,   86,   87,   88,   89,
    ++ /*  1160 */    90,   91,   92,   93,   94,   88,   89,  195,  196,   35,
    ++ /*  1170 */   211,  211,  152,   96,   97,   98,  152,  100,  198,  207,
    ++ /*  1180 */   171,  122,  240,  152,  107,  215,  109,  240,  202,  215,
    ++ /*  1190 */   202,  152,  220,  173,  174,  177,  185,  173,  174,   65,
    ++ /*  1200 */   152,  176,  152,  181,  173,  174,  215,   73,  176,  132,
    ++ /*  1210 */   228,  134,  173,  174,  176,  152,  201,  152,  199,  155,
    ++ /*  1220 */   152,  173,  174,  173,  174,   60,  152,  122,  244,   38,
    ++ /*  1230 */   159,  159,  152,  241,  241,  152,  173,  174,  173,  174,
    ++ /*  1240 */   152,  173,  174,  152,  159,  111,  152,  173,  174,  152,
    ++ /*  1250 */    22,  152,   43,  173,  174,  152,  173,  174,  152,  190,
    ++ /*  1260 */   130,  173,  174,  152,  173,  174,  152,  173,  174,  202,
    ++ /*  1270 */   173,  174,  173,  174,  152,   18,  173,  174,  152,  173,
    ++ /*  1280 */   174,  152,  221,  152,  173,  174,  193,  173,  174,  152,
    ++ /*  1290 */   158,  152,  159,  152,   22,  173,  174,  152,   18,  173,
    ++ /*  1300 */   174,  152,  173,  174,  173,  174,  152,  221,  152,  193,
    ++ /*  1310 */   173,  174,  173,  174,  173,  174,  152,  193,  173,  174,
    ++ /*  1320 */   152,  193,  173,  174,  158,  152,  190,  173,  174,  173,
    ++ /*  1330 */   174,   59,  152,  190,  159,  137,  152,  173,  174,  152,
    ++ /*  1340 */   202,  173,  174,   61,  152,  237,  173,  174,  202,  236,
    ++ /*  1350 */    22,  107,  159,  173,  174,  159,  178,  173,  174,  158,
    ++ /*  1360 */   173,  174,  159,  158,  158,  173,  174,  159,  178,   97,
    ++ /*  1370 */   175,   63,  175,  106,  175,  125,  217,  183,  178,  175,
    ++ /*  1380 */   107,  159,   22,  216,  177,  175,  217,  175,  175,  217,
    ++ /*  1390 */   216,  159,  216,  216,  183,  225,  217,  137,  227,  178,
    ++ /*  1400 */    94,  178,  126,  129,   25,  128,  127,  162,  206,   26,
    ++ /*  1410 */   161,  230,  230,   13,  153,  153,    6,  151,  203,  205,
    ++ /*  1420 */   204,  202,  151,  165,  171,  171,  151,  171,  165,  165,
    ++ /*  1430 */   171,  179,    4,  250,  179,  250,  247,    3,   22,  171,
    ++ /*  1440 */   171,  171,  142,   81,   15,   23,   16,   23,  131,  171,
    ++ /*  1450 */   120,  111,  123,   20,   16,    1,  125,  123,  131,   53,
    ++ /*  1460 */    53,   53,   53,  111,   96,   34,  122,    1,    5,   22,
    ++ /*  1470 */   107,   67,  140,   74,   26,   24,   41,  107,   67,   20,
    ++ /*  1480 */    19,  112,  105,   66,   22,   66,   22,   22,   28,   66,
    ++ /*  1490 */    23,   22,   22,   37,   23,   23,   23,  116,   22,   22,
    ++ /*  1500 */    26,   23,  122,   23,   23,   26,   22,   11,   96,   34,
    ++ /*  1510 */   124,   26,   26,   23,   23,   23,   34,   34,   23,   26,
    ++ /*  1520 */    23,   22,   24,   23,   22,  122,   23,   26,   22,   24,
    ++ /*  1530 */    23,   22,   15,   23,   23,   22,  122,  122,   23,    1,
    ++ /*  1540 */   122,  252,  252,  252,  252,  252,  252,  252,  252,  252,
    ++ /*  1550 */   252,  252,  252,  252,  252,  252,  252,  252,  252,  252,
    ++ /*  1560 */   252,  252,  252,  252,  252,  252,  252,  252,  252,  252,
    ++ /*  1570 */   252,  252,  252,  252,  252,  252,  252,  252,  252,  252,
    ++ /*  1580 */   252,  252,  252,  252,  252,  252,  252,  252,  252,  252,
    ++ /*  1590 */   252,  252,  252,  252,  252,  252,  252,  252,  252,  252,
    ++ /*  1600 */   252,  252,  252,  252,  252,  252,  252,  252,  252,  252,
    ++ /*  1610 */   252,  252,  252,  252,  252,  252,  252,  252,  252,  252,
    ++ /*  1620 */   252,  252,  252,  252,  252,  252,  252,  252,  252,  252,
    ++ /*  1630 */   252,  252,  252,  252,  252,  252,  252,  252,  252,  252,
    ++ /*  1640 */   252,  252,  252,  252,  252,  252,  252,  252,  252,  252,
    ++ /*  1650 */   252,  252,  252,  252,  252,  252,  252,  252,  252,  252,
    ++ /*  1660 */   252,  252,  252,  252,  252,  252,  252,  252,  252,  252,
    ++ /*  1670 */   252,  252,  252,  252,  252,  252,  252,  252,  252,  252,
    ++ /*  1680 */   252,  252,  252,  252,
    + };
    +-#define YY_SHIFT_USE_DFLT (-72)
    +-#define YY_SHIFT_COUNT (435)
    +-#define YY_SHIFT_MIN   (-71)
    +-#define YY_SHIFT_MAX   (1485)
    +-static const short yy_shift_ofst[] = {
    +- /*     0 */     5, 1057, 1355, 1070, 1204, 1204, 1204,   90,   60,  -19,
    +- /*    10 */    58,   58,  186, 1204, 1204, 1204, 1204, 1204, 1204, 1204,
    +- /*    20 */    67,   67,  182,  336,   65,  250,  135,  263,  340,  417,
    +- /*    30 */   494,  571,  622,  699,  776,  827,  827,  827,  827,  827,
    +- /*    40 */   827,  827,  827,  827,  827,  827,  827,  827,  827,  827,
    +- /*    50 */   878,  827,  929,  980,  980, 1156, 1204, 1204, 1204, 1204,
    +- /*    60 */  1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204,
    +- /*    70 */  1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204,
    +- /*    80 */  1204, 1204, 1204, 1204, 1258, 1204, 1204, 1204, 1204, 1204,
    +- /*    90 */  1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204,  -71,  -47,
    +- /*   100 */   -47,  -47,  -47,  -47,   -6,   88,  -66,   65,   65,  451,
    +- /*   110 */   502,  112,  112,   33,  127,  278,  -30,  -72,  -72,  -72,
    +- /*   120 */    11,  412,  412,  268,  608,  610,   65,   65,   65,   65,
    +- /*   130 */    65,   65,   65,   65,   65,   65,   65,   65,   65,   65,
    +- /*   140 */    65,   65,   65,   65,   65,  559,  138,  278,  127,   24,
    +- /*   150 */    24,   24,   24,   24,   24,  -72,  -72,  -72,  228,  341,
    +- /*   160 */   341,  207,  276,  300,  352,  354,  350,   65,   65,   65,
    +- /*   170 */    65,   65,   65,   65,   65,   65,   65,   65,   65,   65,
    +- /*   180 */    65,   65,   65,   65,  495,  495,  495,   65,   65,  499,
    +- /*   190 */    65,   65,   65,  574,   65,   65,  517,   65,   65,   65,
    +- /*   200 */    65,   65,   65,   65,   65,   65,   65,  566,  691,  288,
    +- /*   210 */   288,  288,  701,  620, 1058,  675,  603,  964,  964,  967,
    +- /*   220 */   603,  967,  722,  965,  936,  999,  964,  264,  999,  999,
    +- /*   230 */   911,  921,  434, 1196, 1119, 1119, 1202, 1202, 1119, 1222,
    +- /*   240 */  1184, 1126, 1244, 1244, 1244, 1244, 1119, 1251, 1126, 1222,
    +- /*   250 */  1184, 1184, 1126, 1119, 1251, 1145, 1237, 1119, 1119, 1251,
    +- /*   260 */  1275, 1119, 1251, 1119, 1251, 1275, 1203, 1203, 1203, 1264,
    +- /*   270 */  1275, 1203, 1211, 1203, 1264, 1203, 1203, 1194, 1216, 1194,
    +- /*   280 */  1216, 1194, 1216, 1194, 1216, 1119, 1119, 1206, 1275, 1250,
    +- /*   290 */  1250, 1275, 1221, 1225, 1224, 1226, 1126, 1336, 1347, 1363,
    +- /*   300 */  1363, 1371, 1371, 1371, 1371,  -72,  -72,  -72,  -72,  -72,
    +- /*   310 */   -72,  477,  623,  742,  819,  624,  694,   74, 1023,  221,
    +- /*   320 */  1055, 1065, 1077, 1087, 1080,  889, 1031,  939, 1093, 1122,
    +- /*   330 */  1085, 1139,  961, 1024, 1172, 1103,  821, 1384, 1392, 1374,
    +- /*   340 */  1255, 1385, 1331, 1386, 1378, 1381, 1285, 1277, 1298, 1287,
    +- /*   350 */  1393, 1289, 1396, 1414, 1293, 1286, 1340, 1341, 1312, 1397,
    +- /*   360 */  1388, 1304, 1426, 1423, 1407, 1323, 1291, 1379, 1406, 1380,
    +- /*   370 */  1375, 1391, 1330, 1415, 1418, 1421, 1329, 1337, 1422, 1390,
    +- /*   380 */  1424, 1425, 1427, 1429, 1395, 1419, 1430, 1400, 1405, 1431,
    +- /*   390 */  1432, 1433, 1342, 1435, 1436, 1438, 1437, 1339, 1439, 1441,
    +- /*   400 */  1440, 1434, 1443, 1343, 1445, 1442, 1446, 1444, 1445, 1450,
    +- /*   410 */  1451, 1452, 1453, 1454, 1459, 1455, 1460, 1462, 1458, 1461,
    +- /*   420 */  1463, 1466, 1465, 1461, 1467, 1469, 1470, 1471, 1473, 1354,
    +- /*   430 */  1370, 1376, 1377, 1474, 1485, 1484,
    ++#define YY_SHIFT_COUNT    (465)
    ++#define YY_SHIFT_MIN      (0)
    ++#define YY_SHIFT_MAX      (1538)
    ++static const unsigned short int yy_shift_ofst[] = {
    ++ /*     0 */    39,  822,  955,  843,  997,  997,  997,  997,    0,    0,
    ++ /*    10 */   104,  630,  997,  997,  997,  997,  997,  997,  997, 1077,
    ++ /*    20 */  1077,  126,  161,  155,   52,  156,  208,  260,  312,  364,
    ++ /*    30 */   416,  468,  523,  578,  630,  630,  630,  630,  630,  630,
    ++ /*    40 */   630,  630,  630,  630,  630,  630,  630,  630,  630,  630,
    ++ /*    50 */   630,  682,  630,  733,  783,  783,  914,  997,  997,  997,
    ++ /*    60 */   997,  997,  997,  997,  997,  997,  997,  997,  997,  997,
    ++ /*    70 */   997,  997,  997,  997,  997,  997,  997,  997,  997,  997,
    ++ /*    80 */   997,  997,  997,  997,  997,  997,  997,  997, 1017,  997,
    ++ /*    90 */   997,  997,  997,  997,  997,  997,  997,  997,  997,  997,
    ++ /*   100 */   997,  997, 1070, 1054, 1054, 1054, 1054, 1054,   40,   25,
    ++ /*   110 */    72,  232,  788,  428,  248,  248,  232,  581,  367,  127,
    ++ /*   120 */   465,  138, 1541, 1541, 1541,  784,  784,  784,  522,  522,
    ++ /*   130 */   887,  887,  893,  406,  408,  232,  232,  232,  232,  232,
    ++ /*   140 */   232,  232,  232,  232,  232,  232,  232,  232,  232,  232,
    ++ /*   150 */   232,  232,  232,  232,  232,  370,  340,  714,  698,  698,
    ++ /*   160 */   465,   89,   89,   89,   89,   89,   89, 1541, 1541, 1541,
    ++ /*   170 */   504,   85,   85,  884,   70,  280,  902,  440,  966,  924,
    ++ /*   180 */   232,  232,  232,  232,  232,  232,  232,  232,  232,  232,
    ++ /*   190 */   232,  232,  232,  232,  232,  232, 1134, 1134, 1134,  232,
    ++ /*   200 */   232,  667,  232,  232,  232,  929,  232,  232,  885,  232,
    ++ /*   210 */   232,  232,  232,  232,  232,  232,  232,  232,  232,  418,
    ++ /*   220 */   678,  981,  981,  981,  981,  766,  271,  911,  510,  429,
    ++ /*   230 */   617,  786,  786,  830,  617,  830,    4,  730,  595,  768,
    ++ /*   240 */   786,  561,  768,  768,  732,  535,   55, 1165, 1105, 1105,
    ++ /*   250 */  1191, 1191, 1105, 1228, 1209, 1130, 1257, 1257, 1257, 1257,
    ++ /*   260 */  1105, 1280, 1130, 1228, 1209, 1209, 1130, 1105, 1280, 1198,
    ++ /*   270 */  1282, 1105, 1105, 1280, 1328, 1105, 1280, 1105, 1280, 1328,
    ++ /*   280 */  1244, 1244, 1244, 1308, 1328, 1244, 1267, 1244, 1308, 1244,
    ++ /*   290 */  1244, 1250, 1273, 1250, 1273, 1250, 1273, 1250, 1273, 1105,
    ++ /*   300 */  1360, 1105, 1260, 1328, 1306, 1306, 1328, 1274, 1276, 1277,
    ++ /*   310 */  1279, 1130, 1379, 1383, 1400, 1400, 1410, 1410, 1410, 1541,
    ++ /*   320 */  1541, 1541, 1541, 1541, 1541, 1541, 1541, 1541, 1541, 1541,
    ++ /*   330 */  1541, 1541, 1541, 1541, 1541,   34,  407,  463,  511,  417,
    ++ /*   340 */   479, 1272,  778,  941,  785,  825,  831,  833,  872,  877,
    ++ /*   350 */   756,  793,  900,  804,  919, 1045,  969, 1049,  803,  909,
    ++ /*   360 */  1051,  983, 1059, 1428, 1434, 1416, 1300, 1429, 1362, 1430,
    ++ /*   370 */  1422, 1424, 1330, 1317, 1340, 1329, 1433, 1331, 1438, 1454,
    ++ /*   380 */  1334, 1327, 1406, 1407, 1408, 1409, 1352, 1368, 1431, 1344,
    ++ /*   390 */  1466, 1463, 1447, 1363, 1332, 1404, 1448, 1411, 1399, 1435,
    ++ /*   400 */  1370, 1451, 1459, 1461, 1369, 1377, 1462, 1417, 1464, 1465,
    ++ /*   410 */  1467, 1469, 1419, 1460, 1470, 1423, 1456, 1471, 1472, 1473,
    ++ /*   420 */  1474, 1381, 1476, 1478, 1477, 1479, 1380, 1480, 1481, 1412,
    ++ /*   430 */  1475, 1484, 1386, 1485, 1482, 1486, 1483, 1490, 1485, 1491,
    ++ /*   440 */  1492, 1495, 1493, 1497, 1499, 1496, 1500, 1502, 1498, 1501,
    ++ /*   450 */  1503, 1506, 1505, 1501, 1507, 1509, 1510, 1511, 1513, 1403,
    ++ /*   460 */  1414, 1415, 1418, 1515, 1517, 1538,
    + };
    +-#define YY_REDUCE_USE_DFLT (-176)
    +-#define YY_REDUCE_COUNT (310)
    +-#define YY_REDUCE_MIN   (-175)
    +-#define YY_REDUCE_MAX   (1234)
    ++#define YY_REDUCE_COUNT (334)
    ++#define YY_REDUCE_MIN   (-217)
    ++#define YY_REDUCE_MAX   (1278)
    + static const short yy_reduce_ofst[] = {
    +- /*     0 */  -143,  954,   86,   21,  -50,   23,   79,  134,  170, -175,
    +- /*    10 */   229,  260, -121,  212,  219,  291,  -54,  349,  362,  156,
    +- /*    20 */   309,  311,  334,   85,  224,  394,  314,  314,  314,  314,
    +- /*    30 */   314,  314,  314,  314,  314,  314,  314,  314,  314,  314,
    +- /*    40 */   314,  314,  314,  314,  314,  314,  314,  314,  314,  314,
    +- /*    50 */   314,  314,  314,  314,  314,  374,  441,  443,  450,  452,
    +- /*    60 */   515,  554,  567,  569,  572,  578,  580,  582,  584,  587,
    +- /*    70 */   593,  631,  644,  646,  649,  655,  657,  659,  661,  664,
    +- /*    80 */   708,  720,  759,  771,  810,  822,  861,  873,  912,  930,
    +- /*    90 */   947,  950,  957,  959,  963,  966,  968,  998,  314,  314,
    +- /*   100 */   314,  314,  314,  314,  314,  314,  314,  447,  -53,  166,
    +- /*   110 */   438,  348,  363,  314,  473,  469,  314,  314,  314,  314,
    +- /*   120 */   -15,   59,  101,  688,  220,  220,  525,  256,  729,  735,
    +- /*   130 */   736,  740,  741,  744,  645,  448,  738,  458,  786,  503,
    +- /*   140 */   780,  656,  721,  724,  792,  545,  568,  706,  683,  681,
    +- /*   150 */   779,  784,  830,  831,  835,  678,  601, -104,   -2,   96,
    +- /*   160 */   111,  218,  287,  308,  310,  312,  335,  411,  453,  461,
    +- /*   170 */   573,  599,  617,  658,  665,  670,  732,  734,  775,  848,
    +- /*   180 */   875,  892,  893,  898,  332,  420,  869,  931,  944,  886,
    +- /*   190 */   983,  992, 1009,  958, 1017, 1028,  988, 1033, 1034, 1035,
    +- /*   200 */   287, 1036, 1044, 1045, 1047, 1049, 1056,  915,  972,  997,
    +- /*   210 */  1000, 1002,  886, 1011, 1015, 1061, 1013, 1001, 1003,  977,
    +- /*   220 */  1018,  979, 1050, 1041, 1040, 1052, 1014, 1004, 1059, 1060,
    +- /*   230 */  1032, 1038, 1084,  995, 1089, 1090, 1008, 1016, 1092, 1037,
    +- /*   240 */  1068, 1062, 1069, 1072, 1073, 1074, 1105, 1112, 1071, 1048,
    +- /*   250 */  1081, 1088, 1078, 1116, 1118, 1046, 1066, 1128, 1136, 1140,
    +- /*   260 */  1120, 1147, 1146, 1148, 1150, 1130, 1135, 1137, 1138, 1132,
    +- /*   270 */  1141, 1142, 1143, 1149, 1144, 1153, 1154, 1104, 1107, 1108,
    +- /*   280 */  1114, 1115, 1117, 1123, 1125, 1173, 1176, 1121, 1165, 1127,
    +- /*   290 */  1131, 1167, 1157, 1151, 1158, 1166, 1168, 1212, 1214, 1227,
    +- /*   300 */  1228, 1231, 1232, 1233, 1234, 1152, 1155, 1159, 1198, 1199,
    +- /*   310 */  1219,
    ++ /*     0 */  -144, -139, -134, -136, -141,   64,  114,  116, -158, -148,
    ++ /*    10 */  -217,   96,  819,  871,  878,  219,  270,  886,  272, -110,
    ++ /*    20 */   413,  918,  972,  228, -214, -214, -214, -214, -214, -214,
    ++ /*    30 */  -214, -214, -214, -214, -214, -214, -214, -214, -214, -214,
    ++ /*    40 */  -214, -214, -214, -214, -214, -214, -214, -214, -214, -214,
    ++ /*    50 */  -214, -214, -214, -214, -214, -214,   62,  323,  377,  536,
    ++ /*    60 */   539,  834,  948, 1020, 1024, 1031, 1039, 1048, 1050, 1063,
    ++ /*    70 */  1065, 1068, 1074, 1080, 1083, 1088, 1091, 1094, 1097, 1099,
    ++ /*    80 */  1103, 1106, 1111, 1114, 1122, 1126, 1129, 1131, 1137, 1139,
    ++ /*    90 */  1141, 1145, 1149, 1154, 1156, 1164, 1168, 1173, 1180, 1184,
    ++ /*   100 */  1187, 1192, -214, -214, -214, -214, -214, -214, -214, -214,
    ++ /*   110 */  -214,  132,  -45,   97,    8,  164,  379,  175,  255, -214,
    ++ /*   120 */   178, -214, -214, -214, -214, -168, -168, -168,  124,  329,
    ++ /*   130 */   399,  401, -129,  347,  347,  331,  133,  451,  452,  498,
    ++ /*   140 */   500,  502,  503,  505,  487,  506,  488,  490,  507,  543,
    ++ /*   150 */   547, -126,  588,  290,   27,  572,  501,  597,  537,  582,
    ++ /*   160 */   183,  599,  600,  601,  649,  650,  653,  508,  538,  -29,
    ++ /*   170 */  -156, -152, -137,  -79,  135,   74,  130,  242,  338,  378,
    ++ /*   180 */   393,  397,  607,  648,  691,  700,  708,  709,  728,  757,
    ++ /*   190 */   763,  769,  796,  810,  818,  845,  202,  748,  792,  861,
    ++ /*   200 */   862,  815,  866,  903,  905,  850,  931,  932,  896,  937,
    ++ /*   210 */   939,  945,   74,  949,  951,  964,  965,  967,  968,  888,
    ++ /*   220 */   820,  923,  926,  959,  960,  815,  980,  908, 1009,  985,
    ++ /*   230 */   986,  970,  974,  942,  988,  947, 1018, 1011, 1022, 1025,
    ++ /*   240 */   991,  982, 1032, 1038, 1015, 1019, 1064,  984, 1071, 1072,
    ++ /*   250 */   992,  993, 1085, 1061, 1069, 1067, 1093, 1116, 1124, 1128,
    ++ /*   260 */  1133, 1132, 1138, 1086, 1136, 1143, 1146, 1175, 1166, 1108,
    ++ /*   270 */  1113, 1193, 1196, 1201, 1178, 1203, 1205, 1208, 1206, 1190,
    ++ /*   280 */  1195, 1197, 1199, 1194, 1200, 1204, 1207, 1210, 1211, 1212,
    ++ /*   290 */  1213, 1159, 1167, 1169, 1174, 1172, 1176, 1179, 1177, 1222,
    ++ /*   300 */  1170, 1232, 1171, 1221, 1181, 1182, 1223, 1202, 1214, 1216,
    ++ /*   310 */  1215, 1219, 1245, 1249, 1261, 1262, 1266, 1271, 1275, 1183,
    ++ /*   320 */  1185, 1189, 1258, 1253, 1254, 1256, 1259, 1263, 1252, 1255,
    ++ /*   330 */  1268, 1269, 1270, 1278, 1264,
    + };
    + static const YYACTIONTYPE yy_default[] = {
    +- /*     0 */   982, 1300, 1300, 1300, 1214, 1214, 1214, 1305, 1300, 1109,
    +- /*    10 */  1138, 1138, 1274, 1305, 1305, 1305, 1305, 1305, 1305, 1212,
    +- /*    20 */  1305, 1305, 1305, 1300, 1305, 1113, 1144, 1305, 1305, 1305,
    +- /*    30 */  1305, 1305, 1305, 1305, 1305, 1273, 1275, 1152, 1151, 1254,
    +- /*    40 */  1125, 1149, 1142, 1146, 1215, 1208, 1209, 1207, 1211, 1216,
    +- /*    50 */  1305, 1145, 1177, 1192, 1176, 1305, 1305, 1305, 1305, 1305,
    +- /*    60 */  1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305,
    +- /*    70 */  1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305,
    +- /*    80 */  1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305,
    +- /*    90 */  1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1186, 1191,
    +- /*   100 */  1198, 1190, 1187, 1179, 1178, 1180, 1181, 1305, 1305, 1008,
    +- /*   110 */  1074, 1305, 1305, 1182, 1305, 1020, 1183, 1195, 1194, 1193,
    +- /*   120 */  1015, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305,
    +- /*   130 */  1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305,
    +- /*   140 */  1305, 1305, 1305, 1305, 1305,  982, 1300, 1305, 1305, 1300,
    +- /*   150 */  1300, 1300, 1300, 1300, 1300, 1292, 1113, 1103, 1305, 1305,
    +- /*   160 */  1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1280, 1278,
    +- /*   170 */  1305, 1227, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305,
    +- /*   180 */  1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305,
    +- /*   190 */  1305, 1305, 1305, 1109, 1305, 1305, 1305, 1305, 1305, 1305,
    +- /*   200 */  1305, 1305, 1305, 1305, 1305, 1305,  988, 1305, 1247, 1109,
    +- /*   210 */  1109, 1109, 1111, 1089, 1101,  990, 1148, 1127, 1127, 1259,
    +- /*   220 */  1148, 1259, 1045, 1068, 1042, 1138, 1127, 1210, 1138, 1138,
    +- /*   230 */  1110, 1101, 1305, 1285, 1118, 1118, 1277, 1277, 1118, 1157,
    +- /*   240 */  1078, 1148, 1085, 1085, 1085, 1085, 1118, 1005, 1148, 1157,
    +- /*   250 */  1078, 1078, 1148, 1118, 1005, 1253, 1251, 1118, 1118, 1005,
    +- /*   260 */  1220, 1118, 1005, 1118, 1005, 1220, 1076, 1076, 1076, 1060,
    +- /*   270 */  1220, 1076, 1045, 1076, 1060, 1076, 1076, 1131, 1126, 1131,
    +- /*   280 */  1126, 1131, 1126, 1131, 1126, 1118, 1118, 1305, 1220, 1224,
    +- /*   290 */  1224, 1220, 1143, 1132, 1141, 1139, 1148, 1011, 1063,  998,
    +- /*   300 */   998,  987,  987,  987,  987, 1297, 1297, 1292, 1047, 1047,
    +- /*   310 */  1030, 1305, 1305, 1305, 1305, 1305, 1305, 1022, 1305, 1229,
    +- /*   320 */  1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305,
    +- /*   330 */  1305, 1305, 1305, 1305, 1305, 1305, 1164, 1305,  983, 1287,
    +- /*   340 */  1305, 1305, 1284, 1305, 1305, 1305, 1305, 1305, 1305, 1305,
    +- /*   350 */  1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305,
    +- /*   360 */  1305, 1257, 1305, 1305, 1305, 1305, 1305, 1305, 1250, 1249,
    +- /*   370 */  1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305,
    +- /*   380 */  1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305,
    +- /*   390 */  1305, 1305, 1092, 1305, 1305, 1305, 1096, 1305, 1305, 1305,
    +- /*   400 */  1305, 1305, 1305, 1305, 1140, 1305, 1133, 1305, 1213, 1305,
    +- /*   410 */  1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1302,
    +- /*   420 */  1305, 1305, 1305, 1301, 1305, 1305, 1305, 1305, 1305, 1166,
    +- /*   430 */  1305, 1165, 1169, 1305,  996, 1305,
    ++ /*     0 */  1286, 1276, 1276, 1276, 1209, 1209, 1209, 1209, 1133, 1133,
    ++ /*    10 */  1260, 1036, 1005, 1005, 1005, 1005, 1005, 1005, 1208, 1005,
    ++ /*    20 */  1005, 1005, 1005, 1108, 1139, 1005, 1005, 1005, 1005, 1210,
    ++ /*    30 */  1211, 1005, 1005, 1005, 1259, 1261, 1149, 1148, 1147, 1146,
    ++ /*    40 */  1242, 1120, 1144, 1137, 1141, 1210, 1204, 1205, 1203, 1207,
    ++ /*    50 */  1211, 1005, 1140, 1174, 1188, 1173, 1005, 1005, 1005, 1005,
    ++ /*    60 */  1005, 1005, 1005, 1005, 1005, 1005, 1005, 1005, 1005, 1005,
    ++ /*    70 */  1005, 1005, 1005, 1005, 1005, 1005, 1005, 1005, 1005, 1005,
    ++ /*    80 */  1005, 1005, 1005, 1005, 1005, 1005, 1005, 1005, 1005, 1005,
    ++ /*    90 */  1005, 1005, 1005, 1005, 1005, 1005, 1005, 1005, 1005, 1005,
    ++ /*   100 */  1005, 1005, 1182, 1187, 1194, 1186, 1183, 1176, 1175, 1177,
    ++ /*   110 */  1178, 1005, 1026, 1075, 1005, 1005, 1005, 1276, 1036, 1179,
    ++ /*   120 */  1005, 1180, 1191, 1190, 1189, 1267, 1294, 1293, 1005, 1005,
    ++ /*   130 */  1005, 1005, 1005, 1005, 1005, 1005, 1005, 1005, 1005, 1005,
    ++ /*   140 */  1005, 1005, 1005, 1005, 1005, 1005, 1005, 1005, 1005, 1005,
    ++ /*   150 */  1005, 1005, 1005, 1005, 1005, 1036, 1286, 1276, 1032, 1032,
    ++ /*   160 */  1005, 1276, 1276, 1276, 1276, 1276, 1276, 1272, 1108, 1099,
    ++ /*   170 */  1005, 1005, 1005, 1005, 1005, 1005, 1005, 1005, 1005, 1005,
    ++ /*   180 */  1005, 1264, 1262, 1005, 1224, 1005, 1005, 1005, 1005, 1005,
    ++ /*   190 */  1005, 1005, 1005, 1005, 1005, 1005, 1005, 1005, 1005, 1005,
    ++ /*   200 */  1005, 1005, 1005, 1005, 1005, 1104, 1005, 1005, 1005, 1005,
    ++ /*   210 */  1005, 1005, 1005, 1005, 1005, 1005, 1005, 1005, 1288, 1005,
    ++ /*   220 */  1237, 1104, 1104, 1104, 1104, 1106, 1088, 1098, 1036, 1012,
    ++ /*   230 */  1143, 1122, 1122, 1327, 1143, 1327, 1050, 1308, 1047, 1133,
    ++ /*   240 */  1122, 1206, 1133, 1133, 1105, 1098, 1005, 1330, 1113, 1113,
    ++ /*   250 */  1329, 1329, 1113, 1154, 1078, 1143, 1084, 1084, 1084, 1084,
    ++ /*   260 */  1113, 1023, 1143, 1154, 1078, 1078, 1143, 1113, 1023, 1241,
    ++ /*   270 */  1324, 1113, 1113, 1023, 1217, 1113, 1023, 1113, 1023, 1217,
    ++ /*   280 */  1076, 1076, 1076, 1065, 1217, 1076, 1050, 1076, 1065, 1076,
    ++ /*   290 */  1076, 1126, 1121, 1126, 1121, 1126, 1121, 1126, 1121, 1113,
    ++ /*   300 */  1212, 1113, 1005, 1217, 1221, 1221, 1217, 1138, 1127, 1136,
    ++ /*   310 */  1134, 1143, 1029, 1068, 1291, 1291, 1287, 1287, 1287, 1335,
    ++ /*   320 */  1335, 1272, 1303, 1036, 1036, 1036, 1036, 1303, 1052, 1052,
    ++ /*   330 */  1036, 1036, 1036, 1036, 1303, 1005, 1005, 1005, 1005, 1005,
    ++ /*   340 */  1005, 1298, 1005, 1226, 1005, 1005, 1005, 1005, 1005, 1005,
    ++ /*   350 */  1005, 1005, 1005, 1005, 1005, 1005, 1005, 1005, 1005, 1005,
    ++ /*   360 */  1005, 1005, 1159, 1005, 1008, 1269, 1005, 1005, 1268, 1005,
    ++ /*   370 */  1005, 1005, 1005, 1005, 1005, 1005, 1005, 1005, 1005, 1005,
    ++ /*   380 */  1005, 1005, 1005, 1005, 1005, 1005, 1005, 1005, 1005, 1326,
    ++ /*   390 */  1005, 1005, 1005, 1005, 1005, 1005, 1240, 1239, 1005, 1005,
    ++ /*   400 */  1005, 1005, 1005, 1005, 1005, 1005, 1005, 1005, 1005, 1005,
    ++ /*   410 */  1005, 1005, 1005, 1005, 1005, 1005, 1005, 1005, 1005, 1005,
    ++ /*   420 */  1005, 1090, 1005, 1005, 1005, 1312, 1005, 1005, 1005, 1005,
    ++ /*   430 */  1005, 1005, 1005, 1135, 1005, 1128, 1005, 1005, 1317, 1005,
    ++ /*   440 */  1005, 1005, 1005, 1005, 1005, 1005, 1005, 1005, 1005, 1278,
    ++ /*   450 */  1005, 1005, 1005, 1277, 1005, 1005, 1005, 1005, 1005, 1161,
    ++ /*   460 */  1005, 1160, 1164, 1005, 1017, 1005,
    + };
    ++/********** End of lemon-generated parsing tables *****************************/
    + 
    +-/* The next table maps tokens into fallback tokens.  If a construct
    +-** like the following:
    ++/* The next table maps tokens (terminal symbols) into fallback tokens.  
    ++** If a construct like the following:
    + ** 
    + **      %fallback ID X Y Z.
    + **
    +@@ -126779,79 +138920,96 @@ static const YYACTIONTYPE yy_default[] = {
    + ** and Z.  Whenever one of the tokens X, Y, or Z is input to the parser
    + ** but it does not parse, the type of the token is changed to ID and
    + ** the parse is retried before an error is thrown.
    ++**
    ++** This feature can be used, for example, to cause some keywords in a language
    ++** to revert to identifiers if they keyword does not apply in the context where
    ++** it appears.
    + */
    + #ifdef YYFALLBACK
    + static const YYCODETYPE yyFallback[] = {
    +     0,  /*          $ => nothing */
    +     0,  /*       SEMI => nothing */
    +-   27,  /*    EXPLAIN => ID */
    +-   27,  /*      QUERY => ID */
    +-   27,  /*       PLAN => ID */
    +-   27,  /*      BEGIN => ID */
    ++   59,  /*    EXPLAIN => ID */
    ++   59,  /*      QUERY => ID */
    ++   59,  /*       PLAN => ID */
    ++   59,  /*      BEGIN => ID */
    +     0,  /* TRANSACTION => nothing */
    +-   27,  /*   DEFERRED => ID */
    +-   27,  /*  IMMEDIATE => ID */
    +-   27,  /*  EXCLUSIVE => ID */
    ++   59,  /*   DEFERRED => ID */
    ++   59,  /*  IMMEDIATE => ID */
    ++   59,  /*  EXCLUSIVE => ID */
    +     0,  /*     COMMIT => nothing */
    +-   27,  /*        END => ID */
    +-   27,  /*   ROLLBACK => ID */
    +-   27,  /*  SAVEPOINT => ID */
    +-   27,  /*    RELEASE => ID */
    ++   59,  /*        END => ID */
    ++   59,  /*   ROLLBACK => ID */
    ++   59,  /*  SAVEPOINT => ID */
    ++   59,  /*    RELEASE => ID */
    +     0,  /*         TO => nothing */
    +     0,  /*      TABLE => nothing */
    +     0,  /*     CREATE => nothing */
    +-   27,  /*         IF => ID */
    ++   59,  /*         IF => ID */
    +     0,  /*        NOT => nothing */
    +     0,  /*     EXISTS => nothing */
    +-   27,  /*       TEMP => ID */
    ++   59,  /*       TEMP => ID */
    +     0,  /*         LP => nothing */
    +     0,  /*         RP => nothing */
    +     0,  /*         AS => nothing */
    +-   27,  /*    WITHOUT => ID */
    ++   59,  /*    WITHOUT => ID */
    +     0,  /*      COMMA => nothing */
    ++   59,  /*      ABORT => ID */
    ++   59,  /*     ACTION => ID */
    ++   59,  /*      AFTER => ID */
    ++   59,  /*    ANALYZE => ID */
    ++   59,  /*        ASC => ID */
    ++   59,  /*     ATTACH => ID */
    ++   59,  /*     BEFORE => ID */
    ++   59,  /*         BY => ID */
    ++   59,  /*    CASCADE => ID */
    ++   59,  /*       CAST => ID */
    ++   59,  /*   CONFLICT => ID */
    ++   59,  /*   DATABASE => ID */
    ++   59,  /*       DESC => ID */
    ++   59,  /*     DETACH => ID */
    ++   59,  /*       EACH => ID */
    ++   59,  /*       FAIL => ID */
    ++    0,  /*         OR => nothing */
    ++    0,  /*        AND => nothing */
    ++    0,  /*         IS => nothing */
    ++   59,  /*      MATCH => ID */
    ++   59,  /*    LIKE_KW => ID */
    ++    0,  /*    BETWEEN => nothing */
    ++    0,  /*         IN => nothing */
    ++    0,  /*     ISNULL => nothing */
    ++    0,  /*    NOTNULL => nothing */
    ++    0,  /*         NE => nothing */
    ++    0,  /*         EQ => nothing */
    ++    0,  /*         GT => nothing */
    ++    0,  /*         LE => nothing */
    ++    0,  /*         LT => nothing */
    ++    0,  /*         GE => nothing */
    ++    0,  /*     ESCAPE => nothing */
    +     0,  /*         ID => nothing */
    +-    0,  /*    INDEXED => nothing */
    +-   27,  /*      ABORT => ID */
    +-   27,  /*     ACTION => ID */
    +-   27,  /*      AFTER => ID */
    +-   27,  /*    ANALYZE => ID */
    +-   27,  /*        ASC => ID */
    +-   27,  /*     ATTACH => ID */
    +-   27,  /*     BEFORE => ID */
    +-   27,  /*         BY => ID */
    +-   27,  /*    CASCADE => ID */
    +-   27,  /*       CAST => ID */
    +-   27,  /*   COLUMNKW => ID */
    +-   27,  /*   CONFLICT => ID */
    +-   27,  /*   DATABASE => ID */
    +-   27,  /*       DESC => ID */
    +-   27,  /*     DETACH => ID */
    +-   27,  /*       EACH => ID */
    +-   27,  /*       FAIL => ID */
    +-   27,  /*        FOR => ID */
    +-   27,  /*     IGNORE => ID */
    +-   27,  /*  INITIALLY => ID */
    +-   27,  /*    INSTEAD => ID */
    +-   27,  /*    LIKE_KW => ID */
    +-   27,  /*      MATCH => ID */
    +-   27,  /*         NO => ID */
    +-   27,  /*        KEY => ID */
    +-   27,  /*         OF => ID */
    +-   27,  /*     OFFSET => ID */
    +-   27,  /*     PRAGMA => ID */
    +-   27,  /*      RAISE => ID */
    +-   27,  /*  RECURSIVE => ID */
    +-   27,  /*    REPLACE => ID */
    +-   27,  /*   RESTRICT => ID */
    +-   27,  /*        ROW => ID */
    +-   27,  /*    TRIGGER => ID */
    +-   27,  /*     VACUUM => ID */
    +-   27,  /*       VIEW => ID */
    +-   27,  /*    VIRTUAL => ID */
    +-   27,  /*       WITH => ID */
    +-   27,  /*    REINDEX => ID */
    +-   27,  /*     RENAME => ID */
    +-   27,  /*   CTIME_KW => ID */
    ++   59,  /*   COLUMNKW => ID */
    ++   59,  /*        FOR => ID */
    ++   59,  /*     IGNORE => ID */
    ++   59,  /*  INITIALLY => ID */
    ++   59,  /*    INSTEAD => ID */
    ++   59,  /*         NO => ID */
    ++   59,  /*        KEY => ID */
    ++   59,  /*         OF => ID */
    ++   59,  /*     OFFSET => ID */
    ++   59,  /*     PRAGMA => ID */
    ++   59,  /*      RAISE => ID */
    ++   59,  /*  RECURSIVE => ID */
    ++   59,  /*    REPLACE => ID */
    ++   59,  /*   RESTRICT => ID */
    ++   59,  /*        ROW => ID */
    ++   59,  /*    TRIGGER => ID */
    ++   59,  /*     VACUUM => ID */
    ++   59,  /*       VIEW => ID */
    ++   59,  /*    VIRTUAL => ID */
    ++   59,  /*       WITH => ID */
    ++   59,  /*    REINDEX => ID */
    ++   59,  /*     RENAME => ID */
    ++   59,  /*   CTIME_KW => ID */
    + };
    + #endif /* YYFALLBACK */
    + 
    +@@ -126883,17 +139041,21 @@ typedef struct yyStackEntry yyStackEntry;
    + /* The state of the parser is completely contained in an instance of
    + ** the following structure */
    + struct yyParser {
    +-  int yyidx;                    /* Index of top element in stack */
    ++  yyStackEntry *yytos;          /* Pointer to top element of the stack */
    + #ifdef YYTRACKMAXSTACKDEPTH
    +-  int yyidxMax;                 /* Maximum value of yyidx */
    ++  int yyhwm;                    /* High-water mark of the stack */
    + #endif
    ++#ifndef YYNOERRORRECOVERY
    +   int yyerrcnt;                 /* Shifts left before out of the error */
    ++#endif
    +   sqlite3ParserARG_SDECL                /* A place to hold %extra_argument */
    + #if YYSTACKDEPTH<=0
    +   int yystksz;                  /* Current side of the stack */
    +   yyStackEntry *yystack;        /* The parser's stack */
    ++  yyStackEntry yystk0;          /* First stack entry */
    + #else
    +   yyStackEntry yystack[YYSTACKDEPTH];  /* The parser's stack */
    ++  yyStackEntry *yystackEnd;            /* Last entry in the stack */
    + #endif
    + };
    + typedef struct yyParser yyParser;
    +@@ -126930,436 +139092,673 @@ SQLITE_PRIVATE void sqlite3ParserTrace(FILE *TraceFILE, char *zTracePrompt){
    + }
    + #endif /* NDEBUG */
    + 
    +-#ifndef NDEBUG
    ++#if defined(YYCOVERAGE) || !defined(NDEBUG)
    + /* For tracing shifts, the names of all terminals and nonterminals
    + ** are required.  The following table supplies these names */
    + static const char *const yyTokenName[] = { 
    +-  "$",             "SEMI",          "EXPLAIN",       "QUERY",       
    +-  "PLAN",          "BEGIN",         "TRANSACTION",   "DEFERRED",    
    +-  "IMMEDIATE",     "EXCLUSIVE",     "COMMIT",        "END",         
    +-  "ROLLBACK",      "SAVEPOINT",     "RELEASE",       "TO",          
    +-  "TABLE",         "CREATE",        "IF",            "NOT",         
    +-  "EXISTS",        "TEMP",          "LP",            "RP",          
    +-  "AS",            "WITHOUT",       "COMMA",         "ID",          
    +-  "INDEXED",       "ABORT",         "ACTION",        "AFTER",       
    +-  "ANALYZE",       "ASC",           "ATTACH",        "BEFORE",      
    +-  "BY",            "CASCADE",       "CAST",          "COLUMNKW",    
    +-  "CONFLICT",      "DATABASE",      "DESC",          "DETACH",      
    +-  "EACH",          "FAIL",          "FOR",           "IGNORE",      
    +-  "INITIALLY",     "INSTEAD",       "LIKE_KW",       "MATCH",       
    +-  "NO",            "KEY",           "OF",            "OFFSET",      
    +-  "PRAGMA",        "RAISE",         "RECURSIVE",     "REPLACE",     
    +-  "RESTRICT",      "ROW",           "TRIGGER",       "VACUUM",      
    +-  "VIEW",          "VIRTUAL",       "WITH",          "REINDEX",     
    +-  "RENAME",        "CTIME_KW",      "ANY",           "OR",          
    +-  "AND",           "IS",            "BETWEEN",       "IN",          
    +-  "ISNULL",        "NOTNULL",       "NE",            "EQ",          
    +-  "GT",            "LE",            "LT",            "GE",          
    +-  "ESCAPE",        "BITAND",        "BITOR",         "LSHIFT",      
    +-  "RSHIFT",        "PLUS",          "MINUS",         "STAR",        
    +-  "SLASH",         "REM",           "CONCAT",        "COLLATE",     
    +-  "BITNOT",        "STRING",        "JOIN_KW",       "CONSTRAINT",  
    +-  "DEFAULT",       "NULL",          "PRIMARY",       "UNIQUE",      
    +-  "CHECK",         "REFERENCES",    "AUTOINCR",      "ON",          
    +-  "INSERT",        "DELETE",        "UPDATE",        "SET",         
    +-  "DEFERRABLE",    "FOREIGN",       "DROP",          "UNION",       
    +-  "ALL",           "EXCEPT",        "INTERSECT",     "SELECT",      
    +-  "VALUES",        "DISTINCT",      "DOT",           "FROM",        
    +-  "JOIN",          "USING",         "ORDER",         "GROUP",       
    +-  "HAVING",        "LIMIT",         "WHERE",         "INTO",        
    +-  "INTEGER",       "FLOAT",         "BLOB",          "VARIABLE",    
    +-  "CASE",          "WHEN",          "THEN",          "ELSE",        
    +-  "INDEX",         "ALTER",         "ADD",           "error",       
    +-  "input",         "cmdlist",       "ecmd",          "explain",     
    +-  "cmdx",          "cmd",           "transtype",     "trans_opt",   
    +-  "nm",            "savepoint_opt",  "create_table",  "create_table_args",
    +-  "createkw",      "temp",          "ifnotexists",   "dbnm",        
    +-  "columnlist",    "conslist_opt",  "table_options",  "select",      
    +-  "column",        "columnid",      "type",          "carglist",    
    +-  "typetoken",     "typename",      "signed",        "plus_num",    
    +-  "minus_num",     "ccons",         "term",          "expr",        
    +-  "onconf",        "sortorder",     "autoinc",       "eidlist_opt", 
    +-  "refargs",       "defer_subclause",  "refarg",        "refact",      
    +-  "init_deferred_pred_opt",  "conslist",      "tconscomma",    "tcons",       
    +-  "sortlist",      "eidlist",       "defer_subclause_opt",  "orconf",      
    +-  "resolvetype",   "raisetype",     "ifexists",      "fullname",    
    +-  "selectnowith",  "oneselect",     "with",          "multiselect_op",
    +-  "distinct",      "selcollist",    "from",          "where_opt",   
    +-  "groupby_opt",   "having_opt",    "orderby_opt",   "limit_opt",   
    +-  "values",        "nexprlist",     "exprlist",      "sclp",        
    +-  "as",            "seltablist",    "stl_prefix",    "joinop",      
    +-  "indexed_opt",   "on_opt",        "using_opt",     "joinop2",     
    +-  "idlist",        "setlist",       "insert_cmd",    "idlist_opt",  
    +-  "likeop",        "between_op",    "in_op",         "case_operand",
    +-  "case_exprlist",  "case_else",     "uniqueflag",    "collate",     
    +-  "nmnum",         "trigger_decl",  "trigger_cmd_list",  "trigger_time",
    +-  "trigger_event",  "foreach_clause",  "when_clause",   "trigger_cmd", 
    +-  "trnm",          "tridxby",       "database_kw_opt",  "key_opt",     
    +-  "add_column_fullname",  "kwcolumn_opt",  "create_vtab",   "vtabarglist", 
    +-  "vtabarg",       "vtabargtoken",  "lp",            "anylist",     
    +-  "wqlist",      
    ++  /*    0 */ "$",
    ++  /*    1 */ "SEMI",
    ++  /*    2 */ "EXPLAIN",
    ++  /*    3 */ "QUERY",
    ++  /*    4 */ "PLAN",
    ++  /*    5 */ "BEGIN",
    ++  /*    6 */ "TRANSACTION",
    ++  /*    7 */ "DEFERRED",
    ++  /*    8 */ "IMMEDIATE",
    ++  /*    9 */ "EXCLUSIVE",
    ++  /*   10 */ "COMMIT",
    ++  /*   11 */ "END",
    ++  /*   12 */ "ROLLBACK",
    ++  /*   13 */ "SAVEPOINT",
    ++  /*   14 */ "RELEASE",
    ++  /*   15 */ "TO",
    ++  /*   16 */ "TABLE",
    ++  /*   17 */ "CREATE",
    ++  /*   18 */ "IF",
    ++  /*   19 */ "NOT",
    ++  /*   20 */ "EXISTS",
    ++  /*   21 */ "TEMP",
    ++  /*   22 */ "LP",
    ++  /*   23 */ "RP",
    ++  /*   24 */ "AS",
    ++  /*   25 */ "WITHOUT",
    ++  /*   26 */ "COMMA",
    ++  /*   27 */ "ABORT",
    ++  /*   28 */ "ACTION",
    ++  /*   29 */ "AFTER",
    ++  /*   30 */ "ANALYZE",
    ++  /*   31 */ "ASC",
    ++  /*   32 */ "ATTACH",
    ++  /*   33 */ "BEFORE",
    ++  /*   34 */ "BY",
    ++  /*   35 */ "CASCADE",
    ++  /*   36 */ "CAST",
    ++  /*   37 */ "CONFLICT",
    ++  /*   38 */ "DATABASE",
    ++  /*   39 */ "DESC",
    ++  /*   40 */ "DETACH",
    ++  /*   41 */ "EACH",
    ++  /*   42 */ "FAIL",
    ++  /*   43 */ "OR",
    ++  /*   44 */ "AND",
    ++  /*   45 */ "IS",
    ++  /*   46 */ "MATCH",
    ++  /*   47 */ "LIKE_KW",
    ++  /*   48 */ "BETWEEN",
    ++  /*   49 */ "IN",
    ++  /*   50 */ "ISNULL",
    ++  /*   51 */ "NOTNULL",
    ++  /*   52 */ "NE",
    ++  /*   53 */ "EQ",
    ++  /*   54 */ "GT",
    ++  /*   55 */ "LE",
    ++  /*   56 */ "LT",
    ++  /*   57 */ "GE",
    ++  /*   58 */ "ESCAPE",
    ++  /*   59 */ "ID",
    ++  /*   60 */ "COLUMNKW",
    ++  /*   61 */ "FOR",
    ++  /*   62 */ "IGNORE",
    ++  /*   63 */ "INITIALLY",
    ++  /*   64 */ "INSTEAD",
    ++  /*   65 */ "NO",
    ++  /*   66 */ "KEY",
    ++  /*   67 */ "OF",
    ++  /*   68 */ "OFFSET",
    ++  /*   69 */ "PRAGMA",
    ++  /*   70 */ "RAISE",
    ++  /*   71 */ "RECURSIVE",
    ++  /*   72 */ "REPLACE",
    ++  /*   73 */ "RESTRICT",
    ++  /*   74 */ "ROW",
    ++  /*   75 */ "TRIGGER",
    ++  /*   76 */ "VACUUM",
    ++  /*   77 */ "VIEW",
    ++  /*   78 */ "VIRTUAL",
    ++  /*   79 */ "WITH",
    ++  /*   80 */ "REINDEX",
    ++  /*   81 */ "RENAME",
    ++  /*   82 */ "CTIME_KW",
    ++  /*   83 */ "ANY",
    ++  /*   84 */ "BITAND",
    ++  /*   85 */ "BITOR",
    ++  /*   86 */ "LSHIFT",
    ++  /*   87 */ "RSHIFT",
    ++  /*   88 */ "PLUS",
    ++  /*   89 */ "MINUS",
    ++  /*   90 */ "STAR",
    ++  /*   91 */ "SLASH",
    ++  /*   92 */ "REM",
    ++  /*   93 */ "CONCAT",
    ++  /*   94 */ "COLLATE",
    ++  /*   95 */ "BITNOT",
    ++  /*   96 */ "INDEXED",
    ++  /*   97 */ "STRING",
    ++  /*   98 */ "JOIN_KW",
    ++  /*   99 */ "CONSTRAINT",
    ++  /*  100 */ "DEFAULT",
    ++  /*  101 */ "NULL",
    ++  /*  102 */ "PRIMARY",
    ++  /*  103 */ "UNIQUE",
    ++  /*  104 */ "CHECK",
    ++  /*  105 */ "REFERENCES",
    ++  /*  106 */ "AUTOINCR",
    ++  /*  107 */ "ON",
    ++  /*  108 */ "INSERT",
    ++  /*  109 */ "DELETE",
    ++  /*  110 */ "UPDATE",
    ++  /*  111 */ "SET",
    ++  /*  112 */ "DEFERRABLE",
    ++  /*  113 */ "FOREIGN",
    ++  /*  114 */ "DROP",
    ++  /*  115 */ "UNION",
    ++  /*  116 */ "ALL",
    ++  /*  117 */ "EXCEPT",
    ++  /*  118 */ "INTERSECT",
    ++  /*  119 */ "SELECT",
    ++  /*  120 */ "VALUES",
    ++  /*  121 */ "DISTINCT",
    ++  /*  122 */ "DOT",
    ++  /*  123 */ "FROM",
    ++  /*  124 */ "JOIN",
    ++  /*  125 */ "USING",
    ++  /*  126 */ "ORDER",
    ++  /*  127 */ "GROUP",
    ++  /*  128 */ "HAVING",
    ++  /*  129 */ "LIMIT",
    ++  /*  130 */ "WHERE",
    ++  /*  131 */ "INTO",
    ++  /*  132 */ "FLOAT",
    ++  /*  133 */ "BLOB",
    ++  /*  134 */ "INTEGER",
    ++  /*  135 */ "VARIABLE",
    ++  /*  136 */ "CASE",
    ++  /*  137 */ "WHEN",
    ++  /*  138 */ "THEN",
    ++  /*  139 */ "ELSE",
    ++  /*  140 */ "INDEX",
    ++  /*  141 */ "ALTER",
    ++  /*  142 */ "ADD",
    ++  /*  143 */ "error",
    ++  /*  144 */ "input",
    ++  /*  145 */ "cmdlist",
    ++  /*  146 */ "ecmd",
    ++  /*  147 */ "explain",
    ++  /*  148 */ "cmdx",
    ++  /*  149 */ "cmd",
    ++  /*  150 */ "transtype",
    ++  /*  151 */ "trans_opt",
    ++  /*  152 */ "nm",
    ++  /*  153 */ "savepoint_opt",
    ++  /*  154 */ "create_table",
    ++  /*  155 */ "create_table_args",
    ++  /*  156 */ "createkw",
    ++  /*  157 */ "temp",
    ++  /*  158 */ "ifnotexists",
    ++  /*  159 */ "dbnm",
    ++  /*  160 */ "columnlist",
    ++  /*  161 */ "conslist_opt",
    ++  /*  162 */ "table_options",
    ++  /*  163 */ "select",
    ++  /*  164 */ "columnname",
    ++  /*  165 */ "carglist",
    ++  /*  166 */ "typetoken",
    ++  /*  167 */ "typename",
    ++  /*  168 */ "signed",
    ++  /*  169 */ "plus_num",
    ++  /*  170 */ "minus_num",
    ++  /*  171 */ "scanpt",
    ++  /*  172 */ "ccons",
    ++  /*  173 */ "term",
    ++  /*  174 */ "expr",
    ++  /*  175 */ "onconf",
    ++  /*  176 */ "sortorder",
    ++  /*  177 */ "autoinc",
    ++  /*  178 */ "eidlist_opt",
    ++  /*  179 */ "refargs",
    ++  /*  180 */ "defer_subclause",
    ++  /*  181 */ "refarg",
    ++  /*  182 */ "refact",
    ++  /*  183 */ "init_deferred_pred_opt",
    ++  /*  184 */ "conslist",
    ++  /*  185 */ "tconscomma",
    ++  /*  186 */ "tcons",
    ++  /*  187 */ "sortlist",
    ++  /*  188 */ "eidlist",
    ++  /*  189 */ "defer_subclause_opt",
    ++  /*  190 */ "orconf",
    ++  /*  191 */ "resolvetype",
    ++  /*  192 */ "raisetype",
    ++  /*  193 */ "ifexists",
    ++  /*  194 */ "fullname",
    ++  /*  195 */ "selectnowith",
    ++  /*  196 */ "oneselect",
    ++  /*  197 */ "with",
    ++  /*  198 */ "multiselect_op",
    ++  /*  199 */ "distinct",
    ++  /*  200 */ "selcollist",
    ++  /*  201 */ "from",
    ++  /*  202 */ "where_opt",
    ++  /*  203 */ "groupby_opt",
    ++  /*  204 */ "having_opt",
    ++  /*  205 */ "orderby_opt",
    ++  /*  206 */ "limit_opt",
    ++  /*  207 */ "values",
    ++  /*  208 */ "nexprlist",
    ++  /*  209 */ "exprlist",
    ++  /*  210 */ "sclp",
    ++  /*  211 */ "as",
    ++  /*  212 */ "seltablist",
    ++  /*  213 */ "stl_prefix",
    ++  /*  214 */ "joinop",
    ++  /*  215 */ "indexed_opt",
    ++  /*  216 */ "on_opt",
    ++  /*  217 */ "using_opt",
    ++  /*  218 */ "idlist",
    ++  /*  219 */ "setlist",
    ++  /*  220 */ "insert_cmd",
    ++  /*  221 */ "idlist_opt",
    ++  /*  222 */ "likeop",
    ++  /*  223 */ "between_op",
    ++  /*  224 */ "in_op",
    ++  /*  225 */ "paren_exprlist",
    ++  /*  226 */ "case_operand",
    ++  /*  227 */ "case_exprlist",
    ++  /*  228 */ "case_else",
    ++  /*  229 */ "uniqueflag",
    ++  /*  230 */ "collate",
    ++  /*  231 */ "nmnum",
    ++  /*  232 */ "trigger_decl",
    ++  /*  233 */ "trigger_cmd_list",
    ++  /*  234 */ "trigger_time",
    ++  /*  235 */ "trigger_event",
    ++  /*  236 */ "foreach_clause",
    ++  /*  237 */ "when_clause",
    ++  /*  238 */ "trigger_cmd",
    ++  /*  239 */ "trnm",
    ++  /*  240 */ "tridxby",
    ++  /*  241 */ "database_kw_opt",
    ++  /*  242 */ "key_opt",
    ++  /*  243 */ "add_column_fullname",
    ++  /*  244 */ "kwcolumn_opt",
    ++  /*  245 */ "create_vtab",
    ++  /*  246 */ "vtabarglist",
    ++  /*  247 */ "vtabarg",
    ++  /*  248 */ "vtabargtoken",
    ++  /*  249 */ "lp",
    ++  /*  250 */ "anylist",
    ++  /*  251 */ "wqlist",
    + };
    +-#endif /* NDEBUG */
    ++#endif /* defined(YYCOVERAGE) || !defined(NDEBUG) */
    + 
    + #ifndef NDEBUG
    + /* For tracing reduce actions, the names of all rules are required.
    + */
    + static const char *const yyRuleName[] = {
    +- /*   0 */ "input ::= cmdlist",
    +- /*   1 */ "cmdlist ::= cmdlist ecmd",
    +- /*   2 */ "cmdlist ::= ecmd",
    +- /*   3 */ "ecmd ::= SEMI",
    +- /*   4 */ "ecmd ::= explain cmdx SEMI",
    +- /*   5 */ "explain ::=",
    +- /*   6 */ "explain ::= EXPLAIN",
    +- /*   7 */ "explain ::= EXPLAIN QUERY PLAN",
    +- /*   8 */ "cmdx ::= cmd",
    +- /*   9 */ "cmd ::= BEGIN transtype trans_opt",
    +- /*  10 */ "trans_opt ::=",
    +- /*  11 */ "trans_opt ::= TRANSACTION",
    +- /*  12 */ "trans_opt ::= TRANSACTION nm",
    +- /*  13 */ "transtype ::=",
    +- /*  14 */ "transtype ::= DEFERRED",
    +- /*  15 */ "transtype ::= IMMEDIATE",
    +- /*  16 */ "transtype ::= EXCLUSIVE",
    +- /*  17 */ "cmd ::= COMMIT trans_opt",
    +- /*  18 */ "cmd ::= END trans_opt",
    +- /*  19 */ "cmd ::= ROLLBACK trans_opt",
    +- /*  20 */ "savepoint_opt ::= SAVEPOINT",
    +- /*  21 */ "savepoint_opt ::=",
    +- /*  22 */ "cmd ::= SAVEPOINT nm",
    +- /*  23 */ "cmd ::= RELEASE savepoint_opt nm",
    +- /*  24 */ "cmd ::= ROLLBACK trans_opt TO savepoint_opt nm",
    +- /*  25 */ "cmd ::= create_table create_table_args",
    +- /*  26 */ "create_table ::= createkw temp TABLE ifnotexists nm dbnm",
    +- /*  27 */ "createkw ::= CREATE",
    +- /*  28 */ "ifnotexists ::=",
    +- /*  29 */ "ifnotexists ::= IF NOT EXISTS",
    +- /*  30 */ "temp ::= TEMP",
    +- /*  31 */ "temp ::=",
    +- /*  32 */ "create_table_args ::= LP columnlist conslist_opt RP table_options",
    +- /*  33 */ "create_table_args ::= AS select",
    +- /*  34 */ "table_options ::=",
    +- /*  35 */ "table_options ::= WITHOUT nm",
    +- /*  36 */ "columnlist ::= columnlist COMMA column",
    +- /*  37 */ "columnlist ::= column",
    +- /*  38 */ "column ::= columnid type carglist",
    +- /*  39 */ "columnid ::= nm",
    +- /*  40 */ "nm ::= ID|INDEXED",
    +- /*  41 */ "nm ::= STRING",
    +- /*  42 */ "nm ::= JOIN_KW",
    +- /*  43 */ "type ::=",
    +- /*  44 */ "type ::= typetoken",
    +- /*  45 */ "typetoken ::= typename",
    +- /*  46 */ "typetoken ::= typename LP signed RP",
    +- /*  47 */ "typetoken ::= typename LP signed COMMA signed RP",
    +- /*  48 */ "typename ::= ID|STRING",
    +- /*  49 */ "typename ::= typename ID|STRING",
    +- /*  50 */ "signed ::= plus_num",
    +- /*  51 */ "signed ::= minus_num",
    +- /*  52 */ "carglist ::= carglist ccons",
    +- /*  53 */ "carglist ::=",
    +- /*  54 */ "ccons ::= CONSTRAINT nm",
    +- /*  55 */ "ccons ::= DEFAULT term",
    +- /*  56 */ "ccons ::= DEFAULT LP expr RP",
    +- /*  57 */ "ccons ::= DEFAULT PLUS term",
    +- /*  58 */ "ccons ::= DEFAULT MINUS term",
    +- /*  59 */ "ccons ::= DEFAULT ID|INDEXED",
    +- /*  60 */ "ccons ::= NULL onconf",
    +- /*  61 */ "ccons ::= NOT NULL onconf",
    +- /*  62 */ "ccons ::= PRIMARY KEY sortorder onconf autoinc",
    +- /*  63 */ "ccons ::= UNIQUE onconf",
    +- /*  64 */ "ccons ::= CHECK LP expr RP",
    +- /*  65 */ "ccons ::= REFERENCES nm eidlist_opt refargs",
    +- /*  66 */ "ccons ::= defer_subclause",
    +- /*  67 */ "ccons ::= COLLATE ID|STRING",
    +- /*  68 */ "autoinc ::=",
    +- /*  69 */ "autoinc ::= AUTOINCR",
    +- /*  70 */ "refargs ::=",
    +- /*  71 */ "refargs ::= refargs refarg",
    +- /*  72 */ "refarg ::= MATCH nm",
    +- /*  73 */ "refarg ::= ON INSERT refact",
    +- /*  74 */ "refarg ::= ON DELETE refact",
    +- /*  75 */ "refarg ::= ON UPDATE refact",
    +- /*  76 */ "refact ::= SET NULL",
    +- /*  77 */ "refact ::= SET DEFAULT",
    +- /*  78 */ "refact ::= CASCADE",
    +- /*  79 */ "refact ::= RESTRICT",
    +- /*  80 */ "refact ::= NO ACTION",
    +- /*  81 */ "defer_subclause ::= NOT DEFERRABLE init_deferred_pred_opt",
    +- /*  82 */ "defer_subclause ::= DEFERRABLE init_deferred_pred_opt",
    +- /*  83 */ "init_deferred_pred_opt ::=",
    +- /*  84 */ "init_deferred_pred_opt ::= INITIALLY DEFERRED",
    +- /*  85 */ "init_deferred_pred_opt ::= INITIALLY IMMEDIATE",
    +- /*  86 */ "conslist_opt ::=",
    +- /*  87 */ "conslist_opt ::= COMMA conslist",
    +- /*  88 */ "conslist ::= conslist tconscomma tcons",
    +- /*  89 */ "conslist ::= tcons",
    +- /*  90 */ "tconscomma ::= COMMA",
    +- /*  91 */ "tconscomma ::=",
    +- /*  92 */ "tcons ::= CONSTRAINT nm",
    +- /*  93 */ "tcons ::= PRIMARY KEY LP sortlist autoinc RP onconf",
    +- /*  94 */ "tcons ::= UNIQUE LP sortlist RP onconf",
    +- /*  95 */ "tcons ::= CHECK LP expr RP onconf",
    +- /*  96 */ "tcons ::= FOREIGN KEY LP eidlist RP REFERENCES nm eidlist_opt refargs defer_subclause_opt",
    +- /*  97 */ "defer_subclause_opt ::=",
    +- /*  98 */ "defer_subclause_opt ::= defer_subclause",
    +- /*  99 */ "onconf ::=",
    +- /* 100 */ "onconf ::= ON CONFLICT resolvetype",
    +- /* 101 */ "orconf ::=",
    +- /* 102 */ "orconf ::= OR resolvetype",
    +- /* 103 */ "resolvetype ::= raisetype",
    +- /* 104 */ "resolvetype ::= IGNORE",
    +- /* 105 */ "resolvetype ::= REPLACE",
    +- /* 106 */ "cmd ::= DROP TABLE ifexists fullname",
    +- /* 107 */ "ifexists ::= IF EXISTS",
    +- /* 108 */ "ifexists ::=",
    +- /* 109 */ "cmd ::= createkw temp VIEW ifnotexists nm dbnm eidlist_opt AS select",
    +- /* 110 */ "cmd ::= DROP VIEW ifexists fullname",
    +- /* 111 */ "cmd ::= select",
    +- /* 112 */ "select ::= with selectnowith",
    +- /* 113 */ "selectnowith ::= oneselect",
    +- /* 114 */ "selectnowith ::= selectnowith multiselect_op oneselect",
    +- /* 115 */ "multiselect_op ::= UNION",
    +- /* 116 */ "multiselect_op ::= UNION ALL",
    +- /* 117 */ "multiselect_op ::= EXCEPT|INTERSECT",
    +- /* 118 */ "oneselect ::= SELECT distinct selcollist from where_opt groupby_opt having_opt orderby_opt limit_opt",
    +- /* 119 */ "oneselect ::= values",
    +- /* 120 */ "values ::= VALUES LP nexprlist RP",
    +- /* 121 */ "values ::= values COMMA LP exprlist RP",
    +- /* 122 */ "distinct ::= DISTINCT",
    +- /* 123 */ "distinct ::= ALL",
    +- /* 124 */ "distinct ::=",
    +- /* 125 */ "sclp ::= selcollist COMMA",
    +- /* 126 */ "sclp ::=",
    +- /* 127 */ "selcollist ::= sclp expr as",
    +- /* 128 */ "selcollist ::= sclp STAR",
    +- /* 129 */ "selcollist ::= sclp nm DOT STAR",
    +- /* 130 */ "as ::= AS nm",
    +- /* 131 */ "as ::= ID|STRING",
    +- /* 132 */ "as ::=",
    +- /* 133 */ "from ::=",
    +- /* 134 */ "from ::= FROM seltablist",
    +- /* 135 */ "stl_prefix ::= seltablist joinop",
    +- /* 136 */ "stl_prefix ::=",
    +- /* 137 */ "seltablist ::= stl_prefix nm dbnm as indexed_opt on_opt using_opt",
    +- /* 138 */ "seltablist ::= stl_prefix nm dbnm LP exprlist RP as on_opt using_opt",
    +- /* 139 */ "seltablist ::= stl_prefix LP select RP as on_opt using_opt",
    +- /* 140 */ "seltablist ::= stl_prefix LP seltablist RP as on_opt using_opt",
    +- /* 141 */ "dbnm ::=",
    +- /* 142 */ "dbnm ::= DOT nm",
    +- /* 143 */ "fullname ::= nm dbnm",
    +- /* 144 */ "joinop ::= COMMA|JOIN",
    +- /* 145 */ "joinop ::= JOIN_KW JOIN",
    +- /* 146 */ "joinop ::= JOIN_KW nm JOIN",
    +- /* 147 */ "joinop ::= JOIN_KW nm nm JOIN",
    +- /* 148 */ "on_opt ::= ON expr",
    +- /* 149 */ "on_opt ::=",
    +- /* 150 */ "indexed_opt ::=",
    +- /* 151 */ "indexed_opt ::= INDEXED BY nm",
    +- /* 152 */ "indexed_opt ::= NOT INDEXED",
    +- /* 153 */ "using_opt ::= USING LP idlist RP",
    +- /* 154 */ "using_opt ::=",
    +- /* 155 */ "orderby_opt ::=",
    +- /* 156 */ "orderby_opt ::= ORDER BY sortlist",
    +- /* 157 */ "sortlist ::= sortlist COMMA expr sortorder",
    +- /* 158 */ "sortlist ::= expr sortorder",
    +- /* 159 */ "sortorder ::= ASC",
    +- /* 160 */ "sortorder ::= DESC",
    +- /* 161 */ "sortorder ::=",
    +- /* 162 */ "groupby_opt ::=",
    +- /* 163 */ "groupby_opt ::= GROUP BY nexprlist",
    +- /* 164 */ "having_opt ::=",
    +- /* 165 */ "having_opt ::= HAVING expr",
    +- /* 166 */ "limit_opt ::=",
    +- /* 167 */ "limit_opt ::= LIMIT expr",
    +- /* 168 */ "limit_opt ::= LIMIT expr OFFSET expr",
    +- /* 169 */ "limit_opt ::= LIMIT expr COMMA expr",
    +- /* 170 */ "cmd ::= with DELETE FROM fullname indexed_opt where_opt",
    +- /* 171 */ "where_opt ::=",
    +- /* 172 */ "where_opt ::= WHERE expr",
    +- /* 173 */ "cmd ::= with UPDATE orconf fullname indexed_opt SET setlist where_opt",
    +- /* 174 */ "setlist ::= setlist COMMA nm EQ expr",
    +- /* 175 */ "setlist ::= nm EQ expr",
    +- /* 176 */ "cmd ::= with insert_cmd INTO fullname idlist_opt select",
    +- /* 177 */ "cmd ::= with insert_cmd INTO fullname idlist_opt DEFAULT VALUES",
    +- /* 178 */ "insert_cmd ::= INSERT orconf",
    +- /* 179 */ "insert_cmd ::= REPLACE",
    +- /* 180 */ "idlist_opt ::=",
    +- /* 181 */ "idlist_opt ::= LP idlist RP",
    +- /* 182 */ "idlist ::= idlist COMMA nm",
    +- /* 183 */ "idlist ::= nm",
    +- /* 184 */ "expr ::= term",
    +- /* 185 */ "expr ::= LP expr RP",
    +- /* 186 */ "term ::= NULL",
    +- /* 187 */ "expr ::= ID|INDEXED",
    +- /* 188 */ "expr ::= JOIN_KW",
    +- /* 189 */ "expr ::= nm DOT nm",
    +- /* 190 */ "expr ::= nm DOT nm DOT nm",
    +- /* 191 */ "term ::= INTEGER|FLOAT|BLOB",
    +- /* 192 */ "term ::= STRING",
    +- /* 193 */ "expr ::= VARIABLE",
    +- /* 194 */ "expr ::= expr COLLATE ID|STRING",
    +- /* 195 */ "expr ::= CAST LP expr AS typetoken RP",
    +- /* 196 */ "expr ::= ID|INDEXED LP distinct exprlist RP",
    +- /* 197 */ "expr ::= ID|INDEXED LP STAR RP",
    +- /* 198 */ "term ::= CTIME_KW",
    +- /* 199 */ "expr ::= expr AND expr",
    +- /* 200 */ "expr ::= expr OR expr",
    +- /* 201 */ "expr ::= expr LT|GT|GE|LE expr",
    +- /* 202 */ "expr ::= expr EQ|NE expr",
    +- /* 203 */ "expr ::= expr BITAND|BITOR|LSHIFT|RSHIFT expr",
    +- /* 204 */ "expr ::= expr PLUS|MINUS expr",
    +- /* 205 */ "expr ::= expr STAR|SLASH|REM expr",
    +- /* 206 */ "expr ::= expr CONCAT expr",
    +- /* 207 */ "likeop ::= LIKE_KW|MATCH",
    +- /* 208 */ "likeop ::= NOT LIKE_KW|MATCH",
    +- /* 209 */ "expr ::= expr likeop expr",
    +- /* 210 */ "expr ::= expr likeop expr ESCAPE expr",
    +- /* 211 */ "expr ::= expr ISNULL|NOTNULL",
    +- /* 212 */ "expr ::= expr NOT NULL",
    +- /* 213 */ "expr ::= expr IS expr",
    +- /* 214 */ "expr ::= expr IS NOT expr",
    +- /* 215 */ "expr ::= NOT expr",
    +- /* 216 */ "expr ::= BITNOT expr",
    +- /* 217 */ "expr ::= MINUS expr",
    +- /* 218 */ "expr ::= PLUS expr",
    +- /* 219 */ "between_op ::= BETWEEN",
    +- /* 220 */ "between_op ::= NOT BETWEEN",
    +- /* 221 */ "expr ::= expr between_op expr AND expr",
    +- /* 222 */ "in_op ::= IN",
    +- /* 223 */ "in_op ::= NOT IN",
    +- /* 224 */ "expr ::= expr in_op LP exprlist RP",
    +- /* 225 */ "expr ::= LP select RP",
    +- /* 226 */ "expr ::= expr in_op LP select RP",
    +- /* 227 */ "expr ::= expr in_op nm dbnm",
    +- /* 228 */ "expr ::= EXISTS LP select RP",
    +- /* 229 */ "expr ::= CASE case_operand case_exprlist case_else END",
    +- /* 230 */ "case_exprlist ::= case_exprlist WHEN expr THEN expr",
    +- /* 231 */ "case_exprlist ::= WHEN expr THEN expr",
    +- /* 232 */ "case_else ::= ELSE expr",
    +- /* 233 */ "case_else ::=",
    +- /* 234 */ "case_operand ::= expr",
    +- /* 235 */ "case_operand ::=",
    +- /* 236 */ "exprlist ::= nexprlist",
    +- /* 237 */ "exprlist ::=",
    +- /* 238 */ "nexprlist ::= nexprlist COMMA expr",
    +- /* 239 */ "nexprlist ::= expr",
    +- /* 240 */ "cmd ::= createkw uniqueflag INDEX ifnotexists nm dbnm ON nm LP sortlist RP where_opt",
    +- /* 241 */ "uniqueflag ::= UNIQUE",
    +- /* 242 */ "uniqueflag ::=",
    +- /* 243 */ "eidlist_opt ::=",
    +- /* 244 */ "eidlist_opt ::= LP eidlist RP",
    +- /* 245 */ "eidlist ::= eidlist COMMA nm collate sortorder",
    +- /* 246 */ "eidlist ::= nm collate sortorder",
    +- /* 247 */ "collate ::=",
    +- /* 248 */ "collate ::= COLLATE ID|STRING",
    +- /* 249 */ "cmd ::= DROP INDEX ifexists fullname",
    +- /* 250 */ "cmd ::= VACUUM",
    +- /* 251 */ "cmd ::= VACUUM nm",
    +- /* 252 */ "cmd ::= PRAGMA nm dbnm",
    +- /* 253 */ "cmd ::= PRAGMA nm dbnm EQ nmnum",
    +- /* 254 */ "cmd ::= PRAGMA nm dbnm LP nmnum RP",
    +- /* 255 */ "cmd ::= PRAGMA nm dbnm EQ minus_num",
    +- /* 256 */ "cmd ::= PRAGMA nm dbnm LP minus_num RP",
    +- /* 257 */ "nmnum ::= plus_num",
    +- /* 258 */ "nmnum ::= nm",
    +- /* 259 */ "nmnum ::= ON",
    +- /* 260 */ "nmnum ::= DELETE",
    +- /* 261 */ "nmnum ::= DEFAULT",
    +- /* 262 */ "plus_num ::= PLUS INTEGER|FLOAT",
    +- /* 263 */ "plus_num ::= INTEGER|FLOAT",
    +- /* 264 */ "minus_num ::= MINUS INTEGER|FLOAT",
    +- /* 265 */ "cmd ::= createkw trigger_decl BEGIN trigger_cmd_list END",
    +- /* 266 */ "trigger_decl ::= temp TRIGGER ifnotexists nm dbnm trigger_time trigger_event ON fullname foreach_clause when_clause",
    +- /* 267 */ "trigger_time ::= BEFORE",
    +- /* 268 */ "trigger_time ::= AFTER",
    +- /* 269 */ "trigger_time ::= INSTEAD OF",
    +- /* 270 */ "trigger_time ::=",
    +- /* 271 */ "trigger_event ::= DELETE|INSERT",
    +- /* 272 */ "trigger_event ::= UPDATE",
    +- /* 273 */ "trigger_event ::= UPDATE OF idlist",
    +- /* 274 */ "foreach_clause ::=",
    +- /* 275 */ "foreach_clause ::= FOR EACH ROW",
    +- /* 276 */ "when_clause ::=",
    +- /* 277 */ "when_clause ::= WHEN expr",
    +- /* 278 */ "trigger_cmd_list ::= trigger_cmd_list trigger_cmd SEMI",
    +- /* 279 */ "trigger_cmd_list ::= trigger_cmd SEMI",
    +- /* 280 */ "trnm ::= nm",
    +- /* 281 */ "trnm ::= nm DOT nm",
    +- /* 282 */ "tridxby ::=",
    +- /* 283 */ "tridxby ::= INDEXED BY nm",
    +- /* 284 */ "tridxby ::= NOT INDEXED",
    +- /* 285 */ "trigger_cmd ::= UPDATE orconf trnm tridxby SET setlist where_opt",
    +- /* 286 */ "trigger_cmd ::= insert_cmd INTO trnm idlist_opt select",
    +- /* 287 */ "trigger_cmd ::= DELETE FROM trnm tridxby where_opt",
    +- /* 288 */ "trigger_cmd ::= select",
    +- /* 289 */ "expr ::= RAISE LP IGNORE RP",
    +- /* 290 */ "expr ::= RAISE LP raisetype COMMA nm RP",
    +- /* 291 */ "raisetype ::= ROLLBACK",
    +- /* 292 */ "raisetype ::= ABORT",
    +- /* 293 */ "raisetype ::= FAIL",
    +- /* 294 */ "cmd ::= DROP TRIGGER ifexists fullname",
    +- /* 295 */ "cmd ::= ATTACH database_kw_opt expr AS expr key_opt",
    +- /* 296 */ "cmd ::= DETACH database_kw_opt expr",
    +- /* 297 */ "key_opt ::=",
    +- /* 298 */ "key_opt ::= KEY expr",
    +- /* 299 */ "database_kw_opt ::= DATABASE",
    +- /* 300 */ "database_kw_opt ::=",
    +- /* 301 */ "cmd ::= REINDEX",
    +- /* 302 */ "cmd ::= REINDEX nm dbnm",
    +- /* 303 */ "cmd ::= ANALYZE",
    +- /* 304 */ "cmd ::= ANALYZE nm dbnm",
    +- /* 305 */ "cmd ::= ALTER TABLE fullname RENAME TO nm",
    +- /* 306 */ "cmd ::= ALTER TABLE add_column_fullname ADD kwcolumn_opt column",
    +- /* 307 */ "add_column_fullname ::= fullname",
    +- /* 308 */ "kwcolumn_opt ::=",
    +- /* 309 */ "kwcolumn_opt ::= COLUMNKW",
    +- /* 310 */ "cmd ::= create_vtab",
    +- /* 311 */ "cmd ::= create_vtab LP vtabarglist RP",
    +- /* 312 */ "create_vtab ::= createkw VIRTUAL TABLE ifnotexists nm dbnm USING nm",
    +- /* 313 */ "vtabarglist ::= vtabarg",
    +- /* 314 */ "vtabarglist ::= vtabarglist COMMA vtabarg",
    +- /* 315 */ "vtabarg ::=",
    +- /* 316 */ "vtabarg ::= vtabarg vtabargtoken",
    +- /* 317 */ "vtabargtoken ::= ANY",
    +- /* 318 */ "vtabargtoken ::= lp anylist RP",
    +- /* 319 */ "lp ::= LP",
    +- /* 320 */ "anylist ::=",
    +- /* 321 */ "anylist ::= anylist LP anylist RP",
    +- /* 322 */ "anylist ::= anylist ANY",
    +- /* 323 */ "with ::=",
    +- /* 324 */ "with ::= WITH wqlist",
    +- /* 325 */ "with ::= WITH RECURSIVE wqlist",
    +- /* 326 */ "wqlist ::= nm eidlist_opt AS LP select RP",
    +- /* 327 */ "wqlist ::= wqlist COMMA nm eidlist_opt AS LP select RP",
    ++ /*   0 */ "explain ::= EXPLAIN",
    ++ /*   1 */ "explain ::= EXPLAIN QUERY PLAN",
    ++ /*   2 */ "cmdx ::= cmd",
    ++ /*   3 */ "cmd ::= BEGIN transtype trans_opt",
    ++ /*   4 */ "transtype ::=",
    ++ /*   5 */ "transtype ::= DEFERRED",
    ++ /*   6 */ "transtype ::= IMMEDIATE",
    ++ /*   7 */ "transtype ::= EXCLUSIVE",
    ++ /*   8 */ "cmd ::= COMMIT|END trans_opt",
    ++ /*   9 */ "cmd ::= ROLLBACK trans_opt",
    ++ /*  10 */ "cmd ::= SAVEPOINT nm",
    ++ /*  11 */ "cmd ::= RELEASE savepoint_opt nm",
    ++ /*  12 */ "cmd ::= ROLLBACK trans_opt TO savepoint_opt nm",
    ++ /*  13 */ "create_table ::= createkw temp TABLE ifnotexists nm dbnm",
    ++ /*  14 */ "createkw ::= CREATE",
    ++ /*  15 */ "ifnotexists ::=",
    ++ /*  16 */ "ifnotexists ::= IF NOT EXISTS",
    ++ /*  17 */ "temp ::= TEMP",
    ++ /*  18 */ "temp ::=",
    ++ /*  19 */ "create_table_args ::= LP columnlist conslist_opt RP table_options",
    ++ /*  20 */ "create_table_args ::= AS select",
    ++ /*  21 */ "table_options ::=",
    ++ /*  22 */ "table_options ::= WITHOUT nm",
    ++ /*  23 */ "columnname ::= nm typetoken",
    ++ /*  24 */ "typetoken ::=",
    ++ /*  25 */ "typetoken ::= typename LP signed RP",
    ++ /*  26 */ "typetoken ::= typename LP signed COMMA signed RP",
    ++ /*  27 */ "typename ::= typename ID|STRING",
    ++ /*  28 */ "scanpt ::=",
    ++ /*  29 */ "ccons ::= CONSTRAINT nm",
    ++ /*  30 */ "ccons ::= DEFAULT scanpt term scanpt",
    ++ /*  31 */ "ccons ::= DEFAULT LP expr RP",
    ++ /*  32 */ "ccons ::= DEFAULT PLUS term scanpt",
    ++ /*  33 */ "ccons ::= DEFAULT MINUS term scanpt",
    ++ /*  34 */ "ccons ::= DEFAULT scanpt ID|INDEXED",
    ++ /*  35 */ "ccons ::= NOT NULL onconf",
    ++ /*  36 */ "ccons ::= PRIMARY KEY sortorder onconf autoinc",
    ++ /*  37 */ "ccons ::= UNIQUE onconf",
    ++ /*  38 */ "ccons ::= CHECK LP expr RP",
    ++ /*  39 */ "ccons ::= REFERENCES nm eidlist_opt refargs",
    ++ /*  40 */ "ccons ::= defer_subclause",
    ++ /*  41 */ "ccons ::= COLLATE ID|STRING",
    ++ /*  42 */ "autoinc ::=",
    ++ /*  43 */ "autoinc ::= AUTOINCR",
    ++ /*  44 */ "refargs ::=",
    ++ /*  45 */ "refargs ::= refargs refarg",
    ++ /*  46 */ "refarg ::= MATCH nm",
    ++ /*  47 */ "refarg ::= ON INSERT refact",
    ++ /*  48 */ "refarg ::= ON DELETE refact",
    ++ /*  49 */ "refarg ::= ON UPDATE refact",
    ++ /*  50 */ "refact ::= SET NULL",
    ++ /*  51 */ "refact ::= SET DEFAULT",
    ++ /*  52 */ "refact ::= CASCADE",
    ++ /*  53 */ "refact ::= RESTRICT",
    ++ /*  54 */ "refact ::= NO ACTION",
    ++ /*  55 */ "defer_subclause ::= NOT DEFERRABLE init_deferred_pred_opt",
    ++ /*  56 */ "defer_subclause ::= DEFERRABLE init_deferred_pred_opt",
    ++ /*  57 */ "init_deferred_pred_opt ::=",
    ++ /*  58 */ "init_deferred_pred_opt ::= INITIALLY DEFERRED",
    ++ /*  59 */ "init_deferred_pred_opt ::= INITIALLY IMMEDIATE",
    ++ /*  60 */ "conslist_opt ::=",
    ++ /*  61 */ "tconscomma ::= COMMA",
    ++ /*  62 */ "tcons ::= CONSTRAINT nm",
    ++ /*  63 */ "tcons ::= PRIMARY KEY LP sortlist autoinc RP onconf",
    ++ /*  64 */ "tcons ::= UNIQUE LP sortlist RP onconf",
    ++ /*  65 */ "tcons ::= CHECK LP expr RP onconf",
    ++ /*  66 */ "tcons ::= FOREIGN KEY LP eidlist RP REFERENCES nm eidlist_opt refargs defer_subclause_opt",
    ++ /*  67 */ "defer_subclause_opt ::=",
    ++ /*  68 */ "onconf ::=",
    ++ /*  69 */ "onconf ::= ON CONFLICT resolvetype",
    ++ /*  70 */ "orconf ::=",
    ++ /*  71 */ "orconf ::= OR resolvetype",
    ++ /*  72 */ "resolvetype ::= IGNORE",
    ++ /*  73 */ "resolvetype ::= REPLACE",
    ++ /*  74 */ "cmd ::= DROP TABLE ifexists fullname",
    ++ /*  75 */ "ifexists ::= IF EXISTS",
    ++ /*  76 */ "ifexists ::=",
    ++ /*  77 */ "cmd ::= createkw temp VIEW ifnotexists nm dbnm eidlist_opt AS select",
    ++ /*  78 */ "cmd ::= DROP VIEW ifexists fullname",
    ++ /*  79 */ "cmd ::= select",
    ++ /*  80 */ "select ::= with selectnowith",
    ++ /*  81 */ "selectnowith ::= selectnowith multiselect_op oneselect",
    ++ /*  82 */ "multiselect_op ::= UNION",
    ++ /*  83 */ "multiselect_op ::= UNION ALL",
    ++ /*  84 */ "multiselect_op ::= EXCEPT|INTERSECT",
    ++ /*  85 */ "oneselect ::= SELECT distinct selcollist from where_opt groupby_opt having_opt orderby_opt limit_opt",
    ++ /*  86 */ "values ::= VALUES LP nexprlist RP",
    ++ /*  87 */ "values ::= values COMMA LP exprlist RP",
    ++ /*  88 */ "distinct ::= DISTINCT",
    ++ /*  89 */ "distinct ::= ALL",
    ++ /*  90 */ "distinct ::=",
    ++ /*  91 */ "sclp ::=",
    ++ /*  92 */ "selcollist ::= sclp scanpt expr scanpt as",
    ++ /*  93 */ "selcollist ::= sclp scanpt STAR",
    ++ /*  94 */ "selcollist ::= sclp scanpt nm DOT STAR",
    ++ /*  95 */ "as ::= AS nm",
    ++ /*  96 */ "as ::=",
    ++ /*  97 */ "from ::=",
    ++ /*  98 */ "from ::= FROM seltablist",
    ++ /*  99 */ "stl_prefix ::= seltablist joinop",
    ++ /* 100 */ "stl_prefix ::=",
    ++ /* 101 */ "seltablist ::= stl_prefix nm dbnm as indexed_opt on_opt using_opt",
    ++ /* 102 */ "seltablist ::= stl_prefix nm dbnm LP exprlist RP as on_opt using_opt",
    ++ /* 103 */ "seltablist ::= stl_prefix LP select RP as on_opt using_opt",
    ++ /* 104 */ "seltablist ::= stl_prefix LP seltablist RP as on_opt using_opt",
    ++ /* 105 */ "dbnm ::=",
    ++ /* 106 */ "dbnm ::= DOT nm",
    ++ /* 107 */ "fullname ::= nm dbnm",
    ++ /* 108 */ "joinop ::= COMMA|JOIN",
    ++ /* 109 */ "joinop ::= JOIN_KW JOIN",
    ++ /* 110 */ "joinop ::= JOIN_KW nm JOIN",
    ++ /* 111 */ "joinop ::= JOIN_KW nm nm JOIN",
    ++ /* 112 */ "on_opt ::= ON expr",
    ++ /* 113 */ "on_opt ::=",
    ++ /* 114 */ "indexed_opt ::=",
    ++ /* 115 */ "indexed_opt ::= INDEXED BY nm",
    ++ /* 116 */ "indexed_opt ::= NOT INDEXED",
    ++ /* 117 */ "using_opt ::= USING LP idlist RP",
    ++ /* 118 */ "using_opt ::=",
    ++ /* 119 */ "orderby_opt ::=",
    ++ /* 120 */ "orderby_opt ::= ORDER BY sortlist",
    ++ /* 121 */ "sortlist ::= sortlist COMMA expr sortorder",
    ++ /* 122 */ "sortlist ::= expr sortorder",
    ++ /* 123 */ "sortorder ::= ASC",
    ++ /* 124 */ "sortorder ::= DESC",
    ++ /* 125 */ "sortorder ::=",
    ++ /* 126 */ "groupby_opt ::=",
    ++ /* 127 */ "groupby_opt ::= GROUP BY nexprlist",
    ++ /* 128 */ "having_opt ::=",
    ++ /* 129 */ "having_opt ::= HAVING expr",
    ++ /* 130 */ "limit_opt ::=",
    ++ /* 131 */ "limit_opt ::= LIMIT expr",
    ++ /* 132 */ "limit_opt ::= LIMIT expr OFFSET expr",
    ++ /* 133 */ "limit_opt ::= LIMIT expr COMMA expr",
    ++ /* 134 */ "cmd ::= with DELETE FROM fullname indexed_opt where_opt",
    ++ /* 135 */ "where_opt ::=",
    ++ /* 136 */ "where_opt ::= WHERE expr",
    ++ /* 137 */ "cmd ::= with UPDATE orconf fullname indexed_opt SET setlist where_opt",
    ++ /* 138 */ "setlist ::= setlist COMMA nm EQ expr",
    ++ /* 139 */ "setlist ::= setlist COMMA LP idlist RP EQ expr",
    ++ /* 140 */ "setlist ::= nm EQ expr",
    ++ /* 141 */ "setlist ::= LP idlist RP EQ expr",
    ++ /* 142 */ "cmd ::= with insert_cmd INTO fullname idlist_opt select",
    ++ /* 143 */ "cmd ::= with insert_cmd INTO fullname idlist_opt DEFAULT VALUES",
    ++ /* 144 */ "insert_cmd ::= INSERT orconf",
    ++ /* 145 */ "insert_cmd ::= REPLACE",
    ++ /* 146 */ "idlist_opt ::=",
    ++ /* 147 */ "idlist_opt ::= LP idlist RP",
    ++ /* 148 */ "idlist ::= idlist COMMA nm",
    ++ /* 149 */ "idlist ::= nm",
    ++ /* 150 */ "expr ::= LP expr RP",
    ++ /* 151 */ "expr ::= ID|INDEXED",
    ++ /* 152 */ "expr ::= JOIN_KW",
    ++ /* 153 */ "expr ::= nm DOT nm",
    ++ /* 154 */ "expr ::= nm DOT nm DOT nm",
    ++ /* 155 */ "term ::= NULL|FLOAT|BLOB",
    ++ /* 156 */ "term ::= STRING",
    ++ /* 157 */ "term ::= INTEGER",
    ++ /* 158 */ "expr ::= VARIABLE",
    ++ /* 159 */ "expr ::= expr COLLATE ID|STRING",
    ++ /* 160 */ "expr ::= CAST LP expr AS typetoken RP",
    ++ /* 161 */ "expr ::= ID|INDEXED LP distinct exprlist RP",
    ++ /* 162 */ "expr ::= ID|INDEXED LP STAR RP",
    ++ /* 163 */ "term ::= CTIME_KW",
    ++ /* 164 */ "expr ::= LP nexprlist COMMA expr RP",
    ++ /* 165 */ "expr ::= expr AND expr",
    ++ /* 166 */ "expr ::= expr OR expr",
    ++ /* 167 */ "expr ::= expr LT|GT|GE|LE expr",
    ++ /* 168 */ "expr ::= expr EQ|NE expr",
    ++ /* 169 */ "expr ::= expr BITAND|BITOR|LSHIFT|RSHIFT expr",
    ++ /* 170 */ "expr ::= expr PLUS|MINUS expr",
    ++ /* 171 */ "expr ::= expr STAR|SLASH|REM expr",
    ++ /* 172 */ "expr ::= expr CONCAT expr",
    ++ /* 173 */ "likeop ::= NOT LIKE_KW|MATCH",
    ++ /* 174 */ "expr ::= expr likeop expr",
    ++ /* 175 */ "expr ::= expr likeop expr ESCAPE expr",
    ++ /* 176 */ "expr ::= expr ISNULL|NOTNULL",
    ++ /* 177 */ "expr ::= expr NOT NULL",
    ++ /* 178 */ "expr ::= expr IS expr",
    ++ /* 179 */ "expr ::= expr IS NOT expr",
    ++ /* 180 */ "expr ::= NOT expr",
    ++ /* 181 */ "expr ::= BITNOT expr",
    ++ /* 182 */ "expr ::= MINUS expr",
    ++ /* 183 */ "expr ::= PLUS expr",
    ++ /* 184 */ "between_op ::= BETWEEN",
    ++ /* 185 */ "between_op ::= NOT BETWEEN",
    ++ /* 186 */ "expr ::= expr between_op expr AND expr",
    ++ /* 187 */ "in_op ::= IN",
    ++ /* 188 */ "in_op ::= NOT IN",
    ++ /* 189 */ "expr ::= expr in_op LP exprlist RP",
    ++ /* 190 */ "expr ::= LP select RP",
    ++ /* 191 */ "expr ::= expr in_op LP select RP",
    ++ /* 192 */ "expr ::= expr in_op nm dbnm paren_exprlist",
    ++ /* 193 */ "expr ::= EXISTS LP select RP",
    ++ /* 194 */ "expr ::= CASE case_operand case_exprlist case_else END",
    ++ /* 195 */ "case_exprlist ::= case_exprlist WHEN expr THEN expr",
    ++ /* 196 */ "case_exprlist ::= WHEN expr THEN expr",
    ++ /* 197 */ "case_else ::= ELSE expr",
    ++ /* 198 */ "case_else ::=",
    ++ /* 199 */ "case_operand ::= expr",
    ++ /* 200 */ "case_operand ::=",
    ++ /* 201 */ "exprlist ::=",
    ++ /* 202 */ "nexprlist ::= nexprlist COMMA expr",
    ++ /* 203 */ "nexprlist ::= expr",
    ++ /* 204 */ "paren_exprlist ::=",
    ++ /* 205 */ "paren_exprlist ::= LP exprlist RP",
    ++ /* 206 */ "cmd ::= createkw uniqueflag INDEX ifnotexists nm dbnm ON nm LP sortlist RP where_opt",
    ++ /* 207 */ "uniqueflag ::= UNIQUE",
    ++ /* 208 */ "uniqueflag ::=",
    ++ /* 209 */ "eidlist_opt ::=",
    ++ /* 210 */ "eidlist_opt ::= LP eidlist RP",
    ++ /* 211 */ "eidlist ::= eidlist COMMA nm collate sortorder",
    ++ /* 212 */ "eidlist ::= nm collate sortorder",
    ++ /* 213 */ "collate ::=",
    ++ /* 214 */ "collate ::= COLLATE ID|STRING",
    ++ /* 215 */ "cmd ::= DROP INDEX ifexists fullname",
    ++ /* 216 */ "cmd ::= VACUUM",
    ++ /* 217 */ "cmd ::= VACUUM nm",
    ++ /* 218 */ "cmd ::= PRAGMA nm dbnm",
    ++ /* 219 */ "cmd ::= PRAGMA nm dbnm EQ nmnum",
    ++ /* 220 */ "cmd ::= PRAGMA nm dbnm LP nmnum RP",
    ++ /* 221 */ "cmd ::= PRAGMA nm dbnm EQ minus_num",
    ++ /* 222 */ "cmd ::= PRAGMA nm dbnm LP minus_num RP",
    ++ /* 223 */ "plus_num ::= PLUS INTEGER|FLOAT",
    ++ /* 224 */ "minus_num ::= MINUS INTEGER|FLOAT",
    ++ /* 225 */ "cmd ::= createkw trigger_decl BEGIN trigger_cmd_list END",
    ++ /* 226 */ "trigger_decl ::= temp TRIGGER ifnotexists nm dbnm trigger_time trigger_event ON fullname foreach_clause when_clause",
    ++ /* 227 */ "trigger_time ::= BEFORE|AFTER",
    ++ /* 228 */ "trigger_time ::= INSTEAD OF",
    ++ /* 229 */ "trigger_time ::=",
    ++ /* 230 */ "trigger_event ::= DELETE|INSERT",
    ++ /* 231 */ "trigger_event ::= UPDATE",
    ++ /* 232 */ "trigger_event ::= UPDATE OF idlist",
    ++ /* 233 */ "when_clause ::=",
    ++ /* 234 */ "when_clause ::= WHEN expr",
    ++ /* 235 */ "trigger_cmd_list ::= trigger_cmd_list trigger_cmd SEMI",
    ++ /* 236 */ "trigger_cmd_list ::= trigger_cmd SEMI",
    ++ /* 237 */ "trnm ::= nm DOT nm",
    ++ /* 238 */ "tridxby ::= INDEXED BY nm",
    ++ /* 239 */ "tridxby ::= NOT INDEXED",
    ++ /* 240 */ "trigger_cmd ::= UPDATE orconf trnm tridxby SET setlist where_opt scanpt",
    ++ /* 241 */ "trigger_cmd ::= scanpt insert_cmd INTO trnm idlist_opt select scanpt",
    ++ /* 242 */ "trigger_cmd ::= DELETE FROM trnm tridxby where_opt scanpt",
    ++ /* 243 */ "trigger_cmd ::= scanpt select scanpt",
    ++ /* 244 */ "expr ::= RAISE LP IGNORE RP",
    ++ /* 245 */ "expr ::= RAISE LP raisetype COMMA nm RP",
    ++ /* 246 */ "raisetype ::= ROLLBACK",
    ++ /* 247 */ "raisetype ::= ABORT",
    ++ /* 248 */ "raisetype ::= FAIL",
    ++ /* 249 */ "cmd ::= DROP TRIGGER ifexists fullname",
    ++ /* 250 */ "cmd ::= ATTACH database_kw_opt expr AS expr key_opt",
    ++ /* 251 */ "cmd ::= DETACH database_kw_opt expr",
    ++ /* 252 */ "key_opt ::=",
    ++ /* 253 */ "key_opt ::= KEY expr",
    ++ /* 254 */ "cmd ::= REINDEX",
    ++ /* 255 */ "cmd ::= REINDEX nm dbnm",
    ++ /* 256 */ "cmd ::= ANALYZE",
    ++ /* 257 */ "cmd ::= ANALYZE nm dbnm",
    ++ /* 258 */ "cmd ::= ALTER TABLE fullname RENAME TO nm",
    ++ /* 259 */ "cmd ::= ALTER TABLE add_column_fullname ADD kwcolumn_opt columnname carglist",
    ++ /* 260 */ "add_column_fullname ::= fullname",
    ++ /* 261 */ "cmd ::= create_vtab",
    ++ /* 262 */ "cmd ::= create_vtab LP vtabarglist RP",
    ++ /* 263 */ "create_vtab ::= createkw VIRTUAL TABLE ifnotexists nm dbnm USING nm",
    ++ /* 264 */ "vtabarg ::=",
    ++ /* 265 */ "vtabargtoken ::= ANY",
    ++ /* 266 */ "vtabargtoken ::= lp anylist RP",
    ++ /* 267 */ "lp ::= LP",
    ++ /* 268 */ "with ::=",
    ++ /* 269 */ "with ::= WITH wqlist",
    ++ /* 270 */ "with ::= WITH RECURSIVE wqlist",
    ++ /* 271 */ "wqlist ::= nm eidlist_opt AS LP select RP",
    ++ /* 272 */ "wqlist ::= wqlist COMMA nm eidlist_opt AS LP select RP",
    ++ /* 273 */ "input ::= cmdlist",
    ++ /* 274 */ "cmdlist ::= cmdlist ecmd",
    ++ /* 275 */ "cmdlist ::= ecmd",
    ++ /* 276 */ "ecmd ::= SEMI",
    ++ /* 277 */ "ecmd ::= explain cmdx SEMI",
    ++ /* 278 */ "explain ::=",
    ++ /* 279 */ "trans_opt ::=",
    ++ /* 280 */ "trans_opt ::= TRANSACTION",
    ++ /* 281 */ "trans_opt ::= TRANSACTION nm",
    ++ /* 282 */ "savepoint_opt ::= SAVEPOINT",
    ++ /* 283 */ "savepoint_opt ::=",
    ++ /* 284 */ "cmd ::= create_table create_table_args",
    ++ /* 285 */ "columnlist ::= columnlist COMMA columnname carglist",
    ++ /* 286 */ "columnlist ::= columnname carglist",
    ++ /* 287 */ "nm ::= ID|INDEXED",
    ++ /* 288 */ "nm ::= STRING",
    ++ /* 289 */ "nm ::= JOIN_KW",
    ++ /* 290 */ "typetoken ::= typename",
    ++ /* 291 */ "typename ::= ID|STRING",
    ++ /* 292 */ "signed ::= plus_num",
    ++ /* 293 */ "signed ::= minus_num",
    ++ /* 294 */ "carglist ::= carglist ccons",
    ++ /* 295 */ "carglist ::=",
    ++ /* 296 */ "ccons ::= NULL onconf",
    ++ /* 297 */ "conslist_opt ::= COMMA conslist",
    ++ /* 298 */ "conslist ::= conslist tconscomma tcons",
    ++ /* 299 */ "conslist ::= tcons",
    ++ /* 300 */ "tconscomma ::=",
    ++ /* 301 */ "defer_subclause_opt ::= defer_subclause",
    ++ /* 302 */ "resolvetype ::= raisetype",
    ++ /* 303 */ "selectnowith ::= oneselect",
    ++ /* 304 */ "oneselect ::= values",
    ++ /* 305 */ "sclp ::= selcollist COMMA",
    ++ /* 306 */ "as ::= ID|STRING",
    ++ /* 307 */ "expr ::= term",
    ++ /* 308 */ "likeop ::= LIKE_KW|MATCH",
    ++ /* 309 */ "exprlist ::= nexprlist",
    ++ /* 310 */ "nmnum ::= plus_num",
    ++ /* 311 */ "nmnum ::= nm",
    ++ /* 312 */ "nmnum ::= ON",
    ++ /* 313 */ "nmnum ::= DELETE",
    ++ /* 314 */ "nmnum ::= DEFAULT",
    ++ /* 315 */ "plus_num ::= INTEGER|FLOAT",
    ++ /* 316 */ "foreach_clause ::=",
    ++ /* 317 */ "foreach_clause ::= FOR EACH ROW",
    ++ /* 318 */ "trnm ::= nm",
    ++ /* 319 */ "tridxby ::=",
    ++ /* 320 */ "database_kw_opt ::= DATABASE",
    ++ /* 321 */ "database_kw_opt ::=",
    ++ /* 322 */ "kwcolumn_opt ::=",
    ++ /* 323 */ "kwcolumn_opt ::= COLUMNKW",
    ++ /* 324 */ "vtabarglist ::= vtabarg",
    ++ /* 325 */ "vtabarglist ::= vtabarglist COMMA vtabarg",
    ++ /* 326 */ "vtabarg ::= vtabarg vtabargtoken",
    ++ /* 327 */ "anylist ::=",
    ++ /* 328 */ "anylist ::= anylist LP anylist RP",
    ++ /* 329 */ "anylist ::= anylist ANY",
    + };
    + #endif /* NDEBUG */
    + 
    + 
    + #if YYSTACKDEPTH<=0
    + /*
    +-** Try to increase the size of the parser stack.
    ++** Try to increase the size of the parser stack.  Return the number
    ++** of errors.  Return 0 on success.
    + */
    +-static void yyGrowStack(yyParser *p){
    ++static int yyGrowStack(yyParser *p){
    +   int newSize;
    ++  int idx;
    +   yyStackEntry *pNew;
    + 
    +   newSize = p->yystksz*2 + 100;
    +-  pNew = realloc(p->yystack, newSize*sizeof(pNew[0]));
    ++  idx = p->yytos ? (int)(p->yytos - p->yystack) : 0;
    ++  if( p->yystack==&p->yystk0 ){
    ++    pNew = malloc(newSize*sizeof(pNew[0]));
    ++    if( pNew ) pNew[0] = p->yystk0;
    ++  }else{
    ++    pNew = realloc(p->yystack, newSize*sizeof(pNew[0]));
    ++  }
    +   if( pNew ){
    +     p->yystack = pNew;
    +-    p->yystksz = newSize;
    ++    p->yytos = &p->yystack[idx];
    + #ifndef NDEBUG
    +     if( yyTraceFILE ){
    +-      fprintf(yyTraceFILE,"%sStack grows to %d entries!\n",
    +-              yyTracePrompt, p->yystksz);
    ++      fprintf(yyTraceFILE,"%sStack grows from %d to %d entries.\n",
    ++              yyTracePrompt, p->yystksz, newSize);
    +     }
    + #endif
    ++    p->yystksz = newSize;
    +   }
    ++  return pNew==0; 
    + }
    + #endif
    + 
    ++/* Datatype of the argument to the memory allocated passed as the
    ++** second argument to sqlite3ParserAlloc() below.  This can be changed by
    ++** putting an appropriate #define in the %include section of the input
    ++** grammar.
    ++*/
    ++#ifndef YYMALLOCARGTYPE
    ++# define YYMALLOCARGTYPE size_t
    ++#endif
    ++
    ++/* Initialize a new parser that has already been allocated.
    ++*/
    ++SQLITE_PRIVATE void sqlite3ParserInit(void *yypParser){
    ++  yyParser *pParser = (yyParser*)yypParser;
    ++#ifdef YYTRACKMAXSTACKDEPTH
    ++  pParser->yyhwm = 0;
    ++#endif
    ++#if YYSTACKDEPTH<=0
    ++  pParser->yytos = NULL;
    ++  pParser->yystack = NULL;
    ++  pParser->yystksz = 0;
    ++  if( yyGrowStack(pParser) ){
    ++    pParser->yystack = &pParser->yystk0;
    ++    pParser->yystksz = 1;
    ++  }
    ++#endif
    ++#ifndef YYNOERRORRECOVERY
    ++  pParser->yyerrcnt = -1;
    ++#endif
    ++  pParser->yytos = pParser->yystack;
    ++  pParser->yystack[0].stateno = 0;
    ++  pParser->yystack[0].major = 0;
    ++#if YYSTACKDEPTH>0
    ++  pParser->yystackEnd = &pParser->yystack[YYSTACKDEPTH-1];
    ++#endif
    ++}
    ++
    ++#ifndef sqlite3Parser_ENGINEALWAYSONSTACK
    + /* 
    + ** This function allocates a new parser.
    + ** The only argument is a pointer to a function which works like
    +@@ -127372,27 +139771,21 @@ static void yyGrowStack(yyParser *p){
    + ** A pointer to a parser.  This pointer is used in subsequent calls
    + ** to sqlite3Parser and sqlite3ParserFree.
    + */
    +-SQLITE_PRIVATE void *sqlite3ParserAlloc(void *(*mallocProc)(u64)){
    ++SQLITE_PRIVATE void *sqlite3ParserAlloc(void *(*mallocProc)(YYMALLOCARGTYPE)){
    +   yyParser *pParser;
    +-  pParser = (yyParser*)(*mallocProc)( (u64)sizeof(yyParser) );
    +-  if( pParser ){
    +-    pParser->yyidx = -1;
    +-#ifdef YYTRACKMAXSTACKDEPTH
    +-    pParser->yyidxMax = 0;
    +-#endif
    +-#if YYSTACKDEPTH<=0
    +-    pParser->yystack = NULL;
    +-    pParser->yystksz = 0;
    +-    yyGrowStack(pParser);
    +-#endif
    +-  }
    ++  pParser = (yyParser*)(*mallocProc)( (YYMALLOCARGTYPE)sizeof(yyParser) );
    ++  if( pParser ) sqlite3ParserInit(pParser);
    +   return pParser;
    + }
    ++#endif /* sqlite3Parser_ENGINEALWAYSONSTACK */
    ++
    + 
    +-/* The following function deletes the value associated with a
    +-** symbol.  The symbol can be either a terminal or nonterminal.
    +-** "yymajor" is the symbol code, and "yypminor" is a pointer to
    +-** the value.
    ++/* The following function deletes the "minor type" or semantic value
    ++** associated with a symbol.  The symbol can be either a terminal
    ++** or nonterminal. "yymajor" is the symbol code, and "yypminor" is
    ++** a pointer to the value to be deleted.  The code used to do the 
    ++** deletions is derived from the %destructor and/or %token_destructor
    ++** directives of the input grammar.
    + */
    + static void yy_destructor(
    +   yyParser *yypParser,    /* The parser */
    +@@ -127408,81 +139801,80 @@ static void yy_destructor(
    +     ** being destroyed before it is finished parsing.
    +     **
    +     ** Note: during a reduce, the only symbols destroyed are those
    +-    ** which appear on the RHS of the rule, but which are not used
    ++    ** which appear on the RHS of the rule, but which are *not* used
    +     ** inside the C code.
    +     */
    ++/********* Begin destructor definitions ***************************************/
    +     case 163: /* select */
    +-    case 196: /* selectnowith */
    +-    case 197: /* oneselect */
    +-    case 208: /* values */
    +-{
    +-sqlite3SelectDelete(pParse->db, (yypminor->yy3));
    +-}
    +-      break;
    +-    case 174: /* term */
    +-    case 175: /* expr */
    ++    case 195: /* selectnowith */
    ++    case 196: /* oneselect */
    ++    case 207: /* values */
    + {
    +-sqlite3ExprDelete(pParse->db, (yypminor->yy346).pExpr);
    ++sqlite3SelectDelete(pParse->db, (yypminor->yy387));
    + }
    +       break;
    +-    case 179: /* eidlist_opt */
    +-    case 188: /* sortlist */
    +-    case 189: /* eidlist */
    +-    case 201: /* selcollist */
    +-    case 204: /* groupby_opt */
    +-    case 206: /* orderby_opt */
    +-    case 209: /* nexprlist */
    +-    case 210: /* exprlist */
    +-    case 211: /* sclp */
    +-    case 221: /* setlist */
    +-    case 228: /* case_exprlist */
    ++    case 173: /* term */
    ++    case 174: /* expr */
    ++    case 202: /* where_opt */
    ++    case 204: /* having_opt */
    ++    case 216: /* on_opt */
    ++    case 226: /* case_operand */
    ++    case 228: /* case_else */
    ++    case 237: /* when_clause */
    ++    case 242: /* key_opt */
    + {
    +-sqlite3ExprListDelete(pParse->db, (yypminor->yy14));
    ++sqlite3ExprDelete(pParse->db, (yypminor->yy314));
    + }
    +       break;
    +-    case 195: /* fullname */
    +-    case 202: /* from */
    +-    case 213: /* seltablist */
    +-    case 214: /* stl_prefix */
    ++    case 178: /* eidlist_opt */
    ++    case 187: /* sortlist */
    ++    case 188: /* eidlist */
    ++    case 200: /* selcollist */
    ++    case 203: /* groupby_opt */
    ++    case 205: /* orderby_opt */
    ++    case 208: /* nexprlist */
    ++    case 209: /* exprlist */
    ++    case 210: /* sclp */
    ++    case 219: /* setlist */
    ++    case 225: /* paren_exprlist */
    ++    case 227: /* case_exprlist */
    + {
    +-sqlite3SrcListDelete(pParse->db, (yypminor->yy65));
    ++sqlite3ExprListDelete(pParse->db, (yypminor->yy322));
    + }
    +       break;
    +-    case 198: /* with */
    +-    case 252: /* wqlist */
    ++    case 194: /* fullname */
    ++    case 201: /* from */
    ++    case 212: /* seltablist */
    ++    case 213: /* stl_prefix */
    + {
    +-sqlite3WithDelete(pParse->db, (yypminor->yy59));
    ++sqlite3SrcListDelete(pParse->db, (yypminor->yy259));
    + }
    +       break;
    +-    case 203: /* where_opt */
    +-    case 205: /* having_opt */
    +-    case 217: /* on_opt */
    +-    case 227: /* case_operand */
    +-    case 229: /* case_else */
    +-    case 238: /* when_clause */
    +-    case 243: /* key_opt */
    ++    case 197: /* with */
    ++    case 251: /* wqlist */
    + {
    +-sqlite3ExprDelete(pParse->db, (yypminor->yy132));
    ++sqlite3WithDelete(pParse->db, (yypminor->yy451));
    + }
    +       break;
    +-    case 218: /* using_opt */
    +-    case 220: /* idlist */
    +-    case 223: /* idlist_opt */
    ++    case 217: /* using_opt */
    ++    case 218: /* idlist */
    ++    case 221: /* idlist_opt */
    + {
    +-sqlite3IdListDelete(pParse->db, (yypminor->yy408));
    ++sqlite3IdListDelete(pParse->db, (yypminor->yy384));
    + }
    +       break;
    +-    case 234: /* trigger_cmd_list */
    +-    case 239: /* trigger_cmd */
    ++    case 233: /* trigger_cmd_list */
    ++    case 238: /* trigger_cmd */
    + {
    +-sqlite3DeleteTriggerStep(pParse->db, (yypminor->yy473));
    ++sqlite3DeleteTriggerStep(pParse->db, (yypminor->yy203));
    + }
    +       break;
    +-    case 236: /* trigger_event */
    ++    case 235: /* trigger_event */
    + {
    +-sqlite3IdListDelete(pParse->db, (yypminor->yy378).b);
    ++sqlite3IdListDelete(pParse->db, (yypminor->yy90).b);
    + }
    +       break;
    ++/********* End destructor definitions *****************************************/
    +     default:  break;   /* If no destructor action specified: do nothing */
    +   }
    + }
    +@@ -127492,55 +139884,53 @@ sqlite3IdListDelete(pParse->db, (yypminor->yy378).b);
    + **
    + ** If there is a destructor routine associated with the token which
    + ** is popped from the stack, then call it.
    +-**
    +-** Return the major token number for the symbol popped.
    + */
    +-static int yy_pop_parser_stack(yyParser *pParser){
    +-  YYCODETYPE yymajor;
    +-  yyStackEntry *yytos = &pParser->yystack[pParser->yyidx];
    +-
    +-  /* There is no mechanism by which the parser stack can be popped below
    +-  ** empty in SQLite.  */
    +-  assert( pParser->yyidx>=0 );
    ++static void yy_pop_parser_stack(yyParser *pParser){
    ++  yyStackEntry *yytos;
    ++  assert( pParser->yytos!=0 );
    ++  assert( pParser->yytos > pParser->yystack );
    ++  yytos = pParser->yytos--;
    + #ifndef NDEBUG
    +-  if( yyTraceFILE && pParser->yyidx>=0 ){
    ++  if( yyTraceFILE ){
    +     fprintf(yyTraceFILE,"%sPopping %s\n",
    +       yyTracePrompt,
    +       yyTokenName[yytos->major]);
    +   }
    + #endif
    +-  yymajor = yytos->major;
    +-  yy_destructor(pParser, yymajor, &yytos->minor);
    +-  pParser->yyidx--;
    +-  return yymajor;
    ++  yy_destructor(pParser, yytos->major, &yytos->minor);
    + }
    + 
    ++/*
    ++** Clear all secondary memory allocations from the parser
    ++*/
    ++SQLITE_PRIVATE void sqlite3ParserFinalize(void *p){
    ++  yyParser *pParser = (yyParser*)p;
    ++  while( pParser->yytos>pParser->yystack ) yy_pop_parser_stack(pParser);
    ++#if YYSTACKDEPTH<=0
    ++  if( pParser->yystack!=&pParser->yystk0 ) free(pParser->yystack);
    ++#endif
    ++}
    ++
    ++#ifndef sqlite3Parser_ENGINEALWAYSONSTACK
    + /* 
    +-** Deallocate and destroy a parser.  Destructors are all called for
    ++** Deallocate and destroy a parser.  Destructors are called for
    + ** all stack elements before shutting the parser down.
    + **
    +-** Inputs:
    +-** <ul>
    +-** <li>  A pointer to the parser.  This should be a pointer
    +-**       obtained from sqlite3ParserAlloc.
    +-** <li>  A pointer to a function used to reclaim memory obtained
    +-**       from malloc.
    +-** </ul>
    ++** If the YYPARSEFREENEVERNULL macro exists (for example because it
    ++** is defined in a %include section of the input grammar) then it is
    ++** assumed that the input pointer is never NULL.
    + */
    + SQLITE_PRIVATE void sqlite3ParserFree(
    +   void *p,                    /* The parser to be deleted */
    +   void (*freeProc)(void*)     /* Function used to reclaim memory */
    + ){
    +-  yyParser *pParser = (yyParser*)p;
    +-  /* In SQLite, we never try to destroy a parser that was not successfully
    +-  ** created in the first place. */
    +-  if( NEVER(pParser==0) ) return;
    +-  while( pParser->yyidx>=0 ) yy_pop_parser_stack(pParser);
    +-#if YYSTACKDEPTH<=0
    +-  free(pParser->yystack);
    ++#ifndef YYPARSEFREENEVERNULL
    ++  if( p==0 ) return;
    + #endif
    +-  (*freeProc)((void*)pParser);
    ++  sqlite3ParserFinalize(p);
    ++  (*freeProc)(p);
    + }
    ++#endif /* sqlite3Parser_ENGINEALWAYSONSTACK */
    + 
    + /*
    + ** Return the peak depth of the stack for a parser.
    +@@ -127548,33 +139938,70 @@ SQLITE_PRIVATE void sqlite3ParserFree(
    + #ifdef YYTRACKMAXSTACKDEPTH
    + SQLITE_PRIVATE int sqlite3ParserStackPeak(void *p){
    +   yyParser *pParser = (yyParser*)p;
    +-  return pParser->yyidxMax;
    ++  return pParser->yyhwm;
    ++}
    ++#endif
    ++
    ++/* This array of booleans keeps track of the parser statement
    ++** coverage.  The element yycoverage[X][Y] is set when the parser
    ++** is in state X and has a lookahead token Y.  In a well-tested
    ++** systems, every element of this matrix should end up being set.
    ++*/
    ++#if defined(YYCOVERAGE)
    ++static unsigned char yycoverage[YYNSTATE][YYNTOKEN];
    ++#endif
    ++
    ++/*
    ++** Write into out a description of every state/lookahead combination that
    ++**
    ++**   (1)  has not been used by the parser, and
    ++**   (2)  is not a syntax error.
    ++**
    ++** Return the number of missed state/lookahead combinations.
    ++*/
    ++#if defined(YYCOVERAGE)
    ++SQLITE_PRIVATE int sqlite3ParserCoverage(FILE *out){
    ++  int stateno, iLookAhead, i;
    ++  int nMissed = 0;
    ++  for(stateno=0; stateno<YYNSTATE; stateno++){
    ++    i = yy_shift_ofst[stateno];
    ++    for(iLookAhead=0; iLookAhead<YYNTOKEN; iLookAhead++){
    ++      if( yy_lookahead[i+iLookAhead]!=iLookAhead ) continue;
    ++      if( yycoverage[stateno][iLookAhead]==0 ) nMissed++;
    ++      if( out ){
    ++        fprintf(out,"State %d lookahead %s %s\n", stateno,
    ++                yyTokenName[iLookAhead],
    ++                yycoverage[stateno][iLookAhead] ? "ok" : "missed");
    ++      }
    ++    }
    ++  }
    ++  return nMissed;
    + }
    + #endif
    + 
    + /*
    + ** Find the appropriate action for a parser given the terminal
    + ** look-ahead token iLookAhead.
    +-**
    +-** If the look-ahead token is YYNOCODE, then check to see if the action is
    +-** independent of the look-ahead.  If it is, return the action, otherwise
    +-** return YY_NO_ACTION.
    + */
    +-static int yy_find_shift_action(
    ++static unsigned int yy_find_shift_action(
    +   yyParser *pParser,        /* The parser */
    +   YYCODETYPE iLookAhead     /* The look-ahead token */
    + ){
    +   int i;
    +-  int stateno = pParser->yystack[pParser->yyidx].stateno;
    ++  int stateno = pParser->yytos->stateno;
    +  
    +-  if( stateno>=YY_MIN_REDUCE ) return stateno;
    ++  if( stateno>YY_MAX_SHIFT ) return stateno;
    +   assert( stateno <= YY_SHIFT_COUNT );
    +-  i = yy_shift_ofst[stateno];
    +-  if( i==YY_SHIFT_USE_DFLT ) return yy_default[stateno];
    +-  assert( iLookAhead!=YYNOCODE );
    +-  i += iLookAhead;
    +-  if( i<0 || i>=YY_ACTTAB_COUNT || yy_lookahead[i]!=iLookAhead ){
    +-    if( iLookAhead>0 ){
    ++#if defined(YYCOVERAGE)
    ++  yycoverage[stateno][iLookAhead] = 1;
    ++#endif
    ++  do{
    ++    i = yy_shift_ofst[stateno];
    ++    assert( i>=0 && i+YYNTOKEN<=sizeof(yy_lookahead)/sizeof(yy_lookahead[0]) );
    ++    assert( iLookAhead!=YYNOCODE );
    ++    assert( iLookAhead < YYNTOKEN );
    ++    i += iLookAhead;
    ++    if( yy_lookahead[i]!=iLookAhead ){
    + #ifdef YYFALLBACK
    +       YYCODETYPE iFallback;            /* Fallback token */
    +       if( iLookAhead<sizeof(yyFallback)/sizeof(yyFallback[0])
    +@@ -127585,7 +140012,9 @@ static int yy_find_shift_action(
    +              yyTracePrompt, yyTokenName[iLookAhead], yyTokenName[iFallback]);
    +         }
    + #endif
    +-        return yy_find_shift_action(pParser, iFallback);
    ++        assert( yyFallback[iFallback]==0 ); /* Fallback loop must terminate */
    ++        iLookAhead = iFallback;
    ++        continue;
    +       }
    + #endif
    + #ifdef YYWILDCARD
    +@@ -127598,32 +140027,29 @@ static int yy_find_shift_action(
    + #if YY_SHIFT_MAX+YYWILDCARD>=YY_ACTTAB_COUNT
    +           j<YY_ACTTAB_COUNT &&
    + #endif
    +-          yy_lookahead[j]==YYWILDCARD
    ++          yy_lookahead[j]==YYWILDCARD && iLookAhead>0
    +         ){
    + #ifndef NDEBUG
    +           if( yyTraceFILE ){
    +             fprintf(yyTraceFILE, "%sWILDCARD %s => %s\n",
    +-               yyTracePrompt, yyTokenName[iLookAhead], yyTokenName[YYWILDCARD]);
    ++               yyTracePrompt, yyTokenName[iLookAhead],
    ++               yyTokenName[YYWILDCARD]);
    +           }
    + #endif /* NDEBUG */
    +           return yy_action[j];
    +         }
    +       }
    + #endif /* YYWILDCARD */
    ++      return yy_default[stateno];
    ++    }else{
    ++      return yy_action[i];
    +     }
    +-    return yy_default[stateno];
    +-  }else{
    +-    return yy_action[i];
    +-  }
    ++  }while(1);
    + }
    + 
    + /*
    + ** Find the appropriate action for a parser given the non-terminal
    + ** look-ahead token iLookAhead.
    +-**
    +-** If the look-ahead token is YYNOCODE, then check to see if the action is
    +-** independent of the look-ahead.  If it is, return the action, otherwise
    +-** return YY_NO_ACTION.
    + */
    + static int yy_find_reduce_action(
    +   int stateno,              /* Current state number */
    +@@ -127638,7 +140064,6 @@ static int yy_find_reduce_action(
    +   assert( stateno<=YY_REDUCE_COUNT );
    + #endif
    +   i = yy_reduce_ofst[stateno];
    +-  assert( i!=YY_REDUCE_USE_DFLT );
    +   assert( iLookAhead!=YYNOCODE );
    +   i += iLookAhead;
    + #ifdef YYERRORSYMBOL
    +@@ -127655,20 +140080,20 @@ static int yy_find_reduce_action(
    + /*
    + ** The following routine is called if the stack overflows.
    + */
    +-static void yyStackOverflow(yyParser *yypParser, YYMINORTYPE *yypMinor){
    ++static void yyStackOverflow(yyParser *yypParser){
    +    sqlite3ParserARG_FETCH;
    +-   yypParser->yyidx--;
    + #ifndef NDEBUG
    +    if( yyTraceFILE ){
    +      fprintf(yyTraceFILE,"%sStack Overflow!\n",yyTracePrompt);
    +    }
    + #endif
    +-   while( yypParser->yyidx>=0 ) yy_pop_parser_stack(yypParser);
    ++   while( yypParser->yytos>yypParser->yystack ) yy_pop_parser_stack(yypParser);
    +    /* Here code is inserted which will execute if the parser
    +    ** stack every overflows */
    ++/******** Begin %stack_overflow code ******************************************/
    + 
    +-  UNUSED_PARAMETER(yypMinor); /* Silence some compiler warnings */
    +   sqlite3ErrorMsg(pParse, "parser stack overflow");
    ++/******** End %stack_overflow code ********************************************/
    +    sqlite3ParserARG_STORE; /* Suppress warning about unused %extra_argument var */
    + }
    + 
    +@@ -127676,396 +140101,402 @@ static void yyStackOverflow(yyParser *yypParser, YYMINORTYPE *yypMinor){
    + ** Print tracing information for a SHIFT action
    + */
    + #ifndef NDEBUG
    +-static void yyTraceShift(yyParser *yypParser, int yyNewState){
    ++static void yyTraceShift(yyParser *yypParser, int yyNewState, const char *zTag){
    +   if( yyTraceFILE ){
    +-    int i;
    +     if( yyNewState<YYNSTATE ){
    +-      fprintf(yyTraceFILE,"%sShift %d\n",yyTracePrompt,yyNewState);
    +-      fprintf(yyTraceFILE,"%sStack:",yyTracePrompt);
    +-      for(i=1; i<=yypParser->yyidx; i++)
    +-        fprintf(yyTraceFILE," %s",yyTokenName[yypParser->yystack[i].major]);
    +-      fprintf(yyTraceFILE,"\n");
    ++      fprintf(yyTraceFILE,"%s%s '%s', go to state %d\n",
    ++         yyTracePrompt, zTag, yyTokenName[yypParser->yytos->major],
    ++         yyNewState);
    +     }else{
    +-      fprintf(yyTraceFILE,"%sShift *\n",yyTracePrompt);
    ++      fprintf(yyTraceFILE,"%s%s '%s', pending reduce %d\n",
    ++         yyTracePrompt, zTag, yyTokenName[yypParser->yytos->major],
    ++         yyNewState - YY_MIN_REDUCE);
    +     }
    +   }
    + }
    + #else
    +-# define yyTraceShift(X,Y)
    ++# define yyTraceShift(X,Y,Z)
    + #endif
    + 
    + /*
    +-** Perform a shift action.  Return the number of errors.
    ++** Perform a shift action.
    + */
    + static void yy_shift(
    +   yyParser *yypParser,          /* The parser to be shifted */
    +   int yyNewState,               /* The new state to shift in */
    +   int yyMajor,                  /* The major token to shift in */
    +-  YYMINORTYPE *yypMinor         /* Pointer to the minor token to shift in */
    ++  sqlite3ParserTOKENTYPE yyMinor        /* The minor token to shift in */
    + ){
    +   yyStackEntry *yytos;
    +-  yypParser->yyidx++;
    ++  yypParser->yytos++;
    + #ifdef YYTRACKMAXSTACKDEPTH
    +-  if( yypParser->yyidx>yypParser->yyidxMax ){
    +-    yypParser->yyidxMax = yypParser->yyidx;
    ++  if( (int)(yypParser->yytos - yypParser->yystack)>yypParser->yyhwm ){
    ++    yypParser->yyhwm++;
    ++    assert( yypParser->yyhwm == (int)(yypParser->yytos - yypParser->yystack) );
    +   }
    + #endif
    + #if YYSTACKDEPTH>0 
    +-  if( yypParser->yyidx>=YYSTACKDEPTH ){
    +-    yyStackOverflow(yypParser, yypMinor);
    ++  if( yypParser->yytos>yypParser->yystackEnd ){
    ++    yypParser->yytos--;
    ++    yyStackOverflow(yypParser);
    +     return;
    +   }
    + #else
    +-  if( yypParser->yyidx>=yypParser->yystksz ){
    +-    yyGrowStack(yypParser);
    +-    if( yypParser->yyidx>=yypParser->yystksz ){
    +-      yyStackOverflow(yypParser, yypMinor);
    ++  if( yypParser->yytos>=&yypParser->yystack[yypParser->yystksz] ){
    ++    if( yyGrowStack(yypParser) ){
    ++      yypParser->yytos--;
    ++      yyStackOverflow(yypParser);
    +       return;
    +     }
    +   }
    + #endif
    +-  yytos = &yypParser->yystack[yypParser->yyidx];
    ++  if( yyNewState > YY_MAX_SHIFT ){
    ++    yyNewState += YY_MIN_REDUCE - YY_MIN_SHIFTREDUCE;
    ++  }
    ++  yytos = yypParser->yytos;
    +   yytos->stateno = (YYACTIONTYPE)yyNewState;
    +   yytos->major = (YYCODETYPE)yyMajor;
    +-  yytos->minor = *yypMinor;
    +-  yyTraceShift(yypParser, yyNewState);
    ++  yytos->minor.yy0 = yyMinor;
    ++  yyTraceShift(yypParser, yyNewState, "Shift");
    + }
    + 
    + /* The following table contains information about every rule that
    + ** is used during the reduce.
    + */
    + static const struct {
    +-  YYCODETYPE lhs;         /* Symbol on the left-hand side of the rule */
    +-  unsigned char nrhs;     /* Number of right-hand side symbols in the rule */
    ++  YYCODETYPE lhs;       /* Symbol on the left-hand side of the rule */
    ++  signed char nrhs;     /* Negative of the number of RHS symbols in the rule */
    + } yyRuleInfo[] = {
    +-  { 144, 1 },
    +-  { 145, 2 },
    +-  { 145, 1 },
    +-  { 146, 1 },
    +-  { 146, 3 },
    +-  { 147, 0 },
    +-  { 147, 1 },
    +-  { 147, 3 },
    +-  { 148, 1 },
    +-  { 149, 3 },
    +-  { 151, 0 },
    +-  { 151, 1 },
    +-  { 151, 2 },
    +-  { 150, 0 },
    +-  { 150, 1 },
    +-  { 150, 1 },
    +-  { 150, 1 },
    +-  { 149, 2 },
    +-  { 149, 2 },
    +-  { 149, 2 },
    +-  { 153, 1 },
    +-  { 153, 0 },
    +-  { 149, 2 },
    +-  { 149, 3 },
    +-  { 149, 5 },
    +-  { 149, 2 },
    +-  { 154, 6 },
    +-  { 156, 1 },
    +-  { 158, 0 },
    +-  { 158, 3 },
    +-  { 157, 1 },
    +-  { 157, 0 },
    +-  { 155, 5 },
    +-  { 155, 2 },
    +-  { 162, 0 },
    +-  { 162, 2 },
    +-  { 160, 3 },
    +-  { 160, 1 },
    +-  { 164, 3 },
    +-  { 165, 1 },
    +-  { 152, 1 },
    +-  { 152, 1 },
    +-  { 152, 1 },
    +-  { 166, 0 },
    +-  { 166, 1 },
    +-  { 168, 1 },
    +-  { 168, 4 },
    +-  { 168, 6 },
    +-  { 169, 1 },
    +-  { 169, 2 },
    +-  { 170, 1 },
    +-  { 170, 1 },
    +-  { 167, 2 },
    +-  { 167, 0 },
    +-  { 173, 2 },
    +-  { 173, 2 },
    +-  { 173, 4 },
    +-  { 173, 3 },
    +-  { 173, 3 },
    +-  { 173, 2 },
    +-  { 173, 2 },
    +-  { 173, 3 },
    +-  { 173, 5 },
    +-  { 173, 2 },
    +-  { 173, 4 },
    +-  { 173, 4 },
    +-  { 173, 1 },
    +-  { 173, 2 },
    +-  { 178, 0 },
    +-  { 178, 1 },
    +-  { 180, 0 },
    +-  { 180, 2 },
    +-  { 182, 2 },
    +-  { 182, 3 },
    +-  { 182, 3 },
    +-  { 182, 3 },
    +-  { 183, 2 },
    +-  { 183, 2 },
    +-  { 183, 1 },
    +-  { 183, 1 },
    +-  { 183, 2 },
    +-  { 181, 3 },
    +-  { 181, 2 },
    +-  { 184, 0 },
    +-  { 184, 2 },
    +-  { 184, 2 },
    +-  { 161, 0 },
    +-  { 161, 2 },
    +-  { 185, 3 },
    +-  { 185, 1 },
    +-  { 186, 1 },
    +-  { 186, 0 },
    +-  { 187, 2 },
    +-  { 187, 7 },
    +-  { 187, 5 },
    +-  { 187, 5 },
    +-  { 187, 10 },
    +-  { 190, 0 },
    +-  { 190, 1 },
    +-  { 176, 0 },
    +-  { 176, 3 },
    +-  { 191, 0 },
    +-  { 191, 2 },
    +-  { 192, 1 },
    +-  { 192, 1 },
    +-  { 192, 1 },
    +-  { 149, 4 },
    +-  { 194, 2 },
    +-  { 194, 0 },
    +-  { 149, 9 },
    +-  { 149, 4 },
    +-  { 149, 1 },
    +-  { 163, 2 },
    +-  { 196, 1 },
    +-  { 196, 3 },
    +-  { 199, 1 },
    +-  { 199, 2 },
    +-  { 199, 1 },
    +-  { 197, 9 },
    +-  { 197, 1 },
    +-  { 208, 4 },
    +-  { 208, 5 },
    +-  { 200, 1 },
    +-  { 200, 1 },
    +-  { 200, 0 },
    +-  { 211, 2 },
    +-  { 211, 0 },
    +-  { 201, 3 },
    +-  { 201, 2 },
    +-  { 201, 4 },
    +-  { 212, 2 },
    +-  { 212, 1 },
    +-  { 212, 0 },
    +-  { 202, 0 },
    +-  { 202, 2 },
    +-  { 214, 2 },
    +-  { 214, 0 },
    +-  { 213, 7 },
    +-  { 213, 9 },
    +-  { 213, 7 },
    +-  { 213, 7 },
    +-  { 159, 0 },
    +-  { 159, 2 },
    +-  { 195, 2 },
    +-  { 215, 1 },
    +-  { 215, 2 },
    +-  { 215, 3 },
    +-  { 215, 4 },
    +-  { 217, 2 },
    +-  { 217, 0 },
    +-  { 216, 0 },
    +-  { 216, 3 },
    +-  { 216, 2 },
    +-  { 218, 4 },
    +-  { 218, 0 },
    +-  { 206, 0 },
    +-  { 206, 3 },
    +-  { 188, 4 },
    +-  { 188, 2 },
    +-  { 177, 1 },
    +-  { 177, 1 },
    +-  { 177, 0 },
    +-  { 204, 0 },
    +-  { 204, 3 },
    +-  { 205, 0 },
    +-  { 205, 2 },
    +-  { 207, 0 },
    +-  { 207, 2 },
    +-  { 207, 4 },
    +-  { 207, 4 },
    +-  { 149, 6 },
    +-  { 203, 0 },
    +-  { 203, 2 },
    +-  { 149, 8 },
    +-  { 221, 5 },
    +-  { 221, 3 },
    +-  { 149, 6 },
    +-  { 149, 7 },
    +-  { 222, 2 },
    +-  { 222, 1 },
    +-  { 223, 0 },
    +-  { 223, 3 },
    +-  { 220, 3 },
    +-  { 220, 1 },
    +-  { 175, 1 },
    +-  { 175, 3 },
    +-  { 174, 1 },
    +-  { 175, 1 },
    +-  { 175, 1 },
    +-  { 175, 3 },
    +-  { 175, 5 },
    +-  { 174, 1 },
    +-  { 174, 1 },
    +-  { 175, 1 },
    +-  { 175, 3 },
    +-  { 175, 6 },
    +-  { 175, 5 },
    +-  { 175, 4 },
    +-  { 174, 1 },
    +-  { 175, 3 },
    +-  { 175, 3 },
    +-  { 175, 3 },
    +-  { 175, 3 },
    +-  { 175, 3 },
    +-  { 175, 3 },
    +-  { 175, 3 },
    +-  { 175, 3 },
    +-  { 224, 1 },
    +-  { 224, 2 },
    +-  { 175, 3 },
    +-  { 175, 5 },
    +-  { 175, 2 },
    +-  { 175, 3 },
    +-  { 175, 3 },
    +-  { 175, 4 },
    +-  { 175, 2 },
    +-  { 175, 2 },
    +-  { 175, 2 },
    +-  { 175, 2 },
    +-  { 225, 1 },
    +-  { 225, 2 },
    +-  { 175, 5 },
    +-  { 226, 1 },
    +-  { 226, 2 },
    +-  { 175, 5 },
    +-  { 175, 3 },
    +-  { 175, 5 },
    +-  { 175, 4 },
    +-  { 175, 4 },
    +-  { 175, 5 },
    +-  { 228, 5 },
    +-  { 228, 4 },
    +-  { 229, 2 },
    +-  { 229, 0 },
    +-  { 227, 1 },
    +-  { 227, 0 },
    +-  { 210, 1 },
    +-  { 210, 0 },
    +-  { 209, 3 },
    +-  { 209, 1 },
    +-  { 149, 12 },
    +-  { 230, 1 },
    +-  { 230, 0 },
    +-  { 179, 0 },
    +-  { 179, 3 },
    +-  { 189, 5 },
    +-  { 189, 3 },
    +-  { 231, 0 },
    +-  { 231, 2 },
    +-  { 149, 4 },
    +-  { 149, 1 },
    +-  { 149, 2 },
    +-  { 149, 3 },
    +-  { 149, 5 },
    +-  { 149, 6 },
    +-  { 149, 5 },
    +-  { 149, 6 },
    +-  { 232, 1 },
    +-  { 232, 1 },
    +-  { 232, 1 },
    +-  { 232, 1 },
    +-  { 232, 1 },
    +-  { 171, 2 },
    +-  { 171, 1 },
    +-  { 172, 2 },
    +-  { 149, 5 },
    +-  { 233, 11 },
    +-  { 235, 1 },
    +-  { 235, 1 },
    +-  { 235, 2 },
    +-  { 235, 0 },
    +-  { 236, 1 },
    +-  { 236, 1 },
    +-  { 236, 3 },
    +-  { 237, 0 },
    +-  { 237, 3 },
    +-  { 238, 0 },
    +-  { 238, 2 },
    +-  { 234, 3 },
    +-  { 234, 2 },
    +-  { 240, 1 },
    +-  { 240, 3 },
    +-  { 241, 0 },
    +-  { 241, 3 },
    +-  { 241, 2 },
    +-  { 239, 7 },
    +-  { 239, 5 },
    +-  { 239, 5 },
    +-  { 239, 1 },
    +-  { 175, 4 },
    +-  { 175, 6 },
    +-  { 193, 1 },
    +-  { 193, 1 },
    +-  { 193, 1 },
    +-  { 149, 4 },
    +-  { 149, 6 },
    +-  { 149, 3 },
    +-  { 243, 0 },
    +-  { 243, 2 },
    +-  { 242, 1 },
    +-  { 242, 0 },
    +-  { 149, 1 },
    +-  { 149, 3 },
    +-  { 149, 1 },
    +-  { 149, 3 },
    +-  { 149, 6 },
    +-  { 149, 6 },
    +-  { 244, 1 },
    +-  { 245, 0 },
    +-  { 245, 1 },
    +-  { 149, 1 },
    +-  { 149, 4 },
    +-  { 246, 8 },
    +-  { 247, 1 },
    +-  { 247, 3 },
    +-  { 248, 0 },
    +-  { 248, 2 },
    +-  { 249, 1 },
    +-  { 249, 3 },
    +-  { 250, 1 },
    +-  { 251, 0 },
    +-  { 251, 4 },
    +-  { 251, 2 },
    +-  { 198, 0 },
    +-  { 198, 2 },
    +-  { 198, 3 },
    +-  { 252, 6 },
    +-  { 252, 8 },
    ++  {  147,   -1 }, /* (0) explain ::= EXPLAIN */
    ++  {  147,   -3 }, /* (1) explain ::= EXPLAIN QUERY PLAN */
    ++  {  148,   -1 }, /* (2) cmdx ::= cmd */
    ++  {  149,   -3 }, /* (3) cmd ::= BEGIN transtype trans_opt */
    ++  {  150,    0 }, /* (4) transtype ::= */
    ++  {  150,   -1 }, /* (5) transtype ::= DEFERRED */
    ++  {  150,   -1 }, /* (6) transtype ::= IMMEDIATE */
    ++  {  150,   -1 }, /* (7) transtype ::= EXCLUSIVE */
    ++  {  149,   -2 }, /* (8) cmd ::= COMMIT|END trans_opt */
    ++  {  149,   -2 }, /* (9) cmd ::= ROLLBACK trans_opt */
    ++  {  149,   -2 }, /* (10) cmd ::= SAVEPOINT nm */
    ++  {  149,   -3 }, /* (11) cmd ::= RELEASE savepoint_opt nm */
    ++  {  149,   -5 }, /* (12) cmd ::= ROLLBACK trans_opt TO savepoint_opt nm */
    ++  {  154,   -6 }, /* (13) create_table ::= createkw temp TABLE ifnotexists nm dbnm */
    ++  {  156,   -1 }, /* (14) createkw ::= CREATE */
    ++  {  158,    0 }, /* (15) ifnotexists ::= */
    ++  {  158,   -3 }, /* (16) ifnotexists ::= IF NOT EXISTS */
    ++  {  157,   -1 }, /* (17) temp ::= TEMP */
    ++  {  157,    0 }, /* (18) temp ::= */
    ++  {  155,   -5 }, /* (19) create_table_args ::= LP columnlist conslist_opt RP table_options */
    ++  {  155,   -2 }, /* (20) create_table_args ::= AS select */
    ++  {  162,    0 }, /* (21) table_options ::= */
    ++  {  162,   -2 }, /* (22) table_options ::= WITHOUT nm */
    ++  {  164,   -2 }, /* (23) columnname ::= nm typetoken */
    ++  {  166,    0 }, /* (24) typetoken ::= */
    ++  {  166,   -4 }, /* (25) typetoken ::= typename LP signed RP */
    ++  {  166,   -6 }, /* (26) typetoken ::= typename LP signed COMMA signed RP */
    ++  {  167,   -2 }, /* (27) typename ::= typename ID|STRING */
    ++  {  171,    0 }, /* (28) scanpt ::= */
    ++  {  172,   -2 }, /* (29) ccons ::= CONSTRAINT nm */
    ++  {  172,   -4 }, /* (30) ccons ::= DEFAULT scanpt term scanpt */
    ++  {  172,   -4 }, /* (31) ccons ::= DEFAULT LP expr RP */
    ++  {  172,   -4 }, /* (32) ccons ::= DEFAULT PLUS term scanpt */
    ++  {  172,   -4 }, /* (33) ccons ::= DEFAULT MINUS term scanpt */
    ++  {  172,   -3 }, /* (34) ccons ::= DEFAULT scanpt ID|INDEXED */
    ++  {  172,   -3 }, /* (35) ccons ::= NOT NULL onconf */
    ++  {  172,   -5 }, /* (36) ccons ::= PRIMARY KEY sortorder onconf autoinc */
    ++  {  172,   -2 }, /* (37) ccons ::= UNIQUE onconf */
    ++  {  172,   -4 }, /* (38) ccons ::= CHECK LP expr RP */
    ++  {  172,   -4 }, /* (39) ccons ::= REFERENCES nm eidlist_opt refargs */
    ++  {  172,   -1 }, /* (40) ccons ::= defer_subclause */
    ++  {  172,   -2 }, /* (41) ccons ::= COLLATE ID|STRING */
    ++  {  177,    0 }, /* (42) autoinc ::= */
    ++  {  177,   -1 }, /* (43) autoinc ::= AUTOINCR */
    ++  {  179,    0 }, /* (44) refargs ::= */
    ++  {  179,   -2 }, /* (45) refargs ::= refargs refarg */
    ++  {  181,   -2 }, /* (46) refarg ::= MATCH nm */
    ++  {  181,   -3 }, /* (47) refarg ::= ON INSERT refact */
    ++  {  181,   -3 }, /* (48) refarg ::= ON DELETE refact */
    ++  {  181,   -3 }, /* (49) refarg ::= ON UPDATE refact */
    ++  {  182,   -2 }, /* (50) refact ::= SET NULL */
    ++  {  182,   -2 }, /* (51) refact ::= SET DEFAULT */
    ++  {  182,   -1 }, /* (52) refact ::= CASCADE */
    ++  {  182,   -1 }, /* (53) refact ::= RESTRICT */
    ++  {  182,   -2 }, /* (54) refact ::= NO ACTION */
    ++  {  180,   -3 }, /* (55) defer_subclause ::= NOT DEFERRABLE init_deferred_pred_opt */
    ++  {  180,   -2 }, /* (56) defer_subclause ::= DEFERRABLE init_deferred_pred_opt */
    ++  {  183,    0 }, /* (57) init_deferred_pred_opt ::= */
    ++  {  183,   -2 }, /* (58) init_deferred_pred_opt ::= INITIALLY DEFERRED */
    ++  {  183,   -2 }, /* (59) init_deferred_pred_opt ::= INITIALLY IMMEDIATE */
    ++  {  161,    0 }, /* (60) conslist_opt ::= */
    ++  {  185,   -1 }, /* (61) tconscomma ::= COMMA */
    ++  {  186,   -2 }, /* (62) tcons ::= CONSTRAINT nm */
    ++  {  186,   -7 }, /* (63) tcons ::= PRIMARY KEY LP sortlist autoinc RP onconf */
    ++  {  186,   -5 }, /* (64) tcons ::= UNIQUE LP sortlist RP onconf */
    ++  {  186,   -5 }, /* (65) tcons ::= CHECK LP expr RP onconf */
    ++  {  186,  -10 }, /* (66) tcons ::= FOREIGN KEY LP eidlist RP REFERENCES nm eidlist_opt refargs defer_subclause_opt */
    ++  {  189,    0 }, /* (67) defer_subclause_opt ::= */
    ++  {  175,    0 }, /* (68) onconf ::= */
    ++  {  175,   -3 }, /* (69) onconf ::= ON CONFLICT resolvetype */
    ++  {  190,    0 }, /* (70) orconf ::= */
    ++  {  190,   -2 }, /* (71) orconf ::= OR resolvetype */
    ++  {  191,   -1 }, /* (72) resolvetype ::= IGNORE */
    ++  {  191,   -1 }, /* (73) resolvetype ::= REPLACE */
    ++  {  149,   -4 }, /* (74) cmd ::= DROP TABLE ifexists fullname */
    ++  {  193,   -2 }, /* (75) ifexists ::= IF EXISTS */
    ++  {  193,    0 }, /* (76) ifexists ::= */
    ++  {  149,   -9 }, /* (77) cmd ::= createkw temp VIEW ifnotexists nm dbnm eidlist_opt AS select */
    ++  {  149,   -4 }, /* (78) cmd ::= DROP VIEW ifexists fullname */
    ++  {  149,   -1 }, /* (79) cmd ::= select */
    ++  {  163,   -2 }, /* (80) select ::= with selectnowith */
    ++  {  195,   -3 }, /* (81) selectnowith ::= selectnowith multiselect_op oneselect */
    ++  {  198,   -1 }, /* (82) multiselect_op ::= UNION */
    ++  {  198,   -2 }, /* (83) multiselect_op ::= UNION ALL */
    ++  {  198,   -1 }, /* (84) multiselect_op ::= EXCEPT|INTERSECT */
    ++  {  196,   -9 }, /* (85) oneselect ::= SELECT distinct selcollist from where_opt groupby_opt having_opt orderby_opt limit_opt */
    ++  {  207,   -4 }, /* (86) values ::= VALUES LP nexprlist RP */
    ++  {  207,   -5 }, /* (87) values ::= values COMMA LP exprlist RP */
    ++  {  199,   -1 }, /* (88) distinct ::= DISTINCT */
    ++  {  199,   -1 }, /* (89) distinct ::= ALL */
    ++  {  199,    0 }, /* (90) distinct ::= */
    ++  {  210,    0 }, /* (91) sclp ::= */
    ++  {  200,   -5 }, /* (92) selcollist ::= sclp scanpt expr scanpt as */
    ++  {  200,   -3 }, /* (93) selcollist ::= sclp scanpt STAR */
    ++  {  200,   -5 }, /* (94) selcollist ::= sclp scanpt nm DOT STAR */
    ++  {  211,   -2 }, /* (95) as ::= AS nm */
    ++  {  211,    0 }, /* (96) as ::= */
    ++  {  201,    0 }, /* (97) from ::= */
    ++  {  201,   -2 }, /* (98) from ::= FROM seltablist */
    ++  {  213,   -2 }, /* (99) stl_prefix ::= seltablist joinop */
    ++  {  213,    0 }, /* (100) stl_prefix ::= */
    ++  {  212,   -7 }, /* (101) seltablist ::= stl_prefix nm dbnm as indexed_opt on_opt using_opt */
    ++  {  212,   -9 }, /* (102) seltablist ::= stl_prefix nm dbnm LP exprlist RP as on_opt using_opt */
    ++  {  212,   -7 }, /* (103) seltablist ::= stl_prefix LP select RP as on_opt using_opt */
    ++  {  212,   -7 }, /* (104) seltablist ::= stl_prefix LP seltablist RP as on_opt using_opt */
    ++  {  159,    0 }, /* (105) dbnm ::= */
    ++  {  159,   -2 }, /* (106) dbnm ::= DOT nm */
    ++  {  194,   -2 }, /* (107) fullname ::= nm dbnm */
    ++  {  214,   -1 }, /* (108) joinop ::= COMMA|JOIN */
    ++  {  214,   -2 }, /* (109) joinop ::= JOIN_KW JOIN */
    ++  {  214,   -3 }, /* (110) joinop ::= JOIN_KW nm JOIN */
    ++  {  214,   -4 }, /* (111) joinop ::= JOIN_KW nm nm JOIN */
    ++  {  216,   -2 }, /* (112) on_opt ::= ON expr */
    ++  {  216,    0 }, /* (113) on_opt ::= */
    ++  {  215,    0 }, /* (114) indexed_opt ::= */
    ++  {  215,   -3 }, /* (115) indexed_opt ::= INDEXED BY nm */
    ++  {  215,   -2 }, /* (116) indexed_opt ::= NOT INDEXED */
    ++  {  217,   -4 }, /* (117) using_opt ::= USING LP idlist RP */
    ++  {  217,    0 }, /* (118) using_opt ::= */
    ++  {  205,    0 }, /* (119) orderby_opt ::= */
    ++  {  205,   -3 }, /* (120) orderby_opt ::= ORDER BY sortlist */
    ++  {  187,   -4 }, /* (121) sortlist ::= sortlist COMMA expr sortorder */
    ++  {  187,   -2 }, /* (122) sortlist ::= expr sortorder */
    ++  {  176,   -1 }, /* (123) sortorder ::= ASC */
    ++  {  176,   -1 }, /* (124) sortorder ::= DESC */
    ++  {  176,    0 }, /* (125) sortorder ::= */
    ++  {  203,    0 }, /* (126) groupby_opt ::= */
    ++  {  203,   -3 }, /* (127) groupby_opt ::= GROUP BY nexprlist */
    ++  {  204,    0 }, /* (128) having_opt ::= */
    ++  {  204,   -2 }, /* (129) having_opt ::= HAVING expr */
    ++  {  206,    0 }, /* (130) limit_opt ::= */
    ++  {  206,   -2 }, /* (131) limit_opt ::= LIMIT expr */
    ++  {  206,   -4 }, /* (132) limit_opt ::= LIMIT expr OFFSET expr */
    ++  {  206,   -4 }, /* (133) limit_opt ::= LIMIT expr COMMA expr */
    ++  {  149,   -6 }, /* (134) cmd ::= with DELETE FROM fullname indexed_opt where_opt */
    ++  {  202,    0 }, /* (135) where_opt ::= */
    ++  {  202,   -2 }, /* (136) where_opt ::= WHERE expr */
    ++  {  149,   -8 }, /* (137) cmd ::= with UPDATE orconf fullname indexed_opt SET setlist where_opt */
    ++  {  219,   -5 }, /* (138) setlist ::= setlist COMMA nm EQ expr */
    ++  {  219,   -7 }, /* (139) setlist ::= setlist COMMA LP idlist RP EQ expr */
    ++  {  219,   -3 }, /* (140) setlist ::= nm EQ expr */
    ++  {  219,   -5 }, /* (141) setlist ::= LP idlist RP EQ expr */
    ++  {  149,   -6 }, /* (142) cmd ::= with insert_cmd INTO fullname idlist_opt select */
    ++  {  149,   -7 }, /* (143) cmd ::= with insert_cmd INTO fullname idlist_opt DEFAULT VALUES */
    ++  {  220,   -2 }, /* (144) insert_cmd ::= INSERT orconf */
    ++  {  220,   -1 }, /* (145) insert_cmd ::= REPLACE */
    ++  {  221,    0 }, /* (146) idlist_opt ::= */
    ++  {  221,   -3 }, /* (147) idlist_opt ::= LP idlist RP */
    ++  {  218,   -3 }, /* (148) idlist ::= idlist COMMA nm */
    ++  {  218,   -1 }, /* (149) idlist ::= nm */
    ++  {  174,   -3 }, /* (150) expr ::= LP expr RP */
    ++  {  174,   -1 }, /* (151) expr ::= ID|INDEXED */
    ++  {  174,   -1 }, /* (152) expr ::= JOIN_KW */
    ++  {  174,   -3 }, /* (153) expr ::= nm DOT nm */
    ++  {  174,   -5 }, /* (154) expr ::= nm DOT nm DOT nm */
    ++  {  173,   -1 }, /* (155) term ::= NULL|FLOAT|BLOB */
    ++  {  173,   -1 }, /* (156) term ::= STRING */
    ++  {  173,   -1 }, /* (157) term ::= INTEGER */
    ++  {  174,   -1 }, /* (158) expr ::= VARIABLE */
    ++  {  174,   -3 }, /* (159) expr ::= expr COLLATE ID|STRING */
    ++  {  174,   -6 }, /* (160) expr ::= CAST LP expr AS typetoken RP */
    ++  {  174,   -5 }, /* (161) expr ::= ID|INDEXED LP distinct exprlist RP */
    ++  {  174,   -4 }, /* (162) expr ::= ID|INDEXED LP STAR RP */
    ++  {  173,   -1 }, /* (163) term ::= CTIME_KW */
    ++  {  174,   -5 }, /* (164) expr ::= LP nexprlist COMMA expr RP */
    ++  {  174,   -3 }, /* (165) expr ::= expr AND expr */
    ++  {  174,   -3 }, /* (166) expr ::= expr OR expr */
    ++  {  174,   -3 }, /* (167) expr ::= expr LT|GT|GE|LE expr */
    ++  {  174,   -3 }, /* (168) expr ::= expr EQ|NE expr */
    ++  {  174,   -3 }, /* (169) expr ::= expr BITAND|BITOR|LSHIFT|RSHIFT expr */
    ++  {  174,   -3 }, /* (170) expr ::= expr PLUS|MINUS expr */
    ++  {  174,   -3 }, /* (171) expr ::= expr STAR|SLASH|REM expr */
    ++  {  174,   -3 }, /* (172) expr ::= expr CONCAT expr */
    ++  {  222,   -2 }, /* (173) likeop ::= NOT LIKE_KW|MATCH */
    ++  {  174,   -3 }, /* (174) expr ::= expr likeop expr */
    ++  {  174,   -5 }, /* (175) expr ::= expr likeop expr ESCAPE expr */
    ++  {  174,   -2 }, /* (176) expr ::= expr ISNULL|NOTNULL */
    ++  {  174,   -3 }, /* (177) expr ::= expr NOT NULL */
    ++  {  174,   -3 }, /* (178) expr ::= expr IS expr */
    ++  {  174,   -4 }, /* (179) expr ::= expr IS NOT expr */
    ++  {  174,   -2 }, /* (180) expr ::= NOT expr */
    ++  {  174,   -2 }, /* (181) expr ::= BITNOT expr */
    ++  {  174,   -2 }, /* (182) expr ::= MINUS expr */
    ++  {  174,   -2 }, /* (183) expr ::= PLUS expr */
    ++  {  223,   -1 }, /* (184) between_op ::= BETWEEN */
    ++  {  223,   -2 }, /* (185) between_op ::= NOT BETWEEN */
    ++  {  174,   -5 }, /* (186) expr ::= expr between_op expr AND expr */
    ++  {  224,   -1 }, /* (187) in_op ::= IN */
    ++  {  224,   -2 }, /* (188) in_op ::= NOT IN */
    ++  {  174,   -5 }, /* (189) expr ::= expr in_op LP exprlist RP */
    ++  {  174,   -3 }, /* (190) expr ::= LP select RP */
    ++  {  174,   -5 }, /* (191) expr ::= expr in_op LP select RP */
    ++  {  174,   -5 }, /* (192) expr ::= expr in_op nm dbnm paren_exprlist */
    ++  {  174,   -4 }, /* (193) expr ::= EXISTS LP select RP */
    ++  {  174,   -5 }, /* (194) expr ::= CASE case_operand case_exprlist case_else END */
    ++  {  227,   -5 }, /* (195) case_exprlist ::= case_exprlist WHEN expr THEN expr */
    ++  {  227,   -4 }, /* (196) case_exprlist ::= WHEN expr THEN expr */
    ++  {  228,   -2 }, /* (197) case_else ::= ELSE expr */
    ++  {  228,    0 }, /* (198) case_else ::= */
    ++  {  226,   -1 }, /* (199) case_operand ::= expr */
    ++  {  226,    0 }, /* (200) case_operand ::= */
    ++  {  209,    0 }, /* (201) exprlist ::= */
    ++  {  208,   -3 }, /* (202) nexprlist ::= nexprlist COMMA expr */
    ++  {  208,   -1 }, /* (203) nexprlist ::= expr */
    ++  {  225,    0 }, /* (204) paren_exprlist ::= */
    ++  {  225,   -3 }, /* (205) paren_exprlist ::= LP exprlist RP */
    ++  {  149,  -12 }, /* (206) cmd ::= createkw uniqueflag INDEX ifnotexists nm dbnm ON nm LP sortlist RP where_opt */
    ++  {  229,   -1 }, /* (207) uniqueflag ::= UNIQUE */
    ++  {  229,    0 }, /* (208) uniqueflag ::= */
    ++  {  178,    0 }, /* (209) eidlist_opt ::= */
    ++  {  178,   -3 }, /* (210) eidlist_opt ::= LP eidlist RP */
    ++  {  188,   -5 }, /* (211) eidlist ::= eidlist COMMA nm collate sortorder */
    ++  {  188,   -3 }, /* (212) eidlist ::= nm collate sortorder */
    ++  {  230,    0 }, /* (213) collate ::= */
    ++  {  230,   -2 }, /* (214) collate ::= COLLATE ID|STRING */
    ++  {  149,   -4 }, /* (215) cmd ::= DROP INDEX ifexists fullname */
    ++  {  149,   -1 }, /* (216) cmd ::= VACUUM */
    ++  {  149,   -2 }, /* (217) cmd ::= VACUUM nm */
    ++  {  149,   -3 }, /* (218) cmd ::= PRAGMA nm dbnm */
    ++  {  149,   -5 }, /* (219) cmd ::= PRAGMA nm dbnm EQ nmnum */
    ++  {  149,   -6 }, /* (220) cmd ::= PRAGMA nm dbnm LP nmnum RP */
    ++  {  149,   -5 }, /* (221) cmd ::= PRAGMA nm dbnm EQ minus_num */
    ++  {  149,   -6 }, /* (222) cmd ::= PRAGMA nm dbnm LP minus_num RP */
    ++  {  169,   -2 }, /* (223) plus_num ::= PLUS INTEGER|FLOAT */
    ++  {  170,   -2 }, /* (224) minus_num ::= MINUS INTEGER|FLOAT */
    ++  {  149,   -5 }, /* (225) cmd ::= createkw trigger_decl BEGIN trigger_cmd_list END */
    ++  {  232,  -11 }, /* (226) trigger_decl ::= temp TRIGGER ifnotexists nm dbnm trigger_time trigger_event ON fullname foreach_clause when_clause */
    ++  {  234,   -1 }, /* (227) trigger_time ::= BEFORE|AFTER */
    ++  {  234,   -2 }, /* (228) trigger_time ::= INSTEAD OF */
    ++  {  234,    0 }, /* (229) trigger_time ::= */
    ++  {  235,   -1 }, /* (230) trigger_event ::= DELETE|INSERT */
    ++  {  235,   -1 }, /* (231) trigger_event ::= UPDATE */
    ++  {  235,   -3 }, /* (232) trigger_event ::= UPDATE OF idlist */
    ++  {  237,    0 }, /* (233) when_clause ::= */
    ++  {  237,   -2 }, /* (234) when_clause ::= WHEN expr */
    ++  {  233,   -3 }, /* (235) trigger_cmd_list ::= trigger_cmd_list trigger_cmd SEMI */
    ++  {  233,   -2 }, /* (236) trigger_cmd_list ::= trigger_cmd SEMI */
    ++  {  239,   -3 }, /* (237) trnm ::= nm DOT nm */
    ++  {  240,   -3 }, /* (238) tridxby ::= INDEXED BY nm */
    ++  {  240,   -2 }, /* (239) tridxby ::= NOT INDEXED */
    ++  {  238,   -8 }, /* (240) trigger_cmd ::= UPDATE orconf trnm tridxby SET setlist where_opt scanpt */
    ++  {  238,   -7 }, /* (241) trigger_cmd ::= scanpt insert_cmd INTO trnm idlist_opt select scanpt */
    ++  {  238,   -6 }, /* (242) trigger_cmd ::= DELETE FROM trnm tridxby where_opt scanpt */
    ++  {  238,   -3 }, /* (243) trigger_cmd ::= scanpt select scanpt */
    ++  {  174,   -4 }, /* (244) expr ::= RAISE LP IGNORE RP */
    ++  {  174,   -6 }, /* (245) expr ::= RAISE LP raisetype COMMA nm RP */
    ++  {  192,   -1 }, /* (246) raisetype ::= ROLLBACK */
    ++  {  192,   -1 }, /* (247) raisetype ::= ABORT */
    ++  {  192,   -1 }, /* (248) raisetype ::= FAIL */
    ++  {  149,   -4 }, /* (249) cmd ::= DROP TRIGGER ifexists fullname */
    ++  {  149,   -6 }, /* (250) cmd ::= ATTACH database_kw_opt expr AS expr key_opt */
    ++  {  149,   -3 }, /* (251) cmd ::= DETACH database_kw_opt expr */
    ++  {  242,    0 }, /* (252) key_opt ::= */
    ++  {  242,   -2 }, /* (253) key_opt ::= KEY expr */
    ++  {  149,   -1 }, /* (254) cmd ::= REINDEX */
    ++  {  149,   -3 }, /* (255) cmd ::= REINDEX nm dbnm */
    ++  {  149,   -1 }, /* (256) cmd ::= ANALYZE */
    ++  {  149,   -3 }, /* (257) cmd ::= ANALYZE nm dbnm */
    ++  {  149,   -6 }, /* (258) cmd ::= ALTER TABLE fullname RENAME TO nm */
    ++  {  149,   -7 }, /* (259) cmd ::= ALTER TABLE add_column_fullname ADD kwcolumn_opt columnname carglist */
    ++  {  243,   -1 }, /* (260) add_column_fullname ::= fullname */
    ++  {  149,   -1 }, /* (261) cmd ::= create_vtab */
    ++  {  149,   -4 }, /* (262) cmd ::= create_vtab LP vtabarglist RP */
    ++  {  245,   -8 }, /* (263) create_vtab ::= createkw VIRTUAL TABLE ifnotexists nm dbnm USING nm */
    ++  {  247,    0 }, /* (264) vtabarg ::= */
    ++  {  248,   -1 }, /* (265) vtabargtoken ::= ANY */
    ++  {  248,   -3 }, /* (266) vtabargtoken ::= lp anylist RP */
    ++  {  249,   -1 }, /* (267) lp ::= LP */
    ++  {  197,    0 }, /* (268) with ::= */
    ++  {  197,   -2 }, /* (269) with ::= WITH wqlist */
    ++  {  197,   -3 }, /* (270) with ::= WITH RECURSIVE wqlist */
    ++  {  251,   -6 }, /* (271) wqlist ::= nm eidlist_opt AS LP select RP */
    ++  {  251,   -8 }, /* (272) wqlist ::= wqlist COMMA nm eidlist_opt AS LP select RP */
    ++  {  144,   -1 }, /* (273) input ::= cmdlist */
    ++  {  145,   -2 }, /* (274) cmdlist ::= cmdlist ecmd */
    ++  {  145,   -1 }, /* (275) cmdlist ::= ecmd */
    ++  {  146,   -1 }, /* (276) ecmd ::= SEMI */
    ++  {  146,   -3 }, /* (277) ecmd ::= explain cmdx SEMI */
    ++  {  147,    0 }, /* (278) explain ::= */
    ++  {  151,    0 }, /* (279) trans_opt ::= */
    ++  {  151,   -1 }, /* (280) trans_opt ::= TRANSACTION */
    ++  {  151,   -2 }, /* (281) trans_opt ::= TRANSACTION nm */
    ++  {  153,   -1 }, /* (282) savepoint_opt ::= SAVEPOINT */
    ++  {  153,    0 }, /* (283) savepoint_opt ::= */
    ++  {  149,   -2 }, /* (284) cmd ::= create_table create_table_args */
    ++  {  160,   -4 }, /* (285) columnlist ::= columnlist COMMA columnname carglist */
    ++  {  160,   -2 }, /* (286) columnlist ::= columnname carglist */
    ++  {  152,   -1 }, /* (287) nm ::= ID|INDEXED */
    ++  {  152,   -1 }, /* (288) nm ::= STRING */
    ++  {  152,   -1 }, /* (289) nm ::= JOIN_KW */
    ++  {  166,   -1 }, /* (290) typetoken ::= typename */
    ++  {  167,   -1 }, /* (291) typename ::= ID|STRING */
    ++  {  168,   -1 }, /* (292) signed ::= plus_num */
    ++  {  168,   -1 }, /* (293) signed ::= minus_num */
    ++  {  165,   -2 }, /* (294) carglist ::= carglist ccons */
    ++  {  165,    0 }, /* (295) carglist ::= */
    ++  {  172,   -2 }, /* (296) ccons ::= NULL onconf */
    ++  {  161,   -2 }, /* (297) conslist_opt ::= COMMA conslist */
    ++  {  184,   -3 }, /* (298) conslist ::= conslist tconscomma tcons */
    ++  {  184,   -1 }, /* (299) conslist ::= tcons */
    ++  {  185,    0 }, /* (300) tconscomma ::= */
    ++  {  189,   -1 }, /* (301) defer_subclause_opt ::= defer_subclause */
    ++  {  191,   -1 }, /* (302) resolvetype ::= raisetype */
    ++  {  195,   -1 }, /* (303) selectnowith ::= oneselect */
    ++  {  196,   -1 }, /* (304) oneselect ::= values */
    ++  {  210,   -2 }, /* (305) sclp ::= selcollist COMMA */
    ++  {  211,   -1 }, /* (306) as ::= ID|STRING */
    ++  {  174,   -1 }, /* (307) expr ::= term */
    ++  {  222,   -1 }, /* (308) likeop ::= LIKE_KW|MATCH */
    ++  {  209,   -1 }, /* (309) exprlist ::= nexprlist */
    ++  {  231,   -1 }, /* (310) nmnum ::= plus_num */
    ++  {  231,   -1 }, /* (311) nmnum ::= nm */
    ++  {  231,   -1 }, /* (312) nmnum ::= ON */
    ++  {  231,   -1 }, /* (313) nmnum ::= DELETE */
    ++  {  231,   -1 }, /* (314) nmnum ::= DEFAULT */
    ++  {  169,   -1 }, /* (315) plus_num ::= INTEGER|FLOAT */
    ++  {  236,    0 }, /* (316) foreach_clause ::= */
    ++  {  236,   -3 }, /* (317) foreach_clause ::= FOR EACH ROW */
    ++  {  239,   -1 }, /* (318) trnm ::= nm */
    ++  {  240,    0 }, /* (319) tridxby ::= */
    ++  {  241,   -1 }, /* (320) database_kw_opt ::= DATABASE */
    ++  {  241,    0 }, /* (321) database_kw_opt ::= */
    ++  {  244,    0 }, /* (322) kwcolumn_opt ::= */
    ++  {  244,   -1 }, /* (323) kwcolumn_opt ::= COLUMNKW */
    ++  {  246,   -1 }, /* (324) vtabarglist ::= vtabarg */
    ++  {  246,   -3 }, /* (325) vtabarglist ::= vtabarglist COMMA vtabarg */
    ++  {  247,   -2 }, /* (326) vtabarg ::= vtabarg vtabargtoken */
    ++  {  250,    0 }, /* (327) anylist ::= */
    ++  {  250,   -4 }, /* (328) anylist ::= anylist LP anylist RP */
    ++  {  250,   -2 }, /* (329) anylist ::= anylist ANY */
    + };
    + 
    + static void yy_accept(yyParser*);  /* Forward Declaration */
    +@@ -128073,44 +140504,66 @@ static void yy_accept(yyParser*);  /* Forward Declaration */
    + /*
    + ** Perform a reduce action and the shift that must immediately
    + ** follow the reduce.
    ++**
    ++** The yyLookahead and yyLookaheadToken parameters provide reduce actions
    ++** access to the lookahead token (if any).  The yyLookahead will be YYNOCODE
    ++** if the lookahead token has already been consumed.  As this procedure is
    ++** only called from one place, optimizing compilers will in-line it, which
    ++** means that the extra parameters have no performance impact.
    + */
    + static void yy_reduce(
    +   yyParser *yypParser,         /* The parser */
    +-  int yyruleno                 /* Number of the rule by which to reduce */
    ++  unsigned int yyruleno,       /* Number of the rule by which to reduce */
    ++  int yyLookahead,             /* Lookahead token, or YYNOCODE if none */
    ++  sqlite3ParserTOKENTYPE yyLookaheadToken  /* Value of the lookahead token */
    + ){
    +   int yygoto;                     /* The next state */
    +   int yyact;                      /* The next action */
    +-  YYMINORTYPE yygotominor;        /* The LHS of the rule reduced */
    +   yyStackEntry *yymsp;            /* The top of the parser's stack */
    +   int yysize;                     /* Amount to pop the stack */
    +   sqlite3ParserARG_FETCH;
    +-  yymsp = &yypParser->yystack[yypParser->yyidx];
    ++  (void)yyLookahead;
    ++  (void)yyLookaheadToken;
    ++  yymsp = yypParser->yytos;
    + #ifndef NDEBUG
    +-  if( yyTraceFILE && yyruleno>=0 
    +-        && yyruleno<(int)(sizeof(yyRuleName)/sizeof(yyRuleName[0])) ){
    ++  if( yyTraceFILE && yyruleno<(int)(sizeof(yyRuleName)/sizeof(yyRuleName[0])) ){
    +     yysize = yyRuleInfo[yyruleno].nrhs;
    +-    fprintf(yyTraceFILE, "%sReduce [%s] -> state %d.\n", yyTracePrompt,
    +-      yyRuleName[yyruleno], yymsp[-yysize].stateno);
    ++    if( yysize ){
    ++      fprintf(yyTraceFILE, "%sReduce %d [%s], go to state %d.\n",
    ++        yyTracePrompt,
    ++        yyruleno, yyRuleName[yyruleno], yymsp[yysize].stateno);
    ++    }else{
    ++      fprintf(yyTraceFILE, "%sReduce %d [%s].\n",
    ++        yyTracePrompt, yyruleno, yyRuleName[yyruleno]);
    ++    }
    +   }
    + #endif /* NDEBUG */
    + 
    +-  /* Silence complaints from purify about yygotominor being uninitialized
    +-  ** in some cases when it is copied into the stack after the following
    +-  ** switch.  yygotominor is uninitialized when a rule reduces that does
    +-  ** not set the value of its left-hand side nonterminal.  Leaving the
    +-  ** value of the nonterminal uninitialized is utterly harmless as long
    +-  ** as the value is never used.  So really the only thing this code
    +-  ** accomplishes is to quieten purify.  
    +-  **
    +-  ** 2007-01-16:  The wireshark project (www.wireshark.org) reports that
    +-  ** without this code, their parser segfaults.  I'm not sure what there
    +-  ** parser is doing to make this happen.  This is the second bug report
    +-  ** from wireshark this week.  Clearly they are stressing Lemon in ways
    +-  ** that it has not been previously stressed...  (SQLite ticket #2172)
    +-  */
    +-  /*memset(&yygotominor, 0, sizeof(yygotominor));*/
    +-  yygotominor = yyzerominor;
    +-
    ++  /* Check that the stack is large enough to grow by a single entry
    ++  ** if the RHS of the rule is empty.  This ensures that there is room
    ++  ** enough on the stack to push the LHS value */
    ++  if( yyRuleInfo[yyruleno].nrhs==0 ){
    ++#ifdef YYTRACKMAXSTACKDEPTH
    ++    if( (int)(yypParser->yytos - yypParser->yystack)>yypParser->yyhwm ){
    ++      yypParser->yyhwm++;
    ++      assert( yypParser->yyhwm == (int)(yypParser->yytos - yypParser->yystack));
    ++    }
    ++#endif
    ++#if YYSTACKDEPTH>0 
    ++    if( yypParser->yytos>=yypParser->yystackEnd ){
    ++      yyStackOverflow(yypParser);
    ++      return;
    ++    }
    ++#else
    ++    if( yypParser->yytos>=&yypParser->yystack[yypParser->yystksz-1] ){
    ++      if( yyGrowStack(yypParser) ){
    ++        yyStackOverflow(yypParser);
    ++        return;
    ++      }
    ++      yymsp = yypParser->yytos;
    ++    }
    ++#endif
    ++  }
    + 
    +   switch( yyruleno ){
    +   /* Beginning here are the reduction cases.  A typical example
    +@@ -128121,354 +140574,323 @@ static void yy_reduce(
    +   **  #line <lineno> <thisfile>
    +   **     break;
    +   */
    +-      case 5: /* explain ::= */
    +-{ sqlite3BeginParse(pParse, 0); }
    +-        break;
    +-      case 6: /* explain ::= EXPLAIN */
    +-{ sqlite3BeginParse(pParse, 1); }
    ++/********** Begin reduce actions **********************************************/
    ++        YYMINORTYPE yylhsminor;
    ++      case 0: /* explain ::= EXPLAIN */
    ++{ pParse->explain = 1; }
    +         break;
    +-      case 7: /* explain ::= EXPLAIN QUERY PLAN */
    +-{ sqlite3BeginParse(pParse, 2); }
    ++      case 1: /* explain ::= EXPLAIN QUERY PLAN */
    ++{ pParse->explain = 2; }
    +         break;
    +-      case 8: /* cmdx ::= cmd */
    ++      case 2: /* cmdx ::= cmd */
    + { sqlite3FinishCoding(pParse); }
    +         break;
    +-      case 9: /* cmd ::= BEGIN transtype trans_opt */
    +-{sqlite3BeginTransaction(pParse, yymsp[-1].minor.yy328);}
    ++      case 3: /* cmd ::= BEGIN transtype trans_opt */
    ++{sqlite3BeginTransaction(pParse, yymsp[-1].minor.yy4);}
    +         break;
    +-      case 13: /* transtype ::= */
    +-{yygotominor.yy328 = TK_DEFERRED;}
    ++      case 4: /* transtype ::= */
    ++{yymsp[1].minor.yy4 = TK_DEFERRED;}
    +         break;
    +-      case 14: /* transtype ::= DEFERRED */
    +-      case 15: /* transtype ::= IMMEDIATE */ yytestcase(yyruleno==15);
    +-      case 16: /* transtype ::= EXCLUSIVE */ yytestcase(yyruleno==16);
    +-      case 115: /* multiselect_op ::= UNION */ yytestcase(yyruleno==115);
    +-      case 117: /* multiselect_op ::= EXCEPT|INTERSECT */ yytestcase(yyruleno==117);
    +-{yygotominor.yy328 = yymsp[0].major;}
    ++      case 5: /* transtype ::= DEFERRED */
    ++      case 6: /* transtype ::= IMMEDIATE */ yytestcase(yyruleno==6);
    ++      case 7: /* transtype ::= EXCLUSIVE */ yytestcase(yyruleno==7);
    ++{yymsp[0].minor.yy4 = yymsp[0].major; /*A-overwrites-X*/}
    +         break;
    +-      case 17: /* cmd ::= COMMIT trans_opt */
    +-      case 18: /* cmd ::= END trans_opt */ yytestcase(yyruleno==18);
    +-{sqlite3CommitTransaction(pParse);}
    ++      case 8: /* cmd ::= COMMIT|END trans_opt */
    ++      case 9: /* cmd ::= ROLLBACK trans_opt */ yytestcase(yyruleno==9);
    ++{sqlite3EndTransaction(pParse,yymsp[-1].major);}
    +         break;
    +-      case 19: /* cmd ::= ROLLBACK trans_opt */
    +-{sqlite3RollbackTransaction(pParse);}
    +-        break;
    +-      case 22: /* cmd ::= SAVEPOINT nm */
    ++      case 10: /* cmd ::= SAVEPOINT nm */
    + {
    +   sqlite3Savepoint(pParse, SAVEPOINT_BEGIN, &yymsp[0].minor.yy0);
    + }
    +         break;
    +-      case 23: /* cmd ::= RELEASE savepoint_opt nm */
    ++      case 11: /* cmd ::= RELEASE savepoint_opt nm */
    + {
    +   sqlite3Savepoint(pParse, SAVEPOINT_RELEASE, &yymsp[0].minor.yy0);
    + }
    +         break;
    +-      case 24: /* cmd ::= ROLLBACK trans_opt TO savepoint_opt nm */
    ++      case 12: /* cmd ::= ROLLBACK trans_opt TO savepoint_opt nm */
    + {
    +   sqlite3Savepoint(pParse, SAVEPOINT_ROLLBACK, &yymsp[0].minor.yy0);
    + }
    +         break;
    +-      case 26: /* create_table ::= createkw temp TABLE ifnotexists nm dbnm */
    ++      case 13: /* create_table ::= createkw temp TABLE ifnotexists nm dbnm */
    + {
    +-   sqlite3StartTable(pParse,&yymsp[-1].minor.yy0,&yymsp[0].minor.yy0,yymsp[-4].minor.yy328,0,0,yymsp[-2].minor.yy328);
    ++   sqlite3StartTable(pParse,&yymsp[-1].minor.yy0,&yymsp[0].minor.yy0,yymsp[-4].minor.yy4,0,0,yymsp[-2].minor.yy4);
    + }
    +         break;
    +-      case 27: /* createkw ::= CREATE */
    +-{
    +-  pParse->db->lookaside.bEnabled = 0;
    +-  yygotominor.yy0 = yymsp[0].minor.yy0;
    +-}
    ++      case 14: /* createkw ::= CREATE */
    ++{disableLookaside(pParse);}
    ++        break;
    ++      case 15: /* ifnotexists ::= */
    ++      case 18: /* temp ::= */ yytestcase(yyruleno==18);
    ++      case 21: /* table_options ::= */ yytestcase(yyruleno==21);
    ++      case 42: /* autoinc ::= */ yytestcase(yyruleno==42);
    ++      case 57: /* init_deferred_pred_opt ::= */ yytestcase(yyruleno==57);
    ++      case 67: /* defer_subclause_opt ::= */ yytestcase(yyruleno==67);
    ++      case 76: /* ifexists ::= */ yytestcase(yyruleno==76);
    ++      case 90: /* distinct ::= */ yytestcase(yyruleno==90);
    ++      case 213: /* collate ::= */ yytestcase(yyruleno==213);
    ++{yymsp[1].minor.yy4 = 0;}
    +         break;
    +-      case 28: /* ifnotexists ::= */
    +-      case 31: /* temp ::= */ yytestcase(yyruleno==31);
    +-      case 68: /* autoinc ::= */ yytestcase(yyruleno==68);
    +-      case 81: /* defer_subclause ::= NOT DEFERRABLE init_deferred_pred_opt */ yytestcase(yyruleno==81);
    +-      case 83: /* init_deferred_pred_opt ::= */ yytestcase(yyruleno==83);
    +-      case 85: /* init_deferred_pred_opt ::= INITIALLY IMMEDIATE */ yytestcase(yyruleno==85);
    +-      case 97: /* defer_subclause_opt ::= */ yytestcase(yyruleno==97);
    +-      case 108: /* ifexists ::= */ yytestcase(yyruleno==108);
    +-      case 219: /* between_op ::= BETWEEN */ yytestcase(yyruleno==219);
    +-      case 222: /* in_op ::= IN */ yytestcase(yyruleno==222);
    +-      case 247: /* collate ::= */ yytestcase(yyruleno==247);
    +-{yygotominor.yy328 = 0;}
    ++      case 16: /* ifnotexists ::= IF NOT EXISTS */
    ++{yymsp[-2].minor.yy4 = 1;}
    +         break;
    +-      case 29: /* ifnotexists ::= IF NOT EXISTS */
    +-      case 30: /* temp ::= TEMP */ yytestcase(yyruleno==30);
    +-      case 69: /* autoinc ::= AUTOINCR */ yytestcase(yyruleno==69);
    +-      case 84: /* init_deferred_pred_opt ::= INITIALLY DEFERRED */ yytestcase(yyruleno==84);
    +-      case 107: /* ifexists ::= IF EXISTS */ yytestcase(yyruleno==107);
    +-      case 220: /* between_op ::= NOT BETWEEN */ yytestcase(yyruleno==220);
    +-      case 223: /* in_op ::= NOT IN */ yytestcase(yyruleno==223);
    +-      case 248: /* collate ::= COLLATE ID|STRING */ yytestcase(yyruleno==248);
    +-{yygotominor.yy328 = 1;}
    ++      case 17: /* temp ::= TEMP */
    ++      case 43: /* autoinc ::= AUTOINCR */ yytestcase(yyruleno==43);
    ++{yymsp[0].minor.yy4 = 1;}
    +         break;
    +-      case 32: /* create_table_args ::= LP columnlist conslist_opt RP table_options */
    ++      case 19: /* create_table_args ::= LP columnlist conslist_opt RP table_options */
    + {
    +-  sqlite3EndTable(pParse,&yymsp[-2].minor.yy0,&yymsp[-1].minor.yy0,yymsp[0].minor.yy186,0);
    ++  sqlite3EndTable(pParse,&yymsp[-2].minor.yy0,&yymsp[-1].minor.yy0,yymsp[0].minor.yy4,0);
    + }
    +         break;
    +-      case 33: /* create_table_args ::= AS select */
    ++      case 20: /* create_table_args ::= AS select */
    + {
    +-  sqlite3EndTable(pParse,0,0,0,yymsp[0].minor.yy3);
    +-  sqlite3SelectDelete(pParse->db, yymsp[0].minor.yy3);
    ++  sqlite3EndTable(pParse,0,0,0,yymsp[0].minor.yy387);
    ++  sqlite3SelectDelete(pParse->db, yymsp[0].minor.yy387);
    + }
    +         break;
    +-      case 34: /* table_options ::= */
    +-{yygotominor.yy186 = 0;}
    +-        break;
    +-      case 35: /* table_options ::= WITHOUT nm */
    ++      case 22: /* table_options ::= WITHOUT nm */
    + {
    +   if( yymsp[0].minor.yy0.n==5 && sqlite3_strnicmp(yymsp[0].minor.yy0.z,"rowid",5)==0 ){
    +-    yygotominor.yy186 = TF_WithoutRowid | TF_NoVisibleRowid;
    ++    yymsp[-1].minor.yy4 = TF_WithoutRowid | TF_NoVisibleRowid;
    +   }else{
    +-    yygotominor.yy186 = 0;
    ++    yymsp[-1].minor.yy4 = 0;
    +     sqlite3ErrorMsg(pParse, "unknown table option: %.*s", yymsp[0].minor.yy0.n, yymsp[0].minor.yy0.z);
    +   }
    + }
    +         break;
    +-      case 38: /* column ::= columnid type carglist */
    +-{
    +-  yygotominor.yy0.z = yymsp[-2].minor.yy0.z;
    +-  yygotominor.yy0.n = (int)(pParse->sLastToken.z-yymsp[-2].minor.yy0.z) + pParse->sLastToken.n;
    +-}
    ++      case 23: /* columnname ::= nm typetoken */
    ++{sqlite3AddColumn(pParse,&yymsp[-1].minor.yy0,&yymsp[0].minor.yy0);}
    ++        break;
    ++      case 24: /* typetoken ::= */
    ++      case 60: /* conslist_opt ::= */ yytestcase(yyruleno==60);
    ++      case 96: /* as ::= */ yytestcase(yyruleno==96);
    ++{yymsp[1].minor.yy0.n = 0; yymsp[1].minor.yy0.z = 0;}
    +         break;
    +-      case 39: /* columnid ::= nm */
    ++      case 25: /* typetoken ::= typename LP signed RP */
    + {
    +-  sqlite3AddColumn(pParse,&yymsp[0].minor.yy0);
    +-  yygotominor.yy0 = yymsp[0].minor.yy0;
    +-  pParse->constraintName.n = 0;
    ++  yymsp[-3].minor.yy0.n = (int)(&yymsp[0].minor.yy0.z[yymsp[0].minor.yy0.n] - yymsp[-3].minor.yy0.z);
    + }
    +         break;
    +-      case 40: /* nm ::= ID|INDEXED */
    +-      case 41: /* nm ::= STRING */ yytestcase(yyruleno==41);
    +-      case 42: /* nm ::= JOIN_KW */ yytestcase(yyruleno==42);
    +-      case 45: /* typetoken ::= typename */ yytestcase(yyruleno==45);
    +-      case 48: /* typename ::= ID|STRING */ yytestcase(yyruleno==48);
    +-      case 130: /* as ::= AS nm */ yytestcase(yyruleno==130);
    +-      case 131: /* as ::= ID|STRING */ yytestcase(yyruleno==131);
    +-      case 142: /* dbnm ::= DOT nm */ yytestcase(yyruleno==142);
    +-      case 151: /* indexed_opt ::= INDEXED BY nm */ yytestcase(yyruleno==151);
    +-      case 257: /* nmnum ::= plus_num */ yytestcase(yyruleno==257);
    +-      case 258: /* nmnum ::= nm */ yytestcase(yyruleno==258);
    +-      case 259: /* nmnum ::= ON */ yytestcase(yyruleno==259);
    +-      case 260: /* nmnum ::= DELETE */ yytestcase(yyruleno==260);
    +-      case 261: /* nmnum ::= DEFAULT */ yytestcase(yyruleno==261);
    +-      case 262: /* plus_num ::= PLUS INTEGER|FLOAT */ yytestcase(yyruleno==262);
    +-      case 263: /* plus_num ::= INTEGER|FLOAT */ yytestcase(yyruleno==263);
    +-      case 264: /* minus_num ::= MINUS INTEGER|FLOAT */ yytestcase(yyruleno==264);
    +-      case 280: /* trnm ::= nm */ yytestcase(yyruleno==280);
    +-{yygotominor.yy0 = yymsp[0].minor.yy0;}
    +-        break;
    +-      case 44: /* type ::= typetoken */
    +-{sqlite3AddColumnType(pParse,&yymsp[0].minor.yy0);}
    +-        break;
    +-      case 46: /* typetoken ::= typename LP signed RP */
    ++      case 26: /* typetoken ::= typename LP signed COMMA signed RP */
    + {
    +-  yygotominor.yy0.z = yymsp[-3].minor.yy0.z;
    +-  yygotominor.yy0.n = (int)(&yymsp[0].minor.yy0.z[yymsp[0].minor.yy0.n] - yymsp[-3].minor.yy0.z);
    ++  yymsp[-5].minor.yy0.n = (int)(&yymsp[0].minor.yy0.z[yymsp[0].minor.yy0.n] - yymsp[-5].minor.yy0.z);
    + }
    +         break;
    +-      case 47: /* typetoken ::= typename LP signed COMMA signed RP */
    ++      case 27: /* typename ::= typename ID|STRING */
    ++{yymsp[-1].minor.yy0.n=yymsp[0].minor.yy0.n+(int)(yymsp[0].minor.yy0.z-yymsp[-1].minor.yy0.z);}
    ++        break;
    ++      case 28: /* scanpt ::= */
    + {
    +-  yygotominor.yy0.z = yymsp[-5].minor.yy0.z;
    +-  yygotominor.yy0.n = (int)(&yymsp[0].minor.yy0.z[yymsp[0].minor.yy0.n] - yymsp[-5].minor.yy0.z);
    ++  assert( yyLookahead!=YYNOCODE );
    ++  yymsp[1].minor.yy336 = yyLookaheadToken.z;
    + }
    +         break;
    +-      case 49: /* typename ::= typename ID|STRING */
    +-{yygotominor.yy0.z=yymsp[-1].minor.yy0.z; yygotominor.yy0.n=yymsp[0].minor.yy0.n+(int)(yymsp[0].minor.yy0.z-yymsp[-1].minor.yy0.z);}
    +-        break;
    +-      case 54: /* ccons ::= CONSTRAINT nm */
    +-      case 92: /* tcons ::= CONSTRAINT nm */ yytestcase(yyruleno==92);
    ++      case 29: /* ccons ::= CONSTRAINT nm */
    ++      case 62: /* tcons ::= CONSTRAINT nm */ yytestcase(yyruleno==62);
    + {pParse->constraintName = yymsp[0].minor.yy0;}
    +         break;
    +-      case 55: /* ccons ::= DEFAULT term */
    +-      case 57: /* ccons ::= DEFAULT PLUS term */ yytestcase(yyruleno==57);
    +-{sqlite3AddDefaultValue(pParse,&yymsp[0].minor.yy346);}
    ++      case 30: /* ccons ::= DEFAULT scanpt term scanpt */
    ++{sqlite3AddDefaultValue(pParse,yymsp[-1].minor.yy314,yymsp[-2].minor.yy336,yymsp[0].minor.yy336);}
    +         break;
    +-      case 56: /* ccons ::= DEFAULT LP expr RP */
    +-{sqlite3AddDefaultValue(pParse,&yymsp[-1].minor.yy346);}
    ++      case 31: /* ccons ::= DEFAULT LP expr RP */
    ++{sqlite3AddDefaultValue(pParse,yymsp[-1].minor.yy314,yymsp[-2].minor.yy0.z+1,yymsp[0].minor.yy0.z);}
    +         break;
    +-      case 58: /* ccons ::= DEFAULT MINUS term */
    ++      case 32: /* ccons ::= DEFAULT PLUS term scanpt */
    ++{sqlite3AddDefaultValue(pParse,yymsp[-1].minor.yy314,yymsp[-2].minor.yy0.z,yymsp[0].minor.yy336);}
    ++        break;
    ++      case 33: /* ccons ::= DEFAULT MINUS term scanpt */
    + {
    +-  ExprSpan v;
    +-  v.pExpr = sqlite3PExpr(pParse, TK_UMINUS, yymsp[0].minor.yy346.pExpr, 0, 0);
    +-  v.zStart = yymsp[-1].minor.yy0.z;
    +-  v.zEnd = yymsp[0].minor.yy346.zEnd;
    +-  sqlite3AddDefaultValue(pParse,&v);
    ++  Expr *p = sqlite3PExpr(pParse, TK_UMINUS, yymsp[-1].minor.yy314, 0);
    ++  sqlite3AddDefaultValue(pParse,p,yymsp[-2].minor.yy0.z,yymsp[0].minor.yy336);
    + }
    +         break;
    +-      case 59: /* ccons ::= DEFAULT ID|INDEXED */
    ++      case 34: /* ccons ::= DEFAULT scanpt ID|INDEXED */
    + {
    +-  ExprSpan v;
    +-  spanExpr(&v, pParse, TK_STRING, &yymsp[0].minor.yy0);
    +-  sqlite3AddDefaultValue(pParse,&v);
    ++  Expr *p = tokenExpr(pParse, TK_STRING, yymsp[0].minor.yy0);
    ++  sqlite3AddDefaultValue(pParse,p,yymsp[0].minor.yy0.z,yymsp[0].minor.yy0.z+yymsp[0].minor.yy0.n);
    + }
    +         break;
    +-      case 61: /* ccons ::= NOT NULL onconf */
    +-{sqlite3AddNotNull(pParse, yymsp[0].minor.yy328);}
    ++      case 35: /* ccons ::= NOT NULL onconf */
    ++{sqlite3AddNotNull(pParse, yymsp[0].minor.yy4);}
    +         break;
    +-      case 62: /* ccons ::= PRIMARY KEY sortorder onconf autoinc */
    +-{sqlite3AddPrimaryKey(pParse,0,yymsp[-1].minor.yy328,yymsp[0].minor.yy328,yymsp[-2].minor.yy328);}
    ++      case 36: /* ccons ::= PRIMARY KEY sortorder onconf autoinc */
    ++{sqlite3AddPrimaryKey(pParse,0,yymsp[-1].minor.yy4,yymsp[0].minor.yy4,yymsp[-2].minor.yy4);}
    +         break;
    +-      case 63: /* ccons ::= UNIQUE onconf */
    +-{sqlite3CreateIndex(pParse,0,0,0,0,yymsp[0].minor.yy328,0,0,0,0);}
    ++      case 37: /* ccons ::= UNIQUE onconf */
    ++{sqlite3CreateIndex(pParse,0,0,0,0,yymsp[0].minor.yy4,0,0,0,0,
    ++                                   SQLITE_IDXTYPE_UNIQUE);}
    +         break;
    +-      case 64: /* ccons ::= CHECK LP expr RP */
    +-{sqlite3AddCheckConstraint(pParse,yymsp[-1].minor.yy346.pExpr);}
    ++      case 38: /* ccons ::= CHECK LP expr RP */
    ++{sqlite3AddCheckConstraint(pParse,yymsp[-1].minor.yy314);}
    +         break;
    +-      case 65: /* ccons ::= REFERENCES nm eidlist_opt refargs */
    +-{sqlite3CreateForeignKey(pParse,0,&yymsp[-2].minor.yy0,yymsp[-1].minor.yy14,yymsp[0].minor.yy328);}
    ++      case 39: /* ccons ::= REFERENCES nm eidlist_opt refargs */
    ++{sqlite3CreateForeignKey(pParse,0,&yymsp[-2].minor.yy0,yymsp[-1].minor.yy322,yymsp[0].minor.yy4);}
    +         break;
    +-      case 66: /* ccons ::= defer_subclause */
    +-{sqlite3DeferForeignKey(pParse,yymsp[0].minor.yy328);}
    ++      case 40: /* ccons ::= defer_subclause */
    ++{sqlite3DeferForeignKey(pParse,yymsp[0].minor.yy4);}
    +         break;
    +-      case 67: /* ccons ::= COLLATE ID|STRING */
    ++      case 41: /* ccons ::= COLLATE ID|STRING */
    + {sqlite3AddCollateType(pParse, &yymsp[0].minor.yy0);}
    +         break;
    +-      case 70: /* refargs ::= */
    +-{ yygotominor.yy328 = OE_None*0x0101; /* EV: R-19803-45884 */}
    ++      case 44: /* refargs ::= */
    ++{ yymsp[1].minor.yy4 = OE_None*0x0101; /* EV: R-19803-45884 */}
    ++        break;
    ++      case 45: /* refargs ::= refargs refarg */
    ++{ yymsp[-1].minor.yy4 = (yymsp[-1].minor.yy4 & ~yymsp[0].minor.yy215.mask) | yymsp[0].minor.yy215.value; }
    +         break;
    +-      case 71: /* refargs ::= refargs refarg */
    +-{ yygotominor.yy328 = (yymsp[-1].minor.yy328 & ~yymsp[0].minor.yy429.mask) | yymsp[0].minor.yy429.value; }
    ++      case 46: /* refarg ::= MATCH nm */
    ++{ yymsp[-1].minor.yy215.value = 0;     yymsp[-1].minor.yy215.mask = 0x000000; }
    +         break;
    +-      case 72: /* refarg ::= MATCH nm */
    +-      case 73: /* refarg ::= ON INSERT refact */ yytestcase(yyruleno==73);
    +-{ yygotominor.yy429.value = 0;     yygotominor.yy429.mask = 0x000000; }
    ++      case 47: /* refarg ::= ON INSERT refact */
    ++{ yymsp[-2].minor.yy215.value = 0;     yymsp[-2].minor.yy215.mask = 0x000000; }
    +         break;
    +-      case 74: /* refarg ::= ON DELETE refact */
    +-{ yygotominor.yy429.value = yymsp[0].minor.yy328;     yygotominor.yy429.mask = 0x0000ff; }
    ++      case 48: /* refarg ::= ON DELETE refact */
    ++{ yymsp[-2].minor.yy215.value = yymsp[0].minor.yy4;     yymsp[-2].minor.yy215.mask = 0x0000ff; }
    +         break;
    +-      case 75: /* refarg ::= ON UPDATE refact */
    +-{ yygotominor.yy429.value = yymsp[0].minor.yy328<<8;  yygotominor.yy429.mask = 0x00ff00; }
    ++      case 49: /* refarg ::= ON UPDATE refact */
    ++{ yymsp[-2].minor.yy215.value = yymsp[0].minor.yy4<<8;  yymsp[-2].minor.yy215.mask = 0x00ff00; }
    +         break;
    +-      case 76: /* refact ::= SET NULL */
    +-{ yygotominor.yy328 = OE_SetNull;  /* EV: R-33326-45252 */}
    ++      case 50: /* refact ::= SET NULL */
    ++{ yymsp[-1].minor.yy4 = OE_SetNull;  /* EV: R-33326-45252 */}
    +         break;
    +-      case 77: /* refact ::= SET DEFAULT */
    +-{ yygotominor.yy328 = OE_SetDflt;  /* EV: R-33326-45252 */}
    ++      case 51: /* refact ::= SET DEFAULT */
    ++{ yymsp[-1].minor.yy4 = OE_SetDflt;  /* EV: R-33326-45252 */}
    +         break;
    +-      case 78: /* refact ::= CASCADE */
    +-{ yygotominor.yy328 = OE_Cascade;  /* EV: R-33326-45252 */}
    ++      case 52: /* refact ::= CASCADE */
    ++{ yymsp[0].minor.yy4 = OE_Cascade;  /* EV: R-33326-45252 */}
    +         break;
    +-      case 79: /* refact ::= RESTRICT */
    +-{ yygotominor.yy328 = OE_Restrict; /* EV: R-33326-45252 */}
    ++      case 53: /* refact ::= RESTRICT */
    ++{ yymsp[0].minor.yy4 = OE_Restrict; /* EV: R-33326-45252 */}
    +         break;
    +-      case 80: /* refact ::= NO ACTION */
    +-{ yygotominor.yy328 = OE_None;     /* EV: R-33326-45252 */}
    ++      case 54: /* refact ::= NO ACTION */
    ++{ yymsp[-1].minor.yy4 = OE_None;     /* EV: R-33326-45252 */}
    +         break;
    +-      case 82: /* defer_subclause ::= DEFERRABLE init_deferred_pred_opt */
    +-      case 98: /* defer_subclause_opt ::= defer_subclause */ yytestcase(yyruleno==98);
    +-      case 100: /* onconf ::= ON CONFLICT resolvetype */ yytestcase(yyruleno==100);
    +-      case 103: /* resolvetype ::= raisetype */ yytestcase(yyruleno==103);
    +-{yygotominor.yy328 = yymsp[0].minor.yy328;}
    ++      case 55: /* defer_subclause ::= NOT DEFERRABLE init_deferred_pred_opt */
    ++{yymsp[-2].minor.yy4 = 0;}
    +         break;
    +-      case 86: /* conslist_opt ::= */
    +-{yygotominor.yy0.n = 0; yygotominor.yy0.z = 0;}
    ++      case 56: /* defer_subclause ::= DEFERRABLE init_deferred_pred_opt */
    ++      case 71: /* orconf ::= OR resolvetype */ yytestcase(yyruleno==71);
    ++      case 144: /* insert_cmd ::= INSERT orconf */ yytestcase(yyruleno==144);
    ++{yymsp[-1].minor.yy4 = yymsp[0].minor.yy4;}
    +         break;
    +-      case 87: /* conslist_opt ::= COMMA conslist */
    +-{yygotominor.yy0 = yymsp[-1].minor.yy0;}
    ++      case 58: /* init_deferred_pred_opt ::= INITIALLY DEFERRED */
    ++      case 75: /* ifexists ::= IF EXISTS */ yytestcase(yyruleno==75);
    ++      case 185: /* between_op ::= NOT BETWEEN */ yytestcase(yyruleno==185);
    ++      case 188: /* in_op ::= NOT IN */ yytestcase(yyruleno==188);
    ++      case 214: /* collate ::= COLLATE ID|STRING */ yytestcase(yyruleno==214);
    ++{yymsp[-1].minor.yy4 = 1;}
    +         break;
    +-      case 90: /* tconscomma ::= COMMA */
    ++      case 59: /* init_deferred_pred_opt ::= INITIALLY IMMEDIATE */
    ++{yymsp[-1].minor.yy4 = 0;}
    ++        break;
    ++      case 61: /* tconscomma ::= COMMA */
    + {pParse->constraintName.n = 0;}
    +         break;
    +-      case 93: /* tcons ::= PRIMARY KEY LP sortlist autoinc RP onconf */
    +-{sqlite3AddPrimaryKey(pParse,yymsp[-3].minor.yy14,yymsp[0].minor.yy328,yymsp[-2].minor.yy328,0);}
    ++      case 63: /* tcons ::= PRIMARY KEY LP sortlist autoinc RP onconf */
    ++{sqlite3AddPrimaryKey(pParse,yymsp[-3].minor.yy322,yymsp[0].minor.yy4,yymsp[-2].minor.yy4,0);}
    +         break;
    +-      case 94: /* tcons ::= UNIQUE LP sortlist RP onconf */
    +-{sqlite3CreateIndex(pParse,0,0,0,yymsp[-2].minor.yy14,yymsp[0].minor.yy328,0,0,0,0);}
    ++      case 64: /* tcons ::= UNIQUE LP sortlist RP onconf */
    ++{sqlite3CreateIndex(pParse,0,0,0,yymsp[-2].minor.yy322,yymsp[0].minor.yy4,0,0,0,0,
    ++                                       SQLITE_IDXTYPE_UNIQUE);}
    +         break;
    +-      case 95: /* tcons ::= CHECK LP expr RP onconf */
    +-{sqlite3AddCheckConstraint(pParse,yymsp[-2].minor.yy346.pExpr);}
    ++      case 65: /* tcons ::= CHECK LP expr RP onconf */
    ++{sqlite3AddCheckConstraint(pParse,yymsp[-2].minor.yy314);}
    +         break;
    +-      case 96: /* tcons ::= FOREIGN KEY LP eidlist RP REFERENCES nm eidlist_opt refargs defer_subclause_opt */
    ++      case 66: /* tcons ::= FOREIGN KEY LP eidlist RP REFERENCES nm eidlist_opt refargs defer_subclause_opt */
    + {
    +-    sqlite3CreateForeignKey(pParse, yymsp[-6].minor.yy14, &yymsp[-3].minor.yy0, yymsp[-2].minor.yy14, yymsp[-1].minor.yy328);
    +-    sqlite3DeferForeignKey(pParse, yymsp[0].minor.yy328);
    ++    sqlite3CreateForeignKey(pParse, yymsp[-6].minor.yy322, &yymsp[-3].minor.yy0, yymsp[-2].minor.yy322, yymsp[-1].minor.yy4);
    ++    sqlite3DeferForeignKey(pParse, yymsp[0].minor.yy4);
    + }
    +         break;
    +-      case 99: /* onconf ::= */
    +-{yygotominor.yy328 = OE_Default;}
    +-        break;
    +-      case 101: /* orconf ::= */
    +-{yygotominor.yy186 = OE_Default;}
    ++      case 68: /* onconf ::= */
    ++      case 70: /* orconf ::= */ yytestcase(yyruleno==70);
    ++{yymsp[1].minor.yy4 = OE_Default;}
    +         break;
    +-      case 102: /* orconf ::= OR resolvetype */
    +-{yygotominor.yy186 = (u8)yymsp[0].minor.yy328;}
    ++      case 69: /* onconf ::= ON CONFLICT resolvetype */
    ++{yymsp[-2].minor.yy4 = yymsp[0].minor.yy4;}
    +         break;
    +-      case 104: /* resolvetype ::= IGNORE */
    +-{yygotominor.yy328 = OE_Ignore;}
    ++      case 72: /* resolvetype ::= IGNORE */
    ++{yymsp[0].minor.yy4 = OE_Ignore;}
    +         break;
    +-      case 105: /* resolvetype ::= REPLACE */
    +-{yygotominor.yy328 = OE_Replace;}
    ++      case 73: /* resolvetype ::= REPLACE */
    ++      case 145: /* insert_cmd ::= REPLACE */ yytestcase(yyruleno==145);
    ++{yymsp[0].minor.yy4 = OE_Replace;}
    +         break;
    +-      case 106: /* cmd ::= DROP TABLE ifexists fullname */
    ++      case 74: /* cmd ::= DROP TABLE ifexists fullname */
    + {
    +-  sqlite3DropTable(pParse, yymsp[0].minor.yy65, 0, yymsp[-1].minor.yy328);
    ++  sqlite3DropTable(pParse, yymsp[0].minor.yy259, 0, yymsp[-1].minor.yy4);
    + }
    +         break;
    +-      case 109: /* cmd ::= createkw temp VIEW ifnotexists nm dbnm eidlist_opt AS select */
    ++      case 77: /* cmd ::= createkw temp VIEW ifnotexists nm dbnm eidlist_opt AS select */
    + {
    +-  sqlite3CreateView(pParse, &yymsp[-8].minor.yy0, &yymsp[-4].minor.yy0, &yymsp[-3].minor.yy0, yymsp[-2].minor.yy14, yymsp[0].minor.yy3, yymsp[-7].minor.yy328, yymsp[-5].minor.yy328);
    ++  sqlite3CreateView(pParse, &yymsp[-8].minor.yy0, &yymsp[-4].minor.yy0, &yymsp[-3].minor.yy0, yymsp[-2].minor.yy322, yymsp[0].minor.yy387, yymsp[-7].minor.yy4, yymsp[-5].minor.yy4);
    + }
    +         break;
    +-      case 110: /* cmd ::= DROP VIEW ifexists fullname */
    ++      case 78: /* cmd ::= DROP VIEW ifexists fullname */
    + {
    +-  sqlite3DropTable(pParse, yymsp[0].minor.yy65, 1, yymsp[-1].minor.yy328);
    ++  sqlite3DropTable(pParse, yymsp[0].minor.yy259, 1, yymsp[-1].minor.yy4);
    + }
    +         break;
    +-      case 111: /* cmd ::= select */
    ++      case 79: /* cmd ::= select */
    + {
    +   SelectDest dest = {SRT_Output, 0, 0, 0, 0, 0};
    +-  sqlite3Select(pParse, yymsp[0].minor.yy3, &dest);
    +-  sqlite3SelectDelete(pParse->db, yymsp[0].minor.yy3);
    ++  sqlite3Select(pParse, yymsp[0].minor.yy387, &dest);
    ++  sqlite3SelectDelete(pParse->db, yymsp[0].minor.yy387);
    + }
    +         break;
    +-      case 112: /* select ::= with selectnowith */
    ++      case 80: /* select ::= with selectnowith */
    + {
    +-  Select *p = yymsp[0].minor.yy3;
    ++  Select *p = yymsp[0].minor.yy387;
    +   if( p ){
    +-    p->pWith = yymsp[-1].minor.yy59;
    ++    p->pWith = yymsp[-1].minor.yy451;
    +     parserDoubleLinkSelect(pParse, p);
    +   }else{
    +-    sqlite3WithDelete(pParse->db, yymsp[-1].minor.yy59);
    ++    sqlite3WithDelete(pParse->db, yymsp[-1].minor.yy451);
    +   }
    +-  yygotominor.yy3 = p;
    ++  yymsp[-1].minor.yy387 = p; /*A-overwrites-W*/
    + }
    +         break;
    +-      case 113: /* selectnowith ::= oneselect */
    +-      case 119: /* oneselect ::= values */ yytestcase(yyruleno==119);
    +-{yygotominor.yy3 = yymsp[0].minor.yy3;}
    +-        break;
    +-      case 114: /* selectnowith ::= selectnowith multiselect_op oneselect */
    ++      case 81: /* selectnowith ::= selectnowith multiselect_op oneselect */
    + {
    +-  Select *pRhs = yymsp[0].minor.yy3;
    +-  Select *pLhs = yymsp[-2].minor.yy3;
    ++  Select *pRhs = yymsp[0].minor.yy387;
    ++  Select *pLhs = yymsp[-2].minor.yy387;
    +   if( pRhs && pRhs->pPrior ){
    +     SrcList *pFrom;
    +     Token x;
    +     x.n = 0;
    +     parserDoubleLinkSelect(pParse, pRhs);
    +     pFrom = sqlite3SrcListAppendFromTerm(pParse,0,0,0,&x,pRhs,0,0);
    +-    pRhs = sqlite3SelectNew(pParse,0,pFrom,0,0,0,0,0,0,0);
    ++    pRhs = sqlite3SelectNew(pParse,0,pFrom,0,0,0,0,0,0);
    +   }
    +   if( pRhs ){
    +-    pRhs->op = (u8)yymsp[-1].minor.yy328;
    ++    pRhs->op = (u8)yymsp[-1].minor.yy4;
    +     pRhs->pPrior = pLhs;
    +     if( ALWAYS(pLhs) ) pLhs->selFlags &= ~SF_MultiValue;
    +     pRhs->selFlags &= ~SF_MultiValue;
    +-    if( yymsp[-1].minor.yy328!=TK_ALL ) pParse->hasCompound = 1;
    ++    if( yymsp[-1].minor.yy4!=TK_ALL ) pParse->hasCompound = 1;
    +   }else{
    +     sqlite3SelectDelete(pParse->db, pLhs);
    +   }
    +-  yygotominor.yy3 = pRhs;
    ++  yymsp[-2].minor.yy387 = pRhs;
    + }
    +         break;
    +-      case 116: /* multiselect_op ::= UNION ALL */
    +-{yygotominor.yy328 = TK_ALL;}
    ++      case 82: /* multiselect_op ::= UNION */
    ++      case 84: /* multiselect_op ::= EXCEPT|INTERSECT */ yytestcase(yyruleno==84);
    ++{yymsp[0].minor.yy4 = yymsp[0].major; /*A-overwrites-OP*/}
    ++        break;
    ++      case 83: /* multiselect_op ::= UNION ALL */
    ++{yymsp[-1].minor.yy4 = TK_ALL;}
    +         break;
    +-      case 118: /* oneselect ::= SELECT distinct selcollist from where_opt groupby_opt having_opt orderby_opt limit_opt */
    ++      case 85: /* oneselect ::= SELECT distinct selcollist from where_opt groupby_opt having_opt orderby_opt limit_opt */
    + {
    +-  yygotominor.yy3 = sqlite3SelectNew(pParse,yymsp[-6].minor.yy14,yymsp[-5].minor.yy65,yymsp[-4].minor.yy132,yymsp[-3].minor.yy14,yymsp[-2].minor.yy132,yymsp[-1].minor.yy14,yymsp[-7].minor.yy381,yymsp[0].minor.yy476.pLimit,yymsp[0].minor.yy476.pOffset);
    ++#if SELECTTRACE_ENABLED
    ++  Token s = yymsp[-8].minor.yy0; /*A-overwrites-S*/
    ++#endif
    ++  yymsp[-8].minor.yy387 = sqlite3SelectNew(pParse,yymsp[-6].minor.yy322,yymsp[-5].minor.yy259,yymsp[-4].minor.yy314,yymsp[-3].minor.yy322,yymsp[-2].minor.yy314,yymsp[-1].minor.yy322,yymsp[-7].minor.yy4,yymsp[0].minor.yy314);
    + #if SELECTTRACE_ENABLED
    +   /* Populate the Select.zSelName[] string that is used to help with
    +   ** query planner debugging, to differentiate between multiple Select
    +@@ -128479,455 +140901,468 @@ static void yy_reduce(
    +   ** comment to be the zSelName value.  Otherwise, the label is #N where
    +   ** is an integer that is incremented with each SELECT statement seen.
    +   */
    +-  if( yygotominor.yy3!=0 ){
    +-    const char *z = yymsp[-8].minor.yy0.z+6;
    ++  if( yymsp[-8].minor.yy387!=0 ){
    ++    const char *z = s.z+6;
    +     int i;
    +-    sqlite3_snprintf(sizeof(yygotominor.yy3->zSelName), yygotominor.yy3->zSelName, "#%d",
    ++    sqlite3_snprintf(sizeof(yymsp[-8].minor.yy387->zSelName), yymsp[-8].minor.yy387->zSelName, "#%d",
    +                      ++pParse->nSelect);
    +     while( z[0]==' ' ) z++;
    +     if( z[0]=='/' && z[1]=='*' ){
    +       z += 2;
    +       while( z[0]==' ' ) z++;
    +       for(i=0; sqlite3Isalnum(z[i]); i++){}
    +-      sqlite3_snprintf(sizeof(yygotominor.yy3->zSelName), yygotominor.yy3->zSelName, "%.*s", i, z);
    ++      sqlite3_snprintf(sizeof(yymsp[-8].minor.yy387->zSelName), yymsp[-8].minor.yy387->zSelName, "%.*s", i, z);
    +     }
    +   }
    + #endif /* SELECTRACE_ENABLED */
    + }
    +         break;
    +-      case 120: /* values ::= VALUES LP nexprlist RP */
    ++      case 86: /* values ::= VALUES LP nexprlist RP */
    + {
    +-  yygotominor.yy3 = sqlite3SelectNew(pParse,yymsp[-1].minor.yy14,0,0,0,0,0,SF_Values,0,0);
    ++  yymsp[-3].minor.yy387 = sqlite3SelectNew(pParse,yymsp[-1].minor.yy322,0,0,0,0,0,SF_Values,0);
    + }
    +         break;
    +-      case 121: /* values ::= values COMMA LP exprlist RP */
    ++      case 87: /* values ::= values COMMA LP exprlist RP */
    + {
    +-  Select *pRight, *pLeft = yymsp[-4].minor.yy3;
    +-  pRight = sqlite3SelectNew(pParse,yymsp[-1].minor.yy14,0,0,0,0,0,SF_Values|SF_MultiValue,0,0);
    ++  Select *pRight, *pLeft = yymsp[-4].minor.yy387;
    ++  pRight = sqlite3SelectNew(pParse,yymsp[-1].minor.yy322,0,0,0,0,0,SF_Values|SF_MultiValue,0);
    +   if( ALWAYS(pLeft) ) pLeft->selFlags &= ~SF_MultiValue;
    +   if( pRight ){
    +     pRight->op = TK_ALL;
    +-    pLeft = yymsp[-4].minor.yy3;
    +     pRight->pPrior = pLeft;
    +-    yygotominor.yy3 = pRight;
    ++    yymsp[-4].minor.yy387 = pRight;
    +   }else{
    +-    yygotominor.yy3 = pLeft;
    ++    yymsp[-4].minor.yy387 = pLeft;
    +   }
    + }
    +         break;
    +-      case 122: /* distinct ::= DISTINCT */
    +-{yygotominor.yy381 = SF_Distinct;}
    +-        break;
    +-      case 123: /* distinct ::= ALL */
    +-{yygotominor.yy381 = SF_All;}
    +-        break;
    +-      case 124: /* distinct ::= */
    +-{yygotominor.yy381 = 0;}
    ++      case 88: /* distinct ::= DISTINCT */
    ++{yymsp[0].minor.yy4 = SF_Distinct;}
    +         break;
    +-      case 125: /* sclp ::= selcollist COMMA */
    +-      case 244: /* eidlist_opt ::= LP eidlist RP */ yytestcase(yyruleno==244);
    +-{yygotominor.yy14 = yymsp[-1].minor.yy14;}
    ++      case 89: /* distinct ::= ALL */
    ++{yymsp[0].minor.yy4 = SF_All;}
    +         break;
    +-      case 126: /* sclp ::= */
    +-      case 155: /* orderby_opt ::= */ yytestcase(yyruleno==155);
    +-      case 162: /* groupby_opt ::= */ yytestcase(yyruleno==162);
    +-      case 237: /* exprlist ::= */ yytestcase(yyruleno==237);
    +-      case 243: /* eidlist_opt ::= */ yytestcase(yyruleno==243);
    +-{yygotominor.yy14 = 0;}
    ++      case 91: /* sclp ::= */
    ++      case 119: /* orderby_opt ::= */ yytestcase(yyruleno==119);
    ++      case 126: /* groupby_opt ::= */ yytestcase(yyruleno==126);
    ++      case 201: /* exprlist ::= */ yytestcase(yyruleno==201);
    ++      case 204: /* paren_exprlist ::= */ yytestcase(yyruleno==204);
    ++      case 209: /* eidlist_opt ::= */ yytestcase(yyruleno==209);
    ++{yymsp[1].minor.yy322 = 0;}
    +         break;
    +-      case 127: /* selcollist ::= sclp expr as */
    ++      case 92: /* selcollist ::= sclp scanpt expr scanpt as */
    + {
    +-   yygotominor.yy14 = sqlite3ExprListAppend(pParse, yymsp[-2].minor.yy14, yymsp[-1].minor.yy346.pExpr);
    +-   if( yymsp[0].minor.yy0.n>0 ) sqlite3ExprListSetName(pParse, yygotominor.yy14, &yymsp[0].minor.yy0, 1);
    +-   sqlite3ExprListSetSpan(pParse,yygotominor.yy14,&yymsp[-1].minor.yy346);
    ++   yymsp[-4].minor.yy322 = sqlite3ExprListAppend(pParse, yymsp[-4].minor.yy322, yymsp[-2].minor.yy314);
    ++   if( yymsp[0].minor.yy0.n>0 ) sqlite3ExprListSetName(pParse, yymsp[-4].minor.yy322, &yymsp[0].minor.yy0, 1);
    ++   sqlite3ExprListSetSpan(pParse,yymsp[-4].minor.yy322,yymsp[-3].minor.yy336,yymsp[-1].minor.yy336);
    + }
    +         break;
    +-      case 128: /* selcollist ::= sclp STAR */
    ++      case 93: /* selcollist ::= sclp scanpt STAR */
    + {
    +-  Expr *p = sqlite3Expr(pParse->db, TK_ALL, 0);
    +-  yygotominor.yy14 = sqlite3ExprListAppend(pParse, yymsp[-1].minor.yy14, p);
    ++  Expr *p = sqlite3Expr(pParse->db, TK_ASTERISK, 0);
    ++  yymsp[-2].minor.yy322 = sqlite3ExprListAppend(pParse, yymsp[-2].minor.yy322, p);
    + }
    +         break;
    +-      case 129: /* selcollist ::= sclp nm DOT STAR */
    ++      case 94: /* selcollist ::= sclp scanpt nm DOT STAR */
    + {
    +-  Expr *pRight = sqlite3PExpr(pParse, TK_ALL, 0, 0, &yymsp[0].minor.yy0);
    +-  Expr *pLeft = sqlite3PExpr(pParse, TK_ID, 0, 0, &yymsp[-2].minor.yy0);
    +-  Expr *pDot = sqlite3PExpr(pParse, TK_DOT, pLeft, pRight, 0);
    +-  yygotominor.yy14 = sqlite3ExprListAppend(pParse,yymsp[-3].minor.yy14, pDot);
    ++  Expr *pRight = sqlite3PExpr(pParse, TK_ASTERISK, 0, 0);
    ++  Expr *pLeft = sqlite3ExprAlloc(pParse->db, TK_ID, &yymsp[-2].minor.yy0, 1);
    ++  Expr *pDot = sqlite3PExpr(pParse, TK_DOT, pLeft, pRight);
    ++  yymsp[-4].minor.yy322 = sqlite3ExprListAppend(pParse,yymsp[-4].minor.yy322, pDot);
    + }
    +         break;
    +-      case 132: /* as ::= */
    +-{yygotominor.yy0.n = 0;}
    ++      case 95: /* as ::= AS nm */
    ++      case 106: /* dbnm ::= DOT nm */ yytestcase(yyruleno==106);
    ++      case 223: /* plus_num ::= PLUS INTEGER|FLOAT */ yytestcase(yyruleno==223);
    ++      case 224: /* minus_num ::= MINUS INTEGER|FLOAT */ yytestcase(yyruleno==224);
    ++{yymsp[-1].minor.yy0 = yymsp[0].minor.yy0;}
    +         break;
    +-      case 133: /* from ::= */
    +-{yygotominor.yy65 = sqlite3DbMallocZero(pParse->db, sizeof(*yygotominor.yy65));}
    ++      case 97: /* from ::= */
    ++{yymsp[1].minor.yy259 = sqlite3DbMallocZero(pParse->db, sizeof(*yymsp[1].minor.yy259));}
    +         break;
    +-      case 134: /* from ::= FROM seltablist */
    ++      case 98: /* from ::= FROM seltablist */
    + {
    +-  yygotominor.yy65 = yymsp[0].minor.yy65;
    +-  sqlite3SrcListShiftJoinType(yygotominor.yy65);
    ++  yymsp[-1].minor.yy259 = yymsp[0].minor.yy259;
    ++  sqlite3SrcListShiftJoinType(yymsp[-1].minor.yy259);
    + }
    +         break;
    +-      case 135: /* stl_prefix ::= seltablist joinop */
    ++      case 99: /* stl_prefix ::= seltablist joinop */
    + {
    +-   yygotominor.yy65 = yymsp[-1].minor.yy65;
    +-   if( ALWAYS(yygotominor.yy65 && yygotominor.yy65->nSrc>0) ) yygotominor.yy65->a[yygotominor.yy65->nSrc-1].fg.jointype = (u8)yymsp[0].minor.yy328;
    ++   if( ALWAYS(yymsp[-1].minor.yy259 && yymsp[-1].minor.yy259->nSrc>0) ) yymsp[-1].minor.yy259->a[yymsp[-1].minor.yy259->nSrc-1].fg.jointype = (u8)yymsp[0].minor.yy4;
    + }
    +         break;
    +-      case 136: /* stl_prefix ::= */
    +-{yygotominor.yy65 = 0;}
    ++      case 100: /* stl_prefix ::= */
    ++{yymsp[1].minor.yy259 = 0;}
    +         break;
    +-      case 137: /* seltablist ::= stl_prefix nm dbnm as indexed_opt on_opt using_opt */
    ++      case 101: /* seltablist ::= stl_prefix nm dbnm as indexed_opt on_opt using_opt */
    + {
    +-  yygotominor.yy65 = sqlite3SrcListAppendFromTerm(pParse,yymsp[-6].minor.yy65,&yymsp[-5].minor.yy0,&yymsp[-4].minor.yy0,&yymsp[-3].minor.yy0,0,yymsp[-1].minor.yy132,yymsp[0].minor.yy408);
    +-  sqlite3SrcListIndexedBy(pParse, yygotominor.yy65, &yymsp[-2].minor.yy0);
    ++  yymsp[-6].minor.yy259 = sqlite3SrcListAppendFromTerm(pParse,yymsp[-6].minor.yy259,&yymsp[-5].minor.yy0,&yymsp[-4].minor.yy0,&yymsp[-3].minor.yy0,0,yymsp[-1].minor.yy314,yymsp[0].minor.yy384);
    ++  sqlite3SrcListIndexedBy(pParse, yymsp[-6].minor.yy259, &yymsp[-2].minor.yy0);
    + }
    +         break;
    +-      case 138: /* seltablist ::= stl_prefix nm dbnm LP exprlist RP as on_opt using_opt */
    ++      case 102: /* seltablist ::= stl_prefix nm dbnm LP exprlist RP as on_opt using_opt */
    + {
    +-  yygotominor.yy65 = sqlite3SrcListAppendFromTerm(pParse,yymsp[-8].minor.yy65,&yymsp[-7].minor.yy0,&yymsp[-6].minor.yy0,&yymsp[-2].minor.yy0,0,yymsp[-1].minor.yy132,yymsp[0].minor.yy408);
    +-  sqlite3SrcListFuncArgs(pParse, yygotominor.yy65, yymsp[-4].minor.yy14);
    ++  yymsp[-8].minor.yy259 = sqlite3SrcListAppendFromTerm(pParse,yymsp[-8].minor.yy259,&yymsp[-7].minor.yy0,&yymsp[-6].minor.yy0,&yymsp[-2].minor.yy0,0,yymsp[-1].minor.yy314,yymsp[0].minor.yy384);
    ++  sqlite3SrcListFuncArgs(pParse, yymsp[-8].minor.yy259, yymsp[-4].minor.yy322);
    + }
    +         break;
    +-      case 139: /* seltablist ::= stl_prefix LP select RP as on_opt using_opt */
    ++      case 103: /* seltablist ::= stl_prefix LP select RP as on_opt using_opt */
    + {
    +-    yygotominor.yy65 = sqlite3SrcListAppendFromTerm(pParse,yymsp[-6].minor.yy65,0,0,&yymsp[-2].minor.yy0,yymsp[-4].minor.yy3,yymsp[-1].minor.yy132,yymsp[0].minor.yy408);
    ++    yymsp[-6].minor.yy259 = sqlite3SrcListAppendFromTerm(pParse,yymsp[-6].minor.yy259,0,0,&yymsp[-2].minor.yy0,yymsp[-4].minor.yy387,yymsp[-1].minor.yy314,yymsp[0].minor.yy384);
    +   }
    +         break;
    +-      case 140: /* seltablist ::= stl_prefix LP seltablist RP as on_opt using_opt */
    ++      case 104: /* seltablist ::= stl_prefix LP seltablist RP as on_opt using_opt */
    + {
    +-    if( yymsp[-6].minor.yy65==0 && yymsp[-2].minor.yy0.n==0 && yymsp[-1].minor.yy132==0 && yymsp[0].minor.yy408==0 ){
    +-      yygotominor.yy65 = yymsp[-4].minor.yy65;
    +-    }else if( yymsp[-4].minor.yy65->nSrc==1 ){
    +-      yygotominor.yy65 = sqlite3SrcListAppendFromTerm(pParse,yymsp[-6].minor.yy65,0,0,&yymsp[-2].minor.yy0,0,yymsp[-1].minor.yy132,yymsp[0].minor.yy408);
    +-      if( yygotominor.yy65 ){
    +-        struct SrcList_item *pNew = &yygotominor.yy65->a[yygotominor.yy65->nSrc-1];
    +-        struct SrcList_item *pOld = yymsp[-4].minor.yy65->a;
    ++    if( yymsp[-6].minor.yy259==0 && yymsp[-2].minor.yy0.n==0 && yymsp[-1].minor.yy314==0 && yymsp[0].minor.yy384==0 ){
    ++      yymsp[-6].minor.yy259 = yymsp[-4].minor.yy259;
    ++    }else if( yymsp[-4].minor.yy259->nSrc==1 ){
    ++      yymsp[-6].minor.yy259 = sqlite3SrcListAppendFromTerm(pParse,yymsp[-6].minor.yy259,0,0,&yymsp[-2].minor.yy0,0,yymsp[-1].minor.yy314,yymsp[0].minor.yy384);
    ++      if( yymsp[-6].minor.yy259 ){
    ++        struct SrcList_item *pNew = &yymsp[-6].minor.yy259->a[yymsp[-6].minor.yy259->nSrc-1];
    ++        struct SrcList_item *pOld = yymsp[-4].minor.yy259->a;
    +         pNew->zName = pOld->zName;
    +         pNew->zDatabase = pOld->zDatabase;
    +         pNew->pSelect = pOld->pSelect;
    +         pOld->zName = pOld->zDatabase = 0;
    +         pOld->pSelect = 0;
    +       }
    +-      sqlite3SrcListDelete(pParse->db, yymsp[-4].minor.yy65);
    ++      sqlite3SrcListDelete(pParse->db, yymsp[-4].minor.yy259);
    +     }else{
    +       Select *pSubquery;
    +-      sqlite3SrcListShiftJoinType(yymsp[-4].minor.yy65);
    +-      pSubquery = sqlite3SelectNew(pParse,0,yymsp[-4].minor.yy65,0,0,0,0,SF_NestedFrom,0,0);
    +-      yygotominor.yy65 = sqlite3SrcListAppendFromTerm(pParse,yymsp[-6].minor.yy65,0,0,&yymsp[-2].minor.yy0,pSubquery,yymsp[-1].minor.yy132,yymsp[0].minor.yy408);
    ++      sqlite3SrcListShiftJoinType(yymsp[-4].minor.yy259);
    ++      pSubquery = sqlite3SelectNew(pParse,0,yymsp[-4].minor.yy259,0,0,0,0,SF_NestedFrom,0);
    ++      yymsp[-6].minor.yy259 = sqlite3SrcListAppendFromTerm(pParse,yymsp[-6].minor.yy259,0,0,&yymsp[-2].minor.yy0,pSubquery,yymsp[-1].minor.yy314,yymsp[0].minor.yy384);
    +     }
    +   }
    +         break;
    +-      case 141: /* dbnm ::= */
    +-      case 150: /* indexed_opt ::= */ yytestcase(yyruleno==150);
    +-{yygotominor.yy0.z=0; yygotominor.yy0.n=0;}
    ++      case 105: /* dbnm ::= */
    ++      case 114: /* indexed_opt ::= */ yytestcase(yyruleno==114);
    ++{yymsp[1].minor.yy0.z=0; yymsp[1].minor.yy0.n=0;}
    +         break;
    +-      case 143: /* fullname ::= nm dbnm */
    +-{yygotominor.yy65 = sqlite3SrcListAppend(pParse->db,0,&yymsp[-1].minor.yy0,&yymsp[0].minor.yy0);}
    ++      case 107: /* fullname ::= nm dbnm */
    ++{yymsp[-1].minor.yy259 = sqlite3SrcListAppend(pParse->db,0,&yymsp[-1].minor.yy0,&yymsp[0].minor.yy0); /*A-overwrites-X*/}
    +         break;
    +-      case 144: /* joinop ::= COMMA|JOIN */
    +-{ yygotominor.yy328 = JT_INNER; }
    ++      case 108: /* joinop ::= COMMA|JOIN */
    ++{ yymsp[0].minor.yy4 = JT_INNER; }
    +         break;
    +-      case 145: /* joinop ::= JOIN_KW JOIN */
    +-{ yygotominor.yy328 = sqlite3JoinType(pParse,&yymsp[-1].minor.yy0,0,0); }
    ++      case 109: /* joinop ::= JOIN_KW JOIN */
    ++{yymsp[-1].minor.yy4 = sqlite3JoinType(pParse,&yymsp[-1].minor.yy0,0,0);  /*X-overwrites-A*/}
    +         break;
    +-      case 146: /* joinop ::= JOIN_KW nm JOIN */
    +-{ yygotominor.yy328 = sqlite3JoinType(pParse,&yymsp[-2].minor.yy0,&yymsp[-1].minor.yy0,0); }
    ++      case 110: /* joinop ::= JOIN_KW nm JOIN */
    ++{yymsp[-2].minor.yy4 = sqlite3JoinType(pParse,&yymsp[-2].minor.yy0,&yymsp[-1].minor.yy0,0); /*X-overwrites-A*/}
    +         break;
    +-      case 147: /* joinop ::= JOIN_KW nm nm JOIN */
    +-{ yygotominor.yy328 = sqlite3JoinType(pParse,&yymsp[-3].minor.yy0,&yymsp[-2].minor.yy0,&yymsp[-1].minor.yy0); }
    ++      case 111: /* joinop ::= JOIN_KW nm nm JOIN */
    ++{yymsp[-3].minor.yy4 = sqlite3JoinType(pParse,&yymsp[-3].minor.yy0,&yymsp[-2].minor.yy0,&yymsp[-1].minor.yy0);/*X-overwrites-A*/}
    +         break;
    +-      case 148: /* on_opt ::= ON expr */
    +-      case 165: /* having_opt ::= HAVING expr */ yytestcase(yyruleno==165);
    +-      case 172: /* where_opt ::= WHERE expr */ yytestcase(yyruleno==172);
    +-      case 232: /* case_else ::= ELSE expr */ yytestcase(yyruleno==232);
    +-      case 234: /* case_operand ::= expr */ yytestcase(yyruleno==234);
    +-{yygotominor.yy132 = yymsp[0].minor.yy346.pExpr;}
    ++      case 112: /* on_opt ::= ON expr */
    ++      case 129: /* having_opt ::= HAVING expr */ yytestcase(yyruleno==129);
    ++      case 136: /* where_opt ::= WHERE expr */ yytestcase(yyruleno==136);
    ++      case 197: /* case_else ::= ELSE expr */ yytestcase(yyruleno==197);
    ++{yymsp[-1].minor.yy314 = yymsp[0].minor.yy314;}
    +         break;
    +-      case 149: /* on_opt ::= */
    +-      case 164: /* having_opt ::= */ yytestcase(yyruleno==164);
    +-      case 171: /* where_opt ::= */ yytestcase(yyruleno==171);
    +-      case 233: /* case_else ::= */ yytestcase(yyruleno==233);
    +-      case 235: /* case_operand ::= */ yytestcase(yyruleno==235);
    +-{yygotominor.yy132 = 0;}
    ++      case 113: /* on_opt ::= */
    ++      case 128: /* having_opt ::= */ yytestcase(yyruleno==128);
    ++      case 130: /* limit_opt ::= */ yytestcase(yyruleno==130);
    ++      case 135: /* where_opt ::= */ yytestcase(yyruleno==135);
    ++      case 198: /* case_else ::= */ yytestcase(yyruleno==198);
    ++      case 200: /* case_operand ::= */ yytestcase(yyruleno==200);
    ++{yymsp[1].minor.yy314 = 0;}
    +         break;
    +-      case 152: /* indexed_opt ::= NOT INDEXED */
    +-{yygotominor.yy0.z=0; yygotominor.yy0.n=1;}
    ++      case 115: /* indexed_opt ::= INDEXED BY nm */
    ++{yymsp[-2].minor.yy0 = yymsp[0].minor.yy0;}
    +         break;
    +-      case 153: /* using_opt ::= USING LP idlist RP */
    +-      case 181: /* idlist_opt ::= LP idlist RP */ yytestcase(yyruleno==181);
    +-{yygotominor.yy408 = yymsp[-1].minor.yy408;}
    ++      case 116: /* indexed_opt ::= NOT INDEXED */
    ++{yymsp[-1].minor.yy0.z=0; yymsp[-1].minor.yy0.n=1;}
    +         break;
    +-      case 154: /* using_opt ::= */
    +-      case 180: /* idlist_opt ::= */ yytestcase(yyruleno==180);
    +-{yygotominor.yy408 = 0;}
    ++      case 117: /* using_opt ::= USING LP idlist RP */
    ++{yymsp[-3].minor.yy384 = yymsp[-1].minor.yy384;}
    +         break;
    +-      case 156: /* orderby_opt ::= ORDER BY sortlist */
    +-      case 163: /* groupby_opt ::= GROUP BY nexprlist */ yytestcase(yyruleno==163);
    +-      case 236: /* exprlist ::= nexprlist */ yytestcase(yyruleno==236);
    +-{yygotominor.yy14 = yymsp[0].minor.yy14;}
    ++      case 118: /* using_opt ::= */
    ++      case 146: /* idlist_opt ::= */ yytestcase(yyruleno==146);
    ++{yymsp[1].minor.yy384 = 0;}
    +         break;
    +-      case 157: /* sortlist ::= sortlist COMMA expr sortorder */
    ++      case 120: /* orderby_opt ::= ORDER BY sortlist */
    ++      case 127: /* groupby_opt ::= GROUP BY nexprlist */ yytestcase(yyruleno==127);
    ++{yymsp[-2].minor.yy322 = yymsp[0].minor.yy322;}
    ++        break;
    ++      case 121: /* sortlist ::= sortlist COMMA expr sortorder */
    + {
    +-  yygotominor.yy14 = sqlite3ExprListAppend(pParse,yymsp[-3].minor.yy14,yymsp[-1].minor.yy346.pExpr);
    +-  sqlite3ExprListSetSortOrder(yygotominor.yy14,yymsp[0].minor.yy328);
    ++  yymsp[-3].minor.yy322 = sqlite3ExprListAppend(pParse,yymsp[-3].minor.yy322,yymsp[-1].minor.yy314);
    ++  sqlite3ExprListSetSortOrder(yymsp[-3].minor.yy322,yymsp[0].minor.yy4);
    + }
    +         break;
    +-      case 158: /* sortlist ::= expr sortorder */
    ++      case 122: /* sortlist ::= expr sortorder */
    + {
    +-  yygotominor.yy14 = sqlite3ExprListAppend(pParse,0,yymsp[-1].minor.yy346.pExpr);
    +-  sqlite3ExprListSetSortOrder(yygotominor.yy14,yymsp[0].minor.yy328);
    ++  yymsp[-1].minor.yy322 = sqlite3ExprListAppend(pParse,0,yymsp[-1].minor.yy314); /*A-overwrites-Y*/
    ++  sqlite3ExprListSetSortOrder(yymsp[-1].minor.yy322,yymsp[0].minor.yy4);
    + }
    +         break;
    +-      case 159: /* sortorder ::= ASC */
    +-{yygotominor.yy328 = SQLITE_SO_ASC;}
    +-        break;
    +-      case 160: /* sortorder ::= DESC */
    +-{yygotominor.yy328 = SQLITE_SO_DESC;}
    ++      case 123: /* sortorder ::= ASC */
    ++{yymsp[0].minor.yy4 = SQLITE_SO_ASC;}
    +         break;
    +-      case 161: /* sortorder ::= */
    +-{yygotominor.yy328 = SQLITE_SO_UNDEFINED;}
    ++      case 124: /* sortorder ::= DESC */
    ++{yymsp[0].minor.yy4 = SQLITE_SO_DESC;}
    +         break;
    +-      case 166: /* limit_opt ::= */
    +-{yygotominor.yy476.pLimit = 0; yygotominor.yy476.pOffset = 0;}
    ++      case 125: /* sortorder ::= */
    ++{yymsp[1].minor.yy4 = SQLITE_SO_UNDEFINED;}
    +         break;
    +-      case 167: /* limit_opt ::= LIMIT expr */
    +-{yygotominor.yy476.pLimit = yymsp[0].minor.yy346.pExpr; yygotominor.yy476.pOffset = 0;}
    ++      case 131: /* limit_opt ::= LIMIT expr */
    ++{yymsp[-1].minor.yy314 = sqlite3PExpr(pParse,TK_LIMIT,yymsp[0].minor.yy314,0);}
    +         break;
    +-      case 168: /* limit_opt ::= LIMIT expr OFFSET expr */
    +-{yygotominor.yy476.pLimit = yymsp[-2].minor.yy346.pExpr; yygotominor.yy476.pOffset = yymsp[0].minor.yy346.pExpr;}
    ++      case 132: /* limit_opt ::= LIMIT expr OFFSET expr */
    ++{yymsp[-3].minor.yy314 = sqlite3PExpr(pParse,TK_LIMIT,yymsp[-2].minor.yy314,yymsp[0].minor.yy314);}
    +         break;
    +-      case 169: /* limit_opt ::= LIMIT expr COMMA expr */
    +-{yygotominor.yy476.pOffset = yymsp[-2].minor.yy346.pExpr; yygotominor.yy476.pLimit = yymsp[0].minor.yy346.pExpr;}
    ++      case 133: /* limit_opt ::= LIMIT expr COMMA expr */
    ++{yymsp[-3].minor.yy314 = sqlite3PExpr(pParse,TK_LIMIT,yymsp[0].minor.yy314,yymsp[-2].minor.yy314);}
    +         break;
    +-      case 170: /* cmd ::= with DELETE FROM fullname indexed_opt where_opt */
    ++      case 134: /* cmd ::= with DELETE FROM fullname indexed_opt where_opt */
    + {
    +-  sqlite3WithPush(pParse, yymsp[-5].minor.yy59, 1);
    +-  sqlite3SrcListIndexedBy(pParse, yymsp[-2].minor.yy65, &yymsp[-1].minor.yy0);
    +-  sqlite3DeleteFrom(pParse,yymsp[-2].minor.yy65,yymsp[0].minor.yy132);
    ++  sqlite3WithPush(pParse, yymsp[-5].minor.yy451, 1);
    ++  sqlite3SrcListIndexedBy(pParse, yymsp[-2].minor.yy259, &yymsp[-1].minor.yy0);
    ++  sqlite3DeleteFrom(pParse,yymsp[-2].minor.yy259,yymsp[0].minor.yy314,0,0);
    + }
    +         break;
    +-      case 173: /* cmd ::= with UPDATE orconf fullname indexed_opt SET setlist where_opt */
    ++      case 137: /* cmd ::= with UPDATE orconf fullname indexed_opt SET setlist where_opt */
    + {
    +-  sqlite3WithPush(pParse, yymsp[-7].minor.yy59, 1);
    +-  sqlite3SrcListIndexedBy(pParse, yymsp[-4].minor.yy65, &yymsp[-3].minor.yy0);
    +-  sqlite3ExprListCheckLength(pParse,yymsp[-1].minor.yy14,"set list"); 
    +-  sqlite3Update(pParse,yymsp[-4].minor.yy65,yymsp[-1].minor.yy14,yymsp[0].minor.yy132,yymsp[-5].minor.yy186);
    ++  sqlite3WithPush(pParse, yymsp[-7].minor.yy451, 1);
    ++  sqlite3SrcListIndexedBy(pParse, yymsp[-4].minor.yy259, &yymsp[-3].minor.yy0);
    ++  sqlite3ExprListCheckLength(pParse,yymsp[-1].minor.yy322,"set list"); 
    ++  sqlite3Update(pParse,yymsp[-4].minor.yy259,yymsp[-1].minor.yy322,yymsp[0].minor.yy314,yymsp[-5].minor.yy4,0,0);
    + }
    +         break;
    +-      case 174: /* setlist ::= setlist COMMA nm EQ expr */
    ++      case 138: /* setlist ::= setlist COMMA nm EQ expr */
    + {
    +-  yygotominor.yy14 = sqlite3ExprListAppend(pParse, yymsp[-4].minor.yy14, yymsp[0].minor.yy346.pExpr);
    +-  sqlite3ExprListSetName(pParse, yygotominor.yy14, &yymsp[-2].minor.yy0, 1);
    ++  yymsp[-4].minor.yy322 = sqlite3ExprListAppend(pParse, yymsp[-4].minor.yy322, yymsp[0].minor.yy314);
    ++  sqlite3ExprListSetName(pParse, yymsp[-4].minor.yy322, &yymsp[-2].minor.yy0, 1);
    + }
    +         break;
    +-      case 175: /* setlist ::= nm EQ expr */
    ++      case 139: /* setlist ::= setlist COMMA LP idlist RP EQ expr */
    + {
    +-  yygotominor.yy14 = sqlite3ExprListAppend(pParse, 0, yymsp[0].minor.yy346.pExpr);
    +-  sqlite3ExprListSetName(pParse, yygotominor.yy14, &yymsp[-2].minor.yy0, 1);
    ++  yymsp[-6].minor.yy322 = sqlite3ExprListAppendVector(pParse, yymsp[-6].minor.yy322, yymsp[-3].minor.yy384, yymsp[0].minor.yy314);
    + }
    +         break;
    +-      case 176: /* cmd ::= with insert_cmd INTO fullname idlist_opt select */
    ++      case 140: /* setlist ::= nm EQ expr */
    + {
    +-  sqlite3WithPush(pParse, yymsp[-5].minor.yy59, 1);
    +-  sqlite3Insert(pParse, yymsp[-2].minor.yy65, yymsp[0].minor.yy3, yymsp[-1].minor.yy408, yymsp[-4].minor.yy186);
    ++  yylhsminor.yy322 = sqlite3ExprListAppend(pParse, 0, yymsp[0].minor.yy314);
    ++  sqlite3ExprListSetName(pParse, yylhsminor.yy322, &yymsp[-2].minor.yy0, 1);
    + }
    ++  yymsp[-2].minor.yy322 = yylhsminor.yy322;
    +         break;
    +-      case 177: /* cmd ::= with insert_cmd INTO fullname idlist_opt DEFAULT VALUES */
    ++      case 141: /* setlist ::= LP idlist RP EQ expr */
    + {
    +-  sqlite3WithPush(pParse, yymsp[-6].minor.yy59, 1);
    +-  sqlite3Insert(pParse, yymsp[-3].minor.yy65, 0, yymsp[-2].minor.yy408, yymsp[-5].minor.yy186);
    ++  yymsp[-4].minor.yy322 = sqlite3ExprListAppendVector(pParse, 0, yymsp[-3].minor.yy384, yymsp[0].minor.yy314);
    + }
    +         break;
    +-      case 178: /* insert_cmd ::= INSERT orconf */
    +-{yygotominor.yy186 = yymsp[0].minor.yy186;}
    ++      case 142: /* cmd ::= with insert_cmd INTO fullname idlist_opt select */
    ++{
    ++  sqlite3WithPush(pParse, yymsp[-5].minor.yy451, 1);
    ++  sqlite3Insert(pParse, yymsp[-2].minor.yy259, yymsp[0].minor.yy387, yymsp[-1].minor.yy384, yymsp[-4].minor.yy4);
    ++}
    +         break;
    +-      case 179: /* insert_cmd ::= REPLACE */
    +-{yygotominor.yy186 = OE_Replace;}
    ++      case 143: /* cmd ::= with insert_cmd INTO fullname idlist_opt DEFAULT VALUES */
    ++{
    ++  sqlite3WithPush(pParse, yymsp[-6].minor.yy451, 1);
    ++  sqlite3Insert(pParse, yymsp[-3].minor.yy259, 0, yymsp[-2].minor.yy384, yymsp[-5].minor.yy4);
    ++}
    +         break;
    +-      case 182: /* idlist ::= idlist COMMA nm */
    +-{yygotominor.yy408 = sqlite3IdListAppend(pParse->db,yymsp[-2].minor.yy408,&yymsp[0].minor.yy0);}
    ++      case 147: /* idlist_opt ::= LP idlist RP */
    ++{yymsp[-2].minor.yy384 = yymsp[-1].minor.yy384;}
    +         break;
    +-      case 183: /* idlist ::= nm */
    +-{yygotominor.yy408 = sqlite3IdListAppend(pParse->db,0,&yymsp[0].minor.yy0);}
    ++      case 148: /* idlist ::= idlist COMMA nm */
    ++{yymsp[-2].minor.yy384 = sqlite3IdListAppend(pParse->db,yymsp[-2].minor.yy384,&yymsp[0].minor.yy0);}
    +         break;
    +-      case 184: /* expr ::= term */
    +-{yygotominor.yy346 = yymsp[0].minor.yy346;}
    ++      case 149: /* idlist ::= nm */
    ++{yymsp[0].minor.yy384 = sqlite3IdListAppend(pParse->db,0,&yymsp[0].minor.yy0); /*A-overwrites-Y*/}
    +         break;
    +-      case 185: /* expr ::= LP expr RP */
    +-{yygotominor.yy346.pExpr = yymsp[-1].minor.yy346.pExpr; spanSet(&yygotominor.yy346,&yymsp[-2].minor.yy0,&yymsp[0].minor.yy0);}
    ++      case 150: /* expr ::= LP expr RP */
    ++{yymsp[-2].minor.yy314 = yymsp[-1].minor.yy314;}
    +         break;
    +-      case 186: /* term ::= NULL */
    +-      case 191: /* term ::= INTEGER|FLOAT|BLOB */ yytestcase(yyruleno==191);
    +-      case 192: /* term ::= STRING */ yytestcase(yyruleno==192);
    +-{spanExpr(&yygotominor.yy346, pParse, yymsp[0].major, &yymsp[0].minor.yy0);}
    ++      case 151: /* expr ::= ID|INDEXED */
    ++      case 152: /* expr ::= JOIN_KW */ yytestcase(yyruleno==152);
    ++{yymsp[0].minor.yy314=tokenExpr(pParse,TK_ID,yymsp[0].minor.yy0); /*A-overwrites-X*/}
    +         break;
    +-      case 187: /* expr ::= ID|INDEXED */
    +-      case 188: /* expr ::= JOIN_KW */ yytestcase(yyruleno==188);
    +-{spanExpr(&yygotominor.yy346, pParse, TK_ID, &yymsp[0].minor.yy0);}
    ++      case 153: /* expr ::= nm DOT nm */
    ++{
    ++  Expr *temp1 = sqlite3ExprAlloc(pParse->db, TK_ID, &yymsp[-2].minor.yy0, 1);
    ++  Expr *temp2 = sqlite3ExprAlloc(pParse->db, TK_ID, &yymsp[0].minor.yy0, 1);
    ++  yylhsminor.yy314 = sqlite3PExpr(pParse, TK_DOT, temp1, temp2);
    ++}
    ++  yymsp[-2].minor.yy314 = yylhsminor.yy314;
    +         break;
    +-      case 189: /* expr ::= nm DOT nm */
    ++      case 154: /* expr ::= nm DOT nm DOT nm */
    + {
    +-  Expr *temp1 = sqlite3PExpr(pParse, TK_ID, 0, 0, &yymsp[-2].minor.yy0);
    +-  Expr *temp2 = sqlite3PExpr(pParse, TK_ID, 0, 0, &yymsp[0].minor.yy0);
    +-  yygotominor.yy346.pExpr = sqlite3PExpr(pParse, TK_DOT, temp1, temp2, 0);
    +-  spanSet(&yygotominor.yy346,&yymsp[-2].minor.yy0,&yymsp[0].minor.yy0);
    ++  Expr *temp1 = sqlite3ExprAlloc(pParse->db, TK_ID, &yymsp[-4].minor.yy0, 1);
    ++  Expr *temp2 = sqlite3ExprAlloc(pParse->db, TK_ID, &yymsp[-2].minor.yy0, 1);
    ++  Expr *temp3 = sqlite3ExprAlloc(pParse->db, TK_ID, &yymsp[0].minor.yy0, 1);
    ++  Expr *temp4 = sqlite3PExpr(pParse, TK_DOT, temp2, temp3);
    ++  yylhsminor.yy314 = sqlite3PExpr(pParse, TK_DOT, temp1, temp4);
    + }
    ++  yymsp[-4].minor.yy314 = yylhsminor.yy314;
    ++        break;
    ++      case 155: /* term ::= NULL|FLOAT|BLOB */
    ++      case 156: /* term ::= STRING */ yytestcase(yyruleno==156);
    ++{yymsp[0].minor.yy314=tokenExpr(pParse,yymsp[0].major,yymsp[0].minor.yy0); /*A-overwrites-X*/}
    +         break;
    +-      case 190: /* expr ::= nm DOT nm DOT nm */
    ++      case 157: /* term ::= INTEGER */
    + {
    +-  Expr *temp1 = sqlite3PExpr(pParse, TK_ID, 0, 0, &yymsp[-4].minor.yy0);
    +-  Expr *temp2 = sqlite3PExpr(pParse, TK_ID, 0, 0, &yymsp[-2].minor.yy0);
    +-  Expr *temp3 = sqlite3PExpr(pParse, TK_ID, 0, 0, &yymsp[0].minor.yy0);
    +-  Expr *temp4 = sqlite3PExpr(pParse, TK_DOT, temp2, temp3, 0);
    +-  yygotominor.yy346.pExpr = sqlite3PExpr(pParse, TK_DOT, temp1, temp4, 0);
    +-  spanSet(&yygotominor.yy346,&yymsp[-4].minor.yy0,&yymsp[0].minor.yy0);
    ++  yylhsminor.yy314 = sqlite3ExprAlloc(pParse->db, TK_INTEGER, &yymsp[0].minor.yy0, 1);
    + }
    ++  yymsp[0].minor.yy314 = yylhsminor.yy314;
    +         break;
    +-      case 193: /* expr ::= VARIABLE */
    ++      case 158: /* expr ::= VARIABLE */
    + {
    +-  if( yymsp[0].minor.yy0.n>=2 && yymsp[0].minor.yy0.z[0]=='#' && sqlite3Isdigit(yymsp[0].minor.yy0.z[1]) ){
    ++  if( !(yymsp[0].minor.yy0.z[0]=='#' && sqlite3Isdigit(yymsp[0].minor.yy0.z[1])) ){
    ++    u32 n = yymsp[0].minor.yy0.n;
    ++    yymsp[0].minor.yy314 = tokenExpr(pParse, TK_VARIABLE, yymsp[0].minor.yy0);
    ++    sqlite3ExprAssignVarNumber(pParse, yymsp[0].minor.yy314, n);
    ++  }else{
    +     /* When doing a nested parse, one can include terms in an expression
    +     ** that look like this:   #1 #2 ...  These terms refer to registers
    +     ** in the virtual machine.  #N is the N-th register. */
    ++    Token t = yymsp[0].minor.yy0; /*A-overwrites-X*/
    ++    assert( t.n>=2 );
    +     if( pParse->nested==0 ){
    +-      sqlite3ErrorMsg(pParse, "near \"%T\": syntax error", &yymsp[0].minor.yy0);
    +-      yygotominor.yy346.pExpr = 0;
    ++      sqlite3ErrorMsg(pParse, "near \"%T\": syntax error", &t);
    ++      yymsp[0].minor.yy314 = 0;
    +     }else{
    +-      yygotominor.yy346.pExpr = sqlite3PExpr(pParse, TK_REGISTER, 0, 0, &yymsp[0].minor.yy0);
    +-      if( yygotominor.yy346.pExpr ) sqlite3GetInt32(&yymsp[0].minor.yy0.z[1], &yygotominor.yy346.pExpr->iTable);
    ++      yymsp[0].minor.yy314 = sqlite3PExpr(pParse, TK_REGISTER, 0, 0);
    ++      if( yymsp[0].minor.yy314 ) sqlite3GetInt32(&t.z[1], &yymsp[0].minor.yy314->iTable);
    +     }
    +-  }else{
    +-    spanExpr(&yygotominor.yy346, pParse, TK_VARIABLE, &yymsp[0].minor.yy0);
    +-    sqlite3ExprAssignVarNumber(pParse, yygotominor.yy346.pExpr);
    +   }
    +-  spanSet(&yygotominor.yy346, &yymsp[0].minor.yy0, &yymsp[0].minor.yy0);
    + }
    +         break;
    +-      case 194: /* expr ::= expr COLLATE ID|STRING */
    ++      case 159: /* expr ::= expr COLLATE ID|STRING */
    + {
    +-  yygotominor.yy346.pExpr = sqlite3ExprAddCollateToken(pParse, yymsp[-2].minor.yy346.pExpr, &yymsp[0].minor.yy0, 1);
    +-  yygotominor.yy346.zStart = yymsp[-2].minor.yy346.zStart;
    +-  yygotominor.yy346.zEnd = &yymsp[0].minor.yy0.z[yymsp[0].minor.yy0.n];
    ++  yymsp[-2].minor.yy314 = sqlite3ExprAddCollateToken(pParse, yymsp[-2].minor.yy314, &yymsp[0].minor.yy0, 1);
    + }
    +         break;
    +-      case 195: /* expr ::= CAST LP expr AS typetoken RP */
    ++      case 160: /* expr ::= CAST LP expr AS typetoken RP */
    + {
    +-  yygotominor.yy346.pExpr = sqlite3PExpr(pParse, TK_CAST, yymsp[-3].minor.yy346.pExpr, 0, &yymsp[-1].minor.yy0);
    +-  spanSet(&yygotominor.yy346,&yymsp[-5].minor.yy0,&yymsp[0].minor.yy0);
    ++  yymsp[-5].minor.yy314 = sqlite3ExprAlloc(pParse->db, TK_CAST, &yymsp[-1].minor.yy0, 1);
    ++  sqlite3ExprAttachSubtrees(pParse->db, yymsp[-5].minor.yy314, yymsp[-3].minor.yy314, 0);
    + }
    +         break;
    +-      case 196: /* expr ::= ID|INDEXED LP distinct exprlist RP */
    ++      case 161: /* expr ::= ID|INDEXED LP distinct exprlist RP */
    + {
    +-  if( yymsp[-1].minor.yy14 && yymsp[-1].minor.yy14->nExpr>pParse->db->aLimit[SQLITE_LIMIT_FUNCTION_ARG] ){
    ++  if( yymsp[-1].minor.yy322 && yymsp[-1].minor.yy322->nExpr>pParse->db->aLimit[SQLITE_LIMIT_FUNCTION_ARG] ){
    +     sqlite3ErrorMsg(pParse, "too many arguments on function %T", &yymsp[-4].minor.yy0);
    +   }
    +-  yygotominor.yy346.pExpr = sqlite3ExprFunction(pParse, yymsp[-1].minor.yy14, &yymsp[-4].minor.yy0);
    +-  spanSet(&yygotominor.yy346,&yymsp[-4].minor.yy0,&yymsp[0].minor.yy0);
    +-  if( yymsp[-2].minor.yy381==SF_Distinct && yygotominor.yy346.pExpr ){
    +-    yygotominor.yy346.pExpr->flags |= EP_Distinct;
    ++  yylhsminor.yy314 = sqlite3ExprFunction(pParse, yymsp[-1].minor.yy322, &yymsp[-4].minor.yy0);
    ++  if( yymsp[-2].minor.yy4==SF_Distinct && yylhsminor.yy314 ){
    ++    yylhsminor.yy314->flags |= EP_Distinct;
    +   }
    + }
    ++  yymsp[-4].minor.yy314 = yylhsminor.yy314;
    +         break;
    +-      case 197: /* expr ::= ID|INDEXED LP STAR RP */
    ++      case 162: /* expr ::= ID|INDEXED LP STAR RP */
    + {
    +-  yygotominor.yy346.pExpr = sqlite3ExprFunction(pParse, 0, &yymsp[-3].minor.yy0);
    +-  spanSet(&yygotominor.yy346,&yymsp[-3].minor.yy0,&yymsp[0].minor.yy0);
    ++  yylhsminor.yy314 = sqlite3ExprFunction(pParse, 0, &yymsp[-3].minor.yy0);
    + }
    ++  yymsp[-3].minor.yy314 = yylhsminor.yy314;
    +         break;
    +-      case 198: /* term ::= CTIME_KW */
    ++      case 163: /* term ::= CTIME_KW */
    + {
    +-  yygotominor.yy346.pExpr = sqlite3ExprFunction(pParse, 0, &yymsp[0].minor.yy0);
    +-  spanSet(&yygotominor.yy346, &yymsp[0].minor.yy0, &yymsp[0].minor.yy0);
    ++  yylhsminor.yy314 = sqlite3ExprFunction(pParse, 0, &yymsp[0].minor.yy0);
    + }
    ++  yymsp[0].minor.yy314 = yylhsminor.yy314;
    +         break;
    +-      case 199: /* expr ::= expr AND expr */
    +-      case 200: /* expr ::= expr OR expr */ yytestcase(yyruleno==200);
    +-      case 201: /* expr ::= expr LT|GT|GE|LE expr */ yytestcase(yyruleno==201);
    +-      case 202: /* expr ::= expr EQ|NE expr */ yytestcase(yyruleno==202);
    +-      case 203: /* expr ::= expr BITAND|BITOR|LSHIFT|RSHIFT expr */ yytestcase(yyruleno==203);
    +-      case 204: /* expr ::= expr PLUS|MINUS expr */ yytestcase(yyruleno==204);
    +-      case 205: /* expr ::= expr STAR|SLASH|REM expr */ yytestcase(yyruleno==205);
    +-      case 206: /* expr ::= expr CONCAT expr */ yytestcase(yyruleno==206);
    +-{spanBinaryExpr(&yygotominor.yy346,pParse,yymsp[-1].major,&yymsp[-2].minor.yy346,&yymsp[0].minor.yy346);}
    ++      case 164: /* expr ::= LP nexprlist COMMA expr RP */
    ++{
    ++  ExprList *pList = sqlite3ExprListAppend(pParse, yymsp[-3].minor.yy322, yymsp[-1].minor.yy314);
    ++  yymsp[-4].minor.yy314 = sqlite3PExpr(pParse, TK_VECTOR, 0, 0);
    ++  if( yymsp[-4].minor.yy314 ){
    ++    yymsp[-4].minor.yy314->x.pList = pList;
    ++  }else{
    ++    sqlite3ExprListDelete(pParse->db, pList);
    ++  }
    ++}
    +         break;
    +-      case 207: /* likeop ::= LIKE_KW|MATCH */
    +-{yygotominor.yy96.eOperator = yymsp[0].minor.yy0; yygotominor.yy96.bNot = 0;}
    ++      case 165: /* expr ::= expr AND expr */
    ++      case 166: /* expr ::= expr OR expr */ yytestcase(yyruleno==166);
    ++      case 167: /* expr ::= expr LT|GT|GE|LE expr */ yytestcase(yyruleno==167);
    ++      case 168: /* expr ::= expr EQ|NE expr */ yytestcase(yyruleno==168);
    ++      case 169: /* expr ::= expr BITAND|BITOR|LSHIFT|RSHIFT expr */ yytestcase(yyruleno==169);
    ++      case 170: /* expr ::= expr PLUS|MINUS expr */ yytestcase(yyruleno==170);
    ++      case 171: /* expr ::= expr STAR|SLASH|REM expr */ yytestcase(yyruleno==171);
    ++      case 172: /* expr ::= expr CONCAT expr */ yytestcase(yyruleno==172);
    ++{yymsp[-2].minor.yy314=sqlite3PExpr(pParse,yymsp[-1].major,yymsp[-2].minor.yy314,yymsp[0].minor.yy314);}
    +         break;
    +-      case 208: /* likeop ::= NOT LIKE_KW|MATCH */
    +-{yygotominor.yy96.eOperator = yymsp[0].minor.yy0; yygotominor.yy96.bNot = 1;}
    ++      case 173: /* likeop ::= NOT LIKE_KW|MATCH */
    ++{yymsp[-1].minor.yy0=yymsp[0].minor.yy0; yymsp[-1].minor.yy0.n|=0x80000000; /*yymsp[-1].minor.yy0-overwrite-yymsp[0].minor.yy0*/}
    +         break;
    +-      case 209: /* expr ::= expr likeop expr */
    ++      case 174: /* expr ::= expr likeop expr */
    + {
    +   ExprList *pList;
    +-  pList = sqlite3ExprListAppend(pParse,0, yymsp[0].minor.yy346.pExpr);
    +-  pList = sqlite3ExprListAppend(pParse,pList, yymsp[-2].minor.yy346.pExpr);
    +-  yygotominor.yy346.pExpr = sqlite3ExprFunction(pParse, pList, &yymsp[-1].minor.yy96.eOperator);
    +-  if( yymsp[-1].minor.yy96.bNot ) yygotominor.yy346.pExpr = sqlite3PExpr(pParse, TK_NOT, yygotominor.yy346.pExpr, 0, 0);
    +-  yygotominor.yy346.zStart = yymsp[-2].minor.yy346.zStart;
    +-  yygotominor.yy346.zEnd = yymsp[0].minor.yy346.zEnd;
    +-  if( yygotominor.yy346.pExpr ) yygotominor.yy346.pExpr->flags |= EP_InfixFunc;
    ++  int bNot = yymsp[-1].minor.yy0.n & 0x80000000;
    ++  yymsp[-1].minor.yy0.n &= 0x7fffffff;
    ++  pList = sqlite3ExprListAppend(pParse,0, yymsp[0].minor.yy314);
    ++  pList = sqlite3ExprListAppend(pParse,pList, yymsp[-2].minor.yy314);
    ++  yymsp[-2].minor.yy314 = sqlite3ExprFunction(pParse, pList, &yymsp[-1].minor.yy0);
    ++  if( bNot ) yymsp[-2].minor.yy314 = sqlite3PExpr(pParse, TK_NOT, yymsp[-2].minor.yy314, 0);
    ++  if( yymsp[-2].minor.yy314 ) yymsp[-2].minor.yy314->flags |= EP_InfixFunc;
    + }
    +         break;
    +-      case 210: /* expr ::= expr likeop expr ESCAPE expr */
    ++      case 175: /* expr ::= expr likeop expr ESCAPE expr */
    + {
    +   ExprList *pList;
    +-  pList = sqlite3ExprListAppend(pParse,0, yymsp[-2].minor.yy346.pExpr);
    +-  pList = sqlite3ExprListAppend(pParse,pList, yymsp[-4].minor.yy346.pExpr);
    +-  pList = sqlite3ExprListAppend(pParse,pList, yymsp[0].minor.yy346.pExpr);
    +-  yygotominor.yy346.pExpr = sqlite3ExprFunction(pParse, pList, &yymsp[-3].minor.yy96.eOperator);
    +-  if( yymsp[-3].minor.yy96.bNot ) yygotominor.yy346.pExpr = sqlite3PExpr(pParse, TK_NOT, yygotominor.yy346.pExpr, 0, 0);
    +-  yygotominor.yy346.zStart = yymsp[-4].minor.yy346.zStart;
    +-  yygotominor.yy346.zEnd = yymsp[0].minor.yy346.zEnd;
    +-  if( yygotominor.yy346.pExpr ) yygotominor.yy346.pExpr->flags |= EP_InfixFunc;
    ++  int bNot = yymsp[-3].minor.yy0.n & 0x80000000;
    ++  yymsp[-3].minor.yy0.n &= 0x7fffffff;
    ++  pList = sqlite3ExprListAppend(pParse,0, yymsp[-2].minor.yy314);
    ++  pList = sqlite3ExprListAppend(pParse,pList, yymsp[-4].minor.yy314);
    ++  pList = sqlite3ExprListAppend(pParse,pList, yymsp[0].minor.yy314);
    ++  yymsp[-4].minor.yy314 = sqlite3ExprFunction(pParse, pList, &yymsp[-3].minor.yy0);
    ++  if( bNot ) yymsp[-4].minor.yy314 = sqlite3PExpr(pParse, TK_NOT, yymsp[-4].minor.yy314, 0);
    ++  if( yymsp[-4].minor.yy314 ) yymsp[-4].minor.yy314->flags |= EP_InfixFunc;
    + }
    +         break;
    +-      case 211: /* expr ::= expr ISNULL|NOTNULL */
    +-{spanUnaryPostfix(&yygotominor.yy346,pParse,yymsp[0].major,&yymsp[-1].minor.yy346,&yymsp[0].minor.yy0);}
    ++      case 176: /* expr ::= expr ISNULL|NOTNULL */
    ++{yymsp[-1].minor.yy314 = sqlite3PExpr(pParse,yymsp[0].major,yymsp[-1].minor.yy314,0);}
    +         break;
    +-      case 212: /* expr ::= expr NOT NULL */
    +-{spanUnaryPostfix(&yygotominor.yy346,pParse,TK_NOTNULL,&yymsp[-2].minor.yy346,&yymsp[0].minor.yy0);}
    ++      case 177: /* expr ::= expr NOT NULL */
    ++{yymsp[-2].minor.yy314 = sqlite3PExpr(pParse,TK_NOTNULL,yymsp[-2].minor.yy314,0);}
    +         break;
    +-      case 213: /* expr ::= expr IS expr */
    ++      case 178: /* expr ::= expr IS expr */
    + {
    +-  spanBinaryExpr(&yygotominor.yy346,pParse,TK_IS,&yymsp[-2].minor.yy346,&yymsp[0].minor.yy346);
    +-  binaryToUnaryIfNull(pParse, yymsp[0].minor.yy346.pExpr, yygotominor.yy346.pExpr, TK_ISNULL);
    ++  yymsp[-2].minor.yy314 = sqlite3PExpr(pParse,TK_IS,yymsp[-2].minor.yy314,yymsp[0].minor.yy314);
    ++  binaryToUnaryIfNull(pParse, yymsp[0].minor.yy314, yymsp[-2].minor.yy314, TK_ISNULL);
    + }
    +         break;
    +-      case 214: /* expr ::= expr IS NOT expr */
    ++      case 179: /* expr ::= expr IS NOT expr */
    + {
    +-  spanBinaryExpr(&yygotominor.yy346,pParse,TK_ISNOT,&yymsp[-3].minor.yy346,&yymsp[0].minor.yy346);
    +-  binaryToUnaryIfNull(pParse, yymsp[0].minor.yy346.pExpr, yygotominor.yy346.pExpr, TK_NOTNULL);
    ++  yymsp[-3].minor.yy314 = sqlite3PExpr(pParse,TK_ISNOT,yymsp[-3].minor.yy314,yymsp[0].minor.yy314);
    ++  binaryToUnaryIfNull(pParse, yymsp[0].minor.yy314, yymsp[-3].minor.yy314, TK_NOTNULL);
    + }
    +         break;
    +-      case 215: /* expr ::= NOT expr */
    +-      case 216: /* expr ::= BITNOT expr */ yytestcase(yyruleno==216);
    +-{spanUnaryPrefix(&yygotominor.yy346,pParse,yymsp[-1].major,&yymsp[0].minor.yy346,&yymsp[-1].minor.yy0);}
    ++      case 180: /* expr ::= NOT expr */
    ++      case 181: /* expr ::= BITNOT expr */ yytestcase(yyruleno==181);
    ++{yymsp[-1].minor.yy314 = sqlite3PExpr(pParse, yymsp[-1].major, yymsp[0].minor.yy314, 0);/*A-overwrites-B*/}
    ++        break;
    ++      case 182: /* expr ::= MINUS expr */
    ++{yymsp[-1].minor.yy314 = sqlite3PExpr(pParse, TK_UMINUS, yymsp[0].minor.yy314, 0);}
    +         break;
    +-      case 217: /* expr ::= MINUS expr */
    +-{spanUnaryPrefix(&yygotominor.yy346,pParse,TK_UMINUS,&yymsp[0].minor.yy346,&yymsp[-1].minor.yy0);}
    ++      case 183: /* expr ::= PLUS expr */
    ++{yymsp[-1].minor.yy314 = sqlite3PExpr(pParse, TK_UPLUS, yymsp[0].minor.yy314, 0);}
    +         break;
    +-      case 218: /* expr ::= PLUS expr */
    +-{spanUnaryPrefix(&yygotominor.yy346,pParse,TK_UPLUS,&yymsp[0].minor.yy346,&yymsp[-1].minor.yy0);}
    ++      case 184: /* between_op ::= BETWEEN */
    ++      case 187: /* in_op ::= IN */ yytestcase(yyruleno==187);
    ++{yymsp[0].minor.yy4 = 0;}
    +         break;
    +-      case 221: /* expr ::= expr between_op expr AND expr */
    ++      case 186: /* expr ::= expr between_op expr AND expr */
    + {
    +-  ExprList *pList = sqlite3ExprListAppend(pParse,0, yymsp[-2].minor.yy346.pExpr);
    +-  pList = sqlite3ExprListAppend(pParse,pList, yymsp[0].minor.yy346.pExpr);
    +-  yygotominor.yy346.pExpr = sqlite3PExpr(pParse, TK_BETWEEN, yymsp[-4].minor.yy346.pExpr, 0, 0);
    +-  if( yygotominor.yy346.pExpr ){
    +-    yygotominor.yy346.pExpr->x.pList = pList;
    ++  ExprList *pList = sqlite3ExprListAppend(pParse,0, yymsp[-2].minor.yy314);
    ++  pList = sqlite3ExprListAppend(pParse,pList, yymsp[0].minor.yy314);
    ++  yymsp[-4].minor.yy314 = sqlite3PExpr(pParse, TK_BETWEEN, yymsp[-4].minor.yy314, 0);
    ++  if( yymsp[-4].minor.yy314 ){
    ++    yymsp[-4].minor.yy314->x.pList = pList;
    +   }else{
    +     sqlite3ExprListDelete(pParse->db, pList);
    +   } 
    +-  if( yymsp[-3].minor.yy328 ) yygotominor.yy346.pExpr = sqlite3PExpr(pParse, TK_NOT, yygotominor.yy346.pExpr, 0, 0);
    +-  yygotominor.yy346.zStart = yymsp[-4].minor.yy346.zStart;
    +-  yygotominor.yy346.zEnd = yymsp[0].minor.yy346.zEnd;
    ++  if( yymsp[-3].minor.yy4 ) yymsp[-4].minor.yy314 = sqlite3PExpr(pParse, TK_NOT, yymsp[-4].minor.yy314, 0);
    + }
    +         break;
    +-      case 224: /* expr ::= expr in_op LP exprlist RP */
    ++      case 189: /* expr ::= expr in_op LP exprlist RP */
    + {
    +-    if( yymsp[-1].minor.yy14==0 ){
    ++    if( yymsp[-1].minor.yy322==0 ){
    +       /* Expressions of the form
    +       **
    +       **      expr1 IN ()
    +@@ -128936,9 +141371,9 @@ static void yy_reduce(
    +       ** simplify to constants 0 (false) and 1 (true), respectively,
    +       ** regardless of the value of expr1.
    +       */
    +-      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 ){
    ++      sqlite3ExprDelete(pParse->db, yymsp[-4].minor.yy314);
    ++      yymsp[-4].minor.yy314 = sqlite3ExprAlloc(pParse->db, TK_INTEGER,&sqlite3IntTokens[yymsp[-3].minor.yy4],1);
    ++    }else if( yymsp[-1].minor.yy322->nExpr==1 ){
    +       /* Expressions of the form:
    +       **
    +       **      expr1 IN (?1)
    +@@ -128955,423 +141390,414 @@ static void yy_reduce(
    +       ** 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);
    ++      Expr *pRHS = yymsp[-1].minor.yy322->a[0].pExpr;
    ++      yymsp[-1].minor.yy322->a[0].pExpr = 0;
    ++      sqlite3ExprListDelete(pParse->db, yymsp[-1].minor.yy322);
    +       /* 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);
    ++      yymsp[-4].minor.yy314 = sqlite3PExpr(pParse, yymsp[-3].minor.yy4 ? TK_NE : TK_EQ, yymsp[-4].minor.yy314, pRHS);
    +     }else{
    +-      yygotominor.yy346.pExpr = sqlite3PExpr(pParse, TK_IN, yymsp[-4].minor.yy346.pExpr, 0, 0);
    +-      if( yygotominor.yy346.pExpr ){
    +-        yygotominor.yy346.pExpr->x.pList = yymsp[-1].minor.yy14;
    +-        sqlite3ExprSetHeightAndFlags(pParse, yygotominor.yy346.pExpr);
    ++      yymsp[-4].minor.yy314 = sqlite3PExpr(pParse, TK_IN, yymsp[-4].minor.yy314, 0);
    ++      if( yymsp[-4].minor.yy314 ){
    ++        yymsp[-4].minor.yy314->x.pList = yymsp[-1].minor.yy322;
    ++        sqlite3ExprSetHeightAndFlags(pParse, yymsp[-4].minor.yy314);
    +       }else{
    +-        sqlite3ExprListDelete(pParse->db, yymsp[-1].minor.yy14);
    ++        sqlite3ExprListDelete(pParse->db, yymsp[-1].minor.yy322);
    +       }
    +-      if( yymsp[-3].minor.yy328 ) yygotominor.yy346.pExpr = sqlite3PExpr(pParse, TK_NOT, yygotominor.yy346.pExpr, 0, 0);
    ++      if( yymsp[-3].minor.yy4 ) yymsp[-4].minor.yy314 = sqlite3PExpr(pParse, TK_NOT, yymsp[-4].minor.yy314, 0);
    +     }
    +-    yygotominor.yy346.zStart = yymsp[-4].minor.yy346.zStart;
    +-    yygotominor.yy346.zEnd = &yymsp[0].minor.yy0.z[yymsp[0].minor.yy0.n];
    +   }
    +         break;
    +-      case 225: /* expr ::= LP select RP */
    ++      case 190: /* expr ::= LP select RP */
    + {
    +-    yygotominor.yy346.pExpr = sqlite3PExpr(pParse, TK_SELECT, 0, 0, 0);
    +-    if( yygotominor.yy346.pExpr ){
    +-      yygotominor.yy346.pExpr->x.pSelect = yymsp[-1].minor.yy3;
    +-      ExprSetProperty(yygotominor.yy346.pExpr, EP_xIsSelect|EP_Subquery);
    +-      sqlite3ExprSetHeightAndFlags(pParse, yygotominor.yy346.pExpr);
    +-    }else{
    +-      sqlite3SelectDelete(pParse->db, yymsp[-1].minor.yy3);
    +-    }
    +-    yygotominor.yy346.zStart = yymsp[-2].minor.yy0.z;
    +-    yygotominor.yy346.zEnd = &yymsp[0].minor.yy0.z[yymsp[0].minor.yy0.n];
    ++    yymsp[-2].minor.yy314 = sqlite3PExpr(pParse, TK_SELECT, 0, 0);
    ++    sqlite3PExprAddSelect(pParse, yymsp[-2].minor.yy314, yymsp[-1].minor.yy387);
    +   }
    +         break;
    +-      case 226: /* expr ::= expr in_op LP select RP */
    ++      case 191: /* expr ::= expr in_op LP select RP */
    + {
    +-    yygotominor.yy346.pExpr = sqlite3PExpr(pParse, TK_IN, yymsp[-4].minor.yy346.pExpr, 0, 0);
    +-    if( yygotominor.yy346.pExpr ){
    +-      yygotominor.yy346.pExpr->x.pSelect = yymsp[-1].minor.yy3;
    +-      ExprSetProperty(yygotominor.yy346.pExpr, EP_xIsSelect|EP_Subquery);
    +-      sqlite3ExprSetHeightAndFlags(pParse, yygotominor.yy346.pExpr);
    +-    }else{
    +-      sqlite3SelectDelete(pParse->db, yymsp[-1].minor.yy3);
    +-    }
    +-    if( yymsp[-3].minor.yy328 ) yygotominor.yy346.pExpr = sqlite3PExpr(pParse, TK_NOT, yygotominor.yy346.pExpr, 0, 0);
    +-    yygotominor.yy346.zStart = yymsp[-4].minor.yy346.zStart;
    +-    yygotominor.yy346.zEnd = &yymsp[0].minor.yy0.z[yymsp[0].minor.yy0.n];
    ++    yymsp[-4].minor.yy314 = sqlite3PExpr(pParse, TK_IN, yymsp[-4].minor.yy314, 0);
    ++    sqlite3PExprAddSelect(pParse, yymsp[-4].minor.yy314, yymsp[-1].minor.yy387);
    ++    if( yymsp[-3].minor.yy4 ) yymsp[-4].minor.yy314 = sqlite3PExpr(pParse, TK_NOT, yymsp[-4].minor.yy314, 0);
    +   }
    +         break;
    +-      case 227: /* expr ::= expr in_op nm dbnm */
    ++      case 192: /* expr ::= expr in_op nm dbnm paren_exprlist */
    + {
    +-    SrcList *pSrc = sqlite3SrcListAppend(pParse->db, 0,&yymsp[-1].minor.yy0,&yymsp[0].minor.yy0);
    +-    yygotominor.yy346.pExpr = sqlite3PExpr(pParse, TK_IN, yymsp[-3].minor.yy346.pExpr, 0, 0);
    +-    if( yygotominor.yy346.pExpr ){
    +-      yygotominor.yy346.pExpr->x.pSelect = sqlite3SelectNew(pParse, 0,pSrc,0,0,0,0,0,0,0);
    +-      ExprSetProperty(yygotominor.yy346.pExpr, EP_xIsSelect|EP_Subquery);
    +-      sqlite3ExprSetHeightAndFlags(pParse, yygotominor.yy346.pExpr);
    +-    }else{
    +-      sqlite3SrcListDelete(pParse->db, pSrc);
    +-    }
    +-    if( yymsp[-2].minor.yy328 ) yygotominor.yy346.pExpr = sqlite3PExpr(pParse, TK_NOT, yygotominor.yy346.pExpr, 0, 0);
    +-    yygotominor.yy346.zStart = yymsp[-3].minor.yy346.zStart;
    +-    yygotominor.yy346.zEnd = yymsp[0].minor.yy0.z ? &yymsp[0].minor.yy0.z[yymsp[0].minor.yy0.n] : &yymsp[-1].minor.yy0.z[yymsp[-1].minor.yy0.n];
    ++    SrcList *pSrc = sqlite3SrcListAppend(pParse->db, 0,&yymsp[-2].minor.yy0,&yymsp[-1].minor.yy0);
    ++    Select *pSelect = sqlite3SelectNew(pParse, 0,pSrc,0,0,0,0,0,0);
    ++    if( yymsp[0].minor.yy322 )  sqlite3SrcListFuncArgs(pParse, pSelect ? pSrc : 0, yymsp[0].minor.yy322);
    ++    yymsp[-4].minor.yy314 = sqlite3PExpr(pParse, TK_IN, yymsp[-4].minor.yy314, 0);
    ++    sqlite3PExprAddSelect(pParse, yymsp[-4].minor.yy314, pSelect);
    ++    if( yymsp[-3].minor.yy4 ) yymsp[-4].minor.yy314 = sqlite3PExpr(pParse, TK_NOT, yymsp[-4].minor.yy314, 0);
    +   }
    +         break;
    +-      case 228: /* expr ::= EXISTS LP select RP */
    ++      case 193: /* expr ::= EXISTS LP select RP */
    + {
    +-    Expr *p = yygotominor.yy346.pExpr = sqlite3PExpr(pParse, TK_EXISTS, 0, 0, 0);
    +-    if( p ){
    +-      p->x.pSelect = yymsp[-1].minor.yy3;
    +-      ExprSetProperty(p, EP_xIsSelect|EP_Subquery);
    +-      sqlite3ExprSetHeightAndFlags(pParse, p);
    +-    }else{
    +-      sqlite3SelectDelete(pParse->db, yymsp[-1].minor.yy3);
    +-    }
    +-    yygotominor.yy346.zStart = yymsp[-3].minor.yy0.z;
    +-    yygotominor.yy346.zEnd = &yymsp[0].minor.yy0.z[yymsp[0].minor.yy0.n];
    ++    Expr *p;
    ++    p = yymsp[-3].minor.yy314 = sqlite3PExpr(pParse, TK_EXISTS, 0, 0);
    ++    sqlite3PExprAddSelect(pParse, p, yymsp[-1].minor.yy387);
    +   }
    +         break;
    +-      case 229: /* expr ::= CASE case_operand case_exprlist case_else END */
    ++      case 194: /* expr ::= CASE case_operand case_exprlist case_else END */
    + {
    +-  yygotominor.yy346.pExpr = sqlite3PExpr(pParse, TK_CASE, yymsp[-3].minor.yy132, 0, 0);
    +-  if( yygotominor.yy346.pExpr ){
    +-    yygotominor.yy346.pExpr->x.pList = yymsp[-1].minor.yy132 ? sqlite3ExprListAppend(pParse,yymsp[-2].minor.yy14,yymsp[-1].minor.yy132) : yymsp[-2].minor.yy14;
    +-    sqlite3ExprSetHeightAndFlags(pParse, yygotominor.yy346.pExpr);
    ++  yymsp[-4].minor.yy314 = sqlite3PExpr(pParse, TK_CASE, yymsp[-3].minor.yy314, 0);
    ++  if( yymsp[-4].minor.yy314 ){
    ++    yymsp[-4].minor.yy314->x.pList = yymsp[-1].minor.yy314 ? sqlite3ExprListAppend(pParse,yymsp[-2].minor.yy322,yymsp[-1].minor.yy314) : yymsp[-2].minor.yy322;
    ++    sqlite3ExprSetHeightAndFlags(pParse, yymsp[-4].minor.yy314);
    +   }else{
    +-    sqlite3ExprListDelete(pParse->db, yymsp[-2].minor.yy14);
    +-    sqlite3ExprDelete(pParse->db, yymsp[-1].minor.yy132);
    ++    sqlite3ExprListDelete(pParse->db, yymsp[-2].minor.yy322);
    ++    sqlite3ExprDelete(pParse->db, yymsp[-1].minor.yy314);
    +   }
    +-  yygotominor.yy346.zStart = yymsp[-4].minor.yy0.z;
    +-  yygotominor.yy346.zEnd = &yymsp[0].minor.yy0.z[yymsp[0].minor.yy0.n];
    + }
    +         break;
    +-      case 230: /* case_exprlist ::= case_exprlist WHEN expr THEN expr */
    ++      case 195: /* case_exprlist ::= case_exprlist WHEN expr THEN expr */
    + {
    +-  yygotominor.yy14 = sqlite3ExprListAppend(pParse,yymsp[-4].minor.yy14, yymsp[-2].minor.yy346.pExpr);
    +-  yygotominor.yy14 = sqlite3ExprListAppend(pParse,yygotominor.yy14, yymsp[0].minor.yy346.pExpr);
    ++  yymsp[-4].minor.yy322 = sqlite3ExprListAppend(pParse,yymsp[-4].minor.yy322, yymsp[-2].minor.yy314);
    ++  yymsp[-4].minor.yy322 = sqlite3ExprListAppend(pParse,yymsp[-4].minor.yy322, yymsp[0].minor.yy314);
    + }
    +         break;
    +-      case 231: /* case_exprlist ::= WHEN expr THEN expr */
    ++      case 196: /* case_exprlist ::= WHEN expr THEN expr */
    + {
    +-  yygotominor.yy14 = sqlite3ExprListAppend(pParse,0, yymsp[-2].minor.yy346.pExpr);
    +-  yygotominor.yy14 = sqlite3ExprListAppend(pParse,yygotominor.yy14, yymsp[0].minor.yy346.pExpr);
    ++  yymsp[-3].minor.yy322 = sqlite3ExprListAppend(pParse,0, yymsp[-2].minor.yy314);
    ++  yymsp[-3].minor.yy322 = sqlite3ExprListAppend(pParse,yymsp[-3].minor.yy322, yymsp[0].minor.yy314);
    + }
    +         break;
    +-      case 238: /* nexprlist ::= nexprlist COMMA expr */
    +-{yygotominor.yy14 = sqlite3ExprListAppend(pParse,yymsp[-2].minor.yy14,yymsp[0].minor.yy346.pExpr);}
    ++      case 199: /* case_operand ::= expr */
    ++{yymsp[0].minor.yy314 = yymsp[0].minor.yy314; /*A-overwrites-X*/}
    ++        break;
    ++      case 202: /* nexprlist ::= nexprlist COMMA expr */
    ++{yymsp[-2].minor.yy322 = sqlite3ExprListAppend(pParse,yymsp[-2].minor.yy322,yymsp[0].minor.yy314);}
    +         break;
    +-      case 239: /* nexprlist ::= expr */
    +-{yygotominor.yy14 = sqlite3ExprListAppend(pParse,0,yymsp[0].minor.yy346.pExpr);}
    ++      case 203: /* nexprlist ::= expr */
    ++{yymsp[0].minor.yy322 = sqlite3ExprListAppend(pParse,0,yymsp[0].minor.yy314); /*A-overwrites-Y*/}
    +         break;
    +-      case 240: /* cmd ::= createkw uniqueflag INDEX ifnotexists nm dbnm ON nm LP sortlist RP where_opt */
    ++      case 205: /* paren_exprlist ::= LP exprlist RP */
    ++      case 210: /* eidlist_opt ::= LP eidlist RP */ yytestcase(yyruleno==210);
    ++{yymsp[-2].minor.yy322 = yymsp[-1].minor.yy322;}
    ++        break;
    ++      case 206: /* cmd ::= createkw uniqueflag INDEX ifnotexists nm dbnm ON nm LP sortlist RP where_opt */
    + {
    +   sqlite3CreateIndex(pParse, &yymsp[-7].minor.yy0, &yymsp[-6].minor.yy0, 
    +-                     sqlite3SrcListAppend(pParse->db,0,&yymsp[-4].minor.yy0,0), yymsp[-2].minor.yy14, yymsp[-10].minor.yy328,
    +-                      &yymsp[-11].minor.yy0, yymsp[0].minor.yy132, SQLITE_SO_ASC, yymsp[-8].minor.yy328);
    ++                     sqlite3SrcListAppend(pParse->db,0,&yymsp[-4].minor.yy0,0), yymsp[-2].minor.yy322, yymsp[-10].minor.yy4,
    ++                      &yymsp[-11].minor.yy0, yymsp[0].minor.yy314, SQLITE_SO_ASC, yymsp[-8].minor.yy4, SQLITE_IDXTYPE_APPDEF);
    + }
    +         break;
    +-      case 241: /* uniqueflag ::= UNIQUE */
    +-      case 292: /* raisetype ::= ABORT */ yytestcase(yyruleno==292);
    +-{yygotominor.yy328 = OE_Abort;}
    ++      case 207: /* uniqueflag ::= UNIQUE */
    ++      case 247: /* raisetype ::= ABORT */ yytestcase(yyruleno==247);
    ++{yymsp[0].minor.yy4 = OE_Abort;}
    +         break;
    +-      case 242: /* uniqueflag ::= */
    +-{yygotominor.yy328 = OE_None;}
    ++      case 208: /* uniqueflag ::= */
    ++{yymsp[1].minor.yy4 = OE_None;}
    +         break;
    +-      case 245: /* eidlist ::= eidlist COMMA nm collate sortorder */
    ++      case 211: /* eidlist ::= eidlist COMMA nm collate sortorder */
    + {
    +-  yygotominor.yy14 = parserAddExprIdListTerm(pParse, yymsp[-4].minor.yy14, &yymsp[-2].minor.yy0, yymsp[-1].minor.yy328, yymsp[0].minor.yy328);
    ++  yymsp[-4].minor.yy322 = parserAddExprIdListTerm(pParse, yymsp[-4].minor.yy322, &yymsp[-2].minor.yy0, yymsp[-1].minor.yy4, yymsp[0].minor.yy4);
    + }
    +         break;
    +-      case 246: /* eidlist ::= nm collate sortorder */
    ++      case 212: /* eidlist ::= nm collate sortorder */
    + {
    +-  yygotominor.yy14 = parserAddExprIdListTerm(pParse, 0, &yymsp[-2].minor.yy0, yymsp[-1].minor.yy328, yymsp[0].minor.yy328);
    ++  yymsp[-2].minor.yy322 = parserAddExprIdListTerm(pParse, 0, &yymsp[-2].minor.yy0, yymsp[-1].minor.yy4, yymsp[0].minor.yy4); /*A-overwrites-Y*/
    + }
    +         break;
    +-      case 249: /* cmd ::= DROP INDEX ifexists fullname */
    +-{sqlite3DropIndex(pParse, yymsp[0].minor.yy65, yymsp[-1].minor.yy328);}
    ++      case 215: /* cmd ::= DROP INDEX ifexists fullname */
    ++{sqlite3DropIndex(pParse, yymsp[0].minor.yy259, yymsp[-1].minor.yy4);}
    ++        break;
    ++      case 216: /* cmd ::= VACUUM */
    ++{sqlite3Vacuum(pParse,0);}
    +         break;
    +-      case 250: /* cmd ::= VACUUM */
    +-      case 251: /* cmd ::= VACUUM nm */ yytestcase(yyruleno==251);
    +-{sqlite3Vacuum(pParse);}
    ++      case 217: /* cmd ::= VACUUM nm */
    ++{sqlite3Vacuum(pParse,&yymsp[0].minor.yy0);}
    +         break;
    +-      case 252: /* cmd ::= PRAGMA nm dbnm */
    ++      case 218: /* cmd ::= PRAGMA nm dbnm */
    + {sqlite3Pragma(pParse,&yymsp[-1].minor.yy0,&yymsp[0].minor.yy0,0,0);}
    +         break;
    +-      case 253: /* cmd ::= PRAGMA nm dbnm EQ nmnum */
    ++      case 219: /* cmd ::= PRAGMA nm dbnm EQ nmnum */
    + {sqlite3Pragma(pParse,&yymsp[-3].minor.yy0,&yymsp[-2].minor.yy0,&yymsp[0].minor.yy0,0);}
    +         break;
    +-      case 254: /* cmd ::= PRAGMA nm dbnm LP nmnum RP */
    ++      case 220: /* cmd ::= PRAGMA nm dbnm LP nmnum RP */
    + {sqlite3Pragma(pParse,&yymsp[-4].minor.yy0,&yymsp[-3].minor.yy0,&yymsp[-1].minor.yy0,0);}
    +         break;
    +-      case 255: /* cmd ::= PRAGMA nm dbnm EQ minus_num */
    ++      case 221: /* cmd ::= PRAGMA nm dbnm EQ minus_num */
    + {sqlite3Pragma(pParse,&yymsp[-3].minor.yy0,&yymsp[-2].minor.yy0,&yymsp[0].minor.yy0,1);}
    +         break;
    +-      case 256: /* cmd ::= PRAGMA nm dbnm LP minus_num RP */
    ++      case 222: /* cmd ::= PRAGMA nm dbnm LP minus_num RP */
    + {sqlite3Pragma(pParse,&yymsp[-4].minor.yy0,&yymsp[-3].minor.yy0,&yymsp[-1].minor.yy0,1);}
    +         break;
    +-      case 265: /* cmd ::= createkw trigger_decl BEGIN trigger_cmd_list END */
    ++      case 225: /* cmd ::= createkw trigger_decl BEGIN trigger_cmd_list END */
    + {
    +   Token all;
    +   all.z = yymsp[-3].minor.yy0.z;
    +   all.n = (int)(yymsp[0].minor.yy0.z - yymsp[-3].minor.yy0.z) + yymsp[0].minor.yy0.n;
    +-  sqlite3FinishTrigger(pParse, yymsp[-1].minor.yy473, &all);
    ++  sqlite3FinishTrigger(pParse, yymsp[-1].minor.yy203, &all);
    + }
    +         break;
    +-      case 266: /* trigger_decl ::= temp TRIGGER ifnotexists nm dbnm trigger_time trigger_event ON fullname foreach_clause when_clause */
    ++      case 226: /* trigger_decl ::= temp TRIGGER ifnotexists nm dbnm trigger_time trigger_event ON fullname foreach_clause when_clause */
    + {
    +-  sqlite3BeginTrigger(pParse, &yymsp[-7].minor.yy0, &yymsp[-6].minor.yy0, yymsp[-5].minor.yy328, yymsp[-4].minor.yy378.a, yymsp[-4].minor.yy378.b, yymsp[-2].minor.yy65, yymsp[0].minor.yy132, yymsp[-10].minor.yy328, yymsp[-8].minor.yy328);
    +-  yygotominor.yy0 = (yymsp[-6].minor.yy0.n==0?yymsp[-7].minor.yy0:yymsp[-6].minor.yy0);
    ++  sqlite3BeginTrigger(pParse, &yymsp[-7].minor.yy0, &yymsp[-6].minor.yy0, yymsp[-5].minor.yy4, yymsp[-4].minor.yy90.a, yymsp[-4].minor.yy90.b, yymsp[-2].minor.yy259, yymsp[0].minor.yy314, yymsp[-10].minor.yy4, yymsp[-8].minor.yy4);
    ++  yymsp[-10].minor.yy0 = (yymsp[-6].minor.yy0.n==0?yymsp[-7].minor.yy0:yymsp[-6].minor.yy0); /*A-overwrites-T*/
    + }
    +         break;
    +-      case 267: /* trigger_time ::= BEFORE */
    +-      case 270: /* trigger_time ::= */ yytestcase(yyruleno==270);
    +-{ yygotominor.yy328 = TK_BEFORE; }
    ++      case 227: /* trigger_time ::= BEFORE|AFTER */
    ++{ yymsp[0].minor.yy4 = yymsp[0].major; /*A-overwrites-X*/ }
    +         break;
    +-      case 268: /* trigger_time ::= AFTER */
    +-{ yygotominor.yy328 = TK_AFTER;  }
    ++      case 228: /* trigger_time ::= INSTEAD OF */
    ++{ yymsp[-1].minor.yy4 = TK_INSTEAD;}
    +         break;
    +-      case 269: /* trigger_time ::= INSTEAD OF */
    +-{ yygotominor.yy328 = TK_INSTEAD;}
    ++      case 229: /* trigger_time ::= */
    ++{ yymsp[1].minor.yy4 = TK_BEFORE; }
    +         break;
    +-      case 271: /* trigger_event ::= DELETE|INSERT */
    +-      case 272: /* trigger_event ::= UPDATE */ yytestcase(yyruleno==272);
    +-{yygotominor.yy378.a = yymsp[0].major; yygotominor.yy378.b = 0;}
    ++      case 230: /* trigger_event ::= DELETE|INSERT */
    ++      case 231: /* trigger_event ::= UPDATE */ yytestcase(yyruleno==231);
    ++{yymsp[0].minor.yy90.a = yymsp[0].major; /*A-overwrites-X*/ yymsp[0].minor.yy90.b = 0;}
    +         break;
    +-      case 273: /* trigger_event ::= UPDATE OF idlist */
    +-{yygotominor.yy378.a = TK_UPDATE; yygotominor.yy378.b = yymsp[0].minor.yy408;}
    ++      case 232: /* trigger_event ::= UPDATE OF idlist */
    ++{yymsp[-2].minor.yy90.a = TK_UPDATE; yymsp[-2].minor.yy90.b = yymsp[0].minor.yy384;}
    +         break;
    +-      case 276: /* when_clause ::= */
    +-      case 297: /* key_opt ::= */ yytestcase(yyruleno==297);
    +-{ yygotominor.yy132 = 0; }
    ++      case 233: /* when_clause ::= */
    ++      case 252: /* key_opt ::= */ yytestcase(yyruleno==252);
    ++{ yymsp[1].minor.yy314 = 0; }
    +         break;
    +-      case 277: /* when_clause ::= WHEN expr */
    +-      case 298: /* key_opt ::= KEY expr */ yytestcase(yyruleno==298);
    +-{ yygotominor.yy132 = yymsp[0].minor.yy346.pExpr; }
    ++      case 234: /* when_clause ::= WHEN expr */
    ++      case 253: /* key_opt ::= KEY expr */ yytestcase(yyruleno==253);
    ++{ yymsp[-1].minor.yy314 = yymsp[0].minor.yy314; }
    +         break;
    +-      case 278: /* trigger_cmd_list ::= trigger_cmd_list trigger_cmd SEMI */
    ++      case 235: /* trigger_cmd_list ::= trigger_cmd_list trigger_cmd SEMI */
    + {
    +-  assert( yymsp[-2].minor.yy473!=0 );
    +-  yymsp[-2].minor.yy473->pLast->pNext = yymsp[-1].minor.yy473;
    +-  yymsp[-2].minor.yy473->pLast = yymsp[-1].minor.yy473;
    +-  yygotominor.yy473 = yymsp[-2].minor.yy473;
    ++  assert( yymsp[-2].minor.yy203!=0 );
    ++  yymsp[-2].minor.yy203->pLast->pNext = yymsp[-1].minor.yy203;
    ++  yymsp[-2].minor.yy203->pLast = yymsp[-1].minor.yy203;
    + }
    +         break;
    +-      case 279: /* trigger_cmd_list ::= trigger_cmd SEMI */
    ++      case 236: /* trigger_cmd_list ::= trigger_cmd SEMI */
    + { 
    +-  assert( yymsp[-1].minor.yy473!=0 );
    +-  yymsp[-1].minor.yy473->pLast = yymsp[-1].minor.yy473;
    +-  yygotominor.yy473 = yymsp[-1].minor.yy473;
    ++  assert( yymsp[-1].minor.yy203!=0 );
    ++  yymsp[-1].minor.yy203->pLast = yymsp[-1].minor.yy203;
    + }
    +         break;
    +-      case 281: /* trnm ::= nm DOT nm */
    ++      case 237: /* trnm ::= nm DOT nm */
    + {
    +-  yygotominor.yy0 = yymsp[0].minor.yy0;
    ++  yymsp[-2].minor.yy0 = yymsp[0].minor.yy0;
    +   sqlite3ErrorMsg(pParse, 
    +         "qualified table names are not allowed on INSERT, UPDATE, and DELETE "
    +         "statements within triggers");
    + }
    +         break;
    +-      case 283: /* tridxby ::= INDEXED BY nm */
    ++      case 238: /* tridxby ::= INDEXED BY nm */
    + {
    +   sqlite3ErrorMsg(pParse,
    +         "the INDEXED BY clause is not allowed on UPDATE or DELETE statements "
    +         "within triggers");
    + }
    +         break;
    +-      case 284: /* tridxby ::= NOT INDEXED */
    ++      case 239: /* tridxby ::= NOT INDEXED */
    + {
    +   sqlite3ErrorMsg(pParse,
    +         "the NOT INDEXED clause is not allowed on UPDATE or DELETE statements "
    +         "within triggers");
    + }
    +         break;
    +-      case 285: /* trigger_cmd ::= UPDATE orconf trnm tridxby SET setlist where_opt */
    +-{ yygotominor.yy473 = sqlite3TriggerUpdateStep(pParse->db, &yymsp[-4].minor.yy0, yymsp[-1].minor.yy14, yymsp[0].minor.yy132, yymsp[-5].minor.yy186); }
    ++      case 240: /* trigger_cmd ::= UPDATE orconf trnm tridxby SET setlist where_opt scanpt */
    ++{yylhsminor.yy203 = sqlite3TriggerUpdateStep(pParse->db, &yymsp[-5].minor.yy0, yymsp[-2].minor.yy322, yymsp[-1].minor.yy314, yymsp[-6].minor.yy4, yymsp[-7].minor.yy0.z, yymsp[0].minor.yy336);}
    ++  yymsp[-7].minor.yy203 = yylhsminor.yy203;
    +         break;
    +-      case 286: /* trigger_cmd ::= insert_cmd INTO trnm idlist_opt select */
    +-{yygotominor.yy473 = sqlite3TriggerInsertStep(pParse->db, &yymsp[-2].minor.yy0, yymsp[-1].minor.yy408, yymsp[0].minor.yy3, yymsp[-4].minor.yy186);}
    ++      case 241: /* trigger_cmd ::= scanpt insert_cmd INTO trnm idlist_opt select scanpt */
    ++{yylhsminor.yy203 = sqlite3TriggerInsertStep(pParse->db,&yymsp[-3].minor.yy0,yymsp[-2].minor.yy384,yymsp[-1].minor.yy387,yymsp[-5].minor.yy4,yymsp[-6].minor.yy336,yymsp[0].minor.yy336);/*yylhsminor.yy203-overwrites-yymsp[-5].minor.yy4*/}
    ++  yymsp[-6].minor.yy203 = yylhsminor.yy203;
    +         break;
    +-      case 287: /* trigger_cmd ::= DELETE FROM trnm tridxby where_opt */
    +-{yygotominor.yy473 = sqlite3TriggerDeleteStep(pParse->db, &yymsp[-2].minor.yy0, yymsp[0].minor.yy132);}
    ++      case 242: /* trigger_cmd ::= DELETE FROM trnm tridxby where_opt scanpt */
    ++{yylhsminor.yy203 = sqlite3TriggerDeleteStep(pParse->db, &yymsp[-3].minor.yy0, yymsp[-1].minor.yy314, yymsp[-5].minor.yy0.z, yymsp[0].minor.yy336);}
    ++  yymsp[-5].minor.yy203 = yylhsminor.yy203;
    +         break;
    +-      case 288: /* trigger_cmd ::= select */
    +-{yygotominor.yy473 = sqlite3TriggerSelectStep(pParse->db, yymsp[0].minor.yy3); }
    ++      case 243: /* trigger_cmd ::= scanpt select scanpt */
    ++{yylhsminor.yy203 = sqlite3TriggerSelectStep(pParse->db, yymsp[-1].minor.yy387, yymsp[-2].minor.yy336, yymsp[0].minor.yy336); /*yylhsminor.yy203-overwrites-yymsp[-1].minor.yy387*/}
    ++  yymsp[-2].minor.yy203 = yylhsminor.yy203;
    +         break;
    +-      case 289: /* expr ::= RAISE LP IGNORE RP */
    ++      case 244: /* expr ::= RAISE LP IGNORE RP */
    + {
    +-  yygotominor.yy346.pExpr = sqlite3PExpr(pParse, TK_RAISE, 0, 0, 0); 
    +-  if( yygotominor.yy346.pExpr ){
    +-    yygotominor.yy346.pExpr->affinity = OE_Ignore;
    ++  yymsp[-3].minor.yy314 = sqlite3PExpr(pParse, TK_RAISE, 0, 0); 
    ++  if( yymsp[-3].minor.yy314 ){
    ++    yymsp[-3].minor.yy314->affinity = OE_Ignore;
    +   }
    +-  yygotominor.yy346.zStart = yymsp[-3].minor.yy0.z;
    +-  yygotominor.yy346.zEnd = &yymsp[0].minor.yy0.z[yymsp[0].minor.yy0.n];
    + }
    +         break;
    +-      case 290: /* expr ::= RAISE LP raisetype COMMA nm RP */
    ++      case 245: /* expr ::= RAISE LP raisetype COMMA nm RP */
    + {
    +-  yygotominor.yy346.pExpr = sqlite3PExpr(pParse, TK_RAISE, 0, 0, &yymsp[-1].minor.yy0); 
    +-  if( yygotominor.yy346.pExpr ) {
    +-    yygotominor.yy346.pExpr->affinity = (char)yymsp[-3].minor.yy328;
    ++  yymsp[-5].minor.yy314 = sqlite3ExprAlloc(pParse->db, TK_RAISE, &yymsp[-1].minor.yy0, 1); 
    ++  if( yymsp[-5].minor.yy314 ) {
    ++    yymsp[-5].minor.yy314->affinity = (char)yymsp[-3].minor.yy4;
    +   }
    +-  yygotominor.yy346.zStart = yymsp[-5].minor.yy0.z;
    +-  yygotominor.yy346.zEnd = &yymsp[0].minor.yy0.z[yymsp[0].minor.yy0.n];
    + }
    +         break;
    +-      case 291: /* raisetype ::= ROLLBACK */
    +-{yygotominor.yy328 = OE_Rollback;}
    ++      case 246: /* raisetype ::= ROLLBACK */
    ++{yymsp[0].minor.yy4 = OE_Rollback;}
    +         break;
    +-      case 293: /* raisetype ::= FAIL */
    +-{yygotominor.yy328 = OE_Fail;}
    ++      case 248: /* raisetype ::= FAIL */
    ++{yymsp[0].minor.yy4 = OE_Fail;}
    +         break;
    +-      case 294: /* cmd ::= DROP TRIGGER ifexists fullname */
    ++      case 249: /* cmd ::= DROP TRIGGER ifexists fullname */
    + {
    +-  sqlite3DropTrigger(pParse,yymsp[0].minor.yy65,yymsp[-1].minor.yy328);
    ++  sqlite3DropTrigger(pParse,yymsp[0].minor.yy259,yymsp[-1].minor.yy4);
    + }
    +         break;
    +-      case 295: /* cmd ::= ATTACH database_kw_opt expr AS expr key_opt */
    ++      case 250: /* cmd ::= ATTACH database_kw_opt expr AS expr key_opt */
    + {
    +-  sqlite3Attach(pParse, yymsp[-3].minor.yy346.pExpr, yymsp[-1].minor.yy346.pExpr, yymsp[0].minor.yy132);
    ++  sqlite3Attach(pParse, yymsp[-3].minor.yy314, yymsp[-1].minor.yy314, yymsp[0].minor.yy314);
    + }
    +         break;
    +-      case 296: /* cmd ::= DETACH database_kw_opt expr */
    ++      case 251: /* cmd ::= DETACH database_kw_opt expr */
    + {
    +-  sqlite3Detach(pParse, yymsp[0].minor.yy346.pExpr);
    ++  sqlite3Detach(pParse, yymsp[0].minor.yy314);
    + }
    +         break;
    +-      case 301: /* cmd ::= REINDEX */
    ++      case 254: /* cmd ::= REINDEX */
    + {sqlite3Reindex(pParse, 0, 0);}
    +         break;
    +-      case 302: /* cmd ::= REINDEX nm dbnm */
    ++      case 255: /* cmd ::= REINDEX nm dbnm */
    + {sqlite3Reindex(pParse, &yymsp[-1].minor.yy0, &yymsp[0].minor.yy0);}
    +         break;
    +-      case 303: /* cmd ::= ANALYZE */
    ++      case 256: /* cmd ::= ANALYZE */
    + {sqlite3Analyze(pParse, 0, 0);}
    +         break;
    +-      case 304: /* cmd ::= ANALYZE nm dbnm */
    ++      case 257: /* cmd ::= ANALYZE nm dbnm */
    + {sqlite3Analyze(pParse, &yymsp[-1].minor.yy0, &yymsp[0].minor.yy0);}
    +         break;
    +-      case 305: /* cmd ::= ALTER TABLE fullname RENAME TO nm */
    ++      case 258: /* cmd ::= ALTER TABLE fullname RENAME TO nm */
    + {
    +-  sqlite3AlterRenameTable(pParse,yymsp[-3].minor.yy65,&yymsp[0].minor.yy0);
    ++  sqlite3AlterRenameTable(pParse,yymsp[-3].minor.yy259,&yymsp[0].minor.yy0);
    + }
    +         break;
    +-      case 306: /* cmd ::= ALTER TABLE add_column_fullname ADD kwcolumn_opt column */
    ++      case 259: /* cmd ::= ALTER TABLE add_column_fullname ADD kwcolumn_opt columnname carglist */
    + {
    +-  sqlite3AlterFinishAddColumn(pParse, &yymsp[0].minor.yy0);
    ++  yymsp[-1].minor.yy0.n = (int)(pParse->sLastToken.z-yymsp[-1].minor.yy0.z) + pParse->sLastToken.n;
    ++  sqlite3AlterFinishAddColumn(pParse, &yymsp[-1].minor.yy0);
    + }
    +         break;
    +-      case 307: /* add_column_fullname ::= fullname */
    ++      case 260: /* add_column_fullname ::= fullname */
    + {
    +-  pParse->db->lookaside.bEnabled = 0;
    +-  sqlite3AlterBeginAddColumn(pParse, yymsp[0].minor.yy65);
    ++  disableLookaside(pParse);
    ++  sqlite3AlterBeginAddColumn(pParse, yymsp[0].minor.yy259);
    + }
    +         break;
    +-      case 310: /* cmd ::= create_vtab */
    ++      case 261: /* cmd ::= create_vtab */
    + {sqlite3VtabFinishParse(pParse,0);}
    +         break;
    +-      case 311: /* cmd ::= create_vtab LP vtabarglist RP */
    ++      case 262: /* cmd ::= create_vtab LP vtabarglist RP */
    + {sqlite3VtabFinishParse(pParse,&yymsp[0].minor.yy0);}
    +         break;
    +-      case 312: /* create_vtab ::= createkw VIRTUAL TABLE ifnotexists nm dbnm USING nm */
    ++      case 263: /* create_vtab ::= createkw VIRTUAL TABLE ifnotexists nm dbnm USING nm */
    + {
    +-    sqlite3VtabBeginParse(pParse, &yymsp[-3].minor.yy0, &yymsp[-2].minor.yy0, &yymsp[0].minor.yy0, yymsp[-4].minor.yy328);
    ++    sqlite3VtabBeginParse(pParse, &yymsp[-3].minor.yy0, &yymsp[-2].minor.yy0, &yymsp[0].minor.yy0, yymsp[-4].minor.yy4);
    + }
    +         break;
    +-      case 315: /* vtabarg ::= */
    ++      case 264: /* vtabarg ::= */
    + {sqlite3VtabArgInit(pParse);}
    +         break;
    +-      case 317: /* vtabargtoken ::= ANY */
    +-      case 318: /* vtabargtoken ::= lp anylist RP */ yytestcase(yyruleno==318);
    +-      case 319: /* lp ::= LP */ yytestcase(yyruleno==319);
    ++      case 265: /* vtabargtoken ::= ANY */
    ++      case 266: /* vtabargtoken ::= lp anylist RP */ yytestcase(yyruleno==266);
    ++      case 267: /* lp ::= LP */ yytestcase(yyruleno==267);
    + {sqlite3VtabArgExtend(pParse,&yymsp[0].minor.yy0);}
    +         break;
    +-      case 323: /* with ::= */
    +-{yygotominor.yy59 = 0;}
    ++      case 268: /* with ::= */
    ++{yymsp[1].minor.yy451 = 0;}
    +         break;
    +-      case 324: /* with ::= WITH wqlist */
    +-      case 325: /* with ::= WITH RECURSIVE wqlist */ yytestcase(yyruleno==325);
    +-{ yygotominor.yy59 = yymsp[0].minor.yy59; }
    ++      case 269: /* with ::= WITH wqlist */
    ++{ yymsp[-1].minor.yy451 = yymsp[0].minor.yy451; }
    +         break;
    +-      case 326: /* wqlist ::= nm eidlist_opt AS LP select RP */
    ++      case 270: /* with ::= WITH RECURSIVE wqlist */
    ++{ yymsp[-2].minor.yy451 = yymsp[0].minor.yy451; }
    ++        break;
    ++      case 271: /* wqlist ::= nm eidlist_opt AS LP select RP */
    + {
    +-  yygotominor.yy59 = sqlite3WithAdd(pParse, 0, &yymsp[-5].minor.yy0, yymsp[-4].minor.yy14, yymsp[-1].minor.yy3);
    ++  yymsp[-5].minor.yy451 = sqlite3WithAdd(pParse, 0, &yymsp[-5].minor.yy0, yymsp[-4].minor.yy322, yymsp[-1].minor.yy387); /*A-overwrites-X*/
    + }
    +         break;
    +-      case 327: /* wqlist ::= wqlist COMMA nm eidlist_opt AS LP select RP */
    ++      case 272: /* wqlist ::= wqlist COMMA nm eidlist_opt AS LP select RP */
    + {
    +-  yygotominor.yy59 = sqlite3WithAdd(pParse, yymsp[-7].minor.yy59, &yymsp[-5].minor.yy0, yymsp[-4].minor.yy14, yymsp[-1].minor.yy3);
    ++  yymsp[-7].minor.yy451 = sqlite3WithAdd(pParse, yymsp[-7].minor.yy451, &yymsp[-5].minor.yy0, yymsp[-4].minor.yy322, yymsp[-1].minor.yy387);
    + }
    +         break;
    +       default:
    +-      /* (0) input ::= cmdlist */ yytestcase(yyruleno==0);
    +-      /* (1) cmdlist ::= cmdlist ecmd */ yytestcase(yyruleno==1);
    +-      /* (2) cmdlist ::= ecmd */ yytestcase(yyruleno==2);
    +-      /* (3) ecmd ::= SEMI */ yytestcase(yyruleno==3);
    +-      /* (4) ecmd ::= explain cmdx SEMI */ yytestcase(yyruleno==4);
    +-      /* (10) trans_opt ::= */ yytestcase(yyruleno==10);
    +-      /* (11) trans_opt ::= TRANSACTION */ yytestcase(yyruleno==11);
    +-      /* (12) trans_opt ::= TRANSACTION nm */ yytestcase(yyruleno==12);
    +-      /* (20) savepoint_opt ::= SAVEPOINT */ yytestcase(yyruleno==20);
    +-      /* (21) savepoint_opt ::= */ yytestcase(yyruleno==21);
    +-      /* (25) cmd ::= create_table create_table_args */ yytestcase(yyruleno==25);
    +-      /* (36) columnlist ::= columnlist COMMA column */ yytestcase(yyruleno==36);
    +-      /* (37) columnlist ::= column */ yytestcase(yyruleno==37);
    +-      /* (43) type ::= */ yytestcase(yyruleno==43);
    +-      /* (50) signed ::= plus_num */ yytestcase(yyruleno==50);
    +-      /* (51) signed ::= minus_num */ yytestcase(yyruleno==51);
    +-      /* (52) carglist ::= carglist ccons */ yytestcase(yyruleno==52);
    +-      /* (53) carglist ::= */ yytestcase(yyruleno==53);
    +-      /* (60) ccons ::= NULL onconf */ yytestcase(yyruleno==60);
    +-      /* (88) conslist ::= conslist tconscomma tcons */ yytestcase(yyruleno==88);
    +-      /* (89) conslist ::= tcons */ yytestcase(yyruleno==89);
    +-      /* (91) tconscomma ::= */ yytestcase(yyruleno==91);
    +-      /* (274) foreach_clause ::= */ yytestcase(yyruleno==274);
    +-      /* (275) foreach_clause ::= FOR EACH ROW */ yytestcase(yyruleno==275);
    +-      /* (282) tridxby ::= */ yytestcase(yyruleno==282);
    +-      /* (299) database_kw_opt ::= DATABASE */ yytestcase(yyruleno==299);
    +-      /* (300) database_kw_opt ::= */ yytestcase(yyruleno==300);
    +-      /* (308) kwcolumn_opt ::= */ yytestcase(yyruleno==308);
    +-      /* (309) kwcolumn_opt ::= COLUMNKW */ yytestcase(yyruleno==309);
    +-      /* (313) vtabarglist ::= vtabarg */ yytestcase(yyruleno==313);
    +-      /* (314) vtabarglist ::= vtabarglist COMMA vtabarg */ yytestcase(yyruleno==314);
    +-      /* (316) vtabarg ::= vtabarg vtabargtoken */ yytestcase(yyruleno==316);
    +-      /* (320) anylist ::= */ yytestcase(yyruleno==320);
    +-      /* (321) anylist ::= anylist LP anylist RP */ yytestcase(yyruleno==321);
    +-      /* (322) anylist ::= anylist ANY */ yytestcase(yyruleno==322);
    ++      /* (273) input ::= cmdlist */ yytestcase(yyruleno==273);
    ++      /* (274) cmdlist ::= cmdlist ecmd */ yytestcase(yyruleno==274);
    ++      /* (275) cmdlist ::= ecmd (OPTIMIZED OUT) */ assert(yyruleno!=275);
    ++      /* (276) ecmd ::= SEMI */ yytestcase(yyruleno==276);
    ++      /* (277) ecmd ::= explain cmdx SEMI */ yytestcase(yyruleno==277);
    ++      /* (278) explain ::= */ yytestcase(yyruleno==278);
    ++      /* (279) trans_opt ::= */ yytestcase(yyruleno==279);
    ++      /* (280) trans_opt ::= TRANSACTION */ yytestcase(yyruleno==280);
    ++      /* (281) trans_opt ::= TRANSACTION nm */ yytestcase(yyruleno==281);
    ++      /* (282) savepoint_opt ::= SAVEPOINT */ yytestcase(yyruleno==282);
    ++      /* (283) savepoint_opt ::= */ yytestcase(yyruleno==283);
    ++      /* (284) cmd ::= create_table create_table_args */ yytestcase(yyruleno==284);
    ++      /* (285) columnlist ::= columnlist COMMA columnname carglist */ yytestcase(yyruleno==285);
    ++      /* (286) columnlist ::= columnname carglist */ yytestcase(yyruleno==286);
    ++      /* (287) nm ::= ID|INDEXED */ yytestcase(yyruleno==287);
    ++      /* (288) nm ::= STRING */ yytestcase(yyruleno==288);
    ++      /* (289) nm ::= JOIN_KW */ yytestcase(yyruleno==289);
    ++      /* (290) typetoken ::= typename */ yytestcase(yyruleno==290);
    ++      /* (291) typename ::= ID|STRING */ yytestcase(yyruleno==291);
    ++      /* (292) signed ::= plus_num (OPTIMIZED OUT) */ assert(yyruleno!=292);
    ++      /* (293) signed ::= minus_num (OPTIMIZED OUT) */ assert(yyruleno!=293);
    ++      /* (294) carglist ::= carglist ccons */ yytestcase(yyruleno==294);
    ++      /* (295) carglist ::= */ yytestcase(yyruleno==295);
    ++      /* (296) ccons ::= NULL onconf */ yytestcase(yyruleno==296);
    ++      /* (297) conslist_opt ::= COMMA conslist */ yytestcase(yyruleno==297);
    ++      /* (298) conslist ::= conslist tconscomma tcons */ yytestcase(yyruleno==298);
    ++      /* (299) conslist ::= tcons (OPTIMIZED OUT) */ assert(yyruleno!=299);
    ++      /* (300) tconscomma ::= */ yytestcase(yyruleno==300);
    ++      /* (301) defer_subclause_opt ::= defer_subclause (OPTIMIZED OUT) */ assert(yyruleno!=301);
    ++      /* (302) resolvetype ::= raisetype (OPTIMIZED OUT) */ assert(yyruleno!=302);
    ++      /* (303) selectnowith ::= oneselect (OPTIMIZED OUT) */ assert(yyruleno!=303);
    ++      /* (304) oneselect ::= values */ yytestcase(yyruleno==304);
    ++      /* (305) sclp ::= selcollist COMMA */ yytestcase(yyruleno==305);
    ++      /* (306) as ::= ID|STRING */ yytestcase(yyruleno==306);
    ++      /* (307) expr ::= term (OPTIMIZED OUT) */ assert(yyruleno!=307);
    ++      /* (308) likeop ::= LIKE_KW|MATCH */ yytestcase(yyruleno==308);
    ++      /* (309) exprlist ::= nexprlist */ yytestcase(yyruleno==309);
    ++      /* (310) nmnum ::= plus_num (OPTIMIZED OUT) */ assert(yyruleno!=310);
    ++      /* (311) nmnum ::= nm (OPTIMIZED OUT) */ assert(yyruleno!=311);
    ++      /* (312) nmnum ::= ON */ yytestcase(yyruleno==312);
    ++      /* (313) nmnum ::= DELETE */ yytestcase(yyruleno==313);
    ++      /* (314) nmnum ::= DEFAULT */ yytestcase(yyruleno==314);
    ++      /* (315) plus_num ::= INTEGER|FLOAT */ yytestcase(yyruleno==315);
    ++      /* (316) foreach_clause ::= */ yytestcase(yyruleno==316);
    ++      /* (317) foreach_clause ::= FOR EACH ROW */ yytestcase(yyruleno==317);
    ++      /* (318) trnm ::= nm */ yytestcase(yyruleno==318);
    ++      /* (319) tridxby ::= */ yytestcase(yyruleno==319);
    ++      /* (320) database_kw_opt ::= DATABASE */ yytestcase(yyruleno==320);
    ++      /* (321) database_kw_opt ::= */ yytestcase(yyruleno==321);
    ++      /* (322) kwcolumn_opt ::= */ yytestcase(yyruleno==322);
    ++      /* (323) kwcolumn_opt ::= COLUMNKW */ yytestcase(yyruleno==323);
    ++      /* (324) vtabarglist ::= vtabarg */ yytestcase(yyruleno==324);
    ++      /* (325) vtabarglist ::= vtabarglist COMMA vtabarg */ yytestcase(yyruleno==325);
    ++      /* (326) vtabarg ::= vtabarg vtabargtoken */ yytestcase(yyruleno==326);
    ++      /* (327) anylist ::= */ yytestcase(yyruleno==327);
    ++      /* (328) anylist ::= anylist LP anylist RP */ yytestcase(yyruleno==328);
    ++      /* (329) anylist ::= anylist ANY */ yytestcase(yyruleno==329);
    +         break;
    ++/********** End reduce actions ************************************************/
    +   };
    +-  assert( yyruleno>=0 && yyruleno<sizeof(yyRuleInfo)/sizeof(yyRuleInfo[0]) );
    ++  assert( yyruleno<sizeof(yyRuleInfo)/sizeof(yyRuleInfo[0]) );
    +   yygoto = yyRuleInfo[yyruleno].lhs;
    +   yysize = yyRuleInfo[yyruleno].nrhs;
    +-  yypParser->yyidx -= yysize;
    +-  yyact = yy_find_reduce_action(yymsp[-yysize].stateno,(YYCODETYPE)yygoto);
    +-  if( yyact <= YY_MAX_SHIFTREDUCE ){
    +-    if( yyact>YY_MAX_SHIFT ) yyact += YY_MIN_REDUCE - YY_MIN_SHIFTREDUCE;
    +-    /* If the reduce action popped at least
    +-    ** one element off the stack, then we can push the new element back
    +-    ** onto the stack here, and skip the stack overflow test in yy_shift().
    +-    ** That gives a significant speed improvement. */
    +-    if( yysize ){
    +-      yypParser->yyidx++;
    +-      yymsp -= yysize-1;
    +-      yymsp->stateno = (YYACTIONTYPE)yyact;
    +-      yymsp->major = (YYCODETYPE)yygoto;
    +-      yymsp->minor = yygotominor;
    +-      yyTraceShift(yypParser, yyact);
    +-    }else{
    +-      yy_shift(yypParser,yyact,yygoto,&yygotominor);
    +-    }
    +-  }else{
    +-    assert( yyact == YY_ACCEPT_ACTION );
    +-    yy_accept(yypParser);
    +-  }
    ++  yyact = yy_find_reduce_action(yymsp[yysize].stateno,(YYCODETYPE)yygoto);
    ++
    ++  /* There are no SHIFTREDUCE actions on nonterminals because the table
    ++  ** generator has simplified them to pure REDUCE actions. */
    ++  assert( !(yyact>YY_MAX_SHIFT && yyact<=YY_MAX_SHIFTREDUCE) );
    ++
    ++  /* It is not possible for a REDUCE to be followed by an error */
    ++  assert( yyact!=YY_ERROR_ACTION );
    ++
    ++  yymsp += yysize+1;
    ++  yypParser->yytos = yymsp;
    ++  yymsp->stateno = (YYACTIONTYPE)yyact;
    ++  yymsp->major = (YYCODETYPE)yygoto;
    ++  yyTraceShift(yypParser, yyact, "... then shift");
    + }
    + 
    + /*
    +@@ -129387,9 +141813,11 @@ static void yy_parse_failed(
    +     fprintf(yyTraceFILE,"%sFail!\n",yyTracePrompt);
    +   }
    + #endif
    +-  while( yypParser->yyidx>=0 ) yy_pop_parser_stack(yypParser);
    ++  while( yypParser->yytos>yypParser->yystack ) yy_pop_parser_stack(yypParser);
    +   /* Here code is inserted which will be executed whenever the
    +   ** parser fails */
    ++/************ Begin %parse_failure code ***************************************/
    ++/************ End %parse_failure code *****************************************/
    +   sqlite3ParserARG_STORE; /* Suppress warning about unused %extra_argument variable */
    + }
    + #endif /* YYNOERRORRECOVERY */
    +@@ -129400,14 +141828,19 @@ static void yy_parse_failed(
    + static void yy_syntax_error(
    +   yyParser *yypParser,           /* The parser */
    +   int yymajor,                   /* The major type of the error token */
    +-  YYMINORTYPE yyminor            /* The minor type of the error token */
    ++  sqlite3ParserTOKENTYPE yyminor         /* The minor type of the error token */
    + ){
    +   sqlite3ParserARG_FETCH;
    +-#define TOKEN (yyminor.yy0)
    ++#define TOKEN yyminor
    ++/************ Begin %syntax_error code ****************************************/
    + 
    +   UNUSED_PARAMETER(yymajor);  /* Silence some compiler warnings */
    +-  assert( TOKEN.z[0] );  /* The tokenizer always gives us a token */
    +-  sqlite3ErrorMsg(pParse, "near \"%T\": syntax error", &TOKEN);
    ++  if( TOKEN.z[0] ){
    ++    sqlite3ErrorMsg(pParse, "near \"%T\": syntax error", &TOKEN);
    ++  }else{
    ++    sqlite3ErrorMsg(pParse, "incomplete input");
    ++  }
    ++/************ End %syntax_error code ******************************************/
    +   sqlite3ParserARG_STORE; /* Suppress warning about unused %extra_argument variable */
    + }
    + 
    +@@ -129423,9 +141856,14 @@ static void yy_accept(
    +     fprintf(yyTraceFILE,"%sAccept!\n",yyTracePrompt);
    +   }
    + #endif
    +-  while( yypParser->yyidx>=0 ) yy_pop_parser_stack(yypParser);
    ++#ifndef YYNOERRORRECOVERY
    ++  yypParser->yyerrcnt = -1;
    ++#endif
    ++  assert( yypParser->yytos==yypParser->yystack );
    +   /* Here code is inserted which will be executed whenever the
    +   ** parser accepts */
    ++/*********** Begin %parse_accept code *****************************************/
    ++/*********** End %parse_accept code *******************************************/
    +   sqlite3ParserARG_STORE; /* Suppress warning about unused %extra_argument variable */
    + }
    + 
    +@@ -129455,7 +141893,7 @@ SQLITE_PRIVATE void sqlite3Parser(
    +   sqlite3ParserARG_PDECL               /* Optional %extra_argument parameter */
    + ){
    +   YYMINORTYPE yyminorunion;
    +-  int yyact;            /* The parser action. */
    ++  unsigned int yyact;   /* The parser action. */
    + #if !defined(YYERRORSYMBOL) && !defined(YYNOERRORRECOVERY)
    +   int yyendofinput;     /* True if we are at the end of input */
    + #endif
    +@@ -129464,23 +141902,8 @@ SQLITE_PRIVATE void sqlite3Parser(
    + #endif
    +   yyParser *yypParser;  /* The parser */
    + 
    +-  /* (re)initialize the parser, if necessary */
    +   yypParser = (yyParser*)yyp;
    +-  if( yypParser->yyidx<0 ){
    +-#if YYSTACKDEPTH<=0
    +-    if( yypParser->yystksz <=0 ){
    +-      /*memset(&yyminorunion, 0, sizeof(yyminorunion));*/
    +-      yyminorunion = yyzerominor;
    +-      yyStackOverflow(yypParser, &yyminorunion);
    +-      return;
    +-    }
    +-#endif
    +-    yypParser->yyidx = 0;
    +-    yypParser->yyerrcnt = -1;
    +-    yypParser->yystack[0].stateno = 0;
    +-    yypParser->yystack[0].major = 0;
    +-  }
    +-  yyminorunion.yy0 = yyminor;
    ++  assert( yypParser->yytos!=0 );
    + #if !defined(YYERRORSYMBOL) && !defined(YYNOERRORRECOVERY)
    +   yyendofinput = (yymajor==0);
    + #endif
    +@@ -129488,21 +141911,34 @@ SQLITE_PRIVATE void sqlite3Parser(
    + 
    + #ifndef NDEBUG
    +   if( yyTraceFILE ){
    +-    fprintf(yyTraceFILE,"%sInput %s\n",yyTracePrompt,yyTokenName[yymajor]);
    ++    int stateno = yypParser->yytos->stateno;
    ++    if( stateno < YY_MIN_REDUCE ){
    ++      fprintf(yyTraceFILE,"%sInput '%s' in state %d\n",
    ++              yyTracePrompt,yyTokenName[yymajor],stateno);
    ++    }else{
    ++      fprintf(yyTraceFILE,"%sInput '%s' with pending reduce %d\n",
    ++              yyTracePrompt,yyTokenName[yymajor],stateno-YY_MIN_REDUCE);
    ++    }
    +   }
    + #endif
    + 
    +   do{
    +     yyact = yy_find_shift_action(yypParser,(YYCODETYPE)yymajor);
    +-    if( yyact <= YY_MAX_SHIFTREDUCE ){
    +-      if( yyact > YY_MAX_SHIFT ) yyact += YY_MIN_REDUCE - YY_MIN_SHIFTREDUCE;
    +-      yy_shift(yypParser,yyact,yymajor,&yyminorunion);
    ++    if( yyact >= YY_MIN_REDUCE ){
    ++      yy_reduce(yypParser,yyact-YY_MIN_REDUCE,yymajor,yyminor);
    ++    }else if( yyact <= YY_MAX_SHIFTREDUCE ){
    ++      yy_shift(yypParser,yyact,yymajor,yyminor);
    ++#ifndef YYNOERRORRECOVERY
    +       yypParser->yyerrcnt--;
    ++#endif
    +       yymajor = YYNOCODE;
    +-    }else if( yyact <= YY_MAX_REDUCE ){
    +-      yy_reduce(yypParser,yyact-YY_MIN_REDUCE);
    ++    }else if( yyact==YY_ACCEPT_ACTION ){
    ++      yypParser->yytos--;
    ++      yy_accept(yypParser);
    ++      return;
    +     }else{
    +       assert( yyact == YY_ERROR_ACTION );
    ++      yyminorunion.yy0 = yyminor;
    + #ifdef YYERRORSYMBOL
    +       int yymx;
    + #endif
    +@@ -129532,9 +141968,9 @@ SQLITE_PRIVATE void sqlite3Parser(
    +       **
    +       */
    +       if( yypParser->yyerrcnt<0 ){
    +-        yy_syntax_error(yypParser,yymajor,yyminorunion);
    ++        yy_syntax_error(yypParser,yymajor,yyminor);
    +       }
    +-      yymx = yypParser->yystack[yypParser->yyidx].major;
    ++      yymx = yypParser->yytos->major;
    +       if( yymx==YYERRORSYMBOL || yyerrorhit ){
    + #ifndef NDEBUG
    +         if( yyTraceFILE ){
    +@@ -129542,26 +141978,26 @@ SQLITE_PRIVATE void sqlite3Parser(
    +              yyTracePrompt,yyTokenName[yymajor]);
    +         }
    + #endif
    +-        yy_destructor(yypParser, (YYCODETYPE)yymajor,&yyminorunion);
    ++        yy_destructor(yypParser, (YYCODETYPE)yymajor, &yyminorunion);
    +         yymajor = YYNOCODE;
    +       }else{
    +-         while(
    +-          yypParser->yyidx >= 0 &&
    +-          yymx != YYERRORSYMBOL &&
    +-          (yyact = yy_find_reduce_action(
    +-                        yypParser->yystack[yypParser->yyidx].stateno,
    ++        while( yypParser->yytos >= yypParser->yystack
    ++            && yymx != YYERRORSYMBOL
    ++            && (yyact = yy_find_reduce_action(
    ++                        yypParser->yytos->stateno,
    +                         YYERRORSYMBOL)) >= YY_MIN_REDUCE
    +         ){
    +           yy_pop_parser_stack(yypParser);
    +         }
    +-        if( yypParser->yyidx < 0 || yymajor==0 ){
    ++        if( yypParser->yytos < yypParser->yystack || yymajor==0 ){
    +           yy_destructor(yypParser,(YYCODETYPE)yymajor,&yyminorunion);
    +           yy_parse_failed(yypParser);
    ++#ifndef YYNOERRORRECOVERY
    ++          yypParser->yyerrcnt = -1;
    ++#endif
    +           yymajor = YYNOCODE;
    +         }else if( yymx!=YYERRORSYMBOL ){
    +-          YYMINORTYPE u2;
    +-          u2.YYERRSYMDT = 0;
    +-          yy_shift(yypParser,yyact,YYERRORSYMBOL,&u2);
    ++          yy_shift(yypParser,yyact,YYERRORSYMBOL,yyminor);
    +         }
    +       }
    +       yypParser->yyerrcnt = 3;
    +@@ -129574,7 +142010,7 @@ SQLITE_PRIVATE void sqlite3Parser(
    +       ** Applications can set this macro (for example inside %include) if
    +       ** they intend to abandon the parse upon the first syntax error seen.
    +       */
    +-      yy_syntax_error(yypParser,yymajor,yyminorunion);
    ++      yy_syntax_error(yypParser,yymajor, yyminor);
    +       yy_destructor(yypParser,(YYCODETYPE)yymajor,&yyminorunion);
    +       yymajor = YYNOCODE;
    +       
    +@@ -129589,20 +142025,30 @@ SQLITE_PRIVATE void sqlite3Parser(
    +       ** three input tokens have been successfully shifted.
    +       */
    +       if( yypParser->yyerrcnt<=0 ){
    +-        yy_syntax_error(yypParser,yymajor,yyminorunion);
    ++        yy_syntax_error(yypParser,yymajor, yyminor);
    +       }
    +       yypParser->yyerrcnt = 3;
    +       yy_destructor(yypParser,(YYCODETYPE)yymajor,&yyminorunion);
    +       if( yyendofinput ){
    +         yy_parse_failed(yypParser);
    ++#ifndef YYNOERRORRECOVERY
    ++        yypParser->yyerrcnt = -1;
    ++#endif
    +       }
    +       yymajor = YYNOCODE;
    + #endif
    +     }
    +-  }while( yymajor!=YYNOCODE && yypParser->yyidx>=0 );
    ++  }while( yymajor!=YYNOCODE && yypParser->yytos>yypParser->yystack );
    + #ifndef NDEBUG
    +   if( yyTraceFILE ){
    +-    fprintf(yyTraceFILE,"%sReturn\n",yyTracePrompt);
    ++    yyStackEntry *i;
    ++    char cDiv = '[';
    ++    fprintf(yyTraceFILE,"%sReturn. Stack=",yyTracePrompt);
    ++    for(i=&yypParser->yystack[1]; i<=yypParser->yytos; i++){
    ++      fprintf(yyTraceFILE,"%c%s", cDiv, yyTokenName[i->major]);
    ++      cDiv = ' ';
    ++    }
    ++    fprintf(yyTraceFILE,"]\n");
    +   }
    + #endif
    +   return;
    +@@ -129630,12 +142076,92 @@ SQLITE_PRIVATE void sqlite3Parser(
    + /* #include "sqliteInt.h" */
    + /* #include <stdlib.h> */
    + 
    ++/* Character classes for tokenizing
    ++**
    ++** In the sqlite3GetToken() function, a switch() on aiClass[c] is implemented
    ++** using a lookup table, whereas a switch() directly on c uses a binary search.
    ++** The lookup table is much faster.  To maximize speed, and to ensure that
    ++** a lookup table is used, all of the classes need to be small integers and
    ++** all of them need to be used within the switch.
    ++*/
    ++#define CC_X          0    /* The letter 'x', or start of BLOB literal */
    ++#define CC_KYWD       1    /* Alphabetics or '_'.  Usable in a keyword */
    ++#define CC_ID         2    /* unicode characters usable in IDs */
    ++#define CC_DIGIT      3    /* Digits */
    ++#define CC_DOLLAR     4    /* '$' */
    ++#define CC_VARALPHA   5    /* '@', '#', ':'.  Alphabetic SQL variables */
    ++#define CC_VARNUM     6    /* '?'.  Numeric SQL variables */
    ++#define CC_SPACE      7    /* Space characters */
    ++#define CC_QUOTE      8    /* '"', '\'', or '`'.  String literals, quoted ids */
    ++#define CC_QUOTE2     9    /* '['.   [...] style quoted ids */
    ++#define CC_PIPE      10    /* '|'.   Bitwise OR or concatenate */
    ++#define CC_MINUS     11    /* '-'.  Minus or SQL-style comment */
    ++#define CC_LT        12    /* '<'.  Part of < or <= or <> */
    ++#define CC_GT        13    /* '>'.  Part of > or >= */
    ++#define CC_EQ        14    /* '='.  Part of = or == */
    ++#define CC_BANG      15    /* '!'.  Part of != */
    ++#define CC_SLASH     16    /* '/'.  / or c-style comment */
    ++#define CC_LP        17    /* '(' */
    ++#define CC_RP        18    /* ')' */
    ++#define CC_SEMI      19    /* ';' */
    ++#define CC_PLUS      20    /* '+' */
    ++#define CC_STAR      21    /* '*' */
    ++#define CC_PERCENT   22    /* '%' */
    ++#define CC_COMMA     23    /* ',' */
    ++#define CC_AND       24    /* '&' */
    ++#define CC_TILDA     25    /* '~' */
    ++#define CC_DOT       26    /* '.' */
    ++#define CC_ILLEGAL   27    /* Illegal character */
    ++
    ++static const unsigned char aiClass[] = {
    ++#ifdef SQLITE_ASCII
    ++/*         x0  x1  x2  x3  x4  x5  x6  x7  x8  x9  xa  xb  xc  xd  xe  xf */
    ++/* 0x */   27, 27, 27, 27, 27, 27, 27, 27, 27,  7,  7, 27,  7,  7, 27, 27,
    ++/* 1x */   27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27,
    ++/* 2x */    7, 15,  8,  5,  4, 22, 24,  8, 17, 18, 21, 20, 23, 11, 26, 16,
    ++/* 3x */    3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  5, 19, 12, 14, 13,  6,
    ++/* 4x */    5,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,
    ++/* 5x */    1,  1,  1,  1,  1,  1,  1,  1,  0,  1,  1,  9, 27, 27, 27,  1,
    ++/* 6x */    8,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,
    ++/* 7x */    1,  1,  1,  1,  1,  1,  1,  1,  0,  1,  1, 27, 10, 27, 25, 27,
    ++/* 8x */    2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,
    ++/* 9x */    2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,
    ++/* Ax */    2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,
    ++/* Bx */    2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,
    ++/* Cx */    2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,
    ++/* Dx */    2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,
    ++/* Ex */    2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,
    ++/* Fx */    2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2
    ++#endif
    ++#ifdef SQLITE_EBCDIC
    ++/*         x0  x1  x2  x3  x4  x5  x6  x7  x8  x9  xa  xb  xc  xd  xe  xf */
    ++/* 0x */   27, 27, 27, 27, 27,  7, 27, 27, 27, 27, 27, 27,  7,  7, 27, 27,
    ++/* 1x */   27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27,
    ++/* 2x */   27, 27, 27, 27, 27,  7, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27,
    ++/* 3x */   27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27,
    ++/* 4x */    7, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 26, 12, 17, 20, 10,
    ++/* 5x */   24, 27, 27, 27, 27, 27, 27, 27, 27, 27, 15,  4, 21, 18, 19, 27,
    ++/* 6x */   11, 16, 27, 27, 27, 27, 27, 27, 27, 27, 27, 23, 22,  1, 13,  6,
    ++/* 7x */   27, 27, 27, 27, 27, 27, 27, 27, 27,  8,  5,  5,  5,  8, 14,  8,
    ++/* 8x */   27,  1,  1,  1,  1,  1,  1,  1,  1,  1, 27, 27, 27, 27, 27, 27,
    ++/* 9x */   27,  1,  1,  1,  1,  1,  1,  1,  1,  1, 27, 27, 27, 27, 27, 27,
    ++/* Ax */   27, 25,  1,  1,  1,  1,  1,  0,  1,  1, 27, 27, 27, 27, 27, 27,
    ++/* Bx */   27, 27, 27, 27, 27, 27, 27, 27, 27, 27,  9, 27, 27, 27, 27, 27,
    ++/* Cx */   27,  1,  1,  1,  1,  1,  1,  1,  1,  1, 27, 27, 27, 27, 27, 27,
    ++/* Dx */   27,  1,  1,  1,  1,  1,  1,  1,  1,  1, 27, 27, 27, 27, 27, 27,
    ++/* Ex */   27, 27,  1,  1,  1,  1,  1,  0,  1,  1, 27, 27, 27, 27, 27, 27,
    ++/* Fx */    3,  3,  3,  3,  3,  3,  3,  3,  3,  3, 27, 27, 27, 27, 27, 27,
    ++#endif
    ++};
    ++
    + /*
    +-** The charMap() macro maps alphabetic characters into their
    ++** The charMap() macro maps alphabetic characters (only) into their
    + ** lower-case ASCII equivalent.  On ASCII machines, this is just
    + ** an upper-to-lower case map.  On EBCDIC machines we also need
    +-** to adjust the encoding.  Only alphabetic characters and underscores
    +-** need to be translated.
    ++** to adjust the encoding.  The mapping is only valid for alphabetics
    ++** which are the only characters for which this feature is used. 
    ++**
    ++** Used by keywordhash.h
    + */
    + #ifdef SQLITE_ASCII
    + # define charMap(X) sqlite3UpperToLower[(unsigned char)X]
    +@@ -129669,7 +142195,7 @@ const unsigned char ebcdicToAscii[] = {
    + ** returned.  If the input is not a keyword, TK_ID is returned.
    + **
    + ** The implementation of this routine was generated by a program,
    +-** mkkeywordhash.h, located in the tool subdirectory of the distribution.
    ++** mkkeywordhash.c, located in the tool subdirectory of the distribution.
    + ** The output of the mkkeywordhash.c program is written into a file
    + ** named keywordhash.h and then included into this source file by
    + ** the #include below.
    +@@ -129690,133 +142216,152 @@ const unsigned char ebcdicToAscii[] = {
    + ** on platforms with limited memory.
    + */
    + /* Hash score: 182 */
    +-static int keywordCode(const char *z, int n){
    +-  /* zText[] encodes 834 bytes of keywords in 554 bytes */
    +-  /*   REINDEXEDESCAPEACHECKEYBEFOREIGNOREGEXPLAINSTEADDATABASELECT       */
    +-  /*   ABLEFTHENDEFERRABLELSEXCEPTRANSACTIONATURALTERAISEXCLUSIVE         */
    +-  /*   XISTSAVEPOINTERSECTRIGGEREFERENCESCONSTRAINTOFFSETEMPORARY         */
    +-  /*   UNIQUERYWITHOUTERELEASEATTACHAVINGROUPDATEBEGINNERECURSIVE         */
    +-  /*   BETWEENOTNULLIKECASCADELETECASECOLLATECREATECURRENT_DATEDETACH     */
    +-  /*   IMMEDIATEJOINSERTMATCHPLANALYZEPRAGMABORTVALUESVIRTUALIMITWHEN     */
    +-  /*   WHERENAMEAFTEREPLACEANDEFAULTAUTOINCREMENTCASTCOLUMNCOMMIT         */
    +-  /*   CONFLICTCROSSCURRENT_TIMESTAMPRIMARYDEFERREDISTINCTDROPFAIL        */
    +-  /*   FROMFULLGLOBYIFISNULLORDERESTRICTRIGHTROLLBACKROWUNIONUSING        */
    +-  /*   VACUUMVIEWINITIALLY                                                */
    +-  static const char zText[553] = {
    +-    'R','E','I','N','D','E','X','E','D','E','S','C','A','P','E','A','C','H',
    +-    'E','C','K','E','Y','B','E','F','O','R','E','I','G','N','O','R','E','G',
    +-    'E','X','P','L','A','I','N','S','T','E','A','D','D','A','T','A','B','A',
    +-    'S','E','L','E','C','T','A','B','L','E','F','T','H','E','N','D','E','F',
    +-    'E','R','R','A','B','L','E','L','S','E','X','C','E','P','T','R','A','N',
    +-    'S','A','C','T','I','O','N','A','T','U','R','A','L','T','E','R','A','I',
    +-    'S','E','X','C','L','U','S','I','V','E','X','I','S','T','S','A','V','E',
    +-    'P','O','I','N','T','E','R','S','E','C','T','R','I','G','G','E','R','E',
    +-    'F','E','R','E','N','C','E','S','C','O','N','S','T','R','A','I','N','T',
    +-    'O','F','F','S','E','T','E','M','P','O','R','A','R','Y','U','N','I','Q',
    +-    'U','E','R','Y','W','I','T','H','O','U','T','E','R','E','L','E','A','S',
    +-    'E','A','T','T','A','C','H','A','V','I','N','G','R','O','U','P','D','A',
    +-    'T','E','B','E','G','I','N','N','E','R','E','C','U','R','S','I','V','E',
    +-    'B','E','T','W','E','E','N','O','T','N','U','L','L','I','K','E','C','A',
    +-    'S','C','A','D','E','L','E','T','E','C','A','S','E','C','O','L','L','A',
    +-    'T','E','C','R','E','A','T','E','C','U','R','R','E','N','T','_','D','A',
    +-    'T','E','D','E','T','A','C','H','I','M','M','E','D','I','A','T','E','J',
    +-    'O','I','N','S','E','R','T','M','A','T','C','H','P','L','A','N','A','L',
    +-    'Y','Z','E','P','R','A','G','M','A','B','O','R','T','V','A','L','U','E',
    +-    'S','V','I','R','T','U','A','L','I','M','I','T','W','H','E','N','W','H',
    +-    'E','R','E','N','A','M','E','A','F','T','E','R','E','P','L','A','C','E',
    +-    'A','N','D','E','F','A','U','L','T','A','U','T','O','I','N','C','R','E',
    +-    'M','E','N','T','C','A','S','T','C','O','L','U','M','N','C','O','M','M',
    +-    'I','T','C','O','N','F','L','I','C','T','C','R','O','S','S','C','U','R',
    +-    'R','E','N','T','_','T','I','M','E','S','T','A','M','P','R','I','M','A',
    +-    'R','Y','D','E','F','E','R','R','E','D','I','S','T','I','N','C','T','D',
    +-    'R','O','P','F','A','I','L','F','R','O','M','F','U','L','L','G','L','O',
    +-    'B','Y','I','F','I','S','N','U','L','L','O','R','D','E','R','E','S','T',
    +-    'R','I','C','T','R','I','G','H','T','R','O','L','L','B','A','C','K','R',
    +-    'O','W','U','N','I','O','N','U','S','I','N','G','V','A','C','U','U','M',
    +-    'V','I','E','W','I','N','I','T','I','A','L','L','Y',
    +-  };
    +-  static const unsigned char aHash[127] = {
    +-      76, 105, 117,  74,   0,  45,   0,   0,  82,   0,  77,   0,   0,
    +-      42,  12,  78,  15,   0, 116,  85,  54, 112,   0,  19,   0,   0,
    +-     121,   0, 119, 115,   0,  22,  93,   0,   9,   0,   0,  70,  71,
    +-       0,  69,   6,   0,  48,  90, 102,   0, 118, 101,   0,   0,  44,
    +-       0, 103,  24,   0,  17,   0, 122,  53,  23,   0,   5, 110,  25,
    +-      96,   0,   0, 124, 106,  60, 123,  57,  28,  55,   0,  91,   0,
    +-     100,  26,   0,  99,   0,   0,   0,  95,  92,  97,  88, 109,  14,
    +-      39, 108,   0,  81,   0,  18,  89, 111,  32,   0, 120,  80, 113,
    +-      62,  46,  84,   0,   0,  94,  40,  59, 114,   0,  36,   0,   0,
    +-      29,   0,  86,  63,  64,   0,  20,  61,   0,  56,
    +-  };
    +-  static const unsigned char aNext[124] = {
    +-       0,   0,   0,   0,   4,   0,   0,   0,   0,   0,   0,   0,   0,
    +-       0,   2,   0,   0,   0,   0,   0,   0,  13,   0,   0,   0,   0,
    +-       0,   7,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
    +-       0,   0,   0,   0,  33,   0,  21,   0,   0,   0,   0,   0,  50,
    +-       0,  43,   3,  47,   0,   0,   0,   0,  30,   0,  58,   0,  38,
    +-       0,   0,   0,   1,  66,   0,   0,  67,   0,  41,   0,   0,   0,
    +-       0,   0,   0,  49,  65,   0,   0,   0,   0,  31,  52,  16,  34,
    +-      10,   0,   0,   0,   0,   0,   0,   0,  11,  72,  79,   0,   8,
    +-       0, 104,  98,   0, 107,   0,  87,   0,  75,  51,   0,  27,  37,
    +-      73,  83,   0,  35,  68,   0,   0,
    +-  };
    +-  static const unsigned char aLen[124] = {
    +-       7,   7,   5,   4,   6,   4,   5,   3,   6,   7,   3,   6,   6,
    +-       7,   7,   3,   8,   2,   6,   5,   4,   4,   3,  10,   4,   6,
    +-      11,   6,   2,   7,   5,   5,   9,   6,   9,   9,   7,  10,  10,
    +-       4,   6,   2,   3,   9,   4,   2,   6,   5,   7,   4,   5,   7,
    +-       6,   6,   5,   6,   5,   5,   9,   7,   7,   3,   2,   4,   4,
    +-       7,   3,   6,   4,   7,   6,  12,   6,   9,   4,   6,   5,   4,
    +-       7,   6,   5,   6,   7,   5,   4,   5,   6,   5,   7,   3,   7,
    +-      13,   2,   2,   4,   6,   6,   8,   5,  17,  12,   7,   8,   8,
    +-       2,   4,   4,   4,   4,   4,   2,   2,   6,   5,   8,   5,   8,
    +-       3,   5,   5,   6,   4,   9,   3,
    +-  };
    +-  static const unsigned short int aOffset[124] = {
    +-       0,   2,   2,   8,   9,  14,  16,  20,  23,  25,  25,  29,  33,
    +-      36,  41,  46,  48,  53,  54,  59,  62,  65,  67,  69,  78,  81,
    +-      86,  91,  95,  96, 101, 105, 109, 117, 122, 128, 136, 142, 152,
    +-     159, 162, 162, 165, 167, 167, 171, 176, 179, 184, 184, 188, 192,
    +-     199, 204, 209, 212, 218, 221, 225, 234, 240, 240, 240, 243, 246,
    +-     250, 251, 255, 261, 265, 272, 278, 290, 296, 305, 307, 313, 318,
    +-     320, 327, 332, 337, 343, 349, 354, 358, 361, 367, 371, 378, 380,
    +-     387, 389, 391, 400, 404, 410, 416, 424, 429, 429, 445, 452, 459,
    +-     460, 467, 471, 475, 479, 483, 486, 488, 490, 496, 500, 508, 513,
    +-     521, 524, 529, 534, 540, 544, 549,
    +-  };
    +-  static const unsigned char aCode[124] = {
    +-    TK_REINDEX,    TK_INDEXED,    TK_INDEX,      TK_DESC,       TK_ESCAPE,     
    +-    TK_EACH,       TK_CHECK,      TK_KEY,        TK_BEFORE,     TK_FOREIGN,    
    +-    TK_FOR,        TK_IGNORE,     TK_LIKE_KW,    TK_EXPLAIN,    TK_INSTEAD,    
    +-    TK_ADD,        TK_DATABASE,   TK_AS,         TK_SELECT,     TK_TABLE,      
    +-    TK_JOIN_KW,    TK_THEN,       TK_END,        TK_DEFERRABLE, TK_ELSE,       
    +-    TK_EXCEPT,     TK_TRANSACTION,TK_ACTION,     TK_ON,         TK_JOIN_KW,    
    +-    TK_ALTER,      TK_RAISE,      TK_EXCLUSIVE,  TK_EXISTS,     TK_SAVEPOINT,  
    +-    TK_INTERSECT,  TK_TRIGGER,    TK_REFERENCES, TK_CONSTRAINT, TK_INTO,       
    +-    TK_OFFSET,     TK_OF,         TK_SET,        TK_TEMP,       TK_TEMP,       
    +-    TK_OR,         TK_UNIQUE,     TK_QUERY,      TK_WITHOUT,    TK_WITH,       
    +-    TK_JOIN_KW,    TK_RELEASE,    TK_ATTACH,     TK_HAVING,     TK_GROUP,      
    +-    TK_UPDATE,     TK_BEGIN,      TK_JOIN_KW,    TK_RECURSIVE,  TK_BETWEEN,    
    +-    TK_NOTNULL,    TK_NOT,        TK_NO,         TK_NULL,       TK_LIKE_KW,    
    +-    TK_CASCADE,    TK_ASC,        TK_DELETE,     TK_CASE,       TK_COLLATE,    
    +-    TK_CREATE,     TK_CTIME_KW,   TK_DETACH,     TK_IMMEDIATE,  TK_JOIN,       
    +-    TK_INSERT,     TK_MATCH,      TK_PLAN,       TK_ANALYZE,    TK_PRAGMA,     
    +-    TK_ABORT,      TK_VALUES,     TK_VIRTUAL,    TK_LIMIT,      TK_WHEN,       
    +-    TK_WHERE,      TK_RENAME,     TK_AFTER,      TK_REPLACE,    TK_AND,        
    +-    TK_DEFAULT,    TK_AUTOINCR,   TK_TO,         TK_IN,         TK_CAST,       
    +-    TK_COLUMNKW,   TK_COMMIT,     TK_CONFLICT,   TK_JOIN_KW,    TK_CTIME_KW,   
    +-    TK_CTIME_KW,   TK_PRIMARY,    TK_DEFERRED,   TK_DISTINCT,   TK_IS,         
    +-    TK_DROP,       TK_FAIL,       TK_FROM,       TK_JOIN_KW,    TK_LIKE_KW,    
    +-    TK_BY,         TK_IF,         TK_ISNULL,     TK_ORDER,      TK_RESTRICT,   
    +-    TK_JOIN_KW,    TK_ROLLBACK,   TK_ROW,        TK_UNION,      TK_USING,      
    +-    TK_VACUUM,     TK_VIEW,       TK_INITIALLY,  TK_ALL,        
    +-  };
    +-  int h, i;
    +-  if( n<2 ) return TK_ID;
    +-  h = ((charMap(z[0])*4) ^
    +-      (charMap(z[n-1])*3) ^
    +-      n) % 127;
    +-  for(i=((int)aHash[h])-1; i>=0; i=((int)aNext[i])-1){
    +-    if( aLen[i]==n && sqlite3StrNICmp(&zText[aOffset[i]],z,n)==0 ){
    ++/* zKWText[] encodes 834 bytes of keyword text in 554 bytes */
    ++/*   REINDEXEDESCAPEACHECKEYBEFOREIGNOREGEXPLAINSTEADDATABASELECT       */
    ++/*   ABLEFTHENDEFERRABLELSEXCEPTRANSACTIONATURALTERAISEXCLUSIVE         */
    ++/*   XISTSAVEPOINTERSECTRIGGEREFERENCESCONSTRAINTOFFSETEMPORARY         */
    ++/*   UNIQUERYWITHOUTERELEASEATTACHAVINGROUPDATEBEGINNERECURSIVE         */
    ++/*   BETWEENOTNULLIKECASCADELETECASECOLLATECREATECURRENT_DATEDETACH     */
    ++/*   IMMEDIATEJOINSERTMATCHPLANALYZEPRAGMABORTVALUESVIRTUALIMITWHEN     */
    ++/*   WHERENAMEAFTEREPLACEANDEFAULTAUTOINCREMENTCASTCOLUMNCOMMIT         */
    ++/*   CONFLICTCROSSCURRENT_TIMESTAMPRIMARYDEFERREDISTINCTDROPFAIL        */
    ++/*   FROMFULLGLOBYIFISNULLORDERESTRICTRIGHTROLLBACKROWUNIONUSING        */
    ++/*   VACUUMVIEWINITIALLY                                                */
    ++static const char zKWText[553] = {
    ++  'R','E','I','N','D','E','X','E','D','E','S','C','A','P','E','A','C','H',
    ++  'E','C','K','E','Y','B','E','F','O','R','E','I','G','N','O','R','E','G',
    ++  'E','X','P','L','A','I','N','S','T','E','A','D','D','A','T','A','B','A',
    ++  'S','E','L','E','C','T','A','B','L','E','F','T','H','E','N','D','E','F',
    ++  'E','R','R','A','B','L','E','L','S','E','X','C','E','P','T','R','A','N',
    ++  'S','A','C','T','I','O','N','A','T','U','R','A','L','T','E','R','A','I',
    ++  'S','E','X','C','L','U','S','I','V','E','X','I','S','T','S','A','V','E',
    ++  'P','O','I','N','T','E','R','S','E','C','T','R','I','G','G','E','R','E',
    ++  'F','E','R','E','N','C','E','S','C','O','N','S','T','R','A','I','N','T',
    ++  'O','F','F','S','E','T','E','M','P','O','R','A','R','Y','U','N','I','Q',
    ++  'U','E','R','Y','W','I','T','H','O','U','T','E','R','E','L','E','A','S',
    ++  'E','A','T','T','A','C','H','A','V','I','N','G','R','O','U','P','D','A',
    ++  'T','E','B','E','G','I','N','N','E','R','E','C','U','R','S','I','V','E',
    ++  'B','E','T','W','E','E','N','O','T','N','U','L','L','I','K','E','C','A',
    ++  'S','C','A','D','E','L','E','T','E','C','A','S','E','C','O','L','L','A',
    ++  'T','E','C','R','E','A','T','E','C','U','R','R','E','N','T','_','D','A',
    ++  'T','E','D','E','T','A','C','H','I','M','M','E','D','I','A','T','E','J',
    ++  'O','I','N','S','E','R','T','M','A','T','C','H','P','L','A','N','A','L',
    ++  'Y','Z','E','P','R','A','G','M','A','B','O','R','T','V','A','L','U','E',
    ++  'S','V','I','R','T','U','A','L','I','M','I','T','W','H','E','N','W','H',
    ++  'E','R','E','N','A','M','E','A','F','T','E','R','E','P','L','A','C','E',
    ++  'A','N','D','E','F','A','U','L','T','A','U','T','O','I','N','C','R','E',
    ++  'M','E','N','T','C','A','S','T','C','O','L','U','M','N','C','O','M','M',
    ++  'I','T','C','O','N','F','L','I','C','T','C','R','O','S','S','C','U','R',
    ++  'R','E','N','T','_','T','I','M','E','S','T','A','M','P','R','I','M','A',
    ++  'R','Y','D','E','F','E','R','R','E','D','I','S','T','I','N','C','T','D',
    ++  'R','O','P','F','A','I','L','F','R','O','M','F','U','L','L','G','L','O',
    ++  'B','Y','I','F','I','S','N','U','L','L','O','R','D','E','R','E','S','T',
    ++  'R','I','C','T','R','I','G','H','T','R','O','L','L','B','A','C','K','R',
    ++  'O','W','U','N','I','O','N','U','S','I','N','G','V','A','C','U','U','M',
    ++  'V','I','E','W','I','N','I','T','I','A','L','L','Y',
    ++};
    ++/* aKWHash[i] is the hash value for the i-th keyword */
    ++static const unsigned char aKWHash[127] = {
    ++    76, 105, 117,  74,   0,  45,   0,   0,  82,   0,  77,   0,   0,
    ++    42,  12,  78,  15,   0, 116,  85,  54, 112,   0,  19,   0,   0,
    ++   121,   0, 119, 115,   0,  22,  93,   0,   9,   0,   0,  70,  71,
    ++     0,  69,   6,   0,  48,  90, 102,   0, 118, 101,   0,   0,  44,
    ++     0, 103,  24,   0,  17,   0, 122,  53,  23,   0,   5, 110,  25,
    ++    96,   0,   0, 124, 106,  60, 123,  57,  28,  55,   0,  91,   0,
    ++   100,  26,   0,  99,   0,   0,   0,  95,  92,  97,  88, 109,  14,
    ++    39, 108,   0,  81,   0,  18,  89, 111,  32,   0, 120,  80, 113,
    ++    62,  46,  84,   0,   0,  94,  40,  59, 114,   0,  36,   0,   0,
    ++    29,   0,  86,  63,  64,   0,  20,  61,   0,  56,
    ++};
    ++/* aKWNext[] forms the hash collision chain.  If aKWHash[i]==0
    ++** then the i-th keyword has no more hash collisions.  Otherwise,
    ++** the next keyword with the same hash is aKWHash[i]-1. */
    ++static const unsigned char aKWNext[124] = {
    ++     0,   0,   0,   0,   4,   0,   0,   0,   0,   0,   0,   0,   0,
    ++     0,   2,   0,   0,   0,   0,   0,   0,  13,   0,   0,   0,   0,
    ++     0,   7,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
    ++     0,   0,   0,   0,  33,   0,  21,   0,   0,   0,   0,   0,  50,
    ++     0,  43,   3,  47,   0,   0,   0,   0,  30,   0,  58,   0,  38,
    ++     0,   0,   0,   1,  66,   0,   0,  67,   0,  41,   0,   0,   0,
    ++     0,   0,   0,  49,  65,   0,   0,   0,   0,  31,  52,  16,  34,
    ++    10,   0,   0,   0,   0,   0,   0,   0,  11,  72,  79,   0,   8,
    ++     0, 104,  98,   0, 107,   0,  87,   0,  75,  51,   0,  27,  37,
    ++    73,  83,   0,  35,  68,   0,   0,
    ++};
    ++/* aKWLen[i] is the length (in bytes) of the i-th keyword */
    ++static const unsigned char aKWLen[124] = {
    ++     7,   7,   5,   4,   6,   4,   5,   3,   6,   7,   3,   6,   6,
    ++     7,   7,   3,   8,   2,   6,   5,   4,   4,   3,  10,   4,   6,
    ++    11,   6,   2,   7,   5,   5,   9,   6,   9,   9,   7,  10,  10,
    ++     4,   6,   2,   3,   9,   4,   2,   6,   5,   7,   4,   5,   7,
    ++     6,   6,   5,   6,   5,   5,   9,   7,   7,   3,   2,   4,   4,
    ++     7,   3,   6,   4,   7,   6,  12,   6,   9,   4,   6,   5,   4,
    ++     7,   6,   5,   6,   7,   5,   4,   5,   6,   5,   7,   3,   7,
    ++    13,   2,   2,   4,   6,   6,   8,   5,  17,  12,   7,   8,   8,
    ++     2,   4,   4,   4,   4,   4,   2,   2,   6,   5,   8,   5,   8,
    ++     3,   5,   5,   6,   4,   9,   3,
    ++};
    ++/* aKWOffset[i] is the index into zKWText[] of the start of
    ++** the text for the i-th keyword. */
    ++static const unsigned short int aKWOffset[124] = {
    ++     0,   2,   2,   8,   9,  14,  16,  20,  23,  25,  25,  29,  33,
    ++    36,  41,  46,  48,  53,  54,  59,  62,  65,  67,  69,  78,  81,
    ++    86,  91,  95,  96, 101, 105, 109, 117, 122, 128, 136, 142, 152,
    ++   159, 162, 162, 165, 167, 167, 171, 176, 179, 184, 184, 188, 192,
    ++   199, 204, 209, 212, 218, 221, 225, 234, 240, 240, 240, 243, 246,
    ++   250, 251, 255, 261, 265, 272, 278, 290, 296, 305, 307, 313, 318,
    ++   320, 327, 332, 337, 343, 349, 354, 358, 361, 367, 371, 378, 380,
    ++   387, 389, 391, 400, 404, 410, 416, 424, 429, 429, 445, 452, 459,
    ++   460, 467, 471, 475, 479, 483, 486, 488, 490, 496, 500, 508, 513,
    ++   521, 524, 529, 534, 540, 544, 549,
    ++};
    ++/* aKWCode[i] is the parser symbol code for the i-th keyword */
    ++static const unsigned char aKWCode[124] = {
    ++  TK_REINDEX,    TK_INDEXED,    TK_INDEX,      TK_DESC,       TK_ESCAPE,     
    ++  TK_EACH,       TK_CHECK,      TK_KEY,        TK_BEFORE,     TK_FOREIGN,    
    ++  TK_FOR,        TK_IGNORE,     TK_LIKE_KW,    TK_EXPLAIN,    TK_INSTEAD,    
    ++  TK_ADD,        TK_DATABASE,   TK_AS,         TK_SELECT,     TK_TABLE,      
    ++  TK_JOIN_KW,    TK_THEN,       TK_END,        TK_DEFERRABLE, TK_ELSE,       
    ++  TK_EXCEPT,     TK_TRANSACTION,TK_ACTION,     TK_ON,         TK_JOIN_KW,    
    ++  TK_ALTER,      TK_RAISE,      TK_EXCLUSIVE,  TK_EXISTS,     TK_SAVEPOINT,  
    ++  TK_INTERSECT,  TK_TRIGGER,    TK_REFERENCES, TK_CONSTRAINT, TK_INTO,       
    ++  TK_OFFSET,     TK_OF,         TK_SET,        TK_TEMP,       TK_TEMP,       
    ++  TK_OR,         TK_UNIQUE,     TK_QUERY,      TK_WITHOUT,    TK_WITH,       
    ++  TK_JOIN_KW,    TK_RELEASE,    TK_ATTACH,     TK_HAVING,     TK_GROUP,      
    ++  TK_UPDATE,     TK_BEGIN,      TK_JOIN_KW,    TK_RECURSIVE,  TK_BETWEEN,    
    ++  TK_NOTNULL,    TK_NOT,        TK_NO,         TK_NULL,       TK_LIKE_KW,    
    ++  TK_CASCADE,    TK_ASC,        TK_DELETE,     TK_CASE,       TK_COLLATE,    
    ++  TK_CREATE,     TK_CTIME_KW,   TK_DETACH,     TK_IMMEDIATE,  TK_JOIN,       
    ++  TK_INSERT,     TK_MATCH,      TK_PLAN,       TK_ANALYZE,    TK_PRAGMA,     
    ++  TK_ABORT,      TK_VALUES,     TK_VIRTUAL,    TK_LIMIT,      TK_WHEN,       
    ++  TK_WHERE,      TK_RENAME,     TK_AFTER,      TK_REPLACE,    TK_AND,        
    ++  TK_DEFAULT,    TK_AUTOINCR,   TK_TO,         TK_IN,         TK_CAST,       
    ++  TK_COLUMNKW,   TK_COMMIT,     TK_CONFLICT,   TK_JOIN_KW,    TK_CTIME_KW,   
    ++  TK_CTIME_KW,   TK_PRIMARY,    TK_DEFERRED,   TK_DISTINCT,   TK_IS,         
    ++  TK_DROP,       TK_FAIL,       TK_FROM,       TK_JOIN_KW,    TK_LIKE_KW,    
    ++  TK_BY,         TK_IF,         TK_ISNULL,     TK_ORDER,      TK_RESTRICT,   
    ++  TK_JOIN_KW,    TK_ROLLBACK,   TK_ROW,        TK_UNION,      TK_USING,      
    ++  TK_VACUUM,     TK_VIEW,       TK_INITIALLY,  TK_ALL,        
    ++};
    ++/* Check to see if z[0..n-1] is a keyword. If it is, write the
    ++** parser symbol code for that keyword into *pType.  Always
    ++** return the integer n (the length of the token). */
    ++static int keywordCode(const char *z, int n, int *pType){
    ++  int i, j;
    ++  const char *zKW;
    ++  if( n>=2 ){
    ++    i = ((charMap(z[0])*4) ^ (charMap(z[n-1])*3) ^ n) % 127;
    ++    for(i=((int)aKWHash[i])-1; i>=0; i=((int)aKWNext[i])-1){
    ++      if( aKWLen[i]!=n ) continue;
    ++      j = 0;
    ++      zKW = &zKWText[aKWOffset[i]];
    ++#ifdef SQLITE_ASCII
    ++      while( j<n && (z[j]&~0x20)==zKW[j] ){ j++; }
    ++#endif
    ++#ifdef SQLITE_EBCDIC
    ++      while( j<n && toupper(z[j])==zKW[j] ){ j++; }
    ++#endif
    ++      if( j<n ) continue;
    +       testcase( i==0 ); /* REINDEX */
    +       testcase( i==1 ); /* INDEXED */
    +       testcase( i==2 ); /* INDEX */
    +@@ -129941,13 +142486,16 @@ static int keywordCode(const char *z, int n){
    +       testcase( i==121 ); /* VIEW */
    +       testcase( i==122 ); /* INITIALLY */
    +       testcase( i==123 ); /* ALL */
    +-      return aCode[i];
    ++      *pType = aKWCode[i];
    ++      break;
    +     }
    +   }
    +-  return TK_ID;
    ++  return n;
    + }
    + SQLITE_PRIVATE int sqlite3KeywordCode(const unsigned char *z, int n){
    +-  return keywordCode((char*)z, n);
    ++  int id = TK_ID;
    ++  keywordCode((char*)z, n, &id);
    ++  return id;
    + }
    + #define SQLITE_N_KEYWORD 124
    + 
    +@@ -130000,13 +142548,15 @@ SQLITE_PRIVATE int sqlite3IsIdChar(u8 c){ return IdChar(c); }
    + 
    + 
    + /*
    +-** Return the length of the token that begins at z[0]. 
    ++** Return the length (in bytes) of the token that begins at z[0]. 
    + ** Store the token type in *tokenType before returning.
    + */
    + SQLITE_PRIVATE int sqlite3GetToken(const unsigned char *z, int *tokenType){
    +   int i, c;
    +-  switch( *z ){
    +-    case ' ': case '\t': case '\n': case '\f': case '\r': {
    ++  switch( aiClass[*z] ){  /* Switch on the character-class of the first byte
    ++                          ** of the token. See the comment on the CC_ defines
    ++                          ** above. */
    ++    case CC_SPACE: {
    +       testcase( z[0]==' ' );
    +       testcase( z[0]=='\t' );
    +       testcase( z[0]=='\n' );
    +@@ -130016,7 +142566,7 @@ SQLITE_PRIVATE int sqlite3GetToken(const unsigned char *z, int *tokenType){
    +       *tokenType = TK_SPACE;
    +       return i;
    +     }
    +-    case '-': {
    ++    case CC_MINUS: {
    +       if( z[1]=='-' ){
    +         for(i=2; (c=z[i])!=0 && c!='\n'; i++){}
    +         *tokenType = TK_SPACE;   /* IMP: R-22934-25134 */
    +@@ -130025,27 +142575,27 @@ SQLITE_PRIVATE int sqlite3GetToken(const unsigned char *z, int *tokenType){
    +       *tokenType = TK_MINUS;
    +       return 1;
    +     }
    +-    case '(': {
    ++    case CC_LP: {
    +       *tokenType = TK_LP;
    +       return 1;
    +     }
    +-    case ')': {
    ++    case CC_RP: {
    +       *tokenType = TK_RP;
    +       return 1;
    +     }
    +-    case ';': {
    ++    case CC_SEMI: {
    +       *tokenType = TK_SEMI;
    +       return 1;
    +     }
    +-    case '+': {
    ++    case CC_PLUS: {
    +       *tokenType = TK_PLUS;
    +       return 1;
    +     }
    +-    case '*': {
    ++    case CC_STAR: {
    +       *tokenType = TK_STAR;
    +       return 1;
    +     }
    +-    case '/': {
    ++    case CC_SLASH: {
    +       if( z[1]!='*' || z[2]==0 ){
    +         *tokenType = TK_SLASH;
    +         return 1;
    +@@ -130055,15 +142605,15 @@ SQLITE_PRIVATE int sqlite3GetToken(const unsigned char *z, int *tokenType){
    +       *tokenType = TK_SPACE;   /* IMP: R-22934-25134 */
    +       return i;
    +     }
    +-    case '%': {
    ++    case CC_PERCENT: {
    +       *tokenType = TK_REM;
    +       return 1;
    +     }
    +-    case '=': {
    ++    case CC_EQ: {
    +       *tokenType = TK_EQ;
    +       return 1 + (z[1]=='=');
    +     }
    +-    case '<': {
    ++    case CC_LT: {
    +       if( (c=z[1])=='=' ){
    +         *tokenType = TK_LE;
    +         return 2;
    +@@ -130078,7 +142628,7 @@ SQLITE_PRIVATE int sqlite3GetToken(const unsigned char *z, int *tokenType){
    +         return 1;
    +       }
    +     }
    +-    case '>': {
    ++    case CC_GT: {
    +       if( (c=z[1])=='=' ){
    +         *tokenType = TK_GE;
    +         return 2;
    +@@ -130090,16 +142640,16 @@ SQLITE_PRIVATE int sqlite3GetToken(const unsigned char *z, int *tokenType){
    +         return 1;
    +       }
    +     }
    +-    case '!': {
    ++    case CC_BANG: {
    +       if( z[1]!='=' ){
    +         *tokenType = TK_ILLEGAL;
    +-        return 2;
    ++        return 1;
    +       }else{
    +         *tokenType = TK_NE;
    +         return 2;
    +       }
    +     }
    +-    case '|': {
    ++    case CC_PIPE: {
    +       if( z[1]!='|' ){
    +         *tokenType = TK_BITOR;
    +         return 1;
    +@@ -130108,21 +142658,19 @@ SQLITE_PRIVATE int sqlite3GetToken(const unsigned char *z, int *tokenType){
    +         return 2;
    +       }
    +     }
    +-    case ',': {
    ++    case CC_COMMA: {
    +       *tokenType = TK_COMMA;
    +       return 1;
    +     }
    +-    case '&': {
    ++    case CC_AND: {
    +       *tokenType = TK_BITAND;
    +       return 1;
    +     }
    +-    case '~': {
    ++    case CC_TILDA: {
    +       *tokenType = TK_BITNOT;
    +       return 1;
    +     }
    +-    case '`':
    +-    case '\'':
    +-    case '"': {
    ++    case CC_QUOTE: {
    +       int delim = z[0];
    +       testcase( delim=='`' );
    +       testcase( delim=='\'' );
    +@@ -130147,7 +142695,7 @@ SQLITE_PRIVATE int sqlite3GetToken(const unsigned char *z, int *tokenType){
    +         return i;
    +       }
    +     }
    +-    case '.': {
    ++    case CC_DOT: {
    + #ifndef SQLITE_OMIT_FLOATING_POINT
    +       if( !sqlite3Isdigit(z[1]) )
    + #endif
    +@@ -130158,8 +142706,7 @@ SQLITE_PRIVATE int sqlite3GetToken(const unsigned char *z, int *tokenType){
    +       /* If the next character is a digit, this is a floating point
    +       ** number that begins with ".".  Fall thru into the next case */
    +     }
    +-    case '0': case '1': case '2': case '3': case '4':
    +-    case '5': case '6': case '7': case '8': case '9': {
    ++    case CC_DIGIT: {
    +       testcase( z[0]=='0' );  testcase( z[0]=='1' );  testcase( z[0]=='2' );
    +       testcase( z[0]=='3' );  testcase( z[0]=='4' );  testcase( z[0]=='5' );
    +       testcase( z[0]=='6' );  testcase( z[0]=='7' );  testcase( z[0]=='8' );
    +@@ -130194,22 +142741,18 @@ SQLITE_PRIVATE int sqlite3GetToken(const unsigned char *z, int *tokenType){
    +       }
    +       return i;
    +     }
    +-    case '[': {
    ++    case CC_QUOTE2: {
    +       for(i=1, c=z[0]; c!=']' && (c=z[i])!=0; i++){}
    +       *tokenType = c==']' ? TK_ID : TK_ILLEGAL;
    +       return i;
    +     }
    +-    case '?': {
    ++    case CC_VARNUM: {
    +       *tokenType = TK_VARIABLE;
    +       for(i=1; sqlite3Isdigit(z[i]); i++){}
    +       return i;
    +     }
    +-#ifndef SQLITE_OMIT_TCL_VARIABLE
    +-    case '$':
    +-#endif
    +-    case '@':  /* For compatibility with MS SQL Server */
    +-    case '#':
    +-    case ':': {
    ++    case CC_DOLLAR:
    ++    case CC_VARALPHA: {
    +       int n = 0;
    +       testcase( z[0]=='$' );  testcase( z[0]=='@' );
    +       testcase( z[0]==':' );  testcase( z[0]=='#' );
    +@@ -130238,8 +142781,20 @@ SQLITE_PRIVATE int sqlite3GetToken(const unsigned char *z, int *tokenType){
    +       if( n==0 ) *tokenType = TK_ILLEGAL;
    +       return i;
    +     }
    ++    case CC_KYWD: {
    ++      for(i=1; aiClass[z[i]]<=CC_KYWD; i++){}
    ++      if( IdChar(z[i]) ){
    ++        /* This token started out using characters that can appear in keywords,
    ++        ** but z[i] is a character not allowed within keywords, so this must
    ++        ** be an identifier instead */
    ++        i++;
    ++        break;
    ++      }
    ++      *tokenType = TK_ID;
    ++      return keywordCode((char*)z, i, tokenType);
    ++    }
    ++    case CC_X: {
    + #ifndef SQLITE_OMIT_BLOB_LITERAL
    +-    case 'x': case 'X': {
    +       testcase( z[0]=='x' ); testcase( z[0]=='X' );
    +       if( z[1]=='\'' ){
    +         *tokenType = TK_BLOB;
    +@@ -130251,20 +142806,22 @@ SQLITE_PRIVATE int sqlite3GetToken(const unsigned char *z, int *tokenType){
    +         if( z[i] ) i++;
    +         return i;
    +       }
    +-      /* Otherwise fall through to the next case */
    +-    }
    + #endif
    ++      /* If it is not a BLOB literal, then it must be an ID, since no
    ++      ** SQL keywords start with the letter 'x'.  Fall through */
    ++    }
    ++    case CC_ID: {
    ++      i = 1;
    ++      break;
    ++    }
    +     default: {
    +-      if( !IdChar(*z) ){
    +-        break;
    +-      }
    +-      for(i=1; IdChar(z[i]); i++){}
    +-      *tokenType = keywordCode((char*)z, i);
    +-      return i;
    ++      *tokenType = TK_ILLEGAL;
    ++      return 1;
    +     }
    +   }
    +-  *tokenType = TK_ILLEGAL;
    +-  return 1;
    ++  while( IdChar(z[i]) ){ i++; }
    ++  *tokenType = TK_ID;
    ++  return i;
    + }
    + 
    + /*
    +@@ -130276,13 +142833,15 @@ SQLITE_PRIVATE int sqlite3GetToken(const unsigned char *z, int *tokenType){
    + */
    + SQLITE_PRIVATE int sqlite3RunParser(Parse *pParse, const char *zSql, char **pzErrMsg){
    +   int nErr = 0;                   /* Number of errors encountered */
    +-  int i;                          /* Loop counter */
    +   void *pEngine;                  /* The LEMON-generated LALR(1) parser */
    ++  int n = 0;                      /* Length of the next token token */
    +   int tokenType;                  /* type of the next token */
    +   int lastTokenParsed = -1;       /* type of the previous token */
    +-  u8 enableLookaside;             /* Saved value of db->lookaside.bEnabled */
    +   sqlite3 *db = pParse->db;       /* The database connection */
    +   int mxSqlLen;                   /* Max length of an SQL string */
    ++#ifdef sqlite3Parser_ENGINEALWAYSONSTACK
    ++  yyParser sEngine;    /* Space to hold the Lemon-generated Parser object */
    ++#endif
    + 
    +   assert( zSql!=0 );
    +   mxSqlLen = db->aLimit[SQLITE_LIMIT_SQL_LENGTH];
    +@@ -130291,81 +142850,78 @@ SQLITE_PRIVATE int sqlite3RunParser(Parse *pParse, const char *zSql, char **pzEr
    +   }
    +   pParse->rc = SQLITE_OK;
    +   pParse->zTail = zSql;
    +-  i = 0;
    +   assert( pzErrMsg!=0 );
    +   /* sqlite3ParserTrace(stdout, "parser: "); */
    ++#ifdef sqlite3Parser_ENGINEALWAYSONSTACK
    ++  pEngine = &sEngine;
    ++  sqlite3ParserInit(pEngine);
    ++#else
    +   pEngine = sqlite3ParserAlloc(sqlite3Malloc);
    +   if( pEngine==0 ){
    +-    db->mallocFailed = 1;
    +-    return SQLITE_NOMEM;
    ++    sqlite3OomFault(db);
    ++    return SQLITE_NOMEM_BKPT;
    +   }
    ++#endif
    +   assert( pParse->pNewTable==0 );
    +   assert( pParse->pNewTrigger==0 );
    +   assert( pParse->nVar==0 );
    +-  assert( pParse->nzVar==0 );
    +-  assert( pParse->azVar==0 );
    +-  enableLookaside = db->lookaside.bEnabled;
    +-  if( db->lookaside.pStart ) db->lookaside.bEnabled = 1;
    +-  while( !db->mallocFailed && zSql[i]!=0 ){
    +-    assert( i>=0 );
    +-    pParse->sLastToken.z = &zSql[i];
    +-    pParse->sLastToken.n = sqlite3GetToken((unsigned char*)&zSql[i],&tokenType);
    +-    i += pParse->sLastToken.n;
    +-    if( i>mxSqlLen ){
    +-      pParse->rc = SQLITE_TOOBIG;
    +-      break;
    +-    }
    +-    switch( tokenType ){
    +-      case TK_SPACE: {
    +-        if( db->u1.isInterrupted ){
    +-          sqlite3ErrorMsg(pParse, "interrupt");
    +-          pParse->rc = SQLITE_INTERRUPT;
    +-          goto abort_parse;
    +-        }
    ++  assert( pParse->pVList==0 );
    ++  while( 1 ){
    ++    if( zSql[0]!=0 ){
    ++      n = sqlite3GetToken((u8*)zSql, &tokenType);
    ++      mxSqlLen -= n;
    ++      if( mxSqlLen<0 ){
    ++        pParse->rc = SQLITE_TOOBIG;
    +         break;
    +       }
    +-      case TK_ILLEGAL: {
    +-        sqlite3ErrorMsg(pParse, "unrecognized token: \"%T\"",
    +-                        &pParse->sLastToken);
    +-        goto abort_parse;
    ++    }else{
    ++      /* Upon reaching the end of input, call the parser two more times
    ++      ** with tokens TK_SEMI and 0, in that order. */
    ++      if( lastTokenParsed==TK_SEMI ){
    ++        tokenType = 0;
    ++      }else if( lastTokenParsed==0 ){
    ++        break;
    ++      }else{
    ++        tokenType = TK_SEMI;
    +       }
    +-      case TK_SEMI: {
    +-        pParse->zTail = &zSql[i];
    +-        /* Fall thru into the default case */
    ++      n = 0;
    ++    }
    ++    if( tokenType>=TK_SPACE ){
    ++      assert( tokenType==TK_SPACE || tokenType==TK_ILLEGAL );
    ++      if( db->u1.isInterrupted ){
    ++        pParse->rc = SQLITE_INTERRUPT;
    ++        break;
    +       }
    +-      default: {
    +-        sqlite3Parser(pEngine, tokenType, pParse->sLastToken, pParse);
    +-        lastTokenParsed = tokenType;
    +-        if( pParse->rc!=SQLITE_OK ){
    +-          goto abort_parse;
    +-        }
    ++      if( tokenType==TK_ILLEGAL ){
    ++        sqlite3ErrorMsg(pParse, "unrecognized token: \"%.*s\"", n, zSql);
    +         break;
    +       }
    ++      zSql += n;
    ++    }else{
    ++      pParse->sLastToken.z = zSql;
    ++      pParse->sLastToken.n = n;
    ++      sqlite3Parser(pEngine, tokenType, pParse->sLastToken, pParse);
    ++      lastTokenParsed = tokenType;
    ++      zSql += n;
    ++      if( pParse->rc!=SQLITE_OK || db->mallocFailed ) break;
    +     }
    +   }
    +-abort_parse:
    +   assert( nErr==0 );
    +-  if( pParse->rc==SQLITE_OK && db->mallocFailed==0 ){
    +-    assert( zSql[i]==0 );
    +-    if( lastTokenParsed!=TK_SEMI ){
    +-      sqlite3Parser(pEngine, TK_SEMI, pParse->sLastToken, pParse);
    +-      pParse->zTail = &zSql[i];
    +-    }
    +-    if( pParse->rc==SQLITE_OK && db->mallocFailed==0 ){
    +-      sqlite3Parser(pEngine, 0, pParse->sLastToken, pParse);
    +-    }
    +-  }
    ++  pParse->zTail = zSql;
    + #ifdef YYTRACKMAXSTACKDEPTH
    +   sqlite3_mutex_enter(sqlite3MallocMutex());
    +-  sqlite3StatusSet(SQLITE_STATUS_PARSER_STACK,
    ++  sqlite3StatusHighwater(SQLITE_STATUS_PARSER_STACK,
    +       sqlite3ParserStackPeak(pEngine)
    +   );
    +   sqlite3_mutex_leave(sqlite3MallocMutex());
    + #endif /* YYDEBUG */
    ++#ifdef sqlite3Parser_ENGINEALWAYSONSTACK
    ++  sqlite3ParserFinalize(pEngine);
    ++#else
    +   sqlite3ParserFree(pEngine, sqlite3_free);
    +-  db->lookaside.bEnabled = enableLookaside;
    ++#endif
    +   if( db->mallocFailed ){
    +-    pParse->rc = SQLITE_NOMEM;
    ++    pParse->rc = SQLITE_NOMEM_BKPT;
    +   }
    +   if( pParse->rc!=SQLITE_OK && pParse->rc!=SQLITE_DONE && pParse->zErrMsg==0 ){
    +     pParse->zErrMsg = sqlite3MPrintf(db, "%s", sqlite3ErrStr(pParse->rc));
    +@@ -130400,14 +142956,13 @@ abort_parse:
    +     sqlite3DeleteTable(db, pParse->pNewTable);
    +   }
    + 
    +-  if( pParse->bFreeWith ) sqlite3WithDelete(db, pParse->pWith);
    ++  if( pParse->pWithToFree ) sqlite3WithDelete(db, pParse->pWithToFree);
    +   sqlite3DeleteTrigger(db, pParse->pNewTrigger);
    +-  for(i=pParse->nzVar-1; i>=0; i--) sqlite3DbFree(db, pParse->azVar[i]);
    +-  sqlite3DbFree(db, pParse->azVar);
    ++  sqlite3DbFree(db, pParse->pVList);
    +   while( pParse->pAinc ){
    +     AutoincInfo *p = pParse->pAinc;
    +     pParse->pAinc = p->pNext;
    +-    sqlite3DbFree(db, p);
    ++    sqlite3DbFreeNN(db, p);
    +   }
    +   while( pParse->pZombieTab ){
    +     Table *p = pParse->pZombieTab;
    +@@ -130523,7 +143078,7 @@ SQLITE_PRIVATE const char sqlite3IsEbcdicIdChar[];
    + ** to recognize the end of a trigger can be omitted.  All we have to do
    + ** is look for a semicolon that is not part of an string or comment.
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_complete(const char *zSql){
    ++SQLITE_API int sqlite3_complete(const char *zSql){
    +   u8 state = 0;   /* Current state, using numbers defined in header comment */
    +   u8 token;       /* Value of the next token */
    + 
    +@@ -130688,7 +143243,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_complete(const char *zSql){
    + ** above, except that the parameter is required to be UTF-16 encoded, not
    + ** UTF-8.
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_complete16(const void *zSql){
    ++SQLITE_API int sqlite3_complete16(const void *zSql){
    +   sqlite3_value *pVal;
    +   char const *zSql8;
    +   int rc;
    +@@ -130703,7 +143258,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_complete16(const void *zSql){
    +   if( zSql8 ){
    +     rc = sqlite3_complete(zSql8);
    +   }else{
    +-    rc = SQLITE_NOMEM;
    ++    rc = SQLITE_NOMEM_BKPT;
    +   }
    +   sqlite3ValueFree(pVal);
    +   return rc & 0xff;
    +@@ -130784,6 +143339,10 @@ SQLITE_PRIVATE int sqlite3Fts3Init(sqlite3 *db);
    + */
    + /* #include "sqlite3.h" */
    + 
    ++#ifdef SQLITE_OMIT_VIRTUALTABLE
    ++# undef SQLITE_ENABLE_RTREE
    ++#endif
    ++
    + #if 0
    + extern "C" {
    + #endif  /* __cplusplus */
    +@@ -130797,7 +143356,7 @@ SQLITE_PRIVATE int sqlite3RtreeInit(sqlite3 *db);
    + /************** End of rtree.h ***********************************************/
    + /************** Continuing where we left off in main.c ***********************/
    + #endif
    +-#ifdef SQLITE_ENABLE_ICU
    ++#if defined(SQLITE_ENABLE_ICU) || defined(SQLITE_ENABLE_ICU_COLLATIONS)
    + /************** Include sqliteicu.h in the middle of main.c ******************/
    + /************** Begin file sqliteicu.h ***************************************/
    + /*
    +@@ -130834,6 +143393,9 @@ SQLITE_PRIVATE int sqlite3IcuInit(sqlite3 *db);
    + #ifdef SQLITE_ENABLE_JSON1
    + SQLITE_PRIVATE int sqlite3Json1Init(sqlite3*);
    + #endif
    ++#ifdef SQLITE_ENABLE_STMTVTAB
    ++SQLITE_PRIVATE int sqlite3StmtVtabInit(sqlite3*);
    ++#endif
    + #ifdef SQLITE_ENABLE_FTS5
    + SQLITE_PRIVATE int sqlite3Fts5Init(sqlite3*);
    + #endif
    +@@ -130848,24 +143410,26 @@ SQLITE_API const char sqlite3_version[] = SQLITE_VERSION;
    + /* IMPLEMENTATION-OF: R-53536-42575 The sqlite3_libversion() function returns
    + ** a pointer to the to the sqlite3_version[] string constant. 
    + */
    +-SQLITE_API const char *SQLITE_STDCALL sqlite3_libversion(void){ return sqlite3_version; }
    ++SQLITE_API const char *sqlite3_libversion(void){ return sqlite3_version; }
    + 
    +-/* IMPLEMENTATION-OF: R-63124-39300 The sqlite3_sourceid() function returns a
    ++/* IMPLEMENTATION-OF: R-25063-23286 The sqlite3_sourceid() function returns a
    + ** pointer to a string constant whose value is the same as the
    +-** SQLITE_SOURCE_ID C preprocessor macro. 
    ++** SQLITE_SOURCE_ID C preprocessor macro. Except if SQLite is built using
    ++** an edited copy of the amalgamation, then the last four characters of
    ++** the hash might be different from SQLITE_SOURCE_ID.
    + */
    +-SQLITE_API const char *SQLITE_STDCALL sqlite3_sourceid(void){ return SQLITE_SOURCE_ID; }
    ++/* SQLITE_API const char *sqlite3_sourceid(void){ return SQLITE_SOURCE_ID; } */
    + 
    + /* IMPLEMENTATION-OF: R-35210-63508 The sqlite3_libversion_number() function
    + ** returns an integer equal to SQLITE_VERSION_NUMBER.
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_libversion_number(void){ return SQLITE_VERSION_NUMBER; }
    ++SQLITE_API int sqlite3_libversion_number(void){ return SQLITE_VERSION_NUMBER; }
    + 
    + /* IMPLEMENTATION-OF: R-20790-14025 The sqlite3_threadsafe() function returns
    + ** zero if and only if SQLite was compiled with mutexing code omitted due to
    + ** the SQLITE_THREADSAFE compile-time option being set to 0.
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_threadsafe(void){ return SQLITE_THREADSAFE; }
    ++SQLITE_API int sqlite3_threadsafe(void){ return SQLITE_THREADSAFE; }
    + 
    + /*
    + ** When compiling the test fixture or with debugging enabled (on Win32),
    +@@ -130938,7 +143502,7 @@ SQLITE_API char *sqlite3_data_directory = 0;
    + **    *  Recursive calls to this routine from thread X return immediately
    + **       without blocking.
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_initialize(void){
    ++SQLITE_API int sqlite3_initialize(void){
    +   MUTEX_LOGIC( sqlite3_mutex *pMaster; )       /* The main static mutex */
    +   int rc;                                      /* Result code */
    + #ifdef SQLITE_EXTRA_INIT
    +@@ -130993,7 +143557,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_initialize(void){
    +       sqlite3GlobalConfig.pInitMutex =
    +            sqlite3MutexAlloc(SQLITE_MUTEX_RECURSIVE);
    +       if( sqlite3GlobalConfig.bCoreMutex && !sqlite3GlobalConfig.pInitMutex ){
    +-        rc = SQLITE_NOMEM;
    ++        rc = SQLITE_NOMEM_BKPT;
    +       }
    +     }
    +   }
    +@@ -131024,10 +143588,15 @@ SQLITE_API int SQLITE_STDCALL sqlite3_initialize(void){
    +   */
    +   sqlite3_mutex_enter(sqlite3GlobalConfig.pInitMutex);
    +   if( sqlite3GlobalConfig.isInit==0 && sqlite3GlobalConfig.inProgress==0 ){
    +-    FuncDefHash *pHash = &GLOBAL(FuncDefHash, sqlite3GlobalFunctions);
    +     sqlite3GlobalConfig.inProgress = 1;
    +-    memset(pHash, 0, sizeof(sqlite3GlobalFunctions));
    +-    sqlite3RegisterGlobalFunctions();
    ++#ifdef SQLITE_ENABLE_SQLLOG
    ++    {
    ++      extern void sqlite3_init_sqllog(void);
    ++      sqlite3_init_sqllog();
    ++    }
    ++#endif
    ++    memset(&sqlite3BuiltinFunctions, 0, sizeof(sqlite3BuiltinFunctions));
    ++    sqlite3RegisterBuiltinFunctions();
    +     if( sqlite3GlobalConfig.isPCacheInit==0 ){
    +       rc = sqlite3PcacheInitialize();
    +     }
    +@@ -131099,7 +143668,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_initialize(void){
    + ** on when SQLite is already shut down.  If SQLite is already shut down
    + ** when this routine is invoked, then this routine is a harmless no-op.
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_shutdown(void){
    ++SQLITE_API int sqlite3_shutdown(void){
    + #ifdef SQLITE_OMIT_WSD
    +   int rc = sqlite3_wsd_init(4096, 24);
    +   if( rc!=SQLITE_OK ){
    +@@ -131153,7 +143722,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_shutdown(void){
    + ** threadsafe.  Failure to heed these warnings can lead to unpredictable
    + ** behavior.
    + */
    +-SQLITE_API int SQLITE_CDECL sqlite3_config(int op, ...){
    ++SQLITE_API int sqlite3_config(int op, ...){
    +   va_list ap;
    +   int rc = SQLITE_OK;
    + 
    +@@ -131234,20 +143803,15 @@ SQLITE_API int SQLITE_CDECL sqlite3_config(int op, ...){
    +       sqlite3GlobalConfig.bMemstat = va_arg(ap, int);
    +       break;
    +     }
    +-    case SQLITE_CONFIG_SCRATCH: {
    +-      /* EVIDENCE-OF: R-08404-60887 There are three arguments to
    +-      ** SQLITE_CONFIG_SCRATCH: A pointer an 8-byte aligned memory buffer from
    +-      ** which the scratch allocations will be drawn, the size of each scratch
    +-      ** allocation (sz), and the maximum number of scratch allocations (N). */
    +-      sqlite3GlobalConfig.pScratch = va_arg(ap, void*);
    +-      sqlite3GlobalConfig.szScratch = va_arg(ap, int);
    +-      sqlite3GlobalConfig.nScratch = va_arg(ap, int);
    ++    case SQLITE_CONFIG_SMALL_MALLOC: {
    ++      sqlite3GlobalConfig.bSmallMalloc = va_arg(ap, int);
    +       break;
    +     }
    +     case SQLITE_CONFIG_PAGECACHE: {
    +-      /* EVIDENCE-OF: R-31408-40510 There are three arguments to
    +-      ** SQLITE_CONFIG_PAGECACHE: A pointer to 8-byte aligned memory, the size
    +-      ** of each page buffer (sz), and the number of pages (N). */
    ++      /* EVIDENCE-OF: R-18761-36601 There are three arguments to
    ++      ** SQLITE_CONFIG_PAGECACHE: A pointer to 8-byte aligned memory (pMem),
    ++      ** the size of each page cache line (sz), and the number of cache lines
    ++      ** (N). */
    +       sqlite3GlobalConfig.pPage = va_arg(ap, void*);
    +       sqlite3GlobalConfig.szPage = va_arg(ap, int);
    +       sqlite3GlobalConfig.nPage = va_arg(ap, int);
    +@@ -131433,6 +143997,11 @@ SQLITE_API int SQLITE_CDECL sqlite3_config(int op, ...){
    +       break;
    +     }
    + 
    ++    case SQLITE_CONFIG_STMTJRNL_SPILL: {
    ++      sqlite3GlobalConfig.nStmtSpill = va_arg(ap, int);
    ++      break;
    ++    }
    ++
    +     default: {
    +       rc = SQLITE_ERROR;
    +       break;
    +@@ -131456,7 +144025,8 @@ SQLITE_API int SQLITE_CDECL sqlite3_config(int op, ...){
    + static int setupLookaside(sqlite3 *db, void *pBuf, int sz, int cnt){
    + #ifndef SQLITE_OMIT_LOOKASIDE
    +   void *pStart;
    +-  if( db->lookaside.nOut ){
    ++  
    ++  if( sqlite3LookasideUsed(db,0)>0 ){
    +     return SQLITE_BUSY;
    +   }
    +   /* Free any existing lookaside buffer for this handle before
    +@@ -131484,26 +144054,29 @@ static int setupLookaside(sqlite3 *db, void *pBuf, int sz, int cnt){
    +     pStart = pBuf;
    +   }
    +   db->lookaside.pStart = pStart;
    ++  db->lookaside.pInit = 0;
    +   db->lookaside.pFree = 0;
    +   db->lookaside.sz = (u16)sz;
    +   if( pStart ){
    +     int i;
    +     LookasideSlot *p;
    +     assert( sz > (int)sizeof(LookasideSlot*) );
    ++    db->lookaside.nSlot = cnt;
    +     p = (LookasideSlot*)pStart;
    +     for(i=cnt-1; i>=0; i--){
    +-      p->pNext = db->lookaside.pFree;
    +-      db->lookaside.pFree = p;
    ++      p->pNext = db->lookaside.pInit;
    ++      db->lookaside.pInit = p;
    +       p = (LookasideSlot*)&((u8*)p)[sz];
    +     }
    +     db->lookaside.pEnd = p;
    +-    db->lookaside.bEnabled = 1;
    ++    db->lookaside.bDisable = 0;
    +     db->lookaside.bMalloced = pBuf==0 ?1:0;
    +   }else{
    +     db->lookaside.pStart = db;
    +     db->lookaside.pEnd = db;
    +-    db->lookaside.bEnabled = 0;
    ++    db->lookaside.bDisable = 1;
    +     db->lookaside.bMalloced = 0;
    ++    db->lookaside.nSlot = 0;
    +   }
    + #endif /* SQLITE_OMIT_LOOKASIDE */
    +   return SQLITE_OK;
    +@@ -131512,7 +144085,7 @@ static int setupLookaside(sqlite3 *db, void *pBuf, int sz, int cnt){
    + /*
    + ** Return the mutex associated with a database connection.
    + */
    +-SQLITE_API sqlite3_mutex *SQLITE_STDCALL sqlite3_db_mutex(sqlite3 *db){
    ++SQLITE_API sqlite3_mutex *sqlite3_db_mutex(sqlite3 *db){
    + #ifdef SQLITE_ENABLE_API_ARMOR
    +   if( !sqlite3SafetyCheckOk(db) ){
    +     (void)SQLITE_MISUSE_BKPT;
    +@@ -131526,7 +144099,7 @@ SQLITE_API sqlite3_mutex *SQLITE_STDCALL sqlite3_db_mutex(sqlite3 *db){
    + ** Free up as much memory as we can from the given database
    + ** connection.
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_db_release_memory(sqlite3 *db){
    ++SQLITE_API int sqlite3_db_release_memory(sqlite3 *db){
    +   int i;
    + 
    + #ifdef SQLITE_ENABLE_API_ARMOR
    +@@ -131546,14 +144119,51 @@ SQLITE_API int SQLITE_STDCALL sqlite3_db_release_memory(sqlite3 *db){
    +   return SQLITE_OK;
    + }
    + 
    ++/*
    ++** Flush any dirty pages in the pager-cache for any attached database
    ++** to disk.
    ++*/
    ++SQLITE_API int sqlite3_db_cacheflush(sqlite3 *db){
    ++  int i;
    ++  int rc = SQLITE_OK;
    ++  int bSeenBusy = 0;
    ++
    ++#ifdef SQLITE_ENABLE_API_ARMOR
    ++  if( !sqlite3SafetyCheckOk(db) ) return SQLITE_MISUSE_BKPT;
    ++#endif
    ++  sqlite3_mutex_enter(db->mutex);
    ++  sqlite3BtreeEnterAll(db);
    ++  for(i=0; rc==SQLITE_OK && i<db->nDb; i++){
    ++    Btree *pBt = db->aDb[i].pBt;
    ++    if( pBt && sqlite3BtreeIsInTrans(pBt) ){
    ++      Pager *pPager = sqlite3BtreePager(pBt);
    ++      rc = sqlite3PagerFlush(pPager);
    ++      if( rc==SQLITE_BUSY ){
    ++        bSeenBusy = 1;
    ++        rc = SQLITE_OK;
    ++      }
    ++    }
    ++  }
    ++  sqlite3BtreeLeaveAll(db);
    ++  sqlite3_mutex_leave(db->mutex);
    ++  return ((rc==SQLITE_OK && bSeenBusy) ? SQLITE_BUSY : rc);
    ++}
    ++
    + /*
    + ** Configuration settings for an individual database connection
    + */
    +-SQLITE_API int SQLITE_CDECL sqlite3_db_config(sqlite3 *db, int op, ...){
    ++SQLITE_API int sqlite3_db_config(sqlite3 *db, int op, ...){
    +   va_list ap;
    +   int rc;
    +   va_start(ap, op);
    +   switch( op ){
    ++    case SQLITE_DBCONFIG_MAINDBNAME: {
    ++      /* IMP: R-06824-28531 */
    ++      /* IMP: R-36257-52125 */
    ++      db->aDb[0].zDbSName = va_arg(ap,char*);
    ++      rc = SQLITE_OK;
    ++      break;
    ++    }
    +     case SQLITE_DBCONFIG_LOOKASIDE: {
    +       void *pBuf = va_arg(ap, void*); /* IMP: R-26835-10964 */
    +       int sz = va_arg(ap, int);       /* IMP: R-47871-25994 */
    +@@ -131566,8 +144176,13 @@ SQLITE_API int SQLITE_CDECL sqlite3_db_config(sqlite3 *db, int op, ...){
    +         int op;      /* The opcode */
    +         u32 mask;    /* Mask of the bit in sqlite3.flags to set/clear */
    +       } aFlagOp[] = {
    +-        { SQLITE_DBCONFIG_ENABLE_FKEY,    SQLITE_ForeignKeys    },
    +-        { SQLITE_DBCONFIG_ENABLE_TRIGGER, SQLITE_EnableTrigger  },
    ++        { SQLITE_DBCONFIG_ENABLE_FKEY,           SQLITE_ForeignKeys    },
    ++        { SQLITE_DBCONFIG_ENABLE_TRIGGER,        SQLITE_EnableTrigger  },
    ++        { SQLITE_DBCONFIG_ENABLE_FTS3_TOKENIZER, SQLITE_Fts3Tokenizer  },
    ++        { SQLITE_DBCONFIG_ENABLE_LOAD_EXTENSION, SQLITE_LoadExtension  },
    ++        { SQLITE_DBCONFIG_NO_CKPT_ON_CLOSE,      SQLITE_NoCkptOnClose  },
    ++        { SQLITE_DBCONFIG_ENABLE_QPSG,           SQLITE_EnableQPSG     },
    ++        { SQLITE_DBCONFIG_TRIGGER_EQP,           SQLITE_TriggerEQP     },
    +       };
    +       unsigned int i;
    +       rc = SQLITE_ERROR; /* IMP: R-42790-23372 */
    +@@ -131575,7 +144190,7 @@ SQLITE_API int SQLITE_CDECL sqlite3_db_config(sqlite3 *db, int op, ...){
    +         if( aFlagOp[i].op==op ){
    +           int onoff = va_arg(ap, int);
    +           int *pRes = va_arg(ap, int*);
    +-          int oldFlags = db->flags;
    ++          u32 oldFlags = db->flags;
    +           if( onoff>0 ){
    +             db->flags |= aFlagOp[i].mask;
    +           }else if( onoff==0 ){
    +@@ -131624,6 +144239,7 @@ static int binCollFunc(
    +   /* EVIDENCE-OF: R-65033-28449 The built-in BINARY collation compares
    +   ** strings byte by byte using the memcmp() function from the standard C
    +   ** library. */
    ++  assert( pKey1 && pKey2 );
    +   rc = memcmp(pKey1, pKey2, n);
    +   if( rc==0 ){
    +     if( padFlag
    +@@ -131668,7 +144284,7 @@ static int nocaseCollatingFunc(
    + /*
    + ** Return the ROWID of the most recent insert
    + */
    +-SQLITE_API sqlite_int64 SQLITE_STDCALL sqlite3_last_insert_rowid(sqlite3 *db){
    ++SQLITE_API sqlite_int64 sqlite3_last_insert_rowid(sqlite3 *db){
    + #ifdef SQLITE_ENABLE_API_ARMOR
    +   if( !sqlite3SafetyCheckOk(db) ){
    +     (void)SQLITE_MISUSE_BKPT;
    +@@ -131678,10 +144294,25 @@ SQLITE_API sqlite_int64 SQLITE_STDCALL sqlite3_last_insert_rowid(sqlite3 *db){
    +   return db->lastRowid;
    + }
    + 
    ++/*
    ++** Set the value returned by the sqlite3_last_insert_rowid() API function.
    ++*/
    ++SQLITE_API void sqlite3_set_last_insert_rowid(sqlite3 *db, sqlite3_int64 iRowid){
    ++#ifdef SQLITE_ENABLE_API_ARMOR
    ++  if( !sqlite3SafetyCheckOk(db) ){
    ++    (void)SQLITE_MISUSE_BKPT;
    ++    return;
    ++  }
    ++#endif
    ++  sqlite3_mutex_enter(db->mutex);
    ++  db->lastRowid = iRowid;
    ++  sqlite3_mutex_leave(db->mutex);
    ++}
    ++
    + /*
    + ** Return the number of changes in the most recent call to sqlite3_exec().
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_changes(sqlite3 *db){
    ++SQLITE_API int sqlite3_changes(sqlite3 *db){
    + #ifdef SQLITE_ENABLE_API_ARMOR
    +   if( !sqlite3SafetyCheckOk(db) ){
    +     (void)SQLITE_MISUSE_BKPT;
    +@@ -131694,7 +144325,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_changes(sqlite3 *db){
    + /*
    + ** Return the number of changes since the database handle was opened.
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_total_changes(sqlite3 *db){
    ++SQLITE_API int sqlite3_total_changes(sqlite3 *db){
    + #ifdef SQLITE_ENABLE_API_ARMOR
    +   if( !sqlite3SafetyCheckOk(db) ){
    +     (void)SQLITE_MISUSE_BKPT;
    +@@ -131727,7 +144358,7 @@ SQLITE_PRIVATE void sqlite3CloseSavepoints(sqlite3 *db){
    + ** with SQLITE_ANY as the encoding.
    + */
    + static void functionDestroy(sqlite3 *db, FuncDef *p){
    +-  FuncDestructor *pDestructor = p->pDestructor;
    ++  FuncDestructor *pDestructor = p->u.pDestructor;
    +   if( pDestructor ){
    +     pDestructor->nRef--;
    +     if( pDestructor->nRef==0 ){
    +@@ -131796,6 +144427,9 @@ static int sqlite3Close(sqlite3 *db, int forceZombie){
    +     return SQLITE_MISUSE_BKPT;
    +   }
    +   sqlite3_mutex_enter(db->mutex);
    ++  if( db->mTrace & SQLITE_TRACE_CLOSE ){
    ++    db->xTrace(SQLITE_TRACE_CLOSE, db->pTraceArg, db, 0);
    ++  }
    + 
    +   /* Force xDisconnect calls on all virtual tables */
    +   disconnectAllVtab(db);
    +@@ -131842,8 +144476,8 @@ static int sqlite3Close(sqlite3 *db, int forceZombie){
    + ** unclosed resources, and arranges for deallocation when the last
    + ** prepare statement or sqlite3_backup closes.
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_close(sqlite3 *db){ return sqlite3Close(db,0); }
    +-SQLITE_API int SQLITE_STDCALL sqlite3_close_v2(sqlite3 *db){ return sqlite3Close(db,1); }
    ++SQLITE_API int sqlite3_close(sqlite3 *db){ return sqlite3Close(db,0); }
    ++SQLITE_API int sqlite3_close_v2(sqlite3 *db){ return sqlite3Close(db,1); }
    + 
    + 
    + /*
    +@@ -131909,18 +144543,17 @@ SQLITE_PRIVATE void sqlite3LeaveMutexAndCloseZombie(sqlite3 *db){
    +   */
    +   sqlite3ConnectionClosed(db);
    + 
    +-  for(j=0; j<ArraySize(db->aFunc.a); j++){
    +-    FuncDef *pNext, *pHash, *p;
    +-    for(p=db->aFunc.a[j]; p; p=pHash){
    +-      pHash = p->pHash;
    +-      while( p ){
    +-        functionDestroy(db, p);
    +-        pNext = p->pNext;
    +-        sqlite3DbFree(db, p);
    +-        p = pNext;
    +-      }
    +-    }
    ++  for(i=sqliteHashFirst(&db->aFunc); i; i=sqliteHashNext(i)){
    ++    FuncDef *pNext, *p;
    ++    p = sqliteHashData(i);
    ++    do{
    ++      functionDestroy(db, p);
    ++      pNext = p->pNext;
    ++      sqlite3DbFree(db, p);
    ++      p = pNext;
    ++    }while( p );
    +   }
    ++  sqlite3HashClear(&db->aFunc);
    +   for(i=sqliteHashFirst(&db->aCollSeq); i; i=sqliteHashNext(i)){
    +     CollSeq *pColl = (CollSeq *)sqliteHashData(i);
    +     /* Invoke any destructors registered for collation sequence user data. */
    +@@ -131964,7 +144597,7 @@ SQLITE_PRIVATE void sqlite3LeaveMutexAndCloseZombie(sqlite3 *db){
    +   sqlite3_mutex_leave(db->mutex);
    +   db->magic = SQLITE_MAGIC_CLOSED;
    +   sqlite3_mutex_free(db->mutex);
    +-  assert( db->lookaside.nOut==0 );  /* Fails on a lookaside memory leak */
    ++  assert( sqlite3LookasideUsed(db,0)==0 );
    +   if( db->lookaside.bMalloced ){
    +     sqlite3_free(db->lookaside.pStart);
    +   }
    +@@ -131992,7 +144625,7 @@ SQLITE_PRIVATE void sqlite3RollbackAll(sqlite3 *db, int tripCode){
    +   ** the database rollback and schema reset, which can cause false
    +   ** corruption reports in some cases.  */
    +   sqlite3BtreeEnterAll(db);
    +-  schemaChange = (db->flags & SQLITE_InternChanges)!=0 && db->init.busy==0;
    ++  schemaChange = (db->mDbFlags & DBFLAG_SchemaChange)!=0 && db->init.busy==0;
    + 
    +   for(i=0; i<db->nDb; i++){
    +     Btree *p = db->aDb[i].pBt;
    +@@ -132006,7 +144639,7 @@ SQLITE_PRIVATE void sqlite3RollbackAll(sqlite3 *db, int tripCode){
    +   sqlite3VtabRollback(db);
    +   sqlite3EndBenignMalloc();
    + 
    +-  if( (db->flags&SQLITE_InternChanges)!=0 && db->init.busy==0 ){
    ++  if( (db->mDbFlags&DBFLAG_SchemaChange)!=0 && db->init.busy==0 ){
    +     sqlite3ExpirePreparedStatements(db);
    +     sqlite3ResetAllSchemasOfConnection(db);
    +   }
    +@@ -132047,9 +144680,10 @@ SQLITE_PRIVATE const char *sqlite3ErrName(int rc){
    +       case SQLITE_NOMEM:              zName = "SQLITE_NOMEM";             break;
    +       case SQLITE_READONLY:           zName = "SQLITE_READONLY";          break;
    +       case SQLITE_READONLY_RECOVERY:  zName = "SQLITE_READONLY_RECOVERY"; break;
    +-      case SQLITE_READONLY_CANTLOCK:  zName = "SQLITE_READONLY_CANTLOCK"; break;
    ++      case SQLITE_READONLY_CANTINIT:  zName = "SQLITE_READONLY_CANTINIT"; break;
    +       case SQLITE_READONLY_ROLLBACK:  zName = "SQLITE_READONLY_ROLLBACK"; break;
    +       case SQLITE_READONLY_DBMOVED:   zName = "SQLITE_READONLY_DBMOVED";  break;
    ++      case SQLITE_READONLY_DIRECTORY: zName = "SQLITE_READONLY_DIRECTORY";break;
    +       case SQLITE_INTERRUPT:          zName = "SQLITE_INTERRUPT";         break;
    +       case SQLITE_IOERR:              zName = "SQLITE_IOERR";             break;
    +       case SQLITE_IOERR_READ:         zName = "SQLITE_IOERR_READ";        break;
    +@@ -132139,10 +144773,10 @@ SQLITE_PRIVATE const char *sqlite3ErrName(int rc){
    + SQLITE_PRIVATE const char *sqlite3ErrStr(int rc){
    +   static const char* const aMsg[] = {
    +     /* SQLITE_OK          */ "not an error",
    +-    /* SQLITE_ERROR       */ "SQL logic error or missing database",
    ++    /* SQLITE_ERROR       */ "SQL logic error",
    +     /* SQLITE_INTERNAL    */ 0,
    +     /* SQLITE_PERM        */ "access permission denied",
    +-    /* SQLITE_ABORT       */ "callback requested query abort",
    ++    /* SQLITE_ABORT       */ "query aborted",
    +     /* SQLITE_BUSY        */ "database is locked",
    +     /* SQLITE_LOCKED      */ "database table is locked",
    +     /* SQLITE_NOMEM       */ "out of memory",
    +@@ -132154,17 +144788,21 @@ SQLITE_PRIVATE const char *sqlite3ErrStr(int rc){
    +     /* SQLITE_FULL        */ "database or disk is full",
    +     /* SQLITE_CANTOPEN    */ "unable to open database file",
    +     /* SQLITE_PROTOCOL    */ "locking protocol",
    +-    /* SQLITE_EMPTY       */ "table contains no data",
    ++    /* SQLITE_EMPTY       */ 0,
    +     /* SQLITE_SCHEMA      */ "database schema has changed",
    +     /* SQLITE_TOOBIG      */ "string or blob too big",
    +     /* SQLITE_CONSTRAINT  */ "constraint failed",
    +     /* SQLITE_MISMATCH    */ "datatype mismatch",
    +-    /* SQLITE_MISUSE      */ "library routine called out of sequence",
    ++    /* SQLITE_MISUSE      */ "bad parameter or other API misuse",
    ++#ifdef SQLITE_DISABLE_LFS
    +     /* SQLITE_NOLFS       */ "large file support is disabled",
    ++#else
    ++    /* SQLITE_NOLFS       */ 0,
    ++#endif
    +     /* SQLITE_AUTH        */ "authorization denied",
    +-    /* SQLITE_FORMAT      */ "auxiliary database format error",
    +-    /* SQLITE_RANGE       */ "bind or column index out of range",
    +-    /* SQLITE_NOTADB      */ "file is encrypted or is not a database",
    ++    /* SQLITE_FORMAT      */ 0,
    ++    /* SQLITE_RANGE       */ "column index out of range",
    ++    /* SQLITE_NOTADB      */ "file is not a database",
    +   };
    +   const char *zErr = "unknown error";
    +   switch( rc ){
    +@@ -132251,7 +144889,7 @@ SQLITE_PRIVATE int sqlite3InvokeBusyHandler(BusyHandler *p){
    + ** This routine sets the busy callback for an Sqlite database to the
    + ** given callback function with the given argument.
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_busy_handler(
    ++SQLITE_API int sqlite3_busy_handler(
    +   sqlite3 *db,
    +   int (*xBusy)(void*,int),
    +   void *pArg
    +@@ -132274,7 +144912,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_busy_handler(
    + ** given callback function with the given argument. The progress callback will
    + ** be invoked every nOps opcodes.
    + */
    +-SQLITE_API void SQLITE_STDCALL sqlite3_progress_handler(
    ++SQLITE_API void sqlite3_progress_handler(
    +   sqlite3 *db, 
    +   int nOps,
    +   int (*xProgress)(void*), 
    +@@ -132305,7 +144943,7 @@ SQLITE_API void SQLITE_STDCALL sqlite3_progress_handler(
    + ** This routine installs a default busy handler that waits for the
    + ** specified number of milliseconds before returning 0.
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_busy_timeout(sqlite3 *db, int ms){
    ++SQLITE_API int sqlite3_busy_timeout(sqlite3 *db, int ms){
    + #ifdef SQLITE_ENABLE_API_ARMOR
    +   if( !sqlite3SafetyCheckOk(db) ) return SQLITE_MISUSE_BKPT;
    + #endif
    +@@ -132321,9 +144959,9 @@ SQLITE_API int SQLITE_STDCALL sqlite3_busy_timeout(sqlite3 *db, int ms){
    + /*
    + ** Cause any pending operation to stop at its earliest opportunity.
    + */
    +-SQLITE_API void SQLITE_STDCALL sqlite3_interrupt(sqlite3 *db){
    ++SQLITE_API void sqlite3_interrupt(sqlite3 *db){
    + #ifdef SQLITE_ENABLE_API_ARMOR
    +-  if( !sqlite3SafetyCheckOk(db) ){
    ++  if( !sqlite3SafetyCheckOk(db) && (db==0 || db->magic!=SQLITE_MAGIC_ZOMBIE) ){
    +     (void)SQLITE_MISUSE_BKPT;
    +     return;
    +   }
    +@@ -132344,7 +144982,7 @@ SQLITE_PRIVATE int sqlite3CreateFunc(
    +   int nArg,
    +   int enc,
    +   void *pUserData,
    +-  void (*xFunc)(sqlite3_context*,int,sqlite3_value **),
    ++  void (*xSFunc)(sqlite3_context*,int,sqlite3_value **),
    +   void (*xStep)(sqlite3_context*,int,sqlite3_value **),
    +   void (*xFinal)(sqlite3_context*),
    +   FuncDestructor *pDestructor
    +@@ -132355,9 +144993,9 @@ SQLITE_PRIVATE int sqlite3CreateFunc(
    + 
    +   assert( sqlite3_mutex_held(db->mutex) );
    +   if( zFunctionName==0 ||
    +-      (xFunc && (xFinal || xStep)) || 
    +-      (!xFunc && (xFinal && !xStep)) ||
    +-      (!xFunc && (!xFinal && xStep)) ||
    ++      (xSFunc && (xFinal || xStep)) || 
    ++      (!xSFunc && (xFinal && !xStep)) ||
    ++      (!xSFunc && (!xFinal && xStep)) ||
    +       (nArg<-1 || nArg>SQLITE_MAX_FUNCTION_ARG) ||
    +       (255<(nName = sqlite3Strlen30( zFunctionName))) ){
    +     return SQLITE_MISUSE_BKPT;
    +@@ -132380,10 +145018,10 @@ SQLITE_PRIVATE int sqlite3CreateFunc(
    +   }else if( enc==SQLITE_ANY ){
    +     int rc;
    +     rc = sqlite3CreateFunc(db, zFunctionName, nArg, SQLITE_UTF8|extraFlags,
    +-         pUserData, xFunc, xStep, xFinal, pDestructor);
    ++         pUserData, xSFunc, xStep, xFinal, pDestructor);
    +     if( rc==SQLITE_OK ){
    +       rc = sqlite3CreateFunc(db, zFunctionName, nArg, SQLITE_UTF16LE|extraFlags,
    +-          pUserData, xFunc, xStep, xFinal, pDestructor);
    ++          pUserData, xSFunc, xStep, xFinal, pDestructor);
    +     }
    +     if( rc!=SQLITE_OK ){
    +       return rc;
    +@@ -132399,7 +145037,7 @@ SQLITE_PRIVATE int sqlite3CreateFunc(
    +   ** is being overridden/deleted but there are no active VMs, allow the
    +   ** operation to continue but invalidate all precompiled statements.
    +   */
    +-  p = sqlite3FindFunction(db, zFunctionName, nName, nArg, (u8)enc, 0);
    ++  p = sqlite3FindFunction(db, zFunctionName, nArg, (u8)enc, 0);
    +   if( p && (p->funcFlags & SQLITE_FUNC_ENCMASK)==enc && p->nArg==nArg ){
    +     if( db->nVdbeActive ){
    +       sqlite3ErrorWithMsg(db, SQLITE_BUSY, 
    +@@ -132411,10 +145049,10 @@ SQLITE_PRIVATE int sqlite3CreateFunc(
    +     }
    +   }
    + 
    +-  p = sqlite3FindFunction(db, zFunctionName, nName, nArg, (u8)enc, 1);
    ++  p = sqlite3FindFunction(db, zFunctionName, nArg, (u8)enc, 1);
    +   assert(p || db->mallocFailed);
    +   if( !p ){
    +-    return SQLITE_NOMEM;
    ++    return SQLITE_NOMEM_BKPT;
    +   }
    + 
    +   /* If an older version of the function with a configured destructor is
    +@@ -132424,11 +145062,10 @@ SQLITE_PRIVATE int sqlite3CreateFunc(
    +   if( pDestructor ){
    +     pDestructor->nRef++;
    +   }
    +-  p->pDestructor = pDestructor;
    ++  p->u.pDestructor = pDestructor;
    +   p->funcFlags = (p->funcFlags & SQLITE_FUNC_ENCMASK) | extraFlags;
    +   testcase( p->funcFlags & SQLITE_DETERMINISTIC );
    +-  p->xFunc = xFunc;
    +-  p->xStep = xStep;
    ++  p->xSFunc = xSFunc ? xSFunc : xStep;
    +   p->xFinalize = xFinal;
    +   p->pUserData = pUserData;
    +   p->nArg = (u16)nArg;
    +@@ -132438,27 +145075,27 @@ SQLITE_PRIVATE int sqlite3CreateFunc(
    + /*
    + ** Create new user functions.
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_create_function(
    ++SQLITE_API int sqlite3_create_function(
    +   sqlite3 *db,
    +   const char *zFunc,
    +   int nArg,
    +   int enc,
    +   void *p,
    +-  void (*xFunc)(sqlite3_context*,int,sqlite3_value **),
    ++  void (*xSFunc)(sqlite3_context*,int,sqlite3_value **),
    +   void (*xStep)(sqlite3_context*,int,sqlite3_value **),
    +   void (*xFinal)(sqlite3_context*)
    + ){
    +-  return sqlite3_create_function_v2(db, zFunc, nArg, enc, p, xFunc, xStep,
    ++  return sqlite3_create_function_v2(db, zFunc, nArg, enc, p, xSFunc, xStep,
    +                                     xFinal, 0);
    + }
    + 
    +-SQLITE_API int SQLITE_STDCALL sqlite3_create_function_v2(
    ++SQLITE_API int sqlite3_create_function_v2(
    +   sqlite3 *db,
    +   const char *zFunc,
    +   int nArg,
    +   int enc,
    +   void *p,
    +-  void (*xFunc)(sqlite3_context*,int,sqlite3_value **),
    ++  void (*xSFunc)(sqlite3_context*,int,sqlite3_value **),
    +   void (*xStep)(sqlite3_context*,int,sqlite3_value **),
    +   void (*xFinal)(sqlite3_context*),
    +   void (*xDestroy)(void *)
    +@@ -132481,7 +145118,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_create_function_v2(
    +     pArg->xDestroy = xDestroy;
    +     pArg->pUserData = p;
    +   }
    +-  rc = sqlite3CreateFunc(db, zFunc, nArg, enc, p, xFunc, xStep, xFinal, pArg);
    ++  rc = sqlite3CreateFunc(db, zFunc, nArg, enc, p, xSFunc, xStep, xFinal, pArg);
    +   if( pArg && pArg->nRef==0 ){
    +     assert( rc!=SQLITE_OK );
    +     xDestroy(p);
    +@@ -132495,13 +145132,13 @@ SQLITE_API int SQLITE_STDCALL sqlite3_create_function_v2(
    + }
    + 
    + #ifndef SQLITE_OMIT_UTF16
    +-SQLITE_API int SQLITE_STDCALL sqlite3_create_function16(
    ++SQLITE_API int sqlite3_create_function16(
    +   sqlite3 *db,
    +   const void *zFunctionName,
    +   int nArg,
    +   int eTextRep,
    +   void *p,
    +-  void (*xFunc)(sqlite3_context*,int,sqlite3_value**),
    ++  void (*xSFunc)(sqlite3_context*,int,sqlite3_value**),
    +   void (*xStep)(sqlite3_context*,int,sqlite3_value**),
    +   void (*xFinal)(sqlite3_context*)
    + ){
    +@@ -132514,7 +145151,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_create_function16(
    +   sqlite3_mutex_enter(db->mutex);
    +   assert( !db->mallocFailed );
    +   zFunc8 = sqlite3Utf16to8(db, zFunctionName, -1, SQLITE_UTF16NATIVE);
    +-  rc = sqlite3CreateFunc(db, zFunc8, nArg, eTextRep, p, xFunc, xStep, xFinal,0);
    ++  rc = sqlite3CreateFunc(db, zFunc8, nArg, eTextRep, p, xSFunc,xStep,xFinal,0);
    +   sqlite3DbFree(db, zFunc8);
    +   rc = sqlite3ApiExit(db, rc);
    +   sqlite3_mutex_leave(db->mutex);
    +@@ -132535,12 +145172,11 @@ SQLITE_API int SQLITE_STDCALL sqlite3_create_function16(
    + ** A global function must exist in order for name resolution to work
    + ** properly.
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_overload_function(
    ++SQLITE_API int sqlite3_overload_function(
    +   sqlite3 *db,
    +   const char *zName,
    +   int nArg
    + ){
    +-  int nName = sqlite3Strlen30(zName);
    +   int rc = SQLITE_OK;
    + 
    + #ifdef SQLITE_ENABLE_API_ARMOR
    +@@ -132549,7 +145185,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_overload_function(
    +   }
    + #endif
    +   sqlite3_mutex_enter(db->mutex);
    +-  if( sqlite3FindFunction(db, zName, nName, nArg, SQLITE_UTF8, 0)==0 ){
    ++  if( sqlite3FindFunction(db, zName, nArg, SQLITE_UTF8, 0)==0 ){
    +     rc = sqlite3CreateFunc(db, zName, nArg, SQLITE_UTF8,
    +                            0, sqlite3InvalidFunction, 0, 0, 0);
    +   }
    +@@ -132567,7 +145203,8 @@ SQLITE_API int SQLITE_STDCALL sqlite3_overload_function(
    + ** trace is a pointer to a function that is invoked at the start of each
    + ** SQL statement.
    + */
    +-SQLITE_API void *SQLITE_STDCALL sqlite3_trace(sqlite3 *db, void (*xTrace)(void*,const char*), void *pArg){
    ++#ifndef SQLITE_OMIT_DEPRECATED
    ++SQLITE_API void *sqlite3_trace(sqlite3 *db, void(*xTrace)(void*,const char*), void *pArg){
    +   void *pOld;
    + 
    + #ifdef SQLITE_ENABLE_API_ARMOR
    +@@ -132578,11 +145215,38 @@ SQLITE_API void *SQLITE_STDCALL sqlite3_trace(sqlite3 *db, void (*xTrace)(void*,
    + #endif
    +   sqlite3_mutex_enter(db->mutex);
    +   pOld = db->pTraceArg;
    +-  db->xTrace = xTrace;
    ++  db->mTrace = xTrace ? SQLITE_TRACE_LEGACY : 0;
    ++  db->xTrace = (int(*)(u32,void*,void*,void*))xTrace;
    +   db->pTraceArg = pArg;
    +   sqlite3_mutex_leave(db->mutex);
    +   return pOld;
    + }
    ++#endif /* SQLITE_OMIT_DEPRECATED */
    ++
    ++/* Register a trace callback using the version-2 interface.
    ++*/
    ++SQLITE_API int sqlite3_trace_v2(
    ++  sqlite3 *db,                               /* Trace this connection */
    ++  unsigned mTrace,                           /* Mask of events to be traced */
    ++  int(*xTrace)(unsigned,void*,void*,void*),  /* Callback to invoke */
    ++  void *pArg                                 /* Context */
    ++){
    ++#ifdef SQLITE_ENABLE_API_ARMOR
    ++  if( !sqlite3SafetyCheckOk(db) ){
    ++    return SQLITE_MISUSE_BKPT;
    ++  }
    ++#endif
    ++  sqlite3_mutex_enter(db->mutex);
    ++  if( mTrace==0 ) xTrace = 0;
    ++  if( xTrace==0 ) mTrace = 0;
    ++  db->mTrace = mTrace;
    ++  db->xTrace = xTrace;
    ++  db->pTraceArg = pArg;
    ++  sqlite3_mutex_leave(db->mutex);
    ++  return SQLITE_OK;
    ++}
    ++
    ++#ifndef SQLITE_OMIT_DEPRECATED
    + /*
    + ** Register a profile function.  The pArg from the previously registered 
    + ** profile function is returned.  
    +@@ -132591,7 +145255,7 @@ SQLITE_API void *SQLITE_STDCALL sqlite3_trace(sqlite3 *db, void (*xTrace)(void*,
    + ** profile is a pointer to a function that is invoked at the conclusion of
    + ** each SQL statement that is run.
    + */
    +-SQLITE_API void *SQLITE_STDCALL sqlite3_profile(
    ++SQLITE_API void *sqlite3_profile(
    +   sqlite3 *db,
    +   void (*xProfile)(void*,const char*,sqlite_uint64),
    +   void *pArg
    +@@ -132611,6 +145275,7 @@ SQLITE_API void *SQLITE_STDCALL sqlite3_profile(
    +   sqlite3_mutex_leave(db->mutex);
    +   return pOld;
    + }
    ++#endif /* SQLITE_OMIT_DEPRECATED */
    + #endif /* SQLITE_OMIT_TRACE */
    + 
    + /*
    +@@ -132618,7 +145283,7 @@ SQLITE_API void *SQLITE_STDCALL sqlite3_profile(
    + ** If the invoked function returns non-zero, then the commit becomes a
    + ** rollback.
    + */
    +-SQLITE_API void *SQLITE_STDCALL sqlite3_commit_hook(
    ++SQLITE_API void *sqlite3_commit_hook(
    +   sqlite3 *db,              /* Attach the hook to this database */
    +   int (*xCallback)(void*),  /* Function to invoke on each commit */
    +   void *pArg                /* Argument to the function */
    +@@ -132643,7 +145308,7 @@ SQLITE_API void *SQLITE_STDCALL sqlite3_commit_hook(
    + ** Register a callback to be invoked each time a row is updated,
    + ** inserted or deleted using this database connection.
    + */
    +-SQLITE_API void *SQLITE_STDCALL sqlite3_update_hook(
    ++SQLITE_API void *sqlite3_update_hook(
    +   sqlite3 *db,              /* Attach the hook to this database */
    +   void (*xCallback)(void*,int,char const *,char const *,sqlite_int64),
    +   void *pArg                /* Argument to the function */
    +@@ -132668,7 +145333,7 @@ SQLITE_API void *SQLITE_STDCALL sqlite3_update_hook(
    + ** Register a callback to be invoked each time a transaction is rolled
    + ** back by this database connection.
    + */
    +-SQLITE_API void *SQLITE_STDCALL sqlite3_rollback_hook(
    ++SQLITE_API void *sqlite3_rollback_hook(
    +   sqlite3 *db,              /* Attach the hook to this database */
    +   void (*xCallback)(void*), /* Callback function */
    +   void *pArg                /* Argument to the function */
    +@@ -132689,6 +145354,27 @@ SQLITE_API void *SQLITE_STDCALL sqlite3_rollback_hook(
    +   return pRet;
    + }
    + 
    ++#ifdef SQLITE_ENABLE_PREUPDATE_HOOK
    ++/*
    ++** Register a callback to be invoked each time a row is updated,
    ++** inserted or deleted using this database connection.
    ++*/
    ++SQLITE_API void *sqlite3_preupdate_hook(
    ++  sqlite3 *db,              /* Attach the hook to this database */
    ++  void(*xCallback)(         /* Callback function */
    ++    void*,sqlite3*,int,char const*,char const*,sqlite3_int64,sqlite3_int64),
    ++  void *pArg                /* First callback argument */
    ++){
    ++  void *pRet;
    ++  sqlite3_mutex_enter(db->mutex);
    ++  pRet = db->pPreUpdateArg;
    ++  db->xPreUpdateCallback = xCallback;
    ++  db->pPreUpdateArg = pArg;
    ++  sqlite3_mutex_leave(db->mutex);
    ++  return pRet;
    ++}
    ++#endif /* SQLITE_ENABLE_PREUPDATE_HOOK */
    ++
    + #ifndef SQLITE_OMIT_WAL
    + /*
    + ** The sqlite3_wal_hook() callback registered by sqlite3_wal_autocheckpoint().
    +@@ -132722,7 +145408,7 @@ SQLITE_PRIVATE int sqlite3WalDefaultHook(
    + ** using sqlite3_wal_hook() disables the automatic checkpoint mechanism
    + ** configured by this function.
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_wal_autocheckpoint(sqlite3 *db, int nFrame){
    ++SQLITE_API int sqlite3_wal_autocheckpoint(sqlite3 *db, int nFrame){
    + #ifdef SQLITE_OMIT_WAL
    +   UNUSED_PARAMETER(db);
    +   UNUSED_PARAMETER(nFrame);
    +@@ -132743,7 +145429,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_wal_autocheckpoint(sqlite3 *db, int nFrame
    + ** Register a callback to be invoked each time a transaction is written
    + ** into the write-ahead-log by this database connection.
    + */
    +-SQLITE_API void *SQLITE_STDCALL sqlite3_wal_hook(
    ++SQLITE_API void *sqlite3_wal_hook(
    +   sqlite3 *db,                    /* Attach the hook to this db handle */
    +   int(*xCallback)(void *, sqlite3*, const char*, int),
    +   void *pArg                      /* First argument passed to xCallback() */
    +@@ -132770,7 +145456,7 @@ SQLITE_API void *SQLITE_STDCALL sqlite3_wal_hook(
    + /*
    + ** Checkpoint database zDb.
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_wal_checkpoint_v2(
    ++SQLITE_API int sqlite3_wal_checkpoint_v2(
    +   sqlite3 *db,                    /* Database handle */
    +   const char *zDb,                /* Name of attached database (or NULL) */
    +   int eMode,                      /* SQLITE_CHECKPOINT_* value */
    +@@ -132814,6 +145500,13 @@ SQLITE_API int SQLITE_STDCALL sqlite3_wal_checkpoint_v2(
    +     sqlite3Error(db, rc);
    +   }
    +   rc = sqlite3ApiExit(db, rc);
    ++
    ++  /* If there are no active statements, clear the interrupt flag at this
    ++  ** point.  */
    ++  if( db->nVdbeActive==0 ){
    ++    db->u1.isInterrupted = 0;
    ++  }
    ++
    +   sqlite3_mutex_leave(db->mutex);
    +   return rc;
    + #endif
    +@@ -132825,7 +145518,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_wal_checkpoint_v2(
    + ** to contains a zero-length string, all attached databases are 
    + ** checkpointed.
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_wal_checkpoint(sqlite3 *db, const char *zDb){
    ++SQLITE_API int sqlite3_wal_checkpoint(sqlite3 *db, const char *zDb){
    +   /* EVIDENCE-OF: R-41613-20553 The sqlite3_wal_checkpoint(D,X) is equivalent to
    +   ** sqlite3_wal_checkpoint_v2(D,X,SQLITE_CHECKPOINT_PASSIVE,0,0). */
    +   return sqlite3_wal_checkpoint_v2(db,zDb,SQLITE_CHECKPOINT_PASSIVE,0,0);
    +@@ -132849,7 +145542,8 @@ SQLITE_API int SQLITE_STDCALL sqlite3_wal_checkpoint(sqlite3 *db, const char *zD
    + ** checkpointed. If an error is encountered it is returned immediately -
    + ** no attempt is made to checkpoint any remaining databases.
    + **
    +-** Parameter eMode is one of SQLITE_CHECKPOINT_PASSIVE, FULL or RESTART.
    ++** Parameter eMode is one of SQLITE_CHECKPOINT_PASSIVE, FULL, RESTART
    ++** or TRUNCATE.
    + */
    + SQLITE_PRIVATE int sqlite3Checkpoint(sqlite3 *db, int iDb, int eMode, int *pnLog, int *pnCkpt){
    +   int rc = SQLITE_OK;             /* Return code */
    +@@ -132916,17 +145610,17 @@ SQLITE_PRIVATE int sqlite3TempInMemory(const sqlite3 *db){
    + ** Return UTF-8 encoded English language explanation of the most recent
    + ** error.
    + */
    +-SQLITE_API const char *SQLITE_STDCALL sqlite3_errmsg(sqlite3 *db){
    ++SQLITE_API const char *sqlite3_errmsg(sqlite3 *db){
    +   const char *z;
    +   if( !db ){
    +-    return sqlite3ErrStr(SQLITE_NOMEM);
    ++    return sqlite3ErrStr(SQLITE_NOMEM_BKPT);
    +   }
    +   if( !sqlite3SafetyCheckSickOrOk(db) ){
    +     return sqlite3ErrStr(SQLITE_MISUSE_BKPT);
    +   }
    +   sqlite3_mutex_enter(db->mutex);
    +   if( db->mallocFailed ){
    +-    z = sqlite3ErrStr(SQLITE_NOMEM);
    ++    z = sqlite3ErrStr(SQLITE_NOMEM_BKPT);
    +   }else{
    +     testcase( db->pErr==0 );
    +     z = (char*)sqlite3_value_text(db->pErr);
    +@@ -132944,17 +145638,14 @@ SQLITE_API const char *SQLITE_STDCALL sqlite3_errmsg(sqlite3 *db){
    + ** Return UTF-16 encoded English language explanation of the most recent
    + ** error.
    + */
    +-SQLITE_API const void *SQLITE_STDCALL sqlite3_errmsg16(sqlite3 *db){
    ++SQLITE_API const void *sqlite3_errmsg16(sqlite3 *db){
    +   static const u16 outOfMem[] = {
    +     'o', 'u', 't', ' ', 'o', 'f', ' ', 'm', 'e', 'm', 'o', 'r', 'y', 0
    +   };
    +   static const u16 misuse[] = {
    +-    'l', 'i', 'b', 'r', 'a', 'r', 'y', ' ', 
    +-    'r', 'o', 'u', 't', 'i', 'n', 'e', ' ', 
    +-    'c', 'a', 'l', 'l', 'e', 'd', ' ', 
    +-    'o', 'u', 't', ' ', 
    +-    'o', 'f', ' ', 
    +-    's', 'e', 'q', 'u', 'e', 'n', 'c', 'e', 0
    ++    'b', 'a', 'd', ' ', 'p', 'a', 'r', 'a', 'm', 'e', 't', 'e', 'r', ' ',
    ++    'o', 'r', ' ', 'o', 't', 'h', 'e', 'r', ' ', 'A', 'P', 'I', ' ',
    ++    'm', 'i', 's', 'u', 's', 'e', 0
    +   };
    + 
    +   const void *z;
    +@@ -132978,7 +145669,7 @@ SQLITE_API const void *SQLITE_STDCALL sqlite3_errmsg16(sqlite3 *db){
    +     ** be cleared before returning. Do this directly, instead of via
    +     ** sqlite3ApiExit(), to avoid setting the database handle error message.
    +     */
    +-    db->mallocFailed = 0;
    ++    sqlite3OomClear(db);
    +   }
    +   sqlite3_mutex_leave(db->mutex);
    +   return z;
    +@@ -132989,31 +145680,34 @@ SQLITE_API const void *SQLITE_STDCALL sqlite3_errmsg16(sqlite3 *db){
    + ** Return the most recent error code generated by an SQLite routine. If NULL is
    + ** passed to this function, we assume a malloc() failed during sqlite3_open().
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_errcode(sqlite3 *db){
    ++SQLITE_API int sqlite3_errcode(sqlite3 *db){
    +   if( db && !sqlite3SafetyCheckSickOrOk(db) ){
    +     return SQLITE_MISUSE_BKPT;
    +   }
    +   if( !db || db->mallocFailed ){
    +-    return SQLITE_NOMEM;
    ++    return SQLITE_NOMEM_BKPT;
    +   }
    +   return db->errCode & db->errMask;
    + }
    +-SQLITE_API int SQLITE_STDCALL sqlite3_extended_errcode(sqlite3 *db){
    ++SQLITE_API int sqlite3_extended_errcode(sqlite3 *db){
    +   if( db && !sqlite3SafetyCheckSickOrOk(db) ){
    +     return SQLITE_MISUSE_BKPT;
    +   }
    +   if( !db || db->mallocFailed ){
    +-    return SQLITE_NOMEM;
    ++    return SQLITE_NOMEM_BKPT;
    +   }
    +   return db->errCode;
    + }
    ++SQLITE_API int sqlite3_system_errno(sqlite3 *db){
    ++  return db ? db->iSysErrno : 0;
    ++}  
    + 
    + /*
    + ** Return a string that describes the kind of error specified in the
    + ** argument.  For now, this simply calls the internal sqlite3ErrStr()
    + ** function.
    + */
    +-SQLITE_API const char *SQLITE_STDCALL sqlite3_errstr(int rc){
    ++SQLITE_API const char *sqlite3_errstr(int rc){
    +   return sqlite3ErrStr(rc);
    + }
    + 
    +@@ -133083,7 +145777,7 @@ static int createCollation(
    +   }
    + 
    +   pColl = sqlite3FindCollSeq(db, (u8)enc2, zName, 1);
    +-  if( pColl==0 ) return SQLITE_NOMEM;
    ++  if( pColl==0 ) return SQLITE_NOMEM_BKPT;
    +   pColl->xCmp = xCompare;
    +   pColl->pUser = pCtx;
    +   pColl->xDel = xDel;
    +@@ -133131,8 +145825,8 @@ static const int aHardLimit[] = {
    + #if SQLITE_MAX_VDBE_OP<40
    + # error SQLITE_MAX_VDBE_OP must be at least 40
    + #endif
    +-#if SQLITE_MAX_FUNCTION_ARG<0 || SQLITE_MAX_FUNCTION_ARG>1000
    +-# error SQLITE_MAX_FUNCTION_ARG must be between 0 and 1000
    ++#if SQLITE_MAX_FUNCTION_ARG<0 || SQLITE_MAX_FUNCTION_ARG>127
    ++# error SQLITE_MAX_FUNCTION_ARG must be between 0 and 127
    + #endif
    + #if SQLITE_MAX_ATTACHED<0 || SQLITE_MAX_ATTACHED>125
    + # error SQLITE_MAX_ATTACHED must be between 0 and 125
    +@@ -133161,7 +145855,7 @@ static const int aHardLimit[] = {
    + ** It merely prevents new constructs that exceed the limit
    + ** from forming.
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_limit(sqlite3 *db, int limitId, int newLimit){
    ++SQLITE_API int sqlite3_limit(sqlite3 *db, int limitId, int newLimit){
    +   int oldLimit;
    + 
    + #ifdef SQLITE_ENABLE_API_ARMOR
    +@@ -133262,7 +145956,7 @@ SQLITE_PRIVATE int sqlite3ParseUri(
    + 
    +     for(iIn=0; iIn<nUri; iIn++) nByte += (zUri[iIn]=='&');
    +     zFile = sqlite3_malloc64(nByte);
    +-    if( !zFile ) return SQLITE_NOMEM;
    ++    if( !zFile ) return SQLITE_NOMEM_BKPT;
    + 
    +     iIn = 5;
    + #ifdef SQLITE_ALLOW_URI_AUTHORITY
    +@@ -133313,6 +146007,7 @@ SQLITE_PRIVATE int sqlite3ParseUri(
    + 
    +         assert( octet>=0 && octet<256 );
    +         if( octet==0 ){
    ++#ifndef SQLITE_ENABLE_URI_00_ERROR
    +           /* This branch is taken when "%00" appears within the URI. In this
    +           ** case we ignore all text in the remainder of the path, name or
    +           ** value currently being parsed. So ignore the current character
    +@@ -133325,6 +146020,12 @@ SQLITE_PRIVATE int sqlite3ParseUri(
    +             iIn++;
    +           }
    +           continue;
    ++#else
    ++          /* If ENABLE_URI_00_ERROR is defined, "%00" in a URI is an error. */
    ++          *pzErrMsg = sqlite3_mprintf("unexpected %%00 in uri");
    ++          rc = SQLITE_ERROR;
    ++          goto parse_uri_out;
    ++#endif
    +         }
    +         c = octet;
    +       }else if( eState==1 && (c=='&' || c=='=') ){
    +@@ -133428,8 +146129,10 @@ SQLITE_PRIVATE int sqlite3ParseUri(
    + 
    +   }else{
    +     zFile = sqlite3_malloc64(nUri+2);
    +-    if( !zFile ) return SQLITE_NOMEM;
    +-    memcpy(zFile, zUri, nUri);
    ++    if( !zFile ) return SQLITE_NOMEM_BKPT;
    ++    if( nUri ){
    ++      memcpy(zFile, zUri, nUri);
    ++    }
    +     zFile[nUri] = '\0';
    +     zFile[nUri+1] = '\0';
    +     flags &= ~SQLITE_OPEN_URI;
    +@@ -133477,26 +146180,6 @@ static int openDatabase(
    +   if( rc ) return rc;
    + #endif
    + 
    +-  /* Only allow sensible combinations of bits in the flags argument.  
    +-  ** Throw an error if any non-sense combination is used.  If we
    +-  ** do not block illegal combinations here, it could trigger
    +-  ** assert() statements in deeper layers.  Sensible combinations
    +-  ** are:
    +-  **
    +-  **  1:  SQLITE_OPEN_READONLY
    +-  **  2:  SQLITE_OPEN_READWRITE
    +-  **  6:  SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE
    +-  */
    +-  assert( SQLITE_OPEN_READONLY  == 0x01 );
    +-  assert( SQLITE_OPEN_READWRITE == 0x02 );
    +-  assert( SQLITE_OPEN_CREATE    == 0x04 );
    +-  testcase( (1<<(flags&7))==0x02 ); /* READONLY */
    +-  testcase( (1<<(flags&7))==0x04 ); /* READWRITE */
    +-  testcase( (1<<(flags&7))==0x40 ); /* READWRITE | CREATE */
    +-  if( ((1<<(flags&7)) & 0x46)==0 ){
    +-    return SQLITE_MISUSE_BKPT;  /* IMP: R-65497-44594 */
    +-  }
    +-
    +   if( sqlite3GlobalConfig.bCoreMutex==0 ){
    +     isThreadsafe = 0;
    +   }else if( flags & SQLITE_OPEN_NOMUTEX ){
    +@@ -133506,6 +146189,7 @@ static int openDatabase(
    +   }else{
    +     isThreadsafe = sqlite3GlobalConfig.bFullMutex;
    +   }
    ++
    +   if( flags & SQLITE_OPEN_PRIVATECACHE ){
    +     flags &= ~SQLITE_OPEN_SHAREDCACHE;
    +   }else if( sqlite3GlobalConfig.sharedCacheEnabled ){
    +@@ -133538,13 +146222,20 @@ static int openDatabase(
    +   /* Allocate the sqlite data structure */
    +   db = sqlite3MallocZero( sizeof(sqlite3) );
    +   if( db==0 ) goto opendb_out;
    +-  if( isThreadsafe ){
    ++  if( isThreadsafe 
    ++#ifdef SQLITE_ENABLE_MULTITHREADED_CHECKS
    ++   || sqlite3GlobalConfig.bCoreMutex
    ++#endif
    ++  ){
    +     db->mutex = sqlite3MutexAlloc(SQLITE_MUTEX_RECURSIVE);
    +     if( db->mutex==0 ){
    +       sqlite3_free(db);
    +       db = 0;
    +       goto opendb_out;
    +     }
    ++    if( isThreadsafe==0 ){
    ++      sqlite3MutexWarnOnContention(db->mutex);
    ++    }
    +   }
    +   sqlite3_mutex_enter(db->mutex);
    +   db->errMask = 0xff;
    +@@ -133584,6 +146275,12 @@ static int openDatabase(
    + #endif
    + #if defined(SQLITE_ENABLE_OVERSIZE_CELL_CHECK)
    +                  | SQLITE_CellSizeCk
    ++#endif
    ++#if defined(SQLITE_ENABLE_FTS3_TOKENIZER)
    ++                 | SQLITE_Fts3Tokenizer
    ++#endif
    ++#if defined(SQLITE_ENABLE_QPSG)
    ++                 | SQLITE_EnableQPSG
    + #endif
    +       ;
    +   sqlite3HashInit(&db->aCollSeq);
    +@@ -133598,9 +146295,9 @@ static int openDatabase(
    +   ** EVIDENCE-OF: R-52786-44878 SQLite defines three built-in collating
    +   ** functions:
    +   */
    +-  createCollation(db, "BINARY", SQLITE_UTF8, 0, binCollFunc, 0);
    +-  createCollation(db, "BINARY", SQLITE_UTF16BE, 0, binCollFunc, 0);
    +-  createCollation(db, "BINARY", SQLITE_UTF16LE, 0, binCollFunc, 0);
    ++  createCollation(db, sqlite3StrBINARY, SQLITE_UTF8, 0, binCollFunc, 0);
    ++  createCollation(db, sqlite3StrBINARY, SQLITE_UTF16BE, 0, binCollFunc, 0);
    ++  createCollation(db, sqlite3StrBINARY, SQLITE_UTF16LE, 0, binCollFunc, 0);
    +   createCollation(db, "NOCASE", SQLITE_UTF8, 0, nocaseCollatingFunc, 0);
    +   createCollation(db, "RTRIM", SQLITE_UTF8, (void*)1, binCollFunc, 0);
    +   if( db->mallocFailed ){
    +@@ -133609,14 +146306,35 @@ static int openDatabase(
    +   /* EVIDENCE-OF: R-08308-17224 The default collating function for all
    +   ** strings is BINARY. 
    +   */
    +-  db->pDfltColl = sqlite3FindCollSeq(db, SQLITE_UTF8, "BINARY", 0);
    ++  db->pDfltColl = sqlite3FindCollSeq(db, SQLITE_UTF8, sqlite3StrBINARY, 0);
    +   assert( db->pDfltColl!=0 );
    + 
    +-  /* Parse the filename/URI argument. */
    ++  /* Parse the filename/URI argument
    ++  **
    ++  ** Only allow sensible combinations of bits in the flags argument.  
    ++  ** Throw an error if any non-sense combination is used.  If we
    ++  ** do not block illegal combinations here, it could trigger
    ++  ** assert() statements in deeper layers.  Sensible combinations
    ++  ** are:
    ++  **
    ++  **  1:  SQLITE_OPEN_READONLY
    ++  **  2:  SQLITE_OPEN_READWRITE
    ++  **  6:  SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE
    ++  */
    +   db->openFlags = flags;
    +-  rc = sqlite3ParseUri(zVfs, zFilename, &flags, &db->pVfs, &zOpen, &zErrMsg);
    ++  assert( SQLITE_OPEN_READONLY  == 0x01 );
    ++  assert( SQLITE_OPEN_READWRITE == 0x02 );
    ++  assert( SQLITE_OPEN_CREATE    == 0x04 );
    ++  testcase( (1<<(flags&7))==0x02 ); /* READONLY */
    ++  testcase( (1<<(flags&7))==0x04 ); /* READWRITE */
    ++  testcase( (1<<(flags&7))==0x40 ); /* READWRITE | CREATE */
    ++  if( ((1<<(flags&7)) & 0x46)==0 ){
    ++    rc = SQLITE_MISUSE_BKPT;  /* IMP: R-65497-44594 */
    ++  }else{
    ++    rc = sqlite3ParseUri(zVfs, zFilename, &flags, &db->pVfs, &zOpen, &zErrMsg);
    ++  }
    +   if( rc!=SQLITE_OK ){
    +-    if( rc==SQLITE_NOMEM ) db->mallocFailed = 1;
    ++    if( rc==SQLITE_NOMEM ) sqlite3OomFault(db);
    +     sqlite3ErrorWithMsg(db, rc, zErrMsg ? "%s" : 0, zErrMsg);
    +     sqlite3_free(zErrMsg);
    +     goto opendb_out;
    +@@ -133627,7 +146345,7 @@ static int openDatabase(
    +                         flags | SQLITE_OPEN_MAIN_DB);
    +   if( rc!=SQLITE_OK ){
    +     if( rc==SQLITE_IOERR_NOMEM ){
    +-      rc = SQLITE_NOMEM;
    ++      rc = SQLITE_NOMEM_BKPT;
    +     }
    +     sqlite3Error(db, rc);
    +     goto opendb_out;
    +@@ -133638,13 +146356,13 @@ static int openDatabase(
    +   sqlite3BtreeLeave(db->aDb[0].pBt);
    +   db->aDb[1].pSchema = sqlite3SchemaGet(db, 0);
    + 
    +-  /* The default safety_level for the main database is 'full'; for the temp
    +-  ** database it is 'NONE'. This matches the pager layer defaults.  
    ++  /* The default safety_level for the main database is FULL; for the temp
    ++  ** database it is OFF. This matches the pager layer defaults.  
    +   */
    +-  db->aDb[0].zName = "main";
    +-  db->aDb[0].safety_level = 3;
    +-  db->aDb[1].zName = "temp";
    +-  db->aDb[1].safety_level = 1;
    ++  db->aDb[0].zDbSName = "main";
    ++  db->aDb[0].safety_level = SQLITE_DEFAULT_SYNCHRONOUS+1;
    ++  db->aDb[1].zDbSName = "temp";
    ++  db->aDb[1].safety_level = PAGER_SYNCHRONOUS_OFF;
    + 
    +   db->magic = SQLITE_MAGIC_OPEN;
    +   if( db->mallocFailed ){
    +@@ -133656,12 +146374,21 @@ static int openDatabase(
    +   ** is accessed.
    +   */
    +   sqlite3Error(db, SQLITE_OK);
    +-  sqlite3RegisterBuiltinFunctions(db);
    ++  sqlite3RegisterPerConnectionBuiltinFunctions(db);
    ++  rc = sqlite3_errcode(db);
    ++
    ++#ifdef SQLITE_ENABLE_FTS5
    ++  /* Register any built-in FTS5 module before loading the automatic
    ++  ** extensions. This allows automatic extensions to register FTS5 
    ++  ** tokenizers and auxiliary functions.  */
    ++  if( !db->mallocFailed && rc==SQLITE_OK ){
    ++    rc = sqlite3Fts5Init(db);
    ++  }
    ++#endif
    + 
    +   /* Load automatic extensions - extensions that have been registered
    +   ** using the sqlite3_automatic_extension() API.
    +   */
    +-  rc = sqlite3_errcode(db);
    +   if( rc==SQLITE_OK ){
    +     sqlite3AutoLoadExtensions(db);
    +     rc = sqlite3_errcode(db);
    +@@ -133690,13 +146417,7 @@ static int openDatabase(
    +   }
    + #endif
    + 
    +-#ifdef SQLITE_ENABLE_FTS5
    +-  if( !db->mallocFailed && rc==SQLITE_OK ){
    +-    rc = sqlite3Fts5Init(db);
    +-  }
    +-#endif
    +-
    +-#ifdef SQLITE_ENABLE_ICU
    ++#if defined(SQLITE_ENABLE_ICU) || defined(SQLITE_ENABLE_ICU_COLLATIONS)
    +   if( !db->mallocFailed && rc==SQLITE_OK ){
    +     rc = sqlite3IcuInit(db);
    +   }
    +@@ -133708,6 +146429,12 @@ static int openDatabase(
    +   }
    + #endif
    + 
    ++#ifdef SQLITE_ENABLE_DBPAGE_VTAB
    ++  if( !db->mallocFailed && rc==SQLITE_OK){
    ++    rc = sqlite3DbpageRegister(db);
    ++  }
    ++#endif
    ++
    + #ifdef SQLITE_ENABLE_DBSTAT_VTAB
    +   if( !db->mallocFailed && rc==SQLITE_OK){
    +     rc = sqlite3DbstatRegister(db);
    +@@ -133720,6 +146447,12 @@ static int openDatabase(
    +   }
    + #endif
    + 
    ++#ifdef SQLITE_ENABLE_STMTVTAB
    ++  if( !db->mallocFailed && rc==SQLITE_OK){
    ++    rc = sqlite3StmtVtabInit(db);
    ++  }
    ++#endif
    ++
    +   /* -DSQLITE_DEFAULT_LOCKING_MODE=1 makes EXCLUSIVE the default locking
    +   ** mode.  -DSQLITE_DEFAULT_LOCKING_MODE=0 make NORMAL the default locking
    +   ** mode.  Doing nothing at all also makes NORMAL the default.
    +@@ -133739,7 +146472,6 @@ static int openDatabase(
    +   sqlite3_wal_autocheckpoint(db, SQLITE_DEFAULT_WAL_AUTOCHECKPOINT);
    + 
    + opendb_out:
    +-  sqlite3_free(zOpen);
    +   if( db ){
    +     assert( db->mutex!=0 || isThreadsafe==0
    +            || sqlite3GlobalConfig.bFullMutex==0 );
    +@@ -133761,20 +146493,38 @@ opendb_out:
    +     sqlite3GlobalConfig.xSqllog(pArg, db, zFilename, 0);
    +   }
    + #endif
    ++#if defined(SQLITE_HAS_CODEC)
    ++  if( rc==SQLITE_OK ){
    ++    const char *zKey;
    ++    if( (zKey = sqlite3_uri_parameter(zOpen, "hexkey"))!=0 && zKey[0] ){
    ++      u8 iByte;
    ++      int i;
    ++      char zDecoded[40];
    ++      for(i=0, iByte=0; i<sizeof(zDecoded)*2 && sqlite3Isxdigit(zKey[i]); i++){
    ++        iByte = (iByte<<4) + sqlite3HexToInt(zKey[i]);
    ++        if( (i&1)!=0 ) zDecoded[i/2] = iByte;
    ++      }
    ++      sqlite3_key_v2(db, 0, zDecoded, i/2);
    ++    }else if( (zKey = sqlite3_uri_parameter(zOpen, "key"))!=0 ){
    ++      sqlite3_key_v2(db, 0, zKey, sqlite3Strlen30(zKey));
    ++    }
    ++  }
    ++#endif
    ++  sqlite3_free(zOpen);
    +   return rc & 0xff;
    + }
    + 
    + /*
    + ** Open a new database handle.
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_open(
    ++SQLITE_API int sqlite3_open(
    +   const char *zFilename, 
    +   sqlite3 **ppDb 
    + ){
    +   return openDatabase(zFilename, ppDb,
    +                       SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE, 0);
    + }
    +-SQLITE_API int SQLITE_STDCALL sqlite3_open_v2(
    ++SQLITE_API int sqlite3_open_v2(
    +   const char *filename,   /* Database filename (UTF-8) */
    +   sqlite3 **ppDb,         /* OUT: SQLite db handle */
    +   int flags,              /* Flags */
    +@@ -133787,7 +146537,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_open_v2(
    + /*
    + ** Open a new database handle.
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_open16(
    ++SQLITE_API int sqlite3_open16(
    +   const void *zFilename, 
    +   sqlite3 **ppDb
    + ){
    +@@ -133815,7 +146565,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_open16(
    +       SCHEMA_ENC(*ppDb) = ENC(*ppDb) = SQLITE_UTF16NATIVE;
    +     }
    +   }else{
    +-    rc = SQLITE_NOMEM;
    ++    rc = SQLITE_NOMEM_BKPT;
    +   }
    +   sqlite3ValueFree(pVal);
    + 
    +@@ -133826,7 +146576,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_open16(
    + /*
    + ** Register a new collation sequence with the database handle db.
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_create_collation(
    ++SQLITE_API int sqlite3_create_collation(
    +   sqlite3* db, 
    +   const char *zName, 
    +   int enc, 
    +@@ -133839,7 +146589,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_create_collation(
    + /*
    + ** Register a new collation sequence with the database handle db.
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_create_collation_v2(
    ++SQLITE_API int sqlite3_create_collation_v2(
    +   sqlite3* db, 
    +   const char *zName, 
    +   int enc, 
    +@@ -133864,7 +146614,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_create_collation_v2(
    + /*
    + ** Register a new collation sequence with the database handle db.
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_create_collation16(
    ++SQLITE_API int sqlite3_create_collation16(
    +   sqlite3* db, 
    +   const void *zName,
    +   int enc, 
    +@@ -133894,7 +146644,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_create_collation16(
    + ** Register a collation sequence factory callback with the database handle
    + ** db. Replace any previously installed collation sequence factory.
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_collation_needed(
    ++SQLITE_API int sqlite3_collation_needed(
    +   sqlite3 *db, 
    +   void *pCollNeededArg, 
    +   void(*xCollNeeded)(void*,sqlite3*,int eTextRep,const char*)
    +@@ -133915,7 +146665,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_collation_needed(
    + ** Register a collation sequence factory callback with the database handle
    + ** db. Replace any previously installed collation sequence factory.
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_collation_needed16(
    ++SQLITE_API int sqlite3_collation_needed16(
    +   sqlite3 *db, 
    +   void *pCollNeededArg, 
    +   void(*xCollNeeded16)(void*,sqlite3*,int eTextRep,const void*)
    +@@ -133937,7 +146687,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_collation_needed16(
    + ** This function is now an anachronism. It used to be used to recover from a
    + ** malloc() failure, but SQLite now does this automatically.
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_global_recover(void){
    ++SQLITE_API int sqlite3_global_recover(void){
    +   return SQLITE_OK;
    + }
    + #endif
    +@@ -133948,7 +146698,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_global_recover(void){
    + ** by default.  Autocommit is disabled by a BEGIN statement and reenabled
    + ** by the next COMMIT or ROLLBACK.
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_get_autocommit(sqlite3 *db){
    ++SQLITE_API int sqlite3_get_autocommit(sqlite3 *db){
    + #ifdef SQLITE_ENABLE_API_ARMOR
    +   if( !sqlite3SafetyCheckOk(db) ){
    +     (void)SQLITE_MISUSE_BKPT;
    +@@ -133960,7 +146710,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_get_autocommit(sqlite3 *db){
    + 
    + /*
    + ** The following routines are substitutes for constants SQLITE_CORRUPT,
    +-** SQLITE_MISUSE, SQLITE_CANTOPEN, SQLITE_IOERR and possibly other error
    ++** SQLITE_MISUSE, SQLITE_CANTOPEN, SQLITE_NOMEM and possibly other error
    + ** constants.  They serve two purposes:
    + **
    + **   1.  Serve as a convenient place to set a breakpoint in a debugger
    +@@ -133969,28 +146719,39 @@ SQLITE_API int SQLITE_STDCALL sqlite3_get_autocommit(sqlite3 *db){
    + **   2.  Invoke sqlite3_log() to provide the source code location where
    + **       a low-level error is first detected.
    + */
    ++SQLITE_PRIVATE int sqlite3ReportError(int iErr, int lineno, const char *zType){
    ++  sqlite3_log(iErr, "%s at line %d of [%.10s]",
    ++              zType, lineno, 20+sqlite3_sourceid());
    ++  return iErr;
    ++}
    + SQLITE_PRIVATE int sqlite3CorruptError(int lineno){
    +   testcase( sqlite3GlobalConfig.xLog!=0 );
    +-  sqlite3_log(SQLITE_CORRUPT,
    +-              "database corruption at line %d of [%.10s]",
    +-              lineno, 20+sqlite3_sourceid());
    +-  return SQLITE_CORRUPT;
    ++  return sqlite3ReportError(SQLITE_CORRUPT, lineno, "database corruption");
    + }
    + SQLITE_PRIVATE int sqlite3MisuseError(int lineno){
    +   testcase( sqlite3GlobalConfig.xLog!=0 );
    +-  sqlite3_log(SQLITE_MISUSE, 
    +-              "misuse at line %d of [%.10s]",
    +-              lineno, 20+sqlite3_sourceid());
    +-  return SQLITE_MISUSE;
    ++  return sqlite3ReportError(SQLITE_MISUSE, lineno, "misuse");
    + }
    + SQLITE_PRIVATE int sqlite3CantopenError(int lineno){
    +   testcase( sqlite3GlobalConfig.xLog!=0 );
    +-  sqlite3_log(SQLITE_CANTOPEN, 
    +-              "cannot open file at line %d of [%.10s]",
    +-              lineno, 20+sqlite3_sourceid());
    +-  return SQLITE_CANTOPEN;
    ++  return sqlite3ReportError(SQLITE_CANTOPEN, lineno, "cannot open file");
    + }
    +-
    ++#ifdef SQLITE_DEBUG
    ++SQLITE_PRIVATE int sqlite3CorruptPgnoError(int lineno, Pgno pgno){
    ++  char zMsg[100];
    ++  sqlite3_snprintf(sizeof(zMsg), zMsg, "database corruption page %d", pgno);
    ++  testcase( sqlite3GlobalConfig.xLog!=0 );
    ++  return sqlite3ReportError(SQLITE_CORRUPT, lineno, zMsg);
    ++}
    ++SQLITE_PRIVATE int sqlite3NomemError(int lineno){
    ++  testcase( sqlite3GlobalConfig.xLog!=0 );
    ++  return sqlite3ReportError(SQLITE_NOMEM, lineno, "OOM");
    ++}
    ++SQLITE_PRIVATE int sqlite3IoerrnomemError(int lineno){
    ++  testcase( sqlite3GlobalConfig.xLog!=0 );
    ++  return sqlite3ReportError(SQLITE_IOERR_NOMEM, lineno, "I/O OOM error");
    ++}
    ++#endif
    + 
    + #ifndef SQLITE_OMIT_DEPRECATED
    + /*
    +@@ -134000,7 +146761,7 @@ SQLITE_PRIVATE int sqlite3CantopenError(int lineno){
    + ** SQLite no longer uses thread-specific data so this routine is now a
    + ** no-op.  It is retained for historical compatibility.
    + */
    +-SQLITE_API void SQLITE_STDCALL sqlite3_thread_cleanup(void){
    ++SQLITE_API void sqlite3_thread_cleanup(void){
    + }
    + #endif
    + 
    +@@ -134008,7 +146769,7 @@ SQLITE_API void SQLITE_STDCALL sqlite3_thread_cleanup(void){
    + ** Return meta information about a specific column of a database table.
    + ** See comment in sqlite3.h (sqlite.h.in) for details.
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_table_column_metadata(
    ++SQLITE_API int sqlite3_table_column_metadata(
    +   sqlite3 *db,                /* Connection handle */
    +   const char *zDbName,        /* Database name or NULL */
    +   const char *zTableName,     /* Table name */
    +@@ -134084,7 +146845,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_table_column_metadata(
    +   **        explicitly declared column. Copy meta information from *pCol.
    +   */ 
    +   if( pCol ){
    +-    zDataType = pCol->zType;
    ++    zDataType = sqlite3ColumnType(pCol,0);
    +     zCollSeq = pCol->zColl;
    +     notnull = pCol->notNull!=0;
    +     primarykey  = (pCol->colFlags & COLFLAG_PRIMKEY)!=0;
    +@@ -134094,7 +146855,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_table_column_metadata(
    +     primarykey = 1;
    +   }
    +   if( !zCollSeq ){
    +-    zCollSeq = "BINARY";
    ++    zCollSeq = sqlite3StrBINARY;
    +   }
    + 
    + error_out:
    +@@ -134126,7 +146887,7 @@ error_out:
    + /*
    + ** Sleep for a little while.  Return the amount of time slept.
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_sleep(int ms){
    ++SQLITE_API int sqlite3_sleep(int ms){
    +   sqlite3_vfs *pVfs;
    +   int rc;
    +   pVfs = sqlite3_vfs_find(0);
    +@@ -134142,7 +146903,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_sleep(int ms){
    + /*
    + ** Enable or disable the extended result codes.
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_extended_result_codes(sqlite3 *db, int onoff){
    ++SQLITE_API int sqlite3_extended_result_codes(sqlite3 *db, int onoff){
    + #ifdef SQLITE_ENABLE_API_ARMOR
    +   if( !sqlite3SafetyCheckOk(db) ) return SQLITE_MISUSE_BKPT;
    + #endif
    +@@ -134155,7 +146916,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_extended_result_codes(sqlite3 *db, int ono
    + /*
    + ** Invoke the xFileControl method on a particular database.
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_file_control(sqlite3 *db, const char *zDbName, int op, void *pArg){
    ++SQLITE_API int sqlite3_file_control(sqlite3 *db, const char *zDbName, int op, void *pArg){
    +   int rc = SQLITE_ERROR;
    +   Btree *pBtree;
    + 
    +@@ -134175,6 +146936,12 @@ SQLITE_API int SQLITE_STDCALL sqlite3_file_control(sqlite3 *db, const char *zDbN
    +     if( op==SQLITE_FCNTL_FILE_POINTER ){
    +       *(sqlite3_file**)pArg = fd;
    +       rc = SQLITE_OK;
    ++    }else if( op==SQLITE_FCNTL_VFS_POINTER ){
    ++      *(sqlite3_vfs**)pArg = sqlite3PagerVfs(pPager);
    ++      rc = SQLITE_OK;
    ++    }else if( op==SQLITE_FCNTL_JOURNAL_POINTER ){
    ++      *(sqlite3_file**)pArg = sqlite3PagerJrnlFile(pPager);
    ++      rc = SQLITE_OK;
    +     }else if( fd->pMethods ){
    +       rc = sqlite3OsFileControl(fd, op, pArg);
    +     }else{
    +@@ -134189,9 +146956,9 @@ SQLITE_API int SQLITE_STDCALL sqlite3_file_control(sqlite3 *db, const char *zDbN
    + /*
    + ** Interface to the testing logic.
    + */
    +-SQLITE_API int SQLITE_CDECL sqlite3_test_control(int op, ...){
    ++SQLITE_API int sqlite3_test_control(int op, ...){
    +   int rc = 0;
    +-#ifdef SQLITE_OMIT_BUILTIN_TEST
    ++#ifdef SQLITE_UNTESTABLE
    +   UNUSED_PARAMETER(op);
    + #else
    +   va_list ap;
    +@@ -134315,7 +147082,7 @@ SQLITE_API int SQLITE_CDECL sqlite3_test_control(int op, ...){
    +     */
    +     case SQLITE_TESTCTRL_ASSERT: {
    +       volatile int x = 0;
    +-      assert( (x = va_arg(ap,int))!=0 );
    ++      assert( /*side-effects-ok*/ (x = va_arg(ap,int))!=0 );
    +       rc = x;
    +       break;
    +     }
    +@@ -134327,7 +147094,7 @@ SQLITE_API int SQLITE_CDECL sqlite3_test_control(int op, ...){
    +     ** This action provides a run-time test to see how the ALWAYS and
    +     ** NEVER macros were defined at compile-time.
    +     **
    +-    ** The return value is ALWAYS(X).  
    ++    ** The return value is ALWAYS(X) if X is true, or 0 if X is false.
    +     **
    +     ** The recommended test is X==2.  If the return value is 2, that means
    +     ** ALWAYS() and NEVER() are both no-op pass-through macros, which is the
    +@@ -134350,7 +147117,7 @@ SQLITE_API int SQLITE_CDECL sqlite3_test_control(int op, ...){
    +     */
    +     case SQLITE_TESTCTRL_ALWAYS: {
    +       int x = va_arg(ap,int);
    +-      rc = ALWAYS(x);
    ++      rc = x ? ALWAYS(x) : 0;
    +       break;
    +     }
    + 
    +@@ -134417,22 +147184,6 @@ SQLITE_API int SQLITE_CDECL sqlite3_test_control(int op, ...){
    +     }
    + #endif 
    + 
    +-    /* sqlite3_test_control(SQLITE_TESTCTRL_SCRATCHMALLOC, sz, &pNew, pFree);
    +-    **
    +-    ** Pass pFree into sqlite3ScratchFree(). 
    +-    ** If sz>0 then allocate a scratch buffer into pNew.  
    +-    */
    +-    case SQLITE_TESTCTRL_SCRATCHMALLOC: {
    +-      void *pFree, **ppNew;
    +-      int sz;
    +-      sz = va_arg(ap, int);
    +-      ppNew = va_arg(ap, void**);
    +-      pFree = va_arg(ap, void*);
    +-      if( sz ) *ppNew = sqlite3ScratchMalloc(sz);
    +-      sqlite3ScratchFree(pFree);
    +-      break;
    +-    }
    +-
    +     /*   sqlite3_test_control(SQLITE_TESTCTRL_LOCALTIME_FAULT, int onoff);
    +     **
    +     ** If parameter onoff is non-zero, configure the wrappers so that all
    +@@ -134457,6 +147208,15 @@ SQLITE_API int SQLITE_CDECL sqlite3_test_control(int op, ...){
    +       break;
    +     }
    + 
    ++    /* Set the threshold at which OP_Once counters reset back to zero.
    ++    ** By default this is 0x7ffffffe (over 2 billion), but that value is
    ++    ** too big to test in a reasonable amount of time, so this control is
    ++    ** provided to set a small and easily reachable reset value.
    ++    */
    ++    case SQLITE_TESTCTRL_ONCE_RESET_THRESHOLD: {
    ++      sqlite3GlobalConfig.iOnceResetThreshold = va_arg(ap, int);
    ++      break;
    ++    }
    + 
    +     /*   sqlite3_test_control(SQLITE_TESTCTRL_VDBE_COVERAGE, xCallback, ptr);
    +     **
    +@@ -134517,9 +147277,25 @@ SQLITE_API int SQLITE_CDECL sqlite3_test_control(int op, ...){
    +       sqlite3_mutex_leave(db->mutex);
    +       break;
    +     }
    ++
    ++#if defined(YYCOVERAGE)
    ++    /*  sqlite3_test_control(SQLITE_TESTCTRL_PARSER_COVERAGE, FILE *out)
    ++    **
    ++    ** This test control (only available when SQLite is compiled with
    ++    ** -DYYCOVERAGE) writes a report onto "out" that shows all
    ++    ** state/lookahead combinations in the parser state machine
    ++    ** which are never exercised.  If any state is missed, make the
    ++    ** return code SQLITE_ERROR.
    ++    */
    ++    case SQLITE_TESTCTRL_PARSER_COVERAGE: {
    ++      FILE *out = va_arg(ap, FILE*);
    ++      if( sqlite3ParserCoverage(out) ) rc = SQLITE_ERROR;
    ++      break;
    ++    }
    ++#endif /* defined(YYCOVERAGE) */
    +   }
    +   va_end(ap);
    +-#endif /* SQLITE_OMIT_BUILTIN_TEST */
    ++#endif /* SQLITE_UNTESTABLE */
    +   return rc;
    + }
    + 
    +@@ -134534,7 +147310,7 @@ SQLITE_API int SQLITE_CDECL sqlite3_test_control(int op, ...){
    + ** parameter if it exists.  If the parameter does not exist, this routine
    + ** returns a NULL pointer.
    + */
    +-SQLITE_API const char *SQLITE_STDCALL sqlite3_uri_parameter(const char *zFilename, const char *zParam){
    ++SQLITE_API const char *sqlite3_uri_parameter(const char *zFilename, const char *zParam){
    +   if( zFilename==0 || zParam==0 ) return 0;
    +   zFilename += sqlite3Strlen30(zFilename) + 1;
    +   while( zFilename[0] ){
    +@@ -134549,7 +147325,7 @@ SQLITE_API const char *SQLITE_STDCALL sqlite3_uri_parameter(const char *zFilenam
    + /*
    + ** Return a boolean value for a query parameter.
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_uri_boolean(const char *zFilename, const char *zParam, int bDflt){
    ++SQLITE_API int sqlite3_uri_boolean(const char *zFilename, const char *zParam, int bDflt){
    +   const char *z = sqlite3_uri_parameter(zFilename, zParam);
    +   bDflt = bDflt!=0;
    +   return z ? sqlite3GetBoolean(z, bDflt) : bDflt;
    +@@ -134558,14 +147334,14 @@ SQLITE_API int SQLITE_STDCALL sqlite3_uri_boolean(const char *zFilename, const c
    + /*
    + ** Return a 64-bit integer value for a query parameter.
    + */
    +-SQLITE_API sqlite3_int64 SQLITE_STDCALL sqlite3_uri_int64(
    ++SQLITE_API sqlite3_int64 sqlite3_uri_int64(
    +   const char *zFilename,    /* Filename as passed to xOpen */
    +   const char *zParam,       /* URI parameter sought */
    +   sqlite3_int64 bDflt       /* return if parameter is missing */
    + ){
    +   const char *z = sqlite3_uri_parameter(zFilename, zParam);
    +   sqlite3_int64 v;
    +-  if( z && sqlite3DecOrHexToI64(z, &v)==SQLITE_OK ){
    ++  if( z && sqlite3DecOrHexToI64(z, &v)==0 ){
    +     bDflt = v;
    +   }
    +   return bDflt;
    +@@ -134575,22 +147351,15 @@ SQLITE_API sqlite3_int64 SQLITE_STDCALL sqlite3_uri_int64(
    + ** Return the Btree pointer identified by zDbName.  Return NULL if not found.
    + */
    + SQLITE_PRIVATE Btree *sqlite3DbNameToBtree(sqlite3 *db, const char *zDbName){
    +-  int i;
    +-  for(i=0; i<db->nDb; i++){
    +-    if( db->aDb[i].pBt
    +-     && (zDbName==0 || sqlite3StrICmp(zDbName, db->aDb[i].zName)==0)
    +-    ){
    +-      return db->aDb[i].pBt;
    +-    }
    +-  }
    +-  return 0;
    ++  int iDb = zDbName ? sqlite3FindDbName(db, zDbName) : 0;
    ++  return iDb<0 ? 0 : db->aDb[iDb].pBt;
    + }
    + 
    + /*
    + ** Return the filename of the database associated with a database
    + ** connection.
    + */
    +-SQLITE_API const char *SQLITE_STDCALL sqlite3_db_filename(sqlite3 *db, const char *zDbName){
    ++SQLITE_API const char *sqlite3_db_filename(sqlite3 *db, const char *zDbName){
    +   Btree *pBt;
    + #ifdef SQLITE_ENABLE_API_ARMOR
    +   if( !sqlite3SafetyCheckOk(db) ){
    +@@ -134606,7 +147375,7 @@ SQLITE_API const char *SQLITE_STDCALL sqlite3_db_filename(sqlite3 *db, const cha
    + ** Return 1 if database is read-only or 0 if read/write.  Return -1 if
    + ** no such database exists.
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_db_readonly(sqlite3 *db, const char *zDbName){
    ++SQLITE_API int sqlite3_db_readonly(sqlite3 *db, const char *zDbName){
    +   Btree *pBt;
    + #ifdef SQLITE_ENABLE_API_ARMOR
    +   if( !sqlite3SafetyCheckOk(db) ){
    +@@ -134618,6 +147387,173 @@ SQLITE_API int SQLITE_STDCALL sqlite3_db_readonly(sqlite3 *db, const char *zDbNa
    +   return pBt ? sqlite3BtreeIsReadonly(pBt) : -1;
    + }
    + 
    ++#ifdef SQLITE_ENABLE_SNAPSHOT
    ++/*
    ++** Obtain a snapshot handle for the snapshot of database zDb currently 
    ++** being read by handle db.
    ++*/
    ++SQLITE_API int sqlite3_snapshot_get(
    ++  sqlite3 *db, 
    ++  const char *zDb,
    ++  sqlite3_snapshot **ppSnapshot
    ++){
    ++  int rc = SQLITE_ERROR;
    ++#ifndef SQLITE_OMIT_WAL
    ++
    ++#ifdef SQLITE_ENABLE_API_ARMOR
    ++  if( !sqlite3SafetyCheckOk(db) ){
    ++    return SQLITE_MISUSE_BKPT;
    ++  }
    ++#endif
    ++  sqlite3_mutex_enter(db->mutex);
    ++
    ++  if( db->autoCommit==0 ){
    ++    int iDb = sqlite3FindDbName(db, zDb);
    ++    if( iDb==0 || iDb>1 ){
    ++      Btree *pBt = db->aDb[iDb].pBt;
    ++      if( 0==sqlite3BtreeIsInTrans(pBt) ){
    ++        rc = sqlite3BtreeBeginTrans(pBt, 0);
    ++        if( rc==SQLITE_OK ){
    ++          rc = sqlite3PagerSnapshotGet(sqlite3BtreePager(pBt), ppSnapshot);
    ++        }
    ++      }
    ++    }
    ++  }
    ++
    ++  sqlite3_mutex_leave(db->mutex);
    ++#endif   /* SQLITE_OMIT_WAL */
    ++  return rc;
    ++}
    ++
    ++/*
    ++** Open a read-transaction on the snapshot idendified by pSnapshot.
    ++*/
    ++SQLITE_API int sqlite3_snapshot_open(
    ++  sqlite3 *db, 
    ++  const char *zDb, 
    ++  sqlite3_snapshot *pSnapshot
    ++){
    ++  int rc = SQLITE_ERROR;
    ++#ifndef SQLITE_OMIT_WAL
    ++
    ++#ifdef SQLITE_ENABLE_API_ARMOR
    ++  if( !sqlite3SafetyCheckOk(db) ){
    ++    return SQLITE_MISUSE_BKPT;
    ++  }
    ++#endif
    ++  sqlite3_mutex_enter(db->mutex);
    ++  if( db->autoCommit==0 ){
    ++    int iDb;
    ++    iDb = sqlite3FindDbName(db, zDb);
    ++    if( iDb==0 || iDb>1 ){
    ++      Btree *pBt = db->aDb[iDb].pBt;
    ++      if( 0==sqlite3BtreeIsInReadTrans(pBt) ){
    ++        rc = sqlite3PagerSnapshotOpen(sqlite3BtreePager(pBt), pSnapshot);
    ++        if( rc==SQLITE_OK ){
    ++          rc = sqlite3BtreeBeginTrans(pBt, 0);
    ++          sqlite3PagerSnapshotOpen(sqlite3BtreePager(pBt), 0);
    ++        }
    ++      }
    ++    }
    ++  }
    ++
    ++  sqlite3_mutex_leave(db->mutex);
    ++#endif   /* SQLITE_OMIT_WAL */
    ++  return rc;
    ++}
    ++
    ++/*
    ++** Recover as many snapshots as possible from the wal file associated with
    ++** schema zDb of database db.
    ++*/
    ++SQLITE_API int sqlite3_snapshot_recover(sqlite3 *db, const char *zDb){
    ++  int rc = SQLITE_ERROR;
    ++  int iDb;
    ++#ifndef SQLITE_OMIT_WAL
    ++
    ++#ifdef SQLITE_ENABLE_API_ARMOR
    ++  if( !sqlite3SafetyCheckOk(db) ){
    ++    return SQLITE_MISUSE_BKPT;
    ++  }
    ++#endif
    ++
    ++  sqlite3_mutex_enter(db->mutex);
    ++  iDb = sqlite3FindDbName(db, zDb);
    ++  if( iDb==0 || iDb>1 ){
    ++    Btree *pBt = db->aDb[iDb].pBt;
    ++    if( 0==sqlite3BtreeIsInReadTrans(pBt) ){
    ++      rc = sqlite3BtreeBeginTrans(pBt, 0);
    ++      if( rc==SQLITE_OK ){
    ++        rc = sqlite3PagerSnapshotRecover(sqlite3BtreePager(pBt));
    ++        sqlite3BtreeCommit(pBt);
    ++      }
    ++    }
    ++  }
    ++  sqlite3_mutex_leave(db->mutex);
    ++#endif   /* SQLITE_OMIT_WAL */
    ++  return rc;
    ++}
    ++
    ++/*
    ++** Free a snapshot handle obtained from sqlite3_snapshot_get().
    ++*/
    ++SQLITE_API void sqlite3_snapshot_free(sqlite3_snapshot *pSnapshot){
    ++  sqlite3_free(pSnapshot);
    ++}
    ++#endif /* SQLITE_ENABLE_SNAPSHOT */
    ++
    ++#ifndef SQLITE_OMIT_COMPILEOPTION_DIAGS
    ++/*
    ++** Given the name of a compile-time option, return true if that option
    ++** was used and false if not.
    ++**
    ++** The name can optionally begin with "SQLITE_" but the "SQLITE_" prefix
    ++** is not required for a match.
    ++*/
    ++SQLITE_API int sqlite3_compileoption_used(const char *zOptName){
    ++  int i, n;
    ++  int nOpt;
    ++  const char **azCompileOpt;
    ++ 
    ++#if SQLITE_ENABLE_API_ARMOR
    ++  if( zOptName==0 ){
    ++    (void)SQLITE_MISUSE_BKPT;
    ++    return 0;
    ++  }
    ++#endif
    ++
    ++  azCompileOpt = sqlite3CompileOptions(&nOpt);
    ++
    ++  if( sqlite3StrNICmp(zOptName, "SQLITE_", 7)==0 ) zOptName += 7;
    ++  n = sqlite3Strlen30(zOptName);
    ++
    ++  /* Since nOpt is normally in single digits, a linear search is 
    ++  ** adequate. No need for a binary search. */
    ++  for(i=0; i<nOpt; i++){
    ++    if( sqlite3StrNICmp(zOptName, azCompileOpt[i], n)==0
    ++     && sqlite3IsIdChar((unsigned char)azCompileOpt[i][n])==0
    ++    ){
    ++      return 1;
    ++    }
    ++  }
    ++  return 0;
    ++}
    ++
    ++/*
    ++** Return the N-th compile-time option string.  If N is out of range,
    ++** return a NULL pointer.
    ++*/
    ++SQLITE_API const char *sqlite3_compileoption_get(int N){
    ++  int nOpt;
    ++  const char **azCompileOpt;
    ++  azCompileOpt = sqlite3CompileOptions(&nOpt);
    ++  if( N>=0 && N<nOpt ){
    ++    return azCompileOpt[N];
    ++  }
    ++  return 0;
    ++}
    ++#endif /* SQLITE_OMIT_COMPILEOPTION_DIAGS */
    ++
    + /************** End of main.c ************************************************/
    + /************** Begin file notify.c ******************************************/
    + /*
    +@@ -134767,7 +147703,7 @@ static void leaveMutex(void){
    + ** on the same "db".  If xNotify==0 then any prior callbacks are immediately
    + ** cancelled.
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_unlock_notify(
    ++SQLITE_API int sqlite3_unlock_notify(
    +   sqlite3 *db,
    +   void (*xNotify)(void **, int),
    +   void *pArg
    +@@ -135267,6 +148203,12 @@ SQLITE_PRIVATE void sqlite3ConnectionClosed(sqlite3 *db){
    + # define NDEBUG 1
    + #endif
    + 
    ++/* FTS3/FTS4 require virtual tables */
    ++#ifdef SQLITE_OMIT_VIRTUALTABLE
    ++# undef SQLITE_ENABLE_FTS3
    ++# undef SQLITE_ENABLE_FTS4
    ++#endif
    ++
    + /*
    + ** FTS4 is really an extension for FTS3.  It is enabled using the
    + ** SQLITE_ENABLE_FTS3 macro.  But to avoid confusion we also all
    +@@ -135754,6 +148696,7 @@ struct Fts3Table {
    +   ** statements is run and reset within a single virtual table API call. 
    +   */
    +   sqlite3_stmt *aStmt[40];
    ++  sqlite3_stmt *pSeekStmt;        /* Cache for fts3CursorSeekStmt() */
    + 
    +   char *zReadExprlist;
    +   char *zWriteExprlist;
    +@@ -135823,6 +148766,7 @@ struct Fts3Cursor {
    +   i16 eSearch;                    /* Search strategy (see below) */
    +   u8 isEof;                       /* True if at End Of Results */
    +   u8 isRequireSeek;               /* True if must seek pStmt to %_content row */
    ++  u8 bSeekStmt;                   /* True if pStmt is a seek */
    +   sqlite3_stmt *pStmt;            /* Prepared statement in use by the cursor */
    +   Fts3Expr *pExpr;                /* Parsed MATCH query string */
    +   int iLangid;                    /* Language being queried for */
    +@@ -136202,8 +149146,9 @@ SQLITE_PRIVATE int sqlite3Fts3PutVarint(char *p, sqlite_int64 v){
    + ** Return the number of bytes read, or 0 on error.
    + ** The value is stored in *v.
    + */
    +-SQLITE_PRIVATE int sqlite3Fts3GetVarint(const char *p, sqlite_int64 *v){
    +-  const char *pStart = p;
    ++SQLITE_PRIVATE int sqlite3Fts3GetVarint(const char *pBuf, sqlite_int64 *v){
    ++  const unsigned char *p = (const unsigned char*)pBuf;
    ++  const unsigned char *pStart = p;
    +   u32 a;
    +   u64 b;
    +   int shift;
    +@@ -136224,8 +149169,8 @@ SQLITE_PRIVATE int sqlite3Fts3GetVarint(const char *p, sqlite_int64 *v){
    + }
    + 
    + /*
    +-** Similar to sqlite3Fts3GetVarint(), except that the output is truncated to a
    +-** 32-bit integer before it is returned.
    ++** Similar to sqlite3Fts3GetVarint(), except that the output is truncated to 
    ++** a non-negative 32-bit integer before it is returned.
    + */
    + SQLITE_PRIVATE int sqlite3Fts3GetVarint32(const char *p, int *pi){
    +   u32 a;
    +@@ -136241,7 +149186,9 @@ SQLITE_PRIVATE int sqlite3Fts3GetVarint32(const char *p, int *pi){
    +   GETVARINT_STEP(a, p, 14, 0x3FFF,   0x200000, *pi, 3);
    +   GETVARINT_STEP(a, p, 21, 0x1FFFFF, 0x10000000, *pi, 4);
    +   a = (a & 0x0FFFFFFF );
    +-  *pi = (int)(a | ((u32)(*p & 0x0F) << 28));
    ++  *pi = (int)(a | ((u32)(*p & 0x07) << 28));
    ++  assert( 0==(a & 0x80000000) );
    ++  assert( *pi>=0 );
    +   return 5;
    + }
    + 
    +@@ -136345,6 +149292,7 @@ static int fts3DisconnectMethod(sqlite3_vtab *pVtab){
    +   assert( p->pSegments==0 );
    + 
    +   /* Free any prepared statements held */
    ++  sqlite3_finalize(p->pSeekStmt);
    +   for(i=0; i<SizeofArray(p->aStmt); i++){
    +     sqlite3_finalize(p->aStmt[i]);
    +   }
    +@@ -137070,65 +150018,66 @@ static int fts3InitVtab(
    +             break;
    +           }
    +         }
    +-        if( iOpt==SizeofArray(aFts4Opt) ){
    +-          sqlite3Fts3ErrMsg(pzErr, "unrecognized parameter: %s", z);
    +-          rc = SQLITE_ERROR;
    +-        }else{
    +-          switch( iOpt ){
    +-            case 0:               /* MATCHINFO */
    +-              if( strlen(zVal)!=4 || sqlite3_strnicmp(zVal, "fts3", 4) ){
    +-                sqlite3Fts3ErrMsg(pzErr, "unrecognized matchinfo: %s", zVal);
    +-                rc = SQLITE_ERROR;
    +-              }
    +-              bNoDocsize = 1;
    +-              break;
    ++        switch( iOpt ){
    ++          case 0:               /* MATCHINFO */
    ++            if( strlen(zVal)!=4 || sqlite3_strnicmp(zVal, "fts3", 4) ){
    ++              sqlite3Fts3ErrMsg(pzErr, "unrecognized matchinfo: %s", zVal);
    ++              rc = SQLITE_ERROR;
    ++            }
    ++            bNoDocsize = 1;
    ++            break;
    + 
    +-            case 1:               /* PREFIX */
    +-              sqlite3_free(zPrefix);
    +-              zPrefix = zVal;
    +-              zVal = 0;
    +-              break;
    ++          case 1:               /* PREFIX */
    ++            sqlite3_free(zPrefix);
    ++            zPrefix = zVal;
    ++            zVal = 0;
    ++            break;
    + 
    +-            case 2:               /* COMPRESS */
    +-              sqlite3_free(zCompress);
    +-              zCompress = zVal;
    +-              zVal = 0;
    +-              break;
    ++          case 2:               /* COMPRESS */
    ++            sqlite3_free(zCompress);
    ++            zCompress = zVal;
    ++            zVal = 0;
    ++            break;
    + 
    +-            case 3:               /* UNCOMPRESS */
    +-              sqlite3_free(zUncompress);
    +-              zUncompress = zVal;
    +-              zVal = 0;
    +-              break;
    ++          case 3:               /* UNCOMPRESS */
    ++            sqlite3_free(zUncompress);
    ++            zUncompress = zVal;
    ++            zVal = 0;
    ++            break;
    + 
    +-            case 4:               /* ORDER */
    +-              if( (strlen(zVal)!=3 || sqlite3_strnicmp(zVal, "asc", 3)) 
    +-               && (strlen(zVal)!=4 || sqlite3_strnicmp(zVal, "desc", 4)) 
    +-              ){
    +-                sqlite3Fts3ErrMsg(pzErr, "unrecognized order: %s", zVal);
    +-                rc = SQLITE_ERROR;
    +-              }
    +-              bDescIdx = (zVal[0]=='d' || zVal[0]=='D');
    +-              break;
    ++          case 4:               /* ORDER */
    ++            if( (strlen(zVal)!=3 || sqlite3_strnicmp(zVal, "asc", 3)) 
    ++             && (strlen(zVal)!=4 || sqlite3_strnicmp(zVal, "desc", 4)) 
    ++            ){
    ++              sqlite3Fts3ErrMsg(pzErr, "unrecognized order: %s", zVal);
    ++              rc = SQLITE_ERROR;
    ++            }
    ++            bDescIdx = (zVal[0]=='d' || zVal[0]=='D');
    ++            break;
    + 
    +-            case 5:              /* CONTENT */
    +-              sqlite3_free(zContent);
    +-              zContent = zVal;
    +-              zVal = 0;
    +-              break;
    ++          case 5:              /* CONTENT */
    ++            sqlite3_free(zContent);
    ++            zContent = zVal;
    ++            zVal = 0;
    ++            break;
    + 
    +-            case 6:              /* LANGUAGEID */
    +-              assert( iOpt==6 );
    +-              sqlite3_free(zLanguageid);
    +-              zLanguageid = zVal;
    +-              zVal = 0;
    +-              break;
    ++          case 6:              /* LANGUAGEID */
    ++            assert( iOpt==6 );
    ++            sqlite3_free(zLanguageid);
    ++            zLanguageid = zVal;
    ++            zVal = 0;
    ++            break;
    + 
    +-            case 7:              /* NOTINDEXED */
    +-              azNotindexed[nNotindexed++] = zVal;
    +-              zVal = 0;
    +-              break;
    +-          }
    ++          case 7:              /* NOTINDEXED */
    ++            azNotindexed[nNotindexed++] = zVal;
    ++            zVal = 0;
    ++            break;
    ++
    ++          default:
    ++            assert( iOpt==SizeofArray(aFts4Opt) );
    ++            sqlite3Fts3ErrMsg(pzErr, "unrecognized parameter: %s", z);
    ++            rc = SQLITE_ERROR;
    ++            break;
    +         }
    +         sqlite3_free(zVal);
    +       }
    +@@ -137216,9 +150165,9 @@ static int fts3InitVtab(
    +   p->pTokenizer = pTokenizer;
    +   p->nMaxPendingData = FTS3_MAX_PENDING_DATA;
    +   p->bHasDocsize = (isFts4 && bNoDocsize==0);
    +-  p->bHasStat = isFts4;
    +-  p->bFts4 = isFts4;
    +-  p->bDescIdx = bDescIdx;
    ++  p->bHasStat = (u8)isFts4;
    ++  p->bFts4 = (u8)isFts4;
    ++  p->bDescIdx = (u8)bDescIdx;
    +   p->nAutoincrmerge = 0xff;   /* 0xff means setting unknown */
    +   p->zContentTbl = zContent;
    +   p->zLanguageid = zLanguageid;
    +@@ -137249,7 +150198,9 @@ static int fts3InitVtab(
    +     char *z; 
    +     int n = 0;
    +     z = (char *)sqlite3Fts3NextToken(aCol[iCol], &n);
    +-    memcpy(zCsr, z, n);
    ++    if( n>0 ){
    ++      memcpy(zCsr, z, n);
    ++    }
    +     zCsr[n] = '\0';
    +     sqlite3Fts3Dequote(zCsr);
    +     p->azColumn[iCol] = zCsr;
    +@@ -137533,6 +150484,39 @@ static int fts3OpenMethod(sqlite3_vtab *pVTab, sqlite3_vtab_cursor **ppCsr){
    +   return SQLITE_OK;
    + }
    + 
    ++/*
    ++** Finalize the statement handle at pCsr->pStmt.
    ++**
    ++** Or, if that statement handle is one created by fts3CursorSeekStmt(),
    ++** and the Fts3Table.pSeekStmt slot is currently NULL, save the statement
    ++** pointer there instead of finalizing it.
    ++*/
    ++static void fts3CursorFinalizeStmt(Fts3Cursor *pCsr){
    ++  if( pCsr->bSeekStmt ){
    ++    Fts3Table *p = (Fts3Table *)pCsr->base.pVtab;
    ++    if( p->pSeekStmt==0 ){
    ++      p->pSeekStmt = pCsr->pStmt;
    ++      sqlite3_reset(pCsr->pStmt);
    ++      pCsr->pStmt = 0;
    ++    }
    ++    pCsr->bSeekStmt = 0;
    ++  }
    ++  sqlite3_finalize(pCsr->pStmt);
    ++}
    ++
    ++/*
    ++** Free all resources currently held by the cursor passed as the only
    ++** argument.
    ++*/
    ++static void fts3ClearCursor(Fts3Cursor *pCsr){
    ++  fts3CursorFinalizeStmt(pCsr);
    ++  sqlite3Fts3FreeDeferredTokens(pCsr);
    ++  sqlite3_free(pCsr->aDoclist);
    ++  sqlite3Fts3MIBufferFree(pCsr->pMIBuffer);
    ++  sqlite3Fts3ExprFree(pCsr->pExpr);
    ++  memset(&(&pCsr->base)[1], 0, sizeof(Fts3Cursor)-sizeof(sqlite3_vtab_cursor));
    ++}
    ++
    + /*
    + ** Close the cursor.  For additional information see the documentation
    + ** on the xClose method of the virtual table interface.
    +@@ -137540,11 +150524,7 @@ static int fts3OpenMethod(sqlite3_vtab *pVTab, sqlite3_vtab_cursor **ppCsr){
    + static int fts3CloseMethod(sqlite3_vtab_cursor *pCursor){
    +   Fts3Cursor *pCsr = (Fts3Cursor *)pCursor;
    +   assert( ((Fts3Table *)pCsr->base.pVtab)->pSegments==0 );
    +-  sqlite3_finalize(pCsr->pStmt);
    +-  sqlite3Fts3ExprFree(pCsr->pExpr);
    +-  sqlite3Fts3FreeDeferredTokens(pCsr);
    +-  sqlite3_free(pCsr->aDoclist);
    +-  sqlite3Fts3MIBufferFree(pCsr->pMIBuffer);
    ++  fts3ClearCursor(pCsr);
    +   assert( ((Fts3Table *)pCsr->base.pVtab)->pSegments==0 );
    +   sqlite3_free(pCsr);
    +   return SQLITE_OK;
    +@@ -137558,20 +150538,23 @@ static int fts3CloseMethod(sqlite3_vtab_cursor *pCursor){
    + **
    + ** (or the equivalent for a content=xxx table) and set pCsr->pStmt to
    + ** it. If an error occurs, return an SQLite error code.
    +-**
    +-** Otherwise, set *ppStmt to point to pCsr->pStmt and return SQLITE_OK.
    + */
    +-static int fts3CursorSeekStmt(Fts3Cursor *pCsr, sqlite3_stmt **ppStmt){
    ++static int fts3CursorSeekStmt(Fts3Cursor *pCsr){
    +   int rc = SQLITE_OK;
    +   if( pCsr->pStmt==0 ){
    +     Fts3Table *p = (Fts3Table *)pCsr->base.pVtab;
    +     char *zSql;
    +-    zSql = sqlite3_mprintf("SELECT %s WHERE rowid = ?", p->zReadExprlist);
    +-    if( !zSql ) return SQLITE_NOMEM;
    +-    rc = sqlite3_prepare_v2(p->db, zSql, -1, &pCsr->pStmt, 0);
    +-    sqlite3_free(zSql);
    ++    if( p->pSeekStmt ){
    ++      pCsr->pStmt = p->pSeekStmt;
    ++      p->pSeekStmt = 0;
    ++    }else{
    ++      zSql = sqlite3_mprintf("SELECT %s WHERE rowid = ?", p->zReadExprlist);
    ++      if( !zSql ) return SQLITE_NOMEM;
    ++      rc = sqlite3_prepare_v3(p->db, zSql,-1,SQLITE_PREPARE_PERSISTENT,&pCsr->pStmt,0);
    ++      sqlite3_free(zSql);
    ++    }
    ++    if( rc==SQLITE_OK ) pCsr->bSeekStmt = 1;
    +   }
    +-  *ppStmt = pCsr->pStmt;
    +   return rc;
    + }
    + 
    +@@ -137583,9 +150566,7 @@ static int fts3CursorSeekStmt(Fts3Cursor *pCsr, sqlite3_stmt **ppStmt){
    + static int fts3CursorSeek(sqlite3_context *pContext, Fts3Cursor *pCsr){
    +   int rc = SQLITE_OK;
    +   if( pCsr->isRequireSeek ){
    +-    sqlite3_stmt *pStmt = 0;
    +-
    +-    rc = fts3CursorSeekStmt(pCsr, &pStmt);
    ++    rc = fts3CursorSeekStmt(pCsr);
    +     if( rc==SQLITE_OK ){
    +       sqlite3_bind_int64(pCsr->pStmt, 1, pCsr->iPrevId);
    +       pCsr->isRequireSeek = 0;
    +@@ -137637,7 +150618,7 @@ static int fts3ScanInteriorNode(
    +   const char *zCsr = zNode;       /* Cursor to iterate through node */
    +   const char *zEnd = &zCsr[nNode];/* End of interior node buffer */
    +   char *zBuffer = 0;              /* Buffer to load terms into */
    +-  int nAlloc = 0;                 /* Size of allocated buffer */
    ++  i64 nAlloc = 0;                 /* Size of allocated buffer */
    +   int isFirstTerm = 1;            /* True when processing first term on page */
    +   sqlite3_int64 iChild;           /* Block id of child node to descend to */
    + 
    +@@ -137674,14 +150655,15 @@ static int fts3ScanInteriorNode(
    +     isFirstTerm = 0;
    +     zCsr += fts3GetVarint32(zCsr, &nSuffix);
    +     
    +-    if( nPrefix<0 || nSuffix<0 || &zCsr[nSuffix]>zEnd ){
    ++    assert( nPrefix>=0 && nSuffix>=0 );
    ++    if( nPrefix>zCsr-zNode || nSuffix>zEnd-zCsr ){
    +       rc = FTS_CORRUPT_VTAB;
    +       goto finish_scan;
    +     }
    +-    if( nPrefix+nSuffix>nAlloc ){
    ++    if( (i64)nPrefix+nSuffix>nAlloc ){
    +       char *zNew;
    +-      nAlloc = (nPrefix+nSuffix) * 2;
    +-      zNew = (char *)sqlite3_realloc(zBuffer, nAlloc);
    ++      nAlloc = ((i64)nPrefix+nSuffix) * 2;
    ++      zNew = (char *)sqlite3_realloc64(zBuffer, nAlloc);
    +       if( !zNew ){
    +         rc = SQLITE_NOMEM;
    +         goto finish_scan;
    +@@ -138484,7 +151466,7 @@ SQLITE_PRIVATE int sqlite3Fts3FirstFilter(
    +     fts3ColumnlistCopy(0, &p);
    +   }
    + 
    +-  while( p<pEnd && *p==0x01 ){
    ++  while( p<pEnd ){
    +     sqlite3_int64 iCol;
    +     p++;
    +     p += sqlite3Fts3GetVarint(p, &iCol);
    +@@ -139043,11 +152025,7 @@ static int fts3FilterMethod(
    +   assert( iIdx==nVal );
    + 
    +   /* In case the cursor has been used before, clear it now. */
    +-  sqlite3_finalize(pCsr->pStmt);
    +-  sqlite3_free(pCsr->aDoclist);
    +-  sqlite3Fts3MIBufferFree(pCsr->pMIBuffer);
    +-  sqlite3Fts3ExprFree(pCsr->pExpr);
    +-  memset(&pCursor[1], 0, sizeof(Fts3Cursor)-sizeof(sqlite3_vtab_cursor));
    ++  fts3ClearCursor(pCsr);
    + 
    +   /* Set the lower and upper bounds on docids to return */
    +   pCsr->iMinDocid = fts3DocidRange(pDocidGe, SMALLEST_INT64);
    +@@ -139105,13 +152083,13 @@ static int fts3FilterMethod(
    +       );
    +     }
    +     if( zSql ){
    +-      rc = sqlite3_prepare_v2(p->db, zSql, -1, &pCsr->pStmt, 0);
    ++      rc = sqlite3_prepare_v3(p->db,zSql,-1,SQLITE_PREPARE_PERSISTENT,&pCsr->pStmt,0);
    +       sqlite3_free(zSql);
    +     }else{
    +       rc = SQLITE_NOMEM;
    +     }
    +   }else if( eSearch==FTS3_DOCID_SEARCH ){
    +-    rc = fts3CursorSeekStmt(pCsr, &pCsr->pStmt);
    ++    rc = fts3CursorSeekStmt(pCsr);
    +     if( rc==SQLITE_OK ){
    +       rc = sqlite3_bind_value(pCsr->pStmt, 1, pCons);
    +     }
    +@@ -139126,7 +152104,12 @@ static int fts3FilterMethod(
    + ** routine to find out if it has reached the end of a result set.
    + */
    + static int fts3EofMethod(sqlite3_vtab_cursor *pCursor){
    +-  return ((Fts3Cursor *)pCursor)->isEof;
    ++  Fts3Cursor *pCsr = (Fts3Cursor*)pCursor;
    ++  if( pCsr->isEof ){
    ++    fts3ClearCursor(pCsr);
    ++    pCsr->isEof = 1;
    ++  }
    ++  return pCsr->isEof;
    + }
    + 
    + /* 
    +@@ -139164,33 +152147,37 @@ static int fts3ColumnMethod(
    +   /* The column value supplied by SQLite must be in range. */
    +   assert( iCol>=0 && iCol<=p->nColumn+2 );
    + 
    +-  if( iCol==p->nColumn+1 ){
    +-    /* This call is a request for the "docid" column. Since "docid" is an 
    +-    ** alias for "rowid", use the xRowid() method to obtain the value.
    +-    */
    +-    sqlite3_result_int64(pCtx, pCsr->iPrevId);
    +-  }else if( iCol==p->nColumn ){
    +-    /* The extra column whose name is the same as the table.
    +-    ** Return a blob which is a pointer to the cursor.  */
    +-    sqlite3_result_blob(pCtx, &pCsr, sizeof(pCsr), SQLITE_TRANSIENT);
    +-  }else if( iCol==p->nColumn+2 && pCsr->pExpr ){
    +-    sqlite3_result_int64(pCtx, pCsr->iLangid);
    +-  }else{
    +-    /* The requested column is either a user column (one that contains 
    +-    ** indexed data), or the language-id column.  */
    +-    rc = fts3CursorSeek(0, pCsr);
    ++  switch( iCol-p->nColumn ){
    ++    case 0:
    ++      /* The special 'table-name' column */
    ++      sqlite3_result_pointer(pCtx, pCsr, "fts3cursor", 0);
    ++      break;
    + 
    +-    if( rc==SQLITE_OK ){
    +-      if( iCol==p->nColumn+2 ){
    +-        int iLangid = 0;
    +-        if( p->zLanguageid ){
    +-          iLangid = sqlite3_column_int(pCsr->pStmt, p->nColumn+1);
    +-        }
    +-        sqlite3_result_int(pCtx, iLangid);
    +-      }else if( sqlite3_data_count(pCsr->pStmt)>(iCol+1) ){
    ++    case 1:
    ++      /* The docid column */
    ++      sqlite3_result_int64(pCtx, pCsr->iPrevId);
    ++      break;
    ++
    ++    case 2:
    ++      if( pCsr->pExpr ){
    ++        sqlite3_result_int64(pCtx, pCsr->iLangid);
    ++        break;
    ++      }else if( p->zLanguageid==0 ){
    ++        sqlite3_result_int(pCtx, 0);
    ++        break;
    ++      }else{
    ++        iCol = p->nColumn;
    ++        /* fall-through */
    ++      }
    ++
    ++    default:
    ++      /* A user column. Or, if this is a full-table scan, possibly the
    ++      ** language-id column. Seek the cursor. */
    ++      rc = fts3CursorSeek(0, pCsr);
    ++      if( rc==SQLITE_OK && sqlite3_data_count(pCsr->pStmt)-1>iCol ){
    +         sqlite3_result_value(pCtx, sqlite3_column_value(pCsr->pStmt, iCol+1));
    +       }
    +-    }
    ++      break;
    +   }
    + 
    +   assert( ((Fts3Table *)pCsr->base.pVtab)->pSegments==0 );
    +@@ -139239,8 +152226,10 @@ static int fts3SyncMethod(sqlite3_vtab *pVtab){
    +   const u32 nMinMerge = 64;       /* Minimum amount of incr-merge work to do */
    + 
    +   Fts3Table *p = (Fts3Table*)pVtab;
    +-  int rc = sqlite3Fts3PendingTermsFlush(p);
    ++  int rc;
    ++  i64 iLastRowid = sqlite3_last_insert_rowid(p->db);
    + 
    ++  rc = sqlite3Fts3PendingTermsFlush(p);
    +   if( rc==SQLITE_OK 
    +    && p->nLeafAdd>(nMinMerge/16) 
    +    && p->nAutoincrmerge && p->nAutoincrmerge!=0xff
    +@@ -139255,6 +152244,7 @@ static int fts3SyncMethod(sqlite3_vtab *pVtab){
    +     if( A>(int)nMinMerge ) rc = sqlite3Fts3Incrmerge(p, A, p->nAutoincrmerge);
    +   }
    +   sqlite3Fts3SegmentsClose(p);
    ++  sqlite3_set_last_insert_rowid(p->db, iLastRowid);
    +   return rc;
    + }
    + 
    +@@ -139267,17 +152257,11 @@ static int fts3SyncMethod(sqlite3_vtab *pVtab){
    + 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);
    ++    char *zTbl = sqlite3_mprintf("%s_stat", p->zName);
    ++    if( zTbl ){
    ++      int res = sqlite3_table_column_metadata(p->db, p->zDb, zTbl, 0,0,0,0,0,0);
    ++      sqlite3_free(zTbl);
    ++      p->bHasStat = (res==SQLITE_OK);
    +     }else{
    +       rc = SQLITE_NOMEM;
    +     }
    +@@ -139384,18 +152368,17 @@ static int fts3FunctionArg(
    +   sqlite3_value *pVal,            /* argv[0] passed to function */
    +   Fts3Cursor **ppCsr              /* OUT: Store cursor handle here */
    + ){
    +-  Fts3Cursor *pRet;
    +-  if( sqlite3_value_type(pVal)!=SQLITE_BLOB 
    +-   || sqlite3_value_bytes(pVal)!=sizeof(Fts3Cursor *)
    +-  ){
    ++  int rc;
    ++  *ppCsr = (Fts3Cursor*)sqlite3_value_pointer(pVal, "fts3cursor");
    ++  if( (*ppCsr)!=0 ){
    ++    rc = SQLITE_OK;
    ++  }else{
    +     char *zErr = sqlite3_mprintf("illegal first argument to %s", zFunc);
    +     sqlite3_result_error(pContext, zErr, -1);
    +     sqlite3_free(zErr);
    +-    return SQLITE_ERROR;
    ++    rc = SQLITE_ERROR;
    +   }
    +-  memcpy(&pRet, sqlite3_value_blob(pVal), sizeof(Fts3Cursor *));
    +-  *ppCsr = pRet;
    +-  return SQLITE_OK;
    ++  return rc;
    + }
    + 
    + /*
    +@@ -139782,7 +152765,7 @@ SQLITE_PRIVATE int sqlite3Fts3Init(sqlite3 *db){
    + #endif
    + 
    +   /* Create the virtual table wrapper around the hash-table and overload 
    +-  ** the two scalar functions. If this is successful, register the
    ++  ** the four scalar functions. If this is successful, register the
    +   ** module with sqlite.
    +   */
    +   if( SQLITE_OK==rc 
    +@@ -140365,7 +153348,7 @@ static int fts3EvalIncrPhraseNext(
    +   ** one incremental token. In which case the bIncr flag is set. */
    +   assert( p->bIncr==1 );
    + 
    +-  if( p->nToken==1 && p->bIncr ){
    ++  if( p->nToken==1 ){
    +     rc = sqlite3Fts3MsrIncrNext(pTab, p->aToken[0].pSegcsr, 
    +         &pDL->iDocid, &pDL->pList, &pDL->nList
    +     );
    +@@ -140598,6 +153581,7 @@ static void fts3EvalTokenCosts(
    + ** the number of overflow pages consumed by a record B bytes in size.
    + */
    + static int fts3EvalAverageDocsize(Fts3Cursor *pCsr, int *pnPage){
    ++  int rc = SQLITE_OK;
    +   if( pCsr->nRowAvg==0 ){
    +     /* The average document size, which is required to calculate the cost
    +     ** of each doclist, has not yet been determined. Read the required 
    +@@ -140610,7 +153594,6 @@ static int fts3EvalAverageDocsize(Fts3Cursor *pCsr, int *pnPage){
    +     ** data stored in all rows of each column of the table, from left
    +     ** to right.
    +     */
    +-    int rc;
    +     Fts3Table *p = (Fts3Table*)pCsr->base.pVtab;
    +     sqlite3_stmt *pStmt;
    +     sqlite3_int64 nDoc = 0;
    +@@ -140637,11 +153620,10 @@ static int fts3EvalAverageDocsize(Fts3Cursor *pCsr, int *pnPage){
    +     pCsr->nRowAvg = (int)(((nByte / nDoc) + p->nPgsz) / p->nPgsz);
    +     assert( pCsr->nRowAvg>0 ); 
    +     rc = sqlite3_reset(pStmt);
    +-    if( rc!=SQLITE_OK ) return rc;
    +   }
    + 
    +   *pnPage = pCsr->nRowAvg;
    +-  return SQLITE_OK;
    ++  return rc;
    + }
    + 
    + /*
    +@@ -140991,7 +153973,8 @@ static void fts3EvalNextRow(
    +           pExpr->iDocid = pLeft->iDocid;
    +           pExpr->bEof = (pLeft->bEof || pRight->bEof);
    +           if( pExpr->eType==FTSQUERY_NEAR && pExpr->bEof ){
    +-            if( pRight->pPhrase && pRight->pPhrase->doclist.aAll ){
    ++            assert( pRight->eType==FTSQUERY_PHRASE );
    ++            if( pRight->pPhrase->doclist.aAll ){
    +               Fts3Doclist *pDl = &pRight->pPhrase->doclist;
    +               while( *pRc==SQLITE_OK && pRight->bEof==0 ){
    +                 memset(pDl->pList, 0, pDl->nList);
    +@@ -141020,7 +154003,7 @@ static void fts3EvalNextRow(
    + 
    +         if( pRight->bEof || (pLeft->bEof==0 && iCmp<0) ){
    +           fts3EvalNextRow(pCsr, pLeft, pRc);
    +-        }else if( pLeft->bEof || (pRight->bEof==0 && iCmp>0) ){
    ++        }else if( pLeft->bEof || iCmp>0 ){
    +           fts3EvalNextRow(pCsr, pRight, pRc);
    +         }else{
    +           fts3EvalNextRow(pCsr, pLeft, pRc);
    +@@ -141112,7 +154095,6 @@ static int fts3EvalNearTest(Fts3Expr *pExpr, int *pRc){
    +   */
    +   if( *pRc==SQLITE_OK 
    +    && pExpr->eType==FTSQUERY_NEAR 
    +-   && pExpr->bEof==0
    +    && (pExpr->pParent==0 || pExpr->pParent->eType!=FTSQUERY_NEAR)
    +   ){
    +     Fts3Expr *p; 
    +@@ -141121,42 +154103,39 @@ static int fts3EvalNearTest(Fts3Expr *pExpr, int *pRc){
    + 
    +     /* Allocate temporary working space. */
    +     for(p=pExpr; p->pLeft; p=p->pLeft){
    ++      assert( p->pRight->pPhrase->doclist.nList>0 );
    +       nTmp += p->pRight->pPhrase->doclist.nList;
    +     }
    +     nTmp += p->pPhrase->doclist.nList;
    +-    if( nTmp==0 ){
    ++    aTmp = sqlite3_malloc(nTmp*2);
    ++    if( !aTmp ){
    ++      *pRc = SQLITE_NOMEM;
    +       res = 0;
    +     }else{
    +-      aTmp = sqlite3_malloc(nTmp*2);
    +-      if( !aTmp ){
    +-        *pRc = SQLITE_NOMEM;
    +-        res = 0;
    +-      }else{
    +-        char *aPoslist = p->pPhrase->doclist.pList;
    +-        int nToken = p->pPhrase->nToken;
    +-
    +-        for(p=p->pParent;res && p && p->eType==FTSQUERY_NEAR; p=p->pParent){
    +-          Fts3Phrase *pPhrase = p->pRight->pPhrase;
    +-          int nNear = p->nNear;
    +-          res = fts3EvalNearTrim(nNear, aTmp, &aPoslist, &nToken, pPhrase);
    +-        }
    +-
    +-        aPoslist = pExpr->pRight->pPhrase->doclist.pList;
    +-        nToken = pExpr->pRight->pPhrase->nToken;
    +-        for(p=pExpr->pLeft; p && res; p=p->pLeft){
    +-          int nNear;
    +-          Fts3Phrase *pPhrase;
    +-          assert( p->pParent && p->pParent->pLeft==p );
    +-          nNear = p->pParent->nNear;
    +-          pPhrase = (
    +-              p->eType==FTSQUERY_NEAR ? p->pRight->pPhrase : p->pPhrase
    +-              );
    +-          res = fts3EvalNearTrim(nNear, aTmp, &aPoslist, &nToken, pPhrase);
    +-        }
    ++      char *aPoslist = p->pPhrase->doclist.pList;
    ++      int nToken = p->pPhrase->nToken;
    ++
    ++      for(p=p->pParent;res && p && p->eType==FTSQUERY_NEAR; p=p->pParent){
    ++        Fts3Phrase *pPhrase = p->pRight->pPhrase;
    ++        int nNear = p->nNear;
    ++        res = fts3EvalNearTrim(nNear, aTmp, &aPoslist, &nToken, pPhrase);
    +       }
    + 
    +-      sqlite3_free(aTmp);
    ++      aPoslist = pExpr->pRight->pPhrase->doclist.pList;
    ++      nToken = pExpr->pRight->pPhrase->nToken;
    ++      for(p=pExpr->pLeft; p && res; p=p->pLeft){
    ++        int nNear;
    ++        Fts3Phrase *pPhrase;
    ++        assert( p->pParent && p->pParent->pLeft==p );
    ++        nNear = p->pParent->nNear;
    ++        pPhrase = (
    ++            p->eType==FTSQUERY_NEAR ? p->pRight->pPhrase : p->pPhrase
    ++        );
    ++        res = fts3EvalNearTrim(nNear, aTmp, &aPoslist, &nToken, pPhrase);
    ++      }
    +     }
    ++
    ++    sqlite3_free(aTmp);
    +   }
    + 
    +   return res;
    +@@ -141764,7 +154743,7 @@ SQLITE_PRIVATE int sqlite3Fts3Corrupt(){
    + #ifdef _WIN32
    + __declspec(dllexport)
    + #endif
    +-SQLITE_API int SQLITE_STDCALL sqlite3_fts3_init(
    ++SQLITE_API int sqlite3_fts3_init(
    +   sqlite3 *db, 
    +   char **pzErrMsg,
    +   const sqlite3_api_routines *pApi
    +@@ -144725,6 +157704,18 @@ SQLITE_PRIVATE void sqlite3Fts3PorterTokenizerModule(
    + /* #include <assert.h> */
    + /* #include <string.h> */
    + 
    ++/*
    ++** Return true if the two-argument version of fts3_tokenizer()
    ++** has been activated via a prior call to sqlite3_db_config(db,
    ++** SQLITE_DBCONFIG_ENABLE_FTS3_TOKENIZER, 1, 0);
    ++*/
    ++static int fts3TokenizerEnabled(sqlite3_context *context){
    ++  sqlite3 *db = sqlite3_context_db_handle(context);
    ++  int isEnabled = 0;
    ++  sqlite3_db_config(db,SQLITE_DBCONFIG_ENABLE_FTS3_TOKENIZER,-1,&isEnabled);
    ++  return isEnabled;
    ++}
    ++
    + /*
    + ** Implementation of the SQL scalar function for accessing the underlying 
    + ** hash table. This function may be called as follows:
    +@@ -144745,7 +157736,7 @@ SQLITE_PRIVATE void sqlite3Fts3PorterTokenizerModule(
    + ** is a blob containing the pointer stored as the hash data corresponding
    + ** to string <key-name> (after the hash-table is updated, if applicable).
    + */
    +-static void scalarFunc(
    ++static void fts3TokenizerFunc(
    +   sqlite3_context *context,
    +   int argc,
    +   sqlite3_value **argv
    +@@ -144763,16 +157754,20 @@ static void scalarFunc(
    +   nName = sqlite3_value_bytes(argv[0])+1;
    + 
    +   if( argc==2 ){
    +-    void *pOld;
    +-    int n = sqlite3_value_bytes(argv[1]);
    +-    if( zName==0 || n!=sizeof(pPtr) ){
    +-      sqlite3_result_error(context, "argument type mismatch", -1);
    +-      return;
    +-    }
    +-    pPtr = *(void **)sqlite3_value_blob(argv[1]);
    +-    pOld = sqlite3Fts3HashInsert(pHash, (void *)zName, nName, pPtr);
    +-    if( pOld==pPtr ){
    +-      sqlite3_result_error(context, "out of memory", -1);
    ++    if( fts3TokenizerEnabled(context) ){
    ++      void *pOld;
    ++      int n = sqlite3_value_bytes(argv[1]);
    ++      if( zName==0 || n!=sizeof(pPtr) ){
    ++        sqlite3_result_error(context, "argument type mismatch", -1);
    ++        return;
    ++      }
    ++      pPtr = *(void **)sqlite3_value_blob(argv[1]);
    ++      pOld = sqlite3Fts3HashInsert(pHash, (void *)zName, nName, pPtr);
    ++      if( pOld==pPtr ){
    ++        sqlite3_result_error(context, "out of memory", -1);
    ++      }
    ++    }else{
    ++      sqlite3_result_error(context, "fts3tokenize disabled", -1);
    +       return;
    +     }
    +   }else{
    +@@ -144786,7 +157781,6 @@ static void scalarFunc(
    +       return;
    +     }
    +   }
    +-
    +   sqlite3_result_blob(context, (void *)&pPtr, sizeof(pPtr), SQLITE_TRANSIENT);
    + }
    + 
    +@@ -144905,7 +157899,11 @@ SQLITE_PRIVATE int sqlite3Fts3InitTokenizer(
    + 
    + #ifdef SQLITE_TEST
    + 
    +-#include <tcl.h>
    ++#if defined(INCLUDE_SQLITE_TCL_H)
    ++#  include "sqlite_tcl.h"
    ++#else
    ++#  include "tcl.h"
    ++#endif
    + /* #include <string.h> */
    + 
    + /*
    +@@ -145046,6 +158044,7 @@ int registerTokenizer(
    +   return sqlite3_finalize(pStmt);
    + }
    + 
    ++
    + static
    + int queryTokenizer(
    +   sqlite3 *db, 
    +@@ -145116,11 +158115,13 @@ static void intTestFunc(
    +   assert( 0==strcmp(sqlite3_errmsg(db), "unknown tokenizer: nosuchtokenizer") );
    + 
    +   /* Test the storage function */
    +-  rc = registerTokenizer(db, "nosuchtokenizer", p1);
    +-  assert( rc==SQLITE_OK );
    +-  rc = queryTokenizer(db, "nosuchtokenizer", &p2);
    +-  assert( rc==SQLITE_OK );
    +-  assert( p2==p1 );
    ++  if( fts3TokenizerEnabled(context) ){
    ++    rc = registerTokenizer(db, "nosuchtokenizer", p1);
    ++    assert( rc==SQLITE_OK );
    ++    rc = queryTokenizer(db, "nosuchtokenizer", &p2);
    ++    assert( rc==SQLITE_OK );
    ++    assert( p2==p1 );
    ++  }
    + 
    +   sqlite3_result_text(context, "ok", -1, SQLITE_STATIC);
    + }
    +@@ -145136,7 +158137,7 @@ static void intTestFunc(
    + **    sqlite3Fts3HashInit(pHash, FTS3_HASH_STRING, 1);
    + **
    + ** This function adds a scalar function (see header comment above
    +-** scalarFunc() in this file for details) and, if ENABLE_TABLE is
    ++** fts3TokenizerFunc() in this file for details) and, if ENABLE_TABLE is
    + ** defined at compilation time, a temporary virtual table (see header 
    + ** comment above struct HashTableVtab) to the database schema. Both 
    + ** provide read/write access to the contents of *pHash.
    +@@ -145165,10 +158166,10 @@ SQLITE_PRIVATE int sqlite3Fts3InitHashTable(
    + #endif
    + 
    +   if( SQLITE_OK==rc ){
    +-    rc = sqlite3_create_function(db, zName, 1, any, p, scalarFunc, 0, 0);
    ++    rc = sqlite3_create_function(db, zName, 1, any, p, fts3TokenizerFunc, 0, 0);
    +   }
    +   if( SQLITE_OK==rc ){
    +-    rc = sqlite3_create_function(db, zName, 2, any, p, scalarFunc, 0, 0);
    ++    rc = sqlite3_create_function(db, zName, 2, any, p, fts3TokenizerFunc, 0, 0);
    +   }
    + #ifdef SQLITE_TEST
    +   if( SQLITE_OK==rc ){
    +@@ -146220,7 +159221,8 @@ static int fts3SqlStmt(
    + ** of the oldest level in the db that contains at least ? segments. Or,
    + ** if no level in the FTS index contains more than ? segments, the statement
    + ** returns zero rows.  */
    +-/* 28 */ "SELECT level FROM %Q.'%q_segdir' GROUP BY level HAVING count(*)>=?"
    ++/* 28 */ "SELECT level, count(*) AS cnt FROM %Q.'%q_segdir' "
    ++         "  GROUP BY level HAVING cnt>=?"
    +          "  ORDER BY (level %% 1024) ASC LIMIT 1",
    + 
    + /* Estimate the upper limit on the number of leaf nodes in a new segment
    +@@ -146293,7 +159295,8 @@ static int fts3SqlStmt(
    +     if( !zSql ){
    +       rc = SQLITE_NOMEM;
    +     }else{
    +-      rc = sqlite3_prepare_v2(p->db, zSql, -1, &pStmt, NULL);
    ++      rc = sqlite3_prepare_v3(p->db, zSql, -1, SQLITE_PREPARE_PERSISTENT,
    ++                              &pStmt, NULL);
    +       sqlite3_free(zSql);
    +       assert( rc==SQLITE_OK || pStmt==0 );
    +       p->aStmt[eStmt] = pStmt;
    +@@ -147259,15 +160262,19 @@ static int fts3SegReaderNext(
    +   ** safe (no risk of overread) even if the node data is corrupted. */
    +   pNext += fts3GetVarint32(pNext, &nPrefix);
    +   pNext += fts3GetVarint32(pNext, &nSuffix);
    +-  if( nPrefix<0 || nSuffix<=0 
    +-   || &pNext[nSuffix]>&pReader->aNode[pReader->nNode] 
    ++  if( nSuffix<=0
    ++   || (&pReader->aNode[pReader->nNode] - pNext)<nSuffix
    ++   || nPrefix>pReader->nTermAlloc
    +   ){
    +     return FTS_CORRUPT_VTAB;
    +   }
    + 
    +-  if( nPrefix+nSuffix>pReader->nTermAlloc ){
    +-    int nNew = (nPrefix+nSuffix)*2;
    +-    char *zNew = sqlite3_realloc(pReader->zTerm, nNew);
    ++  /* Both nPrefix and nSuffix were read by fts3GetVarint32() and so are
    ++  ** between 0 and 0x7FFFFFFF. But the sum of the two may cause integer
    ++  ** overflow - hence the (i64) casts.  */
    ++  if( (i64)nPrefix+nSuffix>(i64)pReader->nTermAlloc ){
    ++    i64 nNew = ((i64)nPrefix+nSuffix)*2;
    ++    char *zNew = sqlite3_realloc64(pReader->zTerm, nNew);
    +     if( !zNew ){
    +       return SQLITE_NOMEM;
    +     }
    +@@ -147289,7 +160296,7 @@ static int fts3SegReaderNext(
    +   ** b-tree node. And that the final byte of the doclist is 0x00. If either 
    +   ** of these statements is untrue, then the data structure is corrupt.
    +   */
    +-  if( &pReader->aDoclist[pReader->nDoclist]>&pReader->aNode[pReader->nNode] 
    ++  if( (&pReader->aNode[pReader->nNode] - pReader->aDoclist)<pReader->nDoclist
    +    || (pReader->nPopulate==0 && pReader->aDoclist[pReader->nDoclist-1])
    +   ){
    +     return FTS_CORRUPT_VTAB;
    +@@ -149081,7 +162088,7 @@ static int fts3SegmentMerge(
    +     ** segment. The level of the new segment is equal to the numerically
    +     ** greatest segment level currently present in the database for this
    +     ** index. The idx of the new segment is always 0.  */
    +-    if( csr.nSegment==1 ){
    ++    if( csr.nSegment==1 && 0==fts3SegReaderIsPending(csr.apSegment[0]) ){
    +       rc = SQLITE_DONE;
    +       goto finished;
    +     }
    +@@ -149612,6 +162619,9 @@ static int nodeReaderNext(NodeReader *p){
    +     }
    +     p->iOff += fts3GetVarint32(&p->aNode[p->iOff], &nSuffix);
    + 
    ++    if( nPrefix>p->iOff || nSuffix>p->nNode-p->iOff ){
    ++      return SQLITE_CORRUPT_VTAB;
    ++    }
    +     blobGrowBuffer(&p->term, nPrefix+nSuffix, &rc);
    +     if( rc==SQLITE_OK ){
    +       memcpy(&p->term.a[nPrefix], &p->aNode[p->iOff], nSuffix);
    +@@ -149619,6 +162629,9 @@ static int nodeReaderNext(NodeReader *p){
    +       p->iOff += nSuffix;
    +       if( p->iChild==0 ){
    +         p->iOff += fts3GetVarint32(&p->aNode[p->iOff], &p->nDoclist);
    ++        if( (p->nNode-p->iOff)<p->nDoclist ){
    ++          return SQLITE_CORRUPT_VTAB;
    ++        }
    +         p->aDoclist = &p->aNode[p->iOff];
    +         p->iOff += p->nDoclist;
    +       }
    +@@ -149626,7 +162639,6 @@ static int nodeReaderNext(NodeReader *p){
    +   }
    + 
    +   assert( p->iOff<=p->nNode );
    +-
    +   return rc;
    + }
    + 
    +@@ -150723,10 +163735,11 @@ SQLITE_PRIVATE int sqlite3Fts3Incrmerge(Fts3Table *p, int nMerge, int nMin){
    +     ** set nSeg to -1.
    +     */
    +     rc = fts3SqlStmt(p, SQL_FIND_MERGE_LEVEL, &pFindLevel, 0);
    +-    sqlite3_bind_int(pFindLevel, 1, nMin);
    ++    sqlite3_bind_int(pFindLevel, 1, MAX(2, nMin));
    +     if( sqlite3_step(pFindLevel)==SQLITE_ROW ){
    +       iAbsLevel = sqlite3_column_int64(pFindLevel, 0);
    +-      nSeg = nMin;
    ++      nSeg = sqlite3_column_int(pFindLevel, 1);
    ++      assert( nSeg>=2 );
    +     }else{
    +       nSeg = -1;
    +     }
    +@@ -150841,11 +163854,14 @@ SQLITE_PRIVATE int sqlite3Fts3Incrmerge(Fts3Table *p, int nMerge, int nMin){
    + ** Convert the text beginning at *pz into an integer and return
    + ** its value.  Advance *pz to point to the first character past
    + ** the integer.
    ++**
    ++** This function used for parameters to merge= and incrmerge=
    ++** commands. 
    + */
    + static int fts3Getint(const char **pz){
    +   const char *z = *pz;
    +   int i = 0;
    +-  while( (*z)>='0' && (*z)<='9' ) i = 10*i + *(z++) - '0';
    ++  while( (*z)>='0' && (*z)<='9' && i<214748363 ) i = 10*i + *(z++) - '0';
    +   *pz = z;
    +   return i;
    + }
    +@@ -153411,16 +166427,16 @@ static int unicodeAddExceptions(
    + ){
    +   const unsigned char *z = (const unsigned char *)zIn;
    +   const unsigned char *zTerm = &z[nIn];
    +-  int iCode;
    ++  unsigned int iCode;
    +   int nEntry = 0;
    + 
    +   assert( bAlnum==0 || bAlnum==1 );
    + 
    +   while( z<zTerm ){
    +     READ_UTF8(z, zTerm, iCode);
    +-    assert( (sqlite3FtsUnicodeIsalnum(iCode) & 0xFFFFFFFE)==0 );
    +-    if( sqlite3FtsUnicodeIsalnum(iCode)!=bAlnum 
    +-     && sqlite3FtsUnicodeIsdiacritic(iCode)==0 
    ++    assert( (sqlite3FtsUnicodeIsalnum((int)iCode) & 0xFFFFFFFE)==0 );
    ++    if( sqlite3FtsUnicodeIsalnum((int)iCode)!=bAlnum 
    ++     && sqlite3FtsUnicodeIsdiacritic((int)iCode)==0 
    +     ){
    +       nEntry++;
    +     }
    +@@ -153437,13 +166453,13 @@ static int unicodeAddExceptions(
    +     z = (const unsigned char *)zIn;
    +     while( z<zTerm ){
    +       READ_UTF8(z, zTerm, iCode);
    +-      if( sqlite3FtsUnicodeIsalnum(iCode)!=bAlnum 
    +-       && sqlite3FtsUnicodeIsdiacritic(iCode)==0
    ++      if( sqlite3FtsUnicodeIsalnum((int)iCode)!=bAlnum 
    ++       && sqlite3FtsUnicodeIsdiacritic((int)iCode)==0
    +       ){
    +         int i, j;
    +-        for(i=0; i<nNew && aNew[i]<iCode; i++);
    ++        for(i=0; i<nNew && aNew[i]<(int)iCode; i++);
    +         for(j=nNew; j>i; j--) aNew[j] = aNew[j-1];
    +-        aNew[i] = iCode;
    ++        aNew[i] = (int)iCode;
    +         nNew++;
    +       }
    +     }
    +@@ -153593,7 +166609,7 @@ static int unicodeNext(
    + ){
    +   unicode_cursor *pCsr = (unicode_cursor *)pC;
    +   unicode_tokenizer *p = ((unicode_tokenizer *)pCsr->base.pTokenizer);
    +-  int iCode = 0;
    ++  unsigned int iCode = 0;
    +   char *zOut;
    +   const unsigned char *z = &pCsr->aInput[pCsr->iOff];
    +   const unsigned char *zStart = z;
    +@@ -153605,7 +166621,7 @@ static int unicodeNext(
    +   ** the input.  */
    +   while( z<zTerm ){
    +     READ_UTF8(z, zTerm, iCode);
    +-    if( unicodeIsAlnum(p, iCode) ) break;
    ++    if( unicodeIsAlnum(p, (int)iCode) ) break;
    +     zStart = z;
    +   }
    +   if( zStart>=zTerm ) return SQLITE_DONE;
    +@@ -153625,7 +166641,7 @@ static int unicodeNext(
    + 
    +     /* Write the folded case of the last character read to the output */
    +     zEnd = z;
    +-    iOut = sqlite3FtsUnicodeFold(iCode, p->bRemoveDiacritic);
    ++    iOut = sqlite3FtsUnicodeFold((int)iCode, p->bRemoveDiacritic);
    +     if( iOut ){
    +       WRITE_UTF8(zOut, iOut);
    +     }
    +@@ -153633,8 +166649,8 @@ static int unicodeNext(
    +     /* If the cursor is not at EOF, read the next character */
    +     if( z>=zTerm ) break;
    +     READ_UTF8(z, zTerm, iCode);
    +-  }while( unicodeIsAlnum(p, iCode) 
    +-       || sqlite3FtsUnicodeIsdiacritic(iCode)
    ++  }while( unicodeIsAlnum(p, (int)iCode) 
    ++       || sqlite3FtsUnicodeIsdiacritic((int)iCode)
    +   );
    + 
    +   /* Set the output variables and return. */
    +@@ -153798,9 +166814,9 @@ SQLITE_PRIVATE int sqlite3FtsUnicodeIsalnum(int c){
    +     0xFFFFFFFF, 0xFC00FFFF, 0xF8000001, 0xF8000001,
    +   };
    + 
    +-  if( c<128 ){
    +-    return ( (aAscii[c >> 5] & (1 << (c & 0x001F)))==0 );
    +-  }else if( c<(1<<22) ){
    ++  if( (unsigned int)c<128 ){
    ++    return ( (aAscii[c >> 5] & ((unsigned int)1 << (c & 0x001F)))==0 );
    ++  }else if( (unsigned int)c<(1<<22) ){
    +     unsigned int key = (((unsigned int)c)<<10) | 0x000003FF;
    +     int iRes = 0;
    +     int iHi = sizeof(aEntry)/sizeof(aEntry[0]) - 1;
    +@@ -153993,16 +167009,17 @@ SQLITE_PRIVATE int sqlite3FtsUnicodeFold(int c, int bRemoveDiacritic){
    + 
    +   int ret = c;
    + 
    +-  assert( c>=0 );
    +   assert( sizeof(unsigned short)==2 && sizeof(unsigned char)==1 );
    + 
    +   if( c<128 ){
    +     if( c>='A' && c<='Z' ) ret = c + ('a' - 'A');
    +   }else if( c<65536 ){
    ++    const struct TableEntry *p;
    +     int iHi = sizeof(aEntry)/sizeof(aEntry[0]) - 1;
    +     int iLo = 0;
    +     int iRes = -1;
    + 
    ++    assert( c>aEntry[0].iCode );
    +     while( iHi>=iLo ){
    +       int iTest = (iHi + iLo) / 2;
    +       int cmp = (c - aEntry[iTest].iCode);
    +@@ -154013,14 +167030,12 @@ SQLITE_PRIVATE int sqlite3FtsUnicodeFold(int c, int bRemoveDiacritic){
    +         iHi = iTest-1;
    +       }
    +     }
    +-    assert( iRes<0 || c>=aEntry[iRes].iCode );
    + 
    +-    if( iRes>=0 ){
    +-      const struct TableEntry *p = &aEntry[iRes];
    +-      if( c<(p->iCode + p->nRange) && 0==(0x01 & p->flags & (p->iCode ^ c)) ){
    +-        ret = (c + (aiOff[p->flags>>1])) & 0x0000FFFF;
    +-        assert( ret>0 );
    +-      }
    ++    assert( iRes>=0 && c>=aEntry[iRes].iCode );
    ++    p = &aEntry[iRes];
    ++    if( c<(p->iCode + p->nRange) && 0==(0x01 & p->flags & (p->iCode ^ c)) ){
    ++      ret = (c + (aiOff[p->flags>>1])) & 0x0000FFFF;
    ++      assert( ret>0 );
    +     }
    + 
    +     if( bRemoveDiacritic ) ret = remove_diacritic(ret);
    +@@ -154091,7 +167106,8 @@ SQLITE_PRIVATE int sqlite3FtsUnicodeFold(int c, int bRemoveDiacritic){
    + **      child page.
    + */
    + 
    +-#if !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_RTREE)
    ++#if !defined(SQLITE_CORE) \
    ++  || (defined(SQLITE_ENABLE_RTREE) && !defined(SQLITE_OMIT_VIRTUALTABLE))
    + 
    + #ifndef SQLITE_CORE
    + /*   #include "sqlite3ext.h" */
    +@@ -154107,6 +167123,7 @@ SQLITE_PRIVATE int sqlite3FtsUnicodeFold(int c, int bRemoveDiacritic){
    + #ifndef SQLITE_AMALGAMATION
    + #include "sqlite3rtree.h"
    + typedef sqlite3_int64 i64;
    ++typedef sqlite3_uint64 u64;
    + typedef unsigned char u8;
    + typedef unsigned short u16;
    + typedef unsigned int u32;
    +@@ -154155,13 +167172,16 @@ struct Rtree {
    +   sqlite3 *db;                /* Host database connection */
    +   int iNodeSize;              /* Size in bytes of each node in the node table */
    +   u8 nDim;                    /* Number of dimensions */
    ++  u8 nDim2;                   /* Twice the number of dimensions */
    +   u8 eCoordType;              /* RTREE_COORD_REAL32 or RTREE_COORD_INT32 */
    +   u8 nBytesPerCell;           /* Bytes consumed per cell */
    ++  u8 inWrTrans;               /* True if inside write transaction */
    +   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 */ 
    +-  int nBusy;                  /* Current number of users of this structure */
    ++  u32 nBusy;                  /* Current number of users of this structure */
    +   i64 nRowEst;                /* Estimated number of rows in this table */
    ++  u32 nCursor;                /* Number of open cursors */
    + 
    +   /* List of nodes removed during a CondenseTree operation. List is
    +   ** linked together via the pointer normally used for hash chains -
    +@@ -154171,8 +167191,10 @@ struct Rtree {
    +   RtreeNode *pDeleted;
    +   int iReinsertHeight;        /* Height of sub-trees Reinsert() has run on */
    + 
    ++  /* Blob I/O on xxx_node */
    ++  sqlite3_blob *pNodeBlob;
    ++
    +   /* Statements to read/write/delete a record from xxx_node */
    +-  sqlite3_stmt *pReadNode;
    +   sqlite3_stmt *pWriteNode;
    +   sqlite3_stmt *pDeleteNode;
    + 
    +@@ -154242,7 +167264,7 @@ struct RtreeSearchPoint {
    + ** The smallest possible node-size is (512-64)==448 bytes. And the largest
    + ** supported cell size is 48 bytes (8 byte rowid + ten 4 byte coordinates).
    + ** Therefore all non-root nodes must contain at least 3 entries. Since 
    +-** 2^40 is greater than 2^64, an r-tree structure always has a depth of
    ++** 3^40 is greater than 2^64, an r-tree structure always has a depth of
    + ** 40 or less.
    + */
    + #define RTREE_MAX_DEPTH 40
    +@@ -154372,14 +167394,6 @@ struct RtreeGeomCallback {
    +   void *pContext;
    + };
    + 
    +-
    +-/*
    +-** Value for the first field of every RtreeMatchArg object. The MATCH
    +-** operator tests that the first field of a blob operand matches this
    +-** value to avoid operating on invalid blobs (which could cause a segfault).
    +-*/
    +-#define RTREE_GEOMETRY_MAGIC 0x891245AB
    +-
    + /*
    + ** An instance of this structure (in the form of a BLOB) is returned by
    + ** the SQL functions that sqlite3_rtree_geometry_callback() and
    +@@ -154387,7 +167401,7 @@ struct RtreeGeomCallback {
    + ** operand to the MATCH operator of an R-Tree.
    + */
    + struct RtreeMatchArg {
    +-  u32 magic;                  /* Always RTREE_GEOMETRY_MAGIC */
    ++  u32 iSize;                  /* Size of this object */
    +   RtreeGeomCallback cb;       /* Info about the callback functions */
    +   int nParam;                 /* Number of parameters to the SQL function */
    +   sqlite3_value **apSqlParam; /* Original SQL parameter values */
    +@@ -154401,6 +167415,58 @@ struct RtreeMatchArg {
    + # define MIN(x,y) ((x) > (y) ? (y) : (x))
    + #endif
    + 
    ++/* What version of GCC is being used.  0 means GCC is not being used .
    ++** Note that the GCC_VERSION macro will also be set correctly when using
    ++** clang, since clang works hard to be gcc compatible.  So the gcc
    ++** optimizations will also work when compiling with clang.
    ++*/
    ++#ifndef GCC_VERSION
    ++#if defined(__GNUC__) && !defined(SQLITE_DISABLE_INTRINSIC)
    ++# define GCC_VERSION (__GNUC__*1000000+__GNUC_MINOR__*1000+__GNUC_PATCHLEVEL__)
    ++#else
    ++# define GCC_VERSION 0
    ++#endif
    ++#endif
    ++
    ++/* The testcase() macro should already be defined in the amalgamation.  If
    ++** it is not, make it a no-op.
    ++*/
    ++#ifndef SQLITE_AMALGAMATION
    ++# define testcase(X)
    ++#endif
    ++
    ++/*
    ++** Macros to determine whether the machine is big or little endian,
    ++** 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.
    ++*/
    ++#ifndef SQLITE_BYTEORDER
    ++#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__)
    ++# define SQLITE_BYTEORDER    1234
    ++#elif defined(sparc)    || defined(__ppc__)
    ++# define SQLITE_BYTEORDER    4321
    ++#else
    ++# define SQLITE_BYTEORDER    0     /* 0 means "unknown at compile-time" */
    ++#endif
    ++#endif
    ++
    ++
    ++/* What version of MSVC is being used.  0 means MSVC is not being used */
    ++#ifndef MSVC_VERSION
    ++#if defined(_MSC_VER) && !defined(SQLITE_DISABLE_INTRINSIC)
    ++# define MSVC_VERSION _MSC_VER
    ++#else
    ++# define MSVC_VERSION 0
    ++#endif
    ++#endif
    ++
    + /*
    + ** Functions to deserialize a 16 bit integer, 32 bit real number and
    + ** 64 bit integer. The deserialized value is returned.
    +@@ -154409,24 +167475,47 @@ static int readInt16(u8 *p){
    +   return (p[0]<<8) + p[1];
    + }
    + static void readCoord(u8 *p, RtreeCoord *pCoord){
    ++  assert( ((((char*)p) - (char*)0)&3)==0 );  /* p is always 4-byte aligned */
    ++#if SQLITE_BYTEORDER==1234 && MSVC_VERSION>=1300
    ++  pCoord->u = _byteswap_ulong(*(u32*)p);
    ++#elif SQLITE_BYTEORDER==1234 && GCC_VERSION>=4003000
    ++  pCoord->u = __builtin_bswap32(*(u32*)p);
    ++#elif SQLITE_BYTEORDER==4321
    ++  pCoord->u = *(u32*)p;
    ++#else
    +   pCoord->u = (
    +     (((u32)p[0]) << 24) + 
    +     (((u32)p[1]) << 16) + 
    +     (((u32)p[2]) <<  8) + 
    +     (((u32)p[3]) <<  0)
    +   );
    ++#endif
    + }
    + static i64 readInt64(u8 *p){
    +-  return (
    +-    (((i64)p[0]) << 56) + 
    +-    (((i64)p[1]) << 48) + 
    +-    (((i64)p[2]) << 40) + 
    +-    (((i64)p[3]) << 32) + 
    +-    (((i64)p[4]) << 24) + 
    +-    (((i64)p[5]) << 16) + 
    +-    (((i64)p[6]) <<  8) + 
    +-    (((i64)p[7]) <<  0)
    ++#if SQLITE_BYTEORDER==1234 && MSVC_VERSION>=1300
    ++  u64 x;
    ++  memcpy(&x, p, 8);
    ++  return (i64)_byteswap_uint64(x);
    ++#elif SQLITE_BYTEORDER==1234 && GCC_VERSION>=4003000
    ++  u64 x;
    ++  memcpy(&x, p, 8);
    ++  return (i64)__builtin_bswap64(x);
    ++#elif SQLITE_BYTEORDER==4321
    ++  i64 x;
    ++  memcpy(&x, p, 8);
    ++  return x;
    ++#else
    ++  return (i64)(
    ++    (((u64)p[0]) << 56) + 
    ++    (((u64)p[1]) << 48) + 
    ++    (((u64)p[2]) << 40) + 
    ++    (((u64)p[3]) << 32) + 
    ++    (((u64)p[4]) << 24) + 
    ++    (((u64)p[5]) << 16) + 
    ++    (((u64)p[6]) <<  8) + 
    ++    (((u64)p[7]) <<  0)
    +   );
    ++#endif
    + }
    + 
    + /*
    +@@ -154434,23 +167523,43 @@ static i64 readInt64(u8 *p){
    + ** 64 bit integer. The value returned is the number of bytes written
    + ** to the argument buffer (always 2, 4 and 8 respectively).
    + */
    +-static int writeInt16(u8 *p, int i){
    ++static void writeInt16(u8 *p, int i){
    +   p[0] = (i>> 8)&0xFF;
    +   p[1] = (i>> 0)&0xFF;
    +-  return 2;
    + }
    + static int writeCoord(u8 *p, RtreeCoord *pCoord){
    +   u32 i;
    ++  assert( ((((char*)p) - (char*)0)&3)==0 );  /* p is always 4-byte aligned */
    +   assert( sizeof(RtreeCoord)==4 );
    +   assert( sizeof(u32)==4 );
    ++#if SQLITE_BYTEORDER==1234 && GCC_VERSION>=4003000
    ++  i = __builtin_bswap32(pCoord->u);
    ++  memcpy(p, &i, 4);
    ++#elif SQLITE_BYTEORDER==1234 && MSVC_VERSION>=1300
    ++  i = _byteswap_ulong(pCoord->u);
    ++  memcpy(p, &i, 4);
    ++#elif SQLITE_BYTEORDER==4321
    ++  i = pCoord->u;
    ++  memcpy(p, &i, 4);
    ++#else
    +   i = pCoord->u;
    +   p[0] = (i>>24)&0xFF;
    +   p[1] = (i>>16)&0xFF;
    +   p[2] = (i>> 8)&0xFF;
    +   p[3] = (i>> 0)&0xFF;
    ++#endif
    +   return 4;
    + }
    + static int writeInt64(u8 *p, i64 i){
    ++#if SQLITE_BYTEORDER==1234 && GCC_VERSION>=4003000
    ++  i = (i64)__builtin_bswap64((u64)i);
    ++  memcpy(p, &i, 8);
    ++#elif SQLITE_BYTEORDER==1234 && MSVC_VERSION>=1300
    ++  i = (i64)_byteswap_uint64((u64)i);
    ++  memcpy(p, &i, 8);
    ++#elif SQLITE_BYTEORDER==4321
    ++  memcpy(p, &i, 8);
    ++#else
    +   p[0] = (i>>56)&0xFF;
    +   p[1] = (i>>48)&0xFF;
    +   p[2] = (i>>40)&0xFF;
    +@@ -154459,6 +167568,7 @@ static int writeInt64(u8 *p, i64 i){
    +   p[5] = (i>>16)&0xFF;
    +   p[6] = (i>> 8)&0xFF;
    +   p[7] = (i>> 0)&0xFF;
    ++#endif
    +   return 8;
    + }
    + 
    +@@ -154541,6 +167651,17 @@ static RtreeNode *nodeNew(Rtree *pRtree, RtreeNode *pParent){
    +   return pNode;
    + }
    + 
    ++/*
    ++** Clear the Rtree.pNodeBlob object
    ++*/
    ++static void nodeBlobReset(Rtree *pRtree){
    ++  if( pRtree->pNodeBlob && pRtree->inWrTrans==0 && pRtree->nCursor==0 ){
    ++    sqlite3_blob *pBlob = pRtree->pNodeBlob;
    ++    pRtree->pNodeBlob = 0;
    ++    sqlite3_blob_close(pBlob);
    ++  }
    ++}
    ++
    + /*
    + ** Obtain a reference to an r-tree node.
    + */
    +@@ -154550,9 +167671,8 @@ static int nodeAcquire(
    +   RtreeNode *pParent,        /* Either the parent node or NULL */
    +   RtreeNode **ppNode         /* OUT: Acquired node */
    + ){
    +-  int rc;
    +-  int rc2 = SQLITE_OK;
    +-  RtreeNode *pNode;
    ++  int rc = SQLITE_OK;
    ++  RtreeNode *pNode = 0;
    + 
    +   /* Check if the requested node is already in the hash table. If so,
    +   ** increase its reference count and return it.
    +@@ -154568,28 +167688,45 @@ static int nodeAcquire(
    +     return SQLITE_OK;
    +   }
    + 
    +-  sqlite3_bind_int64(pRtree->pReadNode, 1, iNode);
    +-  rc = sqlite3_step(pRtree->pReadNode);
    +-  if( rc==SQLITE_ROW ){
    +-    const u8 *zBlob = sqlite3_column_blob(pRtree->pReadNode, 0);
    +-    if( pRtree->iNodeSize==sqlite3_column_bytes(pRtree->pReadNode, 0) ){
    +-      pNode = (RtreeNode *)sqlite3_malloc(sizeof(RtreeNode)+pRtree->iNodeSize);
    +-      if( !pNode ){
    +-        rc2 = SQLITE_NOMEM;
    +-      }else{
    +-        pNode->pParent = pParent;
    +-        pNode->zData = (u8 *)&pNode[1];
    +-        pNode->nRef = 1;
    +-        pNode->iNode = iNode;
    +-        pNode->isDirty = 0;
    +-        pNode->pNext = 0;
    +-        memcpy(pNode->zData, zBlob, pRtree->iNodeSize);
    +-        nodeReference(pParent);
    +-      }
    ++  if( pRtree->pNodeBlob ){
    ++    sqlite3_blob *pBlob = pRtree->pNodeBlob;
    ++    pRtree->pNodeBlob = 0;
    ++    rc = sqlite3_blob_reopen(pBlob, iNode);
    ++    pRtree->pNodeBlob = pBlob;
    ++    if( rc ){
    ++      nodeBlobReset(pRtree);
    ++      if( rc==SQLITE_NOMEM ) return SQLITE_NOMEM;
    ++    }
    ++  }
    ++  if( pRtree->pNodeBlob==0 ){
    ++    char *zTab = sqlite3_mprintf("%s_node", pRtree->zName);
    ++    if( zTab==0 ) return SQLITE_NOMEM;
    ++    rc = sqlite3_blob_open(pRtree->db, pRtree->zDb, zTab, "data", iNode, 0,
    ++                           &pRtree->pNodeBlob);
    ++    sqlite3_free(zTab);
    ++  }
    ++  if( rc ){
    ++    nodeBlobReset(pRtree);
    ++    *ppNode = 0;
    ++    /* If unable to open an sqlite3_blob on the desired row, that can only
    ++    ** be because the shadow tables hold erroneous data. */
    ++    if( rc==SQLITE_ERROR ) rc = SQLITE_CORRUPT_VTAB;
    ++  }else if( pRtree->iNodeSize==sqlite3_blob_bytes(pRtree->pNodeBlob) ){
    ++    pNode = (RtreeNode *)sqlite3_malloc(sizeof(RtreeNode)+pRtree->iNodeSize);
    ++    if( !pNode ){
    ++      rc = SQLITE_NOMEM;
    ++    }else{
    ++      pNode->pParent = pParent;
    ++      pNode->zData = (u8 *)&pNode[1];
    ++      pNode->nRef = 1;
    ++      pNode->iNode = iNode;
    ++      pNode->isDirty = 0;
    ++      pNode->pNext = 0;
    ++      rc = sqlite3_blob_read(pRtree->pNodeBlob, pNode->zData,
    ++                             pRtree->iNodeSize, 0);
    ++      nodeReference(pParent);
    +     }
    +   }
    +-  rc = sqlite3_reset(pRtree->pReadNode);
    +-  if( rc==SQLITE_OK ) rc = rc2;
    + 
    +   /* If the root node was just loaded, set pRtree->iDepth to the height
    +   ** of the r-tree structure. A height of zero means all data is stored on
    +@@ -154641,7 +167778,7 @@ static void nodeOverwriteCell(
    +   int ii;
    +   u8 *p = &pNode->zData[4 + pRtree->nBytesPerCell*iCell];
    +   p += writeInt64(p, pCell->iRowid);
    +-  for(ii=0; ii<(pRtree->nDim*2); ii++){
    ++  for(ii=0; ii<pRtree->nDim2; ii++){
    +     p += writeCoord(p, &pCell->aCoord[ii]);
    +   }
    +   pNode->isDirty = 1;
    +@@ -154775,13 +167912,16 @@ static void nodeGetCell(
    + ){
    +   u8 *pData;
    +   RtreeCoord *pCoord;
    +-  int ii;
    ++  int ii = 0;
    +   pCell->iRowid = nodeGetRowid(pRtree, pNode, iCell);
    +   pData = pNode->zData + (12 + pRtree->nBytesPerCell*iCell);
    +   pCoord = pCell->aCoord;
    +-  for(ii=0; ii<pRtree->nDim*2; ii++){
    +-    readCoord(&pData[ii*4], &pCoord[ii]);
    +-  }
    ++  do{
    ++    readCoord(pData, &pCoord[ii]);
    ++    readCoord(pData+4, &pCoord[ii+1]);
    ++    pData += 8;
    ++    ii += 2;
    ++  }while( ii<pRtree->nDim2 );
    + }
    + 
    + 
    +@@ -154832,7 +167972,9 @@ static void rtreeReference(Rtree *pRtree){
    + static void rtreeRelease(Rtree *pRtree){
    +   pRtree->nBusy--;
    +   if( pRtree->nBusy==0 ){
    +-    sqlite3_finalize(pRtree->pReadNode);
    ++    pRtree->inWrTrans = 0;
    ++    pRtree->nCursor = 0;
    ++    nodeBlobReset(pRtree);
    +     sqlite3_finalize(pRtree->pWriteNode);
    +     sqlite3_finalize(pRtree->pDeleteNode);
    +     sqlite3_finalize(pRtree->pReadRowid);
    +@@ -154870,6 +168012,7 @@ static int rtreeDestroy(sqlite3_vtab *pVtab){
    +   if( !zCreate ){
    +     rc = SQLITE_NOMEM;
    +   }else{
    ++    nodeBlobReset(pRtree);
    +     rc = sqlite3_exec(pRtree->db, zCreate, 0, 0, 0);
    +     sqlite3_free(zCreate);
    +   }
    +@@ -154885,6 +168028,7 @@ static int rtreeDestroy(sqlite3_vtab *pVtab){
    + */
    + static int rtreeOpen(sqlite3_vtab *pVTab, sqlite3_vtab_cursor **ppCursor){
    +   int rc = SQLITE_NOMEM;
    ++  Rtree *pRtree = (Rtree *)pVTab;
    +   RtreeCursor *pCsr;
    + 
    +   pCsr = (RtreeCursor *)sqlite3_malloc(sizeof(RtreeCursor));
    +@@ -154892,6 +168036,7 @@ static int rtreeOpen(sqlite3_vtab *pVTab, sqlite3_vtab_cursor **ppCursor){
    +     memset(pCsr, 0, sizeof(RtreeCursor));
    +     pCsr->base.pVtab = pVTab;
    +     rc = SQLITE_OK;
    ++    pRtree->nCursor++;
    +   }
    +   *ppCursor = (sqlite3_vtab_cursor *)pCsr;
    + 
    +@@ -154924,10 +168069,13 @@ static int rtreeClose(sqlite3_vtab_cursor *cur){
    +   Rtree *pRtree = (Rtree *)(cur->pVtab);
    +   int ii;
    +   RtreeCursor *pCsr = (RtreeCursor *)cur;
    ++  assert( pRtree->nCursor>0 );
    +   freeCursorConstraints(pCsr);
    +   sqlite3_free(pCsr->aPoint);
    +   for(ii=0; ii<RTREE_CACHE_SZ; ii++) nodeRelease(pRtree, pCsr->aNode[ii]);
    +   sqlite3_free(pCsr);
    ++  pRtree->nCursor--;
    ++  nodeBlobReset(pRtree);
    +   return SQLITE_OK;
    + }
    + 
    +@@ -154950,15 +168098,22 @@ static int rtreeEof(sqlite3_vtab_cursor *cur){
    + ** false.  a[] is the four bytes of the on-disk record to be decoded.
    + ** Store the results in "r".
    + **
    +-** 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.
    ++** There are five versions of this macro.  The last one is generic.  The
    ++** other four are various architectures-specific optimizations.
    + */
    +-#if defined(SQLITE_BYTEORDER) && SQLITE_BYTEORDER==1234
    ++#if SQLITE_BYTEORDER==1234 && MSVC_VERSION>=1300
    ++#define RTREE_DECODE_COORD(eInt, a, r) {                        \
    ++    RtreeCoord c;    /* Coordinate decoded */                   \
    ++    c.u = _byteswap_ulong(*(u32*)a);                            \
    ++    r = eInt ? (sqlite3_rtree_dbl)c.i : (sqlite3_rtree_dbl)c.f; \
    ++}
    ++#elif SQLITE_BYTEORDER==1234 && GCC_VERSION>=4003000
    ++#define RTREE_DECODE_COORD(eInt, a, r) {                        \
    ++    RtreeCoord c;    /* Coordinate decoded */                   \
    ++    c.u = __builtin_bswap32(*(u32*)a);                          \
    ++    r = eInt ? (sqlite3_rtree_dbl)c.i : (sqlite3_rtree_dbl)c.f; \
    ++}
    ++#elif SQLITE_BYTEORDER==1234
    + #define RTREE_DECODE_COORD(eInt, a, r) {                        \
    +     RtreeCoord c;    /* Coordinate decoded */                   \
    +     memcpy(&c.u,a,4);                                           \
    +@@ -154966,7 +168121,7 @@ static int rtreeEof(sqlite3_vtab_cursor *cur){
    +           ((c.u&0xff)<<24)|((c.u&0xff00)<<8);                   \
    +     r = eInt ? (sqlite3_rtree_dbl)c.i : (sqlite3_rtree_dbl)c.f; \
    + }
    +-#elif defined(SQLITE_BYTEORDER) && SQLITE_BYTEORDER==4321
    ++#elif SQLITE_BYTEORDER==4321
    + #define RTREE_DECODE_COORD(eInt, a, r) {                        \
    +     RtreeCoord c;    /* Coordinate decoded */                   \
    +     memcpy(&c.u,a,4);                                           \
    +@@ -154993,10 +168148,10 @@ static int rtreeCallbackConstraint(
    +   sqlite3_rtree_dbl *prScore,    /* OUT: score for the cell */
    +   int *peWithin                  /* OUT: visibility of the cell */
    + ){
    +-  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 */
    ++  RtreeCoord c;                                       /* Translator union */
    +   sqlite3_rtree_dbl aCoord[RTREE_MAX_DIMENSIONS*2];   /* Decoded coordinates */
    + 
    +   assert( pConstraint->op==RTREE_MATCH || pConstraint->op==RTREE_QUERY );
    +@@ -155006,13 +168161,41 @@ static int rtreeCallbackConstraint(
    +     pInfo->iRowid = readInt64(pCellData);
    +   }
    +   pCellData += 8;
    +-  for(i=0; i<nCoord; i++, pCellData += 4){
    +-    RTREE_DECODE_COORD(eInt, pCellData, aCoord[i]);
    ++#ifndef SQLITE_RTREE_INT_ONLY
    ++  if( eInt==0 ){
    ++    switch( nCoord ){
    ++      case 10:  readCoord(pCellData+36, &c); aCoord[9] = c.f;
    ++                readCoord(pCellData+32, &c); aCoord[8] = c.f;
    ++      case 8:   readCoord(pCellData+28, &c); aCoord[7] = c.f;
    ++                readCoord(pCellData+24, &c); aCoord[6] = c.f;
    ++      case 6:   readCoord(pCellData+20, &c); aCoord[5] = c.f;
    ++                readCoord(pCellData+16, &c); aCoord[4] = c.f;
    ++      case 4:   readCoord(pCellData+12, &c); aCoord[3] = c.f;
    ++                readCoord(pCellData+8,  &c); aCoord[2] = c.f;
    ++      default:  readCoord(pCellData+4,  &c); aCoord[1] = c.f;
    ++                readCoord(pCellData,    &c); aCoord[0] = c.f;
    ++    }
    ++  }else
    ++#endif
    ++  {
    ++    switch( nCoord ){
    ++      case 10:  readCoord(pCellData+36, &c); aCoord[9] = c.i;
    ++                readCoord(pCellData+32, &c); aCoord[8] = c.i;
    ++      case 8:   readCoord(pCellData+28, &c); aCoord[7] = c.i;
    ++                readCoord(pCellData+24, &c); aCoord[6] = c.i;
    ++      case 6:   readCoord(pCellData+20, &c); aCoord[5] = c.i;
    ++                readCoord(pCellData+16, &c); aCoord[4] = c.i;
    ++      case 4:   readCoord(pCellData+12, &c); aCoord[3] = c.i;
    ++                readCoord(pCellData+8,  &c); aCoord[2] = c.i;
    ++      default:  readCoord(pCellData+4,  &c); aCoord[1] = c.i;
    ++                readCoord(pCellData,    &c); aCoord[0] = c.i;
    ++    }
    +   }
    +   if( pConstraint->op==RTREE_MATCH ){
    ++    int eWithin = 0;
    +     rc = pConstraint->u.xGeom((sqlite3_rtree_geometry*)pInfo,
    +-                              nCoord, aCoord, &i);
    +-    if( i==0 ) *peWithin = NOT_WITHIN;
    ++                              nCoord, aCoord, &eWithin);
    ++    if( eWithin==0 ) *peWithin = NOT_WITHIN;
    +     *prScore = RTREE_ZERO;
    +   }else{
    +     pInfo->aCoord = aCoord;
    +@@ -155048,6 +168231,7 @@ static void rtreeNonleafConstraint(
    + 
    +   assert(p->op==RTREE_LE || p->op==RTREE_LT || p->op==RTREE_GE 
    +       || p->op==RTREE_GT || p->op==RTREE_EQ );
    ++  assert( ((((char*)pCellData) - (char*)0)&3)==0 );  /* 4-byte aligned */
    +   switch( p->op ){
    +     case RTREE_LE:
    +     case RTREE_LT:
    +@@ -155088,6 +168272,7 @@ static void rtreeLeafConstraint(
    +   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;
    ++  assert( ((((char*)pCellData) - (char*)0)&3)==0 );  /* 4-byte aligned */
    +   RTREE_DECODE_COORD(eInt, pCellData, xN);
    +   switch( p->op ){
    +     case RTREE_LE: if( xN <= p->u.rValue ) return;  break;
    +@@ -155156,7 +168341,7 @@ static int rtreeSearchPointCompare(
    + }
    + 
    + /*
    +-** Interchange to search points in a cursor.
    ++** Interchange two search points in a cursor.
    + */
    + static void rtreeSearchPointSwap(RtreeCursor *p, int i, int j){
    +   RtreeSearchPoint t = p->aPoint[i];
    +@@ -155404,7 +168589,7 @@ static int rtreeStepToLeaf(RtreeCursor *pCur){
    +       if( rScore<RTREE_ZERO ) rScore = RTREE_ZERO;
    +       p = rtreeSearchPointNew(pCur, rScore, x.iLevel);
    +       if( p==0 ) return SQLITE_NOMEM;
    +-      p->eWithin = eWithin;
    ++      p->eWithin = (u8)eWithin;
    +       p->id = x.id;
    +       p->iCell = x.iCell;
    +       RTREE_QUEUE_TRACE(pCur, "PUSH-S:");
    +@@ -155463,7 +168648,6 @@ static int rtreeColumn(sqlite3_vtab_cursor *cur, sqlite3_context *ctx, int i){
    +   if( i==0 ){
    +     sqlite3_result_int64(ctx, nodeGetRowid(pRtree, pNode, p->iCell));
    +   }else{
    +-    if( rc ) return rc;
    +     nodeGetCoord(pRtree, pNode, p->iCell, i-1, &c);
    + #ifndef SQLITE_RTREE_INT_ONLY
    +     if( pRtree->eCoordType==RTREE_COORD_REAL32 ){
    +@@ -155512,33 +168696,17 @@ static int findLeafNode(
    + ** operator.
    + */
    + static int deserializeGeometry(sqlite3_value *pValue, RtreeConstraint *pCons){
    +-  RtreeMatchArg *pBlob;              /* BLOB returned by geometry function */
    ++  RtreeMatchArg *pBlob, *pSrc;       /* 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;
    +-
    +-  /* Check that the blob is roughly the right size. */
    +-  nBlob = sqlite3_value_bytes(pValue);
    +-  if( nBlob<(int)sizeof(RtreeMatchArg) ){
    +-    return SQLITE_ERROR;
    +-  }
    +-
    +-  pInfo = (sqlite3_rtree_query_info*)sqlite3_malloc( sizeof(*pInfo)+nBlob );
    ++  pSrc = sqlite3_value_pointer(pValue, "RtreeMatchArg");
    ++  if( pSrc==0 ) return SQLITE_ERROR;
    ++  pInfo = (sqlite3_rtree_query_info*)
    ++                sqlite3_malloc64( sizeof(*pInfo)+pSrc->iSize );
    +   if( !pInfo ) return SQLITE_NOMEM;
    +   memset(pInfo, 0, sizeof(*pInfo));
    +   pBlob = (RtreeMatchArg*)&pInfo[1];
    +-
    +-  memcpy(pBlob, sqlite3_value_blob(pValue), nBlob);
    +-  nExpected = (int)(sizeof(RtreeMatchArg) +
    +-                    pBlob->nParam*sizeof(sqlite3_value*) +
    +-                    (pBlob->nParam-1)*sizeof(RtreeDValue));
    +-  if( pBlob->magic!=RTREE_GEOMETRY_MAGIC || nBlob!=nExpected ){
    +-    sqlite3_free(pInfo);
    +-    return SQLITE_ERROR;
    +-  }
    ++  memcpy(pBlob, pSrc, pSrc->iSize);
    +   pInfo->pContext = pBlob->cb.pContext;
    +   pInfo->nParam = pBlob->nParam;
    +   pInfo->aParam = pBlob->aParam;
    +@@ -155581,7 +168749,7 @@ static int rtreeFilter(
    +   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 */
    ++    RtreeSearchPoint *p;     /* Search point for the leaf */
    +     i64 iRowid = sqlite3_value_int64(argv[0]);
    +     i64 iNode = 0;
    +     rc = findLeafNode(pRtree, iRowid, &pLeaf, &iNode);
    +@@ -155592,7 +168760,7 @@ static int rtreeFilter(
    +       p->id = iNode;
    +       p->eWithin = PARTLY_WITHIN;
    +       rc = nodeRowidIndex(pRtree, pLeaf, iRowid, &iCell);
    +-      p->iCell = iCell;
    ++      p->iCell = (u8)iCell;
    +       RTREE_QUEUE_TRACE(pCsr, "PUSH-F1:");
    +     }else{
    +       pCsr->atEOF = 1;
    +@@ -155625,7 +168793,7 @@ static int rtreeFilter(
    +             if( rc!=SQLITE_OK ){
    +               break;
    +             }
    +-            p->pInfo->nCoord = pRtree->nDim*2;
    ++            p->pInfo->nCoord = pRtree->nDim2;
    +             p->pInfo->anQueue = pCsr->anQueue;
    +             p->pInfo->mxLevel = pRtree->iDepth + 1;
    +           }else{
    +@@ -155640,7 +168808,7 @@ static int rtreeFilter(
    +     }
    +     if( rc==SQLITE_OK ){
    +       RtreeSearchPoint *pNew;
    +-      pNew = rtreeSearchPointNew(pCsr, RTREE_ZERO, pRtree->iDepth+1);
    ++      pNew = rtreeSearchPointNew(pCsr, RTREE_ZERO, (u8)(pRtree->iDepth+1));
    +       if( pNew==0 ) return SQLITE_NOMEM;
    +       pNew->id = 1;
    +       pNew->iCell = 0;
    +@@ -155658,19 +168826,6 @@ static int rtreeFilter(
    +   return rc;
    + }
    + 
    +-/*
    +-** Set the pIdxInfo->estimatedRows variable to nRow. Unless this
    +-** extension is currently being used by a version of SQLite too old to
    +-** support estimatedRows. In that case this function is a no-op.
    +-*/
    +-static void setEstimatedRows(sqlite3_index_info *pIdxInfo, i64 nRow){
    +-#if SQLITE_VERSION_NUMBER>=3008002
    +-  if( sqlite3_libversion_number()>=3008002 ){
    +-    pIdxInfo->estimatedRows = nRow;
    +-  }
    +-#endif
    +-}
    +-
    + /*
    + ** Rtree virtual table module xBestIndex method. There are three
    + ** table scan strategies to choose from (in order from most to 
    +@@ -155750,7 +168905,7 @@ static int rtreeBestIndex(sqlite3_vtab *tab, sqlite3_index_info *pIdxInfo){
    +       ** a single row.
    +       */ 
    +       pIdxInfo->estimatedCost = 30.0;
    +-      setEstimatedRows(pIdxInfo, 1);
    ++      pIdxInfo->estimatedRows = 1;
    +       return SQLITE_OK;
    +     }
    + 
    +@@ -155768,7 +168923,7 @@ static int rtreeBestIndex(sqlite3_vtab *tab, sqlite3_index_info *pIdxInfo){
    +           break;
    +       }
    +       zIdxStr[iIdx++] = op;
    +-      zIdxStr[iIdx++] = p->iColumn - 1 + '0';
    ++      zIdxStr[iIdx++] = (char)(p->iColumn - 1 + '0');
    +       pIdxInfo->aConstraintUsage[ii].argvIndex = (iIdx/2);
    +       pIdxInfo->aConstraintUsage[ii].omit = 1;
    +     }
    +@@ -155780,9 +168935,9 @@ static int rtreeBestIndex(sqlite3_vtab *tab, sqlite3_index_info *pIdxInfo){
    +     return SQLITE_NOMEM;
    +   }
    + 
    +-  nRow = pRtree->nRowEst / (iIdx + 1);
    ++  nRow = pRtree->nRowEst >> (iIdx/2);
    +   pIdxInfo->estimatedCost = (double)6.0 * (double)nRow;
    +-  setEstimatedRows(pIdxInfo, nRow);
    ++  pIdxInfo->estimatedRows = nRow;
    + 
    +   return rc;
    + }
    +@@ -155792,9 +168947,26 @@ static int rtreeBestIndex(sqlite3_vtab *tab, sqlite3_index_info *pIdxInfo){
    + */
    + static RtreeDValue cellArea(Rtree *pRtree, RtreeCell *p){
    +   RtreeDValue area = (RtreeDValue)1;
    +-  int ii;
    +-  for(ii=0; ii<(pRtree->nDim*2); ii+=2){
    +-    area = (area * (DCOORD(p->aCoord[ii+1]) - DCOORD(p->aCoord[ii])));
    ++  assert( pRtree->nDim>=1 && pRtree->nDim<=5 );
    ++#ifndef SQLITE_RTREE_INT_ONLY
    ++  if( pRtree->eCoordType==RTREE_COORD_REAL32 ){
    ++    switch( pRtree->nDim ){
    ++      case 5:  area  = p->aCoord[9].f - p->aCoord[8].f;
    ++      case 4:  area *= p->aCoord[7].f - p->aCoord[6].f;
    ++      case 3:  area *= p->aCoord[5].f - p->aCoord[4].f;
    ++      case 2:  area *= p->aCoord[3].f - p->aCoord[2].f;
    ++      default: area *= p->aCoord[1].f - p->aCoord[0].f;
    ++    }
    ++  }else
    ++#endif
    ++  {
    ++    switch( pRtree->nDim ){
    ++      case 5:  area  = p->aCoord[9].i - p->aCoord[8].i;
    ++      case 4:  area *= p->aCoord[7].i - p->aCoord[6].i;
    ++      case 3:  area *= p->aCoord[5].i - p->aCoord[4].i;
    ++      case 2:  area *= p->aCoord[3].i - p->aCoord[2].i;
    ++      default: area *= p->aCoord[1].i - p->aCoord[0].i;
    ++    }
    +   }
    +   return area;
    + }
    +@@ -155804,11 +168976,12 @@ static RtreeDValue cellArea(Rtree *pRtree, RtreeCell *p){
    + ** of the objects size in each dimension.
    + */
    + static RtreeDValue cellMargin(Rtree *pRtree, RtreeCell *p){
    +-  RtreeDValue margin = (RtreeDValue)0;
    +-  int ii;
    +-  for(ii=0; ii<(pRtree->nDim*2); ii+=2){
    ++  RtreeDValue margin = 0;
    ++  int ii = pRtree->nDim2 - 2;
    ++  do{
    +     margin += (DCOORD(p->aCoord[ii+1]) - DCOORD(p->aCoord[ii]));
    +-  }
    ++    ii -= 2;
    ++  }while( ii>=0 );
    +   return margin;
    + }
    + 
    +@@ -155816,17 +168989,19 @@ static RtreeDValue cellMargin(Rtree *pRtree, RtreeCell *p){
    + ** Store the union of cells p1 and p2 in p1.
    + */
    + static void cellUnion(Rtree *pRtree, RtreeCell *p1, RtreeCell *p2){
    +-  int ii;
    ++  int ii = 0;
    +   if( pRtree->eCoordType==RTREE_COORD_REAL32 ){
    +-    for(ii=0; ii<(pRtree->nDim*2); ii+=2){
    ++    do{
    +       p1->aCoord[ii].f = MIN(p1->aCoord[ii].f, p2->aCoord[ii].f);
    +       p1->aCoord[ii+1].f = MAX(p1->aCoord[ii+1].f, p2->aCoord[ii+1].f);
    +-    }
    ++      ii += 2;
    ++    }while( ii<pRtree->nDim2 );
    +   }else{
    +-    for(ii=0; ii<(pRtree->nDim*2); ii+=2){
    ++    do{
    +       p1->aCoord[ii].i = MIN(p1->aCoord[ii].i, p2->aCoord[ii].i);
    +       p1->aCoord[ii+1].i = MAX(p1->aCoord[ii+1].i, p2->aCoord[ii+1].i);
    +-    }
    ++      ii += 2;
    ++    }while( ii<pRtree->nDim2 );
    +   }
    + }
    + 
    +@@ -155837,7 +169012,7 @@ static void cellUnion(Rtree *pRtree, RtreeCell *p1, RtreeCell *p2){
    + static int cellContains(Rtree *pRtree, RtreeCell *p1, RtreeCell *p2){
    +   int ii;
    +   int isInt = (pRtree->eCoordType==RTREE_COORD_INT32);
    +-  for(ii=0; ii<(pRtree->nDim*2); ii+=2){
    ++  for(ii=0; ii<pRtree->nDim2; ii+=2){
    +     RtreeCoord *a1 = &p1->aCoord[ii];
    +     RtreeCoord *a2 = &p2->aCoord[ii];
    +     if( (!isInt && (a2[0].f<a1[0].f || a2[1].f>a1[1].f)) 
    +@@ -155872,7 +169047,7 @@ static RtreeDValue cellOverlap(
    +   for(ii=0; ii<nCell; ii++){
    +     int jj;
    +     RtreeDValue o = (RtreeDValue)1;
    +-    for(jj=0; jj<(pRtree->nDim*2); jj+=2){
    ++    for(jj=0; jj<pRtree->nDim2; 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]));
    +@@ -155901,7 +169076,7 @@ static int ChooseLeaf(
    + ){
    +   int rc;
    +   int ii;
    +-  RtreeNode *pNode;
    ++  RtreeNode *pNode = 0;
    +   rc = nodeAcquire(pRtree, 1, 0, &pNode);
    + 
    +   for(ii=0; rc==SQLITE_OK && ii<(pRtree->iDepth-iHeight); ii++){
    +@@ -156733,7 +169908,7 @@ static int rtreeDeleteRowid(Rtree *pRtree, sqlite3_int64 iDelete){
    +   int rc;                         /* Return code */
    +   RtreeNode *pLeaf = 0;           /* Leaf node containing record iDelete */
    +   int iCell;                      /* Index of iDelete cell in pLeaf */
    +-  RtreeNode *pRoot;               /* Root node of rtree structure */
    ++  RtreeNode *pRoot = 0;           /* Root node of rtree structure */
    + 
    + 
    +   /* Obtain a reference to the root node to initialize Rtree.iDepth */
    +@@ -156776,7 +169951,7 @@ static int rtreeDeleteRowid(Rtree *pRtree, sqlite3_int64 iDelete){
    +   */
    +   if( rc==SQLITE_OK && pRtree->iDepth>0 && NCELL(pRoot)==1 ){
    +     int rc2;
    +-    RtreeNode *pChild;
    ++    RtreeNode *pChild = 0;
    +     i64 iChild = nodeGetRowid(pRtree, pRoot, 0);
    +     rc = nodeAcquire(pRtree, iChild, pRoot, &pChild);
    +     if( rc==SQLITE_OK ){
    +@@ -156839,6 +170014,53 @@ static RtreeValue rtreeValueUp(sqlite3_value *v){
    + }
    + #endif /* !defined(SQLITE_RTREE_INT_ONLY) */
    + 
    ++/*
    ++** A constraint has failed while inserting a row into an rtree table. 
    ++** Assuming no OOM error occurs, this function sets the error message 
    ++** (at pRtree->base.zErrMsg) to an appropriate value and returns
    ++** SQLITE_CONSTRAINT.
    ++**
    ++** Parameter iCol is the index of the leftmost column involved in the
    ++** constraint failure. If it is 0, then the constraint that failed is
    ++** the unique constraint on the id column. Otherwise, it is the rtree
    ++** (c1<=c2) constraint on columns iCol and iCol+1 that has failed.
    ++**
    ++** If an OOM occurs, SQLITE_NOMEM is returned instead of SQLITE_CONSTRAINT.
    ++*/
    ++static int rtreeConstraintError(Rtree *pRtree, int iCol){
    ++  sqlite3_stmt *pStmt = 0;
    ++  char *zSql; 
    ++  int rc;
    ++
    ++  assert( iCol==0 || iCol%2 );
    ++  zSql = sqlite3_mprintf("SELECT * FROM %Q.%Q", pRtree->zDb, pRtree->zName);
    ++  if( zSql ){
    ++    rc = sqlite3_prepare_v2(pRtree->db, zSql, -1, &pStmt, 0);
    ++  }else{
    ++    rc = SQLITE_NOMEM;
    ++  }
    ++  sqlite3_free(zSql);
    ++
    ++  if( rc==SQLITE_OK ){
    ++    if( iCol==0 ){
    ++      const char *zCol = sqlite3_column_name(pStmt, 0);
    ++      pRtree->base.zErrMsg = sqlite3_mprintf(
    ++          "UNIQUE constraint failed: %s.%s", pRtree->zName, zCol
    ++      );
    ++    }else{
    ++      const char *zCol1 = sqlite3_column_name(pStmt, iCol);
    ++      const char *zCol2 = sqlite3_column_name(pStmt, iCol+1);
    ++      pRtree->base.zErrMsg = sqlite3_mprintf(
    ++          "rtree constraint failed: %s.(%s<=%s)", pRtree->zName, zCol1, zCol2
    ++      );
    ++    }
    ++  }
    ++
    ++  sqlite3_finalize(pStmt);
    ++  return (rc==SQLITE_OK ? SQLITE_CONSTRAINT : rc);
    ++}
    ++
    ++
    + 
    + /*
    + ** The xUpdate method for rtree module virtual tables.
    +@@ -156881,7 +170103,7 @@ static int rtreeUpdate(
    +     ** This problem was discovered after years of use, so we silently ignore
    +     ** these kinds of misdeclared tables to avoid breaking any legacy.
    +     */
    +-    assert( nData<=(pRtree->nDim*2 + 3) );
    ++    assert( nData<=(pRtree->nDim2 + 3) );
    + 
    + #ifndef SQLITE_RTREE_INT_ONLY
    +     if( pRtree->eCoordType==RTREE_COORD_REAL32 ){
    +@@ -156889,7 +170111,7 @@ static int rtreeUpdate(
    +         cell.aCoord[ii].f = rtreeValueDown(azData[ii+3]);
    +         cell.aCoord[ii+1].f = rtreeValueUp(azData[ii+4]);
    +         if( cell.aCoord[ii].f>cell.aCoord[ii+1].f ){
    +-          rc = SQLITE_CONSTRAINT;
    ++          rc = rtreeConstraintError(pRtree, ii+1);
    +           goto constraint;
    +         }
    +       }
    +@@ -156900,7 +170122,7 @@ static int rtreeUpdate(
    +         cell.aCoord[ii].i = sqlite3_value_int(azData[ii+3]);
    +         cell.aCoord[ii+1].i = sqlite3_value_int(azData[ii+4]);
    +         if( cell.aCoord[ii].i>cell.aCoord[ii+1].i ){
    +-          rc = SQLITE_CONSTRAINT;
    ++          rc = rtreeConstraintError(pRtree, ii+1);
    +           goto constraint;
    +         }
    +       }
    +@@ -156921,7 +170143,7 @@ static int rtreeUpdate(
    +           if( sqlite3_vtab_on_conflict(pRtree->db)==SQLITE_REPLACE ){
    +             rc = rtreeDeleteRowid(pRtree, cell.iRowid);
    +           }else{
    +-            rc = SQLITE_CONSTRAINT;
    ++            rc = rtreeConstraintError(pRtree, 0);
    +             goto constraint;
    +           }
    +         }
    +@@ -156971,6 +170193,27 @@ constraint:
    +   return rc;
    + }
    + 
    ++/*
    ++** Called when a transaction starts.
    ++*/
    ++static int rtreeBeginTransaction(sqlite3_vtab *pVtab){
    ++  Rtree *pRtree = (Rtree *)pVtab;
    ++  assert( pRtree->inWrTrans==0 );
    ++  pRtree->inWrTrans++;
    ++  return SQLITE_OK;
    ++}
    ++
    ++/*
    ++** Called when a transaction completes (either by COMMIT or ROLLBACK).
    ++** The sqlite3_blob object should be released at this point.
    ++*/
    ++static int rtreeEndTransaction(sqlite3_vtab *pVtab){
    ++  Rtree *pRtree = (Rtree *)pVtab;
    ++  pRtree->inWrTrans = 0;
    ++  nodeBlobReset(pRtree);
    ++  return SQLITE_OK;
    ++}
    ++
    + /*
    + ** The xRename method for rtree module virtual tables.
    + */
    +@@ -156986,12 +170229,37 @@ static int rtreeRename(sqlite3_vtab *pVtab, const char *zNewName){
    +     , pRtree->zDb, pRtree->zName, zNewName
    +   );
    +   if( zSql ){
    ++    nodeBlobReset(pRtree);
    +     rc = sqlite3_exec(pRtree->db, zSql, 0, 0, 0);
    +     sqlite3_free(zSql);
    +   }
    +   return rc;
    + }
    + 
    ++/*
    ++** The xSavepoint method.
    ++**
    ++** This module does not need to do anything to support savepoints. However,
    ++** it uses this hook to close any open blob handle. This is done because a 
    ++** DROP TABLE command - which fortunately always opens a savepoint - cannot 
    ++** succeed if there are any open blob handles. i.e. if the blob handle were
    ++** not closed here, the following would fail:
    ++**
    ++**   BEGIN;
    ++**     INSERT INTO rtree...
    ++**     DROP TABLE <tablename>;    -- Would fail with SQLITE_LOCKED
    ++**   COMMIT;
    ++*/
    ++static int rtreeSavepoint(sqlite3_vtab *pVtab, int iSavepoint){
    ++  Rtree *pRtree = (Rtree *)pVtab;
    ++  int iwt = pRtree->inWrTrans;
    ++  UNUSED_PARAMETER(iSavepoint);
    ++  pRtree->inWrTrans = 0;
    ++  nodeBlobReset(pRtree);
    ++  pRtree->inWrTrans = iwt;
    ++  return SQLITE_OK;
    ++}
    ++
    + /*
    + ** This function populates the pRtree->nRowEst variable with an estimate
    + ** of the number of rows in the virtual table. If possible, this is based
    +@@ -157004,6 +170272,13 @@ static int rtreeQueryStat1(sqlite3 *db, Rtree *pRtree){
    +   int rc;
    +   i64 nRow = 0;
    + 
    ++  rc = sqlite3_table_column_metadata(
    ++      db, pRtree->zDb, "sqlite_stat1",0,0,0,0,0,0
    ++  );
    ++  if( rc!=SQLITE_OK ){
    ++    pRtree->nRowEst = RTREE_DEFAULT_ROWEST;
    ++    return rc==SQLITE_ERROR ? SQLITE_OK : rc;
    ++  }
    +   zSql = sqlite3_mprintf(zFmt, pRtree->zDb, pRtree->zName);
    +   if( zSql==0 ){
    +     rc = SQLITE_NOMEM;
    +@@ -157030,7 +170305,7 @@ static int rtreeQueryStat1(sqlite3 *db, Rtree *pRtree){
    + }
    + 
    + static sqlite3_module rtreeModule = {
    +-  0,                          /* iVersion */
    ++  2,                          /* iVersion */
    +   rtreeCreate,                /* xCreate - create a table */
    +   rtreeConnect,               /* xConnect - connect to an existing table */
    +   rtreeBestIndex,             /* xBestIndex - Determine search strategy */
    +@@ -157044,15 +170319,15 @@ static sqlite3_module rtreeModule = {
    +   rtreeColumn,                /* xColumn - read data */
    +   rtreeRowid,                 /* xRowid - read data */
    +   rtreeUpdate,                /* xUpdate - write data */
    +-  0,                          /* xBegin - begin transaction */
    +-  0,                          /* xSync - sync transaction */
    +-  0,                          /* xCommit - commit transaction */
    +-  0,                          /* xRollback - rollback transaction */
    ++  rtreeBeginTransaction,      /* xBegin - begin transaction */
    ++  rtreeEndTransaction,        /* xSync - sync transaction */
    ++  rtreeEndTransaction,        /* xCommit - commit transaction */
    ++  rtreeEndTransaction,        /* xRollback - rollback transaction */
    +   0,                          /* xFindFunction - function overloading */
    +   rtreeRename,                /* xRename - rename the table */
    +-  0,                          /* xSavepoint */
    ++  rtreeSavepoint,             /* xSavepoint */
    +   0,                          /* xRelease */
    +-  0                           /* xRollbackTo */
    ++  0,                          /* xRollbackTo */
    + };
    + 
    + static int rtreeSqlInit(
    +@@ -157064,10 +170339,9 @@ static int rtreeSqlInit(
    + ){
    +   int rc = SQLITE_OK;
    + 
    +-  #define N_STATEMENT 9
    ++  #define N_STATEMENT 8
    +   static const char *azSql[N_STATEMENT] = {
    +-    /* Read and write the xxx_node table */
    +-    "SELECT data FROM '%q'.'%q_node' WHERE nodeno = :1",
    ++    /* Write the xxx_node table */
    +     "INSERT OR REPLACE INTO '%q'.'%q_node' VALUES(:1, :2)",
    +     "DELETE FROM '%q'.'%q_node' WHERE nodeno = :1",
    + 
    +@@ -157105,21 +170379,21 @@ static int rtreeSqlInit(
    +     }
    +   }
    + 
    +-  appStmt[0] = &pRtree->pReadNode;
    +-  appStmt[1] = &pRtree->pWriteNode;
    +-  appStmt[2] = &pRtree->pDeleteNode;
    +-  appStmt[3] = &pRtree->pReadRowid;
    +-  appStmt[4] = &pRtree->pWriteRowid;
    +-  appStmt[5] = &pRtree->pDeleteRowid;
    +-  appStmt[6] = &pRtree->pReadParent;
    +-  appStmt[7] = &pRtree->pWriteParent;
    +-  appStmt[8] = &pRtree->pDeleteParent;
    ++  appStmt[0] = &pRtree->pWriteNode;
    ++  appStmt[1] = &pRtree->pDeleteNode;
    ++  appStmt[2] = &pRtree->pReadRowid;
    ++  appStmt[3] = &pRtree->pWriteRowid;
    ++  appStmt[4] = &pRtree->pDeleteRowid;
    ++  appStmt[5] = &pRtree->pReadParent;
    ++  appStmt[6] = &pRtree->pWriteParent;
    ++  appStmt[7] = &pRtree->pDeleteParent;
    + 
    +   rc = rtreeQueryStat1(db, pRtree);
    +   for(i=0; i<N_STATEMENT && rc==SQLITE_OK; i++){
    +     char *zSql = sqlite3_mprintf(azSql[i], zDb, zPrefix);
    +     if( zSql ){
    +-      rc = sqlite3_prepare_v2(db, zSql, -1, appStmt[i], 0); 
    ++      rc = sqlite3_prepare_v3(db, zSql, -1, SQLITE_PREPARE_PERSISTENT,
    ++                              appStmt[i], 0); 
    +     }else{
    +       rc = SQLITE_NOMEM;
    +     }
    +@@ -157194,6 +170468,10 @@ static int getNodeSize(
    +     rc = getIntFromStmt(db, zSql, &pRtree->iNodeSize);
    +     if( rc!=SQLITE_OK ){
    +       *pzErr = sqlite3_mprintf("%s", sqlite3_errmsg(db));
    ++    }else if( pRtree->iNodeSize<(512-64) ){
    ++      rc = SQLITE_CORRUPT_VTAB;
    ++      *pzErr = sqlite3_mprintf("undersize RTree blobs in \"%q_node\"",
    ++                               pRtree->zName);
    +     }
    +   }
    + 
    +@@ -157251,9 +170529,10 @@ static int rtreeInit(
    +   pRtree->base.pModule = &rtreeModule;
    +   pRtree->zDb = (char *)&pRtree[1];
    +   pRtree->zName = &pRtree->zDb[nDb+1];
    +-  pRtree->nDim = (argc-4)/2;
    +-  pRtree->nBytesPerCell = 8 + pRtree->nDim*4*2;
    +-  pRtree->eCoordType = eCoordType;
    ++  pRtree->nDim = (u8)((argc-4)/2);
    ++  pRtree->nDim2 = pRtree->nDim*2;
    ++  pRtree->nBytesPerCell = 8 + pRtree->nDim2*4;
    ++  pRtree->eCoordType = (u8)eCoordType;
    +   memcpy(pRtree->zDb, argv[1], nDb);
    +   memcpy(pRtree->zName, argv[2], nName);
    + 
    +@@ -157326,7 +170605,8 @@ static void rtreenode(sqlite3_context *ctx, int nArg, sqlite3_value **apArg){
    +   UNUSED_PARAMETER(nArg);
    +   memset(&node, 0, sizeof(RtreeNode));
    +   memset(&tree, 0, sizeof(Rtree));
    +-  tree.nDim = sqlite3_value_int(apArg[0]);
    ++  tree.nDim = (u8)sqlite3_value_int(apArg[0]);
    ++  tree.nDim2 = tree.nDim*2;
    +   tree.nBytesPerCell = 8 + 8 * tree.nDim;
    +   node.zData = (u8 *)sqlite3_value_blob(apArg[1]);
    + 
    +@@ -157339,7 +170619,7 @@ static void rtreenode(sqlite3_context *ctx, int nArg, sqlite3_value **apArg){
    +     nodeGetCell(&tree, &node, ii, &cell);
    +     sqlite3_snprintf(512-nCell,&zCell[nCell],"%lld", cell.iRowid);
    +     nCell = (int)strlen(zCell);
    +-    for(jj=0; jj<tree.nDim*2; jj++){
    ++    for(jj=0; jj<tree.nDim2; jj++){
    + #ifndef SQLITE_RTREE_INT_ONLY
    +       sqlite3_snprintf(512-nCell,&zCell[nCell], " %g",
    +                        (double)cell.aCoord[jj].f);
    +@@ -157383,6 +170663,463 @@ static void rtreedepth(sqlite3_context *ctx, int nArg, sqlite3_value **apArg){
    +   }
    + }
    + 
    ++/*
    ++** Context object passed between the various routines that make up the
    ++** implementation of integrity-check function rtreecheck().
    ++*/
    ++typedef struct RtreeCheck RtreeCheck;
    ++struct RtreeCheck {
    ++  sqlite3 *db;                    /* Database handle */
    ++  const char *zDb;                /* Database containing rtree table */
    ++  const char *zTab;               /* Name of rtree table */
    ++  int bInt;                       /* True for rtree_i32 table */
    ++  int nDim;                       /* Number of dimensions for this rtree tbl */
    ++  sqlite3_stmt *pGetNode;         /* Statement used to retrieve nodes */
    ++  sqlite3_stmt *aCheckMapping[2]; /* Statements to query %_parent/%_rowid */
    ++  int nLeaf;                      /* Number of leaf cells in table */
    ++  int nNonLeaf;                   /* Number of non-leaf cells in table */
    ++  int rc;                         /* Return code */
    ++  char *zReport;                  /* Message to report */
    ++  int nErr;                       /* Number of lines in zReport */
    ++};
    ++
    ++#define RTREE_CHECK_MAX_ERROR 100
    ++
    ++/*
    ++** Reset SQL statement pStmt. If the sqlite3_reset() call returns an error,
    ++** and RtreeCheck.rc==SQLITE_OK, set RtreeCheck.rc to the error code.
    ++*/
    ++static void rtreeCheckReset(RtreeCheck *pCheck, sqlite3_stmt *pStmt){
    ++  int rc = sqlite3_reset(pStmt);
    ++  if( pCheck->rc==SQLITE_OK ) pCheck->rc = rc;
    ++}
    ++
    ++/*
    ++** The second and subsequent arguments to this function are a format string
    ++** and printf style arguments. This function formats the string and attempts
    ++** to compile it as an SQL statement.
    ++**
    ++** If successful, a pointer to the new SQL statement is returned. Otherwise,
    ++** NULL is returned and an error code left in RtreeCheck.rc.
    ++*/
    ++static sqlite3_stmt *rtreeCheckPrepare(
    ++  RtreeCheck *pCheck,             /* RtreeCheck object */
    ++  const char *zFmt, ...           /* Format string and trailing args */
    ++){
    ++  va_list ap;
    ++  char *z;
    ++  sqlite3_stmt *pRet = 0;
    ++
    ++  va_start(ap, zFmt);
    ++  z = sqlite3_vmprintf(zFmt, ap);
    ++
    ++  if( pCheck->rc==SQLITE_OK ){
    ++    if( z==0 ){
    ++      pCheck->rc = SQLITE_NOMEM;
    ++    }else{
    ++      pCheck->rc = sqlite3_prepare_v2(pCheck->db, z, -1, &pRet, 0);
    ++    }
    ++  }
    ++
    ++  sqlite3_free(z);
    ++  va_end(ap);
    ++  return pRet;
    ++}
    ++
    ++/*
    ++** The second and subsequent arguments to this function are a printf()
    ++** style format string and arguments. This function formats the string and
    ++** appends it to the report being accumuated in pCheck.
    ++*/
    ++static void rtreeCheckAppendMsg(RtreeCheck *pCheck, const char *zFmt, ...){
    ++  va_list ap;
    ++  va_start(ap, zFmt);
    ++  if( pCheck->rc==SQLITE_OK && pCheck->nErr<RTREE_CHECK_MAX_ERROR ){
    ++    char *z = sqlite3_vmprintf(zFmt, ap);
    ++    if( z==0 ){
    ++      pCheck->rc = SQLITE_NOMEM;
    ++    }else{
    ++      pCheck->zReport = sqlite3_mprintf("%z%s%z", 
    ++          pCheck->zReport, (pCheck->zReport ? "\n" : ""), z
    ++      );
    ++      if( pCheck->zReport==0 ){
    ++        pCheck->rc = SQLITE_NOMEM;
    ++      }
    ++    }
    ++    pCheck->nErr++;
    ++  }
    ++  va_end(ap);
    ++}
    ++
    ++/*
    ++** This function is a no-op if there is already an error code stored
    ++** in the RtreeCheck object indicated by the first argument. NULL is
    ++** returned in this case.
    ++**
    ++** Otherwise, the contents of rtree table node iNode are loaded from
    ++** the database and copied into a buffer obtained from sqlite3_malloc().
    ++** If no error occurs, a pointer to the buffer is returned and (*pnNode)
    ++** is set to the size of the buffer in bytes.
    ++**
    ++** Or, if an error does occur, NULL is returned and an error code left
    ++** in the RtreeCheck object. The final value of *pnNode is undefined in
    ++** this case.
    ++*/
    ++static u8 *rtreeCheckGetNode(RtreeCheck *pCheck, i64 iNode, int *pnNode){
    ++  u8 *pRet = 0;                   /* Return value */
    ++
    ++  assert( pCheck->rc==SQLITE_OK );
    ++  if( pCheck->pGetNode==0 ){
    ++    pCheck->pGetNode = rtreeCheckPrepare(pCheck,
    ++        "SELECT data FROM %Q.'%q_node' WHERE nodeno=?", 
    ++        pCheck->zDb, pCheck->zTab
    ++    );
    ++  }
    ++
    ++  if( pCheck->rc==SQLITE_OK ){
    ++    sqlite3_bind_int64(pCheck->pGetNode, 1, iNode);
    ++    if( sqlite3_step(pCheck->pGetNode)==SQLITE_ROW ){
    ++      int nNode = sqlite3_column_bytes(pCheck->pGetNode, 0);
    ++      const u8 *pNode = (const u8*)sqlite3_column_blob(pCheck->pGetNode, 0);
    ++      pRet = sqlite3_malloc(nNode);
    ++      if( pRet==0 ){
    ++        pCheck->rc = SQLITE_NOMEM;
    ++      }else{
    ++        memcpy(pRet, pNode, nNode);
    ++        *pnNode = nNode;
    ++      }
    ++    }
    ++    rtreeCheckReset(pCheck, pCheck->pGetNode);
    ++    if( pCheck->rc==SQLITE_OK && pRet==0 ){
    ++      rtreeCheckAppendMsg(pCheck, "Node %lld missing from database", iNode);
    ++    }
    ++  }
    ++
    ++  return pRet;
    ++}
    ++
    ++/*
    ++** This function is used to check that the %_parent (if bLeaf==0) or %_rowid
    ++** (if bLeaf==1) table contains a specified entry. The schemas of the
    ++** two tables are:
    ++**
    ++**   CREATE TABLE %_parent(nodeno INTEGER PRIMARY KEY, parentnode INTEGER)
    ++**   CREATE TABLE %_rowid(rowid INTEGER PRIMARY KEY, nodeno INTEGER)
    ++**
    ++** In both cases, this function checks that there exists an entry with
    ++** IPK value iKey and the second column set to iVal.
    ++**
    ++*/
    ++static void rtreeCheckMapping(
    ++  RtreeCheck *pCheck,             /* RtreeCheck object */
    ++  int bLeaf,                      /* True for a leaf cell, false for interior */
    ++  i64 iKey,                       /* Key for mapping */
    ++  i64 iVal                        /* Expected value for mapping */
    ++){
    ++  int rc;
    ++  sqlite3_stmt *pStmt;
    ++  const char *azSql[2] = {
    ++    "SELECT parentnode FROM %Q.'%q_parent' WHERE nodeno=?",
    ++    "SELECT nodeno FROM %Q.'%q_rowid' WHERE rowid=?"
    ++  };
    ++
    ++  assert( bLeaf==0 || bLeaf==1 );
    ++  if( pCheck->aCheckMapping[bLeaf]==0 ){
    ++    pCheck->aCheckMapping[bLeaf] = rtreeCheckPrepare(pCheck,
    ++        azSql[bLeaf], pCheck->zDb, pCheck->zTab
    ++    );
    ++  }
    ++  if( pCheck->rc!=SQLITE_OK ) return;
    ++
    ++  pStmt = pCheck->aCheckMapping[bLeaf];
    ++  sqlite3_bind_int64(pStmt, 1, iKey);
    ++  rc = sqlite3_step(pStmt);
    ++  if( rc==SQLITE_DONE ){
    ++    rtreeCheckAppendMsg(pCheck, "Mapping (%lld -> %lld) missing from %s table",
    ++        iKey, iVal, (bLeaf ? "%_rowid" : "%_parent")
    ++    );
    ++  }else if( rc==SQLITE_ROW ){
    ++    i64 ii = sqlite3_column_int64(pStmt, 0);
    ++    if( ii!=iVal ){
    ++      rtreeCheckAppendMsg(pCheck, 
    ++          "Found (%lld -> %lld) in %s table, expected (%lld -> %lld)",
    ++          iKey, ii, (bLeaf ? "%_rowid" : "%_parent"), iKey, iVal
    ++      );
    ++    }
    ++  }
    ++  rtreeCheckReset(pCheck, pStmt);
    ++}
    ++
    ++/*
    ++** Argument pCell points to an array of coordinates stored on an rtree page.
    ++** This function checks that the coordinates are internally consistent (no
    ++** x1>x2 conditions) and adds an error message to the RtreeCheck object
    ++** if they are not.
    ++**
    ++** Additionally, if pParent is not NULL, then it is assumed to point to
    ++** the array of coordinates on the parent page that bound the page 
    ++** containing pCell. In this case it is also verified that the two
    ++** sets of coordinates are mutually consistent and an error message added
    ++** to the RtreeCheck object if they are not.
    ++*/
    ++static void rtreeCheckCellCoord(
    ++  RtreeCheck *pCheck, 
    ++  i64 iNode,                      /* Node id to use in error messages */
    ++  int iCell,                      /* Cell number to use in error messages */
    ++  u8 *pCell,                      /* Pointer to cell coordinates */
    ++  u8 *pParent                     /* Pointer to parent coordinates */
    ++){
    ++  RtreeCoord c1, c2;
    ++  RtreeCoord p1, p2;
    ++  int i;
    ++
    ++  for(i=0; i<pCheck->nDim; i++){
    ++    readCoord(&pCell[4*2*i], &c1);
    ++    readCoord(&pCell[4*(2*i + 1)], &c2);
    ++
    ++    /* printf("%e, %e\n", c1.u.f, c2.u.f); */
    ++    if( pCheck->bInt ? c1.i>c2.i : c1.f>c2.f ){
    ++      rtreeCheckAppendMsg(pCheck, 
    ++          "Dimension %d of cell %d on node %lld is corrupt", i, iCell, iNode
    ++      );
    ++    }
    ++
    ++    if( pParent ){
    ++      readCoord(&pParent[4*2*i], &p1);
    ++      readCoord(&pParent[4*(2*i + 1)], &p2);
    ++
    ++      if( (pCheck->bInt ? c1.i<p1.i : c1.f<p1.f) 
    ++       || (pCheck->bInt ? c2.i>p2.i : c2.f>p2.f)
    ++      ){
    ++        rtreeCheckAppendMsg(pCheck, 
    ++            "Dimension %d of cell %d on node %lld is corrupt relative to parent"
    ++            , i, iCell, iNode
    ++        );
    ++      }
    ++    }
    ++  }
    ++}
    ++
    ++/*
    ++** Run rtreecheck() checks on node iNode, which is at depth iDepth within
    ++** the r-tree structure. Argument aParent points to the array of coordinates
    ++** that bound node iNode on the parent node.
    ++**
    ++** If any problems are discovered, an error message is appended to the
    ++** report accumulated in the RtreeCheck object.
    ++*/
    ++static void rtreeCheckNode(
    ++  RtreeCheck *pCheck,
    ++  int iDepth,                     /* Depth of iNode (0==leaf) */
    ++  u8 *aParent,                    /* Buffer containing parent coords */
    ++  i64 iNode                       /* Node to check */
    ++){
    ++  u8 *aNode = 0;
    ++  int nNode = 0;
    ++
    ++  assert( iNode==1 || aParent!=0 );
    ++  assert( pCheck->nDim>0 );
    ++
    ++  aNode = rtreeCheckGetNode(pCheck, iNode, &nNode);
    ++  if( aNode ){
    ++    if( nNode<4 ){
    ++      rtreeCheckAppendMsg(pCheck, 
    ++          "Node %lld is too small (%d bytes)", iNode, nNode
    ++      );
    ++    }else{
    ++      int nCell;                  /* Number of cells on page */
    ++      int i;                      /* Used to iterate through cells */
    ++      if( aParent==0 ){
    ++        iDepth = readInt16(aNode);
    ++        if( iDepth>RTREE_MAX_DEPTH ){
    ++          rtreeCheckAppendMsg(pCheck, "Rtree depth out of range (%d)", iDepth);
    ++          sqlite3_free(aNode);
    ++          return;
    ++        }
    ++      }
    ++      nCell = readInt16(&aNode[2]);
    ++      if( (4 + nCell*(8 + pCheck->nDim*2*4))>nNode ){
    ++        rtreeCheckAppendMsg(pCheck, 
    ++            "Node %lld is too small for cell count of %d (%d bytes)", 
    ++            iNode, nCell, nNode
    ++        );
    ++      }else{
    ++        for(i=0; i<nCell; i++){
    ++          u8 *pCell = &aNode[4 + i*(8 + pCheck->nDim*2*4)];
    ++          i64 iVal = readInt64(pCell);
    ++          rtreeCheckCellCoord(pCheck, iNode, i, &pCell[8], aParent);
    ++
    ++          if( iDepth>0 ){
    ++            rtreeCheckMapping(pCheck, 0, iVal, iNode);
    ++            rtreeCheckNode(pCheck, iDepth-1, &pCell[8], iVal);
    ++            pCheck->nNonLeaf++;
    ++          }else{
    ++            rtreeCheckMapping(pCheck, 1, iVal, iNode);
    ++            pCheck->nLeaf++;
    ++          }
    ++        }
    ++      }
    ++    }
    ++    sqlite3_free(aNode);
    ++  }
    ++}
    ++
    ++/*
    ++** The second argument to this function must be either "_rowid" or
    ++** "_parent". This function checks that the number of entries in the
    ++** %_rowid or %_parent table is exactly nExpect. If not, it adds
    ++** an error message to the report in the RtreeCheck object indicated
    ++** by the first argument.
    ++*/
    ++static void rtreeCheckCount(RtreeCheck *pCheck, const char *zTbl, i64 nExpect){
    ++  if( pCheck->rc==SQLITE_OK ){
    ++    sqlite3_stmt *pCount;
    ++    pCount = rtreeCheckPrepare(pCheck, "SELECT count(*) FROM %Q.'%q%s'",
    ++        pCheck->zDb, pCheck->zTab, zTbl
    ++    );
    ++    if( pCount ){
    ++      if( sqlite3_step(pCount)==SQLITE_ROW ){
    ++        i64 nActual = sqlite3_column_int64(pCount, 0);
    ++        if( nActual!=nExpect ){
    ++          rtreeCheckAppendMsg(pCheck, "Wrong number of entries in %%%s table"
    ++              " - expected %lld, actual %lld" , zTbl, nExpect, nActual
    ++          );
    ++        }
    ++      }
    ++      pCheck->rc = sqlite3_finalize(pCount);
    ++    }
    ++  }
    ++}
    ++
    ++/*
    ++** This function does the bulk of the work for the rtree integrity-check.
    ++** It is called by rtreecheck(), which is the SQL function implementation.
    ++*/
    ++static int rtreeCheckTable(
    ++  sqlite3 *db,                    /* Database handle to access db through */
    ++  const char *zDb,                /* Name of db ("main", "temp" etc.) */
    ++  const char *zTab,               /* Name of rtree table to check */
    ++  char **pzReport                 /* OUT: sqlite3_malloc'd report text */
    ++){
    ++  RtreeCheck check;               /* Common context for various routines */
    ++  sqlite3_stmt *pStmt = 0;        /* Used to find column count of rtree table */
    ++  int bEnd = 0;                   /* True if transaction should be closed */
    ++
    ++  /* Initialize the context object */
    ++  memset(&check, 0, sizeof(check));
    ++  check.db = db;
    ++  check.zDb = zDb;
    ++  check.zTab = zTab;
    ++
    ++  /* If there is not already an open transaction, open one now. This is
    ++  ** to ensure that the queries run as part of this integrity-check operate
    ++  ** on a consistent snapshot.  */
    ++  if( sqlite3_get_autocommit(db) ){
    ++    check.rc = sqlite3_exec(db, "BEGIN", 0, 0, 0);
    ++    bEnd = 1;
    ++  }
    ++
    ++  /* Find number of dimensions in the rtree table. */
    ++  pStmt = rtreeCheckPrepare(&check, "SELECT * FROM %Q.%Q", zDb, zTab);
    ++  if( pStmt ){
    ++    int rc;
    ++    check.nDim = (sqlite3_column_count(pStmt) - 1) / 2;
    ++    if( check.nDim<1 ){
    ++      rtreeCheckAppendMsg(&check, "Schema corrupt or not an rtree");
    ++    }else if( SQLITE_ROW==sqlite3_step(pStmt) ){
    ++      check.bInt = (sqlite3_column_type(pStmt, 1)==SQLITE_INTEGER);
    ++    }
    ++    rc = sqlite3_finalize(pStmt);
    ++    if( rc!=SQLITE_CORRUPT ) check.rc = rc;
    ++  }
    ++
    ++  /* Do the actual integrity-check */
    ++  if( check.nDim>=1 ){
    ++    if( check.rc==SQLITE_OK ){
    ++      rtreeCheckNode(&check, 0, 0, 1);
    ++    }
    ++    rtreeCheckCount(&check, "_rowid", check.nLeaf);
    ++    rtreeCheckCount(&check, "_parent", check.nNonLeaf);
    ++  }
    ++
    ++  /* Finalize SQL statements used by the integrity-check */
    ++  sqlite3_finalize(check.pGetNode);
    ++  sqlite3_finalize(check.aCheckMapping[0]);
    ++  sqlite3_finalize(check.aCheckMapping[1]);
    ++
    ++  /* If one was opened, close the transaction */
    ++  if( bEnd ){
    ++    int rc = sqlite3_exec(db, "END", 0, 0, 0);
    ++    if( check.rc==SQLITE_OK ) check.rc = rc;
    ++  }
    ++  *pzReport = check.zReport;
    ++  return check.rc;
    ++}
    ++
    ++/*
    ++** Usage:
    ++**
    ++**   rtreecheck(<rtree-table>);
    ++**   rtreecheck(<database>, <rtree-table>);
    ++**
    ++** Invoking this SQL function runs an integrity-check on the named rtree
    ++** table. The integrity-check verifies the following:
    ++**
    ++**   1. For each cell in the r-tree structure (%_node table), that:
    ++**
    ++**       a) for each dimension, (coord1 <= coord2).
    ++**
    ++**       b) unless the cell is on the root node, that the cell is bounded
    ++**          by the parent cell on the parent node.
    ++**
    ++**       c) for leaf nodes, that there is an entry in the %_rowid 
    ++**          table corresponding to the cell's rowid value that 
    ++**          points to the correct node.
    ++**
    ++**       d) for cells on non-leaf nodes, that there is an entry in the 
    ++**          %_parent table mapping from the cell's child node to the
    ++**          node that it resides on.
    ++**
    ++**   2. That there are the same number of entries in the %_rowid table
    ++**      as there are leaf cells in the r-tree structure, and that there
    ++**      is a leaf cell that corresponds to each entry in the %_rowid table.
    ++**
    ++**   3. That there are the same number of entries in the %_parent table
    ++**      as there are non-leaf cells in the r-tree structure, and that 
    ++**      there is a non-leaf cell that corresponds to each entry in the 
    ++**      %_parent table.
    ++*/
    ++static void rtreecheck(
    ++  sqlite3_context *ctx, 
    ++  int nArg, 
    ++  sqlite3_value **apArg
    ++){
    ++  if( nArg!=1 && nArg!=2 ){
    ++    sqlite3_result_error(ctx, 
    ++        "wrong number of arguments to function rtreecheck()", -1
    ++    );
    ++  }else{
    ++    int rc;
    ++    char *zReport = 0;
    ++    const char *zDb = (const char*)sqlite3_value_text(apArg[0]);
    ++    const char *zTab;
    ++    if( nArg==1 ){
    ++      zTab = zDb;
    ++      zDb = "main";
    ++    }else{
    ++      zTab = (const char*)sqlite3_value_text(apArg[1]);
    ++    }
    ++    rc = rtreeCheckTable(sqlite3_context_db_handle(ctx), zDb, zTab, &zReport);
    ++    if( rc==SQLITE_OK ){
    ++      sqlite3_result_text(ctx, zReport ? zReport : "ok", -1, SQLITE_TRANSIENT);
    ++    }else{
    ++      sqlite3_result_error_code(ctx, rc);
    ++    }
    ++    sqlite3_free(zReport);
    ++  }
    ++}
    ++
    ++
    + /*
    + ** Register the r-tree module with database handle db. This creates the
    + ** virtual table module "rtree" and the debugging/analysis scalar 
    +@@ -157396,6 +171133,9 @@ SQLITE_PRIVATE int sqlite3RtreeInit(sqlite3 *db){
    +   if( rc==SQLITE_OK ){
    +     rc = sqlite3_create_function(db, "rtreedepth", 1, utf8, 0,rtreedepth, 0, 0);
    +   }
    ++  if( rc==SQLITE_OK ){
    ++    rc = sqlite3_create_function(db, "rtreecheck", -1, utf8, 0,rtreecheck, 0,0);
    ++  }
    +   if( rc==SQLITE_OK ){
    + #ifdef SQLITE_RTREE_INT_ONLY
    +     void *c = (void *)RTREE_COORD_INT32;
    +@@ -157464,7 +171204,7 @@ static void geomCallback(sqlite3_context *ctx, int nArg, sqlite3_value **aArg){
    +     sqlite3_result_error_nomem(ctx);
    +   }else{
    +     int i;
    +-    pBlob->magic = RTREE_GEOMETRY_MAGIC;
    ++    pBlob->iSize = nBlob;
    +     pBlob->cb = pGeomCtx[0];
    +     pBlob->apSqlParam = (sqlite3_value**)&pBlob->aParam[nArg];
    +     pBlob->nParam = nArg;
    +@@ -157481,7 +171221,7 @@ static void geomCallback(sqlite3_context *ctx, int nArg, sqlite3_value **aArg){
    +       sqlite3_result_error_nomem(ctx);
    +       rtreeMatchArgFree(pBlob);
    +     }else{
    +-      sqlite3_result_blob(ctx, pBlob, nBlob, rtreeMatchArgFree);
    ++      sqlite3_result_pointer(ctx, pBlob, "RtreeMatchArg", rtreeMatchArgFree);
    +     }
    +   }
    + }
    +@@ -157489,7 +171229,7 @@ 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 SQLITE_STDCALL sqlite3_rtree_geometry_callback(
    ++SQLITE_API int sqlite3_rtree_geometry_callback(
    +   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 */
    +@@ -157513,7 +171253,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_rtree_geometry_callback(
    + ** Register a new 2nd-generation geometry function for use with the
    + ** r-tree MATCH operator.
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_rtree_query_callback(
    ++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 */
    +@@ -157538,7 +171278,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_rtree_query_callback(
    + #ifdef _WIN32
    + __declspec(dllexport)
    + #endif
    +-SQLITE_API int SQLITE_STDCALL sqlite3_rtree_init(
    ++SQLITE_API int sqlite3_rtree_init(
    +   sqlite3 *db,
    +   char **pzErrMsg,
    +   const sqlite3_api_routines *pApi
    +@@ -157582,7 +171322,9 @@ SQLITE_API int SQLITE_STDCALL sqlite3_rtree_init(
    + **     provide case-independent matching.
    + */
    + 
    +-#if !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_ICU)
    ++#if !defined(SQLITE_CORE)                  \
    ++ || defined(SQLITE_ENABLE_ICU)             \
    ++ || defined(SQLITE_ENABLE_ICU_COLLATIONS)
    + 
    + /* Include ICU headers */
    + #include <unicode/utypes.h>
    +@@ -157599,6 +171341,26 @@ SQLITE_API int SQLITE_STDCALL sqlite3_rtree_init(
    + /*   #include "sqlite3.h" */
    + #endif
    + 
    ++/*
    ++** This function is called when an ICU function called from within
    ++** the implementation of an SQL scalar function returns an error.
    ++**
    ++** The scalar function context passed as the first argument is 
    ++** loaded with an error message based on the following two args.
    ++*/
    ++static void icuFunctionError(
    ++  sqlite3_context *pCtx,       /* SQLite scalar function context */
    ++  const char *zName,           /* Name of ICU function that failed */
    ++  UErrorCode e                 /* Error code returned by ICU function */
    ++){
    ++  char zBuf[128];
    ++  sqlite3_snprintf(128, zBuf, "ICU error: %s(): %s", zName, u_errorName(e));
    ++  zBuf[127] = '\0';
    ++  sqlite3_result_error(pCtx, zBuf, -1);
    ++}
    ++
    ++#if !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_ICU)
    ++
    + /*
    + ** Maximum length (in bytes) of the pattern in a LIKE or GLOB
    + ** operator.
    +@@ -157614,6 +171376,38 @@ static void xFree(void *p){
    +   sqlite3_free(p);
    + }
    + 
    ++/*
    ++** This lookup table is used to help decode the first byte of
    ++** a multi-byte UTF8 character. It is copied here from SQLite source
    ++** code file utf8.c.
    ++*/
    ++static const unsigned char icuUtf8Trans1[] = {
    ++  0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
    ++  0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
    ++  0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
    ++  0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
    ++  0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
    ++  0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
    ++  0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
    ++  0x00, 0x01, 0x02, 0x03, 0x00, 0x01, 0x00, 0x00,
    ++};
    ++
    ++#define SQLITE_ICU_READ_UTF8(zIn, c)                       \
    ++  c = *(zIn++);                                            \
    ++  if( c>=0xc0 ){                                           \
    ++    c = icuUtf8Trans1[c-0xc0];                             \
    ++    while( (*zIn & 0xc0)==0x80 ){                          \
    ++      c = (c<<6) + (0x3f & *(zIn++));                      \
    ++    }                                                      \
    ++  }
    ++
    ++#define SQLITE_ICU_SKIP_UTF8(zIn)                          \
    ++  assert( *zIn );                                          \
    ++  if( *(zIn++)>=0xc0 ){                                    \
    ++    while( (*zIn & 0xc0)==0x80 ){zIn++;}                   \
    ++  }
    ++
    ++
    + /*
    + ** Compare two UTF-8 strings for equality where the first string is
    + ** a "LIKE" expression. Return true (1) if they are the same and 
    +@@ -157624,19 +171418,17 @@ static int icuLikeCompare(
    +   const uint8_t *zString,    /* The UTF-8 string to compare against */
    +   const UChar32 uEsc         /* The escape character */
    + ){
    +-  static const int MATCH_ONE = (UChar32)'_';
    +-  static const int MATCH_ALL = (UChar32)'%';
    +-
    +-  int iPattern = 0;       /* Current byte index in zPattern */
    +-  int iString = 0;        /* Current byte index in zString */
    ++  static const uint32_t MATCH_ONE = (uint32_t)'_';
    ++  static const uint32_t MATCH_ALL = (uint32_t)'%';
    + 
    +   int prevEscape = 0;     /* True if the previous character was uEsc */
    + 
    +-  while( zPattern[iPattern]!=0 ){
    ++  while( 1 ){
    + 
    +     /* Read (and consume) the next character from the input pattern. */
    +-    UChar32 uPattern;
    +-    U8_NEXT_UNSAFE(zPattern, iPattern, uPattern);
    ++    uint32_t uPattern;
    ++    SQLITE_ICU_READ_UTF8(zPattern, uPattern);
    ++    if( uPattern==0 ) break;
    + 
    +     /* There are now 4 possibilities:
    +     **
    +@@ -157653,39 +171445,39 @@ static int icuLikeCompare(
    +       ** MATCH_ALL. For each MATCH_ONE, skip one character in the 
    +       ** test string.
    +       */
    +-      while( (c=zPattern[iPattern]) == MATCH_ALL || c == MATCH_ONE ){
    ++      while( (c=*zPattern) == MATCH_ALL || c == MATCH_ONE ){
    +         if( c==MATCH_ONE ){
    +-          if( zString[iString]==0 ) return 0;
    +-          U8_FWD_1_UNSAFE(zString, iString);
    ++          if( *zString==0 ) return 0;
    ++          SQLITE_ICU_SKIP_UTF8(zString);
    +         }
    +-        iPattern++;
    ++        zPattern++;
    +       }
    + 
    +-      if( zPattern[iPattern]==0 ) return 1;
    ++      if( *zPattern==0 ) return 1;
    + 
    +-      while( zString[iString] ){
    +-        if( icuLikeCompare(&zPattern[iPattern], &zString[iString], uEsc) ){
    ++      while( *zString ){
    ++        if( icuLikeCompare(zPattern, zString, uEsc) ){
    +           return 1;
    +         }
    +-        U8_FWD_1_UNSAFE(zString, iString);
    ++        SQLITE_ICU_SKIP_UTF8(zString);
    +       }
    +       return 0;
    + 
    +     }else if( !prevEscape && uPattern==MATCH_ONE ){
    +       /* Case 2. */
    +-      if( zString[iString]==0 ) return 0;
    +-      U8_FWD_1_UNSAFE(zString, iString);
    ++      if( *zString==0 ) return 0;
    ++      SQLITE_ICU_SKIP_UTF8(zString);
    + 
    +-    }else if( !prevEscape && uPattern==uEsc){
    ++    }else if( !prevEscape && uPattern==(uint32_t)uEsc){
    +       /* Case 3. */
    +       prevEscape = 1;
    + 
    +     }else{
    +       /* Case 4. */
    +-      UChar32 uString;
    +-      U8_NEXT_UNSAFE(zString, iString, uString);
    +-      uString = u_foldCase(uString, U_FOLD_CASE_DEFAULT);
    +-      uPattern = u_foldCase(uPattern, U_FOLD_CASE_DEFAULT);
    ++      uint32_t uString;
    ++      SQLITE_ICU_READ_UTF8(zString, uString);
    ++      uString = (uint32_t)u_foldCase((UChar32)uString, U_FOLD_CASE_DEFAULT);
    ++      uPattern = (uint32_t)u_foldCase((UChar32)uPattern, U_FOLD_CASE_DEFAULT);
    +       if( uString!=uPattern ){
    +         return 0;
    +       }
    +@@ -157693,7 +171485,7 @@ static int icuLikeCompare(
    +     }
    +   }
    + 
    +-  return zString[iString]==0;
    ++  return *zString==0;
    + }
    + 
    + /*
    +@@ -157748,24 +171540,6 @@ static void icuLikeFunc(
    +   }
    + }
    + 
    +-/*
    +-** This function is called when an ICU function called from within
    +-** the implementation of an SQL scalar function returns an error.
    +-**
    +-** The scalar function context passed as the first argument is 
    +-** loaded with an error message based on the following two args.
    +-*/
    +-static void icuFunctionError(
    +-  sqlite3_context *pCtx,       /* SQLite scalar function context */
    +-  const char *zName,           /* Name of ICU function that failed */
    +-  UErrorCode e                 /* Error code returned by ICU function */
    +-){
    +-  char zBuf[128];
    +-  sqlite3_snprintf(128, zBuf, "ICU error: %s(): %s", zName, u_errorName(e));
    +-  zBuf[127] = '\0';
    +-  sqlite3_result_error(pCtx, zBuf, -1);
    +-}
    +-
    + /*
    + ** Function to delete compiled regexp objects. Registered as
    + ** a destructor function with sqlite3_set_auxdata().
    +@@ -157873,20 +171647,22 @@ static void icuRegexpFunc(sqlite3_context *p, int nArg, sqlite3_value **apArg){
    + ** of upper() or lower().
    + **
    + **     lower('I', 'en_us') -> 'i'
    +-**     lower('I', 'tr_tr') -> 'ı' (small dotless i)
    ++**     lower('I', 'tr_tr') -> '\u131' (small dotless i)
    + **
    + ** http://www.icu-project.org/userguide/posix.html#case_mappings
    + */
    + static void icuCaseFunc16(sqlite3_context *p, int nArg, sqlite3_value **apArg){
    +-  const UChar *zInput;
    +-  UChar *zOutput;
    +-  int nInput;
    +-  int nOutput;
    +-
    +-  UErrorCode status = U_ZERO_ERROR;
    ++  const UChar *zInput;            /* Pointer to input string */
    ++  UChar *zOutput = 0;             /* Pointer to output buffer */
    ++  int nInput;                     /* Size of utf-16 input string in bytes */
    ++  int nOut;                       /* Size of output buffer in bytes */
    ++  int cnt;
    ++  int bToUpper;                   /* True for toupper(), false for tolower() */
    ++  UErrorCode status;
    +   const char *zLocale = 0;
    + 
    +   assert(nArg==1 || nArg==2);
    ++  bToUpper = (sqlite3_user_data(p)!=0);
    +   if( nArg==2 ){
    +     zLocale = (const char *)sqlite3_value_text(apArg[1]);
    +   }
    +@@ -157895,28 +171671,42 @@ static void icuCaseFunc16(sqlite3_context *p, int nArg, sqlite3_value **apArg){
    +   if( !zInput ){
    +     return;
    +   }
    +-  nInput = sqlite3_value_bytes16(apArg[0]);
    +-
    +-  nOutput = nInput * 2 + 2;
    +-  zOutput = sqlite3_malloc(nOutput);
    +-  if( !zOutput ){
    ++  nOut = nInput = sqlite3_value_bytes16(apArg[0]);
    ++  if( nOut==0 ){
    ++    sqlite3_result_text16(p, "", 0, SQLITE_STATIC);
    +     return;
    +   }
    + 
    +-  if( sqlite3_user_data(p) ){
    +-    u_strToUpper(zOutput, nOutput/2, zInput, nInput/2, zLocale, &status);
    +-  }else{
    +-    u_strToLower(zOutput, nOutput/2, zInput, nInput/2, zLocale, &status);
    +-  }
    ++  for(cnt=0; cnt<2; cnt++){
    ++    UChar *zNew = sqlite3_realloc(zOutput, nOut);
    ++    if( zNew==0 ){
    ++      sqlite3_free(zOutput);
    ++      sqlite3_result_error_nomem(p);
    ++      return;
    ++    }
    ++    zOutput = zNew;
    ++    status = U_ZERO_ERROR;
    ++    if( bToUpper ){
    ++      nOut = 2*u_strToUpper(zOutput,nOut/2,zInput,nInput/2,zLocale,&status);
    ++    }else{
    ++      nOut = 2*u_strToLower(zOutput,nOut/2,zInput,nInput/2,zLocale,&status);
    ++    }
    + 
    +-  if( !U_SUCCESS(status) ){
    +-    icuFunctionError(p, "u_strToLower()/u_strToUpper", status);
    ++    if( U_SUCCESS(status) ){
    ++      sqlite3_result_text16(p, zOutput, nOut, xFree);
    ++    }else if( status==U_BUFFER_OVERFLOW_ERROR ){
    ++      assert( cnt==0 );
    ++      continue;
    ++    }else{
    ++      icuFunctionError(p, bToUpper ? "u_strToUpper" : "u_strToLower", status);
    ++    }
    +     return;
    +   }
    +-
    +-  sqlite3_result_text16(p, zOutput, -1, xFree);
    ++  assert( 0 );     /* Unreachable */
    + }
    + 
    ++#endif /* !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_ICU) */
    ++
    + /*
    + ** Collation sequence destructor function. The pCtx argument points to
    + ** a UCollator structure previously allocated using ucol_open().
    +@@ -158003,38 +171793,37 @@ static void icuLoadCollation(
    + ** Register the ICU extension functions with database db.
    + */
    + SQLITE_PRIVATE int sqlite3IcuInit(sqlite3 *db){
    +-  struct IcuScalar {
    ++  static const struct IcuScalar {
    +     const char *zName;                        /* Function name */
    +-    int nArg;                                 /* Number of arguments */
    +-    int enc;                                  /* Optimal text encoding */
    +-    void *pContext;                           /* sqlite3_user_data() context */
    ++    unsigned char nArg;                       /* Number of arguments */
    ++    unsigned short enc;                       /* Optimal text encoding */
    ++    unsigned char iContext;                   /* sqlite3_user_data() context */
    +     void (*xFunc)(sqlite3_context*,int,sqlite3_value**);
    +   } scalars[] = {
    +-    {"regexp", 2, SQLITE_ANY,          0, icuRegexpFunc},
    +-
    +-    {"lower",  1, SQLITE_UTF16,        0, icuCaseFunc16},
    +-    {"lower",  2, SQLITE_UTF16,        0, icuCaseFunc16},
    +-    {"upper",  1, SQLITE_UTF16, (void*)1, icuCaseFunc16},
    +-    {"upper",  2, SQLITE_UTF16, (void*)1, icuCaseFunc16},
    +-
    +-    {"lower",  1, SQLITE_UTF8,         0, icuCaseFunc16},
    +-    {"lower",  2, SQLITE_UTF8,         0, icuCaseFunc16},
    +-    {"upper",  1, SQLITE_UTF8,  (void*)1, icuCaseFunc16},
    +-    {"upper",  2, SQLITE_UTF8,  (void*)1, icuCaseFunc16},
    +-
    +-    {"like",   2, SQLITE_UTF8,         0, icuLikeFunc},
    +-    {"like",   3, SQLITE_UTF8,         0, icuLikeFunc},
    +-
    +-    {"icu_load_collation",  2, SQLITE_UTF8, (void*)db, icuLoadCollation},
    ++    {"icu_load_collation",  2, SQLITE_UTF8,                1, icuLoadCollation},
    ++#if !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_ICU)
    ++    {"regexp", 2, SQLITE_ANY|SQLITE_DETERMINISTIC,         0, icuRegexpFunc},
    ++    {"lower",  1, SQLITE_UTF16|SQLITE_DETERMINISTIC,       0, icuCaseFunc16},
    ++    {"lower",  2, SQLITE_UTF16|SQLITE_DETERMINISTIC,       0, icuCaseFunc16},
    ++    {"upper",  1, SQLITE_UTF16|SQLITE_DETERMINISTIC,       1, icuCaseFunc16},
    ++    {"upper",  2, SQLITE_UTF16|SQLITE_DETERMINISTIC,       1, icuCaseFunc16},
    ++    {"lower",  1, SQLITE_UTF8|SQLITE_DETERMINISTIC,        0, icuCaseFunc16},
    ++    {"lower",  2, SQLITE_UTF8|SQLITE_DETERMINISTIC,        0, icuCaseFunc16},
    ++    {"upper",  1, SQLITE_UTF8|SQLITE_DETERMINISTIC,        1, icuCaseFunc16},
    ++    {"upper",  2, SQLITE_UTF8|SQLITE_DETERMINISTIC,        1, icuCaseFunc16},
    ++    {"like",   2, SQLITE_UTF8|SQLITE_DETERMINISTIC,        0, icuLikeFunc},
    ++    {"like",   3, SQLITE_UTF8|SQLITE_DETERMINISTIC,        0, icuLikeFunc},
    ++#endif /* !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_ICU) */
    +   };
    +-
    +   int rc = SQLITE_OK;
    +   int i;
    +-
    ++  
    +   for(i=0; rc==SQLITE_OK && i<(int)(sizeof(scalars)/sizeof(scalars[0])); i++){
    +-    struct IcuScalar *p = &scalars[i];
    ++    const struct IcuScalar *p = &scalars[i];
    +     rc = sqlite3_create_function(
    +-        db, p->zName, p->nArg, p->enc, p->pContext, p->xFunc, 0, 0
    ++        db, p->zName, p->nArg, p->enc, 
    ++        p->iContext ? (void*)db : (void*)0,
    ++        p->xFunc, 0, 0
    +     );
    +   }
    + 
    +@@ -158045,7 +171834,7 @@ SQLITE_PRIVATE int sqlite3IcuInit(sqlite3 *db){
    + #ifdef _WIN32
    + __declspec(dllexport)
    + #endif
    +-SQLITE_API int SQLITE_STDCALL sqlite3_icu_init(
    ++SQLITE_API int sqlite3_icu_init(
    +   sqlite3 *db, 
    +   char **pzErrMsg,
    +   const sqlite3_api_routines *pApi
    +@@ -158521,7 +172310,7 @@ SQLITE_PRIVATE void sqlite3Fts3IcuTokenizerModule(
    + ** may also be named data<integer>_<target>, where <integer> is any sequence
    + ** of zero or more numeric characters (0-9). This can be significant because
    + ** tables within the RBU database are always processed in order sorted by 
    +-** name. By judicious selection of the the <integer> portion of the names
    ++** name. By judicious selection of the <integer> portion of the names
    + ** of the RBU tables the user can therefore control the order in which they
    + ** are processed. This can be useful, for example, to ensure that "external
    + ** content" FTS4 tables are updated before their underlying content tables.
    +@@ -158725,12 +172514,72 @@ typedef struct sqlite3rbu sqlite3rbu;
    + ** not work out of the box with zipvfs. Refer to the comment describing
    + ** the zipvfs_create_vfs() API below for details on using RBU with zipvfs.
    + */
    +-SQLITE_API sqlite3rbu *SQLITE_STDCALL sqlite3rbu_open(
    ++SQLITE_API sqlite3rbu *sqlite3rbu_open(
    +   const char *zTarget, 
    +   const char *zRbu,
    +   const char *zState
    + );
    + 
    ++/*
    ++** Open an RBU handle to perform an RBU vacuum on database file zTarget.
    ++** An RBU vacuum is similar to SQLite's built-in VACUUM command, except
    ++** that it can be suspended and resumed like an RBU update.
    ++**
    ++** The second argument to this function identifies a database in which 
    ++** to store the state of the RBU vacuum operation if it is suspended. The 
    ++** first time sqlite3rbu_vacuum() is called, to start an RBU vacuum
    ++** operation, the state database should either not exist or be empty
    ++** (contain no tables). If an RBU vacuum is suspended by calling 
    ++** sqlite3rbu_close() on the RBU handle before sqlite3rbu_step() has
    ++** returned SQLITE_DONE, the vacuum state is stored in the state database. 
    ++** The vacuum can be resumed by calling this function to open a new RBU
    ++** handle specifying the same target and state databases.
    ++**
    ++** If the second argument passed to this function is NULL, then the
    ++** name of the state database is "<database>-vacuum", where <database>
    ++** is the name of the target database file. In this case, on UNIX, if the
    ++** state database is not already present in the file-system, it is created
    ++** with the same permissions as the target db is made.
    ++**
    ++** This function does not delete the state database after an RBU vacuum
    ++** is completed, even if it created it. However, if the call to
    ++** sqlite3rbu_close() returns any value other than SQLITE_OK, the contents
    ++** of the state tables within the state database are zeroed. This way,
    ++** the next call to sqlite3rbu_vacuum() opens a handle that starts a 
    ++** new RBU vacuum operation.
    ++**
    ++** As with sqlite3rbu_open(), Zipvfs users should rever to the comment
    ++** describing the sqlite3rbu_create_vfs() API function below for 
    ++** a description of the complications associated with using RBU with 
    ++** zipvfs databases.
    ++*/
    ++SQLITE_API sqlite3rbu *sqlite3rbu_vacuum(
    ++  const char *zTarget, 
    ++  const char *zState
    ++);
    ++
    ++/*
    ++** Configure a limit for the amount of temp space that may be used by
    ++** the RBU handle passed as the first argument. The new limit is specified
    ++** in bytes by the second parameter. If it is positive, the limit is updated.
    ++** If the second parameter to this function is passed zero, then the limit
    ++** is removed entirely. If the second parameter is negative, the limit is
    ++** not modified (this is useful for querying the current limit).
    ++**
    ++** In all cases the returned value is the current limit in bytes (zero 
    ++** indicates unlimited).
    ++**
    ++** If the temp space limit is exceeded during operation, an SQLITE_FULL
    ++** error is returned.
    ++*/
    ++SQLITE_API sqlite3_int64 sqlite3rbu_temp_size_limit(sqlite3rbu*, sqlite3_int64);
    ++
    ++/*
    ++** Return the current amount of temp file space, in bytes, currently used by 
    ++** the RBU handle passed as the only argument.
    ++*/
    ++SQLITE_API sqlite3_int64 sqlite3rbu_temp_size(sqlite3rbu*);
    ++
    + /*
    + ** Internally, each RBU connection uses a separate SQLite database 
    + ** connection to access the target and rbu update databases. This
    +@@ -158758,8 +172607,11 @@ SQLITE_API sqlite3rbu *SQLITE_STDCALL sqlite3rbu_open(
    + ** If an error has occurred, either while opening or stepping the RBU object,
    + ** this function may return NULL. The error code and message may be collected
    + ** when sqlite3rbu_close() is called.
    ++**
    ++** Database handles returned by this function remain valid until the next
    ++** call to any sqlite3rbu_xxx() function other than sqlite3rbu_db().
    + */
    +-SQLITE_API sqlite3 *SQLITE_STDCALL sqlite3rbu_db(sqlite3rbu*, int bRbu);
    ++SQLITE_API sqlite3 *sqlite3rbu_db(sqlite3rbu*, int bRbu);
    + 
    + /*
    + ** Do some work towards applying the RBU update to the target db. 
    +@@ -158773,7 +172625,7 @@ SQLITE_API sqlite3 *SQLITE_STDCALL sqlite3rbu_db(sqlite3rbu*, int bRbu);
    + ** SQLITE_OK, all subsequent calls on the same RBU handle are no-ops
    + ** that immediately return the same value.
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3rbu_step(sqlite3rbu *pRbu);
    ++SQLITE_API int sqlite3rbu_step(sqlite3rbu *pRbu);
    + 
    + /*
    + ** Force RBU to save its state to disk.
    +@@ -158785,7 +172637,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3rbu_step(sqlite3rbu *pRbu);
    + **
    + ** SQLITE_OK is returned if successful, or an SQLite error code otherwise.
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3rbu_savestate(sqlite3rbu *pRbu);
    ++SQLITE_API int sqlite3rbu_savestate(sqlite3rbu *pRbu);
    + 
    + /*
    + ** Close an RBU handle. 
    +@@ -158796,23 +172648,103 @@ SQLITE_API int SQLITE_STDCALL sqlite3rbu_savestate(sqlite3rbu *pRbu);
    + **
    + ** If an error has already occurred as part of an sqlite3rbu_step()
    + ** or sqlite3rbu_open() call, or if one occurs within this function, an
    +-** SQLite error code is returned. Additionally, *pzErrmsg may be set to
    +-** point to a buffer containing a utf-8 formatted English language error
    +-** message. It is the responsibility of the caller to eventually free any 
    +-** such buffer using sqlite3_free().
    ++** SQLite error code is returned. Additionally, if pzErrmsg is not NULL,
    ++** *pzErrmsg may be set to point to a buffer containing a utf-8 formatted
    ++** English language error message. It is the responsibility of the caller to
    ++** eventually free any such buffer using sqlite3_free().
    + **
    + ** Otherwise, if no error occurs, this function returns SQLITE_OK if the
    + ** update has been partially applied, or SQLITE_DONE if it has been 
    + ** completely applied.
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3rbu_close(sqlite3rbu *pRbu, char **pzErrmsg);
    ++SQLITE_API int sqlite3rbu_close(sqlite3rbu *pRbu, char **pzErrmsg);
    + 
    + /*
    + ** Return the total number of key-value operations (inserts, deletes or 
    + ** updates) that have been performed on the target database since the
    + ** current RBU update was started.
    + */
    +-SQLITE_API sqlite3_int64 SQLITE_STDCALL sqlite3rbu_progress(sqlite3rbu *pRbu);
    ++SQLITE_API sqlite3_int64 sqlite3rbu_progress(sqlite3rbu *pRbu);
    ++
    ++/*
    ++** Obtain permyriadage (permyriadage is to 10000 as percentage is to 100) 
    ++** progress indications for the two stages of an RBU update. This API may
    ++** be useful for driving GUI progress indicators and similar.
    ++**
    ++** An RBU update is divided into two stages:
    ++**
    ++**   * Stage 1, in which changes are accumulated in an oal/wal file, and
    ++**   * Stage 2, in which the contents of the wal file are copied into the
    ++**     main database.
    ++**
    ++** The update is visible to non-RBU clients during stage 2. During stage 1
    ++** non-RBU reader clients may see the original database.
    ++**
    ++** If this API is called during stage 2 of the update, output variable 
    ++** (*pnOne) is set to 10000 to indicate that stage 1 has finished and (*pnTwo)
    ++** to a value between 0 and 10000 to indicate the permyriadage progress of
    ++** stage 2. A value of 5000 indicates that stage 2 is half finished, 
    ++** 9000 indicates that it is 90% finished, and so on.
    ++**
    ++** If this API is called during stage 1 of the update, output variable 
    ++** (*pnTwo) is set to 0 to indicate that stage 2 has not yet started. The
    ++** value to which (*pnOne) is set depends on whether or not the RBU 
    ++** database contains an "rbu_count" table. The rbu_count table, if it 
    ++** exists, must contain the same columns as the following:
    ++**
    ++**   CREATE TABLE rbu_count(tbl TEXT PRIMARY KEY, cnt INTEGER) WITHOUT ROWID;
    ++**
    ++** There must be one row in the table for each source (data_xxx) table within
    ++** the RBU database. The 'tbl' column should contain the name of the source
    ++** table. The 'cnt' column should contain the number of rows within the
    ++** source table.
    ++**
    ++** If the rbu_count table is present and populated correctly and this
    ++** API is called during stage 1, the *pnOne output variable is set to the
    ++** permyriadage progress of the same stage. If the rbu_count table does
    ++** not exist, then (*pnOne) is set to -1 during stage 1. If the rbu_count
    ++** table exists but is not correctly populated, the value of the *pnOne
    ++** output variable during stage 1 is undefined.
    ++*/
    ++SQLITE_API void sqlite3rbu_bp_progress(sqlite3rbu *pRbu, int *pnOne, int*pnTwo);
    ++
    ++/*
    ++** Obtain an indication as to the current stage of an RBU update or vacuum.
    ++** This function always returns one of the SQLITE_RBU_STATE_XXX constants
    ++** defined in this file. Return values should be interpreted as follows:
    ++**
    ++** SQLITE_RBU_STATE_OAL:
    ++**   RBU is currently building a *-oal file. The next call to sqlite3rbu_step()
    ++**   may either add further data to the *-oal file, or compute data that will
    ++**   be added by a subsequent call.
    ++**
    ++** SQLITE_RBU_STATE_MOVE:
    ++**   RBU has finished building the *-oal file. The next call to sqlite3rbu_step()
    ++**   will move the *-oal file to the equivalent *-wal path. If the current
    ++**   operation is an RBU update, then the updated version of the database
    ++**   file will become visible to ordinary SQLite clients following the next
    ++**   call to sqlite3rbu_step().
    ++**
    ++** SQLITE_RBU_STATE_CHECKPOINT:
    ++**   RBU is currently performing an incremental checkpoint. The next call to
    ++**   sqlite3rbu_step() will copy a page of data from the *-wal file into
    ++**   the target database file.
    ++**
    ++** SQLITE_RBU_STATE_DONE:
    ++**   The RBU operation has finished. Any subsequent calls to sqlite3rbu_step()
    ++**   will immediately return SQLITE_DONE.
    ++**
    ++** SQLITE_RBU_STATE_ERROR:
    ++**   An error has occurred. Any subsequent calls to sqlite3rbu_step() will
    ++**   immediately return the SQLite error code associated with the error.
    ++*/
    ++#define SQLITE_RBU_STATE_OAL        1
    ++#define SQLITE_RBU_STATE_MOVE       2
    ++#define SQLITE_RBU_STATE_CHECKPOINT 3
    ++#define SQLITE_RBU_STATE_DONE       4
    ++#define SQLITE_RBU_STATE_ERROR      5
    ++
    ++SQLITE_API int sqlite3rbu_state(sqlite3rbu *pRbu);
    + 
    + /*
    + ** Create an RBU VFS named zName that accesses the underlying file-system
    +@@ -158856,7 +172788,7 @@ SQLITE_API sqlite3_int64 SQLITE_STDCALL sqlite3rbu_progress(sqlite3rbu *pRbu);
    + ** file-system via "rbu" all the time, even if it only uses RBU functionality 
    + ** occasionally.
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3rbu_create_vfs(const char *zName, const char *zParent);
    ++SQLITE_API int sqlite3rbu_create_vfs(const char *zName, const char *zParent);
    + 
    + /*
    + ** Deregister and destroy an RBU vfs created by an earlier call to
    +@@ -158866,7 +172798,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3rbu_create_vfs(const char *zName, const cha
    + ** before all database handles that use it have been closed, the results
    + ** are undefined.
    + */
    +-SQLITE_API void SQLITE_STDCALL sqlite3rbu_destroy_vfs(const char *zName);
    ++SQLITE_API void sqlite3rbu_destroy_vfs(const char *zName);
    + 
    + #if 0
    + }  /* end of the 'extern "C"' block */
    +@@ -158884,6 +172816,13 @@ SQLITE_API void SQLITE_STDCALL sqlite3rbu_destroy_vfs(const char *zName);
    + /* Maximum number of prepared UPDATE statements held by this module */
    + #define SQLITE_RBU_UPDATE_CACHESIZE 16
    + 
    ++/* Delta checksums disabled by default.  Compile with -DRBU_ENABLE_DELTA_CKSUM
    ++** to enable checksum verification.
    ++*/
    ++#ifndef RBU_ENABLE_DELTA_CKSUM
    ++# define RBU_ENABLE_DELTA_CKSUM 0
    ++#endif
    ++
    + /*
    + ** Swap two objects of type TYPE.
    + */
    +@@ -158935,14 +172874,15 @@ SQLITE_API void SQLITE_STDCALL sqlite3rbu_destroy_vfs(const char *zName);
    + ** RBU_STATE_OALSZ:
    + **   Valid if STAGE==1. The size in bytes of the *-oal file.
    + */
    +-#define RBU_STATE_STAGE       1
    +-#define RBU_STATE_TBL         2
    +-#define RBU_STATE_IDX         3
    +-#define RBU_STATE_ROW         4
    +-#define RBU_STATE_PROGRESS    5
    +-#define RBU_STATE_CKPT        6
    +-#define RBU_STATE_COOKIE      7
    +-#define RBU_STATE_OALSZ       8
    ++#define RBU_STATE_STAGE        1
    ++#define RBU_STATE_TBL          2
    ++#define RBU_STATE_IDX          3
    ++#define RBU_STATE_ROW          4
    ++#define RBU_STATE_PROGRESS     5
    ++#define RBU_STATE_CKPT         6
    ++#define RBU_STATE_COOKIE       7
    ++#define RBU_STATE_OALSZ        8
    ++#define RBU_STATE_PHASEONESTEP 9
    + 
    + #define RBU_STAGE_OAL         1
    + #define RBU_STAGE_MOVE        2
    +@@ -158963,6 +172903,7 @@ typedef struct RbuUpdateStmt RbuUpdateStmt;
    + 
    + #if !defined(SQLITE_AMALGAMATION)
    + typedef unsigned int u32;
    ++typedef unsigned short u16;
    + typedef unsigned char u8;
    + typedef sqlite3_int64 i64;
    + #endif
    +@@ -158976,6 +172917,8 @@ typedef sqlite3_int64 i64;
    + #define WAL_LOCK_CKPT   1
    + #define WAL_LOCK_READ0  3
    + 
    ++#define SQLITE_FCNTL_RBUCNT    5149216
    ++
    + /*
    + ** A structure to store values read from the rbu_state table in memory.
    + */
    +@@ -158988,6 +172931,7 @@ struct RbuState {
    +   i64 nProgress;
    +   u32 iCookie;
    +   i64 iOalSz;
    ++  i64 nPhaseOneStep;
    + };
    + 
    + struct RbuUpdateStmt {
    +@@ -159032,6 +172976,7 @@ struct RbuObjIter {
    +   int iTnum;                      /* Root page of current object */
    +   int iPkTnum;                    /* If eType==EXTERNAL, root of PK index */
    +   int bUnique;                    /* Current index is unique */
    ++  int nIndex;                     /* Number of aux. indexes on table zTbl */
    + 
    +   /* Statements created by rbuObjIterPrepareAll() */
    +   int nCol;                       /* Number of columns in current object */
    +@@ -159068,10 +173013,11 @@ struct RbuObjIter {
    + */
    + #define RBU_INSERT     1          /* Insert on a main table b-tree */
    + #define RBU_DELETE     2          /* Delete a row from a main table b-tree */
    +-#define RBU_IDX_DELETE 3          /* Delete a row from an aux. index b-tree */
    +-#define RBU_IDX_INSERT 4          /* Insert on an aux. index b-tree */
    +-#define RBU_UPDATE     5          /* Update a row in a main table b-tree */
    ++#define RBU_REPLACE    3          /* Delete and then insert a row */
    ++#define RBU_IDX_DELETE 4          /* Delete a row from an aux. index b-tree */
    ++#define RBU_IDX_INSERT 5          /* Insert on an aux. index b-tree */
    + 
    ++#define RBU_UPDATE     6          /* Update a row in a main table b-tree */
    + 
    + /*
    + ** A single step of an incremental checkpoint - frame iWalFrame of the wal
    +@@ -159084,6 +173030,43 @@ struct RbuFrame {
    + 
    + /*
    + ** RBU handle.
    ++**
    ++** nPhaseOneStep:
    ++**   If the RBU database contains an rbu_count table, this value is set to
    ++**   a running estimate of the number of b-tree operations required to 
    ++**   finish populating the *-oal file. This allows the sqlite3_bp_progress()
    ++**   API to calculate the permyriadage progress of populating the *-oal file
    ++**   using the formula:
    ++**
    ++**     permyriadage = (10000 * nProgress) / nPhaseOneStep
    ++**
    ++**   nPhaseOneStep is initialized to the sum of:
    ++**
    ++**     nRow * (nIndex + 1)
    ++**
    ++**   for all source tables in the RBU database, where nRow is the number
    ++**   of rows in the source table and nIndex the number of indexes on the
    ++**   corresponding target database table.
    ++**
    ++**   This estimate is accurate if the RBU update consists entirely of
    ++**   INSERT operations. However, it is inaccurate if:
    ++**
    ++**     * the RBU update contains any UPDATE operations. If the PK specified
    ++**       for an UPDATE operation does not exist in the target table, then
    ++**       no b-tree operations are required on index b-trees. Or if the 
    ++**       specified PK does exist, then (nIndex*2) such operations are
    ++**       required (one delete and one insert on each index b-tree).
    ++**
    ++**     * the RBU update contains any DELETE operations for which the specified
    ++**       PK does not exist. In this case no operations are required on index
    ++**       b-trees.
    ++**
    ++**     * the RBU update contains REPLACE operations. These are similar to
    ++**       UPDATE operations.
    ++**
    ++**   nPhaseOneStep is updated to account for the conditions above during the
    ++**   first pass of each source table. The updated nPhaseOneStep value is
    ++**   stored in the rbu_state table if the RBU update is suspended.
    + */
    + struct sqlite3rbu {
    +   int eStage;                     /* Value of RBU_STATE_STAGE field */
    +@@ -159100,7 +173083,9 @@ struct sqlite3rbu {
    +   RbuObjIter objiter;             /* Iterator for skipping through tbl/idx */
    +   const char *zVfsName;           /* Name of automatically created rbu vfs */
    +   rbu_file *pTargetFd;            /* File handle open on target db */
    ++  int nPagePerSector;             /* Pages per sector for pTargetFd */
    +   i64 iOalSz;
    ++  i64 nPhaseOneStep;
    + 
    +   /* The following state variables are used as part of the incremental
    +   ** checkpoint stage (eStage==RBU_STAGE_CKPT). See comments surrounding
    +@@ -159113,31 +173098,49 @@ struct sqlite3rbu {
    +   int pgsz;
    +   u8 *aBuf;
    +   i64 iWalCksum;
    ++  i64 szTemp;                     /* Current size of all temp files in use */
    ++  i64 szTempLimit;                /* Total size limit for temp files */
    ++
    ++  /* Used in RBU vacuum mode only */
    ++  int nRbu;                       /* Number of RBU VFS in the stack */
    ++  rbu_file *pRbuFd;               /* Fd for main db of dbRbu */
    + };
    + 
    + /*
    + ** An rbu VFS is implemented using an instance of this structure.
    ++**
    ++** Variable pRbu is only non-NULL for automatically created RBU VFS objects.
    ++** It is NULL for RBU VFS objects created explicitly using
    ++** sqlite3rbu_create_vfs(). It is used to track the total amount of temp
    ++** space used by the RBU handle.
    + */
    + struct rbu_vfs {
    +   sqlite3_vfs base;               /* rbu VFS shim methods */
    +   sqlite3_vfs *pRealVfs;          /* Underlying VFS */
    +   sqlite3_mutex *mutex;           /* Mutex to protect pMain */
    +-  rbu_file *pMain;                /* Linked list of main db files */
    ++  sqlite3rbu *pRbu;               /* Owner RBU object */
    ++  rbu_file *pMain;                /* List of main db files */
    ++  rbu_file *pMainRbu;             /* List of main db files with pRbu!=0 */
    + };
    + 
    + /*
    + ** Each file opened by an rbu VFS is represented by an instance of
    + ** the following structure.
    ++**
    ++** If this is a temporary file (pRbu!=0 && flags&DELETE_ON_CLOSE), variable
    ++** "sz" is set to the current size of the database file.
    + */
    + struct rbu_file {
    +   sqlite3_file base;              /* sqlite3_file methods */
    +   sqlite3_file *pReal;            /* Underlying file handle */
    +   rbu_vfs *pRbuVfs;               /* Pointer to the rbu_vfs object */
    +   sqlite3rbu *pRbu;               /* Pointer to rbu object (rbu target only) */
    ++  i64 sz;                         /* Size of file in bytes (temp only) */
    + 
    +   int openFlags;                  /* Flags this file was opened with */
    +   u32 iCookie;                    /* Cookie value for main db files */
    +   u8 iWriteVer;                   /* "write-version" value for main db files */
    ++  u8 bNolock;                     /* True to fail EXCLUSIVE locks */
    + 
    +   int nShm;                       /* Number of entries in apShm[] array */
    +   char **apShm;                   /* Array of mmap'd *-shm regions */
    +@@ -159146,8 +173149,14 @@ struct rbu_file {
    +   const char *zWal;               /* Wal filename for this main db file */
    +   rbu_file *pWalFd;               /* Wal file descriptor for this main db */
    +   rbu_file *pMainNext;            /* Next MAIN_DB file */
    ++  rbu_file *pMainRbuNext;         /* Next MAIN_DB file with pRbu!=0 */
    + };
    + 
    ++/*
    ++** True for an RBU vacuum handle, or false otherwise.
    ++*/
    ++#define rbuIsVacuum(p) ((p)->zTarget==0)
    ++
    + 
    + /*************************************************************************
    + ** The following three functions, found below:
    +@@ -159190,6 +173199,7 @@ static unsigned int rbuDeltaGetInt(const char **pz, int *pLen){
    +   return v;
    + }
    + 
    ++#if RBU_ENABLE_DELTA_CKSUM
    + /*
    + ** Compute a 32-bit checksum on the N-byte buffer.  Return the result.
    + */
    +@@ -159224,6 +173234,7 @@ static unsigned int rbuDeltaChecksum(const char *zIn, size_t N){
    +   }
    +   return sum3;
    + }
    ++#endif
    + 
    + /*
    + ** Apply a delta.
    +@@ -159254,7 +173265,7 @@ static int rbuDeltaApply(
    + ){
    +   unsigned int limit;
    +   unsigned int total = 0;
    +-#ifndef FOSSIL_OMIT_DELTA_CKSUM_TEST
    ++#if RBU_ENABLE_DELTA_CKSUM
    +   char *zOrigOut = zOut;
    + #endif
    + 
    +@@ -159309,7 +173320,7 @@ static int rbuDeltaApply(
    +       case ';': {
    +         zDelta++; lenDelta--;
    +         zOut[0] = 0;
    +-#ifndef FOSSIL_OMIT_DELTA_CKSUM_TEST
    ++#if RBU_ENABLE_DELTA_CKSUM
    +         if( cnt!=rbuDeltaChecksum(zOrigOut, total) ){
    +           /* ERROR:  bad checksum */
    +           return -1;
    +@@ -159596,8 +173607,11 @@ static int rbuObjIterNext(sqlite3rbu *p, RbuObjIter *pIter){
    + 
    + /*
    + ** The implementation of the rbu_target_name() SQL function. This function
    +-** accepts one argument - the name of a table in the RBU database. If the
    +-** table name matches the pattern:
    ++** accepts one or two arguments. The first argument is the name of a table -
    ++** the name of a table in the RBU database.  The second, if it is present, is 1
    ++** for a view or 0 for a table. 
    ++**
    ++** For a non-vacuum RBU handle, if the table name matches the pattern:
    + **
    + **     data[0-9]_<name>
    + **
    +@@ -159608,21 +173622,33 @@ static int rbuObjIterNext(sqlite3rbu *p, RbuObjIter *pIter){
    + **     "data_t1"     -> "t1"
    + **     "data0123_t2" -> "t2"
    + **     "dataAB_t3"   -> NULL
    ++**
    ++** For an rbu vacuum handle, a copy of the first argument is returned if
    ++** the second argument is either missing or 0 (not a view).
    + */
    + static void rbuTargetNameFunc(
    +-  sqlite3_context *context,
    ++  sqlite3_context *pCtx,
    +   int argc,
    +   sqlite3_value **argv
    + ){
    ++  sqlite3rbu *p = sqlite3_user_data(pCtx);
    +   const char *zIn;
    +-  assert( argc==1 );
    ++  assert( argc==1 || argc==2 );
    + 
    +   zIn = (const char*)sqlite3_value_text(argv[0]);
    +-  if( zIn && strlen(zIn)>4 && memcmp("data", zIn, 4)==0 ){
    +-    int i;
    +-    for(i=4; zIn[i]>='0' && zIn[i]<='9'; i++);
    +-    if( zIn[i]=='_' && zIn[i+1] ){
    +-      sqlite3_result_text(context, &zIn[i+1], -1, SQLITE_STATIC);
    ++  if( zIn ){
    ++    if( rbuIsVacuum(p) ){
    ++      if( argc==1 || 0==sqlite3_value_int(argv[1]) ){
    ++        sqlite3_result_text(pCtx, zIn, -1, SQLITE_STATIC);
    ++      }
    ++    }else{
    ++      if( strlen(zIn)>4 && memcmp("data", zIn, 4)==0 ){
    ++        int i;
    ++        for(i=4; zIn[i]>='0' && zIn[i]<='9'; i++);
    ++        if( zIn[i]=='_' && zIn[i+1] ){
    ++          sqlite3_result_text(pCtx, &zIn[i+1], -1, SQLITE_STATIC);
    ++        }
    ++      }
    +     }
    +   }
    + }
    +@@ -159639,11 +173665,14 @@ static int rbuObjIterFirst(sqlite3rbu *p, RbuObjIter *pIter){
    +   int rc;
    +   memset(pIter, 0, sizeof(RbuObjIter));
    + 
    +-  rc = prepareAndCollectError(p->dbRbu, &pIter->pTblIter, &p->zErrmsg, 
    +-      "SELECT rbu_target_name(name) AS target, name FROM sqlite_master "
    ++  rc = prepareFreeAndCollectError(p->dbRbu, &pIter->pTblIter, &p->zErrmsg, 
    ++    sqlite3_mprintf(
    ++      "SELECT rbu_target_name(name, type='view') AS target, name "
    ++      "FROM sqlite_master "
    +       "WHERE type IN ('table', 'view') AND target IS NOT NULL "
    ++      " %s "
    +       "ORDER BY name"
    +-  );
    ++  , rbuIsVacuum(p) ? "AND rootpage!=0 AND rootpage IS NOT NULL" : ""));
    + 
    +   if( rc==SQLITE_OK ){
    +     rc = prepareAndCollectError(p->dbMain, &pIter->pIdxIter, &p->zErrmsg,
    +@@ -159723,7 +173752,7 @@ static void *rbuMalloc(sqlite3rbu *p, int nByte){
    +   void *pRet = 0;
    +   if( p->rc==SQLITE_OK ){
    +     assert( nByte>0 );
    +-    pRet = sqlite3_malloc(nByte);
    ++    pRet = sqlite3_malloc64(nByte);
    +     if( pRet==0 ){
    +       p->rc = SQLITE_NOMEM;
    +     }else{
    +@@ -159769,8 +173798,8 @@ static char *rbuStrndup(const char *zStr, int *pRc){
    + 
    +   assert( *pRc==SQLITE_OK );
    +   if( zStr ){
    +-    int nCopy = strlen(zStr) + 1;
    +-    zRet = (char*)sqlite3_malloc(nCopy);
    ++    size_t nCopy = strlen(zStr) + 1;
    ++    zRet = (char*)sqlite3_malloc64(nCopy);
    +     if( zRet ){
    +       memcpy(zRet, zStr, nCopy);
    +     }else{
    +@@ -159931,6 +173960,7 @@ static void rbuObjIterCacheIndexedCols(sqlite3rbu *p, RbuObjIter *pIter){
    +     );
    +   }
    + 
    ++  pIter->nIndex = 0;
    +   while( p->rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pList) ){
    +     const char *zIdx = (const char*)sqlite3_column_text(pList, 1);
    +     sqlite3_stmt *pXInfo = 0;
    +@@ -159944,6 +173974,12 @@ static void rbuObjIterCacheIndexedCols(sqlite3rbu *p, RbuObjIter *pIter){
    +     }
    +     rbuFinalize(p, pXInfo);
    +     bIndex = 1;
    ++    pIter->nIndex++;
    ++  }
    ++
    ++  if( pIter->eType==RBU_PK_WITHOUT_ROWID ){
    ++    /* "PRAGMA index_list" includes the main PK b-tree */
    ++    pIter->nIndex--;
    +   }
    + 
    +   rbuFinalize(p, pList);
    +@@ -160009,6 +174045,7 @@ static int rbuObjIterCacheTableInfo(sqlite3rbu *p, RbuObjIter *pIter){
    +     pStmt = 0;
    + 
    +     if( p->rc==SQLITE_OK
    ++     && rbuIsVacuum(p)==0
    +      && bRbuRowid!=(pIter->eType==RBU_PK_VTAB || pIter->eType==RBU_PK_NONE)
    +     ){
    +       p->rc = SQLITE_ERROR;
    +@@ -160057,6 +174094,7 @@ static int rbuObjIterCacheTableInfo(sqlite3rbu *p, RbuObjIter *pIter){
    +     rbuFinalize(p, pStmt);
    +     rbuObjIterCacheIndexedCols(p, pIter);
    +     assert( pIter->eType!=RBU_PK_VTAB || pIter->abIndexed==0 );
    ++    assert( pIter->eType!=RBU_PK_VTAB || pIter->nIndex==0 );
    +   }
    + 
    +   return p->rc;
    +@@ -160147,6 +174185,8 @@ static char *rbuObjIterGetIndexCols(
    +         for(i=0; pIter->abTblPk[i]==0; i++);
    +         assert( i<pIter->nTblCol );
    +         zCol = pIter->azTblCol[i];
    ++      }else if( rbuIsVacuum(p) ){
    ++        zCol = "_rowid_";
    +       }else{
    +         zCol = "rbu_rowid";
    +       }
    +@@ -160488,7 +174528,7 @@ static void rbuCreateImposterTable2(sqlite3rbu *p, RbuObjIter *pIter){
    +         int iCid = sqlite3_column_int(pXInfo, 1);
    +         int bDesc = sqlite3_column_int(pXInfo, 3);
    +         const char *zCollate = (const char*)sqlite3_column_text(pXInfo, 4);
    +-        zCols = rbuMPrintf(p, "%z%sc%d %s COLLATE %s", zCols, zComma, 
    ++        zCols = rbuMPrintf(p, "%z%sc%d %s COLLATE %Q", zCols, zComma,
    +             iCid, pIter->azTblType[iCid], zCollate
    +         );
    +         zPk = rbuMPrintf(p, "%z%sc%d%s", zPk, zComma, iCid, bDesc?" DESC":"");
    +@@ -160549,7 +174589,7 @@ static void rbuCreateImposterTable(sqlite3rbu *p, RbuObjIter *pIter){
    +         ** "PRIMARY KEY" to the imposter table column declaration. */
    +         zPk = "PRIMARY KEY ";
    +       }
    +-      zSql = rbuMPrintf(p, "%z%s\"%w\" %s %sCOLLATE %s%s", 
    ++      zSql = rbuMPrintf(p, "%z%s\"%w\" %s %sCOLLATE %Q%s",
    +           zSql, zComma, zCol, pIter->azTblType[iCol], zPk, zColl,
    +           (pIter->abNotNull[iCol] ? " NOT NULL" : "")
    +       );
    +@@ -160610,6 +174650,14 @@ static void rbuTmpInsertFunc(
    +   int rc = SQLITE_OK;
    +   int i;
    + 
    ++  assert( sqlite3_value_int(apVal[0])!=0
    ++      || p->objiter.eType==RBU_PK_EXTERNAL 
    ++      || p->objiter.eType==RBU_PK_NONE 
    ++  );
    ++  if( sqlite3_value_int(apVal[0])!=0 ){
    ++    p->nPhaseOneStep += p->objiter.nIndex;
    ++  }
    ++
    +   for(i=0; rc==SQLITE_OK && i<nVal; i++){
    +     rc = sqlite3_bind_value(p->objiter.pTmpInsert, i+1, apVal[i]);
    +   }
    +@@ -160679,7 +174727,7 @@ static int rbuObjIterPrepareAll(
    +       }
    + 
    +       /* And to delete index entries */
    +-      if( p->rc==SQLITE_OK ){
    ++      if( rbuIsVacuum(p)==0 && p->rc==SQLITE_OK ){
    +         p->rc = prepareFreeAndCollectError(
    +             p->dbMain, &pIter->pDelete, &p->zErrmsg,
    +           sqlite3_mprintf("DELETE FROM \"rbu_imp_%w\" WHERE %s", zTbl, zWhere)
    +@@ -160689,6 +174737,15 @@ static int rbuObjIterPrepareAll(
    +       /* Create the SELECT statement to read keys in sorted order */
    +       if( p->rc==SQLITE_OK ){
    +         char *zSql;
    ++        if( rbuIsVacuum(p) ){
    ++          zSql = sqlite3_mprintf(
    ++              "SELECT %s, 0 AS rbu_control FROM '%q' ORDER BY %s%s",
    ++              zCollist, 
    ++              pIter->zDataTbl,
    ++              zCollist, zLimit
    ++          );
    ++        }else
    ++
    +         if( pIter->eType==RBU_PK_EXTERNAL || pIter->eType==RBU_PK_NONE ){
    +           zSql = sqlite3_mprintf(
    +               "SELECT %s, rbu_control FROM %s.'rbu_tmp_%q' ORDER BY %s%s",
    +@@ -160697,13 +174754,13 @@ static int rbuObjIterPrepareAll(
    +           );
    +         }else{
    +           zSql = sqlite3_mprintf(
    ++              "SELECT %s, rbu_control FROM %s.'rbu_tmp_%q' "
    ++              "UNION ALL "
    +               "SELECT %s, rbu_control FROM '%q' "
    +               "WHERE typeof(rbu_control)='integer' AND rbu_control!=1 "
    +-              "UNION ALL "
    +-              "SELECT %s, rbu_control FROM %s.'rbu_tmp_%q' "
    +               "ORDER BY %s%s",
    +-              zCollist, pIter->zDataTbl, 
    +               zCollist, p->zStateDb, pIter->zDataTbl, 
    ++              zCollist, pIter->zDataTbl, 
    +               zCollist, zLimit
    +           );
    +         }
    +@@ -160715,7 +174772,9 @@ static int rbuObjIterPrepareAll(
    +       sqlite3_free(zWhere);
    +       sqlite3_free(zBind);
    +     }else{
    +-      int bRbuRowid = (pIter->eType==RBU_PK_VTAB || pIter->eType==RBU_PK_NONE);
    ++      int bRbuRowid = (pIter->eType==RBU_PK_VTAB)
    ++                    ||(pIter->eType==RBU_PK_NONE)
    ++                    ||(pIter->eType==RBU_PK_EXTERNAL && rbuIsVacuum(p));
    +       const char *zTbl = pIter->zTbl;       /* Table this step applies to */
    +       const char *zWrite;                   /* Imposter table name */
    + 
    +@@ -160742,8 +174801,10 @@ static int rbuObjIterPrepareAll(
    +         );
    +       }
    + 
    +-      /* Create the DELETE statement to write to the target PK b-tree */
    +-      if( p->rc==SQLITE_OK ){
    ++      /* Create the DELETE statement to write to the target PK b-tree.
    ++      ** Because it only performs INSERT operations, this is not required for
    ++      ** an rbu vacuum handle.  */
    ++      if( rbuIsVacuum(p)==0 && p->rc==SQLITE_OK ){
    +         p->rc = prepareFreeAndCollectError(p->dbMain, &pIter->pDelete, pz,
    +             sqlite3_mprintf(
    +               "DELETE FROM \"%s%w\" WHERE %s", zWrite, zTbl, zWhere
    +@@ -160751,7 +174812,7 @@ static int rbuObjIterPrepareAll(
    +         );
    +       }
    + 
    +-      if( pIter->abIndexed ){
    ++      if( rbuIsVacuum(p)==0 && pIter->abIndexed ){
    +         const char *zRbuRowid = "";
    +         if( pIter->eType==RBU_PK_EXTERNAL || pIter->eType==RBU_PK_NONE ){
    +           zRbuRowid = ", rbu_rowid";
    +@@ -160769,17 +174830,17 @@ static int rbuObjIterPrepareAll(
    +         rbuMPrintfExec(p, p->dbMain,
    +             "CREATE TEMP TRIGGER rbu_delete_tr BEFORE DELETE ON \"%s%w\" "
    +             "BEGIN "
    +-            "  SELECT rbu_tmp_insert(2, %s);"
    ++            "  SELECT rbu_tmp_insert(3, %s);"
    +             "END;"
    + 
    +             "CREATE TEMP TRIGGER rbu_update1_tr BEFORE UPDATE ON \"%s%w\" "
    +             "BEGIN "
    +-            "  SELECT rbu_tmp_insert(2, %s);"
    ++            "  SELECT rbu_tmp_insert(3, %s);"
    +             "END;"
    + 
    +             "CREATE TEMP TRIGGER rbu_update2_tr AFTER UPDATE ON \"%s%w\" "
    +             "BEGIN "
    +-            "  SELECT rbu_tmp_insert(3, %s);"
    ++            "  SELECT rbu_tmp_insert(4, %s);"
    +             "END;",
    +             zWrite, zTbl, zOldlist,
    +             zWrite, zTbl, zOldlist,
    +@@ -160801,10 +174862,16 @@ static int rbuObjIterPrepareAll(
    + 
    +       /* Create the SELECT statement to read keys from data_xxx */
    +       if( p->rc==SQLITE_OK ){
    ++        const char *zRbuRowid = "";
    ++        if( bRbuRowid ){
    ++          zRbuRowid = rbuIsVacuum(p) ? ",_rowid_ " : ",rbu_rowid";
    ++        }
    +         p->rc = prepareFreeAndCollectError(p->dbRbu, &pIter->pSelect, pz,
    +             sqlite3_mprintf(
    +-              "SELECT %s, rbu_control%s FROM '%q'%s", 
    +-              zCollist, (bRbuRowid ? ", rbu_rowid" : ""), 
    ++              "SELECT %s,%s rbu_control%s FROM '%q'%s", 
    ++              zCollist, 
    ++              (rbuIsVacuum(p) ? "0 AS " : ""),
    ++              zRbuRowid,
    +               pIter->zDataTbl, zLimit
    +             )
    +         );
    +@@ -160899,11 +174966,15 @@ static int rbuGetUpdateStmt(
    +   return p->rc;
    + }
    + 
    +-static sqlite3 *rbuOpenDbhandle(sqlite3rbu *p, const char *zName){
    ++static sqlite3 *rbuOpenDbhandle(
    ++  sqlite3rbu *p, 
    ++  const char *zName, 
    ++  int bUseVfs
    ++){
    +   sqlite3 *db = 0;
    +   if( p->rc==SQLITE_OK ){
    +     const int flags = SQLITE_OPEN_READWRITE|SQLITE_OPEN_CREATE|SQLITE_OPEN_URI;
    +-    p->rc = sqlite3_open_v2(zName, &db, flags, p->zVfsName);
    ++    p->rc = sqlite3_open_v2(zName, &db, flags, bUseVfs ? p->zVfsName : 0);
    +     if( p->rc ){
    +       p->zErrmsg = sqlite3_mprintf("%s", sqlite3_errmsg(db));
    +       sqlite3_close(db);
    +@@ -160913,17 +174984,113 @@ static sqlite3 *rbuOpenDbhandle(sqlite3rbu *p, const char *zName){
    +   return db;
    + }
    + 
    ++/*
    ++** Free an RbuState object allocated by rbuLoadState().
    ++*/
    ++static void rbuFreeState(RbuState *p){
    ++  if( p ){
    ++    sqlite3_free(p->zTbl);
    ++    sqlite3_free(p->zIdx);
    ++    sqlite3_free(p);
    ++  }
    ++}
    ++
    ++/*
    ++** Allocate an RbuState object and load the contents of the rbu_state 
    ++** table into it. Return a pointer to the new object. It is the 
    ++** responsibility of the caller to eventually free the object using
    ++** sqlite3_free().
    ++**
    ++** If an error occurs, leave an error code and message in the rbu handle
    ++** and return NULL.
    ++*/
    ++static RbuState *rbuLoadState(sqlite3rbu *p){
    ++  RbuState *pRet = 0;
    ++  sqlite3_stmt *pStmt = 0;
    ++  int rc;
    ++  int rc2;
    ++
    ++  pRet = (RbuState*)rbuMalloc(p, sizeof(RbuState));
    ++  if( pRet==0 ) return 0;
    ++
    ++  rc = prepareFreeAndCollectError(p->dbRbu, &pStmt, &p->zErrmsg, 
    ++      sqlite3_mprintf("SELECT k, v FROM %s.rbu_state", p->zStateDb)
    ++  );
    ++  while( rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pStmt) ){
    ++    switch( sqlite3_column_int(pStmt, 0) ){
    ++      case RBU_STATE_STAGE:
    ++        pRet->eStage = sqlite3_column_int(pStmt, 1);
    ++        if( pRet->eStage!=RBU_STAGE_OAL
    ++         && pRet->eStage!=RBU_STAGE_MOVE
    ++         && pRet->eStage!=RBU_STAGE_CKPT
    ++        ){
    ++          p->rc = SQLITE_CORRUPT;
    ++        }
    ++        break;
    ++
    ++      case RBU_STATE_TBL:
    ++        pRet->zTbl = rbuStrndup((char*)sqlite3_column_text(pStmt, 1), &rc);
    ++        break;
    ++
    ++      case RBU_STATE_IDX:
    ++        pRet->zIdx = rbuStrndup((char*)sqlite3_column_text(pStmt, 1), &rc);
    ++        break;
    ++
    ++      case RBU_STATE_ROW:
    ++        pRet->nRow = sqlite3_column_int(pStmt, 1);
    ++        break;
    ++
    ++      case RBU_STATE_PROGRESS:
    ++        pRet->nProgress = sqlite3_column_int64(pStmt, 1);
    ++        break;
    ++
    ++      case RBU_STATE_CKPT:
    ++        pRet->iWalCksum = sqlite3_column_int64(pStmt, 1);
    ++        break;
    ++
    ++      case RBU_STATE_COOKIE:
    ++        pRet->iCookie = (u32)sqlite3_column_int64(pStmt, 1);
    ++        break;
    ++
    ++      case RBU_STATE_OALSZ:
    ++        pRet->iOalSz = (u32)sqlite3_column_int64(pStmt, 1);
    ++        break;
    ++
    ++      case RBU_STATE_PHASEONESTEP:
    ++        pRet->nPhaseOneStep = sqlite3_column_int64(pStmt, 1);
    ++        break;
    ++
    ++      default:
    ++        rc = SQLITE_CORRUPT;
    ++        break;
    ++    }
    ++  }
    ++  rc2 = sqlite3_finalize(pStmt);
    ++  if( rc==SQLITE_OK ) rc = rc2;
    ++
    ++  p->rc = rc;
    ++  return pRet;
    ++}
    ++
    ++
    + /*
    + ** Open the database handle and attach the RBU database as "rbu". If an
    + ** error occurs, leave an error code and message in the RBU handle.
    + */
    +-static void rbuOpenDatabase(sqlite3rbu *p){
    +-  assert( p->rc==SQLITE_OK );
    +-  assert( p->dbMain==0 && p->dbRbu==0 );
    ++static void rbuOpenDatabase(sqlite3rbu *p, int *pbRetry){
    ++  assert( p->rc || (p->dbMain==0 && p->dbRbu==0) );
    ++  assert( p->rc || rbuIsVacuum(p) || p->zTarget!=0 );
    + 
    +-  p->eStage = 0;
    +-  p->dbMain = rbuOpenDbhandle(p, p->zTarget);
    +-  p->dbRbu = rbuOpenDbhandle(p, p->zRbu);
    ++  /* Open the RBU database */
    ++  p->dbRbu = rbuOpenDbhandle(p, p->zRbu, 1);
    ++
    ++  if( p->rc==SQLITE_OK && rbuIsVacuum(p) ){
    ++    sqlite3_file_control(p->dbRbu, "main", SQLITE_FCNTL_RBUCNT, (void*)p);
    ++    if( p->zState==0 ){
    ++      const char *zFile = sqlite3_db_filename(p->dbRbu, "main");
    ++      p->zState = rbuMPrintf(p, "file://%s-vacuum?modeof=%s", zFile, zFile);
    ++    }
    ++  }
    + 
    +   /* If using separate RBU and state databases, attach the state database to
    +   ** the RBU db handle now.  */
    +@@ -160934,6 +175101,105 @@ static void rbuOpenDatabase(sqlite3rbu *p){
    +     memcpy(p->zStateDb, "main", 4);
    +   }
    + 
    ++#if 0
    ++  if( p->rc==SQLITE_OK && rbuIsVacuum(p) ){
    ++    p->rc = sqlite3_exec(p->dbRbu, "BEGIN", 0, 0, 0);
    ++  }
    ++#endif
    ++
    ++  /* If it has not already been created, create the rbu_state table */
    ++  rbuMPrintfExec(p, p->dbRbu, RBU_CREATE_STATE, p->zStateDb);
    ++
    ++#if 0
    ++  if( rbuIsVacuum(p) ){
    ++    if( p->rc==SQLITE_OK ){
    ++      int rc2;
    ++      int bOk = 0;
    ++      sqlite3_stmt *pCnt = 0;
    ++      p->rc = prepareAndCollectError(p->dbRbu, &pCnt, &p->zErrmsg,
    ++          "SELECT count(*) FROM stat.sqlite_master"
    ++      );
    ++      if( p->rc==SQLITE_OK 
    ++       && sqlite3_step(pCnt)==SQLITE_ROW
    ++       && 1==sqlite3_column_int(pCnt, 0)
    ++      ){
    ++        bOk = 1;
    ++      }
    ++      rc2 = sqlite3_finalize(pCnt);
    ++      if( p->rc==SQLITE_OK ) p->rc = rc2;
    ++
    ++      if( p->rc==SQLITE_OK && bOk==0 ){
    ++        p->rc = SQLITE_ERROR;
    ++        p->zErrmsg = sqlite3_mprintf("invalid state database");
    ++      }
    ++    
    ++      if( p->rc==SQLITE_OK ){
    ++        p->rc = sqlite3_exec(p->dbRbu, "COMMIT", 0, 0, 0);
    ++      }
    ++    }
    ++  }
    ++#endif
    ++
    ++  if( p->rc==SQLITE_OK && rbuIsVacuum(p) ){
    ++    int bOpen = 0;
    ++    int rc;
    ++    p->nRbu = 0;
    ++    p->pRbuFd = 0;
    ++    rc = sqlite3_file_control(p->dbRbu, "main", SQLITE_FCNTL_RBUCNT, (void*)p);
    ++    if( rc!=SQLITE_NOTFOUND ) p->rc = rc;
    ++    if( p->eStage>=RBU_STAGE_MOVE ){
    ++      bOpen = 1;
    ++    }else{
    ++      RbuState *pState = rbuLoadState(p);
    ++      if( pState ){
    ++        bOpen = (pState->eStage>=RBU_STAGE_MOVE);
    ++        rbuFreeState(pState);
    ++      }
    ++    }
    ++    if( bOpen ) p->dbMain = rbuOpenDbhandle(p, p->zRbu, p->nRbu<=1);
    ++  }
    ++
    ++  p->eStage = 0;
    ++  if( p->rc==SQLITE_OK && p->dbMain==0 ){
    ++    if( !rbuIsVacuum(p) ){
    ++      p->dbMain = rbuOpenDbhandle(p, p->zTarget, 1);
    ++    }else if( p->pRbuFd->pWalFd ){
    ++      if( pbRetry ){
    ++        p->pRbuFd->bNolock = 0;
    ++        sqlite3_close(p->dbRbu);
    ++        sqlite3_close(p->dbMain);
    ++        p->dbMain = 0;
    ++        p->dbRbu = 0;
    ++        *pbRetry = 1;
    ++        return;
    ++      }
    ++      p->rc = SQLITE_ERROR;
    ++      p->zErrmsg = sqlite3_mprintf("cannot vacuum wal mode database");
    ++    }else{
    ++      char *zTarget;
    ++      char *zExtra = 0;
    ++      if( strlen(p->zRbu)>=5 && 0==memcmp("file:", p->zRbu, 5) ){
    ++        zExtra = &p->zRbu[5];
    ++        while( *zExtra ){
    ++          if( *zExtra++=='?' ) break;
    ++        }
    ++        if( *zExtra=='\0' ) zExtra = 0;
    ++      }
    ++
    ++      zTarget = sqlite3_mprintf("file:%s-vacuum?rbu_memory=1%s%s", 
    ++          sqlite3_db_filename(p->dbRbu, "main"),
    ++          (zExtra==0 ? "" : "&"), (zExtra==0 ? "" : zExtra)
    ++      );
    ++
    ++      if( zTarget==0 ){
    ++        p->rc = SQLITE_NOMEM;
    ++        return;
    ++      }
    ++      p->dbMain = rbuOpenDbhandle(p, zTarget, p->nRbu<=1);
    ++      sqlite3_free(zTarget);
    ++    }
    ++  }
    ++
    +   if( p->rc==SQLITE_OK ){
    +     p->rc = sqlite3_create_function(p->dbMain, 
    +         "rbu_tmp_insert", -1, SQLITE_UTF8, (void*)p, rbuTmpInsertFunc, 0, 0
    +@@ -160948,7 +175214,7 @@ static void rbuOpenDatabase(sqlite3rbu *p){
    + 
    +   if( p->rc==SQLITE_OK ){
    +     p->rc = sqlite3_create_function(p->dbRbu, 
    +-        "rbu_target_name", 1, SQLITE_UTF8, (void*)p, rbuTargetNameFunc, 0, 0
    ++        "rbu_target_name", -1, SQLITE_UTF8, (void*)p, rbuTargetNameFunc, 0, 0
    +     );
    +   }
    + 
    +@@ -160997,9 +175263,9 @@ static void rbuFileSuffix3(const char *zBase, char *z){
    + #endif
    +   {
    +     int i, sz;
    +-    sz = sqlite3Strlen30(z);
    ++    sz = (int)strlen(z)&0xffffff;
    +     for(i=sz-1; i>0 && z[i]!='/' && z[i]!='.'; i--){}
    +-    if( z[i]=='.' && ALWAYS(sz>i+4) ) memmove(&z[i+1], &z[sz-3], 4);
    ++    if( z[i]=='.' && sz>i+4 ) memmove(&z[i+1], &z[sz-3], 4);
    +   }
    + #endif
    + }
    +@@ -161087,16 +175353,35 @@ static void rbuSetupCheckpoint(sqlite3rbu *p, RbuState *pState){
    +     if( rc2!=SQLITE_INTERNAL ) p->rc = rc2;
    +   }
    + 
    +-  if( p->rc==SQLITE_OK ){
    ++  if( p->rc==SQLITE_OK && p->nFrame>0 ){
    +     p->eStage = RBU_STAGE_CKPT;
    +     p->nStep = (pState ? pState->nRow : 0);
    +     p->aBuf = rbuMalloc(p, p->pgsz);
    +     p->iWalCksum = rbuShmChecksum(p);
    +   }
    + 
    +-  if( p->rc==SQLITE_OK && pState && pState->iWalCksum!=p->iWalCksum ){
    +-    p->rc = SQLITE_DONE;
    +-    p->eStage = RBU_STAGE_DONE;
    ++  if( p->rc==SQLITE_OK ){
    ++    if( p->nFrame==0 || (pState && pState->iWalCksum!=p->iWalCksum) ){
    ++      p->rc = SQLITE_DONE;
    ++      p->eStage = RBU_STAGE_DONE;
    ++    }else{
    ++      int nSectorSize;
    ++      sqlite3_file *pDb = p->pTargetFd->pReal;
    ++      sqlite3_file *pWal = p->pTargetFd->pWalFd->pReal;
    ++      assert( p->nPagePerSector==0 );
    ++      nSectorSize = pDb->pMethods->xSectorSize(pDb);
    ++      if( nSectorSize>p->pgsz ){
    ++        p->nPagePerSector = nSectorSize / p->pgsz;
    ++      }else{
    ++        p->nPagePerSector = 1;
    ++      }
    ++
    ++      /* Call xSync() on the wal file. This causes SQLite to sync the 
    ++      ** directory in which the target database and the wal file reside, in 
    ++      ** case it has not been synced since the rename() call in 
    ++      ** rbuMoveOalFile(). */
    ++      p->rc = pWal->pMethods->xSync(pWal, SQLITE_SYNC_NORMAL);
    ++    }
    +   }
    + }
    + 
    +@@ -161118,7 +175403,7 @@ static int rbuCaptureWalRead(sqlite3rbu *pRbu, i64 iOff, int iAmt){
    +   if( pRbu->nFrame==pRbu->nFrameAlloc ){
    +     int nNew = (pRbu->nFrameAlloc ? pRbu->nFrameAlloc : 64) * 2;
    +     RbuFrame *aNew;
    +-    aNew = (RbuFrame*)sqlite3_realloc(pRbu->aFrame, nNew * sizeof(RbuFrame));
    ++    aNew = (RbuFrame*)sqlite3_realloc64(pRbu->aFrame, nNew * sizeof(RbuFrame));
    +     if( aNew==0 ) return SQLITE_NOMEM;
    +     pRbu->aFrame = aNew;
    +     pRbu->nFrameAlloc = nNew;
    +@@ -161183,7 +175468,7 @@ static LPWSTR rbuWinUtf8ToUnicode(const char *zFilename){
    +   if( nChar==0 ){
    +     return 0;
    +   }
    +-  zWideFilename = sqlite3_malloc( nChar*sizeof(zWideFilename[0]) );
    ++  zWideFilename = sqlite3_malloc64( nChar*sizeof(zWideFilename[0]) );
    +   if( zWideFilename==0 ){
    +     return 0;
    +   }
    +@@ -161207,9 +175492,15 @@ static LPWSTR rbuWinUtf8ToUnicode(const char *zFilename){
    + */
    + static void rbuMoveOalFile(sqlite3rbu *p){
    +   const char *zBase = sqlite3_db_filename(p->dbMain, "main");
    ++  const char *zMove = zBase;
    ++  char *zOal;
    ++  char *zWal;
    + 
    +-  char *zWal = sqlite3_mprintf("%s-wal", zBase);
    +-  char *zOal = sqlite3_mprintf("%s-oal", zBase);
    ++  if( rbuIsVacuum(p) ){
    ++    zMove = sqlite3_db_filename(p->dbRbu, "main");
    ++  }
    ++  zOal = sqlite3_mprintf("%s-oal", zMove);
    ++  zWal = sqlite3_mprintf("%s-wal", zMove);
    + 
    +   assert( p->eStage==RBU_STAGE_MOVE );
    +   assert( p->rc==SQLITE_OK && p->zErrmsg==0 );
    +@@ -161230,8 +175521,8 @@ static void rbuMoveOalFile(sqlite3rbu *p){
    + 
    +       /* Re-open the databases. */
    +       rbuObjIterFinalize(&p->objiter);
    +-      sqlite3_close(p->dbMain);
    +       sqlite3_close(p->dbRbu);
    ++      sqlite3_close(p->dbMain);
    +       p->dbMain = 0;
    +       p->dbRbu = 0;
    + 
    +@@ -161263,7 +175554,7 @@ static void rbuMoveOalFile(sqlite3rbu *p){
    + #endif
    + 
    +       if( p->rc==SQLITE_OK ){
    +-        rbuOpenDatabase(p);
    ++        rbuOpenDatabase(p, 0);
    +         rbuSetupCheckpoint(p, 0);
    +       }
    +     }
    +@@ -161297,14 +175588,12 @@ static int rbuStepType(sqlite3rbu *p, const char **pzMask){
    +   switch( sqlite3_column_type(p->objiter.pSelect, iCol) ){
    +     case SQLITE_INTEGER: {
    +       int iVal = sqlite3_column_int(p->objiter.pSelect, iCol);
    +-      if( iVal==0 ){
    +-        res = RBU_INSERT;
    +-      }else if( iVal==1 ){
    +-        res = RBU_DELETE;
    +-      }else if( iVal==2 ){
    +-        res = RBU_IDX_DELETE;
    +-      }else if( iVal==3 ){
    +-        res = RBU_IDX_INSERT;
    ++      switch( iVal ){
    ++        case 0: res = RBU_INSERT;     break;
    ++        case 1: res = RBU_DELETE;     break;
    ++        case 2: res = RBU_REPLACE;    break;
    ++        case 3: res = RBU_IDX_DELETE; break;
    ++        case 4: res = RBU_IDX_INSERT; break;
    +       }
    +       break;
    +     }
    +@@ -161343,6 +175632,83 @@ static void assertColumnName(sqlite3_stmt *pStmt, int iCol, const char *zName){
    + # define assertColumnName(x,y,z)
    + #endif
    + 
    ++/*
    ++** Argument eType must be one of RBU_INSERT, RBU_DELETE, RBU_IDX_INSERT or
    ++** RBU_IDX_DELETE. This function performs the work of a single
    ++** sqlite3rbu_step() call for the type of operation specified by eType.
    ++*/
    ++static void rbuStepOneOp(sqlite3rbu *p, int eType){
    ++  RbuObjIter *pIter = &p->objiter;
    ++  sqlite3_value *pVal;
    ++  sqlite3_stmt *pWriter;
    ++  int i;
    ++
    ++  assert( p->rc==SQLITE_OK );
    ++  assert( eType!=RBU_DELETE || pIter->zIdx==0 );
    ++  assert( eType==RBU_DELETE || eType==RBU_IDX_DELETE
    ++       || eType==RBU_INSERT || eType==RBU_IDX_INSERT
    ++  );
    ++
    ++  /* If this is a delete, decrement nPhaseOneStep by nIndex. If the DELETE
    ++  ** statement below does actually delete a row, nPhaseOneStep will be
    ++  ** incremented by the same amount when SQL function rbu_tmp_insert()
    ++  ** is invoked by the trigger.  */
    ++  if( eType==RBU_DELETE ){
    ++    p->nPhaseOneStep -= p->objiter.nIndex;
    ++  }
    ++
    ++  if( eType==RBU_IDX_DELETE || eType==RBU_DELETE ){
    ++    pWriter = pIter->pDelete;
    ++  }else{
    ++    pWriter = pIter->pInsert;
    ++  }
    ++
    ++  for(i=0; i<pIter->nCol; i++){
    ++    /* If this is an INSERT into a table b-tree and the table has an
    ++    ** explicit INTEGER PRIMARY KEY, check that this is not an attempt
    ++    ** to write a NULL into the IPK column. That is not permitted.  */
    ++    if( eType==RBU_INSERT 
    ++     && pIter->zIdx==0 && pIter->eType==RBU_PK_IPK && pIter->abTblPk[i] 
    ++     && sqlite3_column_type(pIter->pSelect, i)==SQLITE_NULL
    ++    ){
    ++      p->rc = SQLITE_MISMATCH;
    ++      p->zErrmsg = sqlite3_mprintf("datatype mismatch");
    ++      return;
    ++    }
    ++
    ++    if( eType==RBU_DELETE && pIter->abTblPk[i]==0 ){
    ++      continue;
    ++    }
    ++
    ++    pVal = sqlite3_column_value(pIter->pSelect, i);
    ++    p->rc = sqlite3_bind_value(pWriter, i+1, pVal);
    ++    if( p->rc ) return;
    ++  }
    ++  if( pIter->zIdx==0 ){
    ++    if( pIter->eType==RBU_PK_VTAB 
    ++     || pIter->eType==RBU_PK_NONE 
    ++     || (pIter->eType==RBU_PK_EXTERNAL && rbuIsVacuum(p)) 
    ++    ){
    ++      /* For a virtual table, or a table with no primary key, the 
    ++      ** SELECT statement is:
    ++      **
    ++      **   SELECT <cols>, rbu_control, rbu_rowid FROM ....
    ++      **
    ++      ** Hence column_value(pIter->nCol+1).
    ++      */
    ++      assertColumnName(pIter->pSelect, pIter->nCol+1, 
    ++          rbuIsVacuum(p) ? "rowid" : "rbu_rowid"
    ++      );
    ++      pVal = sqlite3_column_value(pIter->pSelect, pIter->nCol+1);
    ++      p->rc = sqlite3_bind_value(pWriter, pIter->nCol+1, pVal);
    ++    }
    ++  }
    ++  if( p->rc==SQLITE_OK ){
    ++    sqlite3_step(pWriter);
    ++    p->rc = resetAndCollectError(pWriter, &p->zErrmsg);
    ++  }
    ++}
    ++
    + /*
    + ** This function does the work for an sqlite3rbu_step() call.
    + **
    +@@ -161357,78 +175723,36 @@ static void assertColumnName(sqlite3_stmt *pStmt, int iCol, const char *zName){
    + static int rbuStep(sqlite3rbu *p){
    +   RbuObjIter *pIter = &p->objiter;
    +   const char *zMask = 0;
    +-  int i;
    +   int eType = rbuStepType(p, &zMask);
    + 
    +   if( eType ){
    ++    assert( eType==RBU_INSERT     || eType==RBU_DELETE
    ++         || eType==RBU_REPLACE    || eType==RBU_IDX_DELETE
    ++         || eType==RBU_IDX_INSERT || eType==RBU_UPDATE
    ++    );
    +     assert( eType!=RBU_UPDATE || pIter->zIdx==0 );
    + 
    +-    if( pIter->zIdx==0 && eType==RBU_IDX_DELETE ){
    ++    if( pIter->zIdx==0 && (eType==RBU_IDX_DELETE || eType==RBU_IDX_INSERT) ){
    +       rbuBadControlError(p);
    +     }
    +-    else if( 
    +-        eType==RBU_INSERT 
    +-     || eType==RBU_DELETE
    +-     || eType==RBU_IDX_DELETE 
    +-     || eType==RBU_IDX_INSERT
    +-    ){
    +-      sqlite3_value *pVal;
    +-      sqlite3_stmt *pWriter;
    +-
    +-      assert( eType!=RBU_UPDATE );
    +-      assert( eType!=RBU_DELETE || pIter->zIdx==0 );
    +-
    +-      if( eType==RBU_IDX_DELETE || eType==RBU_DELETE ){
    +-        pWriter = pIter->pDelete;
    +-      }else{
    +-        pWriter = pIter->pInsert;
    +-      }
    +-
    +-      for(i=0; i<pIter->nCol; i++){
    +-        /* If this is an INSERT into a table b-tree and the table has an
    +-        ** explicit INTEGER PRIMARY KEY, check that this is not an attempt
    +-        ** to write a NULL into the IPK column. That is not permitted.  */
    +-        if( eType==RBU_INSERT 
    +-         && pIter->zIdx==0 && pIter->eType==RBU_PK_IPK && pIter->abTblPk[i] 
    +-         && sqlite3_column_type(pIter->pSelect, i)==SQLITE_NULL
    +-        ){
    +-          p->rc = SQLITE_MISMATCH;
    +-          p->zErrmsg = sqlite3_mprintf("datatype mismatch");
    +-          goto step_out;
    +-        }
    +-
    +-        if( eType==RBU_DELETE && pIter->abTblPk[i]==0 ){
    +-          continue;
    +-        }
    +-
    +-        pVal = sqlite3_column_value(pIter->pSelect, i);
    +-        p->rc = sqlite3_bind_value(pWriter, i+1, pVal);
    +-        if( p->rc ) goto step_out;
    +-      }
    +-      if( pIter->zIdx==0
    +-       && (pIter->eType==RBU_PK_VTAB || pIter->eType==RBU_PK_NONE) 
    +-      ){
    +-        /* For a virtual table, or a table with no primary key, the 
    +-        ** SELECT statement is:
    +-        **
    +-        **   SELECT <cols>, rbu_control, rbu_rowid FROM ....
    +-        **
    +-        ** Hence column_value(pIter->nCol+1).
    +-        */
    +-        assertColumnName(pIter->pSelect, pIter->nCol+1, "rbu_rowid");
    +-        pVal = sqlite3_column_value(pIter->pSelect, pIter->nCol+1);
    +-        p->rc = sqlite3_bind_value(pWriter, pIter->nCol+1, pVal);
    ++    else if( eType==RBU_REPLACE ){
    ++      if( pIter->zIdx==0 ){
    ++        p->nPhaseOneStep += p->objiter.nIndex;
    ++        rbuStepOneOp(p, RBU_DELETE);
    +       }
    +-      if( p->rc==SQLITE_OK ){
    +-        sqlite3_step(pWriter);
    +-        p->rc = resetAndCollectError(pWriter, &p->zErrmsg);
    +-      }
    +-    }else{
    ++      if( p->rc==SQLITE_OK ) rbuStepOneOp(p, RBU_INSERT);
    ++    }
    ++    else if( eType!=RBU_UPDATE ){
    ++      rbuStepOneOp(p, eType);
    ++    }
    ++    else{
    +       sqlite3_value *pVal;
    +       sqlite3_stmt *pUpdate = 0;
    +       assert( eType==RBU_UPDATE );
    ++      p->nPhaseOneStep -= p->objiter.nIndex;
    +       rbuGetUpdateStmt(p, pIter, zMask, &pUpdate);
    +       if( pUpdate ){
    ++        int i;
    +         for(i=0; p->rc==SQLITE_OK && i<pIter->nCol; i++){
    +           char c = zMask[pIter->aiSrcOrder[i]];
    +           pVal = sqlite3_column_value(pIter->pSelect, i);
    +@@ -161451,20 +175775,23 @@ static int rbuStep(sqlite3rbu *p){
    +       }
    +     }
    +   }
    +-
    +- step_out:
    +   return p->rc;
    + }
    + 
    + /*
    + ** Increment the schema cookie of the main database opened by p->dbMain.
    ++**
    ++** Or, if this is an RBU vacuum, set the schema cookie of the main db
    ++** opened by p->dbMain to one more than the schema cookie of the main
    ++** db opened by p->dbRbu.
    + */
    + static void rbuIncrSchemaCookie(sqlite3rbu *p){
    +   if( p->rc==SQLITE_OK ){
    ++    sqlite3 *dbread = (rbuIsVacuum(p) ? p->dbRbu : p->dbMain);
    +     int iCookie = 1000000;
    +     sqlite3_stmt *pStmt;
    + 
    +-    p->rc = prepareAndCollectError(p->dbMain, &pStmt, &p->zErrmsg, 
    ++    p->rc = prepareAndCollectError(dbread, &pStmt, &p->zErrmsg, 
    +         "PRAGMA schema_version"
    +     );
    +     if( p->rc==SQLITE_OK ){
    +@@ -161492,6 +175819,7 @@ static void rbuIncrSchemaCookie(sqlite3rbu *p){
    + static void rbuSaveState(sqlite3rbu *p, int eStage){
    +   if( p->rc==SQLITE_OK || p->rc==SQLITE_DONE ){
    +     sqlite3_stmt *pInsert = 0;
    ++    rbu_file *pFd = (rbuIsVacuum(p) ? p->pRbuFd : p->pTargetFd);
    +     int rc;
    + 
    +     assert( p->zErrmsg==0 );
    +@@ -161505,6 +175833,7 @@ static void rbuSaveState(sqlite3rbu *p, int eStage){
    +           "(%d, %d), "
    +           "(%d, %lld), "
    +           "(%d, %lld), "
    ++          "(%d, %lld), "
    +           "(%d, %lld) ",
    +           p->zStateDb,
    +           RBU_STATE_STAGE, eStage,
    +@@ -161513,8 +175842,9 @@ static void rbuSaveState(sqlite3rbu *p, int eStage){
    +           RBU_STATE_ROW, p->nStep, 
    +           RBU_STATE_PROGRESS, p->nProgress,
    +           RBU_STATE_CKPT, p->iWalCksum,
    +-          RBU_STATE_COOKIE, (i64)p->pTargetFd->iCookie,
    +-          RBU_STATE_OALSZ, p->iOalSz
    ++          RBU_STATE_COOKIE, (i64)pFd->iCookie,
    ++          RBU_STATE_OALSZ, p->iOalSz,
    ++          RBU_STATE_PHASEONESTEP, p->nPhaseOneStep
    +       )
    +     );
    +     assert( pInsert==0 || rc==SQLITE_OK );
    +@@ -161528,21 +175858,116 @@ static void rbuSaveState(sqlite3rbu *p, int eStage){
    + }
    + 
    + 
    ++/*
    ++** The second argument passed to this function is the name of a PRAGMA 
    ++** setting - "page_size", "auto_vacuum", "user_version" or "application_id".
    ++** This function executes the following on sqlite3rbu.dbRbu:
    ++**
    ++**   "PRAGMA main.$zPragma"
    ++**
    ++** where $zPragma is the string passed as the second argument, then
    ++** on sqlite3rbu.dbMain:
    ++**
    ++**   "PRAGMA main.$zPragma = $val"
    ++**
    ++** where $val is the value returned by the first PRAGMA invocation.
    ++**
    ++** In short, it copies the value  of the specified PRAGMA setting from
    ++** dbRbu to dbMain.
    ++*/
    ++static void rbuCopyPragma(sqlite3rbu *p, const char *zPragma){
    ++  if( p->rc==SQLITE_OK ){
    ++    sqlite3_stmt *pPragma = 0;
    ++    p->rc = prepareFreeAndCollectError(p->dbRbu, &pPragma, &p->zErrmsg, 
    ++        sqlite3_mprintf("PRAGMA main.%s", zPragma)
    ++    );
    ++    if( p->rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pPragma) ){
    ++      p->rc = rbuMPrintfExec(p, p->dbMain, "PRAGMA main.%s = %d",
    ++          zPragma, sqlite3_column_int(pPragma, 0)
    ++      );
    ++    }
    ++    rbuFinalize(p, pPragma);
    ++  }
    ++}
    ++
    ++/*
    ++** The RBU handle passed as the only argument has just been opened and 
    ++** the state database is empty. If this RBU handle was opened for an
    ++** RBU vacuum operation, create the schema in the target db.
    ++*/
    ++static void rbuCreateTargetSchema(sqlite3rbu *p){
    ++  sqlite3_stmt *pSql = 0;
    ++  sqlite3_stmt *pInsert = 0;
    ++
    ++  assert( rbuIsVacuum(p) );
    ++  p->rc = sqlite3_exec(p->dbMain, "PRAGMA writable_schema=1", 0,0, &p->zErrmsg);
    ++  if( p->rc==SQLITE_OK ){
    ++    p->rc = prepareAndCollectError(p->dbRbu, &pSql, &p->zErrmsg, 
    ++      "SELECT sql FROM sqlite_master WHERE sql!='' AND rootpage!=0"
    ++      " AND name!='sqlite_sequence' "
    ++      " ORDER BY type DESC"
    ++    );
    ++  }
    ++
    ++  while( p->rc==SQLITE_OK && sqlite3_step(pSql)==SQLITE_ROW ){
    ++    const char *zSql = (const char*)sqlite3_column_text(pSql, 0);
    ++    p->rc = sqlite3_exec(p->dbMain, zSql, 0, 0, &p->zErrmsg);
    ++  }
    ++  rbuFinalize(p, pSql);
    ++  if( p->rc!=SQLITE_OK ) return;
    ++
    ++  if( p->rc==SQLITE_OK ){
    ++    p->rc = prepareAndCollectError(p->dbRbu, &pSql, &p->zErrmsg, 
    ++        "SELECT * FROM sqlite_master WHERE rootpage=0 OR rootpage IS NULL" 
    ++    );
    ++  }
    ++
    ++  if( p->rc==SQLITE_OK ){
    ++    p->rc = prepareAndCollectError(p->dbMain, &pInsert, &p->zErrmsg, 
    ++        "INSERT INTO sqlite_master VALUES(?,?,?,?,?)"
    ++    );
    ++  }
    ++
    ++  while( p->rc==SQLITE_OK && sqlite3_step(pSql)==SQLITE_ROW ){
    ++    int i;
    ++    for(i=0; i<5; i++){
    ++      sqlite3_bind_value(pInsert, i+1, sqlite3_column_value(pSql, i));
    ++    }
    ++    sqlite3_step(pInsert);
    ++    p->rc = sqlite3_reset(pInsert);
    ++  }
    ++  if( p->rc==SQLITE_OK ){
    ++    p->rc = sqlite3_exec(p->dbMain, "PRAGMA writable_schema=0",0,0,&p->zErrmsg);
    ++  }
    ++
    ++  rbuFinalize(p, pSql);
    ++  rbuFinalize(p, pInsert);
    ++}
    ++
    + /*
    + ** Step the RBU object.
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3rbu_step(sqlite3rbu *p){
    ++SQLITE_API int sqlite3rbu_step(sqlite3rbu *p){
    +   if( p ){
    +     switch( p->eStage ){
    +       case RBU_STAGE_OAL: {
    +         RbuObjIter *pIter = &p->objiter;
    ++
    ++        /* If this is an RBU vacuum operation and the state table was empty
    ++        ** when this handle was opened, create the target database schema. */
    ++        if( rbuIsVacuum(p) && p->nProgress==0 && p->rc==SQLITE_OK ){
    ++          rbuCreateTargetSchema(p);
    ++          rbuCopyPragma(p, "user_version");
    ++          rbuCopyPragma(p, "application_id");
    ++        }
    ++
    +         while( p->rc==SQLITE_OK && pIter->zTbl ){
    + 
    +           if( pIter->bCleanup ){
    +             /* Clean up the rbu_tmp_xxx table for the previous table. It 
    +             ** cannot be dropped as there are currently active SQL statements.
    +             ** But the contents can be deleted.  */
    +-            if( pIter->abIndexed ){
    ++            if( rbuIsVacuum(p)==0 && pIter->abIndexed ){
    +               rbuMPrintfExec(p, p->dbRbu, 
    +                   "DELETE FROM %s.'rbu_tmp_%q'", p->zStateDb, pIter->zDataTbl
    +               );
    +@@ -161611,9 +176036,26 @@ SQLITE_API int SQLITE_STDCALL sqlite3rbu_step(sqlite3rbu *p){
    +               p->rc = SQLITE_DONE;
    +             }
    +           }else{
    +-            RbuFrame *pFrame = &p->aFrame[p->nStep];
    +-            rbuCheckpointFrame(p, pFrame);
    +-            p->nStep++;
    ++            /* At one point the following block copied a single frame from the
    ++            ** wal file to the database file. So that one call to sqlite3rbu_step()
    ++            ** checkpointed a single frame. 
    ++            **
    ++            ** However, if the sector-size is larger than the page-size, and the
    ++            ** application calls sqlite3rbu_savestate() or close() immediately
    ++            ** after this step, then rbu_step() again, then a power failure occurs,
    ++            ** then the database page written here may be damaged. Work around
    ++            ** this by checkpointing frames until the next page in the aFrame[]
    ++            ** lies on a different disk sector to the current one. */
    ++            u32 iSector;
    ++            do{
    ++              RbuFrame *pFrame = &p->aFrame[p->nStep];
    ++              iSector = (pFrame->iDbPage-1) / p->nPagePerSector;
    ++              rbuCheckpointFrame(p, pFrame);
    ++              p->nStep++;
    ++            }while( p->nStep<p->nFrame 
    ++                 && iSector==((p->aFrame[p->nStep].iDbPage-1) / p->nPagePerSector)
    ++                 && p->rc==SQLITE_OK
    ++            );
    +           }
    +           p->nProgress++;
    +         }
    +@@ -161629,90 +176071,6 @@ SQLITE_API int SQLITE_STDCALL sqlite3rbu_step(sqlite3rbu *p){
    +   }
    + }
    + 
    +-/*
    +-** Free an RbuState object allocated by rbuLoadState().
    +-*/
    +-static void rbuFreeState(RbuState *p){
    +-  if( p ){
    +-    sqlite3_free(p->zTbl);
    +-    sqlite3_free(p->zIdx);
    +-    sqlite3_free(p);
    +-  }
    +-}
    +-
    +-/*
    +-** Allocate an RbuState object and load the contents of the rbu_state 
    +-** table into it. Return a pointer to the new object. It is the 
    +-** responsibility of the caller to eventually free the object using
    +-** sqlite3_free().
    +-**
    +-** If an error occurs, leave an error code and message in the rbu handle
    +-** and return NULL.
    +-*/
    +-static RbuState *rbuLoadState(sqlite3rbu *p){
    +-  RbuState *pRet = 0;
    +-  sqlite3_stmt *pStmt = 0;
    +-  int rc;
    +-  int rc2;
    +-
    +-  pRet = (RbuState*)rbuMalloc(p, sizeof(RbuState));
    +-  if( pRet==0 ) return 0;
    +-
    +-  rc = prepareFreeAndCollectError(p->dbRbu, &pStmt, &p->zErrmsg, 
    +-      sqlite3_mprintf("SELECT k, v FROM %s.rbu_state", p->zStateDb)
    +-  );
    +-  while( rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pStmt) ){
    +-    switch( sqlite3_column_int(pStmt, 0) ){
    +-      case RBU_STATE_STAGE:
    +-        pRet->eStage = sqlite3_column_int(pStmt, 1);
    +-        if( pRet->eStage!=RBU_STAGE_OAL
    +-         && pRet->eStage!=RBU_STAGE_MOVE
    +-         && pRet->eStage!=RBU_STAGE_CKPT
    +-        ){
    +-          p->rc = SQLITE_CORRUPT;
    +-        }
    +-        break;
    +-
    +-      case RBU_STATE_TBL:
    +-        pRet->zTbl = rbuStrndup((char*)sqlite3_column_text(pStmt, 1), &rc);
    +-        break;
    +-
    +-      case RBU_STATE_IDX:
    +-        pRet->zIdx = rbuStrndup((char*)sqlite3_column_text(pStmt, 1), &rc);
    +-        break;
    +-
    +-      case RBU_STATE_ROW:
    +-        pRet->nRow = sqlite3_column_int(pStmt, 1);
    +-        break;
    +-
    +-      case RBU_STATE_PROGRESS:
    +-        pRet->nProgress = sqlite3_column_int64(pStmt, 1);
    +-        break;
    +-
    +-      case RBU_STATE_CKPT:
    +-        pRet->iWalCksum = sqlite3_column_int64(pStmt, 1);
    +-        break;
    +-
    +-      case RBU_STATE_COOKIE:
    +-        pRet->iCookie = (u32)sqlite3_column_int64(pStmt, 1);
    +-        break;
    +-
    +-      case RBU_STATE_OALSZ:
    +-        pRet->iOalSz = (u32)sqlite3_column_int64(pStmt, 1);
    +-        break;
    +-
    +-      default:
    +-        rc = SQLITE_CORRUPT;
    +-        break;
    +-    }
    +-  }
    +-  rc2 = sqlite3_finalize(pStmt);
    +-  if( rc==SQLITE_OK ) rc = rc2;
    +-
    +-  p->rc = rc;
    +-  return pRet;
    +-}
    +-
    + /*
    + ** Compare strings z1 and z2, returning 0 if they are identical, or non-zero
    + ** otherwise. Either or both argument may be NULL. Two NULL values are
    +@@ -161794,6 +176152,7 @@ static void rbuCreateVfs(sqlite3rbu *p){
    +     sqlite3_vfs *pVfs = sqlite3_vfs_find(zRnd);
    +     assert( pVfs );
    +     p->zVfsName = pVfs->zName;
    ++    ((rbu_vfs*)pVfs)->pRbu = p;
    +   }
    + }
    + 
    +@@ -161809,19 +176168,111 @@ static void rbuDeleteVfs(sqlite3rbu *p){
    + }
    + 
    + /*
    +-** Open and return a new RBU handle. 
    ++** This user-defined SQL function is invoked with a single argument - the
    ++** name of a table expected to appear in the target database. It returns
    ++** the number of auxilliary indexes on the table.
    + */
    +-SQLITE_API sqlite3rbu *SQLITE_STDCALL sqlite3rbu_open(
    ++static void rbuIndexCntFunc(
    ++  sqlite3_context *pCtx, 
    ++  int nVal,
    ++  sqlite3_value **apVal
    ++){
    ++  sqlite3rbu *p = (sqlite3rbu*)sqlite3_user_data(pCtx);
    ++  sqlite3_stmt *pStmt = 0;
    ++  char *zErrmsg = 0;
    ++  int rc;
    ++
    ++  assert( nVal==1 );
    ++  
    ++  rc = prepareFreeAndCollectError(p->dbMain, &pStmt, &zErrmsg, 
    ++      sqlite3_mprintf("SELECT count(*) FROM sqlite_master "
    ++        "WHERE type='index' AND tbl_name = %Q", sqlite3_value_text(apVal[0]))
    ++  );
    ++  if( rc!=SQLITE_OK ){
    ++    sqlite3_result_error(pCtx, zErrmsg, -1);
    ++  }else{
    ++    int nIndex = 0;
    ++    if( SQLITE_ROW==sqlite3_step(pStmt) ){
    ++      nIndex = sqlite3_column_int(pStmt, 0);
    ++    }
    ++    rc = sqlite3_finalize(pStmt);
    ++    if( rc==SQLITE_OK ){
    ++      sqlite3_result_int(pCtx, nIndex);
    ++    }else{
    ++      sqlite3_result_error(pCtx, sqlite3_errmsg(p->dbMain), -1);
    ++    }
    ++  }
    ++
    ++  sqlite3_free(zErrmsg);
    ++}
    ++
    ++/*
    ++** If the RBU database contains the rbu_count table, use it to initialize
    ++** the sqlite3rbu.nPhaseOneStep variable. The schema of the rbu_count table
    ++** is assumed to contain the same columns as:
    ++**
    ++**   CREATE TABLE rbu_count(tbl TEXT PRIMARY KEY, cnt INTEGER) WITHOUT ROWID;
    ++**
    ++** There should be one row in the table for each data_xxx table in the
    ++** database. The 'tbl' column should contain the name of a data_xxx table,
    ++** and the cnt column the number of rows it contains.
    ++**
    ++** sqlite3rbu.nPhaseOneStep is initialized to the sum of (1 + nIndex) * cnt
    ++** for all rows in the rbu_count table, where nIndex is the number of 
    ++** indexes on the corresponding target database table.
    ++*/
    ++static void rbuInitPhaseOneSteps(sqlite3rbu *p){
    ++  if( p->rc==SQLITE_OK ){
    ++    sqlite3_stmt *pStmt = 0;
    ++    int bExists = 0;                /* True if rbu_count exists */
    ++
    ++    p->nPhaseOneStep = -1;
    ++
    ++    p->rc = sqlite3_create_function(p->dbRbu, 
    ++        "rbu_index_cnt", 1, SQLITE_UTF8, (void*)p, rbuIndexCntFunc, 0, 0
    ++    );
    ++  
    ++    /* Check for the rbu_count table. If it does not exist, or if an error
    ++    ** occurs, nPhaseOneStep will be left set to -1. */
    ++    if( p->rc==SQLITE_OK ){
    ++      p->rc = prepareAndCollectError(p->dbRbu, &pStmt, &p->zErrmsg,
    ++          "SELECT 1 FROM sqlite_master WHERE tbl_name = 'rbu_count'"
    ++      );
    ++    }
    ++    if( p->rc==SQLITE_OK ){
    ++      if( SQLITE_ROW==sqlite3_step(pStmt) ){
    ++        bExists = 1;
    ++      }
    ++      p->rc = sqlite3_finalize(pStmt);
    ++    }
    ++  
    ++    if( p->rc==SQLITE_OK && bExists ){
    ++      p->rc = prepareAndCollectError(p->dbRbu, &pStmt, &p->zErrmsg,
    ++          "SELECT sum(cnt * (1 + rbu_index_cnt(rbu_target_name(tbl))))"
    ++          "FROM rbu_count"
    ++      );
    ++      if( p->rc==SQLITE_OK ){
    ++        if( SQLITE_ROW==sqlite3_step(pStmt) ){
    ++          p->nPhaseOneStep = sqlite3_column_int64(pStmt, 0);
    ++        }
    ++        p->rc = sqlite3_finalize(pStmt);
    ++      }
    ++    }
    ++  }
    ++}
    ++
    ++
    ++static sqlite3rbu *openRbuHandle(
    +   const char *zTarget, 
    +   const char *zRbu,
    +   const char *zState
    + ){
    +   sqlite3rbu *p;
    +-  int nTarget = strlen(zTarget);
    +-  int nRbu = strlen(zRbu);
    +-  int nState = zState ? strlen(zState) : 0;
    ++  size_t nTarget = zTarget ? strlen(zTarget) : 0;
    ++  size_t nRbu = strlen(zRbu);
    ++  size_t nByte = sizeof(sqlite3rbu) + nTarget+1 + nRbu+1;
    + 
    +-  p = (sqlite3rbu*)sqlite3_malloc(sizeof(sqlite3rbu)+nTarget+1+nRbu+1+nState+1);
    ++  p = (sqlite3rbu*)sqlite3_malloc64(nByte);
    +   if( p ){
    +     RbuState *pState = 0;
    + 
    +@@ -161829,21 +176280,34 @@ SQLITE_API sqlite3rbu *SQLITE_STDCALL sqlite3rbu_open(
    +     memset(p, 0, sizeof(sqlite3rbu));
    +     rbuCreateVfs(p);
    + 
    +-    /* Open the target database */
    ++    /* Open the target, RBU and state databases */
    +     if( p->rc==SQLITE_OK ){
    +-      p->zTarget = (char*)&p[1];
    +-      memcpy(p->zTarget, zTarget, nTarget+1);
    +-      p->zRbu = &p->zTarget[nTarget+1];
    ++      char *pCsr = (char*)&p[1];
    ++      int bRetry = 0;
    ++      if( zTarget ){
    ++        p->zTarget = pCsr;
    ++        memcpy(p->zTarget, zTarget, nTarget+1);
    ++        pCsr += nTarget+1;
    ++      }
    ++      p->zRbu = pCsr;
    +       memcpy(p->zRbu, zRbu, nRbu+1);
    ++      pCsr += nRbu+1;
    +       if( zState ){
    +-        p->zState = &p->zRbu[nRbu+1];
    +-        memcpy(p->zState, zState, nState+1);
    ++        p->zState = rbuMPrintf(p, "%s", zState);
    +       }
    +-      rbuOpenDatabase(p);
    +-    }
    + 
    +-    /* If it has not already been created, create the rbu_state table */
    +-    rbuMPrintfExec(p, p->dbRbu, RBU_CREATE_STATE, p->zStateDb);
    ++      /* If the first attempt to open the database file fails and the bRetry
    ++      ** flag it set, this means that the db was not opened because it seemed
    ++      ** to be a wal-mode db. But, this may have happened due to an earlier
    ++      ** RBU vacuum operation leaving an old wal file in the directory.
    ++      ** If this is the case, it will have been checkpointed and deleted
    ++      ** when the handle was closed and a second attempt to open the 
    ++      ** database may succeed.  */
    ++      rbuOpenDatabase(p, &bRetry);
    ++      if( bRetry ){
    ++        rbuOpenDatabase(p, 0);
    ++      }
    ++    }
    + 
    +     if( p->rc==SQLITE_OK ){
    +       pState = rbuLoadState(p);
    +@@ -161852,9 +176316,11 @@ SQLITE_API sqlite3rbu *SQLITE_STDCALL sqlite3rbu_open(
    + 
    +         if( pState->eStage==0 ){ 
    +           rbuDeleteOalFile(p);
    ++          rbuInitPhaseOneSteps(p);
    +           p->eStage = RBU_STAGE_OAL;
    +         }else{
    +           p->eStage = pState->eStage;
    ++          p->nPhaseOneStep = pState->nPhaseOneStep;
    +         }
    +         p->nProgress = pState->nProgress;
    +         p->iOalSz = pState->iOalSz;
    +@@ -161872,38 +176338,27 @@ SQLITE_API sqlite3rbu *SQLITE_STDCALL sqlite3rbu_open(
    +       }
    +     }
    + 
    +-    if( p->rc==SQLITE_OK
    ++    if( p->rc==SQLITE_OK 
    +      && (p->eStage==RBU_STAGE_OAL || p->eStage==RBU_STAGE_MOVE)
    +-     && pState->eStage!=0 && p->pTargetFd->iCookie!=pState->iCookie
    +-    ){   
    +-      /* At this point (pTargetFd->iCookie) contains the value of the
    +-      ** change-counter cookie (the thing that gets incremented when a 
    +-      ** transaction is committed in rollback mode) currently stored on 
    +-      ** page 1 of the database file. */
    +-      p->rc = SQLITE_BUSY;
    +-      p->zErrmsg = sqlite3_mprintf("database modified during rbu update");
    ++     && pState->eStage!=0
    ++    ){
    ++      rbu_file *pFd = (rbuIsVacuum(p) ? p->pRbuFd : p->pTargetFd);
    ++      if( pFd->iCookie!=pState->iCookie ){   
    ++        /* At this point (pTargetFd->iCookie) contains the value of the
    ++        ** change-counter cookie (the thing that gets incremented when a 
    ++        ** transaction is committed in rollback mode) currently stored on 
    ++        ** page 1 of the database file. */
    ++        p->rc = SQLITE_BUSY;
    ++        p->zErrmsg = sqlite3_mprintf("database modified during rbu %s",
    ++            (rbuIsVacuum(p) ? "vacuum" : "update")
    ++        );
    ++      }
    +     }
    + 
    +     if( p->rc==SQLITE_OK ){
    +       if( p->eStage==RBU_STAGE_OAL ){
    +         sqlite3 *db = p->dbMain;
    +-
    +-        /* Open transactions both databases. The *-oal file is opened or
    +-        ** created at this point. */
    +-        p->rc = sqlite3_exec(db, "BEGIN IMMEDIATE", 0, 0, &p->zErrmsg);
    +-        if( p->rc==SQLITE_OK ){
    +-          p->rc = sqlite3_exec(p->dbRbu, "BEGIN IMMEDIATE", 0, 0, &p->zErrmsg);
    +-        }
    +-
    +-        /* Check if the main database is a zipvfs db. If it is, set the upper
    +-        ** level pager to use "journal_mode=off". This prevents it from 
    +-        ** generating a large journal using a temp file.  */
    +-        if( p->rc==SQLITE_OK ){
    +-          int frc = sqlite3_file_control(db, "main", SQLITE_FCNTL_ZIPVFS, 0);
    +-          if( frc==SQLITE_OK ){
    +-            p->rc = sqlite3_exec(db, "PRAGMA journal_mode=off",0,0,&p->zErrmsg);
    +-          }
    +-        }
    ++        p->rc = sqlite3_exec(p->dbRbu, "BEGIN", 0, 0, &p->zErrmsg);
    + 
    +         /* Point the object iterator at the first object */
    +         if( p->rc==SQLITE_OK ){
    +@@ -161914,12 +176369,34 @@ SQLITE_API sqlite3rbu *SQLITE_STDCALL sqlite3rbu_open(
    +         ** update finished.  */
    +         if( p->rc==SQLITE_OK && p->objiter.zTbl==0 ){
    +           p->rc = SQLITE_DONE;
    +-        }
    ++          p->eStage = RBU_STAGE_DONE;
    ++        }else{
    ++          if( p->rc==SQLITE_OK && pState->eStage==0 && rbuIsVacuum(p) ){
    ++            rbuCopyPragma(p, "page_size");
    ++            rbuCopyPragma(p, "auto_vacuum");
    ++          }
    + 
    +-        if( p->rc==SQLITE_OK ){
    +-          rbuSetupOal(p, pState);
    +-        }
    ++          /* Open transactions both databases. The *-oal file is opened or
    ++          ** created at this point. */
    ++          if( p->rc==SQLITE_OK ){
    ++            p->rc = sqlite3_exec(db, "BEGIN IMMEDIATE", 0, 0, &p->zErrmsg);
    ++          }
    ++
    ++          /* Check if the main database is a zipvfs db. If it is, set the upper
    ++          ** level pager to use "journal_mode=off". This prevents it from 
    ++          ** generating a large journal using a temp file.  */
    ++          if( p->rc==SQLITE_OK ){
    ++            int frc = sqlite3_file_control(db, "main", SQLITE_FCNTL_ZIPVFS, 0);
    ++            if( frc==SQLITE_OK ){
    ++              p->rc = sqlite3_exec(
    ++                db, "PRAGMA journal_mode=off",0,0,&p->zErrmsg);
    ++            }
    ++          }
    + 
    ++          if( p->rc==SQLITE_OK ){
    ++            rbuSetupOal(p, pState);
    ++          }
    ++        }
    +       }else if( p->eStage==RBU_STAGE_MOVE ){
    +         /* no-op */
    +       }else if( p->eStage==RBU_STAGE_CKPT ){
    +@@ -161937,11 +176414,49 @@ SQLITE_API sqlite3rbu *SQLITE_STDCALL sqlite3rbu_open(
    +   return p;
    + }
    + 
    ++/*
    ++** Allocate and return an RBU handle with all fields zeroed except for the
    ++** error code, which is set to SQLITE_MISUSE.
    ++*/
    ++static sqlite3rbu *rbuMisuseError(void){
    ++  sqlite3rbu *pRet;
    ++  pRet = sqlite3_malloc64(sizeof(sqlite3rbu));
    ++  if( pRet ){
    ++    memset(pRet, 0, sizeof(sqlite3rbu));
    ++    pRet->rc = SQLITE_MISUSE;
    ++  }
    ++  return pRet;
    ++}
    ++
    ++/*
    ++** Open and return a new RBU handle. 
    ++*/
    ++SQLITE_API sqlite3rbu *sqlite3rbu_open(
    ++  const char *zTarget, 
    ++  const char *zRbu,
    ++  const char *zState
    ++){
    ++  if( zTarget==0 || zRbu==0 ){ return rbuMisuseError(); }
    ++  /* TODO: Check that zTarget and zRbu are non-NULL */
    ++  return openRbuHandle(zTarget, zRbu, zState);
    ++}
    ++
    ++/*
    ++** Open a handle to begin or resume an RBU VACUUM operation.
    ++*/
    ++SQLITE_API sqlite3rbu *sqlite3rbu_vacuum(
    ++  const char *zTarget, 
    ++  const char *zState
    ++){
    ++  if( zTarget==0 ){ return rbuMisuseError(); }
    ++  /* TODO: Check that both arguments are non-NULL */
    ++  return openRbuHandle(0, zTarget, zState);
    ++}
    + 
    + /*
    + ** Return the database handle used by pRbu.
    + */
    +-SQLITE_API sqlite3 *SQLITE_STDCALL sqlite3rbu_db(sqlite3rbu *pRbu, int bRbu){
    ++SQLITE_API sqlite3 *sqlite3rbu_db(sqlite3rbu *pRbu, int bRbu){
    +   sqlite3 *db = 0;
    +   if( pRbu ){
    +     db = (bRbu ? pRbu->dbRbu : pRbu->dbMain);
    +@@ -161957,8 +176472,8 @@ SQLITE_API sqlite3 *SQLITE_STDCALL sqlite3rbu_db(sqlite3rbu *pRbu, int bRbu){
    + */
    + static void rbuEditErrmsg(sqlite3rbu *p){
    +   if( p->rc==SQLITE_CONSTRAINT && p->zErrmsg ){
    +-    int i;
    +-    int nErrmsg = strlen(p->zErrmsg);
    ++    unsigned int i;
    ++    size_t nErrmsg = strlen(p->zErrmsg);
    +     for(i=0; i<(nErrmsg-8); i++){
    +       if( memcmp(&p->zErrmsg[i], "rbu_imp_", 8)==0 ){
    +         int nDel = 8;
    +@@ -161973,7 +176488,7 @@ static void rbuEditErrmsg(sqlite3rbu *p){
    + /*
    + ** Close the RBU handle.
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3rbu_close(sqlite3rbu *p, char **pzErrmsg){
    ++SQLITE_API int sqlite3rbu_close(sqlite3rbu *p, char **pzErrmsg){
    +   int rc;
    +   if( p ){
    + 
    +@@ -161982,6 +176497,12 @@ SQLITE_API int SQLITE_STDCALL sqlite3rbu_close(sqlite3rbu *p, char **pzErrmsg){
    +       p->rc = sqlite3_exec(p->dbMain, "COMMIT", 0, 0, &p->zErrmsg);
    +     }
    + 
    ++    /* Sync the db file if currently doing an incremental checkpoint */
    ++    if( p->rc==SQLITE_OK && p->eStage==RBU_STAGE_CKPT ){
    ++      sqlite3_file *pDb = p->pTargetFd->pReal;
    ++      p->rc = pDb->pMethods->xSync(pDb, SQLITE_SYNC_NORMAL);
    ++    }
    ++
    +     rbuSaveState(p, p->eStage);
    + 
    +     if( p->rc==SQLITE_OK && p->eStage==RBU_STAGE_OAL ){
    +@@ -161991,16 +176512,32 @@ SQLITE_API int SQLITE_STDCALL sqlite3rbu_close(sqlite3rbu *p, char **pzErrmsg){
    +     /* Close any open statement handles. */
    +     rbuObjIterFinalize(&p->objiter);
    + 
    ++    /* If this is an RBU vacuum handle and the vacuum has either finished
    ++    ** successfully or encountered an error, delete the contents of the 
    ++    ** state table. This causes the next call to sqlite3rbu_vacuum() 
    ++    ** specifying the current target and state databases to start a new
    ++    ** vacuum from scratch.  */
    ++    if( rbuIsVacuum(p) && p->rc!=SQLITE_OK && p->dbRbu ){
    ++      int rc2 = sqlite3_exec(p->dbRbu, "DELETE FROM stat.rbu_state", 0, 0, 0);
    ++      if( p->rc==SQLITE_DONE && rc2!=SQLITE_OK ) p->rc = rc2;
    ++    }
    ++
    +     /* Close the open database handle and VFS object. */
    +-    sqlite3_close(p->dbMain);
    +     sqlite3_close(p->dbRbu);
    ++    sqlite3_close(p->dbMain);
    ++    assert( p->szTemp==0 );
    +     rbuDeleteVfs(p);
    +     sqlite3_free(p->aBuf);
    +     sqlite3_free(p->aFrame);
    + 
    +     rbuEditErrmsg(p);
    +     rc = p->rc;
    +-    *pzErrmsg = p->zErrmsg;
    ++    if( pzErrmsg ){
    ++      *pzErrmsg = p->zErrmsg;
    ++    }else{
    ++      sqlite3_free(p->zErrmsg);
    ++    }
    ++    sqlite3_free(p->zState);
    +     sqlite3_free(p);
    +   }else{
    +     rc = SQLITE_NOMEM;
    +@@ -162014,13 +176551,79 @@ SQLITE_API int SQLITE_STDCALL sqlite3rbu_close(sqlite3rbu *p, char **pzErrmsg){
    + ** updates) that have been performed on the target database since the
    + ** current RBU update was started.
    + */
    +-SQLITE_API sqlite3_int64 SQLITE_STDCALL sqlite3rbu_progress(sqlite3rbu *pRbu){
    ++SQLITE_API sqlite3_int64 sqlite3rbu_progress(sqlite3rbu *pRbu){
    +   return pRbu->nProgress;
    + }
    + 
    +-SQLITE_API int SQLITE_STDCALL sqlite3rbu_savestate(sqlite3rbu *p){
    ++/*
    ++** Return permyriadage progress indications for the two main stages of
    ++** an RBU update.
    ++*/
    ++SQLITE_API void sqlite3rbu_bp_progress(sqlite3rbu *p, int *pnOne, int *pnTwo){
    ++  const int MAX_PROGRESS = 10000;
    ++  switch( p->eStage ){
    ++    case RBU_STAGE_OAL:
    ++      if( p->nPhaseOneStep>0 ){
    ++        *pnOne = (int)(MAX_PROGRESS * (i64)p->nProgress/(i64)p->nPhaseOneStep);
    ++      }else{
    ++        *pnOne = -1;
    ++      }
    ++      *pnTwo = 0;
    ++      break;
    ++
    ++    case RBU_STAGE_MOVE:
    ++      *pnOne = MAX_PROGRESS;
    ++      *pnTwo = 0;
    ++      break;
    ++
    ++    case RBU_STAGE_CKPT:
    ++      *pnOne = MAX_PROGRESS;
    ++      *pnTwo = (int)(MAX_PROGRESS * (i64)p->nStep / (i64)p->nFrame);
    ++      break;
    ++
    ++    case RBU_STAGE_DONE:
    ++      *pnOne = MAX_PROGRESS;
    ++      *pnTwo = MAX_PROGRESS;
    ++      break;
    ++
    ++    default:
    ++      assert( 0 );
    ++  }
    ++}
    ++
    ++/*
    ++** Return the current state of the RBU vacuum or update operation.
    ++*/
    ++SQLITE_API int sqlite3rbu_state(sqlite3rbu *p){
    ++  int aRes[] = {
    ++    0, SQLITE_RBU_STATE_OAL, SQLITE_RBU_STATE_MOVE,
    ++    0, SQLITE_RBU_STATE_CHECKPOINT, SQLITE_RBU_STATE_DONE
    ++  };
    ++
    ++  assert( RBU_STAGE_OAL==1 );
    ++  assert( RBU_STAGE_MOVE==2 );
    ++  assert( RBU_STAGE_CKPT==4 );
    ++  assert( RBU_STAGE_DONE==5 );
    ++  assert( aRes[RBU_STAGE_OAL]==SQLITE_RBU_STATE_OAL );
    ++  assert( aRes[RBU_STAGE_MOVE]==SQLITE_RBU_STATE_MOVE );
    ++  assert( aRes[RBU_STAGE_CKPT]==SQLITE_RBU_STATE_CHECKPOINT );
    ++  assert( aRes[RBU_STAGE_DONE]==SQLITE_RBU_STATE_DONE );
    ++
    ++  if( p->rc!=SQLITE_OK && p->rc!=SQLITE_DONE ){
    ++    return SQLITE_RBU_STATE_ERROR;
    ++  }else{
    ++    assert( p->rc!=SQLITE_DONE || p->eStage==RBU_STAGE_DONE );
    ++    assert( p->eStage==RBU_STAGE_OAL
    ++         || p->eStage==RBU_STAGE_MOVE
    ++         || p->eStage==RBU_STAGE_CKPT
    ++         || p->eStage==RBU_STAGE_DONE
    ++    );
    ++    return aRes[p->eStage];
    ++  }
    ++}
    ++
    ++SQLITE_API int sqlite3rbu_savestate(sqlite3rbu *p){
    +   int rc = p->rc;
    +-  
    +   if( rc==SQLITE_DONE ) return SQLITE_OK;
    + 
    +   assert( p->eStage>=RBU_STAGE_OAL && p->eStage<=RBU_STAGE_DONE );
    +@@ -162029,6 +176632,12 @@ SQLITE_API int SQLITE_STDCALL sqlite3rbu_savestate(sqlite3rbu *p){
    +     if( rc==SQLITE_OK ) rc = sqlite3_exec(p->dbMain, "COMMIT", 0, 0, 0);
    +   }
    + 
    ++  /* Sync the db file */
    ++  if( rc==SQLITE_OK && p->eStage==RBU_STAGE_CKPT ){
    ++    sqlite3_file *pDb = p->pTargetFd->pReal;
    ++    rc = pDb->pMethods->xSync(pDb, SQLITE_SYNC_NORMAL);
    ++  }
    ++
    +   p->rc = rc;
    +   rbuSaveState(p, p->eStage);
    +   rc = p->rc;
    +@@ -162104,6 +176713,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3rbu_savestate(sqlite3rbu *p){
    + */
    + 
    + static void rbuUnlockShm(rbu_file *p){
    ++  assert( p->openFlags & SQLITE_OPEN_MAIN_DB );
    +   if( p->pRbu ){
    +     int (*xShmLock)(sqlite3_file*,int,int,int) = p->pReal->pMethods->xShmLock;
    +     int i;
    +@@ -162116,6 +176726,81 @@ static void rbuUnlockShm(rbu_file *p){
    +   }
    + }
    + 
    ++/*
    ++*/
    ++static int rbuUpdateTempSize(rbu_file *pFd, sqlite3_int64 nNew){
    ++  sqlite3rbu *pRbu = pFd->pRbu;
    ++  i64 nDiff = nNew - pFd->sz;
    ++  pRbu->szTemp += nDiff;
    ++  pFd->sz = nNew;
    ++  assert( pRbu->szTemp>=0 );
    ++  if( pRbu->szTempLimit && pRbu->szTemp>pRbu->szTempLimit ) return SQLITE_FULL;
    ++  return SQLITE_OK;
    ++}
    ++
    ++/*
    ++** Add an item to the main-db lists, if it is not already present.
    ++**
    ++** There are two main-db lists. One for all file descriptors, and one
    ++** for all file descriptors with rbu_file.pDb!=0. If the argument has
    ++** rbu_file.pDb!=0, then it is assumed to already be present on the
    ++** main list and is only added to the pDb!=0 list.
    ++*/
    ++static void rbuMainlistAdd(rbu_file *p){
    ++  rbu_vfs *pRbuVfs = p->pRbuVfs;
    ++  rbu_file *pIter;
    ++  assert( (p->openFlags & SQLITE_OPEN_MAIN_DB) );
    ++  sqlite3_mutex_enter(pRbuVfs->mutex);
    ++  if( p->pRbu==0 ){
    ++    for(pIter=pRbuVfs->pMain; pIter; pIter=pIter->pMainNext);
    ++    p->pMainNext = pRbuVfs->pMain;
    ++    pRbuVfs->pMain = p;
    ++  }else{
    ++    for(pIter=pRbuVfs->pMainRbu; pIter && pIter!=p; pIter=pIter->pMainRbuNext){}
    ++    if( pIter==0 ){
    ++      p->pMainRbuNext = pRbuVfs->pMainRbu;
    ++      pRbuVfs->pMainRbu = p;
    ++    }
    ++  }
    ++  sqlite3_mutex_leave(pRbuVfs->mutex);
    ++}
    ++
    ++/*
    ++** Remove an item from the main-db lists.
    ++*/
    ++static void rbuMainlistRemove(rbu_file *p){
    ++  rbu_file **pp;
    ++  sqlite3_mutex_enter(p->pRbuVfs->mutex);
    ++  for(pp=&p->pRbuVfs->pMain; *pp && *pp!=p; pp=&((*pp)->pMainNext)){}
    ++  if( *pp ) *pp = p->pMainNext;
    ++  p->pMainNext = 0;
    ++  for(pp=&p->pRbuVfs->pMainRbu; *pp && *pp!=p; pp=&((*pp)->pMainRbuNext)){}
    ++  if( *pp ) *pp = p->pMainRbuNext;
    ++  p->pMainRbuNext = 0;
    ++  sqlite3_mutex_leave(p->pRbuVfs->mutex);
    ++}
    ++
    ++/*
    ++** Given that zWal points to a buffer containing a wal file name passed to
    ++** either the xOpen() or xAccess() VFS method, search the main-db list for
    ++** a file-handle opened by the same database connection on the corresponding
    ++** database file.
    ++**
    ++** If parameter bRbu is true, only search for file-descriptors with
    ++** rbu_file.pDb!=0.
    ++*/
    ++static rbu_file *rbuFindMaindb(rbu_vfs *pRbuVfs, const char *zWal, int bRbu){
    ++  rbu_file *pDb;
    ++  sqlite3_mutex_enter(pRbuVfs->mutex);
    ++  if( bRbu ){
    ++    for(pDb=pRbuVfs->pMainRbu; pDb && pDb->zWal!=zWal; pDb=pDb->pMainRbuNext){}
    ++  }else{
    ++    for(pDb=pRbuVfs->pMain; pDb && pDb->zWal!=zWal; pDb=pDb->pMainNext){}
    ++  }
    ++  sqlite3_mutex_leave(pRbuVfs->mutex);
    ++  return pDb;
    ++}
    ++
    + /*
    + ** Close an rbu file.
    + */
    +@@ -162133,14 +176818,14 @@ static int rbuVfsClose(sqlite3_file *pFile){
    +   sqlite3_free(p->zDel);
    + 
    +   if( p->openFlags & SQLITE_OPEN_MAIN_DB ){
    +-    rbu_file **pp;
    +-    sqlite3_mutex_enter(p->pRbuVfs->mutex);
    +-    for(pp=&p->pRbuVfs->pMain; *pp!=p; pp=&((*pp)->pMainNext));
    +-    *pp = p->pMainNext;
    +-    sqlite3_mutex_leave(p->pRbuVfs->mutex);
    ++    rbuMainlistRemove(p);
    +     rbuUnlockShm(p);
    +     p->pReal->pMethods->xShmUnmap(p->pReal, 0);
    +   }
    ++  else if( (p->openFlags & SQLITE_OPEN_DELETEONCLOSE) && p->pRbu ){
    ++    rbuUpdateTempSize(p, 0);
    ++  }
    ++  assert( p->pMainNext==0 && p->pRbuVfs->pMain!=p );
    + 
    +   /* Close the underlying file handle */
    +   rc = p->pReal->pMethods->xClose(p->pReal);
    +@@ -162159,6 +176844,22 @@ static u32 rbuGetU32(u8 *aBuf){
    +        + ((u32)aBuf[3]);
    + }
    + 
    ++/*
    ++** Write an unsigned 32-bit value in big-endian format to the supplied
    ++** buffer.
    ++*/
    ++static void rbuPutU32(u8 *aBuf, u32 iVal){
    ++  aBuf[0] = (iVal >> 24) & 0xFF;
    ++  aBuf[1] = (iVal >> 16) & 0xFF;
    ++  aBuf[2] = (iVal >>  8) & 0xFF;
    ++  aBuf[3] = (iVal >>  0) & 0xFF;
    ++}
    ++
    ++static void rbuPutU16(u8 *aBuf, u16 iVal){
    ++  aBuf[0] = (iVal >>  8) & 0xFF;
    ++  aBuf[1] = (iVal >>  0) & 0xFF;
    ++}
    ++
    + /*
    + ** Read data from an rbuVfs-file.
    + */
    +@@ -162184,6 +176885,35 @@ static int rbuVfsRead(
    +       memset(zBuf, 0, iAmt);
    +     }else{
    +       rc = p->pReal->pMethods->xRead(p->pReal, zBuf, iAmt, iOfst);
    ++#if 1
    ++      /* If this is being called to read the first page of the target 
    ++      ** database as part of an rbu vacuum operation, synthesize the 
    ++      ** contents of the first page if it does not yet exist. Otherwise,
    ++      ** SQLite will not check for a *-wal file.  */
    ++      if( pRbu && rbuIsVacuum(pRbu) 
    ++          && rc==SQLITE_IOERR_SHORT_READ && iOfst==0
    ++          && (p->openFlags & SQLITE_OPEN_MAIN_DB)
    ++          && pRbu->rc==SQLITE_OK
    ++      ){
    ++        sqlite3_file *pFd = (sqlite3_file*)pRbu->pRbuFd;
    ++        rc = pFd->pMethods->xRead(pFd, zBuf, iAmt, iOfst);
    ++        if( rc==SQLITE_OK ){
    ++          u8 *aBuf = (u8*)zBuf;
    ++          u32 iRoot = rbuGetU32(&aBuf[52]) ? 1 : 0;
    ++          rbuPutU32(&aBuf[52], iRoot);      /* largest root page number */
    ++          rbuPutU32(&aBuf[36], 0);          /* number of free pages */
    ++          rbuPutU32(&aBuf[32], 0);          /* first page on free list trunk */
    ++          rbuPutU32(&aBuf[28], 1);          /* size of db file in pages */
    ++          rbuPutU32(&aBuf[24], pRbu->pRbuFd->iCookie+1);  /* Change counter */
    ++
    ++          if( iAmt>100 ){
    ++            memset(&aBuf[100], 0, iAmt-100);
    ++            rbuPutU16(&aBuf[105], iAmt & 0xFFFF);
    ++            aBuf[100] = 0x0D;
    ++          }
    ++        }
    ++      }
    ++#endif
    +     }
    +     if( rc==SQLITE_OK && iOfst==0 && (p->openFlags & SQLITE_OPEN_MAIN_DB) ){
    +       /* These look like magic numbers. But they are stable, as they are part
    +@@ -162213,11 +176943,19 @@ static int rbuVfsWrite(
    +     assert( p->openFlags & SQLITE_OPEN_MAIN_DB );
    +     rc = rbuCaptureDbWrite(p->pRbu, iOfst);
    +   }else{
    +-    if( pRbu && pRbu->eStage==RBU_STAGE_OAL 
    +-     && (p->openFlags & SQLITE_OPEN_WAL) 
    +-     && iOfst>=pRbu->iOalSz
    +-    ){
    +-      pRbu->iOalSz = iAmt + iOfst;
    ++    if( pRbu ){
    ++      if( pRbu->eStage==RBU_STAGE_OAL 
    ++       && (p->openFlags & SQLITE_OPEN_WAL) 
    ++       && iOfst>=pRbu->iOalSz
    ++      ){
    ++        pRbu->iOalSz = iAmt + iOfst;
    ++      }else if( p->openFlags & SQLITE_OPEN_DELETEONCLOSE ){
    ++        i64 szNew = iAmt+iOfst;
    ++        if( szNew>p->sz ){
    ++          rc = rbuUpdateTempSize(p, szNew);
    ++          if( rc!=SQLITE_OK ) return rc;
    ++        }
    ++      }
    +     }
    +     rc = p->pReal->pMethods->xWrite(p->pReal, zBuf, iAmt, iOfst);
    +     if( rc==SQLITE_OK && iOfst==0 && (p->openFlags & SQLITE_OPEN_MAIN_DB) ){
    +@@ -162236,6 +176974,10 @@ static int rbuVfsWrite(
    + */
    + static int rbuVfsTruncate(sqlite3_file *pFile, sqlite_int64 size){
    +   rbu_file *p = (rbu_file*)pFile;
    ++  if( (p->openFlags & SQLITE_OPEN_DELETEONCLOSE) && p->pRbu ){
    ++    int rc = rbuUpdateTempSize(p, size);
    ++    if( rc!=SQLITE_OK ) return rc;
    ++  }
    +   return p->pReal->pMethods->xTruncate(p->pReal, size);
    + }
    + 
    +@@ -162258,7 +177000,20 @@ static int rbuVfsSync(sqlite3_file *pFile, int flags){
    + */
    + static int rbuVfsFileSize(sqlite3_file *pFile, sqlite_int64 *pSize){
    +   rbu_file *p = (rbu_file *)pFile;
    +-  return p->pReal->pMethods->xFileSize(p->pReal, pSize);
    ++  int rc;
    ++  rc = p->pReal->pMethods->xFileSize(p->pReal, pSize);
    ++
    ++  /* If this is an RBU vacuum operation and this is the target database,
    ++  ** pretend that it has at least one page. Otherwise, SQLite will not
    ++  ** check for the existance of a *-wal file. rbuVfsRead() contains 
    ++  ** similar logic.  */
    ++  if( rc==SQLITE_OK && *pSize==0 
    ++   && p->pRbu && rbuIsVacuum(p->pRbu) 
    ++   && (p->openFlags & SQLITE_OPEN_MAIN_DB)
    ++  ){
    ++    *pSize = 1024;
    ++  }
    ++  return rc;
    + }
    + 
    + /*
    +@@ -162270,7 +177025,9 @@ static int rbuVfsLock(sqlite3_file *pFile, int eLock){
    +   int rc = SQLITE_OK;
    + 
    +   assert( p->openFlags & (SQLITE_OPEN_MAIN_DB|SQLITE_OPEN_TEMP_DB) );
    +-  if( pRbu && eLock==SQLITE_LOCK_EXCLUSIVE && pRbu->eStage!=RBU_STAGE_DONE ){
    ++  if( eLock==SQLITE_LOCK_EXCLUSIVE 
    ++   && (p->bNolock || (pRbu && pRbu->eStage!=RBU_STAGE_DONE))
    ++  ){
    +     /* Do not allow EXCLUSIVE locks. Preventing SQLite from taking this 
    +     ** prevents it from checkpointing the database from sqlite3_close(). */
    +     rc = SQLITE_BUSY;
    +@@ -162327,12 +177084,21 @@ static int rbuVfsFileControl(sqlite3_file *pFile, int op, void *pArg){
    +       }else if( rc==SQLITE_NOTFOUND ){
    +         pRbu->pTargetFd = p;
    +         p->pRbu = pRbu;
    ++        if( p->openFlags & SQLITE_OPEN_MAIN_DB ){
    ++          rbuMainlistAdd(p);
    ++        }
    +         if( p->pWalFd ) p->pWalFd->pRbu = pRbu;
    +         rc = SQLITE_OK;
    +       }
    +     }
    +     return rc;
    +   }
    ++  else if( op==SQLITE_FCNTL_RBUCNT ){
    ++    sqlite3rbu *pRbu = (sqlite3rbu*)pArg;
    ++    pRbu->nRbu++;
    ++    pRbu->pRbuFd = p;
    ++    p->bNolock = 1;
    ++  }
    + 
    +   rc = xControl(p->pReal, op, pArg);
    +   if( rc==SQLITE_OK && op==SQLITE_FCNTL_VFSNAME ){
    +@@ -162422,7 +177188,7 @@ static int rbuVfsShmMap(
    +   if( eStage==RBU_STAGE_OAL || eStage==RBU_STAGE_MOVE ){
    +     if( iRegion<=p->nShm ){
    +       int nByte = (iRegion+1) * sizeof(char*);
    +-      char **apNew = (char**)sqlite3_realloc(p->apShm, nByte);
    ++      char **apNew = (char**)sqlite3_realloc64(p->apShm, nByte);
    +       if( apNew==0 ){
    +         rc = SQLITE_NOMEM;
    +       }else{
    +@@ -162433,7 +177199,7 @@ static int rbuVfsShmMap(
    +     }
    + 
    +     if( rc==SQLITE_OK && p->apShm[iRegion]==0 ){
    +-      char *pNew = (char*)sqlite3_malloc(szRegion);
    ++      char *pNew = (char*)sqlite3_malloc64(szRegion);
    +       if( pNew==0 ){
    +         rc = SQLITE_NOMEM;
    +       }else{
    +@@ -162482,18 +177248,31 @@ static int rbuVfsShmUnmap(sqlite3_file *pFile, int delFlag){
    +   return rc;
    + }
    + 
    +-/*
    +-** Given that zWal points to a buffer containing a wal file name passed to 
    +-** either the xOpen() or xAccess() VFS method, return a pointer to the
    +-** file-handle opened by the same database connection on the corresponding
    +-** database file.
    +-*/
    +-static rbu_file *rbuFindMaindb(rbu_vfs *pRbuVfs, const char *zWal){
    +-  rbu_file *pDb;
    +-  sqlite3_mutex_enter(pRbuVfs->mutex);
    +-  for(pDb=pRbuVfs->pMain; pDb && pDb->zWal!=zWal; pDb=pDb->pMainNext);
    +-  sqlite3_mutex_leave(pRbuVfs->mutex);
    +-  return pDb;
    ++/* 
    ++** A main database named zName has just been opened. The following 
    ++** function returns a pointer to a buffer owned by SQLite that contains
    ++** the name of the *-wal file this db connection will use. SQLite
    ++** happens to pass a pointer to this buffer when using xAccess()
    ++** or xOpen() to operate on the *-wal file.  
    ++*/
    ++static const char *rbuMainToWal(const char *zName, int flags){
    ++  int n = (int)strlen(zName);
    ++  const char *z = &zName[n];
    ++  if( flags & SQLITE_OPEN_URI ){
    ++    int odd = 0;
    ++    while( 1 ){
    ++      if( z[0]==0 ){
    ++        odd = 1 - odd;
    ++        if( odd && z[1]==0 ) break;
    ++      }
    ++      z++;
    ++    }
    ++    z += 2;
    ++  }else{
    ++    while( *z==0 ) z++;
    ++  }
    ++  z += (n + 8 + 1);
    ++  return z;
    + }
    + 
    + /*
    +@@ -162531,6 +177310,7 @@ static int rbuVfsOpen(
    +   rbu_file *pFd = (rbu_file *)pFile;
    +   int rc = SQLITE_OK;
    +   const char *zOpen = zName;
    ++  int oflags = flags;
    + 
    +   memset(pFd, 0, sizeof(rbu_file));
    +   pFd->pReal = (sqlite3_file*)&pFd[1];
    +@@ -162543,36 +177323,27 @@ static int rbuVfsOpen(
    +       ** the name of the *-wal file this db connection will use. SQLite
    +       ** happens to pass a pointer to this buffer when using xAccess()
    +       ** or xOpen() to operate on the *-wal file.  */
    +-      int n = strlen(zName);
    +-      const char *z = &zName[n];
    +-      if( flags & SQLITE_OPEN_URI ){
    +-        int odd = 0;
    +-        while( 1 ){
    +-          if( z[0]==0 ){
    +-            odd = 1 - odd;
    +-            if( odd && z[1]==0 ) break;
    +-          }
    +-          z++;
    +-        }
    +-        z += 2;
    +-      }else{
    +-        while( *z==0 ) z++;
    +-      }
    +-      z += (n + 8 + 1);
    +-      pFd->zWal = z;
    ++      pFd->zWal = rbuMainToWal(zName, flags);
    +     }
    +     else if( flags & SQLITE_OPEN_WAL ){
    +-      rbu_file *pDb = rbuFindMaindb(pRbuVfs, zName);
    ++      rbu_file *pDb = rbuFindMaindb(pRbuVfs, zName, 0);
    +       if( pDb ){
    +         if( pDb->pRbu && pDb->pRbu->eStage==RBU_STAGE_OAL ){
    +           /* This call is to open a *-wal file. Intead, open the *-oal. This
    +           ** code ensures that the string passed to xOpen() is terminated by a
    +           ** pair of '\0' bytes in case the VFS attempts to extract a URI 
    +           ** parameter from it.  */
    +-          int nCopy = strlen(zName);
    +-          char *zCopy = sqlite3_malloc(nCopy+2);
    ++          const char *zBase = zName;
    ++          size_t nCopy;
    ++          char *zCopy;
    ++          if( rbuIsVacuum(pDb->pRbu) ){
    ++            zBase = sqlite3_db_filename(pDb->pRbu->dbRbu, "main");
    ++            zBase = rbuMainToWal(zBase, SQLITE_OPEN_URI);
    ++          }
    ++          nCopy = strlen(zBase);
    ++          zCopy = sqlite3_malloc64(nCopy+2);
    +           if( zCopy ){
    +-            memcpy(zCopy, zName, nCopy);
    ++            memcpy(zCopy, zBase, nCopy);
    +             zCopy[nCopy-3] = 'o';
    +             zCopy[nCopy] = '\0';
    +             zCopy[nCopy+1] = '\0';
    +@@ -162585,10 +177356,21 @@ static int rbuVfsOpen(
    +         pDb->pWalFd = pFd;
    +       }
    +     }
    ++  }else{
    ++    pFd->pRbu = pRbuVfs->pRbu;
    ++  }
    ++
    ++  if( oflags & SQLITE_OPEN_MAIN_DB 
    ++   && sqlite3_uri_boolean(zName, "rbu_memory", 0) 
    ++  ){
    ++    assert( oflags & SQLITE_OPEN_MAIN_DB );
    ++    oflags =  SQLITE_OPEN_TEMP_DB | SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE |
    ++              SQLITE_OPEN_EXCLUSIVE | SQLITE_OPEN_DELETEONCLOSE;
    ++    zOpen = 0;
    +   }
    + 
    +   if( rc==SQLITE_OK ){
    +-    rc = pRealVfs->xOpen(pRealVfs, zOpen, pFd->pReal, flags, pOutFlags);
    ++    rc = pRealVfs->xOpen(pRealVfs, zOpen, pFd->pReal, oflags, pOutFlags);
    +   }
    +   if( pFd->pReal->pMethods ){
    +     /* The xOpen() operation has succeeded. Set the sqlite3_file.pMethods
    +@@ -162596,10 +177378,7 @@ static int rbuVfsOpen(
    +     ** mutex protected linked list of all such files.  */
    +     pFile->pMethods = &rbuvfs_io_methods;
    +     if( flags & SQLITE_OPEN_MAIN_DB ){
    +-      sqlite3_mutex_enter(pRbuVfs->mutex);
    +-      pFd->pMainNext = pRbuVfs->pMain;
    +-      pRbuVfs->pMain = pFd;
    +-      sqlite3_mutex_leave(pRbuVfs->mutex);
    ++      rbuMainlistAdd(pFd);
    +     }
    +   }else{
    +     sqlite3_free(pFd->zDel);
    +@@ -162647,12 +177426,14 @@ static int rbuVfsAccess(
    +   **      file opened instead.
    +   */
    +   if( rc==SQLITE_OK && flags==SQLITE_ACCESS_EXISTS ){
    +-    rbu_file *pDb = rbuFindMaindb(pRbuVfs, zPath);
    ++    rbu_file *pDb = rbuFindMaindb(pRbuVfs, zPath, 1);
    +     if( pDb && pDb->pRbu && pDb->pRbu->eStage==RBU_STAGE_OAL ){
    +       if( *pResOut ){
    +         rc = SQLITE_CANTOPEN;
    +       }else{
    +-        *pResOut = 1;
    ++        sqlite3_int64 sz = 0;
    ++        rc = rbuVfsFileSize(&pDb->base, &sz);
    ++        *pResOut = (sz>0);
    +       }
    +     }
    +   }
    +@@ -162752,7 +177533,7 @@ static int rbuVfsGetLastError(sqlite3_vfs *pVfs, int a, char *b){
    + ** Deregister and destroy an RBU vfs created by an earlier call to
    + ** sqlite3rbu_create_vfs().
    + */
    +-SQLITE_API void SQLITE_STDCALL sqlite3rbu_destroy_vfs(const char *zName){
    ++SQLITE_API void sqlite3rbu_destroy_vfs(const char *zName){
    +   sqlite3_vfs *pVfs = sqlite3_vfs_find(zName);
    +   if( pVfs && pVfs->xOpen==rbuVfsOpen ){
    +     sqlite3_mutex_free(((rbu_vfs*)pVfs)->mutex);
    +@@ -162766,7 +177547,7 @@ SQLITE_API void SQLITE_STDCALL sqlite3rbu_destroy_vfs(const char *zName){
    + ** via existing VFS zParent. The new object is registered as a non-default
    + ** VFS with SQLite before returning.
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3rbu_create_vfs(const char *zName, const char *zParent){
    ++SQLITE_API int sqlite3rbu_create_vfs(const char *zName, const char *zParent){
    + 
    +   /* Template for VFS */
    +   static sqlite3_vfs vfs_template = {
    +@@ -162799,13 +177580,13 @@ SQLITE_API int SQLITE_STDCALL sqlite3rbu_create_vfs(const char *zName, const cha
    +   };
    + 
    +   rbu_vfs *pNew = 0;              /* Newly allocated VFS */
    +-  int nName;
    +   int rc = SQLITE_OK;
    ++  size_t nName;
    ++  size_t nByte;
    + 
    +-  int nByte;
    +   nName = strlen(zName);
    +   nByte = sizeof(rbu_vfs) + nName + 1;
    +-  pNew = (rbu_vfs*)sqlite3_malloc(nByte);
    ++  pNew = (rbu_vfs*)sqlite3_malloc64(nByte);
    +   if( pNew==0 ){
    +     rc = SQLITE_NOMEM;
    +   }else{
    +@@ -162841,6 +177622,20 @@ SQLITE_API int SQLITE_STDCALL sqlite3rbu_create_vfs(const char *zName, const cha
    +   return rc;
    + }
    + 
    ++/*
    ++** Configure the aggregate temp file size limit for this RBU handle.
    ++*/
    ++SQLITE_API sqlite3_int64 sqlite3rbu_temp_size_limit(sqlite3rbu *pRbu, sqlite3_int64 n){
    ++  if( n>=0 ){
    ++    pRbu->szTempLimit = n;
    ++  }
    ++  return pRbu->szTempLimit;
    ++}
    ++
    ++SQLITE_API sqlite3_int64 sqlite3rbu_temp_size(sqlite3rbu *pRbu){
    ++  return pRbu->szTemp;
    ++}
    ++
    + 
    + /**************************************************************************/
    + 
    +@@ -162908,10 +177703,10 @@ SQLITE_API int SQLITE_STDCALL sqlite3rbu_create_vfs(const char *zName, const cha
    + */
    + #define VTAB_SCHEMA                                                         \
    +   "CREATE TABLE xx( "                                                       \
    +-  "  name       STRING,           /* Name of table or index */"             \
    +-  "  path       INTEGER,          /* Path to page from root */"             \
    ++  "  name       TEXT,             /* Name of table or index */"             \
    ++  "  path       TEXT,             /* Path to page from root */"             \
    +   "  pageno     INTEGER,          /* Page number */"                        \
    +-  "  pagetype   STRING,           /* 'internal', 'leaf' or 'overflow' */"   \
    ++  "  pagetype   TEXT,             /* 'internal', 'leaf' or 'overflow' */"   \
    +   "  ncell      INTEGER,          /* Cells on page (0 for overflow) */"     \
    +   "  payload    INTEGER,          /* Bytes of payload on this page */"      \
    +   "  unused     INTEGER,          /* Bytes of unused space on this page */" \
    +@@ -162999,7 +177794,9 @@ static int statConnect(
    +   int iDb;
    + 
    +   if( argc>=4 ){
    +-    iDb = sqlite3FindDbName(db, argv[3]);
    ++    Token nm;
    ++    sqlite3TokenInit(&nm, (char*)argv[3]);
    ++    iDb = sqlite3FindDb(db, &nm);
    +     if( iDb<0 ){
    +       *pzErr = sqlite3_mprintf("no such database: %s", argv[3]);
    +       return SQLITE_ERROR;
    +@@ -163010,7 +177807,7 @@ static int statConnect(
    +   rc = sqlite3_declare_vtab(db, VTAB_SCHEMA);
    +   if( rc==SQLITE_OK ){
    +     pTab = (StatTable *)sqlite3_malloc64(sizeof(StatTable));
    +-    if( pTab==0 ) rc = SQLITE_NOMEM;
    ++    if( pTab==0 ) rc = SQLITE_NOMEM_BKPT;
    +   }
    + 
    +   assert( rc==SQLITE_OK || pTab==0 );
    +@@ -163091,7 +177888,7 @@ static int statOpen(sqlite3_vtab *pVTab, sqlite3_vtab_cursor **ppCursor){
    + 
    +   pCsr = (StatCursor *)sqlite3_malloc64(sizeof(StatCursor));
    +   if( pCsr==0 ){
    +-    return SQLITE_NOMEM;
    ++    return SQLITE_NOMEM_BKPT;
    +   }else{
    +     memset(pCsr, 0, sizeof(StatCursor));
    +     pCsr->base.pVtab = pVTab;
    +@@ -163197,7 +177994,7 @@ static int statDecodePage(Btree *pBt, StatPage *p){
    +     nUsable = szPage - sqlite3BtreeGetReserveNoMutex(pBt);
    +     sqlite3BtreeLeave(pBt);
    +     p->aCell = sqlite3_malloc64((p->nCell+1) * sizeof(StatCell));
    +-    if( p->aCell==0 ) return SQLITE_NOMEM;
    ++    if( p->aCell==0 ) return SQLITE_NOMEM_BKPT;
    +     memset(p->aCell, 0, (p->nCell+1) * sizeof(StatCell));
    + 
    +     for(i=0; i<p->nCell; i++){
    +@@ -163230,13 +178027,13 @@ static int statDecodePage(Btree *pBt, StatPage *p){
    +           pCell->nLastOvfl = (nPayload-nLocal) - (nOvfl-1) * (nUsable-4);
    +           pCell->nOvfl = nOvfl;
    +           pCell->aOvfl = sqlite3_malloc64(sizeof(u32)*nOvfl);
    +-          if( pCell->aOvfl==0 ) return SQLITE_NOMEM;
    ++          if( pCell->aOvfl==0 ) return SQLITE_NOMEM_BKPT;
    +           pCell->aOvfl[0] = sqlite3Get4byte(&aData[iOff+nLocal]);
    +           for(j=1; j<nOvfl; j++){
    +             int rc;
    +             u32 iPrev = pCell->aOvfl[j-1];
    +             DbPage *pPg = 0;
    +-            rc = sqlite3PagerGet(sqlite3BtreePager(pBt), iPrev, &pPg);
    ++            rc = sqlite3PagerGet(sqlite3BtreePager(pBt), iPrev, &pPg, 0);
    +             if( rc!=SQLITE_OK ){
    +               assert( pPg==0 );
    +               return rc;
    +@@ -163304,12 +178101,12 @@ statNextRestart:
    +         pCsr->isEof = 1;
    +         return sqlite3_reset(pCsr->pStmt);
    +       }
    +-      rc = sqlite3PagerGet(pPager, iRoot, &pCsr->aPage[0].pPg);
    ++      rc = sqlite3PagerGet(pPager, iRoot, &pCsr->aPage[0].pPg, 0);
    +       pCsr->aPage[0].iPgno = iRoot;
    +       pCsr->aPage[0].iCell = 0;
    +       pCsr->aPage[0].zPath = z = sqlite3_mprintf("/");
    +       pCsr->iPage = 0;
    +-      if( z==0 ) rc = SQLITE_NOMEM;
    ++      if( z==0 ) rc = SQLITE_NOMEM_BKPT;
    +     }else{
    +       pCsr->isEof = 1;
    +       return sqlite3_reset(pCsr->pStmt);
    +@@ -163344,7 +178141,7 @@ statNextRestart:
    +         }
    +         pCell->iOvfl++;
    +         statSizeAndOffset(pCsr);
    +-        return z==0 ? SQLITE_NOMEM : SQLITE_OK;
    ++        return z==0 ? SQLITE_NOMEM_BKPT : SQLITE_OK;
    +       }
    +       if( p->iRightChildPg ) break;
    +       p->iCell++;
    +@@ -163364,11 +178161,11 @@ statNextRestart:
    +     }else{
    +       p[1].iPgno = p->aCell[p->iCell].iChildPg;
    +     }
    +-    rc = sqlite3PagerGet(pPager, p[1].iPgno, &p[1].pPg);
    ++    rc = sqlite3PagerGet(pPager, p[1].iPgno, &p[1].pPg, 0);
    +     p[1].iCell = 0;
    +     p[1].zPath = z = sqlite3_mprintf("%s%.3x/", p->zPath, p->iCell);
    +     p->iCell++;
    +-    if( z==0 ) rc = SQLITE_NOMEM;
    ++    if( z==0 ) rc = SQLITE_NOMEM_BKPT;
    +   }
    + 
    + 
    +@@ -163402,7 +178199,7 @@ statNextRestart:
    +       pCsr->nUnused = p->nUnused;
    +       pCsr->nMxPayload = p->nMxPayload;
    +       pCsr->zPath = z = sqlite3_mprintf("%s", p->zPath);
    +-      if( z==0 ) rc = SQLITE_NOMEM;
    ++      if( z==0 ) rc = SQLITE_NOMEM_BKPT;
    +       nPayload = 0;
    +       for(i=0; i<p->nCell; i++){
    +         nPayload += p->aCell[i].nLocal;
    +@@ -163436,7 +178233,7 @@ static int statFilter(
    +     if( pCsr->iDb<0 ){
    +       sqlite3_free(pCursor->pVtab->zErrMsg);
    +       pCursor->pVtab->zErrMsg = sqlite3_mprintf("no such schema: %s", zDbase);
    +-      return pCursor->pVtab->zErrMsg ? SQLITE_ERROR : SQLITE_NOMEM;
    ++      return pCursor->pVtab->zErrMsg ? SQLITE_ERROR : SQLITE_NOMEM_BKPT;
    +     }
    +   }else{
    +     pCsr->iDb = pTab->iDb;
    +@@ -163450,9 +178247,9 @@ static int statFilter(
    +       "  UNION ALL  "
    +       "SELECT name, rootpage, type"
    +       "  FROM \"%w\".%s WHERE rootpage!=0"
    +-      "  ORDER BY name", pTab->db->aDb[pCsr->iDb].zName, zMaster);
    ++      "  ORDER BY name", pTab->db->aDb[pCsr->iDb].zDbSName, zMaster);
    +   if( zSql==0 ){
    +-    return SQLITE_NOMEM;
    ++    return SQLITE_NOMEM_BKPT;
    +   }else{
    +     rc = sqlite3_prepare_v2(pTab->db, zSql, -1, &pCsr->pStmt, 0);
    +     sqlite3_free(zSql);
    +@@ -163504,7 +178301,7 @@ static int statColumn(
    +     default: {          /* schema */
    +       sqlite3 *db = sqlite3_context_db_handle(ctx);
    +       int iDb = pCsr->iDb;
    +-      sqlite3_result_text(ctx, db->aDb[iDb].zName, -1, SQLITE_STATIC);
    ++      sqlite3_result_text(ctx, db->aDb[iDb].zDbSName, -1, SQLITE_STATIC);
    +       break;
    +     }
    +   }
    +@@ -163542,6 +178339,9 @@ SQLITE_PRIVATE int sqlite3DbstatRegister(sqlite3 *db){
    +     0,                            /* xRollback */
    +     0,                            /* xFindMethod */
    +     0,                            /* xRename */
    ++    0,                            /* xSavepoint */
    ++    0,                            /* xRelease */
    ++    0,                            /* xRollbackTo */
    +   };
    +   return sqlite3_create_module(db, "dbstat", &dbstat_module, 0);
    + }
    +@@ -163550,9 +178350,9 @@ SQLITE_PRIVATE int sqlite3DbstatRegister(sqlite3 *db){ return SQLITE_OK; }
    + #endif /* SQLITE_ENABLE_DBSTAT_VTAB */
    + 
    + /************** End of dbstat.c **********************************************/
    +-/************** Begin file json1.c *******************************************/
    ++/************** Begin file dbpage.c ******************************************/
    + /*
    +-** 2015-08-12
    ++** 2017-10-11
    + **
    + ** The author disclaims copyright to this source code.  In place of
    + ** a legal notice, here is a blessing:
    +@@ -163563,710 +178363,6002 @@ SQLITE_PRIVATE int sqlite3DbstatRegister(sqlite3 *db){ return SQLITE_OK; }
    + **
    + ******************************************************************************
    + **
    +-** This SQLite extension implements JSON functions.  The interface is
    +-** modeled after MySQL JSON functions:
    ++** This file contains an implementation of the "sqlite_dbpage" virtual table.
    + **
    +-**     https://dev.mysql.com/doc/refman/5.7/en/json.html
    ++** The sqlite_dbpage virtual table is used to read or write whole raw
    ++** pages of the database file.  The pager interface is used so that 
    ++** uncommitted changes and changes recorded in the WAL file are correctly
    ++** retrieved.
    + **
    +-** For the time being, all JSON is stored as pure text.  (We might add
    +-** a JSONB type in the future which stores a binary encoding of JSON in
    +-** a BLOB, but there is no support for JSONB in the current implementation.
    +-** This implementation parses JSON text at 250 MB/s, so it is hard to see
    +-** how JSONB might improve on that.)
    ++** Usage example:
    ++**
    ++**    SELECT data FROM sqlite_dbpage('aux1') WHERE pgno=123;
    ++**
    ++** This is an eponymous virtual table so it does not need to be created before
    ++** use.  The optional argument to the sqlite_dbpage() table name is the
    ++** schema for the database file that is to be read.  The default schema is
    ++** "main".
    ++**
    ++** The data field of sqlite_dbpage table can be updated.  The new
    ++** value must be a BLOB which is the correct page size, otherwise the
    ++** update fails.  Rows may not be deleted or inserted.
    + */
    +-#if !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_JSON1)
    +-#if !defined(_SQLITEINT_H_)
    +-/* #include "sqlite3ext.h" */
    +-#endif
    +-SQLITE_EXTENSION_INIT1
    +-/* #include <assert.h> */
    +-/* #include <string.h> */
    +-/* #include <stdlib.h> */
    +-/* #include <stdarg.h> */
    + 
    +-#define UNUSED_PARAM(X)  (void)(X)
    +-
    +-#ifndef LARGEST_INT64
    +-# define LARGEST_INT64  (0xffffffff|(((sqlite3_int64)0x7fffffff)<<32))
    +-# define SMALLEST_INT64 (((sqlite3_int64)-1) - LARGEST_INT64)
    +-#endif
    ++/* #include "sqliteInt.h"   ** Requires access to internal data structures ** */
    ++#if (defined(SQLITE_ENABLE_DBPAGE_VTAB) || defined(SQLITE_TEST)) \
    ++    && !defined(SQLITE_OMIT_VIRTUALTABLE)
    + 
    +-/*
    +-** Versions of isspace(), isalnum() and isdigit() to which it is safe
    +-** to pass signed char values.
    +-*/
    +-#ifdef sqlite3Isdigit
    +-   /* Use the SQLite core versions if this routine is part of the
    +-   ** SQLite amalgamation */
    +-#  define safe_isdigit(x) sqlite3Isdigit(x)
    +-#  define safe_isalnum(x) sqlite3Isalnum(x)
    +-#else
    +-   /* Use the standard library for separate compilation */
    +-#include <ctype.h>  /* amalgamator: keep */
    +-#  define safe_isdigit(x) isdigit((unsigned char)(x))
    +-#  define safe_isalnum(x) isalnum((unsigned char)(x))
    +-#endif
    ++typedef struct DbpageTable DbpageTable;
    ++typedef struct DbpageCursor DbpageCursor;
    + 
    +-/*
    +-** Growing our own isspace() routine this way is twice as fast as
    +-** the library isspace() function, resulting in a 7% overall performance
    +-** increase for the parser.  (Ubuntu14.10 gcc 4.8.4 x64 with -Os).
    +-*/
    +-static const char jsonIsSpace[] = {
    +-  0, 0, 0, 0, 0, 0, 0, 0,     0, 1, 1, 0, 0, 1, 0, 0,
    +-  0, 0, 0, 0, 0, 0, 0, 0,     0, 0, 0, 0, 0, 0, 0, 0,
    +-  1, 0, 0, 0, 0, 0, 0, 0,     0, 0, 0, 0, 0, 0, 0, 0,
    +-  0, 0, 0, 0, 0, 0, 0, 0,     0, 0, 0, 0, 0, 0, 0, 0,
    +-  0, 0, 0, 0, 0, 0, 0, 0,     0, 0, 0, 0, 0, 0, 0, 0,
    +-  0, 0, 0, 0, 0, 0, 0, 0,     0, 0, 0, 0, 0, 0, 0, 0,
    +-  0, 0, 0, 0, 0, 0, 0, 0,     0, 0, 0, 0, 0, 0, 0, 0,
    +-  0, 0, 0, 0, 0, 0, 0, 0,     0, 0, 0, 0, 0, 0, 0, 0,
    +-  0, 0, 0, 0, 0, 0, 0, 0,     0, 0, 0, 0, 0, 0, 0, 0,
    +-  0, 0, 0, 0, 0, 0, 0, 0,     0, 0, 0, 0, 0, 0, 0, 0,
    +-  0, 0, 0, 0, 0, 0, 0, 0,     0, 0, 0, 0, 0, 0, 0, 0,
    +-  0, 0, 0, 0, 0, 0, 0, 0,     0, 0, 0, 0, 0, 0, 0, 0,
    +-  0, 0, 0, 0, 0, 0, 0, 0,     0, 0, 0, 0, 0, 0, 0, 0,
    +-  0, 0, 0, 0, 0, 0, 0, 0,     0, 0, 0, 0, 0, 0, 0, 0,
    +-  0, 0, 0, 0, 0, 0, 0, 0,     0, 0, 0, 0, 0, 0, 0, 0,
    +-  0, 0, 0, 0, 0, 0, 0, 0,     0, 0, 0, 0, 0, 0, 0, 0,
    ++struct DbpageCursor {
    ++  sqlite3_vtab_cursor base;       /* Base class.  Must be first */
    ++  int pgno;                       /* Current page number */
    ++  int mxPgno;                     /* Last page to visit on this scan */
    ++  Pager *pPager;                  /* Pager being read/written */
    ++  DbPage *pPage1;                 /* Page 1 of the database */
    ++  int iDb;                        /* Index of database to analyze */
    ++  int szPage;                     /* Size of each page in bytes */
    + };
    +-#define safe_isspace(x) (jsonIsSpace[(unsigned char)x])
    +-
    +-#ifndef SQLITE_AMALGAMATION
    +-  /* Unsigned integer types.  These are already defined in the sqliteInt.h,
    +-  ** but the definitions need to be repeated for separate compilation. */
    +-  typedef sqlite3_uint64 u64;
    +-  typedef unsigned int u32;
    +-  typedef unsigned char u8;
    +-#endif
    + 
    +-/* Objects */
    +-typedef struct JsonString JsonString;
    +-typedef struct JsonNode JsonNode;
    +-typedef struct JsonParse JsonParse;
    +-
    +-/* An instance of this object represents a JSON string
    +-** under construction.  Really, this is a generic string accumulator
    +-** that can be and is used to create strings other than JSON.
    +-*/
    +-struct JsonString {
    +-  sqlite3_context *pCtx;   /* Function context - put error messages here */
    +-  char *zBuf;              /* Append JSON content here */
    +-  u64 nAlloc;              /* Bytes of storage available in zBuf[] */
    +-  u64 nUsed;               /* Bytes of zBuf[] currently used */
    +-  u8 bStatic;              /* True if zBuf is static space */
    +-  u8 bErr;                 /* True if an error has been encountered */
    +-  char zSpace[100];        /* Initial static space */
    ++struct DbpageTable {
    ++  sqlite3_vtab base;              /* Base class.  Must be first */
    ++  sqlite3 *db;                    /* The database */
    + };
    + 
    +-/* JSON type values
    +-*/
    +-#define JSON_NULL     0
    +-#define JSON_TRUE     1
    +-#define JSON_FALSE    2
    +-#define JSON_INT      3
    +-#define JSON_REAL     4
    +-#define JSON_STRING   5
    +-#define JSON_ARRAY    6
    +-#define JSON_OBJECT   7
    ++/* Columns */
    ++#define DBPAGE_COLUMN_PGNO    0
    ++#define DBPAGE_COLUMN_DATA    1
    ++#define DBPAGE_COLUMN_SCHEMA  2
    + 
    +-/* The "subtype" set for JSON values */
    +-#define JSON_SUBTYPE  74    /* Ascii for "J" */
    + 
    +-/*
    +-** Names of the various JSON types:
    +-*/
    +-static const char * const jsonType[] = {
    +-  "null", "true", "false", "integer", "real", "text", "array", "object"
    +-};
    + 
    +-/* Bit values for the JsonNode.jnFlag field
    ++/*
    ++** Connect to or create a dbpagevfs virtual table.
    + */
    +-#define JNODE_RAW     0x01         /* Content is raw, not JSON encoded */
    +-#define JNODE_ESCAPE  0x02         /* Content is text with \ escapes */
    +-#define JNODE_REMOVE  0x04         /* Do not output */
    +-#define JNODE_REPLACE 0x08         /* Replace with JsonNode.iVal */
    +-#define JNODE_APPEND  0x10         /* More ARRAY/OBJECT entries at u.iAppend */
    +-#define JNODE_LABEL   0x20         /* Is a label of an object */
    +-
    ++static int dbpageConnect(
    ++  sqlite3 *db,
    ++  void *pAux,
    ++  int argc, const char *const*argv,
    ++  sqlite3_vtab **ppVtab,
    ++  char **pzErr
    ++){
    ++  DbpageTable *pTab = 0;
    ++  int rc = SQLITE_OK;
    + 
    +-/* A single node of parsed JSON
    +-*/
    +-struct JsonNode {
    +-  u8 eType;              /* One of the JSON_ type values */
    +-  u8 jnFlags;            /* JNODE flags */
    +-  u8 iVal;               /* Replacement value when JNODE_REPLACE */
    +-  u32 n;                 /* Bytes of content, or number of sub-nodes */
    +-  union {
    +-    const char *zJContent; /* Content for INT, REAL, and STRING */
    +-    u32 iAppend;           /* More terms for ARRAY and OBJECT */
    +-    u32 iKey;              /* Key for ARRAY objects in json_tree() */
    +-  } u;
    +-};
    ++  rc = sqlite3_declare_vtab(db, 
    ++          "CREATE TABLE x(pgno INTEGER PRIMARY KEY, data BLOB, schema HIDDEN)");
    ++  if( rc==SQLITE_OK ){
    ++    pTab = (DbpageTable *)sqlite3_malloc64(sizeof(DbpageTable));
    ++    if( pTab==0 ) rc = SQLITE_NOMEM_BKPT;
    ++  }
    + 
    +-/* A completely parsed JSON string
    +-*/
    +-struct JsonParse {
    +-  u32 nNode;         /* Number of slots of aNode[] used */
    +-  u32 nAlloc;        /* Number of slots of aNode[] allocated */
    +-  JsonNode *aNode;   /* Array of nodes containing the parse */
    +-  const char *zJson; /* Original JSON string */
    +-  u32 *aUp;          /* Index of parent of each node */
    +-  u8 oom;            /* Set to true if out of memory */
    +-  u8 nErr;           /* Number of errors seen */
    +-};
    ++  assert( rc==SQLITE_OK || pTab==0 );
    ++  if( rc==SQLITE_OK ){
    ++    memset(pTab, 0, sizeof(DbpageTable));
    ++    pTab->db = db;
    ++  }
    + 
    +-/**************************************************************************
    +-** Utility routines for dealing with JsonString objects
    +-**************************************************************************/
    ++  *ppVtab = (sqlite3_vtab*)pTab;
    ++  return rc;
    ++}
    + 
    +-/* Set the JsonString object to an empty string
    ++/*
    ++** Disconnect from or destroy a dbpagevfs virtual table.
    + */
    +-static void jsonZero(JsonString *p){
    +-  p->zBuf = p->zSpace;
    +-  p->nAlloc = sizeof(p->zSpace);
    +-  p->nUsed = 0;
    +-  p->bStatic = 1;
    ++static int dbpageDisconnect(sqlite3_vtab *pVtab){
    ++  sqlite3_free(pVtab);
    ++  return SQLITE_OK;
    + }
    + 
    +-/* Initialize the JsonString object
    ++/*
    ++** idxNum:
    ++**
    ++**     0     schema=main, full table scan
    ++**     1     schema=main, pgno=?1
    ++**     2     schema=?1, full table scan
    ++**     3     schema=?1, pgno=?2
    + */
    +-static void jsonInit(JsonString *p, sqlite3_context *pCtx){
    +-  p->pCtx = pCtx;
    +-  p->bErr = 0;
    +-  jsonZero(p);
    +-}
    ++static int dbpageBestIndex(sqlite3_vtab *tab, sqlite3_index_info *pIdxInfo){
    ++  int i;
    ++  int iPlan = 0;
    + 
    ++  /* If there is a schema= constraint, it must be honored.  Report a
    ++  ** ridiculously large estimated cost if the schema= constraint is
    ++  ** unavailable
    ++  */
    ++  for(i=0; i<pIdxInfo->nConstraint; i++){
    ++    struct sqlite3_index_constraint *p = &pIdxInfo->aConstraint[i];
    ++    if( p->iColumn!=DBPAGE_COLUMN_SCHEMA ) continue;
    ++    if( p->op!=SQLITE_INDEX_CONSTRAINT_EQ ) continue;
    ++    if( !p->usable ){
    ++      /* No solution.  Use the default SQLITE_BIG_DBL cost */
    ++      pIdxInfo->estimatedRows = 0x7fffffff;
    ++      return SQLITE_OK;
    ++    }
    ++    iPlan = 2;
    ++    pIdxInfo->aConstraintUsage[i].argvIndex = 1;
    ++    pIdxInfo->aConstraintUsage[i].omit = 1;
    ++    break;
    ++  }
    + 
    +-/* Free all allocated memory and reset the JsonString object back to its
    +-** initial state.
    +-*/
    +-static void jsonReset(JsonString *p){
    +-  if( !p->bStatic ) sqlite3_free(p->zBuf);
    +-  jsonZero(p);
    +-}
    ++  /* If we reach this point, it means that either there is no schema=
    ++  ** constraint (in which case we use the "main" schema) or else the
    ++  ** schema constraint was accepted.  Lower the estimated cost accordingly
    ++  */
    ++  pIdxInfo->estimatedCost = 1.0e6;
    + 
    ++  /* Check for constraints against pgno */
    ++  for(i=0; i<pIdxInfo->nConstraint; i++){
    ++    struct sqlite3_index_constraint *p = &pIdxInfo->aConstraint[i];
    ++    if( p->usable && p->iColumn<=0 && p->op==SQLITE_INDEX_CONSTRAINT_EQ ){
    ++      pIdxInfo->estimatedRows = 1;
    ++      pIdxInfo->idxFlags = SQLITE_INDEX_SCAN_UNIQUE;
    ++      pIdxInfo->estimatedCost = 1.0;
    ++      pIdxInfo->aConstraintUsage[i].argvIndex = iPlan ? 2 : 1;
    ++      pIdxInfo->aConstraintUsage[i].omit = 1;
    ++      iPlan |= 1;
    ++      break;
    ++    }
    ++  }
    ++  pIdxInfo->idxNum = iPlan;
    + 
    +-/* Report an out-of-memory (OOM) condition 
    +-*/
    +-static void jsonOom(JsonString *p){
    +-  p->bErr = 1;
    +-  sqlite3_result_error_nomem(p->pCtx);
    +-  jsonReset(p);
    ++  if( pIdxInfo->nOrderBy>=1
    ++   && pIdxInfo->aOrderBy[0].iColumn<=0
    ++   && pIdxInfo->aOrderBy[0].desc==0
    ++  ){
    ++    pIdxInfo->orderByConsumed = 1;
    ++  }
    ++  return SQLITE_OK;
    + }
    + 
    +-/* Enlarge pJson->zBuf so that it can hold at least N more bytes.
    +-** Return zero on success.  Return non-zero on an OOM error
    ++/*
    ++** Open a new dbpagevfs cursor.
    + */
    +-static int jsonGrow(JsonString *p, u32 N){
    +-  u64 nTotal = N<p->nAlloc ? p->nAlloc*2 : p->nAlloc+N+10;
    +-  char *zNew;
    +-  if( p->bStatic ){
    +-    if( p->bErr ) return 1;
    +-    zNew = sqlite3_malloc64(nTotal);
    +-    if( zNew==0 ){
    +-      jsonOom(p);
    +-      return SQLITE_NOMEM;
    +-    }
    +-    memcpy(zNew, p->zBuf, (size_t)p->nUsed);
    +-    p->zBuf = zNew;
    +-    p->bStatic = 0;
    ++static int dbpageOpen(sqlite3_vtab *pVTab, sqlite3_vtab_cursor **ppCursor){
    ++  DbpageCursor *pCsr;
    ++
    ++  pCsr = (DbpageCursor *)sqlite3_malloc64(sizeof(DbpageCursor));
    ++  if( pCsr==0 ){
    ++    return SQLITE_NOMEM_BKPT;
    +   }else{
    +-    zNew = sqlite3_realloc64(p->zBuf, nTotal);
    +-    if( zNew==0 ){
    +-      jsonOom(p);
    +-      return SQLITE_NOMEM;
    +-    }
    +-    p->zBuf = zNew;
    ++    memset(pCsr, 0, sizeof(DbpageCursor));
    ++    pCsr->base.pVtab = pVTab;
    ++    pCsr->pgno = -1;
    +   }
    +-  p->nAlloc = nTotal;
    ++
    ++  *ppCursor = (sqlite3_vtab_cursor *)pCsr;
    +   return SQLITE_OK;
    + }
    + 
    +-/* Append N bytes from zIn onto the end of the JsonString string.
    ++/*
    ++** Close a dbpagevfs cursor.
    + */
    +-static void jsonAppendRaw(JsonString *p, const char *zIn, u32 N){
    +-  if( (N+p->nUsed >= p->nAlloc) && jsonGrow(p,N)!=0 ) return;
    +-  memcpy(p->zBuf+p->nUsed, zIn, N);
    +-  p->nUsed += N;
    ++static int dbpageClose(sqlite3_vtab_cursor *pCursor){
    ++  DbpageCursor *pCsr = (DbpageCursor *)pCursor;
    ++  if( pCsr->pPage1 ) sqlite3PagerUnrefPageOne(pCsr->pPage1);
    ++  sqlite3_free(pCsr);
    ++  return SQLITE_OK;
    + }
    + 
    +-/* Append formatted text (not to exceed N bytes) to the JsonString.
    ++/*
    ++** Move a dbpagevfs cursor to the next entry in the file.
    + */
    +-static void jsonPrintf(int N, JsonString *p, const char *zFormat, ...){
    +-  va_list ap;
    +-  if( (p->nUsed + N >= p->nAlloc) && jsonGrow(p, N) ) return;
    +-  va_start(ap, zFormat);
    +-  sqlite3_vsnprintf(N, p->zBuf+p->nUsed, zFormat, ap);
    +-  va_end(ap);
    +-  p->nUsed += (int)strlen(p->zBuf+p->nUsed);
    ++static int dbpageNext(sqlite3_vtab_cursor *pCursor){
    ++  int rc = SQLITE_OK;
    ++  DbpageCursor *pCsr = (DbpageCursor *)pCursor;
    ++  pCsr->pgno++;
    ++  return rc;
    + }
    + 
    +-/* Append a single character
    +-*/
    +-static void jsonAppendChar(JsonString *p, char c){
    +-  if( p->nUsed>=p->nAlloc && jsonGrow(p,1)!=0 ) return;
    +-  p->zBuf[p->nUsed++] = c;
    ++static int dbpageEof(sqlite3_vtab_cursor *pCursor){
    ++  DbpageCursor *pCsr = (DbpageCursor *)pCursor;
    ++  return pCsr->pgno > pCsr->mxPgno;
    + }
    + 
    +-/* Append a comma separator to the output buffer, if the previous
    +-** character is not '[' or '{'.
    ++/*
    ++** idxNum:
    ++**
    ++**     0     schema=main, full table scan
    ++**     1     schema=main, pgno=?1
    ++**     2     schema=?1, full table scan
    ++**     3     schema=?1, pgno=?2
    ++**
    ++** idxStr is not used
    + */
    +-static void jsonAppendSeparator(JsonString *p){
    +-  char c;
    +-  if( p->nUsed==0 ) return;
    +-  c = p->zBuf[p->nUsed-1];
    +-  if( c!='[' && c!='{' ) jsonAppendChar(p, ',');
    +-}
    ++static int dbpageFilter(
    ++  sqlite3_vtab_cursor *pCursor, 
    ++  int idxNum, const char *idxStr,
    ++  int argc, sqlite3_value **argv
    ++){
    ++  DbpageCursor *pCsr = (DbpageCursor *)pCursor;
    ++  DbpageTable *pTab = (DbpageTable *)pCursor->pVtab;
    ++  int rc;
    ++  sqlite3 *db = pTab->db;
    ++  Btree *pBt;
    + 
    +-/* Append the N-byte string in zIn to the end of the JsonString string
    +-** under construction.  Enclose the string in "..." and escape
    +-** any double-quotes or backslash characters contained within the
    +-** string.
    +-*/
    +-static void jsonAppendString(JsonString *p, const char *zIn, u32 N){
    +-  u32 i;
    +-  if( (N+p->nUsed+2 >= p->nAlloc) && jsonGrow(p,N+2)!=0 ) return;
    +-  p->zBuf[p->nUsed++] = '"';
    +-  for(i=0; i<N; i++){
    +-    char c = zIn[i];
    +-    if( c=='"' || c=='\\' ){
    +-      if( (p->nUsed+N+3-i > p->nAlloc) && jsonGrow(p,N+3-i)!=0 ) return;
    +-      p->zBuf[p->nUsed++] = '\\';
    ++  /* Default setting is no rows of result */
    ++  pCsr->pgno = 1; 
    ++  pCsr->mxPgno = 0;
    ++
    ++  if( idxNum & 2 ){
    ++    const char *zSchema;
    ++    assert( argc>=1 );
    ++    zSchema = (const char*)sqlite3_value_text(argv[0]);
    ++    pCsr->iDb = sqlite3FindDbName(db, zSchema);
    ++    if( pCsr->iDb<0 ) return SQLITE_OK;
    ++  }else{
    ++    pCsr->iDb = 0;
    ++  }
    ++  pBt = db->aDb[pCsr->iDb].pBt;
    ++  if( pBt==0 ) return SQLITE_OK;
    ++  pCsr->pPager = sqlite3BtreePager(pBt);
    ++  pCsr->szPage = sqlite3BtreeGetPageSize(pBt);
    ++  pCsr->mxPgno = sqlite3BtreeLastPage(pBt);
    ++  if( idxNum & 1 ){
    ++    assert( argc>(idxNum>>1) );
    ++    pCsr->pgno = sqlite3_value_int(argv[idxNum>>1]);
    ++    if( pCsr->pgno<1 || pCsr->pgno>pCsr->mxPgno ){
    ++      pCsr->pgno = 1;
    ++      pCsr->mxPgno = 0;
    ++    }else{
    ++      pCsr->mxPgno = pCsr->pgno;
    +     }
    +-    p->zBuf[p->nUsed++] = c;
    ++  }else{
    ++    assert( pCsr->pgno==1 );
    +   }
    +-  p->zBuf[p->nUsed++] = '"';
    +-  assert( p->nUsed<p->nAlloc );
    ++  if( pCsr->pPage1 ) sqlite3PagerUnrefPageOne(pCsr->pPage1);
    ++  rc = sqlite3PagerGet(pCsr->pPager, 1, &pCsr->pPage1, 0);
    ++  return rc;
    + }
    + 
    +-/*
    +-** Append a function parameter value to the JSON string under 
    +-** construction.
    +-*/
    +-static void jsonAppendValue(
    +-  JsonString *p,                 /* Append to this JSON string */
    +-  sqlite3_value *pValue          /* Value to append */
    ++static int dbpageColumn(
    ++  sqlite3_vtab_cursor *pCursor, 
    ++  sqlite3_context *ctx, 
    ++  int i
    + ){
    +-  switch( sqlite3_value_type(pValue) ){
    +-    case SQLITE_NULL: {
    +-      jsonAppendRaw(p, "null", 4);
    +-      break;
    +-    }
    +-    case SQLITE_INTEGER:
    +-    case SQLITE_FLOAT: {
    +-      const char *z = (const char*)sqlite3_value_text(pValue);
    +-      u32 n = (u32)sqlite3_value_bytes(pValue);
    +-      jsonAppendRaw(p, z, n);
    ++  DbpageCursor *pCsr = (DbpageCursor *)pCursor;
    ++  int rc = SQLITE_OK;
    ++  switch( i ){
    ++    case 0: {           /* pgno */
    ++      sqlite3_result_int(ctx, pCsr->pgno);
    +       break;
    +     }
    +-    case SQLITE_TEXT: {
    +-      const char *z = (const char*)sqlite3_value_text(pValue);
    +-      u32 n = (u32)sqlite3_value_bytes(pValue);
    +-      if( sqlite3_value_subtype(pValue)==JSON_SUBTYPE ){
    +-        jsonAppendRaw(p, z, n);
    +-      }else{
    +-        jsonAppendString(p, z, n);
    ++    case 1: {           /* data */
    ++      DbPage *pDbPage = 0;
    ++      rc = sqlite3PagerGet(pCsr->pPager, pCsr->pgno, (DbPage**)&pDbPage, 0);
    ++      if( rc==SQLITE_OK ){
    ++        sqlite3_result_blob(ctx, sqlite3PagerGetData(pDbPage), pCsr->szPage,
    ++                            SQLITE_TRANSIENT);
    +       }
    ++      sqlite3PagerUnref(pDbPage);
    +       break;
    +     }
    +-    default: {
    +-      if( p->bErr==0 ){
    +-        sqlite3_result_error(p->pCtx, "JSON cannot hold BLOB values", -1);
    +-        p->bErr = 1;
    +-        jsonReset(p);
    +-      }
    ++    default: {          /* schema */
    ++      sqlite3 *db = sqlite3_context_db_handle(ctx);
    ++      sqlite3_result_text(ctx, db->aDb[pCsr->iDb].zDbSName, -1, SQLITE_STATIC);
    +       break;
    +     }
    +   }
    ++  return SQLITE_OK;
    + }
    + 
    ++static int dbpageRowid(sqlite3_vtab_cursor *pCursor, sqlite_int64 *pRowid){
    ++  DbpageCursor *pCsr = (DbpageCursor *)pCursor;
    ++  *pRowid = pCsr->pgno;
    ++  return SQLITE_OK;
    ++}
    + 
    +-/* Make the JSON in p the result of the SQL function.
    ++static int dbpageUpdate(
    ++  sqlite3_vtab *pVtab,
    ++  int argc,
    ++  sqlite3_value **argv,
    ++  sqlite_int64 *pRowid
    ++){
    ++  DbpageTable *pTab = (DbpageTable *)pVtab;
    ++  Pgno pgno;
    ++  DbPage *pDbPage = 0;
    ++  int rc = SQLITE_OK;
    ++  char *zErr = 0;
    ++  const char *zSchema;
    ++  int iDb;
    ++  Btree *pBt;
    ++  Pager *pPager;
    ++  int szPage;
    ++
    ++  if( argc==1 ){
    ++    zErr = "cannot delete";
    ++    goto update_fail;
    ++  }
    ++  pgno = sqlite3_value_int(argv[0]);
    ++  if( (Pgno)sqlite3_value_int(argv[1])!=pgno ){
    ++    zErr = "cannot insert";
    ++    goto update_fail;
    ++  }
    ++  zSchema = (const char*)sqlite3_value_text(argv[4]);
    ++  iDb = zSchema ? sqlite3FindDbName(pTab->db, zSchema) : -1;
    ++  if( iDb<0 ){
    ++    zErr = "no such schema";
    ++    goto update_fail;
    ++  }
    ++  pBt = pTab->db->aDb[iDb].pBt;
    ++  if( pgno<1 || pBt==0 || pgno>(int)sqlite3BtreeLastPage(pBt) ){
    ++    zErr = "bad page number";
    ++    goto update_fail;
    ++  }
    ++  szPage = sqlite3BtreeGetPageSize(pBt);
    ++  if( sqlite3_value_type(argv[3])!=SQLITE_BLOB 
    ++   || sqlite3_value_bytes(argv[3])!=szPage
    ++  ){
    ++    zErr = "bad page value";
    ++    goto update_fail;
    ++  }
    ++  pPager = sqlite3BtreePager(pBt);
    ++  rc = sqlite3PagerGet(pPager, pgno, (DbPage**)&pDbPage, 0);
    ++  if( rc==SQLITE_OK ){
    ++    rc = sqlite3PagerWrite(pDbPage);
    ++    if( rc==SQLITE_OK ){
    ++      memcpy(sqlite3PagerGetData(pDbPage),
    ++             sqlite3_value_blob(argv[3]),
    ++             szPage);
    ++    }
    ++  }
    ++  sqlite3PagerUnref(pDbPage);
    ++  return rc;
    ++
    ++update_fail:
    ++  sqlite3_free(pVtab->zErrMsg);
    ++  pVtab->zErrMsg = sqlite3_mprintf("%s", zErr);
    ++  return SQLITE_ERROR;
    ++}
    ++
    ++/* Since we do not know in advance which database files will be
    ++** written by the sqlite_dbpage virtual table, start a write transaction
    ++** on them all.
    + */
    +-static void jsonResult(JsonString *p){
    +-  if( p->bErr==0 ){
    +-    sqlite3_result_text64(p->pCtx, p->zBuf, p->nUsed, 
    +-                          p->bStatic ? SQLITE_TRANSIENT : sqlite3_free,
    +-                          SQLITE_UTF8);
    +-    jsonZero(p);
    ++static int dbpageBegin(sqlite3_vtab *pVtab){
    ++  DbpageTable *pTab = (DbpageTable *)pVtab;
    ++  sqlite3 *db = pTab->db;
    ++  int i;
    ++  for(i=0; i<db->nDb; i++){
    ++    Btree *pBt = db->aDb[i].pBt;
    ++    if( pBt ) sqlite3BtreeBeginTrans(pBt, 1);
    +   }
    +-  assert( p->bStatic );
    ++  return SQLITE_OK;
    + }
    + 
    +-/**************************************************************************
    +-** Utility routines for dealing with JsonNode and JsonParse objects
    +-**************************************************************************/
    + 
    + /*
    +-** Return the number of consecutive JsonNode slots need to represent
    +-** the parsed JSON at pNode.  The minimum answer is 1.  For ARRAY and
    +-** OBJECT types, the number might be larger.
    ++** Invoke this routine to register the "dbpage" virtual table module
    ++*/
    ++SQLITE_PRIVATE int sqlite3DbpageRegister(sqlite3 *db){
    ++  static sqlite3_module dbpage_module = {
    ++    0,                            /* iVersion */
    ++    dbpageConnect,                /* xCreate */
    ++    dbpageConnect,                /* xConnect */
    ++    dbpageBestIndex,              /* xBestIndex */
    ++    dbpageDisconnect,             /* xDisconnect */
    ++    dbpageDisconnect,             /* xDestroy */
    ++    dbpageOpen,                   /* xOpen - open a cursor */
    ++    dbpageClose,                  /* xClose - close a cursor */
    ++    dbpageFilter,                 /* xFilter - configure scan constraints */
    ++    dbpageNext,                   /* xNext - advance a cursor */
    ++    dbpageEof,                    /* xEof - check for end of scan */
    ++    dbpageColumn,                 /* xColumn - read data */
    ++    dbpageRowid,                  /* xRowid - read data */
    ++    dbpageUpdate,                 /* xUpdate */
    ++    dbpageBegin,                  /* xBegin */
    ++    0,                            /* xSync */
    ++    0,                            /* xCommit */
    ++    0,                            /* xRollback */
    ++    0,                            /* xFindMethod */
    ++    0,                            /* xRename */
    ++    0,                            /* xSavepoint */
    ++    0,                            /* xRelease */
    ++    0,                            /* xRollbackTo */
    ++  };
    ++  return sqlite3_create_module(db, "sqlite_dbpage", &dbpage_module, 0);
    ++}
    ++#elif defined(SQLITE_ENABLE_DBPAGE_VTAB)
    ++SQLITE_PRIVATE int sqlite3DbpageRegister(sqlite3 *db){ return SQLITE_OK; }
    ++#endif /* SQLITE_ENABLE_DBSTAT_VTAB */
    ++
    ++/************** End of dbpage.c **********************************************/
    ++/************** Begin file sqlite3session.c **********************************/
    ++
    ++#if defined(SQLITE_ENABLE_SESSION) && defined(SQLITE_ENABLE_PREUPDATE_HOOK)
    ++/* #include "sqlite3session.h" */
    ++/* #include <assert.h> */
    ++/* #include <string.h> */
    ++
    ++#ifndef SQLITE_AMALGAMATION
    ++/* # include "sqliteInt.h" */
    ++/* # include "vdbeInt.h" */
    ++#endif
    ++
    ++typedef struct SessionTable SessionTable;
    ++typedef struct SessionChange SessionChange;
    ++typedef struct SessionBuffer SessionBuffer;
    ++typedef struct SessionInput SessionInput;
    ++
    ++/*
    ++** Minimum chunk size used by streaming versions of functions.
    ++*/
    ++#ifndef SESSIONS_STRM_CHUNK_SIZE
    ++# ifdef SQLITE_TEST
    ++#   define SESSIONS_STRM_CHUNK_SIZE 64
    ++# else
    ++#   define SESSIONS_STRM_CHUNK_SIZE 1024
    ++# endif
    ++#endif
    ++
    ++typedef struct SessionHook SessionHook;
    ++struct SessionHook {
    ++  void *pCtx;
    ++  int (*xOld)(void*,int,sqlite3_value**);
    ++  int (*xNew)(void*,int,sqlite3_value**);
    ++  int (*xCount)(void*);
    ++  int (*xDepth)(void*);
    ++};
    ++
    ++/*
    ++** Session handle structure.
    ++*/
    ++struct sqlite3_session {
    ++  sqlite3 *db;                    /* Database handle session is attached to */
    ++  char *zDb;                      /* Name of database session is attached to */
    ++  int bEnable;                    /* True if currently recording */
    ++  int bIndirect;                  /* True if all changes are indirect */
    ++  int bAutoAttach;                /* True to auto-attach tables */
    ++  int rc;                         /* Non-zero if an error has occurred */
    ++  void *pFilterCtx;               /* First argument to pass to xTableFilter */
    ++  int (*xTableFilter)(void *pCtx, const char *zTab);
    ++  sqlite3_value *pZeroBlob;       /* Value containing X'' */
    ++  sqlite3_session *pNext;         /* Next session object on same db. */
    ++  SessionTable *pTable;           /* List of attached tables */
    ++  SessionHook hook;               /* APIs to grab new and old data with */
    ++};
    ++
    ++/*
    ++** Instances of this structure are used to build strings or binary records.
    ++*/
    ++struct SessionBuffer {
    ++  u8 *aBuf;                       /* Pointer to changeset buffer */
    ++  int nBuf;                       /* Size of buffer aBuf */
    ++  int nAlloc;                     /* Size of allocation containing aBuf */
    ++};
    ++
    ++/*
    ++** An object of this type is used internally as an abstraction for 
    ++** input data. Input data may be supplied either as a single large buffer
    ++** (e.g. sqlite3changeset_start()) or using a stream function (e.g.
    ++**  sqlite3changeset_start_strm()).
    ++*/
    ++struct SessionInput {
    ++  int bNoDiscard;                 /* If true, discard no data */
    ++  int iCurrent;                   /* Offset in aData[] of current change */
    ++  int iNext;                      /* Offset in aData[] of next change */
    ++  u8 *aData;                      /* Pointer to buffer containing changeset */
    ++  int nData;                      /* Number of bytes in aData */
    ++
    ++  SessionBuffer buf;              /* Current read buffer */
    ++  int (*xInput)(void*, void*, int*);        /* Input stream call (or NULL) */
    ++  void *pIn;                                /* First argument to xInput */
    ++  int bEof;                       /* Set to true after xInput finished */
    ++};
    ++
    ++/*
    ++** Structure for changeset iterators.
    ++*/
    ++struct sqlite3_changeset_iter {
    ++  SessionInput in;                /* Input buffer or stream */
    ++  SessionBuffer tblhdr;           /* Buffer to hold apValue/zTab/abPK/ */
    ++  int bPatchset;                  /* True if this is a patchset */
    ++  int rc;                         /* Iterator error code */
    ++  sqlite3_stmt *pConflict;        /* Points to conflicting row, if any */
    ++  char *zTab;                     /* Current table */
    ++  int nCol;                       /* Number of columns in zTab */
    ++  int op;                         /* Current operation */
    ++  int bIndirect;                  /* True if current change was indirect */
    ++  u8 *abPK;                       /* Primary key array */
    ++  sqlite3_value **apValue;        /* old.* and new.* values */
    ++};
    ++
    ++/*
    ++** Each session object maintains a set of the following structures, one
    ++** for each table the session object is monitoring. The structures are
    ++** stored in a linked list starting at sqlite3_session.pTable.
    + **
    +-** Appended elements are not counted.  The value returned is the number
    +-** by which the JsonNode counter should increment in order to go to the
    +-** next peer value.
    ++** The keys of the SessionTable.aChange[] hash table are all rows that have
    ++** been modified in any way since the session object was attached to the
    ++** table.
    ++**
    ++** The data associated with each hash-table entry is a structure containing
    ++** a subset of the initial values that the modified row contained at the
    ++** start of the session. Or no initial values if the row was inserted.
    ++*/
    ++struct SessionTable {
    ++  SessionTable *pNext;
    ++  char *zName;                    /* Local name of table */
    ++  int nCol;                       /* Number of columns in table zName */
    ++  int bStat1;                     /* True if this is sqlite_stat1 */
    ++  const char **azCol;             /* Column names */
    ++  u8 *abPK;                       /* Array of primary key flags */
    ++  int nEntry;                     /* Total number of entries in hash table */
    ++  int nChange;                    /* Size of apChange[] array */
    ++  SessionChange **apChange;       /* Hash table buckets */
    ++};
    ++
    ++/* 
    ++** RECORD FORMAT:
    ++**
    ++** The following record format is similar to (but not compatible with) that 
    ++** used in SQLite database files. This format is used as part of the 
    ++** change-set binary format, and so must be architecture independent.
    ++**
    ++** Unlike the SQLite database record format, each field is self-contained -
    ++** there is no separation of header and data. Each field begins with a
    ++** single byte describing its type, as follows:
    ++**
    ++**       0x00: Undefined value.
    ++**       0x01: Integer value.
    ++**       0x02: Real value.
    ++**       0x03: Text value.
    ++**       0x04: Blob value.
    ++**       0x05: SQL NULL value.
    ++**
    ++** Note that the above match the definitions of SQLITE_INTEGER, SQLITE_TEXT
    ++** and so on in sqlite3.h. For undefined and NULL values, the field consists
    ++** only of the single type byte. For other types of values, the type byte
    ++** is followed by:
    ++**
    ++**   Text values:
    ++**     A varint containing the number of bytes in the value (encoded using
    ++**     UTF-8). Followed by a buffer containing the UTF-8 representation
    ++**     of the text value. There is no nul terminator.
    ++**
    ++**   Blob values:
    ++**     A varint containing the number of bytes in the value, followed by
    ++**     a buffer containing the value itself.
    ++**
    ++**   Integer values:
    ++**     An 8-byte big-endian integer value.
    ++**
    ++**   Real values:
    ++**     An 8-byte big-endian IEEE 754-2008 real value.
    ++**
    ++** Varint values are encoded in the same way as varints in the SQLite 
    ++** record format.
    ++**
    ++** CHANGESET FORMAT:
    ++**
    ++** A changeset is a collection of DELETE, UPDATE and INSERT operations on
    ++** one or more tables. Operations on a single table are grouped together,
    ++** but may occur in any order (i.e. deletes, updates and inserts are all
    ++** mixed together).
    ++**
    ++** Each group of changes begins with a table header:
    ++**
    ++**   1 byte: Constant 0x54 (capital 'T')
    ++**   Varint: Number of columns in the table.
    ++**   nCol bytes: 0x01 for PK columns, 0x00 otherwise.
    ++**   N bytes: Unqualified table name (encoded using UTF-8). Nul-terminated.
    ++**
    ++** Followed by one or more changes to the table.
    ++**
    ++**   1 byte: Either SQLITE_INSERT (0x12), UPDATE (0x17) or DELETE (0x09).
    ++**   1 byte: The "indirect-change" flag.
    ++**   old.* record: (delete and update only)
    ++**   new.* record: (insert and update only)
    ++**
    ++** The "old.*" and "new.*" records, if present, are N field records in the
    ++** format described above under "RECORD FORMAT", where N is the number of
    ++** columns in the table. The i'th field of each record is associated with
    ++** the i'th column of the table, counting from left to right in the order
    ++** in which columns were declared in the CREATE TABLE statement.
    ++**
    ++** The new.* record that is part of each INSERT change contains the values
    ++** that make up the new row. Similarly, the old.* record that is part of each
    ++** DELETE change contains the values that made up the row that was deleted 
    ++** from the database. In the changeset format, the records that are part
    ++** of INSERT or DELETE changes never contain any undefined (type byte 0x00)
    ++** fields.
    ++**
    ++** Within the old.* record associated with an UPDATE change, all fields
    ++** associated with table columns that are not PRIMARY KEY columns and are
    ++** not modified by the UPDATE change are set to "undefined". Other fields
    ++** are set to the values that made up the row before the UPDATE that the
    ++** change records took place. Within the new.* record, fields associated 
    ++** with table columns modified by the UPDATE change contain the new 
    ++** values. Fields associated with table columns that are not modified
    ++** are set to "undefined".
    ++**
    ++** PATCHSET FORMAT:
    ++**
    ++** A patchset is also a collection of changes. It is similar to a changeset,
    ++** but leaves undefined those fields that are not useful if no conflict
    ++** resolution is required when applying the changeset.
    ++**
    ++** Each group of changes begins with a table header:
    ++**
    ++**   1 byte: Constant 0x50 (capital 'P')
    ++**   Varint: Number of columns in the table.
    ++**   nCol bytes: 0x01 for PK columns, 0x00 otherwise.
    ++**   N bytes: Unqualified table name (encoded using UTF-8). Nul-terminated.
    ++**
    ++** Followed by one or more changes to the table.
    ++**
    ++**   1 byte: Either SQLITE_INSERT (0x12), UPDATE (0x17) or DELETE (0x09).
    ++**   1 byte: The "indirect-change" flag.
    ++**   single record: (PK fields for DELETE, PK and modified fields for UPDATE,
    ++**                   full record for INSERT).
    ++**
    ++** As in the changeset format, each field of the single record that is part
    ++** of a patchset change is associated with the correspondingly positioned
    ++** table column, counting from left to right within the CREATE TABLE 
    ++** statement.
    ++**
    ++** For a DELETE change, all fields within the record except those associated
    ++** with PRIMARY KEY columns are set to "undefined". The PRIMARY KEY fields
    ++** contain the values identifying the row to delete.
    ++**
    ++** For an UPDATE change, all fields except those associated with PRIMARY KEY
    ++** columns and columns that are modified by the UPDATE are set to "undefined".
    ++** PRIMARY KEY fields contain the values identifying the table row to update,
    ++** and fields associated with modified columns contain the new column values.
    ++**
    ++** The records associated with INSERT changes are in the same format as for
    ++** changesets. It is not possible for a record associated with an INSERT
    ++** change to contain a field set to "undefined".
    + */
    +-static u32 jsonNodeSize(JsonNode *pNode){
    +-  return pNode->eType>=JSON_ARRAY ? pNode->n+1 : 1;
    ++
    ++/*
    ++** For each row modified during a session, there exists a single instance of
    ++** this structure stored in a SessionTable.aChange[] hash table.
    ++*/
    ++struct SessionChange {
    ++  int op;                         /* One of UPDATE, DELETE, INSERT */
    ++  int bIndirect;                  /* True if this change is "indirect" */
    ++  int nRecord;                    /* Number of bytes in buffer aRecord[] */
    ++  u8 *aRecord;                    /* Buffer containing old.* record */
    ++  SessionChange *pNext;           /* For hash-table collisions */
    ++};
    ++
    ++/*
    ++** Write a varint with value iVal into the buffer at aBuf. Return the 
    ++** number of bytes written.
    ++*/
    ++static int sessionVarintPut(u8 *aBuf, int iVal){
    ++  return putVarint32(aBuf, iVal);
    + }
    + 
    + /*
    +-** Reclaim all memory allocated by a JsonParse object.  But do not
    +-** delete the JsonParse object itself.
    ++** Return the number of bytes required to store value iVal as a varint.
    + */
    +-static void jsonParseReset(JsonParse *pParse){
    +-  sqlite3_free(pParse->aNode);
    +-  pParse->aNode = 0;
    +-  pParse->nNode = 0;
    +-  pParse->nAlloc = 0;
    +-  sqlite3_free(pParse->aUp);
    +-  pParse->aUp = 0;
    ++static int sessionVarintLen(int iVal){
    ++  return sqlite3VarintLen(iVal);
    + }
    + 
    + /*
    +-** Convert the JsonNode pNode into a pure JSON string and
    +-** append to pOut.  Subsubstructure is also included.  Return
    +-** the number of JsonNode objects that are encoded.
    ++** Read a varint value from aBuf[] into *piVal. Return the number of 
    ++** bytes read.
    + */
    +-static void jsonRenderNode(
    +-  JsonNode *pNode,               /* The node to render */
    +-  JsonString *pOut,              /* Write JSON here */
    +-  sqlite3_value **aReplace       /* Replacement values */
    ++static int sessionVarintGet(u8 *aBuf, int *piVal){
    ++  return getVarint32(aBuf, *piVal);
    ++}
    ++
    ++/* Load an unaligned and unsigned 32-bit integer */
    ++#define SESSION_UINT32(x) (((u32)(x)[0]<<24)|((x)[1]<<16)|((x)[2]<<8)|(x)[3])
    ++
    ++/*
    ++** Read a 64-bit big-endian integer value from buffer aRec[]. Return
    ++** the value read.
    ++*/
    ++static sqlite3_int64 sessionGetI64(u8 *aRec){
    ++  u64 x = SESSION_UINT32(aRec);
    ++  u32 y = SESSION_UINT32(aRec+4);
    ++  x = (x<<32) + y;
    ++  return (sqlite3_int64)x;
    ++}
    ++
    ++/*
    ++** Write a 64-bit big-endian integer value to the buffer aBuf[].
    ++*/
    ++static void sessionPutI64(u8 *aBuf, sqlite3_int64 i){
    ++  aBuf[0] = (i>>56) & 0xFF;
    ++  aBuf[1] = (i>>48) & 0xFF;
    ++  aBuf[2] = (i>>40) & 0xFF;
    ++  aBuf[3] = (i>>32) & 0xFF;
    ++  aBuf[4] = (i>>24) & 0xFF;
    ++  aBuf[5] = (i>>16) & 0xFF;
    ++  aBuf[6] = (i>> 8) & 0xFF;
    ++  aBuf[7] = (i>> 0) & 0xFF;
    ++}
    ++
    ++/*
    ++** This function is used to serialize the contents of value pValue (see
    ++** comment titled "RECORD FORMAT" above).
    ++**
    ++** If it is non-NULL, the serialized form of the value is written to 
    ++** buffer aBuf. *pnWrite is set to the number of bytes written before
    ++** returning. Or, if aBuf is NULL, the only thing this function does is
    ++** set *pnWrite.
    ++**
    ++** If no error occurs, SQLITE_OK is returned. Or, if an OOM error occurs
    ++** within a call to sqlite3_value_text() (may fail if the db is utf-16)) 
    ++** SQLITE_NOMEM is returned.
    ++*/
    ++static int sessionSerializeValue(
    ++  u8 *aBuf,                       /* If non-NULL, write serialized value here */
    ++  sqlite3_value *pValue,          /* Value to serialize */
    ++  int *pnWrite                    /* IN/OUT: Increment by bytes written */
    + ){
    +-  switch( pNode->eType ){
    +-    default: {
    +-      assert( pNode->eType==JSON_NULL );
    +-      jsonAppendRaw(pOut, "null", 4);
    +-      break;
    +-    }
    +-    case JSON_TRUE: {
    +-      jsonAppendRaw(pOut, "true", 4);
    +-      break;
    +-    }
    +-    case JSON_FALSE: {
    +-      jsonAppendRaw(pOut, "false", 5);
    +-      break;
    +-    }
    +-    case JSON_STRING: {
    +-      if( pNode->jnFlags & JNODE_RAW ){
    +-        jsonAppendString(pOut, pNode->u.zJContent, pNode->n);
    ++  int nByte;                      /* Size of serialized value in bytes */
    ++
    ++  if( pValue ){
    ++    int eType;                    /* Value type (SQLITE_NULL, TEXT etc.) */
    ++  
    ++    eType = sqlite3_value_type(pValue);
    ++    if( aBuf ) aBuf[0] = eType;
    ++  
    ++    switch( eType ){
    ++      case SQLITE_NULL: 
    ++        nByte = 1;
    +         break;
    +-      }
    +-      /* Fall through into the next case */
    +-    }
    +-    case JSON_REAL:
    +-    case JSON_INT: {
    +-      jsonAppendRaw(pOut, pNode->u.zJContent, pNode->n);
    +-      break;
    +-    }
    +-    case JSON_ARRAY: {
    +-      u32 j = 1;
    +-      jsonAppendChar(pOut, '[');
    +-      for(;;){
    +-        while( j<=pNode->n ){
    +-          if( pNode[j].jnFlags & (JNODE_REMOVE|JNODE_REPLACE) ){
    +-            if( pNode[j].jnFlags & JNODE_REPLACE ){
    +-              jsonAppendSeparator(pOut);
    +-              jsonAppendValue(pOut, aReplace[pNode[j].iVal]);
    +-            }
    ++  
    ++      case SQLITE_INTEGER: 
    ++      case SQLITE_FLOAT:
    ++        if( aBuf ){
    ++          /* TODO: SQLite does something special to deal with mixed-endian
    ++          ** floating point values (e.g. ARM7). This code probably should
    ++          ** too.  */
    ++          u64 i;
    ++          if( eType==SQLITE_INTEGER ){
    ++            i = (u64)sqlite3_value_int64(pValue);
    +           }else{
    +-            jsonAppendSeparator(pOut);
    +-            jsonRenderNode(&pNode[j], pOut, aReplace);
    ++            double r;
    ++            assert( sizeof(double)==8 && sizeof(u64)==8 );
    ++            r = sqlite3_value_double(pValue);
    ++            memcpy(&i, &r, 8);
    +           }
    +-          j += jsonNodeSize(&pNode[j]);
    ++          sessionPutI64(&aBuf[1], i);
    +         }
    +-        if( (pNode->jnFlags & JNODE_APPEND)==0 ) break;
    +-        pNode = &pNode[pNode->u.iAppend];
    +-        j = 1;
    +-      }
    +-      jsonAppendChar(pOut, ']');
    +-      break;
    +-    }
    +-    case JSON_OBJECT: {
    +-      u32 j = 1;
    +-      jsonAppendChar(pOut, '{');
    +-      for(;;){
    +-        while( j<=pNode->n ){
    +-          if( (pNode[j+1].jnFlags & JNODE_REMOVE)==0 ){
    +-            jsonAppendSeparator(pOut);
    +-            jsonRenderNode(&pNode[j], pOut, aReplace);
    +-            jsonAppendChar(pOut, ':');
    +-            if( pNode[j+1].jnFlags & JNODE_REPLACE ){
    +-              jsonAppendValue(pOut, aReplace[pNode[j+1].iVal]);
    +-            }else{
    +-              jsonRenderNode(&pNode[j+1], pOut, aReplace);
    +-            }
    +-          }
    +-          j += 1 + jsonNodeSize(&pNode[j+1]);
    ++        nByte = 9; 
    ++        break;
    ++  
    ++      default: {
    ++        u8 *z;
    ++        int n;
    ++        int nVarint;
    ++  
    ++        assert( eType==SQLITE_TEXT || eType==SQLITE_BLOB );
    ++        if( eType==SQLITE_TEXT ){
    ++          z = (u8 *)sqlite3_value_text(pValue);
    ++        }else{
    ++          z = (u8 *)sqlite3_value_blob(pValue);
    +         }
    +-        if( (pNode->jnFlags & JNODE_APPEND)==0 ) break;
    +-        pNode = &pNode[pNode->u.iAppend];
    +-        j = 1;
    ++        n = sqlite3_value_bytes(pValue);
    ++        if( z==0 && (eType!=SQLITE_BLOB || n>0) ) return SQLITE_NOMEM;
    ++        nVarint = sessionVarintLen(n);
    ++  
    ++        if( aBuf ){
    ++          sessionVarintPut(&aBuf[1], n);
    ++          if( n ) memcpy(&aBuf[nVarint + 1], z, n);
    ++        }
    ++  
    ++        nByte = 1 + nVarint + n;
    ++        break;
    +       }
    +-      jsonAppendChar(pOut, '}');
    +-      break;
    +     }
    ++  }else{
    ++    nByte = 1;
    ++    if( aBuf ) aBuf[0] = '\0';
    +   }
    ++
    ++  if( pnWrite ) *pnWrite += nByte;
    ++  return SQLITE_OK;
    + }
    + 
    ++
    + /*
    +-** Return a JsonNode and all its descendents as a JSON string.
    ++** This macro is used to calculate hash key values for data structures. In
    ++** order to use this macro, the entire data structure must be represented
    ++** as a series of unsigned integers. In order to calculate a hash-key value
    ++** for a data structure represented as three such integers, the macro may
    ++** then be used as follows:
    ++**
    ++**    int hash_key_value;
    ++**    hash_key_value = HASH_APPEND(0, <value 1>);
    ++**    hash_key_value = HASH_APPEND(hash_key_value, <value 2>);
    ++**    hash_key_value = HASH_APPEND(hash_key_value, <value 3>);
    ++**
    ++** In practice, the data structures this macro is used for are the primary
    ++** key values of modified rows.
    + */
    +-static void jsonReturnJson(
    +-  JsonNode *pNode,            /* Node to return */
    +-  sqlite3_context *pCtx,      /* Return value for this function */
    +-  sqlite3_value **aReplace    /* Array of replacement values */
    +-){
    +-  JsonString s;
    +-  jsonInit(&s, pCtx);
    +-  jsonRenderNode(pNode, &s, aReplace);
    +-  jsonResult(&s);
    +-  sqlite3_result_subtype(pCtx, JSON_SUBTYPE);
    ++#define HASH_APPEND(hash, add) ((hash) << 3) ^ (hash) ^ (unsigned int)(add)
    ++
    ++/*
    ++** Append the hash of the 64-bit integer passed as the second argument to the
    ++** hash-key value passed as the first. Return the new hash-key value.
    ++*/
    ++static unsigned int sessionHashAppendI64(unsigned int h, i64 i){
    ++  h = HASH_APPEND(h, i & 0xFFFFFFFF);
    ++  return HASH_APPEND(h, (i>>32)&0xFFFFFFFF);
    + }
    + 
    + /*
    +-** Make the JsonNode the return value of the function.
    ++** Append the hash of the blob passed via the second and third arguments to 
    ++** the hash-key value passed as the first. Return the new hash-key value.
    + */
    +-static void jsonReturn(
    +-  JsonNode *pNode,            /* Node to return */
    +-  sqlite3_context *pCtx,      /* Return value for this function */
    +-  sqlite3_value **aReplace    /* Array of replacement values */
    ++static unsigned int sessionHashAppendBlob(unsigned int h, int n, const u8 *z){
    ++  int i;
    ++  for(i=0; i<n; i++) h = HASH_APPEND(h, z[i]);
    ++  return h;
    ++}
    ++
    ++/*
    ++** Append the hash of the data type passed as the second argument to the
    ++** hash-key value passed as the first. Return the new hash-key value.
    ++*/
    ++static unsigned int sessionHashAppendType(unsigned int h, int eType){
    ++  return HASH_APPEND(h, eType);
    ++}
    ++
    ++/*
    ++** This function may only be called from within a pre-update callback.
    ++** It calculates a hash based on the primary key values of the old.* or 
    ++** new.* row currently available and, assuming no error occurs, writes it to
    ++** *piHash before returning. If the primary key contains one or more NULL
    ++** values, *pbNullPK is set to true before returning.
    ++**
    ++** If an error occurs, an SQLite error code is returned and the final values
    ++** of *piHash asn *pbNullPK are undefined. Otherwise, SQLITE_OK is returned
    ++** and the output variables are set as described above.
    ++*/
    ++static int sessionPreupdateHash(
    ++  sqlite3_session *pSession,      /* Session object that owns pTab */
    ++  SessionTable *pTab,             /* Session table handle */
    ++  int bNew,                       /* True to hash the new.* PK */
    ++  int *piHash,                    /* OUT: Hash value */
    ++  int *pbNullPK                   /* OUT: True if there are NULL values in PK */
    + ){
    +-  switch( pNode->eType ){
    +-    default: {
    +-      assert( pNode->eType==JSON_NULL );
    +-      sqlite3_result_null(pCtx);
    +-      break;
    +-    }
    +-    case JSON_TRUE: {
    +-      sqlite3_result_int(pCtx, 1);
    +-      break;
    +-    }
    +-    case JSON_FALSE: {
    +-      sqlite3_result_int(pCtx, 0);
    +-      break;
    +-    }
    +-    case JSON_INT: {
    +-      sqlite3_int64 i = 0;
    +-      const char *z = pNode->u.zJContent;
    +-      if( z[0]=='-' ){ z++; }
    +-      while( z[0]>='0' && z[0]<='9' ){
    +-        unsigned v = *(z++) - '0';
    +-        if( i>=LARGEST_INT64/10 ){
    +-          if( i>LARGEST_INT64/10 ) goto int_as_real;
    +-          if( z[0]>='0' && z[0]<='9' ) goto int_as_real;
    +-          if( v==9 ) goto int_as_real;
    +-          if( v==8 ){
    +-            if( pNode->u.zJContent[0]=='-' ){
    +-              sqlite3_result_int64(pCtx, SMALLEST_INT64);
    +-              goto int_done;
    +-            }else{
    +-              goto int_as_real;
    +-            }
    +-          }
    +-        }
    +-        i = i*10 + v;
    +-      }
    +-      if( pNode->u.zJContent[0]=='-' ){ i = -i; }
    +-      sqlite3_result_int64(pCtx, i);
    +-      int_done:
    +-      break;
    +-      int_as_real: /* fall through to real */;
    +-    }
    +-    case JSON_REAL: {
    +-      double r;
    +-#ifdef SQLITE_AMALGAMATION
    +-      const char *z = pNode->u.zJContent;
    +-      sqlite3AtoF(z, &r, sqlite3Strlen30(z), SQLITE_UTF8);
    +-#else
    +-      r = strtod(pNode->u.zJContent, 0);
    +-#endif
    +-      sqlite3_result_double(pCtx, r);
    +-      break;
    +-    }
    +-    case JSON_STRING: {
    +-#if 0 /* Never happens because JNODE_RAW is only set by json_set(),
    +-      ** json_insert() and json_replace() and those routines do not
    +-      ** call jsonReturn() */
    +-      if( pNode->jnFlags & JNODE_RAW ){
    +-        sqlite3_result_text(pCtx, pNode->u.zJContent, pNode->n,
    +-                            SQLITE_TRANSIENT);
    +-      }else 
    +-#endif
    +-      assert( (pNode->jnFlags & JNODE_RAW)==0 );
    +-      if( (pNode->jnFlags & JNODE_ESCAPE)==0 ){
    +-        /* JSON formatted without any backslash-escapes */
    +-        sqlite3_result_text(pCtx, pNode->u.zJContent+1, pNode->n-2,
    +-                            SQLITE_TRANSIENT);
    ++  unsigned int h = 0;             /* Hash value to return */
    ++  int i;                          /* Used to iterate through columns */
    ++
    ++  assert( *pbNullPK==0 );
    ++  assert( pTab->nCol==pSession->hook.xCount(pSession->hook.pCtx) );
    ++  for(i=0; i<pTab->nCol; i++){
    ++    if( pTab->abPK[i] ){
    ++      int rc;
    ++      int eType;
    ++      sqlite3_value *pVal;
    ++
    ++      if( bNew ){
    ++        rc = pSession->hook.xNew(pSession->hook.pCtx, i, &pVal);
    +       }else{
    +-        /* Translate JSON formatted string into raw text */
    +-        u32 i;
    +-        u32 n = pNode->n;
    +-        const char *z = pNode->u.zJContent;
    +-        char *zOut;
    +-        u32 j;
    +-        zOut = sqlite3_malloc( n+1 );
    +-        if( zOut==0 ){
    +-          sqlite3_result_error_nomem(pCtx);
    +-          break;
    ++        rc = pSession->hook.xOld(pSession->hook.pCtx, i, &pVal);
    ++      }
    ++      if( rc!=SQLITE_OK ) return rc;
    ++
    ++      eType = sqlite3_value_type(pVal);
    ++      h = sessionHashAppendType(h, eType);
    ++      if( eType==SQLITE_INTEGER || eType==SQLITE_FLOAT ){
    ++        i64 iVal;
    ++        if( eType==SQLITE_INTEGER ){
    ++          iVal = sqlite3_value_int64(pVal);
    ++        }else{
    ++          double rVal = sqlite3_value_double(pVal);
    ++          assert( sizeof(iVal)==8 && sizeof(rVal)==8 );
    ++          memcpy(&iVal, &rVal, 8);
    +         }
    +-        for(i=1, j=0; i<n-1; i++){
    +-          char c = z[i];
    +-          if( c!='\\' ){
    +-            zOut[j++] = c;
    +-          }else{
    +-            c = z[++i];
    +-            if( c=='u' ){
    +-              u32 v = 0, k;
    +-              for(k=0; k<4 && i<n-2; i++, k++){
    +-                c = z[i+1];
    +-                if( c>='0' && c<='9' ) v = v*16 + c - '0';
    +-                else if( c>='A' && c<='F' ) v = v*16 + c - 'A' + 10;
    +-                else if( c>='a' && c<='f' ) v = v*16 + c - 'a' + 10;
    +-                else break;
    +-              }
    +-              if( v==0 ) break;
    +-              if( v<=0x7f ){
    +-                zOut[j++] = (char)v;
    +-              }else if( v<=0x7ff ){
    +-                zOut[j++] = (char)(0xc0 | (v>>6));
    +-                zOut[j++] = 0x80 | (v&0x3f);
    +-              }else{
    +-                zOut[j++] = (char)(0xe0 | (v>>12));
    +-                zOut[j++] = 0x80 | ((v>>6)&0x3f);
    +-                zOut[j++] = 0x80 | (v&0x3f);
    +-              }
    +-            }else{
    +-              if( c=='b' ){
    +-                c = '\b';
    +-              }else if( c=='f' ){
    +-                c = '\f';
    +-              }else if( c=='n' ){
    +-                c = '\n';
    +-              }else if( c=='r' ){
    +-                c = '\r';
    +-              }else if( c=='t' ){
    +-                c = '\t';
    +-              }
    +-              zOut[j++] = c;
    +-            }
    +-          }
    ++        h = sessionHashAppendI64(h, iVal);
    ++      }else if( eType==SQLITE_TEXT || eType==SQLITE_BLOB ){
    ++        const u8 *z;
    ++        int n;
    ++        if( eType==SQLITE_TEXT ){
    ++          z = (const u8 *)sqlite3_value_text(pVal);
    ++        }else{
    ++          z = (const u8 *)sqlite3_value_blob(pVal);
    +         }
    +-        zOut[j] = 0;
    +-        sqlite3_result_text(pCtx, zOut, j, sqlite3_free);
    ++        n = sqlite3_value_bytes(pVal);
    ++        if( !z && (eType!=SQLITE_BLOB || n>0) ) return SQLITE_NOMEM;
    ++        h = sessionHashAppendBlob(h, n, z);
    ++      }else{
    ++        assert( eType==SQLITE_NULL );
    ++        assert( pTab->bStat1==0 || i!=1 );
    ++        *pbNullPK = 1;
    +       }
    +-      break;
    +-    }
    +-    case JSON_ARRAY:
    +-    case JSON_OBJECT: {
    +-      jsonReturnJson(pNode, pCtx, aReplace);
    +-      break;
    +     }
    +   }
    ++
    ++  *piHash = (h % pTab->nChange);
    ++  return SQLITE_OK;
    + }
    + 
    +-/* Forward reference */
    +-static int jsonParseAddNode(JsonParse*,u32,u32,const char*);
    ++/*
    ++** The buffer that the argument points to contains a serialized SQL value.
    ++** Return the number of bytes of space occupied by the value (including
    ++** the type byte).
    ++*/
    ++static int sessionSerialLen(u8 *a){
    ++  int e = *a;
    ++  int n;
    ++  if( e==0 ) return 1;
    ++  if( e==SQLITE_NULL ) return 1;
    ++  if( e==SQLITE_INTEGER || e==SQLITE_FLOAT ) return 9;
    ++  return sessionVarintGet(&a[1], &n) + 1 + n;
    ++}
    + 
    + /*
    +-** A macro to hint to the compiler that a function should not be
    +-** inlined.
    ++** Based on the primary key values stored in change aRecord, calculate a
    ++** hash key. Assume the has table has nBucket buckets. The hash keys
    ++** calculated by this function are compatible with those calculated by
    ++** sessionPreupdateHash().
    ++**
    ++** The bPkOnly argument is non-zero if the record at aRecord[] is from
    ++** a patchset DELETE. In this case the non-PK fields are omitted entirely.
    + */
    +-#if defined(__GNUC__)
    +-#  define JSON_NOINLINE  __attribute__((noinline))
    +-#elif defined(_MSC_VER) && _MSC_VER>=1310
    +-#  define JSON_NOINLINE  __declspec(noinline)
    +-#else
    +-#  define JSON_NOINLINE
    +-#endif
    ++static unsigned int sessionChangeHash(
    ++  SessionTable *pTab,             /* Table handle */
    ++  int bPkOnly,                    /* Record consists of PK fields only */
    ++  u8 *aRecord,                    /* Change record */
    ++  int nBucket                     /* Assume this many buckets in hash table */
    ++){
    ++  unsigned int h = 0;             /* Value to return */
    ++  int i;                          /* Used to iterate through columns */
    ++  u8 *a = aRecord;                /* Used to iterate through change record */
    + 
    ++  for(i=0; i<pTab->nCol; i++){
    ++    int eType = *a;
    ++    int isPK = pTab->abPK[i];
    ++    if( bPkOnly && isPK==0 ) continue;
    ++
    ++    /* It is not possible for eType to be SQLITE_NULL here. The session 
    ++    ** module does not record changes for rows with NULL values stored in
    ++    ** primary key columns. */
    ++    assert( eType==SQLITE_INTEGER || eType==SQLITE_FLOAT 
    ++         || eType==SQLITE_TEXT || eType==SQLITE_BLOB 
    ++         || eType==SQLITE_NULL || eType==0 
    ++    );
    ++    assert( !isPK || (eType!=0 && eType!=SQLITE_NULL) );
    ++
    ++    if( isPK ){
    ++      a++;
    ++      h = sessionHashAppendType(h, eType);
    ++      if( eType==SQLITE_INTEGER || eType==SQLITE_FLOAT ){
    ++        h = sessionHashAppendI64(h, sessionGetI64(a));
    ++        a += 8;
    ++      }else{
    ++        int n; 
    ++        a += sessionVarintGet(a, &n);
    ++        h = sessionHashAppendBlob(h, n, a);
    ++        a += n;
    ++      }
    ++    }else{
    ++      a += sessionSerialLen(a);
    ++    }
    ++  }
    ++  return (h % nBucket);
    ++}
    + 
    +-static JSON_NOINLINE int jsonParseAddNodeExpand(
    +-  JsonParse *pParse,        /* Append the node to this object */
    +-  u32 eType,                /* Node type */
    +-  u32 n,                    /* Content size or sub-node count */
    +-  const char *zContent      /* Content */
    ++/*
    ++** Arguments aLeft and aRight are pointers to change records for table pTab.
    ++** This function returns true if the two records apply to the same row (i.e.
    ++** have the same values stored in the primary key columns), or false 
    ++** otherwise.
    ++*/
    ++static int sessionChangeEqual(
    ++  SessionTable *pTab,             /* Table used for PK definition */
    ++  int bLeftPkOnly,                /* True if aLeft[] contains PK fields only */
    ++  u8 *aLeft,                      /* Change record */
    ++  int bRightPkOnly,               /* True if aRight[] contains PK fields only */
    ++  u8 *aRight                      /* Change record */
    + ){
    +-  u32 nNew;
    +-  JsonNode *pNew;
    +-  assert( pParse->nNode>=pParse->nAlloc );
    +-  if( pParse->oom ) return -1;
    +-  nNew = pParse->nAlloc*2 + 10;
    +-  pNew = sqlite3_realloc(pParse->aNode, sizeof(JsonNode)*nNew);
    +-  if( pNew==0 ){
    +-    pParse->oom = 1;
    +-    return -1;
    ++  u8 *a1 = aLeft;                 /* Cursor to iterate through aLeft */
    ++  u8 *a2 = aRight;                /* Cursor to iterate through aRight */
    ++  int iCol;                       /* Used to iterate through table columns */
    ++
    ++  for(iCol=0; iCol<pTab->nCol; iCol++){
    ++    if( pTab->abPK[iCol] ){
    ++      int n1 = sessionSerialLen(a1);
    ++      int n2 = sessionSerialLen(a2);
    ++
    ++      if( pTab->abPK[iCol] && (n1!=n2 || memcmp(a1, a2, n1)) ){
    ++        return 0;
    ++      }
    ++      a1 += n1;
    ++      a2 += n2;
    ++    }else{
    ++      if( bLeftPkOnly==0 ) a1 += sessionSerialLen(a1);
    ++      if( bRightPkOnly==0 ) a2 += sessionSerialLen(a2);
    ++    }
    +   }
    +-  pParse->nAlloc = nNew;
    +-  pParse->aNode = pNew;
    +-  assert( pParse->nNode<pParse->nAlloc );
    +-  return jsonParseAddNode(pParse, eType, n, zContent);
    ++
    ++  return 1;
    + }
    + 
    + /*
    +-** Create a new JsonNode instance based on the arguments and append that
    +-** instance to the JsonParse.  Return the index in pParse->aNode[] of the
    +-** new node, or -1 if a memory allocation fails.
    ++** Arguments aLeft and aRight both point to buffers containing change
    ++** records with nCol columns. This function "merges" the two records into
    ++** a single records which is written to the buffer at *paOut. *paOut is
    ++** then set to point to one byte after the last byte written before 
    ++** returning.
    ++**
    ++** The merging of records is done as follows: For each column, if the 
    ++** aRight record contains a value for the column, copy the value from
    ++** their. Otherwise, if aLeft contains a value, copy it. If neither
    ++** record contains a value for a given column, then neither does the
    ++** output record.
    + */
    +-static int jsonParseAddNode(
    +-  JsonParse *pParse,        /* Append the node to this object */
    +-  u32 eType,                /* Node type */
    +-  u32 n,                    /* Content size or sub-node count */
    +-  const char *zContent      /* Content */
    ++static void sessionMergeRecord(
    ++  u8 **paOut, 
    ++  int nCol,
    ++  u8 *aLeft,
    ++  u8 *aRight
    + ){
    +-  JsonNode *p;
    +-  if( pParse->nNode>=pParse->nAlloc ){
    +-    return jsonParseAddNodeExpand(pParse, eType, n, zContent);
    ++  u8 *a1 = aLeft;                 /* Cursor used to iterate through aLeft */
    ++  u8 *a2 = aRight;                /* Cursor used to iterate through aRight */
    ++  u8 *aOut = *paOut;              /* Output cursor */
    ++  int iCol;                       /* Used to iterate from 0 to nCol */
    ++
    ++  for(iCol=0; iCol<nCol; iCol++){
    ++    int n1 = sessionSerialLen(a1);
    ++    int n2 = sessionSerialLen(a2);
    ++    if( *a2 ){
    ++      memcpy(aOut, a2, n2);
    ++      aOut += n2;
    ++    }else{
    ++      memcpy(aOut, a1, n1);
    ++      aOut += n1;
    ++    }
    ++    a1 += n1;
    ++    a2 += n2;
    +   }
    +-  p = &pParse->aNode[pParse->nNode];
    +-  p->eType = (u8)eType;
    +-  p->jnFlags = 0;
    +-  p->iVal = 0;
    +-  p->n = n;
    +-  p->u.zJContent = zContent;
    +-  return pParse->nNode++;
    ++
    ++  *paOut = aOut;
    + }
    + 
    + /*
    +-** Parse a single JSON value which begins at pParse->zJson[i].  Return the
    +-** index of the first character past the end of the value parsed.
    ++** This is a helper function used by sessionMergeUpdate().
    ++**
    ++** When this function is called, both *paOne and *paTwo point to a value 
    ++** within a change record. Before it returns, both have been advanced so 
    ++** as to point to the next value in the record.
    ++**
    ++** If, when this function is called, *paTwo points to a valid value (i.e.
    ++** *paTwo[0] is not 0x00 - the "no value" placeholder), a copy of the *paTwo
    ++** pointer is returned and *pnVal is set to the number of bytes in the 
    ++** serialized value. Otherwise, a copy of *paOne is returned and *pnVal
    ++** set to the number of bytes in the value at *paOne. If *paOne points
    ++** to the "no value" placeholder, *pnVal is set to 1. In other words:
    ++**
    ++**   if( *paTwo is valid ) return *paTwo;
    ++**   return *paOne;
    + **
    +-** Return negative for a syntax error.  Special cases:  return -2 if the
    +-** first non-whitespace character is '}' and return -3 if the first
    +-** non-whitespace character is ']'.
    + */
    +-static int jsonParseValue(JsonParse *pParse, u32 i){
    +-  char c;
    +-  u32 j;
    +-  int iThis;
    +-  int x;
    +-  JsonNode *pNode;
    +-  while( safe_isspace(pParse->zJson[i]) ){ i++; }
    +-  if( (c = pParse->zJson[i])=='{' ){
    +-    /* Parse object */
    +-    iThis = jsonParseAddNode(pParse, JSON_OBJECT, 0, 0);
    +-    if( iThis<0 ) return -1;
    +-    for(j=i+1;;j++){
    +-      while( safe_isspace(pParse->zJson[j]) ){ j++; }
    +-      x = jsonParseValue(pParse, j);
    +-      if( x<0 ){
    +-        if( x==(-2) && pParse->nNode==(u32)iThis+1 ) return j+1;
    +-        return -1;
    +-      }
    +-      if( pParse->oom ) return -1;
    +-      pNode = &pParse->aNode[pParse->nNode-1];
    +-      if( pNode->eType!=JSON_STRING ) return -1;
    +-      pNode->jnFlags |= JNODE_LABEL;
    +-      j = x;
    +-      while( safe_isspace(pParse->zJson[j]) ){ j++; }
    +-      if( pParse->zJson[j]!=':' ) return -1;
    +-      j++;
    +-      x = jsonParseValue(pParse, j);
    ++static u8 *sessionMergeValue(
    ++  u8 **paOne,                     /* IN/OUT: Left-hand buffer pointer */
    ++  u8 **paTwo,                     /* IN/OUT: Right-hand buffer pointer */
    ++  int *pnVal                      /* OUT: Bytes in returned value */
    ++){
    ++  u8 *a1 = *paOne;
    ++  u8 *a2 = *paTwo;
    ++  u8 *pRet = 0;
    ++  int n1;
    ++
    ++  assert( a1 );
    ++  if( a2 ){
    ++    int n2 = sessionSerialLen(a2);
    ++    if( *a2 ){
    ++      *pnVal = n2;
    ++      pRet = a2;
    ++    }
    ++    *paTwo = &a2[n2];
    ++  }
    ++
    ++  n1 = sessionSerialLen(a1);
    ++  if( pRet==0 ){
    ++    *pnVal = n1;
    ++    pRet = a1;
    ++  }
    ++  *paOne = &a1[n1];
    ++
    ++  return pRet;
    ++}
    ++
    ++/*
    ++** This function is used by changeset_concat() to merge two UPDATE changes
    ++** on the same row.
    ++*/
    ++static int sessionMergeUpdate(
    ++  u8 **paOut,                     /* IN/OUT: Pointer to output buffer */
    ++  SessionTable *pTab,             /* Table change pertains to */
    ++  int bPatchset,                  /* True if records are patchset records */
    ++  u8 *aOldRecord1,                /* old.* record for first change */
    ++  u8 *aOldRecord2,                /* old.* record for second change */
    ++  u8 *aNewRecord1,                /* new.* record for first change */
    ++  u8 *aNewRecord2                 /* new.* record for second change */
    ++){
    ++  u8 *aOld1 = aOldRecord1;
    ++  u8 *aOld2 = aOldRecord2;
    ++  u8 *aNew1 = aNewRecord1;
    ++  u8 *aNew2 = aNewRecord2;
    ++
    ++  u8 *aOut = *paOut;
    ++  int i;
    ++
    ++  if( bPatchset==0 ){
    ++    int bRequired = 0;
    ++
    ++    assert( aOldRecord1 && aNewRecord1 );
    ++
    ++    /* Write the old.* vector first. */
    ++    for(i=0; i<pTab->nCol; i++){
    ++      int nOld;
    ++      u8 *aOld;
    ++      int nNew;
    ++      u8 *aNew;
    ++
    ++      aOld = sessionMergeValue(&aOld1, &aOld2, &nOld);
    ++      aNew = sessionMergeValue(&aNew1, &aNew2, &nNew);
    ++      if( pTab->abPK[i] || nOld!=nNew || memcmp(aOld, aNew, nNew) ){
    ++        if( pTab->abPK[i]==0 ) bRequired = 1;
    ++        memcpy(aOut, aOld, nOld);
    ++        aOut += nOld;
    ++      }else{
    ++        *(aOut++) = '\0';
    ++      }
    ++    }
    ++
    ++    if( !bRequired ) return 0;
    ++  }
    ++
    ++  /* Write the new.* vector */
    ++  aOld1 = aOldRecord1;
    ++  aOld2 = aOldRecord2;
    ++  aNew1 = aNewRecord1;
    ++  aNew2 = aNewRecord2;
    ++  for(i=0; i<pTab->nCol; i++){
    ++    int nOld;
    ++    u8 *aOld;
    ++    int nNew;
    ++    u8 *aNew;
    ++
    ++    aOld = sessionMergeValue(&aOld1, &aOld2, &nOld);
    ++    aNew = sessionMergeValue(&aNew1, &aNew2, &nNew);
    ++    if( bPatchset==0 
    ++     && (pTab->abPK[i] || (nOld==nNew && 0==memcmp(aOld, aNew, nNew))) 
    ++    ){
    ++      *(aOut++) = '\0';
    ++    }else{
    ++      memcpy(aOut, aNew, nNew);
    ++      aOut += nNew;
    ++    }
    ++  }
    ++
    ++  *paOut = aOut;
    ++  return 1;
    ++}
    ++
    ++/*
    ++** This function is only called from within a pre-update-hook callback.
    ++** It determines if the current pre-update-hook change affects the same row
    ++** as the change stored in argument pChange. If so, it returns true. Otherwise
    ++** if the pre-update-hook does not affect the same row as pChange, it returns
    ++** false.
    ++*/
    ++static int sessionPreupdateEqual(
    ++  sqlite3_session *pSession,      /* Session object that owns SessionTable */
    ++  SessionTable *pTab,             /* Table associated with change */
    ++  SessionChange *pChange,         /* Change to compare to */
    ++  int op                          /* Current pre-update operation */
    ++){
    ++  int iCol;                       /* Used to iterate through columns */
    ++  u8 *a = pChange->aRecord;       /* Cursor used to scan change record */
    ++
    ++  assert( op==SQLITE_INSERT || op==SQLITE_UPDATE || op==SQLITE_DELETE );
    ++  for(iCol=0; iCol<pTab->nCol; iCol++){
    ++    if( !pTab->abPK[iCol] ){
    ++      a += sessionSerialLen(a);
    ++    }else{
    ++      sqlite3_value *pVal;        /* Value returned by preupdate_new/old */
    ++      int rc;                     /* Error code from preupdate_new/old */
    ++      int eType = *a++;           /* Type of value from change record */
    ++
    ++      /* The following calls to preupdate_new() and preupdate_old() can not
    ++      ** fail. This is because they cache their return values, and by the
    ++      ** time control flows to here they have already been called once from
    ++      ** within sessionPreupdateHash(). The first two asserts below verify
    ++      ** this (that the method has already been called). */
    ++      if( op==SQLITE_INSERT ){
    ++        /* assert( db->pPreUpdate->pNewUnpacked || db->pPreUpdate->aNew ); */
    ++        rc = pSession->hook.xNew(pSession->hook.pCtx, iCol, &pVal);
    ++      }else{
    ++        /* assert( db->pPreUpdate->pUnpacked ); */
    ++        rc = pSession->hook.xOld(pSession->hook.pCtx, iCol, &pVal);
    ++      }
    ++      assert( rc==SQLITE_OK );
    ++      if( sqlite3_value_type(pVal)!=eType ) return 0;
    ++
    ++      /* A SessionChange object never has a NULL value in a PK column */
    ++      assert( eType==SQLITE_INTEGER || eType==SQLITE_FLOAT
    ++           || eType==SQLITE_BLOB    || eType==SQLITE_TEXT
    ++      );
    ++
    ++      if( eType==SQLITE_INTEGER || eType==SQLITE_FLOAT ){
    ++        i64 iVal = sessionGetI64(a);
    ++        a += 8;
    ++        if( eType==SQLITE_INTEGER ){
    ++          if( sqlite3_value_int64(pVal)!=iVal ) return 0;
    ++        }else{
    ++          double rVal;
    ++          assert( sizeof(iVal)==8 && sizeof(rVal)==8 );
    ++          memcpy(&rVal, &iVal, 8);
    ++          if( sqlite3_value_double(pVal)!=rVal ) return 0;
    ++        }
    ++      }else{
    ++        int n;
    ++        const u8 *z;
    ++        a += sessionVarintGet(a, &n);
    ++        if( sqlite3_value_bytes(pVal)!=n ) return 0;
    ++        if( eType==SQLITE_TEXT ){
    ++          z = sqlite3_value_text(pVal);
    ++        }else{
    ++          z = sqlite3_value_blob(pVal);
    ++        }
    ++        if( memcmp(a, z, n) ) return 0;
    ++        a += n;
    ++      }
    ++    }
    ++  }
    ++
    ++  return 1;
    ++}
    ++
    ++/*
    ++** If required, grow the hash table used to store changes on table pTab 
    ++** (part of the session pSession). If a fatal OOM error occurs, set the
    ++** session object to failed and return SQLITE_ERROR. Otherwise, return
    ++** SQLITE_OK.
    ++**
    ++** It is possible that a non-fatal OOM error occurs in this function. In
    ++** that case the hash-table does not grow, but SQLITE_OK is returned anyway.
    ++** Growing the hash table in this case is a performance optimization only,
    ++** it is not required for correct operation.
    ++*/
    ++static int sessionGrowHash(int bPatchset, SessionTable *pTab){
    ++  if( pTab->nChange==0 || pTab->nEntry>=(pTab->nChange/2) ){
    ++    int i;
    ++    SessionChange **apNew;
    ++    int nNew = (pTab->nChange ? pTab->nChange : 128) * 2;
    ++
    ++    apNew = (SessionChange **)sqlite3_malloc(sizeof(SessionChange *) * nNew);
    ++    if( apNew==0 ){
    ++      if( pTab->nChange==0 ){
    ++        return SQLITE_ERROR;
    ++      }
    ++      return SQLITE_OK;
    ++    }
    ++    memset(apNew, 0, sizeof(SessionChange *) * nNew);
    ++
    ++    for(i=0; i<pTab->nChange; i++){
    ++      SessionChange *p;
    ++      SessionChange *pNext;
    ++      for(p=pTab->apChange[i]; p; p=pNext){
    ++        int bPkOnly = (p->op==SQLITE_DELETE && bPatchset);
    ++        int iHash = sessionChangeHash(pTab, bPkOnly, p->aRecord, nNew);
    ++        pNext = p->pNext;
    ++        p->pNext = apNew[iHash];
    ++        apNew[iHash] = p;
    ++      }
    ++    }
    ++
    ++    sqlite3_free(pTab->apChange);
    ++    pTab->nChange = nNew;
    ++    pTab->apChange = apNew;
    ++  }
    ++
    ++  return SQLITE_OK;
    ++}
    ++
    ++/*
    ++** This function queries the database for the names of the columns of table
    ++** zThis, in schema zDb.
    ++**
    ++** Otherwise, if they are not NULL, variable *pnCol is set to the number
    ++** of columns in the database table and variable *pzTab is set to point to a
    ++** nul-terminated copy of the table name. *pazCol (if not NULL) is set to
    ++** point to an array of pointers to column names. And *pabPK (again, if not
    ++** NULL) is set to point to an array of booleans - true if the corresponding
    ++** column is part of the primary key.
    ++**
    ++** For example, if the table is declared as:
    ++**
    ++**     CREATE TABLE tbl1(w, x, y, z, PRIMARY KEY(w, z));
    ++**
    ++** Then the four output variables are populated as follows:
    ++**
    ++**     *pnCol  = 4
    ++**     *pzTab  = "tbl1"
    ++**     *pazCol = {"w", "x", "y", "z"}
    ++**     *pabPK  = {1, 0, 0, 1}
    ++**
    ++** All returned buffers are part of the same single allocation, which must
    ++** be freed using sqlite3_free() by the caller
    ++*/
    ++static int sessionTableInfo(
    ++  sqlite3 *db,                    /* Database connection */
    ++  const char *zDb,                /* Name of attached database (e.g. "main") */
    ++  const char *zThis,              /* Table name */
    ++  int *pnCol,                     /* OUT: number of columns */
    ++  const char **pzTab,             /* OUT: Copy of zThis */
    ++  const char ***pazCol,           /* OUT: Array of column names for table */
    ++  u8 **pabPK                      /* OUT: Array of booleans - true for PK col */
    ++){
    ++  char *zPragma;
    ++  sqlite3_stmt *pStmt;
    ++  int rc;
    ++  int nByte;
    ++  int nDbCol = 0;
    ++  int nThis;
    ++  int i;
    ++  u8 *pAlloc = 0;
    ++  char **azCol = 0;
    ++  u8 *abPK = 0;
    ++
    ++  assert( pazCol && pabPK );
    ++
    ++  nThis = sqlite3Strlen30(zThis);
    ++  if( nThis==12 && 0==sqlite3_stricmp("sqlite_stat1", zThis) ){
    ++    rc = sqlite3_table_column_metadata(db, zDb, zThis, 0, 0, 0, 0, 0, 0);
    ++    if( rc==SQLITE_OK ){
    ++      /* For sqlite_stat1, pretend that (tbl,idx) is the PRIMARY KEY. */
    ++      zPragma = sqlite3_mprintf(
    ++          "SELECT 0, 'tbl',  '', 0, '', 1     UNION ALL "
    ++          "SELECT 1, 'idx',  '', 0, '', 2     UNION ALL "
    ++          "SELECT 2, 'stat', '', 0, '', 0"
    ++      );
    ++    }else if( rc==SQLITE_ERROR ){
    ++      zPragma = sqlite3_mprintf("");
    ++    }else{
    ++      return rc;
    ++    }
    ++  }else{
    ++    zPragma = sqlite3_mprintf("PRAGMA '%q'.table_info('%q')", zDb, zThis);
    ++  }
    ++  if( !zPragma ) return SQLITE_NOMEM;
    ++
    ++  rc = sqlite3_prepare_v2(db, zPragma, -1, &pStmt, 0);
    ++  sqlite3_free(zPragma);
    ++  if( rc!=SQLITE_OK ) return rc;
    ++
    ++  nByte = nThis + 1;
    ++  while( SQLITE_ROW==sqlite3_step(pStmt) ){
    ++    nByte += sqlite3_column_bytes(pStmt, 1);
    ++    nDbCol++;
    ++  }
    ++  rc = sqlite3_reset(pStmt);
    ++
    ++  if( rc==SQLITE_OK ){
    ++    nByte += nDbCol * (sizeof(const char *) + sizeof(u8) + 1);
    ++    pAlloc = sqlite3_malloc(nByte);
    ++    if( pAlloc==0 ){
    ++      rc = SQLITE_NOMEM;
    ++    }
    ++  }
    ++  if( rc==SQLITE_OK ){
    ++    azCol = (char **)pAlloc;
    ++    pAlloc = (u8 *)&azCol[nDbCol];
    ++    abPK = (u8 *)pAlloc;
    ++    pAlloc = &abPK[nDbCol];
    ++    if( pzTab ){
    ++      memcpy(pAlloc, zThis, nThis+1);
    ++      *pzTab = (char *)pAlloc;
    ++      pAlloc += nThis+1;
    ++    }
    ++  
    ++    i = 0;
    ++    while( SQLITE_ROW==sqlite3_step(pStmt) ){
    ++      int nName = sqlite3_column_bytes(pStmt, 1);
    ++      const unsigned char *zName = sqlite3_column_text(pStmt, 1);
    ++      if( zName==0 ) break;
    ++      memcpy(pAlloc, zName, nName+1);
    ++      azCol[i] = (char *)pAlloc;
    ++      pAlloc += nName+1;
    ++      abPK[i] = sqlite3_column_int(pStmt, 5);
    ++      i++;
    ++    }
    ++    rc = sqlite3_reset(pStmt);
    ++  
    ++  }
    ++
    ++  /* If successful, populate the output variables. Otherwise, zero them and
    ++  ** free any allocation made. An error code will be returned in this case.
    ++  */
    ++  if( rc==SQLITE_OK ){
    ++    *pazCol = (const char **)azCol;
    ++    *pabPK = abPK;
    ++    *pnCol = nDbCol;
    ++  }else{
    ++    *pazCol = 0;
    ++    *pabPK = 0;
    ++    *pnCol = 0;
    ++    if( pzTab ) *pzTab = 0;
    ++    sqlite3_free(azCol);
    ++  }
    ++  sqlite3_finalize(pStmt);
    ++  return rc;
    ++}
    ++
    ++/*
    ++** This function is only called from within a pre-update handler for a
    ++** write to table pTab, part of session pSession. If this is the first
    ++** write to this table, initalize the SessionTable.nCol, azCol[] and
    ++** abPK[] arrays accordingly.
    ++**
    ++** If an error occurs, an error code is stored in sqlite3_session.rc and
    ++** non-zero returned. Or, if no error occurs but the table has no primary
    ++** key, sqlite3_session.rc is left set to SQLITE_OK and non-zero returned to
    ++** indicate that updates on this table should be ignored. SessionTable.abPK 
    ++** is set to NULL in this case.
    ++*/
    ++static int sessionInitTable(sqlite3_session *pSession, SessionTable *pTab){
    ++  if( pTab->nCol==0 ){
    ++    u8 *abPK;
    ++    assert( pTab->azCol==0 || pTab->abPK==0 );
    ++    pSession->rc = sessionTableInfo(pSession->db, pSession->zDb, 
    ++        pTab->zName, &pTab->nCol, 0, &pTab->azCol, &abPK
    ++    );
    ++    if( pSession->rc==SQLITE_OK ){
    ++      int i;
    ++      for(i=0; i<pTab->nCol; i++){
    ++        if( abPK[i] ){
    ++          pTab->abPK = abPK;
    ++          break;
    ++        }
    ++      }
    ++      if( 0==sqlite3_stricmp("sqlite_stat1", pTab->zName) ){
    ++        pTab->bStat1 = 1;
    ++      }
    ++    }
    ++  }
    ++  return (pSession->rc || pTab->abPK==0);
    ++}
    ++
    ++/*
    ++** Versions of the four methods in object SessionHook for use with the
    ++** sqlite_stat1 table. The purpose of this is to substitute a zero-length
    ++** blob each time a NULL value is read from the "idx" column of the
    ++** sqlite_stat1 table.
    ++*/
    ++typedef struct SessionStat1Ctx SessionStat1Ctx;
    ++struct SessionStat1Ctx {
    ++  SessionHook hook;
    ++  sqlite3_session *pSession;
    ++};
    ++static int sessionStat1Old(void *pCtx, int iCol, sqlite3_value **ppVal){
    ++  SessionStat1Ctx *p = (SessionStat1Ctx*)pCtx;
    ++  sqlite3_value *pVal = 0;
    ++  int rc = p->hook.xOld(p->hook.pCtx, iCol, &pVal);
    ++  if( rc==SQLITE_OK && iCol==1 && sqlite3_value_type(pVal)==SQLITE_NULL ){
    ++    pVal = p->pSession->pZeroBlob;
    ++  }
    ++  *ppVal = pVal;
    ++  return rc;
    ++}
    ++static int sessionStat1New(void *pCtx, int iCol, sqlite3_value **ppVal){
    ++  SessionStat1Ctx *p = (SessionStat1Ctx*)pCtx;
    ++  sqlite3_value *pVal = 0;
    ++  int rc = p->hook.xNew(p->hook.pCtx, iCol, &pVal);
    ++  if( rc==SQLITE_OK && iCol==1 && sqlite3_value_type(pVal)==SQLITE_NULL ){
    ++    pVal = p->pSession->pZeroBlob;
    ++  }
    ++  *ppVal = pVal;
    ++  return rc;
    ++}
    ++static int sessionStat1Count(void *pCtx){
    ++  SessionStat1Ctx *p = (SessionStat1Ctx*)pCtx;
    ++  return p->hook.xCount(p->hook.pCtx);
    ++}
    ++static int sessionStat1Depth(void *pCtx){
    ++  SessionStat1Ctx *p = (SessionStat1Ctx*)pCtx;
    ++  return p->hook.xDepth(p->hook.pCtx);
    ++}
    ++
    ++
    ++/*
    ++** This function is only called from with a pre-update-hook reporting a 
    ++** change on table pTab (attached to session pSession). The type of change
    ++** (UPDATE, INSERT, DELETE) is specified by the first argument.
    ++**
    ++** Unless one is already present or an error occurs, an entry is added
    ++** to the changed-rows hash table associated with table pTab.
    ++*/
    ++static void sessionPreupdateOneChange(
    ++  int op,                         /* One of SQLITE_UPDATE, INSERT, DELETE */
    ++  sqlite3_session *pSession,      /* Session object pTab is attached to */
    ++  SessionTable *pTab              /* Table that change applies to */
    ++){
    ++  int iHash; 
    ++  int bNull = 0; 
    ++  int rc = SQLITE_OK;
    ++  SessionStat1Ctx stat1;
    ++
    ++  if( pSession->rc ) return;
    ++
    ++  /* Load table details if required */
    ++  if( sessionInitTable(pSession, pTab) ) return;
    ++
    ++  /* Check the number of columns in this xPreUpdate call matches the 
    ++  ** number of columns in the table.  */
    ++  if( pTab->nCol!=pSession->hook.xCount(pSession->hook.pCtx) ){
    ++    pSession->rc = SQLITE_SCHEMA;
    ++    return;
    ++  }
    ++
    ++  /* Grow the hash table if required */
    ++  if( sessionGrowHash(0, pTab) ){
    ++    pSession->rc = SQLITE_NOMEM;
    ++    return;
    ++  }
    ++
    ++  if( pTab->bStat1 ){
    ++    stat1.hook = pSession->hook;
    ++    stat1.pSession = pSession;
    ++    pSession->hook.pCtx = (void*)&stat1;
    ++    pSession->hook.xNew = sessionStat1New;
    ++    pSession->hook.xOld = sessionStat1Old;
    ++    pSession->hook.xCount = sessionStat1Count;
    ++    pSession->hook.xDepth = sessionStat1Depth;
    ++    if( pSession->pZeroBlob==0 ){
    ++      sqlite3_value *p = sqlite3ValueNew(0);
    ++      if( p==0 ){
    ++        rc = SQLITE_NOMEM;
    ++        goto error_out;
    ++      }
    ++      sqlite3ValueSetStr(p, 0, "", 0, SQLITE_STATIC);
    ++      pSession->pZeroBlob = p;
    ++    }
    ++  }
    ++
    ++  /* Calculate the hash-key for this change. If the primary key of the row
    ++  ** includes a NULL value, exit early. Such changes are ignored by the
    ++  ** session module. */
    ++  rc = sessionPreupdateHash(pSession, pTab, op==SQLITE_INSERT, &iHash, &bNull);
    ++  if( rc!=SQLITE_OK ) goto error_out;
    ++
    ++  if( bNull==0 ){
    ++    /* Search the hash table for an existing record for this row. */
    ++    SessionChange *pC;
    ++    for(pC=pTab->apChange[iHash]; pC; pC=pC->pNext){
    ++      if( sessionPreupdateEqual(pSession, pTab, pC, op) ) break;
    ++    }
    ++
    ++    if( pC==0 ){
    ++      /* Create a new change object containing all the old values (if
    ++      ** this is an SQLITE_UPDATE or SQLITE_DELETE), or just the PK
    ++      ** values (if this is an INSERT). */
    ++      SessionChange *pChange; /* New change object */
    ++      int nByte;              /* Number of bytes to allocate */
    ++      int i;                  /* Used to iterate through columns */
    ++  
    ++      assert( rc==SQLITE_OK );
    ++      pTab->nEntry++;
    ++  
    ++      /* Figure out how large an allocation is required */
    ++      nByte = sizeof(SessionChange);
    ++      for(i=0; i<pTab->nCol; i++){
    ++        sqlite3_value *p = 0;
    ++        if( op!=SQLITE_INSERT ){
    ++          TESTONLY(int trc = ) pSession->hook.xOld(pSession->hook.pCtx, i, &p);
    ++          assert( trc==SQLITE_OK );
    ++        }else if( pTab->abPK[i] ){
    ++          TESTONLY(int trc = ) pSession->hook.xNew(pSession->hook.pCtx, i, &p);
    ++          assert( trc==SQLITE_OK );
    ++        }
    ++
    ++        /* This may fail if SQLite value p contains a utf-16 string that must
    ++        ** be converted to utf-8 and an OOM error occurs while doing so. */
    ++        rc = sessionSerializeValue(0, p, &nByte);
    ++        if( rc!=SQLITE_OK ) goto error_out;
    ++      }
    ++  
    ++      /* Allocate the change object */
    ++      pChange = (SessionChange *)sqlite3_malloc(nByte);
    ++      if( !pChange ){
    ++        rc = SQLITE_NOMEM;
    ++        goto error_out;
    ++      }else{
    ++        memset(pChange, 0, sizeof(SessionChange));
    ++        pChange->aRecord = (u8 *)&pChange[1];
    ++      }
    ++  
    ++      /* Populate the change object. None of the preupdate_old(),
    ++      ** preupdate_new() or SerializeValue() calls below may fail as all
    ++      ** required values and encodings have already been cached in memory.
    ++      ** It is not possible for an OOM to occur in this block. */
    ++      nByte = 0;
    ++      for(i=0; i<pTab->nCol; i++){
    ++        sqlite3_value *p = 0;
    ++        if( op!=SQLITE_INSERT ){
    ++          pSession->hook.xOld(pSession->hook.pCtx, i, &p);
    ++        }else if( pTab->abPK[i] ){
    ++          pSession->hook.xNew(pSession->hook.pCtx, i, &p);
    ++        }
    ++        sessionSerializeValue(&pChange->aRecord[nByte], p, &nByte);
    ++      }
    ++
    ++      /* Add the change to the hash-table */
    ++      if( pSession->bIndirect || pSession->hook.xDepth(pSession->hook.pCtx) ){
    ++        pChange->bIndirect = 1;
    ++      }
    ++      pChange->nRecord = nByte;
    ++      pChange->op = op;
    ++      pChange->pNext = pTab->apChange[iHash];
    ++      pTab->apChange[iHash] = pChange;
    ++
    ++    }else if( pC->bIndirect ){
    ++      /* If the existing change is considered "indirect", but this current
    ++      ** change is "direct", mark the change object as direct. */
    ++      if( pSession->hook.xDepth(pSession->hook.pCtx)==0 
    ++       && pSession->bIndirect==0 
    ++      ){
    ++        pC->bIndirect = 0;
    ++      }
    ++    }
    ++  }
    ++
    ++  /* If an error has occurred, mark the session object as failed. */
    ++ error_out:
    ++  if( pTab->bStat1 ){
    ++    pSession->hook = stat1.hook;
    ++  }
    ++  if( rc!=SQLITE_OK ){
    ++    pSession->rc = rc;
    ++  }
    ++}
    ++
    ++static int sessionFindTable(
    ++  sqlite3_session *pSession, 
    ++  const char *zName,
    ++  SessionTable **ppTab
    ++){
    ++  int rc = SQLITE_OK;
    ++  int nName = sqlite3Strlen30(zName);
    ++  SessionTable *pRet;
    ++
    ++  /* Search for an existing table */
    ++  for(pRet=pSession->pTable; pRet; pRet=pRet->pNext){
    ++    if( 0==sqlite3_strnicmp(pRet->zName, zName, nName+1) ) break;
    ++  }
    ++
    ++  if( pRet==0 && pSession->bAutoAttach ){
    ++    /* If there is a table-filter configured, invoke it. If it returns 0,
    ++    ** do not automatically add the new table. */
    ++    if( pSession->xTableFilter==0
    ++     || pSession->xTableFilter(pSession->pFilterCtx, zName) 
    ++    ){
    ++      rc = sqlite3session_attach(pSession, zName);
    ++      if( rc==SQLITE_OK ){
    ++        for(pRet=pSession->pTable; pRet->pNext; pRet=pRet->pNext);
    ++        assert( 0==sqlite3_strnicmp(pRet->zName, zName, nName+1) );
    ++      }
    ++    }
    ++  }
    ++
    ++  assert( rc==SQLITE_OK || pRet==0 );
    ++  *ppTab = pRet;
    ++  return rc;
    ++}
    ++
    ++/*
    ++** The 'pre-update' hook registered by this module with SQLite databases.
    ++*/
    ++static void xPreUpdate(
    ++  void *pCtx,                     /* Copy of third arg to preupdate_hook() */
    ++  sqlite3 *db,                    /* Database handle */
    ++  int op,                         /* SQLITE_UPDATE, DELETE or INSERT */
    ++  char const *zDb,                /* Database name */
    ++  char const *zName,              /* Table name */
    ++  sqlite3_int64 iKey1,            /* Rowid of row about to be deleted/updated */
    ++  sqlite3_int64 iKey2             /* New rowid value (for a rowid UPDATE) */
    ++){
    ++  sqlite3_session *pSession;
    ++  int nDb = sqlite3Strlen30(zDb);
    ++
    ++  assert( sqlite3_mutex_held(db->mutex) );
    ++
    ++  for(pSession=(sqlite3_session *)pCtx; pSession; pSession=pSession->pNext){
    ++    SessionTable *pTab;
    ++
    ++    /* If this session is attached to a different database ("main", "temp" 
    ++    ** etc.), or if it is not currently enabled, there is nothing to do. Skip 
    ++    ** to the next session object attached to this database. */
    ++    if( pSession->bEnable==0 ) continue;
    ++    if( pSession->rc ) continue;
    ++    if( sqlite3_strnicmp(zDb, pSession->zDb, nDb+1) ) continue;
    ++
    ++    pSession->rc = sessionFindTable(pSession, zName, &pTab);
    ++    if( pTab ){
    ++      assert( pSession->rc==SQLITE_OK );
    ++      sessionPreupdateOneChange(op, pSession, pTab);
    ++      if( op==SQLITE_UPDATE ){
    ++        sessionPreupdateOneChange(SQLITE_INSERT, pSession, pTab);
    ++      }
    ++    }
    ++  }
    ++}
    ++
    ++/*
    ++** The pre-update hook implementations.
    ++*/
    ++static int sessionPreupdateOld(void *pCtx, int iVal, sqlite3_value **ppVal){
    ++  return sqlite3_preupdate_old((sqlite3*)pCtx, iVal, ppVal);
    ++}
    ++static int sessionPreupdateNew(void *pCtx, int iVal, sqlite3_value **ppVal){
    ++  return sqlite3_preupdate_new((sqlite3*)pCtx, iVal, ppVal);
    ++}
    ++static int sessionPreupdateCount(void *pCtx){
    ++  return sqlite3_preupdate_count((sqlite3*)pCtx);
    ++}
    ++static int sessionPreupdateDepth(void *pCtx){
    ++  return sqlite3_preupdate_depth((sqlite3*)pCtx);
    ++}
    ++
    ++/*
    ++** Install the pre-update hooks on the session object passed as the only
    ++** argument.
    ++*/
    ++static void sessionPreupdateHooks(
    ++  sqlite3_session *pSession
    ++){
    ++  pSession->hook.pCtx = (void*)pSession->db;
    ++  pSession->hook.xOld = sessionPreupdateOld;
    ++  pSession->hook.xNew = sessionPreupdateNew;
    ++  pSession->hook.xCount = sessionPreupdateCount;
    ++  pSession->hook.xDepth = sessionPreupdateDepth;
    ++}
    ++
    ++typedef struct SessionDiffCtx SessionDiffCtx;
    ++struct SessionDiffCtx {
    ++  sqlite3_stmt *pStmt;
    ++  int nOldOff;
    ++};
    ++
    ++/*
    ++** The diff hook implementations.
    ++*/
    ++static int sessionDiffOld(void *pCtx, int iVal, sqlite3_value **ppVal){
    ++  SessionDiffCtx *p = (SessionDiffCtx*)pCtx;
    ++  *ppVal = sqlite3_column_value(p->pStmt, iVal+p->nOldOff);
    ++  return SQLITE_OK;
    ++}
    ++static int sessionDiffNew(void *pCtx, int iVal, sqlite3_value **ppVal){
    ++  SessionDiffCtx *p = (SessionDiffCtx*)pCtx;
    ++  *ppVal = sqlite3_column_value(p->pStmt, iVal);
    ++   return SQLITE_OK;
    ++}
    ++static int sessionDiffCount(void *pCtx){
    ++  SessionDiffCtx *p = (SessionDiffCtx*)pCtx;
    ++  return p->nOldOff ? p->nOldOff : sqlite3_column_count(p->pStmt);
    ++}
    ++static int sessionDiffDepth(void *pCtx){
    ++  return 0;
    ++}
    ++
    ++/*
    ++** Install the diff hooks on the session object passed as the only
    ++** argument.
    ++*/
    ++static void sessionDiffHooks(
    ++  sqlite3_session *pSession,
    ++  SessionDiffCtx *pDiffCtx
    ++){
    ++  pSession->hook.pCtx = (void*)pDiffCtx;
    ++  pSession->hook.xOld = sessionDiffOld;
    ++  pSession->hook.xNew = sessionDiffNew;
    ++  pSession->hook.xCount = sessionDiffCount;
    ++  pSession->hook.xDepth = sessionDiffDepth;
    ++}
    ++
    ++static char *sessionExprComparePK(
    ++  int nCol,
    ++  const char *zDb1, const char *zDb2, 
    ++  const char *zTab,
    ++  const char **azCol, u8 *abPK
    ++){
    ++  int i;
    ++  const char *zSep = "";
    ++  char *zRet = 0;
    ++
    ++  for(i=0; i<nCol; i++){
    ++    if( abPK[i] ){
    ++      zRet = sqlite3_mprintf("%z%s\"%w\".\"%w\".\"%w\"=\"%w\".\"%w\".\"%w\"",
    ++          zRet, zSep, zDb1, zTab, azCol[i], zDb2, zTab, azCol[i]
    ++      );
    ++      zSep = " AND ";
    ++      if( zRet==0 ) break;
    ++    }
    ++  }
    ++
    ++  return zRet;
    ++}
    ++
    ++static char *sessionExprCompareOther(
    ++  int nCol,
    ++  const char *zDb1, const char *zDb2, 
    ++  const char *zTab,
    ++  const char **azCol, u8 *abPK
    ++){
    ++  int i;
    ++  const char *zSep = "";
    ++  char *zRet = 0;
    ++  int bHave = 0;
    ++
    ++  for(i=0; i<nCol; i++){
    ++    if( abPK[i]==0 ){
    ++      bHave = 1;
    ++      zRet = sqlite3_mprintf(
    ++          "%z%s\"%w\".\"%w\".\"%w\" IS NOT \"%w\".\"%w\".\"%w\"",
    ++          zRet, zSep, zDb1, zTab, azCol[i], zDb2, zTab, azCol[i]
    ++      );
    ++      zSep = " OR ";
    ++      if( zRet==0 ) break;
    ++    }
    ++  }
    ++
    ++  if( bHave==0 ){
    ++    assert( zRet==0 );
    ++    zRet = sqlite3_mprintf("0");
    ++  }
    ++
    ++  return zRet;
    ++}
    ++
    ++static char *sessionSelectFindNew(
    ++  int nCol,
    ++  const char *zDb1,      /* Pick rows in this db only */
    ++  const char *zDb2,      /* But not in this one */
    ++  const char *zTbl,      /* Table name */
    ++  const char *zExpr
    ++){
    ++  char *zRet = sqlite3_mprintf(
    ++      "SELECT * FROM \"%w\".\"%w\" WHERE NOT EXISTS ("
    ++      "  SELECT 1 FROM \"%w\".\"%w\" WHERE %s"
    ++      ")",
    ++      zDb1, zTbl, zDb2, zTbl, zExpr
    ++  );
    ++  return zRet;
    ++}
    ++
    ++static int sessionDiffFindNew(
    ++  int op,
    ++  sqlite3_session *pSession,
    ++  SessionTable *pTab,
    ++  const char *zDb1,
    ++  const char *zDb2,
    ++  char *zExpr
    ++){
    ++  int rc = SQLITE_OK;
    ++  char *zStmt = sessionSelectFindNew(pTab->nCol, zDb1, zDb2, pTab->zName,zExpr);
    ++
    ++  if( zStmt==0 ){
    ++    rc = SQLITE_NOMEM;
    ++  }else{
    ++    sqlite3_stmt *pStmt;
    ++    rc = sqlite3_prepare(pSession->db, zStmt, -1, &pStmt, 0);
    ++    if( rc==SQLITE_OK ){
    ++      SessionDiffCtx *pDiffCtx = (SessionDiffCtx*)pSession->hook.pCtx;
    ++      pDiffCtx->pStmt = pStmt;
    ++      pDiffCtx->nOldOff = 0;
    ++      while( SQLITE_ROW==sqlite3_step(pStmt) ){
    ++        sessionPreupdateOneChange(op, pSession, pTab);
    ++      }
    ++      rc = sqlite3_finalize(pStmt);
    ++    }
    ++    sqlite3_free(zStmt);
    ++  }
    ++
    ++  return rc;
    ++}
    ++
    ++static int sessionDiffFindModified(
    ++  sqlite3_session *pSession, 
    ++  SessionTable *pTab, 
    ++  const char *zFrom, 
    ++  const char *zExpr
    ++){
    ++  int rc = SQLITE_OK;
    ++
    ++  char *zExpr2 = sessionExprCompareOther(pTab->nCol,
    ++      pSession->zDb, zFrom, pTab->zName, pTab->azCol, pTab->abPK
    ++  );
    ++  if( zExpr2==0 ){
    ++    rc = SQLITE_NOMEM;
    ++  }else{
    ++    char *zStmt = sqlite3_mprintf(
    ++        "SELECT * FROM \"%w\".\"%w\", \"%w\".\"%w\" WHERE %s AND (%z)",
    ++        pSession->zDb, pTab->zName, zFrom, pTab->zName, zExpr, zExpr2
    ++    );
    ++    if( zStmt==0 ){
    ++      rc = SQLITE_NOMEM;
    ++    }else{
    ++      sqlite3_stmt *pStmt;
    ++      rc = sqlite3_prepare(pSession->db, zStmt, -1, &pStmt, 0);
    ++
    ++      if( rc==SQLITE_OK ){
    ++        SessionDiffCtx *pDiffCtx = (SessionDiffCtx*)pSession->hook.pCtx;
    ++        pDiffCtx->pStmt = pStmt;
    ++        pDiffCtx->nOldOff = pTab->nCol;
    ++        while( SQLITE_ROW==sqlite3_step(pStmt) ){
    ++          sessionPreupdateOneChange(SQLITE_UPDATE, pSession, pTab);
    ++        }
    ++        rc = sqlite3_finalize(pStmt);
    ++      }
    ++      sqlite3_free(zStmt);
    ++    }
    ++  }
    ++
    ++  return rc;
    ++}
    ++
    ++SQLITE_API int sqlite3session_diff(
    ++  sqlite3_session *pSession,
    ++  const char *zFrom,
    ++  const char *zTbl,
    ++  char **pzErrMsg
    ++){
    ++  const char *zDb = pSession->zDb;
    ++  int rc = pSession->rc;
    ++  SessionDiffCtx d;
    ++
    ++  memset(&d, 0, sizeof(d));
    ++  sessionDiffHooks(pSession, &d);
    ++
    ++  sqlite3_mutex_enter(sqlite3_db_mutex(pSession->db));
    ++  if( pzErrMsg ) *pzErrMsg = 0;
    ++  if( rc==SQLITE_OK ){
    ++    char *zExpr = 0;
    ++    sqlite3 *db = pSession->db;
    ++    SessionTable *pTo;            /* Table zTbl */
    ++
    ++    /* Locate and if necessary initialize the target table object */
    ++    rc = sessionFindTable(pSession, zTbl, &pTo);
    ++    if( pTo==0 ) goto diff_out;
    ++    if( sessionInitTable(pSession, pTo) ){
    ++      rc = pSession->rc;
    ++      goto diff_out;
    ++    }
    ++
    ++    /* Check the table schemas match */
    ++    if( rc==SQLITE_OK ){
    ++      int bHasPk = 0;
    ++      int bMismatch = 0;
    ++      int nCol;                   /* Columns in zFrom.zTbl */
    ++      u8 *abPK;
    ++      const char **azCol = 0;
    ++      rc = sessionTableInfo(db, zFrom, zTbl, &nCol, 0, &azCol, &abPK);
    ++      if( rc==SQLITE_OK ){
    ++        if( pTo->nCol!=nCol ){
    ++          bMismatch = 1;
    ++        }else{
    ++          int i;
    ++          for(i=0; i<nCol; i++){
    ++            if( pTo->abPK[i]!=abPK[i] ) bMismatch = 1;
    ++            if( sqlite3_stricmp(azCol[i], pTo->azCol[i]) ) bMismatch = 1;
    ++            if( abPK[i] ) bHasPk = 1;
    ++          }
    ++        }
    ++      }
    ++      sqlite3_free((char*)azCol);
    ++      if( bMismatch ){
    ++        *pzErrMsg = sqlite3_mprintf("table schemas do not match");
    ++        rc = SQLITE_SCHEMA;
    ++      }
    ++      if( bHasPk==0 ){
    ++        /* Ignore tables with no primary keys */
    ++        goto diff_out;
    ++      }
    ++    }
    ++
    ++    if( rc==SQLITE_OK ){
    ++      zExpr = sessionExprComparePK(pTo->nCol, 
    ++          zDb, zFrom, pTo->zName, pTo->azCol, pTo->abPK
    ++      );
    ++    }
    ++
    ++    /* Find new rows */
    ++    if( rc==SQLITE_OK ){
    ++      rc = sessionDiffFindNew(SQLITE_INSERT, pSession, pTo, zDb, zFrom, zExpr);
    ++    }
    ++
    ++    /* Find old rows */
    ++    if( rc==SQLITE_OK ){
    ++      rc = sessionDiffFindNew(SQLITE_DELETE, pSession, pTo, zFrom, zDb, zExpr);
    ++    }
    ++
    ++    /* Find modified rows */
    ++    if( rc==SQLITE_OK ){
    ++      rc = sessionDiffFindModified(pSession, pTo, zFrom, zExpr);
    ++    }
    ++
    ++    sqlite3_free(zExpr);
    ++  }
    ++
    ++ diff_out:
    ++  sessionPreupdateHooks(pSession);
    ++  sqlite3_mutex_leave(sqlite3_db_mutex(pSession->db));
    ++  return rc;
    ++}
    ++
    ++/*
    ++** Create a session object. This session object will record changes to
    ++** database zDb attached to connection db.
    ++*/
    ++SQLITE_API int sqlite3session_create(
    ++  sqlite3 *db,                    /* Database handle */
    ++  const char *zDb,                /* Name of db (e.g. "main") */
    ++  sqlite3_session **ppSession     /* OUT: New session object */
    ++){
    ++  sqlite3_session *pNew;          /* Newly allocated session object */
    ++  sqlite3_session *pOld;          /* Session object already attached to db */
    ++  int nDb = sqlite3Strlen30(zDb); /* Length of zDb in bytes */
    ++
    ++  /* Zero the output value in case an error occurs. */
    ++  *ppSession = 0;
    ++
    ++  /* Allocate and populate the new session object. */
    ++  pNew = (sqlite3_session *)sqlite3_malloc(sizeof(sqlite3_session) + nDb + 1);
    ++  if( !pNew ) return SQLITE_NOMEM;
    ++  memset(pNew, 0, sizeof(sqlite3_session));
    ++  pNew->db = db;
    ++  pNew->zDb = (char *)&pNew[1];
    ++  pNew->bEnable = 1;
    ++  memcpy(pNew->zDb, zDb, nDb+1);
    ++  sessionPreupdateHooks(pNew);
    ++
    ++  /* Add the new session object to the linked list of session objects 
    ++  ** attached to database handle $db. Do this under the cover of the db
    ++  ** handle mutex.  */
    ++  sqlite3_mutex_enter(sqlite3_db_mutex(db));
    ++  pOld = (sqlite3_session*)sqlite3_preupdate_hook(db, xPreUpdate, (void*)pNew);
    ++  pNew->pNext = pOld;
    ++  sqlite3_mutex_leave(sqlite3_db_mutex(db));
    ++
    ++  *ppSession = pNew;
    ++  return SQLITE_OK;
    ++}
    ++
    ++/*
    ++** Free the list of table objects passed as the first argument. The contents
    ++** of the changed-rows hash tables are also deleted.
    ++*/
    ++static void sessionDeleteTable(SessionTable *pList){
    ++  SessionTable *pNext;
    ++  SessionTable *pTab;
    ++
    ++  for(pTab=pList; pTab; pTab=pNext){
    ++    int i;
    ++    pNext = pTab->pNext;
    ++    for(i=0; i<pTab->nChange; i++){
    ++      SessionChange *p;
    ++      SessionChange *pNextChange;
    ++      for(p=pTab->apChange[i]; p; p=pNextChange){
    ++        pNextChange = p->pNext;
    ++        sqlite3_free(p);
    ++      }
    ++    }
    ++    sqlite3_free((char*)pTab->azCol);  /* cast works around VC++ bug */
    ++    sqlite3_free(pTab->apChange);
    ++    sqlite3_free(pTab);
    ++  }
    ++}
    ++
    ++/*
    ++** Delete a session object previously allocated using sqlite3session_create().
    ++*/
    ++SQLITE_API void sqlite3session_delete(sqlite3_session *pSession){
    ++  sqlite3 *db = pSession->db;
    ++  sqlite3_session *pHead;
    ++  sqlite3_session **pp;
    ++
    ++  /* Unlink the session from the linked list of sessions attached to the
    ++  ** database handle. Hold the db mutex while doing so.  */
    ++  sqlite3_mutex_enter(sqlite3_db_mutex(db));
    ++  pHead = (sqlite3_session*)sqlite3_preupdate_hook(db, 0, 0);
    ++  for(pp=&pHead; ALWAYS((*pp)!=0); pp=&((*pp)->pNext)){
    ++    if( (*pp)==pSession ){
    ++      *pp = (*pp)->pNext;
    ++      if( pHead ) sqlite3_preupdate_hook(db, xPreUpdate, (void*)pHead);
    ++      break;
    ++    }
    ++  }
    ++  sqlite3_mutex_leave(sqlite3_db_mutex(db));
    ++  sqlite3ValueFree(pSession->pZeroBlob);
    ++
    ++  /* Delete all attached table objects. And the contents of their 
    ++  ** associated hash-tables. */
    ++  sessionDeleteTable(pSession->pTable);
    ++
    ++  /* Free the session object itself. */
    ++  sqlite3_free(pSession);
    ++}
    ++
    ++/*
    ++** Set a table filter on a Session Object.
    ++*/
    ++SQLITE_API void sqlite3session_table_filter(
    ++  sqlite3_session *pSession, 
    ++  int(*xFilter)(void*, const char*),
    ++  void *pCtx                      /* First argument passed to xFilter */
    ++){
    ++  pSession->bAutoAttach = 1;
    ++  pSession->pFilterCtx = pCtx;
    ++  pSession->xTableFilter = xFilter;
    ++}
    ++
    ++/*
    ++** Attach a table to a session. All subsequent changes made to the table
    ++** while the session object is enabled will be recorded.
    ++**
    ++** Only tables that have a PRIMARY KEY defined may be attached. It does
    ++** not matter if the PRIMARY KEY is an "INTEGER PRIMARY KEY" (rowid alias)
    ++** or not.
    ++*/
    ++SQLITE_API int sqlite3session_attach(
    ++  sqlite3_session *pSession,      /* Session object */
    ++  const char *zName               /* Table name */
    ++){
    ++  int rc = SQLITE_OK;
    ++  sqlite3_mutex_enter(sqlite3_db_mutex(pSession->db));
    ++
    ++  if( !zName ){
    ++    pSession->bAutoAttach = 1;
    ++  }else{
    ++    SessionTable *pTab;           /* New table object (if required) */
    ++    int nName;                    /* Number of bytes in string zName */
    ++
    ++    /* First search for an existing entry. If one is found, this call is
    ++    ** a no-op. Return early. */
    ++    nName = sqlite3Strlen30(zName);
    ++    for(pTab=pSession->pTable; pTab; pTab=pTab->pNext){
    ++      if( 0==sqlite3_strnicmp(pTab->zName, zName, nName+1) ) break;
    ++    }
    ++
    ++    if( !pTab ){
    ++      /* Allocate new SessionTable object. */
    ++      pTab = (SessionTable *)sqlite3_malloc(sizeof(SessionTable) + nName + 1);
    ++      if( !pTab ){
    ++        rc = SQLITE_NOMEM;
    ++      }else{
    ++        /* Populate the new SessionTable object and link it into the list.
    ++        ** The new object must be linked onto the end of the list, not 
    ++        ** simply added to the start of it in order to ensure that tables
    ++        ** appear in the correct order when a changeset or patchset is
    ++        ** eventually generated. */
    ++        SessionTable **ppTab;
    ++        memset(pTab, 0, sizeof(SessionTable));
    ++        pTab->zName = (char *)&pTab[1];
    ++        memcpy(pTab->zName, zName, nName+1);
    ++        for(ppTab=&pSession->pTable; *ppTab; ppTab=&(*ppTab)->pNext);
    ++        *ppTab = pTab;
    ++      }
    ++    }
    ++  }
    ++
    ++  sqlite3_mutex_leave(sqlite3_db_mutex(pSession->db));
    ++  return rc;
    ++}
    ++
    ++/*
    ++** Ensure that there is room in the buffer to append nByte bytes of data.
    ++** If not, use sqlite3_realloc() to grow the buffer so that there is.
    ++**
    ++** If successful, return zero. Otherwise, if an OOM condition is encountered,
    ++** set *pRc to SQLITE_NOMEM and return non-zero.
    ++*/
    ++static int sessionBufferGrow(SessionBuffer *p, int nByte, int *pRc){
    ++  if( *pRc==SQLITE_OK && p->nAlloc-p->nBuf<nByte ){
    ++    u8 *aNew;
    ++    int nNew = p->nAlloc ? p->nAlloc : 128;
    ++    do {
    ++      nNew = nNew*2;
    ++    }while( nNew<(p->nBuf+nByte) );
    ++
    ++    aNew = (u8 *)sqlite3_realloc(p->aBuf, nNew);
    ++    if( 0==aNew ){
    ++      *pRc = SQLITE_NOMEM;
    ++    }else{
    ++      p->aBuf = aNew;
    ++      p->nAlloc = nNew;
    ++    }
    ++  }
    ++  return (*pRc!=SQLITE_OK);
    ++}
    ++
    ++/*
    ++** Append the value passed as the second argument to the buffer passed
    ++** as the first.
    ++**
    ++** This function is a no-op if *pRc is non-zero when it is called.
    ++** Otherwise, if an error occurs, *pRc is set to an SQLite error code
    ++** before returning.
    ++*/
    ++static void sessionAppendValue(SessionBuffer *p, sqlite3_value *pVal, int *pRc){
    ++  int rc = *pRc;
    ++  if( rc==SQLITE_OK ){
    ++    int nByte = 0;
    ++    rc = sessionSerializeValue(0, pVal, &nByte);
    ++    sessionBufferGrow(p, nByte, &rc);
    ++    if( rc==SQLITE_OK ){
    ++      rc = sessionSerializeValue(&p->aBuf[p->nBuf], pVal, 0);
    ++      p->nBuf += nByte;
    ++    }else{
    ++      *pRc = rc;
    ++    }
    ++  }
    ++}
    ++
    ++/*
    ++** This function is a no-op if *pRc is other than SQLITE_OK when it is 
    ++** called. Otherwise, append a single byte to the buffer. 
    ++**
    ++** If an OOM condition is encountered, set *pRc to SQLITE_NOMEM before
    ++** returning.
    ++*/
    ++static void sessionAppendByte(SessionBuffer *p, u8 v, int *pRc){
    ++  if( 0==sessionBufferGrow(p, 1, pRc) ){
    ++    p->aBuf[p->nBuf++] = v;
    ++  }
    ++}
    ++
    ++/*
    ++** This function is a no-op if *pRc is other than SQLITE_OK when it is 
    ++** called. Otherwise, append a single varint to the buffer. 
    ++**
    ++** If an OOM condition is encountered, set *pRc to SQLITE_NOMEM before
    ++** returning.
    ++*/
    ++static void sessionAppendVarint(SessionBuffer *p, int v, int *pRc){
    ++  if( 0==sessionBufferGrow(p, 9, pRc) ){
    ++    p->nBuf += sessionVarintPut(&p->aBuf[p->nBuf], v);
    ++  }
    ++}
    ++
    ++/*
    ++** This function is a no-op if *pRc is other than SQLITE_OK when it is 
    ++** called. Otherwise, append a blob of data to the buffer. 
    ++**
    ++** If an OOM condition is encountered, set *pRc to SQLITE_NOMEM before
    ++** returning.
    ++*/
    ++static void sessionAppendBlob(
    ++  SessionBuffer *p, 
    ++  const u8 *aBlob, 
    ++  int nBlob, 
    ++  int *pRc
    ++){
    ++  if( nBlob>0 && 0==sessionBufferGrow(p, nBlob, pRc) ){
    ++    memcpy(&p->aBuf[p->nBuf], aBlob, nBlob);
    ++    p->nBuf += nBlob;
    ++  }
    ++}
    ++
    ++/*
    ++** This function is a no-op if *pRc is other than SQLITE_OK when it is 
    ++** called. Otherwise, append a string to the buffer. All bytes in the string
    ++** up to (but not including) the nul-terminator are written to the buffer.
    ++**
    ++** If an OOM condition is encountered, set *pRc to SQLITE_NOMEM before
    ++** returning.
    ++*/
    ++static void sessionAppendStr(
    ++  SessionBuffer *p, 
    ++  const char *zStr, 
    ++  int *pRc
    ++){
    ++  int nStr = sqlite3Strlen30(zStr);
    ++  if( 0==sessionBufferGrow(p, nStr, pRc) ){
    ++    memcpy(&p->aBuf[p->nBuf], zStr, nStr);
    ++    p->nBuf += nStr;
    ++  }
    ++}
    ++
    ++/*
    ++** This function is a no-op if *pRc is other than SQLITE_OK when it is 
    ++** called. Otherwise, append the string representation of integer iVal
    ++** to the buffer. No nul-terminator is written.
    ++**
    ++** If an OOM condition is encountered, set *pRc to SQLITE_NOMEM before
    ++** returning.
    ++*/
    ++static void sessionAppendInteger(
    ++  SessionBuffer *p,               /* Buffer to append to */
    ++  int iVal,                       /* Value to write the string rep. of */
    ++  int *pRc                        /* IN/OUT: Error code */
    ++){
    ++  char aBuf[24];
    ++  sqlite3_snprintf(sizeof(aBuf)-1, aBuf, "%d", iVal);
    ++  sessionAppendStr(p, aBuf, pRc);
    ++}
    ++
    ++/*
    ++** This function is a no-op if *pRc is other than SQLITE_OK when it is 
    ++** called. Otherwise, append the string zStr enclosed in quotes (") and
    ++** with any embedded quote characters escaped to the buffer. No 
    ++** nul-terminator byte is written.
    ++**
    ++** If an OOM condition is encountered, set *pRc to SQLITE_NOMEM before
    ++** returning.
    ++*/
    ++static void sessionAppendIdent(
    ++  SessionBuffer *p,               /* Buffer to a append to */
    ++  const char *zStr,               /* String to quote, escape and append */
    ++  int *pRc                        /* IN/OUT: Error code */
    ++){
    ++  int nStr = sqlite3Strlen30(zStr)*2 + 2 + 1;
    ++  if( 0==sessionBufferGrow(p, nStr, pRc) ){
    ++    char *zOut = (char *)&p->aBuf[p->nBuf];
    ++    const char *zIn = zStr;
    ++    *zOut++ = '"';
    ++    while( *zIn ){
    ++      if( *zIn=='"' ) *zOut++ = '"';
    ++      *zOut++ = *(zIn++);
    ++    }
    ++    *zOut++ = '"';
    ++    p->nBuf = (int)((u8 *)zOut - p->aBuf);
    ++  }
    ++}
    ++
    ++/*
    ++** This function is a no-op if *pRc is other than SQLITE_OK when it is
    ++** called. Otherwse, it appends the serialized version of the value stored
    ++** in column iCol of the row that SQL statement pStmt currently points
    ++** to to the buffer.
    ++*/
    ++static void sessionAppendCol(
    ++  SessionBuffer *p,               /* Buffer to append to */
    ++  sqlite3_stmt *pStmt,            /* Handle pointing to row containing value */
    ++  int iCol,                       /* Column to read value from */
    ++  int *pRc                        /* IN/OUT: Error code */
    ++){
    ++  if( *pRc==SQLITE_OK ){
    ++    int eType = sqlite3_column_type(pStmt, iCol);
    ++    sessionAppendByte(p, (u8)eType, pRc);
    ++    if( eType==SQLITE_INTEGER || eType==SQLITE_FLOAT ){
    ++      sqlite3_int64 i;
    ++      u8 aBuf[8];
    ++      if( eType==SQLITE_INTEGER ){
    ++        i = sqlite3_column_int64(pStmt, iCol);
    ++      }else{
    ++        double r = sqlite3_column_double(pStmt, iCol);
    ++        memcpy(&i, &r, 8);
    ++      }
    ++      sessionPutI64(aBuf, i);
    ++      sessionAppendBlob(p, aBuf, 8, pRc);
    ++    }
    ++    if( eType==SQLITE_BLOB || eType==SQLITE_TEXT ){
    ++      u8 *z;
    ++      int nByte;
    ++      if( eType==SQLITE_BLOB ){
    ++        z = (u8 *)sqlite3_column_blob(pStmt, iCol);
    ++      }else{
    ++        z = (u8 *)sqlite3_column_text(pStmt, iCol);
    ++      }
    ++      nByte = sqlite3_column_bytes(pStmt, iCol);
    ++      if( z || (eType==SQLITE_BLOB && nByte==0) ){
    ++        sessionAppendVarint(p, nByte, pRc);
    ++        sessionAppendBlob(p, z, nByte, pRc);
    ++      }else{
    ++        *pRc = SQLITE_NOMEM;
    ++      }
    ++    }
    ++  }
    ++}
    ++
    ++/*
    ++**
    ++** This function appends an update change to the buffer (see the comments 
    ++** under "CHANGESET FORMAT" at the top of the file). An update change 
    ++** consists of:
    ++**
    ++**   1 byte:  SQLITE_UPDATE (0x17)
    ++**   n bytes: old.* record (see RECORD FORMAT)
    ++**   m bytes: new.* record (see RECORD FORMAT)
    ++**
    ++** The SessionChange object passed as the third argument contains the
    ++** values that were stored in the row when the session began (the old.*
    ++** values). The statement handle passed as the second argument points
    ++** at the current version of the row (the new.* values).
    ++**
    ++** If all of the old.* values are equal to their corresponding new.* value
    ++** (i.e. nothing has changed), then no data at all is appended to the buffer.
    ++**
    ++** Otherwise, the old.* record contains all primary key values and the 
    ++** original values of any fields that have been modified. The new.* record 
    ++** contains the new values of only those fields that have been modified.
    ++*/ 
    ++static int sessionAppendUpdate(
    ++  SessionBuffer *pBuf,            /* Buffer to append to */
    ++  int bPatchset,                  /* True for "patchset", 0 for "changeset" */
    ++  sqlite3_stmt *pStmt,            /* Statement handle pointing at new row */
    ++  SessionChange *p,               /* Object containing old values */
    ++  u8 *abPK                        /* Boolean array - true for PK columns */
    ++){
    ++  int rc = SQLITE_OK;
    ++  SessionBuffer buf2 = {0,0,0}; /* Buffer to accumulate new.* record in */
    ++  int bNoop = 1;                /* Set to zero if any values are modified */
    ++  int nRewind = pBuf->nBuf;     /* Set to zero if any values are modified */
    ++  int i;                        /* Used to iterate through columns */
    ++  u8 *pCsr = p->aRecord;        /* Used to iterate through old.* values */
    ++
    ++  sessionAppendByte(pBuf, SQLITE_UPDATE, &rc);
    ++  sessionAppendByte(pBuf, p->bIndirect, &rc);
    ++  for(i=0; i<sqlite3_column_count(pStmt); i++){
    ++    int bChanged = 0;
    ++    int nAdvance;
    ++    int eType = *pCsr;
    ++    switch( eType ){
    ++      case SQLITE_NULL:
    ++        nAdvance = 1;
    ++        if( sqlite3_column_type(pStmt, i)!=SQLITE_NULL ){
    ++          bChanged = 1;
    ++        }
    ++        break;
    ++
    ++      case SQLITE_FLOAT:
    ++      case SQLITE_INTEGER: {
    ++        nAdvance = 9;
    ++        if( eType==sqlite3_column_type(pStmt, i) ){
    ++          sqlite3_int64 iVal = sessionGetI64(&pCsr[1]);
    ++          if( eType==SQLITE_INTEGER ){
    ++            if( iVal==sqlite3_column_int64(pStmt, i) ) break;
    ++          }else{
    ++            double dVal;
    ++            memcpy(&dVal, &iVal, 8);
    ++            if( dVal==sqlite3_column_double(pStmt, i) ) break;
    ++          }
    ++        }
    ++        bChanged = 1;
    ++        break;
    ++      }
    ++
    ++      default: {
    ++        int n;
    ++        int nHdr = 1 + sessionVarintGet(&pCsr[1], &n);
    ++        assert( eType==SQLITE_TEXT || eType==SQLITE_BLOB );
    ++        nAdvance = nHdr + n;
    ++        if( eType==sqlite3_column_type(pStmt, i) 
    ++         && n==sqlite3_column_bytes(pStmt, i) 
    ++         && (n==0 || 0==memcmp(&pCsr[nHdr], sqlite3_column_blob(pStmt, i), n))
    ++        ){
    ++          break;
    ++        }
    ++        bChanged = 1;
    ++      }
    ++    }
    ++
    ++    /* If at least one field has been modified, this is not a no-op. */
    ++    if( bChanged ) bNoop = 0;
    ++
    ++    /* Add a field to the old.* record. This is omitted if this modules is
    ++    ** currently generating a patchset. */
    ++    if( bPatchset==0 ){
    ++      if( bChanged || abPK[i] ){
    ++        sessionAppendBlob(pBuf, pCsr, nAdvance, &rc);
    ++      }else{
    ++        sessionAppendByte(pBuf, 0, &rc);
    ++      }
    ++    }
    ++
    ++    /* Add a field to the new.* record. Or the only record if currently
    ++    ** generating a patchset.  */
    ++    if( bChanged || (bPatchset && abPK[i]) ){
    ++      sessionAppendCol(&buf2, pStmt, i, &rc);
    ++    }else{
    ++      sessionAppendByte(&buf2, 0, &rc);
    ++    }
    ++
    ++    pCsr += nAdvance;
    ++  }
    ++
    ++  if( bNoop ){
    ++    pBuf->nBuf = nRewind;
    ++  }else{
    ++    sessionAppendBlob(pBuf, buf2.aBuf, buf2.nBuf, &rc);
    ++  }
    ++  sqlite3_free(buf2.aBuf);
    ++
    ++  return rc;
    ++}
    ++
    ++/*
    ++** Append a DELETE change to the buffer passed as the first argument. Use
    ++** the changeset format if argument bPatchset is zero, or the patchset
    ++** format otherwise.
    ++*/
    ++static int sessionAppendDelete(
    ++  SessionBuffer *pBuf,            /* Buffer to append to */
    ++  int bPatchset,                  /* True for "patchset", 0 for "changeset" */
    ++  SessionChange *p,               /* Object containing old values */
    ++  int nCol,                       /* Number of columns in table */
    ++  u8 *abPK                        /* Boolean array - true for PK columns */
    ++){
    ++  int rc = SQLITE_OK;
    ++
    ++  sessionAppendByte(pBuf, SQLITE_DELETE, &rc);
    ++  sessionAppendByte(pBuf, p->bIndirect, &rc);
    ++
    ++  if( bPatchset==0 ){
    ++    sessionAppendBlob(pBuf, p->aRecord, p->nRecord, &rc);
    ++  }else{
    ++    int i;
    ++    u8 *a = p->aRecord;
    ++    for(i=0; i<nCol; i++){
    ++      u8 *pStart = a;
    ++      int eType = *a++;
    ++
    ++      switch( eType ){
    ++        case 0:
    ++        case SQLITE_NULL:
    ++          assert( abPK[i]==0 );
    ++          break;
    ++
    ++        case SQLITE_FLOAT:
    ++        case SQLITE_INTEGER:
    ++          a += 8;
    ++          break;
    ++
    ++        default: {
    ++          int n;
    ++          a += sessionVarintGet(a, &n);
    ++          a += n;
    ++          break;
    ++        }
    ++      }
    ++      if( abPK[i] ){
    ++        sessionAppendBlob(pBuf, pStart, (int)(a-pStart), &rc);
    ++      }
    ++    }
    ++    assert( (a - p->aRecord)==p->nRecord );
    ++  }
    ++
    ++  return rc;
    ++}
    ++
    ++/*
    ++** Formulate and prepare a SELECT statement to retrieve a row from table
    ++** zTab in database zDb based on its primary key. i.e.
    ++**
    ++**   SELECT * FROM zDb.zTab WHERE pk1 = ? AND pk2 = ? AND ...
    ++*/
    ++static int sessionSelectStmt(
    ++  sqlite3 *db,                    /* Database handle */
    ++  const char *zDb,                /* Database name */
    ++  const char *zTab,               /* Table name */
    ++  int nCol,                       /* Number of columns in table */
    ++  const char **azCol,             /* Names of table columns */
    ++  u8 *abPK,                       /* PRIMARY KEY  array */
    ++  sqlite3_stmt **ppStmt           /* OUT: Prepared SELECT statement */
    ++){
    ++  int rc = SQLITE_OK;
    ++  char *zSql = 0;
    ++  int nSql = -1;
    ++
    ++  if( 0==sqlite3_stricmp("sqlite_stat1", zTab) ){
    ++    zSql = sqlite3_mprintf(
    ++        "SELECT tbl, ?2, stat FROM %Q.sqlite_stat1 WHERE tbl IS ?1 AND "
    ++        "idx IS (CASE WHEN ?2=X'' THEN NULL ELSE ?2 END)", zDb
    ++    );
    ++  }else{
    ++    int i;
    ++    const char *zSep = "";
    ++    SessionBuffer buf = {0, 0, 0};
    ++
    ++    sessionAppendStr(&buf, "SELECT * FROM ", &rc);
    ++    sessionAppendIdent(&buf, zDb, &rc);
    ++    sessionAppendStr(&buf, ".", &rc);
    ++    sessionAppendIdent(&buf, zTab, &rc);
    ++    sessionAppendStr(&buf, " WHERE ", &rc);
    ++    for(i=0; i<nCol; i++){
    ++      if( abPK[i] ){
    ++        sessionAppendStr(&buf, zSep, &rc);
    ++        sessionAppendIdent(&buf, azCol[i], &rc);
    ++        sessionAppendStr(&buf, " IS ?", &rc);
    ++        sessionAppendInteger(&buf, i+1, &rc);
    ++        zSep = " AND ";
    ++      }
    ++    }
    ++    zSql = (char*)buf.aBuf;
    ++    nSql = buf.nBuf;
    ++  }
    ++
    ++  if( rc==SQLITE_OK ){
    ++    rc = sqlite3_prepare_v2(db, zSql, nSql, ppStmt, 0);
    ++  }
    ++  sqlite3_free(zSql);
    ++  return rc;
    ++}
    ++
    ++/*
    ++** Bind the PRIMARY KEY values from the change passed in argument pChange
    ++** to the SELECT statement passed as the first argument. The SELECT statement
    ++** is as prepared by function sessionSelectStmt().
    ++**
    ++** Return SQLITE_OK if all PK values are successfully bound, or an SQLite
    ++** error code (e.g. SQLITE_NOMEM) otherwise.
    ++*/
    ++static int sessionSelectBind(
    ++  sqlite3_stmt *pSelect,          /* SELECT from sessionSelectStmt() */
    ++  int nCol,                       /* Number of columns in table */
    ++  u8 *abPK,                       /* PRIMARY KEY array */
    ++  SessionChange *pChange          /* Change structure */
    ++){
    ++  int i;
    ++  int rc = SQLITE_OK;
    ++  u8 *a = pChange->aRecord;
    ++
    ++  for(i=0; i<nCol && rc==SQLITE_OK; i++){
    ++    int eType = *a++;
    ++
    ++    switch( eType ){
    ++      case 0:
    ++      case SQLITE_NULL:
    ++        assert( abPK[i]==0 );
    ++        break;
    ++
    ++      case SQLITE_INTEGER: {
    ++        if( abPK[i] ){
    ++          i64 iVal = sessionGetI64(a);
    ++          rc = sqlite3_bind_int64(pSelect, i+1, iVal);
    ++        }
    ++        a += 8;
    ++        break;
    ++      }
    ++
    ++      case SQLITE_FLOAT: {
    ++        if( abPK[i] ){
    ++          double rVal;
    ++          i64 iVal = sessionGetI64(a);
    ++          memcpy(&rVal, &iVal, 8);
    ++          rc = sqlite3_bind_double(pSelect, i+1, rVal);
    ++        }
    ++        a += 8;
    ++        break;
    ++      }
    ++
    ++      case SQLITE_TEXT: {
    ++        int n;
    ++        a += sessionVarintGet(a, &n);
    ++        if( abPK[i] ){
    ++          rc = sqlite3_bind_text(pSelect, i+1, (char *)a, n, SQLITE_TRANSIENT);
    ++        }
    ++        a += n;
    ++        break;
    ++      }
    ++
    ++      default: {
    ++        int n;
    ++        assert( eType==SQLITE_BLOB );
    ++        a += sessionVarintGet(a, &n);
    ++        if( abPK[i] ){
    ++          rc = sqlite3_bind_blob(pSelect, i+1, a, n, SQLITE_TRANSIENT);
    ++        }
    ++        a += n;
    ++        break;
    ++      }
    ++    }
    ++  }
    ++
    ++  return rc;
    ++}
    ++
    ++/*
    ++** This function is a no-op if *pRc is set to other than SQLITE_OK when it
    ++** is called. Otherwise, append a serialized table header (part of the binary 
    ++** changeset format) to buffer *pBuf. If an error occurs, set *pRc to an
    ++** SQLite error code before returning.
    ++*/
    ++static void sessionAppendTableHdr(
    ++  SessionBuffer *pBuf,            /* Append header to this buffer */
    ++  int bPatchset,                  /* Use the patchset format if true */
    ++  SessionTable *pTab,             /* Table object to append header for */
    ++  int *pRc                        /* IN/OUT: Error code */
    ++){
    ++  /* Write a table header */
    ++  sessionAppendByte(pBuf, (bPatchset ? 'P' : 'T'), pRc);
    ++  sessionAppendVarint(pBuf, pTab->nCol, pRc);
    ++  sessionAppendBlob(pBuf, pTab->abPK, pTab->nCol, pRc);
    ++  sessionAppendBlob(pBuf, (u8 *)pTab->zName, (int)strlen(pTab->zName)+1, pRc);
    ++}
    ++
    ++/*
    ++** Generate either a changeset (if argument bPatchset is zero) or a patchset
    ++** (if it is non-zero) based on the current contents of the session object
    ++** passed as the first argument.
    ++**
    ++** If no error occurs, SQLITE_OK is returned and the new changeset/patchset
    ++** stored in output variables *pnChangeset and *ppChangeset. Or, if an error
    ++** occurs, an SQLite error code is returned and both output variables set 
    ++** to 0.
    ++*/
    ++static int sessionGenerateChangeset(
    ++  sqlite3_session *pSession,      /* Session object */
    ++  int bPatchset,                  /* True for patchset, false for changeset */
    ++  int (*xOutput)(void *pOut, const void *pData, int nData),
    ++  void *pOut,                     /* First argument for xOutput */
    ++  int *pnChangeset,               /* OUT: Size of buffer at *ppChangeset */
    ++  void **ppChangeset              /* OUT: Buffer containing changeset */
    ++){
    ++  sqlite3 *db = pSession->db;     /* Source database handle */
    ++  SessionTable *pTab;             /* Used to iterate through attached tables */
    ++  SessionBuffer buf = {0,0,0};    /* Buffer in which to accumlate changeset */
    ++  int rc;                         /* Return code */
    ++
    ++  assert( xOutput==0 || (pnChangeset==0 && ppChangeset==0 ) );
    ++
    ++  /* Zero the output variables in case an error occurs. If this session
    ++  ** object is already in the error state (sqlite3_session.rc != SQLITE_OK),
    ++  ** this call will be a no-op.  */
    ++  if( xOutput==0 ){
    ++    *pnChangeset = 0;
    ++    *ppChangeset = 0;
    ++  }
    ++
    ++  if( pSession->rc ) return pSession->rc;
    ++  rc = sqlite3_exec(pSession->db, "SAVEPOINT changeset", 0, 0, 0);
    ++  if( rc!=SQLITE_OK ) return rc;
    ++
    ++  sqlite3_mutex_enter(sqlite3_db_mutex(db));
    ++
    ++  for(pTab=pSession->pTable; rc==SQLITE_OK && pTab; pTab=pTab->pNext){
    ++    if( pTab->nEntry ){
    ++      const char *zName = pTab->zName;
    ++      int nCol;                   /* Number of columns in table */
    ++      u8 *abPK;                   /* Primary key array */
    ++      const char **azCol = 0;     /* Table columns */
    ++      int i;                      /* Used to iterate through hash buckets */
    ++      sqlite3_stmt *pSel = 0;     /* SELECT statement to query table pTab */
    ++      int nRewind = buf.nBuf;     /* Initial size of write buffer */
    ++      int nNoop;                  /* Size of buffer after writing tbl header */
    ++
    ++      /* Check the table schema is still Ok. */
    ++      rc = sessionTableInfo(db, pSession->zDb, zName, &nCol, 0, &azCol, &abPK);
    ++      if( !rc && (pTab->nCol!=nCol || memcmp(abPK, pTab->abPK, nCol)) ){
    ++        rc = SQLITE_SCHEMA;
    ++      }
    ++
    ++      /* Write a table header */
    ++      sessionAppendTableHdr(&buf, bPatchset, pTab, &rc);
    ++
    ++      /* Build and compile a statement to execute: */
    ++      if( rc==SQLITE_OK ){
    ++        rc = sessionSelectStmt(
    ++            db, pSession->zDb, zName, nCol, azCol, abPK, &pSel);
    ++      }
    ++
    ++      nNoop = buf.nBuf;
    ++      for(i=0; i<pTab->nChange && rc==SQLITE_OK; i++){
    ++        SessionChange *p;         /* Used to iterate through changes */
    ++
    ++        for(p=pTab->apChange[i]; rc==SQLITE_OK && p; p=p->pNext){
    ++          rc = sessionSelectBind(pSel, nCol, abPK, p);
    ++          if( rc!=SQLITE_OK ) continue;
    ++          if( sqlite3_step(pSel)==SQLITE_ROW ){
    ++            if( p->op==SQLITE_INSERT ){
    ++              int iCol;
    ++              sessionAppendByte(&buf, SQLITE_INSERT, &rc);
    ++              sessionAppendByte(&buf, p->bIndirect, &rc);
    ++              for(iCol=0; iCol<nCol; iCol++){
    ++                sessionAppendCol(&buf, pSel, iCol, &rc);
    ++              }
    ++            }else{
    ++              rc = sessionAppendUpdate(&buf, bPatchset, pSel, p, abPK);
    ++            }
    ++          }else if( p->op!=SQLITE_INSERT ){
    ++            rc = sessionAppendDelete(&buf, bPatchset, p, nCol, abPK);
    ++          }
    ++          if( rc==SQLITE_OK ){
    ++            rc = sqlite3_reset(pSel);
    ++          }
    ++
    ++          /* If the buffer is now larger than SESSIONS_STRM_CHUNK_SIZE, pass
    ++          ** its contents to the xOutput() callback. */
    ++          if( xOutput 
    ++           && rc==SQLITE_OK 
    ++           && buf.nBuf>nNoop 
    ++           && buf.nBuf>SESSIONS_STRM_CHUNK_SIZE 
    ++          ){
    ++            rc = xOutput(pOut, (void*)buf.aBuf, buf.nBuf);
    ++            nNoop = -1;
    ++            buf.nBuf = 0;
    ++          }
    ++
    ++        }
    ++      }
    ++
    ++      sqlite3_finalize(pSel);
    ++      if( buf.nBuf==nNoop ){
    ++        buf.nBuf = nRewind;
    ++      }
    ++      sqlite3_free((char*)azCol);  /* cast works around VC++ bug */
    ++    }
    ++  }
    ++
    ++  if( rc==SQLITE_OK ){
    ++    if( xOutput==0 ){
    ++      *pnChangeset = buf.nBuf;
    ++      *ppChangeset = buf.aBuf;
    ++      buf.aBuf = 0;
    ++    }else if( buf.nBuf>0 ){
    ++      rc = xOutput(pOut, (void*)buf.aBuf, buf.nBuf);
    ++    }
    ++  }
    ++
    ++  sqlite3_free(buf.aBuf);
    ++  sqlite3_exec(db, "RELEASE changeset", 0, 0, 0);
    ++  sqlite3_mutex_leave(sqlite3_db_mutex(db));
    ++  return rc;
    ++}
    ++
    ++/*
    ++** Obtain a changeset object containing all changes recorded by the 
    ++** session object passed as the first argument.
    ++**
    ++** It is the responsibility of the caller to eventually free the buffer 
    ++** using sqlite3_free().
    ++*/
    ++SQLITE_API int sqlite3session_changeset(
    ++  sqlite3_session *pSession,      /* Session object */
    ++  int *pnChangeset,               /* OUT: Size of buffer at *ppChangeset */
    ++  void **ppChangeset              /* OUT: Buffer containing changeset */
    ++){
    ++  return sessionGenerateChangeset(pSession, 0, 0, 0, pnChangeset, ppChangeset);
    ++}
    ++
    ++/*
    ++** Streaming version of sqlite3session_changeset().
    ++*/
    ++SQLITE_API int sqlite3session_changeset_strm(
    ++  sqlite3_session *pSession,
    ++  int (*xOutput)(void *pOut, const void *pData, int nData),
    ++  void *pOut
    ++){
    ++  return sessionGenerateChangeset(pSession, 0, xOutput, pOut, 0, 0);
    ++}
    ++
    ++/*
    ++** Streaming version of sqlite3session_patchset().
    ++*/
    ++SQLITE_API int sqlite3session_patchset_strm(
    ++  sqlite3_session *pSession,
    ++  int (*xOutput)(void *pOut, const void *pData, int nData),
    ++  void *pOut
    ++){
    ++  return sessionGenerateChangeset(pSession, 1, xOutput, pOut, 0, 0);
    ++}
    ++
    ++/*
    ++** Obtain a patchset object containing all changes recorded by the 
    ++** session object passed as the first argument.
    ++**
    ++** It is the responsibility of the caller to eventually free the buffer 
    ++** using sqlite3_free().
    ++*/
    ++SQLITE_API int sqlite3session_patchset(
    ++  sqlite3_session *pSession,      /* Session object */
    ++  int *pnPatchset,                /* OUT: Size of buffer at *ppChangeset */
    ++  void **ppPatchset               /* OUT: Buffer containing changeset */
    ++){
    ++  return sessionGenerateChangeset(pSession, 1, 0, 0, pnPatchset, ppPatchset);
    ++}
    ++
    ++/*
    ++** Enable or disable the session object passed as the first argument.
    ++*/
    ++SQLITE_API int sqlite3session_enable(sqlite3_session *pSession, int bEnable){
    ++  int ret;
    ++  sqlite3_mutex_enter(sqlite3_db_mutex(pSession->db));
    ++  if( bEnable>=0 ){
    ++    pSession->bEnable = bEnable;
    ++  }
    ++  ret = pSession->bEnable;
    ++  sqlite3_mutex_leave(sqlite3_db_mutex(pSession->db));
    ++  return ret;
    ++}
    ++
    ++/*
    ++** Enable or disable the session object passed as the first argument.
    ++*/
    ++SQLITE_API int sqlite3session_indirect(sqlite3_session *pSession, int bIndirect){
    ++  int ret;
    ++  sqlite3_mutex_enter(sqlite3_db_mutex(pSession->db));
    ++  if( bIndirect>=0 ){
    ++    pSession->bIndirect = bIndirect;
    ++  }
    ++  ret = pSession->bIndirect;
    ++  sqlite3_mutex_leave(sqlite3_db_mutex(pSession->db));
    ++  return ret;
    ++}
    ++
    ++/*
    ++** Return true if there have been no changes to monitored tables recorded
    ++** by the session object passed as the only argument.
    ++*/
    ++SQLITE_API int sqlite3session_isempty(sqlite3_session *pSession){
    ++  int ret = 0;
    ++  SessionTable *pTab;
    ++
    ++  sqlite3_mutex_enter(sqlite3_db_mutex(pSession->db));
    ++  for(pTab=pSession->pTable; pTab && ret==0; pTab=pTab->pNext){
    ++    ret = (pTab->nEntry>0);
    ++  }
    ++  sqlite3_mutex_leave(sqlite3_db_mutex(pSession->db));
    ++
    ++  return (ret==0);
    ++}
    ++
    ++/*
    ++** Do the work for either sqlite3changeset_start() or start_strm().
    ++*/
    ++static int sessionChangesetStart(
    ++  sqlite3_changeset_iter **pp,    /* OUT: Changeset iterator handle */
    ++  int (*xInput)(void *pIn, void *pData, int *pnData),
    ++  void *pIn,
    ++  int nChangeset,                 /* Size of buffer pChangeset in bytes */
    ++  void *pChangeset                /* Pointer to buffer containing changeset */
    ++){
    ++  sqlite3_changeset_iter *pRet;   /* Iterator to return */
    ++  int nByte;                      /* Number of bytes to allocate for iterator */
    ++
    ++  assert( xInput==0 || (pChangeset==0 && nChangeset==0) );
    ++
    ++  /* Zero the output variable in case an error occurs. */
    ++  *pp = 0;
    ++
    ++  /* Allocate and initialize the iterator structure. */
    ++  nByte = sizeof(sqlite3_changeset_iter);
    ++  pRet = (sqlite3_changeset_iter *)sqlite3_malloc(nByte);
    ++  if( !pRet ) return SQLITE_NOMEM;
    ++  memset(pRet, 0, sizeof(sqlite3_changeset_iter));
    ++  pRet->in.aData = (u8 *)pChangeset;
    ++  pRet->in.nData = nChangeset;
    ++  pRet->in.xInput = xInput;
    ++  pRet->in.pIn = pIn;
    ++  pRet->in.bEof = (xInput ? 0 : 1);
    ++
    ++  /* Populate the output variable and return success. */
    ++  *pp = pRet;
    ++  return SQLITE_OK;
    ++}
    ++
    ++/*
    ++** Create an iterator used to iterate through the contents of a changeset.
    ++*/
    ++SQLITE_API int sqlite3changeset_start(
    ++  sqlite3_changeset_iter **pp,    /* OUT: Changeset iterator handle */
    ++  int nChangeset,                 /* Size of buffer pChangeset in bytes */
    ++  void *pChangeset                /* Pointer to buffer containing changeset */
    ++){
    ++  return sessionChangesetStart(pp, 0, 0, nChangeset, pChangeset);
    ++}
    ++
    ++/*
    ++** Streaming version of sqlite3changeset_start().
    ++*/
    ++SQLITE_API int sqlite3changeset_start_strm(
    ++  sqlite3_changeset_iter **pp,    /* OUT: Changeset iterator handle */
    ++  int (*xInput)(void *pIn, void *pData, int *pnData),
    ++  void *pIn
    ++){
    ++  return sessionChangesetStart(pp, xInput, pIn, 0, 0);
    ++}
    ++
    ++/*
    ++** If the SessionInput object passed as the only argument is a streaming
    ++** object and the buffer is full, discard some data to free up space.
    ++*/
    ++static void sessionDiscardData(SessionInput *pIn){
    ++  if( pIn->bEof && pIn->xInput && pIn->iNext>=SESSIONS_STRM_CHUNK_SIZE ){
    ++    int nMove = pIn->buf.nBuf - pIn->iNext;
    ++    assert( nMove>=0 );
    ++    if( nMove>0 ){
    ++      memmove(pIn->buf.aBuf, &pIn->buf.aBuf[pIn->iNext], nMove);
    ++    }
    ++    pIn->buf.nBuf -= pIn->iNext;
    ++    pIn->iNext = 0;
    ++    pIn->nData = pIn->buf.nBuf;
    ++  }
    ++}
    ++
    ++/*
    ++** Ensure that there are at least nByte bytes available in the buffer. Or,
    ++** if there are not nByte bytes remaining in the input, that all available
    ++** data is in the buffer.
    ++**
    ++** Return an SQLite error code if an error occurs, or SQLITE_OK otherwise.
    ++*/
    ++static int sessionInputBuffer(SessionInput *pIn, int nByte){
    ++  int rc = SQLITE_OK;
    ++  if( pIn->xInput ){
    ++    while( !pIn->bEof && (pIn->iNext+nByte)>=pIn->nData && rc==SQLITE_OK ){
    ++      int nNew = SESSIONS_STRM_CHUNK_SIZE;
    ++
    ++      if( pIn->bNoDiscard==0 ) sessionDiscardData(pIn);
    ++      if( SQLITE_OK==sessionBufferGrow(&pIn->buf, nNew, &rc) ){
    ++        rc = pIn->xInput(pIn->pIn, &pIn->buf.aBuf[pIn->buf.nBuf], &nNew);
    ++        if( nNew==0 ){
    ++          pIn->bEof = 1;
    ++        }else{
    ++          pIn->buf.nBuf += nNew;
    ++        }
    ++      }
    ++
    ++      pIn->aData = pIn->buf.aBuf;
    ++      pIn->nData = pIn->buf.nBuf;
    ++    }
    ++  }
    ++  return rc;
    ++}
    ++
    ++/*
    ++** When this function is called, *ppRec points to the start of a record
    ++** that contains nCol values. This function advances the pointer *ppRec
    ++** until it points to the byte immediately following that record.
    ++*/
    ++static void sessionSkipRecord(
    ++  u8 **ppRec,                     /* IN/OUT: Record pointer */
    ++  int nCol                        /* Number of values in record */
    ++){
    ++  u8 *aRec = *ppRec;
    ++  int i;
    ++  for(i=0; i<nCol; i++){
    ++    int eType = *aRec++;
    ++    if( eType==SQLITE_TEXT || eType==SQLITE_BLOB ){
    ++      int nByte;
    ++      aRec += sessionVarintGet((u8*)aRec, &nByte);
    ++      aRec += nByte;
    ++    }else if( eType==SQLITE_INTEGER || eType==SQLITE_FLOAT ){
    ++      aRec += 8;
    ++    }
    ++  }
    ++
    ++  *ppRec = aRec;
    ++}
    ++
    ++/*
    ++** This function sets the value of the sqlite3_value object passed as the
    ++** first argument to a copy of the string or blob held in the aData[] 
    ++** buffer. SQLITE_OK is returned if successful, or SQLITE_NOMEM if an OOM
    ++** error occurs.
    ++*/
    ++static int sessionValueSetStr(
    ++  sqlite3_value *pVal,            /* Set the value of this object */
    ++  u8 *aData,                      /* Buffer containing string or blob data */
    ++  int nData,                      /* Size of buffer aData[] in bytes */
    ++  u8 enc                          /* String encoding (0 for blobs) */
    ++){
    ++  /* In theory this code could just pass SQLITE_TRANSIENT as the final
    ++  ** argument to sqlite3ValueSetStr() and have the copy created 
    ++  ** automatically. But doing so makes it difficult to detect any OOM
    ++  ** error. Hence the code to create the copy externally. */
    ++  u8 *aCopy = sqlite3_malloc(nData+1);
    ++  if( aCopy==0 ) return SQLITE_NOMEM;
    ++  memcpy(aCopy, aData, nData);
    ++  sqlite3ValueSetStr(pVal, nData, (char*)aCopy, enc, sqlite3_free);
    ++  return SQLITE_OK;
    ++}
    ++
    ++/*
    ++** Deserialize a single record from a buffer in memory. See "RECORD FORMAT"
    ++** for details.
    ++**
    ++** When this function is called, *paChange points to the start of the record
    ++** to deserialize. Assuming no error occurs, *paChange is set to point to
    ++** one byte after the end of the same record before this function returns.
    ++** If the argument abPK is NULL, then the record contains nCol values. Or,
    ++** if abPK is other than NULL, then the record contains only the PK fields
    ++** (in other words, it is a patchset DELETE record).
    ++**
    ++** If successful, each element of the apOut[] array (allocated by the caller)
    ++** is set to point to an sqlite3_value object containing the value read
    ++** from the corresponding position in the record. If that value is not
    ++** included in the record (i.e. because the record is part of an UPDATE change
    ++** and the field was not modified), the corresponding element of apOut[] is
    ++** set to NULL.
    ++**
    ++** It is the responsibility of the caller to free all sqlite_value structures
    ++** using sqlite3_free().
    ++**
    ++** If an error occurs, an SQLite error code (e.g. SQLITE_NOMEM) is returned.
    ++** The apOut[] array may have been partially populated in this case.
    ++*/
    ++static int sessionReadRecord(
    ++  SessionInput *pIn,              /* Input data */
    ++  int nCol,                       /* Number of values in record */
    ++  u8 *abPK,                       /* Array of primary key flags, or NULL */
    ++  sqlite3_value **apOut           /* Write values to this array */
    ++){
    ++  int i;                          /* Used to iterate through columns */
    ++  int rc = SQLITE_OK;
    ++
    ++  for(i=0; i<nCol && rc==SQLITE_OK; i++){
    ++    int eType = 0;                /* Type of value (SQLITE_NULL, TEXT etc.) */
    ++    if( abPK && abPK[i]==0 ) continue;
    ++    rc = sessionInputBuffer(pIn, 9);
    ++    if( rc==SQLITE_OK ){
    ++      eType = pIn->aData[pIn->iNext++];
    ++    }
    ++
    ++    assert( apOut[i]==0 );
    ++    if( eType ){
    ++      apOut[i] = sqlite3ValueNew(0);
    ++      if( !apOut[i] ) rc = SQLITE_NOMEM;
    ++    }
    ++
    ++    if( rc==SQLITE_OK ){
    ++      u8 *aVal = &pIn->aData[pIn->iNext];
    ++      if( eType==SQLITE_TEXT || eType==SQLITE_BLOB ){
    ++        int nByte;
    ++        pIn->iNext += sessionVarintGet(aVal, &nByte);
    ++        rc = sessionInputBuffer(pIn, nByte);
    ++        if( rc==SQLITE_OK ){
    ++          u8 enc = (eType==SQLITE_TEXT ? SQLITE_UTF8 : 0);
    ++          rc = sessionValueSetStr(apOut[i],&pIn->aData[pIn->iNext],nByte,enc);
    ++        }
    ++        pIn->iNext += nByte;
    ++      }
    ++      if( eType==SQLITE_INTEGER || eType==SQLITE_FLOAT ){
    ++        sqlite3_int64 v = sessionGetI64(aVal);
    ++        if( eType==SQLITE_INTEGER ){
    ++          sqlite3VdbeMemSetInt64(apOut[i], v);
    ++        }else{
    ++          double d;
    ++          memcpy(&d, &v, 8);
    ++          sqlite3VdbeMemSetDouble(apOut[i], d);
    ++        }
    ++        pIn->iNext += 8;
    ++      }
    ++    }
    ++  }
    ++
    ++  return rc;
    ++}
    ++
    ++/*
    ++** The input pointer currently points to the second byte of a table-header.
    ++** Specifically, to the following:
    ++**
    ++**   + number of columns in table (varint)
    ++**   + array of PK flags (1 byte per column),
    ++**   + table name (nul terminated).
    ++**
    ++** This function ensures that all of the above is present in the input 
    ++** buffer (i.e. that it can be accessed without any calls to xInput()).
    ++** If successful, SQLITE_OK is returned. Otherwise, an SQLite error code.
    ++** The input pointer is not moved.
    ++*/
    ++static int sessionChangesetBufferTblhdr(SessionInput *pIn, int *pnByte){
    ++  int rc = SQLITE_OK;
    ++  int nCol = 0;
    ++  int nRead = 0;
    ++
    ++  rc = sessionInputBuffer(pIn, 9);
    ++  if( rc==SQLITE_OK ){
    ++    nRead += sessionVarintGet(&pIn->aData[pIn->iNext + nRead], &nCol);
    ++    rc = sessionInputBuffer(pIn, nRead+nCol+100);
    ++    nRead += nCol;
    ++  }
    ++
    ++  while( rc==SQLITE_OK ){
    ++    while( (pIn->iNext + nRead)<pIn->nData && pIn->aData[pIn->iNext + nRead] ){
    ++      nRead++;
    ++    }
    ++    if( (pIn->iNext + nRead)<pIn->nData ) break;
    ++    rc = sessionInputBuffer(pIn, nRead + 100);
    ++  }
    ++  *pnByte = nRead+1;
    ++  return rc;
    ++}
    ++
    ++/*
    ++** The input pointer currently points to the first byte of the first field
    ++** of a record consisting of nCol columns. This function ensures the entire
    ++** record is buffered. It does not move the input pointer.
    ++**
    ++** If successful, SQLITE_OK is returned and *pnByte is set to the size of
    ++** the record in bytes. Otherwise, an SQLite error code is returned. The
    ++** final value of *pnByte is undefined in this case.
    ++*/
    ++static int sessionChangesetBufferRecord(
    ++  SessionInput *pIn,              /* Input data */
    ++  int nCol,                       /* Number of columns in record */
    ++  int *pnByte                     /* OUT: Size of record in bytes */
    ++){
    ++  int rc = SQLITE_OK;
    ++  int nByte = 0;
    ++  int i;
    ++  for(i=0; rc==SQLITE_OK && i<nCol; i++){
    ++    int eType;
    ++    rc = sessionInputBuffer(pIn, nByte + 10);
    ++    if( rc==SQLITE_OK ){
    ++      eType = pIn->aData[pIn->iNext + nByte++];
    ++      if( eType==SQLITE_TEXT || eType==SQLITE_BLOB ){
    ++        int n;
    ++        nByte += sessionVarintGet(&pIn->aData[pIn->iNext+nByte], &n);
    ++        nByte += n;
    ++        rc = sessionInputBuffer(pIn, nByte);
    ++      }else if( eType==SQLITE_INTEGER || eType==SQLITE_FLOAT ){
    ++        nByte += 8;
    ++      }
    ++    }
    ++  }
    ++  *pnByte = nByte;
    ++  return rc;
    ++}
    ++
    ++/*
    ++** The input pointer currently points to the second byte of a table-header.
    ++** Specifically, to the following:
    ++**
    ++**   + number of columns in table (varint)
    ++**   + array of PK flags (1 byte per column),
    ++**   + table name (nul terminated).
    ++**
    ++** This function decodes the table-header and populates the p->nCol, 
    ++** p->zTab and p->abPK[] variables accordingly. The p->apValue[] array is 
    ++** also allocated or resized according to the new value of p->nCol. The
    ++** input pointer is left pointing to the byte following the table header.
    ++**
    ++** If successful, SQLITE_OK is returned. Otherwise, an SQLite error code
    ++** is returned and the final values of the various fields enumerated above
    ++** are undefined.
    ++*/
    ++static int sessionChangesetReadTblhdr(sqlite3_changeset_iter *p){
    ++  int rc;
    ++  int nCopy;
    ++  assert( p->rc==SQLITE_OK );
    ++
    ++  rc = sessionChangesetBufferTblhdr(&p->in, &nCopy);
    ++  if( rc==SQLITE_OK ){
    ++    int nByte;
    ++    int nVarint;
    ++    nVarint = sessionVarintGet(&p->in.aData[p->in.iNext], &p->nCol);
    ++    nCopy -= nVarint;
    ++    p->in.iNext += nVarint;
    ++    nByte = p->nCol * sizeof(sqlite3_value*) * 2 + nCopy;
    ++    p->tblhdr.nBuf = 0;
    ++    sessionBufferGrow(&p->tblhdr, nByte, &rc);
    ++  }
    ++
    ++  if( rc==SQLITE_OK ){
    ++    int iPK = sizeof(sqlite3_value*)*p->nCol*2;
    ++    memset(p->tblhdr.aBuf, 0, iPK);
    ++    memcpy(&p->tblhdr.aBuf[iPK], &p->in.aData[p->in.iNext], nCopy);
    ++    p->in.iNext += nCopy;
    ++  }
    ++
    ++  p->apValue = (sqlite3_value**)p->tblhdr.aBuf;
    ++  p->abPK = (u8*)&p->apValue[p->nCol*2];
    ++  p->zTab = (char*)&p->abPK[p->nCol];
    ++  return (p->rc = rc);
    ++}
    ++
    ++/*
    ++** Advance the changeset iterator to the next change.
    ++**
    ++** If both paRec and pnRec are NULL, then this function works like the public
    ++** API sqlite3changeset_next(). If SQLITE_ROW is returned, then the
    ++** sqlite3changeset_new() and old() APIs may be used to query for values.
    ++**
    ++** Otherwise, if paRec and pnRec are not NULL, then a pointer to the change
    ++** record is written to *paRec before returning and the number of bytes in
    ++** the record to *pnRec.
    ++**
    ++** Either way, this function returns SQLITE_ROW if the iterator is 
    ++** successfully advanced to the next change in the changeset, an SQLite 
    ++** error code if an error occurs, or SQLITE_DONE if there are no further 
    ++** changes in the changeset.
    ++*/
    ++static int sessionChangesetNext(
    ++  sqlite3_changeset_iter *p,      /* Changeset iterator */
    ++  u8 **paRec,                     /* If non-NULL, store record pointer here */
    ++  int *pnRec                      /* If non-NULL, store size of record here */
    ++){
    ++  int i;
    ++  u8 op;
    ++
    ++  assert( (paRec==0 && pnRec==0) || (paRec && pnRec) );
    ++
    ++  /* If the iterator is in the error-state, return immediately. */
    ++  if( p->rc!=SQLITE_OK ) return p->rc;
    ++
    ++  /* Free the current contents of p->apValue[], if any. */
    ++  if( p->apValue ){
    ++    for(i=0; i<p->nCol*2; i++){
    ++      sqlite3ValueFree(p->apValue[i]);
    ++    }
    ++    memset(p->apValue, 0, sizeof(sqlite3_value*)*p->nCol*2);
    ++  }
    ++
    ++  /* Make sure the buffer contains at least 10 bytes of input data, or all
    ++  ** remaining data if there are less than 10 bytes available. This is
    ++  ** sufficient either for the 'T' or 'P' byte and the varint that follows
    ++  ** it, or for the two single byte values otherwise. */
    ++  p->rc = sessionInputBuffer(&p->in, 2);
    ++  if( p->rc!=SQLITE_OK ) return p->rc;
    ++
    ++  /* If the iterator is already at the end of the changeset, return DONE. */
    ++  if( p->in.iNext>=p->in.nData ){
    ++    return SQLITE_DONE;
    ++  }
    ++
    ++  sessionDiscardData(&p->in);
    ++  p->in.iCurrent = p->in.iNext;
    ++
    ++  op = p->in.aData[p->in.iNext++];
    ++  while( op=='T' || op=='P' ){
    ++    p->bPatchset = (op=='P');
    ++    if( sessionChangesetReadTblhdr(p) ) return p->rc;
    ++    if( (p->rc = sessionInputBuffer(&p->in, 2)) ) return p->rc;
    ++    p->in.iCurrent = p->in.iNext;
    ++    if( p->in.iNext>=p->in.nData ) return SQLITE_DONE;
    ++    op = p->in.aData[p->in.iNext++];
    ++  }
    ++
    ++  p->op = op;
    ++  p->bIndirect = p->in.aData[p->in.iNext++];
    ++  if( p->op!=SQLITE_UPDATE && p->op!=SQLITE_DELETE && p->op!=SQLITE_INSERT ){
    ++    return (p->rc = SQLITE_CORRUPT_BKPT);
    ++  }
    ++
    ++  if( paRec ){ 
    ++    int nVal;                     /* Number of values to buffer */
    ++    if( p->bPatchset==0 && op==SQLITE_UPDATE ){
    ++      nVal = p->nCol * 2;
    ++    }else if( p->bPatchset && op==SQLITE_DELETE ){
    ++      nVal = 0;
    ++      for(i=0; i<p->nCol; i++) if( p->abPK[i] ) nVal++;
    ++    }else{
    ++      nVal = p->nCol;
    ++    }
    ++    p->rc = sessionChangesetBufferRecord(&p->in, nVal, pnRec);
    ++    if( p->rc!=SQLITE_OK ) return p->rc;
    ++    *paRec = &p->in.aData[p->in.iNext];
    ++    p->in.iNext += *pnRec;
    ++  }else{
    ++
    ++    /* If this is an UPDATE or DELETE, read the old.* record. */
    ++    if( p->op!=SQLITE_INSERT && (p->bPatchset==0 || p->op==SQLITE_DELETE) ){
    ++      u8 *abPK = p->bPatchset ? p->abPK : 0;
    ++      p->rc = sessionReadRecord(&p->in, p->nCol, abPK, p->apValue);
    ++      if( p->rc!=SQLITE_OK ) return p->rc;
    ++    }
    ++
    ++    /* If this is an INSERT or UPDATE, read the new.* record. */
    ++    if( p->op!=SQLITE_DELETE ){
    ++      p->rc = sessionReadRecord(&p->in, p->nCol, 0, &p->apValue[p->nCol]);
    ++      if( p->rc!=SQLITE_OK ) return p->rc;
    ++    }
    ++
    ++    if( p->bPatchset && p->op==SQLITE_UPDATE ){
    ++      /* If this is an UPDATE that is part of a patchset, then all PK and
    ++      ** modified fields are present in the new.* record. The old.* record
    ++      ** is currently completely empty. This block shifts the PK fields from
    ++      ** new.* to old.*, to accommodate the code that reads these arrays.  */
    ++      for(i=0; i<p->nCol; i++){
    ++        assert( p->apValue[i]==0 );
    ++        assert( p->abPK[i]==0 || p->apValue[i+p->nCol] );
    ++        if( p->abPK[i] ){
    ++          p->apValue[i] = p->apValue[i+p->nCol];
    ++          p->apValue[i+p->nCol] = 0;
    ++        }
    ++      }
    ++    }
    ++  }
    ++
    ++  return SQLITE_ROW;
    ++}
    ++
    ++/*
    ++** Advance an iterator created by sqlite3changeset_start() to the next
    ++** change in the changeset. This function may return SQLITE_ROW, SQLITE_DONE
    ++** or SQLITE_CORRUPT.
    ++**
    ++** This function may not be called on iterators passed to a conflict handler
    ++** callback by changeset_apply().
    ++*/
    ++SQLITE_API int sqlite3changeset_next(sqlite3_changeset_iter *p){
    ++  return sessionChangesetNext(p, 0, 0);
    ++}
    ++
    ++/*
    ++** The following function extracts information on the current change
    ++** from a changeset iterator. It may only be called after changeset_next()
    ++** has returned SQLITE_ROW.
    ++*/
    ++SQLITE_API int sqlite3changeset_op(
    ++  sqlite3_changeset_iter *pIter,  /* Iterator handle */
    ++  const char **pzTab,             /* OUT: Pointer to table name */
    ++  int *pnCol,                     /* OUT: Number of columns in table */
    ++  int *pOp,                       /* OUT: SQLITE_INSERT, DELETE or UPDATE */
    ++  int *pbIndirect                 /* OUT: True if change is indirect */
    ++){
    ++  *pOp = pIter->op;
    ++  *pnCol = pIter->nCol;
    ++  *pzTab = pIter->zTab;
    ++  if( pbIndirect ) *pbIndirect = pIter->bIndirect;
    ++  return SQLITE_OK;
    ++}
    ++
    ++/*
    ++** Return information regarding the PRIMARY KEY and number of columns in
    ++** the database table affected by the change that pIter currently points
    ++** to. This function may only be called after changeset_next() returns
    ++** SQLITE_ROW.
    ++*/
    ++SQLITE_API int sqlite3changeset_pk(
    ++  sqlite3_changeset_iter *pIter,  /* Iterator object */
    ++  unsigned char **pabPK,          /* OUT: Array of boolean - true for PK cols */
    ++  int *pnCol                      /* OUT: Number of entries in output array */
    ++){
    ++  *pabPK = pIter->abPK;
    ++  if( pnCol ) *pnCol = pIter->nCol;
    ++  return SQLITE_OK;
    ++}
    ++
    ++/*
    ++** This function may only be called while the iterator is pointing to an
    ++** SQLITE_UPDATE or SQLITE_DELETE change (see sqlite3changeset_op()).
    ++** Otherwise, SQLITE_MISUSE is returned.
    ++**
    ++** It sets *ppValue to point to an sqlite3_value structure containing the
    ++** iVal'th value in the old.* record. Or, if that particular value is not
    ++** included in the record (because the change is an UPDATE and the field
    ++** was not modified and is not a PK column), set *ppValue to NULL.
    ++**
    ++** If value iVal is out-of-range, SQLITE_RANGE is returned and *ppValue is
    ++** not modified. Otherwise, SQLITE_OK.
    ++*/
    ++SQLITE_API int sqlite3changeset_old(
    ++  sqlite3_changeset_iter *pIter,  /* Changeset iterator */
    ++  int iVal,                       /* Index of old.* value to retrieve */
    ++  sqlite3_value **ppValue         /* OUT: Old value (or NULL pointer) */
    ++){
    ++  if( pIter->op!=SQLITE_UPDATE && pIter->op!=SQLITE_DELETE ){
    ++    return SQLITE_MISUSE;
    ++  }
    ++  if( iVal<0 || iVal>=pIter->nCol ){
    ++    return SQLITE_RANGE;
    ++  }
    ++  *ppValue = pIter->apValue[iVal];
    ++  return SQLITE_OK;
    ++}
    ++
    ++/*
    ++** This function may only be called while the iterator is pointing to an
    ++** SQLITE_UPDATE or SQLITE_INSERT change (see sqlite3changeset_op()).
    ++** Otherwise, SQLITE_MISUSE is returned.
    ++**
    ++** It sets *ppValue to point to an sqlite3_value structure containing the
    ++** iVal'th value in the new.* record. Or, if that particular value is not
    ++** included in the record (because the change is an UPDATE and the field
    ++** was not modified), set *ppValue to NULL.
    ++**
    ++** If value iVal is out-of-range, SQLITE_RANGE is returned and *ppValue is
    ++** not modified. Otherwise, SQLITE_OK.
    ++*/
    ++SQLITE_API int sqlite3changeset_new(
    ++  sqlite3_changeset_iter *pIter,  /* Changeset iterator */
    ++  int iVal,                       /* Index of new.* value to retrieve */
    ++  sqlite3_value **ppValue         /* OUT: New value (or NULL pointer) */
    ++){
    ++  if( pIter->op!=SQLITE_UPDATE && pIter->op!=SQLITE_INSERT ){
    ++    return SQLITE_MISUSE;
    ++  }
    ++  if( iVal<0 || iVal>=pIter->nCol ){
    ++    return SQLITE_RANGE;
    ++  }
    ++  *ppValue = pIter->apValue[pIter->nCol+iVal];
    ++  return SQLITE_OK;
    ++}
    ++
    ++/*
    ++** The following two macros are used internally. They are similar to the
    ++** sqlite3changeset_new() and sqlite3changeset_old() functions, except that
    ++** they omit all error checking and return a pointer to the requested value.
    ++*/
    ++#define sessionChangesetNew(pIter, iVal) (pIter)->apValue[(pIter)->nCol+(iVal)]
    ++#define sessionChangesetOld(pIter, iVal) (pIter)->apValue[(iVal)]
    ++
    ++/*
    ++** This function may only be called with a changeset iterator that has been
    ++** passed to an SQLITE_CHANGESET_DATA or SQLITE_CHANGESET_CONFLICT 
    ++** conflict-handler function. Otherwise, SQLITE_MISUSE is returned.
    ++**
    ++** If successful, *ppValue is set to point to an sqlite3_value structure
    ++** containing the iVal'th value of the conflicting record.
    ++**
    ++** If value iVal is out-of-range or some other error occurs, an SQLite error
    ++** code is returned. Otherwise, SQLITE_OK.
    ++*/
    ++SQLITE_API int sqlite3changeset_conflict(
    ++  sqlite3_changeset_iter *pIter,  /* Changeset iterator */
    ++  int iVal,                       /* Index of conflict record value to fetch */
    ++  sqlite3_value **ppValue         /* OUT: Value from conflicting row */
    ++){
    ++  if( !pIter->pConflict ){
    ++    return SQLITE_MISUSE;
    ++  }
    ++  if( iVal<0 || iVal>=pIter->nCol ){
    ++    return SQLITE_RANGE;
    ++  }
    ++  *ppValue = sqlite3_column_value(pIter->pConflict, iVal);
    ++  return SQLITE_OK;
    ++}
    ++
    ++/*
    ++** This function may only be called with an iterator passed to an
    ++** SQLITE_CHANGESET_FOREIGN_KEY conflict handler callback. In this case
    ++** it sets the output variable to the total number of known foreign key
    ++** violations in the destination database and returns SQLITE_OK.
    ++**
    ++** In all other cases this function returns SQLITE_MISUSE.
    ++*/
    ++SQLITE_API int sqlite3changeset_fk_conflicts(
    ++  sqlite3_changeset_iter *pIter,  /* Changeset iterator */
    ++  int *pnOut                      /* OUT: Number of FK violations */
    ++){
    ++  if( pIter->pConflict || pIter->apValue ){
    ++    return SQLITE_MISUSE;
    ++  }
    ++  *pnOut = pIter->nCol;
    ++  return SQLITE_OK;
    ++}
    ++
    ++
    ++/*
    ++** Finalize an iterator allocated with sqlite3changeset_start().
    ++**
    ++** This function may not be called on iterators passed to a conflict handler
    ++** callback by changeset_apply().
    ++*/
    ++SQLITE_API int sqlite3changeset_finalize(sqlite3_changeset_iter *p){
    ++  int rc = SQLITE_OK;
    ++  if( p ){
    ++    int i;                        /* Used to iterate through p->apValue[] */
    ++    rc = p->rc;
    ++    if( p->apValue ){
    ++      for(i=0; i<p->nCol*2; i++) sqlite3ValueFree(p->apValue[i]);
    ++    }
    ++    sqlite3_free(p->tblhdr.aBuf);
    ++    sqlite3_free(p->in.buf.aBuf);
    ++    sqlite3_free(p);
    ++  }
    ++  return rc;
    ++}
    ++
    ++static int sessionChangesetInvert(
    ++  SessionInput *pInput,           /* Input changeset */
    ++  int (*xOutput)(void *pOut, const void *pData, int nData),
    ++  void *pOut,
    ++  int *pnInverted,                /* OUT: Number of bytes in output changeset */
    ++  void **ppInverted               /* OUT: Inverse of pChangeset */
    ++){
    ++  int rc = SQLITE_OK;             /* Return value */
    ++  SessionBuffer sOut;             /* Output buffer */
    ++  int nCol = 0;                   /* Number of cols in current table */
    ++  u8 *abPK = 0;                   /* PK array for current table */
    ++  sqlite3_value **apVal = 0;      /* Space for values for UPDATE inversion */
    ++  SessionBuffer sPK = {0, 0, 0};  /* PK array for current table */
    ++
    ++  /* Initialize the output buffer */
    ++  memset(&sOut, 0, sizeof(SessionBuffer));
    ++
    ++  /* Zero the output variables in case an error occurs. */
    ++  if( ppInverted ){
    ++    *ppInverted = 0;
    ++    *pnInverted = 0;
    ++  }
    ++
    ++  while( 1 ){
    ++    u8 eType;
    ++
    ++    /* Test for EOF. */
    ++    if( (rc = sessionInputBuffer(pInput, 2)) ) goto finished_invert;
    ++    if( pInput->iNext>=pInput->nData ) break;
    ++    eType = pInput->aData[pInput->iNext];
    ++
    ++    switch( eType ){
    ++      case 'T': {
    ++        /* A 'table' record consists of:
    ++        **
    ++        **   * A constant 'T' character,
    ++        **   * Number of columns in said table (a varint),
    ++        **   * An array of nCol bytes (sPK),
    ++        **   * A nul-terminated table name.
    ++        */
    ++        int nByte;
    ++        int nVar;
    ++        pInput->iNext++;
    ++        if( (rc = sessionChangesetBufferTblhdr(pInput, &nByte)) ){
    ++          goto finished_invert;
    ++        }
    ++        nVar = sessionVarintGet(&pInput->aData[pInput->iNext], &nCol);
    ++        sPK.nBuf = 0;
    ++        sessionAppendBlob(&sPK, &pInput->aData[pInput->iNext+nVar], nCol, &rc);
    ++        sessionAppendByte(&sOut, eType, &rc);
    ++        sessionAppendBlob(&sOut, &pInput->aData[pInput->iNext], nByte, &rc);
    ++        if( rc ) goto finished_invert;
    ++
    ++        pInput->iNext += nByte;
    ++        sqlite3_free(apVal);
    ++        apVal = 0;
    ++        abPK = sPK.aBuf;
    ++        break;
    ++      }
    ++
    ++      case SQLITE_INSERT:
    ++      case SQLITE_DELETE: {
    ++        int nByte;
    ++        int bIndirect = pInput->aData[pInput->iNext+1];
    ++        int eType2 = (eType==SQLITE_DELETE ? SQLITE_INSERT : SQLITE_DELETE);
    ++        pInput->iNext += 2;
    ++        assert( rc==SQLITE_OK );
    ++        rc = sessionChangesetBufferRecord(pInput, nCol, &nByte);
    ++        sessionAppendByte(&sOut, eType2, &rc);
    ++        sessionAppendByte(&sOut, bIndirect, &rc);
    ++        sessionAppendBlob(&sOut, &pInput->aData[pInput->iNext], nByte, &rc);
    ++        pInput->iNext += nByte;
    ++        if( rc ) goto finished_invert;
    ++        break;
    ++      }
    ++
    ++      case SQLITE_UPDATE: {
    ++        int iCol;
    ++
    ++        if( 0==apVal ){
    ++          apVal = (sqlite3_value **)sqlite3_malloc(sizeof(apVal[0])*nCol*2);
    ++          if( 0==apVal ){
    ++            rc = SQLITE_NOMEM;
    ++            goto finished_invert;
    ++          }
    ++          memset(apVal, 0, sizeof(apVal[0])*nCol*2);
    ++        }
    ++
    ++        /* Write the header for the new UPDATE change. Same as the original. */
    ++        sessionAppendByte(&sOut, eType, &rc);
    ++        sessionAppendByte(&sOut, pInput->aData[pInput->iNext+1], &rc);
    ++
    ++        /* Read the old.* and new.* records for the update change. */
    ++        pInput->iNext += 2;
    ++        rc = sessionReadRecord(pInput, nCol, 0, &apVal[0]);
    ++        if( rc==SQLITE_OK ){
    ++          rc = sessionReadRecord(pInput, nCol, 0, &apVal[nCol]);
    ++        }
    ++
    ++        /* Write the new old.* record. Consists of the PK columns from the
    ++        ** original old.* record, and the other values from the original
    ++        ** new.* record. */
    ++        for(iCol=0; iCol<nCol; iCol++){
    ++          sqlite3_value *pVal = apVal[iCol + (abPK[iCol] ? 0 : nCol)];
    ++          sessionAppendValue(&sOut, pVal, &rc);
    ++        }
    ++
    ++        /* Write the new new.* record. Consists of a copy of all values
    ++        ** from the original old.* record, except for the PK columns, which
    ++        ** are set to "undefined". */
    ++        for(iCol=0; iCol<nCol; iCol++){
    ++          sqlite3_value *pVal = (abPK[iCol] ? 0 : apVal[iCol]);
    ++          sessionAppendValue(&sOut, pVal, &rc);
    ++        }
    ++
    ++        for(iCol=0; iCol<nCol*2; iCol++){
    ++          sqlite3ValueFree(apVal[iCol]);
    ++        }
    ++        memset(apVal, 0, sizeof(apVal[0])*nCol*2);
    ++        if( rc!=SQLITE_OK ){
    ++          goto finished_invert;
    ++        }
    ++
    ++        break;
    ++      }
    ++
    ++      default:
    ++        rc = SQLITE_CORRUPT_BKPT;
    ++        goto finished_invert;
    ++    }
    ++
    ++    assert( rc==SQLITE_OK );
    ++    if( xOutput && sOut.nBuf>=SESSIONS_STRM_CHUNK_SIZE ){
    ++      rc = xOutput(pOut, sOut.aBuf, sOut.nBuf);
    ++      sOut.nBuf = 0;
    ++      if( rc!=SQLITE_OK ) goto finished_invert;
    ++    }
    ++  }
    ++
    ++  assert( rc==SQLITE_OK );
    ++  if( pnInverted ){
    ++    *pnInverted = sOut.nBuf;
    ++    *ppInverted = sOut.aBuf;
    ++    sOut.aBuf = 0;
    ++  }else if( sOut.nBuf>0 ){
    ++    rc = xOutput(pOut, sOut.aBuf, sOut.nBuf);
    ++  }
    ++
    ++ finished_invert:
    ++  sqlite3_free(sOut.aBuf);
    ++  sqlite3_free(apVal);
    ++  sqlite3_free(sPK.aBuf);
    ++  return rc;
    ++}
    ++
    ++
    ++/*
    ++** Invert a changeset object.
    ++*/
    ++SQLITE_API int sqlite3changeset_invert(
    ++  int nChangeset,                 /* Number of bytes in input */
    ++  const void *pChangeset,         /* Input changeset */
    ++  int *pnInverted,                /* OUT: Number of bytes in output changeset */
    ++  void **ppInverted               /* OUT: Inverse of pChangeset */
    ++){
    ++  SessionInput sInput;
    ++
    ++  /* Set up the input stream */
    ++  memset(&sInput, 0, sizeof(SessionInput));
    ++  sInput.nData = nChangeset;
    ++  sInput.aData = (u8*)pChangeset;
    ++
    ++  return sessionChangesetInvert(&sInput, 0, 0, pnInverted, ppInverted);
    ++}
    ++
    ++/*
    ++** Streaming version of sqlite3changeset_invert().
    ++*/
    ++SQLITE_API int sqlite3changeset_invert_strm(
    ++  int (*xInput)(void *pIn, void *pData, int *pnData),
    ++  void *pIn,
    ++  int (*xOutput)(void *pOut, const void *pData, int nData),
    ++  void *pOut
    ++){
    ++  SessionInput sInput;
    ++  int rc;
    ++
    ++  /* Set up the input stream */
    ++  memset(&sInput, 0, sizeof(SessionInput));
    ++  sInput.xInput = xInput;
    ++  sInput.pIn = pIn;
    ++
    ++  rc = sessionChangesetInvert(&sInput, xOutput, pOut, 0, 0);
    ++  sqlite3_free(sInput.buf.aBuf);
    ++  return rc;
    ++}
    ++
    ++typedef struct SessionApplyCtx SessionApplyCtx;
    ++struct SessionApplyCtx {
    ++  sqlite3 *db;
    ++  sqlite3_stmt *pDelete;          /* DELETE statement */
    ++  sqlite3_stmt *pUpdate;          /* UPDATE statement */
    ++  sqlite3_stmt *pInsert;          /* INSERT statement */
    ++  sqlite3_stmt *pSelect;          /* SELECT statement */
    ++  int nCol;                       /* Size of azCol[] and abPK[] arrays */
    ++  const char **azCol;             /* Array of column names */
    ++  u8 *abPK;                       /* Boolean array - true if column is in PK */
    ++  int bStat1;                     /* True if table is sqlite_stat1 */
    ++  int bDeferConstraints;          /* True to defer constraints */
    ++  SessionBuffer constraints;      /* Deferred constraints are stored here */
    ++};
    ++
    ++/*
    ++** Formulate a statement to DELETE a row from database db. Assuming a table
    ++** structure like this:
    ++**
    ++**     CREATE TABLE x(a, b, c, d, PRIMARY KEY(a, c));
    ++**
    ++** The DELETE statement looks like this:
    ++**
    ++**     DELETE FROM x WHERE a = :1 AND c = :3 AND (:5 OR b IS :2 AND d IS :4)
    ++**
    ++** Variable :5 (nCol+1) is a boolean. It should be set to 0 if we require
    ++** matching b and d values, or 1 otherwise. The second case comes up if the
    ++** conflict handler is invoked with NOTFOUND and returns CHANGESET_REPLACE.
    ++**
    ++** If successful, SQLITE_OK is returned and SessionApplyCtx.pDelete is left
    ++** pointing to the prepared version of the SQL statement.
    ++*/
    ++static int sessionDeleteRow(
    ++  sqlite3 *db,                    /* Database handle */
    ++  const char *zTab,               /* Table name */
    ++  SessionApplyCtx *p              /* Session changeset-apply context */
    ++){
    ++  int i;
    ++  const char *zSep = "";
    ++  int rc = SQLITE_OK;
    ++  SessionBuffer buf = {0, 0, 0};
    ++  int nPk = 0;
    ++
    ++  sessionAppendStr(&buf, "DELETE FROM ", &rc);
    ++  sessionAppendIdent(&buf, zTab, &rc);
    ++  sessionAppendStr(&buf, " WHERE ", &rc);
    ++
    ++  for(i=0; i<p->nCol; i++){
    ++    if( p->abPK[i] ){
    ++      nPk++;
    ++      sessionAppendStr(&buf, zSep, &rc);
    ++      sessionAppendIdent(&buf, p->azCol[i], &rc);
    ++      sessionAppendStr(&buf, " = ?", &rc);
    ++      sessionAppendInteger(&buf, i+1, &rc);
    ++      zSep = " AND ";
    ++    }
    ++  }
    ++
    ++  if( nPk<p->nCol ){
    ++    sessionAppendStr(&buf, " AND (?", &rc);
    ++    sessionAppendInteger(&buf, p->nCol+1, &rc);
    ++    sessionAppendStr(&buf, " OR ", &rc);
    ++
    ++    zSep = "";
    ++    for(i=0; i<p->nCol; i++){
    ++      if( !p->abPK[i] ){
    ++        sessionAppendStr(&buf, zSep, &rc);
    ++        sessionAppendIdent(&buf, p->azCol[i], &rc);
    ++        sessionAppendStr(&buf, " IS ?", &rc);
    ++        sessionAppendInteger(&buf, i+1, &rc);
    ++        zSep = "AND ";
    ++      }
    ++    }
    ++    sessionAppendStr(&buf, ")", &rc);
    ++  }
    ++
    ++  if( rc==SQLITE_OK ){
    ++    rc = sqlite3_prepare_v2(db, (char *)buf.aBuf, buf.nBuf, &p->pDelete, 0);
    ++  }
    ++  sqlite3_free(buf.aBuf);
    ++
    ++  return rc;
    ++}
    ++
    ++/*
    ++** Formulate and prepare a statement to UPDATE a row from database db. 
    ++** Assuming a table structure like this:
    ++**
    ++**     CREATE TABLE x(a, b, c, d, PRIMARY KEY(a, c));
    ++**
    ++** The UPDATE statement looks like this:
    ++**
    ++**     UPDATE x SET
    ++**     a = CASE WHEN ?2  THEN ?3  ELSE a END,
    ++**     b = CASE WHEN ?5  THEN ?6  ELSE b END,
    ++**     c = CASE WHEN ?8  THEN ?9  ELSE c END,
    ++**     d = CASE WHEN ?11 THEN ?12 ELSE d END
    ++**     WHERE a = ?1 AND c = ?7 AND (?13 OR 
    ++**       (?5==0 OR b IS ?4) AND (?11==0 OR d IS ?10) AND
    ++**     )
    ++**
    ++** For each column in the table, there are three variables to bind:
    ++**
    ++**     ?(i*3+1)    The old.* value of the column, if any.
    ++**     ?(i*3+2)    A boolean flag indicating that the value is being modified.
    ++**     ?(i*3+3)    The new.* value of the column, if any.
    ++**
    ++** Also, a boolean flag that, if set to true, causes the statement to update
    ++** a row even if the non-PK values do not match. This is required if the
    ++** conflict-handler is invoked with CHANGESET_DATA and returns
    ++** CHANGESET_REPLACE. This is variable "?(nCol*3+1)".
    ++**
    ++** If successful, SQLITE_OK is returned and SessionApplyCtx.pUpdate is left
    ++** pointing to the prepared version of the SQL statement.
    ++*/
    ++static int sessionUpdateRow(
    ++  sqlite3 *db,                    /* Database handle */
    ++  const char *zTab,               /* Table name */
    ++  SessionApplyCtx *p              /* Session changeset-apply context */
    ++){
    ++  int rc = SQLITE_OK;
    ++  int i;
    ++  const char *zSep = "";
    ++  SessionBuffer buf = {0, 0, 0};
    ++
    ++  /* Append "UPDATE tbl SET " */
    ++  sessionAppendStr(&buf, "UPDATE ", &rc);
    ++  sessionAppendIdent(&buf, zTab, &rc);
    ++  sessionAppendStr(&buf, " SET ", &rc);
    ++
    ++  /* Append the assignments */
    ++  for(i=0; i<p->nCol; i++){
    ++    sessionAppendStr(&buf, zSep, &rc);
    ++    sessionAppendIdent(&buf, p->azCol[i], &rc);
    ++    sessionAppendStr(&buf, " = CASE WHEN ?", &rc);
    ++    sessionAppendInteger(&buf, i*3+2, &rc);
    ++    sessionAppendStr(&buf, " THEN ?", &rc);
    ++    sessionAppendInteger(&buf, i*3+3, &rc);
    ++    sessionAppendStr(&buf, " ELSE ", &rc);
    ++    sessionAppendIdent(&buf, p->azCol[i], &rc);
    ++    sessionAppendStr(&buf, " END", &rc);
    ++    zSep = ", ";
    ++  }
    ++
    ++  /* Append the PK part of the WHERE clause */
    ++  sessionAppendStr(&buf, " WHERE ", &rc);
    ++  for(i=0; i<p->nCol; i++){
    ++    if( p->abPK[i] ){
    ++      sessionAppendIdent(&buf, p->azCol[i], &rc);
    ++      sessionAppendStr(&buf, " = ?", &rc);
    ++      sessionAppendInteger(&buf, i*3+1, &rc);
    ++      sessionAppendStr(&buf, " AND ", &rc);
    ++    }
    ++  }
    ++
    ++  /* Append the non-PK part of the WHERE clause */
    ++  sessionAppendStr(&buf, " (?", &rc);
    ++  sessionAppendInteger(&buf, p->nCol*3+1, &rc);
    ++  sessionAppendStr(&buf, " OR 1", &rc);
    ++  for(i=0; i<p->nCol; i++){
    ++    if( !p->abPK[i] ){
    ++      sessionAppendStr(&buf, " AND (?", &rc);
    ++      sessionAppendInteger(&buf, i*3+2, &rc);
    ++      sessionAppendStr(&buf, "=0 OR ", &rc);
    ++      sessionAppendIdent(&buf, p->azCol[i], &rc);
    ++      sessionAppendStr(&buf, " IS ?", &rc);
    ++      sessionAppendInteger(&buf, i*3+1, &rc);
    ++      sessionAppendStr(&buf, ")", &rc);
    ++    }
    ++  }
    ++  sessionAppendStr(&buf, ")", &rc);
    ++
    ++  if( rc==SQLITE_OK ){
    ++    rc = sqlite3_prepare_v2(db, (char *)buf.aBuf, buf.nBuf, &p->pUpdate, 0);
    ++  }
    ++  sqlite3_free(buf.aBuf);
    ++
    ++  return rc;
    ++}
    ++
    ++
    ++/*
    ++** Formulate and prepare an SQL statement to query table zTab by primary
    ++** key. Assuming the following table structure:
    ++**
    ++**     CREATE TABLE x(a, b, c, d, PRIMARY KEY(a, c));
    ++**
    ++** The SELECT statement looks like this:
    ++**
    ++**     SELECT * FROM x WHERE a = ?1 AND c = ?3
    ++**
    ++** If successful, SQLITE_OK is returned and SessionApplyCtx.pSelect is left
    ++** pointing to the prepared version of the SQL statement.
    ++*/
    ++static int sessionSelectRow(
    ++  sqlite3 *db,                    /* Database handle */
    ++  const char *zTab,               /* Table name */
    ++  SessionApplyCtx *p              /* Session changeset-apply context */
    ++){
    ++  return sessionSelectStmt(
    ++      db, "main", zTab, p->nCol, p->azCol, p->abPK, &p->pSelect);
    ++}
    ++
    ++/*
    ++** Formulate and prepare an INSERT statement to add a record to table zTab.
    ++** For example:
    ++**
    ++**     INSERT INTO main."zTab" VALUES(?1, ?2, ?3 ...);
    ++**
    ++** If successful, SQLITE_OK is returned and SessionApplyCtx.pInsert is left
    ++** pointing to the prepared version of the SQL statement.
    ++*/
    ++static int sessionInsertRow(
    ++  sqlite3 *db,                    /* Database handle */
    ++  const char *zTab,               /* Table name */
    ++  SessionApplyCtx *p              /* Session changeset-apply context */
    ++){
    ++  int rc = SQLITE_OK;
    ++  int i;
    ++  SessionBuffer buf = {0, 0, 0};
    ++
    ++  sessionAppendStr(&buf, "INSERT INTO main.", &rc);
    ++  sessionAppendIdent(&buf, zTab, &rc);
    ++  sessionAppendStr(&buf, "(", &rc);
    ++  for(i=0; i<p->nCol; i++){
    ++    if( i!=0 ) sessionAppendStr(&buf, ", ", &rc);
    ++    sessionAppendIdent(&buf, p->azCol[i], &rc);
    ++  }
    ++
    ++  sessionAppendStr(&buf, ") VALUES(?", &rc);
    ++  for(i=1; i<p->nCol; i++){
    ++    sessionAppendStr(&buf, ", ?", &rc);
    ++  }
    ++  sessionAppendStr(&buf, ")", &rc);
    ++
    ++  if( rc==SQLITE_OK ){
    ++    rc = sqlite3_prepare_v2(db, (char *)buf.aBuf, buf.nBuf, &p->pInsert, 0);
    ++  }
    ++  sqlite3_free(buf.aBuf);
    ++  return rc;
    ++}
    ++
    ++static int sessionPrepare(sqlite3 *db, sqlite3_stmt **pp, const char *zSql){
    ++  return sqlite3_prepare_v2(db, zSql, -1, pp, 0);
    ++}
    ++
    ++/*
    ++** Prepare statements for applying changes to the sqlite_stat1 table.
    ++** These are similar to those created by sessionSelectRow(),
    ++** sessionInsertRow(), sessionUpdateRow() and sessionDeleteRow() for 
    ++** other tables.
    ++*/
    ++static int sessionStat1Sql(sqlite3 *db, SessionApplyCtx *p){
    ++  int rc = sessionSelectRow(db, "sqlite_stat1", p);
    ++  if( rc==SQLITE_OK ){
    ++    rc = sessionPrepare(db, &p->pInsert,
    ++        "INSERT INTO main.sqlite_stat1 VALUES(?1, "
    ++        "CASE WHEN length(?2)=0 AND typeof(?2)='blob' THEN NULL ELSE ?2 END, "
    ++        "?3)"
    ++    );
    ++  }
    ++  if( rc==SQLITE_OK ){
    ++    rc = sessionPrepare(db, &p->pUpdate,
    ++        "UPDATE main.sqlite_stat1 SET "
    ++        "tbl = CASE WHEN ?2 THEN ?3 ELSE tbl END, "
    ++        "idx = CASE WHEN ?5 THEN ?6 ELSE idx END, "
    ++        "stat = CASE WHEN ?8 THEN ?9 ELSE stat END  "
    ++        "WHERE tbl=?1 AND idx IS "
    ++        "CASE WHEN length(?4)=0 AND typeof(?4)='blob' THEN NULL ELSE ?4 END "
    ++        "AND (?10 OR ?8=0 OR stat IS ?7)"
    ++    );
    ++  }
    ++  if( rc==SQLITE_OK ){
    ++    rc = sessionPrepare(db, &p->pDelete,
    ++        "DELETE FROM main.sqlite_stat1 WHERE tbl=?1 AND idx IS "
    ++        "CASE WHEN length(?2)=0 AND typeof(?2)='blob' THEN NULL ELSE ?2 END "
    ++        "AND (?4 OR stat IS ?3)"
    ++    );
    ++  }
    ++  assert( rc==SQLITE_OK );
    ++  return rc;
    ++}
    ++
    ++/*
    ++** A wrapper around sqlite3_bind_value() that detects an extra problem. 
    ++** See comments in the body of this function for details.
    ++*/
    ++static int sessionBindValue(
    ++  sqlite3_stmt *pStmt,            /* Statement to bind value to */
    ++  int i,                          /* Parameter number to bind to */
    ++  sqlite3_value *pVal             /* Value to bind */
    ++){
    ++  int eType = sqlite3_value_type(pVal);
    ++  /* COVERAGE: The (pVal->z==0) branch is never true using current versions
    ++  ** of SQLite. If a malloc fails in an sqlite3_value_xxx() function, either
    ++  ** the (pVal->z) variable remains as it was or the type of the value is
    ++  ** set to SQLITE_NULL.  */
    ++  if( (eType==SQLITE_TEXT || eType==SQLITE_BLOB) && pVal->z==0 ){
    ++    /* This condition occurs when an earlier OOM in a call to
    ++    ** sqlite3_value_text() or sqlite3_value_blob() (perhaps from within
    ++    ** a conflict-handler) has zeroed the pVal->z pointer. Return NOMEM. */
    ++    return SQLITE_NOMEM;
    ++  }
    ++  return sqlite3_bind_value(pStmt, i, pVal);
    ++}
    ++
    ++/*
    ++** Iterator pIter must point to an SQLITE_INSERT entry. This function 
    ++** transfers new.* values from the current iterator entry to statement
    ++** pStmt. The table being inserted into has nCol columns.
    ++**
    ++** New.* value $i from the iterator is bound to variable ($i+1) of 
    ++** statement pStmt. If parameter abPK is NULL, all values from 0 to (nCol-1)
    ++** are transfered to the statement. Otherwise, if abPK is not NULL, it points
    ++** to an array nCol elements in size. In this case only those values for 
    ++** which abPK[$i] is true are read from the iterator and bound to the 
    ++** statement.
    ++**
    ++** An SQLite error code is returned if an error occurs. Otherwise, SQLITE_OK.
    ++*/
    ++static int sessionBindRow(
    ++  sqlite3_changeset_iter *pIter,  /* Iterator to read values from */
    ++  int(*xValue)(sqlite3_changeset_iter *, int, sqlite3_value **),
    ++  int nCol,                       /* Number of columns */
    ++  u8 *abPK,                       /* If not NULL, bind only if true */
    ++  sqlite3_stmt *pStmt             /* Bind values to this statement */
    ++){
    ++  int i;
    ++  int rc = SQLITE_OK;
    ++
    ++  /* Neither sqlite3changeset_old or sqlite3changeset_new can fail if the
    ++  ** argument iterator points to a suitable entry. Make sure that xValue 
    ++  ** is one of these to guarantee that it is safe to ignore the return 
    ++  ** in the code below. */
    ++  assert( xValue==sqlite3changeset_old || xValue==sqlite3changeset_new );
    ++
    ++  for(i=0; rc==SQLITE_OK && i<nCol; i++){
    ++    if( !abPK || abPK[i] ){
    ++      sqlite3_value *pVal;
    ++      (void)xValue(pIter, i, &pVal);
    ++      rc = sessionBindValue(pStmt, i+1, pVal);
    ++    }
    ++  }
    ++  return rc;
    ++}
    ++
    ++/*
    ++** SQL statement pSelect is as generated by the sessionSelectRow() function.
    ++** This function binds the primary key values from the change that changeset
    ++** iterator pIter points to to the SELECT and attempts to seek to the table
    ++** entry. If a row is found, the SELECT statement left pointing at the row 
    ++** and SQLITE_ROW is returned. Otherwise, if no row is found and no error
    ++** has occured, the statement is reset and SQLITE_OK is returned. If an
    ++** error occurs, the statement is reset and an SQLite error code is returned.
    ++**
    ++** If this function returns SQLITE_ROW, the caller must eventually reset() 
    ++** statement pSelect. If any other value is returned, the statement does
    ++** not require a reset().
    ++**
    ++** If the iterator currently points to an INSERT record, bind values from the
    ++** new.* record to the SELECT statement. Or, if it points to a DELETE or
    ++** UPDATE, bind values from the old.* record. 
    ++*/
    ++static int sessionSeekToRow(
    ++  sqlite3 *db,                    /* Database handle */
    ++  sqlite3_changeset_iter *pIter,  /* Changeset iterator */
    ++  u8 *abPK,                       /* Primary key flags array */
    ++  sqlite3_stmt *pSelect           /* SELECT statement from sessionSelectRow() */
    ++){
    ++  int rc;                         /* Return code */
    ++  int nCol;                       /* Number of columns in table */
    ++  int op;                         /* Changset operation (SQLITE_UPDATE etc.) */
    ++  const char *zDummy;             /* Unused */
    ++
    ++  sqlite3changeset_op(pIter, &zDummy, &nCol, &op, 0);
    ++  rc = sessionBindRow(pIter, 
    ++      op==SQLITE_INSERT ? sqlite3changeset_new : sqlite3changeset_old,
    ++      nCol, abPK, pSelect
    ++  );
    ++
    ++  if( rc==SQLITE_OK ){
    ++    rc = sqlite3_step(pSelect);
    ++    if( rc!=SQLITE_ROW ) rc = sqlite3_reset(pSelect);
    ++  }
    ++
    ++  return rc;
    ++}
    ++
    ++/*
    ++** Invoke the conflict handler for the change that the changeset iterator
    ++** currently points to.
    ++**
    ++** Argument eType must be either CHANGESET_DATA or CHANGESET_CONFLICT.
    ++** If argument pbReplace is NULL, then the type of conflict handler invoked
    ++** depends solely on eType, as follows:
    ++**
    ++**    eType value                 Value passed to xConflict
    ++**    -------------------------------------------------
    ++**    CHANGESET_DATA              CHANGESET_NOTFOUND
    ++**    CHANGESET_CONFLICT          CHANGESET_CONSTRAINT
    ++**
    ++** Or, if pbReplace is not NULL, then an attempt is made to find an existing
    ++** record with the same primary key as the record about to be deleted, updated
    ++** or inserted. If such a record can be found, it is available to the conflict
    ++** handler as the "conflicting" record. In this case the type of conflict
    ++** handler invoked is as follows:
    ++**
    ++**    eType value         PK Record found?   Value passed to xConflict
    ++**    ----------------------------------------------------------------
    ++**    CHANGESET_DATA      Yes                CHANGESET_DATA
    ++**    CHANGESET_DATA      No                 CHANGESET_NOTFOUND
    ++**    CHANGESET_CONFLICT  Yes                CHANGESET_CONFLICT
    ++**    CHANGESET_CONFLICT  No                 CHANGESET_CONSTRAINT
    ++**
    ++** If pbReplace is not NULL, and a record with a matching PK is found, and
    ++** the conflict handler function returns SQLITE_CHANGESET_REPLACE, *pbReplace
    ++** is set to non-zero before returning SQLITE_OK.
    ++**
    ++** If the conflict handler returns SQLITE_CHANGESET_ABORT, SQLITE_ABORT is
    ++** returned. Or, if the conflict handler returns an invalid value, 
    ++** SQLITE_MISUSE. If the conflict handler returns SQLITE_CHANGESET_OMIT,
    ++** this function returns SQLITE_OK.
    ++*/
    ++static int sessionConflictHandler(
    ++  int eType,                      /* Either CHANGESET_DATA or CONFLICT */
    ++  SessionApplyCtx *p,             /* changeset_apply() context */
    ++  sqlite3_changeset_iter *pIter,  /* Changeset iterator */
    ++  int(*xConflict)(void *, int, sqlite3_changeset_iter*),
    ++  void *pCtx,                     /* First argument for conflict handler */
    ++  int *pbReplace                  /* OUT: Set to true if PK row is found */
    ++){
    ++  int res = 0;                    /* Value returned by conflict handler */
    ++  int rc;
    ++  int nCol;
    ++  int op;
    ++  const char *zDummy;
    ++
    ++  sqlite3changeset_op(pIter, &zDummy, &nCol, &op, 0);
    ++
    ++  assert( eType==SQLITE_CHANGESET_CONFLICT || eType==SQLITE_CHANGESET_DATA );
    ++  assert( SQLITE_CHANGESET_CONFLICT+1==SQLITE_CHANGESET_CONSTRAINT );
    ++  assert( SQLITE_CHANGESET_DATA+1==SQLITE_CHANGESET_NOTFOUND );
    ++
    ++  /* Bind the new.* PRIMARY KEY values to the SELECT statement. */
    ++  if( pbReplace ){
    ++    rc = sessionSeekToRow(p->db, pIter, p->abPK, p->pSelect);
    ++  }else{
    ++    rc = SQLITE_OK;
    ++  }
    ++
    ++  if( rc==SQLITE_ROW ){
    ++    /* There exists another row with the new.* primary key. */
    ++    pIter->pConflict = p->pSelect;
    ++    res = xConflict(pCtx, eType, pIter);
    ++    pIter->pConflict = 0;
    ++    rc = sqlite3_reset(p->pSelect);
    ++  }else if( rc==SQLITE_OK ){
    ++    if( p->bDeferConstraints && eType==SQLITE_CHANGESET_CONFLICT ){
    ++      /* Instead of invoking the conflict handler, append the change blob
    ++      ** to the SessionApplyCtx.constraints buffer. */
    ++      u8 *aBlob = &pIter->in.aData[pIter->in.iCurrent];
    ++      int nBlob = pIter->in.iNext - pIter->in.iCurrent;
    ++      sessionAppendBlob(&p->constraints, aBlob, nBlob, &rc);
    ++      res = SQLITE_CHANGESET_OMIT;
    ++    }else{
    ++      /* No other row with the new.* primary key. */
    ++      res = xConflict(pCtx, eType+1, pIter);
    ++      if( res==SQLITE_CHANGESET_REPLACE ) rc = SQLITE_MISUSE;
    ++    }
    ++  }
    ++
    ++  if( rc==SQLITE_OK ){
    ++    switch( res ){
    ++      case SQLITE_CHANGESET_REPLACE:
    ++        assert( pbReplace );
    ++        *pbReplace = 1;
    ++        break;
    ++
    ++      case SQLITE_CHANGESET_OMIT:
    ++        break;
    ++
    ++      case SQLITE_CHANGESET_ABORT:
    ++        rc = SQLITE_ABORT;
    ++        break;
    ++
    ++      default:
    ++        rc = SQLITE_MISUSE;
    ++        break;
    ++    }
    ++  }
    ++
    ++  return rc;
    ++}
    ++
    ++/*
    ++** Attempt to apply the change that the iterator passed as the first argument
    ++** currently points to to the database. If a conflict is encountered, invoke
    ++** the conflict handler callback.
    ++**
    ++** If argument pbRetry is NULL, then ignore any CHANGESET_DATA conflict. If
    ++** one is encountered, update or delete the row with the matching primary key
    ++** instead. Or, if pbRetry is not NULL and a CHANGESET_DATA conflict occurs,
    ++** invoke the conflict handler. If it returns CHANGESET_REPLACE, set *pbRetry
    ++** to true before returning. In this case the caller will invoke this function
    ++** again, this time with pbRetry set to NULL.
    ++**
    ++** If argument pbReplace is NULL and a CHANGESET_CONFLICT conflict is 
    ++** encountered invoke the conflict handler with CHANGESET_CONSTRAINT instead.
    ++** Or, if pbReplace is not NULL, invoke it with CHANGESET_CONFLICT. If such
    ++** an invocation returns SQLITE_CHANGESET_REPLACE, set *pbReplace to true
    ++** before retrying. In this case the caller attempts to remove the conflicting
    ++** row before invoking this function again, this time with pbReplace set 
    ++** to NULL.
    ++**
    ++** If any conflict handler returns SQLITE_CHANGESET_ABORT, this function
    ++** returns SQLITE_ABORT. Otherwise, if no error occurs, SQLITE_OK is 
    ++** returned.
    ++*/
    ++static int sessionApplyOneOp(
    ++  sqlite3_changeset_iter *pIter,  /* Changeset iterator */
    ++  SessionApplyCtx *p,             /* changeset_apply() context */
    ++  int(*xConflict)(void *, int, sqlite3_changeset_iter *),
    ++  void *pCtx,                     /* First argument for the conflict handler */
    ++  int *pbReplace,                 /* OUT: True to remove PK row and retry */
    ++  int *pbRetry                    /* OUT: True to retry. */
    ++){
    ++  const char *zDummy;
    ++  int op;
    ++  int nCol;
    ++  int rc = SQLITE_OK;
    ++
    ++  assert( p->pDelete && p->pUpdate && p->pInsert && p->pSelect );
    ++  assert( p->azCol && p->abPK );
    ++  assert( !pbReplace || *pbReplace==0 );
    ++
    ++  sqlite3changeset_op(pIter, &zDummy, &nCol, &op, 0);
    ++
    ++  if( op==SQLITE_DELETE ){
    ++
    ++    /* Bind values to the DELETE statement. If conflict handling is required,
    ++    ** bind values for all columns and set bound variable (nCol+1) to true.
    ++    ** Or, if conflict handling is not required, bind just the PK column
    ++    ** values and, if it exists, set (nCol+1) to false. Conflict handling
    ++    ** is not required if:
    ++    **
    ++    **   * this is a patchset, or
    ++    **   * (pbRetry==0), or
    ++    **   * all columns of the table are PK columns (in this case there is
    ++    **     no (nCol+1) variable to bind to).
    ++    */
    ++    u8 *abPK = (pIter->bPatchset ? p->abPK : 0);
    ++    rc = sessionBindRow(pIter, sqlite3changeset_old, nCol, abPK, p->pDelete);
    ++    if( rc==SQLITE_OK && sqlite3_bind_parameter_count(p->pDelete)>nCol ){
    ++      rc = sqlite3_bind_int(p->pDelete, nCol+1, (pbRetry==0 || abPK));
    ++    }
    ++    if( rc!=SQLITE_OK ) return rc;
    ++
    ++    sqlite3_step(p->pDelete);
    ++    rc = sqlite3_reset(p->pDelete);
    ++    if( rc==SQLITE_OK && sqlite3_changes(p->db)==0 ){
    ++      rc = sessionConflictHandler(
    ++          SQLITE_CHANGESET_DATA, p, pIter, xConflict, pCtx, pbRetry
    ++      );
    ++    }else if( (rc&0xff)==SQLITE_CONSTRAINT ){
    ++      rc = sessionConflictHandler(
    ++          SQLITE_CHANGESET_CONFLICT, p, pIter, xConflict, pCtx, 0
    ++      );
    ++    }
    ++
    ++  }else if( op==SQLITE_UPDATE ){
    ++    int i;
    ++
    ++    /* Bind values to the UPDATE statement. */
    ++    for(i=0; rc==SQLITE_OK && i<nCol; i++){
    ++      sqlite3_value *pOld = sessionChangesetOld(pIter, i);
    ++      sqlite3_value *pNew = sessionChangesetNew(pIter, i);
    ++
    ++      sqlite3_bind_int(p->pUpdate, i*3+2, !!pNew);
    ++      if( pOld ){
    ++        rc = sessionBindValue(p->pUpdate, i*3+1, pOld);
    ++      }
    ++      if( rc==SQLITE_OK && pNew ){
    ++        rc = sessionBindValue(p->pUpdate, i*3+3, pNew);
    ++      }
    ++    }
    ++    if( rc==SQLITE_OK ){
    ++      sqlite3_bind_int(p->pUpdate, nCol*3+1, pbRetry==0 || pIter->bPatchset);
    ++    }
    ++    if( rc!=SQLITE_OK ) return rc;
    ++
    ++    /* Attempt the UPDATE. In the case of a NOTFOUND or DATA conflict,
    ++    ** the result will be SQLITE_OK with 0 rows modified. */
    ++    sqlite3_step(p->pUpdate);
    ++    rc = sqlite3_reset(p->pUpdate);
    ++
    ++    if( rc==SQLITE_OK && sqlite3_changes(p->db)==0 ){
    ++      /* A NOTFOUND or DATA error. Search the table to see if it contains
    ++      ** a row with a matching primary key. If so, this is a DATA conflict.
    ++      ** Otherwise, if there is no primary key match, it is a NOTFOUND. */
    ++
    ++      rc = sessionConflictHandler(
    ++          SQLITE_CHANGESET_DATA, p, pIter, xConflict, pCtx, pbRetry
    ++      );
    ++
    ++    }else if( (rc&0xff)==SQLITE_CONSTRAINT ){
    ++      /* This is always a CONSTRAINT conflict. */
    ++      rc = sessionConflictHandler(
    ++          SQLITE_CHANGESET_CONFLICT, p, pIter, xConflict, pCtx, 0
    ++      );
    ++    }
    ++
    ++  }else{
    ++    assert( op==SQLITE_INSERT );
    ++    if( p->bStat1 ){
    ++      /* Check if there is a conflicting row. For sqlite_stat1, this needs
    ++      ** to be done using a SELECT, as there is no PRIMARY KEY in the 
    ++      ** database schema to throw an exception if a duplicate is inserted.  */
    ++      rc = sessionSeekToRow(p->db, pIter, p->abPK, p->pSelect);
    ++      if( rc==SQLITE_ROW ){
    ++        rc = SQLITE_CONSTRAINT;
    ++        sqlite3_reset(p->pSelect);
    ++      }
    ++    }
    ++
    ++    if( rc==SQLITE_OK ){
    ++      rc = sessionBindRow(pIter, sqlite3changeset_new, nCol, 0, p->pInsert);
    ++      if( rc!=SQLITE_OK ) return rc;
    ++
    ++      sqlite3_step(p->pInsert);
    ++      rc = sqlite3_reset(p->pInsert);
    ++    }
    ++
    ++    if( (rc&0xff)==SQLITE_CONSTRAINT ){
    ++      rc = sessionConflictHandler(
    ++          SQLITE_CHANGESET_CONFLICT, p, pIter, xConflict, pCtx, pbReplace
    ++      );
    ++    }
    ++  }
    ++
    ++  return rc;
    ++}
    ++
    ++/*
    ++** Attempt to apply the change that the iterator passed as the first argument
    ++** currently points to to the database. If a conflict is encountered, invoke
    ++** the conflict handler callback.
    ++**
    ++** The difference between this function and sessionApplyOne() is that this
    ++** function handles the case where the conflict-handler is invoked and 
    ++** returns SQLITE_CHANGESET_REPLACE - indicating that the change should be
    ++** retried in some manner.
    ++*/
    ++static int sessionApplyOneWithRetry(
    ++  sqlite3 *db,                    /* Apply change to "main" db of this handle */
    ++  sqlite3_changeset_iter *pIter,  /* Changeset iterator to read change from */
    ++  SessionApplyCtx *pApply,        /* Apply context */
    ++  int(*xConflict)(void*, int, sqlite3_changeset_iter*),
    ++  void *pCtx                      /* First argument passed to xConflict */
    ++){
    ++  int bReplace = 0;
    ++  int bRetry = 0;
    ++  int rc;
    ++
    ++  rc = sessionApplyOneOp(pIter, pApply, xConflict, pCtx, &bReplace, &bRetry);
    ++  assert( rc==SQLITE_OK || (bRetry==0 && bReplace==0) );
    ++
    ++  /* If the bRetry flag is set, the change has not been applied due to an
    ++  ** SQLITE_CHANGESET_DATA problem (i.e. this is an UPDATE or DELETE and
    ++  ** a row with the correct PK is present in the db, but one or more other
    ++  ** fields do not contain the expected values) and the conflict handler 
    ++  ** returned SQLITE_CHANGESET_REPLACE. In this case retry the operation,
    ++  ** but pass NULL as the final argument so that sessionApplyOneOp() ignores
    ++  ** the SQLITE_CHANGESET_DATA problem.  */
    ++  if( bRetry ){
    ++    assert( pIter->op==SQLITE_UPDATE || pIter->op==SQLITE_DELETE );
    ++    rc = sessionApplyOneOp(pIter, pApply, xConflict, pCtx, 0, 0);
    ++  }
    ++
    ++  /* If the bReplace flag is set, the change is an INSERT that has not
    ++  ** been performed because the database already contains a row with the
    ++  ** specified primary key and the conflict handler returned
    ++  ** SQLITE_CHANGESET_REPLACE. In this case remove the conflicting row
    ++  ** before reattempting the INSERT.  */
    ++  else if( bReplace ){
    ++    assert( pIter->op==SQLITE_INSERT );
    ++    rc = sqlite3_exec(db, "SAVEPOINT replace_op", 0, 0, 0);
    ++    if( rc==SQLITE_OK ){
    ++      rc = sessionBindRow(pIter, 
    ++          sqlite3changeset_new, pApply->nCol, pApply->abPK, pApply->pDelete);
    ++      sqlite3_bind_int(pApply->pDelete, pApply->nCol+1, 1);
    ++    }
    ++    if( rc==SQLITE_OK ){
    ++      sqlite3_step(pApply->pDelete);
    ++      rc = sqlite3_reset(pApply->pDelete);
    ++    }
    ++    if( rc==SQLITE_OK ){
    ++      rc = sessionApplyOneOp(pIter, pApply, xConflict, pCtx, 0, 0);
    ++    }
    ++    if( rc==SQLITE_OK ){
    ++      rc = sqlite3_exec(db, "RELEASE replace_op", 0, 0, 0);
    ++    }
    ++  }
    ++
    ++  return rc;
    ++}
    ++
    ++/*
    ++** Retry the changes accumulated in the pApply->constraints buffer.
    ++*/
    ++static int sessionRetryConstraints(
    ++  sqlite3 *db, 
    ++  int bPatchset,
    ++  const char *zTab,
    ++  SessionApplyCtx *pApply,
    ++  int(*xConflict)(void*, int, sqlite3_changeset_iter*),
    ++  void *pCtx                      /* First argument passed to xConflict */
    ++){
    ++  int rc = SQLITE_OK;
    ++
    ++  while( pApply->constraints.nBuf ){
    ++    sqlite3_changeset_iter *pIter2 = 0;
    ++    SessionBuffer cons = pApply->constraints;
    ++    memset(&pApply->constraints, 0, sizeof(SessionBuffer));
    ++
    ++    rc = sessionChangesetStart(&pIter2, 0, 0, cons.nBuf, cons.aBuf);
    ++    if( rc==SQLITE_OK ){
    ++      int nByte = 2*pApply->nCol*sizeof(sqlite3_value*);
    ++      int rc2;
    ++      pIter2->bPatchset = bPatchset;
    ++      pIter2->zTab = (char*)zTab;
    ++      pIter2->nCol = pApply->nCol;
    ++      pIter2->abPK = pApply->abPK;
    ++      sessionBufferGrow(&pIter2->tblhdr, nByte, &rc);
    ++      pIter2->apValue = (sqlite3_value**)pIter2->tblhdr.aBuf;
    ++      if( rc==SQLITE_OK ) memset(pIter2->apValue, 0, nByte);
    ++
    ++      while( rc==SQLITE_OK && SQLITE_ROW==sqlite3changeset_next(pIter2) ){
    ++        rc = sessionApplyOneWithRetry(db, pIter2, pApply, xConflict, pCtx);
    ++      }
    ++
    ++      rc2 = sqlite3changeset_finalize(pIter2);
    ++      if( rc==SQLITE_OK ) rc = rc2;
    ++    }
    ++    assert( pApply->bDeferConstraints || pApply->constraints.nBuf==0 );
    ++
    ++    sqlite3_free(cons.aBuf);
    ++    if( rc!=SQLITE_OK ) break;
    ++    if( pApply->constraints.nBuf>=cons.nBuf ){
    ++      /* No progress was made on the last round. */
    ++      pApply->bDeferConstraints = 0;
    ++    }
    ++  }
    ++
    ++  return rc;
    ++}
    ++
    ++/*
    ++** Argument pIter is a changeset iterator that has been initialized, but
    ++** not yet passed to sqlite3changeset_next(). This function applies the 
    ++** changeset to the main database attached to handle "db". The supplied
    ++** conflict handler callback is invoked to resolve any conflicts encountered
    ++** while applying the change.
    ++*/
    ++static int sessionChangesetApply(
    ++  sqlite3 *db,                    /* Apply change to "main" db of this handle */
    ++  sqlite3_changeset_iter *pIter,  /* Changeset to apply */
    ++  int(*xFilter)(
    ++    void *pCtx,                   /* Copy of sixth arg to _apply() */
    ++    const char *zTab              /* Table name */
    ++  ),
    ++  int(*xConflict)(
    ++    void *pCtx,                   /* Copy of fifth arg to _apply() */
    ++    int eConflict,                /* DATA, MISSING, CONFLICT, CONSTRAINT */
    ++    sqlite3_changeset_iter *p     /* Handle describing change and conflict */
    ++  ),
    ++  void *pCtx                      /* First argument passed to xConflict */
    ++){
    ++  int schemaMismatch = 0;
    ++  int rc;                         /* Return code */
    ++  const char *zTab = 0;           /* Name of current table */
    ++  int nTab = 0;                   /* Result of sqlite3Strlen30(zTab) */
    ++  SessionApplyCtx sApply;         /* changeset_apply() context object */
    ++  int bPatchset;
    ++
    ++  assert( xConflict!=0 );
    ++
    ++  pIter->in.bNoDiscard = 1;
    ++  memset(&sApply, 0, sizeof(sApply));
    ++  sqlite3_mutex_enter(sqlite3_db_mutex(db));
    ++  rc = sqlite3_exec(db, "SAVEPOINT changeset_apply", 0, 0, 0);
    ++  if( rc==SQLITE_OK ){
    ++    rc = sqlite3_exec(db, "PRAGMA defer_foreign_keys = 1", 0, 0, 0);
    ++  }
    ++  while( rc==SQLITE_OK && SQLITE_ROW==sqlite3changeset_next(pIter) ){
    ++    int nCol;
    ++    int op;
    ++    const char *zNew;
    ++    
    ++    sqlite3changeset_op(pIter, &zNew, &nCol, &op, 0);
    ++
    ++    if( zTab==0 || sqlite3_strnicmp(zNew, zTab, nTab+1) ){
    ++      u8 *abPK;
    ++
    ++      rc = sessionRetryConstraints(
    ++          db, pIter->bPatchset, zTab, &sApply, xConflict, pCtx
    ++      );
    ++      if( rc!=SQLITE_OK ) break;
    ++
    ++      sqlite3_free((char*)sApply.azCol);  /* cast works around VC++ bug */
    ++      sqlite3_finalize(sApply.pDelete);
    ++      sqlite3_finalize(sApply.pUpdate); 
    ++      sqlite3_finalize(sApply.pInsert);
    ++      sqlite3_finalize(sApply.pSelect);
    ++      memset(&sApply, 0, sizeof(sApply));
    ++      sApply.db = db;
    ++      sApply.bDeferConstraints = 1;
    ++
    ++      /* If an xFilter() callback was specified, invoke it now. If the 
    ++      ** xFilter callback returns zero, skip this table. If it returns
    ++      ** non-zero, proceed. */
    ++      schemaMismatch = (xFilter && (0==xFilter(pCtx, zNew)));
    ++      if( schemaMismatch ){
    ++        zTab = sqlite3_mprintf("%s", zNew);
    ++        if( zTab==0 ){
    ++          rc = SQLITE_NOMEM;
    ++          break;
    ++        }
    ++        nTab = (int)strlen(zTab);
    ++        sApply.azCol = (const char **)zTab;
    ++      }else{
    ++        int nMinCol = 0;
    ++        int i;
    ++
    ++        sqlite3changeset_pk(pIter, &abPK, 0);
    ++        rc = sessionTableInfo(
    ++            db, "main", zNew, &sApply.nCol, &zTab, &sApply.azCol, &sApply.abPK
    ++        );
    ++        if( rc!=SQLITE_OK ) break;
    ++        for(i=0; i<sApply.nCol; i++){
    ++          if( sApply.abPK[i] ) nMinCol = i+1;
    ++        }
    ++  
    ++        if( sApply.nCol==0 ){
    ++          schemaMismatch = 1;
    ++          sqlite3_log(SQLITE_SCHEMA, 
    ++              "sqlite3changeset_apply(): no such table: %s", zTab
    ++          );
    ++        }
    ++        else if( sApply.nCol<nCol ){
    ++          schemaMismatch = 1;
    ++          sqlite3_log(SQLITE_SCHEMA, 
    ++              "sqlite3changeset_apply(): table %s has %d columns, "
    ++              "expected %d or more", 
    ++              zTab, sApply.nCol, nCol
    ++          );
    ++        }
    ++        else if( nCol<nMinCol || memcmp(sApply.abPK, abPK, nCol)!=0 ){
    ++          schemaMismatch = 1;
    ++          sqlite3_log(SQLITE_SCHEMA, "sqlite3changeset_apply(): "
    ++              "primary key mismatch for table %s", zTab
    ++          );
    ++        }
    ++        else{
    ++          sApply.nCol = nCol;
    ++          if( 0==sqlite3_stricmp(zTab, "sqlite_stat1") ){
    ++            if( (rc = sessionStat1Sql(db, &sApply) ) ){
    ++              break;
    ++            }
    ++            sApply.bStat1 = 1;
    ++          }else{
    ++            if((rc = sessionSelectRow(db, zTab, &sApply))
    ++                || (rc = sessionUpdateRow(db, zTab, &sApply))
    ++                || (rc = sessionDeleteRow(db, zTab, &sApply))
    ++                || (rc = sessionInsertRow(db, zTab, &sApply))
    ++              ){
    ++              break;
    ++            }
    ++            sApply.bStat1 = 0;
    ++          }
    ++        }
    ++        nTab = sqlite3Strlen30(zTab);
    ++      }
    ++    }
    ++
    ++    /* If there is a schema mismatch on the current table, proceed to the
    ++    ** next change. A log message has already been issued. */
    ++    if( schemaMismatch ) continue;
    ++
    ++    rc = sessionApplyOneWithRetry(db, pIter, &sApply, xConflict, pCtx);
    ++  }
    ++
    ++  bPatchset = pIter->bPatchset;
    ++  if( rc==SQLITE_OK ){
    ++    rc = sqlite3changeset_finalize(pIter);
    ++  }else{
    ++    sqlite3changeset_finalize(pIter);
    ++  }
    ++
    ++  if( rc==SQLITE_OK ){
    ++    rc = sessionRetryConstraints(db, bPatchset, zTab, &sApply, xConflict, pCtx);
    ++  }
    ++
    ++  if( rc==SQLITE_OK ){
    ++    int nFk, notUsed;
    ++    sqlite3_db_status(db, SQLITE_DBSTATUS_DEFERRED_FKS, &nFk, &notUsed, 0);
    ++    if( nFk!=0 ){
    ++      int res = SQLITE_CHANGESET_ABORT;
    ++      sqlite3_changeset_iter sIter;
    ++      memset(&sIter, 0, sizeof(sIter));
    ++      sIter.nCol = nFk;
    ++      res = xConflict(pCtx, SQLITE_CHANGESET_FOREIGN_KEY, &sIter);
    ++      if( res!=SQLITE_CHANGESET_OMIT ){
    ++        rc = SQLITE_CONSTRAINT;
    ++      }
    ++    }
    ++  }
    ++  sqlite3_exec(db, "PRAGMA defer_foreign_keys = 0", 0, 0, 0);
    ++
    ++  if( rc==SQLITE_OK ){
    ++    rc = sqlite3_exec(db, "RELEASE changeset_apply", 0, 0, 0);
    ++  }else{
    ++    sqlite3_exec(db, "ROLLBACK TO changeset_apply", 0, 0, 0);
    ++    sqlite3_exec(db, "RELEASE changeset_apply", 0, 0, 0);
    ++  }
    ++
    ++  sqlite3_finalize(sApply.pInsert);
    ++  sqlite3_finalize(sApply.pDelete);
    ++  sqlite3_finalize(sApply.pUpdate);
    ++  sqlite3_finalize(sApply.pSelect);
    ++  sqlite3_free((char*)sApply.azCol);  /* cast works around VC++ bug */
    ++  sqlite3_free((char*)sApply.constraints.aBuf);
    ++  sqlite3_mutex_leave(sqlite3_db_mutex(db));
    ++  return rc;
    ++}
    ++
    ++/*
    ++** Apply the changeset passed via pChangeset/nChangeset to the main database
    ++** attached to handle "db". Invoke the supplied conflict handler callback
    ++** to resolve any conflicts encountered while applying the change.
    ++*/
    ++SQLITE_API int sqlite3changeset_apply(
    ++  sqlite3 *db,                    /* Apply change to "main" db of this handle */
    ++  int nChangeset,                 /* Size of changeset in bytes */
    ++  void *pChangeset,               /* Changeset blob */
    ++  int(*xFilter)(
    ++    void *pCtx,                   /* Copy of sixth arg to _apply() */
    ++    const char *zTab              /* Table name */
    ++  ),
    ++  int(*xConflict)(
    ++    void *pCtx,                   /* Copy of fifth arg to _apply() */
    ++    int eConflict,                /* DATA, MISSING, CONFLICT, CONSTRAINT */
    ++    sqlite3_changeset_iter *p     /* Handle describing change and conflict */
    ++  ),
    ++  void *pCtx                      /* First argument passed to xConflict */
    ++){
    ++  sqlite3_changeset_iter *pIter;  /* Iterator to skip through changeset */  
    ++  int rc = sqlite3changeset_start(&pIter, nChangeset, pChangeset);
    ++  if( rc==SQLITE_OK ){
    ++    rc = sessionChangesetApply(db, pIter, xFilter, xConflict, pCtx);
    ++  }
    ++  return rc;
    ++}
    ++
    ++/*
    ++** Apply the changeset passed via xInput/pIn to the main database
    ++** attached to handle "db". Invoke the supplied conflict handler callback
    ++** to resolve any conflicts encountered while applying the change.
    ++*/
    ++SQLITE_API int sqlite3changeset_apply_strm(
    ++  sqlite3 *db,                    /* Apply change to "main" db of this handle */
    ++  int (*xInput)(void *pIn, void *pData, int *pnData), /* Input function */
    ++  void *pIn,                                          /* First arg for xInput */
    ++  int(*xFilter)(
    ++    void *pCtx,                   /* Copy of sixth arg to _apply() */
    ++    const char *zTab              /* Table name */
    ++  ),
    ++  int(*xConflict)(
    ++    void *pCtx,                   /* Copy of sixth arg to _apply() */
    ++    int eConflict,                /* DATA, MISSING, CONFLICT, CONSTRAINT */
    ++    sqlite3_changeset_iter *p     /* Handle describing change and conflict */
    ++  ),
    ++  void *pCtx                      /* First argument passed to xConflict */
    ++){
    ++  sqlite3_changeset_iter *pIter;  /* Iterator to skip through changeset */  
    ++  int rc = sqlite3changeset_start_strm(&pIter, xInput, pIn);
    ++  if( rc==SQLITE_OK ){
    ++    rc = sessionChangesetApply(db, pIter, xFilter, xConflict, pCtx);
    ++  }
    ++  return rc;
    ++}
    ++
    ++/*
    ++** sqlite3_changegroup handle.
    ++*/
    ++struct sqlite3_changegroup {
    ++  int rc;                         /* Error code */
    ++  int bPatch;                     /* True to accumulate patchsets */
    ++  SessionTable *pList;            /* List of tables in current patch */
    ++};
    ++
    ++/*
    ++** This function is called to merge two changes to the same row together as
    ++** part of an sqlite3changeset_concat() operation. A new change object is
    ++** allocated and a pointer to it stored in *ppNew.
    ++*/
    ++static int sessionChangeMerge(
    ++  SessionTable *pTab,             /* Table structure */
    ++  int bPatchset,                  /* True for patchsets */
    ++  SessionChange *pExist,          /* Existing change */
    ++  int op2,                        /* Second change operation */
    ++  int bIndirect,                  /* True if second change is indirect */
    ++  u8 *aRec,                       /* Second change record */
    ++  int nRec,                       /* Number of bytes in aRec */
    ++  SessionChange **ppNew           /* OUT: Merged change */
    ++){
    ++  SessionChange *pNew = 0;
    ++
    ++  if( !pExist ){
    ++    pNew = (SessionChange *)sqlite3_malloc(sizeof(SessionChange) + nRec);
    ++    if( !pNew ){
    ++      return SQLITE_NOMEM;
    ++    }
    ++    memset(pNew, 0, sizeof(SessionChange));
    ++    pNew->op = op2;
    ++    pNew->bIndirect = bIndirect;
    ++    pNew->nRecord = nRec;
    ++    pNew->aRecord = (u8*)&pNew[1];
    ++    memcpy(pNew->aRecord, aRec, nRec);
    ++  }else{
    ++    int op1 = pExist->op;
    ++
    ++    /* 
    ++    **   op1=INSERT, op2=INSERT      ->      Unsupported. Discard op2.
    ++    **   op1=INSERT, op2=UPDATE      ->      INSERT.
    ++    **   op1=INSERT, op2=DELETE      ->      (none)
    ++    **
    ++    **   op1=UPDATE, op2=INSERT      ->      Unsupported. Discard op2.
    ++    **   op1=UPDATE, op2=UPDATE      ->      UPDATE.
    ++    **   op1=UPDATE, op2=DELETE      ->      DELETE.
    ++    **
    ++    **   op1=DELETE, op2=INSERT      ->      UPDATE.
    ++    **   op1=DELETE, op2=UPDATE      ->      Unsupported. Discard op2.
    ++    **   op1=DELETE, op2=DELETE      ->      Unsupported. Discard op2.
    ++    */   
    ++    if( (op1==SQLITE_INSERT && op2==SQLITE_INSERT)
    ++     || (op1==SQLITE_UPDATE && op2==SQLITE_INSERT)
    ++     || (op1==SQLITE_DELETE && op2==SQLITE_UPDATE)
    ++     || (op1==SQLITE_DELETE && op2==SQLITE_DELETE)
    ++    ){
    ++      pNew = pExist;
    ++    }else if( op1==SQLITE_INSERT && op2==SQLITE_DELETE ){
    ++      sqlite3_free(pExist);
    ++      assert( pNew==0 );
    ++    }else{
    ++      u8 *aExist = pExist->aRecord;
    ++      int nByte;
    ++      u8 *aCsr;
    ++
    ++      /* Allocate a new SessionChange object. Ensure that the aRecord[]
    ++      ** buffer of the new object is large enough to hold any record that
    ++      ** may be generated by combining the input records.  */
    ++      nByte = sizeof(SessionChange) + pExist->nRecord + nRec;
    ++      pNew = (SessionChange *)sqlite3_malloc(nByte);
    ++      if( !pNew ){
    ++        sqlite3_free(pExist);
    ++        return SQLITE_NOMEM;
    ++      }
    ++      memset(pNew, 0, sizeof(SessionChange));
    ++      pNew->bIndirect = (bIndirect && pExist->bIndirect);
    ++      aCsr = pNew->aRecord = (u8 *)&pNew[1];
    ++
    ++      if( op1==SQLITE_INSERT ){             /* INSERT + UPDATE */
    ++        u8 *a1 = aRec;
    ++        assert( op2==SQLITE_UPDATE );
    ++        pNew->op = SQLITE_INSERT;
    ++        if( bPatchset==0 ) sessionSkipRecord(&a1, pTab->nCol);
    ++        sessionMergeRecord(&aCsr, pTab->nCol, aExist, a1);
    ++      }else if( op1==SQLITE_DELETE ){       /* DELETE + INSERT */
    ++        assert( op2==SQLITE_INSERT );
    ++        pNew->op = SQLITE_UPDATE;
    ++        if( bPatchset ){
    ++          memcpy(aCsr, aRec, nRec);
    ++          aCsr += nRec;
    ++        }else{
    ++          if( 0==sessionMergeUpdate(&aCsr, pTab, bPatchset, aExist, 0,aRec,0) ){
    ++            sqlite3_free(pNew);
    ++            pNew = 0;
    ++          }
    ++        }
    ++      }else if( op2==SQLITE_UPDATE ){       /* UPDATE + UPDATE */
    ++        u8 *a1 = aExist;
    ++        u8 *a2 = aRec;
    ++        assert( op1==SQLITE_UPDATE );
    ++        if( bPatchset==0 ){
    ++          sessionSkipRecord(&a1, pTab->nCol);
    ++          sessionSkipRecord(&a2, pTab->nCol);
    ++        }
    ++        pNew->op = SQLITE_UPDATE;
    ++        if( 0==sessionMergeUpdate(&aCsr, pTab, bPatchset, aRec, aExist,a1,a2) ){
    ++          sqlite3_free(pNew);
    ++          pNew = 0;
    ++        }
    ++      }else{                                /* UPDATE + DELETE */
    ++        assert( op1==SQLITE_UPDATE && op2==SQLITE_DELETE );
    ++        pNew->op = SQLITE_DELETE;
    ++        if( bPatchset ){
    ++          memcpy(aCsr, aRec, nRec);
    ++          aCsr += nRec;
    ++        }else{
    ++          sessionMergeRecord(&aCsr, pTab->nCol, aRec, aExist);
    ++        }
    ++      }
    ++
    ++      if( pNew ){
    ++        pNew->nRecord = (int)(aCsr - pNew->aRecord);
    ++      }
    ++      sqlite3_free(pExist);
    ++    }
    ++  }
    ++
    ++  *ppNew = pNew;
    ++  return SQLITE_OK;
    ++}
    ++
    ++/*
    ++** Add all changes in the changeset traversed by the iterator passed as
    ++** the first argument to the changegroup hash tables.
    ++*/
    ++static int sessionChangesetToHash(
    ++  sqlite3_changeset_iter *pIter,   /* Iterator to read from */
    ++  sqlite3_changegroup *pGrp        /* Changegroup object to add changeset to */
    ++){
    ++  u8 *aRec;
    ++  int nRec;
    ++  int rc = SQLITE_OK;
    ++  SessionTable *pTab = 0;
    ++
    ++
    ++  while( SQLITE_ROW==sessionChangesetNext(pIter, &aRec, &nRec) ){
    ++    const char *zNew;
    ++    int nCol;
    ++    int op;
    ++    int iHash;
    ++    int bIndirect;
    ++    SessionChange *pChange;
    ++    SessionChange *pExist = 0;
    ++    SessionChange **pp;
    ++
    ++    if( pGrp->pList==0 ){
    ++      pGrp->bPatch = pIter->bPatchset;
    ++    }else if( pIter->bPatchset!=pGrp->bPatch ){
    ++      rc = SQLITE_ERROR;
    ++      break;
    ++    }
    ++
    ++    sqlite3changeset_op(pIter, &zNew, &nCol, &op, &bIndirect);
    ++    if( !pTab || sqlite3_stricmp(zNew, pTab->zName) ){
    ++      /* Search the list for a matching table */
    ++      int nNew = (int)strlen(zNew);
    ++      u8 *abPK;
    ++
    ++      sqlite3changeset_pk(pIter, &abPK, 0);
    ++      for(pTab = pGrp->pList; pTab; pTab=pTab->pNext){
    ++        if( 0==sqlite3_strnicmp(pTab->zName, zNew, nNew+1) ) break;
    ++      }
    ++      if( !pTab ){
    ++        SessionTable **ppTab;
    ++
    ++        pTab = sqlite3_malloc(sizeof(SessionTable) + nCol + nNew+1);
    ++        if( !pTab ){
    ++          rc = SQLITE_NOMEM;
    ++          break;
    ++        }
    ++        memset(pTab, 0, sizeof(SessionTable));
    ++        pTab->nCol = nCol;
    ++        pTab->abPK = (u8*)&pTab[1];
    ++        memcpy(pTab->abPK, abPK, nCol);
    ++        pTab->zName = (char*)&pTab->abPK[nCol];
    ++        memcpy(pTab->zName, zNew, nNew+1);
    ++
    ++        /* The new object must be linked on to the end of the list, not
    ++        ** simply added to the start of it. This is to ensure that the
    ++        ** tables within the output of sqlite3changegroup_output() are in 
    ++        ** the right order.  */
    ++        for(ppTab=&pGrp->pList; *ppTab; ppTab=&(*ppTab)->pNext);
    ++        *ppTab = pTab;
    ++      }else if( pTab->nCol!=nCol || memcmp(pTab->abPK, abPK, nCol) ){
    ++        rc = SQLITE_SCHEMA;
    ++        break;
    ++      }
    ++    }
    ++
    ++    if( sessionGrowHash(pIter->bPatchset, pTab) ){
    ++      rc = SQLITE_NOMEM;
    ++      break;
    ++    }
    ++    iHash = sessionChangeHash(
    ++        pTab, (pIter->bPatchset && op==SQLITE_DELETE), aRec, pTab->nChange
    ++    );
    ++
    ++    /* Search for existing entry. If found, remove it from the hash table. 
    ++    ** Code below may link it back in.
    ++    */
    ++    for(pp=&pTab->apChange[iHash]; *pp; pp=&(*pp)->pNext){
    ++      int bPkOnly1 = 0;
    ++      int bPkOnly2 = 0;
    ++      if( pIter->bPatchset ){
    ++        bPkOnly1 = (*pp)->op==SQLITE_DELETE;
    ++        bPkOnly2 = op==SQLITE_DELETE;
    ++      }
    ++      if( sessionChangeEqual(pTab, bPkOnly1, (*pp)->aRecord, bPkOnly2, aRec) ){
    ++        pExist = *pp;
    ++        *pp = (*pp)->pNext;
    ++        pTab->nEntry--;
    ++        break;
    ++      }
    ++    }
    ++
    ++    rc = sessionChangeMerge(pTab, 
    ++        pIter->bPatchset, pExist, op, bIndirect, aRec, nRec, &pChange
    ++    );
    ++    if( rc ) break;
    ++    if( pChange ){
    ++      pChange->pNext = pTab->apChange[iHash];
    ++      pTab->apChange[iHash] = pChange;
    ++      pTab->nEntry++;
    ++    }
    ++  }
    ++
    ++  if( rc==SQLITE_OK ) rc = pIter->rc;
    ++  return rc;
    ++}
    ++
    ++/*
    ++** Serialize a changeset (or patchset) based on all changesets (or patchsets)
    ++** added to the changegroup object passed as the first argument.
    ++**
    ++** If xOutput is not NULL, then the changeset/patchset is returned to the
    ++** user via one or more calls to xOutput, as with the other streaming
    ++** interfaces. 
    ++**
    ++** Or, if xOutput is NULL, then (*ppOut) is populated with a pointer to a
    ++** buffer containing the output changeset before this function returns. In
    ++** this case (*pnOut) is set to the size of the output buffer in bytes. It
    ++** is the responsibility of the caller to free the output buffer using
    ++** sqlite3_free() when it is no longer required.
    ++**
    ++** If successful, SQLITE_OK is returned. Or, if an error occurs, an SQLite
    ++** error code. If an error occurs and xOutput is NULL, (*ppOut) and (*pnOut)
    ++** are both set to 0 before returning.
    ++*/
    ++static int sessionChangegroupOutput(
    ++  sqlite3_changegroup *pGrp,
    ++  int (*xOutput)(void *pOut, const void *pData, int nData),
    ++  void *pOut,
    ++  int *pnOut,
    ++  void **ppOut
    ++){
    ++  int rc = SQLITE_OK;
    ++  SessionBuffer buf = {0, 0, 0};
    ++  SessionTable *pTab;
    ++  assert( xOutput==0 || (ppOut==0 && pnOut==0) );
    ++
    ++  /* Create the serialized output changeset based on the contents of the
    ++  ** hash tables attached to the SessionTable objects in list p->pList. 
    ++  */
    ++  for(pTab=pGrp->pList; rc==SQLITE_OK && pTab; pTab=pTab->pNext){
    ++    int i;
    ++    if( pTab->nEntry==0 ) continue;
    ++
    ++    sessionAppendTableHdr(&buf, pGrp->bPatch, pTab, &rc);
    ++    for(i=0; i<pTab->nChange; i++){
    ++      SessionChange *p;
    ++      for(p=pTab->apChange[i]; p; p=p->pNext){
    ++        sessionAppendByte(&buf, p->op, &rc);
    ++        sessionAppendByte(&buf, p->bIndirect, &rc);
    ++        sessionAppendBlob(&buf, p->aRecord, p->nRecord, &rc);
    ++      }
    ++    }
    ++
    ++    if( rc==SQLITE_OK && xOutput && buf.nBuf>=SESSIONS_STRM_CHUNK_SIZE ){
    ++      rc = xOutput(pOut, buf.aBuf, buf.nBuf);
    ++      buf.nBuf = 0;
    ++    }
    ++  }
    ++
    ++  if( rc==SQLITE_OK ){
    ++    if( xOutput ){
    ++      if( buf.nBuf>0 ) rc = xOutput(pOut, buf.aBuf, buf.nBuf);
    ++    }else{
    ++      *ppOut = buf.aBuf;
    ++      *pnOut = buf.nBuf;
    ++      buf.aBuf = 0;
    ++    }
    ++  }
    ++  sqlite3_free(buf.aBuf);
    ++
    ++  return rc;
    ++}
    ++
    ++/*
    ++** Allocate a new, empty, sqlite3_changegroup.
    ++*/
    ++SQLITE_API int sqlite3changegroup_new(sqlite3_changegroup **pp){
    ++  int rc = SQLITE_OK;             /* Return code */
    ++  sqlite3_changegroup *p;         /* New object */
    ++  p = (sqlite3_changegroup*)sqlite3_malloc(sizeof(sqlite3_changegroup));
    ++  if( p==0 ){
    ++    rc = SQLITE_NOMEM;
    ++  }else{
    ++    memset(p, 0, sizeof(sqlite3_changegroup));
    ++  }
    ++  *pp = p;
    ++  return rc;
    ++}
    ++
    ++/*
    ++** Add the changeset currently stored in buffer pData, size nData bytes,
    ++** to changeset-group p.
    ++*/
    ++SQLITE_API int sqlite3changegroup_add(sqlite3_changegroup *pGrp, int nData, void *pData){
    ++  sqlite3_changeset_iter *pIter;  /* Iterator opened on pData/nData */
    ++  int rc;                         /* Return code */
    ++
    ++  rc = sqlite3changeset_start(&pIter, nData, pData);
    ++  if( rc==SQLITE_OK ){
    ++    rc = sessionChangesetToHash(pIter, pGrp);
    ++  }
    ++  sqlite3changeset_finalize(pIter);
    ++  return rc;
    ++}
    ++
    ++/*
    ++** Obtain a buffer containing a changeset representing the concatenation
    ++** of all changesets added to the group so far.
    ++*/
    ++SQLITE_API int sqlite3changegroup_output(
    ++    sqlite3_changegroup *pGrp,
    ++    int *pnData,
    ++    void **ppData
    ++){
    ++  return sessionChangegroupOutput(pGrp, 0, 0, pnData, ppData);
    ++}
    ++
    ++/*
    ++** Streaming versions of changegroup_add().
    ++*/
    ++SQLITE_API int sqlite3changegroup_add_strm(
    ++  sqlite3_changegroup *pGrp,
    ++  int (*xInput)(void *pIn, void *pData, int *pnData),
    ++  void *pIn
    ++){
    ++  sqlite3_changeset_iter *pIter;  /* Iterator opened on pData/nData */
    ++  int rc;                         /* Return code */
    ++
    ++  rc = sqlite3changeset_start_strm(&pIter, xInput, pIn);
    ++  if( rc==SQLITE_OK ){
    ++    rc = sessionChangesetToHash(pIter, pGrp);
    ++  }
    ++  sqlite3changeset_finalize(pIter);
    ++  return rc;
    ++}
    ++
    ++/*
    ++** Streaming versions of changegroup_output().
    ++*/
    ++SQLITE_API int sqlite3changegroup_output_strm(
    ++  sqlite3_changegroup *pGrp,
    ++  int (*xOutput)(void *pOut, const void *pData, int nData), 
    ++  void *pOut
    ++){
    ++  return sessionChangegroupOutput(pGrp, xOutput, pOut, 0, 0);
    ++}
    ++
    ++/*
    ++** Delete a changegroup object.
    ++*/
    ++SQLITE_API void sqlite3changegroup_delete(sqlite3_changegroup *pGrp){
    ++  if( pGrp ){
    ++    sessionDeleteTable(pGrp->pList);
    ++    sqlite3_free(pGrp);
    ++  }
    ++}
    ++
    ++/* 
    ++** Combine two changesets together.
    ++*/
    ++SQLITE_API int sqlite3changeset_concat(
    ++  int nLeft,                      /* Number of bytes in lhs input */
    ++  void *pLeft,                    /* Lhs input changeset */
    ++  int nRight                      /* Number of bytes in rhs input */,
    ++  void *pRight,                   /* Rhs input changeset */
    ++  int *pnOut,                     /* OUT: Number of bytes in output changeset */
    ++  void **ppOut                    /* OUT: changeset (left <concat> right) */
    ++){
    ++  sqlite3_changegroup *pGrp;
    ++  int rc;
    ++
    ++  rc = sqlite3changegroup_new(&pGrp);
    ++  if( rc==SQLITE_OK ){
    ++    rc = sqlite3changegroup_add(pGrp, nLeft, pLeft);
    ++  }
    ++  if( rc==SQLITE_OK ){
    ++    rc = sqlite3changegroup_add(pGrp, nRight, pRight);
    ++  }
    ++  if( rc==SQLITE_OK ){
    ++    rc = sqlite3changegroup_output(pGrp, pnOut, ppOut);
    ++  }
    ++  sqlite3changegroup_delete(pGrp);
    ++
    ++  return rc;
    ++}
    ++
    ++/*
    ++** Streaming version of sqlite3changeset_concat().
    ++*/
    ++SQLITE_API int sqlite3changeset_concat_strm(
    ++  int (*xInputA)(void *pIn, void *pData, int *pnData),
    ++  void *pInA,
    ++  int (*xInputB)(void *pIn, void *pData, int *pnData),
    ++  void *pInB,
    ++  int (*xOutput)(void *pOut, const void *pData, int nData),
    ++  void *pOut
    ++){
    ++  sqlite3_changegroup *pGrp;
    ++  int rc;
    ++
    ++  rc = sqlite3changegroup_new(&pGrp);
    ++  if( rc==SQLITE_OK ){
    ++    rc = sqlite3changegroup_add_strm(pGrp, xInputA, pInA);
    ++  }
    ++  if( rc==SQLITE_OK ){
    ++    rc = sqlite3changegroup_add_strm(pGrp, xInputB, pInB);
    ++  }
    ++  if( rc==SQLITE_OK ){
    ++    rc = sqlite3changegroup_output_strm(pGrp, xOutput, pOut);
    ++  }
    ++  sqlite3changegroup_delete(pGrp);
    ++
    ++  return rc;
    ++}
    ++
    ++#endif /* SQLITE_ENABLE_SESSION && SQLITE_ENABLE_PREUPDATE_HOOK */
    ++
    ++/************** End of sqlite3session.c **************************************/
    ++/************** Begin file json1.c *******************************************/
    ++/*
    ++** 2015-08-12
    ++**
    ++** 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 SQLite extension implements JSON functions.  The interface is
    ++** modeled after MySQL JSON functions:
    ++**
    ++**     https://dev.mysql.com/doc/refman/5.7/en/json.html
    ++**
    ++** For the time being, all JSON is stored as pure text.  (We might add
    ++** a JSONB type in the future which stores a binary encoding of JSON in
    ++** a BLOB, but there is no support for JSONB in the current implementation.
    ++** This implementation parses JSON text at 250 MB/s, so it is hard to see
    ++** how JSONB might improve on that.)
    ++*/
    ++#if !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_JSON1)
    ++#if !defined(SQLITEINT_H)
    ++/* #include "sqlite3ext.h" */
    ++#endif
    ++SQLITE_EXTENSION_INIT1
    ++/* #include <assert.h> */
    ++/* #include <string.h> */
    ++/* #include <stdlib.h> */
    ++/* #include <stdarg.h> */
    ++
    ++/* Mark a function parameter as unused, to suppress nuisance compiler
    ++** warnings. */
    ++#ifndef UNUSED_PARAM
    ++# define UNUSED_PARAM(X)  (void)(X)
    ++#endif
    ++
    ++#ifndef LARGEST_INT64
    ++# define LARGEST_INT64  (0xffffffff|(((sqlite3_int64)0x7fffffff)<<32))
    ++# define SMALLEST_INT64 (((sqlite3_int64)-1) - LARGEST_INT64)
    ++#endif
    ++
    ++/*
    ++** Versions of isspace(), isalnum() and isdigit() to which it is safe
    ++** to pass signed char values.
    ++*/
    ++#ifdef sqlite3Isdigit
    ++   /* Use the SQLite core versions if this routine is part of the
    ++   ** SQLite amalgamation */
    ++#  define safe_isdigit(x)  sqlite3Isdigit(x)
    ++#  define safe_isalnum(x)  sqlite3Isalnum(x)
    ++#  define safe_isxdigit(x) sqlite3Isxdigit(x)
    ++#else
    ++   /* Use the standard library for separate compilation */
    ++#include <ctype.h>  /* amalgamator: keep */
    ++#  define safe_isdigit(x)  isdigit((unsigned char)(x))
    ++#  define safe_isalnum(x)  isalnum((unsigned char)(x))
    ++#  define safe_isxdigit(x) isxdigit((unsigned char)(x))
    ++#endif
    ++
    ++/*
    ++** Growing our own isspace() routine this way is twice as fast as
    ++** the library isspace() function, resulting in a 7% overall performance
    ++** increase for the parser.  (Ubuntu14.10 gcc 4.8.4 x64 with -Os).
    ++*/
    ++static const char jsonIsSpace[] = {
    ++  0, 0, 0, 0, 0, 0, 0, 0,     0, 1, 1, 0, 0, 1, 0, 0,
    ++  0, 0, 0, 0, 0, 0, 0, 0,     0, 0, 0, 0, 0, 0, 0, 0,
    ++  1, 0, 0, 0, 0, 0, 0, 0,     0, 0, 0, 0, 0, 0, 0, 0,
    ++  0, 0, 0, 0, 0, 0, 0, 0,     0, 0, 0, 0, 0, 0, 0, 0,
    ++  0, 0, 0, 0, 0, 0, 0, 0,     0, 0, 0, 0, 0, 0, 0, 0,
    ++  0, 0, 0, 0, 0, 0, 0, 0,     0, 0, 0, 0, 0, 0, 0, 0,
    ++  0, 0, 0, 0, 0, 0, 0, 0,     0, 0, 0, 0, 0, 0, 0, 0,
    ++  0, 0, 0, 0, 0, 0, 0, 0,     0, 0, 0, 0, 0, 0, 0, 0,
    ++  0, 0, 0, 0, 0, 0, 0, 0,     0, 0, 0, 0, 0, 0, 0, 0,
    ++  0, 0, 0, 0, 0, 0, 0, 0,     0, 0, 0, 0, 0, 0, 0, 0,
    ++  0, 0, 0, 0, 0, 0, 0, 0,     0, 0, 0, 0, 0, 0, 0, 0,
    ++  0, 0, 0, 0, 0, 0, 0, 0,     0, 0, 0, 0, 0, 0, 0, 0,
    ++  0, 0, 0, 0, 0, 0, 0, 0,     0, 0, 0, 0, 0, 0, 0, 0,
    ++  0, 0, 0, 0, 0, 0, 0, 0,     0, 0, 0, 0, 0, 0, 0, 0,
    ++  0, 0, 0, 0, 0, 0, 0, 0,     0, 0, 0, 0, 0, 0, 0, 0,
    ++  0, 0, 0, 0, 0, 0, 0, 0,     0, 0, 0, 0, 0, 0, 0, 0,
    ++};
    ++#define safe_isspace(x) (jsonIsSpace[(unsigned char)x])
    ++
    ++#ifndef SQLITE_AMALGAMATION
    ++  /* Unsigned integer types.  These are already defined in the sqliteInt.h,
    ++  ** but the definitions need to be repeated for separate compilation. */
    ++  typedef sqlite3_uint64 u64;
    ++  typedef unsigned int u32;
    ++  typedef unsigned short int u16;
    ++  typedef unsigned char u8;
    ++#endif
    ++
    ++/* Objects */
    ++typedef struct JsonString JsonString;
    ++typedef struct JsonNode JsonNode;
    ++typedef struct JsonParse JsonParse;
    ++
    ++/* An instance of this object represents a JSON string
    ++** under construction.  Really, this is a generic string accumulator
    ++** that can be and is used to create strings other than JSON.
    ++*/
    ++struct JsonString {
    ++  sqlite3_context *pCtx;   /* Function context - put error messages here */
    ++  char *zBuf;              /* Append JSON content here */
    ++  u64 nAlloc;              /* Bytes of storage available in zBuf[] */
    ++  u64 nUsed;               /* Bytes of zBuf[] currently used */
    ++  u8 bStatic;              /* True if zBuf is static space */
    ++  u8 bErr;                 /* True if an error has been encountered */
    ++  char zSpace[100];        /* Initial static space */
    ++};
    ++
    ++/* JSON type values
    ++*/
    ++#define JSON_NULL     0
    ++#define JSON_TRUE     1
    ++#define JSON_FALSE    2
    ++#define JSON_INT      3
    ++#define JSON_REAL     4
    ++#define JSON_STRING   5
    ++#define JSON_ARRAY    6
    ++#define JSON_OBJECT   7
    ++
    ++/* The "subtype" set for JSON values */
    ++#define JSON_SUBTYPE  74    /* Ascii for "J" */
    ++
    ++/*
    ++** Names of the various JSON types:
    ++*/
    ++static const char * const jsonType[] = {
    ++  "null", "true", "false", "integer", "real", "text", "array", "object"
    ++};
    ++
    ++/* Bit values for the JsonNode.jnFlag field
    ++*/
    ++#define JNODE_RAW     0x01         /* Content is raw, not JSON encoded */
    ++#define JNODE_ESCAPE  0x02         /* Content is text with \ escapes */
    ++#define JNODE_REMOVE  0x04         /* Do not output */
    ++#define JNODE_REPLACE 0x08         /* Replace with JsonNode.u.iReplace */
    ++#define JNODE_PATCH   0x10         /* Patch with JsonNode.u.pPatch */
    ++#define JNODE_APPEND  0x20         /* More ARRAY/OBJECT entries at u.iAppend */
    ++#define JNODE_LABEL   0x40         /* Is a label of an object */
    ++
    ++
    ++/* A single node of parsed JSON
    ++*/
    ++struct JsonNode {
    ++  u8 eType;              /* One of the JSON_ type values */
    ++  u8 jnFlags;            /* JNODE flags */
    ++  u32 n;                 /* Bytes of content, or number of sub-nodes */
    ++  union {
    ++    const char *zJContent; /* Content for INT, REAL, and STRING */
    ++    u32 iAppend;           /* More terms for ARRAY and OBJECT */
    ++    u32 iKey;              /* Key for ARRAY objects in json_tree() */
    ++    u32 iReplace;          /* Replacement content for JNODE_REPLACE */
    ++    JsonNode *pPatch;      /* Node chain of patch for JNODE_PATCH */
    ++  } u;
    ++};
    ++
    ++/* A completely parsed JSON string
    ++*/
    ++struct JsonParse {
    ++  u32 nNode;         /* Number of slots of aNode[] used */
    ++  u32 nAlloc;        /* Number of slots of aNode[] allocated */
    ++  JsonNode *aNode;   /* Array of nodes containing the parse */
    ++  const char *zJson; /* Original JSON string */
    ++  u32 *aUp;          /* Index of parent of each node */
    ++  u8 oom;            /* Set to true if out of memory */
    ++  u8 nErr;           /* Number of errors seen */
    ++  u16 iDepth;        /* Nesting depth */
    ++  int nJson;         /* Length of the zJson string in bytes */
    ++};
    ++
    ++/*
    ++** Maximum nesting depth of JSON for this implementation.
    ++**
    ++** This limit is needed to avoid a stack overflow in the recursive
    ++** descent parser.  A depth of 2000 is far deeper than any sane JSON
    ++** should go.
    ++*/
    ++#define JSON_MAX_DEPTH  2000
    ++
    ++/**************************************************************************
    ++** Utility routines for dealing with JsonString objects
    ++**************************************************************************/
    ++
    ++/* Set the JsonString object to an empty string
    ++*/
    ++static void jsonZero(JsonString *p){
    ++  p->zBuf = p->zSpace;
    ++  p->nAlloc = sizeof(p->zSpace);
    ++  p->nUsed = 0;
    ++  p->bStatic = 1;
    ++}
    ++
    ++/* Initialize the JsonString object
    ++*/
    ++static void jsonInit(JsonString *p, sqlite3_context *pCtx){
    ++  p->pCtx = pCtx;
    ++  p->bErr = 0;
    ++  jsonZero(p);
    ++}
    ++
    ++
    ++/* Free all allocated memory and reset the JsonString object back to its
    ++** initial state.
    ++*/
    ++static void jsonReset(JsonString *p){
    ++  if( !p->bStatic ) sqlite3_free(p->zBuf);
    ++  jsonZero(p);
    ++}
    ++
    ++
    ++/* Report an out-of-memory (OOM) condition 
    ++*/
    ++static void jsonOom(JsonString *p){
    ++  p->bErr = 1;
    ++  sqlite3_result_error_nomem(p->pCtx);
    ++  jsonReset(p);
    ++}
    ++
    ++/* Enlarge pJson->zBuf so that it can hold at least N more bytes.
    ++** Return zero on success.  Return non-zero on an OOM error
    ++*/
    ++static int jsonGrow(JsonString *p, u32 N){
    ++  u64 nTotal = N<p->nAlloc ? p->nAlloc*2 : p->nAlloc+N+10;
    ++  char *zNew;
    ++  if( p->bStatic ){
    ++    if( p->bErr ) return 1;
    ++    zNew = sqlite3_malloc64(nTotal);
    ++    if( zNew==0 ){
    ++      jsonOom(p);
    ++      return SQLITE_NOMEM;
    ++    }
    ++    memcpy(zNew, p->zBuf, (size_t)p->nUsed);
    ++    p->zBuf = zNew;
    ++    p->bStatic = 0;
    ++  }else{
    ++    zNew = sqlite3_realloc64(p->zBuf, nTotal);
    ++    if( zNew==0 ){
    ++      jsonOom(p);
    ++      return SQLITE_NOMEM;
    ++    }
    ++    p->zBuf = zNew;
    ++  }
    ++  p->nAlloc = nTotal;
    ++  return SQLITE_OK;
    ++}
    ++
    ++/* Append N bytes from zIn onto the end of the JsonString string.
    ++*/
    ++static void jsonAppendRaw(JsonString *p, const char *zIn, u32 N){
    ++  if( (N+p->nUsed >= p->nAlloc) && jsonGrow(p,N)!=0 ) return;
    ++  memcpy(p->zBuf+p->nUsed, zIn, N);
    ++  p->nUsed += N;
    ++}
    ++
    ++/* Append formatted text (not to exceed N bytes) to the JsonString.
    ++*/
    ++static void jsonPrintf(int N, JsonString *p, const char *zFormat, ...){
    ++  va_list ap;
    ++  if( (p->nUsed + N >= p->nAlloc) && jsonGrow(p, N) ) return;
    ++  va_start(ap, zFormat);
    ++  sqlite3_vsnprintf(N, p->zBuf+p->nUsed, zFormat, ap);
    ++  va_end(ap);
    ++  p->nUsed += (int)strlen(p->zBuf+p->nUsed);
    ++}
    ++
    ++/* Append a single character
    ++*/
    ++static void jsonAppendChar(JsonString *p, char c){
    ++  if( p->nUsed>=p->nAlloc && jsonGrow(p,1)!=0 ) return;
    ++  p->zBuf[p->nUsed++] = c;
    ++}
    ++
    ++/* Append a comma separator to the output buffer, if the previous
    ++** character is not '[' or '{'.
    ++*/
    ++static void jsonAppendSeparator(JsonString *p){
    ++  char c;
    ++  if( p->nUsed==0 ) return;
    ++  c = p->zBuf[p->nUsed-1];
    ++  if( c!='[' && c!='{' ) jsonAppendChar(p, ',');
    ++}
    ++
    ++/* Append the N-byte string in zIn to the end of the JsonString string
    ++** under construction.  Enclose the string in "..." and escape
    ++** any double-quotes or backslash characters contained within the
    ++** string.
    ++*/
    ++static void jsonAppendString(JsonString *p, const char *zIn, u32 N){
    ++  u32 i;
    ++  if( (N+p->nUsed+2 >= p->nAlloc) && jsonGrow(p,N+2)!=0 ) return;
    ++  p->zBuf[p->nUsed++] = '"';
    ++  for(i=0; i<N; i++){
    ++    unsigned char c = ((unsigned const char*)zIn)[i];
    ++    if( c=='"' || c=='\\' ){
    ++      json_simple_escape:
    ++      if( (p->nUsed+N+3-i > p->nAlloc) && jsonGrow(p,N+3-i)!=0 ) return;
    ++      p->zBuf[p->nUsed++] = '\\';
    ++    }else if( c<=0x1f ){
    ++      static const char aSpecial[] = {
    ++         0, 0, 0, 0, 0, 0, 0, 0, 'b', 't', 'n', 0, 'f', 'r', 0, 0,
    ++         0, 0, 0, 0, 0, 0, 0, 0,   0,   0,   0, 0,   0,   0, 0, 0
    ++      };
    ++      assert( sizeof(aSpecial)==32 );
    ++      assert( aSpecial['\b']=='b' );
    ++      assert( aSpecial['\f']=='f' );
    ++      assert( aSpecial['\n']=='n' );
    ++      assert( aSpecial['\r']=='r' );
    ++      assert( aSpecial['\t']=='t' );
    ++      if( aSpecial[c] ){
    ++        c = aSpecial[c];
    ++        goto json_simple_escape;
    ++      }
    ++      if( (p->nUsed+N+7+i > p->nAlloc) && jsonGrow(p,N+7-i)!=0 ) return;
    ++      p->zBuf[p->nUsed++] = '\\';
    ++      p->zBuf[p->nUsed++] = 'u';
    ++      p->zBuf[p->nUsed++] = '0';
    ++      p->zBuf[p->nUsed++] = '0';
    ++      p->zBuf[p->nUsed++] = '0' + (c>>4);
    ++      c = "0123456789abcdef"[c&0xf];
    ++    }
    ++    p->zBuf[p->nUsed++] = c;
    ++  }
    ++  p->zBuf[p->nUsed++] = '"';
    ++  assert( p->nUsed<p->nAlloc );
    ++}
    ++
    ++/*
    ++** Append a function parameter value to the JSON string under 
    ++** construction.
    ++*/
    ++static void jsonAppendValue(
    ++  JsonString *p,                 /* Append to this JSON string */
    ++  sqlite3_value *pValue          /* Value to append */
    ++){
    ++  switch( sqlite3_value_type(pValue) ){
    ++    case SQLITE_NULL: {
    ++      jsonAppendRaw(p, "null", 4);
    ++      break;
    ++    }
    ++    case SQLITE_INTEGER:
    ++    case SQLITE_FLOAT: {
    ++      const char *z = (const char*)sqlite3_value_text(pValue);
    ++      u32 n = (u32)sqlite3_value_bytes(pValue);
    ++      jsonAppendRaw(p, z, n);
    ++      break;
    ++    }
    ++    case SQLITE_TEXT: {
    ++      const char *z = (const char*)sqlite3_value_text(pValue);
    ++      u32 n = (u32)sqlite3_value_bytes(pValue);
    ++      if( sqlite3_value_subtype(pValue)==JSON_SUBTYPE ){
    ++        jsonAppendRaw(p, z, n);
    ++      }else{
    ++        jsonAppendString(p, z, n);
    ++      }
    ++      break;
    ++    }
    ++    default: {
    ++      if( p->bErr==0 ){
    ++        sqlite3_result_error(p->pCtx, "JSON cannot hold BLOB values", -1);
    ++        p->bErr = 2;
    ++        jsonReset(p);
    ++      }
    ++      break;
    ++    }
    ++  }
    ++}
    ++
    ++
    ++/* Make the JSON in p the result of the SQL function.
    ++*/
    ++static void jsonResult(JsonString *p){
    ++  if( p->bErr==0 ){
    ++    sqlite3_result_text64(p->pCtx, p->zBuf, p->nUsed, 
    ++                          p->bStatic ? SQLITE_TRANSIENT : sqlite3_free,
    ++                          SQLITE_UTF8);
    ++    jsonZero(p);
    ++  }
    ++  assert( p->bStatic );
    ++}
    ++
    ++/**************************************************************************
    ++** Utility routines for dealing with JsonNode and JsonParse objects
    ++**************************************************************************/
    ++
    ++/*
    ++** Return the number of consecutive JsonNode slots need to represent
    ++** the parsed JSON at pNode.  The minimum answer is 1.  For ARRAY and
    ++** OBJECT types, the number might be larger.
    ++**
    ++** Appended elements are not counted.  The value returned is the number
    ++** by which the JsonNode counter should increment in order to go to the
    ++** next peer value.
    ++*/
    ++static u32 jsonNodeSize(JsonNode *pNode){
    ++  return pNode->eType>=JSON_ARRAY ? pNode->n+1 : 1;
    ++}
    ++
    ++/*
    ++** Reclaim all memory allocated by a JsonParse object.  But do not
    ++** delete the JsonParse object itself.
    ++*/
    ++static void jsonParseReset(JsonParse *pParse){
    ++  sqlite3_free(pParse->aNode);
    ++  pParse->aNode = 0;
    ++  pParse->nNode = 0;
    ++  pParse->nAlloc = 0;
    ++  sqlite3_free(pParse->aUp);
    ++  pParse->aUp = 0;
    ++}
    ++
    ++/*
    ++** Free a JsonParse object that was obtained from sqlite3_malloc().
    ++*/
    ++static void jsonParseFree(JsonParse *pParse){
    ++  jsonParseReset(pParse);
    ++  sqlite3_free(pParse);
    ++}
    ++
    ++/*
    ++** Convert the JsonNode pNode into a pure JSON string and
    ++** append to pOut.  Subsubstructure is also included.  Return
    ++** the number of JsonNode objects that are encoded.
    ++*/
    ++static void jsonRenderNode(
    ++  JsonNode *pNode,               /* The node to render */
    ++  JsonString *pOut,              /* Write JSON here */
    ++  sqlite3_value **aReplace       /* Replacement values */
    ++){
    ++  if( pNode->jnFlags & (JNODE_REPLACE|JNODE_PATCH) ){
    ++    if( pNode->jnFlags & JNODE_REPLACE ){
    ++      jsonAppendValue(pOut, aReplace[pNode->u.iReplace]);
    ++      return;
    ++    }
    ++    pNode = pNode->u.pPatch;
    ++  }
    ++  switch( pNode->eType ){
    ++    default: {
    ++      assert( pNode->eType==JSON_NULL );
    ++      jsonAppendRaw(pOut, "null", 4);
    ++      break;
    ++    }
    ++    case JSON_TRUE: {
    ++      jsonAppendRaw(pOut, "true", 4);
    ++      break;
    ++    }
    ++    case JSON_FALSE: {
    ++      jsonAppendRaw(pOut, "false", 5);
    ++      break;
    ++    }
    ++    case JSON_STRING: {
    ++      if( pNode->jnFlags & JNODE_RAW ){
    ++        jsonAppendString(pOut, pNode->u.zJContent, pNode->n);
    ++        break;
    ++      }
    ++      /* Fall through into the next case */
    ++    }
    ++    case JSON_REAL:
    ++    case JSON_INT: {
    ++      jsonAppendRaw(pOut, pNode->u.zJContent, pNode->n);
    ++      break;
    ++    }
    ++    case JSON_ARRAY: {
    ++      u32 j = 1;
    ++      jsonAppendChar(pOut, '[');
    ++      for(;;){
    ++        while( j<=pNode->n ){
    ++          if( (pNode[j].jnFlags & JNODE_REMOVE)==0 ){
    ++            jsonAppendSeparator(pOut);
    ++            jsonRenderNode(&pNode[j], pOut, aReplace);
    ++          }
    ++          j += jsonNodeSize(&pNode[j]);
    ++        }
    ++        if( (pNode->jnFlags & JNODE_APPEND)==0 ) break;
    ++        pNode = &pNode[pNode->u.iAppend];
    ++        j = 1;
    ++      }
    ++      jsonAppendChar(pOut, ']');
    ++      break;
    ++    }
    ++    case JSON_OBJECT: {
    ++      u32 j = 1;
    ++      jsonAppendChar(pOut, '{');
    ++      for(;;){
    ++        while( j<=pNode->n ){
    ++          if( (pNode[j+1].jnFlags & JNODE_REMOVE)==0 ){
    ++            jsonAppendSeparator(pOut);
    ++            jsonRenderNode(&pNode[j], pOut, aReplace);
    ++            jsonAppendChar(pOut, ':');
    ++            jsonRenderNode(&pNode[j+1], pOut, aReplace);
    ++          }
    ++          j += 1 + jsonNodeSize(&pNode[j+1]);
    ++        }
    ++        if( (pNode->jnFlags & JNODE_APPEND)==0 ) break;
    ++        pNode = &pNode[pNode->u.iAppend];
    ++        j = 1;
    ++      }
    ++      jsonAppendChar(pOut, '}');
    ++      break;
    ++    }
    ++  }
    ++}
    ++
    ++/*
    ++** Return a JsonNode and all its descendents as a JSON string.
    ++*/
    ++static void jsonReturnJson(
    ++  JsonNode *pNode,            /* Node to return */
    ++  sqlite3_context *pCtx,      /* Return value for this function */
    ++  sqlite3_value **aReplace    /* Array of replacement values */
    ++){
    ++  JsonString s;
    ++  jsonInit(&s, pCtx);
    ++  jsonRenderNode(pNode, &s, aReplace);
    ++  jsonResult(&s);
    ++  sqlite3_result_subtype(pCtx, JSON_SUBTYPE);
    ++}
    ++
    ++/*
    ++** Make the JsonNode the return value of the function.
    ++*/
    ++static void jsonReturn(
    ++  JsonNode *pNode,            /* Node to return */
    ++  sqlite3_context *pCtx,      /* Return value for this function */
    ++  sqlite3_value **aReplace    /* Array of replacement values */
    ++){
    ++  switch( pNode->eType ){
    ++    default: {
    ++      assert( pNode->eType==JSON_NULL );
    ++      sqlite3_result_null(pCtx);
    ++      break;
    ++    }
    ++    case JSON_TRUE: {
    ++      sqlite3_result_int(pCtx, 1);
    ++      break;
    ++    }
    ++    case JSON_FALSE: {
    ++      sqlite3_result_int(pCtx, 0);
    ++      break;
    ++    }
    ++    case JSON_INT: {
    ++      sqlite3_int64 i = 0;
    ++      const char *z = pNode->u.zJContent;
    ++      if( z[0]=='-' ){ z++; }
    ++      while( z[0]>='0' && z[0]<='9' ){
    ++        unsigned v = *(z++) - '0';
    ++        if( i>=LARGEST_INT64/10 ){
    ++          if( i>LARGEST_INT64/10 ) goto int_as_real;
    ++          if( z[0]>='0' && z[0]<='9' ) goto int_as_real;
    ++          if( v==9 ) goto int_as_real;
    ++          if( v==8 ){
    ++            if( pNode->u.zJContent[0]=='-' ){
    ++              sqlite3_result_int64(pCtx, SMALLEST_INT64);
    ++              goto int_done;
    ++            }else{
    ++              goto int_as_real;
    ++            }
    ++          }
    ++        }
    ++        i = i*10 + v;
    ++      }
    ++      if( pNode->u.zJContent[0]=='-' ){ i = -i; }
    ++      sqlite3_result_int64(pCtx, i);
    ++      int_done:
    ++      break;
    ++      int_as_real: /* fall through to real */;
    ++    }
    ++    case JSON_REAL: {
    ++      double r;
    ++#ifdef SQLITE_AMALGAMATION
    ++      const char *z = pNode->u.zJContent;
    ++      sqlite3AtoF(z, &r, sqlite3Strlen30(z), SQLITE_UTF8);
    ++#else
    ++      r = strtod(pNode->u.zJContent, 0);
    ++#endif
    ++      sqlite3_result_double(pCtx, r);
    ++      break;
    ++    }
    ++    case JSON_STRING: {
    ++#if 0 /* Never happens because JNODE_RAW is only set by json_set(),
    ++      ** json_insert() and json_replace() and those routines do not
    ++      ** call jsonReturn() */
    ++      if( pNode->jnFlags & JNODE_RAW ){
    ++        sqlite3_result_text(pCtx, pNode->u.zJContent, pNode->n,
    ++                            SQLITE_TRANSIENT);
    ++      }else 
    ++#endif
    ++      assert( (pNode->jnFlags & JNODE_RAW)==0 );
    ++      if( (pNode->jnFlags & JNODE_ESCAPE)==0 ){
    ++        /* JSON formatted without any backslash-escapes */
    ++        sqlite3_result_text(pCtx, pNode->u.zJContent+1, pNode->n-2,
    ++                            SQLITE_TRANSIENT);
    ++      }else{
    ++        /* Translate JSON formatted string into raw text */
    ++        u32 i;
    ++        u32 n = pNode->n;
    ++        const char *z = pNode->u.zJContent;
    ++        char *zOut;
    ++        u32 j;
    ++        zOut = sqlite3_malloc( n+1 );
    ++        if( zOut==0 ){
    ++          sqlite3_result_error_nomem(pCtx);
    ++          break;
    ++        }
    ++        for(i=1, j=0; i<n-1; i++){
    ++          char c = z[i];
    ++          if( c!='\\' ){
    ++            zOut[j++] = c;
    ++          }else{
    ++            c = z[++i];
    ++            if( c=='u' ){
    ++              u32 v = 0, k;
    ++              for(k=0; k<4; i++, k++){
    ++                assert( i<n-2 );
    ++                c = z[i+1];
    ++                assert( safe_isxdigit(c) );
    ++                if( c<='9' ) v = v*16 + c - '0';
    ++                else if( c<='F' ) v = v*16 + c - 'A' + 10;
    ++                else v = v*16 + c - 'a' + 10;
    ++              }
    ++              if( v==0 ) break;
    ++              if( v<=0x7f ){
    ++                zOut[j++] = (char)v;
    ++              }else if( v<=0x7ff ){
    ++                zOut[j++] = (char)(0xc0 | (v>>6));
    ++                zOut[j++] = 0x80 | (v&0x3f);
    ++              }else{
    ++                zOut[j++] = (char)(0xe0 | (v>>12));
    ++                zOut[j++] = 0x80 | ((v>>6)&0x3f);
    ++                zOut[j++] = 0x80 | (v&0x3f);
    ++              }
    ++            }else{
    ++              if( c=='b' ){
    ++                c = '\b';
    ++              }else if( c=='f' ){
    ++                c = '\f';
    ++              }else if( c=='n' ){
    ++                c = '\n';
    ++              }else if( c=='r' ){
    ++                c = '\r';
    ++              }else if( c=='t' ){
    ++                c = '\t';
    ++              }
    ++              zOut[j++] = c;
    ++            }
    ++          }
    ++        }
    ++        zOut[j] = 0;
    ++        sqlite3_result_text(pCtx, zOut, j, sqlite3_free);
    ++      }
    ++      break;
    ++    }
    ++    case JSON_ARRAY:
    ++    case JSON_OBJECT: {
    ++      jsonReturnJson(pNode, pCtx, aReplace);
    ++      break;
    ++    }
    ++  }
    ++}
    ++
    ++/* Forward reference */
    ++static int jsonParseAddNode(JsonParse*,u32,u32,const char*);
    ++
    ++/*
    ++** A macro to hint to the compiler that a function should not be
    ++** inlined.
    ++*/
    ++#if defined(__GNUC__)
    ++#  define JSON_NOINLINE  __attribute__((noinline))
    ++#elif defined(_MSC_VER) && _MSC_VER>=1310
    ++#  define JSON_NOINLINE  __declspec(noinline)
    ++#else
    ++#  define JSON_NOINLINE
    ++#endif
    ++
    ++
    ++static JSON_NOINLINE int jsonParseAddNodeExpand(
    ++  JsonParse *pParse,        /* Append the node to this object */
    ++  u32 eType,                /* Node type */
    ++  u32 n,                    /* Content size or sub-node count */
    ++  const char *zContent      /* Content */
    ++){
    ++  u32 nNew;
    ++  JsonNode *pNew;
    ++  assert( pParse->nNode>=pParse->nAlloc );
    ++  if( pParse->oom ) return -1;
    ++  nNew = pParse->nAlloc*2 + 10;
    ++  pNew = sqlite3_realloc(pParse->aNode, sizeof(JsonNode)*nNew);
    ++  if( pNew==0 ){
    ++    pParse->oom = 1;
    ++    return -1;
    ++  }
    ++  pParse->nAlloc = nNew;
    ++  pParse->aNode = pNew;
    ++  assert( pParse->nNode<pParse->nAlloc );
    ++  return jsonParseAddNode(pParse, eType, n, zContent);
    ++}
    ++
    ++/*
    ++** Create a new JsonNode instance based on the arguments and append that
    ++** instance to the JsonParse.  Return the index in pParse->aNode[] of the
    ++** new node, or -1 if a memory allocation fails.
    ++*/
    ++static int jsonParseAddNode(
    ++  JsonParse *pParse,        /* Append the node to this object */
    ++  u32 eType,                /* Node type */
    ++  u32 n,                    /* Content size or sub-node count */
    ++  const char *zContent      /* Content */
    ++){
    ++  JsonNode *p;
    ++  if( pParse->nNode>=pParse->nAlloc ){
    ++    return jsonParseAddNodeExpand(pParse, eType, n, zContent);
    ++  }
    ++  p = &pParse->aNode[pParse->nNode];
    ++  p->eType = (u8)eType;
    ++  p->jnFlags = 0;
    ++  p->n = n;
    ++  p->u.zJContent = zContent;
    ++  return pParse->nNode++;
    ++}
    ++
    ++/*
    ++** Return true if z[] begins with 4 (or more) hexadecimal digits
    ++*/
    ++static int jsonIs4Hex(const char *z){
    ++  int i;
    ++  for(i=0; i<4; i++) if( !safe_isxdigit(z[i]) ) return 0;
    ++  return 1;
    ++}
    ++
    ++/*
    ++** Parse a single JSON value which begins at pParse->zJson[i].  Return the
    ++** index of the first character past the end of the value parsed.
    ++**
    ++** Return negative for a syntax error.  Special cases:  return -2 if the
    ++** first non-whitespace character is '}' and return -3 if the first
    ++** non-whitespace character is ']'.
    ++*/
    ++static int jsonParseValue(JsonParse *pParse, u32 i){
    ++  char c;
    ++  u32 j;
    ++  int iThis;
    ++  int x;
    ++  JsonNode *pNode;
    ++  const char *z = pParse->zJson;
    ++  while( safe_isspace(z[i]) ){ i++; }
    ++  if( (c = z[i])=='{' ){
    ++    /* Parse object */
    ++    iThis = jsonParseAddNode(pParse, JSON_OBJECT, 0, 0);
    ++    if( iThis<0 ) return -1;
    ++    for(j=i+1;;j++){
    ++      while( safe_isspace(z[j]) ){ j++; }
    ++      if( ++pParse->iDepth > JSON_MAX_DEPTH ) return -1;
    ++      x = jsonParseValue(pParse, j);
    ++      if( x<0 ){
    ++        pParse->iDepth--;
    ++        if( x==(-2) && pParse->nNode==(u32)iThis+1 ) return j+1;
    ++        return -1;
    ++      }
    ++      if( pParse->oom ) return -1;
    ++      pNode = &pParse->aNode[pParse->nNode-1];
    ++      if( pNode->eType!=JSON_STRING ) return -1;
    ++      pNode->jnFlags |= JNODE_LABEL;
    ++      j = x;
    ++      while( safe_isspace(z[j]) ){ j++; }
    ++      if( z[j]!=':' ) return -1;
    ++      j++;
    ++      x = jsonParseValue(pParse, j);
    ++      pParse->iDepth--;
    +       if( x<0 ) return -1;
    +       j = x;
    +-      while( safe_isspace(pParse->zJson[j]) ){ j++; }
    +-      c = pParse->zJson[j];
    ++      while( safe_isspace(z[j]) ){ j++; }
    ++      c = z[j];
    +       if( c==',' ) continue;
    +       if( c!='}' ) return -1;
    +       break;
    +@@ -164278,15 +184370,17 @@ static int jsonParseValue(JsonParse *pParse, u32 i){
    +     iThis = jsonParseAddNode(pParse, JSON_ARRAY, 0, 0);
    +     if( iThis<0 ) return -1;
    +     for(j=i+1;;j++){
    +-      while( safe_isspace(pParse->zJson[j]) ){ j++; }
    ++      while( safe_isspace(z[j]) ){ j++; }
    ++      if( ++pParse->iDepth > JSON_MAX_DEPTH ) return -1;
    +       x = jsonParseValue(pParse, j);
    ++      pParse->iDepth--;
    +       if( x<0 ){
    +         if( x==(-3) && pParse->nNode==(u32)iThis+1 ) return j+1;
    +         return -1;
    +       }
    +       j = x;
    +-      while( safe_isspace(pParse->zJson[j]) ){ j++; }
    +-      c = pParse->zJson[j];
    ++      while( safe_isspace(z[j]) ){ j++; }
    ++      c = z[j];
    +       if( c==',' ) continue;
    +       if( c!=']' ) return -1;
    +       break;
    +@@ -164298,66 +184392,79 @@ static int jsonParseValue(JsonParse *pParse, u32 i){
    +     u8 jnFlags = 0;
    +     j = i+1;
    +     for(;;){
    +-      c = pParse->zJson[j];
    +-      if( c==0 ) return -1;
    ++      c = z[j];
    ++      if( (c & ~0x1f)==0 ){
    ++        /* Control characters are not allowed in strings */
    ++        return -1;
    ++      }
    +       if( c=='\\' ){
    +-        c = pParse->zJson[++j];
    +-        if( c==0 ) return -1;
    +-        jnFlags = JNODE_ESCAPE;
    ++        c = z[++j];
    ++        if( c=='"' || c=='\\' || c=='/' || c=='b' || c=='f'
    ++           || c=='n' || c=='r' || c=='t'
    ++           || (c=='u' && jsonIs4Hex(z+j+1)) ){
    ++          jnFlags = JNODE_ESCAPE;
    ++        }else{
    ++          return -1;
    ++        }
    +       }else if( c=='"' ){
    +         break;
    +       }
    +       j++;
    +     }
    +-    jsonParseAddNode(pParse, JSON_STRING, j+1-i, &pParse->zJson[i]);
    ++    jsonParseAddNode(pParse, JSON_STRING, j+1-i, &z[i]);
    +     if( !pParse->oom ) pParse->aNode[pParse->nNode-1].jnFlags = jnFlags;
    +     return j+1;
    +   }else if( c=='n'
    +-         && strncmp(pParse->zJson+i,"null",4)==0
    +-         && !safe_isalnum(pParse->zJson[i+4]) ){
    ++         && strncmp(z+i,"null",4)==0
    ++         && !safe_isalnum(z[i+4]) ){
    +     jsonParseAddNode(pParse, JSON_NULL, 0, 0);
    +     return i+4;
    +   }else if( c=='t'
    +-         && strncmp(pParse->zJson+i,"true",4)==0
    +-         && !safe_isalnum(pParse->zJson[i+4]) ){
    ++         && strncmp(z+i,"true",4)==0
    ++         && !safe_isalnum(z[i+4]) ){
    +     jsonParseAddNode(pParse, JSON_TRUE, 0, 0);
    +     return i+4;
    +   }else if( c=='f'
    +-         && strncmp(pParse->zJson+i,"false",5)==0
    +-         && !safe_isalnum(pParse->zJson[i+5]) ){
    ++         && strncmp(z+i,"false",5)==0
    ++         && !safe_isalnum(z[i+5]) ){
    +     jsonParseAddNode(pParse, JSON_FALSE, 0, 0);
    +     return i+5;
    +   }else if( c=='-' || (c>='0' && c<='9') ){
    +     /* Parse number */
    +     u8 seenDP = 0;
    +     u8 seenE = 0;
    ++    assert( '-' < '0' );
    ++    if( c<='0' ){
    ++      j = c=='-' ? i+1 : i;
    ++      if( z[j]=='0' && z[j+1]>='0' && z[j+1]<='9' ) return -1;
    ++    }
    +     j = i+1;
    +     for(;; j++){
    +-      c = pParse->zJson[j];
    ++      c = z[j];
    +       if( c>='0' && c<='9' ) continue;
    +       if( c=='.' ){
    +-        if( pParse->zJson[j-1]=='-' ) return -1;
    ++        if( z[j-1]=='-' ) return -1;
    +         if( seenDP ) return -1;
    +         seenDP = 1;
    +         continue;
    +       }
    +       if( c=='e' || c=='E' ){
    +-        if( pParse->zJson[j-1]<'0' ) return -1;
    ++        if( z[j-1]<'0' ) return -1;
    +         if( seenE ) return -1;
    +         seenDP = seenE = 1;
    +-        c = pParse->zJson[j+1];
    ++        c = z[j+1];
    +         if( c=='+' || c=='-' ){
    +           j++;
    +-          c = pParse->zJson[j+1];
    ++          c = z[j+1];
    +         }
    +         if( c<'0' || c>'9' ) return -1;
    +         continue;
    +       }
    +       break;
    +     }
    +-    if( pParse->zJson[j-1]<'0' ) return -1;
    ++    if( z[j-1]<'0' ) return -1;
    +     jsonParseAddNode(pParse, seenDP ? JSON_REAL : JSON_INT,
    +-                        j - i, &pParse->zJson[i]);
    ++                        j - i, &z[i]);
    +     return j;
    +   }else if( c=='}' ){
    +     return -2;  /* End of {...} */
    +@@ -164389,6 +184496,7 @@ static int jsonParse(
    +   i = jsonParseValue(pParse, 0);
    +   if( pParse->oom ) i = -1;
    +   if( i>0 ){
    ++    assert( pParse->iDepth==0 );
    +     while( safe_isspace(zJson[i]) ) i++;
    +     if( zJson[i] ) i = -1;
    +   }
    +@@ -164448,6 +184556,49 @@ static int jsonParseFindParents(JsonParse *pParse){
    +   return SQLITE_OK;
    + }
    + 
    ++/*
    ++** Magic number used for the JSON parse cache in sqlite3_get_auxdata()
    ++*/
    ++#define JSON_CACHE_ID  (-429938)
    ++
    ++/*
    ++** Obtain a complete parse of the JSON found in the first argument
    ++** of the argv array.  Use the sqlite3_get_auxdata() cache for this
    ++** parse if it is available.  If the cache is not available or if it
    ++** is no longer valid, parse the JSON again and return the new parse,
    ++** and also register the new parse so that it will be available for
    ++** future sqlite3_get_auxdata() calls.
    ++*/
    ++static JsonParse *jsonParseCached(
    ++  sqlite3_context *pCtx,
    ++  sqlite3_value **argv
    ++){
    ++  const char *zJson = (const char*)sqlite3_value_text(argv[0]);
    ++  int nJson = sqlite3_value_bytes(argv[0]);
    ++  JsonParse *p;
    ++  if( zJson==0 ) return 0;
    ++  p = (JsonParse*)sqlite3_get_auxdata(pCtx, JSON_CACHE_ID);
    ++  if( p && p->nJson==nJson && memcmp(p->zJson,zJson,nJson)==0 ){
    ++    p->nErr = 0;
    ++    return p; /* The cached entry matches, so return it */
    ++  }
    ++  p = sqlite3_malloc( sizeof(*p) + nJson + 1 );
    ++  if( p==0 ){
    ++    sqlite3_result_error_nomem(pCtx);
    ++    return 0;
    ++  }
    ++  memset(p, 0, sizeof(*p));
    ++  p->zJson = (char*)&p[1];
    ++  memcpy((char*)p->zJson, zJson, nJson+1);
    ++  if( jsonParse(p, pCtx, p->zJson) ){
    ++    sqlite3_free(p);
    ++    return 0;
    ++  }
    ++  p->nJson = nJson;
    ++  sqlite3_set_auxdata(pCtx, JSON_CACHE_ID, p, (void(*)(void*))jsonParseFree);
    ++  return (JsonParse*)sqlite3_get_auxdata(pCtx, JSON_CACHE_ID);
    ++}
    ++
    + /*
    + ** Compare the OBJECT label at pNode against zKey,nKey.  Return true on
    + ** a match.
    +@@ -164674,6 +184825,25 @@ static void jsonWrongNumArgs(
    +   sqlite3_free(zMsg);     
    + }
    + 
    ++/*
    ++** Mark all NULL entries in the Object passed in as JNODE_REMOVE.
    ++*/
    ++static void jsonRemoveAllNulls(JsonNode *pNode){
    ++  int i, n;
    ++  assert( pNode->eType==JSON_OBJECT );
    ++  n = pNode->n;
    ++  for(i=2; i<=n; i += jsonNodeSize(&pNode[i])+1){
    ++    switch( pNode[i].eType ){
    ++      case JSON_NULL:
    ++        pNode[i].jnFlags |= JNODE_REMOVE;
    ++        break;
    ++      case JSON_OBJECT:
    ++        jsonRemoveAllNulls(&pNode[i]);
    ++        break;
    ++    }
    ++  }
    ++}
    ++
    + 
    + /****************************************************************************
    + ** SQL functions used for testing and debugging
    +@@ -164734,9 +184904,29 @@ static void jsonTest1Func(
    + #endif /* SQLITE_DEBUG */
    + 
    + /****************************************************************************
    +-** SQL function implementations
    ++** Scalar SQL function implementations
    + ****************************************************************************/
    + 
    ++/*
    ++** Implementation of the json_QUOTE(VALUE) function.  Return a JSON value
    ++** corresponding to the SQL value input.  Mostly this means putting 
    ++** double-quotes around strings and returning the unquoted string "null"
    ++** when given a NULL input.
    ++*/
    ++static void jsonQuoteFunc(
    ++  sqlite3_context *ctx,
    ++  int argc,
    ++  sqlite3_value **argv
    ++){
    ++  JsonString jx;
    ++  UNUSED_PARAM(argc);
    ++
    ++  jsonInit(&jx, ctx);
    ++  jsonAppendValue(&jx, argv[0]);
    ++  jsonResult(&jx);
    ++  sqlite3_result_subtype(ctx, JSON_SUBTYPE);
    ++}
    ++
    + /*
    + ** Implementation of the json_array(VALUE,...) function.  Return a JSON
    + ** array that contains all values given in arguments.  Or if any argument
    +@@ -164774,29 +184964,30 @@ static void jsonArrayLengthFunc(
    +   int argc,
    +   sqlite3_value **argv
    + ){
    +-  JsonParse x;          /* The parse */
    ++  JsonParse *p;          /* The parse */
    +   sqlite3_int64 n = 0;
    +   u32 i;
    +   JsonNode *pNode;
    + 
    +-  if( jsonParse(&x, ctx, (const char*)sqlite3_value_text(argv[0])) ) return;
    +-  assert( x.nNode );
    ++  p = jsonParseCached(ctx, argv);
    ++  if( p==0 ) return;
    ++  assert( p->nNode );
    +   if( argc==2 ){
    +     const char *zPath = (const char*)sqlite3_value_text(argv[1]);
    +-    pNode = jsonLookup(&x, zPath, 0, ctx);
    ++    pNode = jsonLookup(p, zPath, 0, ctx);
    +   }else{
    +-    pNode = x.aNode;
    ++    pNode = p->aNode;
    +   }
    +   if( pNode==0 ){
    +-    x.nErr = 1;
    +-  }else if( pNode->eType==JSON_ARRAY ){
    ++    return;
    ++  }
    ++  if( pNode->eType==JSON_ARRAY ){
    +     assert( (pNode->jnFlags & JNODE_APPEND)==0 );
    +     for(i=1; i<=pNode->n; n++){
    +       i += jsonNodeSize(&pNode[i]);
    +     }
    +   }
    +-  if( x.nErr==0 ) sqlite3_result_int64(ctx, n);
    +-  jsonParseReset(&x);
    ++  sqlite3_result_int64(ctx, n);
    + }
    + 
    + /*
    +@@ -164812,20 +185003,21 @@ static void jsonExtractFunc(
    +   int argc,
    +   sqlite3_value **argv
    + ){
    +-  JsonParse x;          /* The parse */
    ++  JsonParse *p;          /* The parse */
    +   JsonNode *pNode;
    +   const char *zPath;
    +   JsonString jx;
    +   int i;
    + 
    +   if( argc<2 ) return;
    +-  if( jsonParse(&x, ctx, (const char*)sqlite3_value_text(argv[0])) ) return;
    ++  p = jsonParseCached(ctx, argv);
    ++  if( p==0 ) return;
    +   jsonInit(&jx, ctx);
    +   jsonAppendChar(&jx, '[');
    +   for(i=1; i<argc; i++){
    +     zPath = (const char*)sqlite3_value_text(argv[i]);
    +-    pNode = jsonLookup(&x, zPath, 0, ctx);
    +-    if( x.nErr ) break;
    ++    pNode = jsonLookup(p, zPath, 0, ctx);
    ++    if( p->nErr ) break;
    +     if( argc>2 ){
    +       jsonAppendSeparator(&jx);
    +       if( pNode ){
    +@@ -164843,9 +185035,107 @@ static void jsonExtractFunc(
    +     sqlite3_result_subtype(ctx, JSON_SUBTYPE);
    +   }
    +   jsonReset(&jx);
    ++}
    ++
    ++/* This is the RFC 7396 MergePatch algorithm.
    ++*/
    ++static JsonNode *jsonMergePatch(
    ++  JsonParse *pParse,   /* The JSON parser that contains the TARGET */
    ++  u32 iTarget,         /* Node of the TARGET in pParse */
    ++  JsonNode *pPatch     /* The PATCH */
    ++){
    ++  u32 i, j;
    ++  u32 iRoot;
    ++  JsonNode *pTarget;
    ++  if( pPatch->eType!=JSON_OBJECT ){
    ++    return pPatch;
    ++  }
    ++  assert( iTarget>=0 && iTarget<pParse->nNode );
    ++  pTarget = &pParse->aNode[iTarget];
    ++  assert( (pPatch->jnFlags & JNODE_APPEND)==0 );
    ++  if( pTarget->eType!=JSON_OBJECT ){
    ++    jsonRemoveAllNulls(pPatch);
    ++    return pPatch;
    ++  }
    ++  iRoot = iTarget;
    ++  for(i=1; i<pPatch->n; i += jsonNodeSize(&pPatch[i+1])+1){
    ++    u32 nKey;
    ++    const char *zKey;
    ++    assert( pPatch[i].eType==JSON_STRING );
    ++    assert( pPatch[i].jnFlags & JNODE_LABEL );
    ++    nKey = pPatch[i].n;
    ++    zKey = pPatch[i].u.zJContent;
    ++    assert( (pPatch[i].jnFlags & JNODE_RAW)==0 );
    ++    for(j=1; j<pTarget->n; j += jsonNodeSize(&pTarget[j+1])+1 ){
    ++      assert( pTarget[j].eType==JSON_STRING );
    ++      assert( pTarget[j].jnFlags & JNODE_LABEL );
    ++      assert( (pPatch[i].jnFlags & JNODE_RAW)==0 );
    ++      if( pTarget[j].n==nKey && strncmp(pTarget[j].u.zJContent,zKey,nKey)==0 ){
    ++        if( pTarget[j+1].jnFlags & (JNODE_REMOVE|JNODE_PATCH) ) break;
    ++        if( pPatch[i+1].eType==JSON_NULL ){
    ++          pTarget[j+1].jnFlags |= JNODE_REMOVE;
    ++        }else{
    ++          JsonNode *pNew = jsonMergePatch(pParse, iTarget+j+1, &pPatch[i+1]);
    ++          if( pNew==0 ) return 0;
    ++          pTarget = &pParse->aNode[iTarget];
    ++          if( pNew!=&pTarget[j+1] ){
    ++            pTarget[j+1].u.pPatch = pNew;
    ++            pTarget[j+1].jnFlags |= JNODE_PATCH;
    ++          }
    ++        }
    ++        break;
    ++      }
    ++    }
    ++    if( j>=pTarget->n && pPatch[i+1].eType!=JSON_NULL ){
    ++      int iStart, iPatch;
    ++      iStart = jsonParseAddNode(pParse, JSON_OBJECT, 2, 0);
    ++      jsonParseAddNode(pParse, JSON_STRING, nKey, zKey);
    ++      iPatch = jsonParseAddNode(pParse, JSON_TRUE, 0, 0);
    ++      if( pParse->oom ) return 0;
    ++      jsonRemoveAllNulls(pPatch);
    ++      pTarget = &pParse->aNode[iTarget];
    ++      pParse->aNode[iRoot].jnFlags |= JNODE_APPEND;
    ++      pParse->aNode[iRoot].u.iAppend = iStart - iRoot;
    ++      iRoot = iStart;
    ++      pParse->aNode[iPatch].jnFlags |= JNODE_PATCH;
    ++      pParse->aNode[iPatch].u.pPatch = &pPatch[i+1];
    ++    }
    ++  }
    ++  return pTarget;
    ++}
    ++
    ++/*
    ++** Implementation of the json_mergepatch(JSON1,JSON2) function.  Return a JSON
    ++** object that is the result of running the RFC 7396 MergePatch() algorithm
    ++** on the two arguments.
    ++*/
    ++static void jsonPatchFunc(
    ++  sqlite3_context *ctx,
    ++  int argc,
    ++  sqlite3_value **argv
    ++){
    ++  JsonParse x;     /* The JSON that is being patched */
    ++  JsonParse y;     /* The patch */
    ++  JsonNode *pResult;   /* The result of the merge */
    ++
    ++  UNUSED_PARAM(argc);
    ++  if( jsonParse(&x, ctx, (const char*)sqlite3_value_text(argv[0])) ) return;
    ++  if( jsonParse(&y, ctx, (const char*)sqlite3_value_text(argv[1])) ){
    ++    jsonParseReset(&x);
    ++    return;
    ++  }
    ++  pResult = jsonMergePatch(&x, 0, y.aNode);
    ++  assert( pResult!=0 || x.oom );
    ++  if( pResult ){
    ++    jsonReturnJson(pResult, ctx, 0);
    ++  }else{
    ++    sqlite3_result_error_nomem(ctx);
    ++  }
    +   jsonParseReset(&x);
    ++  jsonParseReset(&y);
    + }
    + 
    ++
    + /*
    + ** Implementation of the json_object(NAME,VALUE,...) function.  Return a JSON
    + ** object that contains all name/value given in arguments.  Or if any name
    +@@ -164949,11 +185239,11 @@ static void jsonReplaceFunc(
    +     if( x.nErr ) goto replace_err;
    +     if( pNode ){
    +       pNode->jnFlags |= (u8)JNODE_REPLACE;
    +-      pNode->iVal = (u8)(i+1);
    ++      pNode->u.iReplace = i + 1;
    +     }
    +   }
    +   if( x.aNode[0].jnFlags & JNODE_REPLACE ){
    +-    sqlite3_result_value(ctx, argv[x.aNode[0].iVal]);
    ++    sqlite3_result_value(ctx, argv[x.aNode[0].u.iReplace]);
    +   }else{
    +     jsonReturnJson(x.aNode, ctx, argv);
    +   }
    +@@ -165003,11 +185293,11 @@ static void jsonSetFunc(
    +       goto jsonSetDone;
    +     }else if( pNode && (bApnd || bIsSet) ){
    +       pNode->jnFlags |= (u8)JNODE_REPLACE;
    +-      pNode->iVal = (u8)(i+1);
    ++      pNode->u.iReplace = i + 1;
    +     }
    +   }
    +   if( x.aNode[0].jnFlags & JNODE_REPLACE ){
    +-    sqlite3_result_value(ctx, argv[x.aNode[0].iVal]);
    ++    sqlite3_result_value(ctx, argv[x.aNode[0].u.iReplace]);
    +   }else{
    +     jsonReturnJson(x.aNode, ctx, argv);
    +   }
    +@@ -165067,6 +185357,104 @@ static void jsonValidFunc(
    +   sqlite3_result_int(ctx, rc);
    + }
    + 
    ++
    ++/****************************************************************************
    ++** Aggregate SQL function implementations
    ++****************************************************************************/
    ++/*
    ++** json_group_array(VALUE)
    ++**
    ++** Return a JSON array composed of all values in the aggregate.
    ++*/
    ++static void jsonArrayStep(
    ++  sqlite3_context *ctx,
    ++  int argc,
    ++  sqlite3_value **argv
    ++){
    ++  JsonString *pStr;
    ++  UNUSED_PARAM(argc);
    ++  pStr = (JsonString*)sqlite3_aggregate_context(ctx, sizeof(*pStr));
    ++  if( pStr ){
    ++    if( pStr->zBuf==0 ){
    ++      jsonInit(pStr, ctx);
    ++      jsonAppendChar(pStr, '[');
    ++    }else{
    ++      jsonAppendChar(pStr, ',');
    ++      pStr->pCtx = ctx;
    ++    }
    ++    jsonAppendValue(pStr, argv[0]);
    ++  }
    ++}
    ++static void jsonArrayFinal(sqlite3_context *ctx){
    ++  JsonString *pStr;
    ++  pStr = (JsonString*)sqlite3_aggregate_context(ctx, 0);
    ++  if( pStr ){
    ++    pStr->pCtx = ctx;
    ++    jsonAppendChar(pStr, ']');
    ++    if( pStr->bErr ){
    ++      if( pStr->bErr==1 ) sqlite3_result_error_nomem(ctx);
    ++      assert( pStr->bStatic );
    ++    }else{
    ++      sqlite3_result_text(ctx, pStr->zBuf, pStr->nUsed,
    ++                          pStr->bStatic ? SQLITE_TRANSIENT : sqlite3_free);
    ++      pStr->bStatic = 1;
    ++    }
    ++  }else{
    ++    sqlite3_result_text(ctx, "[]", 2, SQLITE_STATIC);
    ++  }
    ++  sqlite3_result_subtype(ctx, JSON_SUBTYPE);
    ++}
    ++
    ++/*
    ++** json_group_obj(NAME,VALUE)
    ++**
    ++** Return a JSON object composed of all names and values in the aggregate.
    ++*/
    ++static void jsonObjectStep(
    ++  sqlite3_context *ctx,
    ++  int argc,
    ++  sqlite3_value **argv
    ++){
    ++  JsonString *pStr;
    ++  const char *z;
    ++  u32 n;
    ++  UNUSED_PARAM(argc);
    ++  pStr = (JsonString*)sqlite3_aggregate_context(ctx, sizeof(*pStr));
    ++  if( pStr ){
    ++    if( pStr->zBuf==0 ){
    ++      jsonInit(pStr, ctx);
    ++      jsonAppendChar(pStr, '{');
    ++    }else{
    ++      jsonAppendChar(pStr, ',');
    ++      pStr->pCtx = ctx;
    ++    }
    ++    z = (const char*)sqlite3_value_text(argv[0]);
    ++    n = (u32)sqlite3_value_bytes(argv[0]);
    ++    jsonAppendString(pStr, z, n);
    ++    jsonAppendChar(pStr, ':');
    ++    jsonAppendValue(pStr, argv[1]);
    ++  }
    ++}
    ++static void jsonObjectFinal(sqlite3_context *ctx){
    ++  JsonString *pStr;
    ++  pStr = (JsonString*)sqlite3_aggregate_context(ctx, 0);
    ++  if( pStr ){
    ++    jsonAppendChar(pStr, '}');
    ++    if( pStr->bErr ){
    ++      if( pStr->bErr==1 ) sqlite3_result_error_nomem(ctx);
    ++      assert( pStr->bStatic );
    ++    }else{
    ++      sqlite3_result_text(ctx, pStr->zBuf, pStr->nUsed,
    ++                          pStr->bStatic ? SQLITE_TRANSIENT : sqlite3_free);
    ++      pStr->bStatic = 1;
    ++    }
    ++  }else{
    ++    sqlite3_result_text(ctx, "{}", 2, SQLITE_STATIC);
    ++  }
    ++  sqlite3_result_subtype(ctx, JSON_SUBTYPE);
    ++}
    ++
    ++
    + #ifndef SQLITE_OMIT_VIRTUALTABLE
    + /****************************************************************************
    + ** The json_each virtual table
    +@@ -165331,9 +185719,9 @@ static int jsonEachColumn(
    +       /* For json_each() path and root are the same so fall through
    +       ** into the root case */
    +     }
    +-    case JEACH_ROOT: {
    ++    default: {
    +       const char *zRoot = p->zRoot;
    +-       if( zRoot==0 ) zRoot = "$";
    ++      if( zRoot==0 ) zRoot = "$";
    +       sqlite3_result_text(ctx, zRoot, -1, SQLITE_STATIC);
    +       break;
    +     }
    +@@ -165552,6 +185940,8 @@ SQLITE_PRIVATE int sqlite3Json1Init(sqlite3 *db){
    +     { "json_extract",        -1, 0,   jsonExtractFunc       },
    +     { "json_insert",         -1, 0,   jsonSetFunc           },
    +     { "json_object",         -1, 0,   jsonObjectFunc        },
    ++    { "json_patch",           2, 0,   jsonPatchFunc         },
    ++    { "json_quote",           1, 0,   jsonQuoteFunc         },
    +     { "json_remove",         -1, 0,   jsonRemoveFunc        },
    +     { "json_replace",        -1, 0,   jsonReplaceFunc       },
    +     { "json_set",            -1, 1,   jsonSetFunc           },
    +@@ -165565,6 +185955,15 @@ SQLITE_PRIVATE int sqlite3Json1Init(sqlite3 *db){
    +     { "json_test1",           1, 0,   jsonTest1Func         },
    + #endif
    +   };
    ++  static const struct {
    ++     const char *zName;
    ++     int nArg;
    ++     void (*xStep)(sqlite3_context*,int,sqlite3_value**);
    ++     void (*xFinal)(sqlite3_context*);
    ++  } aAgg[] = {
    ++    { "json_group_array",     1,   jsonArrayStep,   jsonArrayFinal  },
    ++    { "json_group_object",    2,   jsonObjectStep,  jsonObjectFinal },
    ++  };
    + #ifndef SQLITE_OMIT_VIRTUALTABLE
    +   static const struct {
    +      const char *zName;
    +@@ -165580,6 +185979,11 @@ SQLITE_PRIVATE int sqlite3Json1Init(sqlite3 *db){
    +                                  (void*)&aFunc[i].flag,
    +                                  aFunc[i].xFunc, 0, 0);
    +   }
    ++  for(i=0; i<sizeof(aAgg)/sizeof(aAgg[0]) && rc==SQLITE_OK; i++){
    ++    rc = sqlite3_create_function(db, aAgg[i].zName, aAgg[i].nArg,
    ++                                 SQLITE_UTF8 | SQLITE_DETERMINISTIC, 0,
    ++                                 0, aAgg[i].xStep, aAgg[i].xFinal);
    ++  }
    + #ifndef SQLITE_OMIT_VIRTUALTABLE
    +   for(i=0; i<sizeof(aMod)/sizeof(aMod[0]) && rc==SQLITE_OK; i++){
    +     rc = sqlite3_create_module(db, aMod[i].zName, aMod[i].pModule, 0);
    +@@ -165593,7 +185997,7 @@ SQLITE_PRIVATE int sqlite3Json1Init(sqlite3 *db){
    + #ifdef _WIN32
    + __declspec(dllexport)
    + #endif
    +-SQLITE_API int SQLITE_STDCALL sqlite3_json_init(
    ++SQLITE_API int sqlite3_json_init(
    +   sqlite3 *db, 
    +   char **pzErrMsg, 
    +   const sqlite3_api_routines *pApi
    +@@ -165704,6 +186108,9 @@ struct Fts5PhraseIter {
    + **   an OOM condition or IO error), an appropriate SQLite error code is 
    + **   returned.
    + **
    ++**   This function may be quite inefficient if used with an FTS5 table
    ++**   created with the "columnsize=0" option.
    ++**
    + ** xColumnText:
    + **   This function attempts to retrieve the text of column iCol of the
    + **   current document. If successful, (*pz) is set to point to a buffer
    +@@ -165724,15 +186131,29 @@ struct Fts5PhraseIter {
    + **   the query within the current row. Return SQLITE_OK if successful, or
    + **   an error code (i.e. SQLITE_NOMEM) if an error occurs.
    + **
    ++**   This API can be quite slow if used with an FTS5 table created with the
    ++**   "detail=none" or "detail=column" option. If the FTS5 table is created 
    ++**   with either "detail=none" or "detail=column" and "content=" option 
    ++**   (i.e. if it is a contentless table), then this API always returns 0.
    ++**
    + ** xInst:
    + **   Query for the details of phrase match iIdx within the current row.
    + **   Phrase matches are numbered starting from zero, so the iIdx argument
    + **   should be greater than or equal to zero and smaller than the value
    + **   output by xInstCount().
    + **
    ++**   Usually, output parameter *piPhrase is set to the phrase number, *piCol
    ++**   to the column in which it occurs and *piOff the token offset of the
    ++**   first token of the phrase. The exception is if the table was created
    ++**   with the offsets=0 option specified. In this case *piOff is always
    ++**   set to -1.
    ++**
    + **   Returns SQLITE_OK if successful, or an error code (i.e. SQLITE_NOMEM) 
    + **   if an error occurs.
    + **
    ++**   This API can be quite slow if used with an FTS5 table created with the
    ++**   "detail=none" or "detail=column" option. 
    ++**
    + ** xRowid:
    + **   Returns the rowid of the current row.
    + **
    +@@ -165746,11 +186167,13 @@ struct Fts5PhraseIter {
    + **       ... FROM ftstable WHERE ftstable MATCH $p ORDER BY rowid
    + **
    + **   with $p set to a phrase equivalent to the phrase iPhrase of the
    +-**   current query is executed. For each row visited, the callback function
    +-**   passed as the fourth argument is invoked. The context and API objects 
    +-**   passed to the callback function may be used to access the properties of
    +-**   each matched row. Invoking Api.xUserData() returns a copy of the pointer
    +-**   passed as the third argument to pUserData.
    ++**   current query is executed. Any column filter that applies to
    ++**   phrase iPhrase of the current query is included in $p. For each 
    ++**   row visited, the callback function passed as the fourth argument 
    ++**   is invoked. The context and API objects passed to the callback 
    ++**   function may be used to access the properties of each matched row.
    ++**   Invoking Api.xUserData() returns a copy of the pointer passed as 
    ++**   the third argument to pUserData.
    + **
    + **   If the callback function returns any value other than SQLITE_OK, the
    + **   query is abandoned and the xQueryPhrase function returns immediately.
    +@@ -165816,7 +186239,7 @@ struct Fts5PhraseIter {
    + **       Fts5PhraseIter iter;
    + **       int iCol, iOff;
    + **       for(pApi->xPhraseFirst(pFts, iPhrase, &iter, &iCol, &iOff);
    +-**           iOff>=0;
    ++**           iCol>=0;
    + **           pApi->xPhraseNext(pFts, &iter, &iCol, &iOff)
    + **       ){
    + **         // An instance of phrase iPhrase at offset iOff of column iCol
    +@@ -165824,13 +186247,51 @@ struct Fts5PhraseIter {
    + **
    + **   The Fts5PhraseIter structure is defined above. Applications should not
    + **   modify this structure directly - it should only be used as shown above
    +-**   with the xPhraseFirst() and xPhraseNext() API methods.
    ++**   with the xPhraseFirst() and xPhraseNext() API methods (and by
    ++**   xPhraseFirstColumn() and xPhraseNextColumn() as illustrated below).
    ++**
    ++**   This API can be quite slow if used with an FTS5 table created with the
    ++**   "detail=none" or "detail=column" option. If the FTS5 table is created 
    ++**   with either "detail=none" or "detail=column" and "content=" option 
    ++**   (i.e. if it is a contentless table), then this API always iterates
    ++**   through an empty set (all calls to xPhraseFirst() set iCol to -1).
    + **
    + ** xPhraseNext()
    + **   See xPhraseFirst above.
    ++**
    ++** xPhraseFirstColumn()
    ++**   This function and xPhraseNextColumn() are similar to the xPhraseFirst()
    ++**   and xPhraseNext() APIs described above. The difference is that instead
    ++**   of iterating through all instances of a phrase in the current row, these
    ++**   APIs are used to iterate through the set of columns in the current row
    ++**   that contain one or more instances of a specified phrase. For example:
    ++**
    ++**       Fts5PhraseIter iter;
    ++**       int iCol;
    ++**       for(pApi->xPhraseFirstColumn(pFts, iPhrase, &iter, &iCol);
    ++**           iCol>=0;
    ++**           pApi->xPhraseNextColumn(pFts, &iter, &iCol)
    ++**       ){
    ++**         // Column iCol contains at least one instance of phrase iPhrase
    ++**       }
    ++**
    ++**   This API can be quite slow if used with an FTS5 table created with the
    ++**   "detail=none" option. If the FTS5 table is created with either 
    ++**   "detail=none" "content=" option (i.e. if it is a contentless table), 
    ++**   then this API always iterates through an empty set (all calls to 
    ++**   xPhraseFirstColumn() set iCol to -1).
    ++**
    ++**   The information accessed using this API and its companion
    ++**   xPhraseFirstColumn() may also be obtained using xPhraseFirst/xPhraseNext
    ++**   (or xInst/xInstCount). The chief advantage of this API is that it is
    ++**   significantly more efficient than those alternatives when used with
    ++**   "detail=column" tables.  
    ++**
    ++** xPhraseNextColumn()
    ++**   See xPhraseFirstColumn above.
    + */
    + struct Fts5ExtensionApi {
    +-  int iVersion;                   /* Currently always set to 1 */
    ++  int iVersion;                   /* Currently always set to 3 */
    + 
    +   void *(*xUserData)(Fts5Context*);
    + 
    +@@ -165860,8 +186321,11 @@ struct Fts5ExtensionApi {
    +   int (*xSetAuxdata)(Fts5Context*, void *pAux, void(*xDelete)(void*));
    +   void *(*xGetAuxdata)(Fts5Context*, int bClear);
    + 
    +-  void (*xPhraseFirst)(Fts5Context*, int iPhrase, Fts5PhraseIter*, int*, int*);
    ++  int (*xPhraseFirst)(Fts5Context*, int iPhrase, Fts5PhraseIter*, int*, int*);
    +   void (*xPhraseNext)(Fts5Context*, Fts5PhraseIter*, int *piCol, int *piOff);
    ++
    ++  int (*xPhraseFirstColumn)(Fts5Context*, int iPhrase, Fts5PhraseIter*, int*);
    ++  void (*xPhraseNextColumn)(Fts5Context*, Fts5PhraseIter*, int *piCol);
    + };
    + 
    + /* 
    +@@ -165878,7 +186342,7 @@ struct Fts5ExtensionApi {
    + ** behaviour. The structure methods are expected to function as follows:
    + **
    + ** xCreate:
    +-**   This function is used to allocate and inititalize a tokenizer instance.
    ++**   This function is used to allocate and initialize a tokenizer instance.
    + **   A tokenizer instance is required to actually tokenize text.
    + **
    + **   The first argument passed to this function is a copy of the (void*)
    +@@ -166138,7 +186602,6 @@ struct fts5_api {
    + 
    + #endif /* _FTS5_H */
    + 
    +-
    + /*
    + ** 2014 May 31
    + **
    +@@ -166155,6 +186618,7 @@ struct fts5_api {
    + #ifndef _FTS5INT_H
    + #define _FTS5INT_H
    + 
    ++/* #include "fts5.h" */
    + /* #include "sqlite3ext.h" */
    + SQLITE_EXTENSION_INIT1
    + 
    +@@ -166166,10 +186630,13 @@ SQLITE_EXTENSION_INIT1
    + typedef unsigned char  u8;
    + typedef unsigned int   u32;
    + typedef unsigned short u16;
    ++typedef short i16;
    + typedef sqlite3_int64 i64;
    + typedef sqlite3_uint64 u64;
    + 
    +-#define ArraySize(x) (sizeof(x) / sizeof(x[0]))
    ++#ifndef ArraySize
    ++# define ArraySize(x) ((int)(sizeof(x) / sizeof(x[0])))
    ++#endif
    + 
    + #define testcase(x)
    + #define ALWAYS(x) 1
    +@@ -166186,6 +186653,10 @@ typedef sqlite3_uint64 u64;
    + 
    + #endif
    + 
    ++/* Truncate very long tokens to this many bytes. Hard limit is 
    ++** (65536-1-1-4-9)==65521 bytes. The limiting factor is the 16-bit offset
    ++** field that occurs at the start of each leaf page (see fts5_index.c). */
    ++#define FTS5_MAX_TOKEN_SIZE 32768
    + 
    + /*
    + ** Maximum number of prefix indexes on single FTS5 table. This must be
    +@@ -166220,6 +186691,16 @@ SQLITE_API extern int sqlite3_fts5_may_be_corrupt;
    + # define assert_nc(x) assert(x)
    + #endif
    + 
    ++/* Mark a function parameter as unused, to suppress nuisance compiler
    ++** warnings. */
    ++#ifndef UNUSED_PARAM
    ++# define UNUSED_PARAM(X)  (void)(X)
    ++#endif
    ++
    ++#ifndef UNUSED_PARAM2
    ++# define UNUSED_PARAM2(X, Y)  (void)(X), (void)(Y)
    ++#endif
    ++
    + typedef struct Fts5Global Fts5Global;
    + typedef struct Fts5Colset Fts5Colset;
    + 
    +@@ -166291,6 +186772,7 @@ struct Fts5Config {
    +   char *zContent;                 /* content table */ 
    +   char *zContentRowid;            /* "content_rowid=" option value */ 
    +   int bColumnsize;                /* "columnsize=" option value (dflt==1) */
    ++  int eDetail;                    /* FTS5_DETAIL_XXX value */
    +   char *zContentExprlist;
    +   Fts5Tokenizer *pTok;
    +   fts5_tokenizer *pTokApi;
    +@@ -166300,6 +186782,8 @@ struct Fts5Config {
    +   int pgsz;                       /* Approximate page size used in %_data */
    +   int nAutomerge;                 /* 'automerge' setting */
    +   int nCrisisMerge;               /* Maximum allowed segments per level */
    ++  int nUsermerge;                 /* 'usermerge' setting */
    ++  int nHashSize;                  /* Bytes of memory for in-memory hash */
    +   char *zRank;                    /* Name of rank function */
    +   char *zRankArgs;                /* Arguments to rank function */
    + 
    +@@ -166318,6 +186802,9 @@ struct Fts5Config {
    + #define FTS5_CONTENT_NONE     1
    + #define FTS5_CONTENT_EXTERNAL 2
    + 
    ++#define FTS5_DETAIL_FULL    0
    ++#define FTS5_DETAIL_NONE    1
    ++#define FTS5_DETAIL_COLUMNS 2
    + 
    + 
    + 
    +@@ -166364,25 +186851,27 @@ struct Fts5Buffer {
    +   int nSpace;
    + };
    + 
    +-static int sqlite3Fts5BufferGrow(int*, Fts5Buffer*, int);
    ++static int sqlite3Fts5BufferSize(int*, Fts5Buffer*, u32);
    + static void sqlite3Fts5BufferAppendVarint(int*, Fts5Buffer*, i64);
    +-static void sqlite3Fts5BufferAppendBlob(int*, Fts5Buffer*, int, const u8*);
    ++static void sqlite3Fts5BufferAppendBlob(int*, Fts5Buffer*, u32, const u8*);
    + static void sqlite3Fts5BufferAppendString(int *, Fts5Buffer*, const char*);
    + static void sqlite3Fts5BufferFree(Fts5Buffer*);
    + static void sqlite3Fts5BufferZero(Fts5Buffer*);
    + static void sqlite3Fts5BufferSet(int*, Fts5Buffer*, int, const u8*);
    + static void sqlite3Fts5BufferAppendPrintf(int *, Fts5Buffer*, char *zFmt, ...);
    +-static void sqlite3Fts5BufferAppend32(int*, Fts5Buffer*, int);
    + 
    + static char *sqlite3Fts5Mprintf(int *pRc, const char *zFmt, ...);
    + 
    + #define fts5BufferZero(x)             sqlite3Fts5BufferZero(x)
    +-#define fts5BufferGrow(a,b,c)         sqlite3Fts5BufferGrow(a,b,c)
    + #define fts5BufferAppendVarint(a,b,c) sqlite3Fts5BufferAppendVarint(a,b,c)
    + #define fts5BufferFree(a)             sqlite3Fts5BufferFree(a)
    + #define fts5BufferAppendBlob(a,b,c,d) sqlite3Fts5BufferAppendBlob(a,b,c,d)
    + #define fts5BufferSet(a,b,c,d)        sqlite3Fts5BufferSet(a,b,c,d)
    +-#define fts5BufferAppend32(a,b,c)     sqlite3Fts5BufferAppend32(a,b,c)
    ++
    ++#define fts5BufferGrow(pRc,pBuf,nn) ( \
    ++  (u32)((pBuf)->n) + (u32)(nn) <= (u32)((pBuf)->nSpace) ? 0 : \
    ++    sqlite3Fts5BufferSize((pRc),(pBuf),(nn)+(pBuf)->n) \
    ++)
    + 
    + /* Write and decode big-endian 32-bit integer values */
    + static void sqlite3Fts5Put32(u8*, int);
    +@@ -166415,6 +186904,7 @@ struct Fts5PoslistWriter {
    +   i64 iPrev;
    + };
    + static int sqlite3Fts5PoslistWriterAppend(Fts5Buffer*, Fts5PoslistWriter*, i64);
    ++static void sqlite3Fts5PoslistSafeAppend(Fts5Buffer*, i64*, i64);
    + 
    + static int sqlite3Fts5PoslistNext64(
    +   const u8 *a, int n,             /* Buffer containing poslist */
    +@@ -166429,6 +186919,13 @@ static char *sqlite3Fts5Strndup(int *pRc, const char *pIn, int nIn);
    + /* Character set tests (like isspace(), isalpha() etc.) */
    + static int sqlite3Fts5IsBareword(char t);
    + 
    ++
    ++/* Bucket of terms object used by the integrity-check in offsets=0 mode. */
    ++typedef struct Fts5Termset Fts5Termset;
    ++static int sqlite3Fts5TermsetNew(Fts5Termset**);
    ++static int sqlite3Fts5TermsetAdd(Fts5Termset*, int, const char*, int, int *pbPresent);
    ++static void sqlite3Fts5TermsetFree(Fts5Termset*);
    ++
    + /*
    + ** End of interface to code in fts5_buffer.c.
    + **************************************************************************/
    +@@ -166441,6 +186938,15 @@ static int sqlite3Fts5IsBareword(char t);
    + typedef struct Fts5Index Fts5Index;
    + typedef struct Fts5IndexIter Fts5IndexIter;
    + 
    ++struct Fts5IndexIter {
    ++  i64 iRowid;
    ++  const u8 *pData;
    ++  int nData;
    ++  u8 bEof;
    ++};
    ++
    ++#define sqlite3Fts5IterEof(x) ((x)->bEof)
    ++
    + /*
    + ** Values used as part of the flags argument passed to IndexQuery().
    + */
    +@@ -166449,6 +186955,12 @@ typedef struct Fts5IndexIter Fts5IndexIter;
    + #define FTS5INDEX_QUERY_TEST_NOIDX 0x0004   /* Do not use prefix index */
    + #define FTS5INDEX_QUERY_SCAN       0x0008   /* Scan query (fts5vocab) */
    + 
    ++/* The following are used internally by the fts5_index.c module. They are
    ++** defined here only to make it easier to avoid clashes with the flags
    ++** above. */
    ++#define FTS5INDEX_QUERY_SKIPEMPTY  0x0010
    ++#define FTS5INDEX_QUERY_NOOUTPUT   0x0020
    ++
    + /*
    + ** Create/destroy an Fts5Index object.
    + */
    +@@ -166456,14 +186968,27 @@ static int sqlite3Fts5IndexOpen(Fts5Config *pConfig, int bCreate, Fts5Index**, c
    + static int sqlite3Fts5IndexClose(Fts5Index *p);
    + 
    + /*
    +-** for(
    +-**   sqlite3Fts5IndexQuery(p, "token", 5, 0, 0, &pIter);
    +-**   0==sqlite3Fts5IterEof(pIter);
    +-**   sqlite3Fts5IterNext(pIter)
    +-** ){
    +-**   i64 iRowid = sqlite3Fts5IterRowid(pIter);
    +-** }
    ++** Return a simple checksum value based on the arguments.
    + */
    ++static u64 sqlite3Fts5IndexEntryCksum(
    ++  i64 iRowid, 
    ++  int iCol, 
    ++  int iPos, 
    ++  int iIdx,
    ++  const char *pTerm,
    ++  int nTerm
    ++);
    ++
    ++/*
    ++** Argument p points to a buffer containing utf-8 text that is n bytes in 
    ++** size. Return the number of bytes in the nChar character prefix of the
    ++** buffer, or 0 if there are less than nChar characters in total.
    ++*/
    ++static int sqlite3Fts5IndexCharlenToBytelen(
    ++  const char *p, 
    ++  int nByte, 
    ++  int nChar
    ++);
    + 
    + /*
    + ** Open a new iterator to iterate though all rowids that match the 
    +@@ -166481,12 +187006,8 @@ static int sqlite3Fts5IndexQuery(
    + ** The various operations on open token or token prefix iterators opened
    + ** using sqlite3Fts5IndexQuery().
    + */
    +-static int sqlite3Fts5IterEof(Fts5IndexIter*);
    + static int sqlite3Fts5IterNext(Fts5IndexIter*);
    + static int sqlite3Fts5IterNextFrom(Fts5IndexIter*, i64 iMatch);
    +-static i64 sqlite3Fts5IterRowid(Fts5IndexIter*);
    +-static int sqlite3Fts5IterPoslist(Fts5IndexIter*,Fts5Colset*, const u8**, int*, i64*);
    +-static int sqlite3Fts5IterPoslistBuffer(Fts5IndexIter *pIter, Fts5Buffer *pBuf);
    + 
    + /*
    + ** Close an iterator opened by sqlite3Fts5IndexQuery().
    +@@ -166529,9 +187050,9 @@ static int sqlite3Fts5IndexBeginWrite(
    + 
    + /*
    + ** Flush any data stored in the in-memory hash tables to the database.
    +-** If the bCommit flag is true, also close any open blob handles.
    ++** Also close any open blob handles.
    + */
    +-static int sqlite3Fts5IndexSync(Fts5Index *p, int bCommit);
    ++static int sqlite3Fts5IndexSync(Fts5Index *p);
    + 
    + /*
    + ** Discard any data stored in the in-memory hash tables. Do not write it
    +@@ -166550,7 +187071,6 @@ static int sqlite3Fts5IndexSetAverages(Fts5Index *p, const u8*, int);
    + /*
    + ** Functions called by the storage module as part of integrity-check.
    + */
    +-static u64 sqlite3Fts5IndexCksum(Fts5Config*,i64,int,int,const char*,int);
    + static int sqlite3Fts5IndexIntegrityCheck(Fts5Index*, u64 cksum);
    + 
    + /* 
    +@@ -166570,6 +187090,7 @@ static int sqlite3Fts5IndexReads(Fts5Index *p);
    + static int sqlite3Fts5IndexReinit(Fts5Index *p);
    + static int sqlite3Fts5IndexOptimize(Fts5Index *p);
    + static int sqlite3Fts5IndexMerge(Fts5Index *p, int nMerge);
    ++static int sqlite3Fts5IndexReset(Fts5Index *p);
    + 
    + static int sqlite3Fts5IndexLoadConfig(Fts5Index *p);
    + 
    +@@ -166615,7 +187136,7 @@ static int sqlite3Fts5GetTokenizer(
    +   char **pzErr
    + );
    + 
    +-static Fts5Index *sqlite3Fts5IndexFromCsrid(Fts5Global*, i64, int*);
    ++static Fts5Index *sqlite3Fts5IndexFromCsrid(Fts5Global*, i64, Fts5Config **);
    + 
    + /*
    + ** End of interface to code in fts5.c.
    +@@ -166629,7 +187150,7 @@ typedef struct Fts5Hash Fts5Hash;
    + /*
    + ** Create a hash table, free a hash table.
    + */
    +-static int sqlite3Fts5HashNew(Fts5Hash**, int *pnSize);
    ++static int sqlite3Fts5HashNew(Fts5Config*, Fts5Hash**, int *pnSize);
    + static void sqlite3Fts5HashFree(Fts5Hash*);
    + 
    + static int sqlite3Fts5HashWrite(
    +@@ -166688,7 +187209,7 @@ static int sqlite3Fts5StorageRename(Fts5Storage*, const char *zName);
    + static int sqlite3Fts5DropAll(Fts5Config*);
    + static int sqlite3Fts5CreateTable(Fts5Config*, const char*, const char*, int, char **);
    + 
    +-static int sqlite3Fts5StorageDelete(Fts5Storage *p, i64);
    ++static int sqlite3Fts5StorageDelete(Fts5Storage *p, i64, sqlite3_value**);
    + static int sqlite3Fts5StorageContentInsert(Fts5Storage *p, sqlite3_value**, i64*);
    + static int sqlite3Fts5StorageIndexInsert(Fts5Storage *p, sqlite3_value**, i64);
    + 
    +@@ -166701,19 +187222,18 @@ static int sqlite3Fts5StorageDocsize(Fts5Storage *p, i64 iRowid, int *aCol);
    + static int sqlite3Fts5StorageSize(Fts5Storage *p, int iCol, i64 *pnAvg);
    + static int sqlite3Fts5StorageRowCount(Fts5Storage *p, i64 *pnRow);
    + 
    +-static int sqlite3Fts5StorageSync(Fts5Storage *p, int bCommit);
    ++static int sqlite3Fts5StorageSync(Fts5Storage *p);
    + static int sqlite3Fts5StorageRollback(Fts5Storage *p);
    + 
    + static int sqlite3Fts5StorageConfigValue(
    +     Fts5Storage *p, const char*, sqlite3_value*, int
    + );
    + 
    +-static int sqlite3Fts5StorageSpecialDelete(Fts5Storage *p, i64 iDel, sqlite3_value**);
    +-
    + static int sqlite3Fts5StorageDeleteAll(Fts5Storage *p);
    + static int sqlite3Fts5StorageRebuild(Fts5Storage *p);
    + static int sqlite3Fts5StorageOptimize(Fts5Storage *p);
    + static int sqlite3Fts5StorageMerge(Fts5Storage *p, int nMerge);
    ++static int sqlite3Fts5StorageReset(Fts5Storage *p);
    + 
    + /*
    + ** End of interface to code in fts5_storage.c.
    +@@ -166738,6 +187258,7 @@ struct Fts5Token {
    + /* Parse a MATCH expression. */
    + static int sqlite3Fts5ExprNew(
    +   Fts5Config *pConfig, 
    ++  int iCol,                       /* Column on LHS of MATCH operator */
    +   const char *zExpr,
    +   Fts5Expr **ppNew, 
    +   char **pzErr
    +@@ -166766,7 +187287,16 @@ static int sqlite3Fts5ExprPhraseCount(Fts5Expr*);
    + static int sqlite3Fts5ExprPhraseSize(Fts5Expr*, int iPhrase);
    + static int sqlite3Fts5ExprPoslist(Fts5Expr*, int, const u8 **);
    + 
    +-static int sqlite3Fts5ExprClonePhrase(Fts5Config*, Fts5Expr*, int, Fts5Expr**);
    ++typedef struct Fts5PoslistPopulator Fts5PoslistPopulator;
    ++static Fts5PoslistPopulator *sqlite3Fts5ExprClearPoslists(Fts5Expr*, int);
    ++static int sqlite3Fts5ExprPopulatePoslists(
    ++    Fts5Config*, Fts5Expr*, Fts5PoslistPopulator*, int, const char*, int
    ++);
    ++static void sqlite3Fts5ExprCheckPoslists(Fts5Expr*, i64);
    ++
    ++static int sqlite3Fts5ExprClonePhrase(Fts5Expr*, int, Fts5Expr**);
    ++
    ++static int sqlite3Fts5ExprPhraseCollist(Fts5Expr *, int, const u8 **, int *);
    + 
    + /*******************************************
    + ** The fts5_expr.c API above this point is used by the other hand-written
    +@@ -166783,6 +187313,12 @@ static Fts5ExprNode *sqlite3Fts5ParseNode(
    +   Fts5ExprNearset *pNear
    + );
    + 
    ++static Fts5ExprNode *sqlite3Fts5ParseImplicitAnd(
    ++  Fts5Parse *pParse,
    ++  Fts5ExprNode *pLeft,
    ++  Fts5ExprNode *pRight
    ++);
    ++
    + static Fts5ExprPhrase *sqlite3Fts5ParseTerm(
    +   Fts5Parse *pParse, 
    +   Fts5ExprPhrase *pPhrase, 
    +@@ -166790,6 +187326,8 @@ static Fts5ExprPhrase *sqlite3Fts5ParseTerm(
    +   int bPrefix
    + );
    + 
    ++static void sqlite3Fts5ParseSetCaret(Fts5ExprPhrase*);
    ++
    + static Fts5ExprNearset *sqlite3Fts5ParseNearset(
    +   Fts5Parse*, 
    +   Fts5ExprNearset*,
    +@@ -166807,7 +187345,8 @@ static void sqlite3Fts5ParseNearsetFree(Fts5ExprNearset*);
    + static void sqlite3Fts5ParseNodeFree(Fts5ExprNode*);
    + 
    + static void sqlite3Fts5ParseSetDistance(Fts5Parse*, Fts5ExprNearset*, Fts5Token*);
    +-static void sqlite3Fts5ParseSetColset(Fts5Parse*, Fts5ExprNearset*, Fts5Colset*);
    ++static void sqlite3Fts5ParseSetColset(Fts5Parse*, Fts5ExprNode*, Fts5Colset*);
    ++static Fts5Colset *sqlite3Fts5ParseColsetInvert(Fts5Parse*, Fts5Colset*);
    + static void sqlite3Fts5ParseFinished(Fts5Parse *pParse, Fts5ExprNode *p);
    + static void sqlite3Fts5ParseNear(Fts5Parse *pParse, Fts5Token*);
    + 
    +@@ -166863,28 +187402,46 @@ static int sqlite3Fts5UnicodeFold(int c, int bRemoveDiacritic);
    + #define FTS5_NOT                              3
    + #define FTS5_TERM                             4
    + #define FTS5_COLON                            5
    +-#define FTS5_LP                               6
    +-#define FTS5_RP                               7
    +-#define FTS5_LCP                              8
    +-#define FTS5_RCP                              9
    +-#define FTS5_STRING                          10
    +-#define FTS5_COMMA                           11
    +-#define FTS5_PLUS                            12
    +-#define FTS5_STAR                            13
    +-
    +-/* Driver template for the LEMON parser generator.
    +-** The author disclaims copyright to this source code.
    ++#define FTS5_MINUS                            6
    ++#define FTS5_LCP                              7
    ++#define FTS5_RCP                              8
    ++#define FTS5_STRING                           9
    ++#define FTS5_LP                              10
    ++#define FTS5_RP                              11
    ++#define FTS5_CARET                           12
    ++#define FTS5_COMMA                           13
    ++#define FTS5_PLUS                            14
    ++#define FTS5_STAR                            15
    ++
    ++/*
    ++** 2000-05-29
    ++**
    ++** 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.
    ++**
    ++*************************************************************************
    ++** Driver template for the LEMON parser generator.
    ++**
    ++** The "lemon" program processes an LALR(1) input grammar file, then uses
    ++** this template to construct a parser.  The "lemon" program inserts text
    ++** at each "%%" line.  Also, any "P-a-r-s-e" identifer prefix (without the
    ++** interstitial "-" characters) contained in this template is changed into
    ++** the value of the %name directive from the grammar.  Otherwise, the content
    ++** of this template is copied straight through into the generate parser
    ++** source file.
    + **
    +-** This version of "lempar.c" is modified, slightly, for use by SQLite.
    +-** The only modifications are the addition of a couple of NEVER()
    +-** macros to disable tests that are needed in the case of a general
    +-** LALR(1) grammar but which are always false in the
    +-** specific grammar used by SQLite.
    ++** The following is the concatenation of all %include directives from the
    ++** input grammar file:
    + */
    +-/* First off, code is included that follows the "include" declaration
    +-** in the input grammar file. */
    + /* #include <stdio.h> */
    ++/************ Begin %include sections from the grammar ************************/
    + 
    ++/* #include "fts5Int.h" */
    ++/* #include "fts5parse.h" */
    + 
    + /*
    + ** Disable all error recovery processing in the parser push-down
    +@@ -166897,44 +187454,54 @@ static int sqlite3Fts5UnicodeFold(int c, int bRemoveDiacritic);
    + */
    + #define fts5yytestcase(X) testcase(X)
    + 
    +-/* Next is all token values, in a form suitable for use by makeheaders.
    +-** This section will be null unless lemon is run with the -m switch.
    +-*/
    +-/* 
    +-** These constants (all generated automatically by the parser generator)
    +-** specify the various kinds of tokens (terminals) that the parser
    +-** understands. 
    +-**
    +-** Each symbol here is a terminal symbol in the grammar.
    ++/*
    ++** Indicate that sqlite3ParserFree() will never be called with a null
    ++** pointer.
    + */
    +-/* Make sure the INTERFACE macro is defined.
    ++#define fts5YYPARSEFREENOTNULL 1
    ++
    ++/*
    ++** Alternative datatype for the argument to the malloc() routine passed
    ++** into sqlite3ParserAlloc().  The default is size_t.
    + */
    +-#ifndef INTERFACE
    +-# define INTERFACE 1
    +-#endif
    +-/* The next thing included is series of defines which control
    ++#define fts5YYMALLOCARGTYPE  u64
    ++
    ++/**************** End of %include directives **********************************/
    ++/* These constants specify the various numeric values for terminal symbols
    ++** in a format understandable to "makeheaders".  This section is blank unless
    ++** "lemon" is run with the "-m" command-line option.
    ++***************** Begin makeheaders token definitions *************************/
    ++/**************** End makeheaders token definitions ***************************/
    ++
    ++/* The next sections is a series of control #defines.
    + ** various aspects of the generated parser.
    +-**    fts5YYCODETYPE         is the data type used for storing terminal
    +-**                       and nonterminal numbers.  "unsigned char" is
    +-**                       used if there are fewer than 250 terminals
    +-**                       and nonterminals.  "int" is used otherwise.
    +-**    fts5YYNOCODE           is a number of type fts5YYCODETYPE which corresponds
    +-**                       to no legal terminal or nonterminal number.  This
    +-**                       number is used to fill in empty slots of the hash 
    +-**                       table.
    ++**    fts5YYCODETYPE         is the data type used to store the integer codes
    ++**                       that represent terminal and non-terminal symbols.
    ++**                       "unsigned char" is used if there are fewer than
    ++**                       256 symbols.  Larger types otherwise.
    ++**    fts5YYNOCODE           is a number of type fts5YYCODETYPE that is not used for
    ++**                       any terminal or nonterminal symbol.
    + **    fts5YYFALLBACK         If defined, this indicates that one or more tokens
    +-**                       have fall-back values which should be used if the
    +-**                       original value of the token will not parse.
    +-**    fts5YYACTIONTYPE       is the data type used for storing terminal
    +-**                       and nonterminal numbers.  "unsigned char" is
    +-**                       used if there are fewer than 250 rules and
    +-**                       states combined.  "int" is used otherwise.
    +-**    sqlite3Fts5ParserFTS5TOKENTYPE     is the data type used for minor tokens given 
    +-**                       directly to the parser from the tokenizer.
    +-**    fts5YYMINORTYPE        is the data type used for all minor tokens.
    ++**                       (also known as: "terminal symbols") have fall-back
    ++**                       values which should be used if the original symbol
    ++**                       would not parse.  This permits keywords to sometimes
    ++**                       be used as identifiers, for example.
    ++**    fts5YYACTIONTYPE       is the data type used for "action codes" - numbers
    ++**                       that indicate what to do in response to the next
    ++**                       token.
    ++**    sqlite3Fts5ParserFTS5TOKENTYPE     is the data type used for minor type for terminal
    ++**                       symbols.  Background: A "minor type" is a semantic
    ++**                       value associated with a terminal or non-terminal
    ++**                       symbols.  For example, for an "ID" terminal symbol,
    ++**                       the minor type might be the name of the identifier.
    ++**                       Each non-terminal can have a different minor type.
    ++**                       Terminal symbols all have the same minor type, though.
    ++**                       This macros defines the minor type for terminal 
    ++**                       symbols.
    ++**    fts5YYMINORTYPE        is the data type used for all minor types.
    + **                       This is typically a union of many types, one of
    + **                       which is sqlite3Fts5ParserFTS5TOKENTYPE.  The entry in the union
    +-**                       for base tokens is called "fts5yy0".
    ++**                       for terminal symbols is called "fts5yy0".
    + **    fts5YYSTACKDEPTH       is the maximum depth of the parser's stack.  If
    + **                       zero the stack is dynamically sized using realloc()
    + **    sqlite3Fts5ParserARG_SDECL     A static variable declaration for the %extra_argument
    +@@ -166945,26 +187512,32 @@ static int sqlite3Fts5UnicodeFold(int c, int bRemoveDiacritic);
    + **                       defined, then do no error processing.
    + **    fts5YYNSTATE           the combined number of states.
    + **    fts5YYNRULE            the number of rules in the grammar
    ++**    fts5YYNFTS5TOKEN           Number of terminal symbols
    + **    fts5YY_MAX_SHIFT       Maximum value for shift actions
    + **    fts5YY_MIN_SHIFTREDUCE Minimum value for shift-reduce actions
    + **    fts5YY_MAX_SHIFTREDUCE Maximum value for shift-reduce actions
    +-**    fts5YY_MIN_REDUCE      Maximum value for reduce actions
    + **    fts5YY_ERROR_ACTION    The fts5yy_action[] code for syntax error
    + **    fts5YY_ACCEPT_ACTION   The fts5yy_action[] code for accept
    + **    fts5YY_NO_ACTION       The fts5yy_action[] code for no-op
    ++**    fts5YY_MIN_REDUCE      Minimum value for reduce actions
    ++**    fts5YY_MAX_REDUCE      Maximum value for reduce actions
    + */
    ++#ifndef INTERFACE
    ++# define INTERFACE 1
    ++#endif
    ++/************* Begin control #defines *****************************************/
    + #define fts5YYCODETYPE unsigned char
    +-#define fts5YYNOCODE 27
    ++#define fts5YYNOCODE 29
    + #define fts5YYACTIONTYPE unsigned char
    + #define sqlite3Fts5ParserFTS5TOKENTYPE Fts5Token
    + typedef union {
    +   int fts5yyinit;
    +   sqlite3Fts5ParserFTS5TOKENTYPE fts5yy0;
    +-  Fts5Colset* fts5yy3;
    ++  int fts5yy4;
    +   Fts5ExprPhrase* fts5yy11;
    +-  Fts5ExprNode* fts5yy18;
    +-  int fts5yy20;
    +-  Fts5ExprNearset* fts5yy26;
    ++  Fts5ExprNearset* fts5yy14;
    ++  Fts5Colset* fts5yy43;
    ++  Fts5ExprNode* fts5yy54;
    + } fts5YYMINORTYPE;
    + #ifndef fts5YYSTACKDEPTH
    + #define fts5YYSTACKDEPTH 100
    +@@ -166973,20 +187546,18 @@ typedef union {
    + #define sqlite3Fts5ParserARG_PDECL ,Fts5Parse *pParse
    + #define sqlite3Fts5ParserARG_FETCH Fts5Parse *pParse = fts5yypParser->pParse
    + #define sqlite3Fts5ParserARG_STORE fts5yypParser->pParse = pParse
    +-#define fts5YYNSTATE             26
    +-#define fts5YYNRULE              24
    +-#define fts5YY_MAX_SHIFT         25
    +-#define fts5YY_MIN_SHIFTREDUCE   40
    +-#define fts5YY_MAX_SHIFTREDUCE   63
    +-#define fts5YY_MIN_REDUCE        64
    +-#define fts5YY_MAX_REDUCE        87
    +-#define fts5YY_ERROR_ACTION      88
    +-#define fts5YY_ACCEPT_ACTION     89
    +-#define fts5YY_NO_ACTION         90
    +-
    +-/* The fts5yyzerominor constant is used to initialize instances of
    +-** fts5YYMINORTYPE objects to zero. */
    +-static const fts5YYMINORTYPE fts5yyzerominor = { 0 };
    ++#define fts5YYNSTATE             35
    ++#define fts5YYNRULE              28
    ++#define fts5YYNFTS5TOKEN             16
    ++#define fts5YY_MAX_SHIFT         34
    ++#define fts5YY_MIN_SHIFTREDUCE   52
    ++#define fts5YY_MAX_SHIFTREDUCE   79
    ++#define fts5YY_ERROR_ACTION      80
    ++#define fts5YY_ACCEPT_ACTION     81
    ++#define fts5YY_NO_ACTION         82
    ++#define fts5YY_MIN_REDUCE        83
    ++#define fts5YY_MAX_REDUCE        110
    ++/************* End control #defines *******************************************/
    + 
    + /* Define the fts5yytestcase() macro to be a no-op if is not already defined
    + ** otherwise.
    +@@ -167015,9 +187586,6 @@ static const fts5YYMINORTYPE fts5yyzerominor = { 0 };
    + **   N between fts5YY_MIN_SHIFTREDUCE       Shift to an arbitrary state then
    + **     and fts5YY_MAX_SHIFTREDUCE           reduce by rule N-fts5YY_MIN_SHIFTREDUCE.
    + **
    +-**   N between fts5YY_MIN_REDUCE            Reduce by rule N-fts5YY_MIN_REDUCE
    +-**     and fts5YY_MAX_REDUCE
    +-
    + **   N == fts5YY_ERROR_ACTION               A syntax error has occurred.
    + **
    + **   N == fts5YY_ACCEPT_ACTION              The parser accepts its input.
    +@@ -167025,21 +187593,22 @@ static const fts5YYMINORTYPE fts5yyzerominor = { 0 };
    + **   N == fts5YY_NO_ACTION                  No such action.  Denotes unused
    + **                                      slots in the fts5yy_action[] table.
    + **
    ++**   N between fts5YY_MIN_REDUCE            Reduce by rule N-fts5YY_MIN_REDUCE
    ++**     and fts5YY_MAX_REDUCE
    ++**
    + ** The action table is constructed as a single large table named fts5yy_action[].
    +-** Given state S and lookahead X, the action is computed as
    ++** Given state S and lookahead X, the action is computed as either:
    + **
    +-**      fts5yy_action[ fts5yy_shift_ofst[S] + X ]
    ++**    (A)   N = fts5yy_action[ fts5yy_shift_ofst[S] + X ]
    ++**    (B)   N = fts5yy_default[S]
    + **
    +-** If the index value fts5yy_shift_ofst[S]+X is out of range or if the value
    +-** fts5yy_lookahead[fts5yy_shift_ofst[S]+X] is not equal to X or if fts5yy_shift_ofst[S]
    +-** is equal to fts5YY_SHIFT_USE_DFLT, it means that the action is not in the table
    +-** and that fts5yy_default[S] should be used instead.  
    ++** The (A) formula is preferred.  The B formula is used instead if
    ++** fts5yy_lookahead[fts5yy_shift_ofst[S]+X] is not equal to X.
    + **
    +-** The formula above is for computing the action when the lookahead is
    ++** The formulas above are for computing the action when the lookahead is
    + ** a terminal symbol.  If the lookahead is a non-terminal (as occurs after
    + ** a reduce action) then the fts5yy_reduce_ofst[] array is used in place of
    +-** the fts5yy_shift_ofst[] array and fts5YY_REDUCE_USE_DFLT is used in place of
    +-** fts5YY_SHIFT_USE_DFLT.
    ++** the fts5yy_shift_ofst[] array.
    + **
    + ** The following are the tables generated in this section:
    + **
    +@@ -167051,53 +187620,63 @@ static const fts5YYMINORTYPE fts5yyzerominor = { 0 };
    + **  fts5yy_reduce_ofst[]   For each state, the offset into fts5yy_action for
    + **                     shifting non-terminals after a reduce.
    + **  fts5yy_default[]       Default action for each state.
    +-*/
    +-#define fts5YY_ACTTAB_COUNT (78)
    ++**
    ++*********** Begin parsing tables **********************************************/
    ++#define fts5YY_ACTTAB_COUNT (105)
    + static const fts5YYACTIONTYPE fts5yy_action[] = {
    +- /*     0 */    89,   15,   46,    5,   48,   24,   12,   19,   23,   14,
    +- /*    10 */    46,    5,   48,   24,   20,   21,   23,   43,   46,    5,
    +- /*    20 */    48,   24,    6,   18,   23,   17,   46,    5,   48,   24,
    +- /*    30 */    75,    7,   23,   25,   46,    5,   48,   24,   62,   47,
    +- /*    40 */    23,   48,   24,    7,   11,   23,    9,    3,    4,    2,
    +- /*    50 */    62,   50,   52,   44,   64,    3,    4,    2,   49,    4,
    +- /*    60 */     2,    1,   23,   11,   16,    9,   12,    2,   10,   61,
    +- /*    70 */    53,   59,   62,   60,   22,   13,   55,    8,
    ++ /*     0 */    81,   20,   96,    6,   28,   99,   98,   26,   26,   18,
    ++ /*    10 */    96,    6,   28,   17,   98,   56,   26,   19,   96,    6,
    ++ /*    20 */    28,   14,   98,  108,   26,   92,   96,    6,   28,   25,
    ++ /*    30 */    98,   78,   26,   21,   96,    6,   28,  107,   98,   58,
    ++ /*    40 */    26,   29,   96,    6,   28,   32,   98,   22,   26,   24,
    ++ /*    50 */    16,   23,   11,    1,   14,   13,   24,   16,   31,   11,
    ++ /*    60 */     3,   97,   13,   27,    8,   98,   82,   26,    7,    4,
    ++ /*    70 */     5,    3,    4,    5,    3,   83,    4,    5,    3,   63,
    ++ /*    80 */    33,   34,   62,   12,    2,   86,   13,   10,   12,   71,
    ++ /*    90 */    10,   13,   78,    5,    3,   78,    9,   30,   75,   82,
    ++ /*   100 */    54,   57,   53,   57,   15,
    + };
    + static const fts5YYCODETYPE fts5yy_lookahead[] = {
    +- /*     0 */    15,   16,   17,   18,   19,   20,   10,   11,   23,   16,
    +- /*    10 */    17,   18,   19,   20,   23,   24,   23,   16,   17,   18,
    +- /*    20 */    19,   20,   22,   23,   23,   16,   17,   18,   19,   20,
    +- /*    30 */     5,    6,   23,   16,   17,   18,   19,   20,   13,   17,
    +- /*    40 */    23,   19,   20,    6,    8,   23,   10,    1,    2,    3,
    +- /*    50 */    13,    9,   10,    7,    0,    1,    2,    3,   19,    2,
    +- /*    60 */     3,    6,   23,    8,   21,   10,   10,    3,   10,   25,
    +- /*    70 */    10,   10,   13,   25,   12,   10,    7,    5,
    ++ /*     0 */    17,   18,   19,   20,   21,   23,   23,   25,   25,   18,
    ++ /*    10 */    19,   20,   21,    7,   23,    9,   25,   18,   19,   20,
    ++ /*    20 */    21,    9,   23,   27,   25,   18,   19,   20,   21,   25,
    ++ /*    30 */    23,   15,   25,   18,   19,   20,   21,   27,   23,    9,
    ++ /*    40 */    25,   18,   19,   20,   21,   14,   23,   22,   25,    6,
    ++ /*    50 */     7,   22,    9,   10,    9,   12,    6,    7,   13,    9,
    ++ /*    60 */     3,   19,   12,   21,    5,   23,   28,   25,    5,    1,
    ++ /*    70 */     2,    3,    1,    2,    3,    0,    1,    2,    3,   11,
    ++ /*    80 */    25,   26,   11,    9,   10,    5,   12,   10,    9,   11,
    ++ /*    90 */    10,   12,   15,    2,    3,   15,   24,   25,    9,   28,
    ++ /*   100 */     8,    9,    8,    9,    9,   28,   28,   28,   28,   28,
    ++ /*   110 */    28,   28,   28,   28,   28,   28,   28,   28,   28,   28,
    ++ /*   120 */    28,
    + };
    +-#define fts5YY_SHIFT_USE_DFLT (-5)
    +-#define fts5YY_SHIFT_COUNT (25)
    +-#define fts5YY_SHIFT_MIN   (-4)
    +-#define fts5YY_SHIFT_MAX   (72)
    +-static const signed char fts5yy_shift_ofst[] = {
    +- /*     0 */    55,   55,   55,   55,   55,   36,   -4,   56,   58,   25,
    +- /*    10 */    37,   60,   59,   59,   46,   54,   42,   57,   62,   61,
    +- /*    20 */    62,   69,   65,   62,   72,   64,
    ++#define fts5YY_SHIFT_COUNT    (34)
    ++#define fts5YY_SHIFT_MIN      (0)
    ++#define fts5YY_SHIFT_MAX      (95)
    ++static const unsigned char fts5yy_shift_ofst[] = {
    ++ /*     0 */    43,   43,   43,   43,   43,   43,   50,   74,   79,   45,
    ++ /*    10 */    12,   80,   77,   12,   16,   16,   30,   30,   68,   71,
    ++ /*    20 */    75,   91,   92,   94,    6,   31,   31,   59,   63,   57,
    ++ /*    30 */    31,   89,   95,   31,   78,
    + };
    +-#define fts5YY_REDUCE_USE_DFLT (-16)
    +-#define fts5YY_REDUCE_COUNT (13)
    +-#define fts5YY_REDUCE_MIN   (-15)
    +-#define fts5YY_REDUCE_MAX   (48)
    ++#define fts5YY_REDUCE_COUNT (17)
    ++#define fts5YY_REDUCE_MIN   (-18)
    ++#define fts5YY_REDUCE_MAX   (72)
    + static const signed char fts5yy_reduce_ofst[] = {
    +- /*     0 */   -15,   -7,    1,    9,   17,   22,   -9,    0,   39,   44,
    +- /*    10 */    44,   43,   44,   48,
    ++ /*     0 */   -17,   -9,   -1,    7,   15,   23,   42,  -18,  -18,   55,
    ++ /*    10 */    72,   -4,   -4,    4,   -4,   10,   25,   29,
    + };
    + static const fts5YYACTIONTYPE fts5yy_default[] = {
    +- /*     0 */    88,   88,   88,   88,   88,   69,   82,   88,   88,   87,
    +- /*    10 */    87,   88,   87,   87,   88,   88,   88,   66,   80,   88,
    +- /*    20 */    81,   88,   88,   78,   88,   65,
    ++ /*     0 */    80,   80,   80,   80,   80,   80,   95,   80,   80,  105,
    ++ /*    10 */    80,  110,  110,   80,  110,  110,   80,   80,   80,   80,
    ++ /*    20 */    80,   91,   80,   80,   80,  101,  100,   80,   80,   90,
    ++ /*    30 */   103,   80,   80,  104,   80,
    + };
    ++/********** End of lemon-generated parsing tables *****************************/
    + 
    +-/* The next table maps tokens into fallback tokens.  If a construct
    +-** like the following:
    ++/* The next table maps tokens (terminal symbols) into fallback tokens.  
    ++** If a construct like the following:
    + ** 
    + **      %fallback ID X Y Z.
    + **
    +@@ -167105,6 +187684,10 @@ static const fts5YYACTIONTYPE fts5yy_default[] = {
    + ** and Z.  Whenever one of the tokens X, Y, or Z is input to the parser
    + ** but it does not parse, the type of the token is changed to ID and
    + ** the parse is retried before an error is thrown.
    ++**
    ++** This feature can be used, for example, to cause some keywords in a language
    ++** to revert to identifiers if they keyword does not apply in the context where
    ++** it appears.
    + */
    + #ifdef fts5YYFALLBACK
    + static const fts5YYCODETYPE fts5yyFallback[] = {
    +@@ -167139,17 +187722,21 @@ typedef struct fts5yyStackEntry fts5yyStackEntry;
    + /* The state of the parser is completely contained in an instance of
    + ** the following structure */
    + struct fts5yyParser {
    +-  int fts5yyidx;                    /* Index of top element in stack */
    ++  fts5yyStackEntry *fts5yytos;          /* Pointer to top element of the stack */
    + #ifdef fts5YYTRACKMAXSTACKDEPTH
    +-  int fts5yyidxMax;                 /* Maximum value of fts5yyidx */
    ++  int fts5yyhwm;                    /* High-water mark of the stack */
    + #endif
    ++#ifndef fts5YYNOERRORRECOVERY
    +   int fts5yyerrcnt;                 /* Shifts left before out of the error */
    ++#endif
    +   sqlite3Fts5ParserARG_SDECL                /* A place to hold %extra_argument */
    + #if fts5YYSTACKDEPTH<=0
    +   int fts5yystksz;                  /* Current side of the stack */
    +   fts5yyStackEntry *fts5yystack;        /* The parser's stack */
    ++  fts5yyStackEntry fts5yystk0;          /* First stack entry */
    + #else
    +   fts5yyStackEntry fts5yystack[fts5YYSTACKDEPTH];  /* The parser's stack */
    ++  fts5yyStackEntry *fts5yystackEnd;            /* Last entry in the stack */
    + #endif
    + };
    + typedef struct fts5yyParser fts5yyParser;
    +@@ -167186,75 +187773,147 @@ static void sqlite3Fts5ParserTrace(FILE *TraceFILE, char *zTracePrompt){
    + }
    + #endif /* NDEBUG */
    + 
    +-#ifndef NDEBUG
    ++#if defined(fts5YYCOVERAGE) || !defined(NDEBUG)
    + /* For tracing shifts, the names of all terminals and nonterminals
    + ** are required.  The following table supplies these names */
    + static const char *const fts5yyTokenName[] = { 
    +-  "$",             "OR",            "AND",           "NOT",         
    +-  "TERM",          "COLON",         "LP",            "RP",          
    +-  "LCP",           "RCP",           "STRING",        "COMMA",       
    +-  "PLUS",          "STAR",          "error",         "input",       
    +-  "expr",          "cnearset",      "exprlist",      "nearset",     
    +-  "colset",        "colsetlist",    "nearphrases",   "phrase",      
    +-  "neardist_opt",  "star_opt",    
    ++  /*    0 */ "$",
    ++  /*    1 */ "OR",
    ++  /*    2 */ "AND",
    ++  /*    3 */ "NOT",
    ++  /*    4 */ "TERM",
    ++  /*    5 */ "COLON",
    ++  /*    6 */ "MINUS",
    ++  /*    7 */ "LCP",
    ++  /*    8 */ "RCP",
    ++  /*    9 */ "STRING",
    ++  /*   10 */ "LP",
    ++  /*   11 */ "RP",
    ++  /*   12 */ "CARET",
    ++  /*   13 */ "COMMA",
    ++  /*   14 */ "PLUS",
    ++  /*   15 */ "STAR",
    ++  /*   16 */ "error",
    ++  /*   17 */ "input",
    ++  /*   18 */ "expr",
    ++  /*   19 */ "cnearset",
    ++  /*   20 */ "exprlist",
    ++  /*   21 */ "colset",
    ++  /*   22 */ "colsetlist",
    ++  /*   23 */ "nearset",
    ++  /*   24 */ "nearphrases",
    ++  /*   25 */ "phrase",
    ++  /*   26 */ "neardist_opt",
    ++  /*   27 */ "star_opt",
    + };
    +-#endif /* NDEBUG */
    ++#endif /* defined(fts5YYCOVERAGE) || !defined(NDEBUG) */
    + 
    + #ifndef NDEBUG
    + /* For tracing reduce actions, the names of all rules are required.
    + */
    + static const char *const fts5yyRuleName[] = {
    +  /*   0 */ "input ::= expr",
    +- /*   1 */ "expr ::= expr AND expr",
    +- /*   2 */ "expr ::= expr OR expr",
    +- /*   3 */ "expr ::= expr NOT expr",
    +- /*   4 */ "expr ::= LP expr RP",
    +- /*   5 */ "expr ::= exprlist",
    +- /*   6 */ "exprlist ::= cnearset",
    +- /*   7 */ "exprlist ::= exprlist cnearset",
    +- /*   8 */ "cnearset ::= nearset",
    +- /*   9 */ "cnearset ::= colset COLON nearset",
    +- /*  10 */ "colset ::= LCP colsetlist RCP",
    +- /*  11 */ "colset ::= STRING",
    +- /*  12 */ "colsetlist ::= colsetlist STRING",
    +- /*  13 */ "colsetlist ::= STRING",
    +- /*  14 */ "nearset ::= phrase",
    +- /*  15 */ "nearset ::= STRING LP nearphrases neardist_opt RP",
    +- /*  16 */ "nearphrases ::= phrase",
    +- /*  17 */ "nearphrases ::= nearphrases phrase",
    +- /*  18 */ "neardist_opt ::=",
    +- /*  19 */ "neardist_opt ::= COMMA STRING",
    +- /*  20 */ "phrase ::= phrase PLUS STRING star_opt",
    +- /*  21 */ "phrase ::= STRING star_opt",
    +- /*  22 */ "star_opt ::= STAR",
    +- /*  23 */ "star_opt ::=",
    ++ /*   1 */ "colset ::= MINUS LCP colsetlist RCP",
    ++ /*   2 */ "colset ::= LCP colsetlist RCP",
    ++ /*   3 */ "colset ::= STRING",
    ++ /*   4 */ "colset ::= MINUS STRING",
    ++ /*   5 */ "colsetlist ::= colsetlist STRING",
    ++ /*   6 */ "colsetlist ::= STRING",
    ++ /*   7 */ "expr ::= expr AND expr",
    ++ /*   8 */ "expr ::= expr OR expr",
    ++ /*   9 */ "expr ::= expr NOT expr",
    ++ /*  10 */ "expr ::= colset COLON LP expr RP",
    ++ /*  11 */ "expr ::= LP expr RP",
    ++ /*  12 */ "expr ::= exprlist",
    ++ /*  13 */ "exprlist ::= cnearset",
    ++ /*  14 */ "exprlist ::= exprlist cnearset",
    ++ /*  15 */ "cnearset ::= nearset",
    ++ /*  16 */ "cnearset ::= colset COLON nearset",
    ++ /*  17 */ "nearset ::= phrase",
    ++ /*  18 */ "nearset ::= CARET phrase",
    ++ /*  19 */ "nearset ::= STRING LP nearphrases neardist_opt RP",
    ++ /*  20 */ "nearphrases ::= phrase",
    ++ /*  21 */ "nearphrases ::= nearphrases phrase",
    ++ /*  22 */ "neardist_opt ::=",
    ++ /*  23 */ "neardist_opt ::= COMMA STRING",
    ++ /*  24 */ "phrase ::= phrase PLUS STRING star_opt",
    ++ /*  25 */ "phrase ::= STRING star_opt",
    ++ /*  26 */ "star_opt ::= STAR",
    ++ /*  27 */ "star_opt ::=",
    + };
    + #endif /* NDEBUG */
    + 
    + 
    + #if fts5YYSTACKDEPTH<=0
    + /*
    +-** Try to increase the size of the parser stack.
    ++** Try to increase the size of the parser stack.  Return the number
    ++** of errors.  Return 0 on success.
    + */
    +-static void fts5yyGrowStack(fts5yyParser *p){
    ++static int fts5yyGrowStack(fts5yyParser *p){
    +   int newSize;
    ++  int idx;
    +   fts5yyStackEntry *pNew;
    + 
    +   newSize = p->fts5yystksz*2 + 100;
    +-  pNew = realloc(p->fts5yystack, newSize*sizeof(pNew[0]));
    ++  idx = p->fts5yytos ? (int)(p->fts5yytos - p->fts5yystack) : 0;
    ++  if( p->fts5yystack==&p->fts5yystk0 ){
    ++    pNew = malloc(newSize*sizeof(pNew[0]));
    ++    if( pNew ) pNew[0] = p->fts5yystk0;
    ++  }else{
    ++    pNew = realloc(p->fts5yystack, newSize*sizeof(pNew[0]));
    ++  }
    +   if( pNew ){
    +     p->fts5yystack = pNew;
    +-    p->fts5yystksz = newSize;
    ++    p->fts5yytos = &p->fts5yystack[idx];
    + #ifndef NDEBUG
    +     if( fts5yyTraceFILE ){
    +-      fprintf(fts5yyTraceFILE,"%sStack grows to %d entries!\n",
    +-              fts5yyTracePrompt, p->fts5yystksz);
    ++      fprintf(fts5yyTraceFILE,"%sStack grows from %d to %d entries.\n",
    ++              fts5yyTracePrompt, p->fts5yystksz, newSize);
    +     }
    + #endif
    ++    p->fts5yystksz = newSize;
    +   }
    ++  return pNew==0; 
    + }
    + #endif
    + 
    ++/* Datatype of the argument to the memory allocated passed as the
    ++** second argument to sqlite3Fts5ParserAlloc() below.  This can be changed by
    ++** putting an appropriate #define in the %include section of the input
    ++** grammar.
    ++*/
    ++#ifndef fts5YYMALLOCARGTYPE
    ++# define fts5YYMALLOCARGTYPE size_t
    ++#endif
    ++
    ++/* Initialize a new parser that has already been allocated.
    ++*/
    ++static void sqlite3Fts5ParserInit(void *fts5yypParser){
    ++  fts5yyParser *pParser = (fts5yyParser*)fts5yypParser;
    ++#ifdef fts5YYTRACKMAXSTACKDEPTH
    ++  pParser->fts5yyhwm = 0;
    ++#endif
    ++#if fts5YYSTACKDEPTH<=0
    ++  pParser->fts5yytos = NULL;
    ++  pParser->fts5yystack = NULL;
    ++  pParser->fts5yystksz = 0;
    ++  if( fts5yyGrowStack(pParser) ){
    ++    pParser->fts5yystack = &pParser->fts5yystk0;
    ++    pParser->fts5yystksz = 1;
    ++  }
    ++#endif
    ++#ifndef fts5YYNOERRORRECOVERY
    ++  pParser->fts5yyerrcnt = -1;
    ++#endif
    ++  pParser->fts5yytos = pParser->fts5yystack;
    ++  pParser->fts5yystack[0].stateno = 0;
    ++  pParser->fts5yystack[0].major = 0;
    ++#if fts5YYSTACKDEPTH>0
    ++  pParser->fts5yystackEnd = &pParser->fts5yystack[fts5YYSTACKDEPTH-1];
    ++#endif
    ++}
    ++
    ++#ifndef sqlite3Fts5Parser_ENGINEALWAYSONSTACK
    + /* 
    + ** This function allocates a new parser.
    + ** The only argument is a pointer to a function which works like
    +@@ -167267,27 +187926,21 @@ static void fts5yyGrowStack(fts5yyParser *p){
    + ** A pointer to a parser.  This pointer is used in subsequent calls
    + ** to sqlite3Fts5Parser and sqlite3Fts5ParserFree.
    + */
    +-static void *sqlite3Fts5ParserAlloc(void *(*mallocProc)(u64)){
    ++static void *sqlite3Fts5ParserAlloc(void *(*mallocProc)(fts5YYMALLOCARGTYPE)){
    +   fts5yyParser *pParser;
    +-  pParser = (fts5yyParser*)(*mallocProc)( (u64)sizeof(fts5yyParser) );
    +-  if( pParser ){
    +-    pParser->fts5yyidx = -1;
    +-#ifdef fts5YYTRACKMAXSTACKDEPTH
    +-    pParser->fts5yyidxMax = 0;
    +-#endif
    +-#if fts5YYSTACKDEPTH<=0
    +-    pParser->fts5yystack = NULL;
    +-    pParser->fts5yystksz = 0;
    +-    fts5yyGrowStack(pParser);
    +-#endif
    +-  }
    ++  pParser = (fts5yyParser*)(*mallocProc)( (fts5YYMALLOCARGTYPE)sizeof(fts5yyParser) );
    ++  if( pParser ) sqlite3Fts5ParserInit(pParser);
    +   return pParser;
    + }
    ++#endif /* sqlite3Fts5Parser_ENGINEALWAYSONSTACK */
    + 
    +-/* The following function deletes the value associated with a
    +-** symbol.  The symbol can be either a terminal or nonterminal.
    +-** "fts5yymajor" is the symbol code, and "fts5yypminor" is a pointer to
    +-** the value.
    ++
    ++/* The following function deletes the "minor type" or semantic value
    ++** associated with a symbol.  The symbol can be either a terminal
    ++** or nonterminal. "fts5yymajor" is the symbol code, and "fts5yypminor" is
    ++** a pointer to the value to be deleted.  The code used to do the 
    ++** deletions is derived from the %destructor and/or %token_destructor
    ++** directives of the input grammar.
    + */
    + static void fts5yy_destructor(
    +   fts5yyParser *fts5yypParser,    /* The parser */
    +@@ -167303,38 +187956,40 @@ static void fts5yy_destructor(
    +     ** being destroyed before it is finished parsing.
    +     **
    +     ** Note: during a reduce, the only symbols destroyed are those
    +-    ** which appear on the RHS of the rule, but which are not used
    ++    ** which appear on the RHS of the rule, but which are *not* used
    +     ** inside the C code.
    +     */
    +-    case 15: /* input */
    ++/********* Begin destructor definitions ***************************************/
    ++    case 17: /* input */
    + {
    +  (void)pParse; 
    + }
    +       break;
    +-    case 16: /* expr */
    +-    case 17: /* cnearset */
    +-    case 18: /* exprlist */
    ++    case 18: /* expr */
    ++    case 19: /* cnearset */
    ++    case 20: /* exprlist */
    + {
    +- sqlite3Fts5ParseNodeFree((fts5yypminor->fts5yy18)); 
    ++ sqlite3Fts5ParseNodeFree((fts5yypminor->fts5yy54)); 
    + }
    +       break;
    +-    case 19: /* nearset */
    +-    case 22: /* nearphrases */
    ++    case 21: /* colset */
    ++    case 22: /* colsetlist */
    + {
    +- sqlite3Fts5ParseNearsetFree((fts5yypminor->fts5yy26)); 
    ++ sqlite3_free((fts5yypminor->fts5yy43)); 
    + }
    +       break;
    +-    case 20: /* colset */
    +-    case 21: /* colsetlist */
    ++    case 23: /* nearset */
    ++    case 24: /* nearphrases */
    + {
    +- sqlite3_free((fts5yypminor->fts5yy3)); 
    ++ sqlite3Fts5ParseNearsetFree((fts5yypminor->fts5yy14)); 
    + }
    +       break;
    +-    case 23: /* phrase */
    ++    case 25: /* phrase */
    + {
    +  sqlite3Fts5ParsePhraseFree((fts5yypminor->fts5yy11)); 
    + }
    +       break;
    ++/********* End destructor definitions *****************************************/
    +     default:  break;   /* If no destructor action specified: do nothing */
    +   }
    + }
    +@@ -167344,55 +187999,53 @@ static void fts5yy_destructor(
    + **
    + ** If there is a destructor routine associated with the token which
    + ** is popped from the stack, then call it.
    +-**
    +-** Return the major token number for the symbol popped.
    + */
    +-static int fts5yy_pop_parser_stack(fts5yyParser *pParser){
    +-  fts5YYCODETYPE fts5yymajor;
    +-  fts5yyStackEntry *fts5yytos = &pParser->fts5yystack[pParser->fts5yyidx];
    +-
    +-  /* There is no mechanism by which the parser stack can be popped below
    +-  ** empty in SQLite.  */
    +-  assert( pParser->fts5yyidx>=0 );
    ++static void fts5yy_pop_parser_stack(fts5yyParser *pParser){
    ++  fts5yyStackEntry *fts5yytos;
    ++  assert( pParser->fts5yytos!=0 );
    ++  assert( pParser->fts5yytos > pParser->fts5yystack );
    ++  fts5yytos = pParser->fts5yytos--;
    + #ifndef NDEBUG
    +-  if( fts5yyTraceFILE && pParser->fts5yyidx>=0 ){
    ++  if( fts5yyTraceFILE ){
    +     fprintf(fts5yyTraceFILE,"%sPopping %s\n",
    +       fts5yyTracePrompt,
    +       fts5yyTokenName[fts5yytos->major]);
    +   }
    + #endif
    +-  fts5yymajor = fts5yytos->major;
    +-  fts5yy_destructor(pParser, fts5yymajor, &fts5yytos->minor);
    +-  pParser->fts5yyidx--;
    +-  return fts5yymajor;
    ++  fts5yy_destructor(pParser, fts5yytos->major, &fts5yytos->minor);
    ++}
    ++
    ++/*
    ++** Clear all secondary memory allocations from the parser
    ++*/
    ++static void sqlite3Fts5ParserFinalize(void *p){
    ++  fts5yyParser *pParser = (fts5yyParser*)p;
    ++  while( pParser->fts5yytos>pParser->fts5yystack ) fts5yy_pop_parser_stack(pParser);
    ++#if fts5YYSTACKDEPTH<=0
    ++  if( pParser->fts5yystack!=&pParser->fts5yystk0 ) free(pParser->fts5yystack);
    ++#endif
    + }
    + 
    ++#ifndef sqlite3Fts5Parser_ENGINEALWAYSONSTACK
    + /* 
    +-** Deallocate and destroy a parser.  Destructors are all called for
    ++** Deallocate and destroy a parser.  Destructors are called for
    + ** all stack elements before shutting the parser down.
    + **
    +-** Inputs:
    +-** <ul>
    +-** <li>  A pointer to the parser.  This should be a pointer
    +-**       obtained from sqlite3Fts5ParserAlloc.
    +-** <li>  A pointer to a function used to reclaim memory obtained
    +-**       from malloc.
    +-** </ul>
    ++** If the fts5YYPARSEFREENEVERNULL macro exists (for example because it
    ++** is defined in a %include section of the input grammar) then it is
    ++** assumed that the input pointer is never NULL.
    + */
    + static void sqlite3Fts5ParserFree(
    +   void *p,                    /* The parser to be deleted */
    +   void (*freeProc)(void*)     /* Function used to reclaim memory */
    + ){
    +-  fts5yyParser *pParser = (fts5yyParser*)p;
    +-  /* In SQLite, we never try to destroy a parser that was not successfully
    +-  ** created in the first place. */
    +-  if( NEVER(pParser==0) ) return;
    +-  while( pParser->fts5yyidx>=0 ) fts5yy_pop_parser_stack(pParser);
    +-#if fts5YYSTACKDEPTH<=0
    +-  free(pParser->fts5yystack);
    ++#ifndef fts5YYPARSEFREENEVERNULL
    ++  if( p==0 ) return;
    + #endif
    +-  (*freeProc)((void*)pParser);
    ++  sqlite3Fts5ParserFinalize(p);
    ++  (*freeProc)(p);
    + }
    ++#endif /* sqlite3Fts5Parser_ENGINEALWAYSONSTACK */
    + 
    + /*
    + ** Return the peak depth of the stack for a parser.
    +@@ -167400,33 +188053,70 @@ static void sqlite3Fts5ParserFree(
    + #ifdef fts5YYTRACKMAXSTACKDEPTH
    + static int sqlite3Fts5ParserStackPeak(void *p){
    +   fts5yyParser *pParser = (fts5yyParser*)p;
    +-  return pParser->fts5yyidxMax;
    ++  return pParser->fts5yyhwm;
    ++}
    ++#endif
    ++
    ++/* This array of booleans keeps track of the parser statement
    ++** coverage.  The element fts5yycoverage[X][Y] is set when the parser
    ++** is in state X and has a lookahead token Y.  In a well-tested
    ++** systems, every element of this matrix should end up being set.
    ++*/
    ++#if defined(fts5YYCOVERAGE)
    ++static unsigned char fts5yycoverage[fts5YYNSTATE][fts5YYNFTS5TOKEN];
    ++#endif
    ++
    ++/*
    ++** Write into out a description of every state/lookahead combination that
    ++**
    ++**   (1)  has not been used by the parser, and
    ++**   (2)  is not a syntax error.
    ++**
    ++** Return the number of missed state/lookahead combinations.
    ++*/
    ++#if defined(fts5YYCOVERAGE)
    ++static int sqlite3Fts5ParserCoverage(FILE *out){
    ++  int stateno, iLookAhead, i;
    ++  int nMissed = 0;
    ++  for(stateno=0; stateno<fts5YYNSTATE; stateno++){
    ++    i = fts5yy_shift_ofst[stateno];
    ++    for(iLookAhead=0; iLookAhead<fts5YYNFTS5TOKEN; iLookAhead++){
    ++      if( fts5yy_lookahead[i+iLookAhead]!=iLookAhead ) continue;
    ++      if( fts5yycoverage[stateno][iLookAhead]==0 ) nMissed++;
    ++      if( out ){
    ++        fprintf(out,"State %d lookahead %s %s\n", stateno,
    ++                fts5yyTokenName[iLookAhead],
    ++                fts5yycoverage[stateno][iLookAhead] ? "ok" : "missed");
    ++      }
    ++    }
    ++  }
    ++  return nMissed;
    + }
    + #endif
    + 
    + /*
    + ** Find the appropriate action for a parser given the terminal
    + ** look-ahead token iLookAhead.
    +-**
    +-** If the look-ahead token is fts5YYNOCODE, then check to see if the action is
    +-** independent of the look-ahead.  If it is, return the action, otherwise
    +-** return fts5YY_NO_ACTION.
    + */
    +-static int fts5yy_find_shift_action(
    ++static unsigned int fts5yy_find_shift_action(
    +   fts5yyParser *pParser,        /* The parser */
    +   fts5YYCODETYPE iLookAhead     /* The look-ahead token */
    + ){
    +   int i;
    +-  int stateno = pParser->fts5yystack[pParser->fts5yyidx].stateno;
    ++  int stateno = pParser->fts5yytos->stateno;
    +  
    +-  if( stateno>=fts5YY_MIN_REDUCE ) return stateno;
    ++  if( stateno>fts5YY_MAX_SHIFT ) return stateno;
    +   assert( stateno <= fts5YY_SHIFT_COUNT );
    +-  i = fts5yy_shift_ofst[stateno];
    +-  if( i==fts5YY_SHIFT_USE_DFLT ) return fts5yy_default[stateno];
    +-  assert( iLookAhead!=fts5YYNOCODE );
    +-  i += iLookAhead;
    +-  if( i<0 || i>=fts5YY_ACTTAB_COUNT || fts5yy_lookahead[i]!=iLookAhead ){
    +-    if( iLookAhead>0 ){
    ++#if defined(fts5YYCOVERAGE)
    ++  fts5yycoverage[stateno][iLookAhead] = 1;
    ++#endif
    ++  do{
    ++    i = fts5yy_shift_ofst[stateno];
    ++    assert( i>=0 && i+fts5YYNFTS5TOKEN<=sizeof(fts5yy_lookahead)/sizeof(fts5yy_lookahead[0]) );
    ++    assert( iLookAhead!=fts5YYNOCODE );
    ++    assert( iLookAhead < fts5YYNFTS5TOKEN );
    ++    i += iLookAhead;
    ++    if( fts5yy_lookahead[i]!=iLookAhead ){
    + #ifdef fts5YYFALLBACK
    +       fts5YYCODETYPE iFallback;            /* Fallback token */
    +       if( iLookAhead<sizeof(fts5yyFallback)/sizeof(fts5yyFallback[0])
    +@@ -167437,7 +188127,9 @@ static int fts5yy_find_shift_action(
    +              fts5yyTracePrompt, fts5yyTokenName[iLookAhead], fts5yyTokenName[iFallback]);
    +         }
    + #endif
    +-        return fts5yy_find_shift_action(pParser, iFallback);
    ++        assert( fts5yyFallback[iFallback]==0 ); /* Fallback loop must terminate */
    ++        iLookAhead = iFallback;
    ++        continue;
    +       }
    + #endif
    + #ifdef fts5YYWILDCARD
    +@@ -167450,32 +188142,29 @@ static int fts5yy_find_shift_action(
    + #if fts5YY_SHIFT_MAX+fts5YYWILDCARD>=fts5YY_ACTTAB_COUNT
    +           j<fts5YY_ACTTAB_COUNT &&
    + #endif
    +-          fts5yy_lookahead[j]==fts5YYWILDCARD
    ++          fts5yy_lookahead[j]==fts5YYWILDCARD && iLookAhead>0
    +         ){
    + #ifndef NDEBUG
    +           if( fts5yyTraceFILE ){
    +             fprintf(fts5yyTraceFILE, "%sWILDCARD %s => %s\n",
    +-               fts5yyTracePrompt, fts5yyTokenName[iLookAhead], fts5yyTokenName[fts5YYWILDCARD]);
    ++               fts5yyTracePrompt, fts5yyTokenName[iLookAhead],
    ++               fts5yyTokenName[fts5YYWILDCARD]);
    +           }
    + #endif /* NDEBUG */
    +           return fts5yy_action[j];
    +         }
    +       }
    + #endif /* fts5YYWILDCARD */
    ++      return fts5yy_default[stateno];
    ++    }else{
    ++      return fts5yy_action[i];
    +     }
    +-    return fts5yy_default[stateno];
    +-  }else{
    +-    return fts5yy_action[i];
    +-  }
    ++  }while(1);
    + }
    + 
    + /*
    + ** Find the appropriate action for a parser given the non-terminal
    + ** look-ahead token iLookAhead.
    +-**
    +-** If the look-ahead token is fts5YYNOCODE, then check to see if the action is
    +-** independent of the look-ahead.  If it is, return the action, otherwise
    +-** return fts5YY_NO_ACTION.
    + */
    + static int fts5yy_find_reduce_action(
    +   int stateno,              /* Current state number */
    +@@ -167490,7 +188179,6 @@ static int fts5yy_find_reduce_action(
    +   assert( stateno<=fts5YY_REDUCE_COUNT );
    + #endif
    +   i = fts5yy_reduce_ofst[stateno];
    +-  assert( i!=fts5YY_REDUCE_USE_DFLT );
    +   assert( iLookAhead!=fts5YYNOCODE );
    +   i += iLookAhead;
    + #ifdef fts5YYERRORSYMBOL
    +@@ -167507,19 +188195,20 @@ static int fts5yy_find_reduce_action(
    + /*
    + ** The following routine is called if the stack overflows.
    + */
    +-static void fts5yyStackOverflow(fts5yyParser *fts5yypParser, fts5YYMINORTYPE *fts5yypMinor){
    ++static void fts5yyStackOverflow(fts5yyParser *fts5yypParser){
    +    sqlite3Fts5ParserARG_FETCH;
    +-   fts5yypParser->fts5yyidx--;
    + #ifndef NDEBUG
    +    if( fts5yyTraceFILE ){
    +      fprintf(fts5yyTraceFILE,"%sStack Overflow!\n",fts5yyTracePrompt);
    +    }
    + #endif
    +-   while( fts5yypParser->fts5yyidx>=0 ) fts5yy_pop_parser_stack(fts5yypParser);
    ++   while( fts5yypParser->fts5yytos>fts5yypParser->fts5yystack ) fts5yy_pop_parser_stack(fts5yypParser);
    +    /* Here code is inserted which will execute if the parser
    +    ** stack every overflows */
    ++/******** Begin %stack_overflow code ******************************************/
    + 
    +-  assert( 0 );
    ++  sqlite3Fts5ParseError(pParse, "fts5: parser stack overflow");
    ++/******** End %stack_overflow code ********************************************/
    +    sqlite3Fts5ParserARG_STORE; /* Suppress warning about unused %extra_argument var */
    + }
    + 
    +@@ -167527,92 +188216,100 @@ static void fts5yyStackOverflow(fts5yyParser *fts5yypParser, fts5YYMINORTYPE *ft
    + ** Print tracing information for a SHIFT action
    + */
    + #ifndef NDEBUG
    +-static void fts5yyTraceShift(fts5yyParser *fts5yypParser, int fts5yyNewState){
    ++static void fts5yyTraceShift(fts5yyParser *fts5yypParser, int fts5yyNewState, const char *zTag){
    +   if( fts5yyTraceFILE ){
    +-    int i;
    +     if( fts5yyNewState<fts5YYNSTATE ){
    +-      fprintf(fts5yyTraceFILE,"%sShift %d\n",fts5yyTracePrompt,fts5yyNewState);
    +-      fprintf(fts5yyTraceFILE,"%sStack:",fts5yyTracePrompt);
    +-      for(i=1; i<=fts5yypParser->fts5yyidx; i++)
    +-        fprintf(fts5yyTraceFILE," %s",fts5yyTokenName[fts5yypParser->fts5yystack[i].major]);
    +-      fprintf(fts5yyTraceFILE,"\n");
    ++      fprintf(fts5yyTraceFILE,"%s%s '%s', go to state %d\n",
    ++         fts5yyTracePrompt, zTag, fts5yyTokenName[fts5yypParser->fts5yytos->major],
    ++         fts5yyNewState);
    +     }else{
    +-      fprintf(fts5yyTraceFILE,"%sShift *\n",fts5yyTracePrompt);
    ++      fprintf(fts5yyTraceFILE,"%s%s '%s', pending reduce %d\n",
    ++         fts5yyTracePrompt, zTag, fts5yyTokenName[fts5yypParser->fts5yytos->major],
    ++         fts5yyNewState - fts5YY_MIN_REDUCE);
    +     }
    +   }
    + }
    + #else
    +-# define fts5yyTraceShift(X,Y)
    ++# define fts5yyTraceShift(X,Y,Z)
    + #endif
    + 
    + /*
    +-** Perform a shift action.  Return the number of errors.
    ++** Perform a shift action.
    + */
    + static void fts5yy_shift(
    +   fts5yyParser *fts5yypParser,          /* The parser to be shifted */
    +   int fts5yyNewState,               /* The new state to shift in */
    +   int fts5yyMajor,                  /* The major token to shift in */
    +-  fts5YYMINORTYPE *fts5yypMinor         /* Pointer to the minor token to shift in */
    ++  sqlite3Fts5ParserFTS5TOKENTYPE fts5yyMinor        /* The minor token to shift in */
    + ){
    +   fts5yyStackEntry *fts5yytos;
    +-  fts5yypParser->fts5yyidx++;
    ++  fts5yypParser->fts5yytos++;
    + #ifdef fts5YYTRACKMAXSTACKDEPTH
    +-  if( fts5yypParser->fts5yyidx>fts5yypParser->fts5yyidxMax ){
    +-    fts5yypParser->fts5yyidxMax = fts5yypParser->fts5yyidx;
    ++  if( (int)(fts5yypParser->fts5yytos - fts5yypParser->fts5yystack)>fts5yypParser->fts5yyhwm ){
    ++    fts5yypParser->fts5yyhwm++;
    ++    assert( fts5yypParser->fts5yyhwm == (int)(fts5yypParser->fts5yytos - fts5yypParser->fts5yystack) );
    +   }
    + #endif
    + #if fts5YYSTACKDEPTH>0 
    +-  if( fts5yypParser->fts5yyidx>=fts5YYSTACKDEPTH ){
    +-    fts5yyStackOverflow(fts5yypParser, fts5yypMinor);
    ++  if( fts5yypParser->fts5yytos>fts5yypParser->fts5yystackEnd ){
    ++    fts5yypParser->fts5yytos--;
    ++    fts5yyStackOverflow(fts5yypParser);
    +     return;
    +   }
    + #else
    +-  if( fts5yypParser->fts5yyidx>=fts5yypParser->fts5yystksz ){
    +-    fts5yyGrowStack(fts5yypParser);
    +-    if( fts5yypParser->fts5yyidx>=fts5yypParser->fts5yystksz ){
    +-      fts5yyStackOverflow(fts5yypParser, fts5yypMinor);
    ++  if( fts5yypParser->fts5yytos>=&fts5yypParser->fts5yystack[fts5yypParser->fts5yystksz] ){
    ++    if( fts5yyGrowStack(fts5yypParser) ){
    ++      fts5yypParser->fts5yytos--;
    ++      fts5yyStackOverflow(fts5yypParser);
    +       return;
    +     }
    +   }
    + #endif
    +-  fts5yytos = &fts5yypParser->fts5yystack[fts5yypParser->fts5yyidx];
    ++  if( fts5yyNewState > fts5YY_MAX_SHIFT ){
    ++    fts5yyNewState += fts5YY_MIN_REDUCE - fts5YY_MIN_SHIFTREDUCE;
    ++  }
    ++  fts5yytos = fts5yypParser->fts5yytos;
    +   fts5yytos->stateno = (fts5YYACTIONTYPE)fts5yyNewState;
    +   fts5yytos->major = (fts5YYCODETYPE)fts5yyMajor;
    +-  fts5yytos->minor = *fts5yypMinor;
    +-  fts5yyTraceShift(fts5yypParser, fts5yyNewState);
    ++  fts5yytos->minor.fts5yy0 = fts5yyMinor;
    ++  fts5yyTraceShift(fts5yypParser, fts5yyNewState, "Shift");
    + }
    + 
    + /* The following table contains information about every rule that
    + ** is used during the reduce.
    + */
    + static const struct {
    +-  fts5YYCODETYPE lhs;         /* Symbol on the left-hand side of the rule */
    +-  unsigned char nrhs;     /* Number of right-hand side symbols in the rule */
    ++  fts5YYCODETYPE lhs;       /* Symbol on the left-hand side of the rule */
    ++  signed char nrhs;     /* Negative of the number of RHS symbols in the rule */
    + } fts5yyRuleInfo[] = {
    +-  { 15, 1 },
    +-  { 16, 3 },
    +-  { 16, 3 },
    +-  { 16, 3 },
    +-  { 16, 3 },
    +-  { 16, 1 },
    +-  { 18, 1 },
    +-  { 18, 2 },
    +-  { 17, 1 },
    +-  { 17, 3 },
    +-  { 20, 3 },
    +-  { 20, 1 },
    +-  { 21, 2 },
    +-  { 21, 1 },
    +-  { 19, 1 },
    +-  { 19, 5 },
    +-  { 22, 1 },
    +-  { 22, 2 },
    +-  { 24, 0 },
    +-  { 24, 2 },
    +-  { 23, 4 },
    +-  { 23, 2 },
    +-  { 25, 1 },
    +-  { 25, 0 },
    ++  {   17,   -1 }, /* (0) input ::= expr */
    ++  {   21,   -4 }, /* (1) colset ::= MINUS LCP colsetlist RCP */
    ++  {   21,   -3 }, /* (2) colset ::= LCP colsetlist RCP */
    ++  {   21,   -1 }, /* (3) colset ::= STRING */
    ++  {   21,   -2 }, /* (4) colset ::= MINUS STRING */
    ++  {   22,   -2 }, /* (5) colsetlist ::= colsetlist STRING */
    ++  {   22,   -1 }, /* (6) colsetlist ::= STRING */
    ++  {   18,   -3 }, /* (7) expr ::= expr AND expr */
    ++  {   18,   -3 }, /* (8) expr ::= expr OR expr */
    ++  {   18,   -3 }, /* (9) expr ::= expr NOT expr */
    ++  {   18,   -5 }, /* (10) expr ::= colset COLON LP expr RP */
    ++  {   18,   -3 }, /* (11) expr ::= LP expr RP */
    ++  {   18,   -1 }, /* (12) expr ::= exprlist */
    ++  {   20,   -1 }, /* (13) exprlist ::= cnearset */
    ++  {   20,   -2 }, /* (14) exprlist ::= exprlist cnearset */
    ++  {   19,   -1 }, /* (15) cnearset ::= nearset */
    ++  {   19,   -3 }, /* (16) cnearset ::= colset COLON nearset */
    ++  {   23,   -1 }, /* (17) nearset ::= phrase */
    ++  {   23,   -2 }, /* (18) nearset ::= CARET phrase */
    ++  {   23,   -5 }, /* (19) nearset ::= STRING LP nearphrases neardist_opt RP */
    ++  {   24,   -1 }, /* (20) nearphrases ::= phrase */
    ++  {   24,   -2 }, /* (21) nearphrases ::= nearphrases phrase */
    ++  {   26,    0 }, /* (22) neardist_opt ::= */
    ++  {   26,   -2 }, /* (23) neardist_opt ::= COMMA STRING */
    ++  {   25,   -4 }, /* (24) phrase ::= phrase PLUS STRING star_opt */
    ++  {   25,   -2 }, /* (25) phrase ::= STRING star_opt */
    ++  {   27,   -1 }, /* (26) star_opt ::= STAR */
    ++  {   27,    0 }, /* (27) star_opt ::= */
    + };
    + 
    + static void fts5yy_accept(fts5yyParser*);  /* Forward Declaration */
    +@@ -167620,44 +188317,66 @@ static void fts5yy_accept(fts5yyParser*);  /* Forward Declaration */
    + /*
    + ** Perform a reduce action and the shift that must immediately
    + ** follow the reduce.
    ++**
    ++** The fts5yyLookahead and fts5yyLookaheadToken parameters provide reduce actions
    ++** access to the lookahead token (if any).  The fts5yyLookahead will be fts5YYNOCODE
    ++** if the lookahead token has already been consumed.  As this procedure is
    ++** only called from one place, optimizing compilers will in-line it, which
    ++** means that the extra parameters have no performance impact.
    + */
    + static void fts5yy_reduce(
    +   fts5yyParser *fts5yypParser,         /* The parser */
    +-  int fts5yyruleno                 /* Number of the rule by which to reduce */
    ++  unsigned int fts5yyruleno,       /* Number of the rule by which to reduce */
    ++  int fts5yyLookahead,             /* Lookahead token, or fts5YYNOCODE if none */
    ++  sqlite3Fts5ParserFTS5TOKENTYPE fts5yyLookaheadToken  /* Value of the lookahead token */
    + ){
    +   int fts5yygoto;                     /* The next state */
    +   int fts5yyact;                      /* The next action */
    +-  fts5YYMINORTYPE fts5yygotominor;        /* The LHS of the rule reduced */
    +   fts5yyStackEntry *fts5yymsp;            /* The top of the parser's stack */
    +   int fts5yysize;                     /* Amount to pop the stack */
    +   sqlite3Fts5ParserARG_FETCH;
    +-  fts5yymsp = &fts5yypParser->fts5yystack[fts5yypParser->fts5yyidx];
    ++  (void)fts5yyLookahead;
    ++  (void)fts5yyLookaheadToken;
    ++  fts5yymsp = fts5yypParser->fts5yytos;
    + #ifndef NDEBUG
    +-  if( fts5yyTraceFILE && fts5yyruleno>=0 
    +-        && fts5yyruleno<(int)(sizeof(fts5yyRuleName)/sizeof(fts5yyRuleName[0])) ){
    ++  if( fts5yyTraceFILE && fts5yyruleno<(int)(sizeof(fts5yyRuleName)/sizeof(fts5yyRuleName[0])) ){
    +     fts5yysize = fts5yyRuleInfo[fts5yyruleno].nrhs;
    +-    fprintf(fts5yyTraceFILE, "%sReduce [%s] -> state %d.\n", fts5yyTracePrompt,
    +-      fts5yyRuleName[fts5yyruleno], fts5yymsp[-fts5yysize].stateno);
    ++    if( fts5yysize ){
    ++      fprintf(fts5yyTraceFILE, "%sReduce %d [%s], go to state %d.\n",
    ++        fts5yyTracePrompt,
    ++        fts5yyruleno, fts5yyRuleName[fts5yyruleno], fts5yymsp[fts5yysize].stateno);
    ++    }else{
    ++      fprintf(fts5yyTraceFILE, "%sReduce %d [%s].\n",
    ++        fts5yyTracePrompt, fts5yyruleno, fts5yyRuleName[fts5yyruleno]);
    ++    }
    +   }
    + #endif /* NDEBUG */
    + 
    +-  /* Silence complaints from purify about fts5yygotominor being uninitialized
    +-  ** in some cases when it is copied into the stack after the following
    +-  ** switch.  fts5yygotominor is uninitialized when a rule reduces that does
    +-  ** not set the value of its left-hand side nonterminal.  Leaving the
    +-  ** value of the nonterminal uninitialized is utterly harmless as long
    +-  ** as the value is never used.  So really the only thing this code
    +-  ** accomplishes is to quieten purify.  
    +-  **
    +-  ** 2007-01-16:  The wireshark project (www.wireshark.org) reports that
    +-  ** without this code, their parser segfaults.  I'm not sure what there
    +-  ** parser is doing to make this happen.  This is the second bug report
    +-  ** from wireshark this week.  Clearly they are stressing Lemon in ways
    +-  ** that it has not been previously stressed...  (SQLite ticket #2172)
    +-  */
    +-  /*memset(&fts5yygotominor, 0, sizeof(fts5yygotominor));*/
    +-  fts5yygotominor = fts5yyzerominor;
    +-
    ++  /* Check that the stack is large enough to grow by a single entry
    ++  ** if the RHS of the rule is empty.  This ensures that there is room
    ++  ** enough on the stack to push the LHS value */
    ++  if( fts5yyRuleInfo[fts5yyruleno].nrhs==0 ){
    ++#ifdef fts5YYTRACKMAXSTACKDEPTH
    ++    if( (int)(fts5yypParser->fts5yytos - fts5yypParser->fts5yystack)>fts5yypParser->fts5yyhwm ){
    ++      fts5yypParser->fts5yyhwm++;
    ++      assert( fts5yypParser->fts5yyhwm == (int)(fts5yypParser->fts5yytos - fts5yypParser->fts5yystack));
    ++    }
    ++#endif
    ++#if fts5YYSTACKDEPTH>0 
    ++    if( fts5yypParser->fts5yytos>=fts5yypParser->fts5yystackEnd ){
    ++      fts5yyStackOverflow(fts5yypParser);
    ++      return;
    ++    }
    ++#else
    ++    if( fts5yypParser->fts5yytos>=&fts5yypParser->fts5yystack[fts5yypParser->fts5yystksz-1] ){
    ++      if( fts5yyGrowStack(fts5yypParser) ){
    ++        fts5yyStackOverflow(fts5yypParser);
    ++        return;
    ++      }
    ++      fts5yymsp = fts5yypParser->fts5yytos;
    ++    }
    ++#endif
    ++  }
    + 
    +   switch( fts5yyruleno ){
    +   /* Beginning here are the reduction cases.  A typical example
    +@@ -167668,134 +188387,169 @@ static void fts5yy_reduce(
    +   **  #line <lineno> <thisfile>
    +   **     break;
    +   */
    ++/********** Begin reduce actions **********************************************/
    ++        fts5YYMINORTYPE fts5yylhsminor;
    +       case 0: /* input ::= expr */
    +-{ sqlite3Fts5ParseFinished(pParse, fts5yymsp[0].minor.fts5yy18); }
    ++{ sqlite3Fts5ParseFinished(pParse, fts5yymsp[0].minor.fts5yy54); }
    +         break;
    +-      case 1: /* expr ::= expr AND expr */
    +-{
    +-  fts5yygotominor.fts5yy18 = sqlite3Fts5ParseNode(pParse, FTS5_AND, fts5yymsp[-2].minor.fts5yy18, fts5yymsp[0].minor.fts5yy18, 0);
    ++      case 1: /* colset ::= MINUS LCP colsetlist RCP */
    ++{ 
    ++    fts5yymsp[-3].minor.fts5yy43 = sqlite3Fts5ParseColsetInvert(pParse, fts5yymsp[-1].minor.fts5yy43);
    + }
    +         break;
    +-      case 2: /* expr ::= expr OR expr */
    ++      case 2: /* colset ::= LCP colsetlist RCP */
    ++{ fts5yymsp[-2].minor.fts5yy43 = fts5yymsp[-1].minor.fts5yy43; }
    ++        break;
    ++      case 3: /* colset ::= STRING */
    + {
    +-  fts5yygotominor.fts5yy18 = sqlite3Fts5ParseNode(pParse, FTS5_OR, fts5yymsp[-2].minor.fts5yy18, fts5yymsp[0].minor.fts5yy18, 0);
    ++  fts5yylhsminor.fts5yy43 = sqlite3Fts5ParseColset(pParse, 0, &fts5yymsp[0].minor.fts5yy0);
    + }
    ++  fts5yymsp[0].minor.fts5yy43 = fts5yylhsminor.fts5yy43;
    +         break;
    +-      case 3: /* expr ::= expr NOT expr */
    ++      case 4: /* colset ::= MINUS STRING */
    + {
    +-  fts5yygotominor.fts5yy18 = sqlite3Fts5ParseNode(pParse, FTS5_NOT, fts5yymsp[-2].minor.fts5yy18, fts5yymsp[0].minor.fts5yy18, 0);
    ++  fts5yymsp[-1].minor.fts5yy43 = sqlite3Fts5ParseColset(pParse, 0, &fts5yymsp[0].minor.fts5yy0);
    ++  fts5yymsp[-1].minor.fts5yy43 = sqlite3Fts5ParseColsetInvert(pParse, fts5yymsp[-1].minor.fts5yy43);
    + }
    +         break;
    +-      case 4: /* expr ::= LP expr RP */
    +-{fts5yygotominor.fts5yy18 = fts5yymsp[-1].minor.fts5yy18;}
    ++      case 5: /* colsetlist ::= colsetlist STRING */
    ++{ 
    ++  fts5yylhsminor.fts5yy43 = sqlite3Fts5ParseColset(pParse, fts5yymsp[-1].minor.fts5yy43, &fts5yymsp[0].minor.fts5yy0); }
    ++  fts5yymsp[-1].minor.fts5yy43 = fts5yylhsminor.fts5yy43;
    +         break;
    +-      case 5: /* expr ::= exprlist */
    +-      case 6: /* exprlist ::= cnearset */ fts5yytestcase(fts5yyruleno==6);
    +-{fts5yygotominor.fts5yy18 = fts5yymsp[0].minor.fts5yy18;}
    ++      case 6: /* colsetlist ::= STRING */
    ++{ 
    ++  fts5yylhsminor.fts5yy43 = sqlite3Fts5ParseColset(pParse, 0, &fts5yymsp[0].minor.fts5yy0); 
    ++}
    ++  fts5yymsp[0].minor.fts5yy43 = fts5yylhsminor.fts5yy43;
    +         break;
    +-      case 7: /* exprlist ::= exprlist cnearset */
    ++      case 7: /* expr ::= expr AND expr */
    + {
    +-  fts5yygotominor.fts5yy18 = sqlite3Fts5ParseNode(pParse, FTS5_AND, fts5yymsp[-1].minor.fts5yy18, fts5yymsp[0].minor.fts5yy18, 0);
    ++  fts5yylhsminor.fts5yy54 = sqlite3Fts5ParseNode(pParse, FTS5_AND, fts5yymsp[-2].minor.fts5yy54, fts5yymsp[0].minor.fts5yy54, 0);
    + }
    ++  fts5yymsp[-2].minor.fts5yy54 = fts5yylhsminor.fts5yy54;
    +         break;
    +-      case 8: /* cnearset ::= nearset */
    +-{ 
    +-  fts5yygotominor.fts5yy18 = sqlite3Fts5ParseNode(pParse, FTS5_STRING, 0, 0, fts5yymsp[0].minor.fts5yy26); 
    ++      case 8: /* expr ::= expr OR expr */
    ++{
    ++  fts5yylhsminor.fts5yy54 = sqlite3Fts5ParseNode(pParse, FTS5_OR, fts5yymsp[-2].minor.fts5yy54, fts5yymsp[0].minor.fts5yy54, 0);
    + }
    ++  fts5yymsp[-2].minor.fts5yy54 = fts5yylhsminor.fts5yy54;
    +         break;
    +-      case 9: /* cnearset ::= colset COLON nearset */
    +-{ 
    +-  sqlite3Fts5ParseSetColset(pParse, fts5yymsp[0].minor.fts5yy26, fts5yymsp[-2].minor.fts5yy3);
    +-  fts5yygotominor.fts5yy18 = sqlite3Fts5ParseNode(pParse, FTS5_STRING, 0, 0, fts5yymsp[0].minor.fts5yy26); 
    ++      case 9: /* expr ::= expr NOT expr */
    ++{
    ++  fts5yylhsminor.fts5yy54 = sqlite3Fts5ParseNode(pParse, FTS5_NOT, fts5yymsp[-2].minor.fts5yy54, fts5yymsp[0].minor.fts5yy54, 0);
    + }
    ++  fts5yymsp[-2].minor.fts5yy54 = fts5yylhsminor.fts5yy54;
    ++        break;
    ++      case 10: /* expr ::= colset COLON LP expr RP */
    ++{
    ++  sqlite3Fts5ParseSetColset(pParse, fts5yymsp[-1].minor.fts5yy54, fts5yymsp[-4].minor.fts5yy43);
    ++  fts5yylhsminor.fts5yy54 = fts5yymsp[-1].minor.fts5yy54;
    ++}
    ++  fts5yymsp[-4].minor.fts5yy54 = fts5yylhsminor.fts5yy54;
    ++        break;
    ++      case 11: /* expr ::= LP expr RP */
    ++{fts5yymsp[-2].minor.fts5yy54 = fts5yymsp[-1].minor.fts5yy54;}
    +         break;
    +-      case 10: /* colset ::= LCP colsetlist RCP */
    +-{ fts5yygotominor.fts5yy3 = fts5yymsp[-1].minor.fts5yy3; }
    ++      case 12: /* expr ::= exprlist */
    ++      case 13: /* exprlist ::= cnearset */ fts5yytestcase(fts5yyruleno==13);
    ++{fts5yylhsminor.fts5yy54 = fts5yymsp[0].minor.fts5yy54;}
    ++  fts5yymsp[0].minor.fts5yy54 = fts5yylhsminor.fts5yy54;
    +         break;
    +-      case 11: /* colset ::= STRING */
    ++      case 14: /* exprlist ::= exprlist cnearset */
    + {
    +-  fts5yygotominor.fts5yy3 = sqlite3Fts5ParseColset(pParse, 0, &fts5yymsp[0].minor.fts5yy0);
    ++  fts5yylhsminor.fts5yy54 = sqlite3Fts5ParseImplicitAnd(pParse, fts5yymsp[-1].minor.fts5yy54, fts5yymsp[0].minor.fts5yy54);
    + }
    ++  fts5yymsp[-1].minor.fts5yy54 = fts5yylhsminor.fts5yy54;
    +         break;
    +-      case 12: /* colsetlist ::= colsetlist STRING */
    ++      case 15: /* cnearset ::= nearset */
    + { 
    +-  fts5yygotominor.fts5yy3 = sqlite3Fts5ParseColset(pParse, fts5yymsp[-1].minor.fts5yy3, &fts5yymsp[0].minor.fts5yy0); }
    ++  fts5yylhsminor.fts5yy54 = sqlite3Fts5ParseNode(pParse, FTS5_STRING, 0, 0, fts5yymsp[0].minor.fts5yy14); 
    ++}
    ++  fts5yymsp[0].minor.fts5yy54 = fts5yylhsminor.fts5yy54;
    +         break;
    +-      case 13: /* colsetlist ::= STRING */
    ++      case 16: /* cnearset ::= colset COLON nearset */
    + { 
    +-  fts5yygotominor.fts5yy3 = sqlite3Fts5ParseColset(pParse, 0, &fts5yymsp[0].minor.fts5yy0); 
    ++  fts5yylhsminor.fts5yy54 = sqlite3Fts5ParseNode(pParse, FTS5_STRING, 0, 0, fts5yymsp[0].minor.fts5yy14); 
    ++  sqlite3Fts5ParseSetColset(pParse, fts5yylhsminor.fts5yy54, fts5yymsp[-2].minor.fts5yy43);
    + }
    ++  fts5yymsp[-2].minor.fts5yy54 = fts5yylhsminor.fts5yy54;
    +         break;
    +-      case 14: /* nearset ::= phrase */
    +-{ fts5yygotominor.fts5yy26 = sqlite3Fts5ParseNearset(pParse, 0, fts5yymsp[0].minor.fts5yy11); }
    ++      case 17: /* nearset ::= phrase */
    ++{ fts5yylhsminor.fts5yy14 = sqlite3Fts5ParseNearset(pParse, 0, fts5yymsp[0].minor.fts5yy11); }
    ++  fts5yymsp[0].minor.fts5yy14 = fts5yylhsminor.fts5yy14;
    +         break;
    +-      case 15: /* nearset ::= STRING LP nearphrases neardist_opt RP */
    ++      case 18: /* nearset ::= CARET phrase */
    ++{ 
    ++  sqlite3Fts5ParseSetCaret(fts5yymsp[0].minor.fts5yy11);
    ++  fts5yymsp[-1].minor.fts5yy14 = sqlite3Fts5ParseNearset(pParse, 0, fts5yymsp[0].minor.fts5yy11); 
    ++}
    ++        break;
    ++      case 19: /* nearset ::= STRING LP nearphrases neardist_opt RP */
    + {
    +   sqlite3Fts5ParseNear(pParse, &fts5yymsp[-4].minor.fts5yy0);
    +-  sqlite3Fts5ParseSetDistance(pParse, fts5yymsp[-2].minor.fts5yy26, &fts5yymsp[-1].minor.fts5yy0);
    +-  fts5yygotominor.fts5yy26 = fts5yymsp[-2].minor.fts5yy26;
    ++  sqlite3Fts5ParseSetDistance(pParse, fts5yymsp[-2].minor.fts5yy14, &fts5yymsp[-1].minor.fts5yy0);
    ++  fts5yylhsminor.fts5yy14 = fts5yymsp[-2].minor.fts5yy14;
    + }
    ++  fts5yymsp[-4].minor.fts5yy14 = fts5yylhsminor.fts5yy14;
    +         break;
    +-      case 16: /* nearphrases ::= phrase */
    ++      case 20: /* nearphrases ::= phrase */
    + { 
    +-  fts5yygotominor.fts5yy26 = sqlite3Fts5ParseNearset(pParse, 0, fts5yymsp[0].minor.fts5yy11); 
    ++  fts5yylhsminor.fts5yy14 = sqlite3Fts5ParseNearset(pParse, 0, fts5yymsp[0].minor.fts5yy11); 
    + }
    ++  fts5yymsp[0].minor.fts5yy14 = fts5yylhsminor.fts5yy14;
    +         break;
    +-      case 17: /* nearphrases ::= nearphrases phrase */
    ++      case 21: /* nearphrases ::= nearphrases phrase */
    + {
    +-  fts5yygotominor.fts5yy26 = sqlite3Fts5ParseNearset(pParse, fts5yymsp[-1].minor.fts5yy26, fts5yymsp[0].minor.fts5yy11);
    ++  fts5yylhsminor.fts5yy14 = sqlite3Fts5ParseNearset(pParse, fts5yymsp[-1].minor.fts5yy14, fts5yymsp[0].minor.fts5yy11);
    + }
    ++  fts5yymsp[-1].minor.fts5yy14 = fts5yylhsminor.fts5yy14;
    +         break;
    +-      case 18: /* neardist_opt ::= */
    +-{ fts5yygotominor.fts5yy0.p = 0; fts5yygotominor.fts5yy0.n = 0; }
    ++      case 22: /* neardist_opt ::= */
    ++{ fts5yymsp[1].minor.fts5yy0.p = 0; fts5yymsp[1].minor.fts5yy0.n = 0; }
    +         break;
    +-      case 19: /* neardist_opt ::= COMMA STRING */
    +-{ fts5yygotominor.fts5yy0 = fts5yymsp[0].minor.fts5yy0; }
    ++      case 23: /* neardist_opt ::= COMMA STRING */
    ++{ fts5yymsp[-1].minor.fts5yy0 = fts5yymsp[0].minor.fts5yy0; }
    +         break;
    +-      case 20: /* phrase ::= phrase PLUS STRING star_opt */
    ++      case 24: /* phrase ::= phrase PLUS STRING star_opt */
    + { 
    +-  fts5yygotominor.fts5yy11 = sqlite3Fts5ParseTerm(pParse, fts5yymsp[-3].minor.fts5yy11, &fts5yymsp[-1].minor.fts5yy0, fts5yymsp[0].minor.fts5yy20);
    ++  fts5yylhsminor.fts5yy11 = sqlite3Fts5ParseTerm(pParse, fts5yymsp[-3].minor.fts5yy11, &fts5yymsp[-1].minor.fts5yy0, fts5yymsp[0].minor.fts5yy4);
    + }
    ++  fts5yymsp[-3].minor.fts5yy11 = fts5yylhsminor.fts5yy11;
    +         break;
    +-      case 21: /* phrase ::= STRING star_opt */
    ++      case 25: /* phrase ::= STRING star_opt */
    + { 
    +-  fts5yygotominor.fts5yy11 = sqlite3Fts5ParseTerm(pParse, 0, &fts5yymsp[-1].minor.fts5yy0, fts5yymsp[0].minor.fts5yy20);
    ++  fts5yylhsminor.fts5yy11 = sqlite3Fts5ParseTerm(pParse, 0, &fts5yymsp[-1].minor.fts5yy0, fts5yymsp[0].minor.fts5yy4);
    + }
    ++  fts5yymsp[-1].minor.fts5yy11 = fts5yylhsminor.fts5yy11;
    +         break;
    +-      case 22: /* star_opt ::= STAR */
    +-{ fts5yygotominor.fts5yy20 = 1; }
    ++      case 26: /* star_opt ::= STAR */
    ++{ fts5yymsp[0].minor.fts5yy4 = 1; }
    +         break;
    +-      case 23: /* star_opt ::= */
    +-{ fts5yygotominor.fts5yy20 = 0; }
    ++      case 27: /* star_opt ::= */
    ++{ fts5yymsp[1].minor.fts5yy4 = 0; }
    +         break;
    +       default:
    +         break;
    ++/********** End reduce actions ************************************************/
    +   };
    +-  assert( fts5yyruleno>=0 && fts5yyruleno<sizeof(fts5yyRuleInfo)/sizeof(fts5yyRuleInfo[0]) );
    ++  assert( fts5yyruleno<sizeof(fts5yyRuleInfo)/sizeof(fts5yyRuleInfo[0]) );
    +   fts5yygoto = fts5yyRuleInfo[fts5yyruleno].lhs;
    +   fts5yysize = fts5yyRuleInfo[fts5yyruleno].nrhs;
    +-  fts5yypParser->fts5yyidx -= fts5yysize;
    +-  fts5yyact = fts5yy_find_reduce_action(fts5yymsp[-fts5yysize].stateno,(fts5YYCODETYPE)fts5yygoto);
    +-  if( fts5yyact <= fts5YY_MAX_SHIFTREDUCE ){
    +-    if( fts5yyact>fts5YY_MAX_SHIFT ) fts5yyact += fts5YY_MIN_REDUCE - fts5YY_MIN_SHIFTREDUCE;
    +-    /* If the reduce action popped at least
    +-    ** one element off the stack, then we can push the new element back
    +-    ** onto the stack here, and skip the stack overflow test in fts5yy_shift().
    +-    ** That gives a significant speed improvement. */
    +-    if( fts5yysize ){
    +-      fts5yypParser->fts5yyidx++;
    +-      fts5yymsp -= fts5yysize-1;
    +-      fts5yymsp->stateno = (fts5YYACTIONTYPE)fts5yyact;
    +-      fts5yymsp->major = (fts5YYCODETYPE)fts5yygoto;
    +-      fts5yymsp->minor = fts5yygotominor;
    +-      fts5yyTraceShift(fts5yypParser, fts5yyact);
    +-    }else{
    +-      fts5yy_shift(fts5yypParser,fts5yyact,fts5yygoto,&fts5yygotominor);
    +-    }
    +-  }else{
    +-    assert( fts5yyact == fts5YY_ACCEPT_ACTION );
    +-    fts5yy_accept(fts5yypParser);
    +-  }
    ++  fts5yyact = fts5yy_find_reduce_action(fts5yymsp[fts5yysize].stateno,(fts5YYCODETYPE)fts5yygoto);
    ++
    ++  /* There are no SHIFTREDUCE actions on nonterminals because the table
    ++  ** generator has simplified them to pure REDUCE actions. */
    ++  assert( !(fts5yyact>fts5YY_MAX_SHIFT && fts5yyact<=fts5YY_MAX_SHIFTREDUCE) );
    ++
    ++  /* It is not possible for a REDUCE to be followed by an error */
    ++  assert( fts5yyact!=fts5YY_ERROR_ACTION );
    ++
    ++  fts5yymsp += fts5yysize+1;
    ++  fts5yypParser->fts5yytos = fts5yymsp;
    ++  fts5yymsp->stateno = (fts5YYACTIONTYPE)fts5yyact;
    ++  fts5yymsp->major = (fts5YYCODETYPE)fts5yygoto;
    ++  fts5yyTraceShift(fts5yypParser, fts5yyact, "... then shift");
    + }
    + 
    + /*
    +@@ -167811,9 +188565,11 @@ static void fts5yy_parse_failed(
    +     fprintf(fts5yyTraceFILE,"%sFail!\n",fts5yyTracePrompt);
    +   }
    + #endif
    +-  while( fts5yypParser->fts5yyidx>=0 ) fts5yy_pop_parser_stack(fts5yypParser);
    ++  while( fts5yypParser->fts5yytos>fts5yypParser->fts5yystack ) fts5yy_pop_parser_stack(fts5yypParser);
    +   /* Here code is inserted which will be executed whenever the
    +   ** parser fails */
    ++/************ Begin %parse_failure code ***************************************/
    ++/************ End %parse_failure code *****************************************/
    +   sqlite3Fts5ParserARG_STORE; /* Suppress warning about unused %extra_argument variable */
    + }
    + #endif /* fts5YYNOERRORRECOVERY */
    +@@ -167824,14 +188580,17 @@ static void fts5yy_parse_failed(
    + static void fts5yy_syntax_error(
    +   fts5yyParser *fts5yypParser,           /* The parser */
    +   int fts5yymajor,                   /* The major type of the error token */
    +-  fts5YYMINORTYPE fts5yyminor            /* The minor type of the error token */
    ++  sqlite3Fts5ParserFTS5TOKENTYPE fts5yyminor         /* The minor type of the error token */
    + ){
    +   sqlite3Fts5ParserARG_FETCH;
    +-#define FTS5TOKEN (fts5yyminor.fts5yy0)
    ++#define FTS5TOKEN fts5yyminor
    ++/************ Begin %syntax_error code ****************************************/
    + 
    ++  UNUSED_PARAM(fts5yymajor); /* Silence a compiler warning */
    +   sqlite3Fts5ParseError(
    +     pParse, "fts5: syntax error near \"%.*s\"",FTS5TOKEN.n,FTS5TOKEN.p
    +   );
    ++/************ End %syntax_error code ******************************************/
    +   sqlite3Fts5ParserARG_STORE; /* Suppress warning about unused %extra_argument variable */
    + }
    + 
    +@@ -167847,9 +188606,14 @@ static void fts5yy_accept(
    +     fprintf(fts5yyTraceFILE,"%sAccept!\n",fts5yyTracePrompt);
    +   }
    + #endif
    +-  while( fts5yypParser->fts5yyidx>=0 ) fts5yy_pop_parser_stack(fts5yypParser);
    ++#ifndef fts5YYNOERRORRECOVERY
    ++  fts5yypParser->fts5yyerrcnt = -1;
    ++#endif
    ++  assert( fts5yypParser->fts5yytos==fts5yypParser->fts5yystack );
    +   /* Here code is inserted which will be executed whenever the
    +   ** parser accepts */
    ++/*********** Begin %parse_accept code *****************************************/
    ++/*********** End %parse_accept code *******************************************/
    +   sqlite3Fts5ParserARG_STORE; /* Suppress warning about unused %extra_argument variable */
    + }
    + 
    +@@ -167879,7 +188643,7 @@ static void sqlite3Fts5Parser(
    +   sqlite3Fts5ParserARG_PDECL               /* Optional %extra_argument parameter */
    + ){
    +   fts5YYMINORTYPE fts5yyminorunion;
    +-  int fts5yyact;            /* The parser action. */
    ++  unsigned int fts5yyact;   /* The parser action. */
    + #if !defined(fts5YYERRORSYMBOL) && !defined(fts5YYNOERRORRECOVERY)
    +   int fts5yyendofinput;     /* True if we are at the end of input */
    + #endif
    +@@ -167888,23 +188652,8 @@ static void sqlite3Fts5Parser(
    + #endif
    +   fts5yyParser *fts5yypParser;  /* The parser */
    + 
    +-  /* (re)initialize the parser, if necessary */
    +   fts5yypParser = (fts5yyParser*)fts5yyp;
    +-  if( fts5yypParser->fts5yyidx<0 ){
    +-#if fts5YYSTACKDEPTH<=0
    +-    if( fts5yypParser->fts5yystksz <=0 ){
    +-      /*memset(&fts5yyminorunion, 0, sizeof(fts5yyminorunion));*/
    +-      fts5yyminorunion = fts5yyzerominor;
    +-      fts5yyStackOverflow(fts5yypParser, &fts5yyminorunion);
    +-      return;
    +-    }
    +-#endif
    +-    fts5yypParser->fts5yyidx = 0;
    +-    fts5yypParser->fts5yyerrcnt = -1;
    +-    fts5yypParser->fts5yystack[0].stateno = 0;
    +-    fts5yypParser->fts5yystack[0].major = 0;
    +-  }
    +-  fts5yyminorunion.fts5yy0 = fts5yyminor;
    ++  assert( fts5yypParser->fts5yytos!=0 );
    + #if !defined(fts5YYERRORSYMBOL) && !defined(fts5YYNOERRORRECOVERY)
    +   fts5yyendofinput = (fts5yymajor==0);
    + #endif
    +@@ -167912,21 +188661,34 @@ static void sqlite3Fts5Parser(
    + 
    + #ifndef NDEBUG
    +   if( fts5yyTraceFILE ){
    +-    fprintf(fts5yyTraceFILE,"%sInput %s\n",fts5yyTracePrompt,fts5yyTokenName[fts5yymajor]);
    ++    int stateno = fts5yypParser->fts5yytos->stateno;
    ++    if( stateno < fts5YY_MIN_REDUCE ){
    ++      fprintf(fts5yyTraceFILE,"%sInput '%s' in state %d\n",
    ++              fts5yyTracePrompt,fts5yyTokenName[fts5yymajor],stateno);
    ++    }else{
    ++      fprintf(fts5yyTraceFILE,"%sInput '%s' with pending reduce %d\n",
    ++              fts5yyTracePrompt,fts5yyTokenName[fts5yymajor],stateno-fts5YY_MIN_REDUCE);
    ++    }
    +   }
    + #endif
    + 
    +   do{
    +     fts5yyact = fts5yy_find_shift_action(fts5yypParser,(fts5YYCODETYPE)fts5yymajor);
    +-    if( fts5yyact <= fts5YY_MAX_SHIFTREDUCE ){
    +-      if( fts5yyact > fts5YY_MAX_SHIFT ) fts5yyact += fts5YY_MIN_REDUCE - fts5YY_MIN_SHIFTREDUCE;
    +-      fts5yy_shift(fts5yypParser,fts5yyact,fts5yymajor,&fts5yyminorunion);
    ++    if( fts5yyact >= fts5YY_MIN_REDUCE ){
    ++      fts5yy_reduce(fts5yypParser,fts5yyact-fts5YY_MIN_REDUCE,fts5yymajor,fts5yyminor);
    ++    }else if( fts5yyact <= fts5YY_MAX_SHIFTREDUCE ){
    ++      fts5yy_shift(fts5yypParser,fts5yyact,fts5yymajor,fts5yyminor);
    ++#ifndef fts5YYNOERRORRECOVERY
    +       fts5yypParser->fts5yyerrcnt--;
    ++#endif
    +       fts5yymajor = fts5YYNOCODE;
    +-    }else if( fts5yyact <= fts5YY_MAX_REDUCE ){
    +-      fts5yy_reduce(fts5yypParser,fts5yyact-fts5YY_MIN_REDUCE);
    ++    }else if( fts5yyact==fts5YY_ACCEPT_ACTION ){
    ++      fts5yypParser->fts5yytos--;
    ++      fts5yy_accept(fts5yypParser);
    ++      return;
    +     }else{
    +       assert( fts5yyact == fts5YY_ERROR_ACTION );
    ++      fts5yyminorunion.fts5yy0 = fts5yyminor;
    + #ifdef fts5YYERRORSYMBOL
    +       int fts5yymx;
    + #endif
    +@@ -167956,9 +188718,9 @@ static void sqlite3Fts5Parser(
    +       **
    +       */
    +       if( fts5yypParser->fts5yyerrcnt<0 ){
    +-        fts5yy_syntax_error(fts5yypParser,fts5yymajor,fts5yyminorunion);
    ++        fts5yy_syntax_error(fts5yypParser,fts5yymajor,fts5yyminor);
    +       }
    +-      fts5yymx = fts5yypParser->fts5yystack[fts5yypParser->fts5yyidx].major;
    ++      fts5yymx = fts5yypParser->fts5yytos->major;
    +       if( fts5yymx==fts5YYERRORSYMBOL || fts5yyerrorhit ){
    + #ifndef NDEBUG
    +         if( fts5yyTraceFILE ){
    +@@ -167966,26 +188728,26 @@ static void sqlite3Fts5Parser(
    +              fts5yyTracePrompt,fts5yyTokenName[fts5yymajor]);
    +         }
    + #endif
    +-        fts5yy_destructor(fts5yypParser, (fts5YYCODETYPE)fts5yymajor,&fts5yyminorunion);
    ++        fts5yy_destructor(fts5yypParser, (fts5YYCODETYPE)fts5yymajor, &fts5yyminorunion);
    +         fts5yymajor = fts5YYNOCODE;
    +       }else{
    +-         while(
    +-          fts5yypParser->fts5yyidx >= 0 &&
    +-          fts5yymx != fts5YYERRORSYMBOL &&
    +-          (fts5yyact = fts5yy_find_reduce_action(
    +-                        fts5yypParser->fts5yystack[fts5yypParser->fts5yyidx].stateno,
    ++        while( fts5yypParser->fts5yytos >= fts5yypParser->fts5yystack
    ++            && fts5yymx != fts5YYERRORSYMBOL
    ++            && (fts5yyact = fts5yy_find_reduce_action(
    ++                        fts5yypParser->fts5yytos->stateno,
    +                         fts5YYERRORSYMBOL)) >= fts5YY_MIN_REDUCE
    +         ){
    +           fts5yy_pop_parser_stack(fts5yypParser);
    +         }
    +-        if( fts5yypParser->fts5yyidx < 0 || fts5yymajor==0 ){
    ++        if( fts5yypParser->fts5yytos < fts5yypParser->fts5yystack || fts5yymajor==0 ){
    +           fts5yy_destructor(fts5yypParser,(fts5YYCODETYPE)fts5yymajor,&fts5yyminorunion);
    +           fts5yy_parse_failed(fts5yypParser);
    ++#ifndef fts5YYNOERRORRECOVERY
    ++          fts5yypParser->fts5yyerrcnt = -1;
    ++#endif
    +           fts5yymajor = fts5YYNOCODE;
    +         }else if( fts5yymx!=fts5YYERRORSYMBOL ){
    +-          fts5YYMINORTYPE u2;
    +-          u2.fts5YYERRSYMDT = 0;
    +-          fts5yy_shift(fts5yypParser,fts5yyact,fts5YYERRORSYMBOL,&u2);
    ++          fts5yy_shift(fts5yypParser,fts5yyact,fts5YYERRORSYMBOL,fts5yyminor);
    +         }
    +       }
    +       fts5yypParser->fts5yyerrcnt = 3;
    +@@ -167998,7 +188760,7 @@ static void sqlite3Fts5Parser(
    +       ** Applications can set this macro (for example inside %include) if
    +       ** they intend to abandon the parse upon the first syntax error seen.
    +       */
    +-      fts5yy_syntax_error(fts5yypParser,fts5yymajor,fts5yyminorunion);
    ++      fts5yy_syntax_error(fts5yypParser,fts5yymajor, fts5yyminor);
    +       fts5yy_destructor(fts5yypParser,(fts5YYCODETYPE)fts5yymajor,&fts5yyminorunion);
    +       fts5yymajor = fts5YYNOCODE;
    +       
    +@@ -168013,20 +188775,30 @@ static void sqlite3Fts5Parser(
    +       ** three input tokens have been successfully shifted.
    +       */
    +       if( fts5yypParser->fts5yyerrcnt<=0 ){
    +-        fts5yy_syntax_error(fts5yypParser,fts5yymajor,fts5yyminorunion);
    ++        fts5yy_syntax_error(fts5yypParser,fts5yymajor, fts5yyminor);
    +       }
    +       fts5yypParser->fts5yyerrcnt = 3;
    +       fts5yy_destructor(fts5yypParser,(fts5YYCODETYPE)fts5yymajor,&fts5yyminorunion);
    +       if( fts5yyendofinput ){
    +         fts5yy_parse_failed(fts5yypParser);
    ++#ifndef fts5YYNOERRORRECOVERY
    ++        fts5yypParser->fts5yyerrcnt = -1;
    ++#endif
    +       }
    +       fts5yymajor = fts5YYNOCODE;
    + #endif
    +     }
    +-  }while( fts5yymajor!=fts5YYNOCODE && fts5yypParser->fts5yyidx>=0 );
    ++  }while( fts5yymajor!=fts5YYNOCODE && fts5yypParser->fts5yytos>fts5yypParser->fts5yystack );
    + #ifndef NDEBUG
    +   if( fts5yyTraceFILE ){
    +-    fprintf(fts5yyTraceFILE,"%sReturn\n",fts5yyTracePrompt);
    ++    fts5yyStackEntry *i;
    ++    char cDiv = '[';
    ++    fprintf(fts5yyTraceFILE,"%sReturn. Stack=",fts5yyTracePrompt);
    ++    for(i=&fts5yypParser->fts5yystack[1]; i<=fts5yypParser->fts5yytos; i++){
    ++      fprintf(fts5yyTraceFILE,"%c%s", cDiv, fts5yyTokenName[i->major]);
    ++      cDiv = ' ';
    ++    }
    ++    fprintf(fts5yyTraceFILE,"]\n");
    +   }
    + #endif
    +   return;
    +@@ -168046,6 +188818,7 @@ static void sqlite3Fts5Parser(
    + */
    + 
    + 
    ++/* #include "fts5Int.h" */
    + #include <math.h>                 /* amalgamator: keep */
    + 
    + /*
    +@@ -168170,7 +188943,7 @@ static void fts5HighlightAppend(
    +   const char *z, int n
    + ){
    +   if( *pRc==SQLITE_OK ){
    +-    if( n<0 ) n = strlen(z);
    ++    if( n<0 ) n = (int)strlen(z);
    +     p->zOut = sqlite3_mprintf("%z%.*s", p->zOut, n, z);
    +     if( p->zOut==0 ) *pRc = SQLITE_NOMEM;
    +   }
    +@@ -168191,6 +188964,8 @@ static int fts5HighlightCb(
    +   int rc = SQLITE_OK;
    +   int iPos;
    + 
    ++  UNUSED_PARAM2(pToken, nToken);
    ++
    +   if( tflags & FTS5_TOKEN_COLOCATED ) return SQLITE_OK;
    +   iPos = p->iPos++;
    + 
    +@@ -168220,7 +188995,7 @@ static int fts5HighlightCb(
    +   if( p->iRangeEnd>0 && iPos==p->iRangeEnd ){
    +     fts5HighlightAppend(&rc, p, &p->zIn[p->iOff], iEndOff - p->iOff);
    +     p->iOff = iEndOff;
    +-    if( iPos<p->iter.iEnd ){
    ++    if( iPos>=p->iter.iStart && iPos<p->iter.iEnd ){
    +       fts5HighlightAppend(&rc, p, p->zClose, -1);
    +     }
    +   }
    +@@ -168277,6 +189052,128 @@ static void fts5HighlightFunction(
    + ** End of highlight() implementation.
    + **************************************************************************/
    + 
    ++/*
    ++** Context object passed to the fts5SentenceFinderCb() function.
    ++*/
    ++typedef struct Fts5SFinder Fts5SFinder;
    ++struct Fts5SFinder {
    ++  int iPos;                       /* Current token position */
    ++  int nFirstAlloc;                /* Allocated size of aFirst[] */
    ++  int nFirst;                     /* Number of entries in aFirst[] */
    ++  int *aFirst;                    /* Array of first token in each sentence */
    ++  const char *zDoc;               /* Document being tokenized */
    ++};
    ++
    ++/*
    ++** Add an entry to the Fts5SFinder.aFirst[] array. Grow the array if
    ++** necessary. Return SQLITE_OK if successful, or SQLITE_NOMEM if an
    ++** error occurs.
    ++*/
    ++static int fts5SentenceFinderAdd(Fts5SFinder *p, int iAdd){
    ++  if( p->nFirstAlloc==p->nFirst ){
    ++    int nNew = p->nFirstAlloc ? p->nFirstAlloc*2 : 64;
    ++    int *aNew;
    ++
    ++    aNew = (int*)sqlite3_realloc(p->aFirst, nNew*sizeof(int));
    ++    if( aNew==0 ) return SQLITE_NOMEM;
    ++    p->aFirst = aNew;
    ++    p->nFirstAlloc = nNew;
    ++  }
    ++  p->aFirst[p->nFirst++] = iAdd;
    ++  return SQLITE_OK;
    ++}
    ++
    ++/*
    ++** This function is an xTokenize() callback used by the auxiliary snippet()
    ++** function. Its job is to identify tokens that are the first in a sentence.
    ++** For each such token, an entry is added to the SFinder.aFirst[] array.
    ++*/
    ++static int fts5SentenceFinderCb(
    ++  void *pContext,                 /* Pointer to HighlightContext object */
    ++  int tflags,                     /* Mask of FTS5_TOKEN_* flags */
    ++  const char *pToken,             /* Buffer containing token */
    ++  int nToken,                     /* Size of token in bytes */
    ++  int iStartOff,                  /* Start offset of token */
    ++  int iEndOff                     /* End offset of token */
    ++){
    ++  int rc = SQLITE_OK;
    ++
    ++  UNUSED_PARAM2(pToken, nToken);
    ++  UNUSED_PARAM(iEndOff);
    ++
    ++  if( (tflags & FTS5_TOKEN_COLOCATED)==0 ){
    ++    Fts5SFinder *p = (Fts5SFinder*)pContext;
    ++    if( p->iPos>0 ){
    ++      int i;
    ++      char c = 0;
    ++      for(i=iStartOff-1; i>=0; i--){
    ++        c = p->zDoc[i];
    ++        if( c!=' ' && c!='\t' && c!='\n' && c!='\r' ) break;
    ++      }
    ++      if( i!=iStartOff-1 && (c=='.' || c==':') ){
    ++        rc = fts5SentenceFinderAdd(p, p->iPos);
    ++      }
    ++    }else{
    ++      rc = fts5SentenceFinderAdd(p, 0);
    ++    }
    ++    p->iPos++;
    ++  }
    ++  return rc;
    ++}
    ++
    ++static int fts5SnippetScore(
    ++  const Fts5ExtensionApi *pApi,   /* API offered by current FTS version */
    ++  Fts5Context *pFts,              /* First arg to pass to pApi functions */
    ++  int nDocsize,                   /* Size of column in tokens */
    ++  unsigned char *aSeen,           /* Array with one element per query phrase */
    ++  int iCol,                       /* Column to score */
    ++  int iPos,                       /* Starting offset to score */
    ++  int nToken,                     /* Max tokens per snippet */
    ++  int *pnScore,                   /* OUT: Score */
    ++  int *piPos                      /* OUT: Adjusted offset */
    ++){
    ++  int rc;
    ++  int i;
    ++  int ip = 0;
    ++  int ic = 0;
    ++  int iOff = 0;
    ++  int iFirst = -1;
    ++  int nInst;
    ++  int nScore = 0;
    ++  int iLast = 0;
    ++
    ++  rc = pApi->xInstCount(pFts, &nInst);
    ++  for(i=0; i<nInst && rc==SQLITE_OK; i++){
    ++    rc = pApi->xInst(pFts, i, &ip, &ic, &iOff);
    ++    if( rc==SQLITE_OK && ic==iCol && iOff>=iPos && iOff<(iPos+nToken) ){
    ++      nScore += (aSeen[ip] ? 1 : 1000);
    ++      aSeen[ip] = 1;
    ++      if( iFirst<0 ) iFirst = iOff;
    ++      iLast = iOff + pApi->xPhraseSize(pFts, ip);
    ++    }
    ++  }
    ++
    ++  *pnScore = nScore;
    ++  if( piPos ){
    ++    int iAdj = iFirst - (nToken - (iLast-iFirst)) / 2;
    ++    if( (iAdj+nToken)>nDocsize ) iAdj = nDocsize - nToken;
    ++    if( iAdj<0 ) iAdj = 0;
    ++    *piPos = iAdj;
    ++  }
    ++
    ++  return rc;
    ++}
    ++
    ++/*
    ++** Return the value in pVal interpreted as utf-8 text. Except, if pVal 
    ++** contains a NULL value, return a pointer to a static string zero
    ++** bytes in length instead of a NULL pointer.
    ++*/
    ++static const char *fts5ValueToText(sqlite3_value *pVal){
    ++  const char *zRet = (const char*)sqlite3_value_text(pVal);
    ++  return zRet ? zRet : "";
    ++}
    ++
    + /*
    + ** Implementation of snippet() function.
    + */
    +@@ -168298,9 +189195,10 @@ static void fts5SnippetFunction(
    +   unsigned char *aSeen;           /* Array of "seen instance" flags */
    +   int iBestCol;                   /* Column containing best snippet */
    +   int iBestStart = 0;             /* First token of best snippet */
    +-  int iBestLast;                  /* Last token of best snippet */
    +   int nBestScore = 0;             /* Score of best snippet */
    +   int nColSize = 0;               /* Total size of iBestCol in tokens */
    ++  Fts5SFinder sFinder;            /* Used to find the beginnings of sentences */
    ++  int nCol;
    + 
    +   if( nVal!=5 ){
    +     const char *zErr = "wrong number of arguments to function snippet()";
    +@@ -168308,13 +189206,13 @@ static void fts5SnippetFunction(
    +     return;
    +   }
    + 
    ++  nCol = pApi->xColumnCount(pFts);
    +   memset(&ctx, 0, sizeof(HighlightContext));
    +   iCol = sqlite3_value_int(apVal[0]);
    +-  ctx.zOpen = (const char*)sqlite3_value_text(apVal[1]);
    +-  ctx.zClose = (const char*)sqlite3_value_text(apVal[2]);
    +-  zEllips = (const char*)sqlite3_value_text(apVal[3]);
    ++  ctx.zOpen = fts5ValueToText(apVal[1]);
    ++  ctx.zClose = fts5ValueToText(apVal[2]);
    ++  zEllips = fts5ValueToText(apVal[3]);
    +   nToken = sqlite3_value_int(apVal[4]);
    +-  iBestLast = nToken-1;
    + 
    +   iBestCol = (iCol>=0 ? iCol : 0);
    +   nPhrase = pApi->xPhraseCount(pFts);
    +@@ -168322,65 +189220,94 @@ static void fts5SnippetFunction(
    +   if( aSeen==0 ){
    +     rc = SQLITE_NOMEM;
    +   }
    +-
    +   if( rc==SQLITE_OK ){
    +     rc = pApi->xInstCount(pFts, &nInst);
    +   }
    +-  for(i=0; rc==SQLITE_OK && i<nInst; i++){
    +-    int ip, iSnippetCol, iStart;
    +-    memset(aSeen, 0, nPhrase);
    +-    rc = pApi->xInst(pFts, i, &ip, &iSnippetCol, &iStart);
    +-    if( rc==SQLITE_OK && (iCol<0 || iSnippetCol==iCol) ){
    +-      int nScore = 1000;
    +-      int iLast = iStart - 1 + pApi->xPhraseSize(pFts, ip);
    +-      int j;
    +-      aSeen[ip] = 1;
    + 
    +-      for(j=i+1; rc==SQLITE_OK && j<nInst; j++){
    +-        int ic; int io; int iFinal;
    +-        rc = pApi->xInst(pFts, j, &ip, &ic, &io);
    +-        iFinal = io + pApi->xPhraseSize(pFts, ip) - 1;
    +-        if( rc==SQLITE_OK && ic==iSnippetCol && iLast<iStart+nToken ){
    +-          nScore += aSeen[ip] ? 1000 : 1;
    +-          aSeen[ip] = 1;
    +-          if( iFinal>iLast ) iLast = iFinal;
    ++  memset(&sFinder, 0, sizeof(Fts5SFinder));
    ++  for(i=0; i<nCol; i++){
    ++    if( iCol<0 || iCol==i ){
    ++      int nDoc;
    ++      int nDocsize;
    ++      int ii;
    ++      sFinder.iPos = 0;
    ++      sFinder.nFirst = 0;
    ++      rc = pApi->xColumnText(pFts, i, &sFinder.zDoc, &nDoc);
    ++      if( rc!=SQLITE_OK ) break;
    ++      rc = pApi->xTokenize(pFts, 
    ++          sFinder.zDoc, nDoc, (void*)&sFinder,fts5SentenceFinderCb
    ++      );
    ++      if( rc!=SQLITE_OK ) break;
    ++      rc = pApi->xColumnSize(pFts, i, &nDocsize);
    ++      if( rc!=SQLITE_OK ) break;
    ++
    ++      for(ii=0; rc==SQLITE_OK && ii<nInst; ii++){
    ++        int ip, ic, io;
    ++        int iAdj;
    ++        int nScore;
    ++        int jj;
    ++
    ++        rc = pApi->xInst(pFts, ii, &ip, &ic, &io);
    ++        if( ic!=i || rc!=SQLITE_OK ) continue;
    ++        memset(aSeen, 0, nPhrase);
    ++        rc = fts5SnippetScore(pApi, pFts, nDocsize, aSeen, i,
    ++            io, nToken, &nScore, &iAdj
    ++        );
    ++        if( rc==SQLITE_OK && nScore>nBestScore ){
    ++          nBestScore = nScore;
    ++          iBestCol = i;
    ++          iBestStart = iAdj;
    ++          nColSize = nDocsize;
    +         }
    +-      }
    + 
    +-      if( rc==SQLITE_OK && nScore>nBestScore ){
    +-        iBestCol = iSnippetCol;
    +-        iBestStart = iStart;
    +-        iBestLast = iLast;
    +-        nBestScore = nScore;
    ++        if( rc==SQLITE_OK && sFinder.nFirst && nDocsize>nToken ){
    ++          for(jj=0; jj<(sFinder.nFirst-1); jj++){
    ++            if( sFinder.aFirst[jj+1]>io ) break;
    ++          }
    ++
    ++          if( sFinder.aFirst[jj]<io ){
    ++            memset(aSeen, 0, nPhrase);
    ++            rc = fts5SnippetScore(pApi, pFts, nDocsize, aSeen, i, 
    ++              sFinder.aFirst[jj], nToken, &nScore, 0
    ++            );
    ++
    ++            nScore += (sFinder.aFirst[jj]==0 ? 120 : 100);
    ++            if( rc==SQLITE_OK && nScore>nBestScore ){
    ++              nBestScore = nScore;
    ++              iBestCol = i;
    ++              iBestStart = sFinder.aFirst[jj];
    ++              nColSize = nDocsize;
    ++            }
    ++          }
    ++        }
    +       }
    +     }
    +   }
    + 
    +-  if( rc==SQLITE_OK ){
    +-    rc = pApi->xColumnSize(pFts, iBestCol, &nColSize);
    +-  }
    +   if( rc==SQLITE_OK ){
    +     rc = pApi->xColumnText(pFts, iBestCol, &ctx.zIn, &ctx.nIn);
    +   }
    ++  if( rc==SQLITE_OK && nColSize==0 ){
    ++    rc = pApi->xColumnSize(pFts, iBestCol, &nColSize);
    ++  }
    +   if( ctx.zIn ){
    +     if( rc==SQLITE_OK ){
    +       rc = fts5CInstIterInit(pApi, pFts, iBestCol, &ctx.iter);
    +     }
    + 
    +-    if( (iBestStart+nToken-1)>iBestLast ){
    +-      iBestStart -= (iBestStart+nToken-1-iBestLast) / 2;
    +-    }
    +-    if( iBestStart+nToken>nColSize ){
    +-      iBestStart = nColSize - nToken;
    +-    }
    +-    if( iBestStart<0 ) iBestStart = 0;
    +-
    +     ctx.iRangeStart = iBestStart;
    +     ctx.iRangeEnd = iBestStart + nToken - 1;
    + 
    +     if( iBestStart>0 ){
    +       fts5HighlightAppend(&rc, &ctx, zEllips, -1);
    +     }
    ++
    ++    /* Advance iterator ctx.iter so that it points to the first coalesced
    ++    ** phrase instance at or following position iBestStart. */
    ++    while( ctx.iter.iStart>=0 && ctx.iter.iStart<iBestStart && rc==SQLITE_OK ){
    ++      rc = fts5CInstIterNext(&ctx.iter);
    ++    }
    ++
    +     if( rc==SQLITE_OK ){
    +       rc = pApi->xTokenize(pFts, ctx.zIn, ctx.nIn, (void*)&ctx,fts5HighlightCb);
    +     }
    +@@ -168389,15 +189316,15 @@ static void fts5SnippetFunction(
    +     }else{
    +       fts5HighlightAppend(&rc, &ctx, zEllips, -1);
    +     }
    +-
    +-    if( rc==SQLITE_OK ){
    +-      sqlite3_result_text(pCtx, (const char*)ctx.zOut, -1, SQLITE_TRANSIENT);
    +-    }else{
    +-      sqlite3_result_error_code(pCtx, rc);
    +-    }
    +-    sqlite3_free(ctx.zOut);
    +   }
    ++  if( rc==SQLITE_OK ){
    ++    sqlite3_result_text(pCtx, (const char*)ctx.zOut, -1, SQLITE_TRANSIENT);
    ++  }else{
    ++    sqlite3_result_error_code(pCtx, rc);
    ++  }
    ++  sqlite3_free(ctx.zOut);
    +   sqlite3_free(aSeen);
    ++  sqlite3_free(sFinder.aFirst);
    + }
    + 
    + /************************************************************************/
    +@@ -168424,6 +189351,7 @@ static int fts5CountCb(
    +   void *pUserData                 /* Pointer to sqlite3_int64 variable */
    + ){
    +   sqlite3_int64 *pn = (sqlite3_int64*)pUserData;
    ++  UNUSED_PARAM2(pApi, pFts);
    +   (*pn)++;
    +   return SQLITE_OK;
    + }
    +@@ -168577,7 +189505,7 @@ static int sqlite3Fts5AuxInit(fts5_api *pApi){
    +   int rc = SQLITE_OK;             /* Return code */
    +   int i;                          /* To iterate through builtin functions */
    + 
    +-  for(i=0; rc==SQLITE_OK && i<sizeof(aBuiltin)/sizeof(aBuiltin[0]); i++){
    ++  for(i=0; rc==SQLITE_OK && i<ArraySize(aBuiltin); i++){
    +     rc = pApi->xCreateFunction(pApi,
    +         aBuiltin[i].zFunc,
    +         aBuiltin[i].pUserData,
    +@@ -168606,17 +189534,13 @@ static int sqlite3Fts5AuxInit(fts5_api *pApi){
    + 
    + 
    + 
    ++/* #include "fts5Int.h" */
    + 
    +-static int sqlite3Fts5BufferGrow(int *pRc, Fts5Buffer *pBuf, int nByte){
    +-
    +-  if( (pBuf->n + nByte) > pBuf->nSpace ){
    ++static int sqlite3Fts5BufferSize(int *pRc, Fts5Buffer *pBuf, u32 nByte){
    ++  if( (u32)pBuf->nSpace<nByte ){
    ++    u32 nNew = pBuf->nSpace ? pBuf->nSpace : 64;
    +     u8 *pNew;
    +-    int nNew = pBuf->nSpace ? pBuf->nSpace*2 : 64;
    +-
    +-    /* A no-op if an error has already occurred */
    +-    if( *pRc ) return 1;
    +-
    +-    while( nNew<(pBuf->n + nByte) ){
    ++    while( nNew<nByte ){
    +       nNew = nNew * 2;
    +     }
    +     pNew = sqlite3_realloc(pBuf->p, nNew);
    +@@ -168631,12 +189555,13 @@ static int sqlite3Fts5BufferGrow(int *pRc, Fts5Buffer *pBuf, int nByte){
    +   return 0;
    + }
    + 
    ++
    + /*
    + ** Encode value iVal as an SQLite varint and append it to the buffer object
    + ** pBuf. If an OOM error occurs, set the error code in p.
    + */
    + static void sqlite3Fts5BufferAppendVarint(int *pRc, Fts5Buffer *pBuf, i64 iVal){
    +-  if( sqlite3Fts5BufferGrow(pRc, pBuf, 9) ) return;
    ++  if( fts5BufferGrow(pRc, pBuf, 9) ) return;
    +   pBuf->n += sqlite3Fts5PutVarint(&pBuf->p[pBuf->n], iVal);
    + }
    + 
    +@@ -168651,12 +189576,6 @@ static int sqlite3Fts5Get32(const u8 *aBuf){
    +   return (aBuf[0] << 24) + (aBuf[1] << 16) + (aBuf[2] << 8) + aBuf[3];
    + }
    + 
    +-static void sqlite3Fts5BufferAppend32(int *pRc, Fts5Buffer *pBuf, int iVal){
    +-  if( sqlite3Fts5BufferGrow(pRc, pBuf, 4) ) return;
    +-  sqlite3Fts5Put32(&pBuf->p[pBuf->n], iVal);
    +-  pBuf->n += 4;
    +-}
    +-
    + /*
    + ** Append buffer nData/pData to buffer pBuf. If an OOM error occurs, set 
    + ** the error code in p. If an error has already occurred when this function
    +@@ -168665,13 +189584,15 @@ static void sqlite3Fts5BufferAppend32(int *pRc, Fts5Buffer *pBuf, int iVal){
    + static void sqlite3Fts5BufferAppendBlob(
    +   int *pRc,
    +   Fts5Buffer *pBuf, 
    +-  int nData, 
    ++  u32 nData, 
    +   const u8 *pData
    + ){
    +-  assert( *pRc || nData>=0 );
    +-  if( sqlite3Fts5BufferGrow(pRc, pBuf, nData) ) return;
    +-  memcpy(&pBuf->p[pBuf->n], pData, nData);
    +-  pBuf->n += nData;
    ++  assert_nc( *pRc || nData>=0 );
    ++  if( nData ){
    ++    if( fts5BufferGrow(pRc, pBuf, nData) ) return;
    ++    memcpy(&pBuf->p[pBuf->n], pData, nData);
    ++    pBuf->n += nData;
    ++  }
    + }
    + 
    + /*
    +@@ -168684,7 +189605,7 @@ static void sqlite3Fts5BufferAppendString(
    +   Fts5Buffer *pBuf, 
    +   const char *zStr
    + ){
    +-  int nStr = strlen(zStr);
    ++  int nStr = (int)strlen(zStr);
    +   sqlite3Fts5BufferAppendBlob(pRc, pBuf, nStr+1, (const u8*)zStr);
    +   pBuf->n--;
    + }
    +@@ -168812,31 +189733,44 @@ static int sqlite3Fts5PoslistReaderInit(
    +   return pIter->bEof;
    + }
    + 
    +-static int sqlite3Fts5PoslistWriterAppend(
    ++/*
    ++** Append position iPos to the position list being accumulated in buffer
    ++** pBuf, which must be already be large enough to hold the new data.
    ++** The previous position written to this list is *piPrev. *piPrev is set
    ++** to iPos before returning.
    ++*/
    ++static void sqlite3Fts5PoslistSafeAppend(
    +   Fts5Buffer *pBuf, 
    +-  Fts5PoslistWriter *pWriter,
    ++  i64 *piPrev, 
    +   i64 iPos
    + ){
    +   static const i64 colmask = ((i64)(0x7FFFFFFF)) << 32;
    +-  int rc = SQLITE_OK;
    +-  if( 0==sqlite3Fts5BufferGrow(&rc, pBuf, 5+5+5) ){
    +-    if( (iPos & colmask) != (pWriter->iPrev & colmask) ){
    +-      pBuf->p[pBuf->n++] = 1;
    +-      pBuf->n += sqlite3Fts5PutVarint(&pBuf->p[pBuf->n], (iPos>>32));
    +-      pWriter->iPrev = (iPos & colmask);
    +-    }
    +-    pBuf->n += sqlite3Fts5PutVarint(&pBuf->p[pBuf->n], (iPos-pWriter->iPrev)+2);
    +-    pWriter->iPrev = iPos;
    ++  if( (iPos & colmask) != (*piPrev & colmask) ){
    ++    pBuf->p[pBuf->n++] = 1;
    ++    pBuf->n += sqlite3Fts5PutVarint(&pBuf->p[pBuf->n], (iPos>>32));
    ++    *piPrev = (iPos & colmask);
    +   }
    +-  return rc;
    ++  pBuf->n += sqlite3Fts5PutVarint(&pBuf->p[pBuf->n], (iPos-*piPrev)+2);
    ++  *piPrev = iPos;
    ++}
    ++
    ++static int sqlite3Fts5PoslistWriterAppend(
    ++  Fts5Buffer *pBuf, 
    ++  Fts5PoslistWriter *pWriter,
    ++  i64 iPos
    ++){
    ++  int rc = 0;   /* Initialized only to suppress erroneous warning from Clang */
    ++  if( fts5BufferGrow(&rc, pBuf, 5+5+5) ) return rc;
    ++  sqlite3Fts5PoslistSafeAppend(pBuf, &pWriter->iPrev, iPos);
    ++  return SQLITE_OK;
    + }
    + 
    + static void *sqlite3Fts5MallocZero(int *pRc, int nByte){
    +   void *pRet = 0;
    +   if( *pRc==SQLITE_OK ){
    +     pRet = sqlite3_malloc(nByte);
    +-    if( pRet==0 && nByte>0 ){
    +-      *pRc = SQLITE_NOMEM;
    ++    if( pRet==0 ){
    ++      if( nByte>0 ) *pRc = SQLITE_NOMEM;
    +     }else{
    +       memset(pRet, 0, nByte);
    +     }
    +@@ -168856,7 +189790,7 @@ static char *sqlite3Fts5Strndup(int *pRc, const char *pIn, int nIn){
    +   char *zRet = 0;
    +   if( *pRc==SQLITE_OK ){
    +     if( nIn<0 ){
    +-      nIn = strlen(pIn);
    ++      nIn = (int)strlen(pIn);
    +     }
    +     zRet = (char*)sqlite3_malloc(nIn+1);
    +     if( zRet ){
    +@@ -168896,6 +189830,89 @@ static int sqlite3Fts5IsBareword(char t){
    + }
    + 
    + 
    ++/*************************************************************************
    ++*/
    ++typedef struct Fts5TermsetEntry Fts5TermsetEntry;
    ++struct Fts5TermsetEntry {
    ++  char *pTerm;
    ++  int nTerm;
    ++  int iIdx;                       /* Index (main or aPrefix[] entry) */
    ++  Fts5TermsetEntry *pNext;
    ++};
    ++
    ++struct Fts5Termset {
    ++  Fts5TermsetEntry *apHash[512];
    ++};
    ++
    ++static int sqlite3Fts5TermsetNew(Fts5Termset **pp){
    ++  int rc = SQLITE_OK;
    ++  *pp = sqlite3Fts5MallocZero(&rc, sizeof(Fts5Termset));
    ++  return rc;
    ++}
    ++
    ++static int sqlite3Fts5TermsetAdd(
    ++  Fts5Termset *p, 
    ++  int iIdx,
    ++  const char *pTerm, int nTerm, 
    ++  int *pbPresent
    ++){
    ++  int rc = SQLITE_OK;
    ++  *pbPresent = 0;
    ++  if( p ){
    ++    int i;
    ++    u32 hash = 13;
    ++    Fts5TermsetEntry *pEntry;
    ++
    ++    /* Calculate a hash value for this term. This is the same hash checksum
    ++    ** used by the fts5_hash.c module. This is not important for correct
    ++    ** operation of the module, but is necessary to ensure that some tests
    ++    ** designed to produce hash table collisions really do work.  */
    ++    for(i=nTerm-1; i>=0; i--){
    ++      hash = (hash << 3) ^ hash ^ pTerm[i];
    ++    }
    ++    hash = (hash << 3) ^ hash ^ iIdx;
    ++    hash = hash % ArraySize(p->apHash);
    ++
    ++    for(pEntry=p->apHash[hash]; pEntry; pEntry=pEntry->pNext){
    ++      if( pEntry->iIdx==iIdx 
    ++          && pEntry->nTerm==nTerm 
    ++          && memcmp(pEntry->pTerm, pTerm, nTerm)==0 
    ++      ){
    ++        *pbPresent = 1;
    ++        break;
    ++      }
    ++    }
    ++
    ++    if( pEntry==0 ){
    ++      pEntry = sqlite3Fts5MallocZero(&rc, sizeof(Fts5TermsetEntry) + nTerm);
    ++      if( pEntry ){
    ++        pEntry->pTerm = (char*)&pEntry[1];
    ++        pEntry->nTerm = nTerm;
    ++        pEntry->iIdx = iIdx;
    ++        memcpy(pEntry->pTerm, pTerm, nTerm);
    ++        pEntry->pNext = p->apHash[hash];
    ++        p->apHash[hash] = pEntry;
    ++      }
    ++    }
    ++  }
    ++
    ++  return rc;
    ++}
    ++
    ++static void sqlite3Fts5TermsetFree(Fts5Termset *p){
    ++  if( p ){
    ++    u32 i;
    ++    for(i=0; i<ArraySize(p->apHash); i++){
    ++      Fts5TermsetEntry *pEntry = p->apHash[i];
    ++      while( pEntry ){
    ++        Fts5TermsetEntry *pDel = pEntry;
    ++        pEntry = pEntry->pNext;
    ++        sqlite3_free(pDel);
    ++      }
    ++    }
    ++    sqlite3_free(p);
    ++  }
    ++}
    + 
    + /*
    + ** 2014 Jun 09
    +@@ -168913,11 +189930,13 @@ static int sqlite3Fts5IsBareword(char t){
    + */
    + 
    + 
    +-
    ++/* #include "fts5Int.h" */
    + 
    + #define FTS5_DEFAULT_PAGE_SIZE   4050
    + #define FTS5_DEFAULT_AUTOMERGE      4
    ++#define FTS5_DEFAULT_USERMERGE      4
    + #define FTS5_DEFAULT_CRISISMERGE   16
    ++#define FTS5_DEFAULT_HASHSIZE    (1024*1024)
    + 
    + /* Maximum allowed page size */
    + #define FTS5_MAX_PAGE_SIZE (128*1024)
    +@@ -169092,6 +190111,33 @@ static void sqlite3Fts5Dequote(char *z){
    +   }
    + }
    + 
    ++
    ++struct Fts5Enum {
    ++  const char *zName;
    ++  int eVal;
    ++};
    ++typedef struct Fts5Enum Fts5Enum;
    ++
    ++static int fts5ConfigSetEnum(
    ++  const Fts5Enum *aEnum, 
    ++  const char *zEnum, 
    ++  int *peVal
    ++){
    ++  int nEnum = (int)strlen(zEnum);
    ++  int i;
    ++  int iVal = -1;
    ++
    ++  for(i=0; aEnum[i].zName; i++){
    ++    if( sqlite3_strnicmp(aEnum[i].zName, zEnum, nEnum)==0 ){
    ++      if( iVal>=0 ) return SQLITE_ERROR;
    ++      iVal = aEnum[i].eVal;
    ++    }
    ++  }
    ++
    ++  *peVal = iVal;
    ++  return iVal<0 ? SQLITE_ERROR : SQLITE_OK;
    ++}
    ++
    + /*
    + ** Parse a "special" CREATE VIRTUAL TABLE directive and update
    + ** configuration object pConfig as appropriate.
    +@@ -169109,44 +190155,63 @@ static int fts5ConfigParseSpecial(
    +   char **pzErr                    /* OUT: Error message */
    + ){
    +   int rc = SQLITE_OK;
    +-  int nCmd = strlen(zCmd);
    ++  int nCmd = (int)strlen(zCmd);
    +   if( sqlite3_strnicmp("prefix", zCmd, nCmd)==0 ){
    +     const int nByte = sizeof(int) * FTS5_MAX_PREFIX_INDEXES;
    +     const char *p;
    +-    if( pConfig->aPrefix ){
    +-      *pzErr = sqlite3_mprintf("multiple prefix=... directives");
    +-      rc = SQLITE_ERROR;
    +-    }else{
    ++    int bFirst = 1;
    ++    if( pConfig->aPrefix==0 ){
    +       pConfig->aPrefix = sqlite3Fts5MallocZero(&rc, nByte);
    ++      if( rc ) return rc;
    +     }
    ++
    +     p = zArg;
    +-    while( rc==SQLITE_OK && p[0] ){
    ++    while( 1 ){
    +       int nPre = 0;
    ++
    +       while( p[0]==' ' ) p++;
    +-      while( p[0]>='0' && p[0]<='9' && nPre<1000 ){
    +-        nPre = nPre*10 + (p[0] - '0');
    ++      if( bFirst==0 && p[0]==',' ){
    +         p++;
    ++        while( p[0]==' ' ) p++;
    ++      }else if( p[0]=='\0' ){
    ++        break;
    +       }
    +-      while( p[0]==' ' ) p++;
    +-      if( p[0]==',' ){
    +-        p++;
    +-      }else if( p[0] ){
    ++      if( p[0]<'0' || p[0]>'9' ){
    +         *pzErr = sqlite3_mprintf("malformed prefix=... directive");
    +         rc = SQLITE_ERROR;
    ++        break;
    +       }
    +-      if( rc==SQLITE_OK && (nPre==0 || nPre>=1000) ){
    +-        *pzErr = sqlite3_mprintf("prefix length out of range: %d", nPre);
    ++
    ++      if( pConfig->nPrefix==FTS5_MAX_PREFIX_INDEXES ){
    ++        *pzErr = sqlite3_mprintf(
    ++            "too many prefix indexes (max %d)", FTS5_MAX_PREFIX_INDEXES
    ++        );
    +         rc = SQLITE_ERROR;
    ++        break;
    +       }
    ++
    ++      while( p[0]>='0' && p[0]<='9' && nPre<1000 ){
    ++        nPre = nPre*10 + (p[0] - '0');
    ++        p++;
    ++      }
    ++
    ++      if( nPre<=0 || nPre>=1000 ){
    ++        *pzErr = sqlite3_mprintf("prefix length out of range (max 999)");
    ++        rc = SQLITE_ERROR;
    ++        break;
    ++      }
    ++
    +       pConfig->aPrefix[pConfig->nPrefix] = nPre;
    +       pConfig->nPrefix++;
    ++      bFirst = 0;
    +     }
    ++    assert( pConfig->nPrefix<=FTS5_MAX_PREFIX_INDEXES );
    +     return rc;
    +   }
    + 
    +   if( sqlite3_strnicmp("tokenize", zCmd, nCmd)==0 ){
    +     const char *p = (const char*)zArg;
    +-    int nArg = strlen(zArg) + 1;
    ++    int nArg = (int)strlen(zArg) + 1;
    +     char **azArg = sqlite3Fts5MallocZero(&rc, sizeof(char*) * nArg);
    +     char *pDel = sqlite3Fts5MallocZero(&rc, nArg * 2);
    +     char *pSpace = pDel;
    +@@ -169223,6 +190288,20 @@ static int fts5ConfigParseSpecial(
    +     return rc;
    +   }
    + 
    ++  if( sqlite3_strnicmp("detail", zCmd, nCmd)==0 ){
    ++    const Fts5Enum aDetail[] = {
    ++      { "none", FTS5_DETAIL_NONE },
    ++      { "full", FTS5_DETAIL_FULL },
    ++      { "columns", FTS5_DETAIL_COLUMNS },
    ++      { 0, 0 }
    ++    };
    ++
    ++    if( (rc = fts5ConfigSetEnum(aDetail, zArg, &pConfig->eDetail)) ){
    ++      *pzErr = sqlite3_mprintf("malformed detail=... directive");
    ++    }
    ++    return rc;
    ++  }
    ++
    +   *pzErr = sqlite3_mprintf("unrecognized option: \"%.*s\"", nCmd, zCmd);
    +   return SQLITE_ERROR;
    + }
    +@@ -169262,7 +190341,7 @@ static const char *fts5ConfigGobbleWord(
    + ){
    +   const char *zRet = 0;
    + 
    +-  int nIn = strlen(zIn);
    ++  int nIn = (int)strlen(zIn);
    +   char *zOut = sqlite3_malloc(nIn+1);
    + 
    +   assert( *pRc==SQLITE_OK );
    +@@ -169279,7 +190358,9 @@ static const char *fts5ConfigGobbleWord(
    +       *pbQuoted = 1;
    +     }else{
    +       zRet = fts5ConfigSkipBareword(zIn);
    +-      zOut[zRet-zIn] = '\0';
    ++      if( zRet ){
    ++        zOut[zRet-zIn] = '\0';
    ++      }
    +     }
    +   }
    + 
    +@@ -169378,6 +190459,7 @@ static int sqlite3Fts5ConfigParse(
    +   pRet->zDb = sqlite3Fts5Strndup(&rc, azArg[1], -1);
    +   pRet->zName = sqlite3Fts5Strndup(&rc, azArg[2], -1);
    +   pRet->bColumnsize = 1;
    ++  pRet->eDetail = FTS5_DETAIL_FULL;
    + #ifdef SQLITE_DEBUG
    +   pRet->bPrefixIndex = 1;
    + #endif
    +@@ -169604,33 +190686,37 @@ static int sqlite3Fts5ConfigParseRank(
    +   *pzRank = 0;
    +   *pzRankArgs = 0;
    + 
    +-  p = fts5ConfigSkipWhitespace(p);
    +-  pRank = p;
    +-  p = fts5ConfigSkipBareword(p);
    +-
    +-  if( p ){
    +-    zRank = sqlite3Fts5MallocZero(&rc, 1 + p - pRank);
    +-    if( zRank ) memcpy(zRank, pRank, p-pRank);
    +-  }else{
    ++  if( p==0 ){
    +     rc = SQLITE_ERROR;
    +-  }
    +-
    +-  if( rc==SQLITE_OK ){
    +-    p = fts5ConfigSkipWhitespace(p);
    +-    if( *p!='(' ) rc = SQLITE_ERROR;
    +-    p++;
    +-  }
    +-  if( rc==SQLITE_OK ){
    +-    const char *pArgs; 
    ++  }else{
    +     p = fts5ConfigSkipWhitespace(p);
    +-    pArgs = p;
    +-    if( *p!=')' ){
    +-      p = fts5ConfigSkipArgs(p);
    +-      if( p==0 ){
    +-        rc = SQLITE_ERROR;
    +-      }else{
    +-        zRankArgs = sqlite3Fts5MallocZero(&rc, 1 + p - pArgs);
    +-        if( zRankArgs ) memcpy(zRankArgs, pArgs, p-pArgs);
    ++    pRank = p;
    ++    p = fts5ConfigSkipBareword(p);
    ++
    ++    if( p ){
    ++      zRank = sqlite3Fts5MallocZero(&rc, 1 + p - pRank);
    ++      if( zRank ) memcpy(zRank, pRank, p-pRank);
    ++    }else{
    ++      rc = SQLITE_ERROR;
    ++    }
    ++
    ++    if( rc==SQLITE_OK ){
    ++      p = fts5ConfigSkipWhitespace(p);
    ++      if( *p!='(' ) rc = SQLITE_ERROR;
    ++      p++;
    ++    }
    ++    if( rc==SQLITE_OK ){
    ++      const char *pArgs; 
    ++      p = fts5ConfigSkipWhitespace(p);
    ++      pArgs = p;
    ++      if( *p!=')' ){
    ++        p = fts5ConfigSkipArgs(p);
    ++        if( p==0 ){
    ++          rc = SQLITE_ERROR;
    ++        }else{
    ++          zRankArgs = sqlite3Fts5MallocZero(&rc, 1 + p - pArgs);
    ++          if( zRankArgs ) memcpy(zRankArgs, pArgs, p-pArgs);
    ++        }
    +       }
    +     }
    +   }
    +@@ -169665,6 +190751,18 @@ static int sqlite3Fts5ConfigSetValue(
    +     }
    +   }
    + 
    ++  else if( 0==sqlite3_stricmp(zKey, "hashsize") ){
    ++    int nHashSize = -1;
    ++    if( SQLITE_INTEGER==sqlite3_value_numeric_type(pVal) ){
    ++      nHashSize = sqlite3_value_int(pVal);
    ++    }
    ++    if( nHashSize<=0 ){
    ++      *pbBadkey = 1;
    ++    }else{
    ++      pConfig->nHashSize = nHashSize;
    ++    }
    ++  }
    ++
    +   else if( 0==sqlite3_stricmp(zKey, "automerge") ){
    +     int nAutomerge = -1;
    +     if( SQLITE_INTEGER==sqlite3_value_numeric_type(pVal) ){
    +@@ -169678,6 +190776,18 @@ static int sqlite3Fts5ConfigSetValue(
    +     }
    +   }
    + 
    ++  else if( 0==sqlite3_stricmp(zKey, "usermerge") ){
    ++    int nUsermerge = -1;
    ++    if( SQLITE_INTEGER==sqlite3_value_numeric_type(pVal) ){
    ++      nUsermerge = sqlite3_value_int(pVal);
    ++    }
    ++    if( nUsermerge<2 || nUsermerge>16 ){
    ++      *pbBadkey = 1;
    ++    }else{
    ++      pConfig->nUsermerge = nUsermerge;
    ++    }
    ++  }
    ++
    +   else if( 0==sqlite3_stricmp(zKey, "crisismerge") ){
    +     int nCrisisMerge = -1;
    +     if( SQLITE_INTEGER==sqlite3_value_numeric_type(pVal) ){
    +@@ -169724,7 +190834,9 @@ static int sqlite3Fts5ConfigLoad(Fts5Config *pConfig, int iCookie){
    +   /* Set default values */
    +   pConfig->pgsz = FTS5_DEFAULT_PAGE_SIZE;
    +   pConfig->nAutomerge = FTS5_DEFAULT_AUTOMERGE;
    ++  pConfig->nUsermerge = FTS5_DEFAULT_USERMERGE;
    +   pConfig->nCrisisMerge = FTS5_DEFAULT_CRISISMERGE;
    ++  pConfig->nHashSize = FTS5_DEFAULT_HASHSIZE;
    + 
    +   zSql = sqlite3Fts5Mprintf(&rc, zSelect, pConfig->zDb, pConfig->zName);
    +   if( zSql ){
    +@@ -169764,7 +190876,6 @@ static int sqlite3Fts5ConfigLoad(Fts5Config *pConfig, int iCookie){
    +   return rc;
    + }
    + 
    +-
    + /*
    + ** 2014 May 31
    + **
    +@@ -169781,6 +190892,8 @@ static int sqlite3Fts5ConfigLoad(Fts5Config *pConfig, int iCookie){
    + 
    + 
    + 
    ++/* #include "fts5Int.h" */
    ++/* #include "fts5parse.h" */
    + 
    + /*
    + ** All token types in the generated fts5parse.h file are greater than 0.
    +@@ -169805,6 +190918,7 @@ static void sqlite3Fts5ParserTrace(FILE*, char*);
    + 
    + struct Fts5Expr {
    +   Fts5Index *pIndex;
    ++  Fts5Config *pConfig;
    +   Fts5ExprNode *pRoot;
    +   int bDesc;                      /* Iterate in descending rowid order */
    +   int nPhrase;                    /* Number of phrases in expression */
    +@@ -169826,6 +190940,9 @@ struct Fts5ExprNode {
    +   int bEof;                       /* True at EOF */
    +   int bNomatch;                   /* True if entry is not a match */
    + 
    ++  /* Next method for this node. */
    ++  int (*xNext)(Fts5Expr*, Fts5ExprNode*, int, i64);
    ++
    +   i64 iRowid;                     /* Current rowid */
    +   Fts5ExprNearset *pNear;         /* For FTS5_STRING - cluster of phrases */
    + 
    +@@ -169837,12 +190954,19 @@ struct Fts5ExprNode {
    + 
    + #define Fts5NodeIsString(p) ((p)->eType==FTS5_TERM || (p)->eType==FTS5_STRING)
    + 
    ++/*
    ++** Invoke the xNext method of an Fts5ExprNode object. This macro should be
    ++** used as if it has the same signature as the xNext() methods themselves.
    ++*/
    ++#define fts5ExprNodeNext(a,b,c,d) (b)->xNext((a), (b), (c), (d))
    ++
    + /*
    + ** An instance of the following structure represents a single search term
    + ** or term prefix.
    + */
    + struct Fts5ExprTerm {
    +-  int bPrefix;                    /* True for a prefix term */
    ++  u8 bPrefix;                     /* True for a prefix term */
    ++  u8 bFirst;                      /* True if token must be first in column */
    +   char *zTerm;                    /* nul-terminated term */
    +   Fts5IndexIter *pIter;           /* Iterator for this term */
    +   Fts5ExprTerm *pSynonym;         /* Pointer to first in list of synonyms */
    +@@ -169922,6 +191046,8 @@ static int fts5ExprGetToken(
    +     case ',':  tok = FTS5_COMMA; break;
    +     case '+':  tok = FTS5_PLUS;  break;
    +     case '*':  tok = FTS5_STAR;  break;
    ++    case '-':  tok = FTS5_MINUS; break;
    ++    case '^':  tok = FTS5_CARET; break;
    +     case '\0': tok = FTS5_EOF;   break;
    + 
    +     case '"': {
    +@@ -169967,6 +191093,7 @@ static void fts5ParseFree(void *p){ sqlite3_free(p); }
    + 
    + static int sqlite3Fts5ExprNew(
    +   Fts5Config *pConfig,            /* FTS5 Configuration */
    ++  int iCol,
    +   const char *zExpr,              /* Expression text */
    +   Fts5Expr **ppNew, 
    +   char **pzErr
    +@@ -169991,6 +191118,18 @@ static int sqlite3Fts5ExprNew(
    +   }while( sParse.rc==SQLITE_OK && t!=FTS5_EOF );
    +   sqlite3Fts5ParserFree(pEngine, fts5ParseFree);
    + 
    ++  /* If the LHS of the MATCH expression was a user column, apply the
    ++  ** implicit column-filter.  */
    ++  if( iCol<pConfig->nCol && sParse.pExpr && sParse.rc==SQLITE_OK ){
    ++    int n = sizeof(Fts5Colset);
    ++    Fts5Colset *pColset = (Fts5Colset*)sqlite3Fts5MallocZero(&sParse.rc, n);
    ++    if( pColset ){
    ++      pColset->nCol = 1;
    ++      pColset->aiCol[0] = iCol;
    ++      sqlite3Fts5ParseSetColset(&sParse, sParse.pExpr, pColset);
    ++    }
    ++  }
    ++
    +   assert( sParse.rc!=SQLITE_OK || sParse.zErr==0 );
    +   if( sParse.rc==SQLITE_OK ){
    +     *ppNew = pNew = sqlite3_malloc(sizeof(Fts5Expr));
    +@@ -169998,12 +191137,23 @@ static int sqlite3Fts5ExprNew(
    +       sParse.rc = SQLITE_NOMEM;
    +       sqlite3Fts5ParseNodeFree(sParse.pExpr);
    +     }else{
    +-      pNew->pRoot = sParse.pExpr;
    ++      if( !sParse.pExpr ){
    ++        const int nByte = sizeof(Fts5ExprNode);
    ++        pNew->pRoot = (Fts5ExprNode*)sqlite3Fts5MallocZero(&sParse.rc, nByte);
    ++        if( pNew->pRoot ){
    ++          pNew->pRoot->bEof = 1;
    ++        }
    ++      }else{
    ++        pNew->pRoot = sParse.pExpr;
    ++      }
    +       pNew->pIndex = 0;
    ++      pNew->pConfig = pConfig;
    +       pNew->apExprPhrase = sParse.apPhrase;
    +       pNew->nPhrase = sParse.nPhrase;
    +       sParse.apPhrase = 0;
    +     }
    ++  }else{
    ++    sqlite3Fts5ParseNodeFree(sParse.pExpr);
    +   }
    + 
    +   sqlite3_free(sParse.apPhrase);
    +@@ -170049,7 +191199,7 @@ static i64 fts5ExprSynonymRowid(Fts5ExprTerm *pTerm, int bDesc, int *pbEof){
    +   assert( bDesc==0 || bDesc==1 );
    +   for(p=pTerm; p; p=p->pSynonym){
    +     if( 0==sqlite3Fts5IterEof(p->pIter) ){
    +-      i64 iRowid = sqlite3Fts5IterRowid(p->pIter);
    ++      i64 iRowid = p->pIter->iRowid;
    +       if( bRetValid==0 || (bDesc!=(iRowid<iRet)) ){
    +         iRet = iRowid;
    +         bRetValid = 1;
    +@@ -170064,11 +191214,10 @@ static i64 fts5ExprSynonymRowid(Fts5ExprTerm *pTerm, int bDesc, int *pbEof){
    + /*
    + ** Argument pTerm must be a synonym iterator.
    + */
    +-static int fts5ExprSynonymPoslist(
    ++static int fts5ExprSynonymList(
    +   Fts5ExprTerm *pTerm, 
    +-  Fts5Colset *pColset,
    +   i64 iRowid,
    +-  int *pbDel,                     /* OUT: Caller should sqlite3_free(*pa) */
    ++  Fts5Buffer *pBuf,               /* Use this buffer for space if required */
    +   u8 **pa, int *pn
    + ){
    +   Fts5PoslistReader aStatic[4];
    +@@ -170081,12 +191230,8 @@ static int fts5ExprSynonymPoslist(
    +   assert( pTerm->pSynonym );
    +   for(p=pTerm; p; p=p->pSynonym){
    +     Fts5IndexIter *pIter = p->pIter;
    +-    if( sqlite3Fts5IterEof(pIter)==0 && sqlite3Fts5IterRowid(pIter)==iRowid ){
    +-      const u8 *a;
    +-      int n;
    +-      i64 dummy;
    +-      rc = sqlite3Fts5IterPoslist(pIter, pColset, &a, &n, &dummy);
    +-      if( rc!=SQLITE_OK ) goto synonym_poslist_out;
    ++    if( sqlite3Fts5IterEof(pIter)==0 && pIter->iRowid==iRowid ){
    ++      if( pIter->nData==0 ) continue;
    +       if( nIter==nAlloc ){
    +         int nByte = sizeof(Fts5PoslistReader) * nAlloc * 2;
    +         Fts5PoslistReader *aNew = (Fts5PoslistReader*)sqlite3_malloc(nByte);
    +@@ -170099,20 +191244,19 @@ static int fts5ExprSynonymPoslist(
    +         if( aIter!=aStatic ) sqlite3_free(aIter);
    +         aIter = aNew;
    +       }
    +-      sqlite3Fts5PoslistReaderInit(a, n, &aIter[nIter]);
    ++      sqlite3Fts5PoslistReaderInit(pIter->pData, pIter->nData, &aIter[nIter]);
    +       assert( aIter[nIter].bEof==0 );
    +       nIter++;
    +     }
    +   }
    + 
    +-  assert( *pbDel==0 );
    +   if( nIter==1 ){
    +     *pa = (u8*)aIter[0].a;
    +     *pn = aIter[0].n;
    +   }else{
    +     Fts5PoslistWriter writer = {0};
    +-    Fts5Buffer buf = {0,0,0};
    +     i64 iPrev = -1;
    ++    fts5BufferZero(pBuf);
    +     while( 1 ){
    +       int i;
    +       i64 iMin = FTS5_LARGEST_INT64;
    +@@ -170127,15 +191271,12 @@ static int fts5ExprSynonymPoslist(
    +         }
    +       }
    +       if( iMin==FTS5_LARGEST_INT64 || rc!=SQLITE_OK ) break;
    +-      rc = sqlite3Fts5PoslistWriterAppend(&buf, &writer, iMin);
    ++      rc = sqlite3Fts5PoslistWriterAppend(pBuf, &writer, iMin);
    +       iPrev = iMin;
    +     }
    +-    if( rc ){
    +-      sqlite3_free(buf.p);
    +-    }else{
    +-      *pa = buf.p;
    +-      *pn = buf.n;
    +-      *pbDel = 1;
    ++    if( rc==SQLITE_OK ){
    ++      *pa = pBuf->p;
    ++      *pn = pBuf->n;
    +     }
    +   }
    + 
    +@@ -170158,7 +191299,6 @@ static int fts5ExprSynonymPoslist(
    + */
    + static int fts5ExprPhraseIsMatch(
    +   Fts5ExprNode *pNode,            /* Node pPhrase belongs to */
    +-  Fts5Colset *pColset,            /* Restrict matches to these columns */
    +   Fts5ExprPhrase *pPhrase,        /* Phrase object to initialize */
    +   int *pbMatch                    /* OUT: Set to true if really a match */
    + ){
    +@@ -170167,12 +191307,13 @@ static int fts5ExprPhraseIsMatch(
    +   Fts5PoslistReader *aIter = aStatic;
    +   int i;
    +   int rc = SQLITE_OK;
    ++  int bFirst = pPhrase->aTerm[0].bFirst;
    +   
    +   fts5BufferZero(&pPhrase->poslist);
    + 
    +   /* If the aStatic[] array is not large enough, allocate a large array
    +   ** using sqlite3_malloc(). This approach could be improved upon. */
    +-  if( pPhrase->nTerm>(sizeof(aStatic) / sizeof(aStatic[0])) ){
    ++  if( pPhrase->nTerm>ArraySize(aStatic) ){
    +     int nByte = sizeof(Fts5PoslistReader) * pPhrase->nTerm;
    +     aIter = (Fts5PoslistReader*)sqlite3_malloc(nByte);
    +     if( !aIter ) return SQLITE_NOMEM;
    +@@ -170182,20 +191323,23 @@ static int fts5ExprPhraseIsMatch(
    +   /* Initialize a term iterator for each term in the phrase */
    +   for(i=0; i<pPhrase->nTerm; i++){
    +     Fts5ExprTerm *pTerm = &pPhrase->aTerm[i];
    +-    i64 dummy;
    +     int n = 0;
    +     int bFlag = 0;
    +-    const u8 *a = 0;
    ++    u8 *a = 0;
    +     if( pTerm->pSynonym ){
    +-      rc = fts5ExprSynonymPoslist(
    +-          pTerm, pColset, pNode->iRowid, &bFlag, (u8**)&a, &n
    +-      );
    ++      Fts5Buffer buf = {0, 0, 0};
    ++      rc = fts5ExprSynonymList(pTerm, pNode->iRowid, &buf, &a, &n);
    ++      if( rc ){
    ++        sqlite3_free(a);
    ++        goto ismatch_out;
    ++      }
    ++      if( a==buf.p ) bFlag = 1;
    +     }else{
    +-      rc = sqlite3Fts5IterPoslist(pTerm->pIter, pColset, &a, &n, &dummy);
    ++      a = (u8*)pTerm->pIter->pData;
    ++      n = pTerm->pIter->nData;
    +     }
    +-    if( rc!=SQLITE_OK ) goto ismatch_out;
    +     sqlite3Fts5PoslistReaderInit(a, n, &aIter[i]);
    +-    aIter[i].bFlag = bFlag;
    ++    aIter[i].bFlag = (u8)bFlag;
    +     if( aIter[i].bEof ) goto ismatch_out;
    +   }
    + 
    +@@ -170218,8 +191362,10 @@ static int fts5ExprPhraseIsMatch(
    +     }while( bMatch==0 );
    + 
    +     /* Append position iPos to the output */
    +-    rc = sqlite3Fts5PoslistWriterAppend(&pPhrase->poslist, &writer, iPos);
    +-    if( rc!=SQLITE_OK ) goto ismatch_out;
    ++    if( bFirst==0 || FTS5_POS2OFFSET(iPos)==0 ){
    ++      rc = sqlite3Fts5PoslistWriterAppend(&pPhrase->poslist, &writer, iPos);
    ++      if( rc!=SQLITE_OK ) goto ismatch_out;
    ++    }
    + 
    +     for(i=0; i<pPhrase->nTerm; i++){
    +       if( sqlite3Fts5PoslistReaderNext(&aIter[i]) ) goto ismatch_out;
    +@@ -170265,12 +191411,6 @@ static int fts5LookaheadReaderInit(
    +   return fts5LookaheadReaderNext(p);
    + }
    + 
    +-#if 0
    +-static int fts5LookaheadReaderEof(Fts5LookaheadReader *p){
    +-  return (p->iPos==FTS5_LOOKAHEAD_EOF);
    +-}
    +-#endif
    +-
    + typedef struct Fts5NearTrimmer Fts5NearTrimmer;
    + struct Fts5NearTrimmer {
    +   Fts5LookaheadReader reader;     /* Input iterator */
    +@@ -170308,7 +191448,7 @@ static int fts5ExprNearIsMatch(int *pRc, Fts5ExprNearset *pNear){
    + 
    +   /* If the aStatic[] array is not large enough, allocate a large array
    +   ** using sqlite3_malloc(). This approach could be improved upon. */
    +-  if( pNear->nPhrase>(sizeof(aStatic) / sizeof(aStatic[0])) ){
    ++  if( pNear->nPhrase>ArraySize(aStatic) ){
    +     int nByte = sizeof(Fts5NearTrimmer) * pNear->nPhrase;
    +     a = (Fts5NearTrimmer*)sqlite3Fts5MallocZero(&rc, nByte);
    +   }else{
    +@@ -170385,71 +191525,6 @@ static int fts5ExprNearIsMatch(int *pRc, Fts5ExprNearset *pNear){
    +   }
    + }
    + 
    +-/*
    +-** Advance the first term iterator in the first phrase of pNear. Set output
    +-** variable *pbEof to true if it reaches EOF or if an error occurs.
    +-**
    +-** Return SQLITE_OK if successful, or an SQLite error code if an error
    +-** occurs.
    +-*/
    +-static int fts5ExprNearAdvanceFirst(
    +-  Fts5Expr *pExpr,                /* Expression pPhrase belongs to */
    +-  Fts5ExprNode *pNode,            /* FTS5_STRING or FTS5_TERM node */
    +-  int bFromValid,
    +-  i64 iFrom 
    +-){
    +-  Fts5ExprTerm *pTerm = &pNode->pNear->apPhrase[0]->aTerm[0];
    +-  int rc = SQLITE_OK;
    +-
    +-  if( pTerm->pSynonym ){
    +-    int bEof = 1;
    +-    Fts5ExprTerm *p;
    +-
    +-    /* Find the firstest rowid any synonym points to. */
    +-    i64 iRowid = fts5ExprSynonymRowid(pTerm, pExpr->bDesc, 0);
    +-
    +-    /* Advance each iterator that currently points to iRowid. Or, if iFrom
    +-    ** is valid - each iterator that points to a rowid before iFrom.  */
    +-    for(p=pTerm; p; p=p->pSynonym){
    +-      if( sqlite3Fts5IterEof(p->pIter)==0 ){
    +-        i64 ii = sqlite3Fts5IterRowid(p->pIter);
    +-        if( ii==iRowid 
    +-         || (bFromValid && ii!=iFrom && (ii>iFrom)==pExpr->bDesc) 
    +-        ){
    +-          if( bFromValid ){
    +-            rc = sqlite3Fts5IterNextFrom(p->pIter, iFrom);
    +-          }else{
    +-            rc = sqlite3Fts5IterNext(p->pIter);
    +-          }
    +-          if( rc!=SQLITE_OK ) break;
    +-          if( sqlite3Fts5IterEof(p->pIter)==0 ){
    +-            bEof = 0;
    +-          }
    +-        }else{
    +-          bEof = 0;
    +-        }
    +-      }
    +-    }
    +-
    +-    /* Set the EOF flag if either all synonym iterators are at EOF or an
    +-    ** error has occurred.  */
    +-    pNode->bEof = (rc || bEof);
    +-  }else{
    +-    Fts5IndexIter *pIter = pTerm->pIter;
    +-
    +-    assert( Fts5NodeIsString(pNode) );
    +-    if( bFromValid ){
    +-      rc = sqlite3Fts5IterNextFrom(pIter, iFrom);
    +-    }else{
    +-      rc = sqlite3Fts5IterNext(pIter);
    +-    }
    +-
    +-    pNode->bEof = (rc || sqlite3Fts5IterEof(pIter));
    +-  }
    +-
    +-  return rc;
    +-}
    +-
    + /*
    + ** Advance iterator pIter until it points to a value equal to or laster
    + ** than the initial value of *piLast. If this means the iterator points
    +@@ -170469,7 +191544,7 @@ static int fts5ExprAdvanceto(
    +   i64 iLast = *piLast;
    +   i64 iRowid;
    + 
    +-  iRowid = sqlite3Fts5IterRowid(pIter);
    ++  iRowid = pIter->iRowid;
    +   if( (bDesc==0 && iLast>iRowid) || (bDesc && iLast<iRowid) ){
    +     int rc = sqlite3Fts5IterNextFrom(pIter, iLast);
    +     if( rc || sqlite3Fts5IterEof(pIter) ){
    +@@ -170477,7 +191552,7 @@ static int fts5ExprAdvanceto(
    +       *pbEof = 1;
    +       return 1;
    +     }
    +-    iRowid = sqlite3Fts5IterRowid(pIter);
    ++    iRowid = pIter->iRowid;
    +     assert( (bDesc==0 && iRowid>=iLast) || (bDesc==1 && iRowid<=iLast) );
    +   }
    +   *piLast = iRowid;
    +@@ -170498,7 +191573,7 @@ static int fts5ExprSynonymAdvanceto(
    + 
    +   for(p=pTerm; rc==SQLITE_OK && p; p=p->pSynonym){
    +     if( sqlite3Fts5IterEof(p->pIter)==0 ){
    +-      i64 iRowid = sqlite3Fts5IterRowid(p->pIter);
    ++      i64 iRowid = p->pIter->iRowid;
    +       if( (bDesc==0 && iLast>iRowid) || (bDesc && iLast<iRowid) ){
    +         rc = sqlite3Fts5IterNextFrom(p->pIter, iLast);
    +       }
    +@@ -170522,56 +191597,182 @@ static int fts5ExprNearTest(
    + ){
    +   Fts5ExprNearset *pNear = pNode->pNear;
    +   int rc = *pRc;
    ++
    ++  if( pExpr->pConfig->eDetail!=FTS5_DETAIL_FULL ){
    ++    Fts5ExprTerm *pTerm;
    ++    Fts5ExprPhrase *pPhrase = pNear->apPhrase[0];
    ++    pPhrase->poslist.n = 0;
    ++    for(pTerm=&pPhrase->aTerm[0]; pTerm; pTerm=pTerm->pSynonym){
    ++      Fts5IndexIter *pIter = pTerm->pIter;
    ++      if( sqlite3Fts5IterEof(pIter)==0 ){
    ++        if( pIter->iRowid==pNode->iRowid && pIter->nData>0 ){
    ++          pPhrase->poslist.n = 1;
    ++        }
    ++      }
    ++    }
    ++    return pPhrase->poslist.n;
    ++  }else{
    ++    int i;
    ++
    ++    /* Check that each phrase in the nearset matches the current row.
    ++    ** Populate the pPhrase->poslist buffers at the same time. If any
    ++    ** phrase is not a match, break out of the loop early.  */
    ++    for(i=0; rc==SQLITE_OK && i<pNear->nPhrase; i++){
    ++      Fts5ExprPhrase *pPhrase = pNear->apPhrase[i];
    ++      if( pPhrase->nTerm>1 || pPhrase->aTerm[0].pSynonym 
    ++       || pNear->pColset || pPhrase->aTerm[0].bFirst
    ++      ){
    ++        int bMatch = 0;
    ++        rc = fts5ExprPhraseIsMatch(pNode, pPhrase, &bMatch);
    ++        if( bMatch==0 ) break;
    ++      }else{
    ++        Fts5IndexIter *pIter = pPhrase->aTerm[0].pIter;
    ++        fts5BufferSet(&rc, &pPhrase->poslist, pIter->nData, pIter->pData);
    ++      }
    ++    }
    ++
    ++    *pRc = rc;
    ++    if( i==pNear->nPhrase && (i==1 || fts5ExprNearIsMatch(pRc, pNear)) ){
    ++      return 1;
    ++    }
    ++    return 0;
    ++  }
    ++}
    ++
    ++
    ++/*
    ++** Initialize all term iterators in the pNear object. If any term is found
    ++** to match no documents at all, return immediately without initializing any
    ++** further iterators.
    ++**
    ++** If an error occurs, return an SQLite error code. Otherwise, return
    ++** SQLITE_OK. It is not considered an error if some term matches zero
    ++** documents.
    ++*/
    ++static int fts5ExprNearInitAll(
    ++  Fts5Expr *pExpr,
    ++  Fts5ExprNode *pNode
    ++){
    ++  Fts5ExprNearset *pNear = pNode->pNear;
    +   int i;
    + 
    +-  /* Check that each phrase in the nearset matches the current row.
    +-  ** Populate the pPhrase->poslist buffers at the same time. If any
    +-  ** phrase is not a match, break out of the loop early.  */
    +-  for(i=0; rc==SQLITE_OK && i<pNear->nPhrase; i++){
    ++  assert( pNode->bNomatch==0 );
    ++  for(i=0; i<pNear->nPhrase; i++){
    +     Fts5ExprPhrase *pPhrase = pNear->apPhrase[i];
    +-    if( pPhrase->nTerm>1 || pPhrase->aTerm[0].pSynonym || pNear->pColset ){
    +-      int bMatch = 0;
    +-      rc = fts5ExprPhraseIsMatch(pNode, pNear->pColset, pPhrase, &bMatch);
    +-      if( bMatch==0 ) break;
    ++    if( pPhrase->nTerm==0 ){
    ++      pNode->bEof = 1;
    ++      return SQLITE_OK;
    +     }else{
    +-      rc = sqlite3Fts5IterPoslistBuffer(
    +-          pPhrase->aTerm[0].pIter, &pPhrase->poslist
    +-      );
    ++      int j;
    ++      for(j=0; j<pPhrase->nTerm; j++){
    ++        Fts5ExprTerm *pTerm = &pPhrase->aTerm[j];
    ++        Fts5ExprTerm *p;
    ++        int bHit = 0;
    ++
    ++        for(p=pTerm; p; p=p->pSynonym){
    ++          int rc;
    ++          if( p->pIter ){
    ++            sqlite3Fts5IterClose(p->pIter);
    ++            p->pIter = 0;
    ++          }
    ++          rc = sqlite3Fts5IndexQuery(
    ++              pExpr->pIndex, p->zTerm, (int)strlen(p->zTerm),
    ++              (pTerm->bPrefix ? FTS5INDEX_QUERY_PREFIX : 0) |
    ++              (pExpr->bDesc ? FTS5INDEX_QUERY_DESC : 0),
    ++              pNear->pColset,
    ++              &p->pIter
    ++          );
    ++          assert( (rc==SQLITE_OK)==(p->pIter!=0) );
    ++          if( rc!=SQLITE_OK ) return rc;
    ++          if( 0==sqlite3Fts5IterEof(p->pIter) ){
    ++            bHit = 1;
    ++          }
    ++        }
    ++
    ++        if( bHit==0 ){
    ++          pNode->bEof = 1;
    ++          return SQLITE_OK;
    ++        }
    ++      }
    +     }
    +   }
    + 
    +-  *pRc = rc;
    +-  if( i==pNear->nPhrase && (i==1 || fts5ExprNearIsMatch(pRc, pNear)) ){
    +-    return 1;
    ++  pNode->bEof = 0;
    ++  return SQLITE_OK;
    ++}
    ++
    ++/*
    ++** If pExpr is an ASC iterator, this function returns a value with the
    ++** same sign as:
    ++**
    ++**   (iLhs - iRhs)
    ++**
    ++** Otherwise, if this is a DESC iterator, the opposite is returned:
    ++**
    ++**   (iRhs - iLhs)
    ++*/
    ++static int fts5RowidCmp(
    ++  Fts5Expr *pExpr,
    ++  i64 iLhs,
    ++  i64 iRhs
    ++){
    ++  assert( pExpr->bDesc==0 || pExpr->bDesc==1 );
    ++  if( pExpr->bDesc==0 ){
    ++    if( iLhs<iRhs ) return -1;
    ++    return (iLhs > iRhs);
    ++  }else{
    ++    if( iLhs>iRhs ) return -1;
    ++    return (iLhs < iRhs);
    +   }
    ++}
    + 
    +-  return 0;
    ++static void fts5ExprSetEof(Fts5ExprNode *pNode){
    ++  int i;
    ++  pNode->bEof = 1;
    ++  pNode->bNomatch = 0;
    ++  for(i=0; i<pNode->nChild; i++){
    ++    fts5ExprSetEof(pNode->apChild[i]);
    ++  }
    + }
    + 
    +-static int fts5ExprTokenTest(
    +-  Fts5Expr *pExpr,                /* Expression that pNear is a part of */
    +-  Fts5ExprNode *pNode             /* The "NEAR" node (FTS5_TERM) */
    +-){
    +-  /* As this "NEAR" object is actually a single phrase that consists 
    +-  ** of a single term only, grab pointers into the poslist managed by the
    +-  ** fts5_index.c iterator object. This is much faster than synthesizing 
    +-  ** a new poslist the way we have to for more complicated phrase or NEAR
    +-  ** expressions.  */
    +-  Fts5ExprNearset *pNear = pNode->pNear;
    +-  Fts5ExprPhrase *pPhrase = pNear->apPhrase[0];
    +-  Fts5IndexIter *pIter = pPhrase->aTerm[0].pIter;
    +-  Fts5Colset *pColset = pNear->pColset;
    +-  int rc;
    ++static void fts5ExprNodeZeroPoslist(Fts5ExprNode *pNode){
    ++  if( pNode->eType==FTS5_STRING || pNode->eType==FTS5_TERM ){
    ++    Fts5ExprNearset *pNear = pNode->pNear;
    ++    int i;
    ++    for(i=0; i<pNear->nPhrase; i++){
    ++      Fts5ExprPhrase *pPhrase = pNear->apPhrase[i];
    ++      pPhrase->poslist.n = 0;
    ++    }
    ++  }else{
    ++    int i;
    ++    for(i=0; i<pNode->nChild; i++){
    ++      fts5ExprNodeZeroPoslist(pNode->apChild[i]);
    ++    }
    ++  }
    ++}
    + 
    +-  assert( pNode->eType==FTS5_TERM );
    +-  assert( pNear->nPhrase==1 && pPhrase->nTerm==1 );
    +-  assert( pPhrase->aTerm[0].pSynonym==0 );
    + 
    +-  rc = sqlite3Fts5IterPoslist(pIter, pColset, 
    +-      (const u8**)&pPhrase->poslist.p, &pPhrase->poslist.n, &pNode->iRowid
    +-  );
    +-  pNode->bNomatch = (pPhrase->poslist.n==0);
    +-  return rc;
    ++
    ++/*
    ++** Compare the values currently indicated by the two nodes as follows:
    ++**
    ++**    res = (*p1) - (*p2)
    ++**
    ++** Nodes that point to values that come later in the iteration order are
    ++** considered to be larger. Nodes at EOF are the largest of all.
    ++**
    ++** This means that if the iteration order is ASC, then numerically larger
    ++** rowids are considered larger. Or if it is the default DESC, numerically
    ++** smaller rowids are larger.
    ++*/
    ++static int fts5NodeCompare(
    ++  Fts5Expr *pExpr,
    ++  Fts5ExprNode *p1, 
    ++  Fts5ExprNode *p2
    ++){
    ++  if( p2->bEof ) return -1;
    ++  if( p1->bEof ) return +1;
    ++  return fts5RowidCmp(pExpr, p1->iRowid, p2->iRowid);
    + }
    + 
    + /*
    +@@ -170585,7 +191786,7 @@ static int fts5ExprTokenTest(
    + ** otherwise. It is not considered an error code if an iterator reaches
    + ** EOF.
    + */
    +-static int fts5ExprNearNextMatch(
    ++static int fts5ExprNodeTest_STRING(
    +   Fts5Expr *pExpr,                /* Expression pPhrase belongs to */
    +   Fts5ExprNode *pNode
    + ){
    +@@ -170601,6 +191802,7 @@ static int fts5ExprNearNextMatch(
    +   assert( pNear->nPhrase>1 
    +        || pNear->apPhrase[0]->nTerm>1 
    +        || pNear->apPhrase[0]->aTerm[0].pSynonym
    ++       || pNear->apPhrase[0]->aTerm[0].bFirst
    +   );
    + 
    +   /* Initialize iLast, the "lastest" rowid any iterator points to. If the
    +@@ -170610,7 +191812,7 @@ static int fts5ExprNearNextMatch(
    +   if( pLeft->aTerm[0].pSynonym ){
    +     iLast = fts5ExprSynonymRowid(&pLeft->aTerm[0], bDesc, 0);
    +   }else{
    +-    iLast = sqlite3Fts5IterRowid(pLeft->aTerm[0].pIter);
    ++    iLast = pLeft->aTerm[0].pIter->iRowid;
    +   }
    + 
    +   do {
    +@@ -170624,13 +191826,13 @@ static int fts5ExprNearNextMatch(
    +           if( iRowid==iLast ) continue;
    +           bMatch = 0;
    +           if( fts5ExprSynonymAdvanceto(pTerm, bDesc, &iLast, &rc) ){
    ++            pNode->bNomatch = 0;
    +             pNode->bEof = 1;
    +             return rc;
    +           }
    +         }else{
    +           Fts5IndexIter *pIter = pPhrase->aTerm[j].pIter;
    +-          i64 iRowid = sqlite3Fts5IterRowid(pIter);
    +-          if( iRowid==iLast ) continue;
    ++          if( pIter->iRowid==iLast || pIter->bEof ) continue;
    +           bMatch = 0;
    +           if( fts5ExprAdvanceto(pIter, bDesc, &iLast, &rc, &pNode->bEof) ){
    +             return rc;
    +@@ -170641,119 +191843,188 @@ static int fts5ExprNearNextMatch(
    +   }while( bMatch==0 );
    + 
    +   pNode->iRowid = iLast;
    +-  pNode->bNomatch = (0==fts5ExprNearTest(&rc, pExpr, pNode));
    ++  pNode->bNomatch = ((0==fts5ExprNearTest(&rc, pExpr, pNode)) && rc==SQLITE_OK);
    ++  assert( pNode->bEof==0 || pNode->bNomatch==0 );
    + 
    +   return rc;
    + }
    + 
    + /*
    +-** Initialize all term iterators in the pNear object. If any term is found
    +-** to match no documents at all, return immediately without initializing any
    +-** further iterators.
    ++** Advance the first term iterator in the first phrase of pNear. Set output
    ++** variable *pbEof to true if it reaches EOF or if an error occurs.
    ++**
    ++** Return SQLITE_OK if successful, or an SQLite error code if an error
    ++** occurs.
    + */
    +-static int fts5ExprNearInitAll(
    +-  Fts5Expr *pExpr,
    +-  Fts5ExprNode *pNode
    ++static int fts5ExprNodeNext_STRING(
    ++  Fts5Expr *pExpr,                /* Expression pPhrase belongs to */
    ++  Fts5ExprNode *pNode,            /* FTS5_STRING or FTS5_TERM node */
    ++  int bFromValid,
    ++  i64 iFrom 
    + ){
    +-  Fts5ExprNearset *pNear = pNode->pNear;
    +-  int i, j;
    ++  Fts5ExprTerm *pTerm = &pNode->pNear->apPhrase[0]->aTerm[0];
    +   int rc = SQLITE_OK;
    + 
    +-  for(i=0; rc==SQLITE_OK && i<pNear->nPhrase; i++){
    +-    Fts5ExprPhrase *pPhrase = pNear->apPhrase[i];
    +-    for(j=0; j<pPhrase->nTerm; j++){
    +-      Fts5ExprTerm *pTerm = &pPhrase->aTerm[j];
    +-      Fts5ExprTerm *p;
    +-      int bEof = 1;
    +-
    +-      for(p=pTerm; p && rc==SQLITE_OK; p=p->pSynonym){
    +-        if( p->pIter ){
    +-          sqlite3Fts5IterClose(p->pIter);
    +-          p->pIter = 0;
    +-        }
    +-        rc = sqlite3Fts5IndexQuery(
    +-            pExpr->pIndex, p->zTerm, strlen(p->zTerm),
    +-            (pTerm->bPrefix ? FTS5INDEX_QUERY_PREFIX : 0) |
    +-            (pExpr->bDesc ? FTS5INDEX_QUERY_DESC : 0),
    +-            pNear->pColset,
    +-            &p->pIter
    +-        );
    +-        assert( rc==SQLITE_OK || p->pIter==0 );
    +-        if( p->pIter && 0==sqlite3Fts5IterEof(p->pIter) ){
    ++  pNode->bNomatch = 0;
    ++  if( pTerm->pSynonym ){
    ++    int bEof = 1;
    ++    Fts5ExprTerm *p;
    ++
    ++    /* Find the firstest rowid any synonym points to. */
    ++    i64 iRowid = fts5ExprSynonymRowid(pTerm, pExpr->bDesc, 0);
    ++
    ++    /* Advance each iterator that currently points to iRowid. Or, if iFrom
    ++    ** is valid - each iterator that points to a rowid before iFrom.  */
    ++    for(p=pTerm; p; p=p->pSynonym){
    ++      if( sqlite3Fts5IterEof(p->pIter)==0 ){
    ++        i64 ii = p->pIter->iRowid;
    ++        if( ii==iRowid 
    ++         || (bFromValid && ii!=iFrom && (ii>iFrom)==pExpr->bDesc) 
    ++        ){
    ++          if( bFromValid ){
    ++            rc = sqlite3Fts5IterNextFrom(p->pIter, iFrom);
    ++          }else{
    ++            rc = sqlite3Fts5IterNext(p->pIter);
    ++          }
    ++          if( rc!=SQLITE_OK ) break;
    ++          if( sqlite3Fts5IterEof(p->pIter)==0 ){
    ++            bEof = 0;
    ++          }
    ++        }else{
    +           bEof = 0;
    +         }
    +       }
    ++    }
    + 
    +-      if( bEof ){
    +-        pNode->bEof = 1;
    +-        return rc;
    +-      }
    ++    /* Set the EOF flag if either all synonym iterators are at EOF or an
    ++    ** error has occurred.  */
    ++    pNode->bEof = (rc || bEof);
    ++  }else{
    ++    Fts5IndexIter *pIter = pTerm->pIter;
    ++
    ++    assert( Fts5NodeIsString(pNode) );
    ++    if( bFromValid ){
    ++      rc = sqlite3Fts5IterNextFrom(pIter, iFrom);
    ++    }else{
    ++      rc = sqlite3Fts5IterNext(pIter);
    +     }
    ++
    ++    pNode->bEof = (rc || sqlite3Fts5IterEof(pIter));
    ++  }
    ++
    ++  if( pNode->bEof==0 ){
    ++    assert( rc==SQLITE_OK );
    ++    rc = fts5ExprNodeTest_STRING(pExpr, pNode);
    +   }
    + 
    +   return rc;
    + }
    + 
    +-/* fts5ExprNodeNext() calls fts5ExprNodeNextMatch(). And vice-versa. */
    +-static int fts5ExprNodeNextMatch(Fts5Expr*, Fts5ExprNode*);
    + 
    ++static int fts5ExprNodeTest_TERM(
    ++  Fts5Expr *pExpr,                /* Expression that pNear is a part of */
    ++  Fts5ExprNode *pNode             /* The "NEAR" node (FTS5_TERM) */
    ++){
    ++  /* As this "NEAR" object is actually a single phrase that consists 
    ++  ** of a single term only, grab pointers into the poslist managed by the
    ++  ** fts5_index.c iterator object. This is much faster than synthesizing 
    ++  ** a new poslist the way we have to for more complicated phrase or NEAR
    ++  ** expressions.  */
    ++  Fts5ExprPhrase *pPhrase = pNode->pNear->apPhrase[0];
    ++  Fts5IndexIter *pIter = pPhrase->aTerm[0].pIter;
    ++
    ++  assert( pNode->eType==FTS5_TERM );
    ++  assert( pNode->pNear->nPhrase==1 && pPhrase->nTerm==1 );
    ++  assert( pPhrase->aTerm[0].pSynonym==0 );
    ++
    ++  pPhrase->poslist.n = pIter->nData;
    ++  if( pExpr->pConfig->eDetail==FTS5_DETAIL_FULL ){
    ++    pPhrase->poslist.p = (u8*)pIter->pData;
    ++  }
    ++  pNode->iRowid = pIter->iRowid;
    ++  pNode->bNomatch = (pPhrase->poslist.n==0);
    ++  return SQLITE_OK;
    ++}
    + 
    + /*
    +-** If pExpr is an ASC iterator, this function returns a value with the
    +-** same sign as:
    +-**
    +-**   (iLhs - iRhs)
    +-**
    +-** Otherwise, if this is a DESC iterator, the opposite is returned:
    +-**
    +-**   (iRhs - iLhs)
    ++** xNext() method for a node of type FTS5_TERM.
    + */
    +-static int fts5RowidCmp(
    +-  Fts5Expr *pExpr,
    +-  i64 iLhs,
    +-  i64 iRhs
    ++static int fts5ExprNodeNext_TERM(
    ++  Fts5Expr *pExpr, 
    ++  Fts5ExprNode *pNode,
    ++  int bFromValid,
    ++  i64 iFrom
    + ){
    +-  assert( pExpr->bDesc==0 || pExpr->bDesc==1 );
    +-  if( pExpr->bDesc==0 ){
    +-    if( iLhs<iRhs ) return -1;
    +-    return (iLhs > iRhs);
    ++  int rc;
    ++  Fts5IndexIter *pIter = pNode->pNear->apPhrase[0]->aTerm[0].pIter;
    ++
    ++  assert( pNode->bEof==0 );
    ++  if( bFromValid ){
    ++    rc = sqlite3Fts5IterNextFrom(pIter, iFrom);
    +   }else{
    +-    if( iLhs>iRhs ) return -1;
    +-    return (iLhs < iRhs);
    ++    rc = sqlite3Fts5IterNext(pIter);
    +   }
    ++  if( rc==SQLITE_OK && sqlite3Fts5IterEof(pIter)==0 ){
    ++    rc = fts5ExprNodeTest_TERM(pExpr, pNode);
    ++  }else{
    ++    pNode->bEof = 1;
    ++    pNode->bNomatch = 0;
    ++  }
    ++  return rc;
    + }
    + 
    +-static void fts5ExprSetEof(Fts5ExprNode *pNode){
    ++static void fts5ExprNodeTest_OR(
    ++  Fts5Expr *pExpr,                /* Expression of which pNode is a part */
    ++  Fts5ExprNode *pNode             /* Expression node to test */
    ++){
    ++  Fts5ExprNode *pNext = pNode->apChild[0];
    +   int i;
    +-  pNode->bEof = 1;
    +-  for(i=0; i<pNode->nChild; i++){
    +-    fts5ExprSetEof(pNode->apChild[i]);
    +-  }
    +-}
    + 
    +-static void fts5ExprNodeZeroPoslist(Fts5ExprNode *pNode){
    +-  if( pNode->eType==FTS5_STRING || pNode->eType==FTS5_TERM ){
    +-    Fts5ExprNearset *pNear = pNode->pNear;
    +-    int i;
    +-    for(i=0; i<pNear->nPhrase; i++){
    +-      Fts5ExprPhrase *pPhrase = pNear->apPhrase[i];
    +-      pPhrase->poslist.n = 0;
    +-    }
    +-  }else{
    +-    int i;
    +-    for(i=0; i<pNode->nChild; i++){
    +-      fts5ExprNodeZeroPoslist(pNode->apChild[i]);
    ++  for(i=1; i<pNode->nChild; i++){
    ++    Fts5ExprNode *pChild = pNode->apChild[i];
    ++    int cmp = fts5NodeCompare(pExpr, pNext, pChild);
    ++    if( cmp>0 || (cmp==0 && pChild->bNomatch==0) ){
    ++      pNext = pChild;
    +     }
    +   }
    ++  pNode->iRowid = pNext->iRowid;
    ++  pNode->bEof = pNext->bEof;
    ++  pNode->bNomatch = pNext->bNomatch;
    + }
    + 
    ++static int fts5ExprNodeNext_OR(
    ++  Fts5Expr *pExpr, 
    ++  Fts5ExprNode *pNode,
    ++  int bFromValid,
    ++  i64 iFrom
    ++){
    ++  int i;
    ++  i64 iLast = pNode->iRowid;
    + 
    +-static int fts5ExprNodeNext(Fts5Expr*, Fts5ExprNode*, int, i64);
    ++  for(i=0; i<pNode->nChild; i++){
    ++    Fts5ExprNode *p1 = pNode->apChild[i];
    ++    assert( p1->bEof || fts5RowidCmp(pExpr, p1->iRowid, iLast)>=0 );
    ++    if( p1->bEof==0 ){
    ++      if( (p1->iRowid==iLast) 
    ++       || (bFromValid && fts5RowidCmp(pExpr, p1->iRowid, iFrom)<0)
    ++      ){
    ++        int rc = fts5ExprNodeNext(pExpr, p1, bFromValid, iFrom);
    ++        if( rc!=SQLITE_OK ){
    ++          pNode->bNomatch = 0;
    ++          return rc;
    ++        }
    ++      }
    ++    }
    ++  }
    ++
    ++  fts5ExprNodeTest_OR(pExpr, pNode);
    ++  return SQLITE_OK;
    ++}
    + 
    + /*
    + ** Argument pNode is an FTS5_AND node.
    + */
    +-static int fts5ExprAndNextRowid(
    ++static int fts5ExprNodeTest_AND(
    +   Fts5Expr *pExpr,                /* Expression pPhrase belongs to */
    +   Fts5ExprNode *pAnd              /* FTS5_AND node to advance */
    + ){
    +@@ -170768,14 +192039,13 @@ static int fts5ExprAndNextRowid(
    +     bMatch = 1;
    +     for(iChild=0; iChild<pAnd->nChild; iChild++){
    +       Fts5ExprNode *pChild = pAnd->apChild[iChild];
    +-      if( 0 && pChild->eType==FTS5_STRING ){
    +-        /* TODO */
    +-      }else{
    +-        int cmp = fts5RowidCmp(pExpr, iLast, pChild->iRowid);
    +-        if( cmp>0 ){
    +-          /* Advance pChild until it points to iLast or laster */
    +-          rc = fts5ExprNodeNext(pExpr, pChild, 1, iLast);
    +-          if( rc!=SQLITE_OK ) return rc;
    ++      int cmp = fts5RowidCmp(pExpr, iLast, pChild->iRowid);
    ++      if( cmp>0 ){
    ++        /* Advance pChild until it points to iLast or laster */
    ++        rc = fts5ExprNodeNext(pExpr, pChild, 1, iLast);
    ++        if( rc!=SQLITE_OK ){
    ++          pAnd->bNomatch = 0;
    ++          return rc;
    +         }
    +       }
    + 
    +@@ -170806,126 +192076,71 @@ static int fts5ExprAndNextRowid(
    +   return SQLITE_OK;
    + }
    + 
    +-
    +-/*
    +-** Compare the values currently indicated by the two nodes as follows:
    +-**
    +-**    res = (*p1) - (*p2)
    +-**
    +-** Nodes that point to values that come later in the iteration order are
    +-** considered to be larger. Nodes at EOF are the largest of all.
    +-**
    +-** This means that if the iteration order is ASC, then numerically larger
    +-** rowids are considered larger. Or if it is the default DESC, numerically
    +-** smaller rowids are larger.
    +-*/
    +-static int fts5NodeCompare(
    +-  Fts5Expr *pExpr,
    +-  Fts5ExprNode *p1, 
    +-  Fts5ExprNode *p2
    +-){
    +-  if( p2->bEof ) return -1;
    +-  if( p1->bEof ) return +1;
    +-  return fts5RowidCmp(pExpr, p1->iRowid, p2->iRowid);
    +-}
    +-
    +-/*
    +-** Advance node iterator pNode, part of expression pExpr. If argument
    +-** bFromValid is zero, then pNode is advanced exactly once. Or, if argument
    +-** bFromValid is non-zero, then pNode is advanced until it is at or past
    +-** rowid value iFrom. Whether "past" means "less than" or "greater than"
    +-** depends on whether this is an ASC or DESC iterator.
    +-*/
    +-static int fts5ExprNodeNext(
    ++static int fts5ExprNodeNext_AND(
    +   Fts5Expr *pExpr, 
    +   Fts5ExprNode *pNode,
    +   int bFromValid,
    +   i64 iFrom
    + ){
    +-  int rc = SQLITE_OK;
    +-
    +-  if( pNode->bEof==0 ){
    +-    switch( pNode->eType ){
    +-      case FTS5_STRING: {
    +-        rc = fts5ExprNearAdvanceFirst(pExpr, pNode, bFromValid, iFrom);
    +-        break;
    +-      };
    +-
    +-      case FTS5_TERM: {
    +-        Fts5IndexIter *pIter = pNode->pNear->apPhrase[0]->aTerm[0].pIter;
    +-        if( bFromValid ){
    +-          rc = sqlite3Fts5IterNextFrom(pIter, iFrom);
    +-        }else{
    +-          rc = sqlite3Fts5IterNext(pIter);
    +-        }
    +-        if( rc==SQLITE_OK && sqlite3Fts5IterEof(pIter)==0 ){
    +-          assert( rc==SQLITE_OK );
    +-          rc = fts5ExprTokenTest(pExpr, pNode);
    +-        }else{
    +-          pNode->bEof = 1;
    +-        }
    +-        return rc;
    +-      };
    +-
    +-      case FTS5_AND: {
    +-        Fts5ExprNode *pLeft = pNode->apChild[0];
    +-        rc = fts5ExprNodeNext(pExpr, pLeft, bFromValid, iFrom);
    +-        break;
    +-      }
    +-
    +-      case FTS5_OR: {
    +-        int i;
    +-        i64 iLast = pNode->iRowid;
    +-
    +-        for(i=0; rc==SQLITE_OK && i<pNode->nChild; i++){
    +-          Fts5ExprNode *p1 = pNode->apChild[i];
    +-          assert( p1->bEof || fts5RowidCmp(pExpr, p1->iRowid, iLast)>=0 );
    +-          if( p1->bEof==0 ){
    +-            if( (p1->iRowid==iLast) 
    +-             || (bFromValid && fts5RowidCmp(pExpr, p1->iRowid, iFrom)<0)
    +-            ){
    +-              rc = fts5ExprNodeNext(pExpr, p1, bFromValid, iFrom);
    +-            }
    +-          }
    +-        }
    +-
    +-        break;
    +-      }
    ++  int rc = fts5ExprNodeNext(pExpr, pNode->apChild[0], bFromValid, iFrom);
    ++  if( rc==SQLITE_OK ){
    ++    rc = fts5ExprNodeTest_AND(pExpr, pNode);
    ++  }else{
    ++    pNode->bNomatch = 0;
    ++  }
    ++  return rc;
    ++}
    + 
    +-      default: assert( pNode->eType==FTS5_NOT ); {
    +-        assert( pNode->nChild==2 );
    +-        rc = fts5ExprNodeNext(pExpr, pNode->apChild[0], bFromValid, iFrom);
    +-        break;
    +-      }
    +-    }
    ++static int fts5ExprNodeTest_NOT(
    ++  Fts5Expr *pExpr,                /* Expression pPhrase belongs to */
    ++  Fts5ExprNode *pNode             /* FTS5_NOT node to advance */
    ++){
    ++  int rc = SQLITE_OK;
    ++  Fts5ExprNode *p1 = pNode->apChild[0];
    ++  Fts5ExprNode *p2 = pNode->apChild[1];
    ++  assert( pNode->nChild==2 );
    + 
    +-    if( rc==SQLITE_OK ){
    +-      rc = fts5ExprNodeNextMatch(pExpr, pNode);
    ++  while( rc==SQLITE_OK && p1->bEof==0 ){
    ++    int cmp = fts5NodeCompare(pExpr, p1, p2);
    ++    if( cmp>0 ){
    ++      rc = fts5ExprNodeNext(pExpr, p2, 1, p1->iRowid);
    ++      cmp = fts5NodeCompare(pExpr, p1, p2);
    +     }
    ++    assert( rc!=SQLITE_OK || cmp<=0 );
    ++    if( cmp || p2->bNomatch ) break;
    ++    rc = fts5ExprNodeNext(pExpr, p1, 0, 0);
    ++  }
    ++  pNode->bEof = p1->bEof;
    ++  pNode->bNomatch = p1->bNomatch;
    ++  pNode->iRowid = p1->iRowid;
    ++  if( p1->bEof ){
    ++    fts5ExprNodeZeroPoslist(p2);
    +   }
    +-
    +-  /* Assert that if bFromValid was true, either:
    +-  **
    +-  **   a) an error occurred, or
    +-  **   b) the node is now at EOF, or
    +-  **   c) the node is now at or past rowid iFrom.
    +-  */
    +-  assert( bFromValid==0 
    +-      || rc!=SQLITE_OK                                                  /* a */
    +-      || pNode->bEof                                                    /* b */
    +-      || pNode->iRowid==iFrom || pExpr->bDesc==(pNode->iRowid<iFrom)    /* c */
    +-  );
    +-
    +   return rc;
    + }
    + 
    ++static int fts5ExprNodeNext_NOT(
    ++  Fts5Expr *pExpr, 
    ++  Fts5ExprNode *pNode,
    ++  int bFromValid,
    ++  i64 iFrom
    ++){
    ++  int rc = fts5ExprNodeNext(pExpr, pNode->apChild[0], bFromValid, iFrom);
    ++  if( rc==SQLITE_OK ){
    ++    rc = fts5ExprNodeTest_NOT(pExpr, pNode);
    ++  }
    ++  if( rc!=SQLITE_OK ){
    ++    pNode->bNomatch = 0;
    ++  }
    ++  return rc;
    ++}
    + 
    + /*
    + ** If pNode currently points to a match, this function returns SQLITE_OK
    + ** without modifying it. Otherwise, pNode is advanced until it does point
    + ** to a match or EOF is reached.
    + */
    +-static int fts5ExprNodeNextMatch(
    ++static int fts5ExprNodeTest(
    +   Fts5Expr *pExpr,                /* Expression of which pNode is a part */
    +   Fts5ExprNode *pNode             /* Expression node to test */
    + ){
    +@@ -170934,55 +192149,27 @@ static int fts5ExprNodeNextMatch(
    +     switch( pNode->eType ){
    + 
    +       case FTS5_STRING: {
    +-        /* Advance the iterators until they all point to the same rowid */
    +-        rc = fts5ExprNearNextMatch(pExpr, pNode);
    ++        rc = fts5ExprNodeTest_STRING(pExpr, pNode);
    +         break;
    +       }
    + 
    +       case FTS5_TERM: {
    +-        rc = fts5ExprTokenTest(pExpr, pNode);
    ++        rc = fts5ExprNodeTest_TERM(pExpr, pNode);
    +         break;
    +       }
    + 
    +       case FTS5_AND: {
    +-        rc = fts5ExprAndNextRowid(pExpr, pNode);
    ++        rc = fts5ExprNodeTest_AND(pExpr, pNode);
    +         break;
    +       }
    + 
    +       case FTS5_OR: {
    +-        Fts5ExprNode *pNext = pNode->apChild[0];
    +-        int i;
    +-
    +-        for(i=1; i<pNode->nChild; i++){
    +-          Fts5ExprNode *pChild = pNode->apChild[i];
    +-          int cmp = fts5NodeCompare(pExpr, pNext, pChild);
    +-          if( cmp>0 || (cmp==0 && pChild->bNomatch==0) ){
    +-            pNext = pChild;
    +-          }
    +-        }
    +-        pNode->iRowid = pNext->iRowid;
    +-        pNode->bEof = pNext->bEof;
    +-        pNode->bNomatch = pNext->bNomatch;
    ++        fts5ExprNodeTest_OR(pExpr, pNode);
    +         break;
    +       }
    + 
    +       default: assert( pNode->eType==FTS5_NOT ); {
    +-        Fts5ExprNode *p1 = pNode->apChild[0];
    +-        Fts5ExprNode *p2 = pNode->apChild[1];
    +-        assert( pNode->nChild==2 );
    +-
    +-        while( rc==SQLITE_OK && p1->bEof==0 ){
    +-          int cmp = fts5NodeCompare(pExpr, p1, p2);
    +-          if( cmp>0 ){
    +-            rc = fts5ExprNodeNext(pExpr, p2, 1, p1->iRowid);
    +-            cmp = fts5NodeCompare(pExpr, p1, p2);
    +-          }
    +-          assert( rc!=SQLITE_OK || cmp<=0 );
    +-          if( cmp || p2->bNomatch ) break;
    +-          rc = fts5ExprNodeNext(pExpr, p1, 0, 0);
    +-        }
    +-        pNode->bEof = p1->bEof;
    +-        pNode->iRowid = p1->iRowid;
    ++        rc = fts5ExprNodeTest_NOT(pExpr, pNode);
    +         break;
    +       }
    +     }
    +@@ -171001,20 +192188,42 @@ static int fts5ExprNodeNextMatch(
    + static int fts5ExprNodeFirst(Fts5Expr *pExpr, Fts5ExprNode *pNode){
    +   int rc = SQLITE_OK;
    +   pNode->bEof = 0;
    ++  pNode->bNomatch = 0;
    + 
    +   if( Fts5NodeIsString(pNode) ){
    +     /* Initialize all term iterators in the NEAR object. */
    +     rc = fts5ExprNearInitAll(pExpr, pNode);
    ++  }else if( pNode->xNext==0 ){
    ++    pNode->bEof = 1;
    +   }else{
    +     int i;
    ++    int nEof = 0;
    +     for(i=0; i<pNode->nChild && rc==SQLITE_OK; i++){
    ++      Fts5ExprNode *pChild = pNode->apChild[i];
    +       rc = fts5ExprNodeFirst(pExpr, pNode->apChild[i]);
    ++      assert( pChild->bEof==0 || pChild->bEof==1 );
    ++      nEof += pChild->bEof;
    +     }
    +     pNode->iRowid = pNode->apChild[0]->iRowid;
    ++
    ++    switch( pNode->eType ){
    ++      case FTS5_AND:
    ++        if( nEof>0 ) fts5ExprSetEof(pNode);
    ++        break;
    ++
    ++      case FTS5_OR:
    ++        if( pNode->nChild==nEof ) fts5ExprSetEof(pNode);
    ++        break;
    ++
    ++      default:
    ++        assert( pNode->eType==FTS5_NOT );
    ++        pNode->bEof = pNode->apChild[0]->bEof;
    ++        break;
    ++    }
    +   }
    + 
    +   if( rc==SQLITE_OK ){
    +-    rc = fts5ExprNodeNextMatch(pExpr, pNode);
    ++    rc = fts5ExprNodeTest(pExpr, pNode);
    +   }
    +   return rc;
    + }
    +@@ -171037,22 +192246,25 @@ static int fts5ExprNodeFirst(Fts5Expr *pExpr, Fts5ExprNode *pNode){
    + */
    + static int sqlite3Fts5ExprFirst(Fts5Expr *p, Fts5Index *pIdx, i64 iFirst, int bDesc){
    +   Fts5ExprNode *pRoot = p->pRoot;
    +-  int rc = SQLITE_OK;
    +-  if( pRoot ){
    +-    p->pIndex = pIdx;
    +-    p->bDesc = bDesc;
    +-    rc = fts5ExprNodeFirst(p, pRoot);
    ++  int rc;                         /* Return code */
    + 
    +-    /* If not at EOF but the current rowid occurs earlier than iFirst in
    +-    ** the iteration order, move to document iFirst or later. */
    +-    if( pRoot->bEof==0 && fts5RowidCmp(p, pRoot->iRowid, iFirst)<0 ){
    +-      rc = fts5ExprNodeNext(p, pRoot, 1, iFirst);
    +-    }
    ++  p->pIndex = pIdx;
    ++  p->bDesc = bDesc;
    ++  rc = fts5ExprNodeFirst(p, pRoot);
    + 
    +-    /* If the iterator is not at a real match, skip forward until it is. */
    +-    while( pRoot->bNomatch && rc==SQLITE_OK && pRoot->bEof==0 ){
    +-      rc = fts5ExprNodeNext(p, pRoot, 0, 0);
    +-    }
    ++  /* If not at EOF but the current rowid occurs earlier than iFirst in
    ++  ** the iteration order, move to document iFirst or later. */
    ++  if( rc==SQLITE_OK 
    ++   && 0==pRoot->bEof 
    ++   && fts5RowidCmp(p, pRoot->iRowid, iFirst)<0 
    ++  ){
    ++    rc = fts5ExprNodeNext(p, pRoot, 1, iFirst);
    ++  }
    ++
    ++  /* If the iterator is not at a real match, skip forward until it is. */
    ++  while( pRoot->bNomatch ){
    ++    assert( pRoot->bEof==0 && rc==SQLITE_OK );
    ++    rc = fts5ExprNodeNext(p, pRoot, 0, 0);
    +   }
    +   return rc;
    + }
    +@@ -171066,9 +192278,11 @@ static int sqlite3Fts5ExprFirst(Fts5Expr *p, Fts5Index *pIdx, i64 iFirst, int bD
    + static int sqlite3Fts5ExprNext(Fts5Expr *p, i64 iLast){
    +   int rc;
    +   Fts5ExprNode *pRoot = p->pRoot;
    ++  assert( pRoot->bEof==0 && pRoot->bNomatch==0 );
    +   do {
    +     rc = fts5ExprNodeNext(p, pRoot, 0, 0);
    +-  }while( pRoot->bNomatch && pRoot->bEof==0 && rc==SQLITE_OK );
    ++    assert( pRoot->bNomatch==0 || (rc==SQLITE_OK && pRoot->bEof==0) );
    ++  }while( pRoot->bNomatch );
    +   if( fts5RowidCmp(p, pRoot->iRowid, iLast)>0 ){
    +     pRoot->bEof = 1;
    +   }
    +@@ -171076,7 +192290,7 @@ static int sqlite3Fts5ExprNext(Fts5Expr *p, i64 iLast){
    + }
    + 
    + static int sqlite3Fts5ExprEof(Fts5Expr *p){
    +-  return (p->pRoot==0 || p->pRoot->bEof);
    ++  return p->pRoot->bEof;
    + }
    + 
    + static i64 sqlite3Fts5ExprRowid(Fts5Expr *p){
    +@@ -171101,10 +192315,10 @@ static void fts5ExprPhraseFree(Fts5ExprPhrase *pPhrase){
    +       Fts5ExprTerm *pTerm = &pPhrase->aTerm[i];
    +       sqlite3_free(pTerm->zTerm);
    +       sqlite3Fts5IterClose(pTerm->pIter);
    +-
    +       for(pSyn=pTerm->pSynonym; pSyn; pSyn=pNext){
    +         pNext = pSyn->pSynonym;
    +         sqlite3Fts5IterClose(pSyn->pIter);
    ++        fts5BufferFree((Fts5Buffer*)&pSyn[1]);
    +         sqlite3_free(pSyn);
    +       }
    +     }
    +@@ -171113,6 +192327,16 @@ static void fts5ExprPhraseFree(Fts5ExprPhrase *pPhrase){
    +   }
    + }
    + 
    ++/*
    ++** Set the "bFirst" flag on the first token of the phrase passed as the
    ++** only argument.
    ++*/
    ++static void sqlite3Fts5ParseSetCaret(Fts5ExprPhrase *pPhrase){
    ++  if( pPhrase && pPhrase->nTerm ){
    ++    pPhrase->aTerm[0].bFirst = 1;
    ++  }
    ++}
    ++
    + /*
    + ** If argument pNear is NULL, then a new Fts5ExprNearset object is allocated
    + ** and populated with pPhrase. Or, if pNear is not NULL, phrase pPhrase is
    +@@ -171159,6 +192383,21 @@ static Fts5ExprNearset *sqlite3Fts5ParseNearset(
    +     sqlite3Fts5ParseNearsetFree(pNear);
    +     sqlite3Fts5ParsePhraseFree(pPhrase);
    +   }else{
    ++    if( pRet->nPhrase>0 ){
    ++      Fts5ExprPhrase *pLast = pRet->apPhrase[pRet->nPhrase-1];
    ++      assert( pLast==pParse->apPhrase[pParse->nPhrase-2] );
    ++      if( pPhrase->nTerm==0 ){
    ++        fts5ExprPhraseFree(pPhrase);
    ++        pRet->nPhrase--;
    ++        pParse->nPhrase--;
    ++        pPhrase = pLast;
    ++      }else if( pLast->nTerm==0 ){
    ++        fts5ExprPhraseFree(pLast);
    ++        pParse->apPhrase[pParse->nPhrase-2] = pPhrase;
    ++        pParse->nPhrase--;
    ++        pRet->nPhrase--;
    ++      }
    ++    }
    +     pRet->apPhrase[pRet->nPhrase++] = pPhrase;
    +   }
    +   return pRet;
    +@@ -171186,19 +192425,21 @@ static int fts5ParseTokenize(
    +   TokenCtx *pCtx = (TokenCtx*)pContext;
    +   Fts5ExprPhrase *pPhrase = pCtx->pPhrase;
    + 
    ++  UNUSED_PARAM2(iUnused1, iUnused2);
    ++
    +   /* If an error has already occurred, this is a no-op */
    +   if( pCtx->rc!=SQLITE_OK ) return pCtx->rc;
    ++  if( nToken>FTS5_MAX_TOKEN_SIZE ) nToken = FTS5_MAX_TOKEN_SIZE;
    + 
    +-  assert( pPhrase==0 || pPhrase->nTerm>0 );
    +-  if( pPhrase && (tflags & FTS5_TOKEN_COLOCATED) ){
    ++  if( pPhrase && pPhrase->nTerm>0 && (tflags & FTS5_TOKEN_COLOCATED) ){
    +     Fts5ExprTerm *pSyn;
    +-    int nByte = sizeof(Fts5ExprTerm) + nToken+1;
    ++    int nByte = sizeof(Fts5ExprTerm) + sizeof(Fts5Buffer) + nToken+1;
    +     pSyn = (Fts5ExprTerm*)sqlite3_malloc(nByte);
    +     if( pSyn==0 ){
    +       rc = SQLITE_NOMEM;
    +     }else{
    +       memset(pSyn, 0, nByte);
    +-      pSyn->zTerm = (char*)&pSyn[1];
    ++      pSyn->zTerm = ((char*)pSyn) + sizeof(Fts5ExprTerm) + sizeof(Fts5Buffer);
    +       memcpy(pSyn->zTerm, pToken, nToken);
    +       pSyn->pSynonym = pPhrase->aTerm[pPhrase->nTerm-1].pSynonym;
    +       pPhrase->aTerm[pPhrase->nTerm-1].pSynonym = pSyn;
    +@@ -171280,10 +192521,10 @@ static Fts5ExprPhrase *sqlite3Fts5ParseTerm(
    + 
    +   rc = fts5ParseStringFromToken(pToken, &z);
    +   if( rc==SQLITE_OK ){
    +-    int flags = FTS5_TOKENIZE_QUERY | (bPrefix ? FTS5_TOKENIZE_QUERY : 0);
    ++    int flags = FTS5_TOKENIZE_QUERY | (bPrefix ? FTS5_TOKENIZE_PREFIX : 0);
    +     int n;
    +     sqlite3Fts5Dequote(z);
    +-    n = strlen(z);
    ++    n = (int)strlen(z);
    +     rc = sqlite3Fts5Tokenize(pConfig, flags, z, n, &sCtx, fts5ParseTokenize);
    +   }
    +   sqlite3_free(z);
    +@@ -171291,7 +192532,7 @@ static Fts5ExprPhrase *sqlite3Fts5ParseTerm(
    +     pParse->rc = rc;
    +     fts5ExprPhraseFree(sCtx.pPhrase);
    +     sCtx.pPhrase = 0;
    +-  }else if( sCtx.pPhrase ){
    ++  }else{
    + 
    +     if( pAppend==0 ){
    +       if( (pParse->nPhrase % 8)==0 ){
    +@@ -171308,9 +192549,14 @@ static Fts5ExprPhrase *sqlite3Fts5ParseTerm(
    +       pParse->nPhrase++;
    +     }
    + 
    ++    if( sCtx.pPhrase==0 ){
    ++      /* This happens when parsing a token or quoted phrase that contains
    ++      ** no token characters at all. (e.g ... MATCH '""'). */
    ++      sCtx.pPhrase = sqlite3Fts5MallocZero(&pParse->rc, sizeof(Fts5ExprPhrase));
    ++    }else if( sCtx.pPhrase->nTerm ){
    ++      sCtx.pPhrase->aTerm[sCtx.pPhrase->nTerm-1].bPrefix = bPrefix;
    ++    }
    +     pParse->apPhrase[pParse->nPhrase-1] = sCtx.pPhrase;
    +-    assert( sCtx.pPhrase->nTerm>0 );
    +-    sCtx.pPhrase->aTerm[sCtx.pPhrase->nTerm-1].bPrefix = bPrefix;
    +   }
    + 
    +   return sCtx.pPhrase;
    +@@ -171321,22 +192567,16 @@ static Fts5ExprPhrase *sqlite3Fts5ParseTerm(
    + ** expression passed as the second argument.
    + */
    + static int sqlite3Fts5ExprClonePhrase(
    +-  Fts5Config *pConfig,
    +   Fts5Expr *pExpr, 
    +   int iPhrase, 
    +   Fts5Expr **ppNew
    + ){
    +   int rc = SQLITE_OK;             /* Return code */
    +   Fts5ExprPhrase *pOrig;          /* The phrase extracted from pExpr */
    +-  int i;                          /* Used to iterate through phrase terms */
    +-
    +   Fts5Expr *pNew = 0;             /* Expression to return via *ppNew */
    +-
    +   TokenCtx sCtx = {0,0};          /* Context object for fts5ParseTokenize */
    + 
    +-
    +   pOrig = pExpr->apExprPhrase[iPhrase];
    +-
    +   pNew = (Fts5Expr*)sqlite3Fts5MallocZero(&rc, sizeof(Fts5Expr));
    +   if( rc==SQLITE_OK ){
    +     pNew->apExprPhrase = (Fts5ExprPhrase**)sqlite3Fts5MallocZero(&rc, 
    +@@ -171350,33 +192590,59 @@ static int sqlite3Fts5ExprClonePhrase(
    +     pNew->pRoot->pNear = (Fts5ExprNearset*)sqlite3Fts5MallocZero(&rc, 
    +         sizeof(Fts5ExprNearset) + sizeof(Fts5ExprPhrase*));
    +   }
    +-
    +-  for(i=0; rc==SQLITE_OK && i<pOrig->nTerm; i++){
    +-    int tflags = 0;
    +-    Fts5ExprTerm *p;
    +-    for(p=&pOrig->aTerm[i]; p && rc==SQLITE_OK; p=p->pSynonym){
    +-      const char *zTerm = p->zTerm;
    +-      rc = fts5ParseTokenize((void*)&sCtx, tflags, zTerm, strlen(zTerm), 0, 0);
    +-      tflags = FTS5_TOKEN_COLOCATED;
    ++  if( rc==SQLITE_OK ){
    ++    Fts5Colset *pColsetOrig = pOrig->pNode->pNear->pColset;
    ++    if( pColsetOrig ){
    ++      int nByte = sizeof(Fts5Colset) + (pColsetOrig->nCol-1) * sizeof(int);
    ++      Fts5Colset *pColset = (Fts5Colset*)sqlite3Fts5MallocZero(&rc, nByte);
    ++      if( pColset ){ 
    ++        memcpy(pColset, pColsetOrig, nByte);
    ++      }
    ++      pNew->pRoot->pNear->pColset = pColset;
    +     }
    +-    if( rc==SQLITE_OK ){
    +-      sCtx.pPhrase->aTerm[i].bPrefix = pOrig->aTerm[i].bPrefix;
    ++  }
    ++
    ++  if( pOrig->nTerm ){
    ++    int i;                          /* Used to iterate through phrase terms */
    ++    for(i=0; rc==SQLITE_OK && i<pOrig->nTerm; i++){
    ++      int tflags = 0;
    ++      Fts5ExprTerm *p;
    ++      for(p=&pOrig->aTerm[i]; p && rc==SQLITE_OK; p=p->pSynonym){
    ++        const char *zTerm = p->zTerm;
    ++        rc = fts5ParseTokenize((void*)&sCtx, tflags, zTerm, (int)strlen(zTerm),
    ++            0, 0);
    ++        tflags = FTS5_TOKEN_COLOCATED;
    ++      }
    ++      if( rc==SQLITE_OK ){
    ++        sCtx.pPhrase->aTerm[i].bPrefix = pOrig->aTerm[i].bPrefix;
    ++        sCtx.pPhrase->aTerm[i].bFirst = pOrig->aTerm[i].bFirst;
    ++      }
    +     }
    ++  }else{
    ++    /* This happens when parsing a token or quoted phrase that contains
    ++    ** no token characters at all. (e.g ... MATCH '""'). */
    ++    sCtx.pPhrase = sqlite3Fts5MallocZero(&rc, sizeof(Fts5ExprPhrase));
    +   }
    + 
    +   if( rc==SQLITE_OK ){
    +     /* All the allocations succeeded. Put the expression object together. */
    +     pNew->pIndex = pExpr->pIndex;
    ++    pNew->pConfig = pExpr->pConfig;
    +     pNew->nPhrase = 1;
    +     pNew->apExprPhrase[0] = sCtx.pPhrase;
    +     pNew->pRoot->pNear->apPhrase[0] = sCtx.pPhrase;
    +     pNew->pRoot->pNear->nPhrase = 1;
    +     sCtx.pPhrase->pNode = pNew->pRoot;
    + 
    +-    if( pOrig->nTerm==1 && pOrig->aTerm[0].pSynonym==0 ){
    ++    if( pOrig->nTerm==1 
    ++     && pOrig->aTerm[0].pSynonym==0 
    ++     && pOrig->aTerm[0].bFirst==0 
    ++    ){
    +       pNew->pRoot->eType = FTS5_TERM;
    ++      pNew->pRoot->xNext = fts5ExprNodeNext_TERM;
    +     }else{
    +       pNew->pRoot->eType = FTS5_STRING;
    ++      pNew->pRoot->xNext = fts5ExprNodeNext_STRING;
    +     }
    +   }else{
    +     sqlite3Fts5ExprFree(pNew);
    +@@ -171407,23 +192673,25 @@ static void sqlite3Fts5ParseSetDistance(
    +   Fts5ExprNearset *pNear,
    +   Fts5Token *p
    + ){
    +-  int nNear = 0;
    +-  int i;
    +-  if( p->n ){
    +-    for(i=0; i<p->n; i++){
    +-      char c = (char)p->p[i];
    +-      if( c<'0' || c>'9' ){
    +-        sqlite3Fts5ParseError(
    +-            pParse, "expected integer, got \"%.*s\"", p->n, p->p
    +-        );
    +-        return;
    ++  if( pNear ){
    ++    int nNear = 0;
    ++    int i;
    ++    if( p->n ){
    ++      for(i=0; i<p->n; i++){
    ++        char c = (char)p->p[i];
    ++        if( c<'0' || c>'9' ){
    ++          sqlite3Fts5ParseError(
    ++              pParse, "expected integer, got \"%.*s\"", p->n, p->p
    ++              );
    ++          return;
    ++        }
    ++        nNear = nNear * 10 + (p->p[i] - '0');
    +       }
    +-      nNear = nNear * 10 + (p->p[i] - '0');
    ++    }else{
    ++      nNear = FTS5_DEFAULT_NEARDIST;
    +     }
    +-  }else{
    +-    nNear = FTS5_DEFAULT_NEARDIST;
    ++    pNear->nNear = nNear;
    +   }
    +-  pNear->nNear = nNear;
    + }
    + 
    + /*
    +@@ -171471,6 +192739,34 @@ static Fts5Colset *fts5ParseColset(
    +   return pNew;
    + }
    + 
    ++/*
    ++** Allocate and return an Fts5Colset object specifying the inverse of
    ++** the colset passed as the second argument. Free the colset passed
    ++** as the second argument before returning.
    ++*/
    ++static Fts5Colset *sqlite3Fts5ParseColsetInvert(Fts5Parse *pParse, Fts5Colset *p){
    ++  Fts5Colset *pRet;
    ++  int nCol = pParse->pConfig->nCol;
    ++
    ++  pRet = (Fts5Colset*)sqlite3Fts5MallocZero(&pParse->rc, 
    ++      sizeof(Fts5Colset) + sizeof(int)*nCol
    ++  );
    ++  if( pRet ){
    ++    int i;
    ++    int iOld = 0;
    ++    for(i=0; i<nCol; i++){
    ++      if( iOld>=p->nCol || p->aiCol[iOld]!=i ){
    ++        pRet->aiCol[pRet->nCol++] = i;
    ++      }else{
    ++        iOld++;
    ++      }
    ++    }
    ++  }
    ++
    ++  sqlite3_free(p);
    ++  return pRet;
    ++}
    ++
    + static Fts5Colset *sqlite3Fts5ParseColset(
    +   Fts5Parse *pParse,              /* Store SQLITE_NOMEM here if required */
    +   Fts5Colset *pColset,            /* Existing colset object */
    +@@ -171503,15 +192799,142 @@ static Fts5Colset *sqlite3Fts5ParseColset(
    +   return pRet;
    + }
    + 
    ++/*
    ++** If argument pOrig is NULL, or if (*pRc) is set to anything other than
    ++** SQLITE_OK when this function is called, NULL is returned. 
    ++**
    ++** Otherwise, a copy of (*pOrig) is made into memory obtained from
    ++** sqlite3Fts5MallocZero() and a pointer to it returned. If the allocation
    ++** fails, (*pRc) is set to SQLITE_NOMEM and NULL is returned.
    ++*/
    ++static Fts5Colset *fts5CloneColset(int *pRc, Fts5Colset *pOrig){
    ++  Fts5Colset *pRet;
    ++  if( pOrig ){
    ++    int nByte = sizeof(Fts5Colset) + (pOrig->nCol-1) * sizeof(int);
    ++    pRet = (Fts5Colset*)sqlite3Fts5MallocZero(pRc, nByte);
    ++    if( pRet ){ 
    ++      memcpy(pRet, pOrig, nByte);
    ++    }
    ++  }else{
    ++    pRet = 0;
    ++  }
    ++  return pRet;
    ++}
    ++
    ++/*
    ++** Remove from colset pColset any columns that are not also in colset pMerge.
    ++*/
    ++static void fts5MergeColset(Fts5Colset *pColset, Fts5Colset *pMerge){
    ++  int iIn = 0;          /* Next input in pColset */
    ++  int iMerge = 0;       /* Next input in pMerge */
    ++  int iOut = 0;         /* Next output slot in pColset */
    ++
    ++  while( iIn<pColset->nCol && iMerge<pMerge->nCol ){
    ++    int iDiff = pColset->aiCol[iIn] - pMerge->aiCol[iMerge];
    ++    if( iDiff==0 ){
    ++      pColset->aiCol[iOut++] = pMerge->aiCol[iMerge];
    ++      iMerge++;
    ++      iIn++;
    ++    }else if( iDiff>0 ){
    ++      iMerge++;
    ++    }else{
    ++      iIn++;
    ++    }
    ++  }
    ++  pColset->nCol = iOut;
    ++}
    ++
    ++/*
    ++** Recursively apply colset pColset to expression node pNode and all of
    ++** its decendents. If (*ppFree) is not NULL, it contains a spare copy
    ++** of pColset. This function may use the spare copy and set (*ppFree) to
    ++** zero, or it may create copies of pColset using fts5CloneColset().
    ++*/
    ++static void fts5ParseSetColset(
    ++  Fts5Parse *pParse, 
    ++  Fts5ExprNode *pNode, 
    ++  Fts5Colset *pColset,
    ++  Fts5Colset **ppFree
    ++){
    ++  if( pParse->rc==SQLITE_OK ){
    ++    assert( pNode->eType==FTS5_TERM || pNode->eType==FTS5_STRING 
    ++         || pNode->eType==FTS5_AND  || pNode->eType==FTS5_OR
    ++         || pNode->eType==FTS5_NOT  || pNode->eType==FTS5_EOF
    ++    );
    ++    if( pNode->eType==FTS5_STRING || pNode->eType==FTS5_TERM ){
    ++      Fts5ExprNearset *pNear = pNode->pNear;
    ++      if( pNear->pColset ){
    ++        fts5MergeColset(pNear->pColset, pColset);
    ++        if( pNear->pColset->nCol==0 ){
    ++          pNode->eType = FTS5_EOF;
    ++          pNode->xNext = 0;
    ++        }
    ++      }else if( *ppFree ){
    ++        pNear->pColset = pColset;
    ++        *ppFree = 0;
    ++      }else{
    ++        pNear->pColset = fts5CloneColset(&pParse->rc, pColset);
    ++      }
    ++    }else{
    ++      int i;
    ++      assert( pNode->eType!=FTS5_EOF || pNode->nChild==0 );
    ++      for(i=0; i<pNode->nChild; i++){
    ++        fts5ParseSetColset(pParse, pNode->apChild[i], pColset, ppFree);
    ++      }
    ++    }
    ++  }
    ++}
    ++
    ++/*
    ++** Apply colset pColset to expression node pExpr and all of its descendents.
    ++*/
    + static void sqlite3Fts5ParseSetColset(
    +   Fts5Parse *pParse, 
    +-  Fts5ExprNearset *pNear, 
    ++  Fts5ExprNode *pExpr, 
    +   Fts5Colset *pColset 
    + ){
    +-  if( pNear ){
    +-    pNear->pColset = pColset;
    ++  Fts5Colset *pFree = pColset;
    ++  if( pParse->pConfig->eDetail==FTS5_DETAIL_NONE ){
    ++    pParse->rc = SQLITE_ERROR;
    ++    pParse->zErr = sqlite3_mprintf(
    ++      "fts5: column queries are not supported (detail=none)"
    ++    );
    +   }else{
    +-    sqlite3_free(pColset);
    ++    fts5ParseSetColset(pParse, pExpr, pColset, &pFree);
    ++  }
    ++  sqlite3_free(pFree);
    ++}
    ++
    ++static void fts5ExprAssignXNext(Fts5ExprNode *pNode){
    ++  switch( pNode->eType ){
    ++    case FTS5_STRING: {
    ++      Fts5ExprNearset *pNear = pNode->pNear;
    ++      if( pNear->nPhrase==1 && pNear->apPhrase[0]->nTerm==1 
    ++       && pNear->apPhrase[0]->aTerm[0].pSynonym==0
    ++       && pNear->apPhrase[0]->aTerm[0].bFirst==0
    ++      ){
    ++        pNode->eType = FTS5_TERM;
    ++        pNode->xNext = fts5ExprNodeNext_TERM;
    ++      }else{
    ++        pNode->xNext = fts5ExprNodeNext_STRING;
    ++      }
    ++      break;
    ++    };
    ++
    ++    case FTS5_OR: {
    ++      pNode->xNext = fts5ExprNodeNext_OR;
    ++      break;
    ++    };
    ++
    ++    case FTS5_AND: {
    ++      pNode->xNext = fts5ExprNodeNext_AND;
    ++      break;
    ++    };
    ++
    ++    default: assert( pNode->eType==FTS5_NOT ); {
    ++      pNode->xNext = fts5ExprNodeNext_NOT;
    ++      break;
    ++    };
    +   }
    + }
    + 
    +@@ -171564,16 +192987,33 @@ static Fts5ExprNode *sqlite3Fts5ParseNode(
    +     if( pRet ){
    +       pRet->eType = eType;
    +       pRet->pNear = pNear;
    ++      fts5ExprAssignXNext(pRet);
    +       if( eType==FTS5_STRING ){
    +         int iPhrase;
    +         for(iPhrase=0; iPhrase<pNear->nPhrase; iPhrase++){
    +           pNear->apPhrase[iPhrase]->pNode = pRet;
    ++          if( pNear->apPhrase[iPhrase]->nTerm==0 ){
    ++            pRet->xNext = 0;
    ++            pRet->eType = FTS5_EOF;
    ++          }
    +         }
    +-        if( pNear->nPhrase==1 
    +-         && pNear->apPhrase[0]->nTerm==1 
    +-         && pNear->apPhrase[0]->aTerm[0].pSynonym==0
    +-        ){
    +-          pRet->eType = FTS5_TERM;
    ++
    ++        if( pParse->pConfig->eDetail!=FTS5_DETAIL_FULL ){
    ++          Fts5ExprPhrase *pPhrase = pNear->apPhrase[0];
    ++          if( pNear->nPhrase!=1 
    ++           || pPhrase->nTerm>1
    ++           || (pPhrase->nTerm>0 && pPhrase->aTerm[0].bFirst)
    ++          ){
    ++            assert( pParse->rc==SQLITE_OK );
    ++            pParse->rc = SQLITE_ERROR;
    ++            assert( pParse->zErr==0 );
    ++            pParse->zErr = sqlite3_mprintf(
    ++                "fts5: %s queries are not supported (detail!=full)", 
    ++                pNear->nPhrase==1 ? "phrase": "NEAR"
    ++                );
    ++            sqlite3_free(pRet);
    ++            pRet = 0;
    ++          }
    +         }
    +       }else{
    +         fts5ExprAddChildren(pRet, pLeft);
    +@@ -171591,6 +193031,70 @@ static Fts5ExprNode *sqlite3Fts5ParseNode(
    +   return pRet;
    + }
    + 
    ++static Fts5ExprNode *sqlite3Fts5ParseImplicitAnd(
    ++  Fts5Parse *pParse,              /* Parse context */
    ++  Fts5ExprNode *pLeft,            /* Left hand child expression */
    ++  Fts5ExprNode *pRight            /* Right hand child expression */
    ++){
    ++  Fts5ExprNode *pRet = 0;
    ++  Fts5ExprNode *pPrev;
    ++
    ++  if( pParse->rc ){
    ++    sqlite3Fts5ParseNodeFree(pLeft);
    ++    sqlite3Fts5ParseNodeFree(pRight);
    ++  }else{
    ++
    ++    assert( pLeft->eType==FTS5_STRING 
    ++        || pLeft->eType==FTS5_TERM
    ++        || pLeft->eType==FTS5_EOF
    ++        || pLeft->eType==FTS5_AND
    ++    );
    ++    assert( pRight->eType==FTS5_STRING 
    ++        || pRight->eType==FTS5_TERM 
    ++        || pRight->eType==FTS5_EOF 
    ++    );
    ++
    ++    if( pLeft->eType==FTS5_AND ){
    ++      pPrev = pLeft->apChild[pLeft->nChild-1];
    ++    }else{
    ++      pPrev = pLeft;
    ++    }
    ++    assert( pPrev->eType==FTS5_STRING 
    ++        || pPrev->eType==FTS5_TERM 
    ++        || pPrev->eType==FTS5_EOF 
    ++        );
    ++
    ++    if( pRight->eType==FTS5_EOF ){
    ++      assert( pParse->apPhrase[pParse->nPhrase-1]==pRight->pNear->apPhrase[0] );
    ++      sqlite3Fts5ParseNodeFree(pRight);
    ++      pRet = pLeft;
    ++      pParse->nPhrase--;
    ++    }
    ++    else if( pPrev->eType==FTS5_EOF ){
    ++      Fts5ExprPhrase **ap;
    ++
    ++      if( pPrev==pLeft ){
    ++        pRet = pRight;
    ++      }else{
    ++        pLeft->apChild[pLeft->nChild-1] = pRight;
    ++        pRet = pLeft;
    ++      }
    ++
    ++      ap = &pParse->apPhrase[pParse->nPhrase-1-pRight->pNear->nPhrase];
    ++      assert( ap[0]==pPrev->pNear->apPhrase[0] );
    ++      memmove(ap, &ap[1], sizeof(Fts5ExprPhrase*)*pRight->pNear->nPhrase);
    ++      pParse->nPhrase--;
    ++
    ++      sqlite3Fts5ParseNodeFree(pPrev);
    ++    }
    ++    else{
    ++      pRet = sqlite3Fts5ParseNode(pParse, FTS5_AND, pLeft, pRight, 0);
    ++    }
    ++  }
    ++
    ++  return pRet;
    ++}
    ++
    + static char *fts5ExprTermPrint(Fts5ExprTerm *pTerm){
    +   int nByte = 0;
    +   Fts5ExprTerm *p;
    +@@ -171598,7 +193102,7 @@ static char *fts5ExprTermPrint(Fts5ExprTerm *pTerm){
    + 
    +   /* Determine the maximum amount of space required. */
    +   for(p=pTerm; p; p=p->pSynonym){
    +-    nByte += strlen(pTerm->zTerm) * 2 + 3 + 2;
    ++    nByte += (int)strlen(pTerm->zTerm) * 2 + 3 + 2;
    +   }
    +   zQuoted = sqlite3_malloc(nByte);
    + 
    +@@ -171687,6 +193191,9 @@ static char *fts5ExprPrintTcl(
    +       for(iTerm=0; zRet && iTerm<pPhrase->nTerm; iTerm++){
    +         char *zTerm = pPhrase->aTerm[iTerm].zTerm;
    +         zRet = fts5PrintfAppend(zRet, "%s%s", iTerm==0?"":" ", zTerm);
    ++        if( pPhrase->aTerm[iTerm].bPrefix ){
    ++          zRet = fts5PrintfAppend(zRet, "*");
    ++        }
    +       }
    + 
    +       if( zRet ) zRet = fts5PrintfAppend(zRet, "}");
    +@@ -171722,6 +193229,9 @@ static char *fts5ExprPrintTcl(
    + 
    + static char *fts5ExprPrint(Fts5Config *pConfig, Fts5ExprNode *pExpr){
    +   char *zRet = 0;
    ++  if( pExpr->eType==0 ){
    ++    return sqlite3_mprintf("\"\"");
    ++  }else
    +   if( pExpr->eType==FTS5_STRING || pExpr->eType==FTS5_TERM ){
    +     Fts5ExprNearset *pNear = pExpr->pNear;
    +     int i; 
    +@@ -171782,7 +193292,7 @@ static char *fts5ExprPrint(Fts5Config *pConfig, Fts5ExprNode *pExpr){
    +         zRet = 0;
    +       }else{
    +         int e = pExpr->apChild[i]->eType;
    +-        int b = (e!=FTS5_STRING && e!=FTS5_TERM);
    ++        int b = (e!=FTS5_STRING && e!=FTS5_TERM && e!=FTS5_EOF);
    +         zRet = fts5PrintfAppend(zRet, "%s%s%z%s", 
    +             (i==0 ? "" : zOp),
    +             (b?"(":""), z, (b?")":"")
    +@@ -171850,11 +193360,11 @@ static void fts5ExprFunction(
    + 
    +   rc = sqlite3Fts5ConfigParse(pGlobal, db, nConfig, azConfig, &pConfig, &zErr);
    +   if( rc==SQLITE_OK ){
    +-    rc = sqlite3Fts5ExprNew(pConfig, zExpr, &pExpr, &zErr);
    ++    rc = sqlite3Fts5ExprNew(pConfig, pConfig->nCol, zExpr, &pExpr, &zErr);
    +   }
    +   if( rc==SQLITE_OK ){
    +     char *zText;
    +-    if( pExpr->pRoot==0 ){
    ++    if( pExpr->pRoot->xNext==0 ){
    +       zText = sqlite3_mprintf("");
    +     }else if( bTcl ){
    +       zText = fts5ExprPrintTcl(pConfig, zNearsetCmd, pExpr->pRoot);
    +@@ -171954,7 +193464,7 @@ static int sqlite3Fts5ExprInit(Fts5Global *pGlobal, sqlite3 *db){
    +   int rc = SQLITE_OK;
    +   void *pCtx = (void*)pGlobal;
    + 
    +-  for(i=0; rc==SQLITE_OK && i<(sizeof(aFunc) / sizeof(aFunc[0])); i++){
    ++  for(i=0; rc==SQLITE_OK && i<ArraySize(aFunc); i++){
    +     struct Fts5ExprFunc *p = &aFunc[i];
    +     rc = sqlite3_create_function(db, p->z, -1, SQLITE_UTF8, pCtx, p->x, 0, 0);
    +   }
    +@@ -172000,6 +193510,215 @@ static int sqlite3Fts5ExprPoslist(Fts5Expr *pExpr, int iPhrase, const u8 **pa){
    +   return nRet;
    + }
    + 
    ++struct Fts5PoslistPopulator {
    ++  Fts5PoslistWriter writer;
    ++  int bOk;                        /* True if ok to populate */
    ++  int bMiss;
    ++};
    ++
    ++static Fts5PoslistPopulator *sqlite3Fts5ExprClearPoslists(Fts5Expr *pExpr, int bLive){
    ++  Fts5PoslistPopulator *pRet;
    ++  pRet = sqlite3_malloc(sizeof(Fts5PoslistPopulator)*pExpr->nPhrase);
    ++  if( pRet ){
    ++    int i;
    ++    memset(pRet, 0, sizeof(Fts5PoslistPopulator)*pExpr->nPhrase);
    ++    for(i=0; i<pExpr->nPhrase; i++){
    ++      Fts5Buffer *pBuf = &pExpr->apExprPhrase[i]->poslist;
    ++      Fts5ExprNode *pNode = pExpr->apExprPhrase[i]->pNode;
    ++      assert( pExpr->apExprPhrase[i]->nTerm==1 );
    ++      if( bLive && 
    ++          (pBuf->n==0 || pNode->iRowid!=pExpr->pRoot->iRowid || pNode->bEof)
    ++      ){
    ++        pRet[i].bMiss = 1;
    ++      }else{
    ++        pBuf->n = 0;
    ++      }
    ++    }
    ++  }
    ++  return pRet;
    ++}
    ++
    ++struct Fts5ExprCtx {
    ++  Fts5Expr *pExpr;
    ++  Fts5PoslistPopulator *aPopulator;
    ++  i64 iOff;
    ++};
    ++typedef struct Fts5ExprCtx Fts5ExprCtx;
    ++
    ++/*
    ++** TODO: Make this more efficient!
    ++*/
    ++static int fts5ExprColsetTest(Fts5Colset *pColset, int iCol){
    ++  int i;
    ++  for(i=0; i<pColset->nCol; i++){
    ++    if( pColset->aiCol[i]==iCol ) return 1;
    ++  }
    ++  return 0;
    ++}
    ++
    ++static int fts5ExprPopulatePoslistsCb(
    ++  void *pCtx,                /* Copy of 2nd argument to xTokenize() */
    ++  int tflags,                /* Mask of FTS5_TOKEN_* flags */
    ++  const char *pToken,        /* Pointer to buffer containing token */
    ++  int nToken,                /* Size of token in bytes */
    ++  int iUnused1,              /* Byte offset of token within input text */
    ++  int iUnused2               /* Byte offset of end of token within input text */
    ++){
    ++  Fts5ExprCtx *p = (Fts5ExprCtx*)pCtx;
    ++  Fts5Expr *pExpr = p->pExpr;
    ++  int i;
    ++
    ++  UNUSED_PARAM2(iUnused1, iUnused2);
    ++
    ++  if( nToken>FTS5_MAX_TOKEN_SIZE ) nToken = FTS5_MAX_TOKEN_SIZE;
    ++  if( (tflags & FTS5_TOKEN_COLOCATED)==0 ) p->iOff++;
    ++  for(i=0; i<pExpr->nPhrase; i++){
    ++    Fts5ExprTerm *pTerm;
    ++    if( p->aPopulator[i].bOk==0 ) continue;
    ++    for(pTerm=&pExpr->apExprPhrase[i]->aTerm[0]; pTerm; pTerm=pTerm->pSynonym){
    ++      int nTerm = (int)strlen(pTerm->zTerm);
    ++      if( (nTerm==nToken || (nTerm<nToken && pTerm->bPrefix))
    ++       && memcmp(pTerm->zTerm, pToken, nTerm)==0
    ++      ){
    ++        int rc = sqlite3Fts5PoslistWriterAppend(
    ++            &pExpr->apExprPhrase[i]->poslist, &p->aPopulator[i].writer, p->iOff
    ++        );
    ++        if( rc ) return rc;
    ++        break;
    ++      }
    ++    }
    ++  }
    ++  return SQLITE_OK;
    ++}
    ++
    ++static int sqlite3Fts5ExprPopulatePoslists(
    ++  Fts5Config *pConfig,
    ++  Fts5Expr *pExpr, 
    ++  Fts5PoslistPopulator *aPopulator,
    ++  int iCol, 
    ++  const char *z, int n
    ++){
    ++  int i;
    ++  Fts5ExprCtx sCtx;
    ++  sCtx.pExpr = pExpr;
    ++  sCtx.aPopulator = aPopulator;
    ++  sCtx.iOff = (((i64)iCol) << 32) - 1;
    ++
    ++  for(i=0; i<pExpr->nPhrase; i++){
    ++    Fts5ExprNode *pNode = pExpr->apExprPhrase[i]->pNode;
    ++    Fts5Colset *pColset = pNode->pNear->pColset;
    ++    if( (pColset && 0==fts5ExprColsetTest(pColset, iCol)) 
    ++     || aPopulator[i].bMiss
    ++    ){
    ++      aPopulator[i].bOk = 0;
    ++    }else{
    ++      aPopulator[i].bOk = 1;
    ++    }
    ++  }
    ++
    ++  return sqlite3Fts5Tokenize(pConfig, 
    ++      FTS5_TOKENIZE_DOCUMENT, z, n, (void*)&sCtx, fts5ExprPopulatePoslistsCb
    ++  );
    ++}
    ++
    ++static void fts5ExprClearPoslists(Fts5ExprNode *pNode){
    ++  if( pNode->eType==FTS5_TERM || pNode->eType==FTS5_STRING ){
    ++    pNode->pNear->apPhrase[0]->poslist.n = 0;
    ++  }else{
    ++    int i;
    ++    for(i=0; i<pNode->nChild; i++){
    ++      fts5ExprClearPoslists(pNode->apChild[i]);
    ++    }
    ++  }
    ++}
    ++
    ++static int fts5ExprCheckPoslists(Fts5ExprNode *pNode, i64 iRowid){
    ++  pNode->iRowid = iRowid;
    ++  pNode->bEof = 0;
    ++  switch( pNode->eType ){
    ++    case FTS5_TERM:
    ++    case FTS5_STRING:
    ++      return (pNode->pNear->apPhrase[0]->poslist.n>0);
    ++
    ++    case FTS5_AND: {
    ++      int i;
    ++      for(i=0; i<pNode->nChild; i++){
    ++        if( fts5ExprCheckPoslists(pNode->apChild[i], iRowid)==0 ){
    ++          fts5ExprClearPoslists(pNode);
    ++          return 0;
    ++        }
    ++      }
    ++      break;
    ++    }
    ++
    ++    case FTS5_OR: {
    ++      int i;
    ++      int bRet = 0;
    ++      for(i=0; i<pNode->nChild; i++){
    ++        if( fts5ExprCheckPoslists(pNode->apChild[i], iRowid) ){
    ++          bRet = 1;
    ++        }
    ++      }
    ++      return bRet;
    ++    }
    ++
    ++    default: {
    ++      assert( pNode->eType==FTS5_NOT );
    ++      if( 0==fts5ExprCheckPoslists(pNode->apChild[0], iRowid)
    ++          || 0!=fts5ExprCheckPoslists(pNode->apChild[1], iRowid)
    ++        ){
    ++        fts5ExprClearPoslists(pNode);
    ++        return 0;
    ++      }
    ++      break;
    ++    }
    ++  }
    ++  return 1;
    ++}
    ++
    ++static void sqlite3Fts5ExprCheckPoslists(Fts5Expr *pExpr, i64 iRowid){
    ++  fts5ExprCheckPoslists(pExpr->pRoot, iRowid);
    ++}
    ++
    ++/*
    ++** This function is only called for detail=columns tables. 
    ++*/
    ++static int sqlite3Fts5ExprPhraseCollist(
    ++  Fts5Expr *pExpr, 
    ++  int iPhrase, 
    ++  const u8 **ppCollist, 
    ++  int *pnCollist
    ++){
    ++  Fts5ExprPhrase *pPhrase = pExpr->apExprPhrase[iPhrase];
    ++  Fts5ExprNode *pNode = pPhrase->pNode;
    ++  int rc = SQLITE_OK;
    ++
    ++  assert( iPhrase>=0 && iPhrase<pExpr->nPhrase );
    ++  assert( pExpr->pConfig->eDetail==FTS5_DETAIL_COLUMNS );
    ++
    ++  if( pNode->bEof==0 
    ++   && pNode->iRowid==pExpr->pRoot->iRowid 
    ++   && pPhrase->poslist.n>0
    ++  ){
    ++    Fts5ExprTerm *pTerm = &pPhrase->aTerm[0];
    ++    if( pTerm->pSynonym ){
    ++      Fts5Buffer *pBuf = (Fts5Buffer*)&pTerm->pSynonym[1];
    ++      rc = fts5ExprSynonymList(
    ++          pTerm, pNode->iRowid, pBuf, (u8**)ppCollist, pnCollist
    ++      );
    ++    }else{
    ++      *ppCollist = pPhrase->aTerm[0].pIter->pData;
    ++      *pnCollist = pPhrase->aTerm[0].pIter->nData;
    ++    }
    ++  }else{
    ++    *ppCollist = 0;
    ++    *pnCollist = 0;
    ++  }
    ++
    ++  return rc;
    ++}
    ++
    ++
    + /*
    + ** 2014 August 11
    + **
    +@@ -172016,6 +193735,7 @@ static int sqlite3Fts5ExprPoslist(Fts5Expr *pExpr, int iPhrase, const u8 **pa){
    + 
    + 
    + 
    ++/* #include "fts5Int.h" */
    + 
    + typedef struct Fts5HashEntry Fts5HashEntry;
    + 
    +@@ -172027,6 +193747,7 @@ typedef struct Fts5HashEntry Fts5HashEntry;
    + 
    + 
    + struct Fts5Hash {
    ++  int eDetail;                    /* Copy of Fts5Config.eDetail */
    +   int *pnByte;                    /* Pointer to bytes counter */
    +   int nEntry;                     /* Number of entries currently in hash */
    +   int nSlot;                      /* Size of aSlot[] array */
    +@@ -172036,9 +193757,10 @@ struct Fts5Hash {
    + 
    + /*
    + ** Each entry in the hash table is represented by an object of the 
    +-** following type. Each object, its key (zKey[]) and its current data
    +-** are stored in a single memory allocation. The position list data 
    +-** immediately follows the key data in memory.
    ++** following type. Each object, its key (a nul-terminated string) and 
    ++** its current data are stored in a single memory allocation. The 
    ++** key immediately follows the object in memory. The position list
    ++** data immediately follows the key data in memory.
    + **
    + ** The data that follows the key is in a similar, but not identical format
    + ** to the doclist data stored in the database. It is:
    +@@ -172062,25 +193784,26 @@ struct Fts5HashEntry {
    +   int nAlloc;                     /* Total size of allocation */
    +   int iSzPoslist;                 /* Offset of space for 4-byte poslist size */
    +   int nData;                      /* Total bytes of data (incl. structure) */
    ++  int nKey;                       /* Length of key in bytes */
    +   u8 bDel;                        /* Set delete-flag @ iSzPoslist */
    +-
    +-  int iCol;                       /* Column of last value written */
    ++  u8 bContent;                    /* Set content-flag (detail=none mode) */
    ++  i16 iCol;                       /* Column of last value written */
    +   int iPos;                       /* Position of last value written */
    +   i64 iRowid;                     /* Rowid of last value written */
    +-  char zKey[8];                   /* Nul-terminated entry key */
    + };
    + 
    + /*
    +-** Size of Fts5HashEntry without the zKey[] array.
    ++** Eqivalent to:
    ++**
    ++**   char *fts5EntryKey(Fts5HashEntry *pEntry){ return zKey; }
    + */
    +-#define FTS5_HASHENTRYSIZE (sizeof(Fts5HashEntry)-8)
    +-
    ++#define fts5EntryKey(p) ( ((char *)(&(p)[1])) )
    + 
    + 
    + /*
    + ** Allocate a new hash table.
    + */
    +-static int sqlite3Fts5HashNew(Fts5Hash **ppNew, int *pnByte){
    ++static int sqlite3Fts5HashNew(Fts5Config *pConfig, Fts5Hash **ppNew, int *pnByte){
    +   int rc = SQLITE_OK;
    +   Fts5Hash *pNew;
    + 
    +@@ -172091,6 +193814,7 @@ static int sqlite3Fts5HashNew(Fts5Hash **ppNew, int *pnByte){
    +     int nByte;
    +     memset(pNew, 0, sizeof(Fts5Hash));
    +     pNew->pnByte = pnByte;
    ++    pNew->eDetail = pConfig->eDetail;
    + 
    +     pNew->nSlot = 1024;
    +     nByte = sizeof(Fts5HashEntry*) * pNew->nSlot;
    +@@ -172168,10 +193892,11 @@ static int fts5HashResize(Fts5Hash *pHash){
    + 
    +   for(i=0; i<pHash->nSlot; i++){
    +     while( apOld[i] ){
    +-      int iHash;
    ++      unsigned int iHash;
    +       Fts5HashEntry *p = apOld[i];
    +       apOld[i] = p->pHashNext;
    +-      iHash = fts5HashKey(nNew, (u8*)p->zKey, strlen(p->zKey));
    ++      iHash = fts5HashKey(nNew, (u8*)fts5EntryKey(p),
    ++                          (int)strlen(fts5EntryKey(p)));
    +       p->pHashNext = apNew[iHash];
    +       apNew[iHash] = p;
    +     }
    +@@ -172183,26 +193908,46 @@ static int fts5HashResize(Fts5Hash *pHash){
    +   return SQLITE_OK;
    + }
    + 
    +-static void fts5HashAddPoslistSize(Fts5HashEntry *p){
    ++static void fts5HashAddPoslistSize(Fts5Hash *pHash, Fts5HashEntry *p){
    +   if( p->iSzPoslist ){
    +     u8 *pPtr = (u8*)p;
    +-    int nSz = (p->nData - p->iSzPoslist - 1);         /* Size in bytes */
    +-    int nPos = nSz*2 + p->bDel;                       /* Value of nPos field */
    +-
    +-    assert( p->bDel==0 || p->bDel==1 );
    +-    if( nPos<=127 ){
    +-      pPtr[p->iSzPoslist] = nPos;
    ++    if( pHash->eDetail==FTS5_DETAIL_NONE ){
    ++      assert( p->nData==p->iSzPoslist );
    ++      if( p->bDel ){
    ++        pPtr[p->nData++] = 0x00;
    ++        if( p->bContent ){
    ++          pPtr[p->nData++] = 0x00;
    ++        }
    ++      }
    +     }else{
    +-      int nByte = sqlite3Fts5GetVarintLen((u32)nPos);
    +-      memmove(&pPtr[p->iSzPoslist + nByte], &pPtr[p->iSzPoslist + 1], nSz);
    +-      sqlite3Fts5PutVarint(&pPtr[p->iSzPoslist], nPos);
    +-      p->nData += (nByte-1);
    ++      int nSz = (p->nData - p->iSzPoslist - 1);       /* Size in bytes */
    ++      int nPos = nSz*2 + p->bDel;                     /* Value of nPos field */
    ++
    ++      assert( p->bDel==0 || p->bDel==1 );
    ++      if( nPos<=127 ){
    ++        pPtr[p->iSzPoslist] = (u8)nPos;
    ++      }else{
    ++        int nByte = sqlite3Fts5GetVarintLen((u32)nPos);
    ++        memmove(&pPtr[p->iSzPoslist + nByte], &pPtr[p->iSzPoslist + 1], nSz);
    ++        sqlite3Fts5PutVarint(&pPtr[p->iSzPoslist], nPos);
    ++        p->nData += (nByte-1);
    ++      }
    +     }
    +-    p->bDel = 0;
    ++
    +     p->iSzPoslist = 0;
    ++    p->bDel = 0;
    ++    p->bContent = 0;
    +   }
    + }
    + 
    ++/*
    ++** Add an entry to the in-memory hash table. The key is the concatenation
    ++** of bByte and (pToken/nToken). The value is (iRowid/iCol/iPos).
    ++**
    ++**     (bByte || pToken) -> (iRowid,iCol,iPos)
    ++**
    ++** Or, if iCol is negative, then the value is a delete marker.
    ++*/
    + static int sqlite3Fts5HashWrite(
    +   Fts5Hash *pHash,
    +   i64 iRowid,                     /* Rowid for this entry */
    +@@ -172215,13 +193960,17 @@ static int sqlite3Fts5HashWrite(
    +   Fts5HashEntry *p;
    +   u8 *pPtr;
    +   int nIncr = 0;                  /* Amount to increment (*pHash->pnByte) by */
    ++  int bNew;                       /* If non-delete entry should be written */
    ++  
    ++  bNew = (pHash->eDetail==FTS5_DETAIL_FULL);
    + 
    +   /* Attempt to locate an existing hash entry */
    +   iHash = fts5HashKey2(pHash->nSlot, (u8)bByte, (const u8*)pToken, nToken);
    +   for(p=pHash->aSlot[iHash]; p; p=p->pHashNext){
    +-    if( p->zKey[0]==bByte 
    +-     && memcmp(&p->zKey[1], pToken, nToken)==0 
    +-     && p->zKey[nToken+1]==0 
    ++    char *zKey = fts5EntryKey(p);
    ++    if( zKey[0]==bByte 
    ++     && p->nKey==nToken
    ++     && memcmp(&zKey[1], pToken, nToken)==0 
    +     ){
    +       break;
    +     }
    +@@ -172229,88 +193978,119 @@ static int sqlite3Fts5HashWrite(
    + 
    +   /* If an existing hash entry cannot be found, create a new one. */
    +   if( p==0 ){
    +-    int nByte = FTS5_HASHENTRYSIZE + (nToken+1) + 1 + 64;
    ++    /* Figure out how much space to allocate */
    ++    char *zKey;
    ++    int nByte = sizeof(Fts5HashEntry) + (nToken+1) + 1 + 64;
    +     if( nByte<128 ) nByte = 128;
    + 
    ++    /* Grow the Fts5Hash.aSlot[] array if necessary. */
    +     if( (pHash->nEntry*2)>=pHash->nSlot ){
    +       int rc = fts5HashResize(pHash);
    +       if( rc!=SQLITE_OK ) return rc;
    +       iHash = fts5HashKey2(pHash->nSlot, (u8)bByte, (const u8*)pToken, nToken);
    +     }
    + 
    ++    /* Allocate new Fts5HashEntry and add it to the hash table. */
    +     p = (Fts5HashEntry*)sqlite3_malloc(nByte);
    +     if( !p ) return SQLITE_NOMEM;
    +-    memset(p, 0, FTS5_HASHENTRYSIZE);
    ++    memset(p, 0, sizeof(Fts5HashEntry));
    +     p->nAlloc = nByte;
    +-    p->zKey[0] = bByte;
    +-    memcpy(&p->zKey[1], pToken, nToken);
    +-    assert( iHash==fts5HashKey(pHash->nSlot, (u8*)p->zKey, nToken+1) );
    +-    p->zKey[nToken+1] = '\0';
    +-    p->nData = nToken+1 + 1 + FTS5_HASHENTRYSIZE;
    +-    p->nData += sqlite3Fts5PutVarint(&((u8*)p)[p->nData], iRowid);
    +-    p->iSzPoslist = p->nData;
    +-    p->nData += 1;
    +-    p->iRowid = iRowid;
    ++    zKey = fts5EntryKey(p);
    ++    zKey[0] = bByte;
    ++    memcpy(&zKey[1], pToken, nToken);
    ++    assert( iHash==fts5HashKey(pHash->nSlot, (u8*)zKey, nToken+1) );
    ++    p->nKey = nToken;
    ++    zKey[nToken+1] = '\0';
    ++    p->nData = nToken+1 + 1 + sizeof(Fts5HashEntry);
    +     p->pHashNext = pHash->aSlot[iHash];
    +     pHash->aSlot[iHash] = p;
    +     pHash->nEntry++;
    ++
    ++    /* Add the first rowid field to the hash-entry */
    ++    p->nData += sqlite3Fts5PutVarint(&((u8*)p)[p->nData], iRowid);
    ++    p->iRowid = iRowid;
    ++
    ++    p->iSzPoslist = p->nData;
    ++    if( pHash->eDetail!=FTS5_DETAIL_NONE ){
    ++      p->nData += 1;
    ++      p->iCol = (pHash->eDetail==FTS5_DETAIL_FULL ? 0 : -1);
    ++    }
    ++
    +     nIncr += p->nData;
    +-  }
    ++  }else{
    + 
    +-  /* Check there is enough space to append a new entry. Worst case scenario
    +-  ** is:
    +-  **
    +-  **     + 9 bytes for a new rowid,
    +-  **     + 4 byte reserved for the "poslist size" varint.
    +-  **     + 1 byte for a "new column" byte,
    +-  **     + 3 bytes for a new column number (16-bit max) as a varint,
    +-  **     + 5 bytes for the new position offset (32-bit max).
    +-  */
    +-  if( (p->nAlloc - p->nData) < (9 + 4 + 1 + 3 + 5) ){
    +-    int nNew = p->nAlloc * 2;
    +-    Fts5HashEntry *pNew;
    +-    Fts5HashEntry **pp;
    +-    pNew = (Fts5HashEntry*)sqlite3_realloc(p, nNew);
    +-    if( pNew==0 ) return SQLITE_NOMEM;
    +-    pNew->nAlloc = nNew;
    +-    for(pp=&pHash->aSlot[iHash]; *pp!=p; pp=&(*pp)->pHashNext);
    +-    *pp = pNew;
    +-    p = pNew;
    ++    /* Appending to an existing hash-entry. Check that there is enough 
    ++    ** space to append the largest possible new entry. Worst case scenario 
    ++    ** is:
    ++    **
    ++    **     + 9 bytes for a new rowid,
    ++    **     + 4 byte reserved for the "poslist size" varint.
    ++    **     + 1 byte for a "new column" byte,
    ++    **     + 3 bytes for a new column number (16-bit max) as a varint,
    ++    **     + 5 bytes for the new position offset (32-bit max).
    ++    */
    ++    if( (p->nAlloc - p->nData) < (9 + 4 + 1 + 3 + 5) ){
    ++      int nNew = p->nAlloc * 2;
    ++      Fts5HashEntry *pNew;
    ++      Fts5HashEntry **pp;
    ++      pNew = (Fts5HashEntry*)sqlite3_realloc(p, nNew);
    ++      if( pNew==0 ) return SQLITE_NOMEM;
    ++      pNew->nAlloc = nNew;
    ++      for(pp=&pHash->aSlot[iHash]; *pp!=p; pp=&(*pp)->pHashNext);
    ++      *pp = pNew;
    ++      p = pNew;
    ++    }
    ++    nIncr -= p->nData;
    +   }
    ++  assert( (p->nAlloc - p->nData) >= (9 + 4 + 1 + 3 + 5) );
    ++
    +   pPtr = (u8*)p;
    +-  nIncr -= p->nData;
    + 
    +   /* If this is a new rowid, append the 4-byte size field for the previous
    +   ** entry, and the new rowid for this entry.  */
    +   if( iRowid!=p->iRowid ){
    +-    fts5HashAddPoslistSize(p);
    ++    fts5HashAddPoslistSize(pHash, p);
    +     p->nData += sqlite3Fts5PutVarint(&pPtr[p->nData], iRowid - p->iRowid);
    +-    p->iSzPoslist = p->nData;
    +-    p->nData += 1;
    +-    p->iCol = 0;
    +-    p->iPos = 0;
    +     p->iRowid = iRowid;
    ++    bNew = 1;
    ++    p->iSzPoslist = p->nData;
    ++    if( pHash->eDetail!=FTS5_DETAIL_NONE ){
    ++      p->nData += 1;
    ++      p->iCol = (pHash->eDetail==FTS5_DETAIL_FULL ? 0 : -1);
    ++      p->iPos = 0;
    ++    }
    +   }
    + 
    +   if( iCol>=0 ){
    +-    /* Append a new column value, if necessary */
    +-    assert( iCol>=p->iCol );
    +-    if( iCol!=p->iCol ){
    +-      pPtr[p->nData++] = 0x01;
    +-      p->nData += sqlite3Fts5PutVarint(&pPtr[p->nData], iCol);
    +-      p->iCol = iCol;
    +-      p->iPos = 0;
    +-    }
    ++    if( pHash->eDetail==FTS5_DETAIL_NONE ){
    ++      p->bContent = 1;
    ++    }else{
    ++      /* Append a new column value, if necessary */
    ++      assert( iCol>=p->iCol );
    ++      if( iCol!=p->iCol ){
    ++        if( pHash->eDetail==FTS5_DETAIL_FULL ){
    ++          pPtr[p->nData++] = 0x01;
    ++          p->nData += sqlite3Fts5PutVarint(&pPtr[p->nData], iCol);
    ++          p->iCol = (i16)iCol;
    ++          p->iPos = 0;
    ++        }else{
    ++          bNew = 1;
    ++          p->iCol = (i16)(iPos = iCol);
    ++        }
    ++      }
    + 
    +-    /* Append the new position offset */
    +-    p->nData += sqlite3Fts5PutVarint(&pPtr[p->nData], iPos - p->iPos + 2);
    +-    p->iPos = iPos;
    ++      /* Append the new position offset, if necessary */
    ++      if( bNew ){
    ++        p->nData += sqlite3Fts5PutVarint(&pPtr[p->nData], iPos - p->iPos + 2);
    ++        p->iPos = iPos;
    ++      }
    ++    }
    +   }else{
    +     /* This is a delete. Set the delete flag. */
    +     p->bDel = 1;
    +   }
    +-  nIncr += p->nData;
    + 
    ++  nIncr += p->nData;
    +   *pHash->pnByte += nIncr;
    +   return SQLITE_OK;
    + }
    +@@ -172339,9 +194119,11 @@ static Fts5HashEntry *fts5HashEntryMerge(
    +       p1 = 0;
    +     }else{
    +       int i = 0;
    +-      while( p1->zKey[i]==p2->zKey[i] ) i++;
    ++      char *zKey1 = fts5EntryKey(p1);
    ++      char *zKey2 = fts5EntryKey(p2);
    ++      while( zKey1[i]==zKey2[i] ) i++;
    + 
    +-      if( ((u8)p1->zKey[i])>((u8)p2->zKey[i]) ){
    ++      if( ((u8)zKey1[i])>((u8)zKey2[i]) ){
    +         /* p2 is smaller */
    +         *ppOut = p2;
    +         ppOut = &p2->pScanNext;
    +@@ -172384,7 +194166,7 @@ static int fts5HashEntrySort(
    +   for(iSlot=0; iSlot<pHash->nSlot; iSlot++){
    +     Fts5HashEntry *pIter;
    +     for(pIter=pHash->aSlot[iSlot]; pIter; pIter=pIter->pHashNext){
    +-      if( pTerm==0 || 0==memcmp(pIter->zKey, pTerm, nTerm) ){
    ++      if( pTerm==0 || 0==memcmp(fts5EntryKey(pIter), pTerm, nTerm) ){
    +         Fts5HashEntry *pEntry = pIter;
    +         pEntry->pScanNext = 0;
    +         for(i=0; ap[i]; i++){
    +@@ -172417,16 +194199,18 @@ static int sqlite3Fts5HashQuery(
    +   int *pnDoclist                  /* OUT: Size of doclist in bytes */
    + ){
    +   unsigned int iHash = fts5HashKey(pHash->nSlot, (const u8*)pTerm, nTerm);
    ++  char *zKey = 0;
    +   Fts5HashEntry *p;
    + 
    +   for(p=pHash->aSlot[iHash]; p; p=p->pHashNext){
    +-    if( memcmp(p->zKey, pTerm, nTerm)==0 && p->zKey[nTerm]==0 ) break;
    ++    zKey = fts5EntryKey(p);
    ++    if( memcmp(zKey, pTerm, nTerm)==0 && zKey[nTerm]==0 ) break;
    +   }
    + 
    +   if( p ){
    +-    fts5HashAddPoslistSize(p);
    +-    *ppDoclist = (const u8*)&p->zKey[nTerm+1];
    +-    *pnDoclist = p->nData - (FTS5_HASHENTRYSIZE + nTerm + 1);
    ++    fts5HashAddPoslistSize(pHash, p);
    ++    *ppDoclist = (const u8*)&zKey[nTerm+1];
    ++    *pnDoclist = p->nData - (sizeof(Fts5HashEntry) + nTerm + 1);
    +   }else{
    +     *ppDoclist = 0;
    +     *pnDoclist = 0;
    +@@ -172459,11 +194243,12 @@ static void sqlite3Fts5HashScanEntry(
    + ){
    +   Fts5HashEntry *p;
    +   if( (p = pHash->pScan) ){
    +-    int nTerm = strlen(p->zKey);
    +-    fts5HashAddPoslistSize(p);
    +-    *pzTerm = p->zKey;
    +-    *ppDoclist = (const u8*)&p->zKey[nTerm+1];
    +-    *pnDoclist = p->nData - (FTS5_HASHENTRYSIZE + nTerm + 1);
    ++    char *zKey = fts5EntryKey(p);
    ++    int nTerm = (int)strlen(zKey);
    ++    fts5HashAddPoslistSize(pHash, p);
    ++    *pzTerm = zKey;
    ++    *ppDoclist = (const u8*)&zKey[nTerm+1];
    ++    *pnDoclist = p->nData - (sizeof(Fts5HashEntry) + nTerm + 1);
    +   }else{
    +     *pzTerm = 0;
    +     *ppDoclist = 0;
    +@@ -172491,6 +194276,7 @@ static void sqlite3Fts5HashScanEntry(
    + */
    + 
    + 
    ++/* #include "fts5Int.h" */
    + 
    + /*
    + ** Overview:
    +@@ -172734,6 +194520,7 @@ typedef struct Fts5Data Fts5Data;
    + typedef struct Fts5DlidxIter Fts5DlidxIter;
    + typedef struct Fts5DlidxLvl Fts5DlidxLvl;
    + typedef struct Fts5DlidxWriter Fts5DlidxWriter;
    ++typedef struct Fts5Iter Fts5Iter;
    + typedef struct Fts5PageWriter Fts5PageWriter;
    + typedef struct Fts5SegIter Fts5SegIter;
    + typedef struct Fts5DoclistIter Fts5DoclistIter;
    +@@ -172761,7 +194548,6 @@ struct Fts5Index {
    +   ** in-memory hash tables before they are flushed to disk.
    +   */
    +   Fts5Hash *pHash;                /* Hash table for in-memory data */
    +-  int nMaxPendingData;            /* Max pending data before flush to disk */
    +   int nPendingData;               /* Current bytes of pending data */
    +   i64 iWriteRowid;                /* Rowid for current doc being written */
    +   int bDelete;                    /* Current write is a delete */
    +@@ -172777,6 +194563,10 @@ struct Fts5Index {
    +   sqlite3_stmt *pIdxDeleter;      /* "DELETE FROM %_idx WHERE segid=? */
    +   sqlite3_stmt *pIdxSelect;
    +   int nRead;                      /* Total number of blocks read */
    ++
    ++  sqlite3_stmt *pDataVersion;
    ++  i64 iStructVersion;             /* data_version when pStruct read */
    ++  Fts5Structure *pStruct;         /* Current db structure (or NULL) */
    + };
    + 
    + struct Fts5DoclistIter {
    +@@ -172847,26 +194637,6 @@ struct Fts5SegWriter {
    +   int iBtPage;                    /* Page number corresponding to btterm */
    + };
    + 
    +-/*
    +-** Object for iterating through the merged results of one or more segments,
    +-** visiting each term/rowid pair in the merged data.
    +-**
    +-** nSeg is always a power of two greater than or equal to the number of
    +-** segments that this object is merging data from. Both the aSeg[] and
    +-** aFirst[] arrays are sized at nSeg entries. The aSeg[] array is padded
    +-** with zeroed objects - these are handled as if they were iterators opened
    +-** on empty segments.
    +-**
    +-** The results of comparing segments aSeg[N] and aSeg[N+1], where N is an
    +-** even number, is stored in aFirst[(nSeg+N)/2]. The "result" of the 
    +-** comparison in this context is the index of the iterator that currently
    +-** points to the smaller term/rowid combination. Iterators at EOF are
    +-** considered to be greater than all other iterators.
    +-**
    +-** aFirst[1] contains the index in aSeg[] of the iterator that points to
    +-** the smallest key overall. aFirst[0] is unused. 
    +-*/
    +-
    + typedef struct Fts5CResult Fts5CResult;
    + struct Fts5CResult {
    +   u16 iFirst;                     /* aSeg[] index of firstest iterator */
    +@@ -172927,6 +194697,9 @@ struct Fts5SegIter {
    +   Fts5Data *pNextLeaf;            /* Leaf page (iLeafPgno+1) */
    +   int iLeafOffset;                /* Byte offset within current leaf */
    + 
    ++  /* Next method */
    ++  void (*xNext)(Fts5Index*, Fts5SegIter*, int*);
    ++
    +   /* The page and offset from which the current term was read. The offset 
    +   ** is the offset of the first rowid in the current doclist.  */
    +   int iTermLeafPgno;
    +@@ -172946,7 +194719,7 @@ struct Fts5SegIter {
    +   Fts5Buffer term;                /* Current term */
    +   i64 iRowid;                     /* Current rowid */
    +   int nPos;                       /* Number of bytes in current position list */
    +-  int bDel;                       /* True if the delete flag is set */
    ++  u8 bDel;                        /* True if the delete flag is set */
    + };
    + 
    + /*
    +@@ -172960,7 +194733,6 @@ struct Fts5SegIter {
    + #define FTS5_SEGITER_ONETERM 0x01
    + #define FTS5_SEGITER_REVERSE 0x02
    + 
    +-
    + /* 
    + ** Argument is a pointer to an Fts5Data structure that contains a leaf
    + ** page. This macro evaluates to true if the leaf contains no terms, or
    +@@ -172973,20 +194745,42 @@ struct Fts5SegIter {
    + #define fts5LeafFirstRowidOff(x) (fts5GetU16((x)->p))
    + 
    + /*
    ++** Object for iterating through the merged results of one or more segments,
    ++** visiting each term/rowid pair in the merged data.
    ++**
    ++** nSeg is always a power of two greater than or equal to the number of
    ++** segments that this object is merging data from. Both the aSeg[] and
    ++** aFirst[] arrays are sized at nSeg entries. The aSeg[] array is padded
    ++** with zeroed objects - these are handled as if they were iterators opened
    ++** on empty segments.
    ++**
    ++** The results of comparing segments aSeg[N] and aSeg[N+1], where N is an
    ++** even number, is stored in aFirst[(nSeg+N)/2]. The "result" of the 
    ++** comparison in this context is the index of the iterator that currently
    ++** points to the smaller term/rowid combination. Iterators at EOF are
    ++** considered to be greater than all other iterators.
    ++**
    ++** aFirst[1] contains the index in aSeg[] of the iterator that points to
    ++** the smallest key overall. aFirst[0] is unused. 
    ++**
    + ** poslist:
    + **   Used by sqlite3Fts5IterPoslist() when the poslist needs to be buffered.
    + **   There is no way to tell if this is populated or not.
    + */
    +-struct Fts5IndexIter {
    ++struct Fts5Iter {
    ++  Fts5IndexIter base;             /* Base class containing output vars */
    ++
    +   Fts5Index *pIndex;              /* Index that owns this iterator */
    +   Fts5Structure *pStruct;         /* Database structure for this iterator */
    +   Fts5Buffer poslist;             /* Buffer containing current poslist */
    ++  Fts5Colset *pColset;            /* Restrict matches to these columns */
    ++
    ++  /* Invoked to set output variables. */
    ++  void (*xSetOutputs)(Fts5Iter*, Fts5SegIter*);
    + 
    +   int nSeg;                       /* Size of aSeg[] array */
    +   int bRev;                       /* True to iterate in reverse order */
    +   u8 bSkipEmpty;                  /* True to skip deleted entries */
    +-  u8 bEof;                        /* True at EOF */
    +-  u8 bFiltered;                   /* True if column-filter already applied */
    + 
    +   i64 iSwitchRowid;               /* Firstest rowid of other than aFirst[1] */
    +   Fts5CResult *aFirst;            /* Current merge state (see above) */
    +@@ -173076,17 +194870,6 @@ static int fts5BufferCompare(Fts5Buffer *pLeft, Fts5Buffer *pRight){
    +   return (res==0 ? (pLeft->n - pRight->n) : res);
    + }
    + 
    +-#ifdef SQLITE_DEBUG
    +-static int fts5BlobCompare(
    +-  const u8 *pLeft, int nLeft, 
    +-  const u8 *pRight, int nRight
    +-){
    +-  int nCmp = MIN(nLeft, nRight);
    +-  int res = memcmp(pLeft, pRight, nCmp);
    +-  return (res==0 ? (nLeft - nRight) : res);
    +-}
    +-#endif
    +-
    + static int fts5LeafFirstTermOff(Fts5Data *pLeaf){
    +   int ret;
    +   fts5GetVarint32(&pLeaf->p[pLeaf->szLeaf], ret);
    +@@ -173104,7 +194887,6 @@ static void fts5CloseReader(Fts5Index *p){
    +   }
    + }
    + 
    +-
    + /*
    + ** Retrieve a record from the %_data table.
    + **
    +@@ -173186,6 +194968,18 @@ static void fts5DataRelease(Fts5Data *pData){
    +   sqlite3_free(pData);
    + }
    + 
    ++static Fts5Data *fts5LeafRead(Fts5Index *p, i64 iRowid){
    ++  Fts5Data *pRet = fts5DataRead(p, iRowid);
    ++  if( pRet ){
    ++    if( pRet->szLeaf>pRet->nn ){
    ++      p->rc = FTS5_CORRUPT;
    ++      fts5DataRelease(pRet);
    ++      pRet = 0;
    ++    }
    ++  }
    ++  return pRet;
    ++}
    ++
    + static int fts5IndexPrepareStmt(
    +   Fts5Index *p,
    +   sqlite3_stmt **ppStmt,
    +@@ -173193,7 +194987,8 @@ static int fts5IndexPrepareStmt(
    + ){
    +   if( p->rc==SQLITE_OK ){
    +     if( zSql ){
    +-      p->rc = sqlite3_prepare_v2(p->pConfig->db, zSql, -1, ppStmt, 0);
    ++      p->rc = sqlite3_prepare_v3(p->pConfig->db, zSql, -1,
    ++                                 SQLITE_PREPARE_PERSISTENT, ppStmt, 0);
    +     }else{
    +       p->rc = SQLITE_NOMEM;
    +     }
    +@@ -173242,7 +195037,8 @@ static void fts5DataDelete(Fts5Index *p, i64 iFirst, i64 iLast){
    +     if( zSql==0 ){
    +       rc = SQLITE_NOMEM;
    +     }else{
    +-      rc = sqlite3_prepare_v2(pConfig->db, zSql, -1, &p->pDeleter, 0);
    ++      rc = sqlite3_prepare_v3(pConfig->db, zSql, -1,
    ++                              SQLITE_PREPARE_PERSISTENT, &p->pDeleter, 0);
    +       sqlite3_free(zSql);
    +     }
    +     if( rc!=SQLITE_OK ){
    +@@ -173345,28 +195141,37 @@ static int fts5StructureDecode(
    + 
    +     for(iLvl=0; rc==SQLITE_OK && iLvl<nLevel; iLvl++){
    +       Fts5StructureLevel *pLvl = &pRet->aLevel[iLvl];
    +-      int nTotal;
    ++      int nTotal = 0;
    +       int iSeg;
    + 
    +-      i += fts5GetVarint32(&pData[i], pLvl->nMerge);
    +-      i += fts5GetVarint32(&pData[i], nTotal);
    +-      assert( nTotal>=pLvl->nMerge );
    +-      pLvl->aSeg = (Fts5StructureSegment*)sqlite3Fts5MallocZero(&rc, 
    +-          nTotal * sizeof(Fts5StructureSegment)
    +-      );
    ++      if( i>=nData ){
    ++        rc = FTS5_CORRUPT;
    ++      }else{
    ++        i += fts5GetVarint32(&pData[i], pLvl->nMerge);
    ++        i += fts5GetVarint32(&pData[i], nTotal);
    ++        assert( nTotal>=pLvl->nMerge );
    ++        pLvl->aSeg = (Fts5StructureSegment*)sqlite3Fts5MallocZero(&rc, 
    ++            nTotal * sizeof(Fts5StructureSegment)
    ++        );
    ++      }
    + 
    +       if( rc==SQLITE_OK ){
    +         pLvl->nSeg = nTotal;
    +         for(iSeg=0; iSeg<nTotal; iSeg++){
    ++          if( i>=nData ){
    ++            rc = FTS5_CORRUPT;
    ++            break;
    ++          }
    +           i += fts5GetVarint32(&pData[i], pLvl->aSeg[iSeg].iSegid);
    +           i += fts5GetVarint32(&pData[i], pLvl->aSeg[iSeg].pgnoFirst);
    +           i += fts5GetVarint32(&pData[i], pLvl->aSeg[iSeg].pgnoLast);
    +         }
    +-      }else{
    +-        fts5StructureRelease(pRet);
    +-        pRet = 0;
    +       }
    +     }
    ++    if( rc!=SQLITE_OK ){
    ++      fts5StructureRelease(pRet);
    ++      pRet = 0;
    ++    }
    +   }
    + 
    +   *ppOut = pRet;
    +@@ -173429,6 +195234,50 @@ static void fts5StructureExtendLevel(
    +   }
    + }
    + 
    ++static Fts5Structure *fts5StructureReadUncached(Fts5Index *p){
    ++  Fts5Structure *pRet = 0;
    ++  Fts5Config *pConfig = p->pConfig;
    ++  int iCookie;                    /* Configuration cookie */
    ++  Fts5Data *pData;
    ++
    ++  pData = fts5DataRead(p, FTS5_STRUCTURE_ROWID);
    ++  if( p->rc==SQLITE_OK ){
    ++    /* TODO: Do we need this if the leaf-index is appended? Probably... */
    ++    memset(&pData->p[pData->nn], 0, FTS5_DATA_PADDING);
    ++    p->rc = fts5StructureDecode(pData->p, pData->nn, &iCookie, &pRet);
    ++    if( p->rc==SQLITE_OK && pConfig->iCookie!=iCookie ){
    ++      p->rc = sqlite3Fts5ConfigLoad(pConfig, iCookie);
    ++    }
    ++    fts5DataRelease(pData);
    ++    if( p->rc!=SQLITE_OK ){
    ++      fts5StructureRelease(pRet);
    ++      pRet = 0;
    ++    }
    ++  }
    ++
    ++  return pRet;
    ++}
    ++
    ++static i64 fts5IndexDataVersion(Fts5Index *p){
    ++  i64 iVersion = 0;
    ++
    ++  if( p->rc==SQLITE_OK ){
    ++    if( p->pDataVersion==0 ){
    ++      p->rc = fts5IndexPrepareStmt(p, &p->pDataVersion, 
    ++          sqlite3_mprintf("PRAGMA %Q.data_version", p->pConfig->zDb)
    ++          );
    ++      if( p->rc ) return 0;
    ++    }
    ++
    ++    if( SQLITE_ROW==sqlite3_step(p->pDataVersion) ){
    ++      iVersion = sqlite3_column_int64(p->pDataVersion, 0);
    ++    }
    ++    p->rc = sqlite3_reset(p->pDataVersion);
    ++  }
    ++
    ++  return iVersion;
    ++}
    ++
    + /*
    + ** Read, deserialize and return the structure record.
    + **
    +@@ -173441,26 +195290,49 @@ static void fts5StructureExtendLevel(
    + ** is called, it is a no-op.
    + */
    + static Fts5Structure *fts5StructureRead(Fts5Index *p){
    +-  Fts5Config *pConfig = p->pConfig;
    +-  Fts5Structure *pRet = 0;        /* Object to return */
    +-  int iCookie;                    /* Configuration cookie */
    +-  Fts5Data *pData;
    + 
    +-  pData = fts5DataRead(p, FTS5_STRUCTURE_ROWID);
    +-  if( p->rc ) return 0;
    +-  /* TODO: Do we need this if the leaf-index is appended? Probably... */
    +-  memset(&pData->p[pData->nn], 0, FTS5_DATA_PADDING);
    +-  p->rc = fts5StructureDecode(pData->p, pData->nn, &iCookie, &pRet);
    +-  if( p->rc==SQLITE_OK && pConfig->iCookie!=iCookie ){
    +-    p->rc = sqlite3Fts5ConfigLoad(pConfig, iCookie);
    ++  if( p->pStruct==0 ){
    ++    p->iStructVersion = fts5IndexDataVersion(p);
    ++    if( p->rc==SQLITE_OK ){
    ++      p->pStruct = fts5StructureReadUncached(p);
    ++    }
    +   }
    + 
    +-  fts5DataRelease(pData);
    +-  if( p->rc!=SQLITE_OK ){
    +-    fts5StructureRelease(pRet);
    +-    pRet = 0;
    ++#if 0
    ++  else{
    ++    Fts5Structure *pTest = fts5StructureReadUncached(p);
    ++    if( pTest ){
    ++      int i, j;
    ++      assert_nc( p->pStruct->nSegment==pTest->nSegment );
    ++      assert_nc( p->pStruct->nLevel==pTest->nLevel );
    ++      for(i=0; i<pTest->nLevel; i++){
    ++        assert_nc( p->pStruct->aLevel[i].nMerge==pTest->aLevel[i].nMerge );
    ++        assert_nc( p->pStruct->aLevel[i].nSeg==pTest->aLevel[i].nSeg );
    ++        for(j=0; j<pTest->aLevel[i].nSeg; j++){
    ++          Fts5StructureSegment *p1 = &pTest->aLevel[i].aSeg[j];
    ++          Fts5StructureSegment *p2 = &p->pStruct->aLevel[i].aSeg[j];
    ++          assert_nc( p1->iSegid==p2->iSegid );
    ++          assert_nc( p1->pgnoFirst==p2->pgnoFirst );
    ++          assert_nc( p1->pgnoLast==p2->pgnoLast );
    ++        }
    ++      }
    ++      fts5StructureRelease(pTest);
    ++    }
    ++  }
    ++#endif
    ++
    ++  if( p->rc!=SQLITE_OK ) return 0;
    ++  assert( p->iStructVersion!=0 );
    ++  assert( p->pStruct!=0 );
    ++  fts5StructureRef(p->pStruct);
    ++  return p->pStruct;
    ++}
    ++
    ++static void fts5StructureInvalidate(Fts5Index *p){
    ++  if( p->pStruct ){
    ++    fts5StructureRelease(p->pStruct);
    ++    p->pStruct = 0;
    +   }
    +-  return pRet;
    + }
    + 
    + /*
    +@@ -173481,6 +195353,18 @@ static int fts5StructureCountSegments(Fts5Structure *pStruct){
    + }
    + #endif
    + 
    ++#define fts5BufferSafeAppendBlob(pBuf, pBlob, nBlob) {     \
    ++  assert( (pBuf)->nSpace>=((pBuf)->n+nBlob) );             \
    ++  memcpy(&(pBuf)->p[(pBuf)->n], pBlob, nBlob);             \
    ++  (pBuf)->n += nBlob;                                      \
    ++}
    ++
    ++#define fts5BufferSafeAppendVarint(pBuf, iVal) {                \
    ++  (pBuf)->n += sqlite3Fts5PutVarint(&(pBuf)->p[(pBuf)->n], (iVal));  \
    ++  assert( (pBuf)->nSpace>=(pBuf)->n );                          \
    ++}
    ++
    ++
    + /*
    + ** Serialize and store the "structure" record.
    + **
    +@@ -173499,11 +195383,14 @@ static void fts5StructureWrite(Fts5Index *p, Fts5Structure *pStruct){
    +     /* Append the current configuration cookie */
    +     iCookie = p->pConfig->iCookie;
    +     if( iCookie<0 ) iCookie = 0;
    +-    fts5BufferAppend32(&p->rc, &buf, iCookie);
    + 
    +-    fts5BufferAppendVarint(&p->rc, &buf, pStruct->nLevel);
    +-    fts5BufferAppendVarint(&p->rc, &buf, pStruct->nSegment);
    +-    fts5BufferAppendVarint(&p->rc, &buf, (i64)pStruct->nWriteCounter);
    ++    if( 0==sqlite3Fts5BufferSize(&p->rc, &buf, 4+9+9+9) ){
    ++      sqlite3Fts5Put32(buf.p, iCookie);
    ++      buf.n = 4;
    ++      fts5BufferSafeAppendVarint(&buf, pStruct->nLevel);
    ++      fts5BufferSafeAppendVarint(&buf, pStruct->nSegment);
    ++      fts5BufferSafeAppendVarint(&buf, (i64)pStruct->nWriteCounter);
    ++    }
    + 
    +     for(iLvl=0; iLvl<pStruct->nLevel; iLvl++){
    +       int iSeg;                     /* Used to iterate through segments */
    +@@ -173903,7 +195790,7 @@ static void fts5SegIterNextPage(
    +     pIter->pLeaf = pIter->pNextLeaf;
    +     pIter->pNextLeaf = 0;
    +   }else if( pIter->iLeafPgno<=pSeg->pgnoLast ){
    +-    pIter->pLeaf = fts5DataRead(p, 
    ++    pIter->pLeaf = fts5LeafRead(p, 
    +         FTS5_SEGMENT_ROWID(pSeg->iSegid, pIter->iLeafPgno)
    +     );
    +   }else{
    +@@ -173953,11 +195840,28 @@ static int fts5GetPoslistSize(const u8 *p, int *pnSz, int *pbDel){
    + static void fts5SegIterLoadNPos(Fts5Index *p, Fts5SegIter *pIter){
    +   if( p->rc==SQLITE_OK ){
    +     int iOff = pIter->iLeafOffset;  /* Offset to read at */
    +-    int nSz;
    +     ASSERT_SZLEAF_OK(pIter->pLeaf);
    +-    fts5FastGetVarint32(pIter->pLeaf->p, iOff, nSz);
    +-    pIter->bDel = (nSz & 0x0001);
    +-    pIter->nPos = nSz>>1;
    ++    if( p->pConfig->eDetail==FTS5_DETAIL_NONE ){
    ++      int iEod = MIN(pIter->iEndofDoclist, pIter->pLeaf->szLeaf);
    ++      pIter->bDel = 0;
    ++      pIter->nPos = 1;
    ++      if( iOff<iEod && pIter->pLeaf->p[iOff]==0 ){
    ++        pIter->bDel = 1;
    ++        iOff++;
    ++        if( iOff<iEod && pIter->pLeaf->p[iOff]==0 ){
    ++          pIter->nPos = 1;
    ++          iOff++;
    ++        }else{
    ++          pIter->nPos = 0;
    ++        }
    ++      }
    ++    }else{
    ++      int nSz;
    ++      fts5FastGetVarint32(pIter->pLeaf->p, iOff, nSz);
    ++      pIter->bDel = (nSz & 0x0001);
    ++      pIter->nPos = nSz>>1;
    ++      assert_nc( pIter->nPos>=0 );
    ++    }
    +     pIter->iLeafOffset = iOff;
    +   }
    + }
    +@@ -174001,6 +195905,10 @@ static void fts5SegIterLoadTerm(Fts5Index *p, Fts5SegIter *pIter, int nKeep){
    +   int nNew;                       /* Bytes of new data */
    + 
    +   iOff += fts5GetVarint32(&a[iOff], nNew);
    ++  if( iOff+nNew>pIter->pLeaf->nn ){
    ++    p->rc = FTS5_CORRUPT;
    ++    return;
    ++  }
    +   pIter->term.n = nKeep;
    +   fts5BufferAppendBlob(&p->rc, &pIter->term, nNew, &a[iOff]);
    +   iOff += nNew;
    +@@ -174019,6 +195927,20 @@ static void fts5SegIterLoadTerm(Fts5Index *p, Fts5SegIter *pIter, int nKeep){
    +   fts5SegIterLoadRowid(p, pIter);
    + }
    + 
    ++static void fts5SegIterNext(Fts5Index*, Fts5SegIter*, int*);
    ++static void fts5SegIterNext_Reverse(Fts5Index*, Fts5SegIter*, int*);
    ++static void fts5SegIterNext_None(Fts5Index*, Fts5SegIter*, int*);
    ++
    ++static void fts5SegIterSetNext(Fts5Index *p, Fts5SegIter *pIter){
    ++  if( pIter->flags & FTS5_SEGITER_REVERSE ){
    ++    pIter->xNext = fts5SegIterNext_Reverse;
    ++  }else if( p->pConfig->eDetail==FTS5_DETAIL_NONE ){
    ++    pIter->xNext = fts5SegIterNext_None;
    ++  }else{
    ++    pIter->xNext = fts5SegIterNext;
    ++  }
    ++}
    ++
    + /*
    + ** Initialize the iterator object pIter to iterate through the entries in
    + ** segment pSeg. The iterator is left pointing to the first entry when 
    +@@ -174044,6 +195966,7 @@ static void fts5SegIterInit(
    + 
    +   if( p->rc==SQLITE_OK ){
    +     memset(pIter, 0, sizeof(*pIter));
    ++    fts5SegIterSetNext(p, pIter);
    +     pIter->pSeg = pSeg;
    +     pIter->iLeafPgno = pSeg->pgnoFirst-1;
    +     fts5SegIterNextPage(p, pIter);
    +@@ -174075,6 +195998,7 @@ static void fts5SegIterInit(
    + ** byte of the position list content associated with said rowid.
    + */
    + static void fts5SegIterReverseInitPage(Fts5Index *p, Fts5SegIter *pIter){
    ++  int eDetail = p->pConfig->eDetail;
    +   int n = pIter->pLeaf->szLeaf;
    +   int i = pIter->iLeafOffset;
    +   u8 *a = pIter->pLeaf->p;
    +@@ -174087,15 +196011,24 @@ static void fts5SegIterReverseInitPage(Fts5Index *p, Fts5SegIter *pIter){
    +   ASSERT_SZLEAF_OK(pIter->pLeaf);
    +   while( 1 ){
    +     i64 iDelta = 0;
    +-    int nPos;
    +-    int bDummy;
    + 
    +-    i += fts5GetPoslistSize(&a[i], &nPos, &bDummy);
    +-    i += nPos;
    ++    if( eDetail==FTS5_DETAIL_NONE ){
    ++      /* todo */
    ++      if( i<n && a[i]==0 ){
    ++        i++;
    ++        if( i<n && a[i]==0 ) i++;
    ++      }
    ++    }else{
    ++      int nPos;
    ++      int bDummy;
    ++      i += fts5GetPoslistSize(&a[i], &nPos, &bDummy);
    ++      i += nPos;
    ++    }
    +     if( i>=n ) break;
    +     i += fts5GetVarint(&a[i], (u64*)&iDelta);
    +     pIter->iRowid += iDelta;
    + 
    ++    /* If necessary, grow the pIter->aRowidOffset[] array. */
    +     if( iRowidOffset>=pIter->nRowidOffset ){
    +       int nNew = pIter->nRowidOffset + 8;
    +       int *aNew = (int*)sqlite3_realloc(pIter->aRowidOffset, nNew*sizeof(int));
    +@@ -174132,12 +196065,13 @@ static void fts5SegIterReverseNewPage(Fts5Index *p, Fts5SegIter *pIter){
    +     if( pNew ){
    +       /* iTermLeafOffset may be equal to szLeaf if the term is the last
    +       ** thing on the page - i.e. the first rowid is on the following page.
    +-      ** In this case leaf pIter->pLeaf==0, this iterator is at EOF. */
    +-      if( pIter->iLeafPgno==pIter->iTermLeafPgno 
    +-       && pIter->iTermLeafOffset<pNew->szLeaf 
    +-      ){
    +-        pIter->pLeaf = pNew;
    +-        pIter->iLeafOffset = pIter->iTermLeafOffset;
    ++      ** In this case leave pIter->pLeaf==0, this iterator is at EOF. */
    ++      if( pIter->iLeafPgno==pIter->iTermLeafPgno ){
    ++        assert( pIter->pLeaf==0 );
    ++        if( pIter->iTermLeafOffset<pNew->szLeaf ){
    ++          pIter->pLeaf = pNew;
    ++          pIter->iLeafOffset = pIter->iTermLeafOffset;
    ++        }
    +       }else{
    +         int iRowidOff;
    +         iRowidOff = fts5LeafFirstRowidOff(pNew);
    +@@ -174168,11 +196102,115 @@ static void fts5SegIterReverseNewPage(Fts5Index *p, Fts5SegIter *pIter){
    + ** points to a delete marker. A delete marker is an entry with a 0 byte
    + ** position-list.
    + */
    +-static int fts5MultiIterIsEmpty(Fts5Index *p, Fts5IndexIter *pIter){
    ++static int fts5MultiIterIsEmpty(Fts5Index *p, Fts5Iter *pIter){
    +   Fts5SegIter *pSeg = &pIter->aSeg[pIter->aFirst[1].iFirst];
    +   return (p->rc==SQLITE_OK && pSeg->pLeaf && pSeg->nPos==0);
    + }
    + 
    ++/*
    ++** Advance iterator pIter to the next entry.
    ++**
    ++** This version of fts5SegIterNext() is only used by reverse iterators.
    ++*/
    ++static void fts5SegIterNext_Reverse(
    ++  Fts5Index *p,                   /* FTS5 backend object */
    ++  Fts5SegIter *pIter,             /* Iterator to advance */
    ++  int *pbUnused                   /* Unused */
    ++){
    ++  assert( pIter->flags & FTS5_SEGITER_REVERSE );
    ++  assert( pIter->pNextLeaf==0 );
    ++  UNUSED_PARAM(pbUnused);
    ++
    ++  if( pIter->iRowidOffset>0 ){
    ++    u8 *a = pIter->pLeaf->p;
    ++    int iOff;
    ++    i64 iDelta;
    ++
    ++    pIter->iRowidOffset--;
    ++    pIter->iLeafOffset = pIter->aRowidOffset[pIter->iRowidOffset];
    ++    fts5SegIterLoadNPos(p, pIter);
    ++    iOff = pIter->iLeafOffset;
    ++    if( p->pConfig->eDetail!=FTS5_DETAIL_NONE ){
    ++      iOff += pIter->nPos;
    ++    }
    ++    fts5GetVarint(&a[iOff], (u64*)&iDelta);
    ++    pIter->iRowid -= iDelta;
    ++  }else{
    ++    fts5SegIterReverseNewPage(p, pIter);
    ++  }
    ++}
    ++
    ++/*
    ++** Advance iterator pIter to the next entry.
    ++**
    ++** This version of fts5SegIterNext() is only used if detail=none and the
    ++** iterator is not a reverse direction iterator.
    ++*/
    ++static void fts5SegIterNext_None(
    ++  Fts5Index *p,                   /* FTS5 backend object */
    ++  Fts5SegIter *pIter,             /* Iterator to advance */
    ++  int *pbNewTerm                  /* OUT: Set for new term */
    ++){
    ++  int iOff;
    ++
    ++  assert( p->rc==SQLITE_OK );
    ++  assert( (pIter->flags & FTS5_SEGITER_REVERSE)==0 );
    ++  assert( p->pConfig->eDetail==FTS5_DETAIL_NONE );
    ++
    ++  ASSERT_SZLEAF_OK(pIter->pLeaf);
    ++  iOff = pIter->iLeafOffset;
    ++
    ++  /* Next entry is on the next page */
    ++  if( pIter->pSeg && iOff>=pIter->pLeaf->szLeaf ){
    ++    fts5SegIterNextPage(p, pIter);
    ++    if( p->rc || pIter->pLeaf==0 ) return;
    ++    pIter->iRowid = 0;
    ++    iOff = 4;
    ++  }
    ++
    ++  if( iOff<pIter->iEndofDoclist ){
    ++    /* Next entry is on the current page */
    ++    i64 iDelta;
    ++    iOff += sqlite3Fts5GetVarint(&pIter->pLeaf->p[iOff], (u64*)&iDelta);
    ++    pIter->iLeafOffset = iOff;
    ++    pIter->iRowid += iDelta;
    ++  }else if( (pIter->flags & FTS5_SEGITER_ONETERM)==0 ){
    ++    if( pIter->pSeg ){
    ++      int nKeep = 0;
    ++      if( iOff!=fts5LeafFirstTermOff(pIter->pLeaf) ){
    ++        iOff += fts5GetVarint32(&pIter->pLeaf->p[iOff], nKeep);
    ++      }
    ++      pIter->iLeafOffset = iOff;
    ++      fts5SegIterLoadTerm(p, pIter, nKeep);
    ++    }else{
    ++      const u8 *pList = 0;
    ++      const char *zTerm = 0;
    ++      int nList;
    ++      sqlite3Fts5HashScanNext(p->pHash);
    ++      sqlite3Fts5HashScanEntry(p->pHash, &zTerm, &pList, &nList);
    ++      if( pList==0 ) goto next_none_eof;
    ++      pIter->pLeaf->p = (u8*)pList;
    ++      pIter->pLeaf->nn = nList;
    ++      pIter->pLeaf->szLeaf = nList;
    ++      pIter->iEndofDoclist = nList;
    ++      sqlite3Fts5BufferSet(&p->rc,&pIter->term, (int)strlen(zTerm), (u8*)zTerm);
    ++      pIter->iLeafOffset = fts5GetVarint(pList, (u64*)&pIter->iRowid);
    ++    }
    ++
    ++    if( pbNewTerm ) *pbNewTerm = 1;
    ++  }else{
    ++    goto next_none_eof;
    ++  }
    ++
    ++  fts5SegIterLoadNPos(p, pIter);
    ++
    ++  return;
    ++ next_none_eof:
    ++  fts5DataRelease(pIter->pLeaf);
    ++  pIter->pLeaf = 0;
    ++}
    ++
    ++
    + /*
    + ** Advance iterator pIter to the next entry. 
    + **
    +@@ -174185,131 +196223,132 @@ static void fts5SegIterNext(
    +   Fts5SegIter *pIter,             /* Iterator to advance */
    +   int *pbNewTerm                  /* OUT: Set for new term */
    + ){
    ++  Fts5Data *pLeaf = pIter->pLeaf;
    ++  int iOff;
    ++  int bNewTerm = 0;
    ++  int nKeep = 0;
    ++  u8 *a;
    ++  int n;
    ++
    +   assert( pbNewTerm==0 || *pbNewTerm==0 );
    +-  if( p->rc==SQLITE_OK ){
    +-    if( pIter->flags & FTS5_SEGITER_REVERSE ){
    +-      assert( pIter->pNextLeaf==0 );
    +-      if( pIter->iRowidOffset>0 ){
    +-        u8 *a = pIter->pLeaf->p;
    +-        int iOff;
    +-        int nPos;
    +-        int bDummy;
    +-        i64 iDelta;
    +-
    +-        pIter->iRowidOffset--;
    +-        pIter->iLeafOffset = iOff = pIter->aRowidOffset[pIter->iRowidOffset];
    +-        iOff += fts5GetPoslistSize(&a[iOff], &nPos, &bDummy);
    +-        iOff += nPos;
    +-        fts5GetVarint(&a[iOff], (u64*)&iDelta);
    +-        pIter->iRowid -= iDelta;
    +-        fts5SegIterLoadNPos(p, pIter);
    +-      }else{
    +-        fts5SegIterReverseNewPage(p, pIter);
    ++  assert( p->pConfig->eDetail!=FTS5_DETAIL_NONE );
    ++
    ++  /* Search for the end of the position list within the current page. */
    ++  a = pLeaf->p;
    ++  n = pLeaf->szLeaf;
    ++
    ++  ASSERT_SZLEAF_OK(pLeaf);
    ++  iOff = pIter->iLeafOffset + pIter->nPos;
    ++
    ++  if( iOff<n ){
    ++    /* The next entry is on the current page. */
    ++    assert_nc( iOff<=pIter->iEndofDoclist );
    ++    if( iOff>=pIter->iEndofDoclist ){
    ++      bNewTerm = 1;
    ++      if( iOff!=fts5LeafFirstTermOff(pLeaf) ){
    ++        iOff += fts5GetVarint32(&a[iOff], nKeep);
    +       }
    +     }else{
    +-      Fts5Data *pLeaf = pIter->pLeaf;
    +-      int iOff;
    +-      int bNewTerm = 0;
    +-      int nKeep = 0;
    +-
    +-      /* Search for the end of the position list within the current page. */
    +-      u8 *a = pLeaf->p;
    +-      int n = pLeaf->szLeaf;
    ++      u64 iDelta;
    ++      iOff += sqlite3Fts5GetVarint(&a[iOff], &iDelta);
    ++      pIter->iRowid += iDelta;
    ++      assert_nc( iDelta>0 );
    ++    }
    ++    pIter->iLeafOffset = iOff;
    + 
    ++  }else if( pIter->pSeg==0 ){
    ++    const u8 *pList = 0;
    ++    const char *zTerm = 0;
    ++    int nList = 0;
    ++    assert( (pIter->flags & FTS5_SEGITER_ONETERM) || pbNewTerm );
    ++    if( 0==(pIter->flags & FTS5_SEGITER_ONETERM) ){
    ++      sqlite3Fts5HashScanNext(p->pHash);
    ++      sqlite3Fts5HashScanEntry(p->pHash, &zTerm, &pList, &nList);
    ++    }
    ++    if( pList==0 ){
    ++      fts5DataRelease(pIter->pLeaf);
    ++      pIter->pLeaf = 0;
    ++    }else{
    ++      pIter->pLeaf->p = (u8*)pList;
    ++      pIter->pLeaf->nn = nList;
    ++      pIter->pLeaf->szLeaf = nList;
    ++      pIter->iEndofDoclist = nList+1;
    ++      sqlite3Fts5BufferSet(&p->rc, &pIter->term, (int)strlen(zTerm),
    ++          (u8*)zTerm);
    ++      pIter->iLeafOffset = fts5GetVarint(pList, (u64*)&pIter->iRowid);
    ++      *pbNewTerm = 1;
    ++    }
    ++  }else{
    ++    iOff = 0;
    ++    /* Next entry is not on the current page */
    ++    while( iOff==0 ){
    ++      fts5SegIterNextPage(p, pIter);
    ++      pLeaf = pIter->pLeaf;
    ++      if( pLeaf==0 ) break;
    +       ASSERT_SZLEAF_OK(pLeaf);
    +-      iOff = pIter->iLeafOffset + pIter->nPos;
    +-
    +-      if( iOff<n ){
    +-        /* The next entry is on the current page. */
    +-        assert_nc( iOff<=pIter->iEndofDoclist );
    +-        if( iOff>=pIter->iEndofDoclist ){
    +-          bNewTerm = 1;
    +-          if( iOff!=fts5LeafFirstTermOff(pLeaf) ){
    +-            iOff += fts5GetVarint32(&a[iOff], nKeep);
    +-          }
    +-        }else{
    +-          u64 iDelta;
    +-          iOff += sqlite3Fts5GetVarint(&a[iOff], &iDelta);
    +-          pIter->iRowid += iDelta;
    +-          assert_nc( iDelta>0 );
    +-        }
    ++      if( (iOff = fts5LeafFirstRowidOff(pLeaf)) && iOff<pLeaf->szLeaf ){
    ++        iOff += sqlite3Fts5GetVarint(&pLeaf->p[iOff], (u64*)&pIter->iRowid);
    +         pIter->iLeafOffset = iOff;
    + 
    +-      }else if( pIter->pSeg==0 ){
    +-        const u8 *pList = 0;
    +-        const char *zTerm = 0;
    +-        int nList = 0;
    +-        if( 0==(pIter->flags & FTS5_SEGITER_ONETERM) ){
    +-          sqlite3Fts5HashScanNext(p->pHash);
    +-          sqlite3Fts5HashScanEntry(p->pHash, &zTerm, &pList, &nList);
    +-        }
    +-        if( pList==0 ){
    +-          fts5DataRelease(pIter->pLeaf);
    +-          pIter->pLeaf = 0;
    +-        }else{
    +-          pIter->pLeaf->p = (u8*)pList;
    +-          pIter->pLeaf->nn = nList;
    +-          pIter->pLeaf->szLeaf = nList;
    +-          pIter->iEndofDoclist = nList+1;
    +-          sqlite3Fts5BufferSet(&p->rc, &pIter->term, strlen(zTerm), (u8*)zTerm);
    +-          pIter->iLeafOffset = fts5GetVarint(pList, (u64*)&pIter->iRowid);
    +-          if( pbNewTerm ) *pbNewTerm = 1;
    +-        }
    +-      }else{
    +-        iOff = 0;
    +-        /* Next entry is not on the current page */
    +-        while( iOff==0 ){
    +-          fts5SegIterNextPage(p, pIter);
    +-          pLeaf = pIter->pLeaf;
    +-          if( pLeaf==0 ) break;
    +-          ASSERT_SZLEAF_OK(pLeaf);
    +-          if( (iOff = fts5LeafFirstRowidOff(pLeaf)) && iOff<pLeaf->szLeaf ){
    +-            iOff += sqlite3Fts5GetVarint(&pLeaf->p[iOff], (u64*)&pIter->iRowid);
    +-            pIter->iLeafOffset = iOff;
    +-
    +-            if( pLeaf->nn>pLeaf->szLeaf ){
    +-              pIter->iPgidxOff = pLeaf->szLeaf + fts5GetVarint32(
    +-                  &pLeaf->p[pLeaf->szLeaf], pIter->iEndofDoclist
    +-              );
    +-            }
    +-
    +-          }
    +-          else if( pLeaf->nn>pLeaf->szLeaf ){
    +-            pIter->iPgidxOff = pLeaf->szLeaf + fts5GetVarint32(
    +-                &pLeaf->p[pLeaf->szLeaf], iOff
    +-            );
    +-            pIter->iLeafOffset = iOff;
    +-            pIter->iEndofDoclist = iOff;
    +-            bNewTerm = 1;
    +-          }
    +-          if( iOff>=pLeaf->szLeaf ){
    +-            p->rc = FTS5_CORRUPT;
    +-            return;
    +-          }
    ++        if( pLeaf->nn>pLeaf->szLeaf ){
    ++          pIter->iPgidxOff = pLeaf->szLeaf + fts5GetVarint32(
    ++              &pLeaf->p[pLeaf->szLeaf], pIter->iEndofDoclist
    ++          );
    +         }
    +       }
    ++      else if( pLeaf->nn>pLeaf->szLeaf ){
    ++        pIter->iPgidxOff = pLeaf->szLeaf + fts5GetVarint32(
    ++            &pLeaf->p[pLeaf->szLeaf], iOff
    ++        );
    ++        pIter->iLeafOffset = iOff;
    ++        pIter->iEndofDoclist = iOff;
    ++        bNewTerm = 1;
    ++      }
    ++      assert_nc( iOff<pLeaf->szLeaf );
    ++      if( iOff>pLeaf->szLeaf ){
    ++        p->rc = FTS5_CORRUPT;
    ++        return;
    ++      }
    ++    }
    ++  }
    + 
    +-      /* Check if the iterator is now at EOF. If so, return early. */
    +-      if( pIter->pLeaf ){
    +-        if( bNewTerm ){
    +-          if( pIter->flags & FTS5_SEGITER_ONETERM ){
    +-            fts5DataRelease(pIter->pLeaf);
    +-            pIter->pLeaf = 0;
    +-          }else{
    +-            fts5SegIterLoadTerm(p, pIter, nKeep);
    +-            fts5SegIterLoadNPos(p, pIter);
    +-            if( pbNewTerm ) *pbNewTerm = 1;
    +-          }
    +-        }else{
    +-          fts5SegIterLoadNPos(p, pIter);
    +-        }
    ++  /* Check if the iterator is now at EOF. If so, return early. */
    ++  if( pIter->pLeaf ){
    ++    if( bNewTerm ){
    ++      if( pIter->flags & FTS5_SEGITER_ONETERM ){
    ++        fts5DataRelease(pIter->pLeaf);
    ++        pIter->pLeaf = 0;
    ++      }else{
    ++        fts5SegIterLoadTerm(p, pIter, nKeep);
    ++        fts5SegIterLoadNPos(p, pIter);
    ++        if( pbNewTerm ) *pbNewTerm = 1;
    +       }
    ++    }else{
    ++      /* The following could be done by calling fts5SegIterLoadNPos(). But
    ++      ** this block is particularly performance critical, so equivalent
    ++      ** code is inlined. 
    ++      **
    ++      ** Later: Switched back to fts5SegIterLoadNPos() because it supports
    ++      ** detail=none mode. Not ideal.
    ++      */
    ++      int nSz;
    ++      assert( p->rc==SQLITE_OK );
    ++      assert( pIter->iLeafOffset<=pIter->pLeaf->nn );
    ++      fts5FastGetVarint32(pIter->pLeaf->p, pIter->iLeafOffset, nSz);
    ++      pIter->bDel = (nSz & 0x0001);
    ++      pIter->nPos = nSz>>1;
    ++      assert_nc( pIter->nPos>=0 );
    +     }
    +   }
    + }
    + 
    + #define SWAPVAL(T, a, b) { T tmp; tmp=a; a=b; b=tmp; }
    + 
    ++#define fts5IndexSkipVarint(a, iOff) {            \
    ++  int iEnd = iOff+9;                              \
    ++  while( (a[iOff++] & 0x80) && iOff<iEnd );       \
    ++}
    ++
    + /*
    + ** Iterator pIter currently points to the first rowid in a doclist. This
    + ** function sets the iterator up so that iterates in reverse order through
    +@@ -174330,7 +196369,14 @@ static void fts5SegIterReverse(Fts5Index *p, Fts5SegIter *pIter){
    +     /* Currently, Fts5SegIter.iLeafOffset points to the first byte of
    +     ** position-list content for the current rowid. Back it up so that it
    +     ** points to the start of the position-list size field. */
    +-    pIter->iLeafOffset -= sqlite3Fts5GetVarintLen(pIter->nPos*2+pIter->bDel);
    ++    int iPoslist;
    ++    if( pIter->iTermLeafPgno==pIter->iLeafPgno ){
    ++      iPoslist = pIter->iTermLeafOffset;
    ++    }else{
    ++      iPoslist = 4;
    ++    }
    ++    fts5IndexSkipVarint(pLeaf->p, iPoslist);
    ++    pIter->iLeafOffset = iPoslist;
    + 
    +     /* If this condition is true then the largest rowid for the current
    +     ** term may not be stored on the current page. So search forward to
    +@@ -174414,11 +196460,6 @@ static void fts5SegIterLoadDlidx(Fts5Index *p, Fts5SegIter *pIter){
    +   pIter->pDlidx = fts5DlidxIterInit(p, bRev, iSeg, pIter->iTermLeafPgno);
    + }
    + 
    +-#define fts5IndexSkipVarint(a, iOff) {            \
    +-  int iEnd = iOff+9;                              \
    +-  while( (a[iOff++] & 0x80) && iOff<iEnd );       \
    +-}
    +-
    + /*
    + ** The iterator object passed as the second argument currently contains
    + ** no valid values except for the Fts5SegIter.pLeaf member variable. This
    +@@ -174456,6 +196497,10 @@ static void fts5LeafSeek(
    +   iPgidx = szLeaf;
    +   iPgidx += fts5GetVarint32(&a[iPgidx], iTermOff);
    +   iOff = iTermOff;
    ++  if( iOff>n ){
    ++    p->rc = FTS5_CORRUPT;
    ++    return;
    ++  }
    + 
    +   while( 1 ){
    + 
    +@@ -174495,6 +196540,11 @@ static void fts5LeafSeek(
    +     iTermOff += nKeep;
    +     iOff = iTermOff;
    + 
    ++    if( iOff>=n ){
    ++      p->rc = FTS5_CORRUPT;
    ++      return;
    ++    }
    ++
    +     /* Read the nKeep field of the next term. */
    +     fts5FastGetVarint32(a, iOff, nKeep);
    +   }
    +@@ -174510,11 +196560,14 @@ static void fts5LeafSeek(
    +       if( pIter->pLeaf==0 ) return;
    +       a = pIter->pLeaf->p;
    +       if( fts5LeafIsTermless(pIter->pLeaf)==0 ){
    +-        fts5GetVarint32(&pIter->pLeaf->p[pIter->pLeaf->szLeaf], iOff);
    ++        iPgidx = pIter->pLeaf->szLeaf;
    ++        iPgidx += fts5GetVarint32(&pIter->pLeaf->p[iPgidx], iOff);
    +         if( iOff<4 || iOff>=pIter->pLeaf->szLeaf ){
    +           p->rc = FTS5_CORRUPT;
    +         }else{
    +           nKeep = 0;
    ++          iTermOff = iOff;
    ++          n = pIter->pLeaf->nn;
    +           iOff += fts5GetVarint32(&a[iOff], nNew);
    +           break;
    +         }
    +@@ -174544,6 +196597,18 @@ static void fts5LeafSeek(
    +   fts5SegIterLoadNPos(p, pIter);
    + }
    + 
    ++static sqlite3_stmt *fts5IdxSelectStmt(Fts5Index *p){
    ++  if( p->pIdxSelect==0 ){
    ++    Fts5Config *pConfig = p->pConfig;
    ++    fts5IndexPrepareStmt(p, &p->pIdxSelect, sqlite3_mprintf(
    ++          "SELECT pgno FROM '%q'.'%q_idx' WHERE "
    ++          "segid=? AND term<=? ORDER BY term DESC LIMIT 1",
    ++          pConfig->zDb, pConfig->zName
    ++    ));
    ++  }
    ++  return p->pIdxSelect;
    ++}
    ++
    + /*
    + ** Initialize the object pIter to point to term pTerm/nTerm within segment
    + ** pSeg. If there is no such term in the index, the iterator is set to EOF.
    +@@ -174553,7 +196618,6 @@ static void fts5LeafSeek(
    + */
    + static void fts5SegIterSeekInit(
    +   Fts5Index *p,                   /* FTS5 backend */
    +-  Fts5Buffer *pBuf,               /* Buffer to use for loading pages */
    +   const u8 *pTerm, int nTerm,     /* Term to seek to */
    +   int flags,                      /* Mask of FTS5INDEX_XXX flags */
    +   Fts5StructureSegment *pSeg,     /* Description of segment */
    +@@ -174562,9 +196626,7 @@ static void fts5SegIterSeekInit(
    +   int iPg = 1;
    +   int bGe = (flags & FTS5INDEX_QUERY_SCAN);
    +   int bDlidx = 0;                 /* True if there is a doclist-index */
    +-
    +-  static int nCall = 0;
    +-  nCall++;
    ++  sqlite3_stmt *pIdxSelect = 0;
    + 
    +   assert( bGe==0 || (flags & FTS5INDEX_QUERY_DESC)==0 );
    +   assert( pTerm && nTerm );
    +@@ -174573,23 +196635,16 @@ static void fts5SegIterSeekInit(
    + 
    +   /* This block sets stack variable iPg to the leaf page number that may
    +   ** contain term (pTerm/nTerm), if it is present in the segment. */
    +-  if( p->pIdxSelect==0 ){
    +-    Fts5Config *pConfig = p->pConfig;
    +-    fts5IndexPrepareStmt(p, &p->pIdxSelect, sqlite3_mprintf(
    +-          "SELECT pgno FROM '%q'.'%q_idx' WHERE "
    +-          "segid=? AND term<=? ORDER BY term DESC LIMIT 1",
    +-          pConfig->zDb, pConfig->zName
    +-    ));
    +-  }
    ++  pIdxSelect = fts5IdxSelectStmt(p);
    +   if( p->rc ) return;
    +-  sqlite3_bind_int(p->pIdxSelect, 1, pSeg->iSegid);
    +-  sqlite3_bind_blob(p->pIdxSelect, 2, pTerm, nTerm, SQLITE_STATIC);
    +-  if( SQLITE_ROW==sqlite3_step(p->pIdxSelect) ){
    +-    i64 val = sqlite3_column_int(p->pIdxSelect, 0);
    ++  sqlite3_bind_int(pIdxSelect, 1, pSeg->iSegid);
    ++  sqlite3_bind_blob(pIdxSelect, 2, pTerm, nTerm, SQLITE_STATIC);
    ++  if( SQLITE_ROW==sqlite3_step(pIdxSelect) ){
    ++    i64 val = sqlite3_column_int(pIdxSelect, 0);
    +     iPg = (int)(val>>1);
    +     bDlidx = (val & 0x0001);
    +   }
    +-  p->rc = sqlite3_reset(p->pIdxSelect);
    ++  p->rc = sqlite3_reset(pIdxSelect);
    + 
    +   if( iPg<pSeg->pgnoFirst ){
    +     iPg = pSeg->pgnoFirst;
    +@@ -174618,6 +196673,8 @@ static void fts5SegIterSeekInit(
    +     }
    +   }
    + 
    ++  fts5SegIterSetNext(p, pIter);
    ++
    +   /* Either:
    +   **
    +   **   1) an error has occurred, or
    +@@ -174658,7 +196715,7 @@ static void fts5SegIterHashInit(
    +   if( pTerm==0 || (flags & FTS5INDEX_QUERY_SCAN) ){
    +     p->rc = sqlite3Fts5HashScanInit(p->pHash, (const char*)pTerm, nTerm);
    +     sqlite3Fts5HashScanEntry(p->pHash, (const char**)&z, &pList, &nList);
    +-    n = (z ? strlen((const char*)z) : 0);
    ++    n = (z ? (int)strlen((const char*)z) : 0);
    +   }else{
    +     pIter->flags |= FTS5_SEGITER_ONETERM;
    +     sqlite3Fts5HashQuery(p->pHash, (const char*)pTerm, nTerm, &pList, &nList);
    +@@ -174675,7 +196732,7 @@ static void fts5SegIterHashInit(
    +     pLeaf->nn = pLeaf->szLeaf = nList;
    +     pIter->pLeaf = pLeaf;
    +     pIter->iLeafOffset = fts5GetVarint(pLeaf->p, (u64*)&pIter->iRowid);
    +-    pIter->iEndofDoclist = pLeaf->nn+1;
    ++    pIter->iEndofDoclist = pLeaf->nn;
    + 
    +     if( flags & FTS5INDEX_QUERY_DESC ){
    +       pIter->flags |= FTS5_SEGITER_REVERSE;
    +@@ -174684,6 +196741,8 @@ static void fts5SegIterHashInit(
    +       fts5SegIterLoadNPos(p, pIter);
    +     }
    +   }
    ++
    ++  fts5SegIterSetNext(p, pIter);
    + }
    + 
    + /*
    +@@ -174707,7 +196766,7 @@ static void fts5SegIterClear(Fts5SegIter *pIter){
    + ** two iterators.
    + */
    + static void fts5AssertComparisonResult(
    +-  Fts5IndexIter *pIter, 
    ++  Fts5Iter *pIter, 
    +   Fts5SegIter *p1,
    +   Fts5SegIter *p2,
    +   Fts5CResult *pRes
    +@@ -174748,12 +196807,12 @@ static void fts5AssertComparisonResult(
    + ** statement used to verify that the contents of the pIter->aFirst[] array
    + ** are correct.
    + */
    +-static void fts5AssertMultiIterSetup(Fts5Index *p, Fts5IndexIter *pIter){
    ++static void fts5AssertMultiIterSetup(Fts5Index *p, Fts5Iter *pIter){
    +   if( p->rc==SQLITE_OK ){
    +     Fts5SegIter *pFirst = &pIter->aSeg[ pIter->aFirst[1].iFirst ];
    +     int i;
    + 
    +-    assert( (pFirst->pLeaf==0)==pIter->bEof );
    ++    assert( (pFirst->pLeaf==0)==pIter->base.bEof );
    + 
    +     /* Check that pIter->iSwitchRowid is set correctly. */
    +     for(i=0; i<pIter->nSeg; i++){
    +@@ -174793,7 +196852,7 @@ static void fts5AssertMultiIterSetup(Fts5Index *p, Fts5IndexIter *pIter){
    + ** to a key that is a duplicate of another, higher priority, 
    + ** segment-iterator in the pSeg->aSeg[] array.
    + */
    +-static int fts5MultiIterDoCompare(Fts5IndexIter *pIter, int iOut){
    ++static int fts5MultiIterDoCompare(Fts5Iter *pIter, int iOut){
    +   int i1;                         /* Index of left-hand Fts5SegIter */
    +   int i2;                         /* Index of right-hand Fts5SegIter */
    +   int iRes;
    +@@ -174839,7 +196898,7 @@ static int fts5MultiIterDoCompare(Fts5IndexIter *pIter, int iOut){
    +     }
    +   }
    + 
    +-  pRes->iFirst = iRes;
    ++  pRes->iFirst = (u16)iRes;
    +   return 0;
    + }
    + 
    +@@ -174927,7 +196986,7 @@ static void fts5SegIterNextFrom(
    +   }
    + 
    +   do{
    +-    if( bMove ) fts5SegIterNext(p, pIter, 0);
    ++    if( bMove && p->rc==SQLITE_OK ) pIter->xNext(p, pIter, 0);
    +     if( pIter->pLeaf==0 ) break;
    +     if( bRev==0 && pIter->iRowid>=iMatch ) break;
    +     if( bRev!=0 && pIter->iRowid<=iMatch ) break;
    +@@ -174939,7 +196998,7 @@ static void fts5SegIterNextFrom(
    + /*
    + ** Free the iterator object passed as the second argument.
    + */
    +-static void fts5MultiIterFree(Fts5Index *p, Fts5IndexIter *pIter){
    ++static void fts5MultiIterFree(Fts5Iter *pIter){
    +   if( pIter ){
    +     int i;
    +     for(i=0; i<pIter->nSeg; i++){
    +@@ -174953,7 +197012,7 @@ static void fts5MultiIterFree(Fts5Index *p, Fts5IndexIter *pIter){
    + 
    + static void fts5MultiIterAdvanced(
    +   Fts5Index *p,                   /* FTS5 backend to iterate within */
    +-  Fts5IndexIter *pIter,           /* Iterator to update aFirst[] array for */
    ++  Fts5Iter *pIter,                /* Iterator to update aFirst[] array for */
    +   int iChanged,                   /* Index of sub-iterator just advanced */
    +   int iMinset                     /* Minimum entry in aFirst[] to set */
    + ){
    +@@ -174961,7 +197020,9 @@ static void fts5MultiIterAdvanced(
    +   for(i=(pIter->nSeg+iChanged)/2; i>=iMinset && p->rc==SQLITE_OK; i=i/2){
    +     int iEq;
    +     if( (iEq = fts5MultiIterDoCompare(pIter, i)) ){
    +-      fts5SegIterNext(p, &pIter->aSeg[iEq], 0);
    ++      Fts5SegIter *pSeg = &pIter->aSeg[iEq];
    ++      assert( p->rc==SQLITE_OK );
    ++      pSeg->xNext(p, pSeg, 0);
    +       i = pIter->nSeg + iEq;
    +     }
    +   }
    +@@ -174978,9 +197039,9 @@ static void fts5MultiIterAdvanced(
    + ** that it deals with more complicated cases as well.
    + */ 
    + static int fts5MultiIterAdvanceRowid(
    +-  Fts5Index *p,                   /* FTS5 backend to iterate within */
    +-  Fts5IndexIter *pIter,           /* Iterator to update aFirst[] array for */
    +-  int iChanged                    /* Index of sub-iterator just advanced */
    ++  Fts5Iter *pIter,                /* Iterator to update aFirst[] array for */
    ++  int iChanged,                   /* Index of sub-iterator just advanced */
    ++  Fts5SegIter **ppFirst
    + ){
    +   Fts5SegIter *pNew = &pIter->aSeg[iChanged];
    + 
    +@@ -175006,22 +197067,23 @@ static int fts5MultiIterAdvanceRowid(
    +           pIter->iSwitchRowid = pOther->iRowid;
    +         }
    +       }
    +-      pRes->iFirst = (pNew - pIter->aSeg);
    ++      pRes->iFirst = (u16)(pNew - pIter->aSeg);
    +       if( i==1 ) break;
    + 
    +       pOther = &pIter->aSeg[ pIter->aFirst[i ^ 0x0001].iFirst ];
    +     }
    +   }
    + 
    ++  *ppFirst = pNew;
    +   return 0;
    + }
    + 
    + /*
    + ** Set the pIter->bEof variable based on the state of the sub-iterators.
    + */
    +-static void fts5MultiIterSetEof(Fts5IndexIter *pIter){
    ++static void fts5MultiIterSetEof(Fts5Iter *pIter){
    +   Fts5SegIter *pSeg = &pIter->aSeg[ pIter->aFirst[1].iFirst ];
    +-  pIter->bEof = pSeg->pLeaf==0;
    ++  pIter->base.bEof = pSeg->pLeaf==0;
    +   pIter->iSwitchRowid = pSeg->iRowid;
    + }
    + 
    +@@ -175034,46 +197096,84 @@ static void fts5MultiIterSetEof(Fts5IndexIter *pIter){
    + */
    + static void fts5MultiIterNext(
    +   Fts5Index *p, 
    +-  Fts5IndexIter *pIter,
    ++  Fts5Iter *pIter,
    +   int bFrom,                      /* True if argument iFrom is valid */
    +   i64 iFrom                       /* Advance at least as far as this */
    + ){
    ++  int bUseFrom = bFrom;
    ++  assert( pIter->base.bEof==0 );
    ++  while( p->rc==SQLITE_OK ){
    ++    int iFirst = pIter->aFirst[1].iFirst;
    ++    int bNewTerm = 0;
    ++    Fts5SegIter *pSeg = &pIter->aSeg[iFirst];
    ++    assert( p->rc==SQLITE_OK );
    ++    if( bUseFrom && pSeg->pDlidx ){
    ++      fts5SegIterNextFrom(p, pSeg, iFrom);
    ++    }else{
    ++      pSeg->xNext(p, pSeg, &bNewTerm);
    ++    }
    ++
    ++    if( pSeg->pLeaf==0 || bNewTerm 
    ++     || fts5MultiIterAdvanceRowid(pIter, iFirst, &pSeg)
    ++    ){
    ++      fts5MultiIterAdvanced(p, pIter, iFirst, 1);
    ++      fts5MultiIterSetEof(pIter);
    ++      pSeg = &pIter->aSeg[pIter->aFirst[1].iFirst];
    ++      if( pSeg->pLeaf==0 ) return;
    ++    }
    ++
    ++    fts5AssertMultiIterSetup(p, pIter);
    ++    assert( pSeg==&pIter->aSeg[pIter->aFirst[1].iFirst] && pSeg->pLeaf );
    ++    if( pIter->bSkipEmpty==0 || pSeg->nPos ){
    ++      pIter->xSetOutputs(pIter, pSeg);
    ++      return;
    ++    }
    ++    bUseFrom = 0;
    ++  }
    ++}
    ++
    ++static void fts5MultiIterNext2(
    ++  Fts5Index *p, 
    ++  Fts5Iter *pIter,
    ++  int *pbNewTerm                  /* OUT: True if *might* be new term */
    ++){
    ++  assert( pIter->bSkipEmpty );
    +   if( p->rc==SQLITE_OK ){
    +-    int bUseFrom = bFrom;
    +-    do {
    ++    *pbNewTerm = 0;
    ++    do{
    +       int iFirst = pIter->aFirst[1].iFirst;
    +-      int bNewTerm = 0;
    +       Fts5SegIter *pSeg = &pIter->aSeg[iFirst];
    +-      assert( p->rc==SQLITE_OK );
    +-      if( bUseFrom && pSeg->pDlidx ){
    +-        fts5SegIterNextFrom(p, pSeg, iFrom);
    +-      }else{
    +-        fts5SegIterNext(p, pSeg, &bNewTerm);
    +-      }
    ++      int bNewTerm = 0;
    + 
    ++      assert( p->rc==SQLITE_OK );
    ++      pSeg->xNext(p, pSeg, &bNewTerm);
    +       if( pSeg->pLeaf==0 || bNewTerm 
    +-       || fts5MultiIterAdvanceRowid(p, pIter, iFirst)
    ++       || fts5MultiIterAdvanceRowid(pIter, iFirst, &pSeg)
    +       ){
    +         fts5MultiIterAdvanced(p, pIter, iFirst, 1);
    +         fts5MultiIterSetEof(pIter);
    ++        *pbNewTerm = 1;
    +       }
    +       fts5AssertMultiIterSetup(p, pIter);
    + 
    +-      bUseFrom = 0;
    +-    }while( pIter->bSkipEmpty && fts5MultiIterIsEmpty(p, pIter) );
    ++    }while( fts5MultiIterIsEmpty(p, pIter) );
    +   }
    + }
    + 
    +-static Fts5IndexIter *fts5MultiIterAlloc(
    ++static void fts5IterSetOutputs_Noop(Fts5Iter *pUnused1, Fts5SegIter *pUnused2){
    ++  UNUSED_PARAM2(pUnused1, pUnused2);
    ++}
    ++
    ++static Fts5Iter *fts5MultiIterAlloc(
    +   Fts5Index *p,                   /* FTS5 backend to iterate within */
    +   int nSeg
    + ){
    +-  Fts5IndexIter *pNew;
    ++  Fts5Iter *pNew;
    +   int nSlot;                      /* Power of two >= nSeg */
    + 
    +   for(nSlot=2; nSlot<nSeg; nSlot=nSlot*2);
    +   pNew = fts5IdxMalloc(p, 
    +-      sizeof(Fts5IndexIter) +             /* pNew */
    ++      sizeof(Fts5Iter) +                  /* pNew */
    +       sizeof(Fts5SegIter) * (nSlot-1) +   /* pNew->aSeg[] */
    +       sizeof(Fts5CResult) * nSlot         /* pNew->aFirst[] */
    +   );
    +@@ -175081,12 +197181,434 @@ static Fts5IndexIter *fts5MultiIterAlloc(
    +     pNew->nSeg = nSlot;
    +     pNew->aFirst = (Fts5CResult*)&pNew->aSeg[nSlot];
    +     pNew->pIndex = p;
    ++    pNew->xSetOutputs = fts5IterSetOutputs_Noop;
    +   }
    +   return pNew;
    + }
    + 
    ++static void fts5PoslistCallback(
    ++  Fts5Index *pUnused, 
    ++  void *pContext, 
    ++  const u8 *pChunk, int nChunk
    ++){
    ++  UNUSED_PARAM(pUnused);
    ++  assert_nc( nChunk>=0 );
    ++  if( nChunk>0 ){
    ++    fts5BufferSafeAppendBlob((Fts5Buffer*)pContext, pChunk, nChunk);
    ++  }
    ++}
    ++
    ++typedef struct PoslistCallbackCtx PoslistCallbackCtx;
    ++struct PoslistCallbackCtx {
    ++  Fts5Buffer *pBuf;               /* Append to this buffer */
    ++  Fts5Colset *pColset;            /* Restrict matches to this column */
    ++  int eState;                     /* See above */
    ++};
    ++
    ++typedef struct PoslistOffsetsCtx PoslistOffsetsCtx;
    ++struct PoslistOffsetsCtx {
    ++  Fts5Buffer *pBuf;               /* Append to this buffer */
    ++  Fts5Colset *pColset;            /* Restrict matches to this column */
    ++  int iRead;
    ++  int iWrite;
    ++};
    ++
    + /*
    +-** Allocate a new Fts5IndexIter object.
    ++** TODO: Make this more efficient!
    ++*/
    ++static int fts5IndexColsetTest(Fts5Colset *pColset, int iCol){
    ++  int i;
    ++  for(i=0; i<pColset->nCol; i++){
    ++    if( pColset->aiCol[i]==iCol ) return 1;
    ++  }
    ++  return 0;
    ++}
    ++
    ++static void fts5PoslistOffsetsCallback(
    ++  Fts5Index *pUnused, 
    ++  void *pContext, 
    ++  const u8 *pChunk, int nChunk
    ++){
    ++  PoslistOffsetsCtx *pCtx = (PoslistOffsetsCtx*)pContext;
    ++  UNUSED_PARAM(pUnused);
    ++  assert_nc( nChunk>=0 );
    ++  if( nChunk>0 ){
    ++    int i = 0;
    ++    while( i<nChunk ){
    ++      int iVal;
    ++      i += fts5GetVarint32(&pChunk[i], iVal);
    ++      iVal += pCtx->iRead - 2;
    ++      pCtx->iRead = iVal;
    ++      if( fts5IndexColsetTest(pCtx->pColset, iVal) ){
    ++        fts5BufferSafeAppendVarint(pCtx->pBuf, iVal + 2 - pCtx->iWrite);
    ++        pCtx->iWrite = iVal;
    ++      }
    ++    }
    ++  }
    ++}
    ++
    ++static void fts5PoslistFilterCallback(
    ++  Fts5Index *pUnused,
    ++  void *pContext, 
    ++  const u8 *pChunk, int nChunk
    ++){
    ++  PoslistCallbackCtx *pCtx = (PoslistCallbackCtx*)pContext;
    ++  UNUSED_PARAM(pUnused);
    ++  assert_nc( nChunk>=0 );
    ++  if( nChunk>0 ){
    ++    /* Search through to find the first varint with value 1. This is the
    ++    ** start of the next columns hits. */
    ++    int i = 0;
    ++    int iStart = 0;
    ++
    ++    if( pCtx->eState==2 ){
    ++      int iCol;
    ++      fts5FastGetVarint32(pChunk, i, iCol);
    ++      if( fts5IndexColsetTest(pCtx->pColset, iCol) ){
    ++        pCtx->eState = 1;
    ++        fts5BufferSafeAppendVarint(pCtx->pBuf, 1);
    ++      }else{
    ++        pCtx->eState = 0;
    ++      }
    ++    }
    ++
    ++    do {
    ++      while( i<nChunk && pChunk[i]!=0x01 ){
    ++        while( pChunk[i] & 0x80 ) i++;
    ++        i++;
    ++      }
    ++      if( pCtx->eState ){
    ++        fts5BufferSafeAppendBlob(pCtx->pBuf, &pChunk[iStart], i-iStart);
    ++      }
    ++      if( i<nChunk ){
    ++        int iCol;
    ++        iStart = i;
    ++        i++;
    ++        if( i>=nChunk ){
    ++          pCtx->eState = 2;
    ++        }else{
    ++          fts5FastGetVarint32(pChunk, i, iCol);
    ++          pCtx->eState = fts5IndexColsetTest(pCtx->pColset, iCol);
    ++          if( pCtx->eState ){
    ++            fts5BufferSafeAppendBlob(pCtx->pBuf, &pChunk[iStart], i-iStart);
    ++            iStart = i;
    ++          }
    ++        }
    ++      }
    ++    }while( i<nChunk );
    ++  }
    ++}
    ++
    ++static void fts5ChunkIterate(
    ++  Fts5Index *p,                   /* Index object */
    ++  Fts5SegIter *pSeg,              /* Poslist of this iterator */
    ++  void *pCtx,                     /* Context pointer for xChunk callback */
    ++  void (*xChunk)(Fts5Index*, void*, const u8*, int)
    ++){
    ++  int nRem = pSeg->nPos;          /* Number of bytes still to come */
    ++  Fts5Data *pData = 0;
    ++  u8 *pChunk = &pSeg->pLeaf->p[pSeg->iLeafOffset];
    ++  int nChunk = MIN(nRem, pSeg->pLeaf->szLeaf - pSeg->iLeafOffset);
    ++  int pgno = pSeg->iLeafPgno;
    ++  int pgnoSave = 0;
    ++
    ++  /* This function does notmwork with detail=none databases. */
    ++  assert( p->pConfig->eDetail!=FTS5_DETAIL_NONE );
    ++
    ++  if( (pSeg->flags & FTS5_SEGITER_REVERSE)==0 ){
    ++    pgnoSave = pgno+1;
    ++  }
    ++
    ++  while( 1 ){
    ++    xChunk(p, pCtx, pChunk, nChunk);
    ++    nRem -= nChunk;
    ++    fts5DataRelease(pData);
    ++    if( nRem<=0 ){
    ++      break;
    ++    }else{
    ++      pgno++;
    ++      pData = fts5LeafRead(p, FTS5_SEGMENT_ROWID(pSeg->pSeg->iSegid, pgno));
    ++      if( pData==0 ) break;
    ++      pChunk = &pData->p[4];
    ++      nChunk = MIN(nRem, pData->szLeaf - 4);
    ++      if( pgno==pgnoSave ){
    ++        assert( pSeg->pNextLeaf==0 );
    ++        pSeg->pNextLeaf = pData;
    ++        pData = 0;
    ++      }
    ++    }
    ++  }
    ++}
    ++
    ++/*
    ++** Iterator pIter currently points to a valid entry (not EOF). This
    ++** function appends the position list data for the current entry to
    ++** buffer pBuf. It does not make a copy of the position-list size
    ++** field.
    ++*/
    ++static void fts5SegiterPoslist(
    ++  Fts5Index *p,
    ++  Fts5SegIter *pSeg,
    ++  Fts5Colset *pColset,
    ++  Fts5Buffer *pBuf
    ++){
    ++  if( 0==fts5BufferGrow(&p->rc, pBuf, pSeg->nPos) ){
    ++    if( pColset==0 ){
    ++      fts5ChunkIterate(p, pSeg, (void*)pBuf, fts5PoslistCallback);
    ++    }else{
    ++      if( p->pConfig->eDetail==FTS5_DETAIL_FULL ){
    ++        PoslistCallbackCtx sCtx;
    ++        sCtx.pBuf = pBuf;
    ++        sCtx.pColset = pColset;
    ++        sCtx.eState = fts5IndexColsetTest(pColset, 0);
    ++        assert( sCtx.eState==0 || sCtx.eState==1 );
    ++        fts5ChunkIterate(p, pSeg, (void*)&sCtx, fts5PoslistFilterCallback);
    ++      }else{
    ++        PoslistOffsetsCtx sCtx;
    ++        memset(&sCtx, 0, sizeof(sCtx));
    ++        sCtx.pBuf = pBuf;
    ++        sCtx.pColset = pColset;
    ++        fts5ChunkIterate(p, pSeg, (void*)&sCtx, fts5PoslistOffsetsCallback);
    ++      }
    ++    }
    ++  }
    ++}
    ++
    ++/*
    ++** IN/OUT parameter (*pa) points to a position list n bytes in size. If
    ++** the position list contains entries for column iCol, then (*pa) is set
    ++** to point to the sub-position-list for that column and the number of
    ++** bytes in it returned. Or, if the argument position list does not
    ++** contain any entries for column iCol, return 0.
    ++*/
    ++static int fts5IndexExtractCol(
    ++  const u8 **pa,                  /* IN/OUT: Pointer to poslist */
    ++  int n,                          /* IN: Size of poslist in bytes */
    ++  int iCol                        /* Column to extract from poslist */
    ++){
    ++  int iCurrent = 0;               /* Anything before the first 0x01 is col 0 */
    ++  const u8 *p = *pa;
    ++  const u8 *pEnd = &p[n];         /* One byte past end of position list */
    ++
    ++  while( iCol>iCurrent ){
    ++    /* Advance pointer p until it points to pEnd or an 0x01 byte that is
    ++    ** not part of a varint. Note that it is not possible for a negative
    ++    ** or extremely large varint to occur within an uncorrupted position 
    ++    ** list. So the last byte of each varint may be assumed to have a clear
    ++    ** 0x80 bit.  */
    ++    while( *p!=0x01 ){
    ++      while( *p++ & 0x80 );
    ++      if( p>=pEnd ) return 0;
    ++    }
    ++    *pa = p++;
    ++    iCurrent = *p++;
    ++    if( iCurrent & 0x80 ){
    ++      p--;
    ++      p += fts5GetVarint32(p, iCurrent);
    ++    }
    ++  }
    ++  if( iCol!=iCurrent ) return 0;
    ++
    ++  /* Advance pointer p until it points to pEnd or an 0x01 byte that is
    ++  ** not part of a varint */
    ++  while( p<pEnd && *p!=0x01 ){
    ++    while( *p++ & 0x80 );
    ++  }
    ++
    ++  return p - (*pa);
    ++}
    ++
    ++static void fts5IndexExtractColset(
    ++  int *pRc,
    ++  Fts5Colset *pColset,            /* Colset to filter on */
    ++  const u8 *pPos, int nPos,       /* Position list */
    ++  Fts5Buffer *pBuf                /* Output buffer */
    ++){
    ++  if( *pRc==SQLITE_OK ){
    ++    int i;
    ++    fts5BufferZero(pBuf);
    ++    for(i=0; i<pColset->nCol; i++){
    ++      const u8 *pSub = pPos;
    ++      int nSub = fts5IndexExtractCol(&pSub, nPos, pColset->aiCol[i]);
    ++      if( nSub ){
    ++        fts5BufferAppendBlob(pRc, pBuf, nSub, pSub);
    ++      }
    ++    }
    ++  }
    ++}
    ++
    ++/*
    ++** xSetOutputs callback used by detail=none tables.
    ++*/
    ++static void fts5IterSetOutputs_None(Fts5Iter *pIter, Fts5SegIter *pSeg){
    ++  assert( pIter->pIndex->pConfig->eDetail==FTS5_DETAIL_NONE );
    ++  pIter->base.iRowid = pSeg->iRowid;
    ++  pIter->base.nData = pSeg->nPos;
    ++}
    ++
    ++/*
    ++** xSetOutputs callback used by detail=full and detail=col tables when no
    ++** column filters are specified.
    ++*/
    ++static void fts5IterSetOutputs_Nocolset(Fts5Iter *pIter, Fts5SegIter *pSeg){
    ++  pIter->base.iRowid = pSeg->iRowid;
    ++  pIter->base.nData = pSeg->nPos;
    ++
    ++  assert( pIter->pIndex->pConfig->eDetail!=FTS5_DETAIL_NONE );
    ++  assert( pIter->pColset==0 );
    ++
    ++  if( pSeg->iLeafOffset+pSeg->nPos<=pSeg->pLeaf->szLeaf ){
    ++    /* All data is stored on the current page. Populate the output 
    ++    ** variables to point into the body of the page object. */
    ++    pIter->base.pData = &pSeg->pLeaf->p[pSeg->iLeafOffset];
    ++  }else{
    ++    /* The data is distributed over two or more pages. Copy it into the
    ++    ** Fts5Iter.poslist buffer and then set the output pointer to point
    ++    ** to this buffer.  */
    ++    fts5BufferZero(&pIter->poslist);
    ++    fts5SegiterPoslist(pIter->pIndex, pSeg, 0, &pIter->poslist);
    ++    pIter->base.pData = pIter->poslist.p;
    ++  }
    ++}
    ++
    ++/*
    ++** xSetOutputs callback used when the Fts5Colset object has nCol==0 (match
    ++** against no columns at all).
    ++*/
    ++static void fts5IterSetOutputs_ZeroColset(Fts5Iter *pIter, Fts5SegIter *pSeg){
    ++  UNUSED_PARAM(pSeg);
    ++  pIter->base.nData = 0;
    ++}
    ++
    ++/*
    ++** xSetOutputs callback used by detail=col when there is a column filter
    ++** and there are 100 or more columns. Also called as a fallback from
    ++** fts5IterSetOutputs_Col100 if the column-list spans more than one page.
    ++*/
    ++static void fts5IterSetOutputs_Col(Fts5Iter *pIter, Fts5SegIter *pSeg){
    ++  fts5BufferZero(&pIter->poslist);
    ++  fts5SegiterPoslist(pIter->pIndex, pSeg, pIter->pColset, &pIter->poslist);
    ++  pIter->base.iRowid = pSeg->iRowid;
    ++  pIter->base.pData = pIter->poslist.p;
    ++  pIter->base.nData = pIter->poslist.n;
    ++}
    ++
    ++/*
    ++** xSetOutputs callback used when: 
    ++**
    ++**   * detail=col,
    ++**   * there is a column filter, and
    ++**   * the table contains 100 or fewer columns. 
    ++**
    ++** The last point is to ensure all column numbers are stored as 
    ++** single-byte varints.
    ++*/
    ++static void fts5IterSetOutputs_Col100(Fts5Iter *pIter, Fts5SegIter *pSeg){
    ++
    ++  assert( pIter->pIndex->pConfig->eDetail==FTS5_DETAIL_COLUMNS );
    ++  assert( pIter->pColset );
    ++
    ++  if( pSeg->iLeafOffset+pSeg->nPos>pSeg->pLeaf->szLeaf ){
    ++    fts5IterSetOutputs_Col(pIter, pSeg);
    ++  }else{
    ++    u8 *a = (u8*)&pSeg->pLeaf->p[pSeg->iLeafOffset];
    ++    u8 *pEnd = (u8*)&a[pSeg->nPos]; 
    ++    int iPrev = 0;
    ++    int *aiCol = pIter->pColset->aiCol;
    ++    int *aiColEnd = &aiCol[pIter->pColset->nCol];
    ++
    ++    u8 *aOut = pIter->poslist.p;
    ++    int iPrevOut = 0;
    ++
    ++    pIter->base.iRowid = pSeg->iRowid;
    ++
    ++    while( a<pEnd ){
    ++      iPrev += (int)a++[0] - 2;
    ++      while( *aiCol<iPrev ){
    ++        aiCol++;
    ++        if( aiCol==aiColEnd ) goto setoutputs_col_out;
    ++      }
    ++      if( *aiCol==iPrev ){
    ++        *aOut++ = (u8)((iPrev - iPrevOut) + 2);
    ++        iPrevOut = iPrev;
    ++      }
    ++    }
    ++
    ++setoutputs_col_out:
    ++    pIter->base.pData = pIter->poslist.p;
    ++    pIter->base.nData = aOut - pIter->poslist.p;
    ++  }
    ++}
    ++
    ++/*
    ++** xSetOutputs callback used by detail=full when there is a column filter.
    ++*/
    ++static void fts5IterSetOutputs_Full(Fts5Iter *pIter, Fts5SegIter *pSeg){
    ++  Fts5Colset *pColset = pIter->pColset;
    ++  pIter->base.iRowid = pSeg->iRowid;
    ++
    ++  assert( pIter->pIndex->pConfig->eDetail==FTS5_DETAIL_FULL );
    ++  assert( pColset );
    ++
    ++  if( pSeg->iLeafOffset+pSeg->nPos<=pSeg->pLeaf->szLeaf ){
    ++    /* All data is stored on the current page. Populate the output 
    ++    ** variables to point into the body of the page object. */
    ++    const u8 *a = &pSeg->pLeaf->p[pSeg->iLeafOffset];
    ++    if( pColset->nCol==1 ){
    ++      pIter->base.nData = fts5IndexExtractCol(&a, pSeg->nPos,pColset->aiCol[0]);
    ++      pIter->base.pData = a;
    ++    }else{
    ++      int *pRc = &pIter->pIndex->rc;
    ++      fts5BufferZero(&pIter->poslist);
    ++      fts5IndexExtractColset(pRc, pColset, a, pSeg->nPos, &pIter->poslist);
    ++      pIter->base.pData = pIter->poslist.p;
    ++      pIter->base.nData = pIter->poslist.n;
    ++    }
    ++  }else{
    ++    /* The data is distributed over two or more pages. Copy it into the
    ++    ** Fts5Iter.poslist buffer and then set the output pointer to point
    ++    ** to this buffer.  */
    ++    fts5BufferZero(&pIter->poslist);
    ++    fts5SegiterPoslist(pIter->pIndex, pSeg, pColset, &pIter->poslist);
    ++    pIter->base.pData = pIter->poslist.p;
    ++    pIter->base.nData = pIter->poslist.n;
    ++  }
    ++}
    ++
    ++static void fts5IterSetOutputCb(int *pRc, Fts5Iter *pIter){
    ++  if( *pRc==SQLITE_OK ){
    ++    Fts5Config *pConfig = pIter->pIndex->pConfig;
    ++    if( pConfig->eDetail==FTS5_DETAIL_NONE ){
    ++      pIter->xSetOutputs = fts5IterSetOutputs_None;
    ++    }
    ++
    ++    else if( pIter->pColset==0 ){
    ++      pIter->xSetOutputs = fts5IterSetOutputs_Nocolset;
    ++    }
    ++
    ++    else if( pIter->pColset->nCol==0 ){
    ++      pIter->xSetOutputs = fts5IterSetOutputs_ZeroColset;
    ++    }
    ++
    ++    else if( pConfig->eDetail==FTS5_DETAIL_FULL ){
    ++      pIter->xSetOutputs = fts5IterSetOutputs_Full;
    ++    }
    ++
    ++    else{
    ++      assert( pConfig->eDetail==FTS5_DETAIL_COLUMNS );
    ++      if( pConfig->nCol<=100 ){
    ++        pIter->xSetOutputs = fts5IterSetOutputs_Col100;
    ++        sqlite3Fts5BufferSize(pRc, &pIter->poslist, pConfig->nCol);
    ++      }else{
    ++        pIter->xSetOutputs = fts5IterSetOutputs_Col;
    ++      }
    ++    }
    ++  }
    ++}
    ++
    ++
    ++/*
    ++** Allocate a new Fts5Iter object.
    + **
    + ** The new object will be used to iterate through data in structure pStruct.
    + ** If iLevel is -ve, then all data in all segments is merged. Or, if iLevel
    +@@ -175099,19 +197621,18 @@ static Fts5IndexIter *fts5MultiIterAlloc(
    + static void fts5MultiIterNew(
    +   Fts5Index *p,                   /* FTS5 backend to iterate within */
    +   Fts5Structure *pStruct,         /* Structure of specific index */
    +-  int bSkipEmpty,                 /* True to ignore delete-keys */
    +   int flags,                      /* FTS5INDEX_QUERY_XXX flags */
    ++  Fts5Colset *pColset,            /* Colset to filter on (or NULL) */
    +   const u8 *pTerm, int nTerm,     /* Term to seek to (or NULL/0) */
    +   int iLevel,                     /* Level to iterate (-1 for all) */
    +   int nSegment,                   /* Number of segments to merge (iLevel>=0) */
    +-  Fts5IndexIter **ppOut           /* New object */
    ++  Fts5Iter **ppOut                /* New object */
    + ){
    +   int nSeg = 0;                   /* Number of segment-iters in use */
    +   int iIter = 0;                  /* */
    +   int iSeg;                       /* Used to iterate through segments */
    +-  Fts5Buffer buf = {0,0,0};       /* Buffer used by fts5SegIterSeekInit() */
    +   Fts5StructureLevel *pLvl;
    +-  Fts5IndexIter *pNew;
    ++  Fts5Iter *pNew;
    + 
    +   assert( (pTerm==0 && nTerm==0) || iLevel<0 );
    + 
    +@@ -175128,36 +197649,42 @@ static void fts5MultiIterNew(
    +   *ppOut = pNew = fts5MultiIterAlloc(p, nSeg);
    +   if( pNew==0 ) return;
    +   pNew->bRev = (0!=(flags & FTS5INDEX_QUERY_DESC));
    +-  pNew->bSkipEmpty = bSkipEmpty;
    ++  pNew->bSkipEmpty = (0!=(flags & FTS5INDEX_QUERY_SKIPEMPTY));
    +   pNew->pStruct = pStruct;
    ++  pNew->pColset = pColset;
    +   fts5StructureRef(pStruct);
    ++  if( (flags & FTS5INDEX_QUERY_NOOUTPUT)==0 ){
    ++    fts5IterSetOutputCb(&p->rc, pNew);
    ++  }
    + 
    +   /* Initialize each of the component segment iterators. */
    +-  if( iLevel<0 ){
    +-    Fts5StructureLevel *pEnd = &pStruct->aLevel[pStruct->nLevel];
    +-    if( p->pHash ){
    +-      /* Add a segment iterator for the current contents of the hash table. */
    +-      Fts5SegIter *pIter = &pNew->aSeg[iIter++];
    +-      fts5SegIterHashInit(p, pTerm, nTerm, flags, pIter);
    +-    }
    +-    for(pLvl=&pStruct->aLevel[0]; pLvl<pEnd; pLvl++){
    +-      for(iSeg=pLvl->nSeg-1; iSeg>=0; iSeg--){
    +-        Fts5StructureSegment *pSeg = &pLvl->aSeg[iSeg];
    ++  if( p->rc==SQLITE_OK ){
    ++    if( iLevel<0 ){
    ++      Fts5StructureLevel *pEnd = &pStruct->aLevel[pStruct->nLevel];
    ++      if( p->pHash ){
    ++        /* Add a segment iterator for the current contents of the hash table. */
    +         Fts5SegIter *pIter = &pNew->aSeg[iIter++];
    +-        if( pTerm==0 ){
    +-          fts5SegIterInit(p, pSeg, pIter);
    +-        }else{
    +-          fts5SegIterSeekInit(p, &buf, pTerm, nTerm, flags, pSeg, pIter);
    ++        fts5SegIterHashInit(p, pTerm, nTerm, flags, pIter);
    ++      }
    ++      for(pLvl=&pStruct->aLevel[0]; pLvl<pEnd; pLvl++){
    ++        for(iSeg=pLvl->nSeg-1; iSeg>=0; iSeg--){
    ++          Fts5StructureSegment *pSeg = &pLvl->aSeg[iSeg];
    ++          Fts5SegIter *pIter = &pNew->aSeg[iIter++];
    ++          if( pTerm==0 ){
    ++            fts5SegIterInit(p, pSeg, pIter);
    ++          }else{
    ++            fts5SegIterSeekInit(p, pTerm, nTerm, flags, pSeg, pIter);
    ++          }
    +         }
    +       }
    ++    }else{
    ++      pLvl = &pStruct->aLevel[iLevel];
    ++      for(iSeg=nSeg-1; iSeg>=0; iSeg--){
    ++        fts5SegIterInit(p, &pLvl->aSeg[iSeg], &pNew->aSeg[iIter++]);
    ++      }
    +     }
    +-  }else{
    +-    pLvl = &pStruct->aLevel[iLevel];
    +-    for(iSeg=nSeg-1; iSeg>=0; iSeg--){
    +-      fts5SegIterInit(p, &pLvl->aSeg[iSeg], &pNew->aSeg[iIter++]);
    +-    }
    ++    assert( iIter==nSeg );
    +   }
    +-  assert( iIter==nSeg );
    + 
    +   /* If the above was successful, each component iterators now points 
    +   ** to the first entry in its segment. In this case initialize the 
    +@@ -175167,7 +197694,8 @@ static void fts5MultiIterNew(
    +     for(iIter=pNew->nSeg-1; iIter>0; iIter--){
    +       int iEq;
    +       if( (iEq = fts5MultiIterDoCompare(pNew, iIter)) ){
    +-        fts5SegIterNext(p, &pNew->aSeg[iEq], 0);
    ++        Fts5SegIter *pSeg = &pNew->aSeg[iEq];
    ++        if( p->rc==SQLITE_OK ) pSeg->xNext(p, pSeg, 0);
    +         fts5MultiIterAdvanced(p, pNew, iEq, iIter);
    +       }
    +     }
    +@@ -175176,30 +197704,32 @@ static void fts5MultiIterNew(
    + 
    +     if( pNew->bSkipEmpty && fts5MultiIterIsEmpty(p, pNew) ){
    +       fts5MultiIterNext(p, pNew, 0, 0);
    ++    }else if( pNew->base.bEof==0 ){
    ++      Fts5SegIter *pSeg = &pNew->aSeg[pNew->aFirst[1].iFirst];
    ++      pNew->xSetOutputs(pNew, pSeg);
    +     }
    ++
    +   }else{
    +-    fts5MultiIterFree(p, pNew);
    ++    fts5MultiIterFree(pNew);
    +     *ppOut = 0;
    +   }
    +-  fts5BufferFree(&buf);
    + }
    + 
    + /*
    +-** Create an Fts5IndexIter that iterates through the doclist provided
    ++** Create an Fts5Iter that iterates through the doclist provided
    + ** as the second argument.
    + */
    + static void fts5MultiIterNew2(
    +   Fts5Index *p,                   /* FTS5 backend to iterate within */
    +   Fts5Data *pData,                /* Doclist to iterate through */
    +   int bDesc,                      /* True for descending rowid order */
    +-  Fts5IndexIter **ppOut           /* New object */
    ++  Fts5Iter **ppOut                /* New object */
    + ){
    +-  Fts5IndexIter *pNew;
    ++  Fts5Iter *pNew;
    +   pNew = fts5MultiIterAlloc(p, 2);
    +   if( pNew ){
    +     Fts5SegIter *pIter = &pNew->aSeg[1];
    + 
    +-    pNew->bFiltered = 1;
    +     pIter->flags = FTS5_SEGITER_ONETERM;
    +     if( pData->szLeaf>0 ){
    +       pIter->pLeaf = pData;
    +@@ -175215,8 +197745,9 @@ static void fts5MultiIterNew2(
    +       }
    +       pData = 0;
    +     }else{
    +-      pNew->bEof = 1;
    ++      pNew->base.bEof = 1;
    +     }
    ++    fts5SegIterSetNext(p, pIter);
    + 
    +     *ppOut = pNew;
    +   }
    +@@ -175228,11 +197759,11 @@ static void fts5MultiIterNew2(
    + ** Return true if the iterator is at EOF or if an error has occurred. 
    + ** False otherwise.
    + */
    +-static int fts5MultiIterEof(Fts5Index *p, Fts5IndexIter *pIter){
    ++static int fts5MultiIterEof(Fts5Index *p, Fts5Iter *pIter){
    +   assert( p->rc 
    +-      || (pIter->aSeg[ pIter->aFirst[1].iFirst ].pLeaf==0)==pIter->bEof 
    ++      || (pIter->aSeg[ pIter->aFirst[1].iFirst ].pLeaf==0)==pIter->base.bEof 
    +   );
    +-  return (p->rc || pIter->bEof);
    ++  return (p->rc || pIter->base.bEof);
    + }
    + 
    + /*
    +@@ -175240,7 +197771,7 @@ static int fts5MultiIterEof(Fts5Index *p, Fts5IndexIter *pIter){
    + ** to. If the iterator points to EOF when this function is called the
    + ** results are undefined.
    + */
    +-static i64 fts5MultiIterRowid(Fts5IndexIter *pIter){
    ++static i64 fts5MultiIterRowid(Fts5Iter *pIter){
    +   assert( pIter->aSeg[ pIter->aFirst[1].iFirst ].pLeaf );
    +   return pIter->aSeg[ pIter->aFirst[1].iFirst ].iRowid;
    + }
    +@@ -175250,7 +197781,7 @@ static i64 fts5MultiIterRowid(Fts5IndexIter *pIter){
    + */
    + static void fts5MultiIterNextFrom(
    +   Fts5Index *p, 
    +-  Fts5IndexIter *pIter, 
    ++  Fts5Iter *pIter, 
    +   i64 iMatch
    + ){
    +   while( 1 ){
    +@@ -175267,52 +197798,12 @@ static void fts5MultiIterNextFrom(
    + ** Return a pointer to a buffer containing the term associated with the 
    + ** entry that the iterator currently points to.
    + */
    +-static const u8 *fts5MultiIterTerm(Fts5IndexIter *pIter, int *pn){
    ++static const u8 *fts5MultiIterTerm(Fts5Iter *pIter, int *pn){
    +   Fts5SegIter *p = &pIter->aSeg[ pIter->aFirst[1].iFirst ];
    +   *pn = p->term.n;
    +   return p->term.p;
    + }
    + 
    +-static void fts5ChunkIterate(
    +-  Fts5Index *p,                   /* Index object */
    +-  Fts5SegIter *pSeg,              /* Poslist of this iterator */
    +-  void *pCtx,                     /* Context pointer for xChunk callback */
    +-  void (*xChunk)(Fts5Index*, void*, const u8*, int)
    +-){
    +-  int nRem = pSeg->nPos;          /* Number of bytes still to come */
    +-  Fts5Data *pData = 0;
    +-  u8 *pChunk = &pSeg->pLeaf->p[pSeg->iLeafOffset];
    +-  int nChunk = MIN(nRem, pSeg->pLeaf->szLeaf - pSeg->iLeafOffset);
    +-  int pgno = pSeg->iLeafPgno;
    +-  int pgnoSave = 0;
    +-
    +-  if( (pSeg->flags & FTS5_SEGITER_REVERSE)==0 ){
    +-    pgnoSave = pgno+1;
    +-  }
    +-
    +-  while( 1 ){
    +-    xChunk(p, pCtx, pChunk, nChunk);
    +-    nRem -= nChunk;
    +-    fts5DataRelease(pData);
    +-    if( nRem<=0 ){
    +-      break;
    +-    }else{
    +-      pgno++;
    +-      pData = fts5DataRead(p, FTS5_SEGMENT_ROWID(pSeg->pSeg->iSegid, pgno));
    +-      if( pData==0 ) break;
    +-      pChunk = &pData->p[4];
    +-      nChunk = MIN(nRem, pData->szLeaf - 4);
    +-      if( pgno==pgnoSave ){
    +-        assert( pSeg->pNextLeaf==0 );
    +-        pSeg->pNextLeaf = pData;
    +-        pData = 0;
    +-      }
    +-    }
    +-  }
    +-}
    +-
    +-
    +-
    + /*
    + ** Allocate a new segment-id for the structure pStruct. The new segment
    + ** id must be between 1 and 65335 inclusive, and must not be used by 
    +@@ -175329,18 +197820,46 @@ static int fts5AllocateSegid(Fts5Index *p, Fts5Structure *pStruct){
    +     if( pStruct->nSegment>=FTS5_MAX_SEGMENT ){
    +       p->rc = SQLITE_FULL;
    +     }else{
    +-      while( iSegid==0 ){
    +-        int iLvl, iSeg;
    +-        sqlite3_randomness(sizeof(u32), (void*)&iSegid);
    +-        iSegid = iSegid & ((1 << FTS5_DATA_ID_B)-1);
    +-        for(iLvl=0; iLvl<pStruct->nLevel; iLvl++){
    +-          for(iSeg=0; iSeg<pStruct->aLevel[iLvl].nSeg; iSeg++){
    +-            if( iSegid==pStruct->aLevel[iLvl].aSeg[iSeg].iSegid ){
    +-              iSegid = 0;
    +-            }
    ++      /* FTS5_MAX_SEGMENT is currently defined as 2000. So the following
    ++      ** array is 63 elements, or 252 bytes, in size.  */
    ++      u32 aUsed[(FTS5_MAX_SEGMENT+31) / 32];
    ++      int iLvl, iSeg;
    ++      int i;
    ++      u32 mask;
    ++      memset(aUsed, 0, sizeof(aUsed));
    ++      for(iLvl=0; iLvl<pStruct->nLevel; iLvl++){
    ++        for(iSeg=0; iSeg<pStruct->aLevel[iLvl].nSeg; iSeg++){
    ++          int iId = pStruct->aLevel[iLvl].aSeg[iSeg].iSegid;
    ++          if( iId<=FTS5_MAX_SEGMENT ){
    ++            aUsed[(iId-1) / 32] |= 1 << ((iId-1) % 32);
    +           }
    +         }
    +       }
    ++
    ++      for(i=0; aUsed[i]==0xFFFFFFFF; i++);
    ++      mask = aUsed[i];
    ++      for(iSegid=0; mask & (1 << iSegid); iSegid++);
    ++      iSegid += 1 + i*32;
    ++
    ++#ifdef SQLITE_DEBUG
    ++      for(iLvl=0; iLvl<pStruct->nLevel; iLvl++){
    ++        for(iSeg=0; iSeg<pStruct->aLevel[iLvl].nSeg; iSeg++){
    ++          assert( iSegid!=pStruct->aLevel[iLvl].aSeg[iSeg].iSegid );
    ++        }
    ++      }
    ++      assert( iSegid>0 && iSegid<=FTS5_MAX_SEGMENT );
    ++
    ++      {
    ++        sqlite3_stmt *pIdxSelect = fts5IdxSelectStmt(p);
    ++        if( p->rc==SQLITE_OK ){
    ++          u8 aBlob[2] = {0xff, 0xff};
    ++          sqlite3_bind_int(pIdxSelect, 1, iSegid);
    ++          sqlite3_bind_blob(pIdxSelect, 2, aBlob, 2, SQLITE_STATIC);
    ++          assert( sqlite3_step(pIdxSelect)!=SQLITE_ROW );
    ++          p->rc = sqlite3_reset(pIdxSelect);
    ++        }
    ++      }
    ++#endif
    +     }
    +   }
    + 
    +@@ -175359,15 +197878,14 @@ static void fts5IndexDiscardData(Fts5Index *p){
    + }
    + 
    + /*
    +-** Return the size of the prefix, in bytes, that buffer (nNew/pNew) shares
    +-** with buffer (nOld/pOld).
    ++** Return the size of the prefix, in bytes, that buffer 
    ++** (pNew/<length-unknown>) shares with buffer (pOld/nOld).
    ++**
    ++** Buffer (pNew/<length-unknown>) is guaranteed to be greater 
    ++** than buffer (pOld/nOld).
    + */
    +-static int fts5PrefixCompress(
    +-  int nOld, const u8 *pOld,
    +-  int nNew, const u8 *pNew
    +-){
    ++static int fts5PrefixCompress(int nOld, const u8 *pOld, const u8 *pNew){
    +   int i;
    +-  assert( fts5BlobCompare(pOld, nOld, pNew, nNew)<0 );
    +   for(i=0; i<nOld; i++){
    +     if( pOld[i]!=pNew[i] ) break;
    +   }
    +@@ -175591,7 +198109,7 @@ static void fts5WriteFlushLeaf(Fts5Index *p, Fts5SegWriter *pWriter){
    + 
    +   /* Set the szLeaf header field. */
    +   assert( 0==fts5GetU16(&pPage->buf.p[2]) );
    +-  fts5PutU16(&pPage->buf.p[2], pPage->buf.n);
    ++  fts5PutU16(&pPage->buf.p[2], (u16)pPage->buf.n);
    + 
    +   if( pWriter->bFirstTermInPage ){
    +     /* No term was written to this page. */
    +@@ -175677,13 +198195,13 @@ static void fts5WriteAppendTerm(
    +       ** inefficient, but still correct.  */
    +       int n = nTerm;
    +       if( pPage->term.n ){
    +-        n = 1 + fts5PrefixCompress(pPage->term.n, pPage->term.p, nTerm, pTerm);
    ++        n = 1 + fts5PrefixCompress(pPage->term.n, pPage->term.p, pTerm);
    +       }
    +       fts5WriteBtreeTerm(p, pWriter, n, pTerm);
    +       pPage = &pWriter->writer;
    +     }
    +   }else{
    +-    nPrefix = fts5PrefixCompress(pPage->term.n, pPage->term.p, nTerm, pTerm);
    ++    nPrefix = fts5PrefixCompress(pPage->term.n, pPage->term.p, pTerm);
    +     fts5BufferAppendVarint(&p->rc, &pPage->buf, nPrefix);
    +   }
    + 
    +@@ -175709,8 +198227,7 @@ static void fts5WriteAppendTerm(
    + static void fts5WriteAppendRowid(
    +   Fts5Index *p, 
    +   Fts5SegWriter *pWriter,
    +-  i64 iRowid,
    +-  int nPos
    ++  i64 iRowid
    + ){
    +   if( p->rc==SQLITE_OK ){
    +     Fts5PageWriter *pPage = &pWriter->writer;
    +@@ -175723,7 +198240,7 @@ static void fts5WriteAppendRowid(
    +     ** rowid-pointer in the page-header. Also append a value to the dlidx
    +     ** buffer, in case a doclist-index is required.  */
    +     if( pWriter->bFirstRowidInPage ){
    +-      fts5PutU16(pPage->buf.p, pPage->buf.n);
    ++      fts5PutU16(pPage->buf.p, (u16)pPage->buf.n);
    +       fts5WriteDlidxAppend(p, pWriter, iRowid);
    +     }
    + 
    +@@ -175737,8 +198254,6 @@ static void fts5WriteAppendRowid(
    +     pWriter->iPrevRowid = iRowid;
    +     pWriter->bFirstRowidInDoclist = 0;
    +     pWriter->bFirstRowidInPage = 0;
    +-
    +-    fts5BufferAppendVarint(&p->rc, &pPage->buf, nPos);
    +   }
    + }
    + 
    +@@ -175789,7 +198304,9 @@ static void fts5WriteFinish(
    +       fts5WriteFlushLeaf(p, pWriter);
    +     }
    +     *pnLeaf = pLeaf->pgno-1;
    +-    fts5WriteFlushBtree(p, pWriter);
    ++    if( pLeaf->pgno>1 ){
    ++      fts5WriteFlushBtree(p, pWriter);
    ++    }
    +   }
    +   fts5BufferFree(&pLeaf->term);
    +   fts5BufferFree(&pLeaf->buf);
    +@@ -175817,9 +198334,12 @@ static void fts5WriteInit(
    +   pWriter->bFirstTermInPage = 1;
    +   pWriter->iBtPage = 1;
    + 
    ++  assert( pWriter->writer.buf.n==0 );
    ++  assert( pWriter->writer.pgidx.n==0 );
    ++
    +   /* Grow the two buffers to pgsz + padding bytes in size. */
    +-  fts5BufferGrow(&p->rc, &pWriter->writer.pgidx, nBuffer);
    +-  fts5BufferGrow(&p->rc, &pWriter->writer.buf, nBuffer);
    ++  sqlite3Fts5BufferSize(&p->rc, &pWriter->writer.pgidx, nBuffer);
    ++  sqlite3Fts5BufferSize(&p->rc, &pWriter->writer.buf, nBuffer);
    + 
    +   if( p->pIdxWriter==0 ){
    +     Fts5Config *pConfig = p->pConfig;
    +@@ -175846,7 +198366,7 @@ static void fts5WriteInit(
    + ** incremental merge operation. This function is called if the incremental
    + ** merge step has finished but the input has not been completely exhausted.
    + */
    +-static void fts5TrimSegments(Fts5Index *p, Fts5IndexIter *pIter){
    ++static void fts5TrimSegments(Fts5Index *p, Fts5Iter *pIter){
    +   int i;
    +   Fts5Buffer buf;
    +   memset(&buf, 0, sizeof(Fts5Buffer));
    +@@ -175878,7 +198398,7 @@ static void fts5TrimSegments(Fts5Index *p, Fts5IndexIter *pIter){
    +         fts5BufferAppendBlob(&p->rc, &buf, pData->szLeaf-iOff, &pData->p[iOff]);
    +         if( p->rc==SQLITE_OK ){
    +           /* Set the szLeaf field */
    +-          fts5PutU16(&buf.p[2], buf.n);
    ++          fts5PutU16(&buf.p[2], (u16)buf.n);
    +         }
    + 
    +         /* Set up the new page-index array */
    +@@ -175924,13 +198444,16 @@ static void fts5IndexMergeLevel(
    +   Fts5Structure *pStruct = *ppStruct;
    +   Fts5StructureLevel *pLvl = &pStruct->aLevel[iLvl];
    +   Fts5StructureLevel *pLvlOut;
    +-  Fts5IndexIter *pIter = 0;       /* Iterator to read input data */
    ++  Fts5Iter *pIter = 0;       /* Iterator to read input data */
    +   int nRem = pnRem ? *pnRem : 0;  /* Output leaf pages left to write */
    +   int nInput;                     /* Number of input segments */
    +   Fts5SegWriter writer;           /* Writer object */
    +   Fts5StructureSegment *pSeg;     /* Output segment */
    +   Fts5Buffer term;
    +   int bOldest;                    /* True if the output segment is the oldest */
    ++  int eDetail = p->pConfig->eDetail;
    ++  const int flags = FTS5INDEX_QUERY_NOOUTPUT;
    ++  int bTermWritten = 0;           /* True if current term already output */
    + 
    +   assert( iLvl<pStruct->nLevel );
    +   assert( pLvl->nMerge<=pLvl->nSeg );
    +@@ -175975,7 +198498,7 @@ static void fts5IndexMergeLevel(
    +   bOldest = (pLvlOut->nSeg==1 && pStruct->nLevel==iLvl+2);
    + 
    +   assert( iLvl>=0 );
    +-  for(fts5MultiIterNew(p, pStruct, 0, 0, 0, 0, iLvl, nInput, &pIter);
    ++  for(fts5MultiIterNew(p, pStruct, flags, 0, 0, 0, iLvl, nInput, &pIter);
    +       fts5MultiIterEof(p, pIter)==0;
    +       fts5MultiIterNext(p, pIter, 0, 0)
    +   ){
    +@@ -175984,27 +198507,41 @@ static void fts5IndexMergeLevel(
    +     int nTerm;
    +     const u8 *pTerm;
    + 
    +-    /* Check for key annihilation. */
    +-    if( pSegIter->nPos==0 && (bOldest || pSegIter->bDel==0) ) continue;
    +-
    +     pTerm = fts5MultiIterTerm(pIter, &nTerm);
    +     if( nTerm!=term.n || memcmp(pTerm, term.p, nTerm) ){
    +       if( pnRem && writer.nLeafWritten>nRem ){
    +         break;
    +       }
    ++      fts5BufferSet(&p->rc, &term, nTerm, pTerm);
    ++      bTermWritten =0;
    ++    }
    ++
    ++    /* Check for key annihilation. */
    ++    if( pSegIter->nPos==0 && (bOldest || pSegIter->bDel==0) ) continue;
    + 
    ++    if( p->rc==SQLITE_OK && bTermWritten==0 ){
    +       /* This is a new term. Append a term to the output segment. */
    +       fts5WriteAppendTerm(p, &writer, nTerm, pTerm);
    +-      fts5BufferSet(&p->rc, &term, nTerm, pTerm);
    ++      bTermWritten = 1;
    +     }
    + 
    +     /* Append the rowid to the output */
    +     /* WRITEPOSLISTSIZE */
    +-    nPos = pSegIter->nPos*2 + pSegIter->bDel;
    +-    fts5WriteAppendRowid(p, &writer, fts5MultiIterRowid(pIter), nPos);
    ++    fts5WriteAppendRowid(p, &writer, fts5MultiIterRowid(pIter));
    + 
    +-    /* Append the position-list data to the output */
    +-    fts5ChunkIterate(p, pSegIter, (void*)&writer, fts5MergeChunkCallback);
    ++    if( eDetail==FTS5_DETAIL_NONE ){
    ++      if( pSegIter->bDel ){
    ++        fts5BufferAppendVarint(&p->rc, &writer.writer.buf, 0);
    ++        if( pSegIter->nPos>0 ){
    ++          fts5BufferAppendVarint(&p->rc, &writer.writer.buf, 0);
    ++        }
    ++      }
    ++    }else{
    ++      /* Append the position-list data to the output */
    ++      nPos = pSegIter->nPos*2 + pSegIter->bDel;
    ++      fts5BufferAppendVarint(&p->rc, &writer.writer.buf, nPos);
    ++      fts5ChunkIterate(p, pSegIter, (void*)&writer, fts5MergeChunkCallback);
    ++    }
    +   }
    + 
    +   /* Flush the last leaf page to disk. Set the output segment b-tree height
    +@@ -176037,20 +198574,24 @@ static void fts5IndexMergeLevel(
    +     pLvl->nMerge = nInput;
    +   }
    + 
    +-  fts5MultiIterFree(p, pIter);
    ++  fts5MultiIterFree(pIter);
    +   fts5BufferFree(&term);
    +   if( pnRem ) *pnRem -= writer.nLeafWritten;
    + }
    + 
    + /*
    + ** Do up to nPg pages of automerge work on the index.
    ++**
    ++** Return true if any changes were actually made, or false otherwise.
    + */
    +-static void fts5IndexMerge(
    ++static int fts5IndexMerge(
    +   Fts5Index *p,                   /* FTS5 backend object */
    +   Fts5Structure **ppStruct,       /* IN/OUT: Current structure of index */
    +-  int nPg                         /* Pages of work to do */
    ++  int nPg,                        /* Pages of work to do */
    ++  int nMin                        /* Minimum number of segments to merge */
    + ){
    +   int nRem = nPg;
    ++  int bRet = 0;
    +   Fts5Structure *pStruct = *ppStruct;
    +   while( nRem>0 && p->rc==SQLITE_OK ){
    +     int iLvl;                   /* To iterate through levels */
    +@@ -176081,17 +198622,17 @@ static void fts5IndexMerge(
    +     }
    + #endif
    + 
    +-    if( nBest<p->pConfig->nAutomerge 
    +-        && pStruct->aLevel[iBestLvl].nMerge==0 
    +-      ){
    ++    if( nBest<nMin && pStruct->aLevel[iBestLvl].nMerge==0 ){
    +       break;
    +     }
    ++    bRet = 1;
    +     fts5IndexMergeLevel(p, &pStruct, iBestLvl, &nRem);
    +     if( p->rc==SQLITE_OK && pStruct->aLevel[iBestLvl].nMerge==0 ){
    +       fts5StructurePromote(p, iBestLvl+1, pStruct);
    +     }
    +   }
    +   *ppStruct = pStruct;
    ++  return bRet;
    + }
    + 
    + /*
    +@@ -176119,7 +198660,7 @@ static void fts5IndexAutomerge(
    +     pStruct->nWriteCounter += nLeaf;
    +     nRem = (int)(p->nWorkUnit * nWork * pStruct->nLevel);
    + 
    +-    fts5IndexMerge(p, ppStruct, nRem);
    ++    fts5IndexMerge(p, ppStruct, nRem, p->pConfig->nAutomerge);
    +   }
    + }
    + 
    +@@ -176172,17 +198713,6 @@ static int fts5PoslistPrefix(const u8 *aBuf, int nMax){
    +   return ret;
    + }
    + 
    +-#define fts5BufferSafeAppendBlob(pBuf, pBlob, nBlob) {     \
    +-  assert( (pBuf)->nSpace>=((pBuf)->n+nBlob) );             \
    +-  memcpy(&(pBuf)->p[(pBuf)->n], pBlob, nBlob);             \
    +-  (pBuf)->n += nBlob;                                      \
    +-}
    +-
    +-#define fts5BufferSafeAppendVarint(pBuf, iVal) {                \
    +-  (pBuf)->n += sqlite3Fts5PutVarint(&(pBuf)->p[(pBuf)->n], (iVal));  \
    +-  assert( (pBuf)->nSpace>=(pBuf)->n );                          \
    +-}
    +-
    + /*
    + ** Flush the contents of in-memory hash table iHash to a new level-0 
    + ** segment on disk. Also update the corresponding structure record.
    +@@ -176200,10 +198730,11 @@ static void fts5FlushOneHash(Fts5Index *p){
    +   ** for the new level-0 segment.  */
    +   pStruct = fts5StructureRead(p);
    +   iSegid = fts5AllocateSegid(p, pStruct);
    ++  fts5StructureInvalidate(p);
    + 
    +   if( iSegid ){
    +     const int pgsz = p->pConfig->pgsz;
    +-
    ++    int eDetail = p->pConfig->eDetail;
    +     Fts5StructureSegment *pSeg;   /* New segment within pStruct */
    +     Fts5Buffer *pBuf;             /* Buffer in which to assemble leaf page */
    +     Fts5Buffer *pPgidx;           /* Buffer in which to assemble pgidx */
    +@@ -176231,7 +198762,7 @@ static void fts5FlushOneHash(Fts5Index *p){
    + 
    +       /* Write the term for this entry to disk. */
    +       sqlite3Fts5HashScanEntry(pHash, &zTerm, &pDoclist, &nDoclist);
    +-      fts5WriteAppendTerm(p, &writer, strlen(zTerm), (const u8*)zTerm);
    ++      fts5WriteAppendTerm(p, &writer, (int)strlen(zTerm), (const u8*)zTerm);
    + 
    +       assert( writer.bFirstRowidInPage==0 );
    +       if( pgsz>=(pBuf->n + pPgidx->n + nDoclist + 1) ){
    +@@ -176246,16 +198777,11 @@ static void fts5FlushOneHash(Fts5Index *p){
    +         ** loop iterates through the poslists that make up the current 
    +         ** doclist.  */
    +         while( p->rc==SQLITE_OK && iOff<nDoclist ){
    +-          int nPos;
    +-          int nCopy;
    +-          int bDummy;
    +           iOff += fts5GetVarint(&pDoclist[iOff], (u64*)&iDelta);
    +-          nCopy = fts5GetPoslistSize(&pDoclist[iOff], &nPos, &bDummy);
    +-          nCopy += nPos;
    +           iRowid += iDelta;
    +           
    +           if( writer.bFirstRowidInPage ){
    +-            fts5PutU16(&pBuf->p[0], pBuf->n);   /* first rowid on page */
    ++            fts5PutU16(&pBuf->p[0], (u16)pBuf->n);   /* first rowid on page */
    +             pBuf->n += sqlite3Fts5PutVarint(&pBuf->p[pBuf->n], iRowid);
    +             writer.bFirstRowidInPage = 0;
    +             fts5WriteDlidxAppend(p, &writer, iRowid);
    +@@ -176264,34 +198790,52 @@ static void fts5FlushOneHash(Fts5Index *p){
    +           }
    +           assert( pBuf->n<=pBuf->nSpace );
    + 
    +-          if( (pBuf->n + pPgidx->n + nCopy) <= pgsz ){
    +-            /* The entire poslist will fit on the current leaf. So copy
    +-            ** it in one go. */
    +-            fts5BufferSafeAppendBlob(pBuf, &pDoclist[iOff], nCopy);
    +-          }else{
    +-            /* The entire poslist will not fit on this leaf. So it needs
    +-            ** to be broken into sections. The only qualification being
    +-            ** that each varint must be stored contiguously.  */
    +-            const u8 *pPoslist = &pDoclist[iOff];
    +-            int iPos = 0;
    +-            while( p->rc==SQLITE_OK ){
    +-              int nSpace = pgsz - pBuf->n - pPgidx->n;
    +-              int n = 0;
    +-              if( (nCopy - iPos)<=nSpace ){
    +-                n = nCopy - iPos;
    +-              }else{
    +-                n = fts5PoslistPrefix(&pPoslist[iPos], nSpace);
    ++          if( eDetail==FTS5_DETAIL_NONE ){
    ++            if( iOff<nDoclist && pDoclist[iOff]==0 ){
    ++              pBuf->p[pBuf->n++] = 0;
    ++              iOff++;
    ++              if( iOff<nDoclist && pDoclist[iOff]==0 ){
    ++                pBuf->p[pBuf->n++] = 0;
    ++                iOff++;
    +               }
    +-              assert( n>0 );
    +-              fts5BufferSafeAppendBlob(pBuf, &pPoslist[iPos], n);
    +-              iPos += n;
    +-              if( (pBuf->n + pPgidx->n)>=pgsz ){
    +-                fts5WriteFlushLeaf(p, &writer);
    ++            }
    ++            if( (pBuf->n + pPgidx->n)>=pgsz ){
    ++              fts5WriteFlushLeaf(p, &writer);
    ++            }
    ++          }else{
    ++            int bDummy;
    ++            int nPos;
    ++            int nCopy = fts5GetPoslistSize(&pDoclist[iOff], &nPos, &bDummy);
    ++            nCopy += nPos;
    ++            if( (pBuf->n + pPgidx->n + nCopy) <= pgsz ){
    ++              /* The entire poslist will fit on the current leaf. So copy
    ++              ** it in one go. */
    ++              fts5BufferSafeAppendBlob(pBuf, &pDoclist[iOff], nCopy);
    ++            }else{
    ++              /* The entire poslist will not fit on this leaf. So it needs
    ++              ** to be broken into sections. The only qualification being
    ++              ** that each varint must be stored contiguously.  */
    ++              const u8 *pPoslist = &pDoclist[iOff];
    ++              int iPos = 0;
    ++              while( p->rc==SQLITE_OK ){
    ++                int nSpace = pgsz - pBuf->n - pPgidx->n;
    ++                int n = 0;
    ++                if( (nCopy - iPos)<=nSpace ){
    ++                  n = nCopy - iPos;
    ++                }else{
    ++                  n = fts5PoslistPrefix(&pPoslist[iPos], nSpace);
    ++                }
    ++                assert( n>0 );
    ++                fts5BufferSafeAppendBlob(pBuf, &pPoslist[iPos], n);
    ++                iPos += n;
    ++                if( (pBuf->n + pPgidx->n)>=pgsz ){
    ++                  fts5WriteFlushLeaf(p, &writer);
    ++                }
    ++                if( iPos>=nCopy ) break;
    +               }
    +-              if( iPos>=nCopy ) break;
    +             }
    ++            iOff += nCopy;
    +           }
    +-          iOff += nCopy;
    +         }
    +       }
    + 
    +@@ -176337,28 +198881,41 @@ static void fts5IndexFlush(Fts5Index *p){
    +   }
    + }
    + 
    +-
    +-static int sqlite3Fts5IndexOptimize(Fts5Index *p){
    +-  Fts5Structure *pStruct;
    ++static Fts5Structure *fts5IndexOptimizeStruct(
    ++  Fts5Index *p, 
    ++  Fts5Structure *pStruct
    ++){
    +   Fts5Structure *pNew = 0;
    +-  int nSeg = 0;
    +-
    +-  assert( p->rc==SQLITE_OK );
    +-  fts5IndexFlush(p);
    +-  pStruct = fts5StructureRead(p);
    ++  int nByte = sizeof(Fts5Structure);
    ++  int nSeg = pStruct->nSegment;
    ++  int i;
    + 
    +-  if( pStruct ){
    +-    assert( pStruct->nSegment==fts5StructureCountSegments(pStruct) );
    +-    nSeg = pStruct->nSegment;
    +-    if( nSeg>1 ){
    +-      int nByte = sizeof(Fts5Structure);
    +-      nByte += (pStruct->nLevel+1) * sizeof(Fts5StructureLevel);
    +-      pNew = (Fts5Structure*)sqlite3Fts5MallocZero(&p->rc, nByte);
    ++  /* Figure out if this structure requires optimization. A structure does
    ++  ** not require optimization if either:
    ++  **
    ++  **  + it consists of fewer than two segments, or 
    ++  **  + all segments are on the same level, or
    ++  **  + all segments except one are currently inputs to a merge operation.
    ++  **
    ++  ** In the first case, return NULL. In the second, increment the ref-count
    ++  ** on *pStruct and return a copy of the pointer to it.
    ++  */
    ++  if( nSeg<2 ) return 0;
    ++  for(i=0; i<pStruct->nLevel; i++){
    ++    int nThis = pStruct->aLevel[i].nSeg;
    ++    if( nThis==nSeg || (nThis==nSeg-1 && pStruct->aLevel[i].nMerge==nThis) ){
    ++      fts5StructureRef(pStruct);
    ++      return pStruct;
    +     }
    ++    assert( pStruct->aLevel[i].nMerge<=nThis );
    +   }
    ++
    ++  nByte += (pStruct->nLevel+1) * sizeof(Fts5StructureLevel);
    ++  pNew = (Fts5Structure*)sqlite3Fts5MallocZero(&p->rc, nByte);
    ++
    +   if( pNew ){
    +     Fts5StructureLevel *pLvl;
    +-    int nByte = nSeg * sizeof(Fts5StructureSegment);
    ++    nByte = nSeg * sizeof(Fts5StructureSegment);
    +     pNew->nLevel = pStruct->nLevel+1;
    +     pNew->nRef = 1;
    +     pNew->nWriteCounter = pStruct->nWriteCounter;
    +@@ -176367,7 +198924,10 @@ static int sqlite3Fts5IndexOptimize(Fts5Index *p){
    +     if( pLvl->aSeg ){
    +       int iLvl, iSeg;
    +       int iSegOut = 0;
    +-      for(iLvl=0; iLvl<pStruct->nLevel; iLvl++){
    ++      /* Iterate through all segments, from oldest to newest. Add them to
    ++      ** the new Fts5Level object so that pLvl->aSeg[0] is the oldest
    ++      ** segment in the data structure.  */
    ++      for(iLvl=pStruct->nLevel-1; iLvl>=0; iLvl--){
    +         for(iSeg=0; iSeg<pStruct->aLevel[iLvl].nSeg; iSeg++){
    +           pLvl->aSeg[iSegOut] = pStruct->aLevel[iLvl].aSeg[iSeg];
    +           iSegOut++;
    +@@ -176380,8 +198940,27 @@ static int sqlite3Fts5IndexOptimize(Fts5Index *p){
    +     }
    +   }
    + 
    ++  return pNew;
    ++}
    ++
    ++static int sqlite3Fts5IndexOptimize(Fts5Index *p){
    ++  Fts5Structure *pStruct;
    ++  Fts5Structure *pNew = 0;
    ++
    ++  assert( p->rc==SQLITE_OK );
    ++  fts5IndexFlush(p);
    ++  pStruct = fts5StructureRead(p);
    ++  fts5StructureInvalidate(p);
    ++
    ++  if( pStruct ){
    ++    pNew = fts5IndexOptimizeStruct(p, pStruct);
    ++  }
    ++  fts5StructureRelease(pStruct);
    ++
    ++  assert( pNew==0 || pNew->nSegment>0 );
    +   if( pNew ){
    +-    int iLvl = pNew->nLevel-1;
    ++    int iLvl;
    ++    for(iLvl=0; pNew->aLevel[iLvl].nSeg==0; iLvl++){}
    +     while( p->rc==SQLITE_OK && pNew->aLevel[iLvl].nSeg>0 ){
    +       int nRem = FTS5_OPT_WORK_UNIT;
    +       fts5IndexMergeLevel(p, &pNew, iLvl, &nRem);
    +@@ -176391,240 +198970,61 @@ static int sqlite3Fts5IndexOptimize(Fts5Index *p){
    +     fts5StructureRelease(pNew);
    +   }
    + 
    +-  fts5StructureRelease(pStruct);
    +   return fts5IndexReturn(p); 
    + }
    + 
    +-static int sqlite3Fts5IndexMerge(Fts5Index *p, int nMerge){
    +-  Fts5Structure *pStruct;
    +-
    +-  pStruct = fts5StructureRead(p);
    +-  if( pStruct && pStruct->nLevel ){
    +-    fts5IndexMerge(p, &pStruct, nMerge);
    +-    fts5StructureWrite(p, pStruct);
    +-  }
    +-  fts5StructureRelease(pStruct);
    +-
    +-  return fts5IndexReturn(p);
    +-}
    +-
    +-static void fts5PoslistCallback(
    +-  Fts5Index *p, 
    +-  void *pContext, 
    +-  const u8 *pChunk, int nChunk
    +-){
    +-  assert_nc( nChunk>=0 );
    +-  if( nChunk>0 ){
    +-    fts5BufferSafeAppendBlob((Fts5Buffer*)pContext, pChunk, nChunk);
    +-  }
    +-}
    +-
    +-typedef struct PoslistCallbackCtx PoslistCallbackCtx;
    +-struct PoslistCallbackCtx {
    +-  Fts5Buffer *pBuf;               /* Append to this buffer */
    +-  Fts5Colset *pColset;            /* Restrict matches to this column */
    +-  int eState;                     /* See above */
    +-};
    +-
    + /*
    +-** TODO: Make this more efficient!
    ++** This is called to implement the special "VALUES('merge', $nMerge)"
    ++** INSERT command.
    + */
    +-static int fts5IndexColsetTest(Fts5Colset *pColset, int iCol){
    +-  int i;
    +-  for(i=0; i<pColset->nCol; i++){
    +-    if( pColset->aiCol[i]==iCol ) return 1;
    +-  }
    +-  return 0;
    +-}
    +-
    +-static void fts5PoslistFilterCallback(
    +-  Fts5Index *p, 
    +-  void *pContext, 
    +-  const u8 *pChunk, int nChunk
    +-){
    +-  PoslistCallbackCtx *pCtx = (PoslistCallbackCtx*)pContext;
    +-  assert_nc( nChunk>=0 );
    +-  if( nChunk>0 ){
    +-    /* Search through to find the first varint with value 1. This is the
    +-    ** start of the next columns hits. */
    +-    int i = 0;
    +-    int iStart = 0;
    +-
    +-    if( pCtx->eState==2 ){
    +-      int iCol;
    +-      fts5FastGetVarint32(pChunk, i, iCol);
    +-      if( fts5IndexColsetTest(pCtx->pColset, iCol) ){
    +-        pCtx->eState = 1;
    +-        fts5BufferSafeAppendVarint(pCtx->pBuf, 1);
    +-      }else{
    +-        pCtx->eState = 0;
    +-      }
    ++static int sqlite3Fts5IndexMerge(Fts5Index *p, int nMerge){
    ++  Fts5Structure *pStruct = fts5StructureRead(p);
    ++  if( pStruct ){
    ++    int nMin = p->pConfig->nUsermerge;
    ++    fts5StructureInvalidate(p);
    ++    if( nMerge<0 ){
    ++      Fts5Structure *pNew = fts5IndexOptimizeStruct(p, pStruct);
    ++      fts5StructureRelease(pStruct);
    ++      pStruct = pNew;
    ++      nMin = 2;
    ++      nMerge = nMerge*-1;
    +     }
    +-
    +-    do {
    +-      while( i<nChunk && pChunk[i]!=0x01 ){
    +-        while( pChunk[i] & 0x80 ) i++;
    +-        i++;
    +-      }
    +-      if( pCtx->eState ){
    +-        fts5BufferSafeAppendBlob(pCtx->pBuf, &pChunk[iStart], i-iStart);
    +-      }
    +-      if( i<nChunk ){
    +-        int iCol;
    +-        iStart = i;
    +-        i++;
    +-        if( i>=nChunk ){
    +-          pCtx->eState = 2;
    +-        }else{
    +-          fts5FastGetVarint32(pChunk, i, iCol);
    +-          pCtx->eState = fts5IndexColsetTest(pCtx->pColset, iCol);
    +-          if( pCtx->eState ){
    +-            fts5BufferSafeAppendBlob(pCtx->pBuf, &pChunk[iStart], i-iStart);
    +-            iStart = i;
    +-          }
    +-        }
    ++    if( pStruct && pStruct->nLevel ){
    ++      if( fts5IndexMerge(p, &pStruct, nMerge, nMin) ){
    ++        fts5StructureWrite(p, pStruct);
    +       }
    +-    }while( i<nChunk );
    ++    }
    ++    fts5StructureRelease(pStruct);
    +   }
    ++  return fts5IndexReturn(p);
    + }
    + 
    +-/*
    +-** Iterator pIter currently points to a valid entry (not EOF). This
    +-** function appends the position list data for the current entry to
    +-** buffer pBuf. It does not make a copy of the position-list size
    +-** field.
    +-*/
    +-static void fts5SegiterPoslist(
    ++static void fts5AppendRowid(
    +   Fts5Index *p,
    +-  Fts5SegIter *pSeg,
    +-  Fts5Colset *pColset,
    ++  i64 iDelta,
    ++  Fts5Iter *pUnused,
    +   Fts5Buffer *pBuf
    + ){
    +-  if( 0==fts5BufferGrow(&p->rc, pBuf, pSeg->nPos) ){
    +-    if( pColset==0 ){
    +-      fts5ChunkIterate(p, pSeg, (void*)pBuf, fts5PoslistCallback);
    +-    }else{
    +-      PoslistCallbackCtx sCtx;
    +-      sCtx.pBuf = pBuf;
    +-      sCtx.pColset = pColset;
    +-      sCtx.eState = pColset ? fts5IndexColsetTest(pColset, 0) : 1;
    +-      assert( sCtx.eState==0 || sCtx.eState==1 );
    +-      fts5ChunkIterate(p, pSeg, (void*)&sCtx, fts5PoslistFilterCallback);
    +-    }
    +-  }
    ++  UNUSED_PARAM(pUnused);
    ++  fts5BufferAppendVarint(&p->rc, pBuf, iDelta);
    + }
    + 
    +-/*
    +-** IN/OUT parameter (*pa) points to a position list n bytes in size. If
    +-** the position list contains entries for column iCol, then (*pa) is set
    +-** to point to the sub-position-list for that column and the number of
    +-** bytes in it returned. Or, if the argument position list does not
    +-** contain any entries for column iCol, return 0.
    +-*/
    +-static int fts5IndexExtractCol(
    +-  const u8 **pa,                  /* IN/OUT: Pointer to poslist */
    +-  int n,                          /* IN: Size of poslist in bytes */
    +-  int iCol                        /* Column to extract from poslist */
    +-){
    +-  int iCurrent = 0;               /* Anything before the first 0x01 is col 0 */
    +-  const u8 *p = *pa;
    +-  const u8 *pEnd = &p[n];         /* One byte past end of position list */
    +-  u8 prev = 0;
    +-
    +-  while( iCol!=iCurrent ){
    +-    /* Advance pointer p until it points to pEnd or an 0x01 byte that is
    +-    ** not part of a varint */
    +-    while( (prev & 0x80) || *p!=0x01 ){
    +-      prev = *p++;
    +-      if( p==pEnd ) return 0;
    +-    }
    +-    *pa = p++;
    +-    p += fts5GetVarint32(p, iCurrent);
    +-  }
    +-
    +-  /* Advance pointer p until it points to pEnd or an 0x01 byte that is
    +-  ** not part of a varint */
    +-  assert( (prev & 0x80)==0 );
    +-  while( p<pEnd && ((prev & 0x80) || *p!=0x01) ){
    +-    prev = *p++;
    +-  }
    +-  return p - (*pa);
    +-}
    +-
    +-
    +-/*
    +-** Iterator pMulti currently points to a valid entry (not EOF). This
    +-** function appends the following to buffer pBuf:
    +-**
    +-**   * The varint iDelta, and
    +-**   * the position list that currently points to, including the size field.
    +-**
    +-** If argument pColset is NULL, then the position list is filtered according
    +-** to pColset before being appended to the buffer. If this means there are
    +-** no entries in the position list, nothing is appended to the buffer (not
    +-** even iDelta).
    +-**
    +-** If an error occurs, an error code is left in p->rc. 
    +-*/
    +-static int fts5AppendPoslist(
    ++static void fts5AppendPoslist(
    +   Fts5Index *p,
    +   i64 iDelta,
    +-  Fts5IndexIter *pMulti,
    +-  Fts5Colset *pColset,
    ++  Fts5Iter *pMulti,
    +   Fts5Buffer *pBuf
    + ){
    +-  if( p->rc==SQLITE_OK ){
    +-    Fts5SegIter *pSeg = &pMulti->aSeg[ pMulti->aFirst[1].iFirst ];
    +-    assert( fts5MultiIterEof(p, pMulti)==0 );
    +-    assert( pSeg->nPos>0 );
    +-    if( 0==fts5BufferGrow(&p->rc, pBuf, pSeg->nPos+9+9) ){
    +-      int iSv1;
    +-      int iSv2;
    +-      int iData;
    +-
    +-      /* Append iDelta */
    +-      iSv1 = pBuf->n;
    +-      fts5BufferSafeAppendVarint(pBuf, iDelta);
    +-
    +-      /* WRITEPOSLISTSIZE */
    +-      iSv2 = pBuf->n;
    +-      fts5BufferSafeAppendVarint(pBuf, pSeg->nPos*2);
    +-      iData = pBuf->n;
    +-
    +-      if( pSeg->iLeafOffset+pSeg->nPos<=pSeg->pLeaf->szLeaf 
    +-       && (pColset==0 || pColset->nCol==1)
    +-      ){
    +-        const u8 *pPos = &pSeg->pLeaf->p[pSeg->iLeafOffset];
    +-        int nPos;
    +-        if( pColset ){
    +-          nPos = fts5IndexExtractCol(&pPos, pSeg->nPos, pColset->aiCol[0]);
    +-        }else{
    +-          nPos = pSeg->nPos;
    +-        }
    +-        fts5BufferSafeAppendBlob(pBuf, pPos, nPos);
    +-      }else{
    +-        fts5SegiterPoslist(p, pSeg, pColset, pBuf);
    +-      }
    +-
    +-      if( pColset ){
    +-        int nActual = pBuf->n - iData;
    +-        if( nActual!=pSeg->nPos ){
    +-          if( nActual==0 ){
    +-            pBuf->n = iSv1;
    +-            return 1;
    +-          }else{
    +-            int nReq = sqlite3Fts5GetVarintLen((u32)(nActual*2));
    +-            while( iSv2<(iData-nReq) ){ pBuf->p[iSv2++] = 0x80; }
    +-            sqlite3Fts5PutVarint(&pBuf->p[iSv2], nActual*2);
    +-          }
    +-        }
    +-      }
    +-    }
    ++  int nData = pMulti->base.nData;
    ++  assert( nData>0 );
    ++  if( p->rc==SQLITE_OK && 0==fts5BufferGrow(&p->rc, pBuf, nData+9+9) ){
    ++    fts5BufferSafeAppendVarint(pBuf, iDelta);
    ++    fts5BufferSafeAppendVarint(pBuf, nData*2);
    ++    fts5BufferSafeAppendBlob(pBuf, pMulti->base.pData, nData);
    +   }
    +-
    +-  return 0;
    + }
    + 
    ++
    + static void fts5DoclistIterNext(Fts5DoclistIter *pIter){
    +   u8 *p = pIter->aPoslist + pIter->nSize + pIter->nPoslist;
    + 
    +@@ -176685,6 +199085,69 @@ static void fts5MergeAppendDocid(
    +   (iLastRowid) = (iRowid);                                     \
    + }
    + 
    ++/*
    ++** Swap the contents of buffer *p1 with that of *p2.
    ++*/
    ++static void fts5BufferSwap(Fts5Buffer *p1, Fts5Buffer *p2){
    ++  Fts5Buffer tmp = *p1;
    ++  *p1 = *p2;
    ++  *p2 = tmp;
    ++}
    ++
    ++static void fts5NextRowid(Fts5Buffer *pBuf, int *piOff, i64 *piRowid){
    ++  int i = *piOff;
    ++  if( i>=pBuf->n ){
    ++    *piOff = -1;
    ++  }else{
    ++    u64 iVal;
    ++    *piOff = i + sqlite3Fts5GetVarint(&pBuf->p[i], &iVal);
    ++    *piRowid += iVal;
    ++  }
    ++}
    ++
    ++/*
    ++** This is the equivalent of fts5MergePrefixLists() for detail=none mode.
    ++** In this case the buffers consist of a delta-encoded list of rowids only.
    ++*/
    ++static void fts5MergeRowidLists(
    ++  Fts5Index *p,                   /* FTS5 backend object */
    ++  Fts5Buffer *p1,                 /* First list to merge */
    ++  Fts5Buffer *p2                  /* Second list to merge */
    ++){
    ++  int i1 = 0;
    ++  int i2 = 0;
    ++  i64 iRowid1 = 0;
    ++  i64 iRowid2 = 0;
    ++  i64 iOut = 0;
    ++
    ++  Fts5Buffer out;
    ++  memset(&out, 0, sizeof(out));
    ++  sqlite3Fts5BufferSize(&p->rc, &out, p1->n + p2->n);
    ++  if( p->rc ) return;
    ++
    ++  fts5NextRowid(p1, &i1, &iRowid1);
    ++  fts5NextRowid(p2, &i2, &iRowid2);
    ++  while( i1>=0 || i2>=0 ){
    ++    if( i1>=0 && (i2<0 || iRowid1<iRowid2) ){
    ++      assert( iOut==0 || iRowid1>iOut );
    ++      fts5BufferSafeAppendVarint(&out, iRowid1 - iOut);
    ++      iOut = iRowid1;
    ++      fts5NextRowid(p1, &i1, &iRowid1);
    ++    }else{
    ++      assert( iOut==0 || iRowid2>iOut );
    ++      fts5BufferSafeAppendVarint(&out, iRowid2 - iOut);
    ++      iOut = iRowid2;
    ++      if( i1>=0 && iRowid1==iRowid2 ){
    ++        fts5NextRowid(p1, &i1, &iRowid1);
    ++      }
    ++      fts5NextRowid(p2, &i2, &iRowid2);
    ++    }
    ++  }
    ++
    ++  fts5BufferSwap(&out, p1);
    ++  fts5BufferFree(&out);
    ++}
    ++
    + /*
    + ** Buffers p1 and p2 contain doclists. This function merges the content
    + ** of the two doclists together and sets buffer p1 to the result before
    +@@ -176702,28 +199165,36 @@ static void fts5MergePrefixLists(
    +     i64 iLastRowid = 0;
    +     Fts5DoclistIter i1;
    +     Fts5DoclistIter i2;
    +-    Fts5Buffer out;
    +-    Fts5Buffer tmp;
    +-    memset(&out, 0, sizeof(out));
    +-    memset(&tmp, 0, sizeof(tmp));
    +-
    +-    sqlite3Fts5BufferGrow(&p->rc, &out, p1->n + p2->n);
    ++    Fts5Buffer out = {0, 0, 0};
    ++    Fts5Buffer tmp = {0, 0, 0};
    ++
    ++    /* The maximum size of the output is equal to the sum of the two 
    ++    ** input sizes + 1 varint (9 bytes). The extra varint is because if the
    ++    ** first rowid in one input is a large negative number, and the first in
    ++    ** the other a non-negative number, the delta for the non-negative
    ++    ** number will be larger on disk than the literal integer value
    ++    ** was.  */
    ++    if( sqlite3Fts5BufferSize(&p->rc, &out, p1->n + p2->n + 9) ) return;
    +     fts5DoclistIterInit(p1, &i1);
    +     fts5DoclistIterInit(p2, &i2);
    +-    while( p->rc==SQLITE_OK && (i1.aPoslist!=0 || i2.aPoslist!=0) ){
    +-      if( i2.aPoslist==0 || (i1.aPoslist && i1.iRowid<i2.iRowid) ){
    ++
    ++    while( 1 ){
    ++      if( i1.iRowid<i2.iRowid ){
    +         /* Copy entry from i1 */
    +         fts5MergeAppendDocid(&out, iLastRowid, i1.iRowid);
    +         fts5BufferSafeAppendBlob(&out, i1.aPoslist, i1.nPoslist+i1.nSize);
    +         fts5DoclistIterNext(&i1);
    ++        if( i1.aPoslist==0 ) break;
    +       }
    +-      else if( i1.aPoslist==0 || i2.iRowid!=i1.iRowid ){
    ++      else if( i2.iRowid!=i1.iRowid ){
    +         /* Copy entry from i2 */
    +         fts5MergeAppendDocid(&out, iLastRowid, i2.iRowid);
    +         fts5BufferSafeAppendBlob(&out, i2.aPoslist, i2.nPoslist+i2.nSize);
    +         fts5DoclistIterNext(&i2);
    ++        if( i2.aPoslist==0 ) break;
    +       }
    +       else{
    ++        /* Merge the two position lists. */ 
    +         i64 iPos1 = 0;
    +         i64 iPos2 = 0;
    +         int iOff1 = 0;
    +@@ -176731,29 +199202,53 @@ static void fts5MergePrefixLists(
    +         u8 *a1 = &i1.aPoslist[i1.nSize];
    +         u8 *a2 = &i2.aPoslist[i2.nSize];
    + 
    ++        i64 iPrev = 0;
    +         Fts5PoslistWriter writer;
    +         memset(&writer, 0, sizeof(writer));
    + 
    +-        /* Merge the two position lists. */ 
    +         fts5MergeAppendDocid(&out, iLastRowid, i2.iRowid);
    +         fts5BufferZero(&tmp);
    ++        sqlite3Fts5BufferSize(&p->rc, &tmp, i1.nPoslist + i2.nPoslist);
    ++        if( p->rc ) break;
    + 
    +         sqlite3Fts5PoslistNext64(a1, i1.nPoslist, &iOff1, &iPos1);
    +         sqlite3Fts5PoslistNext64(a2, i2.nPoslist, &iOff2, &iPos2);
    ++        assert( iPos1>=0 && iPos2>=0 );
    + 
    +-        while( p->rc==SQLITE_OK && (iPos1>=0 || iPos2>=0) ){
    +-          i64 iNew;
    +-          if( iPos2<0 || (iPos1>=0 && iPos1<iPos2) ){
    +-            iNew = iPos1;
    +-            sqlite3Fts5PoslistNext64(a1, i1.nPoslist, &iOff1, &iPos1);
    +-          }else{
    +-            iNew = iPos2;
    +-            sqlite3Fts5PoslistNext64(a2, i2.nPoslist, &iOff2, &iPos2);
    +-            if( iPos1==iPos2 ){
    +-              sqlite3Fts5PoslistNext64(a1, i1.nPoslist, &iOff1,&iPos1);
    ++        if( iPos1<iPos2 ){
    ++          sqlite3Fts5PoslistSafeAppend(&tmp, &iPrev, iPos1);
    ++          sqlite3Fts5PoslistNext64(a1, i1.nPoslist, &iOff1, &iPos1);
    ++        }else{
    ++          sqlite3Fts5PoslistSafeAppend(&tmp, &iPrev, iPos2);
    ++          sqlite3Fts5PoslistNext64(a2, i2.nPoslist, &iOff2, &iPos2);
    ++        }
    ++
    ++        if( iPos1>=0 && iPos2>=0 ){
    ++          while( 1 ){
    ++            if( iPos1<iPos2 ){
    ++              if( iPos1!=iPrev ){
    ++                sqlite3Fts5PoslistSafeAppend(&tmp, &iPrev, iPos1);
    ++              }
    ++              sqlite3Fts5PoslistNext64(a1, i1.nPoslist, &iOff1, &iPos1);
    ++              if( iPos1<0 ) break;
    ++            }else{
    ++              assert( iPos2!=iPrev );
    ++              sqlite3Fts5PoslistSafeAppend(&tmp, &iPrev, iPos2);
    ++              sqlite3Fts5PoslistNext64(a2, i2.nPoslist, &iOff2, &iPos2);
    ++              if( iPos2<0 ) break;
    +             }
    +           }
    +-          p->rc = sqlite3Fts5PoslistWriterAppend(&tmp, &writer, iNew);
    ++        }
    ++
    ++        if( iPos1>=0 ){
    ++          if( iPos1!=iPrev ){
    ++            sqlite3Fts5PoslistSafeAppend(&tmp, &iPrev, iPos1);
    ++          }
    ++          fts5BufferSafeAppendBlob(&tmp, &a1[iOff1], i1.nPoslist-iOff1);
    ++        }else{
    ++          assert( iPos2>=0 && iPos2!=iPrev );
    ++          sqlite3Fts5PoslistSafeAppend(&tmp, &iPrev, iPos2);
    ++          fts5BufferSafeAppendBlob(&tmp, &a2[iOff2], i2.nPoslist-iOff2);
    +         }
    + 
    +         /* WRITEPOSLISTSIZE */
    +@@ -176761,87 +199256,112 @@ static void fts5MergePrefixLists(
    +         fts5BufferSafeAppendBlob(&out, tmp.p, tmp.n);
    +         fts5DoclistIterNext(&i1);
    +         fts5DoclistIterNext(&i2);
    ++        if( i1.aPoslist==0 || i2.aPoslist==0 ) break;
    +       }
    +     }
    + 
    ++    if( i1.aPoslist ){
    ++      fts5MergeAppendDocid(&out, iLastRowid, i1.iRowid);
    ++      fts5BufferSafeAppendBlob(&out, i1.aPoslist, i1.aEof - i1.aPoslist);
    ++    }
    ++    else if( i2.aPoslist ){
    ++      fts5MergeAppendDocid(&out, iLastRowid, i2.iRowid);
    ++      fts5BufferSafeAppendBlob(&out, i2.aPoslist, i2.aEof - i2.aPoslist);
    ++    }
    ++    assert( out.n<=(p1->n+p2->n+9) );
    ++
    +     fts5BufferSet(&p->rc, p1, out.n, out.p);
    +     fts5BufferFree(&tmp);
    +     fts5BufferFree(&out);
    +   }
    + }
    + 
    +-static void fts5BufferSwap(Fts5Buffer *p1, Fts5Buffer *p2){
    +-  Fts5Buffer tmp = *p1;
    +-  *p1 = *p2;
    +-  *p2 = tmp;
    +-}
    +-
    + static void fts5SetupPrefixIter(
    +   Fts5Index *p,                   /* Index to read from */
    +   int bDesc,                      /* True for "ORDER BY rowid DESC" */
    +   const u8 *pToken,               /* Buffer containing prefix to match */
    +   int nToken,                     /* Size of buffer pToken in bytes */
    +   Fts5Colset *pColset,            /* Restrict matches to these columns */
    +-  Fts5IndexIter **ppIter          /* OUT: New iterator */
    ++  Fts5Iter **ppIter          /* OUT: New iterator */
    + ){
    +   Fts5Structure *pStruct;
    +   Fts5Buffer *aBuf;
    +   const int nBuf = 32;
    + 
    ++  void (*xMerge)(Fts5Index*, Fts5Buffer*, Fts5Buffer*);
    ++  void (*xAppend)(Fts5Index*, i64, Fts5Iter*, Fts5Buffer*);
    ++  if( p->pConfig->eDetail==FTS5_DETAIL_NONE ){
    ++    xMerge = fts5MergeRowidLists;
    ++    xAppend = fts5AppendRowid;
    ++  }else{
    ++    xMerge = fts5MergePrefixLists;
    ++    xAppend = fts5AppendPoslist;
    ++  }
    ++
    +   aBuf = (Fts5Buffer*)fts5IdxMalloc(p, sizeof(Fts5Buffer)*nBuf);
    +   pStruct = fts5StructureRead(p);
    + 
    +   if( aBuf && pStruct ){
    +-    const int flags = FTS5INDEX_QUERY_SCAN;
    ++    const int flags = FTS5INDEX_QUERY_SCAN 
    ++                    | FTS5INDEX_QUERY_SKIPEMPTY 
    ++                    | FTS5INDEX_QUERY_NOOUTPUT;
    +     int i;
    +     i64 iLastRowid = 0;
    +-    Fts5IndexIter *p1 = 0;     /* Iterator used to gather data from index */
    ++    Fts5Iter *p1 = 0;     /* Iterator used to gather data from index */
    +     Fts5Data *pData;
    +     Fts5Buffer doclist;
    ++    int bNewTerm = 1;
    + 
    +     memset(&doclist, 0, sizeof(doclist));
    +-    for(fts5MultiIterNew(p, pStruct, 1, flags, pToken, nToken, -1, 0, &p1);
    ++    fts5MultiIterNew(p, pStruct, flags, pColset, pToken, nToken, -1, 0, &p1);
    ++    fts5IterSetOutputCb(&p->rc, p1);
    ++    for( /* no-op */ ;
    +         fts5MultiIterEof(p, p1)==0;
    +-        fts5MultiIterNext(p, p1, 0, 0)
    ++        fts5MultiIterNext2(p, p1, &bNewTerm)
    +     ){
    +-      i64 iRowid = fts5MultiIterRowid(p1);
    +-      int nTerm;
    +-      const u8 *pTerm = fts5MultiIterTerm(p1, &nTerm);
    ++      Fts5SegIter *pSeg = &p1->aSeg[ p1->aFirst[1].iFirst ];
    ++      int nTerm = pSeg->term.n;
    ++      const u8 *pTerm = pSeg->term.p;
    ++      p1->xSetOutputs(p1, pSeg);
    ++
    +       assert_nc( memcmp(pToken, pTerm, MIN(nToken, nTerm))<=0 );
    +-      if( nTerm<nToken || memcmp(pToken, pTerm, nToken) ) break;
    ++      if( bNewTerm ){
    ++        if( nTerm<nToken || memcmp(pToken, pTerm, nToken) ) break;
    ++      }
    ++
    ++      if( p1->base.nData==0 ) continue;
    + 
    +-      if( doclist.n>0 && iRowid<=iLastRowid ){
    ++      if( p1->base.iRowid<=iLastRowid && doclist.n>0 ){
    +         for(i=0; p->rc==SQLITE_OK && doclist.n; i++){
    +           assert( i<nBuf );
    +           if( aBuf[i].n==0 ){
    +             fts5BufferSwap(&doclist, &aBuf[i]);
    +             fts5BufferZero(&doclist);
    +           }else{
    +-            fts5MergePrefixLists(p, &doclist, &aBuf[i]);
    ++            xMerge(p, &doclist, &aBuf[i]);
    +             fts5BufferZero(&aBuf[i]);
    +           }
    +         }
    +         iLastRowid = 0;
    +       }
    + 
    +-      if( !fts5AppendPoslist(p, iRowid-iLastRowid, p1, pColset, &doclist) ){
    +-        iLastRowid = iRowid;
    +-      }
    ++      xAppend(p, p1->base.iRowid-iLastRowid, p1, &doclist);
    ++      iLastRowid = p1->base.iRowid;
    +     }
    + 
    +     for(i=0; i<nBuf; i++){
    +       if( p->rc==SQLITE_OK ){
    +-        fts5MergePrefixLists(p, &doclist, &aBuf[i]);
    ++        xMerge(p, &doclist, &aBuf[i]);
    +       }
    +       fts5BufferFree(&aBuf[i]);
    +     }
    +-    fts5MultiIterFree(p, p1);
    ++    fts5MultiIterFree(p1);
    + 
    +     pData = fts5IdxMalloc(p, sizeof(Fts5Data) + doclist.n);
    +     if( pData ){
    +       pData->p = (u8*)&pData[1];
    +       pData->nn = pData->szLeaf = doclist.n;
    +-      memcpy(pData->p, doclist.p, doclist.n);
    ++      if( doclist.n ) memcpy(pData->p, doclist.p, doclist.n);
    +       fts5MultiIterNew2(p, pData, bDesc, ppIter);
    +     }
    +     fts5BufferFree(&doclist);
    +@@ -176861,13 +199381,13 @@ static int sqlite3Fts5IndexBeginWrite(Fts5Index *p, int bDelete, i64 iRowid){
    + 
    +   /* Allocate the hash table if it has not already been allocated */
    +   if( p->pHash==0 ){
    +-    p->rc = sqlite3Fts5HashNew(&p->pHash, &p->nPendingData);
    ++    p->rc = sqlite3Fts5HashNew(p->pConfig, &p->pHash, &p->nPendingData);
    +   }
    + 
    +   /* Flush the hash table to disk if required */
    +   if( iRowid<p->iWriteRowid 
    +    || (iRowid==p->iWriteRowid && p->bDelete==0)
    +-   || (p->nPendingData > p->nMaxPendingData) 
    ++   || (p->nPendingData > p->pConfig->nHashSize) 
    +   ){
    +     fts5IndexFlush(p);
    +   }
    +@@ -176880,10 +199400,10 @@ static int sqlite3Fts5IndexBeginWrite(Fts5Index *p, int bDelete, i64 iRowid){
    + /*
    + ** Commit data to disk.
    + */
    +-static int sqlite3Fts5IndexSync(Fts5Index *p, int bCommit){
    ++static int sqlite3Fts5IndexSync(Fts5Index *p){
    +   assert( p->rc==SQLITE_OK );
    +   fts5IndexFlush(p);
    +-  if( bCommit ) fts5CloseReader(p);
    ++  fts5CloseReader(p);
    +   return fts5IndexReturn(p);
    + }
    + 
    +@@ -176896,7 +199416,8 @@ static int sqlite3Fts5IndexSync(Fts5Index *p, int bCommit){
    + static int sqlite3Fts5IndexRollback(Fts5Index *p){
    +   fts5CloseReader(p);
    +   fts5IndexDiscardData(p);
    +-  assert( p->rc==SQLITE_OK );
    ++  fts5StructureInvalidate(p);
    ++  /* assert( p->rc==SQLITE_OK ); */
    +   return SQLITE_OK;
    + }
    + 
    +@@ -176907,6 +199428,7 @@ static int sqlite3Fts5IndexRollback(Fts5Index *p){
    + */
    + static int sqlite3Fts5IndexReinit(Fts5Index *p){
    +   Fts5Structure s;
    ++  fts5StructureInvalidate(p);
    +   memset(&s, 0, sizeof(Fts5Structure));
    +   fts5DataWrite(p, FTS5_AVERAGES_ROWID, (const u8*)"", 0);
    +   fts5StructureWrite(p, &s);
    +@@ -176933,7 +199455,6 @@ static int sqlite3Fts5IndexOpen(
    +   if( rc==SQLITE_OK ){
    +     p->pConfig = pConfig;
    +     p->nWorkUnit = FTS5_WORK_UNIT;
    +-    p->nMaxPendingData = 1024*1024;
    +     p->zDataTbl = sqlite3Fts5Mprintf(&rc, "%s_data", pConfig->zName);
    +     if( p->zDataTbl && bCreate ){
    +       rc = sqlite3Fts5CreateTable(
    +@@ -176966,11 +199487,13 @@ static int sqlite3Fts5IndexClose(Fts5Index *p){
    +   int rc = SQLITE_OK;
    +   if( p ){
    +     assert( p->pReader==0 );
    ++    fts5StructureInvalidate(p);
    +     sqlite3_finalize(p->pWriter);
    +     sqlite3_finalize(p->pDeleter);
    +     sqlite3_finalize(p->pIdxWriter);
    +     sqlite3_finalize(p->pIdxDeleter);
    +     sqlite3_finalize(p->pIdxSelect);
    ++    sqlite3_finalize(p->pDataVersion);
    +     sqlite3Fts5HashFree(p->pHash);
    +     sqlite3_free(p->zDataTbl);
    +     sqlite3_free(p);
    +@@ -176983,7 +199506,11 @@ static int sqlite3Fts5IndexClose(Fts5Index *p){
    + ** size. Return the number of bytes in the nChar character prefix of the
    + ** buffer, or 0 if there are less than nChar characters in total.
    + */
    +-static int fts5IndexCharlenToBytelen(const char *p, int nByte, int nChar){
    ++static int sqlite3Fts5IndexCharlenToBytelen(
    ++  const char *p, 
    ++  int nByte, 
    ++  int nChar
    ++){
    +   int n = 0;
    +   int i;
    +   for(i=0; i<nChar; i++){
    +@@ -177040,10 +199567,12 @@ static int sqlite3Fts5IndexWrite(
    +   );
    + 
    +   for(i=0; i<pConfig->nPrefix && rc==SQLITE_OK; i++){
    +-    int nByte = fts5IndexCharlenToBytelen(pToken, nToken, pConfig->aPrefix[i]);
    ++    const int nChar = pConfig->aPrefix[i];
    ++    int nByte = sqlite3Fts5IndexCharlenToBytelen(pToken, nToken, nChar);
    +     if( nByte ){
    +       rc = sqlite3Fts5HashWrite(p->pHash, 
    +-          p->iWriteRowid, iCol, iPos, FTS5_MAIN_PREFIX+i+1, pToken, nByte
    ++          p->iWriteRowid, iCol, iPos, (char)(FTS5_MAIN_PREFIX+i+1), pToken,
    ++          nByte
    +       );
    +     }
    +   }
    +@@ -177063,24 +199592,27 @@ static int sqlite3Fts5IndexQuery(
    +   Fts5IndexIter **ppIter          /* OUT: New iterator object */
    + ){
    +   Fts5Config *pConfig = p->pConfig;
    +-  Fts5IndexIter *pRet = 0;
    +-  int iIdx = 0;
    ++  Fts5Iter *pRet = 0;
    +   Fts5Buffer buf = {0, 0, 0};
    + 
    +   /* If the QUERY_SCAN flag is set, all other flags must be clear. */
    +-  assert( (flags & FTS5INDEX_QUERY_SCAN)==0
    +-       || (flags & FTS5INDEX_QUERY_SCAN)==FTS5INDEX_QUERY_SCAN
    +-  );
    ++  assert( (flags & FTS5INDEX_QUERY_SCAN)==0 || flags==FTS5INDEX_QUERY_SCAN );
    + 
    +-  if( sqlite3Fts5BufferGrow(&p->rc, &buf, nToken+1)==0 ){
    +-    memcpy(&buf.p[1], pToken, nToken);
    ++  if( sqlite3Fts5BufferSize(&p->rc, &buf, nToken+1)==0 ){
    ++    int iIdx = 0;                 /* Index to search */
    ++    if( nToken ) memcpy(&buf.p[1], pToken, nToken);
    + 
    +-#ifdef SQLITE_DEBUG
    +-    /* If the QUERY_TEST_NOIDX flag was specified, then this must be a
    ++    /* Figure out which index to search and set iIdx accordingly. If this
    ++    ** is a prefix query for which there is no prefix index, set iIdx to
    ++    ** greater than pConfig->nPrefix to indicate that the query will be
    ++    ** satisfied by scanning multiple terms in the main index.
    ++    **
    ++    ** If the QUERY_TEST_NOIDX flag was specified, then this must be a
    +     ** prefix-query. Instead of using a prefix-index (if one exists), 
    +     ** evaluate the prefix query using the main FTS index. This is used
    +     ** for internal sanity checking by the integrity-check in debug 
    +     ** mode only.  */
    ++#ifdef SQLITE_DEBUG
    +     if( pConfig->bPrefixIndex==0 || (flags & FTS5INDEX_QUERY_TEST_NOIDX) ){
    +       assert( flags & FTS5INDEX_QUERY_PREFIX );
    +       iIdx = 1+pConfig->nPrefix;
    +@@ -177094,24 +199626,35 @@ static int sqlite3Fts5IndexQuery(
    +     }
    + 
    +     if( iIdx<=pConfig->nPrefix ){
    ++      /* Straight index lookup */
    +       Fts5Structure *pStruct = fts5StructureRead(p);
    +-      buf.p[0] = FTS5_MAIN_PREFIX + iIdx;
    ++      buf.p[0] = (u8)(FTS5_MAIN_PREFIX + iIdx);
    +       if( pStruct ){
    +-        fts5MultiIterNew(p, pStruct, 1, flags, buf.p, nToken+1, -1, 0, &pRet);
    ++        fts5MultiIterNew(p, pStruct, flags | FTS5INDEX_QUERY_SKIPEMPTY, 
    ++            pColset, buf.p, nToken+1, -1, 0, &pRet
    ++        );
    +         fts5StructureRelease(pStruct);
    +       }
    +     }else{
    ++      /* Scan multiple terms in the main index */
    +       int bDesc = (flags & FTS5INDEX_QUERY_DESC)!=0;
    +       buf.p[0] = FTS5_MAIN_PREFIX;
    +       fts5SetupPrefixIter(p, bDesc, buf.p, nToken+1, pColset, &pRet);
    ++      assert( p->rc!=SQLITE_OK || pRet->pColset==0 );
    ++      fts5IterSetOutputCb(&p->rc, pRet);
    ++      if( p->rc==SQLITE_OK ){
    ++        Fts5SegIter *pSeg = &pRet->aSeg[pRet->aFirst[1].iFirst];
    ++        if( pSeg->pLeaf ) pRet->xSetOutputs(pRet, pSeg);
    ++      }
    +     }
    + 
    +     if( p->rc ){
    +-      sqlite3Fts5IterClose(pRet);
    ++      sqlite3Fts5IterClose((Fts5IndexIter*)pRet);
    +       pRet = 0;
    +       fts5CloseReader(p);
    +     }
    +-    *ppIter = pRet;
    ++
    ++    *ppIter = &pRet->base;
    +     sqlite3Fts5BufferFree(&buf);
    +   }
    +   return fts5IndexReturn(p);
    +@@ -177120,15 +199663,11 @@ static int sqlite3Fts5IndexQuery(
    + /*
    + ** Return true if the iterator passed as the only argument is at EOF.
    + */
    +-static int sqlite3Fts5IterEof(Fts5IndexIter *pIter){
    +-  assert( pIter->pIndex->rc==SQLITE_OK );
    +-  return pIter->bEof;
    +-}
    +-
    + /*
    + ** Move to the next matching rowid. 
    + */
    +-static int sqlite3Fts5IterNext(Fts5IndexIter *pIter){
    ++static int sqlite3Fts5IterNext(Fts5IndexIter *pIndexIter){
    ++  Fts5Iter *pIter = (Fts5Iter*)pIndexIter;
    +   assert( pIter->pIndex->rc==SQLITE_OK );
    +   fts5MultiIterNext(pIter->pIndex, pIter, 0, 0);
    +   return fts5IndexReturn(pIter->pIndex);
    +@@ -177137,7 +199676,8 @@ static int sqlite3Fts5IterNext(Fts5IndexIter *pIter){
    + /*
    + ** Move to the next matching term/rowid. Used by the fts5vocab module.
    + */
    +-static int sqlite3Fts5IterNextScan(Fts5IndexIter *pIter){
    ++static int sqlite3Fts5IterNextScan(Fts5IndexIter *pIndexIter){
    ++  Fts5Iter *pIter = (Fts5Iter*)pIndexIter;
    +   Fts5Index *p = pIter->pIndex;
    + 
    +   assert( pIter->pIndex->rc==SQLITE_OK );
    +@@ -177148,7 +199688,7 @@ static int sqlite3Fts5IterNextScan(Fts5IndexIter *pIter){
    +     if( pSeg->pLeaf && pSeg->term.p[0]!=FTS5_MAIN_PREFIX ){
    +       fts5DataRelease(pSeg->pLeaf);
    +       pSeg->pLeaf = 0;
    +-      pIter->bEof = 1;
    ++      pIter->base.bEof = 1;
    +     }
    +   }
    + 
    +@@ -177160,111 +199700,30 @@ static int sqlite3Fts5IterNextScan(Fts5IndexIter *pIter){
    + ** definition of "at or after" depends on whether this iterator iterates
    + ** in ascending or descending rowid order.
    + */
    +-static int sqlite3Fts5IterNextFrom(Fts5IndexIter *pIter, i64 iMatch){
    ++static int sqlite3Fts5IterNextFrom(Fts5IndexIter *pIndexIter, i64 iMatch){
    ++  Fts5Iter *pIter = (Fts5Iter*)pIndexIter;
    +   fts5MultiIterNextFrom(pIter->pIndex, pIter, iMatch);
    +   return fts5IndexReturn(pIter->pIndex);
    + }
    + 
    +-/*
    +-** Return the current rowid.
    +-*/
    +-static i64 sqlite3Fts5IterRowid(Fts5IndexIter *pIter){
    +-  return fts5MultiIterRowid(pIter);
    +-}
    +-
    + /*
    + ** Return the current term.
    + */
    +-static const char *sqlite3Fts5IterTerm(Fts5IndexIter *pIter, int *pn){
    ++static const char *sqlite3Fts5IterTerm(Fts5IndexIter *pIndexIter, int *pn){
    +   int n;
    +-  const char *z = (const char*)fts5MultiIterTerm(pIter, &n);
    ++  const char *z = (const char*)fts5MultiIterTerm((Fts5Iter*)pIndexIter, &n);
    +   *pn = n-1;
    +   return &z[1];
    + }
    + 
    +-
    +-static int fts5IndexExtractColset (
    +-  Fts5Colset *pColset,            /* Colset to filter on */
    +-  const u8 *pPos, int nPos,       /* Position list */
    +-  Fts5Buffer *pBuf                /* Output buffer */
    +-){
    +-  int rc = SQLITE_OK;
    +-  int i;
    +-
    +-  fts5BufferZero(pBuf);
    +-  for(i=0; i<pColset->nCol; i++){
    +-    const u8 *pSub = pPos;
    +-    int nSub = fts5IndexExtractCol(&pSub, nPos, pColset->aiCol[i]);
    +-    if( nSub ){
    +-      fts5BufferAppendBlob(&rc, pBuf, nSub, pSub);
    +-    }
    +-  }
    +-  return rc;
    +-}
    +-
    +-
    +-/*
    +-** Return a pointer to a buffer containing a copy of the position list for
    +-** the current entry. Output variable *pn is set to the size of the buffer 
    +-** in bytes before returning.
    +-**
    +-** The returned position list does not include the "number of bytes" varint
    +-** field that starts the position list on disk.
    +-*/
    +-static int sqlite3Fts5IterPoslist(
    +-  Fts5IndexIter *pIter, 
    +-  Fts5Colset *pColset,            /* Column filter (or NULL) */
    +-  const u8 **pp,                  /* OUT: Pointer to position-list data */
    +-  int *pn,                        /* OUT: Size of position-list in bytes */
    +-  i64 *piRowid                    /* OUT: Current rowid */
    +-){
    +-  Fts5SegIter *pSeg = &pIter->aSeg[ pIter->aFirst[1].iFirst ];
    +-  assert( pIter->pIndex->rc==SQLITE_OK );
    +-  *piRowid = pSeg->iRowid;
    +-  if( pSeg->iLeafOffset+pSeg->nPos<=pSeg->pLeaf->szLeaf ){
    +-    u8 *pPos = &pSeg->pLeaf->p[pSeg->iLeafOffset];
    +-    if( pColset==0 || pIter->bFiltered ){
    +-      *pn = pSeg->nPos;
    +-      *pp = pPos;
    +-    }else if( pColset->nCol==1 ){
    +-      *pp = pPos;
    +-      *pn = fts5IndexExtractCol(pp, pSeg->nPos, pColset->aiCol[0]);
    +-    }else{
    +-      fts5BufferZero(&pIter->poslist);
    +-      fts5IndexExtractColset(pColset, pPos, pSeg->nPos, &pIter->poslist);
    +-      *pp = pIter->poslist.p;
    +-      *pn = pIter->poslist.n;
    +-    }
    +-  }else{
    +-    fts5BufferZero(&pIter->poslist);
    +-    fts5SegiterPoslist(pIter->pIndex, pSeg, pColset, &pIter->poslist);
    +-    *pp = pIter->poslist.p;
    +-    *pn = pIter->poslist.n;
    +-  }
    +-  return fts5IndexReturn(pIter->pIndex);
    +-}
    +-
    +-/*
    +-** This function is similar to sqlite3Fts5IterPoslist(), except that it
    +-** copies the position list into the buffer supplied as the second 
    +-** argument.
    +-*/
    +-static int sqlite3Fts5IterPoslistBuffer(Fts5IndexIter *pIter, Fts5Buffer *pBuf){
    +-  Fts5Index *p = pIter->pIndex;
    +-  Fts5SegIter *pSeg = &pIter->aSeg[ pIter->aFirst[1].iFirst ];
    +-  assert( p->rc==SQLITE_OK );
    +-  fts5BufferZero(pBuf);
    +-  fts5SegiterPoslist(p, pSeg, 0, pBuf);
    +-  return fts5IndexReturn(p);
    +-}
    +-
    + /*
    + ** Close an iterator opened by an earlier call to sqlite3Fts5IndexQuery().
    + */
    +-static void sqlite3Fts5IterClose(Fts5IndexIter *pIter){
    +-  if( pIter ){
    ++static void sqlite3Fts5IterClose(Fts5IndexIter *pIndexIter){
    ++  if( pIndexIter ){
    ++    Fts5Iter *pIter = (Fts5Iter*)pIndexIter;
    +     Fts5Index *pIndex = pIter->pIndex;
    +-    fts5MultiIterFree(pIter->pIndex, pIter);
    ++    fts5MultiIterFree(pIter);
    +     fts5CloseReader(pIndex);
    +   }
    + }
    +@@ -177357,7 +199816,7 @@ static int sqlite3Fts5IndexLoadConfig(Fts5Index *p){
    + /*
    + ** Return a simple checksum value based on the arguments.
    + */
    +-static u64 fts5IndexEntryCksum(
    ++static u64 sqlite3Fts5IndexEntryCksum(
    +   i64 iRowid, 
    +   int iCol, 
    +   int iPos, 
    +@@ -177427,30 +199886,32 @@ static int fts5QueryCksum(
    +   int flags,                      /* Flags for Fts5IndexQuery */
    +   u64 *pCksum                     /* IN/OUT: Checksum value */
    + ){
    ++  int eDetail = p->pConfig->eDetail;
    +   u64 cksum = *pCksum;
    +-  Fts5IndexIter *pIdxIter = 0;
    +-  int rc = sqlite3Fts5IndexQuery(p, z, n, flags, 0, &pIdxIter);
    ++  Fts5IndexIter *pIter = 0;
    ++  int rc = sqlite3Fts5IndexQuery(p, z, n, flags, 0, &pIter);
    + 
    +-  while( rc==SQLITE_OK && 0==sqlite3Fts5IterEof(pIdxIter) ){
    +-    i64 dummy;
    +-    const u8 *pPos;
    +-    int nPos;
    +-    i64 rowid = sqlite3Fts5IterRowid(pIdxIter);
    +-    rc = sqlite3Fts5IterPoslist(pIdxIter, 0, &pPos, &nPos, &dummy);
    +-    if( rc==SQLITE_OK ){
    ++  while( rc==SQLITE_OK && 0==sqlite3Fts5IterEof(pIter) ){
    ++    i64 rowid = pIter->iRowid;
    ++
    ++    if( eDetail==FTS5_DETAIL_NONE ){
    ++      cksum ^= sqlite3Fts5IndexEntryCksum(rowid, 0, 0, iIdx, z, n);
    ++    }else{
    +       Fts5PoslistReader sReader;
    +-      for(sqlite3Fts5PoslistReaderInit(pPos, nPos, &sReader);
    ++      for(sqlite3Fts5PoslistReaderInit(pIter->pData, pIter->nData, &sReader);
    +           sReader.bEof==0;
    +           sqlite3Fts5PoslistReaderNext(&sReader)
    +       ){
    +         int iCol = FTS5_POS2COLUMN(sReader.iPos);
    +         int iOff = FTS5_POS2OFFSET(sReader.iPos);
    +-        cksum ^= fts5IndexEntryCksum(rowid, iCol, iOff, iIdx, z, n);
    ++        cksum ^= sqlite3Fts5IndexEntryCksum(rowid, iCol, iOff, iIdx, z, n);
    +       }
    +-      rc = sqlite3Fts5IterNext(pIdxIter);
    ++    }
    ++    if( rc==SQLITE_OK ){
    ++      rc = sqlite3Fts5IterNext(pIter);
    +     }
    +   }
    +-  sqlite3Fts5IterClose(pIdxIter);
    ++  sqlite3Fts5IterClose(pIter);
    + 
    +   *pCksum = cksum;
    +   return rc;
    +@@ -177638,7 +200099,7 @@ static void fts5IndexIntegrityCheckSegment(
    +     ** ignore this b-tree entry. Otherwise, load it into memory. */
    +     if( iIdxLeaf<pSeg->pgnoFirst ) continue;
    +     iRow = FTS5_SEGMENT_ROWID(pSeg->iSegid, iIdxLeaf);
    +-    pLeaf = fts5DataRead(p, iRow);
    ++    pLeaf = fts5LeafRead(p, iRow);
    +     if( pLeaf==0 ) break;
    + 
    +     /* Check that the leaf contains at least one term, and that it is equal
    +@@ -177669,7 +200130,6 @@ static void fts5IndexIntegrityCheckSegment(
    +     fts5DataRelease(pLeaf);
    +     if( p->rc ) break;
    + 
    +-
    +     /* Now check that the iter.nEmpty leaves following the current leaf
    +     ** (a) exist and (b) contain no terms. */
    +     fts5IndexIntegrityCheckEmpty(
    +@@ -177745,7 +200205,7 @@ static void fts5IndexIntegrityCheckSegment(
    + /*
    + ** Run internal checks to ensure that the FTS index (a) is internally 
    + ** consistent and (b) contains entries for which the XOR of the checksums
    +-** as calculated by fts5IndexEntryCksum() is cksum.
    ++** as calculated by sqlite3Fts5IndexEntryCksum() is cksum.
    + **
    + ** Return SQLITE_CORRUPT if any of the internal checks fail, or if the
    + ** checksum does not match. Return SQLITE_OK if all checks pass without
    +@@ -177753,14 +200213,18 @@ static void fts5IndexIntegrityCheckSegment(
    + ** occurs.
    + */
    + static int sqlite3Fts5IndexIntegrityCheck(Fts5Index *p, u64 cksum){
    ++  int eDetail = p->pConfig->eDetail;
    +   u64 cksum2 = 0;                 /* Checksum based on contents of indexes */
    +   Fts5Buffer poslist = {0,0,0};   /* Buffer used to hold a poslist */
    +-  Fts5IndexIter *pIter;           /* Used to iterate through entire index */
    ++  Fts5Iter *pIter;                /* Used to iterate through entire index */
    +   Fts5Structure *pStruct;         /* Index structure */
    + 
    ++#ifdef SQLITE_DEBUG
    +   /* Used by extra internal tests only run if NDEBUG is not defined */
    +   u64 cksum3 = 0;                 /* Checksum based on contents of indexes */
    +   Fts5Buffer term = {0,0,0};      /* Buffer used to hold most recent term */
    ++#endif
    ++  const int flags = FTS5INDEX_QUERY_NOOUTPUT;
    +   
    +   /* Load the FTS index structure */
    +   pStruct = fts5StructureRead(p);
    +@@ -177789,7 +200253,7 @@ static int sqlite3Fts5IndexIntegrityCheck(Fts5Index *p, u64 cksum){
    +   ** same term is performed. cksum3 is calculated based on the entries
    +   ** extracted by these queries.
    +   */
    +-  for(fts5MultiIterNew(p, pStruct, 0, 0, 0, 0, -1, 0, &pIter);
    ++  for(fts5MultiIterNew(p, pStruct, flags, 0, 0, 0, -1, 0, &pIter);
    +       fts5MultiIterEof(p, pIter)==0;
    +       fts5MultiIterNext(p, pIter, 0, 0)
    +   ){
    +@@ -177802,53 +200266,33 @@ static int sqlite3Fts5IndexIntegrityCheck(Fts5Index *p, u64 cksum){
    +     /* If this is a new term, query for it. Update cksum3 with the results. */
    +     fts5TestTerm(p, &term, z, n, cksum2, &cksum3);
    + 
    +-    poslist.n = 0;
    +-    fts5SegiterPoslist(p, &pIter->aSeg[pIter->aFirst[1].iFirst] , 0, &poslist);
    +-    while( 0==sqlite3Fts5PoslistNext64(poslist.p, poslist.n, &iOff, &iPos) ){
    +-      int iCol = FTS5_POS2COLUMN(iPos);
    +-      int iTokOff = FTS5_POS2OFFSET(iPos);
    +-      cksum2 ^= fts5IndexEntryCksum(iRowid, iCol, iTokOff, -1, z, n);
    ++    if( eDetail==FTS5_DETAIL_NONE ){
    ++      if( 0==fts5MultiIterIsEmpty(p, pIter) ){
    ++        cksum2 ^= sqlite3Fts5IndexEntryCksum(iRowid, 0, 0, -1, z, n);
    ++      }
    ++    }else{
    ++      poslist.n = 0;
    ++      fts5SegiterPoslist(p, &pIter->aSeg[pIter->aFirst[1].iFirst], 0, &poslist);
    ++      while( 0==sqlite3Fts5PoslistNext64(poslist.p, poslist.n, &iOff, &iPos) ){
    ++        int iCol = FTS5_POS2COLUMN(iPos);
    ++        int iTokOff = FTS5_POS2OFFSET(iPos);
    ++        cksum2 ^= sqlite3Fts5IndexEntryCksum(iRowid, iCol, iTokOff, -1, z, n);
    ++      }
    +     }
    +   }
    +   fts5TestTerm(p, &term, 0, 0, cksum2, &cksum3);
    + 
    +-  fts5MultiIterFree(p, pIter);
    ++  fts5MultiIterFree(pIter);
    +   if( p->rc==SQLITE_OK && cksum!=cksum2 ) p->rc = FTS5_CORRUPT;
    + 
    +   fts5StructureRelease(pStruct);
    ++#ifdef SQLITE_DEBUG
    +   fts5BufferFree(&term);
    ++#endif
    +   fts5BufferFree(&poslist);
    +   return fts5IndexReturn(p);
    + }
    + 
    +-
    +-/*
    +-** Calculate and return a checksum that is the XOR of the index entry
    +-** checksum of all entries that would be generated by the token specified
    +-** by the final 5 arguments.
    +-*/
    +-static u64 sqlite3Fts5IndexCksum(
    +-  Fts5Config *pConfig,            /* Configuration object */
    +-  i64 iRowid,                     /* Document term appears in */
    +-  int iCol,                       /* Column term appears in */
    +-  int iPos,                       /* Position term appears in */
    +-  const char *pTerm, int nTerm    /* Term at iPos */
    +-){
    +-  u64 ret = 0;                    /* Return value */
    +-  int iIdx;                       /* For iterating through indexes */
    +-
    +-  ret = fts5IndexEntryCksum(iRowid, iCol, iPos, 0, pTerm, nTerm);
    +-
    +-  for(iIdx=0; iIdx<pConfig->nPrefix; iIdx++){
    +-    int nByte = fts5IndexCharlenToBytelen(pTerm, nTerm, pConfig->aPrefix[iIdx]);
    +-    if( nByte ){
    +-      ret ^= fts5IndexEntryCksum(iRowid, iCol, iPos, iIdx+1, pTerm, nByte);
    +-    }
    +-  }
    +-
    +-  return ret;
    +-}
    +-
    + /*************************************************************************
    + **************************************************************************
    + ** Below this point is the implementation of the fts5_decode() scalar
    +@@ -178001,8 +200445,9 @@ static int fts5DecodeDoclist(int *pRc, Fts5Buffer *pBuf, const u8 *a, int n){
    +   }
    +   while( iOff<n ){
    +     int nPos;
    +-    int bDummy;
    +-    iOff += fts5GetPoslistSize(&a[iOff], &nPos, &bDummy);
    ++    int bDel;
    ++    iOff += fts5GetPoslistSize(&a[iOff], &nPos, &bDel);
    ++    sqlite3Fts5BufferAppendPrintf(pRc, pBuf, " nPos=%d%s", nPos, bDel?"*":"");
    +     iOff += fts5DecodePoslist(pRc, pBuf, &a[iOff], MIN(n-iOff, nPos));
    +     if( iOff<n ){
    +       i64 iDelta;
    +@@ -178015,6 +200460,47 @@ static int fts5DecodeDoclist(int *pRc, Fts5Buffer *pBuf, const u8 *a, int n){
    +   return iOff;
    + }
    + 
    ++/*
    ++** This function is part of the fts5_decode() debugging function. It is 
    ++** only ever used with detail=none tables.
    ++**
    ++** Buffer (pData/nData) contains a doclist in the format used by detail=none
    ++** tables. This function appends a human-readable version of that list to
    ++** buffer pBuf.
    ++**
    ++** If *pRc is other than SQLITE_OK when this function is called, it is a
    ++** no-op. If an OOM or other error occurs within this function, *pRc is
    ++** set to an SQLite error code before returning. The final state of buffer
    ++** pBuf is undefined in this case.
    ++*/
    ++static void fts5DecodeRowidList(
    ++  int *pRc,                       /* IN/OUT: Error code */
    ++  Fts5Buffer *pBuf,               /* Buffer to append text to */
    ++  const u8 *pData, int nData      /* Data to decode list-of-rowids from */
    ++){
    ++  int i = 0;
    ++  i64 iRowid = 0;
    ++
    ++  while( i<nData ){
    ++    const char *zApp = "";
    ++    u64 iVal;
    ++    i += sqlite3Fts5GetVarint(&pData[i], &iVal);
    ++    iRowid += iVal;
    ++
    ++    if( i<nData && pData[i]==0x00 ){
    ++      i++;
    ++      if( i<nData && pData[i]==0x00 ){
    ++        i++;
    ++        zApp = "+";
    ++      }else{
    ++        zApp = "*";
    ++      }
    ++    }
    ++
    ++    sqlite3Fts5BufferAppendPrintf(pRc, pBuf, " %lld%s", iRowid, zApp);
    ++  }
    ++}
    ++
    + /*
    + ** The implementation of user-defined scalar function fts5_decode().
    + */
    +@@ -178030,8 +200516,10 @@ static void fts5DecodeFunction(
    +   Fts5Buffer s;                   /* Build up text to return here */
    +   int rc = SQLITE_OK;             /* Return code */
    +   int nSpace = 0;
    ++  int eDetailNone = (sqlite3_user_data(pCtx)!=0);
    + 
    +   assert( nArg==2 );
    ++  UNUSED_PARAM(nArg);
    +   memset(&s, 0, sizeof(Fts5Buffer));
    +   iRowid = sqlite3_value_int64(apVal[0]);
    + 
    +@@ -178071,6 +200559,54 @@ static void fts5DecodeFunction(
    +     }else{
    +       fts5DecodeStructure(&rc, &s, a, n);
    +     }
    ++  }else if( eDetailNone ){
    ++    Fts5Buffer term;              /* Current term read from page */
    ++    int szLeaf;
    ++    int iPgidxOff = szLeaf = fts5GetU16(&a[2]);
    ++    int iTermOff;
    ++    int nKeep = 0;
    ++    int iOff;
    ++
    ++    memset(&term, 0, sizeof(Fts5Buffer));
    ++
    ++    /* Decode any entries that occur before the first term. */
    ++    if( szLeaf<n ){
    ++      iPgidxOff += fts5GetVarint32(&a[iPgidxOff], iTermOff);
    ++    }else{
    ++      iTermOff = szLeaf;
    ++    }
    ++    fts5DecodeRowidList(&rc, &s, &a[4], iTermOff-4);
    ++
    ++    iOff = iTermOff;
    ++    while( iOff<szLeaf ){
    ++      int nAppend;
    ++
    ++      /* Read the term data for the next term*/
    ++      iOff += fts5GetVarint32(&a[iOff], nAppend);
    ++      term.n = nKeep;
    ++      fts5BufferAppendBlob(&rc, &term, nAppend, &a[iOff]);
    ++      sqlite3Fts5BufferAppendPrintf(
    ++          &rc, &s, " term=%.*s", term.n, (const char*)term.p
    ++      );
    ++      iOff += nAppend;
    ++
    ++      /* Figure out where the doclist for this term ends */
    ++      if( iPgidxOff<n ){
    ++        int nIncr;
    ++        iPgidxOff += fts5GetVarint32(&a[iPgidxOff], nIncr);
    ++        iTermOff += nIncr;
    ++      }else{
    ++        iTermOff = szLeaf;
    ++      }
    ++
    ++      fts5DecodeRowidList(&rc, &s, &a[iOff], iTermOff-iOff);
    ++      iOff = iTermOff;
    ++      if( iOff<szLeaf ){
    ++        iOff += fts5GetVarint32(&a[iOff], nKeep);
    ++      }
    ++    }
    ++
    ++    fts5BufferFree(&term);
    +   }else{
    +     Fts5Buffer term;              /* Current term read from page */
    +     int szLeaf;                   /* Offset of pgidx in a[] */
    +@@ -178198,6 +200734,14 @@ static int sqlite3Fts5IndexInit(sqlite3 *db){
    +   int rc = sqlite3_create_function(
    +       db, "fts5_decode", 2, SQLITE_UTF8, 0, fts5DecodeFunction, 0, 0
    +   );
    ++
    ++  if( rc==SQLITE_OK ){
    ++    rc = sqlite3_create_function(
    ++        db, "fts5_decode_none", 2, 
    ++        SQLITE_UTF8, (void*)db, fts5DecodeFunction, 0, 0
    ++    );
    ++  }
    ++
    +   if( rc==SQLITE_OK ){
    +     rc = sqlite3_create_function(
    +         db, "fts5_rowid", -1, SQLITE_UTF8, 0, fts5RowidFunction, 0, 0
    +@@ -178207,6 +200751,14 @@ static int sqlite3Fts5IndexInit(sqlite3 *db){
    + }
    + 
    + 
    ++static int sqlite3Fts5IndexReset(Fts5Index *p){
    ++  assert( p->pStruct==0 || p->iStructVersion!=0 );
    ++  if( fts5IndexDataVersion(p)!=p->iStructVersion ){
    ++    fts5StructureInvalidate(p);
    ++  }
    ++  return fts5IndexReturn(p);
    ++}
    ++
    + /*
    + ** 2014 Jun 09
    + **
    +@@ -178223,6 +200775,7 @@ static int sqlite3Fts5IndexInit(sqlite3 *db){
    + */
    + 
    + 
    ++/* #include "fts5Int.h" */
    + 
    + /*
    + ** This variable is set to false when running tests for which the on disk
    +@@ -178428,12 +200981,13 @@ struct Fts5Cursor {
    + /*
    + ** Values for Fts5Cursor.csrflags
    + */
    +-#define FTS5CSR_REQUIRE_CONTENT   0x01
    +-#define FTS5CSR_REQUIRE_DOCSIZE   0x02
    +-#define FTS5CSR_REQUIRE_INST      0x04
    +-#define FTS5CSR_EOF               0x08
    ++#define FTS5CSR_EOF               0x01
    ++#define FTS5CSR_REQUIRE_CONTENT   0x02
    ++#define FTS5CSR_REQUIRE_DOCSIZE   0x04
    ++#define FTS5CSR_REQUIRE_INST      0x08
    + #define FTS5CSR_FREE_ZRANK        0x10
    + #define FTS5CSR_REQUIRE_RESEEK    0x20
    ++#define FTS5CSR_REQUIRE_POSLIST   0x40
    + 
    + #define BitFlagAllTest(x,y) (((x) & (y))==(y))
    + #define BitFlagTest(x,y)    (((x) & (y))!=0)
    +@@ -178603,6 +201157,15 @@ static int fts5InitVtab(
    +     rc = sqlite3Fts5ConfigDeclareVtab(pConfig);
    +   }
    + 
    ++  /* Load the initial configuration */
    ++  if( rc==SQLITE_OK ){
    ++    assert( pConfig->pzErrmsg==0 );
    ++    pConfig->pzErrmsg = pzErr;
    ++    rc = sqlite3Fts5IndexLoadConfig(pTab->pIndex);
    ++    sqlite3Fts5IndexRollback(pTab->pIndex);
    ++    pConfig->pzErrmsg = 0;
    ++  }
    ++
    +   if( rc!=SQLITE_OK ){
    +     fts5FreeVtab(pTab);
    +     pTab = 0;
    +@@ -178655,7 +201218,10 @@ static int fts5CreateMethod(
    + */
    + static void fts5SetUniqueFlag(sqlite3_index_info *pIdxInfo){
    + #if SQLITE_VERSION_NUMBER>=3008012
    +-  if( sqlite3_libversion_number()>=3008012 ){
    ++#ifndef SQLITE_CORE
    ++  if( sqlite3_libversion_number()>=3008012 )
    ++#endif
    ++  {
    +     pIdxInfo->idxFlags |= SQLITE_INDEX_SCAN_UNIQUE;
    +   }
    + #endif
    +@@ -178701,6 +201267,7 @@ static void fts5SetUniqueFlag(sqlite3_index_info *pIdxInfo){
    + static int fts5BestIndexMethod(sqlite3_vtab *pVTab, sqlite3_index_info *pInfo){
    +   Fts5Table *pTab = (Fts5Table*)pVTab;
    +   Fts5Config *pConfig = pTab->pConfig;
    ++  const int nCol = pConfig->nCol;
    +   int idxFlags = 0;               /* Parameter passed through to xFilter() */
    +   int bHasMatch;
    +   int iNext;
    +@@ -178726,24 +201293,34 @@ static int fts5BestIndexMethod(sqlite3_vtab *pVTab, sqlite3_index_info *pInfo){
    + 
    +   int aColMap[3];
    +   aColMap[0] = -1;
    +-  aColMap[1] = pConfig->nCol;
    +-  aColMap[2] = pConfig->nCol+1;
    ++  aColMap[1] = nCol;
    ++  aColMap[2] = nCol+1;
    + 
    +   /* Set idxFlags flags for all WHERE clause terms that will be used. */
    +   for(i=0; i<pInfo->nConstraint; i++){
    +     struct sqlite3_index_constraint *p = &pInfo->aConstraint[i];
    +-    int j;
    +-    for(j=0; j<sizeof(aConstraint)/sizeof(aConstraint[0]); j++){
    +-      struct Constraint *pC = &aConstraint[j];
    +-      if( p->iColumn==aColMap[pC->iCol] && p->op & pC->op ){
    +-        if( p->usable ){
    ++    int iCol = p->iColumn;
    ++
    ++    if( (p->op==SQLITE_INDEX_CONSTRAINT_MATCH && iCol>=0 && iCol<=nCol)
    ++     || (p->op==SQLITE_INDEX_CONSTRAINT_EQ && iCol==nCol)
    ++    ){
    ++      /* A MATCH operator or equivalent */
    ++      if( p->usable ){
    ++        idxFlags = (idxFlags & 0xFFFF) | FTS5_BI_MATCH | (iCol << 16);
    ++        aConstraint[0].iConsIndex = i;
    ++      }else{
    ++        /* As there exists an unusable MATCH constraint this is an 
    ++        ** unusable plan. Set a prohibitively high cost. */
    ++        pInfo->estimatedCost = 1e50;
    ++        return SQLITE_OK;
    ++      }
    ++    }else{
    ++      int j;
    ++      for(j=1; j<ArraySize(aConstraint); j++){
    ++        struct Constraint *pC = &aConstraint[j];
    ++        if( iCol==aColMap[pC->iCol] && p->op & pC->op && p->usable ){
    +           pC->iConsIndex = i;
    +           idxFlags |= pC->fts5op;
    +-        }else if( j==0 ){
    +-          /* As there exists an unusable MATCH constraint this is an 
    +-          ** unusable plan. Set a prohibitively high cost. */
    +-          pInfo->estimatedCost = 1e50;
    +-          return SQLITE_OK;
    +         }
    +       }
    +     }
    +@@ -178780,11 +201357,11 @@ static int fts5BestIndexMethod(sqlite3_vtab *pVTab, sqlite3_index_info *pInfo){
    + 
    +   /* Assign argvIndex values to each constraint in use. */
    +   iNext = 1;
    +-  for(i=0; i<sizeof(aConstraint)/sizeof(aConstraint[0]); i++){
    ++  for(i=0; i<ArraySize(aConstraint); i++){
    +     struct Constraint *pC = &aConstraint[i];
    +     if( pC->iConsIndex>=0 ){
    +       pInfo->aConstraintUsage[pC->iConsIndex].argvIndex = iNext++;
    +-      pInfo->aConstraintUsage[pC->iConsIndex].omit = pC->omit;
    ++      pInfo->aConstraintUsage[pC->iConsIndex].omit = (unsigned char)pC->omit;
    +     }
    +   }
    + 
    +@@ -178792,27 +201369,38 @@ static int fts5BestIndexMethod(sqlite3_vtab *pVTab, sqlite3_index_info *pInfo){
    +   return SQLITE_OK;
    + }
    + 
    ++static int fts5NewTransaction(Fts5Table *pTab){
    ++  Fts5Cursor *pCsr;
    ++  for(pCsr=pTab->pGlobal->pCsr; pCsr; pCsr=pCsr->pNext){
    ++    if( pCsr->base.pVtab==(sqlite3_vtab*)pTab ) return SQLITE_OK;
    ++  }
    ++  return sqlite3Fts5StorageReset(pTab->pStorage);
    ++}
    ++
    + /*
    + ** Implementation of xOpen method.
    + */
    + static int fts5OpenMethod(sqlite3_vtab *pVTab, sqlite3_vtab_cursor **ppCsr){
    +   Fts5Table *pTab = (Fts5Table*)pVTab;
    +   Fts5Config *pConfig = pTab->pConfig;
    +-  Fts5Cursor *pCsr;               /* New cursor object */
    ++  Fts5Cursor *pCsr = 0;           /* New cursor object */
    +   int nByte;                      /* Bytes of space to allocate */
    +-  int rc = SQLITE_OK;             /* Return code */
    ++  int rc;                         /* Return code */
    + 
    +-  nByte = sizeof(Fts5Cursor) + pConfig->nCol * sizeof(int);
    +-  pCsr = (Fts5Cursor*)sqlite3_malloc(nByte);
    +-  if( pCsr ){
    +-    Fts5Global *pGlobal = pTab->pGlobal;
    +-    memset(pCsr, 0, nByte);
    +-    pCsr->aColumnSize = (int*)&pCsr[1];
    +-    pCsr->pNext = pGlobal->pCsr;
    +-    pGlobal->pCsr = pCsr;
    +-    pCsr->iCsrId = ++pGlobal->iNextId;
    +-  }else{
    +-    rc = SQLITE_NOMEM;
    ++  rc = fts5NewTransaction(pTab);
    ++  if( rc==SQLITE_OK ){
    ++    nByte = sizeof(Fts5Cursor) + pConfig->nCol * sizeof(int);
    ++    pCsr = (Fts5Cursor*)sqlite3_malloc(nByte);
    ++    if( pCsr ){
    ++      Fts5Global *pGlobal = pTab->pGlobal;
    ++      memset(pCsr, 0, nByte);
    ++      pCsr->aColumnSize = (int*)&pCsr[1];
    ++      pCsr->pNext = pGlobal->pCsr;
    ++      pGlobal->pCsr = pCsr;
    ++      pCsr->iCsrId = ++pGlobal->iNextId;
    ++    }else{
    ++      rc = SQLITE_NOMEM;
    ++    }
    +   }
    +   *ppCsr = (sqlite3_vtab_cursor*)pCsr;
    +   return rc;
    +@@ -178835,6 +201423,7 @@ static void fts5CsrNewrow(Fts5Cursor *pCsr){
    +       FTS5CSR_REQUIRE_CONTENT 
    +     | FTS5CSR_REQUIRE_DOCSIZE 
    +     | FTS5CSR_REQUIRE_INST 
    ++    | FTS5CSR_REQUIRE_POSLIST 
    +   );
    + }
    + 
    +@@ -178917,15 +201506,18 @@ static int fts5SorterNext(Fts5Cursor *pCsr){
    +     nBlob = sqlite3_column_bytes(pSorter->pStmt, 1);
    +     aBlob = a = sqlite3_column_blob(pSorter->pStmt, 1);
    + 
    +-    for(i=0; i<(pSorter->nIdx-1); i++){
    +-      int iVal;
    +-      a += fts5GetVarint32(a, iVal);
    +-      iOff += iVal;
    +-      pSorter->aIdx[i] = iOff;
    ++    /* nBlob==0 in detail=none mode. */
    ++    if( nBlob>0 ){
    ++      for(i=0; i<(pSorter->nIdx-1); i++){
    ++        int iVal;
    ++        a += fts5GetVarint32(a, iVal);
    ++        iOff += iVal;
    ++        pSorter->aIdx[i] = iOff;
    ++      }
    ++      pSorter->aIdx[i] = &aBlob[nBlob] - a;
    ++      pSorter->aPoslist = a;
    +     }
    +-    pSorter->aIdx[i] = &aBlob[nBlob] - a;
    + 
    +-    pSorter->aPoslist = a;
    +     fts5CsrNewrow(pCsr);
    +   }
    + 
    +@@ -178969,7 +201561,7 @@ static int fts5CursorReseek(Fts5Cursor *pCsr, int *pbSkip){
    +     i64 iRowid = sqlite3Fts5ExprRowid(pCsr->pExpr);
    + 
    +     rc = sqlite3Fts5ExprFirst(pCsr->pExpr, pTab->pIndex, iRowid, bDesc);
    +-    if( rc==SQLITE_OK && iRowid!=sqlite3Fts5ExprRowid(pCsr->pExpr) ){
    ++    if( rc==SQLITE_OK &&  iRowid!=sqlite3Fts5ExprRowid(pCsr->pExpr) ){
    +       *pbSkip = 1;
    +     }
    + 
    +@@ -178977,6 +201569,7 @@ static int fts5CursorReseek(Fts5Cursor *pCsr, int *pbSkip){
    +     fts5CsrNewrow(pCsr);
    +     if( sqlite3Fts5ExprEof(pCsr->pExpr) ){
    +       CsrFlagSet(pCsr, FTS5CSR_EOF);
    ++      *pbSkip = 1;
    +     }
    +   }
    +   return rc;
    +@@ -178993,24 +201586,24 @@ static int fts5CursorReseek(Fts5Cursor *pCsr, int *pbSkip){
    + */
    + static int fts5NextMethod(sqlite3_vtab_cursor *pCursor){
    +   Fts5Cursor *pCsr = (Fts5Cursor*)pCursor;
    +-  int rc = SQLITE_OK;
    ++  int rc;
    + 
    +   assert( (pCsr->ePlan<3)==
    +           (pCsr->ePlan==FTS5_PLAN_MATCH || pCsr->ePlan==FTS5_PLAN_SOURCE) 
    +   );
    ++  assert( !CsrFlagTest(pCsr, FTS5CSR_EOF) );
    + 
    +   if( pCsr->ePlan<3 ){
    +     int bSkip = 0;
    +     if( (rc = fts5CursorReseek(pCsr, &bSkip)) || bSkip ) return rc;
    +     rc = sqlite3Fts5ExprNext(pCsr->pExpr, pCsr->iLastRowid);
    +-    if( sqlite3Fts5ExprEof(pCsr->pExpr) ){
    +-      CsrFlagSet(pCsr, FTS5CSR_EOF);
    +-    }
    ++    CsrFlagSet(pCsr, sqlite3Fts5ExprEof(pCsr->pExpr));
    +     fts5CsrNewrow(pCsr);
    +   }else{
    +     switch( pCsr->ePlan ){
    +       case FTS5_PLAN_SPECIAL: {
    +         CsrFlagSet(pCsr, FTS5CSR_EOF);
    ++        rc = SQLITE_OK;
    +         break;
    +       }
    +   
    +@@ -179034,13 +201627,42 @@ static int fts5NextMethod(sqlite3_vtab_cursor *pCursor){
    +   return rc;
    + }
    + 
    ++
    ++static int fts5PrepareStatement(
    ++  sqlite3_stmt **ppStmt,
    ++  Fts5Config *pConfig, 
    ++  const char *zFmt,
    ++  ...
    ++){
    ++  sqlite3_stmt *pRet = 0;
    ++  int rc;
    ++  char *zSql;
    ++  va_list ap;
    ++
    ++  va_start(ap, zFmt);
    ++  zSql = sqlite3_vmprintf(zFmt, ap);
    ++  if( zSql==0 ){
    ++    rc = SQLITE_NOMEM; 
    ++  }else{
    ++    rc = sqlite3_prepare_v3(pConfig->db, zSql, -1, 
    ++                            SQLITE_PREPARE_PERSISTENT, &pRet, 0);
    ++    if( rc!=SQLITE_OK ){
    ++      *pConfig->pzErrmsg = sqlite3_mprintf("%s", sqlite3_errmsg(pConfig->db));
    ++    }
    ++    sqlite3_free(zSql);
    ++  }
    ++
    ++  va_end(ap);
    ++  *ppStmt = pRet;
    ++  return rc;
    ++} 
    ++
    + static int fts5CursorFirstSorted(Fts5Table *pTab, Fts5Cursor *pCsr, int bDesc){
    +   Fts5Config *pConfig = pTab->pConfig;
    +   Fts5Sorter *pSorter;
    +   int nPhrase;
    +   int nByte;
    +-  int rc = SQLITE_OK;
    +-  char *zSql;
    ++  int rc;
    +   const char *zRank = pCsr->zRank;
    +   const char *zRankArgs = pCsr->zRankArgs;
    +   
    +@@ -179058,17 +201680,13 @@ static int fts5CursorFirstSorted(Fts5Table *pTab, Fts5Cursor *pCsr, int bDesc){
    +   ** table, saving it creates a circular reference.
    +   **
    +   ** If SQLite a built-in statement cache, this wouldn't be a problem. */
    +-  zSql = sqlite3Fts5Mprintf(&rc, 
    ++  rc = fts5PrepareStatement(&pSorter->pStmt, pConfig,
    +       "SELECT rowid, rank FROM %Q.%Q ORDER BY %s(%s%s%s) %s",
    +       pConfig->zDb, pConfig->zName, zRank, pConfig->zName,
    +       (zRankArgs ? ", " : ""),
    +       (zRankArgs ? zRankArgs : ""),
    +       bDesc ? "DESC" : "ASC"
    +   );
    +-  if( zSql ){
    +-    rc = sqlite3_prepare_v2(pConfig->db, zSql, -1, &pSorter->pStmt, 0);
    +-    sqlite3_free(zSql);
    +-  }
    + 
    +   pCsr->pSorter = pSorter;
    +   if( rc==SQLITE_OK ){
    +@@ -179163,7 +201781,8 @@ static int fts5FindRankFunction(Fts5Cursor *pCsr){
    +     char *zSql = sqlite3Fts5Mprintf(&rc, "SELECT %s", zRankArgs);
    +     if( zSql ){
    +       sqlite3_stmt *pStmt = 0;
    +-      rc = sqlite3_prepare_v2(pConfig->db, zSql, -1, &pStmt, 0);
    ++      rc = sqlite3_prepare_v3(pConfig->db, zSql, -1,
    ++                              SQLITE_PREPARE_PERSISTENT, &pStmt, 0);
    +       sqlite3_free(zSql);
    +       assert( rc==SQLITE_OK || pCsr->pRankArgStmt==0 );
    +       if( rc==SQLITE_OK ){
    +@@ -179262,7 +201881,7 @@ static i64 fts5GetRowidLimit(sqlite3_value *pVal, i64 iDefault){
    + static int fts5FilterMethod(
    +   sqlite3_vtab_cursor *pCursor,   /* The cursor used for this query */
    +   int idxNum,                     /* Strategy index */
    +-  const char *idxStr,             /* Unused */
    ++  const char *zUnused,            /* Unused */
    +   int nVal,                       /* Number of elements in apVal */
    +   sqlite3_value **apVal           /* Arguments for the indexing scheme */
    + ){
    +@@ -179278,8 +201897,12 @@ static int fts5FilterMethod(
    +   sqlite3_value *pRowidEq = 0;    /* rowid = ? expression (or NULL) */
    +   sqlite3_value *pRowidLe = 0;    /* rowid <= ? expression (or NULL) */
    +   sqlite3_value *pRowidGe = 0;    /* rowid >= ? expression (or NULL) */
    ++  int iCol;                       /* Column on LHS of MATCH operator */
    +   char **pzErrmsg = pConfig->pzErrmsg;
    + 
    ++  UNUSED_PARAM(zUnused);
    ++  UNUSED_PARAM(nVal);
    ++
    +   if( pCsr->ePlan ){
    +     fts5FreeCursorComponents(pCsr);
    +     memset(&pCsr->ePlan, 0, sizeof(Fts5Cursor) - ((u8*)&pCsr->ePlan-(u8*)pCsr));
    +@@ -179305,6 +201928,8 @@ static int fts5FilterMethod(
    +   if( BitFlagTest(idxNum, FTS5_BI_ROWID_EQ) ) pRowidEq = apVal[iVal++];
    +   if( BitFlagTest(idxNum, FTS5_BI_ROWID_LE) ) pRowidLe = apVal[iVal++];
    +   if( BitFlagTest(idxNum, FTS5_BI_ROWID_GE) ) pRowidGe = apVal[iVal++];
    ++  iCol = (idxNum>>16);
    ++  assert( iCol>=0 && iCol<=pConfig->nCol );
    +   assert( iVal==nVal );
    +   bOrderByRank = ((idxNum & FTS5_BI_ORDER_RANK) ? 1 : 0);
    +   pCsr->bDesc = bDesc = ((idxNum & FTS5_BI_ORDER_DESC) ? 1 : 0);
    +@@ -179351,7 +201976,7 @@ static int fts5FilterMethod(
    +         rc = fts5SpecialMatch(pTab, pCsr, &zExpr[1]);
    +       }else{
    +         char **pzErr = &pTab->base.zErrMsg;
    +-        rc = sqlite3Fts5ExprNew(pConfig, zExpr, &pCsr->pExpr, pzErr);
    ++        rc = sqlite3Fts5ExprNew(pConfig, iCol, zExpr, &pCsr->pExpr, pzErr);
    +         if( rc==SQLITE_OK ){
    +           if( bOrderByRank ){
    +             pCsr->ePlan = FTS5_PLAN_SORTED_MATCH;
    +@@ -179563,14 +202188,13 @@ static int fts5SpecialInsert(
    + 
    + static int fts5SpecialDelete(
    +   Fts5Table *pTab, 
    +-  sqlite3_value **apVal, 
    +-  sqlite3_int64 *piRowid
    ++  sqlite3_value **apVal
    + ){
    +   int rc = SQLITE_OK;
    +   int eType1 = sqlite3_value_type(apVal[1]);
    +   if( eType1==SQLITE_INTEGER ){
    +     sqlite3_int64 iDel = sqlite3_value_int64(apVal[1]);
    +-    rc = sqlite3Fts5StorageSpecialDelete(pTab->pStorage, iDel, &apVal[2]);
    ++    rc = sqlite3Fts5StorageDelete(pTab->pStorage, iDel, &apVal[2]);
    +   }
    +   return rc;
    + }
    +@@ -179640,7 +202264,7 @@ static int fts5UpdateMethod(
    +     if( pConfig->eContent!=FTS5_CONTENT_NORMAL 
    +       && 0==sqlite3_stricmp("delete", z) 
    +     ){
    +-      rc = fts5SpecialDelete(pTab, apVal, pRowid);
    ++      rc = fts5SpecialDelete(pTab, apVal);
    +     }else{
    +       rc = fts5SpecialInsert(pTab, z, apVal[2 + pConfig->nCol + 1]);
    +     }
    +@@ -179656,7 +202280,10 @@ static int fts5UpdateMethod(
    +     **
    +     ** Cases 3 and 4 may violate the rowid constraint.
    +     */
    +-    int eConflict = sqlite3_vtab_on_conflict(pConfig->db);
    ++    int eConflict = SQLITE_ABORT;
    ++    if( pConfig->eContent==FTS5_CONTENT_NORMAL ){
    ++      eConflict = sqlite3_vtab_on_conflict(pConfig->db);
    ++    }
    + 
    +     assert( eType0==SQLITE_INTEGER || eType0==SQLITE_NULL );
    +     assert( nArg!=1 || eType0==SQLITE_INTEGER );
    +@@ -179671,46 +202298,46 @@ static int fts5UpdateMethod(
    +       rc = SQLITE_ERROR;
    +     }
    + 
    +-    /* Case 1: DELETE */
    ++    /* DELETE */
    +     else if( nArg==1 ){
    +       i64 iDel = sqlite3_value_int64(apVal[0]);  /* Rowid to delete */
    +-      rc = sqlite3Fts5StorageDelete(pTab->pStorage, iDel);
    ++      rc = sqlite3Fts5StorageDelete(pTab->pStorage, iDel, 0);
    +     }
    + 
    +-    /* Case 2: INSERT */
    ++    /* INSERT */
    +     else if( eType0!=SQLITE_INTEGER ){     
    +       /* If this is a REPLACE, first remove the current entry (if any) */
    +       if( eConflict==SQLITE_REPLACE 
    +        && sqlite3_value_type(apVal[1])==SQLITE_INTEGER 
    +       ){
    +         i64 iNew = sqlite3_value_int64(apVal[1]);  /* Rowid to delete */
    +-        rc = sqlite3Fts5StorageDelete(pTab->pStorage, iNew);
    ++        rc = sqlite3Fts5StorageDelete(pTab->pStorage, iNew, 0);
    +       }
    +       fts5StorageInsert(&rc, pTab, apVal, pRowid);
    +     }
    + 
    +-    /* Case 2: UPDATE */
    ++    /* UPDATE */
    +     else{
    +       i64 iOld = sqlite3_value_int64(apVal[0]);  /* Old rowid */
    +       i64 iNew = sqlite3_value_int64(apVal[1]);  /* New rowid */
    +       if( iOld!=iNew ){
    +         if( eConflict==SQLITE_REPLACE ){
    +-          rc = sqlite3Fts5StorageDelete(pTab->pStorage, iOld);
    ++          rc = sqlite3Fts5StorageDelete(pTab->pStorage, iOld, 0);
    +           if( rc==SQLITE_OK ){
    +-            rc = sqlite3Fts5StorageDelete(pTab->pStorage, iNew);
    ++            rc = sqlite3Fts5StorageDelete(pTab->pStorage, iNew, 0);
    +           }
    +           fts5StorageInsert(&rc, pTab, apVal, pRowid);
    +         }else{
    +           rc = sqlite3Fts5StorageContentInsert(pTab->pStorage, apVal, pRowid);
    +           if( rc==SQLITE_OK ){
    +-            rc = sqlite3Fts5StorageDelete(pTab->pStorage, iOld);
    ++            rc = sqlite3Fts5StorageDelete(pTab->pStorage, iOld, 0);
    +           }
    +           if( rc==SQLITE_OK ){
    +             rc = sqlite3Fts5StorageIndexInsert(pTab->pStorage, apVal, *pRowid);
    +           }
    +         }
    +       }else{
    +-        rc = sqlite3Fts5StorageDelete(pTab->pStorage, iOld);
    ++        rc = sqlite3Fts5StorageDelete(pTab->pStorage, iOld, 0);
    +         fts5StorageInsert(&rc, pTab, apVal, pRowid);
    +       }
    +     }
    +@@ -179729,7 +202356,7 @@ static int fts5SyncMethod(sqlite3_vtab *pVtab){
    +   fts5CheckTransactionState(pTab, FTS5_SYNC, 0);
    +   pTab->pConfig->pzErrmsg = &pTab->base.zErrMsg;
    +   fts5TripCursors(pTab);
    +-  rc = sqlite3Fts5StorageSync(pTab->pStorage, 1);
    ++  rc = sqlite3Fts5StorageSync(pTab->pStorage);
    +   pTab->pConfig->pzErrmsg = 0;
    +   return rc;
    + }
    +@@ -179739,6 +202366,7 @@ static int fts5SyncMethod(sqlite3_vtab *pVtab){
    + */
    + static int fts5BeginMethod(sqlite3_vtab *pVtab){
    +   fts5CheckTransactionState((Fts5Table*)pVtab, FTS5_BEGIN, 0);
    ++  fts5NewTransaction((Fts5Table*)pVtab);
    +   return SQLITE_OK;
    + }
    + 
    +@@ -179748,6 +202376,7 @@ static int fts5BeginMethod(sqlite3_vtab *pVtab){
    + ** by fts5SyncMethod().
    + */
    + static int fts5CommitMethod(sqlite3_vtab *pVtab){
    ++  UNUSED_PARAM(pVtab);  /* Call below is a no-op for NDEBUG builds */
    +   fts5CheckTransactionState((Fts5Table*)pVtab, FTS5_COMMIT, 0);
    +   return SQLITE_OK;
    + }
    +@@ -179764,6 +202393,8 @@ static int fts5RollbackMethod(sqlite3_vtab *pVtab){
    +   return rc;
    + }
    + 
    ++static int fts5CsrPoslist(Fts5Cursor*, int, const u8**, int*);
    ++
    + static void *fts5ApiUserData(Fts5Context *pCtx){
    +   Fts5Cursor *pCsr = (Fts5Cursor*)pCtx;
    +   return pCsr->pAux->pUserData;
    +@@ -179813,17 +202444,72 @@ static int fts5ApiPhraseSize(Fts5Context *pCtx, int iPhrase){
    +   return sqlite3Fts5ExprPhraseSize(pCsr->pExpr, iPhrase);
    + }
    + 
    +-static int fts5CsrPoslist(Fts5Cursor *pCsr, int iPhrase, const u8 **pa){
    +-  int n;
    +-  if( pCsr->pSorter ){
    ++static int fts5ApiColumnText(
    ++  Fts5Context *pCtx, 
    ++  int iCol, 
    ++  const char **pz, 
    ++  int *pn
    ++){
    ++  int rc = SQLITE_OK;
    ++  Fts5Cursor *pCsr = (Fts5Cursor*)pCtx;
    ++  if( fts5IsContentless((Fts5Table*)(pCsr->base.pVtab)) ){
    ++    *pz = 0;
    ++    *pn = 0;
    ++  }else{
    ++    rc = fts5SeekCursor(pCsr, 0);
    ++    if( rc==SQLITE_OK ){
    ++      *pz = (const char*)sqlite3_column_text(pCsr->pStmt, iCol+1);
    ++      *pn = sqlite3_column_bytes(pCsr->pStmt, iCol+1);
    ++    }
    ++  }
    ++  return rc;
    ++}
    ++
    ++static int fts5CsrPoslist(
    ++  Fts5Cursor *pCsr, 
    ++  int iPhrase, 
    ++  const u8 **pa,
    ++  int *pn
    ++){
    ++  Fts5Config *pConfig = ((Fts5Table*)(pCsr->base.pVtab))->pConfig;
    ++  int rc = SQLITE_OK;
    ++  int bLive = (pCsr->pSorter==0);
    ++
    ++  if( CsrFlagTest(pCsr, FTS5CSR_REQUIRE_POSLIST) ){
    ++
    ++    if( pConfig->eDetail!=FTS5_DETAIL_FULL ){
    ++      Fts5PoslistPopulator *aPopulator;
    ++      int i;
    ++      aPopulator = sqlite3Fts5ExprClearPoslists(pCsr->pExpr, bLive);
    ++      if( aPopulator==0 ) rc = SQLITE_NOMEM;
    ++      for(i=0; i<pConfig->nCol && rc==SQLITE_OK; i++){
    ++        int n; const char *z;
    ++        rc = fts5ApiColumnText((Fts5Context*)pCsr, i, &z, &n);
    ++        if( rc==SQLITE_OK ){
    ++          rc = sqlite3Fts5ExprPopulatePoslists(
    ++              pConfig, pCsr->pExpr, aPopulator, i, z, n
    ++          );
    ++        }
    ++      }
    ++      sqlite3_free(aPopulator);
    ++
    ++      if( pCsr->pSorter ){
    ++        sqlite3Fts5ExprCheckPoslists(pCsr->pExpr, pCsr->pSorter->iRowid);
    ++      }
    ++    }
    ++    CsrFlagClear(pCsr, FTS5CSR_REQUIRE_POSLIST);
    ++  }
    ++
    ++  if( pCsr->pSorter && pConfig->eDetail==FTS5_DETAIL_FULL ){
    +     Fts5Sorter *pSorter = pCsr->pSorter;
    +     int i1 = (iPhrase==0 ? 0 : pSorter->aIdx[iPhrase-1]);
    +-    n = pSorter->aIdx[iPhrase] - i1;
    ++    *pn = pSorter->aIdx[iPhrase] - i1;
    +     *pa = &pSorter->aPoslist[i1];
    +   }else{
    +-    n = sqlite3Fts5ExprPoslist(pCsr->pExpr, iPhrase, pa);
    ++    *pn = sqlite3Fts5ExprPoslist(pCsr->pExpr, iPhrase, pa);
    +   }
    +-  return n;
    ++
    ++  return rc;
    + }
    + 
    + /*
    +@@ -179848,43 +202534,48 @@ static int fts5CacheInstArray(Fts5Cursor *pCsr){
    +     int i;
    + 
    +     /* Initialize all iterators */
    +-    for(i=0; i<nIter; i++){
    ++    for(i=0; i<nIter && rc==SQLITE_OK; i++){
    +       const u8 *a;
    +-      int n = fts5CsrPoslist(pCsr, i, &a);
    +-      sqlite3Fts5PoslistReaderInit(a, n, &aIter[i]);
    ++      int n; 
    ++      rc = fts5CsrPoslist(pCsr, i, &a, &n);
    ++      if( rc==SQLITE_OK ){
    ++        sqlite3Fts5PoslistReaderInit(a, n, &aIter[i]);
    ++      }
    +     }
    + 
    +-    while( 1 ){
    +-      int *aInst;
    +-      int iBest = -1;
    +-      for(i=0; i<nIter; i++){
    +-        if( (aIter[i].bEof==0) 
    +-         && (iBest<0 || aIter[i].iPos<aIter[iBest].iPos) 
    +-        ){
    +-          iBest = i;
    ++    if( rc==SQLITE_OK ){
    ++      while( 1 ){
    ++        int *aInst;
    ++        int iBest = -1;
    ++        for(i=0; i<nIter; i++){
    ++          if( (aIter[i].bEof==0) 
    ++              && (iBest<0 || aIter[i].iPos<aIter[iBest].iPos) 
    ++            ){
    ++            iBest = i;
    ++          }
    +         }
    +-      }
    +-      if( iBest<0 ) break;
    ++        if( iBest<0 ) break;
    + 
    +-      nInst++;
    +-      if( nInst>=pCsr->nInstAlloc ){
    +-        pCsr->nInstAlloc = pCsr->nInstAlloc ? pCsr->nInstAlloc*2 : 32;
    +-        aInst = (int*)sqlite3_realloc(
    +-            pCsr->aInst, pCsr->nInstAlloc*sizeof(int)*3
    +-        );
    +-        if( aInst ){
    +-          pCsr->aInst = aInst;
    +-        }else{
    +-          rc = SQLITE_NOMEM;
    +-          break;
    ++        nInst++;
    ++        if( nInst>=pCsr->nInstAlloc ){
    ++          pCsr->nInstAlloc = pCsr->nInstAlloc ? pCsr->nInstAlloc*2 : 32;
    ++          aInst = (int*)sqlite3_realloc(
    ++              pCsr->aInst, pCsr->nInstAlloc*sizeof(int)*3
    ++              );
    ++          if( aInst ){
    ++            pCsr->aInst = aInst;
    ++          }else{
    ++            rc = SQLITE_NOMEM;
    ++            break;
    ++          }
    +         }
    +-      }
    + 
    +-      aInst = &pCsr->aInst[3 * (nInst-1)];
    +-      aInst[0] = iBest;
    +-      aInst[1] = FTS5_POS2COLUMN(aIter[iBest].iPos);
    +-      aInst[2] = FTS5_POS2OFFSET(aIter[iBest].iPos);
    +-      sqlite3Fts5PoslistReaderNext(&aIter[iBest]);
    ++        aInst = &pCsr->aInst[3 * (nInst-1)];
    ++        aInst[0] = iBest;
    ++        aInst[1] = FTS5_POS2COLUMN(aIter[iBest].iPos);
    ++        aInst[2] = FTS5_POS2OFFSET(aIter[iBest].iPos);
    ++        sqlite3Fts5PoslistReaderNext(&aIter[iBest]);
    ++      }
    +     }
    + 
    +     pCsr->nInstCount = nInst;
    +@@ -179917,6 +202608,12 @@ static int fts5ApiInst(
    +   ){
    +     if( iIdx<0 || iIdx>=pCsr->nInstCount ){
    +       rc = SQLITE_RANGE;
    ++#if 0
    ++    }else if( fts5IsOffsetless((Fts5Table*)pCsr->base.pVtab) ){
    ++      *piPhrase = pCsr->aInst[iIdx*3];
    ++      *piCol = pCsr->aInst[iIdx*3 + 2];
    ++      *piOff = -1;
    ++#endif
    +     }else{
    +       *piPhrase = pCsr->aInst[iIdx*3];
    +       *piCol = pCsr->aInst[iIdx*3 + 1];
    +@@ -179930,36 +202627,17 @@ static sqlite3_int64 fts5ApiRowid(Fts5Context *pCtx){
    +   return fts5CursorRowid((Fts5Cursor*)pCtx);
    + }
    + 
    +-static int fts5ApiColumnText(
    +-  Fts5Context *pCtx, 
    +-  int iCol, 
    +-  const char **pz, 
    +-  int *pn
    +-){
    +-  int rc = SQLITE_OK;
    +-  Fts5Cursor *pCsr = (Fts5Cursor*)pCtx;
    +-  if( fts5IsContentless((Fts5Table*)(pCsr->base.pVtab)) ){
    +-    *pz = 0;
    +-    *pn = 0;
    +-  }else{
    +-    rc = fts5SeekCursor(pCsr, 0);
    +-    if( rc==SQLITE_OK ){
    +-      *pz = (const char*)sqlite3_column_text(pCsr->pStmt, iCol+1);
    +-      *pn = sqlite3_column_bytes(pCsr->pStmt, iCol+1);
    +-    }
    +-  }
    +-  return rc;
    +-}
    +-
    + static int fts5ColumnSizeCb(
    +   void *pContext,                 /* Pointer to int */
    +   int tflags,
    +-  const char *pToken,             /* Buffer containing token */
    +-  int nToken,                     /* Size of token in bytes */
    +-  int iStart,                     /* Start offset of token */
    +-  int iEnd                        /* End offset of token */
    ++  const char *pUnused,            /* Buffer containing token */
    ++  int nUnused,                    /* Size of token in bytes */
    ++  int iUnused1,                   /* Start offset of token */
    ++  int iUnused2                    /* End offset of token */
    + ){
    +   int *pCnt = (int*)pContext;
    ++  UNUSED_PARAM2(pUnused, nUnused);
    ++  UNUSED_PARAM2(iUnused1, iUnused2);
    +   if( (tflags & FTS5_TOKEN_COLOCATED)==0 ){
    +     (*pCnt)++;
    +   }
    +@@ -180075,10 +202753,11 @@ static void *fts5ApiGetAuxdata(Fts5Context *pCtx, int bClear){
    + }
    + 
    + static void fts5ApiPhraseNext(
    +-  Fts5Context *pCtx, 
    ++  Fts5Context *pUnused, 
    +   Fts5PhraseIter *pIter, 
    +   int *piCol, int *piOff
    + ){
    ++  UNUSED_PARAM(pUnused);
    +   if( pIter->a>=pIter->b ){
    +     *piCol = -1;
    +     *piOff = -1;
    +@@ -180095,20 +202774,98 @@ static void fts5ApiPhraseNext(
    +   }
    + }
    + 
    +-static void fts5ApiPhraseFirst(
    ++static int fts5ApiPhraseFirst(
    +   Fts5Context *pCtx, 
    +   int iPhrase, 
    +   Fts5PhraseIter *pIter, 
    +   int *piCol, int *piOff
    + ){
    +   Fts5Cursor *pCsr = (Fts5Cursor*)pCtx;
    +-  int n = fts5CsrPoslist(pCsr, iPhrase, &pIter->a);
    +-  pIter->b = &pIter->a[n];
    +-  *piCol = 0;
    +-  *piOff = 0;
    +-  fts5ApiPhraseNext(pCtx, pIter, piCol, piOff);
    ++  int n;
    ++  int rc = fts5CsrPoslist(pCsr, iPhrase, &pIter->a, &n);
    ++  if( rc==SQLITE_OK ){
    ++    pIter->b = &pIter->a[n];
    ++    *piCol = 0;
    ++    *piOff = 0;
    ++    fts5ApiPhraseNext(pCtx, pIter, piCol, piOff);
    ++  }
    ++  return rc;
    ++}
    ++
    ++static void fts5ApiPhraseNextColumn(
    ++  Fts5Context *pCtx, 
    ++  Fts5PhraseIter *pIter, 
    ++  int *piCol
    ++){
    ++  Fts5Cursor *pCsr = (Fts5Cursor*)pCtx;
    ++  Fts5Config *pConfig = ((Fts5Table*)(pCsr->base.pVtab))->pConfig;
    ++
    ++  if( pConfig->eDetail==FTS5_DETAIL_COLUMNS ){
    ++    if( pIter->a>=pIter->b ){
    ++      *piCol = -1;
    ++    }else{
    ++      int iIncr;
    ++      pIter->a += fts5GetVarint32(&pIter->a[0], iIncr);
    ++      *piCol += (iIncr-2);
    ++    }
    ++  }else{
    ++    while( 1 ){
    ++      int dummy;
    ++      if( pIter->a>=pIter->b ){
    ++        *piCol = -1;
    ++        return;
    ++      }
    ++      if( pIter->a[0]==0x01 ) break;
    ++      pIter->a += fts5GetVarint32(pIter->a, dummy);
    ++    }
    ++    pIter->a += 1 + fts5GetVarint32(&pIter->a[1], *piCol);
    ++  }
    ++}
    ++
    ++static int fts5ApiPhraseFirstColumn(
    ++  Fts5Context *pCtx, 
    ++  int iPhrase, 
    ++  Fts5PhraseIter *pIter, 
    ++  int *piCol
    ++){
    ++  int rc = SQLITE_OK;
    ++  Fts5Cursor *pCsr = (Fts5Cursor*)pCtx;
    ++  Fts5Config *pConfig = ((Fts5Table*)(pCsr->base.pVtab))->pConfig;
    ++
    ++  if( pConfig->eDetail==FTS5_DETAIL_COLUMNS ){
    ++    Fts5Sorter *pSorter = pCsr->pSorter;
    ++    int n;
    ++    if( pSorter ){
    ++      int i1 = (iPhrase==0 ? 0 : pSorter->aIdx[iPhrase-1]);
    ++      n = pSorter->aIdx[iPhrase] - i1;
    ++      pIter->a = &pSorter->aPoslist[i1];
    ++    }else{
    ++      rc = sqlite3Fts5ExprPhraseCollist(pCsr->pExpr, iPhrase, &pIter->a, &n);
    ++    }
    ++    if( rc==SQLITE_OK ){
    ++      pIter->b = &pIter->a[n];
    ++      *piCol = 0;
    ++      fts5ApiPhraseNextColumn(pCtx, pIter, piCol);
    ++    }
    ++  }else{
    ++    int n;
    ++    rc = fts5CsrPoslist(pCsr, iPhrase, &pIter->a, &n);
    ++    if( rc==SQLITE_OK ){
    ++      pIter->b = &pIter->a[n];
    ++      if( n<=0 ){
    ++        *piCol = -1;
    ++      }else if( pIter->a[0]==0x01 ){
    ++        pIter->a += 1 + fts5GetVarint32(&pIter->a[1], *piCol);
    ++      }else{
    ++        *piCol = 0;
    ++      }
    ++    }
    ++  }
    ++
    ++  return rc;
    + }
    + 
    ++
    + static int fts5ApiQueryPhrase(Fts5Context*, int, void*, 
    +     int(*)(const Fts5ExtensionApi*, Fts5Context*, void*)
    + );
    +@@ -180132,9 +202889,10 @@ static const Fts5ExtensionApi sFts5Api = {
    +   fts5ApiGetAuxdata,
    +   fts5ApiPhraseFirst,
    +   fts5ApiPhraseNext,
    ++  fts5ApiPhraseFirstColumn,
    ++  fts5ApiPhraseNextColumn,
    + };
    + 
    +-
    + /*
    + ** Implementation of API function xQueryPhrase().
    + */
    +@@ -180151,12 +202909,11 @@ static int fts5ApiQueryPhrase(
    + 
    +   rc = fts5OpenMethod(pCsr->base.pVtab, (sqlite3_vtab_cursor**)&pNew);
    +   if( rc==SQLITE_OK ){
    +-    Fts5Config *pConf = pTab->pConfig;
    +     pNew->ePlan = FTS5_PLAN_MATCH;
    +     pNew->iFirstRowid = SMALLEST_INT64;
    +     pNew->iLastRowid = LARGEST_INT64;
    +     pNew->base.pVtab = (sqlite3_vtab*)pTab;
    +-    rc = sqlite3Fts5ExprClonePhrase(pConf, pCsr->pExpr, iPhrase, &pNew->pExpr);
    ++    rc = sqlite3Fts5ExprClonePhrase(pCsr->pExpr, iPhrase, &pNew->pExpr);
    +   }
    + 
    +   if( rc==SQLITE_OK ){
    +@@ -180226,20 +202983,20 @@ static void fts5ApiCallback(
    + ** Given cursor id iId, return a pointer to the corresponding Fts5Index 
    + ** object. Or NULL If the cursor id does not exist.
    + **
    +-** If successful, set *pnCol to the number of indexed columns in the
    +-** table before returning.
    ++** If successful, set *ppConfig to point to the associated config object 
    ++** before returning.
    + */
    + static Fts5Index *sqlite3Fts5IndexFromCsrid(
    +-  Fts5Global *pGlobal, 
    +-  i64 iCsrId, 
    +-  int *pnCol
    ++  Fts5Global *pGlobal,            /* FTS5 global context for db handle */
    ++  i64 iCsrId,                     /* Id of cursor to find */
    ++  Fts5Config **ppConfig           /* OUT: Configuration object */
    + ){
    +   Fts5Cursor *pCsr;
    +   Fts5Table *pTab;
    + 
    +   pCsr = fts5CursorFromCsrid(pGlobal, iCsrId);
    +   pTab = (Fts5Table*)pCsr->base.pVtab;
    +-  *pnCol = pTab->pConfig->nCol;
    ++  *ppConfig = pTab->pConfig;
    + 
    +   return pTab->pIndex;
    + }
    +@@ -180266,20 +203023,46 @@ static int fts5PoslistBlob(sqlite3_context *pCtx, Fts5Cursor *pCsr){
    +   Fts5Buffer val;
    + 
    +   memset(&val, 0, sizeof(Fts5Buffer));
    ++  switch( ((Fts5Table*)(pCsr->base.pVtab))->pConfig->eDetail ){
    ++    case FTS5_DETAIL_FULL:
    + 
    +-  /* Append the varints */
    +-  for(i=0; i<(nPhrase-1); i++){
    +-    const u8 *dummy;
    +-    int nByte = sqlite3Fts5ExprPoslist(pCsr->pExpr, i, &dummy);
    +-    sqlite3Fts5BufferAppendVarint(&rc, &val, nByte);
    +-  }
    ++      /* Append the varints */
    ++      for(i=0; i<(nPhrase-1); i++){
    ++        const u8 *dummy;
    ++        int nByte = sqlite3Fts5ExprPoslist(pCsr->pExpr, i, &dummy);
    ++        sqlite3Fts5BufferAppendVarint(&rc, &val, nByte);
    ++      }
    ++
    ++      /* Append the position lists */
    ++      for(i=0; i<nPhrase; i++){
    ++        const u8 *pPoslist;
    ++        int nPoslist;
    ++        nPoslist = sqlite3Fts5ExprPoslist(pCsr->pExpr, i, &pPoslist);
    ++        sqlite3Fts5BufferAppendBlob(&rc, &val, nPoslist, pPoslist);
    ++      }
    ++      break;
    ++
    ++    case FTS5_DETAIL_COLUMNS:
    ++
    ++      /* Append the varints */
    ++      for(i=0; rc==SQLITE_OK && i<(nPhrase-1); i++){
    ++        const u8 *dummy;
    ++        int nByte;
    ++        rc = sqlite3Fts5ExprPhraseCollist(pCsr->pExpr, i, &dummy, &nByte);
    ++        sqlite3Fts5BufferAppendVarint(&rc, &val, nByte);
    ++      }
    + 
    +-  /* Append the position lists */
    +-  for(i=0; i<nPhrase; i++){
    +-    const u8 *pPoslist;
    +-    int nPoslist;
    +-    nPoslist = sqlite3Fts5ExprPoslist(pCsr->pExpr, i, &pPoslist);
    +-    sqlite3Fts5BufferAppendBlob(&rc, &val, nPoslist, pPoslist);
    ++      /* Append the position lists */
    ++      for(i=0; rc==SQLITE_OK && i<nPhrase; i++){
    ++        const u8 *pPoslist;
    ++        int nPoslist;
    ++        rc = sqlite3Fts5ExprPhraseCollist(pCsr->pExpr, i, &pPoslist, &nPoslist);
    ++        sqlite3Fts5BufferAppendBlob(&rc, &val, nPoslist, pPoslist);
    ++      }
    ++      break;
    ++
    ++    default:
    ++      break;
    +   }
    + 
    +   sqlite3_result_blob(pCtx, val.p, val.n, sqlite3_free);
    +@@ -180343,7 +203126,7 @@ static int fts5ColumnMethod(
    + */
    + static int fts5FindFunctionMethod(
    +   sqlite3_vtab *pVtab,            /* Virtual table handle */
    +-  int nArg,                       /* Number of SQL function arguments */
    ++  int nUnused,                    /* Number of SQL function arguments */
    +   const char *zName,              /* Name of SQL function */
    +   void (**pxFunc)(sqlite3_context*,int,sqlite3_value**), /* OUT: Result */
    +   void **ppArg                    /* OUT: User data for *pxFunc */
    +@@ -180351,6 +203134,7 @@ static int fts5FindFunctionMethod(
    +   Fts5Table *pTab = (Fts5Table*)pVtab;
    +   Fts5Auxiliary *pAux;
    + 
    ++  UNUSED_PARAM(nUnused);
    +   pAux = fts5FindAuxiliary(pTab, zName);
    +   if( pAux ){
    +     *pxFunc = fts5ApiCallback;
    +@@ -180380,9 +203164,10 @@ static int fts5RenameMethod(
    + */
    + static int fts5SavepointMethod(sqlite3_vtab *pVtab, int iSavepoint){
    +   Fts5Table *pTab = (Fts5Table*)pVtab;
    ++  UNUSED_PARAM(iSavepoint);  /* Call below is a no-op for NDEBUG builds */
    +   fts5CheckTransactionState(pTab, FTS5_SAVEPOINT, iSavepoint);
    +   fts5TripCursors(pTab);
    +-  return sqlite3Fts5StorageSync(pTab->pStorage, 0);
    ++  return sqlite3Fts5StorageSync(pTab->pStorage);
    + }
    + 
    + /*
    +@@ -180392,9 +203177,10 @@ static int fts5SavepointMethod(sqlite3_vtab *pVtab, int iSavepoint){
    + */
    + static int fts5ReleaseMethod(sqlite3_vtab *pVtab, int iSavepoint){
    +   Fts5Table *pTab = (Fts5Table*)pVtab;
    ++  UNUSED_PARAM(iSavepoint);  /* Call below is a no-op for NDEBUG builds */
    +   fts5CheckTransactionState(pTab, FTS5_RELEASE, iSavepoint);
    +   fts5TripCursors(pTab);
    +-  return sqlite3Fts5StorageSync(pTab->pStorage, 0);
    ++  return sqlite3Fts5StorageSync(pTab->pStorage);
    + }
    + 
    + /*
    +@@ -180404,6 +203190,7 @@ static int fts5ReleaseMethod(sqlite3_vtab *pVtab, int iSavepoint){
    + */
    + static int fts5RollbackToMethod(sqlite3_vtab *pVtab, int iSavepoint){
    +   Fts5Table *pTab = (Fts5Table*)pVtab;
    ++  UNUSED_PARAM(iSavepoint);  /* Call below is a no-op for NDEBUG builds */
    +   fts5CheckTransactionState(pTab, FTS5_ROLLBACKTO, iSavepoint);
    +   fts5TripCursors(pTab);
    +   return sqlite3Fts5StorageRollback(pTab->pStorage);
    +@@ -180583,14 +203370,14 @@ static void fts5ModuleDestroy(void *pCtx){
    + static void fts5Fts5Func(
    +   sqlite3_context *pCtx,          /* Function call context */
    +   int nArg,                       /* Number of args */
    +-  sqlite3_value **apVal           /* Function arguments */
    ++  sqlite3_value **apArg           /* Function arguments */
    + ){
    +   Fts5Global *pGlobal = (Fts5Global*)sqlite3_user_data(pCtx);
    +-  char buf[8];
    +-  assert( nArg==0 );
    +-  assert( sizeof(buf)>=sizeof(pGlobal) );
    +-  memcpy(buf, (void*)&pGlobal, sizeof(pGlobal));
    +-  sqlite3_result_blob(pCtx, buf, sizeof(pGlobal), SQLITE_TRANSIENT);
    ++  fts5_api **ppApi;
    ++  UNUSED_PARAM(nArg);
    ++  assert( nArg==1 );
    ++  ppApi = (fts5_api**)sqlite3_value_pointer(apArg[0], "fts5_api_ptr");
    ++  if( ppApi ) *ppApi = &pGlobal->api;
    + }
    + 
    + /*
    +@@ -180599,10 +203386,11 @@ static void fts5Fts5Func(
    + static void fts5SourceIdFunc(
    +   sqlite3_context *pCtx,          /* Function call context */
    +   int nArg,                       /* Number of args */
    +-  sqlite3_value **apVal           /* Function arguments */
    ++  sqlite3_value **apUnused        /* Function arguments */
    + ){
    +   assert( nArg==0 );
    +-  sqlite3_result_text(pCtx, "fts5: 2015-11-02 18:31:45 bda77dda9697c463c3d0704014d51627fceee328", -1, SQLITE_TRANSIENT);
    ++  UNUSED_PARAM2(nArg, apUnused);
    ++  sqlite3_result_text(pCtx, "fts5: 2018-12-19 01:30:22 c255889bd95bd5430dc7ced3317011ae2abb483d6c9af883af3dc7d6c2c2f234", -1, SQLITE_TRANSIENT);
    + }
    + 
    + static int fts5Init(sqlite3 *db){
    +@@ -180654,7 +203442,7 @@ static int fts5Init(sqlite3 *db){
    +     if( rc==SQLITE_OK ) rc = sqlite3Fts5VocabInit(pGlobal, db);
    +     if( rc==SQLITE_OK ){
    +       rc = sqlite3_create_function(
    +-          db, "fts5", 0, SQLITE_UTF8, p, fts5Fts5Func, 0, 0
    ++          db, "fts5", 1, SQLITE_UTF8, p, fts5Fts5Func, 0, 0
    +       );
    +     }
    +     if( rc==SQLITE_OK ){
    +@@ -180663,6 +203451,17 @@ static int fts5Init(sqlite3 *db){
    +       );
    +     }
    +   }
    ++
    ++  /* If SQLITE_FTS5_ENABLE_TEST_MI is defined, assume that the file
    ++  ** fts5_test_mi.c is compiled and linked into the executable. And call
    ++  ** its entry point to enable the matchinfo() demo.  */
    ++#ifdef SQLITE_FTS5_ENABLE_TEST_MI
    ++  if( rc==SQLITE_OK ){
    ++    extern int sqlite3Fts5TestRegisterMatchinfo(sqlite3*);
    ++    rc = sqlite3Fts5TestRegisterMatchinfo(db);
    ++  }
    ++#endif
    ++
    +   return rc;
    + }
    + 
    +@@ -180679,7 +203478,7 @@ static int fts5Init(sqlite3 *db){
    + #ifdef _WIN32
    + __declspec(dllexport)
    + #endif
    +-SQLITE_API int SQLITE_STDCALL sqlite3_fts_init(
    ++SQLITE_API int sqlite3_fts_init(
    +   sqlite3 *db,
    +   char **pzErrMsg,
    +   const sqlite3_api_routines *pApi
    +@@ -180692,7 +203491,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_fts_init(
    + #ifdef _WIN32
    + __declspec(dllexport)
    + #endif
    +-SQLITE_API int SQLITE_STDCALL sqlite3_fts5_init(
    ++SQLITE_API int sqlite3_fts5_init(
    +   sqlite3 *db,
    +   char **pzErrMsg,
    +   const sqlite3_api_routines *pApi
    +@@ -180723,6 +203522,7 @@ SQLITE_PRIVATE int sqlite3Fts5Init(sqlite3 *db){
    + 
    + 
    + 
    ++/* #include "fts5Int.h" */
    + 
    + struct Fts5Storage {
    +   Fts5Config *pConfig;
    +@@ -180844,7 +203644,8 @@ static int fts5StorageGetStmt(
    +     if( zSql==0 ){
    +       rc = SQLITE_NOMEM;
    +     }else{
    +-      rc = sqlite3_prepare_v2(pC->db, zSql, -1, &p->aStmt[eStmt], 0);
    ++      rc = sqlite3_prepare_v3(pC->db, zSql, -1,
    ++                              SQLITE_PREPARE_PERSISTENT, &p->aStmt[eStmt], 0);
    +       sqlite3_free(zSql);
    +       if( rc!=SQLITE_OK && pzErrMsg ){
    +         *pzErrMsg = sqlite3_mprintf("%s", sqlite3_errmsg(pC->db));
    +@@ -180853,6 +203654,7 @@ static int fts5StorageGetStmt(
    +   }
    + 
    +   *ppStmt = p->aStmt[eStmt];
    ++  sqlite3_reset(*ppStmt);
    +   return rc;
    + }
    + 
    +@@ -180925,7 +203727,7 @@ static void fts5StorageRenameOne(
    + 
    + static int sqlite3Fts5StorageRename(Fts5Storage *pStorage, const char *zName){
    +   Fts5Config *pConfig = pStorage->pConfig;
    +-  int rc = sqlite3Fts5StorageSync(pStorage, 1);
    ++  int rc = sqlite3Fts5StorageSync(pStorage);
    + 
    +   fts5StorageRenameOne(pConfig, &rc, "data", zName);
    +   fts5StorageRenameOne(pConfig, &rc, "idx", zName);
    +@@ -180954,7 +203756,11 @@ static int sqlite3Fts5CreateTable(
    +   char *zErr = 0;
    + 
    +   rc = fts5ExecPrintf(pConfig->db, &zErr, "CREATE TABLE %Q.'%q_%q'(%s)%s",
    +-      pConfig->zDb, pConfig->zName, zPost, zDefn, bWithout?" WITHOUT ROWID":""
    ++      pConfig->zDb, pConfig->zName, zPost, zDefn, 
    ++#ifndef SQLITE_FTS5_NO_WITHOUT_ROWID
    ++      bWithout?" WITHOUT ROWID":
    ++#endif
    ++      ""
    +   );
    +   if( zErr ){
    +     *pzErr = sqlite3_mprintf(
    +@@ -181005,10 +203811,10 @@ static int sqlite3Fts5StorageOpen(
    +         int i;
    +         int iOff;
    +         sqlite3_snprintf(nDefn, zDefn, "id INTEGER PRIMARY KEY");
    +-        iOff = strlen(zDefn);
    ++        iOff = (int)strlen(zDefn);
    +         for(i=0; i<pConfig->nCol; i++){
    +           sqlite3_snprintf(nDefn-iOff, &zDefn[iOff], ", c%d", i);
    +-          iOff += strlen(&zDefn[iOff]);
    ++          iOff += (int)strlen(&zDefn[iOff]);
    +         }
    +         rc = sqlite3Fts5CreateTable(pConfig, "content", zDefn, 0, pzErr);
    +       }
    +@@ -181070,11 +203876,13 @@ static int fts5StorageInsertCallback(
    +   int tflags,
    +   const char *pToken,             /* Buffer containing token */
    +   int nToken,                     /* Size of token in bytes */
    +-  int iStart,                     /* Start offset of token */
    +-  int iEnd                        /* End offset of token */
    ++  int iUnused1,                   /* Start offset of token */
    ++  int iUnused2                    /* End offset of token */
    + ){
    +   Fts5InsertCtx *pCtx = (Fts5InsertCtx*)pContext;
    +   Fts5Index *pIdx = pCtx->pStorage->pIndex;
    ++  UNUSED_PARAM2(iUnused1, iUnused2);
    ++  if( nToken>FTS5_MAX_TOKEN_SIZE ) nToken = FTS5_MAX_TOKEN_SIZE;
    +   if( (tflags & FTS5_TOKEN_COLOCATED)==0 || pCtx->szCol==0 ){
    +     pCtx->szCol++;
    +   }
    +@@ -181086,39 +203894,52 @@ static int fts5StorageInsertCallback(
    + ** delete-markers to the FTS index necessary to delete it. Do not actually
    + ** remove the %_content row at this time though.
    + */
    +-static int fts5StorageDeleteFromIndex(Fts5Storage *p, i64 iDel){
    ++static int fts5StorageDeleteFromIndex(
    ++  Fts5Storage *p, 
    ++  i64 iDel, 
    ++  sqlite3_value **apVal
    ++){
    +   Fts5Config *pConfig = p->pConfig;
    +-  sqlite3_stmt *pSeek;            /* SELECT to read row iDel from %_data */
    ++  sqlite3_stmt *pSeek = 0;        /* SELECT to read row iDel from %_data */
    +   int rc;                         /* Return code */
    ++  int rc2;                        /* sqlite3_reset() return code */
    ++  int iCol;
    ++  Fts5InsertCtx ctx;
    + 
    +-  rc = fts5StorageGetStmt(p, FTS5_STMT_LOOKUP, &pSeek, 0);
    +-  if( rc==SQLITE_OK ){
    +-    int rc2;
    ++  if( apVal==0 ){
    ++    rc = fts5StorageGetStmt(p, FTS5_STMT_LOOKUP, &pSeek, 0);
    ++    if( rc!=SQLITE_OK ) return rc;
    +     sqlite3_bind_int64(pSeek, 1, iDel);
    +-    if( sqlite3_step(pSeek)==SQLITE_ROW ){
    +-      int iCol;
    +-      Fts5InsertCtx ctx;
    +-      ctx.pStorage = p;
    +-      ctx.iCol = -1;
    +-      rc = sqlite3Fts5IndexBeginWrite(p->pIndex, 1, iDel);
    +-      for(iCol=1; rc==SQLITE_OK && iCol<=pConfig->nCol; iCol++){
    +-        if( pConfig->abUnindexed[iCol-1] ) continue;
    +-        ctx.szCol = 0;
    +-        rc = sqlite3Fts5Tokenize(pConfig, 
    +-            FTS5_TOKENIZE_DOCUMENT,
    +-            (const char*)sqlite3_column_text(pSeek, iCol),
    +-            sqlite3_column_bytes(pSeek, iCol),
    +-            (void*)&ctx,
    +-            fts5StorageInsertCallback
    +-        );
    +-        p->aTotalSize[iCol-1] -= (i64)ctx.szCol;
    ++    if( sqlite3_step(pSeek)!=SQLITE_ROW ){
    ++      return sqlite3_reset(pSeek);
    ++    }
    ++  }
    ++
    ++  ctx.pStorage = p;
    ++  ctx.iCol = -1;
    ++  rc = sqlite3Fts5IndexBeginWrite(p->pIndex, 1, iDel);
    ++  for(iCol=1; rc==SQLITE_OK && iCol<=pConfig->nCol; iCol++){
    ++    if( pConfig->abUnindexed[iCol-1]==0 ){
    ++      const char *zText;
    ++      int nText;
    ++      if( pSeek ){
    ++        zText = (const char*)sqlite3_column_text(pSeek, iCol);
    ++        nText = sqlite3_column_bytes(pSeek, iCol);
    ++      }else{
    ++        zText = (const char*)sqlite3_value_text(apVal[iCol-1]);
    ++        nText = sqlite3_value_bytes(apVal[iCol-1]);
    +       }
    +-      p->nTotalRow--;
    ++      ctx.szCol = 0;
    ++      rc = sqlite3Fts5Tokenize(pConfig, FTS5_TOKENIZE_DOCUMENT, 
    ++          zText, nText, (void*)&ctx, fts5StorageInsertCallback
    ++      );
    ++      p->aTotalSize[iCol-1] -= (i64)ctx.szCol;
    +     }
    +-    rc2 = sqlite3_reset(pSeek);
    +-    if( rc==SQLITE_OK ) rc = rc2;
    +   }
    ++  p->nTotalRow--;
    + 
    ++  rc2 = sqlite3_reset(pSeek);
    ++  if( rc==SQLITE_OK ) rc = rc2;
    +   return rc;
    + }
    + 
    +@@ -181198,16 +204019,17 @@ static int fts5StorageSaveTotals(Fts5Storage *p){
    + /*
    + ** Remove a row from the FTS table.
    + */
    +-static int sqlite3Fts5StorageDelete(Fts5Storage *p, i64 iDel){
    ++static int sqlite3Fts5StorageDelete(Fts5Storage *p, i64 iDel, sqlite3_value **apVal){
    +   Fts5Config *pConfig = p->pConfig;
    +   int rc;
    +   sqlite3_stmt *pDel = 0;
    + 
    ++  assert( pConfig->eContent!=FTS5_CONTENT_NORMAL || apVal==0 );
    +   rc = fts5StorageLoadTotals(p, 1);
    + 
    +   /* Delete the index records */
    +   if( rc==SQLITE_OK ){
    +-    rc = fts5StorageDeleteFromIndex(p, iDel);
    ++    rc = fts5StorageDeleteFromIndex(p, iDel, apVal);
    +   }
    + 
    +   /* Delete the %_docsize record */
    +@@ -181221,62 +204043,9 @@ static int sqlite3Fts5StorageDelete(Fts5Storage *p, i64 iDel){
    +   }
    + 
    +   /* Delete the %_content record */
    +-  if( rc==SQLITE_OK ){
    +-    rc = fts5StorageGetStmt(p, FTS5_STMT_DELETE_CONTENT, &pDel, 0);
    +-  }
    +-  if( rc==SQLITE_OK ){
    +-    sqlite3_bind_int64(pDel, 1, iDel);
    +-    sqlite3_step(pDel);
    +-    rc = sqlite3_reset(pDel);
    +-  }
    +-
    +-  /* Write the averages record */
    +-  if( rc==SQLITE_OK ){
    +-    rc = fts5StorageSaveTotals(p);
    +-  }
    +-
    +-  return rc;
    +-}
    +-
    +-static int sqlite3Fts5StorageSpecialDelete(
    +-  Fts5Storage *p, 
    +-  i64 iDel, 
    +-  sqlite3_value **apVal
    +-){
    +-  Fts5Config *pConfig = p->pConfig;
    +-  int rc;
    +-  sqlite3_stmt *pDel = 0;
    +-
    +-  assert( pConfig->eContent!=FTS5_CONTENT_NORMAL );
    +-  rc = fts5StorageLoadTotals(p, 1);
    +-
    +-  /* Delete the index records */
    +-  if( rc==SQLITE_OK ){
    +-    int iCol;
    +-    Fts5InsertCtx ctx;
    +-    ctx.pStorage = p;
    +-    ctx.iCol = -1;
    +-
    +-    rc = sqlite3Fts5IndexBeginWrite(p->pIndex, 1, iDel);
    +-    for(iCol=0; rc==SQLITE_OK && iCol<pConfig->nCol; iCol++){
    +-      if( pConfig->abUnindexed[iCol] ) continue;
    +-      ctx.szCol = 0;
    +-      rc = sqlite3Fts5Tokenize(pConfig, 
    +-        FTS5_TOKENIZE_DOCUMENT,
    +-        (const char*)sqlite3_value_text(apVal[iCol]),
    +-        sqlite3_value_bytes(apVal[iCol]),
    +-        (void*)&ctx,
    +-        fts5StorageInsertCallback
    +-      );
    +-      p->aTotalSize[iCol] -= (i64)ctx.szCol;
    +-    }
    +-    p->nTotalRow--;
    +-  }
    +-
    +-  /* Delete the %_docsize record */
    +-  if( pConfig->bColumnsize ){
    ++  if( pConfig->eContent==FTS5_CONTENT_NORMAL ){
    +     if( rc==SQLITE_OK ){
    +-      rc = fts5StorageGetStmt(p, FTS5_STMT_DELETE_DOCSIZE, &pDel, 0);
    ++      rc = fts5StorageGetStmt(p, FTS5_STMT_DELETE_CONTENT, &pDel, 0);
    +     }
    +     if( rc==SQLITE_OK ){
    +       sqlite3_bind_int64(pDel, 1, iDel);
    +@@ -181285,11 +204054,6 @@ static int sqlite3Fts5StorageSpecialDelete(
    +     }
    +   }
    + 
    +-  /* Write the averages record */
    +-  if( rc==SQLITE_OK ){
    +-    rc = fts5StorageSaveTotals(p);
    +-  }
    +-
    +   return rc;
    + }
    + 
    +@@ -181385,6 +204149,10 @@ static int sqlite3Fts5StorageMerge(Fts5Storage *p, int nMerge){
    +   return sqlite3Fts5IndexMerge(p->pIndex, nMerge);
    + }
    + 
    ++static int sqlite3Fts5StorageReset(Fts5Storage *p){
    ++  return sqlite3Fts5IndexReset(p->pIndex);
    ++}
    ++
    + /*
    + ** Allocate a new rowid. This is used for "external content" tables when
    + ** a NULL value is inserted into the rowid column. The new rowid is allocated
    +@@ -181433,17 +204201,7 @@ static int sqlite3Fts5StorageContentInsert(
    +   }else{
    +     sqlite3_stmt *pInsert = 0;    /* Statement to write %_content table */
    +     int i;                        /* Counter variable */
    +-#if 0
    +-    if( eConflict==SQLITE_REPLACE ){
    +-      eStmt = FTS5_STMT_REPLACE_CONTENT;
    +-      rc = fts5StorageDeleteFromIndex(p, sqlite3_value_int64(apVal[1]));
    +-    }else{
    +-      eStmt = FTS5_STMT_INSERT_CONTENT;
    +-    }
    +-#endif
    +-    if( rc==SQLITE_OK ){
    +-      rc = fts5StorageGetStmt(p, FTS5_STMT_INSERT_CONTENT, &pInsert, 0);
    +-    }
    ++    rc = fts5StorageGetStmt(p, FTS5_STMT_INSERT_CONTENT, &pInsert, 0);
    +     for(i=1; rc==SQLITE_OK && i<=pConfig->nCol+1; i++){
    +       rc = sqlite3_bind_value(pInsert, i, apVal[i]);
    +     }
    +@@ -181499,11 +204257,6 @@ static int sqlite3Fts5StorageIndexInsert(
    +   }
    +   sqlite3_free(buf.p);
    + 
    +-  /* Write the averages record */
    +-  if( rc==SQLITE_OK ){
    +-    rc = fts5StorageSaveTotals(p);
    +-  }
    +-
    +   return rc;
    + }
    + 
    +@@ -181541,28 +204294,76 @@ struct Fts5IntegrityCtx {
    +   int iCol;
    +   int szCol;
    +   u64 cksum;
    ++  Fts5Termset *pTermset;
    +   Fts5Config *pConfig;
    + };
    + 
    ++
    + /*
    + ** Tokenization callback used by integrity check.
    + */
    + static int fts5StorageIntegrityCallback(
    +-  void *pContext,                 /* Pointer to Fts5InsertCtx object */
    ++  void *pContext,                 /* Pointer to Fts5IntegrityCtx object */
    +   int tflags,
    +   const char *pToken,             /* Buffer containing token */
    +   int nToken,                     /* Size of token in bytes */
    +-  int iStart,                     /* Start offset of token */
    +-  int iEnd                        /* End offset of token */
    ++  int iUnused1,                   /* Start offset of token */
    ++  int iUnused2                    /* End offset of token */
    + ){
    +   Fts5IntegrityCtx *pCtx = (Fts5IntegrityCtx*)pContext;
    ++  Fts5Termset *pTermset = pCtx->pTermset;
    ++  int bPresent;
    ++  int ii;
    ++  int rc = SQLITE_OK;
    ++  int iPos;
    ++  int iCol;
    ++
    ++  UNUSED_PARAM2(iUnused1, iUnused2);
    ++  if( nToken>FTS5_MAX_TOKEN_SIZE ) nToken = FTS5_MAX_TOKEN_SIZE;
    ++
    +   if( (tflags & FTS5_TOKEN_COLOCATED)==0 || pCtx->szCol==0 ){
    +     pCtx->szCol++;
    +   }
    +-  pCtx->cksum ^= sqlite3Fts5IndexCksum(
    +-      pCtx->pConfig, pCtx->iRowid, pCtx->iCol, pCtx->szCol-1, pToken, nToken
    +-  );
    +-  return SQLITE_OK;
    ++
    ++  switch( pCtx->pConfig->eDetail ){
    ++    case FTS5_DETAIL_FULL:
    ++      iPos = pCtx->szCol-1;
    ++      iCol = pCtx->iCol;
    ++      break;
    ++
    ++    case FTS5_DETAIL_COLUMNS:
    ++      iPos = pCtx->iCol;
    ++      iCol = 0;
    ++      break;
    ++
    ++    default:
    ++      assert( pCtx->pConfig->eDetail==FTS5_DETAIL_NONE );
    ++      iPos = 0;
    ++      iCol = 0;
    ++      break;
    ++  }
    ++
    ++  rc = sqlite3Fts5TermsetAdd(pTermset, 0, pToken, nToken, &bPresent);
    ++  if( rc==SQLITE_OK && bPresent==0 ){
    ++    pCtx->cksum ^= sqlite3Fts5IndexEntryCksum(
    ++        pCtx->iRowid, iCol, iPos, 0, pToken, nToken
    ++    );
    ++  }
    ++
    ++  for(ii=0; rc==SQLITE_OK && ii<pCtx->pConfig->nPrefix; ii++){
    ++    const int nChar = pCtx->pConfig->aPrefix[ii];
    ++    int nByte = sqlite3Fts5IndexCharlenToBytelen(pToken, nToken, nChar);
    ++    if( nByte ){
    ++      rc = sqlite3Fts5TermsetAdd(pTermset, ii+1, pToken, nByte, &bPresent);
    ++      if( bPresent==0 ){
    ++        pCtx->cksum ^= sqlite3Fts5IndexEntryCksum(
    ++            pCtx->iRowid, iCol, iPos, ii+1, pToken, nByte
    ++        );
    ++      }
    ++    }
    ++  }
    ++
    ++  return rc;
    + }
    + 
    + /*
    +@@ -181598,22 +204399,37 @@ static int sqlite3Fts5StorageIntegrity(Fts5Storage *p){
    +       if( pConfig->bColumnsize ){
    +         rc = sqlite3Fts5StorageDocsize(p, ctx.iRowid, aColSize);
    +       }
    ++      if( rc==SQLITE_OK && pConfig->eDetail==FTS5_DETAIL_NONE ){
    ++        rc = sqlite3Fts5TermsetNew(&ctx.pTermset);
    ++      }
    +       for(i=0; rc==SQLITE_OK && i<pConfig->nCol; i++){
    +         if( pConfig->abUnindexed[i] ) continue;
    +         ctx.iCol = i;
    +         ctx.szCol = 0;
    +-        rc = sqlite3Fts5Tokenize(pConfig, 
    +-            FTS5_TOKENIZE_DOCUMENT,
    +-            (const char*)sqlite3_column_text(pScan, i+1),
    +-            sqlite3_column_bytes(pScan, i+1),
    +-            (void*)&ctx,
    +-            fts5StorageIntegrityCallback
    +-        );
    +-        if( pConfig->bColumnsize && ctx.szCol!=aColSize[i] ){
    ++        if( pConfig->eDetail==FTS5_DETAIL_COLUMNS ){
    ++          rc = sqlite3Fts5TermsetNew(&ctx.pTermset);
    ++        }
    ++        if( rc==SQLITE_OK ){
    ++          rc = sqlite3Fts5Tokenize(pConfig, 
    ++              FTS5_TOKENIZE_DOCUMENT,
    ++              (const char*)sqlite3_column_text(pScan, i+1),
    ++              sqlite3_column_bytes(pScan, i+1),
    ++              (void*)&ctx,
    ++              fts5StorageIntegrityCallback
    ++          );
    ++        }
    ++        if( rc==SQLITE_OK && pConfig->bColumnsize && ctx.szCol!=aColSize[i] ){
    +           rc = FTS5_CORRUPT;
    +         }
    +         aTotalSize[i] += ctx.szCol;
    ++        if( pConfig->eDetail==FTS5_DETAIL_COLUMNS ){
    ++          sqlite3Fts5TermsetFree(ctx.pTermset);
    ++          ctx.pTermset = 0;
    ++        }
    +       }
    ++      sqlite3Fts5TermsetFree(ctx.pTermset);
    ++      ctx.pTermset = 0;
    ++
    +       if( rc!=SQLITE_OK ) break;
    +     }
    +     rc2 = sqlite3_reset(pScan);
    +@@ -181632,12 +204448,12 @@ static int sqlite3Fts5StorageIntegrity(Fts5Storage *p){
    +   /* Check that the %_docsize and %_content tables contain the expected
    +   ** number of rows.  */
    +   if( rc==SQLITE_OK && pConfig->eContent==FTS5_CONTENT_NORMAL ){
    +-    i64 nRow;
    ++    i64 nRow = 0;
    +     rc = fts5StorageCount(p, "content", &nRow);
    +     if( rc==SQLITE_OK && nRow!=p->nTotalRow ) rc = FTS5_CORRUPT;
    +   }
    +   if( rc==SQLITE_OK && pConfig->bColumnsize ){
    +-    i64 nRow;
    ++    i64 nRow = 0;
    +     rc = fts5StorageCount(p, "docsize", &nRow);
    +     if( rc==SQLITE_OK && nRow!=p->nTotalRow ) rc = FTS5_CORRUPT;
    +   }
    +@@ -181774,13 +204590,18 @@ static int sqlite3Fts5StorageRowCount(Fts5Storage *p, i64 *pnRow){
    + /*
    + ** Flush any data currently held in-memory to disk.
    + */
    +-static int sqlite3Fts5StorageSync(Fts5Storage *p, int bCommit){
    +-  if( bCommit && p->bTotalsValid ){
    +-    int rc = fts5StorageSaveTotals(p);
    ++static int sqlite3Fts5StorageSync(Fts5Storage *p){
    ++  int rc = SQLITE_OK;
    ++  i64 iLastRowid = sqlite3_last_insert_rowid(p->pConfig->db);
    ++  if( p->bTotalsValid ){
    ++    rc = fts5StorageSaveTotals(p);
    +     p->bTotalsValid = 0;
    +-    if( rc!=SQLITE_OK ) return rc;
    +   }
    +-  return sqlite3Fts5IndexSync(p->pIndex, bCommit);
    ++  if( rc==SQLITE_OK ){
    ++    rc = sqlite3Fts5IndexSync(p->pIndex);
    ++  }
    ++  sqlite3_set_last_insert_rowid(p->pConfig->db, iLastRowid);
    ++  return rc;
    + }
    + 
    + static int sqlite3Fts5StorageRollback(Fts5Storage *p){
    +@@ -181816,8 +204637,6 @@ static int sqlite3Fts5StorageConfigValue(
    +   return rc;
    + }
    + 
    +-
    +-
    + /*
    + ** 2014 May 31
    + **
    +@@ -181832,6 +204651,7 @@ static int sqlite3Fts5StorageConfigValue(
    + */
    + 
    + 
    ++/* #include "fts5Int.h" */
    + 
    + /**************************************************************************
    + ** Start of ascii tokenizer implementation.
    +@@ -181881,12 +204701,13 @@ static void fts5AsciiDelete(Fts5Tokenizer *p){
    + ** Create an "ascii" tokenizer.
    + */
    + static int fts5AsciiCreate(
    +-  void *pCtx, 
    ++  void *pUnused, 
    +   const char **azArg, int nArg,
    +   Fts5Tokenizer **ppOut
    + ){
    +   int rc = SQLITE_OK;
    +   AsciiTokenizer *p = 0;
    ++  UNUSED_PARAM(pUnused);
    +   if( nArg%2 ){
    +     rc = SQLITE_ERROR;
    +   }else{
    +@@ -181935,7 +204756,7 @@ static void asciiFold(char *aOut, const char *aIn, int nByte){
    + static int fts5AsciiTokenize(
    +   Fts5Tokenizer *pTokenizer,
    +   void *pCtx,
    +-  int flags,
    ++  int iUnused,
    +   const char *pText, int nText,
    +   int (*xToken)(void*, int, const char*, int nToken, int iStart, int iEnd)
    + ){
    +@@ -181949,6 +204770,8 @@ static int fts5AsciiTokenize(
    +   char *pFold = aFold;
    +   unsigned char *a = p->aTokenChar;
    + 
    ++  UNUSED_PARAM(iUnused);
    ++
    +   while( is<nText && rc==SQLITE_OK ){
    +     int nByte;
    + 
    +@@ -182061,7 +204884,7 @@ static int fts5UnicodeAddExceptions(
    +   int bTokenChars                 /* 1 for 'tokenchars', 0 for 'separators' */
    + ){
    +   int rc = SQLITE_OK;
    +-  int n = strlen(z);
    ++  int n = (int)strlen(z);
    +   int *aNew;
    + 
    +   if( n>0 ){
    +@@ -182075,7 +204898,7 @@ static int fts5UnicodeAddExceptions(
    +         int bToken;
    +         READ_UTF8(zCsr, zTerm, iCode);
    +         if( iCode<128 ){
    +-          p->aTokenChar[iCode] = bTokenChars;
    ++          p->aTokenChar[iCode] = (unsigned char)bTokenChars;
    +         }else{
    +           bToken = sqlite3Fts5UnicodeIsalnum(iCode);
    +           assert( (bToken==0 || bToken==1) ); 
    +@@ -182142,13 +204965,15 @@ static void fts5UnicodeDelete(Fts5Tokenizer *pTok){
    + ** Create a "unicode61" tokenizer.
    + */
    + static int fts5UnicodeCreate(
    +-  void *pCtx, 
    ++  void *pUnused, 
    +   const char **azArg, int nArg,
    +   Fts5Tokenizer **ppOut
    + ){
    +   int rc = SQLITE_OK;             /* Return code */
    +   Unicode61Tokenizer *p = 0;      /* New tokenizer object */ 
    + 
    ++  UNUSED_PARAM(pUnused);
    ++
    +   if( nArg%2 ){
    +     rc = SQLITE_ERROR;
    +   }else{
    +@@ -182205,7 +205030,7 @@ static int fts5UnicodeIsAlnum(Unicode61Tokenizer *p, int iCode){
    + static int fts5UnicodeTokenize(
    +   Fts5Tokenizer *pTokenizer,
    +   void *pCtx,
    +-  int flags,
    ++  int iUnused,
    +   const char *pText, int nText,
    +   int (*xToken)(void*, int, const char*, int nToken, int iStart, int iEnd)
    + ){
    +@@ -182221,6 +205046,8 @@ static int fts5UnicodeTokenize(
    +   int nFold = p->nFold;
    +   const char *pEnd = &aFold[nFold-6];
    + 
    ++  UNUSED_PARAM(iUnused);
    ++
    +   /* Each iteration of this loop gobbles up a contiguous run of separators,
    +   ** then the next token.  */
    +   while( rc==SQLITE_OK ){
    +@@ -183039,7 +205866,7 @@ static int sqlite3Fts5TokenizerInit(fts5_api *pApi){
    +   int rc = SQLITE_OK;             /* Return code */
    +   int i;                          /* To iterate through builtin functions */
    + 
    +-  for(i=0; rc==SQLITE_OK && i<sizeof(aBuiltin)/sizeof(aBuiltin[0]); i++){
    ++  for(i=0; rc==SQLITE_OK && i<ArraySize(aBuiltin); i++){
    +     rc = pApi->xCreateTokenizer(pApi,
    +         aBuiltin[i].zName,
    +         (void*)pApi,
    +@@ -183180,9 +206007,9 @@ static int sqlite3Fts5UnicodeIsalnum(int c){
    +     0xFFFFFFFF, 0xFC00FFFF, 0xF8000001, 0xF8000001,
    +   };
    + 
    +-  if( c<128 ){
    ++  if( (unsigned int)c<128 ){
    +     return ( (aAscii[c >> 5] & (1 << (c & 0x001F)))==0 );
    +-  }else if( c<(1<<22) ){
    ++  }else if( (unsigned int)c<(1<<22) ){
    +     unsigned int key = (((unsigned int)c)<<10) | 0x000003FF;
    +     int iRes = 0;
    +     int iHi = sizeof(aEntry)/sizeof(aEntry[0]) - 1;
    +@@ -183430,6 +206257,7 @@ static int sqlite3Fts5UnicodeFold(int c, int bRemoveDiacritic){
    + */
    + 
    + 
    ++/* #include "fts5Int.h" */
    + 
    + /*
    + ** This is a copy of the sqlite3GetVarint32() routine from the SQLite core.
    +@@ -183748,7 +206576,10 @@ static int sqlite3Fts5PutVarint(unsigned char *p, u64 v){
    + 
    + 
    + static int sqlite3Fts5GetVarintLen(u32 iVal){
    ++#if 0
    +   if( iVal<(1 << 7 ) ) return 1;
    ++#endif
    ++  assert( iVal>=(1 << 7) );
    +   if( iVal<(1 << 14) ) return 2;
    +   if( iVal<(1 << 21) ) return 3;
    +   if( iVal<(1 << 28) ) return 4;
    +@@ -183787,9 +206618,15 @@ static int sqlite3Fts5GetVarintLen(u32 iVal){
    + **   the number of fts5 rows that contain at least one instance of term
    + **   $term. Field $cnt is set to the total number of instances of term 
    + **   $term in the database.
    ++**
    ++** instance:
    ++**     CREATE TABLE vocab(term, doc, col, offset, PRIMARY KEY(<all-fields>));
    ++**
    ++**   One row for each term instance in the database. 
    + */
    + 
    + 
    ++/* #include "fts5Int.h" */
    + 
    + 
    + typedef struct Fts5VocabTable Fts5VocabTable;
    +@@ -183801,7 +206638,7 @@ struct Fts5VocabTable {
    +   char *zFts5Db;                  /* Db containing fts5 table */
    +   sqlite3 *db;                    /* Database handle */
    +   Fts5Global *pGlobal;            /* FTS5 global object for this database */
    +-  int eType;                      /* FTS5_VOCAB_COL or ROW */
    ++  int eType;                      /* FTS5_VOCAB_COL, ROW or INSTANCE */
    + };
    + 
    + struct Fts5VocabCursor {
    +@@ -183812,23 +206649,39 @@ struct Fts5VocabCursor {
    +   int bEof;                       /* True if this cursor is at EOF */
    +   Fts5IndexIter *pIter;           /* Term/rowid iterator object */
    + 
    ++  int nLeTerm;                    /* Size of zLeTerm in bytes */
    ++  char *zLeTerm;                  /* (term <= $zLeTerm) paramater, or NULL */
    ++
    +   /* These are used by 'col' tables only */
    +-  int nCol;
    ++  Fts5Config *pConfig;            /* Fts5 table configuration */
    +   int iCol;
    +   i64 *aCnt;
    +   i64 *aDoc;
    + 
    +-  /* Output values */
    ++  /* Output values used by all tables. */
    +   i64 rowid;                      /* This table's current rowid value */
    +   Fts5Buffer term;                /* Current value of 'term' column */
    +-  i64 aVal[3];                    /* Up to three columns left of 'term' */
    ++
    ++  /* Output values Used by 'instance' tables only */
    ++  i64 iInstPos;
    ++  int iInstOff;
    + };
    + 
    +-#define FTS5_VOCAB_COL    0
    +-#define FTS5_VOCAB_ROW    1
    ++#define FTS5_VOCAB_COL      0
    ++#define FTS5_VOCAB_ROW      1
    ++#define FTS5_VOCAB_INSTANCE 2
    + 
    + #define FTS5_VOCAB_COL_SCHEMA  "term, col, doc, cnt"
    + #define FTS5_VOCAB_ROW_SCHEMA  "term, doc, cnt"
    ++#define FTS5_VOCAB_INST_SCHEMA "term, doc, col, offset"
    ++
    ++/*
    ++** Bits for the mask used as the idxNum value by xBestIndex/xFilter.
    ++*/
    ++#define FTS5_VOCAB_TERM_EQ 0x01
    ++#define FTS5_VOCAB_TERM_GE 0x02
    ++#define FTS5_VOCAB_TERM_LE 0x04
    ++
    + 
    + /*
    + ** Translate a string containing an fts5vocab table type to an 
    +@@ -183848,6 +206701,9 @@ static int fts5VocabTableType(const char *zType, char **pzErr, int *peType){
    +     if( sqlite3_stricmp(zCopy, "row")==0 ){
    +       *peType = FTS5_VOCAB_ROW;
    +     }else
    ++    if( sqlite3_stricmp(zCopy, "instance")==0 ){
    ++      *peType = FTS5_VOCAB_INSTANCE;
    ++    }else
    +     {
    +       *pzErr = sqlite3_mprintf("fts5vocab: unknown table type: %Q", zCopy);
    +       rc = SQLITE_ERROR;
    +@@ -183908,7 +206764,8 @@ static int fts5VocabInitVtab(
    + ){
    +   const char *azSchema[] = { 
    +     "CREATE TABlE vocab(" FTS5_VOCAB_COL_SCHEMA  ")", 
    +-    "CREATE TABlE vocab(" FTS5_VOCAB_ROW_SCHEMA  ")"
    ++    "CREATE TABlE vocab(" FTS5_VOCAB_ROW_SCHEMA  ")",
    ++    "CREATE TABlE vocab(" FTS5_VOCAB_INST_SCHEMA ")"
    +   };
    + 
    +   Fts5VocabTable *pRet = 0;
    +@@ -183925,13 +206782,13 @@ static int fts5VocabInitVtab(
    +     const char *zDb = bDb ? argv[3] : argv[1];
    +     const char *zTab = bDb ? argv[4] : argv[3];
    +     const char *zType = bDb ? argv[5] : argv[4];
    +-    int nDb = strlen(zDb)+1; 
    +-    int nTab = strlen(zTab)+1;
    +-    int eType;
    ++    int nDb = (int)strlen(zDb)+1; 
    ++    int nTab = (int)strlen(zTab)+1;
    ++    int eType = 0;
    +     
    +     rc = fts5VocabTableType(zType, pzErr, &eType);
    +     if( rc==SQLITE_OK ){
    +-      assert( eType>=0 && eType<sizeof(azSchema)/sizeof(azSchema[0]) );
    ++      assert( eType>=0 && eType<ArraySize(azSchema) );
    +       rc = sqlite3_declare_vtab(db, azSchema[eType]);
    +     }
    + 
    +@@ -183982,11 +206839,72 @@ static int fts5VocabCreateMethod(
    + 
    + /* 
    + ** Implementation of the xBestIndex method.
    ++**
    ++** Only constraints of the form:
    ++**
    ++**     term <= ?
    ++**     term == ?
    ++**     term >= ?
    ++**
    ++** are interpreted. Less-than and less-than-or-equal are treated 
    ++** identically, as are greater-than and greater-than-or-equal.
    + */
    + static int fts5VocabBestIndexMethod(
    +-  sqlite3_vtab *pVTab, 
    ++  sqlite3_vtab *pUnused,
    +   sqlite3_index_info *pInfo
    + ){
    ++  int i;
    ++  int iTermEq = -1;
    ++  int iTermGe = -1;
    ++  int iTermLe = -1;
    ++  int idxNum = 0;
    ++  int nArg = 0;
    ++
    ++  UNUSED_PARAM(pUnused);
    ++
    ++  for(i=0; i<pInfo->nConstraint; i++){
    ++    struct sqlite3_index_constraint *p = &pInfo->aConstraint[i];
    ++    if( p->usable==0 ) continue;
    ++    if( p->iColumn==0 ){          /* term column */
    ++      if( p->op==SQLITE_INDEX_CONSTRAINT_EQ ) iTermEq = i;
    ++      if( p->op==SQLITE_INDEX_CONSTRAINT_LE ) iTermLe = i;
    ++      if( p->op==SQLITE_INDEX_CONSTRAINT_LT ) iTermLe = i;
    ++      if( p->op==SQLITE_INDEX_CONSTRAINT_GE ) iTermGe = i;
    ++      if( p->op==SQLITE_INDEX_CONSTRAINT_GT ) iTermGe = i;
    ++    }
    ++  }
    ++
    ++  if( iTermEq>=0 ){
    ++    idxNum |= FTS5_VOCAB_TERM_EQ;
    ++    pInfo->aConstraintUsage[iTermEq].argvIndex = ++nArg;
    ++    pInfo->estimatedCost = 100;
    ++  }else{
    ++    pInfo->estimatedCost = 1000000;
    ++    if( iTermGe>=0 ){
    ++      idxNum |= FTS5_VOCAB_TERM_GE;
    ++      pInfo->aConstraintUsage[iTermGe].argvIndex = ++nArg;
    ++      pInfo->estimatedCost = pInfo->estimatedCost / 2;
    ++    }
    ++    if( iTermLe>=0 ){
    ++      idxNum |= FTS5_VOCAB_TERM_LE;
    ++      pInfo->aConstraintUsage[iTermLe].argvIndex = ++nArg;
    ++      pInfo->estimatedCost = pInfo->estimatedCost / 2;
    ++    }
    ++  }
    ++
    ++  /* This virtual table always delivers results in ascending order of
    ++  ** the "term" column (column 0). So if the user has requested this
    ++  ** specifically - "ORDER BY term" or "ORDER BY term ASC" - set the
    ++  ** sqlite3_index_info.orderByConsumed flag to tell the core the results
    ++  ** are already in sorted order.  */
    ++  if( pInfo->nOrderBy==1 
    ++   && pInfo->aOrderBy[0].iColumn==0 
    ++   && pInfo->aOrderBy[0].desc==0
    ++  ){
    ++    pInfo->orderByConsumed = 1;
    ++  }
    ++
    ++  pInfo->idxNum = idxNum;
    +   return SQLITE_OK;
    + }
    + 
    +@@ -183999,12 +206917,11 @@ static int fts5VocabOpenMethod(
    + ){
    +   Fts5VocabTable *pTab = (Fts5VocabTable*)pVTab;
    +   Fts5Index *pIndex = 0;
    +-  int nCol = 0;
    ++  Fts5Config *pConfig = 0;
    +   Fts5VocabCursor *pCsr = 0;
    +   int rc = SQLITE_OK;
    +   sqlite3_stmt *pStmt = 0;
    +   char *zSql = 0;
    +-  int nByte;
    + 
    +   zSql = sqlite3Fts5Mprintf(&rc,
    +       "SELECT t.%Q FROM %Q.%Q AS t WHERE t.%Q MATCH '*id'",
    +@@ -184019,7 +206936,7 @@ static int fts5VocabOpenMethod(
    + 
    +   if( pStmt && sqlite3_step(pStmt)==SQLITE_ROW ){
    +     i64 iId = sqlite3_column_int64(pStmt, 0);
    +-    pIndex = sqlite3Fts5IndexFromCsrid(pTab->pGlobal, iId, &nCol);
    ++    pIndex = sqlite3Fts5IndexFromCsrid(pTab->pGlobal, iId, &pConfig);
    +   }
    + 
    +   if( rc==SQLITE_OK && pIndex==0 ){
    +@@ -184033,14 +206950,17 @@ static int fts5VocabOpenMethod(
    +     }
    +   }
    + 
    +-  nByte = nCol * sizeof(i64) * 2 + sizeof(Fts5VocabCursor);
    +-  pCsr = (Fts5VocabCursor*)sqlite3Fts5MallocZero(&rc, nByte);
    ++  if( rc==SQLITE_OK ){
    ++    int nByte = pConfig->nCol * sizeof(i64) * 2 + sizeof(Fts5VocabCursor);
    ++    pCsr = (Fts5VocabCursor*)sqlite3Fts5MallocZero(&rc, nByte);
    ++  }
    ++
    +   if( pCsr ){
    +     pCsr->pIndex = pIndex;
    +     pCsr->pStmt = pStmt;
    +-    pCsr->nCol = nCol;
    ++    pCsr->pConfig = pConfig;
    +     pCsr->aCnt = (i64*)&pCsr[1];
    +-    pCsr->aDoc = &pCsr->aCnt[nCol];
    ++    pCsr->aDoc = &pCsr->aCnt[pConfig->nCol];
    +   }else{
    +     sqlite3_finalize(pStmt);
    +   }
    +@@ -184053,6 +206973,9 @@ static void fts5VocabResetCursor(Fts5VocabCursor *pCsr){
    +   pCsr->rowid = 0;
    +   sqlite3Fts5IterClose(pCsr->pIter);
    +   pCsr->pIter = 0;
    ++  sqlite3_free(pCsr->zLeTerm);
    ++  pCsr->nLeTerm = -1;
    ++  pCsr->zLeTerm = 0;
    + }
    + 
    + /*
    +@@ -184068,6 +206991,54 @@ static int fts5VocabCloseMethod(sqlite3_vtab_cursor *pCursor){
    +   return SQLITE_OK;
    + }
    + 
    ++static int fts5VocabInstanceNewTerm(Fts5VocabCursor *pCsr){
    ++  int rc = SQLITE_OK;
    ++  
    ++  if( sqlite3Fts5IterEof(pCsr->pIter) ){
    ++    pCsr->bEof = 1;
    ++  }else{
    ++    const char *zTerm;
    ++    int nTerm;
    ++    zTerm = sqlite3Fts5IterTerm(pCsr->pIter, &nTerm);
    ++    if( pCsr->nLeTerm>=0 ){
    ++      int nCmp = MIN(nTerm, pCsr->nLeTerm);
    ++      int bCmp = memcmp(pCsr->zLeTerm, zTerm, nCmp);
    ++      if( bCmp<0 || (bCmp==0 && pCsr->nLeTerm<nTerm) ){
    ++        pCsr->bEof = 1;
    ++      }
    ++    }
    ++
    ++    sqlite3Fts5BufferSet(&rc, &pCsr->term, nTerm, (const u8*)zTerm);
    ++  }
    ++  return rc;
    ++}
    ++
    ++static int fts5VocabInstanceNext(Fts5VocabCursor *pCsr){
    ++  int eDetail = pCsr->pConfig->eDetail;
    ++  int rc = SQLITE_OK;
    ++  Fts5IndexIter *pIter = pCsr->pIter;
    ++  i64 *pp = &pCsr->iInstPos;
    ++  int *po = &pCsr->iInstOff;
    ++  
    ++  while( eDetail==FTS5_DETAIL_NONE
    ++      || sqlite3Fts5PoslistNext64(pIter->pData, pIter->nData, po, pp) 
    ++  ){
    ++    pCsr->iInstPos = 0;
    ++    pCsr->iInstOff = 0;
    ++
    ++    rc = sqlite3Fts5IterNextScan(pCsr->pIter);
    ++    if( rc==SQLITE_OK ){
    ++      rc = fts5VocabInstanceNewTerm(pCsr);
    ++      if( eDetail==FTS5_DETAIL_NONE ) break;
    ++    }
    ++    if( rc ){
    ++      pCsr->bEof = 1;
    ++      break;
    ++    }
    ++  }
    ++
    ++  return rc;
    ++}
    + 
    + /*
    + ** Advance the cursor to the next row in the table.
    +@@ -184076,16 +207047,21 @@ static int fts5VocabNextMethod(sqlite3_vtab_cursor *pCursor){
    +   Fts5VocabCursor *pCsr = (Fts5VocabCursor*)pCursor;
    +   Fts5VocabTable *pTab = (Fts5VocabTable*)pCursor->pVtab;
    +   int rc = SQLITE_OK;
    ++  int nCol = pCsr->pConfig->nCol;
    + 
    +   pCsr->rowid++;
    + 
    ++  if( pTab->eType==FTS5_VOCAB_INSTANCE ){
    ++    return fts5VocabInstanceNext(pCsr);
    ++  }
    ++
    +   if( pTab->eType==FTS5_VOCAB_COL ){
    +-    for(pCsr->iCol++; pCsr->iCol<pCsr->nCol; pCsr->iCol++){
    +-      if( pCsr->aCnt[pCsr->iCol] ) break;
    ++    for(pCsr->iCol++; pCsr->iCol<nCol; pCsr->iCol++){
    ++      if( pCsr->aDoc[pCsr->iCol] ) break;
    +     }
    +   }
    + 
    +-  if( pTab->eType==FTS5_VOCAB_ROW || pCsr->iCol>=pCsr->nCol ){
    ++  if( pTab->eType!=FTS5_VOCAB_COL || pCsr->iCol>=nCol ){
    +     if( sqlite3Fts5IterEof(pCsr->pIter) ){
    +       pCsr->bEof = 1;
    +     }else{
    +@@ -184093,53 +207069,94 @@ static int fts5VocabNextMethod(sqlite3_vtab_cursor *pCursor){
    +       int nTerm;
    + 
    +       zTerm = sqlite3Fts5IterTerm(pCsr->pIter, &nTerm);
    ++      if( pCsr->nLeTerm>=0 ){
    ++        int nCmp = MIN(nTerm, pCsr->nLeTerm);
    ++        int bCmp = memcmp(pCsr->zLeTerm, zTerm, nCmp);
    ++        if( bCmp<0 || (bCmp==0 && pCsr->nLeTerm<nTerm) ){
    ++          pCsr->bEof = 1;
    ++          return SQLITE_OK;
    ++        }
    ++      }
    ++
    +       sqlite3Fts5BufferSet(&rc, &pCsr->term, nTerm, (const u8*)zTerm);
    +-      memset(pCsr->aVal, 0, sizeof(pCsr->aVal));
    +-      memset(pCsr->aCnt, 0, pCsr->nCol * sizeof(i64));
    +-      memset(pCsr->aDoc, 0, pCsr->nCol * sizeof(i64));
    ++      memset(pCsr->aCnt, 0, nCol * sizeof(i64));
    ++      memset(pCsr->aDoc, 0, nCol * sizeof(i64));
    +       pCsr->iCol = 0;
    + 
    +       assert( pTab->eType==FTS5_VOCAB_COL || pTab->eType==FTS5_VOCAB_ROW );
    +       while( rc==SQLITE_OK ){
    +-        i64 dummy;
    ++        int eDetail = pCsr->pConfig->eDetail;
    +         const u8 *pPos; int nPos;   /* Position list */
    +         i64 iPos = 0;               /* 64-bit position read from poslist */
    +         int iOff = 0;               /* Current offset within position list */
    + 
    +-        rc = sqlite3Fts5IterPoslist(pCsr->pIter, 0, &pPos, &nPos, &dummy);
    +-        if( rc==SQLITE_OK ){
    +-          if( pTab->eType==FTS5_VOCAB_ROW ){
    +-            while( 0==sqlite3Fts5PoslistNext64(pPos, nPos, &iOff, &iPos) ){
    +-              pCsr->aVal[1]++;
    ++        pPos = pCsr->pIter->pData;
    ++        nPos = pCsr->pIter->nData;
    ++
    ++        switch( pTab->eType ){
    ++          case FTS5_VOCAB_ROW:
    ++            if( eDetail==FTS5_DETAIL_FULL ){
    ++              while( 0==sqlite3Fts5PoslistNext64(pPos, nPos, &iOff, &iPos) ){
    ++                pCsr->aCnt[0]++;
    ++              }
    +             }
    +-            pCsr->aVal[0]++;
    +-          }else{
    +-            int iCol = -1;
    +-            while( 0==sqlite3Fts5PoslistNext64(pPos, nPos, &iOff, &iPos) ){
    +-              int ii = FTS5_POS2COLUMN(iPos);
    +-              pCsr->aCnt[ii]++;
    +-              if( iCol!=ii ){
    +-                pCsr->aDoc[ii]++;
    +-                iCol = ii;
    ++            pCsr->aDoc[0]++;
    ++            break;
    ++
    ++          case FTS5_VOCAB_COL:
    ++            if( eDetail==FTS5_DETAIL_FULL ){
    ++              int iCol = -1;
    ++              while( 0==sqlite3Fts5PoslistNext64(pPos, nPos, &iOff, &iPos) ){
    ++                int ii = FTS5_POS2COLUMN(iPos);
    ++                pCsr->aCnt[ii]++;
    ++                if( iCol!=ii ){
    ++                  if( ii>=nCol ){
    ++                    rc = FTS5_CORRUPT;
    ++                    break;
    ++                  }
    ++                  pCsr->aDoc[ii]++;
    ++                  iCol = ii;
    ++                }
    +               }
    ++            }else if( eDetail==FTS5_DETAIL_COLUMNS ){
    ++              while( 0==sqlite3Fts5PoslistNext64(pPos, nPos, &iOff,&iPos) ){
    ++                assert_nc( iPos>=0 && iPos<nCol );
    ++                if( iPos>=nCol ){
    ++                  rc = FTS5_CORRUPT;
    ++                  break;
    ++                }
    ++                pCsr->aDoc[iPos]++;
    ++              }
    ++            }else{
    ++              assert( eDetail==FTS5_DETAIL_NONE );
    ++              pCsr->aDoc[0]++;
    +             }
    +-          }
    ++            break;
    ++
    ++          default:
    ++            assert( pTab->eType==FTS5_VOCAB_INSTANCE );
    ++            break;
    ++        }
    ++
    ++        if( rc==SQLITE_OK ){
    +           rc = sqlite3Fts5IterNextScan(pCsr->pIter);
    +         }
    ++        if( pTab->eType==FTS5_VOCAB_INSTANCE ) break;
    ++
    +         if( rc==SQLITE_OK ){
    +           zTerm = sqlite3Fts5IterTerm(pCsr->pIter, &nTerm);
    +-          if( nTerm!=pCsr->term.n || memcmp(zTerm, pCsr->term.p, nTerm) ) break;
    ++          if( nTerm!=pCsr->term.n || memcmp(zTerm, pCsr->term.p, nTerm) ){
    ++            break;
    ++          }
    +           if( sqlite3Fts5IterEof(pCsr->pIter) ) break;
    +         }
    +       }
    +     }
    +   }
    + 
    +-  if( pCsr->bEof==0 && pTab->eType==FTS5_VOCAB_COL ){
    +-    while( pCsr->aCnt[pCsr->iCol]==0 ) pCsr->iCol++;
    +-    pCsr->aVal[0] = pCsr->iCol;
    +-    pCsr->aVal[1] = pCsr->aDoc[pCsr->iCol];
    +-    pCsr->aVal[2] = pCsr->aCnt[pCsr->iCol];
    ++  if( rc==SQLITE_OK && pCsr->bEof==0 && pTab->eType==FTS5_VOCAB_COL ){
    ++    while( pCsr->aDoc[pCsr->iCol]==0 ) pCsr->iCol++;
    ++    assert( pCsr->iCol<pCsr->pConfig->nCol );
    +   }
    +   return rc;
    + }
    +@@ -184150,17 +207167,62 @@ static int fts5VocabNextMethod(sqlite3_vtab_cursor *pCursor){
    + static int fts5VocabFilterMethod(
    +   sqlite3_vtab_cursor *pCursor,   /* The cursor used for this query */
    +   int idxNum,                     /* Strategy index */
    +-  const char *idxStr,             /* Unused */
    +-  int nVal,                       /* Number of elements in apVal */
    ++  const char *zUnused,            /* Unused */
    ++  int nUnused,                    /* Number of elements in apVal */
    +   sqlite3_value **apVal           /* Arguments for the indexing scheme */
    + ){
    ++  Fts5VocabTable *pTab = (Fts5VocabTable*)pCursor->pVtab;
    +   Fts5VocabCursor *pCsr = (Fts5VocabCursor*)pCursor;
    +-  int rc;
    +-  const int flags = FTS5INDEX_QUERY_SCAN;
    ++  int eType = pTab->eType;
    ++  int rc = SQLITE_OK;
    ++
    ++  int iVal = 0;
    ++  int f = FTS5INDEX_QUERY_SCAN;
    ++  const char *zTerm = 0;
    ++  int nTerm = 0;
    ++
    ++  sqlite3_value *pEq = 0;
    ++  sqlite3_value *pGe = 0;
    ++  sqlite3_value *pLe = 0;
    ++
    ++  UNUSED_PARAM2(zUnused, nUnused);
    + 
    +   fts5VocabResetCursor(pCsr);
    +-  rc = sqlite3Fts5IndexQuery(pCsr->pIndex, 0, 0, flags, 0, &pCsr->pIter);
    ++  if( idxNum & FTS5_VOCAB_TERM_EQ ) pEq = apVal[iVal++];
    ++  if( idxNum & FTS5_VOCAB_TERM_GE ) pGe = apVal[iVal++];
    ++  if( idxNum & FTS5_VOCAB_TERM_LE ) pLe = apVal[iVal++];
    ++
    ++  if( pEq ){
    ++    zTerm = (const char *)sqlite3_value_text(pEq);
    ++    nTerm = sqlite3_value_bytes(pEq);
    ++    f = 0;
    ++  }else{
    ++    if( pGe ){
    ++      zTerm = (const char *)sqlite3_value_text(pGe);
    ++      nTerm = sqlite3_value_bytes(pGe);
    ++    }
    ++    if( pLe ){
    ++      const char *zCopy = (const char *)sqlite3_value_text(pLe);
    ++      pCsr->nLeTerm = sqlite3_value_bytes(pLe);
    ++      pCsr->zLeTerm = sqlite3_malloc(pCsr->nLeTerm+1);
    ++      if( pCsr->zLeTerm==0 ){
    ++        rc = SQLITE_NOMEM;
    ++      }else{
    ++        memcpy(pCsr->zLeTerm, zCopy, pCsr->nLeTerm+1);
    ++      }
    ++    }
    ++  }
    ++
    +   if( rc==SQLITE_OK ){
    ++    rc = sqlite3Fts5IndexQuery(pCsr->pIndex, zTerm, nTerm, f, 0, &pCsr->pIter);
    ++  }
    ++  if( rc==SQLITE_OK && eType==FTS5_VOCAB_INSTANCE ){
    ++    rc = fts5VocabInstanceNewTerm(pCsr);
    ++  }
    ++  if( rc==SQLITE_OK 
    ++   && !pCsr->bEof 
    ++   && (eType!=FTS5_VOCAB_INSTANCE || pCsr->pConfig->eDetail!=FTS5_DETAIL_NONE)
    ++  ){
    +     rc = fts5VocabNextMethod(pCursor);
    +   }
    + 
    +@@ -184182,18 +207244,64 @@ static int fts5VocabColumnMethod(
    +   int iCol                        /* Index of column to read value from */
    + ){
    +   Fts5VocabCursor *pCsr = (Fts5VocabCursor*)pCursor;
    +-  switch( iCol ){
    +-    case 0: /* term */
    +-      sqlite3_result_text(
    +-          pCtx, (const char*)pCsr->term.p, pCsr->term.n, SQLITE_TRANSIENT
    +-      );
    +-      break;
    ++  int eDetail = pCsr->pConfig->eDetail;
    ++  int eType = ((Fts5VocabTable*)(pCursor->pVtab))->eType;
    ++  i64 iVal = 0;
    + 
    +-    default:
    +-      assert( iCol<4 && iCol>0 );
    +-      sqlite3_result_int64(pCtx, pCsr->aVal[iCol-1]);
    +-      break;
    ++  if( iCol==0 ){
    ++    sqlite3_result_text(
    ++        pCtx, (const char*)pCsr->term.p, pCsr->term.n, SQLITE_TRANSIENT
    ++    );
    ++  }else if( eType==FTS5_VOCAB_COL ){
    ++    assert( iCol==1 || iCol==2 || iCol==3 );
    ++    if( iCol==1 ){
    ++      if( eDetail!=FTS5_DETAIL_NONE ){
    ++        const char *z = pCsr->pConfig->azCol[pCsr->iCol];
    ++        sqlite3_result_text(pCtx, z, -1, SQLITE_STATIC);
    ++      }
    ++    }else if( iCol==2 ){
    ++      iVal = pCsr->aDoc[pCsr->iCol];
    ++    }else{
    ++      iVal = pCsr->aCnt[pCsr->iCol];
    ++    }
    ++  }else if( eType==FTS5_VOCAB_ROW ){
    ++    assert( iCol==1 || iCol==2 );
    ++    if( iCol==1 ){
    ++      iVal = pCsr->aDoc[0];
    ++    }else{
    ++      iVal = pCsr->aCnt[0];
    ++    }
    ++  }else{
    ++    assert( eType==FTS5_VOCAB_INSTANCE );
    ++    switch( iCol ){
    ++      case 1:
    ++        sqlite3_result_int64(pCtx, pCsr->pIter->iRowid);
    ++        break;
    ++      case 2: {
    ++        int ii = -1;
    ++        if( eDetail==FTS5_DETAIL_FULL ){
    ++          ii = FTS5_POS2COLUMN(pCsr->iInstPos);
    ++        }else if( eDetail==FTS5_DETAIL_COLUMNS ){
    ++          ii = (int)pCsr->iInstPos;
    ++        }
    ++        if( ii>=0 && ii<pCsr->pConfig->nCol ){
    ++          const char *z = pCsr->pConfig->azCol[ii];
    ++          sqlite3_result_text(pCtx, z, -1, SQLITE_STATIC);
    ++        }
    ++        break;
    ++      }
    ++      default: {
    ++        assert( iCol==3 );
    ++        if( eDetail==FTS5_DETAIL_FULL ){
    ++          int ii = FTS5_POS2OFFSET(pCsr->iInstPos);
    ++          sqlite3_result_int(pCtx, ii);
    ++        }
    ++        break;
    ++      }
    ++    }
    +   }
    ++
    ++  if( iVal>0 ) sqlite3_result_int64(pCtx, iVal);
    +   return SQLITE_OK;
    + }
    + 
    +@@ -184249,3 +207357,311 @@ static int sqlite3Fts5VocabInit(Fts5Global *pGlobal, sqlite3 *db){
    + #endif /* !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_FTS5) */
    + 
    + /************** End of fts5.c ************************************************/
    ++/************** Begin file stmt.c ********************************************/
    ++/*
    ++** 2017-05-31
    ++**
    ++** 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 demonstrates an eponymous virtual table that returns information
    ++** about all prepared statements for the database connection.
    ++**
    ++** Usage example:
    ++**
    ++**     .load ./stmt
    ++**     .mode line
    ++**     .header on
    ++**     SELECT * FROM stmt;
    ++*/
    ++#if !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_STMTVTAB)
    ++#if !defined(SQLITEINT_H)
    ++/* #include "sqlite3ext.h" */
    ++#endif
    ++SQLITE_EXTENSION_INIT1
    ++/* #include <assert.h> */
    ++/* #include <string.h> */
    ++
    ++#ifndef SQLITE_OMIT_VIRTUALTABLE
    ++
    ++/* stmt_vtab is a subclass of sqlite3_vtab which will
    ++** serve as the underlying representation of a stmt virtual table
    ++*/
    ++typedef struct stmt_vtab stmt_vtab;
    ++struct stmt_vtab {
    ++  sqlite3_vtab base;  /* Base class - must be first */
    ++  sqlite3 *db;        /* Database connection for this stmt vtab */
    ++};
    ++
    ++/* stmt_cursor is a subclass of sqlite3_vtab_cursor which will
    ++** serve as the underlying representation of a cursor that scans
    ++** over rows of the result
    ++*/
    ++typedef struct stmt_cursor stmt_cursor;
    ++struct stmt_cursor {
    ++  sqlite3_vtab_cursor base;  /* Base class - must be first */
    ++  sqlite3 *db;               /* Database connection for this cursor */
    ++  sqlite3_stmt *pStmt;       /* Statement cursor is currently pointing at */
    ++  sqlite3_int64 iRowid;      /* The rowid */
    ++};
    ++
    ++/*
    ++** The stmtConnect() method is invoked to create a new
    ++** stmt_vtab that describes the stmt virtual table.
    ++**
    ++** Think of this routine as the constructor for stmt_vtab objects.
    ++**
    ++** All this routine needs to do is:
    ++**
    ++**    (1) Allocate the stmt_vtab object and initialize all fields.
    ++**
    ++**    (2) Tell SQLite (via the sqlite3_declare_vtab() interface) what the
    ++**        result set of queries against stmt will look like.
    ++*/
    ++static int stmtConnect(
    ++  sqlite3 *db,
    ++  void *pAux,
    ++  int argc, const char *const*argv,
    ++  sqlite3_vtab **ppVtab,
    ++  char **pzErr
    ++){
    ++  stmt_vtab *pNew;
    ++  int rc;
    ++
    ++/* Column numbers */
    ++#define STMT_COLUMN_SQL     0   /* SQL for the statement */
    ++#define STMT_COLUMN_NCOL    1   /* Number of result columns */
    ++#define STMT_COLUMN_RO      2   /* True if read-only */
    ++#define STMT_COLUMN_BUSY    3   /* True if currently busy */
    ++#define STMT_COLUMN_NSCAN   4   /* SQLITE_STMTSTATUS_FULLSCAN_STEP */
    ++#define STMT_COLUMN_NSORT   5   /* SQLITE_STMTSTATUS_SORT */
    ++#define STMT_COLUMN_NAIDX   6   /* SQLITE_STMTSTATUS_AUTOINDEX */
    ++#define STMT_COLUMN_NSTEP   7   /* SQLITE_STMTSTATUS_VM_STEP */
    ++#define STMT_COLUMN_REPREP  8   /* SQLITE_STMTSTATUS_REPREPARE */
    ++#define STMT_COLUMN_RUN     9   /* SQLITE_STMTSTATUS_RUN */
    ++#define STMT_COLUMN_MEM    10   /* SQLITE_STMTSTATUS_MEMUSED */
    ++
    ++
    ++  rc = sqlite3_declare_vtab(db,
    ++     "CREATE TABLE x(sql,ncol,ro,busy,nscan,nsort,naidx,nstep,"
    ++                    "reprep,run,mem)");
    ++  if( rc==SQLITE_OK ){
    ++    pNew = sqlite3_malloc( sizeof(*pNew) );
    ++    *ppVtab = (sqlite3_vtab*)pNew;
    ++    if( pNew==0 ) return SQLITE_NOMEM;
    ++    memset(pNew, 0, sizeof(*pNew));
    ++    pNew->db = db;
    ++  }
    ++  return rc;
    ++}
    ++
    ++/*
    ++** This method is the destructor for stmt_cursor objects.
    ++*/
    ++static int stmtDisconnect(sqlite3_vtab *pVtab){
    ++  sqlite3_free(pVtab);
    ++  return SQLITE_OK;
    ++}
    ++
    ++/*
    ++** Constructor for a new stmt_cursor object.
    ++*/
    ++static int stmtOpen(sqlite3_vtab *p, sqlite3_vtab_cursor **ppCursor){
    ++  stmt_cursor *pCur;
    ++  pCur = sqlite3_malloc( sizeof(*pCur) );
    ++  if( pCur==0 ) return SQLITE_NOMEM;
    ++  memset(pCur, 0, sizeof(*pCur));
    ++  pCur->db = ((stmt_vtab*)p)->db;
    ++  *ppCursor = &pCur->base;
    ++  return SQLITE_OK;
    ++}
    ++
    ++/*
    ++** Destructor for a stmt_cursor.
    ++*/
    ++static int stmtClose(sqlite3_vtab_cursor *cur){
    ++  sqlite3_free(cur);
    ++  return SQLITE_OK;
    ++}
    ++
    ++
    ++/*
    ++** Advance a stmt_cursor to its next row of output.
    ++*/
    ++static int stmtNext(sqlite3_vtab_cursor *cur){
    ++  stmt_cursor *pCur = (stmt_cursor*)cur;
    ++  pCur->iRowid++;
    ++  pCur->pStmt = sqlite3_next_stmt(pCur->db, pCur->pStmt);
    ++  return SQLITE_OK;
    ++}
    ++
    ++/*
    ++** Return values of columns for the row at which the stmt_cursor
    ++** is currently pointing.
    ++*/
    ++static int stmtColumn(
    ++  sqlite3_vtab_cursor *cur,   /* The cursor */
    ++  sqlite3_context *ctx,       /* First argument to sqlite3_result_...() */
    ++  int i                       /* Which column to return */
    ++){
    ++  stmt_cursor *pCur = (stmt_cursor*)cur;
    ++  switch( i ){
    ++    case STMT_COLUMN_SQL: {
    ++      sqlite3_result_text(ctx, sqlite3_sql(pCur->pStmt), -1, SQLITE_TRANSIENT);
    ++      break;
    ++    }
    ++    case STMT_COLUMN_NCOL: {
    ++      sqlite3_result_int(ctx, sqlite3_column_count(pCur->pStmt));
    ++      break;
    ++    }
    ++    case STMT_COLUMN_RO: {
    ++      sqlite3_result_int(ctx, sqlite3_stmt_readonly(pCur->pStmt));
    ++      break;
    ++    }
    ++    case STMT_COLUMN_BUSY: {
    ++      sqlite3_result_int(ctx, sqlite3_stmt_busy(pCur->pStmt));
    ++      break;
    ++    }
    ++    case STMT_COLUMN_MEM: {
    ++      i = SQLITE_STMTSTATUS_MEMUSED + 
    ++            STMT_COLUMN_NSCAN - SQLITE_STMTSTATUS_FULLSCAN_STEP;
    ++      /* Fall thru */
    ++    }
    ++    case STMT_COLUMN_NSCAN:
    ++    case STMT_COLUMN_NSORT:
    ++    case STMT_COLUMN_NAIDX:
    ++    case STMT_COLUMN_NSTEP:
    ++    case STMT_COLUMN_REPREP:
    ++    case STMT_COLUMN_RUN: {
    ++      sqlite3_result_int(ctx, sqlite3_stmt_status(pCur->pStmt,
    ++                      i-STMT_COLUMN_NSCAN+SQLITE_STMTSTATUS_FULLSCAN_STEP, 0));
    ++      break;
    ++    }
    ++  }
    ++  return SQLITE_OK;
    ++}
    ++
    ++/*
    ++** Return the rowid for the current row.  In this implementation, the
    ++** rowid is the same as the output value.
    ++*/
    ++static int stmtRowid(sqlite3_vtab_cursor *cur, sqlite_int64 *pRowid){
    ++  stmt_cursor *pCur = (stmt_cursor*)cur;
    ++  *pRowid = pCur->iRowid;
    ++  return SQLITE_OK;
    ++}
    ++
    ++/*
    ++** Return TRUE if the cursor has been moved off of the last
    ++** row of output.
    ++*/
    ++static int stmtEof(sqlite3_vtab_cursor *cur){
    ++  stmt_cursor *pCur = (stmt_cursor*)cur;
    ++  return pCur->pStmt==0;
    ++}
    ++
    ++/*
    ++** This method is called to "rewind" the stmt_cursor object back
    ++** to the first row of output.  This method is always called at least
    ++** once prior to any call to stmtColumn() or stmtRowid() or 
    ++** stmtEof().
    ++*/
    ++static int stmtFilter(
    ++  sqlite3_vtab_cursor *pVtabCursor, 
    ++  int idxNum, const char *idxStr,
    ++  int argc, sqlite3_value **argv
    ++){
    ++  stmt_cursor *pCur = (stmt_cursor *)pVtabCursor;
    ++  pCur->pStmt = 0;
    ++  pCur->iRowid = 0;
    ++  return stmtNext(pVtabCursor);
    ++}
    ++
    ++/*
    ++** SQLite will invoke this method one or more times while planning a query
    ++** that uses the stmt virtual table.  This routine needs to create
    ++** a query plan for each invocation and compute an estimated cost for that
    ++** plan.
    ++*/
    ++static int stmtBestIndex(
    ++  sqlite3_vtab *tab,
    ++  sqlite3_index_info *pIdxInfo
    ++){
    ++  pIdxInfo->estimatedCost = (double)500;
    ++  pIdxInfo->estimatedRows = 500;
    ++  return SQLITE_OK;
    ++}
    ++
    ++/*
    ++** This following structure defines all the methods for the 
    ++** stmt virtual table.
    ++*/
    ++static sqlite3_module stmtModule = {
    ++  0,                         /* iVersion */
    ++  0,                         /* xCreate */
    ++  stmtConnect,               /* xConnect */
    ++  stmtBestIndex,             /* xBestIndex */
    ++  stmtDisconnect,            /* xDisconnect */
    ++  0,                         /* xDestroy */
    ++  stmtOpen,                  /* xOpen - open a cursor */
    ++  stmtClose,                 /* xClose - close a cursor */
    ++  stmtFilter,                /* xFilter - configure scan constraints */
    ++  stmtNext,                  /* xNext - advance a cursor */
    ++  stmtEof,                   /* xEof - check for end of scan */
    ++  stmtColumn,                /* xColumn - read data */
    ++  stmtRowid,                 /* xRowid - read data */
    ++  0,                         /* xUpdate */
    ++  0,                         /* xBegin */
    ++  0,                         /* xSync */
    ++  0,                         /* xCommit */
    ++  0,                         /* xRollback */
    ++  0,                         /* xFindMethod */
    ++  0,                         /* xRename */
    ++  0,                         /* xSavepoint */
    ++  0,                         /* xRelease */
    ++  0,                         /* xRollbackTo */
    ++};
    ++
    ++#endif /* SQLITE_OMIT_VIRTUALTABLE */
    ++
    ++SQLITE_PRIVATE int sqlite3StmtVtabInit(sqlite3 *db){
    ++  int rc = SQLITE_OK;
    ++#ifndef SQLITE_OMIT_VIRTUALTABLE
    ++  rc = sqlite3_create_module(db, "sqlite_stmt", &stmtModule, 0);
    ++#endif
    ++  return rc;
    ++}
    ++
    ++#ifndef SQLITE_CORE
    ++#ifdef _WIN32
    ++__declspec(dllexport)
    ++#endif
    ++SQLITE_API int sqlite3_stmt_init(
    ++  sqlite3 *db, 
    ++  char **pzErrMsg, 
    ++  const sqlite3_api_routines *pApi
    ++){
    ++  int rc = SQLITE_OK;
    ++  SQLITE_EXTENSION_INIT2(pApi);
    ++#ifndef SQLITE_OMIT_VIRTUALTABLE
    ++  rc = sqlite3StmtVtabInit(db);
    ++#endif
    ++  return rc;
    ++}
    ++#endif /* SQLITE_CORE */
    ++#endif /* !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_STMTVTAB) */
    ++
    ++/************** End of stmt.c ************************************************/
    ++#if __LINE__!=207661
    ++#undef SQLITE_SOURCE_ID
    ++#define SQLITE_SOURCE_ID      "2018-12-19 01:30:22 c255889bd95bd5430dc7ced3317011ae2abb483d6c9af883af3dc7d6c2c2alt2"
    ++#endif
    ++/* Return the source-id for this library */
    ++SQLITE_API const char *sqlite3_sourceid(void){ return SQLITE_SOURCE_ID; }
    ++/************************** End of sqlite3.c ******************************/
    +diff --git a/dist/orig/sqlite3.h b/dist/orig/sqlite3.h
    +index 7cca0ac..57669e1 100644
    +--- a/dist/orig/sqlite3.h
    ++++ b/dist/orig/sqlite3.h
    +@@ -1,5 +1,5 @@
    + /*
    +-** 2001 September 15
    ++** 2001-09-15
    + **
    + ** The author disclaims copyright to this source code.  In place of
    + ** a legal notice, here is a blessing:
    +@@ -30,8 +30,8 @@
    + ** the version number) and changes its name to "sqlite3.h" as
    + ** part of the build process.
    + */
    +-#ifndef _SQLITE3_H_
    +-#define _SQLITE3_H_
    ++#ifndef SQLITE3_H
    ++#define SQLITE3_H
    + #include <stdarg.h>     /* Needed for the definition of va_list */
    + 
    + /*
    +@@ -54,8 +54,17 @@ extern "C" {
    + #ifndef SQLITE_CDECL
    + # define SQLITE_CDECL
    + #endif
    ++#ifndef SQLITE_APICALL
    ++# define SQLITE_APICALL
    ++#endif
    + #ifndef SQLITE_STDCALL
    +-# define SQLITE_STDCALL
    ++# define SQLITE_STDCALL SQLITE_APICALL
    ++#endif
    ++#ifndef SQLITE_CALLBACK
    ++# define SQLITE_CALLBACK
    ++#endif
    ++#ifndef SQLITE_SYSAPI
    ++# define SQLITE_SYSAPI
    + #endif
    + 
    + /*
    +@@ -99,25 +108,28 @@ extern "C" {
    + ** be held constant and Z will be incremented or else Y will be incremented
    + ** and Z will be reset to zero.
    + **
    +-** Since version 3.6.18, SQLite source code has been stored in the
    ++** Since [version 3.6.18] ([dateof:3.6.18]), 
    ++** SQLite source code has been stored in the
    + ** <a href="http://www.fossil-scm.org/">Fossil configuration management
    + ** system</a>.  ^The SQLITE_SOURCE_ID macro evaluates to
    + ** a string which identifies a particular check-in of SQLite
    + ** within its configuration management system.  ^The SQLITE_SOURCE_ID
    +-** string contains the date and time of the check-in (UTC) and an SHA1
    +-** hash of the entire source tree.
    ++** string contains the date and time of the check-in (UTC) and a SHA1
    ++** or SHA3-256 hash of the entire source tree.  If the source code has
    ++** been edited in any way since it was last checked in, then the last
    ++** four hexadecimal digits of the hash may be modified.
    + **
    + ** See also: [sqlite3_libversion()],
    + ** [sqlite3_libversion_number()], [sqlite3_sourceid()],
    + ** [sqlite_version()] and [sqlite_source_id()].
    + */
    +-#define SQLITE_VERSION        "3.9.2"
    +-#define SQLITE_VERSION_NUMBER 3009002
    +-#define SQLITE_SOURCE_ID      "2015-11-02 18:31:45 bda77dda9697c463c3d0704014d51627fceee328"
    ++#define SQLITE_VERSION        "3.22.0"
    ++#define SQLITE_VERSION_NUMBER 3022000
    ++#define SQLITE_SOURCE_ID      "2018-12-19 01:30:22 c255889bd95bd5430dc7ced3317011ae2abb483d6c9af883af3dc7d6c2c2f234"
    + 
    + /*
    + ** CAPI3REF: Run-Time Library Version Numbers
    +-** KEYWORDS: sqlite3_version, sqlite3_sourceid
    ++** KEYWORDS: sqlite3_version sqlite3_sourceid
    + **
    + ** These interfaces provide the same information as the [SQLITE_VERSION],
    + ** [SQLITE_VERSION_NUMBER], and [SQLITE_SOURCE_ID] C preprocessor macros
    +@@ -129,7 +141,7 @@ extern "C" {
    + **
    + ** <blockquote><pre>
    + ** assert( sqlite3_libversion_number()==SQLITE_VERSION_NUMBER );
    +-** assert( strcmp(sqlite3_sourceid(),SQLITE_SOURCE_ID)==0 );
    ++** assert( strncmp(sqlite3_sourceid(),SQLITE_SOURCE_ID,80)==0 );
    + ** assert( strcmp(sqlite3_libversion(),SQLITE_VERSION)==0 );
    + ** </pre></blockquote>)^
    + **
    +@@ -139,16 +151,18 @@ extern "C" {
    + ** function is provided for use in DLLs since DLL users usually do not have
    + ** direct access to string constants within the DLL.  ^The
    + ** sqlite3_libversion_number() function returns an integer equal to
    +-** [SQLITE_VERSION_NUMBER].  ^The sqlite3_sourceid() function returns 
    ++** [SQLITE_VERSION_NUMBER].  ^(The sqlite3_sourceid() function returns 
    + ** a pointer to a string constant whose value is the same as the 
    +-** [SQLITE_SOURCE_ID] C preprocessor macro.
    ++** [SQLITE_SOURCE_ID] C preprocessor macro.  Except if SQLite is built
    ++** using an edited copy of [the amalgamation], then the last four characters
    ++** of the hash might be different from [SQLITE_SOURCE_ID].)^
    + **
    + ** See also: [sqlite_version()] and [sqlite_source_id()].
    + */
    + SQLITE_API SQLITE_EXTERN const char sqlite3_version[];
    +-SQLITE_API const char *SQLITE_STDCALL sqlite3_libversion(void);
    +-SQLITE_API const char *SQLITE_STDCALL sqlite3_sourceid(void);
    +-SQLITE_API int SQLITE_STDCALL sqlite3_libversion_number(void);
    ++SQLITE_API const char *sqlite3_libversion(void);
    ++SQLITE_API const char *sqlite3_sourceid(void);
    ++SQLITE_API int sqlite3_libversion_number(void);
    + 
    + /*
    + ** CAPI3REF: Run-Time Library Compilation Options Diagnostics
    +@@ -173,8 +187,8 @@ SQLITE_API int SQLITE_STDCALL sqlite3_libversion_number(void);
    + ** [sqlite_compileoption_get()] and the [compile_options pragma].
    + */
    + #ifndef SQLITE_OMIT_COMPILEOPTION_DIAGS
    +-SQLITE_API int SQLITE_STDCALL sqlite3_compileoption_used(const char *zOptName);
    +-SQLITE_API const char *SQLITE_STDCALL sqlite3_compileoption_get(int N);
    ++SQLITE_API int sqlite3_compileoption_used(const char *zOptName);
    ++SQLITE_API const char *sqlite3_compileoption_get(int N);
    + #endif
    + 
    + /*
    +@@ -213,7 +227,7 @@ SQLITE_API const char *SQLITE_STDCALL sqlite3_compileoption_get(int N);
    + **
    + ** See the [threading mode] documentation for additional information.
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_threadsafe(void);
    ++SQLITE_API int sqlite3_threadsafe(void);
    + 
    + /*
    + ** CAPI3REF: Database Connection Handle
    +@@ -249,7 +263,11 @@ typedef struct sqlite3 sqlite3;
    + */
    + #ifdef SQLITE_INT64_TYPE
    +   typedef SQLITE_INT64_TYPE sqlite_int64;
    +-  typedef unsigned SQLITE_INT64_TYPE sqlite_uint64;
    ++# ifdef SQLITE_UINT64_TYPE
    ++    typedef SQLITE_UINT64_TYPE sqlite_uint64;
    ++# else  
    ++    typedef unsigned SQLITE_INT64_TYPE sqlite_uint64;
    ++# endif
    + #elif defined(_MSC_VER) || defined(__BORLANDC__)
    +   typedef __int64 sqlite_int64;
    +   typedef unsigned __int64 sqlite_uint64;
    +@@ -310,8 +328,8 @@ typedef sqlite_uint64 sqlite3_uint64;
    + ** ^Calling sqlite3_close() or sqlite3_close_v2() with a NULL pointer
    + ** argument is a harmless no-op.
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_close(sqlite3*);
    +-SQLITE_API int SQLITE_STDCALL sqlite3_close_v2(sqlite3*);
    ++SQLITE_API int sqlite3_close(sqlite3*);
    ++SQLITE_API int sqlite3_close_v2(sqlite3*);
    + 
    + /*
    + ** The type for a callback function.
    +@@ -347,7 +365,7 @@ typedef int (*sqlite3_callback)(void*,int,char**, char**);
    + ** from [sqlite3_malloc()] and passed back through the 5th parameter.
    + ** To avoid memory leaks, the application should invoke [sqlite3_free()]
    + ** on error message strings returned through the 5th parameter of
    +-** of sqlite3_exec() after the error message string is no longer needed.
    ++** sqlite3_exec() after the error message string is no longer needed.
    + ** ^If the 5th parameter to sqlite3_exec() is not NULL and no errors
    + ** occur, then sqlite3_exec() sets the pointer in its 5th parameter to
    + ** NULL before returning.
    +@@ -382,7 +400,7 @@ typedef int (*sqlite3_callback)(void*,int,char**, char**);
    + **      the 2nd parameter of sqlite3_exec() while sqlite3_exec() is running.
    + ** </ul>
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_exec(
    ++SQLITE_API int sqlite3_exec(
    +   sqlite3*,                                  /* An open database */
    +   const char *sql,                           /* SQL to be evaluated */
    +   int (*callback)(void*,int,char**,char**),  /* Callback function */
    +@@ -403,7 +421,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_exec(
    + */
    + #define SQLITE_OK           0   /* Successful result */
    + /* beginning-of-error-codes */
    +-#define SQLITE_ERROR        1   /* SQL error or missing database */
    ++#define SQLITE_ERROR        1   /* Generic error */
    + #define SQLITE_INTERNAL     2   /* Internal logic error in SQLite */
    + #define SQLITE_PERM         3   /* Access permission denied */
    + #define SQLITE_ABORT        4   /* Callback routine requested an abort */
    +@@ -418,7 +436,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_exec(
    + #define SQLITE_FULL        13   /* Insertion failed because database is full */
    + #define SQLITE_CANTOPEN    14   /* Unable to open the database file */
    + #define SQLITE_PROTOCOL    15   /* Database lock protocol error */
    +-#define SQLITE_EMPTY       16   /* Database is empty */
    ++#define SQLITE_EMPTY       16   /* Internal use only */
    + #define SQLITE_SCHEMA      17   /* The database schema changed */
    + #define SQLITE_TOOBIG      18   /* String or BLOB exceeds size limit */
    + #define SQLITE_CONSTRAINT  19   /* Abort due to constraint violation */
    +@@ -426,7 +444,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_exec(
    + #define SQLITE_MISUSE      21   /* Library used incorrectly */
    + #define SQLITE_NOLFS       22   /* Uses OS features not supported on host */
    + #define SQLITE_AUTH        23   /* Authorization denied */
    +-#define SQLITE_FORMAT      24   /* Auxiliary database format error */
    ++#define SQLITE_FORMAT      24   /* Not used */
    + #define SQLITE_RANGE       25   /* 2nd parameter to sqlite3_bind out of range */
    + #define SQLITE_NOTADB      26   /* File opened that is not a database file */
    + #define SQLITE_NOTICE      27   /* Notifications from sqlite3_log() */
    +@@ -443,7 +461,8 @@ SQLITE_API int SQLITE_STDCALL sqlite3_exec(
    + ** [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
    ++** address this, newer versions of SQLite (version 3.3.8 [dateof:3.3.8]
    ++** and later) include
    + ** support for additional result codes that provide more detailed information
    + ** about errors. These [extended result codes] are enabled or disabled
    + ** on a per database connection basis using the
    +@@ -451,6 +470,8 @@ SQLITE_API int SQLITE_STDCALL sqlite3_exec(
    + ** the most recent error can be obtained using
    + ** [sqlite3_extended_errcode()].
    + */
    ++#define SQLITE_ERROR_MISSING_COLLSEQ   (SQLITE_ERROR | (1<<8))
    ++#define SQLITE_ERROR_RETRY             (SQLITE_ERROR | (2<<8))
    + #define SQLITE_IOERR_READ              (SQLITE_IOERR | (1<<8))
    + #define SQLITE_IOERR_SHORT_READ        (SQLITE_IOERR | (2<<8))
    + #define SQLITE_IOERR_WRITE             (SQLITE_IOERR | (3<<8))
    +@@ -478,6 +499,10 @@ SQLITE_API int SQLITE_STDCALL sqlite3_exec(
    + #define SQLITE_IOERR_GETTEMPPATH       (SQLITE_IOERR | (25<<8))
    + #define SQLITE_IOERR_CONVPATH          (SQLITE_IOERR | (26<<8))
    + #define SQLITE_IOERR_VNODE             (SQLITE_IOERR | (27<<8))
    ++#define SQLITE_IOERR_AUTH              (SQLITE_IOERR | (28<<8))
    ++#define SQLITE_IOERR_BEGIN_ATOMIC      (SQLITE_IOERR | (29<<8))
    ++#define SQLITE_IOERR_COMMIT_ATOMIC     (SQLITE_IOERR | (30<<8))
    ++#define SQLITE_IOERR_ROLLBACK_ATOMIC   (SQLITE_IOERR | (31<<8))
    + #define SQLITE_LOCKED_SHAREDCACHE      (SQLITE_LOCKED |  (1<<8))
    + #define SQLITE_BUSY_RECOVERY           (SQLITE_BUSY   |  (1<<8))
    + #define SQLITE_BUSY_SNAPSHOT           (SQLITE_BUSY   |  (2<<8))
    +@@ -490,6 +515,8 @@ SQLITE_API int SQLITE_STDCALL sqlite3_exec(
    + #define SQLITE_READONLY_CANTLOCK       (SQLITE_READONLY | (2<<8))
    + #define SQLITE_READONLY_ROLLBACK       (SQLITE_READONLY | (3<<8))
    + #define SQLITE_READONLY_DBMOVED        (SQLITE_READONLY | (4<<8))
    ++#define SQLITE_READONLY_CANTINIT       (SQLITE_READONLY | (5<<8))
    ++#define SQLITE_READONLY_DIRECTORY      (SQLITE_READONLY | (6<<8))
    + #define SQLITE_ABORT_ROLLBACK          (SQLITE_ABORT | (2<<8))
    + #define SQLITE_CONSTRAINT_CHECK        (SQLITE_CONSTRAINT | (1<<8))
    + #define SQLITE_CONSTRAINT_COMMITHOOK   (SQLITE_CONSTRAINT | (2<<8))
    +@@ -505,6 +532,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_exec(
    + #define SQLITE_NOTICE_RECOVER_ROLLBACK (SQLITE_NOTICE | (2<<8))
    + #define SQLITE_WARNING_AUTOINDEX       (SQLITE_WARNING | (1<<8))
    + #define SQLITE_AUTH_USER               (SQLITE_AUTH | (1<<8))
    ++#define SQLITE_OK_LOAD_PERMANENTLY     (SQLITE_OK | (1<<8))
    + 
    + /*
    + ** CAPI3REF: Flags For File Open Operations
    +@@ -559,10 +587,15 @@ SQLITE_API int SQLITE_STDCALL 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.  The
    ++** flag indicates 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.
    ++**
    ++** The SQLITE_IOCAP_BATCH_ATOMIC property means that the underlying
    ++** filesystem supports doing multiple write operations atomically when those
    ++** write operations are bracketed by [SQLITE_FCNTL_BEGIN_ATOMIC_WRITE] and
    ++** [SQLITE_FCNTL_COMMIT_ATOMIC_WRITE].
    + */
    + #define SQLITE_IOCAP_ATOMIC                 0x00000001
    + #define SQLITE_IOCAP_ATOMIC512              0x00000002
    +@@ -578,6 +611,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_exec(
    + #define SQLITE_IOCAP_UNDELETABLE_WHEN_OPEN  0x00000800
    + #define SQLITE_IOCAP_POWERSAFE_OVERWRITE    0x00001000
    + #define SQLITE_IOCAP_IMMUTABLE              0x00002000
    ++#define SQLITE_IOCAP_BATCH_ATOMIC           0x00004000
    + 
    + /*
    + ** CAPI3REF: File Locking Levels
    +@@ -709,6 +743,10 @@ struct sqlite3_file {
    + ** <li> [SQLITE_IOCAP_ATOMIC64K]
    + ** <li> [SQLITE_IOCAP_SAFE_APPEND]
    + ** <li> [SQLITE_IOCAP_SEQUENTIAL]
    ++** <li> [SQLITE_IOCAP_UNDELETABLE_WHEN_OPEN]
    ++** <li> [SQLITE_IOCAP_POWERSAFE_OVERWRITE]
    ++** <li> [SQLITE_IOCAP_IMMUTABLE]
    ++** <li> [SQLITE_IOCAP_BATCH_ATOMIC]
    + ** </ul>
    + **
    + ** The SQLITE_IOCAP_ATOMIC property means that all writes of
    +@@ -793,8 +831,13 @@ struct sqlite3_io_methods {
    + ** <li>[[SQLITE_FCNTL_FILE_POINTER]]
    + ** The [SQLITE_FCNTL_FILE_POINTER] opcode is used to obtain a pointer
    + ** to the [sqlite3_file] object associated with a particular database
    +-** connection.  See the [sqlite3_file_control()] documentation for
    +-** additional information.
    ++** connection.  See also [SQLITE_FCNTL_JOURNAL_POINTER].
    ++**
    ++** <li>[[SQLITE_FCNTL_JOURNAL_POINTER]]
    ++** The [SQLITE_FCNTL_JOURNAL_POINTER] opcode is used to obtain a pointer
    ++** to the [sqlite3_file] object associated with the journal file (either
    ++** the [rollback journal] or the [write-ahead log]) for a particular database
    ++** connection.  See also [SQLITE_FCNTL_FILE_POINTER].
    + **
    + ** <li>[[SQLITE_FCNTL_SYNC_OMITTED]]
    + ** No longer in use.
    +@@ -832,7 +875,7 @@ struct sqlite3_io_methods {
    + ** opcode allows these two values (10 retries and 25 milliseconds of delay)
    + ** to be adjusted.  The values are changed for all database connections
    + ** within the same process.  The argument is a pointer to an array of two
    +-** integers where the first integer i the new retry count and the second
    ++** integers where the first integer is the new retry count and the second
    + ** integer is the delay.  If either integer is negative, then the setting
    + ** is not changed but instead the prior value of that setting is written
    + ** into the array entry, allowing the current retry settings to be
    +@@ -881,6 +924,15 @@ struct sqlite3_io_methods {
    + ** pointer in case this file-control is not implemented.  This file-control
    + ** is intended for diagnostic use only.
    + **
    ++** <li>[[SQLITE_FCNTL_VFS_POINTER]]
    ++** ^The [SQLITE_FCNTL_VFS_POINTER] opcode finds a pointer to the top-level
    ++** [VFSes] currently in use.  ^(The argument X in
    ++** sqlite3_file_control(db,SQLITE_FCNTL_VFS_POINTER,X) must be
    ++** of type "[sqlite3_vfs] **".  This opcodes will set *X
    ++** to a pointer to the top-level VFS.)^
    ++** ^When there are multiple VFS shims in the stack, this opcode finds the
    ++** upper-most shim only.
    ++**
    + ** <li>[[SQLITE_FCNTL_PRAGMA]]
    + ** ^Whenever a [PRAGMA] statement is parsed, an [SQLITE_FCNTL_PRAGMA] 
    + ** file control is sent to the open [sqlite3_file] object corresponding
    +@@ -951,6 +1003,12 @@ struct sqlite3_io_methods {
    + ** on whether or not the file has been renamed, moved, or deleted since it
    + ** was first opened.
    + **
    ++** <li>[[SQLITE_FCNTL_WIN32_GET_HANDLE]]
    ++** The [SQLITE_FCNTL_WIN32_GET_HANDLE] opcode can be used to obtain the
    ++** underlying native file handle associated with a file handle.  This file
    ++** control interprets its argument as a pointer to a native file handle and
    ++** writes the resulting value there.
    ++**
    + ** <li>[[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
    +@@ -972,6 +1030,40 @@ struct sqlite3_io_methods {
    + ** The [SQLITE_FCNTL_RBU] opcode is implemented by the special VFS used by
    + ** the RBU extension only.  All other VFS should return SQLITE_NOTFOUND for
    + ** this opcode.  
    ++**
    ++** <li>[[SQLITE_FCNTL_BEGIN_ATOMIC_WRITE]]
    ++** If the [SQLITE_FCNTL_BEGIN_ATOMIC_WRITE] opcode returns SQLITE_OK, then
    ++** the file descriptor is placed in "batch write mode", which
    ++** means all subsequent write operations will be deferred and done
    ++** atomically at the next [SQLITE_FCNTL_COMMIT_ATOMIC_WRITE].  Systems
    ++** that do not support batch atomic writes will return SQLITE_NOTFOUND.
    ++** ^Following a successful SQLITE_FCNTL_BEGIN_ATOMIC_WRITE and prior to
    ++** the closing [SQLITE_FCNTL_COMMIT_ATOMIC_WRITE] or
    ++** [SQLITE_FCNTL_ROLLBACK_ATOMIC_WRITE], SQLite will make
    ++** no VFS interface calls on the same [sqlite3_file] file descriptor
    ++** except for calls to the xWrite method and the xFileControl method
    ++** with [SQLITE_FCNTL_SIZE_HINT].
    ++**
    ++** <li>[[SQLITE_FCNTL_COMMIT_ATOMIC_WRITE]]
    ++** The [SQLITE_FCNTL_COMMIT_ATOMIC_WRITE] opcode causes all write
    ++** operations since the previous successful call to 
    ++** [SQLITE_FCNTL_BEGIN_ATOMIC_WRITE] to be performed atomically.
    ++** This file control returns [SQLITE_OK] if and only if the writes were
    ++** all performed successfully and have been committed to persistent storage.
    ++** ^Regardless of whether or not it is successful, this file control takes
    ++** the file descriptor out of batch write mode so that all subsequent
    ++** write operations are independent.
    ++** ^SQLite will never invoke SQLITE_FCNTL_COMMIT_ATOMIC_WRITE without
    ++** a prior successful call to [SQLITE_FCNTL_BEGIN_ATOMIC_WRITE].
    ++**
    ++** <li>[[SQLITE_FCNTL_ROLLBACK_ATOMIC_WRITE]]
    ++** The [SQLITE_FCNTL_ROLLBACK_ATOMIC_WRITE] opcode causes all write
    ++** operations since the previous successful call to 
    ++** [SQLITE_FCNTL_BEGIN_ATOMIC_WRITE] to be rolled back.
    ++** ^This file control takes the file descriptor out of batch write mode
    ++** so that all subsequent write operations are independent.
    ++** ^SQLite will never invoke SQLITE_FCNTL_ROLLBACK_ATOMIC_WRITE without
    ++** a prior successful call to [SQLITE_FCNTL_BEGIN_ATOMIC_WRITE].
    + ** </ul>
    + */
    + #define SQLITE_FCNTL_LOCKSTATE               1
    +@@ -999,6 +1091,13 @@ struct sqlite3_io_methods {
    + #define SQLITE_FCNTL_WAL_BLOCK              24
    + #define SQLITE_FCNTL_ZIPVFS                 25
    + #define SQLITE_FCNTL_RBU                    26
    ++#define SQLITE_FCNTL_VFS_POINTER            27
    ++#define SQLITE_FCNTL_JOURNAL_POINTER        28
    ++#define SQLITE_FCNTL_WIN32_GET_HANDLE       29
    ++#define SQLITE_FCNTL_PDB                    30
    ++#define SQLITE_FCNTL_BEGIN_ATOMIC_WRITE     31
    ++#define SQLITE_FCNTL_COMMIT_ATOMIC_WRITE    32
    ++#define SQLITE_FCNTL_ROLLBACK_ATOMIC_WRITE  33
    + 
    + /* deprecated names */
    + #define SQLITE_GET_LOCKPROXYFILE      SQLITE_FCNTL_GET_LOCKPROXYFILE
    +@@ -1018,6 +1117,16 @@ struct sqlite3_io_methods {
    + */
    + typedef struct sqlite3_mutex sqlite3_mutex;
    + 
    ++/*
    ++** CAPI3REF: Loadable Extension Thunk
    ++**
    ++** A pointer to the opaque sqlite3_api_routines structure is passed as
    ++** the third parameter to entry points of [loadable extensions].  This
    ++** structure must be typedefed in order to work around compiler warnings
    ++** on some platforms.
    ++*/
    ++typedef struct sqlite3_api_routines sqlite3_api_routines;
    ++
    + /*
    + ** CAPI3REF: OS Interface Object
    + **
    +@@ -1026,12 +1135,18 @@ typedef struct sqlite3_mutex sqlite3_mutex;
    + ** in the name of the object stands for "virtual file system".  See
    + ** the [VFS | VFS documentation] for further information.
    + **
    +-** The value of the iVersion field is initially 1 but may be larger in
    +-** future versions of SQLite.  Additional fields may be appended to this
    +-** object when the iVersion value is increased.  Note that the structure
    +-** of the sqlite3_vfs object changes in the transaction between
    +-** SQLite version 3.5.9 and 3.6.0 and yet the iVersion field was not
    +-** modified.
    ++** The VFS interface is sometimes extended by adding new methods onto
    ++** the end.  Each time such an extension occurs, the iVersion field
    ++** is incremented.  The iVersion value started out as 1 in
    ++** SQLite [version 3.5.0] on [dateof:3.5.0], then increased to 2
    ++** with SQLite [version 3.7.0] on [dateof:3.7.0], and then increased
    ++** to 3 with SQLite [version 3.7.6] on [dateof:3.7.6].  Additional fields
    ++** may be appended to the sqlite3_vfs object and the iVersion value
    ++** may increase again in future versions of SQLite.
    ++** Note that the structure
    ++** of the sqlite3_vfs object changes in the transition from
    ++** SQLite [version 3.5.9] to [version 3.6.0] on [dateof:3.6.0]
    ++** and yet the iVersion field was not modified.
    + **
    + ** The szOsFile field is the size of the subclassed [sqlite3_file]
    + ** structure used by this VFS.  mxPathname is the maximum length of
    +@@ -1211,7 +1326,7 @@ struct sqlite3_vfs {
    +   const char *(*xNextSystemCall)(sqlite3_vfs*, const char *zName);
    +   /*
    +   ** The methods above are in versions 1 through 3 of the sqlite_vfs object.
    +-  ** New fields may be appended in figure versions.  The iVersion
    ++  ** New fields may be appended in future versions.  The iVersion
    +   ** value will increment whenever this happens. 
    +   */
    + };
    +@@ -1353,10 +1468,10 @@ struct sqlite3_vfs {
    + ** must return [SQLITE_OK] on success and some other [error code] upon
    + ** failure.
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_initialize(void);
    +-SQLITE_API int SQLITE_STDCALL sqlite3_shutdown(void);
    +-SQLITE_API int SQLITE_STDCALL sqlite3_os_init(void);
    +-SQLITE_API int SQLITE_STDCALL sqlite3_os_end(void);
    ++SQLITE_API int sqlite3_initialize(void);
    ++SQLITE_API int sqlite3_shutdown(void);
    ++SQLITE_API int sqlite3_os_init(void);
    ++SQLITE_API int sqlite3_os_end(void);
    + 
    + /*
    + ** CAPI3REF: Configuring The SQLite Library
    +@@ -1389,7 +1504,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_os_end(void);
    + ** ^If the option is unknown or SQLite is unable to set the option
    + ** then this routine returns a non-zero [error code].
    + */
    +-SQLITE_API int SQLITE_CDECL sqlite3_config(int, ...);
    ++SQLITE_API int sqlite3_config(int, ...);
    + 
    + /*
    + ** CAPI3REF: Configure database connections
    +@@ -1408,7 +1523,7 @@ SQLITE_API int SQLITE_CDECL sqlite3_config(int, ...);
    + ** ^Calls to sqlite3_db_config() return SQLITE_OK if and only if
    + ** the call is considered successful.
    + */
    +-SQLITE_API int SQLITE_CDECL sqlite3_db_config(sqlite3*, int op, ...);
    ++SQLITE_API int sqlite3_db_config(sqlite3*, int op, ...);
    + 
    + /*
    + ** CAPI3REF: Memory Allocation Routines
    +@@ -1559,6 +1674,16 @@ struct sqlite3_mem_methods {
    + ** routines with a wrapper that simulations memory allocation failure or
    + ** tracks memory usage, for example. </dd>
    + **
    ++** [[SQLITE_CONFIG_SMALL_MALLOC]] <dt>SQLITE_CONFIG_SMALL_MALLOC</dt>
    ++** <dd> ^The SQLITE_CONFIG_SMALL_MALLOC option takes single argument of
    ++** type int, interpreted as a boolean, which if true provides a hint to
    ++** SQLite that it should avoid large memory allocations if possible.
    ++** SQLite will run faster if it is free to make large memory allocations,
    ++** but some application might prefer to run slower in exchange for
    ++** guarantees about memory fragmentation that are possible if large
    ++** allocations are avoided.  This hint is normally off.
    ++** </dd>
    ++**
    + ** [[SQLITE_CONFIG_MEMSTATUS]] <dt>SQLITE_CONFIG_MEMSTATUS</dt>
    + ** <dd> ^The SQLITE_CONFIG_MEMSTATUS option takes single argument of type int,
    + ** interpreted as a boolean, which enables or disables the collection of
    +@@ -1576,57 +1701,43 @@ struct sqlite3_mem_methods {
    + ** </dd>
    + **
    + ** [[SQLITE_CONFIG_SCRATCH]] <dt>SQLITE_CONFIG_SCRATCH</dt>
    +-** <dd> ^The SQLITE_CONFIG_SCRATCH option specifies a static memory buffer
    +-** that SQLite can use for scratch memory.  ^(There are three arguments
    +-** to SQLITE_CONFIG_SCRATCH:  A pointer an 8-byte
    +-** aligned memory buffer from which the scratch allocations will be
    +-** drawn, the size of each scratch allocation (sz),
    +-** and the maximum number of scratch allocations (N).)^
    +-** The first argument must be a pointer to an 8-byte aligned buffer
    +-** of at least sz*N bytes of memory.
    +-** ^SQLite will not use more than one scratch buffers per thread.
    +-** ^SQLite will never request a scratch buffer that is more than 6
    +-** times the database page size.
    +-** ^If SQLite needs needs additional
    +-** scratch memory beyond what is provided by this configuration option, then 
    +-** [sqlite3_malloc()] will be used to obtain the memory needed.<p>
    +-** ^When the application provides any amount of scratch memory using
    +-** SQLITE_CONFIG_SCRATCH, SQLite avoids unnecessary large
    +-** [sqlite3_malloc|heap allocations].
    +-** This can help [Robson proof|prevent memory allocation failures] due to heap
    +-** fragmentation in low-memory embedded systems.
    ++** <dd> The SQLITE_CONFIG_SCRATCH option is no longer used.
    + ** </dd>
    + **
    + ** [[SQLITE_CONFIG_PAGECACHE]] <dt>SQLITE_CONFIG_PAGECACHE</dt>
    +-** <dd> ^The SQLITE_CONFIG_PAGECACHE option specifies a static memory buffer
    ++** <dd> ^The SQLITE_CONFIG_PAGECACHE option specifies a memory pool
    + ** that SQLite can use for the database page cache with the default page
    + ** cache implementation.  
    +-** This configuration should not be used if an application-define page
    +-** cache implementation is loaded using the [SQLITE_CONFIG_PCACHE2]
    +-** configuration option.
    ++** This configuration option is a no-op if an application-define page
    ++** cache implementation is loaded using the [SQLITE_CONFIG_PCACHE2].
    + ** ^There are three arguments to SQLITE_CONFIG_PAGECACHE: A pointer to
    +-** 8-byte aligned
    +-** memory, the size of each page buffer (sz), and the number of pages (N).
    ++** 8-byte aligned memory (pMem), the size of each page cache line (sz),
    ++** and the number of cache lines (N).
    + ** The sz argument should be the size of the largest database page
    + ** (a power of two between 512 and 65536) plus some extra bytes for each
    + ** page header.  ^The number of extra bytes needed by the page header
    +-** can be determined using the [SQLITE_CONFIG_PCACHE_HDRSZ] option 
    +-** to [sqlite3_config()].
    ++** can be determined using [SQLITE_CONFIG_PCACHE_HDRSZ].
    + ** ^It is harmless, apart from the wasted memory,
    +-** for the sz parameter to be larger than necessary.  The first
    +-** argument should pointer to an 8-byte aligned block of memory that
    +-** is at least sz*N bytes of memory, otherwise subsequent behavior is
    +-** undefined.
    +-** ^SQLite will use the memory provided by the first argument to satisfy its
    +-** memory needs for the first N pages that it adds to cache.  ^If additional
    +-** page cache memory is needed beyond what is provided by this option, then
    +-** SQLite goes to [sqlite3_malloc()] for the additional storage space.</dd>
    ++** for the sz parameter to be larger than necessary.  The pMem
    ++** argument must be either a NULL pointer or a pointer to an 8-byte
    ++** aligned block of memory of at least sz*N bytes, otherwise
    ++** subsequent behavior is undefined.
    ++** ^When pMem is not NULL, SQLite will strive to use the memory provided
    ++** to satisfy page cache needs, falling back to [sqlite3_malloc()] if
    ++** a page cache line is larger than sz bytes or if all of the pMem buffer
    ++** is exhausted.
    ++** ^If pMem is NULL and N is non-zero, then each database connection
    ++** does an initial bulk allocation for page cache memory
    ++** from [sqlite3_malloc()] sufficient for N cache lines if N is positive or
    ++** of -1024*N bytes if N is negative, . ^If additional
    ++** page cache memory is needed beyond what is provided by the initial
    ++** allocation, then SQLite goes to [sqlite3_malloc()] separately for each
    ++** additional cache line. </dd>
    + **
    + ** [[SQLITE_CONFIG_HEAP]] <dt>SQLITE_CONFIG_HEAP</dt>
    + ** <dd> ^The SQLITE_CONFIG_HEAP option specifies a static memory buffer 
    + ** that SQLite will use for all of its dynamic memory allocation needs
    +-** beyond those provided for by [SQLITE_CONFIG_SCRATCH] and
    +-** [SQLITE_CONFIG_PAGECACHE].
    ++** beyond those provided for by [SQLITE_CONFIG_PAGECACHE].
    + ** ^The SQLITE_CONFIG_HEAP option is only available if SQLite is compiled
    + ** with either [SQLITE_ENABLE_MEMSYS3] or [SQLITE_ENABLE_MEMSYS5] and returns
    + ** [SQLITE_ERROR] if invoked otherwise.
    +@@ -1798,6 +1909,20 @@ struct sqlite3_mem_methods {
    + ** is enabled (using the [PRAGMA threads] command) and the amount of content
    + ** to be sorted exceeds the page size times the minimum of the
    + ** [PRAGMA cache_size] setting and this value.
    ++**
    ++** [[SQLITE_CONFIG_STMTJRNL_SPILL]]
    ++** <dt>SQLITE_CONFIG_STMTJRNL_SPILL
    ++** <dd>^The SQLITE_CONFIG_STMTJRNL_SPILL option takes a single parameter which
    ++** becomes the [statement journal] spill-to-disk threshold.  
    ++** [Statement journals] are held in memory until their size (in bytes)
    ++** exceeds this threshold, at which point they are written to disk.
    ++** Or if the threshold is -1, statement journals are always held
    ++** exclusively in memory.
    ++** Since many statement journals never become large, setting the spill
    ++** threshold to a value such as 64KiB can greatly reduce the amount of
    ++** I/O required to support statement rollback.
    ++** The default value for this setting is controlled by the
    ++** [SQLITE_STMTJRNL_SPILL] compile-time option.
    + ** </dl>
    + */
    + #define SQLITE_CONFIG_SINGLETHREAD  1  /* nil */
    +@@ -1805,7 +1930,7 @@ struct sqlite3_mem_methods {
    + #define SQLITE_CONFIG_SERIALIZED    3  /* nil */
    + #define SQLITE_CONFIG_MALLOC        4  /* sqlite3_mem_methods* */
    + #define SQLITE_CONFIG_GETMALLOC     5  /* sqlite3_mem_methods* */
    +-#define SQLITE_CONFIG_SCRATCH       6  /* void*, int sz, int N */
    ++#define SQLITE_CONFIG_SCRATCH       6  /* No longer used */
    + #define SQLITE_CONFIG_PAGECACHE     7  /* void*, int sz, int N */
    + #define SQLITE_CONFIG_HEAP          8  /* void*, int nByte, int min */
    + #define SQLITE_CONFIG_MEMSTATUS     9  /* boolean */
    +@@ -1825,6 +1950,8 @@ struct sqlite3_mem_methods {
    + #define SQLITE_CONFIG_WIN32_HEAPSIZE      23  /* int nByte */
    + #define SQLITE_CONFIG_PCACHE_HDRSZ        24  /* int *psz */
    + #define SQLITE_CONFIG_PMASZ               25  /* unsigned int szPma */
    ++#define SQLITE_CONFIG_STMTJRNL_SPILL      26  /* int nByte */
    ++#define SQLITE_CONFIG_SMALL_MALLOC        27  /* boolean */
    + 
    + /*
    + ** CAPI3REF: Database Connection Configuration Options
    +@@ -1882,12 +2009,88 @@ struct sqlite3_mem_methods {
    + ** following this call.  The second parameter may be a NULL pointer, in
    + ** which case the trigger setting is not reported back. </dd>
    + **
    ++** <dt>SQLITE_DBCONFIG_ENABLE_FTS3_TOKENIZER</dt>
    ++** <dd> ^This option is used to enable or disable the two-argument
    ++** version of the [fts3_tokenizer()] function which is part of the
    ++** [FTS3] full-text search engine extension.
    ++** There should be two additional arguments.
    ++** The first argument is an integer which is 0 to disable fts3_tokenizer() or
    ++** positive to enable fts3_tokenizer() or negative to leave the setting
    ++** unchanged.
    ++** The second parameter is a pointer to an integer into which
    ++** is written 0 or 1 to indicate whether fts3_tokenizer is disabled or enabled
    ++** following this call.  The second parameter may be a NULL pointer, in
    ++** which case the new setting is not reported back. </dd>
    ++**
    ++** <dt>SQLITE_DBCONFIG_ENABLE_LOAD_EXTENSION</dt>
    ++** <dd> ^This option is used to enable or disable the [sqlite3_load_extension()]
    ++** interface independently of the [load_extension()] SQL function.
    ++** The [sqlite3_enable_load_extension()] API enables or disables both the
    ++** C-API [sqlite3_load_extension()] and the SQL function [load_extension()].
    ++** There should be two additional arguments.
    ++** When the first argument to this interface is 1, then only the C-API is
    ++** enabled and the SQL function remains disabled.  If the first argument to
    ++** this interface is 0, then both the C-API and the SQL function are disabled.
    ++** If the first argument is -1, then no changes are made to state of either the
    ++** C-API or the SQL function.
    ++** The second parameter is a pointer to an integer into which
    ++** is written 0 or 1 to indicate whether [sqlite3_load_extension()] interface
    ++** is disabled or enabled following this call.  The second parameter may
    ++** be a NULL pointer, in which case the new setting is not reported back.
    ++** </dd>
    ++**
    ++** <dt>SQLITE_DBCONFIG_MAINDBNAME</dt>
    ++** <dd> ^This option is used to change the name of the "main" database
    ++** schema.  ^The sole argument is a pointer to a constant UTF8 string
    ++** which will become the new schema name in place of "main".  ^SQLite
    ++** does not make a copy of the new main schema name string, so the application
    ++** must ensure that the argument passed into this DBCONFIG option is unchanged
    ++** until after the database connection closes.
    ++** </dd>
    ++**
    ++** <dt>SQLITE_DBCONFIG_NO_CKPT_ON_CLOSE</dt>
    ++** <dd> Usually, when a database in wal mode is closed or detached from a 
    ++** database handle, SQLite checks if this will mean that there are now no 
    ++** connections at all to the database. If so, it performs a checkpoint 
    ++** operation before closing the connection. This option may be used to
    ++** override this behaviour. The first parameter passed to this operation
    ++** is an integer - non-zero to disable checkpoints-on-close, or zero (the
    ++** default) to enable them. The second parameter is a pointer to an integer
    ++** into which is written 0 or 1 to indicate whether checkpoints-on-close
    ++** have been disabled - 0 if they are not disabled, 1 if they are.
    ++** </dd>
    ++** <dt>SQLITE_DBCONFIG_ENABLE_QPSG</dt>
    ++** <dd>^(The SQLITE_DBCONFIG_ENABLE_QPSG option activates or deactivates
    ++** the [query planner stability guarantee] (QPSG).  When the QPSG is active,
    ++** a single SQL query statement will always use the same algorithm regardless
    ++** of values of [bound parameters].)^ The QPSG disables some query optimizations
    ++** that look at the values of bound parameters, which can make some queries
    ++** slower.  But the QPSG has the advantage of more predictable behavior.  With
    ++** the QPSG active, SQLite will always use the same query plan in the field as
    ++** was used during testing in the lab.
    ++** </dd>
    ++** <dt>SQLITE_DBCONFIG_TRIGGER_EQP</dt>
    ++** <dd> By default, the output of EXPLAIN QUERY PLAN commands does not 
    ++** include output for any operations performed by trigger programs. This
    ++** option is used to set or clear (the default) a flag that governs this
    ++** behavior. The first parameter passed to this operation is an integer -
    ++** non-zero to enable output for trigger programs, or zero to disable it.
    ++** The second parameter is a pointer to an integer into which is written 
    ++** 0 or 1 to indicate whether output-for-triggers has been disabled - 0 if 
    ++** it is not disabled, 1 if it is.  
    ++** </dd>
    + ** </dl>
    + */
    +-#define SQLITE_DBCONFIG_LOOKASIDE       1001  /* void* int int */
    +-#define SQLITE_DBCONFIG_ENABLE_FKEY     1002  /* int int* */
    +-#define SQLITE_DBCONFIG_ENABLE_TRIGGER  1003  /* int int* */
    +-
    ++#define SQLITE_DBCONFIG_MAINDBNAME            1000 /* const char* */
    ++#define SQLITE_DBCONFIG_LOOKASIDE             1001 /* void* int int */
    ++#define SQLITE_DBCONFIG_ENABLE_FKEY           1002 /* int int* */
    ++#define SQLITE_DBCONFIG_ENABLE_TRIGGER        1003 /* int int* */
    ++#define SQLITE_DBCONFIG_ENABLE_FTS3_TOKENIZER 1004 /* int int* */
    ++#define SQLITE_DBCONFIG_ENABLE_LOAD_EXTENSION 1005 /* int int* */
    ++#define SQLITE_DBCONFIG_NO_CKPT_ON_CLOSE      1006 /* int int* */
    ++#define SQLITE_DBCONFIG_ENABLE_QPSG           1007 /* int int* */
    ++#define SQLITE_DBCONFIG_TRIGGER_EQP           1008 /* int int* */
    ++#define SQLITE_DBCONFIG_MAX                   1008 /* Largest DBCONFIG */
    + 
    + /*
    + ** CAPI3REF: Enable Or Disable Extended Result Codes
    +@@ -1897,7 +2100,7 @@ struct sqlite3_mem_methods {
    + ** [extended result codes] feature of SQLite. ^The extended result
    + ** codes are disabled by default for historical compatibility.
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_extended_result_codes(sqlite3*, int onoff);
    ++SQLITE_API int sqlite3_extended_result_codes(sqlite3*, int onoff);
    + 
    + /*
    + ** CAPI3REF: Last Insert Rowid
    +@@ -1911,20 +2114,30 @@ SQLITE_API int SQLITE_STDCALL sqlite3_extended_result_codes(sqlite3*, int onoff)
    + ** the table has a column of type [INTEGER PRIMARY KEY] then that column
    + ** is another alias for the rowid.
    + **
    +-** ^The sqlite3_last_insert_rowid(D) interface returns the [rowid] of the 
    +-** most recent successful [INSERT] into a rowid table or [virtual table]
    +-** on database connection D.
    +-** ^Inserts into [WITHOUT ROWID] tables are not recorded.
    +-** ^If no successful [INSERT]s into rowid tables
    +-** have ever occurred on the database connection D, 
    +-** then sqlite3_last_insert_rowid(D) returns zero.
    +-**
    +-** ^(If an [INSERT] occurs within a trigger or within a [virtual table]
    +-** method, then this routine will return the [rowid] of the inserted
    +-** row as long as the trigger or virtual table method is running.
    +-** But once the trigger or virtual table method ends, the value returned 
    +-** by this routine reverts to what it was before the trigger or virtual
    +-** table method began.)^
    ++** ^The sqlite3_last_insert_rowid(D) interface usually returns the [rowid] of
    ++** the most recent successful [INSERT] into a rowid table or [virtual table]
    ++** on database connection D. ^Inserts into [WITHOUT ROWID] tables are not
    ++** recorded. ^If no successful [INSERT]s into rowid tables have ever occurred 
    ++** on the database connection D, then sqlite3_last_insert_rowid(D) returns 
    ++** zero.
    ++**
    ++** As well as being set automatically as rows are inserted into database
    ++** tables, the value returned by this function may be set explicitly by
    ++** [sqlite3_set_last_insert_rowid()]
    ++**
    ++** Some virtual table implementations may INSERT rows into rowid tables as
    ++** part of committing a transaction (e.g. to flush data accumulated in memory
    ++** to disk). In this case subsequent calls to this function return the rowid
    ++** associated with these internal INSERT operations, which leads to 
    ++** unintuitive results. Virtual table implementations that do write to rowid
    ++** tables in this way can avoid this problem by restoring the original 
    ++** rowid value using [sqlite3_set_last_insert_rowid()] before returning 
    ++** control to the user.
    ++**
    ++** ^(If an [INSERT] occurs within a trigger then this routine will 
    ++** return the [rowid] of the inserted row as long as the trigger is 
    ++** running. Once the trigger program ends, the value returned 
    ++** by this routine reverts to what it was before the trigger was fired.)^
    + **
    + ** ^An [INSERT] that fails due to a constraint violation is not a
    + ** successful [INSERT] and does not change the value returned by this
    +@@ -1949,7 +2162,17 @@ SQLITE_API int SQLITE_STDCALL sqlite3_extended_result_codes(sqlite3*, int onoff)
    + ** unpredictable and might not equal either the old or the new
    + ** last insert [rowid].
    + */
    +-SQLITE_API sqlite3_int64 SQLITE_STDCALL sqlite3_last_insert_rowid(sqlite3*);
    ++SQLITE_API sqlite3_int64 sqlite3_last_insert_rowid(sqlite3*);
    ++
    ++/*
    ++** CAPI3REF: Set the Last Insert Rowid value.
    ++** METHOD: sqlite3
    ++**
    ++** The sqlite3_set_last_insert_rowid(D, R) method allows the application to
    ++** set the value returned by calling sqlite3_last_insert_rowid(D) to R 
    ++** without inserting a row into the database.
    ++*/
    ++SQLITE_API void sqlite3_set_last_insert_rowid(sqlite3*,sqlite3_int64);
    + 
    + /*
    + ** CAPI3REF: Count The Number Of Rows Modified
    +@@ -2002,7 +2225,7 @@ SQLITE_API sqlite3_int64 SQLITE_STDCALL sqlite3_last_insert_rowid(sqlite3*);
    + ** while [sqlite3_changes()] is running then the value returned
    + ** is unpredictable and not meaningful.
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_changes(sqlite3*);
    ++SQLITE_API int sqlite3_changes(sqlite3*);
    + 
    + /*
    + ** CAPI3REF: Total Number Of Rows Modified
    +@@ -2026,7 +2249,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_changes(sqlite3*);
    + ** while [sqlite3_total_changes()] is running then the value
    + ** returned is unpredictable and not meaningful.
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_total_changes(sqlite3*);
    ++SQLITE_API int sqlite3_total_changes(sqlite3*);
    + 
    + /*
    + ** CAPI3REF: Interrupt A Long-Running Query
    +@@ -2062,11 +2285,8 @@ SQLITE_API int SQLITE_STDCALL sqlite3_total_changes(sqlite3*);
    + ** ^A call to sqlite3_interrupt(D) that occurs when there are no running
    + ** SQL statements is a no-op and has no effect on SQL statements
    + ** that are started after the sqlite3_interrupt() call returns.
    +-**
    +-** If the database connection closes while [sqlite3_interrupt()]
    +-** is running then bad things will likely happen.
    + */
    +-SQLITE_API void SQLITE_STDCALL sqlite3_interrupt(sqlite3*);
    ++SQLITE_API void sqlite3_interrupt(sqlite3*);
    + 
    + /*
    + ** CAPI3REF: Determine If An SQL Statement Is Complete
    +@@ -2101,8 +2321,8 @@ SQLITE_API void SQLITE_STDCALL sqlite3_interrupt(sqlite3*);
    + ** The input to [sqlite3_complete16()] must be a zero-terminated
    + ** UTF-16 string in native byte order.
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_complete(const char *sql);
    +-SQLITE_API int SQLITE_STDCALL sqlite3_complete16(const void *sql);
    ++SQLITE_API int sqlite3_complete(const char *sql);
    ++SQLITE_API int sqlite3_complete16(const void *sql);
    + 
    + /*
    + ** CAPI3REF: Register A Callback To Handle SQLITE_BUSY Errors
    +@@ -2163,7 +2383,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_complete16(const void *sql);
    + ** A busy handler must not close the database connection
    + ** or [prepared statement] that invoked the busy handler.
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_busy_handler(sqlite3*, int(*)(void*,int), void*);
    ++SQLITE_API int sqlite3_busy_handler(sqlite3*,int(*)(void*,int),void*);
    + 
    + /*
    + ** CAPI3REF: Set A Busy Timeout
    +@@ -2186,7 +2406,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_busy_handler(sqlite3*, int(*)(void*,int),
    + **
    + ** See also:  [PRAGMA busy_timeout]
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_busy_timeout(sqlite3*, int ms);
    ++SQLITE_API int sqlite3_busy_timeout(sqlite3*, int ms);
    + 
    + /*
    + ** CAPI3REF: Convenience Routines For Running Queries
    +@@ -2261,7 +2481,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_busy_timeout(sqlite3*, int ms);
    + ** reflected in subsequent calls to [sqlite3_errcode()] or
    + ** [sqlite3_errmsg()].
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_get_table(
    ++SQLITE_API int sqlite3_get_table(
    +   sqlite3 *db,          /* An open database */
    +   const char *zSql,     /* SQL to be evaluated */
    +   char ***pazResult,    /* Results of the query */
    +@@ -2269,7 +2489,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_get_table(
    +   int *pnColumn,        /* Number of result columns written here */
    +   char **pzErrmsg       /* Error msg written here */
    + );
    +-SQLITE_API void SQLITE_STDCALL sqlite3_free_table(char **result);
    ++SQLITE_API void sqlite3_free_table(char **result);
    + 
    + /*
    + ** CAPI3REF: Formatted String Printing Functions
    +@@ -2375,10 +2595,10 @@ SQLITE_API void SQLITE_STDCALL sqlite3_free_table(char **result);
    + ** addition that after the string has been read and copied into
    + ** the result, [sqlite3_free()] is called on the input string.)^
    + */
    +-SQLITE_API char *SQLITE_CDECL sqlite3_mprintf(const char*,...);
    +-SQLITE_API char *SQLITE_STDCALL sqlite3_vmprintf(const char*, va_list);
    +-SQLITE_API char *SQLITE_CDECL sqlite3_snprintf(int,char*,const char*, ...);
    +-SQLITE_API char *SQLITE_STDCALL sqlite3_vsnprintf(int,char*,const char*, va_list);
    ++SQLITE_API char *sqlite3_mprintf(const char*,...);
    ++SQLITE_API char *sqlite3_vmprintf(const char*, va_list);
    ++SQLITE_API char *sqlite3_snprintf(int,char*,const char*, ...);
    ++SQLITE_API char *sqlite3_vsnprintf(int,char*,const char*, va_list);
    + 
    + /*
    + ** CAPI3REF: Memory Allocation Subsystem
    +@@ -2468,12 +2688,12 @@ SQLITE_API char *SQLITE_STDCALL sqlite3_vsnprintf(int,char*,const char*, va_list
    + ** a block of memory after it has been released using
    + ** [sqlite3_free()] or [sqlite3_realloc()].
    + */
    +-SQLITE_API void *SQLITE_STDCALL sqlite3_malloc(int);
    +-SQLITE_API void *SQLITE_STDCALL sqlite3_malloc64(sqlite3_uint64);
    +-SQLITE_API void *SQLITE_STDCALL sqlite3_realloc(void*, int);
    +-SQLITE_API void *SQLITE_STDCALL sqlite3_realloc64(void*, sqlite3_uint64);
    +-SQLITE_API void SQLITE_STDCALL sqlite3_free(void*);
    +-SQLITE_API sqlite3_uint64 SQLITE_STDCALL sqlite3_msize(void*);
    ++SQLITE_API void *sqlite3_malloc(int);
    ++SQLITE_API void *sqlite3_malloc64(sqlite3_uint64);
    ++SQLITE_API void *sqlite3_realloc(void*, int);
    ++SQLITE_API void *sqlite3_realloc64(void*, sqlite3_uint64);
    ++SQLITE_API void sqlite3_free(void*);
    ++SQLITE_API sqlite3_uint64 sqlite3_msize(void*);
    + 
    + /*
    + ** CAPI3REF: Memory Allocator Statistics
    +@@ -2498,8 +2718,8 @@ SQLITE_API sqlite3_uint64 SQLITE_STDCALL sqlite3_msize(void*);
    + ** by [sqlite3_memory_highwater(1)] is the high-water mark
    + ** prior to the reset.
    + */
    +-SQLITE_API sqlite3_int64 SQLITE_STDCALL sqlite3_memory_used(void);
    +-SQLITE_API sqlite3_int64 SQLITE_STDCALL sqlite3_memory_highwater(int resetFlag);
    ++SQLITE_API sqlite3_int64 sqlite3_memory_used(void);
    ++SQLITE_API sqlite3_int64 sqlite3_memory_highwater(int resetFlag);
    + 
    + /*
    + ** CAPI3REF: Pseudo-Random Number Generator
    +@@ -2522,17 +2742,19 @@ SQLITE_API sqlite3_int64 SQLITE_STDCALL sqlite3_memory_highwater(int resetFlag);
    + ** internally and without recourse to the [sqlite3_vfs] xRandomness
    + ** method.
    + */
    +-SQLITE_API void SQLITE_STDCALL sqlite3_randomness(int N, void *P);
    ++SQLITE_API void sqlite3_randomness(int N, void *P);
    + 
    + /*
    + ** CAPI3REF: Compile-Time Authorization Callbacks
    + ** METHOD: sqlite3
    ++** KEYWORDS: {authorizer callback}
    + **
    + ** ^This routine registers an authorizer callback with a particular
    + ** [database connection], supplied in the first argument.
    + ** ^The authorizer callback is invoked as SQL statements are being compiled
    + ** by [sqlite3_prepare()] or its variants [sqlite3_prepare_v2()],
    +-** [sqlite3_prepare16()] and [sqlite3_prepare16_v2()].  ^At various
    ++** [sqlite3_prepare_v3()], [sqlite3_prepare16()], [sqlite3_prepare16_v2()],
    ++** and [sqlite3_prepare16_v3()].  ^At various
    + ** points during the compilation process, as logic is being created
    + ** to perform various actions, the authorizer callback is invoked to
    + ** see if those actions are allowed.  ^The authorizer callback should
    +@@ -2554,8 +2776,10 @@ SQLITE_API void SQLITE_STDCALL sqlite3_randomness(int N, void *P);
    + ** parameter to the sqlite3_set_authorizer() interface. ^The second parameter
    + ** to the callback is an integer [SQLITE_COPY | action code] that specifies
    + ** the particular action to be authorized. ^The third through sixth parameters
    +-** to the callback are zero-terminated strings that contain additional
    +-** details about the action to be authorized.
    ++** to the callback are either NULL pointers or zero-terminated strings
    ++** that contain additional details about the action to be authorized.
    ++** Applications must always be prepared to encounter a NULL pointer in any
    ++** of the third through the sixth parameters of the authorization callback.
    + **
    + ** ^If the action code is [SQLITE_READ]
    + ** and the callback returns [SQLITE_IGNORE] then the
    +@@ -2564,6 +2788,10 @@ SQLITE_API void SQLITE_STDCALL sqlite3_randomness(int N, void *P);
    + ** been read if [SQLITE_OK] had been returned.  The [SQLITE_IGNORE]
    + ** return can be used to deny an untrusted user access to individual
    + ** columns of a table.
    ++** ^When a table is referenced by a [SELECT] but no column values are
    ++** extracted from that table (for example in a query like
    ++** "SELECT count(*) FROM tab") then the [SQLITE_READ] authorizer callback
    ++** is invoked once for that table with a column name that is an empty string.
    + ** ^If the action code is [SQLITE_DELETE] and the callback returns
    + ** [SQLITE_IGNORE] then the [DELETE] operation proceeds but the
    + ** [truncate optimization] is disabled and all rows are deleted individually.
    +@@ -2605,7 +2833,7 @@ SQLITE_API void SQLITE_STDCALL sqlite3_randomness(int N, void *P);
    + ** as stated in the previous paragraph, sqlite3_step() invokes
    + ** sqlite3_prepare_v2() to reprepare a statement after a schema change.
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_set_authorizer(
    ++SQLITE_API int sqlite3_set_authorizer(
    +   sqlite3*,
    +   int (*xAuth)(void*,int,const char*,const char*,const char*,const char*),
    +   void *pUserData
    +@@ -2685,6 +2913,9 @@ SQLITE_API int SQLITE_STDCALL sqlite3_set_authorizer(
    + ** CAPI3REF: Tracing And Profiling Functions
    + ** METHOD: sqlite3
    + **
    ++** These routines are deprecated. Use the [sqlite3_trace_v2()] interface
    ++** instead of the routines described here.
    ++**
    + ** These routines register callback functions that can be used for
    + ** tracing and profiling the execution of SQL statements.
    + **
    +@@ -2710,10 +2941,104 @@ SQLITE_API int SQLITE_STDCALL sqlite3_set_authorizer(
    + ** sqlite3_profile() function is considered experimental and is
    + ** subject to change in future versions of SQLite.
    + */
    +-SQLITE_API void *SQLITE_STDCALL sqlite3_trace(sqlite3*, void(*xTrace)(void*,const char*), void*);
    +-SQLITE_API SQLITE_EXPERIMENTAL void *SQLITE_STDCALL sqlite3_profile(sqlite3*,
    ++SQLITE_API SQLITE_DEPRECATED void *sqlite3_trace(sqlite3*,
    ++   void(*xTrace)(void*,const char*), void*);
    ++SQLITE_API SQLITE_DEPRECATED void *sqlite3_profile(sqlite3*,
    +    void(*xProfile)(void*,const char*,sqlite3_uint64), void*);
    + 
    ++/*
    ++** CAPI3REF: SQL Trace Event Codes
    ++** KEYWORDS: SQLITE_TRACE
    ++**
    ++** These constants identify classes of events that can be monitored
    ++** using the [sqlite3_trace_v2()] tracing logic.  The M argument
    ++** to [sqlite3_trace_v2(D,M,X,P)] is an OR-ed combination of one or more of
    ++** the following constants.  ^The first argument to the trace callback
    ++** is one of the following constants.
    ++**
    ++** New tracing constants may be added in future releases.
    ++**
    ++** ^A trace callback has four arguments: xCallback(T,C,P,X).
    ++** ^The T argument is one of the integer type codes above.
    ++** ^The C argument is a copy of the context pointer passed in as the
    ++** fourth argument to [sqlite3_trace_v2()].
    ++** The P and X arguments are pointers whose meanings depend on T.
    ++**
    ++** <dl>
    ++** [[SQLITE_TRACE_STMT]] <dt>SQLITE_TRACE_STMT</dt>
    ++** <dd>^An SQLITE_TRACE_STMT callback is invoked when a prepared statement
    ++** first begins running and possibly at other times during the
    ++** execution of the prepared statement, such as at the start of each
    ++** trigger subprogram. ^The P argument is a pointer to the
    ++** [prepared statement]. ^The X argument is a pointer to a string which
    ++** is the unexpanded SQL text of the prepared statement or an SQL comment 
    ++** that indicates the invocation of a trigger.  ^The callback can compute
    ++** the same text that would have been returned by the legacy [sqlite3_trace()]
    ++** interface by using the X argument when X begins with "--" and invoking
    ++** [sqlite3_expanded_sql(P)] otherwise.
    ++**
    ++** [[SQLITE_TRACE_PROFILE]] <dt>SQLITE_TRACE_PROFILE</dt>
    ++** <dd>^An SQLITE_TRACE_PROFILE callback provides approximately the same
    ++** information as is provided by the [sqlite3_profile()] callback.
    ++** ^The P argument is a pointer to the [prepared statement] and the
    ++** X argument points to a 64-bit integer which is the estimated of
    ++** the number of nanosecond that the prepared statement took to run.
    ++** ^The SQLITE_TRACE_PROFILE callback is invoked when the statement finishes.
    ++**
    ++** [[SQLITE_TRACE_ROW]] <dt>SQLITE_TRACE_ROW</dt>
    ++** <dd>^An SQLITE_TRACE_ROW callback is invoked whenever a prepared
    ++** statement generates a single row of result.  
    ++** ^The P argument is a pointer to the [prepared statement] and the
    ++** X argument is unused.
    ++**
    ++** [[SQLITE_TRACE_CLOSE]] <dt>SQLITE_TRACE_CLOSE</dt>
    ++** <dd>^An SQLITE_TRACE_CLOSE callback is invoked when a database
    ++** connection closes.
    ++** ^The P argument is a pointer to the [database connection] object
    ++** and the X argument is unused.
    ++** </dl>
    ++*/
    ++#define SQLITE_TRACE_STMT       0x01
    ++#define SQLITE_TRACE_PROFILE    0x02
    ++#define SQLITE_TRACE_ROW        0x04
    ++#define SQLITE_TRACE_CLOSE      0x08
    ++
    ++/*
    ++** CAPI3REF: SQL Trace Hook
    ++** METHOD: sqlite3
    ++**
    ++** ^The sqlite3_trace_v2(D,M,X,P) interface registers a trace callback
    ++** function X against [database connection] D, using property mask M
    ++** and context pointer P.  ^If the X callback is
    ++** NULL or if the M mask is zero, then tracing is disabled.  The
    ++** M argument should be the bitwise OR-ed combination of
    ++** zero or more [SQLITE_TRACE] constants.
    ++**
    ++** ^Each call to either sqlite3_trace() or sqlite3_trace_v2() overrides 
    ++** (cancels) any prior calls to sqlite3_trace() or sqlite3_trace_v2().
    ++**
    ++** ^The X callback is invoked whenever any of the events identified by 
    ++** mask M occur.  ^The integer return value from the callback is currently
    ++** ignored, though this may change in future releases.  Callback
    ++** implementations should return zero to ensure future compatibility.
    ++**
    ++** ^A trace callback is invoked with four arguments: callback(T,C,P,X).
    ++** ^The T argument is one of the [SQLITE_TRACE]
    ++** constants to indicate why the callback was invoked.
    ++** ^The C argument is a copy of the context pointer.
    ++** The P and X arguments are pointers whose meanings depend on T.
    ++**
    ++** The sqlite3_trace_v2() interface is intended to replace the legacy
    ++** interfaces [sqlite3_trace()] and [sqlite3_profile()], both of which
    ++** are deprecated.
    ++*/
    ++SQLITE_API int sqlite3_trace_v2(
    ++  sqlite3*,
    ++  unsigned uMask,
    ++  int(*xCallback)(unsigned,void*,void*,void*),
    ++  void *pCtx
    ++);
    ++
    + /*
    + ** CAPI3REF: Query Progress Callbacks
    + ** METHOD: sqlite3
    +@@ -2746,7 +3071,7 @@ SQLITE_API SQLITE_EXPERIMENTAL void *SQLITE_STDCALL sqlite3_profile(sqlite3*,
    + ** database connections for the meaning of "modify" in this paragraph.
    + **
    + */
    +-SQLITE_API void SQLITE_STDCALL sqlite3_progress_handler(sqlite3*, int, int(*)(void*), void*);
    ++SQLITE_API void sqlite3_progress_handler(sqlite3*, int, int(*)(void*), void*);
    + 
    + /*
    + ** CAPI3REF: Opening A New Database Connection
    +@@ -2836,10 +3161,10 @@ SQLITE_API void SQLITE_STDCALL sqlite3_progress_handler(sqlite3*, int, int(*)(vo
    + ** ^If [URI filename] interpretation is enabled, and the filename argument
    + ** begins with "file:", then the filename is interpreted as a URI. ^URI
    + ** filename interpretation is enabled if the [SQLITE_OPEN_URI] flag is
    +-** set in the fourth argument to sqlite3_open_v2(), or if it has
    ++** set in the third argument to sqlite3_open_v2(), or if it has
    + ** been enabled globally using the [SQLITE_CONFIG_URI] option with the
    + ** [sqlite3_config()] method or by the [SQLITE_USE_URI] compile-time option.
    +-** As of SQLite version 3.7.7, URI filename interpretation is turned off
    ++** URI filename interpretation is turned off
    + ** by default, but future releases of SQLite might enable URI filename
    + ** interpretation by default.  See "[URI filenames]" for additional
    + ** information.
    +@@ -2975,15 +3300,15 @@ SQLITE_API void SQLITE_STDCALL sqlite3_progress_handler(sqlite3*, int, int(*)(vo
    + **
    + ** See also: [sqlite3_temp_directory]
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_open(
    ++SQLITE_API int sqlite3_open(
    +   const char *filename,   /* Database filename (UTF-8) */
    +   sqlite3 **ppDb          /* OUT: SQLite db handle */
    + );
    +-SQLITE_API int SQLITE_STDCALL sqlite3_open16(
    ++SQLITE_API int sqlite3_open16(
    +   const void *filename,   /* Database filename (UTF-16) */
    +   sqlite3 **ppDb          /* OUT: SQLite db handle */
    + );
    +-SQLITE_API int SQLITE_STDCALL sqlite3_open_v2(
    ++SQLITE_API int sqlite3_open_v2(
    +   const char *filename,   /* Database filename (UTF-8) */
    +   sqlite3 **ppDb,         /* OUT: SQLite db handle */
    +   int flags,              /* Flags */
    +@@ -3029,9 +3354,9 @@ SQLITE_API int SQLITE_STDCALL sqlite3_open_v2(
    + ** VFS method, then the behavior of this routine is undefined and probably
    + ** undesirable.
    + */
    +-SQLITE_API const char *SQLITE_STDCALL sqlite3_uri_parameter(const char *zFilename, const char *zParam);
    +-SQLITE_API int SQLITE_STDCALL sqlite3_uri_boolean(const char *zFile, const char *zParam, int bDefault);
    +-SQLITE_API sqlite3_int64 SQLITE_STDCALL sqlite3_uri_int64(const char*, const char*, sqlite3_int64);
    ++SQLITE_API const char *sqlite3_uri_parameter(const char *zFilename, const char *zParam);
    ++SQLITE_API int sqlite3_uri_boolean(const char *zFile, const char *zParam, int bDefault);
    ++SQLITE_API sqlite3_int64 sqlite3_uri_int64(const char*, const char*, sqlite3_int64);
    + 
    + 
    + /*
    +@@ -3075,11 +3400,11 @@ SQLITE_API sqlite3_int64 SQLITE_STDCALL sqlite3_uri_int64(const char*, const cha
    + ** was invoked incorrectly by the application.  In that case, the
    + ** error code and message may or may not be set.
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_errcode(sqlite3 *db);
    +-SQLITE_API int SQLITE_STDCALL sqlite3_extended_errcode(sqlite3 *db);
    +-SQLITE_API const char *SQLITE_STDCALL sqlite3_errmsg(sqlite3*);
    +-SQLITE_API const void *SQLITE_STDCALL sqlite3_errmsg16(sqlite3*);
    +-SQLITE_API const char *SQLITE_STDCALL sqlite3_errstr(int);
    ++SQLITE_API int sqlite3_errcode(sqlite3 *db);
    ++SQLITE_API int sqlite3_extended_errcode(sqlite3 *db);
    ++SQLITE_API const char *sqlite3_errmsg(sqlite3*);
    ++SQLITE_API const void *sqlite3_errmsg16(sqlite3*);
    ++SQLITE_API const char *sqlite3_errstr(int);
    + 
    + /*
    + ** CAPI3REF: Prepared Statement Object
    +@@ -3147,7 +3472,7 @@ typedef struct sqlite3_stmt sqlite3_stmt;
    + **
    + ** New run-time limit categories may be added in future releases.
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_limit(sqlite3*, int id, int newVal);
    ++SQLITE_API int sqlite3_limit(sqlite3*, int id, int newVal);
    + 
    + /*
    + ** CAPI3REF: Run-Time Limit Categories
    +@@ -3178,9 +3503,9 @@ SQLITE_API int SQLITE_STDCALL sqlite3_limit(sqlite3*, int id, int newVal);
    + **
    + ** [[SQLITE_LIMIT_VDBE_OP]] ^(<dt>SQLITE_LIMIT_VDBE_OP</dt>
    + ** <dd>The maximum number of instructions in a virtual machine program
    +-** used to implement an SQL statement.  This limit is not currently
    +-** enforced, though that might be added in some future release of
    +-** SQLite.</dd>)^
    ++** used to implement an SQL statement.  If [sqlite3_prepare_v2()] or
    ++** the equivalent tries to allocate space for more than this many opcodes
    ++** in a single prepared statement, an SQLITE_NOMEM error is returned.</dd>)^
    + **
    + ** [[SQLITE_LIMIT_FUNCTION_ARG]] ^(<dt>SQLITE_LIMIT_FUNCTION_ARG</dt>
    + ** <dd>The maximum number of arguments on a function.</dd>)^
    +@@ -3218,23 +3543,59 @@ SQLITE_API int SQLITE_STDCALL sqlite3_limit(sqlite3*, int id, int newVal);
    + #define SQLITE_LIMIT_TRIGGER_DEPTH            10
    + #define SQLITE_LIMIT_WORKER_THREADS           11
    + 
    ++/*
    ++** CAPI3REF: Prepare Flags
    ++**
    ++** These constants define various flags that can be passed into
    ++** "prepFlags" parameter of the [sqlite3_prepare_v3()] and
    ++** [sqlite3_prepare16_v3()] interfaces.
    ++**
    ++** New flags may be added in future releases of SQLite.
    ++**
    ++** <dl>
    ++** [[SQLITE_PREPARE_PERSISTENT]] ^(<dt>SQLITE_PREPARE_PERSISTENT</dt>
    ++** <dd>The SQLITE_PREPARE_PERSISTENT flag is a hint to the query planner
    ++** that the prepared statement will be retained for a long time and
    ++** probably reused many times.)^ ^Without this flag, [sqlite3_prepare_v3()]
    ++** and [sqlite3_prepare16_v3()] assume that the prepared statement will 
    ++** be used just once or at most a few times and then destroyed using
    ++** [sqlite3_finalize()] relatively soon. The current implementation acts
    ++** on this hint by avoiding the use of [lookaside memory] so as not to
    ++** deplete the limited store of lookaside memory. Future versions of
    ++** SQLite may act on this hint differently.
    ++** </dl>
    ++*/
    ++#define SQLITE_PREPARE_PERSISTENT              0x01
    ++
    + /*
    + ** CAPI3REF: Compiling An SQL Statement
    + ** KEYWORDS: {SQL statement compiler}
    + ** METHOD: sqlite3
    + ** CONSTRUCTOR: sqlite3_stmt
    + **
    +-** To execute an SQL query, it must first be compiled into a byte-code
    +-** program using one of these routines.
    ++** To execute an SQL statement, it must first be compiled into a byte-code
    ++** program using one of these routines.  Or, in other words, these routines
    ++** are constructors for the [prepared statement] object.
    ++**
    ++** The preferred routine to use is [sqlite3_prepare_v2()].  The
    ++** [sqlite3_prepare()] interface is legacy and should be avoided.
    ++** [sqlite3_prepare_v3()] has an extra "prepFlags" option that is used
    ++** for special purposes.
    ++**
    ++** The use of the UTF-8 interfaces is preferred, as SQLite currently
    ++** does all parsing using UTF-8.  The UTF-16 interfaces are provided
    ++** as a convenience.  The UTF-16 interfaces work by converting the
    ++** input text into UTF-8, then invoking the corresponding UTF-8 interface.
    + **
    + ** The first argument, "db", is a [database connection] obtained from a
    + ** prior successful call to [sqlite3_open()], [sqlite3_open_v2()] or
    + ** [sqlite3_open16()].  The database connection must not have been closed.
    + **
    + ** The second argument, "zSql", is the statement to be compiled, encoded
    +-** as either UTF-8 or UTF-16.  The sqlite3_prepare() and sqlite3_prepare_v2()
    +-** interfaces use UTF-8, and sqlite3_prepare16() and sqlite3_prepare16_v2()
    +-** use UTF-16.
    ++** as either UTF-8 or UTF-16.  The sqlite3_prepare(), sqlite3_prepare_v2(),
    ++** and sqlite3_prepare_v3()
    ++** interfaces use UTF-8, and sqlite3_prepare16(), sqlite3_prepare16_v2(),
    ++** and sqlite3_prepare16_v3() use UTF-16.
    + **
    + ** ^If the nByte argument is negative, then zSql is read up to the
    + ** first zero terminator. ^If nByte is positive, then it is the
    +@@ -3261,10 +3622,11 @@ SQLITE_API int SQLITE_STDCALL sqlite3_limit(sqlite3*, int id, int newVal);
    + ** ^On success, the sqlite3_prepare() family of routines return [SQLITE_OK];
    + ** otherwise an [error code] is returned.
    + **
    +-** The sqlite3_prepare_v2() and sqlite3_prepare16_v2() interfaces are
    +-** recommended for all new programs. The two older interfaces are retained
    +-** for backwards compatibility, but their use is discouraged.
    +-** ^In the "v2" interfaces, the prepared statement
    ++** The sqlite3_prepare_v2(), sqlite3_prepare_v3(), sqlite3_prepare16_v2(),
    ++** and sqlite3_prepare16_v3() interfaces are recommended for all new programs.
    ++** The older interfaces (sqlite3_prepare() and sqlite3_prepare16())
    ++** are retained for backwards compatibility, but their use is discouraged.
    ++** ^In the "vX" interfaces, the prepared statement
    + ** that is returned (the [sqlite3_stmt] object) contains a copy of the
    + ** original SQL text. This causes the [sqlite3_step()] interface to
    + ** behave differently in three ways:
    +@@ -3297,33 +3659,55 @@ SQLITE_API int SQLITE_STDCALL sqlite3_limit(sqlite3*, int id, int newVal);
    + ** or [GLOB] operator or if the parameter is compared to an indexed column
    + ** and the [SQLITE_ENABLE_STAT3] compile-time option is enabled.
    + ** </li>
    ++**
    ++** <p>^sqlite3_prepare_v3() differs from sqlite3_prepare_v2() only in having
    ++** the extra prepFlags parameter, which is a bit array consisting of zero or
    ++** more of the [SQLITE_PREPARE_PERSISTENT|SQLITE_PREPARE_*] flags.  ^The
    ++** sqlite3_prepare_v2() interface works exactly the same as
    ++** sqlite3_prepare_v3() with a zero prepFlags parameter.
    + ** </ol>
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_prepare(
    ++SQLITE_API int sqlite3_prepare(
    ++  sqlite3 *db,            /* Database handle */
    ++  const char *zSql,       /* SQL statement, UTF-8 encoded */
    ++  int nByte,              /* Maximum length of zSql in bytes. */
    ++  sqlite3_stmt **ppStmt,  /* OUT: Statement handle */
    ++  const char **pzTail     /* OUT: Pointer to unused portion of zSql */
    ++);
    ++SQLITE_API int sqlite3_prepare_v2(
    +   sqlite3 *db,            /* Database handle */
    +   const char *zSql,       /* SQL statement, UTF-8 encoded */
    +   int nByte,              /* Maximum length of zSql in bytes. */
    +   sqlite3_stmt **ppStmt,  /* OUT: Statement handle */
    +   const char **pzTail     /* OUT: Pointer to unused portion of zSql */
    + );
    +-SQLITE_API int SQLITE_STDCALL sqlite3_prepare_v2(
    ++SQLITE_API int sqlite3_prepare_v3(
    +   sqlite3 *db,            /* Database handle */
    +   const char *zSql,       /* SQL statement, UTF-8 encoded */
    +   int nByte,              /* Maximum length of zSql in bytes. */
    ++  unsigned int prepFlags, /* Zero or more SQLITE_PREPARE_ flags */
    +   sqlite3_stmt **ppStmt,  /* OUT: Statement handle */
    +   const char **pzTail     /* OUT: Pointer to unused portion of zSql */
    + );
    +-SQLITE_API int SQLITE_STDCALL sqlite3_prepare16(
    ++SQLITE_API int sqlite3_prepare16(
    ++  sqlite3 *db,            /* Database handle */
    ++  const void *zSql,       /* SQL statement, UTF-16 encoded */
    ++  int nByte,              /* Maximum length of zSql in bytes. */
    ++  sqlite3_stmt **ppStmt,  /* OUT: Statement handle */
    ++  const void **pzTail     /* OUT: Pointer to unused portion of zSql */
    ++);
    ++SQLITE_API int sqlite3_prepare16_v2(
    +   sqlite3 *db,            /* Database handle */
    +   const void *zSql,       /* SQL statement, UTF-16 encoded */
    +   int nByte,              /* Maximum length of zSql in bytes. */
    +   sqlite3_stmt **ppStmt,  /* OUT: Statement handle */
    +   const void **pzTail     /* OUT: Pointer to unused portion of zSql */
    + );
    +-SQLITE_API int SQLITE_STDCALL sqlite3_prepare16_v2(
    ++SQLITE_API int sqlite3_prepare16_v3(
    +   sqlite3 *db,            /* Database handle */
    +   const void *zSql,       /* SQL statement, UTF-16 encoded */
    +   int nByte,              /* Maximum length of zSql in bytes. */
    ++  unsigned int prepFlags, /* Zero or more SQLITE_PREPARE_ flags */
    +   sqlite3_stmt **ppStmt,  /* OUT: Statement handle */
    +   const void **pzTail     /* OUT: Pointer to unused portion of zSql */
    + );
    +@@ -3332,11 +3716,36 @@ SQLITE_API int SQLITE_STDCALL sqlite3_prepare16_v2(
    + ** CAPI3REF: Retrieving Statement SQL
    + ** METHOD: sqlite3_stmt
    + **
    +-** ^This interface can be used to retrieve a saved copy of the original
    +-** SQL text used to create a [prepared statement] if that statement was
    +-** compiled using either [sqlite3_prepare_v2()] or [sqlite3_prepare16_v2()].
    ++** ^The sqlite3_sql(P) interface returns a pointer to a copy of the UTF-8
    ++** SQL text used to create [prepared statement] P if P was
    ++** created by [sqlite3_prepare_v2()], [sqlite3_prepare_v3()],
    ++** [sqlite3_prepare16_v2()], or [sqlite3_prepare16_v3()].
    ++** ^The sqlite3_expanded_sql(P) interface returns a pointer to a UTF-8
    ++** string containing the SQL text of prepared statement P with
    ++** [bound parameters] expanded.
    ++**
    ++** ^(For example, if a prepared statement is created using the SQL
    ++** text "SELECT $abc,:xyz" and if parameter $abc is bound to integer 2345
    ++** and parameter :xyz is unbound, then sqlite3_sql() will return
    ++** the original string, "SELECT $abc,:xyz" but sqlite3_expanded_sql()
    ++** will return "SELECT 2345,NULL".)^
    ++**
    ++** ^The sqlite3_expanded_sql() interface returns NULL if insufficient memory
    ++** is available to hold the result, or if the result would exceed the
    ++** the maximum string length determined by the [SQLITE_LIMIT_LENGTH].
    ++**
    ++** ^The [SQLITE_TRACE_SIZE_LIMIT] compile-time option limits the size of
    ++** bound parameter expansions.  ^The [SQLITE_OMIT_TRACE] compile-time
    ++** option causes sqlite3_expanded_sql() to always return NULL.
    ++**
    ++** ^The string returned by sqlite3_sql(P) is managed by SQLite and is
    ++** automatically freed when the prepared statement is finalized.
    ++** ^The string returned by sqlite3_expanded_sql(P), on the other hand,
    ++** is obtained from [sqlite3_malloc()] and must be free by the application
    ++** by passing it to [sqlite3_free()].
    + */
    +-SQLITE_API const char *SQLITE_STDCALL sqlite3_sql(sqlite3_stmt *pStmt);
    ++SQLITE_API const char *sqlite3_sql(sqlite3_stmt *pStmt);
    ++SQLITE_API char *sqlite3_expanded_sql(sqlite3_stmt *pStmt);
    + 
    + /*
    + ** CAPI3REF: Determine If An SQL Statement Writes The Database
    +@@ -3367,8 +3776,12 @@ SQLITE_API const char *SQLITE_STDCALL sqlite3_sql(sqlite3_stmt *pStmt);
    + ** sqlite3_stmt_readonly() to return true since, while those statements
    + ** change the configuration of a database connection, they do not make 
    + ** changes to the content of the database files on disk.
    ++** ^The sqlite3_stmt_readonly() interface returns true for [BEGIN] since
    ++** [BEGIN] merely sets internal flags, but the [BEGIN|BEGIN IMMEDIATE] and
    ++** [BEGIN|BEGIN EXCLUSIVE] commands do touch the database and so
    ++** sqlite3_stmt_readonly() returns false for those commands.
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_stmt_readonly(sqlite3_stmt *pStmt);
    ++SQLITE_API int sqlite3_stmt_readonly(sqlite3_stmt *pStmt);
    + 
    + /*
    + ** CAPI3REF: Determine If A Prepared Statement Has Been Reset
    +@@ -3389,7 +3802,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_stmt_readonly(sqlite3_stmt *pStmt);
    + ** for example, in diagnostic routines to search for prepared 
    + ** statements that are holding a transaction open.
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_stmt_busy(sqlite3_stmt*);
    ++SQLITE_API int sqlite3_stmt_busy(sqlite3_stmt*);
    + 
    + /*
    + ** CAPI3REF: Dynamically Typed Value Object
    +@@ -3425,12 +3838,13 @@ SQLITE_API int SQLITE_STDCALL sqlite3_stmt_busy(sqlite3_stmt*);
    + ** implementation of [application-defined SQL functions] are protected.
    + ** ^The sqlite3_value object returned by
    + ** [sqlite3_column_value()] is unprotected.
    +-** Unprotected sqlite3_value objects may only be used with
    +-** [sqlite3_result_value()] and [sqlite3_bind_value()].
    ++** Unprotected sqlite3_value objects may only be used as arguments
    ++** to [sqlite3_result_value()], [sqlite3_bind_value()], and
    ++** [sqlite3_value_dup()].
    + ** The [sqlite3_value_blob | sqlite3_value_type()] family of
    + ** interfaces require protected sqlite3_value objects.
    + */
    +-typedef struct Mem sqlite3_value;
    ++typedef struct sqlite3_value sqlite3_value;
    + 
    + /*
    + ** CAPI3REF: SQL Function Context Object
    +@@ -3532,6 +3946,15 @@ typedef struct sqlite3_context sqlite3_context;
    + ** [sqlite3_blob_open | incremental BLOB I/O] routines.
    + ** ^A negative value for the zeroblob results in a zero-length BLOB.
    + **
    ++** ^The sqlite3_bind_pointer(S,I,P,T,D) routine causes the I-th parameter in
    ++** [prepared statement] S to have an SQL value of NULL, but to also be
    ++** associated with the pointer P of type T.  ^D is either a NULL pointer or
    ++** a pointer to a destructor function for P. ^SQLite will invoke the
    ++** destructor D with a single argument of P when it is finished using
    ++** P.  The T parameter should be a static string, preferably a string
    ++** literal. The sqlite3_bind_pointer() routine is part of the
    ++** [pointer passing interface] added for SQLite 3.20.0.
    ++**
    + ** ^If any of the sqlite3_bind_*() routines are called with a NULL pointer
    + ** for the [prepared statement] or with a prepared statement for which
    + ** [sqlite3_step()] has been called more recently than [sqlite3_reset()],
    +@@ -3553,20 +3976,21 @@ typedef struct sqlite3_context sqlite3_context;
    + ** See also: [sqlite3_bind_parameter_count()],
    + ** [sqlite3_bind_parameter_name()], and [sqlite3_bind_parameter_index()].
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_bind_blob(sqlite3_stmt*, int, const void*, int n, void(*)(void*));
    +-SQLITE_API int SQLITE_STDCALL sqlite3_bind_blob64(sqlite3_stmt*, int, const void*, sqlite3_uint64,
    ++SQLITE_API int sqlite3_bind_blob(sqlite3_stmt*, int, const void*, int n, void(*)(void*));
    ++SQLITE_API int sqlite3_bind_blob64(sqlite3_stmt*, int, const void*, sqlite3_uint64,
    +                         void(*)(void*));
    +-SQLITE_API int SQLITE_STDCALL sqlite3_bind_double(sqlite3_stmt*, int, double);
    +-SQLITE_API int SQLITE_STDCALL sqlite3_bind_int(sqlite3_stmt*, int, int);
    +-SQLITE_API int SQLITE_STDCALL sqlite3_bind_int64(sqlite3_stmt*, int, sqlite3_int64);
    +-SQLITE_API int SQLITE_STDCALL sqlite3_bind_null(sqlite3_stmt*, int);
    +-SQLITE_API int SQLITE_STDCALL sqlite3_bind_text(sqlite3_stmt*,int,const char*,int,void(*)(void*));
    +-SQLITE_API int SQLITE_STDCALL sqlite3_bind_text16(sqlite3_stmt*, int, const void*, int, void(*)(void*));
    +-SQLITE_API int SQLITE_STDCALL sqlite3_bind_text64(sqlite3_stmt*, int, const char*, sqlite3_uint64,
    ++SQLITE_API int sqlite3_bind_double(sqlite3_stmt*, int, double);
    ++SQLITE_API int sqlite3_bind_int(sqlite3_stmt*, int, int);
    ++SQLITE_API int sqlite3_bind_int64(sqlite3_stmt*, int, sqlite3_int64);
    ++SQLITE_API int sqlite3_bind_null(sqlite3_stmt*, int);
    ++SQLITE_API int sqlite3_bind_text(sqlite3_stmt*,int,const char*,int,void(*)(void*));
    ++SQLITE_API int sqlite3_bind_text16(sqlite3_stmt*, int, const void*, int, void(*)(void*));
    ++SQLITE_API int sqlite3_bind_text64(sqlite3_stmt*, int, const char*, sqlite3_uint64,
    +                          void(*)(void*), unsigned char encoding);
    +-SQLITE_API int SQLITE_STDCALL sqlite3_bind_value(sqlite3_stmt*, int, const sqlite3_value*);
    +-SQLITE_API int SQLITE_STDCALL sqlite3_bind_zeroblob(sqlite3_stmt*, int, int n);
    +-SQLITE_API int SQLITE_STDCALL sqlite3_bind_zeroblob64(sqlite3_stmt*, int, sqlite3_uint64);
    ++SQLITE_API int sqlite3_bind_value(sqlite3_stmt*, int, const sqlite3_value*);
    ++SQLITE_API int sqlite3_bind_pointer(sqlite3_stmt*, int, void*, const char*,void(*)(void*));
    ++SQLITE_API int sqlite3_bind_zeroblob(sqlite3_stmt*, int, int n);
    ++SQLITE_API int sqlite3_bind_zeroblob64(sqlite3_stmt*, int, sqlite3_uint64);
    + 
    + /*
    + ** CAPI3REF: Number Of SQL Parameters
    +@@ -3587,7 +4011,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_bind_zeroblob64(sqlite3_stmt*, int, sqlite
    + ** [sqlite3_bind_parameter_name()], and
    + ** [sqlite3_bind_parameter_index()].
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_bind_parameter_count(sqlite3_stmt*);
    ++SQLITE_API int sqlite3_bind_parameter_count(sqlite3_stmt*);
    + 
    + /*
    + ** CAPI3REF: Name Of A Host Parameter
    +@@ -3608,14 +4032,14 @@ SQLITE_API int SQLITE_STDCALL sqlite3_bind_parameter_count(sqlite3_stmt*);
    + ** ^If the value N is out of range or if the N-th parameter is
    + ** nameless, then NULL is returned.  ^The returned string is
    + ** always in UTF-8 encoding even if the named parameter was
    +-** originally specified as UTF-16 in [sqlite3_prepare16()] or
    +-** [sqlite3_prepare16_v2()].
    ++** originally specified as UTF-16 in [sqlite3_prepare16()],
    ++** [sqlite3_prepare16_v2()], or [sqlite3_prepare16_v3()].
    + **
    + ** See also: [sqlite3_bind_blob|sqlite3_bind()],
    + ** [sqlite3_bind_parameter_count()], and
    + ** [sqlite3_bind_parameter_index()].
    + */
    +-SQLITE_API const char *SQLITE_STDCALL sqlite3_bind_parameter_name(sqlite3_stmt*, int);
    ++SQLITE_API const char *sqlite3_bind_parameter_name(sqlite3_stmt*, int);
    + 
    + /*
    + ** CAPI3REF: Index Of A Parameter With A Given Name
    +@@ -3626,13 +4050,14 @@ SQLITE_API const char *SQLITE_STDCALL sqlite3_bind_parameter_name(sqlite3_stmt*,
    + ** parameter to [sqlite3_bind_blob|sqlite3_bind()].  ^A zero
    + ** is returned if no matching parameter is found.  ^The parameter
    + ** name must be given in UTF-8 even if the original statement
    +-** was prepared from UTF-16 text using [sqlite3_prepare16_v2()].
    ++** was prepared from UTF-16 text using [sqlite3_prepare16_v2()] or
    ++** [sqlite3_prepare16_v3()].
    + **
    + ** See also: [sqlite3_bind_blob|sqlite3_bind()],
    + ** [sqlite3_bind_parameter_count()], and
    + ** [sqlite3_bind_parameter_name()].
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_bind_parameter_index(sqlite3_stmt*, const char *zName);
    ++SQLITE_API int sqlite3_bind_parameter_index(sqlite3_stmt*, const char *zName);
    + 
    + /*
    + ** CAPI3REF: Reset All Bindings On A Prepared Statement
    +@@ -3642,19 +4067,23 @@ SQLITE_API int SQLITE_STDCALL sqlite3_bind_parameter_index(sqlite3_stmt*, const
    + ** the [sqlite3_bind_blob | bindings] on a [prepared statement].
    + ** ^Use this routine to reset all host parameters to NULL.
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_clear_bindings(sqlite3_stmt*);
    ++SQLITE_API int sqlite3_clear_bindings(sqlite3_stmt*);
    + 
    + /*
    + ** CAPI3REF: Number Of Columns In A Result Set
    + ** METHOD: sqlite3_stmt
    + **
    + ** ^Return the number of columns in the result set returned by the
    +-** [prepared statement]. ^This routine returns 0 if pStmt is an SQL
    +-** statement that does not return data (for example an [UPDATE]).
    ++** [prepared statement]. ^If this routine returns 0, that means the 
    ++** [prepared statement] returns no data (for example an [UPDATE]).
    ++** ^However, just because this routine returns a positive number does not
    ++** mean that one or more rows of data will be returned.  ^A SELECT statement
    ++** will always have a positive sqlite3_column_count() but depending on the
    ++** WHERE clause constraints and the table content, it might return no rows.
    + **
    + ** See also: [sqlite3_data_count()]
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_column_count(sqlite3_stmt *pStmt);
    ++SQLITE_API int sqlite3_column_count(sqlite3_stmt *pStmt);
    + 
    + /*
    + ** CAPI3REF: Column Names In A Result Set
    +@@ -3683,8 +4112,8 @@ SQLITE_API int SQLITE_STDCALL sqlite3_column_count(sqlite3_stmt *pStmt);
    + ** then the name of the column is unspecified and may change from
    + ** one release of SQLite to the next.
    + */
    +-SQLITE_API const char *SQLITE_STDCALL sqlite3_column_name(sqlite3_stmt*, int N);
    +-SQLITE_API const void *SQLITE_STDCALL sqlite3_column_name16(sqlite3_stmt*, int N);
    ++SQLITE_API const char *sqlite3_column_name(sqlite3_stmt*, int N);
    ++SQLITE_API const void *sqlite3_column_name16(sqlite3_stmt*, int N);
    + 
    + /*
    + ** CAPI3REF: Source Of Data In A Query Result
    +@@ -3732,12 +4161,12 @@ SQLITE_API const void *SQLITE_STDCALL sqlite3_column_name16(sqlite3_stmt*, int N
    + ** for the same [prepared statement] and result column
    + ** at the same time then the results are undefined.
    + */
    +-SQLITE_API const char *SQLITE_STDCALL sqlite3_column_database_name(sqlite3_stmt*,int);
    +-SQLITE_API const void *SQLITE_STDCALL sqlite3_column_database_name16(sqlite3_stmt*,int);
    +-SQLITE_API const char *SQLITE_STDCALL sqlite3_column_table_name(sqlite3_stmt*,int);
    +-SQLITE_API const void *SQLITE_STDCALL sqlite3_column_table_name16(sqlite3_stmt*,int);
    +-SQLITE_API const char *SQLITE_STDCALL sqlite3_column_origin_name(sqlite3_stmt*,int);
    +-SQLITE_API const void *SQLITE_STDCALL sqlite3_column_origin_name16(sqlite3_stmt*,int);
    ++SQLITE_API const char *sqlite3_column_database_name(sqlite3_stmt*,int);
    ++SQLITE_API const void *sqlite3_column_database_name16(sqlite3_stmt*,int);
    ++SQLITE_API const char *sqlite3_column_table_name(sqlite3_stmt*,int);
    ++SQLITE_API const void *sqlite3_column_table_name16(sqlite3_stmt*,int);
    ++SQLITE_API const char *sqlite3_column_origin_name(sqlite3_stmt*,int);
    ++SQLITE_API const void *sqlite3_column_origin_name16(sqlite3_stmt*,int);
    + 
    + /*
    + ** CAPI3REF: Declared Datatype Of A Query Result
    +@@ -3769,23 +4198,25 @@ SQLITE_API const void *SQLITE_STDCALL sqlite3_column_origin_name16(sqlite3_stmt*
    + ** is associated with individual values, not with the containers
    + ** used to hold those values.
    + */
    +-SQLITE_API const char *SQLITE_STDCALL sqlite3_column_decltype(sqlite3_stmt*,int);
    +-SQLITE_API const void *SQLITE_STDCALL sqlite3_column_decltype16(sqlite3_stmt*,int);
    ++SQLITE_API const char *sqlite3_column_decltype(sqlite3_stmt*,int);
    ++SQLITE_API const void *sqlite3_column_decltype16(sqlite3_stmt*,int);
    + 
    + /*
    + ** CAPI3REF: Evaluate An SQL Statement
    + ** METHOD: sqlite3_stmt
    + **
    +-** After a [prepared statement] has been prepared using either
    +-** [sqlite3_prepare_v2()] or [sqlite3_prepare16_v2()] or one of the legacy
    ++** After a [prepared statement] has been prepared using any of
    ++** [sqlite3_prepare_v2()], [sqlite3_prepare_v3()], [sqlite3_prepare16_v2()],
    ++** or [sqlite3_prepare16_v3()] or one of the legacy
    + ** interfaces [sqlite3_prepare()] or [sqlite3_prepare16()], this function
    + ** must be called one or more times to evaluate the statement.
    + **
    + ** The details of the behavior of the sqlite3_step() interface depend
    +-** on whether the statement was prepared using the newer "v2" interface
    +-** [sqlite3_prepare_v2()] and [sqlite3_prepare16_v2()] or the older legacy
    +-** interface [sqlite3_prepare()] and [sqlite3_prepare16()].  The use of the
    +-** new "v2" interface is recommended for new applications but the legacy
    ++** on whether the statement was prepared using the newer "vX" interfaces
    ++** [sqlite3_prepare_v3()], [sqlite3_prepare_v2()], [sqlite3_prepare16_v3()],
    ++** [sqlite3_prepare16_v2()] or the older legacy
    ++** interfaces [sqlite3_prepare()] and [sqlite3_prepare16()].  The use of the
    ++** new "vX" interface is recommended for new applications but the legacy
    + ** interface will continue to be supported.
    + **
    + ** ^In the legacy interface, the return value will be either [SQLITE_BUSY],
    +@@ -3831,7 +4262,8 @@ SQLITE_API const void *SQLITE_STDCALL sqlite3_column_decltype16(sqlite3_stmt*,in
    + ** other than [SQLITE_ROW] before any subsequent invocation of
    + ** sqlite3_step().  Failure to reset the prepared statement using 
    + ** [sqlite3_reset()] would result in an [SQLITE_MISUSE] return from
    +-** sqlite3_step().  But after version 3.6.23.1, sqlite3_step() began
    ++** sqlite3_step().  But after [version 3.6.23.1] ([dateof:3.6.23.1],
    ++** sqlite3_step() began
    + ** calling [sqlite3_reset()] automatically in this circumstance rather
    + ** than returning [SQLITE_MISUSE].  This is not considered a compatibility
    + ** break because any application that ever receives an SQLITE_MISUSE error
    +@@ -3845,12 +4277,13 @@ SQLITE_API const void *SQLITE_STDCALL sqlite3_column_decltype16(sqlite3_stmt*,in
    + ** specific [error codes] that better describes the error.
    + ** We admit that this is a goofy design.  The problem has been fixed
    + ** with the "v2" interface.  If you prepare all of your SQL statements
    +-** using either [sqlite3_prepare_v2()] or [sqlite3_prepare16_v2()] instead
    ++** using [sqlite3_prepare_v3()] or [sqlite3_prepare_v2()]
    ++** or [sqlite3_prepare16_v2()] or [sqlite3_prepare16_v3()] instead
    + ** of the legacy [sqlite3_prepare()] and [sqlite3_prepare16()] interfaces,
    + ** then the more specific [error codes] are returned directly
    +-** by sqlite3_step().  The use of the "v2" interface is recommended.
    ++** by sqlite3_step().  The use of the "vX" interfaces is recommended.
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_step(sqlite3_stmt*);
    ++SQLITE_API int sqlite3_step(sqlite3_stmt*);
    + 
    + /*
    + ** CAPI3REF: Number of columns in a result set
    +@@ -3871,7 +4304,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_step(sqlite3_stmt*);
    + **
    + ** See also: [sqlite3_column_count()]
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_data_count(sqlite3_stmt *pStmt);
    ++SQLITE_API int sqlite3_data_count(sqlite3_stmt *pStmt);
    + 
    + /*
    + ** CAPI3REF: Fundamental Datatypes
    +@@ -3910,6 +4343,28 @@ SQLITE_API int SQLITE_STDCALL sqlite3_data_count(sqlite3_stmt *pStmt);
    + ** KEYWORDS: {column access functions}
    + ** METHOD: sqlite3_stmt
    + **
    ++** <b>Summary:</b>
    ++** <blockquote><table border=0 cellpadding=0 cellspacing=0>
    ++** <tr><td><b>sqlite3_column_blob</b><td>&rarr;<td>BLOB result
    ++** <tr><td><b>sqlite3_column_double</b><td>&rarr;<td>REAL result
    ++** <tr><td><b>sqlite3_column_int</b><td>&rarr;<td>32-bit INTEGER result
    ++** <tr><td><b>sqlite3_column_int64</b><td>&rarr;<td>64-bit INTEGER result
    ++** <tr><td><b>sqlite3_column_text</b><td>&rarr;<td>UTF-8 TEXT result
    ++** <tr><td><b>sqlite3_column_text16</b><td>&rarr;<td>UTF-16 TEXT result
    ++** <tr><td><b>sqlite3_column_value</b><td>&rarr;<td>The result as an 
    ++** [sqlite3_value|unprotected sqlite3_value] object.
    ++** <tr><td>&nbsp;<td>&nbsp;<td>&nbsp;
    ++** <tr><td><b>sqlite3_column_bytes</b><td>&rarr;<td>Size of a BLOB
    ++** or a UTF-8 TEXT result in bytes
    ++** <tr><td><b>sqlite3_column_bytes16&nbsp;&nbsp;</b>
    ++** <td>&rarr;&nbsp;&nbsp;<td>Size of UTF-16
    ++** TEXT in bytes
    ++** <tr><td><b>sqlite3_column_type</b><td>&rarr;<td>Default
    ++** datatype of the result
    ++** </table></blockquote>
    ++**
    ++** <b>Details:</b>
    ++**
    + ** ^These routines return information about a single column of the current
    + ** result row of a query.  ^In every case the first argument is a pointer
    + ** to the [prepared statement] that is being evaluated (the [sqlite3_stmt*]
    +@@ -3931,16 +4386,29 @@ SQLITE_API int SQLITE_STDCALL sqlite3_data_count(sqlite3_stmt *pStmt);
    + ** are called from a different thread while any of these routines
    + ** are pending, then the results are undefined.
    + **
    ++** The first six interfaces (_blob, _double, _int, _int64, _text, and _text16)
    ++** each return the value of a result column in a specific data format.  If
    ++** the result column is not initially in the requested format (for example,
    ++** if the query returns an integer but the sqlite3_column_text() interface
    ++** is used to extract the value) then an automatic type conversion is performed.
    ++**
    + ** ^The sqlite3_column_type() routine returns the
    + ** [SQLITE_INTEGER | datatype code] for the initial data type
    + ** of the result column.  ^The returned value is one of [SQLITE_INTEGER],
    +-** [SQLITE_FLOAT], [SQLITE_TEXT], [SQLITE_BLOB], or [SQLITE_NULL].  The value
    +-** returned by sqlite3_column_type() is only meaningful if no type
    +-** conversions have occurred as described below.  After a type conversion,
    +-** the value returned by sqlite3_column_type() is undefined.  Future
    ++** [SQLITE_FLOAT], [SQLITE_TEXT], [SQLITE_BLOB], or [SQLITE_NULL].
    ++** The return value of sqlite3_column_type() can be used to decide which
    ++** of the first six interface should be used to extract the column value.
    ++** The value returned by sqlite3_column_type() is only meaningful if no
    ++** automatic type conversions have occurred for the value in question.  
    ++** After a type conversion, the result of calling sqlite3_column_type()
    ++** is undefined, though harmless.  Future
    + ** versions of SQLite may change the behavior of sqlite3_column_type()
    + ** following a type conversion.
    + **
    ++** If the result is a BLOB or a TEXT string, then the sqlite3_column_bytes()
    ++** or sqlite3_column_bytes16() interfaces can be used to determine the size
    ++** of that BLOB or string.
    ++**
    + ** ^If the result is a BLOB or UTF-8 string then the sqlite3_column_bytes()
    + ** routine returns the number of bytes in that BLOB or string.
    + ** ^If the result is a UTF-16 string, then sqlite3_column_bytes() converts
    +@@ -3977,9 +4445,13 @@ SQLITE_API int SQLITE_STDCALL sqlite3_data_count(sqlite3_stmt *pStmt);
    + ** [sqlite3_column_value()] is used in any other way, including calls
    + ** to routines like [sqlite3_value_int()], [sqlite3_value_text()],
    + ** or [sqlite3_value_bytes()], the behavior is not threadsafe.
    ++** Hence, the sqlite3_column_value() interface
    ++** is normally only useful within the implementation of 
    ++** [application-defined SQL functions] or [virtual tables], not within
    ++** top-level application code.
    + **
    +-** These routines attempt to convert the value where appropriate.  ^For
    +-** example, if the internal representation is FLOAT and a text result
    ++** The these routines may attempt to convert the datatype of the result.
    ++** ^For example, if the internal representation is FLOAT and a text result
    + ** is requested, [sqlite3_snprintf()] is used internally to perform the
    + ** conversion automatically.  ^(The following table details the conversions
    + ** that are applied:
    +@@ -4051,7 +4523,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_data_count(sqlite3_stmt *pStmt);
    + ** ^The pointers returned are valid until a type conversion occurs as
    + ** described above, or until [sqlite3_step()] or [sqlite3_reset()] or
    + ** [sqlite3_finalize()] is called.  ^The memory space used to hold strings
    +-** and BLOBs is freed automatically.  Do <em>not</em> pass the pointers returned
    ++** and BLOBs is freed automatically.  Do not pass the pointers returned
    + ** from [sqlite3_column_blob()], [sqlite3_column_text()], etc. into
    + ** [sqlite3_free()].
    + **
    +@@ -4061,16 +4533,16 @@ SQLITE_API int SQLITE_STDCALL sqlite3_data_count(sqlite3_stmt *pStmt);
    + ** pointer.  Subsequent calls to [sqlite3_errcode()] will return
    + ** [SQLITE_NOMEM].)^
    + */
    +-SQLITE_API const void *SQLITE_STDCALL sqlite3_column_blob(sqlite3_stmt*, int iCol);
    +-SQLITE_API int SQLITE_STDCALL sqlite3_column_bytes(sqlite3_stmt*, int iCol);
    +-SQLITE_API int SQLITE_STDCALL sqlite3_column_bytes16(sqlite3_stmt*, int iCol);
    +-SQLITE_API double SQLITE_STDCALL sqlite3_column_double(sqlite3_stmt*, int iCol);
    +-SQLITE_API int SQLITE_STDCALL sqlite3_column_int(sqlite3_stmt*, int iCol);
    +-SQLITE_API sqlite3_int64 SQLITE_STDCALL sqlite3_column_int64(sqlite3_stmt*, int iCol);
    +-SQLITE_API const unsigned char *SQLITE_STDCALL sqlite3_column_text(sqlite3_stmt*, int iCol);
    +-SQLITE_API const void *SQLITE_STDCALL sqlite3_column_text16(sqlite3_stmt*, int iCol);
    +-SQLITE_API int SQLITE_STDCALL sqlite3_column_type(sqlite3_stmt*, int iCol);
    +-SQLITE_API sqlite3_value *SQLITE_STDCALL sqlite3_column_value(sqlite3_stmt*, int iCol);
    ++SQLITE_API const void *sqlite3_column_blob(sqlite3_stmt*, int iCol);
    ++SQLITE_API double sqlite3_column_double(sqlite3_stmt*, int iCol);
    ++SQLITE_API int sqlite3_column_int(sqlite3_stmt*, int iCol);
    ++SQLITE_API sqlite3_int64 sqlite3_column_int64(sqlite3_stmt*, int iCol);
    ++SQLITE_API const unsigned char *sqlite3_column_text(sqlite3_stmt*, int iCol);
    ++SQLITE_API const void *sqlite3_column_text16(sqlite3_stmt*, int iCol);
    ++SQLITE_API sqlite3_value *sqlite3_column_value(sqlite3_stmt*, int iCol);
    ++SQLITE_API int sqlite3_column_bytes(sqlite3_stmt*, int iCol);
    ++SQLITE_API int sqlite3_column_bytes16(sqlite3_stmt*, int iCol);
    ++SQLITE_API int sqlite3_column_type(sqlite3_stmt*, int iCol);
    + 
    + /*
    + ** CAPI3REF: Destroy A Prepared Statement Object
    +@@ -4098,7 +4570,7 @@ SQLITE_API sqlite3_value *SQLITE_STDCALL sqlite3_column_value(sqlite3_stmt*, int
    + ** statement after it has been finalized can result in undefined and
    + ** undesirable behavior such as segfaults and heap corruption.
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_finalize(sqlite3_stmt *pStmt);
    ++SQLITE_API int sqlite3_finalize(sqlite3_stmt *pStmt);
    + 
    + /*
    + ** CAPI3REF: Reset A Prepared Statement Object
    +@@ -4125,7 +4597,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_finalize(sqlite3_stmt *pStmt);
    + ** ^The [sqlite3_reset(S)] interface does not change the values
    + ** of any [sqlite3_bind_blob|bindings] on the [prepared statement] S.
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_reset(sqlite3_stmt *pStmt);
    ++SQLITE_API int sqlite3_reset(sqlite3_stmt *pStmt);
    + 
    + /*
    + ** CAPI3REF: Create Or Redefine SQL Functions
    +@@ -4225,7 +4697,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_reset(sqlite3_stmt *pStmt);
    + ** close the database connection nor finalize or reset the prepared
    + ** statement in which the function is running.
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_create_function(
    ++SQLITE_API int sqlite3_create_function(
    +   sqlite3 *db,
    +   const char *zFunctionName,
    +   int nArg,
    +@@ -4235,7 +4707,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_create_function(
    +   void (*xStep)(sqlite3_context*,int,sqlite3_value**),
    +   void (*xFinal)(sqlite3_context*)
    + );
    +-SQLITE_API int SQLITE_STDCALL sqlite3_create_function16(
    ++SQLITE_API int sqlite3_create_function16(
    +   sqlite3 *db,
    +   const void *zFunctionName,
    +   int nArg,
    +@@ -4245,7 +4717,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_create_function16(
    +   void (*xStep)(sqlite3_context*,int,sqlite3_value**),
    +   void (*xFinal)(sqlite3_context*)
    + );
    +-SQLITE_API int SQLITE_STDCALL sqlite3_create_function_v2(
    ++SQLITE_API int sqlite3_create_function_v2(
    +   sqlite3 *db,
    +   const char *zFunctionName,
    +   int nArg,
    +@@ -4291,12 +4763,12 @@ SQLITE_API int SQLITE_STDCALL sqlite3_create_function_v2(
    + ** these functions, we will not explain what they do.
    + */
    + #ifndef SQLITE_OMIT_DEPRECATED
    +-SQLITE_API SQLITE_DEPRECATED int SQLITE_STDCALL sqlite3_aggregate_count(sqlite3_context*);
    +-SQLITE_API SQLITE_DEPRECATED int SQLITE_STDCALL sqlite3_expired(sqlite3_stmt*);
    +-SQLITE_API SQLITE_DEPRECATED int SQLITE_STDCALL sqlite3_transfer_bindings(sqlite3_stmt*, sqlite3_stmt*);
    +-SQLITE_API SQLITE_DEPRECATED int SQLITE_STDCALL sqlite3_global_recover(void);
    +-SQLITE_API SQLITE_DEPRECATED void SQLITE_STDCALL sqlite3_thread_cleanup(void);
    +-SQLITE_API SQLITE_DEPRECATED int SQLITE_STDCALL sqlite3_memory_alarm(void(*)(void*,sqlite3_int64,int),
    ++SQLITE_API SQLITE_DEPRECATED int sqlite3_aggregate_count(sqlite3_context*);
    ++SQLITE_API SQLITE_DEPRECATED int sqlite3_expired(sqlite3_stmt*);
    ++SQLITE_API SQLITE_DEPRECATED int sqlite3_transfer_bindings(sqlite3_stmt*, sqlite3_stmt*);
    ++SQLITE_API SQLITE_DEPRECATED int sqlite3_global_recover(void);
    ++SQLITE_API SQLITE_DEPRECATED void sqlite3_thread_cleanup(void);
    ++SQLITE_API SQLITE_DEPRECATED int sqlite3_memory_alarm(void(*)(void*,sqlite3_int64,int),
    +                       void*,sqlite3_int64);
    + #endif
    + 
    +@@ -4304,21 +4776,43 @@ SQLITE_API SQLITE_DEPRECATED int SQLITE_STDCALL sqlite3_memory_alarm(void(*)(voi
    + ** CAPI3REF: Obtaining SQL Values
    + ** METHOD: sqlite3_value
    + **
    +-** The C-language implementation of SQL functions and aggregates uses
    +-** this set of interface routines to access the parameter values on
    +-** the function or aggregate.  
    +-**
    +-** The xFunc (for scalar functions) or xStep (for aggregates) parameters
    +-** to [sqlite3_create_function()] and [sqlite3_create_function16()]
    +-** define callbacks that implement the SQL functions and aggregates.
    +-** The 3rd parameter to these callbacks is an array of pointers to
    +-** [protected sqlite3_value] objects.  There is one [sqlite3_value] object for
    +-** each parameter to the SQL function.  These routines are used to
    +-** extract values from the [sqlite3_value] objects.
    ++** <b>Summary:</b>
    ++** <blockquote><table border=0 cellpadding=0 cellspacing=0>
    ++** <tr><td><b>sqlite3_value_blob</b><td>&rarr;<td>BLOB value
    ++** <tr><td><b>sqlite3_value_double</b><td>&rarr;<td>REAL value
    ++** <tr><td><b>sqlite3_value_int</b><td>&rarr;<td>32-bit INTEGER value
    ++** <tr><td><b>sqlite3_value_int64</b><td>&rarr;<td>64-bit INTEGER value
    ++** <tr><td><b>sqlite3_value_pointer</b><td>&rarr;<td>Pointer value
    ++** <tr><td><b>sqlite3_value_text</b><td>&rarr;<td>UTF-8 TEXT value
    ++** <tr><td><b>sqlite3_value_text16</b><td>&rarr;<td>UTF-16 TEXT value in
    ++** the native byteorder
    ++** <tr><td><b>sqlite3_value_text16be</b><td>&rarr;<td>UTF-16be TEXT value
    ++** <tr><td><b>sqlite3_value_text16le</b><td>&rarr;<td>UTF-16le TEXT value
    ++** <tr><td>&nbsp;<td>&nbsp;<td>&nbsp;
    ++** <tr><td><b>sqlite3_value_bytes</b><td>&rarr;<td>Size of a BLOB
    ++** or a UTF-8 TEXT in bytes
    ++** <tr><td><b>sqlite3_value_bytes16&nbsp;&nbsp;</b>
    ++** <td>&rarr;&nbsp;&nbsp;<td>Size of UTF-16
    ++** TEXT in bytes
    ++** <tr><td><b>sqlite3_value_type</b><td>&rarr;<td>Default
    ++** datatype of the value
    ++** <tr><td><b>sqlite3_value_numeric_type&nbsp;&nbsp;</b>
    ++** <td>&rarr;&nbsp;&nbsp;<td>Best numeric datatype of the value
    ++** <tr><td><b>sqlite3_value_nochange&nbsp;&nbsp;</b>
    ++** <td>&rarr;&nbsp;&nbsp;<td>True if the column is unchanged in an UPDATE
    ++** against a virtual table.
    ++** </table></blockquote>
    ++**
    ++** <b>Details:</b>
    ++**
    ++** These routines extract type, size, and content information from
    ++** [protected sqlite3_value] objects.  Protected sqlite3_value objects
    ++** are used to pass parameter information into implementation of
    ++** [application-defined SQL functions] and [virtual tables].
    + **
    + ** These routines work only with [protected sqlite3_value] objects.
    + ** Any attempt to use these routines on an [unprotected sqlite3_value]
    +-** object results in undefined behavior.
    ++** is not threadsafe.
    + **
    + ** ^These routines work just like the corresponding [column access functions]
    + ** except that these routines take a single [protected sqlite3_value] object
    +@@ -4329,6 +4823,24 @@ SQLITE_API SQLITE_DEPRECATED int SQLITE_STDCALL sqlite3_memory_alarm(void(*)(voi
    + ** sqlite3_value_text16be() and sqlite3_value_text16le() interfaces
    + ** extract UTF-16 strings as big-endian and little-endian respectively.
    + **
    ++** ^If [sqlite3_value] object V was initialized 
    ++** using [sqlite3_bind_pointer(S,I,P,X,D)] or [sqlite3_result_pointer(C,P,X,D)]
    ++** and if X and Y are strings that compare equal according to strcmp(X,Y),
    ++** then sqlite3_value_pointer(V,Y) will return the pointer P.  ^Otherwise,
    ++** sqlite3_value_pointer(V,Y) returns a NULL. The sqlite3_bind_pointer() 
    ++** routine is part of the [pointer passing interface] added for SQLite 3.20.0.
    ++**
    ++** ^(The sqlite3_value_type(V) interface returns the
    ++** [SQLITE_INTEGER | datatype code] for the initial datatype of the
    ++** [sqlite3_value] object V. The returned value is one of [SQLITE_INTEGER],
    ++** [SQLITE_FLOAT], [SQLITE_TEXT], [SQLITE_BLOB], or [SQLITE_NULL].)^
    ++** Other interfaces might change the datatype for an sqlite3_value object.
    ++** For example, if the datatype is initially SQLITE_INTEGER and
    ++** sqlite3_value_text(V) is called to extract a text value for that
    ++** integer, then subsequent calls to sqlite3_value_type(V) might return
    ++** SQLITE_TEXT.  Whether or not a persistent internal datatype conversion
    ++** occurs is undefined and may change from one release of SQLite to the next.
    ++**
    + ** ^(The sqlite3_value_numeric_type() interface attempts to apply
    + ** numeric affinity to the value.  This means that an attempt is
    + ** made to convert the value to an integer or floating point.  If
    +@@ -4337,6 +4849,19 @@ SQLITE_API SQLITE_DEPRECATED int SQLITE_STDCALL sqlite3_memory_alarm(void(*)(voi
    + ** then the conversion is performed.  Otherwise no conversion occurs.
    + ** The [SQLITE_INTEGER | datatype] after conversion is returned.)^
    + **
    ++** ^Within the [xUpdate] method of a [virtual table], the
    ++** sqlite3_value_nochange(X) interface returns true if and only if
    ++** the column corresponding to X is unchanged by the UPDATE operation
    ++** that the xUpdate method call was invoked to implement and if
    ++** and the prior [xColumn] method call that was invoked to extracted
    ++** the value for that column returned without setting a result (probably
    ++** because it queried [sqlite3_vtab_nochange()] and found that the column
    ++** was unchanging).  ^Within an [xUpdate] method, any value for which
    ++** sqlite3_value_nochange(X) is true will in all other respects appear
    ++** to be a NULL value.  If sqlite3_value_nochange(X) is invoked anywhere other
    ++** than within an [xUpdate] method call for an UPDATE statement, then
    ++** the return value is arbitrary and meaningless.
    ++**
    + ** Please pay particular attention to the fact that the pointer returned
    + ** from [sqlite3_value_blob()], [sqlite3_value_text()], or
    + ** [sqlite3_value_text16()] can be invalidated by a subsequent call to
    +@@ -4346,18 +4871,20 @@ SQLITE_API SQLITE_DEPRECATED int SQLITE_STDCALL sqlite3_memory_alarm(void(*)(voi
    + ** These routines must be called from the same thread as
    + ** the SQL function that supplied the [sqlite3_value*] parameters.
    + */
    +-SQLITE_API const void *SQLITE_STDCALL sqlite3_value_blob(sqlite3_value*);
    +-SQLITE_API int SQLITE_STDCALL sqlite3_value_bytes(sqlite3_value*);
    +-SQLITE_API int SQLITE_STDCALL sqlite3_value_bytes16(sqlite3_value*);
    +-SQLITE_API double SQLITE_STDCALL sqlite3_value_double(sqlite3_value*);
    +-SQLITE_API int SQLITE_STDCALL sqlite3_value_int(sqlite3_value*);
    +-SQLITE_API sqlite3_int64 SQLITE_STDCALL sqlite3_value_int64(sqlite3_value*);
    +-SQLITE_API const unsigned char *SQLITE_STDCALL sqlite3_value_text(sqlite3_value*);
    +-SQLITE_API const void *SQLITE_STDCALL sqlite3_value_text16(sqlite3_value*);
    +-SQLITE_API const void *SQLITE_STDCALL sqlite3_value_text16le(sqlite3_value*);
    +-SQLITE_API const void *SQLITE_STDCALL sqlite3_value_text16be(sqlite3_value*);
    +-SQLITE_API int SQLITE_STDCALL sqlite3_value_type(sqlite3_value*);
    +-SQLITE_API int SQLITE_STDCALL sqlite3_value_numeric_type(sqlite3_value*);
    ++SQLITE_API const void *sqlite3_value_blob(sqlite3_value*);
    ++SQLITE_API double sqlite3_value_double(sqlite3_value*);
    ++SQLITE_API int sqlite3_value_int(sqlite3_value*);
    ++SQLITE_API sqlite3_int64 sqlite3_value_int64(sqlite3_value*);
    ++SQLITE_API void *sqlite3_value_pointer(sqlite3_value*, const char*);
    ++SQLITE_API const unsigned char *sqlite3_value_text(sqlite3_value*);
    ++SQLITE_API const void *sqlite3_value_text16(sqlite3_value*);
    ++SQLITE_API const void *sqlite3_value_text16le(sqlite3_value*);
    ++SQLITE_API const void *sqlite3_value_text16be(sqlite3_value*);
    ++SQLITE_API int sqlite3_value_bytes(sqlite3_value*);
    ++SQLITE_API int sqlite3_value_bytes16(sqlite3_value*);
    ++SQLITE_API int sqlite3_value_type(sqlite3_value*);
    ++SQLITE_API int sqlite3_value_numeric_type(sqlite3_value*);
    ++SQLITE_API int sqlite3_value_nochange(sqlite3_value*);
    + 
    + /*
    + ** CAPI3REF: Finding The Subtype Of SQL Values
    +@@ -4368,12 +4895,8 @@ SQLITE_API int SQLITE_STDCALL sqlite3_value_numeric_type(sqlite3_value*);
    + ** information can be used to pass a limited amount of context from
    + ** one SQL function to another.  Use the [sqlite3_result_subtype()]
    + ** routine to set the subtype for the return value of an SQL function.
    +-**
    +-** SQLite makes no use of subtype itself.  It merely passes the subtype
    +-** from the result of one [application-defined SQL function] into the
    +-** input of another.
    + */
    +-SQLITE_API unsigned int SQLITE_STDCALL sqlite3_value_subtype(sqlite3_value*);
    ++SQLITE_API unsigned int sqlite3_value_subtype(sqlite3_value*);
    + 
    + /*
    + ** CAPI3REF: Copy And Free SQL Values
    +@@ -4389,8 +4912,8 @@ SQLITE_API unsigned int SQLITE_STDCALL sqlite3_value_subtype(sqlite3_value*);
    + ** previously obtained from [sqlite3_value_dup()].  ^If V is a NULL pointer
    + ** then sqlite3_value_free(V) is a harmless no-op.
    + */
    +-SQLITE_API SQLITE_EXPERIMENTAL sqlite3_value *SQLITE_STDCALL sqlite3_value_dup(const sqlite3_value*);
    +-SQLITE_API SQLITE_EXPERIMENTAL void SQLITE_STDCALL sqlite3_value_free(sqlite3_value*);
    ++SQLITE_API sqlite3_value *sqlite3_value_dup(const sqlite3_value*);
    ++SQLITE_API void sqlite3_value_free(sqlite3_value*);
    + 
    + /*
    + ** CAPI3REF: Obtain Aggregate Function Context
    +@@ -4435,7 +4958,7 @@ SQLITE_API SQLITE_EXPERIMENTAL void SQLITE_STDCALL sqlite3_value_free(sqlite3_va
    + ** This routine must be called from the same thread in which
    + ** the aggregate SQL function is running.
    + */
    +-SQLITE_API void *SQLITE_STDCALL sqlite3_aggregate_context(sqlite3_context*, int nBytes);
    ++SQLITE_API void *sqlite3_aggregate_context(sqlite3_context*, int nBytes);
    + 
    + /*
    + ** CAPI3REF: User Data For Functions
    +@@ -4450,7 +4973,7 @@ SQLITE_API void *SQLITE_STDCALL sqlite3_aggregate_context(sqlite3_context*, int
    + ** This routine must be called from the same thread in which
    + ** the application-defined function is running.
    + */
    +-SQLITE_API void *SQLITE_STDCALL sqlite3_user_data(sqlite3_context*);
    ++SQLITE_API void *sqlite3_user_data(sqlite3_context*);
    + 
    + /*
    + ** CAPI3REF: Database Connection For Functions
    +@@ -4462,7 +4985,7 @@ SQLITE_API void *SQLITE_STDCALL sqlite3_user_data(sqlite3_context*);
    + ** and [sqlite3_create_function16()] routines that originally
    + ** registered the application defined function.
    + */
    +-SQLITE_API sqlite3 *SQLITE_STDCALL sqlite3_context_db_handle(sqlite3_context*);
    ++SQLITE_API sqlite3 *sqlite3_context_db_handle(sqlite3_context*);
    + 
    + /*
    + ** CAPI3REF: Function Auxiliary Data
    +@@ -4479,10 +5002,11 @@ SQLITE_API sqlite3 *SQLITE_STDCALL sqlite3_context_db_handle(sqlite3_context*);
    + ** the compiled regular expression can be reused on multiple
    + ** invocations of the same function.
    + **
    +-** ^The sqlite3_get_auxdata() interface returns a pointer to the metadata
    +-** associated by the sqlite3_set_auxdata() function with the Nth argument
    +-** value to the application-defined function. ^If there is no metadata
    +-** associated with the function argument, this sqlite3_get_auxdata() interface
    ++** ^The sqlite3_get_auxdata(C,N) interface returns a pointer to the metadata
    ++** associated by the sqlite3_set_auxdata(C,N,P,X) function with the Nth argument
    ++** value to the application-defined function.  ^N is zero for the left-most
    ++** function argument.  ^If there is no metadata
    ++** associated with the function argument, the sqlite3_get_auxdata(C,N) interface
    + ** returns a NULL pointer.
    + **
    + ** ^The sqlite3_set_auxdata(C,N,P,X) interface saves P as metadata for the N-th
    +@@ -4494,12 +5018,13 @@ SQLITE_API sqlite3 *SQLITE_STDCALL sqlite3_context_db_handle(sqlite3_context*);
    + ** SQLite will invoke the destructor function X with parameter P exactly
    + ** once, when the metadata is discarded.
    + ** SQLite is free to discard the metadata at any time, including: <ul>
    +-** <li> when the corresponding function parameter changes, or
    +-** <li> when [sqlite3_reset()] or [sqlite3_finalize()] is called for the
    +-**      SQL statement, or
    +-** <li> when sqlite3_set_auxdata() is invoked again on the same parameter, or
    +-** <li> during the original sqlite3_set_auxdata() call when a memory 
    +-**      allocation error occurs. </ul>)^
    ++** <li> ^(when the corresponding function parameter changes)^, or
    ++** <li> ^(when [sqlite3_reset()] or [sqlite3_finalize()] is called for the
    ++**      SQL statement)^, or
    ++** <li> ^(when sqlite3_set_auxdata() is invoked again on the same
    ++**       parameter)^, or
    ++** <li> ^(during the original sqlite3_set_auxdata() call when a memory 
    ++**      allocation error occurs.)^ </ul>
    + **
    + ** Note the last bullet in particular.  The destructor X in 
    + ** sqlite3_set_auxdata(C,N,P,X) might be called immediately, before the
    +@@ -4512,11 +5037,15 @@ SQLITE_API sqlite3 *SQLITE_STDCALL sqlite3_context_db_handle(sqlite3_context*);
    + ** function parameters that are compile-time constants, including literal
    + ** values and [parameters] and expressions composed from the same.)^
    + **
    ++** The value of the N parameter to these interfaces should be non-negative.
    ++** Future enhancements may make use of negative N values to define new
    ++** kinds of function caching behavior.
    ++**
    + ** These routines must be called from the same thread in which
    + ** the SQL function is running.
    + */
    +-SQLITE_API void *SQLITE_STDCALL sqlite3_get_auxdata(sqlite3_context*, int N);
    +-SQLITE_API void SQLITE_STDCALL sqlite3_set_auxdata(sqlite3_context*, int N, void*, void (*)(void*));
    ++SQLITE_API void *sqlite3_get_auxdata(sqlite3_context*, int N);
    ++SQLITE_API void sqlite3_set_auxdata(sqlite3_context*, int N, void*, void (*)(void*));
    + 
    + 
    + /*
    +@@ -4635,7 +5164,7 @@ typedef void (*sqlite3_destructor_type)(void*);
    + ** when it has finished using that result.
    + ** ^If the 4th parameter to the sqlite3_result_text* interfaces
    + ** or sqlite3_result_blob is the special constant SQLITE_TRANSIENT
    +-** then SQLite makes a copy of the result into space obtained from
    ++** then SQLite makes a copy of the result into space obtained
    + ** from [sqlite3_malloc()] before it returns.
    + **
    + ** ^The sqlite3_result_value() interface sets the result of
    +@@ -4648,31 +5177,43 @@ typedef void (*sqlite3_destructor_type)(void*);
    + ** [unprotected sqlite3_value] object is required, so either
    + ** kind of [sqlite3_value] object can be used with this interface.
    + **
    ++** ^The sqlite3_result_pointer(C,P,T,D) interface sets the result to an
    ++** SQL NULL value, just like [sqlite3_result_null(C)], except that it
    ++** also associates the host-language pointer P or type T with that 
    ++** NULL value such that the pointer can be retrieved within an
    ++** [application-defined SQL function] using [sqlite3_value_pointer()].
    ++** ^If the D parameter is not NULL, then it is a pointer to a destructor
    ++** for the P parameter.  ^SQLite invokes D with P as its only argument
    ++** when SQLite is finished with P.  The T parameter should be a static
    ++** string and preferably a string literal. The sqlite3_result_pointer()
    ++** routine is part of the [pointer passing interface] added for SQLite 3.20.0.
    ++**
    + ** If these routines are called from within the different thread
    + ** than the one containing the application-defined function that received
    + ** the [sqlite3_context] pointer, the results are undefined.
    + */
    +-SQLITE_API void SQLITE_STDCALL sqlite3_result_blob(sqlite3_context*, const void*, int, void(*)(void*));
    +-SQLITE_API void SQLITE_STDCALL sqlite3_result_blob64(sqlite3_context*,const void*,
    ++SQLITE_API void sqlite3_result_blob(sqlite3_context*, const void*, int, void(*)(void*));
    ++SQLITE_API void sqlite3_result_blob64(sqlite3_context*,const void*,
    +                            sqlite3_uint64,void(*)(void*));
    +-SQLITE_API void SQLITE_STDCALL sqlite3_result_double(sqlite3_context*, double);
    +-SQLITE_API void SQLITE_STDCALL sqlite3_result_error(sqlite3_context*, const char*, int);
    +-SQLITE_API void SQLITE_STDCALL sqlite3_result_error16(sqlite3_context*, const void*, int);
    +-SQLITE_API void SQLITE_STDCALL sqlite3_result_error_toobig(sqlite3_context*);
    +-SQLITE_API void SQLITE_STDCALL sqlite3_result_error_nomem(sqlite3_context*);
    +-SQLITE_API void SQLITE_STDCALL sqlite3_result_error_code(sqlite3_context*, int);
    +-SQLITE_API void SQLITE_STDCALL sqlite3_result_int(sqlite3_context*, int);
    +-SQLITE_API void SQLITE_STDCALL sqlite3_result_int64(sqlite3_context*, sqlite3_int64);
    +-SQLITE_API void SQLITE_STDCALL sqlite3_result_null(sqlite3_context*);
    +-SQLITE_API void SQLITE_STDCALL sqlite3_result_text(sqlite3_context*, const char*, int, void(*)(void*));
    +-SQLITE_API void SQLITE_STDCALL sqlite3_result_text64(sqlite3_context*, const char*,sqlite3_uint64,
    ++SQLITE_API void sqlite3_result_double(sqlite3_context*, double);
    ++SQLITE_API void sqlite3_result_error(sqlite3_context*, const char*, int);
    ++SQLITE_API void sqlite3_result_error16(sqlite3_context*, const void*, int);
    ++SQLITE_API void sqlite3_result_error_toobig(sqlite3_context*);
    ++SQLITE_API void sqlite3_result_error_nomem(sqlite3_context*);
    ++SQLITE_API void sqlite3_result_error_code(sqlite3_context*, int);
    ++SQLITE_API void sqlite3_result_int(sqlite3_context*, int);
    ++SQLITE_API void sqlite3_result_int64(sqlite3_context*, sqlite3_int64);
    ++SQLITE_API void sqlite3_result_null(sqlite3_context*);
    ++SQLITE_API void sqlite3_result_text(sqlite3_context*, const char*, int, void(*)(void*));
    ++SQLITE_API void sqlite3_result_text64(sqlite3_context*, const char*,sqlite3_uint64,
    +                            void(*)(void*), unsigned char encoding);
    +-SQLITE_API void SQLITE_STDCALL sqlite3_result_text16(sqlite3_context*, const void*, int, void(*)(void*));
    +-SQLITE_API void SQLITE_STDCALL sqlite3_result_text16le(sqlite3_context*, const void*, int,void(*)(void*));
    +-SQLITE_API void SQLITE_STDCALL sqlite3_result_text16be(sqlite3_context*, const void*, int,void(*)(void*));
    +-SQLITE_API void SQLITE_STDCALL sqlite3_result_value(sqlite3_context*, sqlite3_value*);
    +-SQLITE_API void SQLITE_STDCALL sqlite3_result_zeroblob(sqlite3_context*, int n);
    +-SQLITE_API int SQLITE_STDCALL sqlite3_result_zeroblob64(sqlite3_context*, sqlite3_uint64 n);
    ++SQLITE_API void sqlite3_result_text16(sqlite3_context*, const void*, int, void(*)(void*));
    ++SQLITE_API void sqlite3_result_text16le(sqlite3_context*, const void*, int,void(*)(void*));
    ++SQLITE_API void sqlite3_result_text16be(sqlite3_context*, const void*, int,void(*)(void*));
    ++SQLITE_API void sqlite3_result_value(sqlite3_context*, sqlite3_value*);
    ++SQLITE_API void sqlite3_result_pointer(sqlite3_context*, void*,const char*,void(*)(void*));
    ++SQLITE_API void sqlite3_result_zeroblob(sqlite3_context*, int n);
    ++SQLITE_API int sqlite3_result_zeroblob64(sqlite3_context*, sqlite3_uint64 n);
    + 
    + 
    + /*
    +@@ -4687,7 +5228,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_result_zeroblob64(sqlite3_context*, sqlite
    + ** The number of subtype bytes preserved by SQLite might increase
    + ** in future releases of SQLite.
    + */
    +-SQLITE_API void SQLITE_STDCALL sqlite3_result_subtype(sqlite3_context*,unsigned int);
    ++SQLITE_API void sqlite3_result_subtype(sqlite3_context*,unsigned int);
    + 
    + /*
    + ** CAPI3REF: Define New Collating Sequences
    +@@ -4769,14 +5310,14 @@ SQLITE_API void SQLITE_STDCALL sqlite3_result_subtype(sqlite3_context*,unsigned
    + **
    + ** See also:  [sqlite3_collation_needed()] and [sqlite3_collation_needed16()].
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_create_collation(
    ++SQLITE_API int sqlite3_create_collation(
    +   sqlite3*, 
    +   const char *zName, 
    +   int eTextRep, 
    +   void *pArg,
    +   int(*xCompare)(void*,int,const void*,int,const void*)
    + );
    +-SQLITE_API int SQLITE_STDCALL sqlite3_create_collation_v2(
    ++SQLITE_API int sqlite3_create_collation_v2(
    +   sqlite3*, 
    +   const char *zName, 
    +   int eTextRep, 
    +@@ -4784,7 +5325,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_create_collation_v2(
    +   int(*xCompare)(void*,int,const void*,int,const void*),
    +   void(*xDestroy)(void*)
    + );
    +-SQLITE_API int SQLITE_STDCALL sqlite3_create_collation16(
    ++SQLITE_API int sqlite3_create_collation16(
    +   sqlite3*, 
    +   const void *zName,
    +   int eTextRep, 
    +@@ -4819,12 +5360,12 @@ SQLITE_API int SQLITE_STDCALL sqlite3_create_collation16(
    + ** [sqlite3_create_collation()], [sqlite3_create_collation16()], or
    + ** [sqlite3_create_collation_v2()].
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_collation_needed(
    ++SQLITE_API int sqlite3_collation_needed(
    +   sqlite3*, 
    +   void*, 
    +   void(*)(void*,sqlite3*,int eTextRep,const char*)
    + );
    +-SQLITE_API int SQLITE_STDCALL sqlite3_collation_needed16(
    ++SQLITE_API int sqlite3_collation_needed16(
    +   sqlite3*, 
    +   void*,
    +   void(*)(void*,sqlite3*,int eTextRep,const void*)
    +@@ -4838,11 +5379,11 @@ SQLITE_API int SQLITE_STDCALL sqlite3_collation_needed16(
    + ** The code to implement this API is not available in the public release
    + ** of SQLite.
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_key(
    ++SQLITE_API int sqlite3_key(
    +   sqlite3 *db,                   /* Database to be rekeyed */
    +   const void *pKey, int nKey     /* The key */
    + );
    +-SQLITE_API int SQLITE_STDCALL sqlite3_key_v2(
    ++SQLITE_API int sqlite3_key_v2(
    +   sqlite3 *db,                   /* Database to be rekeyed */
    +   const char *zDbName,           /* Name of the database */
    +   const void *pKey, int nKey     /* The key */
    +@@ -4856,11 +5397,11 @@ SQLITE_API int SQLITE_STDCALL sqlite3_key_v2(
    + ** The code to implement this API is not available in the public release
    + ** of SQLite.
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_rekey(
    ++SQLITE_API int sqlite3_rekey(
    +   sqlite3 *db,                   /* Database to be rekeyed */
    +   const void *pKey, int nKey     /* The new key */
    + );
    +-SQLITE_API int SQLITE_STDCALL sqlite3_rekey_v2(
    ++SQLITE_API int sqlite3_rekey_v2(
    +   sqlite3 *db,                   /* Database to be rekeyed */
    +   const char *zDbName,           /* Name of the database */
    +   const void *pKey, int nKey     /* The new key */
    +@@ -4870,7 +5411,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_rekey_v2(
    + ** Specify the activation key for a SEE database.  Unless 
    + ** activated, none of the SEE routines will work.
    + */
    +-SQLITE_API void SQLITE_STDCALL sqlite3_activate_see(
    ++SQLITE_API void sqlite3_activate_see(
    +   const char *zPassPhrase        /* Activation phrase */
    + );
    + #endif
    +@@ -4880,7 +5421,7 @@ SQLITE_API void SQLITE_STDCALL sqlite3_activate_see(
    + ** Specify the activation key for a CEROD database.  Unless 
    + ** activated, none of the CEROD routines will work.
    + */
    +-SQLITE_API void SQLITE_STDCALL sqlite3_activate_cerod(
    ++SQLITE_API void sqlite3_activate_cerod(
    +   const char *zPassPhrase        /* Activation phrase */
    + );
    + #endif
    +@@ -4902,7 +5443,7 @@ SQLITE_API void SQLITE_STDCALL sqlite3_activate_cerod(
    + ** all, then the behavior of sqlite3_sleep() may deviate from the description
    + ** in the previous paragraphs.
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_sleep(int);
    ++SQLITE_API int sqlite3_sleep(int);
    + 
    + /*
    + ** CAPI3REF: Name Of The Folder Holding Temporary Files
    +@@ -5021,7 +5562,7 @@ SQLITE_API SQLITE_EXTERN char *sqlite3_data_directory;
    + ** connection while this routine is running, then the return value
    + ** is undefined.
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_get_autocommit(sqlite3*);
    ++SQLITE_API int sqlite3_get_autocommit(sqlite3*);
    + 
    + /*
    + ** CAPI3REF: Find The Database Handle Of A Prepared Statement
    +@@ -5034,7 +5575,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_get_autocommit(sqlite3*);
    + ** to the [sqlite3_prepare_v2()] call (or its variants) that was used to
    + ** create the statement in the first place.
    + */
    +-SQLITE_API sqlite3 *SQLITE_STDCALL sqlite3_db_handle(sqlite3_stmt*);
    ++SQLITE_API sqlite3 *sqlite3_db_handle(sqlite3_stmt*);
    + 
    + /*
    + ** CAPI3REF: Return The Filename For A Database Connection
    +@@ -5051,7 +5592,7 @@ SQLITE_API sqlite3 *SQLITE_STDCALL sqlite3_db_handle(sqlite3_stmt*);
    + ** will be an absolute pathname, even if the filename used
    + ** to open the database originally was a URI or relative pathname.
    + */
    +-SQLITE_API const char *SQLITE_STDCALL sqlite3_db_filename(sqlite3 *db, const char *zDbName);
    ++SQLITE_API const char *sqlite3_db_filename(sqlite3 *db, const char *zDbName);
    + 
    + /*
    + ** CAPI3REF: Determine if a database is read-only
    +@@ -5061,7 +5602,7 @@ SQLITE_API const char *SQLITE_STDCALL sqlite3_db_filename(sqlite3 *db, const cha
    + ** of connection D is read-only, 0 if it is read/write, or -1 if N is not
    + ** the name of a database on connection D.
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_db_readonly(sqlite3 *db, const char *zDbName);
    ++SQLITE_API int sqlite3_db_readonly(sqlite3 *db, const char *zDbName);
    + 
    + /*
    + ** CAPI3REF: Find the next prepared statement
    +@@ -5077,7 +5618,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_db_readonly(sqlite3 *db, const char *zDbNa
    + ** [sqlite3_next_stmt(D,S)] must refer to an open database
    + ** connection and in particular must not be a NULL pointer.
    + */
    +-SQLITE_API sqlite3_stmt *SQLITE_STDCALL sqlite3_next_stmt(sqlite3 *pDb, sqlite3_stmt *pStmt);
    ++SQLITE_API sqlite3_stmt *sqlite3_next_stmt(sqlite3 *pDb, sqlite3_stmt *pStmt);
    + 
    + /*
    + ** CAPI3REF: Commit And Rollback Notification Callbacks
    +@@ -5126,8 +5667,8 @@ SQLITE_API sqlite3_stmt *SQLITE_STDCALL sqlite3_next_stmt(sqlite3 *pDb, sqlite3_
    + **
    + ** See also the [sqlite3_update_hook()] interface.
    + */
    +-SQLITE_API void *SQLITE_STDCALL sqlite3_commit_hook(sqlite3*, int(*)(void*), void*);
    +-SQLITE_API void *SQLITE_STDCALL sqlite3_rollback_hook(sqlite3*, void(*)(void *), void*);
    ++SQLITE_API void *sqlite3_commit_hook(sqlite3*, int(*)(void*), void*);
    ++SQLITE_API void *sqlite3_rollback_hook(sqlite3*, void(*)(void *), void*);
    + 
    + /*
    + ** CAPI3REF: Data Change Notification Callbacks
    +@@ -5136,7 +5677,7 @@ SQLITE_API void *SQLITE_STDCALL sqlite3_rollback_hook(sqlite3*, void(*)(void *),
    + ** ^The sqlite3_update_hook() interface registers a callback function
    + ** with the [database connection] identified by the first argument
    + ** to be invoked whenever a row is updated, inserted or deleted in
    +-** a rowid table.
    ++** a [rowid table].
    + ** ^Any callback set by a previous call to this function
    + ** for the same database connection is overridden.
    + **
    +@@ -5157,7 +5698,7 @@ SQLITE_API void *SQLITE_STDCALL sqlite3_rollback_hook(sqlite3*, void(*)(void *),
    + ** ^The update hook is not invoked when [WITHOUT ROWID] tables are modified.
    + **
    + ** ^In the current implementation, the update hook
    +-** is not invoked when duplication rows are deleted because of an
    ++** is not invoked when conflicting rows are deleted because of an
    + ** [ON CONFLICT | ON CONFLICT REPLACE] clause.  ^Nor is the update hook
    + ** invoked when rows are deleted using the [truncate optimization].
    + ** The exceptions defined in this paragraph might change in a future
    +@@ -5175,10 +5716,10 @@ SQLITE_API void *SQLITE_STDCALL sqlite3_rollback_hook(sqlite3*, void(*)(void *),
    + ** on the same [database connection] D, or NULL for
    + ** the first call on D.
    + **
    +-** See also the [sqlite3_commit_hook()] and [sqlite3_rollback_hook()]
    +-** interfaces.
    ++** See also the [sqlite3_commit_hook()], [sqlite3_rollback_hook()],
    ++** and [sqlite3_preupdate_hook()] interfaces.
    + */
    +-SQLITE_API void *SQLITE_STDCALL sqlite3_update_hook(
    ++SQLITE_API void *sqlite3_update_hook(
    +   sqlite3*, 
    +   void(*)(void *,int ,char const *,char const *,sqlite3_int64),
    +   void*
    +@@ -5193,7 +5734,8 @@ SQLITE_API void *SQLITE_STDCALL sqlite3_update_hook(
    + ** and disabled if the argument is false.)^
    + **
    + ** ^Cache sharing is enabled and disabled for an entire process.
    +-** This is a change as of SQLite version 3.5.0. In prior versions of SQLite,
    ++** This is a change as of SQLite [version 3.5.0] ([dateof:3.5.0]). 
    ++** In prior versions of SQLite,
    + ** sharing was enabled or disabled for each thread separately.
    + **
    + ** ^(The cache sharing mode set by this interface effects all subsequent
    +@@ -5218,7 +5760,7 @@ SQLITE_API void *SQLITE_STDCALL sqlite3_update_hook(
    + **
    + ** See Also:  [SQLite Shared-Cache Mode]
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_enable_shared_cache(int);
    ++SQLITE_API int sqlite3_enable_shared_cache(int);
    + 
    + /*
    + ** CAPI3REF: Attempt To Free Heap Memory
    +@@ -5234,7 +5776,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_enable_shared_cache(int);
    + **
    + ** See also: [sqlite3_db_release_memory()]
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_release_memory(int);
    ++SQLITE_API int sqlite3_release_memory(int);
    + 
    + /*
    + ** CAPI3REF: Free Memory Used By A Database Connection
    +@@ -5248,7 +5790,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_release_memory(int);
    + **
    + ** See also: [sqlite3_release_memory()]
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_db_release_memory(sqlite3*);
    ++SQLITE_API int sqlite3_db_release_memory(sqlite3*);
    + 
    + /*
    + ** CAPI3REF: Impose A Limit On Heap Size
    +@@ -5287,7 +5829,8 @@ SQLITE_API int SQLITE_STDCALL sqlite3_db_release_memory(sqlite3*);
    + **      from the heap.
    + ** </ul>)^
    + **
    +-** Beginning with SQLite version 3.7.3, the soft heap limit is enforced
    ++** Beginning with SQLite [version 3.7.3] ([dateof:3.7.3]), 
    ++** the soft heap limit is enforced
    + ** regardless of whether or not the [SQLITE_ENABLE_MEMORY_MANAGEMENT]
    + ** compile-time option is invoked.  With [SQLITE_ENABLE_MEMORY_MANAGEMENT],
    + ** the soft heap limit is enforced on every memory allocation.  Without
    +@@ -5300,7 +5843,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_db_release_memory(sqlite3*);
    + ** The circumstances under which SQLite will enforce the soft heap limit may
    + ** changes in future releases of SQLite.
    + */
    +-SQLITE_API sqlite3_int64 SQLITE_STDCALL sqlite3_soft_heap_limit64(sqlite3_int64 N);
    ++SQLITE_API sqlite3_int64 sqlite3_soft_heap_limit64(sqlite3_int64 N);
    + 
    + /*
    + ** CAPI3REF: Deprecated Soft Heap Limit Interface
    +@@ -5311,7 +5854,7 @@ SQLITE_API sqlite3_int64 SQLITE_STDCALL sqlite3_soft_heap_limit64(sqlite3_int64
    + ** only.  All new applications should use the
    + ** [sqlite3_soft_heap_limit64()] interface rather than this one.
    + */
    +-SQLITE_API SQLITE_DEPRECATED void SQLITE_STDCALL sqlite3_soft_heap_limit(int N);
    ++SQLITE_API SQLITE_DEPRECATED void sqlite3_soft_heap_limit(int N);
    + 
    + 
    + /*
    +@@ -5326,9 +5869,11 @@ SQLITE_API SQLITE_DEPRECATED void SQLITE_STDCALL sqlite3_soft_heap_limit(int N);
    + ** column exists.  ^The sqlite3_table_column_metadata() interface returns
    + ** SQLITE_ERROR and if the specified column does not exist.
    + ** ^If the column-name parameter to sqlite3_table_column_metadata() is a
    +-** NULL pointer, then this routine simply checks for the existance of the
    ++** NULL pointer, then this routine simply checks for the existence of the
    + ** table and returns SQLITE_OK if the table exists and SQLITE_ERROR if it
    +-** does not.
    ++** does not.  If the table name parameter T in a call to
    ++** sqlite3_table_column_metadata(X,D,T,C,...) is NULL then the result is
    ++** undefined behavior.
    + **
    + ** ^The column is identified by the second, third and fourth parameters to
    + ** this function. ^(The second parameter is either the name of the database
    +@@ -5381,7 +5926,7 @@ SQLITE_API SQLITE_DEPRECATED void SQLITE_STDCALL sqlite3_soft_heap_limit(int N);
    + ** parsed, if that has not already been done, and returns an error if
    + ** any errors are encountered while loading the schema.
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_table_column_metadata(
    ++SQLITE_API int sqlite3_table_column_metadata(
    +   sqlite3 *db,                /* Connection handle */
    +   const char *zDbName,        /* Database name or NULL */
    +   const char *zTableName,     /* Table name */
    +@@ -5423,12 +5968,21 @@ SQLITE_API int SQLITE_STDCALL sqlite3_table_column_metadata(
    + ** should free this memory by calling [sqlite3_free()].
    + **
    + ** ^Extension loading must be enabled using
    +-** [sqlite3_enable_load_extension()] prior to calling this API,
    ++** [sqlite3_enable_load_extension()] or
    ++** [sqlite3_db_config](db,[SQLITE_DBCONFIG_ENABLE_LOAD_EXTENSION],1,NULL)
    ++** prior to calling this API,
    + ** otherwise an error will be returned.
    + **
    ++** <b>Security warning:</b> It is recommended that the 
    ++** [SQLITE_DBCONFIG_ENABLE_LOAD_EXTENSION] method be used to enable only this
    ++** interface.  The use of the [sqlite3_enable_load_extension()] interface
    ++** should be avoided.  This will keep the SQL function [load_extension()]
    ++** disabled and prevent SQL injections from giving attackers
    ++** access to extension loading capabilities.
    ++**
    + ** See also the [load_extension() SQL function].
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_load_extension(
    ++SQLITE_API int sqlite3_load_extension(
    +   sqlite3 *db,          /* Load the extension into this database connection */
    +   const char *zFile,    /* Name of the shared library containing extension */
    +   const char *zProc,    /* Entry point.  Derived from zFile if 0 */
    +@@ -5448,8 +6002,19 @@ SQLITE_API int SQLITE_STDCALL sqlite3_load_extension(
    + ** ^Call the sqlite3_enable_load_extension() routine with onoff==1
    + ** to turn extension loading on and call it with onoff==0 to turn
    + ** it back off again.
    ++**
    ++** ^This interface enables or disables both the C-API
    ++** [sqlite3_load_extension()] and the SQL function [load_extension()].
    ++** ^(Use [sqlite3_db_config](db,[SQLITE_DBCONFIG_ENABLE_LOAD_EXTENSION],..)
    ++** to enable or disable only the C-API.)^
    ++**
    ++** <b>Security warning:</b> It is recommended that extension loading
    ++** be disabled using the [SQLITE_DBCONFIG_ENABLE_LOAD_EXTENSION] method
    ++** rather than this interface, so the [load_extension()] SQL function
    ++** remains disabled. This will prevent SQL injections from giving attackers
    ++** access to extension loading capabilities.
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_enable_load_extension(sqlite3 *db, int onoff);
    ++SQLITE_API int sqlite3_enable_load_extension(sqlite3 *db, int onoff);
    + 
    + /*
    + ** CAPI3REF: Automatically Load Statically Linked Extensions
    +@@ -5461,7 +6026,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_enable_load_extension(sqlite3 *db, int ono
    + **
    + ** ^(Even though the function prototype shows that xEntryPoint() takes
    + ** no arguments and returns void, SQLite invokes xEntryPoint() with three
    +-** arguments and expects and integer result as if the signature of the
    ++** arguments and expects an integer result as if the signature of the
    + ** entry point where as follows:
    + **
    + ** <blockquote><pre>
    +@@ -5487,7 +6052,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_enable_load_extension(sqlite3 *db, int ono
    + ** See also: [sqlite3_reset_auto_extension()]
    + ** and [sqlite3_cancel_auto_extension()]
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_auto_extension(void (*xEntryPoint)(void));
    ++SQLITE_API int sqlite3_auto_extension(void(*xEntryPoint)(void));
    + 
    + /*
    + ** CAPI3REF: Cancel Automatic Extension Loading
    +@@ -5499,7 +6064,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_auto_extension(void (*xEntryPoint)(void));
    + ** unregistered and it returns 0 if X was not on the list of initialization
    + ** routines.
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_cancel_auto_extension(void (*xEntryPoint)(void));
    ++SQLITE_API int sqlite3_cancel_auto_extension(void(*xEntryPoint)(void));
    + 
    + /*
    + ** CAPI3REF: Reset Automatic Extension Loading
    +@@ -5507,7 +6072,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_cancel_auto_extension(void (*xEntryPoint)(
    + ** ^This interface disables all automatic extensions previously
    + ** registered using [sqlite3_auto_extension()].
    + */
    +-SQLITE_API void SQLITE_STDCALL sqlite3_reset_auto_extension(void);
    ++SQLITE_API void sqlite3_reset_auto_extension(void);
    + 
    + /*
    + ** The interface to the virtual-table mechanism is currently considered
    +@@ -5609,6 +6174,17 @@ struct sqlite3_module {
    + ** ^Information about the ORDER BY clause is stored in aOrderBy[].
    + ** ^Each term of aOrderBy records a column of the ORDER BY clause.
    + **
    ++** The colUsed field indicates which columns of the virtual table may be
    ++** required by the current scan. Virtual table columns are numbered from
    ++** zero in the order in which they appear within the CREATE TABLE statement
    ++** passed to sqlite3_declare_vtab(). For the first 63 columns (columns 0-62),
    ++** the corresponding bit is set within the colUsed mask if the column may be
    ++** required by SQLite. If the table has at least 64 columns and any column
    ++** to the right of the first 63 is required, then bit 63 of colUsed is also
    ++** set. In other words, column iCol may be required if the expression
    ++** (colUsed & ((sqlite3_uint64)1 << (iCol>=63 ? 63 : iCol))) evaluates to 
    ++** non-zero.
    ++**
    + ** The [xBestIndex] method must fill aConstraintUsage[] with information
    + ** about what parameters to pass to xFilter.  ^If argvIndex>0 then
    + ** the right-hand side of the corresponding aConstraint[] is evaluated
    +@@ -5650,13 +6226,15 @@ struct sqlite3_module {
    + ** the xUpdate method are automatically rolled back by SQLite.
    + **
    + ** IMPORTANT: The estimatedRows field was added to the sqlite3_index_info
    +-** structure for SQLite version 3.8.2. If a virtual table extension is
    ++** structure for SQLite [version 3.8.2] ([dateof:3.8.2]). 
    ++** If a virtual table extension is
    + ** used with an SQLite version earlier than 3.8.2, the results of attempting 
    + ** to read or write the estimatedRows field are undefined (but are likely 
    + ** to included crashing the application). The estimatedRows field should
    + ** therefore only be used if [sqlite3_libversion_number()] returns a
    + ** value greater than or equal to 3008002. Similarly, the idxFlags field
    +-** was added for version 3.9.0. It may therefore only be used if
    ++** was added for [version 3.9.0] ([dateof:3.9.0]). 
    ++** It may therefore only be used if
    + ** sqlite3_libversion_number() returns a value greater than or equal to
    + ** 3009000.
    + */
    +@@ -5664,7 +6242,7 @@ struct sqlite3_index_info {
    +   /* Inputs */
    +   int nConstraint;           /* Number of entries in aConstraint */
    +   struct sqlite3_index_constraint {
    +-     int iColumn;              /* Column on left-hand side of constraint */
    ++     int iColumn;              /* Column constrained.  -1 for ROWID */
    +      unsigned char op;         /* Constraint operator */
    +      unsigned char usable;     /* True if this constraint is usable */
    +      int iTermOffset;          /* Used internally - xBestIndex should ignore */
    +@@ -5688,6 +6266,8 @@ struct sqlite3_index_info {
    +   sqlite3_int64 estimatedRows;    /* Estimated number of rows returned */
    +   /* Fields below are only available in SQLite 3.9.0 and later */
    +   int idxFlags;              /* Mask of SQLITE_INDEX_SCAN_* flags */
    ++  /* Fields below are only available in SQLite 3.10.0 and later */
    ++  sqlite3_uint64 colUsed;    /* Input: Mask of columns used by statement */
    + };
    + 
    + /*
    +@@ -5703,12 +6283,20 @@ struct sqlite3_index_info {
    + ** an operator that is part of a constraint term in the wHERE clause of
    + ** a query that uses a [virtual table].
    + */
    +-#define SQLITE_INDEX_CONSTRAINT_EQ    2
    +-#define SQLITE_INDEX_CONSTRAINT_GT    4
    +-#define SQLITE_INDEX_CONSTRAINT_LE    8
    +-#define SQLITE_INDEX_CONSTRAINT_LT    16
    +-#define SQLITE_INDEX_CONSTRAINT_GE    32
    +-#define SQLITE_INDEX_CONSTRAINT_MATCH 64
    ++#define SQLITE_INDEX_CONSTRAINT_EQ         2
    ++#define SQLITE_INDEX_CONSTRAINT_GT         4
    ++#define SQLITE_INDEX_CONSTRAINT_LE         8
    ++#define SQLITE_INDEX_CONSTRAINT_LT        16
    ++#define SQLITE_INDEX_CONSTRAINT_GE        32
    ++#define SQLITE_INDEX_CONSTRAINT_MATCH     64
    ++#define SQLITE_INDEX_CONSTRAINT_LIKE      65
    ++#define SQLITE_INDEX_CONSTRAINT_GLOB      66
    ++#define SQLITE_INDEX_CONSTRAINT_REGEXP    67
    ++#define SQLITE_INDEX_CONSTRAINT_NE        68
    ++#define SQLITE_INDEX_CONSTRAINT_ISNOT     69
    ++#define SQLITE_INDEX_CONSTRAINT_ISNOTNULL 70
    ++#define SQLITE_INDEX_CONSTRAINT_ISNULL    71
    ++#define SQLITE_INDEX_CONSTRAINT_IS        72
    + 
    + /*
    + ** CAPI3REF: Register A Virtual Table Implementation
    +@@ -5736,13 +6324,13 @@ struct sqlite3_index_info {
    + ** interface is equivalent to sqlite3_create_module_v2() with a NULL
    + ** destructor.
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_create_module(
    ++SQLITE_API int sqlite3_create_module(
    +   sqlite3 *db,               /* SQLite connection to register module with */
    +   const char *zName,         /* Name of the module */
    +   const sqlite3_module *p,   /* Methods for the module */
    +   void *pClientData          /* Client data for xCreate/xConnect */
    + );
    +-SQLITE_API int SQLITE_STDCALL sqlite3_create_module_v2(
    ++SQLITE_API int sqlite3_create_module_v2(
    +   sqlite3 *db,               /* SQLite connection to register module with */
    +   const char *zName,         /* Name of the module */
    +   const sqlite3_module *p,   /* Methods for the module */
    +@@ -5805,7 +6393,7 @@ struct sqlite3_vtab_cursor {
    + ** to declare the format (the names and datatypes of the columns) of
    + ** the virtual tables they implement.
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_declare_vtab(sqlite3*, const char *zSQL);
    ++SQLITE_API int sqlite3_declare_vtab(sqlite3*, const char *zSQL);
    + 
    + /*
    + ** CAPI3REF: Overload A Function For A Virtual Table
    +@@ -5824,7 +6412,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_declare_vtab(sqlite3*, const char *zSQL);
    + ** purpose is to be a placeholder function that can be overloaded
    + ** by a [virtual table].
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_overload_function(sqlite3*, const char *zFuncName, int nArg);
    ++SQLITE_API int sqlite3_overload_function(sqlite3*, const char *zFuncName, int nArg);
    + 
    + /*
    + ** The interface to the virtual-table mechanism defined above (back up
    +@@ -5899,6 +6487,12 @@ typedef struct sqlite3_blob sqlite3_blob;
    + ** [database connection] error code and message accessible via 
    + ** [sqlite3_errcode()] and [sqlite3_errmsg()] and related functions. 
    + **
    ++** A BLOB referenced by sqlite3_blob_open() may be read using the
    ++** [sqlite3_blob_read()] interface and modified by using
    ++** [sqlite3_blob_write()].  The [BLOB handle] can be moved to a
    ++** different row of the same table using the [sqlite3_blob_reopen()]
    ++** interface.  However, the column, table, or database of a [BLOB handle]
    ++** cannot be changed after the [BLOB handle] is opened.
    + **
    + ** ^(If the row that a BLOB handle points to is modified by an
    + ** [UPDATE], [DELETE], or by [ON CONFLICT] side-effects
    +@@ -5922,8 +6516,12 @@ typedef struct sqlite3_blob sqlite3_blob;
    + **
    + ** To avoid a resource leak, every open [BLOB handle] should eventually
    + ** be released by a call to [sqlite3_blob_close()].
    ++**
    ++** See also: [sqlite3_blob_close()],
    ++** [sqlite3_blob_reopen()], [sqlite3_blob_read()],
    ++** [sqlite3_blob_bytes()], [sqlite3_blob_write()].
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_blob_open(
    ++SQLITE_API int sqlite3_blob_open(
    +   sqlite3*,
    +   const char *zDb,
    +   const char *zTable,
    +@@ -5937,11 +6535,11 @@ SQLITE_API int SQLITE_STDCALL sqlite3_blob_open(
    + ** CAPI3REF: Move a BLOB Handle to a New Row
    + ** METHOD: sqlite3_blob
    + **
    +-** ^This function is used to move an existing blob handle so that it points
    ++** ^This function is used to move an existing [BLOB handle] so that it points
    + ** to a different row of the same database table. ^The new row is identified
    + ** by the rowid value passed as the second argument. Only the row can be
    + ** changed. ^The database, table and column on which the blob handle is open
    +-** remain the same. Moving an existing blob handle to a new row can be
    ++** remain the same. Moving an existing [BLOB handle] to a new row is
    + ** faster than closing the existing handle and opening a new one.
    + **
    + ** ^(The new row must meet the same criteria as for [sqlite3_blob_open()] -
    +@@ -5956,7 +6554,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_blob_open(
    + **
    + ** ^This function sets the database handle error code and message.
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_blob_reopen(sqlite3_blob *, sqlite3_int64);
    ++SQLITE_API int sqlite3_blob_reopen(sqlite3_blob *, sqlite3_int64);
    + 
    + /*
    + ** CAPI3REF: Close A BLOB Handle
    +@@ -5979,7 +6577,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_blob_reopen(sqlite3_blob *, sqlite3_int64)
    + ** is passed a valid open blob handle, the values returned by the 
    + ** sqlite3_errcode() and sqlite3_errmsg() functions are set before returning.
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_blob_close(sqlite3_blob *);
    ++SQLITE_API int sqlite3_blob_close(sqlite3_blob *);
    + 
    + /*
    + ** CAPI3REF: Return The Size Of An Open BLOB
    +@@ -5995,7 +6593,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_blob_close(sqlite3_blob *);
    + ** been closed by [sqlite3_blob_close()].  Passing any other pointer in
    + ** to this routine results in undefined and probably undesirable behavior.
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_blob_bytes(sqlite3_blob *);
    ++SQLITE_API int sqlite3_blob_bytes(sqlite3_blob *);
    + 
    + /*
    + ** CAPI3REF: Read Data From A BLOB Incrementally
    +@@ -6024,7 +6622,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_blob_bytes(sqlite3_blob *);
    + **
    + ** See also: [sqlite3_blob_write()].
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_blob_read(sqlite3_blob *, void *Z, int N, int iOffset);
    ++SQLITE_API int sqlite3_blob_read(sqlite3_blob *, void *Z, int N, int iOffset);
    + 
    + /*
    + ** CAPI3REF: Write Data Into A BLOB Incrementally
    +@@ -6066,7 +6664,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_blob_read(sqlite3_blob *, void *Z, int N,
    + **
    + ** See also: [sqlite3_blob_read()].
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_blob_write(sqlite3_blob *, const void *z, int n, int iOffset);
    ++SQLITE_API int sqlite3_blob_write(sqlite3_blob *, const void *z, int n, int iOffset);
    + 
    + /*
    + ** CAPI3REF: Virtual File System Objects
    +@@ -6097,9 +6695,9 @@ SQLITE_API int SQLITE_STDCALL sqlite3_blob_write(sqlite3_blob *, const void *z,
    + ** ^(If the default VFS is unregistered, another VFS is chosen as
    + ** the default.  The choice for the new VFS is arbitrary.)^
    + */
    +-SQLITE_API sqlite3_vfs *SQLITE_STDCALL sqlite3_vfs_find(const char *zVfsName);
    +-SQLITE_API int SQLITE_STDCALL sqlite3_vfs_register(sqlite3_vfs*, int makeDflt);
    +-SQLITE_API int SQLITE_STDCALL sqlite3_vfs_unregister(sqlite3_vfs*);
    ++SQLITE_API sqlite3_vfs *sqlite3_vfs_find(const char *zVfsName);
    ++SQLITE_API int sqlite3_vfs_register(sqlite3_vfs*, int makeDflt);
    ++SQLITE_API int sqlite3_vfs_unregister(sqlite3_vfs*);
    + 
    + /*
    + ** CAPI3REF: Mutexes
    +@@ -6215,11 +6813,11 @@ SQLITE_API int SQLITE_STDCALL sqlite3_vfs_unregister(sqlite3_vfs*);
    + **
    + ** See also: [sqlite3_mutex_held()] and [sqlite3_mutex_notheld()].
    + */
    +-SQLITE_API sqlite3_mutex *SQLITE_STDCALL sqlite3_mutex_alloc(int);
    +-SQLITE_API void SQLITE_STDCALL sqlite3_mutex_free(sqlite3_mutex*);
    +-SQLITE_API void SQLITE_STDCALL sqlite3_mutex_enter(sqlite3_mutex*);
    +-SQLITE_API int SQLITE_STDCALL sqlite3_mutex_try(sqlite3_mutex*);
    +-SQLITE_API void SQLITE_STDCALL sqlite3_mutex_leave(sqlite3_mutex*);
    ++SQLITE_API sqlite3_mutex *sqlite3_mutex_alloc(int);
    ++SQLITE_API void sqlite3_mutex_free(sqlite3_mutex*);
    ++SQLITE_API void sqlite3_mutex_enter(sqlite3_mutex*);
    ++SQLITE_API int sqlite3_mutex_try(sqlite3_mutex*);
    ++SQLITE_API void sqlite3_mutex_leave(sqlite3_mutex*);
    + 
    + /*
    + ** CAPI3REF: Mutex Methods Object
    +@@ -6329,8 +6927,8 @@ struct sqlite3_mutex_methods {
    + ** interface should also return 1 when given a NULL pointer.
    + */
    + #ifndef NDEBUG
    +-SQLITE_API int SQLITE_STDCALL sqlite3_mutex_held(sqlite3_mutex*);
    +-SQLITE_API int SQLITE_STDCALL sqlite3_mutex_notheld(sqlite3_mutex*);
    ++SQLITE_API int sqlite3_mutex_held(sqlite3_mutex*);
    ++SQLITE_API int sqlite3_mutex_notheld(sqlite3_mutex*);
    + #endif
    + 
    + /*
    +@@ -6349,7 +6947,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_mutex_notheld(sqlite3_mutex*);
    + #define SQLITE_MUTEX_STATIC_MEM       3  /* sqlite3_malloc() */
    + #define SQLITE_MUTEX_STATIC_MEM2      4  /* NOT USED */
    + #define SQLITE_MUTEX_STATIC_OPEN      4  /* sqlite3BtreeOpen() */
    +-#define SQLITE_MUTEX_STATIC_PRNG      5  /* sqlite3_random() */
    ++#define SQLITE_MUTEX_STATIC_PRNG      5  /* sqlite3_randomness() */
    + #define SQLITE_MUTEX_STATIC_LRU       6  /* lru page list */
    + #define SQLITE_MUTEX_STATIC_LRU2      7  /* NOT USED */
    + #define SQLITE_MUTEX_STATIC_PMEM      7  /* sqlite3PageMalloc() */
    +@@ -6370,7 +6968,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_mutex_notheld(sqlite3_mutex*);
    + ** ^If the [threading mode] is Single-thread or Multi-thread then this
    + ** routine returns a NULL pointer.
    + */
    +-SQLITE_API sqlite3_mutex *SQLITE_STDCALL sqlite3_db_mutex(sqlite3*);
    ++SQLITE_API sqlite3_mutex *sqlite3_db_mutex(sqlite3*);
    + 
    + /*
    + ** CAPI3REF: Low-Level Control Of Database Files
    +@@ -6389,9 +6987,9 @@ SQLITE_API sqlite3_mutex *SQLITE_STDCALL sqlite3_db_mutex(sqlite3*);
    + ** the xFileControl method.  ^The return value of the xFileControl
    + ** method becomes the return value of this routine.
    + **
    +-** ^The SQLITE_FCNTL_FILE_POINTER value for the op parameter causes
    ++** ^The [SQLITE_FCNTL_FILE_POINTER] value for the op parameter causes
    + ** a pointer to the underlying [sqlite3_file] object to be written into
    +-** the space pointed to by the 4th parameter.  ^The SQLITE_FCNTL_FILE_POINTER
    ++** the space pointed to by the 4th parameter.  ^The [SQLITE_FCNTL_FILE_POINTER]
    + ** case is a short-circuit path which does not actually invoke the
    + ** underlying sqlite3_io_methods.xFileControl method.
    + **
    +@@ -6403,9 +7001,9 @@ SQLITE_API sqlite3_mutex *SQLITE_STDCALL sqlite3_db_mutex(sqlite3*);
    + ** an incorrect zDbName and an SQLITE_ERROR return from the underlying
    + ** xFileControl method.
    + **
    +-** See also: [SQLITE_FCNTL_LOCKSTATE]
    ++** See also: [file control opcodes]
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_file_control(sqlite3*, const char *zDbName, int op, void*);
    ++SQLITE_API int sqlite3_file_control(sqlite3*, const char *zDbName, int op, void*);
    + 
    + /*
    + ** CAPI3REF: Testing Interface
    +@@ -6424,7 +7022,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_file_control(sqlite3*, const char *zDbName
    + ** Unlike most of the SQLite API, this function is not guaranteed to
    + ** operate consistently from one release to the next.
    + */
    +-SQLITE_API int SQLITE_CDECL sqlite3_test_control(int op, ...);
    ++SQLITE_API int sqlite3_test_control(int op, ...);
    + 
    + /*
    + ** CAPI3REF: Testing Interface Operation Codes
    +@@ -6450,16 +7048,18 @@ SQLITE_API int SQLITE_CDECL sqlite3_test_control(int op, ...);
    + #define SQLITE_TESTCTRL_RESERVE                 14
    + #define SQLITE_TESTCTRL_OPTIMIZATIONS           15
    + #define SQLITE_TESTCTRL_ISKEYWORD               16
    +-#define SQLITE_TESTCTRL_SCRATCHMALLOC           17
    ++#define SQLITE_TESTCTRL_SCRATCHMALLOC           17  /* NOT USED */
    + #define SQLITE_TESTCTRL_LOCALTIME_FAULT         18
    + #define SQLITE_TESTCTRL_EXPLAIN_STMT            19  /* NOT USED */
    ++#define SQLITE_TESTCTRL_ONCE_RESET_THRESHOLD    19
    + #define SQLITE_TESTCTRL_NEVER_CORRUPT           20
    + #define SQLITE_TESTCTRL_VDBE_COVERAGE           21
    + #define SQLITE_TESTCTRL_BYTEORDER               22
    + #define SQLITE_TESTCTRL_ISINIT                  23
    + #define SQLITE_TESTCTRL_SORTER_MMAP             24
    + #define SQLITE_TESTCTRL_IMPOSTER                25
    +-#define SQLITE_TESTCTRL_LAST                    25
    ++#define SQLITE_TESTCTRL_PARSER_COVERAGE         26
    ++#define SQLITE_TESTCTRL_LAST                    26  /* Largest TESTCTRL */
    + 
    + /*
    + ** CAPI3REF: SQLite Runtime Status
    +@@ -6487,8 +7087,8 @@ SQLITE_API int SQLITE_CDECL sqlite3_test_control(int op, ...);
    + **
    + ** See also: [sqlite3_db_status()]
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_status(int op, int *pCurrent, int *pHighwater, int resetFlag);
    +-SQLITE_API int SQLITE_STDCALL sqlite3_status64(
    ++SQLITE_API int sqlite3_status(int op, int *pCurrent, int *pHighwater, int resetFlag);
    ++SQLITE_API int sqlite3_status64(
    +   int op,
    +   sqlite3_int64 *pCurrent,
    +   sqlite3_int64 *pHighwater,
    +@@ -6508,8 +7108,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_status64(
    + ** <dd>This parameter is the current amount of memory checked out
    + ** using [sqlite3_malloc()], either directly or indirectly.  The
    + ** figure includes calls made to [sqlite3_malloc()] by the application
    +-** and internal memory usage by the SQLite library.  Scratch memory
    +-** controlled by [SQLITE_CONFIG_SCRATCH] and auxiliary page-cache
    ++** and internal memory usage by the SQLite library.  Auxiliary page-cache
    + ** memory controlled by [SQLITE_CONFIG_PAGECACHE] is not included in
    + ** this parameter.  The amount returned is the sum of the allocation
    + ** sizes as reported by the xSize method in [sqlite3_mem_methods].</dd>)^
    +@@ -6547,32 +7146,18 @@ SQLITE_API int SQLITE_STDCALL sqlite3_status64(
    + ** *pHighwater parameter to [sqlite3_status()] is of interest.  
    + ** The value written into the *pCurrent parameter is undefined.</dd>)^
    + **
    +-** [[SQLITE_STATUS_SCRATCH_USED]] ^(<dt>SQLITE_STATUS_SCRATCH_USED</dt>
    +-** <dd>This parameter returns the number of allocations used out of the
    +-** [scratch memory allocator] configured using
    +-** [SQLITE_CONFIG_SCRATCH].  The value returned is in allocations, not
    +-** in bytes.  Since a single thread may only have one scratch allocation
    +-** outstanding at time, this parameter also reports the number of threads
    +-** using scratch memory at the same time.</dd>)^
    ++** [[SQLITE_STATUS_SCRATCH_USED]] <dt>SQLITE_STATUS_SCRATCH_USED</dt>
    ++** <dd>No longer used.</dd>
    + **
    + ** [[SQLITE_STATUS_SCRATCH_OVERFLOW]] ^(<dt>SQLITE_STATUS_SCRATCH_OVERFLOW</dt>
    +-** <dd>This parameter returns the number of bytes of scratch memory
    +-** allocation which could not be satisfied by the [SQLITE_CONFIG_SCRATCH]
    +-** buffer and where forced to overflow to [sqlite3_malloc()].  The values
    +-** returned include overflows because the requested allocation was too
    +-** larger (that is, because the requested allocation was larger than the
    +-** "sz" parameter to [SQLITE_CONFIG_SCRATCH]) and because no scratch buffer
    +-** slots were available.
    +-** </dd>)^
    +-**
    +-** [[SQLITE_STATUS_SCRATCH_SIZE]] ^(<dt>SQLITE_STATUS_SCRATCH_SIZE</dt>
    +-** <dd>This parameter records the largest memory allocation request
    +-** handed to [scratch memory allocator].  Only the value returned in the
    +-** *pHighwater parameter to [sqlite3_status()] is of interest.  
    +-** The value written into the *pCurrent parameter is undefined.</dd>)^
    ++** <dd>No longer used.</dd>
    ++**
    ++** [[SQLITE_STATUS_SCRATCH_SIZE]] <dt>SQLITE_STATUS_SCRATCH_SIZE</dt>
    ++** <dd>No longer used.</dd>
    + **
    + ** [[SQLITE_STATUS_PARSER_STACK]] ^(<dt>SQLITE_STATUS_PARSER_STACK</dt>
    +-** <dd>This parameter records the deepest parser stack.  It is only
    ++** <dd>The *pHighwater parameter records the deepest parser stack. 
    ++** The *pCurrent value is undefined.  The *pHighwater value is only
    + ** meaningful if SQLite is compiled with [YYTRACKMAXSTACKDEPTH].</dd>)^
    + ** </dl>
    + **
    +@@ -6581,12 +7166,12 @@ SQLITE_API int SQLITE_STDCALL sqlite3_status64(
    + #define SQLITE_STATUS_MEMORY_USED          0
    + #define SQLITE_STATUS_PAGECACHE_USED       1
    + #define SQLITE_STATUS_PAGECACHE_OVERFLOW   2
    +-#define SQLITE_STATUS_SCRATCH_USED         3
    +-#define SQLITE_STATUS_SCRATCH_OVERFLOW     4
    ++#define SQLITE_STATUS_SCRATCH_USED         3  /* NOT USED */
    ++#define SQLITE_STATUS_SCRATCH_OVERFLOW     4  /* NOT USED */
    + #define SQLITE_STATUS_MALLOC_SIZE          5
    + #define SQLITE_STATUS_PARSER_STACK         6
    + #define SQLITE_STATUS_PAGECACHE_SIZE       7
    +-#define SQLITE_STATUS_SCRATCH_SIZE         8
    ++#define SQLITE_STATUS_SCRATCH_SIZE         8  /* NOT USED */
    + #define SQLITE_STATUS_MALLOC_COUNT         9
    + 
    + /*
    +@@ -6612,7 +7197,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_status64(
    + **
    + ** See also: [sqlite3_status()] and [sqlite3_stmt_status()].
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_db_status(sqlite3*, int op, int *pCur, int *pHiwtr, int resetFlg);
    ++SQLITE_API int sqlite3_db_status(sqlite3*, int op, int *pCur, int *pHiwtr, int resetFlg);
    + 
    + /*
    + ** CAPI3REF: Status Parameters for database connections
    +@@ -6658,6 +7243,18 @@ SQLITE_API int SQLITE_STDCALL sqlite3_db_status(sqlite3*, int op, int *pCur, int
    + ** memory used by all pager caches associated with the database connection.)^
    + ** ^The highwater mark associated with SQLITE_DBSTATUS_CACHE_USED is always 0.
    + **
    ++** [[SQLITE_DBSTATUS_CACHE_USED_SHARED]] 
    ++** ^(<dt>SQLITE_DBSTATUS_CACHE_USED_SHARED</dt>
    ++** <dd>This parameter is similar to DBSTATUS_CACHE_USED, except that if a
    ++** pager cache is shared between two or more connections the bytes of heap
    ++** memory used by that pager cache is divided evenly between the attached
    ++** connections.)^  In other words, if none of the pager caches associated
    ++** with the database connection are shared, this request returns the same
    ++** value as DBSTATUS_CACHE_USED. Or, if one or more or the pager caches are
    ++** shared, the value returned by this call will be smaller than that returned
    ++** by DBSTATUS_CACHE_USED. ^The highwater mark associated with
    ++** SQLITE_DBSTATUS_CACHE_USED_SHARED is always 0.
    ++**
    + ** [[SQLITE_DBSTATUS_SCHEMA_USED]] ^(<dt>SQLITE_DBSTATUS_SCHEMA_USED</dt>
    + ** <dd>This parameter returns the approximate number of bytes of heap
    + ** memory used to store the schema for all databases associated
    +@@ -6715,7 +7312,8 @@ SQLITE_API int SQLITE_STDCALL sqlite3_db_status(sqlite3*, int op, int *pCur, int
    + #define SQLITE_DBSTATUS_CACHE_MISS           8
    + #define SQLITE_DBSTATUS_CACHE_WRITE          9
    + #define SQLITE_DBSTATUS_DEFERRED_FKS        10
    +-#define SQLITE_DBSTATUS_MAX                 10   /* Largest defined DBSTATUS */
    ++#define SQLITE_DBSTATUS_CACHE_USED_SHARED   11
    ++#define SQLITE_DBSTATUS_MAX                 11   /* Largest defined DBSTATUS */
    + 
    + 
    + /*
    +@@ -6742,7 +7340,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_db_status(sqlite3*, int op, int *pCur, int
    + **
    + ** See also: [sqlite3_status()] and [sqlite3_db_status()].
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_stmt_status(sqlite3_stmt*, int op,int resetFlg);
    ++SQLITE_API int sqlite3_stmt_status(sqlite3_stmt*, int op,int resetFlg);
    + 
    + /*
    + ** CAPI3REF: Status Parameters for prepared statements
    +@@ -6778,6 +7376,24 @@ SQLITE_API int SQLITE_STDCALL sqlite3_stmt_status(sqlite3_stmt*, int op,int rese
    + ** used as a proxy for the total work done by the prepared statement.
    + ** If the number of virtual machine operations exceeds 2147483647
    + ** then the value returned by this statement status code is undefined.
    ++**
    ++** [[SQLITE_STMTSTATUS_REPREPARE]] <dt>SQLITE_STMTSTATUS_REPREPARE</dt>
    ++** <dd>^This is the number of times that the prepare statement has been
    ++** automatically regenerated due to schema changes or change to 
    ++** [bound parameters] that might affect the query plan.
    ++**
    ++** [[SQLITE_STMTSTATUS_RUN]] <dt>SQLITE_STMTSTATUS_RUN</dt>
    ++** <dd>^This is the number of times that the prepared statement has
    ++** been run.  A single "run" for the purposes of this counter is one
    ++** or more calls to [sqlite3_step()] followed by a call to [sqlite3_reset()].
    ++** The counter is incremented on the first [sqlite3_step()] call of each
    ++** cycle.
    ++**
    ++** [[SQLITE_STMTSTATUS_MEMUSED]] <dt>SQLITE_STMTSTATUS_MEMUSED</dt>
    ++** <dd>^This is the approximate number of bytes of heap memory
    ++** used to store the prepared statement.  ^This value is not actually
    ++** a counter, and so the resetFlg parameter to sqlite3_stmt_status()
    ++** is ignored when the opcode is SQLITE_STMTSTATUS_MEMUSED.
    + ** </dd>
    + ** </dl>
    + */
    +@@ -6785,6 +7401,9 @@ SQLITE_API int SQLITE_STDCALL sqlite3_stmt_status(sqlite3_stmt*, int op,int rese
    + #define SQLITE_STMTSTATUS_SORT              2
    + #define SQLITE_STMTSTATUS_AUTOINDEX         3
    + #define SQLITE_STMTSTATUS_VM_STEP           4
    ++#define SQLITE_STMTSTATUS_REPREPARE         5
    ++#define SQLITE_STMTSTATUS_RUN               6
    ++#define SQLITE_STMTSTATUS_MEMUSED           99
    + 
    + /*
    + ** CAPI3REF: Custom Page Cache Object
    +@@ -7069,7 +7688,7 @@ typedef struct sqlite3_backup sqlite3_backup;
    + ** must be different or else sqlite3_backup_init(D,N,S,M) will fail with
    + ** an error.
    + **
    +-** ^A call to sqlite3_backup_init() will fail, returning SQLITE_ERROR, if 
    ++** ^A call to sqlite3_backup_init() will fail, returning NULL, if 
    + ** there is already a read or read-write transaction open on the 
    + ** destination database.
    + **
    +@@ -7211,16 +7830,16 @@ typedef struct sqlite3_backup sqlite3_backup;
    + ** same time as another thread is invoking sqlite3_backup_step() it is
    + ** possible that they return invalid values.
    + */
    +-SQLITE_API sqlite3_backup *SQLITE_STDCALL sqlite3_backup_init(
    ++SQLITE_API sqlite3_backup *sqlite3_backup_init(
    +   sqlite3 *pDest,                        /* Destination database handle */
    +   const char *zDestName,                 /* Destination database name */
    +   sqlite3 *pSource,                      /* Source database handle */
    +   const char *zSourceName                /* Source database name */
    + );
    +-SQLITE_API int SQLITE_STDCALL sqlite3_backup_step(sqlite3_backup *p, int nPage);
    +-SQLITE_API int SQLITE_STDCALL sqlite3_backup_finish(sqlite3_backup *p);
    +-SQLITE_API int SQLITE_STDCALL sqlite3_backup_remaining(sqlite3_backup *p);
    +-SQLITE_API int SQLITE_STDCALL sqlite3_backup_pagecount(sqlite3_backup *p);
    ++SQLITE_API int sqlite3_backup_step(sqlite3_backup *p, int nPage);
    ++SQLITE_API int sqlite3_backup_finish(sqlite3_backup *p);
    ++SQLITE_API int sqlite3_backup_remaining(sqlite3_backup *p);
    ++SQLITE_API int sqlite3_backup_pagecount(sqlite3_backup *p);
    + 
    + /*
    + ** CAPI3REF: Unlock Notification
    +@@ -7337,7 +7956,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_backup_pagecount(sqlite3_backup *p);
    + ** the special "DROP TABLE/INDEX" case, the extended error code is just 
    + ** SQLITE_LOCKED.)^
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_unlock_notify(
    ++SQLITE_API int sqlite3_unlock_notify(
    +   sqlite3 *pBlocked,                          /* Waiting connection */
    +   void (*xNotify)(void **apArg, int nArg),    /* Callback function to invoke */
    +   void *pNotifyArg                            /* Argument to pass to xNotify */
    +@@ -7352,23 +7971,48 @@ SQLITE_API int SQLITE_STDCALL sqlite3_unlock_notify(
    + ** strings in a case-independent fashion, using the same definition of "case
    + ** independence" that SQLite uses internally when comparing identifiers.
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_stricmp(const char *, const char *);
    +-SQLITE_API int SQLITE_STDCALL sqlite3_strnicmp(const char *, const char *, int);
    ++SQLITE_API int sqlite3_stricmp(const char *, const char *);
    ++SQLITE_API int sqlite3_strnicmp(const char *, const char *, int);
    + 
    + /*
    + ** CAPI3REF: String Globbing
    + *
    +-** ^The [sqlite3_strglob(P,X)] interface returns zero if string X matches
    +-** the glob pattern P, and it returns non-zero if string X does not match
    +-** the glob pattern P.  ^The definition of glob pattern matching used in
    ++** ^The [sqlite3_strglob(P,X)] interface returns zero if and only if
    ++** string X matches the [GLOB] pattern P.
    ++** ^The definition of [GLOB] pattern matching used in
    + ** [sqlite3_strglob(P,X)] is the same as for the "X GLOB P" operator in the
    +-** SQL dialect used by SQLite.  ^The sqlite3_strglob(P,X) function is case
    +-** sensitive.
    ++** SQL dialect understood by SQLite.  ^The [sqlite3_strglob(P,X)] function
    ++** is case sensitive.
    ++**
    ++** Note that this routine returns zero on a match and non-zero if the strings
    ++** do not match, the same as [sqlite3_stricmp()] and [sqlite3_strnicmp()].
    ++**
    ++** See also: [sqlite3_strlike()].
    ++*/
    ++SQLITE_API int sqlite3_strglob(const char *zGlob, const char *zStr);
    ++
    ++/*
    ++** CAPI3REF: String LIKE Matching
    ++*
    ++** ^The [sqlite3_strlike(P,X,E)] interface returns zero if and only if
    ++** string X matches the [LIKE] pattern P with escape character E.
    ++** ^The definition of [LIKE] pattern matching used in
    ++** [sqlite3_strlike(P,X,E)] is the same as for the "X LIKE P ESCAPE E"
    ++** operator in the SQL dialect understood by SQLite.  ^For "X LIKE P" without
    ++** the ESCAPE clause, set the E parameter of [sqlite3_strlike(P,X,E)] to 0.
    ++** ^As with the LIKE operator, the [sqlite3_strlike(P,X,E)] function is case
    ++** insensitive - equivalent upper and lower case ASCII characters match
    ++** one another.
    ++**
    ++** ^The [sqlite3_strlike(P,X,E)] function matches Unicode characters, though
    ++** only ASCII characters are case folded.
    + **
    + ** Note that this routine returns zero on a match and non-zero if the strings
    + ** do not match, the same as [sqlite3_stricmp()] and [sqlite3_strnicmp()].
    ++**
    ++** See also: [sqlite3_strglob()].
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_strglob(const char *zGlob, const char *zStr);
    ++SQLITE_API int sqlite3_strlike(const char *zGlob, const char *zStr, unsigned int cEsc);
    + 
    + /*
    + ** CAPI3REF: Error Logging Interface
    +@@ -7391,7 +8035,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_strglob(const char *zGlob, const char *zSt
    + ** a few hundred characters, it will be truncated to the length of the
    + ** buffer.
    + */
    +-SQLITE_API void SQLITE_CDECL sqlite3_log(int iErrCode, const char *zFormat, ...);
    ++SQLITE_API void sqlite3_log(int iErrCode, const char *zFormat, ...);
    + 
    + /*
    + ** CAPI3REF: Write-Ahead Log Commit Hook
    +@@ -7425,9 +8069,9 @@ SQLITE_API void SQLITE_CDECL sqlite3_log(int iErrCode, const char *zFormat, ...)
    + ** previously registered write-ahead log callback. ^Note that the
    + ** [sqlite3_wal_autocheckpoint()] interface and the
    + ** [wal_autocheckpoint pragma] both invoke [sqlite3_wal_hook()] and will
    +-** those overwrite any prior [sqlite3_wal_hook()] settings.
    ++** overwrite any prior [sqlite3_wal_hook()] settings.
    + */
    +-SQLITE_API void *SQLITE_STDCALL sqlite3_wal_hook(
    ++SQLITE_API void *sqlite3_wal_hook(
    +   sqlite3*, 
    +   int(*)(void *,sqlite3*,const char*,int),
    +   void*
    +@@ -7462,7 +8106,7 @@ SQLITE_API void *SQLITE_STDCALL sqlite3_wal_hook(
    + ** is only necessary if the default setting is found to be suboptimal
    + ** for a particular application.
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_wal_autocheckpoint(sqlite3 *db, int N);
    ++SQLITE_API int sqlite3_wal_autocheckpoint(sqlite3 *db, int N);
    + 
    + /*
    + ** CAPI3REF: Checkpoint a database
    +@@ -7484,7 +8128,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_wal_autocheckpoint(sqlite3 *db, int N);
    + ** start a callback but which do not need the full power (and corresponding
    + ** complication) of [sqlite3_wal_checkpoint_v2()].
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_wal_checkpoint(sqlite3 *db, const char *zDb);
    ++SQLITE_API int sqlite3_wal_checkpoint(sqlite3 *db, const char *zDb);
    + 
    + /*
    + ** CAPI3REF: Checkpoint a database
    +@@ -7578,7 +8222,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_wal_checkpoint(sqlite3 *db, const char *zD
    + ** ^The [PRAGMA wal_checkpoint] command can be used to invoke this interface
    + ** from SQL.
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_wal_checkpoint_v2(
    ++SQLITE_API int sqlite3_wal_checkpoint_v2(
    +   sqlite3 *db,                    /* Database handle */
    +   const char *zDb,                /* Name of attached database (or NULL) */
    +   int eMode,                      /* SQLITE_CHECKPOINT_* value */
    +@@ -7614,7 +8258,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_wal_checkpoint_v2(
    + ** this function. (See [SQLITE_VTAB_CONSTRAINT_SUPPORT].)  Further options
    + ** may be added in the future.
    + */
    +-SQLITE_API int SQLITE_CDECL sqlite3_vtab_config(sqlite3*, int op, ...);
    ++SQLITE_API int sqlite3_vtab_config(sqlite3*, int op, ...);
    + 
    + /*
    + ** CAPI3REF: Virtual Table Configuration Options
    +@@ -7667,7 +8311,41 @@ SQLITE_API int SQLITE_CDECL sqlite3_vtab_config(sqlite3*, int op, ...);
    + ** of the SQL statement that triggered the call to the [xUpdate] method of the
    + ** [virtual table].
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_vtab_on_conflict(sqlite3 *);
    ++SQLITE_API int sqlite3_vtab_on_conflict(sqlite3 *);
    ++
    ++/*
    ++** CAPI3REF: Determine If Virtual Table Column Access Is For UPDATE
    ++**
    ++** If the sqlite3_vtab_nochange(X) routine is called within the [xColumn]
    ++** method of a [virtual table], then it returns true if and only if the
    ++** column is being fetched as part of an UPDATE operation during which the
    ++** column value will not change.  Applications might use this to substitute
    ++** a lighter-weight value to return that the corresponding [xUpdate] method
    ++** understands as a "no-change" value.
    ++**
    ++** If the [xColumn] method calls sqlite3_vtab_nochange() and finds that
    ++** the column is not changed by the UPDATE statement, they the xColumn
    ++** method can optionally return without setting a result, without calling
    ++** any of the [sqlite3_result_int|sqlite3_result_xxxxx() interfaces].
    ++** In that case, [sqlite3_value_nochange(X)] will return true for the
    ++** same column in the [xUpdate] method.
    ++*/
    ++SQLITE_API int sqlite3_vtab_nochange(sqlite3_context*);
    ++
    ++/*
    ++** CAPI3REF: Determine The Collation For a Virtual Table Constraint
    ++**
    ++** This function may only be called from within a call to the [xBestIndex]
    ++** method of a [virtual table]. 
    ++**
    ++** The first argument must be the sqlite3_index_info object that is the
    ++** first parameter to the xBestIndex() method. The second argument must be
    ++** an index into the aConstraint[] array belonging to the sqlite3_index_info
    ++** structure passed to xBestIndex. This function returns a pointer to a buffer 
    ++** containing the name of the collation sequence for the corresponding
    ++** constraint.
    ++*/
    ++SQLITE_API SQLITE_EXPERIMENTAL const char *sqlite3_vtab_collation(sqlite3_index_info*,int);
    + 
    + /*
    + ** CAPI3REF: Conflict resolution modes
    +@@ -7772,7 +8450,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_vtab_on_conflict(sqlite3 *);
    + **
    + ** See also: [sqlite3_stmt_scanstatus_reset()]
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_stmt_scanstatus(
    ++SQLITE_API int sqlite3_stmt_scanstatus(
    +   sqlite3_stmt *pStmt,      /* Prepared statement for which info desired */
    +   int idx,                  /* Index of loop to report on */
    +   int iScanStatusOp,        /* Information desired.  SQLITE_SCANSTAT_* */
    +@@ -7788,8 +8466,332 @@ SQLITE_API int SQLITE_STDCALL sqlite3_stmt_scanstatus(
    + ** This API is only available if the library is built with pre-processor
    + ** symbol [SQLITE_ENABLE_STMT_SCANSTATUS] defined.
    + */
    +-SQLITE_API void SQLITE_STDCALL sqlite3_stmt_scanstatus_reset(sqlite3_stmt*);
    ++SQLITE_API void sqlite3_stmt_scanstatus_reset(sqlite3_stmt*);
    ++
    ++/*
    ++** CAPI3REF: Flush caches to disk mid-transaction
    ++**
    ++** ^If a write-transaction is open on [database connection] D when the
    ++** [sqlite3_db_cacheflush(D)] interface invoked, any dirty
    ++** pages in the pager-cache that are not currently in use are written out 
    ++** to disk. A dirty page may be in use if a database cursor created by an
    ++** active SQL statement is reading from it, or if it is page 1 of a database
    ++** file (page 1 is always "in use").  ^The [sqlite3_db_cacheflush(D)]
    ++** interface flushes caches for all schemas - "main", "temp", and
    ++** any [attached] databases.
    ++**
    ++** ^If this function needs to obtain extra database locks before dirty pages 
    ++** can be flushed to disk, it does so. ^If those locks cannot be obtained 
    ++** immediately and there is a busy-handler callback configured, it is invoked
    ++** in the usual manner. ^If the required lock still cannot be obtained, then
    ++** the database is skipped and an attempt made to flush any dirty pages
    ++** belonging to the next (if any) database. ^If any databases are skipped
    ++** because locks cannot be obtained, but no other error occurs, this
    ++** function returns SQLITE_BUSY.
    ++**
    ++** ^If any other error occurs while flushing dirty pages to disk (for
    ++** example an IO error or out-of-memory condition), then processing is
    ++** abandoned and an SQLite [error code] is returned to the caller immediately.
    ++**
    ++** ^Otherwise, if no error occurs, [sqlite3_db_cacheflush()] returns SQLITE_OK.
    ++**
    ++** ^This function does not set the database handle error code or message
    ++** returned by the [sqlite3_errcode()] and [sqlite3_errmsg()] functions.
    ++*/
    ++SQLITE_API int sqlite3_db_cacheflush(sqlite3*);
    ++
    ++/*
    ++** CAPI3REF: The pre-update hook.
    ++**
    ++** ^These interfaces are only available if SQLite is compiled using the
    ++** [SQLITE_ENABLE_PREUPDATE_HOOK] compile-time option.
    ++**
    ++** ^The [sqlite3_preupdate_hook()] interface registers a callback function
    ++** that is invoked prior to each [INSERT], [UPDATE], and [DELETE] operation
    ++** on a database table.
    ++** ^At most one preupdate hook may be registered at a time on a single
    ++** [database connection]; each call to [sqlite3_preupdate_hook()] overrides
    ++** the previous setting.
    ++** ^The preupdate hook is disabled by invoking [sqlite3_preupdate_hook()]
    ++** with a NULL pointer as the second parameter.
    ++** ^The third parameter to [sqlite3_preupdate_hook()] is passed through as
    ++** the first parameter to callbacks.
    ++**
    ++** ^The preupdate hook only fires for changes to real database tables; the
    ++** preupdate hook is not invoked for changes to [virtual tables] or to
    ++** system tables like sqlite_master or sqlite_stat1.
    ++**
    ++** ^The second parameter to the preupdate callback is a pointer to
    ++** the [database connection] that registered the preupdate hook.
    ++** ^The third parameter to the preupdate callback is one of the constants
    ++** [SQLITE_INSERT], [SQLITE_DELETE], or [SQLITE_UPDATE] to identify the
    ++** kind of update operation that is about to occur.
    ++** ^(The fourth parameter to the preupdate callback is the name of the
    ++** database within the database connection that is being modified.  This
    ++** will be "main" for the main database or "temp" for TEMP tables or 
    ++** the name given after the AS keyword in the [ATTACH] statement for attached
    ++** databases.)^
    ++** ^The fifth parameter to the preupdate callback is the name of the
    ++** table that is being modified.
    ++**
    ++** For an UPDATE or DELETE operation on a [rowid table], the sixth
    ++** parameter passed to the preupdate callback is the initial [rowid] of the 
    ++** row being modified or deleted. For an INSERT operation on a rowid table,
    ++** or any operation on a WITHOUT ROWID table, the value of the sixth 
    ++** parameter is undefined. For an INSERT or UPDATE on a rowid table the
    ++** seventh parameter is the final rowid value of the row being inserted
    ++** or updated. The value of the seventh parameter passed to the callback
    ++** function is not defined for operations on WITHOUT ROWID tables, or for
    ++** INSERT operations on rowid tables.
    ++**
    ++** The [sqlite3_preupdate_old()], [sqlite3_preupdate_new()],
    ++** [sqlite3_preupdate_count()], and [sqlite3_preupdate_depth()] interfaces
    ++** provide additional information about a preupdate event. These routines
    ++** may only be called from within a preupdate callback.  Invoking any of
    ++** these routines from outside of a preupdate callback or with a
    ++** [database connection] pointer that is different from the one supplied
    ++** to the preupdate callback results in undefined and probably undesirable
    ++** behavior.
    ++**
    ++** ^The [sqlite3_preupdate_count(D)] interface returns the number of columns
    ++** in the row that is being inserted, updated, or deleted.
    ++**
    ++** ^The [sqlite3_preupdate_old(D,N,P)] interface writes into P a pointer to
    ++** a [protected sqlite3_value] that contains the value of the Nth column of
    ++** the table row before it is updated.  The N parameter must be between 0
    ++** and one less than the number of columns or the behavior will be
    ++** undefined. This must only be used within SQLITE_UPDATE and SQLITE_DELETE
    ++** preupdate callbacks; if it is used by an SQLITE_INSERT callback then the
    ++** behavior is undefined.  The [sqlite3_value] that P points to
    ++** will be destroyed when the preupdate callback returns.
    ++**
    ++** ^The [sqlite3_preupdate_new(D,N,P)] interface writes into P a pointer to
    ++** a [protected sqlite3_value] that contains the value of the Nth column of
    ++** the table row after it is updated.  The N parameter must be between 0
    ++** and one less than the number of columns or the behavior will be
    ++** undefined. This must only be used within SQLITE_INSERT and SQLITE_UPDATE
    ++** preupdate callbacks; if it is used by an SQLITE_DELETE callback then the
    ++** behavior is undefined.  The [sqlite3_value] that P points to
    ++** will be destroyed when the preupdate callback returns.
    ++**
    ++** ^The [sqlite3_preupdate_depth(D)] interface returns 0 if the preupdate
    ++** callback was invoked as a result of a direct insert, update, or delete
    ++** operation; or 1 for inserts, updates, or deletes invoked by top-level 
    ++** triggers; or 2 for changes resulting from triggers called by top-level
    ++** triggers; and so forth.
    ++**
    ++** See also:  [sqlite3_update_hook()]
    ++*/
    ++#if defined(SQLITE_ENABLE_PREUPDATE_HOOK)
    ++SQLITE_API void *sqlite3_preupdate_hook(
    ++  sqlite3 *db,
    ++  void(*xPreUpdate)(
    ++    void *pCtx,                   /* Copy of third arg to preupdate_hook() */
    ++    sqlite3 *db,                  /* Database handle */
    ++    int op,                       /* SQLITE_UPDATE, DELETE or INSERT */
    ++    char const *zDb,              /* Database name */
    ++    char const *zName,            /* Table name */
    ++    sqlite3_int64 iKey1,          /* Rowid of row about to be deleted/updated */
    ++    sqlite3_int64 iKey2           /* New rowid value (for a rowid UPDATE) */
    ++  ),
    ++  void*
    ++);
    ++SQLITE_API int sqlite3_preupdate_old(sqlite3 *, int, sqlite3_value **);
    ++SQLITE_API int sqlite3_preupdate_count(sqlite3 *);
    ++SQLITE_API int sqlite3_preupdate_depth(sqlite3 *);
    ++SQLITE_API int sqlite3_preupdate_new(sqlite3 *, int, sqlite3_value **);
    ++#endif
    ++
    ++/*
    ++** CAPI3REF: Low-level system error code
    ++**
    ++** ^Attempt to return the underlying operating system error code or error
    ++** number that caused the most recent I/O error or failure to open a file.
    ++** The return value is OS-dependent.  For example, on unix systems, after
    ++** [sqlite3_open_v2()] returns [SQLITE_CANTOPEN], this interface could be
    ++** called to get back the underlying "errno" that caused the problem, such
    ++** as ENOSPC, EAUTH, EISDIR, and so forth.  
    ++*/
    ++SQLITE_API int sqlite3_system_errno(sqlite3*);
    ++
    ++/*
    ++** CAPI3REF: Database Snapshot
    ++** KEYWORDS: {snapshot} {sqlite3_snapshot}
    ++** EXPERIMENTAL
    ++**
    ++** An instance of the snapshot object records the state of a [WAL mode]
    ++** database for some specific point in history.
    ++**
    ++** In [WAL mode], multiple [database connections] that are open on the
    ++** same database file can each be reading a different historical version
    ++** of the database file.  When a [database connection] begins a read
    ++** transaction, that connection sees an unchanging copy of the database
    ++** as it existed for the point in time when the transaction first started.
    ++** Subsequent changes to the database from other connections are not seen
    ++** by the reader until a new read transaction is started.
    ++**
    ++** The sqlite3_snapshot object records state information about an historical
    ++** version of the database file so that it is possible to later open a new read
    ++** transaction that sees that historical version of the database rather than
    ++** the most recent version.
    ++**
    ++** The constructor for this object is [sqlite3_snapshot_get()].  The
    ++** [sqlite3_snapshot_open()] method causes a fresh read transaction to refer
    ++** to an historical snapshot (if possible).  The destructor for 
    ++** sqlite3_snapshot objects is [sqlite3_snapshot_free()].
    ++*/
    ++typedef struct sqlite3_snapshot {
    ++  unsigned char hidden[48];
    ++} sqlite3_snapshot;
    ++
    ++/*
    ++** CAPI3REF: Record A Database Snapshot
    ++** EXPERIMENTAL
    ++**
    ++** ^The [sqlite3_snapshot_get(D,S,P)] interface attempts to make a
    ++** new [sqlite3_snapshot] object that records the current state of
    ++** schema S in database connection D.  ^On success, the
    ++** [sqlite3_snapshot_get(D,S,P)] interface writes a pointer to the newly
    ++** created [sqlite3_snapshot] object into *P and returns SQLITE_OK.
    ++** If there is not already a read-transaction open on schema S when
    ++** this function is called, one is opened automatically. 
    ++**
    ++** The following must be true for this function to succeed. If any of
    ++** the following statements are false when sqlite3_snapshot_get() is
    ++** called, SQLITE_ERROR is returned. The final value of *P is undefined
    ++** in this case. 
    ++**
    ++** <ul>
    ++**   <li> The database handle must be in [autocommit mode].
    ++**
    ++**   <li> Schema S of [database connection] D must be a [WAL mode] database.
    ++**
    ++**   <li> There must not be a write transaction open on schema S of database
    ++**        connection D.
    ++**
    ++**   <li> One or more transactions must have been written to the current wal
    ++**        file since it was created on disk (by any connection). This means
    ++**        that a snapshot cannot be taken on a wal mode database with no wal 
    ++**        file immediately after it is first opened. At least one transaction
    ++**        must be written to it first.
    ++** </ul>
    ++**
    ++** This function may also return SQLITE_NOMEM.  If it is called with the
    ++** database handle in autocommit mode but fails for some other reason, 
    ++** whether or not a read transaction is opened on schema S is undefined.
    ++**
    ++** The [sqlite3_snapshot] object returned from a successful call to
    ++** [sqlite3_snapshot_get()] must be freed using [sqlite3_snapshot_free()]
    ++** to avoid a memory leak.
    ++**
    ++** The [sqlite3_snapshot_get()] interface is only available when the
    ++** SQLITE_ENABLE_SNAPSHOT compile-time option is used.
    ++*/
    ++SQLITE_API SQLITE_EXPERIMENTAL int sqlite3_snapshot_get(
    ++  sqlite3 *db,
    ++  const char *zSchema,
    ++  sqlite3_snapshot **ppSnapshot
    ++);
    ++
    ++/*
    ++** CAPI3REF: Start a read transaction on an historical snapshot
    ++** EXPERIMENTAL
    ++**
    ++** ^The [sqlite3_snapshot_open(D,S,P)] interface starts a
    ++** read transaction for schema S of
    ++** [database connection] D such that the read transaction
    ++** refers to historical [snapshot] P, rather than the most
    ++** recent change to the database.
    ++** ^The [sqlite3_snapshot_open()] interface returns SQLITE_OK on success
    ++** or an appropriate [error code] if it fails.
    ++**
    ++** ^In order to succeed, a call to [sqlite3_snapshot_open(D,S,P)] must be
    ++** the first operation following the [BEGIN] that takes the schema S
    ++** out of [autocommit mode].
    ++** ^In other words, schema S must not currently be in
    ++** a transaction for [sqlite3_snapshot_open(D,S,P)] to work, but the
    ++** database connection D must be out of [autocommit mode].
    ++** ^A [snapshot] will fail to open if it has been overwritten by a
    ++** [checkpoint].
    ++** ^(A call to [sqlite3_snapshot_open(D,S,P)] will fail if the
    ++** database connection D does not know that the database file for
    ++** schema S is in [WAL mode].  A database connection might not know
    ++** that the database file is in [WAL mode] if there has been no prior
    ++** I/O on that database connection, or if the database entered [WAL mode] 
    ++** after the most recent I/O on the database connection.)^
    ++** (Hint: Run "[PRAGMA application_id]" against a newly opened
    ++** database connection in order to make it ready to use snapshots.)
    ++**
    ++** The [sqlite3_snapshot_open()] interface is only available when the
    ++** SQLITE_ENABLE_SNAPSHOT compile-time option is used.
    ++*/
    ++SQLITE_API SQLITE_EXPERIMENTAL int sqlite3_snapshot_open(
    ++  sqlite3 *db,
    ++  const char *zSchema,
    ++  sqlite3_snapshot *pSnapshot
    ++);
    ++
    ++/*
    ++** CAPI3REF: Destroy a snapshot
    ++** EXPERIMENTAL
    ++**
    ++** ^The [sqlite3_snapshot_free(P)] interface destroys [sqlite3_snapshot] P.
    ++** The application must eventually free every [sqlite3_snapshot] object
    ++** using this routine to avoid a memory leak.
    ++**
    ++** The [sqlite3_snapshot_free()] interface is only available when the
    ++** SQLITE_ENABLE_SNAPSHOT compile-time option is used.
    ++*/
    ++SQLITE_API SQLITE_EXPERIMENTAL void sqlite3_snapshot_free(sqlite3_snapshot*);
    ++
    ++/*
    ++** CAPI3REF: Compare the ages of two snapshot handles.
    ++** EXPERIMENTAL
    ++**
    ++** The sqlite3_snapshot_cmp(P1, P2) interface is used to compare the ages
    ++** of two valid snapshot handles. 
    ++**
    ++** If the two snapshot handles are not associated with the same database 
    ++** file, the result of the comparison is undefined. 
    ++**
    ++** Additionally, the result of the comparison is only valid if both of the
    ++** snapshot handles were obtained by calling sqlite3_snapshot_get() since the
    ++** last time the wal file was deleted. The wal file is deleted when the
    ++** database is changed back to rollback mode or when the number of database
    ++** clients drops to zero. If either snapshot handle was obtained before the 
    ++** wal file was last deleted, the value returned by this function 
    ++** is undefined.
    ++**
    ++** Otherwise, this API returns a negative value if P1 refers to an older
    ++** snapshot than P2, zero if the two handles refer to the same database
    ++** snapshot, and a positive value if P1 is a newer snapshot than P2.
    ++*/
    ++SQLITE_API SQLITE_EXPERIMENTAL int sqlite3_snapshot_cmp(
    ++  sqlite3_snapshot *p1,
    ++  sqlite3_snapshot *p2
    ++);
    + 
    ++/*
    ++** CAPI3REF: Recover snapshots from a wal file
    ++** EXPERIMENTAL
    ++**
    ++** If all connections disconnect from a database file but do not perform
    ++** a checkpoint, the existing wal file is opened along with the database
    ++** file the next time the database is opened. At this point it is only
    ++** possible to successfully call sqlite3_snapshot_open() to open the most
    ++** recent snapshot of the database (the one at the head of the wal file),
    ++** even though the wal file may contain other valid snapshots for which
    ++** clients have sqlite3_snapshot handles.
    ++**
    ++** This function attempts to scan the wal file associated with database zDb
    ++** of database handle db and make all valid snapshots available to
    ++** sqlite3_snapshot_open(). It is an error if there is already a read
    ++** transaction open on the database, or if the database is not a wal mode
    ++** database.
    ++**
    ++** SQLITE_OK is returned if successful, or an SQLite error code otherwise.
    ++*/
    ++SQLITE_API SQLITE_EXPERIMENTAL int sqlite3_snapshot_recover(sqlite3 *db, const char *zDb);
    + 
    + /*
    + ** Undo the hack that converts floating point types to integer for
    +@@ -7802,8 +8804,9 @@ SQLITE_API void SQLITE_STDCALL sqlite3_stmt_scanstatus_reset(sqlite3_stmt*);
    + #ifdef __cplusplus
    + }  /* End of the 'extern "C"' block */
    + #endif
    +-#endif /* _SQLITE3_H_ */
    ++#endif /* SQLITE3_H */
    + 
    ++/******** Begin file sqlite3rtree.h *********/
    + /*
    + ** 2010 August 30
    + **
    +@@ -7843,7 +8846,7 @@ typedef struct sqlite3_rtree_query_info sqlite3_rtree_query_info;
    + **
    + **   SELECT ... FROM <rtree> WHERE <rtree col> MATCH $zGeom(... params ...)
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_rtree_geometry_callback(
    ++SQLITE_API int sqlite3_rtree_geometry_callback(
    +   sqlite3 *db,
    +   const char *zGeom,
    +   int (*xGeom)(sqlite3_rtree_geometry*, int, sqlite3_rtree_dbl*,int*),
    +@@ -7869,7 +8872,7 @@ struct sqlite3_rtree_geometry {
    + **
    + **   SELECT ... FROM <rtree> WHERE <rtree col> MATCH $zQueryFunc(... params ...)
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_rtree_query_callback(
    ++SQLITE_API int sqlite3_rtree_query_callback(
    +   sqlite3 *db,
    +   const char *zQueryFunc,
    +   int (*xQueryFunc)(sqlite3_rtree_query_info*),
    +@@ -7921,6 +8924,1327 @@ struct sqlite3_rtree_query_info {
    + 
    + #endif  /* ifndef _SQLITE3RTREE_H_ */
    + 
    ++/******** End of sqlite3rtree.h *********/
    ++/******** Begin file sqlite3session.h *********/
    ++
    ++#if !defined(__SQLITESESSION_H_) && defined(SQLITE_ENABLE_SESSION)
    ++#define __SQLITESESSION_H_ 1
    ++
    ++/*
    ++** Make sure we can call this stuff from C++.
    ++*/
    ++#ifdef __cplusplus
    ++extern "C" {
    ++#endif
    ++
    ++
    ++/*
    ++** CAPI3REF: Session Object Handle
    ++*/
    ++typedef struct sqlite3_session sqlite3_session;
    ++
    ++/*
    ++** CAPI3REF: Changeset Iterator Handle
    ++*/
    ++typedef struct sqlite3_changeset_iter sqlite3_changeset_iter;
    ++
    ++/*
    ++** CAPI3REF: Create A New Session Object
    ++**
    ++** Create a new session object attached to database handle db. If successful,
    ++** a pointer to the new object is written to *ppSession and SQLITE_OK is
    ++** returned. If an error occurs, *ppSession is set to NULL and an SQLite
    ++** error code (e.g. SQLITE_NOMEM) is returned.
    ++**
    ++** It is possible to create multiple session objects attached to a single
    ++** database handle.
    ++**
    ++** Session objects created using this function should be deleted using the
    ++** [sqlite3session_delete()] function before the database handle that they
    ++** are attached to is itself closed. If the database handle is closed before
    ++** the session object is deleted, then the results of calling any session
    ++** module function, including [sqlite3session_delete()] on the session object
    ++** are undefined.
    ++**
    ++** Because the session module uses the [sqlite3_preupdate_hook()] API, it
    ++** is not possible for an application to register a pre-update hook on a
    ++** database handle that has one or more session objects attached. Nor is
    ++** it possible to create a session object attached to a database handle for
    ++** which a pre-update hook is already defined. The results of attempting 
    ++** either of these things are undefined.
    ++**
    ++** The session object will be used to create changesets for tables in
    ++** database zDb, where zDb is either "main", or "temp", or the name of an
    ++** attached database. It is not an error if database zDb is not attached
    ++** to the database when the session object is created.
    ++*/
    ++SQLITE_API int sqlite3session_create(
    ++  sqlite3 *db,                    /* Database handle */
    ++  const char *zDb,                /* Name of db (e.g. "main") */
    ++  sqlite3_session **ppSession     /* OUT: New session object */
    ++);
    ++
    ++/*
    ++** CAPI3REF: Delete A Session Object
    ++**
    ++** Delete a session object previously allocated using 
    ++** [sqlite3session_create()]. Once a session object has been deleted, the
    ++** results of attempting to use pSession with any other session module
    ++** function are undefined.
    ++**
    ++** Session objects must be deleted before the database handle to which they
    ++** are attached is closed. Refer to the documentation for 
    ++** [sqlite3session_create()] for details.
    ++*/
    ++SQLITE_API void sqlite3session_delete(sqlite3_session *pSession);
    ++
    ++
    ++/*
    ++** CAPI3REF: Enable Or Disable A Session Object
    ++**
    ++** Enable or disable the recording of changes by a session object. When
    ++** enabled, a session object records changes made to the database. When
    ++** disabled - it does not. A newly created session object is enabled.
    ++** Refer to the documentation for [sqlite3session_changeset()] for further
    ++** details regarding how enabling and disabling a session object affects
    ++** the eventual changesets.
    ++**
    ++** Passing zero to this function disables the session. Passing a value
    ++** greater than zero enables it. Passing a value less than zero is a 
    ++** no-op, and may be used to query the current state of the session.
    ++**
    ++** The return value indicates the final state of the session object: 0 if 
    ++** the session is disabled, or 1 if it is enabled.
    ++*/
    ++SQLITE_API int sqlite3session_enable(sqlite3_session *pSession, int bEnable);
    ++
    ++/*
    ++** CAPI3REF: Set Or Clear the Indirect Change Flag
    ++**
    ++** Each change recorded by a session object is marked as either direct or
    ++** indirect. A change is marked as indirect if either:
    ++**
    ++** <ul>
    ++**   <li> The session object "indirect" flag is set when the change is
    ++**        made, or
    ++**   <li> The change is made by an SQL trigger or foreign key action 
    ++**        instead of directly as a result of a users SQL statement.
    ++** </ul>
    ++**
    ++** If a single row is affected by more than one operation within a session,
    ++** then the change is considered indirect if all operations meet the criteria
    ++** for an indirect change above, or direct otherwise.
    ++**
    ++** This function is used to set, clear or query the session object indirect
    ++** flag.  If the second argument passed to this function is zero, then the
    ++** indirect flag is cleared. If it is greater than zero, the indirect flag
    ++** is set. Passing a value less than zero does not modify the current value
    ++** of the indirect flag, and may be used to query the current state of the 
    ++** indirect flag for the specified session object.
    ++**
    ++** The return value indicates the final state of the indirect flag: 0 if 
    ++** it is clear, or 1 if it is set.
    ++*/
    ++SQLITE_API int sqlite3session_indirect(sqlite3_session *pSession, int bIndirect);
    ++
    ++/*
    ++** CAPI3REF: Attach A Table To A Session Object
    ++**
    ++** If argument zTab is not NULL, then it is the name of a table to attach
    ++** to the session object passed as the first argument. All subsequent changes 
    ++** made to the table while the session object is enabled will be recorded. See 
    ++** documentation for [sqlite3session_changeset()] for further details.
    ++**
    ++** Or, if argument zTab is NULL, then changes are recorded for all tables
    ++** in the database. If additional tables are added to the database (by 
    ++** executing "CREATE TABLE" statements) after this call is made, changes for 
    ++** the new tables are also recorded.
    ++**
    ++** Changes can only be recorded for tables that have a PRIMARY KEY explicitly
    ++** defined as part of their CREATE TABLE statement. It does not matter if the 
    ++** PRIMARY KEY is an "INTEGER PRIMARY KEY" (rowid alias) or not. The PRIMARY
    ++** KEY may consist of a single column, or may be a composite key.
    ++** 
    ++** It is not an error if the named table does not exist in the database. Nor
    ++** is it an error if the named table does not have a PRIMARY KEY. However,
    ++** no changes will be recorded in either of these scenarios.
    ++**
    ++** Changes are not recorded for individual rows that have NULL values stored
    ++** in one or more of their PRIMARY KEY columns.
    ++**
    ++** SQLITE_OK is returned if the call completes without error. Or, if an error 
    ++** occurs, an SQLite error code (e.g. SQLITE_NOMEM) is returned.
    ++**
    ++** <h3>Special sqlite_stat1 Handling</h3>
    ++**
    ++** As of SQLite version 3.22.0, the "sqlite_stat1" table is an exception to 
    ++** some of the rules above. In SQLite, the schema of sqlite_stat1 is:
    ++**  <pre>
    ++**  &nbsp;     CREATE TABLE sqlite_stat1(tbl,idx,stat)  
    ++**  </pre>
    ++**
    ++** Even though sqlite_stat1 does not have a PRIMARY KEY, changes are 
    ++** recorded for it as if the PRIMARY KEY is (tbl,idx). Additionally, changes 
    ++** are recorded for rows for which (idx IS NULL) is true. However, for such
    ++** rows a zero-length blob (SQL value X'') is stored in the changeset or
    ++** patchset instead of a NULL value. This allows such changesets to be
    ++** manipulated by legacy implementations of sqlite3changeset_invert(),
    ++** concat() and similar.
    ++**
    ++** The sqlite3changeset_apply() function automatically converts the 
    ++** zero-length blob back to a NULL value when updating the sqlite_stat1
    ++** table. However, if the application calls sqlite3changeset_new(),
    ++** sqlite3changeset_old() or sqlite3changeset_conflict on a changeset 
    ++** iterator directly (including on a changeset iterator passed to a
    ++** conflict-handler callback) then the X'' value is returned. The application
    ++** must translate X'' to NULL itself if required.
    ++**
    ++** Legacy (older than 3.22.0) versions of the sessions module cannot capture
    ++** changes made to the sqlite_stat1 table. Legacy versions of the
    ++** sqlite3changeset_apply() function silently ignore any modifications to the
    ++** sqlite_stat1 table that are part of a changeset or patchset.
    ++*/
    ++SQLITE_API int sqlite3session_attach(
    ++  sqlite3_session *pSession,      /* Session object */
    ++  const char *zTab                /* Table name */
    ++);
    ++
    ++/*
    ++** CAPI3REF: Set a table filter on a Session Object.
    ++**
    ++** The second argument (xFilter) is the "filter callback". For changes to rows 
    ++** in tables that are not attached to the Session object, the filter is called
    ++** to determine whether changes to the table's rows should be tracked or not. 
    ++** If xFilter returns 0, changes is not tracked. Note that once a table is 
    ++** attached, xFilter will not be called again.
    ++*/
    ++SQLITE_API void sqlite3session_table_filter(
    ++  sqlite3_session *pSession,      /* Session object */
    ++  int(*xFilter)(
    ++    void *pCtx,                   /* Copy of third arg to _filter_table() */
    ++    const char *zTab              /* Table name */
    ++  ),
    ++  void *pCtx                      /* First argument passed to xFilter */
    ++);
    ++
    ++/*
    ++** CAPI3REF: Generate A Changeset From A Session Object
    ++**
    ++** Obtain a changeset containing changes to the tables attached to the 
    ++** session object passed as the first argument. If successful, 
    ++** set *ppChangeset to point to a buffer containing the changeset 
    ++** and *pnChangeset to the size of the changeset in bytes before returning
    ++** SQLITE_OK. If an error occurs, set both *ppChangeset and *pnChangeset to
    ++** zero and return an SQLite error code.
    ++**
    ++** A changeset consists of zero or more INSERT, UPDATE and/or DELETE changes,
    ++** each representing a change to a single row of an attached table. An INSERT
    ++** change contains the values of each field of a new database row. A DELETE
    ++** contains the original values of each field of a deleted database row. An
    ++** UPDATE change contains the original values of each field of an updated
    ++** database row along with the updated values for each updated non-primary-key
    ++** column. It is not possible for an UPDATE change to represent a change that
    ++** modifies the values of primary key columns. If such a change is made, it
    ++** is represented in a changeset as a DELETE followed by an INSERT.
    ++**
    ++** Changes are not recorded for rows that have NULL values stored in one or 
    ++** more of their PRIMARY KEY columns. If such a row is inserted or deleted,
    ++** no corresponding change is present in the changesets returned by this
    ++** function. If an existing row with one or more NULL values stored in
    ++** PRIMARY KEY columns is updated so that all PRIMARY KEY columns are non-NULL,
    ++** only an INSERT is appears in the changeset. Similarly, if an existing row
    ++** with non-NULL PRIMARY KEY values is updated so that one or more of its
    ++** PRIMARY KEY columns are set to NULL, the resulting changeset contains a
    ++** DELETE change only.
    ++**
    ++** The contents of a changeset may be traversed using an iterator created
    ++** using the [sqlite3changeset_start()] API. A changeset may be applied to
    ++** a database with a compatible schema using the [sqlite3changeset_apply()]
    ++** API.
    ++**
    ++** Within a changeset generated by this function, all changes related to a
    ++** single table are grouped together. In other words, when iterating through
    ++** a changeset or when applying a changeset to a database, all changes related
    ++** to a single table are processed before moving on to the next table. Tables
    ++** are sorted in the same order in which they were attached (or auto-attached)
    ++** to the sqlite3_session object. The order in which the changes related to
    ++** a single table are stored is undefined.
    ++**
    ++** Following a successful call to this function, it is the responsibility of
    ++** the caller to eventually free the buffer that *ppChangeset points to using
    ++** [sqlite3_free()].
    ++**
    ++** <h3>Changeset Generation</h3>
    ++**
    ++** Once a table has been attached to a session object, the session object
    ++** records the primary key values of all new rows inserted into the table.
    ++** It also records the original primary key and other column values of any
    ++** deleted or updated rows. For each unique primary key value, data is only
    ++** recorded once - the first time a row with said primary key is inserted,
    ++** updated or deleted in the lifetime of the session.
    ++**
    ++** There is one exception to the previous paragraph: when a row is inserted,
    ++** updated or deleted, if one or more of its primary key columns contain a
    ++** NULL value, no record of the change is made.
    ++**
    ++** The session object therefore accumulates two types of records - those
    ++** that consist of primary key values only (created when the user inserts
    ++** a new record) and those that consist of the primary key values and the
    ++** original values of other table columns (created when the users deletes
    ++** or updates a record).
    ++**
    ++** When this function is called, the requested changeset is created using
    ++** both the accumulated records and the current contents of the database
    ++** file. Specifically:
    ++**
    ++** <ul>
    ++**   <li> For each record generated by an insert, the database is queried
    ++**        for a row with a matching primary key. If one is found, an INSERT
    ++**        change is added to the changeset. If no such row is found, no change 
    ++**        is added to the changeset.
    ++**
    ++**   <li> For each record generated by an update or delete, the database is 
    ++**        queried for a row with a matching primary key. If such a row is
    ++**        found and one or more of the non-primary key fields have been
    ++**        modified from their original values, an UPDATE change is added to 
    ++**        the changeset. Or, if no such row is found in the table, a DELETE 
    ++**        change is added to the changeset. If there is a row with a matching
    ++**        primary key in the database, but all fields contain their original
    ++**        values, no change is added to the changeset.
    ++** </ul>
    ++**
    ++** This means, amongst other things, that if a row is inserted and then later
    ++** deleted while a session object is active, neither the insert nor the delete
    ++** will be present in the changeset. Or if a row is deleted and then later a 
    ++** row with the same primary key values inserted while a session object is
    ++** active, the resulting changeset will contain an UPDATE change instead of
    ++** a DELETE and an INSERT.
    ++**
    ++** When a session object is disabled (see the [sqlite3session_enable()] API),
    ++** it does not accumulate records when rows are inserted, updated or deleted.
    ++** This may appear to have some counter-intuitive effects if a single row
    ++** is written to more than once during a session. For example, if a row
    ++** is inserted while a session object is enabled, then later deleted while 
    ++** the same session object is disabled, no INSERT record will appear in the
    ++** changeset, even though the delete took place while the session was disabled.
    ++** Or, if one field of a row is updated while a session is disabled, and 
    ++** another field of the same row is updated while the session is enabled, the
    ++** resulting changeset will contain an UPDATE change that updates both fields.
    ++*/
    ++SQLITE_API int sqlite3session_changeset(
    ++  sqlite3_session *pSession,      /* Session object */
    ++  int *pnChangeset,               /* OUT: Size of buffer at *ppChangeset */
    ++  void **ppChangeset              /* OUT: Buffer containing changeset */
    ++);
    ++
    ++/*
    ++** CAPI3REF: Load The Difference Between Tables Into A Session 
    ++**
    ++** If it is not already attached to the session object passed as the first
    ++** argument, this function attaches table zTbl in the same manner as the
    ++** [sqlite3session_attach()] function. If zTbl does not exist, or if it
    ++** does not have a primary key, this function is a no-op (but does not return
    ++** an error).
    ++**
    ++** Argument zFromDb must be the name of a database ("main", "temp" etc.)
    ++** attached to the same database handle as the session object that contains 
    ++** a table compatible with the table attached to the session by this function.
    ++** A table is considered compatible if it:
    ++**
    ++** <ul>
    ++**   <li> Has the same name,
    ++**   <li> Has the same set of columns declared in the same order, and
    ++**   <li> Has the same PRIMARY KEY definition.
    ++** </ul>
    ++**
    ++** If the tables are not compatible, SQLITE_SCHEMA is returned. If the tables
    ++** are compatible but do not have any PRIMARY KEY columns, it is not an error
    ++** but no changes are added to the session object. As with other session
    ++** APIs, tables without PRIMARY KEYs are simply ignored.
    ++**
    ++** This function adds a set of changes to the session object that could be
    ++** used to update the table in database zFrom (call this the "from-table") 
    ++** so that its content is the same as the table attached to the session 
    ++** object (call this the "to-table"). Specifically:
    ++**
    ++** <ul>
    ++**   <li> For each row (primary key) that exists in the to-table but not in 
    ++**     the from-table, an INSERT record is added to the session object.
    ++**
    ++**   <li> For each row (primary key) that exists in the to-table but not in 
    ++**     the from-table, a DELETE record is added to the session object.
    ++**
    ++**   <li> For each row (primary key) that exists in both tables, but features 
    ++**     different non-PK values in each, an UPDATE record is added to the
    ++**     session.  
    ++** </ul>
    ++**
    ++** To clarify, if this function is called and then a changeset constructed
    ++** using [sqlite3session_changeset()], then after applying that changeset to 
    ++** database zFrom the contents of the two compatible tables would be 
    ++** identical.
    ++**
    ++** It an error if database zFrom does not exist or does not contain the
    ++** required compatible table.
    ++**
    ++** If the operation successful, SQLITE_OK is returned. Otherwise, an SQLite
    ++** error code. In this case, if argument pzErrMsg is not NULL, *pzErrMsg
    ++** may be set to point to a buffer containing an English language error 
    ++** message. It is the responsibility of the caller to free this buffer using
    ++** sqlite3_free().
    ++*/
    ++SQLITE_API int sqlite3session_diff(
    ++  sqlite3_session *pSession,
    ++  const char *zFromDb,
    ++  const char *zTbl,
    ++  char **pzErrMsg
    ++);
    ++
    ++
    ++/*
    ++** CAPI3REF: Generate A Patchset From A Session Object
    ++**
    ++** The differences between a patchset and a changeset are that:
    ++**
    ++** <ul>
    ++**   <li> DELETE records consist of the primary key fields only. The 
    ++**        original values of other fields are omitted.
    ++**   <li> The original values of any modified fields are omitted from 
    ++**        UPDATE records.
    ++** </ul>
    ++**
    ++** A patchset blob may be used with up to date versions of all 
    ++** sqlite3changeset_xxx API functions except for sqlite3changeset_invert(), 
    ++** which returns SQLITE_CORRUPT if it is passed a patchset. Similarly,
    ++** attempting to use a patchset blob with old versions of the
    ++** sqlite3changeset_xxx APIs also provokes an SQLITE_CORRUPT error. 
    ++**
    ++** Because the non-primary key "old.*" fields are omitted, no 
    ++** SQLITE_CHANGESET_DATA conflicts can be detected or reported if a patchset
    ++** is passed to the sqlite3changeset_apply() API. Other conflict types work
    ++** in the same way as for changesets.
    ++**
    ++** Changes within a patchset are ordered in the same way as for changesets
    ++** generated by the sqlite3session_changeset() function (i.e. all changes for
    ++** a single table are grouped together, tables appear in the order in which
    ++** they were attached to the session object).
    ++*/
    ++SQLITE_API int sqlite3session_patchset(
    ++  sqlite3_session *pSession,      /* Session object */
    ++  int *pnPatchset,                /* OUT: Size of buffer at *ppPatchset */
    ++  void **ppPatchset               /* OUT: Buffer containing patchset */
    ++);
    ++
    ++/*
    ++** CAPI3REF: Test if a changeset has recorded any changes.
    ++**
    ++** Return non-zero if no changes to attached tables have been recorded by 
    ++** the session object passed as the first argument. Otherwise, if one or 
    ++** more changes have been recorded, return zero.
    ++**
    ++** Even if this function returns zero, it is possible that calling
    ++** [sqlite3session_changeset()] on the session handle may still return a
    ++** changeset that contains no changes. This can happen when a row in 
    ++** an attached table is modified and then later on the original values 
    ++** are restored. However, if this function returns non-zero, then it is
    ++** guaranteed that a call to sqlite3session_changeset() will return a 
    ++** changeset containing zero changes.
    ++*/
    ++SQLITE_API int sqlite3session_isempty(sqlite3_session *pSession);
    ++
    ++/*
    ++** CAPI3REF: Create An Iterator To Traverse A Changeset 
    ++**
    ++** Create an iterator used to iterate through the contents of a changeset.
    ++** If successful, *pp is set to point to the iterator handle and SQLITE_OK
    ++** is returned. Otherwise, if an error occurs, *pp is set to zero and an
    ++** SQLite error code is returned.
    ++**
    ++** The following functions can be used to advance and query a changeset 
    ++** iterator created by this function:
    ++**
    ++** <ul>
    ++**   <li> [sqlite3changeset_next()]
    ++**   <li> [sqlite3changeset_op()]
    ++**   <li> [sqlite3changeset_new()]
    ++**   <li> [sqlite3changeset_old()]
    ++** </ul>
    ++**
    ++** It is the responsibility of the caller to eventually destroy the iterator
    ++** by passing it to [sqlite3changeset_finalize()]. The buffer containing the
    ++** changeset (pChangeset) must remain valid until after the iterator is
    ++** destroyed.
    ++**
    ++** Assuming the changeset blob was created by one of the
    ++** [sqlite3session_changeset()], [sqlite3changeset_concat()] or
    ++** [sqlite3changeset_invert()] functions, all changes within the changeset 
    ++** that apply to a single table are grouped together. This means that when 
    ++** an application iterates through a changeset using an iterator created by 
    ++** this function, all changes that relate to a single table are visited 
    ++** consecutively. There is no chance that the iterator will visit a change 
    ++** the applies to table X, then one for table Y, and then later on visit 
    ++** another change for table X.
    ++*/
    ++SQLITE_API int sqlite3changeset_start(
    ++  sqlite3_changeset_iter **pp,    /* OUT: New changeset iterator handle */
    ++  int nChangeset,                 /* Size of changeset blob in bytes */
    ++  void *pChangeset                /* Pointer to blob containing changeset */
    ++);
    ++
    ++
    ++/*
    ++** CAPI3REF: Advance A Changeset Iterator
    ++**
    ++** This function may only be used with iterators created by function
    ++** [sqlite3changeset_start()]. If it is called on an iterator passed to
    ++** a conflict-handler callback by [sqlite3changeset_apply()], SQLITE_MISUSE
    ++** is returned and the call has no effect.
    ++**
    ++** Immediately after an iterator is created by sqlite3changeset_start(), it
    ++** does not point to any change in the changeset. Assuming the changeset
    ++** is not empty, the first call to this function advances the iterator to
    ++** point to the first change in the changeset. Each subsequent call advances
    ++** the iterator to point to the next change in the changeset (if any). If
    ++** no error occurs and the iterator points to a valid change after a call
    ++** to sqlite3changeset_next() has advanced it, SQLITE_ROW is returned. 
    ++** Otherwise, if all changes in the changeset have already been visited,
    ++** SQLITE_DONE is returned.
    ++**
    ++** If an error occurs, an SQLite error code is returned. Possible error 
    ++** codes include SQLITE_CORRUPT (if the changeset buffer is corrupt) or 
    ++** SQLITE_NOMEM.
    ++*/
    ++SQLITE_API int sqlite3changeset_next(sqlite3_changeset_iter *pIter);
    ++
    ++/*
    ++** CAPI3REF: Obtain The Current Operation From A Changeset Iterator
    ++**
    ++** The pIter argument passed to this function may either be an iterator
    ++** passed to a conflict-handler by [sqlite3changeset_apply()], or an iterator
    ++** created by [sqlite3changeset_start()]. In the latter case, the most recent
    ++** call to [sqlite3changeset_next()] must have returned [SQLITE_ROW]. If this
    ++** is not the case, this function returns [SQLITE_MISUSE].
    ++**
    ++** If argument pzTab is not NULL, then *pzTab is set to point to a
    ++** nul-terminated utf-8 encoded string containing the name of the table
    ++** affected by the current change. The buffer remains valid until either
    ++** sqlite3changeset_next() is called on the iterator or until the 
    ++** conflict-handler function returns. If pnCol is not NULL, then *pnCol is 
    ++** set to the number of columns in the table affected by the change. If
    ++** pbIncorrect is not NULL, then *pbIndirect is set to true (1) if the change
    ++** is an indirect change, or false (0) otherwise. See the documentation for
    ++** [sqlite3session_indirect()] for a description of direct and indirect
    ++** changes. Finally, if pOp is not NULL, then *pOp is set to one of 
    ++** [SQLITE_INSERT], [SQLITE_DELETE] or [SQLITE_UPDATE], depending on the 
    ++** type of change that the iterator currently points to.
    ++**
    ++** If no error occurs, SQLITE_OK is returned. If an error does occur, an
    ++** SQLite error code is returned. The values of the output variables may not
    ++** be trusted in this case.
    ++*/
    ++SQLITE_API int sqlite3changeset_op(
    ++  sqlite3_changeset_iter *pIter,  /* Iterator object */
    ++  const char **pzTab,             /* OUT: Pointer to table name */
    ++  int *pnCol,                     /* OUT: Number of columns in table */
    ++  int *pOp,                       /* OUT: SQLITE_INSERT, DELETE or UPDATE */
    ++  int *pbIndirect                 /* OUT: True for an 'indirect' change */
    ++);
    ++
    ++/*
    ++** CAPI3REF: Obtain The Primary Key Definition Of A Table
    ++**
    ++** For each modified table, a changeset includes the following:
    ++**
    ++** <ul>
    ++**   <li> The number of columns in the table, and
    ++**   <li> Which of those columns make up the tables PRIMARY KEY.
    ++** </ul>
    ++**
    ++** This function is used to find which columns comprise the PRIMARY KEY of
    ++** the table modified by the change that iterator pIter currently points to.
    ++** If successful, *pabPK is set to point to an array of nCol entries, where
    ++** nCol is the number of columns in the table. Elements of *pabPK are set to
    ++** 0x01 if the corresponding column is part of the tables primary key, or
    ++** 0x00 if it is not.
    ++**
    ++** If argument pnCol is not NULL, then *pnCol is set to the number of columns
    ++** in the table.
    ++**
    ++** If this function is called when the iterator does not point to a valid
    ++** entry, SQLITE_MISUSE is returned and the output variables zeroed. Otherwise,
    ++** SQLITE_OK is returned and the output variables populated as described
    ++** above.
    ++*/
    ++SQLITE_API int sqlite3changeset_pk(
    ++  sqlite3_changeset_iter *pIter,  /* Iterator object */
    ++  unsigned char **pabPK,          /* OUT: Array of boolean - true for PK cols */
    ++  int *pnCol                      /* OUT: Number of entries in output array */
    ++);
    ++
    ++/*
    ++** CAPI3REF: Obtain old.* Values From A Changeset Iterator
    ++**
    ++** The pIter argument passed to this function may either be an iterator
    ++** passed to a conflict-handler by [sqlite3changeset_apply()], or an iterator
    ++** created by [sqlite3changeset_start()]. In the latter case, the most recent
    ++** call to [sqlite3changeset_next()] must have returned SQLITE_ROW. 
    ++** Furthermore, it may only be called if the type of change that the iterator
    ++** currently points to is either [SQLITE_DELETE] or [SQLITE_UPDATE]. Otherwise,
    ++** this function returns [SQLITE_MISUSE] and sets *ppValue to NULL.
    ++**
    ++** Argument iVal must be greater than or equal to 0, and less than the number
    ++** of columns in the table affected by the current change. Otherwise,
    ++** [SQLITE_RANGE] is returned and *ppValue is set to NULL.
    ++**
    ++** If successful, this function sets *ppValue to point to a protected
    ++** sqlite3_value object containing the iVal'th value from the vector of 
    ++** original row values stored as part of the UPDATE or DELETE change and
    ++** returns SQLITE_OK. The name of the function comes from the fact that this 
    ++** is similar to the "old.*" columns available to update or delete triggers.
    ++**
    ++** If some other error occurs (e.g. an OOM condition), an SQLite error code
    ++** is returned and *ppValue is set to NULL.
    ++*/
    ++SQLITE_API int sqlite3changeset_old(
    ++  sqlite3_changeset_iter *pIter,  /* Changeset iterator */
    ++  int iVal,                       /* Column number */
    ++  sqlite3_value **ppValue         /* OUT: Old value (or NULL pointer) */
    ++);
    ++
    ++/*
    ++** CAPI3REF: Obtain new.* Values From A Changeset Iterator
    ++**
    ++** The pIter argument passed to this function may either be an iterator
    ++** passed to a conflict-handler by [sqlite3changeset_apply()], or an iterator
    ++** created by [sqlite3changeset_start()]. In the latter case, the most recent
    ++** call to [sqlite3changeset_next()] must have returned SQLITE_ROW. 
    ++** Furthermore, it may only be called if the type of change that the iterator
    ++** currently points to is either [SQLITE_UPDATE] or [SQLITE_INSERT]. Otherwise,
    ++** this function returns [SQLITE_MISUSE] and sets *ppValue to NULL.
    ++**
    ++** Argument iVal must be greater than or equal to 0, and less than the number
    ++** of columns in the table affected by the current change. Otherwise,
    ++** [SQLITE_RANGE] is returned and *ppValue is set to NULL.
    ++**
    ++** If successful, this function sets *ppValue to point to a protected
    ++** sqlite3_value object containing the iVal'th value from the vector of 
    ++** new row values stored as part of the UPDATE or INSERT change and
    ++** returns SQLITE_OK. If the change is an UPDATE and does not include
    ++** a new value for the requested column, *ppValue is set to NULL and 
    ++** SQLITE_OK returned. The name of the function comes from the fact that 
    ++** this is similar to the "new.*" columns available to update or delete 
    ++** triggers.
    ++**
    ++** If some other error occurs (e.g. an OOM condition), an SQLite error code
    ++** is returned and *ppValue is set to NULL.
    ++*/
    ++SQLITE_API int sqlite3changeset_new(
    ++  sqlite3_changeset_iter *pIter,  /* Changeset iterator */
    ++  int iVal,                       /* Column number */
    ++  sqlite3_value **ppValue         /* OUT: New value (or NULL pointer) */
    ++);
    ++
    ++/*
    ++** CAPI3REF: Obtain Conflicting Row Values From A Changeset Iterator
    ++**
    ++** This function should only be used with iterator objects passed to a
    ++** conflict-handler callback by [sqlite3changeset_apply()] with either
    ++** [SQLITE_CHANGESET_DATA] or [SQLITE_CHANGESET_CONFLICT]. If this function
    ++** is called on any other iterator, [SQLITE_MISUSE] is returned and *ppValue
    ++** is set to NULL.
    ++**
    ++** Argument iVal must be greater than or equal to 0, and less than the number
    ++** of columns in the table affected by the current change. Otherwise,
    ++** [SQLITE_RANGE] is returned and *ppValue is set to NULL.
    ++**
    ++** If successful, this function sets *ppValue to point to a protected
    ++** sqlite3_value object containing the iVal'th value from the 
    ++** "conflicting row" associated with the current conflict-handler callback
    ++** and returns SQLITE_OK.
    ++**
    ++** If some other error occurs (e.g. an OOM condition), an SQLite error code
    ++** is returned and *ppValue is set to NULL.
    ++*/
    ++SQLITE_API int sqlite3changeset_conflict(
    ++  sqlite3_changeset_iter *pIter,  /* Changeset iterator */
    ++  int iVal,                       /* Column number */
    ++  sqlite3_value **ppValue         /* OUT: Value from conflicting row */
    ++);
    ++
    ++/*
    ++** CAPI3REF: Determine The Number Of Foreign Key Constraint Violations
    ++**
    ++** This function may only be called with an iterator passed to an
    ++** SQLITE_CHANGESET_FOREIGN_KEY conflict handler callback. In this case
    ++** it sets the output variable to the total number of known foreign key
    ++** violations in the destination database and returns SQLITE_OK.
    ++**
    ++** In all other cases this function returns SQLITE_MISUSE.
    ++*/
    ++SQLITE_API int sqlite3changeset_fk_conflicts(
    ++  sqlite3_changeset_iter *pIter,  /* Changeset iterator */
    ++  int *pnOut                      /* OUT: Number of FK violations */
    ++);
    ++
    ++
    ++/*
    ++** CAPI3REF: Finalize A Changeset Iterator
    ++**
    ++** This function is used to finalize an iterator allocated with
    ++** [sqlite3changeset_start()].
    ++**
    ++** This function should only be called on iterators created using the
    ++** [sqlite3changeset_start()] function. If an application calls this
    ++** function with an iterator passed to a conflict-handler by
    ++** [sqlite3changeset_apply()], [SQLITE_MISUSE] is immediately returned and the
    ++** call has no effect.
    ++**
    ++** If an error was encountered within a call to an sqlite3changeset_xxx()
    ++** function (for example an [SQLITE_CORRUPT] in [sqlite3changeset_next()] or an 
    ++** [SQLITE_NOMEM] in [sqlite3changeset_new()]) then an error code corresponding
    ++** to that error is returned by this function. Otherwise, SQLITE_OK is
    ++** returned. This is to allow the following pattern (pseudo-code):
    ++**
    ++**   sqlite3changeset_start();
    ++**   while( SQLITE_ROW==sqlite3changeset_next() ){
    ++**     // Do something with change.
    ++**   }
    ++**   rc = sqlite3changeset_finalize();
    ++**   if( rc!=SQLITE_OK ){
    ++**     // An error has occurred 
    ++**   }
    ++*/
    ++SQLITE_API int sqlite3changeset_finalize(sqlite3_changeset_iter *pIter);
    ++
    ++/*
    ++** CAPI3REF: Invert A Changeset
    ++**
    ++** This function is used to "invert" a changeset object. Applying an inverted
    ++** changeset to a database reverses the effects of applying the uninverted
    ++** changeset. Specifically:
    ++**
    ++** <ul>
    ++**   <li> Each DELETE change is changed to an INSERT, and
    ++**   <li> Each INSERT change is changed to a DELETE, and
    ++**   <li> For each UPDATE change, the old.* and new.* values are exchanged.
    ++** </ul>
    ++**
    ++** This function does not change the order in which changes appear within
    ++** the changeset. It merely reverses the sense of each individual change.
    ++**
    ++** If successful, a pointer to a buffer containing the inverted changeset
    ++** is stored in *ppOut, the size of the same buffer is stored in *pnOut, and
    ++** SQLITE_OK is returned. If an error occurs, both *pnOut and *ppOut are
    ++** zeroed and an SQLite error code returned.
    ++**
    ++** It is the responsibility of the caller to eventually call sqlite3_free()
    ++** on the *ppOut pointer to free the buffer allocation following a successful 
    ++** call to this function.
    ++**
    ++** WARNING/TODO: This function currently assumes that the input is a valid
    ++** changeset. If it is not, the results are undefined.
    ++*/
    ++SQLITE_API int sqlite3changeset_invert(
    ++  int nIn, const void *pIn,       /* Input changeset */
    ++  int *pnOut, void **ppOut        /* OUT: Inverse of input */
    ++);
    ++
    ++/*
    ++** CAPI3REF: Concatenate Two Changeset Objects
    ++**
    ++** This function is used to concatenate two changesets, A and B, into a 
    ++** single changeset. The result is a changeset equivalent to applying
    ++** changeset A followed by changeset B. 
    ++**
    ++** This function combines the two input changesets using an 
    ++** sqlite3_changegroup object. Calling it produces similar results as the
    ++** following code fragment:
    ++**
    ++**   sqlite3_changegroup *pGrp;
    ++**   rc = sqlite3_changegroup_new(&pGrp);
    ++**   if( rc==SQLITE_OK ) rc = sqlite3changegroup_add(pGrp, nA, pA);
    ++**   if( rc==SQLITE_OK ) rc = sqlite3changegroup_add(pGrp, nB, pB);
    ++**   if( rc==SQLITE_OK ){
    ++**     rc = sqlite3changegroup_output(pGrp, pnOut, ppOut);
    ++**   }else{
    ++**     *ppOut = 0;
    ++**     *pnOut = 0;
    ++**   }
    ++**
    ++** Refer to the sqlite3_changegroup documentation below for details.
    ++*/
    ++SQLITE_API int sqlite3changeset_concat(
    ++  int nA,                         /* Number of bytes in buffer pA */
    ++  void *pA,                       /* Pointer to buffer containing changeset A */
    ++  int nB,                         /* Number of bytes in buffer pB */
    ++  void *pB,                       /* Pointer to buffer containing changeset B */
    ++  int *pnOut,                     /* OUT: Number of bytes in output changeset */
    ++  void **ppOut                    /* OUT: Buffer containing output changeset */
    ++);
    ++
    ++
    ++/*
    ++** CAPI3REF: Changegroup Handle
    ++*/
    ++typedef struct sqlite3_changegroup sqlite3_changegroup;
    ++
    ++/*
    ++** CAPI3REF: Create A New Changegroup Object
    ++**
    ++** An sqlite3_changegroup object is used to combine two or more changesets
    ++** (or patchsets) into a single changeset (or patchset). A single changegroup
    ++** object may combine changesets or patchsets, but not both. The output is
    ++** always in the same format as the input.
    ++**
    ++** If successful, this function returns SQLITE_OK and populates (*pp) with
    ++** a pointer to a new sqlite3_changegroup object before returning. The caller
    ++** should eventually free the returned object using a call to 
    ++** sqlite3changegroup_delete(). If an error occurs, an SQLite error code
    ++** (i.e. SQLITE_NOMEM) is returned and *pp is set to NULL.
    ++**
    ++** The usual usage pattern for an sqlite3_changegroup object is as follows:
    ++**
    ++** <ul>
    ++**   <li> It is created using a call to sqlite3changegroup_new().
    ++**
    ++**   <li> Zero or more changesets (or patchsets) are added to the object
    ++**        by calling sqlite3changegroup_add().
    ++**
    ++**   <li> The result of combining all input changesets together is obtained 
    ++**        by the application via a call to sqlite3changegroup_output().
    ++**
    ++**   <li> The object is deleted using a call to sqlite3changegroup_delete().
    ++** </ul>
    ++**
    ++** Any number of calls to add() and output() may be made between the calls to
    ++** new() and delete(), and in any order.
    ++**
    ++** As well as the regular sqlite3changegroup_add() and 
    ++** sqlite3changegroup_output() functions, also available are the streaming
    ++** versions sqlite3changegroup_add_strm() and sqlite3changegroup_output_strm().
    ++*/
    ++SQLITE_API int sqlite3changegroup_new(sqlite3_changegroup **pp);
    ++
    ++/*
    ++** CAPI3REF: Add A Changeset To A Changegroup
    ++**
    ++** Add all changes within the changeset (or patchset) in buffer pData (size
    ++** nData bytes) to the changegroup. 
    ++**
    ++** If the buffer contains a patchset, then all prior calls to this function
    ++** on the same changegroup object must also have specified patchsets. Or, if
    ++** the buffer contains a changeset, so must have the earlier calls to this
    ++** function. Otherwise, SQLITE_ERROR is returned and no changes are added
    ++** to the changegroup.
    ++**
    ++** Rows within the changeset and changegroup are identified by the values in
    ++** their PRIMARY KEY columns. A change in the changeset is considered to
    ++** apply to the same row as a change already present in the changegroup if
    ++** the two rows have the same primary key.
    ++**
    ++** Changes to rows that do not already appear in the changegroup are
    ++** simply copied into it. Or, if both the new changeset and the changegroup
    ++** contain changes that apply to a single row, the final contents of the
    ++** changegroup depends on the type of each change, as follows:
    ++**
    ++** <table border=1 style="margin-left:8ex;margin-right:8ex">
    ++**   <tr><th style="white-space:pre">Existing Change  </th>
    ++**       <th style="white-space:pre">New Change       </th>
    ++**       <th>Output Change
    ++**   <tr><td>INSERT <td>INSERT <td>
    ++**       The new change is ignored. This case does not occur if the new
    ++**       changeset was recorded immediately after the changesets already
    ++**       added to the changegroup.
    ++**   <tr><td>INSERT <td>UPDATE <td>
    ++**       The INSERT change remains in the changegroup. The values in the 
    ++**       INSERT change are modified as if the row was inserted by the
    ++**       existing change and then updated according to the new change.
    ++**   <tr><td>INSERT <td>DELETE <td>
    ++**       The existing INSERT is removed from the changegroup. The DELETE is
    ++**       not added.
    ++**   <tr><td>UPDATE <td>INSERT <td>
    ++**       The new change is ignored. This case does not occur if the new
    ++**       changeset was recorded immediately after the changesets already
    ++**       added to the changegroup.
    ++**   <tr><td>UPDATE <td>UPDATE <td>
    ++**       The existing UPDATE remains within the changegroup. It is amended 
    ++**       so that the accompanying values are as if the row was updated once 
    ++**       by the existing change and then again by the new change.
    ++**   <tr><td>UPDATE <td>DELETE <td>
    ++**       The existing UPDATE is replaced by the new DELETE within the
    ++**       changegroup.
    ++**   <tr><td>DELETE <td>INSERT <td>
    ++**       If one or more of the column values in the row inserted by the
    ++**       new change differ from those in the row deleted by the existing 
    ++**       change, the existing DELETE is replaced by an UPDATE within the
    ++**       changegroup. Otherwise, if the inserted row is exactly the same 
    ++**       as the deleted row, the existing DELETE is simply discarded.
    ++**   <tr><td>DELETE <td>UPDATE <td>
    ++**       The new change is ignored. This case does not occur if the new
    ++**       changeset was recorded immediately after the changesets already
    ++**       added to the changegroup.
    ++**   <tr><td>DELETE <td>DELETE <td>
    ++**       The new change is ignored. This case does not occur if the new
    ++**       changeset was recorded immediately after the changesets already
    ++**       added to the changegroup.
    ++** </table>
    ++**
    ++** If the new changeset contains changes to a table that is already present
    ++** in the changegroup, then the number of columns and the position of the
    ++** primary key columns for the table must be consistent. If this is not the
    ++** case, this function fails with SQLITE_SCHEMA. If the input changeset
    ++** appears to be corrupt and the corruption is detected, SQLITE_CORRUPT is
    ++** returned. Or, if an out-of-memory condition occurs during processing, this
    ++** function returns SQLITE_NOMEM. In all cases, if an error occurs the
    ++** final contents of the changegroup is undefined.
    ++**
    ++** If no error occurs, SQLITE_OK is returned.
    ++*/
    ++SQLITE_API int sqlite3changegroup_add(sqlite3_changegroup*, int nData, void *pData);
    ++
    ++/*
    ++** CAPI3REF: Obtain A Composite Changeset From A Changegroup
    ++**
    ++** Obtain a buffer containing a changeset (or patchset) representing the
    ++** current contents of the changegroup. If the inputs to the changegroup
    ++** were themselves changesets, the output is a changeset. Or, if the
    ++** inputs were patchsets, the output is also a patchset.
    ++**
    ++** As with the output of the sqlite3session_changeset() and
    ++** sqlite3session_patchset() functions, all changes related to a single
    ++** table are grouped together in the output of this function. Tables appear
    ++** in the same order as for the very first changeset added to the changegroup.
    ++** If the second or subsequent changesets added to the changegroup contain
    ++** changes for tables that do not appear in the first changeset, they are
    ++** appended onto the end of the output changeset, again in the order in
    ++** which they are first encountered.
    ++**
    ++** If an error occurs, an SQLite error code is returned and the output
    ++** variables (*pnData) and (*ppData) are set to 0. Otherwise, SQLITE_OK
    ++** is returned and the output variables are set to the size of and a 
    ++** pointer to the output buffer, respectively. In this case it is the
    ++** responsibility of the caller to eventually free the buffer using a
    ++** call to sqlite3_free().
    ++*/
    ++SQLITE_API int sqlite3changegroup_output(
    ++  sqlite3_changegroup*,
    ++  int *pnData,                    /* OUT: Size of output buffer in bytes */
    ++  void **ppData                   /* OUT: Pointer to output buffer */
    ++);
    ++
    ++/*
    ++** CAPI3REF: Delete A Changegroup Object
    ++*/
    ++SQLITE_API void sqlite3changegroup_delete(sqlite3_changegroup*);
    ++
    ++/*
    ++** CAPI3REF: Apply A Changeset To A Database
    ++**
    ++** Apply a changeset to a database. This function attempts to update the
    ++** "main" database attached to handle db with the changes found in the
    ++** changeset passed via the second and third arguments.
    ++**
    ++** The fourth argument (xFilter) passed to this function is the "filter
    ++** callback". If it is not NULL, then for each table affected by at least one
    ++** change in the changeset, the filter callback is invoked with
    ++** the table name as the second argument, and a copy of the context pointer
    ++** passed as the sixth argument to this function as the first. If the "filter
    ++** callback" returns zero, then no attempt is made to apply any changes to 
    ++** the table. Otherwise, if the return value is non-zero or the xFilter
    ++** argument to this function is NULL, all changes related to the table are
    ++** attempted.
    ++**
    ++** For each table that is not excluded by the filter callback, this function 
    ++** tests that the target database contains a compatible table. A table is 
    ++** considered compatible if all of the following are true:
    ++**
    ++** <ul>
    ++**   <li> The table has the same name as the name recorded in the 
    ++**        changeset, and
    ++**   <li> The table has at least as many columns as recorded in the 
    ++**        changeset, and
    ++**   <li> The table has primary key columns in the same position as 
    ++**        recorded in the changeset.
    ++** </ul>
    ++**
    ++** If there is no compatible table, it is not an error, but none of the
    ++** changes associated with the table are applied. A warning message is issued
    ++** via the sqlite3_log() mechanism with the error code SQLITE_SCHEMA. At most
    ++** one such warning is issued for each table in the changeset.
    ++**
    ++** For each change for which there is a compatible table, an attempt is made 
    ++** to modify the table contents according to the UPDATE, INSERT or DELETE 
    ++** change. If a change cannot be applied cleanly, the conflict handler 
    ++** function passed as the fifth argument to sqlite3changeset_apply() may be 
    ++** invoked. A description of exactly when the conflict handler is invoked for 
    ++** each type of change is below.
    ++**
    ++** Unlike the xFilter argument, xConflict may not be passed NULL. The results
    ++** of passing anything other than a valid function pointer as the xConflict
    ++** argument are undefined.
    ++**
    ++** Each time the conflict handler function is invoked, it must return one
    ++** of [SQLITE_CHANGESET_OMIT], [SQLITE_CHANGESET_ABORT] or 
    ++** [SQLITE_CHANGESET_REPLACE]. SQLITE_CHANGESET_REPLACE may only be returned
    ++** if the second argument passed to the conflict handler is either
    ++** SQLITE_CHANGESET_DATA or SQLITE_CHANGESET_CONFLICT. If the conflict-handler
    ++** returns an illegal value, any changes already made are rolled back and
    ++** the call to sqlite3changeset_apply() returns SQLITE_MISUSE. Different 
    ++** actions are taken by sqlite3changeset_apply() depending on the value
    ++** returned by each invocation of the conflict-handler function. Refer to
    ++** the documentation for the three 
    ++** [SQLITE_CHANGESET_OMIT|available return values] for details.
    ++**
    ++** <dl>
    ++** <dt>DELETE Changes<dd>
    ++**   For each DELETE change, this function checks if the target database 
    ++**   contains a row with the same primary key value (or values) as the 
    ++**   original row values stored in the changeset. If it does, and the values 
    ++**   stored in all non-primary key columns also match the values stored in 
    ++**   the changeset the row is deleted from the target database.
    ++**
    ++**   If a row with matching primary key values is found, but one or more of
    ++**   the non-primary key fields contains a value different from the original
    ++**   row value stored in the changeset, the conflict-handler function is
    ++**   invoked with [SQLITE_CHANGESET_DATA] as the second argument. If the
    ++**   database table has more columns than are recorded in the changeset,
    ++**   only the values of those non-primary key fields are compared against
    ++**   the current database contents - any trailing database table columns
    ++**   are ignored.
    ++**
    ++**   If no row with matching primary key values is found in the database,
    ++**   the conflict-handler function is invoked with [SQLITE_CHANGESET_NOTFOUND]
    ++**   passed as the second argument.
    ++**
    ++**   If the DELETE operation is attempted, but SQLite returns SQLITE_CONSTRAINT
    ++**   (which can only happen if a foreign key constraint is violated), the
    ++**   conflict-handler function is invoked with [SQLITE_CHANGESET_CONSTRAINT]
    ++**   passed as the second argument. This includes the case where the DELETE
    ++**   operation is attempted because an earlier call to the conflict handler
    ++**   function returned [SQLITE_CHANGESET_REPLACE].
    ++**
    ++** <dt>INSERT Changes<dd>
    ++**   For each INSERT change, an attempt is made to insert the new row into
    ++**   the database. If the changeset row contains fewer fields than the
    ++**   database table, the trailing fields are populated with their default
    ++**   values.
    ++**
    ++**   If the attempt to insert the row fails because the database already 
    ++**   contains a row with the same primary key values, the conflict handler
    ++**   function is invoked with the second argument set to 
    ++**   [SQLITE_CHANGESET_CONFLICT].
    ++**
    ++**   If the attempt to insert the row fails because of some other constraint
    ++**   violation (e.g. NOT NULL or UNIQUE), the conflict handler function is 
    ++**   invoked with the second argument set to [SQLITE_CHANGESET_CONSTRAINT].
    ++**   This includes the case where the INSERT operation is re-attempted because 
    ++**   an earlier call to the conflict handler function returned 
    ++**   [SQLITE_CHANGESET_REPLACE].
    ++**
    ++** <dt>UPDATE Changes<dd>
    ++**   For each UPDATE change, this function checks if the target database 
    ++**   contains a row with the same primary key value (or values) as the 
    ++**   original row values stored in the changeset. If it does, and the values 
    ++**   stored in all modified non-primary key columns also match the values
    ++**   stored in the changeset the row is updated within the target database.
    ++**
    ++**   If a row with matching primary key values is found, but one or more of
    ++**   the modified non-primary key fields contains a value different from an
    ++**   original row value stored in the changeset, the conflict-handler function
    ++**   is invoked with [SQLITE_CHANGESET_DATA] as the second argument. Since
    ++**   UPDATE changes only contain values for non-primary key fields that are
    ++**   to be modified, only those fields need to match the original values to
    ++**   avoid the SQLITE_CHANGESET_DATA conflict-handler callback.
    ++**
    ++**   If no row with matching primary key values is found in the database,
    ++**   the conflict-handler function is invoked with [SQLITE_CHANGESET_NOTFOUND]
    ++**   passed as the second argument.
    ++**
    ++**   If the UPDATE operation is attempted, but SQLite returns 
    ++**   SQLITE_CONSTRAINT, the conflict-handler function is invoked with 
    ++**   [SQLITE_CHANGESET_CONSTRAINT] passed as the second argument.
    ++**   This includes the case where the UPDATE operation is attempted after 
    ++**   an earlier call to the conflict handler function returned
    ++**   [SQLITE_CHANGESET_REPLACE].  
    ++** </dl>
    ++**
    ++** It is safe to execute SQL statements, including those that write to the
    ++** table that the callback related to, from within the xConflict callback.
    ++** This can be used to further customize the applications conflict
    ++** resolution strategy.
    ++**
    ++** All changes made by this function are enclosed in a savepoint transaction.
    ++** If any other error (aside from a constraint failure when attempting to
    ++** write to the target database) occurs, then the savepoint transaction is
    ++** rolled back, restoring the target database to its original state, and an 
    ++** SQLite error code returned.
    ++*/
    ++SQLITE_API int sqlite3changeset_apply(
    ++  sqlite3 *db,                    /* Apply change to "main" db of this handle */
    ++  int nChangeset,                 /* Size of changeset in bytes */
    ++  void *pChangeset,               /* Changeset blob */
    ++  int(*xFilter)(
    ++    void *pCtx,                   /* Copy of sixth arg to _apply() */
    ++    const char *zTab              /* Table name */
    ++  ),
    ++  int(*xConflict)(
    ++    void *pCtx,                   /* Copy of sixth arg to _apply() */
    ++    int eConflict,                /* DATA, MISSING, CONFLICT, CONSTRAINT */
    ++    sqlite3_changeset_iter *p     /* Handle describing change and conflict */
    ++  ),
    ++  void *pCtx                      /* First argument passed to xConflict */
    ++);
    ++
    ++/* 
    ++** CAPI3REF: Constants Passed To The Conflict Handler
    ++**
    ++** Values that may be passed as the second argument to a conflict-handler.
    ++**
    ++** <dl>
    ++** <dt>SQLITE_CHANGESET_DATA<dd>
    ++**   The conflict handler is invoked with CHANGESET_DATA as the second argument
    ++**   when processing a DELETE or UPDATE change if a row with the required
    ++**   PRIMARY KEY fields is present in the database, but one or more other 
    ++**   (non primary-key) fields modified by the update do not contain the 
    ++**   expected "before" values.
    ++** 
    ++**   The conflicting row, in this case, is the database row with the matching
    ++**   primary key.
    ++** 
    ++** <dt>SQLITE_CHANGESET_NOTFOUND<dd>
    ++**   The conflict handler is invoked with CHANGESET_NOTFOUND as the second
    ++**   argument when processing a DELETE or UPDATE change if a row with the
    ++**   required PRIMARY KEY fields is not present in the database.
    ++** 
    ++**   There is no conflicting row in this case. The results of invoking the
    ++**   sqlite3changeset_conflict() API are undefined.
    ++** 
    ++** <dt>SQLITE_CHANGESET_CONFLICT<dd>
    ++**   CHANGESET_CONFLICT is passed as the second argument to the conflict
    ++**   handler while processing an INSERT change if the operation would result 
    ++**   in duplicate primary key values.
    ++** 
    ++**   The conflicting row in this case is the database row with the matching
    ++**   primary key.
    ++**
    ++** <dt>SQLITE_CHANGESET_FOREIGN_KEY<dd>
    ++**   If foreign key handling is enabled, and applying a changeset leaves the
    ++**   database in a state containing foreign key violations, the conflict 
    ++**   handler is invoked with CHANGESET_FOREIGN_KEY as the second argument
    ++**   exactly once before the changeset is committed. If the conflict handler
    ++**   returns CHANGESET_OMIT, the changes, including those that caused the
    ++**   foreign key constraint violation, are committed. Or, if it returns
    ++**   CHANGESET_ABORT, the changeset is rolled back.
    ++**
    ++**   No current or conflicting row information is provided. The only function
    ++**   it is possible to call on the supplied sqlite3_changeset_iter handle
    ++**   is sqlite3changeset_fk_conflicts().
    ++** 
    ++** <dt>SQLITE_CHANGESET_CONSTRAINT<dd>
    ++**   If any other constraint violation occurs while applying a change (i.e. 
    ++**   a UNIQUE, CHECK or NOT NULL constraint), the conflict handler is 
    ++**   invoked with CHANGESET_CONSTRAINT as the second argument.
    ++** 
    ++**   There is no conflicting row in this case. The results of invoking the
    ++**   sqlite3changeset_conflict() API are undefined.
    ++**
    ++** </dl>
    ++*/
    ++#define SQLITE_CHANGESET_DATA        1
    ++#define SQLITE_CHANGESET_NOTFOUND    2
    ++#define SQLITE_CHANGESET_CONFLICT    3
    ++#define SQLITE_CHANGESET_CONSTRAINT  4
    ++#define SQLITE_CHANGESET_FOREIGN_KEY 5
    ++
    ++/* 
    ++** CAPI3REF: Constants Returned By The Conflict Handler
    ++**
    ++** A conflict handler callback must return one of the following three values.
    ++**
    ++** <dl>
    ++** <dt>SQLITE_CHANGESET_OMIT<dd>
    ++**   If a conflict handler returns this value no special action is taken. The
    ++**   change that caused the conflict is not applied. The session module 
    ++**   continues to the next change in the changeset.
    ++**
    ++** <dt>SQLITE_CHANGESET_REPLACE<dd>
    ++**   This value may only be returned if the second argument to the conflict
    ++**   handler was SQLITE_CHANGESET_DATA or SQLITE_CHANGESET_CONFLICT. If this
    ++**   is not the case, any changes applied so far are rolled back and the 
    ++**   call to sqlite3changeset_apply() returns SQLITE_MISUSE.
    ++**
    ++**   If CHANGESET_REPLACE is returned by an SQLITE_CHANGESET_DATA conflict
    ++**   handler, then the conflicting row is either updated or deleted, depending
    ++**   on the type of change.
    ++**
    ++**   If CHANGESET_REPLACE is returned by an SQLITE_CHANGESET_CONFLICT conflict
    ++**   handler, then the conflicting row is removed from the database and a
    ++**   second attempt to apply the change is made. If this second attempt fails,
    ++**   the original row is restored to the database before continuing.
    ++**
    ++** <dt>SQLITE_CHANGESET_ABORT<dd>
    ++**   If this value is returned, any changes applied so far are rolled back 
    ++**   and the call to sqlite3changeset_apply() returns SQLITE_ABORT.
    ++** </dl>
    ++*/
    ++#define SQLITE_CHANGESET_OMIT       0
    ++#define SQLITE_CHANGESET_REPLACE    1
    ++#define SQLITE_CHANGESET_ABORT      2
    ++
    ++/*
    ++** CAPI3REF: Streaming Versions of API functions.
    ++**
    ++** The six streaming API xxx_strm() functions serve similar purposes to the 
    ++** corresponding non-streaming API functions:
    ++**
    ++** <table border=1 style="margin-left:8ex;margin-right:8ex">
    ++**   <tr><th>Streaming function<th>Non-streaming equivalent</th>
    ++**   <tr><td>sqlite3changeset_apply_strm<td>[sqlite3changeset_apply] 
    ++**   <tr><td>sqlite3changeset_concat_strm<td>[sqlite3changeset_concat] 
    ++**   <tr><td>sqlite3changeset_invert_strm<td>[sqlite3changeset_invert] 
    ++**   <tr><td>sqlite3changeset_start_strm<td>[sqlite3changeset_start] 
    ++**   <tr><td>sqlite3session_changeset_strm<td>[sqlite3session_changeset] 
    ++**   <tr><td>sqlite3session_patchset_strm<td>[sqlite3session_patchset] 
    ++** </table>
    ++**
    ++** Non-streaming functions that accept changesets (or patchsets) as input
    ++** require that the entire changeset be stored in a single buffer in memory. 
    ++** Similarly, those that return a changeset or patchset do so by returning 
    ++** a pointer to a single large buffer allocated using sqlite3_malloc(). 
    ++** Normally this is convenient. However, if an application running in a 
    ++** low-memory environment is required to handle very large changesets, the
    ++** large contiguous memory allocations required can become onerous.
    ++**
    ++** In order to avoid this problem, instead of a single large buffer, input
    ++** is passed to a streaming API functions by way of a callback function that
    ++** the sessions module invokes to incrementally request input data as it is
    ++** required. In all cases, a pair of API function parameters such as
    ++**
    ++**  <pre>
    ++**  &nbsp;     int nChangeset,
    ++**  &nbsp;     void *pChangeset,
    ++**  </pre>
    ++**
    ++** Is replaced by:
    ++**
    ++**  <pre>
    ++**  &nbsp;     int (*xInput)(void *pIn, void *pData, int *pnData),
    ++**  &nbsp;     void *pIn,
    ++**  </pre>
    ++**
    ++** Each time the xInput callback is invoked by the sessions module, the first
    ++** argument passed is a copy of the supplied pIn context pointer. The second 
    ++** argument, pData, points to a buffer (*pnData) bytes in size. Assuming no 
    ++** error occurs the xInput method should copy up to (*pnData) bytes of data 
    ++** into the buffer and set (*pnData) to the actual number of bytes copied 
    ++** before returning SQLITE_OK. If the input is completely exhausted, (*pnData) 
    ++** should be set to zero to indicate this. Or, if an error occurs, an SQLite 
    ++** error code should be returned. In all cases, if an xInput callback returns
    ++** an error, all processing is abandoned and the streaming API function
    ++** returns a copy of the error code to the caller.
    ++**
    ++** In the case of sqlite3changeset_start_strm(), the xInput callback may be
    ++** invoked by the sessions module at any point during the lifetime of the
    ++** iterator. If such an xInput callback returns an error, the iterator enters
    ++** an error state, whereby all subsequent calls to iterator functions 
    ++** immediately fail with the same error code as returned by xInput.
    ++**
    ++** Similarly, streaming API functions that return changesets (or patchsets)
    ++** return them in chunks by way of a callback function instead of via a
    ++** pointer to a single large buffer. In this case, a pair of parameters such
    ++** as:
    ++**
    ++**  <pre>
    ++**  &nbsp;     int *pnChangeset,
    ++**  &nbsp;     void **ppChangeset,
    ++**  </pre>
    ++**
    ++** Is replaced by:
    ++**
    ++**  <pre>
    ++**  &nbsp;     int (*xOutput)(void *pOut, const void *pData, int nData),
    ++**  &nbsp;     void *pOut
    ++**  </pre>
    ++**
    ++** The xOutput callback is invoked zero or more times to return data to
    ++** the application. The first parameter passed to each call is a copy of the
    ++** pOut pointer supplied by the application. The second parameter, pData,
    ++** points to a buffer nData bytes in size containing the chunk of output
    ++** data being returned. If the xOutput callback successfully processes the
    ++** supplied data, it should return SQLITE_OK to indicate success. Otherwise,
    ++** it should return some other SQLite error code. In this case processing
    ++** is immediately abandoned and the streaming API function returns a copy
    ++** of the xOutput error code to the application.
    ++**
    ++** The sessions module never invokes an xOutput callback with the third 
    ++** parameter set to a value less than or equal to zero. Other than this,
    ++** no guarantees are made as to the size of the chunks of data returned.
    ++*/
    ++SQLITE_API int sqlite3changeset_apply_strm(
    ++  sqlite3 *db,                    /* Apply change to "main" db of this handle */
    ++  int (*xInput)(void *pIn, void *pData, int *pnData), /* Input function */
    ++  void *pIn,                                          /* First arg for xInput */
    ++  int(*xFilter)(
    ++    void *pCtx,                   /* Copy of sixth arg to _apply() */
    ++    const char *zTab              /* Table name */
    ++  ),
    ++  int(*xConflict)(
    ++    void *pCtx,                   /* Copy of sixth arg to _apply() */
    ++    int eConflict,                /* DATA, MISSING, CONFLICT, CONSTRAINT */
    ++    sqlite3_changeset_iter *p     /* Handle describing change and conflict */
    ++  ),
    ++  void *pCtx                      /* First argument passed to xConflict */
    ++);
    ++SQLITE_API int sqlite3changeset_concat_strm(
    ++  int (*xInputA)(void *pIn, void *pData, int *pnData),
    ++  void *pInA,
    ++  int (*xInputB)(void *pIn, void *pData, int *pnData),
    ++  void *pInB,
    ++  int (*xOutput)(void *pOut, const void *pData, int nData),
    ++  void *pOut
    ++);
    ++SQLITE_API int sqlite3changeset_invert_strm(
    ++  int (*xInput)(void *pIn, void *pData, int *pnData),
    ++  void *pIn,
    ++  int (*xOutput)(void *pOut, const void *pData, int nData),
    ++  void *pOut
    ++);
    ++SQLITE_API int sqlite3changeset_start_strm(
    ++  sqlite3_changeset_iter **pp,
    ++  int (*xInput)(void *pIn, void *pData, int *pnData),
    ++  void *pIn
    ++);
    ++SQLITE_API int sqlite3session_changeset_strm(
    ++  sqlite3_session *pSession,
    ++  int (*xOutput)(void *pOut, const void *pData, int nData),
    ++  void *pOut
    ++);
    ++SQLITE_API int sqlite3session_patchset_strm(
    ++  sqlite3_session *pSession,
    ++  int (*xOutput)(void *pOut, const void *pData, int nData),
    ++  void *pOut
    ++);
    ++SQLITE_API int sqlite3changegroup_add_strm(sqlite3_changegroup*, 
    ++    int (*xInput)(void *pIn, void *pData, int *pnData),
    ++    void *pIn
    ++);
    ++SQLITE_API int sqlite3changegroup_output_strm(sqlite3_changegroup*,
    ++    int (*xOutput)(void *pOut, const void *pData, int nData), 
    ++    void *pOut
    ++);
    ++
    ++
    ++/*
    ++** Make sure we can call this stuff from C++.
    ++*/
    ++#ifdef __cplusplus
    ++}
    ++#endif
    ++
    ++#endif  /* !defined(__SQLITESESSION_H_) && defined(SQLITE_ENABLE_SESSION) */
    ++
    ++/******** End of sqlite3session.h *********/
    ++/******** Begin file fts5.h *********/
    + /*
    + ** 2014 May 31
    + **
    +@@ -8006,6 +10330,9 @@ struct Fts5PhraseIter {
    + **   an OOM condition or IO error), an appropriate SQLite error code is 
    + **   returned.
    + **
    ++**   This function may be quite inefficient if used with an FTS5 table
    ++**   created with the "columnsize=0" option.
    ++**
    + ** xColumnText:
    + **   This function attempts to retrieve the text of column iCol of the
    + **   current document. If successful, (*pz) is set to point to a buffer
    +@@ -8026,15 +10353,29 @@ struct Fts5PhraseIter {
    + **   the query within the current row. Return SQLITE_OK if successful, or
    + **   an error code (i.e. SQLITE_NOMEM) if an error occurs.
    + **
    ++**   This API can be quite slow if used with an FTS5 table created with the
    ++**   "detail=none" or "detail=column" option. If the FTS5 table is created 
    ++**   with either "detail=none" or "detail=column" and "content=" option 
    ++**   (i.e. if it is a contentless table), then this API always returns 0.
    ++**
    + ** xInst:
    + **   Query for the details of phrase match iIdx within the current row.
    + **   Phrase matches are numbered starting from zero, so the iIdx argument
    + **   should be greater than or equal to zero and smaller than the value
    + **   output by xInstCount().
    + **
    ++**   Usually, output parameter *piPhrase is set to the phrase number, *piCol
    ++**   to the column in which it occurs and *piOff the token offset of the
    ++**   first token of the phrase. The exception is if the table was created
    ++**   with the offsets=0 option specified. In this case *piOff is always
    ++**   set to -1.
    ++**
    + **   Returns SQLITE_OK if successful, or an error code (i.e. SQLITE_NOMEM) 
    + **   if an error occurs.
    + **
    ++**   This API can be quite slow if used with an FTS5 table created with the
    ++**   "detail=none" or "detail=column" option. 
    ++**
    + ** xRowid:
    + **   Returns the rowid of the current row.
    + **
    +@@ -8048,11 +10389,13 @@ struct Fts5PhraseIter {
    + **       ... FROM ftstable WHERE ftstable MATCH $p ORDER BY rowid
    + **
    + **   with $p set to a phrase equivalent to the phrase iPhrase of the
    +-**   current query is executed. For each row visited, the callback function
    +-**   passed as the fourth argument is invoked. The context and API objects 
    +-**   passed to the callback function may be used to access the properties of
    +-**   each matched row. Invoking Api.xUserData() returns a copy of the pointer
    +-**   passed as the third argument to pUserData.
    ++**   current query is executed. Any column filter that applies to
    ++**   phrase iPhrase of the current query is included in $p. For each 
    ++**   row visited, the callback function passed as the fourth argument 
    ++**   is invoked. The context and API objects passed to the callback 
    ++**   function may be used to access the properties of each matched row.
    ++**   Invoking Api.xUserData() returns a copy of the pointer passed as 
    ++**   the third argument to pUserData.
    + **
    + **   If the callback function returns any value other than SQLITE_OK, the
    + **   query is abandoned and the xQueryPhrase function returns immediately.
    +@@ -8118,7 +10461,7 @@ struct Fts5PhraseIter {
    + **       Fts5PhraseIter iter;
    + **       int iCol, iOff;
    + **       for(pApi->xPhraseFirst(pFts, iPhrase, &iter, &iCol, &iOff);
    +-**           iOff>=0;
    ++**           iCol>=0;
    + **           pApi->xPhraseNext(pFts, &iter, &iCol, &iOff)
    + **       ){
    + **         // An instance of phrase iPhrase at offset iOff of column iCol
    +@@ -8126,13 +10469,51 @@ struct Fts5PhraseIter {
    + **
    + **   The Fts5PhraseIter structure is defined above. Applications should not
    + **   modify this structure directly - it should only be used as shown above
    +-**   with the xPhraseFirst() and xPhraseNext() API methods.
    ++**   with the xPhraseFirst() and xPhraseNext() API methods (and by
    ++**   xPhraseFirstColumn() and xPhraseNextColumn() as illustrated below).
    ++**
    ++**   This API can be quite slow if used with an FTS5 table created with the
    ++**   "detail=none" or "detail=column" option. If the FTS5 table is created 
    ++**   with either "detail=none" or "detail=column" and "content=" option 
    ++**   (i.e. if it is a contentless table), then this API always iterates
    ++**   through an empty set (all calls to xPhraseFirst() set iCol to -1).
    + **
    + ** xPhraseNext()
    + **   See xPhraseFirst above.
    ++**
    ++** xPhraseFirstColumn()
    ++**   This function and xPhraseNextColumn() are similar to the xPhraseFirst()
    ++**   and xPhraseNext() APIs described above. The difference is that instead
    ++**   of iterating through all instances of a phrase in the current row, these
    ++**   APIs are used to iterate through the set of columns in the current row
    ++**   that contain one or more instances of a specified phrase. For example:
    ++**
    ++**       Fts5PhraseIter iter;
    ++**       int iCol;
    ++**       for(pApi->xPhraseFirstColumn(pFts, iPhrase, &iter, &iCol);
    ++**           iCol>=0;
    ++**           pApi->xPhraseNextColumn(pFts, &iter, &iCol)
    ++**       ){
    ++**         // Column iCol contains at least one instance of phrase iPhrase
    ++**       }
    ++**
    ++**   This API can be quite slow if used with an FTS5 table created with the
    ++**   "detail=none" option. If the FTS5 table is created with either 
    ++**   "detail=none" "content=" option (i.e. if it is a contentless table), 
    ++**   then this API always iterates through an empty set (all calls to 
    ++**   xPhraseFirstColumn() set iCol to -1).
    ++**
    ++**   The information accessed using this API and its companion
    ++**   xPhraseFirstColumn() may also be obtained using xPhraseFirst/xPhraseNext
    ++**   (or xInst/xInstCount). The chief advantage of this API is that it is
    ++**   significantly more efficient than those alternatives when used with
    ++**   "detail=column" tables.  
    ++**
    ++** xPhraseNextColumn()
    ++**   See xPhraseFirstColumn above.
    + */
    + struct Fts5ExtensionApi {
    +-  int iVersion;                   /* Currently always set to 1 */
    ++  int iVersion;                   /* Currently always set to 3 */
    + 
    +   void *(*xUserData)(Fts5Context*);
    + 
    +@@ -8162,8 +10543,11 @@ struct Fts5ExtensionApi {
    +   int (*xSetAuxdata)(Fts5Context*, void *pAux, void(*xDelete)(void*));
    +   void *(*xGetAuxdata)(Fts5Context*, int bClear);
    + 
    +-  void (*xPhraseFirst)(Fts5Context*, int iPhrase, Fts5PhraseIter*, int*, int*);
    ++  int (*xPhraseFirst)(Fts5Context*, int iPhrase, Fts5PhraseIter*, int*, int*);
    +   void (*xPhraseNext)(Fts5Context*, Fts5PhraseIter*, int *piCol, int *piOff);
    ++
    ++  int (*xPhraseFirstColumn)(Fts5Context*, int iPhrase, Fts5PhraseIter*, int*);
    ++  void (*xPhraseNextColumn)(Fts5Context*, Fts5PhraseIter*, int *piCol);
    + };
    + 
    + /* 
    +@@ -8180,7 +10564,7 @@ struct Fts5ExtensionApi {
    + ** behaviour. The structure methods are expected to function as follows:
    + **
    + ** xCreate:
    +-**   This function is used to allocate and inititalize a tokenizer instance.
    ++**   This function is used to allocate and initialize a tokenizer instance.
    + **   A tokenizer instance is required to actually tokenize text.
    + **
    + **   The first argument passed to this function is a copy of the (void*)
    +@@ -8440,4 +10824,4 @@ struct fts5_api {
    + 
    + #endif /* _FTS5_H */
    + 
    +-
    ++/******** End of fts5.h *********/
    +diff --git a/dist/orig/sqlite3ext.h b/dist/orig/sqlite3ext.h
    +index 017ea30..ac92a74 100644
    +--- a/dist/orig/sqlite3ext.h
    ++++ b/dist/orig/sqlite3ext.h
    +@@ -15,12 +15,10 @@
    + ** as extensions by SQLite should #include this file instead of 
    + ** sqlite3.h.
    + */
    +-#ifndef _SQLITE3EXT_H_
    +-#define _SQLITE3EXT_H_
    ++#ifndef SQLITE3EXT_H
    ++#define SQLITE3EXT_H
    + #include "sqlite3.h"
    + 
    +-typedef struct sqlite3_api_routines sqlite3_api_routines;
    +-
    + /*
    + ** The following structure holds pointers to all of the SQLite API
    + ** routines.
    +@@ -136,7 +134,7 @@ struct sqlite3_api_routines {
    +   int  (*set_authorizer)(sqlite3*,int(*)(void*,int,const char*,const char*,
    +                          const char*,const char*),void*);
    +   void  (*set_auxdata)(sqlite3_context*,int,void*,void (*)(void*));
    +-  char * (*snprintf)(int,char*,const char*,...);
    ++  char * (*xsnprintf)(int,char*,const char*,...);
    +   int  (*step)(sqlite3_stmt*);
    +   int  (*table_column_metadata)(sqlite3*,const char*,const char*,const char*,
    +                                 char const**,char const**,int*,int*,int*);
    +@@ -248,7 +246,7 @@ struct sqlite3_api_routines {
    +   int (*uri_boolean)(const char*,const char*,int);
    +   sqlite3_int64 (*uri_int64)(const char*,const char*,sqlite3_int64);
    +   const char *(*uri_parameter)(const char*,const char*);
    +-  char *(*vsnprintf)(int,char*,const char*,va_list);
    ++  char *(*xvsnprintf)(int,char*,const char*,va_list);
    +   int (*wal_checkpoint_v2)(sqlite3*,const char*,int,int*,int*);
    +   /* Version 3.8.7 and later */
    +   int (*auto_extension)(void(*)(void));
    +@@ -275,8 +273,40 @@ struct sqlite3_api_routines {
    +   /* Version 3.9.0 and later */
    +   unsigned int (*value_subtype)(sqlite3_value*);
    +   void (*result_subtype)(sqlite3_context*,unsigned int);
    ++  /* Version 3.10.0 and later */
    ++  int (*status64)(int,sqlite3_int64*,sqlite3_int64*,int);
    ++  int (*strlike)(const char*,const char*,unsigned int);
    ++  int (*db_cacheflush)(sqlite3*);
    ++  /* Version 3.12.0 and later */
    ++  int (*system_errno)(sqlite3*);
    ++  /* Version 3.14.0 and later */
    ++  int (*trace_v2)(sqlite3*,unsigned,int(*)(unsigned,void*,void*,void*),void*);
    ++  char *(*expanded_sql)(sqlite3_stmt*);
    ++  /* Version 3.18.0 and later */
    ++  void (*set_last_insert_rowid)(sqlite3*,sqlite3_int64);
    ++  /* Version 3.20.0 and later */
    ++  int (*prepare_v3)(sqlite3*,const char*,int,unsigned int,
    ++                    sqlite3_stmt**,const char**);
    ++  int (*prepare16_v3)(sqlite3*,const void*,int,unsigned int,
    ++                      sqlite3_stmt**,const void**);
    ++  int (*bind_pointer)(sqlite3_stmt*,int,void*,const char*,void(*)(void*));
    ++  void (*result_pointer)(sqlite3_context*,void*,const char*,void(*)(void*));
    ++  void *(*value_pointer)(sqlite3_value*,const char*);
    ++  int (*vtab_nochange)(sqlite3_context*);
    ++  int (*value_nochange)(sqlite3_value*);
    ++  const char *(*vtab_collation)(sqlite3_index_info*,int);
    + };
    + 
    ++/*
    ++** This is the function signature used for all extension entry points.  It
    ++** is also defined in the file "loadext.c".
    ++*/
    ++typedef int (*sqlite3_loadext_entry)(
    ++  sqlite3 *db,                       /* Handle to the database. */
    ++  char **pzErrMsg,                   /* Used to set error string on failure. */
    ++  const sqlite3_api_routines *pThunk /* Extension API function pointers. */
    ++);
    ++
    + /*
    + ** The following macros redefine the API routines so that they are
    + ** redirected through the global sqlite3_api structure.
    +@@ -391,7 +421,7 @@ struct sqlite3_api_routines {
    + #define sqlite3_rollback_hook          sqlite3_api->rollback_hook
    + #define sqlite3_set_authorizer         sqlite3_api->set_authorizer
    + #define sqlite3_set_auxdata            sqlite3_api->set_auxdata
    +-#define sqlite3_snprintf               sqlite3_api->snprintf
    ++#define sqlite3_snprintf               sqlite3_api->xsnprintf
    + #define sqlite3_step                   sqlite3_api->step
    + #define sqlite3_table_column_metadata  sqlite3_api->table_column_metadata
    + #define sqlite3_thread_cleanup         sqlite3_api->thread_cleanup
    +@@ -415,7 +445,7 @@ struct sqlite3_api_routines {
    + #define sqlite3_value_text16le         sqlite3_api->value_text16le
    + #define sqlite3_value_type             sqlite3_api->value_type
    + #define sqlite3_vmprintf               sqlite3_api->vmprintf
    +-#define sqlite3_vsnprintf              sqlite3_api->vsnprintf
    ++#define sqlite3_vsnprintf              sqlite3_api->xvsnprintf
    + #define sqlite3_overload_function      sqlite3_api->overload_function
    + #define sqlite3_prepare_v2             sqlite3_api->prepare_v2
    + #define sqlite3_prepare16_v2           sqlite3_api->prepare16_v2
    +@@ -491,7 +521,7 @@ struct sqlite3_api_routines {
    + #define sqlite3_uri_boolean            sqlite3_api->uri_boolean
    + #define sqlite3_uri_int64              sqlite3_api->uri_int64
    + #define sqlite3_uri_parameter          sqlite3_api->uri_parameter
    +-#define sqlite3_uri_vsnprintf          sqlite3_api->vsnprintf
    ++#define sqlite3_uri_vsnprintf          sqlite3_api->xvsnprintf
    + #define sqlite3_wal_checkpoint_v2      sqlite3_api->wal_checkpoint_v2
    + /* Version 3.8.7 and later */
    + #define sqlite3_auto_extension         sqlite3_api->auto_extension
    +@@ -514,6 +544,27 @@ struct sqlite3_api_routines {
    + /* Version 3.9.0 and later */
    + #define sqlite3_value_subtype          sqlite3_api->value_subtype
    + #define sqlite3_result_subtype         sqlite3_api->result_subtype
    ++/* Version 3.10.0 and later */
    ++#define sqlite3_status64               sqlite3_api->status64
    ++#define sqlite3_strlike                sqlite3_api->strlike
    ++#define sqlite3_db_cacheflush          sqlite3_api->db_cacheflush
    ++/* Version 3.12.0 and later */
    ++#define sqlite3_system_errno           sqlite3_api->system_errno
    ++/* Version 3.14.0 and later */
    ++#define sqlite3_trace_v2               sqlite3_api->trace_v2
    ++#define sqlite3_expanded_sql           sqlite3_api->expanded_sql
    ++/* Version 3.18.0 and later */
    ++#define sqlite3_set_last_insert_rowid  sqlite3_api->set_last_insert_rowid
    ++/* Version 3.20.0 and later */
    ++#define sqlite3_prepare_v3             sqlite3_api->prepare_v3
    ++#define sqlite3_prepare16_v3           sqlite3_api->prepare16_v3
    ++#define sqlite3_bind_pointer           sqlite3_api->bind_pointer
    ++#define sqlite3_result_pointer         sqlite3_api->result_pointer
    ++#define sqlite3_value_pointer          sqlite3_api->value_pointer
    ++/* Version 3.22.0 and later */
    ++#define sqlite3_vtab_nochange          sqlite3_api->vtab_nochange
    ++#define sqlite3_value_nochange         sqltie3_api->value_nochange
    ++#define sqlite3_vtab_collation         sqltie3_api->vtab_collation
    + #endif /* !defined(SQLITE_CORE) && !defined(SQLITE_OMIT_LOAD_EXTENSION) */
    + 
    + #if !defined(SQLITE_CORE) && !defined(SQLITE_OMIT_LOAD_EXTENSION)
    +@@ -531,4 +582,4 @@ struct sqlite3_api_routines {
    + # define SQLITE_EXTENSION_INIT3     /*no-op*/
    + #endif
    + 
    +-#endif /* _SQLITE3EXT_H_ */
    ++#endif /* SQLITE3EXT_H */
    +diff --git a/dist/shell.c b/dist/shell.c
    +index fc1b664..735aaff 100644
    +--- a/dist/shell.c
    ++++ b/dist/shell.c
    +@@ -1,3 +1,21 @@
    ++/* DO NOT EDIT!
    ++** This file is automatically generated by the script in the canonical
    ++** SQLite source tree at tool/mkshellc.tcl.  That script combines source
    ++** code from various constituent source files of SQLite into this single
    ++** "shell.c" file used to implement the SQLite command-line shell.
    ++**
    ++** Most of the code found below comes from the "src/shell.c.in" file in
    ++** the canonical SQLite source tree.  That main file contains "INCLUDE"
    ++** lines that specify other files in the canonical source tree that are
    ++** inserted to getnerate this complete program source file.
    ++**
    ++** The code from multiple files is combined into this single "shell.c"
    ++** source file to help make the command-line program easier to compile.
    ++**
    ++** To modify this program, get a copy of the canonical SQLite source tree,
    ++** edit the src/shell.c.in" and/or some of the other files that are included
    ++** by "src/shell.c.in", then rerun the tool/mkshellc.tcl script.
    ++*/
    + /*
    + ** 2001 September 15
    + **
    +@@ -18,11 +36,25 @@
    + #endif
    + 
    + /*
    +-** If requested, include the SQLite compiler options file for MSVC.
    ++** Warning pragmas copied from msvc.h in the core.
    + */
    +-#if defined(INCLUDE_MSVC_H)
    +-#include "msvc.h"
    +-#endif
    ++#if defined(_MSC_VER)
    ++#pragma warning(disable : 4054)
    ++#pragma warning(disable : 4055)
    ++#pragma warning(disable : 4100)
    ++#pragma warning(disable : 4127)
    ++#pragma warning(disable : 4130)
    ++#pragma warning(disable : 4152)
    ++#pragma warning(disable : 4189)
    ++#pragma warning(disable : 4206)
    ++#pragma warning(disable : 4210)
    ++#pragma warning(disable : 4232)
    ++#pragma warning(disable : 4244)
    ++#pragma warning(disable : 4305)
    ++#pragma warning(disable : 4306)
    ++#pragma warning(disable : 4702)
    ++#pragma warning(disable : 4706)
    ++#endif /* defined(_MSC_VER) */
    + 
    + /*
    + ** No support for loadable extensions in VxWorks.
    +@@ -47,6 +79,9 @@
    + #include <stdio.h>
    + #include <assert.h>
    + #include "sqlite3.h"
    ++typedef sqlite3_int64 i64;
    ++typedef sqlite3_uint64 u64;
    ++typedef unsigned char u8;
    + #if SQLITE_USER_AUTHENTICATION
    + # include "sqlite3userauth.h"
    + #endif
    +@@ -64,9 +99,19 @@
    + # if !defined(__RTP__) && !defined(_WRS_KERNEL)
    + #  include <pwd.h>
    + # endif
    ++#endif
    ++#if (!defined(_WIN32) && !defined(WIN32)) || defined(__MINGW32__)
    + # include <unistd.h>
    +-# include <sys/types.h>
    ++# include <dirent.h>
    ++# if defined(__MINGW32__)
    ++#  define DIRENT dirent
    ++#  ifndef S_ISLNK
    ++#   define S_ISLNK(mode) (0)
    ++#  endif
    ++# endif
    + #endif
    ++#include <sys/types.h>
    ++#include <sys/stat.h>
    + 
    + #if HAVE_READLINE
    + # include <readline/readline.h>
    +@@ -96,7 +141,7 @@
    + 
    + #else
    + 
    +-# define shell_read_history(X) 
    ++# define shell_read_history(X)
    + # define shell_write_history(X)
    + # define shell_stifle_history(X)
    + 
    +@@ -142,6 +187,16 @@
    + #define IsDigit(X)  isdigit((unsigned char)X)
    + #define ToLower(X)  (char)tolower((unsigned char)X)
    + 
    ++#if defined(_WIN32) || defined(WIN32)
    ++#include <windows.h>
    ++
    ++/* string conversion routines only needed on Win32 */
    ++extern char *sqlite3_win32_unicode_to_utf8(LPCWSTR);
    ++extern char *sqlite3_win32_mbcs_to_utf8_v2(const char *, int);
    ++extern char *sqlite3_win32_utf8_to_mbcs_v2(const char *, int);
    ++extern LPWSTR sqlite3_win32_utf8_to_unicode(const char *zText);
    ++#endif
    ++
    + /* On Windows, we normally run with output mode of TEXT so that \n characters
    + ** are automatically translated into \r\n.  However, this behavior needs
    + ** to be disabled in some cases (ex: when generating CSV output and when
    +@@ -149,17 +204,17 @@
    + ** routines take care of that.
    + */
    + #if defined(_WIN32) || defined(WIN32)
    +-static void setBinaryMode(FILE *out){
    +-  fflush(out);
    +-  _setmode(_fileno(out), _O_BINARY);
    ++static void setBinaryMode(FILE *file, int isOutput){
    ++  if( isOutput ) fflush(file);
    ++  _setmode(_fileno(file), _O_BINARY);
    + }
    +-static void setTextMode(FILE *out){
    +-  fflush(out);
    +-  _setmode(_fileno(out), _O_TEXT);
    ++static void setTextMode(FILE *file, int isOutput){
    ++  if( isOutput ) fflush(file);
    ++  _setmode(_fileno(file), _O_TEXT);
    + }
    + #else
    +-# define setBinaryMode(X)
    +-# define setTextMode(X)
    ++# define setBinaryMode(X,Y)
    ++# define setTextMode(X,Y)
    + #endif
    + 
    + 
    +@@ -171,7 +226,7 @@ static sqlite3_int64 timeOfDay(void){
    +   static sqlite3_vfs *clockVfs = 0;
    +   sqlite3_int64 t;
    +   if( clockVfs==0 ) clockVfs = sqlite3_vfs_find(0);
    +-  if( clockVfs->iVersion>=1 && clockVfs->xCurrentTimeInt64!=0 ){
    ++  if( clockVfs->iVersion>=2 && clockVfs->xCurrentTimeInt64!=0 ){
    +     clockVfs->xCurrentTimeInt64(clockVfs, &t);
    +   }else{
    +     double r;
    +@@ -210,7 +265,7 @@ static void beginTimer(void){
    + 
    + /* Return the difference of two time_structs in seconds */
    + static double timeDiff(struct timeval *pStart, struct timeval *pEnd){
    +-  return (pEnd->tv_usec - pStart->tv_usec)*0.000001 + 
    ++  return (pEnd->tv_usec - pStart->tv_usec)*0.000001 +
    +          (double)(pEnd->tv_sec - pStart->tv_sec);
    + }
    + 
    +@@ -235,8 +290,6 @@ static void endTimer(void){
    + 
    + #elif (defined(_WIN32) || defined(WIN32))
    + 
    +-#include <windows.h>
    +-
    + /* Saved resource information for the beginning of an operation */
    + static HANDLE hProcess;
    + static FILETIME ftKernelBegin;
    +@@ -267,7 +320,7 @@ static int hasTimer(void){
    +         if( NULL != getProcessTimesAddr ){
    +           return 1;
    +         }
    +-        FreeLibrary(hinstLib); 
    ++        FreeLibrary(hinstLib);
    +       }
    +     }
    +   }
    +@@ -313,7 +366,7 @@ static void endTimer(void){
    + #define HAS_TIMER hasTimer()
    + 
    + #else
    +-#define BEGIN_TIMER 
    ++#define BEGIN_TIMER
    + #define END_TIMER
    + #define HAS_TIMER 0
    + #endif
    +@@ -323,6 +376,11 @@ static void endTimer(void){
    + */
    + #define UNUSED_PARAMETER(x) (void)(x)
    + 
    ++/*
    ++** Number of elements in an array
    ++*/
    ++#define ArraySize(X)  (int)(sizeof(X)/sizeof(X[0]))
    ++
    + /*
    + ** If the following flag is set, then command execution stops
    + ** at an error if we are not interactive.
    +@@ -335,6 +393,13 @@ static int bail_on_error = 0;
    + */
    + static int stdin_is_interactive = 1;
    + 
    ++/*
    ++** On Windows systems we have to know if standard output is a console
    ++** in order to translate UTF-8 into MBCS.  The following variable is
    ++** true if translation is required.
    ++*/
    ++static int stdout_is_console = 1;
    ++
    + /*
    + ** The following is the open SQLite database.  We make a pointer
    + ** to this database a static variable so that it can be accessed
    +@@ -360,6 +425,38 @@ static char *Argv0;
    + static char mainPrompt[20];     /* First line prompt. default: "sqlite> "*/
    + static char continuePrompt[20]; /* Continuation prompt. default: "   ...> " */
    + 
    ++/*
    ++** Render output like fprintf().  Except, if the output is going to the
    ++** console and if this is running on a Windows machine, translate the
    ++** output from UTF-8 into MBCS.
    ++*/
    ++#if defined(_WIN32) || defined(WIN32)
    ++void utf8_printf(FILE *out, const char *zFormat, ...){
    ++  va_list ap;
    ++  va_start(ap, zFormat);
    ++  if( stdout_is_console && (out==stdout || out==stderr) ){
    ++    char *z1 = sqlite3_vmprintf(zFormat, ap);
    ++    char *z2 = sqlite3_win32_utf8_to_mbcs_v2(z1, 0);
    ++    sqlite3_free(z1);
    ++    fputs(z2, out);
    ++    sqlite3_free(z2);
    ++  }else{
    ++    vfprintf(out, zFormat, ap);
    ++  }
    ++  va_end(ap);
    ++}
    ++#elif !defined(utf8_printf)
    ++# define utf8_printf fprintf
    ++#endif
    ++
    ++/*
    ++** Render output like fprintf().  This should not be used on anything that
    ++** includes string formatting (e.g. "%s").
    ++*/
    ++#if !defined(raw_printf)
    ++# define raw_printf fprintf
    ++#endif
    ++
    + /*
    + ** Write I/O traces to the following stream.
    + */
    +@@ -381,11 +478,41 @@ static void SQLITE_CDECL iotracePrintf(const char *zFormat, ...){
    +   va_start(ap, zFormat);
    +   z = sqlite3_vmprintf(zFormat, ap);
    +   va_end(ap);
    +-  fprintf(iotrace, "%s", z);
    ++  utf8_printf(iotrace, "%s", z);
    +   sqlite3_free(z);
    + }
    + #endif
    + 
    ++/*
    ++** Output string zUtf to stream pOut as w characters.  If w is negative,
    ++** then right-justify the text.  W is the width in UTF-8 characters, not
    ++** in bytes.  This is different from the %*.*s specification in printf
    ++** since with %*.*s the width is measured in bytes, not characters.
    ++*/
    ++static void utf8_width_print(FILE *pOut, int w, const char *zUtf){
    ++  int i;
    ++  int n;
    ++  int aw = w<0 ? -w : w;
    ++  char zBuf[1000];
    ++  if( aw>(int)sizeof(zBuf)/3 ) aw = (int)sizeof(zBuf)/3;
    ++  for(i=n=0; zUtf[i]; i++){
    ++    if( (zUtf[i]&0xc0)!=0x80 ){
    ++      n++;
    ++      if( n==aw ){
    ++        do{ i++; }while( (zUtf[i]&0xc0)==0x80 );
    ++        break;
    ++      }
    ++    }
    ++  }
    ++  if( n>=aw ){
    ++    utf8_printf(pOut, "%.*s", i, zUtf);
    ++  }else if( w<0 ){
    ++    utf8_printf(pOut, "%*s%s", aw-n, "", zUtf);
    ++  }else{
    ++    utf8_printf(pOut, "%s%*s", zUtf, aw-n, "");
    ++  }
    ++}
    ++
    + 
    + /*
    + ** Determines if a string is a number of not.
    +@@ -415,26 +542,26 @@ static int isNumber(const char *z, int *realnum){
    + }
    + 
    + /*
    +-** A global char* and an SQL function to access its current value 
    +-** from within an SQL statement. This program used to use the 
    +-** sqlite_exec_printf() API to substitue a string into an SQL statement.
    +-** The correct way to do this with sqlite3 is to use the bind API, but
    +-** since the shell is built around the callback paradigm it would be a lot
    +-** of work. Instead just use this hack, which is quite harmless.
    ++** Compute a string length that is limited to what can be stored in
    ++** lower 30 bits of a 32-bit signed integer.
    + */
    +-static const char *zShellStatic = 0;
    +-static void shellstaticFunc(
    +-  sqlite3_context *context,
    +-  int argc,
    +-  sqlite3_value **argv
    +-){
    +-  assert( 0==argc );
    +-  assert( zShellStatic );
    +-  UNUSED_PARAMETER(argc);
    +-  UNUSED_PARAMETER(argv);
    +-  sqlite3_result_text(context, zShellStatic, -1, SQLITE_STATIC);
    ++static int strlen30(const char *z){
    ++  const char *z2 = z;
    ++  while( *z2 ){ z2++; }
    ++  return 0x3fffffff & (int)(z2 - z);
    + }
    + 
    ++/*
    ++** Return the length of a string in characters.  Multibyte UTF8 characters
    ++** count as a single character.
    ++*/
    ++static int strlenChar(const char *z){
    ++  int n = 0;
    ++  while( *z ){
    ++    if( (0xc0&*(z++))!=0x80 ) n++;
    ++  }
    ++  return n;
    ++}
    + 
    + /*
    + ** This routine reads a line of text from FILE in, stores
    +@@ -471,6 +598,25 @@ static char *local_getline(char *zLine, FILE *in){
    +       break;
    +     }
    +   }
    ++#if defined(_WIN32) || defined(WIN32)
    ++  /* For interactive input on Windows systems, translate the
    ++  ** multi-byte characterset characters into UTF-8. */
    ++  if( stdin_is_interactive && in==stdin ){
    ++    char *zTrans = sqlite3_win32_mbcs_to_utf8_v2(zLine, 0);
    ++    if( zTrans ){
    ++      int nTrans = strlen30(zTrans)+1;
    ++      if( nTrans>nLine ){
    ++        zLine = realloc(zLine, nTrans);
    ++        if( zLine==0 ){
    ++          sqlite3_free(zTrans);
    ++          return 0;
    ++        }
    ++      }
    ++      memcpy(zLine, zTrans, nTrans);
    ++      sqlite3_free(zTrans);
    ++    }
    ++  }
    ++#endif /* defined(_WIN32) || defined(WIN32) */
    +   return zLine;
    + }
    + 
    +@@ -508,2148 +654,11652 @@ static char *one_input_line(FILE *in, char *zPrior, int isContinuation){
    +   return zResult;
    + }
    + 
    +-/*
    +-** Shell output mode information from before ".explain on", 
    +-** saved so that it can be restored by ".explain off"
    +-*/
    +-typedef struct SavedModeInfo SavedModeInfo;
    +-struct SavedModeInfo {
    +-  int valid;          /* Is there legit data in here? */
    +-  int mode;           /* Mode prior to ".explain on" */
    +-  int showHeader;     /* The ".header" setting prior to ".explain on" */
    +-  int colWidth[100];  /* Column widths prior to ".explain on" */
    +-};
    + 
    + /*
    +-** State information about the database connection is contained in an
    +-** instance of the following structure.
    ++** Return the value of a hexadecimal digit.  Return -1 if the input
    ++** is not a hex digit.
    + */
    +-typedef struct ShellState ShellState;
    +-struct ShellState {
    +-  sqlite3 *db;           /* The database */
    +-  int echoOn;            /* True to echo input commands */
    +-  int autoEQP;           /* Run EXPLAIN QUERY PLAN prior to seach SQL stmt */
    +-  int statsOn;           /* True to display memory stats before each finalize */
    +-  int scanstatsOn;       /* True to display scan stats before each finalize */
    +-  int backslashOn;       /* Resolve C-style \x escapes in SQL input text */
    +-  int outCount;          /* Revert to stdout when reaching zero */
    +-  int cnt;               /* Number of records displayed so far */
    +-  FILE *out;             /* Write results here */
    +-  FILE *traceOut;        /* Output for sqlite3_trace() */
    +-  int nErr;              /* Number of errors seen */
    +-  int mode;              /* An output mode setting */
    +-  int writableSchema;    /* True if PRAGMA writable_schema=ON */
    +-  int showHeader;        /* True to show column names in List or Column mode */
    +-  unsigned shellFlgs;    /* Various flags */
    +-  char *zDestTable;      /* Name of destination table when MODE_Insert */
    +-  char colSeparator[20]; /* Column separator character for several modes */
    +-  char rowSeparator[20]; /* Row separator character for MODE_Ascii */
    +-  int colWidth[100];     /* Requested width of each column when in column mode*/
    +-  int actualWidth[100];  /* Actual width of each column */
    +-  char nullValue[20];    /* The text to print when a NULL comes back from
    +-                         ** the database */
    +-  SavedModeInfo normalMode;/* Holds the mode just before .explain ON */
    +-  char outfile[FILENAME_MAX]; /* Filename for *out */
    +-  const char *zDbFilename;    /* name of the database file */
    +-  char *zFreeOnClose;         /* Filename to free when closing */
    +-  const char *zVfs;           /* Name of VFS to use */
    +-  sqlite3_stmt *pStmt;   /* Current statement if any. */
    +-  FILE *pLog;            /* Write log output here */
    +-  int *aiIndent;         /* Array of indents used in MODE_Explain */
    +-  int nIndent;           /* Size of array aiIndent[] */
    +-  int iIndent;           /* Index of current op in aiIndent[] */
    +-};
    ++static int hexDigitValue(char c){
    ++  if( c>='0' && c<='9' ) return c - '0';
    ++  if( c>='a' && c<='f' ) return c - 'a' + 10;
    ++  if( c>='A' && c<='F' ) return c - 'A' + 10;
    ++  return -1;
    ++}
    + 
    + /*
    +-** These are the allowed shellFlgs values
    ++** Interpret zArg as an integer value, possibly with suffixes.
    + */
    +-#define SHFLG_Scratch     0x00001     /* The --scratch option is used */
    +-#define SHFLG_Pagecache   0x00002     /* The --pagecache option is used */
    +-#define SHFLG_Lookaside   0x00004     /* Lookaside memory is used */
    ++static sqlite3_int64 integerValue(const char *zArg){
    ++  sqlite3_int64 v = 0;
    ++  static const struct { char *zSuffix; int iMult; } aMult[] = {
    ++    { "KiB", 1024 },
    ++    { "MiB", 1024*1024 },
    ++    { "GiB", 1024*1024*1024 },
    ++    { "KB",  1000 },
    ++    { "MB",  1000000 },
    ++    { "GB",  1000000000 },
    ++    { "K",   1000 },
    ++    { "M",   1000000 },
    ++    { "G",   1000000000 },
    ++  };
    ++  int i;
    ++  int isNeg = 0;
    ++  if( zArg[0]=='-' ){
    ++    isNeg = 1;
    ++    zArg++;
    ++  }else if( zArg[0]=='+' ){
    ++    zArg++;
    ++  }
    ++  if( zArg[0]=='0' && zArg[1]=='x' ){
    ++    int x;
    ++    zArg += 2;
    ++    while( (x = hexDigitValue(zArg[0]))>=0 ){
    ++      v = (v<<4) + x;
    ++      zArg++;
    ++    }
    ++  }else{
    ++    while( IsDigit(zArg[0]) ){
    ++      v = v*10 + zArg[0] - '0';
    ++      zArg++;
    ++    }
    ++  }
    ++  for(i=0; i<ArraySize(aMult); i++){
    ++    if( sqlite3_stricmp(aMult[i].zSuffix, zArg)==0 ){
    ++      v *= aMult[i].iMult;
    ++      break;
    ++    }
    ++  }
    ++  return isNeg? -v : v;
    ++}
    + 
    + /*
    +-** These are the allowed modes.
    ++** A variable length string to which one can append text.
    + */
    +-#define MODE_Line     0  /* One column per line.  Blank line between records */
    +-#define MODE_Column   1  /* One record per line in neat columns */
    +-#define MODE_List     2  /* One record per line with a separator */
    +-#define MODE_Semi     3  /* Same as MODE_List but append ";" to each line */
    +-#define MODE_Html     4  /* Generate an XHTML table */
    +-#define MODE_Insert   5  /* Generate SQL "insert" statements */
    +-#define MODE_Tcl      6  /* Generate ANSI-C or TCL quoted elements */
    +-#define MODE_Csv      7  /* Quote strings, numbers are plain */
    +-#define MODE_Explain  8  /* Like MODE_Column, but do not truncate data */
    +-#define MODE_Ascii    9  /* Use ASCII unit and record separators (0x1F/0x1E) */
    +-
    +-static const char *modeDescr[] = {
    +-  "line",
    +-  "column",
    +-  "list",
    +-  "semi",
    +-  "html",
    +-  "insert",
    +-  "tcl",
    +-  "csv",
    +-  "explain",
    +-  "ascii",
    ++typedef struct ShellText ShellText;
    ++struct ShellText {
    ++  char *z;
    ++  int n;
    ++  int nAlloc;
    + };
    + 
    + /*
    +-** These are the column/row/line separators used by the various
    +-** import/export modes.
    ++** Initialize and destroy a ShellText object
    + */
    +-#define SEP_Column    "|"
    +-#define SEP_Row       "\n"
    +-#define SEP_Tab       "\t"
    +-#define SEP_Space     " "
    +-#define SEP_Comma     ","
    +-#define SEP_CrLf      "\r\n"
    +-#define SEP_Unit      "\x1F"
    +-#define SEP_Record    "\x1E"
    ++static void initText(ShellText *p){
    ++  memset(p, 0, sizeof(*p));
    ++}
    ++static void freeText(ShellText *p){
    ++  free(p->z);
    ++  initText(p);
    ++}
    + 
    +-/*
    +-** Number of elements in an array
    ++/* zIn is either a pointer to a NULL-terminated string in memory obtained
    ++** from malloc(), or a NULL pointer. The string pointed to by zAppend is
    ++** added to zIn, and the result returned in memory obtained from malloc().
    ++** zIn, if it was not NULL, is freed.
    ++**
    ++** If the third argument, quote, is not '\0', then it is used as a
    ++** quote character for zAppend.
    + */
    +-#define ArraySize(X)  (int)(sizeof(X)/sizeof(X[0]))
    ++static void appendText(ShellText *p, char const *zAppend, char quote){
    ++  int len;
    ++  int i;
    ++  int nAppend = strlen30(zAppend);
    ++
    ++  len = nAppend+p->n+1;
    ++  if( quote ){
    ++    len += 2;
    ++    for(i=0; i<nAppend; i++){
    ++      if( zAppend[i]==quote ) len++;
    ++    }
    ++  }
    ++
    ++  if( p->n+len>=p->nAlloc ){
    ++    p->nAlloc = p->nAlloc*2 + len + 20;
    ++    p->z = realloc(p->z, p->nAlloc);
    ++    if( p->z==0 ){
    ++      memset(p, 0, sizeof(*p));
    ++      return;
    ++    }
    ++  }
    ++
    ++  if( quote ){
    ++    char *zCsr = p->z+p->n;
    ++    *zCsr++ = quote;
    ++    for(i=0; i<nAppend; i++){
    ++      *zCsr++ = zAppend[i];
    ++      if( zAppend[i]==quote ) *zCsr++ = quote;
    ++    }
    ++    *zCsr++ = quote;
    ++    p->n = (int)(zCsr - p->z);
    ++    *zCsr = '\0';
    ++  }else{
    ++    memcpy(p->z+p->n, zAppend, nAppend);
    ++    p->n += nAppend;
    ++    p->z[p->n] = '\0';
    ++  }
    ++}
    + 
    + /*
    +-** Compute a string length that is limited to what can be stored in
    +-** lower 30 bits of a 32-bit signed integer.
    ++** Attempt to determine if identifier zName needs to be quoted, either
    ++** because it contains non-alphanumeric characters, or because it is an
    ++** SQLite keyword.  Be conservative in this estimate:  When in doubt assume
    ++** that quoting is required.
    ++**
    ++** Return '"' if quoting is required.  Return 0 if no quoting is required.
    + */
    +-static int strlen30(const char *z){
    +-  const char *z2 = z;
    +-  while( *z2 ){ z2++; }
    +-  return 0x3fffffff & (int)(z2 - z);
    ++static char quoteChar(const char *zName){
    ++  /* All SQLite keywords, in alphabetical order */
    ++  static const char *azKeywords[] = {
    ++    "ABORT", "ACTION", "ADD", "AFTER", "ALL", "ALTER", "ANALYZE", "AND", "AS",
    ++    "ASC", "ATTACH", "AUTOINCREMENT", "BEFORE", "BEGIN", "BETWEEN", "BY",
    ++    "CASCADE", "CASE", "CAST", "CHECK", "COLLATE", "COLUMN", "COMMIT",
    ++    "CONFLICT", "CONSTRAINT", "CREATE", "CROSS", "CURRENT_DATE",
    ++    "CURRENT_TIME", "CURRENT_TIMESTAMP", "DATABASE", "DEFAULT", "DEFERRABLE",
    ++    "DEFERRED", "DELETE", "DESC", "DETACH", "DISTINCT", "DROP", "EACH",
    ++    "ELSE", "END", "ESCAPE", "EXCEPT", "EXCLUSIVE", "EXISTS", "EXPLAIN",
    ++    "FAIL", "FOR", "FOREIGN", "FROM", "FULL", "GLOB", "GROUP", "HAVING", "IF",
    ++    "IGNORE", "IMMEDIATE", "IN", "INDEX", "INDEXED", "INITIALLY", "INNER",
    ++    "INSERT", "INSTEAD", "INTERSECT", "INTO", "IS", "ISNULL", "JOIN", "KEY",
    ++    "LEFT", "LIKE", "LIMIT", "MATCH", "NATURAL", "NO", "NOT", "NOTNULL",
    ++    "NULL", "OF", "OFFSET", "ON", "OR", "ORDER", "OUTER", "PLAN", "PRAGMA",
    ++    "PRIMARY", "QUERY", "RAISE", "RECURSIVE", "REFERENCES", "REGEXP",
    ++    "REINDEX", "RELEASE", "RENAME", "REPLACE", "RESTRICT", "RIGHT",
    ++    "ROLLBACK", "ROW", "SAVEPOINT", "SELECT", "SET", "TABLE", "TEMP",
    ++    "TEMPORARY", "THEN", "TO", "TRANSACTION", "TRIGGER", "UNION", "UNIQUE",
    ++    "UPDATE", "USING", "VACUUM", "VALUES", "VIEW", "VIRTUAL", "WHEN", "WHERE",
    ++    "WITH", "WITHOUT",
    ++  };
    ++  int i, lwr, upr, mid, c;
    ++  if( !isalpha((unsigned char)zName[0]) && zName[0]!='_' ) return '"';
    ++  for(i=0; zName[i]; i++){
    ++    if( !isalnum((unsigned char)zName[i]) && zName[i]!='_' ) return '"';
    ++  }
    ++  lwr = 0;
    ++  upr = sizeof(azKeywords)/sizeof(azKeywords[0]) - 1;
    ++  while( lwr<=upr ){
    ++    mid = (lwr+upr)/2;
    ++    c = sqlite3_stricmp(azKeywords[mid], zName);
    ++    if( c==0 ) return '"';
    ++    if( c<0 ){
    ++      lwr = mid+1;
    ++    }else{
    ++      upr = mid-1;
    ++    }
    ++  }
    ++  return 0;
    + }
    + 
    + /*
    +-** A callback for the sqlite3_log() interface.
    ++** Construct a fake object name and column list to describe the structure
    ++** of the view, virtual table, or table valued function zSchema.zName.
    + */
    +-static void shellLog(void *pArg, int iErrCode, const char *zMsg){
    +-  ShellState *p = (ShellState*)pArg;
    +-  if( p->pLog==0 ) return;
    +-  fprintf(p->pLog, "(%d) %s\n", iErrCode, zMsg);
    +-  fflush(p->pLog);
    ++static char *shellFakeSchema(
    ++  sqlite3 *db,            /* The database connection containing the vtab */
    ++  const char *zSchema,    /* Schema of the database holding the vtab */
    ++  const char *zName       /* The name of the virtual table */
    ++){
    ++  sqlite3_stmt *pStmt = 0;
    ++  char *zSql;
    ++  ShellText s;
    ++  char cQuote;
    ++  char *zDiv = "(";
    ++  int nRow = 0;
    ++
    ++  zSql = sqlite3_mprintf("PRAGMA \"%w\".table_info=%Q;",
    ++                         zSchema ? zSchema : "main", zName);
    ++  sqlite3_prepare_v2(db, zSql, -1, &pStmt, 0);
    ++  sqlite3_free(zSql);
    ++  initText(&s);
    ++  if( zSchema ){
    ++    cQuote = quoteChar(zSchema);
    ++    if( cQuote && sqlite3_stricmp(zSchema,"temp")==0 ) cQuote = 0;
    ++    appendText(&s, zSchema, cQuote);
    ++    appendText(&s, ".", 0);
    ++  }
    ++  cQuote = quoteChar(zName);
    ++  appendText(&s, zName, cQuote);
    ++  while( sqlite3_step(pStmt)==SQLITE_ROW ){
    ++    const char *zCol = (const char*)sqlite3_column_text(pStmt, 1);
    ++    nRow++;
    ++    appendText(&s, zDiv, 0);
    ++    zDiv = ",";
    ++    cQuote = quoteChar(zCol);
    ++    appendText(&s, zCol, cQuote);
    ++  }
    ++  appendText(&s, ")", 0);
    ++  sqlite3_finalize(pStmt);
    ++  if( nRow==0 ){
    ++    freeText(&s);
    ++    s.z = 0;
    ++  }
    ++  return s.z;
    + }
    + 
    + /*
    +-** Output the given string as a hex-encoded blob (eg. X'1234' )
    ++** SQL function:  shell_module_schema(X)
    ++**
    ++** Return a fake schema for the table-valued function or eponymous virtual
    ++** table X.
    + */
    +-static void output_hex_blob(FILE *out, const void *pBlob, int nBlob){
    +-  int i;
    +-  char *zBlob = (char *)pBlob;
    +-  fprintf(out,"X'");
    +-  for(i=0; i<nBlob; i++){ fprintf(out,"%02x",zBlob[i]&0xff); }
    +-  fprintf(out,"'");
    ++static void shellModuleSchema(
    ++  sqlite3_context *pCtx,
    ++  int nVal,
    ++  sqlite3_value **apVal
    ++){
    ++  const char *zName = (const char*)sqlite3_value_text(apVal[0]);
    ++  char *zFake = shellFakeSchema(sqlite3_context_db_handle(pCtx), 0, zName);
    ++  UNUSED_PARAMETER(nVal);
    ++  if( zFake ){
    ++    sqlite3_result_text(pCtx, sqlite3_mprintf("/* %s */", zFake),
    ++                        -1, sqlite3_free);
    ++    free(zFake);
    ++  }
    + }
    + 
    + /*
    +-** Output the given string as a quoted string using SQL quoting conventions.
    ++** SQL function:  shell_add_schema(S,X)
    ++**
    ++** Add the schema name X to the CREATE statement in S and return the result.
    ++** Examples:
    ++**
    ++**    CREATE TABLE t1(x)   ->   CREATE TABLE xyz.t1(x);
    ++**
    ++** Also works on
    ++**
    ++**    CREATE INDEX
    ++**    CREATE UNIQUE INDEX
    ++**    CREATE VIEW
    ++**    CREATE TRIGGER
    ++**    CREATE VIRTUAL TABLE
    ++**
    ++** This UDF is used by the .schema command to insert the schema name of
    ++** attached databases into the middle of the sqlite_master.sql field.
    + */
    +-static void output_quoted_string(FILE *out, const char *z){
    +-  int i;
    +-  int nSingle = 0;
    +-  setBinaryMode(out);
    +-  for(i=0; z[i]; i++){
    +-    if( z[i]=='\'' ) nSingle++;
    +-  }
    +-  if( nSingle==0 ){
    +-    fprintf(out,"'%s'",z);
    +-  }else{
    +-    fprintf(out,"'");
    +-    while( *z ){
    +-      for(i=0; z[i] && z[i]!='\''; i++){}
    +-      if( i==0 ){
    +-        fprintf(out,"''");
    +-        z++;
    +-      }else if( z[i]=='\'' ){
    +-        fprintf(out,"%.*s''",i,z);
    +-        z += i+1;
    +-      }else{
    +-        fprintf(out,"%s",z);
    +-        break;
    ++static void shellAddSchemaName(
    ++  sqlite3_context *pCtx,
    ++  int nVal,
    ++  sqlite3_value **apVal
    ++){
    ++  static const char *aPrefix[] = {
    ++     "TABLE",
    ++     "INDEX",
    ++     "UNIQUE INDEX",
    ++     "VIEW",
    ++     "TRIGGER",
    ++     "VIRTUAL TABLE"
    ++  };
    ++  int i = 0;
    ++  const char *zIn = (const char*)sqlite3_value_text(apVal[0]);
    ++  const char *zSchema = (const char*)sqlite3_value_text(apVal[1]);
    ++  const char *zName = (const char*)sqlite3_value_text(apVal[2]);
    ++  sqlite3 *db = sqlite3_context_db_handle(pCtx);
    ++  UNUSED_PARAMETER(nVal);
    ++  if( zIn!=0 && strncmp(zIn, "CREATE ", 7)==0 ){
    ++    for(i=0; i<(int)(sizeof(aPrefix)/sizeof(aPrefix[0])); i++){
    ++      int n = strlen30(aPrefix[i]);
    ++      if( strncmp(zIn+7, aPrefix[i], n)==0 && zIn[n+7]==' ' ){
    ++        char *z = 0;
    ++        char *zFake = 0;
    ++        if( zSchema ){
    ++          char cQuote = quoteChar(zSchema);
    ++          if( cQuote && sqlite3_stricmp(zSchema,"temp")!=0 ){
    ++            z = sqlite3_mprintf("%.*s \"%w\".%s", n+7, zIn, zSchema, zIn+n+8);
    ++          }else{
    ++            z = sqlite3_mprintf("%.*s %s.%s", n+7, zIn, zSchema, zIn+n+8);
    ++          }
    ++        }
    ++        if( zName
    ++         && aPrefix[i][0]=='V'
    ++         && (zFake = shellFakeSchema(db, zSchema, zName))!=0
    ++        ){
    ++          if( z==0 ){
    ++            z = sqlite3_mprintf("%s\n/* %s */", zIn, zFake);
    ++          }else{
    ++            z = sqlite3_mprintf("%z\n/* %s */", z, zFake);
    ++          }
    ++          free(zFake);
    ++        }
    ++        if( z ){
    ++          sqlite3_result_text(pCtx, z, -1, sqlite3_free);
    ++          return;
    ++        }
    +       }
    +     }
    +-    fprintf(out,"'");
    +   }
    +-  setTextMode(out);
    ++  sqlite3_result_value(pCtx, apVal[0]);
    + }
    + 
    + /*
    +-** Output the given string as a quoted according to C or TCL quoting rules.
    ++** The source code for several run-time loadable extensions is inserted
    ++** below by the ../tool/mkshellc.tcl script.  Before processing that included
    ++** code, we need to override some macros to make the included program code
    ++** work here in the middle of this regular program.
    + */
    +-static void output_c_string(FILE *out, const char *z){
    +-  unsigned int c;
    +-  fputc('"', out);
    +-  while( (c = *(z++))!=0 ){
    +-    if( c=='\\' ){
    +-      fputc(c, out);
    +-      fputc(c, out);
    +-    }else if( c=='"' ){
    +-      fputc('\\', out);
    +-      fputc('"', out);
    +-    }else if( c=='\t' ){
    +-      fputc('\\', out);
    +-      fputc('t', out);
    +-    }else if( c=='\n' ){
    +-      fputc('\\', out);
    +-      fputc('n', out);
    +-    }else if( c=='\r' ){
    +-      fputc('\\', out);
    +-      fputc('r', out);
    +-    }else if( !isprint(c&0xff) ){
    +-      fprintf(out, "\\%03o", c&0xff);
    +-    }else{
    +-      fputc(c, out);
    +-    }
    +-  }
    +-  fputc('"', out);
    +-}
    ++#define SQLITE_EXTENSION_INIT1
    ++#define SQLITE_EXTENSION_INIT2(X) (void)(X)
    + 
    ++#if defined(_WIN32) && defined(_MSC_VER)
    ++/************************* Begin test_windirent.h ******************/
    + /*
    +-** Output the given string with characters that are special to
    +-** HTML escaped.
    ++** 2015 November 30
    ++**
    ++** 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 declarations for most of the opendir() family of
    ++** POSIX functions on Win32 using the MSVCRT.
    + */
    +-static void output_html_string(FILE *out, const char *z){
    +-  int i;
    +-  if( z==0 ) z = "";
    +-  while( *z ){
    +-    for(i=0;   z[i] 
    +-            && z[i]!='<' 
    +-            && z[i]!='&' 
    +-            && z[i]!='>' 
    +-            && z[i]!='\"' 
    +-            && z[i]!='\'';
    +-        i++){}
    +-    if( i>0 ){
    +-      fprintf(out,"%.*s",i,z);
    +-    }
    +-    if( z[i]=='<' ){
    +-      fprintf(out,"&lt;");
    +-    }else if( z[i]=='&' ){
    +-      fprintf(out,"&amp;");
    +-    }else if( z[i]=='>' ){
    +-      fprintf(out,"&gt;");
    +-    }else if( z[i]=='\"' ){
    +-      fprintf(out,"&quot;");
    +-    }else if( z[i]=='\'' ){
    +-      fprintf(out,"&#39;");
    +-    }else{
    +-      break;
    +-    }
    +-    z += i + 1;
    +-  }
    +-}
    ++
    ++#if defined(_WIN32) && defined(_MSC_VER) && !defined(SQLITE_WINDIRENT_H)
    ++#define SQLITE_WINDIRENT_H
    + 
    + /*
    +-** If a field contains any character identified by a 1 in the following
    +-** array, then the string must be quoted for CSV.
    ++** We need several data types from the Windows SDK header.
    + */
    +-static const char needCsvQuote[] = {
    +-  1, 1, 1, 1, 1, 1, 1, 1,   1, 1, 1, 1, 1, 1, 1, 1,   
    +-  1, 1, 1, 1, 1, 1, 1, 1,   1, 1, 1, 1, 1, 1, 1, 1,   
    +-  1, 0, 1, 0, 0, 0, 0, 1,   0, 0, 0, 0, 0, 0, 0, 0, 
    +-  0, 0, 0, 0, 0, 0, 0, 0,   0, 0, 0, 0, 0, 0, 0, 0, 
    +-  0, 0, 0, 0, 0, 0, 0, 0,   0, 0, 0, 0, 0, 0, 0, 0, 
    +-  0, 0, 0, 0, 0, 0, 0, 0,   0, 0, 0, 0, 0, 0, 0, 0, 
    +-  0, 0, 0, 0, 0, 0, 0, 0,   0, 0, 0, 0, 0, 0, 0, 0, 
    +-  0, 0, 0, 0, 0, 0, 0, 0,   0, 0, 0, 0, 0, 0, 0, 1, 
    +-  1, 1, 1, 1, 1, 1, 1, 1,   1, 1, 1, 1, 1, 1, 1, 1,   
    +-  1, 1, 1, 1, 1, 1, 1, 1,   1, 1, 1, 1, 1, 1, 1, 1,   
    +-  1, 1, 1, 1, 1, 1, 1, 1,   1, 1, 1, 1, 1, 1, 1, 1,   
    +-  1, 1, 1, 1, 1, 1, 1, 1,   1, 1, 1, 1, 1, 1, 1, 1,   
    +-  1, 1, 1, 1, 1, 1, 1, 1,   1, 1, 1, 1, 1, 1, 1, 1,   
    +-  1, 1, 1, 1, 1, 1, 1, 1,   1, 1, 1, 1, 1, 1, 1, 1,   
    +-  1, 1, 1, 1, 1, 1, 1, 1,   1, 1, 1, 1, 1, 1, 1, 1,   
    +-  1, 1, 1, 1, 1, 1, 1, 1,   1, 1, 1, 1, 1, 1, 1, 1,   
    ++
    ++#define WIN32_LEAN_AND_MEAN
    ++#include "windows.h"
    ++
    ++/*
    ++** We need several support functions from the SQLite core.
    ++*/
    ++
    ++
    ++/*
    ++** We need several things from the ANSI and MSVCRT headers.
    ++*/
    ++
    ++#include <stdio.h>
    ++#include <stdlib.h>
    ++#include <errno.h>
    ++#include <io.h>
    ++#include <limits.h>
    ++#include <sys/types.h>
    ++#include <sys/stat.h>
    ++
    ++/*
    ++** We may need several defines that should have been in "sys/stat.h".
    ++*/
    ++
    ++#ifndef S_ISREG
    ++#define S_ISREG(mode) (((mode) & S_IFMT) == S_IFREG)
    ++#endif
    ++
    ++#ifndef S_ISDIR
    ++#define S_ISDIR(mode) (((mode) & S_IFMT) == S_IFDIR)
    ++#endif
    ++
    ++#ifndef S_ISLNK
    ++#define S_ISLNK(mode) (0)
    ++#endif
    ++
    ++/*
    ++** We may need to provide the "mode_t" type.
    ++*/
    ++
    ++#ifndef MODE_T_DEFINED
    ++  #define MODE_T_DEFINED
    ++  typedef unsigned short mode_t;
    ++#endif
    ++
    ++/*
    ++** We may need to provide the "ino_t" type.
    ++*/
    ++
    ++#ifndef INO_T_DEFINED
    ++  #define INO_T_DEFINED
    ++  typedef unsigned short ino_t;
    ++#endif
    ++
    ++/*
    ++** We need to define "NAME_MAX" if it was not present in "limits.h".
    ++*/
    ++
    ++#ifndef NAME_MAX
    ++#  ifdef FILENAME_MAX
    ++#    define NAME_MAX (FILENAME_MAX)
    ++#  else
    ++#    define NAME_MAX (260)
    ++#  endif
    ++#endif
    ++
    ++/*
    ++** We need to define "NULL_INTPTR_T" and "BAD_INTPTR_T".
    ++*/
    ++
    ++#ifndef NULL_INTPTR_T
    ++#  define NULL_INTPTR_T ((intptr_t)(0))
    ++#endif
    ++
    ++#ifndef BAD_INTPTR_T
    ++#  define BAD_INTPTR_T ((intptr_t)(-1))
    ++#endif
    ++
    ++/*
    ++** We need to provide the necessary structures and related types.
    ++*/
    ++
    ++#ifndef DIRENT_DEFINED
    ++#define DIRENT_DEFINED
    ++typedef struct DIRENT DIRENT;
    ++typedef DIRENT *LPDIRENT;
    ++struct DIRENT {
    ++  ino_t d_ino;               /* Sequence number, do not use. */
    ++  unsigned d_attributes;     /* Win32 file attributes. */
    ++  char d_name[NAME_MAX + 1]; /* Name within the directory. */
    + };
    ++#endif
    ++
    ++#ifndef DIR_DEFINED
    ++#define DIR_DEFINED
    ++typedef struct DIR DIR;
    ++typedef DIR *LPDIR;
    ++struct DIR {
    ++  intptr_t d_handle; /* Value returned by "_findfirst". */
    ++  DIRENT d_first;    /* DIRENT constructed based on "_findfirst". */
    ++  DIRENT d_next;     /* DIRENT constructed based on "_findnext". */
    ++};
    ++#endif
    + 
    + /*
    +-** Output a single term of CSV.  Actually, p->colSeparator is used for
    +-** the separator, which may or may not be a comma.  p->nullValue is
    +-** the null value.  Strings are quoted if necessary.  The separator
    +-** is only issued if bSep is true.
    ++** Provide a macro, for use by the implementation, to determine if a
    ++** particular directory entry should be skipped over when searching for
    ++** the next directory entry that should be returned by the readdir() or
    ++** readdir_r() functions.
    + */
    +-static void output_csv(ShellState *p, const char *z, int bSep){
    +-  FILE *out = p->out;
    +-  if( z==0 ){
    +-    fprintf(out,"%s",p->nullValue);
    ++
    ++#ifndef is_filtered
    ++#  define is_filtered(a) ((((a).attrib)&_A_HIDDEN) || (((a).attrib)&_A_SYSTEM))
    ++#endif
    ++
    ++/*
    ++** Provide the function prototype for the POSIX compatiable getenv()
    ++** function.  This function is not thread-safe.
    ++*/
    ++
    ++extern const char *windirent_getenv(const char *name);
    ++
    ++/*
    ++** Finally, we can provide the function prototypes for the opendir(),
    ++** readdir(), readdir_r(), and closedir() POSIX functions.
    ++*/
    ++
    ++extern LPDIR opendir(const char *dirname);
    ++extern LPDIRENT readdir(LPDIR dirp);
    ++extern INT readdir_r(LPDIR dirp, LPDIRENT entry, LPDIRENT *result);
    ++extern INT closedir(LPDIR dirp);
    ++
    ++#endif /* defined(WIN32) && defined(_MSC_VER) */
    ++
    ++/************************* End test_windirent.h ********************/
    ++/************************* Begin test_windirent.c ******************/
    ++/*
    ++** 2015 November 30
    ++**
    ++** 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 to implement most of the opendir() family of
    ++** POSIX functions on Win32 using the MSVCRT.
    ++*/
    ++
    ++#if defined(_WIN32) && defined(_MSC_VER)
    ++/* #include "test_windirent.h" */
    ++
    ++/*
    ++** Implementation of the POSIX getenv() function using the Win32 API.
    ++** This function is not thread-safe.
    ++*/
    ++const char *windirent_getenv(
    ++  const char *name
    ++){
    ++  static char value[32768]; /* Maximum length, per MSDN */
    ++  DWORD dwSize = sizeof(value) / sizeof(char); /* Size in chars */
    ++  DWORD dwRet; /* Value returned by GetEnvironmentVariableA() */
    ++
    ++  memset(value, 0, sizeof(value));
    ++  dwRet = GetEnvironmentVariableA(name, value, dwSize);
    ++  if( dwRet==0 || dwRet>dwSize ){
    ++    /*
    ++    ** The function call to GetEnvironmentVariableA() failed -OR-
    ++    ** the buffer is not large enough.  Either way, return NULL.
    ++    */
    ++    return 0;
    +   }else{
    +-    int i;
    +-    int nSep = strlen30(p->colSeparator);
    +-    for(i=0; z[i]; i++){
    +-      if( needCsvQuote[((unsigned char*)z)[i]] 
    +-         || (z[i]==p->colSeparator[0] && 
    +-             (nSep==1 || memcmp(z, p->colSeparator, nSep)==0)) ){
    +-        i = 0;
    +-        break;
    +-      }
    +-    }
    +-    if( i==0 ){
    +-      putc('"', out);
    +-      for(i=0; z[i]; i++){
    +-        if( z[i]=='"' ) putc('"', out);
    +-        putc(z[i], out);
    +-      }
    +-      putc('"', out);
    +-    }else{
    +-      fprintf(out, "%s", z);
    ++    /*
    ++    ** The function call to GetEnvironmentVariableA() succeeded
    ++    ** -AND- the buffer contains the entire value.
    ++    */
    ++    return value;
    ++  }
    ++}
    ++
    ++/*
    ++** Implementation of the POSIX opendir() function using the MSVCRT.
    ++*/
    ++LPDIR opendir(
    ++  const char *dirname
    ++){
    ++  struct _finddata_t data;
    ++  LPDIR dirp = (LPDIR)sqlite3_malloc(sizeof(DIR));
    ++  SIZE_T namesize = sizeof(data.name) / sizeof(data.name[0]);
    ++
    ++  if( dirp==NULL ) return NULL;
    ++  memset(dirp, 0, sizeof(DIR));
    ++
    ++  /* TODO: Remove this if Unix-style root paths are not used. */
    ++  if( sqlite3_stricmp(dirname, "/")==0 ){
    ++    dirname = windirent_getenv("SystemDrive");
    ++  }
    ++
    ++  memset(&data, 0, sizeof(struct _finddata_t));
    ++  _snprintf(data.name, namesize, "%s\\*", dirname);
    ++  dirp->d_handle = _findfirst(data.name, &data);
    ++
    ++  if( dirp->d_handle==BAD_INTPTR_T ){
    ++    closedir(dirp);
    ++    return NULL;
    ++  }
    ++
    ++  /* TODO: Remove this block to allow hidden and/or system files. */
    ++  if( is_filtered(data) ){
    ++next:
    ++
    ++    memset(&data, 0, sizeof(struct _finddata_t));
    ++    if( _findnext(dirp->d_handle, &data)==-1 ){
    ++      closedir(dirp);
    ++      return NULL;
    +     }
    ++
    ++    /* TODO: Remove this block to allow hidden and/or system files. */
    ++    if( is_filtered(data) ) goto next;
    +   }
    +-  if( bSep ){
    +-    fprintf(p->out, "%s", p->colSeparator);
    ++
    ++  dirp->d_first.d_attributes = data.attrib;
    ++  strncpy(dirp->d_first.d_name, data.name, NAME_MAX);
    ++  dirp->d_first.d_name[NAME_MAX] = '\0';
    ++
    ++  return dirp;
    ++}
    ++
    ++/*
    ++** Implementation of the POSIX readdir() function using the MSVCRT.
    ++*/
    ++LPDIRENT readdir(
    ++  LPDIR dirp
    ++){
    ++  struct _finddata_t data;
    ++
    ++  if( dirp==NULL ) return NULL;
    ++
    ++  if( dirp->d_first.d_ino==0 ){
    ++    dirp->d_first.d_ino++;
    ++    dirp->d_next.d_ino++;
    ++
    ++    return &dirp->d_first;
    +   }
    ++
    ++next:
    ++
    ++  memset(&data, 0, sizeof(struct _finddata_t));
    ++  if( _findnext(dirp->d_handle, &data)==-1 ) return NULL;
    ++
    ++  /* TODO: Remove this block to allow hidden and/or system files. */
    ++  if( is_filtered(data) ) goto next;
    ++
    ++  dirp->d_next.d_ino++;
    ++  dirp->d_next.d_attributes = data.attrib;
    ++  strncpy(dirp->d_next.d_name, data.name, NAME_MAX);
    ++  dirp->d_next.d_name[NAME_MAX] = '\0';
    ++
    ++  return &dirp->d_next;
    + }
    + 
    +-#ifdef SIGINT
    + /*
    +-** This routine runs when the user presses Ctrl-C
    ++** Implementation of the POSIX readdir_r() function using the MSVCRT.
    + */
    +-static void interrupt_handler(int NotUsed){
    +-  UNUSED_PARAMETER(NotUsed);
    +-  seenInterrupt++;
    +-  if( seenInterrupt>2 ) exit(1);
    +-  if( globalDb ) sqlite3_interrupt(globalDb);
    ++INT readdir_r(
    ++  LPDIR dirp,
    ++  LPDIRENT entry,
    ++  LPDIRENT *result
    ++){
    ++  struct _finddata_t data;
    ++
    ++  if( dirp==NULL ) return EBADF;
    ++
    ++  if( dirp->d_first.d_ino==0 ){
    ++    dirp->d_first.d_ino++;
    ++    dirp->d_next.d_ino++;
    ++
    ++    entry->d_ino = dirp->d_first.d_ino;
    ++    entry->d_attributes = dirp->d_first.d_attributes;
    ++    strncpy(entry->d_name, dirp->d_first.d_name, NAME_MAX);
    ++    entry->d_name[NAME_MAX] = '\0';
    ++
    ++    *result = entry;
    ++    return 0;
    ++  }
    ++
    ++next:
    ++
    ++  memset(&data, 0, sizeof(struct _finddata_t));
    ++  if( _findnext(dirp->d_handle, &data)==-1 ){
    ++    *result = NULL;
    ++    return ENOENT;
    ++  }
    ++
    ++  /* TODO: Remove this block to allow hidden and/or system files. */
    ++  if( is_filtered(data) ) goto next;
    ++
    ++  entry->d_ino = (ino_t)-1; /* not available */
    ++  entry->d_attributes = data.attrib;
    ++  strncpy(entry->d_name, data.name, NAME_MAX);
    ++  entry->d_name[NAME_MAX] = '\0';
    ++
    ++  *result = entry;
    ++  return 0;
    + }
    +-#endif
    + 
    + /*
    +-** This is the callback routine that the shell
    +-** invokes for each row of a query result.
    ++** Implementation of the POSIX closedir() function using the MSVCRT.
    + */
    +-static int shell_callback(
    +-  void *pArg,
    +-  int nArg,        /* Number of result columns */
    +-  char **azArg,    /* Text of each result column */
    +-  char **azCol,    /* Column names */
    +-  int *aiType      /* Column types */
    ++INT closedir(
    ++  LPDIR dirp
    + ){
    +-  int i;
    +-  ShellState *p = (ShellState*)pArg;
    ++  INT result = 0;
    + 
    +-  switch( p->mode ){
    +-    case MODE_Line: {
    +-      int w = 5;
    +-      if( azArg==0 ) break;
    +-      for(i=0; i<nArg; i++){
    +-        int len = strlen30(azCol[i] ? azCol[i] : "");
    +-        if( len>w ) w = len;
    +-      }
    +-      if( p->cnt++>0 ) fprintf(p->out, "%s", p->rowSeparator);
    +-      for(i=0; i<nArg; i++){
    +-        fprintf(p->out,"%*s = %s%s", w, azCol[i],
    +-                azArg[i] ? azArg[i] : p->nullValue, p->rowSeparator);
    +-      }
    +-      break;
    +-    }
    +-    case MODE_Explain:
    +-    case MODE_Column: {
    +-      if( p->cnt++==0 ){
    +-        for(i=0; i<nArg; i++){
    +-          int w, n;
    +-          if( i<ArraySize(p->colWidth) ){
    +-            w = p->colWidth[i];
    +-          }else{
    +-            w = 0;
    +-          }
    +-          if( w==0 ){
    +-            w = strlen30(azCol[i] ? azCol[i] : "");
    +-            if( w<10 ) w = 10;
    +-            n = strlen30(azArg && azArg[i] ? azArg[i] : p->nullValue);
    +-            if( w<n ) w = n;
    +-          }
    +-          if( i<ArraySize(p->actualWidth) ){
    +-            p->actualWidth[i] = w;
    +-          }
    +-          if( p->showHeader ){
    +-            if( w<0 ){
    +-              fprintf(p->out,"%*.*s%s",-w,-w,azCol[i],
    +-                      i==nArg-1 ? p->rowSeparator : "  ");
    +-            }else{
    +-              fprintf(p->out,"%-*.*s%s",w,w,azCol[i],
    +-                      i==nArg-1 ? p->rowSeparator : "  ");
    +-            }
    +-          }
    +-        }
    +-        if( p->showHeader ){
    +-          for(i=0; i<nArg; i++){
    +-            int w;
    +-            if( i<ArraySize(p->actualWidth) ){
    +-               w = p->actualWidth[i];
    +-               if( w<0 ) w = -w;
    +-            }else{
    +-               w = 10;
    +-            }
    +-            fprintf(p->out,"%-*.*s%s",w,w,"-----------------------------------"
    +-                   "----------------------------------------------------------",
    +-                    i==nArg-1 ? p->rowSeparator : "  ");
    +-          }
    +-        }
    +-      }
    +-      if( azArg==0 ) break;
    +-      for(i=0; i<nArg; i++){
    +-        int w;
    +-        if( i<ArraySize(p->actualWidth) ){
    +-           w = p->actualWidth[i];
    +-        }else{
    +-           w = 10;
    +-        }
    +-        if( p->mode==MODE_Explain && azArg[i] && strlen30(azArg[i])>w ){
    +-          w = strlen30(azArg[i]);
    +-        }
    +-        if( i==1 && p->aiIndent && p->pStmt ){
    +-          if( p->iIndent<p->nIndent ){
    +-            fprintf(p->out, "%*.s", p->aiIndent[p->iIndent], "");
    +-          }
    +-          p->iIndent++;
    +-        }
    +-        if( w<0 ){
    +-          fprintf(p->out,"%*.*s%s",-w,-w,
    +-              azArg[i] ? azArg[i] : p->nullValue,
    +-              i==nArg-1 ? p->rowSeparator : "  ");
    +-        }else{
    +-          fprintf(p->out,"%-*.*s%s",w,w,
    +-              azArg[i] ? azArg[i] : p->nullValue,
    +-              i==nArg-1 ? p->rowSeparator : "  ");
    +-        }
    +-      }
    +-      break;
    +-    }
    +-    case MODE_Semi:
    +-    case MODE_List: {
    +-      if( p->cnt++==0 && p->showHeader ){
    +-        for(i=0; i<nArg; i++){
    +-          fprintf(p->out,"%s%s",azCol[i],
    +-                  i==nArg-1 ? p->rowSeparator : p->colSeparator);
    +-        }
    +-      }
    +-      if( azArg==0 ) break;
    +-      for(i=0; i<nArg; i++){
    +-        char *z = azArg[i];
    +-        if( z==0 ) z = p->nullValue;
    +-        fprintf(p->out, "%s", z);
    +-        if( i<nArg-1 ){
    +-          fprintf(p->out, "%s", p->colSeparator);
    +-        }else if( p->mode==MODE_Semi ){
    +-          fprintf(p->out, ";%s", p->rowSeparator);
    +-        }else{
    +-          fprintf(p->out, "%s", p->rowSeparator);
    +-        }
    +-      }
    +-      break;
    +-    }
    +-    case MODE_Html: {
    +-      if( p->cnt++==0 && p->showHeader ){
    +-        fprintf(p->out,"<TR>");
    +-        for(i=0; i<nArg; i++){
    +-          fprintf(p->out,"<TH>");
    +-          output_html_string(p->out, azCol[i]);
    +-          fprintf(p->out,"</TH>\n");
    +-        }
    +-        fprintf(p->out,"</TR>\n");
    +-      }
    +-      if( azArg==0 ) break;
    +-      fprintf(p->out,"<TR>");
    +-      for(i=0; i<nArg; i++){
    +-        fprintf(p->out,"<TD>");
    +-        output_html_string(p->out, azArg[i] ? azArg[i] : p->nullValue);
    +-        fprintf(p->out,"</TD>\n");
    +-      }
    +-      fprintf(p->out,"</TR>\n");
    +-      break;
    +-    }
    +-    case MODE_Tcl: {
    +-      if( p->cnt++==0 && p->showHeader ){
    +-        for(i=0; i<nArg; i++){
    +-          output_c_string(p->out,azCol[i] ? azCol[i] : "");
    +-          if(i<nArg-1) fprintf(p->out, "%s", p->colSeparator);
    +-        }
    +-        fprintf(p->out, "%s", p->rowSeparator);
    +-      }
    +-      if( azArg==0 ) break;
    +-      for(i=0; i<nArg; i++){
    +-        output_c_string(p->out, azArg[i] ? azArg[i] : p->nullValue);
    +-        if(i<nArg-1) fprintf(p->out, "%s", p->colSeparator);
    +-      }
    +-      fprintf(p->out, "%s", p->rowSeparator);
    +-      break;
    +-    }
    +-    case MODE_Csv: {
    +-      setBinaryMode(p->out);
    +-      if( p->cnt++==0 && p->showHeader ){
    +-        for(i=0; i<nArg; i++){
    +-          output_csv(p, azCol[i] ? azCol[i] : "", i<nArg-1);
    +-        }
    +-        fprintf(p->out, "%s", p->rowSeparator);
    +-      }
    +-      if( nArg>0 ){
    +-        for(i=0; i<nArg; i++){
    +-          output_csv(p, azArg[i], i<nArg-1);
    +-        }
    +-        fprintf(p->out, "%s", p->rowSeparator);
    +-      }
    +-      setTextMode(p->out);
    +-      break;
    +-    }
    +-    case MODE_Insert: {
    +-      p->cnt++;
    +-      if( azArg==0 ) break;
    +-      fprintf(p->out,"INSERT INTO %s",p->zDestTable);
    +-      if( p->showHeader ){
    +-        fprintf(p->out,"(");
    +-        for(i=0; i<nArg; i++){
    +-          char *zSep = i>0 ? ",": "";
    +-          fprintf(p->out, "%s%s", zSep, azCol[i]);
    +-        }
    +-        fprintf(p->out,")");
    +-      }
    +-      fprintf(p->out," VALUES(");
    +-      for(i=0; i<nArg; i++){
    +-        char *zSep = i>0 ? ",": "";
    +-        if( (azArg[i]==0) || (aiType && aiType[i]==SQLITE_NULL) ){
    +-          fprintf(p->out,"%sNULL",zSep);
    +-        }else if( aiType && aiType[i]==SQLITE_TEXT ){
    +-          if( zSep[0] ) fprintf(p->out,"%s",zSep);
    +-          output_quoted_string(p->out, azArg[i]);
    +-        }else if( aiType && (aiType[i]==SQLITE_INTEGER
    +-                             || aiType[i]==SQLITE_FLOAT) ){
    +-          fprintf(p->out,"%s%s",zSep, azArg[i]);
    +-        }else if( aiType && aiType[i]==SQLITE_BLOB && p->pStmt ){
    +-          const void *pBlob = sqlite3_column_blob(p->pStmt, i);
    +-          int nBlob = sqlite3_column_bytes(p->pStmt, i);
    +-          if( zSep[0] ) fprintf(p->out,"%s",zSep);
    +-          output_hex_blob(p->out, pBlob, nBlob);
    +-        }else if( isNumber(azArg[i], 0) ){
    +-          fprintf(p->out,"%s%s",zSep, azArg[i]);
    +-        }else{
    +-          if( zSep[0] ) fprintf(p->out,"%s",zSep);
    +-          output_quoted_string(p->out, azArg[i]);
    +-        }
    +-      }
    +-      fprintf(p->out,");\n");
    +-      break;
    +-    }
    +-    case MODE_Ascii: {
    +-      if( p->cnt++==0 && p->showHeader ){
    +-        for(i=0; i<nArg; i++){
    +-          if( i>0 ) fprintf(p->out, "%s", p->colSeparator);
    +-          fprintf(p->out,"%s",azCol[i] ? azCol[i] : "");
    +-        }
    +-        fprintf(p->out, "%s", p->rowSeparator);
    +-      }
    +-      if( azArg==0 ) break;
    +-      for(i=0; i<nArg; i++){
    +-        if( i>0 ) fprintf(p->out, "%s", p->colSeparator);
    +-        fprintf(p->out,"%s",azArg[i] ? azArg[i] : p->nullValue);
    +-      }
    +-      fprintf(p->out, "%s", p->rowSeparator);
    +-      break;
    +-    }
    ++  if( dirp==NULL ) return EINVAL;
    ++
    ++  if( dirp->d_handle!=NULL_INTPTR_T && dirp->d_handle!=BAD_INTPTR_T ){
    ++    result = _findclose(dirp->d_handle);
    +   }
    +-  return 0;
    ++
    ++  sqlite3_free(dirp);
    ++  return result;
    + }
    + 
    ++#endif /* defined(WIN32) && defined(_MSC_VER) */
    ++
    ++/************************* End test_windirent.c ********************/
    ++#define dirent DIRENT
    ++#endif
    ++/************************* Begin ../ext/misc/shathree.c ******************/
    + /*
    +-** This is the callback routine that the SQLite library
    +-** invokes for each row of a query result.
    ++** 2017-03-08
    ++**
    ++** 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 SQLite extension implements a functions that compute SHA1 hashes.
    ++** Two SQL functions are implemented:
    ++**
    ++**     sha3(X,SIZE)
    ++**     sha3_query(Y,SIZE)
    ++**
    ++** The sha3(X) function computes the SHA3 hash of the input X, or NULL if
    ++** X is NULL.
    ++**
    ++** The sha3_query(Y) function evalutes all queries in the SQL statements of Y
    ++** and returns a hash of their results.
    ++**
    ++** The SIZE argument is optional.  If omitted, the SHA3-256 hash algorithm
    ++** is used.  If SIZE is included it must be one of the integers 224, 256,
    ++** 384, or 512, to determine SHA3 hash variant that is computed.
    + */
    +-static int callback(void *pArg, int nArg, char **azArg, char **azCol){
    +-  /* since we don't have type info, call the shell_callback with a NULL value */
    +-  return shell_callback(pArg, nArg, azArg, azCol, NULL);
    +-}
    ++SQLITE_EXTENSION_INIT1
    ++#include <assert.h>
    ++#include <string.h>
    ++#include <stdarg.h>
    ++/* typedef sqlite3_uint64 u64; */
    + 
    ++/******************************************************************************
    ++** The Hash Engine
    ++*/
    + /*
    +-** Set the destination table field of the ShellState structure to
    +-** the name of the table given.  Escape any quote characters in the
    +-** table name.
    ++** Macros to determine whether the machine is big or little endian,
    ++** 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
    ++** -DSHA3_BYTEORDER=0 is set, then byte-order is determined
    ++** at run-time.
    + */
    +-static void set_table_name(ShellState *p, const char *zName){
    +-  int i, n;
    +-  int needQuote;
    +-  char *z;
    ++#ifndef SHA3_BYTEORDER
    ++# 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__)
    ++#   define SHA3_BYTEORDER    1234
    ++# elif defined(sparc)    || defined(__ppc__)
    ++#   define SHA3_BYTEORDER    4321
    ++# else
    ++#   define SHA3_BYTEORDER 0
    ++# endif
    ++#endif
    + 
    +-  if( p->zDestTable ){
    +-    free(p->zDestTable);
    +-    p->zDestTable = 0;
    +-  }
    +-  if( zName==0 ) return;
    +-  needQuote = !isalpha((unsigned char)*zName) && *zName!='_';
    +-  for(i=n=0; zName[i]; i++, n++){
    +-    if( !isalnum((unsigned char)zName[i]) && zName[i]!='_' ){
    +-      needQuote = 1;
    +-      if( zName[i]=='\'' ) n++;
    +-    }
    ++
    ++/*
    ++** State structure for a SHA3 hash in progress
    ++*/
    ++typedef struct SHA3Context SHA3Context;
    ++struct SHA3Context {
    ++  union {
    ++    u64 s[25];                /* Keccak state. 5x5 lines of 64 bits each */
    ++    unsigned char x[1600];    /* ... or 1600 bytes */
    ++  } u;
    ++  unsigned nRate;        /* Bytes of input accepted per Keccak iteration */
    ++  unsigned nLoaded;      /* Input bytes loaded into u.x[] so far this cycle */
    ++  unsigned ixMask;       /* Insert next input into u.x[nLoaded^ixMask]. */
    ++};
    ++
    ++/*
    ++** A single step of the Keccak mixing function for a 1600-bit state
    ++*/
    ++static void KeccakF1600Step(SHA3Context *p){
    ++  int i;
    ++  u64 b0, b1, b2, b3, b4;
    ++  u64 c0, c1, c2, c3, c4;
    ++  u64 d0, d1, d2, d3, d4;
    ++  static const u64 RC[] = {
    ++    0x0000000000000001ULL,  0x0000000000008082ULL,
    ++    0x800000000000808aULL,  0x8000000080008000ULL,
    ++    0x000000000000808bULL,  0x0000000080000001ULL,
    ++    0x8000000080008081ULL,  0x8000000000008009ULL,
    ++    0x000000000000008aULL,  0x0000000000000088ULL,
    ++    0x0000000080008009ULL,  0x000000008000000aULL,
    ++    0x000000008000808bULL,  0x800000000000008bULL,
    ++    0x8000000000008089ULL,  0x8000000000008003ULL,
    ++    0x8000000000008002ULL,  0x8000000000000080ULL,
    ++    0x000000000000800aULL,  0x800000008000000aULL,
    ++    0x8000000080008081ULL,  0x8000000000008080ULL,
    ++    0x0000000080000001ULL,  0x8000000080008008ULL
    ++  };
    ++# define a00 (p->u.s[0])
    ++# define a01 (p->u.s[1])
    ++# define a02 (p->u.s[2])
    ++# define a03 (p->u.s[3])
    ++# define a04 (p->u.s[4])
    ++# define a10 (p->u.s[5])
    ++# define a11 (p->u.s[6])
    ++# define a12 (p->u.s[7])
    ++# define a13 (p->u.s[8])
    ++# define a14 (p->u.s[9])
    ++# define a20 (p->u.s[10])
    ++# define a21 (p->u.s[11])
    ++# define a22 (p->u.s[12])
    ++# define a23 (p->u.s[13])
    ++# define a24 (p->u.s[14])
    ++# define a30 (p->u.s[15])
    ++# define a31 (p->u.s[16])
    ++# define a32 (p->u.s[17])
    ++# define a33 (p->u.s[18])
    ++# define a34 (p->u.s[19])
    ++# define a40 (p->u.s[20])
    ++# define a41 (p->u.s[21])
    ++# define a42 (p->u.s[22])
    ++# define a43 (p->u.s[23])
    ++# define a44 (p->u.s[24])
    ++# define ROL64(a,x) ((a<<x)|(a>>(64-x)))
    ++
    ++  for(i=0; i<24; i+=4){
    ++    c0 = a00^a10^a20^a30^a40;
    ++    c1 = a01^a11^a21^a31^a41;
    ++    c2 = a02^a12^a22^a32^a42;
    ++    c3 = a03^a13^a23^a33^a43;
    ++    c4 = a04^a14^a24^a34^a44;
    ++    d0 = c4^ROL64(c1, 1);
    ++    d1 = c0^ROL64(c2, 1);
    ++    d2 = c1^ROL64(c3, 1);
    ++    d3 = c2^ROL64(c4, 1);
    ++    d4 = c3^ROL64(c0, 1);
    ++
    ++    b0 = (a00^d0);
    ++    b1 = ROL64((a11^d1), 44);
    ++    b2 = ROL64((a22^d2), 43);
    ++    b3 = ROL64((a33^d3), 21);
    ++    b4 = ROL64((a44^d4), 14);
    ++    a00 =   b0 ^((~b1)&  b2 );
    ++    a00 ^= RC[i];
    ++    a11 =   b1 ^((~b2)&  b3 );
    ++    a22 =   b2 ^((~b3)&  b4 );
    ++    a33 =   b3 ^((~b4)&  b0 );
    ++    a44 =   b4 ^((~b0)&  b1 );
    ++
    ++    b2 = ROL64((a20^d0), 3);
    ++    b3 = ROL64((a31^d1), 45);
    ++    b4 = ROL64((a42^d2), 61);
    ++    b0 = ROL64((a03^d3), 28);
    ++    b1 = ROL64((a14^d4), 20);
    ++    a20 =   b0 ^((~b1)&  b2 );
    ++    a31 =   b1 ^((~b2)&  b3 );
    ++    a42 =   b2 ^((~b3)&  b4 );
    ++    a03 =   b3 ^((~b4)&  b0 );
    ++    a14 =   b4 ^((~b0)&  b1 );
    ++
    ++    b4 = ROL64((a40^d0), 18);
    ++    b0 = ROL64((a01^d1), 1);
    ++    b1 = ROL64((a12^d2), 6);
    ++    b2 = ROL64((a23^d3), 25);
    ++    b3 = ROL64((a34^d4), 8);
    ++    a40 =   b0 ^((~b1)&  b2 );
    ++    a01 =   b1 ^((~b2)&  b3 );
    ++    a12 =   b2 ^((~b3)&  b4 );
    ++    a23 =   b3 ^((~b4)&  b0 );
    ++    a34 =   b4 ^((~b0)&  b1 );
    ++
    ++    b1 = ROL64((a10^d0), 36);
    ++    b2 = ROL64((a21^d1), 10);
    ++    b3 = ROL64((a32^d2), 15);
    ++    b4 = ROL64((a43^d3), 56);
    ++    b0 = ROL64((a04^d4), 27);
    ++    a10 =   b0 ^((~b1)&  b2 );
    ++    a21 =   b1 ^((~b2)&  b3 );
    ++    a32 =   b2 ^((~b3)&  b4 );
    ++    a43 =   b3 ^((~b4)&  b0 );
    ++    a04 =   b4 ^((~b0)&  b1 );
    ++
    ++    b3 = ROL64((a30^d0), 41);
    ++    b4 = ROL64((a41^d1), 2);
    ++    b0 = ROL64((a02^d2), 62);
    ++    b1 = ROL64((a13^d3), 55);
    ++    b2 = ROL64((a24^d4), 39);
    ++    a30 =   b0 ^((~b1)&  b2 );
    ++    a41 =   b1 ^((~b2)&  b3 );
    ++    a02 =   b2 ^((~b3)&  b4 );
    ++    a13 =   b3 ^((~b4)&  b0 );
    ++    a24 =   b4 ^((~b0)&  b1 );
    ++
    ++    c0 = a00^a20^a40^a10^a30;
    ++    c1 = a11^a31^a01^a21^a41;
    ++    c2 = a22^a42^a12^a32^a02;
    ++    c3 = a33^a03^a23^a43^a13;
    ++    c4 = a44^a14^a34^a04^a24;
    ++    d0 = c4^ROL64(c1, 1);
    ++    d1 = c0^ROL64(c2, 1);
    ++    d2 = c1^ROL64(c3, 1);
    ++    d3 = c2^ROL64(c4, 1);
    ++    d4 = c3^ROL64(c0, 1);
    ++
    ++    b0 = (a00^d0);
    ++    b1 = ROL64((a31^d1), 44);
    ++    b2 = ROL64((a12^d2), 43);
    ++    b3 = ROL64((a43^d3), 21);
    ++    b4 = ROL64((a24^d4), 14);
    ++    a00 =   b0 ^((~b1)&  b2 );
    ++    a00 ^= RC[i+1];
    ++    a31 =   b1 ^((~b2)&  b3 );
    ++    a12 =   b2 ^((~b3)&  b4 );
    ++    a43 =   b3 ^((~b4)&  b0 );
    ++    a24 =   b4 ^((~b0)&  b1 );
    ++
    ++    b2 = ROL64((a40^d0), 3);
    ++    b3 = ROL64((a21^d1), 45);
    ++    b4 = ROL64((a02^d2), 61);
    ++    b0 = ROL64((a33^d3), 28);
    ++    b1 = ROL64((a14^d4), 20);
    ++    a40 =   b0 ^((~b1)&  b2 );
    ++    a21 =   b1 ^((~b2)&  b3 );
    ++    a02 =   b2 ^((~b3)&  b4 );
    ++    a33 =   b3 ^((~b4)&  b0 );
    ++    a14 =   b4 ^((~b0)&  b1 );
    ++
    ++    b4 = ROL64((a30^d0), 18);
    ++    b0 = ROL64((a11^d1), 1);
    ++    b1 = ROL64((a42^d2), 6);
    ++    b2 = ROL64((a23^d3), 25);
    ++    b3 = ROL64((a04^d4), 8);
    ++    a30 =   b0 ^((~b1)&  b2 );
    ++    a11 =   b1 ^((~b2)&  b3 );
    ++    a42 =   b2 ^((~b3)&  b4 );
    ++    a23 =   b3 ^((~b4)&  b0 );
    ++    a04 =   b4 ^((~b0)&  b1 );
    ++
    ++    b1 = ROL64((a20^d0), 36);
    ++    b2 = ROL64((a01^d1), 10);
    ++    b3 = ROL64((a32^d2), 15);
    ++    b4 = ROL64((a13^d3), 56);
    ++    b0 = ROL64((a44^d4), 27);
    ++    a20 =   b0 ^((~b1)&  b2 );
    ++    a01 =   b1 ^((~b2)&  b3 );
    ++    a32 =   b2 ^((~b3)&  b4 );
    ++    a13 =   b3 ^((~b4)&  b0 );
    ++    a44 =   b4 ^((~b0)&  b1 );
    ++
    ++    b3 = ROL64((a10^d0), 41);
    ++    b4 = ROL64((a41^d1), 2);
    ++    b0 = ROL64((a22^d2), 62);
    ++    b1 = ROL64((a03^d3), 55);
    ++    b2 = ROL64((a34^d4), 39);
    ++    a10 =   b0 ^((~b1)&  b2 );
    ++    a41 =   b1 ^((~b2)&  b3 );
    ++    a22 =   b2 ^((~b3)&  b4 );
    ++    a03 =   b3 ^((~b4)&  b0 );
    ++    a34 =   b4 ^((~b0)&  b1 );
    ++
    ++    c0 = a00^a40^a30^a20^a10;
    ++    c1 = a31^a21^a11^a01^a41;
    ++    c2 = a12^a02^a42^a32^a22;
    ++    c3 = a43^a33^a23^a13^a03;
    ++    c4 = a24^a14^a04^a44^a34;
    ++    d0 = c4^ROL64(c1, 1);
    ++    d1 = c0^ROL64(c2, 1);
    ++    d2 = c1^ROL64(c3, 1);
    ++    d3 = c2^ROL64(c4, 1);
    ++    d4 = c3^ROL64(c0, 1);
    ++
    ++    b0 = (a00^d0);
    ++    b1 = ROL64((a21^d1), 44);
    ++    b2 = ROL64((a42^d2), 43);
    ++    b3 = ROL64((a13^d3), 21);
    ++    b4 = ROL64((a34^d4), 14);
    ++    a00 =   b0 ^((~b1)&  b2 );
    ++    a00 ^= RC[i+2];
    ++    a21 =   b1 ^((~b2)&  b3 );
    ++    a42 =   b2 ^((~b3)&  b4 );
    ++    a13 =   b3 ^((~b4)&  b0 );
    ++    a34 =   b4 ^((~b0)&  b1 );
    ++
    ++    b2 = ROL64((a30^d0), 3);
    ++    b3 = ROL64((a01^d1), 45);
    ++    b4 = ROL64((a22^d2), 61);
    ++    b0 = ROL64((a43^d3), 28);
    ++    b1 = ROL64((a14^d4), 20);
    ++    a30 =   b0 ^((~b1)&  b2 );
    ++    a01 =   b1 ^((~b2)&  b3 );
    ++    a22 =   b2 ^((~b3)&  b4 );
    ++    a43 =   b3 ^((~b4)&  b0 );
    ++    a14 =   b4 ^((~b0)&  b1 );
    ++
    ++    b4 = ROL64((a10^d0), 18);
    ++    b0 = ROL64((a31^d1), 1);
    ++    b1 = ROL64((a02^d2), 6);
    ++    b2 = ROL64((a23^d3), 25);
    ++    b3 = ROL64((a44^d4), 8);
    ++    a10 =   b0 ^((~b1)&  b2 );
    ++    a31 =   b1 ^((~b2)&  b3 );
    ++    a02 =   b2 ^((~b3)&  b4 );
    ++    a23 =   b3 ^((~b4)&  b0 );
    ++    a44 =   b4 ^((~b0)&  b1 );
    ++
    ++    b1 = ROL64((a40^d0), 36);
    ++    b2 = ROL64((a11^d1), 10);
    ++    b3 = ROL64((a32^d2), 15);
    ++    b4 = ROL64((a03^d3), 56);
    ++    b0 = ROL64((a24^d4), 27);
    ++    a40 =   b0 ^((~b1)&  b2 );
    ++    a11 =   b1 ^((~b2)&  b3 );
    ++    a32 =   b2 ^((~b3)&  b4 );
    ++    a03 =   b3 ^((~b4)&  b0 );
    ++    a24 =   b4 ^((~b0)&  b1 );
    ++
    ++    b3 = ROL64((a20^d0), 41);
    ++    b4 = ROL64((a41^d1), 2);
    ++    b0 = ROL64((a12^d2), 62);
    ++    b1 = ROL64((a33^d3), 55);
    ++    b2 = ROL64((a04^d4), 39);
    ++    a20 =   b0 ^((~b1)&  b2 );
    ++    a41 =   b1 ^((~b2)&  b3 );
    ++    a12 =   b2 ^((~b3)&  b4 );
    ++    a33 =   b3 ^((~b4)&  b0 );
    ++    a04 =   b4 ^((~b0)&  b1 );
    ++
    ++    c0 = a00^a30^a10^a40^a20;
    ++    c1 = a21^a01^a31^a11^a41;
    ++    c2 = a42^a22^a02^a32^a12;
    ++    c3 = a13^a43^a23^a03^a33;
    ++    c4 = a34^a14^a44^a24^a04;
    ++    d0 = c4^ROL64(c1, 1);
    ++    d1 = c0^ROL64(c2, 1);
    ++    d2 = c1^ROL64(c3, 1);
    ++    d3 = c2^ROL64(c4, 1);
    ++    d4 = c3^ROL64(c0, 1);
    ++
    ++    b0 = (a00^d0);
    ++    b1 = ROL64((a01^d1), 44);
    ++    b2 = ROL64((a02^d2), 43);
    ++    b3 = ROL64((a03^d3), 21);
    ++    b4 = ROL64((a04^d4), 14);
    ++    a00 =   b0 ^((~b1)&  b2 );
    ++    a00 ^= RC[i+3];
    ++    a01 =   b1 ^((~b2)&  b3 );
    ++    a02 =   b2 ^((~b3)&  b4 );
    ++    a03 =   b3 ^((~b4)&  b0 );
    ++    a04 =   b4 ^((~b0)&  b1 );
    ++
    ++    b2 = ROL64((a10^d0), 3);
    ++    b3 = ROL64((a11^d1), 45);
    ++    b4 = ROL64((a12^d2), 61);
    ++    b0 = ROL64((a13^d3), 28);
    ++    b1 = ROL64((a14^d4), 20);
    ++    a10 =   b0 ^((~b1)&  b2 );
    ++    a11 =   b1 ^((~b2)&  b3 );
    ++    a12 =   b2 ^((~b3)&  b4 );
    ++    a13 =   b3 ^((~b4)&  b0 );
    ++    a14 =   b4 ^((~b0)&  b1 );
    ++
    ++    b4 = ROL64((a20^d0), 18);
    ++    b0 = ROL64((a21^d1), 1);
    ++    b1 = ROL64((a22^d2), 6);
    ++    b2 = ROL64((a23^d3), 25);
    ++    b3 = ROL64((a24^d4), 8);
    ++    a20 =   b0 ^((~b1)&  b2 );
    ++    a21 =   b1 ^((~b2)&  b3 );
    ++    a22 =   b2 ^((~b3)&  b4 );
    ++    a23 =   b3 ^((~b4)&  b0 );
    ++    a24 =   b4 ^((~b0)&  b1 );
    ++
    ++    b1 = ROL64((a30^d0), 36);
    ++    b2 = ROL64((a31^d1), 10);
    ++    b3 = ROL64((a32^d2), 15);
    ++    b4 = ROL64((a33^d3), 56);
    ++    b0 = ROL64((a34^d4), 27);
    ++    a30 =   b0 ^((~b1)&  b2 );
    ++    a31 =   b1 ^((~b2)&  b3 );
    ++    a32 =   b2 ^((~b3)&  b4 );
    ++    a33 =   b3 ^((~b4)&  b0 );
    ++    a34 =   b4 ^((~b0)&  b1 );
    ++
    ++    b3 = ROL64((a40^d0), 41);
    ++    b4 = ROL64((a41^d1), 2);
    ++    b0 = ROL64((a42^d2), 62);
    ++    b1 = ROL64((a43^d3), 55);
    ++    b2 = ROL64((a44^d4), 39);
    ++    a40 =   b0 ^((~b1)&  b2 );
    ++    a41 =   b1 ^((~b2)&  b3 );
    ++    a42 =   b2 ^((~b3)&  b4 );
    ++    a43 =   b3 ^((~b4)&  b0 );
    ++    a44 =   b4 ^((~b0)&  b1 );
    +   }
    +-  if( needQuote ) n += 2;
    +-  z = p->zDestTable = malloc( n+1 );
    +-  if( z==0 ){
    +-    fprintf(stderr,"Error: out of memory\n");
    +-    exit(1);
    ++}
    ++
    ++/*
    ++** Initialize a new hash.  iSize determines the size of the hash
    ++** in bits and should be one of 224, 256, 384, or 512.  Or iSize
    ++** can be zero to use the default hash size of 256 bits.
    ++*/
    ++static void SHA3Init(SHA3Context *p, int iSize){
    ++  memset(p, 0, sizeof(*p));
    ++  if( iSize>=128 && iSize<=512 ){
    ++    p->nRate = (1600 - ((iSize + 31)&~31)*2)/8;
    ++  }else{
    ++    p->nRate = (1600 - 2*256)/8;
    +   }
    +-  n = 0;
    +-  if( needQuote ) z[n++] = '\'';
    +-  for(i=0; zName[i]; i++){
    +-    z[n++] = zName[i];
    +-    if( zName[i]=='\'' ) z[n++] = '\'';
    ++#if SHA3_BYTEORDER==1234
    ++  /* Known to be little-endian at compile-time. No-op */
    ++#elif SHA3_BYTEORDER==4321
    ++  p->ixMask = 7;  /* Big-endian */
    ++#else
    ++  {
    ++    static unsigned int one = 1;
    ++    if( 1==*(unsigned char*)&one ){
    ++      /* Little endian.  No byte swapping. */
    ++      p->ixMask = 0;
    ++    }else{
    ++      /* Big endian.  Byte swap. */
    ++      p->ixMask = 7;
    ++    }
    +   }
    +-  if( needQuote ) z[n++] = '\'';
    +-  z[n] = 0;
    ++#endif
    + }
    + 
    +-/* zIn is either a pointer to a NULL-terminated string in memory obtained
    +-** from malloc(), or a NULL pointer. The string pointed to by zAppend is
    +-** added to zIn, and the result returned in memory obtained from malloc().
    +-** zIn, if it was not NULL, is freed.
    +-**
    +-** If the third argument, quote, is not '\0', then it is used as a 
    +-** quote character for zAppend.
    ++/*
    ++** Make consecutive calls to the SHA3Update function to add new content
    ++** to the hash
    + */
    +-static char *appendText(char *zIn, char const *zAppend, char quote){
    +-  int len;
    +-  int i;
    +-  int nAppend = strlen30(zAppend);
    +-  int nIn = (zIn?strlen30(zIn):0);
    +-
    +-  len = nAppend+nIn+1;
    +-  if( quote ){
    +-    len += 2;
    +-    for(i=0; i<nAppend; i++){
    +-      if( zAppend[i]==quote ) len++;
    ++static void SHA3Update(
    ++  SHA3Context *p,
    ++  const unsigned char *aData,
    ++  unsigned int nData
    ++){
    ++  unsigned int i = 0;
    ++#if SHA3_BYTEORDER==1234
    ++  if( (p->nLoaded % 8)==0 && ((aData - (const unsigned char*)0)&7)==0 ){
    ++    for(; i+7<nData; i+=8){
    ++      p->u.s[p->nLoaded/8] ^= *(u64*)&aData[i];
    ++      p->nLoaded += 8;
    ++      if( p->nLoaded>=p->nRate ){
    ++        KeccakF1600Step(p);
    ++        p->nLoaded = 0;
    ++      }
    +     }
    +   }
    +-
    +-  zIn = (char *)realloc(zIn, len);
    +-  if( !zIn ){
    +-    return 0;
    ++#endif
    ++  for(; i<nData; i++){
    ++#if SHA3_BYTEORDER==1234
    ++    p->u.x[p->nLoaded] ^= aData[i];
    ++#elif SHA3_BYTEORDER==4321
    ++    p->u.x[p->nLoaded^0x07] ^= aData[i];
    ++#else
    ++    p->u.x[p->nLoaded^p->ixMask] ^= aData[i];
    ++#endif
    ++    p->nLoaded++;
    ++    if( p->nLoaded==p->nRate ){
    ++      KeccakF1600Step(p);
    ++      p->nLoaded = 0;
    ++    }
    +   }
    ++}
    + 
    +-  if( quote ){
    +-    char *zCsr = &zIn[nIn];
    +-    *zCsr++ = quote;
    +-    for(i=0; i<nAppend; i++){
    +-      *zCsr++ = zAppend[i];
    +-      if( zAppend[i]==quote ) *zCsr++ = quote;
    +-    }
    +-    *zCsr++ = quote;
    +-    *zCsr++ = '\0';
    +-    assert( (zCsr-zIn)==len );
    ++/*
    ++** After all content has been added, invoke SHA3Final() to compute
    ++** the final hash.  The function returns a pointer to the binary
    ++** hash value.
    ++*/
    ++static unsigned char *SHA3Final(SHA3Context *p){
    ++  unsigned int i;
    ++  if( p->nLoaded==p->nRate-1 ){
    ++    const unsigned char c1 = 0x86;
    ++    SHA3Update(p, &c1, 1);
    +   }else{
    +-    memcpy(&zIn[nIn], zAppend, nAppend);
    +-    zIn[len-1] = '\0';
    ++    const unsigned char c2 = 0x06;
    ++    const unsigned char c3 = 0x80;
    ++    SHA3Update(p, &c2, 1);
    ++    p->nLoaded = p->nRate - 1;
    ++    SHA3Update(p, &c3, 1);
    +   }
    +-
    +-  return zIn;
    ++  for(i=0; i<p->nRate; i++){
    ++    p->u.x[i+p->nRate] = p->u.x[i^p->ixMask];
    ++  }
    ++  return &p->u.x[p->nRate];
    + }
    +-
    ++/* End of the hashing logic
    ++*****************************************************************************/
    + 
    + /*
    +-** Execute a query statement that will generate SQL output.  Print
    +-** the result columns, comma-separated, on a line and then add a
    +-** semicolon terminator to the end of that line.
    ++** Implementation of the sha3(X,SIZE) function.
    + **
    +-** If the number of columns is 1 and that column contains text "--"
    +-** then write the semicolon on a separate line.  That way, if a 
    +-** "--" comment occurs at the end of the statement, the comment
    +-** won't consume the semicolon terminator.
    ++** Return a BLOB which is the SIZE-bit SHA3 hash of X.  The default
    ++** size is 256.  If X is a BLOB, it is hashed as is.  
    ++** For all other non-NULL types of input, X is converted into a UTF-8 string
    ++** and the string is hashed without the trailing 0x00 terminator.  The hash
    ++** of a NULL value is NULL.
    + */
    +-static int run_table_dump_query(
    +-  ShellState *p,           /* Query context */
    +-  const char *zSelect,     /* SELECT statement to extract content */
    +-  const char *zFirstRow    /* Print before first row, if not NULL */
    ++static void sha3Func(
    ++  sqlite3_context *context,
    ++  int argc,
    ++  sqlite3_value **argv
    + ){
    +-  sqlite3_stmt *pSelect;
    +-  int rc;
    +-  int nResult;
    +-  int i;
    +-  const char *z;
    +-  rc = sqlite3_prepare_v2(p->db, zSelect, -1, &pSelect, 0);
    +-  if( rc!=SQLITE_OK || !pSelect ){
    +-    fprintf(p->out, "/**** ERROR: (%d) %s *****/\n", rc, sqlite3_errmsg(p->db));
    +-    if( (rc&0xff)!=SQLITE_CORRUPT ) p->nErr++;
    +-    return rc;
    +-  }
    +-  rc = sqlite3_step(pSelect);
    +-  nResult = sqlite3_column_count(pSelect);
    +-  while( rc==SQLITE_ROW ){
    +-    if( zFirstRow ){
    +-      fprintf(p->out, "%s", zFirstRow);
    +-      zFirstRow = 0;
    +-    }
    +-    z = (const char*)sqlite3_column_text(pSelect, 0);
    +-    fprintf(p->out, "%s", z);
    +-    for(i=1; i<nResult; i++){ 
    +-      fprintf(p->out, ",%s", sqlite3_column_text(pSelect, i));
    ++  SHA3Context cx;
    ++  int eType = sqlite3_value_type(argv[0]);
    ++  int nByte = sqlite3_value_bytes(argv[0]);
    ++  int iSize;
    ++  if( argc==1 ){
    ++    iSize = 256;
    ++  }else{
    ++    iSize = sqlite3_value_int(argv[1]);
    ++    if( iSize!=224 && iSize!=256 && iSize!=384 && iSize!=512 ){
    ++      sqlite3_result_error(context, "SHA3 size should be one of: 224 256 "
    ++                                    "384 512", -1);
    ++      return;
    +     }
    +-    if( z==0 ) z = "";
    +-    while( z[0] && (z[0]!='-' || z[1]!='-') ) z++;
    +-    if( z[0] ){
    +-      fprintf(p->out, "\n;\n");
    +-    }else{
    +-      fprintf(p->out, ";\n");
    +-    }    
    +-    rc = sqlite3_step(pSelect);
    +   }
    +-  rc = sqlite3_finalize(pSelect);
    +-  if( rc!=SQLITE_OK ){
    +-    fprintf(p->out, "/**** ERROR: (%d) %s *****/\n", rc, sqlite3_errmsg(p->db));
    +-    if( (rc&0xff)!=SQLITE_CORRUPT ) p->nErr++;
    ++  if( eType==SQLITE_NULL ) return;
    ++  SHA3Init(&cx, iSize);
    ++  if( eType==SQLITE_BLOB ){
    ++    SHA3Update(&cx, sqlite3_value_blob(argv[0]), nByte);
    ++  }else{
    ++    SHA3Update(&cx, sqlite3_value_text(argv[0]), nByte);
    +   }
    +-  return rc;
    ++  sqlite3_result_blob(context, SHA3Final(&cx), iSize/8, SQLITE_TRANSIENT);
    + }
    + 
    +-/*
    +-** Allocate space and save off current error string.
    ++/* Compute a string using sqlite3_vsnprintf() with a maximum length
    ++** of 50 bytes and add it to the hash.
    + */
    +-static char *save_err_msg(
    +-  sqlite3 *db            /* Database to query */
    ++static void hash_step_vformat(
    ++  SHA3Context *p,                 /* Add content to this context */
    ++  const char *zFormat,
    ++  ...
    + ){
    +-  int nErrMsg = 1+strlen30(sqlite3_errmsg(db));
    +-  char *zErrMsg = sqlite3_malloc64(nErrMsg);
    +-  if( zErrMsg ){
    +-    memcpy(zErrMsg, sqlite3_errmsg(db), nErrMsg);
    +-  }
    +-  return zErrMsg;
    ++  va_list ap;
    ++  int n;
    ++  char zBuf[50];
    ++  va_start(ap, zFormat);
    ++  sqlite3_vsnprintf(sizeof(zBuf),zBuf,zFormat,ap);
    ++  va_end(ap);
    ++  n = (int)strlen(zBuf);
    ++  SHA3Update(p, (unsigned char*)zBuf, n);
    + }
    + 
    + /*
    +-** Display memory stats.
    ++** Implementation of the sha3_query(SQL,SIZE) function.
    ++**
    ++** This function compiles and runs the SQL statement(s) given in the
    ++** argument. The results are hashed using a SIZE-bit SHA3.  The default
    ++** size is 256.
    ++**
    ++** The format of the byte stream that is hashed is summarized as follows:
    ++**
    ++**       S<n>:<sql>
    ++**       R
    ++**       N
    ++**       I<int>
    ++**       F<ieee-float>
    ++**       B<size>:<bytes>
    ++**       T<size>:<text>
    ++**
    ++** <sql> is the original SQL text for each statement run and <n> is
    ++** the size of that text.  The SQL text is UTF-8.  A single R character
    ++** occurs before the start of each row.  N means a NULL value.
    ++** I mean an 8-byte little-endian integer <int>.  F is a floating point
    ++** number with an 8-byte little-endian IEEE floating point value <ieee-float>.
    ++** B means blobs of <size> bytes.  T means text rendered as <size>
    ++** bytes of UTF-8.  The <n> and <size> values are expressed as an ASCII
    ++** text integers.
    ++**
    ++** For each SQL statement in the X input, there is one S segment.  Each
    ++** S segment is followed by zero or more R segments, one for each row in the
    ++** result set.  After each R, there are one or more N, I, F, B, or T segments,
    ++** one for each column in the result set.  Segments are concatentated directly
    ++** with no delimiters of any kind.
    + */
    +-static int display_stats(
    +-  sqlite3 *db,                /* Database to query */
    +-  ShellState *pArg,           /* Pointer to ShellState */
    +-  int bReset                  /* True to reset the stats */
    ++static void sha3QueryFunc(
    ++  sqlite3_context *context,
    ++  int argc,
    ++  sqlite3_value **argv
    + ){
    +-  int iCur;
    +-  int iHiwtr;
    ++  sqlite3 *db = sqlite3_context_db_handle(context);
    ++  const char *zSql = (const char*)sqlite3_value_text(argv[0]);
    ++  sqlite3_stmt *pStmt = 0;
    ++  int nCol;                   /* Number of columns in the result set */
    ++  int i;                      /* Loop counter */
    ++  int rc;
    ++  int n;
    ++  const char *z;
    ++  SHA3Context cx;
    ++  int iSize;
    + 
    +-  if( pArg && pArg->out ){
    +-    
    +-    iHiwtr = iCur = -1;
    +-    sqlite3_status(SQLITE_STATUS_MEMORY_USED, &iCur, &iHiwtr, bReset);
    +-    fprintf(pArg->out,
    +-            "Memory Used:                         %d (max %d) bytes\n",
    +-            iCur, iHiwtr);
    +-    iHiwtr = iCur = -1;
    +-    sqlite3_status(SQLITE_STATUS_MALLOC_COUNT, &iCur, &iHiwtr, bReset);
    +-    fprintf(pArg->out, "Number of Outstanding Allocations:   %d (max %d)\n",
    +-            iCur, iHiwtr);
    +-    if( pArg->shellFlgs & SHFLG_Pagecache ){
    +-      iHiwtr = iCur = -1;
    +-      sqlite3_status(SQLITE_STATUS_PAGECACHE_USED, &iCur, &iHiwtr, bReset);
    +-      fprintf(pArg->out,
    +-              "Number of Pcache Pages Used:         %d (max %d) pages\n",
    +-              iCur, iHiwtr);
    +-    }
    +-    iHiwtr = iCur = -1;
    +-    sqlite3_status(SQLITE_STATUS_PAGECACHE_OVERFLOW, &iCur, &iHiwtr, bReset);
    +-    fprintf(pArg->out,
    +-            "Number of Pcache Overflow Bytes:     %d (max %d) bytes\n",
    +-            iCur, iHiwtr);
    +-    if( pArg->shellFlgs & SHFLG_Scratch ){
    +-      iHiwtr = iCur = -1;
    +-      sqlite3_status(SQLITE_STATUS_SCRATCH_USED, &iCur, &iHiwtr, bReset);
    +-      fprintf(pArg->out, "Number of Scratch Allocations Used:  %d (max %d)\n",
    +-              iCur, iHiwtr);
    ++  if( argc==1 ){
    ++    iSize = 256;
    ++  }else{
    ++    iSize = sqlite3_value_int(argv[1]);
    ++    if( iSize!=224 && iSize!=256 && iSize!=384 && iSize!=512 ){
    ++      sqlite3_result_error(context, "SHA3 size should be one of: 224 256 "
    ++                                    "384 512", -1);
    ++      return;
    +     }
    +-    iHiwtr = iCur = -1;
    +-    sqlite3_status(SQLITE_STATUS_SCRATCH_OVERFLOW, &iCur, &iHiwtr, bReset);
    +-    fprintf(pArg->out,
    +-            "Number of Scratch Overflow Bytes:    %d (max %d) bytes\n",
    +-            iCur, iHiwtr);
    +-    iHiwtr = iCur = -1;
    +-    sqlite3_status(SQLITE_STATUS_MALLOC_SIZE, &iCur, &iHiwtr, bReset);
    +-    fprintf(pArg->out, "Largest Allocation:                  %d bytes\n",
    +-            iHiwtr);
    +-    iHiwtr = iCur = -1;
    +-    sqlite3_status(SQLITE_STATUS_PAGECACHE_SIZE, &iCur, &iHiwtr, bReset);
    +-    fprintf(pArg->out, "Largest Pcache Allocation:           %d bytes\n",
    +-            iHiwtr);
    +-    iHiwtr = iCur = -1;
    +-    sqlite3_status(SQLITE_STATUS_SCRATCH_SIZE, &iCur, &iHiwtr, bReset);
    +-    fprintf(pArg->out, "Largest Scratch Allocation:          %d bytes\n",
    +-            iHiwtr);
    +-#ifdef YYTRACKMAXSTACKDEPTH
    +-    iHiwtr = iCur = -1;
    +-    sqlite3_status(SQLITE_STATUS_PARSER_STACK, &iCur, &iHiwtr, bReset);
    +-    fprintf(pArg->out, "Deepest Parser Stack:                %d (max %d)\n",
    +-            iCur, iHiwtr);
    +-#endif
    +   }
    +-
    +-  if( pArg && pArg->out && db ){
    +-    if( pArg->shellFlgs & SHFLG_Lookaside ){
    +-      iHiwtr = iCur = -1;
    +-      sqlite3_db_status(db, SQLITE_DBSTATUS_LOOKASIDE_USED,
    +-                        &iCur, &iHiwtr, bReset);
    +-      fprintf(pArg->out, "Lookaside Slots Used:                %d (max %d)\n",
    +-              iCur, iHiwtr);
    +-      sqlite3_db_status(db, SQLITE_DBSTATUS_LOOKASIDE_HIT,
    +-                        &iCur, &iHiwtr, bReset);
    +-      fprintf(pArg->out, "Successful lookaside attempts:       %d\n", iHiwtr);
    +-      sqlite3_db_status(db, SQLITE_DBSTATUS_LOOKASIDE_MISS_SIZE,
    +-                        &iCur, &iHiwtr, bReset);
    +-      fprintf(pArg->out, "Lookaside failures due to size:      %d\n", iHiwtr);
    +-      sqlite3_db_status(db, SQLITE_DBSTATUS_LOOKASIDE_MISS_FULL,
    +-                        &iCur, &iHiwtr, bReset);
    +-      fprintf(pArg->out, "Lookaside failures due to OOM:       %d\n", iHiwtr);
    ++  if( zSql==0 ) return;
    ++  SHA3Init(&cx, iSize);
    ++  while( zSql[0] ){
    ++    rc = sqlite3_prepare_v2(db, zSql, -1, &pStmt, &zSql);
    ++    if( rc ){
    ++      char *zMsg = sqlite3_mprintf("error SQL statement [%s]: %s",
    ++                                   zSql, sqlite3_errmsg(db));
    ++      sqlite3_finalize(pStmt);
    ++      sqlite3_result_error(context, zMsg, -1);
    ++      sqlite3_free(zMsg);
    ++      return;
    +     }
    +-    iHiwtr = iCur = -1;
    +-    sqlite3_db_status(db, SQLITE_DBSTATUS_CACHE_USED, &iCur, &iHiwtr, bReset);
    +-    fprintf(pArg->out, "Pager Heap Usage:                    %d bytes\n",iCur);
    +-    iHiwtr = iCur = -1;
    +-    sqlite3_db_status(db, SQLITE_DBSTATUS_CACHE_HIT, &iCur, &iHiwtr, 1);
    +-    fprintf(pArg->out, "Page cache hits:                     %d\n", iCur);
    +-    iHiwtr = iCur = -1;
    +-    sqlite3_db_status(db, SQLITE_DBSTATUS_CACHE_MISS, &iCur, &iHiwtr, 1);
    +-    fprintf(pArg->out, "Page cache misses:                   %d\n", iCur); 
    +-    iHiwtr = iCur = -1;
    +-    sqlite3_db_status(db, SQLITE_DBSTATUS_CACHE_WRITE, &iCur, &iHiwtr, 1);
    +-    fprintf(pArg->out, "Page cache writes:                   %d\n", iCur); 
    +-    iHiwtr = iCur = -1;
    +-    sqlite3_db_status(db, SQLITE_DBSTATUS_SCHEMA_USED, &iCur, &iHiwtr, bReset);
    +-    fprintf(pArg->out, "Schema Heap Usage:                   %d bytes\n",iCur); 
    +-    iHiwtr = iCur = -1;
    +-    sqlite3_db_status(db, SQLITE_DBSTATUS_STMT_USED, &iCur, &iHiwtr, bReset);
    +-    fprintf(pArg->out, "Statement Heap/Lookaside Usage:      %d bytes\n",iCur); 
    ++    if( !sqlite3_stmt_readonly(pStmt) ){
    ++      char *zMsg = sqlite3_mprintf("non-query: [%s]", sqlite3_sql(pStmt));
    ++      sqlite3_finalize(pStmt);
    ++      sqlite3_result_error(context, zMsg, -1);
    ++      sqlite3_free(zMsg);
    ++      return;
    ++    }
    ++    nCol = sqlite3_column_count(pStmt);
    ++    z = sqlite3_sql(pStmt);
    ++    n = (int)strlen(z);
    ++    hash_step_vformat(&cx,"S%d:",n);
    ++    SHA3Update(&cx,(unsigned char*)z,n);
    ++
    ++    /* Compute a hash over the result of the query */
    ++    while( SQLITE_ROW==sqlite3_step(pStmt) ){
    ++      SHA3Update(&cx,(const unsigned char*)"R",1);
    ++      for(i=0; i<nCol; i++){
    ++        switch( sqlite3_column_type(pStmt,i) ){
    ++          case SQLITE_NULL: {
    ++            SHA3Update(&cx, (const unsigned char*)"N",1);
    ++            break;
    ++          }
    ++          case SQLITE_INTEGER: {
    ++            sqlite3_uint64 u;
    ++            int j;
    ++            unsigned char x[9];
    ++            sqlite3_int64 v = sqlite3_column_int64(pStmt,i);
    ++            memcpy(&u, &v, 8);
    ++            for(j=8; j>=1; j--){
    ++              x[j] = u & 0xff;
    ++              u >>= 8;
    ++            }
    ++            x[0] = 'I';
    ++            SHA3Update(&cx, x, 9);
    ++            break;
    ++          }
    ++          case SQLITE_FLOAT: {
    ++            sqlite3_uint64 u;
    ++            int j;
    ++            unsigned char x[9];
    ++            double r = sqlite3_column_double(pStmt,i);
    ++            memcpy(&u, &r, 8);
    ++            for(j=8; j>=1; j--){
    ++              x[j] = u & 0xff;
    ++              u >>= 8;
    ++            }
    ++            x[0] = 'F';
    ++            SHA3Update(&cx,x,9);
    ++            break;
    ++          }
    ++          case SQLITE_TEXT: {
    ++            int n2 = sqlite3_column_bytes(pStmt, i);
    ++            const unsigned char *z2 = sqlite3_column_text(pStmt, i);
    ++            hash_step_vformat(&cx,"T%d:",n2);
    ++            SHA3Update(&cx, z2, n2);
    ++            break;
    ++          }
    ++          case SQLITE_BLOB: {
    ++            int n2 = sqlite3_column_bytes(pStmt, i);
    ++            const unsigned char *z2 = sqlite3_column_blob(pStmt, i);
    ++            hash_step_vformat(&cx,"B%d:",n2);
    ++            SHA3Update(&cx, z2, n2);
    ++            break;
    ++          }
    ++        }
    ++      }
    ++    }
    ++    sqlite3_finalize(pStmt);
    +   }
    ++  sqlite3_result_blob(context, SHA3Final(&cx), iSize/8, SQLITE_TRANSIENT);
    ++}
    + 
    +-  if( pArg && pArg->out && db && pArg->pStmt ){
    +-    iCur = sqlite3_stmt_status(pArg->pStmt, SQLITE_STMTSTATUS_FULLSCAN_STEP,
    +-                               bReset);
    +-    fprintf(pArg->out, "Fullscan Steps:                      %d\n", iCur);
    +-    iCur = sqlite3_stmt_status(pArg->pStmt, SQLITE_STMTSTATUS_SORT, bReset);
    +-    fprintf(pArg->out, "Sort Operations:                     %d\n", iCur);
    +-    iCur = sqlite3_stmt_status(pArg->pStmt, SQLITE_STMTSTATUS_AUTOINDEX,bReset);
    +-    fprintf(pArg->out, "Autoindex Inserts:                   %d\n", iCur);
    +-    iCur = sqlite3_stmt_status(pArg->pStmt, SQLITE_STMTSTATUS_VM_STEP, bReset);
    +-    fprintf(pArg->out, "Virtual Machine Steps:               %d\n", iCur);
    +-  }
    + 
    +-  /* Do not remove this machine readable comment: extra-stats-output-here */
    ++#ifdef _WIN32
    + 
    +-  return 0;
    ++#endif
    ++int sqlite3_shathree_init(
    ++  sqlite3 *db,
    ++  char **pzErrMsg,
    ++  const sqlite3_api_routines *pApi
    ++){
    ++  int rc = SQLITE_OK;
    ++  SQLITE_EXTENSION_INIT2(pApi);
    ++  (void)pzErrMsg;  /* Unused parameter */
    ++  rc = sqlite3_create_function(db, "sha3", 1, SQLITE_UTF8, 0,
    ++                               sha3Func, 0, 0);
    ++  if( rc==SQLITE_OK ){
    ++    rc = sqlite3_create_function(db, "sha3", 2, SQLITE_UTF8, 0,
    ++                                 sha3Func, 0, 0);
    ++  }
    ++  if( rc==SQLITE_OK ){
    ++    rc = sqlite3_create_function(db, "sha3_query", 1, SQLITE_UTF8, 0,
    ++                                 sha3QueryFunc, 0, 0);
    ++  }
    ++  if( rc==SQLITE_OK ){
    ++    rc = sqlite3_create_function(db, "sha3_query", 2, SQLITE_UTF8, 0,
    ++                                 sha3QueryFunc, 0, 0);
    ++  }
    ++  return rc;
    + }
    + 
    ++/************************* End ../ext/misc/shathree.c ********************/
    ++/************************* Begin ../ext/misc/fileio.c ******************/
    + /*
    +-** Display scan stats.
    ++** 2014-06-13
    ++**
    ++** 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 SQLite extension implements SQL functions readfile() and
    ++** writefile(), and eponymous virtual type "fsdir".
    ++**
    ++** WRITEFILE(FILE, DATA [, MODE [, MTIME]]):
    ++**
    ++**   If neither of the optional arguments is present, then this UDF
    ++**   function writes blob DATA to file FILE. If successful, the number
    ++**   of bytes written is returned. If an error occurs, NULL is returned.
    ++**
    ++**   If the first option argument - MODE - is present, then it must
    ++**   be passed an integer value that corresponds to a POSIX mode
    ++**   value (file type + permissions, as returned in the stat.st_mode
    ++**   field by the stat() system call). Three types of files may
    ++**   be written/created:
    ++**
    ++**     regular files:  (mode & 0170000)==0100000
    ++**     symbolic links: (mode & 0170000)==0120000
    ++**     directories:    (mode & 0170000)==0040000
    ++**
    ++**   For a directory, the DATA is ignored. For a symbolic link, it is
    ++**   interpreted as text and used as the target of the link. For a
    ++**   regular file, it is interpreted as a blob and written into the
    ++**   named file. Regardless of the type of file, its permissions are
    ++**   set to (mode & 0777) before returning.
    ++**
    ++**   If the optional MTIME argument is present, then it is interpreted
    ++**   as an integer - the number of seconds since the unix epoch. The
    ++**   modification-time of the target file is set to this value before
    ++**   returning.
    ++**
    ++**   If three or more arguments are passed to this function and an
    ++**   error is encountered, an exception is raised.
    ++**
    ++** READFILE(FILE):
    ++**
    ++**   Read and return the contents of file FILE (type blob) from disk.
    ++**
    ++** FSDIR:
    ++**
    ++**   Used as follows:
    ++**
    ++**     SELECT * FROM fsdir($path [, $dir]);
    ++**
    ++**   Parameter $path is an absolute or relative pathname. If the file that it
    ++**   refers to does not exist, it is an error. If the path refers to a regular
    ++**   file or symbolic link, it returns a single row. Or, if the path refers
    ++**   to a directory, it returns one row for the directory, and one row for each
    ++**   file within the hierarchy rooted at $path.
    ++**
    ++**   Each row has the following columns:
    ++**
    ++**     name:  Path to file or directory (text value).
    ++**     mode:  Value of stat.st_mode for directory entry (an integer).
    ++**     mtime: Value of stat.st_mtime for directory entry (an integer).
    ++**     data:  For a regular file, a blob containing the file data. For a
    ++**            symlink, a text value containing the text of the link. For a
    ++**            directory, NULL.
    ++**
    ++**   If a non-NULL value is specified for the optional $dir parameter and
    ++**   $path is a relative path, then $path is interpreted relative to $dir. 
    ++**   And the paths returned in the "name" column of the table are also 
    ++**   relative to directory $dir.
    + */
    +-static void display_scanstats(
    +-  sqlite3 *db,                    /* Database to query */
    +-  ShellState *pArg                /* Pointer to ShellState */
    +-){
    +-#ifndef SQLITE_ENABLE_STMT_SCANSTATUS
    +-  UNUSED_PARAMETER(db);
    +-  UNUSED_PARAMETER(pArg);
    ++SQLITE_EXTENSION_INIT1
    ++#include <stdio.h>
    ++#include <string.h>
    ++#include <assert.h>
    ++
    ++#include <sys/types.h>
    ++#include <sys/stat.h>
    ++#include <fcntl.h>
    ++#if !defined(_WIN32) && !defined(WIN32)
    ++#  include <unistd.h>
    ++#  include <dirent.h>
    ++#  include <utime.h>
    ++#  include <sys/time.h>
    + #else
    +-  int i, k, n, mx;
    +-  fprintf(pArg->out, "-------- scanstats --------\n");
    +-  mx = 0;
    +-  for(k=0; k<=mx; k++){
    +-    double rEstLoop = 1.0;
    +-    for(i=n=0; 1; i++){
    +-      sqlite3_stmt *p = pArg->pStmt;
    +-      sqlite3_int64 nLoop, nVisit;
    +-      double rEst;
    +-      int iSid;
    +-      const char *zExplain;
    +-      if( sqlite3_stmt_scanstatus(p, i, SQLITE_SCANSTAT_NLOOP, (void*)&nLoop) ){
    +-        break;
    +-      }
    +-      sqlite3_stmt_scanstatus(p, i, SQLITE_SCANSTAT_SELECTID, (void*)&iSid);
    +-      if( iSid>mx ) mx = iSid;
    +-      if( iSid!=k ) continue;
    +-      if( n==0 ){
    +-        rEstLoop = (double)nLoop;
    +-        if( k>0 ) fprintf(pArg->out, "-------- subquery %d -------\n", k);
    +-      }
    +-      n++;
    +-      sqlite3_stmt_scanstatus(p, i, SQLITE_SCANSTAT_NVISIT, (void*)&nVisit);
    +-      sqlite3_stmt_scanstatus(p, i, SQLITE_SCANSTAT_EST, (void*)&rEst);
    +-      sqlite3_stmt_scanstatus(p, i, SQLITE_SCANSTAT_EXPLAIN, (void*)&zExplain);
    +-      fprintf(pArg->out, "Loop %2d: %s\n", n, zExplain);
    +-      rEstLoop *= rEst;
    +-      fprintf(pArg->out, 
    +-          "         nLoop=%-8lld nRow=%-8lld estRow=%-8lld estRow/Loop=%-8g\n",
    +-          nLoop, nVisit, (sqlite3_int64)(rEstLoop+0.5), rEst
    +-      );
    +-    }
    +-  }
    +-  fprintf(pArg->out, "---------------------------\n");
    ++#  include "windows.h"
    ++#  include <io.h>
    ++#  include <direct.h>
    ++/* #  include "test_windirent.h" */
    ++#  define dirent DIRENT
    ++#  ifndef stat
    ++#    define stat _stat
    ++#  endif
    ++#  define mkdir(path,mode) _mkdir(path)
    ++#  define lstat(path,buf) stat(path,buf)
    + #endif
    +-}
    ++#include <time.h>
    ++#include <errno.h>
    ++
    ++
    ++#define FSDIR_SCHEMA "(name,mode,mtime,data,path HIDDEN,dir HIDDEN)"
    + 
    + /*
    +-** Parameter azArray points to a zero-terminated array of strings. zStr
    +-** points to a single nul-terminated string. Return non-zero if zStr
    +-** is equal, according to strcmp(), to any of the strings in the array.
    +-** Otherwise, return zero.
    ++** Set the result stored by context ctx to a blob containing the 
    ++** contents of file zName.
    + */
    +-static int str_in_array(const char *zStr, const char **azArray){
    +-  int i;
    +-  for(i=0; azArray[i]; i++){
    +-    if( 0==strcmp(zStr, azArray[i]) ) return 1;
    ++static void readFileContents(sqlite3_context *ctx, const char *zName){
    ++  FILE *in;
    ++  long nIn;
    ++  void *pBuf;
    ++
    ++  in = fopen(zName, "rb");
    ++  if( in==0 ) return;
    ++  fseek(in, 0, SEEK_END);
    ++  nIn = ftell(in);
    ++  rewind(in);
    ++  pBuf = sqlite3_malloc( nIn );
    ++  if( pBuf && 1==fread(pBuf, nIn, 1, in) ){
    ++    sqlite3_result_blob(ctx, pBuf, nIn, sqlite3_free);
    ++  }else{
    ++    sqlite3_free(pBuf);
    +   }
    +-  return 0;
    ++  fclose(in);
    + }
    + 
    + /*
    +-** If compiled statement pSql appears to be an EXPLAIN statement, allocate
    +-** and populate the ShellState.aiIndent[] array with the number of
    +-** spaces each opcode should be indented before it is output. 
    +-**
    +-** The indenting rules are:
    +-**
    +-**     * For each "Next", "Prev", "VNext" or "VPrev" instruction, indent
    +-**       all opcodes that occur between the p2 jump destination and the opcode
    +-**       itself by 2 spaces.
    +-**
    +-**     * For each "Goto", if the jump destination is earlier in the program
    +-**       and ends on one of:
    +-**          Yield  SeekGt  SeekLt  RowSetRead  Rewind
    +-**       or if the P1 parameter is one instead of zero,
    +-**       then indent all opcodes between the earlier instruction
    +-**       and "Goto" by 2 spaces.
    ++** Implementation of the "readfile(X)" SQL function.  The entire content
    ++** of the file named X is read and returned as a BLOB.  NULL is returned
    ++** if the file does not exist or is unreadable.
    + */
    +-static void explain_data_prepare(ShellState *p, sqlite3_stmt *pSql){
    +-  const char *zSql;               /* The text of the SQL statement */
    +-  const char *z;                  /* Used to check if this is an EXPLAIN */
    +-  int *abYield = 0;               /* True if op is an OP_Yield */
    +-  int nAlloc = 0;                 /* Allocated size of p->aiIndent[], abYield */
    +-  int iOp;                        /* Index of operation in p->aiIndent[] */
    +-
    +-  const char *azNext[] = { "Next", "Prev", "VPrev", "VNext", "SorterNext",
    +-                           "NextIfOpen", "PrevIfOpen", 0 };
    +-  const char *azYield[] = { "Yield", "SeekLT", "SeekGT", "RowSetRead",
    +-                            "Rewind", 0 };
    +-  const char *azGoto[] = { "Goto", 0 };
    +-
    +-  /* Try to figure out if this is really an EXPLAIN statement. If this
    +-  ** cannot be verified, return early.  */
    +-  zSql = sqlite3_sql(pSql);
    +-  if( zSql==0 ) return;
    +-  for(z=zSql; *z==' ' || *z=='\t' || *z=='\n' || *z=='\f' || *z=='\r'; z++);
    +-  if( sqlite3_strnicmp(z, "explain", 7) ) return;
    +-
    +-  for(iOp=0; SQLITE_ROW==sqlite3_step(pSql); iOp++){
    +-    int i;
    +-    int iAddr = sqlite3_column_int(pSql, 0);
    +-    const char *zOp = (const char*)sqlite3_column_text(pSql, 1);
    +-
    +-    /* Set p2 to the P2 field of the current opcode. Then, assuming that
    +-    ** p2 is an instruction address, set variable p2op to the index of that
    +-    ** instruction in the aiIndent[] array. p2 and p2op may be different if
    +-    ** the current instruction is part of a sub-program generated by an
    +-    ** SQL trigger or foreign key.  */
    +-    int p2 = sqlite3_column_int(pSql, 3);
    +-    int p2op = (p2 + (iOp-iAddr));
    +-
    +-    /* Grow the p->aiIndent array as required */
    +-    if( iOp>=nAlloc ){
    +-      nAlloc += 100;
    +-      p->aiIndent = (int*)sqlite3_realloc64(p->aiIndent, nAlloc*sizeof(int));
    +-      abYield = (int*)sqlite3_realloc64(abYield, nAlloc*sizeof(int));
    +-    }
    +-    abYield[iOp] = str_in_array(zOp, azYield);
    +-    p->aiIndent[iOp] = 0;
    +-    p->nIndent = iOp+1;
    +-
    +-    if( str_in_array(zOp, azNext) ){
    +-      for(i=p2op; i<iOp; i++) p->aiIndent[i] += 2;
    +-    }
    +-    if( str_in_array(zOp, azGoto) && p2op<p->nIndent
    +-     && (abYield[p2op] || sqlite3_column_int(pSql, 2))
    +-    ){
    +-      for(i=p2op+1; i<iOp; i++) p->aiIndent[i] += 2;
    +-    }
    +-  }
    +-
    +-  p->iIndent = 0;
    +-  sqlite3_free(abYield);
    +-  sqlite3_reset(pSql);
    ++static void readfileFunc(
    ++  sqlite3_context *context,
    ++  int argc,
    ++  sqlite3_value **argv
    ++){
    ++  const char *zName;
    ++  (void)(argc);  /* Unused parameter */
    ++  zName = (const char*)sqlite3_value_text(argv[0]);
    ++  if( zName==0 ) return;
    ++  readFileContents(context, zName);
    + }
    + 
    + /*
    +-** Free the array allocated by explain_data_prepare().
    ++** Set the error message contained in context ctx to the results of
    ++** vprintf(zFmt, ...).
    + */
    +-static void explain_data_delete(ShellState *p){
    +-  sqlite3_free(p->aiIndent);
    +-  p->aiIndent = 0;
    +-  p->nIndent = 0;
    +-  p->iIndent = 0;
    ++static void ctxErrorMsg(sqlite3_context *ctx, const char *zFmt, ...){
    ++  char *zMsg = 0;
    ++  va_list ap;
    ++  va_start(ap, zFmt);
    ++  zMsg = sqlite3_vmprintf(zFmt, ap);
    ++  sqlite3_result_error(ctx, zMsg, -1);
    ++  sqlite3_free(zMsg);
    ++  va_end(ap);
    + }
    + 
    + /*
    +-** Execute a statement or set of statements.  Print 
    +-** any result rows/columns depending on the current mode 
    +-** set via the supplied callback.
    ++** Argument zFile is the name of a file that will be created and/or written
    ++** by SQL function writefile(). This function ensures that the directory
    ++** zFile will be written to exists, creating it if required. The permissions
    ++** for any path components created by this function are set to (mode&0777).
    + **
    +-** This is very similar to SQLite's built-in sqlite3_exec() 
    +-** function except it takes a slightly different callback 
    +-** and callback data argument.
    ++** If an OOM condition is encountered, SQLITE_NOMEM is returned. Otherwise,
    ++** SQLITE_OK is returned if the directory is successfully created, or
    ++** SQLITE_ERROR otherwise.
    + */
    +-static int shell_exec(
    +-  sqlite3 *db,                              /* An open database */
    +-  const char *zSql,                         /* SQL to be evaluated */
    +-  int (*xCallback)(void*,int,char**,char**,int*),   /* Callback function */
    +-                                            /* (not the same as sqlite3_exec) */
    +-  ShellState *pArg,                         /* Pointer to ShellState */
    +-  char **pzErrMsg                           /* Error msg written here */
    ++static int makeDirectory(
    ++  const char *zFile,
    ++  mode_t mode
    + ){
    +-  sqlite3_stmt *pStmt = NULL;     /* Statement to execute. */
    +-  int rc = SQLITE_OK;             /* Return Code */
    +-  int rc2;
    +-  const char *zLeftover;          /* Tail of unprocessed SQL */
    ++  char *zCopy = sqlite3_mprintf("%s", zFile);
    ++  int rc = SQLITE_OK;
    + 
    +-  if( pzErrMsg ){
    +-    *pzErrMsg = NULL;
    +-  }
    ++  if( zCopy==0 ){
    ++    rc = SQLITE_NOMEM;
    ++  }else{
    ++    int nCopy = (int)strlen(zCopy);
    ++    int i = 1;
    + 
    +-  while( zSql[0] && (SQLITE_OK == rc) ){
    +-    rc = sqlite3_prepare_v2(db, zSql, -1, &pStmt, &zLeftover);
    +-    if( SQLITE_OK != rc ){
    +-      if( pzErrMsg ){
    +-        *pzErrMsg = save_err_msg(db);
    +-      }
    +-    }else{
    +-      if( !pStmt ){
    +-        /* this happens for a comment or white-space */
    +-        zSql = zLeftover;
    +-        while( IsSpace(zSql[0]) ) zSql++;
    +-        continue;
    +-      }
    ++    while( rc==SQLITE_OK ){
    ++      struct stat sStat;
    ++      int rc2;
    + 
    +-      /* save off the prepared statment handle and reset row count */
    +-      if( pArg ){
    +-        pArg->pStmt = pStmt;
    +-        pArg->cnt = 0;
    +-      }
    ++      for(; zCopy[i]!='/' && i<nCopy; i++);
    ++      if( i==nCopy ) break;
    ++      zCopy[i] = '\0';
    + 
    +-      /* echo the sql statement if echo on */
    +-      if( pArg && pArg->echoOn ){
    +-        const char *zStmtSql = sqlite3_sql(pStmt);
    +-        fprintf(pArg->out, "%s\n", zStmtSql ? zStmtSql : zSql);
    ++      rc2 = stat(zCopy, &sStat);
    ++      if( rc2!=0 ){
    ++        if( mkdir(zCopy, mode & 0777) ) rc = SQLITE_ERROR;
    ++      }else{
    ++        if( !S_ISDIR(sStat.st_mode) ) rc = SQLITE_ERROR;
    +       }
    ++      zCopy[i] = '/';
    ++      i++;
    ++    }
    + 
    +-      /* Show the EXPLAIN QUERY PLAN if .eqp is on */
    +-      if( pArg && pArg->autoEQP ){
    +-        sqlite3_stmt *pExplain;
    +-        char *zEQP = sqlite3_mprintf("EXPLAIN QUERY PLAN %s",
    +-                                     sqlite3_sql(pStmt));
    +-        rc = sqlite3_prepare_v2(db, zEQP, -1, &pExplain, 0);
    +-        if( rc==SQLITE_OK ){
    +-          while( sqlite3_step(pExplain)==SQLITE_ROW ){
    +-            fprintf(pArg->out,"--EQP-- %d,", sqlite3_column_int(pExplain, 0));
    +-            fprintf(pArg->out,"%d,", sqlite3_column_int(pExplain, 1));
    +-            fprintf(pArg->out,"%d,", sqlite3_column_int(pExplain, 2));
    +-            fprintf(pArg->out,"%s\n", sqlite3_column_text(pExplain, 3));
    +-          }
    +-        }
    +-        sqlite3_finalize(pExplain);
    +-        sqlite3_free(zEQP);
    +-      }
    ++    sqlite3_free(zCopy);
    ++  }
    + 
    +-      /* If the shell is currently in ".explain" mode, gather the extra
    +-      ** data required to add indents to the output.*/
    +-      if( pArg && pArg->mode==MODE_Explain ){
    +-        explain_data_prepare(pArg, pStmt);
    +-      }
    ++  return rc;
    ++}
    + 
    +-      /* perform the first step.  this will tell us if we
    +-      ** have a result set or not and how wide it is.
    +-      */
    +-      rc = sqlite3_step(pStmt);
    +-      /* if we have a result set... */
    +-      if( SQLITE_ROW == rc ){
    +-        /* if we have a callback... */
    +-        if( xCallback ){
    +-          /* allocate space for col name ptr, value ptr, and type */
    +-          int nCol = sqlite3_column_count(pStmt);
    +-          void *pData = sqlite3_malloc64(3*nCol*sizeof(const char*) + 1);
    +-          if( !pData ){
    +-            rc = SQLITE_NOMEM;
    +-          }else{
    +-            char **azCols = (char **)pData;      /* Names of result columns */
    +-            char **azVals = &azCols[nCol];       /* Results */
    +-            int *aiTypes = (int *)&azVals[nCol]; /* Result types */
    +-            int i, x;
    +-            assert(sizeof(int) <= sizeof(char *)); 
    +-            /* save off ptrs to column names */
    +-            for(i=0; i<nCol; i++){
    +-              azCols[i] = (char *)sqlite3_column_name(pStmt, i);
    +-            }
    +-            do{
    +-              /* extract the data and data types */
    +-              for(i=0; i<nCol; i++){
    +-                aiTypes[i] = x = sqlite3_column_type(pStmt, i);
    +-                if( x==SQLITE_BLOB && pArg && pArg->mode==MODE_Insert ){
    +-                  azVals[i] = "";
    +-                }else{
    +-                  azVals[i] = (char*)sqlite3_column_text(pStmt, i);
    +-                }
    +-                if( !azVals[i] && (aiTypes[i]!=SQLITE_NULL) ){
    +-                  rc = SQLITE_NOMEM;
    +-                  break; /* from for */
    +-                }
    +-              } /* end for */
    +-
    +-              /* if data and types extracted successfully... */
    +-              if( SQLITE_ROW == rc ){ 
    +-                /* call the supplied callback with the result row data */
    +-                if( xCallback(pArg, nCol, azVals, azCols, aiTypes) ){
    +-                  rc = SQLITE_ABORT;
    +-                }else{
    +-                  rc = sqlite3_step(pStmt);
    +-                }
    +-              }
    +-            } while( SQLITE_ROW == rc );
    +-            sqlite3_free(pData);
    +-          }
    +-        }else{
    +-          do{
    +-            rc = sqlite3_step(pStmt);
    +-          } while( rc == SQLITE_ROW );
    ++/*
    ++** This function does the work for the writefile() UDF. Refer to 
    ++** header comments at the top of this file for details.
    ++*/
    ++static int writeFile(
    ++  sqlite3_context *pCtx,          /* Context to return bytes written in */
    ++  const char *zFile,              /* File to write */
    ++  sqlite3_value *pData,           /* Data to write */
    ++  mode_t mode,                    /* MODE parameter passed to writefile() */
    ++  sqlite3_int64 mtime             /* MTIME parameter (or -1 to not set time) */
    ++){
    ++#if !defined(_WIN32) && !defined(WIN32)
    ++  if( S_ISLNK(mode) ){
    ++    const char *zTo = (const char*)sqlite3_value_text(pData);
    ++    if( symlink(zTo, zFile)<0 ) return 1;
    ++  }else
    ++#endif
    ++  {
    ++    if( S_ISDIR(mode) ){
    ++      if( mkdir(zFile, mode) ){
    ++        /* The mkdir() call to create the directory failed. This might not
    ++        ** be an error though - if there is already a directory at the same
    ++        ** path and either the permissions already match or can be changed
    ++        ** to do so using chmod(), it is not an error.  */
    ++        struct stat sStat;
    ++        if( errno!=EEXIST
    ++         || 0!=stat(zFile, &sStat)
    ++         || !S_ISDIR(sStat.st_mode)
    ++         || ((sStat.st_mode&0777)!=(mode&0777) && 0!=chmod(zFile, mode&0777))
    ++        ){
    ++          return 1;
    +         }
    +       }
    +-
    +-      explain_data_delete(pArg);
    +-
    +-      /* print usage stats if stats on */
    +-      if( pArg && pArg->statsOn ){
    +-        display_stats(db, pArg, 0);
    +-      }
    +-
    +-      /* print loop-counters if required */
    +-      if( pArg && pArg->scanstatsOn ){
    +-        display_scanstats(db, pArg);
    ++    }else{
    ++      sqlite3_int64 nWrite = 0;
    ++      const char *z;
    ++      int rc = 0;
    ++      FILE *out = fopen(zFile, "wb");
    ++      if( out==0 ) return 1;
    ++      z = (const char*)sqlite3_value_blob(pData);
    ++      if( z ){
    ++        sqlite3_int64 n = fwrite(z, 1, sqlite3_value_bytes(pData), out);
    ++        nWrite = sqlite3_value_bytes(pData);
    ++        if( nWrite!=n ){
    ++          rc = 1;
    ++        }
    +       }
    +-
    +-      /* Finalize the statement just executed. If this fails, save a 
    +-      ** copy of the error message. Otherwise, set zSql to point to the
    +-      ** next statement to execute. */
    +-      rc2 = sqlite3_finalize(pStmt);
    +-      if( rc!=SQLITE_NOMEM ) rc = rc2;
    +-      if( rc==SQLITE_OK ){
    +-        zSql = zLeftover;
    +-        while( IsSpace(zSql[0]) ) zSql++;
    +-      }else if( pzErrMsg ){
    +-        *pzErrMsg = save_err_msg(db);
    ++      fclose(out);
    ++      if( rc==0 && mode && chmod(zFile, mode & 0777) ){
    ++        rc = 1;
    +       }
    ++      if( rc ) return 2;
    ++      sqlite3_result_int64(pCtx, nWrite);
    ++    }
    ++  }
    + 
    +-      /* clear saved stmt handle */
    +-      if( pArg ){
    +-        pArg->pStmt = NULL;
    +-      }
    ++  if( mtime>=0 ){
    ++#if defined(_WIN32)
    ++    /* Windows */
    ++    FILETIME lastAccess;
    ++    FILETIME lastWrite;
    ++    SYSTEMTIME currentTime;
    ++    LONGLONG intervals;
    ++    HANDLE hFile;
    ++    GetSystemTime(&currentTime);
    ++    SystemTimeToFileTime(&currentTime, &lastAccess);
    ++    intervals = Int32x32To64(mtime, 10000000) + 116444736000000000;
    ++    lastWrite.dwLowDateTime = (DWORD)intervals;
    ++    lastWrite.dwHighDateTime = intervals >> 32;
    ++    hFile = CreateFile(
    ++      zFile, FILE_WRITE_ATTRIBUTES, 0, NULL, OPEN_EXISTING,
    ++      FILE_FLAG_BACKUP_SEMANTICS, NULL
    ++    );
    ++    if( hFile!=INVALID_HANDLE_VALUE ){
    ++      BOOL bResult = SetFileTime(hFile, NULL, &lastAccess, &lastWrite);
    ++      CloseHandle(hFile);
    ++      return !bResult;
    ++    }else{
    ++      return 1;
    +     }
    +-  } /* end while */
    ++#elif defined(AT_FDCWD) && 0 /* utimensat() is not univerally available */
    ++    /* Recent unix */
    ++    struct timespec times[2];
    ++    times[0].tv_nsec = times[1].tv_nsec = 0;
    ++    times[0].tv_sec = time(0);
    ++    times[1].tv_sec = mtime;
    ++    if( utimensat(AT_FDCWD, zFile, times, AT_SYMLINK_NOFOLLOW) ){
    ++      return 1;
    ++    }
    ++#else
    ++    /* Legacy unix */
    ++    struct timeval times[2];
    ++    times[0].tv_usec = times[1].tv_usec = 0;
    ++    times[0].tv_sec = time(0);
    ++    times[1].tv_sec = mtime;
    ++    if( utimes(zFile, times) ){
    ++      return 1;
    ++    }
    ++#endif
    ++  }
    + 
    +-  return rc;
    ++  return 0;
    + }
    + 
    +-
    + /*
    +-** This is a different callback routine used for dumping the database.
    +-** Each row received by this callback consists of a table name,
    +-** the table type ("index" or "table") and SQL to create the table.
    +-** This routine should print text sufficient to recreate the table.
    ++** Implementation of the "writefile(W,X[,Y[,Z]]])" SQL function.  
    ++** Refer to header comments at the top of this file for details.
    + */
    +-static int dump_callback(void *pArg, int nArg, char **azArg, char **azCol){
    +-  int rc;
    +-  const char *zTable;
    +-  const char *zType;
    +-  const char *zSql;
    +-  const char *zPrepStmt = 0;
    +-  ShellState *p = (ShellState *)pArg;
    ++static void writefileFunc(
    ++  sqlite3_context *context,
    ++  int argc,
    ++  sqlite3_value **argv
    ++){
    ++  const char *zFile;
    ++  mode_t mode = 0;
    ++  int res;
    ++  sqlite3_int64 mtime = -1;
    + 
    +-  UNUSED_PARAMETER(azCol);
    +-  if( nArg!=3 ) return 1;
    +-  zTable = azArg[0];
    +-  zType = azArg[1];
    +-  zSql = azArg[2];
    +-  
    +-  if( strcmp(zTable, "sqlite_sequence")==0 ){
    +-    zPrepStmt = "DELETE FROM sqlite_sequence;\n";
    +-  }else if( sqlite3_strglob("sqlite_stat?", zTable)==0 ){
    +-    fprintf(p->out, "ANALYZE sqlite_master;\n");
    +-  }else if( strncmp(zTable, "sqlite_", 7)==0 ){
    +-    return 0;
    +-  }else if( strncmp(zSql, "CREATE VIRTUAL TABLE", 20)==0 ){
    +-    char *zIns;
    +-    if( !p->writableSchema ){
    +-      fprintf(p->out, "PRAGMA writable_schema=ON;\n");
    +-      p->writableSchema = 1;
    +-    }
    +-    zIns = sqlite3_mprintf(
    +-       "INSERT INTO sqlite_master(type,name,tbl_name,rootpage,sql)"
    +-       "VALUES('table','%q','%q',0,'%q');",
    +-       zTable, zTable, zSql);
    +-    fprintf(p->out, "%s\n", zIns);
    +-    sqlite3_free(zIns);
    +-    return 0;
    +-  }else{
    +-    fprintf(p->out, "%s;\n", zSql);
    ++  if( argc<2 || argc>4 ){
    ++    sqlite3_result_error(context, 
    ++        "wrong number of arguments to function writefile()", -1
    ++    );
    ++    return;
    +   }
    + 
    +-  if( strcmp(zType, "table")==0 ){
    +-    sqlite3_stmt *pTableInfo = 0;
    +-    char *zSelect = 0;
    +-    char *zTableInfo = 0;
    +-    char *zTmp = 0;
    +-    int nRow = 0;
    +-   
    +-    zTableInfo = appendText(zTableInfo, "PRAGMA table_info(", 0);
    +-    zTableInfo = appendText(zTableInfo, zTable, '"');
    +-    zTableInfo = appendText(zTableInfo, ");", 0);
    +-
    +-    rc = sqlite3_prepare_v2(p->db, zTableInfo, -1, &pTableInfo, 0);
    +-    free(zTableInfo);
    +-    if( rc!=SQLITE_OK || !pTableInfo ){
    +-      return 1;
    +-    }
    ++  zFile = (const char*)sqlite3_value_text(argv[0]);
    ++  if( zFile==0 ) return;
    ++  if( argc>=3 ){
    ++    mode = (mode_t)sqlite3_value_int(argv[2]);
    ++  }
    ++  if( argc==4 ){
    ++    mtime = sqlite3_value_int64(argv[3]);
    ++  }
    + 
    +-    zSelect = appendText(zSelect, "SELECT 'INSERT INTO ' || ", 0);
    +-    /* Always quote the table name, even if it appears to be pure ascii,
    +-    ** in case it is a keyword. Ex:  INSERT INTO "table" ... */
    +-    zTmp = appendText(zTmp, zTable, '"');
    +-    if( zTmp ){
    +-      zSelect = appendText(zSelect, zTmp, '\'');
    +-      free(zTmp);
    +-    }
    +-    zSelect = appendText(zSelect, " || ' VALUES(' || ", 0);
    +-    rc = sqlite3_step(pTableInfo);
    +-    while( rc==SQLITE_ROW ){
    +-      const char *zText = (const char *)sqlite3_column_text(pTableInfo, 1);
    +-      zSelect = appendText(zSelect, "quote(", 0);
    +-      zSelect = appendText(zSelect, zText, '"');
    +-      rc = sqlite3_step(pTableInfo);
    +-      if( rc==SQLITE_ROW ){
    +-        zSelect = appendText(zSelect, "), ", 0);
    +-      }else{
    +-        zSelect = appendText(zSelect, ") ", 0);
    +-      }
    +-      nRow++;
    +-    }
    +-    rc = sqlite3_finalize(pTableInfo);
    +-    if( rc!=SQLITE_OK || nRow==0 ){
    +-      free(zSelect);
    +-      return 1;
    ++  res = writeFile(context, zFile, argv[1], mode, mtime);
    ++  if( res==1 && errno==ENOENT ){
    ++    if( makeDirectory(zFile, mode)==SQLITE_OK ){
    ++      res = writeFile(context, zFile, argv[1], mode, mtime);
    +     }
    +-    zSelect = appendText(zSelect, "|| ')' FROM  ", 0);
    +-    zSelect = appendText(zSelect, zTable, '"');
    ++  }
    + 
    +-    rc = run_table_dump_query(p, zSelect, zPrepStmt);
    +-    if( rc==SQLITE_CORRUPT ){
    +-      zSelect = appendText(zSelect, " ORDER BY rowid DESC", 0);
    +-      run_table_dump_query(p, zSelect, 0);
    ++  if( argc>2 && res!=0 ){
    ++    if( S_ISLNK(mode) ){
    ++      ctxErrorMsg(context, "failed to create symlink: %s", zFile);
    ++    }else if( S_ISDIR(mode) ){
    ++      ctxErrorMsg(context, "failed to create directory: %s", zFile);
    ++    }else{
    ++      ctxErrorMsg(context, "failed to write file: %s", zFile);
    +     }
    +-    free(zSelect);
    +   }
    +-  return 0;
    + }
    + 
    + /*
    +-** Run zQuery.  Use dump_callback() as the callback routine so that
    +-** the contents of the query are output as SQL statements.
    ++** SQL function:   lsmode(MODE)
    + **
    +-** If we get a SQLITE_CORRUPT error, rerun the query after appending
    +-** "ORDER BY rowid DESC" to the end.
    ++** Given a numberic st_mode from stat(), convert it into a human-readable
    ++** text string in the style of "ls -l".
    + */
    +-static int run_schema_dump_query(
    +-  ShellState *p, 
    +-  const char *zQuery
    ++static void lsModeFunc(
    ++  sqlite3_context *context,
    ++  int argc,
    ++  sqlite3_value **argv
    ++){
    ++  int i;
    ++  int iMode = sqlite3_value_int(argv[0]);
    ++  char z[16];
    ++  (void)argc;
    ++  if( S_ISLNK(iMode) ){
    ++    z[0] = 'l';
    ++  }else if( S_ISREG(iMode) ){
    ++    z[0] = '-';
    ++  }else if( S_ISDIR(iMode) ){
    ++    z[0] = 'd';
    ++  }else{
    ++    z[0] = '?';
    ++  }
    ++  for(i=0; i<3; i++){
    ++    int m = (iMode >> ((2-i)*3));
    ++    char *a = &z[1 + i*3];
    ++    a[0] = (m & 0x4) ? 'r' : '-';
    ++    a[1] = (m & 0x2) ? 'w' : '-';
    ++    a[2] = (m & 0x1) ? 'x' : '-';
    ++  }
    ++  z[10] = '\0';
    ++  sqlite3_result_text(context, z, -1, SQLITE_TRANSIENT);
    ++}
    ++
    ++#ifndef SQLITE_OMIT_VIRTUALTABLE
    ++
    ++/* 
    ++** Cursor type for recursively iterating through a directory structure.
    ++*/
    ++typedef struct fsdir_cursor fsdir_cursor;
    ++typedef struct FsdirLevel FsdirLevel;
    ++
    ++struct FsdirLevel {
    ++  DIR *pDir;                 /* From opendir() */
    ++  char *zDir;                /* Name of directory (nul-terminated) */
    ++};
    ++
    ++struct fsdir_cursor {
    ++  sqlite3_vtab_cursor base;  /* Base class - must be first */
    ++
    ++  int nLvl;                  /* Number of entries in aLvl[] array */
    ++  int iLvl;                  /* Index of current entry */
    ++  FsdirLevel *aLvl;          /* Hierarchy of directories being traversed */
    ++
    ++  const char *zBase;
    ++  int nBase;
    ++
    ++  struct stat sStat;         /* Current lstat() results */
    ++  char *zPath;               /* Path to current entry */
    ++  sqlite3_int64 iRowid;      /* Current rowid */
    ++};
    ++
    ++typedef struct fsdir_tab fsdir_tab;
    ++struct fsdir_tab {
    ++  sqlite3_vtab base;         /* Base class - must be first */
    ++};
    ++
    ++/*
    ++** Construct a new fsdir virtual table object.
    ++*/
    ++static int fsdirConnect(
    ++  sqlite3 *db,
    ++  void *pAux,
    ++  int argc, const char *const*argv,
    ++  sqlite3_vtab **ppVtab,
    ++  char **pzErr
    + ){
    ++  fsdir_tab *pNew = 0;
    +   int rc;
    +-  char *zErr = 0;
    +-  rc = sqlite3_exec(p->db, zQuery, dump_callback, p, &zErr);
    +-  if( rc==SQLITE_CORRUPT ){
    +-    char *zQ2;
    +-    int len = strlen30(zQuery);
    +-    fprintf(p->out, "/****** CORRUPTION ERROR *******/\n");
    +-    if( zErr ){
    +-      fprintf(p->out, "/****** %s ******/\n", zErr);
    +-      sqlite3_free(zErr);
    +-      zErr = 0;
    ++  (void)pAux;
    ++  (void)argc;
    ++  (void)argv;
    ++  (void)pzErr;
    ++  rc = sqlite3_declare_vtab(db, "CREATE TABLE x" FSDIR_SCHEMA);
    ++  if( rc==SQLITE_OK ){
    ++    pNew = (fsdir_tab*)sqlite3_malloc( sizeof(*pNew) );
    ++    if( pNew==0 ) return SQLITE_NOMEM;
    ++    memset(pNew, 0, sizeof(*pNew));
    ++  }
    ++  *ppVtab = (sqlite3_vtab*)pNew;
    ++  return rc;
    ++}
    ++
    ++/*
    ++** This method is the destructor for fsdir vtab objects.
    ++*/
    ++static int fsdirDisconnect(sqlite3_vtab *pVtab){
    ++  sqlite3_free(pVtab);
    ++  return SQLITE_OK;
    ++}
    ++
    ++/*
    ++** Constructor for a new fsdir_cursor object.
    ++*/
    ++static int fsdirOpen(sqlite3_vtab *p, sqlite3_vtab_cursor **ppCursor){
    ++  fsdir_cursor *pCur;
    ++  (void)p;
    ++  pCur = sqlite3_malloc( sizeof(*pCur) );
    ++  if( pCur==0 ) return SQLITE_NOMEM;
    ++  memset(pCur, 0, sizeof(*pCur));
    ++  pCur->iLvl = -1;
    ++  *ppCursor = &pCur->base;
    ++  return SQLITE_OK;
    ++}
    ++
    ++/*
    ++** Reset a cursor back to the state it was in when first returned
    ++** by fsdirOpen().
    ++*/
    ++static void fsdirResetCursor(fsdir_cursor *pCur){
    ++  int i;
    ++  for(i=0; i<=pCur->iLvl; i++){
    ++    FsdirLevel *pLvl = &pCur->aLvl[i];
    ++    if( pLvl->pDir ) closedir(pLvl->pDir);
    ++    sqlite3_free(pLvl->zDir);
    ++  }
    ++  sqlite3_free(pCur->zPath);
    ++  pCur->aLvl = 0;
    ++  pCur->zPath = 0;
    ++  pCur->zBase = 0;
    ++  pCur->nBase = 0;
    ++  pCur->iLvl = -1;
    ++  pCur->iRowid = 1;
    ++}
    ++
    ++/*
    ++** Destructor for an fsdir_cursor.
    ++*/
    ++static int fsdirClose(sqlite3_vtab_cursor *cur){
    ++  fsdir_cursor *pCur = (fsdir_cursor*)cur;
    ++
    ++  fsdirResetCursor(pCur);
    ++  sqlite3_free(pCur->aLvl);
    ++  sqlite3_free(pCur);
    ++  return SQLITE_OK;
    ++}
    ++
    ++/*
    ++** Set the error message for the virtual table associated with cursor
    ++** pCur to the results of vprintf(zFmt, ...).
    ++*/
    ++static void fsdirSetErrmsg(fsdir_cursor *pCur, const char *zFmt, ...){
    ++  va_list ap;
    ++  va_start(ap, zFmt);
    ++  pCur->base.pVtab->zErrMsg = sqlite3_vmprintf(zFmt, ap);
    ++  va_end(ap);
    ++}
    ++
    ++
    ++/*
    ++** Advance an fsdir_cursor to its next row of output.
    ++*/
    ++static int fsdirNext(sqlite3_vtab_cursor *cur){
    ++  fsdir_cursor *pCur = (fsdir_cursor*)cur;
    ++  mode_t m = pCur->sStat.st_mode;
    ++
    ++  pCur->iRowid++;
    ++  if( S_ISDIR(m) ){
    ++    /* Descend into this directory */
    ++    int iNew = pCur->iLvl + 1;
    ++    FsdirLevel *pLvl;
    ++    if( iNew>=pCur->nLvl ){
    ++      int nNew = iNew+1;
    ++      int nByte = nNew*sizeof(FsdirLevel);
    ++      FsdirLevel *aNew = (FsdirLevel*)sqlite3_realloc(pCur->aLvl, nByte);
    ++      if( aNew==0 ) return SQLITE_NOMEM;
    ++      memset(&aNew[pCur->nLvl], 0, sizeof(FsdirLevel)*(nNew-pCur->nLvl));
    ++      pCur->aLvl = aNew;
    ++      pCur->nLvl = nNew;
    ++    }
    ++    pCur->iLvl = iNew;
    ++    pLvl = &pCur->aLvl[iNew];
    ++    
    ++    pLvl->zDir = pCur->zPath;
    ++    pCur->zPath = 0;
    ++    pLvl->pDir = opendir(pLvl->zDir);
    ++    if( pLvl->pDir==0 ){
    ++      fsdirSetErrmsg(pCur, "cannot read directory: %s", pCur->zPath);
    ++      return SQLITE_ERROR;
    +     }
    +-    zQ2 = malloc( len+100 );
    +-    if( zQ2==0 ) return rc;
    +-    sqlite3_snprintf(len+100, zQ2, "%s ORDER BY rowid DESC", zQuery);
    +-    rc = sqlite3_exec(p->db, zQ2, dump_callback, p, &zErr);
    +-    if( rc ){
    +-      fprintf(p->out, "/****** ERROR: %s ******/\n", zErr);
    +-    }else{
    +-      rc = SQLITE_CORRUPT;
    ++  }
    ++
    ++  while( pCur->iLvl>=0 ){
    ++    FsdirLevel *pLvl = &pCur->aLvl[pCur->iLvl];
    ++    struct dirent *pEntry = readdir(pLvl->pDir);
    ++    if( pEntry ){
    ++      if( pEntry->d_name[0]=='.' ){
    ++       if( pEntry->d_name[1]=='.' && pEntry->d_name[2]=='\0' ) continue;
    ++       if( pEntry->d_name[1]=='\0' ) continue;
    ++      }
    ++      sqlite3_free(pCur->zPath);
    ++      pCur->zPath = sqlite3_mprintf("%s/%s", pLvl->zDir, pEntry->d_name);
    ++      if( pCur->zPath==0 ) return SQLITE_NOMEM;
    ++      if( lstat(pCur->zPath, &pCur->sStat) ){
    ++        fsdirSetErrmsg(pCur, "cannot stat file: %s", pCur->zPath);
    ++        return SQLITE_ERROR;
    ++      }
    ++      return SQLITE_OK;
    +     }
    +-    sqlite3_free(zErr);
    +-    free(zQ2);
    ++    closedir(pLvl->pDir);
    ++    sqlite3_free(pLvl->zDir);
    ++    pLvl->pDir = 0;
    ++    pLvl->zDir = 0;
    ++    pCur->iLvl--;
    +   }
    +-  return rc;
    ++
    ++  /* EOF */
    ++  sqlite3_free(pCur->zPath);
    ++  pCur->zPath = 0;
    ++  return SQLITE_OK;
    + }
    + 
    + /*
    +-** Text of a help message
    ++** Return values of columns for the row at which the series_cursor
    ++** is currently pointing.
    + */
    +-static char zHelp[] =
    +-  ".backup ?DB? FILE      Backup DB (default \"main\") to FILE\n"
    +-  ".bail on|off           Stop after hitting an error.  Default OFF\n"
    +-  ".binary on|off         Turn binary output on or off.  Default OFF\n"
    +-  ".clone NEWDB           Clone data into NEWDB from the existing database\n"
    +-  ".databases             List names and files of attached databases\n"
    +-  ".dbinfo ?DB?           Show status information about the database\n"
    +-  ".dump ?TABLE? ...      Dump the database in an SQL text format\n"
    +-  "                         If TABLE specified, only dump tables matching\n"
    +-  "                         LIKE pattern TABLE.\n"
    +-  ".echo on|off           Turn command echo on or off\n"
    +-  ".eqp on|off            Enable or disable automatic EXPLAIN QUERY PLAN\n"
    +-  ".exit                  Exit this program\n"
    +-  ".explain ?on|off?      Turn output mode suitable for EXPLAIN on or off.\n"
    +-  "                         With no args, it turns EXPLAIN on.\n"
    +-  ".fullschema            Show schema and the content of sqlite_stat tables\n"
    +-  ".headers on|off        Turn display of headers on or off\n"
    +-  ".help                  Show this message\n"
    +-  ".import FILE TABLE     Import data from FILE into TABLE\n"
    +-  ".indexes ?TABLE?       Show names of all indexes\n"
    +-  "                         If TABLE specified, only show indexes for tables\n"
    +-  "                         matching LIKE pattern TABLE.\n"
    +-#ifdef SQLITE_ENABLE_IOTRACE
    +-  ".iotrace FILE          Enable I/O diagnostic logging to FILE\n"
    +-#endif
    +-  ".limit ?LIMIT? ?VAL?   Display or change the value of an SQLITE_LIMIT\n"
    +-#ifndef SQLITE_OMIT_LOAD_EXTENSION
    +-  ".load FILE ?ENTRY?     Load an extension library\n"
    ++static int fsdirColumn(
    ++  sqlite3_vtab_cursor *cur,   /* The cursor */
    ++  sqlite3_context *ctx,       /* First argument to sqlite3_result_...() */
    ++  int i                       /* Which column to return */
    ++){
    ++  fsdir_cursor *pCur = (fsdir_cursor*)cur;
    ++  switch( i ){
    ++    case 0: { /* name */
    ++      sqlite3_result_text(ctx, &pCur->zPath[pCur->nBase], -1, SQLITE_TRANSIENT);
    ++      break;
    ++    }
    ++
    ++    case 1: /* mode */
    ++      sqlite3_result_int64(ctx, pCur->sStat.st_mode);
    ++      break;
    ++
    ++    case 2: /* mtime */
    ++      sqlite3_result_int64(ctx, pCur->sStat.st_mtime);
    ++      break;
    ++
    ++    case 3: { /* data */
    ++      mode_t m = pCur->sStat.st_mode;
    ++      if( S_ISDIR(m) ){
    ++        sqlite3_result_null(ctx);
    ++#if !defined(_WIN32) && !defined(WIN32)
    ++      }else if( S_ISLNK(m) ){
    ++        char aStatic[64];
    ++        char *aBuf = aStatic;
    ++        int nBuf = 64;
    ++        int n;
    ++
    ++        while( 1 ){
    ++          n = readlink(pCur->zPath, aBuf, nBuf);
    ++          if( n<nBuf ) break;
    ++          if( aBuf!=aStatic ) sqlite3_free(aBuf);
    ++          nBuf = nBuf*2;
    ++          aBuf = sqlite3_malloc(nBuf);
    ++          if( aBuf==0 ){
    ++            sqlite3_result_error_nomem(ctx);
    ++            return SQLITE_NOMEM;
    ++          }
    ++        }
    ++
    ++        sqlite3_result_text(ctx, aBuf, n, SQLITE_TRANSIENT);
    ++        if( aBuf!=aStatic ) sqlite3_free(aBuf);
    + #endif
    +-  ".log FILE|off          Turn logging on or off.  FILE can be stderr/stdout\n"
    +-  ".mode MODE ?TABLE?     Set output mode where MODE is one of:\n"
    +-  "                         ascii    Columns/rows delimited by 0x1F and 0x1E\n"
    +-  "                         csv      Comma-separated values\n"
    +-  "                         column   Left-aligned columns.  (See .width)\n"
    +-  "                         html     HTML <table> code\n"
    +-  "                         insert   SQL insert statements for TABLE\n"
    +-  "                         line     One value per line\n"
    +-  "                         list     Values delimited by .separator strings\n"
    +-  "                         tabs     Tab-separated values\n"
    +-  "                         tcl      TCL list elements\n"
    +-  ".nullvalue STRING      Use STRING in place of NULL values\n"
    +-  ".once FILENAME         Output for the next SQL command only to FILENAME\n"
    +-  ".open ?FILENAME?       Close existing database and reopen FILENAME\n"
    +-  ".output ?FILENAME?     Send output to FILENAME or stdout\n"
    +-  ".print STRING...       Print literal STRING\n"
    +-  ".prompt MAIN CONTINUE  Replace the standard prompts\n"
    +-  ".quit                  Exit this program\n"
    +-  ".read FILENAME         Execute SQL in FILENAME\n"
    +-  ".restore ?DB? FILE     Restore content of DB (default \"main\") from FILE\n"
    +-  ".save FILE             Write in-memory database into FILE\n"
    +-  ".scanstats on|off      Turn sqlite3_stmt_scanstatus() metrics on or off\n"
    +-  ".schema ?TABLE?        Show the CREATE statements\n"
    +-  "                         If TABLE specified, only show tables matching\n"
    +-  "                         LIKE pattern TABLE.\n"
    +-  ".separator COL ?ROW?   Change the column separator and optionally the row\n"
    +-  "                         separator for both the output mode and .import\n"
    +-  ".shell CMD ARGS...     Run CMD ARGS... in a system shell\n"
    +-  ".show                  Show the current values for various settings\n"
    +-  ".stats on|off          Turn stats on or off\n"
    +-  ".system CMD ARGS...    Run CMD ARGS... in a system shell\n"
    +-  ".tables ?TABLE?        List names of tables\n"
    +-  "                         If TABLE specified, only list tables matching\n"
    +-  "                         LIKE pattern TABLE.\n"
    +-  ".timeout MS            Try opening locked tables for MS milliseconds\n"
    +-  ".timer on|off          Turn SQL timer on or off\n"
    +-  ".trace FILE|off        Output each SQL statement as it is run\n"
    +-  ".vfsname ?AUX?         Print the name of the VFS stack\n"
    +-  ".width NUM1 NUM2 ...   Set column widths for \"column\" mode\n"
    +-  "                         Negative values right-justify\n"
    +-;
    ++      }else{
    ++        readFileContents(ctx, pCur->zPath);
    ++      }
    ++    }
    ++  }
    ++  return SQLITE_OK;
    ++}
    + 
    +-/* Forward reference */
    +-static int process_input(ShellState *p, FILE *in);
    + /*
    +-** Implementation of the "readfile(X)" SQL function.  The entire content
    +-** of the file named X is read and returned as a BLOB.  NULL is returned
    +-** if the file does not exist or is unreadable.
    ++** Return the rowid for the current row. In this implementation, the
    ++** first row returned is assigned rowid value 1, and each subsequent
    ++** row a value 1 more than that of the previous.
    + */
    +-static void readfileFunc(
    +-  sqlite3_context *context,
    +-  int argc,
    +-  sqlite3_value **argv
    ++static int fsdirRowid(sqlite3_vtab_cursor *cur, sqlite_int64 *pRowid){
    ++  fsdir_cursor *pCur = (fsdir_cursor*)cur;
    ++  *pRowid = pCur->iRowid;
    ++  return SQLITE_OK;
    ++}
    ++
    ++/*
    ++** Return TRUE if the cursor has been moved off of the last
    ++** row of output.
    ++*/
    ++static int fsdirEof(sqlite3_vtab_cursor *cur){
    ++  fsdir_cursor *pCur = (fsdir_cursor*)cur;
    ++  return (pCur->zPath==0);
    ++}
    ++
    ++/*
    ++** xFilter callback.
    ++*/
    ++static int fsdirFilter(
    ++  sqlite3_vtab_cursor *cur, 
    ++  int idxNum, const char *idxStr,
    ++  int argc, sqlite3_value **argv
    + ){
    +-  const char *zName;
    +-  FILE *in;
    +-  long nIn;
    +-  void *pBuf;
    ++  const char *zDir = 0;
    ++  fsdir_cursor *pCur = (fsdir_cursor*)cur;
    ++  (void)idxStr;
    ++  fsdirResetCursor(pCur);
    ++
    ++  if( idxNum==0 ){
    ++    fsdirSetErrmsg(pCur, "table function fsdir requires an argument");
    ++    return SQLITE_ERROR;
    ++  }
    + 
    +-  UNUSED_PARAMETER(argc);
    +-  zName = (const char*)sqlite3_value_text(argv[0]);
    +-  if( zName==0 ) return;
    +-  in = fopen(zName, "rb");
    +-  if( in==0 ) return;
    +-  fseek(in, 0, SEEK_END);
    +-  nIn = ftell(in);
    +-  rewind(in);
    +-  pBuf = sqlite3_malloc64( nIn );
    +-  if( pBuf && 1==fread(pBuf, nIn, 1, in) ){
    +-    sqlite3_result_blob(context, pBuf, nIn, sqlite3_free);
    ++  assert( argc==idxNum && (argc==1 || argc==2) );
    ++  zDir = (const char*)sqlite3_value_text(argv[0]);
    ++  if( zDir==0 ){
    ++    fsdirSetErrmsg(pCur, "table function fsdir requires a non-NULL argument");
    ++    return SQLITE_ERROR;
    ++  }
    ++  if( argc==2 ){
    ++    pCur->zBase = (const char*)sqlite3_value_text(argv[1]);
    ++  }
    ++  if( pCur->zBase ){
    ++    pCur->nBase = (int)strlen(pCur->zBase)+1;
    ++    pCur->zPath = sqlite3_mprintf("%s/%s", pCur->zBase, zDir);
    +   }else{
    +-    sqlite3_free(pBuf);
    ++    pCur->zPath = sqlite3_mprintf("%s", zDir);
    +   }
    +-  fclose(in);
    ++
    ++  if( pCur->zPath==0 ){
    ++    return SQLITE_NOMEM;
    ++  }
    ++  if( lstat(pCur->zPath, &pCur->sStat) ){
    ++    fsdirSetErrmsg(pCur, "cannot stat file: %s", pCur->zPath);
    ++    return SQLITE_ERROR;
    ++  }
    ++
    ++  return SQLITE_OK;
    + }
    + 
    + /*
    +-** Implementation of the "writefile(X,Y)" SQL function.  The argument Y
    +-** is written into file X.  The number of bytes written is returned.  Or
    +-** NULL is returned if something goes wrong, such as being unable to open
    +-** file X for writing.
    ++** SQLite will invoke this method one or more times while planning a query
    ++** that uses the generate_series virtual table.  This routine needs to create
    ++** a query plan for each invocation and compute an estimated cost for that
    ++** plan.
    ++**
    ++** In this implementation idxNum is used to represent the
    ++** query plan.  idxStr is unused.
    ++**
    ++** The query plan is represented by bits in idxNum:
    ++**
    ++**  (1)  start = $value  -- constraint exists
    ++**  (2)  stop = $value   -- constraint exists
    ++**  (4)  step = $value   -- constraint exists
    ++**  (8)  output in descending order
    + */
    +-static void writefileFunc(
    +-  sqlite3_context *context,
    +-  int argc,
    +-  sqlite3_value **argv
    ++static int fsdirBestIndex(
    ++  sqlite3_vtab *tab,
    ++  sqlite3_index_info *pIdxInfo
    + ){
    +-  FILE *out;
    +-  const char *z;
    +-  sqlite3_int64 rc;
    +-  const char *zFile;
    ++  int i;                 /* Loop over constraints */
    ++  int idx4 = -1;
    ++  int idx5 = -1;
    ++  const struct sqlite3_index_constraint *pConstraint;
    ++
    ++  (void)tab;
    ++  pConstraint = pIdxInfo->aConstraint;
    ++  for(i=0; i<pIdxInfo->nConstraint; i++, pConstraint++){
    ++    if( pConstraint->usable==0 ) continue;
    ++    if( pConstraint->op!=SQLITE_INDEX_CONSTRAINT_EQ ) continue;
    ++    if( pConstraint->iColumn==4 ) idx4 = i;
    ++    if( pConstraint->iColumn==5 ) idx5 = i;
    ++  }
    + 
    +-  UNUSED_PARAMETER(argc);
    +-  zFile = (const char*)sqlite3_value_text(argv[0]);
    +-  if( zFile==0 ) return;
    +-  out = fopen(zFile, "wb");
    +-  if( out==0 ) return;
    +-  z = (const char*)sqlite3_value_blob(argv[1]);
    +-  if( z==0 ){
    +-    rc = 0;
    ++  if( idx4<0 ){
    ++    pIdxInfo->idxNum = 0;
    ++    pIdxInfo->estimatedCost = (double)(((sqlite3_int64)1) << 50);
    +   }else{
    +-    rc = fwrite(z, 1, sqlite3_value_bytes(argv[1]), out);
    ++    pIdxInfo->aConstraintUsage[idx4].omit = 1;
    ++    pIdxInfo->aConstraintUsage[idx4].argvIndex = 1;
    ++    if( idx5>=0 ){
    ++      pIdxInfo->aConstraintUsage[idx5].omit = 1;
    ++      pIdxInfo->aConstraintUsage[idx5].argvIndex = 2;
    ++      pIdxInfo->idxNum = 2;
    ++      pIdxInfo->estimatedCost = 10.0;
    ++    }else{
    ++      pIdxInfo->idxNum = 1;
    ++      pIdxInfo->estimatedCost = 100.0;
    ++    }
    +   }
    +-  fclose(out);
    +-  sqlite3_result_int64(context, rc);
    ++
    ++  return SQLITE_OK;
    + }
    + 
    + /*
    +-** Make sure the database is open.  If it is not, then open it.  If
    +-** the database fails to open, print an error message and exit.
    ++** Register the "fsdir" virtual table.
    + */
    +-static void open_db(ShellState *p, int keepAlive){
    +-  if( p->db==0 ){
    +-    sqlite3_initialize();
    +-    sqlite3_open(p->zDbFilename, &p->db);
    +-    globalDb = p->db;
    +-    if( p->db && sqlite3_errcode(p->db)==SQLITE_OK ){
    +-      sqlite3_create_function(p->db, "shellstatic", 0, SQLITE_UTF8, 0,
    +-          shellstaticFunc, 0, 0);
    +-    }
    +-    if( p->db==0 || SQLITE_OK!=sqlite3_errcode(p->db) ){
    +-      fprintf(stderr,"Error: unable to open database \"%s\": %s\n", 
    +-          p->zDbFilename, sqlite3_errmsg(p->db));
    +-      if( keepAlive ) return;
    +-      exit(1);
    +-    }
    +-#ifndef SQLITE_OMIT_LOAD_EXTENSION
    +-    sqlite3_enable_load_extension(p->db, 1);
    ++static int fsdirRegister(sqlite3 *db){
    ++  static sqlite3_module fsdirModule = {
    ++    0,                         /* iVersion */
    ++    0,                         /* xCreate */
    ++    fsdirConnect,              /* xConnect */
    ++    fsdirBestIndex,            /* xBestIndex */
    ++    fsdirDisconnect,           /* xDisconnect */
    ++    0,                         /* xDestroy */
    ++    fsdirOpen,                 /* xOpen - open a cursor */
    ++    fsdirClose,                /* xClose - close a cursor */
    ++    fsdirFilter,               /* xFilter - configure scan constraints */
    ++    fsdirNext,                 /* xNext - advance a cursor */
    ++    fsdirEof,                  /* xEof - check for end of scan */
    ++    fsdirColumn,               /* xColumn - read data */
    ++    fsdirRowid,                /* xRowid - read data */
    ++    0,                         /* xUpdate */
    ++    0,                         /* xBegin */
    ++    0,                         /* xSync */
    ++    0,                         /* xCommit */
    ++    0,                         /* xRollback */
    ++    0,                         /* xFindMethod */
    ++    0,                         /* xRename */
    ++    0,                         /* xSavepoint */
    ++    0,                         /* xRelease */
    ++    0                          /* xRollbackTo */
    ++  };
    ++
    ++  int rc = sqlite3_create_module(db, "fsdir", &fsdirModule, 0);
    ++  return rc;
    ++}
    ++#else         /* SQLITE_OMIT_VIRTUALTABLE */
    ++# define fsdirRegister(x) SQLITE_OK
    + #endif
    +-    sqlite3_create_function(p->db, "readfile", 1, SQLITE_UTF8, 0,
    +-                            readfileFunc, 0, 0);
    +-    sqlite3_create_function(p->db, "writefile", 2, SQLITE_UTF8, 0,
    +-                            writefileFunc, 0, 0);
    + 
    +-    // Begin Android Add
    +-    #ifndef NO_ANDROID_FUNCS
    +-        InitializeIcuOrDie();
    +-        int err = register_localized_collators(p->db, "en_US", 0);
    +-        if (err != SQLITE_OK) {
    +-          fprintf(stderr, "register_localized_collators() failed\n");
    +-          exit(1);
    +-        }
    +-        err = register_android_functions(p->db, 0);
    +-        if (err != SQLITE_OK) {
    +-          fprintf(stderr, "register_android_functions() failed\n");
    +-          exit(1);
    +-        }
    +-    #endif
    +-    // End Android Add
    ++#ifdef _WIN32
    ++
    ++#endif
    ++int sqlite3_fileio_init(
    ++  sqlite3 *db, 
    ++  char **pzErrMsg, 
    ++  const sqlite3_api_routines *pApi
    ++){
    ++  int rc = SQLITE_OK;
    ++  SQLITE_EXTENSION_INIT2(pApi);
    ++  (void)pzErrMsg;  /* Unused parameter */
    ++  rc = sqlite3_create_function(db, "readfile", 1, SQLITE_UTF8, 0,
    ++                               readfileFunc, 0, 0);
    ++  if( rc==SQLITE_OK ){
    ++    rc = sqlite3_create_function(db, "writefile", -1, SQLITE_UTF8, 0,
    ++                                 writefileFunc, 0, 0);
    ++  }
    ++  if( rc==SQLITE_OK ){
    ++    rc = sqlite3_create_function(db, "lsmode", 1, SQLITE_UTF8, 0,
    ++                                 lsModeFunc, 0, 0);
    ++  }
    ++  if( rc==SQLITE_OK ){
    ++    rc = fsdirRegister(db);
    ++  }
    ++  return rc;
    ++}
    ++
    ++/************************* End ../ext/misc/fileio.c ********************/
    ++/************************* Begin ../ext/misc/completion.c ******************/
    ++/*
    ++** 2017-07-10
    ++**
    ++** 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 implements an eponymous virtual table that returns suggested
    ++** completions for a partial SQL input.
    ++**
    ++** Suggested usage:
    ++**
    ++**     SELECT DISTINCT candidate COLLATE nocase
    ++**       FROM completion($prefix,$wholeline)
    ++**      ORDER BY 1;
    ++**
    ++** The two query parameters are optional.  $prefix is the text of the
    ++** current word being typed and that is to be completed.  $wholeline is
    ++** the complete input line, used for context.
    ++**
    ++** The raw completion() table might return the same candidate multiple
    ++** times, for example if the same column name is used to two or more
    ++** tables.  And the candidates are returned in an arbitrary order.  Hence,
    ++** the DISTINCT and ORDER BY are recommended.
    ++**
    ++** This virtual table operates at the speed of human typing, and so there
    ++** is no attempt to make it fast.  Even a slow implementation will be much
    ++** faster than any human can type.
    ++**
    ++*/
    ++SQLITE_EXTENSION_INIT1
    ++#include <assert.h>
    ++#include <string.h>
    ++#include <ctype.h>
    ++
    ++#ifndef SQLITE_OMIT_VIRTUALTABLE
    ++
    ++/* completion_vtab is a subclass of sqlite3_vtab which will
    ++** serve as the underlying representation of a completion virtual table
    ++*/
    ++typedef struct completion_vtab completion_vtab;
    ++struct completion_vtab {
    ++  sqlite3_vtab base;  /* Base class - must be first */
    ++  sqlite3 *db;        /* Database connection for this completion vtab */
    ++};
    ++
    ++/* completion_cursor is a subclass of sqlite3_vtab_cursor which will
    ++** serve as the underlying representation of a cursor that scans
    ++** over rows of the result
    ++*/
    ++typedef struct completion_cursor completion_cursor;
    ++struct completion_cursor {
    ++  sqlite3_vtab_cursor base;  /* Base class - must be first */
    ++  sqlite3 *db;               /* Database connection for this cursor */
    ++  int nPrefix, nLine;        /* Number of bytes in zPrefix and zLine */
    ++  char *zPrefix;             /* The prefix for the word we want to complete */
    ++  char *zLine;               /* The whole that we want to complete */
    ++  const char *zCurrentRow;   /* Current output row */
    ++  sqlite3_stmt *pStmt;       /* Current statement */
    ++  sqlite3_int64 iRowid;      /* The rowid */
    ++  int ePhase;                /* Current phase */
    ++  int j;                     /* inter-phase counter */
    ++};
    ++
    ++/* Values for ePhase:
    ++*/
    ++#define COMPLETION_FIRST_PHASE   1
    ++#define COMPLETION_KEYWORDS      1
    ++#define COMPLETION_PRAGMAS       2
    ++#define COMPLETION_FUNCTIONS     3
    ++#define COMPLETION_COLLATIONS    4
    ++#define COMPLETION_INDEXES       5
    ++#define COMPLETION_TRIGGERS      6
    ++#define COMPLETION_DATABASES     7
    ++#define COMPLETION_TABLES        8
    ++#define COMPLETION_COLUMNS       9
    ++#define COMPLETION_MODULES       10
    ++#define COMPLETION_EOF           11
    ++
    ++/*
    ++** The completionConnect() method is invoked to create a new
    ++** completion_vtab that describes the completion virtual table.
    ++**
    ++** Think of this routine as the constructor for completion_vtab objects.
    ++**
    ++** All this routine needs to do is:
    ++**
    ++**    (1) Allocate the completion_vtab object and initialize all fields.
    ++**
    ++**    (2) Tell SQLite (via the sqlite3_declare_vtab() interface) what the
    ++**        result set of queries against completion will look like.
    ++*/
    ++static int completionConnect(
    ++  sqlite3 *db,
    ++  void *pAux,
    ++  int argc, const char *const*argv,
    ++  sqlite3_vtab **ppVtab,
    ++  char **pzErr
    ++){
    ++  completion_vtab *pNew;
    ++  int rc;
    ++
    ++  (void)(pAux);    /* Unused parameter */
    ++  (void)(argc);    /* Unused parameter */
    ++  (void)(argv);    /* Unused parameter */
    ++  (void)(pzErr);   /* Unused parameter */
    ++
    ++/* Column numbers */
    ++#define COMPLETION_COLUMN_CANDIDATE 0  /* Suggested completion of the input */
    ++#define COMPLETION_COLUMN_PREFIX    1  /* Prefix of the word to be completed */
    ++#define COMPLETION_COLUMN_WHOLELINE 2  /* Entire line seen so far */
    ++#define COMPLETION_COLUMN_PHASE     3  /* ePhase - used for debugging only */
    ++
    ++  rc = sqlite3_declare_vtab(db,
    ++      "CREATE TABLE x("
    ++      "  candidate TEXT,"
    ++      "  prefix TEXT HIDDEN,"
    ++      "  wholeline TEXT HIDDEN,"
    ++      "  phase INT HIDDEN"        /* Used for debugging only */
    ++      ")");
    ++  if( rc==SQLITE_OK ){
    ++    pNew = sqlite3_malloc( sizeof(*pNew) );
    ++    *ppVtab = (sqlite3_vtab*)pNew;
    ++    if( pNew==0 ) return SQLITE_NOMEM;
    ++    memset(pNew, 0, sizeof(*pNew));
    ++    pNew->db = db;
    ++  }
    ++  return rc;
    ++}
    ++
    ++/*
    ++** This method is the destructor for completion_cursor objects.
    ++*/
    ++static int completionDisconnect(sqlite3_vtab *pVtab){
    ++  sqlite3_free(pVtab);
    ++  return SQLITE_OK;
    ++}
    ++
    ++/*
    ++** Constructor for a new completion_cursor object.
    ++*/
    ++static int completionOpen(sqlite3_vtab *p, sqlite3_vtab_cursor **ppCursor){
    ++  completion_cursor *pCur;
    ++  pCur = sqlite3_malloc( sizeof(*pCur) );
    ++  if( pCur==0 ) return SQLITE_NOMEM;
    ++  memset(pCur, 0, sizeof(*pCur));
    ++  pCur->db = ((completion_vtab*)p)->db;
    ++  *ppCursor = &pCur->base;
    ++  return SQLITE_OK;
    ++}
    ++
    ++/*
    ++** Reset the completion_cursor.
    ++*/
    ++static void completionCursorReset(completion_cursor *pCur){
    ++  sqlite3_free(pCur->zPrefix);   pCur->zPrefix = 0;  pCur->nPrefix = 0;
    ++  sqlite3_free(pCur->zLine);     pCur->zLine = 0;    pCur->nLine = 0;
    ++  sqlite3_finalize(pCur->pStmt); pCur->pStmt = 0;
    ++  pCur->j = 0;
    ++}
    ++
    ++/*
    ++** Destructor for a completion_cursor.
    ++*/
    ++static int completionClose(sqlite3_vtab_cursor *cur){
    ++  completionCursorReset((completion_cursor*)cur);
    ++  sqlite3_free(cur);
    ++  return SQLITE_OK;
    ++}
    ++
    ++/*
    ++** All SQL keywords understood by SQLite
    ++*/
    ++static const char *completionKwrds[] = {
    ++  "ABORT", "ACTION", "ADD", "AFTER", "ALL", "ALTER", "ANALYZE", "AND", "AS",
    ++  "ASC", "ATTACH", "AUTOINCREMENT", "BEFORE", "BEGIN", "BETWEEN", "BY",
    ++  "CASCADE", "CASE", "CAST", "CHECK", "COLLATE", "COLUMN", "COMMIT",
    ++  "CONFLICT", "CONSTRAINT", "CREATE", "CROSS", "CURRENT_DATE",
    ++  "CURRENT_TIME", "CURRENT_TIMESTAMP", "DATABASE", "DEFAULT", "DEFERRABLE",
    ++  "DEFERRED", "DELETE", "DESC", "DETACH", "DISTINCT", "DROP", "EACH",
    ++  "ELSE", "END", "ESCAPE", "EXCEPT", "EXCLUSIVE", "EXISTS", "EXPLAIN",
    ++  "FAIL", "FOR", "FOREIGN", "FROM", "FULL", "GLOB", "GROUP", "HAVING", "IF",
    ++  "IGNORE", "IMMEDIATE", "IN", "INDEX", "INDEXED", "INITIALLY", "INNER",
    ++  "INSERT", "INSTEAD", "INTERSECT", "INTO", "IS", "ISNULL", "JOIN", "KEY",
    ++  "LEFT", "LIKE", "LIMIT", "MATCH", "NATURAL", "NO", "NOT", "NOTNULL",
    ++  "NULL", "OF", "OFFSET", "ON", "OR", "ORDER", "OUTER", "PLAN", "PRAGMA",
    ++  "PRIMARY", "QUERY", "RAISE", "RECURSIVE", "REFERENCES", "REGEXP",
    ++  "REINDEX", "RELEASE", "RENAME", "REPLACE", "RESTRICT", "RIGHT",
    ++  "ROLLBACK", "ROW", "SAVEPOINT", "SELECT", "SET", "TABLE", "TEMP",
    ++  "TEMPORARY", "THEN", "TO", "TRANSACTION", "TRIGGER", "UNION", "UNIQUE",
    ++  "UPDATE", "USING", "VACUUM", "VALUES", "VIEW", "VIRTUAL", "WHEN", "WHERE",
    ++  "WITH", "WITHOUT",
    ++};
    ++#define completionKwCount \
    ++   (int)(sizeof(completionKwrds)/sizeof(completionKwrds[0]))
    ++
    ++/*
    ++** Advance a completion_cursor to its next row of output.
    ++**
    ++** The ->ePhase, ->j, and ->pStmt fields of the completion_cursor object
    ++** record the current state of the scan.  This routine sets ->zCurrentRow
    ++** to the current row of output and then returns.  If no more rows remain,
    ++** then ->ePhase is set to COMPLETION_EOF which will signal the virtual
    ++** table that has reached the end of its scan.
    ++**
    ++** The current implementation just lists potential identifiers and
    ++** keywords and filters them by zPrefix.  Future enhancements should
    ++** take zLine into account to try to restrict the set of identifiers and
    ++** keywords based on what would be legal at the current point of input.
    ++*/
    ++static int completionNext(sqlite3_vtab_cursor *cur){
    ++  completion_cursor *pCur = (completion_cursor*)cur;
    ++  int eNextPhase = 0;  /* Next phase to try if current phase reaches end */
    ++  int iCol = -1;       /* If >=0, step pCur->pStmt and use the i-th column */
    ++  pCur->iRowid++;
    ++  while( pCur->ePhase!=COMPLETION_EOF ){
    ++    switch( pCur->ePhase ){
    ++      case COMPLETION_KEYWORDS: {
    ++        if( pCur->j >= completionKwCount ){
    ++          pCur->zCurrentRow = 0;
    ++          pCur->ePhase = COMPLETION_DATABASES;
    ++        }else{
    ++          pCur->zCurrentRow = completionKwrds[pCur->j++];
    ++        }
    ++        iCol = -1;
    ++        break;
    ++      }
    ++      case COMPLETION_DATABASES: {
    ++        if( pCur->pStmt==0 ){
    ++          sqlite3_prepare_v2(pCur->db, "PRAGMA database_list", -1,
    ++                             &pCur->pStmt, 0);
    ++        }
    ++        iCol = 1;
    ++        eNextPhase = COMPLETION_TABLES;
    ++        break;
    ++      }
    ++      case COMPLETION_TABLES: {
    ++        if( pCur->pStmt==0 ){
    ++          sqlite3_stmt *pS2;
    ++          char *zSql = 0;
    ++          const char *zSep = "";
    ++          sqlite3_prepare_v2(pCur->db, "PRAGMA database_list", -1, &pS2, 0);
    ++          while( sqlite3_step(pS2)==SQLITE_ROW ){
    ++            const char *zDb = (const char*)sqlite3_column_text(pS2, 1);
    ++            zSql = sqlite3_mprintf(
    ++               "%z%s"
    ++               "SELECT name FROM \"%w\".sqlite_master"
    ++               " WHERE type='table'",
    ++               zSql, zSep, zDb
    ++            );
    ++            if( zSql==0 ) return SQLITE_NOMEM;
    ++            zSep = " UNION ";
    ++          }
    ++          sqlite3_finalize(pS2);
    ++          sqlite3_prepare_v2(pCur->db, zSql, -1, &pCur->pStmt, 0);
    ++          sqlite3_free(zSql);
    ++        }
    ++        iCol = 0;
    ++        eNextPhase = COMPLETION_COLUMNS;
    ++        break;
    ++      }
    ++      case COMPLETION_COLUMNS: {
    ++        if( pCur->pStmt==0 ){
    ++          sqlite3_stmt *pS2;
    ++          char *zSql = 0;
    ++          const char *zSep = "";
    ++          sqlite3_prepare_v2(pCur->db, "PRAGMA database_list", -1, &pS2, 0);
    ++          while( sqlite3_step(pS2)==SQLITE_ROW ){
    ++            const char *zDb = (const char*)sqlite3_column_text(pS2, 1);
    ++            zSql = sqlite3_mprintf(
    ++               "%z%s"
    ++               "SELECT pti.name FROM \"%w\".sqlite_master AS sm"
    ++                       " JOIN pragma_table_info(sm.name,%Q) AS pti"
    ++               " WHERE sm.type='table'",
    ++               zSql, zSep, zDb, zDb
    ++            );
    ++            if( zSql==0 ) return SQLITE_NOMEM;
    ++            zSep = " UNION ";
    ++          }
    ++          sqlite3_finalize(pS2);
    ++          sqlite3_prepare_v2(pCur->db, zSql, -1, &pCur->pStmt, 0);
    ++          sqlite3_free(zSql);
    ++        }
    ++        iCol = 0;
    ++        eNextPhase = COMPLETION_EOF;
    ++        break;
    ++      }
    ++    }
    ++    if( iCol<0 ){
    ++      /* This case is when the phase presets zCurrentRow */
    ++      if( pCur->zCurrentRow==0 ) continue;
    ++    }else{
    ++      if( sqlite3_step(pCur->pStmt)==SQLITE_ROW ){
    ++        /* Extract the next row of content */
    ++        pCur->zCurrentRow = (const char*)sqlite3_column_text(pCur->pStmt, iCol);
    ++      }else{
    ++        /* When all rows are finished, advance to the next phase */
    ++        sqlite3_finalize(pCur->pStmt);
    ++        pCur->pStmt = 0;
    ++        pCur->ePhase = eNextPhase;
    ++        continue;
    ++      }
    ++    }
    ++    if( pCur->nPrefix==0 ) break;
    ++    if( sqlite3_strnicmp(pCur->zPrefix, pCur->zCurrentRow, pCur->nPrefix)==0 ){
    ++      break;
    ++    }
    ++  }
    ++
    ++  return SQLITE_OK;
    ++}
    ++
    ++/*
    ++** Return values of columns for the row at which the completion_cursor
    ++** is currently pointing.
    ++*/
    ++static int completionColumn(
    ++  sqlite3_vtab_cursor *cur,   /* The cursor */
    ++  sqlite3_context *ctx,       /* First argument to sqlite3_result_...() */
    ++  int i                       /* Which column to return */
    ++){
    ++  completion_cursor *pCur = (completion_cursor*)cur;
    ++  switch( i ){
    ++    case COMPLETION_COLUMN_CANDIDATE: {
    ++      sqlite3_result_text(ctx, pCur->zCurrentRow, -1, SQLITE_TRANSIENT);
    ++      break;
    ++    }
    ++    case COMPLETION_COLUMN_PREFIX: {
    ++      sqlite3_result_text(ctx, pCur->zPrefix, -1, SQLITE_TRANSIENT);
    ++      break;
    ++    }
    ++    case COMPLETION_COLUMN_WHOLELINE: {
    ++      sqlite3_result_text(ctx, pCur->zLine, -1, SQLITE_TRANSIENT);
    ++      break;
    ++    }
    ++    case COMPLETION_COLUMN_PHASE: {
    ++      sqlite3_result_int(ctx, pCur->ePhase);
    ++      break;
    ++    }
    ++  }
    ++  return SQLITE_OK;
    ++}
    ++
    ++/*
    ++** Return the rowid for the current row.  In this implementation, the
    ++** rowid is the same as the output value.
    ++*/
    ++static int completionRowid(sqlite3_vtab_cursor *cur, sqlite_int64 *pRowid){
    ++  completion_cursor *pCur = (completion_cursor*)cur;
    ++  *pRowid = pCur->iRowid;
    ++  return SQLITE_OK;
    ++}
    ++
    ++/*
    ++** Return TRUE if the cursor has been moved off of the last
    ++** row of output.
    ++*/
    ++static int completionEof(sqlite3_vtab_cursor *cur){
    ++  completion_cursor *pCur = (completion_cursor*)cur;
    ++  return pCur->ePhase >= COMPLETION_EOF;
    ++}
    ++
    ++/*
    ++** This method is called to "rewind" the completion_cursor object back
    ++** to the first row of output.  This method is always called at least
    ++** once prior to any call to completionColumn() or completionRowid() or 
    ++** completionEof().
    ++*/
    ++static int completionFilter(
    ++  sqlite3_vtab_cursor *pVtabCursor, 
    ++  int idxNum, const char *idxStr,
    ++  int argc, sqlite3_value **argv
    ++){
    ++  completion_cursor *pCur = (completion_cursor *)pVtabCursor;
    ++  int iArg = 0;
    ++  (void)(idxStr);   /* Unused parameter */
    ++  (void)(argc);     /* Unused parameter */
    ++  completionCursorReset(pCur);
    ++  if( idxNum & 1 ){
    ++    pCur->nPrefix = sqlite3_value_bytes(argv[iArg]);
    ++    if( pCur->nPrefix>0 ){
    ++      pCur->zPrefix = sqlite3_mprintf("%s", sqlite3_value_text(argv[iArg]));
    ++      if( pCur->zPrefix==0 ) return SQLITE_NOMEM;
    ++    }
    ++    iArg++;
    ++  }
    ++  if( idxNum & 2 ){
    ++    pCur->nLine = sqlite3_value_bytes(argv[iArg]);
    ++    if( pCur->nLine>0 ){
    ++      pCur->zLine = sqlite3_mprintf("%s", sqlite3_value_text(argv[iArg]));
    ++      if( pCur->zLine==0 ) return SQLITE_NOMEM;
    ++    }
    ++    iArg++;
    ++  }
    ++  if( pCur->zLine!=0 && pCur->zPrefix==0 ){
    ++    int i = pCur->nLine;
    ++    while( i>0 && (isalnum(pCur->zLine[i-1]) || pCur->zLine[i-1]=='_') ){
    ++      i--;
    ++    }
    ++    pCur->nPrefix = pCur->nLine - i;
    ++    if( pCur->nPrefix>0 ){
    ++      pCur->zPrefix = sqlite3_mprintf("%.*s", pCur->nPrefix, pCur->zLine + i);
    ++      if( pCur->zPrefix==0 ) return SQLITE_NOMEM;
    ++    }
    ++  }
    ++  pCur->iRowid = 0;
    ++  pCur->ePhase = COMPLETION_FIRST_PHASE;
    ++  return completionNext(pVtabCursor);
    ++}
    ++
    ++/*
    ++** SQLite will invoke this method one or more times while planning a query
    ++** that uses the completion virtual table.  This routine needs to create
    ++** a query plan for each invocation and compute an estimated cost for that
    ++** plan.
    ++**
    ++** There are two hidden parameters that act as arguments to the table-valued
    ++** function:  "prefix" and "wholeline".  Bit 0 of idxNum is set if "prefix"
    ++** is available and bit 1 is set if "wholeline" is available.
    ++*/
    ++static int completionBestIndex(
    ++  sqlite3_vtab *tab,
    ++  sqlite3_index_info *pIdxInfo
    ++){
    ++  int i;                 /* Loop over constraints */
    ++  int idxNum = 0;        /* The query plan bitmask */
    ++  int prefixIdx = -1;    /* Index of the start= constraint, or -1 if none */
    ++  int wholelineIdx = -1; /* Index of the stop= constraint, or -1 if none */
    ++  int nArg = 0;          /* Number of arguments that completeFilter() expects */
    ++  const struct sqlite3_index_constraint *pConstraint;
    ++
    ++  (void)(tab);    /* Unused parameter */
    ++  pConstraint = pIdxInfo->aConstraint;
    ++  for(i=0; i<pIdxInfo->nConstraint; i++, pConstraint++){
    ++    if( pConstraint->usable==0 ) continue;
    ++    if( pConstraint->op!=SQLITE_INDEX_CONSTRAINT_EQ ) continue;
    ++    switch( pConstraint->iColumn ){
    ++      case COMPLETION_COLUMN_PREFIX:
    ++        prefixIdx = i;
    ++        idxNum |= 1;
    ++        break;
    ++      case COMPLETION_COLUMN_WHOLELINE:
    ++        wholelineIdx = i;
    ++        idxNum |= 2;
    ++        break;
    ++    }
    ++  }
    ++  if( prefixIdx>=0 ){
    ++    pIdxInfo->aConstraintUsage[prefixIdx].argvIndex = ++nArg;
    ++    pIdxInfo->aConstraintUsage[prefixIdx].omit = 1;
    ++  }
    ++  if( wholelineIdx>=0 ){
    ++    pIdxInfo->aConstraintUsage[wholelineIdx].argvIndex = ++nArg;
    ++    pIdxInfo->aConstraintUsage[wholelineIdx].omit = 1;
    ++  }
    ++  pIdxInfo->idxNum = idxNum;
    ++  pIdxInfo->estimatedCost = (double)5000 - 1000*nArg;
    ++  pIdxInfo->estimatedRows = 500 - 100*nArg;
    ++  return SQLITE_OK;
    ++}
    ++
    ++/*
    ++** This following structure defines all the methods for the 
    ++** completion virtual table.
    ++*/
    ++static sqlite3_module completionModule = {
    ++  0,                         /* iVersion */
    ++  0,                         /* xCreate */
    ++  completionConnect,         /* xConnect */
    ++  completionBestIndex,       /* xBestIndex */
    ++  completionDisconnect,      /* xDisconnect */
    ++  0,                         /* xDestroy */
    ++  completionOpen,            /* xOpen - open a cursor */
    ++  completionClose,           /* xClose - close a cursor */
    ++  completionFilter,          /* xFilter - configure scan constraints */
    ++  completionNext,            /* xNext - advance a cursor */
    ++  completionEof,             /* xEof - check for end of scan */
    ++  completionColumn,          /* xColumn - read data */
    ++  completionRowid,           /* xRowid - read data */
    ++  0,                         /* xUpdate */
    ++  0,                         /* xBegin */
    ++  0,                         /* xSync */
    ++  0,                         /* xCommit */
    ++  0,                         /* xRollback */
    ++  0,                         /* xFindMethod */
    ++  0,                         /* xRename */
    ++  0,                         /* xSavepoint */
    ++  0,                         /* xRelease */
    ++  0                          /* xRollbackTo */
    ++};
    ++
    ++#endif /* SQLITE_OMIT_VIRTUALTABLE */
    ++
    ++int sqlite3CompletionVtabInit(sqlite3 *db){
    ++  int rc = SQLITE_OK;
    ++#ifndef SQLITE_OMIT_VIRTUALTABLE
    ++  rc = sqlite3_create_module(db, "completion", &completionModule, 0);
    ++#endif
    ++  return rc;
    ++}
    ++
    ++#ifdef _WIN32
    ++
    ++#endif
    ++int sqlite3_completion_init(
    ++  sqlite3 *db, 
    ++  char **pzErrMsg, 
    ++  const sqlite3_api_routines *pApi
    ++){
    ++  int rc = SQLITE_OK;
    ++  SQLITE_EXTENSION_INIT2(pApi);
    ++  (void)(pzErrMsg);  /* Unused parameter */
    ++#ifndef SQLITE_OMIT_VIRTUALTABLE
    ++  rc = sqlite3CompletionVtabInit(db);
    ++#endif
    ++  return rc;
    ++}
    ++
    ++/************************* End ../ext/misc/completion.c ********************/
    ++/************************* Begin ../ext/misc/appendvfs.c ******************/
    ++/*
    ++** 2017-10-20
    ++**
    ++** 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 implements a VFS shim that allows an SQLite database to be
    ++** appended onto the end of some other file, such as an executable.
    ++**
    ++** A special record must appear at the end of the file that identifies the
    ++** file as an appended database and provides an offset to page 1.  For
    ++** best performance page 1 should be located at a disk page boundary, though
    ++** that is not required.
    ++**
    ++** When opening a database using this VFS, the connection might treat
    ++** the file as an ordinary SQLite database, or it might treat is as a
    ++** database appended onto some other file.  Here are the rules:
    ++**
    ++**  (1)  When opening a new empty file, that file is treated as an ordinary
    ++**       database.
    ++**
    ++**  (2)  When opening a file that begins with the standard SQLite prefix
    ++**       string "SQLite format 3", that file is treated as an ordinary
    ++**       database.
    ++**
    ++**  (3)  When opening a file that ends with the appendvfs trailer string
    ++**       "Start-Of-SQLite3-NNNNNNNN" that file is treated as an appended
    ++**       database.
    ++**
    ++**  (4)  If none of the above apply and the SQLITE_OPEN_CREATE flag is
    ++**       set, then a new database is appended to the already existing file.
    ++**
    ++**  (5)  Otherwise, SQLITE_CANTOPEN is returned.
    ++**
    ++** To avoid unnecessary complications with the PENDING_BYTE, the size of
    ++** the file containing the database is limited to 1GB.  This VFS will refuse
    ++** to read or write past the 1GB mark.  This restriction might be lifted in
    ++** future versions.  For now, if you need a large database, then keep the
    ++** database in a separate file.
    ++**
    ++** If the file being opened is not an appended database, then this shim is
    ++** a pass-through into the default underlying VFS.
    ++**/
    ++SQLITE_EXTENSION_INIT1
    ++#include <string.h>
    ++#include <assert.h>
    ++
    ++/* The append mark at the end of the database is:
    ++**
    ++**     Start-Of-SQLite3-NNNNNNNN
    ++**     123456789 123456789 12345
    ++**
    ++** The NNNNNNNN represents a 64-bit big-endian unsigned integer which is
    ++** the offset to page 1.
    ++*/
    ++#define APND_MARK_PREFIX     "Start-Of-SQLite3-"
    ++#define APND_MARK_PREFIX_SZ  17
    ++#define APND_MARK_SIZE       25
    ++
    ++/*
    ++** Maximum size of the combined prefix + database + append-mark.  This
    ++** must be less than 0x40000000 to avoid locking issues on Windows.
    ++*/
    ++#define APND_MAX_SIZE  (65536*15259)
    ++
    ++/*
    ++** Forward declaration of objects used by this utility
    ++*/
    ++typedef struct sqlite3_vfs ApndVfs;
    ++typedef struct ApndFile ApndFile;
    ++
    ++/* Access to a lower-level VFS that (might) implement dynamic loading,
    ++** access to randomness, etc.
    ++*/
    ++#define ORIGVFS(p)  ((sqlite3_vfs*)((p)->pAppData))
    ++#define ORIGFILE(p) ((sqlite3_file*)(((ApndFile*)(p))+1))
    ++
    ++/* An open file */
    ++struct ApndFile {
    ++  sqlite3_file base;              /* IO methods */
    ++  sqlite3_int64 iPgOne;           /* File offset to page 1 */
    ++  sqlite3_int64 iMark;            /* Start of the append-mark */
    ++};
    ++
    ++/*
    ++** Methods for ApndFile
    ++*/
    ++static int apndClose(sqlite3_file*);
    ++static int apndRead(sqlite3_file*, void*, int iAmt, sqlite3_int64 iOfst);
    ++static int apndWrite(sqlite3_file*,const void*,int iAmt, sqlite3_int64 iOfst);
    ++static int apndTruncate(sqlite3_file*, sqlite3_int64 size);
    ++static int apndSync(sqlite3_file*, int flags);
    ++static int apndFileSize(sqlite3_file*, sqlite3_int64 *pSize);
    ++static int apndLock(sqlite3_file*, int);
    ++static int apndUnlock(sqlite3_file*, int);
    ++static int apndCheckReservedLock(sqlite3_file*, int *pResOut);
    ++static int apndFileControl(sqlite3_file*, int op, void *pArg);
    ++static int apndSectorSize(sqlite3_file*);
    ++static int apndDeviceCharacteristics(sqlite3_file*);
    ++static int apndShmMap(sqlite3_file*, int iPg, int pgsz, int, void volatile**);
    ++static int apndShmLock(sqlite3_file*, int offset, int n, int flags);
    ++static void apndShmBarrier(sqlite3_file*);
    ++static int apndShmUnmap(sqlite3_file*, int deleteFlag);
    ++static int apndFetch(sqlite3_file*, sqlite3_int64 iOfst, int iAmt, void **pp);
    ++static int apndUnfetch(sqlite3_file*, sqlite3_int64 iOfst, void *p);
    ++
    ++/*
    ++** Methods for ApndVfs
    ++*/
    ++static int apndOpen(sqlite3_vfs*, const char *, sqlite3_file*, int , int *);
    ++static int apndDelete(sqlite3_vfs*, const char *zName, int syncDir);
    ++static int apndAccess(sqlite3_vfs*, const char *zName, int flags, int *);
    ++static int apndFullPathname(sqlite3_vfs*, const char *zName, int, char *zOut);
    ++static void *apndDlOpen(sqlite3_vfs*, const char *zFilename);
    ++static void apndDlError(sqlite3_vfs*, int nByte, char *zErrMsg);
    ++static void (*apndDlSym(sqlite3_vfs *pVfs, void *p, const char*zSym))(void);
    ++static void apndDlClose(sqlite3_vfs*, void*);
    ++static int apndRandomness(sqlite3_vfs*, int nByte, char *zOut);
    ++static int apndSleep(sqlite3_vfs*, int microseconds);
    ++static int apndCurrentTime(sqlite3_vfs*, double*);
    ++static int apndGetLastError(sqlite3_vfs*, int, char *);
    ++static int apndCurrentTimeInt64(sqlite3_vfs*, sqlite3_int64*);
    ++static int apndSetSystemCall(sqlite3_vfs*, const char*,sqlite3_syscall_ptr);
    ++static sqlite3_syscall_ptr apndGetSystemCall(sqlite3_vfs*, const char *z);
    ++static const char *apndNextSystemCall(sqlite3_vfs*, const char *zName);
    ++
    ++static sqlite3_vfs apnd_vfs = {
    ++  3,                            /* iVersion (set when registered) */
    ++  0,                            /* szOsFile (set when registered) */
    ++  1024,                         /* mxPathname */
    ++  0,                            /* pNext */
    ++  "apndvfs",                    /* zName */
    ++  0,                            /* pAppData (set when registered) */ 
    ++  apndOpen,                     /* xOpen */
    ++  apndDelete,                   /* xDelete */
    ++  apndAccess,                   /* xAccess */
    ++  apndFullPathname,             /* xFullPathname */
    ++  apndDlOpen,                   /* xDlOpen */
    ++  apndDlError,                  /* xDlError */
    ++  apndDlSym,                    /* xDlSym */
    ++  apndDlClose,                  /* xDlClose */
    ++  apndRandomness,               /* xRandomness */
    ++  apndSleep,                    /* xSleep */
    ++  apndCurrentTime,              /* xCurrentTime */
    ++  apndGetLastError,             /* xGetLastError */
    ++  apndCurrentTimeInt64,         /* xCurrentTimeInt64 */
    ++  apndSetSystemCall,            /* xSetSystemCall */
    ++  apndGetSystemCall,            /* xGetSystemCall */
    ++  apndNextSystemCall            /* xNextSystemCall */
    ++};
    ++
    ++static const sqlite3_io_methods apnd_io_methods = {
    ++  3,                              /* iVersion */
    ++  apndClose,                      /* xClose */
    ++  apndRead,                       /* xRead */
    ++  apndWrite,                      /* xWrite */
    ++  apndTruncate,                   /* xTruncate */
    ++  apndSync,                       /* xSync */
    ++  apndFileSize,                   /* xFileSize */
    ++  apndLock,                       /* xLock */
    ++  apndUnlock,                     /* xUnlock */
    ++  apndCheckReservedLock,          /* xCheckReservedLock */
    ++  apndFileControl,                /* xFileControl */
    ++  apndSectorSize,                 /* xSectorSize */
    ++  apndDeviceCharacteristics,      /* xDeviceCharacteristics */
    ++  apndShmMap,                     /* xShmMap */
    ++  apndShmLock,                    /* xShmLock */
    ++  apndShmBarrier,                 /* xShmBarrier */
    ++  apndShmUnmap,                   /* xShmUnmap */
    ++  apndFetch,                      /* xFetch */
    ++  apndUnfetch                     /* xUnfetch */
    ++};
    ++
    ++
    ++
    ++/*
    ++** Close an apnd-file.
    ++*/
    ++static int apndClose(sqlite3_file *pFile){
    ++  pFile = ORIGFILE(pFile);
    ++  return pFile->pMethods->xClose(pFile);
    ++}
    ++
    ++/*
    ++** Read data from an apnd-file.
    ++*/
    ++static int apndRead(
    ++  sqlite3_file *pFile, 
    ++  void *zBuf, 
    ++  int iAmt, 
    ++  sqlite_int64 iOfst
    ++){
    ++  ApndFile *p = (ApndFile *)pFile;
    ++  pFile = ORIGFILE(pFile);
    ++  return pFile->pMethods->xRead(pFile, zBuf, iAmt, iOfst+p->iPgOne);
    ++}
    ++
    ++/*
    ++** Add the append-mark onto the end of the file.
    ++*/
    ++static int apndWriteMark(ApndFile *p, sqlite3_file *pFile){
    ++  int i;
    ++  unsigned char a[APND_MARK_SIZE];
    ++  memcpy(a, APND_MARK_PREFIX, APND_MARK_PREFIX_SZ);
    ++  for(i=0; i<8; i++){
    ++    a[APND_MARK_PREFIX_SZ+i] = (p->iPgOne >> (56 - i*8)) & 0xff;
    ++  }
    ++  return pFile->pMethods->xWrite(pFile, a, APND_MARK_SIZE, p->iMark);
    ++}
    ++
    ++/*
    ++** Write data to an apnd-file.
    ++*/
    ++static int apndWrite(
    ++  sqlite3_file *pFile,
    ++  const void *zBuf,
    ++  int iAmt,
    ++  sqlite_int64 iOfst
    ++){
    ++  int rc;
    ++  ApndFile *p = (ApndFile *)pFile;
    ++  pFile = ORIGFILE(pFile);
    ++  if( iOfst+iAmt>=APND_MAX_SIZE ) return SQLITE_FULL;
    ++  rc = pFile->pMethods->xWrite(pFile, zBuf, iAmt, iOfst+p->iPgOne);
    ++  if( rc==SQLITE_OK &&  iOfst + iAmt + p->iPgOne > p->iMark ){
    ++    sqlite3_int64 sz = 0;
    ++    rc = pFile->pMethods->xFileSize(pFile, &sz);
    ++    if( rc==SQLITE_OK ){
    ++      p->iMark = sz - APND_MARK_SIZE;
    ++      if( iOfst + iAmt + p->iPgOne > p->iMark ){
    ++        p->iMark = p->iPgOne + iOfst + iAmt;
    ++        rc = apndWriteMark(p, pFile);
    ++      }
    ++    }
    ++  }
    ++  return rc;
    ++}
    ++
    ++/*
    ++** Truncate an apnd-file.
    ++*/
    ++static int apndTruncate(sqlite3_file *pFile, sqlite_int64 size){
    ++  int rc;
    ++  ApndFile *p = (ApndFile *)pFile;
    ++  pFile = ORIGFILE(pFile);
    ++  rc = pFile->pMethods->xTruncate(pFile, size+p->iPgOne+APND_MARK_SIZE);
    ++  if( rc==SQLITE_OK ){
    ++    p->iMark = p->iPgOne+size;
    ++    rc = apndWriteMark(p, pFile);
    ++  }
    ++  return rc;
    ++}
    ++
    ++/*
    ++** Sync an apnd-file.
    ++*/
    ++static int apndSync(sqlite3_file *pFile, int flags){
    ++  pFile = ORIGFILE(pFile);
    ++  return pFile->pMethods->xSync(pFile, flags);
    ++}
    ++
    ++/*
    ++** Return the current file-size of an apnd-file.
    ++*/
    ++static int apndFileSize(sqlite3_file *pFile, sqlite_int64 *pSize){
    ++  ApndFile *p = (ApndFile *)pFile;
    ++  int rc;
    ++  pFile = ORIGFILE(p);
    ++  rc = pFile->pMethods->xFileSize(pFile, pSize);
    ++  if( rc==SQLITE_OK && p->iPgOne ){
    ++    *pSize -= p->iPgOne + APND_MARK_SIZE;
    ++  }
    ++  return rc;
    ++}
    ++
    ++/*
    ++** Lock an apnd-file.
    ++*/
    ++static int apndLock(sqlite3_file *pFile, int eLock){
    ++  pFile = ORIGFILE(pFile);
    ++  return pFile->pMethods->xLock(pFile, eLock);
    ++}
    ++
    ++/*
    ++** Unlock an apnd-file.
    ++*/
    ++static int apndUnlock(sqlite3_file *pFile, int eLock){
    ++  pFile = ORIGFILE(pFile);
    ++  return pFile->pMethods->xUnlock(pFile, eLock);
    ++}
    ++
    ++/*
    ++** Check if another file-handle holds a RESERVED lock on an apnd-file.
    ++*/
    ++static int apndCheckReservedLock(sqlite3_file *pFile, int *pResOut){
    ++  pFile = ORIGFILE(pFile);
    ++  return pFile->pMethods->xCheckReservedLock(pFile, pResOut);
    ++}
    ++
    ++/*
    ++** File control method. For custom operations on an apnd-file.
    ++*/
    ++static int apndFileControl(sqlite3_file *pFile, int op, void *pArg){
    ++  ApndFile *p = (ApndFile *)pFile;
    ++  int rc;
    ++  pFile = ORIGFILE(pFile);
    ++  rc = pFile->pMethods->xFileControl(pFile, op, pArg);
    ++  if( rc==SQLITE_OK && op==SQLITE_FCNTL_VFSNAME ){
    ++    *(char**)pArg = sqlite3_mprintf("apnd(%lld)/%z", p->iPgOne, *(char**)pArg);
    ++  }
    ++  return rc;
    ++}
    ++
    ++/*
    ++** Return the sector-size in bytes for an apnd-file.
    ++*/
    ++static int apndSectorSize(sqlite3_file *pFile){
    ++  pFile = ORIGFILE(pFile);
    ++  return pFile->pMethods->xSectorSize(pFile);
    ++}
    ++
    ++/*
    ++** Return the device characteristic flags supported by an apnd-file.
    ++*/
    ++static int apndDeviceCharacteristics(sqlite3_file *pFile){
    ++  pFile = ORIGFILE(pFile);
    ++  return pFile->pMethods->xDeviceCharacteristics(pFile);
    ++}
    ++
    ++/* Create a shared memory file mapping */
    ++static int apndShmMap(
    ++  sqlite3_file *pFile,
    ++  int iPg,
    ++  int pgsz,
    ++  int bExtend,
    ++  void volatile **pp
    ++){
    ++  pFile = ORIGFILE(pFile);
    ++  return pFile->pMethods->xShmMap(pFile,iPg,pgsz,bExtend,pp);
    ++}
    ++
    ++/* Perform locking on a shared-memory segment */
    ++static int apndShmLock(sqlite3_file *pFile, int offset, int n, int flags){
    ++  pFile = ORIGFILE(pFile);
    ++  return pFile->pMethods->xShmLock(pFile,offset,n,flags);
    ++}
    ++
    ++/* Memory barrier operation on shared memory */
    ++static void apndShmBarrier(sqlite3_file *pFile){
    ++  pFile = ORIGFILE(pFile);
    ++  pFile->pMethods->xShmBarrier(pFile);
    ++}
    ++
    ++/* Unmap a shared memory segment */
    ++static int apndShmUnmap(sqlite3_file *pFile, int deleteFlag){
    ++  pFile = ORIGFILE(pFile);
    ++  return pFile->pMethods->xShmUnmap(pFile,deleteFlag);
    ++}
    ++
    ++/* Fetch a page of a memory-mapped file */
    ++static int apndFetch(
    ++  sqlite3_file *pFile,
    ++  sqlite3_int64 iOfst,
    ++  int iAmt,
    ++  void **pp
    ++){
    ++  ApndFile *p = (ApndFile *)pFile;
    ++  pFile = ORIGFILE(pFile);
    ++  return pFile->pMethods->xFetch(pFile, iOfst+p->iPgOne, iAmt, pp);
    ++}
    ++
    ++/* Release a memory-mapped page */
    ++static int apndUnfetch(sqlite3_file *pFile, sqlite3_int64 iOfst, void *pPage){
    ++  ApndFile *p = (ApndFile *)pFile;
    ++  pFile = ORIGFILE(pFile);
    ++  return pFile->pMethods->xUnfetch(pFile, iOfst+p->iPgOne, pPage);
    ++}
    ++
    ++/*
    ++** Check to see if the file is an ordinary SQLite database file.
    ++*/
    ++static int apndIsOrdinaryDatabaseFile(sqlite3_int64 sz, sqlite3_file *pFile){
    ++  int rc;
    ++  char zHdr[16];
    ++  static const char aSqliteHdr[] = "SQLite format 3";
    ++  if( sz<512 ) return 0;
    ++  rc = pFile->pMethods->xRead(pFile, zHdr, sizeof(zHdr), 0);
    ++  if( rc ) return 0;
    ++  return memcmp(zHdr, aSqliteHdr, sizeof(zHdr))==0;
    ++}
    ++
    ++/*
    ++** Try to read the append-mark off the end of a file.  Return the
    ++** start of the appended database if the append-mark is present.  If
    ++** there is no append-mark, return -1;
    ++*/
    ++static sqlite3_int64 apndReadMark(sqlite3_int64 sz, sqlite3_file *pFile){
    ++  int rc, i;
    ++  sqlite3_int64 iMark;
    ++  unsigned char a[APND_MARK_SIZE];
    ++
    ++  if( sz<=APND_MARK_SIZE ) return -1;
    ++  rc = pFile->pMethods->xRead(pFile, a, APND_MARK_SIZE, sz-APND_MARK_SIZE);
    ++  if( rc ) return -1;
    ++  if( memcmp(a, APND_MARK_PREFIX, APND_MARK_PREFIX_SZ)!=0 ) return -1;
    ++  iMark = ((sqlite3_int64)(a[APND_MARK_PREFIX_SZ]&0x7f))<<56;
    ++  for(i=1; i<8; i++){    
    ++    iMark += (sqlite3_int64)a[APND_MARK_PREFIX_SZ+i]<<(56-8*i);
    ++  }
    ++  return iMark;
    ++}
    ++
    ++/*
    ++** Open an apnd file handle.
    ++*/
    ++static int apndOpen(
    ++  sqlite3_vfs *pVfs,
    ++  const char *zName,
    ++  sqlite3_file *pFile,
    ++  int flags,
    ++  int *pOutFlags
    ++){
    ++  ApndFile *p;
    ++  sqlite3_file *pSubFile;
    ++  sqlite3_vfs *pSubVfs;
    ++  int rc;
    ++  sqlite3_int64 sz;
    ++  pSubVfs = ORIGVFS(pVfs);
    ++  if( (flags & SQLITE_OPEN_MAIN_DB)==0 ){
    ++    return pSubVfs->xOpen(pSubVfs, zName, pFile, flags, pOutFlags);
    ++  }
    ++  p = (ApndFile*)pFile;
    ++  memset(p, 0, sizeof(*p));
    ++  pSubFile = ORIGFILE(pFile);
    ++  p->base.pMethods = &apnd_io_methods;
    ++  rc = pSubVfs->xOpen(pSubVfs, zName, pSubFile, flags, pOutFlags);
    ++  if( rc ) goto apnd_open_done;
    ++  rc = pSubFile->pMethods->xFileSize(pSubFile, &sz);
    ++  if( rc ){
    ++    pSubFile->pMethods->xClose(pSubFile);
    ++    goto apnd_open_done;
    ++  }
    ++  if( apndIsOrdinaryDatabaseFile(sz, pSubFile) ){
    ++    memmove(pFile, pSubFile, pSubVfs->szOsFile);
    ++    return SQLITE_OK;
    ++  }
    ++  p->iMark = 0;
    ++  p->iPgOne = apndReadMark(sz, pFile);
    ++  if( p->iPgOne>0 ){
    ++    return SQLITE_OK;
    ++  }
    ++  if( (flags & SQLITE_OPEN_CREATE)==0 ){
    ++    pSubFile->pMethods->xClose(pSubFile);
    ++    rc = SQLITE_CANTOPEN;
    ++  }
    ++  p->iPgOne = (sz+0xfff) & ~(sqlite3_int64)0xfff;
    ++apnd_open_done:
    ++  if( rc ) pFile->pMethods = 0;
    ++  return rc;
    ++}
    ++
    ++/*
    ++** All other VFS methods are pass-thrus.
    ++*/
    ++static int apndDelete(sqlite3_vfs *pVfs, const char *zPath, int dirSync){
    ++  return ORIGVFS(pVfs)->xDelete(ORIGVFS(pVfs), zPath, dirSync);
    ++}
    ++static int apndAccess(
    ++  sqlite3_vfs *pVfs, 
    ++  const char *zPath, 
    ++  int flags, 
    ++  int *pResOut
    ++){
    ++  return ORIGVFS(pVfs)->xAccess(ORIGVFS(pVfs), zPath, flags, pResOut);
    ++}
    ++static int apndFullPathname(
    ++  sqlite3_vfs *pVfs, 
    ++  const char *zPath, 
    ++  int nOut, 
    ++  char *zOut
    ++){
    ++  return ORIGVFS(pVfs)->xFullPathname(ORIGVFS(pVfs),zPath,nOut,zOut);
    ++}
    ++static void *apndDlOpen(sqlite3_vfs *pVfs, const char *zPath){
    ++  return ORIGVFS(pVfs)->xDlOpen(ORIGVFS(pVfs), zPath);
    ++}
    ++static void apndDlError(sqlite3_vfs *pVfs, int nByte, char *zErrMsg){
    ++  ORIGVFS(pVfs)->xDlError(ORIGVFS(pVfs), nByte, zErrMsg);
    ++}
    ++static void (*apndDlSym(sqlite3_vfs *pVfs, void *p, const char *zSym))(void){
    ++  return ORIGVFS(pVfs)->xDlSym(ORIGVFS(pVfs), p, zSym);
    ++}
    ++static void apndDlClose(sqlite3_vfs *pVfs, void *pHandle){
    ++  ORIGVFS(pVfs)->xDlClose(ORIGVFS(pVfs), pHandle);
    ++}
    ++static int apndRandomness(sqlite3_vfs *pVfs, int nByte, char *zBufOut){
    ++  return ORIGVFS(pVfs)->xRandomness(ORIGVFS(pVfs), nByte, zBufOut);
    ++}
    ++static int apndSleep(sqlite3_vfs *pVfs, int nMicro){
    ++  return ORIGVFS(pVfs)->xSleep(ORIGVFS(pVfs), nMicro);
    ++}
    ++static int apndCurrentTime(sqlite3_vfs *pVfs, double *pTimeOut){
    ++  return ORIGVFS(pVfs)->xCurrentTime(ORIGVFS(pVfs), pTimeOut);
    ++}
    ++static int apndGetLastError(sqlite3_vfs *pVfs, int a, char *b){
    ++  return ORIGVFS(pVfs)->xGetLastError(ORIGVFS(pVfs), a, b);
    ++}
    ++static int apndCurrentTimeInt64(sqlite3_vfs *pVfs, sqlite3_int64 *p){
    ++  return ORIGVFS(pVfs)->xCurrentTimeInt64(ORIGVFS(pVfs), p);
    ++}
    ++static int apndSetSystemCall(
    ++  sqlite3_vfs *pVfs,
    ++  const char *zName,
    ++  sqlite3_syscall_ptr pCall
    ++){
    ++  return ORIGVFS(pVfs)->xSetSystemCall(ORIGVFS(pVfs),zName,pCall);
    ++}
    ++static sqlite3_syscall_ptr apndGetSystemCall(
    ++  sqlite3_vfs *pVfs,
    ++  const char *zName
    ++){
    ++  return ORIGVFS(pVfs)->xGetSystemCall(ORIGVFS(pVfs),zName);
    ++}
    ++static const char *apndNextSystemCall(sqlite3_vfs *pVfs, const char *zName){
    ++  return ORIGVFS(pVfs)->xNextSystemCall(ORIGVFS(pVfs), zName);
    ++}
    ++
    ++  
    ++#ifdef _WIN32
    ++
    ++#endif
    ++/* 
    ++** This routine is called when the extension is loaded.
    ++** Register the new VFS.
    ++*/
    ++int sqlite3_appendvfs_init(
    ++  sqlite3 *db, 
    ++  char **pzErrMsg, 
    ++  const sqlite3_api_routines *pApi
    ++){
    ++  int rc = SQLITE_OK;
    ++  sqlite3_vfs *pOrig;
    ++  SQLITE_EXTENSION_INIT2(pApi);
    ++  (void)pzErrMsg;
    ++  (void)db;
    ++  pOrig = sqlite3_vfs_find(0);
    ++  apnd_vfs.iVersion = pOrig->iVersion;
    ++  apnd_vfs.pAppData = pOrig;
    ++  apnd_vfs.szOsFile = pOrig->szOsFile + sizeof(ApndFile);
    ++  rc = sqlite3_vfs_register(&apnd_vfs, 0);
    ++#ifdef APPENDVFS_TEST
    ++  if( rc==SQLITE_OK ){
    ++    rc = sqlite3_auto_extension((void(*)(void))apndvfsRegister);
    ++  }
    ++#endif
    ++  if( rc==SQLITE_OK ) rc = SQLITE_OK_LOAD_PERMANENTLY;
    ++  return rc;
    ++}
    ++
    ++/************************* End ../ext/misc/appendvfs.c ********************/
    ++#ifdef SQLITE_HAVE_ZLIB
    ++/************************* Begin ../ext/misc/zipfile.c ******************/
    ++/*
    ++** 2017-12-26
    ++**
    ++** 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 implements a virtual table for reading and writing ZIP archive
    ++** files.
    ++**
    ++** Usage example:
    ++**
    ++**     SELECT name, sz, datetime(mtime,'unixepoch') FROM zipfile($filename);
    ++**
    ++** Current limitations:
    ++**
    ++**    *  No support for encryption
    ++**    *  No support for ZIP archives spanning multiple files
    ++**    *  No support for zip64 extensions
    ++**    *  Only the "inflate/deflate" (zlib) compression method is supported
    ++*/
    ++SQLITE_EXTENSION_INIT1
    ++#include <stdio.h>
    ++#include <string.h>
    ++#include <assert.h>
    ++
    ++#include <sys/types.h>
    ++#include <sys/stat.h>
    ++#include <fcntl.h>
    ++#if !defined(_WIN32) && !defined(WIN32)
    ++#  include <unistd.h>
    ++#  include <dirent.h>
    ++#  include <utime.h>
    ++#else
    ++#  include <io.h>
    ++#endif
    ++#include <time.h>
    ++#include <errno.h>
    ++
    ++#include <zlib.h>
    ++
    ++#ifndef SQLITE_OMIT_VIRTUALTABLE
    ++
    ++#ifndef SQLITE_AMALGAMATION
    ++/* typedef sqlite3_int64 i64; */
    ++/* typedef unsigned char u8; */
    ++typedef unsigned short u16;
    ++typedef unsigned long u32;
    ++#define MIN(a,b) ((a)<(b) ? (a) : (b))
    ++#endif
    ++
    ++static const char ZIPFILE_SCHEMA[] = 
    ++  "CREATE TABLE y("
    ++    "name PRIMARY KEY,"  /* 0: Name of file in zip archive */
    ++    "mode,"              /* 1: POSIX mode for file */
    ++    "mtime,"             /* 2: Last modification time (secs since 1970)*/
    ++    "sz,"                /* 3: Size of object */
    ++    "rawdata,"           /* 4: Raw data */
    ++    "data,"              /* 5: Uncompressed data */
    ++    "method,"            /* 6: Compression method (integer) */
    ++    "z HIDDEN"           /* 7: Name of zip file */
    ++  ") WITHOUT ROWID;";
    ++
    ++#define ZIPFILE_F_COLUMN_IDX 7    /* Index of column "file" in the above */
    ++#define ZIPFILE_BUFFER_SIZE (64*1024)
    ++
    ++
    ++/*
    ++** Magic numbers used to read and write zip files.
    ++**
    ++** ZIPFILE_NEWENTRY_MADEBY:
    ++**   Use this value for the "version-made-by" field in new zip file
    ++**   entries. The upper byte indicates "unix", and the lower byte 
    ++**   indicates that the zip file matches pkzip specification 3.0. 
    ++**   This is what info-zip seems to do.
    ++**
    ++** ZIPFILE_NEWENTRY_REQUIRED:
    ++**   Value for "version-required-to-extract" field of new entries.
    ++**   Version 2.0 is required to support folders and deflate compression.
    ++**
    ++** ZIPFILE_NEWENTRY_FLAGS:
    ++**   Value for "general-purpose-bit-flags" field of new entries. Bit
    ++**   11 means "utf-8 filename and comment".
    ++**
    ++** ZIPFILE_SIGNATURE_CDS:
    ++**   First 4 bytes of a valid CDS record.
    ++**
    ++** ZIPFILE_SIGNATURE_LFH:
    ++**   First 4 bytes of a valid LFH record.
    ++*/
    ++#define ZIPFILE_EXTRA_TIMESTAMP   0x5455
    ++#define ZIPFILE_NEWENTRY_MADEBY   ((3<<8) + 30)
    ++#define ZIPFILE_NEWENTRY_REQUIRED 20
    ++#define ZIPFILE_NEWENTRY_FLAGS    0x800
    ++#define ZIPFILE_SIGNATURE_CDS     0x02014b50
    ++#define ZIPFILE_SIGNATURE_LFH     0x04034b50
    ++#define ZIPFILE_SIGNATURE_EOCD    0x06054b50
    ++#define ZIPFILE_LFH_FIXED_SZ      30
    ++
    ++/*
    ++** Set the error message contained in context ctx to the results of
    ++** vprintf(zFmt, ...).
    ++*/
    ++static void zipfileCtxErrorMsg(sqlite3_context *ctx, const char *zFmt, ...){
    ++  char *zMsg = 0;
    ++  va_list ap;
    ++  va_start(ap, zFmt);
    ++  zMsg = sqlite3_vmprintf(zFmt, ap);
    ++  sqlite3_result_error(ctx, zMsg, -1);
    ++  sqlite3_free(zMsg);
    ++  va_end(ap);
    ++}
    ++
    ++
    ++/*
    ++*** 4.3.16  End of central directory record:
    ++***
    ++***   end of central dir signature    4 bytes  (0x06054b50)
    ++***   number of this disk             2 bytes
    ++***   number of the disk with the
    ++***   start of the central directory  2 bytes
    ++***   total number of entries in the
    ++***   central directory on this disk  2 bytes
    ++***   total number of entries in
    ++***   the central directory           2 bytes
    ++***   size of the central directory   4 bytes
    ++***   offset of start of central
    ++***   directory with respect to
    ++***   the starting disk number        4 bytes
    ++***   .ZIP file comment length        2 bytes
    ++***   .ZIP file comment       (variable size)
    ++*/
    ++typedef struct ZipfileEOCD ZipfileEOCD;
    ++struct ZipfileEOCD {
    ++  u16 iDisk;
    ++  u16 iFirstDisk;
    ++  u16 nEntry;
    ++  u16 nEntryTotal;
    ++  u32 nSize;
    ++  u32 iOffset;
    ++};
    ++
    ++/*
    ++*** 4.3.12  Central directory structure:
    ++***
    ++*** ...
    ++***
    ++***   central file header signature   4 bytes  (0x02014b50)
    ++***   version made by                 2 bytes
    ++***   version needed to extract       2 bytes
    ++***   general purpose bit flag        2 bytes
    ++***   compression method              2 bytes
    ++***   last mod file time              2 bytes
    ++***   last mod file date              2 bytes
    ++***   crc-32                          4 bytes
    ++***   compressed size                 4 bytes
    ++***   uncompressed size               4 bytes
    ++***   file name length                2 bytes
    ++***   extra field length              2 bytes
    ++***   file comment length             2 bytes
    ++***   disk number start               2 bytes
    ++***   internal file attributes        2 bytes
    ++***   external file attributes        4 bytes
    ++***   relative offset of local header 4 bytes
    ++*/
    ++typedef struct ZipfileCDS ZipfileCDS;
    ++struct ZipfileCDS {
    ++  u16 iVersionMadeBy;
    ++  u16 iVersionExtract;
    ++  u16 flags;
    ++  u16 iCompression;
    ++  u16 mTime;
    ++  u16 mDate;
    ++  u32 crc32;
    ++  u32 szCompressed;
    ++  u32 szUncompressed;
    ++  u16 nFile;
    ++  u16 nExtra;
    ++  u16 nComment;
    ++  u16 iDiskStart;
    ++  u16 iInternalAttr;
    ++  u32 iExternalAttr;
    ++  u32 iOffset;
    ++  char *zFile;                    /* Filename (sqlite3_malloc()) */
    ++};
    ++
    ++/*
    ++*** 4.3.7  Local file header:
    ++***
    ++***   local file header signature     4 bytes  (0x04034b50)
    ++***   version needed to extract       2 bytes
    ++***   general purpose bit flag        2 bytes
    ++***   compression method              2 bytes
    ++***   last mod file time              2 bytes
    ++***   last mod file date              2 bytes
    ++***   crc-32                          4 bytes
    ++***   compressed size                 4 bytes
    ++***   uncompressed size               4 bytes
    ++***   file name length                2 bytes
    ++***   extra field length              2 bytes
    ++***   
    ++*/
    ++typedef struct ZipfileLFH ZipfileLFH;
    ++struct ZipfileLFH {
    ++  u16 iVersionExtract;
    ++  u16 flags;
    ++  u16 iCompression;
    ++  u16 mTime;
    ++  u16 mDate;
    ++  u32 crc32;
    ++  u32 szCompressed;
    ++  u32 szUncompressed;
    ++  u16 nFile;
    ++  u16 nExtra;
    ++};
    ++
    ++typedef struct ZipfileEntry ZipfileEntry;
    ++struct ZipfileEntry {
    ++  char *zPath;               /* Path of zipfile entry */
    ++  u8 *aCdsEntry;             /* Buffer containing entire CDS entry */
    ++  int nCdsEntry;             /* Size of buffer aCdsEntry[] in bytes */
    ++  int bDeleted;              /* True if entry has been deleted */
    ++  ZipfileEntry *pNext;       /* Next element in in-memory CDS */
    ++};
    ++
    ++/* 
    ++** Cursor type for recursively iterating through a directory structure.
    ++*/
    ++typedef struct ZipfileCsr ZipfileCsr;
    ++struct ZipfileCsr {
    ++  sqlite3_vtab_cursor base;  /* Base class - must be first */
    ++  i64 iId;                   /* Cursor ID */
    ++  int bEof;                  /* True when at EOF */
    ++
    ++  /* Used outside of write transactions */
    ++  FILE *pFile;               /* Zip file */
    ++  i64 iNextOff;              /* Offset of next record in central directory */
    ++  ZipfileEOCD eocd;          /* Parse of central directory record */
    ++
    ++  /* Used inside write transactions */
    ++  ZipfileEntry *pCurrent;
    ++
    ++  ZipfileCDS cds;            /* Central Directory Structure */
    ++  ZipfileLFH lfh;            /* Local File Header for current entry */
    ++  i64 iDataOff;              /* Offset in zipfile to data */
    ++  u32 mTime;                 /* Extended mtime value */
    ++  int flags;                 /* Flags byte (see below for bits) */
    ++  ZipfileCsr *pCsrNext;      /* Next cursor on same virtual table */
    ++};
    ++
    ++/*
    ++** Values for ZipfileCsr.flags.
    ++*/
    ++#define ZIPFILE_MTIME_VALID 0x0001
    ++
    ++typedef struct ZipfileTab ZipfileTab;
    ++struct ZipfileTab {
    ++  sqlite3_vtab base;         /* Base class - must be first */
    ++  char *zFile;               /* Zip file this table accesses (may be NULL) */
    ++  u8 *aBuffer;               /* Temporary buffer used for various tasks */
    ++
    ++  ZipfileCsr *pCsrList;      /* List of cursors */
    ++  i64 iNextCsrid;
    ++
    ++  /* The following are used by write transactions only */
    ++  ZipfileEntry *pFirstEntry; /* Linked list of all files (if pWriteFd!=0) */
    ++  ZipfileEntry *pLastEntry;  /* Last element in pFirstEntry list */
    ++  FILE *pWriteFd;            /* File handle open on zip archive */
    ++  i64 szCurrent;             /* Current size of zip archive */
    ++  i64 szOrig;                /* Size of archive at start of transaction */
    ++};
    ++
    ++static void zipfileDequote(char *zIn){
    ++  char q = zIn[0];
    ++  if( q=='"' || q=='\'' || q=='`' || q=='[' ){
    ++    char c;
    ++    int iIn = 1;
    ++    int iOut = 0;
    ++    if( q=='[' ) q = ']';
    ++    while( (c = zIn[iIn++]) ){
    ++      if( c==q ){
    ++        if( zIn[iIn++]!=q ) break;
    ++      }
    ++      zIn[iOut++] = c;
    ++    }
    ++    zIn[iOut] = '\0';
    ++  }
    ++}
    ++
    ++/*
    ++** Construct a new ZipfileTab virtual table object.
    ++** 
    ++**   argv[0]   -> module name  ("zipfile")
    ++**   argv[1]   -> database name
    ++**   argv[2]   -> table name
    ++**   argv[...] -> "column name" and other module argument fields.
    ++*/
    ++static int zipfileConnect(
    ++  sqlite3 *db,
    ++  void *pAux,
    ++  int argc, const char *const*argv,
    ++  sqlite3_vtab **ppVtab,
    ++  char **pzErr
    ++){
    ++  int nByte = sizeof(ZipfileTab) + ZIPFILE_BUFFER_SIZE;
    ++  int nFile = 0;
    ++  const char *zFile = 0;
    ++  ZipfileTab *pNew = 0;
    ++  int rc;
    ++
    ++  if( argc>3 ){
    ++    zFile = argv[3];
    ++    nFile = (int)strlen(zFile)+1;
    ++  }
    ++
    ++  rc = sqlite3_declare_vtab(db, ZIPFILE_SCHEMA);
    ++  if( rc==SQLITE_OK ){
    ++    pNew = (ZipfileTab*)sqlite3_malloc(nByte+nFile);
    ++    if( pNew==0 ) return SQLITE_NOMEM;
    ++    memset(pNew, 0, nByte+nFile);
    ++    pNew->aBuffer = (u8*)&pNew[1];
    ++    if( zFile ){
    ++      pNew->zFile = (char*)&pNew->aBuffer[ZIPFILE_BUFFER_SIZE];
    ++      memcpy(pNew->zFile, zFile, nFile);
    ++      zipfileDequote(pNew->zFile);
    ++    }
    ++  }
    ++  *ppVtab = (sqlite3_vtab*)pNew;
    ++  return rc;
    ++}
    ++
    ++/*
    ++** This method is the destructor for zipfile vtab objects.
    ++*/
    ++static int zipfileDisconnect(sqlite3_vtab *pVtab){
    ++  sqlite3_free(pVtab);
    ++  return SQLITE_OK;
    ++}
    ++
    ++/*
    ++** Constructor for a new ZipfileCsr object.
    ++*/
    ++static int zipfileOpen(sqlite3_vtab *p, sqlite3_vtab_cursor **ppCsr){
    ++  ZipfileTab *pTab = (ZipfileTab*)p;
    ++  ZipfileCsr *pCsr;
    ++  pCsr = sqlite3_malloc(sizeof(*pCsr));
    ++  *ppCsr = (sqlite3_vtab_cursor*)pCsr;
    ++  if( pCsr==0 ){
    ++    return SQLITE_NOMEM;
    ++  }
    ++  memset(pCsr, 0, sizeof(*pCsr));
    ++  pCsr->iId = ++pTab->iNextCsrid;
    ++  pCsr->pCsrNext = pTab->pCsrList;
    ++  pTab->pCsrList = pCsr;
    ++  return SQLITE_OK;
    ++}
    ++
    ++/*
    ++** Reset a cursor back to the state it was in when first returned
    ++** by zipfileOpen().
    ++*/
    ++static void zipfileResetCursor(ZipfileCsr *pCsr){
    ++  sqlite3_free(pCsr->cds.zFile);
    ++  pCsr->cds.zFile = 0;
    ++  pCsr->bEof = 0;
    ++  if( pCsr->pFile ){
    ++    fclose(pCsr->pFile);
    ++    pCsr->pFile = 0;
    ++  }
    ++}
    ++
    ++/*
    ++** Destructor for an ZipfileCsr.
    ++*/
    ++static int zipfileClose(sqlite3_vtab_cursor *cur){
    ++  ZipfileCsr *pCsr = (ZipfileCsr*)cur;
    ++  ZipfileTab *pTab = (ZipfileTab*)(pCsr->base.pVtab);
    ++  ZipfileCsr **pp;
    ++  zipfileResetCursor(pCsr);
    ++
    ++  /* Remove this cursor from the ZipfileTab.pCsrList list. */
    ++  for(pp=&pTab->pCsrList; *pp; pp=&((*pp)->pCsrNext)){
    ++    if( *pp==pCsr ){ 
    ++      *pp = pCsr->pCsrNext;
    ++      break;
    ++    }
    ++  }
    ++
    ++  sqlite3_free(pCsr);
    ++  return SQLITE_OK;
    ++}
    ++
    ++/*
    ++** Set the error message for the virtual table associated with cursor
    ++** pCsr to the results of vprintf(zFmt, ...).
    ++*/
    ++static void zipfileSetErrmsg(ZipfileCsr *pCsr, const char *zFmt, ...){
    ++  va_list ap;
    ++  va_start(ap, zFmt);
    ++  pCsr->base.pVtab->zErrMsg = sqlite3_vmprintf(zFmt, ap);
    ++  va_end(ap);
    ++}
    ++
    ++static int zipfileReadData(
    ++  FILE *pFile,                    /* Read from this file */
    ++  u8 *aRead,                      /* Read into this buffer */
    ++  int nRead,                      /* Number of bytes to read */
    ++  i64 iOff,                       /* Offset to read from */
    ++  char **pzErrmsg                 /* OUT: Error message (from sqlite3_malloc) */
    ++){
    ++  size_t n;
    ++  fseek(pFile, (long)iOff, SEEK_SET);
    ++  n = fread(aRead, 1, nRead, pFile);
    ++  if( (int)n!=nRead ){
    ++    *pzErrmsg = sqlite3_mprintf("error in fread()");
    ++    return SQLITE_ERROR;
    ++  }
    ++  return SQLITE_OK;
    ++}
    ++
    ++static int zipfileAppendData(
    ++  ZipfileTab *pTab,
    ++  const u8 *aWrite,
    ++  int nWrite
    ++){
    ++  size_t n;
    ++  fseek(pTab->pWriteFd, (long)pTab->szCurrent, SEEK_SET);
    ++  n = fwrite(aWrite, 1, nWrite, pTab->pWriteFd);
    ++  if( (int)n!=nWrite ){
    ++    pTab->base.zErrMsg = sqlite3_mprintf("error in fwrite()");
    ++    return SQLITE_ERROR;
    ++  }
    ++  pTab->szCurrent += nWrite;
    ++  return SQLITE_OK;
    ++}
    ++
    ++static u16 zipfileGetU16(const u8 *aBuf){
    ++  return (aBuf[1] << 8) + aBuf[0];
    ++}
    ++static u32 zipfileGetU32(const u8 *aBuf){
    ++  return ((u32)(aBuf[3]) << 24)
    ++       + ((u32)(aBuf[2]) << 16)
    ++       + ((u32)(aBuf[1]) <<  8)
    ++       + ((u32)(aBuf[0]) <<  0);
    ++}
    ++
    ++static void zipfilePutU16(u8 *aBuf, u16 val){
    ++  aBuf[0] = val & 0xFF;
    ++  aBuf[1] = (val>>8) & 0xFF;
    ++}
    ++static void zipfilePutU32(u8 *aBuf, u32 val){
    ++  aBuf[0] = val & 0xFF;
    ++  aBuf[1] = (val>>8) & 0xFF;
    ++  aBuf[2] = (val>>16) & 0xFF;
    ++  aBuf[3] = (val>>24) & 0xFF;
    ++}
    ++
    ++#define zipfileRead32(aBuf) ( aBuf+=4, zipfileGetU32(aBuf-4) )
    ++#define zipfileRead16(aBuf) ( aBuf+=2, zipfileGetU16(aBuf-2) )
    ++
    ++#define zipfileWrite32(aBuf,val) { zipfilePutU32(aBuf,val); aBuf+=4; }
    ++#define zipfileWrite16(aBuf,val) { zipfilePutU16(aBuf,val); aBuf+=2; }
    ++
    ++static u8* zipfileCsrBuffer(ZipfileCsr *pCsr){
    ++  return ((ZipfileTab*)(pCsr->base.pVtab))->aBuffer;
    ++}
    ++
    ++/*
    ++** Magic numbers used to read CDS records.
    ++*/
    ++#define ZIPFILE_CDS_FIXED_SZ         46
    ++#define ZIPFILE_CDS_NFILE_OFF        28
    ++
    ++/*
    ++** Decode the CDS record in buffer aBuf into (*pCDS). Return SQLITE_ERROR
    ++** if the record is not well-formed, or SQLITE_OK otherwise.
    ++*/
    ++static int zipfileReadCDS(u8 *aBuf, ZipfileCDS *pCDS){
    ++  u8 *aRead = aBuf;
    ++  u32 sig = zipfileRead32(aRead);
    ++  int rc = SQLITE_OK;
    ++  if( sig!=ZIPFILE_SIGNATURE_CDS ){
    ++    rc = SQLITE_ERROR;
    ++  }else{
    ++    pCDS->iVersionMadeBy = zipfileRead16(aRead);
    ++    pCDS->iVersionExtract = zipfileRead16(aRead);
    ++    pCDS->flags = zipfileRead16(aRead);
    ++    pCDS->iCompression = zipfileRead16(aRead);
    ++    pCDS->mTime = zipfileRead16(aRead);
    ++    pCDS->mDate = zipfileRead16(aRead);
    ++    pCDS->crc32 = zipfileRead32(aRead);
    ++    pCDS->szCompressed = zipfileRead32(aRead);
    ++    pCDS->szUncompressed = zipfileRead32(aRead);
    ++    assert( aRead==&aBuf[ZIPFILE_CDS_NFILE_OFF] );
    ++    pCDS->nFile = zipfileRead16(aRead);
    ++    pCDS->nExtra = zipfileRead16(aRead);
    ++    pCDS->nComment = zipfileRead16(aRead);
    ++    pCDS->iDiskStart = zipfileRead16(aRead);
    ++    pCDS->iInternalAttr = zipfileRead16(aRead);
    ++    pCDS->iExternalAttr = zipfileRead32(aRead);
    ++    pCDS->iOffset = zipfileRead32(aRead);
    ++    assert( aRead==&aBuf[ZIPFILE_CDS_FIXED_SZ] );
    ++  }
    ++
    ++  return rc;
    ++}
    ++
    ++/*
    ++** Read the CDS record for the current entry from disk into pCsr->cds.
    ++*/
    ++static int zipfileCsrReadCDS(ZipfileCsr *pCsr){
    ++  char **pzErr = &pCsr->base.pVtab->zErrMsg;
    ++  u8 *aRead;
    ++  int rc = SQLITE_OK;
    ++
    ++  sqlite3_free(pCsr->cds.zFile);
    ++  pCsr->cds.zFile = 0;
    ++
    ++  if( pCsr->pCurrent==0 ){
    ++    aRead = zipfileCsrBuffer(pCsr);
    ++    rc = zipfileReadData(
    ++        pCsr->pFile, aRead, ZIPFILE_CDS_FIXED_SZ, pCsr->iNextOff, pzErr
    ++    );
    ++  }else{
    ++    aRead = pCsr->pCurrent->aCdsEntry;
    ++  }
    ++
    ++  if( rc==SQLITE_OK ){
    ++    rc = zipfileReadCDS(aRead, &pCsr->cds);
    ++    if( rc!=SQLITE_OK ){
    ++      assert( pCsr->pCurrent==0 );
    ++      zipfileSetErrmsg(pCsr,"failed to read CDS at offset %lld",pCsr->iNextOff);
    ++    }else{
    ++      int nRead;
    ++      if( pCsr->pCurrent==0 ){
    ++        nRead = pCsr->cds.nFile + pCsr->cds.nExtra;
    ++        aRead = zipfileCsrBuffer(pCsr);
    ++        pCsr->iNextOff += ZIPFILE_CDS_FIXED_SZ;
    ++        rc = zipfileReadData(pCsr->pFile, aRead, nRead, pCsr->iNextOff, pzErr);
    ++      }else{
    ++        aRead = &aRead[ZIPFILE_CDS_FIXED_SZ];
    ++      }
    ++
    ++      if( rc==SQLITE_OK ){
    ++        pCsr->cds.zFile = sqlite3_mprintf("%.*s", (int)pCsr->cds.nFile, aRead);
    ++        pCsr->iNextOff += pCsr->cds.nFile;
    ++        pCsr->iNextOff += pCsr->cds.nExtra;
    ++        pCsr->iNextOff += pCsr->cds.nComment;
    ++      }
    ++
    ++      /* Scan the cds.nExtra bytes of "extra" fields for any that can
    ++      ** be interpreted. The general format of an extra field is:
    ++      **
    ++      **   Header ID    2 bytes
    ++      **   Data Size    2 bytes
    ++      **   Data         N bytes
    ++      **
    ++      */
    ++      if( rc==SQLITE_OK ){
    ++        u8 *p = &aRead[pCsr->cds.nFile];
    ++        u8 *pEnd = &p[pCsr->cds.nExtra];
    ++
    ++        while( p<pEnd ){
    ++          u16 id = zipfileRead16(p);
    ++          u16 nByte = zipfileRead16(p);
    ++
    ++          switch( id ){
    ++            case ZIPFILE_EXTRA_TIMESTAMP: {
    ++              u8 b = p[0];
    ++              if( b & 0x01 ){     /* 0x01 -> modtime is present */
    ++                pCsr->mTime = zipfileGetU32(&p[1]);
    ++                pCsr->flags |= ZIPFILE_MTIME_VALID;
    ++              }
    ++              break;
    ++            }
    ++          }
    ++
    ++          p += nByte;
    ++        }
    ++      }
    ++    }
    ++  }
    ++
    ++  return rc;
    ++}
    ++
    ++static FILE *zipfileGetFd(ZipfileCsr *pCsr){
    ++  if( pCsr->pFile ) return pCsr->pFile;
    ++  return ((ZipfileTab*)(pCsr->base.pVtab))->pWriteFd;
    ++}
    ++
    ++static int zipfileReadLFH(
    ++  FILE *pFd, 
    ++  i64 iOffset,
    ++  u8 *aTmp, 
    ++  ZipfileLFH *pLFH, 
    ++  char **pzErr
    ++){
    ++  u8 *aRead = aTmp;
    ++  static const int szFix = ZIPFILE_LFH_FIXED_SZ;
    ++  int rc;
    ++
    ++  rc = zipfileReadData(pFd, aRead, szFix, iOffset, pzErr);
    ++  if( rc==SQLITE_OK ){
    ++    u32 sig = zipfileRead32(aRead);
    ++    if( sig!=ZIPFILE_SIGNATURE_LFH ){
    ++      *pzErr = sqlite3_mprintf("failed to read LFH at offset %d", (int)iOffset);
    ++      rc = SQLITE_ERROR;
    ++    }else{
    ++      pLFH->iVersionExtract = zipfileRead16(aRead);
    ++      pLFH->flags = zipfileRead16(aRead);
    ++      pLFH->iCompression = zipfileRead16(aRead);
    ++      pLFH->mTime = zipfileRead16(aRead);
    ++      pLFH->mDate = zipfileRead16(aRead);
    ++      pLFH->crc32 = zipfileRead32(aRead);
    ++      pLFH->szCompressed = zipfileRead32(aRead);
    ++      pLFH->szUncompressed = zipfileRead32(aRead);
    ++      pLFH->nFile = zipfileRead16(aRead);
    ++      pLFH->nExtra = zipfileRead16(aRead);
    ++      assert( aRead==&aTmp[szFix] );
    ++    }
    ++  }
    ++  return rc;
    ++}
    ++
    ++static int zipfileCsrReadLFH(ZipfileCsr *pCsr){
    ++  FILE *pFile = zipfileGetFd(pCsr);
    ++  char **pzErr = &pCsr->base.pVtab->zErrMsg;
    ++  u8 *aRead = zipfileCsrBuffer(pCsr);
    ++  int rc = zipfileReadLFH(pFile, pCsr->cds.iOffset, aRead, &pCsr->lfh, pzErr);
    ++  pCsr->iDataOff =  pCsr->cds.iOffset + ZIPFILE_LFH_FIXED_SZ;
    ++  pCsr->iDataOff += pCsr->lfh.nFile+pCsr->lfh.nExtra;
    ++  return rc;
    ++}
    ++
    ++
    ++/*
    ++** Advance an ZipfileCsr to its next row of output.
    ++*/
    ++static int zipfileNext(sqlite3_vtab_cursor *cur){
    ++  ZipfileCsr *pCsr = (ZipfileCsr*)cur;
    ++  int rc = SQLITE_OK;
    ++  pCsr->flags = 0;
    ++
    ++  if( pCsr->pCurrent==0 ){
    ++    i64 iEof = pCsr->eocd.iOffset + pCsr->eocd.nSize;
    ++    if( pCsr->iNextOff>=iEof ){
    ++      pCsr->bEof = 1;
    ++    }
    ++  }else{
    ++    assert( pCsr->pFile==0 );
    ++    do {
    ++      pCsr->pCurrent = pCsr->pCurrent->pNext;
    ++    }while( pCsr->pCurrent && pCsr->pCurrent->bDeleted );
    ++    if( pCsr->pCurrent==0 ){
    ++      pCsr->bEof = 1;
    ++    }
    ++  }
    ++
    ++  if( pCsr->bEof==0 ){
    ++    rc = zipfileCsrReadCDS(pCsr);
    ++    if( rc==SQLITE_OK ){
    ++      rc = zipfileCsrReadLFH(pCsr);
    ++    }
    ++  }
    ++
    ++  return rc;
    ++}
    ++
    ++/*
    ++** "Standard" MS-DOS time format:
    ++**
    ++**   File modification time:
    ++**     Bits 00-04: seconds divided by 2
    ++**     Bits 05-10: minute
    ++**     Bits 11-15: hour
    ++**   File modification date:
    ++**     Bits 00-04: day
    ++**     Bits 05-08: month (1-12)
    ++**     Bits 09-15: years from 1980 
    ++*/
    ++static time_t zipfileMtime(ZipfileCsr *pCsr){
    ++  struct tm t;
    ++  memset(&t, 0, sizeof(t));
    ++  t.tm_sec = (pCsr->cds.mTime & 0x1F)*2;
    ++  t.tm_min = (pCsr->cds.mTime >> 5) & 0x2F;
    ++  t.tm_hour = (pCsr->cds.mTime >> 11) & 0x1F;
    ++
    ++  t.tm_mday = (pCsr->cds.mDate & 0x1F);
    ++  t.tm_mon = ((pCsr->cds.mDate >> 5) & 0x0F) - 1;
    ++  t.tm_year = 80 + ((pCsr->cds.mDate >> 9) & 0x7F);
    ++
    ++  return mktime(&t);
    ++}
    ++
    ++static void zipfileMtimeToDos(ZipfileCDS *pCds, u32 mTime){
    ++  time_t t = (time_t)mTime;
    ++  struct tm res;
    ++
    ++#if !defined(_WIN32) && !defined(WIN32)
    ++  localtime_r(&t, &res);
    ++#else
    ++  memcpy(&res, localtime(&t), sizeof(struct tm));
    ++#endif
    ++
    ++  pCds->mTime = (u16)(
    ++    (res.tm_sec / 2) + 
    ++    (res.tm_min << 5) +
    ++    (res.tm_hour << 11));
    ++
    ++  pCds->mDate = (u16)(
    ++    (res.tm_mday-1) +
    ++    ((res.tm_mon+1) << 5) +
    ++    ((res.tm_year-80) << 9));
    ++}
    ++
    ++static void zipfileInflate(
    ++  sqlite3_context *pCtx,          /* Store error here, if any */
    ++  const u8 *aIn,                  /* Compressed data */
    ++  int nIn,                        /* Size of buffer aIn[] in bytes */
    ++  int nOut                        /* Expected output size */
    ++){
    ++  u8 *aRes = sqlite3_malloc(nOut);
    ++  if( aRes==0 ){
    ++    sqlite3_result_error_nomem(pCtx);
    ++  }else{
    ++    int err;
    ++    z_stream str;
    ++    memset(&str, 0, sizeof(str));
    ++
    ++    str.next_in = (Byte*)aIn;
    ++    str.avail_in = nIn;
    ++    str.next_out = (Byte*)aRes;
    ++    str.avail_out = nOut;
    ++
    ++    err = inflateInit2(&str, -15);
    ++    if( err!=Z_OK ){
    ++      zipfileCtxErrorMsg(pCtx, "inflateInit2() failed (%d)", err);
    ++    }else{
    ++      err = inflate(&str, Z_NO_FLUSH);
    ++      if( err!=Z_STREAM_END ){
    ++        zipfileCtxErrorMsg(pCtx, "inflate() failed (%d)", err);
    ++      }else{
    ++        sqlite3_result_blob(pCtx, aRes, nOut, SQLITE_TRANSIENT);
    ++      }
    ++    }
    ++    sqlite3_free(aRes);
    ++    inflateEnd(&str);
    ++  }
    ++}
    ++
    ++static int zipfileDeflate(
    ++  ZipfileTab *pTab,               /* Set error message here */
    ++  const u8 *aIn, int nIn,         /* Input */
    ++  u8 **ppOut, int *pnOut          /* Output */
    ++){
    ++  int nAlloc = (int)compressBound(nIn);
    ++  u8 *aOut;
    ++  int rc = SQLITE_OK;
    ++
    ++  aOut = (u8*)sqlite3_malloc(nAlloc);
    ++  if( aOut==0 ){
    ++    rc = SQLITE_NOMEM;
    ++  }else{
    ++    int res;
    ++    z_stream str;
    ++    memset(&str, 0, sizeof(str));
    ++    str.next_in = (Bytef*)aIn;
    ++    str.avail_in = nIn;
    ++    str.next_out = aOut;
    ++    str.avail_out = nAlloc;
    ++
    ++    deflateInit2(&str, 9, Z_DEFLATED, -15, 8, Z_DEFAULT_STRATEGY);
    ++    res = deflate(&str, Z_FINISH);
    ++
    ++    if( res==Z_STREAM_END ){
    ++      *ppOut = aOut;
    ++      *pnOut = (int)str.total_out;
    ++    }else{
    ++      sqlite3_free(aOut);
    ++      pTab->base.zErrMsg = sqlite3_mprintf("zipfile: deflate() error");
    ++      rc = SQLITE_ERROR;
    ++    }
    ++    deflateEnd(&str);
    ++  }
    ++
    ++  return rc;
    ++}
    ++
    ++
    ++/*
    ++** Return values of columns for the row at which the series_cursor
    ++** is currently pointing.
    ++*/
    ++static int zipfileColumn(
    ++  sqlite3_vtab_cursor *cur,   /* The cursor */
    ++  sqlite3_context *ctx,       /* First argument to sqlite3_result_...() */
    ++  int i                       /* Which column to return */
    ++){
    ++  ZipfileCsr *pCsr = (ZipfileCsr*)cur;
    ++  int rc = SQLITE_OK;
    ++  switch( i ){
    ++    case 0:   /* name */
    ++      sqlite3_result_text(ctx, pCsr->cds.zFile, -1, SQLITE_TRANSIENT);
    ++      break;
    ++    case 1:   /* mode */
    ++      /* TODO: Whether or not the following is correct surely depends on
    ++      ** the platform on which the archive was created.  */
    ++      sqlite3_result_int(ctx, pCsr->cds.iExternalAttr >> 16);
    ++      break;
    ++    case 2: { /* mtime */
    ++      if( pCsr->flags & ZIPFILE_MTIME_VALID ){
    ++        sqlite3_result_int64(ctx, pCsr->mTime);
    ++      }else{
    ++        sqlite3_result_int64(ctx, zipfileMtime(pCsr));
    ++      }
    ++      break;
    ++    }
    ++    case 3: { /* sz */
    ++      if( sqlite3_vtab_nochange(ctx)==0 ){
    ++        sqlite3_result_int64(ctx, pCsr->cds.szUncompressed);
    ++      }
    ++      break;
    ++    }
    ++    case 4:   /* rawdata */
    ++      if( sqlite3_vtab_nochange(ctx) ) break;
    ++    case 5: { /* data */
    ++      if( i==4 || pCsr->cds.iCompression==0 || pCsr->cds.iCompression==8 ){
    ++        int sz = pCsr->cds.szCompressed;
    ++        int szFinal = pCsr->cds.szUncompressed;
    ++        if( szFinal>0 ){
    ++          u8 *aBuf = sqlite3_malloc(sz);
    ++          if( aBuf==0 ){
    ++            rc = SQLITE_NOMEM;
    ++          }else{
    ++            FILE *pFile = zipfileGetFd(pCsr);
    ++            rc = zipfileReadData(pFile, aBuf, sz, pCsr->iDataOff,
    ++                &pCsr->base.pVtab->zErrMsg
    ++            );
    ++          }
    ++          if( rc==SQLITE_OK ){
    ++            if( i==5 && pCsr->cds.iCompression ){
    ++              zipfileInflate(ctx, aBuf, sz, szFinal);
    ++            }else{
    ++              sqlite3_result_blob(ctx, aBuf, sz, SQLITE_TRANSIENT);
    ++            }
    ++            sqlite3_free(aBuf);
    ++          }
    ++        }else{
    ++          /* Figure out if this is a directory or a zero-sized file. Consider
    ++          ** it to be a directory either if the mode suggests so, or if
    ++          ** the final character in the name is '/'.  */
    ++          u32 mode = pCsr->cds.iExternalAttr >> 16;
    ++          if( !(mode & S_IFDIR) && pCsr->cds.zFile[pCsr->cds.nFile-1]!='/' ){
    ++            sqlite3_result_blob(ctx, "", 0, SQLITE_STATIC);
    ++          }
    ++        }
    ++      }
    ++      break;
    ++    }
    ++    case 6:   /* method */
    ++      sqlite3_result_int(ctx, pCsr->cds.iCompression);
    ++      break;
    ++    case 7:   /* z */
    ++      sqlite3_result_int64(ctx, pCsr->iId);
    ++      break;
    ++  }
    ++
    ++  return rc;
    ++}
    ++
    ++/*
    ++** Return the rowid for the current row.
    ++*/
    ++static int zipfileRowid(sqlite3_vtab_cursor *cur, sqlite_int64 *pRowid){
    ++  assert( 0 );
    ++  return SQLITE_OK;
    ++}
    ++
    ++/*
    ++** Return TRUE if the cursor has been moved off of the last
    ++** row of output.
    ++*/
    ++static int zipfileEof(sqlite3_vtab_cursor *cur){
    ++  ZipfileCsr *pCsr = (ZipfileCsr*)cur;
    ++  return pCsr->bEof;
    ++}
    ++
    ++/*
    ++*/
    ++static int zipfileReadEOCD(
    ++  ZipfileTab *pTab,               /* Return errors here */
    ++  FILE *pFile,                    /* Read from this file */
    ++  ZipfileEOCD *pEOCD              /* Object to populate */
    ++){
    ++  u8 *aRead = pTab->aBuffer;      /* Temporary buffer */
    ++  i64 szFile;                     /* Total size of file in bytes */
    ++  int nRead;                      /* Bytes to read from file */
    ++  i64 iOff;                       /* Offset to read from */
    ++  int rc;
    ++
    ++  fseek(pFile, 0, SEEK_END);
    ++  szFile = (i64)ftell(pFile);
    ++  if( szFile==0 ){
    ++    memset(pEOCD, 0, sizeof(ZipfileEOCD));
    ++    return SQLITE_OK;
    ++  }
    ++  nRead = (int)(MIN(szFile, ZIPFILE_BUFFER_SIZE));
    ++  iOff = szFile - nRead;
    ++
    ++  rc = zipfileReadData(pFile, aRead, nRead, iOff, &pTab->base.zErrMsg);
    ++  if( rc==SQLITE_OK ){
    ++    int i;
    ++
    ++    /* Scan backwards looking for the signature bytes */
    ++    for(i=nRead-20; i>=0; i--){
    ++      if( aRead[i]==0x50 && aRead[i+1]==0x4b 
    ++       && aRead[i+2]==0x05 && aRead[i+3]==0x06 
    ++      ){
    ++        break;
    ++      }
    ++    }
    ++    if( i<0 ){
    ++      pTab->base.zErrMsg = sqlite3_mprintf(
    ++          "cannot find end of central directory record"
    ++      );
    ++      return SQLITE_ERROR;
    ++    }
    ++
    ++    aRead += i+4;
    ++    pEOCD->iDisk = zipfileRead16(aRead);
    ++    pEOCD->iFirstDisk = zipfileRead16(aRead);
    ++    pEOCD->nEntry = zipfileRead16(aRead);
    ++    pEOCD->nEntryTotal = zipfileRead16(aRead);
    ++    pEOCD->nSize = zipfileRead32(aRead);
    ++    pEOCD->iOffset = zipfileRead32(aRead);
    ++
    ++#if 0
    ++    printf("iDisk=%d  iFirstDisk=%d  nEntry=%d  "
    ++           "nEntryTotal=%d  nSize=%d  iOffset=%d", 
    ++           (int)pEOCD->iDisk, (int)pEOCD->iFirstDisk, (int)pEOCD->nEntry,
    ++           (int)pEOCD->nEntryTotal, (int)pEOCD->nSize, (int)pEOCD->iOffset
    ++    );
    ++#endif
    ++  }
    ++
    ++  return SQLITE_OK;
    ++}
    ++
    ++/*
    ++** xFilter callback.
    ++*/
    ++static int zipfileFilter(
    ++  sqlite3_vtab_cursor *cur, 
    ++  int idxNum, const char *idxStr,
    ++  int argc, sqlite3_value **argv
    ++){
    ++  ZipfileTab *pTab = (ZipfileTab*)cur->pVtab;
    ++  ZipfileCsr *pCsr = (ZipfileCsr*)cur;
    ++  const char *zFile;              /* Zip file to scan */
    ++  int rc = SQLITE_OK;             /* Return Code */
    ++
    ++  zipfileResetCursor(pCsr);
    ++
    ++  if( pTab->zFile ){
    ++    zFile = pTab->zFile;
    ++  }else if( idxNum==0 ){
    ++    /* Error. This is an eponymous virtual table and the user has not 
    ++    ** supplied a file name. */
    ++    zipfileSetErrmsg(pCsr, "table function zipfile() requires an argument");
    ++    return SQLITE_ERROR;
    ++  }else{
    ++    zFile = (const char*)sqlite3_value_text(argv[0]);
    ++  }
    ++
    ++  if( pTab->pWriteFd==0 ){
    ++    pCsr->pFile = fopen(zFile, "rb");
    ++    if( pCsr->pFile==0 ){
    ++      zipfileSetErrmsg(pCsr, "cannot open file: %s", zFile);
    ++      rc = SQLITE_ERROR;
    ++    }else{
    ++      rc = zipfileReadEOCD(pTab, pCsr->pFile, &pCsr->eocd);
    ++      if( rc==SQLITE_OK ){
    ++        if( pCsr->eocd.nEntry==0 ){
    ++          pCsr->bEof = 1;
    ++        }else{
    ++          pCsr->iNextOff = pCsr->eocd.iOffset;
    ++          rc = zipfileNext(cur);
    ++        }
    ++      }
    ++    }
    ++  }else{
    ++    ZipfileEntry e;
    ++    memset(&e, 0, sizeof(e));
    ++    e.pNext = pTab->pFirstEntry;
    ++    pCsr->pCurrent = &e;
    ++    rc = zipfileNext(cur);
    ++    assert( pCsr->pCurrent!=&e );
    ++  }
    ++
    ++  return rc;
    ++}
    ++
    ++/*
    ++** xBestIndex callback.
    ++*/
    ++static int zipfileBestIndex(
    ++  sqlite3_vtab *tab,
    ++  sqlite3_index_info *pIdxInfo
    ++){
    ++  int i;
    ++
    ++  for(i=0; i<pIdxInfo->nConstraint; i++){
    ++    const struct sqlite3_index_constraint *pCons = &pIdxInfo->aConstraint[i];
    ++    if( pCons->usable==0 ) continue;
    ++    if( pCons->op!=SQLITE_INDEX_CONSTRAINT_EQ ) continue;
    ++    if( pCons->iColumn!=ZIPFILE_F_COLUMN_IDX ) continue;
    ++    break;
    ++  }
    ++
    ++  if( i<pIdxInfo->nConstraint ){
    ++    pIdxInfo->aConstraintUsage[i].argvIndex = 1;
    ++    pIdxInfo->aConstraintUsage[i].omit = 1;
    ++    pIdxInfo->estimatedCost = 1000.0;
    ++    pIdxInfo->idxNum = 1;
    ++  }else{
    ++    pIdxInfo->estimatedCost = (double)(((sqlite3_int64)1) << 50);
    ++    pIdxInfo->idxNum = 0;
    ++  }
    ++
    ++  return SQLITE_OK;
    ++}
    ++
    ++/*
    ++** Add object pNew to the end of the linked list that begins at
    ++** ZipfileTab.pFirstEntry and ends with pLastEntry.
    ++*/
    ++static void zipfileAddEntry(
    ++  ZipfileTab *pTab, 
    ++  ZipfileEntry *pBefore, 
    ++  ZipfileEntry *pNew
    ++){
    ++  assert( (pTab->pFirstEntry==0)==(pTab->pLastEntry==0) );
    ++  assert( pNew->pNext==0 );
    ++  if( pBefore==0 ){
    ++    if( pTab->pFirstEntry==0 ){
    ++      pTab->pFirstEntry = pTab->pLastEntry = pNew;
    ++    }else{
    ++      assert( pTab->pLastEntry->pNext==0 );
    ++      pTab->pLastEntry->pNext = pNew;
    ++      pTab->pLastEntry = pNew;
    ++    }
    ++  }else{
    ++    ZipfileEntry **pp;
    ++    for(pp=&pTab->pFirstEntry; *pp!=pBefore; pp=&((*pp)->pNext));
    ++    pNew->pNext = pBefore;
    ++    *pp = pNew;
    ++  }
    ++}
    ++
    ++static int zipfileLoadDirectory(ZipfileTab *pTab){
    ++  ZipfileEOCD eocd;
    ++  int rc;
    ++
    ++  rc = zipfileReadEOCD(pTab, pTab->pWriteFd, &eocd);
    ++  if( rc==SQLITE_OK && eocd.nEntry>0 ){
    ++    int i;
    ++    int iOff = 0;
    ++    u8 *aBuf = sqlite3_malloc(eocd.nSize);
    ++    if( aBuf==0 ){
    ++      rc = SQLITE_NOMEM;
    ++    }else{
    ++      rc = zipfileReadData(
    ++          pTab->pWriteFd, aBuf, eocd.nSize, eocd.iOffset, &pTab->base.zErrMsg
    ++      );
    ++    }
    ++
    ++    for(i=0; rc==SQLITE_OK && i<eocd.nEntry; i++){
    ++      u16 nFile;
    ++      u16 nExtra;
    ++      u16 nComment;
    ++      ZipfileEntry *pNew;
    ++      u8 *aRec = &aBuf[iOff];
    ++
    ++      nFile = zipfileGetU16(&aRec[ZIPFILE_CDS_NFILE_OFF]);
    ++      nExtra = zipfileGetU16(&aRec[ZIPFILE_CDS_NFILE_OFF+2]);
    ++      nComment = zipfileGetU16(&aRec[ZIPFILE_CDS_NFILE_OFF+4]);
    ++
    ++      pNew = sqlite3_malloc(
    ++          sizeof(ZipfileEntry) 
    ++        + nFile+1 
    ++        + ZIPFILE_CDS_FIXED_SZ+nFile+nExtra+nComment
    ++      );
    ++      if( pNew==0 ){
    ++        rc = SQLITE_NOMEM;
    ++      }else{
    ++        memset(pNew, 0, sizeof(ZipfileEntry));
    ++        pNew->zPath = (char*)&pNew[1];
    ++        memcpy(pNew->zPath, &aRec[ZIPFILE_CDS_FIXED_SZ], nFile);
    ++        pNew->zPath[nFile] = '\0';
    ++        pNew->aCdsEntry = (u8*)&pNew->zPath[nFile+1];
    ++        pNew->nCdsEntry = ZIPFILE_CDS_FIXED_SZ+nFile+nExtra+nComment;
    ++        memcpy(pNew->aCdsEntry, aRec, pNew->nCdsEntry);
    ++        zipfileAddEntry(pTab, 0, pNew);
    ++      }
    ++
    ++      iOff += ZIPFILE_CDS_FIXED_SZ+nFile+nExtra+nComment;
    ++    }
    ++
    ++    sqlite3_free(aBuf);
    ++  }
    ++
    ++  return rc;
    ++}
    ++
    ++static ZipfileEntry *zipfileNewEntry(
    ++  ZipfileCDS *pCds,               /* Values for fixed size part of CDS */
    ++  const char *zPath,              /* Path for new entry */
    ++  int nPath,                      /* strlen(zPath) */
    ++  u32 mTime                       /* Modification time (or 0) */
    ++){
    ++  u8 *aWrite;
    ++  ZipfileEntry *pNew;
    ++  pCds->nFile = (u16)nPath;
    ++  pCds->nExtra = mTime ? 9 : 0;
    ++  pNew = (ZipfileEntry*)sqlite3_malloc(
    ++    sizeof(ZipfileEntry) + 
    ++    nPath+1 + 
    ++    ZIPFILE_CDS_FIXED_SZ + nPath + pCds->nExtra
    ++  );
    ++
    ++  if( pNew ){
    ++    memset(pNew, 0, sizeof(ZipfileEntry));
    ++    pNew->zPath = (char*)&pNew[1];
    ++    pNew->aCdsEntry = (u8*)&pNew->zPath[nPath+1];
    ++    pNew->nCdsEntry = ZIPFILE_CDS_FIXED_SZ + nPath + pCds->nExtra;
    ++    memcpy(pNew->zPath, zPath, nPath+1);
    ++
    ++    aWrite = pNew->aCdsEntry;
    ++    zipfileWrite32(aWrite, ZIPFILE_SIGNATURE_CDS);
    ++    zipfileWrite16(aWrite, pCds->iVersionMadeBy);
    ++    zipfileWrite16(aWrite, pCds->iVersionExtract);
    ++    zipfileWrite16(aWrite, pCds->flags);
    ++    zipfileWrite16(aWrite, pCds->iCompression);
    ++    zipfileWrite16(aWrite, pCds->mTime);
    ++    zipfileWrite16(aWrite, pCds->mDate);
    ++    zipfileWrite32(aWrite, pCds->crc32);
    ++    zipfileWrite32(aWrite, pCds->szCompressed);
    ++    zipfileWrite32(aWrite, pCds->szUncompressed);
    ++    zipfileWrite16(aWrite, pCds->nFile);
    ++    zipfileWrite16(aWrite, pCds->nExtra);
    ++    zipfileWrite16(aWrite, pCds->nComment);      assert( pCds->nComment==0 );
    ++    zipfileWrite16(aWrite, pCds->iDiskStart);
    ++    zipfileWrite16(aWrite, pCds->iInternalAttr);
    ++    zipfileWrite32(aWrite, pCds->iExternalAttr);
    ++    zipfileWrite32(aWrite, pCds->iOffset);
    ++    assert( aWrite==&pNew->aCdsEntry[ZIPFILE_CDS_FIXED_SZ] );
    ++    memcpy(aWrite, zPath, nPath);
    ++    if( pCds->nExtra ){
    ++      aWrite += nPath;
    ++      zipfileWrite16(aWrite, ZIPFILE_EXTRA_TIMESTAMP);
    ++      zipfileWrite16(aWrite, 5);
    ++      *aWrite++ = 0x01;
    ++      zipfileWrite32(aWrite, mTime);
    ++    }
    ++  }
    ++
    ++  return pNew;
    ++}
    ++
    ++static int zipfileAppendEntry(
    ++  ZipfileTab *pTab,
    ++  ZipfileCDS *pCds,
    ++  const char *zPath,              /* Path for new entry */
    ++  int nPath,                      /* strlen(zPath) */
    ++  const u8 *pData,
    ++  int nData,
    ++  u32 mTime
    ++){
    ++  u8 *aBuf = pTab->aBuffer;
    ++  int rc;
    ++
    ++  zipfileWrite32(aBuf, ZIPFILE_SIGNATURE_LFH);
    ++  zipfileWrite16(aBuf, pCds->iVersionExtract);
    ++  zipfileWrite16(aBuf, pCds->flags);
    ++  zipfileWrite16(aBuf, pCds->iCompression);
    ++  zipfileWrite16(aBuf, pCds->mTime);
    ++  zipfileWrite16(aBuf, pCds->mDate);
    ++  zipfileWrite32(aBuf, pCds->crc32);
    ++  zipfileWrite32(aBuf, pCds->szCompressed);
    ++  zipfileWrite32(aBuf, pCds->szUncompressed);
    ++  zipfileWrite16(aBuf, (u16)nPath);
    ++  zipfileWrite16(aBuf, pCds->nExtra);
    ++  assert( aBuf==&pTab->aBuffer[ZIPFILE_LFH_FIXED_SZ] );
    ++  rc = zipfileAppendData(pTab, pTab->aBuffer, (int)(aBuf - pTab->aBuffer));
    ++  if( rc==SQLITE_OK ){
    ++    rc = zipfileAppendData(pTab, (const u8*)zPath, nPath);
    ++  }
    ++
    ++  if( rc==SQLITE_OK && pCds->nExtra ){
    ++    aBuf = pTab->aBuffer;
    ++    zipfileWrite16(aBuf, ZIPFILE_EXTRA_TIMESTAMP);
    ++    zipfileWrite16(aBuf, 5);
    ++    *aBuf++ = 0x01;
    ++    zipfileWrite32(aBuf, mTime);
    ++    rc = zipfileAppendData(pTab, pTab->aBuffer, 9);
    ++  }
    ++
    ++  if( rc==SQLITE_OK ){
    ++    rc = zipfileAppendData(pTab, pData, nData);
    ++  }
    ++
    ++  return rc;
    ++}
    ++
    ++static int zipfileGetMode(
    ++  ZipfileTab *pTab, 
    ++  sqlite3_value *pVal, 
    ++  u32 defaultMode,                /* Value to use if pVal IS NULL */
    ++  u32 *pMode
    ++){
    ++  const char *z = (const char*)sqlite3_value_text(pVal);
    ++  u32 mode = 0;
    ++  if( z==0 ){
    ++    mode = defaultMode;
    ++  }else if( z[0]>='0' && z[0]<='9' ){
    ++    mode = (unsigned int)sqlite3_value_int(pVal);
    ++  }else{
    ++    const char zTemplate[11] = "-rwxrwxrwx";
    ++    int i;
    ++    if( strlen(z)!=10 ) goto parse_error;
    ++    switch( z[0] ){
    ++      case '-': mode |= S_IFREG; break;
    ++      case 'd': mode |= S_IFDIR; break;
    ++#if !defined(_WIN32) && !defined(WIN32)
    ++      case 'l': mode |= S_IFLNK; break;
    ++#endif
    ++      default: goto parse_error;
    ++    }
    ++    for(i=1; i<10; i++){
    ++      if( z[i]==zTemplate[i] ) mode |= 1 << (9-i);
    ++      else if( z[i]!='-' ) goto parse_error;
    ++    }
    ++  }
    ++  *pMode = mode;
    ++  return SQLITE_OK;
    ++
    ++ parse_error:
    ++  pTab->base.zErrMsg = sqlite3_mprintf("zipfile: parse error in mode: %s", z);
    ++  return SQLITE_ERROR;
    ++}
    ++
    ++/*
    ++** Both (const char*) arguments point to nul-terminated strings. Argument
    ++** nB is the value of strlen(zB). This function returns 0 if the strings are
    ++** identical, ignoring any trailing '/' character in either path.  */
    ++static int zipfileComparePath(const char *zA, const char *zB, int nB){
    ++  int nA = (int)strlen(zA);
    ++  if( zA[nA-1]=='/' ) nA--;
    ++  if( zB[nB-1]=='/' ) nB--;
    ++  if( nA==nB && memcmp(zA, zB, nA)==0 ) return 0;
    ++  return 1;
    ++}
    ++
    ++/*
    ++** xUpdate method.
    ++*/
    ++static int zipfileUpdate(
    ++  sqlite3_vtab *pVtab, 
    ++  int nVal, 
    ++  sqlite3_value **apVal, 
    ++  sqlite_int64 *pRowid
    ++){
    ++  ZipfileTab *pTab = (ZipfileTab*)pVtab;
    ++  int rc = SQLITE_OK;             /* Return Code */
    ++  ZipfileEntry *pNew = 0;         /* New in-memory CDS entry */
    ++
    ++  u32 mode = 0;                   /* Mode for new entry */
    ++  i64 mTime = 0;                  /* Modification time for new entry */
    ++  i64 sz = 0;                     /* Uncompressed size */
    ++  const char *zPath = 0;          /* Path for new entry */
    ++  int nPath = 0;                  /* strlen(zPath) */
    ++  const u8 *pData = 0;            /* Pointer to buffer containing content */
    ++  int nData = 0;                  /* Size of pData buffer in bytes */
    ++  int iMethod = 0;                /* Compression method for new entry */
    ++  u8 *pFree = 0;                  /* Free this */
    ++  char *zFree = 0;                /* Also free this */
    ++  ZipfileCDS cds;                 /* New Central Directory Structure entry */
    ++  ZipfileEntry *pOld = 0;
    ++  int bIsDir = 0;
    ++  u32 iCrc32 = 0;
    ++
    ++  assert( pTab->zFile );
    ++  assert( pTab->pWriteFd );
    ++
    ++  if( sqlite3_value_type(apVal[0])!=SQLITE_NULL ){
    ++    const char *zDelete = (const char*)sqlite3_value_text(apVal[0]);
    ++    int nDelete = (int)strlen(zDelete);
    ++    for(pOld=pTab->pFirstEntry; 1; pOld=pOld->pNext){
    ++      if( pOld->bDeleted ) continue;
    ++      if( zipfileComparePath(pOld->zPath, zDelete, nDelete)==0 ){
    ++        pOld->bDeleted = 1;
    ++        break;
    ++      }
    ++      assert( pOld->pNext );
    ++    }
    ++    if( nVal==1 ) return SQLITE_OK;
    ++  }
    ++
    ++  /* Check that "sz" and "rawdata" are both NULL: */
    ++  if( sqlite3_value_type(apVal[5])!=SQLITE_NULL
    ++   || sqlite3_value_type(apVal[6])!=SQLITE_NULL
    ++  ){
    ++    rc = SQLITE_CONSTRAINT;
    ++  }
    ++
    ++  if( rc==SQLITE_OK ){
    ++    if( sqlite3_value_type(apVal[7])==SQLITE_NULL ){
    ++      /* data=NULL. A directory */
    ++      bIsDir = 1;
    ++    }else{
    ++      /* Value specified for "data", and possibly "method". This must be
    ++      ** a regular file or a symlink. */
    ++      const u8 *aIn = sqlite3_value_blob(apVal[7]);
    ++      int nIn = sqlite3_value_bytes(apVal[7]);
    ++      int bAuto = sqlite3_value_type(apVal[8])==SQLITE_NULL;
    ++
    ++      iMethod = sqlite3_value_int(apVal[8]);
    ++      sz = nIn;
    ++      pData = aIn;
    ++      nData = nIn;
    ++      if( iMethod!=0 && iMethod!=8 ){
    ++        rc = SQLITE_CONSTRAINT;
    ++      }else{
    ++        if( bAuto || iMethod ){
    ++          int nCmp;
    ++          rc = zipfileDeflate(pTab, aIn, nIn, &pFree, &nCmp);
    ++          if( rc==SQLITE_OK ){
    ++            if( iMethod || nCmp<nIn ){
    ++              iMethod = 8;
    ++              pData = pFree;
    ++              nData = nCmp;
    ++            }
    ++          }
    ++        }
    ++        iCrc32 = crc32(0, aIn, nIn);
    ++      }
    ++    }
    ++  }
    ++
    ++  if( rc==SQLITE_OK ){
    ++    rc = zipfileGetMode(pTab, apVal[3], 
    ++        (bIsDir ? (S_IFDIR + 0755) : (S_IFREG + 0644)), &mode
    ++    );
    ++    if( rc==SQLITE_OK && (bIsDir == ((mode & S_IFDIR)==0)) ){
    ++      /* The "mode" attribute is a directory, but data has been specified.
    ++      ** Or vice-versa - no data but "mode" is a file or symlink.  */
    ++      rc = SQLITE_CONSTRAINT;
    ++    }
    ++  }
    ++
    ++  if( rc==SQLITE_OK ){
    ++    zPath = (const char*)sqlite3_value_text(apVal[2]);
    ++    nPath = (int)strlen(zPath);
    ++    if( sqlite3_value_type(apVal[4])==SQLITE_NULL ){
    ++      mTime = (sqlite3_int64)time(0);
    ++    }else{
    ++      mTime = sqlite3_value_int64(apVal[4]);
    ++    }
    ++  }
    ++
    ++  if( rc==SQLITE_OK && bIsDir ){
    ++    /* For a directory, check that the last character in the path is a
    ++    ** '/'. This appears to be required for compatibility with info-zip
    ++    ** (the unzip command on unix). It does not create directories
    ++    ** otherwise.  */
    ++    if( zPath[nPath-1]!='/' ){
    ++      zFree = sqlite3_mprintf("%s/", zPath);
    ++      if( zFree==0 ){ rc = SQLITE_NOMEM; }
    ++      zPath = (const char*)zFree;
    ++      nPath++;
    ++    }
    ++  }
    ++
    ++  /* Check that we're not inserting a duplicate entry */
    ++  if( rc==SQLITE_OK ){
    ++    ZipfileEntry *p;
    ++    for(p=pTab->pFirstEntry; p; p=p->pNext){
    ++      if( p->bDeleted ) continue;
    ++      if( zipfileComparePath(p->zPath, zPath, nPath)==0 ){
    ++        rc = SQLITE_CONSTRAINT;
    ++        break;
    ++      }
    ++    }
    ++  }
    ++
    ++  if( rc==SQLITE_OK ){
    ++    /* Create the new CDS record. */
    ++    memset(&cds, 0, sizeof(cds));
    ++    cds.iVersionMadeBy = ZIPFILE_NEWENTRY_MADEBY;
    ++    cds.iVersionExtract = ZIPFILE_NEWENTRY_REQUIRED;
    ++    cds.flags = ZIPFILE_NEWENTRY_FLAGS;
    ++    cds.iCompression = (u16)iMethod;
    ++    zipfileMtimeToDos(&cds, (u32)mTime);
    ++    cds.crc32 = iCrc32;
    ++    cds.szCompressed = nData;
    ++    cds.szUncompressed = (u32)sz;
    ++    cds.iExternalAttr = (mode<<16);
    ++    cds.iOffset = (u32)pTab->szCurrent;
    ++    pNew = zipfileNewEntry(&cds, zPath, nPath, (u32)mTime);
    ++    if( pNew==0 ){
    ++      rc = SQLITE_NOMEM;
    ++    }else{
    ++      zipfileAddEntry(pTab, pOld, pNew);
    ++    }
    ++  }
    ++
    ++  /* Append the new header+file to the archive */
    ++  if( rc==SQLITE_OK ){
    ++    rc = zipfileAppendEntry(pTab, &cds, zPath, nPath, pData, nData, (u32)mTime);
    ++  }
    ++
    ++  if( rc!=SQLITE_OK && pOld ){
    ++    pOld->bDeleted = 0;
    ++  }
    ++  sqlite3_free(pFree);
    ++  sqlite3_free(zFree);
    ++  return rc;
    ++}
    ++
    ++static int zipfileAppendEOCD(ZipfileTab *pTab, ZipfileEOCD *p){
    ++  u8 *aBuf = pTab->aBuffer;
    ++
    ++  zipfileWrite32(aBuf, ZIPFILE_SIGNATURE_EOCD);
    ++  zipfileWrite16(aBuf, p->iDisk);
    ++  zipfileWrite16(aBuf, p->iFirstDisk);
    ++  zipfileWrite16(aBuf, p->nEntry);
    ++  zipfileWrite16(aBuf, p->nEntryTotal);
    ++  zipfileWrite32(aBuf, p->nSize);
    ++  zipfileWrite32(aBuf, p->iOffset);
    ++  zipfileWrite16(aBuf, 0);        /* Size of trailing comment in bytes*/
    ++
    ++  assert( (aBuf-pTab->aBuffer)==22 );
    ++  return zipfileAppendData(pTab, pTab->aBuffer, (int)(aBuf - pTab->aBuffer));
    ++}
    ++
    ++static void zipfileCleanupTransaction(ZipfileTab *pTab){
    ++  ZipfileEntry *pEntry;
    ++  ZipfileEntry *pNext;
    ++
    ++  for(pEntry=pTab->pFirstEntry; pEntry; pEntry=pNext){
    ++    pNext = pEntry->pNext;
    ++    sqlite3_free(pEntry);
    ++  }
    ++  pTab->pFirstEntry = 0;
    ++  pTab->pLastEntry = 0;
    ++  fclose(pTab->pWriteFd);
    ++  pTab->pWriteFd = 0;
    ++  pTab->szCurrent = 0;
    ++  pTab->szOrig = 0;
    ++}
    ++
    ++static int zipfileBegin(sqlite3_vtab *pVtab){
    ++  ZipfileTab *pTab = (ZipfileTab*)pVtab;
    ++  int rc = SQLITE_OK;
    ++
    ++  assert( pTab->pWriteFd==0 );
    ++
    ++  /* This table is only writable if a default archive path was specified 
    ++  ** as part of the CREATE VIRTUAL TABLE statement. */
    ++  if( pTab->zFile==0 ){
    ++    pTab->base.zErrMsg = sqlite3_mprintf(
    ++        "zipfile: writing requires a default archive"
    ++    );
    ++    return SQLITE_ERROR;
    ++  }
    ++
    ++  /* Open a write fd on the file. Also load the entire central directory
    ++  ** structure into memory. During the transaction any new file data is 
    ++  ** appended to the archive file, but the central directory is accumulated
    ++  ** in main-memory until the transaction is committed.  */
    ++  pTab->pWriteFd = fopen(pTab->zFile, "ab+");
    ++  if( pTab->pWriteFd==0 ){
    ++    pTab->base.zErrMsg = sqlite3_mprintf(
    ++        "zipfile: failed to open file %s for writing", pTab->zFile
    ++    );
    ++    rc = SQLITE_ERROR;
    ++  }else{
    ++    fseek(pTab->pWriteFd, 0, SEEK_END);
    ++    pTab->szCurrent = pTab->szOrig = (i64)ftell(pTab->pWriteFd);
    ++    rc = zipfileLoadDirectory(pTab);
    ++  }
    ++
    ++  if( rc!=SQLITE_OK ){
    ++    zipfileCleanupTransaction(pTab);
    ++  }
    ++
    ++  return rc;
    ++}
    ++
    ++static int zipfileCommit(sqlite3_vtab *pVtab){
    ++  ZipfileTab *pTab = (ZipfileTab*)pVtab;
    ++  int rc = SQLITE_OK;
    ++  if( pTab->pWriteFd ){
    ++    i64 iOffset = pTab->szCurrent;
    ++    ZipfileEntry *p;
    ++    ZipfileEOCD eocd;
    ++    int nEntry = 0;
    ++
    ++    /* Write out all undeleted entries */
    ++    for(p=pTab->pFirstEntry; rc==SQLITE_OK && p; p=p->pNext){
    ++      if( p->bDeleted ) continue;
    ++      rc = zipfileAppendData(pTab, p->aCdsEntry, p->nCdsEntry);
    ++      nEntry++;
    ++    }
    ++
    ++    /* Write out the EOCD record */
    ++    eocd.iDisk = 0;
    ++    eocd.iFirstDisk = 0;
    ++    eocd.nEntry = (u16)nEntry;
    ++    eocd.nEntryTotal = (u16)nEntry;
    ++    eocd.nSize = (u32)(pTab->szCurrent - iOffset);
    ++    eocd.iOffset = (u32)iOffset;
    ++    rc = zipfileAppendEOCD(pTab, &eocd);
    ++
    ++    zipfileCleanupTransaction(pTab);
    ++  }
    ++  return rc;
    ++}
    ++
    ++static int zipfileRollback(sqlite3_vtab *pVtab){
    ++  return zipfileCommit(pVtab);
    ++}
    ++
    ++static ZipfileCsr *zipfileFindCursor(ZipfileTab *pTab, i64 iId){
    ++  ZipfileCsr *pCsr;
    ++  for(pCsr=pTab->pCsrList; pCsr; pCsr=pCsr->pCsrNext){
    ++    if( iId==pCsr->iId ) break;
    ++  }
    ++  return pCsr;
    ++}
    ++
    ++static void zipfileFunctionCds(
    ++  sqlite3_context *context,
    ++  int argc,
    ++  sqlite3_value **argv
    ++){
    ++  ZipfileCsr *pCsr;
    ++  ZipfileTab *pTab = (ZipfileTab*)sqlite3_user_data(context);
    ++  assert( argc>0 );
    ++
    ++  pCsr = zipfileFindCursor(pTab, sqlite3_value_int64(argv[0]));
    ++  if( pCsr ){
    ++    ZipfileCDS *p = &pCsr->cds;
    ++    char *zRes = sqlite3_mprintf("{"
    ++        "\"version-made-by\" : %u, "
    ++        "\"version-to-extract\" : %u, "
    ++        "\"flags\" : %u, "
    ++        "\"compression\" : %u, "
    ++        "\"time\" : %u, "
    ++        "\"date\" : %u, "
    ++        "\"crc32\" : %u, "
    ++        "\"compressed-size\" : %u, "
    ++        "\"uncompressed-size\" : %u, "
    ++        "\"file-name-length\" : %u, "
    ++        "\"extra-field-length\" : %u, "
    ++        "\"file-comment-length\" : %u, "
    ++        "\"disk-number-start\" : %u, "
    ++        "\"internal-attr\" : %u, "
    ++        "\"external-attr\" : %u, "
    ++        "\"offset\" : %u }",
    ++        (u32)p->iVersionMadeBy, (u32)p->iVersionExtract,
    ++        (u32)p->flags, (u32)p->iCompression,
    ++        (u32)p->mTime, (u32)p->mDate,
    ++        (u32)p->crc32, (u32)p->szCompressed,
    ++        (u32)p->szUncompressed, (u32)p->nFile,
    ++        (u32)p->nExtra, (u32)p->nComment,
    ++        (u32)p->iDiskStart, (u32)p->iInternalAttr,
    ++        (u32)p->iExternalAttr, (u32)p->iOffset
    ++    );
    ++
    ++    if( zRes==0 ){
    ++      sqlite3_result_error_nomem(context);
    ++    }else{
    ++      sqlite3_result_text(context, zRes, -1, SQLITE_TRANSIENT);
    ++      sqlite3_free(zRes);
    ++    }
    ++  }
    ++}
    ++
    ++
    ++/*
    ++** xFindFunction method.
    ++*/
    ++static int zipfileFindFunction(
    ++  sqlite3_vtab *pVtab,            /* Virtual table handle */
    ++  int nArg,                       /* Number of SQL function arguments */
    ++  const char *zName,              /* Name of SQL function */
    ++  void (**pxFunc)(sqlite3_context*,int,sqlite3_value**), /* OUT: Result */
    ++  void **ppArg                    /* OUT: User data for *pxFunc */
    ++){
    ++  if( nArg>0 ){
    ++    if( sqlite3_stricmp("zipfile_cds", zName)==0 ){
    ++      *pxFunc = zipfileFunctionCds;
    ++      *ppArg = (void*)pVtab;
    ++      return 1;
    ++    }
    ++  }
    ++
    ++  return 0;
    ++}
    ++
    ++/*
    ++** Register the "zipfile" virtual table.
    ++*/
    ++static int zipfileRegister(sqlite3 *db){
    ++  static sqlite3_module zipfileModule = {
    ++    1,                         /* iVersion */
    ++    zipfileConnect,            /* xCreate */
    ++    zipfileConnect,            /* xConnect */
    ++    zipfileBestIndex,          /* xBestIndex */
    ++    zipfileDisconnect,         /* xDisconnect */
    ++    zipfileDisconnect,         /* xDestroy */
    ++    zipfileOpen,               /* xOpen - open a cursor */
    ++    zipfileClose,              /* xClose - close a cursor */
    ++    zipfileFilter,             /* xFilter - configure scan constraints */
    ++    zipfileNext,               /* xNext - advance a cursor */
    ++    zipfileEof,                /* xEof - check for end of scan */
    ++    zipfileColumn,             /* xColumn - read data */
    ++    zipfileRowid,              /* xRowid - read data */
    ++    zipfileUpdate,             /* xUpdate */
    ++    zipfileBegin,              /* xBegin */
    ++    0,                         /* xSync */
    ++    zipfileCommit,             /* xCommit */
    ++    zipfileRollback,           /* xRollback */
    ++    zipfileFindFunction,       /* xFindMethod */
    ++    0,                         /* xRename */
    ++  };
    ++
    ++  int rc = sqlite3_create_module(db, "zipfile"  , &zipfileModule, 0);
    ++  if( rc==SQLITE_OK ){
    ++    rc = sqlite3_overload_function(db, "zipfile_cds", -1);
    ++  }
    ++  return rc;
    ++}
    ++#else         /* SQLITE_OMIT_VIRTUALTABLE */
    ++# define zipfileRegister(x) SQLITE_OK
    ++#endif
    ++
    ++#ifdef _WIN32
    ++
    ++#endif
    ++int sqlite3_zipfile_init(
    ++  sqlite3 *db, 
    ++  char **pzErrMsg, 
    ++  const sqlite3_api_routines *pApi
    ++){
    ++  SQLITE_EXTENSION_INIT2(pApi);
    ++  (void)pzErrMsg;  /* Unused parameter */
    ++  return zipfileRegister(db);
    ++}
    ++
    ++/************************* End ../ext/misc/zipfile.c ********************/
    ++/************************* Begin ../ext/misc/sqlar.c ******************/
    ++/*
    ++** 2017-12-17
    ++**
    ++** 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.
    ++**
    ++******************************************************************************
    ++**
    ++** Utility functions sqlar_compress() and sqlar_uncompress(). Useful
    ++** for working with sqlar archives and used by the shell tool's built-in
    ++** sqlar support.
    ++*/
    ++SQLITE_EXTENSION_INIT1
    ++#include <zlib.h>
    ++
    ++/*
    ++** Implementation of the "sqlar_compress(X)" SQL function.
    ++**
    ++** If the type of X is SQLITE_BLOB, and compressing that blob using
    ++** zlib utility function compress() yields a smaller blob, return the
    ++** compressed blob. Otherwise, return a copy of X.
    ++**
    ++** SQLar uses the "zlib format" for compressed content.  The zlib format
    ++** contains a two-byte identification header and a four-byte checksum at
    ++** the end.  This is different from ZIP which uses the raw deflate format.
    ++**
    ++** Future enhancements to SQLar might add support for new compression formats.
    ++** If so, those new formats will be identified by alternative headers in the
    ++** compressed data.
    ++*/
    ++static void sqlarCompressFunc(
    ++  sqlite3_context *context,
    ++  int argc,
    ++  sqlite3_value **argv
    ++){
    ++  assert( argc==1 );
    ++  if( sqlite3_value_type(argv[0])==SQLITE_BLOB ){
    ++    const Bytef *pData = sqlite3_value_blob(argv[0]);
    ++    uLong nData = sqlite3_value_bytes(argv[0]);
    ++    uLongf nOut = compressBound(nData);
    ++    Bytef *pOut;
    ++
    ++    pOut = (Bytef*)sqlite3_malloc(nOut);
    ++    if( pOut==0 ){
    ++      sqlite3_result_error_nomem(context);
    ++      return;
    ++    }else{
    ++      if( Z_OK!=compress(pOut, &nOut, pData, nData) ){
    ++        sqlite3_result_error(context, "error in compress()", -1);
    ++      }else if( nOut<nData ){
    ++        sqlite3_result_blob(context, pOut, nOut, SQLITE_TRANSIENT);
    ++      }else{
    ++        sqlite3_result_value(context, argv[0]);
    ++      }
    ++      sqlite3_free(pOut);
    ++    }
    ++  }else{
    ++    sqlite3_result_value(context, argv[0]);
    ++  }
    ++}
    ++
    ++/*
    ++** Implementation of the "sqlar_uncompress(X,SZ)" SQL function
    ++**
    ++** Parameter SZ is interpreted as an integer. If it is less than or
    ++** equal to zero, then this function returns a copy of X. Or, if
    ++** SZ is equal to the size of X when interpreted as a blob, also
    ++** return a copy of X. Otherwise, decompress blob X using zlib
    ++** utility function uncompress() and return the results (another
    ++** blob).
    ++*/
    ++static void sqlarUncompressFunc(
    ++  sqlite3_context *context,
    ++  int argc,
    ++  sqlite3_value **argv
    ++){
    ++  uLong nData;
    ++  uLongf sz;
    ++
    ++  assert( argc==2 );
    ++  sz = sqlite3_value_int(argv[1]);
    ++
    ++  if( sz<=0 || sz==(nData = sqlite3_value_bytes(argv[0])) ){
    ++    sqlite3_result_value(context, argv[0]);
    ++  }else{
    ++    const Bytef *pData= sqlite3_value_blob(argv[0]);
    ++    Bytef *pOut = sqlite3_malloc(sz);
    ++    if( Z_OK!=uncompress(pOut, &sz, pData, nData) ){
    ++      sqlite3_result_error(context, "error in uncompress()", -1);
    ++    }else{
    ++      sqlite3_result_blob(context, pOut, sz, SQLITE_TRANSIENT);
    ++    }
    ++    sqlite3_free(pOut);
    ++  }
    ++}
    ++
    ++
    ++#ifdef _WIN32
    ++
    ++#endif
    ++int sqlite3_sqlar_init(
    ++  sqlite3 *db, 
    ++  char **pzErrMsg, 
    ++  const sqlite3_api_routines *pApi
    ++){
    ++  int rc = SQLITE_OK;
    ++  SQLITE_EXTENSION_INIT2(pApi);
    ++  (void)pzErrMsg;  /* Unused parameter */
    ++  rc = sqlite3_create_function(db, "sqlar_compress", 1, SQLITE_UTF8, 0,
    ++                               sqlarCompressFunc, 0, 0);
    ++  if( rc==SQLITE_OK ){
    ++    rc = sqlite3_create_function(db, "sqlar_uncompress", 2, SQLITE_UTF8, 0,
    ++                                 sqlarUncompressFunc, 0, 0);
    ++  }
    ++  return rc;
    ++}
    ++
    ++/************************* End ../ext/misc/sqlar.c ********************/
    ++#endif
    ++/************************* Begin ../ext/expert/sqlite3expert.h ******************/
    ++/*
    ++** 2017 April 07
    ++**
    ++** 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.
    ++**
    ++*************************************************************************
    ++*/
    ++
    ++
    ++
    ++typedef struct sqlite3expert sqlite3expert;
    ++
    ++/*
    ++** Create a new sqlite3expert object.
    ++**
    ++** If successful, a pointer to the new object is returned and (*pzErr) set
    ++** to NULL. Or, if an error occurs, NULL is returned and (*pzErr) set to
    ++** an English-language error message. In this case it is the responsibility
    ++** of the caller to eventually free the error message buffer using
    ++** sqlite3_free().
    ++*/
    ++sqlite3expert *sqlite3_expert_new(sqlite3 *db, char **pzErr);
    ++
    ++/*
    ++** Configure an sqlite3expert object.
    ++**
    ++** EXPERT_CONFIG_SAMPLE:
    ++**   By default, sqlite3_expert_analyze() generates sqlite_stat1 data for
    ++**   each candidate index. This involves scanning and sorting the entire
    ++**   contents of each user database table once for each candidate index
    ++**   associated with the table. For large databases, this can be 
    ++**   prohibitively slow. This option allows the sqlite3expert object to
    ++**   be configured so that sqlite_stat1 data is instead generated based on a
    ++**   subset of each table, or so that no sqlite_stat1 data is used at all.
    ++**
    ++**   A single integer argument is passed to this option. If the value is less
    ++**   than or equal to zero, then no sqlite_stat1 data is generated or used by
    ++**   the analysis - indexes are recommended based on the database schema only.
    ++**   Or, if the value is 100 or greater, complete sqlite_stat1 data is
    ++**   generated for each candidate index (this is the default). Finally, if the
    ++**   value falls between 0 and 100, then it represents the percentage of user
    ++**   table rows that should be considered when generating sqlite_stat1 data.
    ++**
    ++**   Examples:
    ++**
    ++**     // Do not generate any sqlite_stat1 data
    ++**     sqlite3_expert_config(pExpert, EXPERT_CONFIG_SAMPLE, 0);
    ++**
    ++**     // Generate sqlite_stat1 data based on 10% of the rows in each table.
    ++**     sqlite3_expert_config(pExpert, EXPERT_CONFIG_SAMPLE, 10);
    ++*/
    ++int sqlite3_expert_config(sqlite3expert *p, int op, ...);
    ++
    ++#define EXPERT_CONFIG_SAMPLE 1    /* int */
    ++
    ++/*
    ++** Specify zero or more SQL statements to be included in the analysis.
    ++**
    ++** Buffer zSql must contain zero or more complete SQL statements. This
    ++** function parses all statements contained in the buffer and adds them
    ++** to the internal list of statements to analyze. If successful, SQLITE_OK
    ++** is returned and (*pzErr) set to NULL. Or, if an error occurs - for example
    ++** due to a error in the SQL - an SQLite error code is returned and (*pzErr)
    ++** may be set to point to an English language error message. In this case
    ++** the caller is responsible for eventually freeing the error message buffer
    ++** using sqlite3_free().
    ++**
    ++** If an error does occur while processing one of the statements in the
    ++** buffer passed as the second argument, none of the statements in the
    ++** buffer are added to the analysis.
    ++**
    ++** This function must be called before sqlite3_expert_analyze(). If a call
    ++** to this function is made on an sqlite3expert object that has already
    ++** been passed to sqlite3_expert_analyze() SQLITE_MISUSE is returned
    ++** immediately and no statements are added to the analysis.
    ++*/
    ++int sqlite3_expert_sql(
    ++  sqlite3expert *p,               /* From a successful sqlite3_expert_new() */
    ++  const char *zSql,               /* SQL statement(s) to add */
    ++  char **pzErr                    /* OUT: Error message (if any) */
    ++);
    ++
    ++
    ++/*
    ++** This function is called after the sqlite3expert object has been configured
    ++** with all SQL statements using sqlite3_expert_sql() to actually perform
    ++** the analysis. Once this function has been called, it is not possible to
    ++** add further SQL statements to the analysis.
    ++**
    ++** If successful, SQLITE_OK is returned and (*pzErr) is set to NULL. Or, if
    ++** an error occurs, an SQLite error code is returned and (*pzErr) set to 
    ++** point to a buffer containing an English language error message. In this
    ++** case it is the responsibility of the caller to eventually free the buffer
    ++** using sqlite3_free().
    ++**
    ++** If an error does occur within this function, the sqlite3expert object
    ++** is no longer useful for any purpose. At that point it is no longer
    ++** possible to add further SQL statements to the object or to re-attempt
    ++** the analysis. The sqlite3expert object must still be freed using a call
    ++** sqlite3_expert_destroy().
    ++*/
    ++int sqlite3_expert_analyze(sqlite3expert *p, char **pzErr);
    ++
    ++/*
    ++** Return the total number of statements loaded using sqlite3_expert_sql().
    ++** The total number of SQL statements may be different from the total number
    ++** to calls to sqlite3_expert_sql().
    ++*/
    ++int sqlite3_expert_count(sqlite3expert*);
    ++
    ++/*
    ++** Return a component of the report.
    ++**
    ++** This function is called after sqlite3_expert_analyze() to extract the
    ++** results of the analysis. Each call to this function returns either a
    ++** NULL pointer or a pointer to a buffer containing a nul-terminated string.
    ++** The value passed as the third argument must be one of the EXPERT_REPORT_*
    ++** #define constants defined below.
    ++**
    ++** For some EXPERT_REPORT_* parameters, the buffer returned contains 
    ++** information relating to a specific SQL statement. In these cases that
    ++** SQL statement is identified by the value passed as the second argument.
    ++** SQL statements are numbered from 0 in the order in which they are parsed.
    ++** If an out-of-range value (less than zero or equal to or greater than the
    ++** value returned by sqlite3_expert_count()) is passed as the second argument
    ++** along with such an EXPERT_REPORT_* parameter, NULL is always returned.
    ++**
    ++** EXPERT_REPORT_SQL:
    ++**   Return the text of SQL statement iStmt.
    ++**
    ++** EXPERT_REPORT_INDEXES:
    ++**   Return a buffer containing the CREATE INDEX statements for all recommended
    ++**   indexes for statement iStmt. If there are no new recommeded indexes, NULL 
    ++**   is returned.
    ++**
    ++** EXPERT_REPORT_PLAN:
    ++**   Return a buffer containing the EXPLAIN QUERY PLAN output for SQL query
    ++**   iStmt after the proposed indexes have been added to the database schema.
    ++**
    ++** EXPERT_REPORT_CANDIDATES:
    ++**   Return a pointer to a buffer containing the CREATE INDEX statements 
    ++**   for all indexes that were tested (for all SQL statements). The iStmt
    ++**   parameter is ignored for EXPERT_REPORT_CANDIDATES calls.
    ++*/
    ++const char *sqlite3_expert_report(sqlite3expert*, int iStmt, int eReport);
    ++
    ++/*
    ++** Values for the third argument passed to sqlite3_expert_report().
    ++*/
    ++#define EXPERT_REPORT_SQL        1
    ++#define EXPERT_REPORT_INDEXES    2
    ++#define EXPERT_REPORT_PLAN       3
    ++#define EXPERT_REPORT_CANDIDATES 4
    ++
    ++/*
    ++** Free an (sqlite3expert*) handle and all associated resources. There 
    ++** should be one call to this function for each successful call to 
    ++** sqlite3-expert_new().
    ++*/
    ++void sqlite3_expert_destroy(sqlite3expert*);
    ++
    ++
    ++
    ++/************************* End ../ext/expert/sqlite3expert.h ********************/
    ++/************************* Begin ../ext/expert/sqlite3expert.c ******************/
    ++/*
    ++** 2017 April 09
    ++**
    ++** 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.
    ++**
    ++*************************************************************************
    ++*/
    ++#include <assert.h>
    ++#include <string.h>
    ++#include <stdio.h>
    ++
    ++#ifndef SQLITE_OMIT_VIRTUALTABLE 
    ++
    ++/* typedef sqlite3_int64 i64; */
    ++/* typedef sqlite3_uint64 u64; */
    ++
    ++typedef struct IdxColumn IdxColumn;
    ++typedef struct IdxConstraint IdxConstraint;
    ++typedef struct IdxScan IdxScan;
    ++typedef struct IdxStatement IdxStatement;
    ++typedef struct IdxTable IdxTable;
    ++typedef struct IdxWrite IdxWrite;
    ++
    ++#define STRLEN  (int)strlen
    ++
    ++/*
    ++** A temp table name that we assume no user database will actually use.
    ++** If this assumption proves incorrect triggers on the table with the
    ++** conflicting name will be ignored.
    ++*/
    ++#define UNIQUE_TABLE_NAME "t592690916721053953805701627921227776"
    ++
    ++/*
    ++** A single constraint. Equivalent to either "col = ?" or "col < ?" (or
    ++** any other type of single-ended range constraint on a column).
    ++**
    ++** pLink:
    ++**   Used to temporarily link IdxConstraint objects into lists while
    ++**   creating candidate indexes.
    ++*/
    ++struct IdxConstraint {
    ++  char *zColl;                    /* Collation sequence */
    ++  int bRange;                     /* True for range, false for eq */
    ++  int iCol;                       /* Constrained table column */
    ++  int bFlag;                      /* Used by idxFindCompatible() */
    ++  int bDesc;                      /* True if ORDER BY <expr> DESC */
    ++  IdxConstraint *pNext;           /* Next constraint in pEq or pRange list */
    ++  IdxConstraint *pLink;           /* See above */
    ++};
    ++
    ++/*
    ++** A single scan of a single table.
    ++*/
    ++struct IdxScan {
    ++  IdxTable *pTab;                 /* Associated table object */
    ++  int iDb;                        /* Database containing table zTable */
    ++  i64 covering;                   /* Mask of columns required for cov. index */
    ++  IdxConstraint *pOrder;          /* ORDER BY columns */
    ++  IdxConstraint *pEq;             /* List of == constraints */
    ++  IdxConstraint *pRange;          /* List of < constraints */
    ++  IdxScan *pNextScan;             /* Next IdxScan object for same analysis */
    ++};
    ++
    ++/*
    ++** Information regarding a single database table. Extracted from 
    ++** "PRAGMA table_info" by function idxGetTableInfo().
    ++*/
    ++struct IdxColumn {
    ++  char *zName;
    ++  char *zColl;
    ++  int iPk;
    ++};
    ++struct IdxTable {
    ++  int nCol;
    ++  char *zName;                    /* Table name */
    ++  IdxColumn *aCol;
    ++  IdxTable *pNext;                /* Next table in linked list of all tables */
    ++};
    ++
    ++/*
    ++** An object of the following type is created for each unique table/write-op
    ++** seen. The objects are stored in a singly-linked list beginning at
    ++** sqlite3expert.pWrite.
    ++*/
    ++struct IdxWrite {
    ++  IdxTable *pTab;
    ++  int eOp;                        /* SQLITE_UPDATE, DELETE or INSERT */
    ++  IdxWrite *pNext;
    ++};
    ++
    ++/*
    ++** Each statement being analyzed is represented by an instance of this
    ++** structure.
    ++*/
    ++struct IdxStatement {
    ++  int iId;                        /* Statement number */
    ++  char *zSql;                     /* SQL statement */
    ++  char *zIdx;                     /* Indexes */
    ++  char *zEQP;                     /* Plan */
    ++  IdxStatement *pNext;
    ++};
    ++
    ++
    ++/*
    ++** A hash table for storing strings. With space for a payload string
    ++** with each entry. Methods are:
    ++**
    ++**   idxHashInit()
    ++**   idxHashClear()
    ++**   idxHashAdd()
    ++**   idxHashSearch()
    ++*/
    ++#define IDX_HASH_SIZE 1023
    ++typedef struct IdxHashEntry IdxHashEntry;
    ++typedef struct IdxHash IdxHash;
    ++struct IdxHashEntry {
    ++  char *zKey;                     /* nul-terminated key */
    ++  char *zVal;                     /* nul-terminated value string */
    ++  char *zVal2;                    /* nul-terminated value string 2 */
    ++  IdxHashEntry *pHashNext;        /* Next entry in same hash bucket */
    ++  IdxHashEntry *pNext;            /* Next entry in hash */
    ++};
    ++struct IdxHash {
    ++  IdxHashEntry *pFirst;
    ++  IdxHashEntry *aHash[IDX_HASH_SIZE];
    ++};
    ++
    ++/*
    ++** sqlite3expert object.
    ++*/
    ++struct sqlite3expert {
    ++  int iSample;                    /* Percentage of tables to sample for stat1 */
    ++  sqlite3 *db;                    /* User database */
    ++  sqlite3 *dbm;                   /* In-memory db for this analysis */
    ++  sqlite3 *dbv;                   /* Vtab schema for this analysis */
    ++  IdxTable *pTable;               /* List of all IdxTable objects */
    ++  IdxScan *pScan;                 /* List of scan objects */
    ++  IdxWrite *pWrite;               /* List of write objects */
    ++  IdxStatement *pStatement;       /* List of IdxStatement objects */
    ++  int bRun;                       /* True once analysis has run */
    ++  char **pzErrmsg;
    ++  int rc;                         /* Error code from whereinfo hook */
    ++  IdxHash hIdx;                   /* Hash containing all candidate indexes */
    ++  char *zCandidates;              /* For EXPERT_REPORT_CANDIDATES */
    ++};
    ++
    ++
    ++/*
    ++** Allocate and return nByte bytes of zeroed memory using sqlite3_malloc(). 
    ++** If the allocation fails, set *pRc to SQLITE_NOMEM and return NULL.
    ++*/
    ++static void *idxMalloc(int *pRc, int nByte){
    ++  void *pRet;
    ++  assert( *pRc==SQLITE_OK );
    ++  assert( nByte>0 );
    ++  pRet = sqlite3_malloc(nByte);
    ++  if( pRet ){
    ++    memset(pRet, 0, nByte);
    ++  }else{
    ++    *pRc = SQLITE_NOMEM;
    ++  }
    ++  return pRet;
    ++}
    ++
    ++/*
    ++** Initialize an IdxHash hash table.
    ++*/
    ++static void idxHashInit(IdxHash *pHash){
    ++  memset(pHash, 0, sizeof(IdxHash));
    ++}
    ++
    ++/*
    ++** Reset an IdxHash hash table.
    ++*/
    ++static void idxHashClear(IdxHash *pHash){
    ++  int i;
    ++  for(i=0; i<IDX_HASH_SIZE; i++){
    ++    IdxHashEntry *pEntry;
    ++    IdxHashEntry *pNext;
    ++    for(pEntry=pHash->aHash[i]; pEntry; pEntry=pNext){
    ++      pNext = pEntry->pHashNext;
    ++      sqlite3_free(pEntry->zVal2);
    ++      sqlite3_free(pEntry);
    ++    }
    ++  }
    ++  memset(pHash, 0, sizeof(IdxHash));
    ++}
    ++
    ++/*
    ++** Return the index of the hash bucket that the string specified by the
    ++** arguments to this function belongs.
    ++*/
    ++static int idxHashString(const char *z, int n){
    ++  unsigned int ret = 0;
    ++  int i;
    ++  for(i=0; i<n; i++){
    ++    ret += (ret<<3) + (unsigned char)(z[i]);
    ++  }
    ++  return (int)(ret % IDX_HASH_SIZE);
    ++}
    ++
    ++/*
    ++** If zKey is already present in the hash table, return non-zero and do
    ++** nothing. Otherwise, add an entry with key zKey and payload string zVal to
    ++** the hash table passed as the second argument. 
    ++*/
    ++static int idxHashAdd(
    ++  int *pRc, 
    ++  IdxHash *pHash, 
    ++  const char *zKey,
    ++  const char *zVal
    ++){
    ++  int nKey = STRLEN(zKey);
    ++  int iHash = idxHashString(zKey, nKey);
    ++  int nVal = (zVal ? STRLEN(zVal) : 0);
    ++  IdxHashEntry *pEntry;
    ++  assert( iHash>=0 );
    ++  for(pEntry=pHash->aHash[iHash]; pEntry; pEntry=pEntry->pHashNext){
    ++    if( STRLEN(pEntry->zKey)==nKey && 0==memcmp(pEntry->zKey, zKey, nKey) ){
    ++      return 1;
    ++    }
    ++  }
    ++  pEntry = idxMalloc(pRc, sizeof(IdxHashEntry) + nKey+1 + nVal+1);
    ++  if( pEntry ){
    ++    pEntry->zKey = (char*)&pEntry[1];
    ++    memcpy(pEntry->zKey, zKey, nKey);
    ++    if( zVal ){
    ++      pEntry->zVal = &pEntry->zKey[nKey+1];
    ++      memcpy(pEntry->zVal, zVal, nVal);
    ++    }
    ++    pEntry->pHashNext = pHash->aHash[iHash];
    ++    pHash->aHash[iHash] = pEntry;
    ++
    ++    pEntry->pNext = pHash->pFirst;
    ++    pHash->pFirst = pEntry;
    ++  }
    ++  return 0;
    ++}
    ++
    ++/*
    ++** If zKey/nKey is present in the hash table, return a pointer to the 
    ++** hash-entry object.
    ++*/
    ++static IdxHashEntry *idxHashFind(IdxHash *pHash, const char *zKey, int nKey){
    ++  int iHash;
    ++  IdxHashEntry *pEntry;
    ++  if( nKey<0 ) nKey = STRLEN(zKey);
    ++  iHash = idxHashString(zKey, nKey);
    ++  assert( iHash>=0 );
    ++  for(pEntry=pHash->aHash[iHash]; pEntry; pEntry=pEntry->pHashNext){
    ++    if( STRLEN(pEntry->zKey)==nKey && 0==memcmp(pEntry->zKey, zKey, nKey) ){
    ++      return pEntry;
    ++    }
    ++  }
    ++  return 0;
    ++}
    ++
    ++/*
    ++** If the hash table contains an entry with a key equal to the string
    ++** passed as the final two arguments to this function, return a pointer
    ++** to the payload string. Otherwise, if zKey/nKey is not present in the
    ++** hash table, return NULL.
    ++*/
    ++static const char *idxHashSearch(IdxHash *pHash, const char *zKey, int nKey){
    ++  IdxHashEntry *pEntry = idxHashFind(pHash, zKey, nKey);
    ++  if( pEntry ) return pEntry->zVal;
    ++  return 0;
    ++}
    ++
    ++/*
    ++** Allocate and return a new IdxConstraint object. Set the IdxConstraint.zColl
    ++** variable to point to a copy of nul-terminated string zColl.
    ++*/
    ++static IdxConstraint *idxNewConstraint(int *pRc, const char *zColl){
    ++  IdxConstraint *pNew;
    ++  int nColl = STRLEN(zColl);
    ++
    ++  assert( *pRc==SQLITE_OK );
    ++  pNew = (IdxConstraint*)idxMalloc(pRc, sizeof(IdxConstraint) * nColl + 1);
    ++  if( pNew ){
    ++    pNew->zColl = (char*)&pNew[1];
    ++    memcpy(pNew->zColl, zColl, nColl+1);
    ++  }
    ++  return pNew;
    ++}
    ++
    ++/*
    ++** An error associated with database handle db has just occurred. Pass
    ++** the error message to callback function xOut.
    ++*/
    ++static void idxDatabaseError(
    ++  sqlite3 *db,                    /* Database handle */
    ++  char **pzErrmsg                 /* Write error here */
    ++){
    ++  *pzErrmsg = sqlite3_mprintf("%s", sqlite3_errmsg(db));
    ++}
    ++
    ++/*
    ++** Prepare an SQL statement.
    ++*/
    ++static int idxPrepareStmt(
    ++  sqlite3 *db,                    /* Database handle to compile against */
    ++  sqlite3_stmt **ppStmt,          /* OUT: Compiled SQL statement */
    ++  char **pzErrmsg,                /* OUT: sqlite3_malloc()ed error message */
    ++  const char *zSql                /* SQL statement to compile */
    ++){
    ++  int rc = sqlite3_prepare_v2(db, zSql, -1, ppStmt, 0);
    ++  if( rc!=SQLITE_OK ){
    ++    *ppStmt = 0;
    ++    idxDatabaseError(db, pzErrmsg);
    ++  }
    ++  return rc;
    ++}
    ++
    ++/*
    ++** Prepare an SQL statement using the results of a printf() formatting.
    ++*/
    ++static int idxPrintfPrepareStmt(
    ++  sqlite3 *db,                    /* Database handle to compile against */
    ++  sqlite3_stmt **ppStmt,          /* OUT: Compiled SQL statement */
    ++  char **pzErrmsg,                /* OUT: sqlite3_malloc()ed error message */
    ++  const char *zFmt,               /* printf() format of SQL statement */
    ++  ...                             /* Trailing printf() arguments */
    ++){
    ++  va_list ap;
    ++  int rc;
    ++  char *zSql;
    ++  va_start(ap, zFmt);
    ++  zSql = sqlite3_vmprintf(zFmt, ap);
    ++  if( zSql==0 ){
    ++    rc = SQLITE_NOMEM;
    ++  }else{
    ++    rc = idxPrepareStmt(db, ppStmt, pzErrmsg, zSql);
    ++    sqlite3_free(zSql);
    ++  }
    ++  va_end(ap);
    ++  return rc;
    ++}
    ++
    ++
    ++/*************************************************************************
    ++** Beginning of virtual table implementation.
    ++*/
    ++typedef struct ExpertVtab ExpertVtab;
    ++struct ExpertVtab {
    ++  sqlite3_vtab base;
    ++  IdxTable *pTab;
    ++  sqlite3expert *pExpert;
    ++};
    ++
    ++typedef struct ExpertCsr ExpertCsr;
    ++struct ExpertCsr {
    ++  sqlite3_vtab_cursor base;
    ++  sqlite3_stmt *pData;
    ++};
    ++
    ++static char *expertDequote(const char *zIn){
    ++  int n = STRLEN(zIn);
    ++  char *zRet = sqlite3_malloc(n);
    ++
    ++  assert( zIn[0]=='\'' );
    ++  assert( zIn[n-1]=='\'' );
    ++
    ++  if( zRet ){
    ++    int iOut = 0;
    ++    int iIn = 0;
    ++    for(iIn=1; iIn<(n-1); iIn++){
    ++      if( zIn[iIn]=='\'' ){
    ++        assert( zIn[iIn+1]=='\'' );
    ++        iIn++;
    ++      }
    ++      zRet[iOut++] = zIn[iIn];
    ++    }
    ++    zRet[iOut] = '\0';
    ++  }
    ++
    ++  return zRet;
    ++}
    ++
    ++/* 
    ++** This function is the implementation of both the xConnect and xCreate
    ++** methods of the r-tree virtual table.
    ++**
    ++**   argv[0]   -> module name
    ++**   argv[1]   -> database name
    ++**   argv[2]   -> table name
    ++**   argv[...] -> column names...
    ++*/
    ++static int expertConnect(
    ++  sqlite3 *db,
    ++  void *pAux,
    ++  int argc, const char *const*argv,
    ++  sqlite3_vtab **ppVtab,
    ++  char **pzErr
    ++){
    ++  sqlite3expert *pExpert = (sqlite3expert*)pAux;
    ++  ExpertVtab *p = 0;
    ++  int rc;
    ++
    ++  if( argc!=4 ){
    ++    *pzErr = sqlite3_mprintf("internal error!");
    ++    rc = SQLITE_ERROR;
    ++  }else{
    ++    char *zCreateTable = expertDequote(argv[3]);
    ++    if( zCreateTable ){
    ++      rc = sqlite3_declare_vtab(db, zCreateTable);
    ++      if( rc==SQLITE_OK ){
    ++        p = idxMalloc(&rc, sizeof(ExpertVtab));
    ++      }
    ++      if( rc==SQLITE_OK ){
    ++        p->pExpert = pExpert;
    ++        p->pTab = pExpert->pTable;
    ++        assert( sqlite3_stricmp(p->pTab->zName, argv[2])==0 );
    ++      }
    ++      sqlite3_free(zCreateTable);
    ++    }else{
    ++      rc = SQLITE_NOMEM;
    ++    }
    ++  }
    ++
    ++  *ppVtab = (sqlite3_vtab*)p;
    ++  return rc;
    ++}
    ++
    ++static int expertDisconnect(sqlite3_vtab *pVtab){
    ++  ExpertVtab *p = (ExpertVtab*)pVtab;
    ++  sqlite3_free(p);
    ++  return SQLITE_OK;
    ++}
    ++
    ++static int expertBestIndex(sqlite3_vtab *pVtab, sqlite3_index_info *pIdxInfo){
    ++  ExpertVtab *p = (ExpertVtab*)pVtab;
    ++  int rc = SQLITE_OK;
    ++  int n = 0;
    ++  IdxScan *pScan;
    ++  const int opmask = 
    ++    SQLITE_INDEX_CONSTRAINT_EQ | SQLITE_INDEX_CONSTRAINT_GT |
    ++    SQLITE_INDEX_CONSTRAINT_LT | SQLITE_INDEX_CONSTRAINT_GE |
    ++    SQLITE_INDEX_CONSTRAINT_LE;
    ++
    ++  pScan = idxMalloc(&rc, sizeof(IdxScan));
    ++  if( pScan ){
    ++    int i;
    ++
    ++    /* Link the new scan object into the list */
    ++    pScan->pTab = p->pTab;
    ++    pScan->pNextScan = p->pExpert->pScan;
    ++    p->pExpert->pScan = pScan;
    ++
    ++    /* Add the constraints to the IdxScan object */
    ++    for(i=0; i<pIdxInfo->nConstraint; i++){
    ++      struct sqlite3_index_constraint *pCons = &pIdxInfo->aConstraint[i];
    ++      if( pCons->usable 
    ++       && pCons->iColumn>=0 
    ++       && p->pTab->aCol[pCons->iColumn].iPk==0
    ++       && (pCons->op & opmask) 
    ++      ){
    ++        IdxConstraint *pNew;
    ++        const char *zColl = sqlite3_vtab_collation(pIdxInfo, i);
    ++        pNew = idxNewConstraint(&rc, zColl);
    ++        if( pNew ){
    ++          pNew->iCol = pCons->iColumn;
    ++          if( pCons->op==SQLITE_INDEX_CONSTRAINT_EQ ){
    ++            pNew->pNext = pScan->pEq;
    ++            pScan->pEq = pNew;
    ++          }else{
    ++            pNew->bRange = 1;
    ++            pNew->pNext = pScan->pRange;
    ++            pScan->pRange = pNew;
    ++          }
    ++        }
    ++        n++;
    ++        pIdxInfo->aConstraintUsage[i].argvIndex = n;
    ++      }
    ++    }
    ++
    ++    /* Add the ORDER BY to the IdxScan object */
    ++    for(i=pIdxInfo->nOrderBy-1; i>=0; i--){
    ++      int iCol = pIdxInfo->aOrderBy[i].iColumn;
    ++      if( iCol>=0 ){
    ++        IdxConstraint *pNew = idxNewConstraint(&rc, p->pTab->aCol[iCol].zColl);
    ++        if( pNew ){
    ++          pNew->iCol = iCol;
    ++          pNew->bDesc = pIdxInfo->aOrderBy[i].desc;
    ++          pNew->pNext = pScan->pOrder;
    ++          pNew->pLink = pScan->pOrder;
    ++          pScan->pOrder = pNew;
    ++          n++;
    ++        }
    ++      }
    ++    }
    ++  }
    ++
    ++  pIdxInfo->estimatedCost = 1000000.0 / (n+1);
    ++  return rc;
    ++}
    ++
    ++static int expertUpdate(
    ++  sqlite3_vtab *pVtab, 
    ++  int nData, 
    ++  sqlite3_value **azData, 
    ++  sqlite_int64 *pRowid
    ++){
    ++  (void)pVtab;
    ++  (void)nData;
    ++  (void)azData;
    ++  (void)pRowid;
    ++  return SQLITE_OK;
    ++}
    ++
    ++/* 
    ++** Virtual table module xOpen method.
    ++*/
    ++static int expertOpen(sqlite3_vtab *pVTab, sqlite3_vtab_cursor **ppCursor){
    ++  int rc = SQLITE_OK;
    ++  ExpertCsr *pCsr;
    ++  (void)pVTab;
    ++  pCsr = idxMalloc(&rc, sizeof(ExpertCsr));
    ++  *ppCursor = (sqlite3_vtab_cursor*)pCsr;
    ++  return rc;
    ++}
    ++
    ++/* 
    ++** Virtual table module xClose method.
    ++*/
    ++static int expertClose(sqlite3_vtab_cursor *cur){
    ++  ExpertCsr *pCsr = (ExpertCsr*)cur;
    ++  sqlite3_finalize(pCsr->pData);
    ++  sqlite3_free(pCsr);
    ++  return SQLITE_OK;
    ++}
    ++
    ++/*
    ++** Virtual table module xEof method.
    ++**
    ++** Return non-zero if the cursor does not currently point to a valid 
    ++** record (i.e if the scan has finished), or zero otherwise.
    ++*/
    ++static int expertEof(sqlite3_vtab_cursor *cur){
    ++  ExpertCsr *pCsr = (ExpertCsr*)cur;
    ++  return pCsr->pData==0;
    ++}
    ++
    ++/* 
    ++** Virtual table module xNext method.
    ++*/
    ++static int expertNext(sqlite3_vtab_cursor *cur){
    ++  ExpertCsr *pCsr = (ExpertCsr*)cur;
    ++  int rc = SQLITE_OK;
    ++
    ++  assert( pCsr->pData );
    ++  rc = sqlite3_step(pCsr->pData);
    ++  if( rc!=SQLITE_ROW ){
    ++    rc = sqlite3_finalize(pCsr->pData);
    ++    pCsr->pData = 0;
    ++  }else{
    ++    rc = SQLITE_OK;
    ++  }
    ++
    ++  return rc;
    ++}
    ++
    ++/* 
    ++** Virtual table module xRowid method.
    ++*/
    ++static int expertRowid(sqlite3_vtab_cursor *cur, sqlite_int64 *pRowid){
    ++  (void)cur;
    ++  *pRowid = 0;
    ++  return SQLITE_OK;
    ++}
    ++
    ++/* 
    ++** Virtual table module xColumn method.
    ++*/
    ++static int expertColumn(sqlite3_vtab_cursor *cur, sqlite3_context *ctx, int i){
    ++  ExpertCsr *pCsr = (ExpertCsr*)cur;
    ++  sqlite3_value *pVal;
    ++  pVal = sqlite3_column_value(pCsr->pData, i);
    ++  if( pVal ){
    ++    sqlite3_result_value(ctx, pVal);
    ++  }
    ++  return SQLITE_OK;
    ++}
    ++
    ++/* 
    ++** Virtual table module xFilter method.
    ++*/
    ++static int expertFilter(
    ++  sqlite3_vtab_cursor *cur, 
    ++  int idxNum, const char *idxStr,
    ++  int argc, sqlite3_value **argv
    ++){
    ++  ExpertCsr *pCsr = (ExpertCsr*)cur;
    ++  ExpertVtab *pVtab = (ExpertVtab*)(cur->pVtab);
    ++  sqlite3expert *pExpert = pVtab->pExpert;
    ++  int rc;
    ++
    ++  (void)idxNum;
    ++  (void)idxStr;
    ++  (void)argc;
    ++  (void)argv;
    ++  rc = sqlite3_finalize(pCsr->pData);
    ++  pCsr->pData = 0;
    ++  if( rc==SQLITE_OK ){
    ++    rc = idxPrintfPrepareStmt(pExpert->db, &pCsr->pData, &pVtab->base.zErrMsg,
    ++        "SELECT * FROM main.%Q WHERE sample()", pVtab->pTab->zName
    ++    );
    ++  }
    ++
    ++  if( rc==SQLITE_OK ){
    ++    rc = expertNext(cur);
    ++  }
    ++  return rc;
    ++}
    ++
    ++static int idxRegisterVtab(sqlite3expert *p){
    ++  static sqlite3_module expertModule = {
    ++    2,                            /* iVersion */
    ++    expertConnect,                /* xCreate - create a table */
    ++    expertConnect,                /* xConnect - connect to an existing table */
    ++    expertBestIndex,              /* xBestIndex - Determine search strategy */
    ++    expertDisconnect,             /* xDisconnect - Disconnect from a table */
    ++    expertDisconnect,             /* xDestroy - Drop a table */
    ++    expertOpen,                   /* xOpen - open a cursor */
    ++    expertClose,                  /* xClose - close a cursor */
    ++    expertFilter,                 /* xFilter - configure scan constraints */
    ++    expertNext,                   /* xNext - advance a cursor */
    ++    expertEof,                    /* xEof */
    ++    expertColumn,                 /* xColumn - read data */
    ++    expertRowid,                  /* xRowid - read data */
    ++    expertUpdate,                 /* xUpdate - write data */
    ++    0,                            /* xBegin - begin transaction */
    ++    0,                            /* xSync - sync transaction */
    ++    0,                            /* xCommit - commit transaction */
    ++    0,                            /* xRollback - rollback transaction */
    ++    0,                            /* xFindFunction - function overloading */
    ++    0,                            /* xRename - rename the table */
    ++    0,                            /* xSavepoint */
    ++    0,                            /* xRelease */
    ++    0,                            /* xRollbackTo */
    ++  };
    ++
    ++  return sqlite3_create_module(p->dbv, "expert", &expertModule, (void*)p);
    ++}
    ++/*
    ++** End of virtual table implementation.
    ++*************************************************************************/
    ++/*
    ++** Finalize SQL statement pStmt. If (*pRc) is SQLITE_OK when this function
    ++** is called, set it to the return value of sqlite3_finalize() before
    ++** returning. Otherwise, discard the sqlite3_finalize() return value.
    ++*/
    ++static void idxFinalize(int *pRc, sqlite3_stmt *pStmt){
    ++  int rc = sqlite3_finalize(pStmt);
    ++  if( *pRc==SQLITE_OK ) *pRc = rc;
    ++}
    ++
    ++/*
    ++** Attempt to allocate an IdxTable structure corresponding to table zTab
    ++** in the main database of connection db. If successful, set (*ppOut) to
    ++** point to the new object and return SQLITE_OK. Otherwise, return an
    ++** SQLite error code and set (*ppOut) to NULL. In this case *pzErrmsg may be
    ++** set to point to an error string.
    ++**
    ++** It is the responsibility of the caller to eventually free either the
    ++** IdxTable object or error message using sqlite3_free().
    ++*/
    ++static int idxGetTableInfo(
    ++  sqlite3 *db,                    /* Database connection to read details from */
    ++  const char *zTab,               /* Table name */
    ++  IdxTable **ppOut,               /* OUT: New object (if successful) */
    ++  char **pzErrmsg                 /* OUT: Error message (if not) */
    ++){
    ++  sqlite3_stmt *p1 = 0;
    ++  int nCol = 0;
    ++  int nTab = STRLEN(zTab);
    ++  int nByte = sizeof(IdxTable) + nTab + 1;
    ++  IdxTable *pNew = 0;
    ++  int rc, rc2;
    ++  char *pCsr = 0;
    ++
    ++  rc = idxPrintfPrepareStmt(db, &p1, pzErrmsg, "PRAGMA table_info=%Q", zTab);
    ++  while( rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(p1) ){
    ++    const char *zCol = (const char*)sqlite3_column_text(p1, 1);
    ++    nByte += 1 + STRLEN(zCol);
    ++    rc = sqlite3_table_column_metadata(
    ++        db, "main", zTab, zCol, 0, &zCol, 0, 0, 0
    ++    );
    ++    nByte += 1 + STRLEN(zCol);
    ++    nCol++;
    ++  }
    ++  rc2 = sqlite3_reset(p1);
    ++  if( rc==SQLITE_OK ) rc = rc2;
    ++
    ++  nByte += sizeof(IdxColumn) * nCol;
    ++  if( rc==SQLITE_OK ){
    ++    pNew = idxMalloc(&rc, nByte);
    ++  }
    ++  if( rc==SQLITE_OK ){
    ++    pNew->aCol = (IdxColumn*)&pNew[1];
    ++    pNew->nCol = nCol;
    ++    pCsr = (char*)&pNew->aCol[nCol];
    ++  }
    ++
    ++  nCol = 0;
    ++  while( rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(p1) ){
    ++    const char *zCol = (const char*)sqlite3_column_text(p1, 1);
    ++    int nCopy = STRLEN(zCol) + 1;
    ++    pNew->aCol[nCol].zName = pCsr;
    ++    pNew->aCol[nCol].iPk = sqlite3_column_int(p1, 5);
    ++    memcpy(pCsr, zCol, nCopy);
    ++    pCsr += nCopy;
    ++
    ++    rc = sqlite3_table_column_metadata(
    ++        db, "main", zTab, zCol, 0, &zCol, 0, 0, 0
    ++    );
    ++    if( rc==SQLITE_OK ){
    ++      nCopy = STRLEN(zCol) + 1;
    ++      pNew->aCol[nCol].zColl = pCsr;
    ++      memcpy(pCsr, zCol, nCopy);
    ++      pCsr += nCopy;
    ++    }
    ++
    ++    nCol++;
    ++  }
    ++  idxFinalize(&rc, p1);
    ++
    ++  if( rc!=SQLITE_OK ){
    ++    sqlite3_free(pNew);
    ++    pNew = 0;
    ++  }else{
    ++    pNew->zName = pCsr;
    ++    memcpy(pNew->zName, zTab, nTab+1);
    ++  }
    ++
    ++  *ppOut = pNew;
    ++  return rc;
    ++}
    ++
    ++/*
    ++** This function is a no-op if *pRc is set to anything other than 
    ++** SQLITE_OK when it is called.
    ++**
    ++** If *pRc is initially set to SQLITE_OK, then the text specified by
    ++** the printf() style arguments is appended to zIn and the result returned
    ++** in a buffer allocated by sqlite3_malloc(). sqlite3_free() is called on
    ++** zIn before returning.
    ++*/
    ++static char *idxAppendText(int *pRc, char *zIn, const char *zFmt, ...){
    ++  va_list ap;
    ++  char *zAppend = 0;
    ++  char *zRet = 0;
    ++  int nIn = zIn ? STRLEN(zIn) : 0;
    ++  int nAppend = 0;
    ++  va_start(ap, zFmt);
    ++  if( *pRc==SQLITE_OK ){
    ++    zAppend = sqlite3_vmprintf(zFmt, ap);
    ++    if( zAppend ){
    ++      nAppend = STRLEN(zAppend);
    ++      zRet = (char*)sqlite3_malloc(nIn + nAppend + 1);
    ++    }
    ++    if( zAppend && zRet ){
    ++      if( nIn ) memcpy(zRet, zIn, nIn);
    ++      memcpy(&zRet[nIn], zAppend, nAppend+1);
    ++    }else{
    ++      sqlite3_free(zRet);
    ++      zRet = 0;
    ++      *pRc = SQLITE_NOMEM;
    ++    }
    ++    sqlite3_free(zAppend);
    ++    sqlite3_free(zIn);
    ++  }
    ++  va_end(ap);
    ++  return zRet;
    ++}
    ++
    ++/*
    ++** Return true if zId must be quoted in order to use it as an SQL
    ++** identifier, or false otherwise.
    ++*/
    ++static int idxIdentifierRequiresQuotes(const char *zId){
    ++  int i;
    ++  for(i=0; zId[i]; i++){
    ++    if( !(zId[i]=='_')
    ++     && !(zId[i]>='0' && zId[i]<='9')
    ++     && !(zId[i]>='a' && zId[i]<='z')
    ++     && !(zId[i]>='A' && zId[i]<='Z')
    ++    ){
    ++      return 1;
    ++    }
    ++  }
    ++  return 0;
    ++}
    ++
    ++/*
    ++** This function appends an index column definition suitable for constraint
    ++** pCons to the string passed as zIn and returns the result.
    ++*/
    ++static char *idxAppendColDefn(
    ++  int *pRc,                       /* IN/OUT: Error code */
    ++  char *zIn,                      /* Column defn accumulated so far */
    ++  IdxTable *pTab,                 /* Table index will be created on */
    ++  IdxConstraint *pCons
    ++){
    ++  char *zRet = zIn;
    ++  IdxColumn *p = &pTab->aCol[pCons->iCol];
    ++  if( zRet ) zRet = idxAppendText(pRc, zRet, ", ");
    ++
    ++  if( idxIdentifierRequiresQuotes(p->zName) ){
    ++    zRet = idxAppendText(pRc, zRet, "%Q", p->zName);
    ++  }else{
    ++    zRet = idxAppendText(pRc, zRet, "%s", p->zName);
    ++  }
    ++
    ++  if( sqlite3_stricmp(p->zColl, pCons->zColl) ){
    ++    if( idxIdentifierRequiresQuotes(pCons->zColl) ){
    ++      zRet = idxAppendText(pRc, zRet, " COLLATE %Q", pCons->zColl);
    ++    }else{
    ++      zRet = idxAppendText(pRc, zRet, " COLLATE %s", pCons->zColl);
    ++    }
    ++  }
    ++
    ++  if( pCons->bDesc ){
    ++    zRet = idxAppendText(pRc, zRet, " DESC");
    ++  }
    ++  return zRet;
    ++}
    ++
    ++/*
    ++** Search database dbm for an index compatible with the one idxCreateFromCons()
    ++** would create from arguments pScan, pEq and pTail. If no error occurs and 
    ++** such an index is found, return non-zero. Or, if no such index is found,
    ++** return zero.
    ++**
    ++** If an error occurs, set *pRc to an SQLite error code and return zero.
    ++*/
    ++static int idxFindCompatible(
    ++  int *pRc,                       /* OUT: Error code */
    ++  sqlite3* dbm,                   /* Database to search */
    ++  IdxScan *pScan,                 /* Scan for table to search for index on */
    ++  IdxConstraint *pEq,             /* List of == constraints */
    ++  IdxConstraint *pTail            /* List of range constraints */
    ++){
    ++  const char *zTbl = pScan->pTab->zName;
    ++  sqlite3_stmt *pIdxList = 0;
    ++  IdxConstraint *pIter;
    ++  int nEq = 0;                    /* Number of elements in pEq */
    ++  int rc;
    ++
    ++  /* Count the elements in list pEq */
    ++  for(pIter=pEq; pIter; pIter=pIter->pLink) nEq++;
    ++
    ++  rc = idxPrintfPrepareStmt(dbm, &pIdxList, 0, "PRAGMA index_list=%Q", zTbl);
    ++  while( rc==SQLITE_OK && sqlite3_step(pIdxList)==SQLITE_ROW ){
    ++    int bMatch = 1;
    ++    IdxConstraint *pT = pTail;
    ++    sqlite3_stmt *pInfo = 0;
    ++    const char *zIdx = (const char*)sqlite3_column_text(pIdxList, 1);
    ++
    ++    /* Zero the IdxConstraint.bFlag values in the pEq list */
    ++    for(pIter=pEq; pIter; pIter=pIter->pLink) pIter->bFlag = 0;
    ++
    ++    rc = idxPrintfPrepareStmt(dbm, &pInfo, 0, "PRAGMA index_xInfo=%Q", zIdx);
    ++    while( rc==SQLITE_OK && sqlite3_step(pInfo)==SQLITE_ROW ){
    ++      int iIdx = sqlite3_column_int(pInfo, 0);
    ++      int iCol = sqlite3_column_int(pInfo, 1);
    ++      const char *zColl = (const char*)sqlite3_column_text(pInfo, 4);
    ++
    ++      if( iIdx<nEq ){
    ++        for(pIter=pEq; pIter; pIter=pIter->pLink){
    ++          if( pIter->bFlag ) continue;
    ++          if( pIter->iCol!=iCol ) continue;
    ++          if( sqlite3_stricmp(pIter->zColl, zColl) ) continue;
    ++          pIter->bFlag = 1;
    ++          break;
    ++        }
    ++        if( pIter==0 ){
    ++          bMatch = 0;
    ++          break;
    ++        }
    ++      }else{
    ++        if( pT ){
    ++          if( pT->iCol!=iCol || sqlite3_stricmp(pT->zColl, zColl) ){
    ++            bMatch = 0;
    ++            break;
    ++          }
    ++          pT = pT->pLink;
    ++        }
    ++      }
    ++    }
    ++    idxFinalize(&rc, pInfo);
    ++
    ++    if( rc==SQLITE_OK && bMatch ){
    ++      sqlite3_finalize(pIdxList);
    ++      return 1;
    ++    }
    ++  }
    ++  idxFinalize(&rc, pIdxList);
    ++
    ++  *pRc = rc;
    ++  return 0;
    ++}
    ++
    ++static int idxCreateFromCons(
    ++  sqlite3expert *p,
    ++  IdxScan *pScan,
    ++  IdxConstraint *pEq, 
    ++  IdxConstraint *pTail
    ++){
    ++  sqlite3 *dbm = p->dbm;
    ++  int rc = SQLITE_OK;
    ++  if( (pEq || pTail) && 0==idxFindCompatible(&rc, dbm, pScan, pEq, pTail) ){
    ++    IdxTable *pTab = pScan->pTab;
    ++    char *zCols = 0;
    ++    char *zIdx = 0;
    ++    IdxConstraint *pCons;
    ++    unsigned int h = 0;
    ++    const char *zFmt;
    ++
    ++    for(pCons=pEq; pCons; pCons=pCons->pLink){
    ++      zCols = idxAppendColDefn(&rc, zCols, pTab, pCons);
    ++    }
    ++    for(pCons=pTail; pCons; pCons=pCons->pLink){
    ++      zCols = idxAppendColDefn(&rc, zCols, pTab, pCons);
    ++    }
    ++
    ++    if( rc==SQLITE_OK ){
    ++      /* Hash the list of columns to come up with a name for the index */
    ++      const char *zTable = pScan->pTab->zName;
    ++      char *zName;                /* Index name */
    ++      int i;
    ++      for(i=0; zCols[i]; i++){
    ++        h += ((h<<3) + zCols[i]);
    ++      }
    ++      zName = sqlite3_mprintf("%s_idx_%08x", zTable, h);
    ++      if( zName==0 ){ 
    ++        rc = SQLITE_NOMEM;
    ++      }else{
    ++        if( idxIdentifierRequiresQuotes(zTable) ){
    ++          zFmt = "CREATE INDEX '%q' ON %Q(%s)";
    ++        }else{
    ++          zFmt = "CREATE INDEX %s ON %s(%s)";
    ++        }
    ++        zIdx = sqlite3_mprintf(zFmt, zName, zTable, zCols);
    ++        if( !zIdx ){
    ++          rc = SQLITE_NOMEM;
    ++        }else{
    ++          rc = sqlite3_exec(dbm, zIdx, 0, 0, p->pzErrmsg);
    ++          idxHashAdd(&rc, &p->hIdx, zName, zIdx);
    ++        }
    ++        sqlite3_free(zName);
    ++        sqlite3_free(zIdx);
    ++      }
    ++    }
    ++
    ++    sqlite3_free(zCols);
    ++  }
    ++  return rc;
    ++}
    ++
    ++/*
    ++** Return true if list pList (linked by IdxConstraint.pLink) contains
    ++** a constraint compatible with *p. Otherwise return false.
    ++*/
    ++static int idxFindConstraint(IdxConstraint *pList, IdxConstraint *p){
    ++  IdxConstraint *pCmp;
    ++  for(pCmp=pList; pCmp; pCmp=pCmp->pLink){
    ++    if( p->iCol==pCmp->iCol ) return 1;
    ++  }
    ++  return 0;
    ++}
    ++
    ++static int idxCreateFromWhere(
    ++  sqlite3expert *p, 
    ++  IdxScan *pScan,                 /* Create indexes for this scan */
    ++  IdxConstraint *pTail            /* range/ORDER BY constraints for inclusion */
    ++){
    ++  IdxConstraint *p1 = 0;
    ++  IdxConstraint *pCon;
    ++  int rc;
    ++
    ++  /* Gather up all the == constraints. */
    ++  for(pCon=pScan->pEq; pCon; pCon=pCon->pNext){
    ++    if( !idxFindConstraint(p1, pCon) && !idxFindConstraint(pTail, pCon) ){
    ++      pCon->pLink = p1;
    ++      p1 = pCon;
    ++    }
    ++  }
    ++
    ++  /* Create an index using the == constraints collected above. And the
    ++  ** range constraint/ORDER BY terms passed in by the caller, if any. */
    ++  rc = idxCreateFromCons(p, pScan, p1, pTail);
    ++
    ++  /* If no range/ORDER BY passed by the caller, create a version of the
    ++  ** index for each range constraint.  */
    ++  if( pTail==0 ){
    ++    for(pCon=pScan->pRange; rc==SQLITE_OK && pCon; pCon=pCon->pNext){
    ++      assert( pCon->pLink==0 );
    ++      if( !idxFindConstraint(p1, pCon) && !idxFindConstraint(pTail, pCon) ){
    ++        rc = idxCreateFromCons(p, pScan, p1, pCon);
    ++      }
    ++    }
    ++  }
    ++
    ++  return rc;
    ++}
    ++
    ++/*
    ++** Create candidate indexes in database [dbm] based on the data in 
    ++** linked-list pScan.
    ++*/
    ++static int idxCreateCandidates(sqlite3expert *p){
    ++  int rc = SQLITE_OK;
    ++  IdxScan *pIter;
    ++
    ++  for(pIter=p->pScan; pIter && rc==SQLITE_OK; pIter=pIter->pNextScan){
    ++    rc = idxCreateFromWhere(p, pIter, 0);
    ++    if( rc==SQLITE_OK && pIter->pOrder ){
    ++      rc = idxCreateFromWhere(p, pIter, pIter->pOrder);
    ++    }
    ++  }
    ++
    ++  return rc;
    ++}
    ++
    ++/*
    ++** Free all elements of the linked list starting at pConstraint.
    ++*/
    ++static void idxConstraintFree(IdxConstraint *pConstraint){
    ++  IdxConstraint *pNext;
    ++  IdxConstraint *p;
    ++
    ++  for(p=pConstraint; p; p=pNext){
    ++    pNext = p->pNext;
    ++    sqlite3_free(p);
    ++  }
    ++}
    ++
    ++/*
    ++** Free all elements of the linked list starting from pScan up until pLast
    ++** (pLast is not freed).
    ++*/
    ++static void idxScanFree(IdxScan *pScan, IdxScan *pLast){
    ++  IdxScan *p;
    ++  IdxScan *pNext;
    ++  for(p=pScan; p!=pLast; p=pNext){
    ++    pNext = p->pNextScan;
    ++    idxConstraintFree(p->pOrder);
    ++    idxConstraintFree(p->pEq);
    ++    idxConstraintFree(p->pRange);
    ++    sqlite3_free(p);
    ++  }
    ++}
    ++
    ++/*
    ++** Free all elements of the linked list starting from pStatement up 
    ++** until pLast (pLast is not freed).
    ++*/
    ++static void idxStatementFree(IdxStatement *pStatement, IdxStatement *pLast){
    ++  IdxStatement *p;
    ++  IdxStatement *pNext;
    ++  for(p=pStatement; p!=pLast; p=pNext){
    ++    pNext = p->pNext;
    ++    sqlite3_free(p->zEQP);
    ++    sqlite3_free(p->zIdx);
    ++    sqlite3_free(p);
    ++  }
    ++}
    ++
    ++/*
    ++** Free the linked list of IdxTable objects starting at pTab.
    ++*/
    ++static void idxTableFree(IdxTable *pTab){
    ++  IdxTable *pIter;
    ++  IdxTable *pNext;
    ++  for(pIter=pTab; pIter; pIter=pNext){
    ++    pNext = pIter->pNext;
    ++    sqlite3_free(pIter);
    ++  }
    ++}
    ++
    ++/*
    ++** Free the linked list of IdxWrite objects starting at pTab.
    ++*/
    ++static void idxWriteFree(IdxWrite *pTab){
    ++  IdxWrite *pIter;
    ++  IdxWrite *pNext;
    ++  for(pIter=pTab; pIter; pIter=pNext){
    ++    pNext = pIter->pNext;
    ++    sqlite3_free(pIter);
    ++  }
    ++}
    ++
    ++
    ++
    ++/*
    ++** This function is called after candidate indexes have been created. It
    ++** runs all the queries to see which indexes they prefer, and populates
    ++** IdxStatement.zIdx and IdxStatement.zEQP with the results.
    ++*/
    ++int idxFindIndexes(
    ++  sqlite3expert *p,
    ++  char **pzErr                         /* OUT: Error message (sqlite3_malloc) */
    ++){
    ++  IdxStatement *pStmt;
    ++  sqlite3 *dbm = p->dbm;
    ++  int rc = SQLITE_OK;
    ++
    ++  IdxHash hIdx;
    ++  idxHashInit(&hIdx);
    ++
    ++  for(pStmt=p->pStatement; rc==SQLITE_OK && pStmt; pStmt=pStmt->pNext){
    ++    IdxHashEntry *pEntry;
    ++    sqlite3_stmt *pExplain = 0;
    ++    idxHashClear(&hIdx);
    ++    rc = idxPrintfPrepareStmt(dbm, &pExplain, pzErr,
    ++        "EXPLAIN QUERY PLAN %s", pStmt->zSql
    ++    );
    ++    while( rc==SQLITE_OK && sqlite3_step(pExplain)==SQLITE_ROW ){
    ++      int iSelectid = sqlite3_column_int(pExplain, 0);
    ++      int iOrder = sqlite3_column_int(pExplain, 1);
    ++      int iFrom = sqlite3_column_int(pExplain, 2);
    ++      const char *zDetail = (const char*)sqlite3_column_text(pExplain, 3);
    ++      int nDetail = STRLEN(zDetail);
    ++      int i;
    ++
    ++      for(i=0; i<nDetail; i++){
    ++        const char *zIdx = 0;
    ++        if( memcmp(&zDetail[i], " USING INDEX ", 13)==0 ){
    ++          zIdx = &zDetail[i+13];
    ++        }else if( memcmp(&zDetail[i], " USING COVERING INDEX ", 22)==0 ){
    ++          zIdx = &zDetail[i+22];
    ++        }
    ++        if( zIdx ){
    ++          const char *zSql;
    ++          int nIdx = 0;
    ++          while( zIdx[nIdx]!='\0' && (zIdx[nIdx]!=' ' || zIdx[nIdx+1]!='(') ){
    ++            nIdx++;
    ++          }
    ++          zSql = idxHashSearch(&p->hIdx, zIdx, nIdx);
    ++          if( zSql ){
    ++            idxHashAdd(&rc, &hIdx, zSql, 0);
    ++            if( rc ) goto find_indexes_out;
    ++          }
    ++          break;
    ++        }
    ++      }
    ++
    ++      pStmt->zEQP = idxAppendText(&rc, pStmt->zEQP, "%d|%d|%d|%s\n", 
    ++          iSelectid, iOrder, iFrom, zDetail
    ++      );
    ++    }
    ++
    ++    for(pEntry=hIdx.pFirst; pEntry; pEntry=pEntry->pNext){
    ++      pStmt->zIdx = idxAppendText(&rc, pStmt->zIdx, "%s;\n", pEntry->zKey);
    ++    }
    ++
    ++    idxFinalize(&rc, pExplain);
    ++  }
    ++
    ++ find_indexes_out:
    ++  idxHashClear(&hIdx);
    ++  return rc;
    ++}
    ++
    ++static int idxAuthCallback(
    ++  void *pCtx,
    ++  int eOp,
    ++  const char *z3,
    ++  const char *z4,
    ++  const char *zDb,
    ++  const char *zTrigger
    ++){
    ++  int rc = SQLITE_OK;
    ++  (void)z4;
    ++  (void)zTrigger;
    ++  if( eOp==SQLITE_INSERT || eOp==SQLITE_UPDATE || eOp==SQLITE_DELETE ){
    ++    if( sqlite3_stricmp(zDb, "main")==0 ){
    ++      sqlite3expert *p = (sqlite3expert*)pCtx;
    ++      IdxTable *pTab;
    ++      for(pTab=p->pTable; pTab; pTab=pTab->pNext){
    ++        if( 0==sqlite3_stricmp(z3, pTab->zName) ) break;
    ++      }
    ++      if( pTab ){
    ++        IdxWrite *pWrite;
    ++        for(pWrite=p->pWrite; pWrite; pWrite=pWrite->pNext){
    ++          if( pWrite->pTab==pTab && pWrite->eOp==eOp ) break;
    ++        }
    ++        if( pWrite==0 ){
    ++          pWrite = idxMalloc(&rc, sizeof(IdxWrite));
    ++          if( rc==SQLITE_OK ){
    ++            pWrite->pTab = pTab;
    ++            pWrite->eOp = eOp;
    ++            pWrite->pNext = p->pWrite;
    ++            p->pWrite = pWrite;
    ++          }
    ++        }
    ++      }
    ++    }
    ++  }
    ++  return rc;
    ++}
    ++
    ++static int idxProcessOneTrigger(
    ++  sqlite3expert *p, 
    ++  IdxWrite *pWrite, 
    ++  char **pzErr
    ++){
    ++  static const char *zInt = UNIQUE_TABLE_NAME;
    ++  static const char *zDrop = "DROP TABLE " UNIQUE_TABLE_NAME;
    ++  IdxTable *pTab = pWrite->pTab;
    ++  const char *zTab = pTab->zName;
    ++  const char *zSql = 
    ++    "SELECT 'CREATE TEMP' || substr(sql, 7) FROM sqlite_master "
    ++    "WHERE tbl_name = %Q AND type IN ('table', 'trigger') "
    ++    "ORDER BY type;";
    ++  sqlite3_stmt *pSelect = 0;
    ++  int rc = SQLITE_OK;
    ++  char *zWrite = 0;
    ++
    ++  /* Create the table and its triggers in the temp schema */
    ++  rc = idxPrintfPrepareStmt(p->db, &pSelect, pzErr, zSql, zTab, zTab);
    ++  while( rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pSelect) ){
    ++    const char *zCreate = (const char*)sqlite3_column_text(pSelect, 0);
    ++    rc = sqlite3_exec(p->dbv, zCreate, 0, 0, pzErr);
    ++  }
    ++  idxFinalize(&rc, pSelect);
    ++
    ++  /* Rename the table in the temp schema to zInt */
    ++  if( rc==SQLITE_OK ){
    ++    char *z = sqlite3_mprintf("ALTER TABLE temp.%Q RENAME TO %Q", zTab, zInt);
    ++    if( z==0 ){
    ++      rc = SQLITE_NOMEM;
    ++    }else{
    ++      rc = sqlite3_exec(p->dbv, z, 0, 0, pzErr);
    ++      sqlite3_free(z);
    ++    }
    ++  }
    ++
    ++  switch( pWrite->eOp ){
    ++    case SQLITE_INSERT: {
    ++      int i;
    ++      zWrite = idxAppendText(&rc, zWrite, "INSERT INTO %Q VALUES(", zInt);
    ++      for(i=0; i<pTab->nCol; i++){
    ++        zWrite = idxAppendText(&rc, zWrite, "%s?", i==0 ? "" : ", ");
    ++      }
    ++      zWrite = idxAppendText(&rc, zWrite, ")");
    ++      break;
    ++    }
    ++    case SQLITE_UPDATE: {
    ++      int i;
    ++      zWrite = idxAppendText(&rc, zWrite, "UPDATE %Q SET ", zInt);
    ++      for(i=0; i<pTab->nCol; i++){
    ++        zWrite = idxAppendText(&rc, zWrite, "%s%Q=?", i==0 ? "" : ", ", 
    ++            pTab->aCol[i].zName
    ++        );
    ++      }
    ++      break;
    ++    }
    ++    default: {
    ++      assert( pWrite->eOp==SQLITE_DELETE );
    ++      if( rc==SQLITE_OK ){
    ++        zWrite = sqlite3_mprintf("DELETE FROM %Q", zInt);
    ++        if( zWrite==0 ) rc = SQLITE_NOMEM;
    ++      }
    ++    }
    ++  }
    ++
    ++  if( rc==SQLITE_OK ){
    ++    sqlite3_stmt *pX = 0;
    ++    rc = sqlite3_prepare_v2(p->dbv, zWrite, -1, &pX, 0);
    ++    idxFinalize(&rc, pX);
    ++    if( rc!=SQLITE_OK ){
    ++      idxDatabaseError(p->dbv, pzErr);
    ++    }
    ++  }
    ++  sqlite3_free(zWrite);
    ++
    ++  if( rc==SQLITE_OK ){
    ++    rc = sqlite3_exec(p->dbv, zDrop, 0, 0, pzErr);
    ++  }
    ++
    ++  return rc;
    ++}
    ++
    ++static int idxProcessTriggers(sqlite3expert *p, char **pzErr){
    ++  int rc = SQLITE_OK;
    ++  IdxWrite *pEnd = 0;
    ++  IdxWrite *pFirst = p->pWrite;
    ++
    ++  while( rc==SQLITE_OK && pFirst!=pEnd ){
    ++    IdxWrite *pIter;
    ++    for(pIter=pFirst; rc==SQLITE_OK && pIter!=pEnd; pIter=pIter->pNext){
    ++      rc = idxProcessOneTrigger(p, pIter, pzErr);
    ++    }
    ++    pEnd = pFirst;
    ++    pFirst = p->pWrite;
    ++  }
    ++
    ++  return rc;
    ++}
    ++
    ++
    ++static int idxCreateVtabSchema(sqlite3expert *p, char **pzErrmsg){
    ++  int rc = idxRegisterVtab(p);
    ++  sqlite3_stmt *pSchema = 0;
    ++
    ++  /* For each table in the main db schema:
    ++  **
    ++  **   1) Add an entry to the p->pTable list, and
    ++  **   2) Create the equivalent virtual table in dbv.
    ++  */
    ++  rc = idxPrepareStmt(p->db, &pSchema, pzErrmsg,
    ++      "SELECT type, name, sql, 1 FROM sqlite_master "
    ++      "WHERE type IN ('table','view') AND name NOT LIKE 'sqlite_%%' "
    ++      " UNION ALL "
    ++      "SELECT type, name, sql, 2 FROM sqlite_master "
    ++      "WHERE type = 'trigger'"
    ++      "  AND tbl_name IN(SELECT name FROM sqlite_master WHERE type = 'view') "
    ++      "ORDER BY 4, 1"
    ++  );
    ++  while( rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pSchema) ){
    ++    const char *zType = (const char*)sqlite3_column_text(pSchema, 0);
    ++    const char *zName = (const char*)sqlite3_column_text(pSchema, 1);
    ++    const char *zSql = (const char*)sqlite3_column_text(pSchema, 2);
    ++
    ++    if( zType[0]=='v' || zType[1]=='r' ){
    ++      rc = sqlite3_exec(p->dbv, zSql, 0, 0, pzErrmsg);
    ++    }else{
    ++      IdxTable *pTab;
    ++      rc = idxGetTableInfo(p->db, zName, &pTab, pzErrmsg);
    ++      if( rc==SQLITE_OK ){
    ++        int i;
    ++        char *zInner = 0;
    ++        char *zOuter = 0;
    ++        pTab->pNext = p->pTable;
    ++        p->pTable = pTab;
    ++
    ++        /* The statement the vtab will pass to sqlite3_declare_vtab() */
    ++        zInner = idxAppendText(&rc, 0, "CREATE TABLE x(");
    ++        for(i=0; i<pTab->nCol; i++){
    ++          zInner = idxAppendText(&rc, zInner, "%s%Q COLLATE %s", 
    ++              (i==0 ? "" : ", "), pTab->aCol[i].zName, pTab->aCol[i].zColl
    ++          );
    ++        }
    ++        zInner = idxAppendText(&rc, zInner, ")");
    ++
    ++        /* The CVT statement to create the vtab */
    ++        zOuter = idxAppendText(&rc, 0, 
    ++            "CREATE VIRTUAL TABLE %Q USING expert(%Q)", zName, zInner
    ++        );
    ++        if( rc==SQLITE_OK ){
    ++          rc = sqlite3_exec(p->dbv, zOuter, 0, 0, pzErrmsg);
    ++        }
    ++        sqlite3_free(zInner);
    ++        sqlite3_free(zOuter);
    ++      }
    ++    }
    ++  }
    ++  idxFinalize(&rc, pSchema);
    ++  return rc;
    ++}
    ++
    ++struct IdxSampleCtx {
    ++  int iTarget;
    ++  double target;                  /* Target nRet/nRow value */
    ++  double nRow;                    /* Number of rows seen */
    ++  double nRet;                    /* Number of rows returned */
    ++};
    ++
    ++static void idxSampleFunc(
    ++  sqlite3_context *pCtx,
    ++  int argc,
    ++  sqlite3_value **argv
    ++){
    ++  struct IdxSampleCtx *p = (struct IdxSampleCtx*)sqlite3_user_data(pCtx);
    ++  int bRet;
    ++
    ++  (void)argv;
    ++  assert( argc==0 );
    ++  if( p->nRow==0.0 ){
    ++    bRet = 1;
    ++  }else{
    ++    bRet = (p->nRet / p->nRow) <= p->target;
    ++    if( bRet==0 ){
    ++      unsigned short rnd;
    ++      sqlite3_randomness(2, (void*)&rnd);
    ++      bRet = ((int)rnd % 100) <= p->iTarget;
    ++    }
    ++  }
    ++
    ++  sqlite3_result_int(pCtx, bRet);
    ++  p->nRow += 1.0;
    ++  p->nRet += (double)bRet;
    ++}
    ++
    ++struct IdxRemCtx {
    ++  int nSlot;
    ++  struct IdxRemSlot {
    ++    int eType;                    /* SQLITE_NULL, INTEGER, REAL, TEXT, BLOB */
    ++    i64 iVal;                     /* SQLITE_INTEGER value */
    ++    double rVal;                  /* SQLITE_FLOAT value */
    ++    int nByte;                    /* Bytes of space allocated at z */
    ++    int n;                        /* Size of buffer z */
    ++    char *z;                      /* SQLITE_TEXT/BLOB value */
    ++  } aSlot[1];
    ++};
    ++
    ++/*
    ++** Implementation of scalar function rem().
    ++*/
    ++static void idxRemFunc(
    ++  sqlite3_context *pCtx,
    ++  int argc,
    ++  sqlite3_value **argv
    ++){
    ++  struct IdxRemCtx *p = (struct IdxRemCtx*)sqlite3_user_data(pCtx);
    ++  struct IdxRemSlot *pSlot;
    ++  int iSlot;
    ++  assert( argc==2 );
    ++
    ++  iSlot = sqlite3_value_int(argv[0]);
    ++  assert( iSlot<=p->nSlot );
    ++  pSlot = &p->aSlot[iSlot];
    ++
    ++  switch( pSlot->eType ){
    ++    case SQLITE_NULL:
    ++      /* no-op */
    ++      break;
    ++
    ++    case SQLITE_INTEGER:
    ++      sqlite3_result_int64(pCtx, pSlot->iVal);
    ++      break;
    ++
    ++    case SQLITE_FLOAT:
    ++      sqlite3_result_double(pCtx, pSlot->rVal);
    ++      break;
    ++
    ++    case SQLITE_BLOB:
    ++      sqlite3_result_blob(pCtx, pSlot->z, pSlot->n, SQLITE_TRANSIENT);
    ++      break;
    ++
    ++    case SQLITE_TEXT:
    ++      sqlite3_result_text(pCtx, pSlot->z, pSlot->n, SQLITE_TRANSIENT);
    ++      break;
    ++  }
    ++
    ++  pSlot->eType = sqlite3_value_type(argv[1]);
    ++  switch( pSlot->eType ){
    ++    case SQLITE_NULL:
    ++      /* no-op */
    ++      break;
    ++
    ++    case SQLITE_INTEGER:
    ++      pSlot->iVal = sqlite3_value_int64(argv[1]);
    ++      break;
    ++
    ++    case SQLITE_FLOAT:
    ++      pSlot->rVal = sqlite3_value_double(argv[1]);
    ++      break;
    ++
    ++    case SQLITE_BLOB:
    ++    case SQLITE_TEXT: {
    ++      int nByte = sqlite3_value_bytes(argv[1]);
    ++      if( nByte>pSlot->nByte ){
    ++        char *zNew = (char*)sqlite3_realloc(pSlot->z, nByte*2);
    ++        if( zNew==0 ){
    ++          sqlite3_result_error_nomem(pCtx);
    ++          return;
    ++        }
    ++        pSlot->nByte = nByte*2;
    ++        pSlot->z = zNew;
    ++      }
    ++      pSlot->n = nByte;
    ++      if( pSlot->eType==SQLITE_BLOB ){
    ++        memcpy(pSlot->z, sqlite3_value_blob(argv[1]), nByte);
    ++      }else{
    ++        memcpy(pSlot->z, sqlite3_value_text(argv[1]), nByte);
    ++      }
    ++      break;
    ++    }
    ++  }
    ++}
    ++
    ++static int idxLargestIndex(sqlite3 *db, int *pnMax, char **pzErr){
    ++  int rc = SQLITE_OK;
    ++  const char *zMax = 
    ++    "SELECT max(i.seqno) FROM "
    ++    "  sqlite_master AS s, "
    ++    "  pragma_index_list(s.name) AS l, "
    ++    "  pragma_index_info(l.name) AS i "
    ++    "WHERE s.type = 'table'";
    ++  sqlite3_stmt *pMax = 0;
    ++
    ++  *pnMax = 0;
    ++  rc = idxPrepareStmt(db, &pMax, pzErr, zMax);
    ++  if( rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pMax) ){
    ++    *pnMax = sqlite3_column_int(pMax, 0) + 1;
    ++  }
    ++  idxFinalize(&rc, pMax);
    ++
    ++  return rc;
    ++}
    ++
    ++static int idxPopulateOneStat1(
    ++  sqlite3expert *p,
    ++  sqlite3_stmt *pIndexXInfo,
    ++  sqlite3_stmt *pWriteStat,
    ++  const char *zTab,
    ++  const char *zIdx,
    ++  char **pzErr
    ++){
    ++  char *zCols = 0;
    ++  char *zOrder = 0;
    ++  char *zQuery = 0;
    ++  int nCol = 0;
    ++  int i;
    ++  sqlite3_stmt *pQuery = 0;
    ++  int *aStat = 0;
    ++  int rc = SQLITE_OK;
    ++
    ++  assert( p->iSample>0 );
    ++
    ++  /* Formulate the query text */
    ++  sqlite3_bind_text(pIndexXInfo, 1, zIdx, -1, SQLITE_STATIC);
    ++  while( SQLITE_OK==rc && SQLITE_ROW==sqlite3_step(pIndexXInfo) ){
    ++    const char *zComma = zCols==0 ? "" : ", ";
    ++    const char *zName = (const char*)sqlite3_column_text(pIndexXInfo, 0);
    ++    const char *zColl = (const char*)sqlite3_column_text(pIndexXInfo, 1);
    ++    zCols = idxAppendText(&rc, zCols, 
    ++        "%sx.%Q IS rem(%d, x.%Q) COLLATE %s", zComma, zName, nCol, zName, zColl
    ++    );
    ++    zOrder = idxAppendText(&rc, zOrder, "%s%d", zComma, ++nCol);
    ++  }
    ++  sqlite3_reset(pIndexXInfo);
    ++  if( rc==SQLITE_OK ){
    ++    if( p->iSample==100 ){
    ++      zQuery = sqlite3_mprintf(
    ++          "SELECT %s FROM %Q x ORDER BY %s", zCols, zTab, zOrder
    ++      );
    ++    }else{
    ++      zQuery = sqlite3_mprintf(
    ++          "SELECT %s FROM temp."UNIQUE_TABLE_NAME" x ORDER BY %s", zCols, zOrder
    ++      );
    ++    }
    ++  }
    ++  sqlite3_free(zCols);
    ++  sqlite3_free(zOrder);
    ++
    ++  /* Formulate the query text */
    ++  if( rc==SQLITE_OK ){
    ++    sqlite3 *dbrem = (p->iSample==100 ? p->db : p->dbv);
    ++    rc = idxPrepareStmt(dbrem, &pQuery, pzErr, zQuery);
    ++  }
    ++  sqlite3_free(zQuery);
    ++
    ++  if( rc==SQLITE_OK ){
    ++    aStat = (int*)idxMalloc(&rc, sizeof(int)*(nCol+1));
    ++  }
    ++  if( rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pQuery) ){
    ++    IdxHashEntry *pEntry;
    ++    char *zStat = 0;
    ++    for(i=0; i<=nCol; i++) aStat[i] = 1;
    ++    while( rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pQuery) ){
    ++      aStat[0]++;
    ++      for(i=0; i<nCol; i++){
    ++        if( sqlite3_column_int(pQuery, i)==0 ) break;
    ++      }
    ++      for(/*no-op*/; i<nCol; i++){
    ++        aStat[i+1]++;
    ++      }
    ++    }
    ++
    ++    if( rc==SQLITE_OK ){
    ++      int s0 = aStat[0];
    ++      zStat = sqlite3_mprintf("%d", s0);
    ++      if( zStat==0 ) rc = SQLITE_NOMEM;
    ++      for(i=1; rc==SQLITE_OK && i<=nCol; i++){
    ++        zStat = idxAppendText(&rc, zStat, " %d", (s0+aStat[i]/2) / aStat[i]);
    ++      }
    ++    }
    ++
    ++    if( rc==SQLITE_OK ){
    ++      sqlite3_bind_text(pWriteStat, 1, zTab, -1, SQLITE_STATIC);
    ++      sqlite3_bind_text(pWriteStat, 2, zIdx, -1, SQLITE_STATIC);
    ++      sqlite3_bind_text(pWriteStat, 3, zStat, -1, SQLITE_STATIC);
    ++      sqlite3_step(pWriteStat);
    ++      rc = sqlite3_reset(pWriteStat);
    ++    }
    ++
    ++    pEntry = idxHashFind(&p->hIdx, zIdx, STRLEN(zIdx));
    ++    if( pEntry ){
    ++      assert( pEntry->zVal2==0 );
    ++      pEntry->zVal2 = zStat;
    ++    }else{
    ++      sqlite3_free(zStat);
    ++    }
    ++  }
    ++  sqlite3_free(aStat);
    ++  idxFinalize(&rc, pQuery);
    ++
    ++  return rc;
    ++}
    ++
    ++static int idxBuildSampleTable(sqlite3expert *p, const char *zTab){
    ++  int rc;
    ++  char *zSql;
    ++
    ++  rc = sqlite3_exec(p->dbv,"DROP TABLE IF EXISTS temp."UNIQUE_TABLE_NAME,0,0,0);
    ++  if( rc!=SQLITE_OK ) return rc;
    ++
    ++  zSql = sqlite3_mprintf(
    ++      "CREATE TABLE temp." UNIQUE_TABLE_NAME " AS SELECT * FROM %Q", zTab
    ++  );
    ++  if( zSql==0 ) return SQLITE_NOMEM;
    ++  rc = sqlite3_exec(p->dbv, zSql, 0, 0, 0);
    ++  sqlite3_free(zSql);
    ++
    ++  return rc;
    ++}
    ++
    ++/*
    ++** This function is called as part of sqlite3_expert_analyze(). Candidate
    ++** indexes have already been created in database sqlite3expert.dbm, this
    ++** function populates sqlite_stat1 table in the same database.
    ++**
    ++** The stat1 data is generated by querying the 
    ++*/
    ++static int idxPopulateStat1(sqlite3expert *p, char **pzErr){
    ++  int rc = SQLITE_OK;
    ++  int nMax =0;
    ++  struct IdxRemCtx *pCtx = 0;
    ++  struct IdxSampleCtx samplectx; 
    ++  int i;
    ++  i64 iPrev = -100000;
    ++  sqlite3_stmt *pAllIndex = 0;
    ++  sqlite3_stmt *pIndexXInfo = 0;
    ++  sqlite3_stmt *pWrite = 0;
    ++
    ++  const char *zAllIndex =
    ++    "SELECT s.rowid, s.name, l.name FROM "
    ++    "  sqlite_master AS s, "
    ++    "  pragma_index_list(s.name) AS l "
    ++    "WHERE s.type = 'table'";
    ++  const char *zIndexXInfo = 
    ++    "SELECT name, coll FROM pragma_index_xinfo(?) WHERE key";
    ++  const char *zWrite = "INSERT INTO sqlite_stat1 VALUES(?, ?, ?)";
    ++
    ++  /* If iSample==0, no sqlite_stat1 data is required. */
    ++  if( p->iSample==0 ) return SQLITE_OK;
    ++
    ++  rc = idxLargestIndex(p->dbm, &nMax, pzErr);
    ++  if( nMax<=0 || rc!=SQLITE_OK ) return rc;
    ++
    ++  rc = sqlite3_exec(p->dbm, "ANALYZE; PRAGMA writable_schema=1", 0, 0, 0);
    ++
    ++  if( rc==SQLITE_OK ){
    ++    int nByte = sizeof(struct IdxRemCtx) + (sizeof(struct IdxRemSlot) * nMax);
    ++    pCtx = (struct IdxRemCtx*)idxMalloc(&rc, nByte);
    ++  }
    ++
    ++  if( rc==SQLITE_OK ){
    ++    sqlite3 *dbrem = (p->iSample==100 ? p->db : p->dbv);
    ++    rc = sqlite3_create_function(
    ++        dbrem, "rem", 2, SQLITE_UTF8, (void*)pCtx, idxRemFunc, 0, 0
    ++    );
    ++  }
    ++  if( rc==SQLITE_OK ){
    ++    rc = sqlite3_create_function(
    ++        p->db, "sample", 0, SQLITE_UTF8, (void*)&samplectx, idxSampleFunc, 0, 0
    ++    );
    ++  }
    ++
    ++  if( rc==SQLITE_OK ){
    ++    pCtx->nSlot = nMax+1;
    ++    rc = idxPrepareStmt(p->dbm, &pAllIndex, pzErr, zAllIndex);
    ++  }
    ++  if( rc==SQLITE_OK ){
    ++    rc = idxPrepareStmt(p->dbm, &pIndexXInfo, pzErr, zIndexXInfo);
    ++  }
    ++  if( rc==SQLITE_OK ){
    ++    rc = idxPrepareStmt(p->dbm, &pWrite, pzErr, zWrite);
    ++  }
    ++
    ++  while( rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pAllIndex) ){
    ++    i64 iRowid = sqlite3_column_int64(pAllIndex, 0);
    ++    const char *zTab = (const char*)sqlite3_column_text(pAllIndex, 1);
    ++    const char *zIdx = (const char*)sqlite3_column_text(pAllIndex, 2);
    ++    if( p->iSample<100 && iPrev!=iRowid ){
    ++      samplectx.target = (double)p->iSample / 100.0;
    ++      samplectx.iTarget = p->iSample;
    ++      samplectx.nRow = 0.0;
    ++      samplectx.nRet = 0.0;
    ++      rc = idxBuildSampleTable(p, zTab);
    ++      if( rc!=SQLITE_OK ) break;
    ++    }
    ++    rc = idxPopulateOneStat1(p, pIndexXInfo, pWrite, zTab, zIdx, pzErr);
    ++    iPrev = iRowid;
    ++  }
    ++  if( rc==SQLITE_OK && p->iSample<100 ){
    ++    rc = sqlite3_exec(p->dbv, 
    ++        "DROP TABLE IF EXISTS temp." UNIQUE_TABLE_NAME, 0,0,0
    ++    );
    ++  }
    ++
    ++  idxFinalize(&rc, pAllIndex);
    ++  idxFinalize(&rc, pIndexXInfo);
    ++  idxFinalize(&rc, pWrite);
    ++
    ++  for(i=0; i<pCtx->nSlot; i++){
    ++    sqlite3_free(pCtx->aSlot[i].z);
    ++  }
    ++  sqlite3_free(pCtx);
    ++
    ++  if( rc==SQLITE_OK ){
    ++    rc = sqlite3_exec(p->dbm, "ANALYZE sqlite_master", 0, 0, 0);
    ++  }
    ++
    ++  sqlite3_exec(p->db, "DROP TABLE IF EXISTS temp."UNIQUE_TABLE_NAME,0,0,0);
    ++  return rc;
    ++}
    ++
    ++/*
    ++** Allocate a new sqlite3expert object.
    ++*/
    ++sqlite3expert *sqlite3_expert_new(sqlite3 *db, char **pzErrmsg){
    ++  int rc = SQLITE_OK;
    ++  sqlite3expert *pNew;
    ++
    ++  pNew = (sqlite3expert*)idxMalloc(&rc, sizeof(sqlite3expert));
    ++
    ++  /* Open two in-memory databases to work with. The "vtab database" (dbv)
    ++  ** will contain a virtual table corresponding to each real table in
    ++  ** the user database schema, and a copy of each view. It is used to
    ++  ** collect information regarding the WHERE, ORDER BY and other clauses
    ++  ** of the user's query.
    ++  */
    ++  if( rc==SQLITE_OK ){
    ++    pNew->db = db;
    ++    pNew->iSample = 100;
    ++    rc = sqlite3_open(":memory:", &pNew->dbv);
    ++  }
    ++  if( rc==SQLITE_OK ){
    ++    rc = sqlite3_open(":memory:", &pNew->dbm);
    ++    if( rc==SQLITE_OK ){
    ++      sqlite3_db_config(pNew->dbm, SQLITE_DBCONFIG_TRIGGER_EQP, 1, (int*)0);
    ++    }
    ++  }
    ++  
    ++
    ++  /* Copy the entire schema of database [db] into [dbm]. */
    ++  if( rc==SQLITE_OK ){
    ++    sqlite3_stmt *pSql;
    ++    rc = idxPrintfPrepareStmt(pNew->db, &pSql, pzErrmsg, 
    ++        "SELECT sql FROM sqlite_master WHERE name NOT LIKE 'sqlite_%%'"
    ++        " AND sql NOT LIKE 'CREATE VIRTUAL %%'"
    ++    );
    ++    while( rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pSql) ){
    ++      const char *zSql = (const char*)sqlite3_column_text(pSql, 0);
    ++      rc = sqlite3_exec(pNew->dbm, zSql, 0, 0, pzErrmsg);
    ++    }
    ++    idxFinalize(&rc, pSql);
    ++  }
    ++
    ++  /* Create the vtab schema */
    ++  if( rc==SQLITE_OK ){
    ++    rc = idxCreateVtabSchema(pNew, pzErrmsg);
    ++  }
    ++
    ++  /* Register the auth callback with dbv */
    ++  if( rc==SQLITE_OK ){
    ++    sqlite3_set_authorizer(pNew->dbv, idxAuthCallback, (void*)pNew);
    ++  }
    ++
    ++  /* If an error has occurred, free the new object and reutrn NULL. Otherwise,
    ++  ** return the new sqlite3expert handle.  */
    ++  if( rc!=SQLITE_OK ){
    ++    sqlite3_expert_destroy(pNew);
    ++    pNew = 0;
    ++  }
    ++  return pNew;
    ++}
    ++
    ++/*
    ++** Configure an sqlite3expert object.
    ++*/
    ++int sqlite3_expert_config(sqlite3expert *p, int op, ...){
    ++  int rc = SQLITE_OK;
    ++  va_list ap;
    ++  va_start(ap, op);
    ++  switch( op ){
    ++    case EXPERT_CONFIG_SAMPLE: {
    ++      int iVal = va_arg(ap, int);
    ++      if( iVal<0 ) iVal = 0;
    ++      if( iVal>100 ) iVal = 100;
    ++      p->iSample = iVal;
    ++      break;
    ++    }
    ++    default:
    ++      rc = SQLITE_NOTFOUND;
    ++      break;
    ++  }
    ++
    ++  va_end(ap);
    ++  return rc;
    ++}
    ++
    ++/*
    ++** Add an SQL statement to the analysis.
    ++*/
    ++int sqlite3_expert_sql(
    ++  sqlite3expert *p,               /* From sqlite3_expert_new() */
    ++  const char *zSql,               /* SQL statement to add */
    ++  char **pzErr                    /* OUT: Error message (if any) */
    ++){
    ++  IdxScan *pScanOrig = p->pScan;
    ++  IdxStatement *pStmtOrig = p->pStatement;
    ++  int rc = SQLITE_OK;
    ++  const char *zStmt = zSql;
    ++
    ++  if( p->bRun ) return SQLITE_MISUSE;
    ++
    ++  while( rc==SQLITE_OK && zStmt && zStmt[0] ){
    ++    sqlite3_stmt *pStmt = 0;
    ++    rc = sqlite3_prepare_v2(p->dbv, zStmt, -1, &pStmt, &zStmt);
    ++    if( rc==SQLITE_OK ){
    ++      if( pStmt ){
    ++        IdxStatement *pNew;
    ++        const char *z = sqlite3_sql(pStmt);
    ++        int n = STRLEN(z);
    ++        pNew = (IdxStatement*)idxMalloc(&rc, sizeof(IdxStatement) + n+1);
    ++        if( rc==SQLITE_OK ){
    ++          pNew->zSql = (char*)&pNew[1];
    ++          memcpy(pNew->zSql, z, n+1);
    ++          pNew->pNext = p->pStatement;
    ++          if( p->pStatement ) pNew->iId = p->pStatement->iId+1;
    ++          p->pStatement = pNew;
    ++        }
    ++        sqlite3_finalize(pStmt);
    ++      }
    ++    }else{
    ++      idxDatabaseError(p->dbv, pzErr);
    ++    }
    ++  }
    ++
    ++  if( rc!=SQLITE_OK ){
    ++    idxScanFree(p->pScan, pScanOrig);
    ++    idxStatementFree(p->pStatement, pStmtOrig);
    ++    p->pScan = pScanOrig;
    ++    p->pStatement = pStmtOrig;
    ++  }
    ++
    ++  return rc;
    ++}
    ++
    ++int sqlite3_expert_analyze(sqlite3expert *p, char **pzErr){
    ++  int rc;
    ++  IdxHashEntry *pEntry;
    ++
    ++  /* Do trigger processing to collect any extra IdxScan structures */
    ++  rc = idxProcessTriggers(p, pzErr);
    ++
    ++  /* Create candidate indexes within the in-memory database file */
    ++  if( rc==SQLITE_OK ){
    ++    rc = idxCreateCandidates(p);
    ++  }
    ++
    ++  /* Generate the stat1 data */
    ++  if( rc==SQLITE_OK ){
    ++    rc = idxPopulateStat1(p, pzErr);
    ++  }
    ++
    ++  /* Formulate the EXPERT_REPORT_CANDIDATES text */
    ++  for(pEntry=p->hIdx.pFirst; pEntry; pEntry=pEntry->pNext){
    ++    p->zCandidates = idxAppendText(&rc, p->zCandidates, 
    ++        "%s;%s%s\n", pEntry->zVal, 
    ++        pEntry->zVal2 ? " -- stat1: " : "", pEntry->zVal2
    ++    );
    ++  }
    ++
    ++  /* Figure out which of the candidate indexes are preferred by the query
    ++  ** planner and report the results to the user.  */
    ++  if( rc==SQLITE_OK ){
    ++    rc = idxFindIndexes(p, pzErr);
    ++  }
    ++
    ++  if( rc==SQLITE_OK ){
    ++    p->bRun = 1;
    ++  }
    ++  return rc;
    ++}
    ++
    ++/*
    ++** Return the total number of statements that have been added to this
    ++** sqlite3expert using sqlite3_expert_sql().
    ++*/
    ++int sqlite3_expert_count(sqlite3expert *p){
    ++  int nRet = 0;
    ++  if( p->pStatement ) nRet = p->pStatement->iId+1;
    ++  return nRet;
    ++}
    ++
    ++/*
    ++** Return a component of the report.
    ++*/
    ++const char *sqlite3_expert_report(sqlite3expert *p, int iStmt, int eReport){
    ++  const char *zRet = 0;
    ++  IdxStatement *pStmt;
    ++
    ++  if( p->bRun==0 ) return 0;
    ++  for(pStmt=p->pStatement; pStmt && pStmt->iId!=iStmt; pStmt=pStmt->pNext);
    ++  switch( eReport ){
    ++    case EXPERT_REPORT_SQL:
    ++      if( pStmt ) zRet = pStmt->zSql;
    ++      break;
    ++    case EXPERT_REPORT_INDEXES:
    ++      if( pStmt ) zRet = pStmt->zIdx;
    ++      break;
    ++    case EXPERT_REPORT_PLAN:
    ++      if( pStmt ) zRet = pStmt->zEQP;
    ++      break;
    ++    case EXPERT_REPORT_CANDIDATES:
    ++      zRet = p->zCandidates;
    ++      break;
    ++  }
    ++  return zRet;
    ++}
    ++
    ++/*
    ++** Free an sqlite3expert object.
    ++*/
    ++void sqlite3_expert_destroy(sqlite3expert *p){
    ++  if( p ){
    ++    sqlite3_close(p->dbm);
    ++    sqlite3_close(p->dbv);
    ++    idxScanFree(p->pScan, 0);
    ++    idxStatementFree(p->pStatement, 0);
    ++    idxTableFree(p->pTable);
    ++    idxWriteFree(p->pWrite);
    ++    idxHashClear(&p->hIdx);
    ++    sqlite3_free(p->zCandidates);
    ++    sqlite3_free(p);
    ++  }
    ++}
    ++
    ++#endif /* ifndef SQLITE_OMIT_VIRTUAL_TABLE */
    ++
    ++/************************* End ../ext/expert/sqlite3expert.c ********************/
    ++
    ++#if defined(SQLITE_ENABLE_SESSION)
    ++/*
    ++** State information for a single open session
    ++*/
    ++typedef struct OpenSession OpenSession;
    ++struct OpenSession {
    ++  char *zName;             /* Symbolic name for this session */
    ++  int nFilter;             /* Number of xFilter rejection GLOB patterns */
    ++  char **azFilter;         /* Array of xFilter rejection GLOB patterns */
    ++  sqlite3_session *p;      /* The open session */
    ++};
    ++#endif
    ++
    ++/*
    ++** Shell output mode information from before ".explain on",
    ++** saved so that it can be restored by ".explain off"
    ++*/
    ++typedef struct SavedModeInfo SavedModeInfo;
    ++struct SavedModeInfo {
    ++  int valid;          /* Is there legit data in here? */
    ++  int mode;           /* Mode prior to ".explain on" */
    ++  int showHeader;     /* The ".header" setting prior to ".explain on" */
    ++  int colWidth[100];  /* Column widths prior to ".explain on" */
    ++};
    ++
    ++typedef struct ExpertInfo ExpertInfo;
    ++struct ExpertInfo {
    ++  sqlite3expert *pExpert;
    ++  int bVerbose;
    ++};
    ++
    ++/*
    ++** State information about the database connection is contained in an
    ++** instance of the following structure.
    ++*/
    ++typedef struct ShellState ShellState;
    ++struct ShellState {
    ++  sqlite3 *db;           /* The database */
    ++  u8 autoExplain;        /* Automatically turn on .explain mode */
    ++  u8 autoEQP;            /* Run EXPLAIN QUERY PLAN prior to seach SQL stmt */
    ++  u8 statsOn;            /* True to display memory stats before each finalize */
    ++  u8 scanstatsOn;        /* True to display scan stats before each finalize */
    ++  u8 openMode;           /* SHELL_OPEN_NORMAL, _APPENDVFS, or _ZIPFILE */
    ++  u8 doXdgOpen;          /* Invoke start/open/xdg-open in output_reset() */
    ++  int outCount;          /* Revert to stdout when reaching zero */
    ++  int cnt;               /* Number of records displayed so far */
    ++  FILE *out;             /* Write results here */
    ++  FILE *traceOut;        /* Output for sqlite3_trace() */
    ++  int nErr;              /* Number of errors seen */
    ++  int mode;              /* An output mode setting */
    ++  int modePrior;         /* Saved mode */
    ++  int cMode;             /* temporary output mode for the current query */
    ++  int normalMode;        /* Output mode before ".explain on" */
    ++  int writableSchema;    /* True if PRAGMA writable_schema=ON */
    ++  int showHeader;        /* True to show column names in List or Column mode */
    ++  int nCheck;            /* Number of ".check" commands run */
    ++  unsigned shellFlgs;    /* Various flags */
    ++  char *zDestTable;      /* Name of destination table when MODE_Insert */
    ++  char *zTempFile;       /* Temporary file that might need deleting */
    ++  char zTestcase[30];    /* Name of current test case */
    ++  char colSeparator[20]; /* Column separator character for several modes */
    ++  char rowSeparator[20]; /* Row separator character for MODE_Ascii */
    ++  char colSepPrior[20];  /* Saved column separator */
    ++  char rowSepPrior[20];  /* Saved row separator */
    ++  int colWidth[100];     /* Requested width of each column when in column mode*/
    ++  int actualWidth[100];  /* Actual width of each column */
    ++  char nullValue[20];    /* The text to print when a NULL comes back from
    ++                         ** the database */
    ++  char outfile[FILENAME_MAX]; /* Filename for *out */
    ++  const char *zDbFilename;    /* name of the database file */
    ++  char *zFreeOnClose;         /* Filename to free when closing */
    ++  const char *zVfs;           /* Name of VFS to use */
    ++  sqlite3_stmt *pStmt;   /* Current statement if any. */
    ++  FILE *pLog;            /* Write log output here */
    ++  int *aiIndent;         /* Array of indents used in MODE_Explain */
    ++  int nIndent;           /* Size of array aiIndent[] */
    ++  int iIndent;           /* Index of current op in aiIndent[] */
    ++#if defined(SQLITE_ENABLE_SESSION)
    ++  int nSession;             /* Number of active sessions */
    ++  OpenSession aSession[4];  /* Array of sessions.  [0] is in focus. */
    ++#endif
    ++  ExpertInfo expert;        /* Valid if previous command was ".expert OPT..." */
    ++};
    ++
    ++
    ++/* Allowed values for ShellState.autoEQP
    ++*/
    ++#define AUTOEQP_off      0
    ++#define AUTOEQP_on       1
    ++#define AUTOEQP_trigger  2
    ++#define AUTOEQP_full     3
    ++
    ++/* Allowed values for ShellState.openMode
    ++*/
    ++#define SHELL_OPEN_UNSPEC     0      /* No open-mode specified */
    ++#define SHELL_OPEN_NORMAL     1      /* Normal database file */
    ++#define SHELL_OPEN_APPENDVFS  2      /* Use appendvfs */
    ++#define SHELL_OPEN_ZIPFILE    3      /* Use the zipfile virtual table */
    ++
    ++/*
    ++** These are the allowed shellFlgs values
    ++*/
    ++#define SHFLG_Pagecache      0x00000001 /* The --pagecache option is used */
    ++#define SHFLG_Lookaside      0x00000002 /* Lookaside memory is used */
    ++#define SHFLG_Backslash      0x00000004 /* The --backslash option is used */
    ++#define SHFLG_PreserveRowid  0x00000008 /* .dump preserves rowid values */
    ++#define SHFLG_Newlines       0x00000010 /* .dump --newline flag */
    ++#define SHFLG_CountChanges   0x00000020 /* .changes setting */
    ++#define SHFLG_Echo           0x00000040 /* .echo or --echo setting */
    ++
    ++/*
    ++** Macros for testing and setting shellFlgs
    ++*/
    ++#define ShellHasFlag(P,X)    (((P)->shellFlgs & (X))!=0)
    ++#define ShellSetFlag(P,X)    ((P)->shellFlgs|=(X))
    ++#define ShellClearFlag(P,X)  ((P)->shellFlgs&=(~(X)))
    ++
    ++/*
    ++** These are the allowed modes.
    ++*/
    ++#define MODE_Line     0  /* One column per line.  Blank line between records */
    ++#define MODE_Column   1  /* One record per line in neat columns */
    ++#define MODE_List     2  /* One record per line with a separator */
    ++#define MODE_Semi     3  /* Same as MODE_List but append ";" to each line */
    ++#define MODE_Html     4  /* Generate an XHTML table */
    ++#define MODE_Insert   5  /* Generate SQL "insert" statements */
    ++#define MODE_Quote    6  /* Quote values as for SQL */
    ++#define MODE_Tcl      7  /* Generate ANSI-C or TCL quoted elements */
    ++#define MODE_Csv      8  /* Quote strings, numbers are plain */
    ++#define MODE_Explain  9  /* Like MODE_Column, but do not truncate data */
    ++#define MODE_Ascii   10  /* Use ASCII unit and record separators (0x1F/0x1E) */
    ++#define MODE_Pretty  11  /* Pretty-print schemas */
    ++
    ++static const char *modeDescr[] = {
    ++  "line",
    ++  "column",
    ++  "list",
    ++  "semi",
    ++  "html",
    ++  "insert",
    ++  "quote",
    ++  "tcl",
    ++  "csv",
    ++  "explain",
    ++  "ascii",
    ++  "prettyprint",
    ++};
    ++
    ++/*
    ++** These are the column/row/line separators used by the various
    ++** import/export modes.
    ++*/
    ++#define SEP_Column    "|"
    ++#define SEP_Row       "\n"
    ++#define SEP_Tab       "\t"
    ++#define SEP_Space     " "
    ++#define SEP_Comma     ","
    ++#define SEP_CrLf      "\r\n"
    ++#define SEP_Unit      "\x1F"
    ++#define SEP_Record    "\x1E"
    ++
    ++/*
    ++** A callback for the sqlite3_log() interface.
    ++*/
    ++static void shellLog(void *pArg, int iErrCode, const char *zMsg){
    ++  ShellState *p = (ShellState*)pArg;
    ++  if( p->pLog==0 ) return;
    ++  utf8_printf(p->pLog, "(%d) %s\n", iErrCode, zMsg);
    ++  fflush(p->pLog);
    ++}
    ++
    ++/*
    ++** SQL function:  shell_putsnl(X)
    ++**
    ++** Write the text X to the screen (or whatever output is being directed)
    ++** adding a newline at the end, and then return X.
    ++*/
    ++static void shellPutsFunc(
    ++  sqlite3_context *pCtx,
    ++  int nVal,
    ++  sqlite3_value **apVal
    ++){
    ++  ShellState *p = (ShellState*)sqlite3_user_data(pCtx);
    ++  (void)nVal;
    ++  utf8_printf(p->out, "%s\n", sqlite3_value_text(apVal[0]));
    ++  sqlite3_result_value(pCtx, apVal[0]);
    ++}
    ++
    ++/*
    ++** SQL function:   edit(VALUE)
    ++**                 edit(VALUE,EDITOR)
    ++**
    ++** These steps:
    ++**
    ++**     (1) Write VALUE into a temporary file.
    ++**     (2) Run program EDITOR on that temporary file.
    ++**     (3) Read the temporary file back and return its content as the result.
    ++**     (4) Delete the temporary file
    ++**
    ++** If the EDITOR argument is omitted, use the value in the VISUAL
    ++** environment variable.  If still there is no EDITOR, through an error.
    ++**
    ++** Also throw an error if the EDITOR program returns a non-zero exit code.
    ++*/
    ++static void editFunc(
    ++  sqlite3_context *context,
    ++  int argc,
    ++  sqlite3_value **argv
    ++){
    ++  const char *zEditor;
    ++  char *zTempFile = 0;
    ++  sqlite3 *db;
    ++  char *zCmd = 0;
    ++  int bBin;
    ++  int rc;
    ++  FILE *f = 0;
    ++  sqlite3_int64 sz;
    ++  sqlite3_int64 x;
    ++  unsigned char *p = 0;
    ++
    ++  if( argc==2 ){
    ++    zEditor = (const char*)sqlite3_value_text(argv[1]);
    ++  }else{
    ++    zEditor = getenv("VISUAL");
    ++  }
    ++  if( zEditor==0 ){
    ++    sqlite3_result_error(context, "no editor for edit()", -1);
    ++    return;
    ++  }
    ++  if( sqlite3_value_type(argv[0])==SQLITE_NULL ){
    ++    sqlite3_result_error(context, "NULL input to edit()", -1);
    ++    return;
    ++  }
    ++  db = sqlite3_context_db_handle(context);
    ++  zTempFile = 0;
    ++  sqlite3_file_control(db, 0, SQLITE_FCNTL_TEMPFILENAME, &zTempFile);
    ++  if( zTempFile==0 ){
    ++    sqlite3_uint64 r = 0;
    ++    sqlite3_randomness(sizeof(r), &r);
    ++    zTempFile = sqlite3_mprintf("temp%llx", r);
    ++    if( zTempFile==0 ){
    ++      sqlite3_result_error_nomem(context);
    ++      return;
    ++    }
    ++  }
    ++  bBin = sqlite3_value_type(argv[0])==SQLITE_BLOB;
    ++  f = fopen(zTempFile, bBin ? "wb" : "w");
    ++  if( f==0 ){
    ++    sqlite3_result_error(context, "edit() cannot open temp file", -1);
    ++    goto edit_func_end;
    ++  }
    ++  sz = sqlite3_value_bytes(argv[0]);
    ++  if( bBin ){
    ++    x = fwrite(sqlite3_value_blob(argv[0]), 1, sz, f);
    ++  }else{
    ++    x = fwrite(sqlite3_value_text(argv[0]), 1, sz, f);
    ++  }
    ++  fclose(f);
    ++  f = 0;
    ++  if( x!=sz ){
    ++    sqlite3_result_error(context, "edit() could not write the whole file", -1);
    ++    goto edit_func_end;
    ++  }
    ++  zCmd = sqlite3_mprintf("%s \"%s\"", zEditor, zTempFile);
    ++  if( zCmd==0 ){
    ++    sqlite3_result_error_nomem(context);
    ++    goto edit_func_end;
    ++  }
    ++  rc = system(zCmd);
    ++  sqlite3_free(zCmd);
    ++  if( rc ){
    ++    sqlite3_result_error(context, "EDITOR returned non-zero", -1);
    ++    goto edit_func_end;
    ++  }
    ++  f = fopen(zTempFile, bBin ? "rb" : "r");
    ++  if( f==0 ){
    ++    sqlite3_result_error(context,
    ++      "edit() cannot reopen temp file after edit", -1);
    ++    goto edit_func_end;
    ++  }
    ++  fseek(f, 0, SEEK_END);
    ++  sz = ftell(f);
    ++  rewind(f);
    ++  p = sqlite3_malloc64( sz+(bBin==0) );
    ++  if( p==0 ){
    ++    sqlite3_result_error_nomem(context);
    ++    goto edit_func_end;
    ++  }
    ++  if( bBin ){
    ++    x = fread(p, 1, sz, f);
    ++  }else{
    ++    x = fread(p, 1, sz, f);
    ++    p[sz] = 0;
    ++  }
    ++  fclose(f);
    ++  f = 0;
    ++  if( x!=sz ){
    ++    sqlite3_result_error(context, "could not read back the whole file", -1);
    ++    goto edit_func_end;
    ++  }
    ++  if( bBin ){
    ++    sqlite3_result_blob(context, p, sz, sqlite3_free);
    ++  }else{
    ++    sqlite3_result_text(context, (const char*)p, sz, sqlite3_free);
    ++  }
    ++  p = 0;
    ++
    ++edit_func_end:
    ++  if( f ) fclose(f);
    ++  unlink(zTempFile);
    ++  sqlite3_free(zTempFile);
    ++  sqlite3_free(p);
    ++}
    ++
    ++/*
    ++** Save or restore the current output mode
    ++*/
    ++static void outputModePush(ShellState *p){
    ++  p->modePrior = p->mode;
    ++  memcpy(p->colSepPrior, p->colSeparator, sizeof(p->colSeparator));
    ++  memcpy(p->rowSepPrior, p->rowSeparator, sizeof(p->rowSeparator));
    ++}
    ++static void outputModePop(ShellState *p){
    ++  p->mode = p->modePrior;
    ++  memcpy(p->colSeparator, p->colSepPrior, sizeof(p->colSeparator));
    ++  memcpy(p->rowSeparator, p->rowSepPrior, sizeof(p->rowSeparator));
    ++}
    ++
    ++/*
    ++** Output the given string as a hex-encoded blob (eg. X'1234' )
    ++*/
    ++static void output_hex_blob(FILE *out, const void *pBlob, int nBlob){
    ++  int i;
    ++  char *zBlob = (char *)pBlob;
    ++  raw_printf(out,"X'");
    ++  for(i=0; i<nBlob; i++){ raw_printf(out,"%02x",zBlob[i]&0xff); }
    ++  raw_printf(out,"'");
    ++}
    ++
    ++/*
    ++** Find a string that is not found anywhere in z[].  Return a pointer
    ++** to that string.
    ++**
    ++** Try to use zA and zB first.  If both of those are already found in z[]
    ++** then make up some string and store it in the buffer zBuf.
    ++*/
    ++static const char *unused_string(
    ++  const char *z,                    /* Result must not appear anywhere in z */
    ++  const char *zA, const char *zB,   /* Try these first */
    ++  char *zBuf                        /* Space to store a generated string */
    ++){
    ++  unsigned i = 0;
    ++  if( strstr(z, zA)==0 ) return zA;
    ++  if( strstr(z, zB)==0 ) return zB;
    ++  do{
    ++    sqlite3_snprintf(20,zBuf,"(%s%u)", zA, i++);
    ++  }while( strstr(z,zBuf)!=0 );
    ++  return zBuf;
    ++}
    ++
    ++/*
    ++** Output the given string as a quoted string using SQL quoting conventions.
    ++**
    ++** See also: output_quoted_escaped_string()
    ++*/
    ++static void output_quoted_string(FILE *out, const char *z){
    ++  int i;
    ++  char c;
    ++  setBinaryMode(out, 1);
    ++  for(i=0; (c = z[i])!=0 && c!='\''; i++){}
    ++  if( c==0 ){
    ++    utf8_printf(out,"'%s'",z);
    ++  }else{
    ++    raw_printf(out, "'");
    ++    while( *z ){
    ++      for(i=0; (c = z[i])!=0 && c!='\''; i++){}
    ++      if( c=='\'' ) i++;
    ++      if( i ){
    ++        utf8_printf(out, "%.*s", i, z);
    ++        z += i;
    ++      }
    ++      if( c=='\'' ){
    ++        raw_printf(out, "'");
    ++        continue;
    ++      }
    ++      if( c==0 ){
    ++        break;
    ++      }
    ++      z++;
    ++    }
    ++    raw_printf(out, "'");
    ++  }
    ++  setTextMode(out, 1);
    ++}
    ++
    ++/*
    ++** Output the given string as a quoted string using SQL quoting conventions.
    ++** Additionallly , escape the "\n" and "\r" characters so that they do not
    ++** get corrupted by end-of-line translation facilities in some operating
    ++** systems.
    ++**
    ++** This is like output_quoted_string() but with the addition of the \r\n
    ++** escape mechanism.
    ++*/
    ++static void output_quoted_escaped_string(FILE *out, const char *z){
    ++  int i;
    ++  char c;
    ++  setBinaryMode(out, 1);
    ++  for(i=0; (c = z[i])!=0 && c!='\'' && c!='\n' && c!='\r'; i++){}
    ++  if( c==0 ){
    ++    utf8_printf(out,"'%s'",z);
    ++  }else{
    ++    const char *zNL = 0;
    ++    const char *zCR = 0;
    ++    int nNL = 0;
    ++    int nCR = 0;
    ++    char zBuf1[20], zBuf2[20];
    ++    for(i=0; z[i]; i++){
    ++      if( z[i]=='\n' ) nNL++;
    ++      if( z[i]=='\r' ) nCR++;
    ++    }
    ++    if( nNL ){
    ++      raw_printf(out, "replace(");
    ++      zNL = unused_string(z, "\\n", "\\012", zBuf1);
    ++    }
    ++    if( nCR ){
    ++      raw_printf(out, "replace(");
    ++      zCR = unused_string(z, "\\r", "\\015", zBuf2);
    ++    }
    ++    raw_printf(out, "'");
    ++    while( *z ){
    ++      for(i=0; (c = z[i])!=0 && c!='\n' && c!='\r' && c!='\''; i++){}
    ++      if( c=='\'' ) i++;
    ++      if( i ){
    ++        utf8_printf(out, "%.*s", i, z);
    ++        z += i;
    ++      }
    ++      if( c=='\'' ){
    ++        raw_printf(out, "'");
    ++        continue;
    ++      }
    ++      if( c==0 ){
    ++        break;
    ++      }
    ++      z++;
    ++      if( c=='\n' ){
    ++        raw_printf(out, "%s", zNL);
    ++        continue;
    ++      }
    ++      raw_printf(out, "%s", zCR);
    ++    }
    ++    raw_printf(out, "'");
    ++    if( nCR ){
    ++      raw_printf(out, ",'%s',char(13))", zCR);
    ++    }
    ++    if( nNL ){
    ++      raw_printf(out, ",'%s',char(10))", zNL);
    ++    }
    ++  }
    ++  setTextMode(out, 1);
    ++}
    ++
    ++/*
    ++** Output the given string as a quoted according to C or TCL quoting rules.
    ++*/
    ++static void output_c_string(FILE *out, const char *z){
    ++  unsigned int c;
    ++  fputc('"', out);
    ++  while( (c = *(z++))!=0 ){
    ++    if( c=='\\' ){
    ++      fputc(c, out);
    ++      fputc(c, out);
    ++    }else if( c=='"' ){
    ++      fputc('\\', out);
    ++      fputc('"', out);
    ++    }else if( c=='\t' ){
    ++      fputc('\\', out);
    ++      fputc('t', out);
    ++    }else if( c=='\n' ){
    ++      fputc('\\', out);
    ++      fputc('n', out);
    ++    }else if( c=='\r' ){
    ++      fputc('\\', out);
    ++      fputc('r', out);
    ++    }else if( !isprint(c&0xff) ){
    ++      raw_printf(out, "\\%03o", c&0xff);
    ++    }else{
    ++      fputc(c, out);
    ++    }
    ++  }
    ++  fputc('"', out);
    ++}
    ++
    ++/*
    ++** Output the given string with characters that are special to
    ++** HTML escaped.
    ++*/
    ++static void output_html_string(FILE *out, const char *z){
    ++  int i;
    ++  if( z==0 ) z = "";
    ++  while( *z ){
    ++    for(i=0;   z[i]
    ++            && z[i]!='<'
    ++            && z[i]!='&'
    ++            && z[i]!='>'
    ++            && z[i]!='\"'
    ++            && z[i]!='\'';
    ++        i++){}
    ++    if( i>0 ){
    ++      utf8_printf(out,"%.*s",i,z);
    ++    }
    ++    if( z[i]=='<' ){
    ++      raw_printf(out,"&lt;");
    ++    }else if( z[i]=='&' ){
    ++      raw_printf(out,"&amp;");
    ++    }else if( z[i]=='>' ){
    ++      raw_printf(out,"&gt;");
    ++    }else if( z[i]=='\"' ){
    ++      raw_printf(out,"&quot;");
    ++    }else if( z[i]=='\'' ){
    ++      raw_printf(out,"&#39;");
    ++    }else{
    ++      break;
    ++    }
    ++    z += i + 1;
    ++  }
    ++}
    ++
    ++/*
    ++** If a field contains any character identified by a 1 in the following
    ++** array, then the string must be quoted for CSV.
    ++*/
    ++static const char needCsvQuote[] = {
    ++  1, 1, 1, 1, 1, 1, 1, 1,   1, 1, 1, 1, 1, 1, 1, 1,
    ++  1, 1, 1, 1, 1, 1, 1, 1,   1, 1, 1, 1, 1, 1, 1, 1,
    ++  1, 0, 1, 0, 0, 0, 0, 1,   0, 0, 0, 0, 0, 0, 0, 0,
    ++  0, 0, 0, 0, 0, 0, 0, 0,   0, 0, 0, 0, 0, 0, 0, 0,
    ++  0, 0, 0, 0, 0, 0, 0, 0,   0, 0, 0, 0, 0, 0, 0, 0,
    ++  0, 0, 0, 0, 0, 0, 0, 0,   0, 0, 0, 0, 0, 0, 0, 0,
    ++  0, 0, 0, 0, 0, 0, 0, 0,   0, 0, 0, 0, 0, 0, 0, 0,
    ++  0, 0, 0, 0, 0, 0, 0, 0,   0, 0, 0, 0, 0, 0, 0, 1,
    ++  1, 1, 1, 1, 1, 1, 1, 1,   1, 1, 1, 1, 1, 1, 1, 1,
    ++  1, 1, 1, 1, 1, 1, 1, 1,   1, 1, 1, 1, 1, 1, 1, 1,
    ++  1, 1, 1, 1, 1, 1, 1, 1,   1, 1, 1, 1, 1, 1, 1, 1,
    ++  1, 1, 1, 1, 1, 1, 1, 1,   1, 1, 1, 1, 1, 1, 1, 1,
    ++  1, 1, 1, 1, 1, 1, 1, 1,   1, 1, 1, 1, 1, 1, 1, 1,
    ++  1, 1, 1, 1, 1, 1, 1, 1,   1, 1, 1, 1, 1, 1, 1, 1,
    ++  1, 1, 1, 1, 1, 1, 1, 1,   1, 1, 1, 1, 1, 1, 1, 1,
    ++  1, 1, 1, 1, 1, 1, 1, 1,   1, 1, 1, 1, 1, 1, 1, 1,
    ++};
    ++
    ++/*
    ++** Output a single term of CSV.  Actually, p->colSeparator is used for
    ++** the separator, which may or may not be a comma.  p->nullValue is
    ++** the null value.  Strings are quoted if necessary.  The separator
    ++** is only issued if bSep is true.
    ++*/
    ++static void output_csv(ShellState *p, const char *z, int bSep){
    ++  FILE *out = p->out;
    ++  if( z==0 ){
    ++    utf8_printf(out,"%s",p->nullValue);
    ++  }else{
    ++    int i;
    ++    int nSep = strlen30(p->colSeparator);
    ++    for(i=0; z[i]; i++){
    ++      if( needCsvQuote[((unsigned char*)z)[i]]
    ++         || (z[i]==p->colSeparator[0] &&
    ++             (nSep==1 || memcmp(z, p->colSeparator, nSep)==0)) ){
    ++        i = 0;
    ++        break;
    ++      }
    ++    }
    ++    if( i==0 ){
    ++      char *zQuoted = sqlite3_mprintf("\"%w\"", z);
    ++      utf8_printf(out, "%s", zQuoted);
    ++      sqlite3_free(zQuoted);
    ++    }else{
    ++      utf8_printf(out, "%s", z);
    ++    }
    ++  }
    ++  if( bSep ){
    ++    utf8_printf(p->out, "%s", p->colSeparator);
    ++  }
    ++}
    ++
    ++/*
    ++** This routine runs when the user presses Ctrl-C
    ++*/
    ++static void interrupt_handler(int NotUsed){
    ++  UNUSED_PARAMETER(NotUsed);
    ++  seenInterrupt++;
    ++  if( seenInterrupt>2 ) exit(1);
    ++  if( globalDb ) sqlite3_interrupt(globalDb);
    ++}
    ++
    ++#if (defined(_WIN32) || defined(WIN32)) && !defined(_WIN32_WCE)
    ++/*
    ++** This routine runs for console events (e.g. Ctrl-C) on Win32
    ++*/
    ++static BOOL WINAPI ConsoleCtrlHandler(
    ++  DWORD dwCtrlType /* One of the CTRL_*_EVENT constants */
    ++){
    ++  if( dwCtrlType==CTRL_C_EVENT ){
    ++    interrupt_handler(0);
    ++    return TRUE;
    ++  }
    ++  return FALSE;
    ++}
    ++#endif
    ++
    ++#ifndef SQLITE_OMIT_AUTHORIZATION
    ++/*
    ++** When the ".auth ON" is set, the following authorizer callback is
    ++** invoked.  It always returns SQLITE_OK.
    ++*/
    ++static int shellAuth(
    ++  void *pClientData,
    ++  int op,
    ++  const char *zA1,
    ++  const char *zA2,
    ++  const char *zA3,
    ++  const char *zA4
    ++){
    ++  ShellState *p = (ShellState*)pClientData;
    ++  static const char *azAction[] = { 0,
    ++     "CREATE_INDEX",         "CREATE_TABLE",         "CREATE_TEMP_INDEX",
    ++     "CREATE_TEMP_TABLE",    "CREATE_TEMP_TRIGGER",  "CREATE_TEMP_VIEW",
    ++     "CREATE_TRIGGER",       "CREATE_VIEW",          "DELETE",
    ++     "DROP_INDEX",           "DROP_TABLE",           "DROP_TEMP_INDEX",
    ++     "DROP_TEMP_TABLE",      "DROP_TEMP_TRIGGER",    "DROP_TEMP_VIEW",
    ++     "DROP_TRIGGER",         "DROP_VIEW",            "INSERT",
    ++     "PRAGMA",               "READ",                 "SELECT",
    ++     "TRANSACTION",          "UPDATE",               "ATTACH",
    ++     "DETACH",               "ALTER_TABLE",          "REINDEX",
    ++     "ANALYZE",              "CREATE_VTABLE",        "DROP_VTABLE",
    ++     "FUNCTION",             "SAVEPOINT",            "RECURSIVE"
    ++  };
    ++  int i;
    ++  const char *az[4];
    ++  az[0] = zA1;
    ++  az[1] = zA2;
    ++  az[2] = zA3;
    ++  az[3] = zA4;
    ++  utf8_printf(p->out, "authorizer: %s", azAction[op]);
    ++  for(i=0; i<4; i++){
    ++    raw_printf(p->out, " ");
    ++    if( az[i] ){
    ++      output_c_string(p->out, az[i]);
    ++    }else{
    ++      raw_printf(p->out, "NULL");
    ++    }
    ++  }
    ++  raw_printf(p->out, "\n");
    ++  return SQLITE_OK;
    ++}
    ++#endif
    ++
    ++/*
    ++** Print a schema statement.  Part of MODE_Semi and MODE_Pretty output.
    ++**
    ++** This routine converts some CREATE TABLE statements for shadow tables
    ++** in FTS3/4/5 into CREATE TABLE IF NOT EXISTS statements.
    ++*/
    ++static void printSchemaLine(FILE *out, const char *z, const char *zTail){
    ++  if( sqlite3_strglob("CREATE TABLE ['\"]*", z)==0 ){
    ++    utf8_printf(out, "CREATE TABLE IF NOT EXISTS %s%s", z+13, zTail);
    ++  }else{
    ++    utf8_printf(out, "%s%s", z, zTail);
    ++  }
    ++}
    ++static void printSchemaLineN(FILE *out, char *z, int n, const char *zTail){
    ++  char c = z[n];
    ++  z[n] = 0;
    ++  printSchemaLine(out, z, zTail);
    ++  z[n] = c;
    ++}
    ++
    ++/*
    ++** Return true if string z[] has nothing but whitespace and comments to the
    ++** end of the first line.
    ++*/
    ++static int wsToEol(const char *z){
    ++  int i;
    ++  for(i=0; z[i]; i++){
    ++    if( z[i]=='\n' ) return 1;
    ++    if( IsSpace(z[i]) ) continue;
    ++    if( z[i]=='-' && z[i+1]=='-' ) return 1;
    ++    return 0;
    ++  }
    ++  return 1;
    ++}
    ++    
    ++
    ++/*
    ++** This is the callback routine that the shell
    ++** invokes for each row of a query result.
    ++*/
    ++static int shell_callback(
    ++  void *pArg,
    ++  int nArg,        /* Number of result columns */
    ++  char **azArg,    /* Text of each result column */
    ++  char **azCol,    /* Column names */
    ++  int *aiType      /* Column types */
    ++){
    ++  int i;
    ++  ShellState *p = (ShellState*)pArg;
    ++
    ++  if( azArg==0 ) return 0;
    ++  switch( p->cMode ){
    ++    case MODE_Line: {
    ++      int w = 5;
    ++      if( azArg==0 ) break;
    ++      for(i=0; i<nArg; i++){
    ++        int len = strlen30(azCol[i] ? azCol[i] : "");
    ++        if( len>w ) w = len;
    ++      }
    ++      if( p->cnt++>0 ) utf8_printf(p->out, "%s", p->rowSeparator);
    ++      for(i=0; i<nArg; i++){
    ++        utf8_printf(p->out,"%*s = %s%s", w, azCol[i],
    ++                azArg[i] ? azArg[i] : p->nullValue, p->rowSeparator);
    ++      }
    ++      break;
    ++    }
    ++    case MODE_Explain:
    ++    case MODE_Column: {
    ++      static const int aExplainWidths[] = {4, 13, 4, 4, 4, 13, 2, 13};
    ++      const int *colWidth;
    ++      int showHdr;
    ++      char *rowSep;
    ++      if( p->cMode==MODE_Column ){
    ++        colWidth = p->colWidth;
    ++        showHdr = p->showHeader;
    ++        rowSep = p->rowSeparator;
    ++      }else{
    ++        colWidth = aExplainWidths;
    ++        showHdr = 1;
    ++        rowSep = SEP_Row;
    ++      }
    ++      if( p->cnt++==0 ){
    ++        for(i=0; i<nArg; i++){
    ++          int w, n;
    ++          if( i<ArraySize(p->colWidth) ){
    ++            w = colWidth[i];
    ++          }else{
    ++            w = 0;
    ++          }
    ++          if( w==0 ){
    ++            w = strlenChar(azCol[i] ? azCol[i] : "");
    ++            if( w<10 ) w = 10;
    ++            n = strlenChar(azArg && azArg[i] ? azArg[i] : p->nullValue);
    ++            if( w<n ) w = n;
    ++          }
    ++          if( i<ArraySize(p->actualWidth) ){
    ++            p->actualWidth[i] = w;
    ++          }
    ++          if( showHdr ){
    ++            utf8_width_print(p->out, w, azCol[i]);
    ++            utf8_printf(p->out, "%s", i==nArg-1 ? rowSep : "  ");
    ++          }
    ++        }
    ++        if( showHdr ){
    ++          for(i=0; i<nArg; i++){
    ++            int w;
    ++            if( i<ArraySize(p->actualWidth) ){
    ++               w = p->actualWidth[i];
    ++               if( w<0 ) w = -w;
    ++            }else{
    ++               w = 10;
    ++            }
    ++            utf8_printf(p->out,"%-*.*s%s",w,w,
    ++                   "----------------------------------------------------------"
    ++                   "----------------------------------------------------------",
    ++                    i==nArg-1 ? rowSep : "  ");
    ++          }
    ++        }
    ++      }
    ++      if( azArg==0 ) break;
    ++      for(i=0; i<nArg; i++){
    ++        int w;
    ++        if( i<ArraySize(p->actualWidth) ){
    ++           w = p->actualWidth[i];
    ++        }else{
    ++           w = 10;
    ++        }
    ++        if( p->cMode==MODE_Explain && azArg[i] && strlenChar(azArg[i])>w ){
    ++          w = strlenChar(azArg[i]);
    ++        }
    ++        if( i==1 && p->aiIndent && p->pStmt ){
    ++          if( p->iIndent<p->nIndent ){
    ++            utf8_printf(p->out, "%*.s", p->aiIndent[p->iIndent], "");
    ++          }
    ++          p->iIndent++;
    ++        }
    ++        utf8_width_print(p->out, w, azArg[i] ? azArg[i] : p->nullValue);
    ++        utf8_printf(p->out, "%s", i==nArg-1 ? rowSep : "  ");
    ++      }
    ++      break;
    ++    }
    ++    case MODE_Semi: {   /* .schema and .fullschema output */
    ++      printSchemaLine(p->out, azArg[0], ";\n");
    ++      break;
    ++    }
    ++    case MODE_Pretty: {  /* .schema and .fullschema with --indent */
    ++      char *z;
    ++      int j;
    ++      int nParen = 0;
    ++      char cEnd = 0;
    ++      char c;
    ++      int nLine = 0;
    ++      assert( nArg==1 );
    ++      if( azArg[0]==0 ) break;
    ++      if( sqlite3_strlike("CREATE VIEW%", azArg[0], 0)==0
    ++       || sqlite3_strlike("CREATE TRIG%", azArg[0], 0)==0
    ++      ){
    ++        utf8_printf(p->out, "%s;\n", azArg[0]);
    ++        break;
    ++      }
    ++      z = sqlite3_mprintf("%s", azArg[0]);
    ++      j = 0;
    ++      for(i=0; IsSpace(z[i]); i++){}
    ++      for(; (c = z[i])!=0; i++){
    ++        if( IsSpace(c) ){
    ++          if( z[j-1]=='\r' ) z[j-1] = '\n';
    ++          if( IsSpace(z[j-1]) || z[j-1]=='(' ) continue;
    ++        }else if( (c=='(' || c==')') && j>0 && IsSpace(z[j-1]) ){
    ++          j--;
    ++        }
    ++        z[j++] = c;
    ++      }
    ++      while( j>0 && IsSpace(z[j-1]) ){ j--; }
    ++      z[j] = 0;
    ++      if( strlen30(z)>=79 ){
    ++        for(i=j=0; (c = z[i])!=0; i++){  /* Copy changes from z[i] back to z[j] */
    ++          if( c==cEnd ){
    ++            cEnd = 0;
    ++          }else if( c=='"' || c=='\'' || c=='`' ){
    ++            cEnd = c;
    ++          }else if( c=='[' ){
    ++            cEnd = ']';
    ++          }else if( c=='-' && z[i+1]=='-' ){
    ++            cEnd = '\n';
    ++          }else if( c=='(' ){
    ++            nParen++;
    ++          }else if( c==')' ){
    ++            nParen--;
    ++            if( nLine>0 && nParen==0 && j>0 ){
    ++              printSchemaLineN(p->out, z, j, "\n");
    ++              j = 0;
    ++            }
    ++          }
    ++          z[j++] = c;
    ++          if( nParen==1 && cEnd==0
    ++           && (c=='(' || c=='\n' || (c==',' && !wsToEol(z+i+1)))
    ++          ){
    ++            if( c=='\n' ) j--;
    ++            printSchemaLineN(p->out, z, j, "\n  ");
    ++            j = 0;
    ++            nLine++;
    ++            while( IsSpace(z[i+1]) ){ i++; }
    ++          }
    ++        }
    ++        z[j] = 0;
    ++      }
    ++      printSchemaLine(p->out, z, ";\n");
    ++      sqlite3_free(z);
    ++      break;
    ++    }
    ++    case MODE_List: {
    ++      if( p->cnt++==0 && p->showHeader ){
    ++        for(i=0; i<nArg; i++){
    ++          utf8_printf(p->out,"%s%s",azCol[i],
    ++                  i==nArg-1 ? p->rowSeparator : p->colSeparator);
    ++        }
    ++      }
    ++      if( azArg==0 ) break;
    ++      for(i=0; i<nArg; i++){
    ++        char *z = azArg[i];
    ++        if( z==0 ) z = p->nullValue;
    ++        utf8_printf(p->out, "%s", z);
    ++        if( i<nArg-1 ){
    ++          utf8_printf(p->out, "%s", p->colSeparator);
    ++        }else{
    ++          utf8_printf(p->out, "%s", p->rowSeparator);
    ++        }
    ++      }
    ++      break;
    ++    }
    ++    case MODE_Html: {
    ++      if( p->cnt++==0 && p->showHeader ){
    ++        raw_printf(p->out,"<TR>");
    ++        for(i=0; i<nArg; i++){
    ++          raw_printf(p->out,"<TH>");
    ++          output_html_string(p->out, azCol[i]);
    ++          raw_printf(p->out,"</TH>\n");
    ++        }
    ++        raw_printf(p->out,"</TR>\n");
    ++      }
    ++      if( azArg==0 ) break;
    ++      raw_printf(p->out,"<TR>");
    ++      for(i=0; i<nArg; i++){
    ++        raw_printf(p->out,"<TD>");
    ++        output_html_string(p->out, azArg[i] ? azArg[i] : p->nullValue);
    ++        raw_printf(p->out,"</TD>\n");
    ++      }
    ++      raw_printf(p->out,"</TR>\n");
    ++      break;
    ++    }
    ++    case MODE_Tcl: {
    ++      if( p->cnt++==0 && p->showHeader ){
    ++        for(i=0; i<nArg; i++){
    ++          output_c_string(p->out,azCol[i] ? azCol[i] : "");
    ++          if(i<nArg-1) utf8_printf(p->out, "%s", p->colSeparator);
    ++        }
    ++        utf8_printf(p->out, "%s", p->rowSeparator);
    ++      }
    ++      if( azArg==0 ) break;
    ++      for(i=0; i<nArg; i++){
    ++        output_c_string(p->out, azArg[i] ? azArg[i] : p->nullValue);
    ++        if(i<nArg-1) utf8_printf(p->out, "%s", p->colSeparator);
    ++      }
    ++      utf8_printf(p->out, "%s", p->rowSeparator);
    ++      break;
    ++    }
    ++    case MODE_Csv: {
    ++      setBinaryMode(p->out, 1);
    ++      if( p->cnt++==0 && p->showHeader ){
    ++        for(i=0; i<nArg; i++){
    ++          output_csv(p, azCol[i] ? azCol[i] : "", i<nArg-1);
    ++        }
    ++        utf8_printf(p->out, "%s", p->rowSeparator);
    ++      }
    ++      if( nArg>0 ){
    ++        for(i=0; i<nArg; i++){
    ++          output_csv(p, azArg[i], i<nArg-1);
    ++        }
    ++        utf8_printf(p->out, "%s", p->rowSeparator);
    ++      }
    ++      setTextMode(p->out, 1);
    ++      break;
    ++    }
    ++    case MODE_Insert: {
    ++      if( azArg==0 ) break;
    ++      utf8_printf(p->out,"INSERT INTO %s",p->zDestTable);
    ++      if( p->showHeader ){
    ++        raw_printf(p->out,"(");
    ++        for(i=0; i<nArg; i++){
    ++          if( i>0 ) raw_printf(p->out, ",");
    ++          if( quoteChar(azCol[i]) ){
    ++            char *z = sqlite3_mprintf("\"%w\"", azCol[i]);
    ++            utf8_printf(p->out, "%s", z);
    ++            sqlite3_free(z);
    ++          }else{
    ++            raw_printf(p->out, "%s", azCol[i]);
    ++          }
    ++        }
    ++        raw_printf(p->out,")");
    ++      }
    ++      p->cnt++;
    ++      for(i=0; i<nArg; i++){
    ++        raw_printf(p->out, i>0 ? "," : " VALUES(");
    ++        if( (azArg[i]==0) || (aiType && aiType[i]==SQLITE_NULL) ){
    ++          utf8_printf(p->out,"NULL");
    ++        }else if( aiType && aiType[i]==SQLITE_TEXT ){
    ++          if( ShellHasFlag(p, SHFLG_Newlines) ){
    ++            output_quoted_string(p->out, azArg[i]);
    ++          }else{
    ++            output_quoted_escaped_string(p->out, azArg[i]);
    ++          }
    ++        }else if( aiType && aiType[i]==SQLITE_INTEGER ){
    ++          utf8_printf(p->out,"%s", azArg[i]);
    ++        }else if( aiType && aiType[i]==SQLITE_FLOAT ){
    ++          char z[50];
    ++          double r = sqlite3_column_double(p->pStmt, i);
    ++          sqlite3_snprintf(50,z,"%!.20g", r);
    ++          raw_printf(p->out, "%s", z);
    ++        }else if( aiType && aiType[i]==SQLITE_BLOB && p->pStmt ){
    ++          const void *pBlob = sqlite3_column_blob(p->pStmt, i);
    ++          int nBlob = sqlite3_column_bytes(p->pStmt, i);
    ++          output_hex_blob(p->out, pBlob, nBlob);
    ++        }else if( isNumber(azArg[i], 0) ){
    ++          utf8_printf(p->out,"%s", azArg[i]);
    ++        }else if( ShellHasFlag(p, SHFLG_Newlines) ){
    ++          output_quoted_string(p->out, azArg[i]);
    ++        }else{
    ++          output_quoted_escaped_string(p->out, azArg[i]);
    ++        }
    ++      }
    ++      raw_printf(p->out,");\n");
    ++      break;
    ++    }
    ++    case MODE_Quote: {
    ++      if( azArg==0 ) break;
    ++      if( p->cnt==0 && p->showHeader ){
    ++        for(i=0; i<nArg; i++){
    ++          if( i>0 ) raw_printf(p->out, ",");
    ++          output_quoted_string(p->out, azCol[i]);
    ++        }
    ++        raw_printf(p->out,"\n");
    ++      }
    ++      p->cnt++;
    ++      for(i=0; i<nArg; i++){
    ++        if( i>0 ) raw_printf(p->out, ",");
    ++        if( (azArg[i]==0) || (aiType && aiType[i]==SQLITE_NULL) ){
    ++          utf8_printf(p->out,"NULL");
    ++        }else if( aiType && aiType[i]==SQLITE_TEXT ){
    ++          output_quoted_string(p->out, azArg[i]);
    ++        }else if( aiType && aiType[i]==SQLITE_INTEGER ){
    ++          utf8_printf(p->out,"%s", azArg[i]);
    ++        }else if( aiType && aiType[i]==SQLITE_FLOAT ){
    ++          char z[50];
    ++          double r = sqlite3_column_double(p->pStmt, i);
    ++          sqlite3_snprintf(50,z,"%!.20g", r);
    ++          raw_printf(p->out, "%s", z);
    ++        }else if( aiType && aiType[i]==SQLITE_BLOB && p->pStmt ){
    ++          const void *pBlob = sqlite3_column_blob(p->pStmt, i);
    ++          int nBlob = sqlite3_column_bytes(p->pStmt, i);
    ++          output_hex_blob(p->out, pBlob, nBlob);
    ++        }else if( isNumber(azArg[i], 0) ){
    ++          utf8_printf(p->out,"%s", azArg[i]);
    ++        }else{
    ++          output_quoted_string(p->out, azArg[i]);
    ++        }
    ++      }
    ++      raw_printf(p->out,"\n");
    ++      break;
    ++    }
    ++    case MODE_Ascii: {
    ++      if( p->cnt++==0 && p->showHeader ){
    ++        for(i=0; i<nArg; i++){
    ++          if( i>0 ) utf8_printf(p->out, "%s", p->colSeparator);
    ++          utf8_printf(p->out,"%s",azCol[i] ? azCol[i] : "");
    ++        }
    ++        utf8_printf(p->out, "%s", p->rowSeparator);
    ++      }
    ++      if( azArg==0 ) break;
    ++      for(i=0; i<nArg; i++){
    ++        if( i>0 ) utf8_printf(p->out, "%s", p->colSeparator);
    ++        utf8_printf(p->out,"%s",azArg[i] ? azArg[i] : p->nullValue);
    ++      }
    ++      utf8_printf(p->out, "%s", p->rowSeparator);
    ++      break;
    ++    }
    ++  }
    ++  return 0;
    ++}
    ++
    ++/*
    ++** This is the callback routine that the SQLite library
    ++** invokes for each row of a query result.
    ++*/
    ++static int callback(void *pArg, int nArg, char **azArg, char **azCol){
    ++  /* since we don't have type info, call the shell_callback with a NULL value */
    ++  return shell_callback(pArg, nArg, azArg, azCol, NULL);
    ++}
    ++
    ++/*
    ++** This is the callback routine from sqlite3_exec() that appends all
    ++** output onto the end of a ShellText object.
    ++*/
    ++static int captureOutputCallback(void *pArg, int nArg, char **azArg, char **az){
    ++  ShellText *p = (ShellText*)pArg;
    ++  int i;
    ++  UNUSED_PARAMETER(az);
    ++  if( azArg==0 ) return 0;
    ++  if( p->n ) appendText(p, "|", 0);
    ++  for(i=0; i<nArg; i++){
    ++    if( i ) appendText(p, ",", 0);
    ++    if( azArg[i] ) appendText(p, azArg[i], 0);
    ++  }
    ++  return 0;
    ++}
    ++
    ++/*
    ++** Generate an appropriate SELFTEST table in the main database.
    ++*/
    ++static void createSelftestTable(ShellState *p){
    ++  char *zErrMsg = 0;
    ++  sqlite3_exec(p->db,
    ++    "SAVEPOINT selftest_init;\n"
    ++    "CREATE TABLE IF NOT EXISTS selftest(\n"
    ++    "  tno INTEGER PRIMARY KEY,\n"   /* Test number */
    ++    "  op TEXT,\n"                   /* Operator:  memo run */
    ++    "  cmd TEXT,\n"                  /* Command text */
    ++    "  ans TEXT\n"                   /* Desired answer */
    ++    ");"
    ++    "CREATE TEMP TABLE [_shell$self](op,cmd,ans);\n"
    ++    "INSERT INTO [_shell$self](rowid,op,cmd)\n"
    ++    "  VALUES(coalesce((SELECT (max(tno)+100)/10 FROM selftest),10),\n"
    ++    "         'memo','Tests generated by --init');\n"
    ++    "INSERT INTO [_shell$self]\n"
    ++    "  SELECT 'run',\n"
    ++    "    'SELECT hex(sha3_query(''SELECT type,name,tbl_name,sql "
    ++                                 "FROM sqlite_master ORDER BY 2'',224))',\n"
    ++    "    hex(sha3_query('SELECT type,name,tbl_name,sql "
    ++                          "FROM sqlite_master ORDER BY 2',224));\n"
    ++    "INSERT INTO [_shell$self]\n"
    ++    "  SELECT 'run',"
    ++    "    'SELECT hex(sha3_query(''SELECT * FROM \"' ||"
    ++    "        printf('%w',name) || '\" NOT INDEXED'',224))',\n"
    ++    "    hex(sha3_query(printf('SELECT * FROM \"%w\" NOT INDEXED',name),224))\n"
    ++    "  FROM (\n"
    ++    "    SELECT name FROM sqlite_master\n"
    ++    "     WHERE type='table'\n"
    ++    "       AND name<>'selftest'\n"
    ++    "       AND coalesce(rootpage,0)>0\n"
    ++    "  )\n"
    ++    " ORDER BY name;\n"
    ++    "INSERT INTO [_shell$self]\n"
    ++    "  VALUES('run','PRAGMA integrity_check','ok');\n"
    ++    "INSERT INTO selftest(tno,op,cmd,ans)"
    ++    "  SELECT rowid*10,op,cmd,ans FROM [_shell$self];\n"
    ++    "DROP TABLE [_shell$self];"
    ++    ,0,0,&zErrMsg);
    ++  if( zErrMsg ){
    ++    utf8_printf(stderr, "SELFTEST initialization failure: %s\n", zErrMsg);
    ++    sqlite3_free(zErrMsg);
    ++  }
    ++  sqlite3_exec(p->db, "RELEASE selftest_init",0,0,0);
    ++}
    ++
    ++
    ++/*
    ++** Set the destination table field of the ShellState structure to
    ++** the name of the table given.  Escape any quote characters in the
    ++** table name.
    ++*/
    ++static void set_table_name(ShellState *p, const char *zName){
    ++  int i, n;
    ++  char cQuote;
    ++  char *z;
    ++
    ++  if( p->zDestTable ){
    ++    free(p->zDestTable);
    ++    p->zDestTable = 0;
    ++  }
    ++  if( zName==0 ) return;
    ++  cQuote = quoteChar(zName);
    ++  n = strlen30(zName);
    ++  if( cQuote ) n += n+2;
    ++  z = p->zDestTable = malloc( n+1 );
    ++  if( z==0 ){
    ++    raw_printf(stderr,"Error: out of memory\n");
    ++    exit(1);
    ++  }
    ++  n = 0;
    ++  if( cQuote ) z[n++] = cQuote;
    ++  for(i=0; zName[i]; i++){
    ++    z[n++] = zName[i];
    ++    if( zName[i]==cQuote ) z[n++] = cQuote;
    ++  }
    ++  if( cQuote ) z[n++] = cQuote;
    ++  z[n] = 0;
    ++}
    ++
    ++
    ++/*
    ++** Execute a query statement that will generate SQL output.  Print
    ++** the result columns, comma-separated, on a line and then add a
    ++** semicolon terminator to the end of that line.
    ++**
    ++** If the number of columns is 1 and that column contains text "--"
    ++** then write the semicolon on a separate line.  That way, if a
    ++** "--" comment occurs at the end of the statement, the comment
    ++** won't consume the semicolon terminator.
    ++*/
    ++static int run_table_dump_query(
    ++  ShellState *p,           /* Query context */
    ++  const char *zSelect,     /* SELECT statement to extract content */
    ++  const char *zFirstRow    /* Print before first row, if not NULL */
    ++){
    ++  sqlite3_stmt *pSelect;
    ++  int rc;
    ++  int nResult;
    ++  int i;
    ++  const char *z;
    ++  rc = sqlite3_prepare_v2(p->db, zSelect, -1, &pSelect, 0);
    ++  if( rc!=SQLITE_OK || !pSelect ){
    ++    utf8_printf(p->out, "/**** ERROR: (%d) %s *****/\n", rc,
    ++                sqlite3_errmsg(p->db));
    ++    if( (rc&0xff)!=SQLITE_CORRUPT ) p->nErr++;
    ++    return rc;
    ++  }
    ++  rc = sqlite3_step(pSelect);
    ++  nResult = sqlite3_column_count(pSelect);
    ++  while( rc==SQLITE_ROW ){
    ++    if( zFirstRow ){
    ++      utf8_printf(p->out, "%s", zFirstRow);
    ++      zFirstRow = 0;
    ++    }
    ++    z = (const char*)sqlite3_column_text(pSelect, 0);
    ++    utf8_printf(p->out, "%s", z);
    ++    for(i=1; i<nResult; i++){
    ++      utf8_printf(p->out, ",%s", sqlite3_column_text(pSelect, i));
    ++    }
    ++    if( z==0 ) z = "";
    ++    while( z[0] && (z[0]!='-' || z[1]!='-') ) z++;
    ++    if( z[0] ){
    ++      raw_printf(p->out, "\n;\n");
    ++    }else{
    ++      raw_printf(p->out, ";\n");
    ++    }
    ++    rc = sqlite3_step(pSelect);
    ++  }
    ++  rc = sqlite3_finalize(pSelect);
    ++  if( rc!=SQLITE_OK ){
    ++    utf8_printf(p->out, "/**** ERROR: (%d) %s *****/\n", rc,
    ++                sqlite3_errmsg(p->db));
    ++    if( (rc&0xff)!=SQLITE_CORRUPT ) p->nErr++;
    ++  }
    ++  return rc;
    ++}
    ++
    ++/*
    ++** Allocate space and save off current error string.
    ++*/
    ++static char *save_err_msg(
    ++  sqlite3 *db            /* Database to query */
    ++){
    ++  int nErrMsg = 1+strlen30(sqlite3_errmsg(db));
    ++  char *zErrMsg = sqlite3_malloc64(nErrMsg);
    ++  if( zErrMsg ){
    ++    memcpy(zErrMsg, sqlite3_errmsg(db), nErrMsg);
    ++  }
    ++  return zErrMsg;
    ++}
    ++
    ++#ifdef __linux__
    ++/*
    ++** Attempt to display I/O stats on Linux using /proc/PID/io
    ++*/
    ++static void displayLinuxIoStats(FILE *out){
    ++  FILE *in;
    ++  char z[200];
    ++  sqlite3_snprintf(sizeof(z), z, "/proc/%d/io", getpid());
    ++  in = fopen(z, "rb");
    ++  if( in==0 ) return;
    ++  while( fgets(z, sizeof(z), in)!=0 ){
    ++    static const struct {
    ++      const char *zPattern;
    ++      const char *zDesc;
    ++    } aTrans[] = {
    ++      { "rchar: ",                  "Bytes received by read():" },
    ++      { "wchar: ",                  "Bytes sent to write():"    },
    ++      { "syscr: ",                  "Read() system calls:"      },
    ++      { "syscw: ",                  "Write() system calls:"     },
    ++      { "read_bytes: ",             "Bytes read from storage:"  },
    ++      { "write_bytes: ",            "Bytes written to storage:" },
    ++      { "cancelled_write_bytes: ",  "Cancelled write bytes:"    },
    ++    };
    ++    int i;
    ++    for(i=0; i<ArraySize(aTrans); i++){
    ++      int n = strlen30(aTrans[i].zPattern);
    ++      if( strncmp(aTrans[i].zPattern, z, n)==0 ){
    ++        utf8_printf(out, "%-36s %s", aTrans[i].zDesc, &z[n]);
    ++        break;
    ++      }
    ++    }
    ++  }
    ++  fclose(in);
    ++}
    ++#endif
    ++
    ++/*
    ++** Display a single line of status using 64-bit values.
    ++*/
    ++static void displayStatLine(
    ++  ShellState *p,            /* The shell context */
    ++  char *zLabel,             /* Label for this one line */
    ++  char *zFormat,            /* Format for the result */
    ++  int iStatusCtrl,          /* Which status to display */
    ++  int bReset                /* True to reset the stats */
    ++){
    ++  sqlite3_int64 iCur = -1;
    ++  sqlite3_int64 iHiwtr = -1;
    ++  int i, nPercent;
    ++  char zLine[200];
    ++  sqlite3_status64(iStatusCtrl, &iCur, &iHiwtr, bReset);
    ++  for(i=0, nPercent=0; zFormat[i]; i++){
    ++    if( zFormat[i]=='%' ) nPercent++;
    ++  }
    ++  if( nPercent>1 ){
    ++    sqlite3_snprintf(sizeof(zLine), zLine, zFormat, iCur, iHiwtr);
    ++  }else{
    ++    sqlite3_snprintf(sizeof(zLine), zLine, zFormat, iHiwtr);
    ++  }
    ++  raw_printf(p->out, "%-36s %s\n", zLabel, zLine);
    ++}
    ++
    ++/*
    ++** Display memory stats.
    ++*/
    ++static int display_stats(
    ++  sqlite3 *db,                /* Database to query */
    ++  ShellState *pArg,           /* Pointer to ShellState */
    ++  int bReset                  /* True to reset the stats */
    ++){
    ++  int iCur;
    ++  int iHiwtr;
    ++
    ++  if( pArg && pArg->out ){
    ++    displayStatLine(pArg, "Memory Used:",
    ++       "%lld (max %lld) bytes", SQLITE_STATUS_MEMORY_USED, bReset);
    ++    displayStatLine(pArg, "Number of Outstanding Allocations:",
    ++       "%lld (max %lld)", SQLITE_STATUS_MALLOC_COUNT, bReset);
    ++    if( pArg->shellFlgs & SHFLG_Pagecache ){
    ++      displayStatLine(pArg, "Number of Pcache Pages Used:",
    ++         "%lld (max %lld) pages", SQLITE_STATUS_PAGECACHE_USED, bReset);
    ++    }
    ++    displayStatLine(pArg, "Number of Pcache Overflow Bytes:",
    ++       "%lld (max %lld) bytes", SQLITE_STATUS_PAGECACHE_OVERFLOW, bReset);
    ++    displayStatLine(pArg, "Largest Allocation:",
    ++       "%lld bytes", SQLITE_STATUS_MALLOC_SIZE, bReset);
    ++    displayStatLine(pArg, "Largest Pcache Allocation:",
    ++       "%lld bytes", SQLITE_STATUS_PAGECACHE_SIZE, bReset);
    ++#ifdef YYTRACKMAXSTACKDEPTH
    ++    displayStatLine(pArg, "Deepest Parser Stack:",
    ++       "%lld (max %lld)", SQLITE_STATUS_PARSER_STACK, bReset);
    ++#endif
    ++  }
    ++
    ++  if( pArg && pArg->out && db ){
    ++    if( pArg->shellFlgs & SHFLG_Lookaside ){
    ++      iHiwtr = iCur = -1;
    ++      sqlite3_db_status(db, SQLITE_DBSTATUS_LOOKASIDE_USED,
    ++                        &iCur, &iHiwtr, bReset);
    ++      raw_printf(pArg->out,
    ++              "Lookaside Slots Used:                %d (max %d)\n",
    ++              iCur, iHiwtr);
    ++      sqlite3_db_status(db, SQLITE_DBSTATUS_LOOKASIDE_HIT,
    ++                        &iCur, &iHiwtr, bReset);
    ++      raw_printf(pArg->out, "Successful lookaside attempts:       %d\n",
    ++              iHiwtr);
    ++      sqlite3_db_status(db, SQLITE_DBSTATUS_LOOKASIDE_MISS_SIZE,
    ++                        &iCur, &iHiwtr, bReset);
    ++      raw_printf(pArg->out, "Lookaside failures due to size:      %d\n",
    ++              iHiwtr);
    ++      sqlite3_db_status(db, SQLITE_DBSTATUS_LOOKASIDE_MISS_FULL,
    ++                        &iCur, &iHiwtr, bReset);
    ++      raw_printf(pArg->out, "Lookaside failures due to OOM:       %d\n",
    ++              iHiwtr);
    ++    }
    ++    iHiwtr = iCur = -1;
    ++    sqlite3_db_status(db, SQLITE_DBSTATUS_CACHE_USED, &iCur, &iHiwtr, bReset);
    ++    raw_printf(pArg->out, "Pager Heap Usage:                    %d bytes\n",
    ++            iCur);
    ++    iHiwtr = iCur = -1;
    ++    sqlite3_db_status(db, SQLITE_DBSTATUS_CACHE_HIT, &iCur, &iHiwtr, 1);
    ++    raw_printf(pArg->out, "Page cache hits:                     %d\n", iCur);
    ++    iHiwtr = iCur = -1;
    ++    sqlite3_db_status(db, SQLITE_DBSTATUS_CACHE_MISS, &iCur, &iHiwtr, 1);
    ++    raw_printf(pArg->out, "Page cache misses:                   %d\n", iCur);
    ++    iHiwtr = iCur = -1;
    ++    sqlite3_db_status(db, SQLITE_DBSTATUS_CACHE_WRITE, &iCur, &iHiwtr, 1);
    ++    raw_printf(pArg->out, "Page cache writes:                   %d\n", iCur);
    ++    iHiwtr = iCur = -1;
    ++    sqlite3_db_status(db, SQLITE_DBSTATUS_SCHEMA_USED, &iCur, &iHiwtr, bReset);
    ++    raw_printf(pArg->out, "Schema Heap Usage:                   %d bytes\n",
    ++            iCur);
    ++    iHiwtr = iCur = -1;
    ++    sqlite3_db_status(db, SQLITE_DBSTATUS_STMT_USED, &iCur, &iHiwtr, bReset);
    ++    raw_printf(pArg->out, "Statement Heap/Lookaside Usage:      %d bytes\n",
    ++            iCur);
    ++  }
    ++
    ++  if( pArg && pArg->out && db && pArg->pStmt ){
    ++    iCur = sqlite3_stmt_status(pArg->pStmt, SQLITE_STMTSTATUS_FULLSCAN_STEP,
    ++                               bReset);
    ++    raw_printf(pArg->out, "Fullscan Steps:                      %d\n", iCur);
    ++    iCur = sqlite3_stmt_status(pArg->pStmt, SQLITE_STMTSTATUS_SORT, bReset);
    ++    raw_printf(pArg->out, "Sort Operations:                     %d\n", iCur);
    ++    iCur = sqlite3_stmt_status(pArg->pStmt, SQLITE_STMTSTATUS_AUTOINDEX,bReset);
    ++    raw_printf(pArg->out, "Autoindex Inserts:                   %d\n", iCur);
    ++    iCur = sqlite3_stmt_status(pArg->pStmt, SQLITE_STMTSTATUS_VM_STEP, bReset);
    ++    raw_printf(pArg->out, "Virtual Machine Steps:               %d\n", iCur);
    ++  }
    ++
    ++#ifdef __linux__
    ++  displayLinuxIoStats(pArg->out);
    ++#endif
    ++
    ++  /* Do not remove this machine readable comment: extra-stats-output-here */
    ++
    ++  return 0;
    ++}
    ++
    ++/*
    ++** Display scan stats.
    ++*/
    ++static void display_scanstats(
    ++  sqlite3 *db,                    /* Database to query */
    ++  ShellState *pArg                /* Pointer to ShellState */
    ++){
    ++#ifndef SQLITE_ENABLE_STMT_SCANSTATUS
    ++  UNUSED_PARAMETER(db);
    ++  UNUSED_PARAMETER(pArg);
    ++#else
    ++  int i, k, n, mx;
    ++  raw_printf(pArg->out, "-------- scanstats --------\n");
    ++  mx = 0;
    ++  for(k=0; k<=mx; k++){
    ++    double rEstLoop = 1.0;
    ++    for(i=n=0; 1; i++){
    ++      sqlite3_stmt *p = pArg->pStmt;
    ++      sqlite3_int64 nLoop, nVisit;
    ++      double rEst;
    ++      int iSid;
    ++      const char *zExplain;
    ++      if( sqlite3_stmt_scanstatus(p, i, SQLITE_SCANSTAT_NLOOP, (void*)&nLoop) ){
    ++        break;
    ++      }
    ++      sqlite3_stmt_scanstatus(p, i, SQLITE_SCANSTAT_SELECTID, (void*)&iSid);
    ++      if( iSid>mx ) mx = iSid;
    ++      if( iSid!=k ) continue;
    ++      if( n==0 ){
    ++        rEstLoop = (double)nLoop;
    ++        if( k>0 ) raw_printf(pArg->out, "-------- subquery %d -------\n", k);
    ++      }
    ++      n++;
    ++      sqlite3_stmt_scanstatus(p, i, SQLITE_SCANSTAT_NVISIT, (void*)&nVisit);
    ++      sqlite3_stmt_scanstatus(p, i, SQLITE_SCANSTAT_EST, (void*)&rEst);
    ++      sqlite3_stmt_scanstatus(p, i, SQLITE_SCANSTAT_EXPLAIN, (void*)&zExplain);
    ++      utf8_printf(pArg->out, "Loop %2d: %s\n", n, zExplain);
    ++      rEstLoop *= rEst;
    ++      raw_printf(pArg->out,
    ++          "         nLoop=%-8lld nRow=%-8lld estRow=%-8lld estRow/Loop=%-8g\n",
    ++          nLoop, nVisit, (sqlite3_int64)(rEstLoop+0.5), rEst
    ++      );
    ++    }
    ++  }
    ++  raw_printf(pArg->out, "---------------------------\n");
    ++#endif
    ++}
    ++
    ++/*
    ++** Parameter azArray points to a zero-terminated array of strings. zStr
    ++** points to a single nul-terminated string. Return non-zero if zStr
    ++** is equal, according to strcmp(), to any of the strings in the array.
    ++** Otherwise, return zero.
    ++*/
    ++static int str_in_array(const char *zStr, const char **azArray){
    ++  int i;
    ++  for(i=0; azArray[i]; i++){
    ++    if( 0==strcmp(zStr, azArray[i]) ) return 1;
    ++  }
    ++  return 0;
    ++}
    ++
    ++/*
    ++** If compiled statement pSql appears to be an EXPLAIN statement, allocate
    ++** and populate the ShellState.aiIndent[] array with the number of
    ++** spaces each opcode should be indented before it is output.
    ++**
    ++** The indenting rules are:
    ++**
    ++**     * For each "Next", "Prev", "VNext" or "VPrev" instruction, indent
    ++**       all opcodes that occur between the p2 jump destination and the opcode
    ++**       itself by 2 spaces.
    ++**
    ++**     * For each "Goto", if the jump destination is earlier in the program
    ++**       and ends on one of:
    ++**          Yield  SeekGt  SeekLt  RowSetRead  Rewind
    ++**       or if the P1 parameter is one instead of zero,
    ++**       then indent all opcodes between the earlier instruction
    ++**       and "Goto" by 2 spaces.
    ++*/
    ++static void explain_data_prepare(ShellState *p, sqlite3_stmt *pSql){
    ++  const char *zSql;               /* The text of the SQL statement */
    ++  const char *z;                  /* Used to check if this is an EXPLAIN */
    ++  int *abYield = 0;               /* True if op is an OP_Yield */
    ++  int nAlloc = 0;                 /* Allocated size of p->aiIndent[], abYield */
    ++  int iOp;                        /* Index of operation in p->aiIndent[] */
    ++
    ++  const char *azNext[] = { "Next", "Prev", "VPrev", "VNext", "SorterNext",
    ++                           "NextIfOpen", "PrevIfOpen", 0 };
    ++  const char *azYield[] = { "Yield", "SeekLT", "SeekGT", "RowSetRead",
    ++                            "Rewind", 0 };
    ++  const char *azGoto[] = { "Goto", 0 };
    ++
    ++  /* Try to figure out if this is really an EXPLAIN statement. If this
    ++  ** cannot be verified, return early.  */
    ++  if( sqlite3_column_count(pSql)!=8 ){
    ++    p->cMode = p->mode;
    ++    return;
    ++  }
    ++  zSql = sqlite3_sql(pSql);
    ++  if( zSql==0 ) return;
    ++  for(z=zSql; *z==' ' || *z=='\t' || *z=='\n' || *z=='\f' || *z=='\r'; z++);
    ++  if( sqlite3_strnicmp(z, "explain", 7) ){
    ++    p->cMode = p->mode;
    ++    return;
    ++  }
    ++
    ++  for(iOp=0; SQLITE_ROW==sqlite3_step(pSql); iOp++){
    ++    int i;
    ++    int iAddr = sqlite3_column_int(pSql, 0);
    ++    const char *zOp = (const char*)sqlite3_column_text(pSql, 1);
    ++
    ++    /* Set p2 to the P2 field of the current opcode. Then, assuming that
    ++    ** p2 is an instruction address, set variable p2op to the index of that
    ++    ** instruction in the aiIndent[] array. p2 and p2op may be different if
    ++    ** the current instruction is part of a sub-program generated by an
    ++    ** SQL trigger or foreign key.  */
    ++    int p2 = sqlite3_column_int(pSql, 3);
    ++    int p2op = (p2 + (iOp-iAddr));
    ++
    ++    /* Grow the p->aiIndent array as required */
    ++    if( iOp>=nAlloc ){
    ++      if( iOp==0 ){
    ++        /* Do further verfication that this is explain output.  Abort if
    ++        ** it is not */
    ++        static const char *explainCols[] = {
    ++           "addr", "opcode", "p1", "p2", "p3", "p4", "p5", "comment" };
    ++        int jj;
    ++        for(jj=0; jj<ArraySize(explainCols); jj++){
    ++          if( strcmp(sqlite3_column_name(pSql,jj),explainCols[jj])!=0 ){
    ++            p->cMode = p->mode;
    ++            sqlite3_reset(pSql);
    ++            return;
    ++          }
    ++        }
    ++      }
    ++      nAlloc += 100;
    ++      p->aiIndent = (int*)sqlite3_realloc64(p->aiIndent, nAlloc*sizeof(int));
    ++      abYield = (int*)sqlite3_realloc64(abYield, nAlloc*sizeof(int));
    ++    }
    ++    abYield[iOp] = str_in_array(zOp, azYield);
    ++    p->aiIndent[iOp] = 0;
    ++    p->nIndent = iOp+1;
    ++
    ++    if( str_in_array(zOp, azNext) ){
    ++      for(i=p2op; i<iOp; i++) p->aiIndent[i] += 2;
    ++    }
    ++    if( str_in_array(zOp, azGoto) && p2op<p->nIndent
    ++     && (abYield[p2op] || sqlite3_column_int(pSql, 2))
    ++    ){
    ++      for(i=p2op; i<iOp; i++) p->aiIndent[i] += 2;
    ++    }
    ++  }
    ++
    ++  p->iIndent = 0;
    ++  sqlite3_free(abYield);
    ++  sqlite3_reset(pSql);
    ++}
    ++
    ++/*
    ++** Free the array allocated by explain_data_prepare().
    ++*/
    ++static void explain_data_delete(ShellState *p){
    ++  sqlite3_free(p->aiIndent);
    ++  p->aiIndent = 0;
    ++  p->nIndent = 0;
    ++  p->iIndent = 0;
    ++}
    ++
    ++/*
    ++** Disable and restore .wheretrace and .selecttrace settings.
    ++*/
    ++#if defined(SQLITE_DEBUG) && defined(SQLITE_ENABLE_SELECTTRACE)
    ++extern int sqlite3SelectTrace;
    ++static int savedSelectTrace;
    ++#endif
    ++#if defined(SQLITE_DEBUG) && defined(SQLITE_ENABLE_WHERETRACE)
    ++extern int sqlite3WhereTrace;
    ++static int savedWhereTrace;
    ++#endif
    ++static void disable_debug_trace_modes(void){
    ++#if defined(SQLITE_DEBUG) && defined(SQLITE_ENABLE_SELECTTRACE)
    ++  savedSelectTrace = sqlite3SelectTrace;
    ++  sqlite3SelectTrace = 0;
    ++#endif
    ++#if defined(SQLITE_DEBUG) && defined(SQLITE_ENABLE_WHERETRACE)
    ++  savedWhereTrace = sqlite3WhereTrace;
    ++  sqlite3WhereTrace = 0;
    ++#endif
    ++}
    ++static void restore_debug_trace_modes(void){
    ++#if defined(SQLITE_DEBUG) && defined(SQLITE_ENABLE_SELECTTRACE)
    ++  sqlite3SelectTrace = savedSelectTrace;
    ++#endif
    ++#if defined(SQLITE_DEBUG) && defined(SQLITE_ENABLE_WHERETRACE)
    ++  sqlite3WhereTrace = savedWhereTrace;
    ++#endif
    ++}
    ++
    ++/*
    ++** Run a prepared statement
    ++*/
    ++static void exec_prepared_stmt(
    ++  ShellState *pArg,                                /* Pointer to ShellState */
    ++  sqlite3_stmt *pStmt,                             /* Statment to run */
    ++  int (*xCallback)(void*,int,char**,char**,int*)   /* Callback function */
    ++){
    ++  int rc;
    ++
    ++  /* perform the first step.  this will tell us if we
    ++  ** have a result set or not and how wide it is.
    ++  */
    ++  rc = sqlite3_step(pStmt);
    ++  /* if we have a result set... */
    ++  if( SQLITE_ROW == rc ){
    ++    /* if we have a callback... */
    ++    if( xCallback ){
    ++      /* allocate space for col name ptr, value ptr, and type */
    ++      int nCol = sqlite3_column_count(pStmt);
    ++      void *pData = sqlite3_malloc64(3*nCol*sizeof(const char*) + 1);
    ++      if( !pData ){
    ++        rc = SQLITE_NOMEM;
    ++      }else{
    ++        char **azCols = (char **)pData;      /* Names of result columns */
    ++        char **azVals = &azCols[nCol];       /* Results */
    ++        int *aiTypes = (int *)&azVals[nCol]; /* Result types */
    ++        int i, x;
    ++        assert(sizeof(int) <= sizeof(char *));
    ++        /* save off ptrs to column names */
    ++        for(i=0; i<nCol; i++){
    ++          azCols[i] = (char *)sqlite3_column_name(pStmt, i);
    ++        }
    ++        do{
    ++          /* extract the data and data types */
    ++          for(i=0; i<nCol; i++){
    ++            aiTypes[i] = x = sqlite3_column_type(pStmt, i);
    ++            if( x==SQLITE_BLOB && pArg && pArg->cMode==MODE_Insert ){
    ++              azVals[i] = "";
    ++            }else{
    ++              azVals[i] = (char*)sqlite3_column_text(pStmt, i);
    ++            }
    ++            if( !azVals[i] && (aiTypes[i]!=SQLITE_NULL) ){
    ++              rc = SQLITE_NOMEM;
    ++              break; /* from for */
    ++            }
    ++          } /* end for */
    ++
    ++          /* if data and types extracted successfully... */
    ++          if( SQLITE_ROW == rc ){
    ++            /* call the supplied callback with the result row data */
    ++            if( xCallback(pArg, nCol, azVals, azCols, aiTypes) ){
    ++              rc = SQLITE_ABORT;
    ++            }else{
    ++              rc = sqlite3_step(pStmt);
    ++            }
    ++          }
    ++        } while( SQLITE_ROW == rc );
    ++        sqlite3_free(pData);
    ++      }
    ++    }else{
    ++      do{
    ++        rc = sqlite3_step(pStmt);
    ++      } while( rc == SQLITE_ROW );
    ++    }
    ++  }
    ++}
    ++
    ++#ifndef SQLITE_OMIT_VIRTUALTABLE
    ++/*
    ++** This function is called to process SQL if the previous shell command
    ++** was ".expert". It passes the SQL in the second argument directly to
    ++** the sqlite3expert object.
    ++**
    ++** If successful, SQLITE_OK is returned. Otherwise, an SQLite error
    ++** code. In this case, (*pzErr) may be set to point to a buffer containing
    ++** an English language error message. It is the responsibility of the
    ++** caller to eventually free this buffer using sqlite3_free().
    ++*/
    ++static int expertHandleSQL(
    ++  ShellState *pState, 
    ++  const char *zSql, 
    ++  char **pzErr
    ++){
    ++  assert( pState->expert.pExpert );
    ++  assert( pzErr==0 || *pzErr==0 );
    ++  return sqlite3_expert_sql(pState->expert.pExpert, zSql, pzErr);
    ++}
    ++
    ++/*
    ++** This function is called either to silently clean up the object
    ++** created by the ".expert" command (if bCancel==1), or to generate a 
    ++** report from it and then clean it up (if bCancel==0).
    ++**
    ++** If successful, SQLITE_OK is returned. Otherwise, an SQLite error
    ++** code. In this case, (*pzErr) may be set to point to a buffer containing
    ++** an English language error message. It is the responsibility of the
    ++** caller to eventually free this buffer using sqlite3_free().
    ++*/
    ++static int expertFinish(
    ++  ShellState *pState,
    ++  int bCancel,
    ++  char **pzErr
    ++){
    ++  int rc = SQLITE_OK;
    ++  sqlite3expert *p = pState->expert.pExpert;
    ++  assert( p );
    ++  assert( bCancel || pzErr==0 || *pzErr==0 );
    ++  if( bCancel==0 ){
    ++    FILE *out = pState->out;
    ++    int bVerbose = pState->expert.bVerbose;
    ++
    ++    rc = sqlite3_expert_analyze(p, pzErr);
    ++    if( rc==SQLITE_OK ){
    ++      int nQuery = sqlite3_expert_count(p);
    ++      int i;
    ++
    ++      if( bVerbose ){
    ++        const char *zCand = sqlite3_expert_report(p,0,EXPERT_REPORT_CANDIDATES);
    ++        raw_printf(out, "-- Candidates -----------------------------\n");
    ++        raw_printf(out, "%s\n", zCand);
    ++      }
    ++      for(i=0; i<nQuery; i++){
    ++        const char *zSql = sqlite3_expert_report(p, i, EXPERT_REPORT_SQL);
    ++        const char *zIdx = sqlite3_expert_report(p, i, EXPERT_REPORT_INDEXES);
    ++        const char *zEQP = sqlite3_expert_report(p, i, EXPERT_REPORT_PLAN);
    ++        if( zIdx==0 ) zIdx = "(no new indexes)\n";
    ++        if( bVerbose ){
    ++          raw_printf(out, "-- Query %d --------------------------------\n",i+1);
    ++          raw_printf(out, "%s\n\n", zSql);
    ++        }
    ++        raw_printf(out, "%s\n", zIdx);
    ++        raw_printf(out, "%s\n", zEQP);
    ++      }
    ++    }
    ++  }
    ++  sqlite3_expert_destroy(p);
    ++  pState->expert.pExpert = 0;
    ++  return rc;
    ++}
    ++
    ++/*
    ++** Implementation of ".expert" dot command.
    ++*/
    ++static int expertDotCommand(
    ++  ShellState *pState,             /* Current shell tool state */
    ++  char **azArg,                   /* Array of arguments passed to dot command */
    ++  int nArg                        /* Number of entries in azArg[] */
    ++){
    ++  int rc = SQLITE_OK;
    ++  char *zErr = 0;
    ++  int i;
    ++  int iSample = 0;
    ++
    ++  assert( pState->expert.pExpert==0 );
    ++  memset(&pState->expert, 0, sizeof(ExpertInfo));
    ++
    ++  for(i=1; rc==SQLITE_OK && i<nArg; i++){
    ++    char *z = azArg[i];
    ++    int n;
    ++    if( z[0]=='-' && z[1]=='-' ) z++;
    ++    n = strlen30(z);
    ++    if( n>=2 && 0==strncmp(z, "-verbose", n) ){
    ++      pState->expert.bVerbose = 1;
    ++    }
    ++    else if( n>=2 && 0==strncmp(z, "-sample", n) ){
    ++      if( i==(nArg-1) ){
    ++        raw_printf(stderr, "option requires an argument: %s\n", z);
    ++        rc = SQLITE_ERROR;
    ++      }else{
    ++        iSample = (int)integerValue(azArg[++i]);
    ++        if( iSample<0 || iSample>100 ){
    ++          raw_printf(stderr, "value out of range: %s\n", azArg[i]);
    ++          rc = SQLITE_ERROR;
    ++        }
    ++      }
    ++    }
    ++    else{
    ++      raw_printf(stderr, "unknown option: %s\n", z);
    ++      rc = SQLITE_ERROR;
    ++    }
    ++  }
    ++
    ++  if( rc==SQLITE_OK ){
    ++    pState->expert.pExpert = sqlite3_expert_new(pState->db, &zErr);
    ++    if( pState->expert.pExpert==0 ){
    ++      raw_printf(stderr, "sqlite3_expert_new: %s\n", zErr);
    ++      rc = SQLITE_ERROR;
    ++    }else{
    ++      sqlite3_expert_config(
    ++          pState->expert.pExpert, EXPERT_CONFIG_SAMPLE, iSample
    ++      );
    ++    }
    ++  }
    ++
    ++  return rc;
    ++}
    ++#endif /* ifndef SQLITE_OMIT_VIRTUALTABLE */
    ++
    ++/*
    ++** Execute a statement or set of statements.  Print
    ++** any result rows/columns depending on the current mode
    ++** set via the supplied callback.
    ++**
    ++** This is very similar to SQLite's built-in sqlite3_exec()
    ++** function except it takes a slightly different callback
    ++** and callback data argument.
    ++*/
    ++static int shell_exec(
    ++  sqlite3 *db,                              /* An open database */
    ++  const char *zSql,                         /* SQL to be evaluated */
    ++  int (*xCallback)(void*,int,char**,char**,int*),   /* Callback function */
    ++                                            /* (not the same as sqlite3_exec) */
    ++  ShellState *pArg,                         /* Pointer to ShellState */
    ++  char **pzErrMsg                           /* Error msg written here */
    ++){
    ++  sqlite3_stmt *pStmt = NULL;     /* Statement to execute. */
    ++  int rc = SQLITE_OK;             /* Return Code */
    ++  int rc2;
    ++  const char *zLeftover;          /* Tail of unprocessed SQL */
    ++
    ++  if( pzErrMsg ){
    ++    *pzErrMsg = NULL;
    ++  }
    ++
    ++#ifndef SQLITE_OMIT_VIRTUALTABLE
    ++  if( pArg->expert.pExpert ){
    ++    rc = expertHandleSQL(pArg, zSql, pzErrMsg);
    ++    return expertFinish(pArg, (rc!=SQLITE_OK), pzErrMsg);
    ++  }
    ++#endif
    ++
    ++  while( zSql[0] && (SQLITE_OK == rc) ){
    ++    static const char *zStmtSql;
    ++    rc = sqlite3_prepare_v2(db, zSql, -1, &pStmt, &zLeftover);
    ++    if( SQLITE_OK != rc ){
    ++      if( pzErrMsg ){
    ++        *pzErrMsg = save_err_msg(db);
    ++      }
    ++    }else{
    ++      if( !pStmt ){
    ++        /* this happens for a comment or white-space */
    ++        zSql = zLeftover;
    ++        while( IsSpace(zSql[0]) ) zSql++;
    ++        continue;
    ++      }
    ++      zStmtSql = sqlite3_sql(pStmt);
    ++      if( zStmtSql==0 ) zStmtSql = "";
    ++      while( IsSpace(zStmtSql[0]) ) zStmtSql++;
    ++
    ++      /* save off the prepared statment handle and reset row count */
    ++      if( pArg ){
    ++        pArg->pStmt = pStmt;
    ++        pArg->cnt = 0;
    ++      }
    ++
    ++      /* echo the sql statement if echo on */
    ++      if( pArg && ShellHasFlag(pArg, SHFLG_Echo) ){
    ++        utf8_printf(pArg->out, "%s\n", zStmtSql ? zStmtSql : zSql);
    ++      }
    ++
    ++      /* Show the EXPLAIN QUERY PLAN if .eqp is on */
    ++      if( pArg && pArg->autoEQP && sqlite3_strlike("EXPLAIN%",zStmtSql,0)!=0 ){
    ++        sqlite3_stmt *pExplain;
    ++        char *zEQP;
    ++        int triggerEQP = 0;
    ++        disable_debug_trace_modes();
    ++        sqlite3_db_config(db, SQLITE_DBCONFIG_TRIGGER_EQP, -1, &triggerEQP);
    ++        if( pArg->autoEQP>=AUTOEQP_trigger ){
    ++          sqlite3_db_config(db, SQLITE_DBCONFIG_TRIGGER_EQP, 1, 0);
    ++        }
    ++        zEQP = sqlite3_mprintf("EXPLAIN QUERY PLAN %s", zStmtSql);
    ++        rc = sqlite3_prepare_v2(db, zEQP, -1, &pExplain, 0);
    ++        if( rc==SQLITE_OK ){
    ++          while( sqlite3_step(pExplain)==SQLITE_ROW ){
    ++            raw_printf(pArg->out,"--EQP-- %d,",sqlite3_column_int(pExplain, 0));
    ++            raw_printf(pArg->out,"%d,", sqlite3_column_int(pExplain, 1));
    ++            raw_printf(pArg->out,"%d,", sqlite3_column_int(pExplain, 2));
    ++            utf8_printf(pArg->out,"%s\n", sqlite3_column_text(pExplain, 3));
    ++          }
    ++        }
    ++        sqlite3_finalize(pExplain);
    ++        sqlite3_free(zEQP);
    ++        if( pArg->autoEQP>=AUTOEQP_full ){
    ++          /* Also do an EXPLAIN for ".eqp full" mode */
    ++          zEQP = sqlite3_mprintf("EXPLAIN %s", zStmtSql);
    ++          rc = sqlite3_prepare_v2(db, zEQP, -1, &pExplain, 0);
    ++          if( rc==SQLITE_OK ){
    ++            pArg->cMode = MODE_Explain;
    ++            explain_data_prepare(pArg, pExplain);
    ++            exec_prepared_stmt(pArg, pExplain, xCallback);
    ++            explain_data_delete(pArg);
    ++          }
    ++          sqlite3_finalize(pExplain);
    ++          sqlite3_free(zEQP);
    ++        }
    ++        sqlite3_db_config(db, SQLITE_DBCONFIG_TRIGGER_EQP, triggerEQP, 0);
    ++        restore_debug_trace_modes();
    ++      }
    ++
    ++      if( pArg ){
    ++        pArg->cMode = pArg->mode;
    ++        if( pArg->autoExplain
    ++         && sqlite3_column_count(pStmt)==8
    ++         && sqlite3_strlike("EXPLAIN%", zStmtSql,0)==0
    ++        ){
    ++          pArg->cMode = MODE_Explain;
    ++        }
    ++
    ++        /* If the shell is currently in ".explain" mode, gather the extra
    ++        ** data required to add indents to the output.*/
    ++        if( pArg->cMode==MODE_Explain ){
    ++          explain_data_prepare(pArg, pStmt);
    ++        }
    ++      }
    ++
    ++      exec_prepared_stmt(pArg, pStmt, xCallback);
    ++      explain_data_delete(pArg);
    ++
    ++      /* print usage stats if stats on */
    ++      if( pArg && pArg->statsOn ){
    ++        display_stats(db, pArg, 0);
    ++      }
    ++
    ++      /* print loop-counters if required */
    ++      if( pArg && pArg->scanstatsOn ){
    ++        display_scanstats(db, pArg);
    ++      }
    ++
    ++      /* Finalize the statement just executed. If this fails, save a
    ++      ** copy of the error message. Otherwise, set zSql to point to the
    ++      ** next statement to execute. */
    ++      rc2 = sqlite3_finalize(pStmt);
    ++      if( rc!=SQLITE_NOMEM ) rc = rc2;
    ++      if( rc==SQLITE_OK ){
    ++        zSql = zLeftover;
    ++        while( IsSpace(zSql[0]) ) zSql++;
    ++      }else if( pzErrMsg ){
    ++        *pzErrMsg = save_err_msg(db);
    ++      }
    ++
    ++      /* clear saved stmt handle */
    ++      if( pArg ){
    ++        pArg->pStmt = NULL;
    ++      }
    ++    }
    ++  } /* end while */
    ++
    ++  return rc;
    ++}
    ++
    ++/*
    ++** Release memory previously allocated by tableColumnList().
    ++*/
    ++static void freeColumnList(char **azCol){
    ++  int i;
    ++  for(i=1; azCol[i]; i++){
    ++    sqlite3_free(azCol[i]);
    ++  }
    ++  /* azCol[0] is a static string */
    ++  sqlite3_free(azCol);
    ++}
    ++
    ++/*
    ++** Return a list of pointers to strings which are the names of all
    ++** columns in table zTab.   The memory to hold the names is dynamically
    ++** allocated and must be released by the caller using a subsequent call
    ++** to freeColumnList().
    ++**
    ++** The azCol[0] entry is usually NULL.  However, if zTab contains a rowid
    ++** value that needs to be preserved, then azCol[0] is filled in with the
    ++** name of the rowid column.
    ++**
    ++** The first regular column in the table is azCol[1].  The list is terminated
    ++** by an entry with azCol[i]==0.
    ++*/
    ++static char **tableColumnList(ShellState *p, const char *zTab){
    ++  char **azCol = 0;
    ++  sqlite3_stmt *pStmt;
    ++  char *zSql;
    ++  int nCol = 0;
    ++  int nAlloc = 0;
    ++  int nPK = 0;       /* Number of PRIMARY KEY columns seen */
    ++  int isIPK = 0;     /* True if one PRIMARY KEY column of type INTEGER */
    ++  int preserveRowid = ShellHasFlag(p, SHFLG_PreserveRowid);
    ++  int rc;
    ++
    ++  zSql = sqlite3_mprintf("PRAGMA table_info=%Q", zTab);
    ++  rc = sqlite3_prepare_v2(p->db, zSql, -1, &pStmt, 0);
    ++  sqlite3_free(zSql);
    ++  if( rc ) return 0;
    ++  while( sqlite3_step(pStmt)==SQLITE_ROW ){
    ++    if( nCol>=nAlloc-2 ){
    ++      nAlloc = nAlloc*2 + nCol + 10;
    ++      azCol = sqlite3_realloc(azCol, nAlloc*sizeof(azCol[0]));
    ++      if( azCol==0 ){
    ++        raw_printf(stderr, "Error: out of memory\n");
    ++        exit(1);
    ++      }
    ++    }
    ++    azCol[++nCol] = sqlite3_mprintf("%s", sqlite3_column_text(pStmt, 1));
    ++    if( sqlite3_column_int(pStmt, 5) ){
    ++      nPK++;
    ++      if( nPK==1
    ++       && sqlite3_stricmp((const char*)sqlite3_column_text(pStmt,2),
    ++                          "INTEGER")==0
    ++      ){
    ++        isIPK = 1;
    ++      }else{
    ++        isIPK = 0;
    ++      }
    ++    }
    ++  }
    ++  sqlite3_finalize(pStmt);
    ++  if( azCol==0 ) return 0;
    ++  azCol[0] = 0;
    ++  azCol[nCol+1] = 0;
    ++
    ++  /* The decision of whether or not a rowid really needs to be preserved
    ++  ** is tricky.  We never need to preserve a rowid for a WITHOUT ROWID table
    ++  ** or a table with an INTEGER PRIMARY KEY.  We are unable to preserve
    ++  ** rowids on tables where the rowid is inaccessible because there are other
    ++  ** columns in the table named "rowid", "_rowid_", and "oid".
    ++  */
    ++  if( preserveRowid && isIPK ){
    ++    /* If a single PRIMARY KEY column with type INTEGER was seen, then it
    ++    ** might be an alise for the ROWID.  But it might also be a WITHOUT ROWID
    ++    ** table or a INTEGER PRIMARY KEY DESC column, neither of which are
    ++    ** ROWID aliases.  To distinguish these cases, check to see if
    ++    ** there is a "pk" entry in "PRAGMA index_list".  There will be
    ++    ** no "pk" index if the PRIMARY KEY really is an alias for the ROWID.
    ++    */
    ++    zSql = sqlite3_mprintf("SELECT 1 FROM pragma_index_list(%Q)"
    ++                           " WHERE origin='pk'", zTab);
    ++    rc = sqlite3_prepare_v2(p->db, zSql, -1, &pStmt, 0);
    ++    sqlite3_free(zSql);
    ++    if( rc ){
    ++      freeColumnList(azCol);
    ++      return 0;
    ++    }
    ++    rc = sqlite3_step(pStmt);
    ++    sqlite3_finalize(pStmt);
    ++    preserveRowid = rc==SQLITE_ROW;
    ++  }
    ++  if( preserveRowid ){
    ++    /* Only preserve the rowid if we can find a name to use for the
    ++    ** rowid */
    ++    static char *azRowid[] = { "rowid", "_rowid_", "oid" };
    ++    int i, j;
    ++    for(j=0; j<3; j++){
    ++      for(i=1; i<=nCol; i++){
    ++        if( sqlite3_stricmp(azRowid[j],azCol[i])==0 ) break;
    ++      }
    ++      if( i>nCol ){
    ++        /* At this point, we know that azRowid[j] is not the name of any
    ++        ** ordinary column in the table.  Verify that azRowid[j] is a valid
    ++        ** name for the rowid before adding it to azCol[0].  WITHOUT ROWID
    ++        ** tables will fail this last check */
    ++        rc = sqlite3_table_column_metadata(p->db,0,zTab,azRowid[j],0,0,0,0,0);
    ++        if( rc==SQLITE_OK ) azCol[0] = azRowid[j];
    ++        break;
    ++      }
    ++    }
    ++  }
    ++  return azCol;
    ++}
    ++
    ++/*
    ++** Toggle the reverse_unordered_selects setting.
    ++*/
    ++static void toggleSelectOrder(sqlite3 *db){
    ++  sqlite3_stmt *pStmt = 0;
    ++  int iSetting = 0;
    ++  char zStmt[100];
    ++  sqlite3_prepare_v2(db, "PRAGMA reverse_unordered_selects", -1, &pStmt, 0);
    ++  if( sqlite3_step(pStmt)==SQLITE_ROW ){
    ++    iSetting = sqlite3_column_int(pStmt, 0);
    ++  }
    ++  sqlite3_finalize(pStmt);
    ++  sqlite3_snprintf(sizeof(zStmt), zStmt,
    ++       "PRAGMA reverse_unordered_selects(%d)", !iSetting);
    ++  sqlite3_exec(db, zStmt, 0, 0, 0);
    ++}
    ++
    ++/*
    ++** This is a different callback routine used for dumping the database.
    ++** Each row received by this callback consists of a table name,
    ++** the table type ("index" or "table") and SQL to create the table.
    ++** This routine should print text sufficient to recreate the table.
    ++*/
    ++static int dump_callback(void *pArg, int nArg, char **azArg, char **azNotUsed){
    ++  int rc;
    ++  const char *zTable;
    ++  const char *zType;
    ++  const char *zSql;
    ++  ShellState *p = (ShellState *)pArg;
    ++
    ++  UNUSED_PARAMETER(azNotUsed);
    ++  if( nArg!=3 || azArg==0 ) return 0;
    ++  zTable = azArg[0];
    ++  zType = azArg[1];
    ++  zSql = azArg[2];
    ++
    ++  if( strcmp(zTable, "sqlite_sequence")==0 ){
    ++    raw_printf(p->out, "DELETE FROM sqlite_sequence;\n");
    ++  }else if( sqlite3_strglob("sqlite_stat?", zTable)==0 ){
    ++    raw_printf(p->out, "ANALYZE sqlite_master;\n");
    ++  }else if( strncmp(zTable, "sqlite_", 7)==0 ){
    ++    return 0;
    ++  }else if( strncmp(zSql, "CREATE VIRTUAL TABLE", 20)==0 ){
    ++    char *zIns;
    ++    if( !p->writableSchema ){
    ++      raw_printf(p->out, "PRAGMA writable_schema=ON;\n");
    ++      p->writableSchema = 1;
    ++    }
    ++    zIns = sqlite3_mprintf(
    ++       "INSERT INTO sqlite_master(type,name,tbl_name,rootpage,sql)"
    ++       "VALUES('table','%q','%q',0,'%q');",
    ++       zTable, zTable, zSql);
    ++    utf8_printf(p->out, "%s\n", zIns);
    ++    sqlite3_free(zIns);
    ++    return 0;
    ++  }else{
    ++    printSchemaLine(p->out, zSql, ";\n");
    ++  }
    ++
    ++  if( strcmp(zType, "table")==0 ){
    ++    ShellText sSelect;
    ++    ShellText sTable;
    ++    char **azCol;
    ++    int i;
    ++    char *savedDestTable;
    ++    int savedMode;
    ++
    ++    azCol = tableColumnList(p, zTable);
    ++    if( azCol==0 ){
    ++      p->nErr++;
    ++      return 0;
    ++    }
    ++
    ++    /* Always quote the table name, even if it appears to be pure ascii,
    ++    ** in case it is a keyword. Ex:  INSERT INTO "table" ... */
    ++    initText(&sTable);
    ++    appendText(&sTable, zTable, quoteChar(zTable));
    ++    /* If preserving the rowid, add a column list after the table name.
    ++    ** In other words:  "INSERT INTO tab(rowid,a,b,c,...) VALUES(...)"
    ++    ** instead of the usual "INSERT INTO tab VALUES(...)".
    ++    */
    ++    if( azCol[0] ){
    ++      appendText(&sTable, "(", 0);
    ++      appendText(&sTable, azCol[0], 0);
    ++      for(i=1; azCol[i]; i++){
    ++        appendText(&sTable, ",", 0);
    ++        appendText(&sTable, azCol[i], quoteChar(azCol[i]));
    ++      }
    ++      appendText(&sTable, ")", 0);
    ++    }
    ++
    ++    /* Build an appropriate SELECT statement */
    ++    initText(&sSelect);
    ++    appendText(&sSelect, "SELECT ", 0);
    ++    if( azCol[0] ){
    ++      appendText(&sSelect, azCol[0], 0);
    ++      appendText(&sSelect, ",", 0);
    ++    }
    ++    for(i=1; azCol[i]; i++){
    ++      appendText(&sSelect, azCol[i], quoteChar(azCol[i]));
    ++      if( azCol[i+1] ){
    ++        appendText(&sSelect, ",", 0);
    ++      }
    ++    }
    ++    freeColumnList(azCol);
    ++    appendText(&sSelect, " FROM ", 0);
    ++    appendText(&sSelect, zTable, quoteChar(zTable));
    ++
    ++    savedDestTable = p->zDestTable;
    ++    savedMode = p->mode;
    ++    p->zDestTable = sTable.z;
    ++    p->mode = p->cMode = MODE_Insert;
    ++    rc = shell_exec(p->db, sSelect.z, shell_callback, p, 0);
    ++    if( (rc&0xff)==SQLITE_CORRUPT ){
    ++      raw_printf(p->out, "/****** CORRUPTION ERROR *******/\n");
    ++      toggleSelectOrder(p->db);
    ++      shell_exec(p->db, sSelect.z, shell_callback, p, 0);
    ++      toggleSelectOrder(p->db);
    ++    }
    ++    p->zDestTable = savedDestTable;
    ++    p->mode = savedMode;
    ++    freeText(&sTable);
    ++    freeText(&sSelect);
    ++    if( rc ) p->nErr++;
    ++  }
    ++  return 0;
    ++}
    ++
    ++/*
    ++** Run zQuery.  Use dump_callback() as the callback routine so that
    ++** the contents of the query are output as SQL statements.
    ++**
    ++** If we get a SQLITE_CORRUPT error, rerun the query after appending
    ++** "ORDER BY rowid DESC" to the end.
    ++*/
    ++static int run_schema_dump_query(
    ++  ShellState *p,
    ++  const char *zQuery
    ++){
    ++  int rc;
    ++  char *zErr = 0;
    ++  rc = sqlite3_exec(p->db, zQuery, dump_callback, p, &zErr);
    ++  if( rc==SQLITE_CORRUPT ){
    ++    char *zQ2;
    ++    int len = strlen30(zQuery);
    ++    raw_printf(p->out, "/****** CORRUPTION ERROR *******/\n");
    ++    if( zErr ){
    ++      utf8_printf(p->out, "/****** %s ******/\n", zErr);
    ++      sqlite3_free(zErr);
    ++      zErr = 0;
    ++    }
    ++    zQ2 = malloc( len+100 );
    ++    if( zQ2==0 ) return rc;
    ++    sqlite3_snprintf(len+100, zQ2, "%s ORDER BY rowid DESC", zQuery);
    ++    rc = sqlite3_exec(p->db, zQ2, dump_callback, p, &zErr);
    ++    if( rc ){
    ++      utf8_printf(p->out, "/****** ERROR: %s ******/\n", zErr);
    ++    }else{
    ++      rc = SQLITE_CORRUPT;
    ++    }
    ++    sqlite3_free(zErr);
    ++    free(zQ2);
    ++  }
    ++  return rc;
    ++}
    ++
    ++/*
    ++** Text of a help message
    ++*/
    ++static char zHelp[] =
    ++#if defined(SQLITE_HAVE_ZLIB) && !defined(SQLITE_OMIT_VIRTUALTABLE)
    ++  ".archive ...           Manage SQL archives: \".archive --help\" for details\n"
    ++#endif
    ++#ifndef SQLITE_OMIT_AUTHORIZATION
    ++  ".auth ON|OFF           Show authorizer callbacks\n"
    ++#endif
    ++  ".backup ?DB? FILE      Backup DB (default \"main\") to FILE\n"
    ++  ".bail on|off           Stop after hitting an error.  Default OFF\n"
    ++  ".binary on|off         Turn binary output on or off.  Default OFF\n"
    ++  ".cd DIRECTORY          Change the working directory to DIRECTORY\n"
    ++  ".changes on|off        Show number of rows changed by SQL\n"
    ++  ".check GLOB            Fail if output since .testcase does not match\n"
    ++  ".clone NEWDB           Clone data into NEWDB from the existing database\n"
    ++  ".databases             List names and files of attached databases\n"
    ++  ".dbinfo ?DB?           Show status information about the database\n"
    ++  ".dump ?TABLE? ...      Dump the database in an SQL text format\n"
    ++  "                         If TABLE specified, only dump tables matching\n"
    ++  "                         LIKE pattern TABLE.\n"
    ++  ".echo on|off           Turn command echo on or off\n"
    ++  ".eqp on|off|full       Enable or disable automatic EXPLAIN QUERY PLAN\n"
    ++  ".excel                 Display the output of next command in a spreadsheet\n"
    ++  ".exit                  Exit this program\n"
    ++  ".expert                EXPERIMENTAL. Suggest indexes for specified queries\n"
    ++/* Because explain mode comes on automatically now, the ".explain" mode
    ++** is removed from the help screen.  It is still supported for legacy, however */
    ++/*".explain ?on|off|auto? Turn EXPLAIN output mode on or off or to automatic\n"*/
    ++  ".fullschema ?--indent? Show schema and the content of sqlite_stat tables\n"
    ++  ".headers on|off        Turn display of headers on or off\n"
    ++  ".help                  Show this message\n"
    ++  ".import FILE TABLE     Import data from FILE into TABLE\n"
    ++#ifndef SQLITE_OMIT_TEST_CONTROL
    ++  ".imposter INDEX TABLE  Create imposter table TABLE on index INDEX\n"
    ++#endif
    ++  ".indexes ?TABLE?       Show names of all indexes\n"
    ++  "                         If TABLE specified, only show indexes for tables\n"
    ++  "                         matching LIKE pattern TABLE.\n"
    ++#ifdef SQLITE_ENABLE_IOTRACE
    ++  ".iotrace FILE          Enable I/O diagnostic logging to FILE\n"
    ++#endif
    ++  ".limit ?LIMIT? ?VAL?   Display or change the value of an SQLITE_LIMIT\n"
    ++  ".lint OPTIONS          Report potential schema issues. Options:\n"
    ++  "                         fkey-indexes     Find missing foreign key indexes\n"
    ++#ifndef SQLITE_OMIT_LOAD_EXTENSION
    ++  ".load FILE ?ENTRY?     Load an extension library\n"
    ++#endif
    ++  ".log FILE|off          Turn logging on or off.  FILE can be stderr/stdout\n"
    ++  ".mode MODE ?TABLE?     Set output mode where MODE is one of:\n"
    ++  "                         ascii    Columns/rows delimited by 0x1F and 0x1E\n"
    ++  "                         csv      Comma-separated values\n"
    ++  "                         column   Left-aligned columns.  (See .width)\n"
    ++  "                         html     HTML <table> code\n"
    ++  "                         insert   SQL insert statements for TABLE\n"
    ++  "                         line     One value per line\n"
    ++  "                         list     Values delimited by \"|\"\n"
    ++  "                         quote    Escape answers as for SQL\n"
    ++  "                         tabs     Tab-separated values\n"
    ++  "                         tcl      TCL list elements\n"
    ++  ".nullvalue STRING      Use STRING in place of NULL values\n"
    ++  ".once (-e|-x|FILE)     Output for the next SQL command only to FILE\n"
    ++  "                         or invoke system text editor (-e) or spreadsheet (-x)\n"
    ++  "                         on the output.\n"
    ++  ".open ?OPTIONS? ?FILE? Close existing database and reopen FILE\n"
    ++  "                         The --new option starts with an empty file\n"
    ++  ".output ?FILE?         Send output to FILE or stdout\n"
    ++  ".print STRING...       Print literal STRING\n"
    ++  ".prompt MAIN CONTINUE  Replace the standard prompts\n"
    ++  ".quit                  Exit this program\n"
    ++  ".read FILENAME         Execute SQL in FILENAME\n"
    ++  ".restore ?DB? FILE     Restore content of DB (default \"main\") from FILE\n"
    ++  ".save FILE             Write in-memory database into FILE\n"
    ++  ".scanstats on|off      Turn sqlite3_stmt_scanstatus() metrics on or off\n"
    ++  ".schema ?PATTERN?      Show the CREATE statements matching PATTERN\n"
    ++  "                          Add --indent for pretty-printing\n"
    ++  ".selftest ?--init?     Run tests defined in the SELFTEST table\n"
    ++  ".separator COL ?ROW?   Change the column separator and optionally the row\n"
    ++  "                         separator for both the output mode and .import\n"
    ++#if defined(SQLITE_ENABLE_SESSION)
    ++  ".session CMD ...       Create or control sessions\n"
    ++#endif
    ++  ".sha3sum ?OPTIONS...?  Compute a SHA3 hash of database content\n"
    ++  ".shell CMD ARGS...     Run CMD ARGS... in a system shell\n"
    ++  ".show                  Show the current values for various settings\n"
    ++  ".stats ?on|off?        Show stats or turn stats on or off\n"
    ++  ".system CMD ARGS...    Run CMD ARGS... in a system shell\n"
    ++  ".tables ?TABLE?        List names of tables\n"
    ++  "                         If TABLE specified, only list tables matching\n"
    ++  "                         LIKE pattern TABLE.\n"
    ++  ".testcase NAME         Begin redirecting output to 'testcase-out.txt'\n"
    ++  ".timeout MS            Try opening locked tables for MS milliseconds\n"
    ++  ".timer on|off          Turn SQL timer on or off\n"
    ++  ".trace FILE|off        Output each SQL statement as it is run\n"
    ++  ".vfsinfo ?AUX?         Information about the top-level VFS\n"
    ++  ".vfslist               List all available VFSes\n"
    ++  ".vfsname ?AUX?         Print the name of the VFS stack\n"
    ++  ".width NUM1 NUM2 ...   Set column widths for \"column\" mode\n"
    ++  "                         Negative values right-justify\n"
    ++;
    ++
    ++#if defined(SQLITE_ENABLE_SESSION)
    ++/*
    ++** Print help information for the ".sessions" command
    ++*/
    ++void session_help(ShellState *p){
    ++  raw_printf(p->out,
    ++    ".session ?NAME? SUBCOMMAND ?ARGS...?\n"
    ++    "If ?NAME? is omitted, the first defined session is used.\n"
    ++    "Subcommands:\n"
    ++    "   attach TABLE             Attach TABLE\n"
    ++    "   changeset FILE           Write a changeset into FILE\n"
    ++    "   close                    Close one session\n"
    ++    "   enable ?BOOLEAN?         Set or query the enable bit\n"
    ++    "   filter GLOB...           Reject tables matching GLOBs\n"
    ++    "   indirect ?BOOLEAN?       Mark or query the indirect status\n"
    ++    "   isempty                  Query whether the session is empty\n"
    ++    "   list                     List currently open session names\n"
    ++    "   open DB NAME             Open a new session on DB\n"
    ++    "   patchset FILE            Write a patchset into FILE\n"
    ++  );
    ++}
    ++#endif
    ++
    ++
    ++/* Forward reference */
    ++static int process_input(ShellState *p, FILE *in);
    ++
    ++/*
    ++** Read the content of file zName into memory obtained from sqlite3_malloc64()
    ++** and return a pointer to the buffer. The caller is responsible for freeing
    ++** the memory.
    ++**
    ++** If parameter pnByte is not NULL, (*pnByte) is set to the number of bytes
    ++** read.
    ++**
    ++** For convenience, a nul-terminator byte is always appended to the data read
    ++** from the file before the buffer is returned. This byte is not included in
    ++** the final value of (*pnByte), if applicable.
    ++**
    ++** NULL is returned if any error is encountered. The final value of *pnByte
    ++** is undefined in this case.
    ++*/
    ++static char *readFile(const char *zName, int *pnByte){
    ++  FILE *in = fopen(zName, "rb");
    ++  long nIn;
    ++  size_t nRead;
    ++  char *pBuf;
    ++  if( in==0 ) return 0;
    ++  fseek(in, 0, SEEK_END);
    ++  nIn = ftell(in);
    ++  rewind(in);
    ++  pBuf = sqlite3_malloc64( nIn+1 );
    ++  if( pBuf==0 ) return 0;
    ++  nRead = fread(pBuf, nIn, 1, in);
    ++  fclose(in);
    ++  if( nRead!=1 ){
    ++    sqlite3_free(pBuf);
    ++    return 0;
    ++  }
    ++  pBuf[nIn] = 0;
    ++  if( pnByte ) *pnByte = nIn;
    ++  return pBuf;
    ++}
    ++
    ++#if defined(SQLITE_ENABLE_SESSION)
    ++/*
    ++** Close a single OpenSession object and release all of its associated
    ++** resources.
    ++*/
    ++static void session_close(OpenSession *pSession){
    ++  int i;
    ++  sqlite3session_delete(pSession->p);
    ++  sqlite3_free(pSession->zName);
    ++  for(i=0; i<pSession->nFilter; i++){
    ++    sqlite3_free(pSession->azFilter[i]);
    ++  }
    ++  sqlite3_free(pSession->azFilter);
    ++  memset(pSession, 0, sizeof(OpenSession));
    ++}
    ++#endif
    ++
    ++/*
    ++** Close all OpenSession objects and release all associated resources.
    ++*/
    ++#if defined(SQLITE_ENABLE_SESSION)
    ++static void session_close_all(ShellState *p){
    ++  int i;
    ++  for(i=0; i<p->nSession; i++){
    ++    session_close(&p->aSession[i]);
    ++  }
    ++  p->nSession = 0;
    ++}
    ++#else
    ++# define session_close_all(X)
    ++#endif
    ++
    ++/*
    ++** Implementation of the xFilter function for an open session.  Omit
    ++** any tables named by ".session filter" but let all other table through.
    ++*/
    ++#if defined(SQLITE_ENABLE_SESSION)
    ++static int session_filter(void *pCtx, const char *zTab){
    ++  OpenSession *pSession = (OpenSession*)pCtx;
    ++  int i;
    ++  for(i=0; i<pSession->nFilter; i++){
    ++    if( sqlite3_strglob(pSession->azFilter[i], zTab)==0 ) return 0;
    ++  }
    ++  return 1;
    ++}
    ++#endif
    ++
    ++/*
    ++** Try to deduce the type of file for zName based on its content.  Return
    ++** one of the SHELL_OPEN_* constants.
    ++*/
    ++static int deduceDatabaseType(const char *zName){
    ++  FILE *f = fopen(zName, "rb");
    ++  size_t n;
    ++  int rc = SHELL_OPEN_UNSPEC;
    ++  char zBuf[100];
    ++  if( f==0 ) return SHELL_OPEN_NORMAL;
    ++  fseek(f, -25, SEEK_END);
    ++  n = fread(zBuf, 25, 1, f);
    ++  if( n==1 && memcmp(zBuf, "Start-Of-SQLite3-", 17)==0 ){
    ++    rc = SHELL_OPEN_APPENDVFS;
    ++  }else{
    ++    fseek(f, -22, SEEK_END);
    ++    n = fread(zBuf, 22, 1, f);
    ++    if( n==1 && zBuf[0]==0x50 && zBuf[1]==0x4b && zBuf[2]==0x05
    ++       && zBuf[3]==0x06 ){
    ++      rc = SHELL_OPEN_ZIPFILE;
    ++    }
    ++  }
    ++  fclose(f);
    ++  return rc;  
    ++}
    ++
    ++/*
    ++** Make sure the database is open.  If it is not, then open it.  If
    ++** the database fails to open, print an error message and exit.
    ++*/
    ++static void open_db(ShellState *p, int keepAlive){
    ++  if( p->db==0 ){
    ++    sqlite3_initialize();
    ++    if( p->openMode==SHELL_OPEN_UNSPEC && access(p->zDbFilename,0)==0 ){
    ++      p->openMode = deduceDatabaseType(p->zDbFilename);
    ++    }
    ++    switch( p->openMode ){
    ++      case SHELL_OPEN_APPENDVFS: {
    ++        sqlite3_open_v2(p->zDbFilename, &p->db, 
    ++           SQLITE_OPEN_READWRITE|SQLITE_OPEN_CREATE, "apndvfs");
    ++        break;
    ++      }
    ++      case SHELL_OPEN_ZIPFILE: {
    ++        sqlite3_open(":memory:", &p->db);
    ++        break;
    ++      }
    ++      case SHELL_OPEN_UNSPEC:
    ++      case SHELL_OPEN_NORMAL: {
    ++        sqlite3_open(p->zDbFilename, &p->db);
    ++        break;
    ++      }
    ++    }
    ++    globalDb = p->db;
    ++    if( p->db==0 || SQLITE_OK!=sqlite3_errcode(p->db) ){
    ++      utf8_printf(stderr,"Error: unable to open database \"%s\": %s\n",
    ++          p->zDbFilename, sqlite3_errmsg(p->db));
    ++      if( keepAlive ) return;
    ++      exit(1);
    ++    }
    ++#ifndef SQLITE_OMIT_LOAD_EXTENSION
    ++    sqlite3_enable_load_extension(p->db, 1);
    ++#endif
    ++    sqlite3_fileio_init(p->db, 0, 0);
    ++    sqlite3_shathree_init(p->db, 0, 0);
    ++    sqlite3_completion_init(p->db, 0, 0);
    ++#ifdef SQLITE_HAVE_ZLIB
    ++    sqlite3_zipfile_init(p->db, 0, 0);
    ++    sqlite3_sqlar_init(p->db, 0, 0);
    ++#endif
    ++    sqlite3_create_function(p->db, "shell_add_schema", 3, SQLITE_UTF8, 0,
    ++                            shellAddSchemaName, 0, 0);
    ++    sqlite3_create_function(p->db, "shell_module_schema", 1, SQLITE_UTF8, 0,
    ++                            shellModuleSchema, 0, 0);
    ++    sqlite3_create_function(p->db, "shell_putsnl", 1, SQLITE_UTF8, p,
    ++                            shellPutsFunc, 0, 0);
    ++    sqlite3_create_function(p->db, "edit", 1, SQLITE_UTF8, 0,
    ++                            editFunc, 0, 0);
    ++    sqlite3_create_function(p->db, "edit", 2, SQLITE_UTF8, 0,
    ++                            editFunc, 0, 0);
    ++
    ++    // Begin Android Add
    ++    #ifndef NO_ANDROID_FUNCS
    ++        InitializeIcuOrDie();
    ++        int err = register_localized_collators(p->db, "en_US", 0);
    ++        if (err != SQLITE_OK) {
    ++          fprintf(stderr, "register_localized_collators() failed\n");
    ++          exit(1);
    ++        }
    ++        err = register_android_functions(p->db, 0);
    ++        if (err != SQLITE_OK) {
    ++          fprintf(stderr, "register_android_functions() failed\n");
    ++          exit(1);
    ++        }
    ++    #endif
    ++    // End Android Add
    ++
    ++    if( p->openMode==SHELL_OPEN_ZIPFILE ){
    ++      char *zSql = sqlite3_mprintf(
    ++         "CREATE VIRTUAL TABLE zip USING zipfile(%Q);", p->zDbFilename);
    ++      sqlite3_exec(p->db, zSql, 0, 0, 0);
    ++      sqlite3_free(zSql);
    ++    }
    ++  }
    ++}
    ++
    ++#if HAVE_READLINE || HAVE_EDITLINE
    ++/*
    ++** Readline completion callbacks
    ++*/
    ++static char *readline_completion_generator(const char *text, int state){
    ++  static sqlite3_stmt *pStmt = 0;
    ++  char *zRet;
    ++  if( state==0 ){
    ++    char *zSql;
    ++    sqlite3_finalize(pStmt);
    ++    zSql = sqlite3_mprintf("SELECT DISTINCT candidate COLLATE nocase"
    ++                           "  FROM completion(%Q) ORDER BY 1", text);
    ++    sqlite3_prepare_v2(globalDb, zSql, -1, &pStmt, 0);
    ++    sqlite3_free(zSql);
    ++  }
    ++  if( sqlite3_step(pStmt)==SQLITE_ROW ){
    ++    zRet = strdup((const char*)sqlite3_column_text(pStmt, 0));
    ++  }else{
    ++    sqlite3_finalize(pStmt);
    ++    pStmt = 0;
    ++    zRet = 0;
    ++  }
    ++  return zRet;
    ++}
    ++static char **readline_completion(const char *zText, int iStart, int iEnd){
    ++  rl_attempted_completion_over = 1;
    ++  return rl_completion_matches(zText, readline_completion_generator);
    ++}
    ++
    ++#elif HAVE_LINENOISE
    ++/*
    ++** Linenoise completion callback
    ++*/
    ++static void linenoise_completion(const char *zLine, linenoiseCompletions *lc){
    ++  int nLine = strlen30(zLine);
    ++  int i, iStart;
    ++  sqlite3_stmt *pStmt = 0;
    ++  char *zSql;
    ++  char zBuf[1000];
    ++
    ++  if( nLine>sizeof(zBuf)-30 ) return;
    ++  if( zLine[0]=='.' ) return;
    ++  for(i=nLine-1; i>=0 && (isalnum(zLine[i]) || zLine[i]=='_'); i--){}
    ++  if( i==nLine-1 ) return;
    ++  iStart = i+1;
    ++  memcpy(zBuf, zLine, iStart);
    ++  zSql = sqlite3_mprintf("SELECT DISTINCT candidate COLLATE nocase"
    ++                         "  FROM completion(%Q,%Q) ORDER BY 1",
    ++                         &zLine[iStart], zLine);
    ++  sqlite3_prepare_v2(globalDb, zSql, -1, &pStmt, 0);
    ++  sqlite3_free(zSql);
    ++  sqlite3_exec(globalDb, "PRAGMA page_count", 0, 0, 0); /* Load the schema */
    ++  while( sqlite3_step(pStmt)==SQLITE_ROW ){
    ++    const char *zCompletion = (const char*)sqlite3_column_text(pStmt, 0);
    ++    int nCompletion = sqlite3_column_bytes(pStmt, 0);
    ++    if( iStart+nCompletion < sizeof(zBuf)-1 ){
    ++      memcpy(zBuf+iStart, zCompletion, nCompletion+1);
    ++      linenoiseAddCompletion(lc, zBuf);
    ++    }
    ++  }
    ++  sqlite3_finalize(pStmt);
    ++}
    ++#endif
    ++
    ++/*
    ++** Do C-language style dequoting.
    ++**
    ++**    \a    -> alarm
    ++**    \b    -> backspace
    ++**    \t    -> tab
    ++**    \n    -> newline
    ++**    \v    -> vertical tab
    ++**    \f    -> form feed
    ++**    \r    -> carriage return
    ++**    \s    -> space
    ++**    \"    -> "
    ++**    \'    -> '
    ++**    \\    -> backslash
    ++**    \NNN  -> ascii character NNN in octal
    ++*/
    ++static void resolve_backslashes(char *z){
    ++  int i, j;
    ++  char c;
    ++  while( *z && *z!='\\' ) z++;
    ++  for(i=j=0; (c = z[i])!=0; i++, j++){
    ++    if( c=='\\' && z[i+1]!=0 ){
    ++      c = z[++i];
    ++      if( c=='a' ){
    ++        c = '\a';
    ++      }else if( c=='b' ){
    ++        c = '\b';
    ++      }else if( c=='t' ){
    ++        c = '\t';
    ++      }else if( c=='n' ){
    ++        c = '\n';
    ++      }else if( c=='v' ){
    ++        c = '\v';
    ++      }else if( c=='f' ){
    ++        c = '\f';
    ++      }else if( c=='r' ){
    ++        c = '\r';
    ++      }else if( c=='"' ){
    ++        c = '"';
    ++      }else if( c=='\'' ){
    ++        c = '\'';
    ++      }else if( c=='\\' ){
    ++        c = '\\';
    ++      }else if( c>='0' && c<='7' ){
    ++        c -= '0';
    ++        if( z[i+1]>='0' && z[i+1]<='7' ){
    ++          i++;
    ++          c = (c<<3) + z[i] - '0';
    ++          if( z[i+1]>='0' && z[i+1]<='7' ){
    ++            i++;
    ++            c = (c<<3) + z[i] - '0';
    ++          }
    ++        }
    ++      }
    ++    }
    ++    z[j] = c;
    ++  }
    ++  if( j<i ) z[j] = 0;
    ++}
    ++
    ++/*
    ++** Interpret zArg as either an integer or a boolean value.  Return 1 or 0
    ++** for TRUE and FALSE.  Return the integer value if appropriate.
    ++*/
    ++static int booleanValue(const char *zArg){
    ++  int i;
    ++  if( zArg[0]=='0' && zArg[1]=='x' ){
    ++    for(i=2; hexDigitValue(zArg[i])>=0; i++){}
    ++  }else{
    ++    for(i=0; zArg[i]>='0' && zArg[i]<='9'; i++){}
    ++  }
    ++  if( i>0 && zArg[i]==0 ) return (int)(integerValue(zArg) & 0xffffffff);
    ++  if( sqlite3_stricmp(zArg, "on")==0 || sqlite3_stricmp(zArg,"yes")==0 ){
    ++    return 1;
    ++  }
    ++  if( sqlite3_stricmp(zArg, "off")==0 || sqlite3_stricmp(zArg,"no")==0 ){
    ++    return 0;
    ++  }
    ++  utf8_printf(stderr, "ERROR: Not a boolean value: \"%s\". Assuming \"no\".\n",
    ++          zArg);
    ++  return 0;
    ++}
    ++
    ++/*
    ++** Set or clear a shell flag according to a boolean value.
    ++*/
    ++static void setOrClearFlag(ShellState *p, unsigned mFlag, const char *zArg){
    ++  if( booleanValue(zArg) ){
    ++    ShellSetFlag(p, mFlag);
    ++  }else{
    ++    ShellClearFlag(p, mFlag);
    ++  }
    ++}
    ++
    ++/*
    ++** Close an output file, assuming it is not stderr or stdout
    ++*/
    ++static void output_file_close(FILE *f){
    ++  if( f && f!=stdout && f!=stderr ) fclose(f);
    ++}
    ++
    ++/*
    ++** Try to open an output file.   The names "stdout" and "stderr" are
    ++** recognized and do the right thing.  NULL is returned if the output
    ++** filename is "off".
    ++*/
    ++static FILE *output_file_open(const char *zFile, int bTextMode){
    ++  FILE *f;
    ++  if( strcmp(zFile,"stdout")==0 ){
    ++    f = stdout;
    ++  }else if( strcmp(zFile, "stderr")==0 ){
    ++    f = stderr;
    ++  }else if( strcmp(zFile, "off")==0 ){
    ++    f = 0;
    ++  }else{
    ++    f = fopen(zFile, bTextMode ? "w" : "wb");
    ++    if( f==0 ){
    ++      utf8_printf(stderr, "Error: cannot open \"%s\"\n", zFile);
    ++    }
    ++  }
    ++  return f;
    ++}
    ++
    ++#if !defined(SQLITE_UNTESTABLE)
    ++#if !defined(SQLITE_OMIT_TRACE) && !defined(SQLITE_OMIT_FLOATING_POINT)
    ++/*
    ++** A routine for handling output from sqlite3_trace().
    ++*/
    ++static int sql_trace_callback(
    ++  unsigned mType,
    ++  void *pArg,
    ++  void *pP,
    ++  void *pX
    ++){
    ++  FILE *f = (FILE*)pArg;
    ++  UNUSED_PARAMETER(mType);
    ++  UNUSED_PARAMETER(pP);
    ++  if( f ){
    ++    const char *z = (const char*)pX;
    ++    int i = strlen30(z);
    ++    while( i>0 && z[i-1]==';' ){ i--; }
    ++    utf8_printf(f, "%.*s;\n", i, z);
    ++  }
    ++  return 0;
    ++}
    ++#endif
    ++#endif
    ++
    ++/*
    ++** A no-op routine that runs with the ".breakpoint" doc-command.  This is
    ++** a useful spot to set a debugger breakpoint.
    ++*/
    ++static void test_breakpoint(void){
    ++  static int nCall = 0;
    ++  nCall++;
    ++}
    ++
    ++/*
    ++** An object used to read a CSV and other files for import.
    ++*/
    ++typedef struct ImportCtx ImportCtx;
    ++struct ImportCtx {
    ++  const char *zFile;  /* Name of the input file */
    ++  FILE *in;           /* Read the CSV text from this input stream */
    ++  char *z;            /* Accumulated text for a field */
    ++  int n;              /* Number of bytes in z */
    ++  int nAlloc;         /* Space allocated for z[] */
    ++  int nLine;          /* Current line number */
    ++  int bNotFirst;      /* True if one or more bytes already read */
    ++  int cTerm;          /* Character that terminated the most recent field */
    ++  int cColSep;        /* The column separator character.  (Usually ",") */
    ++  int cRowSep;        /* The row separator character.  (Usually "\n") */
    ++};
    ++
    ++/* Append a single byte to z[] */
    ++static void import_append_char(ImportCtx *p, int c){
    ++  if( p->n+1>=p->nAlloc ){
    ++    p->nAlloc += p->nAlloc + 100;
    ++    p->z = sqlite3_realloc64(p->z, p->nAlloc);
    ++    if( p->z==0 ){
    ++      raw_printf(stderr, "out of memory\n");
    ++      exit(1);
    ++    }
    ++  }
    ++  p->z[p->n++] = (char)c;
    ++}
    ++
    ++/* Read a single field of CSV text.  Compatible with rfc4180 and extended
    ++** with the option of having a separator other than ",".
    ++**
    ++**   +  Input comes from p->in.
    ++**   +  Store results in p->z of length p->n.  Space to hold p->z comes
    ++**      from sqlite3_malloc64().
    ++**   +  Use p->cSep as the column separator.  The default is ",".
    ++**   +  Use p->rSep as the row separator.  The default is "\n".
    ++**   +  Keep track of the line number in p->nLine.
    ++**   +  Store the character that terminates the field in p->cTerm.  Store
    ++**      EOF on end-of-file.
    ++**   +  Report syntax errors on stderr
    ++*/
    ++static char *SQLITE_CDECL csv_read_one_field(ImportCtx *p){
    ++  int c;
    ++  int cSep = p->cColSep;
    ++  int rSep = p->cRowSep;
    ++  p->n = 0;
    ++  c = fgetc(p->in);
    ++  if( c==EOF || seenInterrupt ){
    ++    p->cTerm = EOF;
    ++    return 0;
    ++  }
    ++  if( c=='"' ){
    ++    int pc, ppc;
    ++    int startLine = p->nLine;
    ++    int cQuote = c;
    ++    pc = ppc = 0;
    ++    while( 1 ){
    ++      c = fgetc(p->in);
    ++      if( c==rSep ) p->nLine++;
    ++      if( c==cQuote ){
    ++        if( pc==cQuote ){
    ++          pc = 0;
    ++          continue;
    ++        }
    ++      }
    ++      if( (c==cSep && pc==cQuote)
    ++       || (c==rSep && pc==cQuote)
    ++       || (c==rSep && pc=='\r' && ppc==cQuote)
    ++       || (c==EOF && pc==cQuote)
    ++      ){
    ++        do{ p->n--; }while( p->z[p->n]!=cQuote );
    ++        p->cTerm = c;
    ++        break;
    ++      }
    ++      if( pc==cQuote && c!='\r' ){
    ++        utf8_printf(stderr, "%s:%d: unescaped %c character\n",
    ++                p->zFile, p->nLine, cQuote);
    ++      }
    ++      if( c==EOF ){
    ++        utf8_printf(stderr, "%s:%d: unterminated %c-quoted field\n",
    ++                p->zFile, startLine, cQuote);
    ++        p->cTerm = c;
    ++        break;
    ++      }
    ++      import_append_char(p, c);
    ++      ppc = pc;
    ++      pc = c;
    ++    }
    ++  }else{
    ++    /* If this is the first field being parsed and it begins with the
    ++    ** UTF-8 BOM  (0xEF BB BF) then skip the BOM */
    ++    if( (c&0xff)==0xef && p->bNotFirst==0 ){
    ++      import_append_char(p, c);
    ++      c = fgetc(p->in);
    ++      if( (c&0xff)==0xbb ){
    ++        import_append_char(p, c);
    ++        c = fgetc(p->in);
    ++        if( (c&0xff)==0xbf ){
    ++          p->bNotFirst = 1;
    ++          p->n = 0;
    ++          return csv_read_one_field(p);
    ++        }
    ++      }
    ++    }
    ++    while( c!=EOF && c!=cSep && c!=rSep ){
    ++      import_append_char(p, c);
    ++      c = fgetc(p->in);
    ++    }
    ++    if( c==rSep ){
    ++      p->nLine++;
    ++      if( p->n>0 && p->z[p->n-1]=='\r' ) p->n--;
    ++    }
    ++    p->cTerm = c;
    ++  }
    ++  if( p->z ) p->z[p->n] = 0;
    ++  p->bNotFirst = 1;
    ++  return p->z;
    ++}
    ++
    ++/* Read a single field of ASCII delimited text.
    ++**
    ++**   +  Input comes from p->in.
    ++**   +  Store results in p->z of length p->n.  Space to hold p->z comes
    ++**      from sqlite3_malloc64().
    ++**   +  Use p->cSep as the column separator.  The default is "\x1F".
    ++**   +  Use p->rSep as the row separator.  The default is "\x1E".
    ++**   +  Keep track of the row number in p->nLine.
    ++**   +  Store the character that terminates the field in p->cTerm.  Store
    ++**      EOF on end-of-file.
    ++**   +  Report syntax errors on stderr
    ++*/
    ++static char *SQLITE_CDECL ascii_read_one_field(ImportCtx *p){
    ++  int c;
    ++  int cSep = p->cColSep;
    ++  int rSep = p->cRowSep;
    ++  p->n = 0;
    ++  c = fgetc(p->in);
    ++  if( c==EOF || seenInterrupt ){
    ++    p->cTerm = EOF;
    ++    return 0;
    ++  }
    ++  while( c!=EOF && c!=cSep && c!=rSep ){
    ++    import_append_char(p, c);
    ++    c = fgetc(p->in);
    ++  }
    ++  if( c==rSep ){
    ++    p->nLine++;
    ++  }
    ++  p->cTerm = c;
    ++  if( p->z ) p->z[p->n] = 0;
    ++  return p->z;
    ++}
    ++
    ++/*
    ++** Try to transfer data for table zTable.  If an error is seen while
    ++** moving forward, try to go backwards.  The backwards movement won't
    ++** work for WITHOUT ROWID tables.
    ++*/
    ++static void tryToCloneData(
    ++  ShellState *p,
    ++  sqlite3 *newDb,
    ++  const char *zTable
    ++){
    ++  sqlite3_stmt *pQuery = 0;
    ++  sqlite3_stmt *pInsert = 0;
    ++  char *zQuery = 0;
    ++  char *zInsert = 0;
    ++  int rc;
    ++  int i, j, n;
    ++  int nTable = strlen30(zTable);
    ++  int k = 0;
    ++  int cnt = 0;
    ++  const int spinRate = 10000;
    ++
    ++  zQuery = sqlite3_mprintf("SELECT * FROM \"%w\"", zTable);
    ++  rc = sqlite3_prepare_v2(p->db, zQuery, -1, &pQuery, 0);
    ++  if( rc ){
    ++    utf8_printf(stderr, "Error %d: %s on [%s]\n",
    ++            sqlite3_extended_errcode(p->db), sqlite3_errmsg(p->db),
    ++            zQuery);
    ++    goto end_data_xfer;
    ++  }
    ++  n = sqlite3_column_count(pQuery);
    ++  zInsert = sqlite3_malloc64(200 + nTable + n*3);
    ++  if( zInsert==0 ){
    ++    raw_printf(stderr, "out of memory\n");
    ++    goto end_data_xfer;
    ++  }
    ++  sqlite3_snprintf(200+nTable,zInsert,
    ++                   "INSERT OR IGNORE INTO \"%s\" VALUES(?", zTable);
    ++  i = strlen30(zInsert);
    ++  for(j=1; j<n; j++){
    ++    memcpy(zInsert+i, ",?", 2);
    ++    i += 2;
    ++  }
    ++  memcpy(zInsert+i, ");", 3);
    ++  rc = sqlite3_prepare_v2(newDb, zInsert, -1, &pInsert, 0);
    ++  if( rc ){
    ++    utf8_printf(stderr, "Error %d: %s on [%s]\n",
    ++            sqlite3_extended_errcode(newDb), sqlite3_errmsg(newDb),
    ++            zQuery);
    ++    goto end_data_xfer;
    ++  }
    ++  for(k=0; k<2; k++){
    ++    while( (rc = sqlite3_step(pQuery))==SQLITE_ROW ){
    ++      for(i=0; i<n; i++){
    ++        switch( sqlite3_column_type(pQuery, i) ){
    ++          case SQLITE_NULL: {
    ++            sqlite3_bind_null(pInsert, i+1);
    ++            break;
    ++          }
    ++          case SQLITE_INTEGER: {
    ++            sqlite3_bind_int64(pInsert, i+1, sqlite3_column_int64(pQuery,i));
    ++            break;
    ++          }
    ++          case SQLITE_FLOAT: {
    ++            sqlite3_bind_double(pInsert, i+1, sqlite3_column_double(pQuery,i));
    ++            break;
    ++          }
    ++          case SQLITE_TEXT: {
    ++            sqlite3_bind_text(pInsert, i+1,
    ++                             (const char*)sqlite3_column_text(pQuery,i),
    ++                             -1, SQLITE_STATIC);
    ++            break;
    ++          }
    ++          case SQLITE_BLOB: {
    ++            sqlite3_bind_blob(pInsert, i+1, sqlite3_column_blob(pQuery,i),
    ++                                            sqlite3_column_bytes(pQuery,i),
    ++                                            SQLITE_STATIC);
    ++            break;
    ++          }
    ++        }
    ++      } /* End for */
    ++      rc = sqlite3_step(pInsert);
    ++      if( rc!=SQLITE_OK && rc!=SQLITE_ROW && rc!=SQLITE_DONE ){
    ++        utf8_printf(stderr, "Error %d: %s\n", sqlite3_extended_errcode(newDb),
    ++                        sqlite3_errmsg(newDb));
    ++      }
    ++      sqlite3_reset(pInsert);
    ++      cnt++;
    ++      if( (cnt%spinRate)==0 ){
    ++        printf("%c\b", "|/-\\"[(cnt/spinRate)%4]);
    ++        fflush(stdout);
    ++      }
    ++    } /* End while */
    ++    if( rc==SQLITE_DONE ) break;
    ++    sqlite3_finalize(pQuery);
    ++    sqlite3_free(zQuery);
    ++    zQuery = sqlite3_mprintf("SELECT * FROM \"%w\" ORDER BY rowid DESC;",
    ++                             zTable);
    ++    rc = sqlite3_prepare_v2(p->db, zQuery, -1, &pQuery, 0);
    ++    if( rc ){
    ++      utf8_printf(stderr, "Warning: cannot step \"%s\" backwards", zTable);
    ++      break;
    ++    }
    ++  } /* End for(k=0...) */
    ++
    ++end_data_xfer:
    ++  sqlite3_finalize(pQuery);
    ++  sqlite3_finalize(pInsert);
    ++  sqlite3_free(zQuery);
    ++  sqlite3_free(zInsert);
    ++}
    ++
    ++
    ++/*
    ++** Try to transfer all rows of the schema that match zWhere.  For
    ++** each row, invoke xForEach() on the object defined by that row.
    ++** If an error is encountered while moving forward through the
    ++** sqlite_master table, try again moving backwards.
    ++*/
    ++static void tryToCloneSchema(
    ++  ShellState *p,
    ++  sqlite3 *newDb,
    ++  const char *zWhere,
    ++  void (*xForEach)(ShellState*,sqlite3*,const char*)
    ++){
    ++  sqlite3_stmt *pQuery = 0;
    ++  char *zQuery = 0;
    ++  int rc;
    ++  const unsigned char *zName;
    ++  const unsigned char *zSql;
    ++  char *zErrMsg = 0;
    ++
    ++  zQuery = sqlite3_mprintf("SELECT name, sql FROM sqlite_master"
    ++                           " WHERE %s", zWhere);
    ++  rc = sqlite3_prepare_v2(p->db, zQuery, -1, &pQuery, 0);
    ++  if( rc ){
    ++    utf8_printf(stderr, "Error: (%d) %s on [%s]\n",
    ++                    sqlite3_extended_errcode(p->db), sqlite3_errmsg(p->db),
    ++                    zQuery);
    ++    goto end_schema_xfer;
    ++  }
    ++  while( (rc = sqlite3_step(pQuery))==SQLITE_ROW ){
    ++    zName = sqlite3_column_text(pQuery, 0);
    ++    zSql = sqlite3_column_text(pQuery, 1);
    ++    printf("%s... ", zName); fflush(stdout);
    ++    sqlite3_exec(newDb, (const char*)zSql, 0, 0, &zErrMsg);
    ++    if( zErrMsg ){
    ++      utf8_printf(stderr, "Error: %s\nSQL: [%s]\n", zErrMsg, zSql);
    ++      sqlite3_free(zErrMsg);
    ++      zErrMsg = 0;
    ++    }
    ++    if( xForEach ){
    ++      xForEach(p, newDb, (const char*)zName);
    ++    }
    ++    printf("done\n");
    ++  }
    ++  if( rc!=SQLITE_DONE ){
    ++    sqlite3_finalize(pQuery);
    ++    sqlite3_free(zQuery);
    ++    zQuery = sqlite3_mprintf("SELECT name, sql FROM sqlite_master"
    ++                             " WHERE %s ORDER BY rowid DESC", zWhere);
    ++    rc = sqlite3_prepare_v2(p->db, zQuery, -1, &pQuery, 0);
    ++    if( rc ){
    ++      utf8_printf(stderr, "Error: (%d) %s on [%s]\n",
    ++                      sqlite3_extended_errcode(p->db), sqlite3_errmsg(p->db),
    ++                      zQuery);
    ++      goto end_schema_xfer;
    ++    }
    ++    while( (rc = sqlite3_step(pQuery))==SQLITE_ROW ){
    ++      zName = sqlite3_column_text(pQuery, 0);
    ++      zSql = sqlite3_column_text(pQuery, 1);
    ++      printf("%s... ", zName); fflush(stdout);
    ++      sqlite3_exec(newDb, (const char*)zSql, 0, 0, &zErrMsg);
    ++      if( zErrMsg ){
    ++        utf8_printf(stderr, "Error: %s\nSQL: [%s]\n", zErrMsg, zSql);
    ++        sqlite3_free(zErrMsg);
    ++        zErrMsg = 0;
    ++      }
    ++      if( xForEach ){
    ++        xForEach(p, newDb, (const char*)zName);
    ++      }
    ++      printf("done\n");
    ++    }
    ++  }
    ++end_schema_xfer:
    ++  sqlite3_finalize(pQuery);
    ++  sqlite3_free(zQuery);
    ++}
    ++
    ++/*
    ++** Open a new database file named "zNewDb".  Try to recover as much information
    ++** as possible out of the main database (which might be corrupt) and write it
    ++** into zNewDb.
    ++*/
    ++static void tryToClone(ShellState *p, const char *zNewDb){
    ++  int rc;
    ++  sqlite3 *newDb = 0;
    ++  if( access(zNewDb,0)==0 ){
    ++    utf8_printf(stderr, "File \"%s\" already exists.\n", zNewDb);
    ++    return;
    ++  }
    ++  rc = sqlite3_open(zNewDb, &newDb);
    ++  if( rc ){
    ++    utf8_printf(stderr, "Cannot create output database: %s\n",
    ++            sqlite3_errmsg(newDb));
    ++  }else{
    ++    sqlite3_exec(p->db, "PRAGMA writable_schema=ON;", 0, 0, 0);
    ++    sqlite3_exec(newDb, "BEGIN EXCLUSIVE;", 0, 0, 0);
    ++    tryToCloneSchema(p, newDb, "type='table'", tryToCloneData);
    ++    tryToCloneSchema(p, newDb, "type!='table'", 0);
    ++    sqlite3_exec(newDb, "COMMIT;", 0, 0, 0);
    ++    sqlite3_exec(p->db, "PRAGMA writable_schema=OFF;", 0, 0, 0);
    +   }
    ++  sqlite3_close(newDb);
    + }
    + 
    + /*
    +-** Do C-language style dequoting.
    ++** Change the output file back to stdout.
    + **
    +-**    \a    -> alarm
    +-**    \b    -> backspace
    +-**    \t    -> tab
    +-**    \n    -> newline
    +-**    \v    -> vertical tab
    +-**    \f    -> form feed
    +-**    \r    -> carriage return
    +-**    \s    -> space
    +-**    \"    -> "
    +-**    \'    -> '
    +-**    \\    -> backslash
    +-**    \NNN  -> ascii character NNN in octal
    ++** If the p->doXdgOpen flag is set, that means the output was being
    ++** redirected to a temporary file named by p->zTempFile.  In that case,
    ++** launch start/open/xdg-open on that temporary file.
    + */
    +-static void resolve_backslashes(char *z){
    +-  int i, j;
    +-  char c;
    +-  while( *z && *z!='\\' ) z++;
    +-  for(i=j=0; (c = z[i])!=0; i++, j++){
    +-    if( c=='\\' && z[i+1]!=0 ){
    +-      c = z[++i];
    +-      if( c=='a' ){
    +-        c = '\a';
    +-      }else if( c=='b' ){
    +-        c = '\b';
    +-      }else if( c=='t' ){
    +-        c = '\t';
    +-      }else if( c=='n' ){
    +-        c = '\n';
    +-      }else if( c=='v' ){
    +-        c = '\v';
    +-      }else if( c=='f' ){
    +-        c = '\f';
    +-      }else if( c=='r' ){
    +-        c = '\r';
    +-      }else if( c=='"' ){
    +-        c = '"';
    +-      }else if( c=='\'' ){
    +-        c = '\'';
    +-      }else if( c=='\\' ){
    +-        c = '\\';
    +-      }else if( c>='0' && c<='7' ){
    +-        c -= '0';
    +-        if( z[i+1]>='0' && z[i+1]<='7' ){
    +-          i++;
    +-          c = (c<<3) + z[i] - '0';
    +-          if( z[i+1]>='0' && z[i+1]<='7' ){
    +-            i++;
    +-            c = (c<<3) + z[i] - '0';
    +-          }
    +-        }
    ++static void output_reset(ShellState *p){
    ++  if( p->outfile[0]=='|' ){
    ++#ifndef SQLITE_OMIT_POPEN
    ++    pclose(p->out);
    ++#endif
    ++  }else{
    ++    output_file_close(p->out);
    ++    if( p->doXdgOpen ){
    ++      const char *zXdgOpenCmd =
    ++#if defined(_WIN32)
    ++      "start";
    ++#elif defined(__APPLE__)
    ++      "open";
    ++#else
    ++      "xdg-open";
    ++#endif
    ++      char *zCmd;
    ++      zCmd = sqlite3_mprintf("%s %s", zXdgOpenCmd, p->zTempFile);
    ++      if( system(zCmd) ){
    ++        utf8_printf(stderr, "Failed: [%s]\n", zCmd);
    +       }
    ++      sqlite3_free(zCmd);
    ++      outputModePop(p);
    ++      p->doXdgOpen = 0;
    +     }
    +-    z[j] = c;
    +   }
    +-  if( j<i ) z[j] = 0;
    ++  p->outfile[0] = 0;
    ++  p->out = stdout;
    + }
    + 
    + /*
    +-** Return the value of a hexadecimal digit.  Return -1 if the input
    +-** is not a hex digit.
    ++** Run an SQL command and return the single integer result.
    + */
    +-static int hexDigitValue(char c){
    +-  if( c>='0' && c<='9' ) return c - '0';
    +-  if( c>='a' && c<='f' ) return c - 'a' + 10;
    +-  if( c>='A' && c<='F' ) return c - 'A' + 10;
    +-  return -1;
    ++static int db_int(ShellState *p, const char *zSql){
    ++  sqlite3_stmt *pStmt;
    ++  int res = 0;
    ++  sqlite3_prepare_v2(p->db, zSql, -1, &pStmt, 0);
    ++  if( pStmt && sqlite3_step(pStmt)==SQLITE_ROW ){
    ++    res = sqlite3_column_int(pStmt,0);
    ++  }
    ++  sqlite3_finalize(pStmt);
    ++  return res;
    + }
    + 
    + /*
    +-** Interpret zArg as an integer value, possibly with suffixes.
    ++** Convert a 2-byte or 4-byte big-endian integer into a native integer
    + */
    +-static sqlite3_int64 integerValue(const char *zArg){
    +-  sqlite3_int64 v = 0;
    +-  static const struct { char *zSuffix; int iMult; } aMult[] = {
    +-    { "KiB", 1024 },
    +-    { "MiB", 1024*1024 },
    +-    { "GiB", 1024*1024*1024 },
    +-    { "KB",  1000 },
    +-    { "MB",  1000000 },
    +-    { "GB",  1000000000 },
    +-    { "K",   1000 },
    +-    { "M",   1000000 },
    +-    { "G",   1000000000 },
    ++static unsigned int get2byteInt(unsigned char *a){
    ++  return (a[0]<<8) + a[1];
    ++}
    ++static unsigned int get4byteInt(unsigned char *a){
    ++  return (a[0]<<24) + (a[1]<<16) + (a[2]<<8) + a[3];
    ++}
    ++
    ++/*
    ++** Implementation of the ".info" command.
    ++**
    ++** Return 1 on error, 2 to exit, and 0 otherwise.
    ++*/
    ++static int shell_dbinfo_command(ShellState *p, int nArg, char **azArg){
    ++  static const struct { const char *zName; int ofst; } aField[] = {
    ++     { "file change counter:",  24  },
    ++     { "database page count:",  28  },
    ++     { "freelist page count:",  36  },
    ++     { "schema cookie:",        40  },
    ++     { "schema format:",        44  },
    ++     { "default cache size:",   48  },
    ++     { "autovacuum top root:",  52  },
    ++     { "incremental vacuum:",   64  },
    ++     { "text encoding:",        56  },
    ++     { "user version:",         60  },
    ++     { "application id:",       68  },
    ++     { "software version:",     96  },
    ++  };
    ++  static const struct { const char *zName; const char *zSql; } aQuery[] = {
    ++     { "number of tables:",
    ++       "SELECT count(*) FROM %s WHERE type='table'" },
    ++     { "number of indexes:",
    ++       "SELECT count(*) FROM %s WHERE type='index'" },
    ++     { "number of triggers:",
    ++       "SELECT count(*) FROM %s WHERE type='trigger'" },
    ++     { "number of views:",
    ++       "SELECT count(*) FROM %s WHERE type='view'" },
    ++     { "schema size:",
    ++       "SELECT total(length(sql)) FROM %s" },
    +   };
    +   int i;
    +-  int isNeg = 0;
    +-  if( zArg[0]=='-' ){
    +-    isNeg = 1;
    +-    zArg++;
    +-  }else if( zArg[0]=='+' ){
    +-    zArg++;
    ++  char *zSchemaTab;
    ++  char *zDb = nArg>=2 ? azArg[1] : "main";
    ++  sqlite3_stmt *pStmt = 0;
    ++  unsigned char aHdr[100];
    ++  open_db(p, 0);
    ++  if( p->db==0 ) return 1;
    ++  sqlite3_prepare_v2(p->db,"SELECT data FROM sqlite_dbpage(?1) WHERE pgno=1",
    ++                     -1, &pStmt, 0);
    ++  sqlite3_bind_text(pStmt, 1, zDb, -1, SQLITE_STATIC);
    ++  if( sqlite3_step(pStmt)==SQLITE_ROW
    ++   && sqlite3_column_bytes(pStmt,0)>100
    ++  ){
    ++    memcpy(aHdr, sqlite3_column_blob(pStmt,0), 100);
    ++    sqlite3_finalize(pStmt);
    ++  }else{
    ++    raw_printf(stderr, "unable to read database header\n");
    ++    sqlite3_finalize(pStmt);
    ++    return 1;
    +   }
    +-  if( zArg[0]=='0' && zArg[1]=='x' ){
    +-    int x;
    +-    zArg += 2;
    +-    while( (x = hexDigitValue(zArg[0]))>=0 ){
    +-      v = (v<<4) + x;
    +-      zArg++;
    ++  i = get2byteInt(aHdr+16);
    ++  if( i==1 ) i = 65536;
    ++  utf8_printf(p->out, "%-20s %d\n", "database page size:", i);
    ++  utf8_printf(p->out, "%-20s %d\n", "write format:", aHdr[18]);
    ++  utf8_printf(p->out, "%-20s %d\n", "read format:", aHdr[19]);
    ++  utf8_printf(p->out, "%-20s %d\n", "reserved bytes:", aHdr[20]);
    ++  for(i=0; i<ArraySize(aField); i++){
    ++    int ofst = aField[i].ofst;
    ++    unsigned int val = get4byteInt(aHdr + ofst);
    ++    utf8_printf(p->out, "%-20s %u", aField[i].zName, val);
    ++    switch( ofst ){
    ++      case 56: {
    ++        if( val==1 ) raw_printf(p->out, " (utf8)");
    ++        if( val==2 ) raw_printf(p->out, " (utf16le)");
    ++        if( val==3 ) raw_printf(p->out, " (utf16be)");
    ++      }
    +     }
    ++    raw_printf(p->out, "\n");
    ++  }
    ++  if( zDb==0 ){
    ++    zSchemaTab = sqlite3_mprintf("main.sqlite_master");
    ++  }else if( strcmp(zDb,"temp")==0 ){
    ++    zSchemaTab = sqlite3_mprintf("%s", "sqlite_temp_master");
    +   }else{
    +-    while( IsDigit(zArg[0]) ){
    +-      v = v*10 + zArg[0] - '0';
    +-      zArg++;
    +-    }
    ++    zSchemaTab = sqlite3_mprintf("\"%w\".sqlite_master", zDb);
    +   }
    +-  for(i=0; i<ArraySize(aMult); i++){
    +-    if( sqlite3_stricmp(aMult[i].zSuffix, zArg)==0 ){
    +-      v *= aMult[i].iMult;
    +-      break;
    +-    }
    ++  for(i=0; i<ArraySize(aQuery); i++){
    ++    char *zSql = sqlite3_mprintf(aQuery[i].zSql, zSchemaTab);
    ++    int val = db_int(p, zSql);
    ++    sqlite3_free(zSql);
    ++    utf8_printf(p->out, "%-20s %d\n", aQuery[i].zName, val);
    +   }
    +-  return isNeg? -v : v;
    ++  sqlite3_free(zSchemaTab);
    ++  return 0;
    + }
    + 
    + /*
    +-** Interpret zArg as either an integer or a boolean value.  Return 1 or 0
    +-** for TRUE and FALSE.  Return the integer value if appropriate.
    ++** Print the current sqlite3_errmsg() value to stderr and return 1.
    + */
    +-static int booleanValue(char *zArg){
    +-  int i;
    +-  if( zArg[0]=='0' && zArg[1]=='x' ){
    +-    for(i=2; hexDigitValue(zArg[i])>=0; i++){}
    +-  }else{
    +-    for(i=0; zArg[i]>='0' && zArg[i]<='9'; i++){}
    +-  }
    +-  if( i>0 && zArg[i]==0 ) return (int)(integerValue(zArg) & 0xffffffff);
    +-  if( sqlite3_stricmp(zArg, "on")==0 || sqlite3_stricmp(zArg,"yes")==0 ){
    +-    return 1;
    +-  }
    +-  if( sqlite3_stricmp(zArg, "off")==0 || sqlite3_stricmp(zArg,"no")==0 ){
    +-    return 0;
    +-  }
    +-  fprintf(stderr, "ERROR: Not a boolean value: \"%s\". Assuming \"no\".\n",
    +-          zArg);
    +-  return 0;
    ++static int shellDatabaseError(sqlite3 *db){
    ++  const char *zErr = sqlite3_errmsg(db);
    ++  utf8_printf(stderr, "Error: %s\n", zErr);
    ++  return 1;
    + }
    + 
    + /*
    +-** Close an output file, assuming it is not stderr or stdout
    ++** Print an out-of-memory message to stderr and return 1.
    + */
    +-static void output_file_close(FILE *f){
    +-  if( f && f!=stdout && f!=stderr ) fclose(f);
    ++static int shellNomemError(void){
    ++  raw_printf(stderr, "Error: out of memory\n");
    ++  return 1;
    + }
    + 
    + /*
    +-** Try to open an output file.   The names "stdout" and "stderr" are
    +-** recognized and do the right thing.  NULL is returned if the output 
    +-** filename is "off".
    ++** Compare the pattern in zGlob[] against the text in z[].  Return TRUE
    ++** if they match and FALSE (0) if they do not match.
    ++**
    ++** Globbing rules:
    ++**
    ++**      '*'       Matches any sequence of zero or more characters.
    ++**
    ++**      '?'       Matches exactly one character.
    ++**
    ++**     [...]      Matches one character from the enclosed list of
    ++**                characters.
    ++**
    ++**     [^...]     Matches one character not in the enclosed list.
    ++**
    ++**      '#'       Matches any sequence of one or more digits with an
    ++**                optional + or - sign in front
    ++**
    ++**      ' '       Any span of whitespace matches any other span of
    ++**                whitespace.
    ++**
    ++** Extra whitespace at the end of z[] is ignored.
    + */
    +-static FILE *output_file_open(const char *zFile){
    +-  FILE *f;
    +-  if( strcmp(zFile,"stdout")==0 ){
    +-    f = stdout;
    +-  }else if( strcmp(zFile, "stderr")==0 ){
    +-    f = stderr;
    +-  }else if( strcmp(zFile, "off")==0 ){
    +-    f = 0;
    +-  }else{
    +-    f = fopen(zFile, "wb");
    +-    if( f==0 ){
    +-      fprintf(stderr, "Error: cannot open \"%s\"\n", zFile);
    ++static int testcase_glob(const char *zGlob, const char *z){
    ++  int c, c2;
    ++  int invert;
    ++  int seen;
    ++
    ++  while( (c = (*(zGlob++)))!=0 ){
    ++    if( IsSpace(c) ){
    ++      if( !IsSpace(*z) ) return 0;
    ++      while( IsSpace(*zGlob) ) zGlob++;
    ++      while( IsSpace(*z) ) z++;
    ++    }else if( c=='*' ){
    ++      while( (c=(*(zGlob++))) == '*' || c=='?' ){
    ++        if( c=='?' && (*(z++))==0 ) return 0;
    ++      }
    ++      if( c==0 ){
    ++        return 1;
    ++      }else if( c=='[' ){
    ++        while( *z && testcase_glob(zGlob-1,z)==0 ){
    ++          z++;
    ++        }
    ++        return (*z)!=0;
    ++      }
    ++      while( (c2 = (*(z++)))!=0 ){
    ++        while( c2!=c ){
    ++          c2 = *(z++);
    ++          if( c2==0 ) return 0;
    ++        }
    ++        if( testcase_glob(zGlob,z) ) return 1;
    ++      }
    ++      return 0;
    ++    }else if( c=='?' ){
    ++      if( (*(z++))==0 ) return 0;
    ++    }else if( c=='[' ){
    ++      int prior_c = 0;
    ++      seen = 0;
    ++      invert = 0;
    ++      c = *(z++);
    ++      if( c==0 ) return 0;
    ++      c2 = *(zGlob++);
    ++      if( c2=='^' ){
    ++        invert = 1;
    ++        c2 = *(zGlob++);
    ++      }
    ++      if( c2==']' ){
    ++        if( c==']' ) seen = 1;
    ++        c2 = *(zGlob++);
    ++      }
    ++      while( c2 && c2!=']' ){
    ++        if( c2=='-' && zGlob[0]!=']' && zGlob[0]!=0 && prior_c>0 ){
    ++          c2 = *(zGlob++);
    ++          if( c>=prior_c && c<=c2 ) seen = 1;
    ++          prior_c = 0;
    ++        }else{
    ++          if( c==c2 ){
    ++            seen = 1;
    ++          }
    ++          prior_c = c2;
    ++        }
    ++        c2 = *(zGlob++);
    ++      }
    ++      if( c2==0 || (seen ^ invert)==0 ) return 0;
    ++    }else if( c=='#' ){
    ++      if( (z[0]=='-' || z[0]=='+') && IsDigit(z[1]) ) z++;
    ++      if( !IsDigit(z[0]) ) return 0;
    ++      z++;
    ++      while( IsDigit(z[0]) ){ z++; }
    ++    }else{
    ++      if( c!=(*(z++)) ) return 0;
    +     }
    +   }
    +-  return f;
    ++  while( IsSpace(*z) ){ z++; }
    ++  return *z==0;
    + }
    + 
    ++
    + /*
    +-** A routine for handling output from sqlite3_trace().
    ++** Compare the string as a command-line option with either one or two
    ++** initial "-" characters.
    + */
    +-static void sql_trace_callback(void *pArg, const char *z){
    +-  FILE *f = (FILE*)pArg;
    +-  if( f ){
    +-    int i = (int)strlen(z);
    +-    while( i>0 && z[i-1]==';' ){ i--; }
    +-    fprintf(f, "%.*s;\n", i, z);
    +-  }
    ++static int optionMatch(const char *zStr, const char *zOpt){
    ++  if( zStr[0]!='-' ) return 0;
    ++  zStr++;
    ++  if( zStr[0]=='-' ) zStr++;
    ++  return strcmp(zStr, zOpt)==0;
    + }
    + 
    + /*
    +-** A no-op routine that runs with the ".breakpoint" doc-command.  This is
    +-** a useful spot to set a debugger breakpoint.
    ++** Delete a file.
    + */
    +-static void test_breakpoint(void){
    +-  static int nCall = 0;
    +-  nCall++;
    ++int shellDeleteFile(const char *zFilename){
    ++  int rc;
    ++#ifdef _WIN32
    ++  wchar_t *z = sqlite3_win32_utf8_to_unicode(zFilename);
    ++  rc = _wunlink(z);
    ++  sqlite3_free(z);
    ++#else
    ++  rc = unlink(zFilename);
    ++#endif
    ++  return rc;
    + }
    + 
    + /*
    +-** An object used to read a CSV and other files for import.
    ++** Try to delete the temporary file (if there is one) and free the
    ++** memory used to hold the name of the temp file.
    + */
    +-typedef struct ImportCtx ImportCtx;
    +-struct ImportCtx {
    +-  const char *zFile;  /* Name of the input file */
    +-  FILE *in;           /* Read the CSV text from this input stream */
    +-  char *z;            /* Accumulated text for a field */
    +-  int n;              /* Number of bytes in z */
    +-  int nAlloc;         /* Space allocated for z[] */
    +-  int nLine;          /* Current line number */
    +-  int cTerm;          /* Character that terminated the most recent field */
    +-  int cColSep;        /* The column separator character.  (Usually ",") */
    +-  int cRowSep;        /* The row separator character.  (Usually "\n") */
    +-};
    +-
    +-/* Append a single byte to z[] */
    +-static void import_append_char(ImportCtx *p, int c){
    +-  if( p->n+1>=p->nAlloc ){
    +-    p->nAlloc += p->nAlloc + 100;
    +-    p->z = sqlite3_realloc64(p->z, p->nAlloc);
    +-    if( p->z==0 ){
    +-      fprintf(stderr, "out of memory\n");
    +-      exit(1);
    +-    }
    +-  }
    +-  p->z[p->n++] = (char)c;
    ++static void clearTempFile(ShellState *p){
    ++  if( p->zTempFile==0 ) return;
    ++  if( p->doXdgOpen ) return;
    ++  if( shellDeleteFile(p->zTempFile) ) return;
    ++  sqlite3_free(p->zTempFile);
    ++  p->zTempFile = 0;
    + }
    + 
    +-/* Read a single field of CSV text.  Compatible with rfc4180 and extended
    +-** with the option of having a separator other than ",".
    +-**
    +-**   +  Input comes from p->in.
    +-**   +  Store results in p->z of length p->n.  Space to hold p->z comes
    +-**      from sqlite3_malloc64().
    +-**   +  Use p->cSep as the column separator.  The default is ",".
    +-**   +  Use p->rSep as the row separator.  The default is "\n".
    +-**   +  Keep track of the line number in p->nLine.
    +-**   +  Store the character that terminates the field in p->cTerm.  Store
    +-**      EOF on end-of-file.
    +-**   +  Report syntax errors on stderr
    ++/*
    ++** Create a new temp file name with the given suffix.
    + */
    +-static char *SQLITE_CDECL csv_read_one_field(ImportCtx *p){
    +-  int c;
    +-  int cSep = p->cColSep;
    +-  int rSep = p->cRowSep;
    +-  p->n = 0;
    +-  c = fgetc(p->in);
    +-  if( c==EOF || seenInterrupt ){
    +-    p->cTerm = EOF;
    +-    return 0;
    ++static void newTempFile(ShellState *p, const char *zSuffix){
    ++  clearTempFile(p);
    ++  sqlite3_free(p->zTempFile);
    ++  p->zTempFile = 0;
    ++  if( p->db ){
    ++    sqlite3_file_control(p->db, 0, SQLITE_FCNTL_TEMPFILENAME, &p->zTempFile);
    +   }
    +-  if( c=='"' ){
    +-    int pc, ppc;
    +-    int startLine = p->nLine;
    +-    int cQuote = c;
    +-    pc = ppc = 0;
    +-    while( 1 ){
    +-      c = fgetc(p->in);
    +-      if( c==rSep ) p->nLine++;
    +-      if( c==cQuote ){
    +-        if( pc==cQuote ){
    +-          pc = 0;
    +-          continue;
    +-        }
    +-      }
    +-      if( (c==cSep && pc==cQuote)
    +-       || (c==rSep && pc==cQuote)
    +-       || (c==rSep && pc=='\r' && ppc==cQuote)
    +-       || (c==EOF && pc==cQuote)
    +-      ){
    +-        do{ p->n--; }while( p->z[p->n]!=cQuote );
    +-        p->cTerm = c;
    +-        break;
    +-      }
    +-      if( pc==cQuote && c!='\r' ){
    +-        fprintf(stderr, "%s:%d: unescaped %c character\n",
    +-                p->zFile, p->nLine, cQuote);
    +-      }
    +-      if( c==EOF ){
    +-        fprintf(stderr, "%s:%d: unterminated %c-quoted field\n",
    +-                p->zFile, startLine, cQuote);
    +-        p->cTerm = c;
    +-        break;
    +-      }
    +-      import_append_char(p, c);
    +-      ppc = pc;
    +-      pc = c;
    +-    }
    ++  if( p->zTempFile==0 ){
    ++    sqlite3_uint64 r;
    ++    sqlite3_randomness(sizeof(r), &r);
    ++    p->zTempFile = sqlite3_mprintf("temp%llx.%s", r, zSuffix);
    +   }else{
    +-    while( c!=EOF && c!=cSep && c!=rSep ){
    +-      import_append_char(p, c);
    +-      c = fgetc(p->in);
    +-    }
    +-    if( c==rSep ){
    +-      p->nLine++;
    +-      if( p->n>0 && p->z[p->n-1]=='\r' ) p->n--;
    +-    }
    +-    p->cTerm = c;
    ++    p->zTempFile = sqlite3_mprintf("%z.%s", p->zTempFile, zSuffix);
    ++  }
    ++  if( p->zTempFile==0 ){
    ++    raw_printf(stderr, "out of memory\n");
    ++    exit(1);
    +   }
    +-  if( p->z ) p->z[p->n] = 0;
    +-  return p->z;
    + }
    + 
    +-/* Read a single field of ASCII delimited text.
    ++
    ++/*
    ++** The implementation of SQL scalar function fkey_collate_clause(), used
    ++** by the ".lint fkey-indexes" command. This scalar function is always
    ++** called with four arguments - the parent table name, the parent column name,
    ++** the child table name and the child column name.
    + **
    +-**   +  Input comes from p->in.
    +-**   +  Store results in p->z of length p->n.  Space to hold p->z comes
    +-**      from sqlite3_malloc64().
    +-**   +  Use p->cSep as the column separator.  The default is "\x1F".
    +-**   +  Use p->rSep as the row separator.  The default is "\x1E".
    +-**   +  Keep track of the row number in p->nLine.
    +-**   +  Store the character that terminates the field in p->cTerm.  Store
    +-**      EOF on end-of-file.
    +-**   +  Report syntax errors on stderr
    ++**   fkey_collate_clause('parent-tab', 'parent-col', 'child-tab', 'child-col')
    ++**
    ++** If either of the named tables or columns do not exist, this function
    ++** returns an empty string. An empty string is also returned if both tables
    ++** and columns exist but have the same default collation sequence. Or,
    ++** if both exist but the default collation sequences are different, this
    ++** function returns the string " COLLATE <parent-collation>", where
    ++** <parent-collation> is the default collation sequence of the parent column.
    + */
    +-static char *SQLITE_CDECL ascii_read_one_field(ImportCtx *p){
    +-  int c;
    +-  int cSep = p->cColSep;
    +-  int rSep = p->cRowSep;
    +-  p->n = 0;
    +-  c = fgetc(p->in);
    +-  if( c==EOF || seenInterrupt ){
    +-    p->cTerm = EOF;
    +-    return 0;
    +-  }
    +-  while( c!=EOF && c!=cSep && c!=rSep ){
    +-    import_append_char(p, c);
    +-    c = fgetc(p->in);
    ++static void shellFkeyCollateClause(
    ++  sqlite3_context *pCtx,
    ++  int nVal,
    ++  sqlite3_value **apVal
    ++){
    ++  sqlite3 *db = sqlite3_context_db_handle(pCtx);
    ++  const char *zParent;
    ++  const char *zParentCol;
    ++  const char *zParentSeq;
    ++  const char *zChild;
    ++  const char *zChildCol;
    ++  const char *zChildSeq = 0;  /* Initialize to avoid false-positive warning */
    ++  int rc;
    ++
    ++  assert( nVal==4 );
    ++  zParent = (const char*)sqlite3_value_text(apVal[0]);
    ++  zParentCol = (const char*)sqlite3_value_text(apVal[1]);
    ++  zChild = (const char*)sqlite3_value_text(apVal[2]);
    ++  zChildCol = (const char*)sqlite3_value_text(apVal[3]);
    ++
    ++  sqlite3_result_text(pCtx, "", -1, SQLITE_STATIC);
    ++  rc = sqlite3_table_column_metadata(
    ++      db, "main", zParent, zParentCol, 0, &zParentSeq, 0, 0, 0
    ++  );
    ++  if( rc==SQLITE_OK ){
    ++    rc = sqlite3_table_column_metadata(
    ++        db, "main", zChild, zChildCol, 0, &zChildSeq, 0, 0, 0
    ++    );
    +   }
    +-  if( c==rSep ){
    +-    p->nLine++;
    ++
    ++  if( rc==SQLITE_OK && sqlite3_stricmp(zParentSeq, zChildSeq) ){
    ++    char *z = sqlite3_mprintf(" COLLATE %s", zParentSeq);
    ++    sqlite3_result_text(pCtx, z, -1, SQLITE_TRANSIENT);
    ++    sqlite3_free(z);
    +   }
    +-  p->cTerm = c;
    +-  if( p->z ) p->z[p->n] = 0;
    +-  return p->z;
    + }
    + 
    ++
    + /*
    +-** Try to transfer data for table zTable.  If an error is seen while
    +-** moving forward, try to go backwards.  The backwards movement won't
    +-** work for WITHOUT ROWID tables.
    ++** The implementation of dot-command ".lint fkey-indexes".
    + */
    +-static void tryToCloneData(
    +-  ShellState *p,
    +-  sqlite3 *newDb,
    +-  const char *zTable
    ++static int lintFkeyIndexes(
    ++  ShellState *pState,             /* Current shell tool state */
    ++  char **azArg,                   /* Array of arguments passed to dot command */
    ++  int nArg                        /* Number of entries in azArg[] */
    + ){
    +-  sqlite3_stmt *pQuery = 0; 
    +-  sqlite3_stmt *pInsert = 0;
    +-  char *zQuery = 0;
    +-  char *zInsert = 0;
    +-  int rc;
    +-  int i, j, n;
    +-  int nTable = (int)strlen(zTable);
    +-  int k = 0;
    +-  int cnt = 0;
    +-  const int spinRate = 10000;
    +-
    +-  zQuery = sqlite3_mprintf("SELECT * FROM \"%w\"", zTable);
    +-  rc = sqlite3_prepare_v2(p->db, zQuery, -1, &pQuery, 0);
    +-  if( rc ){
    +-    fprintf(stderr, "Error %d: %s on [%s]\n",
    +-            sqlite3_extended_errcode(p->db), sqlite3_errmsg(p->db),
    +-            zQuery);
    +-    goto end_data_xfer;
    +-  }
    +-  n = sqlite3_column_count(pQuery);
    +-  zInsert = sqlite3_malloc64(200 + nTable + n*3);
    +-  if( zInsert==0 ){
    +-    fprintf(stderr, "out of memory\n");
    +-    goto end_data_xfer;
    ++  sqlite3 *db = pState->db;       /* Database handle to query "main" db of */
    ++  FILE *out = pState->out;        /* Stream to write non-error output to */
    ++  int bVerbose = 0;               /* If -verbose is present */
    ++  int bGroupByParent = 0;         /* If -groupbyparent is present */
    ++  int i;                          /* To iterate through azArg[] */
    ++  const char *zIndent = "";       /* How much to indent CREATE INDEX by */
    ++  int rc;                         /* Return code */
    ++  sqlite3_stmt *pSql = 0;         /* Compiled version of SQL statement below */
    ++
    ++  /*
    ++  ** This SELECT statement returns one row for each foreign key constraint
    ++  ** in the schema of the main database. The column values are:
    ++  **
    ++  ** 0. The text of an SQL statement similar to:
    ++  **
    ++  **      "EXPLAIN QUERY PLAN SELECT 1 FROM child_table WHERE child_key=?"
    ++  **
    ++  **    This SELECT is similar to the one that the foreign keys implementation
    ++  **    needs to run internally on child tables. If there is an index that can
    ++  **    be used to optimize this query, then it can also be used by the FK
    ++  **    implementation to optimize DELETE or UPDATE statements on the parent
    ++  **    table.
    ++  **
    ++  ** 1. A GLOB pattern suitable for sqlite3_strglob(). If the plan output by
    ++  **    the EXPLAIN QUERY PLAN command matches this pattern, then the schema
    ++  **    contains an index that can be used to optimize the query.
    ++  **
    ++  ** 2. Human readable text that describes the child table and columns. e.g.
    ++  **
    ++  **       "child_table(child_key1, child_key2)"
    ++  **
    ++  ** 3. Human readable text that describes the parent table and columns. e.g.
    ++  **
    ++  **       "parent_table(parent_key1, parent_key2)"
    ++  **
    ++  ** 4. A full CREATE INDEX statement for an index that could be used to
    ++  **    optimize DELETE or UPDATE statements on the parent table. e.g.
    ++  **
    ++  **       "CREATE INDEX child_table_child_key ON child_table(child_key)"
    ++  **
    ++  ** 5. The name of the parent table.
    ++  **
    ++  ** These six values are used by the C logic below to generate the report.
    ++  */
    ++  const char *zSql =
    ++  "SELECT "
    ++    "     'EXPLAIN QUERY PLAN SELECT 1 FROM ' || quote(s.name) || ' WHERE '"
    ++    "  || group_concat(quote(s.name) || '.' || quote(f.[from]) || '=?' "
    ++    "  || fkey_collate_clause("
    ++    "       f.[table], COALESCE(f.[to], p.[name]), s.name, f.[from]),' AND ')"
    ++    ", "
    ++    "     'SEARCH TABLE ' || s.name || ' USING COVERING INDEX*('"
    ++    "  || group_concat('*=?', ' AND ') || ')'"
    ++    ", "
    ++    "     s.name  || '(' || group_concat(f.[from],  ', ') || ')'"
    ++    ", "
    ++    "     f.[table] || '(' || group_concat(COALESCE(f.[to], p.[name])) || ')'"
    ++    ", "
    ++    "     'CREATE INDEX ' || quote(s.name ||'_'|| group_concat(f.[from], '_'))"
    ++    "  || ' ON ' || quote(s.name) || '('"
    ++    "  || group_concat(quote(f.[from]) ||"
    ++    "        fkey_collate_clause("
    ++    "          f.[table], COALESCE(f.[to], p.[name]), s.name, f.[from]), ', ')"
    ++    "  || ');'"
    ++    ", "
    ++    "     f.[table] "
    ++    "FROM sqlite_master AS s, pragma_foreign_key_list(s.name) AS f "
    ++    "LEFT JOIN pragma_table_info AS p ON (pk-1=seq AND p.arg=f.[table]) "
    ++    "GROUP BY s.name, f.id "
    ++    "ORDER BY (CASE WHEN ? THEN f.[table] ELSE s.name END)"
    ++  ;
    ++  const char *zGlobIPK = "SEARCH TABLE * USING INTEGER PRIMARY KEY (rowid=?)";
    ++
    ++  for(i=2; i<nArg; i++){
    ++    int n = strlen30(azArg[i]);
    ++    if( n>1 && sqlite3_strnicmp("-verbose", azArg[i], n)==0 ){
    ++      bVerbose = 1;
    ++    }
    ++    else if( n>1 && sqlite3_strnicmp("-groupbyparent", azArg[i], n)==0 ){
    ++      bGroupByParent = 1;
    ++      zIndent = "    ";
    ++    }
    ++    else{
    ++      raw_printf(stderr, "Usage: %s %s ?-verbose? ?-groupbyparent?\n",
    ++          azArg[0], azArg[1]
    ++      );
    ++      return SQLITE_ERROR;
    ++    }
    +   }
    +-  sqlite3_snprintf(200+nTable,zInsert,
    +-                   "INSERT OR IGNORE INTO \"%s\" VALUES(?", zTable);
    +-  i = (int)strlen(zInsert);
    +-  for(j=1; j<n; j++){
    +-    memcpy(zInsert+i, ",?", 2);
    +-    i += 2;
    ++
    ++  /* Register the fkey_collate_clause() SQL function */
    ++  rc = sqlite3_create_function(db, "fkey_collate_clause", 4, SQLITE_UTF8,
    ++      0, shellFkeyCollateClause, 0, 0
    ++  );
    ++
    ++
    ++  if( rc==SQLITE_OK ){
    ++    rc = sqlite3_prepare_v2(db, zSql, -1, &pSql, 0);
    +   }
    +-  memcpy(zInsert+i, ");", 3);
    +-  rc = sqlite3_prepare_v2(newDb, zInsert, -1, &pInsert, 0);
    +-  if( rc ){
    +-    fprintf(stderr, "Error %d: %s on [%s]\n",
    +-            sqlite3_extended_errcode(newDb), sqlite3_errmsg(newDb),
    +-            zQuery);
    +-    goto end_data_xfer;
    ++  if( rc==SQLITE_OK ){
    ++    sqlite3_bind_int(pSql, 1, bGroupByParent);
    +   }
    +-  for(k=0; k<2; k++){
    +-    while( (rc = sqlite3_step(pQuery))==SQLITE_ROW ){
    +-      for(i=0; i<n; i++){
    +-        switch( sqlite3_column_type(pQuery, i) ){
    +-          case SQLITE_NULL: {
    +-            sqlite3_bind_null(pInsert, i+1);
    +-            break;
    +-          }
    +-          case SQLITE_INTEGER: {
    +-            sqlite3_bind_int64(pInsert, i+1, sqlite3_column_int64(pQuery,i));
    +-            break;
    +-          }
    +-          case SQLITE_FLOAT: {
    +-            sqlite3_bind_double(pInsert, i+1, sqlite3_column_double(pQuery,i));
    +-            break;
    +-          }
    +-          case SQLITE_TEXT: {
    +-            sqlite3_bind_text(pInsert, i+1,
    +-                             (const char*)sqlite3_column_text(pQuery,i),
    +-                             -1, SQLITE_STATIC);
    +-            break;
    +-          }
    +-          case SQLITE_BLOB: {
    +-            sqlite3_bind_blob(pInsert, i+1, sqlite3_column_blob(pQuery,i),
    +-                                            sqlite3_column_bytes(pQuery,i),
    +-                                            SQLITE_STATIC);
    +-            break;
    +-          }
    +-        }
    +-      } /* End for */
    +-      rc = sqlite3_step(pInsert);
    +-      if( rc!=SQLITE_OK && rc!=SQLITE_ROW && rc!=SQLITE_DONE ){
    +-        fprintf(stderr, "Error %d: %s\n", sqlite3_extended_errcode(newDb),
    +-                        sqlite3_errmsg(newDb));
    +-      }
    +-      sqlite3_reset(pInsert);
    +-      cnt++;
    +-      if( (cnt%spinRate)==0 ){
    +-        printf("%c\b", "|/-\\"[(cnt/spinRate)%4]);
    +-        fflush(stdout);
    ++
    ++  if( rc==SQLITE_OK ){
    ++    int rc2;
    ++    char *zPrev = 0;
    ++    while( SQLITE_ROW==sqlite3_step(pSql) ){
    ++      int res = -1;
    ++      sqlite3_stmt *pExplain = 0;
    ++      const char *zEQP = (const char*)sqlite3_column_text(pSql, 0);
    ++      const char *zGlob = (const char*)sqlite3_column_text(pSql, 1);
    ++      const char *zFrom = (const char*)sqlite3_column_text(pSql, 2);
    ++      const char *zTarget = (const char*)sqlite3_column_text(pSql, 3);
    ++      const char *zCI = (const char*)sqlite3_column_text(pSql, 4);
    ++      const char *zParent = (const char*)sqlite3_column_text(pSql, 5);
    ++
    ++      rc = sqlite3_prepare_v2(db, zEQP, -1, &pExplain, 0);
    ++      if( rc!=SQLITE_OK ) break;
    ++      if( SQLITE_ROW==sqlite3_step(pExplain) ){
    ++        const char *zPlan = (const char*)sqlite3_column_text(pExplain, 3);
    ++        res = (
    ++              0==sqlite3_strglob(zGlob, zPlan)
    ++           || 0==sqlite3_strglob(zGlobIPK, zPlan)
    ++        );
    ++      }
    ++      rc = sqlite3_finalize(pExplain);
    ++      if( rc!=SQLITE_OK ) break;
    ++
    ++      if( res<0 ){
    ++        raw_printf(stderr, "Error: internal error");
    ++        break;
    ++      }else{
    ++        if( bGroupByParent
    ++        && (bVerbose || res==0)
    ++        && (zPrev==0 || sqlite3_stricmp(zParent, zPrev))
    ++        ){
    ++          raw_printf(out, "-- Parent table %s\n", zParent);
    ++          sqlite3_free(zPrev);
    ++          zPrev = sqlite3_mprintf("%s", zParent);
    ++        }
    ++
    ++        if( res==0 ){
    ++          raw_printf(out, "%s%s --> %s\n", zIndent, zCI, zTarget);
    ++        }else if( bVerbose ){
    ++          raw_printf(out, "%s/* no extra indexes required for %s -> %s */\n",
    ++              zIndent, zFrom, zTarget
    ++          );
    ++        }
    +       }
    +-    } /* End while */
    +-    if( rc==SQLITE_DONE ) break;
    +-    sqlite3_finalize(pQuery);
    +-    sqlite3_free(zQuery);
    +-    zQuery = sqlite3_mprintf("SELECT * FROM \"%w\" ORDER BY rowid DESC;",
    +-                             zTable);
    +-    rc = sqlite3_prepare_v2(p->db, zQuery, -1, &pQuery, 0);
    +-    if( rc ){
    +-      fprintf(stderr, "Warning: cannot step \"%s\" backwards", zTable);
    +-      break;
    +     }
    +-  } /* End for(k=0...) */
    ++    sqlite3_free(zPrev);
    + 
    +-end_data_xfer:
    +-  sqlite3_finalize(pQuery);
    +-  sqlite3_finalize(pInsert);
    +-  sqlite3_free(zQuery);
    +-  sqlite3_free(zInsert);
    +-}
    ++    if( rc!=SQLITE_OK ){
    ++      raw_printf(stderr, "%s\n", sqlite3_errmsg(db));
    ++    }
    ++
    ++    rc2 = sqlite3_finalize(pSql);
    ++    if( rc==SQLITE_OK && rc2!=SQLITE_OK ){
    ++      rc = rc2;
    ++      raw_printf(stderr, "%s\n", sqlite3_errmsg(db));
    ++    }
    ++  }else{
    ++    raw_printf(stderr, "%s\n", sqlite3_errmsg(db));
    ++  }
    + 
    ++  return rc;
    ++}
    + 
    + /*
    +-** Try to transfer all rows of the schema that match zWhere.  For
    +-** each row, invoke xForEach() on the object defined by that row.
    +-** If an error is encountered while moving forward through the
    +-** sqlite_master table, try again moving backwards.
    ++** Implementation of ".lint" dot command.
    + */
    +-static void tryToCloneSchema(
    +-  ShellState *p,
    +-  sqlite3 *newDb,
    +-  const char *zWhere,
    +-  void (*xForEach)(ShellState*,sqlite3*,const char*)
    ++static int lintDotCommand(
    ++  ShellState *pState,             /* Current shell tool state */
    ++  char **azArg,                   /* Array of arguments passed to dot command */
    ++  int nArg                        /* Number of entries in azArg[] */
    + ){
    +-  sqlite3_stmt *pQuery = 0;
    +-  char *zQuery = 0;
    +-  int rc;
    +-  const unsigned char *zName;
    +-  const unsigned char *zSql;
    +-  char *zErrMsg = 0;
    ++  int n;
    ++  n = (nArg>=2 ? strlen30(azArg[1]) : 0);
    ++  if( n<1 || sqlite3_strnicmp(azArg[1], "fkey-indexes", n) ) goto usage;
    ++  return lintFkeyIndexes(pState, azArg, nArg);
    ++
    ++ usage:
    ++  raw_printf(stderr, "Usage %s sub-command ?switches...?\n", azArg[0]);
    ++  raw_printf(stderr, "Where sub-commands are:\n");
    ++  raw_printf(stderr, "    fkey-indexes\n");
    ++  return SQLITE_ERROR;
    ++}
    + 
    +-  zQuery = sqlite3_mprintf("SELECT name, sql FROM sqlite_master"
    +-                           " WHERE %s", zWhere);
    +-  rc = sqlite3_prepare_v2(p->db, zQuery, -1, &pQuery, 0);
    +-  if( rc ){
    +-    fprintf(stderr, "Error: (%d) %s on [%s]\n",
    +-                    sqlite3_extended_errcode(p->db), sqlite3_errmsg(p->db),
    +-                    zQuery);
    +-    goto end_schema_xfer;
    +-  }
    +-  while( (rc = sqlite3_step(pQuery))==SQLITE_ROW ){
    +-    zName = sqlite3_column_text(pQuery, 0);
    +-    zSql = sqlite3_column_text(pQuery, 1);
    +-    printf("%s... ", zName); fflush(stdout);
    +-    sqlite3_exec(newDb, (const char*)zSql, 0, 0, &zErrMsg);
    +-    if( zErrMsg ){
    +-      fprintf(stderr, "Error: %s\nSQL: [%s]\n", zErrMsg, zSql);
    +-      sqlite3_free(zErrMsg);
    +-      zErrMsg = 0;
    +-    }
    +-    if( xForEach ){
    +-      xForEach(p, newDb, (const char*)zName);
    ++#if !defined(SQLITE_OMIT_VIRTUALTABLE) && defined(SQLITE_HAVE_ZLIB)
    ++/*********************************************************************************
    ++** The ".archive" or ".ar" command.
    ++*/
    ++static void shellPrepare(
    ++  sqlite3 *db, 
    ++  int *pRc, 
    ++  const char *zSql, 
    ++  sqlite3_stmt **ppStmt
    ++){
    ++  *ppStmt = 0;
    ++  if( *pRc==SQLITE_OK ){
    ++    int rc = sqlite3_prepare_v2(db, zSql, -1, ppStmt, 0);
    ++    if( rc!=SQLITE_OK ){
    ++      raw_printf(stderr, "sql error: %s (%d)\n", 
    ++          sqlite3_errmsg(db), sqlite3_errcode(db)
    ++      );
    ++      *pRc = rc;
    +     }
    +-    printf("done\n");
    +   }
    +-  if( rc!=SQLITE_DONE ){
    +-    sqlite3_finalize(pQuery);
    +-    sqlite3_free(zQuery);
    +-    zQuery = sqlite3_mprintf("SELECT name, sql FROM sqlite_master"
    +-                             " WHERE %s ORDER BY rowid DESC", zWhere);
    +-    rc = sqlite3_prepare_v2(p->db, zQuery, -1, &pQuery, 0);
    +-    if( rc ){
    +-      fprintf(stderr, "Error: (%d) %s on [%s]\n",
    +-                      sqlite3_extended_errcode(p->db), sqlite3_errmsg(p->db),
    +-                      zQuery);
    +-      goto end_schema_xfer;
    ++}
    ++
    ++static void shellPreparePrintf(
    ++  sqlite3 *db, 
    ++  int *pRc, 
    ++  sqlite3_stmt **ppStmt,
    ++  const char *zFmt, 
    ++  ...
    ++){
    ++  *ppStmt = 0;
    ++  if( *pRc==SQLITE_OK ){
    ++    va_list ap;
    ++    char *z;
    ++    va_start(ap, zFmt);
    ++    z = sqlite3_vmprintf(zFmt, ap);
    ++    if( z==0 ){
    ++      *pRc = SQLITE_NOMEM;
    ++    }else{
    ++      shellPrepare(db, pRc, z, ppStmt);
    ++      sqlite3_free(z);
    +     }
    +-    while( (rc = sqlite3_step(pQuery))==SQLITE_ROW ){
    +-      zName = sqlite3_column_text(pQuery, 0);
    +-      zSql = sqlite3_column_text(pQuery, 1);
    +-      printf("%s... ", zName); fflush(stdout);
    +-      sqlite3_exec(newDb, (const char*)zSql, 0, 0, &zErrMsg);
    +-      if( zErrMsg ){
    +-        fprintf(stderr, "Error: %s\nSQL: [%s]\n", zErrMsg, zSql);
    +-        sqlite3_free(zErrMsg);
    +-        zErrMsg = 0;
    +-      }
    +-      if( xForEach ){
    +-        xForEach(p, newDb, (const char*)zName);
    ++  }
    ++}
    ++
    ++static void shellFinalize(
    ++  int *pRc, 
    ++  sqlite3_stmt *pStmt
    ++){
    ++  if( pStmt ){
    ++    sqlite3 *db = sqlite3_db_handle(pStmt);
    ++    int rc = sqlite3_finalize(pStmt);
    ++    if( *pRc==SQLITE_OK ){
    ++      if( rc!=SQLITE_OK ){
    ++        raw_printf(stderr, "SQL error: %s\n", sqlite3_errmsg(db));
    +       }
    +-      printf("done\n");
    ++      *pRc = rc;
    +     }
    +   }
    +-end_schema_xfer:
    +-  sqlite3_finalize(pQuery);
    +-  sqlite3_free(zQuery);
    + }
    + 
    ++static void shellReset(
    ++  int *pRc, 
    ++  sqlite3_stmt *pStmt
    ++){
    ++  int rc = sqlite3_reset(pStmt);
    ++  if( *pRc==SQLITE_OK ){
    ++    if( rc!=SQLITE_OK ){
    ++      sqlite3 *db = sqlite3_db_handle(pStmt);
    ++      raw_printf(stderr, "SQL error: %s\n", sqlite3_errmsg(db));
    ++    }
    ++    *pRc = rc;
    ++  }
    ++}
    ++/*
    ++** Structure representing a single ".ar" command.
    ++*/
    ++typedef struct ArCommand ArCommand;
    ++struct ArCommand {
    ++  u8 eCmd;                        /* An AR_CMD_* value */
    ++  u8 bVerbose;                    /* True if --verbose */
    ++  u8 bZip;                        /* True if the archive is a ZIP */
    ++  u8 bDryRun;                     /* True if --dry-run */
    ++  u8 bAppend;                     /* True if --append */
    ++  int nArg;                       /* Number of command arguments */
    ++  char *zSrcTable;                /* "sqlar", "zipfile($file)" or "zip" */
    ++  const char *zFile;              /* --file argument, or NULL */
    ++  const char *zDir;               /* --directory argument, or NULL */
    ++  char **azArg;                   /* Array of command arguments */
    ++  ShellState *p;                  /* Shell state */
    ++  sqlite3 *db;                    /* Database containing the archive */
    ++};
    ++
    + /*
    +-** Open a new database file named "zNewDb".  Try to recover as much information
    +-** as possible out of the main database (which might be corrupt) and write it
    +-** into zNewDb.
    ++** Print a usage message for the .ar command to stderr and return SQLITE_ERROR.
    + */
    +-static void tryToClone(ShellState *p, const char *zNewDb){
    +-  int rc;
    +-  sqlite3 *newDb = 0;
    +-  if( access(zNewDb,0)==0 ){
    +-    fprintf(stderr, "File \"%s\" already exists.\n", zNewDb);
    +-    return;
    +-  }
    +-  rc = sqlite3_open(zNewDb, &newDb);
    +-  if( rc ){
    +-    fprintf(stderr, "Cannot create output database: %s\n",
    +-            sqlite3_errmsg(newDb));
    +-  }else{
    +-    sqlite3_exec(p->db, "PRAGMA writable_schema=ON;", 0, 0, 0);
    +-    sqlite3_exec(newDb, "BEGIN EXCLUSIVE;", 0, 0, 0);
    +-    tryToCloneSchema(p, newDb, "type='table'", tryToCloneData);
    +-    tryToCloneSchema(p, newDb, "type!='table'", 0);
    +-    sqlite3_exec(newDb, "COMMIT;", 0, 0, 0);
    +-    sqlite3_exec(p->db, "PRAGMA writable_schema=OFF;", 0, 0, 0);
    ++static int arUsage(FILE *f){
    ++  raw_printf(f,
    ++"\n"
    ++"Usage: .ar [OPTION...] [FILE...]\n"
    ++"The .ar command manages sqlar archives.\n"
    ++"\n"
    ++"Examples:\n"
    ++"  .ar -cf archive.sar foo bar    # Create archive.sar from files foo and bar\n"
    ++"  .ar -tf archive.sar            # List members of archive.sar\n"
    ++"  .ar -xvf archive.sar           # Verbosely extract files from archive.sar\n"
    ++"\n"
    ++"Each command line must feature exactly one command option:\n"
    ++"  -c, --create               Create a new archive\n"
    ++"  -u, --update               Update or add files to an existing archive\n"
    ++"  -t, --list                 List contents of archive\n"
    ++"  -x, --extract              Extract files from archive\n"
    ++"\n"
    ++"And zero or more optional options:\n"
    ++"  -v, --verbose              Print each filename as it is processed\n"
    ++"  -f FILE, --file FILE       Operate on archive FILE (default is current db)\n"
    ++"  -a FILE, --append FILE     Operate on FILE opened using the apndvfs VFS\n"
    ++"  -C DIR, --directory DIR    Change to directory DIR to read/extract files\n"
    ++"  -n, --dryrun               Show the SQL that would have occurred\n"
    ++"\n"
    ++"See also: http://sqlite.org/cli.html#sqlar_archive_support\n"
    ++"\n"
    ++);
    ++  return SQLITE_ERROR;
    ++}
    ++
    ++/*
    ++** Print an error message for the .ar command to stderr and return 
    ++** SQLITE_ERROR.
    ++*/
    ++static int arErrorMsg(const char *zFmt, ...){
    ++  va_list ap;
    ++  char *z;
    ++  va_start(ap, zFmt);
    ++  z = sqlite3_vmprintf(zFmt, ap);
    ++  va_end(ap);
    ++  raw_printf(stderr, "Error: %s (try \".ar --help\")\n", z);
    ++  sqlite3_free(z);
    ++  return SQLITE_ERROR;
    ++}
    ++
    ++/*
    ++** Values for ArCommand.eCmd.
    ++*/
    ++#define AR_CMD_CREATE       1
    ++#define AR_CMD_EXTRACT      2
    ++#define AR_CMD_LIST         3
    ++#define AR_CMD_UPDATE       4
    ++#define AR_CMD_HELP         5
    ++
    ++/*
    ++** Other (non-command) switches.
    ++*/
    ++#define AR_SWITCH_VERBOSE     6
    ++#define AR_SWITCH_FILE        7
    ++#define AR_SWITCH_DIRECTORY   8
    ++#define AR_SWITCH_APPEND      9
    ++#define AR_SWITCH_DRYRUN     10
    ++
    ++static int arProcessSwitch(ArCommand *pAr, int eSwitch, const char *zArg){
    ++  switch( eSwitch ){
    ++    case AR_CMD_CREATE:
    ++    case AR_CMD_EXTRACT:
    ++    case AR_CMD_LIST:
    ++    case AR_CMD_UPDATE:
    ++    case AR_CMD_HELP:
    ++      if( pAr->eCmd ){
    ++        return arErrorMsg("multiple command options");
    ++      }
    ++      pAr->eCmd = eSwitch;
    ++      break;
    ++
    ++    case AR_SWITCH_DRYRUN:
    ++      pAr->bDryRun = 1;
    ++      break;
    ++    case AR_SWITCH_VERBOSE:
    ++      pAr->bVerbose = 1;
    ++      break;
    ++    case AR_SWITCH_APPEND:
    ++      pAr->bAppend = 1;
    ++      /* Fall thru into --file */
    ++    case AR_SWITCH_FILE:
    ++      pAr->zFile = zArg;
    ++      break;
    ++    case AR_SWITCH_DIRECTORY:
    ++      pAr->zDir = zArg;
    ++      break;
    +   }
    +-  sqlite3_close(newDb);
    ++
    ++  return SQLITE_OK;
    + }
    + 
    + /*
    +-** Change the output file back to stdout
    ++** Parse the command line for an ".ar" command. The results are written into
    ++** structure (*pAr). SQLITE_OK is returned if the command line is parsed
    ++** successfully, otherwise an error message is written to stderr and 
    ++** SQLITE_ERROR returned.
    + */
    +-static void output_reset(ShellState *p){
    +-  if( p->outfile[0]=='|' ){
    +-#ifndef SQLITE_OMIT_POPEN
    +-    pclose(p->out);
    +-#endif
    ++static int arParseCommand(
    ++  char **azArg,                   /* Array of arguments passed to dot command */
    ++  int nArg,                       /* Number of entries in azArg[] */
    ++  ArCommand *pAr                  /* Populate this object */
    ++){
    ++  struct ArSwitch {
    ++    const char *zLong;
    ++    char cShort;
    ++    u8 eSwitch;
    ++    u8 bArg;
    ++  } aSwitch[] = {
    ++    { "create",    'c', AR_CMD_CREATE,       0 },
    ++    { "extract",   'x', AR_CMD_EXTRACT,      0 },
    ++    { "list",      't', AR_CMD_LIST,         0 },
    ++    { "update",    'u', AR_CMD_UPDATE,       0 },
    ++    { "help",      'h', AR_CMD_HELP,         0 },
    ++    { "verbose",   'v', AR_SWITCH_VERBOSE,   0 },
    ++    { "file",      'f', AR_SWITCH_FILE,      1 },
    ++    { "append",    'a', AR_SWITCH_APPEND,    1 },
    ++    { "directory", 'C', AR_SWITCH_DIRECTORY, 1 },
    ++    { "dryrun",    'n', AR_SWITCH_DRYRUN,    0 },
    ++  };
    ++  int nSwitch = sizeof(aSwitch) / sizeof(struct ArSwitch);
    ++  struct ArSwitch *pEnd = &aSwitch[nSwitch];
    ++
    ++  if( nArg<=1 ){
    ++    return arUsage(stderr);
    +   }else{
    +-    output_file_close(p->out);
    ++    char *z = azArg[1];
    ++    memset(pAr, 0, sizeof(ArCommand));
    ++
    ++    if( z[0]!='-' ){
    ++      /* Traditional style [tar] invocation */
    ++      int i;
    ++      int iArg = 2;
    ++      for(i=0; z[i]; i++){
    ++        const char *zArg = 0;
    ++        struct ArSwitch *pOpt;
    ++        for(pOpt=&aSwitch[0]; pOpt<pEnd; pOpt++){
    ++          if( z[i]==pOpt->cShort ) break;
    ++        }
    ++        if( pOpt==pEnd ){
    ++          return arErrorMsg("unrecognized option: %c", z[i]);
    ++        }
    ++        if( pOpt->bArg ){
    ++          if( iArg>=nArg ){
    ++            return arErrorMsg("option requires an argument: %c",z[i]);
    ++          }
    ++          zArg = azArg[iArg++];
    ++        }
    ++        if( arProcessSwitch(pAr, pOpt->eSwitch, zArg) ) return SQLITE_ERROR;
    ++      }
    ++      pAr->nArg = nArg-iArg;
    ++      if( pAr->nArg>0 ){
    ++        pAr->azArg = &azArg[iArg];
    ++      }
    ++    }else{
    ++      /* Non-traditional invocation */
    ++      int iArg;
    ++      for(iArg=1; iArg<nArg; iArg++){
    ++        int n;
    ++        z = azArg[iArg];
    ++        if( z[0]!='-' ){
    ++          /* All remaining command line words are command arguments. */
    ++          pAr->azArg = &azArg[iArg];
    ++          pAr->nArg = nArg-iArg;
    ++          break;
    ++        }
    ++        n = strlen30(z);
    ++
    ++        if( z[1]!='-' ){
    ++          int i;
    ++          /* One or more short options */
    ++          for(i=1; i<n; i++){
    ++            const char *zArg = 0;
    ++            struct ArSwitch *pOpt;
    ++            for(pOpt=&aSwitch[0]; pOpt<pEnd; pOpt++){
    ++              if( z[i]==pOpt->cShort ) break;
    ++            }
    ++            if( pOpt==pEnd ){
    ++              return arErrorMsg("unrecognized option: %c\n", z[i]);
    ++            }
    ++            if( pOpt->bArg ){
    ++              if( i<(n-1) ){
    ++                zArg = &z[i+1];
    ++                i = n;
    ++              }else{
    ++                if( iArg>=(nArg-1) ){
    ++                  return arErrorMsg("option requires an argument: %c\n",z[i]);
    ++                }
    ++                zArg = azArg[++iArg];
    ++              }
    ++            }
    ++            if( arProcessSwitch(pAr, pOpt->eSwitch, zArg) ) return SQLITE_ERROR;
    ++          }
    ++        }else if( z[2]=='\0' ){
    ++          /* A -- option, indicating that all remaining command line words
    ++          ** are command arguments.  */
    ++          pAr->azArg = &azArg[iArg+1];
    ++          pAr->nArg = nArg-iArg-1;
    ++          break;
    ++        }else{
    ++          /* A long option */
    ++          const char *zArg = 0;             /* Argument for option, if any */
    ++          struct ArSwitch *pMatch = 0;      /* Matching option */
    ++          struct ArSwitch *pOpt;            /* Iterator */
    ++          for(pOpt=&aSwitch[0]; pOpt<pEnd; pOpt++){
    ++            const char *zLong = pOpt->zLong;
    ++            if( (n-2)<=strlen30(zLong) && 0==memcmp(&z[2], zLong, n-2) ){
    ++              if( pMatch ){
    ++                return arErrorMsg("ambiguous option: %s",z);
    ++              }else{
    ++                pMatch = pOpt;
    ++              }
    ++            }
    ++          }
    ++
    ++          if( pMatch==0 ){
    ++            return arErrorMsg("unrecognized option: %s", z);
    ++          }
    ++          if( pMatch->bArg ){
    ++            if( iArg>=(nArg-1) ){
    ++              return arErrorMsg("option requires an argument: %s", z);
    ++            }
    ++            zArg = azArg[++iArg];
    ++          }
    ++          if( arProcessSwitch(pAr, pMatch->eSwitch, zArg) ) return SQLITE_ERROR;
    ++        }
    ++      }
    ++    }
    +   }
    +-  p->outfile[0] = 0;
    +-  p->out = stdout;
    ++
    ++  return SQLITE_OK;
    + }
    + 
    + /*
    +-** Run an SQL command and return the single integer result.
    ++** This function assumes that all arguments within the ArCommand.azArg[]
    ++** array refer to archive members, as for the --extract or --list commands. 
    ++** It checks that each of them are present. If any specified file is not
    ++** present in the archive, an error is printed to stderr and an error
    ++** code returned. Otherwise, if all specified arguments are present in
    ++** the archive, SQLITE_OK is returned.
    ++**
    ++** This function strips any trailing '/' characters from each argument.
    ++** This is consistent with the way the [tar] command seems to work on
    ++** Linux.
    + */
    +-static int db_int(ShellState *p, const char *zSql){
    +-  sqlite3_stmt *pStmt;
    +-  int res = 0;
    +-  sqlite3_prepare_v2(p->db, zSql, -1, &pStmt, 0);
    +-  if( pStmt && sqlite3_step(pStmt)==SQLITE_ROW ){
    +-    res = sqlite3_column_int(pStmt,0);
    ++static int arCheckEntries(ArCommand *pAr){
    ++  int rc = SQLITE_OK;
    ++  if( pAr->nArg ){
    ++    int i, j;
    ++    sqlite3_stmt *pTest = 0;
    ++
    ++    shellPreparePrintf(pAr->db, &rc, &pTest,
    ++        "SELECT name FROM %s WHERE name=$name", 
    ++        pAr->zSrcTable
    ++    );
    ++    j = sqlite3_bind_parameter_index(pTest, "$name");
    ++    for(i=0; i<pAr->nArg && rc==SQLITE_OK; i++){
    ++      char *z = pAr->azArg[i];
    ++      int n = strlen30(z);
    ++      int bOk = 0;
    ++      while( n>0 && z[n-1]=='/' ) n--;
    ++      z[n] = '\0';
    ++      sqlite3_bind_text(pTest, j, z, -1, SQLITE_STATIC);
    ++      if( SQLITE_ROW==sqlite3_step(pTest) ){
    ++        bOk = 1;
    ++      }
    ++      shellReset(&rc, pTest);
    ++      if( rc==SQLITE_OK && bOk==0 ){
    ++        utf8_printf(stderr, "not found in archive: %s\n", z);
    ++        rc = SQLITE_ERROR;
    ++      }
    ++    }
    ++    shellFinalize(&rc, pTest);
    +   }
    +-  sqlite3_finalize(pStmt);
    +-  return res;
    ++  return rc;
    + }
    + 
    + /*
    +-** Convert a 2-byte or 4-byte big-endian integer into a native integer
    ++** Format a WHERE clause that can be used against the "sqlar" table to
    ++** identify all archive members that match the command arguments held
    ++** in (*pAr). Leave this WHERE clause in (*pzWhere) before returning.
    ++** The caller is responsible for eventually calling sqlite3_free() on
    ++** any non-NULL (*pzWhere) value.
    + */
    +-unsigned int get2byteInt(unsigned char *a){
    +-  return (a[0]<<8) + a[1];
    +-}
    +-unsigned int get4byteInt(unsigned char *a){
    +-  return (a[0]<<24) + (a[1]<<16) + (a[2]<<8) + a[3];
    ++static void arWhereClause(
    ++  int *pRc, 
    ++  ArCommand *pAr, 
    ++  char **pzWhere                  /* OUT: New WHERE clause */
    ++){
    ++  char *zWhere = 0;
    ++  if( *pRc==SQLITE_OK ){
    ++    if( pAr->nArg==0 ){
    ++      zWhere = sqlite3_mprintf("1");
    ++    }else{
    ++      int i;
    ++      const char *zSep = "";
    ++      for(i=0; i<pAr->nArg; i++){
    ++        const char *z = pAr->azArg[i];
    ++        zWhere = sqlite3_mprintf(
    ++          "%z%s name = '%q' OR substr(name,1,%d) = '%q/'", 
    ++          zWhere, zSep, z, strlen30(z)+1, z
    ++        );
    ++        if( zWhere==0 ){
    ++          *pRc = SQLITE_NOMEM;
    ++          break;
    ++        }
    ++        zSep = " OR ";
    ++      }
    ++    }
    ++  }
    ++  *pzWhere = zWhere;
    + }
    + 
    + /*
    +-** Implementation of the ".info" command.
    +-**
    +-** Return 1 on error, 2 to exit, and 0 otherwise.
    ++** Implementation of .ar "lisT" command. 
    + */
    +-static int shell_dbinfo_command(ShellState *p, int nArg, char **azArg){
    +-  static const struct { const char *zName; int ofst; } aField[] = {
    +-     { "file change counter:",  24  },
    +-     { "database page count:",  28  },
    +-     { "freelist page count:",  36  },
    +-     { "schema cookie:",        40  },
    +-     { "schema format:",        44  },
    +-     { "default cache size:",   48  },
    +-     { "autovacuum top root:",  52  },
    +-     { "incremental vacuum:",   64  },
    +-     { "text encoding:",        56  },
    +-     { "user version:",         60  },
    +-     { "application id:",       68  },
    +-     { "software version:",     96  },
    +-  };
    +-  static const struct { const char *zName; const char *zSql; } aQuery[] = {
    +-     { "number of tables:",
    +-       "SELECT count(*) FROM %s WHERE type='table'" },
    +-     { "number of indexes:",
    +-       "SELECT count(*) FROM %s WHERE type='index'" },
    +-     { "number of triggers:",
    +-       "SELECT count(*) FROM %s WHERE type='trigger'" },
    +-     { "number of views:",
    +-       "SELECT count(*) FROM %s WHERE type='view'" },
    +-     { "schema size:",
    +-       "SELECT total(length(sql)) FROM %s" },
    ++static int arListCommand(ArCommand *pAr){
    ++  const char *zSql = "SELECT %s FROM %s WHERE %s"; 
    ++  const char *azCols[] = {
    ++    "name",
    ++    "lsmode(mode), sz, datetime(mtime, 'unixepoch'), name"
    +   };
    +-  sqlite3_file *pFile;
    +-  int i;
    +-  char *zSchemaTab;
    +-  char *zDb = nArg>=2 ? azArg[1] : "main";
    +-  unsigned char aHdr[100];
    +-  open_db(p, 0);
    +-  if( p->db==0 ) return 1;
    +-  sqlite3_file_control(p->db, zDb, SQLITE_FCNTL_FILE_POINTER, &pFile);
    +-  if( pFile==0 || pFile->pMethods==0 || pFile->pMethods->xRead==0 ){
    +-    return 1;
    ++
    ++  char *zWhere = 0;
    ++  sqlite3_stmt *pSql = 0;
    ++  int rc;
    ++
    ++  rc = arCheckEntries(pAr);
    ++  arWhereClause(&rc, pAr, &zWhere);
    ++
    ++  shellPreparePrintf(pAr->db, &rc, &pSql, zSql, azCols[pAr->bVerbose],
    ++                     pAr->zSrcTable, zWhere);
    ++  if( pAr->bDryRun ){
    ++    utf8_printf(pAr->p->out, "%s\n", sqlite3_sql(pSql));
    ++  }else{
    ++    while( rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pSql) ){
    ++      if( pAr->bVerbose ){
    ++        utf8_printf(pAr->p->out, "%s % 10d  %s  %s\n",
    ++            sqlite3_column_text(pSql, 0),
    ++            sqlite3_column_int(pSql, 1), 
    ++            sqlite3_column_text(pSql, 2),
    ++            sqlite3_column_text(pSql, 3)
    ++        );
    ++      }else{
    ++        utf8_printf(pAr->p->out, "%s\n", sqlite3_column_text(pSql, 0));
    ++      }
    ++    }
    +   }
    +-  i = pFile->pMethods->xRead(pFile, aHdr, 100, 0);
    +-  if( i!=SQLITE_OK ){
    +-    fprintf(stderr, "unable to read database header\n");
    +-    return 1;
    ++  shellFinalize(&rc, pSql);
    ++  return rc;
    ++}
    ++
    ++
    ++/*
    ++** Implementation of .ar "eXtract" command. 
    ++*/
    ++static int arExtractCommand(ArCommand *pAr){
    ++  const char *zSql1 = 
    ++    "SELECT "
    ++    " ($dir || name),"
    ++    " writefile(($dir || name), %s, mode, mtime) "
    ++    "FROM %s WHERE (%s) AND (data IS NULL OR $dirOnly = 0)";
    ++
    ++  const char *azExtraArg[] = { 
    ++    "sqlar_uncompress(data, sz)",
    ++    "data"
    ++  };
    ++
    ++  sqlite3_stmt *pSql = 0;
    ++  int rc = SQLITE_OK;
    ++  char *zDir = 0;
    ++  char *zWhere = 0;
    ++  int i, j;
    ++
    ++  /* If arguments are specified, check that they actually exist within
    ++  ** the archive before proceeding. And formulate a WHERE clause to
    ++  ** match them.  */
    ++  rc = arCheckEntries(pAr);
    ++  arWhereClause(&rc, pAr, &zWhere);
    ++
    ++  if( rc==SQLITE_OK ){
    ++    if( pAr->zDir ){
    ++      zDir = sqlite3_mprintf("%s/", pAr->zDir);
    ++    }else{
    ++      zDir = sqlite3_mprintf("");
    ++    }
    ++    if( zDir==0 ) rc = SQLITE_NOMEM;
    +   }
    +-  i = get2byteInt(aHdr+16);
    +-  if( i==1 ) i = 65536;
    +-  fprintf(p->out, "%-20s %d\n", "database page size:", i);
    +-  fprintf(p->out, "%-20s %d\n", "write format:", aHdr[18]);
    +-  fprintf(p->out, "%-20s %d\n", "read format:", aHdr[19]);
    +-  fprintf(p->out, "%-20s %d\n", "reserved bytes:", aHdr[20]);
    +-  for(i=0; i<ArraySize(aField); i++){
    +-    int ofst = aField[i].ofst;
    +-    unsigned int val = get4byteInt(aHdr + ofst);
    +-    fprintf(p->out, "%-20s %u", aField[i].zName, val);
    +-    switch( ofst ){
    +-      case 56: {
    +-        if( val==1 ) fprintf(p->out, " (utf8)"); 
    +-        if( val==2 ) fprintf(p->out, " (utf16le)"); 
    +-        if( val==3 ) fprintf(p->out, " (utf16be)"); 
    ++
    ++  shellPreparePrintf(pAr->db, &rc, &pSql, zSql1, 
    ++      azExtraArg[pAr->bZip], pAr->zSrcTable, zWhere
    ++  );
    ++
    ++  if( rc==SQLITE_OK ){
    ++    j = sqlite3_bind_parameter_index(pSql, "$dir");
    ++    sqlite3_bind_text(pSql, j, zDir, -1, SQLITE_STATIC);
    ++
    ++    /* Run the SELECT statement twice. The first time, writefile() is called
    ++    ** for all archive members that should be extracted. The second time,
    ++    ** only for the directories. This is because the timestamps for
    ++    ** extracted directories must be reset after they are populated (as
    ++    ** populating them changes the timestamp).  */
    ++    for(i=0; i<2; i++){
    ++      j = sqlite3_bind_parameter_index(pSql, "$dirOnly");
    ++      sqlite3_bind_int(pSql, j, i);
    ++      if( pAr->bDryRun ){
    ++        utf8_printf(pAr->p->out, "%s\n", sqlite3_sql(pSql));
    ++      }else{
    ++        while( rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pSql) ){
    ++          if( i==0 && pAr->bVerbose ){
    ++            utf8_printf(pAr->p->out, "%s\n", sqlite3_column_text(pSql, 0));
    ++          }
    ++        }
    +       }
    ++      shellReset(&rc, pSql);
    +     }
    +-    fprintf(p->out, "\n");
    ++    shellFinalize(&rc, pSql);
    +   }
    +-  if( zDb==0 ){
    +-    zSchemaTab = sqlite3_mprintf("main.sqlite_master");
    +-  }else if( strcmp(zDb,"temp")==0 ){
    +-    zSchemaTab = sqlite3_mprintf("%s", "sqlite_temp_master");
    ++
    ++  sqlite3_free(zDir);
    ++  sqlite3_free(zWhere);
    ++  return rc;
    ++}
    ++
    ++/*
    ++** Run the SQL statement in zSql.  Or if doing a --dryrun, merely print it out.
    ++*/
    ++static int arExecSql(ArCommand *pAr, const char *zSql){
    ++  int rc;
    ++  if( pAr->bDryRun ){
    ++    utf8_printf(pAr->p->out, "%s\n", zSql);
    ++    rc = SQLITE_OK;
    +   }else{
    +-    zSchemaTab = sqlite3_mprintf("\"%w\".sqlite_master", zDb);
    +-  }
    +-  for(i=0; i<ArraySize(aQuery); i++){
    +-    char *zSql = sqlite3_mprintf(aQuery[i].zSql, zSchemaTab);
    +-    int val = db_int(p, zSql);
    +-    sqlite3_free(zSql);
    +-    fprintf(p->out, "%-20s %d\n", aQuery[i].zName, val);
    ++    char *zErr = 0;
    ++    rc = sqlite3_exec(pAr->db, zSql, 0, 0, &zErr);
    ++    if( zErr ){
    ++      utf8_printf(stdout, "ERROR: %s\n", zErr);
    ++      sqlite3_free(zErr);
    ++    }
    +   }
    +-  sqlite3_free(zSchemaTab);
    +-  return 0;
    ++  return rc;
    + }
    + 
    ++
    + /*
    +-** Print the current sqlite3_errmsg() value to stderr and return 1.
    ++** Implementation of .ar "create" and "update" commands.
    ++**
    ++** Create the "sqlar" table in the database if it does not already exist.
    ++** Then add each file in the azFile[] array to the archive. Directories
    ++** are added recursively. If argument bVerbose is non-zero, a message is
    ++** printed on stdout for each file archived.
    ++**
    ++** The create command is the same as update, except that it drops
    ++** any existing "sqlar" table before beginning.
    + */
    +-static int shellDatabaseError(sqlite3 *db){
    +-  const char *zErr = sqlite3_errmsg(db);
    +-  fprintf(stderr, "Error: %s\n", zErr);
    +-  return 1;
    ++static int arCreateOrUpdateCommand(
    ++  ArCommand *pAr,                 /* Command arguments and options */
    ++  int bUpdate                     /* true for a --create.  false for --update */
    ++){
    ++  const char *zCreate = 
    ++      "CREATE TABLE IF NOT EXISTS sqlar(\n"
    ++      "  name TEXT PRIMARY KEY,  -- name of the file\n"
    ++      "  mode INT,               -- access permissions\n"
    ++      "  mtime INT,              -- last modification time\n"
    ++      "  sz INT,                 -- original file size\n"
    ++      "  data BLOB               -- compressed content\n"
    ++      ")";
    ++  const char *zDrop = "DROP TABLE IF EXISTS sqlar";
    ++  const char *zInsertFmt = 
    ++     "REPLACE INTO sqlar(name,mode,mtime,sz,data)\n"
    ++     "  SELECT\n"
    ++     "    %s,\n"
    ++     "    mode,\n"
    ++     "    mtime,\n"
    ++     "    CASE substr(lsmode(mode),1,1)\n"
    ++     "      WHEN '-' THEN length(data)\n"
    ++     "      WHEN 'd' THEN 0\n"
    ++     "      ELSE -1 END,\n"
    ++     "    CASE WHEN lsmode(mode) LIKE 'd%%' THEN NULL else data END\n"
    ++     "  FROM fsdir(%Q,%Q)\n"
    ++     "  WHERE lsmode(mode) NOT LIKE '?%%';";
    ++  int i;                          /* For iterating through azFile[] */
    ++  int rc;                         /* Return code */
    ++
    ++  rc = arExecSql(pAr, "SAVEPOINT ar;");
    ++  if( rc!=SQLITE_OK ) return rc;
    ++  if( bUpdate==0 ){
    ++    rc = arExecSql(pAr, zDrop);
    ++    if( rc!=SQLITE_OK ) return rc;
    ++  }
    ++  rc = arExecSql(pAr, zCreate);
    ++  for(i=0; i<pAr->nArg && rc==SQLITE_OK; i++){
    ++    char *zSql = sqlite3_mprintf(zInsertFmt,
    ++        pAr->bVerbose ? "shell_putsnl(name)" : "name",
    ++        pAr->azArg[i], pAr->zDir);
    ++    rc = arExecSql(pAr, zSql);
    ++    sqlite3_free(zSql);
    ++  }
    ++  if( rc!=SQLITE_OK ){
    ++    arExecSql(pAr, "ROLLBACK TO ar; RELEASE ar;");
    ++  }else{
    ++    rc = arExecSql(pAr, "RELEASE ar;");
    ++  }
    ++  return rc;
    + }
    + 
    + /*
    +-** Print an out-of-memory message to stderr and return 1.
    ++** Implementation of ".ar" dot command.
    + */
    +-static int shellNomemError(void){
    +-  fprintf(stderr, "Error: out of memory\n");
    +-  return 1;
    ++static int arDotCommand(
    ++  ShellState *pState,             /* Current shell tool state */
    ++  char **azArg,                   /* Array of arguments passed to dot command */
    ++  int nArg                        /* Number of entries in azArg[] */
    ++){
    ++  ArCommand cmd;
    ++  int rc;
    ++  memset(&cmd, 0, sizeof(cmd));
    ++  rc = arParseCommand(azArg, nArg, &cmd);
    ++  if( rc==SQLITE_OK ){
    ++    int eDbType = SHELL_OPEN_UNSPEC;
    ++    cmd.p = pState;
    ++    cmd.db = pState->db;
    ++    if( cmd.zFile ){
    ++      eDbType = deduceDatabaseType(cmd.zFile);
    ++    }else{
    ++      eDbType = pState->openMode;
    ++    }
    ++    if( eDbType==SHELL_OPEN_ZIPFILE ){
    ++      if( cmd.zFile==0 ){
    ++        cmd.zSrcTable = sqlite3_mprintf("zip");
    ++      }else{
    ++        cmd.zSrcTable = sqlite3_mprintf("zipfile(%Q)", cmd.zFile);
    ++      }
    ++      if( cmd.eCmd==AR_CMD_CREATE || cmd.eCmd==AR_CMD_UPDATE ){
    ++        utf8_printf(stderr, "zip archives are read-only\n");
    ++        rc = SQLITE_ERROR;
    ++        goto end_ar_command;
    ++      }
    ++      cmd.bZip = 1;
    ++    }else if( cmd.zFile ){
    ++      int flags;
    ++      if( cmd.bAppend ) eDbType = SHELL_OPEN_APPENDVFS;
    ++      if( cmd.eCmd==AR_CMD_CREATE || cmd.eCmd==AR_CMD_UPDATE ){
    ++        flags = SQLITE_OPEN_READWRITE|SQLITE_OPEN_CREATE;
    ++      }else{
    ++        flags = SQLITE_OPEN_READONLY;
    ++      }
    ++      cmd.db = 0;
    ++      if( cmd.bDryRun ){
    ++        utf8_printf(pState->out, "-- open database '%s'%s\n", cmd.zFile,
    ++             eDbType==SHELL_OPEN_APPENDVFS ? " using 'apndvfs'" : "");
    ++      }
    ++      rc = sqlite3_open_v2(cmd.zFile, &cmd.db, flags, 
    ++             eDbType==SHELL_OPEN_APPENDVFS ? "apndvfs" : 0);
    ++      if( rc!=SQLITE_OK ){
    ++        utf8_printf(stderr, "cannot open file: %s (%s)\n", 
    ++            cmd.zFile, sqlite3_errmsg(cmd.db)
    ++        );
    ++        goto end_ar_command;
    ++      }
    ++      sqlite3_fileio_init(cmd.db, 0, 0);
    ++#ifdef SQLITE_HAVE_ZLIB
    ++      sqlite3_sqlar_init(cmd.db, 0, 0);
    ++#endif
    ++      sqlite3_create_function(cmd.db, "shell_putsnl", 1, SQLITE_UTF8, cmd.p,
    ++                              shellPutsFunc, 0, 0);
    ++
    ++    }
    ++    if( cmd.zSrcTable==0 ){
    ++      if( cmd.eCmd!=AR_CMD_CREATE
    ++       && sqlite3_table_column_metadata(cmd.db,0,"sqlar","name",0,0,0,0,0)
    ++      ){
    ++        utf8_printf(stderr, "database does not contain an 'sqlar' table\n");
    ++        rc = SQLITE_ERROR;
    ++        goto end_ar_command;
    ++      }
    ++      cmd.zSrcTable = sqlite3_mprintf("sqlar");
    ++    }
    ++
    ++    switch( cmd.eCmd ){
    ++      case AR_CMD_CREATE:
    ++        rc = arCreateOrUpdateCommand(&cmd, 0);
    ++        break;
    ++
    ++      case AR_CMD_EXTRACT:
    ++        rc = arExtractCommand(&cmd);
    ++        break;
    ++
    ++      case AR_CMD_LIST:
    ++        rc = arListCommand(&cmd);
    ++        break;
    ++
    ++      case AR_CMD_HELP:
    ++        arUsage(pState->out);
    ++        break;
    ++
    ++      default:
    ++        assert( cmd.eCmd==AR_CMD_UPDATE );
    ++        rc = arCreateOrUpdateCommand(&cmd, 1);
    ++        break;
    ++    }
    ++  }
    ++end_ar_command:
    ++  if( cmd.db!=pState->db ){
    ++    sqlite3_close(cmd.db);
    ++  }
    ++  sqlite3_free(cmd.zSrcTable);
    ++
    ++  return rc;
    + }
    ++/* End of the ".archive" or ".ar" command logic
    ++**********************************************************************************/
    ++#endif /* !defined(SQLITE_OMIT_VIRTUALTABLE) && defined(SQLITE_HAVE_ZLIB) */
    ++
    + 
    + /*
    + ** If an input line begins with "." then invoke this routine to
    +@@ -2664,6 +12314,12 @@ static int do_meta_command(char *zLine, ShellState *p){
    +   int rc = 0;
    +   char *azArg[50];
    + 
    ++#ifndef SQLITE_OMIT_VIRTUALTABLE
    ++  if( p->expert.pExpert ){
    ++    expertFinish(p, 1, 0);
    ++  }
    ++#endif
    ++
    +   /* Parse the input line into tokens.
    +   */
    +   while( zLine[h] && nArg<ArraySize(azArg) ){
    +@@ -2672,9 +12328,9 @@ static int do_meta_command(char *zLine, ShellState *p){
    +     if( zLine[h]=='\'' || zLine[h]=='"' ){
    +       int delim = zLine[h++];
    +       azArg[nArg++] = &zLine[h];
    +-      while( zLine[h] && zLine[h]!=delim ){ 
    ++      while( zLine[h] && zLine[h]!=delim ){
    +         if( zLine[h]=='\\' && delim=='"' && zLine[h+1]!=0 ) h++;
    +-        h++; 
    ++        h++;
    +       }
    +       if( zLine[h]==delim ){
    +         zLine[h++] = 0;
    +@@ -2693,6 +12349,31 @@ static int do_meta_command(char *zLine, ShellState *p){
    +   if( nArg==0 ) return 0; /* no tokens, no error */
    +   n = strlen30(azArg[0]);
    +   c = azArg[0][0];
    ++  clearTempFile(p);
    ++
    ++#ifndef SQLITE_OMIT_AUTHORIZATION
    ++  if( c=='a' && strncmp(azArg[0], "auth", n)==0 ){
    ++    if( nArg!=2 ){
    ++      raw_printf(stderr, "Usage: .auth ON|OFF\n");
    ++      rc = 1;
    ++      goto meta_command_exit;
    ++    }
    ++    open_db(p, 0);
    ++    if( booleanValue(azArg[1]) ){
    ++      sqlite3_set_authorizer(p->db, shellAuth, p);
    ++    }else{
    ++      sqlite3_set_authorizer(p->db, 0, 0);
    ++    }
    ++  }else
    ++#endif
    ++
    ++#if !defined(SQLITE_OMIT_VIRTUALTABLE) && defined(SQLITE_HAVE_ZLIB)
    ++  if( c=='a' && strncmp(azArg[0], "archive", n)==0 ){
    ++    open_db(p, 0);
    ++    rc = arDotCommand(p, azArg, nArg);
    ++  }else
    ++#endif
    ++
    +   if( (c=='b' && n>=3 && strncmp(azArg[0], "backup", n)==0)
    +    || (c=='s' && n>=3 && strncmp(azArg[0], "save", n)==0)
    +   ){
    +@@ -2707,7 +12388,7 @@ static int do_meta_command(char *zLine, ShellState *p){
    +         while( z[0]=='-' ) z++;
    +         /* No options to process at this time */
    +         {
    +-          fprintf(stderr, "unknown option: %s\n", azArg[j]);
    ++          utf8_printf(stderr, "unknown option: %s\n", azArg[j]);
    +           return 1;
    +         }
    +       }else if( zDestFile==0 ){
    +@@ -2716,25 +12397,25 @@ static int do_meta_command(char *zLine, ShellState *p){
    +         zDb = zDestFile;
    +         zDestFile = azArg[j];
    +       }else{
    +-        fprintf(stderr, "too many arguments to .backup\n");
    ++        raw_printf(stderr, "too many arguments to .backup\n");
    +         return 1;
    +       }
    +     }
    +     if( zDestFile==0 ){
    +-      fprintf(stderr, "missing FILENAME argument on .backup\n");
    ++      raw_printf(stderr, "missing FILENAME argument on .backup\n");
    +       return 1;
    +     }
    +     if( zDb==0 ) zDb = "main";
    +     rc = sqlite3_open(zDestFile, &pDest);
    +     if( rc!=SQLITE_OK ){
    +-      fprintf(stderr, "Error: cannot open \"%s\"\n", zDestFile);
    ++      utf8_printf(stderr, "Error: cannot open \"%s\"\n", zDestFile);
    +       sqlite3_close(pDest);
    +       return 1;
    +     }
    +     open_db(p, 0);
    +     pBackup = sqlite3_backup_init(pDest, "main", p->db, zDb);
    +     if( pBackup==0 ){
    +-      fprintf(stderr, "Error: %s\n", sqlite3_errmsg(pDest));
    ++      utf8_printf(stderr, "Error: %s\n", sqlite3_errmsg(pDest));
    +       sqlite3_close(pDest);
    +       return 1;
    +     }
    +@@ -2743,7 +12424,7 @@ static int do_meta_command(char *zLine, ShellState *p){
    +     if( rc==SQLITE_DONE ){
    +       rc = 0;
    +     }else{
    +-      fprintf(stderr, "Error: %s\n", sqlite3_errmsg(pDest));
    ++      utf8_printf(stderr, "Error: %s\n", sqlite3_errmsg(pDest));
    +       rc = 1;
    +     }
    +     sqlite3_close(pDest);
    +@@ -2753,7 +12434,7 @@ static int do_meta_command(char *zLine, ShellState *p){
    +     if( nArg==2 ){
    +       bail_on_error = booleanValue(azArg[1]);
    +     }else{
    +-      fprintf(stderr, "Usage: .bail on|off\n");
    ++      raw_printf(stderr, "Usage: .bail on|off\n");
    +       rc = 1;
    +     }
    +   }else
    +@@ -2761,12 +12442,31 @@ static int do_meta_command(char *zLine, ShellState *p){
    +   if( c=='b' && n>=3 && strncmp(azArg[0], "binary", n)==0 ){
    +     if( nArg==2 ){
    +       if( booleanValue(azArg[1]) ){
    +-        setBinaryMode(p->out);
    ++        setBinaryMode(p->out, 1);
    +       }else{
    +-        setTextMode(p->out);
    ++        setTextMode(p->out, 1);
    ++      }
    ++    }else{
    ++      raw_printf(stderr, "Usage: .binary on|off\n");
    ++      rc = 1;
    ++    }
    ++  }else
    ++
    ++  if( c=='c' && strcmp(azArg[0],"cd")==0 ){
    ++    if( nArg==2 ){
    ++#if defined(_WIN32) || defined(WIN32)
    ++      wchar_t *z = sqlite3_win32_utf8_to_unicode(azArg[1]);
    ++      rc = !SetCurrentDirectoryW(z);
    ++      sqlite3_free(z);
    ++#else
    ++      rc = chdir(azArg[1]);
    ++#endif
    ++      if( rc ){
    ++        utf8_printf(stderr, "Cannot change to directory \"%s\"\n", azArg[1]);
    ++        rc = 1;
    +       }
    +     }else{
    +-      fprintf(stderr, "Usage: .binary on|off\n");
    ++      raw_printf(stderr, "Usage: .cd DIRECTORY\n");
    +       rc = 1;
    +     }
    +   }else
    +@@ -2778,11 +12478,45 @@ static int do_meta_command(char *zLine, ShellState *p){
    +     test_breakpoint();
    +   }else
    + 
    ++  if( c=='c' && n>=3 && strncmp(azArg[0], "changes", n)==0 ){
    ++    if( nArg==2 ){
    ++      setOrClearFlag(p, SHFLG_CountChanges, azArg[1]);
    ++    }else{
    ++      raw_printf(stderr, "Usage: .changes on|off\n");
    ++      rc = 1;
    ++    }
    ++  }else
    ++
    ++  /* Cancel output redirection, if it is currently set (by .testcase)
    ++  ** Then read the content of the testcase-out.txt file and compare against
    ++  ** azArg[1].  If there are differences, report an error and exit.
    ++  */
    ++  if( c=='c' && n>=3 && strncmp(azArg[0], "check", n)==0 ){
    ++    char *zRes = 0;
    ++    output_reset(p);
    ++    if( nArg!=2 ){
    ++      raw_printf(stderr, "Usage: .check GLOB-PATTERN\n");
    ++      rc = 2;
    ++    }else if( (zRes = readFile("testcase-out.txt", 0))==0 ){
    ++      raw_printf(stderr, "Error: cannot read 'testcase-out.txt'\n");
    ++      rc = 2;
    ++    }else if( testcase_glob(azArg[1],zRes)==0 ){
    ++      utf8_printf(stderr,
    ++                 "testcase-%s FAILED\n Expected: [%s]\n      Got: [%s]\n",
    ++                 p->zTestcase, azArg[1], zRes);
    ++      rc = 1;
    ++    }else{
    ++      utf8_printf(stdout, "testcase-%s ok\n", p->zTestcase);
    ++      p->nCheck++;
    ++    }
    ++    sqlite3_free(zRes);
    ++  }else
    ++
    +   if( c=='c' && strncmp(azArg[0], "clone", n)==0 ){
    +     if( nArg==2 ){
    +       tryToClone(p, azArg[1]);
    +     }else{
    +-      fprintf(stderr, "Usage: .clone FILENAME\n");
    ++      raw_printf(stderr, "Usage: .clone FILENAME\n");
    +       rc = 1;
    +     }
    +   }else
    +@@ -2792,15 +12526,14 @@ static int do_meta_command(char *zLine, ShellState *p){
    +     char *zErrMsg = 0;
    +     open_db(p, 0);
    +     memcpy(&data, p, sizeof(data));
    +-    data.showHeader = 1;
    +-    data.mode = MODE_Column;
    +-    data.colWidth[0] = 3;
    +-    data.colWidth[1] = 15;
    +-    data.colWidth[2] = 58;
    ++    data.showHeader = 0;
    ++    data.cMode = data.mode = MODE_List;
    ++    sqlite3_snprintf(sizeof(data.colSeparator),data.colSeparator,": ");
    +     data.cnt = 0;
    +-    sqlite3_exec(p->db, "PRAGMA database_list; ", callback, &data, &zErrMsg);
    ++    sqlite3_exec(p->db, "SELECT name, file FROM pragma_database_list",
    ++                 callback, &data, &zErrMsg);
    +     if( zErrMsg ){
    +-      fprintf(stderr,"Error: %s\n", zErrMsg);
    ++      utf8_printf(stderr,"Error: %s\n", zErrMsg);
    +       sqlite3_free(zErrMsg);
    +       rc = 1;
    +     }
    +@@ -2811,26 +12544,60 @@ static int do_meta_command(char *zLine, ShellState *p){
    +   }else
    + 
    +   if( c=='d' && strncmp(azArg[0], "dump", n)==0 ){
    ++    const char *zLike = 0;
    ++    int i;
    ++    int savedShowHeader = p->showHeader;
    ++    ShellClearFlag(p, SHFLG_PreserveRowid|SHFLG_Newlines);
    ++    for(i=1; i<nArg; i++){
    ++      if( azArg[i][0]=='-' ){
    ++        const char *z = azArg[i]+1;
    ++        if( z[0]=='-' ) z++;
    ++        if( strcmp(z,"preserve-rowids")==0 ){
    ++#ifdef SQLITE_OMIT_VIRTUALTABLE
    ++          raw_printf(stderr, "The --preserve-rowids option is not compatible"
    ++                             " with SQLITE_OMIT_VIRTUALTABLE\n");
    ++          rc = 1;
    ++          goto meta_command_exit;
    ++#else
    ++          ShellSetFlag(p, SHFLG_PreserveRowid);
    ++#endif
    ++        }else
    ++        if( strcmp(z,"newlines")==0 ){
    ++          ShellSetFlag(p, SHFLG_Newlines);
    ++        }else
    ++        {
    ++          raw_printf(stderr, "Unknown option \"%s\" on \".dump\"\n", azArg[i]);
    ++          rc = 1;
    ++          goto meta_command_exit;
    ++        }
    ++      }else if( zLike ){
    ++        raw_printf(stderr, "Usage: .dump ?--preserve-rowids? "
    ++                           "?--newlines? ?LIKE-PATTERN?\n");
    ++        rc = 1;
    ++        goto meta_command_exit;
    ++      }else{
    ++        zLike = azArg[i];
    ++      }
    ++    }
    +     open_db(p, 0);
    +     /* When playing back a "dump", the content might appear in an order
    +     ** which causes immediate foreign key constraints to be violated.
    +     ** So disable foreign-key constraint enforcement to prevent problems. */
    +-    if( nArg!=1 && nArg!=2 ){
    +-      fprintf(stderr, "Usage: .dump ?LIKE-PATTERN?\n");
    +-      rc = 1;
    +-      goto meta_command_exit;
    +-    }
    +-    fprintf(p->out, "PRAGMA foreign_keys=OFF;\n");
    +-    fprintf(p->out, "BEGIN TRANSACTION;\n");
    ++    raw_printf(p->out, "PRAGMA foreign_keys=OFF;\n");
    ++    raw_printf(p->out, "BEGIN TRANSACTION;\n");
    +     p->writableSchema = 0;
    ++    p->showHeader = 0;
    ++    /* Set writable_schema=ON since doing so forces SQLite to initialize
    ++    ** as much of the schema as it can even if the sqlite_master table is
    ++    ** corrupt. */
    +     sqlite3_exec(p->db, "SAVEPOINT dump; PRAGMA writable_schema=ON", 0, 0, 0);
    +     p->nErr = 0;
    +-    if( nArg==1 ){
    +-      run_schema_dump_query(p, 
    ++    if( zLike==0 ){
    ++      run_schema_dump_query(p,
    +         "SELECT name, type, sql FROM sqlite_master "
    +         "WHERE sql NOT NULL AND type=='table' AND name!='sqlite_sequence'"
    +       );
    +-      run_schema_dump_query(p, 
    ++      run_schema_dump_query(p,
    +         "SELECT name, type, sql FROM sqlite_master "
    +         "WHERE name=='sqlite_sequence'"
    +       );
    +@@ -2839,47 +12606,53 @@ static int do_meta_command(char *zLine, ShellState *p){
    +         "WHERE sql NOT NULL AND type IN ('index','trigger','view')", 0
    +       );
    +     }else{
    +-      int i;
    +-      for(i=1; i<nArg; i++){
    +-        zShellStatic = azArg[i];
    +-        run_schema_dump_query(p,
    +-          "SELECT name, type, sql FROM sqlite_master "
    +-          "WHERE tbl_name LIKE shellstatic() AND type=='table'"
    +-          "  AND sql NOT NULL");
    +-        run_table_dump_query(p,
    +-          "SELECT sql FROM sqlite_master "
    +-          "WHERE sql NOT NULL"
    +-          "  AND type IN ('index','trigger','view')"
    +-          "  AND tbl_name LIKE shellstatic()", 0
    +-        );
    +-        zShellStatic = 0;
    +-      }
    ++      char *zSql;
    ++      zSql = sqlite3_mprintf(
    ++        "SELECT name, type, sql FROM sqlite_master "
    ++        "WHERE tbl_name LIKE %Q AND type=='table'"
    ++        "  AND sql NOT NULL", zLike);
    ++      run_schema_dump_query(p,zSql);
    ++      sqlite3_free(zSql);
    ++      zSql = sqlite3_mprintf(
    ++        "SELECT sql FROM sqlite_master "
    ++        "WHERE sql NOT NULL"
    ++        "  AND type IN ('index','trigger','view')"
    ++        "  AND tbl_name LIKE %Q", zLike);
    ++      run_table_dump_query(p, zSql, 0);
    ++      sqlite3_free(zSql);
    +     }
    +     if( p->writableSchema ){
    +-      fprintf(p->out, "PRAGMA writable_schema=OFF;\n");
    ++      raw_printf(p->out, "PRAGMA writable_schema=OFF;\n");
    +       p->writableSchema = 0;
    +     }
    +     sqlite3_exec(p->db, "PRAGMA writable_schema=OFF;", 0, 0, 0);
    +     sqlite3_exec(p->db, "RELEASE dump;", 0, 0, 0);
    +-    fprintf(p->out, p->nErr ? "ROLLBACK; -- due to errors\n" : "COMMIT;\n");
    ++    raw_printf(p->out, p->nErr ? "ROLLBACK; -- due to errors\n" : "COMMIT;\n");
    ++    p->showHeader = savedShowHeader;
    +   }else
    + 
    +   if( c=='e' && strncmp(azArg[0], "echo", n)==0 ){
    +     if( nArg==2 ){
    +-      p->echoOn = booleanValue(azArg[1]);
    ++      setOrClearFlag(p, SHFLG_Echo, azArg[1]);
    +     }else{
    +-      fprintf(stderr, "Usage: .echo on|off\n");
    ++      raw_printf(stderr, "Usage: .echo on|off\n");
    +       rc = 1;
    +     }
    +   }else
    + 
    +   if( c=='e' && strncmp(azArg[0], "eqp", n)==0 ){
    +     if( nArg==2 ){
    +-      p->autoEQP = booleanValue(azArg[1]);
    ++      if( strcmp(azArg[1],"full")==0 ){
    ++        p->autoEQP = AUTOEQP_full;
    ++      }else if( strcmp(azArg[1],"trigger")==0 ){
    ++        p->autoEQP = AUTOEQP_trigger;
    ++      }else{
    ++        p->autoEQP = booleanValue(azArg[1]);
    ++      }
    +     }else{
    +-      fprintf(stderr, "Usage: .eqp on|off\n");
    ++      raw_printf(stderr, "Usage: .eqp off|on|trigger|full\n");
    +       rc = 1;
    +-    }   
    ++    }
    +   }else
    + 
    +   if( c=='e' && strncmp(azArg[0], "exit", n)==0 ){
    +@@ -2887,54 +12660,54 @@ static int do_meta_command(char *zLine, ShellState *p){
    +     rc = 2;
    +   }else
    + 
    ++  /* The ".explain" command is automatic now.  It is largely pointless.  It
    ++  ** retained purely for backwards compatibility */
    +   if( c=='e' && strncmp(azArg[0], "explain", n)==0 ){
    +-    int val = nArg>=2 ? booleanValue(azArg[1]) : 1;
    +-    if(val == 1) {
    +-      if(!p->normalMode.valid) {
    +-        p->normalMode.valid = 1;
    +-        p->normalMode.mode = p->mode;
    +-        p->normalMode.showHeader = p->showHeader;
    +-        memcpy(p->normalMode.colWidth,p->colWidth,sizeof(p->colWidth));
    +-      }
    +-      /* We could put this code under the !p->explainValid
    +-      ** condition so that it does not execute if we are already in
    +-      ** explain mode. However, always executing it allows us an easy
    +-      ** was to reset to explain mode in case the user previously
    +-      ** did an .explain followed by a .width, .mode or .header
    +-      ** command.
    +-      */
    ++    int val = 1;
    ++    if( nArg>=2 ){
    ++      if( strcmp(azArg[1],"auto")==0 ){
    ++        val = 99;
    ++      }else{
    ++        val =  booleanValue(azArg[1]);
    ++      }
    ++    }
    ++    if( val==1 && p->mode!=MODE_Explain ){
    ++      p->normalMode = p->mode;
    +       p->mode = MODE_Explain;
    +-      p->showHeader = 1;
    +-      memset(p->colWidth,0,sizeof(p->colWidth));
    +-      p->colWidth[0] = 4;                  /* addr */
    +-      p->colWidth[1] = 13;                 /* opcode */
    +-      p->colWidth[2] = 4;                  /* P1 */
    +-      p->colWidth[3] = 4;                  /* P2 */
    +-      p->colWidth[4] = 4;                  /* P3 */
    +-      p->colWidth[5] = 13;                 /* P4 */
    +-      p->colWidth[6] = 2;                  /* P5 */
    +-      p->colWidth[7] = 13;                  /* Comment */
    +-    }else if (p->normalMode.valid) {
    +-      p->normalMode.valid = 0;
    +-      p->mode = p->normalMode.mode;
    +-      p->showHeader = p->normalMode.showHeader;
    +-      memcpy(p->colWidth,p->normalMode.colWidth,sizeof(p->colWidth));
    ++      p->autoExplain = 0;
    ++    }else if( val==0 ){
    ++      if( p->mode==MODE_Explain ) p->mode = p->normalMode;
    ++      p->autoExplain = 0;
    ++    }else if( val==99 ){
    ++      if( p->mode==MODE_Explain ) p->mode = p->normalMode;
    ++      p->autoExplain = 1;
    +     }
    +   }else
    + 
    ++#ifndef SQLITE_OMIT_VIRTUALTABLE
    ++  if( c=='e' && strncmp(azArg[0], "expert", n)==0 ){
    ++    open_db(p, 0);
    ++    expertDotCommand(p, azArg, nArg);
    ++  }else
    ++#endif
    ++
    +   if( c=='f' && strncmp(azArg[0], "fullschema", n)==0 ){
    +     ShellState data;
    +     char *zErrMsg = 0;
    +     int doStats = 0;
    ++    memcpy(&data, p, sizeof(data));
    ++    data.showHeader = 0;
    ++    data.cMode = data.mode = MODE_Semi;
    ++    if( nArg==2 && optionMatch(azArg[1], "indent") ){
    ++      data.cMode = data.mode = MODE_Pretty;
    ++      nArg = 1;
    ++    }
    +     if( nArg!=1 ){
    +-      fprintf(stderr, "Usage: .fullschema\n");
    ++      raw_printf(stderr, "Usage: .fullschema ?--indent?\n");
    +       rc = 1;
    +       goto meta_command_exit;
    +     }
    +     open_db(p, 0);
    +-    memcpy(&data, p, sizeof(data));
    +-    data.showHeader = 0;
    +-    data.mode = MODE_Semi;
    +     rc = sqlite3_exec(p->db,
    +        "SELECT sql FROM"
    +        "  (SELECT sql sql, type type, tbl_name tbl_name, name name, rowid x"
    +@@ -2954,12 +12727,12 @@ static int do_meta_command(char *zLine, ShellState *p){
    +       sqlite3_finalize(pStmt);
    +     }
    +     if( doStats==0 ){
    +-      fprintf(p->out, "/* No STAT tables available */\n");
    ++      raw_printf(p->out, "/* No STAT tables available */\n");
    +     }else{
    +-      fprintf(p->out, "ANALYZE sqlite_master;\n");
    ++      raw_printf(p->out, "ANALYZE sqlite_master;\n");
    +       sqlite3_exec(p->db, "SELECT 'ANALYZE sqlite_master'",
    +                    callback, &data, &zErrMsg);
    +-      data.mode = MODE_Insert;
    ++      data.cMode = data.mode = MODE_Insert;
    +       data.zDestTable = "sqlite_stat1";
    +       shell_exec(p->db, "SELECT * FROM sqlite_stat1",
    +                  shell_callback, &data,&zErrMsg);
    +@@ -2969,7 +12742,7 @@ static int do_meta_command(char *zLine, ShellState *p){
    +       data.zDestTable = "sqlite_stat4";
    +       shell_exec(p->db, "SELECT * FROM sqlite_stat4",
    +                  shell_callback, &data, &zErrMsg);
    +-      fprintf(p->out, "ANALYZE sqlite_master;\n");
    ++      raw_printf(p->out, "ANALYZE sqlite_master;\n");
    +     }
    +   }else
    + 
    +@@ -2977,13 +12750,13 @@ static int do_meta_command(char *zLine, ShellState *p){
    +     if( nArg==2 ){
    +       p->showHeader = booleanValue(azArg[1]);
    +     }else{
    +-      fprintf(stderr, "Usage: .headers on|off\n");
    ++      raw_printf(stderr, "Usage: .headers on|off\n");
    +       rc = 1;
    +     }
    +   }else
    + 
    +   if( c=='h' && strncmp(azArg[0], "help", n)==0 ){
    +-    fprintf(p->out, "%s", zHelp);
    ++    utf8_printf(p->out, "%s", zHelp);
    +   }else
    + 
    +   if( c=='i' && strncmp(azArg[0], "import", n)==0 ){
    +@@ -3001,7 +12774,7 @@ static int do_meta_command(char *zLine, ShellState *p){
    +     int (SQLITE_CDECL *xCloser)(FILE*);      /* Func to close file */
    + 
    +     if( nArg!=3 ){
    +-      fprintf(stderr, "Usage: .import FILE TABLE\n");
    ++      raw_printf(stderr, "Usage: .import FILE TABLE\n");
    +       goto meta_command_exit;
    +     }
    +     zFile = azArg[1];
    +@@ -3011,17 +12784,18 @@ static int do_meta_command(char *zLine, ShellState *p){
    +     open_db(p, 0);
    +     nSep = strlen30(p->colSeparator);
    +     if( nSep==0 ){
    +-      fprintf(stderr, "Error: non-null column separator required for import\n");
    ++      raw_printf(stderr,
    ++                 "Error: non-null column separator required for import\n");
    +       return 1;
    +     }
    +     if( nSep>1 ){
    +-      fprintf(stderr, "Error: multi-character column separators not allowed"
    ++      raw_printf(stderr, "Error: multi-character column separators not allowed"
    +                       " for import\n");
    +       return 1;
    +     }
    +     nSep = strlen30(p->rowSeparator);
    +     if( nSep==0 ){
    +-      fprintf(stderr, "Error: non-null row separator required for import\n");
    ++      raw_printf(stderr, "Error: non-null row separator required for import\n");
    +       return 1;
    +     }
    +     if( nSep==2 && p->mode==MODE_Csv && strcmp(p->rowSeparator, SEP_CrLf)==0 ){
    +@@ -3033,7 +12807,7 @@ static int do_meta_command(char *zLine, ShellState *p){
    +       nSep = strlen30(p->rowSeparator);
    +     }
    +     if( nSep>1 ){
    +-      fprintf(stderr, "Error: multi-character row separators not allowed"
    ++      raw_printf(stderr, "Error: multi-character row separators not allowed"
    +                       " for import\n");
    +       return 1;
    +     }
    +@@ -3041,7 +12815,7 @@ static int do_meta_command(char *zLine, ShellState *p){
    +     sCtx.nLine = 1;
    +     if( sCtx.zFile[0]=='|' ){
    + #ifdef SQLITE_OMIT_POPEN
    +-      fprintf(stderr, "Error: pipes are not supported in this OS\n");
    ++      raw_printf(stderr, "Error: pipes are not supported in this OS\n");
    +       return 1;
    + #else
    +       sCtx.in = popen(sCtx.zFile+1, "r");
    +@@ -3058,14 +12832,14 @@ static int do_meta_command(char *zLine, ShellState *p){
    +       xRead = csv_read_one_field;
    +     }
    +     if( sCtx.in==0 ){
    +-      fprintf(stderr, "Error: cannot open \"%s\"\n", zFile);
    ++      utf8_printf(stderr, "Error: cannot open \"%s\"\n", zFile);
    +       return 1;
    +     }
    +     sCtx.cColSep = p->colSeparator[0];
    +     sCtx.cRowSep = p->rowSeparator[0];
    +     zSql = sqlite3_mprintf("SELECT * FROM %s", zTable);
    +     if( zSql==0 ){
    +-      fprintf(stderr, "Error: out of memory\n");
    ++      raw_printf(stderr, "Error: out of memory\n");
    +       xCloser(sCtx.in);
    +       return 1;
    +     }
    +@@ -3076,7 +12850,7 @@ static int do_meta_command(char *zLine, ShellState *p){
    +       char *zCreate = sqlite3_mprintf("CREATE TABLE %s", zTable);
    +       char cSep = '(';
    +       while( xRead(&sCtx) ){
    +-        zCreate = sqlite3_mprintf("%z%c\n  \"%s\" TEXT", zCreate, cSep, sCtx.z);
    ++        zCreate = sqlite3_mprintf("%z%c\n  \"%w\" TEXT", zCreate, cSep, sCtx.z);
    +         cSep = ',';
    +         if( sCtx.cTerm!=sCtx.cColSep ) break;
    +       }
    +@@ -3084,14 +12858,14 @@ static int do_meta_command(char *zLine, ShellState *p){
    +         sqlite3_free(zCreate);
    +         sqlite3_free(sCtx.z);
    +         xCloser(sCtx.in);
    +-        fprintf(stderr,"%s: empty file\n", sCtx.zFile);
    ++        utf8_printf(stderr,"%s: empty file\n", sCtx.zFile);
    +         return 1;
    +       }
    +       zCreate = sqlite3_mprintf("%z\n)", zCreate);
    +       rc = sqlite3_exec(p->db, zCreate, 0, 0, 0);
    +       sqlite3_free(zCreate);
    +       if( rc ){
    +-        fprintf(stderr, "CREATE TABLE %s(...) failed: %s\n", zTable,
    ++        utf8_printf(stderr, "CREATE TABLE %s(...) failed: %s\n", zTable,
    +                 sqlite3_errmsg(p->db));
    +         sqlite3_free(sCtx.z);
    +         xCloser(sCtx.in);
    +@@ -3102,7 +12876,7 @@ static int do_meta_command(char *zLine, ShellState *p){
    +     sqlite3_free(zSql);
    +     if( rc ){
    +       if (pStmt) sqlite3_finalize(pStmt);
    +-      fprintf(stderr,"Error: %s\n", sqlite3_errmsg(p->db));
    ++      utf8_printf(stderr,"Error: %s\n", sqlite3_errmsg(p->db));
    +       xCloser(sCtx.in);
    +       return 1;
    +     }
    +@@ -3112,7 +12886,7 @@ static int do_meta_command(char *zLine, ShellState *p){
    +     if( nCol==0 ) return 0; /* no columns, no error */
    +     zSql = sqlite3_malloc64( nByte*2 + 20 + nCol*2 );
    +     if( zSql==0 ){
    +-      fprintf(stderr, "Error: out of memory\n");
    ++      raw_printf(stderr, "Error: out of memory\n");
    +       xCloser(sCtx.in);
    +       return 1;
    +     }
    +@@ -3127,7 +12901,7 @@ static int do_meta_command(char *zLine, ShellState *p){
    +     rc = sqlite3_prepare_v2(p->db, zSql, -1, &pStmt, 0);
    +     sqlite3_free(zSql);
    +     if( rc ){
    +-      fprintf(stderr, "Error: %s\n", sqlite3_errmsg(p->db));
    ++      utf8_printf(stderr, "Error: %s\n", sqlite3_errmsg(p->db));
    +       if (pStmt) sqlite3_finalize(pStmt);
    +       xCloser(sCtx.in);
    +       return 1;
    +@@ -3151,7 +12925,7 @@ static int do_meta_command(char *zLine, ShellState *p){
    +         if( p->mode==MODE_Ascii && (z==0 || z[0]==0) && i==0 ) break;
    +         sqlite3_bind_text(pStmt, i+1, z, -1, SQLITE_TRANSIENT);
    +         if( i<nCol-1 && sCtx.cTerm!=sCtx.cColSep ){
    +-          fprintf(stderr, "%s:%d: expected %d columns but found %d - "
    ++          utf8_printf(stderr, "%s:%d: expected %d columns but found %d - "
    +                           "filling the rest with NULL\n",
    +                           sCtx.zFile, startLine, nCol, i+1);
    +           i += 2;
    +@@ -3163,7 +12937,7 @@ static int do_meta_command(char *zLine, ShellState *p){
    +           xRead(&sCtx);
    +           i++;
    +         }while( sCtx.cTerm==sCtx.cColSep );
    +-        fprintf(stderr, "%s:%d: expected %d columns but found %d - "
    ++        utf8_printf(stderr, "%s:%d: expected %d columns but found %d - "
    +                         "extras ignored\n",
    +                         sCtx.zFile, startLine, nCol, i);
    +       }
    +@@ -3171,8 +12945,8 @@ static int do_meta_command(char *zLine, ShellState *p){
    +         sqlite3_step(pStmt);
    +         rc = sqlite3_reset(pStmt);
    +         if( rc!=SQLITE_OK ){
    +-          fprintf(stderr, "%s:%d: INSERT failed: %s\n", sCtx.zFile, startLine,
    +-                  sqlite3_errmsg(p->db));
    ++          utf8_printf(stderr, "%s:%d: INSERT failed: %s\n", sCtx.zFile,
    ++                      startLine, sqlite3_errmsg(p->db));
    +         }
    +       }
    +     }while( sCtx.cTerm!=EOF );
    +@@ -3183,50 +12957,78 @@ static int do_meta_command(char *zLine, ShellState *p){
    +     if( needCommit ) sqlite3_exec(p->db, "COMMIT", 0, 0, 0);
    +   }else
    + 
    +-  if( c=='i' && (strncmp(azArg[0], "indices", n)==0
    +-                 || strncmp(azArg[0], "indexes", n)==0) ){
    +-    ShellState data;
    +-    char *zErrMsg = 0;
    +-    open_db(p, 0);
    +-    memcpy(&data, p, sizeof(data));
    +-    data.showHeader = 0;
    +-    data.mode = MODE_List;
    +-    if( nArg==1 ){
    +-      rc = sqlite3_exec(p->db,
    +-        "SELECT name FROM sqlite_master "
    +-        "WHERE type='index' AND name NOT LIKE 'sqlite_%' "
    +-        "UNION ALL "
    +-        "SELECT name FROM sqlite_temp_master "
    +-        "WHERE type='index' "
    +-        "ORDER BY 1",
    +-        callback, &data, &zErrMsg
    +-      );
    +-    }else if( nArg==2 ){
    +-      zShellStatic = azArg[1];
    +-      rc = sqlite3_exec(p->db,
    +-        "SELECT name FROM sqlite_master "
    +-        "WHERE type='index' AND tbl_name LIKE shellstatic() "
    +-        "UNION ALL "
    +-        "SELECT name FROM sqlite_temp_master "
    +-        "WHERE type='index' AND tbl_name LIKE shellstatic() "
    +-        "ORDER BY 1",
    +-        callback, &data, &zErrMsg
    +-      );
    +-      zShellStatic = 0;
    +-    }else{
    +-      fprintf(stderr, "Usage: .indexes ?LIKE-PATTERN?\n");
    ++#ifndef SQLITE_UNTESTABLE
    ++  if( c=='i' && strncmp(azArg[0], "imposter", n)==0 ){
    ++    char *zSql;
    ++    char *zCollist = 0;
    ++    sqlite3_stmt *pStmt;
    ++    int tnum = 0;
    ++    int i;
    ++    if( nArg!=3 ){
    ++      utf8_printf(stderr, "Usage: .imposter INDEX IMPOSTER\n");
    +       rc = 1;
    +       goto meta_command_exit;
    +     }
    +-    if( zErrMsg ){
    +-      fprintf(stderr,"Error: %s\n", zErrMsg);
    +-      sqlite3_free(zErrMsg);
    ++    open_db(p, 0);
    ++    zSql = sqlite3_mprintf("SELECT rootpage FROM sqlite_master"
    ++                           " WHERE name='%q' AND type='index'", azArg[1]);
    ++    sqlite3_prepare_v2(p->db, zSql, -1, &pStmt, 0);
    ++    sqlite3_free(zSql);
    ++    if( sqlite3_step(pStmt)==SQLITE_ROW ){
    ++      tnum = sqlite3_column_int(pStmt, 0);
    ++    }
    ++    sqlite3_finalize(pStmt);
    ++    if( tnum==0 ){
    ++      utf8_printf(stderr, "no such index: \"%s\"\n", azArg[1]);
    +       rc = 1;
    +-    }else if( rc != SQLITE_OK ){
    +-      fprintf(stderr,"Error: querying sqlite_master and sqlite_temp_master\n");
    ++      goto meta_command_exit;
    ++    }
    ++    zSql = sqlite3_mprintf("PRAGMA index_xinfo='%q'", azArg[1]);
    ++    rc = sqlite3_prepare_v2(p->db, zSql, -1, &pStmt, 0);
    ++    sqlite3_free(zSql);
    ++    i = 0;
    ++    while( sqlite3_step(pStmt)==SQLITE_ROW ){
    ++      char zLabel[20];
    ++      const char *zCol = (const char*)sqlite3_column_text(pStmt,2);
    ++      i++;
    ++      if( zCol==0 ){
    ++        if( sqlite3_column_int(pStmt,1)==-1 ){
    ++          zCol = "_ROWID_";
    ++        }else{
    ++          sqlite3_snprintf(sizeof(zLabel),zLabel,"expr%d",i);
    ++          zCol = zLabel;
    ++        }
    ++      }
    ++      if( zCollist==0 ){
    ++        zCollist = sqlite3_mprintf("\"%w\"", zCol);
    ++      }else{
    ++        zCollist = sqlite3_mprintf("%z,\"%w\"", zCollist, zCol);
    ++      }
    ++    }
    ++    sqlite3_finalize(pStmt);
    ++    zSql = sqlite3_mprintf(
    ++          "CREATE TABLE \"%w\"(%s,PRIMARY KEY(%s))WITHOUT ROWID",
    ++          azArg[2], zCollist, zCollist);
    ++    sqlite3_free(zCollist);
    ++    rc = sqlite3_test_control(SQLITE_TESTCTRL_IMPOSTER, p->db, "main", 1, tnum);
    ++    if( rc==SQLITE_OK ){
    ++      rc = sqlite3_exec(p->db, zSql, 0, 0, 0);
    ++      sqlite3_test_control(SQLITE_TESTCTRL_IMPOSTER, p->db, "main", 0, 0);
    ++      if( rc ){
    ++        utf8_printf(stderr, "Error in [%s]: %s\n", zSql, sqlite3_errmsg(p->db));
    ++      }else{
    ++        utf8_printf(stdout, "%s;\n", zSql);
    ++        raw_printf(stdout,
    ++           "WARNING: writing to an imposter table will corrupt the index!\n"
    ++        );
    ++      }
    ++    }else{
    ++      raw_printf(stderr, "SQLITE_TESTCTRL_IMPOSTER returns %d\n", rc);
    +       rc = 1;
    +     }
    ++    sqlite3_free(zSql);
    +   }else
    ++#endif /* !defined(SQLITE_OMIT_TEST_CONTROL) */
    + 
    + #ifdef SQLITE_ENABLE_IOTRACE
    +   if( c=='i' && strncmp(azArg[0], "iotrace", n)==0 ){
    +@@ -3241,7 +13043,7 @@ static int do_meta_command(char *zLine, ShellState *p){
    +     }else{
    +       iotrace = fopen(azArg[1], "w");
    +       if( iotrace==0 ){
    +-        fprintf(stderr, "Error: cannot open \"%s\"\n", azArg[1]);
    ++        utf8_printf(stderr, "Error: cannot open \"%s\"\n", azArg[1]);
    +         sqlite3IoTrace = 0;
    +         rc = 1;
    +       }else{
    +@@ -3250,6 +13052,7 @@ static int do_meta_command(char *zLine, ShellState *p){
    +     }
    +   }else
    + #endif
    ++
    +   if( c=='l' && n>=5 && strncmp(azArg[0], "limits", n)==0 ){
    +     static const struct {
    +        const char *zLimitName;   /* Name of a limit */
    +@@ -3272,11 +13075,11 @@ static int do_meta_command(char *zLine, ShellState *p){
    +     open_db(p, 0);
    +     if( nArg==1 ){
    +       for(i=0; i<ArraySize(aLimit); i++){
    +-        printf("%20s %d\n", aLimit[i].zLimitName, 
    ++        printf("%20s %d\n", aLimit[i].zLimitName,
    +                sqlite3_limit(p->db, aLimit[i].limitCode, -1));
    +       }
    +     }else if( nArg>3 ){
    +-      fprintf(stderr, "Usage: .limit NAME ?NEW-VALUE?\n");
    ++      raw_printf(stderr, "Usage: .limit NAME ?NEW-VALUE?\n");
    +       rc = 1;
    +       goto meta_command_exit;
    +     }else{
    +@@ -3287,14 +13090,14 @@ static int do_meta_command(char *zLine, ShellState *p){
    +           if( iLimit<0 ){
    +             iLimit = i;
    +           }else{
    +-            fprintf(stderr, "ambiguous limit: \"%s\"\n", azArg[1]);
    ++            utf8_printf(stderr, "ambiguous limit: \"%s\"\n", azArg[1]);
    +             rc = 1;
    +             goto meta_command_exit;
    +           }
    +         }
    +       }
    +       if( iLimit<0 ){
    +-        fprintf(stderr, "unknown limit: \"%s\"\n"
    ++        utf8_printf(stderr, "unknown limit: \"%s\"\n"
    +                         "enter \".limits\" with no arguments for a list.\n",
    +                          azArg[1]);
    +         rc = 1;
    +@@ -3309,12 +13112,17 @@ static int do_meta_command(char *zLine, ShellState *p){
    +     }
    +   }else
    + 
    ++  if( c=='l' && n>2 && strncmp(azArg[0], "lint", n)==0 ){
    ++    open_db(p, 0);
    ++    lintDotCommand(p, azArg, nArg);
    ++  }else
    ++
    + #ifndef SQLITE_OMIT_LOAD_EXTENSION
    +   if( c=='l' && strncmp(azArg[0], "load", n)==0 ){
    +     const char *zFile, *zProc;
    +     char *zErrMsg = 0;
    +     if( nArg<2 ){
    +-      fprintf(stderr, "Usage: .load FILE ?ENTRYPOINT?\n");
    ++      raw_printf(stderr, "Usage: .load FILE ?ENTRYPOINT?\n");
    +       rc = 1;
    +       goto meta_command_exit;
    +     }
    +@@ -3323,7 +13131,7 @@ static int do_meta_command(char *zLine, ShellState *p){
    +     open_db(p, 0);
    +     rc = sqlite3_load_extension(p->db, zFile, zProc, &zErrMsg);
    +     if( rc!=SQLITE_OK ){
    +-      fprintf(stderr, "Error: %s\n", zErrMsg);
    ++      utf8_printf(stderr, "Error: %s\n", zErrMsg);
    +       sqlite3_free(zErrMsg);
    +       rc = 1;
    +     }
    +@@ -3332,30 +13140,35 @@ static int do_meta_command(char *zLine, ShellState *p){
    + 
    +   if( c=='l' && strncmp(azArg[0], "log", n)==0 ){
    +     if( nArg!=2 ){
    +-      fprintf(stderr, "Usage: .log FILENAME\n");
    ++      raw_printf(stderr, "Usage: .log FILENAME\n");
    +       rc = 1;
    +     }else{
    +       const char *zFile = azArg[1];
    +       output_file_close(p->pLog);
    +-      p->pLog = output_file_open(zFile);
    ++      p->pLog = output_file_open(zFile, 0);
    +     }
    +   }else
    + 
    +   if( c=='m' && strncmp(azArg[0], "mode", n)==0 ){
    +     const char *zMode = nArg>=2 ? azArg[1] : "";
    +-    int n2 = (int)strlen(zMode);
    ++    int n2 = strlen30(zMode);
    +     int c2 = zMode[0];
    +     if( c2=='l' && n2>2 && strncmp(azArg[1],"lines",n2)==0 ){
    +       p->mode = MODE_Line;
    ++      sqlite3_snprintf(sizeof(p->rowSeparator), p->rowSeparator, SEP_Row);
    +     }else if( c2=='c' && strncmp(azArg[1],"columns",n2)==0 ){
    +       p->mode = MODE_Column;
    ++      sqlite3_snprintf(sizeof(p->rowSeparator), p->rowSeparator, SEP_Row);
    +     }else if( c2=='l' && n2>2 && strncmp(azArg[1],"list",n2)==0 ){
    +       p->mode = MODE_List;
    ++      sqlite3_snprintf(sizeof(p->colSeparator), p->colSeparator, SEP_Column);
    ++      sqlite3_snprintf(sizeof(p->rowSeparator), p->rowSeparator, SEP_Row);
    +     }else if( c2=='h' && strncmp(azArg[1],"html",n2)==0 ){
    +       p->mode = MODE_Html;
    +     }else if( c2=='t' && strncmp(azArg[1],"tcl",n2)==0 ){
    +       p->mode = MODE_Tcl;
    +       sqlite3_snprintf(sizeof(p->colSeparator), p->colSeparator, SEP_Space);
    ++      sqlite3_snprintf(sizeof(p->rowSeparator), p->rowSeparator, SEP_Row);
    +     }else if( c2=='c' && strncmp(azArg[1],"csv",n2)==0 ){
    +       p->mode = MODE_Csv;
    +       sqlite3_snprintf(sizeof(p->colSeparator), p->colSeparator, SEP_Comma);
    +@@ -3366,15 +13179,20 @@ static int do_meta_command(char *zLine, ShellState *p){
    +     }else if( c2=='i' && strncmp(azArg[1],"insert",n2)==0 ){
    +       p->mode = MODE_Insert;
    +       set_table_name(p, nArg>=3 ? azArg[2] : "table");
    ++    }else if( c2=='q' && strncmp(azArg[1],"quote",n2)==0 ){
    ++      p->mode = MODE_Quote;
    +     }else if( c2=='a' && strncmp(azArg[1],"ascii",n2)==0 ){
    +       p->mode = MODE_Ascii;
    +       sqlite3_snprintf(sizeof(p->colSeparator), p->colSeparator, SEP_Unit);
    +       sqlite3_snprintf(sizeof(p->rowSeparator), p->rowSeparator, SEP_Record);
    +-    }else {
    +-      fprintf(stderr,"Error: mode should be one of: "
    +-         "ascii column csv html insert line list tabs tcl\n");
    ++    }else if( nArg==1 ){
    ++      raw_printf(p->out, "current output mode: %s\n", modeDescr[p->mode]);
    ++    }else{
    ++      raw_printf(stderr, "Error: mode should be one of: "
    ++         "ascii column csv html insert line list quote tabs tcl\n");
    +       rc = 1;
    +     }
    ++    p->cMode = p->mode;
    +   }else
    + 
    +   if( c=='n' && strncmp(azArg[0], "nullvalue", n)==0 ){
    +@@ -3382,42 +13200,81 @@ static int do_meta_command(char *zLine, ShellState *p){
    +       sqlite3_snprintf(sizeof(p->nullValue), p->nullValue,
    +                        "%.*s", (int)ArraySize(p->nullValue)-1, azArg[1]);
    +     }else{
    +-      fprintf(stderr, "Usage: .nullvalue STRING\n");
    ++      raw_printf(stderr, "Usage: .nullvalue STRING\n");
    +       rc = 1;
    +     }
    +   }else
    + 
    +   if( c=='o' && strncmp(azArg[0], "open", n)==0 && n>=2 ){
    +-    sqlite3 *savedDb = p->db;
    +-    const char *zSavedFilename = p->zDbFilename;
    +-    char *zNewFilename = 0;
    ++    char *zNewFilename;  /* Name of the database file to open */
    ++    int iName = 1;       /* Index in azArg[] of the filename */
    ++    int newFlag = 0;     /* True to delete file before opening */
    ++    /* Close the existing database */
    ++    session_close_all(p);
    ++    sqlite3_close(p->db);
    +     p->db = 0;
    +-    if( nArg>=2 ) zNewFilename = sqlite3_mprintf("%s", azArg[1]);
    +-    p->zDbFilename = zNewFilename;
    +-    open_db(p, 1);
    +-    if( p->db!=0 ){
    +-      sqlite3_close(savedDb);
    +-      sqlite3_free(p->zFreeOnClose);
    +-      p->zFreeOnClose = zNewFilename;
    +-    }else{
    +-      sqlite3_free(zNewFilename);
    +-      p->db = savedDb;
    +-      p->zDbFilename = zSavedFilename;
    ++    p->zDbFilename = 0;
    ++    sqlite3_free(p->zFreeOnClose);
    ++    p->zFreeOnClose = 0;
    ++    p->openMode = SHELL_OPEN_UNSPEC;
    ++    /* Check for command-line arguments */
    ++    for(iName=1; iName<nArg && azArg[iName][0]=='-'; iName++){
    ++      const char *z = azArg[iName];
    ++      if( optionMatch(z,"new") ){
    ++        newFlag = 1;
    ++#ifdef SQLITE_HAVE_ZIP
    ++      }else if( optionMatch(z, "zip") ){
    ++        p->openMode = SHELL_OPEN_ZIPFILE;
    ++#endif
    ++      }else if( optionMatch(z, "append") ){
    ++        p->openMode = SHELL_OPEN_APPENDVFS;
    ++      }else if( z[0]=='-' ){
    ++        utf8_printf(stderr, "unknown option: %s\n", z);
    ++        rc = 1;
    ++        goto meta_command_exit;
    ++      }
    ++    }
    ++    /* If a filename is specified, try to open it first */
    ++    zNewFilename = nArg>iName ? sqlite3_mprintf("%s", azArg[iName]) : 0;
    ++    if( zNewFilename ){
    ++      if( newFlag ) shellDeleteFile(zNewFilename);
    ++      p->zDbFilename = zNewFilename;
    ++      open_db(p, 1);
    ++      if( p->db==0 ){
    ++        utf8_printf(stderr, "Error: cannot open '%s'\n", zNewFilename);
    ++        sqlite3_free(zNewFilename);
    ++      }else{
    ++        p->zFreeOnClose = zNewFilename;
    ++      }
    ++    }
    ++    if( p->db==0 ){
    ++      /* As a fall-back open a TEMP database */
    ++      p->zDbFilename = 0;
    ++      open_db(p, 0);
    +     }
    +   }else
    + 
    +-  if( c=='o'
    +-   && (strncmp(azArg[0], "output", n)==0 || strncmp(azArg[0], "once", n)==0)
    ++  if( (c=='o'
    ++        && (strncmp(azArg[0], "output", n)==0||strncmp(azArg[0], "once", n)==0))
    ++   || (c=='e' && n==5 && strcmp(azArg[0],"excel")==0)
    +   ){
    +     const char *zFile = nArg>=2 ? azArg[1] : "stdout";
    ++    int bTxtMode = 0;
    ++    if( azArg[0][0]=='e' ){
    ++      /* Transform the ".excel" command into ".once -x" */
    ++      nArg = 2;
    ++      azArg[0] = "once";
    ++      zFile = azArg[1] = "-x";
    ++      n = 4;
    ++    }
    +     if( nArg>2 ){
    +-      fprintf(stderr, "Usage: .%s FILE\n", azArg[0]);
    ++      utf8_printf(stderr, "Usage: .%s [-e|-x|FILE]\n", azArg[0]);
    +       rc = 1;
    +       goto meta_command_exit;
    +     }
    +     if( n>1 && strncmp(azArg[0], "once", n)==0 ){
    +       if( nArg<2 ){
    +-        fprintf(stderr, "Usage: .once FILE\n");
    ++        raw_printf(stderr, "Usage: .once (-e|-x|FILE)\n");
    +         rc = 1;
    +         goto meta_command_exit;
    +       }
    +@@ -3426,15 +13283,30 @@ static int do_meta_command(char *zLine, ShellState *p){
    +       p->outCount = 0;
    +     }
    +     output_reset(p);
    ++    if( zFile[0]=='-' && zFile[1]=='-' ) zFile++;
    ++    if( strcmp(zFile, "-e")==0 || strcmp(zFile, "-x")==0 ){
    ++      p->doXdgOpen = 1;
    ++      outputModePush(p);
    ++      if( zFile[1]=='x' ){
    ++        newTempFile(p, "csv");
    ++        p->mode = MODE_Csv;
    ++        sqlite3_snprintf(sizeof(p->colSeparator), p->colSeparator, SEP_Comma);
    ++        sqlite3_snprintf(sizeof(p->rowSeparator), p->rowSeparator, SEP_CrLf);
    ++      }else{
    ++        newTempFile(p, "txt");
    ++        bTxtMode = 1;
    ++      }
    ++      zFile = p->zTempFile;
    ++    }
    +     if( zFile[0]=='|' ){
    + #ifdef SQLITE_OMIT_POPEN
    +-      fprintf(stderr,"Error: pipes are not supported in this OS\n");
    ++      raw_printf(stderr, "Error: pipes are not supported in this OS\n");
    +       rc = 1;
    +       p->out = stdout;
    + #else
    +       p->out = popen(zFile + 1, "w");
    +       if( p->out==0 ){
    +-        fprintf(stderr,"Error: cannot open pipe \"%s\"\n", zFile + 1);
    ++        utf8_printf(stderr,"Error: cannot open pipe \"%s\"\n", zFile + 1);
    +         p->out = stdout;
    +         rc = 1;
    +       }else{
    +@@ -3442,10 +13314,10 @@ static int do_meta_command(char *zLine, ShellState *p){
    +       }
    + #endif
    +     }else{
    +-      p->out = output_file_open(zFile);
    ++      p->out = output_file_open(zFile, bTxtMode);
    +       if( p->out==0 ){
    +         if( strcmp(zFile,"off")!=0 ){
    +-          fprintf(stderr,"Error: cannot write to \"%s\"\n", zFile);
    ++          utf8_printf(stderr,"Error: cannot write to \"%s\"\n", zFile);
    +         }
    +         p->out = stdout;
    +         rc = 1;
    +@@ -3458,10 +13330,10 @@ static int do_meta_command(char *zLine, ShellState *p){
    +   if( c=='p' && n>=3 && strncmp(azArg[0], "print", n)==0 ){
    +     int i;
    +     for(i=1; i<nArg; i++){
    +-      if( i>1 ) fprintf(p->out, " ");
    +-      fprintf(p->out, "%s", azArg[i]);
    ++      if( i>1 ) raw_printf(p->out, " ");
    ++      utf8_printf(p->out, "%s", azArg[i]);
    +     }
    +-    fprintf(p->out, "\n");
    ++    raw_printf(p->out, "\n");
    +   }else
    + 
    +   if( c=='p' && strncmp(azArg[0], "prompt", n)==0 ){
    +@@ -3480,13 +13352,13 @@ static int do_meta_command(char *zLine, ShellState *p){
    +   if( c=='r' && n>=3 && strncmp(azArg[0], "read", n)==0 ){
    +     FILE *alt;
    +     if( nArg!=2 ){
    +-      fprintf(stderr, "Usage: .read FILE\n");
    ++      raw_printf(stderr, "Usage: .read FILE\n");
    +       rc = 1;
    +       goto meta_command_exit;
    +     }
    +     alt = fopen(azArg[1], "rb");
    +     if( alt==0 ){
    +-      fprintf(stderr,"Error: cannot open \"%s\"\n", azArg[1]);
    ++      utf8_printf(stderr,"Error: cannot open \"%s\"\n", azArg[1]);
    +       rc = 1;
    +     }else{
    +       rc = process_input(p, alt);
    +@@ -3508,20 +13380,20 @@ static int do_meta_command(char *zLine, ShellState *p){
    +       zSrcFile = azArg[2];
    +       zDb = azArg[1];
    +     }else{
    +-      fprintf(stderr, "Usage: .restore ?DB? FILE\n");
    ++      raw_printf(stderr, "Usage: .restore ?DB? FILE\n");
    +       rc = 1;
    +       goto meta_command_exit;
    +     }
    +     rc = sqlite3_open(zSrcFile, &pSrc);
    +     if( rc!=SQLITE_OK ){
    +-      fprintf(stderr, "Error: cannot open \"%s\"\n", zSrcFile);
    ++      utf8_printf(stderr, "Error: cannot open \"%s\"\n", zSrcFile);
    +       sqlite3_close(pSrc);
    +       return 1;
    +     }
    +     open_db(p, 0);
    +     pBackup = sqlite3_backup_init(p->db, zDb, pSrc, "main");
    +     if( pBackup==0 ){
    +-      fprintf(stderr, "Error: %s\n", sqlite3_errmsg(p->db));
    ++      utf8_printf(stderr, "Error: %s\n", sqlite3_errmsg(p->db));
    +       sqlite3_close(pSrc);
    +       return 1;
    +     }
    +@@ -3536,10 +13408,10 @@ static int do_meta_command(char *zLine, ShellState *p){
    +     if( rc==SQLITE_DONE ){
    +       rc = 0;
    +     }else if( rc==SQLITE_BUSY || rc==SQLITE_LOCKED ){
    +-      fprintf(stderr, "Error: source database is busy\n");
    ++      raw_printf(stderr, "Error: source database is busy\n");
    +       rc = 1;
    +     }else{
    +-      fprintf(stderr, "Error: %s\n", sqlite3_errmsg(p->db));
    ++      utf8_printf(stderr, "Error: %s\n", sqlite3_errmsg(p->db));
    +       rc = 1;
    +     }
    +     sqlite3_close(pSrc);
    +@@ -3550,100 +13422,336 @@ static int do_meta_command(char *zLine, ShellState *p){
    +     if( nArg==2 ){
    +       p->scanstatsOn = booleanValue(azArg[1]);
    + #ifndef SQLITE_ENABLE_STMT_SCANSTATUS
    +-      fprintf(stderr, "Warning: .scanstats not available in this build.\n");
    ++      raw_printf(stderr, "Warning: .scanstats not available in this build.\n");
    + #endif
    +     }else{
    +-      fprintf(stderr, "Usage: .scanstats on|off\n");
    ++      raw_printf(stderr, "Usage: .scanstats on|off\n");
    +       rc = 1;
    +     }
    +   }else
    + 
    +   if( c=='s' && strncmp(azArg[0], "schema", n)==0 ){
    ++    ShellText sSelect;
    +     ShellState data;
    +     char *zErrMsg = 0;
    ++    const char *zDiv = "(";
    ++    const char *zName = 0;
    ++    int iSchema = 0;
    ++    int bDebug = 0;
    ++    int ii;
    ++
    +     open_db(p, 0);
    +     memcpy(&data, p, sizeof(data));
    +     data.showHeader = 0;
    +-    data.mode = MODE_Semi;
    +-    if( nArg==2 ){
    +-      int i;
    +-      for(i=0; azArg[1][i]; i++) azArg[1][i] = ToLower(azArg[1][i]);
    +-      if( strcmp(azArg[1],"sqlite_master")==0 ){
    +-        char *new_argv[2], *new_colv[2];
    +-        new_argv[0] = "CREATE TABLE sqlite_master (\n"
    +-                      "  type text,\n"
    +-                      "  name text,\n"
    +-                      "  tbl_name text,\n"
    +-                      "  rootpage integer,\n"
    +-                      "  sql text\n"
    +-                      ")";
    +-        new_argv[1] = 0;
    +-        new_colv[0] = "sql";
    +-        new_colv[1] = 0;
    +-        callback(&data, 1, new_argv, new_colv);
    +-        rc = SQLITE_OK;
    +-      }else if( strcmp(azArg[1],"sqlite_temp_master")==0 ){
    ++    data.cMode = data.mode = MODE_Semi;
    ++    initText(&sSelect);
    ++    for(ii=1; ii<nArg; ii++){
    ++      if( optionMatch(azArg[ii],"indent") ){
    ++        data.cMode = data.mode = MODE_Pretty;
    ++      }else if( optionMatch(azArg[ii],"debug") ){
    ++        bDebug = 1;
    ++      }else if( zName==0 ){
    ++        zName = azArg[ii];
    ++      }else{
    ++        raw_printf(stderr, "Usage: .schema ?--indent? ?LIKE-PATTERN?\n");
    ++        rc = 1;
    ++        goto meta_command_exit;
    ++      }
    ++    }
    ++    if( zName!=0 ){
    ++      int isMaster = sqlite3_strlike(zName, "sqlite_master", 0)==0;
    ++      if( isMaster || sqlite3_strlike(zName,"sqlite_temp_master",0)==0 ){
    +         char *new_argv[2], *new_colv[2];
    +-        new_argv[0] = "CREATE TEMP TABLE sqlite_temp_master (\n"
    ++        new_argv[0] = sqlite3_mprintf(
    ++                      "CREATE TABLE %s (\n"
    +                       "  type text,\n"
    +                       "  name text,\n"
    +                       "  tbl_name text,\n"
    +                       "  rootpage integer,\n"
    +                       "  sql text\n"
    +-                      ")";
    ++                      ")", isMaster ? "sqlite_master" : "sqlite_temp_master");
    +         new_argv[1] = 0;
    +         new_colv[0] = "sql";
    +         new_colv[1] = 0;
    +         callback(&data, 1, new_argv, new_colv);
    +-        rc = SQLITE_OK;
    ++        sqlite3_free(new_argv[0]);
    ++      }
    ++    }
    ++    if( zDiv ){
    ++      sqlite3_stmt *pStmt = 0;
    ++      rc = sqlite3_prepare_v2(p->db, "SELECT name FROM pragma_database_list",
    ++                              -1, &pStmt, 0);
    ++      if( rc ){
    ++        utf8_printf(stderr, "Error: %s\n", sqlite3_errmsg(p->db));
    ++        sqlite3_finalize(pStmt);
    ++        rc = 1;
    ++        goto meta_command_exit;
    ++      }
    ++      appendText(&sSelect, "SELECT sql FROM", 0);
    ++      iSchema = 0;
    ++      while( sqlite3_step(pStmt)==SQLITE_ROW ){
    ++        const char *zDb = (const char*)sqlite3_column_text(pStmt, 0);
    ++        char zScNum[30];
    ++        sqlite3_snprintf(sizeof(zScNum), zScNum, "%d", ++iSchema);
    ++        appendText(&sSelect, zDiv, 0);
    ++        zDiv = " UNION ALL ";
    ++        appendText(&sSelect, "SELECT shell_add_schema(sql,", 0);
    ++        if( sqlite3_stricmp(zDb, "main")!=0 ){
    ++          appendText(&sSelect, zDb, '"');
    ++        }else{
    ++          appendText(&sSelect, "NULL", 0);
    ++        }
    ++        appendText(&sSelect, ",name) AS sql, type, tbl_name, name, rowid,", 0);
    ++        appendText(&sSelect, zScNum, 0);
    ++        appendText(&sSelect, " AS snum, ", 0);
    ++        appendText(&sSelect, zDb, '\'');
    ++        appendText(&sSelect, " AS sname FROM ", 0);
    ++        appendText(&sSelect, zDb, '"');
    ++        appendText(&sSelect, ".sqlite_master", 0);
    ++      }
    ++      sqlite3_finalize(pStmt);
    ++#ifdef SQLITE_INTROSPECTION_PRAGMAS
    ++      if( zName ){
    ++        appendText(&sSelect,
    ++           " UNION ALL SELECT shell_module_schema(name),"
    ++           " 'table', name, name, name, 9e+99, 'main' FROM pragma_module_list", 0);
    ++      }
    ++#endif
    ++      appendText(&sSelect, ") WHERE ", 0);
    ++      if( zName ){
    ++        char *zQarg = sqlite3_mprintf("%Q", zName);
    ++        if( strchr(zName, '.') ){
    ++          appendText(&sSelect, "lower(printf('%s.%s',sname,tbl_name))", 0);
    ++        }else{
    ++          appendText(&sSelect, "lower(tbl_name)", 0);
    ++        }
    ++        appendText(&sSelect, strchr(zName, '*') ? " GLOB " : " LIKE ", 0);
    ++        appendText(&sSelect, zQarg, 0);
    ++        appendText(&sSelect, " AND ", 0);
    ++        sqlite3_free(zQarg);
    ++      }
    ++      appendText(&sSelect, "type!='meta' AND sql IS NOT NULL"
    ++                           " ORDER BY snum, rowid", 0);
    ++      if( bDebug ){
    ++        utf8_printf(p->out, "SQL: %s;\n", sSelect.z);
    +       }else{
    +-        zShellStatic = azArg[1];
    +-        rc = sqlite3_exec(p->db,
    +-          "SELECT sql FROM "
    +-          "  (SELECT sql sql, type type, tbl_name tbl_name, name name, rowid x"
    +-          "     FROM sqlite_master UNION ALL"
    +-          "   SELECT sql, type, tbl_name, name, rowid FROM sqlite_temp_master) "
    +-          "WHERE lower(tbl_name) LIKE shellstatic()"
    +-          "  AND type!='meta' AND sql NOTNULL "
    +-          "ORDER BY rowid",
    +-          callback, &data, &zErrMsg);
    +-        zShellStatic = 0;
    ++        rc = sqlite3_exec(p->db, sSelect.z, callback, &data, &zErrMsg);
    +       }
    +-    }else if( nArg==1 ){
    +-      rc = sqlite3_exec(p->db,
    +-         "SELECT sql FROM "
    +-         "  (SELECT sql sql, type type, tbl_name tbl_name, name name, rowid x"
    +-         "     FROM sqlite_master UNION ALL"
    +-         "   SELECT sql, type, tbl_name, name, rowid FROM sqlite_temp_master) "
    +-         "WHERE type!='meta' AND sql NOTNULL AND name NOT LIKE 'sqlite_%' "
    +-         "ORDER BY rowid",
    +-         callback, &data, &zErrMsg
    +-      );
    +-    }else{
    +-      fprintf(stderr, "Usage: .schema ?LIKE-PATTERN?\n");
    +-      rc = 1;
    +-      goto meta_command_exit;
    ++      freeText(&sSelect);
    +     }
    +     if( zErrMsg ){
    +-      fprintf(stderr,"Error: %s\n", zErrMsg);
    ++      utf8_printf(stderr,"Error: %s\n", zErrMsg);
    +       sqlite3_free(zErrMsg);
    +       rc = 1;
    +     }else if( rc != SQLITE_OK ){
    +-      fprintf(stderr,"Error: querying schema information\n");
    ++      raw_printf(stderr,"Error: querying schema information\n");
    +       rc = 1;
    +     }else{
    +       rc = 0;
    +     }
    +   }else
    + 
    +-
    + #if defined(SQLITE_DEBUG) && defined(SQLITE_ENABLE_SELECTTRACE)
    +   if( c=='s' && n==11 && strncmp(azArg[0], "selecttrace", n)==0 ){
    +-    extern int sqlite3SelectTrace;
    +-    sqlite3SelectTrace = integerValue(azArg[1]);
    ++    sqlite3SelectTrace = (int)integerValue(azArg[1]);
    +   }else
    + #endif
    + 
    ++#if defined(SQLITE_ENABLE_SESSION)
    ++  if( c=='s' && strncmp(azArg[0],"session",n)==0 && n>=3 ){
    ++    OpenSession *pSession = &p->aSession[0];
    ++    char **azCmd = &azArg[1];
    ++    int iSes = 0;
    ++    int nCmd = nArg - 1;
    ++    int i;
    ++    if( nArg<=1 ) goto session_syntax_error;
    ++    open_db(p, 0);
    ++    if( nArg>=3 ){
    ++      for(iSes=0; iSes<p->nSession; iSes++){
    ++        if( strcmp(p->aSession[iSes].zName, azArg[1])==0 ) break;
    ++      }
    ++      if( iSes<p->nSession ){
    ++        pSession = &p->aSession[iSes];
    ++        azCmd++;
    ++        nCmd--;
    ++      }else{
    ++        pSession = &p->aSession[0];
    ++        iSes = 0;
    ++      }
    ++    }
    ++
    ++    /* .session attach TABLE
    ++    ** Invoke the sqlite3session_attach() interface to attach a particular
    ++    ** table so that it is never filtered.
    ++    */
    ++    if( strcmp(azCmd[0],"attach")==0 ){
    ++      if( nCmd!=2 ) goto session_syntax_error;
    ++      if( pSession->p==0 ){
    ++        session_not_open:
    ++        raw_printf(stderr, "ERROR: No sessions are open\n");
    ++      }else{
    ++        rc = sqlite3session_attach(pSession->p, azCmd[1]);
    ++        if( rc ){
    ++          raw_printf(stderr, "ERROR: sqlite3session_attach() returns %d\n", rc);
    ++          rc = 0;
    ++        }
    ++      }
    ++    }else
    ++
    ++    /* .session changeset FILE
    ++    ** .session patchset FILE
    ++    ** Write a changeset or patchset into a file.  The file is overwritten.
    ++    */
    ++    if( strcmp(azCmd[0],"changeset")==0 || strcmp(azCmd[0],"patchset")==0 ){
    ++      FILE *out = 0;
    ++      if( nCmd!=2 ) goto session_syntax_error;
    ++      if( pSession->p==0 ) goto session_not_open;
    ++      out = fopen(azCmd[1], "wb");
    ++      if( out==0 ){
    ++        utf8_printf(stderr, "ERROR: cannot open \"%s\" for writing\n", azCmd[1]);
    ++      }else{
    ++        int szChng;
    ++        void *pChng;
    ++        if( azCmd[0][0]=='c' ){
    ++          rc = sqlite3session_changeset(pSession->p, &szChng, &pChng);
    ++        }else{
    ++          rc = sqlite3session_patchset(pSession->p, &szChng, &pChng);
    ++        }
    ++        if( rc ){
    ++          printf("Error: error code %d\n", rc);
    ++          rc = 0;
    ++        }
    ++        if( pChng
    ++          && fwrite(pChng, szChng, 1, out)!=1 ){
    ++          raw_printf(stderr, "ERROR: Failed to write entire %d-byte output\n",
    ++                  szChng);
    ++        }
    ++        sqlite3_free(pChng);
    ++        fclose(out);
    ++      }
    ++    }else
    ++
    ++    /* .session close
    ++    ** Close the identified session
    ++    */
    ++    if( strcmp(azCmd[0], "close")==0 ){
    ++      if( nCmd!=1 ) goto session_syntax_error;
    ++      if( p->nSession ){
    ++        session_close(pSession);
    ++        p->aSession[iSes] = p->aSession[--p->nSession];
    ++      }
    ++    }else
    ++
    ++    /* .session enable ?BOOLEAN?
    ++    ** Query or set the enable flag
    ++    */
    ++    if( strcmp(azCmd[0], "enable")==0 ){
    ++      int ii;
    ++      if( nCmd>2 ) goto session_syntax_error;
    ++      ii = nCmd==1 ? -1 : booleanValue(azCmd[1]);
    ++      if( p->nSession ){
    ++        ii = sqlite3session_enable(pSession->p, ii);
    ++        utf8_printf(p->out, "session %s enable flag = %d\n",
    ++                    pSession->zName, ii);
    ++      }
    ++    }else
    ++
    ++    /* .session filter GLOB ....
    ++    ** Set a list of GLOB patterns of table names to be excluded.
    ++    */
    ++    if( strcmp(azCmd[0], "filter")==0 ){
    ++      int ii, nByte;
    ++      if( nCmd<2 ) goto session_syntax_error;
    ++      if( p->nSession ){
    ++        for(ii=0; ii<pSession->nFilter; ii++){
    ++          sqlite3_free(pSession->azFilter[ii]);
    ++        }
    ++        sqlite3_free(pSession->azFilter);
    ++        nByte = sizeof(pSession->azFilter[0])*(nCmd-1);
    ++        pSession->azFilter = sqlite3_malloc( nByte );
    ++        if( pSession->azFilter==0 ){
    ++          raw_printf(stderr, "Error: out or memory\n");
    ++          exit(1);
    ++        }
    ++        for(ii=1; ii<nCmd; ii++){
    ++          pSession->azFilter[ii-1] = sqlite3_mprintf("%s", azCmd[ii]);
    ++        }
    ++        pSession->nFilter = ii-1;
    ++      }
    ++    }else
    ++
    ++    /* .session indirect ?BOOLEAN?
    ++    ** Query or set the indirect flag
    ++    */
    ++    if( strcmp(azCmd[0], "indirect")==0 ){
    ++      int ii;
    ++      if( nCmd>2 ) goto session_syntax_error;
    ++      ii = nCmd==1 ? -1 : booleanValue(azCmd[1]);
    ++      if( p->nSession ){
    ++        ii = sqlite3session_indirect(pSession->p, ii);
    ++        utf8_printf(p->out, "session %s indirect flag = %d\n",
    ++                    pSession->zName, ii);
    ++      }
    ++    }else
    ++
    ++    /* .session isempty
    ++    ** Determine if the session is empty
    ++    */
    ++    if( strcmp(azCmd[0], "isempty")==0 ){
    ++      int ii;
    ++      if( nCmd!=1 ) goto session_syntax_error;
    ++      if( p->nSession ){
    ++        ii = sqlite3session_isempty(pSession->p);
    ++        utf8_printf(p->out, "session %s isempty flag = %d\n",
    ++                    pSession->zName, ii);
    ++      }
    ++    }else
    ++
    ++    /* .session list
    ++    ** List all currently open sessions
    ++    */
    ++    if( strcmp(azCmd[0],"list")==0 ){
    ++      for(i=0; i<p->nSession; i++){
    ++        utf8_printf(p->out, "%d %s\n", i, p->aSession[i].zName);
    ++      }
    ++    }else
    ++
    ++    /* .session open DB NAME
    ++    ** Open a new session called NAME on the attached database DB.
    ++    ** DB is normally "main".
    ++    */
    ++    if( strcmp(azCmd[0],"open")==0 ){
    ++      char *zName;
    ++      if( nCmd!=3 ) goto session_syntax_error;
    ++      zName = azCmd[2];
    ++      if( zName[0]==0 ) goto session_syntax_error;
    ++      for(i=0; i<p->nSession; i++){
    ++        if( strcmp(p->aSession[i].zName,zName)==0 ){
    ++          utf8_printf(stderr, "Session \"%s\" already exists\n", zName);
    ++          goto meta_command_exit;
    ++        }
    ++      }
    ++      if( p->nSession>=ArraySize(p->aSession) ){
    ++        raw_printf(stderr, "Maximum of %d sessions\n", ArraySize(p->aSession));
    ++        goto meta_command_exit;
    ++      }
    ++      pSession = &p->aSession[p->nSession];
    ++      rc = sqlite3session_create(p->db, azCmd[1], &pSession->p);
    ++      if( rc ){
    ++        raw_printf(stderr, "Cannot open session: error code=%d\n", rc);
    ++        rc = 0;
    ++        goto meta_command_exit;
    ++      }
    ++      pSession->nFilter = 0;
    ++      sqlite3session_table_filter(pSession->p, session_filter, pSession);
    ++      p->nSession++;
    ++      pSession->zName = sqlite3_mprintf("%s", zName);
    ++    }else
    ++    /* If no command name matches, show a syntax error */
    ++    session_syntax_error:
    ++    session_help(p);
    ++  }else
    ++#endif
    + 
    + #ifdef SQLITE_DEBUG
    +   /* Undocumented commands for internal testing.  Subject to change
    +@@ -3653,7 +13761,7 @@ static int do_meta_command(char *zLine, ShellState *p){
    +       int i, v;
    +       for(i=1; i<nArg; i++){
    +         v = booleanValue(azArg[i]);
    +-        fprintf(p->out, "%s: %d 0x%x\n", azArg[i], v, v);
    ++        utf8_printf(p->out, "%s: %d 0x%x\n", azArg[i], v, v);
    +       }
    +     }
    +     if( strncmp(azArg[0]+9, "integer", n-9)==0 ){
    +@@ -3662,15 +13770,121 @@ static int do_meta_command(char *zLine, ShellState *p){
    +         char zBuf[200];
    +         v = integerValue(azArg[i]);
    +         sqlite3_snprintf(sizeof(zBuf),zBuf,"%s: %lld 0x%llx\n", azArg[i],v,v);
    +-        fprintf(p->out, "%s", zBuf);
    ++        utf8_printf(p->out, "%s", zBuf);
    +       }
    +     }
    +   }else
    + #endif
    + 
    ++  if( c=='s' && n>=4 && strncmp(azArg[0],"selftest",n)==0 ){
    ++    int bIsInit = 0;         /* True to initialize the SELFTEST table */
    ++    int bVerbose = 0;        /* Verbose output */
    ++    int bSelftestExists;     /* True if SELFTEST already exists */
    ++    int i, k;                /* Loop counters */
    ++    int nTest = 0;           /* Number of tests runs */
    ++    int nErr = 0;            /* Number of errors seen */
    ++    ShellText str;           /* Answer for a query */
    ++    sqlite3_stmt *pStmt = 0; /* Query against the SELFTEST table */
    ++
    ++    open_db(p,0);
    ++    for(i=1; i<nArg; i++){
    ++      const char *z = azArg[i];
    ++      if( z[0]=='-' && z[1]=='-' ) z++;
    ++      if( strcmp(z,"-init")==0 ){
    ++        bIsInit = 1;
    ++      }else
    ++      if( strcmp(z,"-v")==0 ){
    ++        bVerbose++;
    ++      }else
    ++      {
    ++        utf8_printf(stderr, "Unknown option \"%s\" on \"%s\"\n",
    ++                    azArg[i], azArg[0]);
    ++        raw_printf(stderr, "Should be one of: --init -v\n");
    ++        rc = 1;
    ++        goto meta_command_exit;
    ++      }
    ++    }
    ++    if( sqlite3_table_column_metadata(p->db,"main","selftest",0,0,0,0,0,0)
    ++           != SQLITE_OK ){
    ++      bSelftestExists = 0;
    ++    }else{
    ++      bSelftestExists = 1;
    ++    }
    ++    if( bIsInit ){
    ++      createSelftestTable(p);
    ++      bSelftestExists = 1;
    ++    }
    ++    initText(&str);
    ++    appendText(&str, "x", 0);
    ++    for(k=bSelftestExists; k>=0; k--){
    ++      if( k==1 ){
    ++        rc = sqlite3_prepare_v2(p->db,
    ++            "SELECT tno,op,cmd,ans FROM selftest ORDER BY tno",
    ++            -1, &pStmt, 0);
    ++      }else{
    ++        rc = sqlite3_prepare_v2(p->db,
    ++          "VALUES(0,'memo','Missing SELFTEST table - default checks only',''),"
    ++          "      (1,'run','PRAGMA integrity_check','ok')",
    ++          -1, &pStmt, 0);
    ++      }
    ++      if( rc ){
    ++        raw_printf(stderr, "Error querying the selftest table\n");
    ++        rc = 1;
    ++        sqlite3_finalize(pStmt);
    ++        goto meta_command_exit;
    ++      }
    ++      for(i=1; sqlite3_step(pStmt)==SQLITE_ROW; i++){
    ++        int tno = sqlite3_column_int(pStmt, 0);
    ++        const char *zOp = (const char*)sqlite3_column_text(pStmt, 1);
    ++        const char *zSql = (const char*)sqlite3_column_text(pStmt, 2);
    ++        const char *zAns = (const char*)sqlite3_column_text(pStmt, 3);
    ++
    ++        k = 0;
    ++        if( bVerbose>0 ){
    ++          char *zQuote = sqlite3_mprintf("%q", zSql);
    ++          printf("%d: %s %s\n", tno, zOp, zSql);
    ++          sqlite3_free(zQuote);
    ++        }
    ++        if( strcmp(zOp,"memo")==0 ){
    ++          utf8_printf(p->out, "%s\n", zSql);
    ++        }else
    ++        if( strcmp(zOp,"run")==0 ){
    ++          char *zErrMsg = 0;
    ++          str.n = 0;
    ++          str.z[0] = 0;
    ++          rc = sqlite3_exec(p->db, zSql, captureOutputCallback, &str, &zErrMsg);
    ++          nTest++;
    ++          if( bVerbose ){
    ++            utf8_printf(p->out, "Result: %s\n", str.z);
    ++          }
    ++          if( rc || zErrMsg ){
    ++            nErr++;
    ++            rc = 1;
    ++            utf8_printf(p->out, "%d: error-code-%d: %s\n", tno, rc, zErrMsg);
    ++            sqlite3_free(zErrMsg);
    ++          }else if( strcmp(zAns,str.z)!=0 ){
    ++            nErr++;
    ++            rc = 1;
    ++            utf8_printf(p->out, "%d: Expected: [%s]\n", tno, zAns);
    ++            utf8_printf(p->out, "%d:      Got: [%s]\n", tno, str.z);
    ++          }
    ++        }else
    ++        {
    ++          utf8_printf(stderr,
    ++            "Unknown operation \"%s\" on selftest line %d\n", zOp, tno);
    ++          rc = 1;
    ++          break;
    ++        }
    ++      } /* End loop over rows of content from SELFTEST */
    ++      sqlite3_finalize(pStmt);
    ++    } /* End loop over k */
    ++    freeText(&str);
    ++    utf8_printf(p->out, "%d errors out of %d tests\n", nErr, nTest);
    ++  }else
    ++
    +   if( c=='s' && strncmp(azArg[0], "separator", n)==0 ){
    +     if( nArg<2 || nArg>3 ){
    +-      fprintf(stderr, "Usage: .separator COL ?ROW?\n");
    ++      raw_printf(stderr, "Usage: .separator COL ?ROW?\n");
    +       rc = 1;
    +     }
    +     if( nArg>=2 ){
    +@@ -3683,13 +13897,129 @@ static int do_meta_command(char *zLine, ShellState *p){
    +     }
    +   }else
    + 
    ++  if( c=='s' && n>=4 && strncmp(azArg[0],"sha3sum",n)==0 ){
    ++    const char *zLike = 0;   /* Which table to checksum. 0 means everything */
    ++    int i;                   /* Loop counter */
    ++    int bSchema = 0;         /* Also hash the schema */
    ++    int bSeparate = 0;       /* Hash each table separately */
    ++    int iSize = 224;         /* Hash algorithm to use */
    ++    int bDebug = 0;          /* Only show the query that would have run */
    ++    sqlite3_stmt *pStmt;     /* For querying tables names */
    ++    char *zSql;              /* SQL to be run */
    ++    char *zSep;              /* Separator */
    ++    ShellText sSql;          /* Complete SQL for the query to run the hash */
    ++    ShellText sQuery;        /* Set of queries used to read all content */
    ++    open_db(p, 0);
    ++    for(i=1; i<nArg; i++){
    ++      const char *z = azArg[i];
    ++      if( z[0]=='-' ){
    ++        z++;
    ++        if( z[0]=='-' ) z++;
    ++        if( strcmp(z,"schema")==0 ){
    ++          bSchema = 1;
    ++        }else
    ++        if( strcmp(z,"sha3-224")==0 || strcmp(z,"sha3-256")==0
    ++         || strcmp(z,"sha3-384")==0 || strcmp(z,"sha3-512")==0
    ++        ){
    ++          iSize = atoi(&z[5]);
    ++        }else
    ++        if( strcmp(z,"debug")==0 ){
    ++          bDebug = 1;
    ++        }else
    ++        {
    ++          utf8_printf(stderr, "Unknown option \"%s\" on \"%s\"\n",
    ++                      azArg[i], azArg[0]);
    ++          raw_printf(stderr, "Should be one of: --schema"
    ++                             " --sha3-224 --sha3-255 --sha3-384 --sha3-512\n");
    ++          rc = 1;
    ++          goto meta_command_exit;
    ++        }
    ++      }else if( zLike ){
    ++        raw_printf(stderr, "Usage: .sha3sum ?OPTIONS? ?LIKE-PATTERN?\n");
    ++        rc = 1;
    ++        goto meta_command_exit;
    ++      }else{
    ++        zLike = z;
    ++        bSeparate = 1;
    ++        if( sqlite3_strlike("sqlite_%", zLike, 0)==0 ) bSchema = 1;
    ++      }
    ++    }
    ++    if( bSchema ){
    ++      zSql = "SELECT lower(name) FROM sqlite_master"
    ++             " WHERE type='table' AND coalesce(rootpage,0)>1"
    ++             " UNION ALL SELECT 'sqlite_master'"
    ++             " ORDER BY 1 collate nocase";
    ++    }else{
    ++      zSql = "SELECT lower(name) FROM sqlite_master"
    ++             " WHERE type='table' AND coalesce(rootpage,0)>1"
    ++             " AND name NOT LIKE 'sqlite_%'"
    ++             " ORDER BY 1 collate nocase";
    ++    }
    ++    sqlite3_prepare_v2(p->db, zSql, -1, &pStmt, 0);
    ++    initText(&sQuery);
    ++    initText(&sSql);
    ++    appendText(&sSql, "WITH [sha3sum$query](a,b) AS(",0);
    ++    zSep = "VALUES(";
    ++    while( SQLITE_ROW==sqlite3_step(pStmt) ){
    ++      const char *zTab = (const char*)sqlite3_column_text(pStmt,0);
    ++      if( zLike && sqlite3_strlike(zLike, zTab, 0)!=0 ) continue;
    ++      if( strncmp(zTab, "sqlite_",7)!=0 ){
    ++        appendText(&sQuery,"SELECT * FROM ", 0);
    ++        appendText(&sQuery,zTab,'"');
    ++        appendText(&sQuery," NOT INDEXED;", 0);
    ++      }else if( strcmp(zTab, "sqlite_master")==0 ){
    ++        appendText(&sQuery,"SELECT type,name,tbl_name,sql FROM sqlite_master"
    ++                           " ORDER BY name;", 0);
    ++      }else if( strcmp(zTab, "sqlite_sequence")==0 ){
    ++        appendText(&sQuery,"SELECT name,seq FROM sqlite_sequence"
    ++                           " ORDER BY name;", 0);
    ++      }else if( strcmp(zTab, "sqlite_stat1")==0 ){
    ++        appendText(&sQuery,"SELECT tbl,idx,stat FROM sqlite_stat1"
    ++                           " ORDER BY tbl,idx;", 0);
    ++      }else if( strcmp(zTab, "sqlite_stat3")==0
    ++             || strcmp(zTab, "sqlite_stat4")==0 ){
    ++        appendText(&sQuery, "SELECT * FROM ", 0);
    ++        appendText(&sQuery, zTab, 0);
    ++        appendText(&sQuery, " ORDER BY tbl, idx, rowid;\n", 0);
    ++      }
    ++      appendText(&sSql, zSep, 0);
    ++      appendText(&sSql, sQuery.z, '\'');
    ++      sQuery.n = 0;
    ++      appendText(&sSql, ",", 0);
    ++      appendText(&sSql, zTab, '\'');
    ++      zSep = "),(";
    ++    }
    ++    sqlite3_finalize(pStmt);
    ++    if( bSeparate ){
    ++      zSql = sqlite3_mprintf(
    ++          "%s))"
    ++          " SELECT lower(hex(sha3_query(a,%d))) AS hash, b AS label"
    ++          "   FROM [sha3sum$query]",
    ++          sSql.z, iSize);
    ++    }else{
    ++      zSql = sqlite3_mprintf(
    ++          "%s))"
    ++          " SELECT lower(hex(sha3_query(group_concat(a,''),%d))) AS hash"
    ++          "   FROM [sha3sum$query]",
    ++          sSql.z, iSize);
    ++    }
    ++    freeText(&sQuery);
    ++    freeText(&sSql);
    ++    if( bDebug ){
    ++      utf8_printf(p->out, "%s\n", zSql);
    ++    }else{
    ++      shell_exec(p->db, zSql, shell_callback, p, 0);
    ++    }
    ++    sqlite3_free(zSql);
    ++  }else
    ++
    +   if( c=='s'
    +    && (strncmp(azArg[0], "shell", n)==0 || strncmp(azArg[0],"system",n)==0)
    +   ){
    +     char *zCmd;
    +     int i, x;
    +     if( nArg<2 ){
    +-      fprintf(stderr, "Usage: .system COMMAND\n");
    ++      raw_printf(stderr, "Usage: .system COMMAND\n");
    +       rc = 1;
    +       goto meta_command_exit;
    +     }
    +@@ -3700,93 +14030,104 @@ static int do_meta_command(char *zLine, ShellState *p){
    +     }
    +     x = system(zCmd);
    +     sqlite3_free(zCmd);
    +-    if( x ) fprintf(stderr, "System command returns %d\n", x);
    ++    if( x ) raw_printf(stderr, "System command returns %d\n", x);
    +   }else
    + 
    +   if( c=='s' && strncmp(azArg[0], "show", n)==0 ){
    ++    static const char *azBool[] = { "off", "on", "trigger", "full"};
    +     int i;
    +     if( nArg!=1 ){
    +-      fprintf(stderr, "Usage: .show\n");
    ++      raw_printf(stderr, "Usage: .show\n");
    +       rc = 1;
    +       goto meta_command_exit;
    +     }
    +-    fprintf(p->out,"%12.12s: %s\n","echo", p->echoOn ? "on" : "off");
    +-    fprintf(p->out,"%12.12s: %s\n","eqp", p->autoEQP ? "on" : "off");
    +-    fprintf(p->out,"%9.9s: %s\n","explain", p->normalMode.valid ? "on" :"off");
    +-    fprintf(p->out,"%12.12s: %s\n","headers", p->showHeader ? "on" : "off");
    +-    fprintf(p->out,"%12.12s: %s\n","mode", modeDescr[p->mode]);
    +-    fprintf(p->out,"%12.12s: ", "nullvalue");
    ++    utf8_printf(p->out, "%12.12s: %s\n","echo",
    ++                                  azBool[ShellHasFlag(p, SHFLG_Echo)]);
    ++    utf8_printf(p->out, "%12.12s: %s\n","eqp", azBool[p->autoEQP&3]);
    ++    utf8_printf(p->out, "%12.12s: %s\n","explain",
    ++         p->mode==MODE_Explain ? "on" : p->autoExplain ? "auto" : "off");
    ++    utf8_printf(p->out,"%12.12s: %s\n","headers", azBool[p->showHeader!=0]);
    ++    utf8_printf(p->out, "%12.12s: %s\n","mode", modeDescr[p->mode]);
    ++    utf8_printf(p->out, "%12.12s: ", "nullvalue");
    +       output_c_string(p->out, p->nullValue);
    +-      fprintf(p->out, "\n");
    +-    fprintf(p->out,"%12.12s: %s\n","output",
    ++      raw_printf(p->out, "\n");
    ++    utf8_printf(p->out,"%12.12s: %s\n","output",
    +             strlen30(p->outfile) ? p->outfile : "stdout");
    +-    fprintf(p->out,"%12.12s: ", "colseparator");
    ++    utf8_printf(p->out,"%12.12s: ", "colseparator");
    +       output_c_string(p->out, p->colSeparator);
    +-      fprintf(p->out, "\n");
    +-    fprintf(p->out,"%12.12s: ", "rowseparator");
    ++      raw_printf(p->out, "\n");
    ++    utf8_printf(p->out,"%12.12s: ", "rowseparator");
    +       output_c_string(p->out, p->rowSeparator);
    +-      fprintf(p->out, "\n");
    +-    fprintf(p->out,"%12.12s: %s\n","stats", p->statsOn ? "on" : "off");
    +-    fprintf(p->out,"%12.12s: ","width");
    ++      raw_printf(p->out, "\n");
    ++    utf8_printf(p->out, "%12.12s: %s\n","stats", azBool[p->statsOn!=0]);
    ++    utf8_printf(p->out, "%12.12s: ", "width");
    +     for (i=0;i<(int)ArraySize(p->colWidth) && p->colWidth[i] != 0;i++) {
    +-      fprintf(p->out,"%d ",p->colWidth[i]);
    ++      raw_printf(p->out, "%d ", p->colWidth[i]);
    +     }
    +-    fprintf(p->out,"\n");
    ++    raw_printf(p->out, "\n");
    ++    utf8_printf(p->out, "%12.12s: %s\n", "filename",
    ++                p->zDbFilename ? p->zDbFilename : "");
    +   }else
    + 
    +   if( c=='s' && strncmp(azArg[0], "stats", n)==0 ){
    +     if( nArg==2 ){
    +       p->statsOn = booleanValue(azArg[1]);
    ++    }else if( nArg==1 ){
    ++      display_stats(p->db, p, 0);
    +     }else{
    +-      fprintf(stderr, "Usage: .stats on|off\n");
    ++      raw_printf(stderr, "Usage: .stats ?on|off?\n");
    +       rc = 1;
    +     }
    +   }else
    + 
    +-  if( c=='t' && n>1 && strncmp(azArg[0], "tables", n)==0 ){
    ++  if( (c=='t' && n>1 && strncmp(azArg[0], "tables", n)==0)
    ++   || (c=='i' && (strncmp(azArg[0], "indices", n)==0
    ++                 || strncmp(azArg[0], "indexes", n)==0) )
    ++  ){
    +     sqlite3_stmt *pStmt;
    +     char **azResult;
    +     int nRow, nAlloc;
    +-    char *zSql = 0;
    +     int ii;
    ++    ShellText s;
    ++    initText(&s);
    +     open_db(p, 0);
    +     rc = sqlite3_prepare_v2(p->db, "PRAGMA database_list", -1, &pStmt, 0);
    +     if( rc ) return shellDatabaseError(p->db);
    + 
    +-    /* Create an SQL statement to query for the list of tables in the
    +-    ** main and all attached databases where the table name matches the
    +-    ** LIKE pattern bound to variable "?1". */
    +-    zSql = sqlite3_mprintf(
    +-        "SELECT name FROM sqlite_master"
    +-        " WHERE type IN ('table','view')"
    +-        "   AND name NOT LIKE 'sqlite_%%'"
    +-        "   AND name LIKE ?1");
    +-    while( zSql && sqlite3_step(pStmt)==SQLITE_ROW ){
    ++    if( nArg>2 && c=='i' ){
    ++      /* It is an historical accident that the .indexes command shows an error
    ++      ** when called with the wrong number of arguments whereas the .tables
    ++      ** command does not. */
    ++      raw_printf(stderr, "Usage: .indexes ?LIKE-PATTERN?\n");
    ++      rc = 1;
    ++      goto meta_command_exit;
    ++    }
    ++    for(ii=0; sqlite3_step(pStmt)==SQLITE_ROW; ii++){
    +       const char *zDbName = (const char*)sqlite3_column_text(pStmt, 1);
    +-      if( zDbName==0 || strcmp(zDbName,"main")==0 ) continue;
    +-      if( strcmp(zDbName,"temp")==0 ){
    +-        zSql = sqlite3_mprintf(
    +-                 "%z UNION ALL "
    +-                 "SELECT 'temp.' || name FROM sqlite_temp_master"
    +-                 " WHERE type IN ('table','view')"
    +-                 "   AND name NOT LIKE 'sqlite_%%'"
    +-                 "   AND name LIKE ?1", zSql);
    ++      if( zDbName==0 ) continue;
    ++      if( s.z && s.z[0] ) appendText(&s, " UNION ALL ", 0);
    ++      if( sqlite3_stricmp(zDbName, "main")==0 ){
    ++        appendText(&s, "SELECT name FROM ", 0);
    ++      }else{
    ++        appendText(&s, "SELECT ", 0);
    ++        appendText(&s, zDbName, '\'');
    ++        appendText(&s, "||'.'||name FROM ", 0);
    ++      }
    ++      appendText(&s, zDbName, '"');
    ++      appendText(&s, ".sqlite_master ", 0);
    ++      if( c=='t' ){
    ++        appendText(&s," WHERE type IN ('table','view')"
    ++                      "   AND name NOT LIKE 'sqlite_%'"
    ++                      "   AND name LIKE ?1", 0);
    +       }else{
    +-        zSql = sqlite3_mprintf(
    +-                 "%z UNION ALL "
    +-                 "SELECT '%q.' || name FROM \"%w\".sqlite_master"
    +-                 " WHERE type IN ('table','view')"
    +-                 "   AND name NOT LIKE 'sqlite_%%'"
    +-                 "   AND name LIKE ?1", zSql, zDbName, zDbName);
    ++        appendText(&s," WHERE type='index'"
    ++                      "   AND tbl_name LIKE ?1", 0);
    +       }
    +     }
    +     rc = sqlite3_finalize(pStmt);
    +-    if( zSql && rc==SQLITE_OK ){
    +-      zSql = sqlite3_mprintf("%z ORDER BY 1", zSql);
    +-      if( zSql ) rc = sqlite3_prepare_v2(p->db, zSql, -1, &pStmt, 0);
    +-    }
    +-    sqlite3_free(zSql);
    +-    if( !zSql ) return shellNomemError();
    ++    appendText(&s, " ORDER BY 1", 0);
    ++    rc = sqlite3_prepare_v2(p->db, s.z, -1, &pStmt, 0);
    ++    freeText(&s);
    +     if( rc ) return shellDatabaseError(p->db);
    + 
    +     /* Run the SQL statement prepared by the above block. Store the results
    +@@ -3836,9 +14177,10 @@ static int do_meta_command(char *zLine, ShellState *p){
    +       for(i=0; i<nPrintRow; i++){
    +         for(j=i; j<nRow; j+=nPrintRow){
    +           char *zSp = j<nPrintRow ? "" : "  ";
    +-          fprintf(p->out, "%s%-*s", zSp, maxlen, azResult[j] ? azResult[j]:"");
    ++          utf8_printf(p->out, "%s%-*s", zSp, maxlen,
    ++                      azResult[j] ? azResult[j]:"");
    +         }
    +-        fprintf(p->out, "\n");
    ++        raw_printf(p->out, "\n");
    +       }
    +     }
    + 
    +@@ -3846,63 +14188,105 @@ static int do_meta_command(char *zLine, ShellState *p){
    +     sqlite3_free(azResult);
    +   }else
    + 
    +-  if( c=='t' && n>=8 && strncmp(azArg[0], "testctrl", n)==0 && nArg>=2 ){
    ++  /* Begin redirecting output to the file "testcase-out.txt" */
    ++  if( c=='t' && strcmp(azArg[0],"testcase")==0 ){
    ++    output_reset(p);
    ++    p->out = output_file_open("testcase-out.txt", 0);
    ++    if( p->out==0 ){
    ++      raw_printf(stderr, "Error: cannot open 'testcase-out.txt'\n");
    ++    }
    ++    if( nArg>=2 ){
    ++      sqlite3_snprintf(sizeof(p->zTestcase), p->zTestcase, "%s", azArg[1]);
    ++    }else{
    ++      sqlite3_snprintf(sizeof(p->zTestcase), p->zTestcase, "?");
    ++    }
    ++  }else
    ++
    ++#ifndef SQLITE_UNTESTABLE
    ++  if( c=='t' && n>=8 && strncmp(azArg[0], "testctrl", n)==0 ){
    +     static const struct {
    +        const char *zCtrlName;   /* Name of a test-control option */
    +        int ctrlCode;            /* Integer code for that option */
    ++       const char *zUsage;      /* Usage notes */
    +     } aCtrl[] = {
    +-      { "prng_save",             SQLITE_TESTCTRL_PRNG_SAVE              },
    +-      { "prng_restore",          SQLITE_TESTCTRL_PRNG_RESTORE           },
    +-      { "prng_reset",            SQLITE_TESTCTRL_PRNG_RESET             },
    +-      { "bitvec_test",           SQLITE_TESTCTRL_BITVEC_TEST            },
    +-      { "fault_install",         SQLITE_TESTCTRL_FAULT_INSTALL          },
    +-      { "benign_malloc_hooks",   SQLITE_TESTCTRL_BENIGN_MALLOC_HOOKS    },
    +-      { "pending_byte",          SQLITE_TESTCTRL_PENDING_BYTE           },
    +-      { "assert",                SQLITE_TESTCTRL_ASSERT                 },
    +-      { "always",                SQLITE_TESTCTRL_ALWAYS                 },
    +-      { "reserve",               SQLITE_TESTCTRL_RESERVE                },
    +-      { "optimizations",         SQLITE_TESTCTRL_OPTIMIZATIONS          },
    +-      { "iskeyword",             SQLITE_TESTCTRL_ISKEYWORD              },
    +-      { "scratchmalloc",         SQLITE_TESTCTRL_SCRATCHMALLOC          },
    +-      { "byteorder",             SQLITE_TESTCTRL_BYTEORDER              },
    +-      { "never_corrupt",         SQLITE_TESTCTRL_NEVER_CORRUPT          },
    +-      { "imposter",              SQLITE_TESTCTRL_IMPOSTER               },
    ++      { "always",             SQLITE_TESTCTRL_ALWAYS,        "BOOLEAN"            },
    ++      { "assert",             SQLITE_TESTCTRL_ASSERT,        "BOOLEAN"            },
    ++    /*{ "benign_malloc_hooks",SQLITE_TESTCTRL_BENIGN_MALLOC_HOOKS, ""          },*/
    ++    /*{ "bitvec_test",        SQLITE_TESTCTRL_BITVEC_TEST,   ""                },*/
    ++      { "byteorder",          SQLITE_TESTCTRL_BYTEORDER,     ""                   },
    ++    /*{ "fault_install",      SQLITE_TESTCTRL_FAULT_INSTALL, ""                }, */
    ++      { "imposter",           SQLITE_TESTCTRL_IMPOSTER,   "SCHEMA ON/OFF ROOTPAGE"},
    ++#ifdef SQLITE_N_KEYWORD
    ++      { "iskeyword",          SQLITE_TESTCTRL_ISKEYWORD,     "IDENTIFIER"         },
    ++#endif
    ++      { "localtime_fault",    SQLITE_TESTCTRL_LOCALTIME_FAULT,"BOOLEAN"           },
    ++      { "never_corrupt",      SQLITE_TESTCTRL_NEVER_CORRUPT, "BOOLEAN"            },
    ++      { "optimizations",      SQLITE_TESTCTRL_OPTIMIZATIONS, "DISABLE-MASK"       },
    ++#ifdef YYCOVERAGE
    ++      { "parser_coverage",    SQLITE_TESTCTRL_PARSER_COVERAGE, ""                 },
    ++#endif
    ++      { "pending_byte",       SQLITE_TESTCTRL_PENDING_BYTE,  "OFFSET  "           },
    ++      { "prng_reset",         SQLITE_TESTCTRL_PRNG_RESET,    ""                   },
    ++      { "prng_restore",       SQLITE_TESTCTRL_PRNG_RESTORE,  ""                   },
    ++      { "prng_save",          SQLITE_TESTCTRL_PRNG_SAVE,     ""                   },
    ++      { "reserve",            SQLITE_TESTCTRL_RESERVE,       "BYTES-OF-RESERVE"   },
    +     };
    +     int testctrl = -1;
    +-    int rc2 = 0;
    ++    int iCtrl = -1;
    ++    int rc2 = 0;    /* 0: usage.  1: %d  2: %x  3: no-output */
    ++    int isOk = 0;
    +     int i, n2;
    ++    const char *zCmd = 0;
    ++
    +     open_db(p, 0);
    ++    zCmd = nArg>=2 ? azArg[1] : "help";
    ++
    ++    /* The argument can optionally begin with "-" or "--" */
    ++    if( zCmd[0]=='-' && zCmd[1] ){
    ++      zCmd++;
    ++      if( zCmd[0]=='-' && zCmd[1] ) zCmd++;
    ++    }
    ++
    ++    /* --help lists all test-controls */
    ++    if( strcmp(zCmd,"help")==0 ){
    ++      utf8_printf(p->out, "Available test-controls:\n");
    ++      for(i=0; i<ArraySize(aCtrl); i++){
    ++        utf8_printf(p->out, "  .testctrl %s %s\n",
    ++                    aCtrl[i].zCtrlName, aCtrl[i].zUsage);
    ++      }
    ++      rc = 1;
    ++      goto meta_command_exit;
    ++    }
    + 
    +     /* convert testctrl text option to value. allow any unique prefix
    +     ** of the option name, or a numerical value. */
    +-    n2 = strlen30(azArg[1]);
    ++    n2 = strlen30(zCmd);
    +     for(i=0; i<ArraySize(aCtrl); i++){
    +-      if( strncmp(azArg[1], aCtrl[i].zCtrlName, n2)==0 ){
    ++      if( strncmp(zCmd, aCtrl[i].zCtrlName, n2)==0 ){
    +         if( testctrl<0 ){
    +           testctrl = aCtrl[i].ctrlCode;
    ++          iCtrl = i;
    +         }else{
    +-          fprintf(stderr, "ambiguous option name: \"%s\"\n", azArg[1]);
    +-          testctrl = -1;
    +-          break;
    ++          utf8_printf(stderr, "Error: ambiguous test-control: \"%s\"\n"
    ++                              "Use \".testctrl --help\" for help\n", zCmd);
    ++          rc = 1;
    ++          goto meta_command_exit;
    +         }
    +       }
    +     }
    +-    if( testctrl<0 ) testctrl = (int)integerValue(azArg[1]);
    +-    if( (testctrl<SQLITE_TESTCTRL_FIRST) || (testctrl>SQLITE_TESTCTRL_LAST) ){
    +-      fprintf(stderr,"Error: invalid testctrl option: %s\n", azArg[1]);
    ++    if( testctrl<0 ){
    ++      utf8_printf(stderr,"Error: unknown test-control: %s\n"
    ++                         "Use \".testctrl --help\" for help\n", zCmd);
    +     }else{
    +       switch(testctrl){
    + 
    +         /* sqlite3_test_control(int, db, int) */
    +         case SQLITE_TESTCTRL_OPTIMIZATIONS:
    +-        case SQLITE_TESTCTRL_RESERVE:             
    ++        case SQLITE_TESTCTRL_RESERVE:
    +           if( nArg==3 ){
    +-            int opt = (int)strtol(azArg[2], 0, 0);        
    ++            int opt = (int)strtol(azArg[2], 0, 0);
    +             rc2 = sqlite3_test_control(testctrl, p->db, opt);
    +-            fprintf(p->out, "%d (0x%08x)\n", rc2, rc2);
    +-          } else {
    +-            fprintf(stderr,"Error: testctrl %s takes a single int option\n",
    +-                    azArg[1]);
    ++            isOk = 3;
    +           }
    +           break;
    + 
    +@@ -3913,108 +14297,112 @@ static int do_meta_command(char *zLine, ShellState *p){
    +         case SQLITE_TESTCTRL_BYTEORDER:
    +           if( nArg==2 ){
    +             rc2 = sqlite3_test_control(testctrl);
    +-            fprintf(p->out, "%d (0x%08x)\n", rc2, rc2);
    +-          } else {
    +-            fprintf(stderr,"Error: testctrl %s takes no options\n", azArg[1]);
    ++            isOk = testctrl==SQLITE_TESTCTRL_BYTEORDER ? 1 : 3;
    +           }
    +           break;
    + 
    +         /* sqlite3_test_control(int, uint) */
    +-        case SQLITE_TESTCTRL_PENDING_BYTE:        
    ++        case SQLITE_TESTCTRL_PENDING_BYTE:
    +           if( nArg==3 ){
    +             unsigned int opt = (unsigned int)integerValue(azArg[2]);
    +             rc2 = sqlite3_test_control(testctrl, opt);
    +-            fprintf(p->out, "%d (0x%08x)\n", rc2, rc2);
    +-          } else {
    +-            fprintf(stderr,"Error: testctrl %s takes a single unsigned"
    +-                           " int option\n", azArg[1]);
    ++            isOk = 3;
    ++          }
    ++          break;
    ++
    ++        /* sqlite3_test_control(int, int) */
    ++        case SQLITE_TESTCTRL_ASSERT:
    ++        case SQLITE_TESTCTRL_ALWAYS:
    ++          if( nArg==3 ){
    ++            int opt = booleanValue(azArg[2]);
    ++            rc2 = sqlite3_test_control(testctrl, opt);
    ++            isOk = 1;
    +           }
    +           break;
    +-          
    ++
    +         /* sqlite3_test_control(int, int) */
    +-        case SQLITE_TESTCTRL_ASSERT:              
    +-        case SQLITE_TESTCTRL_ALWAYS:      
    +-        case SQLITE_TESTCTRL_NEVER_CORRUPT:        
    ++        case SQLITE_TESTCTRL_LOCALTIME_FAULT:
    ++        case SQLITE_TESTCTRL_NEVER_CORRUPT:
    +           if( nArg==3 ){
    +-            int opt = booleanValue(azArg[2]);        
    ++            int opt = booleanValue(azArg[2]);
    +             rc2 = sqlite3_test_control(testctrl, opt);
    +-            fprintf(p->out, "%d (0x%08x)\n", rc2, rc2);
    +-          } else {
    +-            fprintf(stderr,"Error: testctrl %s takes a single int option\n",
    +-                            azArg[1]);
    ++            isOk = 3;
    +           }
    +           break;
    + 
    +         /* sqlite3_test_control(int, char *) */
    + #ifdef SQLITE_N_KEYWORD
    +-        case SQLITE_TESTCTRL_ISKEYWORD:           
    ++        case SQLITE_TESTCTRL_ISKEYWORD:
    +           if( nArg==3 ){
    +-            const char *opt = azArg[2];        
    ++            const char *opt = azArg[2];
    +             rc2 = sqlite3_test_control(testctrl, opt);
    +-            fprintf(p->out, "%d (0x%08x)\n", rc2, rc2);
    +-          } else {
    +-            fprintf(stderr,"Error: testctrl %s takes a single char * option\n",
    +-                            azArg[1]);
    ++            isOk = 1;
    +           }
    +           break;
    + #endif
    + 
    +         case SQLITE_TESTCTRL_IMPOSTER:
    +           if( nArg==5 ){
    +-            rc2 = sqlite3_test_control(testctrl, p->db, 
    ++            rc2 = sqlite3_test_control(testctrl, p->db,
    +                           azArg[2],
    +                           integerValue(azArg[3]),
    +                           integerValue(azArg[4]));
    +-            fprintf(p->out, "%d (0x%08x)\n", rc2, rc2);
    +-          }else{
    +-            fprintf(stderr,"Usage: .testctrl imposter dbName onoff tnum\n");
    ++            isOk = 3;
    +           }
    +           break;
    + 
    +-        case SQLITE_TESTCTRL_BITVEC_TEST:         
    +-        case SQLITE_TESTCTRL_FAULT_INSTALL:       
    +-        case SQLITE_TESTCTRL_BENIGN_MALLOC_HOOKS: 
    +-        case SQLITE_TESTCTRL_SCRATCHMALLOC:       
    +-        default:
    +-          fprintf(stderr,"Error: CLI support for testctrl %s not implemented\n",
    +-                  azArg[1]);
    +-          break;
    ++#ifdef YYCOVERAGE
    ++        case SQLITE_TESTCTRL_PARSER_COVERAGE:
    ++          if( nArg==2 ){
    ++            sqlite3_test_control(testctrl, p->out);
    ++            isOk = 3;
    ++          }
    ++#endif
    +       }
    +     }
    ++    if( isOk==0 && iCtrl>=0 ){
    ++      utf8_printf(p->out, "Usage: .testctrl %s %s\n", zCmd, aCtrl[iCtrl].zUsage);
    ++      rc = 1;
    ++    }else if( isOk==1 ){
    ++      raw_printf(p->out, "%d\n", rc2);
    ++    }else if( isOk==2 ){
    ++      raw_printf(p->out, "0x%08x\n", rc2);
    ++    }
    +   }else
    ++#endif /* !defined(SQLITE_UNTESTABLE) */
    + 
    +   if( c=='t' && n>4 && strncmp(azArg[0], "timeout", n)==0 ){
    +     open_db(p, 0);
    +     sqlite3_busy_timeout(p->db, nArg>=2 ? (int)integerValue(azArg[1]) : 0);
    +   }else
    +-    
    ++
    +   if( c=='t' && n>=5 && strncmp(azArg[0], "timer", n)==0 ){
    +     if( nArg==2 ){
    +       enableTimer = booleanValue(azArg[1]);
    +       if( enableTimer && !HAS_TIMER ){
    +-        fprintf(stderr, "Error: timer not available on this system.\n");
    ++        raw_printf(stderr, "Error: timer not available on this system.\n");
    +         enableTimer = 0;
    +       }
    +     }else{
    +-      fprintf(stderr, "Usage: .timer on|off\n");
    ++      raw_printf(stderr, "Usage: .timer on|off\n");
    +       rc = 1;
    +     }
    +   }else
    +-  
    ++
    +   if( c=='t' && strncmp(azArg[0], "trace", n)==0 ){
    +     open_db(p, 0);
    +     if( nArg!=2 ){
    +-      fprintf(stderr, "Usage: .trace FILE|off\n");
    ++      raw_printf(stderr, "Usage: .trace FILE|off\n");
    +       rc = 1;
    +       goto meta_command_exit;
    +     }
    +     output_file_close(p->traceOut);
    +-    p->traceOut = output_file_open(azArg[1]);
    ++    p->traceOut = output_file_open(azArg[1], 0);
    + #if !defined(SQLITE_OMIT_TRACE) && !defined(SQLITE_OMIT_FLOATING_POINT)
    +     if( p->traceOut==0 ){
    +-      sqlite3_trace(p->db, 0, 0);
    ++      sqlite3_trace_v2(p->db, 0, 0, 0);
    +     }else{
    +-      sqlite3_trace(p->db, sql_trace_callback, p->traceOut);
    ++      sqlite3_trace_v2(p->db, SQLITE_TRACE_STMT, sql_trace_callback,p->traceOut);
    +     }
    + #endif
    +   }else
    +@@ -4022,71 +14410,114 @@ static int do_meta_command(char *zLine, ShellState *p){
    + #if SQLITE_USER_AUTHENTICATION
    +   if( c=='u' && strncmp(azArg[0], "user", n)==0 ){
    +     if( nArg<2 ){
    +-      fprintf(stderr, "Usage: .user SUBCOMMAND ...\n");
    ++      raw_printf(stderr, "Usage: .user SUBCOMMAND ...\n");
    +       rc = 1;
    +       goto meta_command_exit;
    +     }
    +     open_db(p, 0);
    +     if( strcmp(azArg[1],"login")==0 ){
    +       if( nArg!=4 ){
    +-        fprintf(stderr, "Usage: .user login USER PASSWORD\n");
    ++        raw_printf(stderr, "Usage: .user login USER PASSWORD\n");
    +         rc = 1;
    +         goto meta_command_exit;
    +       }
    +-      rc = sqlite3_user_authenticate(p->db, azArg[2], azArg[3],
    +-                                    (int)strlen(azArg[3]));
    ++      rc = sqlite3_user_authenticate(p->db, azArg[2], azArg[3], strlen30(azArg[3]));
    +       if( rc ){
    +-        fprintf(stderr, "Authentication failed for user %s\n", azArg[2]);
    ++        utf8_printf(stderr, "Authentication failed for user %s\n", azArg[2]);
    +         rc = 1;
    +       }
    +     }else if( strcmp(azArg[1],"add")==0 ){
    +       if( nArg!=5 ){
    +-        fprintf(stderr, "Usage: .user add USER PASSWORD ISADMIN\n");
    ++        raw_printf(stderr, "Usage: .user add USER PASSWORD ISADMIN\n");
    +         rc = 1;
    +         goto meta_command_exit;
    +       }
    +-      rc = sqlite3_user_add(p->db, azArg[2],
    +-                            azArg[3], (int)strlen(azArg[3]),
    ++      rc = sqlite3_user_add(p->db, azArg[2], azArg[3], strlen30(azArg[3]),
    +                             booleanValue(azArg[4]));
    +       if( rc ){
    +-        fprintf(stderr, "User-Add failed: %d\n", rc);
    ++        raw_printf(stderr, "User-Add failed: %d\n", rc);
    +         rc = 1;
    +       }
    +     }else if( strcmp(azArg[1],"edit")==0 ){
    +       if( nArg!=5 ){
    +-        fprintf(stderr, "Usage: .user edit USER PASSWORD ISADMIN\n");
    ++        raw_printf(stderr, "Usage: .user edit USER PASSWORD ISADMIN\n");
    +         rc = 1;
    +         goto meta_command_exit;
    +       }
    +-      rc = sqlite3_user_change(p->db, azArg[2],
    +-                              azArg[3], (int)strlen(azArg[3]),
    ++      rc = sqlite3_user_change(p->db, azArg[2], azArg[3], strlen30(azArg[3]),
    +                               booleanValue(azArg[4]));
    +       if( rc ){
    +-        fprintf(stderr, "User-Edit failed: %d\n", rc);
    ++        raw_printf(stderr, "User-Edit failed: %d\n", rc);
    +         rc = 1;
    +       }
    +     }else if( strcmp(azArg[1],"delete")==0 ){
    +       if( nArg!=3 ){
    +-        fprintf(stderr, "Usage: .user delete USER\n");
    ++        raw_printf(stderr, "Usage: .user delete USER\n");
    +         rc = 1;
    +         goto meta_command_exit;
    +       }
    +       rc = sqlite3_user_delete(p->db, azArg[2]);
    +       if( rc ){
    +-        fprintf(stderr, "User-Delete failed: %d\n", rc);
    ++        raw_printf(stderr, "User-Delete failed: %d\n", rc);
    +         rc = 1;
    +       }
    +     }else{
    +-      fprintf(stderr, "Usage: .user login|add|edit|delete ...\n");
    ++      raw_printf(stderr, "Usage: .user login|add|edit|delete ...\n");
    +       rc = 1;
    +       goto meta_command_exit;
    +-    }    
    ++    }
    +   }else
    + #endif /* SQLITE_USER_AUTHENTICATION */
    + 
    +   if( c=='v' && strncmp(azArg[0], "version", n)==0 ){
    +-    fprintf(p->out, "SQLite %s %s\n" /*extra-version-info*/,
    ++    utf8_printf(p->out, "SQLite %s %s\n" /*extra-version-info*/,
    +         sqlite3_libversion(), sqlite3_sourceid());
    ++#if SQLITE_HAVE_ZLIB
    ++    utf8_printf(p->out, "zlib version %s\n", zlibVersion());
    ++#endif
    ++#define CTIMEOPT_VAL_(opt) #opt
    ++#define CTIMEOPT_VAL(opt) CTIMEOPT_VAL_(opt)
    ++#if defined(__clang__) && defined(__clang_major__)
    ++    utf8_printf(p->out, "clang-" CTIMEOPT_VAL(__clang_major__) "."
    ++                    CTIMEOPT_VAL(__clang_minor__) "."
    ++                    CTIMEOPT_VAL(__clang_patchlevel__) "\n");
    ++#elif defined(_MSC_VER)
    ++    utf8_printf(p->out, "msvc-" CTIMEOPT_VAL(_MSC_VER) "\n");
    ++#elif defined(__GNUC__) && defined(__VERSION__)
    ++    utf8_printf(p->out, "gcc-" __VERSION__ "\n");
    ++#endif
    ++  }else
    ++
    ++  if( c=='v' && strncmp(azArg[0], "vfsinfo", n)==0 ){
    ++    const char *zDbName = nArg==2 ? azArg[1] : "main";
    ++    sqlite3_vfs *pVfs = 0;
    ++    if( p->db ){
    ++      sqlite3_file_control(p->db, zDbName, SQLITE_FCNTL_VFS_POINTER, &pVfs);
    ++      if( pVfs ){
    ++        utf8_printf(p->out, "vfs.zName      = \"%s\"\n", pVfs->zName);
    ++        raw_printf(p->out, "vfs.iVersion   = %d\n", pVfs->iVersion);
    ++        raw_printf(p->out, "vfs.szOsFile   = %d\n", pVfs->szOsFile);
    ++        raw_printf(p->out, "vfs.mxPathname = %d\n", pVfs->mxPathname);
    ++      }
    ++    }
    ++  }else
    ++
    ++  if( c=='v' && strncmp(azArg[0], "vfslist", n)==0 ){
    ++    sqlite3_vfs *pVfs;
    ++    sqlite3_vfs *pCurrent = 0;
    ++    if( p->db ){
    ++      sqlite3_file_control(p->db, "main", SQLITE_FCNTL_VFS_POINTER, &pCurrent);
    ++    }
    ++    for(pVfs=sqlite3_vfs_find(0); pVfs; pVfs=pVfs->pNext){
    ++      utf8_printf(p->out, "vfs.zName      = \"%s\"%s\n", pVfs->zName,
    ++           pVfs==pCurrent ? "  <--- CURRENT" : "");
    ++      raw_printf(p->out, "vfs.iVersion   = %d\n", pVfs->iVersion);
    ++      raw_printf(p->out, "vfs.szOsFile   = %d\n", pVfs->szOsFile);
    ++      raw_printf(p->out, "vfs.mxPathname = %d\n", pVfs->mxPathname);
    ++      if( pVfs->pNext ){
    ++        raw_printf(p->out, "-----------------------------------\n");
    ++      }
    ++    }
    +   }else
    + 
    +   if( c=='v' && strncmp(azArg[0], "vfsname", n)==0 ){
    +@@ -4095,7 +14526,7 @@ static int do_meta_command(char *zLine, ShellState *p){
    +     if( p->db ){
    +       sqlite3_file_control(p->db, zDbName, SQLITE_FCNTL_VFSNAME, &zVfsName);
    +       if( zVfsName ){
    +-        fprintf(p->out, "%s\n", zVfsName);
    ++        utf8_printf(p->out, "%s\n", zVfsName);
    +         sqlite3_free(zVfsName);
    +       }
    +     }
    +@@ -4103,7 +14534,6 @@ static int do_meta_command(char *zLine, ShellState *p){
    + 
    + #if defined(SQLITE_DEBUG) && defined(SQLITE_ENABLE_WHERETRACE)
    +   if( c=='w' && strncmp(azArg[0], "wheretrace", n)==0 ){
    +-    extern int sqlite3WhereTrace;
    +     sqlite3WhereTrace = nArg>=2 ? booleanValue(azArg[1]) : 0xff;
    +   }else
    + #endif
    +@@ -4117,7 +14547,7 @@ static int do_meta_command(char *zLine, ShellState *p){
    +   }else
    + 
    +   {
    +-    fprintf(stderr, "Error: unknown command or invalid arguments: "
    ++    utf8_printf(stderr, "Error: unknown command or invalid arguments: "
    +       " \"%s\". Enter \".help\" for help\n", azArg[0]);
    +     rc = 1;
    +   }
    +@@ -4195,6 +14625,42 @@ static int line_is_complete(char *zSql, int nSql){
    +   return rc;
    + }
    + 
    ++/*
    ++** Run a single line of SQL
    ++*/
    ++static int runOneSqlLine(ShellState *p, char *zSql, FILE *in, int startline){
    ++  int rc;
    ++  char *zErrMsg = 0;
    ++
    ++  open_db(p, 0);
    ++  if( ShellHasFlag(p,SHFLG_Backslash) ) resolve_backslashes(zSql);
    ++  BEGIN_TIMER;
    ++  rc = shell_exec(p->db, zSql, shell_callback, p, &zErrMsg);
    ++  END_TIMER;
    ++  if( rc || zErrMsg ){
    ++    char zPrefix[100];
    ++    if( in!=0 || !stdin_is_interactive ){
    ++      sqlite3_snprintf(sizeof(zPrefix), zPrefix,
    ++                       "Error: near line %d:", startline);
    ++    }else{
    ++      sqlite3_snprintf(sizeof(zPrefix), zPrefix, "Error:");
    ++    }
    ++    if( zErrMsg!=0 ){
    ++      utf8_printf(stderr, "%s %s\n", zPrefix, zErrMsg);
    ++      sqlite3_free(zErrMsg);
    ++      zErrMsg = 0;
    ++    }else{
    ++      utf8_printf(stderr, "%s %s\n", zPrefix, sqlite3_errmsg(p->db));
    ++    }
    ++    return 1;
    ++  }else if( ShellHasFlag(p, SHFLG_CountChanges) ){
    ++    raw_printf(p->out, "changes: %3d   total_changes: %d\n",
    ++            sqlite3_changes(p->db), sqlite3_total_changes(p->db));
    ++  }
    ++  return 0;
    ++}
    ++
    ++
    + /*
    + ** Read input from *in and process it.  If *in==0 then input
    + ** is interactive - the user is typing it it.  Otherwise, input
    +@@ -4211,7 +14677,6 @@ static int process_input(ShellState *p, FILE *in){
    +   int nSql = 0;             /* Bytes of zSql[] used */
    +   int nAlloc = 0;           /* Allocated zSql[] space */
    +   int nSqlPrior = 0;        /* Bytes of zSql[] used by prior line */
    +-  char *zErrMsg;            /* Error message returned */
    +   int rc;                   /* Error code */
    +   int errCnt = 0;           /* Number of errors seen */
    +   int lineno = 0;           /* Current line number */
    +@@ -4222,7 +14687,7 @@ static int process_input(ShellState *p, FILE *in){
    +     zLine = one_input_line(in, zLine, nSql>0);
    +     if( zLine==0 ){
    +       /* End of input */
    +-      if( stdin_is_interactive ) printf("\n");
    ++      if( in==0 && stdin_is_interactive ) printf("\n");
    +       break;
    +     }
    +     if( seenInterrupt ){
    +@@ -4231,11 +14696,11 @@ static int process_input(ShellState *p, FILE *in){
    +     }
    +     lineno++;
    +     if( nSql==0 && _all_whitespace(zLine) ){
    +-      if( p->echoOn ) printf("%s\n", zLine);
    ++      if( ShellHasFlag(p, SHFLG_Echo) ) printf("%s\n", zLine);
    +       continue;
    +     }
    +     if( zLine && zLine[0]=='.' && nSql==0 ){
    +-      if( p->echoOn ) printf("%s\n", zLine);
    ++      if( ShellHasFlag(p, SHFLG_Echo) ) printf("%s\n", zLine);
    +       rc = do_meta_command(zLine, p);
    +       if( rc==2 ){ /* exit requested */
    +         break;
    +@@ -4252,7 +14717,7 @@ static int process_input(ShellState *p, FILE *in){
    +       nAlloc = nSql+nLine+100;
    +       zSql = realloc(zSql, nAlloc);
    +       if( zSql==0 ){
    +-        fprintf(stderr, "Error: out of memory\n");
    ++        raw_printf(stderr, "Error: out of memory\n");
    +         exit(1);
    +       }
    +     }
    +@@ -4271,44 +14736,21 @@ static int process_input(ShellState *p, FILE *in){
    +     }
    +     if( nSql && line_contains_semicolon(&zSql[nSqlPrior], nSql-nSqlPrior)
    +                 && sqlite3_complete(zSql) ){
    +-      p->cnt = 0;
    +-      open_db(p, 0);
    +-      if( p->backslashOn ) resolve_backslashes(zSql);
    +-      BEGIN_TIMER;
    +-      rc = shell_exec(p->db, zSql, shell_callback, p, &zErrMsg);
    +-      END_TIMER;
    +-      if( rc || zErrMsg ){
    +-        char zPrefix[100];
    +-        if( in!=0 || !stdin_is_interactive ){
    +-          sqlite3_snprintf(sizeof(zPrefix), zPrefix, 
    +-                           "Error: near line %d:", startline);
    +-        }else{
    +-          sqlite3_snprintf(sizeof(zPrefix), zPrefix, "Error:");
    +-        }
    +-        if( zErrMsg!=0 ){
    +-          fprintf(stderr, "%s %s\n", zPrefix, zErrMsg);
    +-          sqlite3_free(zErrMsg);
    +-          zErrMsg = 0;
    +-        }else{
    +-          fprintf(stderr, "%s %s\n", zPrefix, sqlite3_errmsg(p->db));
    +-        }
    +-        errCnt++;
    +-      }
    ++      errCnt += runOneSqlLine(p, zSql, in, startline);
    +       nSql = 0;
    +       if( p->outCount ){
    +         output_reset(p);
    +         p->outCount = 0;
    ++      }else{
    ++        clearTempFile(p);
    +       }
    +     }else if( nSql && _all_whitespace(zSql) ){
    +-      if( p->echoOn ) printf("%s\n", zSql);
    ++      if( ShellHasFlag(p, SHFLG_Echo) ) printf("%s\n", zSql);
    +       nSql = 0;
    +     }
    +   }
    +-  if( nSql ){
    +-    if( !_all_whitespace(zSql) ){
    +-      fprintf(stderr, "Error: incomplete SQL: %s\n", zSql);
    +-      errCnt++;
    +-    }
    ++  if( nSql && !_all_whitespace(zSql) ){
    ++    runOneSqlLine(p, zSql, in, startline);
    +   }
    +   free(zSql);
    +   free(zLine);
    +@@ -4319,8 +14761,13 @@ static int process_input(ShellState *p, FILE *in){
    + ** Return a pathname which is the user's home directory.  A
    + ** 0 return indicates an error of some kind.
    + */
    +-static char *find_home_dir(void){
    ++static char *find_home_dir(int clearFlag){
    +   static char *home_dir = NULL;
    ++  if( clearFlag ){
    ++    free(home_dir);
    ++    home_dir = 0;
    ++    return 0;
    ++  }
    +   if( home_dir ) return home_dir;
    + 
    + #if !defined(_WIN32) && !defined(WIN32) && !defined(_WIN32_WCE) \
    +@@ -4395,9 +14842,9 @@ static void process_sqliterc(
    +   FILE *in = NULL;
    + 
    +   if (sqliterc == NULL) {
    +-    home_dir = find_home_dir();
    ++    home_dir = find_home_dir(0);
    +     if( home_dir==0 ){
    +-      fprintf(stderr, "-- warning: cannot find home directory;"
    ++      raw_printf(stderr, "-- warning: cannot find home directory;"
    +                       " cannot read ~/.sqliterc\n");
    +       return;
    +     }
    +@@ -4408,7 +14855,7 @@ static void process_sqliterc(
    +   in = fopen(sqliterc,"rb");
    +   if( in ){
    +     if( stdin_is_interactive ){
    +-      fprintf(stderr,"-- Loading resources from %s\n",sqliterc);
    ++      utf8_printf(stderr,"-- Loading resources from %s\n",sqliterc);
    +     }
    +     process_input(p,in);
    +     fclose(in);
    +@@ -4419,7 +14866,7 @@ static void process_sqliterc(
    + /*
    + ** Show available command line options
    + */
    +-static const char zOptions[] = 
    ++static const char zOptions[] =
    +   "   -ascii               set output mode to 'ascii'\n"
    +   "   -bail                stop after hitting an error\n"
    +   "   -batch               force batch I/O\n"
    +@@ -4445,7 +14892,7 @@ static const char zOptions[] =
    +   "   -newline SEP         set output row separator. Default: '\\n'\n"
    +   "   -nullvalue TEXT      set text string for NULL values. Default ''\n"
    +   "   -pagecache SIZE N    use N slots of SZ bytes each for page cache memory\n"
    +-  "   -scratch SIZE N      use N slots of SZ bytes each for scratch memory\n"
    ++  "   -quote               set output mode to 'quote'\n"
    +   "   -separator SEP       set output column separator. Default: '|'\n"
    +   "   -stats               print memory stats before each finalize\n"
    +   "   -version             show SQLite version\n"
    +@@ -4455,14 +14902,14 @@ static const char zOptions[] =
    + #endif
    + ;
    + static void usage(int showDetail){
    +-  fprintf(stderr,
    +-      "Usage: %s [OPTIONS] FILENAME [SQL]\n"  
    ++  utf8_printf(stderr,
    ++      "Usage: %s [OPTIONS] FILENAME [SQL]\n"
    +       "FILENAME is the name of an SQLite database. A new database is created\n"
    +       "if the file does not previously exist.\n", Argv0);
    +   if( showDetail ){
    +-    fprintf(stderr, "OPTIONS include:\n%s", zOptions);
    ++    utf8_printf(stderr, "OPTIONS include:\n%s", zOptions);
    +   }else{
    +-    fprintf(stderr, "Use the -help option for additional information\n");
    ++    raw_printf(stderr, "Use the -help option for additional information\n");
    +   }
    +   exit(1);
    + }
    +@@ -4472,7 +14919,8 @@ static void usage(int showDetail){
    + */
    + static void main_init(ShellState *data) {
    +   memset(data, 0, sizeof(*data));
    +-  data->mode = MODE_List;
    ++  data->normalMode = data->cMode = data->mode = MODE_List;
    ++  data->autoExplain = 1;
    +   memcpy(data->colSeparator,SEP_Column, 2);
    +   memcpy(data->rowSeparator,SEP_Row, 2);
    +   data->showHeader = 0;
    +@@ -4510,14 +14958,27 @@ static void printBold(const char *zText){
    + */
    + static char *cmdline_option_value(int argc, char **argv, int i){
    +   if( i==argc ){
    +-    fprintf(stderr, "%s: Error: missing argument to %s\n",
    ++    utf8_printf(stderr, "%s: Error: missing argument to %s\n",
    +             argv[0], argv[argc-1]);
    +     exit(1);
    +   }
    +   return argv[i];
    + }
    + 
    ++#ifndef SQLITE_SHELL_IS_UTF8
    ++#  if (defined(_WIN32) || defined(WIN32)) && defined(_MSC_VER)
    ++#    define SQLITE_SHELL_IS_UTF8          (0)
    ++#  else
    ++#    define SQLITE_SHELL_IS_UTF8          (1)
    ++#  endif
    ++#endif
    ++
    ++#if SQLITE_SHELL_IS_UTF8
    + int SQLITE_CDECL main(int argc, char **argv){
    ++#else
    ++int SQLITE_CDECL wmain(int argc, wchar_t **wargv){
    ++  char **argv;
    ++#endif
    +   char *zErrMsg = 0;
    +   ShellState data;
    +   const char *zInitFile = 0;
    +@@ -4528,24 +14989,44 @@ int SQLITE_CDECL main(int argc, char **argv){
    +   int nCmd = 0;
    +   char **azCmd = 0;
    + 
    ++  setBinaryMode(stdin, 0);
    ++  setvbuf(stderr, 0, _IONBF, 0); /* Make sure stderr is unbuffered */
    ++  stdin_is_interactive = isatty(0);
    ++  stdout_is_console = isatty(1);
    ++
    + #if USE_SYSTEM_SQLITE+0!=1
    +-  if( strcmp(sqlite3_sourceid(),SQLITE_SOURCE_ID)!=0 ){
    +-    fprintf(stderr, "SQLite header and source version mismatch\n%s\n%s\n",
    ++  if( strncmp(sqlite3_sourceid(),SQLITE_SOURCE_ID,60)!=0 ){
    ++    utf8_printf(stderr, "SQLite header and source version mismatch\n%s\n%s\n",
    +             sqlite3_sourceid(), SQLITE_SOURCE_ID);
    +     exit(1);
    +   }
    + #endif
    +-  setBinaryMode(stdin);
    +-  setvbuf(stderr, 0, _IONBF, 0); /* Make sure stderr is unbuffered */
    +-  Argv0 = argv[0];
    +   main_init(&data);
    +-  stdin_is_interactive = isatty(0);
    ++#if !SQLITE_SHELL_IS_UTF8
    ++  sqlite3_initialize();
    ++  argv = sqlite3_malloc64(sizeof(argv[0])*argc);
    ++  if( argv==0 ){
    ++    raw_printf(stderr, "out of memory\n");
    ++    exit(1);
    ++  }
    ++  for(i=0; i<argc; i++){
    ++    argv[i] = sqlite3_win32_unicode_to_utf8(wargv[i]);
    ++    if( argv[i]==0 ){
    ++      raw_printf(stderr, "out of memory\n");
    ++      exit(1);
    ++    }
    ++  }
    ++#endif
    ++  assert( argc>=1 && argv && argv[0] );
    ++  Argv0 = argv[0];
    + 
    +   /* Make sure we have a valid signal handler early, before anything
    +   ** else is done.
    +   */
    + #ifdef SIGINT
    +   signal(SIGINT, interrupt_handler);
    ++#elif (defined(_WIN32) || defined(WIN32)) && !defined(_WIN32_WCE)
    ++  SetConsoleCtrlHandler(ConsoleCtrlHandler, TRUE);
    + #endif
    + 
    + #ifdef SQLITE_SHELL_DBNAME_PROC
    +@@ -4578,7 +15059,7 @@ int SQLITE_CDECL main(int argc, char **argv){
    +         nCmd++;
    +         azCmd = realloc(azCmd, sizeof(azCmd[0])*nCmd);
    +         if( azCmd==0 ){
    +-          fprintf(stderr, "out of memory\n");
    ++          raw_printf(stderr, "out of memory\n");
    +           exit(1);
    +         }
    +         azCmd[nCmd-1] = z;
    +@@ -4595,7 +15076,7 @@ int SQLITE_CDECL main(int argc, char **argv){
    +       zInitFile = cmdline_option_value(argc, argv, ++i);
    +     }else if( strcmp(z,"-batch")==0 ){
    +       /* Need to check for batch mode here to so we can avoid printing
    +-      ** informational messages (like from process_sqliterc) before 
    ++      ** informational messages (like from process_sqliterc) before
    +       ** we do the actual processing of arguments later in a second pass.
    +       */
    +       stdin_is_interactive = 0;
    +@@ -4608,25 +15089,17 @@ int SQLITE_CDECL main(int argc, char **argv){
    +       szHeap = integerValue(zSize);
    +       if( szHeap>0x7fff0000 ) szHeap = 0x7fff0000;
    +       sqlite3_config(SQLITE_CONFIG_HEAP, malloc((int)szHeap), (int)szHeap, 64);
    ++#else
    ++      (void)cmdline_option_value(argc, argv, ++i);
    + #endif
    +-    }else if( strcmp(z,"-scratch")==0 ){
    +-      int n, sz;
    +-      sz = (int)integerValue(cmdline_option_value(argc,argv,++i));
    +-      if( sz>400000 ) sz = 400000;
    +-      if( sz<2500 ) sz = 2500;
    +-      n = (int)integerValue(cmdline_option_value(argc,argv,++i));
    +-      if( n>10 ) n = 10;
    +-      if( n<1 ) n = 1;
    +-      sqlite3_config(SQLITE_CONFIG_SCRATCH, malloc(n*sz+1), sz, n);
    +-      data.shellFlgs |= SHFLG_Scratch;
    +     }else if( strcmp(z,"-pagecache")==0 ){
    +       int n, sz;
    +       sz = (int)integerValue(cmdline_option_value(argc,argv,++i));
    +       if( sz>70000 ) sz = 70000;
    +-      if( sz<800 ) sz = 800;
    ++      if( sz<0 ) sz = 0;
    +       n = (int)integerValue(cmdline_option_value(argc,argv,++i));
    +-      if( n<10 ) n = 10;
    +-      sqlite3_config(SQLITE_CONFIG_PAGECACHE, malloc(n*sz+1), sz, n);
    ++      sqlite3_config(SQLITE_CONFIG_PAGECACHE,
    ++                    (n>0 && sz>0) ? malloc(n*sz) : 0, sz, n);
    +       data.shellFlgs |= SHFLG_Pagecache;
    +     }else if( strcmp(z,"-lookaside")==0 ){
    +       int n, sz;
    +@@ -4660,9 +15133,15 @@ int SQLITE_CDECL main(int argc, char **argv){
    +       if( pVfs ){
    +         sqlite3_vfs_register(pVfs, 1);
    +       }else{
    +-        fprintf(stderr, "no such VFS: \"%s\"\n", argv[i]);
    ++        utf8_printf(stderr, "no such VFS: \"%s\"\n", argv[i]);
    +         exit(1);
    +       }
    ++#ifdef SQLITE_HAVE_ZIP
    ++    }else if( strcmp(z,"-zip")==0 ){
    ++      data.openMode = SHELL_OPEN_ZIPFILE;
    ++#endif
    ++    }else if( strcmp(z,"-append")==0 ){
    ++      data.openMode = SHELL_OPEN_APPENDVFS;
    +     }
    +   }
    +   if( data.zDbFilename==0 ){
    +@@ -4670,11 +15149,12 @@ int SQLITE_CDECL main(int argc, char **argv){
    +     data.zDbFilename = ":memory:";
    +     warnInmemoryDb = argc==1;
    + #else
    +-    fprintf(stderr,"%s: Error: no database filename specified\n", Argv0);
    ++    utf8_printf(stderr,"%s: Error: no database filename specified\n", Argv0);
    +     return 1;
    + #endif
    +   }
    +   data.out = stdout;
    ++  sqlite3_appendvfs_init(0,0,0);
    + 
    +   /* Go ahead and open the database file if it already exists.  If the
    +   ** file does not exist, delay opening it.  This prevents empty database
    +@@ -4706,6 +15186,8 @@ int SQLITE_CDECL main(int argc, char **argv){
    +       data.mode = MODE_Html;
    +     }else if( strcmp(z,"-list")==0 ){
    +       data.mode = MODE_List;
    ++    }else if( strcmp(z,"-quote")==0 ){
    ++      data.mode = MODE_Quote;
    +     }else if( strcmp(z,"-line")==0 ){
    +       data.mode = MODE_Line;
    +     }else if( strcmp(z,"-column")==0 ){
    +@@ -4713,6 +15195,12 @@ int SQLITE_CDECL main(int argc, char **argv){
    +     }else if( strcmp(z,"-csv")==0 ){
    +       data.mode = MODE_Csv;
    +       memcpy(data.colSeparator,",",2);
    ++#ifdef SQLITE_HAVE_ZIP
    ++    }else if( strcmp(z,"-zip")==0 ){
    ++      data.openMode = SHELL_OPEN_ZIPFILE;
    ++#endif
    ++    }else if( strcmp(z,"-append")==0 ){
    ++      data.openMode = SHELL_OPEN_APPENDVFS;
    +     }else if( strcmp(z,"-ascii")==0 ){
    +       data.mode = MODE_Ascii;
    +       sqlite3_snprintf(sizeof(data.colSeparator), data.colSeparator,
    +@@ -4733,9 +15221,11 @@ int SQLITE_CDECL main(int argc, char **argv){
    +     }else if( strcmp(z,"-noheader")==0 ){
    +       data.showHeader = 0;
    +     }else if( strcmp(z,"-echo")==0 ){
    +-      data.echoOn = 1;
    ++      ShellSetFlag(&data, SHFLG_Echo);
    +     }else if( strcmp(z,"-eqp")==0 ){
    +-      data.autoEQP = 1;
    ++      data.autoEQP = AUTOEQP_on;
    ++    }else if( strcmp(z,"-eqpfull")==0 ){
    ++      data.autoEQP = AUTOEQP_full;
    +     }else if( strcmp(z,"-stats")==0 ){
    +       data.statsOn = 1;
    +     }else if( strcmp(z,"-scanstats")==0 ){
    +@@ -4746,7 +15236,7 @@ int SQLITE_CDECL main(int argc, char **argv){
    +       ** prior to sending the SQL into SQLite.  Useful for injecting
    +       ** crazy bytes in the middle of SQL statements for testing and debugging.
    +       */
    +-      data.backslashOn = 1;
    ++      ShellSetFlag(&data, SHFLG_Backslash);
    +     }else if( strcmp(z,"-bail")==0 ){
    +       bail_on_error = 1;
    +     }else if( strcmp(z,"-version")==0 ){
    +@@ -4758,8 +15248,6 @@ int SQLITE_CDECL main(int argc, char **argv){
    +       stdin_is_interactive = 0;
    +     }else if( strcmp(z,"-heap")==0 ){
    +       i++;
    +-    }else if( strcmp(z,"-scratch")==0 ){
    +-      i+=2;
    +     }else if( strcmp(z,"-pagecache")==0 ){
    +       i+=2;
    +     }else if( strcmp(z,"-lookaside")==0 ){
    +@@ -4792,18 +15280,19 @@ int SQLITE_CDECL main(int argc, char **argv){
    +         open_db(&data, 0);
    +         rc = shell_exec(data.db, z, shell_callback, &data, &zErrMsg);
    +         if( zErrMsg!=0 ){
    +-          fprintf(stderr,"Error: %s\n", zErrMsg);
    ++          utf8_printf(stderr,"Error: %s\n", zErrMsg);
    +           if( bail_on_error ) return rc!=0 ? rc : 1;
    +         }else if( rc!=0 ){
    +-          fprintf(stderr,"Error: unable to process SQL \"%s\"\n", z);
    ++          utf8_printf(stderr,"Error: unable to process SQL \"%s\"\n", z);
    +           if( bail_on_error ) return rc;
    +         }
    +       }
    +     }else{
    +-      fprintf(stderr,"%s: Error: unknown option: %s\n", Argv0, z);
    +-      fprintf(stderr,"Use -help for a list of options.\n");
    ++      utf8_printf(stderr,"%s: Error: unknown option: %s\n", Argv0, z);
    ++      raw_printf(stderr,"Use -help for a list of options.\n");
    +       return 1;
    +     }
    ++    data.cMode = data.mode;
    +   }
    + 
    +   if( !readStdin ){
    +@@ -4819,10 +15308,10 @@ int SQLITE_CDECL main(int argc, char **argv){
    +         open_db(&data, 0);
    +         rc = shell_exec(data.db, azCmd[i], shell_callback, &data, &zErrMsg);
    +         if( zErrMsg!=0 ){
    +-          fprintf(stderr,"Error: %s\n", zErrMsg);
    ++          utf8_printf(stderr,"Error: %s\n", zErrMsg);
    +           return rc!=0 ? rc : 1;
    +         }else if( rc!=0 ){
    +-          fprintf(stderr,"Error: unable to process SQL: %s\n", azCmd[i]);
    ++          utf8_printf(stderr,"Error: unable to process SQL: %s\n", azCmd[i]);
    +           return rc;
    +         }
    +       }
    +@@ -4846,7 +15335,7 @@ int SQLITE_CDECL main(int argc, char **argv){
    +         printf(".\nUse \".open FILENAME\" to reopen on a "
    +                "persistent database.\n");
    +       }
    +-      zHome = find_home_dir();
    ++      zHome = find_home_dir(0);
    +       if( zHome ){
    +         nHistory = strlen30(zHome) + 20;
    +         if( (zHistory = malloc(nHistory))!=0 ){
    +@@ -4854,9 +15343,14 @@ int SQLITE_CDECL main(int argc, char **argv){
    +         }
    +       }
    +       if( zHistory ){ shell_read_history(zHistory); }
    ++#if HAVE_READLINE || HAVE_EDITLINE
    ++      rl_attempted_completion_function = readline_completion;
    ++#elif HAVE_LINENOISE
    ++      linenoiseSetCompletionCallback(linenoise_completion);
    ++#endif
    +       rc = process_input(&data, 0);
    +       if( zHistory ){
    +-        shell_stifle_history(100);
    ++        shell_stifle_history(2000);
    +         shell_write_history(zHistory);
    +         free(zHistory);
    +       }
    +@@ -4866,8 +15360,17 @@ int SQLITE_CDECL main(int argc, char **argv){
    +   }
    +   set_table_name(&data, 0);
    +   if( data.db ){
    ++    session_close_all(&data);
    +     sqlite3_close(data.db);
    +   }
    +-  sqlite3_free(data.zFreeOnClose); 
    ++  sqlite3_free(data.zFreeOnClose);
    ++  find_home_dir(1);
    ++  output_reset(&data);
    ++  data.doXdgOpen = 0;
    ++  clearTempFile(&data);
    ++#if !SQLITE_SHELL_IS_UTF8
    ++  for(i=0; i<argc; i++) sqlite3_free(argv[i]);
    ++  sqlite3_free(argv);
    ++#endif
    +   return rc;
    + }
    +diff --git a/dist/sqlite3.c b/dist/sqlite3.c
    +index b0536a4..3322b52 100644
    +--- a/dist/sqlite3.c
    ++++ b/dist/sqlite3.c
    +@@ -1,6 +1,6 @@
    + /******************************************************************************
    + ** This file is an amalgamation of many separate C source files from SQLite
    +-** version 3.9.2.  By combining all the individual C code files into this 
    ++** version 3.22.0.  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
    +@@ -9,7 +9,7 @@
    + **
    + ** This file is all you need to compile SQLite.  To use SQLite in other
    + ** programs, you need this file and the "sqlite3.h" header file that defines
    +-** the programming interface to the SQLite library.  (If you do not have 
    ++** the programming interface to the SQLite library.  (If you do not have
    + ** the "sqlite3.h" header file at hand, you will find a copy embedded within
    + ** the text of this file.  Search for "Begin file sqlite3.h" to find the start
    + ** of the embedded sqlite3.h header file.) Additional code files may be needed
    +@@ -22,6 +22,761 @@
    + #ifndef SQLITE_PRIVATE
    + # define SQLITE_PRIVATE static
    + #endif
    ++/************** Begin file ctime.c *******************************************/
    ++/*
    ++** 2010 February 23
    ++**
    ++** 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 implements routines used to report what compile-time options
    ++** SQLite was built with.
    ++*/
    ++
    ++#ifndef SQLITE_OMIT_COMPILEOPTION_DIAGS
    ++
    ++/*
    ++** Include the configuration header output by 'configure' if we're using the
    ++** autoconf-based build
    ++*/
    ++#if defined(_HAVE_SQLITE_CONFIG_H) && !defined(SQLITECONFIG_H)
    ++#include "config.h"
    ++#define SQLITECONFIG_H 1
    ++#endif
    ++
    ++/* These macros are provided to "stringify" the value of the define
    ++** for those options in which the value is meaningful. */
    ++#define CTIMEOPT_VAL_(opt) #opt
    ++#define CTIMEOPT_VAL(opt) CTIMEOPT_VAL_(opt)
    ++
    ++/*
    ++** An array of names of all compile-time options.  This array should 
    ++** be sorted A-Z.
    ++**
    ++** This array looks large, but in a typical installation actually uses
    ++** only a handful of compile-time options, so most times this array is usually
    ++** rather short and uses little memory space.
    ++*/
    ++static const char * const sqlite3azCompileOpt[] = {
    ++
    ++/* 
    ++** BEGIN CODE GENERATED BY tool/mkctime.tcl 
    ++*/
    ++#if SQLITE_32BIT_ROWID
    ++  "32BIT_ROWID",
    ++#endif
    ++#if SQLITE_4_BYTE_ALIGNED_MALLOC
    ++  "4_BYTE_ALIGNED_MALLOC",
    ++#endif
    ++#if SQLITE_64BIT_STATS
    ++  "64BIT_STATS",
    ++#endif
    ++#if SQLITE_ALLOW_COVERING_INDEX_SCAN
    ++  "ALLOW_COVERING_INDEX_SCAN",
    ++#endif
    ++#if SQLITE_ALLOW_URI_AUTHORITY
    ++  "ALLOW_URI_AUTHORITY",
    ++#endif
    ++#ifdef SQLITE_BITMASK_TYPE
    ++  "BITMASK_TYPE=" CTIMEOPT_VAL(SQLITE_BITMASK_TYPE),
    ++#endif
    ++#if SQLITE_BUG_COMPATIBLE_20160819
    ++  "BUG_COMPATIBLE_20160819",
    ++#endif
    ++#if SQLITE_CASE_SENSITIVE_LIKE
    ++  "CASE_SENSITIVE_LIKE",
    ++#endif
    ++#if SQLITE_CHECK_PAGES
    ++  "CHECK_PAGES",
    ++#endif
    ++#if defined(__clang__) && defined(__clang_major__)
    ++  "COMPILER=clang-" CTIMEOPT_VAL(__clang_major__) "."
    ++                    CTIMEOPT_VAL(__clang_minor__) "."
    ++                    CTIMEOPT_VAL(__clang_patchlevel__),
    ++#elif defined(_MSC_VER)
    ++  "COMPILER=msvc-" CTIMEOPT_VAL(_MSC_VER),
    ++#elif defined(__GNUC__) && defined(__VERSION__)
    ++  "COMPILER=gcc-" __VERSION__,
    ++#endif
    ++#if SQLITE_COVERAGE_TEST
    ++  "COVERAGE_TEST",
    ++#endif
    ++#if SQLITE_DEBUG
    ++  "DEBUG",
    ++#endif
    ++#if SQLITE_DEFAULT_AUTOMATIC_INDEX
    ++  "DEFAULT_AUTOMATIC_INDEX",
    ++#endif
    ++#if SQLITE_DEFAULT_AUTOVACUUM
    ++  "DEFAULT_AUTOVACUUM",
    ++#endif
    ++#ifdef SQLITE_DEFAULT_CACHE_SIZE
    ++  "DEFAULT_CACHE_SIZE=" CTIMEOPT_VAL(SQLITE_DEFAULT_CACHE_SIZE),
    ++#endif
    ++#if SQLITE_DEFAULT_CKPTFULLFSYNC
    ++  "DEFAULT_CKPTFULLFSYNC",
    ++#endif
    ++#ifdef SQLITE_DEFAULT_FILE_FORMAT
    ++  "DEFAULT_FILE_FORMAT=" CTIMEOPT_VAL(SQLITE_DEFAULT_FILE_FORMAT),
    ++#endif
    ++#ifdef SQLITE_DEFAULT_FILE_PERMISSIONS
    ++  "DEFAULT_FILE_PERMISSIONS=" CTIMEOPT_VAL(SQLITE_DEFAULT_FILE_PERMISSIONS),
    ++#endif
    ++#if SQLITE_DEFAULT_FOREIGN_KEYS
    ++  "DEFAULT_FOREIGN_KEYS",
    ++#endif
    ++#ifdef SQLITE_DEFAULT_JOURNAL_SIZE_LIMIT
    ++  "DEFAULT_JOURNAL_SIZE_LIMIT=" CTIMEOPT_VAL(SQLITE_DEFAULT_JOURNAL_SIZE_LIMIT),
    ++#endif
    ++#ifdef SQLITE_DEFAULT_LOCKING_MODE
    ++  "DEFAULT_LOCKING_MODE=" CTIMEOPT_VAL(SQLITE_DEFAULT_LOCKING_MODE),
    ++#endif
    ++#ifdef SQLITE_DEFAULT_LOOKASIDE
    ++  "DEFAULT_LOOKASIDE=" CTIMEOPT_VAL(SQLITE_DEFAULT_LOOKASIDE),
    ++#endif
    ++#if SQLITE_DEFAULT_MEMSTATUS
    ++  "DEFAULT_MEMSTATUS",
    ++#endif
    ++#ifdef SQLITE_DEFAULT_MMAP_SIZE
    ++  "DEFAULT_MMAP_SIZE=" CTIMEOPT_VAL(SQLITE_DEFAULT_MMAP_SIZE),
    ++#endif
    ++#ifdef SQLITE_DEFAULT_PAGE_SIZE
    ++  "DEFAULT_PAGE_SIZE=" CTIMEOPT_VAL(SQLITE_DEFAULT_PAGE_SIZE),
    ++#endif
    ++#ifdef SQLITE_DEFAULT_PCACHE_INITSZ
    ++  "DEFAULT_PCACHE_INITSZ=" CTIMEOPT_VAL(SQLITE_DEFAULT_PCACHE_INITSZ),
    ++#endif
    ++#ifdef SQLITE_DEFAULT_PROXYDIR_PERMISSIONS
    ++  "DEFAULT_PROXYDIR_PERMISSIONS=" CTIMEOPT_VAL(SQLITE_DEFAULT_PROXYDIR_PERMISSIONS),
    ++#endif
    ++#if SQLITE_DEFAULT_RECURSIVE_TRIGGERS
    ++  "DEFAULT_RECURSIVE_TRIGGERS",
    ++#endif
    ++#ifdef SQLITE_DEFAULT_ROWEST
    ++  "DEFAULT_ROWEST=" CTIMEOPT_VAL(SQLITE_DEFAULT_ROWEST),
    ++#endif
    ++#ifdef SQLITE_DEFAULT_SECTOR_SIZE
    ++  "DEFAULT_SECTOR_SIZE=" CTIMEOPT_VAL(SQLITE_DEFAULT_SECTOR_SIZE),
    ++#endif
    ++#ifdef SQLITE_DEFAULT_SYNCHRONOUS
    ++  "DEFAULT_SYNCHRONOUS=" CTIMEOPT_VAL(SQLITE_DEFAULT_SYNCHRONOUS),
    ++#endif
    ++#ifdef SQLITE_DEFAULT_WAL_AUTOCHECKPOINT
    ++  "DEFAULT_WAL_AUTOCHECKPOINT=" CTIMEOPT_VAL(SQLITE_DEFAULT_WAL_AUTOCHECKPOINT),
    ++#endif
    ++#ifdef SQLITE_DEFAULT_WAL_SYNCHRONOUS
    ++  "DEFAULT_WAL_SYNCHRONOUS=" CTIMEOPT_VAL(SQLITE_DEFAULT_WAL_SYNCHRONOUS),
    ++#endif
    ++#ifdef SQLITE_DEFAULT_WORKER_THREADS
    ++  "DEFAULT_WORKER_THREADS=" CTIMEOPT_VAL(SQLITE_DEFAULT_WORKER_THREADS),
    ++#endif
    ++#if SQLITE_DIRECT_OVERFLOW_READ
    ++  "DIRECT_OVERFLOW_READ",
    ++#endif
    ++#if SQLITE_DISABLE_DIRSYNC
    ++  "DISABLE_DIRSYNC",
    ++#endif
    ++#if SQLITE_DISABLE_FTS3_UNICODE
    ++  "DISABLE_FTS3_UNICODE",
    ++#endif
    ++#if SQLITE_DISABLE_FTS4_DEFERRED
    ++  "DISABLE_FTS4_DEFERRED",
    ++#endif
    ++#if SQLITE_DISABLE_INTRINSIC
    ++  "DISABLE_INTRINSIC",
    ++#endif
    ++#if SQLITE_DISABLE_LFS
    ++  "DISABLE_LFS",
    ++#endif
    ++#if SQLITE_DISABLE_PAGECACHE_OVERFLOW_STATS
    ++  "DISABLE_PAGECACHE_OVERFLOW_STATS",
    ++#endif
    ++#if SQLITE_DISABLE_SKIPAHEAD_DISTINCT
    ++  "DISABLE_SKIPAHEAD_DISTINCT",
    ++#endif
    ++#ifdef SQLITE_ENABLE_8_3_NAMES
    ++  "ENABLE_8_3_NAMES=" CTIMEOPT_VAL(SQLITE_ENABLE_8_3_NAMES),
    ++#endif
    ++#if SQLITE_ENABLE_API_ARMOR
    ++  "ENABLE_API_ARMOR",
    ++#endif
    ++#if SQLITE_ENABLE_ATOMIC_WRITE
    ++  "ENABLE_ATOMIC_WRITE",
    ++#endif
    ++#if SQLITE_ENABLE_BATCH_ATOMIC_WRITE
    ++  "ENABLE_BATCH_ATOMIC_WRITE",
    ++#endif
    ++#if SQLITE_ENABLE_CEROD
    ++  "ENABLE_CEROD",
    ++#endif
    ++#if SQLITE_ENABLE_COLUMN_METADATA
    ++  "ENABLE_COLUMN_METADATA",
    ++#endif
    ++#if SQLITE_ENABLE_COLUMN_USED_MASK
    ++  "ENABLE_COLUMN_USED_MASK",
    ++#endif
    ++#if SQLITE_ENABLE_COSTMULT
    ++  "ENABLE_COSTMULT",
    ++#endif
    ++#if SQLITE_ENABLE_CURSOR_HINTS
    ++  "ENABLE_CURSOR_HINTS",
    ++#endif
    ++#if SQLITE_ENABLE_DBSTAT_VTAB
    ++  "ENABLE_DBSTAT_VTAB",
    ++#endif
    ++#if SQLITE_ENABLE_EXPENSIVE_ASSERT
    ++  "ENABLE_EXPENSIVE_ASSERT",
    ++#endif
    ++#if SQLITE_ENABLE_FTS1
    ++  "ENABLE_FTS1",
    ++#endif
    ++#if SQLITE_ENABLE_FTS2
    ++  "ENABLE_FTS2",
    ++#endif
    ++#if SQLITE_ENABLE_FTS3
    ++  "ENABLE_FTS3",
    ++#endif
    ++#if SQLITE_ENABLE_FTS3_PARENTHESIS
    ++  "ENABLE_FTS3_PARENTHESIS",
    ++#endif
    ++#if SQLITE_ENABLE_FTS3_TOKENIZER
    ++  "ENABLE_FTS3_TOKENIZER",
    ++#endif
    ++#if SQLITE_ENABLE_FTS4
    ++  "ENABLE_FTS4",
    ++#endif
    ++#if SQLITE_ENABLE_FTS5
    ++  "ENABLE_FTS5",
    ++#endif
    ++#if SQLITE_ENABLE_HIDDEN_COLUMNS
    ++  "ENABLE_HIDDEN_COLUMNS",
    ++#endif
    ++#if SQLITE_ENABLE_ICU
    ++  "ENABLE_ICU",
    ++#endif
    ++#if SQLITE_ENABLE_IOTRACE
    ++  "ENABLE_IOTRACE",
    ++#endif
    ++#if SQLITE_ENABLE_JSON1
    ++  "ENABLE_JSON1",
    ++#endif
    ++#if SQLITE_ENABLE_LOAD_EXTENSION
    ++  "ENABLE_LOAD_EXTENSION",
    ++#endif
    ++#ifdef SQLITE_ENABLE_LOCKING_STYLE
    ++  "ENABLE_LOCKING_STYLE=" CTIMEOPT_VAL(SQLITE_ENABLE_LOCKING_STYLE),
    ++#endif
    ++#if SQLITE_ENABLE_MEMORY_MANAGEMENT
    ++  "ENABLE_MEMORY_MANAGEMENT",
    ++#endif
    ++#if SQLITE_ENABLE_MEMSYS3
    ++  "ENABLE_MEMSYS3",
    ++#endif
    ++#if SQLITE_ENABLE_MEMSYS5
    ++  "ENABLE_MEMSYS5",
    ++#endif
    ++#if SQLITE_ENABLE_MULTIPLEX
    ++  "ENABLE_MULTIPLEX",
    ++#endif
    ++#if SQLITE_ENABLE_NULL_TRIM
    ++  "ENABLE_NULL_TRIM",
    ++#endif
    ++#if SQLITE_ENABLE_OVERSIZE_CELL_CHECK
    ++  "ENABLE_OVERSIZE_CELL_CHECK",
    ++#endif
    ++#if SQLITE_ENABLE_PREUPDATE_HOOK
    ++  "ENABLE_PREUPDATE_HOOK",
    ++#endif
    ++#if SQLITE_ENABLE_QPSG
    ++  "ENABLE_QPSG",
    ++#endif
    ++#if SQLITE_ENABLE_RBU
    ++  "ENABLE_RBU",
    ++#endif
    ++#if SQLITE_ENABLE_RTREE
    ++  "ENABLE_RTREE",
    ++#endif
    ++#if SQLITE_ENABLE_SELECTTRACE
    ++  "ENABLE_SELECTTRACE",
    ++#endif
    ++#if SQLITE_ENABLE_SESSION
    ++  "ENABLE_SESSION",
    ++#endif
    ++#if SQLITE_ENABLE_SNAPSHOT
    ++  "ENABLE_SNAPSHOT",
    ++#endif
    ++#if SQLITE_ENABLE_SQLLOG
    ++  "ENABLE_SQLLOG",
    ++#endif
    ++#if defined(SQLITE_ENABLE_STAT4)
    ++  "ENABLE_STAT4",
    ++#elif defined(SQLITE_ENABLE_STAT3)
    ++  "ENABLE_STAT3",
    ++#endif
    ++#if SQLITE_ENABLE_STMTVTAB
    ++  "ENABLE_STMTVTAB",
    ++#endif
    ++#if SQLITE_ENABLE_STMT_SCANSTATUS
    ++  "ENABLE_STMT_SCANSTATUS",
    ++#endif
    ++#if SQLITE_ENABLE_UNKNOWN_SQL_FUNCTION
    ++  "ENABLE_UNKNOWN_SQL_FUNCTION",
    ++#endif
    ++#if SQLITE_ENABLE_UNLOCK_NOTIFY
    ++  "ENABLE_UNLOCK_NOTIFY",
    ++#endif
    ++#if SQLITE_ENABLE_UPDATE_DELETE_LIMIT
    ++  "ENABLE_UPDATE_DELETE_LIMIT",
    ++#endif
    ++#if SQLITE_ENABLE_URI_00_ERROR
    ++  "ENABLE_URI_00_ERROR",
    ++#endif
    ++#if SQLITE_ENABLE_VFSTRACE
    ++  "ENABLE_VFSTRACE",
    ++#endif
    ++#if SQLITE_ENABLE_WHERETRACE
    ++  "ENABLE_WHERETRACE",
    ++#endif
    ++#if SQLITE_ENABLE_ZIPVFS
    ++  "ENABLE_ZIPVFS",
    ++#endif
    ++#if SQLITE_EXPLAIN_ESTIMATED_ROWS
    ++  "EXPLAIN_ESTIMATED_ROWS",
    ++#endif
    ++#if SQLITE_EXTRA_IFNULLROW
    ++  "EXTRA_IFNULLROW",
    ++#endif
    ++#ifdef SQLITE_EXTRA_INIT
    ++  "EXTRA_INIT=" CTIMEOPT_VAL(SQLITE_EXTRA_INIT),
    ++#endif
    ++#ifdef SQLITE_EXTRA_SHUTDOWN
    ++  "EXTRA_SHUTDOWN=" CTIMEOPT_VAL(SQLITE_EXTRA_SHUTDOWN),
    ++#endif
    ++#ifdef SQLITE_FTS3_MAX_EXPR_DEPTH
    ++  "FTS3_MAX_EXPR_DEPTH=" CTIMEOPT_VAL(SQLITE_FTS3_MAX_EXPR_DEPTH),
    ++#endif
    ++#if SQLITE_FTS5_ENABLE_TEST_MI
    ++  "FTS5_ENABLE_TEST_MI",
    ++#endif
    ++#if SQLITE_FTS5_NO_WITHOUT_ROWID
    ++  "FTS5_NO_WITHOUT_ROWID",
    ++#endif
    ++#if SQLITE_HAS_CODEC
    ++  "HAS_CODEC",
    ++#endif
    ++#if HAVE_ISNAN || SQLITE_HAVE_ISNAN
    ++  "HAVE_ISNAN",
    ++#endif
    ++#if SQLITE_HOMEGROWN_RECURSIVE_MUTEX
    ++  "HOMEGROWN_RECURSIVE_MUTEX",
    ++#endif
    ++#if SQLITE_IGNORE_AFP_LOCK_ERRORS
    ++  "IGNORE_AFP_LOCK_ERRORS",
    ++#endif
    ++#if SQLITE_IGNORE_FLOCK_LOCK_ERRORS
    ++  "IGNORE_FLOCK_LOCK_ERRORS",
    ++#endif
    ++#if SQLITE_INLINE_MEMCPY
    ++  "INLINE_MEMCPY",
    ++#endif
    ++#if SQLITE_INT64_TYPE
    ++  "INT64_TYPE",
    ++#endif
    ++#ifdef SQLITE_INTEGRITY_CHECK_ERROR_MAX
    ++  "INTEGRITY_CHECK_ERROR_MAX=" CTIMEOPT_VAL(SQLITE_INTEGRITY_CHECK_ERROR_MAX),
    ++#endif
    ++#if SQLITE_LIKE_DOESNT_MATCH_BLOBS
    ++  "LIKE_DOESNT_MATCH_BLOBS",
    ++#endif
    ++#if SQLITE_LOCK_TRACE
    ++  "LOCK_TRACE",
    ++#endif
    ++#if SQLITE_LOG_CACHE_SPILL
    ++  "LOG_CACHE_SPILL",
    ++#endif
    ++#ifdef SQLITE_MALLOC_SOFT_LIMIT
    ++  "MALLOC_SOFT_LIMIT=" CTIMEOPT_VAL(SQLITE_MALLOC_SOFT_LIMIT),
    ++#endif
    ++#ifdef SQLITE_MAX_ATTACHED
    ++  "MAX_ATTACHED=" CTIMEOPT_VAL(SQLITE_MAX_ATTACHED),
    ++#endif
    ++#ifdef SQLITE_MAX_COLUMN
    ++  "MAX_COLUMN=" CTIMEOPT_VAL(SQLITE_MAX_COLUMN),
    ++#endif
    ++#ifdef SQLITE_MAX_COMPOUND_SELECT
    ++  "MAX_COMPOUND_SELECT=" CTIMEOPT_VAL(SQLITE_MAX_COMPOUND_SELECT),
    ++#endif
    ++#ifdef SQLITE_MAX_DEFAULT_PAGE_SIZE
    ++  "MAX_DEFAULT_PAGE_SIZE=" CTIMEOPT_VAL(SQLITE_MAX_DEFAULT_PAGE_SIZE),
    ++#endif
    ++#ifdef SQLITE_MAX_EXPR_DEPTH
    ++  "MAX_EXPR_DEPTH=" CTIMEOPT_VAL(SQLITE_MAX_EXPR_DEPTH),
    ++#endif
    ++#ifdef SQLITE_MAX_FUNCTION_ARG
    ++  "MAX_FUNCTION_ARG=" CTIMEOPT_VAL(SQLITE_MAX_FUNCTION_ARG),
    ++#endif
    ++#ifdef SQLITE_MAX_LENGTH
    ++  "MAX_LENGTH=" CTIMEOPT_VAL(SQLITE_MAX_LENGTH),
    ++#endif
    ++#ifdef SQLITE_MAX_LIKE_PATTERN_LENGTH
    ++  "MAX_LIKE_PATTERN_LENGTH=" CTIMEOPT_VAL(SQLITE_MAX_LIKE_PATTERN_LENGTH),
    ++#endif
    ++#ifdef SQLITE_MAX_MEMORY
    ++  "MAX_MEMORY=" CTIMEOPT_VAL(SQLITE_MAX_MEMORY),
    ++#endif
    ++#ifdef SQLITE_MAX_MMAP_SIZE
    ++  "MAX_MMAP_SIZE=" CTIMEOPT_VAL(SQLITE_MAX_MMAP_SIZE),
    ++#endif
    ++#ifdef SQLITE_MAX_MMAP_SIZE_
    ++  "MAX_MMAP_SIZE_=" CTIMEOPT_VAL(SQLITE_MAX_MMAP_SIZE_),
    ++#endif
    ++#ifdef SQLITE_MAX_PAGE_COUNT
    ++  "MAX_PAGE_COUNT=" CTIMEOPT_VAL(SQLITE_MAX_PAGE_COUNT),
    ++#endif
    ++#ifdef SQLITE_MAX_PAGE_SIZE
    ++  "MAX_PAGE_SIZE=" CTIMEOPT_VAL(SQLITE_MAX_PAGE_SIZE),
    ++#endif
    ++#ifdef SQLITE_MAX_SCHEMA_RETRY
    ++  "MAX_SCHEMA_RETRY=" CTIMEOPT_VAL(SQLITE_MAX_SCHEMA_RETRY),
    ++#endif
    ++#ifdef SQLITE_MAX_SQL_LENGTH
    ++  "MAX_SQL_LENGTH=" CTIMEOPT_VAL(SQLITE_MAX_SQL_LENGTH),
    ++#endif
    ++#ifdef SQLITE_MAX_TRIGGER_DEPTH
    ++  "MAX_TRIGGER_DEPTH=" CTIMEOPT_VAL(SQLITE_MAX_TRIGGER_DEPTH),
    ++#endif
    ++#ifdef SQLITE_MAX_VARIABLE_NUMBER
    ++  "MAX_VARIABLE_NUMBER=" CTIMEOPT_VAL(SQLITE_MAX_VARIABLE_NUMBER),
    ++#endif
    ++#ifdef SQLITE_MAX_VDBE_OP
    ++  "MAX_VDBE_OP=" CTIMEOPT_VAL(SQLITE_MAX_VDBE_OP),
    ++#endif
    ++#ifdef SQLITE_MAX_WORKER_THREADS
    ++  "MAX_WORKER_THREADS=" CTIMEOPT_VAL(SQLITE_MAX_WORKER_THREADS),
    ++#endif
    ++#if SQLITE_MEMDEBUG
    ++  "MEMDEBUG",
    ++#endif
    ++#if SQLITE_MIXED_ENDIAN_64BIT_FLOAT
    ++  "MIXED_ENDIAN_64BIT_FLOAT",
    ++#endif
    ++#if SQLITE_MMAP_READWRITE
    ++  "MMAP_READWRITE",
    ++#endif
    ++#if SQLITE_MUTEX_NOOP
    ++  "MUTEX_NOOP",
    ++#endif
    ++#if SQLITE_MUTEX_NREF
    ++  "MUTEX_NREF",
    ++#endif
    ++#if SQLITE_MUTEX_OMIT
    ++  "MUTEX_OMIT",
    ++#endif
    ++#if SQLITE_MUTEX_PTHREADS
    ++  "MUTEX_PTHREADS",
    ++#endif
    ++#if SQLITE_MUTEX_W32
    ++  "MUTEX_W32",
    ++#endif
    ++#if SQLITE_NEED_ERR_NAME
    ++  "NEED_ERR_NAME",
    ++#endif
    ++#if SQLITE_NOINLINE
    ++  "NOINLINE",
    ++#endif
    ++#if SQLITE_NO_SYNC
    ++  "NO_SYNC",
    ++#endif
    ++#if SQLITE_OMIT_ALTERTABLE
    ++  "OMIT_ALTERTABLE",
    ++#endif
    ++#if SQLITE_OMIT_ANALYZE
    ++  "OMIT_ANALYZE",
    ++#endif
    ++#if SQLITE_OMIT_ATTACH
    ++  "OMIT_ATTACH",
    ++#endif
    ++#if SQLITE_OMIT_AUTHORIZATION
    ++  "OMIT_AUTHORIZATION",
    ++#endif
    ++#if SQLITE_OMIT_AUTOINCREMENT
    ++  "OMIT_AUTOINCREMENT",
    ++#endif
    ++#if SQLITE_OMIT_AUTOINIT
    ++  "OMIT_AUTOINIT",
    ++#endif
    ++#if SQLITE_OMIT_AUTOMATIC_INDEX
    ++  "OMIT_AUTOMATIC_INDEX",
    ++#endif
    ++#if SQLITE_OMIT_AUTORESET
    ++  "OMIT_AUTORESET",
    ++#endif
    ++#if SQLITE_OMIT_AUTOVACUUM
    ++  "OMIT_AUTOVACUUM",
    ++#endif
    ++#if SQLITE_OMIT_BETWEEN_OPTIMIZATION
    ++  "OMIT_BETWEEN_OPTIMIZATION",
    ++#endif
    ++#if SQLITE_OMIT_BLOB_LITERAL
    ++  "OMIT_BLOB_LITERAL",
    ++#endif
    ++#if SQLITE_OMIT_BTREECOUNT
    ++  "OMIT_BTREECOUNT",
    ++#endif
    ++#if SQLITE_OMIT_CAST
    ++  "OMIT_CAST",
    ++#endif
    ++#if SQLITE_OMIT_CHECK
    ++  "OMIT_CHECK",
    ++#endif
    ++#if SQLITE_OMIT_COMPLETE
    ++  "OMIT_COMPLETE",
    ++#endif
    ++#if SQLITE_OMIT_COMPOUND_SELECT
    ++  "OMIT_COMPOUND_SELECT",
    ++#endif
    ++#if SQLITE_OMIT_CONFLICT_CLAUSE
    ++  "OMIT_CONFLICT_CLAUSE",
    ++#endif
    ++#if SQLITE_OMIT_CTE
    ++  "OMIT_CTE",
    ++#endif
    ++#if SQLITE_OMIT_DATETIME_FUNCS
    ++  "OMIT_DATETIME_FUNCS",
    ++#endif
    ++#if SQLITE_OMIT_DECLTYPE
    ++  "OMIT_DECLTYPE",
    ++#endif
    ++#if SQLITE_OMIT_DEPRECATED
    ++  "OMIT_DEPRECATED",
    ++#endif
    ++#if SQLITE_OMIT_DISKIO
    ++  "OMIT_DISKIO",
    ++#endif
    ++#if SQLITE_OMIT_EXPLAIN
    ++  "OMIT_EXPLAIN",
    ++#endif
    ++#if SQLITE_OMIT_FLAG_PRAGMAS
    ++  "OMIT_FLAG_PRAGMAS",
    ++#endif
    ++#if SQLITE_OMIT_FLOATING_POINT
    ++  "OMIT_FLOATING_POINT",
    ++#endif
    ++#if SQLITE_OMIT_FOREIGN_KEY
    ++  "OMIT_FOREIGN_KEY",
    ++#endif
    ++#if SQLITE_OMIT_GET_TABLE
    ++  "OMIT_GET_TABLE",
    ++#endif
    ++#if SQLITE_OMIT_HEX_INTEGER
    ++  "OMIT_HEX_INTEGER",
    ++#endif
    ++#if SQLITE_OMIT_INCRBLOB
    ++  "OMIT_INCRBLOB",
    ++#endif
    ++#if SQLITE_OMIT_INTEGRITY_CHECK
    ++  "OMIT_INTEGRITY_CHECK",
    ++#endif
    ++#if SQLITE_OMIT_LIKE_OPTIMIZATION
    ++  "OMIT_LIKE_OPTIMIZATION",
    ++#endif
    ++#if SQLITE_OMIT_LOAD_EXTENSION
    ++  "OMIT_LOAD_EXTENSION",
    ++#endif
    ++#if SQLITE_OMIT_LOCALTIME
    ++  "OMIT_LOCALTIME",
    ++#endif
    ++#if SQLITE_OMIT_LOOKASIDE
    ++  "OMIT_LOOKASIDE",
    ++#endif
    ++#if SQLITE_OMIT_MEMORYDB
    ++  "OMIT_MEMORYDB",
    ++#endif
    ++#if SQLITE_OMIT_OR_OPTIMIZATION
    ++  "OMIT_OR_OPTIMIZATION",
    ++#endif
    ++#if SQLITE_OMIT_PAGER_PRAGMAS
    ++  "OMIT_PAGER_PRAGMAS",
    ++#endif
    ++#if SQLITE_OMIT_PARSER_TRACE
    ++  "OMIT_PARSER_TRACE",
    ++#endif
    ++#if SQLITE_OMIT_POPEN
    ++  "OMIT_POPEN",
    ++#endif
    ++#if SQLITE_OMIT_PRAGMA
    ++  "OMIT_PRAGMA",
    ++#endif
    ++#if SQLITE_OMIT_PROGRESS_CALLBACK
    ++  "OMIT_PROGRESS_CALLBACK",
    ++#endif
    ++#if SQLITE_OMIT_QUICKBALANCE
    ++  "OMIT_QUICKBALANCE",
    ++#endif
    ++#if SQLITE_OMIT_REINDEX
    ++  "OMIT_REINDEX",
    ++#endif
    ++#if SQLITE_OMIT_SCHEMA_PRAGMAS
    ++  "OMIT_SCHEMA_PRAGMAS",
    ++#endif
    ++#if SQLITE_OMIT_SCHEMA_VERSION_PRAGMAS
    ++  "OMIT_SCHEMA_VERSION_PRAGMAS",
    ++#endif
    ++#if SQLITE_OMIT_SHARED_CACHE
    ++  "OMIT_SHARED_CACHE",
    ++#endif
    ++#if SQLITE_OMIT_SHUTDOWN_DIRECTORIES
    ++  "OMIT_SHUTDOWN_DIRECTORIES",
    ++#endif
    ++#if SQLITE_OMIT_SUBQUERY
    ++  "OMIT_SUBQUERY",
    ++#endif
    ++#if SQLITE_OMIT_TCL_VARIABLE
    ++  "OMIT_TCL_VARIABLE",
    ++#endif
    ++#if SQLITE_OMIT_TEMPDB
    ++  "OMIT_TEMPDB",
    ++#endif
    ++#if SQLITE_OMIT_TEST_CONTROL
    ++  "OMIT_TEST_CONTROL",
    ++#endif
    ++#if SQLITE_OMIT_TRACE
    ++  "OMIT_TRACE",
    ++#endif
    ++#if SQLITE_OMIT_TRIGGER
    ++  "OMIT_TRIGGER",
    ++#endif
    ++#if SQLITE_OMIT_TRUNCATE_OPTIMIZATION
    ++  "OMIT_TRUNCATE_OPTIMIZATION",
    ++#endif
    ++#if SQLITE_OMIT_UTF16
    ++  "OMIT_UTF16",
    ++#endif
    ++#if SQLITE_OMIT_VACUUM
    ++  "OMIT_VACUUM",
    ++#endif
    ++#if SQLITE_OMIT_VIEW
    ++  "OMIT_VIEW",
    ++#endif
    ++#if SQLITE_OMIT_VIRTUALTABLE
    ++  "OMIT_VIRTUALTABLE",
    ++#endif
    ++#if SQLITE_OMIT_WAL
    ++  "OMIT_WAL",
    ++#endif
    ++#if SQLITE_OMIT_WSD
    ++  "OMIT_WSD",
    ++#endif
    ++#if SQLITE_OMIT_XFER_OPT
    ++  "OMIT_XFER_OPT",
    ++#endif
    ++#if SQLITE_PCACHE_SEPARATE_HEADER
    ++  "PCACHE_SEPARATE_HEADER",
    ++#endif
    ++#if SQLITE_PERFORMANCE_TRACE
    ++  "PERFORMANCE_TRACE",
    ++#endif
    ++#if SQLITE_POWERSAFE_OVERWRITE
    ++  "POWERSAFE_OVERWRITE",
    ++#endif
    ++#if SQLITE_PREFER_PROXY_LOCKING
    ++  "PREFER_PROXY_LOCKING",
    ++#endif
    ++#if SQLITE_PROXY_DEBUG
    ++  "PROXY_DEBUG",
    ++#endif
    ++#if SQLITE_REVERSE_UNORDERED_SELECTS
    ++  "REVERSE_UNORDERED_SELECTS",
    ++#endif
    ++#if SQLITE_RTREE_INT_ONLY
    ++  "RTREE_INT_ONLY",
    ++#endif
    ++#if SQLITE_SECURE_DELETE
    ++  "SECURE_DELETE",
    ++#endif
    ++#if SQLITE_SMALL_STACK
    ++  "SMALL_STACK",
    ++#endif
    ++#ifdef SQLITE_SORTER_PMASZ
    ++  "SORTER_PMASZ=" CTIMEOPT_VAL(SQLITE_SORTER_PMASZ),
    ++#endif
    ++#if SQLITE_SOUNDEX
    ++  "SOUNDEX",
    ++#endif
    ++#ifdef SQLITE_STAT4_SAMPLES
    ++  "STAT4_SAMPLES=" CTIMEOPT_VAL(SQLITE_STAT4_SAMPLES),
    ++#endif
    ++#ifdef SQLITE_STMTJRNL_SPILL
    ++  "STMTJRNL_SPILL=" CTIMEOPT_VAL(SQLITE_STMTJRNL_SPILL),
    ++#endif
    ++#if SQLITE_SUBSTR_COMPATIBILITY
    ++  "SUBSTR_COMPATIBILITY",
    ++#endif
    ++#if SQLITE_SYSTEM_MALLOC
    ++  "SYSTEM_MALLOC",
    ++#endif
    ++#if SQLITE_TCL
    ++  "TCL",
    ++#endif
    ++#ifdef SQLITE_TEMP_STORE
    ++  "TEMP_STORE=" CTIMEOPT_VAL(SQLITE_TEMP_STORE),
    ++#endif
    ++#if SQLITE_TEST
    ++  "TEST",
    ++#endif
    ++#if defined(SQLITE_THREADSAFE)
    ++  "THREADSAFE=" CTIMEOPT_VAL(SQLITE_THREADSAFE),
    ++#elif defined(THREADSAFE)
    ++  "THREADSAFE=" CTIMEOPT_VAL(THREADSAFE),
    ++#else
    ++  "THREADSAFE=1",
    ++#endif
    ++#if SQLITE_UNLINK_AFTER_CLOSE
    ++  "UNLINK_AFTER_CLOSE",
    ++#endif
    ++#if SQLITE_UNTESTABLE
    ++  "UNTESTABLE",
    ++#endif
    ++#if SQLITE_USER_AUTHENTICATION
    ++  "USER_AUTHENTICATION",
    ++#endif
    ++#if SQLITE_USE_ALLOCA
    ++  "USE_ALLOCA",
    ++#endif
    ++#if SQLITE_USE_FCNTL_TRACE
    ++  "USE_FCNTL_TRACE",
    ++#endif
    ++#if SQLITE_USE_URI
    ++  "USE_URI",
    ++#endif
    ++#if SQLITE_VDBE_COVERAGE
    ++  "VDBE_COVERAGE",
    ++#endif
    ++#if SQLITE_WIN32_MALLOC
    ++  "WIN32_MALLOC",
    ++#endif
    ++#if SQLITE_ZERO_MALLOC
    ++  "ZERO_MALLOC",
    ++#endif
    ++/* 
    ++** END CODE GENERATED BY tool/mkctime.tcl 
    ++*/
    ++};
    ++
    ++SQLITE_PRIVATE const char **sqlite3CompileOptions(int *pnOpt){
    ++  *pnOpt = sizeof(sqlite3azCompileOpt) / sizeof(sqlite3azCompileOpt[0]);
    ++  return (const char**)sqlite3azCompileOpt;
    ++}
    ++
    ++#endif /* SQLITE_OMIT_COMPILEOPTION_DIAGS */
    ++
    ++/************** End of ctime.c ***********************************************/
    + /************** Begin file sqliteInt.h ***************************************/
    + /*
    + ** 2001 September 15
    +@@ -37,8 +792,43 @@
    + ** Internal interface definitions for SQLite.
    + **
    + */
    +-#ifndef _SQLITEINT_H_
    +-#define _SQLITEINT_H_
    ++#ifndef SQLITEINT_H
    ++#define SQLITEINT_H
    ++
    ++/* Special Comments:
    ++**
    ++** Some comments have special meaning to the tools that measure test
    ++** coverage:
    ++**
    ++**    NO_TEST                     - The branches on this line are not
    ++**                                  measured by branch coverage.  This is
    ++**                                  used on lines of code that actually
    ++**                                  implement parts of coverage testing.
    ++**
    ++**    OPTIMIZATION-IF-TRUE        - This branch is allowed to alway be false
    ++**                                  and the correct answer is still obtained,
    ++**                                  though perhaps more slowly.
    ++**
    ++**    OPTIMIZATION-IF-FALSE       - This branch is allowed to alway be true
    ++**                                  and the correct answer is still obtained,
    ++**                                  though perhaps more slowly.
    ++**
    ++**    PREVENTS-HARMLESS-OVERREAD  - This branch prevents a buffer overread
    ++**                                  that would be harmless and undetectable
    ++**                                  if it did occur.  
    ++**
    ++** In all cases, the special comment must be enclosed in the usual
    ++** slash-asterisk...asterisk-slash comment marks, with no spaces between the 
    ++** asterisks and the comment text.
    ++*/
    ++
    ++/*
    ++** Make sure the Tcl calling convention macro is defined.  This macro is
    ++** only used by test code and Tcl integration code.
    ++*/
    ++#ifndef SQLITE_TCLAPI
    ++#  define SQLITE_TCLAPI
    ++#endif
    + 
    + /*
    + ** Include the header file used to customize the compiler options for MSVC.
    +@@ -62,8 +852,8 @@
    + **
    + ** This file contains code that is specific to MSVC.
    + */
    +-#ifndef _MSVC_H_
    +-#define _MSVC_H_
    ++#ifndef SQLITE_MSVC_H
    ++#define SQLITE_MSVC_H
    + 
    + #if defined(_MSC_VER)
    + #pragma warning(disable : 4054)
    +@@ -83,7 +873,7 @@
    + #pragma warning(disable : 4706)
    + #endif /* defined(_MSC_VER) */
    + 
    +-#endif /* _MSVC_H_ */
    ++#endif /* SQLITE_MSVC_H */
    + 
    + /************** End of msvc.h ************************************************/
    + /************** Continuing where we left off in sqliteInt.h ******************/
    +@@ -121,6 +911,9 @@
    + #else
    + /* This is not VxWorks. */
    + #define OS_VXWORKS 0
    ++#define HAVE_FCHOWN 1
    ++#define HAVE_READLINK 1
    ++#define HAVE_LSTAT 1
    + #endif /* defined(_WRS_KERNEL) */
    + 
    + /************** End of vxworks.h *********************************************/
    +@@ -158,12 +951,29 @@
    + # define _LARGEFILE_SOURCE 1
    + #endif
    + 
    +-/* What version of GCC is being used.  0 means GCC is not being used */
    +-#ifdef __GNUC__
    ++/* The GCC_VERSION and MSVC_VERSION macros are used to
    ++** conditionally include optimizations for each of these compilers.  A
    ++** value of 0 means that compiler is not being used.  The
    ++** SQLITE_DISABLE_INTRINSIC macro means do not use any compiler-specific
    ++** optimizations, and hence set all compiler macros to 0
    ++**
    ++** There was once also a CLANG_VERSION macro.  However, we learn that the
    ++** version numbers in clang are for "marketing" only and are inconsistent
    ++** and unreliable.  Fortunately, all versions of clang also recognize the
    ++** gcc version numbers and have reasonable settings for gcc version numbers,
    ++** so the GCC_VERSION macro will be set to a correct non-zero value even
    ++** when compiling with clang.
    ++*/
    ++#if defined(__GNUC__) && !defined(SQLITE_DISABLE_INTRINSIC)
    + # define GCC_VERSION (__GNUC__*1000000+__GNUC_MINOR__*1000+__GNUC_PATCHLEVEL__)
    + #else
    + # define GCC_VERSION 0
    + #endif
    ++#if defined(_MSC_VER) && !defined(SQLITE_DISABLE_INTRINSIC)
    ++# define MSVC_VERSION _MSC_VER
    ++#else
    ++# define MSVC_VERSION 0
    ++#endif
    + 
    + /* Needed for various definitions... */
    + #if defined(__GNUC__) && !defined(_GNU_SOURCE)
    +@@ -213,7 +1023,7 @@
    + /************** Include sqlite3.h in the middle of sqliteInt.h ***************/
    + /************** Begin file sqlite3.h *****************************************/
    + /*
    +-** 2001 September 15
    ++** 2001-09-15
    + **
    + ** The author disclaims copyright to this source code.  In place of
    + ** a legal notice, here is a blessing:
    +@@ -244,8 +1054,8 @@
    + ** the version number) and changes its name to "sqlite3.h" as
    + ** part of the build process.
    + */
    +-#ifndef _SQLITE3_H_
    +-#define _SQLITE3_H_
    ++#ifndef SQLITE3_H
    ++#define SQLITE3_H
    + #include <stdarg.h>     /* Needed for the definition of va_list */
    + 
    + /*
    +@@ -268,8 +1078,17 @@ extern "C" {
    + #ifndef SQLITE_CDECL
    + # define SQLITE_CDECL
    + #endif
    ++#ifndef SQLITE_APICALL
    ++# define SQLITE_APICALL
    ++#endif
    + #ifndef SQLITE_STDCALL
    +-# define SQLITE_STDCALL
    ++# define SQLITE_STDCALL SQLITE_APICALL
    ++#endif
    ++#ifndef SQLITE_CALLBACK
    ++# define SQLITE_CALLBACK
    ++#endif
    ++#ifndef SQLITE_SYSAPI
    ++# define SQLITE_SYSAPI
    + #endif
    + 
    + /*
    +@@ -313,25 +1132,28 @@ extern "C" {
    + ** be held constant and Z will be incremented or else Y will be incremented
    + ** and Z will be reset to zero.
    + **
    +-** Since version 3.6.18, SQLite source code has been stored in the
    ++** Since [version 3.6.18] ([dateof:3.6.18]), 
    ++** SQLite source code has been stored in the
    + ** <a href="http://www.fossil-scm.org/">Fossil configuration management
    + ** system</a>.  ^The SQLITE_SOURCE_ID macro evaluates to
    + ** a string which identifies a particular check-in of SQLite
    + ** within its configuration management system.  ^The SQLITE_SOURCE_ID
    +-** string contains the date and time of the check-in (UTC) and an SHA1
    +-** hash of the entire source tree.
    ++** string contains the date and time of the check-in (UTC) and a SHA1
    ++** or SHA3-256 hash of the entire source tree.  If the source code has
    ++** been edited in any way since it was last checked in, then the last
    ++** four hexadecimal digits of the hash may be modified.
    + **
    + ** See also: [sqlite3_libversion()],
    + ** [sqlite3_libversion_number()], [sqlite3_sourceid()],
    + ** [sqlite_version()] and [sqlite_source_id()].
    + */
    +-#define SQLITE_VERSION        "3.9.2"
    +-#define SQLITE_VERSION_NUMBER 3009002
    +-#define SQLITE_SOURCE_ID      "2015-11-02 18:31:45 bda77dda9697c463c3d0704014d51627fceee328"
    ++#define SQLITE_VERSION        "3.22.0"
    ++#define SQLITE_VERSION_NUMBER 3022000
    ++#define SQLITE_SOURCE_ID      "2018-12-19 01:30:22 c255889bd95bd5430dc7ced3317011ae2abb483d6c9af883af3dc7d6c2c2f234"
    + 
    + /*
    + ** CAPI3REF: Run-Time Library Version Numbers
    +-** KEYWORDS: sqlite3_version, sqlite3_sourceid
    ++** KEYWORDS: sqlite3_version sqlite3_sourceid
    + **
    + ** These interfaces provide the same information as the [SQLITE_VERSION],
    + ** [SQLITE_VERSION_NUMBER], and [SQLITE_SOURCE_ID] C preprocessor macros
    +@@ -343,7 +1165,7 @@ extern "C" {
    + **
    + ** <blockquote><pre>
    + ** assert( sqlite3_libversion_number()==SQLITE_VERSION_NUMBER );
    +-** assert( strcmp(sqlite3_sourceid(),SQLITE_SOURCE_ID)==0 );
    ++** assert( strncmp(sqlite3_sourceid(),SQLITE_SOURCE_ID,80)==0 );
    + ** assert( strcmp(sqlite3_libversion(),SQLITE_VERSION)==0 );
    + ** </pre></blockquote>)^
    + **
    +@@ -353,16 +1175,18 @@ extern "C" {
    + ** function is provided for use in DLLs since DLL users usually do not have
    + ** direct access to string constants within the DLL.  ^The
    + ** sqlite3_libversion_number() function returns an integer equal to
    +-** [SQLITE_VERSION_NUMBER].  ^The sqlite3_sourceid() function returns 
    ++** [SQLITE_VERSION_NUMBER].  ^(The sqlite3_sourceid() function returns 
    + ** a pointer to a string constant whose value is the same as the 
    +-** [SQLITE_SOURCE_ID] C preprocessor macro.
    ++** [SQLITE_SOURCE_ID] C preprocessor macro.  Except if SQLite is built
    ++** using an edited copy of [the amalgamation], then the last four characters
    ++** of the hash might be different from [SQLITE_SOURCE_ID].)^
    + **
    + ** See also: [sqlite_version()] and [sqlite_source_id()].
    + */
    + SQLITE_API const char sqlite3_version[] = SQLITE_VERSION;
    +-SQLITE_API const char *SQLITE_STDCALL sqlite3_libversion(void);
    +-SQLITE_API const char *SQLITE_STDCALL sqlite3_sourceid(void);
    +-SQLITE_API int SQLITE_STDCALL sqlite3_libversion_number(void);
    ++SQLITE_API const char *sqlite3_libversion(void);
    ++SQLITE_API const char *sqlite3_sourceid(void);
    ++SQLITE_API int sqlite3_libversion_number(void);
    + 
    + /*
    + ** CAPI3REF: Run-Time Library Compilation Options Diagnostics
    +@@ -387,8 +1211,8 @@ SQLITE_API int SQLITE_STDCALL sqlite3_libversion_number(void);
    + ** [sqlite_compileoption_get()] and the [compile_options pragma].
    + */
    + #ifndef SQLITE_OMIT_COMPILEOPTION_DIAGS
    +-SQLITE_API int SQLITE_STDCALL sqlite3_compileoption_used(const char *zOptName);
    +-SQLITE_API const char *SQLITE_STDCALL sqlite3_compileoption_get(int N);
    ++SQLITE_API int sqlite3_compileoption_used(const char *zOptName);
    ++SQLITE_API const char *sqlite3_compileoption_get(int N);
    + #endif
    + 
    + /*
    +@@ -427,7 +1251,7 @@ SQLITE_API const char *SQLITE_STDCALL sqlite3_compileoption_get(int N);
    + **
    + ** See the [threading mode] documentation for additional information.
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_threadsafe(void);
    ++SQLITE_API int sqlite3_threadsafe(void);
    + 
    + /*
    + ** CAPI3REF: Database Connection Handle
    +@@ -463,7 +1287,11 @@ typedef struct sqlite3 sqlite3;
    + */
    + #ifdef SQLITE_INT64_TYPE
    +   typedef SQLITE_INT64_TYPE sqlite_int64;
    +-  typedef unsigned SQLITE_INT64_TYPE sqlite_uint64;
    ++# ifdef SQLITE_UINT64_TYPE
    ++    typedef SQLITE_UINT64_TYPE sqlite_uint64;
    ++# else  
    ++    typedef unsigned SQLITE_INT64_TYPE sqlite_uint64;
    ++# endif
    + #elif defined(_MSC_VER) || defined(__BORLANDC__)
    +   typedef __int64 sqlite_int64;
    +   typedef unsigned __int64 sqlite_uint64;
    +@@ -524,8 +1352,8 @@ typedef sqlite_uint64 sqlite3_uint64;
    + ** ^Calling sqlite3_close() or sqlite3_close_v2() with a NULL pointer
    + ** argument is a harmless no-op.
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_close(sqlite3*);
    +-SQLITE_API int SQLITE_STDCALL sqlite3_close_v2(sqlite3*);
    ++SQLITE_API int sqlite3_close(sqlite3*);
    ++SQLITE_API int sqlite3_close_v2(sqlite3*);
    + 
    + /*
    + ** The type for a callback function.
    +@@ -561,7 +1389,7 @@ typedef int (*sqlite3_callback)(void*,int,char**, char**);
    + ** from [sqlite3_malloc()] and passed back through the 5th parameter.
    + ** To avoid memory leaks, the application should invoke [sqlite3_free()]
    + ** on error message strings returned through the 5th parameter of
    +-** of sqlite3_exec() after the error message string is no longer needed.
    ++** sqlite3_exec() after the error message string is no longer needed.
    + ** ^If the 5th parameter to sqlite3_exec() is not NULL and no errors
    + ** occur, then sqlite3_exec() sets the pointer in its 5th parameter to
    + ** NULL before returning.
    +@@ -596,7 +1424,7 @@ typedef int (*sqlite3_callback)(void*,int,char**, char**);
    + **      the 2nd parameter of sqlite3_exec() while sqlite3_exec() is running.
    + ** </ul>
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_exec(
    ++SQLITE_API int sqlite3_exec(
    +   sqlite3*,                                  /* An open database */
    +   const char *sql,                           /* SQL to be evaluated */
    +   int (*callback)(void*,int,char**,char**),  /* Callback function */
    +@@ -617,7 +1445,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_exec(
    + */
    + #define SQLITE_OK           0   /* Successful result */
    + /* beginning-of-error-codes */
    +-#define SQLITE_ERROR        1   /* SQL error or missing database */
    ++#define SQLITE_ERROR        1   /* Generic error */
    + #define SQLITE_INTERNAL     2   /* Internal logic error in SQLite */
    + #define SQLITE_PERM         3   /* Access permission denied */
    + #define SQLITE_ABORT        4   /* Callback routine requested an abort */
    +@@ -632,7 +1460,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_exec(
    + #define SQLITE_FULL        13   /* Insertion failed because database is full */
    + #define SQLITE_CANTOPEN    14   /* Unable to open the database file */
    + #define SQLITE_PROTOCOL    15   /* Database lock protocol error */
    +-#define SQLITE_EMPTY       16   /* Database is empty */
    ++#define SQLITE_EMPTY       16   /* Internal use only */
    + #define SQLITE_SCHEMA      17   /* The database schema changed */
    + #define SQLITE_TOOBIG      18   /* String or BLOB exceeds size limit */
    + #define SQLITE_CONSTRAINT  19   /* Abort due to constraint violation */
    +@@ -640,7 +1468,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_exec(
    + #define SQLITE_MISUSE      21   /* Library used incorrectly */
    + #define SQLITE_NOLFS       22   /* Uses OS features not supported on host */
    + #define SQLITE_AUTH        23   /* Authorization denied */
    +-#define SQLITE_FORMAT      24   /* Auxiliary database format error */
    ++#define SQLITE_FORMAT      24   /* Not used */
    + #define SQLITE_RANGE       25   /* 2nd parameter to sqlite3_bind out of range */
    + #define SQLITE_NOTADB      26   /* File opened that is not a database file */
    + #define SQLITE_NOTICE      27   /* Notifications from sqlite3_log() */
    +@@ -657,7 +1485,8 @@ SQLITE_API int SQLITE_STDCALL sqlite3_exec(
    + ** [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
    ++** address this, newer versions of SQLite (version 3.3.8 [dateof:3.3.8]
    ++** and later) include
    + ** support for additional result codes that provide more detailed information
    + ** about errors. These [extended result codes] are enabled or disabled
    + ** on a per database connection basis using the
    +@@ -665,6 +1494,8 @@ SQLITE_API int SQLITE_STDCALL sqlite3_exec(
    + ** the most recent error can be obtained using
    + ** [sqlite3_extended_errcode()].
    + */
    ++#define SQLITE_ERROR_MISSING_COLLSEQ   (SQLITE_ERROR | (1<<8))
    ++#define SQLITE_ERROR_RETRY             (SQLITE_ERROR | (2<<8))
    + #define SQLITE_IOERR_READ              (SQLITE_IOERR | (1<<8))
    + #define SQLITE_IOERR_SHORT_READ        (SQLITE_IOERR | (2<<8))
    + #define SQLITE_IOERR_WRITE             (SQLITE_IOERR | (3<<8))
    +@@ -692,6 +1523,10 @@ SQLITE_API int SQLITE_STDCALL sqlite3_exec(
    + #define SQLITE_IOERR_GETTEMPPATH       (SQLITE_IOERR | (25<<8))
    + #define SQLITE_IOERR_CONVPATH          (SQLITE_IOERR | (26<<8))
    + #define SQLITE_IOERR_VNODE             (SQLITE_IOERR | (27<<8))
    ++#define SQLITE_IOERR_AUTH              (SQLITE_IOERR | (28<<8))
    ++#define SQLITE_IOERR_BEGIN_ATOMIC      (SQLITE_IOERR | (29<<8))
    ++#define SQLITE_IOERR_COMMIT_ATOMIC     (SQLITE_IOERR | (30<<8))
    ++#define SQLITE_IOERR_ROLLBACK_ATOMIC   (SQLITE_IOERR | (31<<8))
    + #define SQLITE_LOCKED_SHAREDCACHE      (SQLITE_LOCKED |  (1<<8))
    + #define SQLITE_BUSY_RECOVERY           (SQLITE_BUSY   |  (1<<8))
    + #define SQLITE_BUSY_SNAPSHOT           (SQLITE_BUSY   |  (2<<8))
    +@@ -704,6 +1539,8 @@ SQLITE_API int SQLITE_STDCALL sqlite3_exec(
    + #define SQLITE_READONLY_CANTLOCK       (SQLITE_READONLY | (2<<8))
    + #define SQLITE_READONLY_ROLLBACK       (SQLITE_READONLY | (3<<8))
    + #define SQLITE_READONLY_DBMOVED        (SQLITE_READONLY | (4<<8))
    ++#define SQLITE_READONLY_CANTINIT       (SQLITE_READONLY | (5<<8))
    ++#define SQLITE_READONLY_DIRECTORY      (SQLITE_READONLY | (6<<8))
    + #define SQLITE_ABORT_ROLLBACK          (SQLITE_ABORT | (2<<8))
    + #define SQLITE_CONSTRAINT_CHECK        (SQLITE_CONSTRAINT | (1<<8))
    + #define SQLITE_CONSTRAINT_COMMITHOOK   (SQLITE_CONSTRAINT | (2<<8))
    +@@ -719,6 +1556,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_exec(
    + #define SQLITE_NOTICE_RECOVER_ROLLBACK (SQLITE_NOTICE | (2<<8))
    + #define SQLITE_WARNING_AUTOINDEX       (SQLITE_WARNING | (1<<8))
    + #define SQLITE_AUTH_USER               (SQLITE_AUTH | (1<<8))
    ++#define SQLITE_OK_LOAD_PERMANENTLY     (SQLITE_OK | (1<<8))
    + 
    + /*
    + ** CAPI3REF: Flags For File Open Operations
    +@@ -773,10 +1611,15 @@ SQLITE_API int SQLITE_STDCALL 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.  The
    ++** flag indicates 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.
    ++**
    ++** The SQLITE_IOCAP_BATCH_ATOMIC property means that the underlying
    ++** filesystem supports doing multiple write operations atomically when those
    ++** write operations are bracketed by [SQLITE_FCNTL_BEGIN_ATOMIC_WRITE] and
    ++** [SQLITE_FCNTL_COMMIT_ATOMIC_WRITE].
    + */
    + #define SQLITE_IOCAP_ATOMIC                 0x00000001
    + #define SQLITE_IOCAP_ATOMIC512              0x00000002
    +@@ -792,6 +1635,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_exec(
    + #define SQLITE_IOCAP_UNDELETABLE_WHEN_OPEN  0x00000800
    + #define SQLITE_IOCAP_POWERSAFE_OVERWRITE    0x00001000
    + #define SQLITE_IOCAP_IMMUTABLE              0x00002000
    ++#define SQLITE_IOCAP_BATCH_ATOMIC           0x00004000
    + 
    + /*
    + ** CAPI3REF: File Locking Levels
    +@@ -923,6 +1767,10 @@ struct sqlite3_file {
    + ** <li> [SQLITE_IOCAP_ATOMIC64K]
    + ** <li> [SQLITE_IOCAP_SAFE_APPEND]
    + ** <li> [SQLITE_IOCAP_SEQUENTIAL]
    ++** <li> [SQLITE_IOCAP_UNDELETABLE_WHEN_OPEN]
    ++** <li> [SQLITE_IOCAP_POWERSAFE_OVERWRITE]
    ++** <li> [SQLITE_IOCAP_IMMUTABLE]
    ++** <li> [SQLITE_IOCAP_BATCH_ATOMIC]
    + ** </ul>
    + **
    + ** The SQLITE_IOCAP_ATOMIC property means that all writes of
    +@@ -1007,8 +1855,13 @@ struct sqlite3_io_methods {
    + ** <li>[[SQLITE_FCNTL_FILE_POINTER]]
    + ** The [SQLITE_FCNTL_FILE_POINTER] opcode is used to obtain a pointer
    + ** to the [sqlite3_file] object associated with a particular database
    +-** connection.  See the [sqlite3_file_control()] documentation for
    +-** additional information.
    ++** connection.  See also [SQLITE_FCNTL_JOURNAL_POINTER].
    ++**
    ++** <li>[[SQLITE_FCNTL_JOURNAL_POINTER]]
    ++** The [SQLITE_FCNTL_JOURNAL_POINTER] opcode is used to obtain a pointer
    ++** to the [sqlite3_file] object associated with the journal file (either
    ++** the [rollback journal] or the [write-ahead log]) for a particular database
    ++** connection.  See also [SQLITE_FCNTL_FILE_POINTER].
    + **
    + ** <li>[[SQLITE_FCNTL_SYNC_OMITTED]]
    + ** No longer in use.
    +@@ -1046,7 +1899,7 @@ struct sqlite3_io_methods {
    + ** opcode allows these two values (10 retries and 25 milliseconds of delay)
    + ** to be adjusted.  The values are changed for all database connections
    + ** within the same process.  The argument is a pointer to an array of two
    +-** integers where the first integer i the new retry count and the second
    ++** integers where the first integer is the new retry count and the second
    + ** integer is the delay.  If either integer is negative, then the setting
    + ** is not changed but instead the prior value of that setting is written
    + ** into the array entry, allowing the current retry settings to be
    +@@ -1095,6 +1948,15 @@ struct sqlite3_io_methods {
    + ** pointer in case this file-control is not implemented.  This file-control
    + ** is intended for diagnostic use only.
    + **
    ++** <li>[[SQLITE_FCNTL_VFS_POINTER]]
    ++** ^The [SQLITE_FCNTL_VFS_POINTER] opcode finds a pointer to the top-level
    ++** [VFSes] currently in use.  ^(The argument X in
    ++** sqlite3_file_control(db,SQLITE_FCNTL_VFS_POINTER,X) must be
    ++** of type "[sqlite3_vfs] **".  This opcodes will set *X
    ++** to a pointer to the top-level VFS.)^
    ++** ^When there are multiple VFS shims in the stack, this opcode finds the
    ++** upper-most shim only.
    ++**
    + ** <li>[[SQLITE_FCNTL_PRAGMA]]
    + ** ^Whenever a [PRAGMA] statement is parsed, an [SQLITE_FCNTL_PRAGMA] 
    + ** file control is sent to the open [sqlite3_file] object corresponding
    +@@ -1165,6 +2027,12 @@ struct sqlite3_io_methods {
    + ** on whether or not the file has been renamed, moved, or deleted since it
    + ** was first opened.
    + **
    ++** <li>[[SQLITE_FCNTL_WIN32_GET_HANDLE]]
    ++** The [SQLITE_FCNTL_WIN32_GET_HANDLE] opcode can be used to obtain the
    ++** underlying native file handle associated with a file handle.  This file
    ++** control interprets its argument as a pointer to a native file handle and
    ++** writes the resulting value there.
    ++**
    + ** <li>[[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
    +@@ -1186,6 +2054,40 @@ struct sqlite3_io_methods {
    + ** The [SQLITE_FCNTL_RBU] opcode is implemented by the special VFS used by
    + ** the RBU extension only.  All other VFS should return SQLITE_NOTFOUND for
    + ** this opcode.  
    ++**
    ++** <li>[[SQLITE_FCNTL_BEGIN_ATOMIC_WRITE]]
    ++** If the [SQLITE_FCNTL_BEGIN_ATOMIC_WRITE] opcode returns SQLITE_OK, then
    ++** the file descriptor is placed in "batch write mode", which
    ++** means all subsequent write operations will be deferred and done
    ++** atomically at the next [SQLITE_FCNTL_COMMIT_ATOMIC_WRITE].  Systems
    ++** that do not support batch atomic writes will return SQLITE_NOTFOUND.
    ++** ^Following a successful SQLITE_FCNTL_BEGIN_ATOMIC_WRITE and prior to
    ++** the closing [SQLITE_FCNTL_COMMIT_ATOMIC_WRITE] or
    ++** [SQLITE_FCNTL_ROLLBACK_ATOMIC_WRITE], SQLite will make
    ++** no VFS interface calls on the same [sqlite3_file] file descriptor
    ++** except for calls to the xWrite method and the xFileControl method
    ++** with [SQLITE_FCNTL_SIZE_HINT].
    ++**
    ++** <li>[[SQLITE_FCNTL_COMMIT_ATOMIC_WRITE]]
    ++** The [SQLITE_FCNTL_COMMIT_ATOMIC_WRITE] opcode causes all write
    ++** operations since the previous successful call to 
    ++** [SQLITE_FCNTL_BEGIN_ATOMIC_WRITE] to be performed atomically.
    ++** This file control returns [SQLITE_OK] if and only if the writes were
    ++** all performed successfully and have been committed to persistent storage.
    ++** ^Regardless of whether or not it is successful, this file control takes
    ++** the file descriptor out of batch write mode so that all subsequent
    ++** write operations are independent.
    ++** ^SQLite will never invoke SQLITE_FCNTL_COMMIT_ATOMIC_WRITE without
    ++** a prior successful call to [SQLITE_FCNTL_BEGIN_ATOMIC_WRITE].
    ++**
    ++** <li>[[SQLITE_FCNTL_ROLLBACK_ATOMIC_WRITE]]
    ++** The [SQLITE_FCNTL_ROLLBACK_ATOMIC_WRITE] opcode causes all write
    ++** operations since the previous successful call to 
    ++** [SQLITE_FCNTL_BEGIN_ATOMIC_WRITE] to be rolled back.
    ++** ^This file control takes the file descriptor out of batch write mode
    ++** so that all subsequent write operations are independent.
    ++** ^SQLite will never invoke SQLITE_FCNTL_ROLLBACK_ATOMIC_WRITE without
    ++** a prior successful call to [SQLITE_FCNTL_BEGIN_ATOMIC_WRITE].
    + ** </ul>
    + */
    + #define SQLITE_FCNTL_LOCKSTATE               1
    +@@ -1213,6 +2115,13 @@ struct sqlite3_io_methods {
    + #define SQLITE_FCNTL_WAL_BLOCK              24
    + #define SQLITE_FCNTL_ZIPVFS                 25
    + #define SQLITE_FCNTL_RBU                    26
    ++#define SQLITE_FCNTL_VFS_POINTER            27
    ++#define SQLITE_FCNTL_JOURNAL_POINTER        28
    ++#define SQLITE_FCNTL_WIN32_GET_HANDLE       29
    ++#define SQLITE_FCNTL_PDB                    30
    ++#define SQLITE_FCNTL_BEGIN_ATOMIC_WRITE     31
    ++#define SQLITE_FCNTL_COMMIT_ATOMIC_WRITE    32
    ++#define SQLITE_FCNTL_ROLLBACK_ATOMIC_WRITE  33
    + 
    + /* deprecated names */
    + #define SQLITE_GET_LOCKPROXYFILE      SQLITE_FCNTL_GET_LOCKPROXYFILE
    +@@ -1232,6 +2141,16 @@ struct sqlite3_io_methods {
    + */
    + typedef struct sqlite3_mutex sqlite3_mutex;
    + 
    ++/*
    ++** CAPI3REF: Loadable Extension Thunk
    ++**
    ++** A pointer to the opaque sqlite3_api_routines structure is passed as
    ++** the third parameter to entry points of [loadable extensions].  This
    ++** structure must be typedefed in order to work around compiler warnings
    ++** on some platforms.
    ++*/
    ++typedef struct sqlite3_api_routines sqlite3_api_routines;
    ++
    + /*
    + ** CAPI3REF: OS Interface Object
    + **
    +@@ -1240,12 +2159,18 @@ typedef struct sqlite3_mutex sqlite3_mutex;
    + ** in the name of the object stands for "virtual file system".  See
    + ** the [VFS | VFS documentation] for further information.
    + **
    +-** The value of the iVersion field is initially 1 but may be larger in
    +-** future versions of SQLite.  Additional fields may be appended to this
    +-** object when the iVersion value is increased.  Note that the structure
    +-** of the sqlite3_vfs object changes in the transaction between
    +-** SQLite version 3.5.9 and 3.6.0 and yet the iVersion field was not
    +-** modified.
    ++** The VFS interface is sometimes extended by adding new methods onto
    ++** the end.  Each time such an extension occurs, the iVersion field
    ++** is incremented.  The iVersion value started out as 1 in
    ++** SQLite [version 3.5.0] on [dateof:3.5.0], then increased to 2
    ++** with SQLite [version 3.7.0] on [dateof:3.7.0], and then increased
    ++** to 3 with SQLite [version 3.7.6] on [dateof:3.7.6].  Additional fields
    ++** may be appended to the sqlite3_vfs object and the iVersion value
    ++** may increase again in future versions of SQLite.
    ++** Note that the structure
    ++** of the sqlite3_vfs object changes in the transition from
    ++** SQLite [version 3.5.9] to [version 3.6.0] on [dateof:3.6.0]
    ++** and yet the iVersion field was not modified.
    + **
    + ** The szOsFile field is the size of the subclassed [sqlite3_file]
    + ** structure used by this VFS.  mxPathname is the maximum length of
    +@@ -1425,7 +2350,7 @@ struct sqlite3_vfs {
    +   const char *(*xNextSystemCall)(sqlite3_vfs*, const char *zName);
    +   /*
    +   ** The methods above are in versions 1 through 3 of the sqlite_vfs object.
    +-  ** New fields may be appended in figure versions.  The iVersion
    ++  ** New fields may be appended in future versions.  The iVersion
    +   ** value will increment whenever this happens. 
    +   */
    + };
    +@@ -1567,10 +2492,10 @@ struct sqlite3_vfs {
    + ** must return [SQLITE_OK] on success and some other [error code] upon
    + ** failure.
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_initialize(void);
    +-SQLITE_API int SQLITE_STDCALL sqlite3_shutdown(void);
    +-SQLITE_API int SQLITE_STDCALL sqlite3_os_init(void);
    +-SQLITE_API int SQLITE_STDCALL sqlite3_os_end(void);
    ++SQLITE_API int sqlite3_initialize(void);
    ++SQLITE_API int sqlite3_shutdown(void);
    ++SQLITE_API int sqlite3_os_init(void);
    ++SQLITE_API int sqlite3_os_end(void);
    + 
    + /*
    + ** CAPI3REF: Configuring The SQLite Library
    +@@ -1603,7 +2528,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_os_end(void);
    + ** ^If the option is unknown or SQLite is unable to set the option
    + ** then this routine returns a non-zero [error code].
    + */
    +-SQLITE_API int SQLITE_CDECL sqlite3_config(int, ...);
    ++SQLITE_API int sqlite3_config(int, ...);
    + 
    + /*
    + ** CAPI3REF: Configure database connections
    +@@ -1622,7 +2547,7 @@ SQLITE_API int SQLITE_CDECL sqlite3_config(int, ...);
    + ** ^Calls to sqlite3_db_config() return SQLITE_OK if and only if
    + ** the call is considered successful.
    + */
    +-SQLITE_API int SQLITE_CDECL sqlite3_db_config(sqlite3*, int op, ...);
    ++SQLITE_API int sqlite3_db_config(sqlite3*, int op, ...);
    + 
    + /*
    + ** CAPI3REF: Memory Allocation Routines
    +@@ -1773,6 +2698,16 @@ struct sqlite3_mem_methods {
    + ** routines with a wrapper that simulations memory allocation failure or
    + ** tracks memory usage, for example. </dd>
    + **
    ++** [[SQLITE_CONFIG_SMALL_MALLOC]] <dt>SQLITE_CONFIG_SMALL_MALLOC</dt>
    ++** <dd> ^The SQLITE_CONFIG_SMALL_MALLOC option takes single argument of
    ++** type int, interpreted as a boolean, which if true provides a hint to
    ++** SQLite that it should avoid large memory allocations if possible.
    ++** SQLite will run faster if it is free to make large memory allocations,
    ++** but some application might prefer to run slower in exchange for
    ++** guarantees about memory fragmentation that are possible if large
    ++** allocations are avoided.  This hint is normally off.
    ++** </dd>
    ++**
    + ** [[SQLITE_CONFIG_MEMSTATUS]] <dt>SQLITE_CONFIG_MEMSTATUS</dt>
    + ** <dd> ^The SQLITE_CONFIG_MEMSTATUS option takes single argument of type int,
    + ** interpreted as a boolean, which enables or disables the collection of
    +@@ -1790,57 +2725,43 @@ struct sqlite3_mem_methods {
    + ** </dd>
    + **
    + ** [[SQLITE_CONFIG_SCRATCH]] <dt>SQLITE_CONFIG_SCRATCH</dt>
    +-** <dd> ^The SQLITE_CONFIG_SCRATCH option specifies a static memory buffer
    +-** that SQLite can use for scratch memory.  ^(There are three arguments
    +-** to SQLITE_CONFIG_SCRATCH:  A pointer an 8-byte
    +-** aligned memory buffer from which the scratch allocations will be
    +-** drawn, the size of each scratch allocation (sz),
    +-** and the maximum number of scratch allocations (N).)^
    +-** The first argument must be a pointer to an 8-byte aligned buffer
    +-** of at least sz*N bytes of memory.
    +-** ^SQLite will not use more than one scratch buffers per thread.
    +-** ^SQLite will never request a scratch buffer that is more than 6
    +-** times the database page size.
    +-** ^If SQLite needs needs additional
    +-** scratch memory beyond what is provided by this configuration option, then 
    +-** [sqlite3_malloc()] will be used to obtain the memory needed.<p>
    +-** ^When the application provides any amount of scratch memory using
    +-** SQLITE_CONFIG_SCRATCH, SQLite avoids unnecessary large
    +-** [sqlite3_malloc|heap allocations].
    +-** This can help [Robson proof|prevent memory allocation failures] due to heap
    +-** fragmentation in low-memory embedded systems.
    ++** <dd> The SQLITE_CONFIG_SCRATCH option is no longer used.
    + ** </dd>
    + **
    + ** [[SQLITE_CONFIG_PAGECACHE]] <dt>SQLITE_CONFIG_PAGECACHE</dt>
    +-** <dd> ^The SQLITE_CONFIG_PAGECACHE option specifies a static memory buffer
    ++** <dd> ^The SQLITE_CONFIG_PAGECACHE option specifies a memory pool
    + ** that SQLite can use for the database page cache with the default page
    + ** cache implementation.  
    +-** This configuration should not be used if an application-define page
    +-** cache implementation is loaded using the [SQLITE_CONFIG_PCACHE2]
    +-** configuration option.
    ++** This configuration option is a no-op if an application-define page
    ++** cache implementation is loaded using the [SQLITE_CONFIG_PCACHE2].
    + ** ^There are three arguments to SQLITE_CONFIG_PAGECACHE: A pointer to
    +-** 8-byte aligned
    +-** memory, the size of each page buffer (sz), and the number of pages (N).
    ++** 8-byte aligned memory (pMem), the size of each page cache line (sz),
    ++** and the number of cache lines (N).
    + ** The sz argument should be the size of the largest database page
    + ** (a power of two between 512 and 65536) plus some extra bytes for each
    + ** page header.  ^The number of extra bytes needed by the page header
    +-** can be determined using the [SQLITE_CONFIG_PCACHE_HDRSZ] option 
    +-** to [sqlite3_config()].
    ++** can be determined using [SQLITE_CONFIG_PCACHE_HDRSZ].
    + ** ^It is harmless, apart from the wasted memory,
    +-** for the sz parameter to be larger than necessary.  The first
    +-** argument should pointer to an 8-byte aligned block of memory that
    +-** is at least sz*N bytes of memory, otherwise subsequent behavior is
    +-** undefined.
    +-** ^SQLite will use the memory provided by the first argument to satisfy its
    +-** memory needs for the first N pages that it adds to cache.  ^If additional
    +-** page cache memory is needed beyond what is provided by this option, then
    +-** SQLite goes to [sqlite3_malloc()] for the additional storage space.</dd>
    ++** for the sz parameter to be larger than necessary.  The pMem
    ++** argument must be either a NULL pointer or a pointer to an 8-byte
    ++** aligned block of memory of at least sz*N bytes, otherwise
    ++** subsequent behavior is undefined.
    ++** ^When pMem is not NULL, SQLite will strive to use the memory provided
    ++** to satisfy page cache needs, falling back to [sqlite3_malloc()] if
    ++** a page cache line is larger than sz bytes or if all of the pMem buffer
    ++** is exhausted.
    ++** ^If pMem is NULL and N is non-zero, then each database connection
    ++** does an initial bulk allocation for page cache memory
    ++** from [sqlite3_malloc()] sufficient for N cache lines if N is positive or
    ++** of -1024*N bytes if N is negative, . ^If additional
    ++** page cache memory is needed beyond what is provided by the initial
    ++** allocation, then SQLite goes to [sqlite3_malloc()] separately for each
    ++** additional cache line. </dd>
    + **
    + ** [[SQLITE_CONFIG_HEAP]] <dt>SQLITE_CONFIG_HEAP</dt>
    + ** <dd> ^The SQLITE_CONFIG_HEAP option specifies a static memory buffer 
    + ** that SQLite will use for all of its dynamic memory allocation needs
    +-** beyond those provided for by [SQLITE_CONFIG_SCRATCH] and
    +-** [SQLITE_CONFIG_PAGECACHE].
    ++** beyond those provided for by [SQLITE_CONFIG_PAGECACHE].
    + ** ^The SQLITE_CONFIG_HEAP option is only available if SQLite is compiled
    + ** with either [SQLITE_ENABLE_MEMSYS3] or [SQLITE_ENABLE_MEMSYS5] and returns
    + ** [SQLITE_ERROR] if invoked otherwise.
    +@@ -2012,6 +2933,20 @@ struct sqlite3_mem_methods {
    + ** is enabled (using the [PRAGMA threads] command) and the amount of content
    + ** to be sorted exceeds the page size times the minimum of the
    + ** [PRAGMA cache_size] setting and this value.
    ++**
    ++** [[SQLITE_CONFIG_STMTJRNL_SPILL]]
    ++** <dt>SQLITE_CONFIG_STMTJRNL_SPILL
    ++** <dd>^The SQLITE_CONFIG_STMTJRNL_SPILL option takes a single parameter which
    ++** becomes the [statement journal] spill-to-disk threshold.  
    ++** [Statement journals] are held in memory until their size (in bytes)
    ++** exceeds this threshold, at which point they are written to disk.
    ++** Or if the threshold is -1, statement journals are always held
    ++** exclusively in memory.
    ++** Since many statement journals never become large, setting the spill
    ++** threshold to a value such as 64KiB can greatly reduce the amount of
    ++** I/O required to support statement rollback.
    ++** The default value for this setting is controlled by the
    ++** [SQLITE_STMTJRNL_SPILL] compile-time option.
    + ** </dl>
    + */
    + #define SQLITE_CONFIG_SINGLETHREAD  1  /* nil */
    +@@ -2019,7 +2954,7 @@ struct sqlite3_mem_methods {
    + #define SQLITE_CONFIG_SERIALIZED    3  /* nil */
    + #define SQLITE_CONFIG_MALLOC        4  /* sqlite3_mem_methods* */
    + #define SQLITE_CONFIG_GETMALLOC     5  /* sqlite3_mem_methods* */
    +-#define SQLITE_CONFIG_SCRATCH       6  /* void*, int sz, int N */
    ++#define SQLITE_CONFIG_SCRATCH       6  /* No longer used */
    + #define SQLITE_CONFIG_PAGECACHE     7  /* void*, int sz, int N */
    + #define SQLITE_CONFIG_HEAP          8  /* void*, int nByte, int min */
    + #define SQLITE_CONFIG_MEMSTATUS     9  /* boolean */
    +@@ -2039,6 +2974,8 @@ struct sqlite3_mem_methods {
    + #define SQLITE_CONFIG_WIN32_HEAPSIZE      23  /* int nByte */
    + #define SQLITE_CONFIG_PCACHE_HDRSZ        24  /* int *psz */
    + #define SQLITE_CONFIG_PMASZ               25  /* unsigned int szPma */
    ++#define SQLITE_CONFIG_STMTJRNL_SPILL      26  /* int nByte */
    ++#define SQLITE_CONFIG_SMALL_MALLOC        27  /* boolean */
    + 
    + /*
    + ** CAPI3REF: Database Connection Configuration Options
    +@@ -2096,12 +3033,88 @@ struct sqlite3_mem_methods {
    + ** following this call.  The second parameter may be a NULL pointer, in
    + ** which case the trigger setting is not reported back. </dd>
    + **
    ++** <dt>SQLITE_DBCONFIG_ENABLE_FTS3_TOKENIZER</dt>
    ++** <dd> ^This option is used to enable or disable the two-argument
    ++** version of the [fts3_tokenizer()] function which is part of the
    ++** [FTS3] full-text search engine extension.
    ++** There should be two additional arguments.
    ++** The first argument is an integer which is 0 to disable fts3_tokenizer() or
    ++** positive to enable fts3_tokenizer() or negative to leave the setting
    ++** unchanged.
    ++** The second parameter is a pointer to an integer into which
    ++** is written 0 or 1 to indicate whether fts3_tokenizer is disabled or enabled
    ++** following this call.  The second parameter may be a NULL pointer, in
    ++** which case the new setting is not reported back. </dd>
    ++**
    ++** <dt>SQLITE_DBCONFIG_ENABLE_LOAD_EXTENSION</dt>
    ++** <dd> ^This option is used to enable or disable the [sqlite3_load_extension()]
    ++** interface independently of the [load_extension()] SQL function.
    ++** The [sqlite3_enable_load_extension()] API enables or disables both the
    ++** C-API [sqlite3_load_extension()] and the SQL function [load_extension()].
    ++** There should be two additional arguments.
    ++** When the first argument to this interface is 1, then only the C-API is
    ++** enabled and the SQL function remains disabled.  If the first argument to
    ++** this interface is 0, then both the C-API and the SQL function are disabled.
    ++** If the first argument is -1, then no changes are made to state of either the
    ++** C-API or the SQL function.
    ++** The second parameter is a pointer to an integer into which
    ++** is written 0 or 1 to indicate whether [sqlite3_load_extension()] interface
    ++** is disabled or enabled following this call.  The second parameter may
    ++** be a NULL pointer, in which case the new setting is not reported back.
    ++** </dd>
    ++**
    ++** <dt>SQLITE_DBCONFIG_MAINDBNAME</dt>
    ++** <dd> ^This option is used to change the name of the "main" database
    ++** schema.  ^The sole argument is a pointer to a constant UTF8 string
    ++** which will become the new schema name in place of "main".  ^SQLite
    ++** does not make a copy of the new main schema name string, so the application
    ++** must ensure that the argument passed into this DBCONFIG option is unchanged
    ++** until after the database connection closes.
    ++** </dd>
    ++**
    ++** <dt>SQLITE_DBCONFIG_NO_CKPT_ON_CLOSE</dt>
    ++** <dd> Usually, when a database in wal mode is closed or detached from a 
    ++** database handle, SQLite checks if this will mean that there are now no 
    ++** connections at all to the database. If so, it performs a checkpoint 
    ++** operation before closing the connection. This option may be used to
    ++** override this behaviour. The first parameter passed to this operation
    ++** is an integer - non-zero to disable checkpoints-on-close, or zero (the
    ++** default) to enable them. The second parameter is a pointer to an integer
    ++** into which is written 0 or 1 to indicate whether checkpoints-on-close
    ++** have been disabled - 0 if they are not disabled, 1 if they are.
    ++** </dd>
    ++** <dt>SQLITE_DBCONFIG_ENABLE_QPSG</dt>
    ++** <dd>^(The SQLITE_DBCONFIG_ENABLE_QPSG option activates or deactivates
    ++** the [query planner stability guarantee] (QPSG).  When the QPSG is active,
    ++** a single SQL query statement will always use the same algorithm regardless
    ++** of values of [bound parameters].)^ The QPSG disables some query optimizations
    ++** that look at the values of bound parameters, which can make some queries
    ++** slower.  But the QPSG has the advantage of more predictable behavior.  With
    ++** the QPSG active, SQLite will always use the same query plan in the field as
    ++** was used during testing in the lab.
    ++** </dd>
    ++** <dt>SQLITE_DBCONFIG_TRIGGER_EQP</dt>
    ++** <dd> By default, the output of EXPLAIN QUERY PLAN commands does not 
    ++** include output for any operations performed by trigger programs. This
    ++** option is used to set or clear (the default) a flag that governs this
    ++** behavior. The first parameter passed to this operation is an integer -
    ++** non-zero to enable output for trigger programs, or zero to disable it.
    ++** The second parameter is a pointer to an integer into which is written 
    ++** 0 or 1 to indicate whether output-for-triggers has been disabled - 0 if 
    ++** it is not disabled, 1 if it is.  
    ++** </dd>
    + ** </dl>
    + */
    +-#define SQLITE_DBCONFIG_LOOKASIDE       1001  /* void* int int */
    +-#define SQLITE_DBCONFIG_ENABLE_FKEY     1002  /* int int* */
    +-#define SQLITE_DBCONFIG_ENABLE_TRIGGER  1003  /* int int* */
    +-
    ++#define SQLITE_DBCONFIG_MAINDBNAME            1000 /* const char* */
    ++#define SQLITE_DBCONFIG_LOOKASIDE             1001 /* void* int int */
    ++#define SQLITE_DBCONFIG_ENABLE_FKEY           1002 /* int int* */
    ++#define SQLITE_DBCONFIG_ENABLE_TRIGGER        1003 /* int int* */
    ++#define SQLITE_DBCONFIG_ENABLE_FTS3_TOKENIZER 1004 /* int int* */
    ++#define SQLITE_DBCONFIG_ENABLE_LOAD_EXTENSION 1005 /* int int* */
    ++#define SQLITE_DBCONFIG_NO_CKPT_ON_CLOSE      1006 /* int int* */
    ++#define SQLITE_DBCONFIG_ENABLE_QPSG           1007 /* int int* */
    ++#define SQLITE_DBCONFIG_TRIGGER_EQP           1008 /* int int* */
    ++#define SQLITE_DBCONFIG_MAX                   1008 /* Largest DBCONFIG */
    + 
    + /*
    + ** CAPI3REF: Enable Or Disable Extended Result Codes
    +@@ -2111,7 +3124,7 @@ struct sqlite3_mem_methods {
    + ** [extended result codes] feature of SQLite. ^The extended result
    + ** codes are disabled by default for historical compatibility.
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_extended_result_codes(sqlite3*, int onoff);
    ++SQLITE_API int sqlite3_extended_result_codes(sqlite3*, int onoff);
    + 
    + /*
    + ** CAPI3REF: Last Insert Rowid
    +@@ -2125,20 +3138,30 @@ SQLITE_API int SQLITE_STDCALL sqlite3_extended_result_codes(sqlite3*, int onoff)
    + ** the table has a column of type [INTEGER PRIMARY KEY] then that column
    + ** is another alias for the rowid.
    + **
    +-** ^The sqlite3_last_insert_rowid(D) interface returns the [rowid] of the 
    +-** most recent successful [INSERT] into a rowid table or [virtual table]
    +-** on database connection D.
    +-** ^Inserts into [WITHOUT ROWID] tables are not recorded.
    +-** ^If no successful [INSERT]s into rowid tables
    +-** have ever occurred on the database connection D, 
    +-** then sqlite3_last_insert_rowid(D) returns zero.
    +-**
    +-** ^(If an [INSERT] occurs within a trigger or within a [virtual table]
    +-** method, then this routine will return the [rowid] of the inserted
    +-** row as long as the trigger or virtual table method is running.
    +-** But once the trigger or virtual table method ends, the value returned 
    +-** by this routine reverts to what it was before the trigger or virtual
    +-** table method began.)^
    ++** ^The sqlite3_last_insert_rowid(D) interface usually returns the [rowid] of
    ++** the most recent successful [INSERT] into a rowid table or [virtual table]
    ++** on database connection D. ^Inserts into [WITHOUT ROWID] tables are not
    ++** recorded. ^If no successful [INSERT]s into rowid tables have ever occurred 
    ++** on the database connection D, then sqlite3_last_insert_rowid(D) returns 
    ++** zero.
    ++**
    ++** As well as being set automatically as rows are inserted into database
    ++** tables, the value returned by this function may be set explicitly by
    ++** [sqlite3_set_last_insert_rowid()]
    ++**
    ++** Some virtual table implementations may INSERT rows into rowid tables as
    ++** part of committing a transaction (e.g. to flush data accumulated in memory
    ++** to disk). In this case subsequent calls to this function return the rowid
    ++** associated with these internal INSERT operations, which leads to 
    ++** unintuitive results. Virtual table implementations that do write to rowid
    ++** tables in this way can avoid this problem by restoring the original 
    ++** rowid value using [sqlite3_set_last_insert_rowid()] before returning 
    ++** control to the user.
    ++**
    ++** ^(If an [INSERT] occurs within a trigger then this routine will 
    ++** return the [rowid] of the inserted row as long as the trigger is 
    ++** running. Once the trigger program ends, the value returned 
    ++** by this routine reverts to what it was before the trigger was fired.)^
    + **
    + ** ^An [INSERT] that fails due to a constraint violation is not a
    + ** successful [INSERT] and does not change the value returned by this
    +@@ -2163,7 +3186,17 @@ SQLITE_API int SQLITE_STDCALL sqlite3_extended_result_codes(sqlite3*, int onoff)
    + ** unpredictable and might not equal either the old or the new
    + ** last insert [rowid].
    + */
    +-SQLITE_API sqlite3_int64 SQLITE_STDCALL sqlite3_last_insert_rowid(sqlite3*);
    ++SQLITE_API sqlite3_int64 sqlite3_last_insert_rowid(sqlite3*);
    ++
    ++/*
    ++** CAPI3REF: Set the Last Insert Rowid value.
    ++** METHOD: sqlite3
    ++**
    ++** The sqlite3_set_last_insert_rowid(D, R) method allows the application to
    ++** set the value returned by calling sqlite3_last_insert_rowid(D) to R 
    ++** without inserting a row into the database.
    ++*/
    ++SQLITE_API void sqlite3_set_last_insert_rowid(sqlite3*,sqlite3_int64);
    + 
    + /*
    + ** CAPI3REF: Count The Number Of Rows Modified
    +@@ -2216,7 +3249,7 @@ SQLITE_API sqlite3_int64 SQLITE_STDCALL sqlite3_last_insert_rowid(sqlite3*);
    + ** while [sqlite3_changes()] is running then the value returned
    + ** is unpredictable and not meaningful.
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_changes(sqlite3*);
    ++SQLITE_API int sqlite3_changes(sqlite3*);
    + 
    + /*
    + ** CAPI3REF: Total Number Of Rows Modified
    +@@ -2240,7 +3273,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_changes(sqlite3*);
    + ** while [sqlite3_total_changes()] is running then the value
    + ** returned is unpredictable and not meaningful.
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_total_changes(sqlite3*);
    ++SQLITE_API int sqlite3_total_changes(sqlite3*);
    + 
    + /*
    + ** CAPI3REF: Interrupt A Long-Running Query
    +@@ -2276,11 +3309,8 @@ SQLITE_API int SQLITE_STDCALL sqlite3_total_changes(sqlite3*);
    + ** ^A call to sqlite3_interrupt(D) that occurs when there are no running
    + ** SQL statements is a no-op and has no effect on SQL statements
    + ** that are started after the sqlite3_interrupt() call returns.
    +-**
    +-** If the database connection closes while [sqlite3_interrupt()]
    +-** is running then bad things will likely happen.
    + */
    +-SQLITE_API void SQLITE_STDCALL sqlite3_interrupt(sqlite3*);
    ++SQLITE_API void sqlite3_interrupt(sqlite3*);
    + 
    + /*
    + ** CAPI3REF: Determine If An SQL Statement Is Complete
    +@@ -2315,8 +3345,8 @@ SQLITE_API void SQLITE_STDCALL sqlite3_interrupt(sqlite3*);
    + ** The input to [sqlite3_complete16()] must be a zero-terminated
    + ** UTF-16 string in native byte order.
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_complete(const char *sql);
    +-SQLITE_API int SQLITE_STDCALL sqlite3_complete16(const void *sql);
    ++SQLITE_API int sqlite3_complete(const char *sql);
    ++SQLITE_API int sqlite3_complete16(const void *sql);
    + 
    + /*
    + ** CAPI3REF: Register A Callback To Handle SQLITE_BUSY Errors
    +@@ -2377,7 +3407,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_complete16(const void *sql);
    + ** A busy handler must not close the database connection
    + ** or [prepared statement] that invoked the busy handler.
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_busy_handler(sqlite3*, int(*)(void*,int), void*);
    ++SQLITE_API int sqlite3_busy_handler(sqlite3*,int(*)(void*,int),void*);
    + 
    + /*
    + ** CAPI3REF: Set A Busy Timeout
    +@@ -2400,7 +3430,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_busy_handler(sqlite3*, int(*)(void*,int),
    + **
    + ** See also:  [PRAGMA busy_timeout]
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_busy_timeout(sqlite3*, int ms);
    ++SQLITE_API int sqlite3_busy_timeout(sqlite3*, int ms);
    + 
    + /*
    + ** CAPI3REF: Convenience Routines For Running Queries
    +@@ -2475,7 +3505,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_busy_timeout(sqlite3*, int ms);
    + ** reflected in subsequent calls to [sqlite3_errcode()] or
    + ** [sqlite3_errmsg()].
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_get_table(
    ++SQLITE_API int sqlite3_get_table(
    +   sqlite3 *db,          /* An open database */
    +   const char *zSql,     /* SQL to be evaluated */
    +   char ***pazResult,    /* Results of the query */
    +@@ -2483,7 +3513,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_get_table(
    +   int *pnColumn,        /* Number of result columns written here */
    +   char **pzErrmsg       /* Error msg written here */
    + );
    +-SQLITE_API void SQLITE_STDCALL sqlite3_free_table(char **result);
    ++SQLITE_API void sqlite3_free_table(char **result);
    + 
    + /*
    + ** CAPI3REF: Formatted String Printing Functions
    +@@ -2589,10 +3619,10 @@ SQLITE_API void SQLITE_STDCALL sqlite3_free_table(char **result);
    + ** addition that after the string has been read and copied into
    + ** the result, [sqlite3_free()] is called on the input string.)^
    + */
    +-SQLITE_API char *SQLITE_CDECL sqlite3_mprintf(const char*,...);
    +-SQLITE_API char *SQLITE_STDCALL sqlite3_vmprintf(const char*, va_list);
    +-SQLITE_API char *SQLITE_CDECL sqlite3_snprintf(int,char*,const char*, ...);
    +-SQLITE_API char *SQLITE_STDCALL sqlite3_vsnprintf(int,char*,const char*, va_list);
    ++SQLITE_API char *sqlite3_mprintf(const char*,...);
    ++SQLITE_API char *sqlite3_vmprintf(const char*, va_list);
    ++SQLITE_API char *sqlite3_snprintf(int,char*,const char*, ...);
    ++SQLITE_API char *sqlite3_vsnprintf(int,char*,const char*, va_list);
    + 
    + /*
    + ** CAPI3REF: Memory Allocation Subsystem
    +@@ -2682,12 +3712,12 @@ SQLITE_API char *SQLITE_STDCALL sqlite3_vsnprintf(int,char*,const char*, va_list
    + ** a block of memory after it has been released using
    + ** [sqlite3_free()] or [sqlite3_realloc()].
    + */
    +-SQLITE_API void *SQLITE_STDCALL sqlite3_malloc(int);
    +-SQLITE_API void *SQLITE_STDCALL sqlite3_malloc64(sqlite3_uint64);
    +-SQLITE_API void *SQLITE_STDCALL sqlite3_realloc(void*, int);
    +-SQLITE_API void *SQLITE_STDCALL sqlite3_realloc64(void*, sqlite3_uint64);
    +-SQLITE_API void SQLITE_STDCALL sqlite3_free(void*);
    +-SQLITE_API sqlite3_uint64 SQLITE_STDCALL sqlite3_msize(void*);
    ++SQLITE_API void *sqlite3_malloc(int);
    ++SQLITE_API void *sqlite3_malloc64(sqlite3_uint64);
    ++SQLITE_API void *sqlite3_realloc(void*, int);
    ++SQLITE_API void *sqlite3_realloc64(void*, sqlite3_uint64);
    ++SQLITE_API void sqlite3_free(void*);
    ++SQLITE_API sqlite3_uint64 sqlite3_msize(void*);
    + 
    + /*
    + ** CAPI3REF: Memory Allocator Statistics
    +@@ -2712,8 +3742,8 @@ SQLITE_API sqlite3_uint64 SQLITE_STDCALL sqlite3_msize(void*);
    + ** by [sqlite3_memory_highwater(1)] is the high-water mark
    + ** prior to the reset.
    + */
    +-SQLITE_API sqlite3_int64 SQLITE_STDCALL sqlite3_memory_used(void);
    +-SQLITE_API sqlite3_int64 SQLITE_STDCALL sqlite3_memory_highwater(int resetFlag);
    ++SQLITE_API sqlite3_int64 sqlite3_memory_used(void);
    ++SQLITE_API sqlite3_int64 sqlite3_memory_highwater(int resetFlag);
    + 
    + /*
    + ** CAPI3REF: Pseudo-Random Number Generator
    +@@ -2736,17 +3766,19 @@ SQLITE_API sqlite3_int64 SQLITE_STDCALL sqlite3_memory_highwater(int resetFlag);
    + ** internally and without recourse to the [sqlite3_vfs] xRandomness
    + ** method.
    + */
    +-SQLITE_API void SQLITE_STDCALL sqlite3_randomness(int N, void *P);
    ++SQLITE_API void sqlite3_randomness(int N, void *P);
    + 
    + /*
    + ** CAPI3REF: Compile-Time Authorization Callbacks
    + ** METHOD: sqlite3
    ++** KEYWORDS: {authorizer callback}
    + **
    + ** ^This routine registers an authorizer callback with a particular
    + ** [database connection], supplied in the first argument.
    + ** ^The authorizer callback is invoked as SQL statements are being compiled
    + ** by [sqlite3_prepare()] or its variants [sqlite3_prepare_v2()],
    +-** [sqlite3_prepare16()] and [sqlite3_prepare16_v2()].  ^At various
    ++** [sqlite3_prepare_v3()], [sqlite3_prepare16()], [sqlite3_prepare16_v2()],
    ++** and [sqlite3_prepare16_v3()].  ^At various
    + ** points during the compilation process, as logic is being created
    + ** to perform various actions, the authorizer callback is invoked to
    + ** see if those actions are allowed.  ^The authorizer callback should
    +@@ -2768,8 +3800,10 @@ SQLITE_API void SQLITE_STDCALL sqlite3_randomness(int N, void *P);
    + ** parameter to the sqlite3_set_authorizer() interface. ^The second parameter
    + ** to the callback is an integer [SQLITE_COPY | action code] that specifies
    + ** the particular action to be authorized. ^The third through sixth parameters
    +-** to the callback are zero-terminated strings that contain additional
    +-** details about the action to be authorized.
    ++** to the callback are either NULL pointers or zero-terminated strings
    ++** that contain additional details about the action to be authorized.
    ++** Applications must always be prepared to encounter a NULL pointer in any
    ++** of the third through the sixth parameters of the authorization callback.
    + **
    + ** ^If the action code is [SQLITE_READ]
    + ** and the callback returns [SQLITE_IGNORE] then the
    +@@ -2778,6 +3812,10 @@ SQLITE_API void SQLITE_STDCALL sqlite3_randomness(int N, void *P);
    + ** been read if [SQLITE_OK] had been returned.  The [SQLITE_IGNORE]
    + ** return can be used to deny an untrusted user access to individual
    + ** columns of a table.
    ++** ^When a table is referenced by a [SELECT] but no column values are
    ++** extracted from that table (for example in a query like
    ++** "SELECT count(*) FROM tab") then the [SQLITE_READ] authorizer callback
    ++** is invoked once for that table with a column name that is an empty string.
    + ** ^If the action code is [SQLITE_DELETE] and the callback returns
    + ** [SQLITE_IGNORE] then the [DELETE] operation proceeds but the
    + ** [truncate optimization] is disabled and all rows are deleted individually.
    +@@ -2819,7 +3857,7 @@ SQLITE_API void SQLITE_STDCALL sqlite3_randomness(int N, void *P);
    + ** as stated in the previous paragraph, sqlite3_step() invokes
    + ** sqlite3_prepare_v2() to reprepare a statement after a schema change.
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_set_authorizer(
    ++SQLITE_API int sqlite3_set_authorizer(
    +   sqlite3*,
    +   int (*xAuth)(void*,int,const char*,const char*,const char*,const char*),
    +   void *pUserData
    +@@ -2899,6 +3937,9 @@ SQLITE_API int SQLITE_STDCALL sqlite3_set_authorizer(
    + ** CAPI3REF: Tracing And Profiling Functions
    + ** METHOD: sqlite3
    + **
    ++** These routines are deprecated. Use the [sqlite3_trace_v2()] interface
    ++** instead of the routines described here.
    ++**
    + ** These routines register callback functions that can be used for
    + ** tracing and profiling the execution of SQL statements.
    + **
    +@@ -2924,10 +3965,104 @@ SQLITE_API int SQLITE_STDCALL sqlite3_set_authorizer(
    + ** sqlite3_profile() function is considered experimental and is
    + ** subject to change in future versions of SQLite.
    + */
    +-SQLITE_API void *SQLITE_STDCALL sqlite3_trace(sqlite3*, void(*xTrace)(void*,const char*), void*);
    +-SQLITE_API SQLITE_EXPERIMENTAL void *SQLITE_STDCALL sqlite3_profile(sqlite3*,
    ++SQLITE_API SQLITE_DEPRECATED void *sqlite3_trace(sqlite3*,
    ++   void(*xTrace)(void*,const char*), void*);
    ++SQLITE_API SQLITE_DEPRECATED void *sqlite3_profile(sqlite3*,
    +    void(*xProfile)(void*,const char*,sqlite3_uint64), void*);
    + 
    ++/*
    ++** CAPI3REF: SQL Trace Event Codes
    ++** KEYWORDS: SQLITE_TRACE
    ++**
    ++** These constants identify classes of events that can be monitored
    ++** using the [sqlite3_trace_v2()] tracing logic.  The M argument
    ++** to [sqlite3_trace_v2(D,M,X,P)] is an OR-ed combination of one or more of
    ++** the following constants.  ^The first argument to the trace callback
    ++** is one of the following constants.
    ++**
    ++** New tracing constants may be added in future releases.
    ++**
    ++** ^A trace callback has four arguments: xCallback(T,C,P,X).
    ++** ^The T argument is one of the integer type codes above.
    ++** ^The C argument is a copy of the context pointer passed in as the
    ++** fourth argument to [sqlite3_trace_v2()].
    ++** The P and X arguments are pointers whose meanings depend on T.
    ++**
    ++** <dl>
    ++** [[SQLITE_TRACE_STMT]] <dt>SQLITE_TRACE_STMT</dt>
    ++** <dd>^An SQLITE_TRACE_STMT callback is invoked when a prepared statement
    ++** first begins running and possibly at other times during the
    ++** execution of the prepared statement, such as at the start of each
    ++** trigger subprogram. ^The P argument is a pointer to the
    ++** [prepared statement]. ^The X argument is a pointer to a string which
    ++** is the unexpanded SQL text of the prepared statement or an SQL comment 
    ++** that indicates the invocation of a trigger.  ^The callback can compute
    ++** the same text that would have been returned by the legacy [sqlite3_trace()]
    ++** interface by using the X argument when X begins with "--" and invoking
    ++** [sqlite3_expanded_sql(P)] otherwise.
    ++**
    ++** [[SQLITE_TRACE_PROFILE]] <dt>SQLITE_TRACE_PROFILE</dt>
    ++** <dd>^An SQLITE_TRACE_PROFILE callback provides approximately the same
    ++** information as is provided by the [sqlite3_profile()] callback.
    ++** ^The P argument is a pointer to the [prepared statement] and the
    ++** X argument points to a 64-bit integer which is the estimated of
    ++** the number of nanosecond that the prepared statement took to run.
    ++** ^The SQLITE_TRACE_PROFILE callback is invoked when the statement finishes.
    ++**
    ++** [[SQLITE_TRACE_ROW]] <dt>SQLITE_TRACE_ROW</dt>
    ++** <dd>^An SQLITE_TRACE_ROW callback is invoked whenever a prepared
    ++** statement generates a single row of result.  
    ++** ^The P argument is a pointer to the [prepared statement] and the
    ++** X argument is unused.
    ++**
    ++** [[SQLITE_TRACE_CLOSE]] <dt>SQLITE_TRACE_CLOSE</dt>
    ++** <dd>^An SQLITE_TRACE_CLOSE callback is invoked when a database
    ++** connection closes.
    ++** ^The P argument is a pointer to the [database connection] object
    ++** and the X argument is unused.
    ++** </dl>
    ++*/
    ++#define SQLITE_TRACE_STMT       0x01
    ++#define SQLITE_TRACE_PROFILE    0x02
    ++#define SQLITE_TRACE_ROW        0x04
    ++#define SQLITE_TRACE_CLOSE      0x08
    ++
    ++/*
    ++** CAPI3REF: SQL Trace Hook
    ++** METHOD: sqlite3
    ++**
    ++** ^The sqlite3_trace_v2(D,M,X,P) interface registers a trace callback
    ++** function X against [database connection] D, using property mask M
    ++** and context pointer P.  ^If the X callback is
    ++** NULL or if the M mask is zero, then tracing is disabled.  The
    ++** M argument should be the bitwise OR-ed combination of
    ++** zero or more [SQLITE_TRACE] constants.
    ++**
    ++** ^Each call to either sqlite3_trace() or sqlite3_trace_v2() overrides 
    ++** (cancels) any prior calls to sqlite3_trace() or sqlite3_trace_v2().
    ++**
    ++** ^The X callback is invoked whenever any of the events identified by 
    ++** mask M occur.  ^The integer return value from the callback is currently
    ++** ignored, though this may change in future releases.  Callback
    ++** implementations should return zero to ensure future compatibility.
    ++**
    ++** ^A trace callback is invoked with four arguments: callback(T,C,P,X).
    ++** ^The T argument is one of the [SQLITE_TRACE]
    ++** constants to indicate why the callback was invoked.
    ++** ^The C argument is a copy of the context pointer.
    ++** The P and X arguments are pointers whose meanings depend on T.
    ++**
    ++** The sqlite3_trace_v2() interface is intended to replace the legacy
    ++** interfaces [sqlite3_trace()] and [sqlite3_profile()], both of which
    ++** are deprecated.
    ++*/
    ++SQLITE_API int sqlite3_trace_v2(
    ++  sqlite3*,
    ++  unsigned uMask,
    ++  int(*xCallback)(unsigned,void*,void*,void*),
    ++  void *pCtx
    ++);
    ++
    + /*
    + ** CAPI3REF: Query Progress Callbacks
    + ** METHOD: sqlite3
    +@@ -2960,7 +4095,7 @@ SQLITE_API SQLITE_EXPERIMENTAL void *SQLITE_STDCALL sqlite3_profile(sqlite3*,
    + ** database connections for the meaning of "modify" in this paragraph.
    + **
    + */
    +-SQLITE_API void SQLITE_STDCALL sqlite3_progress_handler(sqlite3*, int, int(*)(void*), void*);
    ++SQLITE_API void sqlite3_progress_handler(sqlite3*, int, int(*)(void*), void*);
    + 
    + /*
    + ** CAPI3REF: Opening A New Database Connection
    +@@ -3050,10 +4185,10 @@ SQLITE_API void SQLITE_STDCALL sqlite3_progress_handler(sqlite3*, int, int(*)(vo
    + ** ^If [URI filename] interpretation is enabled, and the filename argument
    + ** begins with "file:", then the filename is interpreted as a URI. ^URI
    + ** filename interpretation is enabled if the [SQLITE_OPEN_URI] flag is
    +-** set in the fourth argument to sqlite3_open_v2(), or if it has
    ++** set in the third argument to sqlite3_open_v2(), or if it has
    + ** been enabled globally using the [SQLITE_CONFIG_URI] option with the
    + ** [sqlite3_config()] method or by the [SQLITE_USE_URI] compile-time option.
    +-** As of SQLite version 3.7.7, URI filename interpretation is turned off
    ++** URI filename interpretation is turned off
    + ** by default, but future releases of SQLite might enable URI filename
    + ** interpretation by default.  See "[URI filenames]" for additional
    + ** information.
    +@@ -3189,15 +4324,15 @@ SQLITE_API void SQLITE_STDCALL sqlite3_progress_handler(sqlite3*, int, int(*)(vo
    + **
    + ** See also: [sqlite3_temp_directory]
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_open(
    ++SQLITE_API int sqlite3_open(
    +   const char *filename,   /* Database filename (UTF-8) */
    +   sqlite3 **ppDb          /* OUT: SQLite db handle */
    + );
    +-SQLITE_API int SQLITE_STDCALL sqlite3_open16(
    ++SQLITE_API int sqlite3_open16(
    +   const void *filename,   /* Database filename (UTF-16) */
    +   sqlite3 **ppDb          /* OUT: SQLite db handle */
    + );
    +-SQLITE_API int SQLITE_STDCALL sqlite3_open_v2(
    ++SQLITE_API int sqlite3_open_v2(
    +   const char *filename,   /* Database filename (UTF-8) */
    +   sqlite3 **ppDb,         /* OUT: SQLite db handle */
    +   int flags,              /* Flags */
    +@@ -3243,9 +4378,9 @@ SQLITE_API int SQLITE_STDCALL sqlite3_open_v2(
    + ** VFS method, then the behavior of this routine is undefined and probably
    + ** undesirable.
    + */
    +-SQLITE_API const char *SQLITE_STDCALL sqlite3_uri_parameter(const char *zFilename, const char *zParam);
    +-SQLITE_API int SQLITE_STDCALL sqlite3_uri_boolean(const char *zFile, const char *zParam, int bDefault);
    +-SQLITE_API sqlite3_int64 SQLITE_STDCALL sqlite3_uri_int64(const char*, const char*, sqlite3_int64);
    ++SQLITE_API const char *sqlite3_uri_parameter(const char *zFilename, const char *zParam);
    ++SQLITE_API int sqlite3_uri_boolean(const char *zFile, const char *zParam, int bDefault);
    ++SQLITE_API sqlite3_int64 sqlite3_uri_int64(const char*, const char*, sqlite3_int64);
    + 
    + 
    + /*
    +@@ -3289,11 +4424,11 @@ SQLITE_API sqlite3_int64 SQLITE_STDCALL sqlite3_uri_int64(const char*, const cha
    + ** was invoked incorrectly by the application.  In that case, the
    + ** error code and message may or may not be set.
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_errcode(sqlite3 *db);
    +-SQLITE_API int SQLITE_STDCALL sqlite3_extended_errcode(sqlite3 *db);
    +-SQLITE_API const char *SQLITE_STDCALL sqlite3_errmsg(sqlite3*);
    +-SQLITE_API const void *SQLITE_STDCALL sqlite3_errmsg16(sqlite3*);
    +-SQLITE_API const char *SQLITE_STDCALL sqlite3_errstr(int);
    ++SQLITE_API int sqlite3_errcode(sqlite3 *db);
    ++SQLITE_API int sqlite3_extended_errcode(sqlite3 *db);
    ++SQLITE_API const char *sqlite3_errmsg(sqlite3*);
    ++SQLITE_API const void *sqlite3_errmsg16(sqlite3*);
    ++SQLITE_API const char *sqlite3_errstr(int);
    + 
    + /*
    + ** CAPI3REF: Prepared Statement Object
    +@@ -3361,7 +4496,7 @@ typedef struct sqlite3_stmt sqlite3_stmt;
    + **
    + ** New run-time limit categories may be added in future releases.
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_limit(sqlite3*, int id, int newVal);
    ++SQLITE_API int sqlite3_limit(sqlite3*, int id, int newVal);
    + 
    + /*
    + ** CAPI3REF: Run-Time Limit Categories
    +@@ -3392,9 +4527,9 @@ SQLITE_API int SQLITE_STDCALL sqlite3_limit(sqlite3*, int id, int newVal);
    + **
    + ** [[SQLITE_LIMIT_VDBE_OP]] ^(<dt>SQLITE_LIMIT_VDBE_OP</dt>
    + ** <dd>The maximum number of instructions in a virtual machine program
    +-** used to implement an SQL statement.  This limit is not currently
    +-** enforced, though that might be added in some future release of
    +-** SQLite.</dd>)^
    ++** used to implement an SQL statement.  If [sqlite3_prepare_v2()] or
    ++** the equivalent tries to allocate space for more than this many opcodes
    ++** in a single prepared statement, an SQLITE_NOMEM error is returned.</dd>)^
    + **
    + ** [[SQLITE_LIMIT_FUNCTION_ARG]] ^(<dt>SQLITE_LIMIT_FUNCTION_ARG</dt>
    + ** <dd>The maximum number of arguments on a function.</dd>)^
    +@@ -3432,23 +4567,59 @@ SQLITE_API int SQLITE_STDCALL sqlite3_limit(sqlite3*, int id, int newVal);
    + #define SQLITE_LIMIT_TRIGGER_DEPTH            10
    + #define SQLITE_LIMIT_WORKER_THREADS           11
    + 
    ++/*
    ++** CAPI3REF: Prepare Flags
    ++**
    ++** These constants define various flags that can be passed into
    ++** "prepFlags" parameter of the [sqlite3_prepare_v3()] and
    ++** [sqlite3_prepare16_v3()] interfaces.
    ++**
    ++** New flags may be added in future releases of SQLite.
    ++**
    ++** <dl>
    ++** [[SQLITE_PREPARE_PERSISTENT]] ^(<dt>SQLITE_PREPARE_PERSISTENT</dt>
    ++** <dd>The SQLITE_PREPARE_PERSISTENT flag is a hint to the query planner
    ++** that the prepared statement will be retained for a long time and
    ++** probably reused many times.)^ ^Without this flag, [sqlite3_prepare_v3()]
    ++** and [sqlite3_prepare16_v3()] assume that the prepared statement will 
    ++** be used just once or at most a few times and then destroyed using
    ++** [sqlite3_finalize()] relatively soon. The current implementation acts
    ++** on this hint by avoiding the use of [lookaside memory] so as not to
    ++** deplete the limited store of lookaside memory. Future versions of
    ++** SQLite may act on this hint differently.
    ++** </dl>
    ++*/
    ++#define SQLITE_PREPARE_PERSISTENT              0x01
    ++
    + /*
    + ** CAPI3REF: Compiling An SQL Statement
    + ** KEYWORDS: {SQL statement compiler}
    + ** METHOD: sqlite3
    + ** CONSTRUCTOR: sqlite3_stmt
    + **
    +-** To execute an SQL query, it must first be compiled into a byte-code
    +-** program using one of these routines.
    ++** To execute an SQL statement, it must first be compiled into a byte-code
    ++** program using one of these routines.  Or, in other words, these routines
    ++** are constructors for the [prepared statement] object.
    ++**
    ++** The preferred routine to use is [sqlite3_prepare_v2()].  The
    ++** [sqlite3_prepare()] interface is legacy and should be avoided.
    ++** [sqlite3_prepare_v3()] has an extra "prepFlags" option that is used
    ++** for special purposes.
    ++**
    ++** The use of the UTF-8 interfaces is preferred, as SQLite currently
    ++** does all parsing using UTF-8.  The UTF-16 interfaces are provided
    ++** as a convenience.  The UTF-16 interfaces work by converting the
    ++** input text into UTF-8, then invoking the corresponding UTF-8 interface.
    + **
    + ** The first argument, "db", is a [database connection] obtained from a
    + ** prior successful call to [sqlite3_open()], [sqlite3_open_v2()] or
    + ** [sqlite3_open16()].  The database connection must not have been closed.
    + **
    + ** The second argument, "zSql", is the statement to be compiled, encoded
    +-** as either UTF-8 or UTF-16.  The sqlite3_prepare() and sqlite3_prepare_v2()
    +-** interfaces use UTF-8, and sqlite3_prepare16() and sqlite3_prepare16_v2()
    +-** use UTF-16.
    ++** as either UTF-8 or UTF-16.  The sqlite3_prepare(), sqlite3_prepare_v2(),
    ++** and sqlite3_prepare_v3()
    ++** interfaces use UTF-8, and sqlite3_prepare16(), sqlite3_prepare16_v2(),
    ++** and sqlite3_prepare16_v3() use UTF-16.
    + **
    + ** ^If the nByte argument is negative, then zSql is read up to the
    + ** first zero terminator. ^If nByte is positive, then it is the
    +@@ -3475,10 +4646,11 @@ SQLITE_API int SQLITE_STDCALL sqlite3_limit(sqlite3*, int id, int newVal);
    + ** ^On success, the sqlite3_prepare() family of routines return [SQLITE_OK];
    + ** otherwise an [error code] is returned.
    + **
    +-** The sqlite3_prepare_v2() and sqlite3_prepare16_v2() interfaces are
    +-** recommended for all new programs. The two older interfaces are retained
    +-** for backwards compatibility, but their use is discouraged.
    +-** ^In the "v2" interfaces, the prepared statement
    ++** The sqlite3_prepare_v2(), sqlite3_prepare_v3(), sqlite3_prepare16_v2(),
    ++** and sqlite3_prepare16_v3() interfaces are recommended for all new programs.
    ++** The older interfaces (sqlite3_prepare() and sqlite3_prepare16())
    ++** are retained for backwards compatibility, but their use is discouraged.
    ++** ^In the "vX" interfaces, the prepared statement
    + ** that is returned (the [sqlite3_stmt] object) contains a copy of the
    + ** original SQL text. This causes the [sqlite3_step()] interface to
    + ** behave differently in three ways:
    +@@ -3511,46 +4683,93 @@ SQLITE_API int SQLITE_STDCALL sqlite3_limit(sqlite3*, int id, int newVal);
    + ** or [GLOB] operator or if the parameter is compared to an indexed column
    + ** and the [SQLITE_ENABLE_STAT3] compile-time option is enabled.
    + ** </li>
    ++**
    ++** <p>^sqlite3_prepare_v3() differs from sqlite3_prepare_v2() only in having
    ++** the extra prepFlags parameter, which is a bit array consisting of zero or
    ++** more of the [SQLITE_PREPARE_PERSISTENT|SQLITE_PREPARE_*] flags.  ^The
    ++** sqlite3_prepare_v2() interface works exactly the same as
    ++** sqlite3_prepare_v3() with a zero prepFlags parameter.
    + ** </ol>
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_prepare(
    ++SQLITE_API int sqlite3_prepare(
    ++  sqlite3 *db,            /* Database handle */
    ++  const char *zSql,       /* SQL statement, UTF-8 encoded */
    ++  int nByte,              /* Maximum length of zSql in bytes. */
    ++  sqlite3_stmt **ppStmt,  /* OUT: Statement handle */
    ++  const char **pzTail     /* OUT: Pointer to unused portion of zSql */
    ++);
    ++SQLITE_API int sqlite3_prepare_v2(
    +   sqlite3 *db,            /* Database handle */
    +   const char *zSql,       /* SQL statement, UTF-8 encoded */
    +   int nByte,              /* Maximum length of zSql in bytes. */
    +   sqlite3_stmt **ppStmt,  /* OUT: Statement handle */
    +   const char **pzTail     /* OUT: Pointer to unused portion of zSql */
    + );
    +-SQLITE_API int SQLITE_STDCALL sqlite3_prepare_v2(
    ++SQLITE_API int sqlite3_prepare_v3(
    +   sqlite3 *db,            /* Database handle */
    +   const char *zSql,       /* SQL statement, UTF-8 encoded */
    +   int nByte,              /* Maximum length of zSql in bytes. */
    ++  unsigned int prepFlags, /* Zero or more SQLITE_PREPARE_ flags */
    +   sqlite3_stmt **ppStmt,  /* OUT: Statement handle */
    +   const char **pzTail     /* OUT: Pointer to unused portion of zSql */
    + );
    +-SQLITE_API int SQLITE_STDCALL sqlite3_prepare16(
    ++SQLITE_API int sqlite3_prepare16(
    +   sqlite3 *db,            /* Database handle */
    +   const void *zSql,       /* SQL statement, UTF-16 encoded */
    +   int nByte,              /* Maximum length of zSql in bytes. */
    +   sqlite3_stmt **ppStmt,  /* OUT: Statement handle */
    +   const void **pzTail     /* OUT: Pointer to unused portion of zSql */
    + );
    +-SQLITE_API int SQLITE_STDCALL sqlite3_prepare16_v2(
    ++SQLITE_API int sqlite3_prepare16_v2(
    +   sqlite3 *db,            /* Database handle */
    +   const void *zSql,       /* SQL statement, UTF-16 encoded */
    +   int nByte,              /* Maximum length of zSql in bytes. */
    +   sqlite3_stmt **ppStmt,  /* OUT: Statement handle */
    +   const void **pzTail     /* OUT: Pointer to unused portion of zSql */
    + );
    ++SQLITE_API int sqlite3_prepare16_v3(
    ++  sqlite3 *db,            /* Database handle */
    ++  const void *zSql,       /* SQL statement, UTF-16 encoded */
    ++  int nByte,              /* Maximum length of zSql in bytes. */
    ++  unsigned int prepFlags, /* Zero or more SQLITE_PREPARE_ flags */
    ++  sqlite3_stmt **ppStmt,  /* OUT: Statement handle */
    ++  const void **pzTail     /* OUT: Pointer to unused portion of zSql */
    ++);
    + 
    + /*
    + ** CAPI3REF: Retrieving Statement SQL
    + ** METHOD: sqlite3_stmt
    + **
    +-** ^This interface can be used to retrieve a saved copy of the original
    +-** SQL text used to create a [prepared statement] if that statement was
    +-** compiled using either [sqlite3_prepare_v2()] or [sqlite3_prepare16_v2()].
    ++** ^The sqlite3_sql(P) interface returns a pointer to a copy of the UTF-8
    ++** SQL text used to create [prepared statement] P if P was
    ++** created by [sqlite3_prepare_v2()], [sqlite3_prepare_v3()],
    ++** [sqlite3_prepare16_v2()], or [sqlite3_prepare16_v3()].
    ++** ^The sqlite3_expanded_sql(P) interface returns a pointer to a UTF-8
    ++** string containing the SQL text of prepared statement P with
    ++** [bound parameters] expanded.
    ++**
    ++** ^(For example, if a prepared statement is created using the SQL
    ++** text "SELECT $abc,:xyz" and if parameter $abc is bound to integer 2345
    ++** and parameter :xyz is unbound, then sqlite3_sql() will return
    ++** the original string, "SELECT $abc,:xyz" but sqlite3_expanded_sql()
    ++** will return "SELECT 2345,NULL".)^
    ++**
    ++** ^The sqlite3_expanded_sql() interface returns NULL if insufficient memory
    ++** is available to hold the result, or if the result would exceed the
    ++** the maximum string length determined by the [SQLITE_LIMIT_LENGTH].
    ++**
    ++** ^The [SQLITE_TRACE_SIZE_LIMIT] compile-time option limits the size of
    ++** bound parameter expansions.  ^The [SQLITE_OMIT_TRACE] compile-time
    ++** option causes sqlite3_expanded_sql() to always return NULL.
    ++**
    ++** ^The string returned by sqlite3_sql(P) is managed by SQLite and is
    ++** automatically freed when the prepared statement is finalized.
    ++** ^The string returned by sqlite3_expanded_sql(P), on the other hand,
    ++** is obtained from [sqlite3_malloc()] and must be free by the application
    ++** by passing it to [sqlite3_free()].
    + */
    +-SQLITE_API const char *SQLITE_STDCALL sqlite3_sql(sqlite3_stmt *pStmt);
    ++SQLITE_API const char *sqlite3_sql(sqlite3_stmt *pStmt);
    ++SQLITE_API char *sqlite3_expanded_sql(sqlite3_stmt *pStmt);
    + 
    + /*
    + ** CAPI3REF: Determine If An SQL Statement Writes The Database
    +@@ -3581,8 +4800,12 @@ SQLITE_API const char *SQLITE_STDCALL sqlite3_sql(sqlite3_stmt *pStmt);
    + ** sqlite3_stmt_readonly() to return true since, while those statements
    + ** change the configuration of a database connection, they do not make 
    + ** changes to the content of the database files on disk.
    ++** ^The sqlite3_stmt_readonly() interface returns true for [BEGIN] since
    ++** [BEGIN] merely sets internal flags, but the [BEGIN|BEGIN IMMEDIATE] and
    ++** [BEGIN|BEGIN EXCLUSIVE] commands do touch the database and so
    ++** sqlite3_stmt_readonly() returns false for those commands.
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_stmt_readonly(sqlite3_stmt *pStmt);
    ++SQLITE_API int sqlite3_stmt_readonly(sqlite3_stmt *pStmt);
    + 
    + /*
    + ** CAPI3REF: Determine If A Prepared Statement Has Been Reset
    +@@ -3603,7 +4826,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_stmt_readonly(sqlite3_stmt *pStmt);
    + ** for example, in diagnostic routines to search for prepared 
    + ** statements that are holding a transaction open.
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_stmt_busy(sqlite3_stmt*);
    ++SQLITE_API int sqlite3_stmt_busy(sqlite3_stmt*);
    + 
    + /*
    + ** CAPI3REF: Dynamically Typed Value Object
    +@@ -3639,12 +4862,13 @@ SQLITE_API int SQLITE_STDCALL sqlite3_stmt_busy(sqlite3_stmt*);
    + ** implementation of [application-defined SQL functions] are protected.
    + ** ^The sqlite3_value object returned by
    + ** [sqlite3_column_value()] is unprotected.
    +-** Unprotected sqlite3_value objects may only be used with
    +-** [sqlite3_result_value()] and [sqlite3_bind_value()].
    ++** Unprotected sqlite3_value objects may only be used as arguments
    ++** to [sqlite3_result_value()], [sqlite3_bind_value()], and
    ++** [sqlite3_value_dup()].
    + ** The [sqlite3_value_blob | sqlite3_value_type()] family of
    + ** interfaces require protected sqlite3_value objects.
    + */
    +-typedef struct Mem sqlite3_value;
    ++typedef struct sqlite3_value sqlite3_value;
    + 
    + /*
    + ** CAPI3REF: SQL Function Context Object
    +@@ -3746,6 +4970,15 @@ typedef struct sqlite3_context sqlite3_context;
    + ** [sqlite3_blob_open | incremental BLOB I/O] routines.
    + ** ^A negative value for the zeroblob results in a zero-length BLOB.
    + **
    ++** ^The sqlite3_bind_pointer(S,I,P,T,D) routine causes the I-th parameter in
    ++** [prepared statement] S to have an SQL value of NULL, but to also be
    ++** associated with the pointer P of type T.  ^D is either a NULL pointer or
    ++** a pointer to a destructor function for P. ^SQLite will invoke the
    ++** destructor D with a single argument of P when it is finished using
    ++** P.  The T parameter should be a static string, preferably a string
    ++** literal. The sqlite3_bind_pointer() routine is part of the
    ++** [pointer passing interface] added for SQLite 3.20.0.
    ++**
    + ** ^If any of the sqlite3_bind_*() routines are called with a NULL pointer
    + ** for the [prepared statement] or with a prepared statement for which
    + ** [sqlite3_step()] has been called more recently than [sqlite3_reset()],
    +@@ -3767,20 +5000,21 @@ typedef struct sqlite3_context sqlite3_context;
    + ** See also: [sqlite3_bind_parameter_count()],
    + ** [sqlite3_bind_parameter_name()], and [sqlite3_bind_parameter_index()].
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_bind_blob(sqlite3_stmt*, int, const void*, int n, void(*)(void*));
    +-SQLITE_API int SQLITE_STDCALL sqlite3_bind_blob64(sqlite3_stmt*, int, const void*, sqlite3_uint64,
    ++SQLITE_API int sqlite3_bind_blob(sqlite3_stmt*, int, const void*, int n, void(*)(void*));
    ++SQLITE_API int sqlite3_bind_blob64(sqlite3_stmt*, int, const void*, sqlite3_uint64,
    +                         void(*)(void*));
    +-SQLITE_API int SQLITE_STDCALL sqlite3_bind_double(sqlite3_stmt*, int, double);
    +-SQLITE_API int SQLITE_STDCALL sqlite3_bind_int(sqlite3_stmt*, int, int);
    +-SQLITE_API int SQLITE_STDCALL sqlite3_bind_int64(sqlite3_stmt*, int, sqlite3_int64);
    +-SQLITE_API int SQLITE_STDCALL sqlite3_bind_null(sqlite3_stmt*, int);
    +-SQLITE_API int SQLITE_STDCALL sqlite3_bind_text(sqlite3_stmt*,int,const char*,int,void(*)(void*));
    +-SQLITE_API int SQLITE_STDCALL sqlite3_bind_text16(sqlite3_stmt*, int, const void*, int, void(*)(void*));
    +-SQLITE_API int SQLITE_STDCALL sqlite3_bind_text64(sqlite3_stmt*, int, const char*, sqlite3_uint64,
    ++SQLITE_API int sqlite3_bind_double(sqlite3_stmt*, int, double);
    ++SQLITE_API int sqlite3_bind_int(sqlite3_stmt*, int, int);
    ++SQLITE_API int sqlite3_bind_int64(sqlite3_stmt*, int, sqlite3_int64);
    ++SQLITE_API int sqlite3_bind_null(sqlite3_stmt*, int);
    ++SQLITE_API int sqlite3_bind_text(sqlite3_stmt*,int,const char*,int,void(*)(void*));
    ++SQLITE_API int sqlite3_bind_text16(sqlite3_stmt*, int, const void*, int, void(*)(void*));
    ++SQLITE_API int sqlite3_bind_text64(sqlite3_stmt*, int, const char*, sqlite3_uint64,
    +                          void(*)(void*), unsigned char encoding);
    +-SQLITE_API int SQLITE_STDCALL sqlite3_bind_value(sqlite3_stmt*, int, const sqlite3_value*);
    +-SQLITE_API int SQLITE_STDCALL sqlite3_bind_zeroblob(sqlite3_stmt*, int, int n);
    +-SQLITE_API int SQLITE_STDCALL sqlite3_bind_zeroblob64(sqlite3_stmt*, int, sqlite3_uint64);
    ++SQLITE_API int sqlite3_bind_value(sqlite3_stmt*, int, const sqlite3_value*);
    ++SQLITE_API int sqlite3_bind_pointer(sqlite3_stmt*, int, void*, const char*,void(*)(void*));
    ++SQLITE_API int sqlite3_bind_zeroblob(sqlite3_stmt*, int, int n);
    ++SQLITE_API int sqlite3_bind_zeroblob64(sqlite3_stmt*, int, sqlite3_uint64);
    + 
    + /*
    + ** CAPI3REF: Number Of SQL Parameters
    +@@ -3801,7 +5035,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_bind_zeroblob64(sqlite3_stmt*, int, sqlite
    + ** [sqlite3_bind_parameter_name()], and
    + ** [sqlite3_bind_parameter_index()].
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_bind_parameter_count(sqlite3_stmt*);
    ++SQLITE_API int sqlite3_bind_parameter_count(sqlite3_stmt*);
    + 
    + /*
    + ** CAPI3REF: Name Of A Host Parameter
    +@@ -3822,14 +5056,14 @@ SQLITE_API int SQLITE_STDCALL sqlite3_bind_parameter_count(sqlite3_stmt*);
    + ** ^If the value N is out of range or if the N-th parameter is
    + ** nameless, then NULL is returned.  ^The returned string is
    + ** always in UTF-8 encoding even if the named parameter was
    +-** originally specified as UTF-16 in [sqlite3_prepare16()] or
    +-** [sqlite3_prepare16_v2()].
    ++** originally specified as UTF-16 in [sqlite3_prepare16()],
    ++** [sqlite3_prepare16_v2()], or [sqlite3_prepare16_v3()].
    + **
    + ** See also: [sqlite3_bind_blob|sqlite3_bind()],
    + ** [sqlite3_bind_parameter_count()], and
    + ** [sqlite3_bind_parameter_index()].
    + */
    +-SQLITE_API const char *SQLITE_STDCALL sqlite3_bind_parameter_name(sqlite3_stmt*, int);
    ++SQLITE_API const char *sqlite3_bind_parameter_name(sqlite3_stmt*, int);
    + 
    + /*
    + ** CAPI3REF: Index Of A Parameter With A Given Name
    +@@ -3840,13 +5074,14 @@ SQLITE_API const char *SQLITE_STDCALL sqlite3_bind_parameter_name(sqlite3_stmt*,
    + ** parameter to [sqlite3_bind_blob|sqlite3_bind()].  ^A zero
    + ** is returned if no matching parameter is found.  ^The parameter
    + ** name must be given in UTF-8 even if the original statement
    +-** was prepared from UTF-16 text using [sqlite3_prepare16_v2()].
    ++** was prepared from UTF-16 text using [sqlite3_prepare16_v2()] or
    ++** [sqlite3_prepare16_v3()].
    + **
    + ** See also: [sqlite3_bind_blob|sqlite3_bind()],
    + ** [sqlite3_bind_parameter_count()], and
    + ** [sqlite3_bind_parameter_name()].
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_bind_parameter_index(sqlite3_stmt*, const char *zName);
    ++SQLITE_API int sqlite3_bind_parameter_index(sqlite3_stmt*, const char *zName);
    + 
    + /*
    + ** CAPI3REF: Reset All Bindings On A Prepared Statement
    +@@ -3856,19 +5091,23 @@ SQLITE_API int SQLITE_STDCALL sqlite3_bind_parameter_index(sqlite3_stmt*, const
    + ** the [sqlite3_bind_blob | bindings] on a [prepared statement].
    + ** ^Use this routine to reset all host parameters to NULL.
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_clear_bindings(sqlite3_stmt*);
    ++SQLITE_API int sqlite3_clear_bindings(sqlite3_stmt*);
    + 
    + /*
    + ** CAPI3REF: Number Of Columns In A Result Set
    + ** METHOD: sqlite3_stmt
    + **
    + ** ^Return the number of columns in the result set returned by the
    +-** [prepared statement]. ^This routine returns 0 if pStmt is an SQL
    +-** statement that does not return data (for example an [UPDATE]).
    ++** [prepared statement]. ^If this routine returns 0, that means the 
    ++** [prepared statement] returns no data (for example an [UPDATE]).
    ++** ^However, just because this routine returns a positive number does not
    ++** mean that one or more rows of data will be returned.  ^A SELECT statement
    ++** will always have a positive sqlite3_column_count() but depending on the
    ++** WHERE clause constraints and the table content, it might return no rows.
    + **
    + ** See also: [sqlite3_data_count()]
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_column_count(sqlite3_stmt *pStmt);
    ++SQLITE_API int sqlite3_column_count(sqlite3_stmt *pStmt);
    + 
    + /*
    + ** CAPI3REF: Column Names In A Result Set
    +@@ -3897,8 +5136,8 @@ SQLITE_API int SQLITE_STDCALL sqlite3_column_count(sqlite3_stmt *pStmt);
    + ** then the name of the column is unspecified and may change from
    + ** one release of SQLite to the next.
    + */
    +-SQLITE_API const char *SQLITE_STDCALL sqlite3_column_name(sqlite3_stmt*, int N);
    +-SQLITE_API const void *SQLITE_STDCALL sqlite3_column_name16(sqlite3_stmt*, int N);
    ++SQLITE_API const char *sqlite3_column_name(sqlite3_stmt*, int N);
    ++SQLITE_API const void *sqlite3_column_name16(sqlite3_stmt*, int N);
    + 
    + /*
    + ** CAPI3REF: Source Of Data In A Query Result
    +@@ -3946,12 +5185,12 @@ SQLITE_API const void *SQLITE_STDCALL sqlite3_column_name16(sqlite3_stmt*, int N
    + ** for the same [prepared statement] and result column
    + ** at the same time then the results are undefined.
    + */
    +-SQLITE_API const char *SQLITE_STDCALL sqlite3_column_database_name(sqlite3_stmt*,int);
    +-SQLITE_API const void *SQLITE_STDCALL sqlite3_column_database_name16(sqlite3_stmt*,int);
    +-SQLITE_API const char *SQLITE_STDCALL sqlite3_column_table_name(sqlite3_stmt*,int);
    +-SQLITE_API const void *SQLITE_STDCALL sqlite3_column_table_name16(sqlite3_stmt*,int);
    +-SQLITE_API const char *SQLITE_STDCALL sqlite3_column_origin_name(sqlite3_stmt*,int);
    +-SQLITE_API const void *SQLITE_STDCALL sqlite3_column_origin_name16(sqlite3_stmt*,int);
    ++SQLITE_API const char *sqlite3_column_database_name(sqlite3_stmt*,int);
    ++SQLITE_API const void *sqlite3_column_database_name16(sqlite3_stmt*,int);
    ++SQLITE_API const char *sqlite3_column_table_name(sqlite3_stmt*,int);
    ++SQLITE_API const void *sqlite3_column_table_name16(sqlite3_stmt*,int);
    ++SQLITE_API const char *sqlite3_column_origin_name(sqlite3_stmt*,int);
    ++SQLITE_API const void *sqlite3_column_origin_name16(sqlite3_stmt*,int);
    + 
    + /*
    + ** CAPI3REF: Declared Datatype Of A Query Result
    +@@ -3983,23 +5222,25 @@ SQLITE_API const void *SQLITE_STDCALL sqlite3_column_origin_name16(sqlite3_stmt*
    + ** is associated with individual values, not with the containers
    + ** used to hold those values.
    + */
    +-SQLITE_API const char *SQLITE_STDCALL sqlite3_column_decltype(sqlite3_stmt*,int);
    +-SQLITE_API const void *SQLITE_STDCALL sqlite3_column_decltype16(sqlite3_stmt*,int);
    ++SQLITE_API const char *sqlite3_column_decltype(sqlite3_stmt*,int);
    ++SQLITE_API const void *sqlite3_column_decltype16(sqlite3_stmt*,int);
    + 
    + /*
    + ** CAPI3REF: Evaluate An SQL Statement
    + ** METHOD: sqlite3_stmt
    + **
    +-** After a [prepared statement] has been prepared using either
    +-** [sqlite3_prepare_v2()] or [sqlite3_prepare16_v2()] or one of the legacy
    ++** After a [prepared statement] has been prepared using any of
    ++** [sqlite3_prepare_v2()], [sqlite3_prepare_v3()], [sqlite3_prepare16_v2()],
    ++** or [sqlite3_prepare16_v3()] or one of the legacy
    + ** interfaces [sqlite3_prepare()] or [sqlite3_prepare16()], this function
    + ** must be called one or more times to evaluate the statement.
    + **
    + ** The details of the behavior of the sqlite3_step() interface depend
    +-** on whether the statement was prepared using the newer "v2" interface
    +-** [sqlite3_prepare_v2()] and [sqlite3_prepare16_v2()] or the older legacy
    +-** interface [sqlite3_prepare()] and [sqlite3_prepare16()].  The use of the
    +-** new "v2" interface is recommended for new applications but the legacy
    ++** on whether the statement was prepared using the newer "vX" interfaces
    ++** [sqlite3_prepare_v3()], [sqlite3_prepare_v2()], [sqlite3_prepare16_v3()],
    ++** [sqlite3_prepare16_v2()] or the older legacy
    ++** interfaces [sqlite3_prepare()] and [sqlite3_prepare16()].  The use of the
    ++** new "vX" interface is recommended for new applications but the legacy
    + ** interface will continue to be supported.
    + **
    + ** ^In the legacy interface, the return value will be either [SQLITE_BUSY],
    +@@ -4045,7 +5286,8 @@ SQLITE_API const void *SQLITE_STDCALL sqlite3_column_decltype16(sqlite3_stmt*,in
    + ** other than [SQLITE_ROW] before any subsequent invocation of
    + ** sqlite3_step().  Failure to reset the prepared statement using 
    + ** [sqlite3_reset()] would result in an [SQLITE_MISUSE] return from
    +-** sqlite3_step().  But after version 3.6.23.1, sqlite3_step() began
    ++** sqlite3_step().  But after [version 3.6.23.1] ([dateof:3.6.23.1],
    ++** sqlite3_step() began
    + ** calling [sqlite3_reset()] automatically in this circumstance rather
    + ** than returning [SQLITE_MISUSE].  This is not considered a compatibility
    + ** break because any application that ever receives an SQLITE_MISUSE error
    +@@ -4059,12 +5301,13 @@ SQLITE_API const void *SQLITE_STDCALL sqlite3_column_decltype16(sqlite3_stmt*,in
    + ** specific [error codes] that better describes the error.
    + ** We admit that this is a goofy design.  The problem has been fixed
    + ** with the "v2" interface.  If you prepare all of your SQL statements
    +-** using either [sqlite3_prepare_v2()] or [sqlite3_prepare16_v2()] instead
    ++** using [sqlite3_prepare_v3()] or [sqlite3_prepare_v2()]
    ++** or [sqlite3_prepare16_v2()] or [sqlite3_prepare16_v3()] instead
    + ** of the legacy [sqlite3_prepare()] and [sqlite3_prepare16()] interfaces,
    + ** then the more specific [error codes] are returned directly
    +-** by sqlite3_step().  The use of the "v2" interface is recommended.
    ++** by sqlite3_step().  The use of the "vX" interfaces is recommended.
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_step(sqlite3_stmt*);
    ++SQLITE_API int sqlite3_step(sqlite3_stmt*);
    + 
    + /*
    + ** CAPI3REF: Number of columns in a result set
    +@@ -4085,7 +5328,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_step(sqlite3_stmt*);
    + **
    + ** See also: [sqlite3_column_count()]
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_data_count(sqlite3_stmt *pStmt);
    ++SQLITE_API int sqlite3_data_count(sqlite3_stmt *pStmt);
    + 
    + /*
    + ** CAPI3REF: Fundamental Datatypes
    +@@ -4124,6 +5367,28 @@ SQLITE_API int SQLITE_STDCALL sqlite3_data_count(sqlite3_stmt *pStmt);
    + ** KEYWORDS: {column access functions}
    + ** METHOD: sqlite3_stmt
    + **
    ++** <b>Summary:</b>
    ++** <blockquote><table border=0 cellpadding=0 cellspacing=0>
    ++** <tr><td><b>sqlite3_column_blob</b><td>&rarr;<td>BLOB result
    ++** <tr><td><b>sqlite3_column_double</b><td>&rarr;<td>REAL result
    ++** <tr><td><b>sqlite3_column_int</b><td>&rarr;<td>32-bit INTEGER result
    ++** <tr><td><b>sqlite3_column_int64</b><td>&rarr;<td>64-bit INTEGER result
    ++** <tr><td><b>sqlite3_column_text</b><td>&rarr;<td>UTF-8 TEXT result
    ++** <tr><td><b>sqlite3_column_text16</b><td>&rarr;<td>UTF-16 TEXT result
    ++** <tr><td><b>sqlite3_column_value</b><td>&rarr;<td>The result as an 
    ++** [sqlite3_value|unprotected sqlite3_value] object.
    ++** <tr><td>&nbsp;<td>&nbsp;<td>&nbsp;
    ++** <tr><td><b>sqlite3_column_bytes</b><td>&rarr;<td>Size of a BLOB
    ++** or a UTF-8 TEXT result in bytes
    ++** <tr><td><b>sqlite3_column_bytes16&nbsp;&nbsp;</b>
    ++** <td>&rarr;&nbsp;&nbsp;<td>Size of UTF-16
    ++** TEXT in bytes
    ++** <tr><td><b>sqlite3_column_type</b><td>&rarr;<td>Default
    ++** datatype of the result
    ++** </table></blockquote>
    ++**
    ++** <b>Details:</b>
    ++**
    + ** ^These routines return information about a single column of the current
    + ** result row of a query.  ^In every case the first argument is a pointer
    + ** to the [prepared statement] that is being evaluated (the [sqlite3_stmt*]
    +@@ -4145,16 +5410,29 @@ SQLITE_API int SQLITE_STDCALL sqlite3_data_count(sqlite3_stmt *pStmt);
    + ** are called from a different thread while any of these routines
    + ** are pending, then the results are undefined.
    + **
    ++** The first six interfaces (_blob, _double, _int, _int64, _text, and _text16)
    ++** each return the value of a result column in a specific data format.  If
    ++** the result column is not initially in the requested format (for example,
    ++** if the query returns an integer but the sqlite3_column_text() interface
    ++** is used to extract the value) then an automatic type conversion is performed.
    ++**
    + ** ^The sqlite3_column_type() routine returns the
    + ** [SQLITE_INTEGER | datatype code] for the initial data type
    + ** of the result column.  ^The returned value is one of [SQLITE_INTEGER],
    +-** [SQLITE_FLOAT], [SQLITE_TEXT], [SQLITE_BLOB], or [SQLITE_NULL].  The value
    +-** returned by sqlite3_column_type() is only meaningful if no type
    +-** conversions have occurred as described below.  After a type conversion,
    +-** the value returned by sqlite3_column_type() is undefined.  Future
    ++** [SQLITE_FLOAT], [SQLITE_TEXT], [SQLITE_BLOB], or [SQLITE_NULL].
    ++** The return value of sqlite3_column_type() can be used to decide which
    ++** of the first six interface should be used to extract the column value.
    ++** The value returned by sqlite3_column_type() is only meaningful if no
    ++** automatic type conversions have occurred for the value in question.  
    ++** After a type conversion, the result of calling sqlite3_column_type()
    ++** is undefined, though harmless.  Future
    + ** versions of SQLite may change the behavior of sqlite3_column_type()
    + ** following a type conversion.
    + **
    ++** If the result is a BLOB or a TEXT string, then the sqlite3_column_bytes()
    ++** or sqlite3_column_bytes16() interfaces can be used to determine the size
    ++** of that BLOB or string.
    ++**
    + ** ^If the result is a BLOB or UTF-8 string then the sqlite3_column_bytes()
    + ** routine returns the number of bytes in that BLOB or string.
    + ** ^If the result is a UTF-16 string, then sqlite3_column_bytes() converts
    +@@ -4191,9 +5469,13 @@ SQLITE_API int SQLITE_STDCALL sqlite3_data_count(sqlite3_stmt *pStmt);
    + ** [sqlite3_column_value()] is used in any other way, including calls
    + ** to routines like [sqlite3_value_int()], [sqlite3_value_text()],
    + ** or [sqlite3_value_bytes()], the behavior is not threadsafe.
    ++** Hence, the sqlite3_column_value() interface
    ++** is normally only useful within the implementation of 
    ++** [application-defined SQL functions] or [virtual tables], not within
    ++** top-level application code.
    + **
    +-** These routines attempt to convert the value where appropriate.  ^For
    +-** example, if the internal representation is FLOAT and a text result
    ++** The these routines may attempt to convert the datatype of the result.
    ++** ^For example, if the internal representation is FLOAT and a text result
    + ** is requested, [sqlite3_snprintf()] is used internally to perform the
    + ** conversion automatically.  ^(The following table details the conversions
    + ** that are applied:
    +@@ -4265,7 +5547,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_data_count(sqlite3_stmt *pStmt);
    + ** ^The pointers returned are valid until a type conversion occurs as
    + ** described above, or until [sqlite3_step()] or [sqlite3_reset()] or
    + ** [sqlite3_finalize()] is called.  ^The memory space used to hold strings
    +-** and BLOBs is freed automatically.  Do <em>not</em> pass the pointers returned
    ++** and BLOBs is freed automatically.  Do not pass the pointers returned
    + ** from [sqlite3_column_blob()], [sqlite3_column_text()], etc. into
    + ** [sqlite3_free()].
    + **
    +@@ -4275,16 +5557,16 @@ SQLITE_API int SQLITE_STDCALL sqlite3_data_count(sqlite3_stmt *pStmt);
    + ** pointer.  Subsequent calls to [sqlite3_errcode()] will return
    + ** [SQLITE_NOMEM].)^
    + */
    +-SQLITE_API const void *SQLITE_STDCALL sqlite3_column_blob(sqlite3_stmt*, int iCol);
    +-SQLITE_API int SQLITE_STDCALL sqlite3_column_bytes(sqlite3_stmt*, int iCol);
    +-SQLITE_API int SQLITE_STDCALL sqlite3_column_bytes16(sqlite3_stmt*, int iCol);
    +-SQLITE_API double SQLITE_STDCALL sqlite3_column_double(sqlite3_stmt*, int iCol);
    +-SQLITE_API int SQLITE_STDCALL sqlite3_column_int(sqlite3_stmt*, int iCol);
    +-SQLITE_API sqlite3_int64 SQLITE_STDCALL sqlite3_column_int64(sqlite3_stmt*, int iCol);
    +-SQLITE_API const unsigned char *SQLITE_STDCALL sqlite3_column_text(sqlite3_stmt*, int iCol);
    +-SQLITE_API const void *SQLITE_STDCALL sqlite3_column_text16(sqlite3_stmt*, int iCol);
    +-SQLITE_API int SQLITE_STDCALL sqlite3_column_type(sqlite3_stmt*, int iCol);
    +-SQLITE_API sqlite3_value *SQLITE_STDCALL sqlite3_column_value(sqlite3_stmt*, int iCol);
    ++SQLITE_API const void *sqlite3_column_blob(sqlite3_stmt*, int iCol);
    ++SQLITE_API double sqlite3_column_double(sqlite3_stmt*, int iCol);
    ++SQLITE_API int sqlite3_column_int(sqlite3_stmt*, int iCol);
    ++SQLITE_API sqlite3_int64 sqlite3_column_int64(sqlite3_stmt*, int iCol);
    ++SQLITE_API const unsigned char *sqlite3_column_text(sqlite3_stmt*, int iCol);
    ++SQLITE_API const void *sqlite3_column_text16(sqlite3_stmt*, int iCol);
    ++SQLITE_API sqlite3_value *sqlite3_column_value(sqlite3_stmt*, int iCol);
    ++SQLITE_API int sqlite3_column_bytes(sqlite3_stmt*, int iCol);
    ++SQLITE_API int sqlite3_column_bytes16(sqlite3_stmt*, int iCol);
    ++SQLITE_API int sqlite3_column_type(sqlite3_stmt*, int iCol);
    + 
    + /*
    + ** CAPI3REF: Destroy A Prepared Statement Object
    +@@ -4312,7 +5594,7 @@ SQLITE_API sqlite3_value *SQLITE_STDCALL sqlite3_column_value(sqlite3_stmt*, int
    + ** statement after it has been finalized can result in undefined and
    + ** undesirable behavior such as segfaults and heap corruption.
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_finalize(sqlite3_stmt *pStmt);
    ++SQLITE_API int sqlite3_finalize(sqlite3_stmt *pStmt);
    + 
    + /*
    + ** CAPI3REF: Reset A Prepared Statement Object
    +@@ -4339,7 +5621,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_finalize(sqlite3_stmt *pStmt);
    + ** ^The [sqlite3_reset(S)] interface does not change the values
    + ** of any [sqlite3_bind_blob|bindings] on the [prepared statement] S.
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_reset(sqlite3_stmt *pStmt);
    ++SQLITE_API int sqlite3_reset(sqlite3_stmt *pStmt);
    + 
    + /*
    + ** CAPI3REF: Create Or Redefine SQL Functions
    +@@ -4439,7 +5721,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_reset(sqlite3_stmt *pStmt);
    + ** close the database connection nor finalize or reset the prepared
    + ** statement in which the function is running.
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_create_function(
    ++SQLITE_API int sqlite3_create_function(
    +   sqlite3 *db,
    +   const char *zFunctionName,
    +   int nArg,
    +@@ -4449,7 +5731,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_create_function(
    +   void (*xStep)(sqlite3_context*,int,sqlite3_value**),
    +   void (*xFinal)(sqlite3_context*)
    + );
    +-SQLITE_API int SQLITE_STDCALL sqlite3_create_function16(
    ++SQLITE_API int sqlite3_create_function16(
    +   sqlite3 *db,
    +   const void *zFunctionName,
    +   int nArg,
    +@@ -4459,7 +5741,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_create_function16(
    +   void (*xStep)(sqlite3_context*,int,sqlite3_value**),
    +   void (*xFinal)(sqlite3_context*)
    + );
    +-SQLITE_API int SQLITE_STDCALL sqlite3_create_function_v2(
    ++SQLITE_API int sqlite3_create_function_v2(
    +   sqlite3 *db,
    +   const char *zFunctionName,
    +   int nArg,
    +@@ -4505,12 +5787,12 @@ SQLITE_API int SQLITE_STDCALL sqlite3_create_function_v2(
    + ** these functions, we will not explain what they do.
    + */
    + #ifndef SQLITE_OMIT_DEPRECATED
    +-SQLITE_API SQLITE_DEPRECATED int SQLITE_STDCALL sqlite3_aggregate_count(sqlite3_context*);
    +-SQLITE_API SQLITE_DEPRECATED int SQLITE_STDCALL sqlite3_expired(sqlite3_stmt*);
    +-SQLITE_API SQLITE_DEPRECATED int SQLITE_STDCALL sqlite3_transfer_bindings(sqlite3_stmt*, sqlite3_stmt*);
    +-SQLITE_API SQLITE_DEPRECATED int SQLITE_STDCALL sqlite3_global_recover(void);
    +-SQLITE_API SQLITE_DEPRECATED void SQLITE_STDCALL sqlite3_thread_cleanup(void);
    +-SQLITE_API SQLITE_DEPRECATED int SQLITE_STDCALL sqlite3_memory_alarm(void(*)(void*,sqlite3_int64,int),
    ++SQLITE_API SQLITE_DEPRECATED int sqlite3_aggregate_count(sqlite3_context*);
    ++SQLITE_API SQLITE_DEPRECATED int sqlite3_expired(sqlite3_stmt*);
    ++SQLITE_API SQLITE_DEPRECATED int sqlite3_transfer_bindings(sqlite3_stmt*, sqlite3_stmt*);
    ++SQLITE_API SQLITE_DEPRECATED int sqlite3_global_recover(void);
    ++SQLITE_API SQLITE_DEPRECATED void sqlite3_thread_cleanup(void);
    ++SQLITE_API SQLITE_DEPRECATED int sqlite3_memory_alarm(void(*)(void*,sqlite3_int64,int),
    +                       void*,sqlite3_int64);
    + #endif
    + 
    +@@ -4518,21 +5800,43 @@ SQLITE_API SQLITE_DEPRECATED int SQLITE_STDCALL sqlite3_memory_alarm(void(*)(voi
    + ** CAPI3REF: Obtaining SQL Values
    + ** METHOD: sqlite3_value
    + **
    +-** The C-language implementation of SQL functions and aggregates uses
    +-** this set of interface routines to access the parameter values on
    +-** the function or aggregate.  
    +-**
    +-** The xFunc (for scalar functions) or xStep (for aggregates) parameters
    +-** to [sqlite3_create_function()] and [sqlite3_create_function16()]
    +-** define callbacks that implement the SQL functions and aggregates.
    +-** The 3rd parameter to these callbacks is an array of pointers to
    +-** [protected sqlite3_value] objects.  There is one [sqlite3_value] object for
    +-** each parameter to the SQL function.  These routines are used to
    +-** extract values from the [sqlite3_value] objects.
    ++** <b>Summary:</b>
    ++** <blockquote><table border=0 cellpadding=0 cellspacing=0>
    ++** <tr><td><b>sqlite3_value_blob</b><td>&rarr;<td>BLOB value
    ++** <tr><td><b>sqlite3_value_double</b><td>&rarr;<td>REAL value
    ++** <tr><td><b>sqlite3_value_int</b><td>&rarr;<td>32-bit INTEGER value
    ++** <tr><td><b>sqlite3_value_int64</b><td>&rarr;<td>64-bit INTEGER value
    ++** <tr><td><b>sqlite3_value_pointer</b><td>&rarr;<td>Pointer value
    ++** <tr><td><b>sqlite3_value_text</b><td>&rarr;<td>UTF-8 TEXT value
    ++** <tr><td><b>sqlite3_value_text16</b><td>&rarr;<td>UTF-16 TEXT value in
    ++** the native byteorder
    ++** <tr><td><b>sqlite3_value_text16be</b><td>&rarr;<td>UTF-16be TEXT value
    ++** <tr><td><b>sqlite3_value_text16le</b><td>&rarr;<td>UTF-16le TEXT value
    ++** <tr><td>&nbsp;<td>&nbsp;<td>&nbsp;
    ++** <tr><td><b>sqlite3_value_bytes</b><td>&rarr;<td>Size of a BLOB
    ++** or a UTF-8 TEXT in bytes
    ++** <tr><td><b>sqlite3_value_bytes16&nbsp;&nbsp;</b>
    ++** <td>&rarr;&nbsp;&nbsp;<td>Size of UTF-16
    ++** TEXT in bytes
    ++** <tr><td><b>sqlite3_value_type</b><td>&rarr;<td>Default
    ++** datatype of the value
    ++** <tr><td><b>sqlite3_value_numeric_type&nbsp;&nbsp;</b>
    ++** <td>&rarr;&nbsp;&nbsp;<td>Best numeric datatype of the value
    ++** <tr><td><b>sqlite3_value_nochange&nbsp;&nbsp;</b>
    ++** <td>&rarr;&nbsp;&nbsp;<td>True if the column is unchanged in an UPDATE
    ++** against a virtual table.
    ++** </table></blockquote>
    ++**
    ++** <b>Details:</b>
    ++**
    ++** These routines extract type, size, and content information from
    ++** [protected sqlite3_value] objects.  Protected sqlite3_value objects
    ++** are used to pass parameter information into implementation of
    ++** [application-defined SQL functions] and [virtual tables].
    + **
    + ** These routines work only with [protected sqlite3_value] objects.
    + ** Any attempt to use these routines on an [unprotected sqlite3_value]
    +-** object results in undefined behavior.
    ++** is not threadsafe.
    + **
    + ** ^These routines work just like the corresponding [column access functions]
    + ** except that these routines take a single [protected sqlite3_value] object
    +@@ -4543,6 +5847,24 @@ SQLITE_API SQLITE_DEPRECATED int SQLITE_STDCALL sqlite3_memory_alarm(void(*)(voi
    + ** sqlite3_value_text16be() and sqlite3_value_text16le() interfaces
    + ** extract UTF-16 strings as big-endian and little-endian respectively.
    + **
    ++** ^If [sqlite3_value] object V was initialized 
    ++** using [sqlite3_bind_pointer(S,I,P,X,D)] or [sqlite3_result_pointer(C,P,X,D)]
    ++** and if X and Y are strings that compare equal according to strcmp(X,Y),
    ++** then sqlite3_value_pointer(V,Y) will return the pointer P.  ^Otherwise,
    ++** sqlite3_value_pointer(V,Y) returns a NULL. The sqlite3_bind_pointer() 
    ++** routine is part of the [pointer passing interface] added for SQLite 3.20.0.
    ++**
    ++** ^(The sqlite3_value_type(V) interface returns the
    ++** [SQLITE_INTEGER | datatype code] for the initial datatype of the
    ++** [sqlite3_value] object V. The returned value is one of [SQLITE_INTEGER],
    ++** [SQLITE_FLOAT], [SQLITE_TEXT], [SQLITE_BLOB], or [SQLITE_NULL].)^
    ++** Other interfaces might change the datatype for an sqlite3_value object.
    ++** For example, if the datatype is initially SQLITE_INTEGER and
    ++** sqlite3_value_text(V) is called to extract a text value for that
    ++** integer, then subsequent calls to sqlite3_value_type(V) might return
    ++** SQLITE_TEXT.  Whether or not a persistent internal datatype conversion
    ++** occurs is undefined and may change from one release of SQLite to the next.
    ++**
    + ** ^(The sqlite3_value_numeric_type() interface attempts to apply
    + ** numeric affinity to the value.  This means that an attempt is
    + ** made to convert the value to an integer or floating point.  If
    +@@ -4551,6 +5873,19 @@ SQLITE_API SQLITE_DEPRECATED int SQLITE_STDCALL sqlite3_memory_alarm(void(*)(voi
    + ** then the conversion is performed.  Otherwise no conversion occurs.
    + ** The [SQLITE_INTEGER | datatype] after conversion is returned.)^
    + **
    ++** ^Within the [xUpdate] method of a [virtual table], the
    ++** sqlite3_value_nochange(X) interface returns true if and only if
    ++** the column corresponding to X is unchanged by the UPDATE operation
    ++** that the xUpdate method call was invoked to implement and if
    ++** and the prior [xColumn] method call that was invoked to extracted
    ++** the value for that column returned without setting a result (probably
    ++** because it queried [sqlite3_vtab_nochange()] and found that the column
    ++** was unchanging).  ^Within an [xUpdate] method, any value for which
    ++** sqlite3_value_nochange(X) is true will in all other respects appear
    ++** to be a NULL value.  If sqlite3_value_nochange(X) is invoked anywhere other
    ++** than within an [xUpdate] method call for an UPDATE statement, then
    ++** the return value is arbitrary and meaningless.
    ++**
    + ** Please pay particular attention to the fact that the pointer returned
    + ** from [sqlite3_value_blob()], [sqlite3_value_text()], or
    + ** [sqlite3_value_text16()] can be invalidated by a subsequent call to
    +@@ -4560,18 +5895,20 @@ SQLITE_API SQLITE_DEPRECATED int SQLITE_STDCALL sqlite3_memory_alarm(void(*)(voi
    + ** These routines must be called from the same thread as
    + ** the SQL function that supplied the [sqlite3_value*] parameters.
    + */
    +-SQLITE_API const void *SQLITE_STDCALL sqlite3_value_blob(sqlite3_value*);
    +-SQLITE_API int SQLITE_STDCALL sqlite3_value_bytes(sqlite3_value*);
    +-SQLITE_API int SQLITE_STDCALL sqlite3_value_bytes16(sqlite3_value*);
    +-SQLITE_API double SQLITE_STDCALL sqlite3_value_double(sqlite3_value*);
    +-SQLITE_API int SQLITE_STDCALL sqlite3_value_int(sqlite3_value*);
    +-SQLITE_API sqlite3_int64 SQLITE_STDCALL sqlite3_value_int64(sqlite3_value*);
    +-SQLITE_API const unsigned char *SQLITE_STDCALL sqlite3_value_text(sqlite3_value*);
    +-SQLITE_API const void *SQLITE_STDCALL sqlite3_value_text16(sqlite3_value*);
    +-SQLITE_API const void *SQLITE_STDCALL sqlite3_value_text16le(sqlite3_value*);
    +-SQLITE_API const void *SQLITE_STDCALL sqlite3_value_text16be(sqlite3_value*);
    +-SQLITE_API int SQLITE_STDCALL sqlite3_value_type(sqlite3_value*);
    +-SQLITE_API int SQLITE_STDCALL sqlite3_value_numeric_type(sqlite3_value*);
    ++SQLITE_API const void *sqlite3_value_blob(sqlite3_value*);
    ++SQLITE_API double sqlite3_value_double(sqlite3_value*);
    ++SQLITE_API int sqlite3_value_int(sqlite3_value*);
    ++SQLITE_API sqlite3_int64 sqlite3_value_int64(sqlite3_value*);
    ++SQLITE_API void *sqlite3_value_pointer(sqlite3_value*, const char*);
    ++SQLITE_API const unsigned char *sqlite3_value_text(sqlite3_value*);
    ++SQLITE_API const void *sqlite3_value_text16(sqlite3_value*);
    ++SQLITE_API const void *sqlite3_value_text16le(sqlite3_value*);
    ++SQLITE_API const void *sqlite3_value_text16be(sqlite3_value*);
    ++SQLITE_API int sqlite3_value_bytes(sqlite3_value*);
    ++SQLITE_API int sqlite3_value_bytes16(sqlite3_value*);
    ++SQLITE_API int sqlite3_value_type(sqlite3_value*);
    ++SQLITE_API int sqlite3_value_numeric_type(sqlite3_value*);
    ++SQLITE_API int sqlite3_value_nochange(sqlite3_value*);
    + 
    + /*
    + ** CAPI3REF: Finding The Subtype Of SQL Values
    +@@ -4582,12 +5919,8 @@ SQLITE_API int SQLITE_STDCALL sqlite3_value_numeric_type(sqlite3_value*);
    + ** information can be used to pass a limited amount of context from
    + ** one SQL function to another.  Use the [sqlite3_result_subtype()]
    + ** routine to set the subtype for the return value of an SQL function.
    +-**
    +-** SQLite makes no use of subtype itself.  It merely passes the subtype
    +-** from the result of one [application-defined SQL function] into the
    +-** input of another.
    + */
    +-SQLITE_API unsigned int SQLITE_STDCALL sqlite3_value_subtype(sqlite3_value*);
    ++SQLITE_API unsigned int sqlite3_value_subtype(sqlite3_value*);
    + 
    + /*
    + ** CAPI3REF: Copy And Free SQL Values
    +@@ -4603,8 +5936,8 @@ SQLITE_API unsigned int SQLITE_STDCALL sqlite3_value_subtype(sqlite3_value*);
    + ** previously obtained from [sqlite3_value_dup()].  ^If V is a NULL pointer
    + ** then sqlite3_value_free(V) is a harmless no-op.
    + */
    +-SQLITE_API SQLITE_EXPERIMENTAL sqlite3_value *SQLITE_STDCALL sqlite3_value_dup(const sqlite3_value*);
    +-SQLITE_API SQLITE_EXPERIMENTAL void SQLITE_STDCALL sqlite3_value_free(sqlite3_value*);
    ++SQLITE_API sqlite3_value *sqlite3_value_dup(const sqlite3_value*);
    ++SQLITE_API void sqlite3_value_free(sqlite3_value*);
    + 
    + /*
    + ** CAPI3REF: Obtain Aggregate Function Context
    +@@ -4649,7 +5982,7 @@ SQLITE_API SQLITE_EXPERIMENTAL void SQLITE_STDCALL sqlite3_value_free(sqlite3_va
    + ** This routine must be called from the same thread in which
    + ** the aggregate SQL function is running.
    + */
    +-SQLITE_API void *SQLITE_STDCALL sqlite3_aggregate_context(sqlite3_context*, int nBytes);
    ++SQLITE_API void *sqlite3_aggregate_context(sqlite3_context*, int nBytes);
    + 
    + /*
    + ** CAPI3REF: User Data For Functions
    +@@ -4664,7 +5997,7 @@ SQLITE_API void *SQLITE_STDCALL sqlite3_aggregate_context(sqlite3_context*, int
    + ** This routine must be called from the same thread in which
    + ** the application-defined function is running.
    + */
    +-SQLITE_API void *SQLITE_STDCALL sqlite3_user_data(sqlite3_context*);
    ++SQLITE_API void *sqlite3_user_data(sqlite3_context*);
    + 
    + /*
    + ** CAPI3REF: Database Connection For Functions
    +@@ -4676,7 +6009,7 @@ SQLITE_API void *SQLITE_STDCALL sqlite3_user_data(sqlite3_context*);
    + ** and [sqlite3_create_function16()] routines that originally
    + ** registered the application defined function.
    + */
    +-SQLITE_API sqlite3 *SQLITE_STDCALL sqlite3_context_db_handle(sqlite3_context*);
    ++SQLITE_API sqlite3 *sqlite3_context_db_handle(sqlite3_context*);
    + 
    + /*
    + ** CAPI3REF: Function Auxiliary Data
    +@@ -4693,10 +6026,11 @@ SQLITE_API sqlite3 *SQLITE_STDCALL sqlite3_context_db_handle(sqlite3_context*);
    + ** the compiled regular expression can be reused on multiple
    + ** invocations of the same function.
    + **
    +-** ^The sqlite3_get_auxdata() interface returns a pointer to the metadata
    +-** associated by the sqlite3_set_auxdata() function with the Nth argument
    +-** value to the application-defined function. ^If there is no metadata
    +-** associated with the function argument, this sqlite3_get_auxdata() interface
    ++** ^The sqlite3_get_auxdata(C,N) interface returns a pointer to the metadata
    ++** associated by the sqlite3_set_auxdata(C,N,P,X) function with the Nth argument
    ++** value to the application-defined function.  ^N is zero for the left-most
    ++** function argument.  ^If there is no metadata
    ++** associated with the function argument, the sqlite3_get_auxdata(C,N) interface
    + ** returns a NULL pointer.
    + **
    + ** ^The sqlite3_set_auxdata(C,N,P,X) interface saves P as metadata for the N-th
    +@@ -4708,12 +6042,13 @@ SQLITE_API sqlite3 *SQLITE_STDCALL sqlite3_context_db_handle(sqlite3_context*);
    + ** SQLite will invoke the destructor function X with parameter P exactly
    + ** once, when the metadata is discarded.
    + ** SQLite is free to discard the metadata at any time, including: <ul>
    +-** <li> when the corresponding function parameter changes, or
    +-** <li> when [sqlite3_reset()] or [sqlite3_finalize()] is called for the
    +-**      SQL statement, or
    +-** <li> when sqlite3_set_auxdata() is invoked again on the same parameter, or
    +-** <li> during the original sqlite3_set_auxdata() call when a memory 
    +-**      allocation error occurs. </ul>)^
    ++** <li> ^(when the corresponding function parameter changes)^, or
    ++** <li> ^(when [sqlite3_reset()] or [sqlite3_finalize()] is called for the
    ++**      SQL statement)^, or
    ++** <li> ^(when sqlite3_set_auxdata() is invoked again on the same
    ++**       parameter)^, or
    ++** <li> ^(during the original sqlite3_set_auxdata() call when a memory 
    ++**      allocation error occurs.)^ </ul>
    + **
    + ** Note the last bullet in particular.  The destructor X in 
    + ** sqlite3_set_auxdata(C,N,P,X) might be called immediately, before the
    +@@ -4726,11 +6061,15 @@ SQLITE_API sqlite3 *SQLITE_STDCALL sqlite3_context_db_handle(sqlite3_context*);
    + ** function parameters that are compile-time constants, including literal
    + ** values and [parameters] and expressions composed from the same.)^
    + **
    ++** The value of the N parameter to these interfaces should be non-negative.
    ++** Future enhancements may make use of negative N values to define new
    ++** kinds of function caching behavior.
    ++**
    + ** These routines must be called from the same thread in which
    + ** the SQL function is running.
    + */
    +-SQLITE_API void *SQLITE_STDCALL sqlite3_get_auxdata(sqlite3_context*, int N);
    +-SQLITE_API void SQLITE_STDCALL sqlite3_set_auxdata(sqlite3_context*, int N, void*, void (*)(void*));
    ++SQLITE_API void *sqlite3_get_auxdata(sqlite3_context*, int N);
    ++SQLITE_API void sqlite3_set_auxdata(sqlite3_context*, int N, void*, void (*)(void*));
    + 
    + 
    + /*
    +@@ -4849,7 +6188,7 @@ typedef void (*sqlite3_destructor_type)(void*);
    + ** when it has finished using that result.
    + ** ^If the 4th parameter to the sqlite3_result_text* interfaces
    + ** or sqlite3_result_blob is the special constant SQLITE_TRANSIENT
    +-** then SQLite makes a copy of the result into space obtained from
    ++** then SQLite makes a copy of the result into space obtained
    + ** from [sqlite3_malloc()] before it returns.
    + **
    + ** ^The sqlite3_result_value() interface sets the result of
    +@@ -4862,31 +6201,43 @@ typedef void (*sqlite3_destructor_type)(void*);
    + ** [unprotected sqlite3_value] object is required, so either
    + ** kind of [sqlite3_value] object can be used with this interface.
    + **
    ++** ^The sqlite3_result_pointer(C,P,T,D) interface sets the result to an
    ++** SQL NULL value, just like [sqlite3_result_null(C)], except that it
    ++** also associates the host-language pointer P or type T with that 
    ++** NULL value such that the pointer can be retrieved within an
    ++** [application-defined SQL function] using [sqlite3_value_pointer()].
    ++** ^If the D parameter is not NULL, then it is a pointer to a destructor
    ++** for the P parameter.  ^SQLite invokes D with P as its only argument
    ++** when SQLite is finished with P.  The T parameter should be a static
    ++** string and preferably a string literal. The sqlite3_result_pointer()
    ++** routine is part of the [pointer passing interface] added for SQLite 3.20.0.
    ++**
    + ** If these routines are called from within the different thread
    + ** than the one containing the application-defined function that received
    + ** the [sqlite3_context] pointer, the results are undefined.
    + */
    +-SQLITE_API void SQLITE_STDCALL sqlite3_result_blob(sqlite3_context*, const void*, int, void(*)(void*));
    +-SQLITE_API void SQLITE_STDCALL sqlite3_result_blob64(sqlite3_context*,const void*,
    ++SQLITE_API void sqlite3_result_blob(sqlite3_context*, const void*, int, void(*)(void*));
    ++SQLITE_API void sqlite3_result_blob64(sqlite3_context*,const void*,
    +                            sqlite3_uint64,void(*)(void*));
    +-SQLITE_API void SQLITE_STDCALL sqlite3_result_double(sqlite3_context*, double);
    +-SQLITE_API void SQLITE_STDCALL sqlite3_result_error(sqlite3_context*, const char*, int);
    +-SQLITE_API void SQLITE_STDCALL sqlite3_result_error16(sqlite3_context*, const void*, int);
    +-SQLITE_API void SQLITE_STDCALL sqlite3_result_error_toobig(sqlite3_context*);
    +-SQLITE_API void SQLITE_STDCALL sqlite3_result_error_nomem(sqlite3_context*);
    +-SQLITE_API void SQLITE_STDCALL sqlite3_result_error_code(sqlite3_context*, int);
    +-SQLITE_API void SQLITE_STDCALL sqlite3_result_int(sqlite3_context*, int);
    +-SQLITE_API void SQLITE_STDCALL sqlite3_result_int64(sqlite3_context*, sqlite3_int64);
    +-SQLITE_API void SQLITE_STDCALL sqlite3_result_null(sqlite3_context*);
    +-SQLITE_API void SQLITE_STDCALL sqlite3_result_text(sqlite3_context*, const char*, int, void(*)(void*));
    +-SQLITE_API void SQLITE_STDCALL sqlite3_result_text64(sqlite3_context*, const char*,sqlite3_uint64,
    ++SQLITE_API void sqlite3_result_double(sqlite3_context*, double);
    ++SQLITE_API void sqlite3_result_error(sqlite3_context*, const char*, int);
    ++SQLITE_API void sqlite3_result_error16(sqlite3_context*, const void*, int);
    ++SQLITE_API void sqlite3_result_error_toobig(sqlite3_context*);
    ++SQLITE_API void sqlite3_result_error_nomem(sqlite3_context*);
    ++SQLITE_API void sqlite3_result_error_code(sqlite3_context*, int);
    ++SQLITE_API void sqlite3_result_int(sqlite3_context*, int);
    ++SQLITE_API void sqlite3_result_int64(sqlite3_context*, sqlite3_int64);
    ++SQLITE_API void sqlite3_result_null(sqlite3_context*);
    ++SQLITE_API void sqlite3_result_text(sqlite3_context*, const char*, int, void(*)(void*));
    ++SQLITE_API void sqlite3_result_text64(sqlite3_context*, const char*,sqlite3_uint64,
    +                            void(*)(void*), unsigned char encoding);
    +-SQLITE_API void SQLITE_STDCALL sqlite3_result_text16(sqlite3_context*, const void*, int, void(*)(void*));
    +-SQLITE_API void SQLITE_STDCALL sqlite3_result_text16le(sqlite3_context*, const void*, int,void(*)(void*));
    +-SQLITE_API void SQLITE_STDCALL sqlite3_result_text16be(sqlite3_context*, const void*, int,void(*)(void*));
    +-SQLITE_API void SQLITE_STDCALL sqlite3_result_value(sqlite3_context*, sqlite3_value*);
    +-SQLITE_API void SQLITE_STDCALL sqlite3_result_zeroblob(sqlite3_context*, int n);
    +-SQLITE_API int SQLITE_STDCALL sqlite3_result_zeroblob64(sqlite3_context*, sqlite3_uint64 n);
    ++SQLITE_API void sqlite3_result_text16(sqlite3_context*, const void*, int, void(*)(void*));
    ++SQLITE_API void sqlite3_result_text16le(sqlite3_context*, const void*, int,void(*)(void*));
    ++SQLITE_API void sqlite3_result_text16be(sqlite3_context*, const void*, int,void(*)(void*));
    ++SQLITE_API void sqlite3_result_value(sqlite3_context*, sqlite3_value*);
    ++SQLITE_API void sqlite3_result_pointer(sqlite3_context*, void*,const char*,void(*)(void*));
    ++SQLITE_API void sqlite3_result_zeroblob(sqlite3_context*, int n);
    ++SQLITE_API int sqlite3_result_zeroblob64(sqlite3_context*, sqlite3_uint64 n);
    + 
    + 
    + /*
    +@@ -4901,7 +6252,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_result_zeroblob64(sqlite3_context*, sqlite
    + ** The number of subtype bytes preserved by SQLite might increase
    + ** in future releases of SQLite.
    + */
    +-SQLITE_API void SQLITE_STDCALL sqlite3_result_subtype(sqlite3_context*,unsigned int);
    ++SQLITE_API void sqlite3_result_subtype(sqlite3_context*,unsigned int);
    + 
    + /*
    + ** CAPI3REF: Define New Collating Sequences
    +@@ -4983,14 +6334,14 @@ SQLITE_API void SQLITE_STDCALL sqlite3_result_subtype(sqlite3_context*,unsigned
    + **
    + ** See also:  [sqlite3_collation_needed()] and [sqlite3_collation_needed16()].
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_create_collation(
    ++SQLITE_API int sqlite3_create_collation(
    +   sqlite3*, 
    +   const char *zName, 
    +   int eTextRep, 
    +   void *pArg,
    +   int(*xCompare)(void*,int,const void*,int,const void*)
    + );
    +-SQLITE_API int SQLITE_STDCALL sqlite3_create_collation_v2(
    ++SQLITE_API int sqlite3_create_collation_v2(
    +   sqlite3*, 
    +   const char *zName, 
    +   int eTextRep, 
    +@@ -4998,7 +6349,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_create_collation_v2(
    +   int(*xCompare)(void*,int,const void*,int,const void*),
    +   void(*xDestroy)(void*)
    + );
    +-SQLITE_API int SQLITE_STDCALL sqlite3_create_collation16(
    ++SQLITE_API int sqlite3_create_collation16(
    +   sqlite3*, 
    +   const void *zName,
    +   int eTextRep, 
    +@@ -5033,12 +6384,12 @@ SQLITE_API int SQLITE_STDCALL sqlite3_create_collation16(
    + ** [sqlite3_create_collation()], [sqlite3_create_collation16()], or
    + ** [sqlite3_create_collation_v2()].
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_collation_needed(
    ++SQLITE_API int sqlite3_collation_needed(
    +   sqlite3*, 
    +   void*, 
    +   void(*)(void*,sqlite3*,int eTextRep,const char*)
    + );
    +-SQLITE_API int SQLITE_STDCALL sqlite3_collation_needed16(
    ++SQLITE_API int sqlite3_collation_needed16(
    +   sqlite3*, 
    +   void*,
    +   void(*)(void*,sqlite3*,int eTextRep,const void*)
    +@@ -5052,11 +6403,11 @@ SQLITE_API int SQLITE_STDCALL sqlite3_collation_needed16(
    + ** The code to implement this API is not available in the public release
    + ** of SQLite.
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_key(
    ++SQLITE_API int sqlite3_key(
    +   sqlite3 *db,                   /* Database to be rekeyed */
    +   const void *pKey, int nKey     /* The key */
    + );
    +-SQLITE_API int SQLITE_STDCALL sqlite3_key_v2(
    ++SQLITE_API int sqlite3_key_v2(
    +   sqlite3 *db,                   /* Database to be rekeyed */
    +   const char *zDbName,           /* Name of the database */
    +   const void *pKey, int nKey     /* The key */
    +@@ -5070,11 +6421,11 @@ SQLITE_API int SQLITE_STDCALL sqlite3_key_v2(
    + ** The code to implement this API is not available in the public release
    + ** of SQLite.
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_rekey(
    ++SQLITE_API int sqlite3_rekey(
    +   sqlite3 *db,                   /* Database to be rekeyed */
    +   const void *pKey, int nKey     /* The new key */
    + );
    +-SQLITE_API int SQLITE_STDCALL sqlite3_rekey_v2(
    ++SQLITE_API int sqlite3_rekey_v2(
    +   sqlite3 *db,                   /* Database to be rekeyed */
    +   const char *zDbName,           /* Name of the database */
    +   const void *pKey, int nKey     /* The new key */
    +@@ -5084,7 +6435,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_rekey_v2(
    + ** Specify the activation key for a SEE database.  Unless 
    + ** activated, none of the SEE routines will work.
    + */
    +-SQLITE_API void SQLITE_STDCALL sqlite3_activate_see(
    ++SQLITE_API void sqlite3_activate_see(
    +   const char *zPassPhrase        /* Activation phrase */
    + );
    + #endif
    +@@ -5094,7 +6445,7 @@ SQLITE_API void SQLITE_STDCALL sqlite3_activate_see(
    + ** Specify the activation key for a CEROD database.  Unless 
    + ** activated, none of the CEROD routines will work.
    + */
    +-SQLITE_API void SQLITE_STDCALL sqlite3_activate_cerod(
    ++SQLITE_API void sqlite3_activate_cerod(
    +   const char *zPassPhrase        /* Activation phrase */
    + );
    + #endif
    +@@ -5116,7 +6467,7 @@ SQLITE_API void SQLITE_STDCALL sqlite3_activate_cerod(
    + ** all, then the behavior of sqlite3_sleep() may deviate from the description
    + ** in the previous paragraphs.
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_sleep(int);
    ++SQLITE_API int sqlite3_sleep(int);
    + 
    + /*
    + ** CAPI3REF: Name Of The Folder Holding Temporary Files
    +@@ -5235,7 +6586,7 @@ SQLITE_API char *sqlite3_data_directory;
    + ** connection while this routine is running, then the return value
    + ** is undefined.
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_get_autocommit(sqlite3*);
    ++SQLITE_API int sqlite3_get_autocommit(sqlite3*);
    + 
    + /*
    + ** CAPI3REF: Find The Database Handle Of A Prepared Statement
    +@@ -5248,7 +6599,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_get_autocommit(sqlite3*);
    + ** to the [sqlite3_prepare_v2()] call (or its variants) that was used to
    + ** create the statement in the first place.
    + */
    +-SQLITE_API sqlite3 *SQLITE_STDCALL sqlite3_db_handle(sqlite3_stmt*);
    ++SQLITE_API sqlite3 *sqlite3_db_handle(sqlite3_stmt*);
    + 
    + /*
    + ** CAPI3REF: Return The Filename For A Database Connection
    +@@ -5265,7 +6616,7 @@ SQLITE_API sqlite3 *SQLITE_STDCALL sqlite3_db_handle(sqlite3_stmt*);
    + ** will be an absolute pathname, even if the filename used
    + ** to open the database originally was a URI or relative pathname.
    + */
    +-SQLITE_API const char *SQLITE_STDCALL sqlite3_db_filename(sqlite3 *db, const char *zDbName);
    ++SQLITE_API const char *sqlite3_db_filename(sqlite3 *db, const char *zDbName);
    + 
    + /*
    + ** CAPI3REF: Determine if a database is read-only
    +@@ -5275,7 +6626,7 @@ SQLITE_API const char *SQLITE_STDCALL sqlite3_db_filename(sqlite3 *db, const cha
    + ** of connection D is read-only, 0 if it is read/write, or -1 if N is not
    + ** the name of a database on connection D.
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_db_readonly(sqlite3 *db, const char *zDbName);
    ++SQLITE_API int sqlite3_db_readonly(sqlite3 *db, const char *zDbName);
    + 
    + /*
    + ** CAPI3REF: Find the next prepared statement
    +@@ -5291,7 +6642,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_db_readonly(sqlite3 *db, const char *zDbNa
    + ** [sqlite3_next_stmt(D,S)] must refer to an open database
    + ** connection and in particular must not be a NULL pointer.
    + */
    +-SQLITE_API sqlite3_stmt *SQLITE_STDCALL sqlite3_next_stmt(sqlite3 *pDb, sqlite3_stmt *pStmt);
    ++SQLITE_API sqlite3_stmt *sqlite3_next_stmt(sqlite3 *pDb, sqlite3_stmt *pStmt);
    + 
    + /*
    + ** CAPI3REF: Commit And Rollback Notification Callbacks
    +@@ -5340,8 +6691,8 @@ SQLITE_API sqlite3_stmt *SQLITE_STDCALL sqlite3_next_stmt(sqlite3 *pDb, sqlite3_
    + **
    + ** See also the [sqlite3_update_hook()] interface.
    + */
    +-SQLITE_API void *SQLITE_STDCALL sqlite3_commit_hook(sqlite3*, int(*)(void*), void*);
    +-SQLITE_API void *SQLITE_STDCALL sqlite3_rollback_hook(sqlite3*, void(*)(void *), void*);
    ++SQLITE_API void *sqlite3_commit_hook(sqlite3*, int(*)(void*), void*);
    ++SQLITE_API void *sqlite3_rollback_hook(sqlite3*, void(*)(void *), void*);
    + 
    + /*
    + ** CAPI3REF: Data Change Notification Callbacks
    +@@ -5350,7 +6701,7 @@ SQLITE_API void *SQLITE_STDCALL sqlite3_rollback_hook(sqlite3*, void(*)(void *),
    + ** ^The sqlite3_update_hook() interface registers a callback function
    + ** with the [database connection] identified by the first argument
    + ** to be invoked whenever a row is updated, inserted or deleted in
    +-** a rowid table.
    ++** a [rowid table].
    + ** ^Any callback set by a previous call to this function
    + ** for the same database connection is overridden.
    + **
    +@@ -5371,7 +6722,7 @@ SQLITE_API void *SQLITE_STDCALL sqlite3_rollback_hook(sqlite3*, void(*)(void *),
    + ** ^The update hook is not invoked when [WITHOUT ROWID] tables are modified.
    + **
    + ** ^In the current implementation, the update hook
    +-** is not invoked when duplication rows are deleted because of an
    ++** is not invoked when conflicting rows are deleted because of an
    + ** [ON CONFLICT | ON CONFLICT REPLACE] clause.  ^Nor is the update hook
    + ** invoked when rows are deleted using the [truncate optimization].
    + ** The exceptions defined in this paragraph might change in a future
    +@@ -5389,10 +6740,10 @@ SQLITE_API void *SQLITE_STDCALL sqlite3_rollback_hook(sqlite3*, void(*)(void *),
    + ** on the same [database connection] D, or NULL for
    + ** the first call on D.
    + **
    +-** See also the [sqlite3_commit_hook()] and [sqlite3_rollback_hook()]
    +-** interfaces.
    ++** See also the [sqlite3_commit_hook()], [sqlite3_rollback_hook()],
    ++** and [sqlite3_preupdate_hook()] interfaces.
    + */
    +-SQLITE_API void *SQLITE_STDCALL sqlite3_update_hook(
    ++SQLITE_API void *sqlite3_update_hook(
    +   sqlite3*, 
    +   void(*)(void *,int ,char const *,char const *,sqlite3_int64),
    +   void*
    +@@ -5407,7 +6758,8 @@ SQLITE_API void *SQLITE_STDCALL sqlite3_update_hook(
    + ** and disabled if the argument is false.)^
    + **
    + ** ^Cache sharing is enabled and disabled for an entire process.
    +-** This is a change as of SQLite version 3.5.0. In prior versions of SQLite,
    ++** This is a change as of SQLite [version 3.5.0] ([dateof:3.5.0]). 
    ++** In prior versions of SQLite,
    + ** sharing was enabled or disabled for each thread separately.
    + **
    + ** ^(The cache sharing mode set by this interface effects all subsequent
    +@@ -5432,7 +6784,7 @@ SQLITE_API void *SQLITE_STDCALL sqlite3_update_hook(
    + **
    + ** See Also:  [SQLite Shared-Cache Mode]
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_enable_shared_cache(int);
    ++SQLITE_API int sqlite3_enable_shared_cache(int);
    + 
    + /*
    + ** CAPI3REF: Attempt To Free Heap Memory
    +@@ -5448,7 +6800,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_enable_shared_cache(int);
    + **
    + ** See also: [sqlite3_db_release_memory()]
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_release_memory(int);
    ++SQLITE_API int sqlite3_release_memory(int);
    + 
    + /*
    + ** CAPI3REF: Free Memory Used By A Database Connection
    +@@ -5462,7 +6814,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_release_memory(int);
    + **
    + ** See also: [sqlite3_release_memory()]
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_db_release_memory(sqlite3*);
    ++SQLITE_API int sqlite3_db_release_memory(sqlite3*);
    + 
    + /*
    + ** CAPI3REF: Impose A Limit On Heap Size
    +@@ -5501,7 +6853,8 @@ SQLITE_API int SQLITE_STDCALL sqlite3_db_release_memory(sqlite3*);
    + **      from the heap.
    + ** </ul>)^
    + **
    +-** Beginning with SQLite version 3.7.3, the soft heap limit is enforced
    ++** Beginning with SQLite [version 3.7.3] ([dateof:3.7.3]), 
    ++** the soft heap limit is enforced
    + ** regardless of whether or not the [SQLITE_ENABLE_MEMORY_MANAGEMENT]
    + ** compile-time option is invoked.  With [SQLITE_ENABLE_MEMORY_MANAGEMENT],
    + ** the soft heap limit is enforced on every memory allocation.  Without
    +@@ -5514,7 +6867,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_db_release_memory(sqlite3*);
    + ** The circumstances under which SQLite will enforce the soft heap limit may
    + ** changes in future releases of SQLite.
    + */
    +-SQLITE_API sqlite3_int64 SQLITE_STDCALL sqlite3_soft_heap_limit64(sqlite3_int64 N);
    ++SQLITE_API sqlite3_int64 sqlite3_soft_heap_limit64(sqlite3_int64 N);
    + 
    + /*
    + ** CAPI3REF: Deprecated Soft Heap Limit Interface
    +@@ -5525,7 +6878,7 @@ SQLITE_API sqlite3_int64 SQLITE_STDCALL sqlite3_soft_heap_limit64(sqlite3_int64
    + ** only.  All new applications should use the
    + ** [sqlite3_soft_heap_limit64()] interface rather than this one.
    + */
    +-SQLITE_API SQLITE_DEPRECATED void SQLITE_STDCALL sqlite3_soft_heap_limit(int N);
    ++SQLITE_API SQLITE_DEPRECATED void sqlite3_soft_heap_limit(int N);
    + 
    + 
    + /*
    +@@ -5540,9 +6893,11 @@ SQLITE_API SQLITE_DEPRECATED void SQLITE_STDCALL sqlite3_soft_heap_limit(int N);
    + ** column exists.  ^The sqlite3_table_column_metadata() interface returns
    + ** SQLITE_ERROR and if the specified column does not exist.
    + ** ^If the column-name parameter to sqlite3_table_column_metadata() is a
    +-** NULL pointer, then this routine simply checks for the existance of the
    ++** NULL pointer, then this routine simply checks for the existence of the
    + ** table and returns SQLITE_OK if the table exists and SQLITE_ERROR if it
    +-** does not.
    ++** does not.  If the table name parameter T in a call to
    ++** sqlite3_table_column_metadata(X,D,T,C,...) is NULL then the result is
    ++** undefined behavior.
    + **
    + ** ^The column is identified by the second, third and fourth parameters to
    + ** this function. ^(The second parameter is either the name of the database
    +@@ -5595,7 +6950,7 @@ SQLITE_API SQLITE_DEPRECATED void SQLITE_STDCALL sqlite3_soft_heap_limit(int N);
    + ** parsed, if that has not already been done, and returns an error if
    + ** any errors are encountered while loading the schema.
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_table_column_metadata(
    ++SQLITE_API int sqlite3_table_column_metadata(
    +   sqlite3 *db,                /* Connection handle */
    +   const char *zDbName,        /* Database name or NULL */
    +   const char *zTableName,     /* Table name */
    +@@ -5637,12 +6992,21 @@ SQLITE_API int SQLITE_STDCALL sqlite3_table_column_metadata(
    + ** should free this memory by calling [sqlite3_free()].
    + **
    + ** ^Extension loading must be enabled using
    +-** [sqlite3_enable_load_extension()] prior to calling this API,
    ++** [sqlite3_enable_load_extension()] or
    ++** [sqlite3_db_config](db,[SQLITE_DBCONFIG_ENABLE_LOAD_EXTENSION],1,NULL)
    ++** prior to calling this API,
    + ** otherwise an error will be returned.
    + **
    ++** <b>Security warning:</b> It is recommended that the 
    ++** [SQLITE_DBCONFIG_ENABLE_LOAD_EXTENSION] method be used to enable only this
    ++** interface.  The use of the [sqlite3_enable_load_extension()] interface
    ++** should be avoided.  This will keep the SQL function [load_extension()]
    ++** disabled and prevent SQL injections from giving attackers
    ++** access to extension loading capabilities.
    ++**
    + ** See also the [load_extension() SQL function].
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_load_extension(
    ++SQLITE_API int sqlite3_load_extension(
    +   sqlite3 *db,          /* Load the extension into this database connection */
    +   const char *zFile,    /* Name of the shared library containing extension */
    +   const char *zProc,    /* Entry point.  Derived from zFile if 0 */
    +@@ -5662,8 +7026,19 @@ SQLITE_API int SQLITE_STDCALL sqlite3_load_extension(
    + ** ^Call the sqlite3_enable_load_extension() routine with onoff==1
    + ** to turn extension loading on and call it with onoff==0 to turn
    + ** it back off again.
    ++**
    ++** ^This interface enables or disables both the C-API
    ++** [sqlite3_load_extension()] and the SQL function [load_extension()].
    ++** ^(Use [sqlite3_db_config](db,[SQLITE_DBCONFIG_ENABLE_LOAD_EXTENSION],..)
    ++** to enable or disable only the C-API.)^
    ++**
    ++** <b>Security warning:</b> It is recommended that extension loading
    ++** be disabled using the [SQLITE_DBCONFIG_ENABLE_LOAD_EXTENSION] method
    ++** rather than this interface, so the [load_extension()] SQL function
    ++** remains disabled. This will prevent SQL injections from giving attackers
    ++** access to extension loading capabilities.
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_enable_load_extension(sqlite3 *db, int onoff);
    ++SQLITE_API int sqlite3_enable_load_extension(sqlite3 *db, int onoff);
    + 
    + /*
    + ** CAPI3REF: Automatically Load Statically Linked Extensions
    +@@ -5675,7 +7050,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_enable_load_extension(sqlite3 *db, int ono
    + **
    + ** ^(Even though the function prototype shows that xEntryPoint() takes
    + ** no arguments and returns void, SQLite invokes xEntryPoint() with three
    +-** arguments and expects and integer result as if the signature of the
    ++** arguments and expects an integer result as if the signature of the
    + ** entry point where as follows:
    + **
    + ** <blockquote><pre>
    +@@ -5701,7 +7076,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_enable_load_extension(sqlite3 *db, int ono
    + ** See also: [sqlite3_reset_auto_extension()]
    + ** and [sqlite3_cancel_auto_extension()]
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_auto_extension(void (*xEntryPoint)(void));
    ++SQLITE_API int sqlite3_auto_extension(void(*xEntryPoint)(void));
    + 
    + /*
    + ** CAPI3REF: Cancel Automatic Extension Loading
    +@@ -5713,7 +7088,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_auto_extension(void (*xEntryPoint)(void));
    + ** unregistered and it returns 0 if X was not on the list of initialization
    + ** routines.
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_cancel_auto_extension(void (*xEntryPoint)(void));
    ++SQLITE_API int sqlite3_cancel_auto_extension(void(*xEntryPoint)(void));
    + 
    + /*
    + ** CAPI3REF: Reset Automatic Extension Loading
    +@@ -5721,7 +7096,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_cancel_auto_extension(void (*xEntryPoint)(
    + ** ^This interface disables all automatic extensions previously
    + ** registered using [sqlite3_auto_extension()].
    + */
    +-SQLITE_API void SQLITE_STDCALL sqlite3_reset_auto_extension(void);
    ++SQLITE_API void sqlite3_reset_auto_extension(void);
    + 
    + /*
    + ** The interface to the virtual-table mechanism is currently considered
    +@@ -5823,6 +7198,17 @@ struct sqlite3_module {
    + ** ^Information about the ORDER BY clause is stored in aOrderBy[].
    + ** ^Each term of aOrderBy records a column of the ORDER BY clause.
    + **
    ++** The colUsed field indicates which columns of the virtual table may be
    ++** required by the current scan. Virtual table columns are numbered from
    ++** zero in the order in which they appear within the CREATE TABLE statement
    ++** passed to sqlite3_declare_vtab(). For the first 63 columns (columns 0-62),
    ++** the corresponding bit is set within the colUsed mask if the column may be
    ++** required by SQLite. If the table has at least 64 columns and any column
    ++** to the right of the first 63 is required, then bit 63 of colUsed is also
    ++** set. In other words, column iCol may be required if the expression
    ++** (colUsed & ((sqlite3_uint64)1 << (iCol>=63 ? 63 : iCol))) evaluates to 
    ++** non-zero.
    ++**
    + ** The [xBestIndex] method must fill aConstraintUsage[] with information
    + ** about what parameters to pass to xFilter.  ^If argvIndex>0 then
    + ** the right-hand side of the corresponding aConstraint[] is evaluated
    +@@ -5864,13 +7250,15 @@ struct sqlite3_module {
    + ** the xUpdate method are automatically rolled back by SQLite.
    + **
    + ** IMPORTANT: The estimatedRows field was added to the sqlite3_index_info
    +-** structure for SQLite version 3.8.2. If a virtual table extension is
    ++** structure for SQLite [version 3.8.2] ([dateof:3.8.2]). 
    ++** If a virtual table extension is
    + ** used with an SQLite version earlier than 3.8.2, the results of attempting 
    + ** to read or write the estimatedRows field are undefined (but are likely 
    + ** to included crashing the application). The estimatedRows field should
    + ** therefore only be used if [sqlite3_libversion_number()] returns a
    + ** value greater than or equal to 3008002. Similarly, the idxFlags field
    +-** was added for version 3.9.0. It may therefore only be used if
    ++** was added for [version 3.9.0] ([dateof:3.9.0]). 
    ++** It may therefore only be used if
    + ** sqlite3_libversion_number() returns a value greater than or equal to
    + ** 3009000.
    + */
    +@@ -5878,7 +7266,7 @@ struct sqlite3_index_info {
    +   /* Inputs */
    +   int nConstraint;           /* Number of entries in aConstraint */
    +   struct sqlite3_index_constraint {
    +-     int iColumn;              /* Column on left-hand side of constraint */
    ++     int iColumn;              /* Column constrained.  -1 for ROWID */
    +      unsigned char op;         /* Constraint operator */
    +      unsigned char usable;     /* True if this constraint is usable */
    +      int iTermOffset;          /* Used internally - xBestIndex should ignore */
    +@@ -5902,6 +7290,8 @@ struct sqlite3_index_info {
    +   sqlite3_int64 estimatedRows;    /* Estimated number of rows returned */
    +   /* Fields below are only available in SQLite 3.9.0 and later */
    +   int idxFlags;              /* Mask of SQLITE_INDEX_SCAN_* flags */
    ++  /* Fields below are only available in SQLite 3.10.0 and later */
    ++  sqlite3_uint64 colUsed;    /* Input: Mask of columns used by statement */
    + };
    + 
    + /*
    +@@ -5917,12 +7307,20 @@ struct sqlite3_index_info {
    + ** an operator that is part of a constraint term in the wHERE clause of
    + ** a query that uses a [virtual table].
    + */
    +-#define SQLITE_INDEX_CONSTRAINT_EQ    2
    +-#define SQLITE_INDEX_CONSTRAINT_GT    4
    +-#define SQLITE_INDEX_CONSTRAINT_LE    8
    +-#define SQLITE_INDEX_CONSTRAINT_LT    16
    +-#define SQLITE_INDEX_CONSTRAINT_GE    32
    +-#define SQLITE_INDEX_CONSTRAINT_MATCH 64
    ++#define SQLITE_INDEX_CONSTRAINT_EQ         2
    ++#define SQLITE_INDEX_CONSTRAINT_GT         4
    ++#define SQLITE_INDEX_CONSTRAINT_LE         8
    ++#define SQLITE_INDEX_CONSTRAINT_LT        16
    ++#define SQLITE_INDEX_CONSTRAINT_GE        32
    ++#define SQLITE_INDEX_CONSTRAINT_MATCH     64
    ++#define SQLITE_INDEX_CONSTRAINT_LIKE      65
    ++#define SQLITE_INDEX_CONSTRAINT_GLOB      66
    ++#define SQLITE_INDEX_CONSTRAINT_REGEXP    67
    ++#define SQLITE_INDEX_CONSTRAINT_NE        68
    ++#define SQLITE_INDEX_CONSTRAINT_ISNOT     69
    ++#define SQLITE_INDEX_CONSTRAINT_ISNOTNULL 70
    ++#define SQLITE_INDEX_CONSTRAINT_ISNULL    71
    ++#define SQLITE_INDEX_CONSTRAINT_IS        72
    + 
    + /*
    + ** CAPI3REF: Register A Virtual Table Implementation
    +@@ -5950,13 +7348,13 @@ struct sqlite3_index_info {
    + ** interface is equivalent to sqlite3_create_module_v2() with a NULL
    + ** destructor.
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_create_module(
    ++SQLITE_API int sqlite3_create_module(
    +   sqlite3 *db,               /* SQLite connection to register module with */
    +   const char *zName,         /* Name of the module */
    +   const sqlite3_module *p,   /* Methods for the module */
    +   void *pClientData          /* Client data for xCreate/xConnect */
    + );
    +-SQLITE_API int SQLITE_STDCALL sqlite3_create_module_v2(
    ++SQLITE_API int sqlite3_create_module_v2(
    +   sqlite3 *db,               /* SQLite connection to register module with */
    +   const char *zName,         /* Name of the module */
    +   const sqlite3_module *p,   /* Methods for the module */
    +@@ -6019,7 +7417,7 @@ struct sqlite3_vtab_cursor {
    + ** to declare the format (the names and datatypes of the columns) of
    + ** the virtual tables they implement.
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_declare_vtab(sqlite3*, const char *zSQL);
    ++SQLITE_API int sqlite3_declare_vtab(sqlite3*, const char *zSQL);
    + 
    + /*
    + ** CAPI3REF: Overload A Function For A Virtual Table
    +@@ -6038,7 +7436,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_declare_vtab(sqlite3*, const char *zSQL);
    + ** purpose is to be a placeholder function that can be overloaded
    + ** by a [virtual table].
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_overload_function(sqlite3*, const char *zFuncName, int nArg);
    ++SQLITE_API int sqlite3_overload_function(sqlite3*, const char *zFuncName, int nArg);
    + 
    + /*
    + ** The interface to the virtual-table mechanism defined above (back up
    +@@ -6113,6 +7511,12 @@ typedef struct sqlite3_blob sqlite3_blob;
    + ** [database connection] error code and message accessible via 
    + ** [sqlite3_errcode()] and [sqlite3_errmsg()] and related functions. 
    + **
    ++** A BLOB referenced by sqlite3_blob_open() may be read using the
    ++** [sqlite3_blob_read()] interface and modified by using
    ++** [sqlite3_blob_write()].  The [BLOB handle] can be moved to a
    ++** different row of the same table using the [sqlite3_blob_reopen()]
    ++** interface.  However, the column, table, or database of a [BLOB handle]
    ++** cannot be changed after the [BLOB handle] is opened.
    + **
    + ** ^(If the row that a BLOB handle points to is modified by an
    + ** [UPDATE], [DELETE], or by [ON CONFLICT] side-effects
    +@@ -6136,8 +7540,12 @@ typedef struct sqlite3_blob sqlite3_blob;
    + **
    + ** To avoid a resource leak, every open [BLOB handle] should eventually
    + ** be released by a call to [sqlite3_blob_close()].
    ++**
    ++** See also: [sqlite3_blob_close()],
    ++** [sqlite3_blob_reopen()], [sqlite3_blob_read()],
    ++** [sqlite3_blob_bytes()], [sqlite3_blob_write()].
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_blob_open(
    ++SQLITE_API int sqlite3_blob_open(
    +   sqlite3*,
    +   const char *zDb,
    +   const char *zTable,
    +@@ -6151,11 +7559,11 @@ SQLITE_API int SQLITE_STDCALL sqlite3_blob_open(
    + ** CAPI3REF: Move a BLOB Handle to a New Row
    + ** METHOD: sqlite3_blob
    + **
    +-** ^This function is used to move an existing blob handle so that it points
    ++** ^This function is used to move an existing [BLOB handle] so that it points
    + ** to a different row of the same database table. ^The new row is identified
    + ** by the rowid value passed as the second argument. Only the row can be
    + ** changed. ^The database, table and column on which the blob handle is open
    +-** remain the same. Moving an existing blob handle to a new row can be
    ++** remain the same. Moving an existing [BLOB handle] to a new row is
    + ** faster than closing the existing handle and opening a new one.
    + **
    + ** ^(The new row must meet the same criteria as for [sqlite3_blob_open()] -
    +@@ -6170,7 +7578,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_blob_open(
    + **
    + ** ^This function sets the database handle error code and message.
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_blob_reopen(sqlite3_blob *, sqlite3_int64);
    ++SQLITE_API int sqlite3_blob_reopen(sqlite3_blob *, sqlite3_int64);
    + 
    + /*
    + ** CAPI3REF: Close A BLOB Handle
    +@@ -6193,7 +7601,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_blob_reopen(sqlite3_blob *, sqlite3_int64)
    + ** is passed a valid open blob handle, the values returned by the 
    + ** sqlite3_errcode() and sqlite3_errmsg() functions are set before returning.
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_blob_close(sqlite3_blob *);
    ++SQLITE_API int sqlite3_blob_close(sqlite3_blob *);
    + 
    + /*
    + ** CAPI3REF: Return The Size Of An Open BLOB
    +@@ -6209,7 +7617,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_blob_close(sqlite3_blob *);
    + ** been closed by [sqlite3_blob_close()].  Passing any other pointer in
    + ** to this routine results in undefined and probably undesirable behavior.
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_blob_bytes(sqlite3_blob *);
    ++SQLITE_API int sqlite3_blob_bytes(sqlite3_blob *);
    + 
    + /*
    + ** CAPI3REF: Read Data From A BLOB Incrementally
    +@@ -6238,7 +7646,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_blob_bytes(sqlite3_blob *);
    + **
    + ** See also: [sqlite3_blob_write()].
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_blob_read(sqlite3_blob *, void *Z, int N, int iOffset);
    ++SQLITE_API int sqlite3_blob_read(sqlite3_blob *, void *Z, int N, int iOffset);
    + 
    + /*
    + ** CAPI3REF: Write Data Into A BLOB Incrementally
    +@@ -6280,7 +7688,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_blob_read(sqlite3_blob *, void *Z, int N,
    + **
    + ** See also: [sqlite3_blob_read()].
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_blob_write(sqlite3_blob *, const void *z, int n, int iOffset);
    ++SQLITE_API int sqlite3_blob_write(sqlite3_blob *, const void *z, int n, int iOffset);
    + 
    + /*
    + ** CAPI3REF: Virtual File System Objects
    +@@ -6311,9 +7719,9 @@ SQLITE_API int SQLITE_STDCALL sqlite3_blob_write(sqlite3_blob *, const void *z,
    + ** ^(If the default VFS is unregistered, another VFS is chosen as
    + ** the default.  The choice for the new VFS is arbitrary.)^
    + */
    +-SQLITE_API sqlite3_vfs *SQLITE_STDCALL sqlite3_vfs_find(const char *zVfsName);
    +-SQLITE_API int SQLITE_STDCALL sqlite3_vfs_register(sqlite3_vfs*, int makeDflt);
    +-SQLITE_API int SQLITE_STDCALL sqlite3_vfs_unregister(sqlite3_vfs*);
    ++SQLITE_API sqlite3_vfs *sqlite3_vfs_find(const char *zVfsName);
    ++SQLITE_API int sqlite3_vfs_register(sqlite3_vfs*, int makeDflt);
    ++SQLITE_API int sqlite3_vfs_unregister(sqlite3_vfs*);
    + 
    + /*
    + ** CAPI3REF: Mutexes
    +@@ -6429,11 +7837,11 @@ SQLITE_API int SQLITE_STDCALL sqlite3_vfs_unregister(sqlite3_vfs*);
    + **
    + ** See also: [sqlite3_mutex_held()] and [sqlite3_mutex_notheld()].
    + */
    +-SQLITE_API sqlite3_mutex *SQLITE_STDCALL sqlite3_mutex_alloc(int);
    +-SQLITE_API void SQLITE_STDCALL sqlite3_mutex_free(sqlite3_mutex*);
    +-SQLITE_API void SQLITE_STDCALL sqlite3_mutex_enter(sqlite3_mutex*);
    +-SQLITE_API int SQLITE_STDCALL sqlite3_mutex_try(sqlite3_mutex*);
    +-SQLITE_API void SQLITE_STDCALL sqlite3_mutex_leave(sqlite3_mutex*);
    ++SQLITE_API sqlite3_mutex *sqlite3_mutex_alloc(int);
    ++SQLITE_API void sqlite3_mutex_free(sqlite3_mutex*);
    ++SQLITE_API void sqlite3_mutex_enter(sqlite3_mutex*);
    ++SQLITE_API int sqlite3_mutex_try(sqlite3_mutex*);
    ++SQLITE_API void sqlite3_mutex_leave(sqlite3_mutex*);
    + 
    + /*
    + ** CAPI3REF: Mutex Methods Object
    +@@ -6543,8 +7951,8 @@ struct sqlite3_mutex_methods {
    + ** interface should also return 1 when given a NULL pointer.
    + */
    + #ifndef NDEBUG
    +-SQLITE_API int SQLITE_STDCALL sqlite3_mutex_held(sqlite3_mutex*);
    +-SQLITE_API int SQLITE_STDCALL sqlite3_mutex_notheld(sqlite3_mutex*);
    ++SQLITE_API int sqlite3_mutex_held(sqlite3_mutex*);
    ++SQLITE_API int sqlite3_mutex_notheld(sqlite3_mutex*);
    + #endif
    + 
    + /*
    +@@ -6563,7 +7971,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_mutex_notheld(sqlite3_mutex*);
    + #define SQLITE_MUTEX_STATIC_MEM       3  /* sqlite3_malloc() */
    + #define SQLITE_MUTEX_STATIC_MEM2      4  /* NOT USED */
    + #define SQLITE_MUTEX_STATIC_OPEN      4  /* sqlite3BtreeOpen() */
    +-#define SQLITE_MUTEX_STATIC_PRNG      5  /* sqlite3_random() */
    ++#define SQLITE_MUTEX_STATIC_PRNG      5  /* sqlite3_randomness() */
    + #define SQLITE_MUTEX_STATIC_LRU       6  /* lru page list */
    + #define SQLITE_MUTEX_STATIC_LRU2      7  /* NOT USED */
    + #define SQLITE_MUTEX_STATIC_PMEM      7  /* sqlite3PageMalloc() */
    +@@ -6584,7 +7992,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_mutex_notheld(sqlite3_mutex*);
    + ** ^If the [threading mode] is Single-thread or Multi-thread then this
    + ** routine returns a NULL pointer.
    + */
    +-SQLITE_API sqlite3_mutex *SQLITE_STDCALL sqlite3_db_mutex(sqlite3*);
    ++SQLITE_API sqlite3_mutex *sqlite3_db_mutex(sqlite3*);
    + 
    + /*
    + ** CAPI3REF: Low-Level Control Of Database Files
    +@@ -6603,9 +8011,9 @@ SQLITE_API sqlite3_mutex *SQLITE_STDCALL sqlite3_db_mutex(sqlite3*);
    + ** the xFileControl method.  ^The return value of the xFileControl
    + ** method becomes the return value of this routine.
    + **
    +-** ^The SQLITE_FCNTL_FILE_POINTER value for the op parameter causes
    ++** ^The [SQLITE_FCNTL_FILE_POINTER] value for the op parameter causes
    + ** a pointer to the underlying [sqlite3_file] object to be written into
    +-** the space pointed to by the 4th parameter.  ^The SQLITE_FCNTL_FILE_POINTER
    ++** the space pointed to by the 4th parameter.  ^The [SQLITE_FCNTL_FILE_POINTER]
    + ** case is a short-circuit path which does not actually invoke the
    + ** underlying sqlite3_io_methods.xFileControl method.
    + **
    +@@ -6617,9 +8025,9 @@ SQLITE_API sqlite3_mutex *SQLITE_STDCALL sqlite3_db_mutex(sqlite3*);
    + ** an incorrect zDbName and an SQLITE_ERROR return from the underlying
    + ** xFileControl method.
    + **
    +-** See also: [SQLITE_FCNTL_LOCKSTATE]
    ++** See also: [file control opcodes]
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_file_control(sqlite3*, const char *zDbName, int op, void*);
    ++SQLITE_API int sqlite3_file_control(sqlite3*, const char *zDbName, int op, void*);
    + 
    + /*
    + ** CAPI3REF: Testing Interface
    +@@ -6638,7 +8046,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_file_control(sqlite3*, const char *zDbName
    + ** Unlike most of the SQLite API, this function is not guaranteed to
    + ** operate consistently from one release to the next.
    + */
    +-SQLITE_API int SQLITE_CDECL sqlite3_test_control(int op, ...);
    ++SQLITE_API int sqlite3_test_control(int op, ...);
    + 
    + /*
    + ** CAPI3REF: Testing Interface Operation Codes
    +@@ -6664,16 +8072,18 @@ SQLITE_API int SQLITE_CDECL sqlite3_test_control(int op, ...);
    + #define SQLITE_TESTCTRL_RESERVE                 14
    + #define SQLITE_TESTCTRL_OPTIMIZATIONS           15
    + #define SQLITE_TESTCTRL_ISKEYWORD               16
    +-#define SQLITE_TESTCTRL_SCRATCHMALLOC           17
    ++#define SQLITE_TESTCTRL_SCRATCHMALLOC           17  /* NOT USED */
    + #define SQLITE_TESTCTRL_LOCALTIME_FAULT         18
    + #define SQLITE_TESTCTRL_EXPLAIN_STMT            19  /* NOT USED */
    ++#define SQLITE_TESTCTRL_ONCE_RESET_THRESHOLD    19
    + #define SQLITE_TESTCTRL_NEVER_CORRUPT           20
    + #define SQLITE_TESTCTRL_VDBE_COVERAGE           21
    + #define SQLITE_TESTCTRL_BYTEORDER               22
    + #define SQLITE_TESTCTRL_ISINIT                  23
    + #define SQLITE_TESTCTRL_SORTER_MMAP             24
    + #define SQLITE_TESTCTRL_IMPOSTER                25
    +-#define SQLITE_TESTCTRL_LAST                    25
    ++#define SQLITE_TESTCTRL_PARSER_COVERAGE         26
    ++#define SQLITE_TESTCTRL_LAST                    26  /* Largest TESTCTRL */
    + 
    + /*
    + ** CAPI3REF: SQLite Runtime Status
    +@@ -6701,8 +8111,8 @@ SQLITE_API int SQLITE_CDECL sqlite3_test_control(int op, ...);
    + **
    + ** See also: [sqlite3_db_status()]
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_status(int op, int *pCurrent, int *pHighwater, int resetFlag);
    +-SQLITE_API int SQLITE_STDCALL sqlite3_status64(
    ++SQLITE_API int sqlite3_status(int op, int *pCurrent, int *pHighwater, int resetFlag);
    ++SQLITE_API int sqlite3_status64(
    +   int op,
    +   sqlite3_int64 *pCurrent,
    +   sqlite3_int64 *pHighwater,
    +@@ -6722,8 +8132,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_status64(
    + ** <dd>This parameter is the current amount of memory checked out
    + ** using [sqlite3_malloc()], either directly or indirectly.  The
    + ** figure includes calls made to [sqlite3_malloc()] by the application
    +-** and internal memory usage by the SQLite library.  Scratch memory
    +-** controlled by [SQLITE_CONFIG_SCRATCH] and auxiliary page-cache
    ++** and internal memory usage by the SQLite library.  Auxiliary page-cache
    + ** memory controlled by [SQLITE_CONFIG_PAGECACHE] is not included in
    + ** this parameter.  The amount returned is the sum of the allocation
    + ** sizes as reported by the xSize method in [sqlite3_mem_methods].</dd>)^
    +@@ -6761,32 +8170,18 @@ SQLITE_API int SQLITE_STDCALL sqlite3_status64(
    + ** *pHighwater parameter to [sqlite3_status()] is of interest.  
    + ** The value written into the *pCurrent parameter is undefined.</dd>)^
    + **
    +-** [[SQLITE_STATUS_SCRATCH_USED]] ^(<dt>SQLITE_STATUS_SCRATCH_USED</dt>
    +-** <dd>This parameter returns the number of allocations used out of the
    +-** [scratch memory allocator] configured using
    +-** [SQLITE_CONFIG_SCRATCH].  The value returned is in allocations, not
    +-** in bytes.  Since a single thread may only have one scratch allocation
    +-** outstanding at time, this parameter also reports the number of threads
    +-** using scratch memory at the same time.</dd>)^
    ++** [[SQLITE_STATUS_SCRATCH_USED]] <dt>SQLITE_STATUS_SCRATCH_USED</dt>
    ++** <dd>No longer used.</dd>
    + **
    + ** [[SQLITE_STATUS_SCRATCH_OVERFLOW]] ^(<dt>SQLITE_STATUS_SCRATCH_OVERFLOW</dt>
    +-** <dd>This parameter returns the number of bytes of scratch memory
    +-** allocation which could not be satisfied by the [SQLITE_CONFIG_SCRATCH]
    +-** buffer and where forced to overflow to [sqlite3_malloc()].  The values
    +-** returned include overflows because the requested allocation was too
    +-** larger (that is, because the requested allocation was larger than the
    +-** "sz" parameter to [SQLITE_CONFIG_SCRATCH]) and because no scratch buffer
    +-** slots were available.
    +-** </dd>)^
    +-**
    +-** [[SQLITE_STATUS_SCRATCH_SIZE]] ^(<dt>SQLITE_STATUS_SCRATCH_SIZE</dt>
    +-** <dd>This parameter records the largest memory allocation request
    +-** handed to [scratch memory allocator].  Only the value returned in the
    +-** *pHighwater parameter to [sqlite3_status()] is of interest.  
    +-** The value written into the *pCurrent parameter is undefined.</dd>)^
    ++** <dd>No longer used.</dd>
    ++**
    ++** [[SQLITE_STATUS_SCRATCH_SIZE]] <dt>SQLITE_STATUS_SCRATCH_SIZE</dt>
    ++** <dd>No longer used.</dd>
    + **
    + ** [[SQLITE_STATUS_PARSER_STACK]] ^(<dt>SQLITE_STATUS_PARSER_STACK</dt>
    +-** <dd>This parameter records the deepest parser stack.  It is only
    ++** <dd>The *pHighwater parameter records the deepest parser stack. 
    ++** The *pCurrent value is undefined.  The *pHighwater value is only
    + ** meaningful if SQLite is compiled with [YYTRACKMAXSTACKDEPTH].</dd>)^
    + ** </dl>
    + **
    +@@ -6795,12 +8190,12 @@ SQLITE_API int SQLITE_STDCALL sqlite3_status64(
    + #define SQLITE_STATUS_MEMORY_USED          0
    + #define SQLITE_STATUS_PAGECACHE_USED       1
    + #define SQLITE_STATUS_PAGECACHE_OVERFLOW   2
    +-#define SQLITE_STATUS_SCRATCH_USED         3
    +-#define SQLITE_STATUS_SCRATCH_OVERFLOW     4
    ++#define SQLITE_STATUS_SCRATCH_USED         3  /* NOT USED */
    ++#define SQLITE_STATUS_SCRATCH_OVERFLOW     4  /* NOT USED */
    + #define SQLITE_STATUS_MALLOC_SIZE          5
    + #define SQLITE_STATUS_PARSER_STACK         6
    + #define SQLITE_STATUS_PAGECACHE_SIZE       7
    +-#define SQLITE_STATUS_SCRATCH_SIZE         8
    ++#define SQLITE_STATUS_SCRATCH_SIZE         8  /* NOT USED */
    + #define SQLITE_STATUS_MALLOC_COUNT         9
    + 
    + /*
    +@@ -6826,7 +8221,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_status64(
    + **
    + ** See also: [sqlite3_status()] and [sqlite3_stmt_status()].
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_db_status(sqlite3*, int op, int *pCur, int *pHiwtr, int resetFlg);
    ++SQLITE_API int sqlite3_db_status(sqlite3*, int op, int *pCur, int *pHiwtr, int resetFlg);
    + 
    + /*
    + ** CAPI3REF: Status Parameters for database connections
    +@@ -6872,6 +8267,18 @@ SQLITE_API int SQLITE_STDCALL sqlite3_db_status(sqlite3*, int op, int *pCur, int
    + ** memory used by all pager caches associated with the database connection.)^
    + ** ^The highwater mark associated with SQLITE_DBSTATUS_CACHE_USED is always 0.
    + **
    ++** [[SQLITE_DBSTATUS_CACHE_USED_SHARED]] 
    ++** ^(<dt>SQLITE_DBSTATUS_CACHE_USED_SHARED</dt>
    ++** <dd>This parameter is similar to DBSTATUS_CACHE_USED, except that if a
    ++** pager cache is shared between two or more connections the bytes of heap
    ++** memory used by that pager cache is divided evenly between the attached
    ++** connections.)^  In other words, if none of the pager caches associated
    ++** with the database connection are shared, this request returns the same
    ++** value as DBSTATUS_CACHE_USED. Or, if one or more or the pager caches are
    ++** shared, the value returned by this call will be smaller than that returned
    ++** by DBSTATUS_CACHE_USED. ^The highwater mark associated with
    ++** SQLITE_DBSTATUS_CACHE_USED_SHARED is always 0.
    ++**
    + ** [[SQLITE_DBSTATUS_SCHEMA_USED]] ^(<dt>SQLITE_DBSTATUS_SCHEMA_USED</dt>
    + ** <dd>This parameter returns the approximate number of bytes of heap
    + ** memory used to store the schema for all databases associated
    +@@ -6929,7 +8336,8 @@ SQLITE_API int SQLITE_STDCALL sqlite3_db_status(sqlite3*, int op, int *pCur, int
    + #define SQLITE_DBSTATUS_CACHE_MISS           8
    + #define SQLITE_DBSTATUS_CACHE_WRITE          9
    + #define SQLITE_DBSTATUS_DEFERRED_FKS        10
    +-#define SQLITE_DBSTATUS_MAX                 10   /* Largest defined DBSTATUS */
    ++#define SQLITE_DBSTATUS_CACHE_USED_SHARED   11
    ++#define SQLITE_DBSTATUS_MAX                 11   /* Largest defined DBSTATUS */
    + 
    + 
    + /*
    +@@ -6956,7 +8364,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_db_status(sqlite3*, int op, int *pCur, int
    + **
    + ** See also: [sqlite3_status()] and [sqlite3_db_status()].
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_stmt_status(sqlite3_stmt*, int op,int resetFlg);
    ++SQLITE_API int sqlite3_stmt_status(sqlite3_stmt*, int op,int resetFlg);
    + 
    + /*
    + ** CAPI3REF: Status Parameters for prepared statements
    +@@ -6992,6 +8400,24 @@ SQLITE_API int SQLITE_STDCALL sqlite3_stmt_status(sqlite3_stmt*, int op,int rese
    + ** used as a proxy for the total work done by the prepared statement.
    + ** If the number of virtual machine operations exceeds 2147483647
    + ** then the value returned by this statement status code is undefined.
    ++**
    ++** [[SQLITE_STMTSTATUS_REPREPARE]] <dt>SQLITE_STMTSTATUS_REPREPARE</dt>
    ++** <dd>^This is the number of times that the prepare statement has been
    ++** automatically regenerated due to schema changes or change to 
    ++** [bound parameters] that might affect the query plan.
    ++**
    ++** [[SQLITE_STMTSTATUS_RUN]] <dt>SQLITE_STMTSTATUS_RUN</dt>
    ++** <dd>^This is the number of times that the prepared statement has
    ++** been run.  A single "run" for the purposes of this counter is one
    ++** or more calls to [sqlite3_step()] followed by a call to [sqlite3_reset()].
    ++** The counter is incremented on the first [sqlite3_step()] call of each
    ++** cycle.
    ++**
    ++** [[SQLITE_STMTSTATUS_MEMUSED]] <dt>SQLITE_STMTSTATUS_MEMUSED</dt>
    ++** <dd>^This is the approximate number of bytes of heap memory
    ++** used to store the prepared statement.  ^This value is not actually
    ++** a counter, and so the resetFlg parameter to sqlite3_stmt_status()
    ++** is ignored when the opcode is SQLITE_STMTSTATUS_MEMUSED.
    + ** </dd>
    + ** </dl>
    + */
    +@@ -6999,6 +8425,9 @@ SQLITE_API int SQLITE_STDCALL sqlite3_stmt_status(sqlite3_stmt*, int op,int rese
    + #define SQLITE_STMTSTATUS_SORT              2
    + #define SQLITE_STMTSTATUS_AUTOINDEX         3
    + #define SQLITE_STMTSTATUS_VM_STEP           4
    ++#define SQLITE_STMTSTATUS_REPREPARE         5
    ++#define SQLITE_STMTSTATUS_RUN               6
    ++#define SQLITE_STMTSTATUS_MEMUSED           99
    + 
    + /*
    + ** CAPI3REF: Custom Page Cache Object
    +@@ -7283,7 +8712,7 @@ typedef struct sqlite3_backup sqlite3_backup;
    + ** must be different or else sqlite3_backup_init(D,N,S,M) will fail with
    + ** an error.
    + **
    +-** ^A call to sqlite3_backup_init() will fail, returning SQLITE_ERROR, if 
    ++** ^A call to sqlite3_backup_init() will fail, returning NULL, if 
    + ** there is already a read or read-write transaction open on the 
    + ** destination database.
    + **
    +@@ -7425,16 +8854,16 @@ typedef struct sqlite3_backup sqlite3_backup;
    + ** same time as another thread is invoking sqlite3_backup_step() it is
    + ** possible that they return invalid values.
    + */
    +-SQLITE_API sqlite3_backup *SQLITE_STDCALL sqlite3_backup_init(
    ++SQLITE_API sqlite3_backup *sqlite3_backup_init(
    +   sqlite3 *pDest,                        /* Destination database handle */
    +   const char *zDestName,                 /* Destination database name */
    +   sqlite3 *pSource,                      /* Source database handle */
    +   const char *zSourceName                /* Source database name */
    + );
    +-SQLITE_API int SQLITE_STDCALL sqlite3_backup_step(sqlite3_backup *p, int nPage);
    +-SQLITE_API int SQLITE_STDCALL sqlite3_backup_finish(sqlite3_backup *p);
    +-SQLITE_API int SQLITE_STDCALL sqlite3_backup_remaining(sqlite3_backup *p);
    +-SQLITE_API int SQLITE_STDCALL sqlite3_backup_pagecount(sqlite3_backup *p);
    ++SQLITE_API int sqlite3_backup_step(sqlite3_backup *p, int nPage);
    ++SQLITE_API int sqlite3_backup_finish(sqlite3_backup *p);
    ++SQLITE_API int sqlite3_backup_remaining(sqlite3_backup *p);
    ++SQLITE_API int sqlite3_backup_pagecount(sqlite3_backup *p);
    + 
    + /*
    + ** CAPI3REF: Unlock Notification
    +@@ -7551,7 +8980,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_backup_pagecount(sqlite3_backup *p);
    + ** the special "DROP TABLE/INDEX" case, the extended error code is just 
    + ** SQLITE_LOCKED.)^
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_unlock_notify(
    ++SQLITE_API int sqlite3_unlock_notify(
    +   sqlite3 *pBlocked,                          /* Waiting connection */
    +   void (*xNotify)(void **apArg, int nArg),    /* Callback function to invoke */
    +   void *pNotifyArg                            /* Argument to pass to xNotify */
    +@@ -7566,23 +8995,48 @@ SQLITE_API int SQLITE_STDCALL sqlite3_unlock_notify(
    + ** strings in a case-independent fashion, using the same definition of "case
    + ** independence" that SQLite uses internally when comparing identifiers.
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_stricmp(const char *, const char *);
    +-SQLITE_API int SQLITE_STDCALL sqlite3_strnicmp(const char *, const char *, int);
    ++SQLITE_API int sqlite3_stricmp(const char *, const char *);
    ++SQLITE_API int sqlite3_strnicmp(const char *, const char *, int);
    + 
    + /*
    + ** CAPI3REF: String Globbing
    + *
    +-** ^The [sqlite3_strglob(P,X)] interface returns zero if string X matches
    +-** the glob pattern P, and it returns non-zero if string X does not match
    +-** the glob pattern P.  ^The definition of glob pattern matching used in
    ++** ^The [sqlite3_strglob(P,X)] interface returns zero if and only if
    ++** string X matches the [GLOB] pattern P.
    ++** ^The definition of [GLOB] pattern matching used in
    + ** [sqlite3_strglob(P,X)] is the same as for the "X GLOB P" operator in the
    +-** SQL dialect used by SQLite.  ^The sqlite3_strglob(P,X) function is case
    +-** sensitive.
    ++** SQL dialect understood by SQLite.  ^The [sqlite3_strglob(P,X)] function
    ++** is case sensitive.
    ++**
    ++** Note that this routine returns zero on a match and non-zero if the strings
    ++** do not match, the same as [sqlite3_stricmp()] and [sqlite3_strnicmp()].
    ++**
    ++** See also: [sqlite3_strlike()].
    ++*/
    ++SQLITE_API int sqlite3_strglob(const char *zGlob, const char *zStr);
    ++
    ++/*
    ++** CAPI3REF: String LIKE Matching
    ++*
    ++** ^The [sqlite3_strlike(P,X,E)] interface returns zero if and only if
    ++** string X matches the [LIKE] pattern P with escape character E.
    ++** ^The definition of [LIKE] pattern matching used in
    ++** [sqlite3_strlike(P,X,E)] is the same as for the "X LIKE P ESCAPE E"
    ++** operator in the SQL dialect understood by SQLite.  ^For "X LIKE P" without
    ++** the ESCAPE clause, set the E parameter of [sqlite3_strlike(P,X,E)] to 0.
    ++** ^As with the LIKE operator, the [sqlite3_strlike(P,X,E)] function is case
    ++** insensitive - equivalent upper and lower case ASCII characters match
    ++** one another.
    ++**
    ++** ^The [sqlite3_strlike(P,X,E)] function matches Unicode characters, though
    ++** only ASCII characters are case folded.
    + **
    + ** Note that this routine returns zero on a match and non-zero if the strings
    + ** do not match, the same as [sqlite3_stricmp()] and [sqlite3_strnicmp()].
    ++**
    ++** See also: [sqlite3_strglob()].
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_strglob(const char *zGlob, const char *zStr);
    ++SQLITE_API int sqlite3_strlike(const char *zGlob, const char *zStr, unsigned int cEsc);
    + 
    + /*
    + ** CAPI3REF: Error Logging Interface
    +@@ -7605,7 +9059,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_strglob(const char *zGlob, const char *zSt
    + ** a few hundred characters, it will be truncated to the length of the
    + ** buffer.
    + */
    +-SQLITE_API void SQLITE_CDECL sqlite3_log(int iErrCode, const char *zFormat, ...);
    ++SQLITE_API void sqlite3_log(int iErrCode, const char *zFormat, ...);
    + 
    + /*
    + ** CAPI3REF: Write-Ahead Log Commit Hook
    +@@ -7639,9 +9093,9 @@ SQLITE_API void SQLITE_CDECL sqlite3_log(int iErrCode, const char *zFormat, ...)
    + ** previously registered write-ahead log callback. ^Note that the
    + ** [sqlite3_wal_autocheckpoint()] interface and the
    + ** [wal_autocheckpoint pragma] both invoke [sqlite3_wal_hook()] and will
    +-** those overwrite any prior [sqlite3_wal_hook()] settings.
    ++** overwrite any prior [sqlite3_wal_hook()] settings.
    + */
    +-SQLITE_API void *SQLITE_STDCALL sqlite3_wal_hook(
    ++SQLITE_API void *sqlite3_wal_hook(
    +   sqlite3*, 
    +   int(*)(void *,sqlite3*,const char*,int),
    +   void*
    +@@ -7676,7 +9130,7 @@ SQLITE_API void *SQLITE_STDCALL sqlite3_wal_hook(
    + ** is only necessary if the default setting is found to be suboptimal
    + ** for a particular application.
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_wal_autocheckpoint(sqlite3 *db, int N);
    ++SQLITE_API int sqlite3_wal_autocheckpoint(sqlite3 *db, int N);
    + 
    + /*
    + ** CAPI3REF: Checkpoint a database
    +@@ -7698,7 +9152,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_wal_autocheckpoint(sqlite3 *db, int N);
    + ** start a callback but which do not need the full power (and corresponding
    + ** complication) of [sqlite3_wal_checkpoint_v2()].
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_wal_checkpoint(sqlite3 *db, const char *zDb);
    ++SQLITE_API int sqlite3_wal_checkpoint(sqlite3 *db, const char *zDb);
    + 
    + /*
    + ** CAPI3REF: Checkpoint a database
    +@@ -7792,7 +9246,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_wal_checkpoint(sqlite3 *db, const char *zD
    + ** ^The [PRAGMA wal_checkpoint] command can be used to invoke this interface
    + ** from SQL.
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_wal_checkpoint_v2(
    ++SQLITE_API int sqlite3_wal_checkpoint_v2(
    +   sqlite3 *db,                    /* Database handle */
    +   const char *zDb,                /* Name of attached database (or NULL) */
    +   int eMode,                      /* SQLITE_CHECKPOINT_* value */
    +@@ -7828,7 +9282,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_wal_checkpoint_v2(
    + ** this function. (See [SQLITE_VTAB_CONSTRAINT_SUPPORT].)  Further options
    + ** may be added in the future.
    + */
    +-SQLITE_API int SQLITE_CDECL sqlite3_vtab_config(sqlite3*, int op, ...);
    ++SQLITE_API int sqlite3_vtab_config(sqlite3*, int op, ...);
    + 
    + /*
    + ** CAPI3REF: Virtual Table Configuration Options
    +@@ -7881,7 +9335,41 @@ SQLITE_API int SQLITE_CDECL sqlite3_vtab_config(sqlite3*, int op, ...);
    + ** of the SQL statement that triggered the call to the [xUpdate] method of the
    + ** [virtual table].
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_vtab_on_conflict(sqlite3 *);
    ++SQLITE_API int sqlite3_vtab_on_conflict(sqlite3 *);
    ++
    ++/*
    ++** CAPI3REF: Determine If Virtual Table Column Access Is For UPDATE
    ++**
    ++** If the sqlite3_vtab_nochange(X) routine is called within the [xColumn]
    ++** method of a [virtual table], then it returns true if and only if the
    ++** column is being fetched as part of an UPDATE operation during which the
    ++** column value will not change.  Applications might use this to substitute
    ++** a lighter-weight value to return that the corresponding [xUpdate] method
    ++** understands as a "no-change" value.
    ++**
    ++** If the [xColumn] method calls sqlite3_vtab_nochange() and finds that
    ++** the column is not changed by the UPDATE statement, they the xColumn
    ++** method can optionally return without setting a result, without calling
    ++** any of the [sqlite3_result_int|sqlite3_result_xxxxx() interfaces].
    ++** In that case, [sqlite3_value_nochange(X)] will return true for the
    ++** same column in the [xUpdate] method.
    ++*/
    ++SQLITE_API int sqlite3_vtab_nochange(sqlite3_context*);
    ++
    ++/*
    ++** CAPI3REF: Determine The Collation For a Virtual Table Constraint
    ++**
    ++** This function may only be called from within a call to the [xBestIndex]
    ++** method of a [virtual table]. 
    ++**
    ++** The first argument must be the sqlite3_index_info object that is the
    ++** first parameter to the xBestIndex() method. The second argument must be
    ++** an index into the aConstraint[] array belonging to the sqlite3_index_info
    ++** structure passed to xBestIndex. This function returns a pointer to a buffer 
    ++** containing the name of the collation sequence for the corresponding
    ++** constraint.
    ++*/
    ++SQLITE_API SQLITE_EXPERIMENTAL const char *sqlite3_vtab_collation(sqlite3_index_info*,int);
    + 
    + /*
    + ** CAPI3REF: Conflict resolution modes
    +@@ -7986,7 +9474,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_vtab_on_conflict(sqlite3 *);
    + **
    + ** See also: [sqlite3_stmt_scanstatus_reset()]
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_stmt_scanstatus(
    ++SQLITE_API int sqlite3_stmt_scanstatus(
    +   sqlite3_stmt *pStmt,      /* Prepared statement for which info desired */
    +   int idx,                  /* Index of loop to report on */
    +   int iScanStatusOp,        /* Information desired.  SQLITE_SCANSTAT_* */
    +@@ -8002,8 +9490,332 @@ SQLITE_API int SQLITE_STDCALL sqlite3_stmt_scanstatus(
    + ** This API is only available if the library is built with pre-processor
    + ** symbol [SQLITE_ENABLE_STMT_SCANSTATUS] defined.
    + */
    +-SQLITE_API void SQLITE_STDCALL sqlite3_stmt_scanstatus_reset(sqlite3_stmt*);
    ++SQLITE_API void sqlite3_stmt_scanstatus_reset(sqlite3_stmt*);
    ++
    ++/*
    ++** CAPI3REF: Flush caches to disk mid-transaction
    ++**
    ++** ^If a write-transaction is open on [database connection] D when the
    ++** [sqlite3_db_cacheflush(D)] interface invoked, any dirty
    ++** pages in the pager-cache that are not currently in use are written out 
    ++** to disk. A dirty page may be in use if a database cursor created by an
    ++** active SQL statement is reading from it, or if it is page 1 of a database
    ++** file (page 1 is always "in use").  ^The [sqlite3_db_cacheflush(D)]
    ++** interface flushes caches for all schemas - "main", "temp", and
    ++** any [attached] databases.
    ++**
    ++** ^If this function needs to obtain extra database locks before dirty pages 
    ++** can be flushed to disk, it does so. ^If those locks cannot be obtained 
    ++** immediately and there is a busy-handler callback configured, it is invoked
    ++** in the usual manner. ^If the required lock still cannot be obtained, then
    ++** the database is skipped and an attempt made to flush any dirty pages
    ++** belonging to the next (if any) database. ^If any databases are skipped
    ++** because locks cannot be obtained, but no other error occurs, this
    ++** function returns SQLITE_BUSY.
    ++**
    ++** ^If any other error occurs while flushing dirty pages to disk (for
    ++** example an IO error or out-of-memory condition), then processing is
    ++** abandoned and an SQLite [error code] is returned to the caller immediately.
    ++**
    ++** ^Otherwise, if no error occurs, [sqlite3_db_cacheflush()] returns SQLITE_OK.
    ++**
    ++** ^This function does not set the database handle error code or message
    ++** returned by the [sqlite3_errcode()] and [sqlite3_errmsg()] functions.
    ++*/
    ++SQLITE_API int sqlite3_db_cacheflush(sqlite3*);
    ++
    ++/*
    ++** CAPI3REF: The pre-update hook.
    ++**
    ++** ^These interfaces are only available if SQLite is compiled using the
    ++** [SQLITE_ENABLE_PREUPDATE_HOOK] compile-time option.
    ++**
    ++** ^The [sqlite3_preupdate_hook()] interface registers a callback function
    ++** that is invoked prior to each [INSERT], [UPDATE], and [DELETE] operation
    ++** on a database table.
    ++** ^At most one preupdate hook may be registered at a time on a single
    ++** [database connection]; each call to [sqlite3_preupdate_hook()] overrides
    ++** the previous setting.
    ++** ^The preupdate hook is disabled by invoking [sqlite3_preupdate_hook()]
    ++** with a NULL pointer as the second parameter.
    ++** ^The third parameter to [sqlite3_preupdate_hook()] is passed through as
    ++** the first parameter to callbacks.
    ++**
    ++** ^The preupdate hook only fires for changes to real database tables; the
    ++** preupdate hook is not invoked for changes to [virtual tables] or to
    ++** system tables like sqlite_master or sqlite_stat1.
    ++**
    ++** ^The second parameter to the preupdate callback is a pointer to
    ++** the [database connection] that registered the preupdate hook.
    ++** ^The third parameter to the preupdate callback is one of the constants
    ++** [SQLITE_INSERT], [SQLITE_DELETE], or [SQLITE_UPDATE] to identify the
    ++** kind of update operation that is about to occur.
    ++** ^(The fourth parameter to the preupdate callback is the name of the
    ++** database within the database connection that is being modified.  This
    ++** will be "main" for the main database or "temp" for TEMP tables or 
    ++** the name given after the AS keyword in the [ATTACH] statement for attached
    ++** databases.)^
    ++** ^The fifth parameter to the preupdate callback is the name of the
    ++** table that is being modified.
    ++**
    ++** For an UPDATE or DELETE operation on a [rowid table], the sixth
    ++** parameter passed to the preupdate callback is the initial [rowid] of the 
    ++** row being modified or deleted. For an INSERT operation on a rowid table,
    ++** or any operation on a WITHOUT ROWID table, the value of the sixth 
    ++** parameter is undefined. For an INSERT or UPDATE on a rowid table the
    ++** seventh parameter is the final rowid value of the row being inserted
    ++** or updated. The value of the seventh parameter passed to the callback
    ++** function is not defined for operations on WITHOUT ROWID tables, or for
    ++** INSERT operations on rowid tables.
    ++**
    ++** The [sqlite3_preupdate_old()], [sqlite3_preupdate_new()],
    ++** [sqlite3_preupdate_count()], and [sqlite3_preupdate_depth()] interfaces
    ++** provide additional information about a preupdate event. These routines
    ++** may only be called from within a preupdate callback.  Invoking any of
    ++** these routines from outside of a preupdate callback or with a
    ++** [database connection] pointer that is different from the one supplied
    ++** to the preupdate callback results in undefined and probably undesirable
    ++** behavior.
    ++**
    ++** ^The [sqlite3_preupdate_count(D)] interface returns the number of columns
    ++** in the row that is being inserted, updated, or deleted.
    ++**
    ++** ^The [sqlite3_preupdate_old(D,N,P)] interface writes into P a pointer to
    ++** a [protected sqlite3_value] that contains the value of the Nth column of
    ++** the table row before it is updated.  The N parameter must be between 0
    ++** and one less than the number of columns or the behavior will be
    ++** undefined. This must only be used within SQLITE_UPDATE and SQLITE_DELETE
    ++** preupdate callbacks; if it is used by an SQLITE_INSERT callback then the
    ++** behavior is undefined.  The [sqlite3_value] that P points to
    ++** will be destroyed when the preupdate callback returns.
    ++**
    ++** ^The [sqlite3_preupdate_new(D,N,P)] interface writes into P a pointer to
    ++** a [protected sqlite3_value] that contains the value of the Nth column of
    ++** the table row after it is updated.  The N parameter must be between 0
    ++** and one less than the number of columns or the behavior will be
    ++** undefined. This must only be used within SQLITE_INSERT and SQLITE_UPDATE
    ++** preupdate callbacks; if it is used by an SQLITE_DELETE callback then the
    ++** behavior is undefined.  The [sqlite3_value] that P points to
    ++** will be destroyed when the preupdate callback returns.
    ++**
    ++** ^The [sqlite3_preupdate_depth(D)] interface returns 0 if the preupdate
    ++** callback was invoked as a result of a direct insert, update, or delete
    ++** operation; or 1 for inserts, updates, or deletes invoked by top-level 
    ++** triggers; or 2 for changes resulting from triggers called by top-level
    ++** triggers; and so forth.
    ++**
    ++** See also:  [sqlite3_update_hook()]
    ++*/
    ++#if defined(SQLITE_ENABLE_PREUPDATE_HOOK)
    ++SQLITE_API void *sqlite3_preupdate_hook(
    ++  sqlite3 *db,
    ++  void(*xPreUpdate)(
    ++    void *pCtx,                   /* Copy of third arg to preupdate_hook() */
    ++    sqlite3 *db,                  /* Database handle */
    ++    int op,                       /* SQLITE_UPDATE, DELETE or INSERT */
    ++    char const *zDb,              /* Database name */
    ++    char const *zName,            /* Table name */
    ++    sqlite3_int64 iKey1,          /* Rowid of row about to be deleted/updated */
    ++    sqlite3_int64 iKey2           /* New rowid value (for a rowid UPDATE) */
    ++  ),
    ++  void*
    ++);
    ++SQLITE_API int sqlite3_preupdate_old(sqlite3 *, int, sqlite3_value **);
    ++SQLITE_API int sqlite3_preupdate_count(sqlite3 *);
    ++SQLITE_API int sqlite3_preupdate_depth(sqlite3 *);
    ++SQLITE_API int sqlite3_preupdate_new(sqlite3 *, int, sqlite3_value **);
    ++#endif
    ++
    ++/*
    ++** CAPI3REF: Low-level system error code
    ++**
    ++** ^Attempt to return the underlying operating system error code or error
    ++** number that caused the most recent I/O error or failure to open a file.
    ++** The return value is OS-dependent.  For example, on unix systems, after
    ++** [sqlite3_open_v2()] returns [SQLITE_CANTOPEN], this interface could be
    ++** called to get back the underlying "errno" that caused the problem, such
    ++** as ENOSPC, EAUTH, EISDIR, and so forth.  
    ++*/
    ++SQLITE_API int sqlite3_system_errno(sqlite3*);
    + 
    ++/*
    ++** CAPI3REF: Database Snapshot
    ++** KEYWORDS: {snapshot} {sqlite3_snapshot}
    ++** EXPERIMENTAL
    ++**
    ++** An instance of the snapshot object records the state of a [WAL mode]
    ++** database for some specific point in history.
    ++**
    ++** In [WAL mode], multiple [database connections] that are open on the
    ++** same database file can each be reading a different historical version
    ++** of the database file.  When a [database connection] begins a read
    ++** transaction, that connection sees an unchanging copy of the database
    ++** as it existed for the point in time when the transaction first started.
    ++** Subsequent changes to the database from other connections are not seen
    ++** by the reader until a new read transaction is started.
    ++**
    ++** The sqlite3_snapshot object records state information about an historical
    ++** version of the database file so that it is possible to later open a new read
    ++** transaction that sees that historical version of the database rather than
    ++** the most recent version.
    ++**
    ++** The constructor for this object is [sqlite3_snapshot_get()].  The
    ++** [sqlite3_snapshot_open()] method causes a fresh read transaction to refer
    ++** to an historical snapshot (if possible).  The destructor for 
    ++** sqlite3_snapshot objects is [sqlite3_snapshot_free()].
    ++*/
    ++typedef struct sqlite3_snapshot {
    ++  unsigned char hidden[48];
    ++} sqlite3_snapshot;
    ++
    ++/*
    ++** CAPI3REF: Record A Database Snapshot
    ++** EXPERIMENTAL
    ++**
    ++** ^The [sqlite3_snapshot_get(D,S,P)] interface attempts to make a
    ++** new [sqlite3_snapshot] object that records the current state of
    ++** schema S in database connection D.  ^On success, the
    ++** [sqlite3_snapshot_get(D,S,P)] interface writes a pointer to the newly
    ++** created [sqlite3_snapshot] object into *P and returns SQLITE_OK.
    ++** If there is not already a read-transaction open on schema S when
    ++** this function is called, one is opened automatically. 
    ++**
    ++** The following must be true for this function to succeed. If any of
    ++** the following statements are false when sqlite3_snapshot_get() is
    ++** called, SQLITE_ERROR is returned. The final value of *P is undefined
    ++** in this case. 
    ++**
    ++** <ul>
    ++**   <li> The database handle must be in [autocommit mode].
    ++**
    ++**   <li> Schema S of [database connection] D must be a [WAL mode] database.
    ++**
    ++**   <li> There must not be a write transaction open on schema S of database
    ++**        connection D.
    ++**
    ++**   <li> One or more transactions must have been written to the current wal
    ++**        file since it was created on disk (by any connection). This means
    ++**        that a snapshot cannot be taken on a wal mode database with no wal 
    ++**        file immediately after it is first opened. At least one transaction
    ++**        must be written to it first.
    ++** </ul>
    ++**
    ++** This function may also return SQLITE_NOMEM.  If it is called with the
    ++** database handle in autocommit mode but fails for some other reason, 
    ++** whether or not a read transaction is opened on schema S is undefined.
    ++**
    ++** The [sqlite3_snapshot] object returned from a successful call to
    ++** [sqlite3_snapshot_get()] must be freed using [sqlite3_snapshot_free()]
    ++** to avoid a memory leak.
    ++**
    ++** The [sqlite3_snapshot_get()] interface is only available when the
    ++** SQLITE_ENABLE_SNAPSHOT compile-time option is used.
    ++*/
    ++SQLITE_API SQLITE_EXPERIMENTAL int sqlite3_snapshot_get(
    ++  sqlite3 *db,
    ++  const char *zSchema,
    ++  sqlite3_snapshot **ppSnapshot
    ++);
    ++
    ++/*
    ++** CAPI3REF: Start a read transaction on an historical snapshot
    ++** EXPERIMENTAL
    ++**
    ++** ^The [sqlite3_snapshot_open(D,S,P)] interface starts a
    ++** read transaction for schema S of
    ++** [database connection] D such that the read transaction
    ++** refers to historical [snapshot] P, rather than the most
    ++** recent change to the database.
    ++** ^The [sqlite3_snapshot_open()] interface returns SQLITE_OK on success
    ++** or an appropriate [error code] if it fails.
    ++**
    ++** ^In order to succeed, a call to [sqlite3_snapshot_open(D,S,P)] must be
    ++** the first operation following the [BEGIN] that takes the schema S
    ++** out of [autocommit mode].
    ++** ^In other words, schema S must not currently be in
    ++** a transaction for [sqlite3_snapshot_open(D,S,P)] to work, but the
    ++** database connection D must be out of [autocommit mode].
    ++** ^A [snapshot] will fail to open if it has been overwritten by a
    ++** [checkpoint].
    ++** ^(A call to [sqlite3_snapshot_open(D,S,P)] will fail if the
    ++** database connection D does not know that the database file for
    ++** schema S is in [WAL mode].  A database connection might not know
    ++** that the database file is in [WAL mode] if there has been no prior
    ++** I/O on that database connection, or if the database entered [WAL mode] 
    ++** after the most recent I/O on the database connection.)^
    ++** (Hint: Run "[PRAGMA application_id]" against a newly opened
    ++** database connection in order to make it ready to use snapshots.)
    ++**
    ++** The [sqlite3_snapshot_open()] interface is only available when the
    ++** SQLITE_ENABLE_SNAPSHOT compile-time option is used.
    ++*/
    ++SQLITE_API SQLITE_EXPERIMENTAL int sqlite3_snapshot_open(
    ++  sqlite3 *db,
    ++  const char *zSchema,
    ++  sqlite3_snapshot *pSnapshot
    ++);
    ++
    ++/*
    ++** CAPI3REF: Destroy a snapshot
    ++** EXPERIMENTAL
    ++**
    ++** ^The [sqlite3_snapshot_free(P)] interface destroys [sqlite3_snapshot] P.
    ++** The application must eventually free every [sqlite3_snapshot] object
    ++** using this routine to avoid a memory leak.
    ++**
    ++** The [sqlite3_snapshot_free()] interface is only available when the
    ++** SQLITE_ENABLE_SNAPSHOT compile-time option is used.
    ++*/
    ++SQLITE_API SQLITE_EXPERIMENTAL void sqlite3_snapshot_free(sqlite3_snapshot*);
    ++
    ++/*
    ++** CAPI3REF: Compare the ages of two snapshot handles.
    ++** EXPERIMENTAL
    ++**
    ++** The sqlite3_snapshot_cmp(P1, P2) interface is used to compare the ages
    ++** of two valid snapshot handles. 
    ++**
    ++** If the two snapshot handles are not associated with the same database 
    ++** file, the result of the comparison is undefined. 
    ++**
    ++** Additionally, the result of the comparison is only valid if both of the
    ++** snapshot handles were obtained by calling sqlite3_snapshot_get() since the
    ++** last time the wal file was deleted. The wal file is deleted when the
    ++** database is changed back to rollback mode or when the number of database
    ++** clients drops to zero. If either snapshot handle was obtained before the 
    ++** wal file was last deleted, the value returned by this function 
    ++** is undefined.
    ++**
    ++** Otherwise, this API returns a negative value if P1 refers to an older
    ++** snapshot than P2, zero if the two handles refer to the same database
    ++** snapshot, and a positive value if P1 is a newer snapshot than P2.
    ++*/
    ++SQLITE_API SQLITE_EXPERIMENTAL int sqlite3_snapshot_cmp(
    ++  sqlite3_snapshot *p1,
    ++  sqlite3_snapshot *p2
    ++);
    ++
    ++/*
    ++** CAPI3REF: Recover snapshots from a wal file
    ++** EXPERIMENTAL
    ++**
    ++** If all connections disconnect from a database file but do not perform
    ++** a checkpoint, the existing wal file is opened along with the database
    ++** file the next time the database is opened. At this point it is only
    ++** possible to successfully call sqlite3_snapshot_open() to open the most
    ++** recent snapshot of the database (the one at the head of the wal file),
    ++** even though the wal file may contain other valid snapshots for which
    ++** clients have sqlite3_snapshot handles.
    ++**
    ++** This function attempts to scan the wal file associated with database zDb
    ++** of database handle db and make all valid snapshots available to
    ++** sqlite3_snapshot_open(). It is an error if there is already a read
    ++** transaction open on the database, or if the database is not a wal mode
    ++** database.
    ++**
    ++** SQLITE_OK is returned if successful, or an SQLite error code otherwise.
    ++*/
    ++SQLITE_API SQLITE_EXPERIMENTAL int sqlite3_snapshot_recover(sqlite3 *db, const char *zDb);
    + 
    + /*
    + ** Undo the hack that converts floating point types to integer for
    +@@ -8016,8 +9828,9 @@ SQLITE_API void SQLITE_STDCALL sqlite3_stmt_scanstatus_reset(sqlite3_stmt*);
    + #if 0
    + }  /* End of the 'extern "C"' block */
    + #endif
    +-#endif /* _SQLITE3_H_ */
    ++#endif /* SQLITE3_H */
    + 
    ++/******** Begin file sqlite3rtree.h *********/
    + /*
    + ** 2010 August 30
    + **
    +@@ -8057,7 +9870,7 @@ typedef struct sqlite3_rtree_query_info sqlite3_rtree_query_info;
    + **
    + **   SELECT ... FROM <rtree> WHERE <rtree col> MATCH $zGeom(... params ...)
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_rtree_geometry_callback(
    ++SQLITE_API int sqlite3_rtree_geometry_callback(
    +   sqlite3 *db,
    +   const char *zGeom,
    +   int (*xGeom)(sqlite3_rtree_geometry*, int, sqlite3_rtree_dbl*,int*),
    +@@ -8083,7 +9896,7 @@ struct sqlite3_rtree_geometry {
    + **
    + **   SELECT ... FROM <rtree> WHERE <rtree col> MATCH $zQueryFunc(... params ...)
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_rtree_query_callback(
    ++SQLITE_API int sqlite3_rtree_query_callback(
    +   sqlite3 *db,
    +   const char *zQueryFunc,
    +   int (*xQueryFunc)(sqlite3_rtree_query_info*),
    +@@ -8135,6 +9948,1327 @@ struct sqlite3_rtree_query_info {
    + 
    + #endif  /* ifndef _SQLITE3RTREE_H_ */
    + 
    ++/******** End of sqlite3rtree.h *********/
    ++/******** Begin file sqlite3session.h *********/
    ++
    ++#if !defined(__SQLITESESSION_H_) && defined(SQLITE_ENABLE_SESSION)
    ++#define __SQLITESESSION_H_ 1
    ++
    ++/*
    ++** Make sure we can call this stuff from C++.
    ++*/
    ++#if 0
    ++extern "C" {
    ++#endif
    ++
    ++
    ++/*
    ++** CAPI3REF: Session Object Handle
    ++*/
    ++typedef struct sqlite3_session sqlite3_session;
    ++
    ++/*
    ++** CAPI3REF: Changeset Iterator Handle
    ++*/
    ++typedef struct sqlite3_changeset_iter sqlite3_changeset_iter;
    ++
    ++/*
    ++** CAPI3REF: Create A New Session Object
    ++**
    ++** Create a new session object attached to database handle db. If successful,
    ++** a pointer to the new object is written to *ppSession and SQLITE_OK is
    ++** returned. If an error occurs, *ppSession is set to NULL and an SQLite
    ++** error code (e.g. SQLITE_NOMEM) is returned.
    ++**
    ++** It is possible to create multiple session objects attached to a single
    ++** database handle.
    ++**
    ++** Session objects created using this function should be deleted using the
    ++** [sqlite3session_delete()] function before the database handle that they
    ++** are attached to is itself closed. If the database handle is closed before
    ++** the session object is deleted, then the results of calling any session
    ++** module function, including [sqlite3session_delete()] on the session object
    ++** are undefined.
    ++**
    ++** Because the session module uses the [sqlite3_preupdate_hook()] API, it
    ++** is not possible for an application to register a pre-update hook on a
    ++** database handle that has one or more session objects attached. Nor is
    ++** it possible to create a session object attached to a database handle for
    ++** which a pre-update hook is already defined. The results of attempting 
    ++** either of these things are undefined.
    ++**
    ++** The session object will be used to create changesets for tables in
    ++** database zDb, where zDb is either "main", or "temp", or the name of an
    ++** attached database. It is not an error if database zDb is not attached
    ++** to the database when the session object is created.
    ++*/
    ++SQLITE_API int sqlite3session_create(
    ++  sqlite3 *db,                    /* Database handle */
    ++  const char *zDb,                /* Name of db (e.g. "main") */
    ++  sqlite3_session **ppSession     /* OUT: New session object */
    ++);
    ++
    ++/*
    ++** CAPI3REF: Delete A Session Object
    ++**
    ++** Delete a session object previously allocated using 
    ++** [sqlite3session_create()]. Once a session object has been deleted, the
    ++** results of attempting to use pSession with any other session module
    ++** function are undefined.
    ++**
    ++** Session objects must be deleted before the database handle to which they
    ++** are attached is closed. Refer to the documentation for 
    ++** [sqlite3session_create()] for details.
    ++*/
    ++SQLITE_API void sqlite3session_delete(sqlite3_session *pSession);
    ++
    ++
    ++/*
    ++** CAPI3REF: Enable Or Disable A Session Object
    ++**
    ++** Enable or disable the recording of changes by a session object. When
    ++** enabled, a session object records changes made to the database. When
    ++** disabled - it does not. A newly created session object is enabled.
    ++** Refer to the documentation for [sqlite3session_changeset()] for further
    ++** details regarding how enabling and disabling a session object affects
    ++** the eventual changesets.
    ++**
    ++** Passing zero to this function disables the session. Passing a value
    ++** greater than zero enables it. Passing a value less than zero is a 
    ++** no-op, and may be used to query the current state of the session.
    ++**
    ++** The return value indicates the final state of the session object: 0 if 
    ++** the session is disabled, or 1 if it is enabled.
    ++*/
    ++SQLITE_API int sqlite3session_enable(sqlite3_session *pSession, int bEnable);
    ++
    ++/*
    ++** CAPI3REF: Set Or Clear the Indirect Change Flag
    ++**
    ++** Each change recorded by a session object is marked as either direct or
    ++** indirect. A change is marked as indirect if either:
    ++**
    ++** <ul>
    ++**   <li> The session object "indirect" flag is set when the change is
    ++**        made, or
    ++**   <li> The change is made by an SQL trigger or foreign key action 
    ++**        instead of directly as a result of a users SQL statement.
    ++** </ul>
    ++**
    ++** If a single row is affected by more than one operation within a session,
    ++** then the change is considered indirect if all operations meet the criteria
    ++** for an indirect change above, or direct otherwise.
    ++**
    ++** This function is used to set, clear or query the session object indirect
    ++** flag.  If the second argument passed to this function is zero, then the
    ++** indirect flag is cleared. If it is greater than zero, the indirect flag
    ++** is set. Passing a value less than zero does not modify the current value
    ++** of the indirect flag, and may be used to query the current state of the 
    ++** indirect flag for the specified session object.
    ++**
    ++** The return value indicates the final state of the indirect flag: 0 if 
    ++** it is clear, or 1 if it is set.
    ++*/
    ++SQLITE_API int sqlite3session_indirect(sqlite3_session *pSession, int bIndirect);
    ++
    ++/*
    ++** CAPI3REF: Attach A Table To A Session Object
    ++**
    ++** If argument zTab is not NULL, then it is the name of a table to attach
    ++** to the session object passed as the first argument. All subsequent changes 
    ++** made to the table while the session object is enabled will be recorded. See 
    ++** documentation for [sqlite3session_changeset()] for further details.
    ++**
    ++** Or, if argument zTab is NULL, then changes are recorded for all tables
    ++** in the database. If additional tables are added to the database (by 
    ++** executing "CREATE TABLE" statements) after this call is made, changes for 
    ++** the new tables are also recorded.
    ++**
    ++** Changes can only be recorded for tables that have a PRIMARY KEY explicitly
    ++** defined as part of their CREATE TABLE statement. It does not matter if the 
    ++** PRIMARY KEY is an "INTEGER PRIMARY KEY" (rowid alias) or not. The PRIMARY
    ++** KEY may consist of a single column, or may be a composite key.
    ++** 
    ++** It is not an error if the named table does not exist in the database. Nor
    ++** is it an error if the named table does not have a PRIMARY KEY. However,
    ++** no changes will be recorded in either of these scenarios.
    ++**
    ++** Changes are not recorded for individual rows that have NULL values stored
    ++** in one or more of their PRIMARY KEY columns.
    ++**
    ++** SQLITE_OK is returned if the call completes without error. Or, if an error 
    ++** occurs, an SQLite error code (e.g. SQLITE_NOMEM) is returned.
    ++**
    ++** <h3>Special sqlite_stat1 Handling</h3>
    ++**
    ++** As of SQLite version 3.22.0, the "sqlite_stat1" table is an exception to 
    ++** some of the rules above. In SQLite, the schema of sqlite_stat1 is:
    ++**  <pre>
    ++**  &nbsp;     CREATE TABLE sqlite_stat1(tbl,idx,stat)  
    ++**  </pre>
    ++**
    ++** Even though sqlite_stat1 does not have a PRIMARY KEY, changes are 
    ++** recorded for it as if the PRIMARY KEY is (tbl,idx). Additionally, changes 
    ++** are recorded for rows for which (idx IS NULL) is true. However, for such
    ++** rows a zero-length blob (SQL value X'') is stored in the changeset or
    ++** patchset instead of a NULL value. This allows such changesets to be
    ++** manipulated by legacy implementations of sqlite3changeset_invert(),
    ++** concat() and similar.
    ++**
    ++** The sqlite3changeset_apply() function automatically converts the 
    ++** zero-length blob back to a NULL value when updating the sqlite_stat1
    ++** table. However, if the application calls sqlite3changeset_new(),
    ++** sqlite3changeset_old() or sqlite3changeset_conflict on a changeset 
    ++** iterator directly (including on a changeset iterator passed to a
    ++** conflict-handler callback) then the X'' value is returned. The application
    ++** must translate X'' to NULL itself if required.
    ++**
    ++** Legacy (older than 3.22.0) versions of the sessions module cannot capture
    ++** changes made to the sqlite_stat1 table. Legacy versions of the
    ++** sqlite3changeset_apply() function silently ignore any modifications to the
    ++** sqlite_stat1 table that are part of a changeset or patchset.
    ++*/
    ++SQLITE_API int sqlite3session_attach(
    ++  sqlite3_session *pSession,      /* Session object */
    ++  const char *zTab                /* Table name */
    ++);
    ++
    ++/*
    ++** CAPI3REF: Set a table filter on a Session Object.
    ++**
    ++** The second argument (xFilter) is the "filter callback". For changes to rows 
    ++** in tables that are not attached to the Session object, the filter is called
    ++** to determine whether changes to the table's rows should be tracked or not. 
    ++** If xFilter returns 0, changes is not tracked. Note that once a table is 
    ++** attached, xFilter will not be called again.
    ++*/
    ++SQLITE_API void sqlite3session_table_filter(
    ++  sqlite3_session *pSession,      /* Session object */
    ++  int(*xFilter)(
    ++    void *pCtx,                   /* Copy of third arg to _filter_table() */
    ++    const char *zTab              /* Table name */
    ++  ),
    ++  void *pCtx                      /* First argument passed to xFilter */
    ++);
    ++
    ++/*
    ++** CAPI3REF: Generate A Changeset From A Session Object
    ++**
    ++** Obtain a changeset containing changes to the tables attached to the 
    ++** session object passed as the first argument. If successful, 
    ++** set *ppChangeset to point to a buffer containing the changeset 
    ++** and *pnChangeset to the size of the changeset in bytes before returning
    ++** SQLITE_OK. If an error occurs, set both *ppChangeset and *pnChangeset to
    ++** zero and return an SQLite error code.
    ++**
    ++** A changeset consists of zero or more INSERT, UPDATE and/or DELETE changes,
    ++** each representing a change to a single row of an attached table. An INSERT
    ++** change contains the values of each field of a new database row. A DELETE
    ++** contains the original values of each field of a deleted database row. An
    ++** UPDATE change contains the original values of each field of an updated
    ++** database row along with the updated values for each updated non-primary-key
    ++** column. It is not possible for an UPDATE change to represent a change that
    ++** modifies the values of primary key columns. If such a change is made, it
    ++** is represented in a changeset as a DELETE followed by an INSERT.
    ++**
    ++** Changes are not recorded for rows that have NULL values stored in one or 
    ++** more of their PRIMARY KEY columns. If such a row is inserted or deleted,
    ++** no corresponding change is present in the changesets returned by this
    ++** function. If an existing row with one or more NULL values stored in
    ++** PRIMARY KEY columns is updated so that all PRIMARY KEY columns are non-NULL,
    ++** only an INSERT is appears in the changeset. Similarly, if an existing row
    ++** with non-NULL PRIMARY KEY values is updated so that one or more of its
    ++** PRIMARY KEY columns are set to NULL, the resulting changeset contains a
    ++** DELETE change only.
    ++**
    ++** The contents of a changeset may be traversed using an iterator created
    ++** using the [sqlite3changeset_start()] API. A changeset may be applied to
    ++** a database with a compatible schema using the [sqlite3changeset_apply()]
    ++** API.
    ++**
    ++** Within a changeset generated by this function, all changes related to a
    ++** single table are grouped together. In other words, when iterating through
    ++** a changeset or when applying a changeset to a database, all changes related
    ++** to a single table are processed before moving on to the next table. Tables
    ++** are sorted in the same order in which they were attached (or auto-attached)
    ++** to the sqlite3_session object. The order in which the changes related to
    ++** a single table are stored is undefined.
    ++**
    ++** Following a successful call to this function, it is the responsibility of
    ++** the caller to eventually free the buffer that *ppChangeset points to using
    ++** [sqlite3_free()].
    ++**
    ++** <h3>Changeset Generation</h3>
    ++**
    ++** Once a table has been attached to a session object, the session object
    ++** records the primary key values of all new rows inserted into the table.
    ++** It also records the original primary key and other column values of any
    ++** deleted or updated rows. For each unique primary key value, data is only
    ++** recorded once - the first time a row with said primary key is inserted,
    ++** updated or deleted in the lifetime of the session.
    ++**
    ++** There is one exception to the previous paragraph: when a row is inserted,
    ++** updated or deleted, if one or more of its primary key columns contain a
    ++** NULL value, no record of the change is made.
    ++**
    ++** The session object therefore accumulates two types of records - those
    ++** that consist of primary key values only (created when the user inserts
    ++** a new record) and those that consist of the primary key values and the
    ++** original values of other table columns (created when the users deletes
    ++** or updates a record).
    ++**
    ++** When this function is called, the requested changeset is created using
    ++** both the accumulated records and the current contents of the database
    ++** file. Specifically:
    ++**
    ++** <ul>
    ++**   <li> For each record generated by an insert, the database is queried
    ++**        for a row with a matching primary key. If one is found, an INSERT
    ++**        change is added to the changeset. If no such row is found, no change 
    ++**        is added to the changeset.
    ++**
    ++**   <li> For each record generated by an update or delete, the database is 
    ++**        queried for a row with a matching primary key. If such a row is
    ++**        found and one or more of the non-primary key fields have been
    ++**        modified from their original values, an UPDATE change is added to 
    ++**        the changeset. Or, if no such row is found in the table, a DELETE 
    ++**        change is added to the changeset. If there is a row with a matching
    ++**        primary key in the database, but all fields contain their original
    ++**        values, no change is added to the changeset.
    ++** </ul>
    ++**
    ++** This means, amongst other things, that if a row is inserted and then later
    ++** deleted while a session object is active, neither the insert nor the delete
    ++** will be present in the changeset. Or if a row is deleted and then later a 
    ++** row with the same primary key values inserted while a session object is
    ++** active, the resulting changeset will contain an UPDATE change instead of
    ++** a DELETE and an INSERT.
    ++**
    ++** When a session object is disabled (see the [sqlite3session_enable()] API),
    ++** it does not accumulate records when rows are inserted, updated or deleted.
    ++** This may appear to have some counter-intuitive effects if a single row
    ++** is written to more than once during a session. For example, if a row
    ++** is inserted while a session object is enabled, then later deleted while 
    ++** the same session object is disabled, no INSERT record will appear in the
    ++** changeset, even though the delete took place while the session was disabled.
    ++** Or, if one field of a row is updated while a session is disabled, and 
    ++** another field of the same row is updated while the session is enabled, the
    ++** resulting changeset will contain an UPDATE change that updates both fields.
    ++*/
    ++SQLITE_API int sqlite3session_changeset(
    ++  sqlite3_session *pSession,      /* Session object */
    ++  int *pnChangeset,               /* OUT: Size of buffer at *ppChangeset */
    ++  void **ppChangeset              /* OUT: Buffer containing changeset */
    ++);
    ++
    ++/*
    ++** CAPI3REF: Load The Difference Between Tables Into A Session 
    ++**
    ++** If it is not already attached to the session object passed as the first
    ++** argument, this function attaches table zTbl in the same manner as the
    ++** [sqlite3session_attach()] function. If zTbl does not exist, or if it
    ++** does not have a primary key, this function is a no-op (but does not return
    ++** an error).
    ++**
    ++** Argument zFromDb must be the name of a database ("main", "temp" etc.)
    ++** attached to the same database handle as the session object that contains 
    ++** a table compatible with the table attached to the session by this function.
    ++** A table is considered compatible if it:
    ++**
    ++** <ul>
    ++**   <li> Has the same name,
    ++**   <li> Has the same set of columns declared in the same order, and
    ++**   <li> Has the same PRIMARY KEY definition.
    ++** </ul>
    ++**
    ++** If the tables are not compatible, SQLITE_SCHEMA is returned. If the tables
    ++** are compatible but do not have any PRIMARY KEY columns, it is not an error
    ++** but no changes are added to the session object. As with other session
    ++** APIs, tables without PRIMARY KEYs are simply ignored.
    ++**
    ++** This function adds a set of changes to the session object that could be
    ++** used to update the table in database zFrom (call this the "from-table") 
    ++** so that its content is the same as the table attached to the session 
    ++** object (call this the "to-table"). Specifically:
    ++**
    ++** <ul>
    ++**   <li> For each row (primary key) that exists in the to-table but not in 
    ++**     the from-table, an INSERT record is added to the session object.
    ++**
    ++**   <li> For each row (primary key) that exists in the to-table but not in 
    ++**     the from-table, a DELETE record is added to the session object.
    ++**
    ++**   <li> For each row (primary key) that exists in both tables, but features 
    ++**     different non-PK values in each, an UPDATE record is added to the
    ++**     session.  
    ++** </ul>
    ++**
    ++** To clarify, if this function is called and then a changeset constructed
    ++** using [sqlite3session_changeset()], then after applying that changeset to 
    ++** database zFrom the contents of the two compatible tables would be 
    ++** identical.
    ++**
    ++** It an error if database zFrom does not exist or does not contain the
    ++** required compatible table.
    ++**
    ++** If the operation successful, SQLITE_OK is returned. Otherwise, an SQLite
    ++** error code. In this case, if argument pzErrMsg is not NULL, *pzErrMsg
    ++** may be set to point to a buffer containing an English language error 
    ++** message. It is the responsibility of the caller to free this buffer using
    ++** sqlite3_free().
    ++*/
    ++SQLITE_API int sqlite3session_diff(
    ++  sqlite3_session *pSession,
    ++  const char *zFromDb,
    ++  const char *zTbl,
    ++  char **pzErrMsg
    ++);
    ++
    ++
    ++/*
    ++** CAPI3REF: Generate A Patchset From A Session Object
    ++**
    ++** The differences between a patchset and a changeset are that:
    ++**
    ++** <ul>
    ++**   <li> DELETE records consist of the primary key fields only. The 
    ++**        original values of other fields are omitted.
    ++**   <li> The original values of any modified fields are omitted from 
    ++**        UPDATE records.
    ++** </ul>
    ++**
    ++** A patchset blob may be used with up to date versions of all 
    ++** sqlite3changeset_xxx API functions except for sqlite3changeset_invert(), 
    ++** which returns SQLITE_CORRUPT if it is passed a patchset. Similarly,
    ++** attempting to use a patchset blob with old versions of the
    ++** sqlite3changeset_xxx APIs also provokes an SQLITE_CORRUPT error. 
    ++**
    ++** Because the non-primary key "old.*" fields are omitted, no 
    ++** SQLITE_CHANGESET_DATA conflicts can be detected or reported if a patchset
    ++** is passed to the sqlite3changeset_apply() API. Other conflict types work
    ++** in the same way as for changesets.
    ++**
    ++** Changes within a patchset are ordered in the same way as for changesets
    ++** generated by the sqlite3session_changeset() function (i.e. all changes for
    ++** a single table are grouped together, tables appear in the order in which
    ++** they were attached to the session object).
    ++*/
    ++SQLITE_API int sqlite3session_patchset(
    ++  sqlite3_session *pSession,      /* Session object */
    ++  int *pnPatchset,                /* OUT: Size of buffer at *ppPatchset */
    ++  void **ppPatchset               /* OUT: Buffer containing patchset */
    ++);
    ++
    ++/*
    ++** CAPI3REF: Test if a changeset has recorded any changes.
    ++**
    ++** Return non-zero if no changes to attached tables have been recorded by 
    ++** the session object passed as the first argument. Otherwise, if one or 
    ++** more changes have been recorded, return zero.
    ++**
    ++** Even if this function returns zero, it is possible that calling
    ++** [sqlite3session_changeset()] on the session handle may still return a
    ++** changeset that contains no changes. This can happen when a row in 
    ++** an attached table is modified and then later on the original values 
    ++** are restored. However, if this function returns non-zero, then it is
    ++** guaranteed that a call to sqlite3session_changeset() will return a 
    ++** changeset containing zero changes.
    ++*/
    ++SQLITE_API int sqlite3session_isempty(sqlite3_session *pSession);
    ++
    ++/*
    ++** CAPI3REF: Create An Iterator To Traverse A Changeset 
    ++**
    ++** Create an iterator used to iterate through the contents of a changeset.
    ++** If successful, *pp is set to point to the iterator handle and SQLITE_OK
    ++** is returned. Otherwise, if an error occurs, *pp is set to zero and an
    ++** SQLite error code is returned.
    ++**
    ++** The following functions can be used to advance and query a changeset 
    ++** iterator created by this function:
    ++**
    ++** <ul>
    ++**   <li> [sqlite3changeset_next()]
    ++**   <li> [sqlite3changeset_op()]
    ++**   <li> [sqlite3changeset_new()]
    ++**   <li> [sqlite3changeset_old()]
    ++** </ul>
    ++**
    ++** It is the responsibility of the caller to eventually destroy the iterator
    ++** by passing it to [sqlite3changeset_finalize()]. The buffer containing the
    ++** changeset (pChangeset) must remain valid until after the iterator is
    ++** destroyed.
    ++**
    ++** Assuming the changeset blob was created by one of the
    ++** [sqlite3session_changeset()], [sqlite3changeset_concat()] or
    ++** [sqlite3changeset_invert()] functions, all changes within the changeset 
    ++** that apply to a single table are grouped together. This means that when 
    ++** an application iterates through a changeset using an iterator created by 
    ++** this function, all changes that relate to a single table are visited 
    ++** consecutively. There is no chance that the iterator will visit a change 
    ++** the applies to table X, then one for table Y, and then later on visit 
    ++** another change for table X.
    ++*/
    ++SQLITE_API int sqlite3changeset_start(
    ++  sqlite3_changeset_iter **pp,    /* OUT: New changeset iterator handle */
    ++  int nChangeset,                 /* Size of changeset blob in bytes */
    ++  void *pChangeset                /* Pointer to blob containing changeset */
    ++);
    ++
    ++
    ++/*
    ++** CAPI3REF: Advance A Changeset Iterator
    ++**
    ++** This function may only be used with iterators created by function
    ++** [sqlite3changeset_start()]. If it is called on an iterator passed to
    ++** a conflict-handler callback by [sqlite3changeset_apply()], SQLITE_MISUSE
    ++** is returned and the call has no effect.
    ++**
    ++** Immediately after an iterator is created by sqlite3changeset_start(), it
    ++** does not point to any change in the changeset. Assuming the changeset
    ++** is not empty, the first call to this function advances the iterator to
    ++** point to the first change in the changeset. Each subsequent call advances
    ++** the iterator to point to the next change in the changeset (if any). If
    ++** no error occurs and the iterator points to a valid change after a call
    ++** to sqlite3changeset_next() has advanced it, SQLITE_ROW is returned. 
    ++** Otherwise, if all changes in the changeset have already been visited,
    ++** SQLITE_DONE is returned.
    ++**
    ++** If an error occurs, an SQLite error code is returned. Possible error 
    ++** codes include SQLITE_CORRUPT (if the changeset buffer is corrupt) or 
    ++** SQLITE_NOMEM.
    ++*/
    ++SQLITE_API int sqlite3changeset_next(sqlite3_changeset_iter *pIter);
    ++
    ++/*
    ++** CAPI3REF: Obtain The Current Operation From A Changeset Iterator
    ++**
    ++** The pIter argument passed to this function may either be an iterator
    ++** passed to a conflict-handler by [sqlite3changeset_apply()], or an iterator
    ++** created by [sqlite3changeset_start()]. In the latter case, the most recent
    ++** call to [sqlite3changeset_next()] must have returned [SQLITE_ROW]. If this
    ++** is not the case, this function returns [SQLITE_MISUSE].
    ++**
    ++** If argument pzTab is not NULL, then *pzTab is set to point to a
    ++** nul-terminated utf-8 encoded string containing the name of the table
    ++** affected by the current change. The buffer remains valid until either
    ++** sqlite3changeset_next() is called on the iterator or until the 
    ++** conflict-handler function returns. If pnCol is not NULL, then *pnCol is 
    ++** set to the number of columns in the table affected by the change. If
    ++** pbIncorrect is not NULL, then *pbIndirect is set to true (1) if the change
    ++** is an indirect change, or false (0) otherwise. See the documentation for
    ++** [sqlite3session_indirect()] for a description of direct and indirect
    ++** changes. Finally, if pOp is not NULL, then *pOp is set to one of 
    ++** [SQLITE_INSERT], [SQLITE_DELETE] or [SQLITE_UPDATE], depending on the 
    ++** type of change that the iterator currently points to.
    ++**
    ++** If no error occurs, SQLITE_OK is returned. If an error does occur, an
    ++** SQLite error code is returned. The values of the output variables may not
    ++** be trusted in this case.
    ++*/
    ++SQLITE_API int sqlite3changeset_op(
    ++  sqlite3_changeset_iter *pIter,  /* Iterator object */
    ++  const char **pzTab,             /* OUT: Pointer to table name */
    ++  int *pnCol,                     /* OUT: Number of columns in table */
    ++  int *pOp,                       /* OUT: SQLITE_INSERT, DELETE or UPDATE */
    ++  int *pbIndirect                 /* OUT: True for an 'indirect' change */
    ++);
    ++
    ++/*
    ++** CAPI3REF: Obtain The Primary Key Definition Of A Table
    ++**
    ++** For each modified table, a changeset includes the following:
    ++**
    ++** <ul>
    ++**   <li> The number of columns in the table, and
    ++**   <li> Which of those columns make up the tables PRIMARY KEY.
    ++** </ul>
    ++**
    ++** This function is used to find which columns comprise the PRIMARY KEY of
    ++** the table modified by the change that iterator pIter currently points to.
    ++** If successful, *pabPK is set to point to an array of nCol entries, where
    ++** nCol is the number of columns in the table. Elements of *pabPK are set to
    ++** 0x01 if the corresponding column is part of the tables primary key, or
    ++** 0x00 if it is not.
    ++**
    ++** If argument pnCol is not NULL, then *pnCol is set to the number of columns
    ++** in the table.
    ++**
    ++** If this function is called when the iterator does not point to a valid
    ++** entry, SQLITE_MISUSE is returned and the output variables zeroed. Otherwise,
    ++** SQLITE_OK is returned and the output variables populated as described
    ++** above.
    ++*/
    ++SQLITE_API int sqlite3changeset_pk(
    ++  sqlite3_changeset_iter *pIter,  /* Iterator object */
    ++  unsigned char **pabPK,          /* OUT: Array of boolean - true for PK cols */
    ++  int *pnCol                      /* OUT: Number of entries in output array */
    ++);
    ++
    ++/*
    ++** CAPI3REF: Obtain old.* Values From A Changeset Iterator
    ++**
    ++** The pIter argument passed to this function may either be an iterator
    ++** passed to a conflict-handler by [sqlite3changeset_apply()], or an iterator
    ++** created by [sqlite3changeset_start()]. In the latter case, the most recent
    ++** call to [sqlite3changeset_next()] must have returned SQLITE_ROW. 
    ++** Furthermore, it may only be called if the type of change that the iterator
    ++** currently points to is either [SQLITE_DELETE] or [SQLITE_UPDATE]. Otherwise,
    ++** this function returns [SQLITE_MISUSE] and sets *ppValue to NULL.
    ++**
    ++** Argument iVal must be greater than or equal to 0, and less than the number
    ++** of columns in the table affected by the current change. Otherwise,
    ++** [SQLITE_RANGE] is returned and *ppValue is set to NULL.
    ++**
    ++** If successful, this function sets *ppValue to point to a protected
    ++** sqlite3_value object containing the iVal'th value from the vector of 
    ++** original row values stored as part of the UPDATE or DELETE change and
    ++** returns SQLITE_OK. The name of the function comes from the fact that this 
    ++** is similar to the "old.*" columns available to update or delete triggers.
    ++**
    ++** If some other error occurs (e.g. an OOM condition), an SQLite error code
    ++** is returned and *ppValue is set to NULL.
    ++*/
    ++SQLITE_API int sqlite3changeset_old(
    ++  sqlite3_changeset_iter *pIter,  /* Changeset iterator */
    ++  int iVal,                       /* Column number */
    ++  sqlite3_value **ppValue         /* OUT: Old value (or NULL pointer) */
    ++);
    ++
    ++/*
    ++** CAPI3REF: Obtain new.* Values From A Changeset Iterator
    ++**
    ++** The pIter argument passed to this function may either be an iterator
    ++** passed to a conflict-handler by [sqlite3changeset_apply()], or an iterator
    ++** created by [sqlite3changeset_start()]. In the latter case, the most recent
    ++** call to [sqlite3changeset_next()] must have returned SQLITE_ROW. 
    ++** Furthermore, it may only be called if the type of change that the iterator
    ++** currently points to is either [SQLITE_UPDATE] or [SQLITE_INSERT]. Otherwise,
    ++** this function returns [SQLITE_MISUSE] and sets *ppValue to NULL.
    ++**
    ++** Argument iVal must be greater than or equal to 0, and less than the number
    ++** of columns in the table affected by the current change. Otherwise,
    ++** [SQLITE_RANGE] is returned and *ppValue is set to NULL.
    ++**
    ++** If successful, this function sets *ppValue to point to a protected
    ++** sqlite3_value object containing the iVal'th value from the vector of 
    ++** new row values stored as part of the UPDATE or INSERT change and
    ++** returns SQLITE_OK. If the change is an UPDATE and does not include
    ++** a new value for the requested column, *ppValue is set to NULL and 
    ++** SQLITE_OK returned. The name of the function comes from the fact that 
    ++** this is similar to the "new.*" columns available to update or delete 
    ++** triggers.
    ++**
    ++** If some other error occurs (e.g. an OOM condition), an SQLite error code
    ++** is returned and *ppValue is set to NULL.
    ++*/
    ++SQLITE_API int sqlite3changeset_new(
    ++  sqlite3_changeset_iter *pIter,  /* Changeset iterator */
    ++  int iVal,                       /* Column number */
    ++  sqlite3_value **ppValue         /* OUT: New value (or NULL pointer) */
    ++);
    ++
    ++/*
    ++** CAPI3REF: Obtain Conflicting Row Values From A Changeset Iterator
    ++**
    ++** This function should only be used with iterator objects passed to a
    ++** conflict-handler callback by [sqlite3changeset_apply()] with either
    ++** [SQLITE_CHANGESET_DATA] or [SQLITE_CHANGESET_CONFLICT]. If this function
    ++** is called on any other iterator, [SQLITE_MISUSE] is returned and *ppValue
    ++** is set to NULL.
    ++**
    ++** Argument iVal must be greater than or equal to 0, and less than the number
    ++** of columns in the table affected by the current change. Otherwise,
    ++** [SQLITE_RANGE] is returned and *ppValue is set to NULL.
    ++**
    ++** If successful, this function sets *ppValue to point to a protected
    ++** sqlite3_value object containing the iVal'th value from the 
    ++** "conflicting row" associated with the current conflict-handler callback
    ++** and returns SQLITE_OK.
    ++**
    ++** If some other error occurs (e.g. an OOM condition), an SQLite error code
    ++** is returned and *ppValue is set to NULL.
    ++*/
    ++SQLITE_API int sqlite3changeset_conflict(
    ++  sqlite3_changeset_iter *pIter,  /* Changeset iterator */
    ++  int iVal,                       /* Column number */
    ++  sqlite3_value **ppValue         /* OUT: Value from conflicting row */
    ++);
    ++
    ++/*
    ++** CAPI3REF: Determine The Number Of Foreign Key Constraint Violations
    ++**
    ++** This function may only be called with an iterator passed to an
    ++** SQLITE_CHANGESET_FOREIGN_KEY conflict handler callback. In this case
    ++** it sets the output variable to the total number of known foreign key
    ++** violations in the destination database and returns SQLITE_OK.
    ++**
    ++** In all other cases this function returns SQLITE_MISUSE.
    ++*/
    ++SQLITE_API int sqlite3changeset_fk_conflicts(
    ++  sqlite3_changeset_iter *pIter,  /* Changeset iterator */
    ++  int *pnOut                      /* OUT: Number of FK violations */
    ++);
    ++
    ++
    ++/*
    ++** CAPI3REF: Finalize A Changeset Iterator
    ++**
    ++** This function is used to finalize an iterator allocated with
    ++** [sqlite3changeset_start()].
    ++**
    ++** This function should only be called on iterators created using the
    ++** [sqlite3changeset_start()] function. If an application calls this
    ++** function with an iterator passed to a conflict-handler by
    ++** [sqlite3changeset_apply()], [SQLITE_MISUSE] is immediately returned and the
    ++** call has no effect.
    ++**
    ++** If an error was encountered within a call to an sqlite3changeset_xxx()
    ++** function (for example an [SQLITE_CORRUPT] in [sqlite3changeset_next()] or an 
    ++** [SQLITE_NOMEM] in [sqlite3changeset_new()]) then an error code corresponding
    ++** to that error is returned by this function. Otherwise, SQLITE_OK is
    ++** returned. This is to allow the following pattern (pseudo-code):
    ++**
    ++**   sqlite3changeset_start();
    ++**   while( SQLITE_ROW==sqlite3changeset_next() ){
    ++**     // Do something with change.
    ++**   }
    ++**   rc = sqlite3changeset_finalize();
    ++**   if( rc!=SQLITE_OK ){
    ++**     // An error has occurred 
    ++**   }
    ++*/
    ++SQLITE_API int sqlite3changeset_finalize(sqlite3_changeset_iter *pIter);
    ++
    ++/*
    ++** CAPI3REF: Invert A Changeset
    ++**
    ++** This function is used to "invert" a changeset object. Applying an inverted
    ++** changeset to a database reverses the effects of applying the uninverted
    ++** changeset. Specifically:
    ++**
    ++** <ul>
    ++**   <li> Each DELETE change is changed to an INSERT, and
    ++**   <li> Each INSERT change is changed to a DELETE, and
    ++**   <li> For each UPDATE change, the old.* and new.* values are exchanged.
    ++** </ul>
    ++**
    ++** This function does not change the order in which changes appear within
    ++** the changeset. It merely reverses the sense of each individual change.
    ++**
    ++** If successful, a pointer to a buffer containing the inverted changeset
    ++** is stored in *ppOut, the size of the same buffer is stored in *pnOut, and
    ++** SQLITE_OK is returned. If an error occurs, both *pnOut and *ppOut are
    ++** zeroed and an SQLite error code returned.
    ++**
    ++** It is the responsibility of the caller to eventually call sqlite3_free()
    ++** on the *ppOut pointer to free the buffer allocation following a successful 
    ++** call to this function.
    ++**
    ++** WARNING/TODO: This function currently assumes that the input is a valid
    ++** changeset. If it is not, the results are undefined.
    ++*/
    ++SQLITE_API int sqlite3changeset_invert(
    ++  int nIn, const void *pIn,       /* Input changeset */
    ++  int *pnOut, void **ppOut        /* OUT: Inverse of input */
    ++);
    ++
    ++/*
    ++** CAPI3REF: Concatenate Two Changeset Objects
    ++**
    ++** This function is used to concatenate two changesets, A and B, into a 
    ++** single changeset. The result is a changeset equivalent to applying
    ++** changeset A followed by changeset B. 
    ++**
    ++** This function combines the two input changesets using an 
    ++** sqlite3_changegroup object. Calling it produces similar results as the
    ++** following code fragment:
    ++**
    ++**   sqlite3_changegroup *pGrp;
    ++**   rc = sqlite3_changegroup_new(&pGrp);
    ++**   if( rc==SQLITE_OK ) rc = sqlite3changegroup_add(pGrp, nA, pA);
    ++**   if( rc==SQLITE_OK ) rc = sqlite3changegroup_add(pGrp, nB, pB);
    ++**   if( rc==SQLITE_OK ){
    ++**     rc = sqlite3changegroup_output(pGrp, pnOut, ppOut);
    ++**   }else{
    ++**     *ppOut = 0;
    ++**     *pnOut = 0;
    ++**   }
    ++**
    ++** Refer to the sqlite3_changegroup documentation below for details.
    ++*/
    ++SQLITE_API int sqlite3changeset_concat(
    ++  int nA,                         /* Number of bytes in buffer pA */
    ++  void *pA,                       /* Pointer to buffer containing changeset A */
    ++  int nB,                         /* Number of bytes in buffer pB */
    ++  void *pB,                       /* Pointer to buffer containing changeset B */
    ++  int *pnOut,                     /* OUT: Number of bytes in output changeset */
    ++  void **ppOut                    /* OUT: Buffer containing output changeset */
    ++);
    ++
    ++
    ++/*
    ++** CAPI3REF: Changegroup Handle
    ++*/
    ++typedef struct sqlite3_changegroup sqlite3_changegroup;
    ++
    ++/*
    ++** CAPI3REF: Create A New Changegroup Object
    ++**
    ++** An sqlite3_changegroup object is used to combine two or more changesets
    ++** (or patchsets) into a single changeset (or patchset). A single changegroup
    ++** object may combine changesets or patchsets, but not both. The output is
    ++** always in the same format as the input.
    ++**
    ++** If successful, this function returns SQLITE_OK and populates (*pp) with
    ++** a pointer to a new sqlite3_changegroup object before returning. The caller
    ++** should eventually free the returned object using a call to 
    ++** sqlite3changegroup_delete(). If an error occurs, an SQLite error code
    ++** (i.e. SQLITE_NOMEM) is returned and *pp is set to NULL.
    ++**
    ++** The usual usage pattern for an sqlite3_changegroup object is as follows:
    ++**
    ++** <ul>
    ++**   <li> It is created using a call to sqlite3changegroup_new().
    ++**
    ++**   <li> Zero or more changesets (or patchsets) are added to the object
    ++**        by calling sqlite3changegroup_add().
    ++**
    ++**   <li> The result of combining all input changesets together is obtained 
    ++**        by the application via a call to sqlite3changegroup_output().
    ++**
    ++**   <li> The object is deleted using a call to sqlite3changegroup_delete().
    ++** </ul>
    ++**
    ++** Any number of calls to add() and output() may be made between the calls to
    ++** new() and delete(), and in any order.
    ++**
    ++** As well as the regular sqlite3changegroup_add() and 
    ++** sqlite3changegroup_output() functions, also available are the streaming
    ++** versions sqlite3changegroup_add_strm() and sqlite3changegroup_output_strm().
    ++*/
    ++SQLITE_API int sqlite3changegroup_new(sqlite3_changegroup **pp);
    ++
    ++/*
    ++** CAPI3REF: Add A Changeset To A Changegroup
    ++**
    ++** Add all changes within the changeset (or patchset) in buffer pData (size
    ++** nData bytes) to the changegroup. 
    ++**
    ++** If the buffer contains a patchset, then all prior calls to this function
    ++** on the same changegroup object must also have specified patchsets. Or, if
    ++** the buffer contains a changeset, so must have the earlier calls to this
    ++** function. Otherwise, SQLITE_ERROR is returned and no changes are added
    ++** to the changegroup.
    ++**
    ++** Rows within the changeset and changegroup are identified by the values in
    ++** their PRIMARY KEY columns. A change in the changeset is considered to
    ++** apply to the same row as a change already present in the changegroup if
    ++** the two rows have the same primary key.
    ++**
    ++** Changes to rows that do not already appear in the changegroup are
    ++** simply copied into it. Or, if both the new changeset and the changegroup
    ++** contain changes that apply to a single row, the final contents of the
    ++** changegroup depends on the type of each change, as follows:
    ++**
    ++** <table border=1 style="margin-left:8ex;margin-right:8ex">
    ++**   <tr><th style="white-space:pre">Existing Change  </th>
    ++**       <th style="white-space:pre">New Change       </th>
    ++**       <th>Output Change
    ++**   <tr><td>INSERT <td>INSERT <td>
    ++**       The new change is ignored. This case does not occur if the new
    ++**       changeset was recorded immediately after the changesets already
    ++**       added to the changegroup.
    ++**   <tr><td>INSERT <td>UPDATE <td>
    ++**       The INSERT change remains in the changegroup. The values in the 
    ++**       INSERT change are modified as if the row was inserted by the
    ++**       existing change and then updated according to the new change.
    ++**   <tr><td>INSERT <td>DELETE <td>
    ++**       The existing INSERT is removed from the changegroup. The DELETE is
    ++**       not added.
    ++**   <tr><td>UPDATE <td>INSERT <td>
    ++**       The new change is ignored. This case does not occur if the new
    ++**       changeset was recorded immediately after the changesets already
    ++**       added to the changegroup.
    ++**   <tr><td>UPDATE <td>UPDATE <td>
    ++**       The existing UPDATE remains within the changegroup. It is amended 
    ++**       so that the accompanying values are as if the row was updated once 
    ++**       by the existing change and then again by the new change.
    ++**   <tr><td>UPDATE <td>DELETE <td>
    ++**       The existing UPDATE is replaced by the new DELETE within the
    ++**       changegroup.
    ++**   <tr><td>DELETE <td>INSERT <td>
    ++**       If one or more of the column values in the row inserted by the
    ++**       new change differ from those in the row deleted by the existing 
    ++**       change, the existing DELETE is replaced by an UPDATE within the
    ++**       changegroup. Otherwise, if the inserted row is exactly the same 
    ++**       as the deleted row, the existing DELETE is simply discarded.
    ++**   <tr><td>DELETE <td>UPDATE <td>
    ++**       The new change is ignored. This case does not occur if the new
    ++**       changeset was recorded immediately after the changesets already
    ++**       added to the changegroup.
    ++**   <tr><td>DELETE <td>DELETE <td>
    ++**       The new change is ignored. This case does not occur if the new
    ++**       changeset was recorded immediately after the changesets already
    ++**       added to the changegroup.
    ++** </table>
    ++**
    ++** If the new changeset contains changes to a table that is already present
    ++** in the changegroup, then the number of columns and the position of the
    ++** primary key columns for the table must be consistent. If this is not the
    ++** case, this function fails with SQLITE_SCHEMA. If the input changeset
    ++** appears to be corrupt and the corruption is detected, SQLITE_CORRUPT is
    ++** returned. Or, if an out-of-memory condition occurs during processing, this
    ++** function returns SQLITE_NOMEM. In all cases, if an error occurs the
    ++** final contents of the changegroup is undefined.
    ++**
    ++** If no error occurs, SQLITE_OK is returned.
    ++*/
    ++SQLITE_API int sqlite3changegroup_add(sqlite3_changegroup*, int nData, void *pData);
    ++
    ++/*
    ++** CAPI3REF: Obtain A Composite Changeset From A Changegroup
    ++**
    ++** Obtain a buffer containing a changeset (or patchset) representing the
    ++** current contents of the changegroup. If the inputs to the changegroup
    ++** were themselves changesets, the output is a changeset. Or, if the
    ++** inputs were patchsets, the output is also a patchset.
    ++**
    ++** As with the output of the sqlite3session_changeset() and
    ++** sqlite3session_patchset() functions, all changes related to a single
    ++** table are grouped together in the output of this function. Tables appear
    ++** in the same order as for the very first changeset added to the changegroup.
    ++** If the second or subsequent changesets added to the changegroup contain
    ++** changes for tables that do not appear in the first changeset, they are
    ++** appended onto the end of the output changeset, again in the order in
    ++** which they are first encountered.
    ++**
    ++** If an error occurs, an SQLite error code is returned and the output
    ++** variables (*pnData) and (*ppData) are set to 0. Otherwise, SQLITE_OK
    ++** is returned and the output variables are set to the size of and a 
    ++** pointer to the output buffer, respectively. In this case it is the
    ++** responsibility of the caller to eventually free the buffer using a
    ++** call to sqlite3_free().
    ++*/
    ++SQLITE_API int sqlite3changegroup_output(
    ++  sqlite3_changegroup*,
    ++  int *pnData,                    /* OUT: Size of output buffer in bytes */
    ++  void **ppData                   /* OUT: Pointer to output buffer */
    ++);
    ++
    ++/*
    ++** CAPI3REF: Delete A Changegroup Object
    ++*/
    ++SQLITE_API void sqlite3changegroup_delete(sqlite3_changegroup*);
    ++
    ++/*
    ++** CAPI3REF: Apply A Changeset To A Database
    ++**
    ++** Apply a changeset to a database. This function attempts to update the
    ++** "main" database attached to handle db with the changes found in the
    ++** changeset passed via the second and third arguments.
    ++**
    ++** The fourth argument (xFilter) passed to this function is the "filter
    ++** callback". If it is not NULL, then for each table affected by at least one
    ++** change in the changeset, the filter callback is invoked with
    ++** the table name as the second argument, and a copy of the context pointer
    ++** passed as the sixth argument to this function as the first. If the "filter
    ++** callback" returns zero, then no attempt is made to apply any changes to 
    ++** the table. Otherwise, if the return value is non-zero or the xFilter
    ++** argument to this function is NULL, all changes related to the table are
    ++** attempted.
    ++**
    ++** For each table that is not excluded by the filter callback, this function 
    ++** tests that the target database contains a compatible table. A table is 
    ++** considered compatible if all of the following are true:
    ++**
    ++** <ul>
    ++**   <li> The table has the same name as the name recorded in the 
    ++**        changeset, and
    ++**   <li> The table has at least as many columns as recorded in the 
    ++**        changeset, and
    ++**   <li> The table has primary key columns in the same position as 
    ++**        recorded in the changeset.
    ++** </ul>
    ++**
    ++** If there is no compatible table, it is not an error, but none of the
    ++** changes associated with the table are applied. A warning message is issued
    ++** via the sqlite3_log() mechanism with the error code SQLITE_SCHEMA. At most
    ++** one such warning is issued for each table in the changeset.
    ++**
    ++** For each change for which there is a compatible table, an attempt is made 
    ++** to modify the table contents according to the UPDATE, INSERT or DELETE 
    ++** change. If a change cannot be applied cleanly, the conflict handler 
    ++** function passed as the fifth argument to sqlite3changeset_apply() may be 
    ++** invoked. A description of exactly when the conflict handler is invoked for 
    ++** each type of change is below.
    ++**
    ++** Unlike the xFilter argument, xConflict may not be passed NULL. The results
    ++** of passing anything other than a valid function pointer as the xConflict
    ++** argument are undefined.
    ++**
    ++** Each time the conflict handler function is invoked, it must return one
    ++** of [SQLITE_CHANGESET_OMIT], [SQLITE_CHANGESET_ABORT] or 
    ++** [SQLITE_CHANGESET_REPLACE]. SQLITE_CHANGESET_REPLACE may only be returned
    ++** if the second argument passed to the conflict handler is either
    ++** SQLITE_CHANGESET_DATA or SQLITE_CHANGESET_CONFLICT. If the conflict-handler
    ++** returns an illegal value, any changes already made are rolled back and
    ++** the call to sqlite3changeset_apply() returns SQLITE_MISUSE. Different 
    ++** actions are taken by sqlite3changeset_apply() depending on the value
    ++** returned by each invocation of the conflict-handler function. Refer to
    ++** the documentation for the three 
    ++** [SQLITE_CHANGESET_OMIT|available return values] for details.
    ++**
    ++** <dl>
    ++** <dt>DELETE Changes<dd>
    ++**   For each DELETE change, this function checks if the target database 
    ++**   contains a row with the same primary key value (or values) as the 
    ++**   original row values stored in the changeset. If it does, and the values 
    ++**   stored in all non-primary key columns also match the values stored in 
    ++**   the changeset the row is deleted from the target database.
    ++**
    ++**   If a row with matching primary key values is found, but one or more of
    ++**   the non-primary key fields contains a value different from the original
    ++**   row value stored in the changeset, the conflict-handler function is
    ++**   invoked with [SQLITE_CHANGESET_DATA] as the second argument. If the
    ++**   database table has more columns than are recorded in the changeset,
    ++**   only the values of those non-primary key fields are compared against
    ++**   the current database contents - any trailing database table columns
    ++**   are ignored.
    ++**
    ++**   If no row with matching primary key values is found in the database,
    ++**   the conflict-handler function is invoked with [SQLITE_CHANGESET_NOTFOUND]
    ++**   passed as the second argument.
    ++**
    ++**   If the DELETE operation is attempted, but SQLite returns SQLITE_CONSTRAINT
    ++**   (which can only happen if a foreign key constraint is violated), the
    ++**   conflict-handler function is invoked with [SQLITE_CHANGESET_CONSTRAINT]
    ++**   passed as the second argument. This includes the case where the DELETE
    ++**   operation is attempted because an earlier call to the conflict handler
    ++**   function returned [SQLITE_CHANGESET_REPLACE].
    ++**
    ++** <dt>INSERT Changes<dd>
    ++**   For each INSERT change, an attempt is made to insert the new row into
    ++**   the database. If the changeset row contains fewer fields than the
    ++**   database table, the trailing fields are populated with their default
    ++**   values.
    ++**
    ++**   If the attempt to insert the row fails because the database already 
    ++**   contains a row with the same primary key values, the conflict handler
    ++**   function is invoked with the second argument set to 
    ++**   [SQLITE_CHANGESET_CONFLICT].
    ++**
    ++**   If the attempt to insert the row fails because of some other constraint
    ++**   violation (e.g. NOT NULL or UNIQUE), the conflict handler function is 
    ++**   invoked with the second argument set to [SQLITE_CHANGESET_CONSTRAINT].
    ++**   This includes the case where the INSERT operation is re-attempted because 
    ++**   an earlier call to the conflict handler function returned 
    ++**   [SQLITE_CHANGESET_REPLACE].
    ++**
    ++** <dt>UPDATE Changes<dd>
    ++**   For each UPDATE change, this function checks if the target database 
    ++**   contains a row with the same primary key value (or values) as the 
    ++**   original row values stored in the changeset. If it does, and the values 
    ++**   stored in all modified non-primary key columns also match the values
    ++**   stored in the changeset the row is updated within the target database.
    ++**
    ++**   If a row with matching primary key values is found, but one or more of
    ++**   the modified non-primary key fields contains a value different from an
    ++**   original row value stored in the changeset, the conflict-handler function
    ++**   is invoked with [SQLITE_CHANGESET_DATA] as the second argument. Since
    ++**   UPDATE changes only contain values for non-primary key fields that are
    ++**   to be modified, only those fields need to match the original values to
    ++**   avoid the SQLITE_CHANGESET_DATA conflict-handler callback.
    ++**
    ++**   If no row with matching primary key values is found in the database,
    ++**   the conflict-handler function is invoked with [SQLITE_CHANGESET_NOTFOUND]
    ++**   passed as the second argument.
    ++**
    ++**   If the UPDATE operation is attempted, but SQLite returns 
    ++**   SQLITE_CONSTRAINT, the conflict-handler function is invoked with 
    ++**   [SQLITE_CHANGESET_CONSTRAINT] passed as the second argument.
    ++**   This includes the case where the UPDATE operation is attempted after 
    ++**   an earlier call to the conflict handler function returned
    ++**   [SQLITE_CHANGESET_REPLACE].  
    ++** </dl>
    ++**
    ++** It is safe to execute SQL statements, including those that write to the
    ++** table that the callback related to, from within the xConflict callback.
    ++** This can be used to further customize the applications conflict
    ++** resolution strategy.
    ++**
    ++** All changes made by this function are enclosed in a savepoint transaction.
    ++** If any other error (aside from a constraint failure when attempting to
    ++** write to the target database) occurs, then the savepoint transaction is
    ++** rolled back, restoring the target database to its original state, and an 
    ++** SQLite error code returned.
    ++*/
    ++SQLITE_API int sqlite3changeset_apply(
    ++  sqlite3 *db,                    /* Apply change to "main" db of this handle */
    ++  int nChangeset,                 /* Size of changeset in bytes */
    ++  void *pChangeset,               /* Changeset blob */
    ++  int(*xFilter)(
    ++    void *pCtx,                   /* Copy of sixth arg to _apply() */
    ++    const char *zTab              /* Table name */
    ++  ),
    ++  int(*xConflict)(
    ++    void *pCtx,                   /* Copy of sixth arg to _apply() */
    ++    int eConflict,                /* DATA, MISSING, CONFLICT, CONSTRAINT */
    ++    sqlite3_changeset_iter *p     /* Handle describing change and conflict */
    ++  ),
    ++  void *pCtx                      /* First argument passed to xConflict */
    ++);
    ++
    ++/* 
    ++** CAPI3REF: Constants Passed To The Conflict Handler
    ++**
    ++** Values that may be passed as the second argument to a conflict-handler.
    ++**
    ++** <dl>
    ++** <dt>SQLITE_CHANGESET_DATA<dd>
    ++**   The conflict handler is invoked with CHANGESET_DATA as the second argument
    ++**   when processing a DELETE or UPDATE change if a row with the required
    ++**   PRIMARY KEY fields is present in the database, but one or more other 
    ++**   (non primary-key) fields modified by the update do not contain the 
    ++**   expected "before" values.
    ++** 
    ++**   The conflicting row, in this case, is the database row with the matching
    ++**   primary key.
    ++** 
    ++** <dt>SQLITE_CHANGESET_NOTFOUND<dd>
    ++**   The conflict handler is invoked with CHANGESET_NOTFOUND as the second
    ++**   argument when processing a DELETE or UPDATE change if a row with the
    ++**   required PRIMARY KEY fields is not present in the database.
    ++** 
    ++**   There is no conflicting row in this case. The results of invoking the
    ++**   sqlite3changeset_conflict() API are undefined.
    ++** 
    ++** <dt>SQLITE_CHANGESET_CONFLICT<dd>
    ++**   CHANGESET_CONFLICT is passed as the second argument to the conflict
    ++**   handler while processing an INSERT change if the operation would result 
    ++**   in duplicate primary key values.
    ++** 
    ++**   The conflicting row in this case is the database row with the matching
    ++**   primary key.
    ++**
    ++** <dt>SQLITE_CHANGESET_FOREIGN_KEY<dd>
    ++**   If foreign key handling is enabled, and applying a changeset leaves the
    ++**   database in a state containing foreign key violations, the conflict 
    ++**   handler is invoked with CHANGESET_FOREIGN_KEY as the second argument
    ++**   exactly once before the changeset is committed. If the conflict handler
    ++**   returns CHANGESET_OMIT, the changes, including those that caused the
    ++**   foreign key constraint violation, are committed. Or, if it returns
    ++**   CHANGESET_ABORT, the changeset is rolled back.
    ++**
    ++**   No current or conflicting row information is provided. The only function
    ++**   it is possible to call on the supplied sqlite3_changeset_iter handle
    ++**   is sqlite3changeset_fk_conflicts().
    ++** 
    ++** <dt>SQLITE_CHANGESET_CONSTRAINT<dd>
    ++**   If any other constraint violation occurs while applying a change (i.e. 
    ++**   a UNIQUE, CHECK or NOT NULL constraint), the conflict handler is 
    ++**   invoked with CHANGESET_CONSTRAINT as the second argument.
    ++** 
    ++**   There is no conflicting row in this case. The results of invoking the
    ++**   sqlite3changeset_conflict() API are undefined.
    ++**
    ++** </dl>
    ++*/
    ++#define SQLITE_CHANGESET_DATA        1
    ++#define SQLITE_CHANGESET_NOTFOUND    2
    ++#define SQLITE_CHANGESET_CONFLICT    3
    ++#define SQLITE_CHANGESET_CONSTRAINT  4
    ++#define SQLITE_CHANGESET_FOREIGN_KEY 5
    ++
    ++/* 
    ++** CAPI3REF: Constants Returned By The Conflict Handler
    ++**
    ++** A conflict handler callback must return one of the following three values.
    ++**
    ++** <dl>
    ++** <dt>SQLITE_CHANGESET_OMIT<dd>
    ++**   If a conflict handler returns this value no special action is taken. The
    ++**   change that caused the conflict is not applied. The session module 
    ++**   continues to the next change in the changeset.
    ++**
    ++** <dt>SQLITE_CHANGESET_REPLACE<dd>
    ++**   This value may only be returned if the second argument to the conflict
    ++**   handler was SQLITE_CHANGESET_DATA or SQLITE_CHANGESET_CONFLICT. If this
    ++**   is not the case, any changes applied so far are rolled back and the 
    ++**   call to sqlite3changeset_apply() returns SQLITE_MISUSE.
    ++**
    ++**   If CHANGESET_REPLACE is returned by an SQLITE_CHANGESET_DATA conflict
    ++**   handler, then the conflicting row is either updated or deleted, depending
    ++**   on the type of change.
    ++**
    ++**   If CHANGESET_REPLACE is returned by an SQLITE_CHANGESET_CONFLICT conflict
    ++**   handler, then the conflicting row is removed from the database and a
    ++**   second attempt to apply the change is made. If this second attempt fails,
    ++**   the original row is restored to the database before continuing.
    ++**
    ++** <dt>SQLITE_CHANGESET_ABORT<dd>
    ++**   If this value is returned, any changes applied so far are rolled back 
    ++**   and the call to sqlite3changeset_apply() returns SQLITE_ABORT.
    ++** </dl>
    ++*/
    ++#define SQLITE_CHANGESET_OMIT       0
    ++#define SQLITE_CHANGESET_REPLACE    1
    ++#define SQLITE_CHANGESET_ABORT      2
    ++
    ++/*
    ++** CAPI3REF: Streaming Versions of API functions.
    ++**
    ++** The six streaming API xxx_strm() functions serve similar purposes to the 
    ++** corresponding non-streaming API functions:
    ++**
    ++** <table border=1 style="margin-left:8ex;margin-right:8ex">
    ++**   <tr><th>Streaming function<th>Non-streaming equivalent</th>
    ++**   <tr><td>sqlite3changeset_apply_strm<td>[sqlite3changeset_apply] 
    ++**   <tr><td>sqlite3changeset_concat_strm<td>[sqlite3changeset_concat] 
    ++**   <tr><td>sqlite3changeset_invert_strm<td>[sqlite3changeset_invert] 
    ++**   <tr><td>sqlite3changeset_start_strm<td>[sqlite3changeset_start] 
    ++**   <tr><td>sqlite3session_changeset_strm<td>[sqlite3session_changeset] 
    ++**   <tr><td>sqlite3session_patchset_strm<td>[sqlite3session_patchset] 
    ++** </table>
    ++**
    ++** Non-streaming functions that accept changesets (or patchsets) as input
    ++** require that the entire changeset be stored in a single buffer in memory. 
    ++** Similarly, those that return a changeset or patchset do so by returning 
    ++** a pointer to a single large buffer allocated using sqlite3_malloc(). 
    ++** Normally this is convenient. However, if an application running in a 
    ++** low-memory environment is required to handle very large changesets, the
    ++** large contiguous memory allocations required can become onerous.
    ++**
    ++** In order to avoid this problem, instead of a single large buffer, input
    ++** is passed to a streaming API functions by way of a callback function that
    ++** the sessions module invokes to incrementally request input data as it is
    ++** required. In all cases, a pair of API function parameters such as
    ++**
    ++**  <pre>
    ++**  &nbsp;     int nChangeset,
    ++**  &nbsp;     void *pChangeset,
    ++**  </pre>
    ++**
    ++** Is replaced by:
    ++**
    ++**  <pre>
    ++**  &nbsp;     int (*xInput)(void *pIn, void *pData, int *pnData),
    ++**  &nbsp;     void *pIn,
    ++**  </pre>
    ++**
    ++** Each time the xInput callback is invoked by the sessions module, the first
    ++** argument passed is a copy of the supplied pIn context pointer. The second 
    ++** argument, pData, points to a buffer (*pnData) bytes in size. Assuming no 
    ++** error occurs the xInput method should copy up to (*pnData) bytes of data 
    ++** into the buffer and set (*pnData) to the actual number of bytes copied 
    ++** before returning SQLITE_OK. If the input is completely exhausted, (*pnData) 
    ++** should be set to zero to indicate this. Or, if an error occurs, an SQLite 
    ++** error code should be returned. In all cases, if an xInput callback returns
    ++** an error, all processing is abandoned and the streaming API function
    ++** returns a copy of the error code to the caller.
    ++**
    ++** In the case of sqlite3changeset_start_strm(), the xInput callback may be
    ++** invoked by the sessions module at any point during the lifetime of the
    ++** iterator. If such an xInput callback returns an error, the iterator enters
    ++** an error state, whereby all subsequent calls to iterator functions 
    ++** immediately fail with the same error code as returned by xInput.
    ++**
    ++** Similarly, streaming API functions that return changesets (or patchsets)
    ++** return them in chunks by way of a callback function instead of via a
    ++** pointer to a single large buffer. In this case, a pair of parameters such
    ++** as:
    ++**
    ++**  <pre>
    ++**  &nbsp;     int *pnChangeset,
    ++**  &nbsp;     void **ppChangeset,
    ++**  </pre>
    ++**
    ++** Is replaced by:
    ++**
    ++**  <pre>
    ++**  &nbsp;     int (*xOutput)(void *pOut, const void *pData, int nData),
    ++**  &nbsp;     void *pOut
    ++**  </pre>
    ++**
    ++** The xOutput callback is invoked zero or more times to return data to
    ++** the application. The first parameter passed to each call is a copy of the
    ++** pOut pointer supplied by the application. The second parameter, pData,
    ++** points to a buffer nData bytes in size containing the chunk of output
    ++** data being returned. If the xOutput callback successfully processes the
    ++** supplied data, it should return SQLITE_OK to indicate success. Otherwise,
    ++** it should return some other SQLite error code. In this case processing
    ++** is immediately abandoned and the streaming API function returns a copy
    ++** of the xOutput error code to the application.
    ++**
    ++** The sessions module never invokes an xOutput callback with the third 
    ++** parameter set to a value less than or equal to zero. Other than this,
    ++** no guarantees are made as to the size of the chunks of data returned.
    ++*/
    ++SQLITE_API int sqlite3changeset_apply_strm(
    ++  sqlite3 *db,                    /* Apply change to "main" db of this handle */
    ++  int (*xInput)(void *pIn, void *pData, int *pnData), /* Input function */
    ++  void *pIn,                                          /* First arg for xInput */
    ++  int(*xFilter)(
    ++    void *pCtx,                   /* Copy of sixth arg to _apply() */
    ++    const char *zTab              /* Table name */
    ++  ),
    ++  int(*xConflict)(
    ++    void *pCtx,                   /* Copy of sixth arg to _apply() */
    ++    int eConflict,                /* DATA, MISSING, CONFLICT, CONSTRAINT */
    ++    sqlite3_changeset_iter *p     /* Handle describing change and conflict */
    ++  ),
    ++  void *pCtx                      /* First argument passed to xConflict */
    ++);
    ++SQLITE_API int sqlite3changeset_concat_strm(
    ++  int (*xInputA)(void *pIn, void *pData, int *pnData),
    ++  void *pInA,
    ++  int (*xInputB)(void *pIn, void *pData, int *pnData),
    ++  void *pInB,
    ++  int (*xOutput)(void *pOut, const void *pData, int nData),
    ++  void *pOut
    ++);
    ++SQLITE_API int sqlite3changeset_invert_strm(
    ++  int (*xInput)(void *pIn, void *pData, int *pnData),
    ++  void *pIn,
    ++  int (*xOutput)(void *pOut, const void *pData, int nData),
    ++  void *pOut
    ++);
    ++SQLITE_API int sqlite3changeset_start_strm(
    ++  sqlite3_changeset_iter **pp,
    ++  int (*xInput)(void *pIn, void *pData, int *pnData),
    ++  void *pIn
    ++);
    ++SQLITE_API int sqlite3session_changeset_strm(
    ++  sqlite3_session *pSession,
    ++  int (*xOutput)(void *pOut, const void *pData, int nData),
    ++  void *pOut
    ++);
    ++SQLITE_API int sqlite3session_patchset_strm(
    ++  sqlite3_session *pSession,
    ++  int (*xOutput)(void *pOut, const void *pData, int nData),
    ++  void *pOut
    ++);
    ++SQLITE_API int sqlite3changegroup_add_strm(sqlite3_changegroup*, 
    ++    int (*xInput)(void *pIn, void *pData, int *pnData),
    ++    void *pIn
    ++);
    ++SQLITE_API int sqlite3changegroup_output_strm(sqlite3_changegroup*,
    ++    int (*xOutput)(void *pOut, const void *pData, int nData), 
    ++    void *pOut
    ++);
    ++
    ++
    ++/*
    ++** Make sure we can call this stuff from C++.
    ++*/
    ++#if 0
    ++}
    ++#endif
    ++
    ++#endif  /* !defined(__SQLITESESSION_H_) && defined(SQLITE_ENABLE_SESSION) */
    ++
    ++/******** End of sqlite3session.h *********/
    ++/******** Begin file fts5.h *********/
    + /*
    + ** 2014 May 31
    + **
    +@@ -8220,6 +11354,9 @@ struct Fts5PhraseIter {
    + **   an OOM condition or IO error), an appropriate SQLite error code is 
    + **   returned.
    + **
    ++**   This function may be quite inefficient if used with an FTS5 table
    ++**   created with the "columnsize=0" option.
    ++**
    + ** xColumnText:
    + **   This function attempts to retrieve the text of column iCol of the
    + **   current document. If successful, (*pz) is set to point to a buffer
    +@@ -8240,15 +11377,29 @@ struct Fts5PhraseIter {
    + **   the query within the current row. Return SQLITE_OK if successful, or
    + **   an error code (i.e. SQLITE_NOMEM) if an error occurs.
    + **
    ++**   This API can be quite slow if used with an FTS5 table created with the
    ++**   "detail=none" or "detail=column" option. If the FTS5 table is created 
    ++**   with either "detail=none" or "detail=column" and "content=" option 
    ++**   (i.e. if it is a contentless table), then this API always returns 0.
    ++**
    + ** xInst:
    + **   Query for the details of phrase match iIdx within the current row.
    + **   Phrase matches are numbered starting from zero, so the iIdx argument
    + **   should be greater than or equal to zero and smaller than the value
    + **   output by xInstCount().
    + **
    ++**   Usually, output parameter *piPhrase is set to the phrase number, *piCol
    ++**   to the column in which it occurs and *piOff the token offset of the
    ++**   first token of the phrase. The exception is if the table was created
    ++**   with the offsets=0 option specified. In this case *piOff is always
    ++**   set to -1.
    ++**
    + **   Returns SQLITE_OK if successful, or an error code (i.e. SQLITE_NOMEM) 
    + **   if an error occurs.
    + **
    ++**   This API can be quite slow if used with an FTS5 table created with the
    ++**   "detail=none" or "detail=column" option. 
    ++**
    + ** xRowid:
    + **   Returns the rowid of the current row.
    + **
    +@@ -8262,11 +11413,13 @@ struct Fts5PhraseIter {
    + **       ... FROM ftstable WHERE ftstable MATCH $p ORDER BY rowid
    + **
    + **   with $p set to a phrase equivalent to the phrase iPhrase of the
    +-**   current query is executed. For each row visited, the callback function
    +-**   passed as the fourth argument is invoked. The context and API objects 
    +-**   passed to the callback function may be used to access the properties of
    +-**   each matched row. Invoking Api.xUserData() returns a copy of the pointer
    +-**   passed as the third argument to pUserData.
    ++**   current query is executed. Any column filter that applies to
    ++**   phrase iPhrase of the current query is included in $p. For each 
    ++**   row visited, the callback function passed as the fourth argument 
    ++**   is invoked. The context and API objects passed to the callback 
    ++**   function may be used to access the properties of each matched row.
    ++**   Invoking Api.xUserData() returns a copy of the pointer passed as 
    ++**   the third argument to pUserData.
    + **
    + **   If the callback function returns any value other than SQLITE_OK, the
    + **   query is abandoned and the xQueryPhrase function returns immediately.
    +@@ -8332,7 +11485,7 @@ struct Fts5PhraseIter {
    + **       Fts5PhraseIter iter;
    + **       int iCol, iOff;
    + **       for(pApi->xPhraseFirst(pFts, iPhrase, &iter, &iCol, &iOff);
    +-**           iOff>=0;
    ++**           iCol>=0;
    + **           pApi->xPhraseNext(pFts, &iter, &iCol, &iOff)
    + **       ){
    + **         // An instance of phrase iPhrase at offset iOff of column iCol
    +@@ -8340,13 +11493,51 @@ struct Fts5PhraseIter {
    + **
    + **   The Fts5PhraseIter structure is defined above. Applications should not
    + **   modify this structure directly - it should only be used as shown above
    +-**   with the xPhraseFirst() and xPhraseNext() API methods.
    ++**   with the xPhraseFirst() and xPhraseNext() API methods (and by
    ++**   xPhraseFirstColumn() and xPhraseNextColumn() as illustrated below).
    ++**
    ++**   This API can be quite slow if used with an FTS5 table created with the
    ++**   "detail=none" or "detail=column" option. If the FTS5 table is created 
    ++**   with either "detail=none" or "detail=column" and "content=" option 
    ++**   (i.e. if it is a contentless table), then this API always iterates
    ++**   through an empty set (all calls to xPhraseFirst() set iCol to -1).
    + **
    + ** xPhraseNext()
    + **   See xPhraseFirst above.
    ++**
    ++** xPhraseFirstColumn()
    ++**   This function and xPhraseNextColumn() are similar to the xPhraseFirst()
    ++**   and xPhraseNext() APIs described above. The difference is that instead
    ++**   of iterating through all instances of a phrase in the current row, these
    ++**   APIs are used to iterate through the set of columns in the current row
    ++**   that contain one or more instances of a specified phrase. For example:
    ++**
    ++**       Fts5PhraseIter iter;
    ++**       int iCol;
    ++**       for(pApi->xPhraseFirstColumn(pFts, iPhrase, &iter, &iCol);
    ++**           iCol>=0;
    ++**           pApi->xPhraseNextColumn(pFts, &iter, &iCol)
    ++**       ){
    ++**         // Column iCol contains at least one instance of phrase iPhrase
    ++**       }
    ++**
    ++**   This API can be quite slow if used with an FTS5 table created with the
    ++**   "detail=none" option. If the FTS5 table is created with either 
    ++**   "detail=none" "content=" option (i.e. if it is a contentless table), 
    ++**   then this API always iterates through an empty set (all calls to 
    ++**   xPhraseFirstColumn() set iCol to -1).
    ++**
    ++**   The information accessed using this API and its companion
    ++**   xPhraseFirstColumn() may also be obtained using xPhraseFirst/xPhraseNext
    ++**   (or xInst/xInstCount). The chief advantage of this API is that it is
    ++**   significantly more efficient than those alternatives when used with
    ++**   "detail=column" tables.  
    ++**
    ++** xPhraseNextColumn()
    ++**   See xPhraseFirstColumn above.
    + */
    + struct Fts5ExtensionApi {
    +-  int iVersion;                   /* Currently always set to 1 */
    ++  int iVersion;                   /* Currently always set to 3 */
    + 
    +   void *(*xUserData)(Fts5Context*);
    + 
    +@@ -8376,8 +11567,11 @@ struct Fts5ExtensionApi {
    +   int (*xSetAuxdata)(Fts5Context*, void *pAux, void(*xDelete)(void*));
    +   void *(*xGetAuxdata)(Fts5Context*, int bClear);
    + 
    +-  void (*xPhraseFirst)(Fts5Context*, int iPhrase, Fts5PhraseIter*, int*, int*);
    ++  int (*xPhraseFirst)(Fts5Context*, int iPhrase, Fts5PhraseIter*, int*, int*);
    +   void (*xPhraseNext)(Fts5Context*, Fts5PhraseIter*, int *piCol, int *piOff);
    ++
    ++  int (*xPhraseFirstColumn)(Fts5Context*, int iPhrase, Fts5PhraseIter*, int*);
    ++  void (*xPhraseNextColumn)(Fts5Context*, Fts5PhraseIter*, int *piCol);
    + };
    + 
    + /* 
    +@@ -8394,7 +11588,7 @@ struct Fts5ExtensionApi {
    + ** behaviour. The structure methods are expected to function as follows:
    + **
    + ** xCreate:
    +-**   This function is used to allocate and inititalize a tokenizer instance.
    ++**   This function is used to allocate and initialize a tokenizer instance.
    + **   A tokenizer instance is required to actually tokenize text.
    + **
    + **   The first argument passed to this function is a copy of the (void*)
    +@@ -8654,7 +11848,7 @@ struct fts5_api {
    + 
    + #endif /* _FTS5_H */
    + 
    +-
    ++/******** End of fts5.h *********/
    + 
    + /************** End of sqlite3.h *********************************************/
    + /************** Continuing where we left off in sqliteInt.h ******************/
    +@@ -8663,8 +11857,9 @@ struct fts5_api {
    + ** Include the configuration header output by 'configure' if we're using the
    + ** autoconf-based build
    + */
    +-#ifdef _HAVE_SQLITE_CONFIG_H
    +-#include "config.h"
    ++#if defined(_HAVE_SQLITE_CONFIG_H) && !defined(SQLITECONFIG_H)
    ++/* #include "config.h" */
    ++#define SQLITECONFIG_H 1
    + #endif
    + 
    + /************** Include sqliteLimit.h in the middle of sqliteInt.h ***********/
    +@@ -8758,7 +11953,7 @@ struct fts5_api {
    + ** Not currently enforced.
    + */
    + #ifndef SQLITE_MAX_VDBE_OP
    +-# define SQLITE_MAX_VDBE_OP 25000
    ++# define SQLITE_MAX_VDBE_OP 250000000
    + #endif
    + 
    + /*
    +@@ -8772,13 +11967,13 @@ struct fts5_api {
    + ** The suggested maximum number of in-memory pages to use for
    + ** the main database table and for temporary tables.
    + **
    +-** IMPLEMENTATION-OF: R-31093-59126 The default suggested cache size
    +-** is 2000 pages.
    ++** IMPLEMENTATION-OF: R-30185-15359 The default suggested cache size is -2000,
    ++** which means the cache size is limited to 2048000 bytes of memory.
    + ** IMPLEMENTATION-OF: R-48205-43578 The default suggested cache size can be
    + ** altered using the SQLITE_DEFAULT_CACHE_SIZE compile-time options.
    + */
    + #ifndef SQLITE_DEFAULT_CACHE_SIZE
    +-# define SQLITE_DEFAULT_CACHE_SIZE  2000
    ++# define SQLITE_DEFAULT_CACHE_SIZE  -2000
    + #endif
    + 
    + /*
    +@@ -8791,8 +11986,9 @@ struct fts5_api {
    + 
    + /*
    + ** The maximum number of attached databases.  This must be between 0
    +-** and 62.  The upper bound on 62 is because a 64-bit integer bitmap
    +-** is used internally to track attached databases.
    ++** and 125.  The upper bound of 125 is because the attached databases are
    ++** counted using a signed 8-bit integer which has a maximum value of 127
    ++** and we have to allow 2 extra counts for the "main" and "temp" databases.
    + */
    + #ifndef SQLITE_MAX_ATTACHED
    + # define SQLITE_MAX_ATTACHED 10
    +@@ -8827,7 +12023,7 @@ struct fts5_api {
    + ** The default size of a database page.
    + */
    + #ifndef SQLITE_DEFAULT_PAGE_SIZE
    +-# define SQLITE_DEFAULT_PAGE_SIZE 1024
    ++# define SQLITE_DEFAULT_PAGE_SIZE 4096
    + #endif
    + #if SQLITE_DEFAULT_PAGE_SIZE>SQLITE_MAX_PAGE_SIZE
    + # undef SQLITE_DEFAULT_PAGE_SIZE
    +@@ -8908,7 +12104,7 @@ struct fts5_api {
    + ** to the next, so we have developed the following set of #if statements
    + ** to generate appropriate macros for a wide range of compilers.
    + **
    +-** The correct "ANSI" way to do this is to use the intptr_t type. 
    ++** The correct "ANSI" way to do this is to use the intptr_t type.
    + ** Unfortunately, that typedef is not available on all compilers, or
    + ** if it is available, it requires an #include of specific headers
    + ** that vary from one machine to the next.
    +@@ -8950,11 +12146,12 @@ struct fts5_api {
    + ** the SQLITE_DISABLE_INTRINSIC define.
    + */
    + #if !defined(SQLITE_DISABLE_INTRINSIC)
    +-#  if defined(_MSC_VER) && _MSC_VER>=1300
    ++#  if defined(_MSC_VER) && _MSC_VER>=1400
    + #    if !defined(_WIN32_WCE)
    + #      include <intrin.h>
    + #      pragma intrinsic(_byteswap_ushort)
    + #      pragma intrinsic(_byteswap_ulong)
    ++#      pragma intrinsic(_byteswap_uint64)
    + #      pragma intrinsic(_ReadWriteBarrier)
    + #    else
    + #      include <cmnintrin.h>
    +@@ -8972,6 +12169,11 @@ struct fts5_api {
    + **
    + ** Older versions of SQLite used an optional THREADSAFE macro.
    + ** We support that for legacy.
    ++**
    ++** To ensure that the correct value of "THREADSAFE" is reported when querying
    ++** for compile-time options at runtime (e.g. "PRAGMA compile_options"), this
    ++** logic is partially replicated in ctime.c. If it is updated here, it should
    ++** also be updated there.
    + */
    + #if !defined(SQLITE_THREADSAFE)
    + # if defined(THREADSAFE)
    +@@ -9060,7 +12262,7 @@ struct fts5_api {
    + ** is set.  Thus NDEBUG becomes an opt-in rather than an opt-out
    + ** feature.
    + */
    +-#if !defined(NDEBUG) && !defined(SQLITE_DEBUG) 
    ++#if !defined(NDEBUG) && !defined(SQLITE_DEBUG)
    + # define NDEBUG 1
    + #endif
    + #if defined(NDEBUG) && defined(SQLITE_DEBUG)
    +@@ -9075,7 +12277,7 @@ struct fts5_api {
    + #endif
    + 
    + /*
    +-** The testcase() macro is used to aid in coverage testing.  When 
    ++** The testcase() macro is used to aid in coverage testing.  When
    + ** doing coverage testing, the condition inside the argument to
    + ** testcase() must be evaluated both true and false in order to
    + ** get full branch coverage.  The testcase() macro is inserted
    +@@ -9121,7 +12323,7 @@ SQLITE_PRIVATE   void sqlite3Coverage(int);
    + #endif
    + 
    + /*
    +-** The ALWAYS and NEVER macros surround boolean expressions which 
    ++** The ALWAYS and NEVER macros surround boolean expressions which
    + ** are intended to always be true or false, respectively.  Such
    + ** expressions could be omitted from the code completely.  But they
    + ** are included in a few cases in order to enhance the resilience
    +@@ -9135,7 +12337,7 @@ SQLITE_PRIVATE   void sqlite3Coverage(int);
    + ** be true and false so that the unreachable code they specify will
    + ** not be counted as untested code.
    + */
    +-#if defined(SQLITE_COVERAGE_TEST)
    ++#if defined(SQLITE_COVERAGE_TEST) || defined(SQLITE_MUTATION_TEST)
    + # define ALWAYS(X)      (1)
    + # define NEVER(X)       (0)
    + #elif !defined(NDEBUG)
    +@@ -9146,6 +12348,36 @@ SQLITE_PRIVATE   void sqlite3Coverage(int);
    + # define NEVER(X)       (X)
    + #endif
    + 
    ++/*
    ++** Some conditionals are optimizations only.  In other words, if the
    ++** conditionals are replaced with a constant 1 (true) or 0 (false) then
    ++** the correct answer is still obtained, though perhaps not as quickly.
    ++**
    ++** The following macros mark these optimizations conditionals.
    ++*/
    ++#if defined(SQLITE_MUTATION_TEST)
    ++# define OK_IF_ALWAYS_TRUE(X)  (1)
    ++# define OK_IF_ALWAYS_FALSE(X) (0)
    ++#else
    ++# define OK_IF_ALWAYS_TRUE(X)  (X)
    ++# define OK_IF_ALWAYS_FALSE(X) (X)
    ++#endif
    ++
    ++/*
    ++** Some malloc failures are only possible if SQLITE_TEST_REALLOC_STRESS is
    ++** defined.  We need to defend against those failures when testing with
    ++** SQLITE_TEST_REALLOC_STRESS, but we don't want the unreachable branches
    ++** during a normal build.  The following macro can be used to disable tests
    ++** that are always false except when SQLITE_TEST_REALLOC_STRESS is set.
    ++*/
    ++#if defined(SQLITE_TEST_REALLOC_STRESS)
    ++# define ONLY_IF_REALLOC_STRESS(X)  (X)
    ++#elif !defined(NDEBUG)
    ++# define ONLY_IF_REALLOC_STRESS(X)  ((X)?(assert(0),1):0)
    ++#else
    ++# define ONLY_IF_REALLOC_STRESS(X)  (0)
    ++#endif
    ++
    + /*
    + ** Declarations used for tracing the operating system interfaces.
    + */
    +@@ -9172,6 +12404,13 @@ SQLITE_PRIVATE   void sqlite3Coverage(int);
    + # undef  SQLITE_NEED_ERR_NAME
    + #endif
    + 
    ++/*
    ++** SQLITE_ENABLE_EXPLAIN_COMMENTS is incompatible with SQLITE_OMIT_EXPLAIN
    ++*/
    ++#ifdef SQLITE_OMIT_EXPLAIN
    ++# undef SQLITE_ENABLE_EXPLAIN_COMMENTS
    ++#endif
    ++
    + /*
    + ** Return true (non-zero) if the input is an integer that is too large
    + ** to fit in 32-bits.  This macro is used inside of various testcase()
    +@@ -9205,8 +12444,8 @@ SQLITE_PRIVATE   void sqlite3Coverage(int);
    + ** This is the header file for the generic hash-table implementation
    + ** used in SQLite.
    + */
    +-#ifndef _SQLITE_HASH_H_
    +-#define _SQLITE_HASH_H_
    ++#ifndef SQLITE_HASH_H
    ++#define SQLITE_HASH_H
    + 
    + /* Forward declarations of structures. */
    + typedef struct Hash Hash;
    +@@ -9286,7 +12525,7 @@ SQLITE_PRIVATE void sqlite3HashClear(Hash*);
    + */
    + /* #define sqliteHashCount(H)  ((H)->count) // NOT USED */
    + 
    +-#endif /* _SQLITE_HASH_H_ */
    ++#endif /* SQLITE_HASH_H */
    + 
    + /************** End of hash.h ************************************************/
    + /************** Continuing where we left off in sqliteInt.h ******************/
    +@@ -9318,76 +12557,76 @@ SQLITE_PRIVATE void sqlite3HashClear(Hash*);
    + #define TK_AS                              24
    + #define TK_WITHOUT                         25
    + #define TK_COMMA                           26
    +-#define TK_ID                              27
    +-#define TK_INDEXED                         28
    +-#define TK_ABORT                           29
    +-#define TK_ACTION                          30
    +-#define TK_AFTER                           31
    +-#define TK_ANALYZE                         32
    +-#define TK_ASC                             33
    +-#define TK_ATTACH                          34
    +-#define TK_BEFORE                          35
    +-#define TK_BY                              36
    +-#define TK_CASCADE                         37
    +-#define TK_CAST                            38
    +-#define TK_COLUMNKW                        39
    +-#define TK_CONFLICT                        40
    +-#define TK_DATABASE                        41
    +-#define TK_DESC                            42
    +-#define TK_DETACH                          43
    +-#define TK_EACH                            44
    +-#define TK_FAIL                            45
    +-#define TK_FOR                             46
    +-#define TK_IGNORE                          47
    +-#define TK_INITIALLY                       48
    +-#define TK_INSTEAD                         49
    +-#define TK_LIKE_KW                         50
    +-#define TK_MATCH                           51
    +-#define TK_NO                              52
    +-#define TK_KEY                             53
    +-#define TK_OF                              54
    +-#define TK_OFFSET                          55
    +-#define TK_PRAGMA                          56
    +-#define TK_RAISE                           57
    +-#define TK_RECURSIVE                       58
    +-#define TK_REPLACE                         59
    +-#define TK_RESTRICT                        60
    +-#define TK_ROW                             61
    +-#define TK_TRIGGER                         62
    +-#define TK_VACUUM                          63
    +-#define TK_VIEW                            64
    +-#define TK_VIRTUAL                         65
    +-#define TK_WITH                            66
    +-#define TK_REINDEX                         67
    +-#define TK_RENAME                          68
    +-#define TK_CTIME_KW                        69
    +-#define TK_ANY                             70
    +-#define TK_OR                              71
    +-#define TK_AND                             72
    +-#define TK_IS                              73
    +-#define TK_BETWEEN                         74
    +-#define TK_IN                              75
    +-#define TK_ISNULL                          76
    +-#define TK_NOTNULL                         77
    +-#define TK_NE                              78
    +-#define TK_EQ                              79
    +-#define TK_GT                              80
    +-#define TK_LE                              81
    +-#define TK_LT                              82
    +-#define TK_GE                              83
    +-#define TK_ESCAPE                          84
    +-#define TK_BITAND                          85
    +-#define TK_BITOR                           86
    +-#define TK_LSHIFT                          87
    +-#define TK_RSHIFT                          88
    +-#define TK_PLUS                            89
    +-#define TK_MINUS                           90
    +-#define TK_STAR                            91
    +-#define TK_SLASH                           92
    +-#define TK_REM                             93
    +-#define TK_CONCAT                          94
    +-#define TK_COLLATE                         95
    +-#define TK_BITNOT                          96
    ++#define TK_ABORT                           27
    ++#define TK_ACTION                          28
    ++#define TK_AFTER                           29
    ++#define TK_ANALYZE                         30
    ++#define TK_ASC                             31
    ++#define TK_ATTACH                          32
    ++#define TK_BEFORE                          33
    ++#define TK_BY                              34
    ++#define TK_CASCADE                         35
    ++#define TK_CAST                            36
    ++#define TK_CONFLICT                        37
    ++#define TK_DATABASE                        38
    ++#define TK_DESC                            39
    ++#define TK_DETACH                          40
    ++#define TK_EACH                            41
    ++#define TK_FAIL                            42
    ++#define TK_OR                              43
    ++#define TK_AND                             44
    ++#define TK_IS                              45
    ++#define TK_MATCH                           46
    ++#define TK_LIKE_KW                         47
    ++#define TK_BETWEEN                         48
    ++#define TK_IN                              49
    ++#define TK_ISNULL                          50
    ++#define TK_NOTNULL                         51
    ++#define TK_NE                              52
    ++#define TK_EQ                              53
    ++#define TK_GT                              54
    ++#define TK_LE                              55
    ++#define TK_LT                              56
    ++#define TK_GE                              57
    ++#define TK_ESCAPE                          58
    ++#define TK_ID                              59
    ++#define TK_COLUMNKW                        60
    ++#define TK_FOR                             61
    ++#define TK_IGNORE                          62
    ++#define TK_INITIALLY                       63
    ++#define TK_INSTEAD                         64
    ++#define TK_NO                              65
    ++#define TK_KEY                             66
    ++#define TK_OF                              67
    ++#define TK_OFFSET                          68
    ++#define TK_PRAGMA                          69
    ++#define TK_RAISE                           70
    ++#define TK_RECURSIVE                       71
    ++#define TK_REPLACE                         72
    ++#define TK_RESTRICT                        73
    ++#define TK_ROW                             74
    ++#define TK_TRIGGER                         75
    ++#define TK_VACUUM                          76
    ++#define TK_VIEW                            77
    ++#define TK_VIRTUAL                         78
    ++#define TK_WITH                            79
    ++#define TK_REINDEX                         80
    ++#define TK_RENAME                          81
    ++#define TK_CTIME_KW                        82
    ++#define TK_ANY                             83
    ++#define TK_BITAND                          84
    ++#define TK_BITOR                           85
    ++#define TK_LSHIFT                          86
    ++#define TK_RSHIFT                          87
    ++#define TK_PLUS                            88
    ++#define TK_MINUS                           89
    ++#define TK_STAR                            90
    ++#define TK_SLASH                           91
    ++#define TK_REM                             92
    ++#define TK_CONCAT                          93
    ++#define TK_COLLATE                         94
    ++#define TK_BITNOT                          95
    ++#define TK_INDEXED                         96
    + #define TK_STRING                          97
    + #define TK_JOIN_KW                         98
    + #define TK_CONSTRAINT                      99
    +@@ -9423,9 +12662,9 @@ SQLITE_PRIVATE void sqlite3HashClear(Hash*);
    + #define TK_LIMIT                          129
    + #define TK_WHERE                          130
    + #define TK_INTO                           131
    +-#define TK_INTEGER                        132
    +-#define TK_FLOAT                          133
    +-#define TK_BLOB                           134
    ++#define TK_FLOAT                          132
    ++#define TK_BLOB                           133
    ++#define TK_INTEGER                        134
    + #define TK_VARIABLE                       135
    + #define TK_CASE                           136
    + #define TK_WHEN                           137
    +@@ -9434,23 +12673,30 @@ SQLITE_PRIVATE void sqlite3HashClear(Hash*);
    + #define TK_INDEX                          140
    + #define TK_ALTER                          141
    + #define TK_ADD                            142
    +-#define TK_TO_TEXT                        143
    +-#define TK_TO_BLOB                        144
    +-#define TK_TO_NUMERIC                     145
    +-#define TK_TO_INT                         146
    +-#define TK_TO_REAL                        147
    +-#define TK_ISNOT                          148
    +-#define TK_END_OF_FILE                    149
    +-#define TK_ILLEGAL                        150
    +-#define TK_SPACE                          151
    +-#define TK_UNCLOSED_STRING                152
    +-#define TK_FUNCTION                       153
    +-#define TK_COLUMN                         154
    +-#define TK_AGG_FUNCTION                   155
    +-#define TK_AGG_COLUMN                     156
    +-#define TK_UMINUS                         157
    +-#define TK_UPLUS                          158
    +-#define TK_REGISTER                       159
    ++#define TK_ISNOT                          143
    ++#define TK_FUNCTION                       144
    ++#define TK_COLUMN                         145
    ++#define TK_AGG_FUNCTION                   146
    ++#define TK_AGG_COLUMN                     147
    ++#define TK_UMINUS                         148
    ++#define TK_UPLUS                          149
    ++#define TK_REGISTER                       150
    ++#define TK_VECTOR                         151
    ++#define TK_SELECT_COLUMN                  152
    ++#define TK_IF_NULL_ROW                    153
    ++#define TK_ASTERISK                       154
    ++#define TK_SPAN                           155
    ++#define TK_END_OF_FILE                    156
    ++#define TK_UNCLOSED_STRING                157
    ++#define TK_SPACE                          158
    ++#define TK_ILLEGAL                        159
    ++
    ++/* The token codes above must all fit in 8 bits */
    ++#define TKFLG_MASK           0xff  
    ++
    ++/* Flags that can be added to a token code when it is not
    ++** being stored in a u8: */
    ++#define TKFLG_DONTFOLD       0x100  /* Omit constant folding optimizations */
    + 
    + /************** End of parse.h ***********************************************/
    + /************** Continuing where we left off in sqliteInt.h ******************/
    +@@ -9460,6 +12706,18 @@ SQLITE_PRIVATE void sqlite3HashClear(Hash*);
    + #include <assert.h>
    + #include <stddef.h>
    + 
    ++/*
    ++** Use a macro to replace memcpy() if compiled with SQLITE_INLINE_MEMCPY.
    ++** This allows better measurements of where memcpy() is used when running
    ++** cachegrind.  But this macro version of memcpy() is very slow so it
    ++** should not be used in production.  This is a performance measurement
    ++** hack only.
    ++*/
    ++#ifdef SQLITE_INLINE_MEMCPY
    ++# define memcpy(D,S,N) {char*xxd=(char*)(D);const char*xxs=(const char*)(S);\
    ++                        int xxn=(N);while(xxn-->0)*(xxd++)=*(xxs++);}
    ++#endif
    ++
    + /*
    + ** If compiling for a processor that lacks floating point support,
    + ** substitute integer for floating-point
    +@@ -9482,7 +12740,7 @@ SQLITE_PRIVATE void sqlite3HashClear(Hash*);
    + 
    + /*
    + ** OMIT_TEMPDB is set to 1 if SQLITE_OMIT_TEMPDB is defined, or 0
    +-** afterward. Having this macro allows us to cause the C compiler 
    ++** afterward. Having this macro allows us to cause the C compiler
    + ** to omit code used by TEMP tables without messy #ifndef statements.
    + */
    + #ifdef SQLITE_OMIT_TEMPDB
    +@@ -9516,12 +12774,11 @@ SQLITE_PRIVATE void sqlite3HashClear(Hash*);
    + */
    + #ifndef SQLITE_TEMP_STORE
    + # define SQLITE_TEMP_STORE 1
    +-# define SQLITE_TEMP_STORE_xc 1  /* Exclude from ctime.c */
    + #endif
    + 
    + /*
    + ** If no value has been provided for SQLITE_MAX_WORKER_THREADS, or if
    +-** SQLITE_TEMP_STORE is set to 3 (never use temporary files), set it 
    ++** SQLITE_TEMP_STORE is set to 3 (never use temporary files), set it
    + ** to zero.
    + */
    + #if SQLITE_TEMP_STORE==3 || SQLITE_THREADSAFE==0
    +@@ -9544,11 +12801,22 @@ SQLITE_PRIVATE void sqlite3HashClear(Hash*);
    + ** pagecaches for each database connection.  A positive number is the
    + ** number of pages.  A negative number N translations means that a buffer
    + ** of -1024*N bytes is allocated and used for as many pages as it will hold.
    ++**
    ++** The default value of "20" was choosen to minimize the run-time of the
    ++** speedtest1 test program with options: --shrink-memory --reprepare
    + */
    + #ifndef SQLITE_DEFAULT_PCACHE_INITSZ
    +-# define SQLITE_DEFAULT_PCACHE_INITSZ 100
    ++# define SQLITE_DEFAULT_PCACHE_INITSZ 20
    + #endif
    + 
    ++/*
    ++** The compile-time options SQLITE_MMAP_READWRITE and 
    ++** SQLITE_ENABLE_BATCH_ATOMIC_WRITE are not compatible with one another.
    ++** You must choose one or the other (or neither) but not both.
    ++*/
    ++#if defined(SQLITE_MMAP_READWRITE) && defined(SQLITE_ENABLE_BATCH_ATOMIC_WRITE)
    ++#error Cannot use both SQLITE_MMAP_READWRITE and SQLITE_ENABLE_BATCH_ATOMIC_WRITE
    ++#endif
    + 
    + /*
    + ** GCC does not define the offsetof() macro so we'll have to do it
    +@@ -9561,8 +12829,12 @@ SQLITE_PRIVATE void sqlite3HashClear(Hash*);
    + /*
    + ** Macros to compute minimum and maximum of two numbers.
    + */
    +-#define MIN(A,B) ((A)<(B)?(A):(B))
    +-#define MAX(A,B) ((A)>(B)?(A):(B))
    ++#ifndef MIN
    ++# define MIN(A,B) ((A)<(B)?(A):(B))
    ++#endif
    ++#ifndef MAX
    ++# define MAX(A,B) ((A)>(B)?(A):(B))
    ++#endif
    + 
    + /*
    + ** Swap two objects of type TYPE.
    +@@ -9670,7 +12942,7 @@ typedef INT8_TYPE i8;              /* 1-byte signed integer */
    + **      4 -> 20           1000 -> 99        1048576 -> 200
    + **     10 -> 33           1024 -> 100    4294967296 -> 320
    + **
    +-** The LogEst can be negative to indicate fractional values. 
    ++** The LogEst can be negative to indicate fractional values.
    + ** Examples:
    + **
    + **    0.5 -> -10           0.1 -> -33        0.0625 -> -40
    +@@ -9691,38 +12963,62 @@ typedef INT16_TYPE LogEst;
    + # endif
    + #endif
    + 
    ++/* The uptr type is an unsigned integer large enough to hold a pointer
    ++*/
    ++#if defined(HAVE_STDINT_H)
    ++  typedef uintptr_t uptr;
    ++#elif SQLITE_PTRSIZE==4
    ++  typedef u32 uptr;
    ++#else
    ++  typedef u64 uptr;
    ++#endif
    ++
    ++/*
    ++** The SQLITE_WITHIN(P,S,E) macro checks to see if pointer P points to
    ++** something between S (inclusive) and E (exclusive).
    ++**
    ++** In other words, S is a buffer and E is a pointer to the first byte after
    ++** the end of buffer S.  This macro returns true if P points to something
    ++** contained within the buffer S.
    ++*/
    ++#define SQLITE_WITHIN(P,S,E) (((uptr)(P)>=(uptr)(S))&&((uptr)(P)<(uptr)(E)))
    ++
    ++
    + /*
    + ** Macros to determine whether the machine is big or little endian,
    + ** 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
    ++** -DSQLITE_BYTEORDER=0 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) ||    \
    ++#ifndef SQLITE_BYTEORDER
    ++# 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
    ++     defined(__arm__)
    ++#   define SQLITE_BYTEORDER    1234
    ++# elif defined(sparc)    || defined(__ppc__)
    ++#   define SQLITE_BYTEORDER    4321
    ++# else
    ++#   define SQLITE_BYTEORDER 0
    ++# endif
    + #endif
    +-#if (defined(sparc)    || defined(__ppc__))  \
    +-    && !defined(SQLITE_RUNTIME_BYTEORDER)
    +-# define SQLITE_BYTEORDER    4321
    ++#if 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" */
    ++#elif SQLITE_BYTEORDER==1234
    ++# define SQLITE_BIGENDIAN    0
    ++# define SQLITE_LITTLEENDIAN 1
    ++# define SQLITE_UTF16NATIVE  SQLITE_UTF16LE
    ++#else
    ++# ifdef SQLITE_AMALGAMATION
    ++  const int sqlite3one = 1;
    ++# else
    ++  extern const int sqlite3one;
    ++# endif
    + # define SQLITE_BIGENDIAN    (*(char *)(&sqlite3one)==0)
    + # define SQLITE_LITTLEENDIAN (*(char *)(&sqlite3one)==1)
    + # define SQLITE_UTF16NATIVE  (SQLITE_BIGENDIAN?SQLITE_UTF16BE:SQLITE_UTF16LE)
    +@@ -9736,7 +13032,7 @@ SQLITE_PRIVATE const int sqlite3one;
    + #define LARGEST_INT64  (0xffffffff|(((i64)0x7fffffff)<<32))
    + #define SMALLEST_INT64 (((i64)-1) - LARGEST_INT64)
    + 
    +-/* 
    ++/*
    + ** Round up a number to the next larger multiple of 8.  This is used
    + ** to force 8-byte alignment on 64-bit architectures.
    + */
    +@@ -9775,10 +13071,6 @@ SQLITE_PRIVATE const int sqlite3one;
    + */
    + #ifdef __APPLE__
    + # include <TargetConditionals.h>
    +-# if TARGET_OS_IPHONE
    +-#   undef SQLITE_MAX_MMAP_SIZE
    +-#   define SQLITE_MAX_MMAP_SIZE 0
    +-# endif
    + #endif
    + #ifndef SQLITE_MAX_MMAP_SIZE
    + # if defined(__linux__) \
    +@@ -9791,7 +13083,6 @@ SQLITE_PRIVATE const int sqlite3one;
    + # else
    + #   define SQLITE_MAX_MMAP_SIZE 0
    + # endif
    +-# define SQLITE_MAX_MMAP_SIZE_xc 1 /* exclude from ctime.c */
    + #endif
    + 
    + /*
    +@@ -9801,7 +13092,6 @@ SQLITE_PRIVATE const int sqlite3one;
    + */
    + #ifndef SQLITE_DEFAULT_MMAP_SIZE
    + # define SQLITE_DEFAULT_MMAP_SIZE 0
    +-# define SQLITE_DEFAULT_MMAP_SIZE_xc 1  /* Exclude from ctime.c */
    + #endif
    + #if SQLITE_DEFAULT_MMAP_SIZE>SQLITE_MAX_MMAP_SIZE
    + # undef SQLITE_DEFAULT_MMAP_SIZE
    +@@ -9826,7 +13116,7 @@ SQLITE_PRIVATE const int sqlite3one;
    + ** SELECTTRACE_ENABLED will be either 1 or 0 depending on whether or not
    + ** the Select query generator tracing logic is turned on.
    + */
    +-#if defined(SQLITE_DEBUG) || defined(SQLITE_ENABLE_SELECTTRACE)
    ++#if defined(SQLITE_ENABLE_SELECTTRACE)
    + # define SELECTTRACE_ENABLED 1
    + #else
    + # define SELECTTRACE_ENABLED 0
    +@@ -9834,7 +13124,7 @@ SQLITE_PRIVATE const int sqlite3one;
    + 
    + /*
    + ** An instance of the following structure is used to store the busy-handler
    +-** callback for a given sqlite handle. 
    ++** callback for a given sqlite handle.
    + **
    + ** The sqlite.busyHandler member of the sqlite struct contains the busy
    + ** callback for the database handle. Each pager opened via the sqlite
    +@@ -9879,9 +13169,9 @@ struct BusyHandler {
    + 
    + /*
    + ** The following value as a destructor means to use sqlite3DbFree().
    +-** The sqlite3DbFree() routine requires two parameters instead of the 
    +-** one parameter that destructors normally want.  So we have to introduce 
    +-** this magic value that the code knows to handle differently.  Any 
    ++** The sqlite3DbFree() routine requires two parameters instead of the
    ++** one parameter that destructors normally want.  So we have to introduce
    ++** this magic value that the code knows to handle differently.  Any
    + ** pointer will work here as long as it is distinct from SQLITE_STATIC
    + ** and SQLITE_TRANSIENT.
    + */
    +@@ -9905,19 +13195,19 @@ struct BusyHandler {
    +   #define SQLITE_WSD const
    +   #define GLOBAL(t,v) (*(t*)sqlite3_wsd_find((void*)&(v), sizeof(v)))
    +   #define sqlite3GlobalConfig GLOBAL(struct Sqlite3Config, sqlite3Config)
    +-SQLITE_API int SQLITE_STDCALL sqlite3_wsd_init(int N, int J);
    +-SQLITE_API void *SQLITE_STDCALL sqlite3_wsd_find(void *K, int L);
    ++SQLITE_API int sqlite3_wsd_init(int N, int J);
    ++SQLITE_API void *sqlite3_wsd_find(void *K, int L);
    + #else
    +-  #define SQLITE_WSD 
    ++  #define SQLITE_WSD
    +   #define GLOBAL(t,v) v
    +   #define sqlite3GlobalConfig sqlite3Config
    + #endif
    + 
    + /*
    + ** The following macros are used to suppress compiler warnings and to
    +-** make it clear to human readers when a function parameter is deliberately 
    ++** make it clear to human readers when a function parameter is deliberately
    + ** left unused within the body of a function. This usually happens when
    +-** a function is called via a function pointer. For example the 
    ++** a function is called via a function pointer. For example the
    + ** implementation of an SQL aggregate step callback may not use the
    + ** parameter indicating the number of arguments passed to the aggregate,
    + ** if it knows that this is enforced elsewhere.
    +@@ -9945,7 +13235,6 @@ typedef struct Db Db;
    + typedef struct Schema Schema;
    + typedef struct Expr Expr;
    + typedef struct ExprList ExprList;
    +-typedef struct ExprSpan ExprSpan;
    + typedef struct FKey FKey;
    + typedef struct FuncDestructor FuncDestructor;
    + typedef struct FuncDef FuncDef;
    +@@ -9960,6 +13249,7 @@ typedef struct LookasideSlot LookasideSlot;
    + typedef struct Module Module;
    + typedef struct NameContext NameContext;
    + typedef struct Parse Parse;
    ++typedef struct PreUpdate PreUpdate;
    + typedef struct PrintfArguments PrintfArguments;
    + typedef struct RowSet RowSet;
    + typedef struct Savepoint Savepoint;
    +@@ -9982,8 +13272,16 @@ typedef struct Walker Walker;
    + typedef struct WhereInfo WhereInfo;
    + typedef struct With With;
    + 
    ++/* A VList object records a mapping between parameters/variables/wildcards
    ++** in the SQL statement (such as $abc, @pqr, or :xyz) and the integer
    ++** variable number associated with that parameter.  See the format description
    ++** on the sqlite3VListAdd() routine for more information.  A VList is really
    ++** just an array of integers.
    ++*/
    ++typedef int VList;
    ++
    + /*
    +-** Defer sourcing vdbe.h and btree.h until after the "u8" and 
    ++** Defer sourcing vdbe.h and btree.h until after the "u8" and
    + ** "BusyHandler" typedefs. vdbe.h also requires a few of the opaque
    + ** pointer types (i.e. FuncDef) defined above.
    + */
    +@@ -10004,8 +13302,8 @@ typedef struct With With;
    + ** subsystem.  See comments in the source code for a detailed description
    + ** of what each interface routine does.
    + */
    +-#ifndef _BTREE_H_
    +-#define _BTREE_H_
    ++#ifndef SQLITE_BTREE_H
    ++#define SQLITE_BTREE_H
    + 
    + /* TODO: This definition is just included so other modules compile. It
    + ** needs to be revisited.
    +@@ -10030,6 +13328,7 @@ typedef struct With With;
    + typedef struct Btree Btree;
    + typedef struct BtCursor BtCursor;
    + typedef struct BtShared BtShared;
    ++typedef struct BtreePayload BtreePayload;
    + 
    + 
    + SQLITE_PRIVATE int sqlite3BtreeOpen(
    +@@ -10054,11 +13353,11 @@ SQLITE_PRIVATE int sqlite3BtreeOpen(
    + 
    + SQLITE_PRIVATE int sqlite3BtreeClose(Btree*);
    + SQLITE_PRIVATE int sqlite3BtreeSetCacheSize(Btree*,int);
    ++SQLITE_PRIVATE int sqlite3BtreeSetSpillSize(Btree*,int);
    + #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);
    + SQLITE_PRIVATE int sqlite3BtreeGetPageSize(Btree*);
    + SQLITE_PRIVATE int sqlite3BtreeMaxPageCount(Btree*,int);
    +@@ -10080,7 +13379,9 @@ SQLITE_PRIVATE int sqlite3BtreeIsInReadTrans(Btree*);
    + SQLITE_PRIVATE int sqlite3BtreeIsInBackup(Btree*);
    + SQLITE_PRIVATE void *sqlite3BtreeSchema(Btree *, int, void(*)(void *));
    + SQLITE_PRIVATE int sqlite3BtreeSchemaLocked(Btree *pBtree);
    ++#ifndef SQLITE_OMIT_SHARED_CACHE
    + SQLITE_PRIVATE int sqlite3BtreeLockTable(Btree *pBtree, int iTab, u8 isWriteLock);
    ++#endif
    + SQLITE_PRIVATE int sqlite3BtreeSavepoint(Btree *, int, int);
    + 
    + SQLITE_PRIVATE const char *sqlite3BtreeGetFilename(Btree *);
    +@@ -10141,8 +13442,37 @@ SQLITE_PRIVATE int sqlite3BtreeNewDb(Btree *p);
    + #define BTREE_DATA_VERSION        15  /* A virtual meta-value */
    + 
    + /*
    +-** Values that may be OR'd together to form the second argument of an
    +-** sqlite3BtreeCursorHints() call.
    ++** Kinds of hints that can be passed into the sqlite3BtreeCursorHint()
    ++** interface.
    ++**
    ++** BTREE_HINT_RANGE  (arguments: Expr*, Mem*)
    ++**
    ++**     The first argument is an Expr* (which is guaranteed to be constant for
    ++**     the lifetime of the cursor) that defines constraints on which rows
    ++**     might be fetched with this cursor.  The Expr* tree may contain
    ++**     TK_REGISTER nodes that refer to values stored in the array of registers
    ++**     passed as the second parameter.  In other words, if Expr.op==TK_REGISTER
    ++**     then the value of the node is the value in Mem[pExpr.iTable].  Any
    ++**     TK_COLUMN node in the expression tree refers to the Expr.iColumn-th
    ++**     column of the b-tree of the cursor.  The Expr tree will not contain
    ++**     any function calls nor subqueries nor references to b-trees other than
    ++**     the cursor being hinted.
    ++**
    ++**     The design of the _RANGE hint is aid b-tree implementations that try
    ++**     to prefetch content from remote machines - to provide those
    ++**     implementations with limits on what needs to be prefetched and thereby
    ++**     reduce network bandwidth.
    ++**
    ++** Note that BTREE_HINT_FLAGS with BTREE_BULKLOAD is the only hint used by
    ++** standard SQLite.  The other hints are provided for extentions that use
    ++** the SQLite parser and code generator but substitute their own storage
    ++** engine.
    ++*/
    ++#define BTREE_HINT_RANGE 0       /* Range constraints on queries */
    ++
    ++/*
    ++** Values that may be OR'd together to form the argument to the
    ++** BTREE_HINT_FLAGS hint for sqlite3BtreeCursorHint():
    + **
    + ** The BTREE_BULKLOAD flag is set on index cursors when the index is going
    + ** to be filled with content that is already in sorted order.
    +@@ -10156,6 +13486,32 @@ SQLITE_PRIVATE int sqlite3BtreeNewDb(Btree *p);
    + #define BTREE_BULKLOAD 0x00000001  /* Used to full index in sorted order */
    + #define BTREE_SEEK_EQ  0x00000002  /* EQ seeks only - no range seeks */
    + 
    ++/* 
    ++** Flags passed as the third argument to sqlite3BtreeCursor().
    ++**
    ++** For read-only cursors the wrFlag argument is always zero. For read-write
    ++** cursors it may be set to either (BTREE_WRCSR|BTREE_FORDELETE) or just
    ++** (BTREE_WRCSR). If the BTREE_FORDELETE bit is set, then the cursor will
    ++** only be used by SQLite for the following:
    ++**
    ++**   * to seek to and then delete specific entries, and/or
    ++**
    ++**   * to read values that will be used to create keys that other
    ++**     BTREE_FORDELETE cursors will seek to and delete.
    ++**
    ++** The BTREE_FORDELETE flag is an optimization hint.  It is not used by
    ++** by this, the native b-tree engine of SQLite, but it is available to
    ++** alternative storage engines that might be substituted in place of this
    ++** b-tree system.  For alternative storage engines in which a delete of
    ++** the main table row automatically deletes corresponding index rows,
    ++** the FORDELETE flag hint allows those alternative storage engines to
    ++** skip a lot of work.  Namely:  FORDELETE cursors may treat all SEEK
    ++** and DELETE operations as no-ops, and any READ operation against a
    ++** FORDELETE cursor may return a null row: 0x01 0x00.
    ++*/
    ++#define BTREE_WRCSR     0x00000004     /* read-write cursor */
    ++#define BTREE_FORDELETE 0x00000008     /* Cursor is for seek/delete only */
    ++
    + SQLITE_PRIVATE int sqlite3BtreeCursor(
    +   Btree*,                              /* BTree containing table to open */
    +   int iTable,                          /* Index of root page */
    +@@ -10163,8 +13519,13 @@ SQLITE_PRIVATE int sqlite3BtreeCursor(
    +   struct KeyInfo*,                     /* First argument to compare function */
    +   BtCursor *pCursor                    /* Space to write cursor structure */
    + );
    ++SQLITE_PRIVATE BtCursor *sqlite3BtreeFakeValidCursor(void);
    + SQLITE_PRIVATE int sqlite3BtreeCursorSize(void);
    + SQLITE_PRIVATE void sqlite3BtreeCursorZero(BtCursor*);
    ++SQLITE_PRIVATE void sqlite3BtreeCursorHintFlags(BtCursor*, unsigned);
    ++#ifdef SQLITE_ENABLE_CURSOR_HINTS
    ++SQLITE_PRIVATE void sqlite3BtreeCursorHint(BtCursor*, int, ...);
    ++#endif
    + 
    + SQLITE_PRIVATE int sqlite3BtreeCloseCursor(BtCursor*);
    + SQLITE_PRIVATE int sqlite3BtreeMovetoUnpacked(
    +@@ -10176,39 +13537,75 @@ SQLITE_PRIVATE int sqlite3BtreeMovetoUnpacked(
    + );
    + SQLITE_PRIVATE int sqlite3BtreeCursorHasMoved(BtCursor*);
    + SQLITE_PRIVATE int sqlite3BtreeCursorRestore(BtCursor*, int*);
    +-SQLITE_PRIVATE int sqlite3BtreeDelete(BtCursor*, int);
    +-SQLITE_PRIVATE int sqlite3BtreeInsert(BtCursor*, const void *pKey, i64 nKey,
    +-                                  const void *pData, int nData,
    +-                                  int nZero, int bias, int seekResult);
    ++SQLITE_PRIVATE int sqlite3BtreeDelete(BtCursor*, u8 flags);
    ++
    ++/* Allowed flags for sqlite3BtreeDelete() and sqlite3BtreeInsert() */
    ++#define BTREE_SAVEPOSITION 0x02  /* Leave cursor pointing at NEXT or PREV */
    ++#define BTREE_AUXDELETE    0x04  /* not the primary delete operation */
    ++#define BTREE_APPEND       0x08  /* Insert is likely an append */
    ++
    ++/* An instance of the BtreePayload object describes the content of a single
    ++** entry in either an index or table btree.
    ++**
    ++** Index btrees (used for indexes and also WITHOUT ROWID tables) contain
    ++** an arbitrary key and no data.  These btrees have pKey,nKey set to their
    ++** key and pData,nData,nZero set to zero.
    ++**
    ++** Table btrees (used for rowid tables) contain an integer rowid used as
    ++** the key and passed in the nKey field.  The pKey field is zero.  
    ++** pData,nData hold the content of the new entry.  nZero extra zero bytes
    ++** are appended to the end of the content when constructing the entry.
    ++**
    ++** This object is used to pass information into sqlite3BtreeInsert().  The
    ++** same information used to be passed as five separate parameters.  But placing
    ++** the information into this object helps to keep the interface more 
    ++** organized and understandable, and it also helps the resulting code to
    ++** run a little faster by using fewer registers for parameter passing.
    ++*/
    ++struct BtreePayload {
    ++  const void *pKey;       /* Key content for indexes.  NULL for tables */
    ++  sqlite3_int64 nKey;     /* Size of pKey for indexes.  PRIMARY KEY for tabs */
    ++  const void *pData;      /* Data for tables.  NULL for indexes */
    ++  sqlite3_value *aMem;    /* First of nMem value in the unpacked pKey */
    ++  u16 nMem;               /* Number of aMem[] value.  Might be zero */
    ++  int nData;              /* Size of pData.  0 if none. */
    ++  int nZero;              /* Extra zero data appended after pData,nData */
    ++};
    ++
    ++SQLITE_PRIVATE int sqlite3BtreeInsert(BtCursor*, const BtreePayload *pPayload,
    ++                       int flags, int seekResult);
    + SQLITE_PRIVATE int sqlite3BtreeFirst(BtCursor*, int *pRes);
    + SQLITE_PRIVATE int sqlite3BtreeLast(BtCursor*, int *pRes);
    +-SQLITE_PRIVATE int sqlite3BtreeNext(BtCursor*, int *pRes);
    ++SQLITE_PRIVATE int sqlite3BtreeNext(BtCursor*, int flags);
    + SQLITE_PRIVATE int sqlite3BtreeEof(BtCursor*);
    +-SQLITE_PRIVATE int sqlite3BtreePrevious(BtCursor*, int *pRes);
    +-SQLITE_PRIVATE int sqlite3BtreeKeySize(BtCursor*, i64 *pSize);
    +-SQLITE_PRIVATE int sqlite3BtreeKey(BtCursor*, u32 offset, u32 amt, void*);
    +-SQLITE_PRIVATE const void *sqlite3BtreeKeyFetch(BtCursor*, u32 *pAmt);
    +-SQLITE_PRIVATE const void *sqlite3BtreeDataFetch(BtCursor*, u32 *pAmt);
    +-SQLITE_PRIVATE int sqlite3BtreeDataSize(BtCursor*, u32 *pSize);
    +-SQLITE_PRIVATE int sqlite3BtreeData(BtCursor*, u32 offset, u32 amt, void*);
    ++SQLITE_PRIVATE int sqlite3BtreePrevious(BtCursor*, int flags);
    ++SQLITE_PRIVATE i64 sqlite3BtreeIntegerKey(BtCursor*);
    ++#ifdef SQLITE_ENABLE_OFFSET_SQL_FUNC
    ++SQLITE_PRIVATE i64 sqlite3BtreeOffset(BtCursor*);
    ++#endif
    ++SQLITE_PRIVATE int sqlite3BtreePayload(BtCursor*, u32 offset, u32 amt, void*);
    ++SQLITE_PRIVATE const void *sqlite3BtreePayloadFetch(BtCursor*, u32 *pAmt);
    ++SQLITE_PRIVATE u32 sqlite3BtreePayloadSize(BtCursor*);
    + 
    + SQLITE_PRIVATE char *sqlite3BtreeIntegrityCheck(Btree*, int *aRoot, int nRoot, int, int*);
    + SQLITE_PRIVATE struct Pager *sqlite3BtreePager(Btree*);
    ++SQLITE_PRIVATE i64 sqlite3BtreeRowCountEst(BtCursor*);
    + 
    ++#ifndef SQLITE_OMIT_INCRBLOB
    ++SQLITE_PRIVATE int sqlite3BtreePayloadChecked(BtCursor*, u32 offset, u32 amt, void*);
    + SQLITE_PRIVATE int sqlite3BtreePutData(BtCursor*, u32 offset, u32 amt, void*);
    + SQLITE_PRIVATE void sqlite3BtreeIncrblobCursor(BtCursor *);
    ++#endif
    + SQLITE_PRIVATE void sqlite3BtreeClearCursor(BtCursor *);
    + SQLITE_PRIVATE int sqlite3BtreeSetVersion(Btree *pBt, int iVersion);
    +-SQLITE_PRIVATE void sqlite3BtreeCursorHints(BtCursor *, unsigned int mask);
    +-#ifdef SQLITE_DEBUG
    + SQLITE_PRIVATE int sqlite3BtreeCursorHasHint(BtCursor*, unsigned int mask);
    +-#endif
    + SQLITE_PRIVATE int sqlite3BtreeIsReadonly(Btree *pBt);
    + SQLITE_PRIVATE int sqlite3HeaderSizeBtree(void);
    + 
    + #ifndef NDEBUG
    + SQLITE_PRIVATE int sqlite3BtreeCursorIsValid(BtCursor*);
    + #endif
    ++SQLITE_PRIVATE int sqlite3BtreeCursorIsValidNN(BtCursor*);
    + 
    + #ifndef SQLITE_OMIT_BTREECOUNT
    + SQLITE_PRIVATE int sqlite3BtreeCount(BtCursor *, i64 *);
    +@@ -10231,15 +13628,19 @@ SQLITE_PRIVATE   int sqlite3BtreeCheckpoint(Btree*, int, int *, int *);
    + #ifndef SQLITE_OMIT_SHARED_CACHE
    + SQLITE_PRIVATE   void sqlite3BtreeEnter(Btree*);
    + SQLITE_PRIVATE   void sqlite3BtreeEnterAll(sqlite3*);
    ++SQLITE_PRIVATE   int sqlite3BtreeSharable(Btree*);
    ++SQLITE_PRIVATE   void sqlite3BtreeEnterCursor(BtCursor*);
    ++SQLITE_PRIVATE   int sqlite3BtreeConnectionCount(Btree*);
    + #else
    + # define sqlite3BtreeEnter(X) 
    + # define sqlite3BtreeEnterAll(X)
    ++# define sqlite3BtreeSharable(X) 0
    ++# define sqlite3BtreeEnterCursor(X)
    ++# define sqlite3BtreeConnectionCount(X) 1
    + #endif
    + 
    + #if !defined(SQLITE_OMIT_SHARED_CACHE) && SQLITE_THREADSAFE
    +-SQLITE_PRIVATE   int sqlite3BtreeSharable(Btree*);
    + SQLITE_PRIVATE   void sqlite3BtreeLeave(Btree*);
    +-SQLITE_PRIVATE   void sqlite3BtreeEnterCursor(BtCursor*);
    + SQLITE_PRIVATE   void sqlite3BtreeLeaveCursor(BtCursor*);
    + SQLITE_PRIVATE   void sqlite3BtreeLeaveAll(sqlite3*);
    + #ifndef NDEBUG
    +@@ -10250,9 +13651,7 @@ SQLITE_PRIVATE   int sqlite3SchemaMutexHeld(sqlite3*,int,Schema*);
    + #endif
    + #else
    + 
    +-# define sqlite3BtreeSharable(X) 0
    + # define sqlite3BtreeLeave(X)
    +-# define sqlite3BtreeEnterCursor(X)
    + # define sqlite3BtreeLeaveCursor(X)
    + # define sqlite3BtreeLeaveAll(X)
    + 
    +@@ -10262,7 +13661,7 @@ SQLITE_PRIVATE   int sqlite3SchemaMutexHeld(sqlite3*,int,Schema*);
    + #endif
    + 
    + 
    +-#endif /* _BTREE_H_ */
    ++#endif /* SQLITE_BTREE_H */
    + 
    + /************** End of btree.h ***********************************************/
    + /************** Continuing where we left off in sqliteInt.h ******************/
    +@@ -10285,8 +13684,8 @@ SQLITE_PRIVATE   int sqlite3SchemaMutexHeld(sqlite3*,int,Schema*);
    + ** or VDBE.  The VDBE implements an abstract machine that runs a
    + ** simple program to access and modify the underlying database.
    + */
    +-#ifndef _SQLITE_VDBE_H_
    +-#define _SQLITE_VDBE_H_
    ++#ifndef SQLITE_VDBE_H
    ++#define SQLITE_VDBE_H
    + /* #include <stdio.h> */
    + 
    + /*
    +@@ -10300,7 +13699,7 @@ typedef struct Vdbe Vdbe;
    + ** The names of the following types declared in vdbeInt.h are required
    + ** for the VdbeOp definition.
    + */
    +-typedef struct Mem Mem;
    ++typedef struct sqlite3_value Mem;
    + typedef struct SubProgram SubProgram;
    + 
    + /*
    +@@ -10311,8 +13710,7 @@ typedef struct SubProgram SubProgram;
    + struct VdbeOp {
    +   u8 opcode;          /* What operation to perform */
    +   signed char p4type; /* One of the P4_xxx constants for p4 */
    +-  u8 opflags;         /* Mask of the OPFLG_* flags in opcodes.h */
    +-  u8 p5;              /* Fifth parameter is an unsigned character */
    ++  u16 p5;             /* Fifth parameter is an unsigned 16-bit integer */
    +   int p1;             /* First operand */
    +   int p2;             /* Second parameter (often the jump destination) */
    +   int p3;             /* The third parameter */
    +@@ -10330,7 +13728,11 @@ struct VdbeOp {
    +     KeyInfo *pKeyInfo;     /* Used when p4type is P4_KEYINFO */
    +     int *ai;               /* Used when p4type is P4_INTARRAY */
    +     SubProgram *pProgram;  /* Used when p4type is P4_SUBPROGRAM */
    +-    int (*xAdvance)(BtCursor *, int *);
    ++    Table *pTab;           /* Used when p4type is P4_TABLE */
    ++#ifdef SQLITE_ENABLE_CURSOR_HINTS
    ++    Expr *pExpr;           /* Used when p4type is P4_EXPR */
    ++#endif
    ++    int (*xAdvance)(BtCursor *, int);
    +   } p4;
    + #ifdef SQLITE_ENABLE_EXPLAIN_COMMENTS
    +   char *zComment;          /* Comment to improve readability */
    +@@ -10354,7 +13756,7 @@ struct SubProgram {
    +   int nOp;                      /* Elements in aOp[] */
    +   int nMem;                     /* Number of memory cells required */
    +   int nCsr;                     /* Number of cursors required */
    +-  int nOnce;                    /* Number of OP_Once instructions */
    ++  u8 *aOnce;                    /* Array of OP_Once flags */
    +   void *token;                  /* id that may be used to recursive triggers */
    +   SubProgram *pNext;            /* Next sub-program already visited */
    + };
    +@@ -10374,23 +13776,27 @@ typedef struct VdbeOpList VdbeOpList;
    + /*
    + ** Allowed values of VdbeOp.p4type
    + */
    +-#define P4_NOTUSED    0   /* The P4 parameter is not used */
    +-#define P4_DYNAMIC  (-1)  /* Pointer to a string obtained from sqliteMalloc() */
    +-#define P4_STATIC   (-2)  /* Pointer to a static string */
    +-#define P4_COLLSEQ  (-4)  /* P4 is a pointer to a CollSeq structure */
    +-#define P4_FUNCDEF  (-5)  /* P4 is a pointer to a FuncDef structure */
    +-#define P4_KEYINFO  (-6)  /* P4 is a pointer to a KeyInfo structure */
    +-#define P4_MEM      (-8)  /* P4 is a pointer to a Mem*    structure */
    +-#define P4_TRANSIENT  0   /* P4 is a pointer to a transient string */
    +-#define P4_VTAB     (-10) /* P4 is a pointer to an sqlite3_vtab structure */
    +-#define P4_MPRINTF  (-11) /* P4 is a string obtained from sqlite3_mprintf() */
    +-#define P4_REAL     (-12) /* P4 is a 64-bit floating point value */
    +-#define P4_INT64    (-13) /* P4 is a 64-bit signed integer */
    +-#define P4_INT32    (-14) /* P4 is a 32-bit signed integer */
    +-#define P4_INTARRAY (-15) /* P4 is a vector of 32-bit integers */
    +-#define P4_SUBPROGRAM  (-18) /* P4 is a pointer to a SubProgram structure */
    +-#define P4_ADVANCE  (-19) /* P4 is a pointer to BtreeNext() or BtreePrev() */
    +-#define P4_FUNCCTX  (-20) /* P4 is a pointer to an sqlite3_context object */
    ++#define P4_NOTUSED      0   /* The P4 parameter is not used */
    ++#define P4_TRANSIENT    0   /* P4 is a pointer to a transient string */
    ++#define P4_STATIC     (-1)  /* Pointer to a static string */
    ++#define P4_COLLSEQ    (-2)  /* P4 is a pointer to a CollSeq structure */
    ++#define P4_INT32      (-3)  /* P4 is a 32-bit signed integer */
    ++#define P4_SUBPROGRAM (-4)  /* P4 is a pointer to a SubProgram structure */
    ++#define P4_ADVANCE    (-5)  /* P4 is a pointer to BtreeNext() or BtreePrev() */
    ++#define P4_TABLE      (-6)  /* P4 is a pointer to a Table structure */
    ++/* Above do not own any resources.  Must free those below */
    ++#define P4_FREE_IF_LE (-7)
    ++#define P4_DYNAMIC    (-7)  /* Pointer to memory from sqliteMalloc() */
    ++#define P4_FUNCDEF    (-8)  /* P4 is a pointer to a FuncDef structure */
    ++#define P4_KEYINFO    (-9)  /* P4 is a pointer to a KeyInfo structure */
    ++#define P4_EXPR       (-10) /* P4 is a pointer to an Expr tree */
    ++#define P4_MEM        (-11) /* P4 is a pointer to a Mem*    structure */
    ++#define P4_VTAB       (-12) /* P4 is a pointer to an sqlite3_vtab structure */
    ++#define P4_REAL       (-13) /* P4 is a 64-bit floating point value */
    ++#define P4_INT64      (-14) /* P4 is a 64-bit signed integer */
    ++#define P4_INTARRAY   (-15) /* P4 is a vector of 32-bit integers */
    ++#define P4_FUNCCTX    (-16) /* P4 is a pointer to an sqlite3_context object */
    ++#define P4_DYNBLOB    (-17) /* Pointer to memory from sqliteMalloc() */
    + 
    + /* Error message codes for OP_Halt */
    + #define P5_ConstraintNotNull 1
    +@@ -10432,205 +13838,229 @@ typedef struct VdbeOpList VdbeOpList;
    + /************** Include opcodes.h in the middle of vdbe.h ********************/
    + /************** Begin file opcodes.h *****************************************/
    + /* Automatically generated.  Do not edit */
    +-/* See the mkopcodeh.awk script for details */
    +-#define OP_Savepoint       1
    +-#define OP_AutoCommit      2
    +-#define OP_Transaction     3
    +-#define OP_SorterNext      4
    +-#define OP_PrevIfOpen      5
    +-#define OP_NextIfOpen      6
    +-#define OP_Prev            7
    +-#define OP_Next            8
    +-#define OP_Checkpoint      9
    +-#define OP_JournalMode    10
    +-#define OP_Vacuum         11
    +-#define OP_VFilter        12 /* synopsis: iplan=r[P3] zplan='P4'           */
    +-#define OP_VUpdate        13 /* synopsis: data=r[P3@P2]                    */
    +-#define OP_Goto           14
    +-#define OP_Gosub          15
    +-#define OP_Return         16
    +-#define OP_InitCoroutine  17
    +-#define OP_EndCoroutine   18
    ++/* See the tool/mkopcodeh.tcl script for details */
    ++#define OP_Savepoint       0
    ++#define OP_AutoCommit      1
    ++#define OP_Transaction     2
    ++#define OP_SorterNext      3 /* jump                                       */
    ++#define OP_PrevIfOpen      4 /* jump                                       */
    ++#define OP_NextIfOpen      5 /* jump                                       */
    ++#define OP_Prev            6 /* jump                                       */
    ++#define OP_Next            7 /* jump                                       */
    ++#define OP_Checkpoint      8
    ++#define OP_JournalMode     9
    ++#define OP_Vacuum         10
    ++#define OP_VFilter        11 /* jump, synopsis: iplan=r[P3] zplan='P4'     */
    ++#define OP_VUpdate        12 /* synopsis: data=r[P3@P2]                    */
    ++#define OP_Goto           13 /* jump                                       */
    ++#define OP_Gosub          14 /* jump                                       */
    ++#define OP_InitCoroutine  15 /* jump                                       */
    ++#define OP_Yield          16 /* jump                                       */
    ++#define OP_MustBeInt      17 /* jump                                       */
    ++#define OP_Jump           18 /* jump                                       */
    + #define OP_Not            19 /* same as TK_NOT, synopsis: r[P2]= !r[P1]    */
    +-#define OP_Yield          20
    +-#define OP_HaltIfNull     21 /* synopsis: if r[P3]=null halt               */
    +-#define OP_Halt           22
    +-#define OP_Integer        23 /* synopsis: r[P2]=P1                         */
    +-#define OP_Int64          24 /* synopsis: r[P2]=P4                         */
    +-#define OP_String         25 /* synopsis: r[P2]='P4' (len=P1)              */
    +-#define OP_Null           26 /* synopsis: r[P2..P3]=NULL                   */
    +-#define OP_SoftNull       27 /* synopsis: r[P1]=NULL                       */
    +-#define OP_Blob           28 /* synopsis: r[P2]=P4 (len=P1)                */
    +-#define OP_Variable       29 /* synopsis: r[P2]=parameter(P1,P4)           */
    +-#define OP_Move           30 /* synopsis: r[P2@P3]=r[P1@P3]                */
    +-#define OP_Copy           31 /* synopsis: r[P2@P3+1]=r[P1@P3+1]            */
    +-#define OP_SCopy          32 /* synopsis: r[P2]=r[P1]                      */
    +-#define OP_ResultRow      33 /* synopsis: output=r[P1@P2]                  */
    +-#define OP_CollSeq        34
    +-#define OP_Function0      35 /* synopsis: r[P3]=func(r[P2@P5])             */
    +-#define OP_Function       36 /* synopsis: r[P3]=func(r[P2@P5])             */
    +-#define OP_AddImm         37 /* synopsis: r[P1]=r[P1]+P2                   */
    +-#define OP_MustBeInt      38
    +-#define OP_RealAffinity   39
    +-#define OP_Cast           40 /* synopsis: affinity(r[P1])                  */
    +-#define OP_Permutation    41
    +-#define OP_Compare        42 /* synopsis: r[P1@P3] <-> r[P2@P3]            */
    +-#define OP_Jump           43
    +-#define OP_Once           44
    +-#define OP_If             45
    +-#define OP_IfNot          46
    +-#define OP_Column         47 /* synopsis: r[P3]=PX                         */
    +-#define OP_Affinity       48 /* synopsis: affinity(r[P1@P2])               */
    +-#define OP_MakeRecord     49 /* synopsis: r[P3]=mkrec(r[P1@P2])            */
    +-#define OP_Count          50 /* synopsis: r[P2]=count()                    */
    +-#define OP_ReadCookie     51
    +-#define OP_SetCookie      52
    +-#define OP_ReopenIdx      53 /* synopsis: root=P2 iDb=P3                   */
    +-#define OP_OpenRead       54 /* synopsis: root=P2 iDb=P3                   */
    +-#define OP_OpenWrite      55 /* synopsis: root=P2 iDb=P3                   */
    +-#define OP_OpenAutoindex  56 /* synopsis: nColumn=P2                       */
    +-#define OP_OpenEphemeral  57 /* synopsis: nColumn=P2                       */
    +-#define OP_SorterOpen     58
    +-#define OP_SequenceTest   59 /* synopsis: if( cursor[P1].ctr++ ) pc = P2   */
    +-#define OP_OpenPseudo     60 /* synopsis: P3 columns in r[P2]              */
    +-#define OP_Close          61
    +-#define OP_ColumnsUsed    62
    +-#define OP_SeekLT         63 /* synopsis: key=r[P3@P4]                     */
    +-#define OP_SeekLE         64 /* synopsis: key=r[P3@P4]                     */
    +-#define OP_SeekGE         65 /* synopsis: key=r[P3@P4]                     */
    +-#define OP_SeekGT         66 /* synopsis: key=r[P3@P4]                     */
    +-#define OP_Seek           67 /* synopsis: intkey=r[P2]                     */
    +-#define OP_NoConflict     68 /* synopsis: key=r[P3@P4]                     */
    +-#define OP_NotFound       69 /* synopsis: key=r[P3@P4]                     */
    +-#define OP_Found          70 /* synopsis: key=r[P3@P4]                     */
    +-#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_NotExists      73 /* synopsis: intkey=r[P3]                     */
    +-#define OP_Sequence       74 /* synopsis: r[P2]=cursor[P1].ctr++           */
    +-#define OP_NewRowid       75 /* synopsis: r[P2]=rowid                      */
    +-#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 */
    +-#define OP_Eq             79 /* same as TK_EQ, synopsis: if r[P1]==r[P3] goto P2 */
    +-#define OP_Gt             80 /* same as TK_GT, synopsis: if r[P1]>r[P3] goto P2 */
    +-#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_Ge             83 /* same as TK_GE, synopsis: if r[P1]>=r[P3] goto P2 */
    +-#define OP_Insert         84 /* synopsis: intkey=r[P3] data=r[P2]          */
    +-#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]<<r[P1] */
    +-#define OP_ShiftRight     88 /* same as TK_RSHIFT, synopsis: r[P3]=r[P2]>>r[P1] */
    +-#define OP_Add            89 /* same as TK_PLUS, synopsis: r[P3]=r[P1]+r[P2] */
    +-#define OP_Subtract       90 /* same as TK_MINUS, synopsis: r[P3]=r[P2]-r[P1] */
    +-#define OP_Multiply       91 /* same as TK_STAR, synopsis: r[P3]=r[P1]*r[P2] */
    +-#define OP_Divide         92 /* same as TK_SLASH, synopsis: r[P3]=r[P2]/r[P1] */
    +-#define OP_Remainder      93 /* same as TK_REM, synopsis: r[P3]=r[P2]%r[P1] */
    +-#define OP_Concat         94 /* same as TK_CONCAT, synopsis: r[P3]=r[P2]+r[P1] */
    +-#define OP_InsertInt      95 /* synopsis: intkey=P3 data=r[P2]             */
    +-#define OP_BitNot         96 /* same as TK_BITNOT, synopsis: r[P1]= ~r[P1] */
    ++#define OP_Once           20 /* jump                                       */
    ++#define OP_If             21 /* jump                                       */
    ++#define OP_IfNot          22 /* jump                                       */
    ++#define OP_IfNullRow      23 /* jump, synopsis: if P1.nullRow then r[P3]=NULL, goto P2 */
    ++#define OP_SeekLT         24 /* jump, synopsis: key=r[P3@P4]               */
    ++#define OP_SeekLE         25 /* jump, synopsis: key=r[P3@P4]               */
    ++#define OP_SeekGE         26 /* jump, synopsis: key=r[P3@P4]               */
    ++#define OP_SeekGT         27 /* jump, synopsis: key=r[P3@P4]               */
    ++#define OP_NoConflict     28 /* jump, synopsis: key=r[P3@P4]               */
    ++#define OP_NotFound       29 /* jump, synopsis: key=r[P3@P4]               */
    ++#define OP_Found          30 /* jump, synopsis: key=r[P3@P4]               */
    ++#define OP_SeekRowid      31 /* jump, synopsis: intkey=r[P3]               */
    ++#define OP_NotExists      32 /* jump, synopsis: intkey=r[P3]               */
    ++#define OP_Last           33 /* jump                                       */
    ++#define OP_IfSmaller      34 /* jump                                       */
    ++#define OP_SorterSort     35 /* jump                                       */
    ++#define OP_Sort           36 /* jump                                       */
    ++#define OP_Rewind         37 /* jump                                       */
    ++#define OP_IdxLE          38 /* jump, synopsis: key=r[P3@P4]               */
    ++#define OP_IdxGT          39 /* jump, synopsis: key=r[P3@P4]               */
    ++#define OP_IdxLT          40 /* jump, synopsis: key=r[P3@P4]               */
    ++#define OP_IdxGE          41 /* jump, synopsis: key=r[P3@P4]               */
    ++#define OP_RowSetRead     42 /* jump, synopsis: r[P3]=rowset(P1)           */
    ++#define OP_Or             43 /* same as TK_OR, synopsis: r[P3]=(r[P1] || r[P2]) */
    ++#define OP_And            44 /* same as TK_AND, synopsis: r[P3]=(r[P1] && r[P2]) */
    ++#define OP_RowSetTest     45 /* jump, synopsis: if r[P3] in rowset(P1) goto P2 */
    ++#define OP_Program        46 /* jump                                       */
    ++#define OP_FkIfZero       47 /* jump, synopsis: if fkctr[P1]==0 goto P2    */
    ++#define OP_IfPos          48 /* jump, synopsis: if r[P1]>0 then r[P1]-=P3, goto P2 */
    ++#define OP_IfNotZero      49 /* jump, synopsis: if r[P1]!=0 then r[P1]--, goto P2 */
    ++#define OP_IsNull         50 /* jump, same as TK_ISNULL, synopsis: if r[P1]==NULL goto P2 */
    ++#define OP_NotNull        51 /* jump, same as TK_NOTNULL, synopsis: if r[P1]!=NULL goto P2 */
    ++#define OP_Ne             52 /* jump, same as TK_NE, synopsis: IF r[P3]!=r[P1] */
    ++#define OP_Eq             53 /* jump, same as TK_EQ, synopsis: IF r[P3]==r[P1] */
    ++#define OP_Gt             54 /* jump, same as TK_GT, synopsis: IF r[P3]>r[P1] */
    ++#define OP_Le             55 /* jump, same as TK_LE, synopsis: IF r[P3]<=r[P1] */
    ++#define OP_Lt             56 /* jump, same as TK_LT, synopsis: IF r[P3]<r[P1] */
    ++#define OP_Ge             57 /* jump, same as TK_GE, synopsis: IF r[P3]>=r[P1] */
    ++#define OP_ElseNotEq      58 /* jump, same as TK_ESCAPE                    */
    ++#define OP_DecrJumpZero   59 /* jump, synopsis: if (--r[P1])==0 goto P2    */
    ++#define OP_IncrVacuum     60 /* jump                                       */
    ++#define OP_VNext          61 /* jump                                       */
    ++#define OP_Init           62 /* jump, synopsis: Start at P2                */
    ++#define OP_Return         63
    ++#define OP_EndCoroutine   64
    ++#define OP_HaltIfNull     65 /* synopsis: if r[P3]=null halt               */
    ++#define OP_Halt           66
    ++#define OP_Integer        67 /* synopsis: r[P2]=P1                         */
    ++#define OP_Int64          68 /* synopsis: r[P2]=P4                         */
    ++#define OP_String         69 /* synopsis: r[P2]='P4' (len=P1)              */
    ++#define OP_Null           70 /* synopsis: r[P2..P3]=NULL                   */
    ++#define OP_SoftNull       71 /* synopsis: r[P1]=NULL                       */
    ++#define OP_Blob           72 /* synopsis: r[P2]=P4 (len=P1)                */
    ++#define OP_Variable       73 /* synopsis: r[P2]=parameter(P1,P4)           */
    ++#define OP_Move           74 /* synopsis: r[P2@P3]=r[P1@P3]                */
    ++#define OP_Copy           75 /* synopsis: r[P2@P3+1]=r[P1@P3+1]            */
    ++#define OP_SCopy          76 /* synopsis: r[P2]=r[P1]                      */
    ++#define OP_IntCopy        77 /* synopsis: r[P2]=r[P1]                      */
    ++#define OP_ResultRow      78 /* synopsis: output=r[P1@P2]                  */
    ++#define OP_CollSeq        79
    ++#define OP_AddImm         80 /* synopsis: r[P1]=r[P1]+P2                   */
    ++#define OP_RealAffinity   81
    ++#define OP_Cast           82 /* synopsis: affinity(r[P1])                  */
    ++#define OP_Permutation    83
    ++#define OP_BitAnd         84 /* same as TK_BITAND, synopsis: r[P3]=r[P1]&r[P2] */
    ++#define OP_BitOr          85 /* same as TK_BITOR, synopsis: r[P3]=r[P1]|r[P2] */
    ++#define OP_ShiftLeft      86 /* same as TK_LSHIFT, synopsis: r[P3]=r[P2]<<r[P1] */
    ++#define OP_ShiftRight     87 /* same as TK_RSHIFT, synopsis: r[P3]=r[P2]>>r[P1] */
    ++#define OP_Add            88 /* same as TK_PLUS, synopsis: r[P3]=r[P1]+r[P2] */
    ++#define OP_Subtract       89 /* same as TK_MINUS, synopsis: r[P3]=r[P2]-r[P1] */
    ++#define OP_Multiply       90 /* same as TK_STAR, synopsis: r[P3]=r[P1]*r[P2] */
    ++#define OP_Divide         91 /* same as TK_SLASH, synopsis: r[P3]=r[P2]/r[P1] */
    ++#define OP_Remainder      92 /* same as TK_REM, synopsis: r[P3]=r[P2]%r[P1] */
    ++#define OP_Concat         93 /* same as TK_CONCAT, synopsis: r[P3]=r[P2]+r[P1] */
    ++#define OP_Compare        94 /* synopsis: r[P1@P3] <-> r[P2@P3]            */
    ++#define OP_BitNot         95 /* same as TK_BITNOT, synopsis: r[P1]= ~r[P1] */
    ++#define OP_Offset         96 /* synopsis: r[P3] = sqlite_offset(P1)        */
    + #define OP_String8        97 /* same as TK_STRING, synopsis: r[P2]='P4'    */
    +-#define OP_Delete         98
    +-#define OP_ResetCount     99
    +-#define OP_SorterCompare 100 /* synopsis: if key(P1)!=trim(r[P3],P4) goto P2 */
    +-#define OP_SorterData    101 /* synopsis: r[P2]=data                       */
    +-#define OP_RowKey        102 /* synopsis: r[P2]=key                        */
    +-#define OP_RowData       103 /* synopsis: r[P2]=data                       */
    +-#define OP_Rowid         104 /* synopsis: r[P2]=rowid                      */
    +-#define OP_NullRow       105
    +-#define OP_Last          106
    +-#define OP_SorterSort    107
    +-#define OP_Sort          108
    +-#define OP_Rewind        109
    +-#define OP_SorterInsert  110
    +-#define OP_IdxInsert     111 /* synopsis: key=r[P2]                        */
    +-#define OP_IdxDelete     112 /* synopsis: key=r[P2@P3]                     */
    +-#define OP_IdxRowid      113 /* synopsis: r[P2]=rowid                      */
    +-#define OP_IdxLE         114 /* synopsis: key=r[P3@P4]                     */
    +-#define OP_IdxGT         115 /* synopsis: key=r[P3@P4]                     */
    +-#define OP_IdxLT         116 /* synopsis: key=r[P3@P4]                     */
    +-#define OP_IdxGE         117 /* synopsis: key=r[P3@P4]                     */
    +-#define OP_Destroy       118
    +-#define OP_Clear         119
    +-#define OP_ResetSorter   120
    +-#define OP_CreateIndex   121 /* synopsis: r[P2]=root iDb=P1                */
    +-#define OP_CreateTable   122 /* synopsis: r[P2]=root iDb=P1                */
    +-#define OP_ParseSchema   123
    +-#define OP_LoadAnalysis  124
    +-#define OP_DropTable     125
    +-#define OP_DropIndex     126
    +-#define OP_DropTrigger   127
    +-#define OP_IntegrityCk   128
    +-#define OP_RowSetAdd     129 /* synopsis: rowset(P1)=r[P2]                 */
    +-#define OP_RowSetRead    130 /* synopsis: r[P3]=rowset(P1)                 */
    +-#define OP_RowSetTest    131 /* synopsis: if r[P3] in rowset(P1) goto P2   */
    +-#define OP_Program       132
    +-#define OP_Real          133 /* same as TK_FLOAT, synopsis: r[P2]=P4       */
    +-#define OP_Param         134
    +-#define OP_FkCounter     135 /* synopsis: fkctr[P1]+=P2                    */
    +-#define OP_FkIfZero      136 /* synopsis: if fkctr[P1]==0 goto P2          */
    +-#define OP_MemMax        137 /* synopsis: r[P1]=max(r[P1],r[P2])           */
    +-#define OP_IfPos         138 /* synopsis: if r[P1]>0 then r[P1]-=P3, goto P2 */
    +-#define OP_SetIfNotPos   139 /* synopsis: if r[P1]<=0 then r[P2]=P3        */
    +-#define OP_IfNotZero     140 /* synopsis: if r[P1]!=0 then r[P1]-=P3, goto P2 */
    +-#define OP_DecrJumpZero  141 /* synopsis: if (--r[P1])==0 goto P2          */
    +-#define OP_JumpZeroIncr  142 /* synopsis: if (r[P1]++)==0 ) goto P2        */
    +-#define OP_AggStep0      143 /* synopsis: accum=r[P3] step(r[P2@P5])       */
    +-#define OP_AggStep       144 /* synopsis: accum=r[P3] step(r[P2@P5])       */
    +-#define OP_AggFinal      145 /* synopsis: accum=r[P1] N=P2                 */
    +-#define OP_IncrVacuum    146
    +-#define OP_Expire        147
    +-#define OP_TableLock     148 /* synopsis: iDb=P1 root=P2 write=P3          */
    +-#define OP_VBegin        149
    +-#define OP_VCreate       150
    +-#define OP_VDestroy      151
    +-#define OP_VOpen         152
    +-#define OP_VColumn       153 /* synopsis: r[P3]=vcolumn(P2)                */
    +-#define OP_VNext         154
    +-#define OP_VRename       155
    +-#define OP_Pagecount     156
    +-#define OP_MaxPgcnt      157
    +-#define OP_Init          158 /* synopsis: Start at P2                      */
    +-#define OP_Noop          159
    +-#define OP_Explain       160
    +-
    ++#define OP_Column         98 /* synopsis: r[P3]=PX                         */
    ++#define OP_Affinity       99 /* synopsis: affinity(r[P1@P2])               */
    ++#define OP_MakeRecord    100 /* synopsis: r[P3]=mkrec(r[P1@P2])            */
    ++#define OP_Count         101 /* synopsis: r[P2]=count()                    */
    ++#define OP_ReadCookie    102
    ++#define OP_SetCookie     103
    ++#define OP_ReopenIdx     104 /* synopsis: root=P2 iDb=P3                   */
    ++#define OP_OpenRead      105 /* synopsis: root=P2 iDb=P3                   */
    ++#define OP_OpenWrite     106 /* synopsis: root=P2 iDb=P3                   */
    ++#define OP_OpenDup       107
    ++#define OP_OpenAutoindex 108 /* synopsis: nColumn=P2                       */
    ++#define OP_OpenEphemeral 109 /* synopsis: nColumn=P2                       */
    ++#define OP_SorterOpen    110
    ++#define OP_SequenceTest  111 /* synopsis: if( cursor[P1].ctr++ ) pc = P2   */
    ++#define OP_OpenPseudo    112 /* synopsis: P3 columns in r[P2]              */
    ++#define OP_Close         113
    ++#define OP_ColumnsUsed   114
    ++#define OP_Sequence      115 /* synopsis: r[P2]=cursor[P1].ctr++           */
    ++#define OP_NewRowid      116 /* synopsis: r[P2]=rowid                      */
    ++#define OP_Insert        117 /* synopsis: intkey=r[P3] data=r[P2]          */
    ++#define OP_InsertInt     118 /* synopsis: intkey=P3 data=r[P2]             */
    ++#define OP_Delete        119
    ++#define OP_ResetCount    120
    ++#define OP_SorterCompare 121 /* synopsis: if key(P1)!=trim(r[P3],P4) goto P2 */
    ++#define OP_SorterData    122 /* synopsis: r[P2]=data                       */
    ++#define OP_RowData       123 /* synopsis: r[P2]=data                       */
    ++#define OP_Rowid         124 /* synopsis: r[P2]=rowid                      */
    ++#define OP_NullRow       125
    ++#define OP_SeekEnd       126
    ++#define OP_SorterInsert  127 /* synopsis: key=r[P2]                        */
    ++#define OP_IdxInsert     128 /* synopsis: key=r[P2]                        */
    ++#define OP_IdxDelete     129 /* synopsis: key=r[P2@P3]                     */
    ++#define OP_DeferredSeek  130 /* synopsis: Move P3 to P1.rowid if needed    */
    ++#define OP_IdxRowid      131 /* synopsis: r[P2]=rowid                      */
    ++#define OP_Real          132 /* same as TK_FLOAT, synopsis: r[P2]=P4       */
    ++#define OP_Destroy       133
    ++#define OP_Clear         134
    ++#define OP_ResetSorter   135
    ++#define OP_CreateBtree   136 /* synopsis: r[P2]=root iDb=P1 flags=P3       */
    ++#define OP_SqlExec       137
    ++#define OP_ParseSchema   138
    ++#define OP_LoadAnalysis  139
    ++#define OP_DropTable     140
    ++#define OP_DropIndex     141
    ++#define OP_DropTrigger   142
    ++#define OP_IntegrityCk   143
    ++#define OP_RowSetAdd     144 /* synopsis: rowset(P1)=r[P2]                 */
    ++#define OP_Param         145
    ++#define OP_FkCounter     146 /* synopsis: fkctr[P1]+=P2                    */
    ++#define OP_MemMax        147 /* synopsis: r[P1]=max(r[P1],r[P2])           */
    ++#define OP_OffsetLimit   148 /* synopsis: if r[P1]>0 then r[P2]=r[P1]+max(0,r[P3]) else r[P2]=(-1) */
    ++#define OP_AggStep0      149 /* synopsis: accum=r[P3] step(r[P2@P5])       */
    ++#define OP_AggStep       150 /* synopsis: accum=r[P3] step(r[P2@P5])       */
    ++#define OP_AggFinal      151 /* synopsis: accum=r[P1] N=P2                 */
    ++#define OP_Expire        152
    ++#define OP_TableLock     153 /* synopsis: iDb=P1 root=P2 write=P3          */
    ++#define OP_VBegin        154
    ++#define OP_VCreate       155
    ++#define OP_VDestroy      156
    ++#define OP_VOpen         157
    ++#define OP_VColumn       158 /* synopsis: r[P3]=vcolumn(P2)                */
    ++#define OP_VRename       159
    ++#define OP_Pagecount     160
    ++#define OP_MaxPgcnt      161
    ++#define OP_PureFunc0     162
    ++#define OP_Function0     163 /* synopsis: r[P3]=func(r[P2@P5])             */
    ++#define OP_PureFunc      164
    ++#define OP_Function      165 /* synopsis: r[P3]=func(r[P2@P5])             */
    ++#define OP_Trace         166
    ++#define OP_CursorHint    167
    ++#define OP_Noop          168
    ++#define OP_Explain       169
    + 
    + /* Properties such as "out2" or "jump" that are specified in
    + ** comments following the "case" for each opcode in the vdbe.c
    + ** are encoded into bitvectors as follows:
    + */
    +-#define OPFLG_JUMP            0x0001  /* jump:  P2 holds jmp target */
    +-#define OPFLG_IN1             0x0002  /* in1:   P1 is an input */
    +-#define OPFLG_IN2             0x0004  /* in2:   P2 is an input */
    +-#define OPFLG_IN3             0x0008  /* in3:   P3 is an input */
    +-#define OPFLG_OUT2            0x0010  /* out2:  P2 is an output */
    +-#define OPFLG_OUT3            0x0020  /* out3:  P3 is an output */
    ++#define OPFLG_JUMP        0x01  /* jump:  P2 holds jmp target */
    ++#define OPFLG_IN1         0x02  /* in1:   P1 is an input */
    ++#define OPFLG_IN2         0x04  /* in2:   P2 is an input */
    ++#define OPFLG_IN3         0x08  /* in3:   P3 is an input */
    ++#define OPFLG_OUT2        0x10  /* out2:  P2 is an output */
    ++#define OPFLG_OUT3        0x20  /* out3:  P3 is an output */
    + #define OPFLG_INITIALIZER {\
    +-/*   0 */ 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x01,\
    +-/*   8 */ 0x01, 0x00, 0x10, 0x00, 0x01, 0x00, 0x01, 0x01,\
    +-/*  16 */ 0x02, 0x01, 0x02, 0x12, 0x03, 0x08, 0x00, 0x10,\
    +-/*  24 */ 0x10, 0x10, 0x10, 0x00, 0x10, 0x10, 0x00, 0x00,\
    +-/*  32 */ 0x10, 0x00, 0x00, 0x00, 0x00, 0x02, 0x03, 0x02,\
    +-/*  40 */ 0x02, 0x00, 0x00, 0x01, 0x01, 0x03, 0x03, 0x00,\
    +-/*  48 */ 0x00, 0x00, 0x10, 0x10, 0x08, 0x00, 0x00, 0x00,\
    +-/*  56 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09,\
    +-/*  64 */ 0x09, 0x09, 0x09, 0x04, 0x09, 0x09, 0x09, 0x26,\
    +-/*  72 */ 0x26, 0x09, 0x10, 0x10, 0x03, 0x03, 0x0b, 0x0b,\
    +-/*  80 */ 0x0b, 0x0b, 0x0b, 0x0b, 0x00, 0x26, 0x26, 0x26,\
    +-/*  88 */ 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x00,\
    +-/*  96 */ 0x12, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\
    +-/* 104 */ 0x10, 0x00, 0x01, 0x01, 0x01, 0x01, 0x04, 0x04,\
    +-/* 112 */ 0x00, 0x10, 0x01, 0x01, 0x01, 0x01, 0x10, 0x00,\
    +-/* 120 */ 0x00, 0x10, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00,\
    +-/* 128 */ 0x00, 0x06, 0x23, 0x0b, 0x01, 0x10, 0x10, 0x00,\
    +-/* 136 */ 0x01, 0x04, 0x03, 0x06, 0x03, 0x03, 0x03, 0x00,\
    +-/* 144 */ 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,\
    +-/* 152 */ 0x00, 0x00, 0x01, 0x00, 0x10, 0x10, 0x01, 0x00,\
    +-/* 160 */ 0x00,}
    ++/*   0 */ 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x01, 0x01,\
    ++/*   8 */ 0x00, 0x10, 0x00, 0x01, 0x00, 0x01, 0x01, 0x01,\
    ++/*  16 */ 0x03, 0x03, 0x01, 0x12, 0x01, 0x03, 0x03, 0x01,\
    ++/*  24 */ 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09,\
    ++/*  32 */ 0x09, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,\
    ++/*  40 */ 0x01, 0x01, 0x23, 0x26, 0x26, 0x0b, 0x01, 0x01,\
    ++/*  48 */ 0x03, 0x03, 0x03, 0x03, 0x0b, 0x0b, 0x0b, 0x0b,\
    ++/*  56 */ 0x0b, 0x0b, 0x01, 0x03, 0x01, 0x01, 0x01, 0x02,\
    ++/*  64 */ 0x02, 0x08, 0x00, 0x10, 0x10, 0x10, 0x10, 0x00,\
    ++/*  72 */ 0x10, 0x10, 0x00, 0x00, 0x10, 0x10, 0x00, 0x00,\
    ++/*  80 */ 0x02, 0x02, 0x02, 0x00, 0x26, 0x26, 0x26, 0x26,\
    ++/*  88 */ 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x00, 0x12,\
    ++/*  96 */ 0x20, 0x10, 0x00, 0x00, 0x00, 0x10, 0x10, 0x00,\
    ++/* 104 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\
    ++/* 112 */ 0x00, 0x00, 0x00, 0x10, 0x10, 0x00, 0x00, 0x00,\
    ++/* 120 */ 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x04,\
    ++/* 128 */ 0x04, 0x00, 0x00, 0x10, 0x10, 0x10, 0x00, 0x00,\
    ++/* 136 */ 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\
    ++/* 144 */ 0x06, 0x10, 0x00, 0x04, 0x1a, 0x00, 0x00, 0x00,\
    ++/* 152 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\
    ++/* 160 */ 0x10, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\
    ++/* 168 */ 0x00, 0x00,}
    ++
    ++/* The sqlite3P2Values() routine is able to run faster if it knows
    ++** the value of the largest JUMP opcode.  The smaller the maximum
    ++** JUMP opcode the better, so the mkopcodeh.tcl script that
    ++** generated this include file strives to group all JUMP opcodes
    ++** together near the beginning of the list.
    ++*/
    ++#define SQLITE_MX_JUMP_OPCODE  62  /* Maximum JUMP opcode */
    + 
    + /************** End of opcodes.h *********************************************/
    + /************** Continuing where we left off in vdbe.h ***********************/
    + 
    ++/*
    ++** Additional non-public SQLITE_PREPARE_* flags
    ++*/
    ++#define SQLITE_PREPARE_SAVESQL  0x80  /* Preserve SQL text */
    ++#define SQLITE_PREPARE_MASK     0x0f  /* Mask of public flags */
    ++
    + /*
    + ** Prototypes for the VDBE interface.  See comments on the implementation
    + ** for a description of what each of these routines does.
    +@@ -10646,22 +14076,32 @@ SQLITE_PRIVATE int sqlite3VdbeAddOp3(Vdbe*,int,int,int,int);
    + SQLITE_PRIVATE int sqlite3VdbeAddOp4(Vdbe*,int,int,int,int,const char *zP4,int);
    + SQLITE_PRIVATE int sqlite3VdbeAddOp4Dup8(Vdbe*,int,int,int,int,const u8*,int);
    + SQLITE_PRIVATE int sqlite3VdbeAddOp4Int(Vdbe*,int,int,int,int,int);
    +-SQLITE_PRIVATE int sqlite3VdbeAddOpList(Vdbe*, int nOp, VdbeOpList const *aOp, int iLineno);
    ++SQLITE_PRIVATE void sqlite3VdbeEndCoroutine(Vdbe*,int);
    ++#if defined(SQLITE_DEBUG) && !defined(SQLITE_TEST_REALLOC_STRESS)
    ++SQLITE_PRIVATE   void sqlite3VdbeVerifyNoMallocRequired(Vdbe *p, int N);
    ++SQLITE_PRIVATE   void sqlite3VdbeVerifyNoResultRow(Vdbe *p);
    ++#else
    ++# define sqlite3VdbeVerifyNoMallocRequired(A,B)
    ++# define sqlite3VdbeVerifyNoResultRow(A)
    ++#endif
    ++SQLITE_PRIVATE VdbeOp *sqlite3VdbeAddOpList(Vdbe*, int nOp, VdbeOpList const *aOp, int iLineno);
    + SQLITE_PRIVATE void sqlite3VdbeAddParseSchemaOp(Vdbe*,int,char*);
    + SQLITE_PRIVATE void sqlite3VdbeChangeOpcode(Vdbe*, u32 addr, u8);
    + SQLITE_PRIVATE void sqlite3VdbeChangeP1(Vdbe*, u32 addr, int P1);
    + SQLITE_PRIVATE void sqlite3VdbeChangeP2(Vdbe*, u32 addr, int P2);
    + SQLITE_PRIVATE void sqlite3VdbeChangeP3(Vdbe*, u32 addr, int P3);
    +-SQLITE_PRIVATE void sqlite3VdbeChangeP5(Vdbe*, u8 P5);
    ++SQLITE_PRIVATE void sqlite3VdbeChangeP5(Vdbe*, u16 P5);
    + SQLITE_PRIVATE void sqlite3VdbeJumpHere(Vdbe*, int addr);
    +-SQLITE_PRIVATE void sqlite3VdbeChangeToNoop(Vdbe*, int addr);
    ++SQLITE_PRIVATE int sqlite3VdbeChangeToNoop(Vdbe*, int addr);
    + SQLITE_PRIVATE int sqlite3VdbeDeletePriorOpcode(Vdbe*, u8 op);
    + SQLITE_PRIVATE void sqlite3VdbeChangeP4(Vdbe*, int addr, const char *zP4, int N);
    ++SQLITE_PRIVATE void sqlite3VdbeAppendP4(Vdbe*, void *pP4, int p4type);
    + SQLITE_PRIVATE void sqlite3VdbeSetP4KeyInfo(Parse*, Index*);
    + SQLITE_PRIVATE void sqlite3VdbeUsesBtree(Vdbe*, int);
    + SQLITE_PRIVATE VdbeOp *sqlite3VdbeGetOp(Vdbe*, int);
    + SQLITE_PRIVATE int sqlite3VdbeMakeLabel(Vdbe*);
    + SQLITE_PRIVATE void sqlite3VdbeRunOnlyOnce(Vdbe*);
    ++SQLITE_PRIVATE void sqlite3VdbeReusable(Vdbe*);
    + SQLITE_PRIVATE void sqlite3VdbeDelete(Vdbe*);
    + SQLITE_PRIVATE void sqlite3VdbeClearObject(sqlite3*,Vdbe*);
    + SQLITE_PRIVATE void sqlite3VdbeMakeReady(Vdbe*,Parse*);
    +@@ -10678,7 +14118,8 @@ SQLITE_PRIVATE void sqlite3VdbeSetNumCols(Vdbe*,int);
    + SQLITE_PRIVATE int sqlite3VdbeSetColName(Vdbe*, int, int, const char *, void(*)(void*));
    + SQLITE_PRIVATE void sqlite3VdbeCountChanges(Vdbe*);
    + SQLITE_PRIVATE sqlite3 *sqlite3VdbeDb(Vdbe*);
    +-SQLITE_PRIVATE void sqlite3VdbeSetSql(Vdbe*, const char *z, int n, int);
    ++SQLITE_PRIVATE u8 sqlite3VdbePrepareFlags(Vdbe*);
    ++SQLITE_PRIVATE void sqlite3VdbeSetSql(Vdbe*, const char *z, int n, u8);
    + SQLITE_PRIVATE void sqlite3VdbeSwap(Vdbe*,Vdbe*);
    + SQLITE_PRIVATE VdbeOp *sqlite3VdbeTakeOpArray(Vdbe*, int*, int*);
    + SQLITE_PRIVATE sqlite3_value *sqlite3VdbeGetBoundValue(Vdbe*, int, u8);
    +@@ -10691,7 +14132,7 @@ 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*,UnpackedRecord*);
    + SQLITE_PRIVATE int sqlite3VdbeRecordCompareWithSkip(int, const void *, UnpackedRecord *, int);
    +-SQLITE_PRIVATE UnpackedRecord *sqlite3VdbeAllocUnpackedRecord(KeyInfo *, char *, int, char **);
    ++SQLITE_PRIVATE UnpackedRecord *sqlite3VdbeAllocUnpackedRecord(KeyInfo*);
    + 
    + typedef int (*RecordCompare)(int,const void*,UnpackedRecord*);
    + SQLITE_PRIVATE RecordCompare sqlite3VdbeFindCompare(UnpackedRecord*);
    +@@ -10700,6 +14141,8 @@ SQLITE_PRIVATE RecordCompare sqlite3VdbeFindCompare(UnpackedRecord*);
    + SQLITE_PRIVATE void sqlite3VdbeLinkSubProgram(Vdbe *, SubProgram *);
    + #endif
    + 
    ++SQLITE_PRIVATE int sqlite3NotPureFunc(sqlite3_context*);
    ++
    + /* Use SQLITE_ENABLE_COMMENTS to enable generation of extra comments on
    + ** each VDBE opcode.
    + **
    +@@ -10766,7 +14209,7 @@ SQLITE_PRIVATE void sqlite3VdbeScanStatus(Vdbe*, int, int, int, LogEst, const ch
    + # define sqlite3VdbeScanStatus(a,b,c,d,e)
    + #endif
    + 
    +-#endif
    ++#endif /* SQLITE_VDBE_H */
    + 
    + /************** End of vdbe.h ************************************************/
    + /************** Continuing where we left off in sqliteInt.h ******************/
    +@@ -10788,8 +14231,8 @@ SQLITE_PRIVATE void sqlite3VdbeScanStatus(Vdbe*, int, int, int, LogEst, const ch
    + ** at a time and provides a journal for rollback.
    + */
    + 
    +-#ifndef _PAGER_H_
    +-#define _PAGER_H_
    ++#ifndef SQLITE_PAGER_H
    ++#define SQLITE_PAGER_H
    + 
    + /*
    + ** Default maximum size for persistent journal files. A negative 
    +@@ -10842,7 +14285,11 @@ typedef struct PgHdr DbPage;
    + #define PAGER_LOCKINGMODE_EXCLUSIVE   1
    + 
    + /*
    +-** Numeric constants that encode the journalmode.  
    ++** Numeric constants that encode the journalmode.
    ++**
    ++** The numeric values encoded here (other than PAGER_JOURNALMODE_QUERY)
    ++** are exposed in the API via the "PRAGMA journal_mode" command and
    ++** therefore cannot be changed without a compatibility break.
    + */
    + #define PAGER_JOURNALMODE_QUERY     (-1)  /* Query the value of journalmode */
    + #define PAGER_JOURNALMODE_DELETE      0   /* Commit by deleting journal file */
    +@@ -10853,22 +14300,28 @@ typedef struct PgHdr DbPage;
    + #define PAGER_JOURNALMODE_WAL         5   /* Use write-ahead logging */
    + 
    + /*
    +-** Flags that make up the mask passed to sqlite3PagerAcquire().
    ++** Flags that make up the mask passed to sqlite3PagerGet().
    + */
    + #define PAGER_GET_NOCONTENT     0x01  /* Do not load data from disk */
    + #define PAGER_GET_READONLY      0x02  /* Read-only page is acceptable */
    + 
    + /*
    + ** Flags for sqlite3PagerSetFlags()
    ++**
    ++** Value constraints (enforced via assert()):
    ++**    PAGER_FULLFSYNC      == SQLITE_FullFSync
    ++**    PAGER_CKPT_FULLFSYNC == SQLITE_CkptFullFSync
    ++**    PAGER_CACHE_SPILL    == SQLITE_CacheSpill
    + */
    + #define PAGER_SYNCHRONOUS_OFF       0x01  /* PRAGMA synchronous=OFF */
    + #define PAGER_SYNCHRONOUS_NORMAL    0x02  /* PRAGMA synchronous=NORMAL */
    + #define PAGER_SYNCHRONOUS_FULL      0x03  /* PRAGMA synchronous=FULL */
    +-#define PAGER_SYNCHRONOUS_MASK      0x03  /* Mask for three values above */
    +-#define PAGER_FULLFSYNC             0x04  /* PRAGMA fullfsync=ON */
    +-#define PAGER_CKPT_FULLFSYNC        0x08  /* PRAGMA checkpoint_fullfsync=ON */
    +-#define PAGER_CACHESPILL            0x10  /* PRAGMA cache_spill=ON */
    +-#define PAGER_FLAGS_MASK            0x1c  /* All above except SYNCHRONOUS */
    ++#define PAGER_SYNCHRONOUS_EXTRA     0x04  /* PRAGMA synchronous=EXTRA */
    ++#define PAGER_SYNCHRONOUS_MASK      0x07  /* Mask for four values above */
    ++#define PAGER_FULLFSYNC             0x08  /* PRAGMA fullfsync=ON */
    ++#define PAGER_CKPT_FULLFSYNC        0x10  /* PRAGMA checkpoint_fullfsync=ON */
    ++#define PAGER_CACHESPILL            0x20  /* PRAGMA cache_spill=ON */
    ++#define PAGER_FLAGS_MASK            0x38  /* All above except SYNCHRONOUS */
    + 
    + /*
    + ** The remainder of this file contains the declarations of the functions
    +@@ -10886,7 +14339,7 @@ SQLITE_PRIVATE int sqlite3PagerOpen(
    +   int,
    +   void(*)(DbPage*)
    + );
    +-SQLITE_PRIVATE int sqlite3PagerClose(Pager *pPager);
    ++SQLITE_PRIVATE int sqlite3PagerClose(Pager *pPager, sqlite3*);
    + SQLITE_PRIVATE int sqlite3PagerReadFileheader(Pager*, int, unsigned char*);
    + 
    + /* Functions used to configure a Pager object. */
    +@@ -10897,6 +14350,7 @@ SQLITE_PRIVATE void sqlite3PagerAlignReserve(Pager*,Pager*);
    + #endif
    + SQLITE_PRIVATE int sqlite3PagerMaxPageCount(Pager*, int);
    + SQLITE_PRIVATE void sqlite3PagerSetCachesize(Pager*, int);
    ++SQLITE_PRIVATE int sqlite3PagerSetSpillsize(Pager*, int);
    + SQLITE_PRIVATE void sqlite3PagerSetMmapLimit(Pager *, sqlite3_int64);
    + SQLITE_PRIVATE void sqlite3PagerShrink(Pager*);
    + SQLITE_PRIVATE void sqlite3PagerSetFlags(Pager*,unsigned);
    +@@ -10906,14 +14360,15 @@ SQLITE_PRIVATE int sqlite3PagerGetJournalMode(Pager*);
    + SQLITE_PRIVATE int sqlite3PagerOkToChangeJournalMode(Pager*);
    + SQLITE_PRIVATE i64 sqlite3PagerJournalSizeLimit(Pager *, i64);
    + SQLITE_PRIVATE sqlite3_backup **sqlite3PagerBackupPtr(Pager*);
    ++SQLITE_PRIVATE int sqlite3PagerFlush(Pager*);
    + 
    + /* Functions used to obtain and release page references. */ 
    +-SQLITE_PRIVATE int sqlite3PagerAcquire(Pager *pPager, Pgno pgno, DbPage **ppPage, int clrFlag);
    +-#define sqlite3PagerGet(A,B,C) sqlite3PagerAcquire(A,B,C,0)
    ++SQLITE_PRIVATE int sqlite3PagerGet(Pager *pPager, Pgno pgno, DbPage **ppPage, int clrFlag);
    + SQLITE_PRIVATE DbPage *sqlite3PagerLookup(Pager *pPager, Pgno pgno);
    + SQLITE_PRIVATE void sqlite3PagerRef(DbPage*);
    + SQLITE_PRIVATE void sqlite3PagerUnref(DbPage*);
    + SQLITE_PRIVATE void sqlite3PagerUnrefNotNull(DbPage*);
    ++SQLITE_PRIVATE void sqlite3PagerUnrefPageOne(DbPage*);
    + 
    + /* Operations on page references. */
    + SQLITE_PRIVATE int sqlite3PagerWrite(DbPage*);
    +@@ -10936,11 +14391,21 @@ SQLITE_PRIVATE int sqlite3PagerSavepoint(Pager *pPager, int op, int iSavepoint);
    + SQLITE_PRIVATE int sqlite3PagerSharedLock(Pager *pPager);
    + 
    + #ifndef SQLITE_OMIT_WAL
    +-SQLITE_PRIVATE   int sqlite3PagerCheckpoint(Pager *pPager, int, int*, int*);
    ++SQLITE_PRIVATE   int sqlite3PagerCheckpoint(Pager *pPager, sqlite3*, int, int*, int*);
    + SQLITE_PRIVATE   int sqlite3PagerWalSupported(Pager *pPager);
    + SQLITE_PRIVATE   int sqlite3PagerWalCallback(Pager *pPager);
    + SQLITE_PRIVATE   int sqlite3PagerOpenWal(Pager *pPager, int *pisOpen);
    +-SQLITE_PRIVATE   int sqlite3PagerCloseWal(Pager *pPager);
    ++SQLITE_PRIVATE   int sqlite3PagerCloseWal(Pager *pPager, sqlite3*);
    ++# ifdef SQLITE_DIRECT_OVERFLOW_READ
    ++SQLITE_PRIVATE   int sqlite3PagerUseWal(Pager *pPager, Pgno);
    ++# endif
    ++# ifdef SQLITE_ENABLE_SNAPSHOT
    ++SQLITE_PRIVATE   int sqlite3PagerSnapshotGet(Pager *pPager, sqlite3_snapshot **ppSnapshot);
    ++SQLITE_PRIVATE   int sqlite3PagerSnapshotOpen(Pager *pPager, sqlite3_snapshot *pSnapshot);
    ++SQLITE_PRIVATE   int sqlite3PagerSnapshotRecover(Pager *pPager);
    ++# endif
    ++#else
    ++# define sqlite3PagerUseWal(x,y) 0
    + #endif
    + 
    + #ifdef SQLITE_ENABLE_ZIPVFS
    +@@ -10955,14 +14420,14 @@ SQLITE_PRIVATE   int sqlite3PagerRefcount(Pager*);
    + #endif
    + SQLITE_PRIVATE int sqlite3PagerMemUsed(Pager*);
    + SQLITE_PRIVATE const char *sqlite3PagerFilename(Pager*, int);
    +-SQLITE_PRIVATE const sqlite3_vfs *sqlite3PagerVfs(Pager*);
    ++SQLITE_PRIVATE sqlite3_vfs *sqlite3PagerVfs(Pager*);
    + SQLITE_PRIVATE sqlite3_file *sqlite3PagerFile(Pager*);
    ++SQLITE_PRIVATE sqlite3_file *sqlite3PagerJrnlFile(Pager*);
    + SQLITE_PRIVATE const char *sqlite3PagerJournalname(Pager*);
    +-SQLITE_PRIVATE int sqlite3PagerNosync(Pager*);
    + SQLITE_PRIVATE void *sqlite3PagerTempSpace(Pager*);
    + SQLITE_PRIVATE int sqlite3PagerIsMemdb(Pager*);
    + SQLITE_PRIVATE void sqlite3PagerCacheStat(Pager *, int, int, int *);
    +-SQLITE_PRIVATE void sqlite3PagerClearCache(Pager *);
    ++SQLITE_PRIVATE void sqlite3PagerClearCache(Pager*);
    + SQLITE_PRIVATE int sqlite3SectorSize(sqlite3_file *);
    + 
    + /* Functions used to truncate the database file. */
    +@@ -10989,7 +14454,7 @@ SQLITE_PRIVATE   void sqlite3PagerRefdump(Pager*);
    + # define enable_simulated_io_errors()
    + #endif
    + 
    +-#endif /* _PAGER_H_ */
    ++#endif /* SQLITE_PAGER_H */
    + 
    + /************** End of pager.h ***********************************************/
    + /************** Continuing where we left off in sqliteInt.h ******************/
    +@@ -11023,7 +14488,8 @@ struct PgHdr {
    +   sqlite3_pcache_page *pPage;    /* Pcache object page handle */
    +   void *pData;                   /* Page data */
    +   void *pExtra;                  /* Extra content */
    +-  PgHdr *pDirty;                 /* Transient list of dirty pages */
    ++  PCache *pCache;                /* PRIVATE: Cache that owns this page */
    ++  PgHdr *pDirty;                 /* Transient list of dirty sorted by pgno */
    +   Pager *pPager;                 /* The pager this page is part of */
    +   Pgno pgno;                     /* Page number for this page */
    + #ifdef SQLITE_CHECK_PAGES
    +@@ -11032,14 +14498,15 @@ struct PgHdr {
    +   u16 flags;                     /* PGHDR flags defined below */
    + 
    +   /**********************************************************************
    +-  ** Elements above are public.  All that follows is private to pcache.c
    +-  ** and should not be accessed by other modules.
    ++  ** Elements above, except pCache, are public.  All that follow are 
    ++  ** private to pcache.c and should not be accessed by other modules.
    ++  ** pCache is grouped with the public elements for efficiency.
    +   */
    +   i16 nRef;                      /* Number of users of this page */
    +-  PCache *pCache;                /* Cache that owns this page */
    +-
    +   PgHdr *pDirtyNext;             /* Next element in list of dirty pages */
    +   PgHdr *pDirtyPrev;             /* Previous element in list of dirty pages */
    ++                          /* NB: pDirtyNext and pDirtyPrev are undefined if the
    ++                          ** PgHdr object is not dirty */
    + };
    + 
    + /* Bit values for PgHdr.flags */
    +@@ -11048,9 +14515,10 @@ struct PgHdr {
    + #define PGHDR_WRITEABLE       0x004  /* Journaled and ready to modify */
    + #define PGHDR_NEED_SYNC       0x008  /* Fsync the rollback journal before
    +                                      ** writing this page to the database */
    +-#define PGHDR_NEED_READ       0x010  /* Content is unread */
    +-#define PGHDR_DONT_WRITE      0x020  /* Do not write content to disk */
    +-#define PGHDR_MMAP            0x040  /* This is an mmap page object */
    ++#define PGHDR_DONT_WRITE      0x010  /* Do not write content to disk */
    ++#define PGHDR_MMAP            0x020  /* This is an mmap page object */
    ++
    ++#define PGHDR_WAL_APPEND      0x040  /* Appended to wal file */
    + 
    + /* Initialize and shutdown the page cache subsystem */
    + SQLITE_PRIVATE int sqlite3PcacheInitialize(void);
    +@@ -11094,6 +14562,7 @@ SQLITE_PRIVATE void sqlite3PcacheDrop(PgHdr*);         /* Remove page from cache
    + SQLITE_PRIVATE void sqlite3PcacheMakeDirty(PgHdr*);    /* Make sure page is marked dirty */
    + SQLITE_PRIVATE void sqlite3PcacheMakeClean(PgHdr*);    /* Mark a single page as clean */
    + SQLITE_PRIVATE void sqlite3PcacheCleanAll(PCache*);    /* Mark all dirty list pages as clean */
    ++SQLITE_PRIVATE void sqlite3PcacheClearWritable(PCache*);
    + 
    + /* Change a page number.  Used by incr-vacuum. */
    + SQLITE_PRIVATE void sqlite3PcacheMove(PgHdr*, Pgno);
    +@@ -11132,6 +14601,11 @@ SQLITE_PRIVATE int sqlite3PcachePagecount(PCache*);
    + SQLITE_PRIVATE void sqlite3PcacheIterateDirty(PCache *pCache, void (*xIter)(PgHdr *));
    + #endif
    + 
    ++#if defined(SQLITE_DEBUG)
    ++/* Check invariants on a PgHdr object */
    ++SQLITE_PRIVATE int sqlite3PcachePageSanity(PgHdr*);
    ++#endif
    ++
    + /* Set and get the suggested cache-size for the specified pager-cache.
    + **
    + ** If no global maximum is configured, then the system attempts to limit
    +@@ -11143,6 +14617,13 @@ SQLITE_PRIVATE void sqlite3PcacheSetCachesize(PCache *, int);
    + SQLITE_PRIVATE int sqlite3PcacheGetCachesize(PCache *);
    + #endif
    + 
    ++/* Set or get the suggested spill-size for the specified pager-cache.
    ++**
    ++** The spill-size is the minimum number of pages in cache before the cache
    ++** will attempt to spill dirty pages by calling xStress.
    ++*/
    ++SQLITE_PRIVATE int sqlite3PcacheSetSpillsize(PCache *, int);
    ++
    + /* Free up as much memory as possible from the page cache */
    + SQLITE_PRIVATE void sqlite3PcacheShrink(PCache*);
    + 
    +@@ -11161,11 +14642,13 @@ SQLITE_PRIVATE void sqlite3PCacheSetDefault(void);
    + SQLITE_PRIVATE int sqlite3HeaderSizePcache(void);
    + SQLITE_PRIVATE int sqlite3HeaderSizePcache1(void);
    + 
    ++/* Number of dirty pages as a percentage of the configured cache size */
    ++SQLITE_PRIVATE int sqlite3PCachePercentDirty(PCache*);
    ++
    + #endif /* _PCACHE_H_ */
    + 
    + /************** End of pcache.h **********************************************/
    + /************** Continuing where we left off in sqliteInt.h ******************/
    +-
    + /************** Include os.h in the middle of sqliteInt.h ********************/
    + /************** Begin file os.h **********************************************/
    + /*
    +@@ -11211,8 +14694,8 @@ SQLITE_PRIVATE int sqlite3HeaderSizePcache1(void);
    + ** This file contains pre-processor directives related to operating system
    + ** detection and/or setup.
    + */
    +-#ifndef _OS_SETUP_H_
    +-#define _OS_SETUP_H_
    ++#ifndef SQLITE_OS_SETUP_H
    ++#define SQLITE_OS_SETUP_H
    + 
    + /*
    + ** Figure out if we are dealing with Unix, Windows, or some other operating
    +@@ -11252,7 +14735,7 @@ SQLITE_PRIVATE int sqlite3HeaderSizePcache1(void);
    + #  endif
    + #endif
    + 
    +-#endif /* _OS_SETUP_H_ */
    ++#endif /* SQLITE_OS_SETUP_H */
    + 
    + /************** End of os_setup.h ********************************************/
    + /************** Continuing where we left off in os.h *************************/
    +@@ -11391,7 +14874,7 @@ SQLITE_PRIVATE int sqlite3OsInit(void);
    + /* 
    + ** Functions for accessing sqlite3_file methods 
    + */
    +-SQLITE_PRIVATE int sqlite3OsClose(sqlite3_file*);
    ++SQLITE_PRIVATE void sqlite3OsClose(sqlite3_file*);
    + SQLITE_PRIVATE int sqlite3OsRead(sqlite3_file*, void*, int amt, i64 offset);
    + SQLITE_PRIVATE int sqlite3OsWrite(sqlite3_file*, const void*, int amt, i64 offset);
    + SQLITE_PRIVATE int sqlite3OsTruncate(sqlite3_file*, i64 size);
    +@@ -11405,10 +14888,12 @@ SQLITE_PRIVATE void sqlite3OsFileControlHint(sqlite3_file*,int,void*);
    + #define SQLITE_FCNTL_DB_UNCHANGED 0xca093fa0
    + SQLITE_PRIVATE int sqlite3OsSectorSize(sqlite3_file *id);
    + SQLITE_PRIVATE int sqlite3OsDeviceCharacteristics(sqlite3_file *id);
    ++#ifndef SQLITE_OMIT_WAL
    + SQLITE_PRIVATE int sqlite3OsShmMap(sqlite3_file *,int,int,int,void volatile **);
    + SQLITE_PRIVATE int sqlite3OsShmLock(sqlite3_file *id, int, int, int);
    + SQLITE_PRIVATE void sqlite3OsShmBarrier(sqlite3_file *id);
    + SQLITE_PRIVATE int sqlite3OsShmUnmap(sqlite3_file *id, int);
    ++#endif /* SQLITE_OMIT_WAL */
    + SQLITE_PRIVATE int sqlite3OsFetch(sqlite3_file *id, i64, int, void **);
    + SQLITE_PRIVATE int sqlite3OsUnfetch(sqlite3_file *, i64, void *);
    + 
    +@@ -11428,6 +14913,7 @@ SQLITE_PRIVATE void sqlite3OsDlClose(sqlite3_vfs *, void *);
    + #endif /* SQLITE_OMIT_LOAD_EXTENSION */
    + SQLITE_PRIVATE int sqlite3OsRandomness(sqlite3_vfs *, int, char *);
    + SQLITE_PRIVATE int sqlite3OsSleep(sqlite3_vfs *, int);
    ++SQLITE_PRIVATE int sqlite3OsGetLastError(sqlite3_vfs*);
    + SQLITE_PRIVATE int sqlite3OsCurrentTimeInt64(sqlite3_vfs *, sqlite3_int64*);
    + 
    + /*
    +@@ -11435,7 +14921,7 @@ SQLITE_PRIVATE int sqlite3OsCurrentTimeInt64(sqlite3_vfs *, sqlite3_int64*);
    + ** sqlite3_malloc() to obtain space for the file-handle structure.
    + */
    + SQLITE_PRIVATE int sqlite3OsOpenMalloc(sqlite3_vfs *, const char *, sqlite3_file **, int,int*);
    +-SQLITE_PRIVATE int sqlite3OsCloseFree(sqlite3_file *);
    ++SQLITE_PRIVATE void sqlite3OsCloseFree(sqlite3_file *);
    + 
    + #endif /* _SQLITE_OS_H_ */
    + 
    +@@ -11517,6 +15003,36 @@ SQLITE_PRIVATE int sqlite3OsCloseFree(sqlite3_file *);
    + /************** End of mutex.h ***********************************************/
    + /************** Continuing where we left off in sqliteInt.h ******************/
    + 
    ++/* The SQLITE_EXTRA_DURABLE compile-time option used to set the default
    ++** synchronous setting to EXTRA.  It is no longer supported.
    ++*/
    ++#ifdef SQLITE_EXTRA_DURABLE
    ++# warning Use SQLITE_DEFAULT_SYNCHRONOUS=3 instead of SQLITE_EXTRA_DURABLE
    ++# define SQLITE_DEFAULT_SYNCHRONOUS 3
    ++#endif
    ++
    ++/*
    ++** Default synchronous levels.
    ++**
    ++** Note that (for historcal reasons) the PAGER_SYNCHRONOUS_* macros differ
    ++** from the SQLITE_DEFAULT_SYNCHRONOUS value by 1.
    ++**
    ++**           PAGER_SYNCHRONOUS       DEFAULT_SYNCHRONOUS
    ++**   OFF           1                         0
    ++**   NORMAL        2                         1
    ++**   FULL          3                         2
    ++**   EXTRA         4                         3
    ++**
    ++** The "PRAGMA synchronous" statement also uses the zero-based numbers.
    ++** In other words, the zero-based numbers are used for all external interfaces
    ++** and the one-based values are used internally.
    ++*/
    ++#ifndef SQLITE_DEFAULT_SYNCHRONOUS
    ++# define SQLITE_DEFAULT_SYNCHRONOUS 2
    ++#endif
    ++#ifndef SQLITE_DEFAULT_WAL_SYNCHRONOUS
    ++# define SQLITE_DEFAULT_WAL_SYNCHRONOUS SQLITE_DEFAULT_SYNCHRONOUS
    ++#endif
    + 
    + /*
    + ** Each database file to be accessed by the system is an instance
    +@@ -11526,9 +15042,10 @@ SQLITE_PRIVATE int sqlite3OsCloseFree(sqlite3_file *);
    + ** databases may be attached.
    + */
    + struct Db {
    +-  char *zName;         /* Name of this database */
    ++  char *zDbSName;      /* Name of this database. (schema name, not filename) */
    +   Btree *pBt;          /* The B*Tree structure for this database file */
    +   u8 safety_level;     /* How aggressive at syncing data to disk */
    ++  u8 bSyncSet;         /* True if "PRAGMA synchronous=N" has been run */
    +   Schema *pSchema;     /* Pointer to database schema (possibly shared) */
    + };
    + 
    +@@ -11539,7 +15056,7 @@ struct Db {
    + ** the Schema for the TEMP databaes (sqlite3.aDb[1]) which is free-standing.
    + ** In shared cache mode, a single Schema object can be shared by multiple
    + ** Btrees that refer to the same underlying BtShared object.
    +-** 
    ++**
    + ** Schema objects are automatically deallocated when the last Btree that
    + ** references them is destroyed.   The TEMP Schema is manually freed by
    + ** sqlite3_close().
    +@@ -11564,7 +15081,7 @@ struct Schema {
    + };
    + 
    + /*
    +-** These macros can be used to test, set, or clear bits in the 
    ++** 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->schemaFlags&(P))==(P))
    +@@ -11585,6 +15102,7 @@ struct Schema {
    + #define DB_SchemaLoaded    0x0001  /* The schema has been loaded */
    + #define DB_UnresetViews    0x0002  /* Some views have defined column names */
    + #define DB_Empty           0x0004  /* The file is empty (length 0 bytes) */
    ++#define DB_ResetWanted     0x0008  /* Reset the schema when nSchemaLock==0 */
    + 
    + /*
    + ** The number of different kinds of things that can be limited
    +@@ -11613,12 +15131,12 @@ struct Schema {
    + ** lookaside allocations are not used to construct the schema objects.
    + */
    + struct Lookaside {
    ++  u32 bDisable;           /* Only operate the lookaside when zero */
    +   u16 sz;                 /* Size of each buffer in bytes */
    +-  u8 bEnabled;            /* False to disable new lookaside allocations */
    +   u8 bMalloced;           /* True if pStart obtained from sqlite3_malloc() */
    +-  int nOut;               /* Number of buffers currently checked out */
    +-  int mxOut;              /* Highwater mark for nOut */
    +-  int anStat[3];          /* 0: hits.  1: size misses.  2: full misses */
    ++  u32 nSlot;              /* Number of lookaside slots allocated */
    ++  u32 anStat[3];          /* 0: hits.  1: size misses.  2: full misses */
    ++  LookasideSlot *pInit;   /* List of buffers not previously used */
    +   LookasideSlot *pFree;   /* List of available buffers */
    +   void *pStart;           /* First byte of available memory space */
    +   void *pEnd;             /* First byte past end of available space */
    +@@ -11628,13 +15146,15 @@ struct LookasideSlot {
    + };
    + 
    + /*
    +-** A hash table for function definitions.
    ++** A hash table for built-in function definitions.  (Application-defined
    ++** functions use a regular table table from hash.h.)
    + **
    + ** Hash each FuncDef structure into one of the FuncDefHash.a[] slots.
    +-** Collisions are on the FuncDef.pHash chain.
    ++** Collisions are on the FuncDef.u.pHash chain.
    + */
    ++#define SQLITE_FUNC_HASH_SZ 23
    + struct FuncDefHash {
    +-  FuncDef *a[23];       /* Hash table for functions */
    ++  FuncDef *a[SQLITE_FUNC_HASH_SZ];       /* Hash table for functions */
    + };
    + 
    + #ifdef SQLITE_USER_AUTHENTICATION
    +@@ -11675,6 +15195,15 @@ SQLITE_PRIVATE void sqlite3CryptFunc(sqlite3_context*,int,sqlite3_value**);
    +                                const char*);
    + #endif
    + 
    ++#ifndef SQLITE_OMIT_DEPRECATED
    ++/* This is an extra SQLITE_TRACE macro that indicates "legacy" tracing
    ++** in the style of sqlite3_trace()
    ++*/
    ++#define SQLITE_TRACE_LEGACY  0x80
    ++#else
    ++#define SQLITE_TRACE_LEGACY  0
    ++#endif /* SQLITE_OMIT_DEPRECATED */
    ++
    + 
    + /*
    + ** Each database connection is an instance of the following structure.
    +@@ -11686,22 +15215,29 @@ struct sqlite3 {
    +   sqlite3_mutex *mutex;         /* Connection mutex */
    +   Db *aDb;                      /* All backends */
    +   int nDb;                      /* Number of backends currently in use */
    +-  int flags;                    /* Miscellaneous flags. See below */
    ++  u32 mDbFlags;                 /* flags recording internal state */
    ++  u32 flags;                    /* flags settable by pragmas. See below */
    +   i64 lastRowid;                /* ROWID of most recent insert (see above) */
    +   i64 szMmap;                   /* Default mmap_size setting */
    ++  u32 nSchemaLock;              /* Do not reset the schema when non-zero */
    +   unsigned int openFlags;       /* Flags passed to sqlite3_vfs.xOpen() */
    +   int errCode;                  /* Most recent error code (SQLITE_*) */
    +   int errMask;                  /* & result codes with this before returning */
    ++  int iSysErrno;                /* Errno value from last system error */
    +   u16 dbOptFlags;               /* Flags to enable/disable optimizations */
    +   u8 enc;                       /* Text encoding */
    +   u8 autoCommit;                /* The auto-commit flag. */
    +   u8 temp_store;                /* 1: file 2: memory 0: default */
    +   u8 mallocFailed;              /* True if we have seen a malloc failure */
    ++  u8 bBenignMalloc;             /* Do not require OOMs if true */
    +   u8 dfltLockMode;              /* Default locking-mode for attached dbs */
    +   signed char nextAutovac;      /* Autovac setting after VACUUM if >=0 */
    +   u8 suppressErr;               /* Do not issue error messages if true */
    +   u8 vtabOnConflict;            /* Value to return for s3_vtab_on_conflict() */
    +   u8 isTransactionSavepoint;    /* True if the outermost savepoint is a TS */
    ++  u8 mTrace;                    /* zero or more SQLITE_TRACE flags */
    ++  u8 skipBtreeMutex;            /* True if no shared-cache backends */
    ++  u8 nSqlExec;                  /* Number of pending OP_SqlExec opcodes */
    +   int nextPagesize;             /* Pagesize after VACUUM if >0 */
    +   u32 magic;                    /* Magic number for detect library misuse */
    +   int nChange;                  /* Value returned by sqlite3_changes() */
    +@@ -11722,16 +15258,23 @@ struct sqlite3 {
    +   int nVDestroy;                /* Number of active OP_VDestroy operations */
    +   int nExtension;               /* Number of loaded extensions */
    +   void **aExtension;            /* Array of shared library handles */
    +-  void (*xTrace)(void*,const char*);        /* Trace function */
    ++  int (*xTrace)(u32,void*,void*,void*);     /* Trace function */
    +   void *pTraceArg;                          /* Argument to the trace function */
    +   void (*xProfile)(void*,const char*,u64);  /* Profiling function */
    +   void *pProfileArg;                        /* Argument to profile function */
    +-  void *pCommitArg;                 /* Argument to xCommitCallback() */   
    ++  void *pCommitArg;                 /* Argument to xCommitCallback() */
    +   int (*xCommitCallback)(void*);    /* Invoked at every commit. */
    +-  void *pRollbackArg;               /* Argument to xRollbackCallback() */   
    ++  void *pRollbackArg;               /* Argument to xRollbackCallback() */
    +   void (*xRollbackCallback)(void*); /* Invoked at every commit. */
    +   void *pUpdateArg;
    +   void (*xUpdateCallback)(void*,int, const char*,const char*,sqlite_int64);
    ++#ifdef SQLITE_ENABLE_PREUPDATE_HOOK
    ++  void *pPreUpdateArg;          /* First argument to xPreUpdateCallback */
    ++  void (*xPreUpdateCallback)(   /* Registered using sqlite3_preupdate_hook() */
    ++    void*,sqlite3*,int,char const*,char const*,sqlite3_int64,sqlite3_int64
    ++  );
    ++  PreUpdate *pPreUpdate;        /* Context for active pre-update callback */
    ++#endif /* SQLITE_ENABLE_PREUPDATE_HOOK */
    + #ifndef SQLITE_OMIT_WAL
    +   int (*xWalCallback)(void *, sqlite3 *, const char *, int);
    +   void *pWalArg;
    +@@ -11759,9 +15302,9 @@ struct sqlite3 {
    +   Hash aModule;                 /* populated by sqlite3_create_module() */
    +   VtabCtx *pVtabCtx;            /* Context for active vtab connect/create */
    +   VTable **aVTrans;             /* Virtual tables with open transactions */
    +-  VTable *pDisconnect;    /* Disconnect these in next sqlite3_prepare() */
    ++  VTable *pDisconnect;          /* Disconnect these in next sqlite3_prepare() */
    + #endif
    +-  FuncDefHash aFunc;            /* Hash table of connection functions */
    ++  Hash aFunc;                   /* Hash table of connection functions */
    +   Hash aCollSeq;                /* All collating sequences */
    +   BusyHandler busyHandler;      /* Busy callback */
    +   Db aDbStatic[2];              /* Static space for the 2 default backends */
    +@@ -11773,8 +15316,8 @@ struct sqlite3 {
    +   i64 nDeferredImmCons;         /* Net deferred immediate constraints */
    +   int *pnBytesFreed;            /* If not NULL, increment this in DbFree() */
    + #ifdef SQLITE_ENABLE_UNLOCK_NOTIFY
    +-  /* The following variables are all protected by the STATIC_MASTER 
    +-  ** mutex, not by sqlite3.mutex. They are used by code in notify.c. 
    ++  /* The following variables are all protected by the STATIC_MASTER
    ++  ** mutex, not by sqlite3.mutex. They are used by code in notify.c.
    +   **
    +   ** When X.pUnlockConnection==Y, that means that X is waiting for Y to
    +   ** unlock so that it can proceed.
    +@@ -11802,40 +15345,56 @@ struct sqlite3 {
    + 
    + /*
    + ** Possible values for the sqlite3.flags.
    +-*/
    +-#define SQLITE_VdbeTrace      0x00000001  /* True to trace VDBE execution */
    +-#define SQLITE_InternChanges  0x00000002  /* Uncommitted Hash table changes */
    +-#define SQLITE_FullFSync      0x00000004  /* Use full fsync on the backend */
    +-#define SQLITE_CkptFullFSync  0x00000008  /* Use full fsync for checkpoint */
    +-#define SQLITE_CacheSpill     0x00000010  /* OK to spill pager cache */
    +-#define SQLITE_FullColNames   0x00000020  /* Show full column names on SELECT */
    ++**
    ++** Value constraints (enforced via assert()):
    ++**      SQLITE_FullFSync     == PAGER_FULLFSYNC
    ++**      SQLITE_CkptFullFSync == PAGER_CKPT_FULLFSYNC
    ++**      SQLITE_CacheSpill    == PAGER_CACHE_SPILL
    ++*/
    ++#define SQLITE_WriteSchema    0x00000001  /* OK to update SQLITE_MASTER */
    ++#define SQLITE_LegacyFileFmt  0x00000002  /* Create new databases in format 1 */
    ++#define SQLITE_FullColNames   0x00000004  /* Show full column names on SELECT */
    ++#define SQLITE_FullFSync      0x00000008  /* Use full fsync on the backend */
    ++#define SQLITE_CkptFullFSync  0x00000010  /* Use full fsync for checkpoint */
    ++#define SQLITE_CacheSpill     0x00000020  /* OK to spill pager cache */
    + #define SQLITE_ShortColNames  0x00000040  /* Show short columns names */
    + #define SQLITE_CountRows      0x00000080  /* Count rows changed by INSERT, */
    +                                           /*   DELETE, or UPDATE and return */
    +                                           /*   the count using a callback. */
    + #define SQLITE_NullCallback   0x00000100  /* Invoke the callback once if the */
    +                                           /*   result set is empty */
    +-#define SQLITE_SqlTrace       0x00000200  /* Debug print SQL as it executes */
    +-#define SQLITE_VdbeListing    0x00000400  /* Debug listings of VDBE programs */
    +-#define SQLITE_WriteSchema    0x00000800  /* OK to update SQLITE_MASTER */
    +-#define SQLITE_VdbeAddopTrace 0x00001000  /* Trace sqlite3VdbeAddOp() calls */
    +-#define SQLITE_IgnoreChecks   0x00002000  /* Do not enforce check constraints */
    +-#define SQLITE_ReadUncommitted 0x0004000  /* For shared-cache mode */
    +-#define SQLITE_LegacyFileFmt  0x00008000  /* Create new databases in format 1 */
    +-#define SQLITE_RecoveryMode   0x00010000  /* Ignore schema errors */
    +-#define SQLITE_ReverseOrder   0x00020000  /* Reverse unordered SELECTs */
    +-#define SQLITE_RecTriggers    0x00040000  /* Enable recursive triggers */
    +-#define SQLITE_ForeignKeys    0x00080000  /* Enforce foreign key constraints  */
    +-#define SQLITE_AutoIndex      0x00100000  /* Enable automatic indexes */
    +-#define SQLITE_PreferBuiltin  0x00200000  /* Preference to built-in funcs */
    +-#define SQLITE_LoadExtension  0x00400000  /* Enable load_extension */
    +-#define SQLITE_EnableTrigger  0x00800000  /* True to enable triggers */
    +-#define SQLITE_DeferFKs       0x01000000  /* Defer all FK constraints */
    +-#define SQLITE_QueryOnly      0x02000000  /* Disable database changes */
    +-#define SQLITE_VdbeEQP        0x04000000  /* Debug EXPLAIN QUERY PLAN */
    +-#define SQLITE_Vacuum         0x08000000  /* Currently in a VACUUM */
    +-#define SQLITE_CellSizeCk     0x10000000  /* Check btree cell sizes on load */
    ++#define SQLITE_IgnoreChecks   0x00000200  /* Do not enforce check constraints */
    ++#define SQLITE_ReadUncommit   0x00000400  /* READ UNCOMMITTED in shared-cache */
    ++#define SQLITE_NoCkptOnClose  0x00000800  /* No checkpoint on close()/DETACH */
    ++#define SQLITE_ReverseOrder   0x00001000  /* Reverse unordered SELECTs */
    ++#define SQLITE_RecTriggers    0x00002000  /* Enable recursive triggers */
    ++#define SQLITE_ForeignKeys    0x00004000  /* Enforce foreign key constraints  */
    ++#define SQLITE_AutoIndex      0x00008000  /* Enable automatic indexes */
    ++#define SQLITE_LoadExtension  0x00010000  /* Enable load_extension */
    ++#define SQLITE_LoadExtFunc    0x00020000  /* Enable load_extension() SQL func */
    ++#define SQLITE_EnableTrigger  0x00040000  /* True to enable triggers */
    ++#define SQLITE_DeferFKs       0x00080000  /* Defer all FK constraints */
    ++#define SQLITE_QueryOnly      0x00100000  /* Disable database changes */
    ++#define SQLITE_CellSizeCk     0x00200000  /* Check btree cell sizes on load */
    ++#define SQLITE_Fts3Tokenizer  0x00400000  /* Enable fts3_tokenizer(2) */
    ++#define SQLITE_EnableQPSG     0x00800000  /* Query Planner Stability Guarantee*/
    ++#define SQLITE_TriggerEQP     0x01000000  /* Show trigger EXPLAIN QUERY PLAN */
    ++
    ++/* Flags used only if debugging */
    ++#ifdef SQLITE_DEBUG
    ++#define SQLITE_SqlTrace       0x08000000  /* Debug print SQL as it executes */
    ++#define SQLITE_VdbeListing    0x10000000  /* Debug listings of VDBE programs */
    ++#define SQLITE_VdbeTrace      0x20000000  /* True to trace VDBE execution */
    ++#define SQLITE_VdbeAddopTrace 0x40000000  /* Trace sqlite3VdbeAddOp() calls */
    ++#define SQLITE_VdbeEQP        0x80000000  /* Debug EXPLAIN QUERY PLAN */
    ++#endif
    + 
    ++/*
    ++** Allowed values for sqlite3.mDbFlags
    ++*/
    ++#define DBFLAG_SchemaChange   0x0001  /* Uncommitted Hash table changes */
    ++#define DBFLAG_PreferBuiltin  0x0002  /* Preference to built-in funcs */
    ++#define DBFLAG_Vacuum         0x0004  /* Currently in a VACUUM */
    + 
    + /*
    + ** Bits of the sqlite3.dbOptFlags field that are used by the
    +@@ -11846,26 +15405,22 @@ struct sqlite3 {
    + #define SQLITE_ColumnCache    0x0002   /* Column cache */
    + #define SQLITE_GroupByOrder   0x0004   /* GROUPBY cover of ORDERBY */
    + #define SQLITE_FactorOutConst 0x0008   /* Constant factoring */
    +-/*                not used    0x0010   // Was: SQLITE_IdxRealAsInt */
    +-#define SQLITE_DistinctOpt    0x0020   /* DISTINCT using indexes */
    +-#define SQLITE_CoverIdxScan   0x0040   /* Covering index scans */
    +-#define SQLITE_OrderByIdxJoin 0x0080   /* ORDER BY of joins via index */
    +-#define SQLITE_SubqCoroutine  0x0100   /* Evaluate subqueries as coroutines */
    +-#define SQLITE_Transitive     0x0200   /* Transitive constraints */
    +-#define SQLITE_OmitNoopJoin   0x0400   /* Omit unused tables in joins */
    ++#define SQLITE_DistinctOpt    0x0010   /* DISTINCT using indexes */
    ++#define SQLITE_CoverIdxScan   0x0020   /* Covering index scans */
    ++#define SQLITE_OrderByIdxJoin 0x0040   /* ORDER BY of joins via index */
    ++#define SQLITE_Transitive     0x0080   /* Transitive constraints */
    ++#define SQLITE_OmitNoopJoin   0x0100   /* Omit unused tables in joins */
    ++#define SQLITE_CountOfView    0x0200   /* The count-of-view optimization */
    ++#define SQLITE_CursorHints    0x0400   /* Add OP_CursorHint opcodes */
    + #define SQLITE_Stat34         0x0800   /* Use STAT3 or STAT4 data */
    ++   /* TH3 expects the Stat34  ^^^^^^ value to be 0x0800.  Don't change it */
    + #define SQLITE_AllOpts        0xffff   /* All optimizations */
    + 
    + /*
    + ** Macros for testing whether or not optimizations are enabled or disabled.
    + */
    +-#ifndef SQLITE_OMIT_BUILTIN_TEST
    + #define OptimizationDisabled(db, mask)  (((db)->dbOptFlags&(mask))!=0)
    + #define OptimizationEnabled(db, mask)   (((db)->dbOptFlags&(mask))==0)
    +-#else
    +-#define OptimizationDisabled(db, mask)  0
    +-#define OptimizationEnabled(db, mask)   1
    +-#endif
    + 
    + /*
    + ** Return true if it OK to factor constant expressions into the initialization
    +@@ -11887,28 +15442,33 @@ struct sqlite3 {
    + 
    + /*
    + ** Each SQL function is defined by an instance of the following
    +-** structure.  A pointer to this structure is stored in the sqlite.aFunc
    +-** hash table.  When multiple functions have the same name, the hash table
    +-** points to a linked list of these structures.
    ++** structure.  For global built-in functions (ex: substr(), max(), count())
    ++** a pointer to this structure is held in the sqlite3BuiltinFunctions object.
    ++** For per-connection application-defined functions, a pointer to this
    ++** structure is held in the db->aHash hash table.
    ++**
    ++** The u.pHash field is used by the global built-ins.  The u.pDestructor
    ++** field is used by per-connection app-def functions.
    + */
    + struct FuncDef {
    +-  i16 nArg;            /* Number of arguments.  -1 means unlimited */
    ++  i8 nArg;             /* Number of arguments.  -1 means unlimited */
    +   u16 funcFlags;       /* Some combination of SQLITE_FUNC_* */
    +   void *pUserData;     /* User data parameter */
    +   FuncDef *pNext;      /* Next function with same name */
    +-  void (*xFunc)(sqlite3_context*,int,sqlite3_value**); /* Regular function */
    +-  void (*xStep)(sqlite3_context*,int,sqlite3_value**); /* Aggregate step */
    +-  void (*xFinalize)(sqlite3_context*);                /* Aggregate finalizer */
    +-  char *zName;         /* SQL name of the function. */
    +-  FuncDef *pHash;      /* Next with a different name but the same hash */
    +-  FuncDestructor *pDestructor;   /* Reference counted destructor function */
    ++  void (*xSFunc)(sqlite3_context*,int,sqlite3_value**); /* func or agg-step */
    ++  void (*xFinalize)(sqlite3_context*);                  /* Agg finalizer */
    ++  const char *zName;   /* SQL name of the function. */
    ++  union {
    ++    FuncDef *pHash;      /* Next with a different name but the same hash */
    ++    FuncDestructor *pDestructor;   /* Reference counted destructor function */
    ++  } u;
    + };
    + 
    + /*
    + ** This structure encapsulates a user-function destructor callback (as
    + ** configured using create_function_v2()) and a reference counter. When
    + ** create_function_v2() is called to create a function with a destructor,
    +-** a single object of this type is allocated. FuncDestructor.nRef is set to 
    ++** a single object of this type is allocated. FuncDestructor.nRef is set to
    + ** the number of FuncDef objects created (either 1 or 3, depending on whether
    + ** or not the specified encoding is SQLITE_ANY). The FuncDef.pDestructor
    + ** member of each of the new FuncDef objects is set to point to the allocated
    +@@ -11926,8 +15486,16 @@ struct FuncDestructor {
    + 
    + /*
    + ** Possible values for FuncDef.flags.  Note that the _LENGTH and _TYPEOF
    +-** values must correspond to OPFLAG_LENGTHARG and OPFLAG_TYPEOFARG.  There
    ++** values must correspond to OPFLAG_LENGTHARG and OPFLAG_TYPEOFARG.  And
    ++** SQLITE_FUNC_CONSTANT must be the same as SQLITE_DETERMINISTIC.  There
    + ** are assert() statements in the code to verify this.
    ++**
    ++** Value constraints (enforced via assert()):
    ++**     SQLITE_FUNC_MINMAX    ==  NC_MinMaxAgg      == SF_MinMaxAgg
    ++**     SQLITE_FUNC_LENGTH    ==  OPFLAG_LENGTHARG
    ++**     SQLITE_FUNC_TYPEOF    ==  OPFLAG_TYPEOFARG
    ++**     SQLITE_FUNC_CONSTANT  ==  SQLITE_DETERMINISTIC from the API
    ++**     SQLITE_FUNC_ENCMASK   depends on SQLITE_UTF* macros in the API
    + */
    + #define SQLITE_FUNC_ENCMASK  0x0003 /* SQLITE_UTF8, SQLITE_UTF16BE or UTF16LE */
    + #define SQLITE_FUNC_LIKE     0x0004 /* Candidate for the LIKE optimization */
    +@@ -11943,16 +15511,18 @@ struct FuncDestructor {
    + #define SQLITE_FUNC_MINMAX   0x1000 /* True for min() and max() aggregates */
    + #define SQLITE_FUNC_SLOCHNG  0x2000 /* "Slow Change". Value constant during a
    +                                     ** single query - might change over time */
    ++#define SQLITE_FUNC_AFFINITY 0x4000 /* Built-in affinity() function */
    ++#define SQLITE_FUNC_OFFSET   0x8000 /* Built-in sqlite_offset() function */
    + 
    + /*
    + ** The following three macros, FUNCTION(), LIKEFUNC() and AGGREGATE() are
    + ** used to create the initializers for the FuncDef structures.
    + **
    + **   FUNCTION(zName, nArg, iArg, bNC, xFunc)
    +-**     Used to create a scalar function definition of a function zName 
    ++**     Used to create a scalar function definition of a function zName
    + **     implemented by C function xFunc that accepts nArg arguments. The
    + **     value passed as iArg is cast to a (void*) and made available
    +-**     as the user-data (sqlite3_user_data()) for the function. If 
    ++**     as the user-data (sqlite3_user_data()) for the function. If
    + **     argument bNC is true, then the SQLITE_FUNC_NEEDCOLL flag is set.
    + **
    + **   VFUNCTION(zName, nArg, iArg, bNC, xFunc)
    +@@ -11962,7 +15532,14 @@ struct FuncDestructor {
    + **     Like FUNCTION except it omits the SQLITE_FUNC_CONSTANT flag and
    + **     adds the SQLITE_FUNC_SLOCHNG flag.  Used for date & time functions
    + **     and functions like sqlite_version() that can change, but not during
    +-**     a single query.
    ++**     a single query.  The iArg is ignored.  The user-data is always set
    ++**     to a NULL pointer.  The bNC parameter is not used.
    ++**
    ++**   PURE_DATE(zName, nArg, iArg, bNC, xFunc)
    ++**     Used for "pure" date/time functions, this macro is like DFUNCTION
    ++**     except that it does set the SQLITE_FUNC_CONSTANT flags.  iArg is
    ++**     ignored and the user-data for these functions is set to an 
    ++**     arbitrary non-NULL pointer.  The bNC parameter is not used.
    + **
    + **   AGGREGATE(zName, nArg, iArg, bNC, xStep, xFinal)
    + **     Used to create an aggregate function definition implemented by
    +@@ -11971,8 +15548,8 @@ struct FuncDestructor {
    + **     FUNCTION().
    + **
    + **   LIKEFUNC(zName, nArg, pArg, flags)
    +-**     Used to create a scalar function definition of a function zName 
    +-**     that accepts nArg arguments and is implemented by a call to C 
    ++**     Used to create a scalar function definition of a function zName
    ++**     that accepts nArg arguments and is implemented by a call to C
    + **     function likeFunc. Argument pArg is cast to a (void *) and made
    + **     available as the function user-data (sqlite3_user_data()). The
    + **     FuncDef.flags variable is set to the value passed as the flags
    +@@ -11980,28 +15557,31 @@ struct FuncDestructor {
    + */
    + #define FUNCTION(zName, nArg, iArg, bNC, xFunc) \
    +   {nArg, SQLITE_FUNC_CONSTANT|SQLITE_UTF8|(bNC*SQLITE_FUNC_NEEDCOLL), \
    +-   SQLITE_INT_TO_PTR(iArg), 0, xFunc, 0, 0, #zName, 0, 0}
    ++   SQLITE_INT_TO_PTR(iArg), 0, xFunc, 0, #zName, {0} }
    + #define VFUNCTION(zName, nArg, iArg, bNC, xFunc) \
    +   {nArg, SQLITE_UTF8|(bNC*SQLITE_FUNC_NEEDCOLL), \
    +-   SQLITE_INT_TO_PTR(iArg), 0, xFunc, 0, 0, #zName, 0, 0}
    ++   SQLITE_INT_TO_PTR(iArg), 0, xFunc, 0, #zName, {0} }
    + #define DFUNCTION(zName, nArg, iArg, bNC, xFunc) \
    +-  {nArg, SQLITE_FUNC_SLOCHNG|SQLITE_UTF8|(bNC*SQLITE_FUNC_NEEDCOLL), \
    +-   SQLITE_INT_TO_PTR(iArg), 0, xFunc, 0, 0, #zName, 0, 0}
    ++  {nArg, SQLITE_FUNC_SLOCHNG|SQLITE_UTF8, \
    ++   0, 0, xFunc, 0, #zName, {0} }
    ++#define PURE_DATE(zName, nArg, iArg, bNC, xFunc) \
    ++  {nArg, SQLITE_FUNC_SLOCHNG|SQLITE_UTF8|SQLITE_FUNC_CONSTANT, \
    ++   (void*)&sqlite3Config, 0, xFunc, 0, #zName, {0} }
    + #define FUNCTION2(zName, nArg, iArg, bNC, xFunc, extraFlags) \
    +   {nArg,SQLITE_FUNC_CONSTANT|SQLITE_UTF8|(bNC*SQLITE_FUNC_NEEDCOLL)|extraFlags,\
    +-   SQLITE_INT_TO_PTR(iArg), 0, xFunc, 0, 0, #zName, 0, 0}
    ++   SQLITE_INT_TO_PTR(iArg), 0, xFunc, 0, #zName, {0} }
    + #define STR_FUNCTION(zName, nArg, pArg, bNC, xFunc) \
    +   {nArg, SQLITE_FUNC_SLOCHNG|SQLITE_UTF8|(bNC*SQLITE_FUNC_NEEDCOLL), \
    +-   pArg, 0, xFunc, 0, 0, #zName, 0, 0}
    ++   pArg, 0, xFunc, 0, #zName, }
    + #define LIKEFUNC(zName, nArg, arg, flags) \
    +   {nArg, SQLITE_FUNC_CONSTANT|SQLITE_UTF8|flags, \
    +-   (void *)arg, 0, likeFunc, 0, 0, #zName, 0, 0}
    ++   (void *)arg, 0, likeFunc, 0, #zName, {0} }
    + #define AGGREGATE(zName, nArg, arg, nc, xStep, xFinal) \
    +   {nArg, SQLITE_UTF8|(nc*SQLITE_FUNC_NEEDCOLL), \
    +-   SQLITE_INT_TO_PTR(arg), 0, 0, xStep,xFinal,#zName,0,0}
    ++   SQLITE_INT_TO_PTR(arg), 0, xStep,xFinal,#zName, {0}}
    + #define AGGREGATE2(zName, nArg, arg, nc, xStep, xFinal, extraFlags) \
    +   {nArg, SQLITE_UTF8|(nc*SQLITE_FUNC_NEEDCOLL)|extraFlags, \
    +-   SQLITE_INT_TO_PTR(arg), 0, 0, xStep,xFinal,#zName,0,0}
    ++   SQLITE_INT_TO_PTR(arg), 0, xStep,xFinal,#zName, {0}}
    + 
    + /*
    + ** All current savepoints are stored in a linked list starting at
    +@@ -12043,14 +15623,12 @@ struct Module {
    + ** of this structure.
    + */
    + struct Column {
    +-  char *zName;     /* Name of this column */
    ++  char *zName;     /* Name of this column, \000, then the type */
    +   Expr *pDflt;     /* Default value of this column */
    +-  char *zDflt;     /* Original text of the default value */
    +-  char *zType;     /* Data type for this column */
    +   char *zColl;     /* Collating sequence.  If NULL, use the default */
    +   u8 notNull;      /* An OE_ code for handling a NOT NULL constraint */
    +   char affinity;   /* One of the SQLITE_AFF_... values */
    +-  u8 szEst;        /* Estimated size of this column.  INT==1 */
    ++  u8 szEst;        /* Estimated size of value in this column. sizeof(INT)==1 */
    +   u8 colFlags;     /* Boolean properties.  See COLFLAG_ defines below */
    + };
    + 
    +@@ -12058,6 +15636,7 @@ struct Column {
    + */
    + #define COLFLAG_PRIMKEY  0x0001    /* Column is part of the primary key */
    + #define COLFLAG_HIDDEN   0x0002    /* A hidden column in a virtual table */
    ++#define COLFLAG_HASTYPE  0x0004    /* Type name follows column name */
    + 
    + /*
    + ** A "Collating Sequence" is defined by an instance of the following
    +@@ -12088,7 +15667,7 @@ struct CollSeq {
    + **
    + ** These used to have mnemonic name like 'i' for SQLITE_AFF_INTEGER and
    + ** 't' for SQLITE_AFF_TEXT.  But we can save a little space and improve
    +-** the speed a little by numbering the values consecutively.  
    ++** the speed a little by numbering the values consecutively.
    + **
    + ** But rather than start with 0 or 1, we begin with 'A'.  That way,
    + ** when multiple affinity types are concatenated into a string and
    +@@ -12107,7 +15686,7 @@ struct CollSeq {
    + 
    + /*
    + ** The SQLITE_AFF_MASK values masks off the significant bits of an
    +-** affinity value. 
    ++** affinity value.
    + */
    + #define SQLITE_AFF_MASK     0x47
    + 
    +@@ -12120,6 +15699,7 @@ struct CollSeq {
    + ** operator is NULL.  It is added to certain comparison operators to
    + ** prove that the operands are always NOT NULL.
    + */
    ++#define SQLITE_KEEPNULL     0x08  /* Used by vector == or <> */
    + #define SQLITE_JUMPIFNULL   0x10  /* jumps if either operand is NULL */
    + #define SQLITE_STOREP2      0x20  /* Store result in reg[P2] rather than jump */
    + #define SQLITE_NULLEQ       0x80  /* NULL=NULL */
    +@@ -12127,20 +15707,20 @@ struct CollSeq {
    + 
    + /*
    + ** An object of this type is created for each virtual table present in
    +-** the database schema. 
    ++** the database schema.
    + **
    + ** If the database schema is shared, then there is one instance of this
    + ** structure for each database connection (sqlite3*) that uses the shared
    + ** schema. This is because each database connection requires its own unique
    +-** instance of the sqlite3_vtab* handle used to access the virtual table 
    +-** implementation. sqlite3_vtab* handles can not be shared between 
    +-** database connections, even when the rest of the in-memory database 
    ++** instance of the sqlite3_vtab* handle used to access the virtual table
    ++** implementation. sqlite3_vtab* handles can not be shared between
    ++** database connections, even when the rest of the in-memory database
    + ** schema is shared, as the implementation often stores the database
    + ** connection handle passed to it via the xConnect() or xCreate() method
    + ** during initialization internally. This database connection handle may
    +-** then be used by the virtual table implementation to access real tables 
    +-** within the database. So that they appear as part of the callers 
    +-** transaction, these accesses need to be made via the same database 
    ++** then be used by the virtual table implementation to access real tables
    ++** within the database. So that they appear as part of the callers
    ++** transaction, these accesses need to be made via the same database
    + ** connection as that used to execute SQL operations on the virtual table.
    + **
    + ** All VTable objects that correspond to a single table in a shared
    +@@ -12152,19 +15732,19 @@ struct CollSeq {
    + ** sqlite3_vtab* handle in the compiled query.
    + **
    + ** When an in-memory Table object is deleted (for example when the
    +-** schema is being reloaded for some reason), the VTable objects are not 
    +-** deleted and the sqlite3_vtab* handles are not xDisconnect()ed 
    ++** schema is being reloaded for some reason), the VTable objects are not
    ++** deleted and the sqlite3_vtab* handles are not xDisconnect()ed
    + ** immediately. Instead, they are moved from the Table.pVTable list to
    + ** another linked list headed by the sqlite3.pDisconnect member of the
    +-** corresponding sqlite3 structure. They are then deleted/xDisconnected 
    ++** corresponding sqlite3 structure. They are then deleted/xDisconnected
    + ** next time a statement is prepared using said sqlite3*. This is done
    + ** to avoid deadlock issues involving multiple sqlite3.mutex mutexes.
    + ** Refer to comments above function sqlite3VtabUnlockList() for an
    + ** explanation as to why it is safe to add an entry to an sqlite3.pDisconnect
    + ** list without holding the corresponding sqlite3.mutex mutex.
    + **
    +-** The memory for objects of this type is always allocated by 
    +-** sqlite3DbMalloc(), using the connection handle stored in VTable.db as 
    ++** The memory for objects of this type is always allocated by
    ++** sqlite3DbMalloc(), using the connection handle stored in VTable.db as
    + ** the first argument.
    + */
    + struct VTable {
    +@@ -12191,15 +15771,15 @@ struct Table {
    +   ExprList *pCheck;    /* All CHECK constraints */
    +                        /*   ... also used as column name list in a VIEW */
    +   int tnum;            /* Root BTree page for this table */
    ++  u32 nTabRef;         /* Number of pointers to this Table */
    ++  u32 tabFlags;        /* Mask of TF_* values */
    +   i16 iPKey;           /* If not negative, use aCol[iPKey] as the rowid */
    +   i16 nCol;            /* Number of columns in this table */
    +-  u16 nRef;            /* Number of pointers to this Table */
    +   LogEst nRowLogEst;   /* Estimated rows in table - from sqlite_stat1 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
    +   int addColOffset;    /* Offset in CREATE TABLE stmt to add a new column */
    +@@ -12217,21 +15797,23 @@ struct Table {
    + /*
    + ** Allowed values for Table.tabFlags.
    + **
    +-** TF_OOOHidden applies to virtual tables that have hidden columns that are
    ++** TF_OOOHidden applies to tables or view that have hidden columns that are
    + ** followed by non-hidden columns.  Example:  "CREATE VIRTUAL TABLE x USING
    + ** vtab1(a HIDDEN, b);".  Since "b" is a non-hidden column but "a" is hidden,
    + ** the TF_OOOHidden attribute would apply in this case.  Such tables require
    + ** special handling during INSERT processing.
    + */
    +-#define TF_Readonly        0x01    /* Read-only system table */
    +-#define TF_Ephemeral       0x02    /* An ephemeral table */
    +-#define TF_HasPrimaryKey   0x04    /* Table has a primary key */
    +-#define TF_Autoincrement   0x08    /* Integer primary key is autoincrement */
    +-#define TF_Virtual         0x10    /* Is a virtual table */
    +-#define TF_WithoutRowid    0x20    /* No rowid.  PRIMARY KEY is the key */
    +-#define TF_NoVisibleRowid  0x40    /* No user-visible "rowid" column */
    +-#define TF_OOOHidden       0x80    /* Out-of-Order hidden columns */
    +-
    ++#define TF_Readonly        0x0001    /* Read-only system table */
    ++#define TF_Ephemeral       0x0002    /* An ephemeral table */
    ++#define TF_HasPrimaryKey   0x0004    /* Table has a primary key */
    ++#define TF_Autoincrement   0x0008    /* Integer primary key is autoincrement */
    ++#define TF_HasStat1        0x0010    /* nRowLogEst set from sqlite_stat1 */
    ++#define TF_WithoutRowid    0x0020    /* No rowid.  PRIMARY KEY is the key */
    ++#define TF_NoVisibleRowid  0x0040    /* No user-visible "rowid" column */
    ++#define TF_OOOHidden       0x0080    /* Out-of-Order hidden columns */
    ++#define TF_StatsUsed       0x0100    /* Query planner decisions affected by
    ++                                     ** Index.aiRowLogEst[] values */
    ++#define TF_HasNotNull      0x0200    /* Contains NOT NULL constraints */
    + 
    + /*
    + ** Test to see whether or not a table is a virtual table.  This is
    +@@ -12239,13 +15821,29 @@ struct Table {
    + ** table support is omitted from the build.
    + */
    + #ifndef SQLITE_OMIT_VIRTUALTABLE
    +-#  define IsVirtual(X)      (((X)->tabFlags & TF_Virtual)!=0)
    +-#  define IsHiddenColumn(X) (((X)->colFlags & COLFLAG_HIDDEN)!=0)
    ++#  define IsVirtual(X)      ((X)->nModuleArg)
    + #else
    + #  define IsVirtual(X)      0
    +-#  define IsHiddenColumn(X) 0
    + #endif
    + 
    ++/*
    ++** Macros to determine if a column is hidden.  IsOrdinaryHiddenColumn()
    ++** only works for non-virtual tables (ordinary tables and views) and is
    ++** always false unless SQLITE_ENABLE_HIDDEN_COLUMNS is defined.  The
    ++** IsHiddenColumn() macro is general purpose.
    ++*/
    ++#if defined(SQLITE_ENABLE_HIDDEN_COLUMNS)
    ++#  define IsHiddenColumn(X)         (((X)->colFlags & COLFLAG_HIDDEN)!=0)
    ++#  define IsOrdinaryHiddenColumn(X) (((X)->colFlags & COLFLAG_HIDDEN)!=0)
    ++#elif !defined(SQLITE_OMIT_VIRTUALTABLE)
    ++#  define IsHiddenColumn(X)         (((X)->colFlags & COLFLAG_HIDDEN)!=0)
    ++#  define IsOrdinaryHiddenColumn(X) 0
    ++#else
    ++#  define IsHiddenColumn(X)         0
    ++#  define IsOrdinaryHiddenColumn(X) 0
    ++#endif
    ++
    ++
    + /* Does the table have a rowid */
    + #define HasRowid(X)     (((X)->tabFlags & TF_WithoutRowid)==0)
    + #define VisibleRowid(X) (((X)->tabFlags & TF_NoVisibleRowid)==0)
    +@@ -12316,7 +15914,7 @@ struct FKey {
    + ** key is set to NULL.  CASCADE means that a DELETE or UPDATE of the
    + ** referenced table row is propagated into the row that holds the
    + ** foreign key.
    +-** 
    ++**
    + ** The following symbolic values are used to record which type
    + ** of action to take.
    + */
    +@@ -12337,7 +15935,7 @@ struct FKey {
    + 
    + /*
    + ** An instance of the following structure is passed as the first
    +-** argument to sqlite3VdbeKeyCompare and is used to control the 
    ++** argument to sqlite3VdbeKeyCompare and is used to control the
    + ** comparison of the two index keys.
    + **
    + ** Note that aSortOrder[] and aColl[] have nField+1 slots.  There
    +@@ -12347,17 +15945,16 @@ struct FKey {
    + struct KeyInfo {
    +   u32 nRef;           /* Number of references to this KeyInfo object */
    +   u8 enc;             /* Text encoding - one of the SQLITE_UTF* values */
    +-  u16 nField;         /* Number of key columns in the index */
    +-  u16 nXField;        /* Number of columns beyond the key columns */
    ++  u16 nKeyField;      /* Number of key columns in the index */
    ++  u16 nAllField;      /* Total columns, including key plus others */
    +   sqlite3 *db;        /* The database connection */
    +   u8 *aSortOrder;     /* Sort order for each column. */
    +   CollSeq *aColl[1];  /* Collating sequence for each term of the key */
    + };
    + 
    + /*
    +-** An instance of the following structure holds information about a
    +-** single index record that has already been parsed out into individual
    +-** values.
    ++** This object holds a record which has been parsed out into individual
    ++** fields, for the purposes of doing a comparison.
    + **
    + ** A record is an object that contains one or more fields of data.
    + ** Records are used to store the content of a table row and to store
    +@@ -12365,20 +15962,40 @@ struct KeyInfo {
    + ** the OP_MakeRecord opcode of the VDBE and is disassembled by the
    + ** OP_Column opcode.
    + **
    +-** This structure holds a record that has already been disassembled
    +-** into its constituent fields.
    +-**
    +-** The r1 and r2 member variables are only used by the optimized comparison
    +-** functions vdbeRecordCompareInt() and vdbeRecordCompareString().
    ++** An instance of this object serves as a "key" for doing a search on
    ++** an index b+tree. The goal of the search is to find the entry that
    ++** is closed to the key described by this object.  This object might hold
    ++** just a prefix of the key.  The number of fields is given by
    ++** pKeyInfo->nField.
    ++**
    ++** The r1 and r2 fields are the values to return if this key is less than
    ++** or greater than a key in the btree, respectively.  These are normally
    ++** -1 and +1 respectively, but might be inverted to +1 and -1 if the b-tree
    ++** is in DESC order.
    ++**
    ++** The key comparison functions actually return default_rc when they find
    ++** an equals comparison.  default_rc can be -1, 0, or +1.  If there are
    ++** multiple entries in the b-tree with the same key (when only looking
    ++** at the first pKeyInfo->nFields,) then default_rc can be set to -1 to
    ++** cause the search to find the last match, or +1 to cause the search to
    ++** find the first match.
    ++**
    ++** The key comparison functions will set eqSeen to true if they ever
    ++** get and equal results when comparing this structure to a b-tree record.
    ++** When default_rc!=0, the search might end up on the record immediately
    ++** before the first match or immediately after the last match.  The
    ++** eqSeen field will indicate whether or not an exact match exists in the
    ++** b-tree.
    + */
    + struct UnpackedRecord {
    +   KeyInfo *pKeyInfo;  /* Collation and sort-order information */
    ++  Mem *aMem;          /* Values */
    +   u16 nField;         /* Number of entries in apMem[] */
    +   i8 default_rc;      /* Comparison result if keys are equal */
    +   u8 errCode;         /* Error detected by xRecordCompare (CORRUPT or NOMEM) */
    +-  Mem *aMem;          /* Values */
    +-  int r1;             /* Value to return if (lhs > rhs) */
    +-  int r2;             /* Value to return if (rhs < lhs) */
    ++  i8 r1;              /* Value to return if (lhs < rhs) */
    ++  i8 r2;              /* Value to return if (lhs > rhs) */
    ++  u8 eqSeen;          /* True if an equality comparison has been seen */
    + };
    + 
    + 
    +@@ -12396,7 +16013,7 @@ struct UnpackedRecord {
    + ** In the Table structure describing Ex1, nCol==3 because there are
    + ** three columns in the table.  In the Index structure describing
    + ** Ex2, nColumn==2 since 2 of the 3 columns of Ex1 are indexed.
    +-** The value of aiColumn is {2, 0}.  aiColumn[0]==2 because the 
    ++** The value of aiColumn is {2, 0}.  aiColumn[0]==2 because the
    + ** first column to be indexed (c3) has an index of 2 in Ex1.aCol[].
    + ** The second column to be indexed (c1) has an index of 0 in
    + ** Ex1.aCol[], hence Ex2.aiColumn[1]==0.
    +@@ -12404,7 +16021,7 @@ struct UnpackedRecord {
    + ** The Index.onError field determines whether or not the indexed columns
    + ** must be unique and what to do if they are not.  When Index.onError=OE_None,
    + ** it means this is not a unique index.  Otherwise it is a unique index
    +-** and the value of Index.onError indicate the which conflict resolution 
    ++** and the value of Index.onError indicate the which conflict resolution
    + ** algorithm to employ whenever an attempt is made to insert a non-unique
    + ** element.
    + **
    +@@ -12425,7 +16042,7 @@ struct Index {
    +   Index *pNext;            /* The next index associated with the same table */
    +   Schema *pSchema;         /* Schema containing this index */
    +   u8 *aSortOrder;          /* for each column: True==DESC, False==ASC */
    +-  char **azColl;           /* Array of collation sequence names for index */
    ++  const char **azColl;     /* Array of collation sequence names for index */
    +   Expr *pPartIdxWhere;     /* WHERE clause for partial indices */
    +   ExprList *aColExpr;      /* Column expressions */
    +   int tnum;                /* DB Page containing root of this index */
    +@@ -12439,6 +16056,8 @@ struct Index {
    +   unsigned isResized:1;    /* True if resizeIndexObject() has been called */
    +   unsigned isCovering:1;   /* True if this is a covering index */
    +   unsigned noSkipScan:1;   /* Do not try to use skip-scan if true */
    ++  unsigned hasStat1:1;     /* aiRowLogEst values come from sqlite_stat1 */
    ++  unsigned bNoQuery:1;     /* Do not use this index to optimize queries */
    + #ifdef SQLITE_ENABLE_STAT3_OR_STAT4
    +   int nSample;             /* Number of elements in aSample[] */
    +   int nSampleCol;          /* Size of IndexSample.anEq[] and so on */
    +@@ -12469,7 +16088,7 @@ struct Index {
    + #define XN_EXPR      (-2)     /* Indexed column is an expression */
    + 
    + /*
    +-** Each sample stored in the sqlite_stat3 table is represented in memory 
    ++** 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
    + ** analyze.c source file for additional information.
    + */
    +@@ -12564,9 +16183,9 @@ typedef int ynVar;
    + ** to represent the greater-than-or-equal-to operator in the expression
    + ** tree.
    + **
    +-** If the expression is an SQL literal (TK_INTEGER, TK_FLOAT, TK_BLOB, 
    ++** If the expression is an SQL literal (TK_INTEGER, TK_FLOAT, TK_BLOB,
    + ** or TK_STRING), then Expr.token contains the text of the SQL literal. If
    +-** the expression is a variable (TK_VARIABLE), then Expr.token contains the 
    ++** the expression is a variable (TK_VARIABLE), then Expr.token contains the
    + ** variable name. Finally, if the expression is an SQL function (TK_FUNCTION),
    + ** then Expr.token contains the name of the function.
    + **
    +@@ -12577,7 +16196,7 @@ typedef int ynVar;
    + ** a CASE expression or an IN expression of the form "<lhs> IN (<y>, <z>...)".
    + ** Expr.x.pSelect is used if the expression is a sub-select or an expression of
    + ** the form "<lhs> IN (SELECT ...)". If the EP_xIsSelect bit is set in the
    +-** Expr.flags mask, then Expr.x.pSelect is valid. Otherwise, Expr.x.pList is 
    ++** Expr.flags mask, then Expr.x.pSelect is valid. Otherwise, Expr.x.pList is
    + ** valid.
    + **
    + ** An expression of the form ID or ID.ID refers to a column in a table.
    +@@ -12588,8 +16207,8 @@ typedef int ynVar;
    + ** value is also stored in the Expr.iAgg column in the aggregate so that
    + ** it can be accessed after all aggregates are computed.
    + **
    +-** If the expression is an unbound variable marker (a question mark 
    +-** character '?' in the original SQL) then the Expr.iTable holds the index 
    ++** If the expression is an unbound variable marker (a question mark
    ++** character '?' in the original SQL) then the Expr.iTable holds the index
    + ** number for that variable.
    + **
    + ** If the expression is a subquery then Expr.iColumn holds an integer
    +@@ -12628,7 +16247,7 @@ struct Expr {
    + 
    +   /* If the EP_TokenOnly flag is set in the Expr.flags mask, then no
    +   ** space is allocated for the fields below this point. An attempt to
    +-  ** access them will result in a segfault or malfunction. 
    ++  ** access them will result in a segfault or malfunction.
    +   *********************************************************************/
    + 
    +   Expr *pLeft;           /* Left subnode */
    +@@ -12649,16 +16268,19 @@ struct Expr {
    +   int iTable;            /* TK_COLUMN: cursor number of table holding column
    +                          ** TK_REGISTER: register number
    +                          ** TK_TRIGGER: 1 -> new, 0 -> old
    +-                         ** EP_Unlikely:  134217728 times likelihood */
    ++                         ** EP_Unlikely:  134217728 times likelihood
    ++                         ** TK_SELECT: 1st register of result vector */
    +   ynVar iColumn;         /* TK_COLUMN: column index.  -1 for rowid.
    +-                         ** TK_VARIABLE: variable number (always >= 1). */
    ++                         ** TK_VARIABLE: variable number (always >= 1).
    ++                         ** TK_SELECT_COLUMN: column of the result vector */
    +   i16 iAgg;              /* Which entry in pAggInfo->aCol[] or ->aFunc[] */
    +   i16 iRightJoinTable;   /* If EP_FromJoin, the right table of the join */
    +   u8 op2;                /* TK_REGISTER: original value of Expr.op
    +                          ** TK_COLUMN: the value of p5 for OP_Column
    +                          ** TK_AGG_FUNCTION: nesting depth */
    +   AggInfo *pAggInfo;     /* Used by TK_AGG_COLUMN and TK_AGG_FUNCTION */
    +-  Table *pTab;           /* Table for TK_COLUMN expressions. */
    ++  Table *pTab;           /* Table for TK_COLUMN expressions.  Can be NULL
    ++                         ** for a column of an index on an expression */
    + };
    + 
    + /*
    +@@ -12666,8 +16288,8 @@ struct Expr {
    + */
    + #define EP_FromJoin  0x000001 /* Originates in ON/USING clause of outer join */
    + #define EP_Agg       0x000002 /* Contains one or more aggregate functions */
    +-#define EP_Resolved  0x000004 /* IDs have been resolved to COLUMNs */
    +-#define EP_Error     0x000008 /* Expression contains one or more errors */
    ++#define EP_HasFunc   0x000004 /* Contains one or more functions of any kind */
    ++                  /* 0x000008 // available for use */
    + #define EP_Distinct  0x000010 /* Aggregate function with DISTINCT keyword */
    + #define EP_VarSelect 0x000020 /* pSelect is correlated, not constant */
    + #define EP_DblQuoted 0x000040 /* token.z was originally in "..." */
    +@@ -12687,14 +16309,16 @@ struct Expr {
    + #define EP_CanBeNull 0x100000 /* Can be null despite NOT NULL constraint */
    + #define EP_Subquery  0x200000 /* Tree contains a TK_SELECT operator */
    + #define EP_Alias     0x400000 /* Is an alias for a result set column */
    ++#define EP_Leaf      0x800000 /* Expr.pLeft, .pRight, .u.pSelect all NULL */
    + 
    + /*
    +-** Combinations of two or more EP_* flags
    ++** The EP_Propagate mask is a set of properties that automatically propagate
    ++** upwards into parent nodes.
    + */
    +-#define EP_Propagate (EP_Collate|EP_Subquery) /* Propagate these bits up tree */
    ++#define EP_Propagate (EP_Collate|EP_Subquery|EP_HasFunc)
    + 
    + /*
    +-** These macros can be used to test, set, or clear bits in the 
    ++** These macros can be used to test, set, or clear bits in the
    + ** Expr.flags field.
    + */
    + #define ExprHasProperty(E,P)     (((E)->flags&(P))!=0)
    +@@ -12713,8 +16337,8 @@ struct Expr {
    + #endif
    + 
    + /*
    +-** Macros to determine the number of bytes required by a normal Expr 
    +-** struct, an Expr struct with the EP_Reduced flag set in Expr.flags 
    ++** Macros to determine the number of bytes required by a normal Expr
    ++** struct, an Expr struct with the EP_Reduced flag set in Expr.flags
    + ** and an Expr struct with the EP_TokenOnly flag set.
    + */
    + #define EXPR_FULLSIZE           sizeof(Expr)           /* Full size */
    +@@ -12722,7 +16346,7 @@ struct Expr {
    + #define EXPR_TOKENONLYSIZE      offsetof(Expr,pLeft)   /* Fewer features */
    + 
    + /*
    +-** Flags passed to the sqlite3ExprDup() function. See the header comment 
    ++** Flags passed to the sqlite3ExprDup() function. See the header comment
    + ** above sqlite3ExprDup() for details.
    + */
    + #define EXPRDUP_REDUCE         0x0001  /* Used reduced-size Expr nodes */
    +@@ -12746,7 +16370,7 @@ struct Expr {
    + struct ExprList {
    +   int nExpr;             /* Number of expressions on the list */
    +   struct ExprList_item { /* For each expression in the list */
    +-    Expr *pExpr;            /* The list of expressions */
    ++    Expr *pExpr;            /* The parse tree for this expression */
    +     char *zName;            /* Token associated with this expression */
    +     char *zSpan;            /* Original text of the expression */
    +     u8 sortOrder;           /* 1 for DESC or 0 for ASC */
    +@@ -12760,18 +16384,7 @@ struct ExprList {
    +       } x;
    +       int iConstExprReg;      /* Register in which Expr value is cached */
    +     } u;
    +-  } *a;                  /* Alloc a power of two greater or equal to nExpr */
    +-};
    +-
    +-/*
    +-** An instance of this structure is used by the parser to record both
    +-** the parse tree for an expression and the span of input text for an
    +-** expression.
    +-*/
    +-struct ExprSpan {
    +-  Expr *pExpr;          /* The expression parse tree */
    +-  const char *zStart;   /* First character of input text */
    +-  const char *zEnd;     /* One character past the end of input text */
    ++  } a[1];                  /* One slot for each expression in the list */
    + };
    + 
    + /*
    +@@ -12804,7 +16417,11 @@ struct IdList {
    + ** tables in a join to 32 instead of 64.  But it also reduces the size
    + ** of the library by 738 bytes on ix86.
    + */
    +-typedef u64 Bitmask;
    ++#ifdef SQLITE_BITMASK_TYPE
    ++  typedef SQLITE_BITMASK_TYPE Bitmask;
    ++#else
    ++  typedef u64 Bitmask;
    ++#endif
    + 
    + /*
    + ** The number of bits in a Bitmask.  "BMS" means "BitMask Size".
    +@@ -12816,6 +16433,7 @@ typedef u64 Bitmask;
    + */
    + #define MASKBIT(n)   (((Bitmask)1)<<(n))
    + #define MASKBIT32(n) (((unsigned int)1)<<(n))
    ++#define ALLBITS      ((Bitmask)-1)
    + 
    + /*
    + ** The following structure describes the FROM clause of a SELECT statement.
    +@@ -12850,7 +16468,7 @@ struct SrcList {
    +     int regReturn;    /* Register holding return address of addrFillSub */
    +     int regResult;    /* Registers holding results of a co-routine */
    +     struct {
    +-      u8 jointype;      /* Type of join between this able and the previous */
    ++      u8 jointype;      /* Type of join between this table and the previous */
    +       unsigned notIndexed :1;    /* True if there is a NOT INDEXED clause */
    +       unsigned isIndexedBy :1;   /* True if there is an INDEXED BY clause */
    +       unsigned isTabFunc :1;     /* True if table-valued-function syntax */
    +@@ -12888,22 +16506,28 @@ struct SrcList {
    + /*
    + ** Flags appropriate for the wctrlFlags parameter of sqlite3WhereBegin()
    + ** and the WhereInfo.wctrlFlags member.
    ++**
    ++** Value constraints (enforced via assert()):
    ++**     WHERE_USE_LIMIT  == SF_FixedLimit
    + */
    + #define WHERE_ORDERBY_NORMAL   0x0000 /* No-op */
    + #define WHERE_ORDERBY_MIN      0x0001 /* ORDER BY processing for min() func */
    + #define WHERE_ORDERBY_MAX      0x0002 /* ORDER BY processing for max() func */
    + #define WHERE_ONEPASS_DESIRED  0x0004 /* Want to do one-pass UPDATE/DELETE */
    +-#define WHERE_DUPLICATES_OK    0x0008 /* Ok to return a row more than once */
    +-#define WHERE_OMIT_OPEN_CLOSE  0x0010 /* Table cursors are already open */
    +-#define WHERE_FORCE_TABLE      0x0020 /* Do not use an index-only search */
    +-#define WHERE_ONETABLE_ONLY    0x0040 /* Only code the 1st table in pTabList */
    +-#define WHERE_NO_AUTOINDEX     0x0080 /* Disallow automatic indexes */
    +-#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 */
    +-#define WHERE_ONEPASS_MULTIROW 0x2000 /* ONEPASS is ok with multiple rows */
    ++#define WHERE_ONEPASS_MULTIROW 0x0008 /* ONEPASS is ok with multiple rows */
    ++#define WHERE_DUPLICATES_OK    0x0010 /* Ok to return a row more than once */
    ++#define WHERE_OR_SUBCLAUSE     0x0020 /* Processing a sub-WHERE as part of
    ++                                      ** the OR optimization  */
    ++#define WHERE_GROUPBY          0x0040 /* pOrderBy is really a GROUP BY */
    ++#define WHERE_DISTINCTBY       0x0080 /* pOrderby is really a DISTINCT clause */
    ++#define WHERE_WANT_DISTINCT    0x0100 /* All output needs to be distinct */
    ++#define WHERE_SORTBYGROUP      0x0200 /* Support sqlite3WhereIsSorted() */
    ++#define WHERE_SEEK_TABLE       0x0400 /* Do not defer seeks on main table */
    ++#define WHERE_ORDERBY_LIMIT    0x0800 /* ORDERBY+LIMIT on the inner loop */
    ++#define WHERE_SEEK_UNIQ_TABLE  0x1000 /* Do not defer seeks if unique */
    ++                        /*     0x2000    not currently used */
    ++#define WHERE_USE_LIMIT        0x4000 /* Use the LIMIT in cost estimates */
    ++                        /*     0x8000    not currently used */
    + 
    + /* Allowed return values from sqlite3WhereIsDistinct()
    + */
    +@@ -12921,12 +16545,12 @@ struct SrcList {
    + ** pEList corresponds to the result set of a SELECT and is NULL for
    + ** other statements.
    + **
    +-** NameContexts can be nested.  When resolving names, the inner-most 
    ++** NameContexts can be nested.  When resolving names, the inner-most
    + ** context is searched first.  If no match is found, the next outer
    + ** context is checked.  If there is still no match, the next context
    + ** is checked.  This process continues until either a match is found
    + ** or all contexts are check.  When a match is found, the nRef member of
    +-** the context containing the match is incremented. 
    ++** the context containing the match is incremented.
    + **
    + ** Each subquery gets a new NameContext.  The pNext field points to the
    + ** NameContext in the parent query.  Thus the process of scanning the
    +@@ -12947,17 +16571,20 @@ struct NameContext {
    + /*
    + ** Allowed values for the NameContext, ncFlags field.
    + **
    +-** Note:  NC_MinMaxAgg must have the same value as SF_MinMaxAgg and
    +-** SQLITE_FUNC_MINMAX.
    +-** 
    ++** Value constraints (all checked via assert()):
    ++**    NC_HasAgg    == SF_HasAgg
    ++**    NC_MinMaxAgg == SF_MinMaxAgg == SQLITE_FUNC_MINMAX
    ++**
    + */
    + #define NC_AllowAgg  0x0001  /* Aggregate functions are allowed here */
    +-#define NC_HasAgg    0x0002  /* One or more aggregate functions seen */
    ++#define NC_PartIdx   0x0002  /* True if resolving a partial index WHERE */
    + #define NC_IsCheck   0x0004  /* True if resolving names in a CHECK constraint */
    + #define NC_InAggFunc 0x0008  /* True if analyzing arguments to an agg func */
    +-#define NC_PartIdx   0x0010  /* True if resolving a partial index WHERE */
    ++#define NC_HasAgg    0x0010  /* One or more aggregate functions seen */
    + #define NC_IdxExpr   0x0020  /* True if resolving columns of CREATE INDEX */
    ++#define NC_VarSelect 0x0040  /* A correlated subquery has been seen */
    + #define NC_MinMaxAgg 0x1000  /* min/max aggregates seen.  See note above */
    ++#define NC_Complex   0x2000  /* True if a function or subquery seen */
    + 
    + /*
    + ** An instance of the following structure contains all information
    +@@ -12982,13 +16609,13 @@ struct NameContext {
    + struct Select {
    +   ExprList *pEList;      /* The fields of the result */
    +   u8 op;                 /* One of: TK_UNION TK_ALL TK_INTERSECT TK_EXCEPT */
    +-  u16 selFlags;          /* Various SF_* values */
    ++  LogEst nSelectRow;     /* Estimated number of result rows */
    ++  u32 selFlags;          /* Various SF_* values */
    +   int iLimit, iOffset;   /* Memory registers holding LIMIT & OFFSET counters */
    + #if SELECTTRACE_ENABLED
    +   char zSelName[12];     /* Symbolic name of this SELECT use for debugging */
    + #endif
    +   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 */
    +   ExprList *pGroupBy;    /* The GROUP BY clause */
    +@@ -12997,29 +16624,37 @@ struct Select {
    +   Select *pPrior;        /* Prior select in a compound select statement */
    +   Select *pNext;         /* Next select to the left in a compound */
    +   Expr *pLimit;          /* LIMIT expression. NULL means not used. */
    +-  Expr *pOffset;         /* OFFSET expression. NULL means not used. */
    +   With *pWith;           /* WITH clause attached to this select. Or NULL. */
    + };
    + 
    + /*
    + ** Allowed values for Select.selFlags.  The "SF" prefix stands for
    + ** "Select Flag".
    +-*/
    +-#define SF_Distinct        0x0001  /* Output should be DISTINCT */
    +-#define SF_All             0x0002  /* Includes the ALL keyword */
    +-#define SF_Resolved        0x0004  /* Identifiers have been resolved */
    +-#define SF_Aggregate       0x0008  /* Contains aggregate functions */
    +-#define SF_UsesEphemeral   0x0010  /* Uses the OpenEphemeral opcode */
    +-#define SF_Expanded        0x0020  /* sqlite3SelectExpand() called on this */
    +-#define SF_HasTypeInfo     0x0040  /* FROM subqueries have Table metadata */
    +-#define SF_Compound        0x0080  /* Part of a compound query */
    +-#define SF_Values          0x0100  /* Synthesized from VALUES clause */
    +-#define SF_MultiValue      0x0200  /* Single VALUES term with multiple rows */
    +-#define SF_NestedFrom      0x0400  /* Part of a parenthesized FROM clause */
    +-#define SF_MaybeConvert    0x0800  /* Need convertCompoundSelectToSubquery() */
    +-#define SF_MinMaxAgg       0x1000  /* Aggregate containing min() or max() */
    +-#define SF_Recursive       0x2000  /* The recursive part of a recursive CTE */
    +-#define SF_Converted       0x4000  /* By convertCompoundSelectToSubquery() */
    ++**
    ++** Value constraints (all checked via assert())
    ++**     SF_HasAgg     == NC_HasAgg
    ++**     SF_MinMaxAgg  == NC_MinMaxAgg     == SQLITE_FUNC_MINMAX
    ++**     SF_FixedLimit == WHERE_USE_LIMIT
    ++*/
    ++#define SF_Distinct       0x00001  /* Output should be DISTINCT */
    ++#define SF_All            0x00002  /* Includes the ALL keyword */
    ++#define SF_Resolved       0x00004  /* Identifiers have been resolved */
    ++#define SF_Aggregate      0x00008  /* Contains agg functions or a GROUP BY */
    ++#define SF_HasAgg         0x00010  /* Contains aggregate functions */
    ++#define SF_UsesEphemeral  0x00020  /* Uses the OpenEphemeral opcode */
    ++#define SF_Expanded       0x00040  /* sqlite3SelectExpand() called on this */
    ++#define SF_HasTypeInfo    0x00080  /* FROM subqueries have Table metadata */
    ++#define SF_Compound       0x00100  /* Part of a compound query */
    ++#define SF_Values         0x00200  /* Synthesized from VALUES clause */
    ++#define SF_MultiValue     0x00400  /* Single VALUES term with multiple rows */
    ++#define SF_NestedFrom     0x00800  /* Part of a parenthesized FROM clause */
    ++#define SF_MinMaxAgg      0x01000  /* Aggregate containing min() or max() */
    ++#define SF_Recursive      0x02000  /* The recursive part of a recursive CTE */
    ++#define SF_FixedLimit     0x04000  /* nSelectRow set by a constant LIMIT */
    ++#define SF_MaybeConvert   0x08000  /* Need convertCompoundSelectToSubquery() */
    ++#define SF_Converted      0x10000  /* By convertCompoundSelectToSubquery() */
    ++#define SF_IncludeHidden  0x20000  /* Include hidden columns in output */
    ++#define SF_ComplexResult  0x40000  /* Result set contains subquery or function */
    + 
    + 
    + /*
    +@@ -13027,7 +16662,7 @@ struct Select {
    + ** by one of the following macros.  The "SRT" prefix means "SELECT Result
    + ** Type".
    + **
    +-**     SRT_Union       Store results as a key in a temporary index 
    ++**     SRT_Union       Store results as a key in a temporary index
    + **                     identified by pDest->iSDParm.
    + **
    + **     SRT_Except      Remove results from the temporary index pDest->iSDParm.
    +@@ -13051,7 +16686,7 @@ struct Select {
    + **                     of the query.  This destination implies "LIMIT 1".
    + **
    + **     SRT_Set         The result must be a single column.  Store each
    +-**                     row of result as the key in table pDest->iSDParm. 
    ++**                     row of result as the key in table pDest->iSDParm.
    + **                     Apply the affinity pDest->affSdst before storing
    + **                     results.  Used to implement "IN (SELECT ...)".
    + **
    +@@ -13111,19 +16746,19 @@ struct Select {
    + */
    + struct SelectDest {
    +   u8 eDest;            /* How to dispose of the results.  On of SRT_* above. */
    +-  char affSdst;        /* Affinity used when eDest==SRT_Set */
    +   int iSDParm;         /* A parameter used by the eDest disposal method */
    +   int iSdst;           /* Base register where results are written */
    +   int nSdst;           /* Number of registers allocated */
    ++  char *zAffSdst;      /* Affinity used when eDest==SRT_Set */
    +   ExprList *pOrderBy;  /* Key columns for SRT_Queue and SRT_DistQueue */
    + };
    + 
    + /*
    +-** During code generation of statements that do inserts into AUTOINCREMENT 
    ++** During code generation of statements that do inserts into AUTOINCREMENT
    + ** tables, the following information is attached to the Table.u.autoInc.p
    + ** pointer of each autoincrement table to record some side information that
    + ** the code generator needs.  We have to keep per-table autoincrement
    +-** information in case inserts are down within triggers.  Triggers do not
    ++** information in case inserts are done within triggers.  Triggers do not
    + ** normally coordinate their activities, but we do need to coordinate the
    + ** loading and saving of autoincrement information.
    + */
    +@@ -13142,7 +16777,7 @@ struct AutoincInfo {
    + #endif
    + 
    + /*
    +-** At least one instance of the following structure is created for each 
    ++** At least one instance of the following structure is created for each
    + ** trigger that may be fired while parsing an INSERT, UPDATE or DELETE
    + ** statement. All such objects are stored in the linked list headed at
    + ** Parse.pTriggerPrg and deleted once statement compilation has been
    +@@ -13155,7 +16790,7 @@ struct AutoincInfo {
    + ** values for both pTrigger and orconf.
    + **
    + ** The TriggerPrg.aColmask[0] variable is set to a mask of old.* columns
    +-** accessed (or set to 0 for triggers fired as a result of INSERT 
    ++** accessed (or set to 0 for triggers fired as a result of INSERT
    + ** statements). Similarly, the TriggerPrg.aColmask[1] variable is set to
    + ** a mask of new.* columns used by the program.
    + */
    +@@ -13196,7 +16831,7 @@ struct TriggerPrg {
    + ** is constant but the second part is reset at the beginning and end of
    + ** each recursion.
    + **
    +-** The nTableLock and aTableLock variables are only used if the shared-cache 
    ++** The nTableLock and aTableLock variables are only used if the shared-cache
    + ** feature is enabled (if sqlite3Tsd()->useSharedData is true). They are
    + ** used to store the set of table-locks required by the statement being
    + ** compiled. Function sqlite3TableLock() is used to add entries to the
    +@@ -13215,35 +16850,25 @@ struct Parse {
    +   u8 mayAbort;         /* True if statement may throw an ABORT exception */
    +   u8 hasCompound;      /* Need to invoke convertCompoundSelectToSubquery() */
    +   u8 okConstFactor;    /* OK to factor out constants */
    +-  int aTempReg[8];     /* Holding area for temporary registers */
    ++  u8 disableLookaside; /* Number of times lookaside has been disabled */
    ++  u8 nColCache;        /* Number of entries in aColCache[] */
    +   int nRangeReg;       /* Size of the temporary register block */
    +   int iRangeReg;       /* First register in temporary register block */
    +   int nErr;            /* Number of errors seen */
    +   int nTab;            /* Number of previously allocated VDBE cursors */
    +   int nMem;            /* Number of memory cells used so far */
    +-  int nSet;            /* Number of sets used so far */
    +-  int nOnce;           /* Number of OP_Once instructions so far */
    +   int nOpAlloc;        /* Number of slots allocated for Vdbe.aOp[] */
    +-  int iFixedOp;        /* Never back out opcodes iFixedOp-1 or earlier */
    +-  int ckBase;          /* Base register of data during check constraints */
    +-  int iSelfTab;        /* Table of an index whose exprs are being coded */
    ++  int szOpAlloc;       /* Bytes of memory space allocated for Vdbe.aOp[] */
    ++  int iSelfTab;        /* Table associated with an index on expr, or negative
    ++                       ** of the base register during check-constraint eval */
    +   int iCacheLevel;     /* ColCache valid when aColCache[].iLevel<=iCacheLevel */
    +   int iCacheCnt;       /* Counter used to generate aColCache[].lru values */
    +   int nLabel;          /* Number of labels used */
    +   int *aLabel;         /* Space to hold the labels */
    +-  struct yColCache {
    +-    int iTable;           /* Table cursor number */
    +-    i16 iColumn;          /* Table column number */
    +-    u8 tempReg;           /* iReg is a temp register that needs to be freed */
    +-    int iLevel;           /* Nesting level */
    +-    int iReg;             /* Reg with value of this column. 0 means none. */
    +-    int lru;              /* Least recently used entry has the smallest value */
    +-  } aColCache[SQLITE_N_COLCACHE];  /* One for each column cache entry */
    +   ExprList *pConstExpr;/* Constant expressions */
    +   Token constraintName;/* Name of the constraint currently being parsed */
    +   yDbMask writeMask;   /* Start a write transaction on these databases */
    +   yDbMask cookieMask;  /* Bitmask of schema verified databases */
    +-  int cookieValue[SQLITE_MAX_ATTACHED+2];  /* Values of cookies to verify */
    +   int regRowid;        /* Register holding rowid of CREATE TABLE entry */
    +   int regRoot;         /* Register holding root page number for new objects */
    +   int nMaxArg;         /* Max args passed to user function by sub-program */
    +@@ -13256,11 +16881,9 @@ struct Parse {
    +   TableLock *aTableLock; /* Required table locks for shared-cache mode */
    + #endif
    +   AutoincInfo *pAinc;  /* Information about AUTOINCREMENT counters */
    +-
    +-  /* Information used while coding trigger programs. */
    +   Parse *pToplevel;    /* Parse structure for main program (or NULL) */
    +   Table *pTriggerTab;  /* Table triggers are being coded for */
    +-  int addrCrTab;       /* Address of OP_CreateTable opcode on CREATE TABLE */
    ++  int addrCrTab;       /* Address of OP_CreateBtree opcode on CREATE TABLE */
    +   u32 nQueryLoop;      /* Est number of iterations of a query (10*log2(N)) */
    +   u32 oldmask;         /* Mask of old.* columns referenced */
    +   u32 newmask;         /* Mask of new.* columns referenced */
    +@@ -13268,36 +16891,50 @@ struct Parse {
    +   u8 eOrconf;          /* Default ON CONFLICT policy for trigger steps */
    +   u8 disableTriggers;  /* True to disable triggers */
    + 
    ++  /**************************************************************************
    ++  ** Fields above must be initialized to zero.  The fields that follow,
    ++  ** down to the beginning of the recursive section, do not need to be
    ++  ** initialized as they will be set before being used.  The boundary is
    ++  ** determined by offsetof(Parse,aColCache).
    ++  **************************************************************************/
    ++
    ++  struct yColCache {
    ++    int iTable;           /* Table cursor number */
    ++    i16 iColumn;          /* Table column number */
    ++    u8 tempReg;           /* iReg is a temp register that needs to be freed */
    ++    int iLevel;           /* Nesting level */
    ++    int iReg;             /* Reg with value of this column. 0 means none. */
    ++    int lru;              /* Least recently used entry has the smallest value */
    ++  } aColCache[SQLITE_N_COLCACHE];  /* One for each column cache entry */
    ++  int aTempReg[8];        /* Holding area for temporary registers */
    ++  Token sNameToken;       /* Token with unqualified schema object name */
    ++
    +   /************************************************************************
    +   ** Above is constant between recursions.  Below is reset before and after
    +   ** each recursion.  The boundary between these two regions is determined
    +-  ** using offsetof(Parse,nVar) so the nVar field must be the first field
    +-  ** in the recursive region.
    ++  ** using offsetof(Parse,sLastToken) so the sLastToken field must be the
    ++  ** first field in the recursive region.
    +   ************************************************************************/
    + 
    +-  int nVar;                 /* Number of '?' variables seen in the SQL so far */
    +-  int nzVar;                /* Number of available slots in azVar[] */
    ++  Token sLastToken;       /* The last token parsed */
    ++  ynVar nVar;               /* Number of '?' variables seen in the SQL so far */
    +   u8 iPkSortOrder;          /* ASC or DESC for INTEGER PRIMARY KEY */
    +-  u8 bFreeWith;             /* True if pWith should be freed with parser */
    +   u8 explain;               /* True if the EXPLAIN flag is found on the query */
    + #ifndef SQLITE_OMIT_VIRTUALTABLE
    +   u8 declareVtab;           /* True if inside sqlite3_declare_vtab() */
    +   int nVtabLock;            /* Number of virtual tables to lock */
    + #endif
    +-  int nAlias;               /* Number of aliased result set columns */
    +   int nHeight;              /* Expression tree height of current sub-select */
    + #ifndef SQLITE_OMIT_EXPLAIN
    +   int iSelectId;            /* ID of current select for EXPLAIN output */
    +   int iNextSelectId;        /* Next available select ID for EXPLAIN output */
    + #endif
    +-  char **azVar;             /* Pointers to names of parameters */
    ++  VList *pVList;            /* Mapping between variable names and numbers */
    +   Vdbe *pReprepare;         /* VM being reprepared (sqlite3Reprepare()) */
    +   const char *zTail;        /* All SQL text past the last semicolon parsed */
    +   Table *pNewTable;         /* A table being constructed by CREATE TABLE */
    +   Trigger *pNewTrigger;     /* Trigger under construct by a CREATE TRIGGER */
    +   const char *zAuthContext; /* The 6th parameter to db->xAuth callbacks */
    +-  Token sNameToken;         /* Token with unqualified schema object name */
    +-  Token sLastToken;         /* The last token parsed */
    + #ifndef SQLITE_OMIT_VIRTUALTABLE
    +   Token sArg;               /* Complete text of a module argument */
    +   Table **apVtabLock;       /* Pointer to virtual tables needing locking */
    +@@ -13305,8 +16942,17 @@ struct Parse {
    +   Table *pZombieTab;        /* List of Table objects to delete after code gen */
    +   TriggerPrg *pTriggerPrg;  /* Linked list of coded triggers */
    +   With *pWith;              /* Current WITH clause, or NULL */
    ++  With *pWithToFree;        /* Free this WITH object at the end of the parse */
    + };
    + 
    ++/*
    ++** Sizes and pointers of various parts of the Parse object.
    ++*/
    ++#define PARSE_HDR_SZ offsetof(Parse,aColCache) /* Recursive part w/o aColCache*/
    ++#define PARSE_RECURSE_SZ offsetof(Parse,sLastToken)    /* Recursive part */
    ++#define PARSE_TAIL_SZ (sizeof(Parse)-PARSE_RECURSE_SZ) /* Non-recursive part */
    ++#define PARSE_TAIL(X) (((char*)(X))+PARSE_RECURSE_SZ)  /* Pointer to tail */
    ++
    + /*
    + ** Return true if currently inside an sqlite3_declare_vtab() call.
    + */
    +@@ -13327,26 +16973,41 @@ struct AuthContext {
    + 
    + /*
    + ** Bitfield flags for P5 value in various opcodes.
    +-*/
    +-#define OPFLAG_NCHANGE       0x01    /* Set to update db->nChange */
    ++**
    ++** Value constraints (enforced via assert()):
    ++**    OPFLAG_LENGTHARG    == SQLITE_FUNC_LENGTH
    ++**    OPFLAG_TYPEOFARG    == SQLITE_FUNC_TYPEOF
    ++**    OPFLAG_BULKCSR      == BTREE_BULKLOAD
    ++**    OPFLAG_SEEKEQ       == BTREE_SEEK_EQ
    ++**    OPFLAG_FORDELETE    == BTREE_FORDELETE
    ++**    OPFLAG_SAVEPOSITION == BTREE_SAVEPOSITION
    ++**    OPFLAG_AUXDELETE    == BTREE_AUXDELETE
    ++*/
    ++#define OPFLAG_NCHANGE       0x01    /* OP_Insert: Set to update db->nChange */
    ++                                     /* Also used in P2 (not P5) of OP_Delete */
    + #define OPFLAG_EPHEM         0x01    /* OP_Column: Ephemeral output is ok */
    +-#define OPFLAG_LASTROWID     0x02    /* Set to update db->lastRowid */
    ++#define OPFLAG_LASTROWID     0x20    /* Set to update db->lastRowid */
    + #define OPFLAG_ISUPDATE      0x04    /* This OP_Insert is an sql UPDATE */
    + #define OPFLAG_APPEND        0x08    /* This is likely to be an append */
    + #define OPFLAG_USESEEKRESULT 0x10    /* Try to avoid a seek in BtreeInsert() */
    ++#define OPFLAG_ISNOOP        0x40    /* OP_Delete does pre-update-hook only */
    + #define OPFLAG_LENGTHARG     0x40    /* OP_Column only used for length() */
    + #define OPFLAG_TYPEOFARG     0x80    /* OP_Column only used for typeof() */
    + #define OPFLAG_BULKCSR       0x01    /* OP_Open** used to open bulk cursor */
    + #define OPFLAG_SEEKEQ        0x02    /* OP_Open** cursor uses EQ seek only */
    +-#define OPFLAG_P2ISREG       0x04    /* P2 to OP_Open** is a register number */
    ++#define OPFLAG_FORDELETE     0x08    /* OP_Open should use BTREE_FORDELETE */
    ++#define OPFLAG_P2ISREG       0x10    /* P2 to OP_Open** is a register number */
    + #define OPFLAG_PERMUTE       0x01    /* OP_Compare: use the permutation */
    ++#define OPFLAG_SAVEPOSITION  0x02    /* OP_Delete/Insert: save cursor pos */
    ++#define OPFLAG_AUXDELETE     0x04    /* OP_Delete: index in a DELETE op */
    ++#define OPFLAG_NOCHNG_MAGIC  0x6d    /* OP_MakeRecord: serialtype 10 is ok */
    + 
    + /*
    +  * Each trigger present in the database schema is stored as an instance of
    +- * struct Trigger. 
    ++ * struct Trigger.
    +  *
    +  * Pointers to instances of struct Trigger are stored in two ways.
    +- * 1. In the "trigHash" hash table (part of the sqlite3* that represents the 
    ++ * 1. In the "trigHash" hash table (part of the sqlite3* that represents the
    +  *    database). This allows Trigger structures to be retrieved by name.
    +  * 2. All triggers associated with a single table form a linked list, using the
    +  *    pNext member of struct Trigger. A pointer to the first element of the
    +@@ -13372,7 +17033,7 @@ struct Trigger {
    + 
    + /*
    + ** A trigger is either a BEFORE or an AFTER trigger.  The following constants
    +-** determine which. 
    ++** determine which.
    + **
    + ** If there are multiple triggers, you might of some BEFORE and some AFTER.
    + ** In that cases, the constants below can be ORed together.
    +@@ -13382,15 +17043,15 @@ struct Trigger {
    + 
    + /*
    +  * An instance of struct TriggerStep is used to store a single SQL statement
    +- * that is a part of a trigger-program. 
    ++ * that is a part of a trigger-program.
    +  *
    +  * Instances of struct TriggerStep are stored in a singly linked list (linked
    +- * using the "pNext" member) referenced by the "step_list" member of the 
    ++ * using the "pNext" member) referenced by the "step_list" member of the
    +  * associated struct Trigger instance. The first element of the linked list is
    +  * the first step of the trigger-program.
    +- * 
    ++ *
    +  * The "op" member indicates whether this is a "DELETE", "INSERT", "UPDATE" or
    +- * "SELECT" statement. The meanings of the other members is determined by the 
    ++ * "SELECT" statement. The meanings of the other members is determined by the
    +  * value of "op" as follows:
    +  *
    +  * (op == TK_INSERT)
    +@@ -13400,7 +17061,7 @@ struct Trigger {
    +  * zTarget   -> Dequoted name of the table to insert into.
    +  * pExprList -> If this is an INSERT INTO ... VALUES ... statement, then
    +  *              this stores values to be inserted. Otherwise NULL.
    +- * pIdList   -> If this is an INSERT INTO ... (<column-names>) VALUES ... 
    ++ * pIdList   -> If this is an INSERT INTO ... (<column-names>) VALUES ...
    +  *              statement, then this stores the column-names to be
    +  *              inserted into.
    +  *
    +@@ -13408,7 +17069,7 @@ struct Trigger {
    +  * zTarget   -> Dequoted name of the table to delete from.
    +  * pWhere    -> The WHERE clause of the DELETE statement if one is specified.
    +  *              Otherwise NULL.
    +- * 
    ++ *
    +  * (op == TK_UPDATE)
    +  * zTarget   -> Dequoted name of the table to update.
    +  * pWhere    -> The WHERE clause of the UPDATE statement if one is specified.
    +@@ -13416,7 +17077,7 @@ struct Trigger {
    +  * pExprList -> A list of the columns to update and the expressions to update
    +  *              them to. See sqlite3Update() documentation of "pChanges"
    +  *              argument.
    +- * 
    ++ *
    +  */
    + struct TriggerStep {
    +   u8 op;               /* One of TK_DELETE, TK_UPDATE, TK_INSERT, TK_SELECT */
    +@@ -13427,6 +17088,7 @@ struct TriggerStep {
    +   Expr *pWhere;        /* The WHERE clause for DELETE or UPDATE steps */
    +   ExprList *pExprList; /* SET clause for UPDATE. */
    +   IdList *pIdList;     /* Column names for INSERT */
    ++  char *zSpan;         /* Original SQL text of this command */
    +   TriggerStep *pNext;  /* Next in the link-list */
    +   TriggerStep *pLast;  /* Last element in link-list. Valid for 1st elem only */
    + };
    +@@ -13434,7 +17096,7 @@ struct TriggerStep {
    + /*
    + ** The following structure contains information used by the sqliteFix...
    + ** routines as they walk the parse tree to make database references
    +-** explicit.  
    ++** explicit.
    + */
    + typedef struct DbFixer DbFixer;
    + struct DbFixer {
    +@@ -13452,15 +17114,21 @@ struct DbFixer {
    + */
    + struct StrAccum {
    +   sqlite3 *db;         /* Optional database for lookaside.  Can be NULL */
    +-  char *zBase;         /* A base allocation.  Not from malloc. */
    +   char *zText;         /* The string collected so far */
    +-  int  nChar;          /* Length of the string so far */
    +-  int  nAlloc;         /* Amount of space allocated in zText */
    +-  int  mxAlloc;        /* Maximum allowed allocation.  0 for no malloc usage */
    ++  u32  nAlloc;         /* Amount of space allocated in zText */
    ++  u32  mxAlloc;        /* Maximum allowed allocation.  0 for no malloc usage */
    ++  u32  nChar;          /* Length of the string so far */
    +   u8   accError;       /* STRACCUM_NOMEM or STRACCUM_TOOBIG */
    ++  u8   printfFlags;    /* SQLITE_PRINTF flags below */
    + };
    + #define STRACCUM_NOMEM   1
    + #define STRACCUM_TOOBIG  2
    ++#define SQLITE_PRINTF_INTERNAL 0x01  /* Internal-use-only converters allowed */
    ++#define SQLITE_PRINTF_SQLFUNC  0x02  /* SQL function arguments to VXPrintf */
    ++#define SQLITE_PRINTF_MALLOCED 0x04  /* True if xText is allocated space */
    ++
    ++#define isMalloced(X)  (((X)->printfFlags & SQLITE_PRINTF_MALLOCED)!=0)
    ++
    + 
    + /*
    + ** A pointer to this structure is used to communicate information
    +@@ -13484,10 +17152,12 @@ struct Sqlite3Config {
    +   int bFullMutex;                   /* True to enable full mutexing */
    +   int bOpenUri;                     /* True to interpret filenames as URIs */
    +   int bUseCis;                      /* Use covering indices for full-scans */
    ++  int bSmallMalloc;                 /* Avoid large memory allocations if true */
    +   int mxStrlen;                     /* Maximum string length */
    +   int neverCorrupt;                 /* Database is always well-formed */
    +   int szLookaside;                  /* Default lookaside buffer size */
    +   int nLookaside;                   /* Default lookaside buffer count */
    ++  int nStmtSpill;                   /* Stmt-journal spill-to-disk threshold */
    +   sqlite3_mem_methods m;            /* Low-level memory allocation interface */
    +   sqlite3_mutex_methods mutex;      /* Low-level mutex interface */
    +   sqlite3_pcache_methods2 pcache2;  /* Low-level page-cache interface */
    +@@ -13496,9 +17166,6 @@ struct Sqlite3Config {
    +   int mnReq, mxReq;                 /* Min and max heap requests sizes */
    +   sqlite3_int64 szMmap;             /* mmap() space per open file */
    +   sqlite3_int64 mxMmap;             /* Maximum value for szMmap */
    +-  void *pScratch;                   /* Scratch memory */
    +-  int szScratch;                    /* Size of each scratch buffer */
    +-  int nScratch;                     /* Number of scratch buffers */
    +   void *pPage;                      /* Page cache memory */
    +   int szPage;                       /* Size of each page in pPage[] */
    +   int nPage;                        /* Number of pages in pPage[] */
    +@@ -13527,10 +17194,11 @@ struct Sqlite3Config {
    +   void (*xVdbeBranch)(void*,int iSrcLine,u8 eThis,u8 eMx);  /* Callback */
    +   void *pVdbeBranchArg;                                     /* 1st argument */
    + #endif
    +-#ifndef SQLITE_OMIT_BUILTIN_TEST
    ++#ifndef SQLITE_UNTESTABLE
    +   int (*xTestCallback)(int);        /* Invoked by sqlite3FaultSim() */
    + #endif
    +   int bLocaltimeFault;              /* True to fail localtime() calls */
    ++  int iOnceResetThreshold;          /* When to reset OP_Once counters */
    + };
    + 
    + /*
    +@@ -13555,18 +17223,24 @@ struct Sqlite3Config {
    + ** Context pointer passed down through the tree-walk.
    + */
    + struct Walker {
    ++  Parse *pParse;                            /* Parser context.  */
    +   int (*xExprCallback)(Walker*, Expr*);     /* Callback for expressions */
    +   int (*xSelectCallback)(Walker*,Select*);  /* Callback for SELECTs */
    +   void (*xSelectCallback2)(Walker*,Select*);/* Second callback for SELECTs */
    +-  Parse *pParse;                            /* Parser context.  */
    +   int walkerDepth;                          /* Number of subqueries */
    +   u8 eCode;                                 /* A small processing code */
    +   union {                                   /* Extra data for callback */
    +-    NameContext *pNC;                          /* Naming context */
    +-    int n;                                     /* A counter */
    +-    int iCur;                                  /* A cursor number */
    +-    SrcList *pSrcList;                         /* FROM clause */
    +-    struct SrcCount *pSrcCount;                /* Counting column references */
    ++    NameContext *pNC;                         /* Naming context */
    ++    int n;                                    /* A counter */
    ++    int iCur;                                 /* A cursor number */
    ++    SrcList *pSrcList;                        /* FROM clause */
    ++    struct SrcCount *pSrcCount;               /* Counting column references */
    ++    struct CCurHint *pCCurHint;               /* Used by codeCursorHint() */
    ++    int *aiCol;                               /* array of column indexes */
    ++    struct IdxCover *pIdxCover;               /* Check for index coverage */
    ++    struct IdxExprTrans *pIdxTrans;           /* Convert indexed expr to column */
    ++    ExprList *pGroupBy;                       /* GROUP BY clause */
    ++    struct HavingToWhereCtx *pHavingCtx;      /* HAVING to WHERE clause ctx */
    +   } u;
    + };
    + 
    +@@ -13576,6 +17250,12 @@ SQLITE_PRIVATE int sqlite3WalkExprList(Walker*, ExprList*);
    + SQLITE_PRIVATE int sqlite3WalkSelect(Walker*, Select*);
    + SQLITE_PRIVATE int sqlite3WalkSelectExpr(Walker*, Select*);
    + SQLITE_PRIVATE int sqlite3WalkSelectFrom(Walker*, Select*);
    ++SQLITE_PRIVATE int sqlite3ExprWalkNoop(Walker*, Expr*);
    ++SQLITE_PRIVATE int sqlite3SelectWalkNoop(Walker*, Select*);
    ++SQLITE_PRIVATE int sqlite3SelectWalkFail(Walker*, Select*);
    ++#ifdef SQLITE_DEBUG
    ++SQLITE_PRIVATE void sqlite3SelectWalkAssert2(Walker*, Select*);
    ++#endif
    + 
    + /*
    + ** Return code from the parse-tree walking primitives and their
    +@@ -13628,13 +17308,33 @@ struct TreeView {
    + ** using sqlite3_log().  The routines also provide a convenient place
    + ** to set a debugger breakpoint.
    + */
    ++SQLITE_PRIVATE int sqlite3ReportError(int iErr, int lineno, const char *zType);
    + SQLITE_PRIVATE int sqlite3CorruptError(int);
    + SQLITE_PRIVATE int sqlite3MisuseError(int);
    + SQLITE_PRIVATE int sqlite3CantopenError(int);
    + #define SQLITE_CORRUPT_BKPT sqlite3CorruptError(__LINE__)
    + #define SQLITE_MISUSE_BKPT sqlite3MisuseError(__LINE__)
    + #define SQLITE_CANTOPEN_BKPT sqlite3CantopenError(__LINE__)
    ++#ifdef SQLITE_DEBUG
    ++SQLITE_PRIVATE   int sqlite3NomemError(int);
    ++SQLITE_PRIVATE   int sqlite3IoerrnomemError(int);
    ++SQLITE_PRIVATE   int sqlite3CorruptPgnoError(int,Pgno);
    ++# define SQLITE_NOMEM_BKPT sqlite3NomemError(__LINE__)
    ++# define SQLITE_IOERR_NOMEM_BKPT sqlite3IoerrnomemError(__LINE__)
    ++# define SQLITE_CORRUPT_PGNO(P) sqlite3CorruptPgnoError(__LINE__,(P))
    ++#else
    ++# define SQLITE_NOMEM_BKPT SQLITE_NOMEM
    ++# define SQLITE_IOERR_NOMEM_BKPT SQLITE_IOERR_NOMEM
    ++# define SQLITE_CORRUPT_PGNO(P) sqlite3CorruptError(__LINE__)
    ++#endif
    + 
    ++/*
    ++** FTS3 and FTS4 both require virtual table support
    ++*/
    ++#if defined(SQLITE_OMIT_VIRTUALTABLE)
    ++# undef SQLITE_ENABLE_FTS3
    ++# undef SQLITE_ENABLE_FTS4
    ++#endif
    + 
    + /*
    + ** FTS4 is really an extension for FTS3.  It is enabled using the
    +@@ -13667,6 +17367,7 @@ SQLITE_PRIVATE int sqlite3CantopenError(int);
    + # define sqlite3Isdigit(x)   (sqlite3CtypeMap[(unsigned char)(x)]&0x04)
    + # define sqlite3Isxdigit(x)  (sqlite3CtypeMap[(unsigned char)(x)]&0x08)
    + # define sqlite3Tolower(x)   (sqlite3UpperToLower[(unsigned char)(x)])
    ++# define sqlite3Isquote(x)   (sqlite3CtypeMap[(unsigned char)(x)]&0x80)
    + #else
    + # define sqlite3Toupper(x)   toupper((unsigned char)(x))
    + # define sqlite3Isspace(x)   isspace((unsigned char)(x))
    +@@ -13675,6 +17376,7 @@ SQLITE_PRIVATE int sqlite3CantopenError(int);
    + # define sqlite3Isdigit(x)   isdigit((unsigned char)(x))
    + # define sqlite3Isxdigit(x)  isxdigit((unsigned char)(x))
    + # define sqlite3Tolower(x)   tolower((unsigned char)(x))
    ++# define sqlite3Isquote(x)   ((x)=='"'||(x)=='\''||(x)=='['||(x)=='`')
    + #endif
    + #ifndef SQLITE_OMIT_COMPILEOPTION_DIAGS
    + SQLITE_PRIVATE int sqlite3IsIdChar(u8);
    +@@ -13683,8 +17385,9 @@ SQLITE_PRIVATE int sqlite3IsIdChar(u8);
    + /*
    + ** Internal function prototypes
    + */
    +-#define sqlite3StrICmp sqlite3_stricmp
    ++SQLITE_PRIVATE int sqlite3StrICmp(const char*,const char*);
    + SQLITE_PRIVATE int sqlite3Strlen30(const char*);
    ++SQLITE_PRIVATE char *sqlite3ColumnType(Column*,char*);
    + #define sqlite3StrNICmp sqlite3_strnicmp
    + 
    + SQLITE_PRIVATE int sqlite3MallocInit(void);
    +@@ -13693,20 +17396,21 @@ SQLITE_PRIVATE void *sqlite3Malloc(u64);
    + SQLITE_PRIVATE void *sqlite3MallocZero(u64);
    + SQLITE_PRIVATE void *sqlite3DbMallocZero(sqlite3*, u64);
    + SQLITE_PRIVATE void *sqlite3DbMallocRaw(sqlite3*, u64);
    ++SQLITE_PRIVATE void *sqlite3DbMallocRawNN(sqlite3*, u64);
    + SQLITE_PRIVATE char *sqlite3DbStrDup(sqlite3*,const char*);
    + SQLITE_PRIVATE char *sqlite3DbStrNDup(sqlite3*,const char*, u64);
    ++SQLITE_PRIVATE char *sqlite3DbSpanDup(sqlite3*,const char*,const char*);
    + SQLITE_PRIVATE void *sqlite3Realloc(void*, u64);
    + SQLITE_PRIVATE void *sqlite3DbReallocOrFree(sqlite3 *, void *, u64);
    + SQLITE_PRIVATE void *sqlite3DbRealloc(sqlite3 *, void *, u64);
    + SQLITE_PRIVATE void sqlite3DbFree(sqlite3*, void*);
    ++SQLITE_PRIVATE void sqlite3DbFreeNN(sqlite3*, void*);
    + SQLITE_PRIVATE int sqlite3MallocSize(void*);
    + SQLITE_PRIVATE int sqlite3DbMallocSize(sqlite3*, void*);
    +-SQLITE_PRIVATE void *sqlite3ScratchMalloc(int);
    +-SQLITE_PRIVATE void sqlite3ScratchFree(void*);
    + SQLITE_PRIVATE void *sqlite3PageMalloc(int);
    + SQLITE_PRIVATE void sqlite3PageFree(void*);
    + SQLITE_PRIVATE void sqlite3MemSetDefault(void);
    +-#ifndef SQLITE_OMIT_BUILTIN_TEST
    ++#ifndef SQLITE_UNTESTABLE
    + SQLITE_PRIVATE void sqlite3BenignMallocHooks(void (*)(void), void (*)(void));
    + #endif
    + SQLITE_PRIVATE int sqlite3HeapNearlyFull(void);
    +@@ -13722,18 +17426,22 @@ SQLITE_PRIVATE int sqlite3HeapNearlyFull(void);
    + #ifdef SQLITE_USE_ALLOCA
    + # define sqlite3StackAllocRaw(D,N)   alloca(N)
    + # define sqlite3StackAllocZero(D,N)  memset(alloca(N), 0, N)
    +-# define sqlite3StackFree(D,P)       
    ++# define sqlite3StackFree(D,P)
    + #else
    + # define sqlite3StackAllocRaw(D,N)   sqlite3DbMallocRaw(D,N)
    + # define sqlite3StackAllocZero(D,N)  sqlite3DbMallocZero(D,N)
    + # define sqlite3StackFree(D,P)       sqlite3DbFree(D,P)
    + #endif
    + 
    +-#ifdef SQLITE_ENABLE_MEMSYS3
    +-SQLITE_PRIVATE const sqlite3_mem_methods *sqlite3MemGetMemsys3(void);
    +-#endif
    ++/* Do not allow both MEMSYS5 and MEMSYS3 to be defined together.  If they
    ++** are, disable MEMSYS3
    ++*/
    + #ifdef SQLITE_ENABLE_MEMSYS5
    + SQLITE_PRIVATE const sqlite3_mem_methods *sqlite3MemGetMemsys5(void);
    ++#undef SQLITE_ENABLE_MEMSYS3
    ++#endif
    ++#ifdef SQLITE_ENABLE_MEMSYS3
    ++SQLITE_PRIVATE const sqlite3_mem_methods *sqlite3MemGetMemsys3(void);
    + #endif
    + 
    + 
    +@@ -13753,12 +17461,19 @@ SQLITE_PRIVATE   void sqlite3MemoryBarrier(void);
    + SQLITE_PRIVATE sqlite3_int64 sqlite3StatusValue(int);
    + SQLITE_PRIVATE void sqlite3StatusUp(int, int);
    + SQLITE_PRIVATE void sqlite3StatusDown(int, int);
    +-SQLITE_PRIVATE void sqlite3StatusSet(int, int);
    ++SQLITE_PRIVATE void sqlite3StatusHighwater(int, int);
    ++SQLITE_PRIVATE int sqlite3LookasideUsed(sqlite3*,int*);
    + 
    + /* Access to mutexes used by sqlite3_status() */
    + SQLITE_PRIVATE sqlite3_mutex *sqlite3Pcache1Mutex(void);
    + SQLITE_PRIVATE sqlite3_mutex *sqlite3MallocMutex(void);
    + 
    ++#if defined(SQLITE_ENABLE_MULTITHREADED_CHECKS) && !defined(SQLITE_MUTEX_OMIT)
    ++SQLITE_PRIVATE void sqlite3MutexWarnOnContention(sqlite3_mutex*);
    ++#else
    ++# define sqlite3MutexWarnOnContention(x)
    ++#endif
    ++
    + #ifndef SQLITE_OMIT_FLOATING_POINT
    + SQLITE_PRIVATE   int sqlite3IsNaN(double);
    + #else
    +@@ -13775,10 +17490,8 @@ struct PrintfArguments {
    +   sqlite3_value **apArg;   /* The argument values */
    + };
    + 
    +-#define SQLITE_PRINTF_INTERNAL 0x01
    +-#define SQLITE_PRINTF_SQLFUNC  0x02
    +-SQLITE_PRIVATE void sqlite3VXPrintf(StrAccum*, u32, const char*, va_list);
    +-SQLITE_PRIVATE void sqlite3XPrintf(StrAccum*, u32, const char*, ...);
    ++SQLITE_PRIVATE void sqlite3VXPrintf(StrAccum*, const char*, va_list);
    ++SQLITE_PRIVATE void sqlite3XPrintf(StrAccum*, const char*, ...);
    + SQLITE_PRIVATE char *sqlite3MPrintf(sqlite3*,const char*, ...);
    + SQLITE_PRIVATE char *sqlite3VMPrintf(sqlite3*,const char*, va_list);
    + #if defined(SQLITE_DEBUG) || defined(SQLITE_HAVE_OS_TRACE)
    +@@ -13790,14 +17503,17 @@ SQLITE_PRIVATE   void *sqlite3TestTextToPtr(const char*);
    + 
    + #if defined(SQLITE_DEBUG)
    + SQLITE_PRIVATE   void sqlite3TreeViewExpr(TreeView*, const Expr*, u8);
    ++SQLITE_PRIVATE   void sqlite3TreeViewBareExprList(TreeView*, const ExprList*, const char*);
    + SQLITE_PRIVATE   void sqlite3TreeViewExprList(TreeView*, const ExprList*, u8, const char*);
    + SQLITE_PRIVATE   void sqlite3TreeViewSelect(TreeView*, const Select*, u8);
    ++SQLITE_PRIVATE   void sqlite3TreeViewWith(TreeView*, const With*, u8);
    + #endif
    + 
    + 
    + SQLITE_PRIVATE void sqlite3SetString(char **, sqlite3*, const char*);
    + SQLITE_PRIVATE void sqlite3ErrorMsg(Parse*, const char*, ...);
    +-SQLITE_PRIVATE int sqlite3Dequote(char*);
    ++SQLITE_PRIVATE void sqlite3Dequote(char*);
    ++SQLITE_PRIVATE void sqlite3TokenInit(Token*,char*);
    + SQLITE_PRIVATE int sqlite3KeywordCode(const unsigned char*, int);
    + SQLITE_PRIVATE int sqlite3RunParser(Parse*, const char*, char **);
    + SQLITE_PRIVATE void sqlite3FinishCoding(Parse*);
    +@@ -13806,49 +17522,60 @@ SQLITE_PRIVATE void sqlite3ReleaseTempReg(Parse*,int);
    + SQLITE_PRIVATE int sqlite3GetTempRange(Parse*,int);
    + SQLITE_PRIVATE void sqlite3ReleaseTempRange(Parse*,int,int);
    + SQLITE_PRIVATE void sqlite3ClearTempRegCache(Parse*);
    ++#ifdef SQLITE_DEBUG
    ++SQLITE_PRIVATE int sqlite3NoTempsInRange(Parse*,int,int);
    ++#endif
    + SQLITE_PRIVATE Expr *sqlite3ExprAlloc(sqlite3*,int,const Token*,int);
    + SQLITE_PRIVATE Expr *sqlite3Expr(sqlite3*,int,const char*);
    + SQLITE_PRIVATE void sqlite3ExprAttachSubtrees(sqlite3*,Expr*,Expr*,Expr*);
    +-SQLITE_PRIVATE Expr *sqlite3PExpr(Parse*, int, Expr*, Expr*, const Token*);
    ++SQLITE_PRIVATE Expr *sqlite3PExpr(Parse*, int, Expr*, Expr*);
    ++SQLITE_PRIVATE void sqlite3PExprAddSelect(Parse*, Expr*, Select*);
    + SQLITE_PRIVATE Expr *sqlite3ExprAnd(sqlite3*,Expr*, Expr*);
    + SQLITE_PRIVATE Expr *sqlite3ExprFunction(Parse*,ExprList*, Token*);
    +-SQLITE_PRIVATE void sqlite3ExprAssignVarNumber(Parse*, Expr*);
    ++SQLITE_PRIVATE void sqlite3ExprAssignVarNumber(Parse*, Expr*, u32);
    + SQLITE_PRIVATE void sqlite3ExprDelete(sqlite3*, Expr*);
    + SQLITE_PRIVATE ExprList *sqlite3ExprListAppend(Parse*,ExprList*,Expr*);
    ++SQLITE_PRIVATE ExprList *sqlite3ExprListAppendVector(Parse*,ExprList*,IdList*,Expr*);
    + SQLITE_PRIVATE void sqlite3ExprListSetSortOrder(ExprList*,int);
    + SQLITE_PRIVATE void sqlite3ExprListSetName(Parse*,ExprList*,Token*,int);
    +-SQLITE_PRIVATE void sqlite3ExprListSetSpan(Parse*,ExprList*,ExprSpan*);
    ++SQLITE_PRIVATE void sqlite3ExprListSetSpan(Parse*,ExprList*,const char*,const char*);
    + SQLITE_PRIVATE void sqlite3ExprListDelete(sqlite3*, ExprList*);
    + SQLITE_PRIVATE u32 sqlite3ExprListFlags(const ExprList*);
    + SQLITE_PRIVATE int sqlite3Init(sqlite3*, char**);
    + SQLITE_PRIVATE int sqlite3InitCallback(void*, int, char**, char**);
    + SQLITE_PRIVATE void sqlite3Pragma(Parse*,Token*,Token*,Token*,int);
    ++#ifndef SQLITE_OMIT_VIRTUALTABLE
    ++SQLITE_PRIVATE Module *sqlite3PragmaVtabRegister(sqlite3*,const char *zName);
    ++#endif
    + SQLITE_PRIVATE void sqlite3ResetAllSchemasOfConnection(sqlite3*);
    + SQLITE_PRIVATE void sqlite3ResetOneSchema(sqlite3*,int);
    + SQLITE_PRIVATE void sqlite3CollapseDatabaseArray(sqlite3*);
    +-SQLITE_PRIVATE void sqlite3BeginParse(Parse*,int);
    + SQLITE_PRIVATE void sqlite3CommitInternalChanges(sqlite3*);
    + SQLITE_PRIVATE void sqlite3DeleteColumnNames(sqlite3*,Table*);
    + SQLITE_PRIVATE int sqlite3ColumnsFromExprList(Parse*,ExprList*,i16*,Column**);
    ++SQLITE_PRIVATE void sqlite3SelectAddColumnTypeAndCollation(Parse*,Table*,Select*);
    + SQLITE_PRIVATE Table *sqlite3ResultSetOfSelect(Parse*,Select*);
    + SQLITE_PRIVATE void sqlite3OpenMasterTable(Parse *, int);
    + SQLITE_PRIVATE Index *sqlite3PrimaryKeyIndex(Table*);
    + SQLITE_PRIVATE i16 sqlite3ColumnOfIndex(Index*, i16);
    + SQLITE_PRIVATE void sqlite3StartTable(Parse*,Token*,Token*,int,int,int,int);
    +-SQLITE_PRIVATE void sqlite3AddColumn(Parse*,Token*);
    ++#if SQLITE_ENABLE_HIDDEN_COLUMNS
    ++SQLITE_PRIVATE   void sqlite3ColumnPropertiesFromName(Table*, Column*);
    ++#else
    ++# define sqlite3ColumnPropertiesFromName(T,C) /* no-op */
    ++#endif
    ++SQLITE_PRIVATE void sqlite3AddColumn(Parse*,Token*,Token*);
    + SQLITE_PRIVATE void sqlite3AddNotNull(Parse*, int);
    + SQLITE_PRIVATE void sqlite3AddPrimaryKey(Parse*, ExprList*, int, int, int);
    + SQLITE_PRIVATE void sqlite3AddCheckConstraint(Parse*, Expr*);
    +-SQLITE_PRIVATE void sqlite3AddColumnType(Parse*,Token*);
    +-SQLITE_PRIVATE void sqlite3AddDefaultValue(Parse*,ExprSpan*);
    ++SQLITE_PRIVATE void sqlite3AddDefaultValue(Parse*,Expr*,const char*,const char*);
    + SQLITE_PRIVATE void sqlite3AddCollateType(Parse*, Token*);
    + SQLITE_PRIVATE void sqlite3EndTable(Parse*,Token*,Token*,u8,Select*);
    + SQLITE_PRIVATE int sqlite3ParseUri(const char*,const char*,unsigned int*,
    +                     sqlite3_vfs**,char**,char **);
    + SQLITE_PRIVATE Btree *sqlite3DbNameToBtree(sqlite3*,const char*);
    +-SQLITE_PRIVATE int sqlite3CodeOnce(Parse *);
    + 
    +-#ifdef SQLITE_OMIT_BUILTIN_TEST
    ++#ifdef SQLITE_UNTESTABLE
    + # define sqlite3FaultSim(X) SQLITE_OK
    + #else
    + SQLITE_PRIVATE   int sqlite3FaultSim(int);
    +@@ -13861,7 +17588,7 @@ SQLITE_PRIVATE int sqlite3BitvecSet(Bitvec*, u32);
    + SQLITE_PRIVATE void sqlite3BitvecClear(Bitvec*, u32, void*);
    + SQLITE_PRIVATE void sqlite3BitvecDestroy(Bitvec*);
    + SQLITE_PRIVATE u32 sqlite3BitvecSize(Bitvec*);
    +-#ifndef SQLITE_OMIT_BUILTIN_TEST
    ++#ifndef SQLITE_UNTESTABLE
    + SQLITE_PRIVATE int sqlite3BitvecBuiltinTest(int,int*);
    + #endif
    + 
    +@@ -13908,26 +17635,27 @@ SQLITE_PRIVATE void sqlite3SrcListAssignCursors(Parse*, SrcList*);
    + SQLITE_PRIVATE void sqlite3IdListDelete(sqlite3*, IdList*);
    + SQLITE_PRIVATE void sqlite3SrcListDelete(sqlite3*, SrcList*);
    + SQLITE_PRIVATE Index *sqlite3AllocateIndexObject(sqlite3*,i16,int,char**);
    +-SQLITE_PRIVATE Index *sqlite3CreateIndex(Parse*,Token*,Token*,SrcList*,ExprList*,int,Token*,
    +-                          Expr*, int, int);
    ++SQLITE_PRIVATE void sqlite3CreateIndex(Parse*,Token*,Token*,SrcList*,ExprList*,int,Token*,
    ++                          Expr*, int, int, u8);
    + SQLITE_PRIVATE void sqlite3DropIndex(Parse*, SrcList*, int);
    + SQLITE_PRIVATE int sqlite3Select(Parse*, Select*, SelectDest*);
    + SQLITE_PRIVATE Select *sqlite3SelectNew(Parse*,ExprList*,SrcList*,Expr*,ExprList*,
    +-                         Expr*,ExprList*,u16,Expr*,Expr*);
    ++                         Expr*,ExprList*,u32,Expr*);
    + SQLITE_PRIVATE void sqlite3SelectDelete(sqlite3*, Select*);
    + SQLITE_PRIVATE Table *sqlite3SrcListLookup(Parse*, SrcList*);
    + SQLITE_PRIVATE int sqlite3IsReadOnly(Parse*, Table*, int);
    + SQLITE_PRIVATE void sqlite3OpenTable(Parse*, int iCur, int iDb, Table*, int);
    + #if defined(SQLITE_ENABLE_UPDATE_DELETE_LIMIT) && !defined(SQLITE_OMIT_SUBQUERY)
    +-SQLITE_PRIVATE Expr *sqlite3LimitWhere(Parse*,SrcList*,Expr*,ExprList*,Expr*,Expr*,char*);
    ++SQLITE_PRIVATE Expr *sqlite3LimitWhere(Parse*,SrcList*,Expr*,ExprList*,Expr*,char*);
    + #endif
    +-SQLITE_PRIVATE void sqlite3DeleteFrom(Parse*, SrcList*, Expr*);
    +-SQLITE_PRIVATE void sqlite3Update(Parse*, SrcList*, ExprList*, Expr*, int);
    ++SQLITE_PRIVATE void sqlite3DeleteFrom(Parse*, SrcList*, Expr*, ExprList*, Expr*);
    ++SQLITE_PRIVATE void sqlite3Update(Parse*, SrcList*, ExprList*,Expr*,int,ExprList*,Expr*);
    + SQLITE_PRIVATE WhereInfo *sqlite3WhereBegin(Parse*,SrcList*,Expr*,ExprList*,ExprList*,u16,int);
    + SQLITE_PRIVATE void sqlite3WhereEnd(WhereInfo*);
    +-SQLITE_PRIVATE u64 sqlite3WhereOutputRowCount(WhereInfo*);
    ++SQLITE_PRIVATE LogEst sqlite3WhereOutputRowCount(WhereInfo*);
    + SQLITE_PRIVATE int sqlite3WhereIsDistinct(WhereInfo*);
    + SQLITE_PRIVATE int sqlite3WhereIsOrdered(WhereInfo*);
    ++SQLITE_PRIVATE int sqlite3WhereOrderedInnerLoop(WhereInfo*);
    + SQLITE_PRIVATE int sqlite3WhereIsSorted(WhereInfo*);
    + SQLITE_PRIVATE int sqlite3WhereContinueLabel(WhereInfo*);
    + SQLITE_PRIVATE int sqlite3WhereBreakLabel(WhereInfo*);
    +@@ -13937,6 +17665,7 @@ SQLITE_PRIVATE int sqlite3WhereOkOnePass(WhereInfo*, int*);
    + #define ONEPASS_MULTI    2        /* ONEPASS is valid for multiple rows */
    + SQLITE_PRIVATE void sqlite3ExprCodeLoadIndexColumn(Parse*, Index*, int, int, int);
    + SQLITE_PRIVATE int sqlite3ExprCodeGetColumn(Parse*, Table*, int, int, int, u8);
    ++SQLITE_PRIVATE void sqlite3ExprCodeGetColumnToReg(Parse*, Table*, int, int, int);
    + 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);
    +@@ -13946,8 +17675,9 @@ SQLITE_PRIVATE void sqlite3ExprCacheRemove(Parse*, int, int);
    + SQLITE_PRIVATE void sqlite3ExprCacheClear(Parse*);
    + SQLITE_PRIVATE void sqlite3ExprCacheAffinityChange(Parse*, int, int);
    + SQLITE_PRIVATE void sqlite3ExprCode(Parse*, Expr*, int);
    ++SQLITE_PRIVATE void sqlite3ExprCodeCopy(Parse*, Expr*, int);
    + SQLITE_PRIVATE void sqlite3ExprCodeFactorable(Parse*, Expr*, int);
    +-SQLITE_PRIVATE void sqlite3ExprCodeAtInit(Parse*, Expr*, int, u8);
    ++SQLITE_PRIVATE int sqlite3ExprCodeAtInit(Parse*, Expr*, int);
    + SQLITE_PRIVATE int sqlite3ExprCodeTemp(Parse*, Expr*, int*);
    + SQLITE_PRIVATE int sqlite3ExprCodeTarget(Parse*, Expr*, int);
    + SQLITE_PRIVATE void sqlite3ExprCodeAndCache(Parse*, Expr*, int);
    +@@ -13955,26 +17685,31 @@ SQLITE_PRIVATE int sqlite3ExprCodeExprList(Parse*, ExprList*, int, int, u8);
    + #define SQLITE_ECEL_DUP      0x01  /* Deep, not shallow copies */
    + #define SQLITE_ECEL_FACTOR   0x02  /* Factor out constant terms */
    + #define SQLITE_ECEL_REF      0x04  /* Use ExprList.u.x.iOrderByCol */
    ++#define SQLITE_ECEL_OMITREF  0x08  /* Omit if ExprList.u.x.iOrderByCol */
    + SQLITE_PRIVATE void sqlite3ExprIfTrue(Parse*, Expr*, int, int);
    + SQLITE_PRIVATE void sqlite3ExprIfFalse(Parse*, Expr*, int, int);
    + SQLITE_PRIVATE void sqlite3ExprIfFalseDup(Parse*, Expr*, int, int);
    + SQLITE_PRIVATE Table *sqlite3FindTable(sqlite3*,const char*, const char*);
    +-SQLITE_PRIVATE Table *sqlite3LocateTable(Parse*,int isView,const char*, const char*);
    +-SQLITE_PRIVATE Table *sqlite3LocateTableItem(Parse*,int isView,struct SrcList_item *);
    ++#define LOCATE_VIEW    0x01
    ++#define LOCATE_NOERR   0x02
    ++SQLITE_PRIVATE Table *sqlite3LocateTable(Parse*,u32 flags,const char*, const char*);
    ++SQLITE_PRIVATE Table *sqlite3LocateTableItem(Parse*,u32 flags,struct SrcList_item *);
    + SQLITE_PRIVATE Index *sqlite3FindIndex(sqlite3*,const char*, const char*);
    + SQLITE_PRIVATE void sqlite3UnlinkAndDeleteTable(sqlite3*,int,const char*);
    + SQLITE_PRIVATE void sqlite3UnlinkAndDeleteIndex(sqlite3*,int,const char*);
    +-SQLITE_PRIVATE void sqlite3Vacuum(Parse*);
    +-SQLITE_PRIVATE int sqlite3RunVacuum(char**, sqlite3*);
    ++SQLITE_PRIVATE void sqlite3Vacuum(Parse*,Token*);
    ++SQLITE_PRIVATE int sqlite3RunVacuum(char**, sqlite3*, int);
    + SQLITE_PRIVATE char *sqlite3NameFromToken(sqlite3*, Token*);
    +-SQLITE_PRIVATE int sqlite3ExprCompare(Expr*, Expr*, int);
    ++SQLITE_PRIVATE int sqlite3ExprCompare(Parse*,Expr*, Expr*, int);
    ++SQLITE_PRIVATE int sqlite3ExprCompareSkip(Expr*, Expr*, int);
    + SQLITE_PRIVATE int sqlite3ExprListCompare(ExprList*, ExprList*, int);
    +-SQLITE_PRIVATE int sqlite3ExprImpliesExpr(Expr*, Expr*, int);
    ++SQLITE_PRIVATE int sqlite3ExprImpliesExpr(Parse*,Expr*, Expr*, int);
    + SQLITE_PRIVATE void sqlite3ExprAnalyzeAggregates(NameContext*, Expr*);
    + SQLITE_PRIVATE void sqlite3ExprAnalyzeAggList(NameContext*,ExprList*);
    ++SQLITE_PRIVATE int sqlite3ExprCoveredByIndex(Expr*, int iCur, Index *pIdx);
    + SQLITE_PRIVATE int sqlite3FunctionUsesThisSrc(Expr*, SrcList*);
    + SQLITE_PRIVATE Vdbe *sqlite3GetVdbe(Parse*);
    +-#ifndef SQLITE_OMIT_BUILTIN_TEST
    ++#ifndef SQLITE_UNTESTABLE
    + SQLITE_PRIVATE void sqlite3PrngSaveState(void);
    + SQLITE_PRIVATE void sqlite3PrngRestoreState(void);
    + #endif
    +@@ -13982,15 +17717,18 @@ SQLITE_PRIVATE void sqlite3RollbackAll(sqlite3*,int);
    + SQLITE_PRIVATE void sqlite3CodeVerifySchema(Parse*, int);
    + SQLITE_PRIVATE void sqlite3CodeVerifyNamedSchema(Parse*, const char *zDb);
    + SQLITE_PRIVATE void sqlite3BeginTransaction(Parse*, int);
    +-SQLITE_PRIVATE void sqlite3CommitTransaction(Parse*);
    +-SQLITE_PRIVATE void sqlite3RollbackTransaction(Parse*);
    ++SQLITE_PRIVATE void sqlite3EndTransaction(Parse*,int);
    + SQLITE_PRIVATE void sqlite3Savepoint(Parse*, int, Token*);
    + SQLITE_PRIVATE void sqlite3CloseSavepoints(sqlite3 *);
    + SQLITE_PRIVATE void sqlite3LeaveMutexAndCloseZombie(sqlite3*);
    + SQLITE_PRIVATE int sqlite3ExprIsConstant(Expr*);
    + SQLITE_PRIVATE int sqlite3ExprIsConstantNotJoin(Expr*);
    + SQLITE_PRIVATE int sqlite3ExprIsConstantOrFunction(Expr*, u8);
    ++SQLITE_PRIVATE int sqlite3ExprIsConstantOrGroupBy(Parse*, Expr*, ExprList*);
    + SQLITE_PRIVATE int sqlite3ExprIsTableConstant(Expr*,int);
    ++#ifdef SQLITE_ENABLE_CURSOR_HINTS
    ++SQLITE_PRIVATE int sqlite3ExprContainsSubquery(Expr*);
    ++#endif
    + SQLITE_PRIVATE int sqlite3ExprIsInteger(Expr*, int*);
    + SQLITE_PRIVATE int sqlite3ExprCanBeNull(const Expr*);
    + SQLITE_PRIVATE int sqlite3ExprNeedsNoAffinityChange(const Expr*, char);
    +@@ -14001,9 +17739,14 @@ 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*);
    ++                                     u8,u8,int,int*,int*);
    ++#ifdef SQLITE_ENABLE_NULL_TRIM
    ++SQLITE_PRIVATE   void sqlite3SetMakeRecordP5(Vdbe*,Table*);
    ++#else
    ++# define sqlite3SetMakeRecordP5(A,B)
    ++#endif
    + SQLITE_PRIVATE void sqlite3CompleteInsertion(Parse*,Table*,int,int,int,int*,int,int,int);
    +-SQLITE_PRIVATE int sqlite3OpenTableAndIndices(Parse*, Table*, int, int, u8*, int*, int*);
    ++SQLITE_PRIVATE int sqlite3OpenTableAndIndices(Parse*, Table*, int, u8, int, u8*, int*, int*);
    + SQLITE_PRIVATE void sqlite3BeginWriteOperation(Parse*, int, int);
    + SQLITE_PRIVATE void sqlite3MultiWrite(Parse*);
    + SQLITE_PRIVATE void sqlite3MayAbort(Parse*);
    +@@ -14020,17 +17763,17 @@ SQLITE_PRIVATE void sqlite3SelectSetName(Select*,const char*);
    + #else
    + # define sqlite3SelectSetName(A,B)
    + #endif
    +-SQLITE_PRIVATE void sqlite3FuncDefInsert(FuncDefHash*, FuncDef*);
    +-SQLITE_PRIVATE FuncDef *sqlite3FindFunction(sqlite3*,const char*,int,int,u8,u8);
    +-SQLITE_PRIVATE void sqlite3RegisterBuiltinFunctions(sqlite3*);
    ++SQLITE_PRIVATE void sqlite3InsertBuiltinFuncs(FuncDef*,int);
    ++SQLITE_PRIVATE FuncDef *sqlite3FindFunction(sqlite3*,const char*,int,u8,u8);
    ++SQLITE_PRIVATE void sqlite3RegisterBuiltinFunctions(void);
    + SQLITE_PRIVATE void sqlite3RegisterDateTimeFunctions(void);
    +-SQLITE_PRIVATE void sqlite3RegisterGlobalFunctions(void);
    ++SQLITE_PRIVATE void sqlite3RegisterPerConnectionBuiltinFunctions(sqlite3*);
    + SQLITE_PRIVATE int sqlite3SafetyCheckOk(sqlite3*);
    + SQLITE_PRIVATE int sqlite3SafetyCheckSickOrOk(sqlite3*);
    + SQLITE_PRIVATE void sqlite3ChangeCookie(Parse*, int);
    + 
    + #if !defined(SQLITE_OMIT_VIEW) && !defined(SQLITE_OMIT_TRIGGER)
    +-SQLITE_PRIVATE void sqlite3MaterializeView(Parse*, Table*, Expr*, int);
    ++SQLITE_PRIVATE void sqlite3MaterializeView(Parse*, Table*, Expr*, ExprList*,Expr*,int);
    + #endif
    + 
    + #ifndef SQLITE_OMIT_TRIGGER
    +@@ -14046,11 +17789,14 @@ SQLITE_PRIVATE   void sqlite3CodeRowTrigger(Parse*, Trigger *, int, ExprList*, i
    + SQLITE_PRIVATE   void sqlite3CodeRowTriggerDirect(Parse *, Trigger *, Table *, int, int, int);
    +   void sqliteViewTriggers(Parse*, Table*, Expr*, int, ExprList*);
    + SQLITE_PRIVATE   void sqlite3DeleteTriggerStep(sqlite3*, TriggerStep*);
    +-SQLITE_PRIVATE   TriggerStep *sqlite3TriggerSelectStep(sqlite3*,Select*);
    ++SQLITE_PRIVATE   TriggerStep *sqlite3TriggerSelectStep(sqlite3*,Select*,
    ++                                        const char*,const char*);
    + SQLITE_PRIVATE   TriggerStep *sqlite3TriggerInsertStep(sqlite3*,Token*, IdList*,
    +-                                        Select*,u8);
    +-SQLITE_PRIVATE   TriggerStep *sqlite3TriggerUpdateStep(sqlite3*,Token*,ExprList*, Expr*, u8);
    +-SQLITE_PRIVATE   TriggerStep *sqlite3TriggerDeleteStep(sqlite3*,Token*, Expr*);
    ++                                        Select*,u8,const char*,const char*);
    ++SQLITE_PRIVATE   TriggerStep *sqlite3TriggerUpdateStep(sqlite3*,Token*,ExprList*, Expr*, u8,
    ++                                        const char*,const char*);
    ++SQLITE_PRIVATE   TriggerStep *sqlite3TriggerDeleteStep(sqlite3*,Token*, Expr*,
    ++                                        const char*,const char*);
    + SQLITE_PRIVATE   void sqlite3DeleteTrigger(sqlite3*, Trigger*);
    + SQLITE_PRIVATE   void sqlite3UnlinkAndDeleteTrigger(sqlite3*,int,const char*);
    + SQLITE_PRIVATE   u32 sqlite3TriggerColmask(Parse*,Trigger*,ExprList*,int,int,Table*,int);
    +@@ -14095,7 +17841,9 @@ SQLITE_PRIVATE int sqlite3FixTriggerStep(DbFixer*, TriggerStep*);
    + SQLITE_PRIVATE int sqlite3AtoF(const char *z, double*, int, u8);
    + SQLITE_PRIVATE int sqlite3GetInt32(const char *, int*);
    + SQLITE_PRIVATE int sqlite3Atoi(const char*);
    ++#ifndef SQLITE_OMIT_UTF16
    + SQLITE_PRIVATE int sqlite3Utf16ByteLen(const void *pData, int nChar);
    ++#endif
    + SQLITE_PRIVATE int sqlite3Utf8CharLen(const char *pData, int nByte);
    + SQLITE_PRIVATE u32 sqlite3Utf8Read(const u8**);
    + SQLITE_PRIVATE LogEst sqlite3LogEst(u64);
    +@@ -14103,7 +17851,14 @@ SQLITE_PRIVATE LogEst sqlite3LogEstAdd(LogEst,LogEst);
    + #ifndef SQLITE_OMIT_VIRTUALTABLE
    + SQLITE_PRIVATE LogEst sqlite3LogEstFromDouble(double);
    + #endif
    ++#if defined(SQLITE_ENABLE_STMT_SCANSTATUS) || \
    ++    defined(SQLITE_ENABLE_STAT3_OR_STAT4) || \
    ++    defined(SQLITE_EXPLAIN_ESTIMATED_ROWS)
    + SQLITE_PRIVATE u64 sqlite3LogEstToInt(LogEst);
    ++#endif
    ++SQLITE_PRIVATE VList *sqlite3VListAdd(sqlite3*,VList*,const char*,int,int);
    ++SQLITE_PRIVATE const char *sqlite3VListNumToName(VList*,int);
    ++SQLITE_PRIVATE int sqlite3VListNameToNum(VList*,const char*,int);
    + 
    + /*
    + ** Routines to read and write variable-length integers.  These used to
    +@@ -14133,11 +17888,13 @@ SQLITE_PRIVATE const char *sqlite3IndexAffinityStr(sqlite3*, Index*);
    + SQLITE_PRIVATE void sqlite3TableAffinity(Vdbe*, Table*, int);
    + SQLITE_PRIVATE char sqlite3CompareAffinity(Expr *pExpr, char aff2);
    + SQLITE_PRIVATE int sqlite3IndexAffinityOk(Expr *pExpr, char idx_affinity);
    ++SQLITE_PRIVATE char sqlite3TableColumnAffinity(Table*,int);
    + 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 sqlite3ErrorWithMsg(sqlite3*, int, const char*,...);
    + SQLITE_PRIVATE void sqlite3Error(sqlite3*,int);
    ++SQLITE_PRIVATE void sqlite3SystemError(sqlite3*,int);
    + SQLITE_PRIVATE void *sqlite3HexToBlob(sqlite3*, const char *z, int n);
    + SQLITE_PRIVATE u8 sqlite3HexToInt(int h);
    + SQLITE_PRIVATE int sqlite3TwoPartName(Parse *, Token *, Token *, Token **);
    +@@ -14151,6 +17908,8 @@ 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 CollSeq *sqlite3ExprNNCollSeq(Parse *pParse, Expr *pExpr);
    ++SQLITE_PRIVATE int sqlite3ExprCollSeqMatch(Parse*,Expr*,Expr*);
    + SQLITE_PRIVATE Expr *sqlite3ExprAddCollateToken(Parse *pParse, Expr*, const Token*, int);
    + SQLITE_PRIVATE Expr *sqlite3ExprAddCollateString(Parse*,Expr*,const char*);
    + SQLITE_PRIVATE Expr *sqlite3ExprSkipCollate(Expr*);
    +@@ -14170,21 +17929,24 @@ SQLITE_PRIVATE u8 sqlite3GetBoolean(const char *z,u8);
    + 
    + SQLITE_PRIVATE const void *sqlite3ValueText(sqlite3_value*, u8);
    + SQLITE_PRIVATE int sqlite3ValueBytes(sqlite3_value*, u8);
    +-SQLITE_PRIVATE void sqlite3ValueSetStr(sqlite3_value*, int, const void *,u8, 
    ++SQLITE_PRIVATE void sqlite3ValueSetStr(sqlite3_value*, int, const void *,u8,
    +                         void(*)(void*));
    + SQLITE_PRIVATE void sqlite3ValueSetNull(sqlite3_value*);
    + SQLITE_PRIVATE void sqlite3ValueFree(sqlite3_value*);
    + SQLITE_PRIVATE sqlite3_value *sqlite3ValueNew(sqlite3 *);
    ++#ifndef SQLITE_OMIT_UTF16
    + SQLITE_PRIVATE char *sqlite3Utf16to8(sqlite3 *, const void*, int, u8);
    ++#endif
    + SQLITE_PRIVATE int sqlite3ValueFromExpr(sqlite3 *, Expr *, u8, u8, sqlite3_value **);
    + SQLITE_PRIVATE void sqlite3ValueApplyAffinity(sqlite3_value *, u8, u8);
    + #ifndef SQLITE_AMALGAMATION
    + SQLITE_PRIVATE const unsigned char sqlite3OpcodeProperty[];
    ++SQLITE_PRIVATE const char sqlite3StrBINARY[];
    + SQLITE_PRIVATE const unsigned char sqlite3UpperToLower[];
    + SQLITE_PRIVATE const unsigned char sqlite3CtypeMap[];
    + SQLITE_PRIVATE const Token sqlite3IntTokens[];
    + SQLITE_PRIVATE SQLITE_WSD struct Sqlite3Config sqlite3Config;
    +-SQLITE_PRIVATE SQLITE_WSD FuncDefHash sqlite3GlobalFunctions;
    ++SQLITE_PRIVATE FuncDefHash sqlite3BuiltinFunctions;
    + #ifndef SQLITE_OMIT_WSD
    + SQLITE_PRIVATE int sqlite3PendingByte;
    + #endif
    +@@ -14196,7 +17958,7 @@ SQLITE_PRIVATE void sqlite3AlterRenameTable(Parse*, SrcList*, Token*);
    + SQLITE_PRIVATE int sqlite3GetToken(const unsigned char *, int *);
    + SQLITE_PRIVATE void sqlite3NestedParse(Parse*, const char*, ...);
    + SQLITE_PRIVATE void sqlite3ExpirePreparedStatements(sqlite3*);
    +-SQLITE_PRIVATE int sqlite3CodeSubselect(Parse *, Expr *, int, int);
    ++SQLITE_PRIVATE int sqlite3CodeSubselect(Parse*, Expr *, int, int);
    + SQLITE_PRIVATE void sqlite3SelectPrep(Parse*, Select*, NameContext*);
    + SQLITE_PRIVATE void sqlite3SelectWrongNumTermsError(Parse *pParse, Select *p);
    + SQLITE_PRIVATE int sqlite3MatchSpanName(const char*, const char*, const char*, const char*);
    +@@ -14219,7 +17981,6 @@ SQLITE_PRIVATE void sqlite3DeleteIndexSamples(sqlite3*,Index*);
    + SQLITE_PRIVATE void sqlite3DefaultRowEst(Index*);
    + SQLITE_PRIVATE void sqlite3RegisterLikeFunctions(sqlite3*, int);
    + SQLITE_PRIVATE int sqlite3IsLikeFunction(sqlite3*,Expr*,int*,char*);
    +-SQLITE_PRIVATE void sqlite3MinimumFileFormat(Parse*, int, int);
    + SQLITE_PRIVATE void sqlite3SchemaClear(void *);
    + SQLITE_PRIVATE Schema *sqlite3SchemaGet(sqlite3 *, Btree *);
    + SQLITE_PRIVATE int sqlite3SchemaToIndex(sqlite3 *db, Schema *);
    +@@ -14230,11 +17991,13 @@ SQLITE_PRIVATE KeyInfo *sqlite3KeyInfoOfIndex(Parse*, Index*);
    + #ifdef SQLITE_DEBUG
    + SQLITE_PRIVATE int sqlite3KeyInfoIsWriteable(KeyInfo*);
    + #endif
    +-SQLITE_PRIVATE int sqlite3CreateFunc(sqlite3 *, const char *, int, int, void *, 
    ++SQLITE_PRIVATE int sqlite3CreateFunc(sqlite3 *, const char *, int, int, void *,
    +   void (*)(sqlite3_context*,int,sqlite3_value **),
    +   void (*)(sqlite3_context*,int,sqlite3_value **), void (*)(sqlite3_context*),
    +   FuncDestructor *pDestructor
    + );
    ++SQLITE_PRIVATE void sqlite3OomFault(sqlite3*);
    ++SQLITE_PRIVATE void sqlite3OomClear(sqlite3*);
    + SQLITE_PRIVATE int sqlite3ApiExit(sqlite3 *db, int);
    + SQLITE_PRIVATE int sqlite3OpenTempDatabase(Parse *);
    + 
    +@@ -14250,19 +18013,29 @@ SQLITE_PRIVATE Expr *sqlite3CreateColumnExpr(sqlite3 *, SrcList *, int, int);
    + SQLITE_PRIVATE void sqlite3BackupRestart(sqlite3_backup *);
    + SQLITE_PRIVATE void sqlite3BackupUpdate(sqlite3_backup *, Pgno, const u8 *);
    + 
    ++#ifndef SQLITE_OMIT_SUBQUERY
    ++SQLITE_PRIVATE int sqlite3ExprCheckIN(Parse*, Expr*);
    ++#else
    ++# define sqlite3ExprCheckIN(x,y) SQLITE_OK
    ++#endif
    ++
    + #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 sqlite3Stat4ProbeSetValue(
    ++    Parse*,Index*,UnpackedRecord**,Expr*,int,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**);
    ++SQLITE_PRIVATE char sqlite3IndexColumnAffinity(sqlite3*, Index*, int);
    + #endif
    + 
    + /*
    + ** The interface to the LEMON-generated parser
    + */
    +-SQLITE_PRIVATE void *sqlite3ParserAlloc(void*(*)(u64));
    +-SQLITE_PRIVATE void sqlite3ParserFree(void*, void(*)(void*));
    ++#ifndef SQLITE_AMALGAMATION
    ++SQLITE_PRIVATE   void *sqlite3ParserAlloc(void*(*)(u64));
    ++SQLITE_PRIVATE   void sqlite3ParserFree(void*, void(*)(void*));
    ++#endif
    + SQLITE_PRIVATE void sqlite3Parser(void*, int, Token, Parse*);
    + #ifdef YYTRACKMAXSTACKDEPTH
    + SQLITE_PRIVATE   int sqlite3ParserStackPeak(void*);
    +@@ -14291,7 +18064,7 @@ SQLITE_PRIVATE   int sqlite3Utf8To8(unsigned char*);
    + #  define sqlite3VtabRollback(X)
    + #  define sqlite3VtabCommit(X)
    + #  define sqlite3VtabInSync(db) 0
    +-#  define sqlite3VtabLock(X) 
    ++#  define sqlite3VtabLock(X)
    + #  define sqlite3VtabUnlock(X)
    + #  define sqlite3VtabUnlockList(X)
    + #  define sqlite3VtabSavepoint(X, Y, Z) SQLITE_OK
    +@@ -14308,6 +18081,13 @@ SQLITE_PRIVATE    void sqlite3VtabUnlockList(sqlite3*);
    + SQLITE_PRIVATE    int sqlite3VtabSavepoint(sqlite3 *, int, int);
    + SQLITE_PRIVATE    void sqlite3VtabImportErrmsg(Vdbe*, sqlite3_vtab*);
    + SQLITE_PRIVATE    VTable *sqlite3GetVTable(sqlite3*, Table*);
    ++SQLITE_PRIVATE    Module *sqlite3VtabCreateModule(
    ++     sqlite3*,
    ++     const char*,
    ++     const sqlite3_module*,
    ++     void*,
    ++     void(*)(void*)
    ++   );
    + #  define sqlite3VtabInSync(db) ((db)->nVTrans>0 && (db)->aVTrans==0)
    + #endif
    + SQLITE_PRIVATE int sqlite3VtabEponymousTableInit(Parse*,Module*);
    +@@ -14349,7 +18129,7 @@ SQLITE_PRIVATE   void sqlite3WithPush(Parse*, With*, u8);
    + ** no-op macros if OMIT_FOREIGN_KEY is defined. In this case no foreign
    + ** key functionality is available. If OMIT_TRIGGER is defined but
    + ** OMIT_FOREIGN_KEY is not, only some of the functions are no-oped. In
    +-** this case foreign keys are parsed, but no other functionality is 
    ++** this case foreign keys are parsed, but no other functionality is
    + ** provided (enforcement of FK constraints requires the triggers sub-system).
    + */
    + #if !defined(SQLITE_OMIT_FOREIGN_KEY) && !defined(SQLITE_OMIT_TRIGGER)
    +@@ -14365,6 +18145,7 @@ SQLITE_PRIVATE   FKey *sqlite3FkReferences(Table *);
    +   #define sqlite3FkDropTable(a,b,c)
    +   #define sqlite3FkOldmask(a,b)         0
    +   #define sqlite3FkRequired(a,b,c,d)    0
    ++  #define sqlite3FkReferences(a)        0
    + #endif
    + #ifndef SQLITE_OMIT_FOREIGN_KEY
    + SQLITE_PRIVATE   void sqlite3FkDelete(sqlite3 *, Table*);
    +@@ -14383,10 +18164,10 @@ SQLITE_PRIVATE   int sqlite3FkLocateIndex(Parse*,Table*,FKey*,Index**,int**);
    + 
    + /*
    + ** The interface to the code in fault.c used for identifying "benign"
    +-** malloc failures. This is only present if SQLITE_OMIT_BUILTIN_TEST
    ++** malloc failures. This is only present if SQLITE_UNTESTABLE
    + ** is not defined.
    + */
    +-#ifndef SQLITE_OMIT_BUILTIN_TEST
    ++#ifndef SQLITE_UNTESTABLE
    + SQLITE_PRIVATE   void sqlite3BeginBenignMalloc(void);
    + SQLITE_PRIVATE   void sqlite3EndBenignMalloc(void);
    + #else
    +@@ -14408,21 +18189,17 @@ SQLITE_PRIVATE   void sqlite3EndBenignMalloc(void);
    + #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*);
    ++SQLITE_PRIVATE int sqlite3FindInIndex(Parse *, Expr *, u32, int*, int*);
    + 
    +-#ifdef SQLITE_ENABLE_ATOMIC_WRITE
    +-SQLITE_PRIVATE   int sqlite3JournalOpen(sqlite3_vfs *, const char *, sqlite3_file *, int, int);
    +-SQLITE_PRIVATE   int sqlite3JournalSize(sqlite3_vfs *);
    ++SQLITE_PRIVATE int sqlite3JournalOpen(sqlite3_vfs *, const char *, sqlite3_file *, int, int);
    ++SQLITE_PRIVATE int sqlite3JournalSize(sqlite3_vfs *);
    ++#if defined(SQLITE_ENABLE_ATOMIC_WRITE) \
    ++ || defined(SQLITE_ENABLE_BATCH_ATOMIC_WRITE)
    + SQLITE_PRIVATE   int sqlite3JournalCreate(sqlite3_file *);
    +-SQLITE_PRIVATE   int sqlite3JournalExists(sqlite3_file *p);
    +-#else
    +-  #define sqlite3JournalSize(pVfs) ((pVfs)->szOsFile)
    +-  #define sqlite3JournalExists(p) 1
    + #endif
    + 
    ++SQLITE_PRIVATE int sqlite3JournalIsInMemory(sqlite3_file *p);
    + SQLITE_PRIVATE void sqlite3MemJournalOpen(sqlite3_file *);
    +-SQLITE_PRIVATE int sqlite3MemJournalSize(void);
    +-SQLITE_PRIVATE int sqlite3IsMemJournal(sqlite3_file *);
    + 
    + SQLITE_PRIVATE void sqlite3ExprSetHeightAndFlags(Parse *pParse, Expr *p);
    + #if SQLITE_MAX_EXPR_DEPTH>0
    +@@ -14449,11 +18226,14 @@ SQLITE_PRIVATE   void sqlite3ConnectionClosed(sqlite3 *db);
    + #ifdef SQLITE_DEBUG
    + SQLITE_PRIVATE   void sqlite3ParserTrace(FILE*, char *);
    + #endif
    ++#if defined(YYCOVERAGE)
    ++SQLITE_PRIVATE   int sqlite3ParserCoverage(FILE*);
    ++#endif
    + 
    + /*
    + ** If the SQLITE_ENABLE IOTRACE exists then the global variable
    + ** sqlite3IoTrace is a pointer to a printf-like routine used to
    +-** print I/O tracing messages. 
    ++** print I/O tracing messages.
    + */
    + #ifdef SQLITE_ENABLE_IOTRACE
    + # define IOTRACE(A)  if( sqlite3IoTrace ){ sqlite3IoTrace A; }
    +@@ -14487,7 +18267,7 @@ SQLITE_API SQLITE_EXTERN void (SQLITE_CDECL *sqlite3IoTrace)(const char*,...);
    + ** that allocations that might have been satisfied by lookaside are not
    + ** passed back to non-lookaside free() routines.  Asserts such as the
    + ** example above are placed on the non-lookaside free() routines to verify
    +-** this constraint. 
    ++** this constraint.
    + **
    + ** All of this is no-op for a production build.  It only comes into
    + ** play when the SQLITE_MEMDEBUG compile-time option is used.
    +@@ -14503,8 +18283,7 @@ SQLITE_PRIVATE   int sqlite3MemdebugNoType(void*,u8);
    + #endif
    + #define MEMTYPE_HEAP       0x01  /* General heap allocations */
    + #define MEMTYPE_LOOKASIDE  0x02  /* Heap that might have been lookaside */
    +-#define MEMTYPE_SCRATCH    0x04  /* Scratch allocations */
    +-#define MEMTYPE_PCACHE     0x08  /* Page cache allocations */
    ++#define MEMTYPE_PCACHE     0x04  /* Page cache allocations */
    + 
    + /*
    + ** Threading interface
    +@@ -14514,11 +18293,24 @@ SQLITE_PRIVATE int sqlite3ThreadCreate(SQLiteThread**,void*(*)(void*),void*);
    + SQLITE_PRIVATE int sqlite3ThreadJoin(SQLiteThread*, void**);
    + #endif
    + 
    ++#if defined(SQLITE_ENABLE_DBPAGE_VTAB) || defined(SQLITE_TEST)
    ++SQLITE_PRIVATE int sqlite3DbpageRegister(sqlite3*);
    ++#endif
    + #if defined(SQLITE_ENABLE_DBSTAT_VTAB) || defined(SQLITE_TEST)
    + SQLITE_PRIVATE int sqlite3DbstatRegister(sqlite3*);
    + #endif
    + 
    +-#endif /* _SQLITEINT_H_ */
    ++SQLITE_PRIVATE int sqlite3ExprVectorSize(Expr *pExpr);
    ++SQLITE_PRIVATE int sqlite3ExprIsVector(Expr *pExpr);
    ++SQLITE_PRIVATE Expr *sqlite3VectorFieldSubexpr(Expr*, int);
    ++SQLITE_PRIVATE Expr *sqlite3ExprForVectorField(Parse*,Expr*,int);
    ++SQLITE_PRIVATE void sqlite3VectorErrorMsg(Parse*, Expr*);
    ++
    ++#ifndef SQLITE_OMIT_COMPILEOPTION_DIAGS
    ++SQLITE_PRIVATE const char **sqlite3CompileOptions(int *pnOpt);
    ++#endif
    ++
    ++#endif /* SQLITEINT_H */
    + 
    + /************** End of sqliteInt.h *******************************************/
    + /************** Begin file global.c ******************************************/
    +@@ -14594,6 +18386,7 @@ SQLITE_PRIVATE const unsigned char sqlite3UpperToLower[] = {
    + **   isxdigit()                       0x08
    + **   toupper()                        0x20
    + **   SQLite identifier character      0x40
    ++**   Quote character                  0x80
    + **
    + ** Bit 0x20 is set if the mapped character requires translation to upper
    + ** case. i.e. if the character is a lower-case ASCII character.
    +@@ -14602,16 +18395,13 @@ SQLITE_PRIVATE const unsigned char sqlite3UpperToLower[] = {
    + **
    + **   (x & ~(map[x]&0x20))
    + **
    +-** Standard function tolower() is implemented using the sqlite3UpperToLower[]
    ++** The equivalent of tolower() is implemented using the sqlite3UpperToLower[]
    + ** array. tolower() is used more often than toupper() by SQLite.
    + **
    +-** Bit 0x40 is set if the character non-alphanumeric and can be used in an 
    ++** Bit 0x40 is set if the character is non-alphanumeric and can be used in an 
    + ** SQLite identifier.  Identifiers are alphanumerics, "_", "$", and any
    + ** non-ASCII UTF character. Hence the test for whether or not a character is
    + ** part of an identifier is 0x46.
    +-**
    +-** SQLite's versions are identical to the standard versions assuming a
    +-** locale of "C". They are implemented as macros in sqliteInt.h.
    + */
    + #ifdef SQLITE_ASCII
    + SQLITE_PRIVATE const unsigned char sqlite3CtypeMap[256] = {
    +@@ -14619,7 +18409,7 @@ SQLITE_PRIVATE const unsigned char sqlite3CtypeMap[256] = {
    +   0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00,  /* 08..0f    ........ */
    +   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,  /* 10..17    ........ */
    +   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,  /* 18..1f    ........ */
    +-  0x01, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00,  /* 20..27     !"#$%&' */
    ++  0x01, 0x00, 0x80, 0x00, 0x40, 0x00, 0x00, 0x80,  /* 20..27     !"#$%&' */
    +   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,  /* 28..2f    ()*+,-./ */
    +   0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c,  /* 30..37    01234567 */
    +   0x0c, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,  /* 38..3f    89:;<=>? */
    +@@ -14627,8 +18417,8 @@ SQLITE_PRIVATE const unsigned char sqlite3CtypeMap[256] = {
    +   0x00, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x02,  /* 40..47    @ABCDEFG */
    +   0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02,  /* 48..4f    HIJKLMNO */
    +   0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02,  /* 50..57    PQRSTUVW */
    +-  0x02, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00, 0x40,  /* 58..5f    XYZ[\]^_ */
    +-  0x00, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x22,  /* 60..67    `abcdefg */
    ++  0x02, 0x02, 0x02, 0x80, 0x00, 0x00, 0x00, 0x40,  /* 58..5f    XYZ[\]^_ */
    ++  0x80, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x22,  /* 60..67    `abcdefg */
    +   0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22,  /* 68..6f    hijklmno */
    +   0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22,  /* 70..77    pqrstuvw */
    +   0x22, 0x22, 0x22, 0x00, 0x00, 0x00, 0x00, 0x00,  /* 78..7f    xyz{|}~. */
    +@@ -14663,9 +18453,16 @@ SQLITE_PRIVATE const unsigned char sqlite3CtypeMap[256] = {
    + ** EVIDENCE-OF: R-43642-56306 By default, URI handling is globally
    + ** disabled. The default value may be changed by compiling with the
    + ** SQLITE_USE_URI symbol defined.
    ++**
    ++** URI filenames are enabled by default if SQLITE_HAS_CODEC is
    ++** enabled.
    + */
    + #ifndef SQLITE_USE_URI
    +-# define  SQLITE_USE_URI 0
    ++# ifdef SQLITE_HAS_CODEC
    ++#  define SQLITE_USE_URI 1
    ++# else
    ++#  define SQLITE_USE_URI 0
    ++# endif
    + #endif
    + 
    + /* EVIDENCE-OF: R-38720-18127 The default setting is determined by the
    +@@ -14683,6 +18480,31 @@ SQLITE_PRIVATE const unsigned char sqlite3CtypeMap[256] = {
    + # define SQLITE_SORTER_PMASZ 250
    + #endif
    + 
    ++/* Statement journals spill to disk when their size exceeds the following
    ++** threshold (in bytes). 0 means that statement journals are created and
    ++** written to disk immediately (the default behavior for SQLite versions
    ++** before 3.12.0).  -1 means always keep the entire statement journal in
    ++** memory.  (The statement journal is also always held entirely in memory
    ++** if journal_mode=MEMORY or if temp_store=MEMORY, regardless of this
    ++** setting.)
    ++*/
    ++#ifndef SQLITE_STMTJRNL_SPILL 
    ++# define SQLITE_STMTJRNL_SPILL (64*1024)
    ++#endif
    ++
    ++/*
    ++** The default lookaside-configuration, the format "SZ,N".  SZ is the
    ++** number of bytes in each lookaside slot (should be a multiple of 8)
    ++** and N is the number of slots.  The lookaside-configuration can be
    ++** changed as start-time using sqlite3_config(SQLITE_CONFIG_LOOKASIDE)
    ++** or at run-time for an individual database connection using
    ++** sqlite3_db_config(db, SQLITE_DBCONFIG_LOOKASIDE);
    ++*/
    ++#ifndef SQLITE_DEFAULT_LOOKASIDE
    ++# define SQLITE_DEFAULT_LOOKASIDE 1200,100
    ++#endif
    ++
    ++
    + /*
    + ** The following singleton contains the global configuration for
    + ** the SQLite library.
    +@@ -14693,10 +18515,11 @@ SQLITE_PRIVATE SQLITE_WSD struct Sqlite3Config sqlite3Config = {
    +    SQLITE_THREADSAFE==1,      /* bFullMutex */
    +    SQLITE_USE_URI,            /* bOpenUri */
    +    SQLITE_ALLOW_COVERING_INDEX_SCAN,   /* bUseCis */
    ++   0,                         /* bSmallMalloc */
    +    0x7ffffffe,                /* mxStrlen */
    +    0,                         /* neverCorrupt */
    +-   128,                       /* szLookaside */
    +-   500,                       /* nLookaside */
    ++   SQLITE_DEFAULT_LOOKASIDE,  /* szLookaside, nLookaside */
    ++   SQLITE_STMTJRNL_SPILL,     /* nStmtSpill */
    +    {0,0,0,0,0,0,0,0},         /* m */
    +    {0,0,0,0,0,0,0,0,0},       /* mutex */
    +    {0,0,0,0,0,0,0,0,0,0,0,0,0},/* pcache2 */
    +@@ -14705,9 +18528,6 @@ SQLITE_PRIVATE SQLITE_WSD struct Sqlite3Config sqlite3Config = {
    +    0, 0,                      /* mnHeap, mxHeap */
    +    SQLITE_DEFAULT_MMAP_SIZE,  /* szMmap */
    +    SQLITE_MAX_MMAP_SIZE,      /* mxMmap */
    +-   (void*)0,                  /* pScratch */
    +-   0,                         /* szScratch */
    +-   0,                         /* nScratch */
    +    (void*)0,                  /* pPage */
    +    0,                         /* szPage */
    +    SQLITE_DEFAULT_PCACHE_INITSZ, /* nPage */
    +@@ -14732,10 +18552,11 @@ SQLITE_PRIVATE SQLITE_WSD struct Sqlite3Config sqlite3Config = {
    +    0,                         /* xVdbeBranch */
    +    0,                         /* pVbeBranchArg */
    + #endif
    +-#ifndef SQLITE_OMIT_BUILTIN_TEST
    ++#ifndef SQLITE_UNTESTABLE
    +    0,                         /* xTestCallback */
    + #endif
    +-   0                          /* bLocaltimeFault */
    ++   0,                         /* bLocaltimeFault */
    ++   0x7ffffffe                 /* iOnceResetThreshold */
    + };
    + 
    + /*
    +@@ -14743,7 +18564,7 @@ SQLITE_PRIVATE SQLITE_WSD struct Sqlite3Config sqlite3Config = {
    + ** database connections.  After initialization, this table is
    + ** read-only.
    + */
    +-SQLITE_PRIVATE SQLITE_WSD FuncDefHash sqlite3GlobalFunctions;
    ++SQLITE_PRIVATE FuncDefHash sqlite3BuiltinFunctions;
    + 
    + /*
    + ** Constant tokens for values 0 and 1.
    +@@ -14758,7 +18579,7 @@ SQLITE_PRIVATE const Token sqlite3IntTokens[] = {
    + ** The value of the "pending" byte must be 0x40000000 (1 byte past the
    + ** 1-gibabyte boundary) in a compatible database.  SQLite never uses
    + ** the database page that contains the pending byte.  It never attempts
    +-** to read or write that page.  The pending byte page is set assign
    ++** to read or write that page.  The pending byte page is set aside
    + ** for use by the VFS layers as space for managing file locks.
    + **
    + ** During testing, it is often desirable to move the pending byte to
    +@@ -14785,446 +18606,12 @@ SQLITE_PRIVATE int sqlite3PendingByte = 0x40000000;
    + */
    + SQLITE_PRIVATE const unsigned char sqlite3OpcodeProperty[] = OPFLG_INITIALIZER;
    + 
    +-/************** End of global.c **********************************************/
    +-/************** Begin file ctime.c *******************************************/
    +-/*
    +-** 2010 February 23
    +-**
    +-** 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 implements routines used to report what compile-time options
    +-** SQLite was built with.
    +-*/
    +-
    +-#ifndef SQLITE_OMIT_COMPILEOPTION_DIAGS
    +-
    +-/* #include "sqliteInt.h" */
    +-
    +-/*
    +-** An array of names of all compile-time options.  This array should 
    +-** be sorted A-Z.
    +-**
    +-** This array looks large, but in a typical installation actually uses
    +-** only a handful of compile-time options, so most times this array is usually
    +-** rather short and uses little memory space.
    +-*/
    +-static const char * const azCompileOpt[] = {
    +-
    +-/* These macros are provided to "stringify" the value of the define
    +-** for those options in which the value is meaningful. */
    +-#define CTIMEOPT_VAL_(opt) #opt
    +-#define CTIMEOPT_VAL(opt) CTIMEOPT_VAL_(opt)
    +-
    +-#if SQLITE_32BIT_ROWID
    +-  "32BIT_ROWID",
    +-#endif
    +-#if SQLITE_4_BYTE_ALIGNED_MALLOC
    +-  "4_BYTE_ALIGNED_MALLOC",
    +-#endif
    +-#if SQLITE_CASE_SENSITIVE_LIKE
    +-  "CASE_SENSITIVE_LIKE",
    +-#endif
    +-#if SQLITE_CHECK_PAGES
    +-  "CHECK_PAGES",
    +-#endif
    +-#if SQLITE_COVERAGE_TEST
    +-  "COVERAGE_TEST",
    +-#endif
    +-#if SQLITE_DEBUG
    +-  "DEBUG",
    +-#endif
    +-#if SQLITE_DEFAULT_LOCKING_MODE
    +-  "DEFAULT_LOCKING_MODE=" CTIMEOPT_VAL(SQLITE_DEFAULT_LOCKING_MODE),
    +-#endif
    +-#if defined(SQLITE_DEFAULT_MMAP_SIZE) && !defined(SQLITE_DEFAULT_MMAP_SIZE_xc)
    +-  "DEFAULT_MMAP_SIZE=" CTIMEOPT_VAL(SQLITE_DEFAULT_MMAP_SIZE),
    +-#endif
    +-#if SQLITE_DISABLE_DIRSYNC
    +-  "DISABLE_DIRSYNC",
    +-#endif
    +-#if SQLITE_DISABLE_LFS
    +-  "DISABLE_LFS",
    +-#endif
    +-#if SQLITE_ENABLE_API_ARMOR
    +-  "ENABLE_API_ARMOR",
    +-#endif
    +-#if SQLITE_ENABLE_ATOMIC_WRITE
    +-  "ENABLE_ATOMIC_WRITE",
    +-#endif
    +-#if SQLITE_ENABLE_CEROD
    +-  "ENABLE_CEROD",
    +-#endif
    +-#if SQLITE_ENABLE_COLUMN_METADATA
    +-  "ENABLE_COLUMN_METADATA",
    +-#endif
    +-#if SQLITE_ENABLE_DBSTAT_VTAB
    +-  "ENABLE_DBSTAT_VTAB",
    +-#endif
    +-#if SQLITE_ENABLE_EXPENSIVE_ASSERT
    +-  "ENABLE_EXPENSIVE_ASSERT",
    +-#endif
    +-#if SQLITE_ENABLE_FTS1
    +-  "ENABLE_FTS1",
    +-#endif
    +-#if SQLITE_ENABLE_FTS2
    +-  "ENABLE_FTS2",
    +-#endif
    +-#if SQLITE_ENABLE_FTS3
    +-  "ENABLE_FTS3",
    +-#endif
    +-#if SQLITE_ENABLE_FTS3_PARENTHESIS
    +-  "ENABLE_FTS3_PARENTHESIS",
    +-#endif
    +-#if SQLITE_ENABLE_FTS4
    +-  "ENABLE_FTS4",
    +-#endif
    +-#if SQLITE_ENABLE_FTS5
    +-  "ENABLE_FTS5",
    +-#endif
    +-#if SQLITE_ENABLE_ICU
    +-  "ENABLE_ICU",
    +-#endif
    +-#if SQLITE_ENABLE_IOTRACE
    +-  "ENABLE_IOTRACE",
    +-#endif
    +-#if SQLITE_ENABLE_JSON1
    +-  "ENABLE_JSON1",
    +-#endif
    +-#if SQLITE_ENABLE_LOAD_EXTENSION
    +-  "ENABLE_LOAD_EXTENSION",
    +-#endif
    +-#if SQLITE_ENABLE_LOCKING_STYLE
    +-  "ENABLE_LOCKING_STYLE=" CTIMEOPT_VAL(SQLITE_ENABLE_LOCKING_STYLE),
    +-#endif
    +-#if SQLITE_ENABLE_MEMORY_MANAGEMENT
    +-  "ENABLE_MEMORY_MANAGEMENT",
    +-#endif
    +-#if SQLITE_ENABLE_MEMSYS3
    +-  "ENABLE_MEMSYS3",
    +-#endif
    +-#if SQLITE_ENABLE_MEMSYS5
    +-  "ENABLE_MEMSYS5",
    +-#endif
    +-#if SQLITE_ENABLE_OVERSIZE_CELL_CHECK
    +-  "ENABLE_OVERSIZE_CELL_CHECK",
    +-#endif
    +-#if SQLITE_ENABLE_RTREE
    +-  "ENABLE_RTREE",
    +-#endif
    +-#if defined(SQLITE_ENABLE_STAT4)
    +-  "ENABLE_STAT4",
    +-#elif defined(SQLITE_ENABLE_STAT3)
    +-  "ENABLE_STAT3",
    +-#endif
    +-#if SQLITE_ENABLE_UNLOCK_NOTIFY
    +-  "ENABLE_UNLOCK_NOTIFY",
    +-#endif
    +-#if SQLITE_ENABLE_UPDATE_DELETE_LIMIT
    +-  "ENABLE_UPDATE_DELETE_LIMIT",
    +-#endif
    +-#if SQLITE_HAS_CODEC
    +-  "HAS_CODEC",
    +-#endif
    +-#if HAVE_ISNAN || SQLITE_HAVE_ISNAN
    +-  "HAVE_ISNAN",
    +-#endif
    +-#if SQLITE_HOMEGROWN_RECURSIVE_MUTEX
    +-  "HOMEGROWN_RECURSIVE_MUTEX",
    +-#endif
    +-#if SQLITE_IGNORE_AFP_LOCK_ERRORS
    +-  "IGNORE_AFP_LOCK_ERRORS",
    +-#endif
    +-#if SQLITE_IGNORE_FLOCK_LOCK_ERRORS
    +-  "IGNORE_FLOCK_LOCK_ERRORS",
    +-#endif
    +-#ifdef SQLITE_INT64_TYPE
    +-  "INT64_TYPE",
    +-#endif
    +-#if SQLITE_LOCK_TRACE
    +-  "LOCK_TRACE",
    +-#endif
    +-#if defined(SQLITE_MAX_MMAP_SIZE) && !defined(SQLITE_MAX_MMAP_SIZE_xc)
    +-  "MAX_MMAP_SIZE=" CTIMEOPT_VAL(SQLITE_MAX_MMAP_SIZE),
    +-#endif
    +-#ifdef SQLITE_MAX_SCHEMA_RETRY
    +-  "MAX_SCHEMA_RETRY=" CTIMEOPT_VAL(SQLITE_MAX_SCHEMA_RETRY),
    +-#endif
    +-#if SQLITE_MEMDEBUG
    +-  "MEMDEBUG",
    +-#endif
    +-#if SQLITE_MIXED_ENDIAN_64BIT_FLOAT
    +-  "MIXED_ENDIAN_64BIT_FLOAT",
    +-#endif
    +-#if SQLITE_NO_SYNC
    +-  "NO_SYNC",
    +-#endif
    +-#if SQLITE_OMIT_ALTERTABLE
    +-  "OMIT_ALTERTABLE",
    +-#endif
    +-#if SQLITE_OMIT_ANALYZE
    +-  "OMIT_ANALYZE",
    +-#endif
    +-#if SQLITE_OMIT_ATTACH
    +-  "OMIT_ATTACH",
    +-#endif
    +-#if SQLITE_OMIT_AUTHORIZATION
    +-  "OMIT_AUTHORIZATION",
    +-#endif
    +-#if SQLITE_OMIT_AUTOINCREMENT
    +-  "OMIT_AUTOINCREMENT",
    +-#endif
    +-#if SQLITE_OMIT_AUTOINIT
    +-  "OMIT_AUTOINIT",
    +-#endif
    +-#if SQLITE_OMIT_AUTOMATIC_INDEX
    +-  "OMIT_AUTOMATIC_INDEX",
    +-#endif
    +-#if SQLITE_OMIT_AUTORESET
    +-  "OMIT_AUTORESET",
    +-#endif
    +-#if SQLITE_OMIT_AUTOVACUUM
    +-  "OMIT_AUTOVACUUM",
    +-#endif
    +-#if SQLITE_OMIT_BETWEEN_OPTIMIZATION
    +-  "OMIT_BETWEEN_OPTIMIZATION",
    +-#endif
    +-#if SQLITE_OMIT_BLOB_LITERAL
    +-  "OMIT_BLOB_LITERAL",
    +-#endif
    +-#if SQLITE_OMIT_BTREECOUNT
    +-  "OMIT_BTREECOUNT",
    +-#endif
    +-#if SQLITE_OMIT_BUILTIN_TEST
    +-  "OMIT_BUILTIN_TEST",
    +-#endif
    +-#if SQLITE_OMIT_CAST
    +-  "OMIT_CAST",
    +-#endif
    +-#if SQLITE_OMIT_CHECK
    +-  "OMIT_CHECK",
    +-#endif
    +-#if SQLITE_OMIT_COMPLETE
    +-  "OMIT_COMPLETE",
    +-#endif
    +-#if SQLITE_OMIT_COMPOUND_SELECT
    +-  "OMIT_COMPOUND_SELECT",
    +-#endif
    +-#if SQLITE_OMIT_CTE
    +-  "OMIT_CTE",
    +-#endif
    +-#if SQLITE_OMIT_DATETIME_FUNCS
    +-  "OMIT_DATETIME_FUNCS",
    +-#endif
    +-#if SQLITE_OMIT_DECLTYPE
    +-  "OMIT_DECLTYPE",
    +-#endif
    +-#if SQLITE_OMIT_DEPRECATED
    +-  "OMIT_DEPRECATED",
    +-#endif
    +-#if SQLITE_OMIT_DISKIO
    +-  "OMIT_DISKIO",
    +-#endif
    +-#if SQLITE_OMIT_EXPLAIN
    +-  "OMIT_EXPLAIN",
    +-#endif
    +-#if SQLITE_OMIT_FLAG_PRAGMAS
    +-  "OMIT_FLAG_PRAGMAS",
    +-#endif
    +-#if SQLITE_OMIT_FLOATING_POINT
    +-  "OMIT_FLOATING_POINT",
    +-#endif
    +-#if SQLITE_OMIT_FOREIGN_KEY
    +-  "OMIT_FOREIGN_KEY",
    +-#endif
    +-#if SQLITE_OMIT_GET_TABLE
    +-  "OMIT_GET_TABLE",
    +-#endif
    +-#if SQLITE_OMIT_INCRBLOB
    +-  "OMIT_INCRBLOB",
    +-#endif
    +-#if SQLITE_OMIT_INTEGRITY_CHECK
    +-  "OMIT_INTEGRITY_CHECK",
    +-#endif
    +-#if SQLITE_OMIT_LIKE_OPTIMIZATION
    +-  "OMIT_LIKE_OPTIMIZATION",
    +-#endif
    +-#if SQLITE_OMIT_LOAD_EXTENSION
    +-  "OMIT_LOAD_EXTENSION",
    +-#endif
    +-#if SQLITE_OMIT_LOCALTIME
    +-  "OMIT_LOCALTIME",
    +-#endif
    +-#if SQLITE_OMIT_LOOKASIDE
    +-  "OMIT_LOOKASIDE",
    +-#endif
    +-#if SQLITE_OMIT_MEMORYDB
    +-  "OMIT_MEMORYDB",
    +-#endif
    +-#if SQLITE_OMIT_OR_OPTIMIZATION
    +-  "OMIT_OR_OPTIMIZATION",
    +-#endif
    +-#if SQLITE_OMIT_PAGER_PRAGMAS
    +-  "OMIT_PAGER_PRAGMAS",
    +-#endif
    +-#if SQLITE_OMIT_PRAGMA
    +-  "OMIT_PRAGMA",
    +-#endif
    +-#if SQLITE_OMIT_PROGRESS_CALLBACK
    +-  "OMIT_PROGRESS_CALLBACK",
    +-#endif
    +-#if SQLITE_OMIT_QUICKBALANCE
    +-  "OMIT_QUICKBALANCE",
    +-#endif
    +-#if SQLITE_OMIT_REINDEX
    +-  "OMIT_REINDEX",
    +-#endif
    +-#if SQLITE_OMIT_SCHEMA_PRAGMAS
    +-  "OMIT_SCHEMA_PRAGMAS",
    +-#endif
    +-#if SQLITE_OMIT_SCHEMA_VERSION_PRAGMAS
    +-  "OMIT_SCHEMA_VERSION_PRAGMAS",
    +-#endif
    +-#if SQLITE_OMIT_SHARED_CACHE
    +-  "OMIT_SHARED_CACHE",
    +-#endif
    +-#if SQLITE_OMIT_SUBQUERY
    +-  "OMIT_SUBQUERY",
    +-#endif
    +-#if SQLITE_OMIT_TCL_VARIABLE
    +-  "OMIT_TCL_VARIABLE",
    +-#endif
    +-#if SQLITE_OMIT_TEMPDB
    +-  "OMIT_TEMPDB",
    +-#endif
    +-#if SQLITE_OMIT_TRACE
    +-  "OMIT_TRACE",
    +-#endif
    +-#if SQLITE_OMIT_TRIGGER
    +-  "OMIT_TRIGGER",
    +-#endif
    +-#if SQLITE_OMIT_TRUNCATE_OPTIMIZATION
    +-  "OMIT_TRUNCATE_OPTIMIZATION",
    +-#endif
    +-#if SQLITE_OMIT_UTF16
    +-  "OMIT_UTF16",
    +-#endif
    +-#if SQLITE_OMIT_VACUUM
    +-  "OMIT_VACUUM",
    +-#endif
    +-#if SQLITE_OMIT_VIEW
    +-  "OMIT_VIEW",
    +-#endif
    +-#if SQLITE_OMIT_VIRTUALTABLE
    +-  "OMIT_VIRTUALTABLE",
    +-#endif
    +-#if SQLITE_OMIT_WAL
    +-  "OMIT_WAL",
    +-#endif
    +-#if SQLITE_OMIT_WSD
    +-  "OMIT_WSD",
    +-#endif
    +-#if SQLITE_OMIT_XFER_OPT
    +-  "OMIT_XFER_OPT",
    +-#endif
    +-#if SQLITE_PERFORMANCE_TRACE
    +-  "PERFORMANCE_TRACE",
    +-#endif
    +-#if SQLITE_PROXY_DEBUG
    +-  "PROXY_DEBUG",
    +-#endif
    +-#if SQLITE_RTREE_INT_ONLY
    +-  "RTREE_INT_ONLY",
    +-#endif
    +-#if SQLITE_SECURE_DELETE
    +-  "SECURE_DELETE",
    +-#endif
    +-#if SQLITE_SMALL_STACK
    +-  "SMALL_STACK",
    +-#endif
    +-#if SQLITE_SOUNDEX
    +-  "SOUNDEX",
    +-#endif
    +-#if SQLITE_SYSTEM_MALLOC
    +-  "SYSTEM_MALLOC",
    +-#endif
    +-#if SQLITE_TCL
    +-  "TCL",
    +-#endif
    +-#if defined(SQLITE_TEMP_STORE) && !defined(SQLITE_TEMP_STORE_xc)
    +-  "TEMP_STORE=" CTIMEOPT_VAL(SQLITE_TEMP_STORE),
    +-#endif
    +-#if SQLITE_TEST
    +-  "TEST",
    +-#endif
    +-#if defined(SQLITE_THREADSAFE)
    +-  "THREADSAFE=" CTIMEOPT_VAL(SQLITE_THREADSAFE),
    +-#endif
    +-#if SQLITE_USE_ALLOCA
    +-  "USE_ALLOCA",
    +-#endif
    +-#if SQLITE_USER_AUTHENTICATION
    +-  "USER_AUTHENTICATION",
    +-#endif
    +-#if SQLITE_WIN32_MALLOC
    +-  "WIN32_MALLOC",
    +-#endif
    +-#if SQLITE_ZERO_MALLOC
    +-  "ZERO_MALLOC"
    +-#endif
    +-};
    +-
    + /*
    +-** Given the name of a compile-time option, return true if that option
    +-** was used and false if not.
    +-**
    +-** The name can optionally begin with "SQLITE_" but the "SQLITE_" prefix
    +-** is not required for a match.
    ++** Name of the default collating sequence
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_compileoption_used(const char *zOptName){
    +-  int i, n;
    +-
    +-#if SQLITE_ENABLE_API_ARMOR
    +-  if( zOptName==0 ){
    +-    (void)SQLITE_MISUSE_BKPT;
    +-    return 0;
    +-  }
    +-#endif
    +-  if( sqlite3StrNICmp(zOptName, "SQLITE_", 7)==0 ) zOptName += 7;
    +-  n = sqlite3Strlen30(zOptName);
    +-
    +-  /* Since ArraySize(azCompileOpt) is normally in single digits, a
    +-  ** linear search is adequate.  No need for a binary search. */
    +-  for(i=0; i<ArraySize(azCompileOpt); i++){
    +-    if( sqlite3StrNICmp(zOptName, azCompileOpt[i], n)==0
    +-     && sqlite3IsIdChar((unsigned char)azCompileOpt[i][n])==0
    +-    ){
    +-      return 1;
    +-    }
    +-  }
    +-  return 0;
    +-}
    +-
    +-/*
    +-** Return the N-th compile-time option string.  If N is out of range,
    +-** return a NULL pointer.
    +-*/
    +-SQLITE_API const char *SQLITE_STDCALL sqlite3_compileoption_get(int N){
    +-  if( N>=0 && N<ArraySize(azCompileOpt) ){
    +-    return azCompileOpt[N];
    +-  }
    +-  return 0;
    +-}
    +-
    +-#endif /* SQLITE_OMIT_COMPILEOPTION_DIAGS */
    ++SQLITE_PRIVATE const char sqlite3StrBINARY[] = "BINARY";
    + 
    +-/************** End of ctime.c ***********************************************/
    ++/************** End of global.c **********************************************/
    + /************** Begin file status.c ******************************************/
    + /*
    + ** 2008 June 18
    +@@ -15261,8 +18648,8 @@ SQLITE_API const char *SQLITE_STDCALL sqlite3_compileoption_get(int N){
    + ** 6000 lines long) it was split up into several smaller files and
    + ** this header information was factored out.
    + */
    +-#ifndef _VDBEINT_H_
    +-#define _VDBEINT_H_
    ++#ifndef SQLITE_VDBEINT_H
    ++#define SQLITE_VDBEINT_H
    + 
    + /*
    + ** The maximum number of times that a statement will try to reparse
    +@@ -15272,6 +18659,17 @@ SQLITE_API const char *SQLITE_STDCALL sqlite3_compileoption_get(int N){
    + # define SQLITE_MAX_SCHEMA_RETRY 50
    + #endif
    + 
    ++/*
    ++** VDBE_DISPLAY_P4 is true or false depending on whether or not the
    ++** "explain" P4 display logic is enabled.
    ++*/
    ++#if !defined(SQLITE_OMIT_EXPLAIN) || !defined(NDEBUG) \
    ++     || defined(VDBE_PROFILE) || defined(SQLITE_DEBUG)
    ++# define VDBE_DISPLAY_P4 1
    ++#else
    ++# define VDBE_DISPLAY_P4 0
    ++#endif
    ++
    + /*
    + ** SQL is translated into a sequence of instructions to be
    + ** executed by a virtual machine.  Each instruction is an instance
    +@@ -15287,73 +18685,88 @@ typedef unsigned Bool;
    + /* Opaque type used by code in vdbesort.c */
    + typedef struct VdbeSorter VdbeSorter;
    + 
    +-/* Opaque type used by the explainer */
    +-typedef struct Explain Explain;
    +-
    + /* Elements of the linked list at Vdbe.pAuxData */
    + typedef struct AuxData AuxData;
    + 
    ++/* Types of VDBE cursors */
    ++#define CURTYPE_BTREE       0
    ++#define CURTYPE_SORTER      1
    ++#define CURTYPE_VTAB        2
    ++#define CURTYPE_PSEUDO      3
    ++
    + /*
    +-** A cursor is a pointer into a single BTree within a database file.
    +-** The cursor can seek to a BTree entry with a particular key, or
    +-** loop over all entries of the Btree.  You can also insert new BTree
    +-** entries or retrieve the key or data from the entry that the cursor
    +-** is currently pointing to.
    ++** A VdbeCursor is an superclass (a wrapper) for various cursor objects:
    + **
    +-** Cursors can also point to virtual tables, sorters, or "pseudo-tables".
    +-** A pseudo-table is a single-row table implemented by registers.
    +-** 
    +-** Every cursor that the virtual machine has open is represented by an
    +-** instance of the following structure.
    ++**      * A b-tree cursor
    ++**          -  In the main database or in an ephemeral database
    ++**          -  On either an index or a table
    ++**      * A sorter
    ++**      * A virtual table
    ++**      * A one-row "pseudotable" stored in a single register
    + */
    ++typedef struct VdbeCursor VdbeCursor;
    + struct VdbeCursor {
    +-  BtCursor *pCursor;    /* The cursor structure of the backend */
    +-  Btree *pBt;           /* Separate file holding temporary table */
    +-  KeyInfo *pKeyInfo;    /* Info about index keys needed by index cursors */
    +-  int seekResult;       /* Result of previous sqlite3BtreeMoveto() */
    +-  int pseudoTableReg;   /* Register holding pseudotable content. */
    +-  i16 nField;           /* Number of fields in the header */
    +-  u16 nHdrParsed;       /* Number of header fields parsed so far */
    ++  u8 eCurType;            /* One of the CURTYPE_* values above */
    ++  i8 iDb;                 /* Index of cursor database in db->aDb[] (or -1) */
    ++  u8 nullRow;             /* True if pointing to a row with no data */
    ++  u8 deferredMoveto;      /* A call to sqlite3BtreeMoveto() is needed */
    ++  u8 isTable;             /* True for rowid tables.  False for indexes */
    + #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 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() */
    +-  VdbeSorter *pSorter;  /* Sorter object for OP_SorterOpen cursors */
    +-#ifdef SQLITE_ENABLE_COLUMN_USED_MASK
    +-  u64 maskUsed;         /* Mask of columns used by this cursor */
    ++  u8 seekOp;              /* Most recent seek operation on this cursor */
    ++  u8 wrFlag;              /* The wrFlag argument to sqlite3BtreeCursor() */
    + #endif
    ++  Bool isEphemeral:1;     /* True for an ephemeral table */
    ++  Bool useRandomRowid:1;  /* Generate new record numbers semi-randomly */
    ++  Bool isOrdered:1;       /* True if the table is not BTREE_UNORDERED */
    ++  Btree *pBtx;            /* Separate file holding temporary table */
    ++  i64 seqCount;           /* Sequence counter */
    ++  int *aAltMap;           /* Mapping from table to index column numbers */
    + 
    +-  /* Cached information about the header for the data record that the
    +-  ** cursor is currently pointing to.  Only valid if cacheStatus matches
    ++  /* Cached OP_Column parse information is only valid if cacheStatus matches
    +   ** Vdbe.cacheCtr.  Vdbe.cacheCtr will never take on the value of
    +-  ** CACHE_STALE and so setting cacheStatus=CACHE_STALE guarantees that
    +-  ** the cache is out of date.
    +-  **
    +-  ** aRow might point to (ephemeral) data for the current row, or it might
    +-  ** be NULL.
    +-  */
    +-  u32 cacheStatus;      /* Cache is valid if this matches Vdbe.cacheCtr */
    +-  u32 payloadSize;      /* Total number of bytes in the record */
    +-  u32 szRow;            /* Byte available in aRow */
    +-  u32 iHdrOffset;       /* Offset to next unparsed byte of the header */
    +-  const u8 *aRow;       /* Data for the current row, if all on one page */
    +-  u32 *aOffset;         /* Pointer to aType[nField] */
    +-  u32 aType[1];         /* Type values for all entries in the record */
    ++  ** CACHE_STALE (0) and so setting cacheStatus=CACHE_STALE guarantees that
    ++  ** the cache is out of date. */
    ++  u32 cacheStatus;        /* Cache is valid if this matches Vdbe.cacheCtr */
    ++  int seekResult;         /* Result of previous sqlite3BtreeMoveto() or 0
    ++                          ** if there have been no prior seeks on the cursor. */
    ++  /* seekResult does not distinguish between "no seeks have ever occurred
    ++  ** on this cursor" and "the most recent seek was an exact match".
    ++  ** For CURTYPE_PSEUDO, seekResult is the register holding the record */
    ++
    ++  /* When a new VdbeCursor is allocated, only the fields above are zeroed.
    ++  ** The fields that follow are uninitialized, and must be individually
    ++  ** initialized prior to first use. */
    ++  VdbeCursor *pAltCursor; /* Associated index cursor from which to read */
    ++  union {
    ++    BtCursor *pCursor;          /* CURTYPE_BTREE or _PSEUDO.  Btree cursor */
    ++    sqlite3_vtab_cursor *pVCur; /* CURTYPE_VTAB.              Vtab cursor */
    ++    VdbeSorter *pSorter;        /* CURTYPE_SORTER.            Sorter object */
    ++  } uc;
    ++  KeyInfo *pKeyInfo;      /* Info about index keys needed by index cursors */
    ++  u32 iHdrOffset;         /* Offset to next unparsed byte of the header */
    ++  Pgno pgnoRoot;          /* Root page of the open btree cursor */
    ++  i16 nField;             /* Number of fields in the header */
    ++  u16 nHdrParsed;         /* Number of header fields parsed so far */
    ++  i64 movetoTarget;       /* Argument to the deferred sqlite3BtreeMoveto() */
    ++  u32 *aOffset;           /* Pointer to aType[nField] */
    ++  const u8 *aRow;         /* Data for the current row, if all on one page */
    ++  u32 payloadSize;        /* Total number of bytes in the record */
    ++  u32 szRow;              /* Byte available in aRow */
    ++#ifdef SQLITE_ENABLE_COLUMN_USED_MASK
    ++  u64 maskUsed;           /* Mask of columns used by this cursor */
    ++#endif
    ++
    +   /* 2*nField extra array elements allocated for aType[], beyond the one
    +   ** static element declared in the structure.  nField total array slots for
    +   ** aType[] and nField+1 array slots for aOffset[] */
    ++  u32 aType[1];           /* Type values record decode.  MUST BE LAST */
    + };
    +-typedef struct VdbeCursor VdbeCursor;
    ++
    ++
    ++/*
    ++** A value for VdbeCursor.cacheStatus that means the cache is always invalid.
    ++*/
    ++#define CACHE_STALE 0
    + 
    + /*
    + ** When a sub-program is executed (OP_Program), a structure of this type
    +@@ -15383,15 +18796,15 @@ struct VdbeFrame {
    +   Op *aOp;                /* Program instructions for parent frame */
    +   i64 *anExec;            /* Event counters from parent frame */
    +   Mem *aMem;              /* Array of memory cells for parent frame */
    +-  u8 *aOnceFlag;          /* Array of OP_Once flags for parent frame */
    +   VdbeCursor **apCsr;     /* Array of Vdbe cursors for parent frame */
    ++  u8 *aOnce;              /* Bitmask used by OP_Once */
    +   void *token;            /* Copy of SubProgram.token */
    +   i64 lastRowid;          /* Last insert rowid (sqlite3.lastRowid) */
    ++  AuxData *pAuxData;      /* Linked list of auxdata allocations */
    +   int nCursor;            /* Number of entries in apCsr */
    +   int pc;                 /* Program Counter in parent (calling) frame */
    +   int nOp;                /* Size of aOp array */
    +   int nMem;               /* Number of entries in aMem */
    +-  int nOnceFlag;          /* Number of entries in aOnceFlag */
    +   int nChildMem;          /* Number of memory cells for child frame */
    +   int nChildCsr;          /* Number of cursors for child frame */
    +   int nChange;            /* Statement changes (Vdbe.nChange)     */
    +@@ -15400,21 +18813,17 @@ struct VdbeFrame {
    + 
    + #define VdbeFrameMem(p) ((Mem *)&((u8 *)p)[ROUND8(sizeof(VdbeFrame))])
    + 
    +-/*
    +-** A value for VdbeCursor.cacheValid that means the cache is always invalid.
    +-*/
    +-#define CACHE_STALE 0
    +-
    + /*
    + ** Internally, the vdbe manipulates nearly all SQL values as Mem
    + ** structures. Each Mem struct may cache multiple representations (string,
    + ** integer etc.) of the same value.
    + */
    +-struct Mem {
    ++struct sqlite3_value {
    +   union MemValue {
    +     double r;           /* Real value used when MEM_Real is set in flags */
    +     i64 i;              /* Integer value used when MEM_Int is set in flags */
    +-    int nZero;          /* Used when bit MEM_Zero is set in flags */
    ++    int nZero;          /* Extra zero bytes when MEM_Zero and MEM_Blob set */
    ++    const char *zPType; /* Pointer type when MEM_Term|MEM_Subtype|MEM_Null */
    +     FuncDef *pDef;      /* Used only when flags==MEM_Agg */
    +     RowSet *pRowSet;    /* Used only when flags==MEM_RowSet */
    +     VdbeFrame *pFrame;  /* Used when flags==MEM_Frame */
    +@@ -15446,7 +18855,10 @@ struct Mem {
    + ** representations of the value stored in the Mem struct.
    + **
    + ** If the MEM_Null flag is set, then the value is an SQL NULL value.
    +-** No other flags may be set in this case.
    ++** For a pointer type created using sqlite3_bind_pointer() or
    ++** sqlite3_result_pointer() the MEM_Term and MEM_Subtype flags are also set.
    ++** If both MEM_Null and MEM_Zero are set, that means that the value is
    ++** an unchanging column value from VColumn.
    + **
    + ** If the MEM_Str flag is set then Mem.z points at a string representation.
    + ** Usually this is encoded in the same unicode encoding as the main
    +@@ -15454,7 +18866,7 @@ struct Mem {
    + ** set, then the string is nul terminated. The MEM_Int and MEM_Real 
    + ** flags may coexist with the MEM_Str flag.
    + */
    +-#define MEM_Null      0x0001   /* Value is NULL */
    ++#define MEM_Null      0x0001   /* Value is NULL (or a pointer) */
    + #define MEM_Str       0x0002   /* Value is a string */
    + #define MEM_Int       0x0004   /* Value is an integer */
    + #define MEM_Real      0x0008   /* Value is a real number */
    +@@ -15464,7 +18876,7 @@ struct Mem {
    + #define MEM_Frame     0x0040   /* Value is a VdbeFrame object */
    + #define MEM_Undefined 0x0080   /* Value is undefined */
    + #define MEM_Cleared   0x0100   /* NULL set by OP_Null, not from data */
    +-#define MEM_TypeMask  0x01ff   /* Mask of type bits */
    ++#define MEM_TypeMask  0xc1ff   /* Mask of type bits */
    + 
    + 
    + /* Whenever Mem contains a valid string or blob representation, one of
    +@@ -15472,17 +18884,24 @@ struct Mem {
    + ** policy for Mem.z.  The MEM_Term flag tells us whether or not the
    + ** string is \000 or \u0000 terminated
    + */
    +-#define MEM_Term      0x0200   /* String rep is nul terminated */
    ++#define MEM_Term      0x0200   /* String in Mem.z is zero terminated */
    + #define MEM_Dyn       0x0400   /* Need to call Mem.xDel() on Mem.z */
    + #define MEM_Static    0x0800   /* Mem.z points to a static string */
    + #define MEM_Ephem     0x1000   /* Mem.z points to an ephemeral string */
    + #define MEM_Agg       0x2000   /* Mem.z points to an agg function context */
    + #define MEM_Zero      0x4000   /* Mem.i contains count of 0s appended to blob */
    ++#define MEM_Subtype   0x8000   /* Mem.eSubtype is valid */
    + #ifdef SQLITE_OMIT_INCRBLOB
    +   #undef MEM_Zero
    +   #define MEM_Zero 0x0000
    + #endif
    + 
    ++/* Return TRUE if Mem X contains dynamically allocated content - anything
    ++** that needs to be deallocated to avoid a leak.
    ++*/
    ++#define VdbeMemDynamic(X)  \
    ++  (((X)->flags&(MEM_Agg|MEM_Dyn|MEM_RowSet|MEM_Frame))!=0)
    ++
    + /*
    + ** Clear any existing type flags from a Mem and replace them with f
    + */
    +@@ -15505,11 +18924,11 @@ struct Mem {
    + ** when the VM is halted (if not before).
    + */
    + struct AuxData {
    +-  int iOp;                        /* Instruction number of OP_Function opcode */
    +-  int iArg;                       /* Index of function argument. */
    ++  int iAuxOp;                     /* Instruction number of OP_Function opcode */
    ++  int iAuxArg;                    /* Index of function argument. */
    +   void *pAux;                     /* Aux data pointer */
    +-  void (*xDelete)(void *);        /* Destructor for the aux data */
    +-  AuxData *pNext;                 /* Next element in list */
    ++  void (*xDeleteAux)(void*);      /* Destructor for the aux data */
    ++  AuxData *pNextAux;              /* Next element in list */
    + };
    + 
    + /*
    +@@ -15538,18 +18957,6 @@ struct sqlite3_context {
    +   sqlite3_value *argv[1]; /* Argument set */
    + };
    + 
    +-/*
    +-** An Explain object accumulates indented output which is helpful
    +-** in describing recursive data structures.
    +-*/
    +-struct Explain {
    +-  Vdbe *pVdbe;       /* Attach the explanation to this Vdbe */
    +-  StrAccum str;      /* The string being accumulated */
    +-  int nIndent;       /* Number of elements in aIndent */
    +-  u16 aIndent[100];  /* Levels of indentation */
    +-  char zBase[100];   /* Initial space */
    +-};
    +-
    + /* A bitfield type for use inside of structures.  Always follow with :N where
    + ** N is the number of bits.
    + */
    +@@ -15574,53 +18981,56 @@ struct ScanStatus {
    + */
    + struct Vdbe {
    +   sqlite3 *db;            /* The database connection that owns this statement */
    ++  Vdbe *pPrev,*pNext;     /* Linked list of VDBEs with the same Vdbe.db */
    ++  Parse *pParse;          /* Parsing context used to create this Vdbe */
    ++  ynVar nVar;             /* Number of entries in aVar[] */
    ++  u32 magic;              /* Magic number for sanity checking */
    ++  int nMem;               /* Number of memory locations currently allocated */
    ++  int nCursor;            /* Number of slots in apCsr[] */
    ++  u32 cacheCtr;           /* VdbeCursor row cache generation counter */
    ++  int pc;                 /* The program counter */
    ++  int rc;                 /* Value to return */
    ++  int nChange;            /* Number of db changes made since last reset */
    ++  int iStatement;         /* Statement number (or 0 if has not opened stmt) */
    ++  i64 iCurrentTime;       /* Value of julianday('now') for this statement */
    ++  i64 nFkConstraint;      /* Number of imm. FK constraints this VM */
    ++  i64 nStmtDefCons;       /* Number of def. constraints when stmt started */
    ++  i64 nStmtDefImmCons;    /* Number of def. imm constraints when stmt started */
    ++
    ++  /* When allocating a new Vdbe object, all of the fields below should be
    ++  ** initialized to zero or NULL */
    ++
    +   Op *aOp;                /* Space to hold the virtual machine's program */
    +   Mem *aMem;              /* The memory locations */
    +   Mem **apArg;            /* Arguments to currently executing user function */
    +   Mem *aColName;          /* Column names to return */
    +   Mem *pResultSet;        /* Pointer to an array of results */
    +-  Parse *pParse;          /* Parsing context used to create this Vdbe */
    +-  int nMem;               /* Number of memory locations currently allocated */
    +-  int nOp;                /* Number of instructions in the program */
    +-  int nCursor;            /* Number of slots in apCsr[] */
    +-  u32 magic;              /* Magic number for sanity checking */
    +   char *zErrMsg;          /* Error message written here */
    +-  Vdbe *pPrev,*pNext;     /* Linked list of VDBEs with the same Vdbe.db */
    +   VdbeCursor **apCsr;     /* One element of this array for each open cursor */
    +   Mem *aVar;              /* Values for the OP_Variable opcode. */
    +-  char **azVar;           /* Name of variables */
    +-  ynVar nVar;             /* Number of entries in aVar[] */
    +-  ynVar nzVar;            /* Number of entries in azVar[] */
    +-  u32 cacheCtr;           /* VdbeCursor row cache generation counter */
    +-  int pc;                 /* The program counter */
    +-  int rc;                 /* Value to return */
    ++  VList *pVList;          /* Name of variables */
    ++#ifndef SQLITE_OMIT_TRACE
    ++  i64 startTime;          /* Time when query started - used for profiling */
    ++#endif
    ++  int nOp;                /* Number of instructions in the program */
    + #ifdef SQLITE_DEBUG
    +   int rcApp;              /* errcode set by sqlite3_result_error_code() */
    + #endif
    +   u16 nResColumn;         /* Number of columns in one row of the result set */
    +   u8 errorAction;         /* Recovery action to do in case of an error */
    +   u8 minWriteFileFormat;  /* Minimum file format for writable database files */
    ++  u8 prepFlags;           /* SQLITE_PREPARE_* flags */
    ++  bft expired:1;          /* True if the VM needs to be recompiled */
    ++  bft doingRerun:1;       /* True if rerunning after an auto-reprepare */
    +   bft explain:2;          /* True if EXPLAIN present on SQL command */
    +   bft changeCntOn:1;      /* True to update the change-counter */
    +-  bft expired:1;          /* True if the VM needs to be recompiled */
    +   bft runOnlyOnce:1;      /* Automatically expire on reset */
    +   bft usesStmtJournal:1;  /* True if uses a statement journal */
    +   bft readOnly:1;         /* True for statements that do not write */
    +   bft bIsReader:1;        /* True for statements that read */
    +-  bft isPrepareV2:1;      /* True if prepared with prepare_v2() */
    +-  bft doingRerun:1;       /* True if rerunning after an auto-reprepare */
    +-  int nChange;            /* Number of db changes made since last reset */
    +   yDbMask btreeMask;      /* Bitmask of db->aDb[] entries referenced */
    +   yDbMask lockMask;       /* Subset of btreeMask that requires a lock */
    +-  int iStatement;         /* Statement number (or 0 if has not opened stmt) */
    +-  u32 aCounter[5];        /* Counters used by sqlite3_stmt_status() */
    +-#ifndef SQLITE_OMIT_TRACE
    +-  i64 startTime;          /* Time when query started - used for profiling */
    +-#endif
    +-  i64 iCurrentTime;       /* Value of julianday('now') for this statement */
    +-  i64 nFkConstraint;      /* Number of imm. FK constraints this VM */
    +-  i64 nStmtDefCons;       /* Number of def. constraints when stmt started */
    +-  i64 nStmtDefImmCons;    /* Number of def. imm constraints when stmt started */
    ++  u32 aCounter[7];        /* Counters used by sqlite3_stmt_status() */
    +   char *zSql;             /* Text of the SQL statement that generated this */
    +   void *pFree;            /* Free this when deleting the vdbe */
    +   VdbeFrame *pFrame;      /* Parent frame */
    +@@ -15628,8 +19038,6 @@ struct Vdbe {
    +   int nFrame;             /* Number of frames in pFrame list */
    +   u32 expmask;            /* Binding to these vars invalidates VM */
    +   SubProgram *pProgram;   /* Linked list of all sub-programs used by VM */
    +-  int nOnceFlag;          /* Size of array aOnceFlag[] */
    +-  u8 *aOnceFlag;          /* Flags for OP_Once */
    +   AuxData *pAuxData;      /* Linked list of auxdata allocations */
    + #ifdef SQLITE_ENABLE_STMT_SCANSTATUS
    +   i64 *anExec;            /* Number of times each op has been executed */
    +@@ -15641,10 +19049,31 @@ struct Vdbe {
    + /*
    + ** The following are allowed values for Vdbe.magic
    + */
    +-#define VDBE_MAGIC_INIT     0x26bceaa5    /* Building a VDBE program */
    +-#define VDBE_MAGIC_RUN      0xbdf20da3    /* VDBE is ready to execute */
    +-#define VDBE_MAGIC_HALT     0x519c2973    /* VDBE has completed execution */
    +-#define VDBE_MAGIC_DEAD     0xb606c3c8    /* The VDBE has been deallocated */
    ++#define VDBE_MAGIC_INIT     0x16bceaa5    /* Building a VDBE program */
    ++#define VDBE_MAGIC_RUN      0x2df20da3    /* VDBE is ready to execute */
    ++#define VDBE_MAGIC_HALT     0x319c2973    /* VDBE has completed execution */
    ++#define VDBE_MAGIC_RESET    0x48fa9f76    /* Reset and ready to run again */
    ++#define VDBE_MAGIC_DEAD     0x5606c3c8    /* The VDBE has been deallocated */
    ++
    ++/*
    ++** Structure used to store the context required by the 
    ++** sqlite3_preupdate_*() API functions.
    ++*/
    ++struct PreUpdate {
    ++  Vdbe *v;
    ++  VdbeCursor *pCsr;               /* Cursor to read old values from */
    ++  int op;                         /* One of SQLITE_INSERT, UPDATE, DELETE */
    ++  u8 *aRecord;                    /* old.* database record */
    ++  KeyInfo keyinfo;
    ++  UnpackedRecord *pUnpacked;      /* Unpacked version of aRecord[] */
    ++  UnpackedRecord *pNewUnpacked;   /* Unpacked version of new.* record */
    ++  int iNewReg;                    /* Register for new.* values */
    ++  i64 iKey1;                      /* First key value passed to hook */
    ++  i64 iKey2;                      /* Second key value passed to hook */
    ++  Mem *aNew;                      /* Array of new.* values */
    ++  Table *pTab;                    /* Schema object being upated */          
    ++  Index *pPk;                     /* PK index if pTab is WITHOUT ROWID */
    ++};
    + 
    + /*
    + ** Function prototypes
    +@@ -15652,16 +19081,17 @@ struct Vdbe {
    + SQLITE_PRIVATE void sqlite3VdbeError(Vdbe*, const char *, ...);
    + SQLITE_PRIVATE void sqlite3VdbeFreeCursor(Vdbe *, VdbeCursor*);
    + void sqliteVdbePopStack(Vdbe*,int);
    +-SQLITE_PRIVATE int sqlite3VdbeCursorMoveto(VdbeCursor*);
    ++SQLITE_PRIVATE int sqlite3VdbeCursorMoveto(VdbeCursor**, int*);
    + SQLITE_PRIVATE int sqlite3VdbeCursorRestore(VdbeCursor*);
    + #if defined(SQLITE_DEBUG) || defined(VDBE_PROFILE)
    + SQLITE_PRIVATE void sqlite3VdbePrintOp(FILE*, int, Op*);
    + #endif
    + SQLITE_PRIVATE u32 sqlite3VdbeSerialTypeLen(u32);
    +-SQLITE_PRIVATE u32 sqlite3VdbeSerialType(Mem*, int);
    ++SQLITE_PRIVATE u8 sqlite3VdbeOneByteSerialTypeLen(u8);
    ++SQLITE_PRIVATE u32 sqlite3VdbeSerialType(Mem*, int, u32*);
    + SQLITE_PRIVATE u32 sqlite3VdbeSerialPut(unsigned char*, Mem*, u32);
    + SQLITE_PRIVATE u32 sqlite3VdbeSerialGet(const unsigned char*, u32, Mem*);
    +-SQLITE_PRIVATE void sqlite3VdbeDeleteAuxData(Vdbe*, int, int);
    ++SQLITE_PRIVATE void sqlite3VdbeDeleteAuxData(sqlite3*, AuxData**, int, int);
    + 
    + int sqlite2BtreeKeyCompare(BtCursor *, const void *, int, int, int *);
    + SQLITE_PRIVATE int sqlite3VdbeIdxKeyCompare(sqlite3*,VdbeCursor*,UnpackedRecord*,int*);
    +@@ -15682,6 +19112,7 @@ SQLITE_PRIVATE void sqlite3VdbeMemSetInt64(Mem*, i64);
    + #else
    + SQLITE_PRIVATE   void sqlite3VdbeMemSetDouble(Mem*, double);
    + #endif
    ++SQLITE_PRIVATE void sqlite3VdbeMemSetPointer(Mem*, void*, const char*, void(*)(void*));
    + SQLITE_PRIVATE void sqlite3VdbeMemInit(Mem*,sqlite3*,u16);
    + SQLITE_PRIVATE void sqlite3VdbeMemSetNull(Mem*);
    + SQLITE_PRIVATE void sqlite3VdbeMemSetZeroBlob(Mem*,int);
    +@@ -15695,10 +19126,8 @@ SQLITE_PRIVATE void sqlite3VdbeIntegerAffinity(Mem*);
    + SQLITE_PRIVATE int sqlite3VdbeMemRealify(Mem*);
    + SQLITE_PRIVATE int sqlite3VdbeMemNumerify(Mem*);
    + SQLITE_PRIVATE void sqlite3VdbeMemCast(Mem*,u8,u8);
    +-SQLITE_PRIVATE int sqlite3VdbeMemFromBtree(BtCursor*,u32,u32,int,Mem*);
    ++SQLITE_PRIVATE int sqlite3VdbeMemFromBtree(BtCursor*,u32,u32,Mem*);
    + SQLITE_PRIVATE void sqlite3VdbeMemRelease(Mem *p);
    +-#define VdbeMemDynamic(X)  \
    +-  (((X)->flags&(MEM_Agg|MEM_Dyn|MEM_RowSet|MEM_Frame))!=0)
    + SQLITE_PRIVATE int sqlite3VdbeMemFinalize(Mem*, FuncDef*);
    + SQLITE_PRIVATE const char *sqlite3OpcodeName(int);
    + SQLITE_PRIVATE int sqlite3VdbeMemGrow(Mem *pMem, int n, int preserve);
    +@@ -15706,22 +19135,29 @@ SQLITE_PRIVATE int sqlite3VdbeMemClearAndResize(Mem *pMem, int n);
    + SQLITE_PRIVATE int sqlite3VdbeCloseStatement(Vdbe *, int);
    + SQLITE_PRIVATE void sqlite3VdbeFrameDelete(VdbeFrame*);
    + SQLITE_PRIVATE int sqlite3VdbeFrameRestore(VdbeFrame *);
    ++#ifdef SQLITE_ENABLE_PREUPDATE_HOOK
    ++SQLITE_PRIVATE void sqlite3VdbePreUpdateHook(Vdbe*,VdbeCursor*,int,const char*,Table*,i64,int);
    ++#endif
    + SQLITE_PRIVATE int sqlite3VdbeTransferError(Vdbe *p);
    + 
    + SQLITE_PRIVATE int sqlite3VdbeSorterInit(sqlite3 *, int, 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 *);
    ++SQLITE_PRIVATE int sqlite3VdbeSorterNext(sqlite3 *, const VdbeCursor *);
    + SQLITE_PRIVATE int sqlite3VdbeSorterRewind(const VdbeCursor *, int *);
    + SQLITE_PRIVATE int sqlite3VdbeSorterWrite(const VdbeCursor *, Mem *);
    + SQLITE_PRIVATE int sqlite3VdbeSorterCompare(const VdbeCursor *, Mem *, int, int *);
    + 
    +-#if !defined(SQLITE_OMIT_SHARED_CACHE) && SQLITE_THREADSAFE>0
    ++#if !defined(SQLITE_OMIT_SHARED_CACHE) 
    + SQLITE_PRIVATE   void sqlite3VdbeEnter(Vdbe*);
    +-SQLITE_PRIVATE   void sqlite3VdbeLeave(Vdbe*);
    + #else
    + # define sqlite3VdbeEnter(X)
    ++#endif
    ++
    ++#if !defined(SQLITE_OMIT_SHARED_CACHE) && SQLITE_THREADSAFE>0
    ++SQLITE_PRIVATE   void sqlite3VdbeLeave(Vdbe*);
    ++#else
    + # define sqlite3VdbeLeave(X)
    + #endif
    + 
    +@@ -15736,12 +19172,14 @@ SQLITE_PRIVATE int sqlite3VdbeCheckFk(Vdbe *, int);
    + # define sqlite3VdbeCheckFk(p,i) 0
    + #endif
    + 
    +-SQLITE_PRIVATE int sqlite3VdbeMemTranslate(Mem*, u8);
    + #ifdef SQLITE_DEBUG
    + SQLITE_PRIVATE   void sqlite3VdbePrintSql(Vdbe*);
    + SQLITE_PRIVATE   void sqlite3VdbeMemPrettyPrint(Mem *pMem, char *zBuf);
    + #endif
    +-SQLITE_PRIVATE int sqlite3VdbeMemHandleBom(Mem *pMem);
    ++#ifndef SQLITE_OMIT_UTF16
    ++SQLITE_PRIVATE   int sqlite3VdbeMemTranslate(Mem*, u8);
    ++SQLITE_PRIVATE   int sqlite3VdbeMemHandleBom(Mem *pMem);
    ++#endif
    + 
    + #ifndef SQLITE_OMIT_INCRBLOB
    + SQLITE_PRIVATE   int sqlite3VdbeMemExpandBlob(Mem *);
    +@@ -15751,7 +19189,7 @@ SQLITE_PRIVATE   int sqlite3VdbeMemExpandBlob(Mem *);
    +   #define ExpandBlob(P) SQLITE_OK
    + #endif
    + 
    +-#endif /* !defined(_VDBEINT_H_) */
    ++#endif /* !defined(SQLITE_VDBEINT_H) */
    + 
    + /************** End of vdbeInt.h *********************************************/
    + /************** Continuing where we left off in status.c *********************/
    +@@ -15759,15 +19197,15 @@ SQLITE_PRIVATE   int sqlite3VdbeMemExpandBlob(Mem *);
    + /*
    + ** Variables in which to record status information.
    + */
    +-typedef struct sqlite3StatType sqlite3StatType;
    +-static SQLITE_WSD struct sqlite3StatType {
    + #if SQLITE_PTRSIZE>4
    +-  sqlite3_int64 nowValue[10];         /* Current value */
    +-  sqlite3_int64 mxValue[10];          /* Maximum value */
    ++typedef sqlite3_int64 sqlite3StatValueType;
    + #else
    +-  u32 nowValue[10];                   /* Current value */
    +-  u32 mxValue[10];                    /* Maximum value */
    ++typedef u32 sqlite3StatValueType;
    + #endif
    ++typedef struct sqlite3StatType sqlite3StatType;
    ++static SQLITE_WSD struct sqlite3StatType {
    ++  sqlite3StatValueType nowValue[10];  /* Current value */
    ++  sqlite3StatValueType mxValue[10];   /* Maximum value */
    + } sqlite3Stat = { {0,}, {0,} };
    + 
    + /*
    +@@ -15848,25 +19286,30 @@ SQLITE_PRIVATE void sqlite3StatusDown(int op, int N){
    + }
    + 
    + /*
    +-** Set the value of a status to X.  The highwater mark is adjusted if
    +-** necessary.  The caller must hold the appropriate mutex.
    ++** Adjust the highwater mark if necessary.
    ++** The caller must hold the appropriate mutex.
    + */
    +-SQLITE_PRIVATE void sqlite3StatusSet(int op, int X){
    ++SQLITE_PRIVATE void sqlite3StatusHighwater(int op, int X){
    ++  sqlite3StatValueType newValue;
    +   wsdStatInit;
    ++  assert( X>=0 );
    ++  newValue = (sqlite3StatValueType)X;
    +   assert( op>=0 && op<ArraySize(wsdStat.nowValue) );
    +   assert( op>=0 && op<ArraySize(statMutex) );
    +   assert( sqlite3_mutex_held(statMutex[op] ? sqlite3Pcache1Mutex()
    +                                            : sqlite3MallocMutex()) );
    +-  wsdStat.nowValue[op] = X;
    +-  if( wsdStat.nowValue[op]>wsdStat.mxValue[op] ){
    +-    wsdStat.mxValue[op] = wsdStat.nowValue[op];
    ++  assert( op==SQLITE_STATUS_MALLOC_SIZE
    ++          || op==SQLITE_STATUS_PAGECACHE_SIZE
    ++          || op==SQLITE_STATUS_PARSER_STACK );
    ++  if( newValue>wsdStat.mxValue[op] ){
    ++    wsdStat.mxValue[op] = newValue;
    +   }
    + }
    + 
    + /*
    + ** Query status information.
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_status64(
    ++SQLITE_API int sqlite3_status64(
    +   int op,
    +   sqlite3_int64 *pCurrent,
    +   sqlite3_int64 *pHighwater,
    +@@ -15891,8 +19334,8 @@ SQLITE_API int SQLITE_STDCALL sqlite3_status64(
    +   (void)pMutex;  /* Prevent warning when SQLITE_THREADSAFE=0 */
    +   return SQLITE_OK;
    + }
    +-SQLITE_API int SQLITE_STDCALL sqlite3_status(int op, int *pCurrent, int *pHighwater, int resetFlag){
    +-  sqlite3_int64 iCur, iHwtr;
    ++SQLITE_API int sqlite3_status(int op, int *pCurrent, int *pHighwater, int resetFlag){
    ++  sqlite3_int64 iCur = 0, iHwtr = 0;
    +   int rc;
    + #ifdef SQLITE_ENABLE_API_ARMOR
    +   if( pCurrent==0 || pHighwater==0 ) return SQLITE_MISUSE_BKPT;
    +@@ -15905,10 +19348,32 @@ SQLITE_API int SQLITE_STDCALL sqlite3_status(int op, int *pCurrent, int *pHighwa
    +   return rc;
    + }
    + 
    ++/*
    ++** Return the number of LookasideSlot elements on the linked list
    ++*/
    ++static u32 countLookasideSlots(LookasideSlot *p){
    ++  u32 cnt = 0;
    ++  while( p ){
    ++    p = p->pNext;
    ++    cnt++;
    ++  }
    ++  return cnt;
    ++}
    ++
    ++/*
    ++** Count the number of slots of lookaside memory that are outstanding
    ++*/
    ++SQLITE_PRIVATE int sqlite3LookasideUsed(sqlite3 *db, int *pHighwater){
    ++  u32 nInit = countLookasideSlots(db->lookaside.pInit);
    ++  u32 nFree = countLookasideSlots(db->lookaside.pFree);
    ++  if( pHighwater ) *pHighwater = db->lookaside.nSlot - nInit;
    ++  return db->lookaside.nSlot - (nInit+nFree);
    ++}
    ++
    + /*
    + ** Query status information for a single database connection
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_db_status(
    ++SQLITE_API int sqlite3_db_status(
    +   sqlite3 *db,          /* The database connection whose status is desired */
    +   int op,               /* Status verb */
    +   int *pCurrent,        /* Write current value here */
    +@@ -15924,10 +19389,15 @@ SQLITE_API int SQLITE_STDCALL sqlite3_db_status(
    +   sqlite3_mutex_enter(db->mutex);
    +   switch( op ){
    +     case SQLITE_DBSTATUS_LOOKASIDE_USED: {
    +-      *pCurrent = db->lookaside.nOut;
    +-      *pHighwater = db->lookaside.mxOut;
    ++      *pCurrent = sqlite3LookasideUsed(db, pHighwater);
    +       if( resetFlag ){
    +-        db->lookaside.mxOut = db->lookaside.nOut;
    ++        LookasideSlot *p = db->lookaside.pFree;
    ++        if( p ){
    ++          while( p->pNext ) p = p->pNext;
    ++          p->pNext = db->lookaside.pInit;
    ++          db->lookaside.pInit = db->lookaside.pFree;
    ++          db->lookaside.pFree = 0;
    ++        }
    +       }
    +       break;
    +     }
    +@@ -15953,6 +19423,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_db_status(
    +     ** by all pagers associated with the given database connection.  The
    +     ** highwater mark is meaningless and is returned as zero.
    +     */
    ++    case SQLITE_DBSTATUS_CACHE_USED_SHARED:
    +     case SQLITE_DBSTATUS_CACHE_USED: {
    +       int totalUsed = 0;
    +       int i;
    +@@ -15961,7 +19432,11 @@ SQLITE_API int SQLITE_STDCALL sqlite3_db_status(
    +         Btree *pBt = db->aDb[i].pBt;
    +         if( pBt ){
    +           Pager *pPager = sqlite3BtreePager(pBt);
    +-          totalUsed += sqlite3PagerMemUsed(pPager);
    ++          int nByte = sqlite3PagerMemUsed(pPager);
    ++          if( op==SQLITE_DBSTATUS_CACHE_USED_SHARED ){
    ++            nByte = nByte / sqlite3BtreeConnectionCount(pBt);
    ++          }
    ++          totalUsed += nByte;
    +         }
    +       }
    +       sqlite3BtreeLeaveAll(db);
    +@@ -15992,10 +19467,10 @@ SQLITE_API int SQLITE_STDCALL sqlite3_db_status(
    +             + pSchema->idxHash.count
    +             + pSchema->fkeyHash.count
    +           );
    +-          nByte += sqlite3MallocSize(pSchema->tblHash.ht);
    +-          nByte += sqlite3MallocSize(pSchema->trigHash.ht);
    +-          nByte += sqlite3MallocSize(pSchema->idxHash.ht);
    +-          nByte += sqlite3MallocSize(pSchema->fkeyHash.ht);
    ++          nByte += sqlite3_msize(pSchema->tblHash.ht);
    ++          nByte += sqlite3_msize(pSchema->trigHash.ht);
    ++          nByte += sqlite3_msize(pSchema->idxHash.ht);
    ++          nByte += sqlite3_msize(pSchema->fkeyHash.ht);
    + 
    +           for(p=sqliteHashFirst(&pSchema->trigHash); p; p=sqliteHashNext(p)){
    +             sqlite3DeleteTrigger(db, (Trigger*)sqliteHashData(p));
    +@@ -16122,7 +19597,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_db_status(
    + **
    + **      Jean Meeus
    + **      Astronomical Algorithms, 2nd Edition, 1998
    +-**      ISBM 0-943396-61-1
    ++**      ISBN 0-943396-61-1
    + **      Willmann-Bell, Inc
    + **      Richmond, Virginia (USA)
    + */
    +@@ -16133,53 +19608,80 @@ SQLITE_API int SQLITE_STDCALL sqlite3_db_status(
    + 
    + #ifndef SQLITE_OMIT_DATETIME_FUNCS
    + 
    ++/*
    ++** The MSVC CRT on Windows CE may not have a localtime() function.
    ++** So declare a substitute.  The substitute function itself is
    ++** defined in "os_win.c".
    ++*/
    ++#if !defined(SQLITE_OMIT_LOCALTIME) && defined(_WIN32_WCE) && \
    ++    (!defined(SQLITE_MSVC_LOCALTIME_API) || !SQLITE_MSVC_LOCALTIME_API)
    ++struct tm *__cdecl localtime(const time_t *);
    ++#endif
    + 
    + /*
    + ** A structure for holding a single date and time.
    + */
    + typedef struct DateTime DateTime;
    + struct DateTime {
    +-  sqlite3_int64 iJD; /* The julian day number times 86400000 */
    +-  int Y, M, D;       /* Year, month, and day */
    +-  int h, m;          /* Hour and minutes */
    +-  int tz;            /* Timezone offset in minutes */
    +-  double s;          /* Seconds */
    +-  char validYMD;     /* True (1) if Y,M,D are valid */
    +-  char validHMS;     /* True (1) if h,m,s are valid */
    +-  char validJD;      /* True (1) if iJD is valid */
    +-  char validTZ;      /* True (1) if tz is valid */
    ++  sqlite3_int64 iJD;  /* The julian day number times 86400000 */
    ++  int Y, M, D;        /* Year, month, and day */
    ++  int h, m;           /* Hour and minutes */
    ++  int tz;             /* Timezone offset in minutes */
    ++  double s;           /* Seconds */
    ++  char validJD;       /* True (1) if iJD is valid */
    ++  char rawS;          /* Raw numeric value stored in s */
    ++  char validYMD;      /* True (1) if Y,M,D are valid */
    ++  char validHMS;      /* True (1) if h,m,s are valid */
    ++  char validTZ;       /* True (1) if tz is valid */
    ++  char tzSet;         /* Timezone was set explicitly */
    ++  char isError;       /* An overflow has occurred */
    + };
    + 
    + 
    + /*
    +-** Convert zDate into one or more integers.  Additional arguments
    +-** come in groups of 5 as follows:
    ++** Convert zDate into one or more integers according to the conversion
    ++** specifier zFormat.
    ++**
    ++** zFormat[] contains 4 characters for each integer converted, except for
    ++** the last integer which is specified by three characters.  The meaning
    ++** of a four-character format specifiers ABCD is:
    + **
    +-**       N       number of digits in the integer
    +-**       min     minimum allowed value of the integer
    +-**       max     maximum allowed value of the integer
    +-**       nextC   first character after the integer
    +-**       pVal    where to write the integers value.
    ++**    A:   number of digits to convert.  Always "2" or "4".
    ++**    B:   minimum value.  Always "0" or "1".
    ++**    C:   maximum value, decoded as:
    ++**           a:  12
    ++**           b:  14
    ++**           c:  24
    ++**           d:  31
    ++**           e:  59
    ++**           f:  9999
    ++**    D:   the separator character, or \000 to indicate this is the
    ++**         last number to convert.
    ++**
    ++** Example:  To translate an ISO-8601 date YYYY-MM-DD, the format would
    ++** be "40f-21a-20c".  The "40f-" indicates the 4-digit year followed by "-".
    ++** The "21a-" indicates the 2-digit month followed by "-".  The "20c" indicates
    ++** the 2-digit day which is the last integer in the set.
    + **
    +-** Conversions continue until one with nextC==0 is encountered.
    + ** The function returns the number of successful conversions.
    + */
    +-static int getDigits(const char *zDate, ...){
    ++static int getDigits(const char *zDate, const char *zFormat, ...){
    ++  /* The aMx[] array translates the 3rd character of each format
    ++  ** spec into a max size:    a   b   c   d   e     f */
    ++  static const u16 aMx[] = { 12, 14, 24, 31, 59, 9999 };
    +   va_list ap;
    +-  int val;
    +-  int N;
    +-  int min;
    +-  int max;
    +-  int nextC;
    +-  int *pVal;
    +   int cnt = 0;
    +-  va_start(ap, zDate);
    ++  char nextC;
    ++  va_start(ap, zFormat);
    +   do{
    +-    N = va_arg(ap, int);
    +-    min = va_arg(ap, int);
    +-    max = va_arg(ap, int);
    +-    nextC = va_arg(ap, int);
    +-    pVal = va_arg(ap, int*);
    ++    char N = zFormat[0] - '0';
    ++    char min = zFormat[1] - '0';
    ++    int val = 0;
    ++    u16 max;
    ++
    ++    assert( zFormat[2]>='a' && zFormat[2]<='f' );
    ++    max = aMx[zFormat[2] - 'a'];
    ++    nextC = zFormat[3];
    +     val = 0;
    +     while( N-- ){
    +       if( !sqlite3Isdigit(*zDate) ){
    +@@ -16188,12 +19690,13 @@ static int getDigits(const char *zDate, ...){
    +       val = val*10 + *zDate - '0';
    +       zDate++;
    +     }
    +-    if( val<min || val>max || (nextC!=0 && nextC!=*zDate) ){
    ++    if( val<(int)min || val>(int)max || (nextC!=0 && nextC!=*zDate) ){
    +       goto end_getDigits;
    +     }
    +-    *pVal = val;
    ++    *va_arg(ap,int*) = val;
    +     zDate++;
    +     cnt++;
    ++    zFormat += 4;
    +   }while( nextC );
    + end_getDigits:
    +   va_end(ap);
    +@@ -16234,13 +19737,14 @@ static int parseTimezone(const char *zDate, DateTime *p){
    +     return c!=0;
    +   }
    +   zDate++;
    +-  if( getDigits(zDate, 2, 0, 14, ':', &nHr, 2, 0, 59, 0, &nMn)!=2 ){
    ++  if( getDigits(zDate, "20b:20e", &nHr, &nMn)!=2 ){
    +     return 1;
    +   }
    +   zDate += 5;
    +   p->tz = sgn*(nMn + nHr*60);
    + zulu_time:
    +   while( sqlite3Isspace(*zDate) ){ zDate++; }
    ++  p->tzSet = 1;
    +   return *zDate!=0;
    + }
    + 
    +@@ -16254,13 +19758,13 @@ zulu_time:
    + static int parseHhMmSs(const char *zDate, DateTime *p){
    +   int h, m, s;
    +   double ms = 0.0;
    +-  if( getDigits(zDate, 2, 0, 24, ':', &h, 2, 0, 59, 0, &m)!=2 ){
    ++  if( getDigits(zDate, "20c:20e", &h, &m)!=2 ){
    +     return 1;
    +   }
    +   zDate += 5;
    +   if( *zDate==':' ){
    +     zDate++;
    +-    if( getDigits(zDate, 2, 0, 59, 0, &s)!=1 ){
    ++    if( getDigits(zDate, "20e", &s)!=1 ){
    +       return 1;
    +     }
    +     zDate += 2;
    +@@ -16278,6 +19782,7 @@ static int parseHhMmSs(const char *zDate, DateTime *p){
    +     s = 0;
    +   }
    +   p->validJD = 0;
    ++  p->rawS = 0;
    +   p->validHMS = 1;
    +   p->h = h;
    +   p->m = m;
    +@@ -16287,6 +19792,14 @@ static int parseHhMmSs(const char *zDate, DateTime *p){
    +   return 0;
    + }
    + 
    ++/*
    ++** Put the DateTime object into its error state.
    ++*/
    ++static void datetimeError(DateTime *p){
    ++  memset(p, 0, sizeof(*p));
    ++  p->isError = 1;
    ++}
    ++
    + /*
    + ** Convert from YYYY-MM-DD HH:MM:SS to julian day.  We always assume
    + ** that the YYYY-MM-DD is according to the Gregorian calendar.
    +@@ -16306,6 +19819,10 @@ static void computeJD(DateTime *p){
    +     M = 1;
    +     D = 1;
    +   }
    ++  if( Y<-4713 || Y>9999 || p->rawS ){
    ++    datetimeError(p);
    ++    return;
    ++  }
    +   if( M<=2 ){
    +     Y--;
    +     M += 12;
    +@@ -16348,7 +19865,7 @@ static int parseYyyyMmDd(const char *zDate, DateTime *p){
    +   }else{
    +     neg = 0;
    +   }
    +-  if( getDigits(zDate,4,0,9999,'-',&Y,2,1,12,'-',&M,2,1,31,0,&D)!=3 ){
    ++  if( getDigits(zDate, "40f-21a-21d", &Y, &M, &D)!=3 ){
    +     return 1;
    +   }
    +   zDate += 10;
    +@@ -16386,6 +19903,21 @@ static int setDateTimeToCurrent(sqlite3_context *context, DateTime *p){
    +   }
    + }
    + 
    ++/*
    ++** Input "r" is a numeric quantity which might be a julian day number,
    ++** or the number of seconds since 1970.  If the value if r is within
    ++** range of a julian day number, install it as such and set validJD.
    ++** If the value is a valid unix timestamp, put it in p->s and set p->rawS.
    ++*/
    ++static void setRawDateNumber(DateTime *p, double r){
    ++  p->s = r;
    ++  p->rawS = 1;
    ++  if( r>=0.0 && r<5373484.5 ){
    ++    p->iJD = (sqlite3_int64)(r*86400000.0 + 0.5);
    ++    p->validJD = 1;
    ++  }
    ++}
    ++
    + /*
    + ** Attempt to parse the given string into a julian day number.  Return
    + ** the number of errors.
    +@@ -16412,16 +19944,33 @@ static int parseDateOrTime(
    +     return 0;
    +   }else if( parseHhMmSs(zDate, p)==0 ){
    +     return 0;
    +-  }else if( sqlite3StrICmp(zDate,"now")==0){
    ++  }else if( sqlite3StrICmp(zDate,"now")==0 && sqlite3NotPureFunc(context) ){
    +     return setDateTimeToCurrent(context, p);
    +   }else if( sqlite3AtoF(zDate, &r, sqlite3Strlen30(zDate), SQLITE_UTF8) ){
    +-    p->iJD = (sqlite3_int64)(r*86400000.0 + 0.5);
    +-    p->validJD = 1;
    ++    setRawDateNumber(p, r);
    +     return 0;
    +   }
    +   return 1;
    + }
    + 
    ++/* The julian day number for 9999-12-31 23:59:59.999 is 5373484.4999999.
    ++** Multiplying this by 86400000 gives 464269060799999 as the maximum value
    ++** for DateTime.iJD.
    ++**
    ++** But some older compilers (ex: gcc 4.2.1 on older Macs) cannot deal with 
    ++** such a large integer literal, so we have to encode it.
    ++*/
    ++#define INT_464269060799999  ((((i64)0x1a640)<<32)|0x1072fdff)
    ++
    ++/*
    ++** Return TRUE if the given julian day number is within range.
    ++**
    ++** The input is the JulianDay times 86400000.
    ++*/
    ++static int validJulianDay(sqlite3_int64 iJD){
    ++  return iJD>=0 && iJD<=INT_464269060799999;
    ++}
    ++
    + /*
    + ** Compute the Year, Month, and Day from the julian day number.
    + */
    +@@ -16432,6 +19981,9 @@ static void computeYMD(DateTime *p){
    +     p->Y = 2000;
    +     p->M = 1;
    +     p->D = 1;
    ++  }else if( !validJulianDay(p->iJD) ){
    ++    datetimeError(p);
    ++    return;
    +   }else{
    +     Z = (int)((p->iJD + 43200000)/86400000);
    +     A = (int)((Z - 1867216.25)/36524.25);
    +@@ -16463,6 +20015,7 @@ static void computeHMS(DateTime *p){
    +   s -= p->h*3600;
    +   p->m = s/60;
    +   p->s += s - p->m*60;
    ++  p->rawS = 0;
    +   p->validHMS = 1;
    + }
    + 
    +@@ -16483,6 +20036,7 @@ static void clearYMD_HMS_TZ(DateTime *p){
    +   p->validTZ = 0;
    + }
    + 
    ++#ifndef SQLITE_OMIT_LOCALTIME
    + /*
    + ** On recent Windows platforms, the localtime_s() function is available
    + ** as part of the "Secure CRT". It is essentially equivalent to 
    +@@ -16501,7 +20055,6 @@ static void clearYMD_HMS_TZ(DateTime *p){
    + #define HAVE_LOCALTIME_S 1
    + #endif
    + 
    +-#ifndef SQLITE_OMIT_LOCALTIME
    + /*
    + ** The following routine implements the rough equivalent of localtime_r()
    + ** using whatever operating-system specific localtime facility that
    +@@ -16524,14 +20077,14 @@ static int osLocaltime(time_t *t, struct tm *pTm){
    + #endif
    +   sqlite3_mutex_enter(mutex);
    +   pX = localtime(t);
    +-#ifndef SQLITE_OMIT_BUILTIN_TEST
    ++#ifndef SQLITE_UNTESTABLE
    +   if( sqlite3GlobalConfig.bLocaltimeFault ) pX = 0;
    + #endif
    +   if( pX ) *pTm = *pX;
    +   sqlite3_mutex_leave(mutex);
    +   rc = pX==0;
    + #else
    +-#ifndef SQLITE_OMIT_BUILTIN_TEST
    ++#ifndef SQLITE_UNTESTABLE
    +   if( sqlite3GlobalConfig.bLocaltimeFault ) return 1;
    + #endif
    + #if HAVE_LOCALTIME_R
    +@@ -16602,13 +20155,38 @@ static sqlite3_int64 localtimeOffset(
    +   y.validYMD = 1;
    +   y.validHMS = 1;
    +   y.validJD = 0;
    ++  y.rawS = 0;
    +   y.validTZ = 0;
    ++  y.isError = 0;
    +   computeJD(&y);
    +   *pRc = SQLITE_OK;
    +   return y.iJD - x.iJD;
    + }
    + #endif /* SQLITE_OMIT_LOCALTIME */
    + 
    ++/*
    ++** The following table defines various date transformations of the form
    ++**
    ++**            'NNN days'
    ++**
    ++** Where NNN is an arbitrary floating-point number and "days" can be one
    ++** of several units of time.
    ++*/
    ++static const struct {
    ++  u8 eType;           /* Transformation type code */
    ++  u8 nName;           /* Length of th name */
    ++  char *zName;        /* Name of the transformation */
    ++  double rLimit;      /* Maximum NNN value for this transform */
    ++  double rXform;      /* Constant used for this transform */
    ++} aXformType[] = {
    ++  { 0, 6, "second", 464269060800.0, 86400000.0/(24.0*60.0*60.0) },
    ++  { 0, 6, "minute", 7737817680.0,   86400000.0/(24.0*60.0)      },
    ++  { 0, 4, "hour",   128963628.0,    86400000.0/24.0             },
    ++  { 0, 3, "day",    5373485.0,      86400000.0                  },
    ++  { 1, 5, "month",  176546.0,       30.0*86400000.0             },
    ++  { 2, 4, "year",   14713.0,        365.0*86400000.0            },
    ++};
    ++
    + /*
    + ** Process a modifier to a date-time stamp.  The modifiers are
    + ** as follows:
    +@@ -16633,17 +20211,15 @@ static sqlite3_int64 localtimeOffset(
    + ** to context pCtx. If the error is an unrecognized modifier, no error is
    + ** written to pCtx.
    + */
    +-static int parseModifier(sqlite3_context *pCtx, const char *zMod, DateTime *p){
    ++static int parseModifier(
    ++  sqlite3_context *pCtx,      /* Function context */
    ++  const char *z,              /* The text of the modifier */
    ++  int n,                      /* Length of zMod in bytes */
    ++  DateTime *p                 /* The date/time value to be modified */
    ++){
    +   int rc = 1;
    +-  int n;
    +   double r;
    +-  char *z, zBuf[30];
    +-  z = zBuf;
    +-  for(n=0; n<ArraySize(zBuf)-1 && zMod[n]; n++){
    +-    z[n] = (char)sqlite3UpperToLower[(u8)zMod[n]];
    +-  }
    +-  z[n] = 0;
    +-  switch( z[0] ){
    ++  switch(sqlite3UpperToLower[(u8)z[0]] ){
    + #ifndef SQLITE_OMIT_LOCALTIME
    +     case 'l': {
    +       /*    localtime
    +@@ -16651,7 +20227,7 @@ static int parseModifier(sqlite3_context *pCtx, const char *zMod, DateTime *p){
    +       ** Assuming the current time value is UTC (a.k.a. GMT), shift it to
    +       ** show local time.
    +       */
    +-      if( strcmp(z, "localtime")==0 ){
    ++      if( sqlite3_stricmp(z, "localtime")==0 && sqlite3NotPureFunc(pCtx) ){
    +         computeJD(p);
    +         p->iJD += localtimeOffset(p, pCtx, &rc);
    +         clearYMD_HMS_TZ(p);
    +@@ -16663,23 +20239,33 @@ static int parseModifier(sqlite3_context *pCtx, const char *zMod, DateTime *p){
    +       /*
    +       **    unixepoch
    +       **
    +-      ** Treat the current value of p->iJD as the number of
    ++      ** Treat the current value of p->s as the number of
    +       ** seconds since 1970.  Convert to a real julian day number.
    +       */
    +-      if( strcmp(z, "unixepoch")==0 && p->validJD ){
    +-        p->iJD = (p->iJD + 43200)/86400 + 21086676*(i64)10000000;
    +-        clearYMD_HMS_TZ(p);
    +-        rc = 0;
    ++      if( sqlite3_stricmp(z, "unixepoch")==0 && p->rawS ){
    ++        r = p->s*1000.0 + 210866760000000.0;
    ++        if( r>=0.0 && r<464269060800000.0 ){
    ++          clearYMD_HMS_TZ(p);
    ++          p->iJD = (sqlite3_int64)r;
    ++          p->validJD = 1;
    ++          p->rawS = 0;
    ++          rc = 0;
    ++        }
    +       }
    + #ifndef SQLITE_OMIT_LOCALTIME
    +-      else if( strcmp(z, "utc")==0 ){
    +-        sqlite3_int64 c1;
    +-        computeJD(p);
    +-        c1 = localtimeOffset(p, pCtx, &rc);
    +-        if( rc==SQLITE_OK ){
    +-          p->iJD -= c1;
    +-          clearYMD_HMS_TZ(p);
    +-          p->iJD += c1 - localtimeOffset(p, pCtx, &rc);
    ++      else if( sqlite3_stricmp(z, "utc")==0 && sqlite3NotPureFunc(pCtx) ){
    ++        if( p->tzSet==0 ){
    ++          sqlite3_int64 c1;
    ++          computeJD(p);
    ++          c1 = localtimeOffset(p, pCtx, &rc);
    ++          if( rc==SQLITE_OK ){
    ++            p->iJD -= c1;
    ++            clearYMD_HMS_TZ(p);
    ++            p->iJD += c1 - localtimeOffset(p, pCtx, &rc);
    ++          }
    ++          p->tzSet = 1;
    ++        }else{
    ++          rc = SQLITE_OK;
    +         }
    +       }
    + #endif
    +@@ -16693,7 +20279,7 @@ static int parseModifier(sqlite3_context *pCtx, const char *zMod, DateTime *p){
    +       ** weekday N where 0==Sunday, 1==Monday, and so forth.  If the
    +       ** date is already on the appropriate weekday, this is a no-op.
    +       */
    +-      if( strncmp(z, "weekday ", 8)==0
    ++      if( sqlite3_strnicmp(z, "weekday ", 8)==0
    +                && sqlite3AtoF(&z[8], &r, sqlite3Strlen30(&z[8]), SQLITE_UTF8)
    +                && (n=(int)r)==r && n>=0 && r<7 ){
    +         sqlite3_int64 Z;
    +@@ -16716,23 +20302,24 @@ static int parseModifier(sqlite3_context *pCtx, const char *zMod, DateTime *p){
    +       ** Move the date backwards to the beginning of the current day,
    +       ** or month or year.
    +       */
    +-      if( strncmp(z, "start of ", 9)!=0 ) break;
    ++      if( sqlite3_strnicmp(z, "start of ", 9)!=0 ) break;
    ++      if( !p->validJD && !p->validYMD && !p->validHMS ) break;
    +       z += 9;
    +       computeYMD(p);
    +       p->validHMS = 1;
    +       p->h = p->m = 0;
    +       p->s = 0.0;
    ++      p->rawS = 0;
    +       p->validTZ = 0;
    +       p->validJD = 0;
    +-      if( strcmp(z,"month")==0 ){
    ++      if( sqlite3_stricmp(z,"month")==0 ){
    +         p->D = 1;
    +         rc = 0;
    +-      }else if( strcmp(z,"year")==0 ){
    +-        computeYMD(p);
    ++      }else if( sqlite3_stricmp(z,"year")==0 ){
    +         p->M = 1;
    +         p->D = 1;
    +         rc = 0;
    +-      }else if( strcmp(z,"day")==0 ){
    ++      }else if( sqlite3_stricmp(z,"day")==0 ){
    +         rc = 0;
    +       }
    +       break;
    +@@ -16750,6 +20337,7 @@ static int parseModifier(sqlite3_context *pCtx, const char *zMod, DateTime *p){
    +     case '8':
    +     case '9': {
    +       double rRounder;
    ++      int i;
    +       for(n=1; z[n] && z[n]!=':' && !sqlite3Isspace(z[n]); n++){}
    +       if( !sqlite3AtoF(z, &r, n, SQLITE_UTF8) ){
    +         rc = 1;
    +@@ -16778,46 +20366,48 @@ static int parseModifier(sqlite3_context *pCtx, const char *zMod, DateTime *p){
    +         rc = 0;
    +         break;
    +       }
    ++
    ++      /* If control reaches this point, it means the transformation is
    ++      ** one of the forms like "+NNN days".  */
    +       z += n;
    +       while( sqlite3Isspace(*z) ) z++;
    +       n = sqlite3Strlen30(z);
    +       if( n>10 || n<3 ) break;
    +-      if( z[n-1]=='s' ){ z[n-1] = 0; n--; }
    ++      if( sqlite3UpperToLower[(u8)z[n-1]]=='s' ) n--;
    +       computeJD(p);
    +-      rc = 0;
    ++      rc = 1;
    +       rRounder = r<0 ? -0.5 : +0.5;
    +-      if( n==3 && strcmp(z,"day")==0 ){
    +-        p->iJD += (sqlite3_int64)(r*86400000.0 + rRounder);
    +-      }else if( n==4 && strcmp(z,"hour")==0 ){
    +-        p->iJD += (sqlite3_int64)(r*(86400000.0/24.0) + rRounder);
    +-      }else if( n==6 && strcmp(z,"minute")==0 ){
    +-        p->iJD += (sqlite3_int64)(r*(86400000.0/(24.0*60.0)) + rRounder);
    +-      }else if( n==6 && strcmp(z,"second")==0 ){
    +-        p->iJD += (sqlite3_int64)(r*(86400000.0/(24.0*60.0*60.0)) + rRounder);
    +-      }else if( n==5 && strcmp(z,"month")==0 ){
    +-        int x, y;
    +-        computeYMD_HMS(p);
    +-        p->M += (int)r;
    +-        x = p->M>0 ? (p->M-1)/12 : (p->M-12)/12;
    +-        p->Y += x;
    +-        p->M -= x*12;
    +-        p->validJD = 0;
    +-        computeJD(p);
    +-        y = (int)r;
    +-        if( y!=r ){
    +-          p->iJD += (sqlite3_int64)((r - y)*30.0*86400000.0 + rRounder);
    +-        }
    +-      }else if( n==4 && strcmp(z,"year")==0 ){
    +-        int y = (int)r;
    +-        computeYMD_HMS(p);
    +-        p->Y += y;
    +-        p->validJD = 0;
    +-        computeJD(p);
    +-        if( y!=r ){
    +-          p->iJD += (sqlite3_int64)((r - y)*365.0*86400000.0 + rRounder);
    ++      for(i=0; i<ArraySize(aXformType); i++){
    ++        if( aXformType[i].nName==n
    ++         && sqlite3_strnicmp(aXformType[i].zName, z, n)==0
    ++         && r>-aXformType[i].rLimit && r<aXformType[i].rLimit
    ++        ){
    ++          switch( aXformType[i].eType ){
    ++            case 1: { /* Special processing to add months */
    ++              int x;
    ++              computeYMD_HMS(p);
    ++              p->M += (int)r;
    ++              x = p->M>0 ? (p->M-1)/12 : (p->M-12)/12;
    ++              p->Y += x;
    ++              p->M -= x*12;
    ++              p->validJD = 0;
    ++              r -= (int)r;
    ++              break;
    ++            }
    ++            case 2: { /* Special processing to add years */
    ++              int y = (int)r;
    ++              computeYMD_HMS(p);
    ++              p->Y += y;
    ++              p->validJD = 0;
    ++              r -= (int)r;
    ++              break;
    ++            }
    ++          }
    ++          computeJD(p);
    ++          p->iJD += (sqlite3_int64)(r*aXformType[i].rXform + rRounder);
    ++          rc = 0;
    ++          break;
    +         }
    +-      }else{
    +-        rc = 1;
    +       }
    +       clearYMD_HMS_TZ(p);
    +       break;
    +@@ -16844,7 +20434,7 @@ static int isDate(
    +   sqlite3_value **argv, 
    +   DateTime *p
    + ){
    +-  int i;
    ++  int i, n;
    +   const unsigned char *z;
    +   int eType;
    +   memset(p, 0, sizeof(*p));
    +@@ -16853,8 +20443,7 @@ static int isDate(
    +   }
    +   if( (eType = sqlite3_value_type(argv[0]))==SQLITE_FLOAT
    +                    || eType==SQLITE_INTEGER ){
    +-    p->iJD = (sqlite3_int64)(sqlite3_value_double(argv[0])*86400000.0 + 0.5);
    +-    p->validJD = 1;
    ++    setRawDateNumber(p, sqlite3_value_double(argv[0]));
    +   }else{
    +     z = sqlite3_value_text(argv[0]);
    +     if( !z || parseDateOrTime(context, (char*)z, p) ){
    +@@ -16863,8 +20452,11 @@ static int isDate(
    +   }
    +   for(i=1; i<argc; i++){
    +     z = sqlite3_value_text(argv[i]);
    +-    if( z==0 || parseModifier(context, (char*)z, p) ) return 1;
    ++    n = sqlite3_value_bytes(argv[i]);
    ++    if( z==0 || parseModifier(context, (char*)z, n, p) ) return 1;
    +   }
    ++  computeJD(p);
    ++  if( p->isError || !validJulianDay(p->iJD) ) return 1;
    +   return 0;
    + }
    + 
    +@@ -17027,7 +20619,7 @@ static void strftimeFunc(
    +     sqlite3_result_error_toobig(context);
    +     return;
    +   }else{
    +-    z = sqlite3DbMallocRaw(db, (int)n);
    ++    z = sqlite3DbMallocRawNN(db, (int)n);
    +     if( z==0 ){
    +       sqlite3_result_error_nomem(context);
    +       return;
    +@@ -17163,7 +20755,6 @@ static void currentTimeFunc(
    + ){
    +   time_t t;
    +   char *zFormat = (char *)sqlite3_user_data(context);
    +-  sqlite3 *db;
    +   sqlite3_int64 iT;
    +   struct tm *pTm;
    +   struct tm sNow;
    +@@ -17196,13 +20787,13 @@ static void currentTimeFunc(
    + ** external linkage.
    + */
    + SQLITE_PRIVATE void sqlite3RegisterDateTimeFunctions(void){
    +-  static SQLITE_WSD FuncDef aDateTimeFuncs[] = {
    ++  static FuncDef aDateTimeFuncs[] = {
    + #ifndef SQLITE_OMIT_DATETIME_FUNCS
    +-    DFUNCTION(julianday,        -1, 0, 0, juliandayFunc ),
    +-    DFUNCTION(date,             -1, 0, 0, dateFunc      ),
    +-    DFUNCTION(time,             -1, 0, 0, timeFunc      ),
    +-    DFUNCTION(datetime,         -1, 0, 0, datetimeFunc  ),
    +-    DFUNCTION(strftime,         -1, 0, 0, strftimeFunc  ),
    ++    PURE_DATE(julianday,        -1, 0, 0, juliandayFunc ),
    ++    PURE_DATE(date,             -1, 0, 0, dateFunc      ),
    ++    PURE_DATE(time,             -1, 0, 0, timeFunc      ),
    ++    PURE_DATE(datetime,         -1, 0, 0, datetimeFunc  ),
    ++    PURE_DATE(strftime,         -1, 0, 0, strftimeFunc  ),
    +     DFUNCTION(current_time,      0, 0, 0, ctimeFunc     ),
    +     DFUNCTION(current_timestamp, 0, 0, 0, ctimestampFunc),
    +     DFUNCTION(current_date,      0, 0, 0, cdateFunc     ),
    +@@ -17212,13 +20803,7 @@ SQLITE_PRIVATE void sqlite3RegisterDateTimeFunctions(void){
    +     STR_FUNCTION(current_timestamp, 0, "%Y-%m-%d %H:%M:%S", 0, currentTimeFunc),
    + #endif
    +   };
    +-  int i;
    +-  FuncDefHash *pHash = &GLOBAL(FuncDefHash, sqlite3GlobalFunctions);
    +-  FuncDef *aFunc = (FuncDef*)&GLOBAL(FuncDef, aDateTimeFuncs);
    +-
    +-  for(i=0; i<ArraySize(aDateTimeFuncs); i++){
    +-    sqlite3FuncDefInsert(pHash, &aFunc[i]);
    +-  }
    ++  sqlite3InsertBuiltinFuncs(aDateTimeFuncs, ArraySize(aDateTimeFuncs));
    + }
    + 
    + /************** End of date.c ************************************************/
    +@@ -17238,9 +20823,29 @@ SQLITE_PRIVATE void sqlite3RegisterDateTimeFunctions(void){
    + ** This file contains OS interface code that is common to all
    + ** architectures.
    + */
    +-#define _SQLITE_OS_C_ 1
    + /* #include "sqliteInt.h" */
    +-#undef _SQLITE_OS_C_
    ++
    ++/*
    ++** 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.
    ++*/
    ++#if defined(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;
    ++#endif /* defined(SQLITE_TEST) */
    ++
    ++/*
    ++** When testing, also keep a count of the number of open files.
    ++*/
    ++#if defined(SQLITE_TEST)
    ++SQLITE_API int sqlite3_open_file_count = 0;
    ++#endif /* defined(SQLITE_TEST) */
    + 
    + /*
    + ** The default SQLite sqlite3_vfs implementations do not allocate
    +@@ -17249,7 +20854,7 @@ SQLITE_PRIVATE void sqlite3RegisterDateTimeFunctions(void){
    + ** So we test the effects of a malloc() failing and the sqlite3OsXXX()
    + ** function returning SQLITE_IOERR_NOMEM using the DO_OS_MALLOC_TEST macro.
    + **
    +-** The following functions are instrumented for malloc() failure 
    ++** The following functions are instrumented for malloc() failure
    + ** testing:
    + **
    + **     sqlite3OsRead()
    +@@ -17269,9 +20874,9 @@ SQLITE_PRIVATE void sqlite3RegisterDateTimeFunctions(void){
    + #if defined(SQLITE_TEST)
    + SQLITE_API int sqlite3_memdebug_vfs_oom_test = 1;
    +   #define DO_OS_MALLOC_TEST(x)                                       \
    +-  if (sqlite3_memdebug_vfs_oom_test && (!x || !sqlite3IsMemJournal(x))) {  \
    ++  if (sqlite3_memdebug_vfs_oom_test && (!x || !sqlite3JournalIsInMemory(x))) { \
    +     void *pTstAlloc = sqlite3Malloc(10);                             \
    +-    if (!pTstAlloc) return SQLITE_IOERR_NOMEM;                       \
    ++    if (!pTstAlloc) return SQLITE_IOERR_NOMEM_BKPT;                  \
    +     sqlite3_free(pTstAlloc);                                         \
    +   }
    + #else
    +@@ -17284,13 +20889,11 @@ SQLITE_API int sqlite3_memdebug_vfs_oom_test = 1;
    + ** of this would be completely automatic if SQLite were coded using
    + ** C++ instead of plain old C.
    + */
    +-SQLITE_PRIVATE int sqlite3OsClose(sqlite3_file *pId){
    +-  int rc = SQLITE_OK;
    ++SQLITE_PRIVATE void sqlite3OsClose(sqlite3_file *pId){
    +   if( pId->pMethods ){
    +-    rc = pId->pMethods->xClose(pId);
    ++    pId->pMethods->xClose(pId);
    +     pId->pMethods = 0;
    +   }
    +-  return rc;
    + }
    + SQLITE_PRIVATE int sqlite3OsRead(sqlite3_file *id, void *pBuf, int amt, i64 offset){
    +   DO_OS_MALLOC_TEST(id);
    +@@ -17305,7 +20908,7 @@ SQLITE_PRIVATE int sqlite3OsTruncate(sqlite3_file *id, i64 size){
    + }
    + SQLITE_PRIVATE int sqlite3OsSync(sqlite3_file *id, int flags){
    +   DO_OS_MALLOC_TEST(id);
    +-  return id->pMethods->xSync(id, flags);
    ++  return flags ? id->pMethods->xSync(id, flags) : SQLITE_OK;
    + }
    + SQLITE_PRIVATE int sqlite3OsFileSize(sqlite3_file *id, i64 *pSize){
    +   DO_OS_MALLOC_TEST(id);
    +@@ -17335,8 +20938,8 @@ SQLITE_PRIVATE int sqlite3OsFileControl(sqlite3_file *id, int op, void *pArg){
    + #ifdef SQLITE_TEST
    +   if( op!=SQLITE_FCNTL_COMMIT_PHASETWO ){
    +     /* Faults are not injected into COMMIT_PHASETWO because, assuming SQLite
    +-    ** is using a regular VFS, it is called after the corresponding 
    +-    ** transaction has been committed. Injecting a fault at this point 
    ++    ** is using a regular VFS, it is called after the corresponding
    ++    ** transaction has been committed. Injecting a fault at this point
    +     ** confuses the test scripts - the COMMIT comand returns SQLITE_NOMEM
    +     ** but the transaction is committed anyway.
    +     **
    +@@ -17360,6 +20963,7 @@ SQLITE_PRIVATE int sqlite3OsSectorSize(sqlite3_file *id){
    + SQLITE_PRIVATE int sqlite3OsDeviceCharacteristics(sqlite3_file *id){
    +   return id->pMethods->xDeviceCharacteristics(id);
    + }
    ++#ifndef SQLITE_OMIT_WAL
    + SQLITE_PRIVATE int sqlite3OsShmLock(sqlite3_file *id, int offset, int n, int flags){
    +   return id->pMethods->xShmLock(id, offset, n, flags);
    + }
    +@@ -17379,6 +20983,7 @@ SQLITE_PRIVATE int sqlite3OsShmMap(
    +   DO_OS_MALLOC_TEST(id);
    +   return id->pMethods->xShmMap(id, iPage, pgsz, bExtend, pp);
    + }
    ++#endif /* SQLITE_OMIT_WAL */
    + 
    + #if SQLITE_MAX_MMAP_SIZE>0
    + /* The real implementation of xFetch and xUnfetch */
    +@@ -17405,10 +21010,10 @@ SQLITE_PRIVATE int sqlite3OsUnfetch(sqlite3_file *id, i64 iOff, void *p){
    + ** VFS methods.
    + */
    + SQLITE_PRIVATE int sqlite3OsOpen(
    +-  sqlite3_vfs *pVfs, 
    +-  const char *zPath, 
    +-  sqlite3_file *pFile, 
    +-  int flags, 
    ++  sqlite3_vfs *pVfs,
    ++  const char *zPath,
    ++  sqlite3_file *pFile,
    ++  int flags,
    +   int *pFlagsOut
    + ){
    +   int rc;
    +@@ -17427,18 +21032,18 @@ SQLITE_PRIVATE int sqlite3OsDelete(sqlite3_vfs *pVfs, const char *zPath, int dir
    +   return pVfs->xDelete(pVfs, zPath, dirSync);
    + }
    + SQLITE_PRIVATE int sqlite3OsAccess(
    +-  sqlite3_vfs *pVfs, 
    +-  const char *zPath, 
    +-  int flags, 
    ++  sqlite3_vfs *pVfs,
    ++  const char *zPath,
    ++  int flags,
    +   int *pResOut
    + ){
    +   DO_OS_MALLOC_TEST(0);
    +   return pVfs->xAccess(pVfs, zPath, flags, pResOut);
    + }
    + SQLITE_PRIVATE int sqlite3OsFullPathname(
    +-  sqlite3_vfs *pVfs, 
    +-  const char *zPath, 
    +-  int nPathOut, 
    ++  sqlite3_vfs *pVfs,
    ++  const char *zPath,
    ++  int nPathOut,
    +   char *zPathOut
    + ){
    +   DO_OS_MALLOC_TEST(0);
    +@@ -17465,6 +21070,9 @@ SQLITE_PRIVATE int sqlite3OsRandomness(sqlite3_vfs *pVfs, int nByte, char *zBufO
    + SQLITE_PRIVATE int sqlite3OsSleep(sqlite3_vfs *pVfs, int nMicro){
    +   return pVfs->xSleep(pVfs, nMicro);
    + }
    ++SQLITE_PRIVATE int sqlite3OsGetLastError(sqlite3_vfs *pVfs){
    ++  return pVfs->xGetLastError ? pVfs->xGetLastError(pVfs, 0, 0) : 0;
    ++}
    + SQLITE_PRIVATE int sqlite3OsCurrentTimeInt64(sqlite3_vfs *pVfs, sqlite3_int64 *pTimeOut){
    +   int rc;
    +   /* IMPLEMENTATION-OF: R-49045-42493 SQLite will use the xCurrentTimeInt64()
    +@@ -17484,13 +21092,13 @@ SQLITE_PRIVATE int sqlite3OsCurrentTimeInt64(sqlite3_vfs *pVfs, sqlite3_int64 *p
    + }
    + 
    + SQLITE_PRIVATE int sqlite3OsOpenMalloc(
    +-  sqlite3_vfs *pVfs, 
    +-  const char *zFile, 
    +-  sqlite3_file **ppFile, 
    ++  sqlite3_vfs *pVfs,
    ++  const char *zFile,
    ++  sqlite3_file **ppFile,
    +   int flags,
    +   int *pOutFlags
    + ){
    +-  int rc = SQLITE_NOMEM;
    ++  int rc;
    +   sqlite3_file *pFile;
    +   pFile = (sqlite3_file *)sqlite3MallocZero(pVfs->szOsFile);
    +   if( pFile ){
    +@@ -17500,15 +21108,15 @@ SQLITE_PRIVATE int sqlite3OsOpenMalloc(
    +     }else{
    +       *ppFile = pFile;
    +     }
    ++  }else{
    ++    rc = SQLITE_NOMEM_BKPT;
    +   }
    +   return rc;
    + }
    +-SQLITE_PRIVATE int sqlite3OsCloseFree(sqlite3_file *pFile){
    +-  int rc = SQLITE_OK;
    ++SQLITE_PRIVATE void sqlite3OsCloseFree(sqlite3_file *pFile){
    +   assert( pFile );
    +-  rc = sqlite3OsClose(pFile);
    ++  sqlite3OsClose(pFile);
    +   sqlite3_free(pFile);
    +-  return rc;
    + }
    + 
    + /*
    +@@ -17519,7 +21127,7 @@ SQLITE_PRIVATE int sqlite3OsCloseFree(sqlite3_file *pFile){
    + */
    + SQLITE_PRIVATE int sqlite3OsInit(void){
    +   void *p = sqlite3_malloc(10);
    +-  if( p==0 ) return SQLITE_NOMEM;
    ++  if( p==0 ) return SQLITE_NOMEM_BKPT;
    +   sqlite3_free(p);
    +   return sqlite3_os_init();
    + }
    +@@ -17534,7 +21142,7 @@ static sqlite3_vfs * SQLITE_WSD vfsList = 0;
    + ** Locate a VFS by name.  If no name is given, simply return the
    + ** first VFS on the list.
    + */
    +-SQLITE_API sqlite3_vfs *SQLITE_STDCALL sqlite3_vfs_find(const char *zVfs){
    ++SQLITE_API sqlite3_vfs *sqlite3_vfs_find(const char *zVfs){
    +   sqlite3_vfs *pVfs = 0;
    + #if SQLITE_THREADSAFE
    +   sqlite3_mutex *mutex;
    +@@ -17580,7 +21188,7 @@ static void vfsUnlink(sqlite3_vfs *pVfs){
    + ** VFS multiple times.  The new VFS becomes the default if makeDflt is
    + ** true.
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_vfs_register(sqlite3_vfs *pVfs, int makeDflt){
    ++SQLITE_API int sqlite3_vfs_register(sqlite3_vfs *pVfs, int makeDflt){
    +   MUTEX_LOGIC(sqlite3_mutex *mutex;)
    + #ifndef SQLITE_OMIT_AUTOINIT
    +   int rc = sqlite3_initialize();
    +@@ -17608,7 +21216,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_vfs_register(sqlite3_vfs *pVfs, int makeDf
    + /*
    + ** Unregister a VFS so that it is no longer accessible.
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_vfs_unregister(sqlite3_vfs *pVfs){
    ++SQLITE_API int sqlite3_vfs_unregister(sqlite3_vfs *pVfs){
    + #if SQLITE_THREADSAFE
    +   sqlite3_mutex *mutex = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MASTER);
    + #endif
    +@@ -17648,7 +21256,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_vfs_unregister(sqlite3_vfs *pVfs){
    + 
    + /* #include "sqliteInt.h" */
    + 
    +-#ifndef SQLITE_OMIT_BUILTIN_TEST
    ++#ifndef SQLITE_UNTESTABLE
    + 
    + /*
    + ** Global variables.
    +@@ -17706,7 +21314,7 @@ SQLITE_PRIVATE void sqlite3EndBenignMalloc(void){
    +   }
    + }
    + 
    +-#endif   /* #ifndef SQLITE_OMIT_BUILTIN_TEST */
    ++#endif   /* #ifndef SQLITE_UNTESTABLE */
    + 
    + /************** End of fault.c ***********************************************/
    + /************** Begin file mem0.c ********************************************/
    +@@ -17831,7 +21439,9 @@ SQLITE_PRIVATE void sqlite3MemSetDefault(void){
    + */
    + #include <sys/sysctl.h>
    + #include <malloc/malloc.h>
    ++#ifdef SQLITE_MIGHT_BE_SINGLE_CORE
    + #include <libkern/OSAtomic.h>
    ++#endif /* SQLITE_MIGHT_BE_SINGLE_CORE */
    + static malloc_zone_t* _sqliteZone_;
    + #define SQLITE_MALLOC(x) malloc_zone_malloc(_sqliteZone_, (x))
    + #define SQLITE_FREE(x) malloc_zone_free(_sqliteZone_, (x));
    +@@ -17899,7 +21509,9 @@ static malloc_zone_t* _sqliteZone_;
    + */
    + static void *sqlite3MemMalloc(int nByte){
    + #ifdef SQLITE_MALLOCSIZE
    +-  void *p = SQLITE_MALLOC( nByte );
    ++  void *p;
    ++  testcase( ROUND8(nByte)==nByte );
    ++  p = SQLITE_MALLOC( nByte );
    +   if( p==0 ){
    +     testcase( sqlite3GlobalConfig.xLog!=0 );
    +     sqlite3_log(SQLITE_NOMEM, "failed to allocate %u bytes of memory", nByte);
    +@@ -17908,7 +21520,7 @@ static void *sqlite3MemMalloc(int nByte){
    + #else
    +   sqlite3_int64 *p;
    +   assert( nByte>0 );
    +-  nByte = ROUND8(nByte);
    ++  testcase( ROUND8(nByte)!=nByte );
    +   p = SQLITE_MALLOC( nByte+8 );
    +   if( p ){
    +     p[0] = nByte;
    +@@ -17946,10 +21558,11 @@ static void sqlite3MemFree(void *pPrior){
    + */
    + static int sqlite3MemSize(void *pPrior){
    + #ifdef SQLITE_MALLOCSIZE
    +-  return pPrior ? (int)SQLITE_MALLOCSIZE(pPrior) : 0;
    ++  assert( pPrior!=0 );
    ++  return (int)SQLITE_MALLOCSIZE(pPrior);
    + #else
    +   sqlite3_int64 *p;
    +-  if( pPrior==0 ) return 0;
    ++  assert( pPrior!=0 );
    +   p = (sqlite3_int64*)pPrior;
    +   p--;
    +   return (int)p[0];
    +@@ -18021,19 +21634,10 @@ static int sqlite3MemInit(void *NotUsed){
    +   }else{
    +     /* only 1 core, use our own zone to contention over global locks, 
    +     ** e.g. we have our own dedicated locks */
    +-    bool success;
    +-    malloc_zone_t* newzone = malloc_create_zone(4096, 0);
    +-    malloc_set_zone_name(newzone, "Sqlite_Heap");
    +-    do{
    +-      success = OSAtomicCompareAndSwapPtrBarrier(NULL, newzone, 
    +-                                 (void * volatile *)&_sqliteZone_);
    +-    }while(!_sqliteZone_);
    +-    if( !success ){
    +-      /* somebody registered a zone first */
    +-      malloc_destroy_zone(newzone);
    +-    }
    ++    _sqliteZone_ = malloc_create_zone(4096, 0);
    ++    malloc_set_zone_name(_sqliteZone_, "Sqlite_Heap");
    +   }
    +-#endif
    ++#endif /*  defined(__APPLE__) && !defined(SQLITE_WITHOUT_ZONEMALLOC) */
    +   UNUSED_PARAMETER(NotUsed);
    +   return SQLITE_OK;
    + }
    +@@ -19079,7 +22683,7 @@ static void memsys3FreeUnsafe(void *pOld){
    + */
    + static int memsys3Size(void *p){
    +   Mem3Block *pBlock;
    +-  if( p==0 ) return 0;
    ++  assert( p!=0 );
    +   pBlock = (Mem3Block*)p;
    +   assert( (pBlock[-1].u.hdr.size4x&1)!=0 );
    +   return (pBlock[-1].u.hdr.size4x&~3)*2 - 4;
    +@@ -19318,7 +22922,7 @@ SQLITE_PRIVATE const sqlite3_mem_methods *sqlite3MemGetMemsys3(void){
    + **
    + ** This memory allocator uses the following algorithm:
    + **
    +-**   1.  All memory allocations sizes are rounded up to a power of 2.
    ++**   1.  All memory allocation sizes are rounded up to a power of 2.
    + **
    + **   2.  If two adjacent free blocks are the halves of a larger block,
    + **       then the two blocks are coalesced into the single larger block.
    +@@ -19395,6 +22999,7 @@ static SQLITE_WSD struct Mem5Global {
    +   */
    +   sqlite3_mutex *mutex;
    + 
    ++#if defined(SQLITE_DEBUG) || defined(SQLITE_TEST)
    +   /*
    +   ** Performance statistics
    +   */
    +@@ -19406,11 +23011,12 @@ static SQLITE_WSD struct Mem5Global {
    +   u32 maxOut;         /* Maximum instantaneous currentOut */
    +   u32 maxCount;       /* Maximum instantaneous currentCount */
    +   u32 maxRequest;     /* Largest allocation (exclusive of internal frag) */
    ++#endif
    +   
    +   /*
    +   ** Lists of free blocks.  aiFreelist[0] is a list of free blocks of
    +   ** size mem5.szAtom.  aiFreelist[1] holds blocks of size szAtom*2.
    +-  ** and so forth.
    ++  ** aiFreelist[2] holds free blocks of size szAtom*4.  And so forth.
    +   */
    +   int aiFreelist[LOGMAX+1];
    + 
    +@@ -19476,9 +23082,7 @@ static void memsys5Link(int i, int iLogsize){
    + }
    + 
    + /*
    +-** If the STATIC_MEM mutex is not already held, obtain it now. The mutex
    +-** will already be held (obtained by code in malloc.c) if
    +-** sqlite3GlobalConfig.bMemStat is true.
    ++** Obtain or release the mutex needed to access global data structures.
    + */
    + static void memsys5Enter(void){
    +   sqlite3_mutex_enter(mem5.mutex);
    +@@ -19488,17 +23092,15 @@ static void memsys5Leave(void){
    + }
    + 
    + /*
    +-** Return the size of an outstanding allocation, in bytes.  The
    +-** size returned omits the 8-byte header overhead.  This only
    +-** works for chunks that are currently checked out.
    ++** Return the size of an outstanding allocation, in bytes.
    ++** This only works for chunks that are currently checked out.
    + */
    + static int memsys5Size(void *p){
    +-  int iSize = 0;
    +-  if( p ){
    +-    int i = (int)(((u8 *)p-mem5.zPool)/mem5.szAtom);
    +-    assert( i>=0 && i<mem5.nBlock );
    +-    iSize = mem5.szAtom * (1 << (mem5.aCtrl[i]&CTRL_LOGSIZE));
    +-  }
    ++  int iSize, i;
    ++  assert( p!=0 );
    ++  i = (int)(((u8 *)p-mem5.zPool)/mem5.szAtom);
    ++  assert( i>=0 && i<mem5.nBlock );
    ++  iSize = mem5.szAtom * (1 << (mem5.aCtrl[i]&CTRL_LOGSIZE));
    +   return iSize;
    + }
    + 
    +@@ -19521,21 +23123,20 @@ static void *memsys5MallocUnsafe(int nByte){
    +   /* nByte must be a positive */
    +   assert( nByte>0 );
    + 
    ++  /* No more than 1GiB per allocation */
    ++  if( nByte > 0x40000000 ) return 0;
    ++
    ++#if defined(SQLITE_DEBUG) || defined(SQLITE_TEST)
    +   /* Keep track of the maximum allocation request.  Even unfulfilled
    +   ** requests are counted */
    +   if( (u32)nByte>mem5.maxRequest ){
    +     mem5.maxRequest = nByte;
    +   }
    ++#endif
    + 
    +-  /* Abort if the requested allocation size is larger than the largest
    +-  ** power of two that we can represent using 32-bit signed integers.
    +-  */
    +-  if( nByte > 0x40000000 ){
    +-    return 0;
    +-  }
    + 
    +   /* Round nByte up to the next valid power of two */
    +-  for(iFullSz=mem5.szAtom, iLogsize=0; iFullSz<nByte; iFullSz *= 2, iLogsize++){}
    ++  for(iFullSz=mem5.szAtom,iLogsize=0; iFullSz<nByte; iFullSz*=2,iLogsize++){}
    + 
    +   /* Make sure mem5.aiFreelist[iLogsize] contains at least one free
    +   ** block.  If not, then split a block of the next larger power of
    +@@ -19559,6 +23160,7 @@ static void *memsys5MallocUnsafe(int nByte){
    +   }
    +   mem5.aCtrl[i] = iLogsize;
    + 
    ++#if defined(SQLITE_DEBUG) || defined(SQLITE_TEST)
    +   /* Update allocator performance statistics. */
    +   mem5.nAlloc++;
    +   mem5.totalAlloc += iFullSz;
    +@@ -19567,6 +23169,7 @@ static void *memsys5MallocUnsafe(int nByte){
    +   mem5.currentOut += iFullSz;
    +   if( mem5.maxCount<mem5.currentCount ) mem5.maxCount = mem5.currentCount;
    +   if( mem5.maxOut<mem5.currentOut ) mem5.maxOut = mem5.currentOut;
    ++#endif
    + 
    + #ifdef SQLITE_DEBUG
    +   /* Make sure the allocated memory does not assume that it is set to zero
    +@@ -19601,23 +23204,26 @@ static void memsys5FreeUnsafe(void *pOld){
    + 
    +   mem5.aCtrl[iBlock] |= CTRL_FREE;
    +   mem5.aCtrl[iBlock+size-1] |= CTRL_FREE;
    ++
    ++#if defined(SQLITE_DEBUG) || defined(SQLITE_TEST)
    +   assert( mem5.currentCount>0 );
    +   assert( mem5.currentOut>=(size*mem5.szAtom) );
    +   mem5.currentCount--;
    +   mem5.currentOut -= size*mem5.szAtom;
    +   assert( mem5.currentOut>0 || mem5.currentCount==0 );
    +   assert( mem5.currentCount>0 || mem5.currentOut==0 );
    ++#endif
    + 
    +   mem5.aCtrl[iBlock] = CTRL_FREE | iLogsize;
    +   while( ALWAYS(iLogsize<LOGMAX) ){
    +     int iBuddy;
    +     if( (iBlock>>iLogsize) & 1 ){
    +       iBuddy = iBlock - size;
    ++      assert( iBuddy>=0 );
    +     }else{
    +       iBuddy = iBlock + size;
    ++      if( iBuddy>=mem5.nBlock ) break;
    +     }
    +-    assert( iBuddy>=0 );
    +-    if( (iBuddy+(1<<iLogsize))>mem5.nBlock ) break;
    +     if( mem5.aCtrl[iBuddy]!=(CTRL_FREE | iLogsize) ) break;
    +     memsys5Unlink(iBuddy, iLogsize);
    +     iLogsize++;
    +@@ -19692,13 +23298,11 @@ static void *memsys5Realloc(void *pPrior, int nBytes){
    +   if( nBytes<=nOld ){
    +     return pPrior;
    +   }
    +-  memsys5Enter();
    +-  p = memsys5MallocUnsafe(nBytes);
    ++  p = memsys5Malloc(nBytes);
    +   if( p ){
    +     memcpy(p, pPrior, nOld);
    +-    memsys5FreeUnsafe(pPrior);
    ++    memsys5Free(pPrior);
    +   }
    +-  memsys5Leave();
    +   return p;
    + }
    + 
    +@@ -19898,6 +23502,193 @@ static SQLITE_WSD int mutexIsInit = 0;
    + 
    + 
    + #ifndef SQLITE_MUTEX_OMIT
    ++
    ++#ifdef SQLITE_ENABLE_MULTITHREADED_CHECKS
    ++/*
    ++** This block (enclosed by SQLITE_ENABLE_MULTITHREADED_CHECKS) contains
    ++** the implementation of a wrapper around the system default mutex
    ++** implementation (sqlite3DefaultMutex()). 
    ++**
    ++** Most calls are passed directly through to the underlying default
    ++** mutex implementation. Except, if a mutex is configured by calling
    ++** sqlite3MutexWarnOnContention() on it, then if contention is ever
    ++** encountered within xMutexEnter() a warning is emitted via sqlite3_log().
    ++**
    ++** This type of mutex is used as the database handle mutex when testing
    ++** apps that usually use SQLITE_CONFIG_MULTITHREAD mode.
    ++*/
    ++
    ++/* 
    ++** Type for all mutexes used when SQLITE_ENABLE_MULTITHREADED_CHECKS
    ++** is defined. Variable CheckMutex.mutex is a pointer to the real mutex
    ++** allocated by the system mutex implementation. Variable iType is usually set
    ++** to the type of mutex requested - SQLITE_MUTEX_RECURSIVE, SQLITE_MUTEX_FAST
    ++** or one of the static mutex identifiers. Or, if this is a recursive mutex
    ++** that has been configured using sqlite3MutexWarnOnContention(), it is
    ++** set to SQLITE_MUTEX_WARNONCONTENTION.
    ++*/
    ++typedef struct CheckMutex CheckMutex;
    ++struct CheckMutex {
    ++  int iType;
    ++  sqlite3_mutex *mutex;
    ++};
    ++
    ++#define SQLITE_MUTEX_WARNONCONTENTION  (-1)
    ++
    ++/* 
    ++** Pointer to real mutex methods object used by the CheckMutex
    ++** implementation. Set by checkMutexInit(). 
    ++*/
    ++static SQLITE_WSD const sqlite3_mutex_methods *pGlobalMutexMethods;
    ++
    ++#ifdef SQLITE_DEBUG
    ++static int checkMutexHeld(sqlite3_mutex *p){
    ++  return pGlobalMutexMethods->xMutexHeld(((CheckMutex*)p)->mutex);
    ++}
    ++static int checkMutexNotheld(sqlite3_mutex *p){
    ++  return pGlobalMutexMethods->xMutexNotheld(((CheckMutex*)p)->mutex);
    ++}
    ++#endif
    ++
    ++/*
    ++** Initialize and deinitialize the mutex subsystem.
    ++*/
    ++static int checkMutexInit(void){ 
    ++  pGlobalMutexMethods = sqlite3DefaultMutex();
    ++  return SQLITE_OK; 
    ++}
    ++static int checkMutexEnd(void){ 
    ++  pGlobalMutexMethods = 0;
    ++  return SQLITE_OK; 
    ++}
    ++
    ++/*
    ++** Allocate a mutex.
    ++*/
    ++static sqlite3_mutex *checkMutexAlloc(int iType){
    ++  static CheckMutex staticMutexes[] = {
    ++    {2, 0}, {3, 0}, {4, 0}, {5, 0},
    ++    {6, 0}, {7, 0}, {8, 0}, {9, 0},
    ++    {10, 0}, {11, 0}, {12, 0}, {13, 0}
    ++  };
    ++  CheckMutex *p = 0;
    ++
    ++  assert( SQLITE_MUTEX_RECURSIVE==1 && SQLITE_MUTEX_FAST==0 );
    ++  if( iType<2 ){
    ++    p = sqlite3MallocZero(sizeof(CheckMutex));
    ++    if( p==0 ) return 0;
    ++    p->iType = iType;
    ++  }else{
    ++#ifdef SQLITE_ENABLE_API_ARMOR
    ++    if( iType-2>=ArraySize(staticMutexes) ){
    ++      (void)SQLITE_MISUSE_BKPT;
    ++      return 0;
    ++    }
    ++#endif
    ++    p = &staticMutexes[iType-2];
    ++  }
    ++
    ++  if( p->mutex==0 ){
    ++    p->mutex = pGlobalMutexMethods->xMutexAlloc(iType);
    ++    if( p->mutex==0 ){
    ++      if( iType<2 ){
    ++        sqlite3_free(p);
    ++      }
    ++      p = 0;
    ++    }
    ++  }
    ++
    ++  return (sqlite3_mutex*)p;
    ++}
    ++
    ++/*
    ++** Free a mutex.
    ++*/
    ++static void checkMutexFree(sqlite3_mutex *p){
    ++  assert( SQLITE_MUTEX_RECURSIVE<2 );
    ++  assert( SQLITE_MUTEX_FAST<2 );
    ++  assert( SQLITE_MUTEX_WARNONCONTENTION<2 );
    ++
    ++#if SQLITE_ENABLE_API_ARMOR
    ++  if( ((CheckMutex*)p)->iType<2 )
    ++#endif
    ++  {
    ++    CheckMutex *pCheck = (CheckMutex*)p;
    ++    pGlobalMutexMethods->xMutexFree(pCheck->mutex);
    ++    sqlite3_free(pCheck);
    ++  }
    ++#ifdef SQLITE_ENABLE_API_ARMOR
    ++  else{
    ++    (void)SQLITE_MISUSE_BKPT;
    ++  }
    ++#endif
    ++}
    ++
    ++/*
    ++** Enter the mutex.
    ++*/
    ++static void checkMutexEnter(sqlite3_mutex *p){
    ++  CheckMutex *pCheck = (CheckMutex*)p;
    ++  if( pCheck->iType==SQLITE_MUTEX_WARNONCONTENTION ){
    ++    if( SQLITE_OK==pGlobalMutexMethods->xMutexTry(pCheck->mutex) ){
    ++      return;
    ++    }
    ++    sqlite3_log(SQLITE_MISUSE, 
    ++        "illegal multi-threaded access to database connection"
    ++    );
    ++  }
    ++  pGlobalMutexMethods->xMutexEnter(pCheck->mutex);
    ++}
    ++
    ++/*
    ++** Enter the mutex (do not block).
    ++*/
    ++static int checkMutexTry(sqlite3_mutex *p){
    ++  CheckMutex *pCheck = (CheckMutex*)p;
    ++  return pGlobalMutexMethods->xMutexTry(pCheck->mutex);
    ++}
    ++
    ++/*
    ++** Leave the mutex.
    ++*/
    ++static void checkMutexLeave(sqlite3_mutex *p){
    ++  CheckMutex *pCheck = (CheckMutex*)p;
    ++  pGlobalMutexMethods->xMutexLeave(pCheck->mutex);
    ++}
    ++
    ++sqlite3_mutex_methods const *multiThreadedCheckMutex(void){
    ++  static const sqlite3_mutex_methods sMutex = {
    ++    checkMutexInit,
    ++    checkMutexEnd,
    ++    checkMutexAlloc,
    ++    checkMutexFree,
    ++    checkMutexEnter,
    ++    checkMutexTry,
    ++    checkMutexLeave,
    ++#ifdef SQLITE_DEBUG
    ++    checkMutexHeld,
    ++    checkMutexNotheld
    ++#else
    ++    0,
    ++    0
    ++#endif
    ++  };
    ++  return &sMutex;
    ++}
    ++
    ++/*
    ++** Mark the SQLITE_MUTEX_RECURSIVE mutex passed as the only argument as
    ++** one on which there should be no contention.
    ++*/
    ++SQLITE_PRIVATE void sqlite3MutexWarnOnContention(sqlite3_mutex *p){
    ++  if( sqlite3GlobalConfig.mutex.xMutexAlloc==checkMutexAlloc ){
    ++    CheckMutex *pCheck = (CheckMutex*)p;
    ++    assert( pCheck->iType==SQLITE_MUTEX_RECURSIVE );
    ++    pCheck->iType = SQLITE_MUTEX_WARNONCONTENTION;
    ++  }
    ++}
    ++#endif   /* ifdef SQLITE_ENABLE_MULTITHREADED_CHECKS */
    ++
    + /*
    + ** Initialize the mutex system.
    + */
    +@@ -19913,7 +23704,11 @@ SQLITE_PRIVATE int sqlite3MutexInit(void){
    +     sqlite3_mutex_methods *pTo = &sqlite3GlobalConfig.mutex;
    + 
    +     if( sqlite3GlobalConfig.bCoreMutex ){
    ++#ifdef SQLITE_ENABLE_MULTITHREADED_CHECKS
    ++      pFrom = multiThreadedCheckMutex();
    ++#else
    +       pFrom = sqlite3DefaultMutex();
    ++#endif
    +     }else{
    +       pFrom = sqlite3NoopMutex();
    +     }
    +@@ -19958,7 +23753,7 @@ SQLITE_PRIVATE int sqlite3MutexEnd(void){
    + /*
    + ** Retrieve a pointer to a static mutex or allocate a new dynamic one.
    + */
    +-SQLITE_API sqlite3_mutex *SQLITE_STDCALL sqlite3_mutex_alloc(int id){
    ++SQLITE_API sqlite3_mutex *sqlite3_mutex_alloc(int id){
    + #ifndef SQLITE_OMIT_AUTOINIT
    +   if( id<=SQLITE_MUTEX_RECURSIVE && sqlite3_initialize() ) return 0;
    +   if( id>SQLITE_MUTEX_RECURSIVE && sqlite3MutexInit() ) return 0;
    +@@ -19979,7 +23774,7 @@ SQLITE_PRIVATE sqlite3_mutex *sqlite3MutexAlloc(int id){
    + /*
    + ** Free a dynamic mutex.
    + */
    +-SQLITE_API void SQLITE_STDCALL sqlite3_mutex_free(sqlite3_mutex *p){
    ++SQLITE_API void sqlite3_mutex_free(sqlite3_mutex *p){
    +   if( p ){
    +     assert( sqlite3GlobalConfig.mutex.xMutexFree );
    +     sqlite3GlobalConfig.mutex.xMutexFree(p);
    +@@ -19990,7 +23785,7 @@ SQLITE_API void SQLITE_STDCALL sqlite3_mutex_free(sqlite3_mutex *p){
    + ** Obtain the mutex p. If some other thread already has the mutex, block
    + ** until it can be obtained.
    + */
    +-SQLITE_API void SQLITE_STDCALL sqlite3_mutex_enter(sqlite3_mutex *p){
    ++SQLITE_API void sqlite3_mutex_enter(sqlite3_mutex *p){
    +   if( p ){
    +     assert( sqlite3GlobalConfig.mutex.xMutexEnter );
    +     sqlite3GlobalConfig.mutex.xMutexEnter(p);
    +@@ -20001,7 +23796,7 @@ SQLITE_API void SQLITE_STDCALL sqlite3_mutex_enter(sqlite3_mutex *p){
    + ** Obtain the mutex p. If successful, return SQLITE_OK. Otherwise, if another
    + ** thread holds the mutex and it cannot be obtained, return SQLITE_BUSY.
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_mutex_try(sqlite3_mutex *p){
    ++SQLITE_API int sqlite3_mutex_try(sqlite3_mutex *p){
    +   int rc = SQLITE_OK;
    +   if( p ){
    +     assert( sqlite3GlobalConfig.mutex.xMutexTry );
    +@@ -20016,7 +23811,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_mutex_try(sqlite3_mutex *p){
    + ** is not currently entered. If a NULL pointer is passed as an argument
    + ** this function is a no-op.
    + */
    +-SQLITE_API void SQLITE_STDCALL sqlite3_mutex_leave(sqlite3_mutex *p){
    ++SQLITE_API void sqlite3_mutex_leave(sqlite3_mutex *p){
    +   if( p ){
    +     assert( sqlite3GlobalConfig.mutex.xMutexLeave );
    +     sqlite3GlobalConfig.mutex.xMutexLeave(p);
    +@@ -20028,11 +23823,11 @@ SQLITE_API void SQLITE_STDCALL sqlite3_mutex_leave(sqlite3_mutex *p){
    + ** The sqlite3_mutex_held() and sqlite3_mutex_notheld() routine are
    + ** intended for use inside assert() statements.
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_mutex_held(sqlite3_mutex *p){
    ++SQLITE_API int sqlite3_mutex_held(sqlite3_mutex *p){
    +   assert( p==0 || sqlite3GlobalConfig.mutex.xMutexHeld );
    +   return p==0 || sqlite3GlobalConfig.mutex.xMutexHeld(p);
    + }
    +-SQLITE_API int SQLITE_STDCALL sqlite3_mutex_notheld(sqlite3_mutex *p){
    ++SQLITE_API int sqlite3_mutex_notheld(sqlite3_mutex *p){
    +   assert( p==0 || sqlite3GlobalConfig.mutex.xMutexNotheld );
    +   return p==0 || sqlite3GlobalConfig.mutex.xMutexNotheld(p);
    + }
    +@@ -20040,6 +23835,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_mutex_notheld(sqlite3_mutex *p){
    + 
    + #endif /* !defined(SQLITE_MUTEX_OMIT) */
    + 
    ++
    + /************** End of mutex.c ***********************************************/
    + /************** Begin file mutex_noop.c **************************************/
    + /*
    +@@ -20312,7 +24108,9 @@ struct sqlite3_mutex {
    + #endif
    + };
    + #if SQLITE_MUTEX_NREF
    +-#define SQLITE3_MUTEX_INITIALIZER { PTHREAD_MUTEX_INITIALIZER, 0, 0, (pthread_t)0, 0 }
    ++#define SQLITE3_MUTEX_INITIALIZER {PTHREAD_MUTEX_INITIALIZER,0,0,(pthread_t)0,0}
    ++#elif defined(SQLITE_ENABLE_API_ARMOR)
    ++#define SQLITE3_MUTEX_INITIALIZER { PTHREAD_MUTEX_INITIALIZER, 0 }
    + #else
    + #define SQLITE3_MUTEX_INITIALIZER { PTHREAD_MUTEX_INITIALIZER }
    + #endif
    +@@ -20706,8 +24504,8 @@ SQLITE_PRIVATE sqlite3_mutex_methods const *sqlite3DefaultMutex(void){
    + */
    + #ifdef SQLITE_PERFORMANCE_TRACE
    + 
    +-/* 
    +-** hwtime.h contains inline assembler code for implementing 
    ++/*
    ++** hwtime.h contains inline assembler code for implementing
    + ** high-performance timing routines.
    + */
    + /************** Include hwtime.h in the middle of os_common.h ****************/
    +@@ -20727,8 +24525,8 @@ SQLITE_PRIVATE sqlite3_mutex_methods const *sqlite3DefaultMutex(void){
    + ** This file contains inline asm code for retrieving "high-performance"
    + ** counters for x86 class CPUs.
    + */
    +-#ifndef _HWTIME_H_
    +-#define _HWTIME_H_
    ++#ifndef SQLITE_HWTIME_H
    ++#define SQLITE_HWTIME_H
    + 
    + /*
    + ** The following routine only works on pentium-class (or newer) processors.
    +@@ -20796,7 +24594,7 @@ SQLITE_PRIVATE   sqlite_uint64 sqlite3Hwtime(void){ return ((sqlite_uint64)0); }
    + 
    + #endif
    + 
    +-#endif /* !defined(_HWTIME_H_) */
    ++#endif /* !defined(SQLITE_HWTIME_H) */
    + 
    + /************** End of hwtime.h **********************************************/
    + /************** Continuing where we left off in os_common.h ******************/
    +@@ -20817,14 +24615,14 @@ static sqlite_uint64 g_elapsed;
    + ** 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;
    ++#if defined(SQLITE_TEST)
    ++SQLITE_API extern int sqlite3_io_error_hit;
    ++SQLITE_API extern int sqlite3_io_error_hardhit;
    ++SQLITE_API extern int sqlite3_io_error_pending;
    ++SQLITE_API extern int sqlite3_io_error_persist;
    ++SQLITE_API extern int sqlite3_io_error_benign;
    ++SQLITE_API extern int sqlite3_diskfull_pending;
    ++SQLITE_API extern int sqlite3_diskfull;
    + #define SimulateIOErrorBenign(X) sqlite3_io_error_benign=(X)
    + #define SimulateIOError(CODE)  \
    +   if( (sqlite3_io_error_persist && sqlite3_io_error_hit) \
    +@@ -20850,17 +24648,17 @@ static void local_ioerr(){
    + #define SimulateIOErrorBenign(X)
    + #define SimulateIOError(A)
    + #define SimulateDiskfullError(A)
    +-#endif
    ++#endif /* defined(SQLITE_TEST) */
    + 
    + /*
    + ** When testing, keep a count of the number of open files.
    + */
    +-#ifdef SQLITE_TEST
    +-SQLITE_API int sqlite3_open_file_count = 0;
    ++#if defined(SQLITE_TEST)
    ++SQLITE_API extern int sqlite3_open_file_count;
    + #define OpenCounter(X)  sqlite3_open_file_count+=(X)
    + #else
    + #define OpenCounter(X)
    +-#endif
    ++#endif /* defined(SQLITE_TEST) */
    + 
    + #endif /* !defined(_OS_COMMON_H_) */
    + 
    +@@ -20886,8 +24684,8 @@ SQLITE_API int sqlite3_open_file_count = 0;
    + **
    + ** This file contains code that is specific to Windows.
    + */
    +-#ifndef _OS_WIN_H_
    +-#define _OS_WIN_H_
    ++#ifndef SQLITE_OS_WIN_H
    ++#define SQLITE_OS_WIN_H
    + 
    + /*
    + ** Include the primary Windows SDK header file.
    +@@ -20959,7 +24757,7 @@ SQLITE_API int sqlite3_open_file_count = 0;
    + # define SQLITE_OS_WIN_THREADS 0
    + #endif
    + 
    +-#endif /* _OS_WIN_H_ */
    ++#endif /* SQLITE_OS_WIN_H */
    + 
    + /************** End of os_win.h **********************************************/
    + /************** Continuing where we left off in mutex_w32.c ******************/
    +@@ -21027,8 +24825,7 @@ SQLITE_PRIVATE void sqlite3MemoryBarrier(void){
    +   SQLITE_MEMORY_BARRIER;
    + #elif defined(__GNUC__)
    +   __sync_synchronize();
    +-#elif !defined(SQLITE_DISABLE_INTRINSIC) && \
    +-      defined(_MSC_VER) && _MSC_VER>=1300
    ++#elif MSVC_VERSION>=1300
    +   _ReadWriteBarrier();
    + #elif defined(MemoryBarrier)
    +   MemoryBarrier();
    +@@ -21062,8 +24859,8 @@ static int winMutex_isNt = -1; /* <0 means "need to query" */
    + */
    + static LONG SQLITE_WIN32_VOLATILE winMutex_lock = 0;
    + 
    +-SQLITE_API int SQLITE_STDCALL sqlite3_win32_is_nt(void); /* os_win.c */
    +-SQLITE_API void SQLITE_STDCALL sqlite3_win32_sleep(DWORD milliseconds); /* os_win.c */
    ++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){
    +   /* The first to increment to 1 does actual initialization */
    +@@ -21239,8 +25036,8 @@ static void winMutexEnter(sqlite3_mutex *p){
    +   p->owner = tid;
    +   p->nRef++;
    +   if( p->trace ){
    +-    OSTRACE(("ENTER-MUTEX tid=%lu, mutex=%p (%d), nRef=%d\n",
    +-             tid, p, p->trace, p->nRef));
    ++    OSTRACE(("ENTER-MUTEX tid=%lu, mutex(%d)=%p (%d), nRef=%d\n",
    ++             tid, p->id, p, p->trace, p->nRef));
    +   }
    + #endif
    + }
    +@@ -21282,8 +25079,8 @@ static int winMutexTry(sqlite3_mutex *p){
    + #endif
    + #ifdef SQLITE_DEBUG
    +   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)));
    ++    OSTRACE(("TRY-MUTEX tid=%lu, mutex(%d)=%p (%d), owner=%lu, nRef=%d, rc=%s\n",
    ++             tid, p->id, p, p->trace, p->owner, p->nRef, sqlite3ErrName(rc)));
    +   }
    + #endif
    +   return rc;
    +@@ -21311,8 +25108,8 @@ static void winMutexLeave(sqlite3_mutex *p){
    +   LeaveCriticalSection(&p->mutex);
    + #ifdef SQLITE_DEBUG
    +   if( p->trace ){
    +-    OSTRACE(("LEAVE-MUTEX tid=%lu, mutex=%p (%d), nRef=%d\n",
    +-             tid, p, p->trace, p->nRef));
    ++    OSTRACE(("LEAVE-MUTEX tid=%lu, mutex(%d)=%p (%d), nRef=%d\n",
    ++             tid, p->id, p, p->trace, p->nRef));
    +   }
    + #endif
    + }
    +@@ -21363,7 +25160,7 @@ SQLITE_PRIVATE sqlite3_mutex_methods const *sqlite3DefaultMutex(void){
    + ** held by SQLite. An example of non-essential memory is memory used to
    + ** cache database pages that are not currently in use.
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_release_memory(int n){
    ++SQLITE_API int sqlite3_release_memory(int n){
    + #ifdef SQLITE_ENABLE_MEMORY_MANAGEMENT
    +   return sqlite3PcacheReleaseMemory(n);
    + #else
    +@@ -21375,14 +25172,6 @@ SQLITE_API int SQLITE_STDCALL sqlite3_release_memory(int n){
    + #endif
    + }
    + 
    +-/*
    +-** An instance of the following object records the location of
    +-** each unused scratch buffer.
    +-*/
    +-typedef struct ScratchFreeslot {
    +-  struct ScratchFreeslot *pNext;   /* Next unused scratch buffer */
    +-} ScratchFreeslot;
    +-
    + /*
    + ** State information local to the memory allocation subsystem.
    + */
    +@@ -21390,22 +25179,12 @@ static SQLITE_WSD struct Mem0Global {
    +   sqlite3_mutex *mutex;         /* Mutex to serialize access */
    +   sqlite3_int64 alarmThreshold; /* The soft heap limit */
    + 
    +-  /*
    +-  ** Pointers to the end of sqlite3GlobalConfig.pScratch memory
    +-  ** (so that a range test can be used to determine if an allocation
    +-  ** being freed came from pScratch) and a pointer to the list of
    +-  ** unused scratch allocations.
    +-  */
    +-  void *pScratchEnd;
    +-  ScratchFreeslot *pScratchFree;
    +-  u32 nScratchFree;
    +-
    +   /*
    +   ** True if heap is nearly "full" where "full" is defined by the
    +   ** sqlite3_soft_heap_limit() setting.
    +   */
    +   int nearlyFull;
    +-} mem0 = { 0, 0, 0, 0, 0, 0 };
    ++} mem0 = { 0, 0, 0 };
    + 
    + #define mem0 GLOBAL(struct Mem0Global, mem0)
    + 
    +@@ -21422,7 +25201,7 @@ SQLITE_PRIVATE sqlite3_mutex *sqlite3MallocMutex(void){
    + ** that was invoked when memory usage grew too large.  Now it is a
    + ** no-op.
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_memory_alarm(
    ++SQLITE_API int sqlite3_memory_alarm(
    +   void(*xCallback)(void *pArg, sqlite3_int64 used,int N),
    +   void *pArg,
    +   sqlite3_int64 iThreshold
    +@@ -21438,7 +25217,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_memory_alarm(
    + ** Set the soft heap-size limit for the library. Passing a zero or 
    + ** negative value indicates no limit.
    + */
    +-SQLITE_API sqlite3_int64 SQLITE_STDCALL sqlite3_soft_heap_limit64(sqlite3_int64 n){
    ++SQLITE_API sqlite3_int64 sqlite3_soft_heap_limit64(sqlite3_int64 n){
    +   sqlite3_int64 priorLimit;
    +   sqlite3_int64 excess;
    +   sqlite3_int64 nUsed;
    +@@ -21460,7 +25239,7 @@ SQLITE_API sqlite3_int64 SQLITE_STDCALL sqlite3_soft_heap_limit64(sqlite3_int64
    +   if( excess>0 ) sqlite3_release_memory((int)(excess & 0x7fffffff));
    +   return priorLimit;
    + }
    +-SQLITE_API void SQLITE_STDCALL sqlite3_soft_heap_limit(int n){
    ++SQLITE_API void sqlite3_soft_heap_limit(int n){
    +   if( n<0 ) n = 0;
    +   sqlite3_soft_heap_limit64(n);
    + }
    +@@ -21474,31 +25253,7 @@ SQLITE_PRIVATE int sqlite3MallocInit(void){
    +     sqlite3MemSetDefault();
    +   }
    +   memset(&mem0, 0, sizeof(mem0));
    +-  if( sqlite3GlobalConfig.bCoreMutex ){
    +-    mem0.mutex = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MEM);
    +-  }
    +-  if( sqlite3GlobalConfig.pScratch && sqlite3GlobalConfig.szScratch>=100
    +-      && sqlite3GlobalConfig.nScratch>0 ){
    +-    int i, n, sz;
    +-    ScratchFreeslot *pSlot;
    +-    sz = ROUNDDOWN8(sqlite3GlobalConfig.szScratch);
    +-    sqlite3GlobalConfig.szScratch = sz;
    +-    pSlot = (ScratchFreeslot*)sqlite3GlobalConfig.pScratch;
    +-    n = sqlite3GlobalConfig.nScratch;
    +-    mem0.pScratchFree = pSlot;
    +-    mem0.nScratchFree = n;
    +-    for(i=0; i<n-1; i++){
    +-      pSlot->pNext = (ScratchFreeslot*)(sz+(char*)pSlot);
    +-      pSlot = pSlot->pNext;
    +-    }
    +-    pSlot->pNext = 0;
    +-    mem0.pScratchEnd = (void*)&pSlot[1];
    +-  }else{
    +-    mem0.pScratchEnd = 0;
    +-    sqlite3GlobalConfig.pScratch = 0;
    +-    sqlite3GlobalConfig.szScratch = 0;
    +-    sqlite3GlobalConfig.nScratch = 0;
    +-  }
    ++  mem0.mutex = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MEM);
    +   if( sqlite3GlobalConfig.pPage==0 || sqlite3GlobalConfig.szPage<512
    +       || sqlite3GlobalConfig.nPage<=0 ){
    +     sqlite3GlobalConfig.pPage = 0;
    +@@ -21531,7 +25286,7 @@ SQLITE_PRIVATE void sqlite3MallocEnd(void){
    + /*
    + ** Return the amount of memory currently checked out.
    + */
    +-SQLITE_API sqlite3_int64 SQLITE_STDCALL sqlite3_memory_used(void){
    ++SQLITE_API sqlite3_int64 sqlite3_memory_used(void){
    +   sqlite3_int64 res, mx;
    +   sqlite3_status64(SQLITE_STATUS_MEMORY_USED, &res, &mx, 0);
    +   return res;
    +@@ -21542,7 +25297,7 @@ SQLITE_API sqlite3_int64 SQLITE_STDCALL sqlite3_memory_used(void){
    + ** checked out since either the beginning of this process
    + ** or since the most recent reset.
    + */
    +-SQLITE_API sqlite3_int64 SQLITE_STDCALL sqlite3_memory_highwater(int resetFlag){
    ++SQLITE_API sqlite3_int64 sqlite3_memory_highwater(int resetFlag){
    +   sqlite3_int64 res, mx;
    +   sqlite3_status64(SQLITE_STATUS_MEMORY_USED, &res, &mx, resetFlag);
    +   return mx;
    +@@ -21562,12 +25317,27 @@ static void sqlite3MallocAlarm(int nByte){
    + ** Do a memory allocation with statistics and alarms.  Assume the
    + ** lock is already held.
    + */
    +-static int mallocWithAlarm(int n, void **pp){
    +-  int nFull;
    ++static void mallocWithAlarm(int n, void **pp){
    +   void *p;
    ++  int nFull;
    +   assert( sqlite3_mutex_held(mem0.mutex) );
    ++  assert( n>0 );
    ++
    ++  /* In Firefox (circa 2017-02-08), xRoundup() is remapped to an internal
    ++  ** implementation of malloc_good_size(), which must be called in debug
    ++  ** mode and specifically when the DMD "Dark Matter Detector" is enabled
    ++  ** or else a crash results.  Hence, do not attempt to optimize out the
    ++  ** following xRoundup() call. */
    +   nFull = sqlite3GlobalConfig.m.xRoundup(n);
    +-  sqlite3StatusSet(SQLITE_STATUS_MALLOC_SIZE, n);
    ++
    ++#ifdef SQLITE_MAX_MEMORY
    ++  if( sqlite3StatusValue(SQLITE_STATUS_MEMORY_USED)+nFull>SQLITE_MAX_MEMORY ){
    ++    *pp = 0;
    ++    return;
    ++  }
    ++#endif
    ++
    ++  sqlite3StatusHighwater(SQLITE_STATUS_MALLOC_SIZE, n);
    +   if( mem0.alarmThreshold>0 ){
    +     sqlite3_int64 nUsed = sqlite3StatusValue(SQLITE_STATUS_MEMORY_USED);
    +     if( nUsed >= mem0.alarmThreshold - nFull ){
    +@@ -21590,7 +25360,6 @@ static int mallocWithAlarm(int n, void **pp){
    +     sqlite3StatusUp(SQLITE_STATUS_MALLOC_COUNT, 1);
    +   }
    +   *pp = p;
    +-  return nFull;
    + }
    + 
    + /*
    +@@ -21622,124 +25391,25 @@ SQLITE_PRIVATE void *sqlite3Malloc(u64 n){
    + ** First make sure the memory subsystem is initialized, then do the
    + ** allocation.
    + */
    +-SQLITE_API void *SQLITE_STDCALL sqlite3_malloc(int n){
    ++SQLITE_API void *sqlite3_malloc(int n){
    + #ifndef SQLITE_OMIT_AUTOINIT
    +   if( sqlite3_initialize() ) return 0;
    + #endif
    +   return n<=0 ? 0 : sqlite3Malloc(n);
    + }
    +-SQLITE_API void *SQLITE_STDCALL sqlite3_malloc64(sqlite3_uint64 n){
    ++SQLITE_API void *sqlite3_malloc64(sqlite3_uint64 n){
    + #ifndef SQLITE_OMIT_AUTOINIT
    +   if( sqlite3_initialize() ) return 0;
    + #endif
    +   return sqlite3Malloc(n);
    + }
    + 
    +-/*
    +-** Each thread may only have a single outstanding allocation from
    +-** xScratchMalloc().  We verify this constraint in the single-threaded
    +-** case by setting scratchAllocOut to 1 when an allocation
    +-** is outstanding clearing it when the allocation is freed.
    +-*/
    +-#if SQLITE_THREADSAFE==0 && !defined(NDEBUG)
    +-static int scratchAllocOut = 0;
    +-#endif
    +-
    +-
    +-/*
    +-** Allocate memory that is to be used and released right away.
    +-** This routine is similar to alloca() in that it is not intended
    +-** for situations where the memory might be held long-term.  This
    +-** routine is intended to get memory to old large transient data
    +-** structures that would not normally fit on the stack of an
    +-** embedded processor.
    +-*/
    +-SQLITE_PRIVATE void *sqlite3ScratchMalloc(int n){
    +-  void *p;
    +-  assert( n>0 );
    +-
    +-  sqlite3_mutex_enter(mem0.mutex);
    +-  sqlite3StatusSet(SQLITE_STATUS_SCRATCH_SIZE, n);
    +-  if( mem0.nScratchFree && sqlite3GlobalConfig.szScratch>=n ){
    +-    p = mem0.pScratchFree;
    +-    mem0.pScratchFree = mem0.pScratchFree->pNext;
    +-    mem0.nScratchFree--;
    +-    sqlite3StatusUp(SQLITE_STATUS_SCRATCH_USED, 1);
    +-    sqlite3_mutex_leave(mem0.mutex);
    +-  }else{
    +-    sqlite3_mutex_leave(mem0.mutex);
    +-    p = sqlite3Malloc(n);
    +-    if( sqlite3GlobalConfig.bMemstat && p ){
    +-      sqlite3_mutex_enter(mem0.mutex);
    +-      sqlite3StatusUp(SQLITE_STATUS_SCRATCH_OVERFLOW, sqlite3MallocSize(p));
    +-      sqlite3_mutex_leave(mem0.mutex);
    +-    }
    +-    sqlite3MemdebugSetType(p, MEMTYPE_SCRATCH);
    +-  }
    +-  assert( sqlite3_mutex_notheld(mem0.mutex) );
    +-
    +-
    +-#if SQLITE_THREADSAFE==0 && !defined(NDEBUG)
    +-  /* EVIDENCE-OF: R-12970-05880 SQLite will not use more than one scratch
    +-  ** buffers per thread.
    +-  **
    +-  ** This can only be checked in single-threaded mode.
    +-  */
    +-  assert( scratchAllocOut==0 );
    +-  if( p ) scratchAllocOut++;
    +-#endif
    +-
    +-  return p;
    +-}
    +-SQLITE_PRIVATE void sqlite3ScratchFree(void *p){
    +-  if( p ){
    +-
    +-#if SQLITE_THREADSAFE==0 && !defined(NDEBUG)
    +-    /* Verify that no more than two scratch allocation per thread
    +-    ** is outstanding at one time.  (This is only checked in the
    +-    ** single-threaded case since checking in the multi-threaded case
    +-    ** would be much more complicated.) */
    +-    assert( scratchAllocOut>=1 && scratchAllocOut<=2 );
    +-    scratchAllocOut--;
    +-#endif
    +-
    +-    if( p>=sqlite3GlobalConfig.pScratch && p<mem0.pScratchEnd ){
    +-      /* Release memory from the SQLITE_CONFIG_SCRATCH allocation */
    +-      ScratchFreeslot *pSlot;
    +-      pSlot = (ScratchFreeslot*)p;
    +-      sqlite3_mutex_enter(mem0.mutex);
    +-      pSlot->pNext = mem0.pScratchFree;
    +-      mem0.pScratchFree = pSlot;
    +-      mem0.nScratchFree++;
    +-      assert( mem0.nScratchFree <= (u32)sqlite3GlobalConfig.nScratch );
    +-      sqlite3StatusDown(SQLITE_STATUS_SCRATCH_USED, 1);
    +-      sqlite3_mutex_leave(mem0.mutex);
    +-    }else{
    +-      /* Release memory back to the heap */
    +-      assert( sqlite3MemdebugHasType(p, MEMTYPE_SCRATCH) );
    +-      assert( sqlite3MemdebugNoType(p, (u8)~MEMTYPE_SCRATCH) );
    +-      sqlite3MemdebugSetType(p, MEMTYPE_HEAP);
    +-      if( sqlite3GlobalConfig.bMemstat ){
    +-        int iSize = sqlite3MallocSize(p);
    +-        sqlite3_mutex_enter(mem0.mutex);
    +-        sqlite3StatusDown(SQLITE_STATUS_SCRATCH_OVERFLOW, iSize);
    +-        sqlite3StatusDown(SQLITE_STATUS_MEMORY_USED, iSize);
    +-        sqlite3StatusDown(SQLITE_STATUS_MALLOC_COUNT, 1);
    +-        sqlite3GlobalConfig.m.xFree(p);
    +-        sqlite3_mutex_leave(mem0.mutex);
    +-      }else{
    +-        sqlite3GlobalConfig.m.xFree(p);
    +-      }
    +-    }
    +-  }
    +-}
    +-
    + /*
    + ** TRUE if p is a lookaside memory allocation from db
    + */
    + #ifndef SQLITE_OMIT_LOOKASIDE
    + static int isLookaside(sqlite3 *db, void *p){
    +-  return p>=db->lookaside.pStart && p<db->lookaside.pEnd;
    ++  return SQLITE_WITHIN(p, db->lookaside.pStart, db->lookaside.pEnd);
    + }
    + #else
    + #define isLookaside(A,B) 0
    +@@ -21754,8 +25424,9 @@ SQLITE_PRIVATE int sqlite3MallocSize(void *p){
    +   return sqlite3GlobalConfig.m.xSize(p);
    + }
    + SQLITE_PRIVATE int sqlite3DbMallocSize(sqlite3 *db, void *p){
    ++  assert( p!=0 );
    +   if( db==0 || !isLookaside(db,p) ){
    +-#if SQLITE_DEBUG
    ++#ifdef SQLITE_DEBUG
    +     if( db==0 ){
    +       assert( sqlite3MemdebugNoType(p, (u8)~MEMTYPE_HEAP) );
    +       assert( sqlite3MemdebugHasType(p, MEMTYPE_HEAP) );
    +@@ -21770,16 +25441,16 @@ SQLITE_PRIVATE int sqlite3DbMallocSize(sqlite3 *db, void *p){
    +     return db->lookaside.sz;
    +   }
    + }
    +-SQLITE_API sqlite3_uint64 SQLITE_STDCALL sqlite3_msize(void *p){
    ++SQLITE_API sqlite3_uint64 sqlite3_msize(void *p){
    +   assert( sqlite3MemdebugNoType(p, (u8)~MEMTYPE_HEAP) );
    +   assert( sqlite3MemdebugHasType(p, MEMTYPE_HEAP) );
    +-  return (sqlite3_uint64)sqlite3GlobalConfig.m.xSize(p);
    ++  return p ? sqlite3GlobalConfig.m.xSize(p) : 0;
    + }
    + 
    + /*
    + ** Free memory previously obtained from sqlite3Malloc().
    + */
    +-SQLITE_API void SQLITE_STDCALL sqlite3_free(void *p){
    ++SQLITE_API void sqlite3_free(void *p){
    +   if( p==0 ) return;  /* IMP: R-49053-54554 */
    +   assert( sqlite3MemdebugHasType(p, MEMTYPE_HEAP) );
    +   assert( sqlite3MemdebugNoType(p, (u8)~MEMTYPE_HEAP) );
    +@@ -21804,11 +25475,12 @@ static SQLITE_NOINLINE void measureAllocationSize(sqlite3 *db, void *p){
    + 
    + /*
    + ** Free memory that might be associated with a particular database
    +-** connection.
    ++** connection.  Calling sqlite3DbFree(D,X) for X==0 is a harmless no-op.
    ++** The sqlite3DbFreeNN(D,X) version requires that X be non-NULL.
    + */
    +-SQLITE_PRIVATE void sqlite3DbFree(sqlite3 *db, void *p){
    ++SQLITE_PRIVATE void sqlite3DbFreeNN(sqlite3 *db, void *p){
    +   assert( db==0 || sqlite3_mutex_held(db->mutex) );
    +-  if( p==0 ) return;
    ++  assert( p!=0 );
    +   if( db ){
    +     if( db->pnBytesFreed ){
    +       measureAllocationSize(db, p);
    +@@ -21816,13 +25488,12 @@ SQLITE_PRIVATE void sqlite3DbFree(sqlite3 *db, void *p){
    +     }
    +     if( isLookaside(db, p) ){
    +       LookasideSlot *pBuf = (LookasideSlot*)p;
    +-#if SQLITE_DEBUG
    ++#ifdef SQLITE_DEBUG
    +       /* Trash all content in the buffer being freed */
    +       memset(p, 0xaa, db->lookaside.sz);
    + #endif
    +       pBuf->pNext = db->lookaside.pFree;
    +       db->lookaside.pFree = pBuf;
    +-      db->lookaside.nOut--;
    +       return;
    +     }
    +   }
    +@@ -21832,6 +25503,10 @@ SQLITE_PRIVATE void sqlite3DbFree(sqlite3 *db, void *p){
    +   sqlite3MemdebugSetType(p, MEMTYPE_HEAP);
    +   sqlite3_free(p);
    + }
    ++SQLITE_PRIVATE void sqlite3DbFree(sqlite3 *db, void *p){
    ++  assert( db==0 || sqlite3_mutex_held(db->mutex) );
    ++  if( p ) sqlite3DbFreeNN(db, p);
    ++}
    + 
    + /*
    + ** Change the size of an existing memory allocation
    +@@ -21861,9 +25536,9 @@ SQLITE_PRIVATE void *sqlite3Realloc(void *pOld, u64 nBytes){
    +     pNew = pOld;
    +   }else if( sqlite3GlobalConfig.bMemstat ){
    +     sqlite3_mutex_enter(mem0.mutex);
    +-    sqlite3StatusSet(SQLITE_STATUS_MALLOC_SIZE, (int)nBytes);
    ++    sqlite3StatusHighwater(SQLITE_STATUS_MALLOC_SIZE, (int)nBytes);
    +     nDiff = nNew - nOld;
    +-    if( sqlite3StatusValue(SQLITE_STATUS_MEMORY_USED) >= 
    ++    if( nDiff>0 && sqlite3StatusValue(SQLITE_STATUS_MEMORY_USED) >= 
    +           mem0.alarmThreshold-nDiff ){
    +       sqlite3MallocAlarm(nDiff);
    +     }
    +@@ -21888,14 +25563,14 @@ SQLITE_PRIVATE void *sqlite3Realloc(void *pOld, u64 nBytes){
    + ** The public interface to sqlite3Realloc.  Make sure that the memory
    + ** subsystem is initialized prior to invoking sqliteRealloc.
    + */
    +-SQLITE_API void *SQLITE_STDCALL sqlite3_realloc(void *pOld, int n){
    ++SQLITE_API void *sqlite3_realloc(void *pOld, int n){
    + #ifndef SQLITE_OMIT_AUTOINIT
    +   if( sqlite3_initialize() ) return 0;
    + #endif
    +   if( n<0 ) n = 0;  /* IMP: R-26507-47431 */
    +   return sqlite3Realloc(pOld, n);
    + }
    +-SQLITE_API void *SQLITE_STDCALL sqlite3_realloc64(void *pOld, sqlite3_uint64 n){
    ++SQLITE_API void *sqlite3_realloc64(void *pOld, sqlite3_uint64 n){
    + #ifndef SQLITE_OMIT_AUTOINIT
    +   if( sqlite3_initialize() ) return 0;
    + #endif
    +@@ -21919,16 +25594,31 @@ SQLITE_PRIVATE void *sqlite3MallocZero(u64 n){
    + ** the mallocFailed flag in the connection pointer.
    + */
    + SQLITE_PRIVATE void *sqlite3DbMallocZero(sqlite3 *db, u64 n){
    +-  void *p = sqlite3DbMallocRaw(db, n);
    +-  if( p ){
    +-    memset(p, 0, (size_t)n);
    +-  }
    ++  void *p;
    ++  testcase( db==0 );
    ++  p = sqlite3DbMallocRaw(db, n);
    ++  if( p ) memset(p, 0, (size_t)n);
    ++  return p;
    ++}
    ++
    ++
    ++/* Finish the work of sqlite3DbMallocRawNN for the unusual and
    ++** slower case when the allocation cannot be fulfilled using lookaside.
    ++*/
    ++static SQLITE_NOINLINE void *dbMallocRawFinish(sqlite3 *db, u64 n){
    ++  void *p;
    ++  assert( db!=0 );
    ++  p = sqlite3Malloc(n);
    ++  if( !p ) sqlite3OomFault(db);
    ++  sqlite3MemdebugSetType(p, 
    ++         (db->lookaside.bDisable==0) ? MEMTYPE_LOOKASIDE : MEMTYPE_HEAP);
    +   return p;
    + }
    + 
    + /*
    +-** Allocate and zero memory.  If the allocation fails, make
    +-** the mallocFailed flag in the connection pointer.
    ++** Allocate memory, either lookaside (if possible) or heap.  
    ++** If the allocation fails, set the mallocFailed flag in
    ++** the connection pointer.
    + **
    + ** If db!=0 and db->mallocFailed is true (indicating a prior malloc
    + ** failure on the same database connection) then always return 0.
    +@@ -21943,64 +25633,73 @@ SQLITE_PRIVATE void *sqlite3DbMallocZero(sqlite3 *db, u64 n){
    + **
    + ** In other words, if a subsequent malloc (ex: "b") worked, it is assumed
    + ** that all prior mallocs (ex: "a") worked too.
    ++**
    ++** The sqlite3MallocRawNN() variant guarantees that the "db" parameter is
    ++** not a NULL pointer.
    + */
    + SQLITE_PRIVATE void *sqlite3DbMallocRaw(sqlite3 *db, u64 n){
    +   void *p;
    +-  assert( db==0 || sqlite3_mutex_held(db->mutex) );
    +-  assert( db==0 || db->pnBytesFreed==0 );
    ++  if( db ) return sqlite3DbMallocRawNN(db, n);
    ++  p = sqlite3Malloc(n);
    ++  sqlite3MemdebugSetType(p, MEMTYPE_HEAP);
    ++  return p;
    ++}
    ++SQLITE_PRIVATE void *sqlite3DbMallocRawNN(sqlite3 *db, u64 n){
    + #ifndef SQLITE_OMIT_LOOKASIDE
    +-  if( db ){
    +-    LookasideSlot *pBuf;
    +-    if( db->mallocFailed ){
    +-      return 0;
    +-    }
    +-    if( db->lookaside.bEnabled ){
    +-      if( n>db->lookaside.sz ){
    +-        db->lookaside.anStat[1]++;
    +-      }else if( (pBuf = db->lookaside.pFree)==0 ){
    +-        db->lookaside.anStat[2]++;
    +-      }else{
    +-        db->lookaside.pFree = pBuf->pNext;
    +-        db->lookaside.nOut++;
    +-        db->lookaside.anStat[0]++;
    +-        if( db->lookaside.nOut>db->lookaside.mxOut ){
    +-          db->lookaside.mxOut = db->lookaside.nOut;
    +-        }
    +-        return (void*)pBuf;
    +-      }
    +-    }
    ++  LookasideSlot *pBuf;
    ++  assert( db!=0 );
    ++  assert( sqlite3_mutex_held(db->mutex) );
    ++  assert( db->pnBytesFreed==0 );
    ++  if( db->lookaside.bDisable==0 ){
    ++    assert( db->mallocFailed==0 );
    ++    if( n>db->lookaside.sz ){
    ++      db->lookaside.anStat[1]++;
    ++    }else if( (pBuf = db->lookaside.pFree)!=0 ){
    ++      db->lookaside.pFree = pBuf->pNext;
    ++      db->lookaside.anStat[0]++;
    ++      return (void*)pBuf;
    ++    }else if( (pBuf = db->lookaside.pInit)!=0 ){
    ++      db->lookaside.pInit = pBuf->pNext;
    ++      db->lookaside.anStat[0]++;
    ++      return (void*)pBuf;
    ++    }else{
    ++      db->lookaside.anStat[2]++;
    ++    }
    ++  }else if( db->mallocFailed ){
    ++    return 0;
    +   }
    + #else
    +-  if( db && db->mallocFailed ){
    ++  assert( db!=0 );
    ++  assert( sqlite3_mutex_held(db->mutex) );
    ++  assert( db->pnBytesFreed==0 );
    ++  if( db->mallocFailed ){
    +     return 0;
    +   }
    + #endif
    +-  p = sqlite3Malloc(n);
    +-  if( !p && db ){
    +-    db->mallocFailed = 1;
    +-  }
    +-  sqlite3MemdebugSetType(p, 
    +-         (db && db->lookaside.bEnabled) ? MEMTYPE_LOOKASIDE : MEMTYPE_HEAP);
    +-  return p;
    ++  return dbMallocRawFinish(db, n);
    + }
    + 
    ++/* Forward declaration */
    ++static SQLITE_NOINLINE void *dbReallocFinish(sqlite3 *db, void *p, u64 n);
    ++
    + /*
    + ** Resize the block of memory pointed to by p to n bytes. If the
    + ** resize fails, set the mallocFailed flag in the connection object.
    + */
    + SQLITE_PRIVATE void *sqlite3DbRealloc(sqlite3 *db, void *p, u64 n){
    +-  void *pNew = 0;
    +   assert( db!=0 );
    ++  if( p==0 ) return sqlite3DbMallocRawNN(db, n);
    +   assert( sqlite3_mutex_held(db->mutex) );
    ++  if( isLookaside(db,p) && n<=db->lookaside.sz ) return p;
    ++  return dbReallocFinish(db, p, n);
    ++}
    ++static SQLITE_NOINLINE void *dbReallocFinish(sqlite3 *db, void *p, u64 n){
    ++  void *pNew = 0;
    ++  assert( db!=0 );
    ++  assert( p!=0 );
    +   if( db->mallocFailed==0 ){
    +-    if( p==0 ){
    +-      return sqlite3DbMallocRaw(db, n);
    +-    }
    +     if( isLookaside(db, p) ){
    +-      if( n<=db->lookaside.sz ){
    +-        return p;
    +-      }
    +-      pNew = sqlite3DbMallocRaw(db, n);
    ++      pNew = sqlite3DbMallocRawNN(db, n);
    +       if( pNew ){
    +         memcpy(pNew, p, db->lookaside.sz);
    +         sqlite3DbFree(db, p);
    +@@ -22011,10 +25710,10 @@ SQLITE_PRIVATE void *sqlite3DbRealloc(sqlite3 *db, void *p, u64 n){
    +       sqlite3MemdebugSetType(p, MEMTYPE_HEAP);
    +       pNew = sqlite3_realloc64(p, n);
    +       if( !pNew ){
    +-        db->mallocFailed = 1;
    ++        sqlite3OomFault(db);
    +       }
    +       sqlite3MemdebugSetType(pNew,
    +-            (db->lookaside.bEnabled ? MEMTYPE_LOOKASIDE : MEMTYPE_HEAP));
    ++            (db->lookaside.bDisable==0 ? MEMTYPE_LOOKASIDE : MEMTYPE_HEAP));
    +     }
    +   }
    +   return pNew;
    +@@ -22046,9 +25745,8 @@ SQLITE_PRIVATE char *sqlite3DbStrDup(sqlite3 *db, const char *z){
    +   if( z==0 ){
    +     return 0;
    +   }
    +-  n = sqlite3Strlen30(z) + 1;
    +-  assert( (n&0x7fffffff)==n );
    +-  zNew = sqlite3DbMallocRaw(db, (int)n);
    ++  n = strlen(z) + 1;
    ++  zNew = sqlite3DbMallocRaw(db, n);
    +   if( zNew ){
    +     memcpy(zNew, z, n);
    +   }
    +@@ -22056,11 +25754,12 @@ SQLITE_PRIVATE char *sqlite3DbStrDup(sqlite3 *db, const char *z){
    + }
    + SQLITE_PRIVATE char *sqlite3DbStrNDup(sqlite3 *db, const char *z, u64 n){
    +   char *zNew;
    ++  assert( db!=0 );
    +   if( z==0 ){
    +     return 0;
    +   }
    +   assert( (n&0x7fffffff)==n );
    +-  zNew = sqlite3DbMallocRaw(db, n+1);
    ++  zNew = sqlite3DbMallocRawNN(db, n+1);
    +   if( zNew ){
    +     memcpy(zNew, z, (size_t)n);
    +     zNew[n] = 0;
    +@@ -22068,6 +25767,19 @@ SQLITE_PRIVATE char *sqlite3DbStrNDup(sqlite3 *db, const char *z, u64 n){
    +   return zNew;
    + }
    + 
    ++/*
    ++** The text between zStart and zEnd represents a phrase within a larger
    ++** SQL statement.  Make a copy of this phrase in space obtained form
    ++** sqlite3DbMalloc().  Omit leading and trailing whitespace.
    ++*/
    ++SQLITE_PRIVATE char *sqlite3DbSpanDup(sqlite3 *db, const char *zStart, const char *zEnd){
    ++  int n;
    ++  while( sqlite3Isspace(zStart[0]) ) zStart++;
    ++  n = (int)(zEnd - zStart);
    ++  while( ALWAYS(n>0) && sqlite3Isspace(zStart[n-1]) ) n--;
    ++  return sqlite3DbStrNDup(db, zStart, n);
    ++}
    ++
    + /*
    + ** Free any prior content in *pz and replace it with a copy of zNew.
    + */
    +@@ -22076,13 +25788,45 @@ SQLITE_PRIVATE void sqlite3SetString(char **pz, sqlite3 *db, const char *zNew){
    +   *pz = sqlite3DbStrDup(db, zNew);
    + }
    + 
    ++/*
    ++** Call this routine to record the fact that an OOM (out-of-memory) error
    ++** has happened.  This routine will set db->mallocFailed, and also
    ++** temporarily disable the lookaside memory allocator and interrupt
    ++** any running VDBEs.
    ++*/
    ++SQLITE_PRIVATE void sqlite3OomFault(sqlite3 *db){
    ++  if( db->mallocFailed==0 && db->bBenignMalloc==0 ){
    ++    db->mallocFailed = 1;
    ++    if( db->nVdbeExec>0 ){
    ++      db->u1.isInterrupted = 1;
    ++    }
    ++    db->lookaside.bDisable++;
    ++  }
    ++}
    ++
    ++/*
    ++** This routine reactivates the memory allocator and clears the
    ++** db->mallocFailed flag as necessary.
    ++**
    ++** The memory allocator is not restarted if there are running
    ++** VDBEs.
    ++*/
    ++SQLITE_PRIVATE void sqlite3OomClear(sqlite3 *db){
    ++  if( db->mallocFailed && db->nVdbeExec==0 ){
    ++    db->mallocFailed = 0;
    ++    db->u1.isInterrupted = 0;
    ++    assert( db->lookaside.bDisable>0 );
    ++    db->lookaside.bDisable--;
    ++  }
    ++}
    ++
    + /*
    + ** Take actions at the end of an API call to indicate an OOM error
    + */
    + static SQLITE_NOINLINE int apiOomError(sqlite3 *db){
    +-  db->mallocFailed = 0;
    ++  sqlite3OomClear(db);
    +   sqlite3Error(db, SQLITE_NOMEM);
    +-  return SQLITE_NOMEM;
    ++  return SQLITE_NOMEM_BKPT;
    + }
    + 
    + /*
    +@@ -22129,26 +25873,27 @@ SQLITE_PRIVATE int sqlite3ApiExit(sqlite3* db, int rc){
    + ** Conversion types fall into various categories as defined by the
    + ** following enumeration.
    + */
    +-#define etRADIX       1 /* Integer types.  %d, %x, %o, and so forth */
    +-#define etFLOAT       2 /* Floating point.  %f */
    +-#define etEXP         3 /* Exponentional notation. %e and %E */
    +-#define etGENERIC     4 /* Floating or exponential, depending on exponent. %g */
    +-#define etSIZE        5 /* Return number of characters processed so far. %n */
    +-#define etSTRING      6 /* Strings. %s */
    +-#define etDYNSTRING   7 /* Dynamically allocated strings. %z */
    +-#define etPERCENT     8 /* Percent symbol. %% */
    +-#define etCHARX       9 /* Characters. %c */
    ++#define etRADIX       0 /* non-decimal integer types.  %x %o */
    ++#define etFLOAT       1 /* Floating point.  %f */
    ++#define etEXP         2 /* Exponentional notation. %e and %E */
    ++#define etGENERIC     3 /* Floating or exponential, depending on exponent. %g */
    ++#define etSIZE        4 /* Return number of characters processed so far. %n */
    ++#define etSTRING      5 /* Strings. %s */
    ++#define etDYNSTRING   6 /* Dynamically allocated strings. %z */
    ++#define etPERCENT     7 /* Percent symbol. %% */
    ++#define etCHARX       8 /* Characters. %c */
    + /* The rest are extensions, not normally found in printf() */
    +-#define etSQLESCAPE  10 /* Strings with '\'' doubled.  %q */
    +-#define etSQLESCAPE2 11 /* Strings with '\'' doubled and enclosed in '',
    ++#define etSQLESCAPE   9 /* Strings with '\'' doubled.  %q */
    ++#define etSQLESCAPE2 10 /* Strings with '\'' doubled and enclosed in '',
    +                           NULL pointers replaced by SQL NULL.  %Q */
    +-#define etTOKEN      12 /* a pointer to a Token structure */
    +-#define etSRCLIST    13 /* a pointer to a SrcList */
    +-#define etPOINTER    14 /* The %p conversion */
    +-#define etSQLESCAPE3 15 /* %w -> Strings with '\"' doubled */
    +-#define etORDINAL    16 /* %r -> 1st, 2nd, 3rd, 4th, etc.  English only */
    ++#define etTOKEN      11 /* a pointer to a Token structure */
    ++#define etSRCLIST    12 /* a pointer to a SrcList */
    ++#define etPOINTER    13 /* The %p conversion */
    ++#define etSQLESCAPE3 14 /* %w -> Strings with '\"' doubled */
    ++#define etORDINAL    15 /* %r -> 1st, 2nd, 3rd, 4th, etc.  English only */
    ++#define etDECIMAL    16 /* %d or %u, but not %x, %o */
    + 
    +-#define etINVALID     0 /* Any unrecognized conversion type */
    ++#define etINVALID    17 /* Any unrecognized conversion type */
    + 
    + 
    + /*
    +@@ -22172,9 +25917,8 @@ typedef struct et_info {   /* Information about each format field */
    + /*
    + ** Allowed values for et_info.flags
    + */
    +-#define FLAG_SIGNED  1     /* True if the value to convert is signed */
    +-#define FLAG_INTERN  2     /* True if for internal use only */
    +-#define FLAG_STRING  4     /* Allow infinity precision */
    ++#define FLAG_SIGNED    1     /* True if the value to convert is signed */
    ++#define FLAG_STRING    4     /* Allow infinite precision */
    + 
    + 
    + /*
    +@@ -22184,7 +25928,7 @@ typedef struct et_info {   /* Information about each format field */
    + static const char aDigits[] = "0123456789ABCDEF0123456789abcdef";
    + static const char aPrefix[] = "-x0\000X0";
    + static const et_info fmtinfo[] = {
    +-  {  'd', 10, 1, etRADIX,      0,  0 },
    ++  {  'd', 10, 1, etDECIMAL,    0,  0 },
    +   {  's',  0, 4, etSTRING,     0,  0 },
    +   {  'g',  0, 1, etGENERIC,    30, 0 },
    +   {  'z',  0, 4, etDYNSTRING,  0,  0 },
    +@@ -22193,7 +25937,7 @@ static const et_info fmtinfo[] = {
    +   {  'w',  0, 4, etSQLESCAPE3, 0,  0 },
    +   {  'c',  0, 0, etCHARX,      0,  0 },
    +   {  'o',  8, 0, etRADIX,      0,  2 },
    +-  {  'u', 10, 0, etRADIX,      0,  0 },
    ++  {  'u', 10, 0, etDECIMAL,    0,  0 },
    +   {  'x', 16, 0, etRADIX,      16, 1 },
    +   {  'X', 16, 0, etRADIX,      0,  4 },
    + #ifndef SQLITE_OMIT_FLOATING_POINT
    +@@ -22202,16 +25946,15 @@ static const et_info fmtinfo[] = {
    +   {  'E',  0, 1, etEXP,        14, 0 },
    +   {  'G',  0, 1, etGENERIC,    14, 0 },
    + #endif
    +-  {  'i', 10, 1, etRADIX,      0,  0 },
    ++  {  'i', 10, 1, etDECIMAL,    0,  0 },
    +   {  'n',  0, 0, etSIZE,       0,  0 },
    +   {  '%',  0, 0, etPERCENT,    0,  0 },
    +   {  'p', 16, 0, etPOINTER,    0,  1 },
    + 
    +-/* All the rest have the FLAG_INTERN bit set and are thus for internal
    +-** use only */
    +-  {  'T',  0, 2, etTOKEN,      0,  0 },
    +-  {  'S',  0, 2, etSRCLIST,    0,  0 },
    +-  {  'r', 10, 3, etORDINAL,    0,  0 },
    ++  /* All the rest are undocumented and are for internal use only */
    ++  {  'T',  0, 0, etTOKEN,      0,  0 },
    ++  {  'S',  0, 0, etSRCLIST,    0,  0 },
    ++  {  'r', 10, 1, etORDINAL,    0,  0 },
    + };
    + 
    + /*
    +@@ -22285,7 +26028,6 @@ static char *getTextArg(PrintfArguments *p){
    + */
    + SQLITE_PRIVATE void sqlite3VXPrintf(
    +   StrAccum *pAccum,          /* Accumulate results here */
    +-  u32 bFlags,                /* SQLITE_PRINTF_* flags */
    +   const char *fmt,           /* Format string */
    +   va_list ap                 /* arguments */
    + ){
    +@@ -22296,17 +26038,15 @@ SQLITE_PRIVATE void sqlite3VXPrintf(
    +   int idx;                   /* A general purpose loop counter */
    +   int width;                 /* Width of the current field */
    +   etByte flag_leftjustify;   /* True if "-" flag is present */
    +-  etByte flag_plussign;      /* True if "+" flag is present */
    +-  etByte flag_blanksign;     /* True if " " flag is present */
    ++  etByte flag_prefix;        /* '+' or ' ' or 0 for prefix */
    +   etByte flag_alternateform; /* True if "#" flag is present */
    +   etByte flag_altform2;      /* True if "!" flag is present */
    +   etByte flag_zeropad;       /* True if field width constant starts with zero */
    +-  etByte flag_long;          /* True if "l" flag is present */
    +-  etByte flag_longlong;      /* True if the "ll" flag is present */
    ++  etByte flag_long;          /* 1 for the "l" flag, 2 for "ll", 0 by default */
    +   etByte done;               /* Loop termination flag */
    +-  etByte xtype = 0;          /* Conversion paradigm */
    ++  etByte cThousand;          /* Thousands separator for %d and %u */
    ++  etByte xtype = etINVALID;  /* Conversion paradigm */
    +   u8 bArgList;               /* True for SQLITE_PRINTF_SQLFUNC */
    +-  u8 useIntern;              /* Ok to use internal conversions (ex: %T) */
    +   char prefix;               /* Prefix character.  "+" or "-" or " " or '\0'. */
    +   sqlite_uint64 longvalue;   /* Value for integer types */
    +   LONGDOUBLE_TYPE realvalue; /* Value for real types */
    +@@ -22325,13 +26065,11 @@ SQLITE_PRIVATE void sqlite3VXPrintf(
    +   char buf[etBUFSIZE];       /* Conversion buffer */
    + 
    +   bufpt = 0;
    +-  if( bFlags ){
    +-    if( (bArgList = (bFlags & SQLITE_PRINTF_SQLFUNC))!=0 ){
    +-      pArgList = va_arg(ap, PrintfArguments*);
    +-    }
    +-    useIntern = bFlags & SQLITE_PRINTF_INTERNAL;
    ++  if( (pAccum->printfFlags & SQLITE_PRINTF_SQLFUNC)!=0 ){
    ++    pArgList = va_arg(ap, PrintfArguments*);
    ++    bArgList = 1;
    +   }else{
    +-    bArgList = useIntern = 0;
    ++    bArgList = 0;
    +   }
    +   for(; (c=(*fmt))!=0; ++fmt){
    +     if( c!='%' ){
    +@@ -22349,17 +26087,18 @@ SQLITE_PRIVATE void sqlite3VXPrintf(
    +       break;
    +     }
    +     /* Find out what flags are present */
    +-    flag_leftjustify = flag_plussign = flag_blanksign = 
    ++    flag_leftjustify = flag_prefix = cThousand =
    +      flag_alternateform = flag_altform2 = flag_zeropad = 0;
    +     done = 0;
    +     do{
    +       switch( c ){
    +         case '-':   flag_leftjustify = 1;     break;
    +-        case '+':   flag_plussign = 1;        break;
    +-        case ' ':   flag_blanksign = 1;       break;
    ++        case '+':   flag_prefix = '+';        break;
    ++        case ' ':   flag_prefix = ' ';        break;
    +         case '#':   flag_alternateform = 1;   break;
    +         case '!':   flag_altform2 = 1;        break;
    +         case '0':   flag_zeropad = 1;         break;
    ++        case ',':   cThousand = ',';          break;
    +         default:    done = 1;                 break;
    +       }
    +     }while( !done && (c=(*++fmt))!=0 );
    +@@ -22384,6 +26123,12 @@ SQLITE_PRIVATE void sqlite3VXPrintf(
    +       testcase( wx>0x7fffffff );
    +       width = wx & 0x7fffffff;
    +     }
    ++    assert( width>=0 );
    ++#ifdef SQLITE_PRINTF_PRECISION_LIMIT
    ++    if( width>SQLITE_PRINTF_PRECISION_LIMIT ){
    ++      width = SQLITE_PRINTF_PRECISION_LIMIT;
    ++    }
    ++#endif
    + 
    +     /* Get the precision */
    +     if( c=='.' ){
    +@@ -22410,18 +26155,24 @@ SQLITE_PRIVATE void sqlite3VXPrintf(
    +     }else{
    +       precision = -1;
    +     }
    ++    assert( precision>=(-1) );
    ++#ifdef SQLITE_PRINTF_PRECISION_LIMIT
    ++    if( precision>SQLITE_PRINTF_PRECISION_LIMIT ){
    ++      precision = SQLITE_PRINTF_PRECISION_LIMIT;
    ++    }
    ++#endif
    ++
    ++
    +     /* Get the conversion type modifier */
    +     if( c=='l' ){
    +       flag_long = 1;
    +       c = *++fmt;
    +       if( c=='l' ){
    +-        flag_longlong = 1;
    ++        flag_long = 2;
    +         c = *++fmt;
    +-      }else{
    +-        flag_longlong = 0;
    +       }
    +     }else{
    +-      flag_long = flag_longlong = 0;
    ++      flag_long = 0;
    +     }
    +     /* Fetch the info entry for the field */
    +     infop = &fmtinfo[0];
    +@@ -22429,11 +26180,7 @@ SQLITE_PRIVATE void sqlite3VXPrintf(
    +     for(idx=0; idx<ArraySize(fmtinfo); idx++){
    +       if( c==fmtinfo[idx].fmttype ){
    +         infop = &fmtinfo[idx];
    +-        if( useIntern || (infop->flags & FLAG_INTERN)==0 ){
    +-          xtype = infop->type;
    +-        }else{
    +-          return;
    +-        }
    ++        xtype = infop->type;
    +         break;
    +       }
    +     }
    +@@ -22443,15 +26190,11 @@ SQLITE_PRIVATE void sqlite3VXPrintf(
    +     **
    +     **   flag_alternateform          TRUE if a '#' is present.
    +     **   flag_altform2               TRUE if a '!' is present.
    +-    **   flag_plussign               TRUE if a '+' is present.
    ++    **   flag_prefix                 '+' or ' ' or zero
    +     **   flag_leftjustify            TRUE if a '-' is present or if the
    +     **                               field width was negative.
    +     **   flag_zeropad                TRUE if the width began with 0.
    +-    **   flag_long                   TRUE if the letter 'l' (ell) prefixed
    +-    **                               the conversion character.
    +-    **   flag_longlong               TRUE if the letter 'll' (ell ell) prefixed
    +-    **                               the conversion character.
    +-    **   flag_blanksign              TRUE if a ' ' is present.
    ++    **   flag_long                   1 for "l", 2 for "ll"
    +     **   width                       The specified field width.  This is
    +     **                               always non-negative.  Zero is the default.
    +     **   precision                   The specified precision.  The default
    +@@ -22461,19 +26204,24 @@ SQLITE_PRIVATE void sqlite3VXPrintf(
    +     */
    +     switch( xtype ){
    +       case etPOINTER:
    +-        flag_longlong = sizeof(char*)==sizeof(i64);
    +-        flag_long = sizeof(char*)==sizeof(long int);
    ++        flag_long = sizeof(char*)==sizeof(i64) ? 2 :
    ++                     sizeof(char*)==sizeof(long int) ? 1 : 0;
    +         /* Fall through into the next case */
    +       case etORDINAL:
    +-      case etRADIX:
    ++      case etRADIX:      
    ++        cThousand = 0;
    ++        /* Fall through into the next case */
    ++      case etDECIMAL:
    +         if( infop->flags & FLAG_SIGNED ){
    +           i64 v;
    +           if( bArgList ){
    +             v = getIntArg(pArgList);
    +-          }else if( flag_longlong ){
    +-            v = va_arg(ap,i64);
    +           }else if( flag_long ){
    +-            v = va_arg(ap,long int);
    ++            if( flag_long==2 ){
    ++              v = va_arg(ap,i64) ;
    ++            }else{
    ++              v = va_arg(ap,long int);
    ++            }
    +           }else{
    +             v = va_arg(ap,int);
    +           }
    +@@ -22486,17 +26234,17 @@ SQLITE_PRIVATE void sqlite3VXPrintf(
    +             prefix = '-';
    +           }else{
    +             longvalue = v;
    +-            if( flag_plussign )        prefix = '+';
    +-            else if( flag_blanksign )  prefix = ' ';
    +-            else                       prefix = 0;
    ++            prefix = flag_prefix;
    +           }
    +         }else{
    +           if( bArgList ){
    +             longvalue = (u64)getIntArg(pArgList);
    +-          }else if( flag_longlong ){
    +-            longvalue = va_arg(ap,u64);
    +           }else if( flag_long ){
    +-            longvalue = va_arg(ap,unsigned long int);
    ++            if( flag_long==2 ){
    ++              longvalue = va_arg(ap,u64);
    ++            }else{
    ++              longvalue = va_arg(ap,unsigned long int);
    ++            }
    +           }else{
    +             longvalue = va_arg(ap,unsigned int);
    +           }
    +@@ -22506,16 +26254,17 @@ SQLITE_PRIVATE void sqlite3VXPrintf(
    +         if( flag_zeropad && precision<width-(prefix!=0) ){
    +           precision = width-(prefix!=0);
    +         }
    +-        if( precision<etBUFSIZE-10 ){
    ++        if( precision<etBUFSIZE-10-etBUFSIZE/3 ){
    +           nOut = etBUFSIZE;
    +           zOut = buf;
    +         }else{
    +-          nOut = precision + 10;
    +-          zOut = zExtra = sqlite3Malloc( nOut );
    ++          u64 n = (u64)precision + 10 + precision/3;
    ++          zOut = zExtra = sqlite3Malloc( n );
    +           if( zOut==0 ){
    +             setStrAccumError(pAccum, STRACCUM_NOMEM);
    +             return;
    +           }
    ++          nOut = (int)n;
    +         }
    +         bufpt = &zOut[nOut-1];
    +         if( xtype==etORDINAL ){
    +@@ -22536,8 +26285,23 @@ SQLITE_PRIVATE void sqlite3VXPrintf(
    +           }while( longvalue>0 );
    +         }
    +         length = (int)(&zOut[nOut-1]-bufpt);
    +-        for(idx=precision-length; idx>0; idx--){
    ++        while( precision>length ){
    +           *(--bufpt) = '0';                             /* Zero pad */
    ++          length++;
    ++        }
    ++        if( cThousand ){
    ++          int nn = (length - 1)/3;  /* Number of "," to insert */
    ++          int ix = (length - 1)%3 + 1;
    ++          bufpt -= nn;
    ++          for(idx=0; nn>0; idx++){
    ++            bufpt[idx] = bufpt[idx+nn];
    ++            ix--;
    ++            if( ix==0 ){
    ++              bufpt[++idx] = cThousand;
    ++              nn--;
    ++              ix = 3;
    ++            }
    ++          }
    +         }
    +         if( prefix ) *(--bufpt) = prefix;               /* Add sign */
    +         if( flag_alternateform && infop->prefix ){      /* Add "0" or "0x" */
    +@@ -22564,9 +26328,7 @@ SQLITE_PRIVATE void sqlite3VXPrintf(
    +           realvalue = -realvalue;
    +           prefix = '-';
    +         }else{
    +-          if( flag_plussign )          prefix = '+';
    +-          else if( flag_blanksign )    prefix = ' ';
    +-          else                         prefix = 0;
    ++          prefix = flag_prefix;
    +         }
    +         if( xtype==etGENERIC && precision>0 ) precision--;
    +         testcase( precision>0xfff );
    +@@ -22752,7 +26514,7 @@ SQLITE_PRIVATE void sqlite3VXPrintf(
    +         if( precision>=0 ){
    +           for(length=0; length<precision && bufpt[length]; length++){}
    +         }else{
    +-          length = sqlite3Strlen30(bufpt);
    ++          length = 0x7fffffff & (int)strlen(bufpt);
    +         }
    +         break;
    +       case etSQLESCAPE:           /* Escape ' characters */
    +@@ -22802,7 +26564,9 @@ SQLITE_PRIVATE void sqlite3VXPrintf(
    +         break;
    +       }
    +       case etTOKEN: {
    +-        Token *pToken = va_arg(ap, Token*);
    ++        Token *pToken;
    ++        if( (pAccum->printfFlags & SQLITE_PRINTF_INTERNAL)==0 ) return;
    ++        pToken = va_arg(ap, Token*);
    +         assert( bArgList==0 );
    +         if( pToken && pToken->n ){
    +           sqlite3StrAccumAppend(pAccum, (const char*)pToken->z, pToken->n);
    +@@ -22811,9 +26575,13 @@ SQLITE_PRIVATE void sqlite3VXPrintf(
    +         break;
    +       }
    +       case etSRCLIST: {
    +-        SrcList *pSrc = va_arg(ap, SrcList*);
    +-        int k = va_arg(ap, int);
    +-        struct SrcList_item *pItem = &pSrc->a[k];
    ++        SrcList *pSrc;
    ++        int k;
    ++        struct SrcList_item *pItem;
    ++        if( (pAccum->printfFlags & SQLITE_PRINTF_INTERNAL)==0 ) return;
    ++        pSrc = va_arg(ap, SrcList*);
    ++        k = va_arg(ap, int);
    ++        pItem = &pSrc->a[k];
    +         assert( bArgList==0 );
    +         assert( k>=0 && k<pSrc->nSrc );
    +         if( pItem->zDatabase ){
    +@@ -22835,12 +26603,16 @@ SQLITE_PRIVATE void sqlite3VXPrintf(
    +     ** the output.
    +     */
    +     width -= length;
    +-    if( width>0 && !flag_leftjustify ) sqlite3AppendChar(pAccum, width, ' ');
    +-    sqlite3StrAccumAppend(pAccum, bufpt, length);
    +-    if( width>0 && flag_leftjustify ) sqlite3AppendChar(pAccum, width, ' ');
    ++    if( width>0 ){
    ++      if( !flag_leftjustify ) sqlite3AppendChar(pAccum, width, ' ');
    ++      sqlite3StrAccumAppend(pAccum, bufpt, length);
    ++      if( flag_leftjustify ) sqlite3AppendChar(pAccum, width, ' ');
    ++    }else{
    ++      sqlite3StrAccumAppend(pAccum, bufpt, length);
    ++    }
    + 
    +     if( zExtra ){
    +-      sqlite3_free(zExtra);
    ++      sqlite3DbFree(pAccum->db, zExtra);
    +       zExtra = 0;
    +     }
    +   }/* End for loop over the format string */
    +@@ -22866,7 +26638,7 @@ static int sqlite3StrAccumEnlarge(StrAccum *p, int N){
    +     setStrAccumError(p, STRACCUM_TOOBIG);
    +     return N;
    +   }else{
    +-    char *zOld = (p->zText==p->zBase ? 0 : p->zText);
    ++    char *zOld = isMalloced(p) ? p->zText : 0;
    +     i64 szNew = p->nChar;
    +     szNew += N + 1;
    +     if( szNew+p->nChar<=p->mxAlloc ){
    +@@ -22888,9 +26660,10 @@ static int sqlite3StrAccumEnlarge(StrAccum *p, int N){
    +     }
    +     if( zNew ){
    +       assert( p->zText!=0 || p->nChar==0 );
    +-      if( zOld==0 && p->nChar>0 ) memcpy(zNew, p->zText, p->nChar);
    ++      if( !isMalloced(p) && p->nChar>0 ) memcpy(zNew, p->zText, p->nChar);
    +       p->zText = zNew;
    +       p->nAlloc = sqlite3DbMallocSize(p->db, zNew);
    ++      p->printfFlags |= SQLITE_PRINTF_MALLOCED;
    +     }else{
    +       sqlite3StrAccumReset(p);
    +       setStrAccumError(p, STRACCUM_NOMEM);
    +@@ -22938,7 +26711,7 @@ SQLITE_PRIVATE void sqlite3StrAccumAppend(StrAccum *p, const char *z, int N){
    +   assert( p->accError==0 || p->nAlloc==0 );
    +   if( p->nChar+N >= p->nAlloc ){
    +     enlargeAndAppend(p,z,N);
    +-  }else{
    ++  }else if( N ){
    +     assert( p->zText );
    +     p->nChar += N;
    +     memcpy(&p->zText[p->nChar-N], z, N);
    +@@ -22958,16 +26731,24 @@ SQLITE_PRIVATE void sqlite3StrAccumAppendAll(StrAccum *p, const char *z){
    + ** Return a pointer to the resulting string.  Return a NULL
    + ** pointer if any kind of error was encountered.
    + */
    ++static SQLITE_NOINLINE char *strAccumFinishRealloc(StrAccum *p){
    ++  char *zText;
    ++  assert( p->mxAlloc>0 && !isMalloced(p) );
    ++  zText = sqlite3DbMallocRaw(p->db, p->nChar+1 );
    ++  if( zText ){
    ++    memcpy(zText, p->zText, p->nChar+1);
    ++    p->printfFlags |= SQLITE_PRINTF_MALLOCED;
    ++  }else{
    ++    setStrAccumError(p, STRACCUM_NOMEM);
    ++  }
    ++  p->zText = zText;
    ++  return zText;
    ++}
    + SQLITE_PRIVATE char *sqlite3StrAccumFinish(StrAccum *p){
    +   if( p->zText ){
    +     p->zText[p->nChar] = 0;
    +-    if( p->mxAlloc>0 && p->zText==p->zBase ){
    +-      p->zText = sqlite3DbMallocRaw(p->db, p->nChar+1 );
    +-      if( p->zText ){
    +-        memcpy(p->zText, p->zBase, p->nChar+1);
    +-      }else{
    +-        setStrAccumError(p, STRACCUM_NOMEM);
    +-      }
    ++    if( p->mxAlloc>0 && !isMalloced(p) ){
    ++      return strAccumFinishRealloc(p);
    +     }
    +   }
    +   return p->zText;
    +@@ -22977,8 +26758,9 @@ SQLITE_PRIVATE char *sqlite3StrAccumFinish(StrAccum *p){
    + ** Reset an StrAccum string.  Reclaim all malloced memory.
    + */
    + SQLITE_PRIVATE void sqlite3StrAccumReset(StrAccum *p){
    +-  if( p->zText!=p->zBase ){
    ++  if( isMalloced(p) ){
    +     sqlite3DbFree(p->db, p->zText);
    ++    p->printfFlags &= ~SQLITE_PRINTF_MALLOCED;
    +   }
    +   p->zText = 0;
    + }
    +@@ -22998,12 +26780,13 @@ SQLITE_PRIVATE void sqlite3StrAccumReset(StrAccum *p){
    + **        allocations will ever occur.
    + */
    + SQLITE_PRIVATE void sqlite3StrAccumInit(StrAccum *p, sqlite3 *db, char *zBase, int n, int mx){
    +-  p->zText = p->zBase = zBase;
    ++  p->zText = zBase;
    +   p->db = db;
    +-  p->nChar = 0;
    +   p->nAlloc = n;
    +   p->mxAlloc = mx;
    ++  p->nChar = 0;
    +   p->accError = 0;
    ++  p->printfFlags = 0;
    + }
    + 
    + /*
    +@@ -23017,10 +26800,11 @@ SQLITE_PRIVATE char *sqlite3VMPrintf(sqlite3 *db, const char *zFormat, va_list a
    +   assert( db!=0 );
    +   sqlite3StrAccumInit(&acc, db, zBase, sizeof(zBase),
    +                       db->aLimit[SQLITE_LIMIT_LENGTH]);
    +-  sqlite3VXPrintf(&acc, SQLITE_PRINTF_INTERNAL, zFormat, ap);
    ++  acc.printfFlags = SQLITE_PRINTF_INTERNAL;
    ++  sqlite3VXPrintf(&acc, zFormat, ap);
    +   z = sqlite3StrAccumFinish(&acc);
    +   if( acc.accError==STRACCUM_NOMEM ){
    +-    db->mallocFailed = 1;
    ++    sqlite3OomFault(db);
    +   }
    +   return z;
    + }
    +@@ -23042,7 +26826,7 @@ SQLITE_PRIVATE char *sqlite3MPrintf(sqlite3 *db, const char *zFormat, ...){
    + ** Print into memory obtained from sqlite3_malloc().  Omit the internal
    + ** %-conversion extensions.
    + */
    +-SQLITE_API char *SQLITE_STDCALL sqlite3_vmprintf(const char *zFormat, va_list ap){
    ++SQLITE_API char *sqlite3_vmprintf(const char *zFormat, va_list ap){
    +   char *z;
    +   char zBase[SQLITE_PRINT_BUF_SIZE];
    +   StrAccum acc;
    +@@ -23057,7 +26841,7 @@ SQLITE_API char *SQLITE_STDCALL sqlite3_vmprintf(const char *zFormat, va_list ap
    +   if( sqlite3_initialize() ) return 0;
    + #endif
    +   sqlite3StrAccumInit(&acc, 0, zBase, sizeof(zBase), SQLITE_MAX_LENGTH);
    +-  sqlite3VXPrintf(&acc, 0, zFormat, ap);
    ++  sqlite3VXPrintf(&acc, zFormat, ap);
    +   z = sqlite3StrAccumFinish(&acc);
    +   return z;
    + }
    +@@ -23066,7 +26850,7 @@ SQLITE_API char *SQLITE_STDCALL sqlite3_vmprintf(const char *zFormat, va_list ap
    + ** Print into memory obtained from sqlite3_malloc()().  Omit the internal
    + ** %-conversion extensions.
    + */
    +-SQLITE_API char *SQLITE_CDECL sqlite3_mprintf(const char *zFormat, ...){
    ++SQLITE_API char *sqlite3_mprintf(const char *zFormat, ...){
    +   va_list ap;
    +   char *z;
    + #ifndef SQLITE_OMIT_AUTOINIT
    +@@ -23091,7 +26875,7 @@ SQLITE_API char *SQLITE_CDECL sqlite3_mprintf(const char *zFormat, ...){
    + **
    + ** sqlite3_vsnprintf() is the varargs version.
    + */
    +-SQLITE_API char *SQLITE_STDCALL sqlite3_vsnprintf(int n, char *zBuf, const char *zFormat, va_list ap){
    ++SQLITE_API char *sqlite3_vsnprintf(int n, char *zBuf, const char *zFormat, va_list ap){
    +   StrAccum acc;
    +   if( n<=0 ) return zBuf;
    + #ifdef SQLITE_ENABLE_API_ARMOR
    +@@ -23102,10 +26886,11 @@ SQLITE_API char *SQLITE_STDCALL sqlite3_vsnprintf(int n, char *zBuf, const char
    +   }
    + #endif
    +   sqlite3StrAccumInit(&acc, 0, zBuf, n, 0);
    +-  sqlite3VXPrintf(&acc, 0, zFormat, ap);
    +-  return sqlite3StrAccumFinish(&acc);
    ++  sqlite3VXPrintf(&acc, zFormat, ap);
    ++  zBuf[acc.nChar] = 0;
    ++  return zBuf;
    + }
    +-SQLITE_API char *SQLITE_CDECL sqlite3_snprintf(int n, char *zBuf, const char *zFormat, ...){
    ++SQLITE_API char *sqlite3_snprintf(int n, char *zBuf, const char *zFormat, ...){
    +   char *z;
    +   va_list ap;
    +   va_start(ap,zFormat);
    +@@ -23133,7 +26918,7 @@ static void renderLogMsg(int iErrCode, const char *zFormat, va_list ap){
    +   char zMsg[SQLITE_PRINT_BUF_SIZE*3];    /* Complete log message */
    + 
    +   sqlite3StrAccumInit(&acc, 0, zMsg, sizeof(zMsg), 0);
    +-  sqlite3VXPrintf(&acc, 0, zFormat, ap);
    ++  sqlite3VXPrintf(&acc, zFormat, ap);
    +   sqlite3GlobalConfig.xLog(sqlite3GlobalConfig.pLogArg, iErrCode,
    +                            sqlite3StrAccumFinish(&acc));
    + }
    +@@ -23141,7 +26926,7 @@ static void renderLogMsg(int iErrCode, const char *zFormat, va_list ap){
    + /*
    + ** Format and write a message to the log if logging is enabled.
    + */
    +-SQLITE_API void SQLITE_CDECL sqlite3_log(int iErrCode, const char *zFormat, ...){
    ++SQLITE_API void sqlite3_log(int iErrCode, const char *zFormat, ...){
    +   va_list ap;                             /* Vararg list */
    +   if( sqlite3GlobalConfig.xLog ){
    +     va_start(ap, zFormat);
    +@@ -23162,11 +26947,18 @@ SQLITE_PRIVATE void sqlite3DebugPrintf(const char *zFormat, ...){
    +   char zBuf[500];
    +   sqlite3StrAccumInit(&acc, 0, zBuf, sizeof(zBuf), 0);
    +   va_start(ap,zFormat);
    +-  sqlite3VXPrintf(&acc, 0, zFormat, ap);
    ++  sqlite3VXPrintf(&acc, zFormat, ap);
    +   va_end(ap);
    +   sqlite3StrAccumFinish(&acc);
    ++#ifdef SQLITE_OS_TRACE_PROC
    ++  {
    ++    extern void SQLITE_OS_TRACE_PROC(const char *zBuf, int nBuf);
    ++    SQLITE_OS_TRACE_PROC(zBuf, sizeof(zBuf));
    ++  }
    ++#else
    +   fprintf(stdout,"%s", zBuf);
    +   fflush(stdout);
    ++#endif
    + }
    + #endif
    + 
    +@@ -23175,10 +26967,10 @@ SQLITE_PRIVATE void sqlite3DebugPrintf(const char *zFormat, ...){
    + ** variable-argument wrapper around sqlite3VXPrintf().  The bFlags argument
    + ** can contain the bit SQLITE_PRINTF_INTERNAL enable internal formats.
    + */
    +-SQLITE_PRIVATE void sqlite3XPrintf(StrAccum *p, u32 bFlags, const char *zFormat, ...){
    ++SQLITE_PRIVATE void sqlite3XPrintf(StrAccum *p, const char *zFormat, ...){
    +   va_list ap;
    +   va_start(ap,zFormat);
    +-  sqlite3VXPrintf(p, bFlags, zFormat, ap);
    ++  sqlite3VXPrintf(p, zFormat, ap);
    +   va_end(ap);
    + }
    + 
    +@@ -23249,8 +27041,9 @@ static void sqlite3TreeViewLine(TreeView *p, const char *zFormat, ...){
    +     sqlite3StrAccumAppend(&acc, p->bLine[i] ? "|-- " : "'-- ", 4);
    +   }
    +   va_start(ap, zFormat);
    +-  sqlite3VXPrintf(&acc, 0, zFormat, ap);
    ++  sqlite3VXPrintf(&acc, zFormat, ap);
    +   va_end(ap);
    ++  assert( acc.nChar>0 );
    +   if( zBuf[acc.nChar-1]!='\n' ) sqlite3StrAccumAppend(&acc, "\n", 1);
    +   sqlite3StrAccumFinish(&acc);
    +   fprintf(stdout,"%s", zBuf);
    +@@ -23265,18 +27058,67 @@ static void sqlite3TreeViewItem(TreeView *p, const char *zLabel,u8 moreFollows){
    +   sqlite3TreeViewLine(p, "%s", zLabel);
    + }
    + 
    ++/*
    ++** Generate a human-readable description of a WITH clause.
    ++*/
    ++SQLITE_PRIVATE void sqlite3TreeViewWith(TreeView *pView, const With *pWith, u8 moreToFollow){
    ++  int i;
    ++  if( pWith==0 ) return;
    ++  if( pWith->nCte==0 ) return;
    ++  if( pWith->pOuter ){
    ++    sqlite3TreeViewLine(pView, "WITH (0x%p, pOuter=0x%p)",pWith,pWith->pOuter);
    ++  }else{
    ++    sqlite3TreeViewLine(pView, "WITH (0x%p)", pWith);
    ++  }
    ++  if( pWith->nCte>0 ){
    ++    pView = sqlite3TreeViewPush(pView, 1);
    ++    for(i=0; i<pWith->nCte; i++){
    ++      StrAccum x;
    ++      char zLine[1000];
    ++      const struct Cte *pCte = &pWith->a[i];
    ++      sqlite3StrAccumInit(&x, 0, zLine, sizeof(zLine), 0);
    ++      sqlite3XPrintf(&x, "%s", pCte->zName);
    ++      if( pCte->pCols && pCte->pCols->nExpr>0 ){
    ++        char cSep = '(';
    ++        int j;
    ++        for(j=0; j<pCte->pCols->nExpr; j++){
    ++          sqlite3XPrintf(&x, "%c%s", cSep, pCte->pCols->a[j].zName);
    ++          cSep = ',';
    ++        }
    ++        sqlite3XPrintf(&x, ")");
    ++      }
    ++      sqlite3XPrintf(&x, " AS");
    ++      sqlite3StrAccumFinish(&x);
    ++      sqlite3TreeViewItem(pView, zLine, i<pWith->nCte-1);
    ++      sqlite3TreeViewSelect(pView, pCte->pSelect, 0);
    ++      sqlite3TreeViewPop(pView);
    ++    }
    ++    sqlite3TreeViewPop(pView);
    ++  }
    ++}
    ++
    + 
    + /*
    +-** Generate a human-readable description of a the Select object.
    ++** Generate a human-readable description of a Select object.
    + */
    + SQLITE_PRIVATE void sqlite3TreeViewSelect(TreeView *pView, const Select *p, u8 moreToFollow){
    +   int n = 0;
    +   int cnt = 0;
    ++  if( p==0 ){
    ++    sqlite3TreeViewLine(pView, "nil-SELECT");
    ++    return;
    ++  } 
    +   pView = sqlite3TreeViewPush(pView, moreToFollow);
    ++  if( p->pWith ){
    ++    sqlite3TreeViewWith(pView, p->pWith, 1);
    ++    cnt = 1;
    ++    sqlite3TreeViewPush(pView, 1);
    ++  }
    +   do{
    +-    sqlite3TreeViewLine(pView, "SELECT%s%s (0x%p) selFlags=0x%x",
    ++    sqlite3TreeViewLine(pView, "SELECT%s%s (0x%p) selFlags=0x%x nSelectRow=%d",
    +       ((p->selFlags & SF_Distinct) ? " DISTINCT" : ""),
    +-      ((p->selFlags & SF_Aggregate) ? " agg_flag" : ""), p, p->selFlags
    ++      ((p->selFlags & SF_Aggregate) ? " agg_flag" : ""), p, p->selFlags,
    ++      (int)p->nSelectRow
    +     );
    +     if( cnt++ ) sqlite3TreeViewPop(pView);
    +     if( p->pPrior ){
    +@@ -23289,7 +27131,6 @@ SQLITE_PRIVATE void sqlite3TreeViewSelect(TreeView *pView, const Select *p, u8 m
    +       if( p->pHaving ) n++;
    +       if( p->pOrderBy ) n++;
    +       if( p->pLimit ) n++;
    +-      if( p->pOffset ) n++;
    +     }
    +     sqlite3TreeViewExprList(pView, p->pEList, (n--)>0, "result-set");
    +     if( p->pSrc && p->pSrc->nSrc ){
    +@@ -23301,20 +27142,20 @@ SQLITE_PRIVATE void sqlite3TreeViewSelect(TreeView *pView, const Select *p, u8 m
    +         StrAccum x;
    +         char zLine[100];
    +         sqlite3StrAccumInit(&x, 0, zLine, sizeof(zLine), 0);
    +-        sqlite3XPrintf(&x, 0, "{%d,*}", pItem->iCursor);
    ++        sqlite3XPrintf(&x, "{%d,*}", pItem->iCursor);
    +         if( pItem->zDatabase ){
    +-          sqlite3XPrintf(&x, 0, " %s.%s", pItem->zDatabase, pItem->zName);
    ++          sqlite3XPrintf(&x, " %s.%s", pItem->zDatabase, pItem->zName);
    +         }else if( pItem->zName ){
    +-          sqlite3XPrintf(&x, 0, " %s", pItem->zName);
    ++          sqlite3XPrintf(&x, " %s", pItem->zName);
    +         }
    +         if( pItem->pTab ){
    +-          sqlite3XPrintf(&x, 0, " tabname=%Q", pItem->pTab->zName);
    ++          sqlite3XPrintf(&x, " tabname=%Q", pItem->pTab->zName);
    +         }
    +         if( pItem->zAlias ){
    +-          sqlite3XPrintf(&x, 0, " (AS %s)", pItem->zAlias);
    ++          sqlite3XPrintf(&x, " (AS %s)", pItem->zAlias);
    +         }
    +         if( pItem->fg.jointype & JT_LEFT ){
    +-          sqlite3XPrintf(&x, 0, " LEFT-JOIN");
    ++          sqlite3XPrintf(&x, " LEFT-JOIN");
    +         }
    +         sqlite3StrAccumFinish(&x);
    +         sqlite3TreeViewItem(pView, zLine, i<p->pSrc->nSrc-1); 
    +@@ -23346,12 +27187,12 @@ SQLITE_PRIVATE void sqlite3TreeViewSelect(TreeView *pView, const Select *p, u8 m
    +     }
    +     if( p->pLimit ){
    +       sqlite3TreeViewItem(pView, "LIMIT", (n--)>0);
    +-      sqlite3TreeViewExpr(pView, p->pLimit, 0);
    +-      sqlite3TreeViewPop(pView);
    +-    }
    +-    if( p->pOffset ){
    +-      sqlite3TreeViewItem(pView, "OFFSET", (n--)>0);
    +-      sqlite3TreeViewExpr(pView, p->pOffset, 0);
    ++      sqlite3TreeViewExpr(pView, p->pLimit->pLeft, p->pLimit->pRight!=0);
    ++      if( p->pLimit->pRight ){
    ++        sqlite3TreeViewItem(pView, "OFFSET", (n--)>0);
    ++        sqlite3TreeViewExpr(pView, p->pLimit->pRight, 0);
    ++        sqlite3TreeViewPop(pView);
    ++      }
    +       sqlite3TreeViewPop(pView);
    +     }
    +     if( p->pPrior ){
    +@@ -23374,7 +27215,7 @@ SQLITE_PRIVATE void sqlite3TreeViewSelect(TreeView *pView, const Select *p, u8 m
    + SQLITE_PRIVATE void sqlite3TreeViewExpr(TreeView *pView, const Expr *pExpr, u8 moreToFollow){
    +   const char *zBinOp = 0;   /* Binary operator */
    +   const char *zUniOp = 0;   /* Unary operator */
    +-  char zFlgs[30];
    ++  char zFlgs[60];
    +   pView = sqlite3TreeViewPush(pView, moreToFollow);
    +   if( pExpr==0 ){
    +     sqlite3TreeViewLine(pView, "nil");
    +@@ -23382,7 +27223,12 @@ SQLITE_PRIVATE void sqlite3TreeViewExpr(TreeView *pView, const Expr *pExpr, u8 m
    +     return;
    +   }
    +   if( pExpr->flags ){
    +-    sqlite3_snprintf(sizeof(zFlgs),zFlgs,"  flags=0x%x",pExpr->flags);
    ++    if( ExprHasProperty(pExpr, EP_FromJoin) ){
    ++      sqlite3_snprintf(sizeof(zFlgs),zFlgs,"  flags=0x%x iRJT=%d",
    ++                       pExpr->flags, pExpr->iRightJoinTable);
    ++    }else{
    ++      sqlite3_snprintf(sizeof(zFlgs),zFlgs,"  flags=0x%x",pExpr->flags);
    ++    }
    +   }else{
    +     zFlgs[0] = 0;
    +   }
    +@@ -23480,6 +27326,12 @@ SQLITE_PRIVATE void sqlite3TreeViewExpr(TreeView *pView, const Expr *pExpr, u8 m
    +     case TK_ISNULL:  zUniOp = "ISNULL"; break;
    +     case TK_NOTNULL: zUniOp = "NOTNULL"; break;
    + 
    ++    case TK_SPAN: {
    ++      sqlite3TreeViewLine(pView, "SPAN %Q", pExpr->u.zToken);
    ++      sqlite3TreeViewExpr(pView, pExpr->pLeft, 0);
    ++      break;
    ++    }
    ++
    +     case TK_COLLATE: {
    +       sqlite3TreeViewLine(pView, "COLLATE %Q", pExpr->u.zToken);
    +       sqlite3TreeViewExpr(pView, pExpr->pLeft, 0);
    +@@ -23507,17 +27359,17 @@ SQLITE_PRIVATE void sqlite3TreeViewExpr(TreeView *pView, const Expr *pExpr, u8 m
    +     }
    + #ifndef SQLITE_OMIT_SUBQUERY
    +     case TK_EXISTS: {
    +-      sqlite3TreeViewLine(pView, "EXISTS-expr");
    ++      sqlite3TreeViewLine(pView, "EXISTS-expr flags=0x%x", pExpr->flags);
    +       sqlite3TreeViewSelect(pView, pExpr->x.pSelect, 0);
    +       break;
    +     }
    +     case TK_SELECT: {
    +-      sqlite3TreeViewLine(pView, "SELECT-expr");
    ++      sqlite3TreeViewLine(pView, "SELECT-expr flags=0x%x", pExpr->flags);
    +       sqlite3TreeViewSelect(pView, pExpr->x.pSelect, 0);
    +       break;
    +     }
    +     case TK_IN: {
    +-      sqlite3TreeViewLine(pView, "IN");
    ++      sqlite3TreeViewLine(pView, "IN flags=0x%x", pExpr->flags);
    +       sqlite3TreeViewExpr(pView, pExpr->pLeft, 1);
    +       if( ExprHasProperty(pExpr, EP_xIsSelect) ){
    +         sqlite3TreeViewSelect(pView, pExpr->x.pSelect, 0);
    +@@ -23580,6 +27432,26 @@ SQLITE_PRIVATE void sqlite3TreeViewExpr(TreeView *pView, const Expr *pExpr, u8 m
    +       break;
    +     }
    + #endif
    ++    case TK_MATCH: {
    ++      sqlite3TreeViewLine(pView, "MATCH {%d:%d}%s",
    ++                          pExpr->iTable, pExpr->iColumn, zFlgs);
    ++      sqlite3TreeViewExpr(pView, pExpr->pRight, 0);
    ++      break;
    ++    }
    ++    case TK_VECTOR: {
    ++      sqlite3TreeViewBareExprList(pView, pExpr->x.pList, "VECTOR");
    ++      break;
    ++    }
    ++    case TK_SELECT_COLUMN: {
    ++      sqlite3TreeViewLine(pView, "SELECT-COLUMN %d", pExpr->iColumn);
    ++      sqlite3TreeViewSelect(pView, pExpr->pLeft->x.pSelect, 0);
    ++      break;
    ++    }
    ++    case TK_IF_NULL_ROW: {
    ++      sqlite3TreeViewLine(pView, "IF-NULL-ROW %d", pExpr->iTable);
    ++      sqlite3TreeViewExpr(pView, pExpr->pLeft, 0);
    ++      break;
    ++    }
    +     default: {
    +       sqlite3TreeViewLine(pView, "op=%d", pExpr->op);
    +       break;
    +@@ -23596,32 +27468,48 @@ SQLITE_PRIVATE void sqlite3TreeViewExpr(TreeView *pView, const Expr *pExpr, u8 m
    +   sqlite3TreeViewPop(pView);
    + }
    + 
    ++
    + /*
    + ** Generate a human-readable explanation of an expression list.
    + */
    +-SQLITE_PRIVATE void sqlite3TreeViewExprList(
    ++SQLITE_PRIVATE void sqlite3TreeViewBareExprList(
    +   TreeView *pView,
    +   const ExprList *pList,
    +-  u8 moreToFollow,
    +   const char *zLabel
    + ){
    +-  int i;
    +-  pView = sqlite3TreeViewPush(pView, moreToFollow);
    +   if( zLabel==0 || zLabel[0]==0 ) zLabel = "LIST";
    +   if( pList==0 ){
    +     sqlite3TreeViewLine(pView, "%s (empty)", zLabel);
    +   }else{
    ++    int i;
    +     sqlite3TreeViewLine(pView, "%s", zLabel);
    +     for(i=0; i<pList->nExpr; i++){
    +       int j = pList->a[i].u.x.iOrderByCol;
    +-      if( j ){
    ++      char *zName = pList->a[i].zName;
    ++      if( j || zName ){
    +         sqlite3TreeViewPush(pView, 0);
    ++      }
    ++      if( zName ){
    ++        sqlite3TreeViewLine(pView, "AS %s", zName);
    ++      }
    ++      if( j ){
    +         sqlite3TreeViewLine(pView, "iOrderByCol=%d", j);
    +       }
    +       sqlite3TreeViewExpr(pView, pList->a[i].pExpr, i<pList->nExpr-1);
    +-      if( j ) sqlite3TreeViewPop(pView);
    ++      if( j || zName ){
    ++        sqlite3TreeViewPop(pView);
    ++      }
    +     }
    +   }
    ++}
    ++SQLITE_PRIVATE void sqlite3TreeViewExprList(
    ++  TreeView *pView,
    ++  const ExprList *pList,
    ++  u8 moreToFollow,
    ++  const char *zLabel
    ++){
    ++  pView = sqlite3TreeViewPush(pView, moreToFollow);
    ++  sqlite3TreeViewBareExprList(pView, pList, zLabel);
    +   sqlite3TreeViewPop(pView);
    + }
    + 
    +@@ -23661,7 +27549,7 @@ static SQLITE_WSD struct sqlite3PrngType {
    + /*
    + ** Return N random bytes.
    + */
    +-SQLITE_API void SQLITE_STDCALL sqlite3_randomness(int N, void *pBuf){
    ++SQLITE_API void sqlite3_randomness(int N, void *pBuf){
    +   unsigned char t;
    +   unsigned char *zBuf = pBuf;
    + 
    +@@ -23737,7 +27625,7 @@ SQLITE_API void SQLITE_STDCALL sqlite3_randomness(int N, void *pBuf){
    +   sqlite3_mutex_leave(mutex);
    + }
    + 
    +-#ifndef SQLITE_OMIT_BUILTIN_TEST
    ++#ifndef SQLITE_UNTESTABLE
    + /*
    + ** For testing purposes, we sometimes want to preserve the state of
    + ** PRNG and restore the PRNG to its saved state at a later time, or
    +@@ -23762,7 +27650,7 @@ SQLITE_PRIVATE void sqlite3PrngRestoreState(void){
    +     sizeof(sqlite3Prng)
    +   );
    + }
    +-#endif /* SQLITE_OMIT_BUILTIN_TEST */
    ++#endif /* SQLITE_UNTESTABLE */
    + 
    + /************** End of random.c **********************************************/
    + /************** Begin file threads.c *****************************************/
    +@@ -23831,7 +27719,7 @@ SQLITE_PRIVATE int sqlite3ThreadCreate(
    + 
    +   *ppThread = 0;
    +   p = sqlite3Malloc(sizeof(*p));
    +-  if( p==0 ) return SQLITE_NOMEM;
    ++  if( p==0 ) return SQLITE_NOMEM_BKPT;
    +   memset(p, 0, sizeof(*p));
    +   p->xTask = xTask;
    +   p->pIn = pIn;
    +@@ -23857,7 +27745,7 @@ SQLITE_PRIVATE int sqlite3ThreadJoin(SQLiteThread *p, void **ppOut){
    +   int rc;
    + 
    +   assert( ppOut!=0 );
    +-  if( NEVER(p==0) ) return SQLITE_NOMEM;
    ++  if( NEVER(p==0) ) return SQLITE_NOMEM_BKPT;
    +   if( p->done ){
    +     *ppOut = p->pOut;
    +     rc = SQLITE_OK;
    +@@ -23922,7 +27810,7 @@ SQLITE_PRIVATE int sqlite3ThreadCreate(
    +   assert( xTask!=0 );
    +   *ppThread = 0;
    +   p = sqlite3Malloc(sizeof(*p));
    +-  if( p==0 ) return SQLITE_NOMEM;
    ++  if( p==0 ) return SQLITE_NOMEM_BKPT;
    +   /* If the SQLITE_TESTCTRL_FAULT_INSTALL callback is registered to a 
    +   ** function that returns SQLITE_ERROR when passed the argument 200, that
    +   ** forces worker threads to run sequentially and deterministically 
    +@@ -23954,7 +27842,7 @@ SQLITE_PRIVATE int sqlite3ThreadJoin(SQLiteThread *p, void **ppOut){
    +   BOOL bRc;
    + 
    +   assert( ppOut!=0 );
    +-  if( NEVER(p==0) ) return SQLITE_NOMEM;
    ++  if( NEVER(p==0) ) return SQLITE_NOMEM_BKPT;
    +   if( p->xTask==0 ){
    +     /* assert( p->id==GetCurrentThreadId() ); */
    +     rc = WAIT_OBJECT_0;
    +@@ -24002,7 +27890,7 @@ SQLITE_PRIVATE int sqlite3ThreadCreate(
    +   assert( xTask!=0 );
    +   *ppThread = 0;
    +   p = sqlite3Malloc(sizeof(*p));
    +-  if( p==0 ) return SQLITE_NOMEM;
    ++  if( p==0 ) return SQLITE_NOMEM_BKPT;
    +   if( (SQLITE_PTR_TO_INT(p)/17)&1 ){
    +     p->xTask = xTask;
    +     p->pIn = pIn;
    +@@ -24018,7 +27906,7 @@ SQLITE_PRIVATE int sqlite3ThreadCreate(
    + SQLITE_PRIVATE int sqlite3ThreadJoin(SQLiteThread *p, void **ppOut){
    + 
    +   assert( ppOut!=0 );
    +-  if( NEVER(p==0) ) return SQLITE_NOMEM;
    ++  if( NEVER(p==0) ) return SQLITE_NOMEM_BKPT;
    +   if( p->xTask ){
    +     *ppOut = p->xTask(p->pIn);
    +   }else{
    +@@ -24029,7 +27917,7 @@ SQLITE_PRIVATE int sqlite3ThreadJoin(SQLiteThread *p, void **ppOut){
    + #if defined(SQLITE_TEST)
    +   {
    +     void *pTstAlloc = sqlite3Malloc(10);
    +-    if (!pTstAlloc) return SQLITE_NOMEM;
    ++    if (!pTstAlloc) return SQLITE_NOMEM_BKPT;
    +     sqlite3_free(pTstAlloc);
    +   }
    + #endif
    +@@ -24082,13 +27970,13 @@ SQLITE_PRIVATE int sqlite3ThreadJoin(SQLiteThread *p, void **ppOut){
    + /* #include <assert.h> */
    + /* #include "vdbeInt.h" */
    + 
    +-#ifndef SQLITE_AMALGAMATION
    ++#if !defined(SQLITE_AMALGAMATION) && SQLITE_BYTEORDER==0
    + /*
    + ** The following constant value is used by the SQLITE_BIGENDIAN and
    + ** SQLITE_LITTLEENDIAN macros.
    + */
    + SQLITE_PRIVATE const int sqlite3one = 1;
    +-#endif /* SQLITE_AMALGAMATION */
    ++#endif /* SQLITE_AMALGAMATION && SQLITE_BYTEORDER==0 */
    + 
    + /*
    + ** This lookup table is used to help decode the first byte of
    +@@ -24276,7 +28164,7 @@ SQLITE_PRIVATE SQLITE_NOINLINE int sqlite3VdbeMemTranslate(Mem *pMem, u8 desired
    +     rc = sqlite3VdbeMemMakeWriteable(pMem);
    +     if( rc!=SQLITE_OK ){
    +       assert( rc==SQLITE_NOMEM );
    +-      return SQLITE_NOMEM;
    ++      return SQLITE_NOMEM_BKPT;
    +     }
    +     zIn = (u8*)pMem->z;
    +     zTerm = &zIn[pMem->n&~1];
    +@@ -24318,7 +28206,7 @@ SQLITE_PRIVATE SQLITE_NOINLINE int sqlite3VdbeMemTranslate(Mem *pMem, u8 desired
    +   zTerm = &zIn[pMem->n];
    +   zOut = sqlite3DbMallocRaw(pMem->db, len);
    +   if( !zOut ){
    +-    return SQLITE_NOMEM;
    ++    return SQLITE_NOMEM_BKPT;
    +   }
    +   z = zOut;
    + 
    +@@ -24361,7 +28249,7 @@ SQLITE_PRIVATE SQLITE_NOINLINE int sqlite3VdbeMemTranslate(Mem *pMem, u8 desired
    + 
    +   c = pMem->flags;
    +   sqlite3VdbeMemRelease(pMem);
    +-  pMem->flags = MEM_Str|MEM_Term|(c&MEM_AffMask);
    ++  pMem->flags = MEM_Str|MEM_Term|(c&(MEM_AffMask|MEM_Subtype));
    +   pMem->enc = desiredEnc;
    +   pMem->z = (char*)zOut;
    +   pMem->zMalloc = pMem->z;
    +@@ -24377,7 +28265,9 @@ translate_out:
    + #endif
    +   return SQLITE_OK;
    + }
    ++#endif /* SQLITE_OMIT_UTF16 */
    + 
    ++#ifndef SQLITE_OMIT_UTF16
    + /*
    + ** This routine checks for a byte-order mark at the beginning of the 
    + ** UTF-16 string stored in *pMem. If one is present, it is removed and
    +@@ -24620,7 +28510,7 @@ SQLITE_PRIVATE void sqlite3Coverage(int x){
    + ** Return whatever integer value the test callback returns, or return
    + ** SQLITE_OK if no test callback is installed.
    + */
    +-#ifndef SQLITE_OMIT_BUILTIN_TEST
    ++#ifndef SQLITE_UNTESTABLE
    + SQLITE_PRIVATE int sqlite3FaultSim(int iTest){
    +   int (*xCallback)(int) = sqlite3GlobalConfig.xTestCallback;
    +   return xCallback ? xCallback(iTest) : SQLITE_OK;
    +@@ -24687,13 +28577,49 @@ SQLITE_PRIVATE int sqlite3Strlen30(const char *z){
    +   return 0x3fffffff & (int)strlen(z);
    + }
    + 
    ++/*
    ++** Return the declared type of a column.  Or return zDflt if the column 
    ++** has no declared type.
    ++**
    ++** The column type is an extra string stored after the zero-terminator on
    ++** the column name if and only if the COLFLAG_HASTYPE flag is set.
    ++*/
    ++SQLITE_PRIVATE char *sqlite3ColumnType(Column *pCol, char *zDflt){
    ++  if( (pCol->colFlags & COLFLAG_HASTYPE)==0 ) return zDflt;
    ++  return pCol->zName + strlen(pCol->zName) + 1;
    ++}
    ++
    ++/*
    ++** Helper function for sqlite3Error() - called rarely.  Broken out into
    ++** a separate routine to avoid unnecessary register saves on entry to
    ++** sqlite3Error().
    ++*/
    ++static SQLITE_NOINLINE void  sqlite3ErrorFinish(sqlite3 *db, int err_code){
    ++  if( db->pErr ) sqlite3ValueSetNull(db->pErr);
    ++  sqlite3SystemError(db, err_code);
    ++}
    ++
    + /*
    + ** Set the current error code to err_code and clear any prior error message.
    ++** Also set iSysErrno (by calling sqlite3System) if the err_code indicates
    ++** that would be appropriate.
    + */
    + SQLITE_PRIVATE void sqlite3Error(sqlite3 *db, int err_code){
    +   assert( db!=0 );
    +   db->errCode = err_code;
    +-  if( db->pErr ) sqlite3ValueSetNull(db->pErr);
    ++  if( err_code || db->pErr ) sqlite3ErrorFinish(db, err_code);
    ++}
    ++
    ++/*
    ++** Load the sqlite3.iSysErrno field if that is an appropriate thing
    ++** to do based on the SQLite error code in rc.
    ++*/
    ++SQLITE_PRIVATE void sqlite3SystemError(sqlite3 *db, int rc){
    ++  if( rc==SQLITE_IOERR_NOMEM ) return;
    ++  rc &= 0xff;
    ++  if( rc==SQLITE_CANTOPEN || rc==SQLITE_IOERR ){
    ++    db->iSysErrno = sqlite3OsGetLastError(db->pVfs);
    ++  }
    + }
    + 
    + /*
    +@@ -24720,6 +28646,7 @@ SQLITE_PRIVATE void sqlite3Error(sqlite3 *db, int err_code){
    + SQLITE_PRIVATE void sqlite3ErrorWithMsg(sqlite3 *db, int err_code, const char *zFormat, ...){
    +   assert( db!=0 );
    +   db->errCode = err_code;
    ++  sqlite3SystemError(db, err_code);
    +   if( zFormat==0 ){
    +     sqlite3Error(db, err_code);
    +   }else if( db->pErr || (db->pErr = sqlite3ValueNew(db))!=0 ){
    +@@ -24783,18 +28710,13 @@ SQLITE_PRIVATE void sqlite3ErrorMsg(Parse *pParse, const char *zFormat, ...){
    + ** brackets from around identifiers.  For example:  "[a-b-c]" becomes
    + ** "a-b-c".
    + */
    +-SQLITE_PRIVATE int sqlite3Dequote(char *z){
    ++SQLITE_PRIVATE void sqlite3Dequote(char *z){
    +   char quote;
    +   int i, j;
    +-  if( z==0 ) return -1;
    ++  if( z==0 ) return;
    +   quote = z[0];
    +-  switch( quote ){
    +-    case '\'':  break;
    +-    case '"':   break;
    +-    case '`':   break;                /* For MySQL compatibility */
    +-    case '[':   quote = ']';  break;  /* For MS SqlServer compatibility */
    +-    default:    return -1;
    +-  }
    ++  if( !sqlite3Isquote(quote) ) return;
    ++  if( quote=='[' ) quote = ']';
    +   for(i=1, j=0;; i++){
    +     assert( z[i] );
    +     if( z[i]==quote ){
    +@@ -24809,7 +28731,14 @@ SQLITE_PRIVATE int sqlite3Dequote(char *z){
    +     }
    +   }
    +   z[j] = 0;
    +-  return j;
    ++}
    ++
    ++/*
    ++** Generate a Token object from a string
    ++*/
    ++SQLITE_PRIVATE void sqlite3TokenInit(Token *p, char *z){
    ++  p->z = z;
    ++  p->n = sqlite3Strlen30(z);
    + }
    + 
    + /* Convenient short-hand */
    +@@ -24825,19 +28754,28 @@ SQLITE_PRIVATE int sqlite3Dequote(char *z){
    + ** case-independent fashion, using the same definition of "case
    + ** independence" that SQLite uses internally when comparing identifiers.
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_stricmp(const char *zLeft, const char *zRight){
    +-  register unsigned char *a, *b;
    ++SQLITE_API int sqlite3_stricmp(const char *zLeft, const char *zRight){
    +   if( zLeft==0 ){
    +     return zRight ? -1 : 0;
    +   }else if( zRight==0 ){
    +     return 1;
    +   }
    ++  return sqlite3StrICmp(zLeft, zRight);
    ++}
    ++SQLITE_PRIVATE int sqlite3StrICmp(const char *zLeft, const char *zRight){
    ++  unsigned char *a, *b;
    ++  int c;
    +   a = (unsigned char *)zLeft;
    +   b = (unsigned char *)zRight;
    +-  while( *a!=0 && UpperToLower[*a]==UpperToLower[*b]){ a++; b++; }
    +-  return UpperToLower[*a] - UpperToLower[*b];
    ++  for(;;){
    ++    c = (int)UpperToLower[*a] - (int)UpperToLower[*b];
    ++    if( c || *a==0 ) break;
    ++    a++;
    ++    b++;
    ++  }
    ++  return c;
    + }
    +-SQLITE_API int SQLITE_STDCALL sqlite3_strnicmp(const char *zLeft, const char *zRight, int N){
    ++SQLITE_API int sqlite3_strnicmp(const char *zLeft, const char *zRight, int N){
    +   register unsigned char *a, *b;
    +   if( zLeft==0 ){
    +     return zRight ? -1 : 0;
    +@@ -24850,6 +28788,45 @@ SQLITE_API int SQLITE_STDCALL sqlite3_strnicmp(const char *zLeft, const char *zR
    +   return N<0 ? 0 : UpperToLower[*a] - UpperToLower[*b];
    + }
    + 
    ++/*
    ++** Compute 10 to the E-th power.  Examples:  E==1 results in 10.
    ++** E==2 results in 100.  E==50 results in 1.0e50.
    ++**
    ++** This routine only works for values of E between 1 and 341.
    ++*/
    ++static LONGDOUBLE_TYPE sqlite3Pow10(int E){
    ++#if defined(_MSC_VER)
    ++  static const LONGDOUBLE_TYPE x[] = {
    ++    1.0e+001,
    ++    1.0e+002,
    ++    1.0e+004,
    ++    1.0e+008,
    ++    1.0e+016,
    ++    1.0e+032,
    ++    1.0e+064,
    ++    1.0e+128,
    ++    1.0e+256
    ++  };
    ++  LONGDOUBLE_TYPE r = 1.0;
    ++  int i;
    ++  assert( E>=0 && E<=307 );
    ++  for(i=0; E!=0; i++, E >>=1){
    ++    if( E & 1 ) r *= x[i];
    ++  }
    ++  return r;
    ++#else
    ++  LONGDOUBLE_TYPE x = 10.0;
    ++  LONGDOUBLE_TYPE r = 1.0;
    ++  while(1){
    ++    if( E & 1 ) r *= x;
    ++    E >>= 1;
    ++    if( E==0 ) break;
    ++    x *= x;
    ++  }
    ++  return r; 
    ++#endif
    ++}
    ++
    + /*
    + ** The string z[] is an text representation of a real number.
    + ** Convert this string to a double and write it into *pResult.
    +@@ -24885,7 +28862,7 @@ SQLITE_PRIVATE int sqlite3AtoF(const char *z, double *pResult, int length, u8 en
    +   int eValid = 1;  /* True exponent is either not used or is well-formed */
    +   double result;
    +   int nDigits = 0;
    +-  int nonNum = 0;
    ++  int nonNum = 0;  /* True if input contains UTF16 with high byte non-zero */
    + 
    +   assert( enc==SQLITE_UTF8 || enc==SQLITE_UTF16LE || enc==SQLITE_UTF16BE );
    +   *pResult = 0.0;   /* Default return value, in case of an error */
    +@@ -24898,7 +28875,7 @@ SQLITE_PRIVATE int sqlite3AtoF(const char *z, double *pResult, int length, u8 en
    +     assert( SQLITE_UTF16LE==2 && SQLITE_UTF16BE==3 );
    +     for(i=3-enc; i<length && z[i]==0; i+=2){}
    +     nonNum = i<length;
    +-    zEnd = z+i+enc-3;
    ++    zEnd = &z[i^1];
    +     z += (enc&1);
    +   }
    + 
    +@@ -24914,18 +28891,15 @@ SQLITE_PRIVATE int sqlite3AtoF(const char *z, double *pResult, int length, u8 en
    +     z+=incr;
    +   }
    + 
    +-  /* skip leading zeroes */
    +-  while( z<zEnd && z[0]=='0' ) z+=incr, nDigits++;
    +-
    +   /* copy max significant digits to significand */
    +   while( z<zEnd && sqlite3Isdigit(*z) && s<((LARGEST_INT64-9)/10) ){
    +     s = s*10 + (*z - '0');
    +-    z+=incr, nDigits++;
    ++    z+=incr; nDigits++;
    +   }
    + 
    +   /* skip non-significant significand digits
    +   ** (increase exponent by d to shift decimal left) */
    +-  while( z<zEnd && sqlite3Isdigit(*z) ) z+=incr, nDigits++, d++;
    ++  while( z<zEnd && sqlite3Isdigit(*z) ){ z+=incr; nDigits++; d++; }
    +   if( z>=zEnd ) goto do_atof_calc;
    + 
    +   /* if decimal point is present */
    +@@ -24933,12 +28907,13 @@ SQLITE_PRIVATE int sqlite3AtoF(const char *z, double *pResult, int length, u8 en
    +     z+=incr;
    +     /* copy digits from after decimal to significand
    +     ** (decrease exponent by d to shift decimal right) */
    +-    while( z<zEnd && sqlite3Isdigit(*z) && s<((LARGEST_INT64-9)/10) ){
    +-      s = s*10 + (*z - '0');
    +-      z+=incr, nDigits++, d--;
    ++    while( z<zEnd && sqlite3Isdigit(*z) ){
    ++      if( s<((LARGEST_INT64-9)/10) ){
    ++        s = s*10 + (*z - '0');
    ++        d--;
    ++      }
    ++      z+=incr; nDigits++;
    +     }
    +-    /* skip non-significant digits */
    +-    while( z<zEnd && sqlite3Isdigit(*z) ) z+=incr, nDigits++;
    +   }
    +   if( z>=zEnd ) goto do_atof_calc;
    + 
    +@@ -24946,7 +28921,12 @@ SQLITE_PRIVATE int sqlite3AtoF(const char *z, double *pResult, int length, u8 en
    +   if( *z=='e' || *z=='E' ){
    +     z+=incr;
    +     eValid = 0;
    +-    if( z>=zEnd ) goto do_atof_calc;
    ++
    ++    /* This branch is needed to avoid a (harmless) buffer overread.  The 
    ++    ** special comment alerts the mutation tester that the correct answer
    ++    ** is obtained even if the branch is omitted */
    ++    if( z>=zEnd ) goto do_atof_calc;              /*PREVENTS-HARMLESS-OVERREAD*/
    ++
    +     /* get sign of exponent */
    +     if( *z=='-' ){
    +       esign = -1;
    +@@ -24963,9 +28943,7 @@ SQLITE_PRIVATE int sqlite3AtoF(const char *z, double *pResult, int length, u8 en
    +   }
    + 
    +   /* skip trailing spaces */
    +-  if( nDigits && eValid ){
    +-    while( z<zEnd && sqlite3Isspace(*z) ) z+=incr;
    +-  }
    ++  while( z<zEnd && sqlite3Isspace(*z) ) z+=incr;
    + 
    + do_atof_calc:
    +   /* adjust exponent by d, and update sign */
    +@@ -24977,55 +28955,63 @@ do_atof_calc:
    +     esign = 1;
    +   }
    + 
    +-  /* if 0 significand */
    +-  if( !s ) {
    +-    /* In the IEEE 754 standard, zero is signed.
    +-    ** Add the sign if we've seen at least one digit */
    +-    result = (sign<0 && nDigits) ? -(double)0 : (double)0;
    ++  if( s==0 ) {
    ++    /* In the IEEE 754 standard, zero is signed. */
    ++    result = sign<0 ? -(double)0 : (double)0;
    +   } else {
    +-    /* attempt to reduce exponent */
    +-    if( esign>0 ){
    +-      while( s<(LARGEST_INT64/10) && e>0 ) e--,s*=10;
    +-    }else{
    +-      while( !(s%10) && e>0 ) e--,s/=10;
    ++    /* Attempt to reduce exponent.
    ++    **
    ++    ** Branches that are not required for the correct answer but which only
    ++    ** help to obtain the correct answer faster are marked with special
    ++    ** comments, as a hint to the mutation tester.
    ++    */
    ++    while( e>0 ){                                       /*OPTIMIZATION-IF-TRUE*/
    ++      if( esign>0 ){
    ++        if( s>=(LARGEST_INT64/10) ) break;             /*OPTIMIZATION-IF-FALSE*/
    ++        s *= 10;
    ++      }else{
    ++        if( s%10!=0 ) break;                           /*OPTIMIZATION-IF-FALSE*/
    ++        s /= 10;
    ++      }
    ++      e--;
    +     }
    + 
    +     /* adjust the sign of significand */
    +     s = sign<0 ? -s : s;
    + 
    +-    /* if exponent, scale significand as appropriate
    +-    ** and store in result. */
    +-    if( e ){
    +-      LONGDOUBLE_TYPE scale = 1.0;
    ++    if( e==0 ){                                         /*OPTIMIZATION-IF-TRUE*/
    ++      result = (double)s;
    ++    }else{
    +       /* attempt to handle extremely small/large numbers better */
    +-      if( e>307 && e<342 ){
    +-        while( e%308 ) { scale *= 1.0e+1; e -= 1; }
    +-        if( esign<0 ){
    +-          result = s / scale;
    +-          result /= 1.0e+308;
    +-        }else{
    +-          result = s * scale;
    +-          result *= 1.0e+308;
    +-        }
    +-      }else if( e>=342 ){
    +-        if( esign<0 ){
    +-          result = 0.0*s;
    +-        }else{
    +-          result = 1e308*1e308*s;  /* Infinity */
    ++      if( e>307 ){                                      /*OPTIMIZATION-IF-TRUE*/
    ++        if( e<342 ){                                    /*OPTIMIZATION-IF-TRUE*/
    ++          LONGDOUBLE_TYPE scale = sqlite3Pow10(e-308);
    ++          if( esign<0 ){
    ++            result = s / scale;
    ++            result /= 1.0e+308;
    ++          }else{
    ++            result = s * scale;
    ++            result *= 1.0e+308;
    ++          }
    ++        }else{ assert( e>=342 );
    ++          if( esign<0 ){
    ++            result = 0.0*s;
    ++          }else{
    ++#ifdef INFINITY
    ++            result = INFINITY*s;
    ++#else
    ++            result = 1e308*1e308*s;  /* Infinity */
    ++#endif
    ++          }
    +         }
    +       }else{
    +-        /* 1.0e+22 is the largest power of 10 than can be 
    +-        ** represented exactly. */
    +-        while( e%22 ) { scale *= 1.0e+1; e -= 1; }
    +-        while( e>0 ) { scale *= 1.0e+22; e -= 22; }
    ++        LONGDOUBLE_TYPE scale = sqlite3Pow10(e);
    +         if( esign<0 ){
    +           result = s / scale;
    +         }else{
    +           result = s * scale;
    +         }
    +       }
    +-    } else {
    +-      result = (double)s;
    +     }
    +   }
    + 
    +@@ -25033,7 +29019,7 @@ do_atof_calc:
    +   *pResult = result;
    + 
    +   /* return true if number and no extra non-whitespace chracters after */
    +-  return z>=zEnd && nDigits>0 && eValid && nonNum==0;
    ++  return z==zEnd && nDigits>0 && eValid && nonNum==0;
    + #else
    +   return !sqlite3Atoi64(z, pResult, length, enc);
    + #endif /* SQLITE_OMIT_FLOATING_POINT */
    +@@ -25074,16 +29060,12 @@ static int compare2pow63(const char *zNum, int incr){
    + ** 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.
    +-**
    +-** If zNum is exactly 9223372036854775808, return 2.  This special
    +-** case is broken out because while 9223372036854775808 cannot be a 
    +-** signed 64-bit integer, its negative -9223372036854775808 can be.
    ++** Returns:
    + **
    +-** If zNum is too big for a 64-bit integer and is not
    +-** 9223372036854775808  or if zNum contains any non-numeric text,
    +-** then return 1.
    ++**     0    Successful transformation.  Fits in a 64-bit signed integer.
    ++**     1    Excess text after the integer value
    ++**     2    Integer too large for a 64-bit signed integer or is malformed
    ++**     3    Special case of 9223372036854775808
    + **
    + ** length is the number of bytes in the string (bytes, not characters).
    + ** The string is not necessarily zero-terminated.  The encoding is
    +@@ -25095,7 +29077,8 @@ SQLITE_PRIVATE int sqlite3Atoi64(const char *zNum, i64 *pNum, int length, u8 enc
    +   int neg = 0; /* assume positive */
    +   int i;
    +   int c = 0;
    +-  int nonNum = 0;
    ++  int nonNum = 0;  /* True if input contains UTF16 with high byte non-zero */
    ++  int rc;          /* Baseline return code */
    +   const char *zStart;
    +   const char *zEnd = zNum + length;
    +   assert( enc==SQLITE_UTF8 || enc==SQLITE_UTF16LE || enc==SQLITE_UTF16BE );
    +@@ -25106,7 +29089,7 @@ SQLITE_PRIVATE int sqlite3Atoi64(const char *zNum, i64 *pNum, int length, u8 enc
    +     assert( SQLITE_UTF16LE==2 && SQLITE_UTF16BE==3 );
    +     for(i=3-enc; i<length && zNum[i]==0; i+=2){}
    +     nonNum = i<length;
    +-    zEnd = zNum+i+enc-3;
    ++    zEnd = &zNum[i^1];
    +     zNum += (enc&1);
    +   }
    +   while( zNum<zEnd && sqlite3Isspace(*zNum) ) zNum+=incr;
    +@@ -25133,29 +29116,37 @@ SQLITE_PRIVATE int sqlite3Atoi64(const char *zNum, i64 *pNum, int length, u8 enc
    +   testcase( i==18 );
    +   testcase( i==19 );
    +   testcase( i==20 );
    +-  if( (c!=0 && &zNum[i]<zEnd) || (i==0 && zStart==zNum) || i>19*incr || nonNum ){
    ++  if( &zNum[i]<zEnd              /* Extra bytes at the end */
    ++   || (i==0 && zStart==zNum)     /* No digits */
    ++   || nonNum                     /* UTF16 with high-order bytes non-zero */
    ++  ){
    ++    rc = 1;
    ++  }else{
    ++    rc = 0;
    ++  }
    ++  if( i>19*incr ){                /* Too many digits */
    +     /* zNum is empty or contains non-numeric text or is longer
    +     ** than 19 digits (thus guaranteeing that it is too large) */
    +-    return 1;
    ++    return 2;
    +   }else if( i<19*incr ){
    +     /* Less than 19 digits, so we know that it fits in 64 bits */
    +     assert( u<=LARGEST_INT64 );
    +-    return 0;
    ++    return rc;
    +   }else{
    +     /* zNum is a 19-digit numbers.  Compare it against 9223372036854775808. */
    +     c = compare2pow63(zNum, incr);
    +     if( c<0 ){
    +       /* zNum is less than 9223372036854775808 so it fits */
    +       assert( u<=LARGEST_INT64 );
    +-      return 0;
    ++      return rc;
    +     }else if( c>0 ){
    +       /* zNum is greater than 9223372036854775808 so it overflows */
    +-      return 1;
    ++      return 2;
    +     }else{
    +       /* zNum is exactly 9223372036854775808.  Fits if negative.  The
    +       ** special case 2 overflow if positive */
    +       assert( u-1==LARGEST_INT64 );
    +-      return neg ? 0 : 2;
    ++      return neg ? rc : 3;
    +     }
    +   }
    + }
    +@@ -25168,14 +29159,14 @@ SQLITE_PRIVATE int sqlite3Atoi64(const char *zNum, i64 *pNum, int length, u8 enc
    + ** 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
    ++**     1    Excess text after the integer value
    ++**     2    Integer too large for a 64-bit signed integer or is malformed
    ++**     3    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;
    +@@ -25184,7 +29175,7 @@ SQLITE_PRIVATE int sqlite3DecOrHexToI64(const char *z, i64 *pOut){
    +       u = u*16 + sqlite3HexToInt(z[k]);
    +     }
    +     memcpy(pOut, &u, 8);
    +-    return (z[k]==0 && k-i<=16) ? 0 : 1;
    ++    return (z[k]==0 && k-i<=16) ? 0 : 2;
    +   }else
    + #endif /* SQLITE_OMIT_HEX_INTEGER */
    +   {
    +@@ -25231,6 +29222,7 @@ SQLITE_PRIVATE int sqlite3GetInt32(const char *zNum, int *pValue){
    +     }
    +   }
    + #endif
    ++  if( !sqlite3Isdigit(zNum[0]) ) return 0;
    +   while( zNum[0]=='0' ) zNum++;
    +   for(i=0; i<11 && (c = zNum[i] - '0')>=0 && c<=9; i++){
    +     v = v*10 + c;
    +@@ -25422,7 +29414,8 @@ SQLITE_PRIVATE u8 sqlite3GetVarint(const unsigned char *p, u64 *v){
    +   /* a: p0<<28 | p2<<14 | p4 (unmasked) */
    +   if (!(a&0x80))
    +   {
    +-    /* we can skip these cause they were (effectively) done above in calc'ing s */
    ++    /* we can skip these cause they were (effectively) done above
    ++    ** while calculating s */
    +     /* a &= (0x7f<<28)|(0x7f<<14)|(0x7f); */
    +     /* b &= (0x7f<<14)|(0x7f); */
    +     b = b<<7;
    +@@ -25644,7 +29637,7 @@ SQLITE_PRIVATE u8 sqlite3GetVarint32(const unsigned char *p, u32 *v){
    + */
    + SQLITE_PRIVATE int sqlite3VarintLen(u64 v){
    +   int i;
    +-  for(i=1; (v >>= 7)!=0; i++){ assert( i<9 ); }
    ++  for(i=1; (v >>= 7)!=0; i++){ assert( i<10 ); }
    +   return i;
    + }
    + 
    +@@ -25657,13 +29650,11 @@ SQLITE_PRIVATE u32 sqlite3Get4byte(const u8 *p){
    +   u32 x;
    +   memcpy(&x,p,4);
    +   return x;
    +-#elif SQLITE_BYTEORDER==1234 && !defined(SQLITE_DISABLE_INTRINSIC) \
    +-    && defined(__GNUC__) && GCC_VERSION>=4003000
    ++#elif SQLITE_BYTEORDER==1234 && GCC_VERSION>=4003000
    +   u32 x;
    +   memcpy(&x,p,4);
    +   return __builtin_bswap32(x);
    +-#elif SQLITE_BYTEORDER==1234 && !defined(SQLITE_DISABLE_INTRINSIC) \
    +-    && defined(_MSC_VER) && _MSC_VER>=1300
    ++#elif SQLITE_BYTEORDER==1234 && MSVC_VERSION>=1300
    +   u32 x;
    +   memcpy(&x,p,4);
    +   return _byteswap_ulong(x);
    +@@ -25675,10 +29666,10 @@ SQLITE_PRIVATE u32 sqlite3Get4byte(const u8 *p){
    + SQLITE_PRIVATE void sqlite3Put4byte(unsigned char *p, u32 v){
    + #if SQLITE_BYTEORDER==4321
    +   memcpy(p,&v,4);
    +-#elif SQLITE_BYTEORDER==1234 && defined(__GNUC__) && GCC_VERSION>=4003000
    ++#elif SQLITE_BYTEORDER==1234 && GCC_VERSION>=4003000
    +   u32 x = __builtin_bswap32(v);
    +   memcpy(p,&x,4);
    +-#elif SQLITE_BYTEORDER==1234 && defined(_MSC_VER) && _MSC_VER>=1300
    ++#elif SQLITE_BYTEORDER==1234 && MSVC_VERSION>=1300
    +   u32 x = _byteswap_ulong(v);
    +   memcpy(p,&x,4);
    + #else
    +@@ -25718,7 +29709,7 @@ SQLITE_PRIVATE void *sqlite3HexToBlob(sqlite3 *db, const char *z, int n){
    +   char *zBlob;
    +   int i;
    + 
    +-  zBlob = (char *)sqlite3DbMallocRaw(db, n/2 + 1);
    ++  zBlob = (char *)sqlite3DbMallocRawNN(db, n/2 + 1);
    +   n--;
    +   if( zBlob ){
    +     for(i=0; i<n; i+=2){
    +@@ -25794,6 +29785,9 @@ SQLITE_PRIVATE int sqlite3SafetyCheckSickOrOk(sqlite3 *db){
    + ** overflow, leave *pA unchanged and return 1.
    + */
    + SQLITE_PRIVATE int sqlite3AddInt64(i64 *pA, i64 iB){
    ++#if GCC_VERSION>=5004000 && !defined(__INTEL_COMPILER)
    ++  return __builtin_add_overflow(*pA, iB, pA);
    ++#else
    +   i64 iA = *pA;
    +   testcase( iA==0 ); testcase( iA==1 );
    +   testcase( iB==-1 ); testcase( iB==0 );
    +@@ -25808,8 +29802,12 @@ SQLITE_PRIVATE int sqlite3AddInt64(i64 *pA, i64 iB){
    +   }
    +   *pA += iB;
    +   return 0; 
    ++#endif
    + }
    + SQLITE_PRIVATE int sqlite3SubInt64(i64 *pA, i64 iB){
    ++#if GCC_VERSION>=5004000 && !defined(__INTEL_COMPILER)
    ++  return __builtin_sub_overflow(*pA, iB, pA);
    ++#else
    +   testcase( iB==SMALLEST_INT64+1 );
    +   if( iB==SMALLEST_INT64 ){
    +     testcase( (*pA)==(-1) ); testcase( (*pA)==0 );
    +@@ -25819,38 +29817,28 @@ SQLITE_PRIVATE int sqlite3SubInt64(i64 *pA, i64 iB){
    +   }else{
    +     return sqlite3AddInt64(pA, -iB);
    +   }
    ++#endif
    + }
    +-#define TWOPOWER32 (((i64)1)<<32)
    +-#define TWOPOWER31 (((i64)1)<<31)
    + SQLITE_PRIVATE int sqlite3MulInt64(i64 *pA, i64 iB){
    ++#if GCC_VERSION>=5004000 && !defined(__INTEL_COMPILER)
    ++  return __builtin_mul_overflow(*pA, iB, pA);
    ++#else
    +   i64 iA = *pA;
    +-  i64 iA1, iA0, iB1, iB0, r;
    +-
    +-  iA1 = iA/TWOPOWER32;
    +-  iA0 = iA % TWOPOWER32;
    +-  iB1 = iB/TWOPOWER32;
    +-  iB0 = iB % TWOPOWER32;
    +-  if( iA1==0 ){
    +-    if( iB1==0 ){
    +-      *pA *= iB;
    +-      return 0;
    +-    }
    +-    r = iA0*iB1;
    +-  }else if( iB1==0 ){
    +-    r = iA1*iB0;
    +-  }else{
    +-    /* If both iA1 and iB1 are non-zero, overflow will result */
    +-    return 1;
    +-  }
    +-  testcase( r==(-TWOPOWER31)-1 );
    +-  testcase( r==(-TWOPOWER31) );
    +-  testcase( r==TWOPOWER31 );
    +-  testcase( r==TWOPOWER31-1 );
    +-  if( r<(-TWOPOWER31) || r>=TWOPOWER31 ) return 1;
    +-  r *= TWOPOWER32;
    +-  if( sqlite3AddInt64(&r, iA0*iB0) ) return 1;
    +-  *pA = r;
    ++  if( iB>0 ){
    ++    if( iA>LARGEST_INT64/iB ) return 1;
    ++    if( iA<SMALLEST_INT64/iB ) return 1;
    ++  }else if( iB<0 ){
    ++    if( iA>0 ){
    ++      if( iB<SMALLEST_INT64/iA ) return 1;
    ++    }else if( iA<0 ){
    ++      if( iB==SMALLEST_INT64 ) return 1;
    ++      if( iA==SMALLEST_INT64 ) return 1;
    ++      if( -iA>LARGEST_INT64/-iB ) return 1;
    ++    }
    ++  }
    ++  *pA = iA*iB;
    +   return 0;
    ++#endif
    + }
    + 
    + /*
    +@@ -25934,8 +29922,14 @@ SQLITE_PRIVATE LogEst sqlite3LogEst(u64 x){
    +     if( x<2 ) return 0;
    +     while( x<8 ){  y -= 10; x <<= 1; }
    +   }else{
    +-    while( x>255 ){ y += 40; x >>= 4; }
    ++#if GCC_VERSION>=5004000
    ++    int i = 60 - __builtin_clzll(x);
    ++    y += i*10;
    ++    x >>= i;
    ++#else
    ++    while( x>255 ){ y += 40; x >>= 4; }  /*OPTIMIZATION-IF-TRUE*/
    +     while( x>15 ){  y += 10; x >>= 1; }
    ++#endif
    +   }
    +   return a[x&7] + y - 10;
    + }
    +@@ -25957,20 +29951,134 @@ SQLITE_PRIVATE LogEst sqlite3LogEstFromDouble(double x){
    + }
    + #endif /* SQLITE_OMIT_VIRTUALTABLE */
    + 
    ++#if defined(SQLITE_ENABLE_STMT_SCANSTATUS) || \
    ++    defined(SQLITE_ENABLE_STAT3_OR_STAT4) || \
    ++    defined(SQLITE_EXPLAIN_ESTIMATED_ROWS)
    + /*
    + ** Convert a LogEst into an integer.
    ++**
    ++** Note that this routine is only used when one or more of various
    ++** non-standard compile-time options is enabled.
    + */
    + SQLITE_PRIVATE u64 sqlite3LogEstToInt(LogEst x){
    +   u64 n;
    +-  if( x<10 ) return 1;
    +   n = x%10;
    +   x /= 10;
    +   if( n>=5 ) n -= 2;
    +   else if( n>=1 ) n -= 1;
    +-  if( x>=3 ){
    +-    return x>60 ? (u64)LARGEST_INT64 : (n+8)<<(x-3);
    +-  }
    +-  return (n+8)>>(3-x);
    ++#if defined(SQLITE_ENABLE_STMT_SCANSTATUS) || \
    ++    defined(SQLITE_EXPLAIN_ESTIMATED_ROWS)
    ++  if( x>60 ) return (u64)LARGEST_INT64;
    ++#else
    ++  /* If only SQLITE_ENABLE_STAT3_OR_STAT4 is on, then the largest input
    ++  ** possible to this routine is 310, resulting in a maximum x of 31 */
    ++  assert( x<=60 );
    ++#endif
    ++  return x>=3 ? (n+8)<<(x-3) : (n+8)>>(3-x);
    ++}
    ++#endif /* defined SCANSTAT or STAT4 or ESTIMATED_ROWS */
    ++
    ++/*
    ++** Add a new name/number pair to a VList.  This might require that the
    ++** VList object be reallocated, so return the new VList.  If an OOM
    ++** error occurs, the original VList returned and the
    ++** db->mallocFailed flag is set.
    ++**
    ++** A VList is really just an array of integers.  To destroy a VList,
    ++** simply pass it to sqlite3DbFree().
    ++**
    ++** The first integer is the number of integers allocated for the whole
    ++** VList.  The second integer is the number of integers actually used.
    ++** Each name/number pair is encoded by subsequent groups of 3 or more
    ++** integers.
    ++**
    ++** Each name/number pair starts with two integers which are the numeric
    ++** value for the pair and the size of the name/number pair, respectively.
    ++** The text name overlays one or more following integers.  The text name
    ++** is always zero-terminated.
    ++**
    ++** Conceptually:
    ++**
    ++**    struct VList {
    ++**      int nAlloc;   // Number of allocated slots 
    ++**      int nUsed;    // Number of used slots 
    ++**      struct VListEntry {
    ++**        int iValue;    // Value for this entry
    ++**        int nSlot;     // Slots used by this entry
    ++**        // ... variable name goes here
    ++**      } a[0];
    ++**    }
    ++**
    ++** During code generation, pointers to the variable names within the
    ++** VList are taken.  When that happens, nAlloc is set to zero as an 
    ++** indication that the VList may never again be enlarged, since the
    ++** accompanying realloc() would invalidate the pointers.
    ++*/
    ++SQLITE_PRIVATE VList *sqlite3VListAdd(
    ++  sqlite3 *db,           /* The database connection used for malloc() */
    ++  VList *pIn,            /* The input VList.  Might be NULL */
    ++  const char *zName,     /* Name of symbol to add */
    ++  int nName,             /* Bytes of text in zName */
    ++  int iVal               /* Value to associate with zName */
    ++){
    ++  int nInt;              /* number of sizeof(int) objects needed for zName */
    ++  char *z;               /* Pointer to where zName will be stored */
    ++  int i;                 /* Index in pIn[] where zName is stored */
    ++
    ++  nInt = nName/4 + 3;
    ++  assert( pIn==0 || pIn[0]>=3 );  /* Verify ok to add new elements */
    ++  if( pIn==0 || pIn[1]+nInt > pIn[0] ){
    ++    /* Enlarge the allocation */
    ++    int nAlloc = (pIn ? pIn[0]*2 : 10) + nInt;
    ++    VList *pOut = sqlite3DbRealloc(db, pIn, nAlloc*sizeof(int));
    ++    if( pOut==0 ) return pIn;
    ++    if( pIn==0 ) pOut[1] = 2;
    ++    pIn = pOut;
    ++    pIn[0] = nAlloc;
    ++  }
    ++  i = pIn[1];
    ++  pIn[i] = iVal;
    ++  pIn[i+1] = nInt;
    ++  z = (char*)&pIn[i+2];
    ++  pIn[1] = i+nInt;
    ++  assert( pIn[1]<=pIn[0] );
    ++  memcpy(z, zName, nName);
    ++  z[nName] = 0;
    ++  return pIn;
    ++}
    ++
    ++/*
    ++** Return a pointer to the name of a variable in the given VList that
    ++** has the value iVal.  Or return a NULL if there is no such variable in
    ++** the list
    ++*/
    ++SQLITE_PRIVATE const char *sqlite3VListNumToName(VList *pIn, int iVal){
    ++  int i, mx;
    ++  if( pIn==0 ) return 0;
    ++  mx = pIn[1];
    ++  i = 2;
    ++  do{
    ++    if( pIn[i]==iVal ) return (char*)&pIn[i+2];
    ++    i += pIn[i+1];
    ++  }while( i<mx );
    ++  return 0;
    ++}
    ++
    ++/*
    ++** Return the number of the variable named zName, if it is in VList.
    ++** or return 0 if there is no such variable.
    ++*/
    ++SQLITE_PRIVATE int sqlite3VListNameToNum(VList *pIn, const char *zName, int nName){
    ++  int i, mx;
    ++  if( pIn==0 ) return 0;
    ++  mx = pIn[1];
    ++  i = 2;
    ++  do{
    ++    const char *z = (const char*)&pIn[i+2];
    ++    if( strncmp(z,zName,nName)==0 && z[nName]==0 ) return pIn[i];
    ++    i += pIn[i+1];
    ++  }while( i<mx );
    ++  return 0;
    + }
    + 
    + /************** End of util.c ************************************************/
    +@@ -26032,8 +30140,12 @@ SQLITE_PRIVATE void sqlite3HashClear(Hash *pH){
    + static unsigned int strHash(const char *z){
    +   unsigned int h = 0;
    +   unsigned char c;
    +-  while( (c = (unsigned char)*z++)!=0 ){
    +-    h = (h<<3) ^ h ^ sqlite3UpperToLower[c];
    ++  while( (c = (unsigned char)*z++)!=0 ){     /*OPTIMIZATION-IF-TRUE*/
    ++    /* Knuth multiplicative hashing.  (Sorting & Searching, p. 510).
    ++    ** 0x9e3779b1 is 2654435761 which is the closest prime number to
    ++    ** (2**32)*golden_ratio, where golden_ratio = (sqrt(5) - 1)/2. */
    ++    h += sqlite3UpperToLower[c];
    ++    h *= 0x9e3779b1;
    +   }
    +   return h;
    + }
    +@@ -26113,8 +30225,9 @@ static int rehash(Hash *pH, unsigned int new_size){
    + }
    + 
    + /* This function (for internal use only) locates an element in an
    +-** hash table that matches the given key.  The hash for this key is
    +-** also computed and returned in the *pH parameter.
    ++** hash table that matches the given key.  If no element is found,
    ++** a pointer to a static null element with HashElem.data==0 is returned.
    ++** If pH is not NULL, then the hash for this key is written to *pH.
    + */
    + static HashElem *findElementWithHash(
    +   const Hash *pH,     /* The pH to be searched */
    +@@ -26124,8 +30237,9 @@ static HashElem *findElementWithHash(
    +   HashElem *elem;                /* Used to loop thru the element list */
    +   int count;                     /* Number of elements left to test */
    +   unsigned int h;                /* The computed hash */
    ++  static HashElem nullElement = { 0, 0, 0, 0 };
    + 
    +-  if( pH->ht ){
    ++  if( pH->ht ){   /*OPTIMIZATION-IF-TRUE*/
    +     struct _ht *pEntry;
    +     h = strHash(pKey) % pH->htsize;
    +     pEntry = &pH->ht[h];
    +@@ -26136,7 +30250,7 @@ static HashElem *findElementWithHash(
    +     elem = pH->first;
    +     count = pH->count;
    +   }
    +-  *pHash = h;
    ++  if( pHash ) *pHash = h;
    +   while( count-- ){
    +     assert( elem!=0 );
    +     if( sqlite3StrICmp(elem->pKey,pKey)==0 ){ 
    +@@ -26144,7 +30258,7 @@ static HashElem *findElementWithHash(
    +     }
    +     elem = elem->next;
    +   }
    +-  return 0;
    ++  return &nullElement;
    + }
    + 
    + /* Remove a single entry from the hash table given a pointer to that
    +@@ -26186,13 +30300,9 @@ static void removeElementGivenHash(
    + ** found, or NULL if there is no match.
    + */
    + SQLITE_PRIVATE void *sqlite3HashFind(const Hash *pH, const char *pKey){
    +-  HashElem *elem;    /* The element that matches key */
    +-  unsigned int h;    /* A hash on key */
    +-
    +   assert( pH!=0 );
    +   assert( pKey!=0 );
    +-  elem = findElementWithHash(pH, pKey, &h);
    +-  return elem ? elem->data : 0;
    ++  return findElementWithHash(pH, pKey, 0)->data;
    + }
    + 
    + /* Insert an element into the hash table pH.  The key is pKey
    +@@ -26217,7 +30327,7 @@ SQLITE_PRIVATE void *sqlite3HashInsert(Hash *pH, const char *pKey, void *data){
    +   assert( pH!=0 );
    +   assert( pKey!=0 );
    +   elem = findElementWithHash(pH,pKey,&h);
    +-  if( elem ){
    ++  if( elem->data ){
    +     void *old_data = elem->data;
    +     if( data==0 ){
    +       removeElementGivenHash(pH,elem,h);
    +@@ -26246,175 +30356,187 @@ SQLITE_PRIVATE void *sqlite3HashInsert(Hash *pH, const char *pKey, void *data){
    + /************** End of hash.c ************************************************/
    + /************** Begin file opcodes.c *****************************************/
    + /* Automatically generated.  Do not edit */
    +-/* See the mkopcodec.awk script for details. */
    +-#if !defined(SQLITE_OMIT_EXPLAIN) || defined(VDBE_PROFILE) || defined(SQLITE_DEBUG)
    ++/* See the tool/mkopcodec.tcl script for details. */
    ++#if !defined(SQLITE_OMIT_EXPLAIN) \
    ++ || defined(VDBE_PROFILE) \
    ++ || defined(SQLITE_DEBUG)
    + #if defined(SQLITE_ENABLE_EXPLAIN_COMMENTS) || defined(SQLITE_DEBUG)
    + # define OpHelp(X) "\0" X
    + #else
    + # define OpHelp(X)
    + #endif
    + SQLITE_PRIVATE const char *sqlite3OpcodeName(int i){
    +- static const char *const azName[] = { "?",
    +-     /*   1 */ "Savepoint"        OpHelp(""),
    +-     /*   2 */ "AutoCommit"       OpHelp(""),
    +-     /*   3 */ "Transaction"      OpHelp(""),
    +-     /*   4 */ "SorterNext"       OpHelp(""),
    +-     /*   5 */ "PrevIfOpen"       OpHelp(""),
    +-     /*   6 */ "NextIfOpen"       OpHelp(""),
    +-     /*   7 */ "Prev"             OpHelp(""),
    +-     /*   8 */ "Next"             OpHelp(""),
    +-     /*   9 */ "Checkpoint"       OpHelp(""),
    +-     /*  10 */ "JournalMode"      OpHelp(""),
    +-     /*  11 */ "Vacuum"           OpHelp(""),
    +-     /*  12 */ "VFilter"          OpHelp("iplan=r[P3] zplan='P4'"),
    +-     /*  13 */ "VUpdate"          OpHelp("data=r[P3@P2]"),
    +-     /*  14 */ "Goto"             OpHelp(""),
    +-     /*  15 */ "Gosub"            OpHelp(""),
    +-     /*  16 */ "Return"           OpHelp(""),
    +-     /*  17 */ "InitCoroutine"    OpHelp(""),
    +-     /*  18 */ "EndCoroutine"     OpHelp(""),
    +-     /*  19 */ "Not"              OpHelp("r[P2]= !r[P1]"),
    +-     /*  20 */ "Yield"            OpHelp(""),
    +-     /*  21 */ "HaltIfNull"       OpHelp("if r[P3]=null halt"),
    +-     /*  22 */ "Halt"             OpHelp(""),
    +-     /*  23 */ "Integer"          OpHelp("r[P2]=P1"),
    +-     /*  24 */ "Int64"            OpHelp("r[P2]=P4"),
    +-     /*  25 */ "String"           OpHelp("r[P2]='P4' (len=P1)"),
    +-     /*  26 */ "Null"             OpHelp("r[P2..P3]=NULL"),
    +-     /*  27 */ "SoftNull"         OpHelp("r[P1]=NULL"),
    +-     /*  28 */ "Blob"             OpHelp("r[P2]=P4 (len=P1)"),
    +-     /*  29 */ "Variable"         OpHelp("r[P2]=parameter(P1,P4)"),
    +-     /*  30 */ "Move"             OpHelp("r[P2@P3]=r[P1@P3]"),
    +-     /*  31 */ "Copy"             OpHelp("r[P2@P3+1]=r[P1@P3+1]"),
    +-     /*  32 */ "SCopy"            OpHelp("r[P2]=r[P1]"),
    +-     /*  33 */ "ResultRow"        OpHelp("output=r[P1@P2]"),
    +-     /*  34 */ "CollSeq"          OpHelp(""),
    +-     /*  35 */ "Function0"        OpHelp("r[P3]=func(r[P2@P5])"),
    +-     /*  36 */ "Function"         OpHelp("r[P3]=func(r[P2@P5])"),
    +-     /*  37 */ "AddImm"           OpHelp("r[P1]=r[P1]+P2"),
    +-     /*  38 */ "MustBeInt"        OpHelp(""),
    +-     /*  39 */ "RealAffinity"     OpHelp(""),
    +-     /*  40 */ "Cast"             OpHelp("affinity(r[P1])"),
    +-     /*  41 */ "Permutation"      OpHelp(""),
    +-     /*  42 */ "Compare"          OpHelp("r[P1@P3] <-> r[P2@P3]"),
    +-     /*  43 */ "Jump"             OpHelp(""),
    +-     /*  44 */ "Once"             OpHelp(""),
    +-     /*  45 */ "If"               OpHelp(""),
    +-     /*  46 */ "IfNot"            OpHelp(""),
    +-     /*  47 */ "Column"           OpHelp("r[P3]=PX"),
    +-     /*  48 */ "Affinity"         OpHelp("affinity(r[P1@P2])"),
    +-     /*  49 */ "MakeRecord"       OpHelp("r[P3]=mkrec(r[P1@P2])"),
    +-     /*  50 */ "Count"            OpHelp("r[P2]=count()"),
    +-     /*  51 */ "ReadCookie"       OpHelp(""),
    +-     /*  52 */ "SetCookie"        OpHelp(""),
    +-     /*  53 */ "ReopenIdx"        OpHelp("root=P2 iDb=P3"),
    +-     /*  54 */ "OpenRead"         OpHelp("root=P2 iDb=P3"),
    +-     /*  55 */ "OpenWrite"        OpHelp("root=P2 iDb=P3"),
    +-     /*  56 */ "OpenAutoindex"    OpHelp("nColumn=P2"),
    +-     /*  57 */ "OpenEphemeral"    OpHelp("nColumn=P2"),
    +-     /*  58 */ "SorterOpen"       OpHelp(""),
    +-     /*  59 */ "SequenceTest"     OpHelp("if( cursor[P1].ctr++ ) pc = P2"),
    +-     /*  60 */ "OpenPseudo"       OpHelp("P3 columns in r[P2]"),
    +-     /*  61 */ "Close"            OpHelp(""),
    +-     /*  62 */ "ColumnsUsed"      OpHelp(""),
    +-     /*  63 */ "SeekLT"           OpHelp("key=r[P3@P4]"),
    +-     /*  64 */ "SeekLE"           OpHelp("key=r[P3@P4]"),
    +-     /*  65 */ "SeekGE"           OpHelp("key=r[P3@P4]"),
    +-     /*  66 */ "SeekGT"           OpHelp("key=r[P3@P4]"),
    +-     /*  67 */ "Seek"             OpHelp("intkey=r[P2]"),
    +-     /*  68 */ "NoConflict"       OpHelp("key=r[P3@P4]"),
    +-     /*  69 */ "NotFound"         OpHelp("key=r[P3@P4]"),
    +-     /*  70 */ "Found"            OpHelp("key=r[P3@P4]"),
    +-     /*  71 */ "Or"               OpHelp("r[P3]=(r[P1] || r[P2])"),
    +-     /*  72 */ "And"              OpHelp("r[P3]=(r[P1] && r[P2])"),
    +-     /*  73 */ "NotExists"        OpHelp("intkey=r[P3]"),
    +-     /*  74 */ "Sequence"         OpHelp("r[P2]=cursor[P1].ctr++"),
    +-     /*  75 */ "NewRowid"         OpHelp("r[P2]=rowid"),
    +-     /*  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"),
    +-     /*  79 */ "Eq"               OpHelp("if r[P1]==r[P3] goto P2"),
    +-     /*  80 */ "Gt"               OpHelp("if r[P1]>r[P3] goto P2"),
    +-     /*  81 */ "Le"               OpHelp("if r[P1]<=r[P3] goto P2"),
    +-     /*  82 */ "Lt"               OpHelp("if r[P1]<r[P3] goto P2"),
    +-     /*  83 */ "Ge"               OpHelp("if r[P1]>=r[P3] goto P2"),
    +-     /*  84 */ "Insert"           OpHelp("intkey=r[P3] data=r[P2]"),
    +-     /*  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]<<r[P1]"),
    +-     /*  88 */ "ShiftRight"       OpHelp("r[P3]=r[P2]>>r[P1]"),
    +-     /*  89 */ "Add"              OpHelp("r[P3]=r[P1]+r[P2]"),
    +-     /*  90 */ "Subtract"         OpHelp("r[P3]=r[P2]-r[P1]"),
    +-     /*  91 */ "Multiply"         OpHelp("r[P3]=r[P1]*r[P2]"),
    +-     /*  92 */ "Divide"           OpHelp("r[P3]=r[P2]/r[P1]"),
    +-     /*  93 */ "Remainder"        OpHelp("r[P3]=r[P2]%r[P1]"),
    +-     /*  94 */ "Concat"           OpHelp("r[P3]=r[P2]+r[P1]"),
    +-     /*  95 */ "InsertInt"        OpHelp("intkey=P3 data=r[P2]"),
    +-     /*  96 */ "BitNot"           OpHelp("r[P1]= ~r[P1]"),
    +-     /*  97 */ "String8"          OpHelp("r[P2]='P4'"),
    +-     /*  98 */ "Delete"           OpHelp(""),
    +-     /*  99 */ "ResetCount"       OpHelp(""),
    +-     /* 100 */ "SorterCompare"    OpHelp("if key(P1)!=trim(r[P3],P4) goto P2"),
    +-     /* 101 */ "SorterData"       OpHelp("r[P2]=data"),
    +-     /* 102 */ "RowKey"           OpHelp("r[P2]=key"),
    +-     /* 103 */ "RowData"          OpHelp("r[P2]=data"),
    +-     /* 104 */ "Rowid"            OpHelp("r[P2]=rowid"),
    +-     /* 105 */ "NullRow"          OpHelp(""),
    +-     /* 106 */ "Last"             OpHelp(""),
    +-     /* 107 */ "SorterSort"       OpHelp(""),
    +-     /* 108 */ "Sort"             OpHelp(""),
    +-     /* 109 */ "Rewind"           OpHelp(""),
    +-     /* 110 */ "SorterInsert"     OpHelp(""),
    +-     /* 111 */ "IdxInsert"        OpHelp("key=r[P2]"),
    +-     /* 112 */ "IdxDelete"        OpHelp("key=r[P2@P3]"),
    +-     /* 113 */ "IdxRowid"         OpHelp("r[P2]=rowid"),
    +-     /* 114 */ "IdxLE"            OpHelp("key=r[P3@P4]"),
    +-     /* 115 */ "IdxGT"            OpHelp("key=r[P3@P4]"),
    +-     /* 116 */ "IdxLT"            OpHelp("key=r[P3@P4]"),
    +-     /* 117 */ "IdxGE"            OpHelp("key=r[P3@P4]"),
    +-     /* 118 */ "Destroy"          OpHelp(""),
    +-     /* 119 */ "Clear"            OpHelp(""),
    +-     /* 120 */ "ResetSorter"      OpHelp(""),
    +-     /* 121 */ "CreateIndex"      OpHelp("r[P2]=root iDb=P1"),
    +-     /* 122 */ "CreateTable"      OpHelp("r[P2]=root iDb=P1"),
    +-     /* 123 */ "ParseSchema"      OpHelp(""),
    +-     /* 124 */ "LoadAnalysis"     OpHelp(""),
    +-     /* 125 */ "DropTable"        OpHelp(""),
    +-     /* 126 */ "DropIndex"        OpHelp(""),
    +-     /* 127 */ "DropTrigger"      OpHelp(""),
    +-     /* 128 */ "IntegrityCk"      OpHelp(""),
    +-     /* 129 */ "RowSetAdd"        OpHelp("rowset(P1)=r[P2]"),
    +-     /* 130 */ "RowSetRead"       OpHelp("r[P3]=rowset(P1)"),
    +-     /* 131 */ "RowSetTest"       OpHelp("if r[P3] in rowset(P1) goto P2"),
    +-     /* 132 */ "Program"          OpHelp(""),
    +-     /* 133 */ "Real"             OpHelp("r[P2]=P4"),
    +-     /* 134 */ "Param"            OpHelp(""),
    +-     /* 135 */ "FkCounter"        OpHelp("fkctr[P1]+=P2"),
    +-     /* 136 */ "FkIfZero"         OpHelp("if fkctr[P1]==0 goto P2"),
    +-     /* 137 */ "MemMax"           OpHelp("r[P1]=max(r[P1],r[P2])"),
    +-     /* 138 */ "IfPos"            OpHelp("if r[P1]>0 then r[P1]-=P3, goto P2"),
    +-     /* 139 */ "SetIfNotPos"      OpHelp("if r[P1]<=0 then r[P2]=P3"),
    +-     /* 140 */ "IfNotZero"        OpHelp("if r[P1]!=0 then r[P1]-=P3, goto P2"),
    +-     /* 141 */ "DecrJumpZero"     OpHelp("if (--r[P1])==0 goto P2"),
    +-     /* 142 */ "JumpZeroIncr"     OpHelp("if (r[P1]++)==0 ) goto P2"),
    +-     /* 143 */ "AggStep0"         OpHelp("accum=r[P3] step(r[P2@P5])"),
    +-     /* 144 */ "AggStep"          OpHelp("accum=r[P3] step(r[P2@P5])"),
    +-     /* 145 */ "AggFinal"         OpHelp("accum=r[P1] N=P2"),
    +-     /* 146 */ "IncrVacuum"       OpHelp(""),
    +-     /* 147 */ "Expire"           OpHelp(""),
    +-     /* 148 */ "TableLock"        OpHelp("iDb=P1 root=P2 write=P3"),
    +-     /* 149 */ "VBegin"           OpHelp(""),
    +-     /* 150 */ "VCreate"          OpHelp(""),
    +-     /* 151 */ "VDestroy"         OpHelp(""),
    +-     /* 152 */ "VOpen"            OpHelp(""),
    +-     /* 153 */ "VColumn"          OpHelp("r[P3]=vcolumn(P2)"),
    +-     /* 154 */ "VNext"            OpHelp(""),
    +-     /* 155 */ "VRename"          OpHelp(""),
    +-     /* 156 */ "Pagecount"        OpHelp(""),
    +-     /* 157 */ "MaxPgcnt"         OpHelp(""),
    +-     /* 158 */ "Init"             OpHelp("Start at P2"),
    +-     /* 159 */ "Noop"             OpHelp(""),
    +-     /* 160 */ "Explain"          OpHelp(""),
    ++ static const char *const azName[] = {
    ++    /*   0 */ "Savepoint"        OpHelp(""),
    ++    /*   1 */ "AutoCommit"       OpHelp(""),
    ++    /*   2 */ "Transaction"      OpHelp(""),
    ++    /*   3 */ "SorterNext"       OpHelp(""),
    ++    /*   4 */ "PrevIfOpen"       OpHelp(""),
    ++    /*   5 */ "NextIfOpen"       OpHelp(""),
    ++    /*   6 */ "Prev"             OpHelp(""),
    ++    /*   7 */ "Next"             OpHelp(""),
    ++    /*   8 */ "Checkpoint"       OpHelp(""),
    ++    /*   9 */ "JournalMode"      OpHelp(""),
    ++    /*  10 */ "Vacuum"           OpHelp(""),
    ++    /*  11 */ "VFilter"          OpHelp("iplan=r[P3] zplan='P4'"),
    ++    /*  12 */ "VUpdate"          OpHelp("data=r[P3@P2]"),
    ++    /*  13 */ "Goto"             OpHelp(""),
    ++    /*  14 */ "Gosub"            OpHelp(""),
    ++    /*  15 */ "InitCoroutine"    OpHelp(""),
    ++    /*  16 */ "Yield"            OpHelp(""),
    ++    /*  17 */ "MustBeInt"        OpHelp(""),
    ++    /*  18 */ "Jump"             OpHelp(""),
    ++    /*  19 */ "Not"              OpHelp("r[P2]= !r[P1]"),
    ++    /*  20 */ "Once"             OpHelp(""),
    ++    /*  21 */ "If"               OpHelp(""),
    ++    /*  22 */ "IfNot"            OpHelp(""),
    ++    /*  23 */ "IfNullRow"        OpHelp("if P1.nullRow then r[P3]=NULL, goto P2"),
    ++    /*  24 */ "SeekLT"           OpHelp("key=r[P3@P4]"),
    ++    /*  25 */ "SeekLE"           OpHelp("key=r[P3@P4]"),
    ++    /*  26 */ "SeekGE"           OpHelp("key=r[P3@P4]"),
    ++    /*  27 */ "SeekGT"           OpHelp("key=r[P3@P4]"),
    ++    /*  28 */ "NoConflict"       OpHelp("key=r[P3@P4]"),
    ++    /*  29 */ "NotFound"         OpHelp("key=r[P3@P4]"),
    ++    /*  30 */ "Found"            OpHelp("key=r[P3@P4]"),
    ++    /*  31 */ "SeekRowid"        OpHelp("intkey=r[P3]"),
    ++    /*  32 */ "NotExists"        OpHelp("intkey=r[P3]"),
    ++    /*  33 */ "Last"             OpHelp(""),
    ++    /*  34 */ "IfSmaller"        OpHelp(""),
    ++    /*  35 */ "SorterSort"       OpHelp(""),
    ++    /*  36 */ "Sort"             OpHelp(""),
    ++    /*  37 */ "Rewind"           OpHelp(""),
    ++    /*  38 */ "IdxLE"            OpHelp("key=r[P3@P4]"),
    ++    /*  39 */ "IdxGT"            OpHelp("key=r[P3@P4]"),
    ++    /*  40 */ "IdxLT"            OpHelp("key=r[P3@P4]"),
    ++    /*  41 */ "IdxGE"            OpHelp("key=r[P3@P4]"),
    ++    /*  42 */ "RowSetRead"       OpHelp("r[P3]=rowset(P1)"),
    ++    /*  43 */ "Or"               OpHelp("r[P3]=(r[P1] || r[P2])"),
    ++    /*  44 */ "And"              OpHelp("r[P3]=(r[P1] && r[P2])"),
    ++    /*  45 */ "RowSetTest"       OpHelp("if r[P3] in rowset(P1) goto P2"),
    ++    /*  46 */ "Program"          OpHelp(""),
    ++    /*  47 */ "FkIfZero"         OpHelp("if fkctr[P1]==0 goto P2"),
    ++    /*  48 */ "IfPos"            OpHelp("if r[P1]>0 then r[P1]-=P3, goto P2"),
    ++    /*  49 */ "IfNotZero"        OpHelp("if r[P1]!=0 then r[P1]--, goto P2"),
    ++    /*  50 */ "IsNull"           OpHelp("if r[P1]==NULL goto P2"),
    ++    /*  51 */ "NotNull"          OpHelp("if r[P1]!=NULL goto P2"),
    ++    /*  52 */ "Ne"               OpHelp("IF r[P3]!=r[P1]"),
    ++    /*  53 */ "Eq"               OpHelp("IF r[P3]==r[P1]"),
    ++    /*  54 */ "Gt"               OpHelp("IF r[P3]>r[P1]"),
    ++    /*  55 */ "Le"               OpHelp("IF r[P3]<=r[P1]"),
    ++    /*  56 */ "Lt"               OpHelp("IF r[P3]<r[P1]"),
    ++    /*  57 */ "Ge"               OpHelp("IF r[P3]>=r[P1]"),
    ++    /*  58 */ "ElseNotEq"        OpHelp(""),
    ++    /*  59 */ "DecrJumpZero"     OpHelp("if (--r[P1])==0 goto P2"),
    ++    /*  60 */ "IncrVacuum"       OpHelp(""),
    ++    /*  61 */ "VNext"            OpHelp(""),
    ++    /*  62 */ "Init"             OpHelp("Start at P2"),
    ++    /*  63 */ "Return"           OpHelp(""),
    ++    /*  64 */ "EndCoroutine"     OpHelp(""),
    ++    /*  65 */ "HaltIfNull"       OpHelp("if r[P3]=null halt"),
    ++    /*  66 */ "Halt"             OpHelp(""),
    ++    /*  67 */ "Integer"          OpHelp("r[P2]=P1"),
    ++    /*  68 */ "Int64"            OpHelp("r[P2]=P4"),
    ++    /*  69 */ "String"           OpHelp("r[P2]='P4' (len=P1)"),
    ++    /*  70 */ "Null"             OpHelp("r[P2..P3]=NULL"),
    ++    /*  71 */ "SoftNull"         OpHelp("r[P1]=NULL"),
    ++    /*  72 */ "Blob"             OpHelp("r[P2]=P4 (len=P1)"),
    ++    /*  73 */ "Variable"         OpHelp("r[P2]=parameter(P1,P4)"),
    ++    /*  74 */ "Move"             OpHelp("r[P2@P3]=r[P1@P3]"),
    ++    /*  75 */ "Copy"             OpHelp("r[P2@P3+1]=r[P1@P3+1]"),
    ++    /*  76 */ "SCopy"            OpHelp("r[P2]=r[P1]"),
    ++    /*  77 */ "IntCopy"          OpHelp("r[P2]=r[P1]"),
    ++    /*  78 */ "ResultRow"        OpHelp("output=r[P1@P2]"),
    ++    /*  79 */ "CollSeq"          OpHelp(""),
    ++    /*  80 */ "AddImm"           OpHelp("r[P1]=r[P1]+P2"),
    ++    /*  81 */ "RealAffinity"     OpHelp(""),
    ++    /*  82 */ "Cast"             OpHelp("affinity(r[P1])"),
    ++    /*  83 */ "Permutation"      OpHelp(""),
    ++    /*  84 */ "BitAnd"           OpHelp("r[P3]=r[P1]&r[P2]"),
    ++    /*  85 */ "BitOr"            OpHelp("r[P3]=r[P1]|r[P2]"),
    ++    /*  86 */ "ShiftLeft"        OpHelp("r[P3]=r[P2]<<r[P1]"),
    ++    /*  87 */ "ShiftRight"       OpHelp("r[P3]=r[P2]>>r[P1]"),
    ++    /*  88 */ "Add"              OpHelp("r[P3]=r[P1]+r[P2]"),
    ++    /*  89 */ "Subtract"         OpHelp("r[P3]=r[P2]-r[P1]"),
    ++    /*  90 */ "Multiply"         OpHelp("r[P3]=r[P1]*r[P2]"),
    ++    /*  91 */ "Divide"           OpHelp("r[P3]=r[P2]/r[P1]"),
    ++    /*  92 */ "Remainder"        OpHelp("r[P3]=r[P2]%r[P1]"),
    ++    /*  93 */ "Concat"           OpHelp("r[P3]=r[P2]+r[P1]"),
    ++    /*  94 */ "Compare"          OpHelp("r[P1@P3] <-> r[P2@P3]"),
    ++    /*  95 */ "BitNot"           OpHelp("r[P1]= ~r[P1]"),
    ++    /*  96 */ "Offset"           OpHelp("r[P3] = sqlite_offset(P1)"),
    ++    /*  97 */ "String8"          OpHelp("r[P2]='P4'"),
    ++    /*  98 */ "Column"           OpHelp("r[P3]=PX"),
    ++    /*  99 */ "Affinity"         OpHelp("affinity(r[P1@P2])"),
    ++    /* 100 */ "MakeRecord"       OpHelp("r[P3]=mkrec(r[P1@P2])"),
    ++    /* 101 */ "Count"            OpHelp("r[P2]=count()"),
    ++    /* 102 */ "ReadCookie"       OpHelp(""),
    ++    /* 103 */ "SetCookie"        OpHelp(""),
    ++    /* 104 */ "ReopenIdx"        OpHelp("root=P2 iDb=P3"),
    ++    /* 105 */ "OpenRead"         OpHelp("root=P2 iDb=P3"),
    ++    /* 106 */ "OpenWrite"        OpHelp("root=P2 iDb=P3"),
    ++    /* 107 */ "OpenDup"          OpHelp(""),
    ++    /* 108 */ "OpenAutoindex"    OpHelp("nColumn=P2"),
    ++    /* 109 */ "OpenEphemeral"    OpHelp("nColumn=P2"),
    ++    /* 110 */ "SorterOpen"       OpHelp(""),
    ++    /* 111 */ "SequenceTest"     OpHelp("if( cursor[P1].ctr++ ) pc = P2"),
    ++    /* 112 */ "OpenPseudo"       OpHelp("P3 columns in r[P2]"),
    ++    /* 113 */ "Close"            OpHelp(""),
    ++    /* 114 */ "ColumnsUsed"      OpHelp(""),
    ++    /* 115 */ "Sequence"         OpHelp("r[P2]=cursor[P1].ctr++"),
    ++    /* 116 */ "NewRowid"         OpHelp("r[P2]=rowid"),
    ++    /* 117 */ "Insert"           OpHelp("intkey=r[P3] data=r[P2]"),
    ++    /* 118 */ "InsertInt"        OpHelp("intkey=P3 data=r[P2]"),
    ++    /* 119 */ "Delete"           OpHelp(""),
    ++    /* 120 */ "ResetCount"       OpHelp(""),
    ++    /* 121 */ "SorterCompare"    OpHelp("if key(P1)!=trim(r[P3],P4) goto P2"),
    ++    /* 122 */ "SorterData"       OpHelp("r[P2]=data"),
    ++    /* 123 */ "RowData"          OpHelp("r[P2]=data"),
    ++    /* 124 */ "Rowid"            OpHelp("r[P2]=rowid"),
    ++    /* 125 */ "NullRow"          OpHelp(""),
    ++    /* 126 */ "SeekEnd"          OpHelp(""),
    ++    /* 127 */ "SorterInsert"     OpHelp("key=r[P2]"),
    ++    /* 128 */ "IdxInsert"        OpHelp("key=r[P2]"),
    ++    /* 129 */ "IdxDelete"        OpHelp("key=r[P2@P3]"),
    ++    /* 130 */ "DeferredSeek"     OpHelp("Move P3 to P1.rowid if needed"),
    ++    /* 131 */ "IdxRowid"         OpHelp("r[P2]=rowid"),
    ++    /* 132 */ "Real"             OpHelp("r[P2]=P4"),
    ++    /* 133 */ "Destroy"          OpHelp(""),
    ++    /* 134 */ "Clear"            OpHelp(""),
    ++    /* 135 */ "ResetSorter"      OpHelp(""),
    ++    /* 136 */ "CreateBtree"      OpHelp("r[P2]=root iDb=P1 flags=P3"),
    ++    /* 137 */ "SqlExec"          OpHelp(""),
    ++    /* 138 */ "ParseSchema"      OpHelp(""),
    ++    /* 139 */ "LoadAnalysis"     OpHelp(""),
    ++    /* 140 */ "DropTable"        OpHelp(""),
    ++    /* 141 */ "DropIndex"        OpHelp(""),
    ++    /* 142 */ "DropTrigger"      OpHelp(""),
    ++    /* 143 */ "IntegrityCk"      OpHelp(""),
    ++    /* 144 */ "RowSetAdd"        OpHelp("rowset(P1)=r[P2]"),
    ++    /* 145 */ "Param"            OpHelp(""),
    ++    /* 146 */ "FkCounter"        OpHelp("fkctr[P1]+=P2"),
    ++    /* 147 */ "MemMax"           OpHelp("r[P1]=max(r[P1],r[P2])"),
    ++    /* 148 */ "OffsetLimit"      OpHelp("if r[P1]>0 then r[P2]=r[P1]+max(0,r[P3]) else r[P2]=(-1)"),
    ++    /* 149 */ "AggStep0"         OpHelp("accum=r[P3] step(r[P2@P5])"),
    ++    /* 150 */ "AggStep"          OpHelp("accum=r[P3] step(r[P2@P5])"),
    ++    /* 151 */ "AggFinal"         OpHelp("accum=r[P1] N=P2"),
    ++    /* 152 */ "Expire"           OpHelp(""),
    ++    /* 153 */ "TableLock"        OpHelp("iDb=P1 root=P2 write=P3"),
    ++    /* 154 */ "VBegin"           OpHelp(""),
    ++    /* 155 */ "VCreate"          OpHelp(""),
    ++    /* 156 */ "VDestroy"         OpHelp(""),
    ++    /* 157 */ "VOpen"            OpHelp(""),
    ++    /* 158 */ "VColumn"          OpHelp("r[P3]=vcolumn(P2)"),
    ++    /* 159 */ "VRename"          OpHelp(""),
    ++    /* 160 */ "Pagecount"        OpHelp(""),
    ++    /* 161 */ "MaxPgcnt"         OpHelp(""),
    ++    /* 162 */ "PureFunc0"        OpHelp(""),
    ++    /* 163 */ "Function0"        OpHelp("r[P3]=func(r[P2@P5])"),
    ++    /* 164 */ "PureFunc"         OpHelp(""),
    ++    /* 165 */ "Function"         OpHelp("r[P3]=func(r[P2@P5])"),
    ++    /* 166 */ "Trace"            OpHelp(""),
    ++    /* 167 */ "CursorHint"       OpHelp(""),
    ++    /* 168 */ "Noop"             OpHelp(""),
    ++    /* 169 */ "Explain"          OpHelp(""),
    +   };
    +   return azName[i];
    + }
    +@@ -26470,13 +30592,6 @@ SQLITE_PRIVATE const char *sqlite3OpcodeName(int i){
    + /* #include "sqliteInt.h" */
    + #if SQLITE_OS_UNIX              /* This file is used on unix only */
    + 
    +-/* Use posix_fallocate() if it is available
    +-*/
    +-#if !defined(HAVE_POSIX_FALLOCATE) \
    +-      && (_XOPEN_SOURCE >= 600 || _POSIX_C_SOURCE >= 200112L)
    +-# define HAVE_POSIX_FALLOCATE 1
    +-#endif
    +-
    + /*
    + ** There are various methods for file locking used for concurrency
    + ** control:
    +@@ -26502,12 +30617,26 @@ SQLITE_PRIVATE const char *sqlite3OpcodeName(int i){
    + #  endif
    + #endif
    + 
    ++/* Use pread() and pwrite() if they are available */
    ++#if defined(__APPLE__)
    ++# define HAVE_PREAD 1
    ++# define HAVE_PWRITE 1
    ++#endif
    ++#if defined(HAVE_PREAD64) && defined(HAVE_PWRITE64)
    ++# undef USE_PREAD
    ++# define USE_PREAD64 1
    ++#elif defined(HAVE_PREAD) && defined(HAVE_PWRITE)
    ++# undef USE_PREAD64
    ++# define USE_PREAD 1
    ++#endif
    ++
    + /*
    + ** standard include files.
    + */
    + #include <sys/types.h>
    + #include <sys/stat.h>
    + #include <fcntl.h>
    ++#include <sys/ioctl.h>
    + #include <unistd.h>
    + /* #include <time.h> */
    + #include <sys/time.h>
    +@@ -26517,7 +30646,7 @@ SQLITE_PRIVATE const char *sqlite3OpcodeName(int i){
    + #endif
    + 
    + #if SQLITE_ENABLE_LOCKING_STYLE
    +-# include <sys/ioctl.h>
    ++/* # include <sys/ioctl.h> */
    + # include <sys/file.h>
    + # include <sys/param.h>
    + #endif /* SQLITE_ENABLE_LOCKING_STYLE */
    +@@ -26580,6 +30709,11 @@ SQLITE_PRIVATE const char *sqlite3OpcodeName(int i){
    + */
    + #define MAX_PATHNAME 512
    + 
    ++/*
    ++** Maximum supported symbolic links
    ++*/
    ++#define SQLITE_MAX_SYMLINKS 100
    ++
    + /* Always cast the getpid() return type for compatibility with
    + ** kernel modules in VxWorks. */
    + #define osGetpid(X) (pid_t)getpid()
    +@@ -26622,7 +30756,7 @@ struct unixFile {
    +   unsigned short int ctrlFlags;       /* Behavioral bits.  UNIXFILE_* flags */
    +   int lastErrno;                      /* The unix errno from last I/O error */
    +   void *lockingContext;               /* Locking style specific state */
    +-  UnixUnusedFd *pUnused;              /* Pre-allocated UnixUnusedFd */
    ++  UnixUnusedFd *pPreallocatedUnused;  /* Pre-allocated UnixUnusedFd */
    +   const char *zPath;                  /* Name of the file */
    +   unixShm *pShm;                      /* Shared memory segment information */
    +   int szChunk;                        /* Configured by FCNTL_CHUNK_SIZE */
    +@@ -26633,10 +30767,8 @@ struct unixFile {
    +   sqlite3_int64 mmapSizeMax;          /* Configured FCNTL_MMAP_SIZE value */
    +   void *pMapRegion;                   /* Memory mapped region */
    + #endif
    +-#ifdef __QNXNTO__
    +   int sectorSize;                     /* Device sector size */
    +   int deviceCharacteristics;          /* Precomputed device characteristics */
    +-#endif
    + #if SQLITE_ENABLE_LOCKING_STYLE
    +   int openFlags;                      /* The flags specified at open() */
    + #endif
    +@@ -26689,8 +30821,6 @@ static pid_t randomnessPid = 0;
    + #define UNIXFILE_DELETE      0x20     /* Delete on close */
    + #define UNIXFILE_URI         0x40     /* Filename might have query parameters */
    + #define UNIXFILE_NOLOCK      0x80     /* Do no file locking */
    +-#define UNIXFILE_WARNED    0x0100     /* verifyDbFile() warnings issued */
    +-#define UNIXFILE_BLOCK     0x0200     /* Next SHM lock might block */
    + 
    + /*
    + ** Include code that is common to all os_*.c files
    +@@ -26734,8 +30864,8 @@ static pid_t randomnessPid = 0;
    + */
    + #ifdef SQLITE_PERFORMANCE_TRACE
    + 
    +-/* 
    +-** hwtime.h contains inline assembler code for implementing 
    ++/*
    ++** hwtime.h contains inline assembler code for implementing
    + ** high-performance timing routines.
    + */
    + /************** Include hwtime.h in the middle of os_common.h ****************/
    +@@ -26755,8 +30885,8 @@ static pid_t randomnessPid = 0;
    + ** This file contains inline asm code for retrieving "high-performance"
    + ** counters for x86 class CPUs.
    + */
    +-#ifndef _HWTIME_H_
    +-#define _HWTIME_H_
    ++#ifndef SQLITE_HWTIME_H
    ++#define SQLITE_HWTIME_H
    + 
    + /*
    + ** The following routine only works on pentium-class (or newer) processors.
    +@@ -26824,7 +30954,7 @@ SQLITE_PRIVATE   sqlite_uint64 sqlite3Hwtime(void){ return ((sqlite_uint64)0); }
    + 
    + #endif
    + 
    +-#endif /* !defined(_HWTIME_H_) */
    ++#endif /* !defined(SQLITE_HWTIME_H) */
    + 
    + /************** End of hwtime.h **********************************************/
    + /************** Continuing where we left off in os_common.h ******************/
    +@@ -26845,14 +30975,14 @@ static sqlite_uint64 g_elapsed;
    + ** 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;
    ++#if defined(SQLITE_TEST)
    ++SQLITE_API extern int sqlite3_io_error_hit;
    ++SQLITE_API extern int sqlite3_io_error_hardhit;
    ++SQLITE_API extern int sqlite3_io_error_pending;
    ++SQLITE_API extern int sqlite3_io_error_persist;
    ++SQLITE_API extern int sqlite3_io_error_benign;
    ++SQLITE_API extern int sqlite3_diskfull_pending;
    ++SQLITE_API extern int sqlite3_diskfull;
    + #define SimulateIOErrorBenign(X) sqlite3_io_error_benign=(X)
    + #define SimulateIOError(CODE)  \
    +   if( (sqlite3_io_error_persist && sqlite3_io_error_hit) \
    +@@ -26878,17 +31008,17 @@ static void local_ioerr(){
    + #define SimulateIOErrorBenign(X)
    + #define SimulateIOError(A)
    + #define SimulateDiskfullError(A)
    +-#endif
    ++#endif /* defined(SQLITE_TEST) */
    + 
    + /*
    + ** When testing, keep a count of the number of open files.
    + */
    +-#ifdef SQLITE_TEST
    +-SQLITE_API int sqlite3_open_file_count = 0;
    ++#if defined(SQLITE_TEST)
    ++SQLITE_API extern int sqlite3_open_file_count;
    + #define OpenCounter(X)  sqlite3_open_file_count+=(X)
    + #else
    + #define OpenCounter(X)
    +-#endif
    ++#endif /* defined(SQLITE_TEST) */
    + 
    + #endif /* !defined(_OS_COMMON_H_) */
    + 
    +@@ -26941,6 +31071,20 @@ SQLITE_API int sqlite3_open_file_count = 0;
    + # define lseek lseek64
    + #endif
    + 
    ++#ifdef __linux__
    ++/*
    ++** Linux-specific IOCTL magic numbers used for controlling F2FS
    ++*/
    ++#define F2FS_IOCTL_MAGIC        0xf5
    ++#define F2FS_IOC_START_ATOMIC_WRITE     _IO(F2FS_IOCTL_MAGIC, 1)
    ++#define F2FS_IOC_COMMIT_ATOMIC_WRITE    _IO(F2FS_IOCTL_MAGIC, 2)
    ++#define F2FS_IOC_START_VOLATILE_WRITE   _IO(F2FS_IOCTL_MAGIC, 3)
    ++#define F2FS_IOC_ABORT_VOLATILE_WRITE   _IO(F2FS_IOCTL_MAGIC, 5)
    ++#define F2FS_IOC_GET_FEATURES           _IOR(F2FS_IOCTL_MAGIC, 12, u32)
    ++#define F2FS_FEATURE_ATOMIC_WRITE 0x0004
    ++#endif /* __linux__ */
    ++
    ++
    + /*
    + ** Different Unix systems declare open() in different ways.  Same use
    + ** open(const char*,int,mode_t).  Others use open(const char*,int,...).
    +@@ -26953,19 +31097,6 @@ static int posixOpen(const char *zFile, int flags, int mode){
    +   return open(zFile, flags, mode);
    + }
    + 
    +-/*
    +-** On some systems, calls to fchown() will trigger a message in a security
    +-** log if they come from non-root processes.  So avoid calling fchown() if
    +-** 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);
    +@@ -27031,12 +31162,7 @@ static struct unix_syscall {
    + #else
    +   { "pread64",      (sqlite3_syscall_ptr)0,          0  },
    + #endif
    +-#ifdef ANDROID
    +-// Bionic defines pread64 using off64_t rather than off_t.
    +-#define osPread64   ((ssize_t(*)(int,void*,size_t,off64_t))aSyscall[10].pCurrent)
    +-#else
    +-#define osPread64   ((ssize_t(*)(int,void*,size_t,off_t))aSyscall[10].pCurrent)
    +-#endif
    ++#define osPread64 ((ssize_t(*)(int,void*,size_t,off64_t))aSyscall[10].pCurrent)
    + 
    +   { "write",        (sqlite3_syscall_ptr)write,      0  },
    + #define osWrite     ((ssize_t(*)(int,const void*,size_t))aSyscall[11].pCurrent)
    +@@ -27054,16 +31180,10 @@ static struct unix_syscall {
    + #else
    +   { "pwrite64",     (sqlite3_syscall_ptr)0,          0  },
    + #endif
    +-#ifdef ANDROID
    +-// Bionic defines pwrite64 using off64_t rather than off_t.
    + #define osPwrite64  ((ssize_t(*)(int,const void*,size_t,off64_t))\
    +                     aSyscall[13].pCurrent)
    +-#else
    +-#define osPwrite64  ((ssize_t(*)(int,const void*,size_t,off_t))\
    +-                    aSyscall[13].pCurrent)
    +-#endif
    + 
    +-  { "fchmod",       (sqlite3_syscall_ptr)fchmod,     0  },
    ++  { "fchmod",       (sqlite3_syscall_ptr)fchmod,          0  },
    + #define osFchmod    ((int(*)(int,mode_t))aSyscall[14].pCurrent)
    + 
    + #if defined(HAVE_POSIX_FALLOCATE) && HAVE_POSIX_FALLOCATE
    +@@ -27085,29 +31205,81 @@ static struct unix_syscall {
    +   { "rmdir",        (sqlite3_syscall_ptr)rmdir,           0 },
    + #define osRmdir     ((int(*)(const char*))aSyscall[19].pCurrent)
    + 
    +-  { "fchown",       (sqlite3_syscall_ptr)posixFchown,     0 },
    ++#if defined(HAVE_FCHOWN)
    ++  { "fchown",       (sqlite3_syscall_ptr)fchown,          0 },
    ++#else
    ++  { "fchown",       (sqlite3_syscall_ptr)0,               0 },
    ++#endif
    + #define osFchown    ((int(*)(int,uid_t,gid_t))aSyscall[20].pCurrent)
    + 
    ++  { "geteuid",      (sqlite3_syscall_ptr)geteuid,         0 },
    ++#define osGeteuid   ((uid_t(*)(void))aSyscall[21].pCurrent)
    ++
    + #if !defined(SQLITE_OMIT_WAL) || SQLITE_MAX_MMAP_SIZE>0
    +-  { "mmap",       (sqlite3_syscall_ptr)mmap,     0 },
    +-#define osMmap ((void*(*)(void*,size_t,int,int,int,off_t))aSyscall[21].pCurrent)
    ++  { "mmap",         (sqlite3_syscall_ptr)mmap,            0 },
    ++#else
    ++  { "mmap",         (sqlite3_syscall_ptr)0,               0 },
    ++#endif
    ++#define osMmap ((void*(*)(void*,size_t,int,int,int,off_t))aSyscall[22].pCurrent)
    + 
    ++#if !defined(SQLITE_OMIT_WAL) || SQLITE_MAX_MMAP_SIZE>0
    +   { "munmap",       (sqlite3_syscall_ptr)munmap,          0 },
    +-#define osMunmap ((void*(*)(void*,size_t))aSyscall[22].pCurrent)
    ++#else
    ++  { "munmap",       (sqlite3_syscall_ptr)0,               0 },
    ++#endif
    ++#define osMunmap ((int(*)(void*,size_t))aSyscall[23].pCurrent)
    + 
    +-#if HAVE_MREMAP
    ++#if HAVE_MREMAP && (!defined(SQLITE_OMIT_WAL) || SQLITE_MAX_MMAP_SIZE>0)
    +   { "mremap",       (sqlite3_syscall_ptr)mremap,          0 },
    + #else
    +   { "mremap",       (sqlite3_syscall_ptr)0,               0 },
    + #endif
    +-#define osMremap ((void*(*)(void*,size_t,size_t,int,...))aSyscall[23].pCurrent)
    ++#define osMremap ((void*(*)(void*,size_t,size_t,int,...))aSyscall[24].pCurrent)
    ++
    ++#if !defined(SQLITE_OMIT_WAL) || SQLITE_MAX_MMAP_SIZE>0
    +   { "getpagesize",  (sqlite3_syscall_ptr)unixGetpagesize, 0 },
    +-#define osGetpagesize ((int(*)(void))aSyscall[24].pCurrent)
    ++#else
    ++  { "getpagesize",  (sqlite3_syscall_ptr)0,               0 },
    ++#endif
    ++#define osGetpagesize ((int(*)(void))aSyscall[25].pCurrent)
    + 
    ++#if defined(HAVE_READLINK)
    ++  { "readlink",     (sqlite3_syscall_ptr)readlink,        0 },
    ++#else
    ++  { "readlink",     (sqlite3_syscall_ptr)0,               0 },
    + #endif
    ++#define osReadlink ((ssize_t(*)(const char*,char*,size_t))aSyscall[26].pCurrent)
    ++
    ++#if defined(HAVE_LSTAT)
    ++  { "lstat",         (sqlite3_syscall_ptr)lstat,          0 },
    ++#else
    ++  { "lstat",         (sqlite3_syscall_ptr)0,              0 },
    ++#endif
    ++#define osLstat      ((int(*)(const char*,struct stat*))aSyscall[27].pCurrent)
    ++
    ++#if defined(__linux__) && defined(SQLITE_ENABLE_BATCH_ATOMIC_WRITE)
    ++  { "ioctl",         (sqlite3_syscall_ptr)ioctl,          0 },
    ++#else
    ++  { "ioctl",         (sqlite3_syscall_ptr)0,              0 },
    ++#endif
    ++#define osIoctl ((int(*)(int,int,...))aSyscall[28].pCurrent)
    + 
    + }; /* End of the overrideable system calls */
    + 
    ++
    ++/*
    ++** On some systems, calls to fchown() will trigger a message in a security
    ++** log if they come from non-root processes.  So avoid calling fchown() if
    ++** we are not running as root.
    ++*/
    ++static int robustFchown(int fd, uid_t uid, gid_t gid){
    ++#if defined(HAVE_FCHOWN)
    ++  return osGeteuid() ? 0 : osFchown(fd,uid,gid);
    ++#else
    ++  return 0;
    ++#endif
    ++}
    ++
    + /*
    + ** This is the xSetSystemCall() method of sqlite3_vfs for all of the
    + ** "unix" VFSes.  Return SQLITE_OK opon successfully updating the
    +@@ -27392,23 +31564,12 @@ static int robust_ftruncate(int h, sqlite3_int64 sz){
    + ** should handle ENOLCK, ENOTSUP, EOPNOTSUPP separately.
    + */
    + static int sqliteErrorFromPosixError(int posixError, int sqliteIOErr) {
    ++  assert( (sqliteIOErr == SQLITE_IOERR_LOCK) || 
    ++          (sqliteIOErr == SQLITE_IOERR_UNLOCK) || 
    ++          (sqliteIOErr == SQLITE_IOERR_RDLOCK) ||
    ++          (sqliteIOErr == SQLITE_IOERR_CHECKRESERVEDLOCK) );
    +   switch (posixError) {
    +-#if 0
    +-  /* At one point this code was not commented out. In theory, this branch
    +-  ** should never be hit, as this function should only be called after
    +-  ** a locking-related function (i.e. fcntl()) has returned non-zero with
    +-  ** the value of errno as the first argument. Since a system call has failed,
    +-  ** errno should be non-zero.
    +-  **
    +-  ** Despite this, if errno really is zero, we still don't want to return
    +-  ** SQLITE_OK. The system call failed, and *some* SQLite error should be
    +-  ** propagated back to the caller. Commenting this branch out means errno==0
    +-  ** will be handled by the "default:" case below.
    +-  */
    +-  case 0: 
    +-    return SQLITE_OK;
    +-#endif
    +-
    ++  case EACCES: 
    +   case EAGAIN:
    +   case ETIMEDOUT:
    +   case EBUSY:
    +@@ -27418,41 +31579,9 @@ static int sqliteErrorFromPosixError(int posixError, int sqliteIOErr) {
    +      * introspection, in which it actually means what it says */
    +     return SQLITE_BUSY;
    +     
    +-  case EACCES: 
    +-    /* EACCES is like EAGAIN during locking operations, but not any other time*/
    +-    if( (sqliteIOErr == SQLITE_IOERR_LOCK) || 
    +-        (sqliteIOErr == SQLITE_IOERR_UNLOCK) || 
    +-        (sqliteIOErr == SQLITE_IOERR_RDLOCK) ||
    +-        (sqliteIOErr == SQLITE_IOERR_CHECKRESERVEDLOCK) ){
    +-      return SQLITE_BUSY;
    +-    }
    +-    /* else fall through */
    +   case EPERM: 
    +     return SQLITE_PERM;
    +     
    +-#if EOPNOTSUPP!=ENOTSUP
    +-  case EOPNOTSUPP: 
    +-    /* something went terribly awry, unless during file system support 
    +-     * introspection, in which it actually means what it says */
    +-#endif
    +-#ifdef ENOTSUP
    +-  case ENOTSUP: 
    +-    /* invalid fd, unless during file system support introspection, in which 
    +-     * it actually means what it says */
    +-#endif
    +-  case EIO:
    +-  case EBADF:
    +-  case EINVAL:
    +-  case ENOTCONN:
    +-  case ENODEV:
    +-  case ENXIO:
    +-  case ENOENT:
    +-#ifdef ESTALE                     /* ESTALE is not defined on Interix systems */
    +-  case ESTALE:
    +-#endif
    +-  case ENOSYS:
    +-    /* these should force the client to close the file and reconnect */
    +-    
    +   default: 
    +     return sqliteIOErr;
    +   }
    +@@ -27696,7 +31825,14 @@ struct unixFileId {
    + #if OS_VXWORKS
    +   struct vxworksFileId *pId;  /* Unique file ID for vxworks. */
    + #else
    +-  ino_t ino;                  /* Inode number */
    ++  /* We are told that some versions of Android contain a bug that
    ++  ** sizes ino_t at only 32-bits instead of 64-bits. (See
    ++  ** https://android-review.googlesource.com/#/c/115351/3/dist/sqlite3.c)
    ++  ** To work around this, always allocate 64-bits for the inode number.  
    ++  ** On small machines that only have 32-bit inodes, this wastes 4 bytes,
    ++  ** but that should not be a big deal. */
    ++  /* WAS:  ino_t ino;   */
    ++  u64 ino;                   /* Inode number */
    + #endif
    + };
    + 
    +@@ -27732,11 +31868,12 @@ struct unixInodeInfo {
    + /*
    + ** A lists of all unixInodeInfo objects.
    + */
    +-static unixInodeInfo *inodeList = 0;
    ++static unixInodeInfo *inodeList = 0;  /* All unixInodeInfo objects */
    ++static unsigned int nUnusedFd = 0;    /* Total unused file descriptors */
    + 
    + /*
    + **
    +-** This function - unixLogError_x(), is only ever called via the macro
    ++** This function - unixLogErrorAtLine(), is only ever called via the macro
    + ** unixLogError().
    + **
    + ** It is invoked after an error occurs in an OS function and errno has been
    +@@ -27842,6 +31979,7 @@ static void closePendingFds(unixFile *pFile){
    +     pNext = p->pNext;
    +     robust_close(pFile, p->fd, __LINE__);
    +     sqlite3_free(p);
    ++    nUnusedFd--;
    +   }
    +   pInode->pUnused = 0;
    + }
    +@@ -27874,6 +32012,7 @@ static void releaseInodeInfo(unixFile *pFile){
    +       sqlite3_free(pInode);
    +     }
    +   }
    ++  assert( inodeList!=0 || nUnusedFd==0 );
    + }
    + 
    + /*
    +@@ -27905,7 +32044,7 @@ static int findInodeInfo(
    +   rc = osFstat(fd, &statbuf);
    +   if( rc!=0 ){
    +     storeLastErrno(pFile, errno);
    +-#ifdef EOVERFLOW
    ++#if defined(EOVERFLOW) && defined(SQLITE_DISABLE_LFS)
    +     if( pFile->lastErrno==EOVERFLOW ) return SQLITE_NOLFS;
    + #endif
    +     return SQLITE_IOERR;
    +@@ -27941,8 +32080,9 @@ static int findInodeInfo(
    + #if OS_VXWORKS
    +   fileId.pId = pFile->pId;
    + #else
    +-  fileId.ino = statbuf.st_ino;
    ++  fileId.ino = (u64)statbuf.st_ino;
    + #endif
    ++  assert( inodeList!=0 || nUnusedFd==0 );
    +   pInode = inodeList;
    +   while( pInode && memcmp(&fileId, &pInode->fileId, sizeof(fileId)) ){
    +     pInode = pInode->pNext;
    +@@ -27950,7 +32090,7 @@ static int findInodeInfo(
    +   if( pInode==0 ){
    +     pInode = sqlite3_malloc64( sizeof(*pInode) );
    +     if( pInode==0 ){
    +-      return SQLITE_NOMEM;
    ++      return SQLITE_NOMEM_BKPT;
    +     }
    +     memset(pInode, 0, sizeof(*pInode));
    +     memcpy(&pInode->fileId, &fileId, sizeof(fileId));
    +@@ -27975,7 +32115,8 @@ static int fileHasMoved(unixFile *pFile){
    + #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 
    ++         || (u64)buf.st_ino!=pFile->pInode->fileId.ino);
    + #endif
    + }
    + 
    +@@ -27992,30 +32133,25 @@ static int fileHasMoved(unixFile *pFile){
    + static void verifyDbFile(unixFile *pFile){
    +   struct stat buf;
    +   int rc;
    +-  if( pFile->ctrlFlags & UNIXFILE_WARNED ){
    +-    /* One or more of the following warnings have already been issued.  Do not
    +-    ** repeat them so as not to clutter the error log */
    +-    return;
    +-  }
    ++
    ++  /* These verifications occurs for the main database only */
    ++  if( pFile->ctrlFlags & UNIXFILE_NOLOCK ) return;
    ++
    +   rc = osFstat(pFile->h, &buf);
    +   if( rc!=0 ){
    +     sqlite3_log(SQLITE_WARNING, "cannot fstat db file %s", pFile->zPath);
    +-    pFile->ctrlFlags |= UNIXFILE_WARNED;
    +     return;
    +   }
    +-  if( buf.st_nlink==0 && (pFile->ctrlFlags & UNIXFILE_DELETE)==0 ){
    ++  if( buf.st_nlink==0 ){
    +     sqlite3_log(SQLITE_WARNING, "file unlinked while open: %s", pFile->zPath);
    +-    pFile->ctrlFlags |= UNIXFILE_WARNED;
    +     return;
    +   }
    +   if( buf.st_nlink>1 ){
    +     sqlite3_log(SQLITE_WARNING, "multiple links to file: %s", pFile->zPath);
    +-    pFile->ctrlFlags |= UNIXFILE_WARNED;
    +     return;
    +   }
    +   if( fileHasMoved(pFile) ){
    +     sqlite3_log(SQLITE_WARNING, "file renamed while open: %s", pFile->zPath);
    +-    pFile->ctrlFlags |= UNIXFILE_WARNED;
    +     return;
    +   }
    + }
    +@@ -28035,6 +32171,7 @@ static int unixCheckReservedLock(sqlite3_file *id, int *pResOut){
    +   SimulateIOError( return SQLITE_IOERR_CHECKRESERVEDLOCK; );
    + 
    +   assert( pFile );
    ++  assert( pFile->eFileLock<=SHARED_LOCK );
    +   unixEnterMutex(); /* Because pFile->pInode is shared across threads */
    + 
    +   /* Check if a thread in this process holds such a lock */
    +@@ -28091,9 +32228,7 @@ static int unixFileLock(unixFile *pFile, struct flock *pLock){
    +   unixInodeInfo *pInode = pFile->pInode;
    +   assert( unixMutexHeld() );
    +   assert( pInode!=0 );
    +-  if( ((pFile->ctrlFlags & UNIXFILE_EXCL)!=0 || pInode->bProcessLock)
    +-   && ((pFile->ctrlFlags & UNIXFILE_RDONLY)==0)
    +-  ){
    ++  if( (pFile->ctrlFlags & (UNIXFILE_EXCL|UNIXFILE_RDONLY))==UNIXFILE_EXCL ){
    +     if( pInode->bProcessLock==0 ){
    +       struct flock lock;
    +       assert( pInode->nLock==0 );
    +@@ -28143,7 +32278,7 @@ static int unixLock(sqlite3_file *id, int eFileLock){
    +   ** lock transitions in terms of the POSIX advisory shared and exclusive
    +   ** lock primitives (called read-locks and write-locks below, to avoid
    +   ** confusion with SQLite lock names). The algorithms are complicated
    +-  ** slightly in order to be compatible with windows systems simultaneously
    ++  ** slightly in order to be compatible with Windows95 systems simultaneously
    +   ** accessing the same database file, in case that is ever required.
    +   **
    +   ** Symbols defined in os.h indentify the 'pending byte' and the 'reserved
    +@@ -28151,8 +32286,14 @@ static int unixLock(sqlite3_file *id, int eFileLock){
    +   ** range', a range of 510 bytes at a well known offset.
    +   **
    +   ** To obtain a SHARED lock, a read-lock is obtained on the 'pending
    +-  ** byte'.  If this is successful, a random byte from the 'shared byte
    +-  ** range' is read-locked and the lock on the 'pending byte' released.
    ++  ** byte'.  If this is successful, 'shared byte range' is read-locked
    ++  ** and the lock on the 'pending byte' released.  (Legacy note:  When
    ++  ** SQLite was first developed, Windows95 systems were still very common,
    ++  ** and Widnows95 lacks a shared-lock capability.  So on Windows95, a
    ++  ** single randomly selected by from the 'shared byte range' is locked.
    ++  ** Windows95 is now pretty much extinct, but this work-around for the
    ++  ** lack of shared-locks on Windows95 lives on, for backwards
    ++  ** compatibility.)
    +   **
    +   ** A process may only obtain a RESERVED lock after it has a SHARED lock.
    +   ** A RESERVED lock is implemented by grabbing a write-lock on the
    +@@ -28171,11 +32312,6 @@ static int unixLock(sqlite3_file *id, int eFileLock){
    +   ** range'. Since all other locks require a read-lock on one of the bytes
    +   ** within this range, this ensures that no other locks are held on the
    +   ** database. 
    +-  **
    +-  ** The reason a single byte cannot be used instead of the 'shared byte
    +-  ** range' is that some versions of windows do not support read-locks. By
    +-  ** locking a random byte from a range, concurrent SHARED locks may exist
    +-  ** even if the locking primitive used is always a write-lock.
    +   */
    +   int rc = SQLITE_OK;
    +   unixFile *pFile = (unixFile*)id;
    +@@ -28366,11 +32502,12 @@ end_lock:
    + */
    + static void setPendingFd(unixFile *pFile){
    +   unixInodeInfo *pInode = pFile->pInode;
    +-  UnixUnusedFd *p = pFile->pUnused;
    ++  UnixUnusedFd *p = pFile->pPreallocatedUnused;
    +   p->pNext = pInode->pUnused;
    +   pInode->pUnused = p;
    +   pFile->h = -1;
    +-  pFile->pUnused = 0;
    ++  pFile->pPreallocatedUnused = 0;
    ++  nUnusedFd++;
    + }
    + 
    + /*
    +@@ -28445,9 +32582,7 @@ static int posixUnlock(sqlite3_file *id, int eFileLock, int handleNFSUnlock){
    +         if( unixFileLock(pFile, &lock)==(-1) ){
    +           tErrno = errno;
    +           rc = SQLITE_IOERR_UNLOCK;
    +-          if( IS_LOCK_ERROR(rc) ){
    +-            storeLastErrno(pFile, tErrno);
    +-          }
    ++          storeLastErrno(pFile, tErrno);
    +           goto end_unlock;
    +         }
    +         lock.l_type = F_RDLCK;
    +@@ -28469,9 +32604,7 @@ static int posixUnlock(sqlite3_file *id, int eFileLock, int handleNFSUnlock){
    +         if( unixFileLock(pFile, &lock)==(-1) ){
    +           tErrno = errno;
    +           rc = SQLITE_IOERR_UNLOCK;
    +-          if( IS_LOCK_ERROR(rc) ){
    +-            storeLastErrno(pFile, tErrno);
    +-          }
    ++          storeLastErrno(pFile, tErrno);
    +           goto end_unlock;
    +         }
    +       }else
    +@@ -28599,7 +32732,7 @@ static int closeUnixFile(sqlite3_file *id){
    + #endif
    +   OSTRACE(("CLOSE   %-3d\n", pFile->h));
    +   OpenCounter(-1);
    +-  sqlite3_free(pFile->pUnused);
    ++  sqlite3_free(pFile->pPreallocatedUnused);
    +   memset(pFile, 0, sizeof(unixFile));
    +   return SQLITE_OK;
    + }
    +@@ -28722,17 +32855,7 @@ static int dotlockCheckReservedLock(sqlite3_file *id, int *pResOut) {
    +   SimulateIOError( return SQLITE_IOERR_CHECKRESERVEDLOCK; );
    +   
    +   assert( pFile );
    +-
    +-  /* Check if a thread in this process holds such a lock */
    +-  if( pFile->eFileLock>SHARED_LOCK ){
    +-    /* Either this connection or some other connection in the same process
    +-    ** holds a lock on the file.  No need to check further. */
    +-    reserved = 1;
    +-  }else{
    +-    /* The lock is held if and only if the lockfile exists */
    +-    const char *zLockFile = (const char*)pFile->lockingContext;
    +-    reserved = osAccess(zLockFile, 0)==0;
    +-  }
    ++  reserved = osAccess((const char*)pFile->lockingContext, 0)==0;
    +   OSTRACE(("TEST WR-LOCK %d %d %d (dotlock)\n", pFile->h, rc, reserved));
    +   *pResOut = reserved;
    +   return rc;
    +@@ -28794,7 +32917,7 @@ static int dotlockLock(sqlite3_file *id, int eFileLock) {
    +       rc = SQLITE_BUSY;
    +     } else {
    +       rc = sqliteErrorFromPosixError(tErrno, SQLITE_IOERR_LOCK);
    +-      if( IS_LOCK_ERROR(rc) ){
    ++      if( rc!=SQLITE_BUSY ){
    +         storeLastErrno(pFile, tErrno);
    +       }
    +     }
    +@@ -28841,14 +32964,12 @@ static int dotlockUnlock(sqlite3_file *id, int eFileLock) {
    +   /* To fully unlock the database, delete the lock file */
    +   assert( eFileLock==NO_LOCK );
    +   rc = osRmdir(zLockFile);
    +-  if( rc<0 && errno==ENOTDIR ) rc = osUnlink(zLockFile);
    +   if( rc<0 ){
    +     int tErrno = errno;
    +-    rc = 0;
    +-    if( ENOENT != tErrno ){
    ++    if( tErrno==ENOENT ){
    ++      rc = SQLITE_OK;
    ++    }else{
    +       rc = SQLITE_IOERR_UNLOCK;
    +-    }
    +-    if( IS_LOCK_ERROR(rc) ){
    +       storeLastErrno(pFile, tErrno);
    +     }
    +     return rc; 
    +@@ -28861,14 +32982,11 @@ static int dotlockUnlock(sqlite3_file *id, int eFileLock) {
    + ** Close a file.  Make sure the lock has been released before closing.
    + */
    + static int dotlockClose(sqlite3_file *id) {
    +-  int rc = SQLITE_OK;
    +-  if( id ){
    +-    unixFile *pFile = (unixFile*)id;
    +-    dotlockUnlock(id, NO_LOCK);
    +-    sqlite3_free(pFile->lockingContext);
    +-    rc = closeUnixFile(id);
    +-  }
    +-  return rc;
    ++  unixFile *pFile = (unixFile*)id;
    ++  assert( id!=0 );
    ++  dotlockUnlock(id, NO_LOCK);
    ++  sqlite3_free(pFile->lockingContext);
    ++  return closeUnixFile(id);
    + }
    + /****************** End of the dot-file lock implementation *******************
    + ******************************************************************************/
    +@@ -28934,10 +33052,8 @@ static int flockCheckReservedLock(sqlite3_file *id, int *pResOut){
    +         int tErrno = errno;
    +         /* unlock failed with an error */
    +         lrc = SQLITE_IOERR_UNLOCK; 
    +-        if( IS_LOCK_ERROR(lrc) ){
    +-          storeLastErrno(pFile, tErrno);
    +-          rc = lrc;
    +-        }
    ++        storeLastErrno(pFile, tErrno);
    ++        rc = lrc;
    +       }
    +     } else {
    +       int tErrno = errno;
    +@@ -28953,7 +33069,7 @@ static int flockCheckReservedLock(sqlite3_file *id, int *pResOut){
    +   OSTRACE(("TEST WR-LOCK %d %d %d (flock)\n", pFile->h, rc, reserved));
    + 
    + #ifdef SQLITE_IGNORE_FLOCK_LOCK_ERRORS
    +-  if( (rc & SQLITE_IOERR) == SQLITE_IOERR ){
    ++  if( (rc & 0xff) == SQLITE_IOERR ){
    +     rc = SQLITE_OK;
    +     reserved=1;
    +   }
    +@@ -29020,7 +33136,7 @@ static int flockLock(sqlite3_file *id, int eFileLock) {
    +   OSTRACE(("LOCK    %d %s %s (flock)\n", pFile->h, azFileLock(eFileLock), 
    +            rc==SQLITE_OK ? "ok" : "failed"));
    + #ifdef SQLITE_IGNORE_FLOCK_LOCK_ERRORS
    +-  if( (rc & SQLITE_IOERR) == SQLITE_IOERR ){
    ++  if( (rc & 0xff) == SQLITE_IOERR ){
    +     rc = SQLITE_BUSY;
    +   }
    + #endif /* SQLITE_IGNORE_FLOCK_LOCK_ERRORS */
    +@@ -29070,12 +33186,9 @@ static int flockUnlock(sqlite3_file *id, int eFileLock) {
    + ** Close a file.
    + */
    + static int flockClose(sqlite3_file *id) {
    +-  int rc = SQLITE_OK;
    +-  if( id ){
    +-    flockUnlock(id, NO_LOCK);
    +-    rc = closeUnixFile(id);
    +-  }
    +-  return rc;
    ++  assert( id!=0 );
    ++  flockUnlock(id, NO_LOCK);
    ++  return closeUnixFile(id);
    + }
    + 
    + #endif /* SQLITE_ENABLE_LOCKING_STYLE && !OS_VXWORK */
    +@@ -29560,7 +33673,7 @@ static int afpLock(sqlite3_file *id, int eFileLock){
    +           /* Can't reestablish the shared lock.  Sqlite can't deal, this is
    +           ** a critical I/O error
    +           */
    +-          rc = ((failed & SQLITE_IOERR) == SQLITE_IOERR) ? failed2 : 
    ++          rc = ((failed & 0xff) == SQLITE_IOERR) ? failed2 : 
    +                SQLITE_IOERR_LOCK;
    +           goto afp_end_lock;
    +         } 
    +@@ -29700,23 +33813,22 @@ static int afpUnlock(sqlite3_file *id, int eFileLock) {
    + */
    + static int afpClose(sqlite3_file *id) {
    +   int rc = SQLITE_OK;
    +-  if( id ){
    +-    unixFile *pFile = (unixFile*)id;
    +-    afpUnlock(id, NO_LOCK);
    +-    unixEnterMutex();
    +-    if( pFile->pInode && pFile->pInode->nLock ){
    +-      /* If there are outstanding locks, do not actually close the file just
    +-      ** yet because that would clear those locks.  Instead, add the file
    +-      ** descriptor to pInode->aPending.  It will be automatically closed when
    +-      ** the last lock is cleared.
    +-      */
    +-      setPendingFd(pFile);
    +-    }
    +-    releaseInodeInfo(pFile);
    +-    sqlite3_free(pFile->lockingContext);
    +-    rc = closeUnixFile(id);
    +-    unixLeaveMutex();
    ++  unixFile *pFile = (unixFile*)id;
    ++  assert( id!=0 );
    ++  afpUnlock(id, NO_LOCK);
    ++  unixEnterMutex();
    ++  if( pFile->pInode && pFile->pInode->nLock ){
    ++    /* If there are outstanding locks, do not actually close the file just
    ++    ** yet because that would clear those locks.  Instead, add the file
    ++    ** descriptor to pInode->aPending.  It will be automatically closed when
    ++    ** the last lock is cleared.
    ++    */
    ++    setPendingFd(pFile);
    +   }
    ++  releaseInodeInfo(pFile);
    ++  sqlite3_free(pFile->lockingContext);
    ++  rc = closeUnixFile(id);
    ++  unixLeaveMutex();
    +   return rc;
    + }
    + 
    +@@ -29795,13 +33907,9 @@ static int seekAndRead(unixFile *id, sqlite3_int64 offset, void *pBuf, int cnt){
    +     SimulateIOError( got = -1 );
    + #else
    +     newOffset = lseek(id->h, offset, SEEK_SET);
    +-    SimulateIOError( newOffset-- );
    +-    if( newOffset!=offset ){
    +-      if( newOffset == -1 ){
    +-        storeLastErrno((unixFile*)id, errno);
    +-      }else{
    +-        storeLastErrno((unixFile*)id, 0);
    +-      }
    ++    SimulateIOError( newOffset = -1 );
    ++    if( newOffset<0 ){
    ++      storeLastErrno((unixFile*)id, errno);
    +       return -1;
    +     }
    +     got = osRead(id->h, pBuf, cnt);
    +@@ -29845,7 +33953,7 @@ static int unixRead(
    +   /* If this is a database file (not a journal, master-journal or temp
    +   ** file), the bytes in the locking range should never be read or written. */
    + #if 0
    +-  assert( pFile->pUnused==0
    ++  assert( pFile->pPreallocatedUnused==0
    +        || offset>=PENDING_BYTE+512
    +        || offset+amt<=PENDING_BYTE 
    +   );
    +@@ -29900,6 +34008,7 @@ static int seekAndWriteFd(
    + 
    +   assert( nBuf==(nBuf&0x1ffff) );
    +   assert( fd>2 );
    ++  assert( piErrno!=0 );
    +   nBuf &= 0x1ffff;
    +   TIMER_START;
    + 
    +@@ -29910,11 +34019,10 @@ static int seekAndWriteFd(
    + #else
    +   do{
    +     i64 iSeek = lseek(fd, iOff, SEEK_SET);
    +-    SimulateIOError( iSeek-- );
    +-
    +-    if( iSeek!=iOff ){
    +-      if( piErrno ) *piErrno = (iSeek==-1 ? errno : 0);
    +-      return -1;
    ++    SimulateIOError( iSeek = -1 );
    ++    if( iSeek<0 ){
    ++      rc = -1;
    ++      break;
    +     }
    +     rc = osWrite(fd, pBuf, nBuf);
    +   }while( rc<0 && errno==EINTR );
    +@@ -29923,7 +34031,7 @@ static int seekAndWriteFd(
    +   TIMER_END;
    +   OSTRACE(("WRITE   %-3d %5d %7lld %llu\n", fd, rc, iOff, TIMER_ELAPSED));
    + 
    +-  if( rc<0 && piErrno ) *piErrno = errno;
    ++  if( rc<0 ) *piErrno = errno;
    +   return rc;
    + }
    + 
    +@@ -29958,7 +34066,7 @@ static int unixWrite(
    +   /* If this is a database file (not a journal, master-journal or temp
    +   ** file), the bytes in the locking range should never be read or written. */
    + #if 0
    +-  assert( pFile->pUnused==0
    ++  assert( pFile->pPreallocatedUnused==0
    +        || offset>=PENDING_BYTE+512
    +        || offset+amt<=PENDING_BYTE 
    +   );
    +@@ -29986,7 +34094,7 @@ static int unixWrite(
    +   }
    + #endif
    + 
    +-#if SQLITE_MAX_MMAP_SIZE>0
    ++#if defined(SQLITE_MMAP_READWRITE) && SQLITE_MAX_MMAP_SIZE>0
    +   /* Deal with as much of this write request as possible by transfering
    +   ** data from the memory mapping using memcpy().  */
    +   if( offset<pFile->mmapSize ){
    +@@ -30107,10 +34215,15 @@ static int full_fsync(int fd, int fullSync, int dataOnly){
    + #endif
    + 
    +   /* If we compiled with the SQLITE_NO_SYNC flag, then syncing is a
    +-  ** no-op
    ++  ** no-op.  But go ahead and call fstat() to validate the file
    ++  ** descriptor as we need a method to provoke a failure during
    ++  ** coverate testing.
    +   */
    + #ifdef SQLITE_NO_SYNC
    +-  rc = SQLITE_OK;
    ++  {
    ++    struct stat buf;
    ++    rc = osFstat(fd, &buf);
    ++  }
    + #elif HAVE_FULLFSYNC
    +   if( fullSync ){
    +     rc = osFcntl(fd, F_FULLFSYNC, 0);
    +@@ -30176,16 +34289,20 @@ static int openDirectory(const char *zFilename, int *pFd){
    +   char zDirname[MAX_PATHNAME+1];
    + 
    +   sqlite3_snprintf(MAX_PATHNAME, zDirname, "%s", zFilename);
    +-  for(ii=(int)strlen(zDirname); ii>1 && zDirname[ii]!='/'; ii--);
    ++  for(ii=(int)strlen(zDirname); ii>0 && zDirname[ii]!='/'; ii--);
    +   if( ii>0 ){
    +     zDirname[ii] = '\0';
    +-    fd = robust_open(zDirname, O_RDONLY|O_BINARY, 0);
    +-    if( fd>=0 ){
    +-      OSTRACE(("OPENDIR %-3d %s\n", fd, zDirname));
    +-    }
    ++  }else{
    ++    if( zDirname[0]!='/' ) zDirname[0] = '.';
    ++    zDirname[1] = 0;
    ++  }
    ++  fd = robust_open(zDirname, O_RDONLY|O_BINARY, 0);
    ++  if( fd>=0 ){
    ++    OSTRACE(("OPENDIR %-3d %s\n", fd, zDirname));
    +   }
    +   *pFd = fd;
    +-  return (fd>=0?SQLITE_OK:unixLogError(SQLITE_CANTOPEN_BKPT, "open", zDirname));
    ++  if( fd>=0 ) return SQLITE_OK;
    ++  return unixLogError(SQLITE_CANTOPEN_BKPT, "openDirectory", zDirname);
    + }
    + 
    + /*
    +@@ -30238,10 +34355,11 @@ static int unixSync(sqlite3_file *id, int flags){
    +     OSTRACE(("DIRSYNC %s (have_fullfsync=%d fullsync=%d)\n", pFile->zPath,
    +             HAVE_FULLFSYNC, isFullsync));
    +     rc = osOpenDirectory(pFile->zPath, &dirfd);
    +-    if( rc==SQLITE_OK && dirfd>=0 ){
    ++    if( rc==SQLITE_OK ){
    +       full_fsync(dirfd, 0, 0);
    +       robust_close(pFile, dirfd, __LINE__);
    +-    }else if( rc==SQLITE_CANTOPEN ){
    ++    }else{
    ++      assert( rc==SQLITE_CANTOPEN );
    +       rc = SQLITE_OK;
    +     }
    +     pFile->ctrlFlags &= ~UNIXFILE_DIRSYNC;
    +@@ -30373,18 +34491,14 @@ static int fcntlSizeHint(unixFile *pFile, i64 nByte){
    +       int nWrite = 0;             /* Number of bytes written by seekAndWrite */
    +       i64 iWrite;                 /* Next offset to write to */
    + 
    +-      iWrite = ((buf.st_size + 2*nBlk - 1)/nBlk)*nBlk-1;
    ++      iWrite = (buf.st_size/nBlk)*nBlk + nBlk - 1;
    +       assert( iWrite>=buf.st_size );
    +-      assert( (iWrite/nBlk)==((buf.st_size+nBlk-1)/nBlk) );
    +       assert( ((iWrite+1)%nBlk)==0 );
    +-      for(/*no-op*/; iWrite<nSize; iWrite+=nBlk ){
    ++      for(/*no-op*/; iWrite<nSize+nBlk-1; iWrite+=nBlk ){
    ++        if( iWrite>=nSize ) iWrite = nSize - 1;
    +         nWrite = seekAndWrite(pFile, iWrite, "", 1);
    +         if( nWrite!=1 ) return SQLITE_IOERR_WRITE;
    +       }
    +-      if( nWrite==0 || (nSize%nBlk) ){
    +-        nWrite = seekAndWrite(pFile, nSize-1, "", 1);
    +-        if( nWrite!=1 ) return SQLITE_IOERR_WRITE;
    +-      }
    + #endif
    +     }
    +   }
    +@@ -30432,10 +34546,21 @@ static int unixGetTempname(int nBuf, char *zBuf);
    + static int unixFileControl(sqlite3_file *id, int op, void *pArg){
    +   unixFile *pFile = (unixFile*)id;
    +   switch( op ){
    +-    case SQLITE_FCNTL_WAL_BLOCK: {
    +-      /* pFile->ctrlFlags |= UNIXFILE_BLOCK; // Deferred feature */
    +-      return SQLITE_OK;
    ++#if defined(__linux__) && defined(SQLITE_ENABLE_BATCH_ATOMIC_WRITE)
    ++    case SQLITE_FCNTL_BEGIN_ATOMIC_WRITE: {
    ++      int rc = osIoctl(pFile->h, F2FS_IOC_START_ATOMIC_WRITE);
    ++      return rc ? SQLITE_IOERR_BEGIN_ATOMIC : SQLITE_OK;
    ++    }
    ++    case SQLITE_FCNTL_COMMIT_ATOMIC_WRITE: {
    ++      int rc = osIoctl(pFile->h, F2FS_IOC_COMMIT_ATOMIC_WRITE);
    ++      return rc ? SQLITE_IOERR_COMMIT_ATOMIC : SQLITE_OK;
    +     }
    ++    case SQLITE_FCNTL_ROLLBACK_ATOMIC_WRITE: {
    ++      int rc = osIoctl(pFile->h, F2FS_IOC_ABORT_VOLATILE_WRITE);
    ++      return rc ? SQLITE_IOERR_ROLLBACK_ATOMIC : SQLITE_OK;
    ++    }
    ++#endif /* __linux__ && SQLITE_ENABLE_BATCH_ATOMIC_WRITE */
    ++
    +     case SQLITE_FCNTL_LOCKSTATE: {
    +       *(int*)pArg = pFile->eFileLock;
    +       return SQLITE_OK;
    +@@ -30486,6 +34611,14 @@ static int unixFileControl(sqlite3_file *id, int op, void *pArg){
    +       if( newLimit>sqlite3GlobalConfig.mxMmap ){
    +         newLimit = sqlite3GlobalConfig.mxMmap;
    +       }
    ++
    ++      /* The value of newLimit may be eventually cast to (size_t) and passed
    ++      ** to mmap(). Restrict its value to 2GB if (size_t) is not at least a
    ++      ** 64-bit type. */
    ++      if( newLimit>0 && sizeof(size_t)<8 ){
    ++        newLimit = (newLimit & 0x7FFFFFFF);
    ++      }
    ++
    +       *(i64*)pArg = pFile->mmapSizeMax;
    +       if( newLimit>=0 && newLimit!=pFile->mmapSizeMax && pFile->nFetchOut==0 ){
    +         pFile->mmapSizeMax = newLimit;
    +@@ -30519,30 +34652,41 @@ static int unixFileControl(sqlite3_file *id, int op, void *pArg){
    + }
    + 
    + /*
    +-** Return the sector size in bytes of the underlying block device for
    +-** the specified file. This is almost always 512 bytes, but may be
    +-** larger for some devices.
    ++** If pFd->sectorSize is non-zero when this function is called, it is a
    ++** no-op. Otherwise, the values of pFd->sectorSize and 
    ++** pFd->deviceCharacteristics are set according to the file-system 
    ++** characteristics. 
    + **
    +-** SQLite code assumes this function cannot fail. It also assumes that
    +-** if two files are created in the same file-system directory (i.e.
    +-** a database and its journal file) that the sector size will be the
    +-** same for both.
    ++** There are two versions of this function. One for QNX and one for all
    ++** other systems.
    + */
    +-#ifndef __QNXNTO__ 
    +-static int unixSectorSize(sqlite3_file *NotUsed){
    +-  UNUSED_PARAMETER(NotUsed);
    +-  return SQLITE_DEFAULT_SECTOR_SIZE;
    +-}
    +-#endif
    ++#ifndef __QNXNTO__
    ++static void setDeviceCharacteristics(unixFile *pFd){
    ++  assert( pFd->deviceCharacteristics==0 || pFd->sectorSize!=0 );
    ++  if( pFd->sectorSize==0 ){
    ++#if defined(__linux__) && defined(SQLITE_ENABLE_BATCH_ATOMIC_WRITE)
    ++    int res;
    ++    u32 f = 0;
    + 
    +-/*
    +-** The following version of unixSectorSize() is optimized for QNX.
    +-*/
    +-#ifdef __QNXNTO__
    ++    /* Check for support for F2FS atomic batch writes. */
    ++    res = osIoctl(pFd->h, F2FS_IOC_GET_FEATURES, &f);
    ++    if( res==0 && (f & F2FS_FEATURE_ATOMIC_WRITE) ){
    ++      pFd->deviceCharacteristics = SQLITE_IOCAP_BATCH_ATOMIC;
    ++    }
    ++#endif /* __linux__ && SQLITE_ENABLE_BATCH_ATOMIC_WRITE */
    ++
    ++    /* Set the POWERSAFE_OVERWRITE flag if requested. */
    ++    if( pFd->ctrlFlags & UNIXFILE_PSOW ){
    ++      pFd->deviceCharacteristics |= SQLITE_IOCAP_POWERSAFE_OVERWRITE;
    ++    }
    ++
    ++    pFd->sectorSize = SQLITE_DEFAULT_SECTOR_SIZE;
    ++  }
    ++}
    ++#else
    + #include <sys/dcmd_blk.h>
    + #include <sys/statvfs.h>
    +-static int unixSectorSize(sqlite3_file *id){
    +-  unixFile *pFile = (unixFile*)id;
    ++static void setDeviceCharacteristics(unixFile *pFile){
    +   if( pFile->sectorSize == 0 ){
    +     struct statvfs fsInfo;
    +        
    +@@ -30550,7 +34694,7 @@ static int unixSectorSize(sqlite3_file *id){
    +     pFile->sectorSize = SQLITE_DEFAULT_SECTOR_SIZE;
    +     pFile->deviceCharacteristics = 0;
    +     if( fstatvfs(pFile->h, &fsInfo) == -1 ) {
    +-      return pFile->sectorSize;
    ++      return;
    +     }
    + 
    +     if( !strcmp(fsInfo.f_basetype, "tmp") ) {
    +@@ -30611,9 +34755,24 @@ static int unixSectorSize(sqlite3_file *id){
    +     pFile->deviceCharacteristics = 0;
    +     pFile->sectorSize = SQLITE_DEFAULT_SECTOR_SIZE;
    +   }
    +-  return pFile->sectorSize;
    + }
    +-#endif /* __QNXNTO__ */
    ++#endif
    ++
    ++/*
    ++** Return the sector size in bytes of the underlying block device for
    ++** the specified file. This is almost always 512 bytes, but may be
    ++** larger for some devices.
    ++**
    ++** SQLite code assumes this function cannot fail. It also assumes that
    ++** if two files are created in the same file-system directory (i.e.
    ++** a database and its journal file) that the sector size will be the
    ++** same for both.
    ++*/
    ++static int unixSectorSize(sqlite3_file *id){
    ++  unixFile *pFd = (unixFile*)id;
    ++  setDeviceCharacteristics(pFd);
    ++  return pFd->sectorSize;
    ++}
    + 
    + /*
    + ** Return the device characteristics for the file.
    +@@ -30629,16 +34788,9 @@ static int unixSectorSize(sqlite3_file *id){
    + ** available to turn it off and URI query parameter available to turn it off.
    + */
    + static int unixDeviceCharacteristics(sqlite3_file *id){
    +-  unixFile *p = (unixFile*)id;
    +-  int rc = 0;
    +-#ifdef __QNXNTO__
    +-  if( p->sectorSize==0 ) unixSectorSize(id);
    +-  rc = p->deviceCharacteristics;
    +-#endif
    +-  if( p->ctrlFlags & UNIXFILE_PSOW ){
    +-    rc |= SQLITE_IOCAP_POWERSAFE_OVERWRITE;
    +-  }
    +-  return rc;
    ++  unixFile *pFd = (unixFile*)id;
    ++  setDeviceCharacteristics(pFd);
    ++  return pFd->deviceCharacteristics;
    + }
    + 
    + #if !defined(SQLITE_OMIT_WAL) || SQLITE_MAX_MMAP_SIZE>0
    +@@ -30700,6 +34852,7 @@ struct unixShmNode {
    +   int szRegion;              /* Size of shared-memory regions */
    +   u16 nRegion;               /* Size of array apRegion */
    +   u8 isReadonly;             /* True if read-only */
    ++  u8 isUnlocked;             /* True if no DMS lock held */
    +   char **apRegion;           /* Array of mapped shared-memory regions */
    +   int nRef;                  /* Number of unixShm objects pointing to this */
    +   unixShm *pFirst;           /* All unixShm objects pointing to this */
    +@@ -30756,16 +34909,15 @@ static int unixShmSystemLock(
    + 
    +   /* Access to the unixShmNode object is serialized by the caller */
    +   pShmNode = pFile->pInode->pShmNode;
    +-  assert( sqlite3_mutex_held(pShmNode->mutex) || pShmNode->nRef==0 );
    ++  assert( pShmNode->nRef==0 || sqlite3_mutex_held(pShmNode->mutex) );
    + 
    +   /* Shared locks never span more than one byte */
    +   assert( n==1 || lockType!=F_RDLCK );
    + 
    +   /* Locks are within range */
    +-  assert( n>=1 && n<SQLITE_SHM_NLOCK );
    ++  assert( n>=1 && n<=SQLITE_SHM_NLOCK );
    + 
    +   if( pShmNode->h>=0 ){
    +-    int lkType;
    +     /* Initialize the locking parameters */
    +     memset(&f, 0, sizeof(f));
    +     f.l_type = lockType;
    +@@ -30773,10 +34925,8 @@ static int unixShmSystemLock(
    +     f.l_start = ofst;
    +     f.l_len = n;
    + 
    +-    lkType = (pFile->ctrlFlags & UNIXFILE_BLOCK)!=0 ? F_SETLKW : F_SETLK;
    +-    rc = osFcntl(pShmNode->h, lkType, &f);
    ++    rc = osFcntl(pShmNode->h, F_SETLK, &f);
    +     rc = (rc!=(-1)) ? SQLITE_OK : SQLITE_BUSY;
    +-    pFile->ctrlFlags &= ~UNIXFILE_BLOCK;
    +   }
    + 
    +   /* Update the global lock state and do debug tracing */
    +@@ -30843,7 +34993,7 @@ static int unixShmRegionPerMap(void){
    + static void unixShmPurge(unixFile *pFd){
    +   unixShmNode *p = pFd->pInode->pShmNode;
    +   assert( unixMutexHeld() );
    +-  if( p && p->nRef==0 ){
    ++  if( p && ALWAYS(p->nRef==0) ){
    +     int nShmPerMap = unixShmRegionPerMap();
    +     int i;
    +     assert( p->pInode==pFd->pInode );
    +@@ -30865,6 +35015,64 @@ static void unixShmPurge(unixFile *pFd){
    +   }
    + }
    + 
    ++/*
    ++** The DMS lock has not yet been taken on shm file pShmNode. Attempt to
    ++** take it now. Return SQLITE_OK if successful, or an SQLite error
    ++** code otherwise.
    ++**
    ++** If the DMS cannot be locked because this is a readonly_shm=1 
    ++** connection and no other process already holds a lock, return
    ++** SQLITE_READONLY_CANTINIT and set pShmNode->isUnlocked=1.
    ++*/
    ++static int unixLockSharedMemory(unixFile *pDbFd, unixShmNode *pShmNode){
    ++  struct flock lock;
    ++  int rc = SQLITE_OK;
    ++
    ++  /* Use F_GETLK to determine the locks other processes are holding
    ++  ** on the DMS byte. If it indicates that another process is holding
    ++  ** a SHARED lock, then this process may also take a SHARED lock
    ++  ** and proceed with opening the *-shm file. 
    ++  **
    ++  ** Or, if no other process is holding any lock, then this process
    ++  ** is the first to open it. In this case take an EXCLUSIVE lock on the
    ++  ** DMS byte and truncate the *-shm file to zero bytes in size. Then
    ++  ** downgrade to a SHARED lock on the DMS byte.
    ++  **
    ++  ** If another process is holding an EXCLUSIVE lock on the DMS byte,
    ++  ** return SQLITE_BUSY to the caller (it will try again). An earlier
    ++  ** version of this code attempted the SHARED lock at this point. But
    ++  ** this introduced a subtle race condition: if the process holding
    ++  ** EXCLUSIVE failed just before truncating the *-shm file, then this
    ++  ** process might open and use the *-shm file without truncating it.
    ++  ** And if the *-shm file has been corrupted by a power failure or
    ++  ** system crash, the database itself may also become corrupt.  */
    ++  lock.l_whence = SEEK_SET;
    ++  lock.l_start = UNIX_SHM_DMS;
    ++  lock.l_len = 1;
    ++  lock.l_type = F_WRLCK;
    ++  if( osFcntl(pShmNode->h, F_GETLK, &lock)!=0 ) {
    ++    rc = SQLITE_IOERR_LOCK;
    ++  }else if( lock.l_type==F_UNLCK ){
    ++    if( pShmNode->isReadonly ){
    ++      pShmNode->isUnlocked = 1;
    ++      rc = SQLITE_READONLY_CANTINIT;
    ++    }else{
    ++      rc = unixShmSystemLock(pDbFd, F_WRLCK, UNIX_SHM_DMS, 1);
    ++      if( rc==SQLITE_OK && robust_ftruncate(pShmNode->h, 0) ){
    ++        rc = unixLogError(SQLITE_IOERR_SHMOPEN,"ftruncate",pShmNode->zFilename);
    ++      }
    ++    }
    ++  }else if( lock.l_type==F_WRLCK ){
    ++    rc = SQLITE_BUSY;
    ++  }
    ++
    ++  if( rc==SQLITE_OK ){
    ++    assert( lock.l_type==F_UNLCK || lock.l_type==F_RDLCK );
    ++    rc = unixShmSystemLock(pDbFd, F_RDLCK, UNIX_SHM_DMS, 1);
    ++  }
    ++  return rc;
    ++}
    ++
    + /*
    + ** Open a shared-memory area associated with open database file pDbFd.  
    + ** This particular implementation uses mmapped files.
    +@@ -30903,14 +35111,14 @@ static void unixShmPurge(unixFile *pFd){
    + static int unixOpenSharedMemory(unixFile *pDbFd){
    +   struct unixShm *p = 0;          /* The connection to be opened */
    +   struct unixShmNode *pShmNode;   /* The underlying mmapped file */
    +-  int rc;                         /* Result code */
    ++  int rc = SQLITE_OK;             /* Result code */
    +   unixInodeInfo *pInode;          /* The inode of fd */
    +-  char *zShmFilename;             /* Name of the file used for SHM */
    ++  char *zShm;             /* Name of the file used for SHM */
    +   int nShmFilename;               /* Size of the SHM filename in bytes */
    + 
    +   /* Allocate space for the new unixShm object. */
    +   p = sqlite3_malloc64( sizeof(*p) );
    +-  if( p==0 ) return SQLITE_NOMEM;
    ++  if( p==0 ) return SQLITE_NOMEM_BKPT;
    +   memset(p, 0, sizeof(*p));
    +   assert( pDbFd->pShm==0 );
    + 
    +@@ -30930,7 +35138,7 @@ static int unixOpenSharedMemory(unixFile *pDbFd){
    +     ** a new *-shm file is created, an attempt will be made to create it
    +     ** with the same permissions.
    +     */
    +-    if( osFstat(pDbFd->h, &sStat) && pInode->bProcessLock==0 ){
    ++    if( osFstat(pDbFd->h, &sStat) ){
    +       rc = unixLogError(SQLITE_IOERR_FSTAT, "fstat", pDbFd->zPath);
    +       goto shm_open_err;
    +     }
    +@@ -30942,59 +35150,51 @@ static int unixOpenSharedMemory(unixFile *pDbFd){
    + #endif
    +     pShmNode = sqlite3_malloc64( sizeof(*pShmNode) + nShmFilename );
    +     if( pShmNode==0 ){
    +-      rc = SQLITE_NOMEM;
    ++      rc = SQLITE_NOMEM_BKPT;
    +       goto shm_open_err;
    +     }
    +     memset(pShmNode, 0, sizeof(*pShmNode)+nShmFilename);
    +-    zShmFilename = pShmNode->zFilename = (char*)&pShmNode[1];
    ++    zShm = pShmNode->zFilename = (char*)&pShmNode[1];
    + #ifdef SQLITE_SHM_DIRECTORY
    +-    sqlite3_snprintf(nShmFilename, zShmFilename, 
    ++    sqlite3_snprintf(nShmFilename, zShm, 
    +                      SQLITE_SHM_DIRECTORY "/sqlite-shm-%x-%x",
    +                      (u32)sStat.st_ino, (u32)sStat.st_dev);
    + #else
    +-    sqlite3_snprintf(nShmFilename, zShmFilename, "%s-shm", zBasePath);
    +-    sqlite3FileSuffix3(pDbFd->zPath, zShmFilename);
    ++    sqlite3_snprintf(nShmFilename, zShm, "%s-shm", zBasePath);
    ++    sqlite3FileSuffix3(pDbFd->zPath, zShm);
    + #endif
    +     pShmNode->h = -1;
    +     pDbFd->pInode->pShmNode = pShmNode;
    +     pShmNode->pInode = pDbFd->pInode;
    +-    pShmNode->mutex = sqlite3_mutex_alloc(SQLITE_MUTEX_FAST);
    +-    if( pShmNode->mutex==0 ){
    +-      rc = SQLITE_NOMEM;
    +-      goto shm_open_err;
    ++    if( sqlite3GlobalConfig.bCoreMutex ){
    ++      pShmNode->mutex = sqlite3_mutex_alloc(SQLITE_MUTEX_FAST);
    ++      if( pShmNode->mutex==0 ){
    ++        rc = SQLITE_NOMEM_BKPT;
    ++        goto shm_open_err;
    ++      }
    +     }
    + 
    +     if( pInode->bProcessLock==0 ){
    +-      int openFlags = O_RDWR | O_CREAT;
    +-      if( sqlite3_uri_boolean(pDbFd->zPath, "readonly_shm", 0) ){
    +-        openFlags = O_RDONLY;
    +-        pShmNode->isReadonly = 1;
    ++      if( 0==sqlite3_uri_boolean(pDbFd->zPath, "readonly_shm", 0) ){
    ++        pShmNode->h = robust_open(zShm, O_RDWR|O_CREAT, (sStat.st_mode&0777));
    +       }
    +-      pShmNode->h = robust_open(zShmFilename, openFlags, (sStat.st_mode&0777));
    +       if( pShmNode->h<0 ){
    +-        rc = unixLogError(SQLITE_CANTOPEN_BKPT, "open", zShmFilename);
    +-        goto shm_open_err;
    ++        pShmNode->h = robust_open(zShm, O_RDONLY, (sStat.st_mode&0777));
    ++        if( pShmNode->h<0 ){
    ++          rc = unixLogError(SQLITE_CANTOPEN_BKPT, "open", zShm);
    ++          goto shm_open_err;
    ++        }
    ++        pShmNode->isReadonly = 1;
    +       }
    + 
    +       /* If this process is running as root, make sure that the SHM file
    +       ** is owned by the same user that owns the original database.  Otherwise,
    +       ** the original owner will not be able to connect.
    +       */
    +-      osFchown(pShmNode->h, sStat.st_uid, sStat.st_gid);
    +-  
    +-      /* Check to see if another process is holding the dead-man switch.
    +-      ** If not, truncate the file to zero length. 
    +-      */
    +-      rc = SQLITE_OK;
    +-      if( unixShmSystemLock(pDbFd, F_WRLCK, UNIX_SHM_DMS, 1)==SQLITE_OK ){
    +-        if( robust_ftruncate(pShmNode->h, 0) ){
    +-          rc = unixLogError(SQLITE_IOERR_SHMOPEN, "ftruncate", zShmFilename);
    +-        }
    +-      }
    +-      if( rc==SQLITE_OK ){
    +-        rc = unixShmSystemLock(pDbFd, F_RDLCK, UNIX_SHM_DMS, 1);
    +-      }
    +-      if( rc ) goto shm_open_err;
    ++      robustFchown(pShmNode->h, sStat.st_uid, sStat.st_gid);
    ++
    ++      rc = unixLockSharedMemory(pDbFd, pShmNode);
    ++      if( rc!=SQLITE_OK && rc!=SQLITE_READONLY_CANTINIT ) goto shm_open_err;
    +     }
    +   }
    + 
    +@@ -31018,7 +35218,7 @@ static int unixOpenSharedMemory(unixFile *pDbFd){
    +   p->pNext = pShmNode->pFirst;
    +   pShmNode->pFirst = p;
    +   sqlite3_mutex_leave(pShmNode->mutex);
    +-  return SQLITE_OK;
    ++  return rc;
    + 
    +   /* Jump here on any error */
    + shm_open_err:
    +@@ -31070,6 +35270,11 @@ static int unixShmMap(
    +   p = pDbFd->pShm;
    +   pShmNode = p->pShmNode;
    +   sqlite3_mutex_enter(pShmNode->mutex);
    ++  if( pShmNode->isUnlocked ){
    ++    rc = unixLockSharedMemory(pDbFd, pShmNode);
    ++    if( rc!=SQLITE_OK ) goto shmpage_out;
    ++    pShmNode->isUnlocked = 0;
    ++  }
    +   assert( szRegion==pShmNode->szRegion || pShmNode->nRegion==0 );
    +   assert( pShmNode->pInode==pDbFd->pInode );
    +   assert( pShmNode->h>=0 || pDbFd->pInode->bProcessLock==1 );
    +@@ -31117,7 +35322,8 @@ static int unixShmMap(
    +           /* Write to the last byte of each newly allocated or extended page */
    +           assert( (nByte % pgsz)==0 );
    +           for(iPg=(sStat.st_size/pgsz); iPg<(nByte/pgsz); iPg++){
    +-            if( seekAndWriteFd(pShmNode->h, iPg*pgsz + pgsz-1, "", 1, 0)!=1 ){
    ++            int x = 0;
    ++            if( seekAndWriteFd(pShmNode->h, iPg*pgsz + pgsz-1, "", 1, &x)!=1 ){
    +               const char *zFile = pShmNode->zFilename;
    +               rc = unixLogError(SQLITE_IOERR_SHMSIZE, "write", zFile);
    +               goto shmpage_out;
    +@@ -31132,7 +35338,7 @@ static int unixShmMap(
    +         pShmNode->apRegion, nReqRegion*sizeof(char *)
    +     );
    +     if( !apNew ){
    +-      rc = SQLITE_IOERR_NOMEM;
    ++      rc = SQLITE_IOERR_NOMEM_BKPT;
    +       goto shmpage_out;
    +     }
    +     pShmNode->apRegion = apNew;
    +@@ -31152,7 +35358,7 @@ static int unixShmMap(
    +       }else{
    +         pMem = sqlite3_malloc64(szRegion);
    +         if( pMem==0 ){
    +-          rc = SQLITE_NOMEM;
    ++          rc = SQLITE_NOMEM_BKPT;
    +           goto shmpage_out;
    +         }
    +         memset(pMem, 0, szRegion);
    +@@ -31411,7 +35617,9 @@ static void unixRemapfile(
    +   assert( pFd->mmapSizeActual>=pFd->mmapSize );
    +   assert( MAP_FAILED!=0 );
    + 
    ++#ifdef SQLITE_MMAP_READWRITE
    +   if( (pFd->ctrlFlags & UNIXFILE_RDONLY)==0 ) flags |= PROT_WRITE;
    ++#endif
    + 
    +   if( pOrig ){
    + #if HAVE_MREMAP
    +@@ -31483,17 +35691,14 @@ static void unixRemapfile(
    + ** recreated as a result of outstanding references) or an SQLite error
    + ** code otherwise.
    + */
    +-static int unixMapfile(unixFile *pFd, i64 nByte){
    +-  i64 nMap = nByte;
    +-  int rc;
    +-
    ++static int unixMapfile(unixFile *pFd, i64 nMap){
    +   assert( nMap>=0 || pFd->nFetchOut==0 );
    ++  assert( nMap>0 || (pFd->mmapSize==0 && pFd->pMapRegion==0) );
    +   if( pFd->nFetchOut>0 ) return SQLITE_OK;
    + 
    +   if( nMap<0 ){
    +     struct stat statbuf;          /* Low-level file information */
    +-    rc = osFstat(pFd->h, &statbuf);
    +-    if( rc!=SQLITE_OK ){
    ++    if( osFstat(pFd->h, &statbuf) ){
    +       return SQLITE_IOERR_FSTAT;
    +     }
    +     nMap = statbuf.st_size;
    +@@ -31502,12 +35707,9 @@ static int unixMapfile(unixFile *pFd, i64 nByte){
    +     nMap = pFd->mmapSizeMax;
    +   }
    + 
    ++  assert( nMap>0 || (pFd->mmapSize==0 && pFd->pMapRegion==0) );
    +   if( nMap!=pFd->mmapSize ){
    +-    if( nMap>0 ){
    +-      unixRemapfile(pFd, nMap);
    +-    }else{
    +-      unixUnmapfile(pFd);
    +-    }
    ++    unixRemapfile(pFd, nMap);
    +   }
    + 
    +   return SQLITE_OK;
    +@@ -31900,17 +36102,6 @@ static int fillInUnixFile(
    + 
    +   assert( pNew->pInode==NULL );
    + 
    +-  /* Usually the path zFilename should not be a relative pathname. The
    +-  ** exception is when opening the proxy "conch" file in builds that
    +-  ** include the special Apple locking styles.
    +-  */
    +-#if defined(__APPLE__) && SQLITE_ENABLE_LOCKING_STYLE
    +-  assert( zFilename==0 || zFilename[0]=='/' 
    +-    || pVfs->pAppData==(void*)&autolockIoFinder );
    +-#else
    +-  assert( zFilename==0 || zFilename[0]=='/' );
    +-#endif
    +-
    +   /* No locking occurs in temporary files */
    +   assert( zFilename!=0 || (ctrlFlags & UNIXFILE_NOLOCK)!=0 );
    + 
    +@@ -31934,7 +36125,7 @@ static int fillInUnixFile(
    +   pNew->pId = vxworksFindFileId(zFilename);
    +   if( pNew->pId==0 ){
    +     ctrlFlags |= UNIXFILE_NOLOCK;
    +-    rc = SQLITE_NOMEM;
    ++    rc = SQLITE_NOMEM_BKPT;
    +   }
    + #endif
    + 
    +@@ -31990,7 +36181,7 @@ static int fillInUnixFile(
    +     afpLockingContext *pCtx;
    +     pNew->lockingContext = pCtx = sqlite3_malloc64( sizeof(*pCtx) );
    +     if( pCtx==0 ){
    +-      rc = SQLITE_NOMEM;
    ++      rc = SQLITE_NOMEM_BKPT;
    +     }else{
    +       /* NB: zFilename exists and remains valid until the file is closed
    +       ** according to requirement F11141.  So we do not need to make a
    +@@ -32020,7 +36211,7 @@ static int fillInUnixFile(
    +     nFilename = (int)strlen(zFilename) + 6;
    +     zLockFile = (char *)sqlite3_malloc64(nFilename);
    +     if( zLockFile==0 ){
    +-      rc = SQLITE_NOMEM;
    ++      rc = SQLITE_NOMEM_BKPT;
    +     }else{
    +       sqlite3_snprintf(nFilename, zLockFile, "%s" DOTLOCK_SUFFIX, zFilename);
    +     }
    +@@ -32043,7 +36234,7 @@ static int fillInUnixFile(
    +         if( zSemName[n]=='/' ) zSemName[n] = '_';
    +       pNew->pInode->pSem = sem_open(zSemName, O_CREAT, 0666, 1);
    +       if( pNew->pInode->pSem == SEM_FAILED ){
    +-        rc = SQLITE_NOMEM;
    ++        rc = SQLITE_NOMEM_BKPT;
    +         pNew->pInode->aSemName[0] = '\0';
    +       }
    +     }
    +@@ -32076,29 +36267,31 @@ static int fillInUnixFile(
    + */
    + static const char *unixTempFileDir(void){
    +   static const char *azDirs[] = {
    +-     0,
    +      0,
    +      0,
    +      "/var/tmp",
    +      "/usr/tmp",
    +      "/tmp",
    +-     0        /* List terminator */
    ++     "."
    +   };
    +-  unsigned int i;
    ++  unsigned int i = 0;
    +   struct stat buf;
    +-  const char *zDir = 0;
    +-
    +-  azDirs[0] = sqlite3_temp_directory;
    +-  if( !azDirs[1] ) azDirs[1] = getenv("SQLITE_TMPDIR");
    +-  if( !azDirs[2] ) azDirs[2] = getenv("TMPDIR");
    +-  for(i=0; i<sizeof(azDirs)/sizeof(azDirs[0]); zDir=azDirs[i++]){
    +-    if( zDir==0 ) continue;
    +-    if( osStat(zDir, &buf) ) continue;
    +-    if( !S_ISDIR(buf.st_mode) ) continue;
    +-    if( osAccess(zDir, 07) ) continue;
    +-    break;
    ++  const char *zDir = sqlite3_temp_directory;
    ++
    ++  if( !azDirs[0] ) azDirs[0] = getenv("SQLITE_TMPDIR");
    ++  if( !azDirs[1] ) azDirs[1] = getenv("TMPDIR");
    ++  while(1){
    ++    if( zDir!=0
    ++     && osStat(zDir, &buf)==0
    ++     && S_ISDIR(buf.st_mode)
    ++     && osAccess(zDir, 03)==0
    ++    ){
    ++      return zDir;
    ++    }
    ++    if( i>=sizeof(azDirs)/sizeof(azDirs[0]) ) break;
    ++    zDir = azDirs[i++];
    +   }
    +-  return zDir;
    ++  return 0;
    + }
    + 
    + /*
    +@@ -32107,38 +36300,26 @@ static const char *unixTempFileDir(void){
    + ** pVfs->mxPathname bytes.
    + */
    + static int unixGetTempname(int nBuf, char *zBuf){
    +-  static const unsigned char zChars[] =
    +-    "abcdefghijklmnopqrstuvwxyz"
    +-    "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
    +-    "0123456789";
    +-  unsigned int i, j;
    +   const char *zDir;
    ++  int iLimit = 0;
    + 
    +   /* 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. 
    +   */
    ++  zBuf[0] = 0;
    +   SimulateIOError( return SQLITE_IOERR );
    + 
    +   zDir = unixTempFileDir();
    +-  if( zDir==0 ) zDir = ".";
    +-
    +-  /* Check that the output buffer is large enough for the temporary file 
    +-  ** name. If it is not, return SQLITE_ERROR.
    +-  */
    +-  if( (strlen(zDir) + strlen(SQLITE_TEMP_FILE_PREFIX) + 18) >= (size_t)nBuf ){
    +-    return SQLITE_ERROR;
    +-  }
    +-
    ++  if( zDir==0 ) return SQLITE_IOERR_GETTEMPPATH;
    +   do{
    +-    sqlite3_snprintf(nBuf-18, zBuf, "%s/"SQLITE_TEMP_FILE_PREFIX, zDir);
    +-    j = (int)strlen(zBuf);
    +-    sqlite3_randomness(15, &zBuf[j]);
    +-    for(i=0; i<15; i++, j++){
    +-      zBuf[j] = (char)zChars[ ((unsigned char)zBuf[j])%(sizeof(zChars)-1) ];
    +-    }
    +-    zBuf[j] = 0;
    +-    zBuf[j+1] = 0;
    ++    u64 r;
    ++    sqlite3_randomness(sizeof(r), &r);
    ++    assert( nBuf>2 );
    ++    zBuf[nBuf-2] = 0;
    ++    sqlite3_snprintf(nBuf, zBuf, "%s/"SQLITE_TEMP_FILE_PREFIX"%llx%c",
    ++                     zDir, r, 0);
    ++    if( zBuf[nBuf-2]!=0 || (iLimit++)>10 ) return SQLITE_ERROR;
    +   }while( osAccess(zBuf,0)==0 );
    +   return SQLITE_OK;
    + }
    +@@ -32179,6 +36360,8 @@ static UnixUnusedFd *findReusableFd(const char *zPath, int flags){
    + #if !OS_VXWORKS
    +   struct stat sStat;                   /* Results of stat() call */
    + 
    ++  unixEnterMutex();
    ++
    +   /* A stat() call may fail for various reasons. If this happens, it is
    +   ** almost certain that an open() call on the same path will also fail.
    +   ** For this reason, if an error occurs in the stat() call here, it is
    +@@ -32187,13 +36370,12 @@ static UnixUnusedFd *findReusableFd(const char *zPath, int flags){
    +   **
    +   ** Even if a subsequent open() call does succeed, the consequences of
    +   ** not searching for a reusable file descriptor are not dire.  */
    +-  if( 0==osStat(zPath, &sStat) ){
    ++  if( nUnusedFd>0 && 0==osStat(zPath, &sStat) ){
    +     unixInodeInfo *pInode;
    + 
    +-    unixEnterMutex();
    +     pInode = inodeList;
    +     while( pInode && (pInode->fileId.dev!=sStat.st_dev
    +-                     || pInode->fileId.ino!=sStat.st_ino) ){
    ++                     || pInode->fileId.ino!=(u64)sStat.st_ino) ){
    +        pInode = pInode->pNext;
    +     }
    +     if( pInode ){
    +@@ -32201,15 +36383,37 @@ static UnixUnusedFd *findReusableFd(const char *zPath, int flags){
    +       for(pp=&pInode->pUnused; *pp && (*pp)->flags!=flags; pp=&((*pp)->pNext));
    +       pUnused = *pp;
    +       if( pUnused ){
    ++        nUnusedFd--;
    +         *pp = pUnused->pNext;
    +       }
    +     }
    +-    unixLeaveMutex();
    +   }
    ++  unixLeaveMutex();
    + #endif    /* if !OS_VXWORKS */
    +   return pUnused;
    + }
    + 
    ++/*
    ++** Find the mode, uid and gid of file zFile. 
    ++*/
    ++static int getFileMode(
    ++  const char *zFile,              /* File name */
    ++  mode_t *pMode,                  /* OUT: Permissions of zFile */
    ++  uid_t *pUid,                    /* OUT: uid of zFile. */
    ++  gid_t *pGid                     /* OUT: gid of zFile. */
    ++){
    ++  struct stat sStat;              /* Output of stat() on database file */
    ++  int rc = SQLITE_OK;
    ++  if( 0==osStat(zFile, &sStat) ){
    ++    *pMode = sStat.st_mode & 0777;
    ++    *pUid = sStat.st_uid;
    ++    *pGid = sStat.st_gid;
    ++  }else{
    ++    rc = SQLITE_IOERR_FSTAT;
    ++  }
    ++  return rc;
    ++}
    ++
    + /*
    + ** This function is called by unixOpen() to determine the unix permissions
    + ** to create new files with. If no error occurs, then SQLITE_OK is returned
    +@@ -32245,7 +36449,6 @@ static int findCreateFileMode(
    +   if( flags & (SQLITE_OPEN_WAL|SQLITE_OPEN_MAIN_JOURNAL) ){
    +     char zDb[MAX_PATHNAME+1];     /* Database file path */
    +     int nDb;                      /* Number of valid bytes in zDb */
    +-    struct stat sStat;            /* Output of stat() on database file */
    + 
    +     /* zPath is a path to a WAL or journal file. The following block derives
    +     ** the path to the associated database file from zPath. This block handles
    +@@ -32260,28 +36463,29 @@ static int findCreateFileMode(
    +     ** used by the test_multiplex.c module.
    +     */
    +     nDb = sqlite3Strlen30(zPath) - 1; 
    +-#ifdef SQLITE_ENABLE_8_3_NAMES
    +-    while( nDb>0 && sqlite3Isalnum(zPath[nDb]) ) nDb--;
    +-    if( nDb==0 || zPath[nDb]!='-' ) return SQLITE_OK;
    +-#else
    +     while( zPath[nDb]!='-' ){
    +-      assert( nDb>0 );
    +-      assert( zPath[nDb]!='\n' );
    ++      /* In normal operation, the journal file name will always contain
    ++      ** a '-' character.  However in 8+3 filename mode, or if a corrupt
    ++      ** rollback journal specifies a master journal with a goofy name, then
    ++      ** the '-' might be missing. */
    ++      if( nDb==0 || zPath[nDb]=='.' ) return SQLITE_OK;
    +       nDb--;
    +     }
    +-#endif
    +     memcpy(zDb, zPath, nDb);
    +     zDb[nDb] = '\0';
    + 
    +-    if( 0==osStat(zDb, &sStat) ){
    +-      *pMode = sStat.st_mode & 0777;
    +-      *pUid = sStat.st_uid;
    +-      *pGid = sStat.st_gid;
    +-    }else{
    +-      rc = unixLogError(SQLITE_IOERR_FSTAT, "stat", zDb);
    +-    }
    ++    rc = getFileMode(zDb, pMode, pUid, pGid);
    +   }else if( flags & SQLITE_OPEN_DELETEONCLOSE ){
    +     *pMode = 0600;
    ++  }else if( flags & SQLITE_OPEN_URI ){
    ++    /* If this is a main database file and the file was opened using a URI
    ++    ** filename, check for the "modeof" parameter. If present, interpret
    ++    ** its value as a filename and try to copy the mode, uid and gid from
    ++    ** that file.  */
    ++    const char *z = sqlite3_uri_parameter(zPath, "modeof");
    ++    if( z ){
    ++      rc = getFileMode(z, pMode, pUid, pGid);
    ++    }
    +   }
    +   return rc;
    + }
    +@@ -32339,7 +36543,7 @@ static int unixOpen(
    +   ** a file-descriptor on the directory too. The first time unixSync()
    +   ** is called the directory file descriptor will be fsync()ed and close()d.
    +   */
    +-  int syncDir = (isCreate && (
    ++  int isNewJrnl = (isCreate && (
    +         eType==SQLITE_OPEN_MASTER_JOURNAL 
    +      || eType==SQLITE_OPEN_MAIN_JOURNAL 
    +      || eType==SQLITE_OPEN_WAL
    +@@ -32397,10 +36601,10 @@ static int unixOpen(
    +     }else{
    +       pUnused = sqlite3_malloc64(sizeof(*pUnused));
    +       if( !pUnused ){
    +-        return SQLITE_NOMEM;
    ++        return SQLITE_NOMEM_BKPT;
    +       }
    +     }
    +-    p->pUnused = pUnused;
    ++    p->pPreallocatedUnused = pUnused;
    + 
    +     /* Database filenames are double-zero terminated if they are not
    +     ** URIs with parameters.  Hence, they can always be passed into
    +@@ -32409,8 +36613,8 @@ static int unixOpen(
    + 
    +   }else if( !zName ){
    +     /* If zName is NULL, the upper layer is requesting a temp file. */
    +-    assert(isDelete && !syncDir);
    +-    rc = unixGetTempname(MAX_PATHNAME+2, zTmpname);
    ++    assert(isDelete && !isNewJrnl);
    ++    rc = unixGetTempname(pVfs->mxPathname, zTmpname);
    +     if( rc!=SQLITE_OK ){
    +       return rc;
    +     }
    +@@ -32437,23 +36641,31 @@ static int unixOpen(
    +     gid_t gid;                    /* Groupid for the file */
    +     rc = findCreateFileMode(zName, flags, &openMode, &uid, &gid);
    +     if( rc!=SQLITE_OK ){
    +-      assert( !p->pUnused );
    ++      assert( !p->pPreallocatedUnused );
    +       assert( eType==SQLITE_OPEN_WAL || eType==SQLITE_OPEN_MAIN_JOURNAL );
    +       return rc;
    +     }
    +     fd = robust_open(zName, openFlags, openMode);
    +     OSTRACE(("OPENX   %-3d %s 0%o\n", fd, zName, openFlags));
    +-    if( fd<0 && errno!=EISDIR && isReadWrite && !isExclusive ){
    +-      /* Failed to open the file for read/write access. Try read-only. */
    +-      flags &= ~(SQLITE_OPEN_READWRITE|SQLITE_OPEN_CREATE);
    +-      openFlags &= ~(O_RDWR|O_CREAT);
    +-      flags |= SQLITE_OPEN_READONLY;
    +-      openFlags |= O_RDONLY;
    +-      isReadonly = 1;
    +-      fd = robust_open(zName, openFlags, openMode);
    ++    assert( !isExclusive || (openFlags & O_CREAT)!=0 );
    ++    if( fd<0 ){
    ++      if( isNewJrnl && errno==EACCES && osAccess(zName, F_OK) ){
    ++        /* If unable to create a journal because the directory is not
    ++        ** writable, change the error code to indicate that. */
    ++        rc = SQLITE_READONLY_DIRECTORY;
    ++      }else if( errno!=EISDIR && isReadWrite ){
    ++        /* Failed to open the file for read/write access. Try read-only. */
    ++        flags &= ~(SQLITE_OPEN_READWRITE|SQLITE_OPEN_CREATE);
    ++        openFlags &= ~(O_RDWR|O_CREAT);
    ++        flags |= SQLITE_OPEN_READONLY;
    ++        openFlags |= O_RDONLY;
    ++        isReadonly = 1;
    ++        fd = robust_open(zName, openFlags, openMode);
    ++      }
    +     }
    +     if( fd<0 ){
    +-      rc = unixLogError(SQLITE_CANTOPEN_BKPT, "open", zName);
    ++      int rc2 = unixLogError(SQLITE_CANTOPEN_BKPT, "open", zName);
    ++      if( rc==SQLITE_OK ) rc = rc2;
    +       goto open_finished;
    +     }
    + 
    +@@ -32462,7 +36674,7 @@ static int unixOpen(
    +     ** the same as the original database.
    +     */
    +     if( flags & (SQLITE_OPEN_WAL|SQLITE_OPEN_MAIN_JOURNAL) ){
    +-      osFchown(fd, uid, gid);
    ++      robustFchown(fd, uid, gid);
    +     }
    +   }
    +   assert( fd>=0 );
    +@@ -32470,9 +36682,9 @@ static int unixOpen(
    +     *pOutFlags = flags;
    +   }
    + 
    +-  if( p->pUnused ){
    +-    p->pUnused->fd = fd;
    +-    p->pUnused->flags = flags;
    ++  if( p->pPreallocatedUnused ){
    ++    p->pPreallocatedUnused->fd = fd;
    ++    p->pPreallocatedUnused->flags = flags;
    +   }
    + 
    +   if( isDelete ){
    +@@ -32482,7 +36694,7 @@ static int unixOpen(
    +     zPath = sqlite3_mprintf("%s", zName);
    +     if( zPath==0 ){
    +       robust_close(p, fd, __LINE__);
    +-      return SQLITE_NOMEM;
    ++      return SQLITE_NOMEM_BKPT;
    +     }
    + #else
    +     osUnlink(zName);
    +@@ -32493,9 +36705,6 @@ static int unixOpen(
    +     p->openFlags = openFlags;
    +   }
    + #endif
    +-
    +-  noLock = eType!=SQLITE_OPEN_MAIN_DB;
    +-
    +   
    + #if defined(__APPLE__) || SQLITE_ENABLE_LOCKING_STYLE
    +   if( fstatfs(fd, &fsInfo) == -1 ){
    +@@ -32514,8 +36723,9 @@ static int unixOpen(
    +   /* Set up appropriate ctrlFlags */
    +   if( isDelete )                ctrlFlags |= UNIXFILE_DELETE;
    +   if( isReadonly )              ctrlFlags |= UNIXFILE_RDONLY;
    ++  noLock = eType!=SQLITE_OPEN_MAIN_DB;
    +   if( noLock )                  ctrlFlags |= UNIXFILE_NOLOCK;
    +-  if( syncDir )                 ctrlFlags |= UNIXFILE_DIRSYNC;
    ++  if( isNewJrnl )               ctrlFlags |= UNIXFILE_DIRSYNC;
    +   if( flags & SQLITE_OPEN_URI ) ctrlFlags |= UNIXFILE_URI;
    + 
    + #if SQLITE_ENABLE_LOCKING_STYLE
    +@@ -32551,11 +36761,14 @@ static int unixOpen(
    +   }
    + #endif
    +   
    ++  assert( zPath==0 || zPath[0]=='/' 
    ++      || eType==SQLITE_OPEN_MASTER_JOURNAL || eType==SQLITE_OPEN_MAIN_JOURNAL 
    ++  );
    +   rc = fillInUnixFile(pVfs, fd, pFile, zPath, ctrlFlags);
    + 
    + open_finished:
    +   if( rc!=SQLITE_OK ){
    +-    sqlite3_free(p->pUnused);
    ++    sqlite3_free(p->pPreallocatedUnused);
    +   }
    +   return rc;
    + }
    +@@ -32590,16 +36803,12 @@ static int unixDelete(
    +     int fd;
    +     rc = osOpenDirectory(zPath, &fd);
    +     if( rc==SQLITE_OK ){
    +-#if OS_VXWORKS
    +-      if( fsync(fd)==-1 )
    +-#else
    +-      if( fsync(fd) )
    +-#endif
    +-      {
    ++      if( full_fsync(fd,0,0) ){
    +         rc = unixLogError(SQLITE_IOERR_DIR_FSYNC, "fsync", zPath);
    +       }
    +       robust_close(0, fd, __LINE__);
    +-    }else if( rc==SQLITE_CANTOPEN ){
    ++    }else{
    ++      assert( rc==SQLITE_CANTOPEN );
    +       rc = SQLITE_OK;
    +     }
    +   }
    +@@ -32623,33 +36832,49 @@ static int unixAccess(
    +   int flags,              /* What do we want to learn about the zPath file? */
    +   int *pResOut            /* Write result boolean here */
    + ){
    +-  int amode = 0;
    +   UNUSED_PARAMETER(NotUsed);
    +   SimulateIOError( return SQLITE_IOERR_ACCESS; );
    +-  switch( flags ){
    +-    case SQLITE_ACCESS_EXISTS:
    +-      amode = F_OK;
    +-      break;
    +-    case SQLITE_ACCESS_READWRITE:
    +-      amode = W_OK|R_OK;
    +-      break;
    +-    case SQLITE_ACCESS_READ:
    +-      amode = R_OK;
    +-      break;
    ++  assert( pResOut!=0 );
    + 
    +-    default:
    +-      assert(!"Invalid flags argument");
    +-  }
    +-  *pResOut = (osAccess(zPath, amode)==0);
    +-  if( flags==SQLITE_ACCESS_EXISTS && *pResOut ){
    ++  /* The spec says there are three possible values for flags.  But only
    ++  ** two of them are actually used */
    ++  assert( flags==SQLITE_ACCESS_EXISTS || flags==SQLITE_ACCESS_READWRITE );
    ++
    ++  if( flags==SQLITE_ACCESS_EXISTS ){
    +     struct stat buf;
    +-    if( 0==osStat(zPath, &buf) && buf.st_size==0 ){
    +-      *pResOut = 0;
    +-    }
    ++    *pResOut = (0==osStat(zPath, &buf) && buf.st_size>0);
    ++  }else{
    ++    *pResOut = osAccess(zPath, W_OK|R_OK)==0;
    +   }
    +   return SQLITE_OK;
    + }
    + 
    ++/*
    ++**
    ++*/
    ++static int mkFullPathname(
    ++  const char *zPath,              /* Input path */
    ++  char *zOut,                     /* Output buffer */
    ++  int nOut                        /* Allocated size of buffer zOut */
    ++){
    ++  int nPath = sqlite3Strlen30(zPath);
    ++  int iOff = 0;
    ++  if( zPath[0]!='/' ){
    ++    if( osGetcwd(zOut, nOut-2)==0 ){
    ++      return unixLogError(SQLITE_CANTOPEN_BKPT, "getcwd", zPath);
    ++    }
    ++    iOff = sqlite3Strlen30(zOut);
    ++    zOut[iOff++] = '/';
    ++  }
    ++  if( (iOff+nPath+1)>nOut ){
    ++    /* SQLite assumes that xFullPathname() nul-terminates the output buffer
    ++    ** even if it returns an error.  */
    ++    zOut[iOff] = '\0';
    ++    return SQLITE_CANTOPEN_BKPT;
    ++  }
    ++  sqlite3_snprintf(nOut-iOff, &zOut[iOff], "%s", zPath);
    ++  return SQLITE_OK;
    ++}
    + 
    + /*
    + ** Turn a relative pathname into a full pathname. The relative path
    +@@ -32666,6 +36891,17 @@ static int unixFullPathname(
    +   int nOut,                     /* Size of output buffer in bytes */
    +   char *zOut                    /* Output buffer */
    + ){
    ++#if !defined(HAVE_READLINK) || !defined(HAVE_LSTAT)
    ++  return mkFullPathname(zPath, zOut, nOut);
    ++#else
    ++  int rc = SQLITE_OK;
    ++  int nByte;
    ++  int nLink = 1;                /* Number of symbolic links followed so far */
    ++  const char *zIn = zPath;      /* Input path for each iteration of loop */
    ++  char *zDel = 0;
    ++
    ++  assert( pVfs->mxPathname==MAX_PATHNAME );
    ++  UNUSED_PARAMETER(pVfs);
    + 
    +   /* 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
    +@@ -32674,21 +36910,62 @@ static int unixFullPathname(
    +   */
    +   SimulateIOError( return SQLITE_ERROR );
    + 
    +-  assert( pVfs->mxPathname==MAX_PATHNAME );
    +-  UNUSED_PARAMETER(pVfs);
    ++  do {
    + 
    +-  zOut[nOut-1] = '\0';
    +-  if( zPath[0]=='/' ){
    +-    sqlite3_snprintf(nOut, zOut, "%s", zPath);
    +-  }else{
    +-    int nCwd;
    +-    if( osGetcwd(zOut, nOut-1)==0 ){
    +-      return unixLogError(SQLITE_CANTOPEN_BKPT, "getcwd", zPath);
    ++    /* Call stat() on path zIn. Set bLink to true if the path is a symbolic
    ++    ** link, or false otherwise.  */
    ++    int bLink = 0;
    ++    struct stat buf;
    ++    if( osLstat(zIn, &buf)!=0 ){
    ++      if( errno!=ENOENT ){
    ++        rc = unixLogError(SQLITE_CANTOPEN_BKPT, "lstat", zIn);
    ++      }
    ++    }else{
    ++      bLink = S_ISLNK(buf.st_mode);
    +     }
    +-    nCwd = (int)strlen(zOut);
    +-    sqlite3_snprintf(nOut-nCwd, &zOut[nCwd], "/%s", zPath);
    +-  }
    +-  return SQLITE_OK;
    ++
    ++    if( bLink ){
    ++      if( zDel==0 ){
    ++        zDel = sqlite3_malloc(nOut);
    ++        if( zDel==0 ) rc = SQLITE_NOMEM_BKPT;
    ++      }else if( ++nLink>SQLITE_MAX_SYMLINKS ){
    ++        rc = SQLITE_CANTOPEN_BKPT;
    ++      }
    ++
    ++      if( rc==SQLITE_OK ){
    ++        nByte = osReadlink(zIn, zDel, nOut-1);
    ++        if( nByte<0 ){
    ++          rc = unixLogError(SQLITE_CANTOPEN_BKPT, "readlink", zIn);
    ++        }else{
    ++          if( zDel[0]!='/' ){
    ++            int n;
    ++            for(n = sqlite3Strlen30(zIn); n>0 && zIn[n-1]!='/'; n--);
    ++            if( nByte+n+1>nOut ){
    ++              rc = SQLITE_CANTOPEN_BKPT;
    ++            }else{
    ++              memmove(&zDel[n], zDel, nByte+1);
    ++              memcpy(zDel, zIn, n);
    ++              nByte += n;
    ++            }
    ++          }
    ++          zDel[nByte] = '\0';
    ++        }
    ++      }
    ++
    ++      zIn = zDel;
    ++    }
    ++
    ++    assert( rc!=SQLITE_OK || zIn!=zOut || zIn[0]=='/' );
    ++    if( rc==SQLITE_OK && zIn!=zOut ){
    ++      rc = mkFullPathname(zIn, zOut, nOut);
    ++    }
    ++    if( bLink==0 ) break;
    ++    zIn = zOut;
    ++  }while( rc==SQLITE_OK );
    ++
    ++  sqlite3_free(zDel);
    ++  return rc;
    ++#endif   /* HAVE_READLINK && HAVE_LSTAT */
    + }
    + 
    + 
    +@@ -32857,11 +37134,8 @@ static int unixCurrentTimeInt64(sqlite3_vfs *NotUsed, sqlite3_int64 *piNow){
    +   *piNow = unixEpoch + 1000*(sqlite3_int64)sNow.tv_sec + sNow.tv_nsec/1000000;
    + #else
    +   struct timeval sNow;
    +-  if( gettimeofday(&sNow, 0)==0 ){
    +-    *piNow = unixEpoch + 1000*(sqlite3_int64)sNow.tv_sec + sNow.tv_usec/1000;
    +-  }else{
    +-    rc = SQLITE_ERROR;
    +-  }
    ++  (void)gettimeofday(&sNow, 0);  /* Cannot fail given valid arguments */
    ++  *piNow = unixEpoch + 1000*(sqlite3_int64)sNow.tv_sec + sNow.tv_usec/1000;
    + #endif
    + 
    + #ifdef SQLITE_TEST
    +@@ -32873,6 +37147,7 @@ static int unixCurrentTimeInt64(sqlite3_vfs *NotUsed, sqlite3_int64 *piNow){
    +   return rc;
    + }
    + 
    ++#ifndef SQLITE_OMIT_DEPRECATED
    + /*
    + ** Find the current time (in Universal Coordinated Time).  Write the
    + ** current time and date as a Julian Day number into *prNow and
    +@@ -32886,19 +37161,21 @@ static int unixCurrentTime(sqlite3_vfs *NotUsed, double *prNow){
    +   *prNow = i/86400000.0;
    +   return rc;
    + }
    ++#else
    ++# define unixCurrentTime 0
    ++#endif
    + 
    + /*
    +-** We added the xGetLastError() method with the intention of providing
    +-** better low-level error messages when operating-system problems come up
    +-** during SQLite operation.  But so far, none of that has been implemented
    +-** in the core.  So this routine is never called.  For now, it is merely
    +-** a place-holder.
    ++** The xGetLastError() method is designed to return a better
    ++** low-level error message when operating-system problems come up
    ++** during SQLite operation.  Only the integer return code is currently
    ++** used.
    + */
    + static int unixGetLastError(sqlite3_vfs *NotUsed, int NotUsed2, char *NotUsed3){
    +   UNUSED_PARAMETER(NotUsed);
    +   UNUSED_PARAMETER(NotUsed2);
    +   UNUSED_PARAMETER(NotUsed3);
    +-  return 0;
    ++  return errno;
    + }
    + 
    + 
    +@@ -33153,7 +37430,7 @@ static int proxyCreateLockPath(const char *lockPath){
    +     }
    +     buf[i] = lockPath[i];
    +   }
    +-  OSTRACE(("CREATELOCKPATH  proxy lock path=%s pid=%d\n", lockPath, osGetpid(0)));
    ++  OSTRACE(("CREATELOCKPATH  proxy lock path=%s pid=%d\n",lockPath,osGetpid(0)));
    +   return 0;
    + }
    + 
    +@@ -33189,7 +37466,7 @@ static int proxyCreateUnixFile(
    +   }else{
    +     pUnused = sqlite3_malloc64(sizeof(*pUnused));
    +     if( !pUnused ){
    +-      return SQLITE_NOMEM;
    ++      return SQLITE_NOMEM_BKPT;
    +     }
    +   }
    +   if( fd<0 ){
    +@@ -33222,7 +37499,7 @@ static int proxyCreateUnixFile(
    +   
    +   pNew = (unixFile *)sqlite3_malloc64(sizeof(*pNew));
    +   if( pNew==NULL ){
    +-    rc = SQLITE_NOMEM;
    ++    rc = SQLITE_NOMEM_BKPT;
    +     goto end_create_proxy;
    +   }
    +   memset(pNew, 0, sizeof(unixFile));
    +@@ -33232,7 +37509,7 @@ static int proxyCreateUnixFile(
    +   dummyVfs.zName = "dummy";
    +   pUnused->fd = fd;
    +   pUnused->flags = openFlags;
    +-  pNew->pUnused = pUnused;
    ++  pNew->pPreallocatedUnused = pUnused;
    +   
    +   rc = fillInUnixFile(&dummyVfs, fd, (sqlite3_file*)pNew, path, 0);
    +   if( rc==SQLITE_OK ){
    +@@ -33565,7 +37842,7 @@ static int proxyTakeConch(unixFile *pFile){
    +         writeSize = PROXY_PATHINDEX + strlen(&writeBuffer[PROXY_PATHINDEX]);
    +         robust_ftruncate(conchFile->h, writeSize);
    +         rc = unixWrite((sqlite3_file *)conchFile, writeBuffer, writeSize, 0);
    +-        fsync(conchFile->h);
    ++        full_fsync(conchFile->h,0,0);
    +         /* If we created a new conch file (not just updated the contents of a 
    +          ** valid conch file), try to match the permissions of the database 
    +          */
    +@@ -33635,7 +37912,7 @@ static int proxyTakeConch(unixFile *pFile){
    +         if( tempLockPath ){
    +           pCtx->lockProxyPath = sqlite3DbStrDup(0, tempLockPath);
    +           if( !pCtx->lockProxyPath ){
    +-            rc = SQLITE_NOMEM;
    ++            rc = SQLITE_NOMEM_BKPT;
    +           }
    +         }
    +       }
    +@@ -33700,7 +37977,7 @@ static int proxyCreateConchPathname(char *dbPath, char **pConchPath){
    +   ** the name of the original database file. */  
    +   *pConchPath = conchPath = (char *)sqlite3_malloc64(len + 8);
    +   if( conchPath==0 ){
    +-    return SQLITE_NOMEM;
    ++    return SQLITE_NOMEM_BKPT;
    +   }
    +   memcpy(conchPath, dbPath, len+1);
    +   
    +@@ -33816,7 +38093,7 @@ static int proxyTransformUnixFile(unixFile *pFile, const char *path) {
    + 
    +   pCtx = sqlite3_malloc64( sizeof(*pCtx) );
    +   if( pCtx==0 ){
    +-    return SQLITE_NOMEM;
    ++    return SQLITE_NOMEM_BKPT;
    +   }
    +   memset(pCtx, 0, sizeof(*pCtx));
    + 
    +@@ -33852,7 +38129,7 @@ static int proxyTransformUnixFile(unixFile *pFile, const char *path) {
    +   if( rc==SQLITE_OK ){
    +     pCtx->dbPath = sqlite3DbStrDup(0, dbPath);
    +     if( pCtx->dbPath==NULL ){
    +-      rc = SQLITE_NOMEM;
    ++      rc = SQLITE_NOMEM_BKPT;
    +     }
    +   }
    +   if( rc==SQLITE_OK ){
    +@@ -34038,7 +38315,7 @@ static int proxyUnlock(sqlite3_file *id, int eFileLock) {
    + ** Close a file that uses proxy locks.
    + */
    + static int proxyClose(sqlite3_file *id) {
    +-  if( id ){
    ++  if( ALWAYS(id) ){
    +     unixFile *pFile = (unixFile*)id;
    +     proxyLockingContext *pCtx = (proxyLockingContext *)pFile->lockingContext;
    +     unixFile *lockProxy = pCtx->lockProxy;
    +@@ -34099,7 +38376,7 @@ static int proxyClose(sqlite3_file *id) {
    + ** necessarily been initialized when this routine is called, and so they
    + ** should not be used.
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_os_init(void){ 
    ++SQLITE_API int sqlite3_os_init(void){ 
    +   /* 
    +   ** The following macro defines an initializer for an sqlite3_vfs object.
    +   ** The name of the VFS is NAME.  The pAppData is a pointer to a pointer
    +@@ -34182,7 +38459,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_os_init(void){
    + 
    +   /* Double-check that the aSyscall[] array has been constructed
    +   ** correctly.  See ticket [bb3a86e890c8e96ab] */
    +-  assert( ArraySize(aSyscall)==25 );
    ++  assert( ArraySize(aSyscall)==29 );
    + 
    +   /* Register all VFSes defined in the aVfs[] array */
    +   for(i=0; i<(sizeof(aVfs)/sizeof(sqlite3_vfs)); i++){
    +@@ -34198,7 +38475,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_os_init(void){
    + ** to release dynamically allocated objects.  But not on unix.
    + ** This routine is a no-op for unix.
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_os_end(void){ 
    ++SQLITE_API int sqlite3_os_end(void){ 
    +   return SQLITE_OK; 
    + }
    +  
    +@@ -34265,8 +38542,8 @@ SQLITE_API int SQLITE_STDCALL sqlite3_os_end(void){
    + */
    + #ifdef SQLITE_PERFORMANCE_TRACE
    + 
    +-/* 
    +-** hwtime.h contains inline assembler code for implementing 
    ++/*
    ++** hwtime.h contains inline assembler code for implementing
    + ** high-performance timing routines.
    + */
    + /************** Include hwtime.h in the middle of os_common.h ****************/
    +@@ -34286,8 +38563,8 @@ SQLITE_API int SQLITE_STDCALL sqlite3_os_end(void){
    + ** This file contains inline asm code for retrieving "high-performance"
    + ** counters for x86 class CPUs.
    + */
    +-#ifndef _HWTIME_H_
    +-#define _HWTIME_H_
    ++#ifndef SQLITE_HWTIME_H
    ++#define SQLITE_HWTIME_H
    + 
    + /*
    + ** The following routine only works on pentium-class (or newer) processors.
    +@@ -34355,7 +38632,7 @@ SQLITE_PRIVATE   sqlite_uint64 sqlite3Hwtime(void){ return ((sqlite_uint64)0); }
    + 
    + #endif
    + 
    +-#endif /* !defined(_HWTIME_H_) */
    ++#endif /* !defined(SQLITE_HWTIME_H) */
    + 
    + /************** End of hwtime.h **********************************************/
    + /************** Continuing where we left off in os_common.h ******************/
    +@@ -34376,14 +38653,14 @@ static sqlite_uint64 g_elapsed;
    + ** 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;
    ++#if defined(SQLITE_TEST)
    ++SQLITE_API extern int sqlite3_io_error_hit;
    ++SQLITE_API extern int sqlite3_io_error_hardhit;
    ++SQLITE_API extern int sqlite3_io_error_pending;
    ++SQLITE_API extern int sqlite3_io_error_persist;
    ++SQLITE_API extern int sqlite3_io_error_benign;
    ++SQLITE_API extern int sqlite3_diskfull_pending;
    ++SQLITE_API extern int sqlite3_diskfull;
    + #define SimulateIOErrorBenign(X) sqlite3_io_error_benign=(X)
    + #define SimulateIOError(CODE)  \
    +   if( (sqlite3_io_error_persist && sqlite3_io_error_hit) \
    +@@ -34409,17 +38686,17 @@ static void local_ioerr(){
    + #define SimulateIOErrorBenign(X)
    + #define SimulateIOError(A)
    + #define SimulateDiskfullError(A)
    +-#endif
    ++#endif /* defined(SQLITE_TEST) */
    + 
    + /*
    + ** When testing, keep a count of the number of open files.
    + */
    +-#ifdef SQLITE_TEST
    +-SQLITE_API int sqlite3_open_file_count = 0;
    ++#if defined(SQLITE_TEST)
    ++SQLITE_API extern int sqlite3_open_file_count;
    + #define OpenCounter(X)  sqlite3_open_file_count+=(X)
    + #else
    + #define OpenCounter(X)
    +-#endif
    ++#endif /* defined(SQLITE_TEST) */
    + 
    + #endif /* !defined(_OS_COMMON_H_) */
    + 
    +@@ -34482,6 +38759,10 @@ SQLITE_API int sqlite3_open_file_count = 0;
    + #  define NTDDI_WINBLUE                     0x06030000
    + #endif
    + 
    ++#ifndef NTDDI_WINTHRESHOLD
    ++#  define NTDDI_WINTHRESHOLD                0x06040000
    ++#endif
    ++
    + /*
    + ** Check to see if the GetVersionEx[AW] functions are deprecated on the
    + ** target system.  GetVersionEx was first deprecated in Win8.1.
    +@@ -34494,6 +38775,19 @@ SQLITE_API int sqlite3_open_file_count = 0;
    + #  endif
    + #endif
    + 
    ++/*
    ++** Check to see if the CreateFileMappingA function is supported on the
    ++** target system.  It is unavailable when using "mincore.lib" on Win10.
    ++** When compiling for Windows 10, always assume "mincore.lib" is in use.
    ++*/
    ++#ifndef SQLITE_WIN32_CREATEFILEMAPPINGA
    ++#  if defined(NTDDI_VERSION) && NTDDI_VERSION >= NTDDI_WINTHRESHOLD
    ++#    define SQLITE_WIN32_CREATEFILEMAPPINGA   0
    ++#  else
    ++#    define SQLITE_WIN32_CREATEFILEMAPPINGA   1
    ++#  endif
    ++#endif
    ++
    + /*
    + ** This constant should already be defined (in the "WinDef.h" SDK file).
    + */
    +@@ -34679,6 +38973,17 @@ struct winFile {
    + #endif
    + };
    + 
    ++/*
    ++** The winVfsAppData structure is used for the pAppData member for all of the
    ++** Win32 VFS variants.
    ++*/
    ++typedef struct winVfsAppData winVfsAppData;
    ++struct winVfsAppData {
    ++  const sqlite3_io_methods *pMethod; /* The file I/O methods to use. */
    ++  void *pAppData;                    /* The extra pAppData, if any. */
    ++  BOOL bNoLock;                      /* Non-zero if locking is disabled. */
    ++};
    ++
    + /*
    + ** Allowed values for winFile.ctrlFlags
    + */
    +@@ -34730,22 +39035,72 @@ struct winFile {
    +  ******************************************************************************
    +  */
    + #ifndef SQLITE_WIN32_HEAP_CREATE
    +-#  define SQLITE_WIN32_HEAP_CREATE    (TRUE)
    ++#  define SQLITE_WIN32_HEAP_CREATE        (TRUE)
    ++#endif
    ++
    ++/*
    ++ * This is the maximum possible initial size of the Win32-specific heap, in
    ++ * bytes.
    ++ */
    ++#ifndef SQLITE_WIN32_HEAP_MAX_INIT_SIZE
    ++#  define SQLITE_WIN32_HEAP_MAX_INIT_SIZE (4294967295U)
    ++#endif
    ++
    ++/*
    ++ * This is the extra space for the initial size of the Win32-specific heap,
    ++ * in bytes.  This value may be zero.
    ++ */
    ++#ifndef SQLITE_WIN32_HEAP_INIT_EXTRA
    ++#  define SQLITE_WIN32_HEAP_INIT_EXTRA  (4194304)
    ++#endif
    ++
    ++/*
    ++ * Calculate the maximum legal cache size, in pages, based on the maximum
    ++ * possible initial heap size and the default page size, setting aside the
    ++ * needed extra space.
    ++ */
    ++#ifndef SQLITE_WIN32_MAX_CACHE_SIZE
    ++#  define SQLITE_WIN32_MAX_CACHE_SIZE   (((SQLITE_WIN32_HEAP_MAX_INIT_SIZE) - \
    ++                                          (SQLITE_WIN32_HEAP_INIT_EXTRA)) / \
    ++                                         (SQLITE_DEFAULT_PAGE_SIZE))
    ++#endif
    ++
    ++/*
    ++ * This is cache size used in the calculation of the initial size of the
    ++ * Win32-specific heap.  It cannot be negative.
    ++ */
    ++#ifndef SQLITE_WIN32_CACHE_SIZE
    ++#  if SQLITE_DEFAULT_CACHE_SIZE>=0
    ++#    define SQLITE_WIN32_CACHE_SIZE     (SQLITE_DEFAULT_CACHE_SIZE)
    ++#  else
    ++#    define SQLITE_WIN32_CACHE_SIZE     (-(SQLITE_DEFAULT_CACHE_SIZE))
    ++#  endif
    ++#endif
    ++
    ++/*
    ++ * Make sure that the calculated cache size, in pages, cannot cause the
    ++ * initial size of the Win32-specific heap to exceed the maximum amount
    ++ * of memory that can be specified in the call to HeapCreate.
    ++ */
    ++#if SQLITE_WIN32_CACHE_SIZE>SQLITE_WIN32_MAX_CACHE_SIZE
    ++#  undef SQLITE_WIN32_CACHE_SIZE
    ++#  define SQLITE_WIN32_CACHE_SIZE       (2000)
    + #endif
    + 
    + /*
    +  * The initial size of the Win32-specific heap.  This value may be zero.
    +  */
    + #ifndef SQLITE_WIN32_HEAP_INIT_SIZE
    +-#  define SQLITE_WIN32_HEAP_INIT_SIZE ((SQLITE_DEFAULT_CACHE_SIZE) * \
    +-                                       (SQLITE_DEFAULT_PAGE_SIZE) + 4194304)
    ++#  define SQLITE_WIN32_HEAP_INIT_SIZE   ((SQLITE_WIN32_CACHE_SIZE) * \
    ++                                         (SQLITE_DEFAULT_PAGE_SIZE) + \
    ++                                         (SQLITE_WIN32_HEAP_INIT_EXTRA))
    + #endif
    + 
    + /*
    +  * The maximum size of the Win32-specific heap.  This value may be zero.
    +  */
    + #ifndef SQLITE_WIN32_HEAP_MAX_SIZE
    +-#  define SQLITE_WIN32_HEAP_MAX_SIZE  (0)
    ++#  define SQLITE_WIN32_HEAP_MAX_SIZE    (0)
    + #endif
    + 
    + /*
    +@@ -34753,7 +39108,7 @@ struct winFile {
    +  * zero for the default behavior.
    +  */
    + #ifndef SQLITE_WIN32_HEAP_FLAGS
    +-#  define SQLITE_WIN32_HEAP_FLAGS     (0)
    ++#  define SQLITE_WIN32_HEAP_FLAGS       (0)
    + #endif
    + 
    + 
    +@@ -34900,8 +39255,9 @@ static struct win_syscall {
    + #define osCreateFileW ((HANDLE(WINAPI*)(LPCWSTR,DWORD,DWORD, \
    +         LPSECURITY_ATTRIBUTES,DWORD,DWORD,HANDLE))aSyscall[5].pCurrent)
    + 
    +-#if (!SQLITE_OS_WINRT && defined(SQLITE_WIN32_HAS_ANSI) && \
    +-        (!defined(SQLITE_OMIT_WAL) || SQLITE_MAX_MMAP_SIZE>0))
    ++#if !SQLITE_OS_WINRT && defined(SQLITE_WIN32_HAS_ANSI) && \
    ++        (!defined(SQLITE_OMIT_WAL) || SQLITE_MAX_MMAP_SIZE>0) && \
    ++        SQLITE_WIN32_CREATEFILEMAPPINGA
    +   { "CreateFileMappingA",      (SYSCALL)CreateFileMappingA,      0 },
    + #else
    +   { "CreateFileMappingA",      (SYSCALL)0,                       0 },
    +@@ -35131,8 +39487,7 @@ static struct win_syscall {
    + 
    + #define osGetTickCount ((DWORD(WINAPI*)(VOID))aSyscall[33].pCurrent)
    + 
    +-#if defined(SQLITE_WIN32_HAS_ANSI) && defined(SQLITE_WIN32_GETVERSIONEX) && \
    +-        SQLITE_WIN32_GETVERSIONEX
    ++#if defined(SQLITE_WIN32_HAS_ANSI) && SQLITE_WIN32_GETVERSIONEX
    +   { "GetVersionExA",           (SYSCALL)GetVersionExA,           0 },
    + #else
    +   { "GetVersionExA",           (SYSCALL)0,                       0 },
    +@@ -35142,7 +39497,7 @@ static struct win_syscall {
    +         LPOSVERSIONINFOA))aSyscall[34].pCurrent)
    + 
    + #if !SQLITE_OS_WINRT && defined(SQLITE_WIN32_HAS_WIDE) && \
    +-        defined(SQLITE_WIN32_GETVERSIONEX) && SQLITE_WIN32_GETVERSIONEX
    ++        SQLITE_WIN32_GETVERSIONEX
    +   { "GetVersionExW",           (SYSCALL)GetVersionExW,           0 },
    + #else
    +   { "GetVersionExW",           (SYSCALL)0,                       0 },
    +@@ -35593,7 +39948,7 @@ static const char *winNextSystemCall(sqlite3_vfs *p, const char *zName){
    + ** "pnLargest" argument, if non-zero, will be used to return the size of the
    + ** largest committed free block in the heap, in bytes.
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_win32_compact_heap(LPUINT pnLargest){
    ++SQLITE_API int sqlite3_win32_compact_heap(LPUINT pnLargest){
    +   int rc = SQLITE_OK;
    +   UINT nLargest = 0;
    +   HANDLE hHeap;
    +@@ -35611,7 +39966,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_win32_compact_heap(LPUINT pnLargest){
    +     if( lastErrno==NO_ERROR ){
    +       sqlite3_log(SQLITE_NOMEM, "failed to HeapCompact (no space), heap=%p",
    +                   (void*)hHeap);
    +-      rc = SQLITE_NOMEM;
    ++      rc = SQLITE_NOMEM_BKPT;
    +     }else{
    +       sqlite3_log(SQLITE_ERROR, "failed to HeapCompact (%lu), heap=%p",
    +                   osGetLastError(), (void*)hHeap);
    +@@ -35633,12 +39988,12 @@ SQLITE_API int SQLITE_STDCALL sqlite3_win32_compact_heap(LPUINT pnLargest){
    + ** the sqlite3_memory_used() function does not return zero, SQLITE_BUSY will
    + ** be returned and no changes will be made to the Win32 native heap.
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_win32_reset_heap(){
    ++SQLITE_API int sqlite3_win32_reset_heap(){
    +   int rc;
    +   MUTEX_LOGIC( sqlite3_mutex *pMaster; ) /* The main static mutex */
    +   MUTEX_LOGIC( sqlite3_mutex *pMem; )    /* The memsys static mutex */
    +-  MUTEX_LOGIC( pMaster = sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_MASTER); )
    +-  MUTEX_LOGIC( pMem = sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_MEM); )
    ++  MUTEX_LOGIC( pMaster = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MASTER); )
    ++  MUTEX_LOGIC( pMem = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MEM); )
    +   sqlite3_mutex_enter(pMaster);
    +   sqlite3_mutex_enter(pMem);
    +   winMemAssertMagic();
    +@@ -35678,11 +40033,17 @@ SQLITE_API int SQLITE_STDCALL sqlite3_win32_reset_heap(){
    + ** (if available).
    + */
    + 
    +-SQLITE_API void SQLITE_STDCALL sqlite3_win32_write_debug(const char *zBuf, int nBuf){
    ++SQLITE_API void sqlite3_win32_write_debug(const char *zBuf, int nBuf){
    +   char zDbgBuf[SQLITE_WIN32_DBG_BUF_SIZE];
    +   int nMin = MIN(nBuf, (SQLITE_WIN32_DBG_BUF_SIZE - 1)); /* may be negative. */
    +   if( nMin<-1 ) nMin = -1; /* all negative values become -1. */
    +   assert( nMin==-1 || nMin==0 || nMin<SQLITE_WIN32_DBG_BUF_SIZE );
    ++#ifdef SQLITE_ENABLE_API_ARMOR
    ++  if( !zBuf ){
    ++    (void)SQLITE_MISUSE_BKPT;
    ++    return;
    ++  }
    ++#endif
    + #if defined(SQLITE_WIN32_HAS_ANSI)
    +   if( nMin>0 ){
    +     memset(zDbgBuf, 0, SQLITE_WIN32_DBG_BUF_SIZE);
    +@@ -35718,7 +40079,7 @@ SQLITE_API void SQLITE_STDCALL sqlite3_win32_write_debug(const char *zBuf, int n
    + static HANDLE sleepObj = NULL;
    + #endif
    + 
    +-SQLITE_API void SQLITE_STDCALL sqlite3_win32_sleep(DWORD milliseconds){
    ++SQLITE_API void sqlite3_win32_sleep(DWORD milliseconds){
    + #if SQLITE_OS_WINRT
    +   if ( sleepObj==NULL ){
    +     sleepObj = osCreateEventExW(NULL, NULL, CREATE_EVENT_MANUAL_RESET,
    +@@ -35753,7 +40114,7 @@ SQLITE_PRIVATE DWORD sqlite3Win32Wait(HANDLE hObject){
    + ** the LockFileEx() API.
    + */
    + 
    +-#if !defined(SQLITE_WIN32_GETVERSIONEX) || !SQLITE_WIN32_GETVERSIONEX
    ++#if !SQLITE_WIN32_GETVERSIONEX
    + # define osIsNT()  (1)
    + #elif SQLITE_OS_WINCE || SQLITE_OS_WINRT || !defined(SQLITE_WIN32_HAS_ANSI)
    + # define osIsNT()  (1)
    +@@ -35767,14 +40128,14 @@ SQLITE_PRIVATE DWORD sqlite3Win32Wait(HANDLE hObject){
    + ** This function determines if the machine is running a version of Windows
    + ** based on the NT kernel.
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_win32_is_nt(void){
    ++SQLITE_API int sqlite3_win32_is_nt(void){
    + #if SQLITE_OS_WINRT
    +   /*
    +   ** NOTE: The WinRT sub-platform is always assumed to be based on the NT
    +   **       kernel.
    +   */
    +   return 1;
    +-#elif defined(SQLITE_WIN32_GETVERSIONEX) && SQLITE_WIN32_GETVERSIONEX
    ++#elif SQLITE_WIN32_GETVERSIONEX
    +   if( osInterlockedCompareExchange(&sqlite3_os_type, 0, 0)==0 ){
    + #if defined(SQLITE_WIN32_HAS_ANSI)
    +     OSVERSIONINFOA sInfo;
    +@@ -35931,7 +40292,7 @@ static int winMemInit(void *pAppData){
    +           "failed to HeapCreate (%lu), flags=%u, initSize=%lu, maxSize=%lu",
    +           osGetLastError(), SQLITE_WIN32_HEAP_FLAGS, dwInitialSize,
    +           dwMaximumSize);
    +-      return SQLITE_NOMEM;
    ++      return SQLITE_NOMEM_BKPT;
    +     }
    +     pWinMemData->bOwned = TRUE;
    +     assert( pWinMemData->bOwned );
    +@@ -35941,7 +40302,7 @@ static int winMemInit(void *pAppData){
    +   if( !pWinMemData->hHeap ){
    +     sqlite3_log(SQLITE_NOMEM,
    +         "failed to GetProcessHeap (%lu)", osGetLastError());
    +-    return SQLITE_NOMEM;
    ++    return SQLITE_NOMEM_BKPT;
    +   }
    +   pWinMemData->bOwned = FALSE;
    +   assert( !pWinMemData->bOwned );
    +@@ -36008,147 +40369,244 @@ 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.
    + **
    +-** Space to hold the returned string is obtained from malloc.
    ++** Space to hold the returned string is obtained from sqlite3_malloc().
    + */
    +-static LPWSTR winUtf8ToUnicode(const char *zFilename){
    ++static LPWSTR winUtf8ToUnicode(const char *zText){
    +   int nChar;
    +-  LPWSTR zWideFilename;
    ++  LPWSTR zWideText;
    + 
    +-  nChar = osMultiByteToWideChar(CP_UTF8, 0, zFilename, -1, NULL, 0);
    ++  nChar = osMultiByteToWideChar(CP_UTF8, 0, zText, -1, NULL, 0);
    +   if( nChar==0 ){
    +     return 0;
    +   }
    +-  zWideFilename = sqlite3MallocZero( nChar*sizeof(zWideFilename[0]) );
    +-  if( zWideFilename==0 ){
    ++  zWideText = sqlite3MallocZero( nChar*sizeof(WCHAR) );
    ++  if( zWideText==0 ){
    +     return 0;
    +   }
    +-  nChar = osMultiByteToWideChar(CP_UTF8, 0, zFilename, -1, zWideFilename,
    ++  nChar = osMultiByteToWideChar(CP_UTF8, 0, zText, -1, zWideText,
    +                                 nChar);
    +   if( nChar==0 ){
    +-    sqlite3_free(zWideFilename);
    +-    zWideFilename = 0;
    ++    sqlite3_free(zWideText);
    ++    zWideText = 0;
    +   }
    +-  return zWideFilename;
    ++  return zWideText;
    + }
    + 
    + /*
    +-** Convert Microsoft Unicode to UTF-8.  Space to hold the returned string is
    +-** obtained from sqlite3_malloc().
    ++** Convert a Microsoft Unicode string to UTF-8.
    ++**
    ++** Space to hold the returned string is obtained from sqlite3_malloc().
    + */
    +-static char *winUnicodeToUtf8(LPCWSTR zWideFilename){
    ++static char *winUnicodeToUtf8(LPCWSTR zWideText){
    +   int nByte;
    +-  char *zFilename;
    ++  char *zText;
    + 
    +-  nByte = osWideCharToMultiByte(CP_UTF8, 0, zWideFilename, -1, 0, 0, 0, 0);
    ++  nByte = osWideCharToMultiByte(CP_UTF8, 0, zWideText, -1, 0, 0, 0, 0);
    +   if( nByte == 0 ){
    +     return 0;
    +   }
    +-  zFilename = sqlite3MallocZero( nByte );
    +-  if( zFilename==0 ){
    ++  zText = sqlite3MallocZero( nByte );
    ++  if( zText==0 ){
    +     return 0;
    +   }
    +-  nByte = osWideCharToMultiByte(CP_UTF8, 0, zWideFilename, -1, zFilename, nByte,
    ++  nByte = osWideCharToMultiByte(CP_UTF8, 0, zWideText, -1, zText, nByte,
    +                                 0, 0);
    +   if( nByte == 0 ){
    +-    sqlite3_free(zFilename);
    +-    zFilename = 0;
    ++    sqlite3_free(zText);
    ++    zText = 0;
    +   }
    +-  return zFilename;
    ++  return zText;
    + }
    + 
    + /*
    +-** Convert an ANSI string to Microsoft Unicode, based on the
    +-** current codepage settings for file apis.
    ++** Convert an ANSI string to Microsoft Unicode, using the ANSI or OEM
    ++** code page.
    + **
    +-** Space to hold the returned string is obtained
    +-** from sqlite3_malloc.
    ++** Space to hold the returned string is obtained from sqlite3_malloc().
    + */
    +-static LPWSTR winMbcsToUnicode(const char *zFilename){
    ++static LPWSTR winMbcsToUnicode(const char *zText, int useAnsi){
    +   int nByte;
    +-  LPWSTR zMbcsFilename;
    +-  int codepage = osAreFileApisANSI() ? CP_ACP : CP_OEMCP;
    ++  LPWSTR zMbcsText;
    ++  int codepage = useAnsi ? CP_ACP : CP_OEMCP;
    + 
    +-  nByte = osMultiByteToWideChar(codepage, 0, zFilename, -1, NULL,
    ++  nByte = osMultiByteToWideChar(codepage, 0, zText, -1, NULL,
    +                                 0)*sizeof(WCHAR);
    +   if( nByte==0 ){
    +     return 0;
    +   }
    +-  zMbcsFilename = sqlite3MallocZero( nByte*sizeof(zMbcsFilename[0]) );
    +-  if( zMbcsFilename==0 ){
    ++  zMbcsText = sqlite3MallocZero( nByte*sizeof(WCHAR) );
    ++  if( zMbcsText==0 ){
    +     return 0;
    +   }
    +-  nByte = osMultiByteToWideChar(codepage, 0, zFilename, -1, zMbcsFilename,
    ++  nByte = osMultiByteToWideChar(codepage, 0, zText, -1, zMbcsText,
    +                                 nByte);
    +   if( nByte==0 ){
    +-    sqlite3_free(zMbcsFilename);
    +-    zMbcsFilename = 0;
    ++    sqlite3_free(zMbcsText);
    ++    zMbcsText = 0;
    +   }
    +-  return zMbcsFilename;
    ++  return zMbcsText;
    + }
    + 
    + /*
    +-** Convert Microsoft Unicode to multi-byte character string, based on the
    +-** user's ANSI codepage.
    ++** Convert a Microsoft Unicode string to a multi-byte character string,
    ++** using the ANSI or OEM code page.
    + **
    +-** Space to hold the returned string is obtained from
    +-** sqlite3_malloc().
    ++** Space to hold the returned string is obtained from sqlite3_malloc().
    + */
    +-static char *winUnicodeToMbcs(LPCWSTR zWideFilename){
    ++static char *winUnicodeToMbcs(LPCWSTR zWideText, int useAnsi){
    +   int nByte;
    +-  char *zFilename;
    +-  int codepage = osAreFileApisANSI() ? CP_ACP : CP_OEMCP;
    ++  char *zText;
    ++  int codepage = useAnsi ? CP_ACP : CP_OEMCP;
    + 
    +-  nByte = osWideCharToMultiByte(codepage, 0, zWideFilename, -1, 0, 0, 0, 0);
    ++  nByte = osWideCharToMultiByte(codepage, 0, zWideText, -1, 0, 0, 0, 0);
    +   if( nByte == 0 ){
    +     return 0;
    +   }
    +-  zFilename = sqlite3MallocZero( nByte );
    +-  if( zFilename==0 ){
    ++  zText = sqlite3MallocZero( nByte );
    ++  if( zText==0 ){
    +     return 0;
    +   }
    +-  nByte = osWideCharToMultiByte(codepage, 0, zWideFilename, -1, zFilename,
    ++  nByte = osWideCharToMultiByte(codepage, 0, zWideText, -1, zText,
    +                                 nByte, 0, 0);
    +   if( nByte == 0 ){
    +-    sqlite3_free(zFilename);
    +-    zFilename = 0;
    ++    sqlite3_free(zText);
    ++    zText = 0;
    +   }
    +-  return zFilename;
    ++  return zText;
    + }
    + 
    + /*
    +-** Convert multibyte character string to UTF-8.  Space to hold the
    +-** returned string is obtained from sqlite3_malloc().
    ++** Convert a multi-byte character string to UTF-8.
    ++**
    ++** Space to hold the returned string is obtained from sqlite3_malloc().
    + */
    +-SQLITE_API char *SQLITE_STDCALL sqlite3_win32_mbcs_to_utf8(const char *zFilename){
    +-  char *zFilenameUtf8;
    ++static char *winMbcsToUtf8(const char *zText, int useAnsi){
    ++  char *zTextUtf8;
    +   LPWSTR zTmpWide;
    + 
    +-  zTmpWide = winMbcsToUnicode(zFilename);
    ++  zTmpWide = winMbcsToUnicode(zText, useAnsi);
    +   if( zTmpWide==0 ){
    +     return 0;
    +   }
    +-  zFilenameUtf8 = winUnicodeToUtf8(zTmpWide);
    ++  zTextUtf8 = winUnicodeToUtf8(zTmpWide);
    +   sqlite3_free(zTmpWide);
    +-  return zFilenameUtf8;
    ++  return zTextUtf8;
    + }
    + 
    + /*
    +-** Convert UTF-8 to multibyte character string.  Space to hold the
    +-** returned string is obtained from sqlite3_malloc().
    ++** Convert a UTF-8 string to a multi-byte character string.
    ++**
    ++** Space to hold the returned string is obtained from sqlite3_malloc().
    + */
    +-SQLITE_API char *SQLITE_STDCALL sqlite3_win32_utf8_to_mbcs(const char *zFilename){
    +-  char *zFilenameMbcs;
    ++static char *winUtf8ToMbcs(const char *zText, int useAnsi){
    ++  char *zTextMbcs;
    +   LPWSTR zTmpWide;
    + 
    +-  zTmpWide = winUtf8ToUnicode(zFilename);
    ++  zTmpWide = winUtf8ToUnicode(zText);
    +   if( zTmpWide==0 ){
    +     return 0;
    +   }
    +-  zFilenameMbcs = winUnicodeToMbcs(zTmpWide);
    ++  zTextMbcs = winUnicodeToMbcs(zTmpWide, useAnsi);
    +   sqlite3_free(zTmpWide);
    +-  return zFilenameMbcs;
    ++  return zTextMbcs;
    ++}
    ++
    ++/*
    ++** This is a public wrapper for the winUtf8ToUnicode() function.
    ++*/
    ++SQLITE_API LPWSTR sqlite3_win32_utf8_to_unicode(const char *zText){
    ++#ifdef SQLITE_ENABLE_API_ARMOR
    ++  if( !zText ){
    ++    (void)SQLITE_MISUSE_BKPT;
    ++    return 0;
    ++  }
    ++#endif
    ++#ifndef SQLITE_OMIT_AUTOINIT
    ++  if( sqlite3_initialize() ) return 0;
    ++#endif
    ++  return winUtf8ToUnicode(zText);
    ++}
    ++
    ++/*
    ++** This is a public wrapper for the winUnicodeToUtf8() function.
    ++*/
    ++SQLITE_API char *sqlite3_win32_unicode_to_utf8(LPCWSTR zWideText){
    ++#ifdef SQLITE_ENABLE_API_ARMOR
    ++  if( !zWideText ){
    ++    (void)SQLITE_MISUSE_BKPT;
    ++    return 0;
    ++  }
    ++#endif
    ++#ifndef SQLITE_OMIT_AUTOINIT
    ++  if( sqlite3_initialize() ) return 0;
    ++#endif
    ++  return winUnicodeToUtf8(zWideText);
    ++}
    ++
    ++/*
    ++** This is a public wrapper for the winMbcsToUtf8() function.
    ++*/
    ++SQLITE_API char *sqlite3_win32_mbcs_to_utf8(const char *zText){
    ++#ifdef SQLITE_ENABLE_API_ARMOR
    ++  if( !zText ){
    ++    (void)SQLITE_MISUSE_BKPT;
    ++    return 0;
    ++  }
    ++#endif
    ++#ifndef SQLITE_OMIT_AUTOINIT
    ++  if( sqlite3_initialize() ) return 0;
    ++#endif
    ++  return winMbcsToUtf8(zText, osAreFileApisANSI());
    ++}
    ++
    ++/*
    ++** This is a public wrapper for the winMbcsToUtf8() function.
    ++*/
    ++SQLITE_API char *sqlite3_win32_mbcs_to_utf8_v2(const char *zText, int useAnsi){
    ++#ifdef SQLITE_ENABLE_API_ARMOR
    ++  if( !zText ){
    ++    (void)SQLITE_MISUSE_BKPT;
    ++    return 0;
    ++  }
    ++#endif
    ++#ifndef SQLITE_OMIT_AUTOINIT
    ++  if( sqlite3_initialize() ) return 0;
    ++#endif
    ++  return winMbcsToUtf8(zText, useAnsi);
    ++}
    ++
    ++/*
    ++** This is a public wrapper for the winUtf8ToMbcs() function.
    ++*/
    ++SQLITE_API char *sqlite3_win32_utf8_to_mbcs(const char *zText){
    ++#ifdef SQLITE_ENABLE_API_ARMOR
    ++  if( !zText ){
    ++    (void)SQLITE_MISUSE_BKPT;
    ++    return 0;
    ++  }
    ++#endif
    ++#ifndef SQLITE_OMIT_AUTOINIT
    ++  if( sqlite3_initialize() ) return 0;
    ++#endif
    ++  return winUtf8ToMbcs(zText, osAreFileApisANSI());
    ++}
    ++
    ++/*
    ++** This is a public wrapper for the winUtf8ToMbcs() function.
    ++*/
    ++SQLITE_API char *sqlite3_win32_utf8_to_mbcs_v2(const char *zText, int useAnsi){
    ++#ifdef SQLITE_ENABLE_API_ARMOR
    ++  if( !zText ){
    ++    (void)SQLITE_MISUSE_BKPT;
    ++    return 0;
    ++  }
    ++#endif
    ++#ifndef SQLITE_OMIT_AUTOINIT
    ++  if( sqlite3_initialize() ) return 0;
    ++#endif
    ++  return winUtf8ToMbcs(zText, useAnsi);
    + }
    + 
    + /*
    +@@ -36158,7 +40616,7 @@ SQLITE_API char *SQLITE_STDCALL sqlite3_win32_utf8_to_mbcs(const char *zFilename
    + ** argument is the name of the directory to use.  The return value will be
    + ** SQLITE_OK if successful.
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_win32_set_directory(DWORD type, LPCWSTR zValue){
    ++SQLITE_API int sqlite3_win32_set_directory(DWORD type, LPCWSTR zValue){
    +   char **ppDirectory = 0;
    + #ifndef SQLITE_OMIT_AUTOINIT
    +   int rc = sqlite3_initialize();
    +@@ -36178,7 +40636,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_win32_set_directory(DWORD type, LPCWSTR zV
    +     if( zValue && zValue[0] ){
    +       zValueUtf8 = winUnicodeToUtf8(zValue);
    +       if ( zValueUtf8==0 ){
    +-        return SQLITE_NOMEM;
    ++        return SQLITE_NOMEM_BKPT;
    +       }
    +     }
    +     sqlite3_free(*ppDirectory);
    +@@ -36250,7 +40708,7 @@ static int winGetLastErrorMsg(DWORD lastErrno, int nBuf, char *zBuf){
    +     if( dwLen > 0 ){
    +       /* allocate a buffer and convert to UTF8 */
    +       sqlite3BeginBenignMalloc();
    +-      zOut = sqlite3_win32_mbcs_to_utf8(zTemp);
    ++      zOut = winMbcsToUtf8(zTemp, osAreFileApisANSI());
    +       sqlite3EndBenignMalloc();
    +       /* free the system buffer allocated by FormatMessage */
    +       osLocalFree(zTemp);
    +@@ -36392,16 +40850,17 @@ static void winLogIoerr(int nRetry, int lineno){
    +   }
    + }
    + 
    +-#if SQLITE_OS_WINCE
    +-/*************************************************************************
    +-** This section contains code for WinCE only.
    ++/*
    ++** This #if does not rely on the SQLITE_OS_WINCE define because the
    ++** corresponding section in "date.c" cannot use it.
    + */
    +-#if !defined(SQLITE_MSVC_LOCALTIME_API) || !SQLITE_MSVC_LOCALTIME_API
    ++#if !defined(SQLITE_OMIT_LOCALTIME) && defined(_WIN32_WCE) && \
    ++    (!defined(SQLITE_MSVC_LOCALTIME_API) || !SQLITE_MSVC_LOCALTIME_API)
    + /*
    +-** The MSVC CRT on Windows CE may not have a localtime() function.  So
    +-** create a substitute.
    ++** The MSVC CRT on Windows CE may not have a localtime() function.
    ++** So define a substitute.
    + */
    +-/* #include <time.h> */
    ++/* #  include <time.h> */
    + struct tm *__cdecl localtime(const time_t *t)
    + {
    +   static struct tm y;
    +@@ -36425,6 +40884,10 @@ struct tm *__cdecl localtime(const time_t *t)
    + }
    + #endif
    + 
    ++#if SQLITE_OS_WINCE
    ++/*************************************************************************
    ++** This section contains code for WinCE only.
    ++*/
    + #define HANDLE_TO_WINFILE(a) (winFile*)&((char*)a)[-(int)offsetof(winFile,h)]
    + 
    + /*
    +@@ -36455,7 +40918,7 @@ static int winceCreateLock(const char *zFilename, winFile *pFile){
    +   zName = winUtf8ToUnicode(zFilename);
    +   if( zName==0 ){
    +     /* out of memory */
    +-    return SQLITE_IOERR_NOMEM;
    ++    return SQLITE_IOERR_NOMEM_BKPT;
    +   }
    + 
    +   /* Initialize the local lockdata */
    +@@ -36880,7 +41343,12 @@ static int winClose(sqlite3_file *id){
    +   }while( rc==0 && ++cnt < MX_CLOSE_ATTEMPT && (sqlite3_win32_sleep(100), 1) );
    + #if SQLITE_OS_WINCE
    + #define WINCE_DELETION_ATTEMPTS 3
    +-  winceDestroyLock(pFile);
    ++  {
    ++    winVfsAppData *pAppData = (winVfsAppData*)pFile->pVfs->pAppData;
    ++    if( pAppData==NULL || !pAppData->bNoLock ){
    ++      winceDestroyLock(pFile);
    ++    }
    ++  }
    +   if( pFile->zDeleteOnClose ){
    +     int cnt = 0;
    +     while(
    +@@ -37008,7 +41476,7 @@ static int winWrite(
    +            "offset=%lld, lock=%d\n", osGetCurrentProcessId(), pFile,
    +            pFile->h, pBuf, amt, offset, pFile->locktype));
    + 
    +-#if SQLITE_MAX_MMAP_SIZE>0
    ++#if defined(SQLITE_MMAP_READWRITE) && SQLITE_MAX_MMAP_SIZE>0
    +   /* Deal with as much of this write request as possible by transfering
    +   ** data from the memory mapping using memcpy().  */
    +   if( offset<pFile->mmapSize ){
    +@@ -37438,9 +41906,8 @@ static int winLock(sqlite3_file *id, int locktype){
    +   ** the PENDING_LOCK byte is temporary.
    +   */
    +   newLocktype = pFile->locktype;
    +-  if(   (pFile->locktype==NO_LOCK)
    +-     || (   (locktype==EXCLUSIVE_LOCK)
    +-         && (pFile->locktype==RESERVED_LOCK))
    ++  if( pFile->locktype==NO_LOCK
    ++   || (locktype==EXCLUSIVE_LOCK && pFile->locktype<=RESERVED_LOCK)
    +   ){
    +     int cnt = 3;
    +     while( cnt-->0 && (res = winLockFile(&pFile->h, SQLITE_LOCKFILE_FLAGS,
    +@@ -37556,7 +42023,7 @@ static int winCheckReservedLock(sqlite3_file *id, int *pResOut){
    +     res = 1;
    +     OSTRACE(("TEST-WR-LOCK file=%p, result=%d (local)\n", pFile->h, res));
    +   }else{
    +-    res = winLockFile(&pFile->h, SQLITE_LOCKFILEEX_FLAGS,RESERVED_BYTE, 0, 1, 0);
    ++    res = winLockFile(&pFile->h, SQLITE_LOCKFILEEX_FLAGS,RESERVED_BYTE,0,1,0);
    +     if( res ){
    +       winUnlockFile(&pFile->h, RESERVED_BYTE, 0, 1, 0);
    +     }
    +@@ -37613,6 +42080,44 @@ static int winUnlock(sqlite3_file *id, int locktype){
    +   return rc;
    + }
    + 
    ++/******************************************************************************
    ++****************************** No-op Locking **********************************
    ++**
    ++** Of the various locking implementations available, this is by far the
    ++** simplest:  locking is ignored.  No attempt is made to lock the database
    ++** file for reading or writing.
    ++**
    ++** This locking mode is appropriate for use on read-only databases
    ++** (ex: databases that are burned into CD-ROM, for example.)  It can
    ++** also be used if the application employs some external mechanism to
    ++** prevent simultaneous access of the same database by two or more
    ++** database connections.  But there is a serious risk of database
    ++** corruption if this locking mode is used in situations where multiple
    ++** database connections are accessing the same database file at the same
    ++** time and one or more of those connections are writing.
    ++*/
    ++
    ++static int winNolockLock(sqlite3_file *id, int locktype){
    ++  UNUSED_PARAMETER(id);
    ++  UNUSED_PARAMETER(locktype);
    ++  return SQLITE_OK;
    ++}
    ++
    ++static int winNolockCheckReservedLock(sqlite3_file *id, int *pResOut){
    ++  UNUSED_PARAMETER(id);
    ++  UNUSED_PARAMETER(pResOut);
    ++  return SQLITE_OK;
    ++}
    ++
    ++static int winNolockUnlock(sqlite3_file *id, int locktype){
    ++  UNUSED_PARAMETER(id);
    ++  UNUSED_PARAMETER(locktype);
    ++  return SQLITE_OK;
    ++}
    ++
    ++/******************* End of the no-op lock implementation *********************
    ++******************************************************************************/
    ++
    + /*
    + ** If *pArg is initially negative then this is a query.  Set *pArg to
    + ** 1 or 0 depending on whether or not bit mask of pFile->ctrlFlags is set.
    +@@ -37646,7 +42151,7 @@ static int winFileControl(sqlite3_file *id, int op, void *pArg){
    +       OSTRACE(("FCNTL file=%p, rc=SQLITE_OK\n", pFile->h));
    +       return SQLITE_OK;
    +     }
    +-    case SQLITE_LAST_ERRNO: {
    ++    case SQLITE_FCNTL_LAST_ERRNO: {
    +       *(int*)pArg = (int)pFile->lastErrno;
    +       OSTRACE(("FCNTL file=%p, rc=SQLITE_OK\n", pFile->h));
    +       return SQLITE_OK;
    +@@ -37704,6 +42209,12 @@ static int winFileControl(sqlite3_file *id, int op, void *pArg){
    +       OSTRACE(("FCNTL file=%p, rc=SQLITE_OK\n", pFile->h));
    +       return SQLITE_OK;
    +     }
    ++    case SQLITE_FCNTL_WIN32_GET_HANDLE: {
    ++      LPHANDLE phFile = (LPHANDLE)pArg;
    ++      *phFile = pFile->h;
    ++      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;
    +@@ -37731,6 +42242,14 @@ static int winFileControl(sqlite3_file *id, int op, void *pArg){
    +       if( newLimit>sqlite3GlobalConfig.mxMmap ){
    +         newLimit = sqlite3GlobalConfig.mxMmap;
    +       }
    ++
    ++      /* The value of newLimit may be eventually cast to (SIZE_T) and passed
    ++      ** to MapViewOfFile(). Restrict its value to 2GB if (SIZE_T) is not at
    ++      ** least a 64-bit type. */
    ++      if( newLimit>0 && sizeof(SIZE_T)<8 ){
    ++        newLimit = (newLimit & 0x7FFFFFFF);
    ++      }
    ++
    +       *(i64*)pArg = pFile->mmapSizeMax;
    +       if( newLimit>=0 && newLimit!=pFile->mmapSizeMax && pFile->nFetchOut==0 ){
    +         pFile->mmapSizeMax = newLimit;
    +@@ -37837,6 +42356,9 @@ struct winShmNode {
    + 
    +   int szRegion;              /* Size of shared-memory regions */
    +   int nRegion;               /* Size of array apRegion */
    ++  u8 isReadonly;             /* True if read-only */
    ++  u8 isUnlocked;             /* True if no DMS lock held */
    ++
    +   struct ShmRegion {
    +     HANDLE hMap;             /* File handle from CreateFileMapping */
    +     void *pMap;
    +@@ -37891,30 +42413,30 @@ struct winShm {
    + /*
    + ** Apply advisory locks for all n bytes beginning at ofst.
    + */
    +-#define _SHM_UNLCK  1
    +-#define _SHM_RDLCK  2
    +-#define _SHM_WRLCK  3
    ++#define WINSHM_UNLCK  1
    ++#define WINSHM_RDLCK  2
    ++#define WINSHM_WRLCK  3
    + static int winShmSystemLock(
    +   winShmNode *pFile,    /* Apply locks to this open shared-memory segment */
    +-  int lockType,         /* _SHM_UNLCK, _SHM_RDLCK, or _SHM_WRLCK */
    ++  int lockType,         /* WINSHM_UNLCK, WINSHM_RDLCK, or WINSHM_WRLCK */
    +   int ofst,             /* Offset to first byte to be locked/unlocked */
    +   int nByte             /* Number of bytes to lock or unlock */
    + ){
    +   int rc = 0;           /* Result code form Lock/UnlockFileEx() */
    + 
    +   /* Access to the winShmNode object is serialized by the caller */
    +-  assert( sqlite3_mutex_held(pFile->mutex) || pFile->nRef==0 );
    ++  assert( pFile->nRef==0 || sqlite3_mutex_held(pFile->mutex) );
    + 
    +   OSTRACE(("SHM-LOCK file=%p, lock=%d, offset=%d, size=%d\n",
    +            pFile->hFile.h, lockType, ofst, nByte));
    + 
    +   /* Release/Acquire the system-level lock */
    +-  if( lockType==_SHM_UNLCK ){
    ++  if( lockType==WINSHM_UNLCK ){
    +     rc = winUnlockFile(&pFile->hFile.h, ofst, 0, nByte, 0);
    +   }else{
    +     /* Initialize the locking parameters */
    +     DWORD dwFlags = LOCKFILE_FAIL_IMMEDIATELY;
    +-    if( lockType == _SHM_WRLCK ) dwFlags |= LOCKFILE_EXCLUSIVE_LOCK;
    ++    if( lockType == WINSHM_WRLCK ) dwFlags |= LOCKFILE_EXCLUSIVE_LOCK;
    +     rc = winLockFile(&pFile->hFile.h, dwFlags, ofst, 0, nByte, 0);
    +   }
    + 
    +@@ -37926,7 +42448,7 @@ static int winShmSystemLock(
    +   }
    + 
    +   OSTRACE(("SHM-LOCK file=%p, func=%s, errno=%lu, rc=%s\n",
    +-           pFile->hFile.h, (lockType == _SHM_UNLCK) ? "winUnlockFile" :
    ++           pFile->hFile.h, (lockType == WINSHM_UNLCK) ? "winUnlockFile" :
    +            "winLockFile", pFile->lastErrno, sqlite3ErrName(rc)));
    + 
    +   return rc;
    +@@ -37984,6 +42506,37 @@ static void winShmPurge(sqlite3_vfs *pVfs, int deleteFlag){
    +   }
    + }
    + 
    ++/*
    ++** The DMS lock has not yet been taken on shm file pShmNode. Attempt to
    ++** take it now. Return SQLITE_OK if successful, or an SQLite error
    ++** code otherwise.
    ++**
    ++** If the DMS cannot be locked because this is a readonly_shm=1
    ++** connection and no other process already holds a lock, return
    ++** SQLITE_READONLY_CANTINIT and set pShmNode->isUnlocked=1.
    ++*/
    ++static int winLockSharedMemory(winShmNode *pShmNode){
    ++  int rc = winShmSystemLock(pShmNode, WINSHM_WRLCK, WIN_SHM_DMS, 1);
    ++
    ++  if( rc==SQLITE_OK ){
    ++    if( pShmNode->isReadonly ){
    ++      pShmNode->isUnlocked = 1;
    ++      winShmSystemLock(pShmNode, WINSHM_UNLCK, WIN_SHM_DMS, 1);
    ++      return SQLITE_READONLY_CANTINIT;
    ++    }else if( winTruncate((sqlite3_file*)&pShmNode->hFile, 0) ){
    ++      winShmSystemLock(pShmNode, WINSHM_UNLCK, WIN_SHM_DMS, 1);
    ++      return winLogError(SQLITE_IOERR_SHMOPEN, osGetLastError(),
    ++                         "winLockSharedMemory", pShmNode->zFilename);
    ++    }
    ++  }
    ++
    ++  if( rc==SQLITE_OK ){
    ++    winShmSystemLock(pShmNode, WINSHM_UNLCK, WIN_SHM_DMS, 1);
    ++  }
    ++
    ++  return winShmSystemLock(pShmNode, WINSHM_RDLCK, WIN_SHM_DMS, 1);
    ++}
    ++
    + /*
    + ** Open the shared-memory area associated with database file pDbFd.
    + **
    +@@ -37993,9 +42546,9 @@ static void winShmPurge(sqlite3_vfs *pVfs, int deleteFlag){
    + */
    + static int winOpenSharedMemory(winFile *pDbFd){
    +   struct winShm *p;                  /* The connection to be opened */
    +-  struct winShmNode *pShmNode = 0;   /* The underlying mmapped file */
    +-  int rc;                            /* Result code */
    +-  struct winShmNode *pNew;           /* Newly allocated winShmNode */
    ++  winShmNode *pShmNode = 0;          /* The underlying mmapped file */
    ++  int rc = SQLITE_OK;                /* Result code */
    ++  winShmNode *pNew;                  /* Newly allocated winShmNode */
    +   int nName;                         /* Size of zName in bytes */
    + 
    +   assert( pDbFd->pShm==0 );    /* Not previously opened */
    +@@ -38004,12 +42557,12 @@ static int winOpenSharedMemory(winFile *pDbFd){
    +   ** allocate space for a new winShmNode and filename.
    +   */
    +   p = sqlite3MallocZero( sizeof(*p) );
    +-  if( p==0 ) return SQLITE_IOERR_NOMEM;
    ++  if( p==0 ) return SQLITE_IOERR_NOMEM_BKPT;
    +   nName = sqlite3Strlen30(pDbFd->zPath);
    +   pNew = sqlite3MallocZero( sizeof(*pShmNode) + nName + 17 );
    +   if( pNew==0 ){
    +     sqlite3_free(p);
    +-    return SQLITE_IOERR_NOMEM;
    ++    return SQLITE_IOERR_NOMEM_BKPT;
    +   }
    +   pNew->zFilename = (char*)&pNew[1];
    +   sqlite3_snprintf(nName+15, pNew->zFilename, "%s-shm", pDbFd->zPath);
    +@@ -38028,42 +42581,40 @@ static int winOpenSharedMemory(winFile *pDbFd){
    +   if( pShmNode ){
    +     sqlite3_free(pNew);
    +   }else{
    ++    int inFlags = SQLITE_OPEN_WAL;
    ++    int outFlags = 0;
    ++
    +     pShmNode = pNew;
    +     pNew = 0;
    +     ((winFile*)(&pShmNode->hFile))->h = INVALID_HANDLE_VALUE;
    +     pShmNode->pNext = winShmNodeList;
    +     winShmNodeList = pShmNode;
    + 
    +-    pShmNode->mutex = sqlite3_mutex_alloc(SQLITE_MUTEX_FAST);
    +-    if( pShmNode->mutex==0 ){
    +-      rc = SQLITE_IOERR_NOMEM;
    +-      goto shm_open_err;
    ++    if( sqlite3GlobalConfig.bCoreMutex ){
    ++      pShmNode->mutex = sqlite3_mutex_alloc(SQLITE_MUTEX_FAST);
    ++      if( pShmNode->mutex==0 ){
    ++        rc = SQLITE_IOERR_NOMEM_BKPT;
    ++        goto shm_open_err;
    ++      }
    +     }
    + 
    +-    rc = winOpen(pDbFd->pVfs,
    +-                 pShmNode->zFilename,             /* Name of the file (UTF-8) */
    +-                 (sqlite3_file*)&pShmNode->hFile,  /* File handle here */
    +-                 SQLITE_OPEN_WAL | SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE,
    +-                 0);
    +-    if( SQLITE_OK!=rc ){
    ++    if( 0==sqlite3_uri_boolean(pDbFd->zPath, "readonly_shm", 0) ){
    ++      inFlags |= SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE;
    ++    }else{
    ++      inFlags |= SQLITE_OPEN_READONLY;
    ++    }
    ++    rc = winOpen(pDbFd->pVfs, pShmNode->zFilename,
    ++                 (sqlite3_file*)&pShmNode->hFile,
    ++                 inFlags, &outFlags);
    ++    if( rc!=SQLITE_OK ){
    ++      rc = winLogError(rc, osGetLastError(), "winOpenShm",
    ++                       pShmNode->zFilename);
    +       goto shm_open_err;
    +     }
    ++    if( outFlags==SQLITE_OPEN_READONLY ) pShmNode->isReadonly = 1;
    + 
    +-    /* Check to see if another process is holding the dead-man switch.
    +-    ** 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);
    +-      if( rc!=SQLITE_OK ){
    +-        rc = winLogError(SQLITE_IOERR_SHMOPEN, osGetLastError(),
    +-                         "winOpenShm", pDbFd->zPath);
    +-      }
    +-    }
    +-    if( rc==SQLITE_OK ){
    +-      winShmSystemLock(pShmNode, _SHM_UNLCK, WIN_SHM_DMS, 1);
    +-      rc = winShmSystemLock(pShmNode, _SHM_RDLCK, WIN_SHM_DMS, 1);
    +-    }
    +-    if( rc ) goto shm_open_err;
    ++    rc = winLockSharedMemory(pShmNode);
    ++    if( rc!=SQLITE_OK && rc!=SQLITE_READONLY_CANTINIT ) goto shm_open_err;
    +   }
    + 
    +   /* Make the new connection a child of the winShmNode */
    +@@ -38086,11 +42637,11 @@ static int winOpenSharedMemory(winFile *pDbFd){
    +   p->pNext = pShmNode->pFirst;
    +   pShmNode->pFirst = p;
    +   sqlite3_mutex_leave(pShmNode->mutex);
    +-  return SQLITE_OK;
    ++  return rc;
    + 
    +   /* Jump here on any error */
    + shm_open_err:
    +-  winShmSystemLock(pShmNode, _SHM_UNLCK, WIN_SHM_DMS, 1);
    ++  winShmSystemLock(pShmNode, WINSHM_UNLCK, WIN_SHM_DMS, 1);
    +   winShmPurge(pDbFd->pVfs, 0);      /* This call frees pShmNode if required */
    +   sqlite3_free(p);
    +   sqlite3_free(pNew);
    +@@ -38179,7 +42730,7 @@ static int winShmLock(
    + 
    +     /* Unlock the system-level locks */
    +     if( (mask & allMask)==0 ){
    +-      rc = winShmSystemLock(pShmNode, _SHM_UNLCK, ofst+WIN_SHM_BASE, n);
    ++      rc = winShmSystemLock(pShmNode, WINSHM_UNLCK, ofst+WIN_SHM_BASE, n);
    +     }else{
    +       rc = SQLITE_OK;
    +     }
    +@@ -38207,7 +42758,7 @@ static int winShmLock(
    +     /* Get shared locks at the system level, if necessary */
    +     if( rc==SQLITE_OK ){
    +       if( (allShared & mask)==0 ){
    +-        rc = winShmSystemLock(pShmNode, _SHM_RDLCK, ofst+WIN_SHM_BASE, n);
    ++        rc = winShmSystemLock(pShmNode, WINSHM_RDLCK, ofst+WIN_SHM_BASE, n);
    +       }else{
    +         rc = SQLITE_OK;
    +       }
    +@@ -38232,7 +42783,7 @@ static int winShmLock(
    +     ** also mark the local connection as being locked.
    +     */
    +     if( rc==SQLITE_OK ){
    +-      rc = winShmSystemLock(pShmNode, _SHM_WRLCK, ofst+WIN_SHM_BASE, n);
    ++      rc = winShmSystemLock(pShmNode, WINSHM_WRLCK, ofst+WIN_SHM_BASE, n);
    +       if( rc==SQLITE_OK ){
    +         assert( (p->sharedMask & mask)==0 );
    +         p->exclMask |= mask;
    +@@ -38290,6 +42841,8 @@ static int winShmMap(
    +   winFile *pDbFd = (winFile*)fd;
    +   winShm *pShm = pDbFd->pShm;
    +   winShmNode *pShmNode;
    ++  DWORD protect = PAGE_READWRITE;
    ++  DWORD flags = FILE_MAP_WRITE | FILE_MAP_READ;
    +   int rc = SQLITE_OK;
    + 
    +   if( !pShm ){
    +@@ -38300,6 +42853,11 @@ static int winShmMap(
    +   pShmNode = pShm->pShmNode;
    + 
    +   sqlite3_mutex_enter(pShmNode->mutex);
    ++  if( pShmNode->isUnlocked ){
    ++    rc = winLockSharedMemory(pShmNode);
    ++    if( rc!=SQLITE_OK ) goto shmpage_out;
    ++    pShmNode->isUnlocked = 0;
    ++  }
    +   assert( szRegion==pShmNode->szRegion || pShmNode->nRegion==0 );
    + 
    +   if( pShmNode->nRegion<=iRegion ){
    +@@ -38341,26 +42899,31 @@ static int winShmMap(
    +         pShmNode->aRegion, (iRegion+1)*sizeof(apNew[0])
    +     );
    +     if( !apNew ){
    +-      rc = SQLITE_IOERR_NOMEM;
    ++      rc = SQLITE_IOERR_NOMEM_BKPT;
    +       goto shmpage_out;
    +     }
    +     pShmNode->aRegion = apNew;
    + 
    ++    if( pShmNode->isReadonly ){
    ++      protect = PAGE_READONLY;
    ++      flags = FILE_MAP_READ;
    ++    }
    ++
    +     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
    ++          NULL, protect, nByte, NULL
    +       );
    + #elif defined(SQLITE_WIN32_HAS_WIDE)
    +       hMap = osCreateFileMappingW(pShmNode->hFile.h,
    +-          NULL, PAGE_READWRITE, 0, nByte, NULL
    ++          NULL, protect, 0, nByte, NULL
    +       );
    +-#elif defined(SQLITE_WIN32_HAS_ANSI)
    ++#elif defined(SQLITE_WIN32_HAS_ANSI) && SQLITE_WIN32_CREATEFILEMAPPINGA
    +       hMap = osCreateFileMappingA(pShmNode->hFile.h,
    +-          NULL, PAGE_READWRITE, 0, nByte, NULL
    ++          NULL, protect, 0, nByte, NULL
    +       );
    + #endif
    +       OSTRACE(("SHM-MAP-CREATE pid=%lu, region=%d, size=%d, rc=%s\n",
    +@@ -38370,11 +42933,11 @@ static int winShmMap(
    +         int iOffset = pShmNode->nRegion*szRegion;
    +         int iOffsetShift = iOffset % winSysInfo.dwAllocationGranularity;
    + #if SQLITE_OS_WINRT
    +-        pMap = osMapViewOfFileFromApp(hMap, FILE_MAP_WRITE | FILE_MAP_READ,
    ++        pMap = osMapViewOfFileFromApp(hMap, flags,
    +             iOffset - iOffsetShift, szRegion + iOffsetShift
    +         );
    + #else
    +-        pMap = osMapViewOfFile(hMap, FILE_MAP_WRITE | FILE_MAP_READ,
    ++        pMap = osMapViewOfFile(hMap, flags,
    +             0, iOffset - iOffsetShift, szRegion + iOffsetShift
    +         );
    + #endif
    +@@ -38405,6 +42968,7 @@ shmpage_out:
    +   }else{
    +     *pp = 0;
    +   }
    ++  if( pShmNode->isReadonly && rc==SQLITE_OK ) rc = SQLITE_READONLY;
    +   sqlite3_mutex_leave(pShmNode->mutex);
    +   return rc;
    + }
    +@@ -38502,17 +43066,19 @@ static int winMapfile(winFile *pFd, sqlite3_int64 nByte){
    +     DWORD flags = FILE_MAP_READ;
    + 
    +     winUnmapfile(pFd);
    ++#ifdef SQLITE_MMAP_READWRITE
    +     if( (pFd->ctrlFlags & WINFILE_RDONLY)==0 ){
    +       protect = PAGE_READWRITE;
    +       flags |= FILE_MAP_WRITE;
    +     }
    ++#endif
    + #if SQLITE_OS_WINRT
    +     pFd->hMap = osCreateFileMappingFromApp(pFd->h, NULL, protect, nMap, NULL);
    + #elif defined(SQLITE_WIN32_HAS_WIDE)
    +     pFd->hMap = osCreateFileMappingW(pFd->h, NULL, protect,
    +                                 (DWORD)((nMap>>32) & 0xffffffff),
    +                                 (DWORD)(nMap & 0xffffffff), NULL);
    +-#elif defined(SQLITE_WIN32_HAS_ANSI)
    ++#elif defined(SQLITE_WIN32_HAS_ANSI) && SQLITE_WIN32_CREATEFILEMAPPINGA
    +     pFd->hMap = osCreateFileMappingA(pFd->h, NULL, protect,
    +                                 (DWORD)((nMap>>32) & 0xffffffff),
    +                                 (DWORD)(nMap & 0xffffffff), NULL);
    +@@ -38673,6 +43239,44 @@ static const sqlite3_io_methods winIoMethod = {
    +   winUnfetch                      /* xUnfetch */
    + };
    + 
    ++/*
    ++** This vector defines all the methods that can operate on an
    ++** sqlite3_file for win32 without performing any locking.
    ++*/
    ++static const sqlite3_io_methods winIoNolockMethod = {
    ++  3,                              /* iVersion */
    ++  winClose,                       /* xClose */
    ++  winRead,                        /* xRead */
    ++  winWrite,                       /* xWrite */
    ++  winTruncate,                    /* xTruncate */
    ++  winSync,                        /* xSync */
    ++  winFileSize,                    /* xFileSize */
    ++  winNolockLock,                  /* xLock */
    ++  winNolockUnlock,                /* xUnlock */
    ++  winNolockCheckReservedLock,     /* xCheckReservedLock */
    ++  winFileControl,                 /* xFileControl */
    ++  winSectorSize,                  /* xSectorSize */
    ++  winDeviceCharacteristics,       /* xDeviceCharacteristics */
    ++  winShmMap,                      /* xShmMap */
    ++  winShmLock,                     /* xShmLock */
    ++  winShmBarrier,                  /* xShmBarrier */
    ++  winShmUnmap,                    /* xShmUnmap */
    ++  winFetch,                       /* xFetch */
    ++  winUnfetch                      /* xUnfetch */
    ++};
    ++
    ++static winVfsAppData winAppData = {
    ++  &winIoMethod,       /* pMethod */
    ++  0,                  /* pAppData */
    ++  0                   /* bNoLock */
    ++};
    ++
    ++static winVfsAppData winNolockAppData = {
    ++  &winIoNolockMethod, /* pMethod */
    ++  0,                  /* pAppData */
    ++  1                   /* bNoLock */
    ++};
    ++
    + /****************************************************************************
    + **************************** sqlite3_vfs methods ****************************
    + **
    +@@ -38693,7 +43297,7 @@ static char *winConvertToUtf8Filename(const void *zFilename){
    +   }
    + #ifdef SQLITE_WIN32_HAS_ANSI
    +   else{
    +-    zConverted = sqlite3_win32_mbcs_to_utf8(zFilename);
    ++    zConverted = winMbcsToUtf8(zFilename, osAreFileApisANSI());
    +   }
    + #endif
    +   /* caller will handle out of memory */
    +@@ -38714,7 +43318,7 @@ static void *winConvertFromUtf8Filename(const char *zFilename){
    +   }
    + #ifdef SQLITE_WIN32_HAS_ANSI
    +   else{
    +-    zConverted = sqlite3_win32_utf8_to_mbcs(zFilename);
    ++    zConverted = winUtf8ToMbcs(zFilename, osAreFileApisANSI());
    +   }
    + #endif
    +   /* caller will handle out of memory */
    +@@ -38769,7 +43373,7 @@ static int winGetTempname(sqlite3_vfs *pVfs, char **pzBuf){
    +   zBuf = sqlite3MallocZero( nBuf );
    +   if( !zBuf ){
    +     OSTRACE(("TEMP-FILENAME rc=SQLITE_IOERR_NOMEM\n"));
    +-    return SQLITE_IOERR_NOMEM;
    ++    return SQLITE_IOERR_NOMEM_BKPT;
    +   }
    + 
    +   /* Figure out the effective temporary directory.  First, check if one
    +@@ -38827,7 +43431,7 @@ static int winGetTempname(sqlite3_vfs *pVfs, char **pzBuf){
    +         if( !zConverted ){
    +           sqlite3_free(zBuf);
    +           OSTRACE(("TEMP-FILENAME rc=SQLITE_IOERR_NOMEM\n"));
    +-          return SQLITE_IOERR_NOMEM;
    ++          return SQLITE_IOERR_NOMEM_BKPT;
    +         }
    +         if( winIsDir(zConverted) ){
    +           sqlite3_snprintf(nMax, zBuf, "%s", zDir);
    +@@ -38840,7 +43444,7 @@ static int winGetTempname(sqlite3_vfs *pVfs, char **pzBuf){
    +         if( !zConverted ){
    +           sqlite3_free(zBuf);
    +           OSTRACE(("TEMP-FILENAME rc=SQLITE_IOERR_NOMEM\n"));
    +-          return SQLITE_IOERR_NOMEM;
    ++          return SQLITE_IOERR_NOMEM_BKPT;
    +         }
    +         if( cygwin_conv_path(
    +                 osIsNT() ? CCP_POSIX_TO_WIN_W : CCP_POSIX_TO_WIN_A, zDir,
    +@@ -38861,7 +43465,7 @@ static int winGetTempname(sqlite3_vfs *pVfs, char **pzBuf){
    +             sqlite3_free(zConverted);
    +             sqlite3_free(zBuf);
    +             OSTRACE(("TEMP-FILENAME rc=SQLITE_IOERR_NOMEM\n"));
    +-            return SQLITE_IOERR_NOMEM;
    ++            return SQLITE_IOERR_NOMEM_BKPT;
    +           }
    +           sqlite3_snprintf(nMax, zBuf, "%s", zUtf8);
    +           sqlite3_free(zUtf8);
    +@@ -38879,7 +43483,7 @@ static int winGetTempname(sqlite3_vfs *pVfs, char **pzBuf){
    +     if( !zWidePath ){
    +       sqlite3_free(zBuf);
    +       OSTRACE(("TEMP-FILENAME rc=SQLITE_IOERR_NOMEM\n"));
    +-      return SQLITE_IOERR_NOMEM;
    ++      return SQLITE_IOERR_NOMEM_BKPT;
    +     }
    +     if( osGetTempPathW(nMax, zWidePath)==0 ){
    +       sqlite3_free(zWidePath);
    +@@ -38897,7 +43501,7 @@ static int winGetTempname(sqlite3_vfs *pVfs, char **pzBuf){
    +       sqlite3_free(zWidePath);
    +       sqlite3_free(zBuf);
    +       OSTRACE(("TEMP-FILENAME rc=SQLITE_IOERR_NOMEM\n"));
    +-      return SQLITE_IOERR_NOMEM;
    ++      return SQLITE_IOERR_NOMEM_BKPT;
    +     }
    +   }
    + #ifdef SQLITE_WIN32_HAS_ANSI
    +@@ -38907,7 +43511,7 @@ static int winGetTempname(sqlite3_vfs *pVfs, char **pzBuf){
    +     if( !zMbcsPath ){
    +       sqlite3_free(zBuf);
    +       OSTRACE(("TEMP-FILENAME rc=SQLITE_IOERR_NOMEM\n"));
    +-      return SQLITE_IOERR_NOMEM;
    ++      return SQLITE_IOERR_NOMEM_BKPT;
    +     }
    +     if( osGetTempPathA(nMax, zMbcsPath)==0 ){
    +       sqlite3_free(zBuf);
    +@@ -38915,14 +43519,14 @@ static int winGetTempname(sqlite3_vfs *pVfs, char **pzBuf){
    +       return winLogError(SQLITE_IOERR_GETTEMPPATH, osGetLastError(),
    +                          "winGetTempname3", 0);
    +     }
    +-    zUtf8 = sqlite3_win32_mbcs_to_utf8(zMbcsPath);
    ++    zUtf8 = winMbcsToUtf8(zMbcsPath, osAreFileApisANSI());
    +     if( zUtf8 ){
    +       sqlite3_snprintf(nMax, zBuf, "%s", zUtf8);
    +       sqlite3_free(zUtf8);
    +     }else{
    +       sqlite3_free(zBuf);
    +       OSTRACE(("TEMP-FILENAME rc=SQLITE_IOERR_NOMEM\n"));
    +-      return SQLITE_IOERR_NOMEM;
    ++      return SQLITE_IOERR_NOMEM_BKPT;
    +     }
    +   }
    + #endif /* SQLITE_WIN32_HAS_ANSI */
    +@@ -39001,11 +43605,19 @@ static int winIsDir(const void *zConverted){
    +   return (attr!=INVALID_FILE_ATTRIBUTES) && (attr&FILE_ATTRIBUTE_DIRECTORY);
    + }
    + 
    ++/* forward reference */
    ++static int winAccess(
    ++  sqlite3_vfs *pVfs,         /* Not used on win32 */
    ++  const char *zFilename,     /* Name of file to check */
    ++  int flags,                 /* Type of test to make on this file */
    ++  int *pResOut               /* OUT: Result */
    ++);
    ++
    + /*
    + ** Open a file.
    + */
    + static int winOpen(
    +-  sqlite3_vfs *pVfs,        /* Used to get maximum path name length */
    ++  sqlite3_vfs *pVfs,        /* Used to get maximum path length and AppData */
    +   const char *zName,        /* Name of the file (UTF-8) */
    +   sqlite3_file *id,         /* Write the SQLite file handle here */
    +   int flags,                /* Open mode flags */
    +@@ -39020,6 +43632,7 @@ static int winOpen(
    + #if SQLITE_OS_WINCE
    +   int isTemp = 0;
    + #endif
    ++  winVfsAppData *pAppData;
    +   winFile *pFile = (winFile*)id;
    +   void *zConverted;              /* Filename in OS encoding */
    +   const char *zUtf8Name = zName; /* Filename in UTF-8 encoding */
    +@@ -39114,7 +43727,7 @@ static int winOpen(
    +   if( zConverted==0 ){
    +     sqlite3_free(zTmpname);
    +     OSTRACE(("OPEN name=%s, rc=SQLITE_IOERR_NOMEM", zUtf8Name));
    +-    return SQLITE_IOERR_NOMEM;
    ++    return SQLITE_IOERR_NOMEM_BKPT;
    +   }
    + 
    +   if( winIsDir(zConverted) ){
    +@@ -39176,37 +43789,58 @@ static int winOpen(
    +     extendedParameters.dwSecurityQosFlags = SECURITY_ANONYMOUS;
    +     extendedParameters.lpSecurityAttributes = NULL;
    +     extendedParameters.hTemplateFile = NULL;
    +-    while( (h = osCreateFile2((LPCWSTR)zConverted,
    +-                              dwDesiredAccess,
    +-                              dwShareMode,
    +-                              dwCreationDisposition,
    +-                              &extendedParameters))==INVALID_HANDLE_VALUE &&
    +-                              winRetryIoerr(&cnt, &lastErrno) ){
    +-               /* Noop */
    +-    }
    ++    do{
    ++      h = osCreateFile2((LPCWSTR)zConverted,
    ++                        dwDesiredAccess,
    ++                        dwShareMode,
    ++                        dwCreationDisposition,
    ++                        &extendedParameters);
    ++      if( h!=INVALID_HANDLE_VALUE ) break;
    ++      if( isReadWrite ){
    ++        int rc2, isRO = 0;
    ++        sqlite3BeginBenignMalloc();
    ++        rc2 = winAccess(pVfs, zName, SQLITE_ACCESS_READ, &isRO);
    ++        sqlite3EndBenignMalloc();
    ++        if( rc2==SQLITE_OK && isRO ) break;
    ++      }
    ++    }while( winRetryIoerr(&cnt, &lastErrno) );
    + #else
    +-    while( (h = osCreateFileW((LPCWSTR)zConverted,
    +-                              dwDesiredAccess,
    +-                              dwShareMode, NULL,
    +-                              dwCreationDisposition,
    +-                              dwFlagsAndAttributes,
    +-                              NULL))==INVALID_HANDLE_VALUE &&
    +-                              winRetryIoerr(&cnt, &lastErrno) ){
    +-               /* Noop */
    +-    }
    ++    do{
    ++      h = osCreateFileW((LPCWSTR)zConverted,
    ++                        dwDesiredAccess,
    ++                        dwShareMode, NULL,
    ++                        dwCreationDisposition,
    ++                        dwFlagsAndAttributes,
    ++                        NULL);
    ++      if( h!=INVALID_HANDLE_VALUE ) break;
    ++      if( isReadWrite ){
    ++        int rc2, isRO = 0;
    ++        sqlite3BeginBenignMalloc();
    ++        rc2 = winAccess(pVfs, zName, SQLITE_ACCESS_READ, &isRO);
    ++        sqlite3EndBenignMalloc();
    ++        if( rc2==SQLITE_OK && isRO ) break;
    ++      }
    ++    }while( winRetryIoerr(&cnt, &lastErrno) );
    + #endif
    +   }
    + #ifdef SQLITE_WIN32_HAS_ANSI
    +   else{
    +-    while( (h = osCreateFileA((LPCSTR)zConverted,
    +-                              dwDesiredAccess,
    +-                              dwShareMode, NULL,
    +-                              dwCreationDisposition,
    +-                              dwFlagsAndAttributes,
    +-                              NULL))==INVALID_HANDLE_VALUE &&
    +-                              winRetryIoerr(&cnt, &lastErrno) ){
    +-               /* Noop */
    +-    }
    ++    do{
    ++      h = osCreateFileA((LPCSTR)zConverted,
    ++                        dwDesiredAccess,
    ++                        dwShareMode, NULL,
    ++                        dwCreationDisposition,
    ++                        dwFlagsAndAttributes,
    ++                        NULL);
    ++      if( h!=INVALID_HANDLE_VALUE ) break;
    ++      if( isReadWrite ){
    ++        int rc2, isRO = 0;
    ++        sqlite3BeginBenignMalloc();
    ++        rc2 = winAccess(pVfs, zName, SQLITE_ACCESS_READ, &isRO);
    ++        sqlite3EndBenignMalloc();
    ++        if( rc2==SQLITE_OK && isRO ) break;
    ++      }
    ++    }while( winRetryIoerr(&cnt, &lastErrno) );
    +   }
    + #endif
    +   winLogIoerr(cnt, __LINE__);
    +@@ -39215,8 +43849,6 @@ static int winOpen(
    +            dwDesiredAccess, (h==INVALID_HANDLE_VALUE) ? "failed" : "ok"));
    + 
    +   if( h==INVALID_HANDLE_VALUE ){
    +-    pFile->lastErrno = lastErrno;
    +-    winLogError(SQLITE_CANTOPEN, pFile->lastErrno, "winOpen", zUtf8Name);
    +     sqlite3_free(zConverted);
    +     sqlite3_free(zTmpname);
    +     if( isReadWrite && !isExclusive ){
    +@@ -39225,6 +43857,8 @@ static int winOpen(
    +                      ~(SQLITE_OPEN_CREATE|SQLITE_OPEN_READWRITE)),
    +          pOutFlags);
    +     }else{
    ++      pFile->lastErrno = lastErrno;
    ++      winLogError(SQLITE_CANTOPEN, pFile->lastErrno, "winOpen", zUtf8Name);
    +       return SQLITE_CANTOPEN_BKPT;
    +     }
    +   }
    +@@ -39241,15 +43875,20 @@ static int winOpen(
    +            "rc=%s\n", h, zUtf8Name, dwDesiredAccess, pOutFlags, pOutFlags ?
    +            *pOutFlags : 0, (h==INVALID_HANDLE_VALUE) ? "failed" : "ok"));
    + 
    ++  pAppData = (winVfsAppData*)pVfs->pAppData;
    ++
    + #if SQLITE_OS_WINCE
    +-  if( isReadWrite && eType==SQLITE_OPEN_MAIN_DB
    +-       && (rc = winceCreateLock(zName, pFile))!=SQLITE_OK
    +-  ){
    +-    osCloseHandle(h);
    +-    sqlite3_free(zConverted);
    +-    sqlite3_free(zTmpname);
    +-    OSTRACE(("OPEN-CE-LOCK name=%s, rc=%s\n", zName, sqlite3ErrName(rc)));
    +-    return rc;
    ++  {
    ++    if( isReadWrite && eType==SQLITE_OPEN_MAIN_DB
    ++         && ((pAppData==NULL) || !pAppData->bNoLock)
    ++         && (rc = winceCreateLock(zName, pFile))!=SQLITE_OK
    ++    ){
    ++      osCloseHandle(h);
    ++      sqlite3_free(zConverted);
    ++      sqlite3_free(zTmpname);
    ++      OSTRACE(("OPEN-CE-LOCK name=%s, rc=%s\n", zName, sqlite3ErrName(rc)));
    ++      return rc;
    ++    }
    +   }
    +   if( isTemp ){
    +     pFile->zDeleteOnClose = zConverted;
    +@@ -39260,7 +43899,7 @@ static int winOpen(
    +   }
    + 
    +   sqlite3_free(zTmpname);
    +-  pFile->pMethod = &winIoMethod;
    ++  pFile->pMethod = pAppData ? pAppData->pMethod : &winIoMethod;
    +   pFile->pVfs = pVfs;
    +   pFile->h = h;
    +   if( isReadonly ){
    +@@ -39314,7 +43953,7 @@ static int winDelete(
    +   zConverted = winConvertFromUtf8Filename(zFilename);
    +   if( zConverted==0 ){
    +     OSTRACE(("DELETE name=%s, rc=SQLITE_IOERR_NOMEM\n", zFilename));
    +-    return SQLITE_IOERR_NOMEM;
    ++    return SQLITE_IOERR_NOMEM_BKPT;
    +   }
    +   if( osIsNT() ){
    +     do {
    +@@ -39422,7 +44061,7 @@ static int winAccess(
    +   zConverted = winConvertFromUtf8Filename(zFilename);
    +   if( zConverted==0 ){
    +     OSTRACE(("ACCESS name=%s, rc=SQLITE_IOERR_NOMEM\n", zFilename));
    +-    return SQLITE_IOERR_NOMEM;
    ++    return SQLITE_IOERR_NOMEM_BKPT;
    +   }
    +   if( osIsNT() ){
    +     int cnt = 0;
    +@@ -39535,6 +44174,18 @@ static int winFullPathname(
    +   int nFull,                    /* Size of output buffer in bytes */
    +   char *zFull                   /* Output buffer */
    + ){
    ++#if !SQLITE_OS_WINCE && !SQLITE_OS_WINRT && !defined(__CYGWIN__)
    ++  DWORD nByte;
    ++  void *zConverted;
    ++  char *zOut;
    ++#endif
    ++
    ++  /* If this path name begins with "/X:", where "X" is any alphabetic
    ++  ** character, discard the initial "/" from the pathname.
    ++  */
    ++  if( zRelative[0]=='/' && winIsDriveLetterAndColon(zRelative+1) ){
    ++    zRelative++;
    ++  }
    + 
    + #if defined(__CYGWIN__)
    +   SimulateIOError( return SQLITE_ERROR );
    +@@ -39549,7 +44200,7 @@ static int winFullPathname(
    +     */
    +     char *zOut = sqlite3MallocZero( pVfs->mxPathname+1 );
    +     if( !zOut ){
    +-      return SQLITE_IOERR_NOMEM;
    ++      return SQLITE_IOERR_NOMEM_BKPT;
    +     }
    +     if( cygwin_conv_path(
    +             (osIsNT() ? CCP_POSIX_TO_WIN_W : CCP_POSIX_TO_WIN_A) |
    +@@ -39561,7 +44212,7 @@ static int winFullPathname(
    +       char *zUtf8 = winConvertToUtf8Filename(zOut);
    +       if( !zUtf8 ){
    +         sqlite3_free(zOut);
    +-        return SQLITE_IOERR_NOMEM;
    ++        return SQLITE_IOERR_NOMEM_BKPT;
    +       }
    +       sqlite3_snprintf(MIN(nFull, pVfs->mxPathname), zFull, "%s%c%s",
    +                        sqlite3_data_directory, winGetDirSep(), zUtf8);
    +@@ -39571,7 +44222,7 @@ static int winFullPathname(
    +   }else{
    +     char *zOut = sqlite3MallocZero( pVfs->mxPathname+1 );
    +     if( !zOut ){
    +-      return SQLITE_IOERR_NOMEM;
    ++      return SQLITE_IOERR_NOMEM_BKPT;
    +     }
    +     if( cygwin_conv_path(
    +             (osIsNT() ? CCP_POSIX_TO_WIN_W : CCP_POSIX_TO_WIN_A),
    +@@ -39583,7 +44234,7 @@ static int winFullPathname(
    +       char *zUtf8 = winConvertToUtf8Filename(zOut);
    +       if( !zUtf8 ){
    +         sqlite3_free(zOut);
    +-        return SQLITE_IOERR_NOMEM;
    ++        return SQLITE_IOERR_NOMEM_BKPT;
    +       }
    +       sqlite3_snprintf(MIN(nFull, pVfs->mxPathname), zFull, "%s", zUtf8);
    +       sqlite3_free(zUtf8);
    +@@ -39613,17 +44264,6 @@ static int winFullPathname(
    + #endif
    + 
    + #if !SQLITE_OS_WINCE && !SQLITE_OS_WINRT && !defined(__CYGWIN__)
    +-  DWORD nByte;
    +-  void *zConverted;
    +-  char *zOut;
    +-
    +-  /* If this path name begins with "/X:", where "X" is any alphabetic
    +-  ** character, discard the initial "/" from the pathname.
    +-  */
    +-  if( zRelative[0]=='/' && winIsDriveLetterAndColon(zRelative+1) ){
    +-    zRelative++;
    +-  }
    +-
    +   /* 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. This function could fail if, for example, the
    +@@ -39643,7 +44283,7 @@ static int winFullPathname(
    +   }
    +   zConverted = winConvertFromUtf8Filename(zRelative);
    +   if( zConverted==0 ){
    +-    return SQLITE_IOERR_NOMEM;
    ++    return SQLITE_IOERR_NOMEM_BKPT;
    +   }
    +   if( osIsNT() ){
    +     LPWSTR zTemp;
    +@@ -39657,7 +44297,7 @@ static int winFullPathname(
    +     zTemp = sqlite3MallocZero( nByte*sizeof(zTemp[0]) );
    +     if( zTemp==0 ){
    +       sqlite3_free(zConverted);
    +-      return SQLITE_IOERR_NOMEM;
    ++      return SQLITE_IOERR_NOMEM_BKPT;
    +     }
    +     nByte = osGetFullPathNameW((LPCWSTR)zConverted, nByte, zTemp, 0);
    +     if( nByte==0 ){
    +@@ -39683,7 +44323,7 @@ static int winFullPathname(
    +     zTemp = sqlite3MallocZero( nByte*sizeof(zTemp[0]) );
    +     if( zTemp==0 ){
    +       sqlite3_free(zConverted);
    +-      return SQLITE_IOERR_NOMEM;
    ++      return SQLITE_IOERR_NOMEM_BKPT;
    +     }
    +     nByte = osGetFullPathNameA((char*)zConverted, nByte, zTemp, 0);
    +     if( nByte==0 ){
    +@@ -39693,7 +44333,7 @@ static int winFullPathname(
    +                          "winFullPathname4", zRelative);
    +     }
    +     sqlite3_free(zConverted);
    +-    zOut = sqlite3_win32_mbcs_to_utf8(zTemp);
    ++    zOut = winMbcsToUtf8(zTemp, osAreFileApisANSI());
    +     sqlite3_free(zTemp);
    +   }
    + #endif
    +@@ -39702,7 +44342,7 @@ static int winFullPathname(
    +     sqlite3_free(zOut);
    +     return SQLITE_OK;
    +   }else{
    +-    return SQLITE_IOERR_NOMEM;
    ++    return SQLITE_IOERR_NOMEM_BKPT;
    +   }
    + #endif
    + }
    +@@ -39777,65 +44417,82 @@ static void winDlClose(sqlite3_vfs *pVfs, void *pHandle){
    +   #define winDlClose 0
    + #endif
    + 
    ++/* State information for the randomness gatherer. */
    ++typedef struct EntropyGatherer EntropyGatherer;
    ++struct EntropyGatherer {
    ++  unsigned char *a;   /* Gather entropy into this buffer */
    ++  int na;             /* Size of a[] in bytes */
    ++  int i;              /* XOR next input into a[i] */
    ++  int nXor;           /* Number of XOR operations done */
    ++};
    ++
    ++#if !defined(SQLITE_TEST) && !defined(SQLITE_OMIT_RANDOMNESS)
    ++/* Mix sz bytes of entropy into p. */
    ++static void xorMemory(EntropyGatherer *p, unsigned char *x, int sz){
    ++  int j, k;
    ++  for(j=0, k=p->i; j<sz; j++){
    ++    p->a[k++] ^= x[j];
    ++    if( k>=p->na ) k = 0;
    ++  }
    ++  p->i = k;
    ++  p->nXor += sz;
    ++}
    ++#endif /* !defined(SQLITE_TEST) && !defined(SQLITE_OMIT_RANDOMNESS) */
    + 
    + /*
    + ** Write up to nBuf bytes of randomness into zBuf.
    + */
    + static int winRandomness(sqlite3_vfs *pVfs, int nBuf, char *zBuf){
    +-  int n = 0;
    +-  UNUSED_PARAMETER(pVfs);
    + #if defined(SQLITE_TEST) || defined(SQLITE_OMIT_RANDOMNESS)
    +-  n = nBuf;
    ++  UNUSED_PARAMETER(pVfs);
    +   memset(zBuf, 0, nBuf);
    ++  return nBuf;
    + #else
    +-  if( sizeof(SYSTEMTIME)<=nBuf-n ){
    ++  EntropyGatherer e;
    ++  UNUSED_PARAMETER(pVfs);
    ++  memset(zBuf, 0, nBuf);
    ++  e.a = (unsigned char*)zBuf;
    ++  e.na = nBuf;
    ++  e.nXor = 0;
    ++  e.i = 0;
    ++  {
    +     SYSTEMTIME x;
    +     osGetSystemTime(&x);
    +-    memcpy(&zBuf[n], &x, sizeof(x));
    +-    n += sizeof(x);
    ++    xorMemory(&e, (unsigned char*)&x, sizeof(SYSTEMTIME));
    +   }
    +-  if( sizeof(DWORD)<=nBuf-n ){
    ++  {
    +     DWORD pid = osGetCurrentProcessId();
    +-    memcpy(&zBuf[n], &pid, sizeof(pid));
    +-    n += sizeof(pid);
    ++    xorMemory(&e, (unsigned char*)&pid, sizeof(DWORD));
    +   }
    + #if SQLITE_OS_WINRT
    +-  if( sizeof(ULONGLONG)<=nBuf-n ){
    ++  {
    +     ULONGLONG cnt = osGetTickCount64();
    +-    memcpy(&zBuf[n], &cnt, sizeof(cnt));
    +-    n += sizeof(cnt);
    ++    xorMemory(&e, (unsigned char*)&cnt, sizeof(ULONGLONG));
    +   }
    + #else
    +-  if( sizeof(DWORD)<=nBuf-n ){
    ++  {
    +     DWORD cnt = osGetTickCount();
    +-    memcpy(&zBuf[n], &cnt, sizeof(cnt));
    +-    n += sizeof(cnt);
    ++    xorMemory(&e, (unsigned char*)&cnt, sizeof(DWORD));
    +   }
    +-#endif
    +-  if( sizeof(LARGE_INTEGER)<=nBuf-n ){
    ++#endif /* SQLITE_OS_WINRT */
    ++  {
    +     LARGE_INTEGER i;
    +     osQueryPerformanceCounter(&i);
    +-    memcpy(&zBuf[n], &i, sizeof(i));
    +-    n += sizeof(i);
    ++    xorMemory(&e, (unsigned char*)&i, sizeof(LARGE_INTEGER));
    +   }
    + #if !SQLITE_OS_WINCE && !SQLITE_OS_WINRT && SQLITE_WIN32_USE_UUID
    +-  if( sizeof(UUID)<=nBuf-n ){
    ++  {
    +     UUID id;
    +     memset(&id, 0, sizeof(UUID));
    +     osUuidCreate(&id);
    +-    memcpy(&zBuf[n], &id, sizeof(UUID));
    +-    n += sizeof(UUID);
    +-  }
    +-  if( sizeof(UUID)<=nBuf-n ){
    +-    UUID id;
    ++    xorMemory(&e, (unsigned char*)&id, sizeof(UUID));
    +     memset(&id, 0, sizeof(UUID));
    +     osUuidCreateSequential(&id);
    +-    memcpy(&zBuf[n], &id, sizeof(UUID));
    +-    n += sizeof(UUID);
    ++    xorMemory(&e, (unsigned char*)&id, sizeof(UUID));
    +   }
    +-#endif
    +-#endif /* defined(SQLITE_TEST) || defined(SQLITE_ZERO_PRNG_SEED) */
    +-  return n;
    ++#endif /* !SQLITE_OS_WINCE && !SQLITE_OS_WINRT && SQLITE_WIN32_USE_UUID */
    ++  return e.nXor>nBuf ? nBuf : e.nXor;
    ++#endif /* defined(SQLITE_TEST) || defined(SQLITE_OMIT_RANDOMNESS) */
    + }
    + 
    + 
    +@@ -39951,62 +44608,114 @@ static int winCurrentTime(sqlite3_vfs *pVfs, double *prNow){
    + ** sqlite3_errmsg(), possibly making IO errors easier to debug.
    + */
    + static int winGetLastError(sqlite3_vfs *pVfs, int nBuf, char *zBuf){
    ++  DWORD e = osGetLastError();
    +   UNUSED_PARAMETER(pVfs);
    +-  return winGetLastErrorMsg(osGetLastError(), nBuf, zBuf);
    ++  if( nBuf>0 ) winGetLastErrorMsg(e, nBuf, zBuf);
    ++  return e;
    + }
    + 
    + /*
    + ** Initialize and deinitialize the operating system interface.
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_os_init(void){
    ++SQLITE_API int sqlite3_os_init(void){
    +   static sqlite3_vfs winVfs = {
    +-    3,                   /* iVersion */
    +-    sizeof(winFile),     /* szOsFile */
    ++    3,                     /* iVersion */
    ++    sizeof(winFile),       /* szOsFile */
    +     SQLITE_WIN32_MAX_PATH_BYTES, /* mxPathname */
    +-    0,                   /* pNext */
    +-    "win32",             /* zName */
    +-    0,                   /* pAppData */
    +-    winOpen,             /* xOpen */
    +-    winDelete,           /* xDelete */
    +-    winAccess,           /* xAccess */
    +-    winFullPathname,     /* xFullPathname */
    +-    winDlOpen,           /* xDlOpen */
    +-    winDlError,          /* xDlError */
    +-    winDlSym,            /* xDlSym */
    +-    winDlClose,          /* xDlClose */
    +-    winRandomness,       /* xRandomness */
    +-    winSleep,            /* xSleep */
    +-    winCurrentTime,      /* xCurrentTime */
    +-    winGetLastError,     /* xGetLastError */
    +-    winCurrentTimeInt64, /* xCurrentTimeInt64 */
    +-    winSetSystemCall,    /* xSetSystemCall */
    +-    winGetSystemCall,    /* xGetSystemCall */
    +-    winNextSystemCall,   /* xNextSystemCall */
    ++    0,                     /* pNext */
    ++    "win32",               /* zName */
    ++    &winAppData,           /* pAppData */
    ++    winOpen,               /* xOpen */
    ++    winDelete,             /* xDelete */
    ++    winAccess,             /* xAccess */
    ++    winFullPathname,       /* xFullPathname */
    ++    winDlOpen,             /* xDlOpen */
    ++    winDlError,            /* xDlError */
    ++    winDlSym,              /* xDlSym */
    ++    winDlClose,            /* xDlClose */
    ++    winRandomness,         /* xRandomness */
    ++    winSleep,              /* xSleep */
    ++    winCurrentTime,        /* xCurrentTime */
    ++    winGetLastError,       /* xGetLastError */
    ++    winCurrentTimeInt64,   /* xCurrentTimeInt64 */
    ++    winSetSystemCall,      /* xSetSystemCall */
    ++    winGetSystemCall,      /* xGetSystemCall */
    ++    winNextSystemCall,     /* xNextSystemCall */
    +   };
    + #if defined(SQLITE_WIN32_HAS_WIDE)
    +   static sqlite3_vfs winLongPathVfs = {
    +-    3,                   /* iVersion */
    +-    sizeof(winFile),     /* szOsFile */
    ++    3,                     /* iVersion */
    ++    sizeof(winFile),       /* szOsFile */
    +     SQLITE_WINNT_MAX_PATH_BYTES, /* mxPathname */
    +-    0,                   /* pNext */
    +-    "win32-longpath",    /* zName */
    +-    0,                   /* pAppData */
    +-    winOpen,             /* xOpen */
    +-    winDelete,           /* xDelete */
    +-    winAccess,           /* xAccess */
    +-    winFullPathname,     /* xFullPathname */
    +-    winDlOpen,           /* xDlOpen */
    +-    winDlError,          /* xDlError */
    +-    winDlSym,            /* xDlSym */
    +-    winDlClose,          /* xDlClose */
    +-    winRandomness,       /* xRandomness */
    +-    winSleep,            /* xSleep */
    +-    winCurrentTime,      /* xCurrentTime */
    +-    winGetLastError,     /* xGetLastError */
    +-    winCurrentTimeInt64, /* xCurrentTimeInt64 */
    +-    winSetSystemCall,    /* xSetSystemCall */
    +-    winGetSystemCall,    /* xGetSystemCall */
    +-    winNextSystemCall,   /* xNextSystemCall */
    ++    0,                     /* pNext */
    ++    "win32-longpath",      /* zName */
    ++    &winAppData,           /* pAppData */
    ++    winOpen,               /* xOpen */
    ++    winDelete,             /* xDelete */
    ++    winAccess,             /* xAccess */
    ++    winFullPathname,       /* xFullPathname */
    ++    winDlOpen,             /* xDlOpen */
    ++    winDlError,            /* xDlError */
    ++    winDlSym,              /* xDlSym */
    ++    winDlClose,            /* xDlClose */
    ++    winRandomness,         /* xRandomness */
    ++    winSleep,              /* xSleep */
    ++    winCurrentTime,        /* xCurrentTime */
    ++    winGetLastError,       /* xGetLastError */
    ++    winCurrentTimeInt64,   /* xCurrentTimeInt64 */
    ++    winSetSystemCall,      /* xSetSystemCall */
    ++    winGetSystemCall,      /* xGetSystemCall */
    ++    winNextSystemCall,     /* xNextSystemCall */
    ++  };
    ++#endif
    ++  static sqlite3_vfs winNolockVfs = {
    ++    3,                     /* iVersion */
    ++    sizeof(winFile),       /* szOsFile */
    ++    SQLITE_WIN32_MAX_PATH_BYTES, /* mxPathname */
    ++    0,                     /* pNext */
    ++    "win32-none",          /* zName */
    ++    &winNolockAppData,     /* pAppData */
    ++    winOpen,               /* xOpen */
    ++    winDelete,             /* xDelete */
    ++    winAccess,             /* xAccess */
    ++    winFullPathname,       /* xFullPathname */
    ++    winDlOpen,             /* xDlOpen */
    ++    winDlError,            /* xDlError */
    ++    winDlSym,              /* xDlSym */
    ++    winDlClose,            /* xDlClose */
    ++    winRandomness,         /* xRandomness */
    ++    winSleep,              /* xSleep */
    ++    winCurrentTime,        /* xCurrentTime */
    ++    winGetLastError,       /* xGetLastError */
    ++    winCurrentTimeInt64,   /* xCurrentTimeInt64 */
    ++    winSetSystemCall,      /* xSetSystemCall */
    ++    winGetSystemCall,      /* xGetSystemCall */
    ++    winNextSystemCall,     /* xNextSystemCall */
    ++  };
    ++#if defined(SQLITE_WIN32_HAS_WIDE)
    ++  static sqlite3_vfs winLongPathNolockVfs = {
    ++    3,                     /* iVersion */
    ++    sizeof(winFile),       /* szOsFile */
    ++    SQLITE_WINNT_MAX_PATH_BYTES, /* mxPathname */
    ++    0,                     /* pNext */
    ++    "win32-longpath-none", /* zName */
    ++    &winNolockAppData,     /* pAppData */
    ++    winOpen,               /* xOpen */
    ++    winDelete,             /* xDelete */
    ++    winAccess,             /* xAccess */
    ++    winFullPathname,       /* xFullPathname */
    ++    winDlOpen,             /* xDlOpen */
    ++    winDlError,            /* xDlError */
    ++    winDlSym,              /* xDlSym */
    ++    winDlClose,            /* xDlClose */
    ++    winRandomness,         /* xRandomness */
    ++    winSleep,              /* xSleep */
    ++    winCurrentTime,        /* xCurrentTime */
    ++    winGetLastError,       /* xGetLastError */
    ++    winCurrentTimeInt64,   /* xCurrentTimeInt64 */
    ++    winSetSystemCall,      /* xSetSystemCall */
    ++    winGetSystemCall,      /* xGetSystemCall */
    ++    winNextSystemCall,     /* xNextSystemCall */
    +   };
    + #endif
    + 
    +@@ -40030,10 +44739,16 @@ SQLITE_API int SQLITE_STDCALL sqlite3_os_init(void){
    +   sqlite3_vfs_register(&winLongPathVfs, 0);
    + #endif
    + 
    ++  sqlite3_vfs_register(&winNolockVfs, 0);
    ++
    ++#if defined(SQLITE_WIN32_HAS_WIDE)
    ++  sqlite3_vfs_register(&winLongPathNolockVfs, 0);
    ++#endif
    ++
    +   return SQLITE_OK;
    + }
    + 
    +-SQLITE_API int SQLITE_STDCALL sqlite3_os_end(void){
    ++SQLITE_API int sqlite3_os_end(void){
    + #if SQLITE_OS_WINRT
    +   if( sleepObj!=NULL ){
    +     osCloseHandle(sleepObj);
    +@@ -40090,7 +44805,8 @@ SQLITE_API int SQLITE_STDCALL sqlite3_os_end(void){
    + 
    + /* Round the union size down to the nearest pointer boundary, since that's how 
    + ** it will be aligned within the Bitvec struct. */
    +-#define BITVEC_USIZE     (((BITVEC_SZ-(3*sizeof(u32)))/sizeof(Bitvec*))*sizeof(Bitvec*))
    ++#define BITVEC_USIZE \
    ++    (((BITVEC_SZ-(3*sizeof(u32)))/sizeof(Bitvec*))*sizeof(Bitvec*))
    + 
    + /* Type of the array "element" for the bitmap representation. 
    + ** Should be a power of 2, and ideally, evenly divide into BITVEC_USIZE. 
    +@@ -40225,7 +44941,7 @@ SQLITE_PRIVATE int sqlite3BitvecSet(Bitvec *p, u32 i){
    +     i = i%p->iDivisor;
    +     if( p->u.apSub[bin]==0 ){
    +       p->u.apSub[bin] = sqlite3BitvecCreate( p->iDivisor );
    +-      if( p->u.apSub[bin]==0 ) return SQLITE_NOMEM;
    ++      if( p->u.apSub[bin]==0 ) return SQLITE_NOMEM_BKPT;
    +     }
    +     p = p->u.apSub[bin];
    +   }
    +@@ -40260,7 +44976,7 @@ bitvec_set_rehash:
    +     int rc;
    +     u32 *aiValues = sqlite3StackAllocRaw(0, sizeof(p->u.aHash));
    +     if( aiValues==0 ){
    +-      return SQLITE_NOMEM;
    ++      return SQLITE_NOMEM_BKPT;
    +     }else{
    +       memcpy(aiValues, p->u.aHash, sizeof(p->u.aHash));
    +       memset(p->u.apSub, 0, sizeof(p->u.apSub));
    +@@ -40341,7 +45057,7 @@ SQLITE_PRIVATE u32 sqlite3BitvecSize(Bitvec *p){
    +   return p->iSize;
    + }
    + 
    +-#ifndef SQLITE_OMIT_BUILTIN_TEST
    ++#ifndef SQLITE_UNTESTABLE
    + /*
    + ** Let V[] be an array of unsigned characters sufficient to hold
    + ** up to N bits.  Let I be an integer between 0 and N.  0<=I<N.
    +@@ -40456,7 +45172,7 @@ bitvec_end:
    +   sqlite3BitvecDestroy(pBitvec);
    +   return rc;
    + }
    +-#endif /* SQLITE_OMIT_BUILTIN_TEST */
    ++#endif /* SQLITE_UNTESTABLE */
    + 
    + /************** End of bitvec.c **********************************************/
    + /************** Begin file pcache.c ******************************************/
    +@@ -40476,13 +45192,36 @@ bitvec_end:
    + /* #include "sqliteInt.h" */
    + 
    + /*
    +-** A complete page cache is an instance of this structure.
    ++** A complete page cache is an instance of this structure.  Every
    ++** entry in the cache holds a single page of the database file.  The
    ++** btree layer only operates on the cached copy of the database pages.
    ++**
    ++** A page cache entry is "clean" if it exactly matches what is currently
    ++** on disk.  A page is "dirty" if it has been modified and needs to be
    ++** persisted to disk.
    ++**
    ++** pDirty, pDirtyTail, pSynced:
    ++**   All dirty pages are linked into the doubly linked list using
    ++**   PgHdr.pDirtyNext and pDirtyPrev. The list is maintained in LRU order
    ++**   such that p was added to the list more recently than p->pDirtyNext.
    ++**   PCache.pDirty points to the first (newest) element in the list and
    ++**   pDirtyTail to the last (oldest).
    ++**
    ++**   The PCache.pSynced variable is used to optimize searching for a dirty
    ++**   page to eject from the cache mid-transaction. It is better to eject
    ++**   a page that does not require a journal sync than one that does. 
    ++**   Therefore, pSynced is maintained to that it *almost* always points
    ++**   to either the oldest page in the pDirty/pDirtyTail list that has a
    ++**   clear PGHDR_NEED_SYNC flag or to a page that is older than this one
    ++**   (so that the right page to eject can be found by following pDirtyPrev
    ++**   pointers).
    + */
    + struct PCache {
    +   PgHdr *pDirty, *pDirtyTail;         /* List of dirty pages in LRU order */
    +   PgHdr *pSynced;                     /* Last synced page in dirty page list */
    +   int nRefSum;                        /* Sum of ref counts over all pages */
    +   int szCache;                        /* Configured cache size */
    ++  int szSpill;                        /* Size before spilling occurs */
    +   int szPage;                         /* Size of every page in this cache */
    +   int szExtra;                        /* Size of extra space for each page */
    +   u8 bPurgeable;                      /* True if pages are on backing store */
    +@@ -40492,6 +45231,95 @@ struct PCache {
    +   sqlite3_pcache *pCache;             /* Pluggable cache module */
    + };
    + 
    ++/********************************** Test and Debug Logic **********************/
    ++/*
    ++** Debug tracing macros.  Enable by by changing the "0" to "1" and
    ++** recompiling.
    ++**
    ++** When sqlite3PcacheTrace is 1, single line trace messages are issued.
    ++** When sqlite3PcacheTrace is 2, a dump of the pcache showing all cache entries
    ++** is displayed for many operations, resulting in a lot of output.
    ++*/
    ++#if defined(SQLITE_DEBUG) && 0
    ++  int sqlite3PcacheTrace = 2;       /* 0: off  1: simple  2: cache dumps */
    ++  int sqlite3PcacheMxDump = 9999;   /* Max cache entries for pcacheDump() */
    ++# define pcacheTrace(X) if(sqlite3PcacheTrace){sqlite3DebugPrintf X;}
    ++  void pcacheDump(PCache *pCache){
    ++    int N;
    ++    int i, j;
    ++    sqlite3_pcache_page *pLower;
    ++    PgHdr *pPg;
    ++    unsigned char *a;
    ++  
    ++    if( sqlite3PcacheTrace<2 ) return;
    ++    if( pCache->pCache==0 ) return;
    ++    N = sqlite3PcachePagecount(pCache);
    ++    if( N>sqlite3PcacheMxDump ) N = sqlite3PcacheMxDump;
    ++    for(i=1; i<=N; i++){
    ++       pLower = sqlite3GlobalConfig.pcache2.xFetch(pCache->pCache, i, 0);
    ++       if( pLower==0 ) continue;
    ++       pPg = (PgHdr*)pLower->pExtra;
    ++       printf("%3d: nRef %2d flgs %02x data ", i, pPg->nRef, pPg->flags);
    ++       a = (unsigned char *)pLower->pBuf;
    ++       for(j=0; j<12; j++) printf("%02x", a[j]);
    ++       printf("\n");
    ++       if( pPg->pPage==0 ){
    ++         sqlite3GlobalConfig.pcache2.xUnpin(pCache->pCache, pLower, 0);
    ++       }
    ++    }
    ++  }
    ++  #else
    ++# define pcacheTrace(X)
    ++# define pcacheDump(X)
    ++#endif
    ++
    ++/*
    ++** Check invariants on a PgHdr entry.  Return true if everything is OK.
    ++** Return false if any invariant is violated.
    ++**
    ++** This routine is for use inside of assert() statements only.  For
    ++** example:
    ++**
    ++**          assert( sqlite3PcachePageSanity(pPg) );
    ++*/
    ++#ifdef SQLITE_DEBUG
    ++SQLITE_PRIVATE int sqlite3PcachePageSanity(PgHdr *pPg){
    ++  PCache *pCache;
    ++  assert( pPg!=0 );
    ++  assert( pPg->pgno>0 || pPg->pPager==0 );    /* Page number is 1 or more */
    ++  pCache = pPg->pCache;
    ++  assert( pCache!=0 );      /* Every page has an associated PCache */
    ++  if( pPg->flags & PGHDR_CLEAN ){
    ++    assert( (pPg->flags & PGHDR_DIRTY)==0 );/* Cannot be both CLEAN and DIRTY */
    ++    assert( pCache->pDirty!=pPg );          /* CLEAN pages not on dirty list */
    ++    assert( pCache->pDirtyTail!=pPg );
    ++  }
    ++  /* WRITEABLE pages must also be DIRTY */
    ++  if( pPg->flags & PGHDR_WRITEABLE ){
    ++    assert( pPg->flags & PGHDR_DIRTY );     /* WRITEABLE implies DIRTY */
    ++  }
    ++  /* NEED_SYNC can be set independently of WRITEABLE.  This can happen,
    ++  ** for example, when using the sqlite3PagerDontWrite() optimization:
    ++  **    (1)  Page X is journalled, and gets WRITEABLE and NEED_SEEK.
    ++  **    (2)  Page X moved to freelist, WRITEABLE is cleared
    ++  **    (3)  Page X reused, WRITEABLE is set again
    ++  ** If NEED_SYNC had been cleared in step 2, then it would not be reset
    ++  ** in step 3, and page might be written into the database without first
    ++  ** syncing the rollback journal, which might cause corruption on a power
    ++  ** loss.
    ++  **
    ++  ** Another example is when the database page size is smaller than the
    ++  ** disk sector size.  When any page of a sector is journalled, all pages
    ++  ** in that sector are marked NEED_SYNC even if they are still CLEAN, just
    ++  ** in case they are later modified, since all pages in the same sector
    ++  ** must be journalled and synced before any of those pages can be safely
    ++  ** written.
    ++  */
    ++  return 1;
    ++}
    ++#endif /* SQLITE_DEBUG */
    ++
    ++
    + /********************************** Linked List Management ********************/
    + 
    + /* Allowed values for second argument to pcacheManageDirtyList() */
    +@@ -40508,17 +45336,16 @@ struct PCache {
    + static void pcacheManageDirtyList(PgHdr *pPage, u8 addRemove){
    +   PCache *p = pPage->pCache;
    + 
    ++  pcacheTrace(("%p.DIRTYLIST.%s %d\n", p,
    ++                addRemove==1 ? "REMOVE" : addRemove==2 ? "ADD" : "FRONT",
    ++                pPage->pgno));
    +   if( addRemove & PCACHE_DIRTYLIST_REMOVE ){
    +     assert( pPage->pDirtyNext || pPage==p->pDirtyTail );
    +     assert( pPage->pDirtyPrev || pPage==p->pDirty );
    +   
    +     /* Update the PCache1.pSynced variable if necessary. */
    +     if( p->pSynced==pPage ){
    +-      PgHdr *pSynced = pPage->pDirtyPrev;
    +-      while( pSynced && (pSynced->flags&PGHDR_NEED_SYNC) ){
    +-        pSynced = pSynced->pDirtyPrev;
    +-      }
    +-      p->pSynced = pSynced;
    ++      p->pSynced = pPage->pDirtyPrev;
    +     }
    +   
    +     if( pPage->pDirtyNext ){
    +@@ -40530,19 +45357,21 @@ static void pcacheManageDirtyList(PgHdr *pPage, u8 addRemove){
    +     if( pPage->pDirtyPrev ){
    +       pPage->pDirtyPrev->pDirtyNext = pPage->pDirtyNext;
    +     }else{
    ++      /* If there are now no dirty pages in the cache, set eCreate to 2. 
    ++      ** This is an optimization that allows sqlite3PcacheFetch() to skip
    ++      ** searching for a dirty page to eject from the cache when it might
    ++      ** otherwise have to.  */
    +       assert( pPage==p->pDirty );
    +       p->pDirty = pPage->pDirtyNext;
    +-      if( p->pDirty==0 && p->bPurgeable ){
    +-        assert( p->eCreate==1 );
    ++      assert( p->bPurgeable || p->eCreate==2 );
    ++      if( p->pDirty==0 ){         /*OPTIMIZATION-IF-TRUE*/
    ++        assert( p->bPurgeable==0 || p->eCreate==1 );
    +         p->eCreate = 2;
    +       }
    +     }
    +-    pPage->pDirtyNext = 0;
    +-    pPage->pDirtyPrev = 0;
    +   }
    +   if( addRemove & PCACHE_DIRTYLIST_ADD ){
    +-    assert( pPage->pDirtyNext==0 && pPage->pDirtyPrev==0 && p->pDirty!=pPage );
    +-  
    ++    pPage->pDirtyPrev = 0;
    +     pPage->pDirtyNext = p->pDirty;
    +     if( pPage->pDirtyNext ){
    +       assert( pPage->pDirtyNext->pDirtyPrev==0 );
    +@@ -40555,10 +45384,19 @@ static void pcacheManageDirtyList(PgHdr *pPage, u8 addRemove){
    +       }
    +     }
    +     p->pDirty = pPage;
    +-    if( !p->pSynced && 0==(pPage->flags&PGHDR_NEED_SYNC) ){
    ++
    ++    /* If pSynced is NULL and this page has a clear NEED_SYNC flag, set
    ++    ** pSynced to point to it. Checking the NEED_SYNC flag is an 
    ++    ** optimization, as if pSynced points to a page with the NEED_SYNC
    ++    ** flag set sqlite3PcacheFetchStress() searches through all newer 
    ++    ** entries of the dirty-list for a page with NEED_SYNC clear anyway.  */
    ++    if( !p->pSynced 
    ++     && 0==(pPage->flags&PGHDR_NEED_SYNC)   /*OPTIMIZATION-IF-FALSE*/
    ++    ){
    +       p->pSynced = pPage;
    +     }
    +   }
    ++  pcacheDump(p);
    + }
    + 
    + /*
    +@@ -40567,15 +45405,15 @@ static void pcacheManageDirtyList(PgHdr *pPage, u8 addRemove){
    + */
    + static void pcacheUnpin(PgHdr *p){
    +   if( p->pCache->bPurgeable ){
    ++    pcacheTrace(("%p.UNPIN %d\n", p->pCache, p->pgno));
    +     sqlite3GlobalConfig.pcache2.xUnpin(p->pCache->pCache, p->pPage, 0);
    ++    pcacheDump(p->pCache);
    +   }
    + }
    + 
    + /*
    +-** Compute the number of pages of cache requested.  p->szCache is the
    ++** Compute the number of pages of cache requested.   p->szCache is the
    + ** cache size requested by the "PRAGMA cache_size" statement.
    +-**
    +-**
    + */
    + static int numberOfCachePages(PCache *p){
    +   if( p->szCache>=0 ){
    +@@ -40621,6 +45459,12 @@ SQLITE_PRIVATE int sqlite3PcacheSize(void){ return sizeof(PCache); }
    + ** has already been allocated and is passed in as the p pointer. 
    + ** The caller discovers how much space needs to be allocated by 
    + ** calling sqlite3PcacheSize().
    ++**
    ++** szExtra is some extra space allocated for each page.  The first
    ++** 8 bytes of the extra space will be zeroed as the page is allocated,
    ++** but remaining content will be uninitialized.  Though it is opaque
    ++** to this module, the extra space really ends up being the MemPage
    ++** structure in the pager.
    + */
    + SQLITE_PRIVATE int sqlite3PcacheOpen(
    +   int szPage,                  /* Size of every page */
    +@@ -40633,11 +45477,14 @@ SQLITE_PRIVATE int sqlite3PcacheOpen(
    +   memset(p, 0, sizeof(PCache));
    +   p->szPage = 1;
    +   p->szExtra = szExtra;
    ++  assert( szExtra>=8 );  /* First 8 bytes will be zeroed */
    +   p->bPurgeable = bPurgeable;
    +   p->eCreate = 2;
    +   p->xStress = xStress;
    +   p->pStress = pStress;
    +   p->szCache = 100;
    ++  p->szSpill = 1;
    ++  pcacheTrace(("%p.OPEN szPage %d bPurgeable %d\n",p,szPage,bPurgeable));
    +   return sqlite3PcacheSetPageSize(p, szPage);
    + }
    + 
    +@@ -40653,13 +45500,14 @@ SQLITE_PRIVATE int sqlite3PcacheSetPageSize(PCache *pCache, int szPage){
    +                 szPage, pCache->szExtra + ROUND8(sizeof(PgHdr)),
    +                 pCache->bPurgeable
    +     );
    +-    if( pNew==0 ) return SQLITE_NOMEM;
    ++    if( pNew==0 ) return SQLITE_NOMEM_BKPT;
    +     sqlite3GlobalConfig.pcache2.xCachesize(pNew, numberOfCachePages(pCache));
    +     if( pCache->pCache ){
    +       sqlite3GlobalConfig.pcache2.xDestroy(pCache->pCache);
    +     }
    +     pCache->pCache = pNew;
    +     pCache->szPage = szPage;
    ++    pcacheTrace(("%p.PAGESIZE %d\n",pCache,szPage));
    +   }
    +   return SQLITE_OK;
    + }
    +@@ -40694,11 +45542,12 @@ SQLITE_PRIVATE sqlite3_pcache_page *sqlite3PcacheFetch(
    +   int createFlag        /* If true, create page if it does not exist already */
    + ){
    +   int eCreate;
    ++  sqlite3_pcache_page *pRes;
    + 
    +   assert( pCache!=0 );
    +   assert( pCache->pCache!=0 );
    +   assert( createFlag==3 || createFlag==0 );
    +-  assert( pgno>0 );
    ++  assert( pCache->eCreate==((pCache->bPurgeable && pCache->pDirty) ? 1 : 2) );
    + 
    +   /* eCreate defines what to do if the page does not exist.
    +   **    0     Do not allocate a new page.  (createFlag==0)
    +@@ -40711,12 +45560,15 @@ SQLITE_PRIVATE sqlite3_pcache_page *sqlite3PcacheFetch(
    +   assert( eCreate==0 || eCreate==1 || eCreate==2 );
    +   assert( createFlag==0 || pCache->eCreate==eCreate );
    +   assert( createFlag==0 || eCreate==1+(!pCache->bPurgeable||!pCache->pDirty) );
    +-  return sqlite3GlobalConfig.pcache2.xFetch(pCache->pCache, pgno, eCreate);
    ++  pRes = sqlite3GlobalConfig.pcache2.xFetch(pCache->pCache, pgno, eCreate);
    ++  pcacheTrace(("%p.FETCH %d%s (result: %p)\n",pCache,pgno,
    ++               createFlag?" create":"",pRes));
    ++  return pRes;
    + }
    + 
    + /*
    + ** If the sqlite3PcacheFetch() routine is unable to allocate a new
    +-** page because new clean pages are available for reuse and the cache
    ++** page because no clean pages are available for reuse and the cache
    + ** size limit has been reached, then this routine can be invoked to 
    + ** try harder to allocate a page.  This routine might invoke the stress
    + ** callback to spill dirty pages to the journal.  It will then try to
    +@@ -40733,36 +45585,43 @@ SQLITE_PRIVATE int sqlite3PcacheFetchStress(
    +   PgHdr *pPg;
    +   if( pCache->eCreate==2 ) return 0;
    + 
    +-
    +-  /* Find a dirty page to write-out and recycle. First try to find a 
    +-  ** page that does not require a journal-sync (one with PGHDR_NEED_SYNC
    +-  ** cleared), but if that is not possible settle for any other 
    +-  ** unreferenced dirty page.
    +-  */
    +-  for(pPg=pCache->pSynced; 
    +-      pPg && (pPg->nRef || (pPg->flags&PGHDR_NEED_SYNC)); 
    +-      pPg=pPg->pDirtyPrev
    +-  );
    +-  pCache->pSynced = pPg;
    +-  if( !pPg ){
    +-    for(pPg=pCache->pDirtyTail; pPg && pPg->nRef; pPg=pPg->pDirtyPrev);
    +-  }
    +-  if( pPg ){
    +-    int rc;
    ++  if( sqlite3PcachePagecount(pCache)>pCache->szSpill ){
    ++    /* Find a dirty page to write-out and recycle. First try to find a 
    ++    ** page that does not require a journal-sync (one with PGHDR_NEED_SYNC
    ++    ** cleared), but if that is not possible settle for any other 
    ++    ** unreferenced dirty page.
    ++    **
    ++    ** If the LRU page in the dirty list that has a clear PGHDR_NEED_SYNC
    ++    ** flag is currently referenced, then the following may leave pSynced
    ++    ** set incorrectly (pointing to other than the LRU page with NEED_SYNC
    ++    ** cleared). This is Ok, as pSynced is just an optimization.  */
    ++    for(pPg=pCache->pSynced; 
    ++        pPg && (pPg->nRef || (pPg->flags&PGHDR_NEED_SYNC)); 
    ++        pPg=pPg->pDirtyPrev
    ++    );
    ++    pCache->pSynced = pPg;
    ++    if( !pPg ){
    ++      for(pPg=pCache->pDirtyTail; pPg && pPg->nRef; pPg=pPg->pDirtyPrev);
    ++    }
    ++    if( pPg ){
    ++      int rc;
    + #ifdef SQLITE_LOG_CACHE_SPILL
    +-    sqlite3_log(SQLITE_FULL, 
    +-                "spill page %d making room for %d - cache used: %d/%d",
    +-                pPg->pgno, pgno,
    +-                sqlite3GlobalConfig.pcache.xPagecount(pCache->pCache),
    ++      sqlite3_log(SQLITE_FULL, 
    ++                  "spill page %d making room for %d - cache used: %d/%d",
    ++                  pPg->pgno, pgno,
    ++                  sqlite3GlobalConfig.pcache.xPagecount(pCache->pCache),
    +                 numberOfCachePages(pCache));
    + #endif
    +-    rc = pCache->xStress(pCache->pStress, pPg);
    +-    if( rc!=SQLITE_OK && rc!=SQLITE_BUSY ){
    +-      return rc;
    ++      pcacheTrace(("%p.SPILL %d\n",pCache,pPg->pgno));
    ++      rc = pCache->xStress(pCache->pStress, pPg);
    ++      pcacheDump(pCache);
    ++      if( rc!=SQLITE_OK && rc!=SQLITE_BUSY ){
    ++        return rc;
    ++      }
    +     }
    +   }
    +   *ppPage = sqlite3GlobalConfig.pcache2.xFetch(pCache->pCache, pgno, 2);
    +-  return *ppPage==0 ? SQLITE_NOMEM : SQLITE_OK;
    ++  return *ppPage==0 ? SQLITE_NOMEM_BKPT : SQLITE_OK;
    + }
    + 
    + /*
    +@@ -40783,11 +45642,11 @@ static SQLITE_NOINLINE PgHdr *pcacheFetchFinishWithInit(
    +   assert( pPage!=0 );
    +   pPgHdr = (PgHdr*)pPage->pExtra;
    +   assert( pPgHdr->pPage==0 );
    +-  memset(pPgHdr, 0, sizeof(PgHdr));
    ++  memset(&pPgHdr->pDirty, 0, sizeof(PgHdr) - offsetof(PgHdr,pDirty));
    +   pPgHdr->pPage = pPage;
    +   pPgHdr->pData = pPage->pBuf;
    +   pPgHdr->pExtra = (void *)&pPgHdr[1];
    +-  memset(pPgHdr->pExtra, 0, pCache->szExtra);
    ++  memset(pPgHdr->pExtra, 0, 8);
    +   pPgHdr->pCache = pCache;
    +   pPgHdr->pgno = pgno;
    +   pPgHdr->flags = PGHDR_CLEAN;
    +@@ -40815,6 +45674,7 @@ SQLITE_PRIVATE PgHdr *sqlite3PcacheFetchFinish(
    +   }
    +   pCache->nRefSum++;
    +   pPgHdr->nRef++;
    ++  assert( sqlite3PcachePageSanity(pPgHdr) );
    +   return pPgHdr;
    + }
    + 
    +@@ -40828,8 +45688,7 @@ SQLITE_PRIVATE void SQLITE_NOINLINE sqlite3PcacheRelease(PgHdr *p){
    +   if( (--p->nRef)==0 ){
    +     if( p->flags&PGHDR_CLEAN ){
    +       pcacheUnpin(p);
    +-    }else if( p->pDirtyPrev!=0 ){
    +-      /* Move the page to the head of the dirty list. */
    ++    }else{
    +       pcacheManageDirtyList(p, PCACHE_DIRTYLIST_FRONT);
    +     }
    +   }
    +@@ -40840,6 +45699,7 @@ SQLITE_PRIVATE void SQLITE_NOINLINE sqlite3PcacheRelease(PgHdr *p){
    + */
    + SQLITE_PRIVATE void sqlite3PcacheRef(PgHdr *p){
    +   assert(p->nRef>0);
    ++  assert( sqlite3PcachePageSanity(p) );
    +   p->nRef++;
    +   p->pCache->nRefSum++;
    + }
    +@@ -40851,6 +45711,7 @@ SQLITE_PRIVATE void sqlite3PcacheRef(PgHdr *p){
    + */
    + SQLITE_PRIVATE void sqlite3PcacheDrop(PgHdr *p){
    +   assert( p->nRef==1 );
    ++  assert( sqlite3PcachePageSanity(p) );
    +   if( p->flags&PGHDR_DIRTY ){
    +     pcacheManageDirtyList(p, PCACHE_DIRTYLIST_REMOVE);
    +   }
    +@@ -40864,13 +45725,16 @@ SQLITE_PRIVATE void sqlite3PcacheDrop(PgHdr *p){
    + */
    + SQLITE_PRIVATE void sqlite3PcacheMakeDirty(PgHdr *p){
    +   assert( p->nRef>0 );
    +-  if( p->flags & (PGHDR_CLEAN|PGHDR_DONT_WRITE) ){
    ++  assert( sqlite3PcachePageSanity(p) );
    ++  if( p->flags & (PGHDR_CLEAN|PGHDR_DONT_WRITE) ){    /*OPTIMIZATION-IF-FALSE*/
    +     p->flags &= ~PGHDR_DONT_WRITE;
    +     if( p->flags & PGHDR_CLEAN ){
    +       p->flags ^= (PGHDR_DIRTY|PGHDR_CLEAN);
    ++      pcacheTrace(("%p.DIRTY %d\n",p->pCache,p->pgno));
    +       assert( (p->flags & (PGHDR_DIRTY|PGHDR_CLEAN))==PGHDR_DIRTY );
    +       pcacheManageDirtyList(p, PCACHE_DIRTYLIST_ADD);
    +     }
    ++    assert( sqlite3PcachePageSanity(p) );
    +   }
    + }
    + 
    +@@ -40879,14 +45743,16 @@ SQLITE_PRIVATE void sqlite3PcacheMakeDirty(PgHdr *p){
    + ** make it so.
    + */
    + SQLITE_PRIVATE void sqlite3PcacheMakeClean(PgHdr *p){
    +-  if( (p->flags & PGHDR_DIRTY) ){
    +-    assert( (p->flags & PGHDR_CLEAN)==0 );
    +-    pcacheManageDirtyList(p, PCACHE_DIRTYLIST_REMOVE);
    +-    p->flags &= ~(PGHDR_DIRTY|PGHDR_NEED_SYNC|PGHDR_WRITEABLE);
    +-    p->flags |= PGHDR_CLEAN;
    +-    if( p->nRef==0 ){
    +-      pcacheUnpin(p);
    +-    }
    ++  assert( sqlite3PcachePageSanity(p) );
    ++  assert( (p->flags & PGHDR_DIRTY)!=0 );
    ++  assert( (p->flags & PGHDR_CLEAN)==0 );
    ++  pcacheManageDirtyList(p, PCACHE_DIRTYLIST_REMOVE);
    ++  p->flags &= ~(PGHDR_DIRTY|PGHDR_NEED_SYNC|PGHDR_WRITEABLE);
    ++  p->flags |= PGHDR_CLEAN;
    ++  pcacheTrace(("%p.CLEAN %d\n",p->pCache,p->pgno));
    ++  assert( sqlite3PcachePageSanity(p) );
    ++  if( p->nRef==0 ){
    ++    pcacheUnpin(p);
    +   }
    + }
    + 
    +@@ -40895,11 +45761,24 @@ SQLITE_PRIVATE void sqlite3PcacheMakeClean(PgHdr *p){
    + */
    + SQLITE_PRIVATE void sqlite3PcacheCleanAll(PCache *pCache){
    +   PgHdr *p;
    ++  pcacheTrace(("%p.CLEAN-ALL\n",pCache));
    +   while( (p = pCache->pDirty)!=0 ){
    +     sqlite3PcacheMakeClean(p);
    +   }
    + }
    + 
    ++/*
    ++** Clear the PGHDR_NEED_SYNC and PGHDR_WRITEABLE flag from all dirty pages.
    ++*/
    ++SQLITE_PRIVATE void sqlite3PcacheClearWritable(PCache *pCache){
    ++  PgHdr *p;
    ++  pcacheTrace(("%p.CLEAR-WRITEABLE\n",pCache));
    ++  for(p=pCache->pDirty; p; p=p->pDirtyNext){
    ++    p->flags &= ~(PGHDR_NEED_SYNC|PGHDR_WRITEABLE);
    ++  }
    ++  pCache->pSynced = pCache->pDirtyTail;
    ++}
    ++
    + /*
    + ** Clear the PGHDR_NEED_SYNC flag from all dirty pages.
    + */
    +@@ -40918,6 +45797,8 @@ SQLITE_PRIVATE void sqlite3PcacheMove(PgHdr *p, Pgno newPgno){
    +   PCache *pCache = p->pCache;
    +   assert( p->nRef>0 );
    +   assert( newPgno>0 );
    ++  assert( sqlite3PcachePageSanity(p) );
    ++  pcacheTrace(("%p.MOVE %d -> %d\n",pCache,p->pgno,newPgno));
    +   sqlite3GlobalConfig.pcache2.xRekey(pCache->pCache, p->pPage, p->pgno,newPgno);
    +   p->pgno = newPgno;
    +   if( (p->flags&PGHDR_DIRTY) && (p->flags&PGHDR_NEED_SYNC) ){
    +@@ -40938,6 +45819,7 @@ SQLITE_PRIVATE void sqlite3PcacheTruncate(PCache *pCache, Pgno pgno){
    +   if( pCache->pCache ){
    +     PgHdr *p;
    +     PgHdr *pNext;
    ++    pcacheTrace(("%p.TRUNCATE %d\n",pCache,pgno));
    +     for(p=pCache->pDirty; p; p=pNext){
    +       pNext = p->pDirtyNext;
    +       /* This routine never gets call with a positive pgno except right
    +@@ -40945,7 +45827,7 @@ SQLITE_PRIVATE void sqlite3PcacheTruncate(PCache *pCache, Pgno pgno){
    +       ** it must be that pgno==0.
    +       */
    +       assert( p->pgno>0 );
    +-      if( ALWAYS(p->pgno>pgno) ){
    ++      if( p->pgno>pgno ){
    +         assert( p->flags&PGHDR_DIRTY );
    +         sqlite3PcacheMakeClean(p);
    +       }
    +@@ -40968,6 +45850,7 @@ SQLITE_PRIVATE void sqlite3PcacheTruncate(PCache *pCache, Pgno pgno){
    + */
    + SQLITE_PRIVATE void sqlite3PcacheClose(PCache *pCache){
    +   assert( pCache->pCache!=0 );
    ++  pcacheTrace(("%p.CLOSE\n",pCache));
    +   sqlite3GlobalConfig.pcache2.xDestroy(pCache->pCache);
    + }
    + 
    +@@ -40980,29 +45863,31 @@ SQLITE_PRIVATE void sqlite3PcacheClear(PCache *pCache){
    + 
    + /*
    + ** Merge two lists of pages connected by pDirty and in pgno order.
    +-** Do not both fixing the pDirtyPrev pointers.
    ++** Do not bother fixing the pDirtyPrev pointers.
    + */
    + static PgHdr *pcacheMergeDirtyList(PgHdr *pA, PgHdr *pB){
    +   PgHdr result, *pTail;
    +   pTail = &result;
    +-  while( pA && pB ){
    ++  assert( pA!=0 && pB!=0 );
    ++  for(;;){
    +     if( pA->pgno<pB->pgno ){
    +       pTail->pDirty = pA;
    +       pTail = pA;
    +       pA = pA->pDirty;
    ++      if( pA==0 ){
    ++        pTail->pDirty = pB;
    ++        break;
    ++      }
    +     }else{
    +       pTail->pDirty = pB;
    +       pTail = pB;
    +       pB = pB->pDirty;
    ++      if( pB==0 ){
    ++        pTail->pDirty = pA;
    ++        break;
    ++      }
    +     }
    +   }
    +-  if( pA ){
    +-    pTail->pDirty = pA;
    +-  }else if( pB ){
    +-    pTail->pDirty = pB;
    +-  }else{
    +-    pTail->pDirty = 0;
    +-  }
    +   return result.pDirty;
    + }
    + 
    +@@ -41043,7 +45928,8 @@ static PgHdr *pcacheSortDirtyList(PgHdr *pIn){
    +   }
    +   p = a[0];
    +   for(i=1; i<N_SORT_BUCKET; i++){
    +-    p = pcacheMergeDirtyList(p, a[i]);
    ++    if( a[i]==0 ) continue;
    ++    p = p ? pcacheMergeDirtyList(p, a[i]) : a[i];
    +   }
    +   return p;
    + }
    +@@ -41103,6 +45989,25 @@ SQLITE_PRIVATE void sqlite3PcacheSetCachesize(PCache *pCache, int mxPage){
    +                                          numberOfCachePages(pCache));
    + }
    + 
    ++/*
    ++** Set the suggested cache-spill value.  Make no changes if if the
    ++** argument is zero.  Return the effective cache-spill size, which will
    ++** be the larger of the szSpill and szCache.
    ++*/
    ++SQLITE_PRIVATE int sqlite3PcacheSetSpillsize(PCache *p, int mxPage){
    ++  int res;
    ++  assert( p->pCache!=0 );
    ++  if( mxPage ){
    ++    if( mxPage<0 ){
    ++      mxPage = (int)((-1024*(i64)mxPage)/(p->szPage+p->szExtra));
    ++    }
    ++    p->szSpill = mxPage;
    ++  }
    ++  res = numberOfCachePages(p);
    ++  if( res<p->szSpill ) res = p->szSpill; 
    ++  return res;
    ++}
    ++
    + /*
    + ** Free up as much memory as possible from the page cache.
    + */
    +@@ -41117,6 +46022,17 @@ SQLITE_PRIVATE void sqlite3PcacheShrink(PCache *pCache){
    + */
    + SQLITE_PRIVATE int sqlite3HeaderSizePcache(void){ return ROUND8(sizeof(PgHdr)); }
    + 
    ++/*
    ++** Return the number of dirty pages currently in the cache, as a percentage
    ++** of the configured cache size.
    ++*/
    ++SQLITE_PRIVATE int sqlite3PCachePercentDirty(PCache *pCache){
    ++  PgHdr *pDirty;
    ++  int nDirty = 0;
    ++  int nCache = numberOfCachePages(pCache);
    ++  for(pDirty=pCache->pDirty; pDirty; pDirty=pDirty->pDirtyNext) nDirty++;
    ++  return nCache ? (int)(((i64)nDirty * 100) / nCache) : 0;
    ++}
    + 
    + #if defined(SQLITE_CHECK_PAGES) || defined(SQLITE_DEBUG)
    + /*
    +@@ -41201,7 +46117,7 @@ SQLITE_PRIVATE void sqlite3PcacheIterateDirty(PCache *pCache, void (*xIter)(PgHd
    + ** that is allocated when the page cache is created.  The size of the local
    + ** bulk allocation can be adjusted using 
    + **
    +-**     sqlite3_config(SQLITE_CONFIG_PAGECACHE, 0, 0, N).
    ++**     sqlite3_config(SQLITE_CONFIG_PAGECACHE, (void*)0, 0, N).
    + **
    + ** If N is positive, then N pages worth of memory are allocated using a single
    + ** sqlite3Malloc() call and that memory is used for the first N pages allocated.
    +@@ -41232,7 +46148,6 @@ typedef struct PGroup PGroup;
    + struct PgHdr1 {
    +   sqlite3_pcache_page page;      /* Base class. Must be first. pBuf & pExtra */
    +   unsigned int iKey;             /* Key value (page number) */
    +-  u8 isPinned;                   /* Page in use, not on the LRU list */
    +   u8 isBulkLocal;                /* This page from bulk local storage */
    +   u8 isAnchor;                   /* This is the PGroup.lru element */
    +   PgHdr1 *pNext;                 /* Next in hash table chain */
    +@@ -41241,6 +46156,12 @@ struct PgHdr1 {
    +   PgHdr1 *pLruPrev;              /* Previous in LRU list of unpinned pages */
    + };
    + 
    ++/*
    ++** A page is pinned if it is no on the LRU list
    ++*/
    ++#define PAGE_IS_PINNED(p)    ((p)->pLruNext==0)
    ++#define PAGE_IS_UNPINNED(p)  ((p)->pLruNext!=0)
    ++
    + /* Each page cache (or PCache) belongs to a PGroup.  A PGroup is a set 
    + ** of one or more PCaches that are able to recycle each other's unpinned
    + ** pages when they are under memory pressure.  A PGroup is an instance of
    +@@ -41268,7 +46189,7 @@ struct PGroup {
    +   unsigned int nMaxPage;         /* Sum of nMax for purgeable caches */
    +   unsigned int nMinPage;         /* Sum of nMin for purgeable caches */
    +   unsigned int mxPinned;         /* nMaxpage + 10 - nMinPage */
    +-  unsigned int nCurrentPage;     /* Number of purgeable pages allocated */
    ++  unsigned int nPurgeable;       /* Number of purgeable pages allocated */
    +   PgHdr1 lru;                    /* The beginning and end of the LRU list */
    + };
    + 
    +@@ -41282,11 +46203,13 @@ struct PGroup {
    + */
    + struct PCache1 {
    +   /* Cache configuration parameters. Page size (szPage) and the purgeable
    +-  ** flag (bPurgeable) are set when the cache is created. nMax may be 
    ++  ** flag (bPurgeable) and the pnPurgeable pointer are all set when the
    ++  ** cache is created and are never changed thereafter. nMax may be 
    +   ** modified at any time by a call to the pcache1Cachesize() method.
    +   ** The PGroup mutex must be held when accessing nMax.
    +   */
    +   PGroup *pGroup;                     /* PGroup this cache belongs to */
    ++  unsigned int *pnPurgeable;          /* Pointer to pGroup->nPurgeable */
    +   int szPage;                         /* Size of database content section */
    +   int szExtra;                        /* sizeof(MemPage)+sizeof(PgHdr) */
    +   int szAlloc;                        /* Total size of one pcache line */
    +@@ -41381,6 +46304,7 @@ SQLITE_PRIVATE void sqlite3PCacheBufferSetup(void *pBuf, int sz, int n){
    +   if( pcache1.isInit ){
    +     PgFreeslot *p;
    +     if( pBuf==0 ) sz = n = 0;
    ++    if( n==0 ) sz = 0;
    +     sz = ROUNDDOWN8(sz);
    +     pcache1.szSlot = sz;
    +     pcache1.nSlot = pcache1.nFreeSlot = n;
    +@@ -41415,14 +46339,13 @@ static int pcache1InitBulk(PCache1 *pCache){
    +     szBulk = -1024 * (i64)pcache1.nInitPage;
    +   }
    +   if( szBulk > pCache->szAlloc*(i64)pCache->nMax ){
    +-    szBulk = pCache->szAlloc*pCache->nMax;
    ++    szBulk = pCache->szAlloc*(i64)pCache->nMax;
    +   }
    +   zBulk = pCache->pBulk = sqlite3Malloc( szBulk );
    +   sqlite3EndBenignMalloc();
    +   if( zBulk ){
    +     int nBulk = sqlite3MallocSize(zBulk)/pCache->szAlloc;
    +-    int i;
    +-    for(i=0; i<nBulk; i++){
    ++    do{
    +       PgHdr1 *pX = (PgHdr1*)&zBulk[pCache->szPage];
    +       pX->page.pBuf = zBulk;
    +       pX->page.pExtra = &pX[1];
    +@@ -41431,7 +46354,7 @@ static int pcache1InitBulk(PCache1 *pCache){
    +       pX->pNext = pCache->pFree;
    +       pCache->pFree = pX;
    +       zBulk += pCache->szAlloc;
    +-    }
    ++    }while( --nBulk );
    +   }
    +   return pCache->pFree!=0;
    + }
    +@@ -41456,7 +46379,7 @@ static void *pcache1Alloc(int nByte){
    +       pcache1.nFreeSlot--;
    +       pcache1.bUnderPressure = pcache1.nFreeSlot<pcache1.nReserve;
    +       assert( pcache1.nFreeSlot>=0 );
    +-      sqlite3StatusSet(SQLITE_STATUS_PAGECACHE_SIZE, nByte);
    ++      sqlite3StatusHighwater(SQLITE_STATUS_PAGECACHE_SIZE, nByte);
    +       sqlite3StatusUp(SQLITE_STATUS_PAGECACHE_USED, 1);
    +     }
    +     sqlite3_mutex_leave(pcache1.mutex);
    +@@ -41470,7 +46393,7 @@ static void *pcache1Alloc(int nByte){
    +     if( p ){
    +       int sz = sqlite3MallocSize(p);
    +       sqlite3_mutex_enter(pcache1.mutex);
    +-      sqlite3StatusSet(SQLITE_STATUS_PAGECACHE_SIZE, nByte);
    ++      sqlite3StatusHighwater(SQLITE_STATUS_PAGECACHE_SIZE, nByte);
    +       sqlite3StatusUp(SQLITE_STATUS_PAGECACHE_OVERFLOW, sz);
    +       sqlite3_mutex_leave(pcache1.mutex);
    +     }
    +@@ -41484,9 +46407,8 @@ static void *pcache1Alloc(int nByte){
    + ** Free an allocated buffer obtained from pcache1Alloc().
    + */
    + static void pcache1Free(void *p){
    +-  int nFreed = 0;
    +   if( p==0 ) return;
    +-  if( p>=pcache1.pStart && p<pcache1.pEnd ){
    ++  if( SQLITE_WITHIN(p, pcache1.pStart, pcache1.pEnd) ){
    +     PgFreeslot *pSlot;
    +     sqlite3_mutex_enter(pcache1.mutex);
    +     sqlite3StatusDown(SQLITE_STATUS_PAGECACHE_USED, 1);
    +@@ -41501,10 +46423,13 @@ static void pcache1Free(void *p){
    +     assert( sqlite3MemdebugHasType(p, MEMTYPE_PCACHE) );
    +     sqlite3MemdebugSetType(p, MEMTYPE_HEAP);
    + #ifndef SQLITE_DISABLE_PAGECACHE_OVERFLOW_STATS
    +-    nFreed = sqlite3MallocSize(p);
    +-    sqlite3_mutex_enter(pcache1.mutex);
    +-    sqlite3StatusDown(SQLITE_STATUS_PAGECACHE_OVERFLOW, nFreed);
    +-    sqlite3_mutex_leave(pcache1.mutex);
    ++    {
    ++      int nFreed = 0;
    ++      nFreed = sqlite3MallocSize(p);
    ++      sqlite3_mutex_enter(pcache1.mutex);
    ++      sqlite3StatusDown(SQLITE_STATUS_PAGECACHE_OVERFLOW, nFreed);
    ++      sqlite3_mutex_leave(pcache1.mutex);
    ++    }
    + #endif
    +     sqlite3_free(p);
    +   }
    +@@ -41572,9 +46497,7 @@ static PgHdr1 *pcache1AllocPage(PCache1 *pCache, int benignMalloc){
    +     p->isBulkLocal = 0;
    +     p->isAnchor = 0;
    +   }
    +-  if( pCache->bPurgeable ){
    +-    pCache->pGroup->nCurrentPage++;
    +-  }
    ++  (*pCache->pnPurgeable)++;
    +   return p;
    + }
    + 
    +@@ -41595,9 +46518,7 @@ static void pcache1FreePage(PgHdr1 *p){
    +     sqlite3_free(p);
    + #endif
    +   }
    +-  if( pCache->bPurgeable ){
    +-    pCache->pGroup->nCurrentPage--;
    +-  }
    ++  (*pCache->pnPurgeable)--;
    + }
    + 
    + /*
    +@@ -41692,22 +46613,18 @@ static void pcache1ResizeHash(PCache1 *p){
    + ** The PGroup mutex must be held when this function is called.
    + */
    + static PgHdr1 *pcache1PinPage(PgHdr1 *pPage){
    +-  PCache1 *pCache;
    +-
    +   assert( pPage!=0 );
    +-  assert( pPage->isPinned==0 );
    +-  pCache = pPage->pCache;
    ++  assert( PAGE_IS_UNPINNED(pPage) );
    +   assert( pPage->pLruNext );
    +   assert( pPage->pLruPrev );
    +-  assert( sqlite3_mutex_held(pCache->pGroup->mutex) );
    ++  assert( sqlite3_mutex_held(pPage->pCache->pGroup->mutex) );
    +   pPage->pLruPrev->pLruNext = pPage->pLruNext;
    +   pPage->pLruNext->pLruPrev = pPage->pLruPrev;
    +   pPage->pLruNext = 0;
    +   pPage->pLruPrev = 0;
    +-  pPage->isPinned = 1;
    +   assert( pPage->isAnchor==0 );
    +-  assert( pCache->pGroup->lru.isAnchor==1 );
    +-  pCache->nRecyclable--;
    ++  assert( pPage->pCache->pGroup->lru.isAnchor==1 );
    ++  pPage->pCache->nRecyclable--;
    +   return pPage;
    + }
    + 
    +@@ -41741,11 +46658,11 @@ static void pcache1EnforceMaxPage(PCache1 *pCache){
    +   PGroup *pGroup = pCache->pGroup;
    +   PgHdr1 *p;
    +   assert( sqlite3_mutex_held(pGroup->mutex) );
    +-  while( pGroup->nCurrentPage>pGroup->nMaxPage
    ++  while( pGroup->nPurgeable>pGroup->nMaxPage
    +       && (p=pGroup->lru.pLruPrev)->isAnchor==0
    +   ){
    +     assert( p->pCache->pGroup==pGroup );
    +-    assert( p->isPinned==0 );
    ++    assert( PAGE_IS_UNPINNED(p) );
    +     pcache1PinPage(p);
    +     pcache1RemoveFromHash(p, 1);
    +   }
    +@@ -41766,25 +46683,45 @@ static void pcache1TruncateUnsafe(
    +   PCache1 *pCache,             /* The cache to truncate */
    +   unsigned int iLimit          /* Drop pages with this pgno or larger */
    + ){
    +-  TESTONLY( unsigned int nPage = 0; )  /* To assert pCache->nPage is correct */
    +-  unsigned int h;
    ++  TESTONLY( int nPage = 0; )  /* To assert pCache->nPage is correct */
    ++  unsigned int h, iStop;
    +   assert( sqlite3_mutex_held(pCache->pGroup->mutex) );
    +-  for(h=0; h<pCache->nHash; h++){
    +-    PgHdr1 **pp = &pCache->apHash[h]; 
    ++  assert( pCache->iMaxKey >= iLimit );
    ++  assert( pCache->nHash > 0 );
    ++  if( pCache->iMaxKey - iLimit < pCache->nHash ){
    ++    /* If we are just shaving the last few pages off the end of the
    ++    ** cache, then there is no point in scanning the entire hash table.
    ++    ** Only scan those hash slots that might contain pages that need to
    ++    ** be removed. */
    ++    h = iLimit % pCache->nHash;
    ++    iStop = pCache->iMaxKey % pCache->nHash;
    ++    TESTONLY( nPage = -10; )  /* Disable the pCache->nPage validity check */
    ++  }else{
    ++    /* This is the general case where many pages are being removed.
    ++    ** It is necessary to scan the entire hash table */
    ++    h = pCache->nHash/2;
    ++    iStop = h - 1;
    ++  }
    ++  for(;;){
    ++    PgHdr1 **pp;
    +     PgHdr1 *pPage;
    ++    assert( h<pCache->nHash );
    ++    pp = &pCache->apHash[h]; 
    +     while( (pPage = *pp)!=0 ){
    +       if( pPage->iKey>=iLimit ){
    +         pCache->nPage--;
    +         *pp = pPage->pNext;
    +-        if( !pPage->isPinned ) pcache1PinPage(pPage);
    ++        if( PAGE_IS_UNPINNED(pPage) ) pcache1PinPage(pPage);
    +         pcache1FreePage(pPage);
    +       }else{
    +         pp = &pPage->pNext;
    +-        TESTONLY( nPage++; )
    ++        TESTONLY( if( nPage>=0 ) nPage++; )
    +       }
    +     }
    ++    if( h==iStop ) break;
    ++    h = (h+1) % pCache->nHash;
    +   }
    +-  assert( pCache->nPage==nPage );
    ++  assert( nPage<0 || pCache->nPage==(unsigned)nPage );
    + }
    + 
    + /******************************************************************************/
    +@@ -41824,8 +46761,8 @@ static int pcache1Init(void *NotUsed){
    + 
    + #if SQLITE_THREADSAFE
    +   if( sqlite3GlobalConfig.bCoreMutex ){
    +-    pcache1.grp.mutex = sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_LRU);
    +-    pcache1.mutex = sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_PMEM);
    ++    pcache1.grp.mutex = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_LRU);
    ++    pcache1.mutex = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_PMEM);
    +   }
    + #endif
    +   if( pcache1.separateCache
    +@@ -41892,6 +46829,10 @@ static sqlite3_pcache *pcache1Create(int szPage, int szExtra, int bPurgeable){
    +       pCache->nMin = 10;
    +       pGroup->nMinPage += pCache->nMin;
    +       pGroup->mxPinned = pGroup->nMaxPage + 10 - pGroup->nMinPage;
    ++      pCache->pnPurgeable = &pGroup->nPurgeable;
    ++    }else{
    ++      static unsigned int dummyCurrentPage;
    ++      pCache->pnPurgeable = &dummyCurrentPage;
    +     }
    +     pcache1LeaveMutex(pGroup);
    +     if( pCache->nHash==0 ){
    +@@ -41993,7 +46934,7 @@ static SQLITE_NOINLINE PgHdr1 *pcache1FetchStage2(
    +   ){
    +     PCache1 *pOther;
    +     pPage = pGroup->lru.pLruPrev;
    +-    assert( pPage->isPinned==0 );
    ++    assert( PAGE_IS_UNPINNED(pPage) );
    +     pcache1RemoveFromHash(pPage, 0);
    +     pcache1PinPage(pPage);
    +     pOther = pPage->pCache;
    +@@ -42001,7 +46942,7 @@ static SQLITE_NOINLINE PgHdr1 *pcache1FetchStage2(
    +       pcache1FreePage(pPage);
    +       pPage = 0;
    +     }else{
    +-      pGroup->nCurrentPage -= (pOther->bPurgeable - pCache->bPurgeable);
    ++      pGroup->nPurgeable -= (pOther->bPurgeable - pCache->bPurgeable);
    +     }
    +   }
    + 
    +@@ -42020,7 +46961,6 @@ static SQLITE_NOINLINE PgHdr1 *pcache1FetchStage2(
    +     pPage->pCache = pCache;
    +     pPage->pLruPrev = 0;
    +     pPage->pLruNext = 0;
    +-    pPage->isPinned = 1;
    +     *(void **)pPage->page.pExtra = 0;
    +     pCache->apHash[h] = pPage;
    +     if( iKey>pCache->iMaxKey ){
    +@@ -42106,7 +47046,7 @@ static PgHdr1 *pcache1FetchNoMutex(
    +   ** Otherwise (page not in hash and createFlag!=0) continue with
    +   ** subsequent steps to try to create the page. */
    +   if( pPage ){
    +-    if( !pPage->isPinned ){
    ++    if( PAGE_IS_UNPINNED(pPage) ){
    +       return pcache1PinPage(pPage);
    +     }else{
    +       return pPage;
    +@@ -42181,9 +47121,9 @@ static void pcache1Unpin(
    +   ** part of the PGroup LRU list.
    +   */
    +   assert( pPage->pLruPrev==0 && pPage->pLruNext==0 );
    +-  assert( pPage->isPinned==1 );
    ++  assert( PAGE_IS_PINNED(pPage) );
    + 
    +-  if( reuseUnlikely || pGroup->nCurrentPage>pGroup->nMaxPage ){
    ++  if( reuseUnlikely || pGroup->nPurgeable>pGroup->nMaxPage ){
    +     pcache1RemoveFromHash(pPage, 1);
    +   }else{
    +     /* Add the page to the PGroup LRU list. */
    +@@ -42192,7 +47132,6 @@ static void pcache1Unpin(
    +     (pPage->pLruNext = *ppFirst)->pLruPrev = pPage;
    +     *ppFirst = pPage;
    +     pCache->nRecyclable++;
    +-    pPage->isPinned = 0;
    +   }
    + 
    +   pcache1LeaveMutex(pCache->pGroup);
    +@@ -42261,7 +47200,7 @@ static void pcache1Destroy(sqlite3_pcache *p){
    +   PGroup *pGroup = pCache->pGroup;
    +   assert( pCache->bPurgeable || (pCache->nMax==0 && pCache->nMin==0) );
    +   pcache1EnterMutex(pGroup);
    +-  pcache1TruncateUnsafe(pCache, 0);
    ++  if( pCache->nPage ) pcache1TruncateUnsafe(pCache, 0);
    +   assert( pGroup->nMaxPage >= pCache->nMax );
    +   pGroup->nMaxPage -= pCache->nMax;
    +   assert( pGroup->nMinPage >= pCache->nMin );
    +@@ -42325,7 +47264,7 @@ SQLITE_PRIVATE int sqlite3PcacheReleaseMemory(int nReq){
    +   int nFree = 0;
    +   assert( sqlite3_mutex_notheld(pcache1.grp.mutex) );
    +   assert( sqlite3_mutex_notheld(pcache1.mutex) );
    +-  if( sqlite3GlobalConfig.nPage==0 ){
    ++  if( sqlite3GlobalConfig.pPage==0 ){
    +     PgHdr1 *p;
    +     pcache1EnterMutex(&pcache1.grp);
    +     while( (nReq<0 || nFree<nReq)
    +@@ -42336,7 +47275,7 @@ SQLITE_PRIVATE int sqlite3PcacheReleaseMemory(int nReq){
    + #ifdef SQLITE_PCACHE_SEPARATE_HEADER
    +       nFree += sqlite3MemSize(p);
    + #endif
    +-      assert( p->isPinned==0 );
    ++      assert( PAGE_IS_UNPINNED(p) );
    +       pcache1PinPage(p);
    +       pcache1RemoveFromHash(p, 1);
    +     }
    +@@ -42360,10 +47299,10 @@ SQLITE_PRIVATE void sqlite3PcacheStats(
    +   PgHdr1 *p;
    +   int nRecyclable = 0;
    +   for(p=pcache1.grp.lru.pLruNext; p && !p->isAnchor; p=p->pLruNext){
    +-    assert( p->isPinned==0 );
    ++    assert( PAGE_IS_UNPINNED(p) );
    +     nRecyclable++;
    +   }
    +-  *pnCurrent = pcache1.grp.nCurrentPage;
    ++  *pnCurrent = pcache1.grp.nPurgeable;
    +   *pnMax = (int)pcache1.grp.nMaxPage;
    +   *pnMin = (int)pcache1.grp.nMinPage;
    +   *pnRecyclable = nRecyclable;
    +@@ -42431,8 +47370,9 @@ SQLITE_PRIVATE void sqlite3PcacheStats(
    + ** of the first SMALLEST is O(NlogN).  Second and subsequent SMALLEST
    + ** primitives are constant time.  The cost of DESTROY is O(N).
    + **
    +-** There is an added cost of O(N) when switching between TEST and
    +-** SMALLEST primitives.
    ++** TEST and SMALLEST may not be used by the same RowSet.  This used to
    ++** be possible, but the feature was not used, so it was removed in order
    ++** to simplify the code.
    + */
    + /* #include "sqliteInt.h" */
    + 
    +@@ -42553,9 +47493,11 @@ SQLITE_PRIVATE void sqlite3RowSetClear(RowSet *p){
    + */
    + static struct RowSetEntry *rowSetEntryAlloc(RowSet *p){
    +   assert( p!=0 );
    +-  if( p->nFresh==0 ){
    ++  if( p->nFresh==0 ){  /*OPTIMIZATION-IF-FALSE*/
    ++    /* We could allocate a fresh RowSetEntry each time one is needed, but it
    ++    ** is more efficient to pull a preallocated entry from the pool */
    +     struct RowSetChunk *pNew;
    +-    pNew = sqlite3DbMallocRaw(p->db, sizeof(*pNew));
    ++    pNew = sqlite3DbMallocRawNN(p->db, sizeof(*pNew));
    +     if( pNew==0 ){
    +       return 0;
    +     }
    +@@ -42587,7 +47529,9 @@ SQLITE_PRIVATE void sqlite3RowSetInsert(RowSet *p, i64 rowid){
    +   pEntry->pRight = 0;
    +   pLast = p->pLast;
    +   if( pLast ){
    +-    if( (p->rsFlags & ROWSET_SORTED)!=0 && rowid<=pLast->v ){
    ++    if( rowid<=pLast->v ){  /*OPTIMIZATION-IF-FALSE*/
    ++      /* Avoid unnecessary sorts by preserving the ROWSET_SORTED flags
    ++      ** where possible */
    +       p->rsFlags &= ~ROWSET_SORTED;
    +     }
    +     pLast->pRight = pEntry;
    +@@ -42611,28 +47555,26 @@ static struct RowSetEntry *rowSetEntryMerge(
    +   struct RowSetEntry *pTail;
    + 
    +   pTail = &head;
    +-  while( pA && pB ){
    ++  assert( pA!=0 && pB!=0 );
    ++  for(;;){
    +     assert( pA->pRight==0 || pA->v<=pA->pRight->v );
    +     assert( pB->pRight==0 || pB->v<=pB->pRight->v );
    +-    if( pA->v<pB->v ){
    +-      pTail->pRight = pA;
    ++    if( pA->v<=pB->v ){
    ++      if( pA->v<pB->v ) pTail = pTail->pRight = pA;
    +       pA = pA->pRight;
    +-      pTail = pTail->pRight;
    +-    }else if( pB->v<pA->v ){
    +-      pTail->pRight = pB;
    +-      pB = pB->pRight;
    +-      pTail = pTail->pRight;
    ++      if( pA==0 ){
    ++        pTail->pRight = pB;
    ++        break;
    ++      }
    +     }else{
    +-      pA = pA->pRight;
    ++      pTail = pTail->pRight = pB;
    ++      pB = pB->pRight;
    ++      if( pB==0 ){
    ++        pTail->pRight = pA;
    ++        break;
    ++      }
    +     }
    +   }
    +-  if( pA ){
    +-    assert( pA->pRight==0 || pA->v<=pA->pRight->v );
    +-    pTail->pRight = pA;
    +-  }else{
    +-    assert( pB==0 || pB->pRight==0 || pB->v<=pB->pRight->v );
    +-    pTail->pRight = pB;
    +-  }
    +   return head.pRight;
    + }
    + 
    +@@ -42655,9 +47597,10 @@ static struct RowSetEntry *rowSetEntrySort(struct RowSetEntry *pIn){
    +     aBucket[i] = pIn;
    +     pIn = pNext;
    +   }
    +-  pIn = 0;
    +-  for(i=0; i<sizeof(aBucket)/sizeof(aBucket[0]); i++){
    +-    pIn = rowSetEntryMerge(pIn, aBucket[i]);
    ++  pIn = aBucket[0];
    ++  for(i=1; i<sizeof(aBucket)/sizeof(aBucket[0]); i++){
    ++    if( aBucket[i]==0 ) continue;
    ++    pIn = pIn ? rowSetEntryMerge(pIn, aBucket[i]) : aBucket[i];
    +   }
    +   return pIn;
    + }
    +@@ -42709,23 +47652,29 @@ static struct RowSetEntry *rowSetNDeepTree(
    + ){
    +   struct RowSetEntry *p;         /* Root of the new tree */
    +   struct RowSetEntry *pLeft;     /* Left subtree */
    +-  if( *ppList==0 ){
    +-    return 0;
    +-  }
    +-  if( iDepth==1 ){
    ++  if( *ppList==0 ){ /*OPTIMIZATION-IF-TRUE*/
    ++    /* Prevent unnecessary deep recursion when we run out of entries */
    ++    return 0; 
    ++  }
    ++  if( iDepth>1 ){   /*OPTIMIZATION-IF-TRUE*/
    ++    /* This branch causes a *balanced* tree to be generated.  A valid tree
    ++    ** is still generated without this branch, but the tree is wildly
    ++    ** unbalanced and inefficient. */
    ++    pLeft = rowSetNDeepTree(ppList, iDepth-1);
    ++    p = *ppList;
    ++    if( p==0 ){     /*OPTIMIZATION-IF-FALSE*/
    ++      /* It is safe to always return here, but the resulting tree
    ++      ** would be unbalanced */
    ++      return pLeft;
    ++    }
    ++    p->pLeft = pLeft;
    ++    *ppList = p->pRight;
    ++    p->pRight = rowSetNDeepTree(ppList, iDepth-1);
    ++  }else{
    +     p = *ppList;
    +     *ppList = p->pRight;
    +     p->pLeft = p->pRight = 0;
    +-    return p;
    +-  }
    +-  pLeft = rowSetNDeepTree(ppList, iDepth-1);
    +-  p = *ppList;
    +-  if( p==0 ){
    +-    return pLeft;
    +   }
    +-  p->pLeft = pLeft;
    +-  *ppList = p->pRight;
    +-  p->pRight = rowSetNDeepTree(ppList, iDepth-1);
    +   return p;
    + }
    + 
    +@@ -42752,59 +47701,37 @@ static struct RowSetEntry *rowSetListToTree(struct RowSetEntry *pList){
    +   return p;
    + }
    + 
    +-/*
    +-** Take all the entries on p->pEntry and on the trees in p->pForest and
    +-** sort them all together into one big ordered list on p->pEntry.
    +-**
    +-** This routine should only be called once in the life of a RowSet.
    +-*/
    +-static void rowSetToList(RowSet *p){
    +-
    +-  /* This routine is called only once */
    +-  assert( p!=0 && (p->rsFlags & ROWSET_NEXT)==0 );
    +-
    +-  if( (p->rsFlags & ROWSET_SORTED)==0 ){
    +-    p->pEntry = rowSetEntrySort(p->pEntry);
    +-  }
    +-
    +-  /* While this module could theoretically support it, sqlite3RowSetNext()
    +-  ** is never called after sqlite3RowSetText() for the same RowSet.  So
    +-  ** there is never a forest to deal with.  Should this change, simply
    +-  ** remove the assert() and the #if 0. */
    +-  assert( p->pForest==0 );
    +-#if 0
    +-  while( p->pForest ){
    +-    struct RowSetEntry *pTree = p->pForest->pLeft;
    +-    if( pTree ){
    +-      struct RowSetEntry *pHead, *pTail;
    +-      rowSetTreeToList(pTree, &pHead, &pTail);
    +-      p->pEntry = rowSetEntryMerge(p->pEntry, pHead);
    +-    }
    +-    p->pForest = p->pForest->pRight;
    +-  }
    +-#endif
    +-  p->rsFlags |= ROWSET_NEXT;  /* Verify this routine is never called again */
    +-}
    +-
    + /*
    + ** Extract the smallest element from the RowSet.
    + ** Write the element into *pRowid.  Return 1 on success.  Return
    + ** 0 if the RowSet is already empty.
    + **
    + ** After this routine has been called, the sqlite3RowSetInsert()
    +-** routine may not be called again.  
    ++** routine may not be called again.
    ++**
    ++** This routine may not be called after sqlite3RowSetTest() has
    ++** been used.  Older versions of RowSet allowed that, but as the
    ++** capability was not used by the code generator, it was removed
    ++** for code economy.
    + */
    + SQLITE_PRIVATE int sqlite3RowSetNext(RowSet *p, i64 *pRowid){
    +   assert( p!=0 );
    ++  assert( p->pForest==0 );  /* Cannot be used with sqlite3RowSetText() */
    + 
    +   /* Merge the forest into a single sorted list on first call */
    +-  if( (p->rsFlags & ROWSET_NEXT)==0 ) rowSetToList(p);
    ++  if( (p->rsFlags & ROWSET_NEXT)==0 ){  /*OPTIMIZATION-IF-FALSE*/
    ++    if( (p->rsFlags & ROWSET_SORTED)==0 ){  /*OPTIMIZATION-IF-FALSE*/
    ++      p->pEntry = rowSetEntrySort(p->pEntry);
    ++    }
    ++    p->rsFlags |= ROWSET_SORTED|ROWSET_NEXT;
    ++  }
    + 
    +   /* Return the next entry on the list */
    +   if( p->pEntry ){
    +     *pRowid = p->pEntry->v;
    +     p->pEntry = p->pEntry->pRight;
    +-    if( p->pEntry==0 ){
    ++    if( p->pEntry==0 ){ /*OPTIMIZATION-IF-TRUE*/
    ++      /* Free memory immediately, rather than waiting on sqlite3_finalize() */
    +       sqlite3RowSetClear(p);
    +     }
    +     return 1;
    +@@ -42827,13 +47754,15 @@ SQLITE_PRIVATE int sqlite3RowSetTest(RowSet *pRowSet, int iBatch, sqlite3_int64
    +   /* This routine is never called after sqlite3RowSetNext() */
    +   assert( pRowSet!=0 && (pRowSet->rsFlags & ROWSET_NEXT)==0 );
    + 
    +-  /* Sort entries into the forest on the first test of a new batch 
    ++  /* Sort entries into the forest on the first test of a new batch.
    ++  ** To save unnecessary work, only do this when the batch number changes.
    +   */
    +-  if( iBatch!=pRowSet->iBatch ){
    ++  if( iBatch!=pRowSet->iBatch ){  /*OPTIMIZATION-IF-FALSE*/
    +     p = pRowSet->pEntry;
    +     if( p ){
    +       struct RowSetEntry **ppPrevTree = &pRowSet->pForest;
    +-      if( (pRowSet->rsFlags & ROWSET_SORTED)==0 ){
    ++      if( (pRowSet->rsFlags & ROWSET_SORTED)==0 ){ /*OPTIMIZATION-IF-FALSE*/
    ++        /* Only sort the current set of entiries if they need it */
    +         p = rowSetEntrySort(p);
    +       }
    +       for(pTree = pRowSet->pForest; pTree; pTree=pTree->pRight){
    +@@ -42923,21 +47852,21 @@ SQLITE_PRIVATE int sqlite3RowSetTest(RowSet *pRowSet, int iBatch, sqlite3_int64
    + ** the implementation of each function in log.c for further details.
    + */
    + 
    +-#ifndef _WAL_H_
    +-#define _WAL_H_
    ++#ifndef SQLITE_WAL_H
    ++#define SQLITE_WAL_H
    + 
    + /* #include "sqliteInt.h" */
    + 
    +-/* Additional values that can be added to the sync_flags argument of
    +-** sqlite3WalFrames():
    ++/* Macros for extracting appropriate sync flags for either transaction
    ++** commits (WAL_SYNC_FLAGS(X)) or for checkpoint ops (CKPT_SYNC_FLAGS(X)):
    + */
    +-#define WAL_SYNC_TRANSACTIONS  0x20   /* Sync at the end of each transaction */
    +-#define SQLITE_SYNC_MASK       0x13   /* Mask off the SQLITE_SYNC_* values */
    ++#define WAL_SYNC_FLAGS(X)   ((X)&0x03)
    ++#define CKPT_SYNC_FLAGS(X)  (((X)>>2)&0x03)
    + 
    + #ifdef SQLITE_OMIT_WAL
    + # define sqlite3WalOpen(x,y,z)                   0
    + # define sqlite3WalLimit(x,y)
    +-# define sqlite3WalClose(w,x,y,z)                0
    ++# define sqlite3WalClose(v,w,x,y,z)              0
    + # define sqlite3WalBeginReadTransaction(y,z)     0
    + # define sqlite3WalEndReadTransaction(z)
    + # define sqlite3WalDbsize(y)                     0
    +@@ -42947,12 +47876,13 @@ SQLITE_PRIVATE int sqlite3RowSetTest(RowSet *pRowSet, int iBatch, sqlite3_int64
    + # define sqlite3WalSavepoint(y,z)
    + # define sqlite3WalSavepointUndo(y,z)            0
    + # define sqlite3WalFrames(u,v,w,x,y,z)           0
    +-# define sqlite3WalCheckpoint(r,s,t,u,v,w,x,y,z) 0
    ++# define sqlite3WalCheckpoint(q,r,s,t,u,v,w,x,y,z) 0
    + # define sqlite3WalCallback(z)                   0
    + # define sqlite3WalExclusiveMode(y,z)            0
    + # define sqlite3WalHeapMemory(z)                 0
    + # define sqlite3WalFramesize(z)                  0
    + # define sqlite3WalFindFrame(x,y,z)              0
    ++# define sqlite3WalFile(x)                       0
    + #else
    + 
    + #define WAL_SAVEPOINT_NDATA 4
    +@@ -42964,7 +47894,7 @@ typedef struct Wal Wal;
    + 
    + /* Open and close a connection to a write-ahead log. */
    + SQLITE_PRIVATE int sqlite3WalOpen(sqlite3_vfs*, sqlite3_file*, const char *, int, i64, Wal**);
    +-SQLITE_PRIVATE int sqlite3WalClose(Wal *pWal, int sync_flags, int, u8 *);
    ++SQLITE_PRIVATE int sqlite3WalClose(Wal *pWal, sqlite3*, int sync_flags, int, u8 *);
    + 
    + /* Set the limiting size of a WAL file. */
    + SQLITE_PRIVATE void sqlite3WalLimit(Wal*, i64);
    +@@ -43007,6 +47937,7 @@ SQLITE_PRIVATE int sqlite3WalFrames(Wal *pWal, int, PgHdr *, Pgno, int, int);
    + /* Copy pages from the log to the database file */ 
    + SQLITE_PRIVATE int sqlite3WalCheckpoint(
    +   Wal *pWal,                      /* Write-ahead log connection */
    ++  sqlite3 *db,                    /* Check this handle's interrupt flag */
    +   int eMode,                      /* One of PASSIVE, FULL and RESTART */
    +   int (*xBusy)(void*),            /* Function to call when busy */
    +   void *pBusyArg,                 /* Context argument for xBusyHandler */
    +@@ -43035,6 +47966,12 @@ SQLITE_PRIVATE int sqlite3WalExclusiveMode(Wal *pWal, int op);
    + */
    + SQLITE_PRIVATE int sqlite3WalHeapMemory(Wal *pWal);
    + 
    ++#ifdef SQLITE_ENABLE_SNAPSHOT
    ++SQLITE_PRIVATE int sqlite3WalSnapshotGet(Wal *pWal, sqlite3_snapshot **ppSnapshot);
    ++SQLITE_PRIVATE void sqlite3WalSnapshotOpen(Wal *pWal, sqlite3_snapshot *pSnapshot);
    ++SQLITE_PRIVATE int sqlite3WalSnapshotRecover(Wal *pWal);
    ++#endif
    ++
    + #ifdef SQLITE_ENABLE_ZIPVFS
    + /* If the WAL file is not empty, return the number of bytes of content
    + ** stored in each frame (i.e. the db page-size when the WAL was created).
    +@@ -43042,8 +47979,11 @@ SQLITE_PRIVATE int sqlite3WalHeapMemory(Wal *pWal);
    + SQLITE_PRIVATE int sqlite3WalFramesize(Wal *pWal);
    + #endif
    + 
    ++/* Return the sqlite3_file object for the WAL file */
    ++SQLITE_PRIVATE sqlite3_file *sqlite3WalFile(Wal *pWal);
    ++
    + #endif /* ifndef SQLITE_OMIT_WAL */
    +-#endif /* _WAL_H_ */
    ++#endif /* SQLITE_WAL_H */
    + 
    + /************** End of wal.h *************************************************/
    + /************** Continuing where we left off in pager.c **********************/
    +@@ -43154,8 +48094,8 @@ int sqlite3PagerTrace=1;  /* True to enable tracing */
    + ** associated file-descriptor is returned. FILEHANDLEID() takes an sqlite3_file
    + ** struct as its argument.
    + */
    +-#define PAGERID(p) ((int)(p->fd))
    +-#define FILEHANDLEID(fd) ((int)fd)
    ++#define PAGERID(p) (SQLITE_PTR_TO_INT(p->fd))
    ++#define FILEHANDLEID(fd) (SQLITE_PTR_TO_INT(fd))
    + 
    + /*
    + ** The Pager.eState variable stores the current 'state' of a pager. A
    +@@ -43454,6 +48394,7 @@ int sqlite3PagerTrace=1;  /* True to enable tracing */
    + */
    + #define MAX_SECTOR_SIZE 0x10000
    + 
    ++
    + /*
    + ** An instance of the following structure is allocated for each active
    + ** savepoint and statement transaction in the system. All such structures
    +@@ -43641,6 +48582,18 @@ struct PagerSavepoint {
    + **   is set to zero in all other states. In PAGER_ERROR state, Pager.errCode 
    + **   is always set to SQLITE_FULL, SQLITE_IOERR or one of the SQLITE_IOERR_XXX 
    + **   sub-codes.
    ++**
    ++** syncFlags, walSyncFlags
    ++**
    ++**   syncFlags is either SQLITE_SYNC_NORMAL (0x02) or SQLITE_SYNC_FULL (0x03).
    ++**   syncFlags is used for rollback mode.  walSyncFlags is used for WAL mode
    ++**   and contains the flags used to sync the checkpoint operations in the
    ++**   lower two bits, and sync flags used for transaction commits in the WAL
    ++**   file in bits 0x04 and 0x08.  In other words, to get the correct sync flags
    ++**   for checkpoint operations, use (walSyncFlags&0x03) and to get the correct
    ++**   sync flags for transaction commit, use ((walSyncFlags>>2)&0x03).  Note
    ++**   that with synchronous=NORMAL in WAL mode, transaction commit is not synced
    ++**   meaning that the 0x04 and 0x08 bits are both zero.
    + */
    + struct Pager {
    +   sqlite3_vfs *pVfs;          /* OS functions to use for IO */
    +@@ -43649,9 +48602,9 @@ struct Pager {
    +   u8 useJournal;              /* Use a rollback journal on this file */
    +   u8 noSync;                  /* Do not sync the journal if true */
    +   u8 fullSync;                /* Do extra syncs of the journal for robustness */
    +-  u8 ckptSyncFlags;           /* SYNC_NORMAL or SYNC_FULL for checkpoint */
    +-  u8 walSyncFlags;            /* SYNC_NORMAL or SYNC_FULL for wal writes */
    ++  u8 extraSync;               /* sync directory after journal delete */
    +   u8 syncFlags;               /* SYNC_NORMAL or SYNC_FULL otherwise */
    ++  u8 walSyncFlags;            /* See description above */
    +   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 */
    +@@ -43717,6 +48670,7 @@ struct Pager {
    +   int nRead;                  /* Database pages read */
    + #endif
    +   void (*xReiniter)(DbPage*); /* Call this routine when reloading pages */
    ++  int (*xGet)(Pager*,Pgno,DbPage**,int); /* Routine to fetch a patch */
    + #ifdef SQLITE_HAS_CODEC
    +   void *(*xCodec)(void*,void*,Pgno,int); /* Routine for en/decoding data */
    +   void (*xCodecSizeChng)(void*,int,int); /* Notify of page size changes */
    +@@ -43837,13 +48791,20 @@ static const unsigned char aJournalMagic[] = {
    + #define isOpen(pFd) ((pFd)->pMethods!=0)
    + 
    + /*
    +-** Return true if this pager uses a write-ahead log instead of the usual
    +-** rollback journal. Otherwise false.
    ++** Return true if this pager uses a write-ahead log to read page pgno.
    ++** Return false if the pager reads pgno directly from the database.
    + */
    +-#ifndef SQLITE_OMIT_WAL
    +-static int pagerUseWal(Pager *pPager){
    +-  return (pPager->pWal!=0);
    ++#if !defined(SQLITE_OMIT_WAL) && defined(SQLITE_DIRECT_OVERFLOW_READ)
    ++SQLITE_PRIVATE int sqlite3PagerUseWal(Pager *pPager, Pgno pgno){
    ++  u32 iRead = 0;
    ++  int rc;
    ++  if( pPager->pWal==0 ) return 0;
    ++  rc = sqlite3WalFindFrame(pPager->pWal, pgno, &iRead);
    ++  return rc || iRead;
    + }
    ++#endif
    ++#ifndef SQLITE_OMIT_WAL
    ++# define pagerUseWal(x) ((x)->pWal!=0)
    + #else
    + # define pagerUseWal(x) 0
    + # define pagerRollbackWal(x) 0
    +@@ -43896,6 +48857,7 @@ static int assert_pager_state(Pager *p){
    +   ** state.
    +   */
    +   if( MEMDB ){
    ++    assert( !isOpen(p->fd) );
    +     assert( p->noSync );
    +     assert( p->journalMode==PAGER_JOURNALMODE_OFF 
    +          || p->journalMode==PAGER_JOURNALMODE_MEMORY 
    +@@ -43962,6 +48924,7 @@ static int assert_pager_state(Pager *p){
    +       assert( isOpen(p->jfd) 
    +            || p->journalMode==PAGER_JOURNALMODE_OFF 
    +            || p->journalMode==PAGER_JOURNALMODE_WAL 
    ++           || (sqlite3OsDeviceCharacteristics(p->fd)&SQLITE_IOCAP_BATCH_ATOMIC)
    +       );
    +       assert( pPager->dbOrigSize<=pPager->dbHintSize );
    +       break;
    +@@ -43973,6 +48936,7 @@ static int assert_pager_state(Pager *p){
    +       assert( isOpen(p->jfd) 
    +            || p->journalMode==PAGER_JOURNALMODE_OFF 
    +            || p->journalMode==PAGER_JOURNALMODE_WAL 
    ++           || (sqlite3OsDeviceCharacteristics(p->fd)&SQLITE_IOCAP_BATCH_ATOMIC)
    +       );
    +       break;
    + 
    +@@ -43982,7 +48946,7 @@ static int assert_pager_state(Pager *p){
    +       ** back to OPEN state.
    +       */
    +       assert( pPager->errCode!=SQLITE_OK );
    +-      assert( sqlite3PcacheRefCount(pPager->pPCache)>0 );
    ++      assert( sqlite3PcacheRefCount(pPager->pPCache)>0 || pPager->tempFile );
    +       break;
    +   }
    + 
    +@@ -44041,6 +49005,33 @@ static char *print_pager_state(Pager *p){
    + }
    + #endif
    + 
    ++/* Forward references to the various page getters */
    ++static int getPageNormal(Pager*,Pgno,DbPage**,int);
    ++static int getPageError(Pager*,Pgno,DbPage**,int);
    ++#if SQLITE_MAX_MMAP_SIZE>0
    ++static int getPageMMap(Pager*,Pgno,DbPage**,int);
    ++#endif
    ++
    ++/*
    ++** Set the Pager.xGet method for the appropriate routine used to fetch
    ++** content from the pager.
    ++*/
    ++static void setGetterMethod(Pager *pPager){
    ++  if( pPager->errCode ){
    ++    pPager->xGet = getPageError;
    ++#if SQLITE_MAX_MMAP_SIZE>0
    ++  }else if( USEFETCH(pPager)
    ++#ifdef SQLITE_HAS_CODEC
    ++   && pPager->xCodec==0
    ++#endif
    ++  ){
    ++    pPager->xGet = getPageMMap;
    ++#endif /* SQLITE_MAX_MMAP_SIZE>0 */
    ++  }else{
    ++    pPager->xGet = getPageNormal;
    ++  }
    ++}
    ++
    + /*
    + ** Return true if it is necessary to write page *pPg into the sub-journal.
    + ** A page needs to be written into the sub-journal if there exists one
    +@@ -44156,34 +49147,47 @@ static int pagerLockDb(Pager *pPager, int eLock){
    + }
    + 
    + /*
    +-** This function determines whether or not the atomic-write optimization
    +-** can be used with this pager. The optimization can be used if:
    ++** This function determines whether or not the atomic-write or
    ++** atomic-batch-write optimizations can be used with this pager. The
    ++** atomic-write optimization can be used if:
    + **
    + **  (a) the value returned by OsDeviceCharacteristics() indicates that
    + **      a database page may be written atomically, and
    + **  (b) the value returned by OsSectorSize() is less than or equal
    + **      to the page size.
    + **
    +-** The optimization is also always enabled for temporary files. It is
    +-** an error to call this function if pPager is opened on an in-memory
    +-** database.
    ++** If it can be used, then the value returned is the size of the journal 
    ++** file when it contains rollback data for exactly one page.
    ++**
    ++** The atomic-batch-write optimization can be used if OsDeviceCharacteristics()
    ++** returns a value with the SQLITE_IOCAP_BATCH_ATOMIC bit set. -1 is
    ++** returned in this case.
    + **
    +-** If the optimization cannot be used, 0 is returned. If it can be used,
    +-** then the value returned is the size of the journal file when it
    +-** contains rollback data for exactly one page.
    ++** If neither optimization can be used, 0 is returned.
    + */
    +-#ifdef SQLITE_ENABLE_ATOMIC_WRITE
    + static int jrnlBufferSize(Pager *pPager){
    +   assert( !MEMDB );
    +-  if( !pPager->tempFile ){
    +-    int dc;                           /* Device characteristics */
    +-    int nSector;                      /* Sector size */
    +-    int szPage;                       /* Page size */
    + 
    +-    assert( isOpen(pPager->fd) );
    +-    dc = sqlite3OsDeviceCharacteristics(pPager->fd);
    +-    nSector = pPager->sectorSize;
    +-    szPage = pPager->pageSize;
    ++#if defined(SQLITE_ENABLE_ATOMIC_WRITE) \
    ++ || defined(SQLITE_ENABLE_BATCH_ATOMIC_WRITE)
    ++  int dc;                           /* Device characteristics */
    ++
    ++  assert( isOpen(pPager->fd) );
    ++  dc = sqlite3OsDeviceCharacteristics(pPager->fd);
    ++#else
    ++  UNUSED_PARAMETER(pPager);
    ++#endif
    ++
    ++#ifdef SQLITE_ENABLE_BATCH_ATOMIC_WRITE
    ++  if( dc&SQLITE_IOCAP_BATCH_ATOMIC ){
    ++    return -1;
    ++  }
    ++#endif
    ++
    ++#ifdef SQLITE_ENABLE_ATOMIC_WRITE
    ++  {
    ++    int nSector = pPager->sectorSize;
    ++    int szPage = pPager->pageSize;
    + 
    +     assert(SQLITE_IOCAP_ATOMIC512==(512>>8));
    +     assert(SQLITE_IOCAP_ATOMIC64K==(65536>>8));
    +@@ -44193,9 +49197,11 @@ static int jrnlBufferSize(Pager *pPager){
    +   }
    + 
    +   return JOURNAL_HDR_SZ(pPager) + JOURNAL_PG_SZ(pPager);
    +-}
    + #endif
    + 
    ++  return 0;
    ++}
    ++
    + /*
    + ** If SQLITE_CHECK_PAGES is defined then we do some sanity checking
    + ** on the cache using a hash function.  This is used for testing
    +@@ -44277,6 +49283,7 @@ static int readMasterJournal(sqlite3_file *pJrnl, char *zMaster, u32 nMaster){
    +    || szJ<16
    +    || SQLITE_OK!=(rc = read32bits(pJrnl, szJ-16, &len))
    +    || len>=nMaster 
    ++   || len>szJ-16
    +    || len==0 
    +    || SQLITE_OK!=(rc = read32bits(pJrnl, szJ-12, &cksum))
    +    || SQLITE_OK!=(rc = sqlite3OsRead(pJrnl, aMagic, 8, szJ-8))
    +@@ -44354,6 +49361,7 @@ static i64 journalHdrOffset(Pager *pPager){
    + static int zeroJournalHdr(Pager *pPager, int doTruncate){
    +   int rc = SQLITE_OK;                               /* Return code */
    +   assert( isOpen(pPager->jfd) );
    ++  assert( !sqlite3JournalIsInMemory(pPager->jfd) );
    +   if( pPager->journalOff ){
    +     const i64 iLimit = pPager->journalSizeLimit;    /* Local cache of jsl */
    + 
    +@@ -44735,7 +49743,7 @@ static void releaseAllSavepoints(Pager *pPager){
    +   for(ii=0; ii<pPager->nSavepoint; ii++){
    +     sqlite3BitvecDestroy(pPager->aSavepoint[ii].pInSavepoint);
    +   }
    +-  if( !pPager->exclusiveMode || sqlite3IsMemJournal(pPager->sjfd) ){
    ++  if( !pPager->exclusiveMode || sqlite3JournalIsInMemory(pPager->sjfd) ){
    +     sqlite3OsClose(pPager->sjfd);
    +   }
    +   sqlite3_free(pPager->aSavepoint);
    +@@ -44841,13 +49849,18 @@ static void pager_unlock(Pager *pPager){
    +   ** it can safely move back to PAGER_OPEN state. This happens in both
    +   ** normal and exclusive-locking mode.
    +   */
    ++  assert( pPager->errCode==SQLITE_OK || !MEMDB );
    +   if( pPager->errCode ){
    +-    assert( !MEMDB );
    +-    pager_reset(pPager);
    +-    pPager->changeCountDone = pPager->tempFile;
    +-    pPager->eState = PAGER_OPEN;
    +-    pPager->errCode = SQLITE_OK;
    ++    if( pPager->tempFile==0 ){
    ++      pager_reset(pPager);
    ++      pPager->changeCountDone = 0;
    ++      pPager->eState = PAGER_OPEN;
    ++    }else{
    ++      pPager->eState = (isOpen(pPager->jfd) ? PAGER_OPEN : PAGER_READER);
    ++    }
    +     if( USEFETCH(pPager) ) sqlite3OsUnfetch(pPager->fd, 0, 0);
    ++    pPager->errCode = SQLITE_OK;
    ++    setGetterMethod(pPager);
    +   }
    + 
    +   pPager->journalOff = 0;
    +@@ -44885,12 +49898,36 @@ static int pager_error(Pager *pPager, int rc){
    +   if( rc2==SQLITE_FULL || rc2==SQLITE_IOERR ){
    +     pPager->errCode = rc;
    +     pPager->eState = PAGER_ERROR;
    ++    setGetterMethod(pPager);
    +   }
    +   return rc;
    + }
    + 
    + static int pager_truncate(Pager *pPager, Pgno nPage);
    + 
    ++/*
    ++** The write transaction open on pPager is being committed (bCommit==1)
    ++** or rolled back (bCommit==0).
    ++**
    ++** Return TRUE if and only if all dirty pages should be flushed to disk.
    ++**
    ++** Rules:
    ++**
    ++**   *  For non-TEMP databases, always sync to disk.  This is necessary
    ++**      for transactions to be durable.
    ++**
    ++**   *  Sync TEMP database only on a COMMIT (not a ROLLBACK) when the backing
    ++**      file has been created already (via a spill on pagerStress()) and
    ++**      when the number of dirty pages in memory exceeds 25% of the total
    ++**      cache size.
    ++*/
    ++static int pagerFlushOnCommit(Pager *pPager, int bCommit){
    ++  if( pPager->tempFile==0 ) return 1;
    ++  if( !bCommit ) return 0;
    ++  if( !isOpen(pPager->fd) ) return 0;
    ++  return (sqlite3PCachePercentDirty(pPager->pPCache)>=25);
    ++}
    ++
    + /*
    + ** This routine ends a transaction. A transaction is usually ended by 
    + ** either a COMMIT or a ROLLBACK operation. This routine may be called 
    +@@ -44968,13 +50005,15 @@ static int pager_end_transaction(Pager *pPager, int hasMaster, int bCommit){
    +   }
    + 
    +   releaseAllSavepoints(pPager);
    +-  assert( isOpen(pPager->jfd) || pPager->pInJournal==0 );
    ++  assert( isOpen(pPager->jfd) || pPager->pInJournal==0 
    ++      || (sqlite3OsDeviceCharacteristics(pPager->fd)&SQLITE_IOCAP_BATCH_ATOMIC)
    ++  );
    +   if( isOpen(pPager->jfd) ){
    +     assert( !pagerUseWal(pPager) );
    + 
    +     /* Finalize the journal file. */
    +-    if( sqlite3IsMemJournal(pPager->jfd) ){
    +-      assert( pPager->journalMode==PAGER_JOURNALMODE_MEMORY );
    ++    if( sqlite3JournalIsInMemory(pPager->jfd) ){
    ++      /* assert( pPager->journalMode==PAGER_JOURNALMODE_MEMORY ); */
    +       sqlite3OsClose(pPager->jfd);
    +     }else if( pPager->journalMode==PAGER_JOURNALMODE_TRUNCATE ){
    +       if( pPager->journalOff==0 ){
    +@@ -44994,22 +50033,23 @@ static int pager_end_transaction(Pager *pPager, int hasMaster, int bCommit){
    +     }else if( pPager->journalMode==PAGER_JOURNALMODE_PERSIST
    +       || (pPager->exclusiveMode && pPager->journalMode!=PAGER_JOURNALMODE_WAL)
    +     ){
    +-      rc = zeroJournalHdr(pPager, hasMaster);
    ++      rc = zeroJournalHdr(pPager, hasMaster||pPager->tempFile);
    +       pPager->journalOff = 0;
    +     }else{
    +       /* This branch may be executed with Pager.journalMode==MEMORY if
    +       ** a hot-journal was just rolled back. In this case the journal
    +       ** file should be closed and deleted. If this connection writes to
    +-      ** the database file, it will do so using an in-memory journal. 
    ++      ** the database file, it will do so using an in-memory journal.
    +       */
    +-      int bDelete = (!pPager->tempFile && sqlite3JournalExists(pPager->jfd));
    ++      int bDelete = !pPager->tempFile;
    ++      assert( sqlite3JournalIsInMemory(pPager->jfd)==0 );
    +       assert( pPager->journalMode==PAGER_JOURNALMODE_DELETE 
    +            || pPager->journalMode==PAGER_JOURNALMODE_MEMORY 
    +            || pPager->journalMode==PAGER_JOURNALMODE_WAL 
    +       );
    +       sqlite3OsClose(pPager->jfd);
    +       if( bDelete ){
    +-        rc = sqlite3OsDelete(pPager->pVfs, pPager->zJournal, 0);
    ++        rc = sqlite3OsDelete(pPager->pVfs, pPager->zJournal, pPager->extraSync);
    +       }
    +     }
    +   }
    +@@ -45028,8 +50068,14 @@ static int pager_end_transaction(Pager *pPager, int hasMaster, int bCommit){
    +   sqlite3BitvecDestroy(pPager->pInJournal);
    +   pPager->pInJournal = 0;
    +   pPager->nRec = 0;
    +-  sqlite3PcacheCleanAll(pPager->pPCache);
    +-  sqlite3PcacheTruncate(pPager->pPCache, pPager->dbSize);
    ++  if( rc==SQLITE_OK ){
    ++    if( MEMDB || pagerFlushOnCommit(pPager, bCommit) ){
    ++      sqlite3PcacheCleanAll(pPager->pPCache);
    ++    }else{
    ++      sqlite3PcacheClearWritable(pPager->pPCache);
    ++    }
    ++    sqlite3PcacheTruncate(pPager->pPCache, pPager->dbSize);
    ++  }
    + 
    +   if( pagerUseWal(pPager) ){
    +     /* Drop the WAL write-lock, if any. Also, if the connection was in 
    +@@ -45207,6 +50253,11 @@ static int pager_playback_one_page(
    +   char *aData;                  /* Temporary storage for the page */
    +   sqlite3_file *jfd;            /* The file descriptor for the journal file */
    +   int isSynced;                 /* True if journal page is synced */
    ++#ifdef SQLITE_HAS_CODEC
    ++  /* The jrnlEnc flag is true if Journal pages should be passed through
    ++  ** the codec.  It is false for pure in-memory journals. */
    ++  const int jrnlEnc = (isMainJrnl || pPager->subjInMemory==0);
    ++#endif
    + 
    +   assert( (isMainJrnl&~1)==0 );      /* isMainJrnl is 0 or 1 */
    +   assert( (isSavepnt&~1)==0 );       /* isSavepnt is 0 or 1 */
    +@@ -45313,7 +50364,7 @@ static int pager_playback_one_page(
    +     pPg = sqlite3PagerLookup(pPager, pgno);
    +   }
    +   assert( pPg || !MEMDB );
    +-  assert( pPager->eState!=PAGER_OPEN || pPg==0 );
    ++  assert( pPager->eState!=PAGER_OPEN || pPg==0 || pPager->tempFile );
    +   PAGERTRACE(("PLAYBACK %d page %d hash(%08x) %s\n",
    +            PAGERID(pPager), pgno, pager_datahash(pPager->pageSize, (u8*)aData),
    +            (isMainJrnl?"main-journal":"sub-journal")
    +@@ -45330,14 +50381,34 @@ static int pager_playback_one_page(
    +     i64 ofst = (pgno-1)*(i64)pPager->pageSize;
    +     testcase( !isSavepnt && pPg!=0 && (pPg->flags&PGHDR_NEED_SYNC)!=0 );
    +     assert( !pagerUseWal(pPager) );
    ++
    ++    /* Write the data read from the journal back into the database file.
    ++    ** This is usually safe even for an encrypted database - as the data
    ++    ** was encrypted before it was written to the journal file. The exception
    ++    ** is if the data was just read from an in-memory sub-journal. In that
    ++    ** case it must be encrypted here before it is copied into the database
    ++    ** file.  */
    ++#ifdef SQLITE_HAS_CODEC
    ++    if( !jrnlEnc ){
    ++      CODEC2(pPager, aData, pgno, 7, rc=SQLITE_NOMEM_BKPT, aData);
    ++      rc = sqlite3OsWrite(pPager->fd, (u8 *)aData, pPager->pageSize, ofst);
    ++      CODEC1(pPager, aData, pgno, 3, rc=SQLITE_NOMEM_BKPT);
    ++    }else
    ++#endif
    +     rc = sqlite3OsWrite(pPager->fd, (u8 *)aData, pPager->pageSize, ofst);
    ++
    +     if( pgno>pPager->dbFileSize ){
    +       pPager->dbFileSize = pgno;
    +     }
    +     if( pPager->pBackup ){
    +-      CODEC1(pPager, aData, pgno, 3, rc=SQLITE_NOMEM);
    ++#ifdef SQLITE_HAS_CODEC
    ++      if( jrnlEnc ){
    ++        CODEC1(pPager, aData, pgno, 3, rc=SQLITE_NOMEM_BKPT);
    ++        sqlite3BackupUpdate(pPager->pBackup, pgno, (u8*)aData);
    ++        CODEC2(pPager, aData, pgno, 7, rc=SQLITE_NOMEM_BKPT,aData);
    ++      }else
    ++#endif
    +       sqlite3BackupUpdate(pPager->pBackup, pgno, (u8*)aData);
    +-      CODEC2(pPager, aData, pgno, 7, rc=SQLITE_NOMEM, aData);
    +     }
    +   }else if( !isMainJrnl && pPg==0 ){
    +     /* If this is a rollback of a savepoint and data was not written to
    +@@ -45359,11 +50430,10 @@ static int pager_playback_one_page(
    +     assert( isSavepnt );
    +     assert( (pPager->doNotSpill & SPILLFLAG_ROLLBACK)==0 );
    +     pPager->doNotSpill |= SPILLFLAG_ROLLBACK;
    +-    rc = sqlite3PagerAcquire(pPager, pgno, &pPg, 1);
    ++    rc = sqlite3PagerGet(pPager, pgno, &pPg, 1);
    +     assert( (pPager->doNotSpill & SPILLFLAG_ROLLBACK)!=0 );
    +     pPager->doNotSpill &= ~SPILLFLAG_ROLLBACK;
    +     if( rc!=SQLITE_OK ) return rc;
    +-    pPg->flags &= ~PGHDR_NEED_READ;
    +     sqlite3PcacheMakeDirty(pPg);
    +   }
    +   if( pPg ){
    +@@ -45377,29 +50447,10 @@ static int pager_playback_one_page(
    +     pData = pPg->pData;
    +     memcpy(pData, (u8*)aData, pPager->pageSize);
    +     pPager->xReiniter(pPg);
    +-    if( isMainJrnl && (!isSavepnt || *pOffset<=pPager->journalHdr) ){
    +-      /* If the contents of this page were just restored from the main 
    +-      ** journal file, then its content must be as they were when the 
    +-      ** transaction was first opened. In this case we can mark the page
    +-      ** as clean, since there will be no need to write it out to the
    +-      ** database.
    +-      **
    +-      ** There is one exception to this rule. If the page is being rolled
    +-      ** back as part of a savepoint (or statement) rollback from an 
    +-      ** unsynced portion of the main journal file, then it is not safe
    +-      ** to mark the page as clean. This is because marking the page as
    +-      ** clean will clear the PGHDR_NEED_SYNC flag. Since the page is
    +-      ** already in the journal file (recorded in Pager.pInJournal) and
    +-      ** the PGHDR_NEED_SYNC flag is cleared, if the page is written to
    +-      ** again within this transaction, it will be marked as dirty but
    +-      ** the PGHDR_NEED_SYNC flag will not be set. It could then potentially
    +-      ** be written out into the database file before its journal file
    +-      ** segment is synced. If a crash occurs during or following this,
    +-      ** database corruption may ensue.
    +-      */
    +-      assert( !pagerUseWal(pPager) );
    +-      sqlite3PcacheMakeClean(pPg);
    +-    }
    ++    /* It used to be that sqlite3PcacheMakeClean(pPg) was called here.  But
    ++    ** that call was dangerous and had no detectable benefit since the cache
    ++    ** is normally cleaned by sqlite3PcacheCleanAll() after rollback and so
    ++    ** has been removed. */
    +     pager_set_pagehash(pPg);
    + 
    +     /* If this was page 1, then restore the value of Pager.dbFileVers.
    +@@ -45409,7 +50460,9 @@ static int pager_playback_one_page(
    +     }
    + 
    +     /* Decode the page just read from disk */
    +-    CODEC1(pPager, pData, pPg->pgno, 3, rc=SQLITE_NOMEM);
    ++#if SQLITE_HAS_CODEC
    ++    if( jrnlEnc ){ CODEC1(pPager, pData, pPg->pgno, 3, rc=SQLITE_NOMEM_BKPT); }
    ++#endif
    +     sqlite3PcacheRelease(pPg);
    +   }
    +   return rc;
    +@@ -45475,7 +50528,7 @@ static int pager_delmaster(Pager *pPager, const char *zMaster){
    +   pMaster = (sqlite3_file *)sqlite3MallocZero(pVfs->szOsFile * 2);
    +   pJournal = (sqlite3_file *)(((u8 *)pMaster) + pVfs->szOsFile);
    +   if( !pMaster ){
    +-    rc = SQLITE_NOMEM;
    ++    rc = SQLITE_NOMEM_BKPT;
    +   }else{
    +     const int flags = (SQLITE_OPEN_READONLY|SQLITE_OPEN_MASTER_JOURNAL);
    +     rc = sqlite3OsOpen(pVfs, zMaster, pMaster, flags, 0);
    +@@ -45492,7 +50545,7 @@ static int pager_delmaster(Pager *pPager, const char *zMaster){
    +   nMasterPtr = pVfs->mxPathname+1;
    +   zMasterJournal = sqlite3Malloc(nMasterJournal + nMasterPtr + 1);
    +   if( !zMasterJournal ){
    +-    rc = SQLITE_NOMEM;
    ++    rc = SQLITE_NOMEM_BKPT;
    +     goto delmaster_out;
    +   }
    +   zMasterPtr = &zMasterJournal[nMasterJournal+1];
    +@@ -45722,6 +50775,7 @@ static int pager_playback(Pager *pPager, int isHot){
    +   char *zMaster = 0;       /* Name of master journal file if any */
    +   int needPagerReset;      /* True to reset page prior to first page rollback */
    +   int nPlayback = 0;       /* Total number of pages restored from journal */
    ++  u32 savedPageSize = pPager->pageSize;
    + 
    +   /* Figure out how many records are in the journal.  Abort early if
    +   ** the journal is empty.
    +@@ -45740,7 +50794,7 @@ static int pager_playback(Pager *pPager, int isHot){
    +   ** TODO: Technically the following is an error because it assumes that
    +   ** buffer Pager.pTmpSpace is (mxPathname+1) bytes or larger. i.e. that
    +   ** (pPager->pageSize >= pPager->pVfs->mxPathname+1). Using os_unix.c,
    +-  **  mxPathname is 512, which is the same as the minimum allowable value
    ++  ** mxPathname is 512, which is the same as the minimum allowable value
    +   ** for pageSize.
    +   */
    +   zMaster = pPager->pTmpSpace;
    +@@ -45851,6 +50905,9 @@ static int pager_playback(Pager *pPager, int isHot){
    +   assert( 0 );
    + 
    + end_playback:
    ++  if( rc==SQLITE_OK ){
    ++    rc = sqlite3PagerSetPagesize(pPager, &savedPageSize, -1);
    ++  }
    +   /* Following a rollback, the database file should be back in its original
    +   ** state prior to the start of the transaction, so invoke the
    +   ** SQLITE_FCNTL_DB_UNCHANGED file-control method to disable the
    +@@ -45909,7 +50966,8 @@ end_playback:
    + 
    + 
    + /*
    +-** Read the content for page pPg out of the database file and into 
    ++** Read the content for page pPg out of the database file (or out of
    ++** the WAL if that is where the most recent copy if found) into 
    + ** pPg->pData. A shared lock or greater must be held on the database
    + ** file before this function is called.
    + **
    +@@ -45919,30 +50977,33 @@ end_playback:
    + ** If an IO error occurs, then the IO error is returned to the caller.
    + ** Otherwise, SQLITE_OK is returned.
    + */
    +-static int readDbPage(PgHdr *pPg, u32 iFrame){
    ++static int readDbPage(PgHdr *pPg){
    +   Pager *pPager = pPg->pPager; /* Pager object associated with page pPg */
    +-  Pgno pgno = pPg->pgno;       /* Page number to read */
    +   int rc = SQLITE_OK;          /* Return code */
    +-  int pgsz = pPager->pageSize; /* Number of bytes to read */
    ++
    ++#ifndef SQLITE_OMIT_WAL
    ++  u32 iFrame = 0;              /* Frame of WAL containing pgno */
    + 
    +   assert( pPager->eState>=PAGER_READER && !MEMDB );
    +   assert( isOpen(pPager->fd) );
    + 
    +-#ifndef SQLITE_OMIT_WAL
    ++  if( pagerUseWal(pPager) ){
    ++    rc = sqlite3WalFindFrame(pPager->pWal, pPg->pgno, &iFrame);
    ++    if( rc ) return rc;
    ++  }
    +   if( iFrame ){
    +-    /* Try to pull the page from the write-ahead log. */
    +-    rc = sqlite3WalReadFrame(pPager->pWal, iFrame, pgsz, pPg->pData);
    ++    rc = sqlite3WalReadFrame(pPager->pWal, iFrame,pPager->pageSize,pPg->pData);
    +   }else
    + #endif
    +   {
    +-    i64 iOffset = (pgno-1)*(i64)pPager->pageSize;
    +-    rc = sqlite3OsRead(pPager->fd, pPg->pData, pgsz, iOffset);
    ++    i64 iOffset = (pPg->pgno-1)*(i64)pPager->pageSize;
    ++    rc = sqlite3OsRead(pPager->fd, pPg->pData, pPager->pageSize, iOffset);
    +     if( rc==SQLITE_IOERR_SHORT_READ ){
    +       rc = SQLITE_OK;
    +     }
    +   }
    + 
    +-  if( pgno==1 ){
    ++  if( pPg->pgno==1 ){
    +     if( rc ){
    +       /* If the read is unsuccessful, set the dbFileVers[] to something
    +       ** that will never be a valid file version.  dbFileVers[] is a copy
    +@@ -45962,13 +51023,13 @@ static int readDbPage(PgHdr *pPg, u32 iFrame){
    +       memcpy(&pPager->dbFileVers, dbFileVers, sizeof(pPager->dbFileVers));
    +     }
    +   }
    +-  CODEC1(pPager, pPg->pData, pgno, 3, rc = SQLITE_NOMEM);
    ++  CODEC1(pPager, pPg->pData, pPg->pgno, 3, rc = SQLITE_NOMEM_BKPT);
    + 
    +   PAGER_INCR(sqlite3_pager_readdb_count);
    +   PAGER_INCR(pPager->nRead);
    +-  IOTRACE(("PGIN %p %d\n", pPager, pgno));
    ++  IOTRACE(("PGIN %p %d\n", pPager, pPg->pgno));
    +   PAGERTRACE(("FETCH %d page %d hash(%08x)\n",
    +-               PAGERID(pPager), pgno, pager_pagehash(pPg)));
    ++               PAGERID(pPager), pPg->pgno, pager_pagehash(pPg)));
    + 
    +   return rc;
    + }
    +@@ -46019,11 +51080,7 @@ static int pagerUndoCallback(void *pCtx, Pgno iPg){
    +     if( sqlite3PcachePageRefcount(pPg)==1 ){
    +       sqlite3PcacheDrop(pPg);
    +     }else{
    +-      u32 iFrame = 0;
    +-      rc = sqlite3WalFindFrame(pPager->pWal, pPg->pgno, &iFrame);
    +-      if( rc==SQLITE_OK ){
    +-        rc = readDbPage(pPg, iFrame);
    +-      }
    ++      rc = readDbPage(pPg);
    +       if( rc==SQLITE_OK ){
    +         pPager->xReiniter(pPg);
    +       }
    +@@ -46190,21 +51247,20 @@ static int pagerPagecount(Pager *pPager, Pgno *pnPage){
    +   */
    +   assert( pPager->eState==PAGER_OPEN );
    +   assert( pPager->eLock>=SHARED_LOCK );
    ++  assert( isOpen(pPager->fd) );
    ++  assert( pPager->tempFile==0 );
    +   nPage = sqlite3WalDbsize(pPager->pWal);
    + 
    +   /* If the number of pages in the database is not available from the
    +-  ** WAL sub-system, determine the page counte based on the size of
    ++  ** WAL sub-system, determine the page count based on the size of
    +   ** the database file.  If the size of the database file is not an
    +   ** integer multiple of the page-size, round up the result.
    +   */
    +-  if( nPage==0 ){
    ++  if( nPage==0 && ALWAYS(isOpen(pPager->fd)) ){
    +     i64 n = 0;                    /* Size of db file in bytes */
    +-    assert( isOpen(pPager->fd) || pPager->tempFile );
    +-    if( isOpen(pPager->fd) ){
    +-      int rc = sqlite3OsFileSize(pPager->fd, &n);
    +-      if( rc!=SQLITE_OK ){
    +-        return rc;
    +-      }
    ++    int rc = sqlite3OsFileSize(pPager->fd, &n);
    ++    if( rc!=SQLITE_OK ){
    ++      return rc;
    +     }
    +     nPage = (Pgno)((n+pPager->pageSize-1) / pPager->pageSize);
    +   }
    +@@ -46247,23 +51303,21 @@ static int pagerOpenWalIfPresent(Pager *pPager){
    + 
    +   if( !pPager->tempFile ){
    +     int isWal;                    /* True if WAL file exists */
    +-    Pgno nPage;                   /* Size of the database file */
    +-
    +-    rc = pagerPagecount(pPager, &nPage);
    +-    if( rc ) return rc;
    +-    if( nPage==0 ){
    +-      rc = sqlite3OsDelete(pPager->pVfs, pPager->zWal, 0);
    +-      if( rc==SQLITE_IOERR_DELETE_NOENT ) rc = SQLITE_OK;
    +-      isWal = 0;
    +-    }else{
    +-      rc = sqlite3OsAccess(
    +-          pPager->pVfs, pPager->zWal, SQLITE_ACCESS_EXISTS, &isWal
    +-      );
    +-    }
    ++    rc = sqlite3OsAccess(
    ++        pPager->pVfs, pPager->zWal, SQLITE_ACCESS_EXISTS, &isWal
    ++    );
    +     if( rc==SQLITE_OK ){
    +       if( isWal ){
    +-        testcase( sqlite3PcachePagecount(pPager->pPCache)==0 );
    +-        rc = sqlite3PagerOpenWal(pPager, 0);
    ++        Pgno nPage;                   /* Size of the database file */
    ++
    ++        rc = pagerPagecount(pPager, &nPage);
    ++        if( rc ) return rc;
    ++        if( nPage==0 ){
    ++          rc = sqlite3OsDelete(pPager->pVfs, pPager->zWal, 0);
    ++        }else{
    ++          testcase( sqlite3PcachePagecount(pPager->pPCache)==0 );
    ++          rc = sqlite3PagerOpenWal(pPager, 0);
    ++        }
    +       }else if( pPager->journalMode==PAGER_JOURNALMODE_WAL ){
    +         pPager->journalMode = PAGER_JOURNALMODE_DELETE;
    +       }
    +@@ -46322,7 +51376,7 @@ static int pagerPlaybackSavepoint(Pager *pPager, PagerSavepoint *pSavepoint){
    +   if( pSavepoint ){
    +     pDone = sqlite3BitvecCreate(pSavepoint->nOrig);
    +     if( !pDone ){
    +-      return SQLITE_NOMEM;
    ++      return SQLITE_NOMEM_BKPT;
    +     }
    +   }
    + 
    +@@ -46418,12 +51472,21 @@ static int pagerPlaybackSavepoint(Pager *pPager, PagerSavepoint *pSavepoint){
    + }
    + 
    + /*
    +-** Change the maximum number of in-memory pages that are allowed.
    ++** Change the maximum number of in-memory pages that are allowed
    ++** before attempting to recycle clean and unused pages.
    + */
    + SQLITE_PRIVATE void sqlite3PagerSetCachesize(Pager *pPager, int mxPage){
    +   sqlite3PcacheSetCachesize(pPager->pPCache, mxPage);
    + }
    + 
    ++/*
    ++** Change the maximum number of in-memory pages that are allowed
    ++** before attempting to spill pages to journal.
    ++*/
    ++SQLITE_PRIVATE int sqlite3PagerSetSpillsize(Pager *pPager, int mxPage){
    ++  return sqlite3PcacheSetSpillsize(pPager->pPCache, mxPage);
    ++}
    ++
    + /*
    + ** Invoke SQLITE_FCNTL_MMAP_SIZE based on the current value of szMmap.
    + */
    +@@ -46434,6 +51497,7 @@ static void pagerFixMaplimit(Pager *pPager){
    +     sqlite3_int64 sz;
    +     sz = pPager->szMmap;
    +     pPager->bUseFetch = (sz>0);
    ++    setGetterMethod(pPager);
    +     sqlite3OsFileControlHint(pPager->fd, SQLITE_FCNTL_MMAP_SIZE, &sz);
    +   }
    + #endif
    +@@ -46460,7 +51524,7 @@ SQLITE_PRIVATE void sqlite3PagerShrink(Pager *pPager){
    + ** The "level" in pgFlags & PAGER_SYNCHRONOUS_MASK sets the robustness
    + ** of the database to damage due to OS crashes or power failures by
    + ** changing the number of syncs()s when writing the journals.
    +-** There are three levels:
    ++** There are four levels:
    + **
    + **    OFF       sqlite3OsSync() is never called.  This is the default
    + **              for temporary and transient files.
    +@@ -46480,6 +51544,10 @@ SQLITE_PRIVATE void sqlite3PagerShrink(Pager *pPager){
    + **              assurance that the journal will not be corrupted to the
    + **              point of causing damage to the database during rollback.
    + **
    ++**    EXTRA     This is like FULL except that is also syncs the directory
    ++**              that contains the rollback journal after the rollback
    ++**              journal is unlinked.
    ++**
    + ** The above is for a rollback-journal mode.  For WAL mode, OFF continues
    + ** to mean that no syncs ever occur.  NORMAL means that the WAL is synced
    + ** prior to the start of checkpoint and that the database file is synced
    +@@ -46487,7 +51555,8 @@ SQLITE_PRIVATE void sqlite3PagerShrink(Pager *pPager){
    + ** was written back into the database.  But no sync operations occur for
    + ** an ordinary commit in NORMAL mode with WAL.  FULL means that the WAL
    + ** file is synced following each commit operation, in addition to the
    +-** syncs associated with NORMAL.
    ++** syncs associated with NORMAL.  There is no difference between FULL
    ++** and EXTRA for WAL mode.
    + **
    + ** Do not confuse synchronous=FULL with SQLITE_SYNC_FULL.  The
    + ** SQLITE_SYNC_FULL macro means to use the MacOSX-style full-fsync
    +@@ -46506,25 +51575,28 @@ SQLITE_PRIVATE void sqlite3PagerSetFlags(
    +   unsigned pgFlags      /* Various flags */
    + ){
    +   unsigned level = pgFlags & PAGER_SYNCHRONOUS_MASK;
    +-  assert( level>=1 && level<=3 );
    +-  pPager->noSync =  (level==1 || pPager->tempFile) ?1:0;
    +-  pPager->fullSync = (level==3 && !pPager->tempFile) ?1:0;
    ++  if( pPager->tempFile ){
    ++    pPager->noSync = 1;
    ++    pPager->fullSync = 0;
    ++    pPager->extraSync = 0;
    ++  }else{
    ++    pPager->noSync =  level==PAGER_SYNCHRONOUS_OFF ?1:0;
    ++    pPager->fullSync = level>=PAGER_SYNCHRONOUS_FULL ?1:0;
    ++    pPager->extraSync = level==PAGER_SYNCHRONOUS_EXTRA ?1:0;
    ++  }
    +   if( pPager->noSync ){
    +     pPager->syncFlags = 0;
    +-    pPager->ckptSyncFlags = 0;
    +   }else if( pgFlags & PAGER_FULLFSYNC ){
    +     pPager->syncFlags = SQLITE_SYNC_FULL;
    +-    pPager->ckptSyncFlags = SQLITE_SYNC_FULL;
    +-  }else if( pgFlags & PAGER_CKPT_FULLFSYNC ){
    +-    pPager->syncFlags = SQLITE_SYNC_NORMAL;
    +-    pPager->ckptSyncFlags = SQLITE_SYNC_FULL;
    +   }else{
    +     pPager->syncFlags = SQLITE_SYNC_NORMAL;
    +-    pPager->ckptSyncFlags = SQLITE_SYNC_NORMAL;
    +   }
    +-  pPager->walSyncFlags = pPager->syncFlags;
    ++  pPager->walSyncFlags = (pPager->syncFlags<<2);
    +   if( pPager->fullSync ){
    +-    pPager->walSyncFlags |= WAL_SYNC_TRANSACTIONS;
    ++    pPager->walSyncFlags |= pPager->syncFlags;
    ++  }
    ++  if( (pgFlags & PAGER_CKPT_FULLFSYNC) && !pPager->noSync ){
    ++    pPager->walSyncFlags |= (SQLITE_SYNC_FULL<<2);
    +   }
    +   if( pgFlags & PAGER_CACHESPILL ){
    +     pPager->doNotSpill &= ~SPILLFLAG_OFF;
    +@@ -46670,7 +51742,7 @@ SQLITE_PRIVATE int sqlite3PagerSetPagesize(Pager *pPager, u32 *pPageSize, int nR
    +     }
    +     if( rc==SQLITE_OK ){
    +       pNew = (char *)sqlite3PageMalloc(pageSize);
    +-      if( !pNew ) rc = SQLITE_NOMEM;
    ++      if( !pNew ) rc = SQLITE_NOMEM_BKPT;
    +     }
    + 
    +     if( rc==SQLITE_OK ){
    +@@ -46919,6 +51991,7 @@ static int pagerSyncHotJournal(Pager *pPager){
    +   return rc;
    + }
    + 
    ++#if SQLITE_MAX_MMAP_SIZE>0
    + /*
    + ** Obtain a reference to a memory mapped page object for page number pgno. 
    + ** The new object will use the pointer pData, obtained from xFetch().
    +@@ -46941,12 +52014,13 @@ static int pagerAcquireMapPage(
    +     *ppPage = p = pPager->pMmapFreelist;
    +     pPager->pMmapFreelist = p->pDirty;
    +     p->pDirty = 0;
    +-    memset(p->pExtra, 0, pPager->nExtra);
    ++    assert( pPager->nExtra>=8 );
    ++    memset(p->pExtra, 0, 8);
    +   }else{
    +     *ppPage = p = (PgHdr *)sqlite3MallocZero(sizeof(PgHdr) + pPager->nExtra);
    +     if( p==0 ){
    +       sqlite3OsUnfetch(pPager->fd, (i64)(pgno-1) * pPager->pageSize, pData);
    +-      return SQLITE_NOMEM;
    ++      return SQLITE_NOMEM_BKPT;
    +     }
    +     p->pExtra = (void *)&p[1];
    +     p->flags = PGHDR_MMAP;
    +@@ -46966,6 +52040,7 @@ static int pagerAcquireMapPage(
    + 
    +   return SQLITE_OK;
    + }
    ++#endif
    + 
    + /*
    + ** Release a reference to page pPg. pPg must have been returned by an 
    +@@ -47008,9 +52083,10 @@ static void pagerFreeMapHdrs(Pager *pPager){
    + ** a hot journal may be left in the filesystem but no error is returned
    + ** to the caller.
    + */
    +-SQLITE_PRIVATE int sqlite3PagerClose(Pager *pPager){
    ++SQLITE_PRIVATE int sqlite3PagerClose(Pager *pPager, sqlite3 *db){
    +   u8 *pTmp = (u8 *)pPager->pTmpSpace;
    + 
    ++  assert( db || pagerUseWal(pPager)==0 );
    +   assert( assert_pager_state(pPager) );
    +   disable_simulated_io_errors();
    +   sqlite3BeginBenignMalloc();
    +@@ -47018,7 +52094,10 @@ SQLITE_PRIVATE int sqlite3PagerClose(Pager *pPager){
    +   /* pPager->errCode = 0; */
    +   pPager->exclusiveMode = 0;
    + #ifndef SQLITE_OMIT_WAL
    +-  sqlite3WalClose(pPager->pWal, pPager->ckptSyncFlags, pPager->pageSize, pTmp);
    ++  assert( db || pPager->pWal==0 );
    ++  sqlite3WalClose(pPager->pWal, db, pPager->walSyncFlags, pPager->pageSize,
    ++      (db && (db->flags & SQLITE_NoCkptOnClose) ? 0 : pTmp)
    ++  );
    +   pPager->pWal = 0;
    + #endif
    +   pager_reset(pPager);
    +@@ -47260,8 +52339,9 @@ static int pager_write_pagelist(Pager *pPager, PgHdr *pList){
    + 
    +   /* This function is only called for rollback pagers in WRITER_DBMOD state. */
    +   assert( !pagerUseWal(pPager) );
    +-  assert( pPager->eState==PAGER_WRITER_DBMOD );
    ++  assert( pPager->tempFile || pPager->eState==PAGER_WRITER_DBMOD );
    +   assert( pPager->eLock==EXCLUSIVE_LOCK );
    ++  assert( isOpen(pPager->fd) || pList->pDirty==0 );
    + 
    +   /* If the file is a temp-file has not yet been opened, open it now. It
    +   ** is not possible for rc to be other than SQLITE_OK if this branch
    +@@ -47304,7 +52384,7 @@ static int pager_write_pagelist(Pager *pPager, PgHdr *pList){
    +       if( pList->pgno==1 ) pager_write_changecounter(pList);
    + 
    +       /* Encode the database */
    +-      CODEC2(pPager, pList->pData, pgno, 6, return SQLITE_NOMEM, pData);
    ++      CODEC2(pPager, pList->pData, pgno, 6, return SQLITE_NOMEM_BKPT, pData);
    + 
    +       /* Write out the page data. */
    +       rc = sqlite3OsWrite(pPager->fd, pData, pPager->pageSize, offset);
    +@@ -47349,11 +52429,14 @@ static int pager_write_pagelist(Pager *pPager, PgHdr *pList){
    + static int openSubJournal(Pager *pPager){
    +   int rc = SQLITE_OK;
    +   if( !isOpen(pPager->sjfd) ){
    ++    const int flags =  SQLITE_OPEN_SUBJOURNAL | SQLITE_OPEN_READWRITE 
    ++      | SQLITE_OPEN_CREATE | SQLITE_OPEN_EXCLUSIVE 
    ++      | SQLITE_OPEN_DELETEONCLOSE;
    ++    int nStmtSpill = sqlite3Config.nStmtSpill;
    +     if( pPager->journalMode==PAGER_JOURNALMODE_MEMORY || pPager->subjInMemory ){
    +-      sqlite3MemJournalOpen(pPager->sjfd);
    +-    }else{
    +-      rc = pagerOpentemp(pPager, pPager->sjfd, SQLITE_OPEN_SUBJOURNAL);
    ++      nStmtSpill = -1;
    +     }
    ++    rc = sqlite3JournalOpen(pPager->pVfs, 0, pPager->sjfd, flags, nStmtSpill);
    +   }
    +   return rc;
    + }
    +@@ -47390,8 +52473,13 @@ static int subjournalPage(PgHdr *pPg){
    +       void *pData = pPg->pData;
    +       i64 offset = (i64)pPager->nSubRec*(4+pPager->pageSize);
    +       char *pData2;
    +-  
    +-      CODEC2(pPager, pData, pPg->pgno, 7, return SQLITE_NOMEM, pData2);
    ++
    ++#if SQLITE_HAS_CODEC   
    ++      if( !pPager->subjInMemory ){
    ++        CODEC2(pPager, pData, pPg->pgno, 7, return SQLITE_NOMEM_BKPT, pData2);
    ++      }else
    ++#endif
    ++      pData2 = pData;
    +       PAGERTRACE(("STMT-JOURNAL %d page %d\n", PAGERID(pPager), pPg->pgno));
    +       rc = write32bits(pPager->sjfd, offset, pPg->pgno);
    +       if( rc==SQLITE_OK ){
    +@@ -47475,6 +52563,13 @@ static int pagerStress(void *p, PgHdr *pPg){
    +       rc = pagerWalFrames(pPager, pPg, 0, 0);
    +     }
    +   }else{
    ++    
    ++#ifdef SQLITE_ENABLE_BATCH_ATOMIC_WRITE
    ++    if( pPager->tempFile==0 ){
    ++      rc = sqlite3JournalCreate(pPager->jfd);
    ++      if( rc!=SQLITE_OK ) return pager_error(pPager, rc);
    ++    }
    ++#endif
    +   
    +     /* Sync the journal file if required. */
    +     if( pPg->flags&PGHDR_NEED_SYNC 
    +@@ -47499,6 +52594,25 @@ static int pagerStress(void *p, PgHdr *pPg){
    +   return pager_error(pPager, rc); 
    + }
    + 
    ++/*
    ++** Flush all unreferenced dirty pages to disk.
    ++*/
    ++SQLITE_PRIVATE int sqlite3PagerFlush(Pager *pPager){
    ++  int rc = pPager->errCode;
    ++  if( !MEMDB ){
    ++    PgHdr *pList = sqlite3PcacheDirtyList(pPager->pPCache);
    ++    assert( assert_pager_state(pPager) );
    ++    while( rc==SQLITE_OK && pList ){
    ++      PgHdr *pNext = pList->pDirty;
    ++      if( pList->nRef==0 ){
    ++        rc = pagerStress((void*)pPager, pList);
    ++      }
    ++      pList = pNext;
    ++    }
    ++  }
    ++
    ++  return rc;
    ++}
    + 
    + /*
    + ** Allocate and initialize a new Pager object and put a pointer to it
    +@@ -47514,7 +52628,9 @@ static int pagerStress(void *p, PgHdr *pPg){
    + **
    + ** The nExtra parameter specifies the number of bytes of space allocated
    + ** along with each page reference. This space is available to the user
    +-** via the sqlite3PagerGetExtra() API.
    ++** via the sqlite3PagerGetExtra() API.  When a new page is allocated, the
    ++** first 8 bytes of this space are zeroed but the remainder is uninitialized.
    ++** (The extra space is used by btree as the MemPage object.)
    + **
    + ** The flags argument is used to specify properties that affect the
    + ** operation of the pager. It should be passed some bitwise combination
    +@@ -47555,18 +52671,8 @@ SQLITE_PRIVATE int sqlite3PagerOpen(
    +   int nUri = 0;            /* Number of bytes of URI args at *zUri */
    + 
    +   /* Figure out how much space is required for each journal file-handle
    +-  ** (there are two of them, the main journal and the sub-journal). This
    +-  ** is the maximum space required for an in-memory journal file handle 
    +-  ** and a regular journal file-handle. Note that a "regular journal-handle"
    +-  ** may be a wrapper capable of caching the first portion of the journal
    +-  ** file in memory to implement the atomic-write optimization (see 
    +-  ** source file journal.c).
    +-  */
    +-  if( sqlite3JournalSize(pVfs)>sqlite3MemJournalSize() ){
    +-    journalFileSize = ROUND8(sqlite3JournalSize(pVfs));
    +-  }else{
    +-    journalFileSize = ROUND8(sqlite3MemJournalSize());
    +-  }
    ++  ** (there are two of them, the main journal and the sub-journal).  */
    ++  journalFileSize = ROUND8(sqlite3JournalSize(pVfs));
    + 
    +   /* Set the output variable to NULL in case an error occurs. */
    +   *ppPager = 0;
    +@@ -47576,7 +52682,7 @@ SQLITE_PRIVATE int sqlite3PagerOpen(
    +     memDb = 1;
    +     if( zFilename && zFilename[0] ){
    +       zPathname = sqlite3DbStrDup(0, zFilename);
    +-      if( zPathname==0  ) return SQLITE_NOMEM;
    ++      if( zPathname==0  ) return SQLITE_NOMEM_BKPT;
    +       nPathname = sqlite3Strlen30(zPathname);
    +       zFilename = 0;
    +     }
    +@@ -47592,7 +52698,7 @@ SQLITE_PRIVATE int sqlite3PagerOpen(
    +     nPathname = pVfs->mxPathname+1;
    +     zPathname = sqlite3DbMallocRaw(0, nPathname*2);
    +     if( zPathname==0 ){
    +-      return SQLITE_NOMEM;
    ++      return SQLITE_NOMEM_BKPT;
    +     }
    +     zPathname[0] = 0; /* Make sure initialized even if FullPathname() fails */
    +     rc = sqlite3OsFullPathname(pVfs, zFilename, nPathname, zPathname);
    +@@ -47645,7 +52751,7 @@ SQLITE_PRIVATE int sqlite3PagerOpen(
    +   assert( EIGHT_BYTE_ALIGNMENT(SQLITE_INT_TO_PTR(journalFileSize)) );
    +   if( !pPtr ){
    +     sqlite3DbFree(0, zPathname);
    +-    return SQLITE_NOMEM;
    ++    return SQLITE_NOMEM_BKPT;
    +   }
    +   pPager =              (Pager*)(pPtr);
    +   pPager->pPCache =    (PCache*)(pPtr += ROUND8(sizeof(*pPager)));
    +@@ -47754,8 +52860,8 @@ act_like_temp_file:
    + 
    +   /* Initialize the PCache object. */
    +   if( rc==SQLITE_OK ){
    +-    assert( nExtra<1000 );
    +     nExtra = ROUND8(nExtra);
    ++    assert( nExtra>=8 && nExtra<1000 );
    +     rc = sqlite3PcacheOpen(szPageDflt, nExtra, !memDb,
    +                        !memDb?pagerStress:0, (void *)pPager, pPager->pPCache);
    +   }
    +@@ -47794,14 +52900,14 @@ act_like_temp_file:
    +   pPager->noSync = pPager->tempFile;
    +   if( pPager->noSync ){
    +     assert( pPager->fullSync==0 );
    ++    assert( pPager->extraSync==0 );
    +     assert( pPager->syncFlags==0 );
    +     assert( pPager->walSyncFlags==0 );
    +-    assert( pPager->ckptSyncFlags==0 );
    +   }else{
    +     pPager->fullSync = 1;
    ++    pPager->extraSync = 0;
    +     pPager->syncFlags = SQLITE_SYNC_NORMAL;
    +-    pPager->walSyncFlags = SQLITE_SYNC_NORMAL | WAL_SYNC_TRANSACTIONS;
    +-    pPager->ckptSyncFlags = SQLITE_SYNC_NORMAL;
    ++    pPager->walSyncFlags = SQLITE_SYNC_NORMAL | (SQLITE_SYNC_NORMAL<<2);
    +   }
    +   /* pPager->pFirst = 0; */
    +   /* pPager->pFirstSynced = 0; */
    +@@ -47818,6 +52924,7 @@ act_like_temp_file:
    +   /* pPager->xBusyHandler = 0; */
    +   /* pPager->pBusyHandlerArg = 0; */
    +   pPager->xReiniter = xReinit;
    ++  setGetterMethod(pPager);
    +   /* memset(pPager->aHash, 0, sizeof(pPager->aHash)); */
    +   /* pPager->szMmap = SQLITE_DEFAULT_MMAP_SIZE // will be set by btree.c */
    + 
    +@@ -47915,6 +53022,7 @@ static int hasHotJournal(Pager *pPager, int *pExists){
    +     if( rc==SQLITE_OK && !locked ){
    +       Pgno nPage;                 /* Number of pages in database file */
    + 
    ++      assert( pPager->tempFile==0 );
    +       rc = pagerPagecount(pPager, &nPage);
    +       if( rc==SQLITE_OK ){
    +         /* If the database is zero pages in size, that means that either (1) the
    +@@ -47976,7 +53084,7 @@ static int hasHotJournal(Pager *pPager, int *pExists){
    + 
    + /*
    + ** This function is called to obtain a shared lock on the database file.
    +-** It is illegal to call sqlite3PagerAcquire() until after this function
    ++** It is illegal to call sqlite3PagerGet() until after this function
    + ** has been successfully called. If a shared-lock is already held when
    + ** this function is called, it is a no-op.
    + **
    +@@ -48007,17 +53115,17 @@ SQLITE_PRIVATE int sqlite3PagerSharedLock(Pager *pPager){
    +   /* This routine is only called from b-tree and only when there are no
    +   ** outstanding pages. This implies that the pager state should either
    +   ** be OPEN or READER. READER is only possible if the pager is or was in 
    +-  ** exclusive access mode.
    +-  */
    ++  ** exclusive access mode.  */
    +   assert( sqlite3PcacheRefCount(pPager->pPCache)==0 );
    +   assert( assert_pager_state(pPager) );
    +   assert( pPager->eState==PAGER_OPEN || pPager->eState==PAGER_READER );
    +-  if( NEVER(MEMDB && pPager->errCode) ){ return pPager->errCode; }
    ++  assert( pPager->errCode==SQLITE_OK );
    + 
    +   if( !pagerUseWal(pPager) && pPager->eState==PAGER_OPEN ){
    +     int bHotJournal = 1;          /* True if there exists a hot journal-file */
    + 
    +     assert( !MEMDB );
    ++    assert( pPager->tempFile==0 || pPager->eLock==EXCLUSIVE_LOCK );
    + 
    +     rc = pager_wait_on_lock(pPager, SHARED_LOCK);
    +     if( rc!=SQLITE_OK ){
    +@@ -48103,7 +53211,7 @@ SQLITE_PRIVATE int sqlite3PagerSharedLock(Pager *pPager){
    +         assert( rc==SQLITE_OK );
    +         rc = pagerSyncHotJournal(pPager);
    +         if( rc==SQLITE_OK ){
    +-          rc = pager_playback(pPager, 1);
    ++          rc = pager_playback(pPager, !pPager->tempFile);
    +           pPager->eState = PAGER_OPEN;
    +         }
    +       }else if( !pPager->exclusiveMode ){
    +@@ -48154,19 +53262,14 @@ SQLITE_PRIVATE int sqlite3PagerSharedLock(Pager *pPager){
    +       ** detected.  The chance of an undetected change is so small that
    +       ** it can be neglected.
    +       */
    +-      Pgno nPage = 0;
    +       char dbFileVers[sizeof(pPager->dbFileVers)];
    + 
    +-      rc = pagerPagecount(pPager, &nPage);
    +-      if( rc ) goto failed;
    +-
    +-      if( nPage>0 ){
    +-        IOTRACE(("CKVERS %p %d\n", pPager, sizeof(dbFileVers)));
    +-        rc = sqlite3OsRead(pPager->fd, &dbFileVers, sizeof(dbFileVers), 24);
    +-        if( rc!=SQLITE_OK && rc!=SQLITE_IOERR_SHORT_READ ){
    ++      IOTRACE(("CKVERS %p %d\n", pPager, sizeof(dbFileVers)));
    ++      rc = sqlite3OsRead(pPager->fd, &dbFileVers, sizeof(dbFileVers), 24);
    ++      if( rc!=SQLITE_OK ){
    ++        if( rc!=SQLITE_IOERR_SHORT_READ ){
    +           goto failed;
    +         }
    +-      }else{
    +         memset(dbFileVers, 0, sizeof(dbFileVers));
    +       }
    + 
    +@@ -48199,7 +53302,7 @@ SQLITE_PRIVATE int sqlite3PagerSharedLock(Pager *pPager){
    +     rc = pagerBeginReadTransaction(pPager);
    +   }
    + 
    +-  if( pPager->eState==PAGER_OPEN && rc==SQLITE_OK ){
    ++  if( pPager->tempFile==0 && pPager->eState==PAGER_OPEN && rc==SQLITE_OK ){
    +     rc = pagerPagecount(pPager, &pPager->dbSize);
    +   }
    + 
    +@@ -48224,16 +53327,24 @@ SQLITE_PRIVATE int sqlite3PagerSharedLock(Pager *pPager){
    + ** nothing to rollback, so this routine is a no-op.
    + */ 
    + static void pagerUnlockIfUnused(Pager *pPager){
    +-  if( pPager->nMmapOut==0 && (sqlite3PcacheRefCount(pPager->pPCache)==0) ){
    ++  if( sqlite3PcacheRefCount(pPager->pPCache)==0 ){
    ++    assert( pPager->nMmapOut==0 ); /* because page1 is never memory mapped */
    +     pagerUnlockAndRollback(pPager);
    +   }
    + }
    + 
    + /*
    +-** Acquire a reference to page number pgno in pager pPager (a page
    +-** reference has type DbPage*). If the requested reference is 
    ++** The page getter methods each try to acquire a reference to a
    ++** page with page number pgno. If the requested reference is 
    + ** successfully obtained, it is copied to *ppPage and SQLITE_OK returned.
    + **
    ++** There are different implementations of the getter method depending
    ++** on the current state of the pager.
    ++**
    ++**     getPageNormal()         --  The normal getter
    ++**     getPageError()          --  Used if the pager is in an error state
    ++**     getPageMmap()           --  Used if memory-mapped I/O is enabled
    ++**
    + ** If the requested page is already in the cache, it is returned. 
    + ** Otherwise, a new page object is allocated and populated with data
    + ** read from the database file. In some cases, the pcache module may
    +@@ -48245,14 +53356,14 @@ static void pagerUnlockIfUnused(Pager *pPager){
    + ** already in the cache when this function is called, then the extra
    + ** data is left as it was when the page object was last used.
    + **
    +-** If the database image is smaller than the requested page or if a 
    +-** non-zero value is passed as the noContent parameter and the 
    ++** If the database image is smaller than the requested page or if 
    ++** the flags parameter contains the PAGER_GET_NOCONTENT bit and the 
    + ** requested page is not already stored in the cache, then no 
    + ** actual disk read occurs. In this case the memory image of the 
    + ** page is initialized to all zeros. 
    + **
    +-** If noContent is true, it means that we do not care about the contents
    +-** of the page. This occurs in two scenarios:
    ++** If PAGER_GET_NOCONTENT is true, it means that we do not care about
    ++** the contents of the page. This occurs in two scenarios:
    + **
    + **   a) When reading a free-list leaf page from the database, and
    + **
    +@@ -48260,8 +53371,8 @@ static void pagerUnlockIfUnused(Pager *pPager){
    + **      a new page into the cache to be filled with the data read
    + **      from the savepoint journal.
    + **
    +-** If noContent is true, then the data returned is zeroed instead of
    +-** being read from the database. Additionally, the bits corresponding
    ++** If PAGER_GET_NOCONTENT is true, then the data returned is zeroed instead
    ++** of being read from the database. Additionally, the bits corresponding
    + ** to pgno in Pager.pInJournal (bitvec of pages already written to the
    + ** journal file) and the PagerSavepoint.pInSavepoint bitvecs of any open
    + ** savepoints are set. This means if the page is made writable at any
    +@@ -48279,106 +53390,39 @@ static void pagerUnlockIfUnused(Pager *pPager){
    + ** Since Lookup() never goes to disk, it never has to deal with locks
    + ** or journal files.
    + */
    +-SQLITE_PRIVATE int sqlite3PagerAcquire(
    ++static int getPageNormal(
    +   Pager *pPager,      /* The pager open on the database file */
    +   Pgno pgno,          /* Page number to fetch */
    +   DbPage **ppPage,    /* Write a pointer to the page here */
    +   int flags           /* PAGER_GET_XXX flags */
    + ){
    +   int rc = SQLITE_OK;
    +-  PgHdr *pPg = 0;
    +-  u32 iFrame = 0;                 /* Frame to read from WAL file */
    +-  const int noContent = (flags & PAGER_GET_NOCONTENT);
    +-
    +-  /* It is acceptable to use a read-only (mmap) page for any page except
    +-  ** page 1 if there is no write-transaction open or the ACQUIRE_READONLY
    +-  ** flag was specified by the caller. And so long as the db is not a 
    +-  ** temporary or in-memory database.  */
    +-  const int bMmapOk = (pgno>1 && USEFETCH(pPager)
    +-   && (pPager->eState==PAGER_READER || (flags & PAGER_GET_READONLY))
    +-#ifdef SQLITE_HAS_CODEC
    +-   && pPager->xCodec==0
    +-#endif
    +-  );
    ++  PgHdr *pPg;
    ++  u8 noContent;                   /* True if PAGER_GET_NOCONTENT is set */
    ++  sqlite3_pcache_page *pBase;
    + 
    +-  /* Optimization note:  Adding the "pgno<=1" term before "pgno==0" here
    +-  ** allows the compiler optimizer to reuse the results of the "pgno>1"
    +-  ** test in the previous statement, and avoid testing pgno==0 in the
    +-  ** common case where pgno is large. */
    +-  if( pgno<=1 && pgno==0 ){
    +-    return SQLITE_CORRUPT_BKPT;
    +-  }
    ++  assert( pPager->errCode==SQLITE_OK );
    +   assert( pPager->eState>=PAGER_READER );
    +   assert( assert_pager_state(pPager) );
    +-  assert( noContent==0 || bMmapOk==0 );
    +-
    +   assert( pPager->hasHeldSharedLock==1 );
    + 
    +-  /* If the pager is in the error state, return an error immediately. 
    +-  ** Otherwise, request the page from the PCache layer. */
    +-  if( pPager->errCode!=SQLITE_OK ){
    +-    rc = pPager->errCode;
    +-  }else{
    +-    if( bMmapOk && pagerUseWal(pPager) ){
    +-      rc = sqlite3WalFindFrame(pPager->pWal, pgno, &iFrame);
    +-      if( rc!=SQLITE_OK ) goto pager_acquire_err;
    +-    }
    +-
    +-    if( bMmapOk && iFrame==0 ){
    +-      void *pData = 0;
    +-
    +-      rc = sqlite3OsFetch(pPager->fd, 
    +-          (i64)(pgno-1) * pPager->pageSize, pPager->pageSize, &pData
    +-      );
    +-
    +-      if( rc==SQLITE_OK && pData ){
    +-        if( pPager->eState>PAGER_READER ){
    +-          pPg = sqlite3PagerLookup(pPager, pgno);
    +-        }
    +-        if( pPg==0 ){
    +-          rc = pagerAcquireMapPage(pPager, pgno, pData, &pPg);
    +-        }else{
    +-          sqlite3OsUnfetch(pPager->fd, (i64)(pgno-1)*pPager->pageSize, pData);
    +-        }
    +-        if( pPg ){
    +-          assert( rc==SQLITE_OK );
    +-          *ppPage = pPg;
    +-          return SQLITE_OK;
    +-        }
    +-      }
    +-      if( rc!=SQLITE_OK ){
    +-        goto pager_acquire_err;
    +-      }
    +-    }
    +-
    +-    {
    +-      sqlite3_pcache_page *pBase;
    +-      pBase = sqlite3PcacheFetch(pPager->pPCache, pgno, 3);
    +-      if( pBase==0 ){
    +-        rc = sqlite3PcacheFetchStress(pPager->pPCache, pgno, &pBase);
    +-        if( rc!=SQLITE_OK ) goto pager_acquire_err;
    +-        if( pBase==0 ){
    +-          pPg = *ppPage = 0;
    +-          rc = SQLITE_NOMEM;
    +-          goto pager_acquire_err;
    +-        }
    +-      }
    +-      pPg = *ppPage = sqlite3PcacheFetchFinish(pPager->pPCache, pgno, pBase);
    +-      assert( pPg!=0 );
    +-    }
    +-  }
    +-
    +-  if( rc!=SQLITE_OK ){
    +-    /* Either the call to sqlite3PcacheFetch() returned an error or the
    +-    ** pager was already in the error-state when this function was called.
    +-    ** Set pPg to 0 and jump to the exception handler.  */
    ++  if( pgno==0 ) return SQLITE_CORRUPT_BKPT;
    ++  pBase = sqlite3PcacheFetch(pPager->pPCache, pgno, 3);
    ++  if( pBase==0 ){
    +     pPg = 0;
    +-    goto pager_acquire_err;
    ++    rc = sqlite3PcacheFetchStress(pPager->pPCache, pgno, &pBase);
    ++    if( rc!=SQLITE_OK ) goto pager_acquire_err;
    ++    if( pBase==0 ){
    ++      rc = SQLITE_NOMEM_BKPT;
    ++      goto pager_acquire_err;
    ++    }
    +   }
    ++  pPg = *ppPage = sqlite3PcacheFetchFinish(pPager->pPCache, pgno, pBase);
    +   assert( pPg==(*ppPage) );
    +   assert( pPg->pgno==pgno );
    +   assert( pPg->pPager==pPager || pPg->pPager==0 );
    + 
    ++  noContent = (flags & PAGER_GET_NOCONTENT)!=0;
    +   if( pPg->pPager && !noContent ){
    +     /* In this case the pcache already contains an initialized copy of
    +     ** the page. Return without further ado.  */
    +@@ -48388,18 +53432,20 @@ SQLITE_PRIVATE int sqlite3PagerAcquire(
    + 
    +   }else{
    +     /* The pager cache has created a new page. Its content needs to 
    +-    ** be initialized.  */
    +-
    +-    pPg->pPager = pPager;
    +-
    +-    /* The maximum page number is 2^31. Return SQLITE_CORRUPT if a page
    +-    ** number greater than this, or the unused locking-page, is requested. */
    ++    ** be initialized. But first some error checks:
    ++    **
    ++    ** (1) The maximum page number is 2^31
    ++    ** (2) Never try to fetch the locking page
    ++    */
    +     if( pgno>PAGER_MAX_PGNO || pgno==PAGER_MJ_PGNO(pPager) ){
    +       rc = SQLITE_CORRUPT_BKPT;
    +       goto pager_acquire_err;
    +     }
    + 
    +-    if( MEMDB || pPager->dbSize<pgno || noContent || !isOpen(pPager->fd) ){
    ++    pPg->pPager = pPager;
    ++
    ++    assert( !isOpen(pPager->fd) || !MEMDB );
    ++    if( !isOpen(pPager->fd) || pPager->dbSize<pgno || noContent ){
    +       if( pgno>pPager->mxPgno ){
    +         rc = SQLITE_FULL;
    +         goto pager_acquire_err;
    +@@ -48423,20 +53469,15 @@ SQLITE_PRIVATE int sqlite3PagerAcquire(
    +       memset(pPg->pData, 0, pPager->pageSize);
    +       IOTRACE(("ZERO %p %d\n", pPager, pgno));
    +     }else{
    +-      if( pagerUseWal(pPager) && bMmapOk==0 ){
    +-        rc = sqlite3WalFindFrame(pPager->pWal, pgno, &iFrame);
    +-        if( rc!=SQLITE_OK ) goto pager_acquire_err;
    +-      }
    +       assert( pPg->pPager==pPager );
    +       pPager->aStat[PAGER_STAT_MISS]++;
    +-      rc = readDbPage(pPg, iFrame);
    ++      rc = readDbPage(pPg);
    +       if( rc!=SQLITE_OK ){
    +         goto pager_acquire_err;
    +       }
    +     }
    +     pager_set_pagehash(pPg);
    +   }
    +-
    +   return SQLITE_OK;
    + 
    + pager_acquire_err:
    +@@ -48445,11 +53486,109 @@ pager_acquire_err:
    +     sqlite3PcacheDrop(pPg);
    +   }
    +   pagerUnlockIfUnused(pPager);
    +-
    +   *ppPage = 0;
    +   return rc;
    + }
    + 
    ++#if SQLITE_MAX_MMAP_SIZE>0
    ++/* The page getter for when memory-mapped I/O is enabled */
    ++static int getPageMMap(
    ++  Pager *pPager,      /* The pager open on the database file */
    ++  Pgno pgno,          /* Page number to fetch */
    ++  DbPage **ppPage,    /* Write a pointer to the page here */
    ++  int flags           /* PAGER_GET_XXX flags */
    ++){
    ++  int rc = SQLITE_OK;
    ++  PgHdr *pPg = 0;
    ++  u32 iFrame = 0;                 /* Frame to read from WAL file */
    ++
    ++  /* It is acceptable to use a read-only (mmap) page for any page except
    ++  ** page 1 if there is no write-transaction open or the ACQUIRE_READONLY
    ++  ** flag was specified by the caller. And so long as the db is not a 
    ++  ** temporary or in-memory database.  */
    ++  const int bMmapOk = (pgno>1
    ++   && (pPager->eState==PAGER_READER || (flags & PAGER_GET_READONLY))
    ++  );
    ++
    ++  assert( USEFETCH(pPager) );
    ++#ifdef SQLITE_HAS_CODEC
    ++  assert( pPager->xCodec==0 );
    ++#endif
    ++
    ++  /* Optimization note:  Adding the "pgno<=1" term before "pgno==0" here
    ++  ** allows the compiler optimizer to reuse the results of the "pgno>1"
    ++  ** test in the previous statement, and avoid testing pgno==0 in the
    ++  ** common case where pgno is large. */
    ++  if( pgno<=1 && pgno==0 ){
    ++    return SQLITE_CORRUPT_BKPT;
    ++  }
    ++  assert( pPager->eState>=PAGER_READER );
    ++  assert( assert_pager_state(pPager) );
    ++  assert( pPager->hasHeldSharedLock==1 );
    ++  assert( pPager->errCode==SQLITE_OK );
    ++
    ++  if( bMmapOk && pagerUseWal(pPager) ){
    ++    rc = sqlite3WalFindFrame(pPager->pWal, pgno, &iFrame);
    ++    if( rc!=SQLITE_OK ){
    ++      *ppPage = 0;
    ++      return rc;
    ++    }
    ++  }
    ++  if( bMmapOk && iFrame==0 ){
    ++    void *pData = 0;
    ++    rc = sqlite3OsFetch(pPager->fd, 
    ++        (i64)(pgno-1) * pPager->pageSize, pPager->pageSize, &pData
    ++    );
    ++    if( rc==SQLITE_OK && pData ){
    ++      if( pPager->eState>PAGER_READER || pPager->tempFile ){
    ++        pPg = sqlite3PagerLookup(pPager, pgno);
    ++      }
    ++      if( pPg==0 ){
    ++        rc = pagerAcquireMapPage(pPager, pgno, pData, &pPg);
    ++      }else{
    ++        sqlite3OsUnfetch(pPager->fd, (i64)(pgno-1)*pPager->pageSize, pData);
    ++      }
    ++      if( pPg ){
    ++        assert( rc==SQLITE_OK );
    ++        *ppPage = pPg;
    ++        return SQLITE_OK;
    ++      }
    ++    }
    ++    if( rc!=SQLITE_OK ){
    ++      *ppPage = 0;
    ++      return rc;
    ++    }
    ++  }
    ++  return getPageNormal(pPager, pgno, ppPage, flags);
    ++}
    ++#endif /* SQLITE_MAX_MMAP_SIZE>0 */
    ++
    ++/* The page getter method for when the pager is an error state */
    ++static int getPageError(
    ++  Pager *pPager,      /* The pager open on the database file */
    ++  Pgno pgno,          /* Page number to fetch */
    ++  DbPage **ppPage,    /* Write a pointer to the page here */
    ++  int flags           /* PAGER_GET_XXX flags */
    ++){
    ++  UNUSED_PARAMETER(pgno);
    ++  UNUSED_PARAMETER(flags);
    ++  assert( pPager->errCode!=SQLITE_OK );
    ++  *ppPage = 0;
    ++  return pPager->errCode;
    ++}
    ++
    ++
    ++/* Dispatch all page fetch requests to the appropriate getter method.
    ++*/
    ++SQLITE_PRIVATE int sqlite3PagerGet(
    ++  Pager *pPager,      /* The pager open on the database file */
    ++  Pgno pgno,          /* Page number to fetch */
    ++  DbPage **ppPage,    /* Write a pointer to the page here */
    ++  int flags           /* PAGER_GET_XXX flags */
    ++){
    ++  return pPager->xGet(pPager, pgno, ppPage, flags);
    ++}
    ++
    + /*
    + ** Acquire a page if it is already in the in-memory cache.  Do
    + ** not read the page from disk.  Return a pointer to the page,
    +@@ -48475,25 +53614,39 @@ SQLITE_PRIVATE DbPage *sqlite3PagerLookup(Pager *pPager, Pgno pgno){
    + /*
    + ** Release a page reference.
    + **
    +-** If the number of references to the page drop to zero, then the
    +-** page is added to the LRU list.  When all references to all pages
    +-** are released, a rollback occurs and the lock on the database is
    +-** removed.
    ++** The sqlite3PagerUnref() and sqlite3PagerUnrefNotNull() may only be
    ++** used if we know that the page being released is not the last page.
    ++** The btree layer always holds page1 open until the end, so these first
    ++** to routines can be used to release any page other than BtShared.pPage1.
    ++**
    ++** Use sqlite3PagerUnrefPageOne() to release page1.  This latter routine
    ++** checks the total number of outstanding pages and if the number of
    ++** pages reaches zero it drops the database lock.
    + */
    + SQLITE_PRIVATE void sqlite3PagerUnrefNotNull(DbPage *pPg){
    +-  Pager *pPager;
    ++  TESTONLY( Pager *pPager = pPg->pPager; )
    +   assert( pPg!=0 );
    +-  pPager = pPg->pPager;
    +   if( pPg->flags & PGHDR_MMAP ){
    ++    assert( pPg->pgno!=1 );  /* Page1 is never memory mapped */
    +     pagerReleaseMapPage(pPg);
    +   }else{
    +     sqlite3PcacheRelease(pPg);
    +   }
    +-  pagerUnlockIfUnused(pPager);
    ++  /* Do not use this routine to release the last reference to page1 */
    ++  assert( sqlite3PcacheRefCount(pPager->pPCache)>0 );
    + }
    + SQLITE_PRIVATE void sqlite3PagerUnref(DbPage *pPg){
    +   if( pPg ) sqlite3PagerUnrefNotNull(pPg);
    + }
    ++SQLITE_PRIVATE void sqlite3PagerUnrefPageOne(DbPage *pPg){
    ++  Pager *pPager;
    ++  assert( pPg!=0 );
    ++  assert( pPg->pgno==1 );
    ++  assert( (pPg->flags & PGHDR_MMAP)==0 ); /* Page1 is never memory mapped */
    ++  pPager = pPg->pPager;
    ++  sqlite3PcacheRelease(pPg);
    ++  pagerUnlockIfUnused(pPager);
    ++}
    + 
    + /*
    + ** This function is called at the start of every write transaction.
    +@@ -48533,7 +53686,7 @@ static int pager_open_journal(Pager *pPager){
    +   if( !pagerUseWal(pPager) && pPager->journalMode!=PAGER_JOURNALMODE_OFF ){
    +     pPager->pInJournal = sqlite3BitvecCreate(pPager->dbSize);
    +     if( pPager->pInJournal==0 ){
    +-      return SQLITE_NOMEM;
    ++      return SQLITE_NOMEM_BKPT;
    +     }
    +   
    +     /* Open the journal file if it is not already open. */
    +@@ -48541,24 +53694,24 @@ static int pager_open_journal(Pager *pPager){
    +       if( pPager->journalMode==PAGER_JOURNALMODE_MEMORY ){
    +         sqlite3MemJournalOpen(pPager->jfd);
    +       }else{
    +-        const int flags =                   /* VFS flags to open journal file */
    +-          SQLITE_OPEN_READWRITE|SQLITE_OPEN_CREATE|
    +-          (pPager->tempFile ? 
    +-            (SQLITE_OPEN_DELETEONCLOSE|SQLITE_OPEN_TEMP_JOURNAL):
    +-            (SQLITE_OPEN_MAIN_JOURNAL)
    +-          );
    ++        int flags = SQLITE_OPEN_READWRITE|SQLITE_OPEN_CREATE;
    ++        int nSpill;
    + 
    ++        if( pPager->tempFile ){
    ++          flags |= (SQLITE_OPEN_DELETEONCLOSE|SQLITE_OPEN_TEMP_JOURNAL);
    ++          nSpill = sqlite3Config.nStmtSpill;
    ++        }else{
    ++          flags |= SQLITE_OPEN_MAIN_JOURNAL;
    ++          nSpill = jrnlBufferSize(pPager);
    ++        }
    ++          
    +         /* Verify that the database still has the same name as it did when
    +         ** it was originally opened. */
    +         rc = databaseIsUnmoved(pPager);
    +         if( rc==SQLITE_OK ){
    +-#ifdef SQLITE_ENABLE_ATOMIC_WRITE
    +-          rc = sqlite3JournalOpen(
    +-              pVfs, pPager->zJournal, pPager->jfd, flags, jrnlBufferSize(pPager)
    ++          rc = sqlite3JournalOpen (
    ++              pVfs, pPager->zJournal, pPager->jfd, flags, nSpill
    +           );
    +-#else
    +-          rc = sqlite3OsOpen(pVfs, pPager->zJournal, pPager->jfd, flags, 0);
    +-#endif
    +         }
    +       }
    +       assert( rc!=SQLITE_OK || isOpen(pPager->jfd) );
    +@@ -48625,7 +53778,7 @@ SQLITE_PRIVATE int sqlite3PagerBegin(Pager *pPager, int exFlag, int subjInMemory
    +         if( rc!=SQLITE_OK ){
    +           return rc;
    +         }
    +-        sqlite3WalExclusiveMode(pPager->pWal, 1);
    ++        (void)sqlite3WalExclusiveMode(pPager->pWal, 1);
    +       }
    + 
    +       /* Grab the write lock on the log file. If successful, upgrade to
    +@@ -48688,7 +53841,7 @@ static SQLITE_NOINLINE int pagerAddPageToRollbackJournal(PgHdr *pPg){
    +   assert( pPg->pgno!=PAGER_MJ_PGNO(pPager) );
    + 
    +   assert( pPager->journalHdr<=pPager->journalOff );
    +-  CODEC2(pPager, pPg->pData, pPg->pgno, 7, return SQLITE_NOMEM, pData2);
    ++  CODEC2(pPager, pPg->pData, pPg->pgno, 7, return SQLITE_NOMEM_BKPT, pData2);
    +   cksum = pager_cksum(pPager, (u8*)pData2);
    + 
    +   /* Even if an IO or diskfull error occurs while journalling the
    +@@ -48865,7 +54018,7 @@ static SQLITE_NOINLINE int pagerWriteLargeSector(PgHdr *pPg){
    +     PgHdr *pPage;
    +     if( pg==pPg->pgno || !sqlite3BitvecTest(pPager->pInJournal, pg) ){
    +       if( pg!=PAGER_MJ_PGNO(pPager) ){
    +-        rc = sqlite3PagerGet(pPager, pg, &pPage);
    ++        rc = sqlite3PagerGet(pPager, pg, &pPage, 0);
    +         if( rc==SQLITE_OK ){
    +           rc = pager_write(pPage);
    +           if( pPage->flags&PGHDR_NEED_SYNC ){
    +@@ -48922,12 +54075,14 @@ SQLITE_PRIVATE int sqlite3PagerWrite(PgHdr *pPg){
    +   Pager *pPager = pPg->pPager;
    +   assert( (pPg->flags & PGHDR_MMAP)==0 );
    +   assert( pPager->eState>=PAGER_WRITER_LOCKED );
    +-  assert( pPager->eState!=PAGER_ERROR );
    +   assert( assert_pager_state(pPager) );
    +   if( (pPg->flags & PGHDR_WRITEABLE)!=0 && pPager->dbSize>=pPg->pgno ){
    +     if( pPager->nSavepoint ) return subjournalPageIfRequired(pPg);
    +     return SQLITE_OK;
    ++  }else if( pPager->errCode ){
    ++    return pPager->errCode;
    +   }else if( pPager->sectorSize > (u32)pPager->pageSize ){
    ++    assert( pPager->tempFile==0 );
    +     return pagerWriteLargeSector(pPg);
    +   }else{
    +     return pager_write(pPg);
    +@@ -48958,14 +54113,21 @@ SQLITE_PRIVATE int sqlite3PagerIswriteable(DbPage *pPg){
    + **
    + ** Tests show that this optimization can quadruple the speed of large 
    + ** DELETE operations.
    ++**
    ++** This optimization cannot be used with a temp-file, as the page may
    ++** have been dirty at the start of the transaction. In that case, if
    ++** memory pressure forces page pPg out of the cache, the data does need 
    ++** to be written out to disk so that it may be read back in if the 
    ++** current transaction is rolled back.
    + */
    + SQLITE_PRIVATE void sqlite3PagerDontWrite(PgHdr *pPg){
    +   Pager *pPager = pPg->pPager;
    +-  if( (pPg->flags&PGHDR_DIRTY) && pPager->nSavepoint==0 ){
    ++  if( !pPager->tempFile && (pPg->flags&PGHDR_DIRTY) && pPager->nSavepoint==0 ){
    +     PAGERTRACE(("DONT_WRITE page %d of %d\n", pPg->pgno, PAGERID(pPager)));
    +     IOTRACE(("CLEAN %p %d\n", pPager, pPg->pgno))
    +     pPg->flags |= PGHDR_DONT_WRITE;
    +     pPg->flags &= ~PGHDR_WRITEABLE;
    ++    testcase( pPg->flags & PGHDR_NEED_SYNC );
    +     pager_set_pagehash(pPg);
    +   }
    + }
    +@@ -49024,7 +54186,7 @@ static int pager_incr_changecounter(Pager *pPager, int isDirectMode){
    +     assert( !pPager->tempFile && isOpen(pPager->fd) );
    + 
    +     /* Open page 1 of the file for writing. */
    +-    rc = sqlite3PagerGet(pPager, 1, &pPgHdr);
    ++    rc = sqlite3PagerGet(pPager, 1, &pPgHdr, 0);
    +     assert( pPgHdr==0 || rc==SQLITE_OK );
    + 
    +     /* If page one was fetched successfully, and this function is not
    +@@ -49044,7 +54206,7 @@ static int pager_incr_changecounter(Pager *pPager, int isDirectMode){
    +       if( DIRECT_MODE ){
    +         const void *zBuf;
    +         assert( pPager->dbFileSize>0 );
    +-        CODEC2(pPager, pPgHdr->pData, 1, 6, rc=SQLITE_NOMEM, zBuf);
    ++        CODEC2(pPager, pPgHdr->pData, 1, 6, rc=SQLITE_NOMEM_BKPT, zBuf);
    +         if( rc==SQLITE_OK ){
    +           rc = sqlite3OsWrite(pPager->fd, zBuf, pPager->pageSize, 0);
    +           pPager->aStat[PAGER_STAT_WRITE]++;
    +@@ -49102,14 +54264,17 @@ SQLITE_PRIVATE int sqlite3PagerSync(Pager *pPager, const char *zMaster){
    + ** returned.
    + */
    + SQLITE_PRIVATE int sqlite3PagerExclusiveLock(Pager *pPager){
    +-  int rc = SQLITE_OK;
    +-  assert( pPager->eState==PAGER_WRITER_CACHEMOD 
    +-       || pPager->eState==PAGER_WRITER_DBMOD 
    +-       || pPager->eState==PAGER_WRITER_LOCKED 
    +-  );
    ++  int rc = pPager->errCode;
    +   assert( assert_pager_state(pPager) );
    +-  if( 0==pagerUseWal(pPager) ){
    +-    rc = pager_wait_on_lock(pPager, EXCLUSIVE_LOCK);
    ++  if( rc==SQLITE_OK ){
    ++    assert( pPager->eState==PAGER_WRITER_CACHEMOD 
    ++         || pPager->eState==PAGER_WRITER_DBMOD 
    ++         || pPager->eState==PAGER_WRITER_LOCKED 
    ++    );
    ++    assert( assert_pager_state(pPager) );
    ++    if( 0==pagerUseWal(pPager) ){
    ++      rc = pager_wait_on_lock(pPager, EXCLUSIVE_LOCK);
    ++    }
    +   }
    +   return rc;
    + }
    +@@ -49157,17 +54322,21 @@ SQLITE_PRIVATE int sqlite3PagerCommitPhaseOne(
    +   /* If a prior error occurred, report that error again. */
    +   if( NEVER(pPager->errCode) ) return pPager->errCode;
    + 
    ++  /* Provide the ability to easily simulate an I/O error during testing */
    ++  if( sqlite3FaultSim(400) ) return SQLITE_IOERR;
    ++
    +   PAGERTRACE(("DATABASE SYNC: File=%s zMaster=%s nSize=%d\n", 
    +       pPager->zFilename, zMaster, pPager->dbSize));
    + 
    +   /* If no database changes have been made, return early. */
    +   if( pPager->eState<PAGER_WRITER_CACHEMOD ) return SQLITE_OK;
    + 
    +-  if( MEMDB ){
    ++  assert( MEMDB==0 || pPager->tempFile );
    ++  assert( isOpen(pPager->fd) || pPager->tempFile );
    ++  if( 0==pagerFlushOnCommit(pPager, 1) ){
    +     /* If this is an in-memory db, or no pages have been written to, or this
    +     ** function has already been called, it is mostly a no-op.  However, any
    +-    ** backup in progress needs to be restarted.
    +-    */
    ++    ** backup in progress needs to be restarted.  */
    +     sqlite3BackupRestart(pPager->pBackup);
    +   }else{
    +     if( pagerUseWal(pPager) ){
    +@@ -49176,7 +54345,7 @@ SQLITE_PRIVATE int sqlite3PagerCommitPhaseOne(
    +       if( pList==0 ){
    +         /* Must have at least one page for the WAL commit flag.
    +         ** Ticket [2d1a5c67dfc2363e44f29d9bbd57f] 2011-05-18 */
    +-        rc = sqlite3PagerGet(pPager, 1, &pPageOne);
    ++        rc = sqlite3PagerGet(pPager, 1, &pPageOne, 0);
    +         pList = pPageOne;
    +         pList->pDirty = 0;
    +       }
    +@@ -49189,6 +54358,21 @@ SQLITE_PRIVATE int sqlite3PagerCommitPhaseOne(
    +         sqlite3PcacheCleanAll(pPager->pPCache);
    +       }
    +     }else{
    ++      /* The bBatch boolean is true if the batch-atomic-write commit method
    ++      ** should be used.  No rollback journal is created if batch-atomic-write
    ++      ** is enabled.
    ++      */
    ++      sqlite3_file *fd = pPager->fd;
    ++#ifdef SQLITE_ENABLE_BATCH_ATOMIC_WRITE
    ++      const int bBatch = zMaster==0    /* An SQLITE_IOCAP_BATCH_ATOMIC commit */
    ++        && (sqlite3OsDeviceCharacteristics(fd) & SQLITE_IOCAP_BATCH_ATOMIC)
    ++        && !pPager->noSync
    ++        && sqlite3JournalIsInMemory(pPager->jfd);
    ++#else
    ++# define bBatch 0
    ++#endif
    ++
    ++#ifdef SQLITE_ENABLE_ATOMIC_WRITE
    +       /* The following block updates the change-counter. Exactly how it
    +       ** does this depends on whether or not the atomic-update optimization
    +       ** was enabled at compile time, and if this transaction meets the 
    +@@ -49212,33 +54396,40 @@ SQLITE_PRIVATE int sqlite3PagerCommitPhaseOne(
    +       ** in 'direct' mode. In this case the journal file will never be
    +       ** created for this transaction.
    +       */
    +-  #ifdef SQLITE_ENABLE_ATOMIC_WRITE
    +-      PgHdr *pPg;
    +-      assert( isOpen(pPager->jfd) 
    +-           || pPager->journalMode==PAGER_JOURNALMODE_OFF 
    +-           || pPager->journalMode==PAGER_JOURNALMODE_WAL 
    +-      );
    +-      if( !zMaster && isOpen(pPager->jfd) 
    +-       && pPager->journalOff==jrnlBufferSize(pPager) 
    +-       && pPager->dbSize>=pPager->dbOrigSize
    +-       && (0==(pPg = sqlite3PcacheDirtyList(pPager->pPCache)) || 0==pPg->pDirty)
    +-      ){
    +-        /* Update the db file change counter via the direct-write method. The 
    +-        ** following call will modify the in-memory representation of page 1 
    +-        ** to include the updated change counter and then write page 1 
    +-        ** directly to the database file. Because of the atomic-write 
    +-        ** property of the host file-system, this is safe.
    +-        */
    +-        rc = pager_incr_changecounter(pPager, 1);
    +-      }else{
    +-        rc = sqlite3JournalCreate(pPager->jfd);
    +-        if( rc==SQLITE_OK ){
    +-          rc = pager_incr_changecounter(pPager, 0);
    ++      if( bBatch==0 ){
    ++        PgHdr *pPg;
    ++        assert( isOpen(pPager->jfd) 
    ++            || pPager->journalMode==PAGER_JOURNALMODE_OFF 
    ++            || pPager->journalMode==PAGER_JOURNALMODE_WAL 
    ++            );
    ++        if( !zMaster && isOpen(pPager->jfd) 
    ++         && pPager->journalOff==jrnlBufferSize(pPager) 
    ++         && pPager->dbSize>=pPager->dbOrigSize
    ++         && (!(pPg = sqlite3PcacheDirtyList(pPager->pPCache)) || 0==pPg->pDirty)
    ++        ){
    ++          /* Update the db file change counter via the direct-write method. The 
    ++          ** following call will modify the in-memory representation of page 1 
    ++          ** to include the updated change counter and then write page 1 
    ++          ** directly to the database file. Because of the atomic-write 
    ++          ** property of the host file-system, this is safe.
    ++          */
    ++          rc = pager_incr_changecounter(pPager, 1);
    ++        }else{
    ++          rc = sqlite3JournalCreate(pPager->jfd);
    ++          if( rc==SQLITE_OK ){
    ++            rc = pager_incr_changecounter(pPager, 0);
    ++          }
    +         }
    +       }
    +-  #else
    ++#else 
    ++#ifdef SQLITE_ENABLE_BATCH_ATOMIC_WRITE
    ++      if( zMaster ){
    ++        rc = sqlite3JournalCreate(pPager->jfd);
    ++        if( rc!=SQLITE_OK ) goto commit_phase_one_exit;
    ++      }
    ++#endif
    +       rc = pager_incr_changecounter(pPager, 0);
    +-  #endif
    ++#endif
    +       if( rc!=SQLITE_OK ) goto commit_phase_one_exit;
    +   
    +       /* Write the master journal name into the journal file. If a master 
    +@@ -49261,8 +54452,24 @@ SQLITE_PRIVATE int sqlite3PagerCommitPhaseOne(
    +       */
    +       rc = syncJournal(pPager, 0);
    +       if( rc!=SQLITE_OK ) goto commit_phase_one_exit;
    +-  
    ++
    ++      if( bBatch ){
    ++        /* The pager is now in DBMOD state. But regardless of what happens
    ++        ** next, attempting to play the journal back into the database would
    ++        ** be unsafe. Close it now to make sure that does not happen.  */
    ++        sqlite3OsClose(pPager->jfd);
    ++        rc = sqlite3OsFileControl(fd, SQLITE_FCNTL_BEGIN_ATOMIC_WRITE, 0);
    ++        if( rc!=SQLITE_OK ) goto commit_phase_one_exit;
    ++      }
    +       rc = pager_write_pagelist(pPager,sqlite3PcacheDirtyList(pPager->pPCache));
    ++      if( bBatch ){
    ++        if( rc==SQLITE_OK ){
    ++          rc = sqlite3OsFileControl(fd, SQLITE_FCNTL_COMMIT_ATOMIC_WRITE, 0);
    ++        }else{
    ++          sqlite3OsFileControl(fd, SQLITE_FCNTL_ROLLBACK_ATOMIC_WRITE, 0);
    ++        }
    ++      }
    ++
    +       if( rc!=SQLITE_OK ){
    +         assert( rc!=SQLITE_IOERR_BLOCKED );
    +         goto commit_phase_one_exit;
    +@@ -49406,6 +54613,7 @@ SQLITE_PRIVATE int sqlite3PagerRollback(Pager *pPager){
    +       */
    +       pPager->errCode = SQLITE_ABORT;
    +       pPager->eState = PAGER_ERROR;
    ++      setGetterMethod(pPager);
    +       return rc;
    +     }
    +   }else{
    +@@ -49506,10 +54714,10 @@ SQLITE_PRIVATE void sqlite3PagerCacheStat(Pager *pPager, int eStat, int reset, i
    + }
    + 
    + /*
    +-** Return true if this is an in-memory pager.
    ++** Return true if this is an in-memory or temp-file backed pager.
    + */
    + SQLITE_PRIVATE int sqlite3PagerIsMemdb(Pager *pPager){
    +-  return MEMDB;
    ++  return pPager->tempFile;
    + }
    + 
    + /*
    +@@ -49540,7 +54748,7 @@ static SQLITE_NOINLINE int pagerOpenSavepoint(Pager *pPager, int nSavepoint){
    +       pPager->aSavepoint, sizeof(PagerSavepoint)*nSavepoint
    +   );
    +   if( !aNew ){
    +-    return SQLITE_NOMEM;
    ++    return SQLITE_NOMEM_BKPT;
    +   }
    +   memset(&aNew[nCurrent], 0, (nSavepoint-nCurrent) * sizeof(PagerSavepoint));
    +   pPager->aSavepoint = aNew;
    +@@ -49556,7 +54764,7 @@ static SQLITE_NOINLINE int pagerOpenSavepoint(Pager *pPager, int nSavepoint){
    +     aNew[ii].iSubRec = pPager->nSubRec;
    +     aNew[ii].pInSavepoint = sqlite3BitvecCreate(pPager->dbSize);
    +     if( !aNew[ii].pInSavepoint ){
    +-      return SQLITE_NOMEM;
    ++      return SQLITE_NOMEM_BKPT;
    +     }
    +     if( pagerUseWal(pPager) ){
    +       sqlite3WalSavepoint(pPager->pWal, aNew[ii].aWalData);
    +@@ -49610,7 +54818,11 @@ SQLITE_PRIVATE int sqlite3PagerOpenSavepoint(Pager *pPager, int nSavepoint){
    + ** savepoint. If no errors occur, SQLITE_OK is returned.
    + */ 
    + SQLITE_PRIVATE int sqlite3PagerSavepoint(Pager *pPager, int op, int iSavepoint){
    +-  int rc = pPager->errCode;       /* Return code */
    ++  int rc = pPager->errCode;
    ++  
    ++#ifdef SQLITE_ENABLE_ZIPVFS
    ++  if( op==SAVEPOINT_RELEASE ) rc = SQLITE_OK;
    ++#endif
    + 
    +   assert( op==SAVEPOINT_RELEASE || op==SAVEPOINT_ROLLBACK );
    +   assert( iSavepoint>=0 || op==SAVEPOINT_ROLLBACK );
    +@@ -49634,7 +54846,7 @@ SQLITE_PRIVATE int sqlite3PagerSavepoint(Pager *pPager, int op, int iSavepoint){
    +     if( op==SAVEPOINT_RELEASE ){
    +       if( nNew==0 && isOpen(pPager->sjfd) ){
    +         /* Only truncate if it is an in-memory sub-journal. */
    +-        if( sqlite3IsMemJournal(pPager->sjfd) ){
    ++        if( sqlite3JournalIsInMemory(pPager->sjfd) ){
    +           rc = sqlite3OsTruncate(pPager->sjfd, 0);
    +           assert( rc==SQLITE_OK );
    +         }
    +@@ -49651,6 +54863,21 @@ SQLITE_PRIVATE int sqlite3PagerSavepoint(Pager *pPager, int op, int iSavepoint){
    +       rc = pagerPlaybackSavepoint(pPager, pSavepoint);
    +       assert(rc!=SQLITE_DONE);
    +     }
    ++    
    ++#ifdef SQLITE_ENABLE_ZIPVFS
    ++    /* If the cache has been modified but the savepoint cannot be rolled 
    ++    ** back journal_mode=off, put the pager in the error state. This way,
    ++    ** if the VFS used by this pager includes ZipVFS, the entire transaction
    ++    ** can be rolled back at the ZipVFS level.  */
    ++    else if( 
    ++        pPager->journalMode==PAGER_JOURNALMODE_OFF 
    ++     && pPager->eState>=PAGER_WRITER_CACHEMOD
    ++    ){
    ++      pPager->errCode = SQLITE_ABORT;
    ++      pPager->eState = PAGER_ERROR;
    ++      setGetterMethod(pPager);
    ++    }
    ++#endif
    +   }
    + 
    +   return rc;
    +@@ -49673,7 +54900,7 @@ SQLITE_PRIVATE const char *sqlite3PagerFilename(Pager *pPager, int nullIfMemDb){
    + /*
    + ** Return the VFS structure for the pager.
    + */
    +-SQLITE_PRIVATE const sqlite3_vfs *sqlite3PagerVfs(Pager *pPager){
    ++SQLITE_PRIVATE sqlite3_vfs *sqlite3PagerVfs(Pager *pPager){
    +   return pPager->pVfs;
    + }
    + 
    +@@ -49687,18 +54914,22 @@ SQLITE_PRIVATE sqlite3_file *sqlite3PagerFile(Pager *pPager){
    + }
    + 
    + /*
    +-** Return the full pathname of the journal file.
    ++** Return the file handle for the journal file (if it exists).
    ++** This will be either the rollback journal or the WAL file.
    + */
    +-SQLITE_PRIVATE const char *sqlite3PagerJournalname(Pager *pPager){
    +-  return pPager->zJournal;
    ++SQLITE_PRIVATE sqlite3_file *sqlite3PagerJrnlFile(Pager *pPager){
    ++#if SQLITE_OMIT_WAL
    ++  return pPager->jfd;
    ++#else
    ++  return pPager->pWal ? sqlite3WalFile(pPager->pWal) : pPager->jfd;
    ++#endif
    + }
    + 
    + /*
    +-** Return true if fsync() calls are disabled for this pager.  Return FALSE
    +-** if fsync()s are executed normally.
    ++** Return the full pathname of the journal file.
    + */
    +-SQLITE_PRIVATE int sqlite3PagerNosync(Pager *pPager){
    +-  return pPager->noSync;
    ++SQLITE_PRIVATE const char *sqlite3PagerJournalname(Pager *pPager){
    ++  return pPager->zJournal;
    + }
    + 
    + #ifdef SQLITE_HAS_CODEC
    +@@ -49717,6 +54948,7 @@ SQLITE_PRIVATE void sqlite3PagerSetCodec(
    +   pPager->xCodecSizeChng = xCodecSizeChng;
    +   pPager->xCodecFree = xCodecFree;
    +   pPager->pCodec = pCodec;
    ++  setGetterMethod(pPager);
    +   pagerReportSize(pPager);
    + }
    + SQLITE_PRIVATE void *sqlite3PagerGetCodec(Pager *pPager){
    +@@ -49785,7 +55017,8 @@ SQLITE_PRIVATE int sqlite3PagerMovepage(Pager *pPager, DbPage *pPg, Pgno pgno, i
    +   /* In order to be able to rollback, an in-memory database must journal
    +   ** the page we are moving from.
    +   */
    +-  if( MEMDB ){
    ++  assert( pPager->tempFile || !MEMDB );
    ++  if( pPager->tempFile ){
    +     rc = sqlite3PagerWrite(pPg);
    +     if( rc ) return rc;
    +   }
    +@@ -49842,7 +55075,7 @@ SQLITE_PRIVATE int sqlite3PagerMovepage(Pager *pPager, DbPage *pPg, Pgno pgno, i
    +   assert( !pPgOld || pPgOld->nRef==1 );
    +   if( pPgOld ){
    +     pPg->flags |= (pPgOld->flags&PGHDR_NEED_SYNC);
    +-    if( MEMDB ){
    ++    if( pPager->tempFile ){
    +       /* Do not discard pages from an in-memory database since we might
    +       ** need to rollback later.  Just move the page out of the way. */
    +       sqlite3PcacheMove(pPgOld, pPager->dbSize+1);
    +@@ -49859,8 +55092,7 @@ SQLITE_PRIVATE int sqlite3PagerMovepage(Pager *pPager, DbPage *pPg, Pgno pgno, i
    +   ** to exist, in case the transaction needs to roll back.  Use pPgOld
    +   ** as the original page since it has already been allocated.
    +   */
    +-  if( MEMDB ){
    +-    assert( pPgOld );
    ++  if( pPager->tempFile && pPgOld ){
    +     sqlite3PcacheMove(pPgOld, origPgno);
    +     sqlite3PagerUnrefNotNull(pPgOld);
    +   }
    +@@ -49881,7 +55113,7 @@ SQLITE_PRIVATE int sqlite3PagerMovepage(Pager *pPager, DbPage *pPg, Pgno pgno, i
    +     ** the journal file twice, but that is not a problem.
    +     */
    +     PgHdr *pPgHdr;
    +-    rc = sqlite3PagerGet(pPager, needSyncPgno, &pPgHdr);
    ++    rc = sqlite3PagerGet(pPager, needSyncPgno, &pPgHdr, 0);
    +     if( rc!=SQLITE_OK ){
    +       if( needSyncPgno<=pPager->dbOrigSize ){
    +         assert( pPager->pTmpSpace!=0 );
    +@@ -50112,10 +55344,12 @@ SQLITE_PRIVATE sqlite3_backup **sqlite3PagerBackupPtr(Pager *pPager){
    + ** Unless this is an in-memory or temporary database, clear the pager cache.
    + */
    + SQLITE_PRIVATE void sqlite3PagerClearCache(Pager *pPager){
    +-  if( !MEMDB && pPager->tempFile==0 ) pager_reset(pPager);
    ++  assert( MEMDB==0 || pPager->tempFile );
    ++  if( pPager->tempFile==0 ) pager_reset(pPager);
    + }
    + #endif
    + 
    ++
    + #ifndef SQLITE_OMIT_WAL
    + /*
    + ** This function is called when the user invokes "PRAGMA wal_checkpoint",
    +@@ -50124,13 +55358,19 @@ SQLITE_PRIVATE void sqlite3PagerClearCache(Pager *pPager){
    + **
    + ** Parameter eMode is one of SQLITE_CHECKPOINT_PASSIVE, FULL or RESTART.
    + */
    +-SQLITE_PRIVATE int sqlite3PagerCheckpoint(Pager *pPager, int eMode, int *pnLog, int *pnCkpt){
    ++SQLITE_PRIVATE int sqlite3PagerCheckpoint(
    ++  Pager *pPager,                  /* Checkpoint on this pager */
    ++  sqlite3 *db,                    /* Db handle used to check for interrupts */
    ++  int eMode,                      /* Type of checkpoint */
    ++  int *pnLog,                     /* OUT: Final number of frames in log */
    ++  int *pnCkpt                     /* OUT: Final number of checkpointed frames */
    ++){
    +   int rc = SQLITE_OK;
    +   if( pPager->pWal ){
    +-    rc = sqlite3WalCheckpoint(pPager->pWal, eMode,
    ++    rc = sqlite3WalCheckpoint(pPager->pWal, db, eMode,
    +         (eMode==SQLITE_CHECKPOINT_PASSIVE ? 0 : pPager->xBusyHandler),
    +         pPager->pBusyHandlerArg,
    +-        pPager->ckptSyncFlags, pPager->pageSize, (u8 *)pPager->pTmpSpace,
    ++        pPager->walSyncFlags, pPager->pageSize, (u8 *)pPager->pTmpSpace,
    +         pnLog, pnCkpt
    +     );
    +   }
    +@@ -50147,6 +55387,7 @@ SQLITE_PRIVATE int sqlite3PagerWalCallback(Pager *pPager){
    + */
    + SQLITE_PRIVATE int sqlite3PagerWalSupported(Pager *pPager){
    +   const sqlite3_io_methods *pMethods = pPager->fd->pMethods;
    ++  if( pPager->noLock ) return 0;
    +   return pPager->exclusiveMode || (pMethods->iVersion>=2 && pMethods->xShmMap);
    + }
    + 
    +@@ -50258,7 +55499,7 @@ SQLITE_PRIVATE int sqlite3PagerOpenWal(
    + ** error (SQLITE_BUSY) is returned and the log connection is not closed.
    + ** If successful, the EXCLUSIVE lock is not released before returning.
    + */
    +-SQLITE_PRIVATE int sqlite3PagerCloseWal(Pager *pPager){
    ++SQLITE_PRIVATE int sqlite3PagerCloseWal(Pager *pPager, sqlite3 *db){
    +   int rc = SQLITE_OK;
    + 
    +   assert( pPager->journalMode==PAGER_JOURNALMODE_WAL );
    +@@ -50286,15 +55527,58 @@ SQLITE_PRIVATE int sqlite3PagerCloseWal(Pager *pPager){
    +   if( rc==SQLITE_OK && pPager->pWal ){
    +     rc = pagerExclusiveLock(pPager);
    +     if( rc==SQLITE_OK ){
    +-      rc = sqlite3WalClose(pPager->pWal, pPager->ckptSyncFlags,
    ++      rc = sqlite3WalClose(pPager->pWal, db, pPager->walSyncFlags,
    +                            pPager->pageSize, (u8*)pPager->pTmpSpace);
    +       pPager->pWal = 0;
    +       pagerFixMaplimit(pPager);
    ++      if( rc && !pPager->exclusiveMode ) pagerUnlockDb(pPager, SHARED_LOCK);
    +     }
    +   }
    +   return rc;
    + }
    + 
    ++#ifdef SQLITE_ENABLE_SNAPSHOT
    ++/*
    ++** If this is a WAL database, obtain a snapshot handle for the snapshot
    ++** currently open. Otherwise, return an error.
    ++*/
    ++SQLITE_PRIVATE int sqlite3PagerSnapshotGet(Pager *pPager, sqlite3_snapshot **ppSnapshot){
    ++  int rc = SQLITE_ERROR;
    ++  if( pPager->pWal ){
    ++    rc = sqlite3WalSnapshotGet(pPager->pWal, ppSnapshot);
    ++  }
    ++  return rc;
    ++}
    ++
    ++/*
    ++** If this is a WAL database, store a pointer to pSnapshot. Next time a
    ++** read transaction is opened, attempt to read from the snapshot it 
    ++** identifies. If this is not a WAL database, return an error.
    ++*/
    ++SQLITE_PRIVATE int sqlite3PagerSnapshotOpen(Pager *pPager, sqlite3_snapshot *pSnapshot){
    ++  int rc = SQLITE_OK;
    ++  if( pPager->pWal ){
    ++    sqlite3WalSnapshotOpen(pPager->pWal, pSnapshot);
    ++  }else{
    ++    rc = SQLITE_ERROR;
    ++  }
    ++  return rc;
    ++}
    ++
    ++/*
    ++** If this is a WAL database, call sqlite3WalSnapshotRecover(). If this 
    ++** is not a WAL database, return an error.
    ++*/
    ++SQLITE_PRIVATE int sqlite3PagerSnapshotRecover(Pager *pPager){
    ++  int rc;
    ++  if( pPager->pWal ){
    ++    rc = sqlite3WalSnapshotRecover(pPager->pWal);
    ++  }else{
    ++    rc = SQLITE_ERROR;
    ++  }
    ++  return rc;
    ++}
    ++#endif /* SQLITE_ENABLE_SNAPSHOT */
    + #endif /* !SQLITE_OMIT_WAL */
    + 
    + #ifdef SQLITE_ENABLE_ZIPVFS
    +@@ -50311,7 +55595,6 @@ SQLITE_PRIVATE int sqlite3PagerWalFramesize(Pager *pPager){
    + }
    + #endif
    + 
    +-
    + #endif /* SQLITE_OMIT_DISKIO */
    + 
    + /************** End of pager.c ***********************************************/
    +@@ -50450,6 +55733,10 @@ SQLITE_PRIVATE int sqlite3PagerWalFramesize(Pager *pPager){
    + ** on a network filesystem.  All users of the database must be able to
    + ** share memory.
    + **
    ++** In the default unix and windows implementation, the wal-index is a mmapped
    ++** file whose name is the database name with a "-shm" suffix added.  For that
    ++** reason, the wal-index is sometimes called the "shm" file.
    ++**
    + ** The wal-index is transient.  After a crash, the wal-index can (and should
    + ** be) reconstructed from the original WAL file.  In fact, the VFS is required
    + ** to either truncate or zero the header of the wal-index when the last
    +@@ -50589,8 +55876,18 @@ SQLITE_PRIVATE int sqlite3WalTrace = 0;
    + #define WALINDEX_MAX_VERSION 3007000
    + 
    + /*
    +-** Indices of various locking bytes.   WAL_NREADER is the number
    +-** of available reader locks and should be at least 3.
    ++** Index numbers for various locking bytes.   WAL_NREADER is the number
    ++** of available reader locks and should be at least 3.  The default
    ++** is SQLITE_SHM_NLOCK==8 and  WAL_NREADER==5.
    ++**
    ++** Technically, the various VFSes are free to implement these locks however
    ++** they see fit.  However, compatibility is encouraged so that VFSes can
    ++** interoperate.  The standard implemention used on both unix and windows
    ++** is for the index number to indicate a byte offset into the
    ++** WalCkptInfo.aLock[] array in the wal-index header.  In other words, all
    ++** locks are on the shm file.  The WALINDEX_LOCK_OFFSET constant (which
    ++** should be 120) is the location in the shm file for the first locking
    ++** byte.
    + */
    + #define WAL_WRITE_LOCK         0
    + #define WAL_ALL_BUT_WRITE      1
    +@@ -50610,7 +55907,10 @@ typedef struct WalCkptInfo WalCkptInfo;
    + ** The following object holds a copy of the wal-index header content.
    + **
    + ** The actual header in the wal-index consists of two copies of this
    +-** object.
    ++** object followed by one instance of the WalCkptInfo object.
    ++** For all versions of SQLite through 3.10.0 and probably beyond,
    ++** the locking bytes (WalCkptInfo.aLock) start at offset 120 and
    ++** the total header size is 136 bytes.
    + **
    + ** The szPage value can be any power of 2 between 512 and 32768, inclusive.
    + ** Or it can be 1 to represent a 65536-byte page.  The latter case was
    +@@ -50643,6 +55943,16 @@ struct WalIndexHdr {
    + ** However, a WAL_WRITE_LOCK thread can move the value of nBackfill from
    + ** mxFrame back to zero when the WAL is reset.
    + **
    ++** nBackfillAttempted is the largest value of nBackfill that a checkpoint
    ++** has attempted to achieve.  Normally nBackfill==nBackfillAtempted, however
    ++** the nBackfillAttempted is set before any backfilling is done and the
    ++** nBackfill is only set after all backfilling completes.  So if a checkpoint
    ++** crashes, nBackfillAttempted might be larger than nBackfill.  The
    ++** WalIndexHdr.mxFrame must never be less than nBackfillAttempted.
    ++**
    ++** The aLock[] field is a set of bytes used for locking.  These bytes should
    ++** never be read or written.
    ++**
    + ** There is one entry in aReadMark[] for each reader lock.  If a reader
    + ** holds read-lock K, then the value in aReadMark[K] is no greater than
    + ** the mxFrame for that reader.  The value READMARK_NOT_USED (0xffffffff)
    +@@ -50682,6 +55992,9 @@ struct WalIndexHdr {
    + struct WalCkptInfo {
    +   u32 nBackfill;                  /* Number of WAL frames backfilled into DB */
    +   u32 aReadMark[WAL_NREADER];     /* Reader marks */
    ++  u8 aLock[SQLITE_SHM_NLOCK];     /* Reserved space for locks */
    ++  u32 nBackfillAttempted;         /* WAL frames perhaps written, or maybe not */
    ++  u32 notUsed0;                   /* Available for future enhancements */
    + };
    + #define READMARK_NOT_USED  0xffffffff
    + 
    +@@ -50691,15 +56004,13 @@ struct WalCkptInfo {
    + ** only support mandatory file-locks, we do not read or write data
    + ** from the region of the file on which locks are applied.
    + */
    +-#define WALINDEX_LOCK_OFFSET   (sizeof(WalIndexHdr)*2 + sizeof(WalCkptInfo))
    +-#define WALINDEX_LOCK_RESERVED 16
    +-#define WALINDEX_HDR_SIZE      (WALINDEX_LOCK_OFFSET+WALINDEX_LOCK_RESERVED)
    ++#define WALINDEX_LOCK_OFFSET (sizeof(WalIndexHdr)*2+offsetof(WalCkptInfo,aLock))
    ++#define WALINDEX_HDR_SIZE    (sizeof(WalIndexHdr)*2+sizeof(WalCkptInfo))
    + 
    + /* Size of header before each frame in wal */
    + #define WAL_FRAME_HDRSIZE 24
    + 
    + /* Size of write ahead log header, including checksum. */
    +-/* #define WAL_HDRSIZE 24 */
    + #define WAL_HDRSIZE 32
    + 
    + /* WAL magic value. Either this value, or the same value with the least
    +@@ -50745,13 +56056,18 @@ struct Wal {
    +   u8 truncateOnCommit;       /* True to truncate WAL file on commit */
    +   u8 syncHeader;             /* Fsync the WAL header if true */
    +   u8 padToSectorBoundary;    /* Pad transactions out to the next sector */
    ++  u8 bShmUnreliable;         /* SHM content is read-only and unreliable */
    +   WalIndexHdr hdr;           /* Wal-index header for current transaction */
    +   u32 minFrame;              /* Ignore wal frames before this one */
    ++  u32 iReCksum;              /* On commit, recalculate checksums from here */
    +   const char *zWalName;      /* Name of WAL file */
    +   u32 nCkpt;                 /* Checkpoint sequence counter in the wal-header */
    + #ifdef SQLITE_DEBUG
    +   u8 lockError;              /* True if a locking error has occurred */
    + #endif
    ++#ifdef SQLITE_ENABLE_SNAPSHOT
    ++  WalIndexHdr *pSnapshot;    /* Start transaction here if not NULL */
    ++#endif
    + };
    + 
    + /*
    +@@ -50830,6 +56146,11 @@ struct WalIterator {
    + ** is broken into pages of WALINDEX_PGSZ bytes. Wal-index pages are
    + ** numbered from zero.
    + **
    ++** If the wal-index is currently smaller the iPage pages then the size
    ++** of the wal-index might be increased, but only if it is safe to do
    ++** so.  It is safe to enlarge the wal-index if pWal->writeLock is true
    ++** or pWal->exclusiveMode==WAL_HEAPMEMORY_MODE.
    ++**
    + ** If this call is successful, *ppPage is set to point to the wal-index
    + ** page and SQLITE_OK is returned. If an error (an OOM or VFS error) occurs,
    + ** then an SQLite error code is returned and *ppPage is set to 0.
    +@@ -50844,7 +56165,7 @@ static int walIndexPage(Wal *pWal, int iPage, volatile u32 **ppPage){
    +     apNew = (volatile u32 **)sqlite3_realloc64((void *)pWal->apWiData, nByte);
    +     if( !apNew ){
    +       *ppPage = 0;
    +-      return SQLITE_NOMEM;
    ++      return SQLITE_NOMEM_BKPT;
    +     }
    +     memset((void*)&apNew[pWal->nWiData], 0,
    +            sizeof(u32*)*(iPage+1-pWal->nWiData));
    +@@ -50856,14 +56177,18 @@ static int walIndexPage(Wal *pWal, int iPage, volatile u32 **ppPage){
    +   if( pWal->apWiData[iPage]==0 ){
    +     if( pWal->exclusiveMode==WAL_HEAPMEMORY_MODE ){
    +       pWal->apWiData[iPage] = (u32 volatile *)sqlite3MallocZero(WALINDEX_PGSZ);
    +-      if( !pWal->apWiData[iPage] ) rc = SQLITE_NOMEM;
    ++      if( !pWal->apWiData[iPage] ) rc = SQLITE_NOMEM_BKPT;
    +     }else{
    +       rc = sqlite3OsShmMap(pWal->pDbFd, iPage, WALINDEX_PGSZ, 
    +           pWal->writeLock, (void volatile **)&pWal->apWiData[iPage]
    +       );
    +-      if( rc==SQLITE_READONLY ){
    ++      assert( pWal->apWiData[iPage]!=0 || rc!=SQLITE_OK || pWal->writeLock==0 );
    ++      testcase( pWal->apWiData[iPage]==0 && rc==SQLITE_OK );
    ++      if( (rc&0xff)==SQLITE_READONLY ){
    +         pWal->readOnly |= WAL_SHM_RDONLY;
    +-        rc = SQLITE_OK;
    ++        if( rc==SQLITE_READONLY ){
    ++          rc = SQLITE_OK;
    ++        }
    +       }
    +     }
    +   }
    +@@ -50997,14 +56322,18 @@ static void walEncodeFrame(
    +   assert( WAL_FRAME_HDRSIZE==24 );
    +   sqlite3Put4byte(&aFrame[0], iPage);
    +   sqlite3Put4byte(&aFrame[4], nTruncate);
    +-  memcpy(&aFrame[8], pWal->hdr.aSalt, 8);
    ++  if( pWal->iReCksum==0 ){
    ++    memcpy(&aFrame[8], pWal->hdr.aSalt, 8);
    + 
    +-  nativeCksum = (pWal->hdr.bigEndCksum==SQLITE_BIGENDIAN);
    +-  walChecksumBytes(nativeCksum, aFrame, 8, aCksum, aCksum);
    +-  walChecksumBytes(nativeCksum, aData, pWal->szPage, aCksum, aCksum);
    ++    nativeCksum = (pWal->hdr.bigEndCksum==SQLITE_BIGENDIAN);
    ++    walChecksumBytes(nativeCksum, aFrame, 8, aCksum, aCksum);
    ++    walChecksumBytes(nativeCksum, aData, pWal->szPage, aCksum, aCksum);
    + 
    +-  sqlite3Put4byte(&aFrame[16], aCksum[0]);
    +-  sqlite3Put4byte(&aFrame[20], aCksum[1]);
    ++    sqlite3Put4byte(&aFrame[16], aCksum[0]);
    ++    sqlite3Put4byte(&aFrame[20], aCksum[1]);
    ++  }else{
    ++    memset(&aFrame[8], 0, 16);
    ++  }
    + }
    + 
    + /*
    +@@ -51107,10 +56436,9 @@ static void walUnlockShared(Wal *pWal, int lockIdx){
    +                          SQLITE_SHM_UNLOCK | SQLITE_SHM_SHARED);
    +   WALTRACE(("WAL%p: release SHARED-%s\n", pWal, walLockName(lockIdx)));
    + }
    +-static int walLockExclusive(Wal *pWal, int lockIdx, int n, int fBlock){
    ++static int walLockExclusive(Wal *pWal, int lockIdx, int n){
    +   int rc;
    +   if( pWal->exclusiveMode ) return SQLITE_OK;
    +-  if( fBlock ) sqlite3OsFileControl(pWal->pDbFd, SQLITE_FCNTL_WAL_BLOCK, 0);
    +   rc = sqlite3OsShmLock(pWal->pDbFd, lockIdx, n,
    +                         SQLITE_SHM_LOCK | SQLITE_SHM_EXCLUSIVE);
    +   WALTRACE(("WAL%p: acquire EXCLUSIVE-%s cnt=%d %s\n", pWal,
    +@@ -51382,7 +56710,6 @@ static int walIndexRecover(Wal *pWal){
    +   i64 nSize;                      /* Size of log file */
    +   u32 aFrameCksum[2] = {0, 0};
    +   int iLock;                      /* Lock offset to lock for checkpoint */
    +-  int nLock;                      /* Number of locks to hold */
    + 
    +   /* Obtain an exclusive lock on all byte in the locking range not already
    +   ** locked by the caller. The caller is guaranteed to have locked the
    +@@ -51395,11 +56722,17 @@ static int walIndexRecover(Wal *pWal){
    +   assert( WAL_CKPT_LOCK==WAL_ALL_BUT_WRITE );
    +   assert( pWal->writeLock );
    +   iLock = WAL_ALL_BUT_WRITE + pWal->ckptLock;
    +-  nLock = SQLITE_SHM_NLOCK - iLock;
    +-  rc = walLockExclusive(pWal, iLock, nLock, 0);
    ++  rc = walLockExclusive(pWal, iLock, WAL_READ_LOCK(0)-iLock);
    ++  if( rc==SQLITE_OK ){
    ++    rc = walLockExclusive(pWal, WAL_READ_LOCK(1), WAL_NREADER-1);
    ++    if( rc!=SQLITE_OK ){
    ++      walUnlockExclusive(pWal, iLock, WAL_READ_LOCK(0)-iLock);
    ++    }
    ++  }
    +   if( rc ){
    +     return rc;
    +   }
    ++
    +   WALTRACE(("WAL%p: recovery begin...\n", pWal));
    + 
    +   memset(&pWal->hdr, 0, sizeof(WalIndexHdr));
    +@@ -51468,7 +56801,7 @@ static int walIndexRecover(Wal *pWal){
    +     szFrame = szPage + WAL_FRAME_HDRSIZE;
    +     aFrame = (u8 *)sqlite3_malloc64(szFrame);
    +     if( !aFrame ){
    +-      rc = SQLITE_NOMEM;
    ++      rc = SQLITE_NOMEM_BKPT;
    +       goto recovery_error;
    +     }
    +     aData = &aFrame[WAL_FRAME_HDRSIZE];
    +@@ -51517,6 +56850,7 @@ finished:
    +     */
    +     pInfo = walCkptInfo(pWal);
    +     pInfo->nBackfill = 0;
    ++    pInfo->nBackfillAttempted = pWal->hdr.mxFrame;
    +     pInfo->aReadMark[0] = 0;
    +     for(i=1; i<WAL_NREADER; i++) pInfo->aReadMark[i] = READMARK_NOT_USED;
    +     if( pWal->hdr.mxFrame ) pInfo->aReadMark[1] = pWal->hdr.mxFrame;
    +@@ -51536,7 +56870,8 @@ finished:
    + 
    + recovery_error:
    +   WALTRACE(("WAL%p: recovery %s\n", pWal, rc ? "failed" : "ok"));
    +-  walUnlockExclusive(pWal, iLock, nLock);
    ++  walUnlockExclusive(pWal, iLock, WAL_READ_LOCK(0)-iLock);
    ++  walUnlockExclusive(pWal, WAL_READ_LOCK(1), WAL_NREADER-1);
    +   return rc;
    + }
    + 
    +@@ -51544,13 +56879,14 @@ recovery_error:
    + ** Close an open wal-index.
    + */
    + static void walIndexClose(Wal *pWal, int isDelete){
    +-  if( pWal->exclusiveMode==WAL_HEAPMEMORY_MODE ){
    ++  if( pWal->exclusiveMode==WAL_HEAPMEMORY_MODE || pWal->bShmUnreliable ){
    +     int i;
    +     for(i=0; i<pWal->nWiData; i++){
    +       sqlite3_free((void *)pWal->apWiData[i]);
    +       pWal->apWiData[i] = 0;
    +     }
    +-  }else{
    ++  }
    ++  if( pWal->exclusiveMode!=WAL_HEAPMEMORY_MODE ){
    +     sqlite3OsShmUnmap(pWal->pDbFd, isDelete);
    +   }
    + }
    +@@ -51588,7 +56924,11 @@ SQLITE_PRIVATE int sqlite3WalOpen(
    +   /* In the amalgamation, the os_unix.c and os_win.c source files come before
    +   ** this source file.  Verify that the #defines of the locking byte offsets
    +   ** in os_unix.c and os_win.c agree with the WALINDEX_LOCK_OFFSET value.
    ++  ** For that matter, if the lock offset ever changes from its initial design
    ++  ** value of 120, we need to know that so there is an assert() to check it.
    +   */
    ++  assert( 120==WALINDEX_LOCK_OFFSET );
    ++  assert( 136==WALINDEX_HDR_SIZE );
    + #ifdef WIN_SHM_BASE
    +   assert( WIN_SHM_BASE==WALINDEX_LOCK_OFFSET );
    + #endif
    +@@ -51601,7 +56941,7 @@ SQLITE_PRIVATE int sqlite3WalOpen(
    +   *ppWal = 0;
    +   pRet = (Wal*)sqlite3MallocZero(sizeof(Wal) + pVfs->szOsFile);
    +   if( !pRet ){
    +-    return SQLITE_NOMEM;
    ++    return SQLITE_NOMEM_BKPT;
    +   }
    + 
    +   pRet->pVfs = pVfs;
    +@@ -51865,7 +57205,7 @@ static int walIteratorInit(Wal *pWal, WalIterator **pp){
    +         + iLast*sizeof(ht_slot);
    +   p = (WalIterator *)sqlite3_malloc64(nByte);
    +   if( !p ){
    +-    return SQLITE_NOMEM;
    ++    return SQLITE_NOMEM_BKPT;
    +   }
    +   memset(p, 0, nByte);
    +   p->nSegment = nSegment;
    +@@ -51877,7 +57217,7 @@ static int walIteratorInit(Wal *pWal, WalIterator **pp){
    +       sizeof(ht_slot) * (iLast>HASHTABLE_NPAGE?HASHTABLE_NPAGE:iLast)
    +   );
    +   if( !aTmp ){
    +-    rc = SQLITE_NOMEM;
    ++    rc = SQLITE_NOMEM_BKPT;
    +   }
    + 
    +   for(i=0; rc==SQLITE_OK && i<nSegment; i++){
    +@@ -51934,7 +57274,7 @@ static int walBusyLock(
    + ){
    +   int rc;
    +   do {
    +-    rc = walLockExclusive(pWal, lockIdx, n, 0);
    ++    rc = walLockExclusive(pWal, lockIdx, n);
    +   }while( xBusy && rc==SQLITE_BUSY && xBusy(pBusyArg) );
    +   return rc;
    + }
    +@@ -51974,6 +57314,7 @@ static void walRestartHdr(Wal *pWal, u32 salt1){
    +   memcpy(&pWal->hdr.aSalt[1], &salt1, 4);
    +   walIndexWriteHdr(pWal);
    +   pInfo->nBackfill = 0;
    ++  pInfo->nBackfillAttempted = 0;
    +   pInfo->aReadMark[1] = 0;
    +   for(i=2; i<WAL_NREADER; i++) pInfo->aReadMark[i] = READMARK_NOT_USED;
    +   assert( pInfo->aReadMark[0]==0 );
    +@@ -52012,6 +57353,7 @@ static void walRestartHdr(Wal *pWal, u32 salt1){
    + */
    + static int walCheckpoint(
    +   Wal *pWal,                      /* Wal connection */
    ++  sqlite3 *db,                    /* Check for interrupts on this handle */
    +   int eMode,                      /* One of PASSIVE, FULL or RESTART */
    +   int (*xBusy)(void*),            /* Function to call when busy */
    +   void *pBusyArg,                 /* Context argument for xBusyHandler */
    +@@ -52083,10 +57425,10 @@ static int walCheckpoint(
    +       i64 nSize;                    /* Current size of database file */
    +       u32 nBackfill = pInfo->nBackfill;
    + 
    ++      pInfo->nBackfillAttempted = mxSafeFrame;
    ++
    +       /* Sync the WAL to disk */
    +-      if( sync_flags ){
    +-        rc = sqlite3OsSync(pWal->pWalFd, sync_flags);
    +-      }
    ++      rc = sqlite3OsSync(pWal->pWalFd, CKPT_SYNC_FLAGS(sync_flags));
    + 
    +       /* If the database may grow as a result of this checkpoint, hint
    +       ** about the eventual size of the db file to the VFS layer.
    +@@ -52104,6 +57446,10 @@ static int walCheckpoint(
    +       while( rc==SQLITE_OK && 0==walIteratorNext(pIter, &iDbpage, &iFrame) ){
    +         i64 iOffset;
    +         assert( walFramePgno(pWal, iFrame)==iDbpage );
    ++        if( db->u1.isInterrupted ){
    ++          rc = db->mallocFailed ? SQLITE_NOMEM_BKPT : SQLITE_INTERRUPT;
    ++          break;
    ++        }
    +         if( iFrame<=nBackfill || iFrame>mxSafeFrame || iDbpage>mxPage ){
    +           continue;
    +         }
    +@@ -52123,8 +57469,8 @@ static int walCheckpoint(
    +           i64 szDb = pWal->hdr.nPage*(i64)szPage;
    +           testcase( IS_BIG_INT(szDb) );
    +           rc = sqlite3OsTruncate(pWal->pDbFd, szDb);
    +-          if( rc==SQLITE_OK && sync_flags ){
    +-            rc = sqlite3OsSync(pWal->pDbFd, sync_flags);
    ++          if( rc==SQLITE_OK ){
    ++            rc = sqlite3OsSync(pWal->pDbFd, CKPT_SYNC_FLAGS(sync_flags));
    +           }
    +         }
    +         if( rc==SQLITE_OK ){
    +@@ -52208,6 +57554,7 @@ static void walLimitSize(Wal *pWal, i64 nMax){
    + */
    + SQLITE_PRIVATE int sqlite3WalClose(
    +   Wal *pWal,                      /* Wal to close */
    ++  sqlite3 *db,                    /* For interrupt flag */
    +   int sync_flags,                 /* Flags to pass to OsSync() (or 0) */
    +   int nBuf,
    +   u8 *zBuf                        /* Buffer of at least nBuf bytes */
    +@@ -52224,13 +57571,14 @@ SQLITE_PRIVATE int sqlite3WalClose(
    +     **
    +     ** The EXCLUSIVE lock is not released before returning.
    +     */
    +-    rc = sqlite3OsLock(pWal->pDbFd, SQLITE_LOCK_EXCLUSIVE);
    +-    if( rc==SQLITE_OK ){
    ++    if( zBuf!=0
    ++     && SQLITE_OK==(rc = sqlite3OsLock(pWal->pDbFd, SQLITE_LOCK_EXCLUSIVE))
    ++    ){
    +       if( pWal->exclusiveMode==WAL_NORMAL_MODE ){
    +         pWal->exclusiveMode = WAL_EXCLUSIVE_MODE;
    +       }
    +-      rc = sqlite3WalCheckpoint(
    +-          pWal, SQLITE_CHECKPOINT_PASSIVE, 0, 0, sync_flags, nBuf, zBuf, 0, 0
    ++      rc = sqlite3WalCheckpoint(pWal, db, 
    ++          SQLITE_CHECKPOINT_PASSIVE, 0, 0, sync_flags, nBuf, zBuf, 0, 0
    +       );
    +       if( rc==SQLITE_OK ){
    +         int bPersist = -1;
    +@@ -52331,6 +57679,12 @@ static int walIndexTryHdr(Wal *pWal, int *pChanged){
    +   return 0;
    + }
    + 
    ++/*
    ++** This is the value that walTryBeginRead returns when it needs to
    ++** be retried.
    ++*/
    ++#define WAL_RETRY  (-1)
    ++
    + /*
    + ** Read the wal-index header from the wal-index and into pWal->hdr.
    + ** If the wal-header appears to be corrupt, try to reconstruct the
    +@@ -52354,9 +57708,29 @@ static int walIndexReadHdr(Wal *pWal, int *pChanged){
    +   assert( pChanged );
    +   rc = walIndexPage(pWal, 0, &page0);
    +   if( rc!=SQLITE_OK ){
    +-    return rc;
    +-  };
    +-  assert( page0 || pWal->writeLock==0 );
    ++    assert( rc!=SQLITE_READONLY ); /* READONLY changed to OK in walIndexPage */
    ++    if( rc==SQLITE_READONLY_CANTINIT ){
    ++      /* The SQLITE_READONLY_CANTINIT return means that the shared-memory
    ++      ** was openable but is not writable, and this thread is unable to
    ++      ** confirm that another write-capable connection has the shared-memory
    ++      ** open, and hence the content of the shared-memory is unreliable,
    ++      ** since the shared-memory might be inconsistent with the WAL file
    ++      ** and there is no writer on hand to fix it. */
    ++      assert( page0==0 );
    ++      assert( pWal->writeLock==0 );
    ++      assert( pWal->readOnly & WAL_SHM_RDONLY );
    ++      pWal->bShmUnreliable = 1;
    ++      pWal->exclusiveMode = WAL_HEAPMEMORY_MODE;
    ++      *pChanged = 1;
    ++    }else{
    ++      return rc; /* Any other non-OK return is just an error */
    ++    }
    ++  }else{
    ++    /* page0 can be NULL if the SHM is zero bytes in size and pWal->writeLock
    ++    ** is zero, which prevents the SHM from growing */
    ++    testcase( page0!=0 );
    ++  }
    ++  assert( page0!=0 || pWal->writeLock==0 );
    + 
    +   /* If the first page of the wal-index has been mapped, try to read the
    +   ** wal-index header immediately, without holding any lock. This usually
    +@@ -52370,12 +57744,12 @@ static int walIndexReadHdr(Wal *pWal, int *pChanged){
    +   */
    +   assert( badHdr==0 || pWal->writeLock==0 );
    +   if( badHdr ){
    +-    if( pWal->readOnly & WAL_SHM_RDONLY ){
    ++    if( pWal->bShmUnreliable==0 && (pWal->readOnly & WAL_SHM_RDONLY) ){
    +       if( SQLITE_OK==(rc = walLockShared(pWal, WAL_WRITE_LOCK)) ){
    +         walUnlockShared(pWal, WAL_WRITE_LOCK);
    +         rc = SQLITE_READONLY_RECOVERY;
    +       }
    +-    }else if( SQLITE_OK==(rc = walLockExclusive(pWal, WAL_WRITE_LOCK, 1, 1)) ){
    ++    }else if( SQLITE_OK==(rc = walLockExclusive(pWal, WAL_WRITE_LOCK, 1)) ){
    +       pWal->writeLock = 1;
    +       if( SQLITE_OK==(rc = walIndexPage(pWal, 0, &page0)) ){
    +         badHdr = walIndexTryHdr(pWal, pChanged);
    +@@ -52400,15 +57774,193 @@ static int walIndexReadHdr(Wal *pWal, int *pChanged){
    +   if( badHdr==0 && pWal->hdr.iVersion!=WALINDEX_MAX_VERSION ){
    +     rc = SQLITE_CANTOPEN_BKPT;
    +   }
    ++  if( pWal->bShmUnreliable ){
    ++    if( rc!=SQLITE_OK ){
    ++      walIndexClose(pWal, 0);
    ++      pWal->bShmUnreliable = 0;
    ++      assert( pWal->nWiData>0 && pWal->apWiData[0]==0 );
    ++      /* walIndexRecover() might have returned SHORT_READ if a concurrent
    ++      ** writer truncated the WAL out from under it.  If that happens, it
    ++      ** indicates that a writer has fixed the SHM file for us, so retry */
    ++      if( rc==SQLITE_IOERR_SHORT_READ ) rc = WAL_RETRY;
    ++    }
    ++    pWal->exclusiveMode = WAL_NORMAL_MODE;
    ++  }
    + 
    +   return rc;
    + }
    + 
    + /*
    +-** This is the value that walTryBeginRead returns when it needs to
    +-** be retried.
    ++** Open a transaction in a connection where the shared-memory is read-only
    ++** and where we cannot verify that there is a separate write-capable connection
    ++** on hand to keep the shared-memory up-to-date with the WAL file.
    ++**
    ++** This can happen, for example, when the shared-memory is implemented by
    ++** memory-mapping a *-shm file, where a prior writer has shut down and
    ++** left the *-shm file on disk, and now the present connection is trying
    ++** to use that database but lacks write permission on the *-shm file.
    ++** Other scenarios are also possible, depending on the VFS implementation.
    ++**
    ++** Precondition:
    ++**
    ++**    The *-wal file has been read and an appropriate wal-index has been
    ++**    constructed in pWal->apWiData[] using heap memory instead of shared
    ++**    memory. 
    ++**
    ++** If this function returns SQLITE_OK, then the read transaction has
    ++** been successfully opened. In this case output variable (*pChanged) 
    ++** is set to true before returning if the caller should discard the
    ++** contents of the page cache before proceeding. Or, if it returns 
    ++** WAL_RETRY, then the heap memory wal-index has been discarded and 
    ++** the caller should retry opening the read transaction from the 
    ++** beginning (including attempting to map the *-shm file). 
    ++**
    ++** If an error occurs, an SQLite error code is returned.
    + */
    +-#define WAL_RETRY  (-1)
    ++static int walBeginShmUnreliable(Wal *pWal, int *pChanged){
    ++  i64 szWal;                      /* Size of wal file on disk in bytes */
    ++  i64 iOffset;                    /* Current offset when reading wal file */
    ++  u8 aBuf[WAL_HDRSIZE];           /* Buffer to load WAL header into */
    ++  u8 *aFrame = 0;                 /* Malloc'd buffer to load entire frame */
    ++  int szFrame;                    /* Number of bytes in buffer aFrame[] */
    ++  u8 *aData;                      /* Pointer to data part of aFrame buffer */
    ++  volatile void *pDummy;          /* Dummy argument for xShmMap */
    ++  int rc;                         /* Return code */
    ++  u32 aSaveCksum[2];              /* Saved copy of pWal->hdr.aFrameCksum */
    ++
    ++  assert( pWal->bShmUnreliable );
    ++  assert( pWal->readOnly & WAL_SHM_RDONLY );
    ++  assert( pWal->nWiData>0 && pWal->apWiData[0] );
    ++
    ++  /* Take WAL_READ_LOCK(0). This has the effect of preventing any
    ++  ** writers from running a checkpoint, but does not stop them
    ++  ** from running recovery.  */
    ++  rc = walLockShared(pWal, WAL_READ_LOCK(0));
    ++  if( rc!=SQLITE_OK ){
    ++    if( rc==SQLITE_BUSY ) rc = WAL_RETRY;
    ++    goto begin_unreliable_shm_out;
    ++  }
    ++  pWal->readLock = 0;
    ++
    ++  /* Check to see if a separate writer has attached to the shared-memory area,
    ++  ** thus making the shared-memory "reliable" again.  Do this by invoking
    ++  ** the xShmMap() routine of the VFS and looking to see if the return
    ++  ** is SQLITE_READONLY instead of SQLITE_READONLY_CANTINIT.
    ++  **
    ++  ** If the shared-memory is now "reliable" return WAL_RETRY, which will
    ++  ** cause the heap-memory WAL-index to be discarded and the actual
    ++  ** shared memory to be used in its place.
    ++  **
    ++  ** This step is important because, even though this connection is holding
    ++  ** the WAL_READ_LOCK(0) which prevents a checkpoint, a writer might
    ++  ** have already checkpointed the WAL file and, while the current
    ++  ** is active, wrap the WAL and start overwriting frames that this
    ++  ** process wants to use.
    ++  **
    ++  ** Once sqlite3OsShmMap() has been called for an sqlite3_file and has
    ++  ** returned any SQLITE_READONLY value, it must return only SQLITE_READONLY
    ++  ** or SQLITE_READONLY_CANTINIT or some error for all subsequent invocations,
    ++  ** even if some external agent does a "chmod" to make the shared-memory
    ++  ** writable by us, until sqlite3OsShmUnmap() has been called.
    ++  ** This is a requirement on the VFS implementation.
    ++   */
    ++  rc = sqlite3OsShmMap(pWal->pDbFd, 0, WALINDEX_PGSZ, 0, &pDummy);
    ++  assert( rc!=SQLITE_OK ); /* SQLITE_OK not possible for read-only connection */
    ++  if( rc!=SQLITE_READONLY_CANTINIT ){
    ++    rc = (rc==SQLITE_READONLY ? WAL_RETRY : rc);
    ++    goto begin_unreliable_shm_out;
    ++  }
    ++
    ++  /* We reach this point only if the real shared-memory is still unreliable.
    ++  ** Assume the in-memory WAL-index substitute is correct and load it
    ++  ** into pWal->hdr.
    ++  */
    ++  memcpy(&pWal->hdr, (void*)walIndexHdr(pWal), sizeof(WalIndexHdr));
    ++
    ++  /* Make sure some writer hasn't come in and changed the WAL file out
    ++  ** from under us, then disconnected, while we were not looking.
    ++  */
    ++  rc = sqlite3OsFileSize(pWal->pWalFd, &szWal);
    ++  if( rc!=SQLITE_OK ){
    ++    goto begin_unreliable_shm_out;
    ++  }
    ++  if( szWal<WAL_HDRSIZE ){
    ++    /* If the wal file is too small to contain a wal-header and the
    ++    ** wal-index header has mxFrame==0, then it must be safe to proceed
    ++    ** reading the database file only. However, the page cache cannot
    ++    ** be trusted, as a read/write connection may have connected, written
    ++    ** the db, run a checkpoint, truncated the wal file and disconnected
    ++    ** since this client's last read transaction.  */
    ++    *pChanged = 1;
    ++    rc = (pWal->hdr.mxFrame==0 ? SQLITE_OK : WAL_RETRY);
    ++    goto begin_unreliable_shm_out;
    ++  }
    ++
    ++  /* Check the salt keys at the start of the wal file still match. */
    ++  rc = sqlite3OsRead(pWal->pWalFd, aBuf, WAL_HDRSIZE, 0);
    ++  if( rc!=SQLITE_OK ){
    ++    goto begin_unreliable_shm_out;
    ++  }
    ++  if( memcmp(&pWal->hdr.aSalt, &aBuf[16], 8) ){
    ++    /* Some writer has wrapped the WAL file while we were not looking.
    ++    ** Return WAL_RETRY which will cause the in-memory WAL-index to be
    ++    ** rebuilt. */
    ++    rc = WAL_RETRY;
    ++    goto begin_unreliable_shm_out;
    ++  }
    ++
    ++  /* Allocate a buffer to read frames into */
    ++  szFrame = pWal->hdr.szPage + WAL_FRAME_HDRSIZE;
    ++  aFrame = (u8 *)sqlite3_malloc64(szFrame);
    ++  if( aFrame==0 ){
    ++    rc = SQLITE_NOMEM_BKPT;
    ++    goto begin_unreliable_shm_out;
    ++  }
    ++  aData = &aFrame[WAL_FRAME_HDRSIZE];
    ++
    ++  /* Check to see if a complete transaction has been appended to the
    ++  ** wal file since the heap-memory wal-index was created. If so, the
    ++  ** heap-memory wal-index is discarded and WAL_RETRY returned to
    ++  ** the caller.  */
    ++  aSaveCksum[0] = pWal->hdr.aFrameCksum[0];
    ++  aSaveCksum[1] = pWal->hdr.aFrameCksum[1];
    ++  for(iOffset=walFrameOffset(pWal->hdr.mxFrame+1, pWal->hdr.szPage); 
    ++      iOffset+szFrame<=szWal; 
    ++      iOffset+=szFrame
    ++  ){
    ++    u32 pgno;                   /* Database page number for frame */
    ++    u32 nTruncate;              /* dbsize field from frame header */
    ++
    ++    /* Read and decode the next log frame. */
    ++    rc = sqlite3OsRead(pWal->pWalFd, aFrame, szFrame, iOffset);
    ++    if( rc!=SQLITE_OK ) break;
    ++    if( !walDecodeFrame(pWal, &pgno, &nTruncate, aData, aFrame) ) break;
    ++
    ++    /* If nTruncate is non-zero, then a complete transaction has been
    ++    ** appended to this wal file. Set rc to WAL_RETRY and break out of
    ++    ** the loop.  */
    ++    if( nTruncate ){
    ++      rc = WAL_RETRY;
    ++      break;
    ++    }
    ++  }
    ++  pWal->hdr.aFrameCksum[0] = aSaveCksum[0];
    ++  pWal->hdr.aFrameCksum[1] = aSaveCksum[1];
    ++
    ++ begin_unreliable_shm_out:
    ++  sqlite3_free(aFrame);
    ++  if( rc!=SQLITE_OK ){
    ++    int i;
    ++    for(i=0; i<pWal->nWiData; i++){
    ++      sqlite3_free((void*)pWal->apWiData[i]);
    ++      pWal->apWiData[i] = 0;
    ++    }
    ++    pWal->bShmUnreliable = 0;
    ++    sqlite3WalEndReadTransaction(pWal);
    ++    *pChanged = 1;
    ++  }
    ++  return rc;
    ++}
    + 
    + /*
    + ** Attempt to start a read transaction.  This might fail due to a race or
    +@@ -52424,7 +57976,7 @@ static int walIndexReadHdr(Wal *pWal, int *pChanged){
    + ** checkpointed.  If useWal==0 then this routine calls walIndexReadHdr() 
    + ** to make a copy of the wal-index header into pWal->hdr.  If the 
    + ** wal-index header has changed, *pChanged is set to 1 (as an indication 
    +-** to the caller that the local paget cache is obsolete and needs to be 
    ++** to the caller that the local page cache is obsolete and needs to be 
    + ** flushed.)  When useWal==1, the wal-index header is assumed to already
    + ** be loaded and the pChanged parameter is unused.
    + **
    +@@ -52466,9 +58018,13 @@ static int walTryBeginRead(Wal *pWal, int *pChanged, int useWal, int cnt){
    +   int mxI;                        /* Index of largest aReadMark[] value */
    +   int i;                          /* Loop counter */
    +   int rc = SQLITE_OK;             /* Return code  */
    ++  u32 mxFrame;                    /* Wal frame to lock to */
    + 
    +   assert( pWal->readLock<0 );     /* Not currently locked */
    + 
    ++  /* useWal may only be set for read/write connections */
    ++  assert( (pWal->readOnly & WAL_SHM_RDONLY)==0 || useWal==0 );
    ++
    +   /* Take steps to avoid spinning forever if there is a protocol error.
    +   **
    +   ** Circumstances that cause a RETRY should only last for the briefest
    +@@ -52497,7 +58053,10 @@ static int walTryBeginRead(Wal *pWal, int *pChanged, int useWal, int cnt){
    +   }
    + 
    +   if( !useWal ){
    +-    rc = walIndexReadHdr(pWal, pChanged);
    ++    assert( rc==SQLITE_OK );
    ++    if( pWal->bShmUnreliable==0 ){
    ++      rc = walIndexReadHdr(pWal, pChanged);
    ++    }
    +     if( rc==SQLITE_BUSY ){
    +       /* If there is not a recovery running in another thread or process
    +       ** then convert BUSY errors to WAL_RETRY.  If recovery is known to
    +@@ -52526,10 +58085,19 @@ static int walTryBeginRead(Wal *pWal, int *pChanged, int useWal, int cnt){
    +     if( rc!=SQLITE_OK ){
    +       return rc;
    +     }
    ++    else if( pWal->bShmUnreliable ){
    ++      return walBeginShmUnreliable(pWal, pChanged);
    ++    }
    +   }
    + 
    ++  assert( pWal->nWiData>0 );
    ++  assert( pWal->apWiData[0]!=0 );
    +   pInfo = walCkptInfo(pWal);
    +-  if( !useWal && pInfo->nBackfill==pWal->hdr.mxFrame ){
    ++  if( !useWal && pInfo->nBackfill==pWal->hdr.mxFrame
    ++#ifdef SQLITE_ENABLE_SNAPSHOT
    ++   && (pWal->pSnapshot==0 || pWal->hdr.mxFrame==0)
    ++#endif
    ++  ){
    +     /* The WAL has been completely backfilled (or it is empty).
    +     ** and can be safely ignored.
    +     */
    +@@ -52567,88 +58135,169 @@ static int walTryBeginRead(Wal *pWal, int *pChanged, int useWal, int cnt){
    +   */
    +   mxReadMark = 0;
    +   mxI = 0;
    ++  mxFrame = pWal->hdr.mxFrame;
    ++#ifdef SQLITE_ENABLE_SNAPSHOT
    ++  if( pWal->pSnapshot && pWal->pSnapshot->mxFrame<mxFrame ){
    ++    mxFrame = pWal->pSnapshot->mxFrame;
    ++  }
    ++#endif
    +   for(i=1; i<WAL_NREADER; i++){
    +     u32 thisMark = pInfo->aReadMark[i];
    +-    if( mxReadMark<=thisMark && thisMark<=pWal->hdr.mxFrame ){
    ++    if( mxReadMark<=thisMark && thisMark<=mxFrame ){
    +       assert( thisMark!=READMARK_NOT_USED );
    +       mxReadMark = thisMark;
    +       mxI = i;
    +     }
    +   }
    +-  /* There was once an "if" here. The extra "{" is to preserve indentation. */
    +-  {
    +-    if( (pWal->readOnly & WAL_SHM_RDONLY)==0
    +-     && (mxReadMark<pWal->hdr.mxFrame || mxI==0)
    +-    ){
    +-      for(i=1; i<WAL_NREADER; i++){
    +-        rc = walLockExclusive(pWal, WAL_READ_LOCK(i), 1, 0);
    +-        if( rc==SQLITE_OK ){
    +-          mxReadMark = pInfo->aReadMark[i] = pWal->hdr.mxFrame;
    +-          mxI = i;
    +-          walUnlockExclusive(pWal, WAL_READ_LOCK(i), 1);
    +-          break;
    +-        }else if( rc!=SQLITE_BUSY ){
    +-          return rc;
    +-        }
    ++  if( (pWal->readOnly & WAL_SHM_RDONLY)==0
    ++   && (mxReadMark<mxFrame || mxI==0)
    ++  ){
    ++    for(i=1; i<WAL_NREADER; i++){
    ++      rc = walLockExclusive(pWal, WAL_READ_LOCK(i), 1);
    ++      if( rc==SQLITE_OK ){
    ++        mxReadMark = pInfo->aReadMark[i] = mxFrame;
    ++        mxI = i;
    ++        walUnlockExclusive(pWal, WAL_READ_LOCK(i), 1);
    ++        break;
    ++      }else if( rc!=SQLITE_BUSY ){
    ++        return rc;
    +       }
    +     }
    +-    if( mxI==0 ){
    +-      assert( rc==SQLITE_BUSY || (pWal->readOnly & WAL_SHM_RDONLY)!=0 );
    +-      return rc==SQLITE_BUSY ? WAL_RETRY : SQLITE_READONLY_CANTLOCK;
    +-    }
    ++  }
    ++  if( mxI==0 ){
    ++    assert( rc==SQLITE_BUSY || (pWal->readOnly & WAL_SHM_RDONLY)!=0 );
    ++    return rc==SQLITE_BUSY ? WAL_RETRY : SQLITE_READONLY_CANTINIT;
    ++  }
    + 
    +-    rc = walLockShared(pWal, WAL_READ_LOCK(mxI));
    +-    if( rc ){
    +-      return rc==SQLITE_BUSY ? WAL_RETRY : rc;
    +-    }
    +-    /* Now that the read-lock has been obtained, check that neither the
    +-    ** value in the aReadMark[] array or the contents of the wal-index
    +-    ** header have changed.
    +-    **
    +-    ** It is necessary to check that the wal-index header did not change
    +-    ** between the time it was read and when the shared-lock was obtained
    +-    ** on WAL_READ_LOCK(mxI) was obtained to account for the possibility
    +-    ** that the log file may have been wrapped by a writer, or that frames
    +-    ** that occur later in the log than pWal->hdr.mxFrame may have been
    +-    ** copied into the database by a checkpointer. If either of these things
    +-    ** happened, then reading the database with the current value of
    +-    ** pWal->hdr.mxFrame risks reading a corrupted snapshot. So, retry
    +-    ** instead.
    +-    **
    +-    ** Before checking that the live wal-index header has not changed
    +-    ** since it was read, set Wal.minFrame to the first frame in the wal
    +-    ** file that has not yet been checkpointed. This client will not need
    +-    ** to read any frames earlier than minFrame from the wal file - they
    +-    ** can be safely read directly from the database file.
    +-    **
    +-    ** Because a ShmBarrier() call is made between taking the copy of 
    +-    ** nBackfill and checking that the wal-header in shared-memory still
    +-    ** matches the one cached in pWal->hdr, it is guaranteed that the 
    +-    ** checkpointer that set nBackfill was not working with a wal-index
    +-    ** header newer than that cached in pWal->hdr. If it were, that could
    +-    ** cause a problem. The checkpointer could omit to checkpoint
    +-    ** a version of page X that lies before pWal->minFrame (call that version
    +-    ** A) on the basis that there is a newer version (version B) of the same
    +-    ** page later in the wal file. But if version B happens to like past
    +-    ** frame pWal->hdr.mxFrame - then the client would incorrectly assume
    +-    ** that it can read version A from the database file. However, since
    +-    ** we can guarantee that the checkpointer that set nBackfill could not
    +-    ** see any pages past pWal->hdr.mxFrame, this problem does not come up.
    +-    */
    +-    pWal->minFrame = pInfo->nBackfill+1;
    +-    walShmBarrier(pWal);
    +-    if( pInfo->aReadMark[mxI]!=mxReadMark
    +-     || memcmp((void *)walIndexHdr(pWal), &pWal->hdr, sizeof(WalIndexHdr))
    +-    ){
    +-      walUnlockShared(pWal, WAL_READ_LOCK(mxI));
    +-      return WAL_RETRY;
    +-    }else{
    +-      assert( mxReadMark<=pWal->hdr.mxFrame );
    +-      pWal->readLock = (i16)mxI;
    ++  rc = walLockShared(pWal, WAL_READ_LOCK(mxI));
    ++  if( rc ){
    ++    return rc==SQLITE_BUSY ? WAL_RETRY : rc;
    ++  }
    ++  /* Now that the read-lock has been obtained, check that neither the
    ++  ** value in the aReadMark[] array or the contents of the wal-index
    ++  ** header have changed.
    ++  **
    ++  ** It is necessary to check that the wal-index header did not change
    ++  ** between the time it was read and when the shared-lock was obtained
    ++  ** on WAL_READ_LOCK(mxI) was obtained to account for the possibility
    ++  ** that the log file may have been wrapped by a writer, or that frames
    ++  ** that occur later in the log than pWal->hdr.mxFrame may have been
    ++  ** copied into the database by a checkpointer. If either of these things
    ++  ** happened, then reading the database with the current value of
    ++  ** pWal->hdr.mxFrame risks reading a corrupted snapshot. So, retry
    ++  ** instead.
    ++  **
    ++  ** Before checking that the live wal-index header has not changed
    ++  ** since it was read, set Wal.minFrame to the first frame in the wal
    ++  ** file that has not yet been checkpointed. This client will not need
    ++  ** to read any frames earlier than minFrame from the wal file - they
    ++  ** can be safely read directly from the database file.
    ++  **
    ++  ** Because a ShmBarrier() call is made between taking the copy of 
    ++  ** nBackfill and checking that the wal-header in shared-memory still
    ++  ** matches the one cached in pWal->hdr, it is guaranteed that the 
    ++  ** checkpointer that set nBackfill was not working with a wal-index
    ++  ** header newer than that cached in pWal->hdr. If it were, that could
    ++  ** cause a problem. The checkpointer could omit to checkpoint
    ++  ** a version of page X that lies before pWal->minFrame (call that version
    ++  ** A) on the basis that there is a newer version (version B) of the same
    ++  ** page later in the wal file. But if version B happens to like past
    ++  ** frame pWal->hdr.mxFrame - then the client would incorrectly assume
    ++  ** that it can read version A from the database file. However, since
    ++  ** we can guarantee that the checkpointer that set nBackfill could not
    ++  ** see any pages past pWal->hdr.mxFrame, this problem does not come up.
    ++  */
    ++  pWal->minFrame = pInfo->nBackfill+1;
    ++  walShmBarrier(pWal);
    ++  if( pInfo->aReadMark[mxI]!=mxReadMark
    ++   || memcmp((void *)walIndexHdr(pWal), &pWal->hdr, sizeof(WalIndexHdr))
    ++  ){
    ++    walUnlockShared(pWal, WAL_READ_LOCK(mxI));
    ++    return WAL_RETRY;
    ++  }else{
    ++    assert( mxReadMark<=pWal->hdr.mxFrame );
    ++    pWal->readLock = (i16)mxI;
    ++  }
    ++  return rc;
    ++}
    ++
    ++#ifdef SQLITE_ENABLE_SNAPSHOT
    ++/*
    ++** Attempt to reduce the value of the WalCkptInfo.nBackfillAttempted 
    ++** variable so that older snapshots can be accessed. To do this, loop
    ++** through all wal frames from nBackfillAttempted to (nBackfill+1), 
    ++** comparing their content to the corresponding page with the database
    ++** file, if any. Set nBackfillAttempted to the frame number of the
    ++** first frame for which the wal file content matches the db file.
    ++**
    ++** This is only really safe if the file-system is such that any page 
    ++** writes made by earlier checkpointers were atomic operations, which 
    ++** is not always true. It is also possible that nBackfillAttempted
    ++** may be left set to a value larger than expected, if a wal frame
    ++** contains content that duplicate of an earlier version of the same
    ++** page.
    ++**
    ++** SQLITE_OK is returned if successful, or an SQLite error code if an
    ++** error occurs. It is not an error if nBackfillAttempted cannot be
    ++** decreased at all.
    ++*/
    ++SQLITE_PRIVATE int sqlite3WalSnapshotRecover(Wal *pWal){
    ++  int rc;
    ++
    ++  assert( pWal->readLock>=0 );
    ++  rc = walLockExclusive(pWal, WAL_CKPT_LOCK, 1);
    ++  if( rc==SQLITE_OK ){
    ++    volatile WalCkptInfo *pInfo = walCkptInfo(pWal);
    ++    int szPage = (int)pWal->szPage;
    ++    i64 szDb;                   /* Size of db file in bytes */
    ++
    ++    rc = sqlite3OsFileSize(pWal->pDbFd, &szDb);
    ++    if( rc==SQLITE_OK ){
    ++      void *pBuf1 = sqlite3_malloc(szPage);
    ++      void *pBuf2 = sqlite3_malloc(szPage);
    ++      if( pBuf1==0 || pBuf2==0 ){
    ++        rc = SQLITE_NOMEM;
    ++      }else{
    ++        u32 i = pInfo->nBackfillAttempted;
    ++        for(i=pInfo->nBackfillAttempted; i>pInfo->nBackfill; i--){
    ++          volatile ht_slot *dummy;
    ++          volatile u32 *aPgno;      /* Array of page numbers */
    ++          u32 iZero;                /* Frame corresponding to aPgno[0] */
    ++          u32 pgno;                 /* Page number in db file */
    ++          i64 iDbOff;               /* Offset of db file entry */
    ++          i64 iWalOff;              /* Offset of wal file entry */
    ++
    ++          rc = walHashGet(pWal, walFramePage(i), &dummy, &aPgno, &iZero);
    ++          if( rc!=SQLITE_OK ) break;
    ++          pgno = aPgno[i-iZero];
    ++          iDbOff = (i64)(pgno-1) * szPage;
    ++
    ++          if( iDbOff+szPage<=szDb ){
    ++            iWalOff = walFrameOffset(i, szPage) + WAL_FRAME_HDRSIZE;
    ++            rc = sqlite3OsRead(pWal->pWalFd, pBuf1, szPage, iWalOff);
    ++
    ++            if( rc==SQLITE_OK ){
    ++              rc = sqlite3OsRead(pWal->pDbFd, pBuf2, szPage, iDbOff);
    ++            }
    ++
    ++            if( rc!=SQLITE_OK || 0==memcmp(pBuf1, pBuf2, szPage) ){
    ++              break;
    ++            }
    ++          }
    ++
    ++          pInfo->nBackfillAttempted = i-1;
    ++        }
    ++      }
    ++
    ++      sqlite3_free(pBuf1);
    ++      sqlite3_free(pBuf2);
    +     }
    ++    walUnlockExclusive(pWal, WAL_CKPT_LOCK, 1);
    +   }
    ++
    +   return rc;
    + }
    ++#endif /* SQLITE_ENABLE_SNAPSHOT */
    + 
    + /*
    + ** Begin a read transaction on the database.
    +@@ -52668,6 +58317,14 @@ SQLITE_PRIVATE int sqlite3WalBeginReadTransaction(Wal *pWal, int *pChanged){
    +   int rc;                         /* Return code */
    +   int cnt = 0;                    /* Number of TryBeginRead attempts */
    + 
    ++#ifdef SQLITE_ENABLE_SNAPSHOT
    ++  int bChanged = 0;
    ++  WalIndexHdr *pSnapshot = pWal->pSnapshot;
    ++  if( pSnapshot && memcmp(pSnapshot, &pWal->hdr, sizeof(WalIndexHdr))!=0 ){
    ++    bChanged = 1;
    ++  }
    ++#endif
    ++
    +   do{
    +     rc = walTryBeginRead(pWal, pChanged, 0, ++cnt);
    +   }while( rc==WAL_RETRY );
    +@@ -52675,6 +58332,70 @@ SQLITE_PRIVATE int sqlite3WalBeginReadTransaction(Wal *pWal, int *pChanged){
    +   testcase( (rc&0xff)==SQLITE_IOERR );
    +   testcase( rc==SQLITE_PROTOCOL );
    +   testcase( rc==SQLITE_OK );
    ++
    ++#ifdef SQLITE_ENABLE_SNAPSHOT
    ++  if( rc==SQLITE_OK ){
    ++    if( pSnapshot && memcmp(pSnapshot, &pWal->hdr, sizeof(WalIndexHdr))!=0 ){
    ++      /* At this point the client has a lock on an aReadMark[] slot holding
    ++      ** a value equal to or smaller than pSnapshot->mxFrame, but pWal->hdr
    ++      ** is populated with the wal-index header corresponding to the head
    ++      ** of the wal file. Verify that pSnapshot is still valid before
    ++      ** continuing.  Reasons why pSnapshot might no longer be valid:
    ++      **
    ++      **    (1)  The WAL file has been reset since the snapshot was taken.
    ++      **         In this case, the salt will have changed.
    ++      **
    ++      **    (2)  A checkpoint as been attempted that wrote frames past
    ++      **         pSnapshot->mxFrame into the database file.  Note that the
    ++      **         checkpoint need not have completed for this to cause problems.
    ++      */
    ++      volatile WalCkptInfo *pInfo = walCkptInfo(pWal);
    ++
    ++      assert( pWal->readLock>0 || pWal->hdr.mxFrame==0 );
    ++      assert( pInfo->aReadMark[pWal->readLock]<=pSnapshot->mxFrame );
    ++
    ++      /* It is possible that there is a checkpointer thread running 
    ++      ** concurrent with this code. If this is the case, it may be that the
    ++      ** checkpointer has already determined that it will checkpoint 
    ++      ** snapshot X, where X is later in the wal file than pSnapshot, but 
    ++      ** has not yet set the pInfo->nBackfillAttempted variable to indicate 
    ++      ** its intent. To avoid the race condition this leads to, ensure that
    ++      ** there is no checkpointer process by taking a shared CKPT lock 
    ++      ** before checking pInfo->nBackfillAttempted.  
    ++      **
    ++      ** TODO: Does the aReadMark[] lock prevent a checkpointer from doing
    ++      **       this already?
    ++      */
    ++      rc = walLockShared(pWal, WAL_CKPT_LOCK);
    ++
    ++      if( rc==SQLITE_OK ){
    ++        /* Check that the wal file has not been wrapped. Assuming that it has
    ++        ** not, also check that no checkpointer has attempted to checkpoint any
    ++        ** frames beyond pSnapshot->mxFrame. If either of these conditions are
    ++        ** true, return SQLITE_BUSY_SNAPSHOT. Otherwise, overwrite pWal->hdr
    ++        ** with *pSnapshot and set *pChanged as appropriate for opening the
    ++        ** snapshot.  */
    ++        if( !memcmp(pSnapshot->aSalt, pWal->hdr.aSalt, sizeof(pWal->hdr.aSalt))
    ++         && pSnapshot->mxFrame>=pInfo->nBackfillAttempted
    ++        ){
    ++          assert( pWal->readLock>0 );
    ++          memcpy(&pWal->hdr, pSnapshot, sizeof(WalIndexHdr));
    ++          *pChanged = bChanged;
    ++        }else{
    ++          rc = SQLITE_BUSY_SNAPSHOT;
    ++        }
    ++
    ++        /* Release the shared CKPT lock obtained above. */
    ++        walUnlockShared(pWal, WAL_CKPT_LOCK);
    ++      }
    ++
    ++
    ++      if( rc!=SQLITE_OK ){
    ++        sqlite3WalEndReadTransaction(pWal);
    ++      }
    ++    }
    ++  }
    ++#endif
    +   return rc;
    + }
    + 
    +@@ -52717,7 +58438,7 @@ SQLITE_PRIVATE int sqlite3WalFindFrame(
    +   ** then the WAL is ignored by the reader so return early, as if the 
    +   ** WAL were empty.
    +   */
    +-  if( iLast==0 || pWal->readLock==0 ){
    ++  if( iLast==0 || (pWal->readLock==0 && pWal->bShmUnreliable==0) ){
    +     *piRead = 0;
    +     return SQLITE_OK;
    +   }
    +@@ -52780,8 +58501,8 @@ SQLITE_PRIVATE int sqlite3WalFindFrame(
    +   {
    +     u32 iRead2 = 0;
    +     u32 iTest;
    +-    assert( pWal->minFrame>0 );
    +-    for(iTest=iLast; iTest>=pWal->minFrame; iTest--){
    ++    assert( pWal->bShmUnreliable || pWal->minFrame>0 );
    ++    for(iTest=iLast; iTest>=pWal->minFrame && iTest>0; iTest--){
    +       if( walFramePgno(pWal, iTest)==pgno ){
    +         iRead2 = iTest;
    +         break;
    +@@ -52847,6 +58568,7 @@ SQLITE_PRIVATE int sqlite3WalBeginWriteTransaction(Wal *pWal){
    +   /* Cannot start a write transaction without first holding a read
    +   ** transaction. */
    +   assert( pWal->readLock>=0 );
    ++  assert( pWal->writeLock==0 && pWal->iReCksum==0 );
    + 
    +   if( pWal->readOnly ){
    +     return SQLITE_READONLY;
    +@@ -52855,7 +58577,7 @@ SQLITE_PRIVATE int sqlite3WalBeginWriteTransaction(Wal *pWal){
    +   /* Only one writer allowed at a time.  Get the write lock.  Return
    +   ** SQLITE_BUSY if unable.
    +   */
    +-  rc = walLockExclusive(pWal, WAL_WRITE_LOCK, 1, 0);
    ++  rc = walLockExclusive(pWal, WAL_WRITE_LOCK, 1);
    +   if( rc ){
    +     return rc;
    +   }
    +@@ -52882,6 +58604,7 @@ SQLITE_PRIVATE int sqlite3WalEndWriteTransaction(Wal *pWal){
    +   if( pWal->writeLock ){
    +     walUnlockExclusive(pWal, WAL_WRITE_LOCK, 1);
    +     pWal->writeLock = 0;
    ++    pWal->iReCksum = 0;
    +     pWal->truncateOnCommit = 0;
    +   }
    +   return SQLITE_OK;
    +@@ -53000,7 +58723,7 @@ static int walRestartLog(Wal *pWal){
    +     if( pInfo->nBackfill>0 ){
    +       u32 salt1;
    +       sqlite3_randomness(4, &salt1);
    +-      rc = walLockExclusive(pWal, WAL_READ_LOCK(1), WAL_NREADER-1, 0);
    ++      rc = walLockExclusive(pWal, WAL_READ_LOCK(1), WAL_NREADER-1);
    +       if( rc==SQLITE_OK ){
    +         /* If all readers are using WAL_READ_LOCK(0) (in other words if no
    +         ** readers are currently using the WAL), then the transactions
    +@@ -53067,8 +58790,8 @@ static int walWriteToLog(
    +     iOffset += iFirstAmt;
    +     iAmt -= iFirstAmt;
    +     pContent = (void*)(iFirstAmt + (char*)pContent);
    +-    assert( p->syncFlags & (SQLITE_SYNC_NORMAL|SQLITE_SYNC_FULL) );
    +-    rc = sqlite3OsSync(p->pFd, p->syncFlags & SQLITE_SYNC_MASK);
    ++    assert( WAL_SYNC_FLAGS(p->syncFlags)!=0 );
    ++    rc = sqlite3OsSync(p->pFd, WAL_SYNC_FLAGS(p->syncFlags));
    +     if( iAmt==0 || rc ) return rc;
    +   }
    +   rc = sqlite3OsWrite(p->pFd, pContent, iAmt, iOffset);
    +@@ -53088,7 +58811,7 @@ static int walWriteOneFrame(
    +   void *pData;                    /* Data actually written */
    +   u8 aFrame[WAL_FRAME_HDRSIZE];   /* Buffer to assemble frame-header in */
    + #if defined(SQLITE_HAS_CODEC)
    +-  if( (pData = sqlite3PagerCodec(pPage))==0 ) return SQLITE_NOMEM;
    ++  if( (pData = sqlite3PagerCodec(pPage))==0 ) return SQLITE_NOMEM_BKPT;
    + #else
    +   pData = pPage->pData;
    + #endif
    +@@ -53100,6 +58823,59 @@ static int walWriteOneFrame(
    +   return rc;
    + }
    + 
    ++/*
    ++** This function is called as part of committing a transaction within which
    ++** one or more frames have been overwritten. It updates the checksums for
    ++** all frames written to the wal file by the current transaction starting
    ++** with the earliest to have been overwritten.
    ++**
    ++** SQLITE_OK is returned if successful, or an SQLite error code otherwise.
    ++*/
    ++static int walRewriteChecksums(Wal *pWal, u32 iLast){
    ++  const int szPage = pWal->szPage;/* Database page size */
    ++  int rc = SQLITE_OK;             /* Return code */
    ++  u8 *aBuf;                       /* Buffer to load data from wal file into */
    ++  u8 aFrame[WAL_FRAME_HDRSIZE];   /* Buffer to assemble frame-headers in */
    ++  u32 iRead;                      /* Next frame to read from wal file */
    ++  i64 iCksumOff;
    ++
    ++  aBuf = sqlite3_malloc(szPage + WAL_FRAME_HDRSIZE);
    ++  if( aBuf==0 ) return SQLITE_NOMEM_BKPT;
    ++
    ++  /* Find the checksum values to use as input for the recalculating the
    ++  ** first checksum. If the first frame is frame 1 (implying that the current
    ++  ** transaction restarted the wal file), these values must be read from the
    ++  ** wal-file header. Otherwise, read them from the frame header of the
    ++  ** previous frame.  */
    ++  assert( pWal->iReCksum>0 );
    ++  if( pWal->iReCksum==1 ){
    ++    iCksumOff = 24;
    ++  }else{
    ++    iCksumOff = walFrameOffset(pWal->iReCksum-1, szPage) + 16;
    ++  }
    ++  rc = sqlite3OsRead(pWal->pWalFd, aBuf, sizeof(u32)*2, iCksumOff);
    ++  pWal->hdr.aFrameCksum[0] = sqlite3Get4byte(aBuf);
    ++  pWal->hdr.aFrameCksum[1] = sqlite3Get4byte(&aBuf[sizeof(u32)]);
    ++
    ++  iRead = pWal->iReCksum;
    ++  pWal->iReCksum = 0;
    ++  for(; rc==SQLITE_OK && iRead<=iLast; iRead++){
    ++    i64 iOff = walFrameOffset(iRead, szPage);
    ++    rc = sqlite3OsRead(pWal->pWalFd, aBuf, szPage+WAL_FRAME_HDRSIZE, iOff);
    ++    if( rc==SQLITE_OK ){
    ++      u32 iPgno, nDbSize;
    ++      iPgno = sqlite3Get4byte(aBuf);
    ++      nDbSize = sqlite3Get4byte(&aBuf[4]);
    ++
    ++      walEncodeFrame(pWal, iPgno, nDbSize, &aBuf[WAL_FRAME_HDRSIZE], aFrame);
    ++      rc = sqlite3OsWrite(pWal->pWalFd, aFrame, sizeof(aFrame), iOff);
    ++    }
    ++  }
    ++
    ++  sqlite3_free(aBuf);
    ++  return rc;
    ++}
    ++
    + /* 
    + ** Write a set of frames to the log. The caller must hold the write-lock
    + ** on the log file (obtained using sqlite3WalBeginWriteTransaction()).
    +@@ -53120,6 +58896,8 @@ SQLITE_PRIVATE int sqlite3WalFrames(
    +   int szFrame;                    /* The size of a single frame */
    +   i64 iOffset;                    /* Next byte to write in WAL file */
    +   WalWriter w;                    /* The writer */
    ++  u32 iFirst = 0;                 /* First frame that may be overwritten */
    ++  WalIndexHdr *pLive;             /* Pointer to shared header */
    + 
    +   assert( pList );
    +   assert( pWal->writeLock );
    +@@ -53135,6 +58913,11 @@ SQLITE_PRIVATE int sqlite3WalFrames(
    +   }
    + #endif
    + 
    ++  pLive = (WalIndexHdr*)walIndexHdr(pWal);
    ++  if( memcmp(&pWal->hdr, (void *)pLive, sizeof(WalIndexHdr))!=0 ){
    ++    iFirst = pLive->mxFrame+1;
    ++  }
    ++
    +   /* See if it is possible to write these frames into the start of the
    +   ** log file, instead of appending to it at pWal->hdr.mxFrame.
    +   */
    +@@ -53178,10 +58961,10 @@ SQLITE_PRIVATE int sqlite3WalFrames(
    +     ** an out-of-order write following a WAL restart could result in
    +     ** database corruption.  See the ticket:
    +     **
    +-    **     http://localhost:591/sqlite/info/ff5be73dee
    ++    **     https://sqlite.org/src/info/ff5be73dee
    +     */
    +-    if( pWal->syncHeader && sync_flags ){
    +-      rc = sqlite3OsSync(pWal->pWalFd, sync_flags & SQLITE_SYNC_MASK);
    ++    if( pWal->syncHeader ){
    ++      rc = sqlite3OsSync(pWal->pWalFd, CKPT_SYNC_FLAGS(sync_flags));
    +       if( rc ) return rc;
    +     }
    +   }
    +@@ -53199,6 +58982,33 @@ SQLITE_PRIVATE int sqlite3WalFrames(
    +   /* Write all frames into the log file exactly once */
    +   for(p=pList; p; p=p->pDirty){
    +     int nDbSize;   /* 0 normally.  Positive == commit flag */
    ++
    ++    /* Check if this page has already been written into the wal file by
    ++    ** the current transaction. If so, overwrite the existing frame and
    ++    ** set Wal.writeLock to WAL_WRITELOCK_RECKSUM - indicating that 
    ++    ** checksums must be recomputed when the transaction is committed.  */
    ++    if( iFirst && (p->pDirty || isCommit==0) ){
    ++      u32 iWrite = 0;
    ++      VVA_ONLY(rc =) sqlite3WalFindFrame(pWal, p->pgno, &iWrite);
    ++      assert( rc==SQLITE_OK || iWrite==0 );
    ++      if( iWrite>=iFirst ){
    ++        i64 iOff = walFrameOffset(iWrite, szPage) + WAL_FRAME_HDRSIZE;
    ++        void *pData;
    ++        if( pWal->iReCksum==0 || iWrite<pWal->iReCksum ){
    ++          pWal->iReCksum = iWrite;
    ++        }
    ++#if defined(SQLITE_HAS_CODEC)
    ++        if( (pData = sqlite3PagerCodec(p))==0 ) return SQLITE_NOMEM;
    ++#else
    ++        pData = p->pData;
    ++#endif
    ++        rc = sqlite3OsWrite(pWal->pWalFd, pData, szPage, iOff);
    ++        if( rc ) return rc;
    ++        p->flags &= ~PGHDR_WAL_APPEND;
    ++        continue;
    ++      }
    ++    }
    ++
    +     iFrame++;
    +     assert( iOffset==walFrameOffset(iFrame, szPage) );
    +     nDbSize = (isCommit && p->pDirty==0) ? nTruncate : 0;
    +@@ -53206,6 +59016,13 @@ SQLITE_PRIVATE int sqlite3WalFrames(
    +     if( rc ) return rc;
    +     pLast = p;
    +     iOffset += szFrame;
    ++    p->flags |= PGHDR_WAL_APPEND;
    ++  }
    ++
    ++  /* Recalculate checksums within the wal file if required. */
    ++  if( isCommit && pWal->iReCksum ){
    ++    rc = walRewriteChecksums(pWal, iFrame);
    ++    if( rc ) return rc;
    +   }
    + 
    +   /* If this is the end of a transaction, then we might need to pad
    +@@ -53222,18 +59039,23 @@ SQLITE_PRIVATE int sqlite3WalFrames(
    +   ** sector boundary is synced; the part of the last frame that extends
    +   ** past the sector boundary is written after the sync.
    +   */
    +-  if( isCommit && (sync_flags & WAL_SYNC_TRANSACTIONS)!=0 ){
    ++  if( isCommit && WAL_SYNC_FLAGS(sync_flags)!=0 ){
    ++    int bSync = 1;
    +     if( pWal->padToSectorBoundary ){
    +       int sectorSize = sqlite3SectorSize(pWal->pWalFd);
    +       w.iSyncPoint = ((iOffset+sectorSize-1)/sectorSize)*sectorSize;
    ++      bSync = (w.iSyncPoint==iOffset);
    ++      testcase( bSync );
    +       while( iOffset<w.iSyncPoint ){
    +         rc = walWriteOneFrame(&w, pLast, nTruncate, iOffset);
    +         if( rc ) return rc;
    +         iOffset += szFrame;
    +         nExtra++;
    +       }
    +-    }else{
    +-      rc = sqlite3OsSync(w.pFd, sync_flags & SQLITE_SYNC_MASK);
    ++    }
    ++    if( bSync ){
    ++      assert( rc==SQLITE_OK );
    ++      rc = sqlite3OsSync(w.pFd, WAL_SYNC_FLAGS(sync_flags));
    +     }
    +   }
    + 
    +@@ -53257,6 +59079,7 @@ SQLITE_PRIVATE int sqlite3WalFrames(
    +   */
    +   iFrame = pWal->hdr.mxFrame;
    +   for(p=pList; p && rc==SQLITE_OK; p=p->pDirty){
    ++    if( (p->flags & PGHDR_WAL_APPEND)==0 ) continue;
    +     iFrame++;
    +     rc = walIndexAppend(pWal, iFrame, p->pgno);
    +   }
    +@@ -53299,6 +59122,7 @@ SQLITE_PRIVATE int sqlite3WalFrames(
    + */
    + SQLITE_PRIVATE int sqlite3WalCheckpoint(
    +   Wal *pWal,                      /* Wal connection */
    ++  sqlite3 *db,                    /* Check this handle's interrupt flag */
    +   int eMode,                      /* PASSIVE, FULL, RESTART, or TRUNCATE */
    +   int (*xBusy)(void*),            /* Function to call when busy */
    +   void *pBusyArg,                 /* Context argument for xBusyHandler */
    +@@ -53325,7 +59149,7 @@ SQLITE_PRIVATE int sqlite3WalCheckpoint(
    + 
    +   /* IMPLEMENTATION-OF: R-62028-47212 All calls obtain an exclusive 
    +   ** "checkpoint" lock on the database file. */
    +-  rc = walLockExclusive(pWal, WAL_CKPT_LOCK, 1, 0);
    ++  rc = walLockExclusive(pWal, WAL_CKPT_LOCK, 1);
    +   if( rc ){
    +     /* EVIDENCE-OF: R-10421-19736 If any other process is running a
    +     ** checkpoint operation at the same time, the lock cannot be obtained and
    +@@ -53369,10 +59193,11 @@ SQLITE_PRIVATE int sqlite3WalCheckpoint(
    + 
    +   /* Copy data from the log to the database file. */
    +   if( rc==SQLITE_OK ){
    ++
    +     if( pWal->hdr.mxFrame && walPagesize(pWal)!=nBuf ){
    +       rc = SQLITE_CORRUPT_BKPT;
    +     }else{
    +-      rc = walCheckpoint(pWal, eMode2, xBusy2, pBusyArg, sync_flags, zBuf);
    ++      rc = walCheckpoint(pWal, db, eMode2, xBusy2, pBusyArg, sync_flags, zBuf);
    +     }
    + 
    +     /* If no error occurred, set the output variables. */
    +@@ -53453,24 +59278,24 @@ SQLITE_PRIVATE int sqlite3WalExclusiveMode(Wal *pWal, int op){
    +   assert( pWal->readLock>=0 || (op<=0 && pWal->exclusiveMode==0) );
    + 
    +   if( op==0 ){
    +-    if( pWal->exclusiveMode ){
    +-      pWal->exclusiveMode = 0;
    ++    if( pWal->exclusiveMode!=WAL_NORMAL_MODE ){
    ++      pWal->exclusiveMode = WAL_NORMAL_MODE;
    +       if( walLockShared(pWal, WAL_READ_LOCK(pWal->readLock))!=SQLITE_OK ){
    +-        pWal->exclusiveMode = 1;
    ++        pWal->exclusiveMode = WAL_EXCLUSIVE_MODE;
    +       }
    +-      rc = pWal->exclusiveMode==0;
    ++      rc = pWal->exclusiveMode==WAL_NORMAL_MODE;
    +     }else{
    +       /* Already in locking_mode=NORMAL */
    +       rc = 0;
    +     }
    +   }else if( op>0 ){
    +-    assert( pWal->exclusiveMode==0 );
    ++    assert( pWal->exclusiveMode==WAL_NORMAL_MODE );
    +     assert( pWal->readLock>=0 );
    +     walUnlockShared(pWal, WAL_READ_LOCK(pWal->readLock));
    +-    pWal->exclusiveMode = 1;
    ++    pWal->exclusiveMode = WAL_EXCLUSIVE_MODE;
    +     rc = 1;
    +   }else{
    +-    rc = pWal->exclusiveMode==0;
    ++    rc = pWal->exclusiveMode==WAL_NORMAL_MODE;
    +   }
    +   return rc;
    + }
    +@@ -53484,6 +59309,57 @@ SQLITE_PRIVATE int sqlite3WalHeapMemory(Wal *pWal){
    +   return (pWal && pWal->exclusiveMode==WAL_HEAPMEMORY_MODE );
    + }
    + 
    ++#ifdef SQLITE_ENABLE_SNAPSHOT
    ++/* Create a snapshot object.  The content of a snapshot is opaque to
    ++** every other subsystem, so the WAL module can put whatever it needs
    ++** in the object.
    ++*/
    ++SQLITE_PRIVATE int sqlite3WalSnapshotGet(Wal *pWal, sqlite3_snapshot **ppSnapshot){
    ++  int rc = SQLITE_OK;
    ++  WalIndexHdr *pRet;
    ++  static const u32 aZero[4] = { 0, 0, 0, 0 };
    ++
    ++  assert( pWal->readLock>=0 && pWal->writeLock==0 );
    ++
    ++  if( memcmp(&pWal->hdr.aFrameCksum[0],aZero,16)==0 ){
    ++    *ppSnapshot = 0;
    ++    return SQLITE_ERROR;
    ++  }
    ++  pRet = (WalIndexHdr*)sqlite3_malloc(sizeof(WalIndexHdr));
    ++  if( pRet==0 ){
    ++    rc = SQLITE_NOMEM_BKPT;
    ++  }else{
    ++    memcpy(pRet, &pWal->hdr, sizeof(WalIndexHdr));
    ++    *ppSnapshot = (sqlite3_snapshot*)pRet;
    ++  }
    ++
    ++  return rc;
    ++}
    ++
    ++/* Try to open on pSnapshot when the next read-transaction starts
    ++*/
    ++SQLITE_PRIVATE void sqlite3WalSnapshotOpen(Wal *pWal, sqlite3_snapshot *pSnapshot){
    ++  pWal->pSnapshot = (WalIndexHdr*)pSnapshot;
    ++}
    ++
    ++/* 
    ++** Return a +ve value if snapshot p1 is newer than p2. A -ve value if
    ++** p1 is older than p2 and zero if p1 and p2 are the same snapshot.
    ++*/
    ++SQLITE_API int sqlite3_snapshot_cmp(sqlite3_snapshot *p1, sqlite3_snapshot *p2){
    ++  WalIndexHdr *pHdr1 = (WalIndexHdr*)p1;
    ++  WalIndexHdr *pHdr2 = (WalIndexHdr*)p2;
    ++
    ++  /* aSalt[0] is a copy of the value stored in the wal file header. It
    ++  ** is incremented each time the wal file is restarted.  */
    ++  if( pHdr1->aSalt[0]<pHdr2->aSalt[0] ) return -1;
    ++  if( pHdr1->aSalt[0]>pHdr2->aSalt[0] ) return +1;
    ++  if( pHdr1->mxFrame<pHdr2->mxFrame ) return -1;
    ++  if( pHdr1->mxFrame>pHdr2->mxFrame ) return +1;
    ++  return 0;
    ++}
    ++#endif /* SQLITE_ENABLE_SNAPSHOT */
    ++
    + #ifdef SQLITE_ENABLE_ZIPVFS
    + /*
    + ** If the argument is not NULL, it points to a Wal object that holds a
    +@@ -53496,6 +59372,12 @@ SQLITE_PRIVATE int sqlite3WalFramesize(Wal *pWal){
    + }
    + #endif
    + 
    ++/* Return the sqlite3_file object for the WAL file
    ++*/
    ++SQLITE_PRIVATE sqlite3_file *sqlite3WalFile(Wal *pWal){
    ++  return pWal->pWalFd;
    ++}
    ++
    + #endif /* #ifndef SQLITE_OMIT_WAL */
    + 
    + /************** End of wal.c *************************************************/
    +@@ -53780,38 +59662,39 @@ typedef struct CellInfo CellInfo;
    + #define PTF_LEAF      0x08
    + 
    + /*
    +-** As each page of the file is loaded into memory, an instance of the following
    +-** structure is appended and initialized to zero.  This structure stores
    +-** information about the page that is decoded from the raw file page.
    ++** An instance of this object stores information about each a single database
    ++** page that has been loaded into memory.  The information in this object
    ++** is derived from the raw on-disk page content.
    + **
    +-** The pParent field points back to the parent page.  This allows us to
    +-** walk up the BTree from any leaf to the root.  Care must be taken to
    +-** unref() the parent page pointer when this page is no longer referenced.
    +-** The pageDestructor() routine handles that chore.
    ++** As each database page is loaded into memory, the pager allocats an
    ++** instance of this object and zeros the first 8 bytes.  (This is the
    ++** "extra" information associated with each page of the pager.)
    + **
    + ** Access to all fields of this structure is controlled by the mutex
    + ** stored in MemPage.pBt->mutex.
    + */
    + struct MemPage {
    +   u8 isInit;           /* True if previously initialized. MUST BE FIRST! */
    +-  u8 nOverflow;        /* Number of overflow cell bodies in aCell[] */
    ++  u8 bBusy;            /* Prevent endless loops on corrupt database files */
    +   u8 intKey;           /* True if table b-trees.  False for index b-trees */
    +   u8 intKeyLeaf;       /* True if the leaf of an intKey table */
    +-  u8 noPayload;        /* True if internal intKey page (thus w/o data) */
    ++  Pgno pgno;           /* Page number for this page */
    ++  /* Only the first 8 bytes (above) are zeroed by pager.c when a new page
    ++  ** is allocated. All fields that follow must be initialized before use */
    +   u8 leaf;             /* True if a leaf page */
    +   u8 hdrOffset;        /* 100 for page 1.  0 otherwise */
    +   u8 childPtrSize;     /* 0 if leaf==1.  4 if leaf==0 */
    +   u8 max1bytePayload;  /* min(maxLocal,127) */
    +-  u8 bBusy;            /* Prevent endless loops on corrupt database files */
    ++  u8 nOverflow;        /* Number of overflow cell bodies in aCell[] */
    +   u16 maxLocal;        /* Copy of BtShared.maxLocal or BtShared.maxLeaf */
    +   u16 minLocal;        /* Copy of BtShared.minLocal or BtShared.minLeaf */
    +   u16 cellOffset;      /* Index in aData of first cell pointer */
    +   u16 nFree;           /* Number of free bytes on the page */
    +   u16 nCell;           /* Number of cells on this page, local and ovfl */
    +   u16 maskPage;        /* Mask for page offset */
    +-  u16 aiOvfl[5];       /* Insert the i-th overflow cell before the aiOvfl-th
    ++  u16 aiOvfl[4];       /* Insert the i-th overflow cell before the aiOvfl-th
    +                        ** non-overflow cell */
    +-  u8 *apOvfl[5];       /* Pointers to the body of overflow cells */
    ++  u8 *apOvfl[4];       /* Pointers to the body of overflow cells */
    +   BtShared *pBt;       /* Pointer to BtShared that this page is part of */
    +   u8 *aData;           /* Pointer to disk image of the page data */
    +   u8 *aDataEnd;        /* One byte past the end of usable data */
    +@@ -53820,16 +59703,8 @@ struct MemPage {
    +   DbPage *pDbPage;     /* Pager page handle */
    +   u16 (*xCellSize)(MemPage*,u8*);             /* cellSizePtr method */
    +   void (*xParseCell)(MemPage*,u8*,CellInfo*); /* btreeParseCell method */
    +-  Pgno pgno;           /* Page number for this page */
    + };
    + 
    +-/*
    +-** The in-memory image of a disk page has the auxiliary information appended
    +-** to the end.  EXTRA_SIZE is the number of bytes of space needed to hold
    +-** that extra information.
    +-*/
    +-#define EXTRA_SIZE sizeof(MemPage)
    +-
    + /*
    + ** A linked list of the following structures is stored at BtShared.pLock.
    + ** Locks are added (or upgraded from READ_LOCK to WRITE_LOCK) when a cursor 
    +@@ -53976,10 +59851,12 @@ struct BtShared {
    + #define BTS_READ_ONLY        0x0001   /* Underlying file is readonly */
    + #define BTS_PAGESIZE_FIXED   0x0002   /* Page size can no longer be changed */
    + #define BTS_SECURE_DELETE    0x0004   /* PRAGMA secure_delete is enabled */
    +-#define BTS_INITIALLY_EMPTY  0x0008   /* Database was empty at trans start */
    +-#define BTS_NO_WAL           0x0010   /* Do not open write-ahead-log files */
    +-#define BTS_EXCLUSIVE        0x0020   /* pWriter has an exclusive lock */
    +-#define BTS_PENDING          0x0040   /* Waiting for read-locks to clear */
    ++#define BTS_OVERWRITE        0x0008   /* Overwrite deleted content with zeros */
    ++#define BTS_FAST_SECURE      0x000c   /* Combination of the previous two */
    ++#define BTS_INITIALLY_EMPTY  0x0010   /* Database was empty at trans start */
    ++#define BTS_NO_WAL           0x0020   /* Do not open write-ahead-log files */
    ++#define BTS_EXCLUSIVE        0x0040   /* pWriter has an exclusive lock */
    ++#define BTS_PENDING          0x0080   /* Waiting for read-locks to clear */
    + 
    + /*
    + ** An instance of the following structure is used to hold information
    +@@ -53991,7 +59868,6 @@ struct CellInfo {
    +   u8 *pPayload;  /* Pointer to the start of payload */
    +   u32 nPayload;  /* Bytes of payload */
    +   u16 nLocal;    /* Amount of payload held locally, not on overflow */
    +-  u16 iOverflow; /* Offset to overflow page number.  Zero if no overflow */
    +   u16 nSize;     /* Size of the cell content on the main b-tree page */
    + };
    + 
    +@@ -54026,6 +59902,11 @@ struct CellInfo {
    + **    eState==FAULT:                   Cursor fault with skipNext as error code.
    + */
    + struct BtCursor {
    ++  u8 eState;                /* One of the CURSOR_XXX constants (see below) */
    ++  u8 curFlags;              /* zero or more BTCF_* flags defined below */
    ++  u8 curPagerFlags;         /* Flags to send to sqlite3PagerGet() */
    ++  u8 hints;                 /* As configured by CursorSetHints() */
    ++  int nOvflAlloc;           /* Allocated size of aOverflow[] array */
    +   Btree *pBtree;            /* The Btree to which this cursor belongs */
    +   BtShared *pBt;            /* The BtShared this cursor points to */
    +   BtCursor *pNext;          /* Forms a linked list of all cursors */
    +@@ -54034,22 +59915,18 @@ struct BtCursor {
    +   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.
    +                    ** Error code if eState==CURSOR_FAULT */
    +-  u8 curFlags;              /* zero or more BTCF_* flags defined below */
    +-  u8 curPagerFlags;         /* Flags to send to sqlite3PagerAcquire() */
    +-  u8 eState;                /* One of the CURSOR_XXX constants (see below) */
    +-  u8 hints;                 /* As configured by CursorSetHints() */
    +   /* All fields above are zeroed when the cursor is allocated.  See
    +   ** sqlite3BtreeCursorZero().  Fields that follow must be manually
    +   ** initialized. */
    +   i8 iPage;                 /* Index of current page in apPage */
    +   u8 curIntKey;             /* Value of apPage[0]->intKey */
    +-  struct KeyInfo *pKeyInfo; /* Argument passed to comparison function */
    +-  void *padding1;           /* Make object size a multiple of 16 */
    +-  u16 aiIdx[BTCURSOR_MAX_DEPTH];        /* Current index in apPage[i] */
    +-  MemPage *apPage[BTCURSOR_MAX_DEPTH];  /* Pages from root to current page */
    ++  u16 ix;                   /* Current index for apPage[iPage] */
    ++  u16 aiIdx[BTCURSOR_MAX_DEPTH-1];     /* Current index in apPage[i] */
    ++  struct KeyInfo *pKeyInfo;            /* Arg passed to comparison function */
    ++  MemPage *pPage;                        /* Current page */
    ++  MemPage *apPage[BTCURSOR_MAX_DEPTH-1]; /* Stack of parents of current page */
    + };
    + 
    + /*
    +@@ -54221,11 +60098,9 @@ struct IntegrityCk {
    + */
    + #if SQLITE_BYTEORDER==4321
    + # define get2byteAligned(x)  (*(u16*)(x))
    +-#elif SQLITE_BYTEORDER==1234 && !defined(SQLITE_DISABLE_INTRINSIC) \
    +-    && GCC_VERSION>=4008000
    ++#elif SQLITE_BYTEORDER==1234 && GCC_VERSION>=4008000
    + # define get2byteAligned(x)  __builtin_bswap16(*(u16*)(x))
    +-#elif SQLITE_BYTEORDER==1234 && !defined(SQLITE_DISABLE_INTRINSIC) \
    +-    && defined(_MSC_VER) && _MSC_VER>=1300
    ++#elif SQLITE_BYTEORDER==1234 && MSVC_VERSION>=1300
    + # define get2byteAligned(x)  _byteswap_ushort(*(u16*)(x))
    + #else
    + # define get2byteAligned(x)  ((x)[0]<<8 | (x)[1])
    +@@ -54386,21 +60261,6 @@ SQLITE_PRIVATE int sqlite3BtreeHoldsMutex(Btree *p){
    + #endif
    + 
    + 
    +-#ifndef SQLITE_OMIT_INCRBLOB
    +-/*
    +-** Enter and leave a mutex on a Btree given a cursor owned by that
    +-** Btree.  These entry points are used by incremental I/O and can be
    +-** omitted if that module is not used.
    +-*/
    +-SQLITE_PRIVATE void sqlite3BtreeEnterCursor(BtCursor *pCur){
    +-  sqlite3BtreeEnter(pCur->pBtree);
    +-}
    +-SQLITE_PRIVATE void sqlite3BtreeLeaveCursor(BtCursor *pCur){
    +-  sqlite3BtreeLeave(pCur->pBtree);
    +-}
    +-#endif /* SQLITE_OMIT_INCRBLOB */
    +-
    +-
    + /*
    + ** Enter the mutex on every Btree associated with a database
    + ** connection.  This is needed (for example) prior to parsing
    +@@ -54415,16 +60275,24 @@ SQLITE_PRIVATE void sqlite3BtreeLeaveCursor(BtCursor *pCur){
    + ** two or more btrees in common both try to lock all their btrees
    + ** at the same instant.
    + */
    +-SQLITE_PRIVATE void sqlite3BtreeEnterAll(sqlite3 *db){
    ++static void SQLITE_NOINLINE btreeEnterAll(sqlite3 *db){
    +   int i;
    ++  int skipOk = 1;
    +   Btree *p;
    +   assert( sqlite3_mutex_held(db->mutex) );
    +   for(i=0; i<db->nDb; i++){
    +     p = db->aDb[i].pBt;
    +-    if( p ) sqlite3BtreeEnter(p);
    ++    if( p && p->sharable ){
    ++      sqlite3BtreeEnter(p);
    ++      skipOk = 0;
    ++    }
    +   }
    ++  db->skipBtreeMutex = skipOk;
    + }
    +-SQLITE_PRIVATE void sqlite3BtreeLeaveAll(sqlite3 *db){
    ++SQLITE_PRIVATE void sqlite3BtreeEnterAll(sqlite3 *db){
    ++  if( db->skipBtreeMutex==0 ) btreeEnterAll(db);
    ++}
    ++static void SQLITE_NOINLINE btreeLeaveAll(sqlite3 *db){
    +   int i;
    +   Btree *p;
    +   assert( sqlite3_mutex_held(db->mutex) );
    +@@ -54433,13 +60301,8 @@ SQLITE_PRIVATE void sqlite3BtreeLeaveAll(sqlite3 *db){
    +     if( p ) sqlite3BtreeLeave(p);
    +   }
    + }
    +-
    +-/*
    +-** Return true if a particular Btree requires a lock.  Return FALSE if
    +-** no lock is ever required since it is not sharable.
    +-*/
    +-SQLITE_PRIVATE int sqlite3BtreeSharable(Btree *p){
    +-  return p->sharable;
    ++SQLITE_PRIVATE void sqlite3BtreeLeaveAll(sqlite3 *db){
    ++  if( db->skipBtreeMutex==0 ) btreeLeaveAll(db);
    + }
    + 
    + #ifndef NDEBUG
    +@@ -54515,6 +60378,25 @@ SQLITE_PRIVATE void sqlite3BtreeEnterAll(sqlite3 *db){
    +   }
    + }
    + #endif /* if SQLITE_THREADSAFE */
    ++
    ++#ifndef SQLITE_OMIT_INCRBLOB
    ++/*
    ++** Enter a mutex on a Btree given a cursor owned by that Btree. 
    ++**
    ++** These entry points are used by incremental I/O only. Enter() is required 
    ++** any time OMIT_SHARED_CACHE is not defined, regardless of whether or not 
    ++** the build is threadsafe. Leave() is only required by threadsafe builds.
    ++*/
    ++SQLITE_PRIVATE void sqlite3BtreeEnterCursor(BtCursor *pCur){
    ++  sqlite3BtreeEnter(pCur->pBtree);
    ++}
    ++# if SQLITE_THREADSAFE
    ++SQLITE_PRIVATE void sqlite3BtreeLeaveCursor(BtCursor *pCur){
    ++  sqlite3BtreeLeave(pCur->pBtree);
    ++}
    ++# endif
    ++#endif /* ifndef SQLITE_OMIT_INCRBLOB */
    ++
    + #endif /* ifndef SQLITE_OMIT_SHARED_CACHE */
    + 
    + /************** End of btmutex.c *********************************************/
    +@@ -54607,7 +60489,7 @@ static BtShared *SQLITE_WSD sqlite3SharedCacheList = 0;
    + ** The shared cache setting effects only future calls to
    + ** sqlite3_open(), sqlite3_open16(), or sqlite3_open_v2().
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_enable_shared_cache(int enable){
    ++SQLITE_API int sqlite3_enable_shared_cache(int enable){
    +   sqlite3GlobalConfig.sharedCacheEnabled = enable;
    +   return SQLITE_OK;
    + }
    +@@ -54633,6 +60515,34 @@ SQLITE_API int SQLITE_STDCALL sqlite3_enable_shared_cache(int enable){
    +   #define hasReadConflicts(a, b) 0
    + #endif
    + 
    ++/*
    ++** Implementation of the SQLITE_CORRUPT_PAGE() macro. Takes a single
    ++** (MemPage*) as an argument. The (MemPage*) must not be NULL.
    ++**
    ++** If SQLITE_DEBUG is not defined, then this macro is equivalent to
    ++** SQLITE_CORRUPT_BKPT. Or, if SQLITE_DEBUG is set, then the log message
    ++** normally produced as a side-effect of SQLITE_CORRUPT_BKPT is augmented
    ++** with the page number and filename associated with the (MemPage*).
    ++*/
    ++#ifdef SQLITE_DEBUG
    ++int corruptPageError(int lineno, MemPage *p){
    ++  char *zMsg;
    ++  sqlite3BeginBenignMalloc();
    ++  zMsg = sqlite3_mprintf("database corruption page %d of %s",
    ++      (int)p->pgno, sqlite3PagerFilename(p->pBt->pPager, 0)
    ++  );
    ++  sqlite3EndBenignMalloc();
    ++  if( zMsg ){
    ++    sqlite3ReportError(SQLITE_CORRUPT, lineno, zMsg);
    ++  }
    ++  sqlite3_free(zMsg);
    ++  return SQLITE_CORRUPT_BKPT;
    ++}
    ++# define SQLITE_CORRUPT_PAGE(pMemPage) corruptPageError(__LINE__, pMemPage)
    ++#else
    ++# define SQLITE_CORRUPT_PAGE(pMemPage) SQLITE_CORRUPT_PGNO(pMemPage->pgno)
    ++#endif
    ++
    + #ifndef SQLITE_OMIT_SHARED_CACHE
    + 
    + #ifdef SQLITE_DEBUG
    +@@ -54673,7 +60583,7 @@ static int hasSharedCacheTableLock(
    +   ** Return true immediately.
    +   */
    +   if( (pBtree->sharable==0)
    +-   || (eLockType==READ_LOCK && (pBtree->db->flags & SQLITE_ReadUncommitted))
    ++   || (eLockType==READ_LOCK && (pBtree->db->flags & SQLITE_ReadUncommit))
    +   ){
    +     return 1;
    +   }
    +@@ -54750,7 +60660,7 @@ static int hasReadConflicts(Btree *pBtree, Pgno iRoot){
    +   for(p=pBtree->pBt->pCursor; p; p=p->pNext){
    +     if( p->pgnoRoot==iRoot 
    +      && p->pBtree!=pBtree
    +-     && 0==(p->pBtree->db->flags & SQLITE_ReadUncommitted)
    ++     && 0==(p->pBtree->db->flags & SQLITE_ReadUncommit)
    +     ){
    +       return 1;
    +     }
    +@@ -54772,7 +60682,7 @@ static int querySharedCacheTableLock(Btree *p, Pgno iTab, u8 eLock){
    +   assert( sqlite3BtreeHoldsMutex(p) );
    +   assert( eLock==READ_LOCK || eLock==WRITE_LOCK );
    +   assert( p->db!=0 );
    +-  assert( !(p->db->flags&SQLITE_ReadUncommitted)||eLock==WRITE_LOCK||iTab==1 );
    ++  assert( !(p->db->flags&SQLITE_ReadUncommit)||eLock==WRITE_LOCK||iTab==1 );
    +   
    +   /* If requesting a write-lock, then the Btree must have an open write
    +   ** transaction on this file. And, obviously, for this to be so there 
    +@@ -54850,7 +60760,7 @@ static int setSharedCacheTableLock(Btree *p, Pgno iTable, u8 eLock){
    +   ** obtain a read-lock using this function. The only read-lock obtained
    +   ** by a connection in read-uncommitted mode is on the sqlite_master 
    +   ** table, and that lock is obtained in BtreeBeginTrans().  */
    +-  assert( 0==(p->db->flags&SQLITE_ReadUncommitted) || eLock==WRITE_LOCK );
    ++  assert( 0==(p->db->flags&SQLITE_ReadUncommit) || eLock==WRITE_LOCK );
    + 
    +   /* This function should only be called on a sharable b-tree after it 
    +   ** has been determined that no other b-tree holds a conflicting lock.  */
    +@@ -54871,7 +60781,7 @@ static int setSharedCacheTableLock(Btree *p, Pgno iTable, u8 eLock){
    +   if( !pLock ){
    +     pLock = (BtLock *)sqlite3MallocZero(sizeof(BtLock));
    +     if( !pLock ){
    +-      return SQLITE_NOMEM;
    ++      return SQLITE_NOMEM_BKPT;
    +     }
    +     pLock->iTable = iTable;
    +     pLock->pBtree = p;
    +@@ -54960,7 +60870,9 @@ static void downgradeAllSharedCacheTableLocks(Btree *p){
    + 
    + #endif /* SQLITE_OMIT_SHARED_CACHE */
    + 
    +-static void releasePage(MemPage *pPage);  /* Forward reference */
    ++static void releasePage(MemPage *pPage);         /* Forward reference */
    ++static void releasePageOne(MemPage *pPage);      /* Forward reference */
    ++static void releasePageNotNull(MemPage *pPage);  /* Forward reference */
    + 
    + /*
    + ***** This routine is used inside of assert() only ****
    +@@ -54971,6 +60883,19 @@ static void releasePage(MemPage *pPage);  /* Forward reference */
    + static int cursorHoldsMutex(BtCursor *p){
    +   return sqlite3_mutex_held(p->pBt->mutex);
    + }
    ++
    ++/* Verify that the cursor and the BtShared agree about what is the current
    ++** database connetion. This is important in shared-cache mode. If the database 
    ++** connection pointers get out-of-sync, it is possible for routines like
    ++** btreeInitPage() to reference an stale connection pointer that references a
    ++** a connection that has already closed.  This routine is used inside assert()
    ++** statements only and for the purpose of double-checking that the btree code
    ++** does keep the database connection pointers up-to-date.
    ++*/
    ++static int cursorOwnsBtShared(BtCursor *p){
    ++  assert( cursorHoldsMutex(p) );
    ++  return (p->pBtree->db==p->pBt->db);
    ++}
    + #endif
    + 
    + /*
    +@@ -55007,6 +60932,7 @@ static void invalidateAllOverflowCache(BtShared *pBt){
    + */
    + static void invalidateIncrblobCursors(
    +   Btree *pBtree,          /* The database file to check */
    ++  Pgno pgnoRoot,          /* The table that might be changing */
    +   i64 iRow,               /* The rowid that might be changing */
    +   int isClearTable        /* True if all rows are being deleted */
    + ){
    +@@ -55017,7 +60943,7 @@ static void invalidateIncrblobCursors(
    +   for(p=pBtree->pBt->pCursor; p; p=p->pNext){
    +     if( (p->curFlags & BTCF_Incrblob)!=0 ){
    +       pBtree->hasIncrblobCur = 1;
    +-      if( isClearTable || p->info.nKey==iRow ){
    ++      if( p->pgnoRoot==pgnoRoot && (isClearTable || p->info.nKey==iRow) ){
    +         p->eState = CURSOR_INVALID;
    +       }
    +     }
    +@@ -55026,7 +60952,7 @@ static void invalidateIncrblobCursors(
    + 
    + #else
    +   /* Stub function when INCRBLOB is omitted */
    +-  #define invalidateIncrblobCursors(x,y,z)
    ++  #define invalidateIncrblobCursors(w,x,y,z)
    + #endif /* SQLITE_OMIT_INCRBLOB */
    + 
    + /*
    +@@ -55070,7 +60996,7 @@ static int btreeSetHasContent(BtShared *pBt, Pgno pgno){
    +     assert( pgno<=pBt->nPage );
    +     pBt->pHasContent = sqlite3BitvecCreate(pBt->nPage);
    +     if( !pBt->pHasContent ){
    +-      rc = SQLITE_NOMEM;
    ++      rc = SQLITE_NOMEM_BKPT;
    +     }
    +   }
    +   if( rc==SQLITE_OK && pgno<=sqlite3BitvecSize(pBt->pHasContent) ){
    +@@ -55105,11 +61031,13 @@ static void btreeClearHasContent(BtShared *pBt){
    + */
    + static void btreeReleaseAllCursorPages(BtCursor *pCur){
    +   int i;
    +-  for(i=0; i<=pCur->iPage; i++){
    +-    releasePage(pCur->apPage[i]);
    +-    pCur->apPage[i] = 0;
    ++  if( pCur->iPage>=0 ){
    ++    for(i=0; i<pCur->iPage; i++){
    ++      releasePageNotNull(pCur->apPage[i]);
    ++    }
    ++    releasePageNotNull(pCur->pPage);
    ++    pCur->iPage = -1;
    +   }
    +-  pCur->iPage = -1;
    + }
    + 
    + /*
    +@@ -55126,30 +61054,28 @@ static void btreeReleaseAllCursorPages(BtCursor *pCur){
    + ** the key.
    + */
    + static int saveCursorKey(BtCursor *pCur){
    +-  int rc;
    ++  int rc = SQLITE_OK;
    +   assert( CURSOR_VALID==pCur->eState );
    +   assert( 0==pCur->pKey );
    +   assert( cursorHoldsMutex(pCur) );
    + 
    +-  rc = sqlite3BtreeKeySize(pCur, &pCur->nKey);
    +-  assert( rc==SQLITE_OK );  /* KeySize() cannot fail */
    +-
    +-  /* If this is an intKey table, then the above call to BtreeKeySize()
    +-  ** stores the integer key in pCur->nKey. In this case this value is
    +-  ** all that is required. Otherwise, if pCur is not open on an intKey
    +-  ** table, then malloc space for and store the pCur->nKey bytes of key 
    +-  ** data.  */
    +-  if( 0==pCur->curIntKey ){
    +-    void *pKey = sqlite3Malloc( pCur->nKey );
    ++  if( pCur->curIntKey ){
    ++    /* Only the rowid is required for a table btree */
    ++    pCur->nKey = sqlite3BtreeIntegerKey(pCur);
    ++  }else{
    ++    /* For an index btree, save the complete key content */
    ++    void *pKey;
    ++    pCur->nKey = sqlite3BtreePayloadSize(pCur);
    ++    pKey = sqlite3Malloc( pCur->nKey );
    +     if( pKey ){
    +-      rc = sqlite3BtreeKey(pCur, 0, (int)pCur->nKey, pKey);
    ++      rc = sqlite3BtreePayload(pCur, 0, (int)pCur->nKey, pKey);
    +       if( rc==SQLITE_OK ){
    +         pCur->pKey = pKey;
    +       }else{
    +         sqlite3_free(pKey);
    +       }
    +     }else{
    +-      rc = SQLITE_NOMEM;
    ++      rc = SQLITE_NOMEM_BKPT;
    +     }
    +   }
    +   assert( !pCur->curIntKey || !pCur->pKey );
    +@@ -55240,7 +61166,7 @@ static int SQLITE_NOINLINE saveCursorsOnList(
    +           return rc;
    +         }
    +       }else{
    +-        testcase( p->iPage>0 );
    ++        testcase( p->iPage>=0 );
    +         btreeReleaseAllCursorPages(p);
    +       }
    +     }
    +@@ -55273,26 +61199,23 @@ static int btreeMoveto(
    + ){
    +   int rc;                    /* Status code */
    +   UnpackedRecord *pIdxKey;   /* Unpacked index key */
    +-  char aSpace[200];          /* Temp space for pIdxKey - to avoid a malloc */
    +-  char *pFree = 0;
    + 
    +   if( pKey ){
    +     assert( nKey==(i64)(int)nKey );
    +-    pIdxKey = sqlite3VdbeAllocUnpackedRecord(
    +-        pCur->pKeyInfo, aSpace, sizeof(aSpace), &pFree
    +-    );
    +-    if( pIdxKey==0 ) return SQLITE_NOMEM;
    ++    pIdxKey = sqlite3VdbeAllocUnpackedRecord(pCur->pKeyInfo);
    ++    if( pIdxKey==0 ) return SQLITE_NOMEM_BKPT;
    +     sqlite3VdbeRecordUnpack(pCur->pKeyInfo, (int)nKey, pKey, pIdxKey);
    +     if( pIdxKey->nField==0 ){
    +-      sqlite3DbFree(pCur->pKeyInfo->db, pFree);
    +-      return SQLITE_CORRUPT_BKPT;
    ++      rc = SQLITE_CORRUPT_BKPT;
    ++      goto moveto_done;
    +     }
    +   }else{
    +     pIdxKey = 0;
    +   }
    +   rc = sqlite3BtreeMovetoUnpacked(pCur, pIdxKey, nKey, bias, pRes);
    +-  if( pFree ){
    +-    sqlite3DbFree(pCur->pKeyInfo->db, pFree);
    ++moveto_done:
    ++  if( pIdxKey ){
    ++    sqlite3DbFree(pCur->pKeyInfo->db, pIdxKey);
    +   }
    +   return rc;
    + }
    +@@ -55307,7 +61230,7 @@ static int btreeMoveto(
    + static int btreeRestoreCursorPosition(BtCursor *pCur){
    +   int rc;
    +   int skipNext;
    +-  assert( cursorHoldsMutex(pCur) );
    ++  assert( cursorOwnsBtShared(pCur) );
    +   assert( pCur->eState>=CURSOR_REQUIRESEEK );
    +   if( pCur->eState==CURSOR_FAULT ){
    +     return pCur->skipNext;
    +@@ -55347,6 +61270,17 @@ SQLITE_PRIVATE int sqlite3BtreeCursorHasMoved(BtCursor *pCur){
    +   return pCur->eState!=CURSOR_VALID;
    + }
    + 
    ++/*
    ++** Return a pointer to a fake BtCursor object that will always answer
    ++** false to the sqlite3BtreeCursorHasMoved() routine above.  The fake
    ++** cursor returned must not be used with any other Btree interface.
    ++*/
    ++SQLITE_PRIVATE BtCursor *sqlite3BtreeFakeValidCursor(void){
    ++  static u8 fakeCursor = CURSOR_VALID;
    ++  assert( offsetof(BtCursor, eState)==0 );
    ++  return (BtCursor*)&fakeCursor;
    ++}
    ++
    + /*
    + ** This routine restores a cursor back to its original position after it
    + ** has been moved by some outside activity (such as a btree rebalance or
    +@@ -55379,6 +61313,26 @@ SQLITE_PRIVATE int sqlite3BtreeCursorRestore(BtCursor *pCur, int *pDifferentRow)
    +   return SQLITE_OK;
    + }
    + 
    ++#ifdef SQLITE_ENABLE_CURSOR_HINTS
    ++/*
    ++** Provide hints to the cursor.  The particular hint given (and the type
    ++** and number of the varargs parameters) is determined by the eHintType
    ++** parameter.  See the definitions of the BTREE_HINT_* macros for details.
    ++*/
    ++SQLITE_PRIVATE void sqlite3BtreeCursorHint(BtCursor *pCur, int eHintType, ...){
    ++  /* Used only by system that substitute their own storage engine */
    ++}
    ++#endif
    ++
    ++/*
    ++** Provide flag hints to the cursor.
    ++*/
    ++SQLITE_PRIVATE void sqlite3BtreeCursorHintFlags(BtCursor *pCur, unsigned x){
    ++  assert( x==BTREE_SEEK_EQ || x==BTREE_BULKLOAD || x==0 );
    ++  pCur->hints = x;
    ++}
    ++
    ++
    + #ifndef SQLITE_OMIT_AUTOVACUUM
    + /*
    + ** Given a page number of a regular database page, return the page
    +@@ -55432,7 +61386,7 @@ static void ptrmapPut(BtShared *pBt, Pgno key, u8 eType, Pgno parent, int *pRC){
    +     return;
    +   }
    +   iPtrmap = PTRMAP_PAGENO(pBt, key);
    +-  rc = sqlite3PagerGet(pBt->pPager, iPtrmap, &pDbPage);
    ++  rc = sqlite3PagerGet(pBt->pPager, iPtrmap, &pDbPage, 0);
    +   if( rc!=SQLITE_OK ){
    +     *pRC = rc;
    +     return;
    +@@ -55475,7 +61429,7 @@ static int ptrmapGet(BtShared *pBt, Pgno key, u8 *pEType, Pgno *pPgno){
    +   assert( sqlite3_mutex_held(pBt->mutex) );
    + 
    +   iPtrmap = PTRMAP_PAGENO(pBt, key);
    +-  rc = sqlite3PagerGet(pBt->pPager, iPtrmap, &pDbPage);
    ++  rc = sqlite3PagerGet(pBt->pPager, iPtrmap, &pDbPage, 0);
    +   if( rc!=0 ){
    +     return rc;
    +   }
    +@@ -55492,7 +61446,7 @@ static int ptrmapGet(BtShared *pBt, Pgno key, u8 *pEType, Pgno *pPgno){
    +   if( pPgno ) *pPgno = get4byte(&pPtrmap[offset+1]);
    + 
    +   sqlite3PagerUnref(pDbPage);
    +-  if( *pEType<1 || *pEType>5 ) return SQLITE_CORRUPT_BKPT;
    ++  if( *pEType<1 || *pEType>5 ) return SQLITE_CORRUPT_PGNO(iPtrmap);
    +   return SQLITE_OK;
    + }
    + 
    +@@ -55552,8 +61506,7 @@ static SQLITE_NOINLINE void btreeParseCellAdjustSizeForOverflow(
    +   }else{
    +     pInfo->nLocal = (u16)minLocal;
    +   }
    +-  pInfo->iOverflow = (u16)(&pInfo->pPayload[pInfo->nLocal] - pCell);
    +-  pInfo->nSize = pInfo->iOverflow + 4;
    ++  pInfo->nSize = (u16)(&pInfo->pPayload[pInfo->nLocal] - pCell) + 4;
    + }
    + 
    + /*
    +@@ -55577,7 +61530,6 @@ static void btreeParseCellPtrNoPayload(
    + ){
    +   assert( sqlite3_mutex_held(pPage->pBt->mutex) );
    +   assert( pPage->leaf==0 );
    +-  assert( pPage->noPayload );
    +   assert( pPage->childPtrSize==4 );
    + #ifndef SQLITE_DEBUG
    +   UNUSED_PARAMETER(pPage);
    +@@ -55585,7 +61537,6 @@ static void btreeParseCellPtrNoPayload(
    +   pInfo->nSize = 4 + getVarint(&pCell[4], (u64*)&pInfo->nKey);
    +   pInfo->nPayload = 0;
    +   pInfo->nLocal = 0;
    +-  pInfo->iOverflow = 0;
    +   pInfo->pPayload = 0;
    +   return;
    + }
    +@@ -55600,8 +61551,6 @@ static void btreeParseCellPtr(
    + 
    +   assert( sqlite3_mutex_held(pPage->pBt->mutex) );
    +   assert( pPage->leaf==0 || pPage->leaf==1 );
    +-  assert( pPage->intKeyLeaf || pPage->noPayload );
    +-  assert( pPage->noPayload==0 );
    +   assert( pPage->intKeyLeaf );
    +   assert( pPage->childPtrSize==0 );
    +   pIter = pCell;
    +@@ -55655,7 +61604,6 @@ static void btreeParseCellPtr(
    +     pInfo->nSize = nPayload + (u16)(pIter - pCell);
    +     if( pInfo->nSize<4 ) pInfo->nSize = 4;
    +     pInfo->nLocal = (u16)nPayload;
    +-    pInfo->iOverflow = 0;
    +   }else{
    +     btreeParseCellAdjustSizeForOverflow(pPage, pCell, pInfo);
    +   }
    +@@ -55671,7 +61619,6 @@ static void btreeParseCellPtrIndex(
    +   assert( sqlite3_mutex_held(pPage->pBt->mutex) );
    +   assert( pPage->leaf==0 || pPage->leaf==1 );
    +   assert( pPage->intKeyLeaf==0 );
    +-  assert( pPage->noPayload==0 );
    +   pIter = pCell + pPage->childPtrSize;
    +   nPayload = *pIter;
    +   if( nPayload>=0x80 ){
    +@@ -55694,7 +61641,6 @@ static void btreeParseCellPtrIndex(
    +     pInfo->nSize = nPayload + (u16)(pIter - pCell);
    +     if( pInfo->nSize<4 ) pInfo->nSize = 4;
    +     pInfo->nLocal = (u16)nPayload;
    +-    pInfo->iOverflow = 0;
    +   }else{
    +     btreeParseCellAdjustSizeForOverflow(pPage, pCell, pInfo);
    +   }
    +@@ -55733,7 +61679,6 @@ static u16 cellSizePtr(MemPage *pPage, u8 *pCell){
    +   pPage->xParseCell(pPage, pCell, &debuginfo);
    + #endif
    + 
    +-  assert( pPage->noPayload==0 );
    +   nSize = *pIter;
    +   if( nSize>=0x80 ){
    +     pEnd = &pIter[8];
    +@@ -55810,8 +61755,8 @@ static void ptrmapPutOvflPtr(MemPage *pPage, u8 *pCell, int *pRC){
    +   if( *pRC ) return;
    +   assert( pCell!=0 );
    +   pPage->xParseCell(pPage, pCell, &info);
    +-  if( info.iOverflow ){
    +-    Pgno ovfl = get4byte(&pCell[info.iOverflow]);
    ++  if( info.nLocal<info.nPayload ){
    ++    Pgno ovfl = get4byte(&pCell[info.nSize-4]);
    +     ptrmapPut(pPage->pBt, ovfl, PTRMAP_OVERFLOW1, pPage->pgno, pRC);
    +   }
    + }
    +@@ -55819,17 +61764,18 @@ static void ptrmapPutOvflPtr(MemPage *pPage, u8 *pCell, int *pRC){
    + 
    + 
    + /*
    +-** Defragment the page given.  All Cells are moved to the
    +-** end of the page and all free space is collected into one
    +-** big FreeBlk that occurs in between the header and cell
    +-** pointer array and the cell content area.
    ++** Defragment the page given. This routine reorganizes cells within the
    ++** page so that there are no free-blocks on the free-block list.
    ++**
    ++** Parameter nMaxFrag is the maximum amount of fragmented space that may be
    ++** present in the page after this routine returns.
    + **
    + ** EVIDENCE-OF: R-44582-60138 SQLite may from time to time reorganize a
    + ** b-tree page so that there are no freeblocks or fragment bytes, all
    + ** unused bytes are contained in the unallocated space region, and all
    + ** cells are packed tightly at the end of the page.
    + */
    +-static int defragmentPage(MemPage *pPage){
    ++static int defragmentPage(MemPage *pPage, int nMaxFrag){
    +   int i;                     /* Loop counter */
    +   int pc;                    /* Address of the i-th cell */
    +   int hdr;                   /* Offset to the page header */
    +@@ -55844,7 +61790,6 @@ static int defragmentPage(MemPage *pPage){
    +   int iCellFirst;            /* First allowable cell index */
    +   int iCellLast;             /* Last possible cell index */
    + 
    +-
    +   assert( sqlite3PagerIswriteable(pPage->pDbPage) );
    +   assert( pPage->pBt!=0 );
    +   assert( pPage->pBt->usableSize <= SQLITE_MAX_PAGE_SIZE );
    +@@ -55856,9 +61801,59 @@ static int defragmentPage(MemPage *pPage){
    +   cellOffset = pPage->cellOffset;
    +   nCell = pPage->nCell;
    +   assert( nCell==get2byte(&data[hdr+3]) );
    ++  iCellFirst = cellOffset + 2*nCell;
    +   usableSize = pPage->pBt->usableSize;
    ++
    ++  /* This block handles pages with two or fewer free blocks and nMaxFrag
    ++  ** or fewer fragmented bytes. In this case it is faster to move the
    ++  ** two (or one) blocks of cells using memmove() and add the required
    ++  ** offsets to each pointer in the cell-pointer array than it is to 
    ++  ** reconstruct the entire page.  */
    ++  if( (int)data[hdr+7]<=nMaxFrag ){
    ++    int iFree = get2byte(&data[hdr+1]);
    ++    if( iFree ){
    ++      int iFree2 = get2byte(&data[iFree]);
    ++
    ++      /* pageFindSlot() has already verified that free blocks are sorted
    ++      ** in order of offset within the page, and that no block extends
    ++      ** past the end of the page. Provided the two free slots do not 
    ++      ** overlap, this guarantees that the memmove() calls below will not
    ++      ** overwrite the usableSize byte buffer, even if the database page
    ++      ** is corrupt.  */
    ++      assert( iFree2==0 || iFree2>iFree );
    ++      assert( iFree+get2byte(&data[iFree+2]) <= usableSize );
    ++      assert( iFree2==0 || iFree2+get2byte(&data[iFree2+2]) <= usableSize );
    ++
    ++      if( 0==iFree2 || (data[iFree2]==0 && data[iFree2+1]==0) ){
    ++        u8 *pEnd = &data[cellOffset + nCell*2];
    ++        u8 *pAddr;
    ++        int sz2 = 0;
    ++        int sz = get2byte(&data[iFree+2]);
    ++        int top = get2byte(&data[hdr+5]);
    ++        if( top>=iFree ){
    ++          return SQLITE_CORRUPT_PAGE(pPage);
    ++        }
    ++        if( iFree2 ){
    ++          assert( iFree+sz<=iFree2 ); /* Verified by pageFindSlot() */
    ++          sz2 = get2byte(&data[iFree2+2]);
    ++          assert( iFree+sz+sz2+iFree2-(iFree+sz) <= usableSize );
    ++          memmove(&data[iFree+sz+sz2], &data[iFree+sz], iFree2-(iFree+sz));
    ++          sz += sz2;
    ++        }
    ++        cbrk = top+sz;
    ++        assert( cbrk+(iFree-top) <= usableSize );
    ++        memmove(&data[cbrk], &data[top], iFree-top);
    ++        for(pAddr=&data[cellOffset]; pAddr<pEnd; pAddr+=2){
    ++          pc = get2byte(pAddr);
    ++          if( pc<iFree ){ put2byte(pAddr, pc+sz); }
    ++          else if( pc<iFree2 ){ put2byte(pAddr, pc+sz2); }
    ++        }
    ++        goto defragment_out;
    ++      }
    ++    }
    ++  }
    ++
    +   cbrk = usableSize;
    +-  iCellFirst = cellOffset + 2*nCell;
    +   iCellLast = usableSize - 4;
    +   for(i=0; i<nCell; i++){
    +     u8 *pAddr;     /* The i-th cell pointer */
    +@@ -55870,13 +61865,13 @@ static int defragmentPage(MemPage *pPage){
    +     ** if PRAGMA cell_size_check=ON.
    +     */
    +     if( pc<iCellFirst || pc>iCellLast ){
    +-      return SQLITE_CORRUPT_BKPT;
    ++      return SQLITE_CORRUPT_PAGE(pPage);
    +     }
    +     assert( pc>=iCellFirst && pc<=iCellLast );
    +     size = pPage->xCellSize(pPage, &src[pc]);
    +     cbrk -= size;
    +     if( cbrk<iCellFirst || pc+size>usableSize ){
    +-      return SQLITE_CORRUPT_BKPT;
    ++      return SQLITE_CORRUPT_PAGE(pPage);
    +     }
    +     assert( cbrk+size<=usableSize && cbrk>=iCellFirst );
    +     testcase( cbrk+size==usableSize );
    +@@ -55892,16 +61887,18 @@ static int defragmentPage(MemPage *pPage){
    +     }
    +     memcpy(&data[cbrk], &src[pc], size);
    +   }
    ++  data[hdr+7] = 0;
    ++
    ++ defragment_out:
    ++  if( data[hdr+7]+cbrk-iCellFirst!=pPage->nFree ){
    ++    return SQLITE_CORRUPT_PAGE(pPage);
    ++  }
    +   assert( cbrk>=iCellFirst );
    +   put2byte(&data[hdr+5], cbrk);
    +   data[hdr+1] = 0;
    +   data[hdr+2] = 0;
    +-  data[hdr+7] = 0;
    +   memset(&data[iCellFirst], 0, cbrk-iCellFirst);
    +   assert( sqlite3PagerIswriteable(pPage->pDbPage) );
    +-  if( cbrk-iCellFirst!=pPage->nFree ){
    +-    return SQLITE_CORRUPT_BKPT;
    +-  }
    +   return SQLITE_OK;
    + }
    + 
    +@@ -55926,16 +61923,10 @@ static u8 *pageFindSlot(MemPage *pPg, int nByte, int *pRc){
    +   int pc = get2byte(&aData[iAddr]);
    +   int x;
    +   int usableSize = pPg->pBt->usableSize;
    ++  int size;            /* Size of the free slot */
    + 
    +   assert( pc>0 );
    +-  do{
    +-    int size;            /* Size of the free slot */
    +-    /* EVIDENCE-OF: R-06866-39125 Freeblocks are always connected in order of
    +-    ** increasing offset. */
    +-    if( pc>usableSize-4 || pc<iAddr+4 ){
    +-      *pRc = SQLITE_CORRUPT_BKPT;
    +-      return 0;
    +-    }
    ++  while( pc<=usableSize-4 ){
    +     /* EVIDENCE-OF: R-22710-53328 The third and fourth bytes of each
    +     ** freeblock form a big-endian integer which is the size of the freeblock
    +     ** in bytes, including the 4-byte header. */
    +@@ -55943,8 +61934,8 @@ static u8 *pageFindSlot(MemPage *pPg, int nByte, int *pRc){
    +     if( (x = size - nByte)>=0 ){
    +       testcase( x==4 );
    +       testcase( x==3 );
    +-      if( pc < pPg->cellOffset+2*pPg->nCell || size+pc > usableSize ){
    +-        *pRc = SQLITE_CORRUPT_BKPT;
    ++      if( size+pc > usableSize ){
    ++        *pRc = SQLITE_CORRUPT_PAGE(pPg);
    +         return 0;
    +       }else if( x<4 ){
    +         /* EVIDENCE-OF: R-11498-58022 In a well-formed b-tree page, the total
    +@@ -55964,7 +61955,11 @@ static u8 *pageFindSlot(MemPage *pPg, int nByte, int *pRc){
    +     }
    +     iAddr = pc;
    +     pc = get2byte(&aData[pc]);
    +-  }while( pc );
    ++    if( pc<iAddr+size ) break;
    ++  }
    ++  if( pc ){
    ++    *pRc = SQLITE_CORRUPT_PAGE(pPg);
    ++  }
    + 
    +   return 0;
    + }
    +@@ -56011,7 +62006,7 @@ static int allocateSpace(MemPage *pPage, int nByte, int *pIdx){
    +     if( top==0 && pPage->pBt->usableSize==65536 ){
    +       top = 65536;
    +     }else{
    +-      return SQLITE_CORRUPT_BKPT;
    ++      return SQLITE_CORRUPT_PAGE(pPage);
    +     }
    +   }
    + 
    +@@ -56039,10 +62034,10 @@ static int allocateSpace(MemPage *pPage, int nByte, int *pIdx){
    +   testcase( gap+2+nByte==top );
    +   if( gap+2+nByte>top ){
    +     assert( pPage->nCell>0 || CORRUPT_DB );
    +-    rc = defragmentPage(pPage);
    ++    rc = defragmentPage(pPage, MIN(4, pPage->nFree - (2+nByte)));
    +     if( rc ) return rc;
    +     top = get2byteNotZero(&data[hdr+5]);
    +-    assert( gap+nByte<=top );
    ++    assert( gap+2+nByte<=top );
    +   }
    + 
    + 
    +@@ -56078,7 +62073,7 @@ static int freeSpace(MemPage *pPage, u16 iStart, u16 iSize){
    +   u8 hdr;                               /* Page header size.  0 or 100 */
    +   u8 nFrag = 0;                         /* Reduction in fragmentation */
    +   u16 iOrigSize = iSize;                /* Original value of iSize */
    +-  u32 iLast = pPage->pBt->usableSize-4; /* Largest possible freeblock offset */
    ++  u16 x;                                /* Offset to cell content area */
    +   u32 iEnd = iStart + iSize;            /* First byte past the iStart buffer */
    +   unsigned char *data = pPage->aData;   /* Page content */
    + 
    +@@ -56088,13 +62083,7 @@ static int freeSpace(MemPage *pPage, u16 iStart, u16 iSize){
    +   assert( CORRUPT_DB || iEnd <= pPage->pBt->usableSize );
    +   assert( sqlite3_mutex_held(pPage->pBt->mutex) );
    +   assert( iSize>=4 );   /* Minimum cell size is 4 */
    +-  assert( iStart<=iLast );
    +-
    +-  /* Overwrite deleted information with zeros when the secure_delete
    +-  ** option is enabled */
    +-  if( pPage->pBt->btsFlags & BTS_SECURE_DELETE ){
    +-    memset(&data[iStart], 0, iSize);
    +-  }
    ++  assert( iStart<=pPage->pBt->usableSize-4 );
    + 
    +   /* The list of freeblocks must be in ascending order.  Find the 
    +   ** spot on the list where iStart should be inserted.
    +@@ -56104,11 +62093,16 @@ static int freeSpace(MemPage *pPage, u16 iStart, u16 iSize){
    +   if( data[iPtr+1]==0 && data[iPtr]==0 ){
    +     iFreeBlk = 0;  /* Shortcut for the case when the freelist is empty */
    +   }else{
    +-    while( (iFreeBlk = get2byte(&data[iPtr]))>0 && iFreeBlk<iStart ){
    +-      if( iFreeBlk<iPtr+4 ) return SQLITE_CORRUPT_BKPT;
    ++    while( (iFreeBlk = get2byte(&data[iPtr]))<iStart ){
    ++      if( iFreeBlk<iPtr+4 ){
    ++        if( iFreeBlk==0 ) break;
    ++        return SQLITE_CORRUPT_PAGE(pPage);
    ++      }
    +       iPtr = iFreeBlk;
    +     }
    +-    if( iFreeBlk>iLast ) return SQLITE_CORRUPT_BKPT;
    ++    if( iFreeBlk>pPage->pBt->usableSize-4 ){
    ++      return SQLITE_CORRUPT_PAGE(pPage);
    ++    }
    +     assert( iFreeBlk>iPtr || iFreeBlk==0 );
    +   
    +     /* At this point:
    +@@ -56119,9 +62113,11 @@ static int freeSpace(MemPage *pPage, u16 iStart, u16 iSize){
    +     */
    +     if( iFreeBlk && iEnd+3>=iFreeBlk ){
    +       nFrag = iFreeBlk - iEnd;
    +-      if( iEnd>iFreeBlk ) return SQLITE_CORRUPT_BKPT;
    ++      if( iEnd>iFreeBlk ) return SQLITE_CORRUPT_PAGE(pPage);
    +       iEnd = iFreeBlk + get2byte(&data[iFreeBlk+2]);
    +-      if( iEnd > pPage->pBt->usableSize ) return SQLITE_CORRUPT_BKPT;
    ++      if( iEnd > pPage->pBt->usableSize ){
    ++        return SQLITE_CORRUPT_PAGE(pPage);
    ++      }
    +       iSize = iEnd - iStart;
    +       iFreeBlk = get2byte(&data[iFreeBlk]);
    +     }
    +@@ -56133,28 +62129,34 @@ static int freeSpace(MemPage *pPage, u16 iStart, u16 iSize){
    +     if( iPtr>hdr+1 ){
    +       int iPtrEnd = iPtr + get2byte(&data[iPtr+2]);
    +       if( iPtrEnd+3>=iStart ){
    +-        if( iPtrEnd>iStart ) return SQLITE_CORRUPT_BKPT;
    ++        if( iPtrEnd>iStart ) return SQLITE_CORRUPT_PAGE(pPage);
    +         nFrag += iStart - iPtrEnd;
    +         iSize = iEnd - iPtr;
    +         iStart = iPtr;
    +       }
    +     }
    +-    if( nFrag>data[hdr+7] ) return SQLITE_CORRUPT_BKPT;
    ++    if( nFrag>data[hdr+7] ) return SQLITE_CORRUPT_PAGE(pPage);
    +     data[hdr+7] -= nFrag;
    +   }
    +-  if( iStart==get2byte(&data[hdr+5]) ){
    ++  x = get2byte(&data[hdr+5]);
    ++  if( iStart<=x ){
    +     /* The new freeblock is at the beginning of the cell content area,
    +     ** so just extend the cell content area rather than create another
    +     ** freelist entry */
    +-    if( iPtr!=hdr+1 ) return SQLITE_CORRUPT_BKPT;
    ++    if( iStart<x || iPtr!=hdr+1 ) return SQLITE_CORRUPT_PAGE(pPage);
    +     put2byte(&data[hdr+1], iFreeBlk);
    +     put2byte(&data[hdr+5], iEnd);
    +   }else{
    +     /* Insert the new freeblock into the freelist */
    +     put2byte(&data[iPtr], iStart);
    +-    put2byte(&data[iStart], iFreeBlk);
    +-    put2byte(&data[iStart+2], iSize);
    +   }
    ++  if( pPage->pBt->btsFlags & BTS_FAST_SECURE ){
    ++    /* Overwrite deleted information with zeros when the secure_delete
    ++    ** option is enabled */
    ++    memset(&data[iStart], 0, iSize);
    ++  }
    ++  put2byte(&data[iStart], iFreeBlk);
    ++  put2byte(&data[iStart+2], iSize);
    +   pPage->nFree += iOrigSize;
    +   return SQLITE_OK;
    + }
    +@@ -56182,42 +62184,39 @@ static int decodeFlags(MemPage *pPage, int flagByte){
    +   pPage->xCellSize = cellSizePtr;
    +   pBt = pPage->pBt;
    +   if( flagByte==(PTF_LEAFDATA | PTF_INTKEY) ){
    +-    /* EVIDENCE-OF: R-03640-13415 A value of 5 means the page is an interior
    +-    ** table b-tree page. */
    ++    /* EVIDENCE-OF: R-07291-35328 A value of 5 (0x05) means the page is an
    ++    ** interior table b-tree page. */
    +     assert( (PTF_LEAFDATA|PTF_INTKEY)==5 );
    +-    /* EVIDENCE-OF: R-20501-61796 A value of 13 means the page is a leaf
    +-    ** table b-tree page. */
    ++    /* EVIDENCE-OF: R-26900-09176 A value of 13 (0x0d) means the page is a
    ++    ** leaf table b-tree page. */
    +     assert( (PTF_LEAFDATA|PTF_INTKEY|PTF_LEAF)==13 );
    +     pPage->intKey = 1;
    +     if( pPage->leaf ){
    +       pPage->intKeyLeaf = 1;
    +-      pPage->noPayload = 0;
    +       pPage->xParseCell = btreeParseCellPtr;
    +     }else{
    +       pPage->intKeyLeaf = 0;
    +-      pPage->noPayload = 1;
    +       pPage->xCellSize = cellSizePtrNoPayload;
    +       pPage->xParseCell = btreeParseCellPtrNoPayload;
    +     }
    +     pPage->maxLocal = pBt->maxLeaf;
    +     pPage->minLocal = pBt->minLeaf;
    +   }else if( flagByte==PTF_ZERODATA ){
    +-    /* EVIDENCE-OF: R-27225-53936 A value of 2 means the page is an interior
    +-    ** index b-tree page. */
    ++    /* EVIDENCE-OF: R-43316-37308 A value of 2 (0x02) means the page is an
    ++    ** interior index b-tree page. */
    +     assert( (PTF_ZERODATA)==2 );
    +-    /* EVIDENCE-OF: R-16571-11615 A value of 10 means the page is a leaf
    +-    ** index b-tree page. */
    ++    /* EVIDENCE-OF: R-59615-42828 A value of 10 (0x0a) means the page is a
    ++    ** leaf index b-tree page. */
    +     assert( (PTF_ZERODATA|PTF_LEAF)==10 );
    +     pPage->intKey = 0;
    +     pPage->intKeyLeaf = 0;
    +-    pPage->noPayload = 0;
    +     pPage->xParseCell = btreeParseCellPtrIndex;
    +     pPage->maxLocal = pBt->maxLocal;
    +     pPage->minLocal = pBt->minLocal;
    +   }else{
    +     /* EVIDENCE-OF: R-47608-56469 Any other value for the b-tree page type is
    +     ** an error. */
    +-    return SQLITE_CORRUPT_BKPT;
    ++    return SQLITE_CORRUPT_PAGE(pPage);
    +   }
    +   pPage->max1bytePayload = pBt->max1bytePayload;
    +   return SQLITE_OK;
    +@@ -56233,6 +62232,16 @@ static int decodeFlags(MemPage *pPage, int flagByte){
    + ** we failed to detect any corruption.
    + */
    + static int btreeInitPage(MemPage *pPage){
    ++  int pc;            /* Address of a freeblock within pPage->aData[] */
    ++  u8 hdr;            /* Offset to beginning of page header */
    ++  u8 *data;          /* Equal to pPage->aData */
    ++  BtShared *pBt;        /* The main btree structure */
    ++  int usableSize;    /* Amount of usable space on each page */
    ++  u16 cellOffset;    /* Offset from start of page to first cell pointer */
    ++  int nFree;         /* Number of unused bytes on the page */
    ++  int top;           /* First byte of the cell content area */
    ++  int iCellFirst;    /* First allowable cell or freeblock offset */
    ++  int iCellLast;     /* Last possible cell or freeblock offset */
    + 
    +   assert( pPage->pBt!=0 );
    +   assert( pPage->pBt->db!=0 );
    +@@ -56240,122 +62249,119 @@ static int btreeInitPage(MemPage *pPage){
    +   assert( pPage->pgno==sqlite3PagerPagenumber(pPage->pDbPage) );
    +   assert( pPage == sqlite3PagerGetExtra(pPage->pDbPage) );
    +   assert( pPage->aData == sqlite3PagerGetData(pPage->pDbPage) );
    ++  assert( pPage->isInit==0 );
    + 
    +-  if( !pPage->isInit ){
    +-    u16 pc;            /* Address of a freeblock within pPage->aData[] */
    +-    u8 hdr;            /* Offset to beginning of page header */
    +-    u8 *data;          /* Equal to pPage->aData */
    +-    BtShared *pBt;        /* The main btree structure */
    +-    int usableSize;    /* Amount of usable space on each page */
    +-    u16 cellOffset;    /* Offset from start of page to first cell pointer */
    +-    int nFree;         /* Number of unused bytes on the page */
    +-    int top;           /* First byte of the cell content area */
    +-    int iCellFirst;    /* First allowable cell or freeblock offset */
    +-    int iCellLast;     /* Last possible cell or freeblock offset */
    +-
    +-    pBt = pPage->pBt;
    +-
    +-    hdr = pPage->hdrOffset;
    +-    data = pPage->aData;
    +-    /* EVIDENCE-OF: R-28594-02890 The one-byte flag at offset 0 indicating
    +-    ** the b-tree page type. */
    +-    if( decodeFlags(pPage, data[hdr]) ) return SQLITE_CORRUPT_BKPT;
    +-    assert( pBt->pageSize>=512 && pBt->pageSize<=65536 );
    +-    pPage->maskPage = (u16)(pBt->pageSize - 1);
    +-    pPage->nOverflow = 0;
    +-    usableSize = pBt->usableSize;
    +-    pPage->cellOffset = cellOffset = hdr + 8 + pPage->childPtrSize;
    +-    pPage->aDataEnd = &data[usableSize];
    +-    pPage->aCellIdx = &data[cellOffset];
    +-    pPage->aDataOfst = &data[pPage->childPtrSize];
    +-    /* EVIDENCE-OF: R-58015-48175 The two-byte integer at offset 5 designates
    +-    ** the start of the cell content area. A zero value for this integer is
    +-    ** interpreted as 65536. */
    +-    top = get2byteNotZero(&data[hdr+5]);
    +-    /* EVIDENCE-OF: R-37002-32774 The two-byte integer at offset 3 gives the
    +-    ** number of cells on the page. */
    +-    pPage->nCell = get2byte(&data[hdr+3]);
    +-    if( pPage->nCell>MX_CELL(pBt) ){
    +-      /* To many cells for a single page.  The page must be corrupt */
    +-      return SQLITE_CORRUPT_BKPT;
    ++  pBt = pPage->pBt;
    ++  hdr = pPage->hdrOffset;
    ++  data = pPage->aData;
    ++  /* EVIDENCE-OF: R-28594-02890 The one-byte flag at offset 0 indicating
    ++  ** the b-tree page type. */
    ++  if( decodeFlags(pPage, data[hdr]) ){
    ++    return SQLITE_CORRUPT_PAGE(pPage);
    ++  }
    ++  assert( pBt->pageSize>=512 && pBt->pageSize<=65536 );
    ++  pPage->maskPage = (u16)(pBt->pageSize - 1);
    ++  pPage->nOverflow = 0;
    ++  usableSize = pBt->usableSize;
    ++  pPage->cellOffset = cellOffset = hdr + 8 + pPage->childPtrSize;
    ++  pPage->aDataEnd = &data[usableSize];
    ++  pPage->aCellIdx = &data[cellOffset];
    ++  pPage->aDataOfst = &data[pPage->childPtrSize];
    ++  /* EVIDENCE-OF: R-58015-48175 The two-byte integer at offset 5 designates
    ++  ** the start of the cell content area. A zero value for this integer is
    ++  ** interpreted as 65536. */
    ++  top = get2byteNotZero(&data[hdr+5]);
    ++  /* EVIDENCE-OF: R-37002-32774 The two-byte integer at offset 3 gives the
    ++  ** number of cells on the page. */
    ++  pPage->nCell = get2byte(&data[hdr+3]);
    ++  if( pPage->nCell>MX_CELL(pBt) ){
    ++    /* To many cells for a single page.  The page must be corrupt */
    ++    return SQLITE_CORRUPT_PAGE(pPage);
    ++  }
    ++  testcase( pPage->nCell==MX_CELL(pBt) );
    ++  /* EVIDENCE-OF: R-24089-57979 If a page contains no cells (which is only
    ++  ** possible for a root page of a table that contains no rows) then the
    ++  ** offset to the cell content area will equal the page size minus the
    ++  ** bytes of reserved space. */
    ++  assert( pPage->nCell>0 || top==usableSize || CORRUPT_DB );
    ++
    ++  /* A malformed database page might cause us to read past the end
    ++  ** of page when parsing a cell.  
    ++  **
    ++  ** The following block of code checks early to see if a cell extends
    ++  ** past the end of a page boundary and causes SQLITE_CORRUPT to be 
    ++  ** returned if it does.
    ++  */
    ++  iCellFirst = cellOffset + 2*pPage->nCell;
    ++  iCellLast = usableSize - 4;
    ++  if( pBt->db->flags & SQLITE_CellSizeCk ){
    ++    int i;            /* Index into the cell pointer array */
    ++    int sz;           /* Size of a cell */
    ++
    ++    if( !pPage->leaf ) iCellLast--;
    ++    for(i=0; i<pPage->nCell; i++){
    ++      pc = get2byteAligned(&data[cellOffset+i*2]);
    ++      testcase( pc==iCellFirst );
    ++      testcase( pc==iCellLast );
    ++      if( pc<iCellFirst || pc>iCellLast ){
    ++        return SQLITE_CORRUPT_PAGE(pPage);
    ++      }
    ++      sz = pPage->xCellSize(pPage, &data[pc]);
    ++      testcase( pc+sz==usableSize );
    ++      if( pc+sz>usableSize ){
    ++        return SQLITE_CORRUPT_PAGE(pPage);
    ++      }
    +     }
    +-    testcase( pPage->nCell==MX_CELL(pBt) );
    +-    /* EVIDENCE-OF: R-24089-57979 If a page contains no cells (which is only
    +-    ** possible for a root page of a table that contains no rows) then the
    +-    ** offset to the cell content area will equal the page size minus the
    +-    ** bytes of reserved space. */
    +-    assert( pPage->nCell>0 || top==usableSize || CORRUPT_DB );
    +-
    +-    /* A malformed database page might cause us to read past the end
    +-    ** of page when parsing a cell.  
    +-    **
    +-    ** The following block of code checks early to see if a cell extends
    +-    ** past the end of a page boundary and causes SQLITE_CORRUPT to be 
    +-    ** returned if it does.
    +-    */
    +-    iCellFirst = cellOffset + 2*pPage->nCell;
    +-    iCellLast = usableSize - 4;
    +-    if( pBt->db->flags & SQLITE_CellSizeCk ){
    +-      int i;            /* Index into the cell pointer array */
    +-      int sz;           /* Size of a cell */
    +-
    +-      if( !pPage->leaf ) iCellLast--;
    +-      for(i=0; i<pPage->nCell; i++){
    +-        pc = get2byteAligned(&data[cellOffset+i*2]);
    +-        testcase( pc==iCellFirst );
    +-        testcase( pc==iCellLast );
    +-        if( pc<iCellFirst || pc>iCellLast ){
    +-          return SQLITE_CORRUPT_BKPT;
    +-        }
    +-        sz = pPage->xCellSize(pPage, &data[pc]);
    +-        testcase( pc+sz==usableSize );
    +-        if( pc+sz>usableSize ){
    +-          return SQLITE_CORRUPT_BKPT;
    +-        }
    +-      }
    +-      if( !pPage->leaf ) iCellLast++;
    +-    }  
    ++    if( !pPage->leaf ) iCellLast++;
    ++  }  
    + 
    +-    /* Compute the total free space on the page
    +-    ** EVIDENCE-OF: R-23588-34450 The two-byte integer at offset 1 gives the
    +-    ** start of the first freeblock on the page, or is zero if there are no
    +-    ** freeblocks. */
    +-    pc = get2byte(&data[hdr+1]);
    +-    nFree = data[hdr+7] + top;  /* Init nFree to non-freeblock free space */
    +-    while( pc>0 ){
    +-      u16 next, size;
    +-      if( pc<iCellFirst || pc>iCellLast ){
    +-        /* EVIDENCE-OF: R-55530-52930 In a well-formed b-tree page, there will
    +-        ** always be at least one cell before the first freeblock.
    +-        **
    +-        ** Or, the freeblock is off the end of the page
    +-        */
    +-        return SQLITE_CORRUPT_BKPT; 
    ++  /* Compute the total free space on the page
    ++  ** EVIDENCE-OF: R-23588-34450 The two-byte integer at offset 1 gives the
    ++  ** start of the first freeblock on the page, or is zero if there are no
    ++  ** freeblocks. */
    ++  pc = get2byte(&data[hdr+1]);
    ++  nFree = data[hdr+7] + top;  /* Init nFree to non-freeblock free space */
    ++  if( pc>0 ){
    ++    u32 next, size;
    ++    if( pc<iCellFirst ){
    ++      /* EVIDENCE-OF: R-55530-52930 In a well-formed b-tree page, there will
    ++      ** always be at least one cell before the first freeblock.
    ++      */
    ++      return SQLITE_CORRUPT_PAGE(pPage); 
    ++    }
    ++    while( 1 ){
    ++      if( pc>iCellLast ){
    ++        /* Freeblock off the end of the page */
    ++        return SQLITE_CORRUPT_PAGE(pPage);
    +       }
    +       next = get2byte(&data[pc]);
    +       size = get2byte(&data[pc+2]);
    +-      if( (next>0 && next<=pc+size+3) || pc+size>usableSize ){
    +-        /* Free blocks must be in ascending order. And the last byte of
    +-        ** the free-block must lie on the database page.  */
    +-        return SQLITE_CORRUPT_BKPT; 
    +-      }
    +       nFree = nFree + size;
    ++      if( next<=pc+size+3 ) break;
    +       pc = next;
    +     }
    +-
    +-    /* At this point, nFree contains the sum of the offset to the start
    +-    ** of the cell-content area plus the number of free bytes within
    +-    ** the cell-content area. If this is greater than the usable-size
    +-    ** of the page, then the page must be corrupted. This check also
    +-    ** serves to verify that the offset to the start of the cell-content
    +-    ** area, according to the page header, lies within the page.
    +-    */
    +-    if( nFree>usableSize ){
    +-      return SQLITE_CORRUPT_BKPT; 
    ++    if( next>0 ){
    ++      /* Freeblock not in ascending order */
    ++      return SQLITE_CORRUPT_PAGE(pPage);
    ++    }
    ++    if( pc+size>(unsigned int)usableSize ){
    ++      /* Last freeblock extends past page end */
    ++      return SQLITE_CORRUPT_PAGE(pPage);
    +     }
    +-    pPage->nFree = (u16)(nFree - iCellFirst);
    +-    pPage->isInit = 1;
    +   }
    ++
    ++  /* At this point, nFree contains the sum of the offset to the start
    ++  ** of the cell-content area plus the number of free bytes within
    ++  ** the cell-content area. If this is greater than the usable-size
    ++  ** of the page, then the page must be corrupted. This check also
    ++  ** serves to verify that the offset to the start of the cell-content
    ++  ** area, according to the page header, lies within the page.
    ++  */
    ++  if( nFree>usableSize ){
    ++    return SQLITE_CORRUPT_PAGE(pPage);
    ++  }
    ++  pPage->nFree = (u16)(nFree - iCellFirst);
    ++  pPage->isInit = 1;
    +   return SQLITE_OK;
    + }
    + 
    +@@ -56374,7 +62380,7 @@ static void zeroPage(MemPage *pPage, int flags){
    +   assert( sqlite3PagerGetData(pPage->pDbPage) == data );
    +   assert( sqlite3PagerIswriteable(pPage->pDbPage) );
    +   assert( sqlite3_mutex_held(pBt->mutex) );
    +-  if( pBt->btsFlags & BTS_SECURE_DELETE ){
    ++  if( pBt->btsFlags & BTS_FAST_SECURE ){
    +     memset(&data[hdr], 0, pBt->usableSize - hdr);
    +   }
    +   data[hdr] = (char)flags;
    +@@ -56402,11 +62408,14 @@ static void zeroPage(MemPage *pPage, int flags){
    + */
    + static MemPage *btreePageFromDbPage(DbPage *pDbPage, Pgno pgno, BtShared *pBt){
    +   MemPage *pPage = (MemPage*)sqlite3PagerGetExtra(pDbPage);
    +-  pPage->aData = sqlite3PagerGetData(pDbPage);
    +-  pPage->pDbPage = pDbPage;
    +-  pPage->pBt = pBt;
    +-  pPage->pgno = pgno;
    +-  pPage->hdrOffset = pgno==1 ? 100 : 0;
    ++  if( pgno!=pPage->pgno ){
    ++    pPage->aData = sqlite3PagerGetData(pDbPage);
    ++    pPage->pDbPage = pDbPage;
    ++    pPage->pBt = pBt;
    ++    pPage->pgno = pgno;
    ++    pPage->hdrOffset = pgno==1 ? 100 : 0;
    ++  }
    ++  assert( pPage->aData==sqlite3PagerGetData(pDbPage) );
    +   return pPage; 
    + }
    + 
    +@@ -56432,7 +62441,7 @@ static int btreeGetPage(
    + 
    +   assert( flags==0 || flags==PAGER_GET_NOCONTENT || flags==PAGER_GET_READONLY );
    +   assert( sqlite3_mutex_held(pBt->mutex) );
    +-  rc = sqlite3PagerAcquire(pBt->pPager, pgno, (DbPage**)&pDbPage, flags);
    ++  rc = sqlite3PagerGet(pBt->pPager, pgno, (DbPage**)&pDbPage, flags);
    +   if( rc ) return rc;
    +   *ppPage = btreePageFromDbPage(pDbPage, pgno, pBt);
    +   return SQLITE_OK;
    +@@ -56462,7 +62471,7 @@ static Pgno btreePagecount(BtShared *pBt){
    + }
    + SQLITE_PRIVATE u32 sqlite3BtreeLastPage(Btree *p){
    +   assert( sqlite3BtreeHoldsMutex(p) );
    +-  assert( ((p->pBt->nPage)&0x8000000)==0 );
    ++  assert( ((p->pBt->nPage)&0x80000000)==0 );
    +   return btreePagecount(p->pBt);
    + }
    + 
    +@@ -56489,7 +62498,7 @@ static int getAndInitPage(
    +   int rc;
    +   DbPage *pDbPage;
    +   assert( sqlite3_mutex_held(pBt->mutex) );
    +-  assert( pCur==0 || ppPage==&pCur->apPage[pCur->iPage] );
    ++  assert( pCur==0 || ppPage==&pCur->pPage );
    +   assert( pCur==0 || bReadOnly==pCur->curPagerFlags );
    +   assert( pCur==0 || pCur->iPage>0 );
    + 
    +@@ -56497,32 +62506,36 @@ static int getAndInitPage(
    +     rc = SQLITE_CORRUPT_BKPT;
    +     goto getAndInitPage_error;
    +   }
    +-  rc = sqlite3PagerAcquire(pBt->pPager, pgno, (DbPage**)&pDbPage, bReadOnly);
    ++  rc = sqlite3PagerGet(pBt->pPager, pgno, (DbPage**)&pDbPage, bReadOnly);
    +   if( rc ){
    +     goto getAndInitPage_error;
    +   }
    +-  *ppPage = btreePageFromDbPage(pDbPage, pgno, pBt);
    ++  *ppPage = (MemPage*)sqlite3PagerGetExtra(pDbPage);
    +   if( (*ppPage)->isInit==0 ){
    ++    btreePageFromDbPage(pDbPage, pgno, pBt);
    +     rc = btreeInitPage(*ppPage);
    +     if( rc!=SQLITE_OK ){
    +       releasePage(*ppPage);
    +       goto getAndInitPage_error;
    +     }
    +   }
    ++  assert( (*ppPage)->pgno==pgno );
    ++  assert( (*ppPage)->aData==sqlite3PagerGetData(pDbPage) );
    + 
    +   /* If obtaining a child page for a cursor, we must verify that the page is
    +   ** compatible with the root page. */
    +-  if( pCur
    +-   && ((*ppPage)->nCell<1 || (*ppPage)->intKey!=pCur->curIntKey)
    +-  ){
    +-    rc = SQLITE_CORRUPT_BKPT;
    ++  if( pCur && ((*ppPage)->nCell<1 || (*ppPage)->intKey!=pCur->curIntKey) ){
    ++    rc = SQLITE_CORRUPT_PGNO(pgno);
    +     releasePage(*ppPage);
    +     goto getAndInitPage_error;
    +   }
    +   return SQLITE_OK;
    + 
    + getAndInitPage_error:
    +-  if( pCur ) pCur->iPage--;
    ++  if( pCur ){
    ++    pCur->iPage--;
    ++    pCur->pPage = pCur->apPage[pCur->iPage];
    ++  }
    +   testcase( pgno==0 );
    +   assert( pgno!=0 || rc==SQLITE_CORRUPT );
    +   return rc;
    +@@ -56531,6 +62544,8 @@ getAndInitPage_error:
    + /*
    + ** Release a MemPage.  This should be called once for each prior
    + ** call to btreeGetPage.
    ++**
    ++** Page1 is a special case and must be released using releasePageOne().
    + */
    + static void releasePageNotNull(MemPage *pPage){
    +   assert( pPage->aData );
    +@@ -56544,6 +62559,16 @@ static void releasePageNotNull(MemPage *pPage){
    + static void releasePage(MemPage *pPage){
    +   if( pPage ) releasePageNotNull(pPage);
    + }
    ++static void releasePageOne(MemPage *pPage){
    ++  assert( pPage!=0 );
    ++  assert( pPage->aData );
    ++  assert( pPage->pBt );
    ++  assert( pPage->pDbPage!=0 );
    ++  assert( sqlite3PagerGetExtra(pPage->pDbPage) == (void*)pPage );
    ++  assert( sqlite3PagerGetData(pPage->pDbPage)==pPage->aData );
    ++  assert( sqlite3_mutex_held(pPage->pBt->mutex) );
    ++  sqlite3PagerUnrefPageOne(pPage->pDbPage);
    ++}
    + 
    + /*
    + ** Get an unused page.
    +@@ -56681,7 +62706,7 @@ SQLITE_PRIVATE int sqlite3BtreeOpen(
    +   }
    +   p = sqlite3MallocZero(sizeof(Btree));
    +   if( !p ){
    +-    return SQLITE_NOMEM;
    ++    return SQLITE_NOMEM_BKPT;
    +   }
    +   p->inTrans = TRANS_NONE;
    +   p->db = db;
    +@@ -56705,7 +62730,7 @@ SQLITE_PRIVATE int sqlite3BtreeOpen(
    +       p->sharable = 1;
    +       if( !zFullPathname ){
    +         sqlite3_free(p);
    +-        return SQLITE_NOMEM;
    ++        return SQLITE_NOMEM_BKPT;
    +       }
    +       if( isMemdb ){
    +         memcpy(zFullPathname, zFilename, nFilename);
    +@@ -56773,11 +62798,11 @@ SQLITE_PRIVATE int sqlite3BtreeOpen(
    +   
    +     pBt = sqlite3MallocZero( sizeof(*pBt) );
    +     if( pBt==0 ){
    +-      rc = SQLITE_NOMEM;
    ++      rc = SQLITE_NOMEM_BKPT;
    +       goto btree_open_out;
    +     }
    +     rc = sqlite3PagerOpen(pVfs, &pBt->pPager, zFilename,
    +-                          EXTRA_SIZE, flags, vfsFlags, pageReinit);
    ++                          sizeof(MemPage), flags, vfsFlags, pageReinit);
    +     if( rc==SQLITE_OK ){
    +       sqlite3PagerSetMmapLimit(pBt->pPager, db->szMmap);
    +       rc = sqlite3PagerReadFileheader(pBt->pPager,sizeof(zDbHeader),zDbHeader);
    +@@ -56793,8 +62818,10 @@ SQLITE_PRIVATE int sqlite3BtreeOpen(
    +     pBt->pCursor = 0;
    +     pBt->pPage1 = 0;
    +     if( sqlite3PagerIsreadonly(pBt->pPager) ) pBt->btsFlags |= BTS_READ_ONLY;
    +-#ifdef SQLITE_SECURE_DELETE
    ++#if defined(SQLITE_SECURE_DELETE)
    +     pBt->btsFlags |= BTS_SECURE_DELETE;
    ++#elif defined(SQLITE_FAST_SECURE_DELETE)
    ++    pBt->btsFlags |= BTS_OVERWRITE;
    + #endif
    +     /* EVIDENCE-OF: R-51873-39618 The page size for a database file is
    +     ** determined by the 2-byte integer located at an offset of 16 bytes from
    +@@ -56835,15 +62862,14 @@ SQLITE_PRIVATE int sqlite3BtreeOpen(
    + #if !defined(SQLITE_OMIT_SHARED_CACHE) && !defined(SQLITE_OMIT_DISKIO)
    +     /* Add the new BtShared object to the linked list sharable BtShareds.
    +     */
    ++    pBt->nRef = 1;
    +     if( p->sharable ){
    +       MUTEX_LOGIC( sqlite3_mutex *mutexShared; )
    +-      pBt->nRef = 1;
    +       MUTEX_LOGIC( mutexShared = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MASTER);)
    +       if( SQLITE_THREADSAFE && sqlite3GlobalConfig.bCoreMutex ){
    +         pBt->mutex = sqlite3MutexAlloc(SQLITE_MUTEX_FAST);
    +         if( pBt->mutex==0 ){
    +-          rc = SQLITE_NOMEM;
    +-          db->mallocFailed = 0;
    ++          rc = SQLITE_NOMEM_BKPT;
    +           goto btree_open_out;
    +         }
    +       }
    +@@ -56866,12 +62892,12 @@ SQLITE_PRIVATE int sqlite3BtreeOpen(
    +     for(i=0; i<db->nDb; i++){
    +       if( (pSib = db->aDb[i].pBt)!=0 && pSib->sharable ){
    +         while( pSib->pPrev ){ pSib = pSib->pPrev; }
    +-        if( p->pBt<pSib->pBt ){
    ++        if( (uptr)p->pBt<(uptr)pSib->pBt ){
    +           p->pNext = pSib;
    +           p->pPrev = 0;
    +           pSib->pPrev = p;
    +         }else{
    +-          while( pSib->pNext && pSib->pNext->pBt<p->pBt ){
    ++          while( pSib->pNext && (uptr)pSib->pNext->pBt<(uptr)p->pBt ){
    +             pSib = pSib->pNext;
    +           }
    +           p->pNext = pSib->pNext;
    +@@ -56891,12 +62917,14 @@ SQLITE_PRIVATE int sqlite3BtreeOpen(
    + btree_open_out:
    +   if( rc!=SQLITE_OK ){
    +     if( pBt && pBt->pPager ){
    +-      sqlite3PagerClose(pBt->pPager);
    ++      sqlite3PagerClose(pBt->pPager, 0);
    +     }
    +     sqlite3_free(pBt);
    +     sqlite3_free(p);
    +     *ppBtree = 0;
    +   }else{
    ++    sqlite3_file *pFile;
    ++
    +     /* If the B-Tree was successfully opened, set the pager-cache size to the
    +     ** default value. Except, when opening on an existing shared pager-cache,
    +     ** do not change the pager-cache size.
    +@@ -56904,11 +62932,17 @@ btree_open_out:
    +     if( sqlite3BtreeSchema(p, 0, 0)==0 ){
    +       sqlite3PagerSetCachesize(p->pBt->pPager, SQLITE_DEFAULT_CACHE_SIZE);
    +     }
    ++
    ++    pFile = sqlite3PagerFile(pBt->pPager);
    ++    if( pFile->pMethods ){
    ++      sqlite3OsFileControlHint(pFile, SQLITE_FCNTL_PDB, (void*)&pBt->db);
    ++    }
    +   }
    +   if( mutexOpen ){
    +     assert( sqlite3_mutex_held(mutexOpen) );
    +     sqlite3_mutex_leave(mutexOpen);
    +   }
    ++  assert( rc!=SQLITE_OK || sqlite3BtreeConnectionCount(*ppBtree)>0 );
    +   return rc;
    + }
    + 
    +@@ -57032,7 +63066,7 @@ SQLITE_PRIVATE int sqlite3BtreeClose(Btree *p){
    +     ** Clean out and delete the BtShared object.
    +     */
    +     assert( !pBt->pCursor );
    +-    sqlite3PagerClose(pBt->pPager);
    ++    sqlite3PagerClose(pBt->pPager, p->db);
    +     if( pBt->xFreeSchema && pBt->pSchema ){
    +       pBt->xFreeSchema(pBt->pSchema);
    +     }
    +@@ -57053,19 +63087,11 @@ SQLITE_PRIVATE int sqlite3BtreeClose(Btree *p){
    + }
    + 
    + /*
    +-** Change the limit on the number of pages allowed in the cache.
    +-**
    +-** The maximum number of cache pages is set to the absolute
    +-** value of mxPage.  If mxPage is negative, the pager will
    +-** operate asynchronously - it will not stop to do fsync()s
    +-** to insure data is written to the disk surface before
    +-** continuing.  Transactions still work if synchronous is off,
    +-** and the database cannot be corrupted if this program
    +-** crashes.  But if the operating system crashes or there is
    +-** an abrupt power failure when synchronous is off, the database
    +-** could be left in an inconsistent and unrecoverable state.
    +-** Synchronous is on by default so database corruption is not
    +-** normally a worry.
    ++** Change the "soft" limit on the number of pages in the cache.
    ++** Unused and unmodified pages will be recycled when the number of
    ++** pages in the cache exceeds this soft limit.  But the size of the
    ++** cache is allowed to grow larger than this limit if it contains
    ++** dirty pages or pages still in active use.
    + */
    + SQLITE_PRIVATE int sqlite3BtreeSetCacheSize(Btree *p, int mxPage){
    +   BtShared *pBt = p->pBt;
    +@@ -57076,6 +63102,26 @@ SQLITE_PRIVATE int sqlite3BtreeSetCacheSize(Btree *p, int mxPage){
    +   return SQLITE_OK;
    + }
    + 
    ++/*
    ++** Change the "spill" limit on the number of pages in the cache.
    ++** If the number of pages exceeds this limit during a write transaction,
    ++** the pager might attempt to "spill" pages to the journal early in
    ++** order to free up memory.
    ++**
    ++** The value returned is the current spill size.  If zero is passed
    ++** as an argument, no changes are made to the spill size setting, so
    ++** using mxPage of 0 is a way to query the current spill size.
    ++*/
    ++SQLITE_PRIVATE int sqlite3BtreeSetSpillSize(Btree *p, int mxPage){
    ++  BtShared *pBt = p->pBt;
    ++  int res;
    ++  assert( sqlite3_mutex_held(p->db->mutex) );
    ++  sqlite3BtreeEnter(p);
    ++  res = sqlite3PagerSetSpillsize(pBt->pPager, mxPage);
    ++  sqlite3BtreeLeave(p);
    ++  return res;
    ++}
    ++
    + #if SQLITE_MAX_MMAP_SIZE>0
    + /*
    + ** Change the limit on the amount of the database file that may be
    +@@ -57113,21 +63159,6 @@ SQLITE_PRIVATE int sqlite3BtreeSetPagerFlags(
    + }
    + #endif
    + 
    +-/*
    +-** Return TRUE if the given btree is set to safety level 1.  In other
    +-** words, return TRUE if no sync() occurs on the disk files.
    +-*/
    +-SQLITE_PRIVATE int sqlite3BtreeSyncDisabled(Btree *p){
    +-  BtShared *pBt = p->pBt;
    +-  int rc;
    +-  assert( sqlite3_mutex_held(p->db->mutex) );  
    +-  sqlite3BtreeEnter(p);
    +-  assert( pBt && pBt->pPager );
    +-  rc = sqlite3PagerNosync(pBt->pPager);
    +-  sqlite3BtreeLeave(p);
    +-  return rc;
    +-}
    +-
    + /*
    + ** Change the default pages size and the number of reserved bytes per page.
    + ** Or, if the page size has already been fixed, return SQLITE_READONLY 
    +@@ -57238,19 +63269,34 @@ SQLITE_PRIVATE int sqlite3BtreeMaxPageCount(Btree *p, int mxPage){
    + }
    + 
    + /*
    +-** Set the BTS_SECURE_DELETE flag if newFlag is 0 or 1.  If newFlag is -1,
    +-** then make no changes.  Always return the value of the BTS_SECURE_DELETE
    +-** setting after the change.
    ++** Change the values for the BTS_SECURE_DELETE and BTS_OVERWRITE flags:
    ++**
    ++**    newFlag==0       Both BTS_SECURE_DELETE and BTS_OVERWRITE are cleared
    ++**    newFlag==1       BTS_SECURE_DELETE set and BTS_OVERWRITE is cleared
    ++**    newFlag==2       BTS_SECURE_DELETE cleared and BTS_OVERWRITE is set
    ++**    newFlag==(-1)    No changes
    ++**
    ++** This routine acts as a query if newFlag is less than zero
    ++**
    ++** With BTS_OVERWRITE set, deleted content is overwritten by zeros, but
    ++** freelist leaf pages are not written back to the database.  Thus in-page
    ++** deleted content is cleared, but freelist deleted content is not.
    ++**
    ++** With BTS_SECURE_DELETE, operation is like BTS_OVERWRITE with the addition
    ++** that freelist leaf pages are written back into the database, increasing
    ++** the amount of disk I/O.
    + */
    + SQLITE_PRIVATE int sqlite3BtreeSecureDelete(Btree *p, int newFlag){
    +   int b;
    +   if( p==0 ) return 0;
    +   sqlite3BtreeEnter(p);
    ++  assert( BTS_OVERWRITE==BTS_SECURE_DELETE*2 );
    ++  assert( BTS_FAST_SECURE==(BTS_OVERWRITE|BTS_SECURE_DELETE) );
    +   if( newFlag>=0 ){
    +-    p->pBt->btsFlags &= ~BTS_SECURE_DELETE;
    +-    if( newFlag ) p->pBt->btsFlags |= BTS_SECURE_DELETE;
    +-  } 
    +-  b = (p->pBt->btsFlags & BTS_SECURE_DELETE)!=0;
    ++    p->pBt->btsFlags &= ~BTS_FAST_SECURE;
    ++    p->pBt->btsFlags |= BTS_SECURE_DELETE*newFlag;
    ++  }
    ++  b = (p->pBt->btsFlags & BTS_FAST_SECURE)/BTS_SECURE_DELETE;
    +   sqlite3BtreeLeave(p);
    +   return b;
    + }
    +@@ -57301,6 +63347,32 @@ SQLITE_PRIVATE int sqlite3BtreeGetAutoVacuum(Btree *p){
    + #endif
    + }
    + 
    ++/*
    ++** If the user has not set the safety-level for this database connection
    ++** using "PRAGMA synchronous", and if the safety-level is not already
    ++** set to the value passed to this function as the second parameter,
    ++** set it so.
    ++*/
    ++#if SQLITE_DEFAULT_SYNCHRONOUS!=SQLITE_DEFAULT_WAL_SYNCHRONOUS \
    ++    && !defined(SQLITE_OMIT_WAL)
    ++static void setDefaultSyncFlag(BtShared *pBt, u8 safety_level){
    ++  sqlite3 *db;
    ++  Db *pDb;
    ++  if( (db=pBt->db)!=0 && (pDb=db->aDb)!=0 ){
    ++    while( pDb->pBt==0 || pDb->pBt->pBt!=pBt ){ pDb++; }
    ++    if( pDb->bSyncSet==0 
    ++     && pDb->safety_level!=safety_level 
    ++     && pDb!=&db->aDb[1] 
    ++    ){
    ++      pDb->safety_level = safety_level;
    ++      sqlite3PagerSetFlags(pBt->pPager,
    ++          pDb->safety_level | (db->flags & PAGER_FLAGS_MASK));
    ++    }
    ++  }
    ++}
    ++#else
    ++# define setDefaultSyncFlag(pBt,safety_level)
    ++#endif
    + 
    + /*
    + ** Get a reference to pPage1 of the database file.  This will
    +@@ -57373,11 +63445,16 @@ static int lockBtree(BtShared *pBt){
    +       rc = sqlite3PagerOpenWal(pBt->pPager, &isOpen);
    +       if( rc!=SQLITE_OK ){
    +         goto page1_init_failed;
    +-      }else if( isOpen==0 ){
    +-        releasePage(pPage1);
    +-        return SQLITE_OK;
    ++      }else{
    ++        setDefaultSyncFlag(pBt, SQLITE_DEFAULT_WAL_SYNCHRONOUS+1);
    ++        if( isOpen==0 ){
    ++          releasePageOne(pPage1);
    ++          return SQLITE_OK;
    ++        }
    +       }
    +       rc = SQLITE_NOTADB;
    ++    }else{
    ++      setDefaultSyncFlag(pBt, SQLITE_DEFAULT_SYNCHRONOUS+1);
    +     }
    + #endif
    + 
    +@@ -57418,7 +63495,7 @@ static int lockBtree(BtShared *pBt){
    +       ** zero and return SQLITE_OK. The caller will call this function
    +       ** again with the correct page-size.
    +       */
    +-      releasePage(pPage1);
    ++      releasePageOne(pPage1);
    +       pBt->usableSize = usableSize;
    +       pBt->pageSize = pageSize;
    +       freeTempSpace(pBt);
    +@@ -57426,7 +63503,7 @@ static int lockBtree(BtShared *pBt){
    +                                    pageSize-usableSize);
    +       return rc;
    +     }
    +-    if( (pBt->db->flags & SQLITE_RecoveryMode)==0 && nPage>nPageFile ){
    ++    if( (pBt->db->flags & SQLITE_WriteSchema)==0 && nPage>nPageFile ){
    +       rc = SQLITE_CORRUPT_BKPT;
    +       goto page1_init_failed;
    +     }
    +@@ -57472,7 +63549,7 @@ static int lockBtree(BtShared *pBt){
    +   return SQLITE_OK;
    + 
    + page1_init_failed:
    +-  releasePage(pPage1);
    ++  releasePageOne(pPage1);
    +   pBt->pPage1 = 0;
    +   return rc;
    + }
    +@@ -57517,7 +63594,7 @@ static void unlockBtreeIfUnused(BtShared *pBt){
    +     assert( pPage1->aData );
    +     assert( sqlite3PagerRefcount(pBt->pPager)==1 );
    +     pBt->pPage1 = 0;
    +-    releasePageNotNull(pPage1);
    ++    releasePageOne(pPage1);
    +   }
    + }
    + 
    +@@ -57615,7 +63692,6 @@ SQLITE_PRIVATE int sqlite3BtreeNewDb(Btree *p){
    + ** proceed.
    + */
    + SQLITE_PRIVATE int sqlite3BtreeBeginTrans(Btree *p, int wrflag){
    +-  sqlite3 *pBlock = 0;
    +   BtShared *pBt = p->pBt;
    +   int rc = SQLITE_OK;
    + 
    +@@ -57638,27 +63714,30 @@ SQLITE_PRIVATE int sqlite3BtreeBeginTrans(Btree *p, int wrflag){
    +   }
    + 
    + #ifndef SQLITE_OMIT_SHARED_CACHE
    +-  /* If another database handle has already opened a write transaction 
    +-  ** on this shared-btree structure and a second write transaction is
    +-  ** requested, return SQLITE_LOCKED.
    +-  */
    +-  if( (wrflag && pBt->inTransaction==TRANS_WRITE)
    +-   || (pBt->btsFlags & BTS_PENDING)!=0
    +-  ){
    +-    pBlock = pBt->pWriter->db;
    +-  }else if( wrflag>1 ){
    +-    BtLock *pIter;
    +-    for(pIter=pBt->pLock; pIter; pIter=pIter->pNext){
    +-      if( pIter->pBtree!=p ){
    +-        pBlock = pIter->pBtree->db;
    +-        break;
    ++  {
    ++    sqlite3 *pBlock = 0;
    ++    /* If another database handle has already opened a write transaction 
    ++    ** on this shared-btree structure and a second write transaction is
    ++    ** requested, return SQLITE_LOCKED.
    ++    */
    ++    if( (wrflag && pBt->inTransaction==TRANS_WRITE)
    ++     || (pBt->btsFlags & BTS_PENDING)!=0
    ++    ){
    ++      pBlock = pBt->pWriter->db;
    ++    }else if( wrflag>1 ){
    ++      BtLock *pIter;
    ++      for(pIter=pBt->pLock; pIter; pIter=pIter->pNext){
    ++        if( pIter->pBtree!=p ){
    ++          pBlock = pIter->pBtree->db;
    ++          break;
    ++        }
    +       }
    +     }
    +-  }
    +-  if( pBlock ){
    +-    sqlite3ConnectionBlocked(p->db, pBlock);
    +-    rc = SQLITE_LOCKED_SHAREDCACHE;
    +-    goto trans_begun;
    ++    if( pBlock ){
    ++      sqlite3ConnectionBlocked(p->db, pBlock);
    ++      rc = SQLITE_LOCKED_SHAREDCACHE;
    ++      goto trans_begun;
    ++    }
    +   }
    + #endif
    + 
    +@@ -57764,14 +63843,11 @@ static int setChildPtrmaps(MemPage *pPage){
    +   int nCell;                         /* Number of cells in page pPage */
    +   int rc;                            /* Return code */
    +   BtShared *pBt = pPage->pBt;
    +-  u8 isInitOrig = pPage->isInit;
    +   Pgno pgno = pPage->pgno;
    + 
    +   assert( sqlite3_mutex_held(pPage->pBt->mutex) );
    +-  rc = btreeInitPage(pPage);
    +-  if( rc!=SQLITE_OK ){
    +-    goto set_child_ptrmaps_out;
    +-  }
    ++  rc = pPage->isInit ? SQLITE_OK : btreeInitPage(pPage);
    ++  if( rc!=SQLITE_OK ) return rc;
    +   nCell = pPage->nCell;
    + 
    +   for(i=0; i<nCell; i++){
    +@@ -57790,8 +63866,6 @@ static int setChildPtrmaps(MemPage *pPage){
    +     ptrmapPut(pBt, childPgno, PTRMAP_BTREE, pgno, &rc);
    +   }
    + 
    +-set_child_ptrmaps_out:
    +-  pPage->isInit = isInitOrig;
    +   return rc;
    + }
    + 
    +@@ -57815,16 +63889,15 @@ static int modifyPagePointer(MemPage *pPage, Pgno iFrom, Pgno iTo, u8 eType){
    +   if( eType==PTRMAP_OVERFLOW2 ){
    +     /* The pointer is always the first 4 bytes of the page in this case.  */
    +     if( get4byte(pPage->aData)!=iFrom ){
    +-      return SQLITE_CORRUPT_BKPT;
    ++      return SQLITE_CORRUPT_PAGE(pPage);
    +     }
    +     put4byte(pPage->aData, iTo);
    +   }else{
    +-    u8 isInitOrig = pPage->isInit;
    +     int i;
    +     int nCell;
    +     int rc;
    + 
    +-    rc = btreeInitPage(pPage);
    ++    rc = pPage->isInit ? SQLITE_OK : btreeInitPage(pPage);
    +     if( rc ) return rc;
    +     nCell = pPage->nCell;
    + 
    +@@ -57833,12 +63906,14 @@ static int modifyPagePointer(MemPage *pPage, Pgno iFrom, Pgno iTo, u8 eType){
    +       if( eType==PTRMAP_OVERFLOW1 ){
    +         CellInfo info;
    +         pPage->xParseCell(pPage, pCell, &info);
    +-        if( info.iOverflow
    +-         && pCell+info.iOverflow+3<=pPage->aData+pPage->maskPage
    +-         && iFrom==get4byte(&pCell[info.iOverflow])
    +-        ){
    +-          put4byte(&pCell[info.iOverflow], iTo);
    +-          break;
    ++        if( info.nLocal<info.nPayload ){
    ++          if( pCell+info.nSize > pPage->aData+pPage->pBt->usableSize ){
    ++            return SQLITE_CORRUPT_PAGE(pPage);
    ++          }
    ++          if( iFrom==get4byte(pCell+info.nSize-4) ){
    ++            put4byte(pCell+info.nSize-4, iTo);
    ++            break;
    ++          }
    +         }
    +       }else{
    +         if( get4byte(pCell)==iFrom ){
    +@@ -57851,12 +63926,10 @@ static int modifyPagePointer(MemPage *pPage, Pgno iFrom, Pgno iTo, u8 eType){
    +     if( i==nCell ){
    +       if( eType!=PTRMAP_BTREE || 
    +           get4byte(&pPage->aData[pPage->hdrOffset+8])!=iFrom ){
    +-        return SQLITE_CORRUPT_BKPT;
    ++        return SQLITE_CORRUPT_PAGE(pPage);
    +       }
    +       put4byte(&pPage->aData[pPage->hdrOffset+8], iTo);
    +     }
    +-
    +-    pPage->isInit = isInitOrig;
    +   }
    +   return SQLITE_OK;
    + }
    +@@ -58373,7 +64446,6 @@ SQLITE_PRIVATE int sqlite3BtreeTripAllCursors(Btree *pBtree, int errCode, int wr
    +   if( pBtree ){
    +     sqlite3BtreeEnter(pBtree);
    +     for(p=pBtree->pBt->pCursor; p; p=p->pNext){
    +-      int i;
    +       if( writeOnly && (p->curFlags & BTCF_WriteFlag)==0 ){
    +         if( p->eState==CURSOR_VALID || p->eState==CURSOR_SKIPNEXT ){
    +           rc = saveCursorPosition(p);
    +@@ -58387,10 +64459,7 @@ SQLITE_PRIVATE int sqlite3BtreeTripAllCursors(Btree *pBtree, int errCode, int wr
    +         p->eState = CURSOR_FAULT;
    +         p->skipNext = errCode;
    +       }
    +-      for(i=0; i<=p->iPage; i++){
    +-        releasePage(p->apPage[i]);
    +-        p->apPage[i] = 0;
    +-      }
    ++      btreeReleaseAllCursorPages(p);
    +     }
    +     sqlite3BtreeLeave(pBtree);
    +   }
    +@@ -58447,7 +64516,7 @@ SQLITE_PRIVATE int sqlite3BtreeRollback(Btree *p, int tripCode, int writeOnly){
    +       if( nPage==0 ) sqlite3PagerPagecount(pBt->pPager, &nPage);
    +       testcase( pBt->nPage!=nPage );
    +       pBt->nPage = nPage;
    +-      releasePage(pPage1);
    ++      releasePageOne(pPage1);
    +     }
    +     assert( countValidCursors(pBt, 1)==0 );
    +     pBt->inTransaction = TRANS_READ;
    +@@ -58515,7 +64584,12 @@ SQLITE_PRIVATE int sqlite3BtreeSavepoint(Btree *p, int op, int iSavepoint){
    +     assert( op==SAVEPOINT_RELEASE || op==SAVEPOINT_ROLLBACK );
    +     assert( iSavepoint>=0 || (iSavepoint==-1 && op==SAVEPOINT_ROLLBACK) );
    +     sqlite3BtreeEnter(p);
    +-    rc = sqlite3PagerSavepoint(pBt->pPager, op, iSavepoint);
    ++    if( op==SAVEPOINT_ROLLBACK ){
    ++      rc = saveAllCursors(pBt, 0, 0);
    ++    }
    ++    if( rc==SQLITE_OK ){
    ++      rc = sqlite3PagerSavepoint(pBt->pPager, op, iSavepoint);
    ++    }
    +     if( rc==SQLITE_OK ){
    +       if( iSavepoint<0 && (pBt->btsFlags & BTS_INITIALLY_EMPTY)!=0 ){
    +         pBt->nPage = 0;
    +@@ -58540,13 +64614,13 @@ SQLITE_PRIVATE int sqlite3BtreeSavepoint(Btree *p, int op, int iSavepoint){
    + ** on the database already. If a write-cursor is requested, then
    + ** the caller is assumed to have an open write transaction.
    + **
    +-** If wrFlag==0, then the cursor can only be used for reading.
    +-** If wrFlag==1, then the cursor can be used for reading or for
    +-** writing if other conditions for writing are also met.  These
    +-** are the conditions that must be met in order for writing to
    +-** be allowed:
    ++** If the BTREE_WRCSR bit of wrFlag is clear, then the cursor can only
    ++** be used for reading.  If the BTREE_WRCSR bit is set, then the cursor
    ++** can be used for reading or for writing if other conditions for writing
    ++** are also met.  These are the conditions that must be met in order
    ++** for writing to be allowed:
    + **
    +-** 1:  The cursor must have been opened with wrFlag==1
    ++** 1:  The cursor must have been opened with wrFlag containing BTREE_WRCSR
    + **
    + ** 2:  Other database connections that share the same pager cache
    + **     but which are not in the READ_UNCOMMITTED state may not have
    +@@ -58558,6 +64632,16 @@ SQLITE_PRIVATE int sqlite3BtreeSavepoint(Btree *p, int op, int iSavepoint){
    + **
    + ** 4:  There must be an active transaction.
    + **
    ++** The BTREE_FORDELETE bit of wrFlag may optionally be set if BTREE_WRCSR
    ++** is set.  If FORDELETE is set, that is a hint to the implementation that
    ++** this cursor will only be used to seek to and delete entries of an index
    ++** as part of a larger DELETE statement.  The FORDELETE hint is not used by
    ++** this implementation.  But in a hypothetical alternative storage engine 
    ++** in which index entries are automatically deleted when corresponding table
    ++** rows are deleted, the FORDELETE flag is a hint that all SEEK and DELETE
    ++** operations on this cursor can be no-ops and all READ operations can 
    ++** return a null row (2-bytes: 0x01 0x00).
    ++**
    + ** No checking is done to make sure that page iTable really is the
    + ** root page of a b-tree.  If it is not, then the cursor acquired
    + ** will not work correctly.
    +@@ -58576,13 +64660,16 @@ static int btreeCursor(
    +   BtCursor *pX;                          /* Looping over other all cursors */
    + 
    +   assert( sqlite3BtreeHoldsMutex(p) );
    +-  assert( wrFlag==0 || wrFlag==1 );
    ++  assert( wrFlag==0 
    ++       || wrFlag==BTREE_WRCSR 
    ++       || wrFlag==(BTREE_WRCSR|BTREE_FORDELETE) 
    ++  );
    + 
    +   /* The following assert statements verify that if this is a sharable 
    +   ** b-tree database, the connection is holding the required table locks, 
    +   ** and that no other connection has any open cursor that conflicts with 
    +   ** this lock.  */
    +-  assert( hasSharedCacheTableLock(p, iTable, pKeyInfo!=0, wrFlag+1) );
    ++  assert( hasSharedCacheTableLock(p, iTable, pKeyInfo!=0, (wrFlag?2:1)) );
    +   assert( wrFlag==0 || !hasReadConflicts(p, iTable) );
    + 
    +   /* Assert that the caller has opened the required transaction. */
    +@@ -58593,7 +64680,7 @@ static int btreeCursor(
    + 
    +   if( wrFlag ){
    +     allocateTempSpace(pBt);
    +-    if( pBt->pTmpSpace==0 ) return SQLITE_NOMEM;
    ++    if( pBt->pTmpSpace==0 ) return SQLITE_NOMEM_BKPT;
    +   }
    +   if( iTable==1 && btreePagecount(pBt)==0 ){
    +     assert( wrFlag==0 );
    +@@ -58607,8 +64694,7 @@ static int btreeCursor(
    +   pCur->pKeyInfo = pKeyInfo;
    +   pCur->pBtree = p;
    +   pCur->pBt = pBt;
    +-  assert( wrFlag==0 || wrFlag==BTCF_WriteFlag );
    +-  pCur->curFlags = wrFlag;
    ++  pCur->curFlags = wrFlag ? BTCF_WriteFlag : 0;
    +   pCur->curPagerFlags = wrFlag ? 0 : PAGER_GET_READONLY;
    +   /* If there are two or more cursors on the same btree, then all such
    +   ** cursors *must* have the BTCF_Multiple flag set. */
    +@@ -58672,10 +64758,8 @@ SQLITE_PRIVATE void sqlite3BtreeCursorZero(BtCursor *p){
    + SQLITE_PRIVATE int sqlite3BtreeCloseCursor(BtCursor *pCur){
    +   Btree *pBtree = pCur->pBtree;
    +   if( pBtree ){
    +-    int i;
    +     BtShared *pBt = pCur->pBt;
    +     sqlite3BtreeEnter(pBtree);
    +-    sqlite3BtreeClearCursor(pCur);
    +     assert( pBt->pCursor!=0 );
    +     if( pBt->pCursor==pCur ){
    +       pBt->pCursor = pCur->pNext;
    +@@ -58689,12 +64773,10 @@ SQLITE_PRIVATE int sqlite3BtreeCloseCursor(BtCursor *pCur){
    +         pPrev = pPrev->pNext;
    +       }while( ALWAYS(pPrev) );
    +     }
    +-    for(i=0; i<=pCur->iPage; i++){
    +-      releasePage(pCur->apPage[i]);
    +-    }
    ++    btreeReleaseAllCursorPages(pCur);
    +     unlockBtreeIfUnused(pBt);
    +     sqlite3_free(pCur->aOverflow);
    +-    /* sqlite3_free(pCur); */
    ++    sqlite3_free(pCur->pKey);
    +     sqlite3BtreeLeave(pBtree);
    +   }
    +   return SQLITE_OK;
    +@@ -58711,9 +64793,8 @@ SQLITE_PRIVATE int sqlite3BtreeCloseCursor(BtCursor *pCur){
    + #ifndef NDEBUG
    +   static void assertCellInfo(BtCursor *pCur){
    +     CellInfo info;
    +-    int iPage = pCur->iPage;
    +     memset(&info, 0, sizeof(info));
    +-    btreeParseCell(pCur->apPage[iPage], pCur->aiIdx[iPage], &info);
    ++    btreeParseCell(pCur->pPage, pCur->ix, &info);
    +     assert( CORRUPT_DB || memcmp(&info, &pCur->info, sizeof(info))==0 );
    +   }
    + #else
    +@@ -58721,9 +64802,8 @@ SQLITE_PRIVATE int sqlite3BtreeCloseCursor(BtCursor *pCur){
    + #endif
    + static SQLITE_NOINLINE void getCellInfo(BtCursor *pCur){
    +   if( pCur->info.nSize==0 ){
    +-    int iPage = pCur->iPage;
    +     pCur->curFlags |= BTCF_ValidNKey;
    +-    btreeParseCell(pCur->apPage[iPage],pCur->aiIdx[iPage],&pCur->info);
    ++    btreeParseCell(pCur->pPage,pCur->ix,&pCur->info);
    +   }else{
    +     assertCellInfo(pCur);
    +   }
    +@@ -58739,48 +64819,53 @@ SQLITE_PRIVATE int sqlite3BtreeCursorIsValid(BtCursor *pCur){
    +   return pCur && pCur->eState==CURSOR_VALID;
    + }
    + #endif /* NDEBUG */
    ++SQLITE_PRIVATE int sqlite3BtreeCursorIsValidNN(BtCursor *pCur){
    ++  assert( pCur!=0 );
    ++  return pCur->eState==CURSOR_VALID;
    ++}
    + 
    + /*
    +-** Set *pSize to the size of the buffer needed to hold the value of
    +-** the key for the current entry.  If the cursor is not pointing
    +-** to a valid entry, *pSize is set to 0. 
    +-**
    +-** For a table with the INTKEY flag set, this routine returns the key
    +-** itself, not the number of bytes in the key.
    +-**
    +-** The caller must position the cursor prior to invoking this routine.
    +-** 
    +-** This routine cannot fail.  It always returns SQLITE_OK.  
    ++** Return the value of the integer key or "rowid" for a table btree.
    ++** This routine is only valid for a cursor that is pointing into a
    ++** ordinary table btree.  If the cursor points to an index btree or
    ++** is invalid, the result of this routine is undefined.
    + */
    +-SQLITE_PRIVATE int sqlite3BtreeKeySize(BtCursor *pCur, i64 *pSize){
    ++SQLITE_PRIVATE i64 sqlite3BtreeIntegerKey(BtCursor *pCur){
    +   assert( cursorHoldsMutex(pCur) );
    +   assert( pCur->eState==CURSOR_VALID );
    ++  assert( pCur->curIntKey );
    +   getCellInfo(pCur);
    +-  *pSize = pCur->info.nKey;
    +-  return SQLITE_OK;
    ++  return pCur->info.nKey;
    ++}
    ++
    ++#ifdef SQLITE_ENABLE_OFFSET_SQL_FUNC
    ++/*
    ++** Return the offset into the database file for the start of the
    ++** payload to which the cursor is pointing.
    ++*/
    ++SQLITE_PRIVATE i64 sqlite3BtreeOffset(BtCursor *pCur){
    ++  assert( cursorHoldsMutex(pCur) );
    ++  assert( pCur->eState==CURSOR_VALID );
    ++  getCellInfo(pCur);
    ++  return (i64)pCur->pBt->pageSize*((i64)pCur->pPage->pgno - 1) +
    ++         (i64)(pCur->info.pPayload - pCur->pPage->aData);
    + }
    ++#endif /* SQLITE_ENABLE_OFFSET_SQL_FUNC */
    + 
    + /*
    +-** Set *pSize to the number of bytes of data in the entry the
    +-** cursor currently points to.
    ++** Return the number of bytes of payload for the entry that pCur is
    ++** currently pointing to.  For table btrees, this will be the amount
    ++** of data.  For index btrees, this will be the size of the key.
    + **
    + ** The caller must guarantee that the cursor is pointing to a non-NULL
    + ** valid entry.  In other words, the calling procedure must guarantee
    + ** that the cursor has Cursor.eState==CURSOR_VALID.
    +-**
    +-** Failure is not possible.  This function always returns SQLITE_OK.
    +-** It might just as well be a procedure (returning void) but we continue
    +-** to return an integer result code for historical reasons.
    + */
    +-SQLITE_PRIVATE int sqlite3BtreeDataSize(BtCursor *pCur, u32 *pSize){
    ++SQLITE_PRIVATE u32 sqlite3BtreePayloadSize(BtCursor *pCur){
    +   assert( cursorHoldsMutex(pCur) );
    +   assert( pCur->eState==CURSOR_VALID );
    +-  assert( pCur->iPage>=0 );
    +-  assert( pCur->iPage<BTCURSOR_MAX_DEPTH );
    +-  assert( pCur->apPage[pCur->iPage]->intKeyLeaf==1 );
    +   getCellInfo(pCur);
    +-  *pSize = pCur->info.nPayload;
    +-  return SQLITE_OK;
    ++  return pCur->info.nPayload;
    + }
    + 
    + /*
    +@@ -58898,7 +64983,6 @@ static int copyPayload(
    + **
    + **   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.
    +@@ -58906,13 +64990,13 @@ 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 current cursor entry uses one or more overflow pages and the
    +-** eOp argument is not 2, this function may allocate space for and lazily 
    +-** populates the overflow page-list cache array (BtCursor.aOverflow). 
    ++** If the current cursor entry uses one or more overflow pages
    ++** this function may allocate space for and lazily populate
    ++** 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
    ++** Once an overflow page-list cache has been allocated, it must be
    + ** invalidated if some other cursor writes to the same table, or if
    + ** the cursor is moved to a different row. Additionally, in auto-vacuum
    + ** mode, the following events may invalidate an overflow page-list cache.
    +@@ -58931,29 +65015,30 @@ static int accessPayload(
    +   unsigned char *aPayload;
    +   int rc = SQLITE_OK;
    +   int iIdx = 0;
    +-  MemPage *pPage = pCur->apPage[pCur->iPage]; /* Btree page of current entry */
    ++  MemPage *pPage = pCur->pPage;               /* Btree page of current entry */
    +   BtShared *pBt = pCur->pBt;                  /* Btree this cursor belongs to */
    + #ifdef SQLITE_DIRECT_OVERFLOW_READ
    +-  unsigned char * const pBufStart = pBuf;
    +-  int bEnd;                                 /* True if reading to end of data */
    ++  unsigned char * const pBufStart = pBuf;     /* Start of original out buffer */
    + #endif
    + 
    +   assert( pPage );
    ++  assert( eOp==0 || eOp==1 );
    +   assert( pCur->eState==CURSOR_VALID );
    +-  assert( pCur->aiIdx[pCur->iPage]<pPage->nCell );
    ++  assert( pCur->ix<pPage->nCell );
    +   assert( cursorHoldsMutex(pCur) );
    +-  assert( eOp!=2 || offset==0 );    /* Always start from beginning for eOp==2 */
    + 
    +   getCellInfo(pCur);
    +   aPayload = pCur->info.pPayload;
    +-#ifdef SQLITE_DIRECT_OVERFLOW_READ
    +-  bEnd = offset+amt==pCur->info.nPayload;
    +-#endif
    +   assert( offset+amt <= pCur->info.nPayload );
    + 
    +-  if( &aPayload[pCur->info.nLocal] > &pPage->aData[pBt->usableSize] ){
    +-    /* Trying to read or write past the end of the data is an error */
    +-    return SQLITE_CORRUPT_BKPT;
    ++  assert( aPayload > pPage->aData );
    ++  if( (uptr)(aPayload - pPage->aData) > (pBt->usableSize - pCur->info.nLocal) ){
    ++    /* Trying to read or write past the end of the data is an error.  The
    ++    ** conditional above is really:
    ++    **    &aPayload[pCur->info.nLocal] > &pPage->aData[pBt->usableSize]
    ++    ** but is recast into its current form to avoid integer overflow problems
    ++    */
    ++    return SQLITE_CORRUPT_PAGE(pPage);
    +   }
    + 
    +   /* Check if data must be read/written to/from the btree page itself. */
    +@@ -58962,7 +65047,7 @@ static int accessPayload(
    +     if( a+offset>pCur->info.nLocal ){
    +       a = pCur->info.nLocal - offset;
    +     }
    +-    rc = copyPayload(&aPayload[offset], pBuf, a, (eOp & 0x01), pPage->pDbPage);
    ++    rc = copyPayload(&aPayload[offset], pBuf, a, eOp, pPage->pDbPage);
    +     offset = 0;
    +     pBuf += a;
    +     amt -= a;
    +@@ -58978,51 +65063,46 @@ static int accessPayload(
    +     nextPage = get4byte(&aPayload[pCur->info.nLocal]);
    + 
    +     /* 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( eOp!=2 && (pCur->curFlags & BTCF_ValidOvfl)==0 ){
    ++    if( (pCur->curFlags & BTCF_ValidOvfl)==0 ){
    +       int nOvfl = (pCur->info.nPayload-pCur->info.nLocal+ovflSize-1)/ovflSize;
    +       if( nOvfl>pCur->nOvflAlloc ){
    +         Pgno *aNew = (Pgno*)sqlite3Realloc(
    +             pCur->aOverflow, nOvfl*2*sizeof(Pgno)
    +         );
    +         if( aNew==0 ){
    +-          rc = SQLITE_NOMEM;
    ++          return SQLITE_NOMEM_BKPT;
    +         }else{
    +           pCur->nOvflAlloc = nOvfl*2;
    +           pCur->aOverflow = aNew;
    +         }
    +       }
    +-      if( rc==SQLITE_OK ){
    +-        memset(pCur->aOverflow, 0, nOvfl*sizeof(Pgno));
    +-        pCur->curFlags |= BTCF_ValidOvfl;
    ++      memset(pCur->aOverflow, 0, nOvfl*sizeof(Pgno));
    ++      pCur->curFlags |= BTCF_ValidOvfl;
    ++    }else{
    ++      /* If the overflow page-list cache has been allocated and the
    ++      ** entry for the first required overflow page is valid, skip
    ++      ** directly to it.
    ++      */
    ++      if( pCur->aOverflow[offset/ovflSize] ){
    ++        iIdx = (offset/ovflSize);
    ++        nextPage = pCur->aOverflow[iIdx];
    ++        offset = (offset%ovflSize);
    +       }
    +     }
    + 
    +-    /* If the overflow page-list cache has been allocated and the
    +-    ** entry for the first required overflow page is valid, skip
    +-    ** directly to it.
    +-    */
    +-    if( (pCur->curFlags & BTCF_ValidOvfl)!=0
    +-     && pCur->aOverflow[offset/ovflSize]
    +-    ){
    +-      iIdx = (offset/ovflSize);
    +-      nextPage = pCur->aOverflow[iIdx];
    +-      offset = (offset%ovflSize);
    +-    }
    +-
    +-    for( ; rc==SQLITE_OK && amt>0 && nextPage; iIdx++){
    +-
    ++    assert( rc==SQLITE_OK && amt>0 );
    ++    while( nextPage ){
    +       /* If required, populate the overflow page-list cache. */
    +-      if( (pCur->curFlags & BTCF_ValidOvfl)!=0 ){
    +-        assert(!pCur->aOverflow[iIdx] || pCur->aOverflow[iIdx]==nextPage);
    +-        pCur->aOverflow[iIdx] = nextPage;
    +-      }
    ++      assert( pCur->aOverflow[iIdx]==0
    ++              || pCur->aOverflow[iIdx]==nextPage
    ++              || CORRUPT_DB );
    ++      pCur->aOverflow[iIdx] = nextPage;
    + 
    +       if( offset>=ovflSize ){
    +         /* The only reason to read this page is to obtain the page
    +@@ -59030,11 +65110,7 @@ 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.
    +         */
    +-        assert( eOp!=2 );
    +         assert( pCur->curFlags & BTCF_ValidOvfl );
    +         assert( pCur->pBtree->db==pBt->db );
    +         if( pCur->aOverflow[iIdx+1] ){
    +@@ -59048,7 +65124,7 @@ static int accessPayload(
    +         ** range of data that is being read (eOp==0) or written (eOp!=0).
    +         */
    + #ifdef SQLITE_DIRECT_OVERFLOW_READ
    +-        sqlite3_file *fd;
    ++        sqlite3_file *fd;      /* File from which to do direct overflow read */
    + #endif
    +         int a = amt;
    +         if( a + offset > ovflSize ){
    +@@ -59060,27 +65136,25 @@ static int accessPayload(
    +         **
    +         **   1) this is a read operation, and 
    +         **   2) data is required from the start of this overflow page, and
    +-        **   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.
    +-        **   7) at least 4 bytes have already been read into the output buffer 
    ++        **   3) there is no open write-transaction, and
    ++        **   4) the database is file-backed, and
    ++        **   5) the page is not in the WAL file
    ++        **   6) at least 4 bytes have already been read into the output buffer 
    +         **
    +         ** 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&0x01)==0                                      /* (1) */
    ++        if( eOp==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) */
    +-         && &pBuf[-4]>=pBufStart                               /* (7) */
    ++         && pBt->inTransaction==TRANS_READ                     /* (3) */
    ++         && (fd = sqlite3PagerFile(pBt->pPager))->pMethods     /* (4) */
    ++         && 0==sqlite3PagerUseWal(pBt->pPager, nextPage)       /* (5) */
    ++         && &pBuf[-4]>=pBufStart                               /* (6) */
    +         ){
    +           u8 aSave[4];
    +           u8 *aWrite = &pBuf[-4];
    +-          assert( aWrite>=pBufStart );                         /* hence (7) */
    ++          assert( aWrite>=pBufStart );                         /* due to (6) */
    +           memcpy(aSave, aWrite, 4);
    +           rc = sqlite3OsRead(fd, aWrite, a+4, (i64)pBt->pageSize*(nextPage-1));
    +           nextPage = get4byte(aWrite);
    +@@ -59090,77 +65164,87 @@ static int accessPayload(
    + 
    +         {
    +           DbPage *pDbPage;
    +-          rc = sqlite3PagerAcquire(pBt->pPager, nextPage, &pDbPage,
    +-              ((eOp&0x01)==0 ? PAGER_GET_READONLY : 0)
    ++          rc = sqlite3PagerGet(pBt->pPager, nextPage, &pDbPage,
    ++              (eOp==0 ? PAGER_GET_READONLY : 0)
    +           );
    +           if( rc==SQLITE_OK ){
    +             aPayload = sqlite3PagerGetData(pDbPage);
    +             nextPage = get4byte(aPayload);
    +-            rc = copyPayload(&aPayload[offset+4], pBuf, a, (eOp&0x01), pDbPage);
    ++            rc = copyPayload(&aPayload[offset+4], pBuf, a, eOp, pDbPage);
    +             sqlite3PagerUnref(pDbPage);
    +             offset = 0;
    +           }
    +         }
    +         amt -= a;
    ++        if( amt==0 ) return rc;
    +         pBuf += a;
    +       }
    ++      if( rc ) break;
    ++      iIdx++;
    +     }
    +   }
    + 
    +   if( rc==SQLITE_OK && amt>0 ){
    +-    return SQLITE_CORRUPT_BKPT;
    ++    /* Overflow chain ends prematurely */
    ++    return SQLITE_CORRUPT_PAGE(pPage);
    +   }
    +   return rc;
    + }
    + 
    + /*
    +-** Read part of the key associated with cursor pCur.  Exactly
    +-** "amt" bytes will be transferred into pBuf[].  The transfer
    ++** Read part of the payload for the row at which that cursor pCur is currently
    ++** pointing.  "amt" bytes will be transferred into pBuf[].  The transfer
    + ** begins at "offset".
    + **
    +-** The caller must ensure that pCur is pointing to a valid row
    +-** in the table.
    ++** pCur can be pointing to either a table or an index b-tree.
    ++** If pointing to a table btree, then the content section is read.  If
    ++** pCur is pointing to an index b-tree then the key section is read.
    ++**
    ++** For sqlite3BtreePayload(), the caller must ensure that pCur is pointing
    ++** to a valid row in the table.  For sqlite3BtreePayloadChecked(), the
    ++** cursor might be invalid or might need to be restored before being read.
    + **
    + ** Return SQLITE_OK on success or an error code if anything goes
    + ** wrong.  An error is returned if "offset+amt" is larger than
    + ** the available payload.
    + */
    +-SQLITE_PRIVATE int sqlite3BtreeKey(BtCursor *pCur, u32 offset, u32 amt, void *pBuf){
    ++SQLITE_PRIVATE int sqlite3BtreePayload(BtCursor *pCur, u32 offset, u32 amt, void *pBuf){
    +   assert( cursorHoldsMutex(pCur) );
    +   assert( pCur->eState==CURSOR_VALID );
    +-  assert( pCur->iPage>=0 && pCur->apPage[pCur->iPage] );
    +-  assert( pCur->aiIdx[pCur->iPage]<pCur->apPage[pCur->iPage]->nCell );
    ++  assert( pCur->iPage>=0 && pCur->pPage );
    ++  assert( pCur->ix<pCur->pPage->nCell );
    +   return accessPayload(pCur, offset, amt, (unsigned char*)pBuf, 0);
    + }
    + 
    + /*
    +-** Read part of the data associated with cursor pCur.  Exactly
    +-** "amt" bytes will be transfered into pBuf[].  The transfer
    +-** begins at "offset".
    +-**
    +-** Return SQLITE_OK on success or an error code if anything goes
    +-** wrong.  An error is returned if "offset+amt" is larger than
    +-** the available payload.
    ++** This variant of sqlite3BtreePayload() works even if the cursor has not
    ++** in the CURSOR_VALID state.  It is only used by the sqlite3_blob_read()
    ++** interface.
    + */
    +-SQLITE_PRIVATE int sqlite3BtreeData(BtCursor *pCur, u32 offset, u32 amt, void *pBuf){
    +-  int rc;
    +-
    + #ifndef SQLITE_OMIT_INCRBLOB
    ++static SQLITE_NOINLINE int accessPayloadChecked(
    ++  BtCursor *pCur,
    ++  u32 offset,
    ++  u32 amt,
    ++  void *pBuf
    ++){
    ++  int rc;
    +   if ( pCur->eState==CURSOR_INVALID ){
    +     return SQLITE_ABORT;
    +   }
    +-#endif
    +-
    +-  assert( cursorHoldsMutex(pCur) );
    +-  rc = restoreCursorPosition(pCur);
    +-  if( rc==SQLITE_OK ){
    +-    assert( pCur->eState==CURSOR_VALID );
    +-    assert( pCur->iPage>=0 && pCur->apPage[pCur->iPage] );
    +-    assert( pCur->aiIdx[pCur->iPage]<pCur->apPage[pCur->iPage]->nCell );
    +-    rc = accessPayload(pCur, offset, amt, pBuf, 0);
    ++  assert( cursorOwnsBtShared(pCur) );
    ++  rc = btreeRestoreCursorPosition(pCur);
    ++  return rc ? rc : accessPayload(pCur, offset, amt, pBuf, 0);
    ++}
    ++SQLITE_PRIVATE int sqlite3BtreePayloadChecked(BtCursor *pCur, u32 offset, u32 amt, void *pBuf){
    ++  if( pCur->eState==CURSOR_VALID ){
    ++    assert( cursorOwnsBtShared(pCur) );
    ++    return accessPayload(pCur, offset, amt, pBuf, 0);
    ++  }else{
    ++    return accessPayloadChecked(pCur, offset, amt, pBuf);
    +   }
    +-  return rc;
    + }
    ++#endif /* SQLITE_OMIT_INCRBLOB */
    + 
    + /*
    + ** Return a pointer to payload information from the entry that the 
    +@@ -59185,18 +65269,23 @@ static const void *fetchPayload(
    +   BtCursor *pCur,      /* Cursor pointing to entry to read from */
    +   u32 *pAmt            /* Write the number of available bytes here */
    + ){
    +-  u32 amt;
    +-  assert( pCur!=0 && pCur->iPage>=0 && pCur->apPage[pCur->iPage]);
    ++  int amt;
    ++  assert( pCur!=0 && pCur->iPage>=0 && pCur->pPage);
    +   assert( pCur->eState==CURSOR_VALID );
    +   assert( sqlite3_mutex_held(pCur->pBtree->db->mutex) );
    +-  assert( cursorHoldsMutex(pCur) );
    +-  assert( pCur->aiIdx[pCur->iPage]<pCur->apPage[pCur->iPage]->nCell );
    ++  assert( cursorOwnsBtShared(pCur) );
    ++  assert( pCur->ix<pCur->pPage->nCell );
    +   assert( pCur->info.nSize>0 );
    +-  assert( pCur->info.pPayload>pCur->apPage[pCur->iPage]->aData || CORRUPT_DB );
    +-  assert( pCur->info.pPayload<pCur->apPage[pCur->iPage]->aDataEnd ||CORRUPT_DB);
    +-  amt = (int)(pCur->apPage[pCur->iPage]->aDataEnd - pCur->info.pPayload);
    +-  if( pCur->info.nLocal<amt ) amt = pCur->info.nLocal;
    +-  *pAmt = amt;
    ++  assert( pCur->info.pPayload>pCur->pPage->aData || CORRUPT_DB );
    ++  assert( pCur->info.pPayload<pCur->pPage->aDataEnd ||CORRUPT_DB);
    ++  amt = pCur->info.nLocal;
    ++  if( amt>(int)(pCur->pPage->aDataEnd - pCur->info.pPayload) ){
    ++    /* There is too little space on the page for the expected amount
    ++    ** of local content. Database must be corrupt. */
    ++    assert( CORRUPT_DB );
    ++    amt = MAX(0, (int)(pCur->pPage->aDataEnd - pCur->info.pPayload));
    ++  }
    ++  *pAmt = (u32)amt;
    +   return (void*)pCur->info.pPayload;
    + }
    + 
    +@@ -59215,10 +65304,7 @@ static const void *fetchPayload(
    + ** These routines is used to get quick access to key and data
    + ** in the common case where no overflow pages are used.
    + */
    +-SQLITE_PRIVATE const void *sqlite3BtreeKeyFetch(BtCursor *pCur, u32 *pAmt){
    +-  return fetchPayload(pCur, pAmt);
    +-}
    +-SQLITE_PRIVATE const void *sqlite3BtreeDataFetch(BtCursor *pCur, u32 *pAmt){
    ++SQLITE_PRIVATE const void *sqlite3BtreePayloadFetch(BtCursor *pCur, u32 *pAmt){
    +   return fetchPayload(pCur, pAmt);
    + }
    + 
    +@@ -59235,7 +65321,7 @@ SQLITE_PRIVATE const void *sqlite3BtreeDataFetch(BtCursor *pCur, u32 *pAmt){
    + static int moveToChild(BtCursor *pCur, u32 newPgno){
    +   BtShared *pBt = pCur->pBt;
    + 
    +-  assert( cursorHoldsMutex(pCur) );
    ++  assert( cursorOwnsBtShared(pCur) );
    +   assert( pCur->eState==CURSOR_VALID );
    +   assert( pCur->iPage<BTCURSOR_MAX_DEPTH );
    +   assert( pCur->iPage>=0 );
    +@@ -59244,13 +65330,14 @@ static int moveToChild(BtCursor *pCur, u32 newPgno){
    +   }
    +   pCur->info.nSize = 0;
    +   pCur->curFlags &= ~(BTCF_ValidNKey|BTCF_ValidOvfl);
    ++  pCur->aiIdx[pCur->iPage] = pCur->ix;
    ++  pCur->apPage[pCur->iPage] = pCur->pPage;
    ++  pCur->ix = 0;
    +   pCur->iPage++;
    +-  pCur->aiIdx[pCur->iPage] = 0;
    +-  return getAndInitPage(pBt, newPgno, &pCur->apPage[pCur->iPage],
    +-                        pCur, pCur->curPagerFlags);
    ++  return getAndInitPage(pBt, newPgno, &pCur->pPage, pCur, pCur->curPagerFlags);
    + }
    + 
    +-#if SQLITE_DEBUG
    ++#ifdef SQLITE_DEBUG
    + /*
    + ** Page pParent is an internal (non-leaf) tree page. This function 
    + ** asserts that page number iChild is the left-child if the iIdx'th
    +@@ -59281,19 +65368,23 @@ static void assertParentIndex(MemPage *pParent, int iIdx, Pgno iChild){
    + ** the largest cell index.
    + */
    + static void moveToParent(BtCursor *pCur){
    +-  assert( cursorHoldsMutex(pCur) );
    ++  MemPage *pLeaf;
    ++  assert( cursorOwnsBtShared(pCur) );
    +   assert( pCur->eState==CURSOR_VALID );
    +   assert( pCur->iPage>0 );
    +-  assert( pCur->apPage[pCur->iPage] );
    ++  assert( pCur->pPage );
    +   assertParentIndex(
    +     pCur->apPage[pCur->iPage-1], 
    +     pCur->aiIdx[pCur->iPage-1], 
    +-    pCur->apPage[pCur->iPage]->pgno
    ++    pCur->pPage->pgno
    +   );
    +   testcase( pCur->aiIdx[pCur->iPage-1] > pCur->apPage[pCur->iPage-1]->nCell );
    +   pCur->info.nSize = 0;
    +   pCur->curFlags &= ~(BTCF_ValidNKey|BTCF_ValidOvfl);
    +-  releasePageNotNull(pCur->apPage[pCur->iPage--]);
    ++  pCur->ix = pCur->aiIdx[pCur->iPage-1];
    ++  pLeaf = pCur->pPage;
    ++  pCur->pPage = pCur->apPage[--pCur->iPage];
    ++  releasePageNotNull(pLeaf);
    + }
    + 
    + /*
    +@@ -59305,9 +65396,9 @@ static void moveToParent(BtCursor *pCur){
    + ** single child page. This can only happen with the table rooted at page 1.
    + **
    + ** If the b-tree structure is empty, the cursor state is set to 
    +-** CURSOR_INVALID. Otherwise, the cursor is set to point to the first
    +-** cell located on the root (or virtual root) page and the cursor state
    +-** is set to CURSOR_VALID.
    ++** CURSOR_INVALID and this routine returns SQLITE_EMPTY. Otherwise,
    ++** the cursor is set to point to the first cell located on the root
    ++** (or virtual root) page and the cursor state is set to CURSOR_VALID.
    + **
    + ** If this function returns successfully, it may be assumed that the
    + ** page-header flags indicate that the [virtual] root-page is the expected 
    +@@ -59321,38 +65412,44 @@ static int moveToRoot(BtCursor *pCur){
    +   MemPage *pRoot;
    +   int rc = SQLITE_OK;
    + 
    +-  assert( cursorHoldsMutex(pCur) );
    ++  assert( cursorOwnsBtShared(pCur) );
    +   assert( CURSOR_INVALID < CURSOR_REQUIRESEEK );
    +   assert( CURSOR_VALID   < CURSOR_REQUIRESEEK );
    +   assert( CURSOR_FAULT   > CURSOR_REQUIRESEEK );
    +-  if( pCur->eState>=CURSOR_REQUIRESEEK ){
    +-    if( pCur->eState==CURSOR_FAULT ){
    +-      assert( pCur->skipNext!=SQLITE_OK );
    +-      return pCur->skipNext;
    +-    }
    +-    sqlite3BtreeClearCursor(pCur);
    +-  }
    ++  assert( pCur->eState < CURSOR_REQUIRESEEK || pCur->iPage<0 );
    ++  assert( pCur->pgnoRoot>0 || pCur->iPage<0 );
    + 
    +   if( pCur->iPage>=0 ){
    +-    while( pCur->iPage ){
    +-      assert( pCur->apPage[pCur->iPage]!=0 );
    +-      releasePageNotNull(pCur->apPage[pCur->iPage--]);
    ++    if( pCur->iPage ){
    ++      releasePageNotNull(pCur->pPage);
    ++      while( --pCur->iPage ){
    ++        releasePageNotNull(pCur->apPage[pCur->iPage]);
    ++      }
    ++      pCur->pPage = pCur->apPage[0];
    ++      goto skip_init;
    +     }
    +   }else if( pCur->pgnoRoot==0 ){
    +     pCur->eState = CURSOR_INVALID;
    +-    return SQLITE_OK;
    ++    return SQLITE_EMPTY;
    +   }else{
    +     assert( pCur->iPage==(-1) );
    +-    rc = getAndInitPage(pCur->pBtree->pBt, pCur->pgnoRoot, &pCur->apPage[0],
    ++    if( pCur->eState>=CURSOR_REQUIRESEEK ){
    ++      if( pCur->eState==CURSOR_FAULT ){
    ++        assert( pCur->skipNext!=SQLITE_OK );
    ++        return pCur->skipNext;
    ++      }
    ++      sqlite3BtreeClearCursor(pCur);
    ++    }
    ++    rc = getAndInitPage(pCur->pBtree->pBt, pCur->pgnoRoot, &pCur->pPage,
    +                         0, pCur->curPagerFlags);
    +     if( rc!=SQLITE_OK ){
    +       pCur->eState = CURSOR_INVALID;
    +       return rc;
    +     }
    +     pCur->iPage = 0;
    +-    pCur->curIntKey = pCur->apPage[0]->intKey;
    ++    pCur->curIntKey = pCur->pPage->intKey;
    +   }
    +-  pRoot = pCur->apPage[0];
    ++  pRoot = pCur->pPage;
    +   assert( pRoot->pgno==pCur->pgnoRoot );
    + 
    +   /* If pCur->pKeyInfo is not NULL, then the caller that opened this cursor
    +@@ -59367,13 +65464,15 @@ static int moveToRoot(BtCursor *pCur){
    +   ** (or the freelist).  */
    +   assert( pRoot->intKey==1 || pRoot->intKey==0 );
    +   if( pRoot->isInit==0 || (pCur->pKeyInfo==0)!=pRoot->intKey ){
    +-    return SQLITE_CORRUPT_BKPT;
    ++    return SQLITE_CORRUPT_PAGE(pCur->pPage);
    +   }
    + 
    +-  pCur->aiIdx[0] = 0;
    ++skip_init:  
    ++  pCur->ix = 0;
    +   pCur->info.nSize = 0;
    +   pCur->curFlags &= ~(BTCF_AtLast|BTCF_ValidNKey|BTCF_ValidOvfl);
    + 
    ++  pRoot = pCur->pPage;
    +   if( pRoot->nCell>0 ){
    +     pCur->eState = CURSOR_VALID;
    +   }else if( !pRoot->leaf ){
    +@@ -59384,6 +65483,7 @@ static int moveToRoot(BtCursor *pCur){
    +     rc = moveToChild(pCur, subpage);
    +   }else{
    +     pCur->eState = CURSOR_INVALID;
    ++    rc = SQLITE_EMPTY;
    +   }
    +   return rc;
    + }
    +@@ -59400,11 +65500,11 @@ static int moveToLeftmost(BtCursor *pCur){
    +   int rc = SQLITE_OK;
    +   MemPage *pPage;
    + 
    +-  assert( cursorHoldsMutex(pCur) );
    ++  assert( cursorOwnsBtShared(pCur) );
    +   assert( pCur->eState==CURSOR_VALID );
    +-  while( rc==SQLITE_OK && !(pPage = pCur->apPage[pCur->iPage])->leaf ){
    +-    assert( pCur->aiIdx[pCur->iPage]<pPage->nCell );
    +-    pgno = get4byte(findCell(pPage, pCur->aiIdx[pCur->iPage]));
    ++  while( rc==SQLITE_OK && !(pPage = pCur->pPage)->leaf ){
    ++    assert( pCur->ix<pPage->nCell );
    ++    pgno = get4byte(findCell(pPage, pCur->ix));
    +     rc = moveToChild(pCur, pgno);
    +   }
    +   return rc;
    +@@ -59425,15 +65525,15 @@ static int moveToRightmost(BtCursor *pCur){
    +   int rc = SQLITE_OK;
    +   MemPage *pPage = 0;
    + 
    +-  assert( cursorHoldsMutex(pCur) );
    ++  assert( cursorOwnsBtShared(pCur) );
    +   assert( pCur->eState==CURSOR_VALID );
    +-  while( !(pPage = pCur->apPage[pCur->iPage])->leaf ){
    ++  while( !(pPage = pCur->pPage)->leaf ){
    +     pgno = get4byte(&pPage->aData[pPage->hdrOffset+8]);
    +-    pCur->aiIdx[pCur->iPage] = pPage->nCell;
    ++    pCur->ix = pPage->nCell;
    +     rc = moveToChild(pCur, pgno);
    +     if( rc ) return rc;
    +   }
    +-  pCur->aiIdx[pCur->iPage] = pPage->nCell-1;
    ++  pCur->ix = pPage->nCell-1;
    +   assert( pCur->info.nSize==0 );
    +   assert( (pCur->curFlags & BTCF_ValidNKey)==0 );
    +   return SQLITE_OK;
    +@@ -59446,18 +65546,17 @@ static int moveToRightmost(BtCursor *pCur){
    + SQLITE_PRIVATE int sqlite3BtreeFirst(BtCursor *pCur, int *pRes){
    +   int rc;
    + 
    +-  assert( cursorHoldsMutex(pCur) );
    ++  assert( cursorOwnsBtShared(pCur) );
    +   assert( sqlite3_mutex_held(pCur->pBtree->db->mutex) );
    +   rc = moveToRoot(pCur);
    +   if( rc==SQLITE_OK ){
    +-    if( pCur->eState==CURSOR_INVALID ){
    +-      assert( pCur->pgnoRoot==0 || pCur->apPage[pCur->iPage]->nCell==0 );
    +-      *pRes = 1;
    +-    }else{
    +-      assert( pCur->apPage[pCur->iPage]->nCell>0 );
    +-      *pRes = 0;
    +-      rc = moveToLeftmost(pCur);
    +-    }
    ++    assert( pCur->pPage->nCell>0 );
    ++    *pRes = 0;
    ++    rc = moveToLeftmost(pCur);
    ++  }else if( rc==SQLITE_EMPTY ){
    ++    assert( pCur->pgnoRoot==0 || pCur->pPage->nCell==0 );
    ++    *pRes = 1;
    ++    rc = SQLITE_OK;
    +   }
    +   return rc;
    + }
    +@@ -59469,7 +65568,7 @@ SQLITE_PRIVATE int sqlite3BtreeFirst(BtCursor *pCur, int *pRes){
    + SQLITE_PRIVATE int sqlite3BtreeLast(BtCursor *pCur, int *pRes){
    +   int rc;
    +  
    +-  assert( cursorHoldsMutex(pCur) );
    ++  assert( cursorOwnsBtShared(pCur) );
    +   assert( sqlite3_mutex_held(pCur->pBtree->db->mutex) );
    + 
    +   /* If the cursor already points to the last entry, this is a no-op. */
    +@@ -59481,28 +65580,26 @@ SQLITE_PRIVATE int sqlite3BtreeLast(BtCursor *pCur, int *pRes){
    +     for(ii=0; ii<pCur->iPage; ii++){
    +       assert( pCur->aiIdx[ii]==pCur->apPage[ii]->nCell );
    +     }
    +-    assert( pCur->aiIdx[pCur->iPage]==pCur->apPage[pCur->iPage]->nCell-1 );
    +-    assert( pCur->apPage[pCur->iPage]->leaf );
    ++    assert( pCur->ix==pCur->pPage->nCell-1 );
    ++    assert( pCur->pPage->leaf );
    + #endif
    +     return SQLITE_OK;
    +   }
    + 
    +   rc = moveToRoot(pCur);
    +   if( rc==SQLITE_OK ){
    +-    if( CURSOR_INVALID==pCur->eState ){
    +-      assert( pCur->pgnoRoot==0 || pCur->apPage[pCur->iPage]->nCell==0 );
    +-      *pRes = 1;
    ++    assert( pCur->eState==CURSOR_VALID );
    ++    *pRes = 0;
    ++    rc = moveToRightmost(pCur);
    ++    if( rc==SQLITE_OK ){
    ++      pCur->curFlags |= BTCF_AtLast;
    +     }else{
    +-      assert( pCur->eState==CURSOR_VALID );
    +-      *pRes = 0;
    +-      rc = moveToRightmost(pCur);
    +-      if( rc==SQLITE_OK ){
    +-        pCur->curFlags |= BTCF_AtLast;
    +-      }else{
    +-        pCur->curFlags &= ~BTCF_AtLast;
    +-      }
    +-   
    ++      pCur->curFlags &= ~BTCF_AtLast;
    +     }
    ++  }else if( rc==SQLITE_EMPTY ){
    ++    assert( pCur->pgnoRoot==0 || pCur->pPage->nCell==0 );
    ++    *pRes = 1;
    ++    rc = SQLITE_OK;
    +   }
    +   return rc;
    + }
    +@@ -59534,6 +65631,8 @@ SQLITE_PRIVATE int sqlite3BtreeLast(BtCursor *pCur, int *pRes){
    + **     *pRes>0      The cursor is left pointing at an entry that
    + **                  is larger than intKey/pIdxKey.
    + **
    ++** For index tables, the pIdxKey->eqSeen field is set to 1 if there
    ++** exists an entry in the table that exactly matches pIdxKey.  
    + */
    + SQLITE_PRIVATE int sqlite3BtreeMovetoUnpacked(
    +   BtCursor *pCur,          /* The cursor to be moved */
    +@@ -59545,23 +65644,44 @@ SQLITE_PRIVATE int sqlite3BtreeMovetoUnpacked(
    +   int rc;
    +   RecordCompare xRecordCompare;
    + 
    +-  assert( cursorHoldsMutex(pCur) );
    ++  assert( cursorOwnsBtShared(pCur) );
    +   assert( sqlite3_mutex_held(pCur->pBtree->db->mutex) );
    +   assert( pRes );
    +   assert( (pIdxKey==0)==(pCur->pKeyInfo==0) );
    ++  assert( pCur->eState!=CURSOR_VALID || (pIdxKey==0)==(pCur->curIntKey!=0) );
    + 
    +   /* 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->curFlags & BTCF_ValidNKey)!=0
    +-   && pCur->curIntKey 
    ++  if( pIdxKey==0
    ++   && pCur->eState==CURSOR_VALID && (pCur->curFlags & BTCF_ValidNKey)!=0
    +   ){
    +     if( pCur->info.nKey==intKey ){
    +       *pRes = 0;
    +       return SQLITE_OK;
    +     }
    +-    if( (pCur->curFlags & BTCF_AtLast)!=0 && pCur->info.nKey<intKey ){
    +-      *pRes = -1;
    +-      return SQLITE_OK;
    ++    if( pCur->info.nKey<intKey ){
    ++      if( (pCur->curFlags & BTCF_AtLast)!=0 ){
    ++        *pRes = -1;
    ++        return SQLITE_OK;
    ++      }
    ++      /* If the requested key is one more than the previous key, then
    ++      ** try to get there using sqlite3BtreeNext() rather than a full
    ++      ** binary search.  This is an optimization only.  The correct answer
    ++      ** is still obtained without this case, only a little more slowely */
    ++      if( pCur->info.nKey+1==intKey && !pCur->skipNext ){
    ++        *pRes = 0;
    ++        rc = sqlite3BtreeNext(pCur, 0);
    ++        if( rc==SQLITE_OK ){
    ++          getCellInfo(pCur);
    ++          if( pCur->info.nKey==intKey ){
    ++            return SQLITE_OK;
    ++          }
    ++        }else if( rc==SQLITE_DONE ){
    ++          rc = SQLITE_OK;
    ++        }else{
    ++          return rc;
    ++        }
    ++      }
    +     }
    +   }
    + 
    +@@ -59578,22 +65698,23 @@ SQLITE_PRIVATE int sqlite3BtreeMovetoUnpacked(
    + 
    +   rc = moveToRoot(pCur);
    +   if( rc ){
    ++    if( rc==SQLITE_EMPTY ){
    ++      assert( pCur->pgnoRoot==0 || pCur->pPage->nCell==0 );
    ++      *pRes = -1;
    ++      return SQLITE_OK;
    ++    }
    +     return rc;
    +   }
    +-  assert( pCur->pgnoRoot==0 || pCur->apPage[pCur->iPage] );
    +-  assert( pCur->pgnoRoot==0 || pCur->apPage[pCur->iPage]->isInit );
    +-  assert( pCur->eState==CURSOR_INVALID || pCur->apPage[pCur->iPage]->nCell>0 );
    +-  if( pCur->eState==CURSOR_INVALID ){
    +-    *pRes = -1;
    +-    assert( pCur->pgnoRoot==0 || pCur->apPage[pCur->iPage]->nCell==0 );
    +-    return SQLITE_OK;
    +-  }
    +-  assert( pCur->apPage[0]->intKey==pCur->curIntKey );
    ++  assert( pCur->pPage );
    ++  assert( pCur->pPage->isInit );
    ++  assert( pCur->eState==CURSOR_VALID );
    ++  assert( pCur->pPage->nCell > 0 );
    ++  assert( pCur->iPage==0 || pCur->apPage[0]->intKey==pCur->curIntKey );
    +   assert( pCur->curIntKey || pIdxKey );
    +   for(;;){
    +     int lwr, upr, idx, c;
    +     Pgno chldPg;
    +-    MemPage *pPage = pCur->apPage[pCur->iPage];
    ++    MemPage *pPage = pCur->pPage;
    +     u8 *pCell;                          /* Pointer to current cell in pPage */
    + 
    +     /* pPage->nCell must be greater than zero. If this is the root-page
    +@@ -59608,14 +65729,16 @@ SQLITE_PRIVATE int sqlite3BtreeMovetoUnpacked(
    +     upr = pPage->nCell-1;
    +     assert( biasRight==0 || biasRight==1 );
    +     idx = upr>>(1-biasRight); /* idx = biasRight ? upr : (lwr+upr)/2; */
    +-    pCur->aiIdx[pCur->iPage] = (u16)idx;
    ++    pCur->ix = (u16)idx;
    +     if( xRecordCompare==0 ){
    +       for(;;){
    +         i64 nCellKey;
    +         pCell = findCellPastPtr(pPage, idx);
    +         if( pPage->intKeyLeaf ){
    +           while( 0x80 <= *(pCell++) ){
    +-            if( pCell>=pPage->aDataEnd ) return SQLITE_CORRUPT_BKPT;
    ++            if( pCell>=pPage->aDataEnd ){
    ++              return SQLITE_CORRUPT_PAGE(pPage);
    ++            }
    +           }
    +         }
    +         getVarint(pCell, (u64*)&nCellKey);
    +@@ -59627,16 +65750,16 @@ SQLITE_PRIVATE int sqlite3BtreeMovetoUnpacked(
    +           if( lwr>upr ){ c = +1; break; }
    +         }else{
    +           assert( nCellKey==intKey );
    +-          pCur->curFlags |= BTCF_ValidNKey;
    +-          pCur->info.nKey = nCellKey;
    +-          pCur->aiIdx[pCur->iPage] = (u16)idx;
    ++          pCur->ix = (u16)idx;
    +           if( !pPage->leaf ){
    +             lwr = idx;
    +             goto moveto_next_layer;
    +           }else{
    ++            pCur->curFlags |= BTCF_ValidNKey;
    ++            pCur->info.nKey = nCellKey;
    ++            pCur->info.nSize = 0;
    +             *pRes = 0;
    +-            rc = SQLITE_OK;
    +-            goto moveto_finish;
    ++            return SQLITE_OK;
    +           }
    +         }
    +         assert( lwr+upr>=0 );
    +@@ -59688,16 +65811,17 @@ SQLITE_PRIVATE int sqlite3BtreeMovetoUnpacked(
    +           testcase( nCell==1 );  /* Invalid key size:  0x80 0x80 0x01 */
    +           testcase( nCell==2 );  /* Minimum legal index key size */
    +           if( nCell<2 ){
    +-            rc = SQLITE_CORRUPT_BKPT;
    ++            rc = SQLITE_CORRUPT_PAGE(pPage);
    +             goto moveto_finish;
    +           }
    +           pCellKey = sqlite3Malloc( nCell+18 );
    +           if( pCellKey==0 ){
    +-            rc = SQLITE_NOMEM;
    ++            rc = SQLITE_NOMEM_BKPT;
    +             goto moveto_finish;
    +           }
    +-          pCur->aiIdx[pCur->iPage] = (u16)idx;
    +-          rc = accessPayload(pCur, 0, nCell, (unsigned char*)pCellKey, 2);
    ++          pCur->ix = (u16)idx;
    ++          rc = accessPayload(pCur, 0, nCell, (unsigned char*)pCellKey, 0);
    ++          pCur->curFlags &= ~BTCF_ValidOvfl;
    +           if( rc ){
    +             sqlite3_free(pCellKey);
    +             goto moveto_finish;
    +@@ -59717,8 +65841,8 @@ SQLITE_PRIVATE int sqlite3BtreeMovetoUnpacked(
    +           assert( c==0 );
    +           *pRes = 0;
    +           rc = SQLITE_OK;
    +-          pCur->aiIdx[pCur->iPage] = (u16)idx;
    +-          if( pIdxKey->errCode ) rc = SQLITE_CORRUPT;
    ++          pCur->ix = (u16)idx;
    ++          if( pIdxKey->errCode ) rc = SQLITE_CORRUPT_BKPT;
    +           goto moveto_finish;
    +         }
    +         if( lwr>upr ) break;
    +@@ -59729,8 +65853,8 @@ SQLITE_PRIVATE int sqlite3BtreeMovetoUnpacked(
    +     assert( lwr==upr+1 || (pPage->intKey && !pPage->leaf) );
    +     assert( pPage->isInit );
    +     if( pPage->leaf ){
    +-      assert( pCur->aiIdx[pCur->iPage]<pCur->apPage[pCur->iPage]->nCell );
    +-      pCur->aiIdx[pCur->iPage] = (u16)idx;
    ++      assert( pCur->ix<pCur->pPage->nCell );
    ++      pCur->ix = (u16)idx;
    +       *pRes = c;
    +       rc = SQLITE_OK;
    +       goto moveto_finish;
    +@@ -59741,13 +65865,13 @@ moveto_next_layer:
    +     }else{
    +       chldPg = get4byte(findCell(pPage, lwr));
    +     }
    +-    pCur->aiIdx[pCur->iPage] = (u16)lwr;
    ++    pCur->ix = (u16)lwr;
    +     rc = moveToChild(pCur, chldPg);
    +     if( rc ) break;
    +   }
    + moveto_finish:
    +   pCur->info.nSize = 0;
    +-  pCur->curFlags &= ~(BTCF_ValidNKey|BTCF_ValidOvfl);
    ++  assert( (pCur->curFlags & BTCF_ValidOvfl)==0 );
    +   return rc;
    + }
    + 
    +@@ -59768,10 +65892,37 @@ SQLITE_PRIVATE int sqlite3BtreeEof(BtCursor *pCur){
    + }
    + 
    + /*
    +-** Advance the cursor to the next entry in the database.  If
    +-** successful then set *pRes=0.  If the cursor
    +-** was already pointing to the last entry in the database before
    +-** this routine was called, then set *pRes=1.
    ++** Return an estimate for the number of rows in the table that pCur is
    ++** pointing to.  Return a negative number if no estimate is currently 
    ++** available.
    ++*/
    ++SQLITE_PRIVATE i64 sqlite3BtreeRowCountEst(BtCursor *pCur){
    ++  i64 n;
    ++  u8 i;
    ++
    ++  assert( cursorOwnsBtShared(pCur) );
    ++  assert( sqlite3_mutex_held(pCur->pBtree->db->mutex) );
    ++
    ++  /* Currently this interface is only called by the OP_IfSmaller
    ++  ** opcode, and it that case the cursor will always be valid and
    ++  ** will always point to a leaf node. */
    ++  if( NEVER(pCur->eState!=CURSOR_VALID) ) return -1;
    ++  if( NEVER(pCur->pPage->leaf==0) ) return -1;
    ++
    ++  n = pCur->pPage->nCell;
    ++  for(i=0; i<pCur->iPage; i++){
    ++    n *= pCur->apPage[i]->nCell;
    ++  }
    ++  return n;
    ++}
    ++
    ++/*
    ++** Advance the cursor to the next entry in the database. 
    ++** Return value:
    ++**
    ++**    SQLITE_OK        success
    ++**    SQLITE_DONE      cursor is already pointing at the last element
    ++**    otherwise        some kind of error occurred
    + **
    + ** The main entry point is sqlite3BtreeNext().  That routine is optimized
    + ** for the common case of merely incrementing the cell counter BtCursor.aiIdx
    +@@ -59779,23 +65930,19 @@ SQLITE_PRIVATE int sqlite3BtreeEof(BtCursor *pCur){
    + ** routine is called when it is necessary to move to a different page or
    + ** to restore the cursor.
    + **
    +-** The calling function will set *pRes to 0 or 1.  The initial *pRes value
    +-** will be 1 if the cursor being stepped corresponds to an SQL index and
    +-** if this routine could have been skipped if that SQL index had been
    +-** a unique index.  Otherwise the caller will have set *pRes to zero.
    +-** Zero is the common case. The btree implementation is free to use the
    +-** initial *pRes value as a hint to improve performance, but the current
    +-** SQLite btree implementation does not. (Note that the comdb2 btree
    +-** implementation does use this hint, however.)
    ++** If bit 0x01 of the F argument in sqlite3BtreeNext(C,F) is 1, then the
    ++** cursor corresponds to an SQL index and this routine could have been
    ++** skipped if the SQL index had been a unique index.  The F argument
    ++** is a hint to the implement.  SQLite btree implementation does not use
    ++** this hint, but COMDB2 does.
    + */
    +-static SQLITE_NOINLINE int btreeNext(BtCursor *pCur, int *pRes){
    ++static SQLITE_NOINLINE int btreeNext(BtCursor *pCur){
    +   int rc;
    +   int idx;
    +   MemPage *pPage;
    + 
    +-  assert( cursorHoldsMutex(pCur) );
    ++  assert( cursorOwnsBtShared(pCur) );
    +   assert( pCur->skipNext==0 || pCur->eState!=CURSOR_VALID );
    +-  assert( *pRes==0 );
    +   if( pCur->eState!=CURSOR_VALID ){
    +     assert( (pCur->curFlags & BTCF_ValidOvfl)==0 );
    +     rc = restoreCursorPosition(pCur);
    +@@ -59803,8 +65950,7 @@ static SQLITE_NOINLINE int btreeNext(BtCursor *pCur, int *pRes){
    +       return rc;
    +     }
    +     if( CURSOR_INVALID==pCur->eState ){
    +-      *pRes = 1;
    +-      return SQLITE_OK;
    ++      return SQLITE_DONE;
    +     }
    +     if( pCur->skipNext ){
    +       assert( pCur->eState==CURSOR_VALID || pCur->eState==CURSOR_SKIPNEXT );
    +@@ -59817,8 +65963,8 @@ static SQLITE_NOINLINE int btreeNext(BtCursor *pCur, int *pRes){
    +     }
    +   }
    + 
    +-  pPage = pCur->apPage[pCur->iPage];
    +-  idx = ++pCur->aiIdx[pCur->iPage];
    ++  pPage = pCur->pPage;
    ++  idx = ++pCur->ix;
    +   assert( pPage->isInit );
    + 
    +   /* If the database file is corrupt, it is possible for the value of idx 
    +@@ -59836,15 +65982,14 @@ static SQLITE_NOINLINE int btreeNext(BtCursor *pCur, int *pRes){
    +     }
    +     do{
    +       if( pCur->iPage==0 ){
    +-        *pRes = 1;
    +         pCur->eState = CURSOR_INVALID;
    +-        return SQLITE_OK;
    ++        return SQLITE_DONE;
    +       }
    +       moveToParent(pCur);
    +-      pPage = pCur->apPage[pCur->iPage];
    +-    }while( pCur->aiIdx[pCur->iPage]>=pPage->nCell );
    ++      pPage = pCur->pPage;
    ++    }while( pCur->ix>=pPage->nCell );
    +     if( pPage->intKey ){
    +-      return sqlite3BtreeNext(pCur, pRes);
    ++      return sqlite3BtreeNext(pCur, 0);
    +     }else{
    +       return SQLITE_OK;
    +     }
    +@@ -59855,20 +66000,19 @@ static SQLITE_NOINLINE int btreeNext(BtCursor *pCur, int *pRes){
    +     return moveToLeftmost(pCur);
    +   }
    + }
    +-SQLITE_PRIVATE int sqlite3BtreeNext(BtCursor *pCur, int *pRes){
    ++SQLITE_PRIVATE int sqlite3BtreeNext(BtCursor *pCur, int flags){
    +   MemPage *pPage;
    +-  assert( cursorHoldsMutex(pCur) );
    +-  assert( pRes!=0 );
    +-  assert( *pRes==0 || *pRes==1 );
    ++  UNUSED_PARAMETER( flags );  /* Used in COMDB2 but not native SQLite */
    ++  assert( cursorOwnsBtShared(pCur) );
    ++  assert( flags==0 || flags==1 );
    +   assert( pCur->skipNext==0 || pCur->eState!=CURSOR_VALID );
    +   pCur->info.nSize = 0;
    +   pCur->curFlags &= ~(BTCF_ValidNKey|BTCF_ValidOvfl);
    +-  *pRes = 0;
    +-  if( pCur->eState!=CURSOR_VALID ) return btreeNext(pCur, pRes);
    +-  pPage = pCur->apPage[pCur->iPage];
    +-  if( (++pCur->aiIdx[pCur->iPage])>=pPage->nCell ){
    +-    pCur->aiIdx[pCur->iPage]--;
    +-    return btreeNext(pCur, pRes);
    ++  if( pCur->eState!=CURSOR_VALID ) return btreeNext(pCur);
    ++  pPage = pCur->pPage;
    ++  if( (++pCur->ix)>=pPage->nCell ){
    ++    pCur->ix--;
    ++    return btreeNext(pCur);
    +   }
    +   if( pPage->leaf ){
    +     return SQLITE_OK;
    +@@ -59878,10 +66022,12 @@ SQLITE_PRIVATE int sqlite3BtreeNext(BtCursor *pCur, int *pRes){
    + }
    + 
    + /*
    +-** Step the cursor to the back to the previous entry in the database.  If
    +-** successful then set *pRes=0.  If the cursor
    +-** was already pointing to the first entry in the database before
    +-** this routine was called, then set *pRes=1.
    ++** Step the cursor to the back to the previous entry in the database.
    ++** Return values:
    ++**
    ++**     SQLITE_OK     success
    ++**     SQLITE_DONE   the cursor is already on the first element of the table
    ++**     otherwise     some kind of error occurred
    + **
    + ** The main entry point is sqlite3BtreePrevious().  That routine is optimized
    + ** for the common case of merely decrementing the cell counter BtCursor.aiIdx
    +@@ -59889,22 +66035,17 @@ SQLITE_PRIVATE int sqlite3BtreeNext(BtCursor *pCur, int *pRes){
    + ** helper routine is called when it is necessary to move to a different page
    + ** or to restore the cursor.
    + **
    +-** The calling function will set *pRes to 0 or 1.  The initial *pRes value
    +-** will be 1 if the cursor being stepped corresponds to an SQL index and
    +-** if this routine could have been skipped if that SQL index had been
    +-** a unique index.  Otherwise the caller will have set *pRes to zero.
    +-** Zero is the common case. The btree implementation is free to use the
    +-** initial *pRes value as a hint to improve performance, but the current
    +-** SQLite btree implementation does not. (Note that the comdb2 btree
    +-** implementation does use this hint, however.)
    ++** If bit 0x01 of the F argument to sqlite3BtreePrevious(C,F) is 1, then
    ++** the cursor corresponds to an SQL index and this routine could have been
    ++** skipped if the SQL index had been a unique index.  The F argument is a
    ++** hint to the implement.  The native SQLite btree implementation does not
    ++** use this hint, but COMDB2 does.
    + */
    +-static SQLITE_NOINLINE int btreePrevious(BtCursor *pCur, int *pRes){
    ++static SQLITE_NOINLINE int btreePrevious(BtCursor *pCur){
    +   int rc;
    +   MemPage *pPage;
    + 
    +-  assert( cursorHoldsMutex(pCur) );
    +-  assert( pRes!=0 );
    +-  assert( *pRes==0 );
    ++  assert( cursorOwnsBtShared(pCur) );
    +   assert( pCur->skipNext==0 || pCur->eState!=CURSOR_VALID );
    +   assert( (pCur->curFlags & (BTCF_AtLast|BTCF_ValidOvfl|BTCF_ValidNKey))==0 );
    +   assert( pCur->info.nSize==0 );
    +@@ -59914,8 +66055,7 @@ static SQLITE_NOINLINE int btreePrevious(BtCursor *pCur, int *pRes){
    +       return rc;
    +     }
    +     if( CURSOR_INVALID==pCur->eState ){
    +-      *pRes = 1;
    +-      return SQLITE_OK;
    ++      return SQLITE_DONE;
    +     }
    +     if( pCur->skipNext ){
    +       assert( pCur->eState==CURSOR_VALID || pCur->eState==CURSOR_SKIPNEXT );
    +@@ -59928,50 +66068,48 @@ static SQLITE_NOINLINE int btreePrevious(BtCursor *pCur, int *pRes){
    +     }
    +   }
    + 
    +-  pPage = pCur->apPage[pCur->iPage];
    ++  pPage = pCur->pPage;
    +   assert( pPage->isInit );
    +   if( !pPage->leaf ){
    +-    int idx = pCur->aiIdx[pCur->iPage];
    ++    int idx = pCur->ix;
    +     rc = moveToChild(pCur, get4byte(findCell(pPage, idx)));
    +     if( rc ) return rc;
    +     rc = moveToRightmost(pCur);
    +   }else{
    +-    while( pCur->aiIdx[pCur->iPage]==0 ){
    ++    while( pCur->ix==0 ){
    +       if( pCur->iPage==0 ){
    +         pCur->eState = CURSOR_INVALID;
    +-        *pRes = 1;
    +-        return SQLITE_OK;
    ++        return SQLITE_DONE;
    +       }
    +       moveToParent(pCur);
    +     }
    +     assert( pCur->info.nSize==0 );
    +-    assert( (pCur->curFlags & (BTCF_ValidNKey|BTCF_ValidOvfl))==0 );
    ++    assert( (pCur->curFlags & (BTCF_ValidOvfl))==0 );
    + 
    +-    pCur->aiIdx[pCur->iPage]--;
    +-    pPage = pCur->apPage[pCur->iPage];
    ++    pCur->ix--;
    ++    pPage = pCur->pPage;
    +     if( pPage->intKey && !pPage->leaf ){
    +-      rc = sqlite3BtreePrevious(pCur, pRes);
    ++      rc = sqlite3BtreePrevious(pCur, 0);
    +     }else{
    +       rc = SQLITE_OK;
    +     }
    +   }
    +   return rc;
    + }
    +-SQLITE_PRIVATE int sqlite3BtreePrevious(BtCursor *pCur, int *pRes){
    +-  assert( cursorHoldsMutex(pCur) );
    +-  assert( pRes!=0 );
    +-  assert( *pRes==0 || *pRes==1 );
    ++SQLITE_PRIVATE int sqlite3BtreePrevious(BtCursor *pCur, int flags){
    ++  assert( cursorOwnsBtShared(pCur) );
    ++  assert( flags==0 || flags==1 );
    +   assert( pCur->skipNext==0 || pCur->eState!=CURSOR_VALID );
    +-  *pRes = 0;
    ++  UNUSED_PARAMETER( flags );  /* Used in COMDB2 but not native SQLite */
    +   pCur->curFlags &= ~(BTCF_AtLast|BTCF_ValidOvfl|BTCF_ValidNKey);
    +   pCur->info.nSize = 0;
    +   if( pCur->eState!=CURSOR_VALID
    +-   || pCur->aiIdx[pCur->iPage]==0
    +-   || pCur->apPage[pCur->iPage]->leaf==0
    ++   || pCur->ix==0
    ++   || pCur->pPage->leaf==0
    +   ){
    +-    return btreePrevious(pCur, pRes);
    ++    return btreePrevious(pCur);
    +   }
    +-  pCur->aiIdx[pCur->iPage]--;
    ++  pCur->ix--;
    +   return SQLITE_OK;
    + }
    + 
    +@@ -60077,7 +66215,7 @@ static int allocateBtreePage(
    +       }
    +       testcase( iTrunk==mxPage );
    +       if( iTrunk>mxPage || nSearch++ > n ){
    +-        rc = SQLITE_CORRUPT_BKPT;
    ++        rc = SQLITE_CORRUPT_PGNO(pPrevTrunk ? pPrevTrunk->pgno : 1);
    +       }else{
    +         rc = btreeGetUnusedPage(pBt, iTrunk, &pTrunk, 0);
    +       }
    +@@ -60106,7 +66244,7 @@ static int allocateBtreePage(
    +         TRACE(("ALLOCATE: %d trunk - %d free pages left\n", *pPgno, n-1));
    +       }else if( k>(u32)(pBt->usableSize/4 - 2) ){
    +         /* Value of k is out of range.  Database corruption */
    +-        rc = SQLITE_CORRUPT_BKPT;
    ++        rc = SQLITE_CORRUPT_PGNO(iTrunk);
    +         goto end_allocate_page;
    + #ifndef SQLITE_OMIT_AUTOVACUUM
    +       }else if( searchList 
    +@@ -60140,7 +66278,7 @@ static int allocateBtreePage(
    +           MemPage *pNewTrunk;
    +           Pgno iNewTrunk = get4byte(&pTrunk->aData[8]);
    +           if( iNewTrunk>mxPage ){ 
    +-            rc = SQLITE_CORRUPT_BKPT;
    ++            rc = SQLITE_CORRUPT_PGNO(iTrunk);
    +             goto end_allocate_page;
    +           }
    +           testcase( iNewTrunk==mxPage );
    +@@ -60205,7 +66343,7 @@ static int allocateBtreePage(
    +         iPage = get4byte(&aData[8+closest*4]);
    +         testcase( iPage==mxPage );
    +         if( iPage>mxPage ){
    +-          rc = SQLITE_CORRUPT_BKPT;
    ++          rc = SQLITE_CORRUPT_PGNO(iTrunk);
    +           goto end_allocate_page;
    +         }
    +         testcase( iPage==mxPage );
    +@@ -60461,30 +66599,30 @@ static void freePage(MemPage *pPage, int *pRC){
    + static int clearCell(
    +   MemPage *pPage,          /* The page that contains the Cell */
    +   unsigned char *pCell,    /* First byte of the Cell */
    +-  u16 *pnSize              /* Write the size of the Cell here */
    ++  CellInfo *pInfo          /* Size information about the cell */
    + ){
    +-  BtShared *pBt = pPage->pBt;
    +-  CellInfo info;
    ++  BtShared *pBt;
    +   Pgno ovflPgno;
    +   int rc;
    +   int nOvfl;
    +   u32 ovflPageSize;
    + 
    +   assert( sqlite3_mutex_held(pPage->pBt->mutex) );
    +-  pPage->xParseCell(pPage, pCell, &info);
    +-  *pnSize = info.nSize;
    +-  if( info.iOverflow==0 ){
    ++  pPage->xParseCell(pPage, pCell, pInfo);
    ++  if( pInfo->nLocal==pInfo->nPayload ){
    +     return SQLITE_OK;  /* No overflow pages. Return without doing anything */
    +   }
    +-  if( pCell+info.iOverflow+3 > pPage->aData+pPage->maskPage ){
    +-    return SQLITE_CORRUPT_BKPT;  /* Cell extends past end of page */
    ++  if( pCell+pInfo->nSize-1 > pPage->aData+pPage->maskPage ){
    ++    /* Cell extends past end of page */
    ++    return SQLITE_CORRUPT_PAGE(pPage);
    +   }
    +-  ovflPgno = get4byte(&pCell[info.iOverflow]);
    ++  ovflPgno = get4byte(pCell + pInfo->nSize - 4);
    ++  pBt = pPage->pBt;
    +   assert( pBt->usableSize > 4 );
    +   ovflPageSize = pBt->usableSize - 4;
    +-  nOvfl = (info.nPayload - info.nLocal + ovflPageSize - 1)/ovflPageSize;
    ++  nOvfl = (pInfo->nPayload - pInfo->nLocal + ovflPageSize - 1)/ovflPageSize;
    +   assert( nOvfl>0 || 
    +-    (CORRUPT_DB && (info.nPayload + ovflPageSize)<ovflPageSize)
    ++    (CORRUPT_DB && (pInfo->nPayload + ovflPageSize)<ovflPageSize)
    +   );
    +   while( nOvfl-- ){
    +     Pgno iNext = 0;
    +@@ -60542,71 +66680,74 @@ static int clearCell(
    + static int fillInCell(
    +   MemPage *pPage,                /* The page that contains the cell */
    +   unsigned char *pCell,          /* Complete text of the cell */
    +-  const void *pKey, i64 nKey,    /* The key */
    +-  const void *pData,int nData,   /* The data */
    +-  int nZero,                     /* Extra zero bytes to append to pData */
    ++  const BtreePayload *pX,        /* Payload with which to construct the cell */
    +   int *pnSize                    /* Write cell size here */
    + ){
    +   int nPayload;
    +   const u8 *pSrc;
    +-  int nSrc, n, rc;
    ++  int nSrc, n, rc, mn;
    +   int spaceLeft;
    +-  MemPage *pOvfl = 0;
    +-  MemPage *pToRelease = 0;
    ++  MemPage *pToRelease;
    +   unsigned char *pPrior;
    +   unsigned char *pPayload;
    +-  BtShared *pBt = pPage->pBt;
    +-  Pgno pgnoOvfl = 0;
    ++  BtShared *pBt;
    ++  Pgno pgnoOvfl;
    +   int nHeader;
    + 
    +   assert( sqlite3_mutex_held(pPage->pBt->mutex) );
    + 
    +   /* pPage is not necessarily writeable since pCell might be auxiliary
    +   ** buffer space that is separate from the pPage buffer area */
    +-  assert( pCell<pPage->aData || pCell>=&pPage->aData[pBt->pageSize]
    ++  assert( pCell<pPage->aData || pCell>=&pPage->aData[pPage->pBt->pageSize]
    +             || sqlite3PagerIswriteable(pPage->pDbPage) );
    + 
    +   /* Fill in the header. */
    +   nHeader = pPage->childPtrSize;
    +-  nPayload = nData + nZero;
    +-  if( pPage->intKeyLeaf ){
    ++  if( pPage->intKey ){
    ++    nPayload = pX->nData + pX->nZero;
    ++    pSrc = pX->pData;
    ++    nSrc = pX->nData;
    ++    assert( pPage->intKeyLeaf ); /* fillInCell() only called for leaves */
    +     nHeader += putVarint32(&pCell[nHeader], nPayload);
    ++    nHeader += putVarint(&pCell[nHeader], *(u64*)&pX->nKey);
    +   }else{
    +-    assert( nData==0 );
    +-    assert( nZero==0 );
    ++    assert( pX->nKey<=0x7fffffff && pX->pKey!=0 );
    ++    nSrc = nPayload = (int)pX->nKey;
    ++    pSrc = pX->pKey;
    ++    nHeader += putVarint32(&pCell[nHeader], nPayload);
    +   }
    +-  nHeader += putVarint(&pCell[nHeader], *(u64*)&nKey);
    +   
    +-  /* Fill in the payload size */
    +-  if( pPage->intKey ){
    +-    pSrc = pData;
    +-    nSrc = nData;
    +-    nData = 0;
    +-  }else{ 
    +-    assert( nKey<=0x7fffffff && pKey!=0 );
    +-    nPayload = (int)nKey;
    +-    pSrc = pKey;
    +-    nSrc = (int)nKey;
    +-  }
    ++  /* Fill in the payload */
    ++  pPayload = &pCell[nHeader];
    +   if( nPayload<=pPage->maxLocal ){
    ++    /* This is the common case where everything fits on the btree page
    ++    ** and no overflow pages are required. */
    +     n = nHeader + nPayload;
    +     testcase( n==3 );
    +     testcase( n==4 );
    +     if( n<4 ) n = 4;
    +     *pnSize = n;
    +-    spaceLeft = nPayload;
    +-    pPrior = pCell;
    +-  }else{
    +-    int mn = pPage->minLocal;
    +-    n = mn + (nPayload - mn) % (pPage->pBt->usableSize - 4);
    +-    testcase( n==pPage->maxLocal );
    +-    testcase( n==pPage->maxLocal+1 );
    +-    if( n > pPage->maxLocal ) n = mn;
    +-    spaceLeft = n;
    +-    *pnSize = n + nHeader + 4;
    +-    pPrior = &pCell[nHeader+n];
    ++    assert( nSrc<=nPayload );
    ++    testcase( nSrc<nPayload );
    ++    memcpy(pPayload, pSrc, nSrc);
    ++    memset(pPayload+nSrc, 0, nPayload-nSrc);
    ++    return SQLITE_OK;
    +   }
    +-  pPayload = &pCell[nHeader];
    ++
    ++  /* If we reach this point, it means that some of the content will need
    ++  ** to spill onto overflow pages.
    ++  */
    ++  mn = pPage->minLocal;
    ++  n = mn + (nPayload - mn) % (pPage->pBt->usableSize - 4);
    ++  testcase( n==pPage->maxLocal );
    ++  testcase( n==pPage->maxLocal+1 );
    ++  if( n > pPage->maxLocal ) n = mn;
    ++  spaceLeft = n;
    ++  *pnSize = n + nHeader + 4;
    ++  pPrior = &pCell[nHeader+n];
    ++  pToRelease = 0;
    ++  pgnoOvfl = 0;
    ++  pBt = pPage->pBt;
    + 
    +   /* At this point variables should be set as follows:
    +   **
    +@@ -60620,21 +66761,47 @@ static int fillInCell(
    +   ** Use a call to btreeParseCellPtr() to verify that the values above
    +   ** were computed correctly.
    +   */
    +-#if SQLITE_DEBUG
    ++#ifdef SQLITE_DEBUG
    +   {
    +     CellInfo info;
    +     pPage->xParseCell(pPage, pCell, &info);
    +-    assert( nHeader=(int)(info.pPayload - pCell) );
    +-    assert( info.nKey==nKey );
    ++    assert( nHeader==(int)(info.pPayload - pCell) );
    ++    assert( info.nKey==pX->nKey );
    +     assert( *pnSize == info.nSize );
    +     assert( spaceLeft == info.nLocal );
    +-    assert( pPrior == &pCell[info.iOverflow] );
    +   }
    + #endif
    + 
    +   /* Write the payload into the local Cell and any extra into overflow pages */
    +-  while( nPayload>0 ){
    ++  while( 1 ){
    ++    n = nPayload;
    ++    if( n>spaceLeft ) n = spaceLeft;
    ++
    ++    /* If pToRelease is not zero than pPayload points into the data area
    ++    ** of pToRelease.  Make sure pToRelease is still writeable. */
    ++    assert( pToRelease==0 || sqlite3PagerIswriteable(pToRelease->pDbPage) );
    ++
    ++    /* If pPayload is part of the data area of pPage, then make sure pPage
    ++    ** is still writeable */
    ++    assert( pPayload<pPage->aData || pPayload>=&pPage->aData[pBt->pageSize]
    ++            || sqlite3PagerIswriteable(pPage->pDbPage) );
    ++
    ++    if( nSrc>=n ){
    ++      memcpy(pPayload, pSrc, n);
    ++    }else if( nSrc>0 ){
    ++      n = nSrc;
    ++      memcpy(pPayload, pSrc, n);
    ++    }else{
    ++      memset(pPayload, 0, n);
    ++    }
    ++    nPayload -= n;
    ++    if( nPayload<=0 ) break;
    ++    pPayload += n;
    ++    pSrc += n;
    ++    nSrc -= n;
    ++    spaceLeft -= n;
    +     if( spaceLeft==0 ){
    ++      MemPage *pOvfl = 0;
    + #ifndef SQLITE_OMIT_AUTOVACUUM
    +       Pgno pgnoPtrmap = pgnoOvfl; /* Overflow page pointer-map entry page */
    +       if( pBt->autoVacuum ){
    +@@ -60687,34 +66854,6 @@ static int fillInCell(
    +       pPayload = &pOvfl->aData[4];
    +       spaceLeft = pBt->usableSize - 4;
    +     }
    +-    n = nPayload;
    +-    if( n>spaceLeft ) n = spaceLeft;
    +-
    +-    /* If pToRelease is not zero than pPayload points into the data area
    +-    ** of pToRelease.  Make sure pToRelease is still writeable. */
    +-    assert( pToRelease==0 || sqlite3PagerIswriteable(pToRelease->pDbPage) );
    +-
    +-    /* If pPayload is part of the data area of pPage, then make sure pPage
    +-    ** is still writeable */
    +-    assert( pPayload<pPage->aData || pPayload>=&pPage->aData[pBt->pageSize]
    +-            || sqlite3PagerIswriteable(pPage->pDbPage) );
    +-
    +-    if( nSrc>0 ){
    +-      if( n>nSrc ) n = nSrc;
    +-      assert( pSrc );
    +-      memcpy(pPayload, pSrc, n);
    +-    }else{
    +-      memset(pPayload, 0, n);
    +-    }
    +-    nPayload -= n;
    +-    pPayload += n;
    +-    pSrc += n;
    +-    nSrc -= n;
    +-    spaceLeft -= n;
    +-    if( nSrc==0 ){
    +-      nSrc = nData;
    +-      pSrc = pData;
    +-    }
    +   }
    +   releasePage(pToRelease);
    +   return SQLITE_OK;
    +@@ -60736,7 +66875,6 @@ static void dropCell(MemPage *pPage, int idx, int sz, int *pRC){
    +   int hdr;        /* Beginning of the header.  0 most pages.  100 page 1 */
    + 
    +   if( *pRC ) return;
    +-
    +   assert( idx>=0 && idx<pPage->nCell );
    +   assert( CORRUPT_DB || sz==cellSize(pPage, idx) );
    +   assert( sqlite3PagerIswriteable(pPage->pDbPage) );
    +@@ -60747,7 +66885,7 @@ static void dropCell(MemPage *pPage, int idx, int sz, int *pRC){
    +   hdr = pPage->hdrOffset;
    +   testcase( pc==get2byte(&data[hdr+5]) );
    +   testcase( pc+sz==pPage->pBt->usableSize );
    +-  if( pc < (u32)get2byte(&data[hdr+5]) || pc+sz > pPage->pBt->usableSize ){
    ++  if( pc+sz > pPage->pBt->usableSize ){
    +     *pRC = SQLITE_CORRUPT_BKPT;
    +     return;
    +   }
    +@@ -60781,6 +66919,8 @@ static void dropCell(MemPage *pPage, int idx, int sz, int *pRC){
    + ** in pTemp or the original pCell) and also record its index. 
    + ** Allocating a new entry in pPage->aCell[] implies that 
    + ** pPage->nOverflow is incremented.
    ++**
    ++** *pRC must be SQLITE_OK when this routine is called.
    + */
    + static void insertCell(
    +   MemPage *pPage,   /* Page into which we are copying */
    +@@ -60796,8 +66936,7 @@ static void insertCell(
    +   u8 *data;         /* The content of the whole page */
    +   u8 *pIns;         /* The point in pPage->aCellIdx[] where no cell inserted */
    + 
    +-  if( *pRC ) return;
    +-
    ++  assert( *pRC==SQLITE_OK );
    +   assert( i>=0 && i<=pPage->nCell+pPage->nOverflow );
    +   assert( MX_CELL(pPage->pBt)<=10921 );
    +   assert( pPage->nCell<=MX_CELL(pPage->pBt) || CORRUPT_DB );
    +@@ -60819,7 +66958,10 @@ static void insertCell(
    +       put4byte(pCell, iChild);
    +     }
    +     j = pPage->nOverflow++;
    +-    assert( j<(int)(sizeof(pPage->apOvfl)/sizeof(pPage->apOvfl[0])) );
    ++    /* Comparison against ArraySize-1 since we hold back one extra slot
    ++    ** as a contingency.  In other words, never need more than 3 overflow
    ++    ** slots but 4 are allocated, just to be safe. */
    ++    assert( j < ArraySize(pPage->apOvfl)-1 );
    +     pPage->apOvfl[j] = pCell;
    +     pPage->aiOvfl[j] = (u16)i;
    + 
    +@@ -60871,7 +67013,7 @@ static void insertCell(
    + 
    + /*
    + ** A CellArray object contains a cache of pointers and sizes for a
    +-** consecutive sequence of cells that might be held multiple pages.
    ++** consecutive sequence of cells that might be held on multiple pages.
    + */
    + typedef struct CellArray CellArray;
    + struct CellArray {
    +@@ -60949,7 +67091,7 @@ static int rebuildPage(
    +   pData = pEnd;
    +   for(i=0; i<nCell; i++){
    +     u8 *pCell = apCell[i];
    +-    if( pCell>aData && pCell<pEnd ){
    ++    if( SQLITE_WITHIN(pCell,aData,pEnd) ){
    +       pCell = &pTmp[pCell - aData];
    +     }
    +     pData -= szCell[i];
    +@@ -61016,8 +67158,8 @@ static int pageInsertArray(
    +     u8 *pSlot;
    +     sz = cachedCellSize(pCArray, i);
    +     if( (aData[1]==0 && aData[2]==0) || (pSlot = pageFindSlot(pPg,sz,&rc))==0 ){
    ++      if( (pData - pBegin)<sz ) return 1;
    +       pData -= sz;
    +-      if( pData<pBegin ) return 1;
    +       pSlot = pData;
    +     }
    +     /* pSlot and pCArray->apCell[i] will never overlap on a well-formed
    +@@ -61060,7 +67202,7 @@ static int pageFreeArray(
    + 
    +   for(i=iFirst; i<iEnd; i++){
    +     u8 *pCell = pCArray->apCell[i];
    +-    if( pCell>=pStart && pCell<pEnd ){
    ++    if( SQLITE_WITHIN(pCell, pStart, pEnd) ){
    +       int sz;
    +       /* No need to use cachedCellSize() here.  The sizes of all cells that
    +       ** are to be freed have already been computing while deciding which
    +@@ -61179,7 +67321,7 @@ static int editPage(
    +   for(i=0; i<nNew && !CORRUPT_DB; i++){
    +     u8 *pCell = pCArray->apCell[i+iNew];
    +     int iOff = get2byteAligned(&pPg->aCellIdx[i*2]);
    +-    if( pCell>=aData && pCell<&aData[pPg->pBt->usableSize] ){
    ++    if( SQLITE_WITHIN(pCell, aData, &aData[pPg->pBt->usableSize]) ){
    +       pCell = &pTmp[pCell - aData];
    +     }
    +     assert( 0==memcmp(pCell, &aData[iOff],
    +@@ -61303,8 +67445,10 @@ static int balance_quick(MemPage *pParent, MemPage *pPage, u8 *pSpace){
    +     while( ((*(pOut++) = *(pCell++))&0x80) && pCell<pStop );
    + 
    +     /* Insert the new divider cell into pParent. */
    +-    insertCell(pParent, pParent->nCell, pSpace, (int)(pOut-pSpace),
    +-               0, pPage->pgno, &rc);
    ++    if( rc==SQLITE_OK ){
    ++      insertCell(pParent, pParent->nCell, pSpace, (int)(pOut-pSpace),
    ++                   0, pPage->pgno, &rc);
    ++    }
    + 
    +     /* Set the right-child pointer of pParent to point to the new page. */
    +     put4byte(&pParent->aData[pParent->hdrOffset+8], pgnoNew);
    +@@ -61338,8 +67482,8 @@ static int ptrmapCheckPages(MemPage **apPage, int nPage){
    +      
    +       z = findCell(pPage, j);
    +       pPage->xParseCell(pPage, z, &info);
    +-      if( info.iOverflow ){
    +-        Pgno ovfl = get4byte(&z[info.iOverflow]);
    ++      if( info.nLocal<info.nPayload ){
    ++        Pgno ovfl = get4byte(&z[info.nSize-4]);
    +         ptrmapGet(pBt, ovfl, &e, &n);
    +         assert( n==pPage->pgno && e==PTRMAP_OVERFLOW1 );
    +       }
    +@@ -61457,9 +67601,6 @@ static void copyNodeContent(MemPage *pFrom, MemPage *pTo, int *pRC){
    + ** If aOvflSpace is set to a null pointer, this function returns 
    + ** SQLITE_NOMEM.
    + */
    +-#if defined(_MSC_VER) && _MSC_VER >= 1700 && defined(_M_ARM)
    +-#pragma optimize("", off)
    +-#endif
    + static int balance_nonroot(
    +   MemPage *pParent,               /* Parent page of siblings being balanced */
    +   int iParentIdx,                 /* Index of "the page" in pParent */
    +@@ -61516,7 +67657,7 @@ static int balance_nonroot(
    +   assert( pParent->nOverflow==0 || pParent->aiOvfl[0]==iParentIdx );
    + 
    +   if( !aOvflSpace ){
    +-    return SQLITE_NOMEM;
    ++    return SQLITE_NOMEM_BKPT;
    +   }
    + 
    +   /* Find the sibling pages to balance. Also locate the cells in pParent 
    +@@ -61560,7 +67701,7 @@ static int balance_nonroot(
    +     nMaxCells += 1+apOld[i]->nCell+apOld[i]->nOverflow;
    +     if( (i--)==0 ) break;
    + 
    +-    if( i+nxDiv==pParent->aiOvfl[0] && pParent->nOverflow ){
    ++    if( pParent->nOverflow && i+nxDiv==pParent->aiOvfl[0] ){
    +       apDiv[i] = pParent->apOvfl[0];
    +       pgno = get4byte(apDiv[i]);
    +       szNew[i] = pParent->xCellSize(pParent, apDiv[i]);
    +@@ -61582,7 +67723,7 @@ static int balance_nonroot(
    +       ** In this case, temporarily copy the cell into the aOvflSpace[]
    +       ** buffer. It will be copied out again as soon as the aSpace[] buffer
    +       ** is allocated.  */
    +-      if( pBt->btsFlags & BTS_SECURE_DELETE ){
    ++      if( pBt->btsFlags & BTS_FAST_SECURE ){
    +         int iOff;
    + 
    +         iOff = SQLITE_PTR_TO_INT(apDiv[i]) - SQLITE_PTR_TO_INT(pParent->aData);
    +@@ -61611,12 +67752,10 @@ static int balance_nonroot(
    +      + nMaxCells*sizeof(u16)                       /* b.szCell */
    +      + pBt->pageSize;                              /* aSpace1 */
    + 
    +-  /* EVIDENCE-OF: R-28375-38319 SQLite will never request a scratch buffer
    +-  ** that is more than 6 times the database page size. */
    +   assert( szScratch<=6*(int)pBt->pageSize );
    +-  b.apCell = sqlite3ScratchMalloc( szScratch ); 
    ++  b.apCell = sqlite3StackAllocRaw(0, szScratch );
    +   if( b.apCell==0 ){
    +-    rc = SQLITE_NOMEM;
    ++    rc = SQLITE_NOMEM_BKPT;
    +     goto balance_cleanup;
    +   }
    +   b.szCell = (u16*)&b.apCell[nMaxCells];
    +@@ -61675,9 +67814,8 @@ static int balance_nonroot(
    +     ** long be able to find the cells if a pointer to each cell is not saved
    +     ** first.
    +     */
    +-    memset(&b.szCell[b.nCell], 0, sizeof(b.szCell[0])*limit);
    ++    memset(&b.szCell[b.nCell], 0, sizeof(b.szCell[0])*(limit+pOld->nOverflow));
    +     if( pOld->nOverflow>0 ){
    +-      memset(&b.szCell[b.nCell+limit], 0, sizeof(b.szCell[0])*pOld->nOverflow);
    +       limit = pOld->aiOvfl[0];
    +       for(j=0; j<limit; j++){
    +         b.apCell[b.nCell] = aData + (maskPage & get2byteAligned(piCell));
    +@@ -61753,7 +67891,6 @@ static int balance_nonroot(
    +   for(i=0; i<nOld; i++){
    +     MemPage *p = apOld[i];
    +     szNew[i] = usableSpace - p->nFree;
    +-    if( szNew[i]<0 ){ rc = SQLITE_CORRUPT_BKPT; goto balance_cleanup; }
    +     for(j=0; j<p->nOverflow; j++){
    +       szNew[i] += 2 + p->xCellSize(p, p->apOvfl[j]);
    +     }
    +@@ -61828,7 +67965,7 @@ static int balance_nonroot(
    +       assert( r<nMaxCells );
    +       (void)cachedCellSize(&b, r);
    +       if( szRight!=0
    +-       && (bBulk || szRight+b.szCell[d]+2 > szLeft-(b.szCell[r]+2)) ){
    ++       && (bBulk || szRight+b.szCell[d]+2 > szLeft-(b.szCell[r]+(i==k-1?0:2)))){
    +         break;
    +       }
    +       szRight += b.szCell[d] + 2;
    +@@ -62003,8 +68140,7 @@ static int balance_nonroot(
    +       ** overflow cell), we can skip updating the pointer map entries.  */
    +       if( iOld>=nNew
    +        || pNew->pgno!=aPgno[iOld]
    +-       || pCell<aOld
    +-       || pCell>=&aOld[usableSize]
    ++       || !SQLITE_WITHIN(pCell,aOld,&aOld[usableSize])
    +       ){
    +         if( !leafCorrection ){
    +           ptrmapPut(pBt, get4byte(pCell), PTRMAP_BTREE, pNew->pgno, &rc);
    +@@ -62053,9 +68189,9 @@ static int balance_nonroot(
    +       ** any cell). But it is important to pass the correct size to 
    +       ** insertCell(), so reparse the cell now.
    +       **
    +-      ** Note that this can never happen in an SQLite data file, as all
    +-      ** cells are at least 4 bytes. It only happens in b-trees used
    +-      ** to evaluate "IN (SELECT ...)" and similar clauses.
    ++      ** This can only happen for b-trees used to evaluate "IN (SELECT ...)"
    ++      ** and WITHOUT ROWID tables with exactly one column which is the
    ++      ** primary key.
    +       */
    +       if( b.szCell[j]==4 ){
    +         assert(leafCorrection==4);
    +@@ -62152,7 +68288,7 @@ static int balance_nonroot(
    +     ** free space needs to be up front.
    +     */
    +     assert( nNew==1 || CORRUPT_DB );
    +-    rc = defragmentPage(apNew[0]);
    ++    rc = defragmentPage(apNew[0], -1);
    +     testcase( rc!=SQLITE_OK );
    +     assert( apNew[0]->nFree == 
    +         (get2byte(&apNew[0]->aData[5])-apNew[0]->cellOffset-apNew[0]->nCell*2)
    +@@ -62195,7 +68331,7 @@ static int balance_nonroot(
    +   ** Cleanup before returning.
    +   */
    + balance_cleanup:
    +-  sqlite3ScratchFree(b.apCell);
    ++  sqlite3StackFree(0, b.apCell);
    +   for(i=0; i<nOld; i++){
    +     releasePage(apOld[i]);
    +   }
    +@@ -62205,9 +68341,6 @@ balance_cleanup:
    + 
    +   return rc;
    + }
    +-#if defined(_MSC_VER) && _MSC_VER >= 1700 && defined(_M_ARM)
    +-#pragma optimize("", on)
    +-#endif
    + 
    + 
    + /*
    +@@ -62292,12 +68425,12 @@ static int balance(BtCursor *pCur){
    +   u8 aBalanceQuickSpace[13];
    +   u8 *pFree = 0;
    + 
    +-  TESTONLY( int balance_quick_called = 0 );
    +-  TESTONLY( int balance_deeper_called = 0 );
    ++  VVA_ONLY( int balance_quick_called = 0 );
    ++  VVA_ONLY( int balance_deeper_called = 0 );
    + 
    +   do {
    +     int iPage = pCur->iPage;
    +-    MemPage *pPage = pCur->apPage[iPage];
    ++    MemPage *pPage = pCur->pPage;
    + 
    +     if( iPage==0 ){
    +       if( pPage->nOverflow ){
    +@@ -62306,13 +68439,16 @@ static int balance(BtCursor *pCur){
    +         ** and copy the current contents of the root-page to it. The
    +         ** next iteration of the do-loop will balance the child page.
    +         */ 
    +-        assert( (balance_deeper_called++)==0 );
    ++        assert( balance_deeper_called==0 );
    ++        VVA_ONLY( balance_deeper_called++ );
    +         rc = balance_deeper(pPage, &pCur->apPage[1]);
    +         if( rc==SQLITE_OK ){
    +           pCur->iPage = 1;
    ++          pCur->ix = 0;
    +           pCur->aiIdx[0] = 0;
    +-          pCur->aiIdx[1] = 0;
    +-          assert( pCur->apPage[1]->nOverflow );
    ++          pCur->apPage[0] = pPage;
    ++          pCur->pPage = pCur->apPage[1];
    ++          assert( pCur->pPage->nOverflow );
    +         }
    +       }else{
    +         break;
    +@@ -62345,7 +68481,8 @@ static int balance(BtCursor *pCur){
    +           ** function. If this were not verified, a subtle bug involving reuse
    +           ** of the aBalanceQuickSpace[] might sneak in.
    +           */
    +-          assert( (balance_quick_called++)==0 );
    ++          assert( balance_quick_called==0 ); 
    ++          VVA_ONLY( balance_quick_called++ );
    +           rc = balance_quick(pParent, pPage, aBalanceQuickSpace);
    +         }else
    + #endif
    +@@ -62391,6 +68528,7 @@ static int balance(BtCursor *pCur){
    +       releasePage(pPage);
    +       pCur->iPage--;
    +       assert( pCur->iPage>=0 );
    ++      pCur->pPage = pCur->apPage[pCur->iPage];
    +     }
    +   }while( rc==SQLITE_OK );
    + 
    +@@ -62402,33 +68540,39 @@ static int balance(BtCursor *pCur){
    + 
    + 
    + /*
    +-** Insert a new record into the BTree.  The key is given by (pKey,nKey)
    +-** and the data is given by (pData,nData).  The cursor is used only to
    +-** define what table the record should be inserted into.  The cursor
    +-** is left pointing at a random location.
    ++** Insert a new record into the BTree.  The content of the new record
    ++** is described by the pX object.  The pCur cursor is used only to
    ++** define what table the record should be inserted into, and is left
    ++** pointing at a random location.
    ++**
    ++** For a table btree (used for rowid tables), only the pX.nKey value of
    ++** the key is used. The pX.pKey value must be NULL.  The pX.nKey is the
    ++** rowid or INTEGER PRIMARY KEY of the row.  The pX.nData,pData,nZero fields
    ++** hold the content of the row.
    + **
    +-** For an INTKEY table, only the nKey value of the key is used.  pKey is
    +-** ignored.  For a ZERODATA table, the pData and nData are both ignored.
    ++** For an index btree (used for indexes and WITHOUT ROWID tables), the
    ++** key is an arbitrary byte sequence stored in pX.pKey,nKey.  The 
    ++** pX.pData,nData,nZero fields must be zero.
    + **
    + ** If the seekResult parameter is non-zero, then a successful call to
    +-** MovetoUnpacked() to seek cursor pCur to (pKey, nKey) has already
    +-** been performed. seekResult is the search result returned (a negative
    +-** number if pCur points at an entry that is smaller than (pKey, nKey), or
    +-** a positive value if pCur points at an entry that is larger than 
    +-** (pKey, nKey)). 
    +-**
    +-** If the seekResult parameter is non-zero, then the caller guarantees that
    +-** cursor pCur is pointing at the existing copy of a row that is to be
    +-** overwritten.  If the seekResult parameter is 0, then cursor pCur may
    +-** point to any entry or to no entry at all and so this function has to seek
    +-** the cursor before the new key can be inserted.
    ++** MovetoUnpacked() to seek cursor pCur to (pKey,nKey) has already
    ++** been performed.  In other words, if seekResult!=0 then the cursor
    ++** is currently pointing to a cell that will be adjacent to the cell
    ++** to be inserted.  If seekResult<0 then pCur points to a cell that is
    ++** smaller then (pKey,nKey).  If seekResult>0 then pCur points to a cell
    ++** that is larger than (pKey,nKey).
    ++**
    ++** If seekResult==0, that means pCur is pointing at some unknown location.
    ++** In that case, this routine must seek the cursor to the correct insertion
    ++** point for (pKey,nKey) before doing the insertion.  For index btrees,
    ++** if pX->nMem is non-zero, then pX->aMem contains pointers to the unpacked
    ++** key values and pX->aMem can be used instead of pX->pKey to avoid having
    ++** to decode the key.
    + */
    + SQLITE_PRIVATE int sqlite3BtreeInsert(
    +   BtCursor *pCur,                /* Insert data into the table of this cursor */
    +-  const void *pKey, i64 nKey,    /* The key of the new record */
    +-  const void *pData, int nData,  /* The data of the new record */
    +-  int nZero,                     /* Number of extra 0 bytes to append to data */
    +-  int appendBias,                /* True if this is likely an append */
    ++  const BtreePayload *pX,        /* Content of the row to be inserted */
    ++  int flags,                     /* True if this is likely an append */
    +   int seekResult                 /* Result of prior MovetoUnpacked() call */
    + ){
    +   int rc;
    +@@ -62441,12 +68585,14 @@ SQLITE_PRIVATE int sqlite3BtreeInsert(
    +   unsigned char *oldCell;
    +   unsigned char *newCell = 0;
    + 
    ++  assert( (flags & (BTREE_SAVEPOSITION|BTREE_APPEND))==flags );
    ++
    +   if( pCur->eState==CURSOR_FAULT ){
    +     assert( pCur->skipNext!=SQLITE_OK );
    +     return pCur->skipNext;
    +   }
    + 
    +-  assert( cursorHoldsMutex(pCur) );
    ++  assert( cursorOwnsBtShared(pCur) );
    +   assert( (pCur->curFlags & BTCF_WriteFlag)!=0
    +               && pBt->inTransaction==TRANS_WRITE
    +               && (pBt->btsFlags & BTS_READ_ONLY)==0 );
    +@@ -62457,7 +68603,7 @@ SQLITE_PRIVATE int sqlite3BtreeInsert(
    +   ** keys with no associated data. If the cursor was opened expecting an
    +   ** intkey table, the caller should be inserting integer keys with a
    +   ** blob of associated data.  */
    +-  assert( (pKey==0)==(pCur->pKeyInfo==0) );
    ++  assert( (pX->pKey==0)==(pCur->pKeyInfo==0) );
    + 
    +   /* Save the positions of any other cursors open on this table.
    +   **
    +@@ -62476,44 +68622,61 @@ SQLITE_PRIVATE int sqlite3BtreeInsert(
    +   }
    + 
    +   if( pCur->pKeyInfo==0 ){
    +-    assert( pKey==0 );
    ++    assert( pX->pKey==0 );
    +     /* If this is an insert into a table b-tree, invalidate any incrblob 
    +     ** cursors open on the row being replaced */
    +-    invalidateIncrblobCursors(p, nKey, 0);
    ++    invalidateIncrblobCursors(p, pCur->pgnoRoot, pX->nKey, 0);
    ++
    ++    /* If BTREE_SAVEPOSITION is set, the cursor must already be pointing 
    ++    ** to a row with the same key as the new entry being inserted.  */
    ++    assert( (flags & BTREE_SAVEPOSITION)==0 || 
    ++            ((pCur->curFlags&BTCF_ValidNKey)!=0 && pX->nKey==pCur->info.nKey) );
    + 
    +     /* 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->curFlags&BTCF_ValidNKey)!=0 && nKey>0
    +-      && pCur->info.nKey==nKey-1 ){
    +-       loc = -1;
    ++    if( (pCur->curFlags&BTCF_ValidNKey)!=0 && pX->nKey==pCur->info.nKey ){
    ++      loc = 0;
    +     }else if( loc==0 ){
    +-      rc = sqlite3BtreeMovetoUnpacked(pCur, 0, nKey, appendBias, &loc);
    ++      rc = sqlite3BtreeMovetoUnpacked(pCur, 0, pX->nKey, flags!=0, &loc);
    +       if( rc ) return rc;
    +     }
    +-  }else if( loc==0 ){
    +-    rc = btreeMoveto(pCur, pKey, nKey, appendBias, &loc);
    ++  }else if( loc==0 && (flags & BTREE_SAVEPOSITION)==0 ){
    ++    if( pX->nMem ){
    ++      UnpackedRecord r;
    ++      r.pKeyInfo = pCur->pKeyInfo;
    ++      r.aMem = pX->aMem;
    ++      r.nField = pX->nMem;
    ++      r.default_rc = 0;
    ++      r.errCode = 0;
    ++      r.r1 = 0;
    ++      r.r2 = 0;
    ++      r.eqSeen = 0;
    ++      rc = sqlite3BtreeMovetoUnpacked(pCur, &r, 0, flags!=0, &loc);
    ++    }else{
    ++      rc = btreeMoveto(pCur, pX->pKey, pX->nKey, flags!=0, &loc);
    ++    }
    +     if( rc ) return rc;
    +   }
    +   assert( pCur->eState==CURSOR_VALID || (pCur->eState==CURSOR_INVALID && loc) );
    + 
    +-  pPage = pCur->apPage[pCur->iPage];
    +-  assert( pPage->intKey || nKey>=0 );
    ++  pPage = pCur->pPage;
    ++  assert( pPage->intKey || pX->nKey>=0 );
    +   assert( pPage->leaf || !pPage->intKey );
    + 
    +   TRACE(("INSERT: table=%d nkey=%lld ndata=%d page=%d %s\n",
    +-          pCur->pgnoRoot, nKey, nData, pPage->pgno,
    ++          pCur->pgnoRoot, pX->nKey, pX->nData, pPage->pgno,
    +           loc==0 ? "overwrite" : "new entry"));
    +   assert( pPage->isInit );
    +   newCell = pBt->pTmpSpace;
    +   assert( newCell!=0 );
    +-  rc = fillInCell(pPage, newCell, pKey, nKey, pData, nData, nZero, &szNew);
    ++  rc = fillInCell(pPage, newCell, pX, &szNew);
    +   if( rc ) goto end_insert;
    +   assert( szNew==pPage->xCellSize(pPage, newCell) );
    +   assert( szNew <= MX_CELL_SIZE(pBt) );
    +-  idx = pCur->aiIdx[pCur->iPage];
    ++  idx = pCur->ix;
    +   if( loc==0 ){
    +-    u16 szOld;
    ++    CellInfo info;
    +     assert( idx<pPage->nCell );
    +     rc = sqlite3PagerWrite(pPage->pDbPage);
    +     if( rc ){
    +@@ -62523,16 +68686,35 @@ SQLITE_PRIVATE int sqlite3BtreeInsert(
    +     if( !pPage->leaf ){
    +       memcpy(newCell, oldCell, 4);
    +     }
    +-    rc = clearCell(pPage, oldCell, &szOld);
    +-    dropCell(pPage, idx, szOld, &rc);
    ++    rc = clearCell(pPage, oldCell, &info);
    ++    if( info.nSize==szNew && info.nLocal==info.nPayload 
    ++     && (!ISAUTOVACUUM || szNew<pPage->minLocal)
    ++    ){
    ++      /* Overwrite the old cell with the new if they are the same size.
    ++      ** We could also try to do this if the old cell is smaller, then add
    ++      ** the leftover space to the free list.  But experiments show that
    ++      ** doing that is no faster then skipping this optimization and just
    ++      ** calling dropCell() and insertCell(). 
    ++      **
    ++      ** This optimization cannot be used on an autovacuum database if the
    ++      ** new entry uses overflow pages, as the insertCell() call below is
    ++      ** necessary to add the PTRMAP_OVERFLOW1 pointer-map entry.  */
    ++      assert( rc==SQLITE_OK ); /* clearCell never fails when nLocal==nPayload */
    ++      if( oldCell+szNew > pPage->aDataEnd ) return SQLITE_CORRUPT_BKPT;
    ++      memcpy(oldCell, newCell, szNew);
    ++      return SQLITE_OK;
    ++    }
    ++    dropCell(pPage, idx, info.nSize, &rc);
    +     if( rc ) goto end_insert;
    +   }else if( loc<0 && pPage->nCell>0 ){
    +     assert( pPage->leaf );
    +-    idx = ++pCur->aiIdx[pCur->iPage];
    ++    idx = ++pCur->ix;
    ++    pCur->curFlags &= ~BTCF_ValidNKey;
    +   }else{
    +     assert( pPage->leaf );
    +   }
    +   insertCell(pPage, idx, newCell, szNew, 0, 0, &rc);
    ++  assert( pPage->nOverflow==0 || rc==SQLITE_OK );
    +   assert( rc!=SQLITE_OK || pPage->nCell>0 || pPage->nOverflow>0 );
    + 
    +   /* If no error has occurred and pPage has an overflow cell, call balance() 
    +@@ -62556,7 +68738,8 @@ SQLITE_PRIVATE int sqlite3BtreeInsert(
    +   ** row without seeking the cursor. This can be a big performance boost.
    +   */
    +   pCur->info.nSize = 0;
    +-  if( rc==SQLITE_OK && pPage->nOverflow ){
    ++  if( pPage->nOverflow ){
    ++    assert( rc==SQLITE_OK );
    +     pCur->curFlags &= ~(BTCF_ValidNKey);
    +     rc = balance(pCur);
    + 
    +@@ -62564,10 +68747,24 @@ SQLITE_PRIVATE int sqlite3BtreeInsert(
    +     ** fails. Internal data structure corruption will result otherwise. 
    +     ** Also, set the cursor state to invalid. This stops saveCursorPosition()
    +     ** from trying to save the current position of the cursor.  */
    +-    pCur->apPage[pCur->iPage]->nOverflow = 0;
    ++    pCur->pPage->nOverflow = 0;
    +     pCur->eState = CURSOR_INVALID;
    ++    if( (flags & BTREE_SAVEPOSITION) && rc==SQLITE_OK ){
    ++      btreeReleaseAllCursorPages(pCur);
    ++      if( pCur->pKeyInfo ){
    ++        assert( pCur->pKey==0 );
    ++        pCur->pKey = sqlite3Malloc( pX->nKey );
    ++        if( pCur->pKey==0 ){
    ++          rc = SQLITE_NOMEM;
    ++        }else{
    ++          memcpy(pCur->pKey, pX->pKey, pX->nKey);
    ++        }
    ++      }
    ++      pCur->eState = CURSOR_REQUIRESEEK;
    ++      pCur->nKey = pX->nKey;
    ++    }
    +   }
    +-  assert( pCur->apPage[pCur->iPage]->nOverflow==0 );
    ++  assert( pCur->iPage<0 || pCur->pPage->nOverflow==0 );
    + 
    + end_insert:
    +   return rc;
    +@@ -62576,13 +68773,21 @@ end_insert:
    + /*
    + ** Delete the entry that the cursor is pointing to. 
    + **
    +-** If the second parameter is zero, then the cursor is left pointing at an
    +-** arbitrary location after the delete. If it is non-zero, then the cursor 
    +-** is left in a state such that the next call to BtreeNext() or BtreePrev()
    +-** moves it to the same row as it would if the call to BtreeDelete() had
    +-** been omitted.
    +-*/
    +-SQLITE_PRIVATE int sqlite3BtreeDelete(BtCursor *pCur, int bPreserve){
    ++** If the BTREE_SAVEPOSITION bit of the flags parameter is zero, then
    ++** the cursor is left pointing at an arbitrary location after the delete.
    ++** But if that bit is set, then the cursor is left in a state such that
    ++** the next call to BtreeNext() or BtreePrev() moves it to the same row
    ++** as it would have been on if the call to BtreeDelete() had been omitted.
    ++**
    ++** The BTREE_AUXDELETE bit of flags indicates that is one of several deletes
    ++** associated with a single table entry and its indexes.  Only one of those
    ++** deletes is considered the "primary" delete.  The primary delete occurs
    ++** on a cursor that is not a BTREE_FORDELETE cursor.  All but one delete
    ++** operation on non-FORDELETE cursors is tagged with the AUXDELETE flag.
    ++** The BTREE_AUXDELETE bit is a hint that is not used by this implementation,
    ++** but which might be used by alternative storage engines.
    ++*/
    ++SQLITE_PRIVATE int sqlite3BtreeDelete(BtCursor *pCur, u8 flags){
    +   Btree *p = pCur->pBtree;
    +   BtShared *pBt = p->pBt;              
    +   int rc;                              /* Return code */
    +@@ -62590,23 +68795,47 @@ SQLITE_PRIVATE int sqlite3BtreeDelete(BtCursor *pCur, int bPreserve){
    +   unsigned char *pCell;                /* Pointer to cell to delete */
    +   int iCellIdx;                        /* Index of cell to delete */
    +   int iCellDepth;                      /* Depth of node containing pCell */ 
    +-  u16 szCell;                          /* Size of the cell being deleted */
    ++  CellInfo info;                       /* Size of the cell being deleted */
    +   int bSkipnext = 0;                   /* Leaf cursor in SKIPNEXT state */
    ++  u8 bPreserve = flags & BTREE_SAVEPOSITION;  /* Keep cursor valid */
    + 
    +-  assert( cursorHoldsMutex(pCur) );
    ++  assert( cursorOwnsBtShared(pCur) );
    +   assert( pBt->inTransaction==TRANS_WRITE );
    +   assert( (pBt->btsFlags & BTS_READ_ONLY)==0 );
    +   assert( pCur->curFlags & BTCF_WriteFlag );
    +   assert( hasSharedCacheTableLock(p, pCur->pgnoRoot, pCur->pKeyInfo!=0, 2) );
    +   assert( !hasReadConflicts(p, pCur->pgnoRoot) );
    +-  assert( pCur->aiIdx[pCur->iPage]<pCur->apPage[pCur->iPage]->nCell );
    ++  assert( pCur->ix<pCur->pPage->nCell );
    +   assert( pCur->eState==CURSOR_VALID );
    ++  assert( (flags & ~(BTREE_SAVEPOSITION | BTREE_AUXDELETE))==0 );
    + 
    +   iCellDepth = pCur->iPage;
    +-  iCellIdx = pCur->aiIdx[iCellDepth];
    +-  pPage = pCur->apPage[iCellDepth];
    ++  iCellIdx = pCur->ix;
    ++  pPage = pCur->pPage;
    +   pCell = findCell(pPage, iCellIdx);
    + 
    ++  /* If the bPreserve flag is set to true, then the cursor position must
    ++  ** be preserved following this delete operation. If the current delete
    ++  ** will cause a b-tree rebalance, then this is done by saving the cursor
    ++  ** key and leaving the cursor in CURSOR_REQUIRESEEK state before 
    ++  ** returning. 
    ++  **
    ++  ** Or, if the current delete will not cause a rebalance, then the cursor
    ++  ** will be left in CURSOR_SKIPNEXT state pointing to the entry immediately
    ++  ** before or after the deleted entry. In this case set bSkipnext to true.  */
    ++  if( bPreserve ){
    ++    if( !pPage->leaf 
    ++     || (pPage->nFree+cellSizePtr(pPage,pCell)+2)>(int)(pBt->usableSize*2/3)
    ++    ){
    ++      /* A b-tree rebalance will be required after deleting this entry.
    ++      ** Save the cursor key.  */
    ++      rc = saveCursorKey(pCur);
    ++      if( rc ) return rc;
    ++    }else{
    ++      bSkipnext = 1;
    ++    }
    ++  }
    ++
    +   /* If the page containing the entry to delete is not a leaf page, move
    +   ** the cursor to the largest entry in the tree that is smaller than
    +   ** the entry being deleted. This cell will replace the cell being deleted
    +@@ -62615,8 +68844,8 @@ SQLITE_PRIVATE int sqlite3BtreeDelete(BtCursor *pCur, int bPreserve){
    +   ** sub-tree headed by the child page of the cell being deleted. This makes
    +   ** balancing the tree following the delete operation easier.  */
    +   if( !pPage->leaf ){
    +-    int notUsed = 0;
    +-    rc = sqlite3BtreePrevious(pCur, &notUsed);
    ++    rc = sqlite3BtreePrevious(pCur, 0);
    ++    assert( rc!=SQLITE_DONE );
    +     if( rc ) return rc;
    +   }
    + 
    +@@ -62630,29 +68859,7 @@ SQLITE_PRIVATE int sqlite3BtreeDelete(BtCursor *pCur, int bPreserve){
    +   /* If this is a delete operation to remove a row from a table b-tree,
    +   ** invalidate any incrblob cursors open on the row being deleted.  */
    +   if( pCur->pKeyInfo==0 ){
    +-    invalidateIncrblobCursors(p, pCur->info.nKey, 0);
    +-  }
    +-
    +-  /* If the bPreserve flag is set to true, then the cursor position must
    +-  ** be preserved following this delete operation. If the current delete
    +-  ** will cause a b-tree rebalance, then this is done by saving the cursor
    +-  ** key and leaving the cursor in CURSOR_REQUIRESEEK state before 
    +-  ** returning. 
    +-  **
    +-  ** Or, if the current delete will not cause a rebalance, then the cursor
    +-  ** will be left in CURSOR_SKIPNEXT state pointing to the entry immediately
    +-  ** before or after the deleted entry. In this case set bSkipnext to true.  */
    +-  if( bPreserve ){
    +-    if( !pPage->leaf 
    +-     || (pPage->nFree+cellSizePtr(pPage,pCell)+2)>(int)(pBt->usableSize*2/3)
    +-    ){
    +-      /* A b-tree rebalance will be required after deleting this entry.
    +-      ** Save the cursor key.  */
    +-      rc = saveCursorKey(pCur);
    +-      if( rc ) return rc;
    +-    }else{
    +-      bSkipnext = 1;
    +-    }
    ++    invalidateIncrblobCursors(p, pCur->pgnoRoot, pCur->info.nKey, 0);
    +   }
    + 
    +   /* Make the page containing the entry to be deleted writable. Then free any
    +@@ -62660,8 +68867,8 @@ SQLITE_PRIVATE int sqlite3BtreeDelete(BtCursor *pCur, int bPreserve){
    +   ** itself from within the page.  */
    +   rc = sqlite3PagerWrite(pPage->pDbPage);
    +   if( rc ) return rc;
    +-  rc = clearCell(pPage, pCell, &szCell);
    +-  dropCell(pPage, iCellIdx, szCell, &rc);
    ++  rc = clearCell(pPage, pCell, &info);
    ++  dropCell(pPage, iCellIdx, info.nSize, &rc);
    +   if( rc ) return rc;
    + 
    +   /* If the cell deleted was not located on a leaf page, then the cursor
    +@@ -62670,11 +68877,16 @@ SQLITE_PRIVATE int sqlite3BtreeDelete(BtCursor *pCur, int bPreserve){
    +   ** node. The cell from the leaf node needs to be moved to the internal
    +   ** node to replace the deleted cell.  */
    +   if( !pPage->leaf ){
    +-    MemPage *pLeaf = pCur->apPage[pCur->iPage];
    ++    MemPage *pLeaf = pCur->pPage;
    +     int nCell;
    +-    Pgno n = pCur->apPage[iCellDepth+1]->pgno;
    ++    Pgno n;
    +     unsigned char *pTmp;
    + 
    ++    if( iCellDepth<pCur->iPage-1 ){
    ++      n = pCur->apPage[iCellDepth+1]->pgno;
    ++    }else{
    ++      n = pCur->pPage->pgno;
    ++    }
    +     pCell = findCell(pLeaf, pLeaf->nCell-1);
    +     if( pCell<&pLeaf->aData[4] ) return SQLITE_CORRUPT_BKPT;
    +     nCell = pLeaf->xCellSize(pLeaf, pCell);
    +@@ -62682,7 +68894,9 @@ SQLITE_PRIVATE int sqlite3BtreeDelete(BtCursor *pCur, int bPreserve){
    +     pTmp = pBt->pTmpSpace;
    +     assert( pTmp!=0 );
    +     rc = sqlite3PagerWrite(pLeaf->pDbPage);
    +-    insertCell(pPage, iCellIdx, pCell-4, nCell+4, pTmp, n, &rc);
    ++    if( rc==SQLITE_OK ){
    ++      insertCell(pPage, iCellIdx, pCell-4, nCell+4, pTmp, n, &rc);
    ++    }
    +     dropCell(pLeaf, pLeaf->nCell-1, nCell, &rc);
    +     if( rc ) return rc;
    +   }
    +@@ -62704,29 +68918,34 @@ SQLITE_PRIVATE int sqlite3BtreeDelete(BtCursor *pCur, int bPreserve){
    +   ** well.  */
    +   rc = balance(pCur);
    +   if( rc==SQLITE_OK && pCur->iPage>iCellDepth ){
    ++    releasePageNotNull(pCur->pPage);
    ++    pCur->iPage--;
    +     while( pCur->iPage>iCellDepth ){
    +       releasePage(pCur->apPage[pCur->iPage--]);
    +     }
    ++    pCur->pPage = pCur->apPage[pCur->iPage];
    +     rc = balance(pCur);
    +   }
    + 
    +   if( rc==SQLITE_OK ){
    +     if( bSkipnext ){
    +-      assert( bPreserve && pCur->iPage==iCellDepth );
    +-      assert( pPage==pCur->apPage[pCur->iPage] );
    ++      assert( bPreserve && (pCur->iPage==iCellDepth || CORRUPT_DB) );
    ++      assert( pPage==pCur->pPage || CORRUPT_DB );
    +       assert( (pPage->nCell>0 || CORRUPT_DB) && iCellIdx<=pPage->nCell );
    +       pCur->eState = CURSOR_SKIPNEXT;
    +       if( iCellIdx>=pPage->nCell ){
    +         pCur->skipNext = -1;
    +-        pCur->aiIdx[iCellDepth] = pPage->nCell-1;
    ++        pCur->ix = pPage->nCell-1;
    +       }else{
    +         pCur->skipNext = 1;
    +       }
    +     }else{
    +       rc = moveToRoot(pCur);
    +       if( bPreserve ){
    ++        btreeReleaseAllCursorPages(pCur);
    +         pCur->eState = CURSOR_REQUIRESEEK;
    +       }
    ++      if( rc==SQLITE_EMPTY ) rc = SQLITE_OK;
    +     }
    +   }
    +   return rc;
    +@@ -62909,7 +69128,7 @@ static int clearDatabasePage(
    +   unsigned char *pCell;
    +   int i;
    +   int hdr;
    +-  u16 szCell;
    ++  CellInfo info;
    + 
    +   assert( sqlite3_mutex_held(pBt->mutex) );
    +   if( pgno>btreePagecount(pBt) ){
    +@@ -62929,7 +69148,7 @@ static int clearDatabasePage(
    +       rc = clearDatabasePage(pBt, get4byte(pCell), 1, pnChange);
    +       if( rc ) goto cleardatabasepage_out;
    +     }
    +-    rc = clearCell(pPage, pCell, &szCell);
    ++    rc = clearCell(pPage, pCell, &info);
    +     if( rc ) goto cleardatabasepage_out;
    +   }
    +   if( !pPage->leaf ){
    +@@ -62977,7 +69196,7 @@ SQLITE_PRIVATE int sqlite3BtreeClearTable(Btree *p, int iTable, int *pnChange){
    +     /* Invalidate all incrblob cursors open on table iTable (assuming iTable
    +     ** is the root of a table b-tree - if it is not, the following call is
    +     ** a no-op).  */
    +-    invalidateIncrblobCursors(p, 0, 1);
    ++    invalidateIncrblobCursors(p, (Pgno)iTable, 0, 1);
    +     rc = clearDatabasePage(pBt, (Pgno)iTable, 0, pnChange);
    +   }
    +   sqlite3BtreeLeave(p);
    +@@ -63020,19 +69239,7 @@ static int btreeDropTable(Btree *p, Pgno iTable, int *piMoved){
    + 
    +   assert( sqlite3BtreeHoldsMutex(p) );
    +   assert( p->inTrans==TRANS_WRITE );
    +-
    +-  /* It is illegal to drop a table if any cursors are open on the
    +-  ** database. This is because in auto-vacuum mode the backend may
    +-  ** need to move another root-page to fill a gap left by the deleted
    +-  ** root page. If an open cursor was using this page a problem would 
    +-  ** occur.
    +-  **
    +-  ** This error is caught long before control reaches this point.
    +-  */
    +-  if( NEVER(pBt->pCursor) ){
    +-    sqlite3ConnectionBlocked(p->db, pBt->pCursor->pBtree->db);
    +-    return SQLITE_LOCKED_SHAREDCACHE;
    +-  }
    ++  assert( iTable>=2 );
    + 
    +   rc = btreeGetPage(pBt, (Pgno)iTable, &pPage, 0);
    +   if( rc ) return rc;
    +@@ -63044,76 +69251,67 @@ static int btreeDropTable(Btree *p, Pgno iTable, int *piMoved){
    + 
    +   *piMoved = 0;
    + 
    +-  if( iTable>1 ){
    + #ifdef SQLITE_OMIT_AUTOVACUUM
    +-    freePage(pPage, &rc);
    +-    releasePage(pPage);
    ++  freePage(pPage, &rc);
    ++  releasePage(pPage);
    + #else
    +-    if( pBt->autoVacuum ){
    +-      Pgno maxRootPgno;
    +-      sqlite3BtreeGetMeta(p, BTREE_LARGEST_ROOT_PAGE, &maxRootPgno);
    +-
    +-      if( iTable==maxRootPgno ){
    +-        /* If the table being dropped is the table with the largest root-page
    +-        ** number in the database, put the root page on the free list. 
    +-        */
    +-        freePage(pPage, &rc);
    +-        releasePage(pPage);
    +-        if( rc!=SQLITE_OK ){
    +-          return rc;
    +-        }
    +-      }else{
    +-        /* The table being dropped does not have the largest root-page
    +-        ** number in the database. So move the page that does into the 
    +-        ** gap left by the deleted root-page.
    +-        */
    +-        MemPage *pMove;
    +-        releasePage(pPage);
    +-        rc = btreeGetPage(pBt, maxRootPgno, &pMove, 0);
    +-        if( rc!=SQLITE_OK ){
    +-          return rc;
    +-        }
    +-        rc = relocatePage(pBt, pMove, PTRMAP_ROOTPAGE, 0, iTable, 0);
    +-        releasePage(pMove);
    +-        if( rc!=SQLITE_OK ){
    +-          return rc;
    +-        }
    +-        pMove = 0;
    +-        rc = btreeGetPage(pBt, maxRootPgno, &pMove, 0);
    +-        freePage(pMove, &rc);
    +-        releasePage(pMove);
    +-        if( rc!=SQLITE_OK ){
    +-          return rc;
    +-        }
    +-        *piMoved = maxRootPgno;
    +-      }
    ++  if( pBt->autoVacuum ){
    ++    Pgno maxRootPgno;
    ++    sqlite3BtreeGetMeta(p, BTREE_LARGEST_ROOT_PAGE, &maxRootPgno);
    + 
    +-      /* Set the new 'max-root-page' value in the database header. This
    +-      ** is the old value less one, less one more if that happens to
    +-      ** be a root-page number, less one again if that is the
    +-      ** PENDING_BYTE_PAGE.
    ++    if( iTable==maxRootPgno ){
    ++      /* If the table being dropped is the table with the largest root-page
    ++      ** number in the database, put the root page on the free list. 
    +       */
    +-      maxRootPgno--;
    +-      while( maxRootPgno==PENDING_BYTE_PAGE(pBt)
    +-             || PTRMAP_ISPAGE(pBt, maxRootPgno) ){
    +-        maxRootPgno--;
    ++      freePage(pPage, &rc);
    ++      releasePage(pPage);
    ++      if( rc!=SQLITE_OK ){
    ++        return rc;
    +       }
    +-      assert( maxRootPgno!=PENDING_BYTE_PAGE(pBt) );
    +-
    +-      rc = sqlite3BtreeUpdateMeta(p, 4, maxRootPgno);
    +     }else{
    +-      freePage(pPage, &rc);
    ++      /* The table being dropped does not have the largest root-page
    ++      ** number in the database. So move the page that does into the 
    ++      ** gap left by the deleted root-page.
    ++      */
    ++      MemPage *pMove;
    +       releasePage(pPage);
    ++      rc = btreeGetPage(pBt, maxRootPgno, &pMove, 0);
    ++      if( rc!=SQLITE_OK ){
    ++        return rc;
    ++      }
    ++      rc = relocatePage(pBt, pMove, PTRMAP_ROOTPAGE, 0, iTable, 0);
    ++      releasePage(pMove);
    ++      if( rc!=SQLITE_OK ){
    ++        return rc;
    ++      }
    ++      pMove = 0;
    ++      rc = btreeGetPage(pBt, maxRootPgno, &pMove, 0);
    ++      freePage(pMove, &rc);
    ++      releasePage(pMove);
    ++      if( rc!=SQLITE_OK ){
    ++        return rc;
    ++      }
    ++      *piMoved = maxRootPgno;
    +     }
    +-#endif
    +-  }else{
    +-    /* If sqlite3BtreeDropTable was called on page 1.
    +-    ** This really never should happen except in a corrupt
    +-    ** database. 
    ++
    ++    /* Set the new 'max-root-page' value in the database header. This
    ++    ** is the old value less one, less one more if that happens to
    ++    ** be a root-page number, less one again if that is the
    ++    ** PENDING_BYTE_PAGE.
    +     */
    +-    zeroPage(pPage, PTF_INTKEY|PTF_LEAF );
    ++    maxRootPgno--;
    ++    while( maxRootPgno==PENDING_BYTE_PAGE(pBt)
    ++           || PTRMAP_ISPAGE(pBt, maxRootPgno) ){
    ++      maxRootPgno--;
    ++    }
    ++    assert( maxRootPgno!=PENDING_BYTE_PAGE(pBt) );
    ++
    ++    rc = sqlite3BtreeUpdateMeta(p, 4, maxRootPgno);
    ++  }else{
    ++    freePage(pPage, &rc);
    +     releasePage(pPage);
    +   }
    ++#endif
    +   return rc;  
    + }
    + SQLITE_PRIVATE int sqlite3BtreeDropTable(Btree *p, int iTable, int *piMoved){
    +@@ -63212,11 +69410,11 @@ SQLITE_PRIVATE int sqlite3BtreeCount(BtCursor *pCur, i64 *pnEntry){
    +   i64 nEntry = 0;                      /* Value to return in *pnEntry */
    +   int rc;                              /* Return code */
    + 
    +-  if( pCur->pgnoRoot==0 ){
    ++  rc = moveToRoot(pCur);
    ++  if( rc==SQLITE_EMPTY ){
    +     *pnEntry = 0;
    +     return SQLITE_OK;
    +   }
    +-  rc = moveToRoot(pCur);
    + 
    +   /* Unless an error occurs, the following loop runs one iteration for each
    +   ** page in the B-Tree structure (not including overflow pages). 
    +@@ -63229,7 +69427,7 @@ SQLITE_PRIVATE int sqlite3BtreeCount(BtCursor *pCur, i64 *pnEntry){
    +     ** this page contains countable entries. Increment the entry counter
    +     ** accordingly.
    +     */
    +-    pPage = pCur->apPage[pCur->iPage];
    ++    pPage = pCur->pPage;
    +     if( pPage->leaf || !pPage->intKey ){
    +       nEntry += pPage->nCell;
    +     }
    +@@ -63252,16 +69450,16 @@ SQLITE_PRIVATE int sqlite3BtreeCount(BtCursor *pCur, i64 *pnEntry){
    +           return moveToRoot(pCur);
    +         }
    +         moveToParent(pCur);
    +-      }while ( pCur->aiIdx[pCur->iPage]>=pCur->apPage[pCur->iPage]->nCell );
    ++      }while ( pCur->ix>=pCur->pPage->nCell );
    + 
    +-      pCur->aiIdx[pCur->iPage]++;
    +-      pPage = pCur->apPage[pCur->iPage];
    ++      pCur->ix++;
    ++      pPage = pCur->pPage;
    +     }
    + 
    +     /* Descend to the child node of the cell that the cursor currently 
    +     ** points at. This is the right-child if (iIdx==pPage->nCell).
    +     */
    +-    iIdx = pCur->aiIdx[pCur->iPage];
    ++    iIdx = pCur->ix;
    +     if( iIdx==pPage->nCell ){
    +       rc = moveToChild(pCur, get4byte(&pPage->aData[pPage->hdrOffset+8]));
    +     }else{
    +@@ -63300,9 +69498,9 @@ static void checkAppendMsg(
    +     sqlite3StrAccumAppend(&pCheck->errMsg, "\n", 1);
    +   }
    +   if( pCheck->zPfx ){
    +-    sqlite3XPrintf(&pCheck->errMsg, 0, pCheck->zPfx, pCheck->v1, pCheck->v2);
    ++    sqlite3XPrintf(&pCheck->errMsg, pCheck->zPfx, pCheck->v1, pCheck->v2);
    +   }
    +-  sqlite3VXPrintf(&pCheck->errMsg, 1, zFormat, ap);
    ++  sqlite3VXPrintf(&pCheck->errMsg, zFormat, ap);
    +   va_end(ap);
    +   if( pCheck->errMsg.accError==STRACCUM_NOMEM ){
    +     pCheck->mallocFailed = 1;
    +@@ -63406,7 +69604,7 @@ static void checkList(
    +       break;
    +     }
    +     if( checkRef(pCheck, iPage) ) break;
    +-    if( sqlite3PagerGet(pCheck->pPager, (Pgno)iPage, &pOvflPage) ){
    ++    if( sqlite3PagerGet(pCheck->pPager, (Pgno)iPage, &pOvflPage, 0) ){
    +       checkAppendMsg(pCheck, "failed to get page %d", iPage);
    +       break;
    +     }
    +@@ -63646,15 +69844,16 @@ static int checkTreePage(
    +         checkAppendMsg(pCheck, "Rowid %lld out of order", info.nKey);
    +       }
    +       maxKey = info.nKey;
    ++      keyCanBeEqual = 0;     /* Only the first key on the page may ==maxKey */
    +     }
    + 
    +     /* Check the content overflow list */
    +     if( info.nPayload>info.nLocal ){
    +       int nPage;       /* Number of pages on the overflow chain */
    +       Pgno pgnoOvfl;   /* First page of the overflow chain */
    +-      assert( pc + info.iOverflow <= usableSize );
    ++      assert( pc + info.nSize - 4 <= usableSize );
    +       nPage = (info.nPayload - info.nLocal + usableSize - 5)/(usableSize - 4);
    +-      pgnoOvfl = get4byte(&pCell[info.iOverflow]);
    ++      pgnoOvfl = get4byte(&pCell[info.nSize - 4]);
    + #ifndef SQLITE_OMIT_AUTOVACUUM
    +       if( pBt->autoVacuum ){
    +         checkPtrmap(pCheck, pgnoOvfl, PTRMAP_OVERFLOW1, iPage);
    +@@ -63803,7 +70002,8 @@ SQLITE_PRIVATE char *sqlite3BtreeIntegrityCheck(
    + 
    +   sqlite3BtreeEnter(p);
    +   assert( p->inTrans>TRANS_NONE && pBt->inTransaction>TRANS_NONE );
    +-  assert( (nRef = sqlite3PagerRefcount(pBt->pPager))>=0 );
    ++  VVA_ONLY( nRef = sqlite3PagerRefcount(pBt->pPager) );
    ++  assert( nRef>=0 );
    +   sCheck.pBt = pBt;
    +   sCheck.pPager = pBt->pPager;
    +   sCheck.nPage = btreePagecount(sCheck.pBt);
    +@@ -63816,6 +70016,7 @@ SQLITE_PRIVATE char *sqlite3BtreeIntegrityCheck(
    +   sCheck.aPgRef = 0;
    +   sCheck.heap = 0;
    +   sqlite3StrAccumInit(&sCheck.errMsg, 0, zErr, sizeof(zErr), SQLITE_MAX_LENGTH);
    ++  sCheck.errMsg.printfFlags = SQLITE_PRINTF_INTERNAL;
    +   if( sCheck.nPage==0 ){
    +     goto integrity_ck_cleanup;
    +   }
    +@@ -63947,7 +70148,7 @@ SQLITE_PRIVATE int sqlite3BtreeCheckpoint(Btree *p, int eMode, int *pnLog, int *
    +     if( pBt->inTransaction!=TRANS_NONE ){
    +       rc = SQLITE_LOCKED;
    +     }else{
    +-      rc = sqlite3PagerCheckpoint(pBt->pPager, eMode, pnLog, pnCkpt);
    ++      rc = sqlite3PagerCheckpoint(pBt->pPager, p->db, eMode, pnLog, pnCkpt);
    +     }
    +     sqlite3BtreeLeave(p);
    +   }
    +@@ -64055,7 +70256,7 @@ SQLITE_PRIVATE int sqlite3BtreeLockTable(Btree *p, int iTab, u8 isWriteLock){
    + */
    + SQLITE_PRIVATE int sqlite3BtreePutData(BtCursor *pCsr, u32 offset, u32 amt, void *z){
    +   int rc;
    +-  assert( cursorHoldsMutex(pCsr) );
    ++  assert( cursorOwnsBtShared(pCsr) );
    +   assert( sqlite3_mutex_held(pCsr->pBtree->db->mutex) );
    +   assert( pCsr->curFlags & BTCF_Incrblob );
    + 
    +@@ -64093,7 +70294,7 @@ SQLITE_PRIVATE int sqlite3BtreePutData(BtCursor *pCsr, u32 offset, u32 amt, void
    +               && pCsr->pBt->inTransaction==TRANS_WRITE );
    +   assert( hasSharedCacheTableLock(pCsr->pBtree, pCsr->pgnoRoot, 0, 2) );
    +   assert( !hasReadConflicts(pCsr->pBtree, pCsr->pgnoRoot) );
    +-  assert( pCsr->apPage[pCsr->iPage]->intKey );
    ++  assert( pCsr->pPage->intKey );
    + 
    +   return accessPayload(pCsr, offset, amt, (unsigned char *)z, 1);
    + }
    +@@ -64143,15 +70344,6 @@ SQLITE_PRIVATE int sqlite3BtreeSetVersion(Btree *pBtree, int iVersion){
    +   return rc;
    + }
    + 
    +-/*
    +-** set the mask of hint flags for cursor pCsr.
    +-*/
    +-SQLITE_PRIVATE void sqlite3BtreeCursorHints(BtCursor *pCsr, unsigned int mask){
    +-  assert( mask==BTREE_BULKLOAD || mask==BTREE_SEEK_EQ || mask==0 );
    +-  pCsr->hints = mask;
    +-}
    +-
    +-#ifdef SQLITE_DEBUG
    + /*
    + ** Return true if the cursor has a hint specified.  This routine is
    + ** only used from within assert() statements
    +@@ -64159,7 +70351,6 @@ SQLITE_PRIVATE void sqlite3BtreeCursorHints(BtCursor *pCsr, unsigned int mask){
    + SQLITE_PRIVATE int sqlite3BtreeCursorHasHint(BtCursor *pCsr, unsigned int mask){
    +   return (pCsr->hints & mask)!=0;
    + }
    +-#endif
    + 
    + /*
    + ** Return true if the given Btree is read-only.
    +@@ -64173,6 +70364,25 @@ SQLITE_PRIVATE int sqlite3BtreeIsReadonly(Btree *p){
    + */
    + SQLITE_PRIVATE int sqlite3HeaderSizeBtree(void){ return ROUND8(sizeof(MemPage)); }
    + 
    ++#if !defined(SQLITE_OMIT_SHARED_CACHE)
    ++/*
    ++** Return true if the Btree passed as the only argument is sharable.
    ++*/
    ++SQLITE_PRIVATE int sqlite3BtreeSharable(Btree *p){
    ++  return p->sharable;
    ++}
    ++
    ++/*
    ++** Return the number of connections to the BtShared object accessed by
    ++** the Btree handle passed as the only argument. For private caches 
    ++** this is always 1. For shared caches it may be 1 or greater.
    ++*/
    ++SQLITE_PRIVATE int sqlite3BtreeConnectionCount(Btree *p){
    ++  testcase( p->sharable );
    ++  return p->pBt->nRef;
    ++}
    ++#endif
    ++
    + /************** End of btree.c ***********************************************/
    + /************** Begin file backup.c ******************************************/
    + /*
    +@@ -64260,22 +70470,16 @@ static Btree *findBtree(sqlite3 *pErrorDb, sqlite3 *pDb, const char *zDb){
    +   int i = sqlite3FindDbName(pDb, zDb);
    + 
    +   if( i==1 ){
    +-    Parse *pParse;
    ++    Parse sParse;
    +     int rc = 0;
    +-    pParse = sqlite3StackAllocZero(pErrorDb, sizeof(*pParse));
    +-    if( pParse==0 ){
    +-      sqlite3ErrorWithMsg(pErrorDb, SQLITE_NOMEM, "out of memory");
    +-      rc = SQLITE_NOMEM;
    +-    }else{
    +-      pParse->db = pDb;
    +-      if( sqlite3OpenTempDatabase(pParse) ){
    +-        sqlite3ErrorWithMsg(pErrorDb, pParse->rc, "%s", pParse->zErrMsg);
    +-        rc = SQLITE_ERROR;
    +-      }
    +-      sqlite3DbFree(pErrorDb, pParse->zErrMsg);
    +-      sqlite3ParserReset(pParse);
    +-      sqlite3StackFree(pErrorDb, pParse);
    ++    memset(&sParse, 0, sizeof(sParse));
    ++    sParse.db = pDb;
    ++    if( sqlite3OpenTempDatabase(&sParse) ){
    ++      sqlite3ErrorWithMsg(pErrorDb, sParse.rc, "%s", sParse.zErrMsg);
    ++      rc = SQLITE_ERROR;
    +     }
    ++    sqlite3DbFree(pErrorDb, sParse.zErrMsg);
    ++    sqlite3ParserReset(&sParse);
    +     if( rc ){
    +       return 0;
    +     }
    +@@ -64321,7 +70525,7 @@ static int checkReadTransaction(sqlite3 *db, Btree *p){
    + ** If an error occurs, NULL is returned and an error code and error message
    + ** stored in database handle pDestDb.
    + */
    +-SQLITE_API sqlite3_backup *SQLITE_STDCALL sqlite3_backup_init(
    ++SQLITE_API sqlite3_backup *sqlite3_backup_init(
    +   sqlite3* pDestDb,                     /* Database to write to */
    +   const char *zDestDb,                  /* Name of database within pDestDb */
    +   sqlite3* pSrcDb,                      /* Database connection to read from */
    +@@ -64359,7 +70563,7 @@ SQLITE_API sqlite3_backup *SQLITE_STDCALL sqlite3_backup_init(
    +     ** sqlite3_backup_finish(). */
    +     p = (sqlite3_backup *)sqlite3MallocZero(sizeof(sqlite3_backup));
    +     if( !p ){
    +-      sqlite3Error(pDestDb, SQLITE_NOMEM);
    ++      sqlite3Error(pDestDb, SQLITE_NOMEM_BKPT);
    +     }
    +   }
    + 
    +@@ -64373,7 +70577,6 @@ SQLITE_API sqlite3_backup *SQLITE_STDCALL sqlite3_backup_init(
    +     p->isAttached = 0;
    + 
    +     if( 0==p->pSrc || 0==p->pDest 
    +-     || setDestPgsz(p)==SQLITE_NOMEM 
    +      || checkReadTransaction(pDestDb, p->pDest)!=SQLITE_OK 
    +      ){
    +       /* One (or both) of the named databases did not exist or an OOM
    +@@ -64470,7 +70673,7 @@ static int backupOnePage(
    +     DbPage *pDestPg = 0;
    +     Pgno iDest = (Pgno)(iOff/nDestPgsz)+1;
    +     if( iDest==PENDING_BYTE_PAGE(p->pDest->pBt) ) continue;
    +-    if( SQLITE_OK==(rc = sqlite3PagerGet(pDestPager, iDest, &pDestPg))
    ++    if( SQLITE_OK==(rc = sqlite3PagerGet(pDestPager, iDest, &pDestPg, 0))
    +      && SQLITE_OK==(rc = sqlite3PagerWrite(pDestPg))
    +     ){
    +       const u8 *zIn = &zSrcData[iOff%nSrcPgsz];
    +@@ -64529,7 +70732,7 @@ static void attachBackupObject(sqlite3_backup *p){
    + /*
    + ** Copy nPage pages from the source b-tree to the destination.
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_backup_step(sqlite3_backup *p, int nPage){
    ++SQLITE_API int sqlite3_backup_step(sqlite3_backup *p, int nPage){
    +   int rc;
    +   int destMode;       /* Destination journal mode */
    +   int pgszSrc = 0;    /* Source page size */
    +@@ -64561,14 +70764,6 @@ SQLITE_API int SQLITE_STDCALL sqlite3_backup_step(sqlite3_backup *p, int nPage){
    +       rc = SQLITE_OK;
    +     }
    + 
    +-    /* Lock the destination database, if it is not locked already. */
    +-    if( SQLITE_OK==rc && p->bDestLocked==0
    +-     && SQLITE_OK==(rc = sqlite3BtreeBeginTrans(p->pDest, 2)) 
    +-    ){
    +-      p->bDestLocked = 1;
    +-      sqlite3BtreeGetMeta(p->pDest, BTREE_SCHEMA_VERSION, &p->iDestSchema);
    +-    }
    +-
    +     /* If there is no open read-transaction on the source database, open
    +     ** one now. If a transaction is opened here, then it will be closed
    +     ** before this function exits.
    +@@ -64578,6 +70773,24 @@ SQLITE_API int SQLITE_STDCALL sqlite3_backup_step(sqlite3_backup *p, int nPage){
    +       bCloseTrans = 1;
    +     }
    + 
    ++    /* If the destination database has not yet been locked (i.e. if this
    ++    ** is the first call to backup_step() for the current backup operation),
    ++    ** try to set its page size to the same as the source database. This
    ++    ** is especially important on ZipVFS systems, as in that case it is
    ++    ** not possible to create a database file that uses one page size by
    ++    ** writing to it with another.  */
    ++    if( p->bDestLocked==0 && rc==SQLITE_OK && setDestPgsz(p)==SQLITE_NOMEM ){
    ++      rc = SQLITE_NOMEM;
    ++    }
    ++
    ++    /* Lock the destination database, if it is not locked already. */
    ++    if( SQLITE_OK==rc && p->bDestLocked==0
    ++     && SQLITE_OK==(rc = sqlite3BtreeBeginTrans(p->pDest, 2)) 
    ++    ){
    ++      p->bDestLocked = 1;
    ++      sqlite3BtreeGetMeta(p->pDest, BTREE_SCHEMA_VERSION, &p->iDestSchema);
    ++    }
    ++
    +     /* Do not allow backup if the destination database is in WAL mode
    +     ** and the page sizes are different between source and destination */
    +     pgszSrc = sqlite3BtreeGetPageSize(p->pSrc);
    +@@ -64596,8 +70809,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_backup_step(sqlite3_backup *p, int nPage){
    +       const Pgno iSrcPg = p->iNext;                 /* Source page number */
    +       if( iSrcPg!=PENDING_BYTE_PAGE(p->pSrc->pBt) ){
    +         DbPage *pSrcPg;                             /* Source page object */
    +-        rc = sqlite3PagerAcquire(pSrcPager, iSrcPg, &pSrcPg,
    +-                                 PAGER_GET_READONLY);
    ++        rc = sqlite3PagerGet(pSrcPager, iSrcPg, &pSrcPg,PAGER_GET_READONLY);
    +         if( rc==SQLITE_OK ){
    +           rc = backupOnePage(p, iSrcPg, sqlite3PagerGetData(pSrcPg), 0);
    +           sqlite3PagerUnref(pSrcPg);
    +@@ -64697,7 +70909,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_backup_step(sqlite3_backup *p, int nPage){
    +           for(iPg=nDestTruncate; rc==SQLITE_OK && iPg<=(Pgno)nDstPage; iPg++){
    +             if( iPg!=PENDING_BYTE_PAGE(p->pDest->pBt) ){
    +               DbPage *pPg;
    +-              rc = sqlite3PagerGet(pDestPager, iPg, &pPg);
    ++              rc = sqlite3PagerGet(pDestPager, iPg, &pPg, 0);
    +               if( rc==SQLITE_OK ){
    +                 rc = sqlite3PagerWrite(pPg);
    +                 sqlite3PagerUnref(pPg);
    +@@ -64717,7 +70929,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_backup_step(sqlite3_backup *p, int nPage){
    +           ){
    +             PgHdr *pSrcPg = 0;
    +             const Pgno iSrcPg = (Pgno)((iOff/pgszSrc)+1);
    +-            rc = sqlite3PagerGet(pSrcPager, iSrcPg, &pSrcPg);
    ++            rc = sqlite3PagerGet(pSrcPager, iSrcPg, &pSrcPg, 0);
    +             if( rc==SQLITE_OK ){
    +               u8 *zData = sqlite3PagerGetData(pSrcPg);
    +               rc = sqlite3OsWrite(pFile, zData, pgszSrc, iOff);
    +@@ -64759,7 +70971,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_backup_step(sqlite3_backup *p, int nPage){
    +     }
    +   
    +     if( rc==SQLITE_IOERR_NOMEM ){
    +-      rc = SQLITE_NOMEM;
    ++      rc = SQLITE_NOMEM_BKPT;
    +     }
    +     p->rc = rc;
    +   }
    +@@ -64774,7 +70986,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_backup_step(sqlite3_backup *p, int nPage){
    + /*
    + ** Release all resources associated with an sqlite3_backup* handle.
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_backup_finish(sqlite3_backup *p){
    ++SQLITE_API int sqlite3_backup_finish(sqlite3_backup *p){
    +   sqlite3_backup **pp;                 /* Ptr to head of pagers backup list */
    +   sqlite3 *pSrcDb;                     /* Source database connection */
    +   int rc;                              /* Value to return */
    +@@ -64826,7 +71038,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_backup_finish(sqlite3_backup *p){
    + ** Return the number of pages still to be backed up as of the most recent
    + ** call to sqlite3_backup_step().
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_backup_remaining(sqlite3_backup *p){
    ++SQLITE_API int sqlite3_backup_remaining(sqlite3_backup *p){
    + #ifdef SQLITE_ENABLE_API_ARMOR
    +   if( p==0 ){
    +     (void)SQLITE_MISUSE_BKPT;
    +@@ -64840,7 +71052,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_backup_remaining(sqlite3_backup *p){
    + ** Return the total number of pages in the source database as of the most 
    + ** recent call to sqlite3_backup_step().
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_backup_pagecount(sqlite3_backup *p){
    ++SQLITE_API int sqlite3_backup_pagecount(sqlite3_backup *p){
    + #ifdef SQLITE_ENABLE_API_ARMOR
    +   if( p==0 ){
    +     (void)SQLITE_MISUSE_BKPT;
    +@@ -64955,10 +71167,10 @@ SQLITE_PRIVATE int sqlite3BtreeCopyFile(Btree *pTo, Btree *pFrom){
    +   ** sqlite3_backup_step(), we can guarantee that the copy finishes 
    +   ** within a single call (unless an error occurs). The assert() statement
    +   ** checks this assumption - (p->rc) should be set to either SQLITE_DONE 
    +-  ** or an error code.
    +-  */
    ++  ** or an error code.  */
    +   sqlite3_backup_step(&b, 0x7FFFFFFF);
    +   assert( b.rc!=SQLITE_OK );
    ++
    +   rc = sqlite3_backup_finish(&b);
    +   if( rc==SQLITE_OK ){
    +     pTo->pBt->btsFlags &= ~BTS_PAGESIZE_FIXED;
    +@@ -65005,7 +71217,7 @@ copy_finished:
    + */
    + SQLITE_PRIVATE int sqlite3VdbeCheckMemInvariants(Mem *p){
    +   /* If MEM_Dyn is set then Mem.xDel!=0.  
    +-  ** Mem.xDel is might not be initialized if MEM_Dyn is clear.
    ++  ** Mem.xDel might not be initialized if MEM_Dyn is clear.
    +   */
    +   assert( (p->flags & MEM_Dyn)==0 || p->xDel!=0 );
    + 
    +@@ -65018,6 +71230,35 @@ SQLITE_PRIVATE int sqlite3VdbeCheckMemInvariants(Mem *p){
    +   /* Cannot be both MEM_Int and MEM_Real at the same time */
    +   assert( (p->flags & (MEM_Int|MEM_Real))!=(MEM_Int|MEM_Real) );
    + 
    ++  if( p->flags & MEM_Null ){
    ++    /* Cannot be both MEM_Null and some other type */
    ++    assert( (p->flags & (MEM_Int|MEM_Real|MEM_Str|MEM_Blob
    ++                         |MEM_RowSet|MEM_Frame|MEM_Agg))==0 );
    ++
    ++    /* If MEM_Null is set, then either the value is a pure NULL (the usual
    ++    ** case) or it is a pointer set using sqlite3_bind_pointer() or
    ++    ** sqlite3_result_pointer().  If a pointer, then MEM_Term must also be
    ++    ** set.
    ++    */
    ++    if( (p->flags & (MEM_Term|MEM_Subtype))==(MEM_Term|MEM_Subtype) ){
    ++      /* This is a pointer type.  There may be a flag to indicate what to
    ++      ** do with the pointer. */
    ++      assert( ((p->flags&MEM_Dyn)!=0 ? 1 : 0) +
    ++              ((p->flags&MEM_Ephem)!=0 ? 1 : 0) +
    ++              ((p->flags&MEM_Static)!=0 ? 1 : 0) <= 1 );
    ++
    ++      /* No other bits set */
    ++      assert( (p->flags & ~(MEM_Null|MEM_Term|MEM_Subtype
    ++                           |MEM_Dyn|MEM_Ephem|MEM_Static))==0 );
    ++    }else{
    ++      /* A pure NULL might have other flags, such as MEM_Static, MEM_Dyn,
    ++      ** MEM_Ephem, MEM_Cleared, or MEM_Subtype */
    ++    }
    ++  }else{
    ++    /* The MEM_Cleared bit is only allowed on NULLs */
    ++    assert( (p->flags & MEM_Cleared)==0 );
    ++  }
    ++
    +   /* The szMalloc field holds the correct memory allocation size */
    +   assert( p->szMalloc==0
    +        || p->szMalloc==sqlite3DbMallocSize(p->db,p->zMalloc) );
    +@@ -65094,6 +71335,7 @@ SQLITE_PRIVATE int sqlite3VdbeChangeEncoding(Mem *pMem, int desiredEnc){
    + SQLITE_PRIVATE SQLITE_NOINLINE int sqlite3VdbeMemGrow(Mem *pMem, int n, int bPreserve){
    +   assert( sqlite3VdbeCheckMemInvariants(pMem) );
    +   assert( (pMem->flags&MEM_RowSet)==0 );
    ++  testcase( pMem->db==0 );
    + 
    +   /* If the bPreserve flag is set to true, then the memory cell must already
    +   ** contain a valid string or blob value.  */
    +@@ -65102,26 +71344,25 @@ SQLITE_PRIVATE SQLITE_NOINLINE int sqlite3VdbeMemGrow(Mem *pMem, int n, int bPre
    + 
    +   assert( pMem->szMalloc==0
    +        || pMem->szMalloc==sqlite3DbMallocSize(pMem->db, pMem->zMalloc) );
    +-  if( pMem->szMalloc<n ){
    +-    if( n<32 ) n = 32;
    +-    if( bPreserve && pMem->szMalloc>0 && pMem->z==pMem->zMalloc ){
    +-      pMem->z = pMem->zMalloc = sqlite3DbReallocOrFree(pMem->db, pMem->z, n);
    +-      bPreserve = 0;
    +-    }else{
    +-      if( pMem->szMalloc>0 ) sqlite3DbFree(pMem->db, pMem->zMalloc);
    +-      pMem->zMalloc = sqlite3DbMallocRaw(pMem->db, n);
    +-    }
    +-    if( pMem->zMalloc==0 ){
    +-      sqlite3VdbeMemSetNull(pMem);
    +-      pMem->z = 0;
    +-      pMem->szMalloc = 0;
    +-      return SQLITE_NOMEM;
    +-    }else{
    +-      pMem->szMalloc = sqlite3DbMallocSize(pMem->db, pMem->zMalloc);
    +-    }
    ++  if( n<32 ) n = 32;
    ++  if( pMem->szMalloc>0 && bPreserve && pMem->z==pMem->zMalloc ){
    ++    pMem->z = pMem->zMalloc = sqlite3DbReallocOrFree(pMem->db, pMem->z, n);
    ++    bPreserve = 0;
    ++  }else{
    ++    if( pMem->szMalloc>0 ) sqlite3DbFreeNN(pMem->db, pMem->zMalloc);
    ++    pMem->zMalloc = sqlite3DbMallocRaw(pMem->db, n);
    ++  }
    ++  if( pMem->zMalloc==0 ){
    ++    sqlite3VdbeMemSetNull(pMem);
    ++    pMem->z = 0;
    ++    pMem->szMalloc = 0;
    ++    return SQLITE_NOMEM_BKPT;
    ++  }else{
    ++    pMem->szMalloc = sqlite3DbMallocSize(pMem->db, pMem->zMalloc);
    +   }
    + 
    +-  if( bPreserve && pMem->z && pMem->z!=pMem->zMalloc ){
    ++  if( bPreserve && pMem->z ){
    ++    assert( pMem->z!=pMem->zMalloc );
    +     memcpy(pMem->zMalloc, pMem->z, pMem->n);
    +   }
    +   if( (pMem->flags&MEM_Dyn)!=0 ){
    +@@ -65159,6 +71400,20 @@ SQLITE_PRIVATE int sqlite3VdbeMemClearAndResize(Mem *pMem, int szNew){
    +   return SQLITE_OK;
    + }
    + 
    ++/*
    ++** It is already known that pMem contains an unterminated string.
    ++** Add the zero terminator.
    ++*/
    ++static SQLITE_NOINLINE int vdbeMemAddTerminator(Mem *pMem){
    ++  if( sqlite3VdbeMemGrow(pMem, pMem->n+2, 1) ){
    ++    return SQLITE_NOMEM_BKPT;
    ++  }
    ++  pMem->z[pMem->n] = 0;
    ++  pMem->z[pMem->n+1] = 0;
    ++  pMem->flags |= MEM_Term;
    ++  return SQLITE_OK;
    ++}
    ++
    + /*
    + ** Change pMem so that its MEM_Str or MEM_Blob value is stored in
    + ** MEM.zMalloc, where it can be safely written.
    +@@ -65166,18 +71421,14 @@ SQLITE_PRIVATE int sqlite3VdbeMemClearAndResize(Mem *pMem, int szNew){
    + ** Return SQLITE_OK on success or SQLITE_NOMEM if malloc fails.
    + */
    + SQLITE_PRIVATE int sqlite3VdbeMemMakeWriteable(Mem *pMem){
    +-  int f;
    +   assert( pMem->db==0 || sqlite3_mutex_held(pMem->db->mutex) );
    +   assert( (pMem->flags&MEM_RowSet)==0 );
    +-  ExpandBlob(pMem);
    +-  f = pMem->flags;
    +-  if( (f&(MEM_Str|MEM_Blob)) && (pMem->szMalloc==0 || pMem->z!=pMem->zMalloc) ){
    +-    if( sqlite3VdbeMemGrow(pMem, pMem->n + 2, 1) ){
    +-      return SQLITE_NOMEM;
    ++  if( (pMem->flags & (MEM_Str|MEM_Blob))!=0 ){
    ++    if( ExpandBlob(pMem) ) return SQLITE_NOMEM;
    ++    if( pMem->szMalloc==0 || pMem->z!=pMem->zMalloc ){
    ++      int rc = vdbeMemAddTerminator(pMem);
    ++      if( rc ) return rc;
    +     }
    +-    pMem->z[pMem->n] = 0;
    +-    pMem->z[pMem->n+1] = 0;
    +-    pMem->flags |= MEM_Term;
    +   }
    +   pMem->flags &= ~MEM_Ephem;
    + #ifdef SQLITE_DEBUG
    +@@ -65193,42 +71444,27 @@ SQLITE_PRIVATE int sqlite3VdbeMemMakeWriteable(Mem *pMem){
    + */
    + #ifndef SQLITE_OMIT_INCRBLOB
    + SQLITE_PRIVATE int sqlite3VdbeMemExpandBlob(Mem *pMem){
    +-  if( pMem->flags & MEM_Zero ){
    +-    int nByte;
    +-    assert( pMem->flags&MEM_Blob );
    +-    assert( (pMem->flags&MEM_RowSet)==0 );
    +-    assert( pMem->db==0 || sqlite3_mutex_held(pMem->db->mutex) );
    +-
    +-    /* Set nByte to the number of bytes required to store the expanded blob. */
    +-    nByte = pMem->n + pMem->u.nZero;
    +-    if( nByte<=0 ){
    +-      nByte = 1;
    +-    }
    +-    if( sqlite3VdbeMemGrow(pMem, nByte, 1) ){
    +-      return SQLITE_NOMEM;
    +-    }
    ++  int nByte;
    ++  assert( pMem->flags & MEM_Zero );
    ++  assert( pMem->flags&MEM_Blob );
    ++  assert( (pMem->flags&MEM_RowSet)==0 );
    ++  assert( pMem->db==0 || sqlite3_mutex_held(pMem->db->mutex) );
    + 
    +-    memset(&pMem->z[pMem->n], 0, pMem->u.nZero);
    +-    pMem->n += pMem->u.nZero;
    +-    pMem->flags &= ~(MEM_Zero|MEM_Term);
    ++  /* Set nByte to the number of bytes required to store the expanded blob. */
    ++  nByte = pMem->n + pMem->u.nZero;
    ++  if( nByte<=0 ){
    ++    nByte = 1;
    +   }
    +-  return SQLITE_OK;
    +-}
    +-#endif
    +-
    +-/*
    +-** It is already known that pMem contains an unterminated string.
    +-** Add the zero terminator.
    +-*/
    +-static SQLITE_NOINLINE int vdbeMemAddTerminator(Mem *pMem){
    +-  if( sqlite3VdbeMemGrow(pMem, pMem->n+2, 1) ){
    +-    return SQLITE_NOMEM;
    ++  if( sqlite3VdbeMemGrow(pMem, nByte, 1) ){
    ++    return SQLITE_NOMEM_BKPT;
    +   }
    +-  pMem->z[pMem->n] = 0;
    +-  pMem->z[pMem->n+1] = 0;
    +-  pMem->flags |= MEM_Term;
    ++
    ++  memset(&pMem->z[pMem->n], 0, pMem->u.nZero);
    ++  pMem->n += pMem->u.nZero;
    ++  pMem->flags &= ~(MEM_Zero|MEM_Term);
    +   return SQLITE_OK;
    + }
    ++#endif
    + 
    + /*
    + ** Make sure the given Mem is \u0000 terminated.
    +@@ -65271,7 +71507,8 @@ SQLITE_PRIVATE int sqlite3VdbeMemStringify(Mem *pMem, u8 enc, u8 bForce){
    + 
    + 
    +   if( sqlite3VdbeMemClearAndResize(pMem, nByte) ){
    +-    return SQLITE_NOMEM;
    ++    pMem->enc = 0;
    ++    return SQLITE_NOMEM_BKPT;
    +   }
    + 
    +   /* For a Real or Integer, use sqlite3_snprintf() to produce the UTF-8
    +@@ -65303,26 +71540,24 @@ SQLITE_PRIVATE int sqlite3VdbeMemStringify(Mem *pMem, u8 enc, u8 bForce){
    + ** otherwise.
    + */
    + SQLITE_PRIVATE int sqlite3VdbeMemFinalize(Mem *pMem, FuncDef *pFunc){
    +-  int rc = SQLITE_OK;
    +-  if( ALWAYS(pFunc && pFunc->xFinalize) ){
    +-    sqlite3_context ctx;
    +-    Mem t;
    +-    assert( (pMem->flags & MEM_Null)!=0 || pFunc==pMem->u.pDef );
    +-    assert( pMem->db==0 || sqlite3_mutex_held(pMem->db->mutex) );
    +-    memset(&ctx, 0, sizeof(ctx));
    +-    memset(&t, 0, sizeof(t));
    +-    t.flags = MEM_Null;
    +-    t.db = pMem->db;
    +-    ctx.pOut = &t;
    +-    ctx.pMem = pMem;
    +-    ctx.pFunc = pFunc;
    +-    pFunc->xFinalize(&ctx); /* IMP: R-24505-23230 */
    +-    assert( (pMem->flags & MEM_Dyn)==0 );
    +-    if( pMem->szMalloc>0 ) sqlite3DbFree(pMem->db, pMem->zMalloc);
    +-    memcpy(pMem, &t, sizeof(t));
    +-    rc = ctx.isError;
    +-  }
    +-  return rc;
    ++  sqlite3_context ctx;
    ++  Mem t;
    ++  assert( pFunc!=0 );
    ++  assert( pFunc->xFinalize!=0 );
    ++  assert( (pMem->flags & MEM_Null)!=0 || pFunc==pMem->u.pDef );
    ++  assert( pMem->db==0 || sqlite3_mutex_held(pMem->db->mutex) );
    ++  memset(&ctx, 0, sizeof(ctx));
    ++  memset(&t, 0, sizeof(t));
    ++  t.flags = MEM_Null;
    ++  t.db = pMem->db;
    ++  ctx.pOut = &t;
    ++  ctx.pMem = pMem;
    ++  ctx.pFunc = pFunc;
    ++  pFunc->xFinalize(&ctx); /* IMP: R-24505-23230 */
    ++  assert( (pMem->flags & MEM_Dyn)==0 );
    ++  if( pMem->szMalloc>0 ) sqlite3DbFreeNN(pMem->db, pMem->zMalloc);
    ++  memcpy(pMem, &t, sizeof(t));
    ++  return ctx.isError;
    + }
    + 
    + /*
    +@@ -65369,7 +71604,7 @@ static SQLITE_NOINLINE void vdbeMemClear(Mem *p){
    +     vdbeMemClearExternAndSetNull(p);
    +   }
    +   if( p->szMalloc ){
    +-    sqlite3DbFree(p->db, p->zMalloc);
    ++    sqlite3DbFreeNN(p->db, p->zMalloc);
    +     p->szMalloc = 0;
    +   }
    +   p->z = 0;
    +@@ -65397,7 +71632,7 @@ SQLITE_PRIVATE void sqlite3VdbeMemRelease(Mem *p){
    + ** If the double is out of range of a 64-bit signed integer then
    + ** return the closest available 64-bit signed integer.
    + */
    +-static i64 doubleToInt64(double r){
    ++static SQLITE_NOINLINE i64 doubleToInt64(double r){
    + #ifdef SQLITE_OMIT_FLOATING_POINT
    +   /* When floating-point is omitted, double and int64 are the same thing */
    +   return r;
    +@@ -65433,6 +71668,11 @@ static i64 doubleToInt64(double r){
    + **
    + ** If pMem represents a string value, its encoding might be changed.
    + */
    ++static SQLITE_NOINLINE i64 memIntValue(Mem *pMem){
    ++  i64 value = 0;
    ++  sqlite3Atoi64(pMem->z, &value, pMem->n, pMem->enc);
    ++  return value;
    ++}
    + SQLITE_PRIVATE i64 sqlite3VdbeIntValue(Mem *pMem){
    +   int flags;
    +   assert( pMem->db==0 || sqlite3_mutex_held(pMem->db->mutex) );
    +@@ -65443,10 +71683,8 @@ SQLITE_PRIVATE i64 sqlite3VdbeIntValue(Mem *pMem){
    +   }else if( flags & MEM_Real ){
    +     return doubleToInt64(pMem->u.r);
    +   }else if( flags & (MEM_Str|MEM_Blob) ){
    +-    i64 value = 0;
    +     assert( pMem->z || pMem->n==0 );
    +-    sqlite3Atoi64(pMem->z, &value, pMem->n, pMem->enc);
    +-    return value;
    ++    return memIntValue(pMem);
    +   }else{
    +     return 0;
    +   }
    +@@ -65458,6 +71696,12 @@ SQLITE_PRIVATE i64 sqlite3VdbeIntValue(Mem *pMem){
    + ** value.  If it is a string or blob, try to convert it to a double.
    + ** If it is a NULL, return 0.0.
    + */
    ++static SQLITE_NOINLINE double memRealValue(Mem *pMem){
    ++  /* (double)0 In case of SQLITE_OMIT_FLOATING_POINT... */
    ++  double val = (double)0;
    ++  sqlite3AtoF(pMem->z, &val, pMem->n, pMem->enc);
    ++  return val;
    ++}
    + SQLITE_PRIVATE double sqlite3VdbeRealValue(Mem *pMem){
    +   assert( pMem->db==0 || sqlite3_mutex_held(pMem->db->mutex) );
    +   assert( EIGHT_BYTE_ALIGNMENT(pMem) );
    +@@ -65466,10 +71710,7 @@ SQLITE_PRIVATE double sqlite3VdbeRealValue(Mem *pMem){
    +   }else if( pMem->flags & MEM_Int ){
    +     return (double)pMem->u.i;
    +   }else if( pMem->flags & (MEM_Str|MEM_Blob) ){
    +-    /* (double)0 In case of SQLITE_OMIT_FLOATING_POINT... */
    +-    double val = (double)0;
    +-    sqlite3AtoF(pMem->z, &val, pMem->n, pMem->enc);
    +-    return val;
    ++    return memRealValue(pMem);
    +   }else{
    +     /* (double)0 In case of SQLITE_OMIT_FLOATING_POINT... */
    +     return (double)0;
    +@@ -65541,18 +71782,25 @@ SQLITE_PRIVATE int sqlite3VdbeMemRealify(Mem *pMem){
    + */
    + SQLITE_PRIVATE int sqlite3VdbeMemNumerify(Mem *pMem){
    +   if( (pMem->flags & (MEM_Int|MEM_Real|MEM_Null))==0 ){
    ++    int rc;
    +     assert( (pMem->flags & (MEM_Blob|MEM_Str))!=0 );
    +     assert( pMem->db==0 || sqlite3_mutex_held(pMem->db->mutex) );
    +-    if( 0==sqlite3Atoi64(pMem->z, &pMem->u.i, pMem->n, pMem->enc) ){
    ++    rc = sqlite3Atoi64(pMem->z, &pMem->u.i, pMem->n, pMem->enc);
    ++    if( rc==0 ){
    +       MemSetTypeFlag(pMem, MEM_Int);
    +     }else{
    +-      pMem->u.r = sqlite3VdbeRealValue(pMem);
    +-      MemSetTypeFlag(pMem, MEM_Real);
    +-      sqlite3VdbeIntegerAffinity(pMem);
    ++      i64 i = pMem->u.i;
    ++      sqlite3AtoF(pMem->z, &pMem->u.r, pMem->n, pMem->enc);
    ++      if( rc==1 && pMem->u.r==(double)i ){
    ++        pMem->u.i = i;
    ++        MemSetTypeFlag(pMem, MEM_Int);
    ++      }else{
    ++        MemSetTypeFlag(pMem, MEM_Real);
    ++      }
    +     }
    +   }
    +   assert( (pMem->flags & (MEM_Int|MEM_Real|MEM_Null))!=0 );
    +-  pMem->flags &= ~(MEM_Str|MEM_Blob);
    ++  pMem->flags &= ~(MEM_Str|MEM_Blob|MEM_Zero);
    +   return SQLITE_OK;
    + }
    + 
    +@@ -65570,7 +71818,7 @@ SQLITE_PRIVATE void sqlite3VdbeMemCast(Mem *pMem, u8 aff, u8 encoding){
    +       if( (pMem->flags & MEM_Blob)==0 ){
    +         sqlite3ValueApplyAffinity(pMem, SQLITE_AFF_TEXT, encoding);
    +         assert( pMem->flags & MEM_Str || pMem->db->mallocFailed );
    +-        MemSetTypeFlag(pMem, MEM_Blob);
    ++        if( pMem->flags & MEM_Str ) MemSetTypeFlag(pMem, MEM_Blob);
    +       }else{
    +         pMem->flags &= ~(MEM_TypeMask&~MEM_Blob);
    +       }
    +@@ -65674,6 +71922,27 @@ SQLITE_PRIVATE void sqlite3VdbeMemSetInt64(Mem *pMem, i64 val){
    +   }
    + }
    + 
    ++/* A no-op destructor */
    ++static void sqlite3NoopDestructor(void *p){ UNUSED_PARAMETER(p); }
    ++
    ++/*
    ++** Set the value stored in *pMem should already be a NULL.
    ++** Also store a pointer to go with it.
    ++*/
    ++SQLITE_PRIVATE void sqlite3VdbeMemSetPointer(
    ++  Mem *pMem,
    ++  void *pPtr,
    ++  const char *zPType,
    ++  void (*xDestructor)(void*)
    ++){
    ++  assert( pMem->flags==MEM_Null );
    ++  pMem->u.zPType = zPType ? zPType : "";
    ++  pMem->z = pPtr;
    ++  pMem->flags = MEM_Null|MEM_Dyn|MEM_Subtype|MEM_Term;
    ++  pMem->eSubtype = 'p';
    ++  pMem->xDel = xDestructor ? xDestructor : sqlite3NoopDestructor;
    ++}
    ++
    + #ifndef SQLITE_OMIT_FLOATING_POINT
    + /*
    + ** Delete any previous value and set the value stored in *pMem to val,
    +@@ -65697,7 +71966,7 @@ SQLITE_PRIVATE void sqlite3VdbeMemSetRowSet(Mem *pMem){
    +   assert( db!=0 );
    +   assert( (pMem->flags & MEM_RowSet)==0 );
    +   sqlite3VdbeMemRelease(pMem);
    +-  pMem->zMalloc = sqlite3DbMallocRaw(db, 64);
    ++  pMem->zMalloc = sqlite3DbMallocRawNN(db, 64);
    +   if( db->mallocFailed ){
    +     pMem->flags = MEM_Null;
    +     pMem->szMalloc = 0;
    +@@ -65738,7 +72007,7 @@ SQLITE_PRIVATE int sqlite3VdbeMemTooBig(Mem *p){
    + SQLITE_PRIVATE void sqlite3VdbeMemAboutToChange(Vdbe *pVdbe, Mem *pMem){
    +   int i;
    +   Mem *pX;
    +-  for(i=1, pX=&pVdbe->aMem[1]; i<=pVdbe->nMem; i++, pX++){
    ++  for(i=0, pX=pVdbe->aMem; i<pVdbe->nMem; i++, pX++){
    +     if( pX->pScopyFrom==pMem ){
    +       pX->flags |= MEM_Undefined;
    +       pX->pScopyFrom = 0;
    +@@ -65779,10 +72048,6 @@ SQLITE_PRIVATE void sqlite3VdbeMemShallowCopy(Mem *pTo, const Mem *pFrom, int sr
    + SQLITE_PRIVATE int sqlite3VdbeMemCopy(Mem *pTo, const Mem *pFrom){
    +   int rc = SQLITE_OK;
    + 
    +-  /* The pFrom==0 case in the following assert() is when an sqlite3_value
    +-  ** from sqlite3_value_dup() is used as the argument
    +-  ** to sqlite3_result_value(). */
    +-  assert( pTo->db==pFrom->db || pFrom->db==0 );
    +   assert( (pFrom->flags & MEM_RowSet)==0 );
    +   if( VdbeMemDynamic(pTo) ) vdbeMemClearExternAndSetNull(pTo);
    +   memcpy(pTo, pFrom, MEMCELLSIZE);
    +@@ -65858,7 +72123,7 @@ SQLITE_PRIVATE int sqlite3VdbeMemSetStr(
    +   if( nByte<0 ){
    +     assert( enc!=0 );
    +     if( enc==SQLITE_UTF8 ){
    +-      nByte = sqlite3Strlen30(z);
    ++      nByte = 0x7fffffff & (int)strlen(z);
    +       if( nByte>iLimit ) nByte = iLimit+1;
    +     }else{
    +       for(nByte=0; nByte<=iLimit && (z[nByte] | z[nByte+1]); nByte+=2){}
    +@@ -65882,7 +72147,7 @@ SQLITE_PRIVATE int sqlite3VdbeMemSetStr(
    +     testcase( nAlloc==31 );
    +     testcase( nAlloc==32 );
    +     if( sqlite3VdbeMemClearAndResize(pMem, MAX(nAlloc,32)) ){
    +-      return SQLITE_NOMEM;
    ++      return SQLITE_NOMEM_BKPT;
    +     }
    +     memcpy(pMem->z, z, nAlloc);
    +   }else if( xDel==SQLITE_DYNAMIC ){
    +@@ -65902,7 +72167,7 @@ SQLITE_PRIVATE int sqlite3VdbeMemSetStr(
    + 
    + #ifndef SQLITE_OMIT_UTF16
    +   if( pMem->enc!=SQLITE_UTF8 && sqlite3VdbeMemHandleBom(pMem) ){
    +-    return SQLITE_NOMEM;
    ++    return SQLITE_NOMEM_BKPT;
    +   }
    + #endif
    + 
    +@@ -65915,10 +72180,9 @@ SQLITE_PRIVATE int sqlite3VdbeMemSetStr(
    + 
    + /*
    + ** Move data out of a btree key or data field and into a Mem structure.
    +-** The data or key is taken from the entry that pCur is currently pointing
    ++** The data is payload from the entry that pCur is currently pointing
    + ** to.  offset and amt determine what portion of the data or key to retrieve.
    +-** key is true to get the key or false to get data.  The result is written
    +-** into the pMem element.
    ++** The result is written into the pMem element.
    + **
    + ** The pMem object must have been initialized.  This routine will use
    + ** pMem->zMalloc to hold the content from the btree, if possible.  New
    +@@ -65933,21 +72197,15 @@ static SQLITE_NOINLINE int vdbeMemFromBtreeResize(
    +   BtCursor *pCur,   /* Cursor pointing at record to retrieve. */
    +   u32 offset,       /* Offset from the start of data to return bytes from. */
    +   u32 amt,          /* Number of bytes to return. */
    +-  int key,          /* If true, retrieve from the btree key, not data. */
    +   Mem *pMem         /* OUT: Return data in this Mem structure. */
    + ){
    +   int rc;
    +   pMem->flags = MEM_Null;
    +-  if( SQLITE_OK==(rc = sqlite3VdbeMemClearAndResize(pMem, amt+2)) ){
    +-    if( key ){
    +-      rc = sqlite3BtreeKey(pCur, offset, amt, pMem->z);
    +-    }else{
    +-      rc = sqlite3BtreeData(pCur, offset, amt, pMem->z);
    +-    }
    ++  if( SQLITE_OK==(rc = sqlite3VdbeMemClearAndResize(pMem, amt+1)) ){
    ++    rc = sqlite3BtreePayload(pCur, offset, amt, pMem->z);
    +     if( rc==SQLITE_OK ){
    +-      pMem->z[amt] = 0;
    +-      pMem->z[amt+1] = 0;
    +-      pMem->flags = MEM_Blob|MEM_Term;
    ++      pMem->z[amt] = 0;   /* Overrun area used when reading malformed records */
    ++      pMem->flags = MEM_Blob;
    +       pMem->n = (int)amt;
    +     }else{
    +       sqlite3VdbeMemRelease(pMem);
    +@@ -65959,7 +72217,6 @@ SQLITE_PRIVATE int sqlite3VdbeMemFromBtree(
    +   BtCursor *pCur,   /* Cursor pointing at record to retrieve. */
    +   u32 offset,       /* Offset from the start of data to return bytes from. */
    +   u32 amt,          /* Number of bytes to return. */
    +-  int key,          /* If true, retrieve from the btree key, not data. */
    +   Mem *pMem         /* OUT: Return data in this Mem structure. */
    + ){
    +   char *zData;        /* Data from the btree layer */
    +@@ -65972,11 +72229,7 @@ SQLITE_PRIVATE int sqlite3VdbeMemFromBtree(
    +   /* Note: the calls to BtreeKeyFetch() and DataFetch() below assert() 
    +   ** that both the BtShared and database handle mutexes are held. */
    +   assert( (pMem->flags & MEM_RowSet)==0 );
    +-  if( key ){
    +-    zData = (char *)sqlite3BtreeKeyFetch(pCur, &available);
    +-  }else{
    +-    zData = (char *)sqlite3BtreeDataFetch(pCur, &available);
    +-  }
    ++  zData = (char *)sqlite3BtreePayloadFetch(pCur, &available);
    +   assert( zData!=0 );
    + 
    +   if( offset+amt<=available ){
    +@@ -65984,7 +72237,7 @@ SQLITE_PRIVATE int sqlite3VdbeMemFromBtree(
    +     pMem->flags = MEM_Blob|MEM_Ephem;
    +     pMem->n = (int)amt;
    +   }else{
    +-    rc = vdbeMemFromBtreeResize(pCur, offset, amt, key, pMem);
    ++    rc = vdbeMemFromBtreeResize(pCur, offset, amt, pMem);
    +   }
    + 
    +   return rc;
    +@@ -66002,10 +72255,8 @@ static SQLITE_NOINLINE const void *valueToText(sqlite3_value* pVal, u8 enc){
    +   assert( (pVal->flags & MEM_RowSet)==0 );
    +   assert( (pVal->flags & (MEM_Null))==0 );
    +   if( pVal->flags & (MEM_Blob|MEM_Str) ){
    ++    if( ExpandBlob(pVal) ) return 0;
    +     pVal->flags |= MEM_Str;
    +-    if( pVal->flags & MEM_Zero ){
    +-      sqlite3VdbeMemExpandBlob(pVal);
    +-    }
    +     if( pVal->enc != (enc & ~SQLITE_UTF16_ALIGNED) ){
    +       sqlite3VdbeChangeEncoding(pVal, enc & ~SQLITE_UTF16_ALIGNED);
    +     }
    +@@ -66103,7 +72354,7 @@ static sqlite3_value *valueNew(sqlite3 *db, struct ValueNewStat4Ctx *p){
    +       if( pRec ){
    +         pRec->pKeyInfo = sqlite3KeyInfoOfIndex(p->pParse, pIdx);
    +         if( pRec->pKeyInfo ){
    +-          assert( pRec->pKeyInfo->nField+pRec->pKeyInfo->nXField==nCol );
    ++          assert( pRec->pKeyInfo->nAllField==nCol );
    +           assert( pRec->pKeyInfo->enc==ENC(db) );
    +           pRec->aMem = (Mem *)((u8*)pRec + ROUND8(sizeof(UnpackedRecord)));
    +           for(i=0; i<nCol; i++){
    +@@ -66111,7 +72362,7 @@ static sqlite3_value *valueNew(sqlite3 *db, struct ValueNewStat4Ctx *p){
    +             pRec->aMem[i].db = db;
    +           }
    +         }else{
    +-          sqlite3DbFree(db, pRec);
    ++          sqlite3DbFreeNN(db, pRec);
    +           pRec = 0;
    +         }
    +       }
    +@@ -66163,7 +72414,6 @@ static int valueFromFunction(
    +   FuncDef *pFunc = 0;             /* Function definition */
    +   sqlite3_value *pVal = 0;        /* New value */
    +   int rc = SQLITE_OK;             /* Return code */
    +-  int nName;                      /* Size of function name in bytes */
    +   ExprList *pList = 0;            /* Function arguments */
    +   int i;                          /* Iterator variable */
    + 
    +@@ -66171,8 +72421,7 @@ static int valueFromFunction(
    +   assert( (p->flags & EP_TokenOnly)==0 );
    +   pList = p->x.pList;
    +   if( pList ) nVal = pList->nExpr;
    +-  nName = sqlite3Strlen30(p->u.zToken);
    +-  pFunc = sqlite3FindFunction(db, p->u.zToken, nName, nVal, enc, 0);
    ++  pFunc = sqlite3FindFunction(db, p->u.zToken, nVal, enc, 0);
    +   assert( pFunc );
    +   if( (pFunc->funcFlags & (SQLITE_FUNC_CONSTANT|SQLITE_FUNC_SLOCHNG))==0 
    +    || (pFunc->funcFlags & SQLITE_FUNC_NEEDCOLL)
    +@@ -66183,7 +72432,7 @@ static int valueFromFunction(
    +   if( pList ){
    +     apVal = (sqlite3_value**)sqlite3DbMallocZero(db, sizeof(apVal[0]) * nVal);
    +     if( apVal==0 ){
    +-      rc = SQLITE_NOMEM;
    ++      rc = SQLITE_NOMEM_BKPT;
    +       goto value_from_function_out;
    +     }
    +     for(i=0; i<nVal; i++){
    +@@ -66194,7 +72443,7 @@ static int valueFromFunction(
    + 
    +   pVal = valueNew(db, pCtx);
    +   if( pVal==0 ){
    +-    rc = SQLITE_NOMEM;
    ++    rc = SQLITE_NOMEM_BKPT;
    +     goto value_from_function_out;
    +   }
    + 
    +@@ -66202,7 +72451,7 @@ static int valueFromFunction(
    +   memset(&ctx, 0, sizeof(ctx));
    +   ctx.pOut = pVal;
    +   ctx.pFunc = pFunc;
    +-  pFunc->xFunc(&ctx, nVal, apVal);
    ++  pFunc->xSFunc(&ctx, nVal, apVal);
    +   if( ctx.isError ){
    +     rc = ctx.isError;
    +     sqlite3ErrorMsg(pCtx->pParse, "%s", sqlite3_value_text(pVal));
    +@@ -66225,7 +72474,7 @@ static int valueFromFunction(
    +     for(i=0; i<nVal; i++){
    +       sqlite3ValueFree(apVal[i]);
    +     }
    +-    sqlite3DbFree(db, apVal);
    ++    sqlite3DbFreeNN(db, apVal);
    +   }
    + 
    +   *ppVal = pVal;
    +@@ -66260,12 +72509,13 @@ static int valueFromExpr(
    +   const char *zNeg = "";
    +   int rc = SQLITE_OK;
    + 
    +-  if( !pExpr ){
    +-    *ppVal = 0;
    +-    return SQLITE_OK;
    +-  }
    +-  while( (op = pExpr->op)==TK_UPLUS ) pExpr = pExpr->pLeft;
    ++  assert( pExpr!=0 );
    ++  while( (op = pExpr->op)==TK_UPLUS || op==TK_SPAN ) pExpr = pExpr->pLeft;
    ++#if defined(SQLITE_ENABLE_STAT3_OR_STAT4)
    ++  if( op==TK_REGISTER ) op = pExpr->op2;
    ++#else
    +   if( NEVER(op==TK_REGISTER) ) op = pExpr->op2;
    ++#endif
    + 
    +   /* Compressed expressions only appear when parsing the DEFAULT clause
    +   ** on a table column definition, and hence only when pCtx==0.  This
    +@@ -66316,7 +72566,7 @@ static int valueFromExpr(
    +     }
    +   }else if( op==TK_UMINUS ) {
    +     /* This branch happens for multiple negative signs.  Ex: -(-5) */
    +-    if( SQLITE_OK==sqlite3ValueFromExpr(db,pExpr->pLeft,enc,affinity,&pVal) 
    ++    if( SQLITE_OK==valueFromExpr(db,pExpr->pLeft,enc,affinity,&pVal,pCtx) 
    +      && pVal!=0
    +     ){
    +       sqlite3VdbeMemNumerify(pVal);
    +@@ -66333,6 +72583,7 @@ static int valueFromExpr(
    +   }else if( op==TK_NULL ){
    +     pVal = valueNew(db, pCtx);
    +     if( pVal==0 ) goto no_mem;
    ++    sqlite3VdbeMemNumerify(pVal);
    +   }
    + #ifndef SQLITE_OMIT_BLOB_LITERAL
    +   else if( op==TK_BLOB ){
    +@@ -66359,7 +72610,10 @@ static int valueFromExpr(
    +   return rc;
    + 
    + no_mem:
    +-  db->mallocFailed = 1;
    ++#ifdef SQLITE_ENABLE_STAT3_OR_STAT4
    ++  if( pCtx==0 || pCtx->pParse->nErr==0 )
    ++#endif
    ++    sqlite3OomFault(db);
    +   sqlite3DbFree(db, zVal);
    +   assert( *ppVal==0 );
    + #ifdef SQLITE_ENABLE_STAT3_OR_STAT4
    +@@ -66367,7 +72621,7 @@ no_mem:
    + #else
    +   assert( pCtx==0 ); sqlite3ValueFree(pVal);
    + #endif
    +-  return SQLITE_NOMEM;
    ++  return SQLITE_NOMEM_BKPT;
    + }
    + 
    + /*
    +@@ -66387,7 +72641,7 @@ SQLITE_PRIVATE int sqlite3ValueFromExpr(
    +   u8 affinity,              /* Affinity to use */
    +   sqlite3_value **ppVal     /* Write the new value here */
    + ){
    +-  return valueFromExpr(db, pExpr, enc, affinity, ppVal, 0);
    ++  return pExpr ? valueFromExpr(db, pExpr, enc, affinity, ppVal, 0) : 0;
    + }
    + 
    + #ifdef SQLITE_ENABLE_STAT3_OR_STAT4
    +@@ -66405,21 +72659,20 @@ static void recordFunc(
    +   sqlite3_value **argv
    + ){
    +   const int file_format = 1;
    +-  int iSerial;                    /* Serial type */
    ++  u32 iSerial;                    /* Serial type */
    +   int nSerial;                    /* Bytes of space for iSerial as varint */
    +-  int nVal;                       /* Bytes of space required for argv[0] */
    ++  u32 nVal;                       /* Bytes of space required for argv[0] */
    +   int nRet;
    +   sqlite3 *db;
    +   u8 *aRet;
    + 
    +   UNUSED_PARAMETER( argc );
    +-  iSerial = sqlite3VdbeSerialType(argv[0], file_format);
    ++  iSerial = sqlite3VdbeSerialType(argv[0], file_format, &nVal);
    +   nSerial = sqlite3VarintLen(iSerial);
    +-  nVal = sqlite3VdbeSerialTypeLen(iSerial);
    +   db = sqlite3_context_db_handle(context);
    + 
    +   nRet = 1 + nSerial + nVal;
    +-  aRet = sqlite3DbMallocRaw(db, nRet);
    ++  aRet = sqlite3DbMallocRawNN(db, nRet);
    +   if( aRet==0 ){
    +     sqlite3_result_error_nomem(context);
    +   }else{
    +@@ -66427,7 +72680,7 @@ static void recordFunc(
    +     putVarint32(&aRet[1], iSerial);
    +     sqlite3VdbeSerialPut(&aRet[1+nSerial], argv[0], iSerial);
    +     sqlite3_result_blob(context, aRet, nRet, SQLITE_TRANSIENT);
    +-    sqlite3DbFree(db, aRet);
    ++    sqlite3DbFreeNN(db, aRet);
    +   }
    + }
    + 
    +@@ -66435,15 +72688,10 @@ static void recordFunc(
    + ** Register built-in functions used to help read ANALYZE data.
    + */
    + SQLITE_PRIVATE void sqlite3AnalyzeFunctions(void){
    +-  static SQLITE_WSD FuncDef aAnalyzeTableFuncs[] = {
    ++  static FuncDef aAnalyzeTableFuncs[] = {
    +     FUNCTION(sqlite_record,   1, 0, 0, recordFunc),
    +   };
    +-  int i;
    +-  FuncDefHash *pHash = &GLOBAL(FuncDefHash, sqlite3GlobalFunctions);
    +-  FuncDef *aFunc = (FuncDef*)&GLOBAL(FuncDef, aAnalyzeTableFuncs);
    +-  for(i=0; i<ArraySize(aAnalyzeTableFuncs); i++){
    +-    sqlite3FuncDefInsert(pHash, &aFunc[i]);
    +-  }
    ++  sqlite3InsertBuiltinFuncs(aAnalyzeTableFuncs, ArraySize(aAnalyzeTableFuncs));
    + }
    + 
    + /*
    +@@ -66478,14 +72726,13 @@ static int stat4ValueFromExpr(
    +   /* Skip over any TK_COLLATE nodes */
    +   pExpr = sqlite3ExprSkipCollate(pExpr);
    + 
    ++  assert( pExpr==0 || pExpr->op!=TK_REGISTER || pExpr->op2!=TK_VARIABLE );
    +   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)
    +-  ){
    ++  }else if( pExpr->op==TK_VARIABLE && (db->flags & SQLITE_EnableQPSG)==0 ){
    +     Vdbe *v;
    +     int iBindVar = pExpr->iColumn;
    +     sqlite3VdbeSetVarmask(pParse->pVdbe, iBindVar);
    +@@ -66493,9 +72740,7 @@ static int stat4ValueFromExpr(
    +       pVal = valueNew(db, pAlloc);
    +       if( pVal ){
    +         rc = sqlite3VdbeMemCopy((Mem*)pVal, &v->aVar[iBindVar-1]);
    +-        if( rc==SQLITE_OK ){
    +-          sqlite3ValueApplyAffinity(pVal, affinity, ENC(db));
    +-        }
    ++        sqlite3ValueApplyAffinity(pVal, affinity, ENC(db));
    +         pVal->db = pParse->db;
    +       }
    +     }
    +@@ -66513,9 +72758,9 @@ static int stat4ValueFromExpr(
    + ** structures intended to be compared against sample index keys stored 
    + ** in the sqlite_stat4 table.
    + **
    +-** A single call to this function attempts to populates field iVal (leftmost 
    +-** is 0 etc.) of the unpacked record with a value extracted from expression
    +-** pExpr. Extraction of values is possible if:
    ++** A single call to this function populates zero or more fields of the
    ++** record starting with field iVal (fields are numbered from left to
    ++** right starting with 0). A single field is populated if:
    + **
    + **  * (pExpr==0). In this case the value is assumed to be an SQL NULL,
    + **
    +@@ -66524,10 +72769,14 @@ static int stat4ValueFromExpr(
    + **  * The sqlite3ValueFromExpr() function is able to extract a value 
    + **    from the expression (i.e. the expression is a literal value).
    + **
    +-** If a value can be extracted, the affinity passed as the 5th argument
    +-** is applied to it before it is copied into the UnpackedRecord. Output
    +-** parameter *pbOk is set to true if a value is extracted, or false 
    +-** otherwise.
    ++** Or, if pExpr is a TK_VECTOR, one field is populated for each of the
    ++** vector components that match either of the two latter criteria listed
    ++** above.
    ++**
    ++** Before any value is appended to the record, the affinity of the 
    ++** corresponding column within index pIdx is applied to it. Before
    ++** this function returns, output parameter *pnExtract is set to the
    ++** number of values appended to the record.
    + **
    + ** When this function is called, *ppRec must either point to an object
    + ** allocated by an earlier call to this function, or must be NULL. If it
    +@@ -66543,22 +72792,33 @@ SQLITE_PRIVATE int sqlite3Stat4ProbeSetValue(
    +   Index *pIdx,                    /* Index being probed */
    +   UnpackedRecord **ppRec,         /* IN/OUT: Probe record */
    +   Expr *pExpr,                    /* The expression to extract a value from */
    +-  u8 affinity,                    /* Affinity to use */
    ++  int nElem,                      /* Maximum number of values to append */
    +   int iVal,                       /* Array element to populate */
    +-  int *pbOk                       /* OUT: True if value was extracted */
    ++  int *pnExtract                  /* OUT: Values appended to the record */
    + ){
    +-  int rc;
    +-  sqlite3_value *pVal = 0;
    +-  struct ValueNewStat4Ctx alloc;
    ++  int rc = SQLITE_OK;
    ++  int nExtract = 0;
    ++
    ++  if( pExpr==0 || pExpr->op!=TK_SELECT ){
    ++    int i;
    ++    struct ValueNewStat4Ctx alloc;
    + 
    +-  alloc.pParse = pParse;
    +-  alloc.pIdx = pIdx;
    +-  alloc.ppRec = ppRec;
    +-  alloc.iVal = iVal;
    ++    alloc.pParse = pParse;
    ++    alloc.pIdx = pIdx;
    ++    alloc.ppRec = ppRec;
    + 
    +-  rc = stat4ValueFromExpr(pParse, pExpr, affinity, &alloc, &pVal);
    +-  assert( pVal==0 || pVal->db==pParse->db );
    +-  *pbOk = (pVal!=0);
    ++    for(i=0; i<nElem; i++){
    ++      sqlite3_value *pVal = 0;
    ++      Expr *pElem = (pExpr ? sqlite3VectorFieldSubexpr(pExpr, i) : 0);
    ++      u8 aff = sqlite3IndexColumnAffinity(pParse->db, pIdx, iVal+i);
    ++      alloc.iVal = iVal+i;
    ++      rc = stat4ValueFromExpr(pParse, pElem, aff, &alloc, &pVal);
    ++      if( !pVal ) break;
    ++      nExtract++;
    ++    }
    ++  }
    ++
    ++  *pnExtract = nExtract;
    +   return rc;
    + }
    + 
    +@@ -66622,7 +72882,7 @@ SQLITE_PRIVATE int sqlite3Stat4Column(
    +   if( iField>nRec ) return SQLITE_CORRUPT_BKPT;
    +   if( pMem==0 ){
    +     pMem = *ppVal = sqlite3ValueNew(db);
    +-    if( pMem==0 ) return SQLITE_NOMEM;
    ++    if( pMem==0 ) return SQLITE_NOMEM_BKPT;
    +   }
    +   sqlite3VdbeSerialGet(&a[iField-szField], t, pMem);
    +   pMem->enc = ENC(db);
    +@@ -66637,14 +72897,14 @@ SQLITE_PRIVATE int sqlite3Stat4Column(
    + SQLITE_PRIVATE void sqlite3Stat4ProbeFree(UnpackedRecord *pRec){
    +   if( pRec ){
    +     int i;
    +-    int nCol = pRec->pKeyInfo->nField+pRec->pKeyInfo->nXField;
    ++    int nCol = pRec->pKeyInfo->nAllField;
    +     Mem *aMem = pRec->aMem;
    +     sqlite3 *db = aMem[0].db;
    +     for(i=0; i<nCol; i++){
    +       sqlite3VdbeMemRelease(&aMem[i]);
    +     }
    +     sqlite3KeyInfoUnref(pRec->pKeyInfo);
    +-    sqlite3DbFree(db, pRec);
    ++    sqlite3DbFreeNN(db, pRec);
    +   }
    + }
    + #endif /* ifdef SQLITE_ENABLE_STAT4 */
    +@@ -66668,7 +72928,7 @@ SQLITE_PRIVATE void sqlite3ValueSetStr(
    + SQLITE_PRIVATE void sqlite3ValueFree(sqlite3_value *v){
    +   if( !v ) return;
    +   sqlite3VdbeMemRelease((Mem *)v);
    +-  sqlite3DbFree(((Mem*)v)->db, v);
    ++  sqlite3DbFreeNN(((Mem*)v)->db, v);
    + }
    + 
    + /*
    +@@ -66721,8 +72981,9 @@ SQLITE_PRIVATE int sqlite3ValueBytes(sqlite3_value *pVal, u8 enc){
    + SQLITE_PRIVATE Vdbe *sqlite3VdbeCreate(Parse *pParse){
    +   sqlite3 *db = pParse->db;
    +   Vdbe *p;
    +-  p = sqlite3DbMallocZero(db, sizeof(Vdbe) );
    ++  p = sqlite3DbMallocRawNN(db, sizeof(Vdbe) );
    +   if( p==0 ) return 0;
    ++  memset(&p->aOp, 0, sizeof(Vdbe)-offsetof(Vdbe,aOp));
    +   p->db = db;
    +   if( db->pVdbe ){
    +     db->pVdbe->pPrev = p;
    +@@ -66732,9 +72993,12 @@ SQLITE_PRIVATE Vdbe *sqlite3VdbeCreate(Parse *pParse){
    +   db->pVdbe = p;
    +   p->magic = VDBE_MAGIC_INIT;
    +   p->pParse = pParse;
    ++  pParse->pVdbe = p;
    +   assert( pParse->aLabel==0 );
    +   assert( pParse->nLabel==0 );
    +   assert( pParse->nOpAlloc==0 );
    ++  assert( pParse->szOpAlloc==0 );
    ++  sqlite3VdbeAddOp2(p, OP_Init, 0, 1);
    +   return p;
    + }
    + 
    +@@ -66752,23 +73016,14 @@ SQLITE_PRIVATE void sqlite3VdbeError(Vdbe *p, const char *zFormat, ...){
    + /*
    + ** Remember the SQL string for a prepared statement.
    + */
    +-SQLITE_PRIVATE void sqlite3VdbeSetSql(Vdbe *p, const char *z, int n, int isPrepareV2){
    +-  assert( isPrepareV2==1 || isPrepareV2==0 );
    ++SQLITE_PRIVATE void sqlite3VdbeSetSql(Vdbe *p, const char *z, int n, u8 prepFlags){
    +   if( p==0 ) return;
    +-#if defined(SQLITE_OMIT_TRACE) && !defined(SQLITE_ENABLE_SQLLOG)
    +-  if( !isPrepareV2 ) return;
    +-#endif
    ++  p->prepFlags = prepFlags;
    ++  if( (prepFlags & SQLITE_PREPARE_SAVESQL)==0 ){
    ++    p->expmask = 0;
    ++  }
    +   assert( p->zSql==0 );
    +   p->zSql = sqlite3DbStrNDup(p->db, z, n);
    +-  p->isPrepareV2 = (u8)isPrepareV2;
    +-}
    +-
    +-/*
    +-** Return the SQL associated with a prepared statement
    +-*/
    +-SQLITE_API const char *SQLITE_STDCALL sqlite3_sql(sqlite3_stmt *pStmt){
    +-  Vdbe *p = (Vdbe *)pStmt;
    +-  return p ? p->zSql : 0;
    + }
    + 
    + /*
    +@@ -66777,6 +73032,7 @@ SQLITE_API const char *SQLITE_STDCALL sqlite3_sql(sqlite3_stmt *pStmt){
    + SQLITE_PRIVATE void sqlite3VdbeSwap(Vdbe *pA, Vdbe *pB){
    +   Vdbe tmp, *pTmp;
    +   char *zTmp;
    ++  assert( pA->db==pB->db );
    +   tmp = *pA;
    +   *pA = *pB;
    +   *pB = tmp;
    +@@ -66789,7 +73045,10 @@ SQLITE_PRIVATE void sqlite3VdbeSwap(Vdbe *pA, Vdbe *pB){
    +   zTmp = pA->zSql;
    +   pA->zSql = pB->zSql;
    +   pB->zSql = zTmp;
    +-  pB->isPrepareV2 = pA->isPrepareV2;
    ++  pB->expmask = pA->expmask;
    ++  pB->prepFlags = pA->prepFlags;
    ++  memcpy(pB->aCounter, pA->aCounter, sizeof(pB->aCounter));
    ++  pB->aCounter[SQLITE_STMTSTATUS_REPREPARE]++;
    + }
    + 
    + /*
    +@@ -66820,14 +73079,21 @@ static int growOpArray(Vdbe *v, int nOp){
    +   UNUSED_PARAMETER(nOp);
    + #endif
    + 
    ++  /* Ensure that the size of a VDBE does not grow too large */
    ++  if( nNew > p->db->aLimit[SQLITE_LIMIT_VDBE_OP] ){
    ++    sqlite3OomFault(p->db);
    ++    return SQLITE_NOMEM;
    ++  }
    ++
    +   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);
    ++    p->szOpAlloc = sqlite3DbMallocSize(p->db, pNew);
    ++    p->nOpAlloc = p->szOpAlloc/sizeof(Op);
    +     v->aOp = pNew;
    +   }
    +-  return (pNew ? SQLITE_OK : SQLITE_NOMEM);
    ++  return (pNew ? SQLITE_OK : SQLITE_NOMEM_BKPT);
    + }
    + 
    + #ifdef SQLITE_DEBUG
    +@@ -66857,17 +73123,21 @@ static void test_addop_breakpoint(void){
    + ** the sqlite3VdbeChangeP4() function to change the value of the P4
    + ** operand.
    + */
    ++static SQLITE_NOINLINE int growOp3(Vdbe *p, int op, int p1, int p2, int p3){
    ++  assert( p->pParse->nOpAlloc<=p->nOp );
    ++  if( growOpArray(p, 1) ) return 1;
    ++  assert( p->pParse->nOpAlloc>p->nOp );
    ++  return sqlite3VdbeAddOp3(p, op, p1, p2, p3);
    ++}
    + SQLITE_PRIVATE int sqlite3VdbeAddOp3(Vdbe *p, int op, int p1, int p2, int p3){
    +   int i;
    +   VdbeOp *pOp;
    + 
    +   i = p->nOp;
    +   assert( p->magic==VDBE_MAGIC_INIT );
    +-  assert( op>0 && op<0xff );
    ++  assert( op>=0 && op<0xff );
    +   if( p->pParse->nOpAlloc<=i ){
    +-    if( growOpArray(p, 1) ){
    +-      return 1;
    +-    }
    ++    return growOp3(p, op, p1, p2, p3);
    +   }
    +   p->nOp++;
    +   pOp = &p->aOp[i];
    +@@ -66885,9 +73155,8 @@ SQLITE_PRIVATE int sqlite3VdbeAddOp3(Vdbe *p, int op, int p1, int p2, int p3){
    +   if( p->db->flags & SQLITE_VdbeAddopTrace ){
    +     int jj, kk;
    +     Parse *pParse = p->pParse;
    +-    for(jj=kk=0; jj<SQLITE_N_COLCACHE; jj++){
    ++    for(jj=kk=0; jj<pParse->nColCache; jj++){
    +       struct yColCache *x = pParse->aColCache + jj;
    +-      if( x->iLevel>pParse->iCacheLevel || x->iReg==0 ) continue;
    +       printf(" r[%d]={%d:%d}", x->iReg, x->iTable, x->iColumn);
    +       kk++;
    +     }
    +@@ -66935,6 +73204,9 @@ SQLITE_PRIVATE int sqlite3VdbeLoadString(Vdbe *p, int iDest, const char *zStr){
    + ** "s" character in zTypes[], the register is a string if the argument is
    + ** not NULL, or OP_Null if the value is a null pointer.  For each "i" character
    + ** in zTypes[], the register is initialized to an integer.
    ++**
    ++** If the input string does not end with "X" then an OP_ResultRow instruction
    ++** is generated for the values inserted.
    + */
    + SQLITE_PRIVATE void sqlite3VdbeMultiLoad(Vdbe *p, int iDest, const char *zTypes, ...){
    +   va_list ap;
    +@@ -66944,13 +73216,15 @@ SQLITE_PRIVATE void sqlite3VdbeMultiLoad(Vdbe *p, int iDest, const char *zTypes,
    +   for(i=0; (c = zTypes[i])!=0; i++){
    +     if( c=='s' ){
    +       const char *z = va_arg(ap, const char*);
    +-      int addr = sqlite3VdbeAddOp2(p, z==0 ? OP_Null : OP_String8, 0, iDest++);
    +-      if( z ) sqlite3VdbeChangeP4(p, addr, z, 0);
    ++      sqlite3VdbeAddOp4(p, z==0 ? OP_Null : OP_String8, 0, iDest+i, 0, z, 0);
    ++    }else if( c=='i' ){
    ++      sqlite3VdbeAddOp2(p, OP_Integer, va_arg(ap, int), iDest+i);
    +     }else{
    +-      assert( c=='i' );
    +-      sqlite3VdbeAddOp2(p, OP_Integer, va_arg(ap, int), iDest++);
    ++      goto skip_op_resultrow;
    +     }
    +   }
    ++  sqlite3VdbeAddOp2(p, OP_ResultRow, iDest, i);
    ++skip_op_resultrow:
    +   va_end(ap);
    + }
    + 
    +@@ -66984,7 +73258,7 @@ SQLITE_PRIVATE int sqlite3VdbeAddOp4Dup8(
    +   const u8 *zP4,      /* The P4 operand */
    +   int p4type          /* P4 operand type */
    + ){
    +-  char *p4copy = sqlite3DbMallocRaw(sqlite3VdbeDb(p), 8);
    ++  char *p4copy = sqlite3DbMallocRawNN(sqlite3VdbeDb(p), 8);
    +   if( p4copy ) memcpy(p4copy, zP4, 8);
    +   return sqlite3VdbeAddOp4(p, op, p1, p2, p3, p4copy, p4type);
    + }
    +@@ -66999,8 +73273,7 @@ SQLITE_PRIVATE int sqlite3VdbeAddOp4Dup8(
    + */
    + SQLITE_PRIVATE void sqlite3VdbeAddParseSchemaOp(Vdbe *p, int iDb, char *zWhere){
    +   int j;
    +-  int addr = sqlite3VdbeAddOp3(p, OP_ParseSchema, iDb, 0, 0);
    +-  sqlite3VdbeChangeP4(p, addr, zWhere, P4_DYNAMIC);
    ++  sqlite3VdbeAddOp4(p, OP_ParseSchema, iDb, 0, 0, zWhere, P4_DYNAMIC);
    +   for(j=0; j<p->db->nDb; j++) sqlite3VdbeUsesBtree(p, j);
    + }
    + 
    +@@ -67016,10 +73289,29 @@ SQLITE_PRIVATE int sqlite3VdbeAddOp4Int(
    +   int p4              /* The P4 operand as an integer */
    + ){
    +   int addr = sqlite3VdbeAddOp3(p, op, p1, p2, p3);
    +-  sqlite3VdbeChangeP4(p, addr, SQLITE_INT_TO_PTR(p4), P4_INT32);
    ++  if( p->db->mallocFailed==0 ){
    ++    VdbeOp *pOp = &p->aOp[addr];
    ++    pOp->p4type = P4_INT32;
    ++    pOp->p4.i = p4;
    ++  }
    +   return addr;
    + }
    + 
    ++/* Insert the end of a co-routine
    ++*/
    ++SQLITE_PRIVATE void sqlite3VdbeEndCoroutine(Vdbe *v, int regYield){
    ++  sqlite3VdbeAddOp1(v, OP_EndCoroutine, regYield);
    ++
    ++  /* Clear the temporary register cache, thereby ensuring that each
    ++  ** co-routine has its own independent set of registers, because co-routines
    ++  ** might expect their registers to be preserved across an OP_Yield, and
    ++  ** that could cause problems if two or more co-routines are using the same
    ++  ** temporary register.
    ++  */
    ++  v->pParse->nTempReg = 0;
    ++  v->pParse->nRangeReg = 0;
    ++}
    ++
    + /*
    + ** Create a new symbolic label for an instruction that has yet to be
    + ** coded.  The symbolic label is really just a negative number.  The
    +@@ -67045,7 +73337,7 @@ SQLITE_PRIVATE int sqlite3VdbeMakeLabel(Vdbe *v){
    +   if( p->aLabel ){
    +     p->aLabel[i] = -1;
    +   }
    +-  return -1-i;
    ++  return ADDR(i);
    + }
    + 
    + /*
    +@@ -67055,14 +73347,13 @@ SQLITE_PRIVATE int sqlite3VdbeMakeLabel(Vdbe *v){
    + */
    + SQLITE_PRIVATE void sqlite3VdbeResolveLabel(Vdbe *v, int x){
    +   Parse *p = v->pParse;
    +-  int j = -1-x;
    ++  int j = ADDR(x);
    +   assert( v->magic==VDBE_MAGIC_INIT );
    +   assert( j<p->nLabel );
    +   assert( j>=0 );
    +   if( p->aLabel ){
    +     p->aLabel[j] = v->nOp;
    +   }
    +-  p->iFixedOp = v->nOp - 1;
    + }
    + 
    + /*
    +@@ -67072,6 +73363,13 @@ SQLITE_PRIVATE void sqlite3VdbeRunOnlyOnce(Vdbe *p){
    +   p->runOnlyOnce = 1;
    + }
    + 
    ++/*
    ++** Mark the VDBE as one that can only be run multiple times.
    ++*/
    ++SQLITE_PRIVATE void sqlite3VdbeReusable(Vdbe *p){
    ++  p->runOnlyOnce = 0;
    ++}
    ++
    + #ifdef SQLITE_DEBUG /* sqlite3AssertMayAbort() logic */
    + 
    + /*
    +@@ -67154,7 +73452,8 @@ static Op *opIterNext(VdbeOpIter *p){
    + **   *  OP_VUpdate
    + **   *  OP_VRename
    + **   *  OP_FkCounter with P2==0 (immediate foreign key constraint)
    +-**   *  OP_CreateTable and OP_InitCoroutine (for CREATE TABLE AS SELECT ...)
    ++**   *  OP_CreateBtree/BTREE_INTKEY and OP_InitCoroutine 
    ++**      (for CREATE TABLE AS SELECT ...)
    + **
    + ** Then check that the value of Parse.mayAbort is true if an
    + ** ABORT may be thrown, or false otherwise. Return true if it does
    +@@ -67182,7 +73481,7 @@ SQLITE_PRIVATE int sqlite3VdbeAssertMayAbort(Vdbe *v, int mayAbort){
    +       hasAbort = 1;
    +       break;
    +     }
    +-    if( opcode==OP_CreateTable ) hasCreateTable = 1;
    ++    if( opcode==OP_CreateBtree && pOp->p3==BTREE_INTKEY ) hasCreateTable = 1;
    +     if( opcode==OP_InitCoroutine ) hasInitCoroutine = 1;
    + #ifndef SQLITE_OMIT_FOREIGN_KEY
    +     if( opcode==OP_FkCounter && pOp->p1==0 && pOp->p2==1 ){
    +@@ -67218,73 +73517,103 @@ SQLITE_PRIVATE int sqlite3VdbeAssertMayAbort(Vdbe *v, int mayAbort){
    + ** (4) Initialize the p4.xAdvance pointer on opcodes that use it.
    + **
    + ** (5) Reclaim the memory allocated for storing labels.
    ++**
    ++** This routine will only function correctly if the mkopcodeh.tcl generator
    ++** script numbers the opcodes correctly.  Changes to this routine must be
    ++** coordinated with changes to mkopcodeh.tcl.
    + */
    + static void resolveP2Values(Vdbe *p, int *pMaxFuncArgs){
    +-  int i;
    +   int nMaxArgs = *pMaxFuncArgs;
    +   Op *pOp;
    +   Parse *pParse = p->pParse;
    +   int *aLabel = pParse->aLabel;
    +   p->readOnly = 1;
    +   p->bIsReader = 0;
    +-  for(pOp=p->aOp, i=p->nOp-1; i>=0; i--, pOp++){
    +-    u8 opcode = pOp->opcode;
    +-
    +-    /* NOTE: Be sure to update mkopcodeh.awk when adding or removing
    +-    ** cases from this switch! */
    +-    switch( opcode ){
    +-      case OP_Transaction: {
    +-        if( pOp->p2!=0 ) p->readOnly = 0;
    +-        /* fall thru */
    +-      }
    +-      case OP_AutoCommit:
    +-      case OP_Savepoint: {
    +-        p->bIsReader = 1;
    +-        break;
    +-      }
    ++  pOp = &p->aOp[p->nOp-1];
    ++  while(1){
    ++
    ++    /* Only JUMP opcodes and the short list of special opcodes in the switch
    ++    ** below need to be considered.  The mkopcodeh.tcl generator script groups
    ++    ** all these opcodes together near the front of the opcode list.  Skip
    ++    ** any opcode that does not need processing by virtual of the fact that
    ++    ** it is larger than SQLITE_MX_JUMP_OPCODE, as a performance optimization.
    ++    */
    ++    if( pOp->opcode<=SQLITE_MX_JUMP_OPCODE ){
    ++      /* NOTE: Be sure to update mkopcodeh.tcl when adding or removing
    ++      ** cases from this switch! */
    ++      switch( pOp->opcode ){
    ++        case OP_Transaction: {
    ++          if( pOp->p2!=0 ) p->readOnly = 0;
    ++          /* fall thru */
    ++        }
    ++        case OP_AutoCommit:
    ++        case OP_Savepoint: {
    ++          p->bIsReader = 1;
    ++          break;
    ++        }
    + #ifndef SQLITE_OMIT_WAL
    +-      case OP_Checkpoint:
    ++        case OP_Checkpoint:
    + #endif
    +-      case OP_Vacuum:
    +-      case OP_JournalMode: {
    +-        p->readOnly = 0;
    +-        p->bIsReader = 1;
    +-        break;
    +-      }
    ++        case OP_Vacuum:
    ++        case OP_JournalMode: {
    ++          p->readOnly = 0;
    ++          p->bIsReader = 1;
    ++          break;
    ++        }
    ++        case OP_Next:
    ++        case OP_NextIfOpen:
    ++        case OP_SorterNext: {
    ++          pOp->p4.xAdvance = sqlite3BtreeNext;
    ++          pOp->p4type = P4_ADVANCE;
    ++          /* The code generator never codes any of these opcodes as a jump
    ++          ** to a label.  They are always coded as a jump backwards to a 
    ++          ** known address */
    ++          assert( pOp->p2>=0 );
    ++          break;
    ++        }
    ++        case OP_Prev:
    ++        case OP_PrevIfOpen: {
    ++          pOp->p4.xAdvance = sqlite3BtreePrevious;
    ++          pOp->p4type = P4_ADVANCE;
    ++          /* The code generator never codes any of these opcodes as a jump
    ++          ** to a label.  They are always coded as a jump backwards to a 
    ++          ** known address */
    ++          assert( pOp->p2>=0 );
    ++          break;
    ++        }
    + #ifndef SQLITE_OMIT_VIRTUALTABLE
    +-      case OP_VUpdate: {
    +-        if( pOp->p2>nMaxArgs ) nMaxArgs = pOp->p2;
    +-        break;
    +-      }
    +-      case OP_VFilter: {
    +-        int n;
    +-        assert( p->nOp - i >= 3 );
    +-        assert( pOp[-1].opcode==OP_Integer );
    +-        n = pOp[-1].p1;
    +-        if( n>nMaxArgs ) nMaxArgs = n;
    +-        break;
    +-      }
    +-#endif
    +-      case OP_Next:
    +-      case OP_NextIfOpen:
    +-      case OP_SorterNext: {
    +-        pOp->p4.xAdvance = sqlite3BtreeNext;
    +-        pOp->p4type = P4_ADVANCE;
    +-        break;
    +-      }
    +-      case OP_Prev:
    +-      case OP_PrevIfOpen: {
    +-        pOp->p4.xAdvance = sqlite3BtreePrevious;
    +-        pOp->p4type = P4_ADVANCE;
    +-        break;
    ++        case OP_VUpdate: {
    ++          if( pOp->p2>nMaxArgs ) nMaxArgs = pOp->p2;
    ++          break;
    ++        }
    ++        case OP_VFilter: {
    ++          int n;
    ++          assert( (pOp - p->aOp) >= 3 );
    ++          assert( pOp[-1].opcode==OP_Integer );
    ++          n = pOp[-1].p1;
    ++          if( n>nMaxArgs ) nMaxArgs = n;
    ++          /* Fall through into the default case */
    ++        }
    ++#endif
    ++        default: {
    ++          if( pOp->p2<0 ){
    ++            /* The mkopcodeh.tcl script has so arranged things that the only
    ++            ** non-jump opcodes less than SQLITE_MX_JUMP_CODE are guaranteed to
    ++            ** have non-negative values for P2. */
    ++            assert( (sqlite3OpcodeProperty[pOp->opcode] & OPFLG_JUMP)!=0 );
    ++            assert( ADDR(pOp->p2)<pParse->nLabel );
    ++            pOp->p2 = aLabel[ADDR(pOp->p2)];
    ++          }
    ++          break;
    ++        }
    +       }
    ++      /* The mkopcodeh.tcl script has so arranged things that the only
    ++      ** non-jump opcodes less than SQLITE_MX_JUMP_CODE are guaranteed to
    ++      ** have non-negative values for P2. */
    ++      assert( (sqlite3OpcodeProperty[pOp->opcode]&OPFLG_JUMP)==0 || pOp->p2>=0);
    +     }
    +-
    +-    pOp->opflags = sqlite3OpcodeProperty[opcode];
    +-    if( (pOp->opflags & OPFLG_JUMP)!=0 && pOp->p2<0 ){
    +-      assert( -1-pOp->p2<pParse->nLabel );
    +-      pOp->p2 = aLabel[-1-pOp->p2];
    +-    }
    ++    if( pOp==p->aOp ) break;
    ++    pOp--;
    +   }
    +   sqlite3DbFree(p->db, pParse->aLabel);
    +   pParse->aLabel = 0;
    +@@ -67301,6 +73630,36 @@ SQLITE_PRIVATE int sqlite3VdbeCurrentAddr(Vdbe *p){
    +   return p->nOp;
    + }
    + 
    ++/*
    ++** Verify that at least N opcode slots are available in p without
    ++** having to malloc for more space (except when compiled using
    ++** SQLITE_TEST_REALLOC_STRESS).  This interface is used during testing
    ++** to verify that certain calls to sqlite3VdbeAddOpList() can never
    ++** fail due to a OOM fault and hence that the return value from
    ++** sqlite3VdbeAddOpList() will always be non-NULL.
    ++*/
    ++#if defined(SQLITE_DEBUG) && !defined(SQLITE_TEST_REALLOC_STRESS)
    ++SQLITE_PRIVATE void sqlite3VdbeVerifyNoMallocRequired(Vdbe *p, int N){
    ++  assert( p->nOp + N <= p->pParse->nOpAlloc );
    ++}
    ++#endif
    ++
    ++/*
    ++** Verify that the VM passed as the only argument does not contain
    ++** an OP_ResultRow opcode. Fail an assert() if it does. This is used
    ++** by code in pragma.c to ensure that the implementation of certain
    ++** pragmas comports with the flags specified in the mkpragmatab.tcl
    ++** script.
    ++*/
    ++#if defined(SQLITE_DEBUG) && !defined(SQLITE_TEST_REALLOC_STRESS)
    ++SQLITE_PRIVATE void sqlite3VdbeVerifyNoResultRow(Vdbe *p){
    ++  int i;
    ++  for(i=0; i<p->nOp; i++){
    ++    assert( p->aOp[i].opcode!=OP_ResultRow );
    ++  }
    ++}
    ++#endif
    ++
    + /*
    + ** This function returns a pointer to the array of opcodes associated with
    + ** the Vdbe passed as the first argument. It is the callers responsibility
    +@@ -67326,28 +73685,33 @@ SQLITE_PRIVATE VdbeOp *sqlite3VdbeTakeOpArray(Vdbe *p, int *pnOp, int *pnMaxArg)
    + }
    + 
    + /*
    +-** Add a whole list of operations to the operation stack.  Return the
    +-** address of the first operation added.
    ++** Add a whole list of operations to the operation stack.  Return a
    ++** pointer to the first operation inserted.
    ++**
    ++** Non-zero P2 arguments to jump instructions are automatically adjusted
    ++** so that the jump target is relative to the first operation inserted.
    + */
    +-SQLITE_PRIVATE int sqlite3VdbeAddOpList(Vdbe *p, int nOp, VdbeOpList const *aOp, int iLineno){
    +-  int addr, i;
    +-  VdbeOp *pOut;
    ++SQLITE_PRIVATE VdbeOp *sqlite3VdbeAddOpList(
    ++  Vdbe *p,                     /* Add opcodes to the prepared statement */
    ++  int nOp,                     /* Number of opcodes to add */
    ++  VdbeOpList const *aOp,       /* The opcodes to be added */
    ++  int iLineno                  /* Source-file line number of first opcode */
    ++){
    ++  int i;
    ++  VdbeOp *pOut, *pFirst;
    +   assert( nOp>0 );
    +   assert( p->magic==VDBE_MAGIC_INIT );
    +   if( p->nOp + nOp > p->pParse->nOpAlloc && growOpArray(p, nOp) ){
    +     return 0;
    +   }
    +-  addr = p->nOp;
    +-  pOut = &p->aOp[addr];
    ++  pFirst = pOut = &p->aOp[p->nOp];
    +   for(i=0; i<nOp; i++, aOp++, pOut++){
    +-    int p2 = aOp->p2;
    +     pOut->opcode = aOp->opcode;
    +     pOut->p1 = aOp->p1;
    +-    if( p2<0 ){
    +-      assert( sqlite3OpcodeProperty[pOut->opcode] & OPFLG_JUMP );
    +-      pOut->p2 = addr + ADDR(p2);
    +-    }else{
    +-      pOut->p2 = p2;
    ++    pOut->p2 = aOp->p2;
    ++    assert( aOp->p2>=0 );
    ++    if( (sqlite3OpcodeProperty[aOp->opcode] & OPFLG_JUMP)!=0 && aOp->p2>0 ){
    ++      pOut->p2 += p->nOp;
    +     }
    +     pOut->p3 = aOp->p3;
    +     pOut->p4type = P4_NOTUSED;
    +@@ -67363,12 +73727,12 @@ SQLITE_PRIVATE int sqlite3VdbeAddOpList(Vdbe *p, int nOp, VdbeOpList const *aOp,
    + #endif
    + #ifdef SQLITE_DEBUG
    +     if( p->db->flags & SQLITE_VdbeAddopTrace ){
    +-      sqlite3VdbePrintOp(0, i+addr, &p->aOp[i+addr]);
    ++      sqlite3VdbePrintOp(0, i+p->nOp, &p->aOp[i+p->nOp]);
    +     }
    + #endif
    +   }
    +   p->nOp += nOp;
    +-  return addr;
    ++  return pFirst;
    + }
    + 
    + #if defined(SQLITE_ENABLE_STMT_SCANSTATUS)
    +@@ -67415,8 +73779,9 @@ SQLITE_PRIVATE void sqlite3VdbeChangeP2(Vdbe *p, u32 addr, int val){
    + SQLITE_PRIVATE void sqlite3VdbeChangeP3(Vdbe *p, u32 addr, int val){
    +   sqlite3VdbeGetOp(p,addr)->p3 = val;
    + }
    +-SQLITE_PRIVATE void sqlite3VdbeChangeP5(Vdbe *p, u8 p5){
    +-  sqlite3VdbeGetOp(p,-1)->p5 = p5;
    ++SQLITE_PRIVATE void sqlite3VdbeChangeP5(Vdbe *p, u16 p5){
    ++  assert( p->nOp>0 || p->db->mallocFailed );
    ++  if( p->nOp>0 ) p->aOp[p->nOp-1].p5 = p5;
    + }
    + 
    + /*
    +@@ -67424,7 +73789,6 @@ SQLITE_PRIVATE void sqlite3VdbeChangeP5(Vdbe *p, u8 p5){
    + ** the address of the next instruction to be coded.
    + */
    + SQLITE_PRIVATE void sqlite3VdbeJumpHere(Vdbe *p, int addr){
    +-  p->pParse->iFixedOp = p->nOp - 1;
    +   sqlite3VdbeChangeP2(p, addr, p->nOp);
    + }
    + 
    +@@ -67434,8 +73798,8 @@ SQLITE_PRIVATE void sqlite3VdbeJumpHere(Vdbe *p, int addr){
    + ** the FuncDef is not ephermal, then do nothing.
    + */
    + static void freeEphemeralFunction(sqlite3 *db, FuncDef *pDef){
    +-  if( ALWAYS(pDef) && (pDef->funcFlags & SQLITE_FUNC_EPHEM)!=0 ){
    +-    sqlite3DbFree(db, pDef);
    ++  if( (pDef->funcFlags & SQLITE_FUNC_EPHEM)!=0 ){
    ++    sqlite3DbFreeNN(db, pDef);
    +   }
    + }
    + 
    +@@ -67444,47 +73808,54 @@ static void vdbeFreeOpArray(sqlite3 *, Op *, int);
    + /*
    + ** Delete a P4 value if necessary.
    + */
    ++static SQLITE_NOINLINE void freeP4Mem(sqlite3 *db, Mem *p){
    ++  if( p->szMalloc ) sqlite3DbFree(db, p->zMalloc);
    ++  sqlite3DbFreeNN(db, p);
    ++}
    ++static SQLITE_NOINLINE void freeP4FuncCtx(sqlite3 *db, sqlite3_context *p){
    ++  freeEphemeralFunction(db, p->pFunc);
    ++ sqlite3DbFreeNN(db, p);
    ++}
    + static void freeP4(sqlite3 *db, int p4type, void *p4){
    +-  if( p4 ){
    +-    assert( db );
    +-    switch( p4type ){
    +-      case P4_FUNCCTX: {
    +-        freeEphemeralFunction(db, ((sqlite3_context*)p4)->pFunc);
    +-        /* Fall through into the next case */
    +-      }
    +-      case P4_REAL:
    +-      case P4_INT64:
    +-      case P4_DYNAMIC:
    +-      case P4_INTARRAY: {
    +-        sqlite3DbFree(db, p4);
    +-        break;
    +-      }
    +-      case P4_KEYINFO: {
    +-        if( db->pnBytesFreed==0 ) sqlite3KeyInfoUnref((KeyInfo*)p4);
    +-        break;
    +-      }
    +-      case P4_MPRINTF: {
    +-        if( db->pnBytesFreed==0 ) sqlite3_free(p4);
    +-        break;
    +-      }
    +-      case P4_FUNCDEF: {
    +-        freeEphemeralFunction(db, (FuncDef*)p4);
    +-        break;
    +-      }
    +-      case P4_MEM: {
    +-        if( db->pnBytesFreed==0 ){
    +-          sqlite3ValueFree((sqlite3_value*)p4);
    +-        }else{
    +-          Mem *p = (Mem*)p4;
    +-          if( p->szMalloc ) sqlite3DbFree(db, p->zMalloc);
    +-          sqlite3DbFree(db, p);
    +-        }
    +-        break;
    +-      }
    +-      case P4_VTAB : {
    +-        if( db->pnBytesFreed==0 ) sqlite3VtabUnlock((VTable *)p4);
    +-        break;
    ++  assert( db );
    ++  switch( p4type ){
    ++    case P4_FUNCCTX: {
    ++      freeP4FuncCtx(db, (sqlite3_context*)p4);
    ++      break;
    ++    }
    ++    case P4_REAL:
    ++    case P4_INT64:
    ++    case P4_DYNAMIC:
    ++    case P4_DYNBLOB:
    ++    case P4_INTARRAY: {
    ++      sqlite3DbFree(db, p4);
    ++      break;
    ++    }
    ++    case P4_KEYINFO: {
    ++      if( db->pnBytesFreed==0 ) sqlite3KeyInfoUnref((KeyInfo*)p4);
    ++      break;
    ++    }
    ++#ifdef SQLITE_ENABLE_CURSOR_HINTS
    ++    case P4_EXPR: {
    ++      sqlite3ExprDelete(db, (Expr*)p4);
    ++      break;
    ++    }
    ++#endif
    ++    case P4_FUNCDEF: {
    ++      freeEphemeralFunction(db, (FuncDef*)p4);
    ++      break;
    ++    }
    ++    case P4_MEM: {
    ++      if( db->pnBytesFreed==0 ){
    ++        sqlite3ValueFree((sqlite3_value*)p4);
    ++      }else{
    ++        freeP4Mem(db, (Mem*)p4);
    +       }
    ++      break;
    ++    }
    ++    case P4_VTAB : {
    ++      if( db->pnBytesFreed==0 ) sqlite3VtabUnlock((VTable *)p4);
    ++      break;
    +     }
    +   }
    + }
    +@@ -67497,14 +73868,14 @@ static void freeP4(sqlite3 *db, int p4type, void *p4){
    + static void vdbeFreeOpArray(sqlite3 *db, Op *aOp, int nOp){
    +   if( aOp ){
    +     Op *pOp;
    +-    for(pOp=aOp; pOp<&aOp[nOp]; pOp++){
    +-      freeP4(db, pOp->p4type, pOp->p4.p);
    ++    for(pOp=&aOp[nOp-1]; pOp>=aOp; pOp--){
    ++      if( pOp->p4type <= P4_FREE_IF_LE ) freeP4(db, pOp->p4type, pOp->p4.p);
    + #ifdef SQLITE_ENABLE_EXPLAIN_COMMENTS
    +       sqlite3DbFree(db, pOp->zComment);
    + #endif     
    +     }
    ++    sqlite3DbFreeNN(db, aOp);
    +   }
    +-  sqlite3DbFree(db, aOp);
    + }
    + 
    + /*
    +@@ -67520,15 +73891,16 @@ 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( addr<p->nOp ){
    +-    VdbeOp *pOp = &p->aOp[addr];
    +-    sqlite3 *db = p->db;
    +-    freeP4(db, pOp->p4type, pOp->p4.p);
    +-    memset(pOp, 0, sizeof(pOp[0]));
    +-    pOp->opcode = OP_Noop;
    +-    if( addr==p->nOp-1 ) p->nOp--;
    +-  }
    ++SQLITE_PRIVATE int sqlite3VdbeChangeToNoop(Vdbe *p, int addr){
    ++  VdbeOp *pOp;
    ++  if( p->db->mallocFailed ) return 0;
    ++  assert( addr>=0 && addr<p->nOp );
    ++  pOp = &p->aOp[addr];
    ++  freeP4(p->db, pOp->p4type, pOp->p4.p);
    ++  pOp->p4type = P4_NOTUSED;
    ++  pOp->p4.z = 0;
    ++  pOp->opcode = OP_Noop;
    ++  return 1;
    + }
    + 
    + /*
    +@@ -67536,9 +73908,8 @@ SQLITE_PRIVATE void sqlite3VdbeChangeToNoop(Vdbe *p, int addr){
    + ** then remove it.  Return true if and only if an opcode was removed.
    + */
    + SQLITE_PRIVATE int sqlite3VdbeDeletePriorOpcode(Vdbe *p, u8 op){
    +-  if( (p->nOp-1)>(p->pParse->iFixedOp) && p->aOp[p->nOp-1].opcode==op ){
    +-    sqlite3VdbeChangeToNoop(p, p->nOp-1);
    +-    return 1;
    ++  if( p->nOp>0 && p->aOp[p->nOp-1].opcode==op ){
    ++    return sqlite3VdbeChangeToNoop(p, p->nOp-1);
    +   }else{
    +     return 0;
    +   }
    +@@ -67561,16 +73932,34 @@ SQLITE_PRIVATE int sqlite3VdbeDeletePriorOpcode(Vdbe *p, u8 op){
    + **
    + ** If addr<0 then change P4 on the most recently inserted instruction.
    + */
    ++static void SQLITE_NOINLINE vdbeChangeP4Full(
    ++  Vdbe *p,
    ++  Op *pOp,
    ++  const char *zP4,
    ++  int n
    ++){
    ++  if( pOp->p4type ){
    ++    freeP4(p->db, pOp->p4type, pOp->p4.p);
    ++    pOp->p4type = 0;
    ++    pOp->p4.p = 0;
    ++  }
    ++  if( n<0 ){
    ++    sqlite3VdbeChangeP4(p, (int)(pOp - p->aOp), zP4, n);
    ++  }else{
    ++    if( n==0 ) n = sqlite3Strlen30(zP4);
    ++    pOp->p4.z = sqlite3DbStrNDup(p->db, zP4, n);
    ++    pOp->p4type = P4_DYNAMIC;
    ++  }
    ++}
    + SQLITE_PRIVATE void sqlite3VdbeChangeP4(Vdbe *p, int addr, const char *zP4, int n){
    +   Op *pOp;
    +   sqlite3 *db;
    +   assert( p!=0 );
    +   db = p->db;
    +   assert( p->magic==VDBE_MAGIC_INIT );
    +-  if( p->aOp==0 || db->mallocFailed ){
    +-    if( n!=P4_VTAB ){
    +-      freeP4(db, n, (void*)*(char**)&zP4);
    +-    }
    ++  assert( p->aOp!=0 || db->mallocFailed );
    ++  if( db->mallocFailed ){
    ++    if( n!=P4_VTAB ) freeP4(db, n, (void*)*(char**)&zP4);
    +     return;
    +   }
    +   assert( p->nOp>0 );
    +@@ -67579,34 +73968,45 @@ 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
    +-       || pOp->p4type==P4_KEYINFO );
    +-  freeP4(db, pOp->p4type, pOp->p4.p);
    +-  pOp->p4.p = 0;
    ++  if( n>=0 || pOp->p4type ){
    ++    vdbeChangeP4Full(p, pOp, zP4, n);
    ++    return;
    ++  }
    +   if( n==P4_INT32 ){
    +     /* Note: this cast is safe, because the origin data point was an int
    +     ** that was cast to a (const char *). */
    +     pOp->p4.i = SQLITE_PTR_TO_INT(zP4);
    +     pOp->p4type = P4_INT32;
    +-  }else if( zP4==0 ){
    +-    pOp->p4.p = 0;
    +-    pOp->p4type = P4_NOTUSED;
    +-  }else if( n==P4_KEYINFO ){
    +-    pOp->p4.p = (void*)zP4;
    +-    pOp->p4type = P4_KEYINFO;
    +-  }else if( n==P4_VTAB ){
    +-    pOp->p4.p = (void*)zP4;
    +-    pOp->p4type = P4_VTAB;
    +-    sqlite3VtabLock((VTable *)zP4);
    +-    assert( ((VTable *)zP4)->db==p->db );
    +-  }else if( n<0 ){
    ++  }else if( zP4!=0 ){
    ++    assert( n<0 );
    +     pOp->p4.p = (void*)zP4;
    +     pOp->p4type = (signed char)n;
    ++    if( n==P4_VTAB ) sqlite3VtabLock((VTable*)zP4);
    ++  }
    ++}
    ++
    ++/*
    ++** Change the P4 operand of the most recently coded instruction 
    ++** to the value defined by the arguments.  This is a high-speed
    ++** version of sqlite3VdbeChangeP4().
    ++**
    ++** The P4 operand must not have been previously defined.  And the new
    ++** P4 must not be P4_INT32.  Use sqlite3VdbeChangeP4() in either of
    ++** those cases.
    ++*/
    ++SQLITE_PRIVATE void sqlite3VdbeAppendP4(Vdbe *p, void *pP4, int n){
    ++  VdbeOp *pOp;
    ++  assert( n!=P4_INT32 && n!=P4_VTAB );
    ++  assert( n<=0 );
    ++  if( p->db->mallocFailed ){
    ++    freeP4(p->db, n, pP4);
    +   }else{
    +-    if( n==0 ) n = sqlite3Strlen30(zP4);
    +-    pOp->p4.z = sqlite3DbStrNDup(p->db, zP4, n);
    +-    pOp->p4type = P4_DYNAMIC;
    ++    assert( pP4!=0 );
    ++    assert( p->nOp>0 );
    ++    pOp = &p->aOp[p->nOp-1];
    ++    assert( pOp->p4type==P4_NOTUSED );
    ++    pOp->p4type = n;
    ++    pOp->p4.p = pP4;
    +   }
    + }
    + 
    +@@ -67616,10 +74016,11 @@ SQLITE_PRIVATE void sqlite3VdbeChangeP4(Vdbe *p, int addr, const char *zP4, int
    + */
    + SQLITE_PRIVATE void sqlite3VdbeSetP4KeyInfo(Parse *pParse, Index *pIdx){
    +   Vdbe *v = pParse->pVdbe;
    ++  KeyInfo *pKeyInfo;
    +   assert( v!=0 );
    +   assert( pIdx!=0 );
    +-  sqlite3VdbeChangeP4(v, -1, (char*)sqlite3KeyInfoOfIndex(pParse, pIdx),
    +-                      P4_KEYINFO);
    ++  pKeyInfo = sqlite3KeyInfoOfIndex(pParse, pIdx);
    ++  if( pKeyInfo ) sqlite3VdbeAppendP4(v, pKeyInfo, P4_KEYINFO);
    + }
    + 
    + #ifdef SQLITE_ENABLE_EXPLAIN_COMMENTS
    +@@ -67731,12 +74132,21 @@ static int displayComment(
    +   const char *zSynopsis;
    +   int nOpName;
    +   int ii, jj;
    ++  char zAlt[50];
    +   zOpName = sqlite3OpcodeName(pOp->opcode);
    +   nOpName = sqlite3Strlen30(zOpName);
    +   if( zOpName[nOpName+1] ){
    +     int seenCom = 0;
    +     char c;
    +     zSynopsis = zOpName += nOpName + 1;
    ++    if( strncmp(zSynopsis,"IF ",3)==0 ){
    ++      if( pOp->p5 & SQLITE_STOREP2 ){
    ++        sqlite3_snprintf(sizeof(zAlt), zAlt, "r[P2] = (%s)", zSynopsis+3);
    ++      }else{
    ++        sqlite3_snprintf(sizeof(zAlt), zAlt, "if %s goto P2", zSynopsis+3);
    ++      }
    ++      zSynopsis = zAlt;
    ++    }
    +     for(ii=jj=0; jj<nTemp-1 && (c = zSynopsis[ii])!=0; ii++){
    +       if( c=='P' ){
    +         c = zSynopsis[++ii];
    +@@ -67785,75 +74195,138 @@ static int displayComment(
    + }
    + #endif /* SQLITE_DEBUG */
    + 
    ++#if VDBE_DISPLAY_P4 && defined(SQLITE_ENABLE_CURSOR_HINTS)
    ++/*
    ++** Translate the P4.pExpr value for an OP_CursorHint opcode into text
    ++** that can be displayed in the P4 column of EXPLAIN output.
    ++*/
    ++static void displayP4Expr(StrAccum *p, Expr *pExpr){
    ++  const char *zOp = 0;
    ++  switch( pExpr->op ){
    ++    case TK_STRING:
    ++      sqlite3XPrintf(p, "%Q", pExpr->u.zToken);
    ++      break;
    ++    case TK_INTEGER:
    ++      sqlite3XPrintf(p, "%d", pExpr->u.iValue);
    ++      break;
    ++    case TK_NULL:
    ++      sqlite3XPrintf(p, "NULL");
    ++      break;
    ++    case TK_REGISTER: {
    ++      sqlite3XPrintf(p, "r[%d]", pExpr->iTable);
    ++      break;
    ++    }
    ++    case TK_COLUMN: {
    ++      if( pExpr->iColumn<0 ){
    ++        sqlite3XPrintf(p, "rowid");
    ++      }else{
    ++        sqlite3XPrintf(p, "c%d", (int)pExpr->iColumn);
    ++      }
    ++      break;
    ++    }
    ++    case TK_LT:      zOp = "LT";      break;
    ++    case TK_LE:      zOp = "LE";      break;
    ++    case TK_GT:      zOp = "GT";      break;
    ++    case TK_GE:      zOp = "GE";      break;
    ++    case TK_NE:      zOp = "NE";      break;
    ++    case TK_EQ:      zOp = "EQ";      break;
    ++    case TK_IS:      zOp = "IS";      break;
    ++    case TK_ISNOT:   zOp = "ISNOT";   break;
    ++    case TK_AND:     zOp = "AND";     break;
    ++    case TK_OR:      zOp = "OR";      break;
    ++    case TK_PLUS:    zOp = "ADD";     break;
    ++    case TK_STAR:    zOp = "MUL";     break;
    ++    case TK_MINUS:   zOp = "SUB";     break;
    ++    case TK_REM:     zOp = "REM";     break;
    ++    case TK_BITAND:  zOp = "BITAND";  break;
    ++    case TK_BITOR:   zOp = "BITOR";   break;
    ++    case TK_SLASH:   zOp = "DIV";     break;
    ++    case TK_LSHIFT:  zOp = "LSHIFT";  break;
    ++    case TK_RSHIFT:  zOp = "RSHIFT";  break;
    ++    case TK_CONCAT:  zOp = "CONCAT";  break;
    ++    case TK_UMINUS:  zOp = "MINUS";   break;
    ++    case TK_UPLUS:   zOp = "PLUS";    break;
    ++    case TK_BITNOT:  zOp = "BITNOT";  break;
    ++    case TK_NOT:     zOp = "NOT";     break;
    ++    case TK_ISNULL:  zOp = "ISNULL";  break;
    ++    case TK_NOTNULL: zOp = "NOTNULL"; break;
    + 
    +-#if !defined(SQLITE_OMIT_EXPLAIN) || !defined(NDEBUG) \
    +-     || defined(VDBE_PROFILE) || defined(SQLITE_DEBUG)
    ++    default:
    ++      sqlite3XPrintf(p, "%s", "expr");
    ++      break;
    ++  }
    ++
    ++  if( zOp ){
    ++    sqlite3XPrintf(p, "%s(", zOp);
    ++    displayP4Expr(p, pExpr->pLeft);
    ++    if( pExpr->pRight ){
    ++      sqlite3StrAccumAppend(p, ",", 1);
    ++      displayP4Expr(p, pExpr->pRight);
    ++    }
    ++    sqlite3StrAccumAppend(p, ")", 1);
    ++  }
    ++}
    ++#endif /* VDBE_DISPLAY_P4 && defined(SQLITE_ENABLE_CURSOR_HINTS) */
    ++
    ++
    ++#if VDBE_DISPLAY_P4
    + /*
    + ** Compute a string that describes the P4 parameter for an opcode.
    + ** Use zTemp for any required temporary buffer space.
    + */
    + static char *displayP4(Op *pOp, char *zTemp, int nTemp){
    +   char *zP4 = zTemp;
    ++  StrAccum x;
    +   assert( nTemp>=20 );
    ++  sqlite3StrAccumInit(&x, 0, zTemp, nTemp, 0);
    +   switch( pOp->p4type ){
    +     case P4_KEYINFO: {
    +-      int i, j;
    ++      int j;
    +       KeyInfo *pKeyInfo = pOp->p4.pKeyInfo;
    +       assert( pKeyInfo->aSortOrder!=0 );
    +-      sqlite3_snprintf(nTemp, zTemp, "k(%d", pKeyInfo->nField);
    +-      i = sqlite3Strlen30(zTemp);
    +-      for(j=0; j<pKeyInfo->nField; j++){
    ++      sqlite3XPrintf(&x, "k(%d", pKeyInfo->nKeyField);
    ++      for(j=0; j<pKeyInfo->nKeyField; j++){
    +         CollSeq *pColl = pKeyInfo->aColl[j];
    +-        const char *zColl = pColl ? pColl->zName : "nil";
    +-        int n = sqlite3Strlen30(zColl);
    +-        if( n==6 && memcmp(zColl,"BINARY",6)==0 ){
    +-          zColl = "B";
    +-          n = 1;
    +-        }
    +-        if( i+n>nTemp-7 ){
    +-          memcpy(&zTemp[i],",...",4);
    +-          i += 4;
    +-          break;
    +-        }
    +-        zTemp[i++] = ',';
    +-        if( pKeyInfo->aSortOrder[j] ){
    +-          zTemp[i++] = '-';
    +-        }
    +-        memcpy(&zTemp[i], zColl, n+1);
    +-        i += n;
    ++        const char *zColl = pColl ? pColl->zName : "";
    ++        if( strcmp(zColl, "BINARY")==0 ) zColl = "B";
    ++        sqlite3XPrintf(&x, ",%s%s", pKeyInfo->aSortOrder[j] ? "-" : "", zColl);
    +       }
    +-      zTemp[i++] = ')';
    +-      zTemp[i] = 0;
    +-      assert( i<nTemp );
    ++      sqlite3StrAccumAppend(&x, ")", 1);
    ++      break;
    ++    }
    ++#ifdef SQLITE_ENABLE_CURSOR_HINTS
    ++    case P4_EXPR: {
    ++      displayP4Expr(&x, pOp->p4.pExpr);
    +       break;
    +     }
    ++#endif
    +     case P4_COLLSEQ: {
    +       CollSeq *pColl = pOp->p4.pColl;
    +-      sqlite3_snprintf(nTemp, zTemp, "(%.20s)", pColl->zName);
    ++      sqlite3XPrintf(&x, "(%.20s)", pColl->zName);
    +       break;
    +     }
    +     case P4_FUNCDEF: {
    +       FuncDef *pDef = pOp->p4.pFunc;
    +-      sqlite3_snprintf(nTemp, zTemp, "%s(%d)", pDef->zName, pDef->nArg);
    ++      sqlite3XPrintf(&x, "%s(%d)", pDef->zName, pDef->nArg);
    +       break;
    +     }
    +-#ifdef SQLITE_DEBUG
    ++#if defined(SQLITE_DEBUG) || defined(VDBE_PROFILE)
    +     case P4_FUNCCTX: {
    +       FuncDef *pDef = pOp->p4.pCtx->pFunc;
    +-      sqlite3_snprintf(nTemp, zTemp, "%s(%d)", pDef->zName, pDef->nArg);
    ++      sqlite3XPrintf(&x, "%s(%d)", pDef->zName, pDef->nArg);
    +       break;
    +     }
    + #endif
    +     case P4_INT64: {
    +-      sqlite3_snprintf(nTemp, zTemp, "%lld", *pOp->p4.pI64);
    ++      sqlite3XPrintf(&x, "%lld", *pOp->p4.pI64);
    +       break;
    +     }
    +     case P4_INT32: {
    +-      sqlite3_snprintf(nTemp, zTemp, "%d", pOp->p4.i);
    ++      sqlite3XPrintf(&x, "%d", pOp->p4.i);
    +       break;
    +     }
    +     case P4_REAL: {
    +-      sqlite3_snprintf(nTemp, zTemp, "%.16g", *pOp->p4.pReal);
    ++      sqlite3XPrintf(&x, "%.16g", *pOp->p4.pReal);
    +       break;
    +     }
    +     case P4_MEM: {
    +@@ -67861,11 +74334,11 @@ static char *displayP4(Op *pOp, char *zTemp, int nTemp){
    +       if( pMem->flags & MEM_Str ){
    +         zP4 = pMem->z;
    +       }else if( pMem->flags & MEM_Int ){
    +-        sqlite3_snprintf(nTemp, zTemp, "%lld", pMem->u.i);
    ++        sqlite3XPrintf(&x, "%lld", pMem->u.i);
    +       }else if( pMem->flags & MEM_Real ){
    +-        sqlite3_snprintf(nTemp, zTemp, "%.16g", pMem->u.r);
    ++        sqlite3XPrintf(&x, "%.16g", pMem->u.r);
    +       }else if( pMem->flags & MEM_Null ){
    +-        sqlite3_snprintf(nTemp, zTemp, "NULL");
    ++        zP4 = "NULL";
    +       }else{
    +         assert( pMem->flags & MEM_Blob );
    +         zP4 = "(blob)";
    +@@ -67875,22 +74348,35 @@ static char *displayP4(Op *pOp, char *zTemp, int nTemp){
    + #ifndef SQLITE_OMIT_VIRTUALTABLE
    +     case P4_VTAB: {
    +       sqlite3_vtab *pVtab = pOp->p4.pVtab->pVtab;
    +-      sqlite3_snprintf(nTemp, zTemp, "vtab:%p", pVtab);
    ++      sqlite3XPrintf(&x, "vtab:%p", pVtab);
    +       break;
    +     }
    + #endif
    +     case P4_INTARRAY: {
    +-      sqlite3_snprintf(nTemp, zTemp, "intarray");
    ++      int i;
    ++      int *ai = pOp->p4.ai;
    ++      int n = ai[0];   /* The first element of an INTARRAY is always the
    ++                       ** count of the number of elements to follow */
    ++      for(i=1; i<=n; i++){
    ++        sqlite3XPrintf(&x, ",%d", ai[i]);
    ++      }
    ++      zTemp[0] = '[';
    ++      sqlite3StrAccumAppend(&x, "]", 1);
    +       break;
    +     }
    +     case P4_SUBPROGRAM: {
    +-      sqlite3_snprintf(nTemp, zTemp, "program");
    ++      sqlite3XPrintf(&x, "program");
    +       break;
    +     }
    ++    case P4_DYNBLOB:
    +     case P4_ADVANCE: {
    +       zTemp[0] = 0;
    +       break;
    +     }
    ++    case P4_TABLE: {
    ++      sqlite3XPrintf(&x, "%s", pOp->p4.pTab->zName);
    ++      break;
    ++    }
    +     default: {
    +       zP4 = pOp->p4.z;
    +       if( zP4==0 ){
    +@@ -67899,10 +74385,11 @@ static char *displayP4(Op *pOp, char *zTemp, int nTemp){
    +       }
    +     }
    +   }
    ++  sqlite3StrAccumFinish(&x);
    +   assert( zP4!=0 );
    +   return zP4;
    + }
    +-#endif
    ++#endif /* VDBE_DISPLAY_P4 */
    + 
    + /*
    + ** Declare to the Vdbe that the BTree object at db->aDb[i] is used.
    +@@ -67921,7 +74408,7 @@ SQLITE_PRIVATE void sqlite3VdbeUsesBtree(Vdbe *p, int i){
    +   }
    + }
    + 
    +-#if !defined(SQLITE_OMIT_SHARED_CACHE) && SQLITE_THREADSAFE>0
    ++#if !defined(SQLITE_OMIT_SHARED_CACHE)
    + /*
    + ** If SQLite is compiled to support shared-cache mode and to be threadsafe,
    + ** this routine obtains the mutex associated with each BtShared structure
    +@@ -68011,6 +74498,21 @@ SQLITE_PRIVATE void sqlite3VdbePrintOp(FILE *pOut, int pc, Op *pOp){
    + }
    + #endif
    + 
    ++/*
    ++** Initialize an array of N Mem element.
    ++*/
    ++static void initMemArray(Mem *p, int N, sqlite3 *db, u16 flags){
    ++  while( (N--)>0 ){
    ++    p->db = db;
    ++    p->flags = flags;
    ++    p->szMalloc = 0;
    ++#ifdef SQLITE_DEBUG
    ++    p->pScopyFrom = 0;
    ++#endif
    ++    p++;
    ++  }
    ++}
    ++
    + /*
    + ** Release an array of N Mem elements
    + */
    +@@ -68018,7 +74520,6 @@ static void releaseMemArray(Mem *p, int N){
    +   if( p && N ){
    +     Mem *pEnd = &p[N];
    +     sqlite3 *db = p->db;
    +-    u8 malloc_failed = db->mallocFailed;
    +     if( db->pnBytesFreed ){
    +       do{
    +         if( p->szMalloc ) sqlite3DbFree(db, p->zMalloc);
    +@@ -68048,13 +74549,12 @@ static void releaseMemArray(Mem *p, int N){
    +       if( p->flags&(MEM_Agg|MEM_Dyn|MEM_Frame|MEM_RowSet) ){
    +         sqlite3VdbeMemRelease(p);
    +       }else if( p->szMalloc ){
    +-        sqlite3DbFree(db, p->zMalloc);
    ++        sqlite3DbFreeNN(db, p->zMalloc);
    +         p->szMalloc = 0;
    +       }
    + 
    +       p->flags = MEM_Undefined;
    +     }while( (++p)<pEnd );
    +-    db->mallocFailed = malloc_failed;
    +   }
    + }
    + 
    +@@ -68070,6 +74570,7 @@ SQLITE_PRIVATE void sqlite3VdbeFrameDelete(VdbeFrame *p){
    +     sqlite3VdbeFreeCursor(p->v, apCsr[i]);
    +   }
    +   releaseMemArray(aMem, p->nChildMem);
    ++  sqlite3VdbeDeleteAuxData(p->v->db, &p->pAuxData, -1, 0);
    +   sqlite3DbFree(p->v->db, p);
    + }
    + 
    +@@ -68100,6 +74601,8 @@ SQLITE_PRIVATE int sqlite3VdbeList(
    +   int i;                               /* Loop counter */
    +   int rc = SQLITE_OK;                  /* Return code */
    +   Mem *pMem = &p->aMem[1];             /* First Mem of result set */
    ++  int bListSubprogs = (p->explain==1 || (db->flags & SQLITE_TriggerEQP)!=0);
    ++  Op *pOp = 0;
    + 
    +   assert( p->explain );
    +   assert( p->magic==VDBE_MAGIC_RUN );
    +@@ -68115,7 +74618,7 @@ SQLITE_PRIVATE int sqlite3VdbeList(
    +   if( p->rc==SQLITE_NOMEM ){
    +     /* This happens if a malloc() inside a call to sqlite3_column_text() or
    +     ** sqlite3_column_text16() failed.  */
    +-    db->mallocFailed = 1;
    ++    sqlite3OomFault(db);
    +     return SQLITE_ERROR;
    +   }
    + 
    +@@ -68127,7 +74630,7 @@ SQLITE_PRIVATE int sqlite3VdbeList(
    +   ** encountered, but p->pc will eventually catch up to nRow.
    +   */
    +   nRow = p->nOp;
    +-  if( p->explain==1 ){
    ++  if( bListSubprogs ){
    +     /* The first 8 memory cells are used for the result set.  So we will
    +     ** commandeer the 9th cell to use as storage for an array of pointers
    +     ** to trigger subprograms.  The VDBE is guaranteed to have at least 9
    +@@ -68147,17 +74650,11 @@ SQLITE_PRIVATE int sqlite3VdbeList(
    + 
    +   do{
    +     i = p->pc++;
    +-  }while( i<nRow && p->explain==2 && p->aOp[i].opcode!=OP_Explain );
    +-  if( i>=nRow ){
    +-    p->rc = SQLITE_OK;
    +-    rc = SQLITE_DONE;
    +-  }else if( db->u1.isInterrupted ){
    +-    p->rc = SQLITE_INTERRUPT;
    +-    rc = SQLITE_ERROR;
    +-    sqlite3VdbeError(p, sqlite3ErrStr(p->rc));
    +-  }else{
    +-    char *zP4;
    +-    Op *pOp;
    ++    if( i>=nRow ){
    ++      p->rc = SQLITE_OK;
    ++      rc = SQLITE_DONE;
    ++      break;
    ++    }
    +     if( i<p->nOp ){
    +       /* The output line number is small enough that we are still in the
    +       ** main program. */
    +@@ -68172,93 +74669,110 @@ SQLITE_PRIVATE int sqlite3VdbeList(
    +       }
    +       pOp = &apSub[j]->aOp[i];
    +     }
    +-    if( p->explain==1 ){
    +-      pMem->flags = MEM_Int;
    +-      pMem->u.i = i;                                /* Program counter */
    +-      pMem++;
    +-  
    +-      pMem->flags = MEM_Static|MEM_Str|MEM_Term;
    +-      pMem->z = (char*)sqlite3OpcodeName(pOp->opcode); /* Opcode */
    +-      assert( pMem->z!=0 );
    +-      pMem->n = sqlite3Strlen30(pMem->z);
    +-      pMem->enc = SQLITE_UTF8;
    +-      pMem++;
    + 
    +-      /* When an OP_Program opcode is encounter (the only opcode that has
    +-      ** a P4_SUBPROGRAM argument), expand the size of the array of subprograms
    +-      ** kept in p->aMem[9].z to hold the new program - assuming this subprogram
    +-      ** has not already been seen.
    +-      */
    +-      if( pOp->p4type==P4_SUBPROGRAM ){
    +-        int nByte = (nSub+1)*sizeof(SubProgram*);
    +-        int j;
    +-        for(j=0; j<nSub; j++){
    +-          if( apSub[j]==pOp->p4.pProgram ) break;
    +-        }
    +-        if( j==nSub && SQLITE_OK==sqlite3VdbeMemGrow(pSub, nByte, nSub!=0) ){
    +-          apSub = (SubProgram **)pSub->z;
    +-          apSub[nSub++] = pOp->p4.pProgram;
    +-          pSub->flags |= MEM_Blob;
    +-          pSub->n = nSub*sizeof(SubProgram*);
    ++    /* When an OP_Program opcode is encounter (the only opcode that has
    ++    ** a P4_SUBPROGRAM argument), expand the size of the array of subprograms
    ++    ** kept in p->aMem[9].z to hold the new program - assuming this subprogram
    ++    ** has not already been seen.
    ++    */
    ++    if( bListSubprogs && pOp->p4type==P4_SUBPROGRAM ){
    ++      int nByte = (nSub+1)*sizeof(SubProgram*);
    ++      int j;
    ++      for(j=0; j<nSub; j++){
    ++        if( apSub[j]==pOp->p4.pProgram ) break;
    ++      }
    ++      if( j==nSub ){
    ++        p->rc = sqlite3VdbeMemGrow(pSub, nByte, nSub!=0);
    ++        if( p->rc!=SQLITE_OK ){
    ++          rc = SQLITE_ERROR;
    ++          break;
    +         }
    ++        apSub = (SubProgram **)pSub->z;
    ++        apSub[nSub++] = pOp->p4.pProgram;
    ++        pSub->flags |= MEM_Blob;
    ++        pSub->n = nSub*sizeof(SubProgram*);
    ++        nRow += pOp->p4.pProgram->nOp;
    +       }
    +     }
    ++  }while( p->explain==2 && pOp->opcode!=OP_Explain );
    + 
    +-    pMem->flags = MEM_Int;
    +-    pMem->u.i = pOp->p1;                          /* P1 */
    +-    pMem++;
    ++  if( rc==SQLITE_OK ){
    ++    if( db->u1.isInterrupted ){
    ++      p->rc = SQLITE_INTERRUPT;
    ++      rc = SQLITE_ERROR;
    ++      sqlite3VdbeError(p, sqlite3ErrStr(p->rc));
    ++    }else{
    ++      char *zP4;
    ++      if( p->explain==1 ){
    ++        pMem->flags = MEM_Int;
    ++        pMem->u.i = i;                                /* Program counter */
    ++        pMem++;
    ++    
    ++        pMem->flags = MEM_Static|MEM_Str|MEM_Term;
    ++        pMem->z = (char*)sqlite3OpcodeName(pOp->opcode); /* Opcode */
    ++        assert( pMem->z!=0 );
    ++        pMem->n = sqlite3Strlen30(pMem->z);
    ++        pMem->enc = SQLITE_UTF8;
    ++        pMem++;
    ++      }
    + 
    +-    pMem->flags = MEM_Int;
    +-    pMem->u.i = pOp->p2;                          /* P2 */
    +-    pMem++;
    ++      pMem->flags = MEM_Int;
    ++      pMem->u.i = pOp->p1;                          /* P1 */
    ++      pMem++;
    + 
    +-    pMem->flags = MEM_Int;
    +-    pMem->u.i = pOp->p3;                          /* P3 */
    +-    pMem++;
    ++      pMem->flags = MEM_Int;
    ++      pMem->u.i = pOp->p2;                          /* P2 */
    ++      pMem++;
    + 
    +-    if( sqlite3VdbeMemClearAndResize(pMem, 32) ){ /* P4 */
    +-      assert( p->db->mallocFailed );
    +-      return SQLITE_ERROR;
    +-    }
    +-    pMem->flags = MEM_Str|MEM_Term;
    +-    zP4 = displayP4(pOp, pMem->z, 32);
    +-    if( zP4!=pMem->z ){
    +-      sqlite3VdbeMemSetStr(pMem, zP4, -1, SQLITE_UTF8, 0);
    +-    }else{
    +-      assert( pMem->z!=0 );
    +-      pMem->n = sqlite3Strlen30(pMem->z);
    +-      pMem->enc = SQLITE_UTF8;
    +-    }
    +-    pMem++;
    ++      pMem->flags = MEM_Int;
    ++      pMem->u.i = pOp->p3;                          /* P3 */
    ++      pMem++;
    + 
    +-    if( p->explain==1 ){
    +-      if( sqlite3VdbeMemClearAndResize(pMem, 4) ){
    ++      if( sqlite3VdbeMemClearAndResize(pMem, 100) ){ /* P4 */
    +         assert( p->db->mallocFailed );
    +         return SQLITE_ERROR;
    +       }
    +       pMem->flags = MEM_Str|MEM_Term;
    +-      pMem->n = 2;
    +-      sqlite3_snprintf(3, pMem->z, "%.2x", pOp->p5);   /* P5 */
    +-      pMem->enc = SQLITE_UTF8;
    ++      zP4 = displayP4(pOp, pMem->z, pMem->szMalloc);
    ++      if( zP4!=pMem->z ){
    ++        pMem->n = 0;
    ++        sqlite3VdbeMemSetStr(pMem, zP4, -1, SQLITE_UTF8, 0);
    ++      }else{
    ++        assert( pMem->z!=0 );
    ++        pMem->n = sqlite3Strlen30(pMem->z);
    ++        pMem->enc = SQLITE_UTF8;
    ++      }
    +       pMem++;
    +-  
    ++
    ++      if( p->explain==1 ){
    ++        if( sqlite3VdbeMemClearAndResize(pMem, 4) ){
    ++          assert( p->db->mallocFailed );
    ++          return SQLITE_ERROR;
    ++        }
    ++        pMem->flags = MEM_Str|MEM_Term;
    ++        pMem->n = 2;
    ++        sqlite3_snprintf(3, pMem->z, "%.2x", pOp->p5);   /* P5 */
    ++        pMem->enc = SQLITE_UTF8;
    ++        pMem++;
    ++    
    + #ifdef SQLITE_ENABLE_EXPLAIN_COMMENTS
    +-      if( sqlite3VdbeMemClearAndResize(pMem, 500) ){
    +-        assert( p->db->mallocFailed );
    +-        return SQLITE_ERROR;
    +-      }
    +-      pMem->flags = MEM_Str|MEM_Term;
    +-      pMem->n = displayComment(pOp, zP4, pMem->z, 500);
    +-      pMem->enc = SQLITE_UTF8;
    ++        if( sqlite3VdbeMemClearAndResize(pMem, 500) ){
    ++          assert( p->db->mallocFailed );
    ++          return SQLITE_ERROR;
    ++        }
    ++        pMem->flags = MEM_Str|MEM_Term;
    ++        pMem->n = displayComment(pOp, zP4, pMem->z, 500);
    ++        pMem->enc = SQLITE_UTF8;
    + #else
    +-      pMem->flags = MEM_Null;                       /* Comment */
    ++        pMem->flags = MEM_Null;                       /* Comment */
    + #endif
    +-    }
    ++      }
    + 
    +-    p->nResColumn = 8 - 4*(p->explain-1);
    +-    p->pResultSet = &p->aMem[1];
    +-    p->rc = SQLITE_OK;
    +-    rc = SQLITE_ROW;
    ++      p->nResColumn = 8 - 4*(p->explain-1);
    ++      p->pResultSet = &p->aMem[1];
    ++      p->rc = SQLITE_OK;
    ++      rc = SQLITE_ROW;
    ++    }
    +   }
    +   return rc;
    + }
    +@@ -68313,43 +74827,46 @@ SQLITE_PRIVATE void sqlite3VdbeIOTraceSql(Vdbe *p){
    + }
    + #endif /* !SQLITE_OMIT_TRACE && SQLITE_ENABLE_IOTRACE */
    + 
    +-/*
    +-** Allocate space from a fixed size buffer and return a pointer to
    +-** that space.  If insufficient space is available, return NULL.
    +-**
    +-** The pBuf parameter is the initial value of a pointer which will
    +-** receive the new memory.  pBuf is normally NULL.  If pBuf is not
    +-** NULL, it means that memory space has already been allocated and that
    +-** this routine should not allocate any new memory.  When pBuf is not
    +-** NULL simply return pBuf.  Only allocate new memory space when pBuf
    +-** is NULL.
    +-**
    +-** nByte is the number of bytes of space needed.
    ++/* An instance of this object describes bulk memory available for use
    ++** by subcomponents of a prepared statement.  Space is allocated out
    ++** of a ReusableSpace object by the allocSpace() routine below.
    ++*/
    ++struct ReusableSpace {
    ++  u8 *pSpace;          /* Available memory */
    ++  int nFree;           /* Bytes of available memory */
    ++  int nNeeded;         /* Total bytes that could not be allocated */
    ++};
    ++
    ++/* Try to allocate nByte bytes of 8-byte aligned bulk memory for pBuf
    ++** from the ReusableSpace object.  Return a pointer to the allocated
    ++** memory on success.  If insufficient memory is available in the
    ++** ReusableSpace object, increase the ReusableSpace.nNeeded
    ++** value by the amount needed and return NULL.
    + **
    +-** *ppFrom points to available space and pEnd points to the end of the
    +-** available space.  When space is allocated, *ppFrom is advanced past
    +-** the end of the allocated space.
    ++** If pBuf is not initially NULL, that means that the memory has already
    ++** been allocated by a prior call to this routine, so just return a copy
    ++** of pBuf and leave ReusableSpace unchanged.
    + **
    +-** *pnByte is a counter of the number of bytes of space that have failed
    +-** to allocate.  If there is insufficient space in *ppFrom to satisfy the
    +-** request, then increment *pnByte by the amount of the request.
    ++** This allocator is employed to repurpose unused slots at the end of the
    ++** opcode array of prepared state for other memory needs of the prepared
    ++** statement.
    + */
    + static void *allocSpace(
    +-  void *pBuf,          /* Where return pointer will be stored */
    +-  int nByte,           /* Number of bytes to allocate */
    +-  u8 **ppFrom,         /* IN/OUT: Allocate from *ppFrom */
    +-  u8 *pEnd,            /* Pointer to 1 byte past the end of *ppFrom buffer */
    +-  int *pnByte          /* If allocation cannot be made, increment *pnByte */
    +-){
    +-  assert( EIGHT_BYTE_ALIGNMENT(*ppFrom) );
    +-  if( pBuf ) return pBuf;
    +-  nByte = ROUND8(nByte);
    +-  if( &(*ppFrom)[nByte] <= pEnd ){
    +-    pBuf = (void*)*ppFrom;
    +-    *ppFrom += nByte;
    +-  }else{
    +-    *pnByte += nByte;
    ++  struct ReusableSpace *p,  /* Bulk memory available for allocation */
    ++  void *pBuf,               /* Pointer to a prior allocation */
    ++  int nByte                 /* Bytes of memory needed */
    ++){
    ++  assert( EIGHT_BYTE_ALIGNMENT(p->pSpace) );
    ++  if( pBuf==0 ){
    ++    nByte = ROUND8(nByte);
    ++    if( nByte <= p->nFree ){
    ++      p->nFree -= nByte;
    ++      pBuf = &p->pSpace[p->nFree];
    ++    }else{
    ++      p->nNeeded += nByte;
    ++    }
    +   }
    ++  assert( EIGHT_BYTE_ALIGNMENT(pBuf) );
    +   return pBuf;
    + }
    + 
    +@@ -68362,7 +74879,7 @@ SQLITE_PRIVATE void sqlite3VdbeRewind(Vdbe *p){
    +   int i;
    + #endif
    +   assert( p!=0 );
    +-  assert( p->magic==VDBE_MAGIC_INIT );
    ++  assert( p->magic==VDBE_MAGIC_INIT || p->magic==VDBE_MAGIC_RESET );
    + 
    +   /* There should be at least one opcode.
    +   */
    +@@ -68372,14 +74889,13 @@ SQLITE_PRIVATE void sqlite3VdbeRewind(Vdbe *p){
    +   p->magic = VDBE_MAGIC_RUN;
    + 
    + #ifdef SQLITE_DEBUG
    +-  for(i=1; i<p->nMem; i++){
    ++  for(i=0; i<p->nMem; i++){
    +     assert( p->aMem[i].db==p->db );
    +   }
    + #endif
    +   p->pc = -1;
    +   p->rc = SQLITE_OK;
    +   p->errorAction = OE_Abort;
    +-  p->magic = VDBE_MAGIC_RUN;
    +   p->nChange = 0;
    +   p->cacheCtr = 1;
    +   p->minWriteFileFormat = 255;
    +@@ -68420,11 +74936,8 @@ SQLITE_PRIVATE void sqlite3VdbeMakeReady(
    +   int nMem;                      /* Number of VM memory registers */
    +   int nCursor;                   /* Number of cursors required */
    +   int nArg;                      /* Number of arguments in subprograms */
    +-  int nOnce;                     /* Number of OP_Once instructions */
    +   int n;                         /* Loop counter */
    +-  u8 *zCsr;                      /* Memory available for allocation */
    +-  u8 *zEnd;                      /* First byte past allocated memory */
    +-  int nByte;                     /* How much extra memory is needed */
    ++  struct ReusableSpace x;        /* Reusable bulk memory */
    + 
    +   assert( p!=0 );
    +   assert( p->nOp>0 );
    +@@ -68437,88 +74950,75 @@ SQLITE_PRIVATE void sqlite3VdbeMakeReady(
    +   nMem = pParse->nMem;
    +   nCursor = pParse->nTab;
    +   nArg = pParse->nMaxArg;
    +-  nOnce = pParse->nOnce;
    +-  if( nOnce==0 ) nOnce = 1; /* Ensure at least one byte in p->aOnceFlag[] */
    +   
    +-  /* For each cursor required, also allocate a memory cell. Memory
    +-  ** cells (nMem+1-nCursor)..nMem, inclusive, will never be used by
    +-  ** the vdbe program. Instead they are used to allocate space for
    +-  ** VdbeCursor/BtCursor structures. The blob of memory associated with 
    +-  ** cursor 0 is stored in memory cell nMem. Memory cell (nMem-1)
    +-  ** stores the blob of memory associated with cursor 1, etc.
    +-  **
    ++  /* Each cursor uses a memory cell.  The first cursor (cursor 0) can
    ++  ** use aMem[0] which is not otherwise used by the VDBE program.  Allocate
    ++  ** space at the end of aMem[] for cursors 1 and greater.
    +   ** See also: allocateCursor().
    +   */
    +   nMem += nCursor;
    ++  if( nCursor==0 && nMem>0 ) nMem++;  /* Space for aMem[0] even if not used */
    + 
    +-  /* Allocate space for memory registers, SQL variables, VDBE cursors and 
    +-  ** an array to marshal SQL function arguments in.
    ++  /* Figure out how much reusable memory is available at the end of the
    ++  ** opcode array.  This extra memory will be reallocated for other elements
    ++  ** of the prepared statement.
    +   */
    +-  zCsr = (u8*)&p->aOp[p->nOp];            /* Memory avaliable for allocation */
    +-  zEnd = (u8*)&p->aOp[pParse->nOpAlloc];  /* First byte past end of zCsr[] */
    ++  n = ROUND8(sizeof(Op)*p->nOp);              /* Bytes of opcode memory used */
    ++  x.pSpace = &((u8*)p->aOp)[n];               /* Unused opcode memory */
    ++  assert( EIGHT_BYTE_ALIGNMENT(x.pSpace) );
    ++  x.nFree = ROUNDDOWN8(pParse->szOpAlloc - n);  /* Bytes of unused memory */
    ++  assert( x.nFree>=0 );
    ++  assert( EIGHT_BYTE_ALIGNMENT(&x.pSpace[x.nFree]) );
    + 
    +   resolveP2Values(p, &nArg);
    +   p->usesStmtJournal = (u8)(pParse->isMultiWrite && pParse->mayAbort);
    +   if( pParse->explain && nMem<10 ){
    +     nMem = 10;
    +   }
    +-  memset(zCsr, 0, zEnd-zCsr);
    +-  zCsr += (zCsr - (u8*)0)&7;
    +-  assert( EIGHT_BYTE_ALIGNMENT(zCsr) );
    +   p->expired = 0;
    + 
    +-  /* Memory for registers, parameters, cursor, etc, is allocated in two
    +-  ** passes.  On the first pass, we try to reuse unused space at the 
    ++  /* Memory for registers, parameters, cursor, etc, is allocated in one or two
    ++  ** passes.  On the first pass, we try to reuse unused memory at the 
    +   ** end of the opcode array.  If we are unable to satisfy all memory
    +   ** requirements by reusing the opcode array tail, then the second
    +-  ** pass will fill in the rest using a fresh allocation.  
    ++  ** pass will fill in the remainder using a fresh memory allocation.  
    +   **
    +   ** This two-pass approach that reuses as much memory as possible from
    +-  ** the leftover space at the end of the opcode array can significantly
    ++  ** the leftover memory at the end of the opcode array.  This can significantly
    +   ** reduce the amount of memory held by a prepared statement.
    +   */
    +   do {
    +-    nByte = 0;
    +-    p->aMem = allocSpace(p->aMem, nMem*sizeof(Mem), &zCsr, zEnd, &nByte);
    +-    p->aVar = allocSpace(p->aVar, nVar*sizeof(Mem), &zCsr, zEnd, &nByte);
    +-    p->apArg = allocSpace(p->apArg, nArg*sizeof(Mem*), &zCsr, zEnd, &nByte);
    +-    p->azVar = allocSpace(p->azVar, nVar*sizeof(char*), &zCsr, zEnd, &nByte);
    +-    p->apCsr = allocSpace(p->apCsr, nCursor*sizeof(VdbeCursor*),
    +-                          &zCsr, zEnd, &nByte);
    +-    p->aOnceFlag = allocSpace(p->aOnceFlag, nOnce, &zCsr, zEnd, &nByte);
    ++    x.nNeeded = 0;
    ++    p->aMem = allocSpace(&x, p->aMem, nMem*sizeof(Mem));
    ++    p->aVar = allocSpace(&x, p->aVar, nVar*sizeof(Mem));
    ++    p->apArg = allocSpace(&x, p->apArg, nArg*sizeof(Mem*));
    ++    p->apCsr = allocSpace(&x, p->apCsr, nCursor*sizeof(VdbeCursor*));
    + #ifdef SQLITE_ENABLE_STMT_SCANSTATUS
    +-    p->anExec = allocSpace(p->anExec, p->nOp*sizeof(i64), &zCsr, zEnd, &nByte);
    ++    p->anExec = allocSpace(&x, p->anExec, p->nOp*sizeof(i64));
    + #endif
    +-    if( nByte ){
    +-      p->pFree = sqlite3DbMallocZero(db, nByte);
    +-    }
    +-    zCsr = p->pFree;
    +-    zEnd = &zCsr[nByte];
    +-  }while( nByte && !db->mallocFailed );
    ++    if( x.nNeeded==0 ) break;
    ++    x.pSpace = p->pFree = sqlite3DbMallocRawNN(db, x.nNeeded);
    ++    x.nFree = x.nNeeded;
    ++  }while( !db->mallocFailed );
    + 
    +-  p->nCursor = nCursor;
    +-  p->nOnceFlag = nOnce;
    +-  if( p->aVar ){
    ++  p->pVList = pParse->pVList;
    ++  pParse->pVList =  0;
    ++  p->explain = pParse->explain;
    ++  if( db->mallocFailed ){
    ++    p->nVar = 0;
    ++    p->nCursor = 0;
    ++    p->nMem = 0;
    ++  }else{
    ++    p->nCursor = nCursor;
    +     p->nVar = (ynVar)nVar;
    +-    for(n=0; n<nVar; n++){
    +-      p->aVar[n].flags = MEM_Null;
    +-      p->aVar[n].db = db;
    +-    }
    +-  }
    +-  if( p->azVar && pParse->nzVar>0 ){
    +-    p->nzVar = pParse->nzVar;
    +-    memcpy(p->azVar, pParse->azVar, p->nzVar*sizeof(p->azVar[0]));
    +-    memset(pParse->azVar, 0, pParse->nzVar*sizeof(pParse->azVar[0]));
    +-  }
    +-  if( p->aMem ){
    +-    p->aMem--;                      /* aMem[] goes from 1..nMem */
    +-    p->nMem = nMem;                 /*       not from 0..nMem-1 */
    +-    for(n=1; n<=nMem; n++){
    +-      p->aMem[n].flags = MEM_Undefined;
    +-      p->aMem[n].db = db;
    +-    }
    ++    initMemArray(p->aVar, nVar, db, MEM_Null);
    ++    p->nMem = nMem;
    ++    initMemArray(p->aMem, nMem, db, MEM_Undefined);
    ++    memset(p->apCsr, 0, nCursor*sizeof(VdbeCursor*));
    ++#ifdef SQLITE_ENABLE_STMT_SCANSTATUS
    ++    memset(p->anExec, 0, p->nOp*sizeof(i64));
    ++#endif
    +   }
    +-  p->explain = pParse->explain;
    +   sqlite3VdbeRewind(p);
    + }
    + 
    +@@ -68530,23 +75030,34 @@ SQLITE_PRIVATE void sqlite3VdbeFreeCursor(Vdbe *p, VdbeCursor *pCx){
    +   if( pCx==0 ){
    +     return;
    +   }
    +-  sqlite3VdbeSorterClose(p->db, pCx);
    +-  if( pCx->pBt ){
    +-    sqlite3BtreeClose(pCx->pBt);
    +-    /* The pCx->pCursor will be close automatically, if it exists, by
    +-    ** the call above. */
    +-  }else if( pCx->pCursor ){
    +-    sqlite3BtreeCloseCursor(pCx->pCursor);
    +-  }
    ++  assert( pCx->pBtx==0 || pCx->eCurType==CURTYPE_BTREE );
    ++  switch( pCx->eCurType ){
    ++    case CURTYPE_SORTER: {
    ++      sqlite3VdbeSorterClose(p->db, pCx);
    ++      break;
    ++    }
    ++    case CURTYPE_BTREE: {
    ++      if( pCx->isEphemeral ){
    ++        if( pCx->pBtx ) sqlite3BtreeClose(pCx->pBtx);
    ++        /* The pCx->pCursor will be close automatically, if it exists, by
    ++        ** the call above. */
    ++      }else{
    ++        assert( pCx->uc.pCursor!=0 );
    ++        sqlite3BtreeCloseCursor(pCx->uc.pCursor);
    ++      }
    ++      break;
    ++    }
    + #ifndef SQLITE_OMIT_VIRTUALTABLE
    +-  else if( pCx->pVtabCursor ){
    +-    sqlite3_vtab_cursor *pVtabCursor = pCx->pVtabCursor;
    +-    const sqlite3_module *pModule = pVtabCursor->pVtab->pModule;
    +-    assert( pVtabCursor->pVtab->nRef>0 );
    +-    pVtabCursor->pVtab->nRef--;
    +-    pModule->xClose(pVtabCursor);
    +-  }
    ++    case CURTYPE_VTAB: {
    ++      sqlite3_vtab_cursor *pVCur = pCx->uc.pVCur;
    ++      const sqlite3_module *pModule = pVCur->pVtab->pModule;
    ++      assert( pVCur->pVtab->nRef>0 );
    ++      pVCur->pVtab->nRef--;
    ++      pModule->xClose(pVCur);
    ++      break;
    ++    }
    + #endif
    ++  }
    + }
    + 
    + /*
    +@@ -68576,8 +75087,6 @@ SQLITE_PRIVATE int sqlite3VdbeFrameRestore(VdbeFrame *pFrame){
    + #ifdef SQLITE_ENABLE_STMT_SCANSTATUS
    +   v->anExec = pFrame->anExec;
    + #endif
    +-  v->aOnceFlag = pFrame->aOnceFlag;
    +-  v->nOnceFlag = pFrame->nOnceFlag;
    +   v->aOp = pFrame->aOp;
    +   v->nOp = pFrame->nOp;
    +   v->aMem = pFrame->aMem;
    +@@ -68587,6 +75096,9 @@ SQLITE_PRIVATE int sqlite3VdbeFrameRestore(VdbeFrame *pFrame){
    +   v->db->lastRowid = pFrame->lastRowid;
    +   v->nChange = pFrame->nChange;
    +   v->db->nChange = pFrame->nDbChange;
    ++  sqlite3VdbeDeleteAuxData(v->db, &v->pAuxData, -1, 0);
    ++  v->pAuxData = pFrame->pAuxData;
    ++  pFrame->pAuxData = 0;
    +   return pFrame->pc;
    + }
    + 
    +@@ -68609,7 +75121,7 @@ static void closeAllCursors(Vdbe *p){
    +   assert( p->nFrame==0 );
    +   closeCursorsInFrame(p);
    +   if( p->aMem ){
    +-    releaseMemArray(&p->aMem[1], p->nMem);
    ++    releaseMemArray(p->aMem, p->nMem);
    +   }
    +   while( p->pDelFrame ){
    +     VdbeFrame *pDel = p->pDelFrame;
    +@@ -68618,31 +75130,10 @@ static void closeAllCursors(Vdbe *p){
    +   }
    + 
    +   /* Delete any auxdata allocations made by the VM */
    +-  if( p->pAuxData ) sqlite3VdbeDeleteAuxData(p, -1, 0);
    ++  if( p->pAuxData ) sqlite3VdbeDeleteAuxData(p->db, &p->pAuxData, -1, 0);
    +   assert( p->pAuxData==0 );
    + }
    + 
    +-/*
    +-** Clean up the VM after a single run.
    +-*/
    +-static void Cleanup(Vdbe *p){
    +-  sqlite3 *db = p->db;
    +-
    +-#ifdef SQLITE_DEBUG
    +-  /* Execute assert() statements to ensure that the Vdbe.apCsr[] and 
    +-  ** Vdbe.aMem[] arrays have already been cleaned up.  */
    +-  int i;
    +-  if( p->apCsr ) for(i=0; i<p->nCursor; i++) assert( p->apCsr[i]==0 );
    +-  if( p->aMem ){
    +-    for(i=1; i<=p->nMem; i++) assert( p->aMem[i].flags==MEM_Undefined );
    +-  }
    +-#endif
    +-
    +-  sqlite3DbFree(db, p->zErrMsg);
    +-  p->zErrMsg = 0;
    +-  p->pResultSet = 0;
    +-}
    +-
    + /*
    + ** Set the number of result columns that will be returned by this SQL
    + ** statement. This is now set at compile time, rather than during
    +@@ -68650,21 +75141,18 @@ static void Cleanup(Vdbe *p){
    + ** be called on an SQL statement before sqlite3_step().
    + */
    + SQLITE_PRIVATE void sqlite3VdbeSetNumCols(Vdbe *p, int nResColumn){
    +-  Mem *pColName;
    +   int n;
    +   sqlite3 *db = p->db;
    + 
    +-  releaseMemArray(p->aColName, p->nResColumn*COLNAME_N);
    +-  sqlite3DbFree(db, p->aColName);
    ++  if( p->nResColumn ){
    ++    releaseMemArray(p->aColName, p->nResColumn*COLNAME_N);
    ++    sqlite3DbFree(db, p->aColName);
    ++  }
    +   n = nResColumn*COLNAME_N;
    +   p->nResColumn = (u16)nResColumn;
    +-  p->aColName = pColName = (Mem*)sqlite3DbMallocZero(db, sizeof(Mem)*n );
    ++  p->aColName = (Mem*)sqlite3DbMallocRawNN(db, sizeof(Mem)*n );
    +   if( p->aColName==0 ) return;
    +-  while( n-- > 0 ){
    +-    pColName->flags = MEM_Null;
    +-    pColName->db = p->db;
    +-    pColName++;
    +-  }
    ++  initMemArray(p->aColName, n, db, MEM_Null);
    + }
    + 
    + /*
    +@@ -68690,7 +75178,7 @@ SQLITE_PRIVATE int sqlite3VdbeSetColName(
    +   assert( var<COLNAME_N );
    +   if( p->db->mallocFailed ){
    +     assert( !zName || xDel!=SQLITE_DYNAMIC );
    +-    return SQLITE_NOMEM;
    ++    return SQLITE_NOMEM_BKPT;
    +   }
    +   assert( p->aColName!=0 );
    +   pColName = &(p->aColName[idx+var*p->nResColumn]);
    +@@ -68707,7 +75195,9 @@ SQLITE_PRIVATE int sqlite3VdbeSetColName(
    + */
    + static int vdbeCommit(sqlite3 *db, Vdbe *p){
    +   int i;
    +-  int nTrans = 0;  /* Number of databases with an active write-transaction */
    ++  int nTrans = 0;  /* Number of databases with an active write-transaction
    ++                   ** that are candidates for a two-phase commit using a
    ++                   ** master-journal */
    +   int rc = SQLITE_OK;
    +   int needXcommit = 0;
    + 
    +@@ -68735,10 +75225,29 @@ static int vdbeCommit(sqlite3 *db, Vdbe *p){
    +   for(i=0; rc==SQLITE_OK && i<db->nDb; i++){ 
    +     Btree *pBt = db->aDb[i].pBt;
    +     if( sqlite3BtreeIsInTrans(pBt) ){
    ++      /* Whether or not a database might need a master journal depends upon
    ++      ** its journal mode (among other things).  This matrix determines which
    ++      ** journal modes use a master journal and which do not */
    ++      static const u8 aMJNeeded[] = {
    ++        /* DELETE   */  1,
    ++        /* PERSIST   */ 1,
    ++        /* OFF       */ 0,
    ++        /* TRUNCATE  */ 1,
    ++        /* MEMORY    */ 0,
    ++        /* WAL       */ 0
    ++      };
    ++      Pager *pPager;   /* Pager associated with pBt */
    +       needXcommit = 1;
    +-      if( i!=1 ) nTrans++;
    +       sqlite3BtreeEnter(pBt);
    +-      rc = sqlite3PagerExclusiveLock(sqlite3BtreePager(pBt));
    ++      pPager = sqlite3BtreePager(pBt);
    ++      if( db->aDb[i].safety_level!=PAGER_SYNCHRONOUS_OFF
    ++       && aMJNeeded[sqlite3PagerGetJournalMode(pPager)]
    ++       && sqlite3PagerIsMemdb(pPager)==0
    ++      ){ 
    ++        assert( i!=1 );
    ++        nTrans++;
    ++      }
    ++      rc = sqlite3PagerExclusiveLock(pPager);
    +       sqlite3BtreeLeave(pBt);
    +     }
    +   }
    +@@ -68796,7 +75305,6 @@ static int vdbeCommit(sqlite3 *db, Vdbe *p){
    + #ifndef SQLITE_OMIT_DISKIO
    +   else{
    +     sqlite3_vfs *pVfs = db->pVfs;
    +-    int needSync = 0;
    +     char *zMaster = 0;   /* File-name for the master journal */
    +     char const *zMainFile = sqlite3BtreeGetFilename(db->aDb[0].pBt);
    +     sqlite3_file *pMaster = 0;
    +@@ -68808,7 +75316,7 @@ static int vdbeCommit(sqlite3 *db, Vdbe *p){
    +     /* Select a master journal file name */
    +     nMainFile = sqlite3Strlen30(zMainFile);
    +     zMaster = sqlite3MPrintf(db, "%s-mjXXXXXX9XXz", zMainFile);
    +-    if( zMaster==0 ) return SQLITE_NOMEM;
    ++    if( zMaster==0 ) return SQLITE_NOMEM_BKPT;
    +     do {
    +       u32 iRandom;
    +       if( retryCount ){
    +@@ -68856,9 +75364,6 @@ static int vdbeCommit(sqlite3 *db, Vdbe *p){
    +           continue;  /* Ignore TEMP and :memory: databases */
    +         }
    +         assert( zFile[0]!=0 );
    +-        if( !needSync && !sqlite3BtreeSyncDisabled(pBt) ){
    +-          needSync = 1;
    +-        }
    +         rc = sqlite3OsWrite(pMaster, zFile, sqlite3Strlen30(zFile)+1, offset);
    +         offset += sqlite3Strlen30(zFile)+1;
    +         if( rc!=SQLITE_OK ){
    +@@ -68873,8 +75378,7 @@ static int vdbeCommit(sqlite3 *db, Vdbe *p){
    +     /* Sync the master journal file. If the IOCAP_SEQUENTIAL device
    +     ** flag is set this is not required.
    +     */
    +-    if( needSync 
    +-     && 0==(sqlite3OsDeviceCharacteristics(pMaster)&SQLITE_IOCAP_SEQUENTIAL)
    ++    if( 0==(sqlite3OsDeviceCharacteristics(pMaster)&SQLITE_IOCAP_SEQUENTIAL)
    +      && SQLITE_OK!=(rc = sqlite3OsSync(pMaster, SQLITE_SYNC_NORMAL))
    +     ){
    +       sqlite3OsCloseFree(pMaster);
    +@@ -68910,7 +75414,7 @@ static int vdbeCommit(sqlite3 *db, Vdbe *p){
    +     ** doing this the directory is synced again before any individual
    +     ** transaction files are deleted.
    +     */
    +-    rc = sqlite3OsDelete(pVfs, zMaster, needSync);
    ++    rc = sqlite3OsDelete(pVfs, zMaster, 1);
    +     sqlite3DbFree(db, zMaster);
    +     zMaster = 0;
    +     if( rc ){
    +@@ -68984,60 +75488,59 @@ static void checkActiveVdbeCnt(sqlite3 *db){
    + ** If an IO error occurs, an SQLITE_IOERR_XXX error code is returned. 
    + ** Otherwise SQLITE_OK.
    + */
    +-SQLITE_PRIVATE int sqlite3VdbeCloseStatement(Vdbe *p, int eOp){
    ++static SQLITE_NOINLINE int vdbeCloseStatement(Vdbe *p, int eOp){
    +   sqlite3 *const db = p->db;
    +   int rc = SQLITE_OK;
    ++  int i;
    ++  const int iSavepoint = p->iStatement-1;
    + 
    +-  /* If p->iStatement is greater than zero, then this Vdbe opened a 
    +-  ** statement transaction that should be closed here. The only exception
    +-  ** is that an IO error may have occurred, causing an emergency rollback.
    +-  ** In this case (db->nStatement==0), and there is nothing to do.
    +-  */
    +-  if( db->nStatement && p->iStatement ){
    +-    int i;
    +-    const int iSavepoint = p->iStatement-1;
    +-
    +-    assert( eOp==SAVEPOINT_ROLLBACK || eOp==SAVEPOINT_RELEASE);
    +-    assert( db->nStatement>0 );
    +-    assert( p->iStatement==(db->nStatement+db->nSavepoint) );
    +-
    +-    for(i=0; i<db->nDb; i++){ 
    +-      int rc2 = SQLITE_OK;
    +-      Btree *pBt = db->aDb[i].pBt;
    +-      if( pBt ){
    +-        if( eOp==SAVEPOINT_ROLLBACK ){
    +-          rc2 = sqlite3BtreeSavepoint(pBt, SAVEPOINT_ROLLBACK, iSavepoint);
    +-        }
    +-        if( rc2==SQLITE_OK ){
    +-          rc2 = sqlite3BtreeSavepoint(pBt, SAVEPOINT_RELEASE, iSavepoint);
    +-        }
    +-        if( rc==SQLITE_OK ){
    +-          rc = rc2;
    +-        }
    +-      }
    +-    }
    +-    db->nStatement--;
    +-    p->iStatement = 0;
    ++  assert( eOp==SAVEPOINT_ROLLBACK || eOp==SAVEPOINT_RELEASE);
    ++  assert( db->nStatement>0 );
    ++  assert( p->iStatement==(db->nStatement+db->nSavepoint) );
    + 
    +-    if( rc==SQLITE_OK ){
    ++  for(i=0; i<db->nDb; i++){ 
    ++    int rc2 = SQLITE_OK;
    ++    Btree *pBt = db->aDb[i].pBt;
    ++    if( pBt ){
    +       if( eOp==SAVEPOINT_ROLLBACK ){
    +-        rc = sqlite3VtabSavepoint(db, SAVEPOINT_ROLLBACK, iSavepoint);
    ++        rc2 = sqlite3BtreeSavepoint(pBt, SAVEPOINT_ROLLBACK, iSavepoint);
    ++      }
    ++      if( rc2==SQLITE_OK ){
    ++        rc2 = sqlite3BtreeSavepoint(pBt, SAVEPOINT_RELEASE, iSavepoint);
    +       }
    +       if( rc==SQLITE_OK ){
    +-        rc = sqlite3VtabSavepoint(db, SAVEPOINT_RELEASE, iSavepoint);
    ++        rc = rc2;
    +       }
    +     }
    ++  }
    ++  db->nStatement--;
    ++  p->iStatement = 0;
    + 
    +-    /* If the statement transaction is being rolled back, also restore the 
    +-    ** database handles deferred constraint counter to the value it had when 
    +-    ** the statement transaction was opened.  */
    ++  if( rc==SQLITE_OK ){
    +     if( eOp==SAVEPOINT_ROLLBACK ){
    +-      db->nDeferredCons = p->nStmtDefCons;
    +-      db->nDeferredImmCons = p->nStmtDefImmCons;
    ++      rc = sqlite3VtabSavepoint(db, SAVEPOINT_ROLLBACK, iSavepoint);
    +     }
    ++    if( rc==SQLITE_OK ){
    ++      rc = sqlite3VtabSavepoint(db, SAVEPOINT_RELEASE, iSavepoint);
    ++    }
    ++  }
    ++
    ++  /* If the statement transaction is being rolled back, also restore the 
    ++  ** database handles deferred constraint counter to the value it had when 
    ++  ** the statement transaction was opened.  */
    ++  if( eOp==SAVEPOINT_ROLLBACK ){
    ++    db->nDeferredCons = p->nStmtDefCons;
    ++    db->nDeferredImmCons = p->nStmtDefImmCons;
    +   }
    +   return rc;
    + }
    ++SQLITE_PRIVATE int sqlite3VdbeCloseStatement(Vdbe *p, int eOp){
    ++  if( p->db->nStatement && p->iStatement ){
    ++    return vdbeCloseStatement(p, eOp);
    ++  }
    ++  return SQLITE_OK;
    ++}
    ++
    + 
    + /*
    + ** This function is called when a transaction opened by the database 
    +@@ -69097,14 +75600,13 @@ SQLITE_PRIVATE int sqlite3VdbeHalt(Vdbe *p){
    +   ** one, or the complete transaction if there is no statement transaction.
    +   */
    + 
    +-  if( p->db->mallocFailed ){
    +-    p->rc = SQLITE_NOMEM;
    +-  }
    +-  if( p->aOnceFlag ) memset(p->aOnceFlag, 0, p->nOnceFlag);
    +-  closeAllCursors(p);
    +   if( p->magic!=VDBE_MAGIC_RUN ){
    +     return SQLITE_OK;
    +   }
    ++  if( db->mallocFailed ){
    ++    p->rc = SQLITE_NOMEM_BKPT;
    ++  }
    ++  closeAllCursors(p);
    +   checkActiveVdbeCnt(db);
    + 
    +   /* No commit or rollback needed if the program never started or if the
    +@@ -69258,8 +75760,8 @@ SQLITE_PRIVATE int sqlite3VdbeHalt(Vdbe *p){
    +   }
    +   p->magic = VDBE_MAGIC_HALT;
    +   checkActiveVdbeCnt(db);
    +-  if( p->db->mallocFailed ){
    +-    p->rc = SQLITE_NOMEM;
    ++  if( db->mallocFailed ){
    ++    p->rc = SQLITE_NOMEM_BKPT;
    +   }
    + 
    +   /* If the auto-commit flag is set to true, then any locks that were held
    +@@ -69295,16 +75797,16 @@ SQLITE_PRIVATE int sqlite3VdbeTransferError(Vdbe *p){
    +   sqlite3 *db = p->db;
    +   int rc = p->rc;
    +   if( p->zErrMsg ){
    +-    u8 mallocFailed = db->mallocFailed;
    ++    db->bBenignMalloc++;
    +     sqlite3BeginBenignMalloc();
    +     if( db->pErr==0 ) db->pErr = sqlite3ValueNew(db);
    +     sqlite3ValueSetStr(db->pErr, -1, p->zErrMsg, SQLITE_UTF8, SQLITE_TRANSIENT);
    +     sqlite3EndBenignMalloc();
    +-    db->mallocFailed = mallocFailed;
    +-    db->errCode = rc;
    +-  }else{
    +-    sqlite3Error(db, rc);
    ++    db->bBenignMalloc--;
    ++  }else if( db->pErr ){
    ++    sqlite3ValueSetNull(db->pErr);
    +   }
    ++  db->errCode = rc;
    +   return rc;
    + }
    + 
    +@@ -69341,6 +75843,10 @@ static void vdbeInvokeSqllog(Vdbe *v){
    + ** VDBE_MAGIC_INIT.
    + */
    + SQLITE_PRIVATE int sqlite3VdbeReset(Vdbe *p){
    ++#if defined(SQLITE_DEBUG) || defined(VDBE_PROFILE)
    ++  int i;
    ++#endif
    ++
    +   sqlite3 *db;
    +   db = p->db;
    + 
    +@@ -69358,8 +75864,6 @@ SQLITE_PRIVATE int sqlite3VdbeReset(Vdbe *p){
    +   if( p->pc>=0 ){
    +     vdbeInvokeSqllog(p);
    +     sqlite3VdbeTransferError(p);
    +-    sqlite3DbFree(db, p->zErrMsg);
    +-    p->zErrMsg = 0;
    +     if( p->runOnlyOnce ) p->expired = 1;
    +   }else if( p->rc && p->expired ){
    +     /* The expired flag was set on the VDBE before the first call
    +@@ -69367,13 +75871,21 @@ SQLITE_PRIVATE int sqlite3VdbeReset(Vdbe *p){
    +     ** called), set the database error in this case as well.
    +     */
    +     sqlite3ErrorWithMsg(db, p->rc, p->zErrMsg ? "%s" : 0, p->zErrMsg);
    +-    sqlite3DbFree(db, p->zErrMsg);
    +-    p->zErrMsg = 0;
    +   }
    + 
    +-  /* Reclaim all memory used by the VDBE
    ++  /* Reset register contents and reclaim error message memory.
    +   */
    +-  Cleanup(p);
    ++#ifdef SQLITE_DEBUG
    ++  /* Execute assert() statements to ensure that the Vdbe.apCsr[] and 
    ++  ** Vdbe.aMem[] arrays have already been cleaned up.  */
    ++  if( p->apCsr ) for(i=0; i<p->nCursor; i++) assert( p->apCsr[i]==0 );
    ++  if( p->aMem ){
    ++    for(i=0; i<p->nMem; i++) assert( p->aMem[i].flags==MEM_Undefined );
    ++  }
    ++#endif
    ++  sqlite3DbFree(db, p->zErrMsg);
    ++  p->zErrMsg = 0;
    ++  p->pResultSet = 0;
    + 
    +   /* Save profiling information from this VDBE run.
    +   */
    +@@ -69381,7 +75893,6 @@ SQLITE_PRIVATE int sqlite3VdbeReset(Vdbe *p){
    +   {
    +     FILE *out = fopen("vdbe_profile.out", "a");
    +     if( out ){
    +-      int i;
    +       fprintf(out, "---- ");
    +       for(i=0; i<p->nOp; i++){
    +         fprintf(out, "%02x", p->aOp[i].opcode);
    +@@ -69411,8 +75922,7 @@ SQLITE_PRIVATE int sqlite3VdbeReset(Vdbe *p){
    +     }
    +   }
    + #endif
    +-  p->iCurrentTime = 0;
    +-  p->magic = VDBE_MAGIC_INIT;
    ++  p->magic = VDBE_MAGIC_RESET;
    +   return p->rc & db->errMask;
    + }
    +  
    +@@ -69446,21 +75956,22 @@ SQLITE_PRIVATE int sqlite3VdbeFinalize(Vdbe *p){
    + **    * the corresponding bit in argument mask is clear (where the first
    + **      function parameter corresponds to bit 0 etc.).
    + */
    +-SQLITE_PRIVATE void sqlite3VdbeDeleteAuxData(Vdbe *pVdbe, int iOp, int mask){
    +-  AuxData **pp = &pVdbe->pAuxData;
    ++SQLITE_PRIVATE void sqlite3VdbeDeleteAuxData(sqlite3 *db, AuxData **pp, int iOp, int mask){
    +   while( *pp ){
    +     AuxData *pAux = *pp;
    +     if( (iOp<0)
    +-     || (pAux->iOp==iOp && (pAux->iArg>31 || !(mask & MASKBIT32(pAux->iArg))))
    ++     || (pAux->iAuxOp==iOp
    ++          && pAux->iAuxArg>=0
    ++          && (pAux->iAuxArg>31 || !(mask & MASKBIT32(pAux->iAuxArg))))
    +     ){
    +-      testcase( pAux->iArg==31 );
    +-      if( pAux->xDelete ){
    +-        pAux->xDelete(pAux->pAux);
    ++      testcase( pAux->iAuxArg==31 );
    ++      if( pAux->xDeleteAux ){
    ++        pAux->xDeleteAux(pAux->pAux);
    +       }
    +-      *pp = pAux->pNext;
    +-      sqlite3DbFree(pVdbe->db, pAux);
    ++      *pp = pAux->pNextAux;
    ++      sqlite3DbFree(db, pAux);
    +     }else{
    +-      pp= &pAux->pNext;
    ++      pp= &pAux->pNextAux;
    +     }
    +   }
    + }
    +@@ -69475,25 +75986,29 @@ SQLITE_PRIVATE void sqlite3VdbeDeleteAuxData(Vdbe *pVdbe, int iOp, int mask){
    + */
    + SQLITE_PRIVATE void sqlite3VdbeClearObject(sqlite3 *db, Vdbe *p){
    +   SubProgram *pSub, *pNext;
    +-  int i;
    +   assert( p->db==0 || p->db==db );
    +-  releaseMemArray(p->aVar, p->nVar);
    +   releaseMemArray(p->aColName, p->nResColumn*COLNAME_N);
    +   for(pSub=p->pProgram; pSub; pSub=pNext){
    +     pNext = pSub->pNext;
    +     vdbeFreeOpArray(db, pSub->aOp, pSub->nOp);
    +     sqlite3DbFree(db, pSub);
    +   }
    +-  for(i=p->nzVar-1; i>=0; i--) sqlite3DbFree(db, p->azVar[i]);
    ++  if( p->magic!=VDBE_MAGIC_INIT ){
    ++    releaseMemArray(p->aVar, p->nVar);
    ++    sqlite3DbFree(db, p->pVList);
    ++    sqlite3DbFree(db, p->pFree);
    ++  }
    +   vdbeFreeOpArray(db, p->aOp, p->nOp);
    +   sqlite3DbFree(db, p->aColName);
    +   sqlite3DbFree(db, p->zSql);
    +-  sqlite3DbFree(db, p->pFree);
    + #ifdef SQLITE_ENABLE_STMT_SCANSTATUS
    +-  for(i=0; i<p->nScan; i++){
    +-    sqlite3DbFree(db, p->aScan[i].zName);
    ++  {
    ++    int i;
    ++    for(i=0; i<p->nScan; i++){
    ++      sqlite3DbFree(db, p->aScan[i].zName);
    ++    }
    ++    sqlite3DbFree(db, p->aScan);
    +   }
    +-  sqlite3DbFree(db, p->aScan);
    + #endif
    + }
    + 
    +@@ -69503,7 +76018,7 @@ SQLITE_PRIVATE void sqlite3VdbeClearObject(sqlite3 *db, Vdbe *p){
    + SQLITE_PRIVATE void sqlite3VdbeDelete(Vdbe *p){
    +   sqlite3 *db;
    + 
    +-  if( NEVER(p==0) ) return;
    ++  assert( p!=0 );
    +   db = p->db;
    +   assert( sqlite3_mutex_held(db->mutex) );
    +   sqlite3VdbeClearObject(db, p);
    +@@ -69518,7 +76033,7 @@ SQLITE_PRIVATE void sqlite3VdbeDelete(Vdbe *p){
    +   }
    +   p->magic = VDBE_MAGIC_DEAD;
    +   p->db = 0;
    +-  sqlite3DbFree(db, p);
    ++  sqlite3DbFreeNN(db, p);
    + }
    + 
    + /*
    +@@ -69533,7 +76048,8 @@ static int SQLITE_NOINLINE handleDeferredMoveto(VdbeCursor *p){
    + #endif
    +   assert( p->deferredMoveto );
    +   assert( p->isTable );
    +-  rc = sqlite3BtreeMovetoUnpacked(p->pCursor, 0, p->movetoTarget, 0, &res);
    ++  assert( p->eCurType==CURTYPE_BTREE );
    ++  rc = sqlite3BtreeMovetoUnpacked(p->uc.pCursor, 0, p->movetoTarget, 0, &res);
    +   if( rc ) return rc;
    +   if( res!=0 ) return SQLITE_CORRUPT_BKPT;
    + #ifdef SQLITE_TEST
    +@@ -69553,9 +76069,10 @@ static int SQLITE_NOINLINE handleDeferredMoveto(VdbeCursor *p){
    + */
    + static int SQLITE_NOINLINE handleMovedCursor(VdbeCursor *p){
    +   int isDifferentRow, rc;
    +-  assert( p->pCursor!=0 );
    +-  assert( sqlite3BtreeCursorHasMoved(p->pCursor) );
    +-  rc = sqlite3BtreeCursorRestore(p->pCursor, &isDifferentRow);
    ++  assert( p->eCurType==CURTYPE_BTREE );
    ++  assert( p->uc.pCursor!=0 );
    ++  assert( sqlite3BtreeCursorHasMoved(p->uc.pCursor) );
    ++  rc = sqlite3BtreeCursorRestore(p->uc.pCursor, &isDifferentRow);
    +   p->cacheStatus = CACHE_STALE;
    +   if( isDifferentRow ) p->nullRow = 1;
    +   return rc;
    +@@ -69566,7 +76083,8 @@ static int SQLITE_NOINLINE handleMovedCursor(VdbeCursor *p){
    + ** if need be.  Return any I/O error from the restore operation.
    + */
    + SQLITE_PRIVATE int sqlite3VdbeCursorRestore(VdbeCursor *p){
    +-  if( sqlite3BtreeCursorHasMoved(p->pCursor) ){
    ++  assert( p->eCurType==CURTYPE_BTREE );
    ++  if( sqlite3BtreeCursorHasMoved(p->uc.pCursor) ){
    +     return handleMovedCursor(p);
    +   }
    +   return SQLITE_OK;
    +@@ -69585,11 +76103,19 @@ SQLITE_PRIVATE int sqlite3VdbeCursorRestore(VdbeCursor *p){
    + ** If the cursor is already pointing to the correct row and that row has
    + ** not been deleted out from under the cursor, then this routine is a no-op.
    + */
    +-SQLITE_PRIVATE int sqlite3VdbeCursorMoveto(VdbeCursor *p){
    ++SQLITE_PRIVATE int sqlite3VdbeCursorMoveto(VdbeCursor **pp, int *piCol){
    ++  VdbeCursor *p = *pp;
    ++  assert( p->eCurType==CURTYPE_BTREE || p->eCurType==CURTYPE_PSEUDO );
    +   if( p->deferredMoveto ){
    ++    int iMap;
    ++    if( p->aAltMap && (iMap = p->aAltMap[1+*piCol])>0 ){
    ++      *pp = p->pAltCursor;
    ++      *piCol = iMap - 1;
    ++      return SQLITE_OK;
    ++    }
    +     return handleDeferredMoveto(p);
    +   }
    +-  if( p->pCursor && sqlite3BtreeCursorHasMoved(p->pCursor) ){
    ++  if( sqlite3BtreeCursorHasMoved(p->uc.pCursor) ){
    +     return handleMovedCursor(p);
    +   }
    +   return SQLITE_OK;
    +@@ -69640,11 +76166,13 @@ SQLITE_PRIVATE int sqlite3VdbeCursorMoveto(VdbeCursor *p){
    + /*
    + ** Return the serial-type for the value stored in pMem.
    + */
    +-SQLITE_PRIVATE u32 sqlite3VdbeSerialType(Mem *pMem, int file_format){
    ++SQLITE_PRIVATE u32 sqlite3VdbeSerialType(Mem *pMem, int file_format, u32 *pLen){
    +   int flags = pMem->flags;
    +   u32 n;
    + 
    ++  assert( pLen!=0 );
    +   if( flags&MEM_Null ){
    ++    *pLen = 0;
    +     return 0;
    +   }
    +   if( flags&MEM_Int ){
    +@@ -69658,15 +76186,23 @@ SQLITE_PRIVATE u32 sqlite3VdbeSerialType(Mem *pMem, int file_format){
    +       u = i;
    +     }
    +     if( u<=127 ){
    +-      return ((i&1)==i && file_format>=4) ? 8+(u32)u : 1;
    ++      if( (i&1)==i && file_format>=4 ){
    ++        *pLen = 0;
    ++        return 8+(u32)u;
    ++      }else{
    ++        *pLen = 1;
    ++        return 1;
    ++      }
    +     }
    +-    if( u<=32767 ) return 2;
    +-    if( u<=8388607 ) return 3;
    +-    if( u<=2147483647 ) return 4;
    +-    if( u<=MAX_6BYTE ) return 5;
    ++    if( u<=32767 ){ *pLen = 2; return 2; }
    ++    if( u<=8388607 ){ *pLen = 3; return 3; }
    ++    if( u<=2147483647 ){ *pLen = 4; return 4; }
    ++    if( u<=MAX_6BYTE ){ *pLen = 6; return 5; }
    ++    *pLen = 8;
    +     return 6;
    +   }
    +   if( flags&MEM_Real ){
    ++    *pLen = 8;
    +     return 7;
    +   }
    +   assert( pMem->db->mallocFailed || flags&(MEM_Str|MEM_Blob) );
    +@@ -69675,26 +76211,46 @@ SQLITE_PRIVATE u32 sqlite3VdbeSerialType(Mem *pMem, int file_format){
    +   if( flags & MEM_Zero ){
    +     n += pMem->u.nZero;
    +   }
    ++  *pLen = n;
    +   return ((n*2) + 12 + ((flags&MEM_Str)!=0));
    + }
    + 
    + /*
    +-** The sizes for serial types less than 12
    ++** The sizes for serial types less than 128
    + */
    + static const u8 sqlite3SmallTypeSizes[] = {
    +-  0, 1, 2, 3, 4, 6, 8, 8, 0, 0, 0, 0
    ++        /*  0   1   2   3   4   5   6   7   8   9 */   
    ++/*   0 */   0,  1,  2,  3,  4,  6,  8,  8,  0,  0,
    ++/*  10 */   0,  0,  0,  0,  1,  1,  2,  2,  3,  3,
    ++/*  20 */   4,  4,  5,  5,  6,  6,  7,  7,  8,  8,
    ++/*  30 */   9,  9, 10, 10, 11, 11, 12, 12, 13, 13,
    ++/*  40 */  14, 14, 15, 15, 16, 16, 17, 17, 18, 18,
    ++/*  50 */  19, 19, 20, 20, 21, 21, 22, 22, 23, 23,
    ++/*  60 */  24, 24, 25, 25, 26, 26, 27, 27, 28, 28,
    ++/*  70 */  29, 29, 30, 30, 31, 31, 32, 32, 33, 33,
    ++/*  80 */  34, 34, 35, 35, 36, 36, 37, 37, 38, 38,
    ++/*  90 */  39, 39, 40, 40, 41, 41, 42, 42, 43, 43,
    ++/* 100 */  44, 44, 45, 45, 46, 46, 47, 47, 48, 48,
    ++/* 110 */  49, 49, 50, 50, 51, 51, 52, 52, 53, 53,
    ++/* 120 */  54, 54, 55, 55, 56, 56, 57, 57
    + };
    + 
    + /*
    + ** Return the length of the data corresponding to the supplied serial-type.
    + */
    + SQLITE_PRIVATE u32 sqlite3VdbeSerialTypeLen(u32 serial_type){
    +-  if( serial_type>=12 ){
    ++  if( serial_type>=128 ){
    +     return (serial_type-12)/2;
    +   }else{
    ++    assert( serial_type<12 
    ++            || sqlite3SmallTypeSizes[serial_type]==(serial_type - 12)/2 );
    +     return sqlite3SmallTypeSizes[serial_type];
    +   }
    + }
    ++SQLITE_PRIVATE u8 sqlite3VdbeOneByteSerialTypeLen(u8 serial_type){
    ++  assert( serial_type<128 );
    ++  return sqlite3SmallTypeSizes[serial_type];  
    ++}
    + 
    + /*
    + ** If we are on an architecture with mixed-endian floating 
    +@@ -69790,7 +76346,7 @@ SQLITE_PRIVATE u32 sqlite3VdbeSerialPut(u8 *buf, Mem *pMem, u32 serial_type){
    +     assert( pMem->n + ((pMem->flags & MEM_Zero)?pMem->u.nZero:0)
    +              == (int)sqlite3VdbeSerialTypeLen(serial_type) );
    +     len = pMem->n;
    +-    memcpy(buf, pMem->z, len);
    ++    if( len>0 ) memcpy(buf, pMem->z, len);
    +     return len;
    +   }
    + 
    +@@ -69858,7 +76414,13 @@ SQLITE_PRIVATE u32 sqlite3VdbeSerialGet(
    +   Mem *pMem                     /* Memory cell to write value into */
    + ){
    +   switch( serial_type ){
    +-    case 10:   /* Reserved for future use */
    ++    case 10: { /* Internal use only: NULL with virtual table
    ++               ** UPDATE no-change flag set */
    ++      pMem->flags = MEM_Null|MEM_Zero;
    ++      pMem->n = 0;
    ++      pMem->u.nZero = 0;
    ++      break;
    ++    }
    +     case 11:   /* Reserved for future use */
    +     case 0: {  /* Null */
    +       /* EVIDENCE-OF: R-24078-09375 Value is a NULL. */
    +@@ -69893,6 +76455,10 @@ SQLITE_PRIVATE u32 sqlite3VdbeSerialGet(
    +       /* EVIDENCE-OF: R-01849-26079 Value is a big-endian 32-bit
    +       ** twos-complement integer. */
    +       pMem->u.i = FOUR_BYTE_INT(buf);
    ++#ifdef __HP_cc 
    ++      /* Work around a sign-extension bug in the HP compiler for HP/UX */
    ++      if( buf[0]&0x80 ) pMem->u.i |= 0xffffffff80000000LL;
    ++#endif
    +       pMem->flags = MEM_Int;
    +       testcase( pMem->u.i<0 );
    +       return 4;
    +@@ -69948,34 +76514,17 @@ SQLITE_PRIVATE u32 sqlite3VdbeSerialGet(
    + ** If an OOM error occurs, NULL is returned.
    + */
    + SQLITE_PRIVATE UnpackedRecord *sqlite3VdbeAllocUnpackedRecord(
    +-  KeyInfo *pKeyInfo,              /* Description of the record */
    +-  char *pSpace,                   /* Unaligned space available */
    +-  int szSpace,                    /* Size of pSpace[] in bytes */
    +-  char **ppFree                   /* OUT: Caller should free this pointer */
    ++  KeyInfo *pKeyInfo               /* Description of the record */
    + ){
    +   UnpackedRecord *p;              /* Unpacked record to return */
    +-  int nOff;                       /* Increment pSpace by nOff to align it */
    +   int nByte;                      /* Number of bytes required for *p */
    +-
    +-  /* We want to shift the pointer pSpace up such that it is 8-byte aligned.
    +-  ** Thus, we need to calculate a value, nOff, between 0 and 7, to shift 
    +-  ** it by.  If pSpace is already 8-byte aligned, nOff should be zero.
    +-  */
    +-  nOff = (8 - (SQLITE_PTR_TO_INT(pSpace) & 7)) & 7;
    +-  nByte = ROUND8(sizeof(UnpackedRecord)) + sizeof(Mem)*(pKeyInfo->nField+1);
    +-  if( nByte>szSpace+nOff ){
    +-    p = (UnpackedRecord *)sqlite3DbMallocRaw(pKeyInfo->db, nByte);
    +-    *ppFree = (char *)p;
    +-    if( !p ) return 0;
    +-  }else{
    +-    p = (UnpackedRecord*)&pSpace[nOff];
    +-    *ppFree = 0;
    +-  }
    +-
    ++  nByte = ROUND8(sizeof(UnpackedRecord)) + sizeof(Mem)*(pKeyInfo->nKeyField+1);
    ++  p = (UnpackedRecord *)sqlite3DbMallocRaw(pKeyInfo->db, nByte);
    ++  if( !p ) return 0;
    +   p->aMem = (Mem*)&((char*)p)[ROUND8(sizeof(UnpackedRecord))];
    +   assert( pKeyInfo->aSortOrder!=0 );
    +   p->pKeyInfo = pKeyInfo;
    +-  p->nField = pKeyInfo->nField + 1;
    ++  p->nField = pKeyInfo->nKeyField + 1;
    +   return p;
    + }
    + 
    +@@ -70010,15 +76559,16 @@ SQLITE_PRIVATE void sqlite3VdbeRecordUnpack(
    +     pMem->db = pKeyInfo->db;
    +     /* pMem->flags = 0; // sqlite3VdbeSerialGet() will set this for us */
    +     pMem->szMalloc = 0;
    ++    pMem->z = 0;
    +     d += sqlite3VdbeSerialGet(&aKey[d], serial_type, pMem);
    +     pMem++;
    +     if( (++u)>=p->nField ) break;
    +   }
    +-  assert( u<=pKeyInfo->nField + 1 );
    ++  assert( u<=pKeyInfo->nKeyField + 1 );
    +   p->nField = u;
    + }
    + 
    +-#if SQLITE_DEBUG
    ++#ifdef SQLITE_DEBUG
    + /*
    + ** This function compares two index or table record keys in the same way
    + ** as the sqlite3VdbeRecordCompare() routine. Unlike VdbeRecordCompare(),
    +@@ -70063,9 +76613,9 @@ static int vdbeRecordCompareDebug(
    +   idx1 = getVarint32(aKey1, szHdr1);
    +   if( szHdr1>98307 ) return SQLITE_CORRUPT;
    +   d1 = szHdr1;
    +-  assert( pKeyInfo->nField+pKeyInfo->nXField>=pPKey2->nField || CORRUPT_DB );
    ++  assert( pKeyInfo->nAllField>=pPKey2->nField || CORRUPT_DB );
    +   assert( pKeyInfo->aSortOrder!=0 );
    +-  assert( pKeyInfo->nField>0 );
    ++  assert( pKeyInfo->nKeyField>0 );
    +   assert( idx1<=szHdr1 || CORRUPT_DB );
    +   do{
    +     u32 serial_type1;
    +@@ -70123,16 +76673,16 @@ debugCompareEnd:
    + }
    + #endif
    + 
    +-#if SQLITE_DEBUG
    ++#ifdef SQLITE_DEBUG
    + /*
    + ** Count the number of fields (a.k.a. columns) in the record given by
    + ** pKey,nKey.  The verify that this count is less than or equal to the
    +-** limit given by pKeyInfo->nField + pKeyInfo->nXField.
    ++** limit given by pKeyInfo->nAllField.
    + **
    + ** If this constraint is not satisfied, it means that the high-speed
    + ** vdbeRecordCompareInt() and vdbeRecordCompareString() routines will
    + ** not work correctly.  If this assert() ever fires, it probably means
    +-** that the KeyInfo.nField or KeyInfo.nXField values were computed
    ++** that the KeyInfo.nKeyField or KeyInfo.nAllField values were computed
    + ** incorrectly.
    + */
    + static void vdbeAssertFieldCountWithinLimits(
    +@@ -70153,7 +76703,7 @@ static void vdbeAssertFieldCountWithinLimits(
    +     idx += getVarint32(aKey+idx, notUsed);
    +     nField++;
    +   }
    +-  assert( nField <= pKeyInfo->nField+pKeyInfo->nXField );
    ++  assert( nField <= pKeyInfo->nAllField );
    + }
    + #else
    + # define vdbeAssertFieldCountWithinLimits(A,B,C)
    +@@ -70178,7 +76728,6 @@ static int vdbeCompareMemString(
    +   }else{
    +     int rc;
    +     const void *v1, *v2;
    +-    int n1, n2;
    +     Mem c1;
    +     Mem c2;
    +     sqlite3VdbeMemInit(&c1, pMem1->db, MEM_Null);
    +@@ -70186,28 +76735,92 @@ static int vdbeCompareMemString(
    +     sqlite3VdbeMemShallowCopy(&c1, pMem1, MEM_Ephem);
    +     sqlite3VdbeMemShallowCopy(&c2, pMem2, MEM_Ephem);
    +     v1 = sqlite3ValueText((sqlite3_value*)&c1, pColl->enc);
    +-    n1 = v1==0 ? 0 : c1.n;
    +     v2 = sqlite3ValueText((sqlite3_value*)&c2, pColl->enc);
    +-    n2 = v2==0 ? 0 : c2.n;
    +-    rc = pColl->xCmp(pColl->pUser, n1, v1, n2, v2);
    ++    if( (v1==0 || v2==0) ){
    ++      if( prcErr ) *prcErr = SQLITE_NOMEM_BKPT;
    ++      rc = 0;
    ++    }else{
    ++      rc = pColl->xCmp(pColl->pUser, c1.n, v1, c2.n, v2);
    ++    }
    +     sqlite3VdbeMemRelease(&c1);
    +     sqlite3VdbeMemRelease(&c2);
    +-    if( (v1==0 || v2==0) && prcErr ) *prcErr = SQLITE_NOMEM;
    +     return rc;
    +   }
    + }
    + 
    ++/*
    ++** The input pBlob is guaranteed to be a Blob that is not marked
    ++** with MEM_Zero.  Return true if it could be a zero-blob.
    ++*/
    ++static int isAllZero(const char *z, int n){
    ++  int i;
    ++  for(i=0; i<n; i++){
    ++    if( z[i] ) return 0;
    ++  }
    ++  return 1;
    ++}
    ++
    + /*
    + ** Compare two blobs.  Return negative, zero, or positive if the first
    + ** is less than, equal to, or greater than the second, respectively.
    + ** If one blob is a prefix of the other, then the shorter is the lessor.
    + */
    + static SQLITE_NOINLINE int sqlite3BlobCompare(const Mem *pB1, const Mem *pB2){
    +-  int c = memcmp(pB1->z, pB2->z, pB1->n>pB2->n ? pB2->n : pB1->n);
    ++  int c;
    ++  int n1 = pB1->n;
    ++  int n2 = pB2->n;
    ++
    ++  /* It is possible to have a Blob value that has some non-zero content
    ++  ** followed by zero content.  But that only comes up for Blobs formed
    ++  ** by the OP_MakeRecord opcode, and such Blobs never get passed into
    ++  ** sqlite3MemCompare(). */
    ++  assert( (pB1->flags & MEM_Zero)==0 || n1==0 );
    ++  assert( (pB2->flags & MEM_Zero)==0 || n2==0 );
    ++
    ++  if( (pB1->flags|pB2->flags) & MEM_Zero ){
    ++    if( pB1->flags & pB2->flags & MEM_Zero ){
    ++      return pB1->u.nZero - pB2->u.nZero;
    ++    }else if( pB1->flags & MEM_Zero ){
    ++      if( !isAllZero(pB2->z, pB2->n) ) return -1;
    ++      return pB1->u.nZero - n2;
    ++    }else{
    ++      if( !isAllZero(pB1->z, pB1->n) ) return +1;
    ++      return n1 - pB2->u.nZero;
    ++    }
    ++  }
    ++  c = memcmp(pB1->z, pB2->z, n1>n2 ? n2 : n1);
    +   if( c ) return c;
    +-  return pB1->n - pB2->n;
    ++  return n1 - n2;
    + }
    + 
    ++/*
    ++** Do a comparison between a 64-bit signed integer and a 64-bit floating-point
    ++** number.  Return negative, zero, or positive if the first (i64) is less than,
    ++** equal to, or greater than the second (double).
    ++*/
    ++static int sqlite3IntFloatCompare(i64 i, double r){
    ++  if( sizeof(LONGDOUBLE_TYPE)>8 ){
    ++    LONGDOUBLE_TYPE x = (LONGDOUBLE_TYPE)i;
    ++    if( x<r ) return -1;
    ++    if( x>r ) return +1;
    ++    return 0;
    ++  }else{
    ++    i64 y;
    ++    double s;
    ++    if( r<-9223372036854775808.0 ) return +1;
    ++    if( r>9223372036854775807.0 ) return -1;
    ++    y = (i64)r;
    ++    if( i<y ) return -1;
    ++    if( i>y ){
    ++      if( y==SMALLEST_INT64 && r>0.0 ) return -1;
    ++      return +1;
    ++    }
    ++    s = (double)i;
    ++    if( s<r ) return -1;
    ++    if( s>r ) return +1;
    ++    return 0;
    ++  }
    ++}
    + 
    + /*
    + ** Compare the values contained by the two memory cells, returning
    +@@ -70234,34 +76847,34 @@ SQLITE_PRIVATE int sqlite3MemCompare(const Mem *pMem1, const Mem *pMem2, const C
    +     return (f2&MEM_Null) - (f1&MEM_Null);
    +   }
    + 
    +-  /* If one value is a number and the other is not, the number is less.
    +-  ** If both are numbers, compare as reals if one is a real, or as integers
    +-  ** if both values are integers.
    ++  /* At least one of the two values is a number
    +   */
    +   if( combined_flags&(MEM_Int|MEM_Real) ){
    +-    double r1, r2;
    +     if( (f1 & f2 & MEM_Int)!=0 ){
    +       if( pMem1->u.i < pMem2->u.i ) return -1;
    +-      if( pMem1->u.i > pMem2->u.i ) return 1;
    ++      if( pMem1->u.i > pMem2->u.i ) return +1;
    +       return 0;
    +     }
    +-    if( (f1&MEM_Real)!=0 ){
    +-      r1 = pMem1->u.r;
    +-    }else if( (f1&MEM_Int)!=0 ){
    +-      r1 = (double)pMem1->u.i;
    +-    }else{
    +-      return 1;
    ++    if( (f1 & f2 & MEM_Real)!=0 ){
    ++      if( pMem1->u.r < pMem2->u.r ) return -1;
    ++      if( pMem1->u.r > pMem2->u.r ) return +1;
    ++      return 0;
    +     }
    +-    if( (f2&MEM_Real)!=0 ){
    +-      r2 = pMem2->u.r;
    +-    }else if( (f2&MEM_Int)!=0 ){
    +-      r2 = (double)pMem2->u.i;
    +-    }else{
    +-      return -1;
    ++    if( (f1&MEM_Int)!=0 ){
    ++      if( (f2&MEM_Real)!=0 ){
    ++        return sqlite3IntFloatCompare(pMem1->u.i, pMem2->u.r);
    ++      }else{
    ++        return -1;
    ++      }
    +     }
    +-    if( r1<r2 ) return -1;
    +-    if( r1>r2 ) return 1;
    +-    return 0;
    ++    if( (f1&MEM_Real)!=0 ){
    ++      if( (f2&MEM_Int)!=0 ){
    ++        return -sqlite3IntFloatCompare(pMem2->u.i, pMem1->u.r);
    ++      }else{
    ++        return -1;
    ++      }
    ++    }
    ++    return +1;
    +   }
    + 
    +   /* If one value is a string and the other is a blob, the string is less.
    +@@ -70275,7 +76888,7 @@ SQLITE_PRIVATE int sqlite3MemCompare(const Mem *pMem1, const Mem *pMem2, const C
    +       return -1;
    +     }
    + 
    +-    assert( pMem1->enc==pMem2->enc );
    ++    assert( pMem1->enc==pMem2->enc || pMem1->db->mallocFailed );
    +     assert( pMem1->enc==SQLITE_UTF8 || 
    +             pMem1->enc==SQLITE_UTF16LE || pMem1->enc==SQLITE_UTF16BE );
    + 
    +@@ -70395,10 +77008,10 @@ SQLITE_PRIVATE int sqlite3VdbeRecordCompareWithSkip(
    +   }
    + 
    +   VVA_ONLY( mem1.szMalloc = 0; ) /* Only needed by assert() statements */
    +-  assert( pPKey2->pKeyInfo->nField+pPKey2->pKeyInfo->nXField>=pPKey2->nField 
    ++  assert( pPKey2->pKeyInfo->nAllField>=pPKey2->nField 
    +        || CORRUPT_DB );
    +   assert( pPKey2->pKeyInfo->aSortOrder!=0 );
    +-  assert( pPKey2->pKeyInfo->nField>0 );
    ++  assert( pPKey2->pKeyInfo->nKeyField>0 );
    +   assert( idx1<=szHdr1 || CORRUPT_DB );
    +   do{
    +     u32 serial_type;
    +@@ -70412,13 +77025,8 @@ SQLITE_PRIVATE int sqlite3VdbeRecordCompareWithSkip(
    +       }else if( serial_type==0 ){
    +         rc = -1;
    +       }else if( serial_type==7 ){
    +-        double rhs = (double)pRhs->u.i;
    +         sqlite3VdbeSerialGet(&aKey1[d1], serial_type, &mem1);
    +-        if( mem1.u.r<rhs ){
    +-          rc = -1;
    +-        }else if( mem1.u.r>rhs ){
    +-          rc = +1;
    +-        }
    ++        rc = -sqlite3IntFloatCompare(pRhs->u.i, mem1.u.r);
    +       }else{
    +         i64 lhs = vdbeRecordDecodeInt(serial_type, &aKey1[d1]);
    +         i64 rhs = pRhs->u.i;
    +@@ -70442,18 +77050,15 @@ SQLITE_PRIVATE int sqlite3VdbeRecordCompareWithSkip(
    +       }else if( serial_type==0 ){
    +         rc = -1;
    +       }else{
    +-        double rhs = pRhs->u.r;
    +-        double lhs;
    +         sqlite3VdbeSerialGet(&aKey1[d1], serial_type, &mem1);
    +         if( serial_type==7 ){
    +-          lhs = mem1.u.r;
    ++          if( mem1.u.r<pRhs->u.r ){
    ++            rc = -1;
    ++          }else if( mem1.u.r>pRhs->u.r ){
    ++            rc = +1;
    ++          }
    +         }else{
    +-          lhs = (double)mem1.u.i;
    +-        }
    +-        if( lhs<rhs ){
    +-          rc = -1;
    +-        }else if( lhs>rhs ){
    +-          rc = +1;
    ++          rc = sqlite3IntFloatCompare(mem1.u.i, pRhs->u.r);
    +         }
    +       }
    +     }
    +@@ -70491,6 +77096,7 @@ SQLITE_PRIVATE int sqlite3VdbeRecordCompareWithSkip(
    + 
    +     /* RHS is a blob */
    +     else if( pRhs->flags & MEM_Blob ){
    ++      assert( (pRhs->flags & MEM_Zero)==0 || pRhs->n==0 );
    +       getVarint32(&aKey1[idx1], serial_type);
    +       testcase( serial_type==12 );
    +       if( serial_type<12 || (serial_type & 0x01) ){
    +@@ -70502,6 +77108,12 @@ SQLITE_PRIVATE int sqlite3VdbeRecordCompareWithSkip(
    +         if( (d1+nStr) > (unsigned)nKey1 ){
    +           pPKey2->errCode = (u8)SQLITE_CORRUPT_BKPT;
    +           return 0;                /* Corruption */
    ++        }else if( pRhs->flags & MEM_Zero ){
    ++          if( !isAllZero((const char*)&aKey1[d1],nStr) ){
    ++            rc = 1;
    ++          }else{
    ++            rc = nStr - pRhs->u.nZero;
    ++          }
    +         }else{
    +           int nCmp = MIN(nStr, pRhs->n);
    +           rc = memcmp(&aKey1[d1], pRhs->z, nCmp);
    +@@ -70543,6 +77155,7 @@ SQLITE_PRIVATE int sqlite3VdbeRecordCompareWithSkip(
    +        || vdbeRecordCompareDebug(nKey1, pKey1, pPKey2, pPKey2->default_rc) 
    +        || pKeyInfo->db->mallocFailed
    +   );
    ++  pPKey2->eqSeen = 1;
    +   return pPKey2->default_rc;
    + }
    + SQLITE_PRIVATE int sqlite3VdbeRecordCompare(
    +@@ -70571,7 +77184,7 @@ static int vdbeRecordCompareInt(
    +   int res;
    +   u32 y;
    +   u64 x;
    +-  i64 v = pPKey2->aMem[0].u.i;
    ++  i64 v;
    +   i64 lhs;
    + 
    +   vdbeAssertFieldCountWithinLimits(nKey1, pKey1, pPKey2->pKeyInfo);
    +@@ -70630,6 +77243,7 @@ static int vdbeRecordCompareInt(
    +       return sqlite3VdbeRecordCompare(nKey1, pKey1, pPKey2);
    +   }
    + 
    ++  v = pPKey2->aMem[0].u.i;
    +   if( v>lhs ){
    +     res = pPKey2->r1;
    +   }else if( v<lhs ){
    +@@ -70642,6 +77256,7 @@ static int vdbeRecordCompareInt(
    +     /* The first fields of the two keys are equal and there are no trailing
    +     ** fields. Return pPKey2->default_rc in this case. */
    +     res = pPKey2->default_rc;
    ++    pPKey2->eqSeen = 1;
    +   }
    + 
    +   assert( vdbeRecordCompareDebug(nKey1, pKey1, pPKey2, res) );
    +@@ -70662,6 +77277,7 @@ static int vdbeRecordCompareString(
    +   int serial_type;
    +   int res;
    + 
    ++  assert( pPKey2->aMem[0].flags & MEM_Str );
    +   vdbeAssertFieldCountWithinLimits(nKey1, pKey1, pPKey2->pKeyInfo);
    +   getVarint32(&aKey1[1], serial_type);
    +   if( serial_type<12 ){
    +@@ -70688,6 +77304,7 @@ static int vdbeRecordCompareString(
    +           res = sqlite3VdbeRecordCompareWithSkip(nKey1, pKey1, pPKey2, 1);
    +         }else{
    +           res = pPKey2->default_rc;
    ++          pPKey2->eqSeen = 1;
    +         }
    +       }else if( res>0 ){
    +         res = pPKey2->r2;
    +@@ -70727,7 +77344,7 @@ SQLITE_PRIVATE RecordCompare sqlite3VdbeFindCompare(UnpackedRecord *p){
    +   ** The easiest way to enforce this limit is to consider only records with
    +   ** 13 fields or less. If the first field is an integer, the maximum legal
    +   ** header size is (12*5 + 1 + 1) bytes.  */
    +-  if( (p->pKeyInfo->nField + p->pKeyInfo->nXField)<=13 ){
    ++  if( p->pKeyInfo->nAllField<=13 ){
    +     int flags = p->aMem[0].flags;
    +     if( p->pKeyInfo->aSortOrder[0] ){
    +       p->r1 = 1;
    +@@ -70773,13 +77390,12 @@ SQLITE_PRIVATE int sqlite3VdbeIdxRowid(sqlite3 *db, BtCursor *pCur, i64 *rowid){
    +   ** this code can safely assume that nCellKey is 32-bits  
    +   */
    +   assert( sqlite3BtreeCursorIsValid(pCur) );
    +-  VVA_ONLY(rc =) sqlite3BtreeKeySize(pCur, &nCellKey);
    +-  assert( rc==SQLITE_OK );     /* pCur is always valid so KeySize cannot fail */
    ++  nCellKey = sqlite3BtreePayloadSize(pCur);
    +   assert( (nCellKey & SQLITE_MAX_U32)==(u64)nCellKey );
    + 
    +   /* Read in the complete content of the index entry */
    +   sqlite3VdbeMemInit(&m, db, 0);
    +-  rc = sqlite3VdbeMemFromBtree(pCur, 0, (u32)nCellKey, 1, &m);
    ++  rc = sqlite3VdbeMemFromBtree(pCur, 0, (u32)nCellKey, &m);
    +   if( rc ){
    +     return rc;
    +   }
    +@@ -70845,12 +77461,13 @@ SQLITE_PRIVATE int sqlite3VdbeIdxKeyCompare(
    + ){
    +   i64 nCellKey = 0;
    +   int rc;
    +-  BtCursor *pCur = pC->pCursor;
    ++  BtCursor *pCur;
    +   Mem m;
    + 
    ++  assert( pC->eCurType==CURTYPE_BTREE );
    ++  pCur = pC->uc.pCursor;
    +   assert( sqlite3BtreeCursorIsValid(pCur) );
    +-  VVA_ONLY(rc =) sqlite3BtreeKeySize(pCur, &nCellKey);
    +-  assert( rc==SQLITE_OK );    /* pCur is always valid so KeySize cannot fail */
    ++  nCellKey = sqlite3BtreePayloadSize(pCur);
    +   /* nCellKey will always be between 0 and 0xffffffff because of the way
    +   ** that btreeParseCellPtr() and sqlite3GetVarint32() are implemented */
    +   if( nCellKey<=0 || nCellKey>0x7fffffff ){
    +@@ -70858,7 +77475,7 @@ SQLITE_PRIVATE int sqlite3VdbeIdxKeyCompare(
    +     return SQLITE_CORRUPT_BKPT;
    +   }
    +   sqlite3VdbeMemInit(&m, db, 0);
    +-  rc = sqlite3VdbeMemFromBtree(pC->pCursor, 0, (u32)nCellKey, 1, &m);
    ++  rc = sqlite3VdbeMemFromBtree(pCur, 0, (u32)nCellKey, &m);
    +   if( rc ){
    +     return rc;
    +   }
    +@@ -70909,6 +77526,13 @@ SQLITE_PRIVATE sqlite3 *sqlite3VdbeDb(Vdbe *v){
    +   return v->db;
    + }
    + 
    ++/*
    ++** Return the SQLITE_PREPARE flags for a Vdbe.
    ++*/
    ++SQLITE_PRIVATE u8 sqlite3VdbePrepareFlags(Vdbe *v){
    ++  return v->prepFlags;
    ++}
    ++
    + /*
    + ** Return a pointer to an sqlite3_value structure containing the value bound
    + ** parameter iVar of VM v. Except, if the value is an SQL NULL, return 
    +@@ -70921,6 +77545,7 @@ SQLITE_PRIVATE sqlite3_value *sqlite3VdbeGetBoundValue(Vdbe *v, int iVar, u8 aff
    +   assert( iVar>0 );
    +   if( v ){
    +     Mem *pMem = &v->aVar[iVar-1];
    ++    assert( (v->db->flags & SQLITE_EnableQPSG)==0 );
    +     if( 0==(pMem->flags & MEM_Null) ){
    +       sqlite3_value *pRet = sqlite3ValueNew(v->db);
    +       if( pRet ){
    +@@ -70940,13 +77565,36 @@ SQLITE_PRIVATE sqlite3_value *sqlite3VdbeGetBoundValue(Vdbe *v, int iVar, u8 aff
    + */
    + SQLITE_PRIVATE void sqlite3VdbeSetVarmask(Vdbe *v, int iVar){
    +   assert( iVar>0 );
    +-  if( iVar>32 ){
    +-    v->expmask = 0xffffffff;
    ++  assert( (v->db->flags & SQLITE_EnableQPSG)==0 );
    ++  if( iVar>=32 ){
    ++    v->expmask |= 0x80000000;
    +   }else{
    +     v->expmask |= ((u32)1 << (iVar-1));
    +   }
    + }
    + 
    ++/*
    ++** Cause a function to throw an error if it was call from OP_PureFunc
    ++** rather than OP_Function.
    ++**
    ++** OP_PureFunc means that the function must be deterministic, and should
    ++** throw an error if it is given inputs that would make it non-deterministic.
    ++** This routine is invoked by date/time functions that use non-deterministic
    ++** features such as 'now'.
    ++*/
    ++SQLITE_PRIVATE int sqlite3NotPureFunc(sqlite3_context *pCtx){
    ++#ifdef SQLITE_ENABLE_STAT3_OR_STAT4
    ++  if( pCtx->pVdbe==0 ) return 1;
    ++#endif
    ++  if( pCtx->pVdbe->aOp[pCtx->iOp].opcode==OP_PureFunc ){
    ++    sqlite3_result_error(pCtx, 
    ++       "non-deterministic function in index expression or CHECK constraint",
    ++       -1);
    ++    return 0;
    ++  }
    ++  return 1;
    ++}
    ++
    + #ifndef SQLITE_OMIT_VIRTUALTABLE
    + /*
    + ** Transfer error message text from an sqlite3_vtab.zErrMsg (text stored
    +@@ -70954,14 +77602,105 @@ SQLITE_PRIVATE void sqlite3VdbeSetVarmask(Vdbe *v, int iVar){
    + ** in memory obtained from sqlite3DbMalloc).
    + */
    + SQLITE_PRIVATE void sqlite3VtabImportErrmsg(Vdbe *p, sqlite3_vtab *pVtab){
    +-  sqlite3 *db = p->db;
    +-  sqlite3DbFree(db, p->zErrMsg);
    +-  p->zErrMsg = sqlite3DbStrDup(db, pVtab->zErrMsg);
    +-  sqlite3_free(pVtab->zErrMsg);
    +-  pVtab->zErrMsg = 0;
    ++  if( pVtab->zErrMsg ){
    ++    sqlite3 *db = p->db;
    ++    sqlite3DbFree(db, p->zErrMsg);
    ++    p->zErrMsg = sqlite3DbStrDup(db, pVtab->zErrMsg);
    ++    sqlite3_free(pVtab->zErrMsg);
    ++    pVtab->zErrMsg = 0;
    ++  }
    + }
    + #endif /* SQLITE_OMIT_VIRTUALTABLE */
    + 
    ++#ifdef SQLITE_ENABLE_PREUPDATE_HOOK
    ++
    ++/*
    ++** If the second argument is not NULL, release any allocations associated 
    ++** with the memory cells in the p->aMem[] array. Also free the UnpackedRecord
    ++** structure itself, using sqlite3DbFree().
    ++**
    ++** This function is used to free UnpackedRecord structures allocated by
    ++** the vdbeUnpackRecord() function found in vdbeapi.c.
    ++*/
    ++static void vdbeFreeUnpacked(sqlite3 *db, int nField, UnpackedRecord *p){
    ++  if( p ){
    ++    int i;
    ++    for(i=0; i<nField; i++){
    ++      Mem *pMem = &p->aMem[i];
    ++      if( pMem->zMalloc ) sqlite3VdbeMemRelease(pMem);
    ++    }
    ++    sqlite3DbFreeNN(db, p);
    ++  }
    ++}
    ++#endif /* SQLITE_ENABLE_PREUPDATE_HOOK */
    ++
    ++#ifdef SQLITE_ENABLE_PREUPDATE_HOOK
    ++/*
    ++** Invoke the pre-update hook. If this is an UPDATE or DELETE pre-update call,
    ++** then cursor passed as the second argument should point to the row about
    ++** to be update or deleted. If the application calls sqlite3_preupdate_old(),
    ++** the required value will be read from the row the cursor points to.
    ++*/
    ++SQLITE_PRIVATE void sqlite3VdbePreUpdateHook(
    ++  Vdbe *v,                        /* Vdbe pre-update hook is invoked by */
    ++  VdbeCursor *pCsr,               /* Cursor to grab old.* values from */
    ++  int op,                         /* SQLITE_INSERT, UPDATE or DELETE */
    ++  const char *zDb,                /* Database name */
    ++  Table *pTab,                    /* Modified table */
    ++  i64 iKey1,                      /* Initial key value */
    ++  int iReg                        /* Register for new.* record */
    ++){
    ++  sqlite3 *db = v->db;
    ++  i64 iKey2;
    ++  PreUpdate preupdate;
    ++  const char *zTbl = pTab->zName;
    ++  static const u8 fakeSortOrder = 0;
    ++
    ++  assert( db->pPreUpdate==0 );
    ++  memset(&preupdate, 0, sizeof(PreUpdate));
    ++  if( HasRowid(pTab)==0 ){
    ++    iKey1 = iKey2 = 0;
    ++    preupdate.pPk = sqlite3PrimaryKeyIndex(pTab);
    ++  }else{
    ++    if( op==SQLITE_UPDATE ){
    ++      iKey2 = v->aMem[iReg].u.i;
    ++    }else{
    ++      iKey2 = iKey1;
    ++    }
    ++  }
    ++
    ++  assert( pCsr->nField==pTab->nCol 
    ++       || (pCsr->nField==pTab->nCol+1 && op==SQLITE_DELETE && iReg==-1)
    ++  );
    ++
    ++  preupdate.v = v;
    ++  preupdate.pCsr = pCsr;
    ++  preupdate.op = op;
    ++  preupdate.iNewReg = iReg;
    ++  preupdate.keyinfo.db = db;
    ++  preupdate.keyinfo.enc = ENC(db);
    ++  preupdate.keyinfo.nKeyField = pTab->nCol;
    ++  preupdate.keyinfo.aSortOrder = (u8*)&fakeSortOrder;
    ++  preupdate.iKey1 = iKey1;
    ++  preupdate.iKey2 = iKey2;
    ++  preupdate.pTab = pTab;
    ++
    ++  db->pPreUpdate = &preupdate;
    ++  db->xPreUpdateCallback(db->pPreUpdateArg, db, op, zDb, zTbl, iKey1, iKey2);
    ++  db->pPreUpdate = 0;
    ++  sqlite3DbFree(db, preupdate.aRecord);
    ++  vdbeFreeUnpacked(db, preupdate.keyinfo.nKeyField+1, preupdate.pUnpacked);
    ++  vdbeFreeUnpacked(db, preupdate.keyinfo.nKeyField+1, preupdate.pNewUnpacked);
    ++  if( preupdate.aNew ){
    ++    int i;
    ++    for(i=0; i<pCsr->nField; i++){
    ++      sqlite3VdbeMemRelease(&preupdate.aNew[i]);
    ++    }
    ++    sqlite3DbFreeNN(db, preupdate.aNew);
    ++  }
    ++}
    ++#endif /* SQLITE_ENABLE_PREUPDATE_HOOK */
    ++
    + /************** End of vdbeaux.c *********************************************/
    + /************** Begin file vdbeapi.c *****************************************/
    + /*
    +@@ -70991,7 +77730,7 @@ SQLITE_PRIVATE void sqlite3VtabImportErrmsg(Vdbe *p, sqlite3_vtab *pVtab){
    + ** collating sequences are registered or if an authorizer function is
    + ** added or changed.
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_expired(sqlite3_stmt *pStmt){
    ++SQLITE_API int sqlite3_expired(sqlite3_stmt *pStmt){
    +   Vdbe *p = (Vdbe*)pStmt;
    +   return p==0 || p->expired;
    + }
    +@@ -71026,12 +77765,19 @@ static int vdbeSafetyNotNull(Vdbe *p){
    + */
    + static SQLITE_NOINLINE void invokeProfileCallback(sqlite3 *db, Vdbe *p){
    +   sqlite3_int64 iNow;
    ++  sqlite3_int64 iElapse;
    +   assert( p->startTime>0 );
    +-  assert( db->xProfile!=0 );
    ++  assert( db->xProfile!=0 || (db->mTrace & SQLITE_TRACE_PROFILE)!=0 );
    +   assert( db->init.busy==0 );
    +   assert( p->zSql!=0 );
    +   sqlite3OsCurrentTimeInt64(db->pVfs, &iNow);
    +-  db->xProfile(db->pProfileArg, p->zSql, (iNow - p->startTime)*1000000);
    ++  iElapse = (iNow - p->startTime)*1000000;
    ++  if( db->xProfile ){
    ++    db->xProfile(db->pProfileArg, p->zSql, iElapse);
    ++  }
    ++  if( db->mTrace & SQLITE_TRACE_PROFILE ){
    ++    db->xTrace(SQLITE_TRACE_PROFILE, db->pTraceArg, p, (void*)&iElapse);
    ++  }
    +   p->startTime = 0;
    + }
    + /*
    +@@ -71053,7 +77799,7 @@ static SQLITE_NOINLINE void invokeProfileCallback(sqlite3 *db, Vdbe *p){
    + ** This routine sets the error code and string returned by
    + ** sqlite3_errcode(), sqlite3_errmsg() and sqlite3_errmsg16().
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_finalize(sqlite3_stmt *pStmt){
    ++SQLITE_API int sqlite3_finalize(sqlite3_stmt *pStmt){
    +   int rc;
    +   if( pStmt==0 ){
    +     /* IMPLEMENTATION-OF: R-57228-12904 Invoking sqlite3_finalize() on a NULL
    +@@ -71080,7 +77826,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_finalize(sqlite3_stmt *pStmt){
    + ** This routine sets the error code and string returned by
    + ** sqlite3_errcode(), sqlite3_errmsg() and sqlite3_errmsg16().
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_reset(sqlite3_stmt *pStmt){
    ++SQLITE_API int sqlite3_reset(sqlite3_stmt *pStmt){
    +   int rc;
    +   if( pStmt==0 ){
    +     rc = SQLITE_OK;
    +@@ -71101,7 +77847,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_reset(sqlite3_stmt *pStmt){
    + /*
    + ** Set all the parameters in the compiled SQL statement to NULL.
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_clear_bindings(sqlite3_stmt *pStmt){
    ++SQLITE_API int sqlite3_clear_bindings(sqlite3_stmt *pStmt){
    +   int i;
    +   int rc = SQLITE_OK;
    +   Vdbe *p = (Vdbe*)pStmt;
    +@@ -71113,7 +77859,8 @@ SQLITE_API int SQLITE_STDCALL sqlite3_clear_bindings(sqlite3_stmt *pStmt){
    +     sqlite3VdbeMemRelease(&p->aVar[i]);
    +     p->aVar[i].flags = MEM_Null;
    +   }
    +-  if( p->isPrepareV2 && p->expmask ){
    ++  assert( (p->prepFlags & SQLITE_PREPARE_SAVESQL)!=0 || p->expmask==0 );
    ++  if( p->expmask ){
    +     p->expired = 1;
    +   }
    +   sqlite3_mutex_leave(mutex);
    +@@ -71125,10 +77872,10 @@ SQLITE_API int SQLITE_STDCALL sqlite3_clear_bindings(sqlite3_stmt *pStmt){
    + ** The following routines extract information from a Mem or sqlite3_value
    + ** structure.
    + */
    +-SQLITE_API const void *SQLITE_STDCALL sqlite3_value_blob(sqlite3_value *pVal){
    ++SQLITE_API const void *sqlite3_value_blob(sqlite3_value *pVal){
    +   Mem *p = (Mem*)pVal;
    +   if( p->flags & (MEM_Blob|MEM_Str) ){
    +-    if( sqlite3VdbeMemExpandBlob(p)!=SQLITE_OK ){
    ++    if( ExpandBlob(p)!=SQLITE_OK ){
    +       assert( p->flags==MEM_Null && p->z==0 );
    +       return 0;
    +     }
    +@@ -71138,35 +77885,49 @@ SQLITE_API const void *SQLITE_STDCALL sqlite3_value_blob(sqlite3_value *pVal){
    +     return sqlite3_value_text(pVal);
    +   }
    + }
    +-SQLITE_API int SQLITE_STDCALL sqlite3_value_bytes(sqlite3_value *pVal){
    ++SQLITE_API int sqlite3_value_bytes(sqlite3_value *pVal){
    +   return sqlite3ValueBytes(pVal, SQLITE_UTF8);
    + }
    +-SQLITE_API int SQLITE_STDCALL sqlite3_value_bytes16(sqlite3_value *pVal){
    ++SQLITE_API int sqlite3_value_bytes16(sqlite3_value *pVal){
    +   return sqlite3ValueBytes(pVal, SQLITE_UTF16NATIVE);
    + }
    +-SQLITE_API double SQLITE_STDCALL sqlite3_value_double(sqlite3_value *pVal){
    ++SQLITE_API double sqlite3_value_double(sqlite3_value *pVal){
    +   return sqlite3VdbeRealValue((Mem*)pVal);
    + }
    +-SQLITE_API int SQLITE_STDCALL sqlite3_value_int(sqlite3_value *pVal){
    ++SQLITE_API int sqlite3_value_int(sqlite3_value *pVal){
    +   return (int)sqlite3VdbeIntValue((Mem*)pVal);
    + }
    +-SQLITE_API sqlite_int64 SQLITE_STDCALL sqlite3_value_int64(sqlite3_value *pVal){
    ++SQLITE_API sqlite_int64 sqlite3_value_int64(sqlite3_value *pVal){
    +   return sqlite3VdbeIntValue((Mem*)pVal);
    + }
    +-SQLITE_API unsigned int SQLITE_STDCALL sqlite3_value_subtype(sqlite3_value *pVal){
    +-  return ((Mem*)pVal)->eSubtype;
    ++SQLITE_API unsigned int sqlite3_value_subtype(sqlite3_value *pVal){
    ++  Mem *pMem = (Mem*)pVal;
    ++  return ((pMem->flags & MEM_Subtype) ? pMem->eSubtype : 0);
    + }
    +-SQLITE_API const unsigned char *SQLITE_STDCALL sqlite3_value_text(sqlite3_value *pVal){
    ++SQLITE_API void *sqlite3_value_pointer(sqlite3_value *pVal, const char *zPType){
    ++  Mem *p = (Mem*)pVal;
    ++  if( (p->flags&(MEM_TypeMask|MEM_Term|MEM_Subtype)) ==
    ++                 (MEM_Null|MEM_Term|MEM_Subtype)
    ++   && zPType!=0
    ++   && p->eSubtype=='p'
    ++   && strcmp(p->u.zPType, zPType)==0
    ++  ){
    ++    return (void*)p->z;
    ++  }else{
    ++    return 0;
    ++  }
    ++}
    ++SQLITE_API const unsigned char *sqlite3_value_text(sqlite3_value *pVal){
    +   return (const unsigned char *)sqlite3ValueText(pVal, SQLITE_UTF8);
    + }
    + #ifndef SQLITE_OMIT_UTF16
    +-SQLITE_API const void *SQLITE_STDCALL sqlite3_value_text16(sqlite3_value* pVal){
    ++SQLITE_API const void *sqlite3_value_text16(sqlite3_value* pVal){
    +   return sqlite3ValueText(pVal, SQLITE_UTF16NATIVE);
    + }
    +-SQLITE_API const void *SQLITE_STDCALL sqlite3_value_text16be(sqlite3_value *pVal){
    ++SQLITE_API const void *sqlite3_value_text16be(sqlite3_value *pVal){
    +   return sqlite3ValueText(pVal, SQLITE_UTF16BE);
    + }
    +-SQLITE_API const void *SQLITE_STDCALL sqlite3_value_text16le(sqlite3_value *pVal){
    ++SQLITE_API const void *sqlite3_value_text16le(sqlite3_value *pVal){
    +   return sqlite3ValueText(pVal, SQLITE_UTF16LE);
    + }
    + #endif /* SQLITE_OMIT_UTF16 */
    +@@ -71174,7 +77935,7 @@ SQLITE_API const void *SQLITE_STDCALL sqlite3_value_text16le(sqlite3_value *pVal
    + ** fundamental datatypes: 64-bit signed integer 64-bit IEEE floating
    + ** point number string BLOB NULL
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_value_type(sqlite3_value* pVal){
    ++SQLITE_API int sqlite3_value_type(sqlite3_value* pVal){
    +   static const u8 aType[] = {
    +      SQLITE_BLOB,     /* 0x00 */
    +      SQLITE_NULL,     /* 0x01 */
    +@@ -71212,9 +77973,14 @@ SQLITE_API int SQLITE_STDCALL sqlite3_value_type(sqlite3_value* pVal){
    +   return aType[pVal->flags&MEM_AffMask];
    + }
    + 
    ++/* Return true if a parameter to xUpdate represents an unchanged column */
    ++SQLITE_API int sqlite3_value_nochange(sqlite3_value *pVal){
    ++  return (pVal->flags&(MEM_Null|MEM_Zero))==(MEM_Null|MEM_Zero);
    ++}
    ++
    + /* Make a copy of an sqlite3_value object
    + */
    +-SQLITE_API sqlite3_value *SQLITE_STDCALL sqlite3_value_dup(const sqlite3_value *pOrig){
    ++SQLITE_API sqlite3_value *sqlite3_value_dup(const sqlite3_value *pOrig){
    +   sqlite3_value *pNew;
    +   if( pOrig==0 ) return 0;
    +   pNew = sqlite3_malloc( sizeof(*pNew) );
    +@@ -71237,7 +78003,7 @@ SQLITE_API sqlite3_value *SQLITE_STDCALL sqlite3_value_dup(const sqlite3_value *
    + /* Destroy an sqlite3_value object previously obtained from
    + ** sqlite3_value_dup().
    + */
    +-SQLITE_API void SQLITE_STDCALL sqlite3_value_free(sqlite3_value *pOld){
    ++SQLITE_API void sqlite3_value_free(sqlite3_value *pOld){
    +   sqlite3ValueFree(pOld);
    + }
    +   
    +@@ -71280,7 +78046,7 @@ static int invokeValueDestructor(
    +   if( pCtx ) sqlite3_result_error_toobig(pCtx);
    +   return SQLITE_TOOBIG;
    + }
    +-SQLITE_API void SQLITE_STDCALL sqlite3_result_blob(
    ++SQLITE_API void sqlite3_result_blob(
    +   sqlite3_context *pCtx, 
    +   const void *z, 
    +   int n, 
    +@@ -71290,7 +78056,7 @@ SQLITE_API void SQLITE_STDCALL sqlite3_result_blob(
    +   assert( sqlite3_mutex_held(pCtx->pOut->db->mutex) );
    +   setResultStrOrError(pCtx, z, n, 0, xDel);
    + }
    +-SQLITE_API void SQLITE_STDCALL sqlite3_result_blob64(
    ++SQLITE_API void sqlite3_result_blob64(
    +   sqlite3_context *pCtx, 
    +   const void *z, 
    +   sqlite3_uint64 n,
    +@@ -71304,41 +78070,55 @@ SQLITE_API void SQLITE_STDCALL sqlite3_result_blob64(
    +     setResultStrOrError(pCtx, z, (int)n, 0, xDel);
    +   }
    + }
    +-SQLITE_API void SQLITE_STDCALL sqlite3_result_double(sqlite3_context *pCtx, double rVal){
    ++SQLITE_API void sqlite3_result_double(sqlite3_context *pCtx, double rVal){
    +   assert( sqlite3_mutex_held(pCtx->pOut->db->mutex) );
    +   sqlite3VdbeMemSetDouble(pCtx->pOut, rVal);
    + }
    +-SQLITE_API void SQLITE_STDCALL sqlite3_result_error(sqlite3_context *pCtx, const char *z, int n){
    ++SQLITE_API void sqlite3_result_error(sqlite3_context *pCtx, const char *z, int n){
    +   assert( sqlite3_mutex_held(pCtx->pOut->db->mutex) );
    +   pCtx->isError = SQLITE_ERROR;
    +   pCtx->fErrorOrAux = 1;
    +   sqlite3VdbeMemSetStr(pCtx->pOut, z, n, SQLITE_UTF8, SQLITE_TRANSIENT);
    + }
    + #ifndef SQLITE_OMIT_UTF16
    +-SQLITE_API void SQLITE_STDCALL sqlite3_result_error16(sqlite3_context *pCtx, const void *z, int n){
    ++SQLITE_API void sqlite3_result_error16(sqlite3_context *pCtx, const void *z, int n){
    +   assert( sqlite3_mutex_held(pCtx->pOut->db->mutex) );
    +   pCtx->isError = SQLITE_ERROR;
    +   pCtx->fErrorOrAux = 1;
    +   sqlite3VdbeMemSetStr(pCtx->pOut, z, n, SQLITE_UTF16NATIVE, SQLITE_TRANSIENT);
    + }
    + #endif
    +-SQLITE_API void SQLITE_STDCALL sqlite3_result_int(sqlite3_context *pCtx, int iVal){
    ++SQLITE_API void sqlite3_result_int(sqlite3_context *pCtx, int iVal){
    +   assert( sqlite3_mutex_held(pCtx->pOut->db->mutex) );
    +   sqlite3VdbeMemSetInt64(pCtx->pOut, (i64)iVal);
    + }
    +-SQLITE_API void SQLITE_STDCALL sqlite3_result_int64(sqlite3_context *pCtx, i64 iVal){
    ++SQLITE_API void sqlite3_result_int64(sqlite3_context *pCtx, i64 iVal){
    +   assert( sqlite3_mutex_held(pCtx->pOut->db->mutex) );
    +   sqlite3VdbeMemSetInt64(pCtx->pOut, iVal);
    + }
    +-SQLITE_API void SQLITE_STDCALL sqlite3_result_null(sqlite3_context *pCtx){
    ++SQLITE_API void sqlite3_result_null(sqlite3_context *pCtx){
    +   assert( sqlite3_mutex_held(pCtx->pOut->db->mutex) );
    +   sqlite3VdbeMemSetNull(pCtx->pOut);
    + }
    +-SQLITE_API void SQLITE_STDCALL sqlite3_result_subtype(sqlite3_context *pCtx, unsigned int eSubtype){
    +-  assert( sqlite3_mutex_held(pCtx->pOut->db->mutex) );
    +-  pCtx->pOut->eSubtype = eSubtype & 0xff;
    ++SQLITE_API void sqlite3_result_pointer(
    ++  sqlite3_context *pCtx,
    ++  void *pPtr,
    ++  const char *zPType,
    ++  void (*xDestructor)(void*)
    ++){
    ++  Mem *pOut = pCtx->pOut;
    ++  assert( sqlite3_mutex_held(pOut->db->mutex) );
    ++  sqlite3VdbeMemRelease(pOut);
    ++  pOut->flags = MEM_Null;
    ++  sqlite3VdbeMemSetPointer(pOut, pPtr, zPType, xDestructor);
    ++}
    ++SQLITE_API void sqlite3_result_subtype(sqlite3_context *pCtx, unsigned int eSubtype){
    ++  Mem *pOut = pCtx->pOut;
    ++  assert( sqlite3_mutex_held(pOut->db->mutex) );
    ++  pOut->eSubtype = eSubtype & 0xff;
    ++  pOut->flags |= MEM_Subtype;
    + }
    +-SQLITE_API void SQLITE_STDCALL sqlite3_result_text(
    ++SQLITE_API void sqlite3_result_text(
    +   sqlite3_context *pCtx, 
    +   const char *z, 
    +   int n,
    +@@ -71347,7 +78127,7 @@ SQLITE_API void SQLITE_STDCALL sqlite3_result_text(
    +   assert( sqlite3_mutex_held(pCtx->pOut->db->mutex) );
    +   setResultStrOrError(pCtx, z, n, SQLITE_UTF8, xDel);
    + }
    +-SQLITE_API void SQLITE_STDCALL sqlite3_result_text64(
    ++SQLITE_API void sqlite3_result_text64(
    +   sqlite3_context *pCtx, 
    +   const char *z, 
    +   sqlite3_uint64 n,
    +@@ -71364,7 +78144,7 @@ SQLITE_API void SQLITE_STDCALL sqlite3_result_text64(
    +   }
    + }
    + #ifndef SQLITE_OMIT_UTF16
    +-SQLITE_API void SQLITE_STDCALL sqlite3_result_text16(
    ++SQLITE_API void sqlite3_result_text16(
    +   sqlite3_context *pCtx, 
    +   const void *z, 
    +   int n, 
    +@@ -71373,7 +78153,7 @@ SQLITE_API void SQLITE_STDCALL sqlite3_result_text16(
    +   assert( sqlite3_mutex_held(pCtx->pOut->db->mutex) );
    +   setResultStrOrError(pCtx, z, n, SQLITE_UTF16NATIVE, xDel);
    + }
    +-SQLITE_API void SQLITE_STDCALL sqlite3_result_text16be(
    ++SQLITE_API void sqlite3_result_text16be(
    +   sqlite3_context *pCtx, 
    +   const void *z, 
    +   int n, 
    +@@ -71382,7 +78162,7 @@ SQLITE_API void SQLITE_STDCALL sqlite3_result_text16be(
    +   assert( sqlite3_mutex_held(pCtx->pOut->db->mutex) );
    +   setResultStrOrError(pCtx, z, n, SQLITE_UTF16BE, xDel);
    + }
    +-SQLITE_API void SQLITE_STDCALL sqlite3_result_text16le(
    ++SQLITE_API void sqlite3_result_text16le(
    +   sqlite3_context *pCtx, 
    +   const void *z, 
    +   int n, 
    +@@ -71392,15 +78172,15 @@ SQLITE_API void SQLITE_STDCALL sqlite3_result_text16le(
    +   setResultStrOrError(pCtx, z, n, SQLITE_UTF16LE, xDel);
    + }
    + #endif /* SQLITE_OMIT_UTF16 */
    +-SQLITE_API void SQLITE_STDCALL sqlite3_result_value(sqlite3_context *pCtx, sqlite3_value *pValue){
    ++SQLITE_API void sqlite3_result_value(sqlite3_context *pCtx, sqlite3_value *pValue){
    +   assert( sqlite3_mutex_held(pCtx->pOut->db->mutex) );
    +   sqlite3VdbeMemCopy(pCtx->pOut, pValue);
    + }
    +-SQLITE_API void SQLITE_STDCALL sqlite3_result_zeroblob(sqlite3_context *pCtx, int n){
    ++SQLITE_API void sqlite3_result_zeroblob(sqlite3_context *pCtx, int n){
    +   assert( sqlite3_mutex_held(pCtx->pOut->db->mutex) );
    +   sqlite3VdbeMemSetZeroBlob(pCtx->pOut, n);
    + }
    +-SQLITE_API int SQLITE_STDCALL sqlite3_result_zeroblob64(sqlite3_context *pCtx, u64 n){
    ++SQLITE_API int sqlite3_result_zeroblob64(sqlite3_context *pCtx, u64 n){
    +   Mem *pOut = pCtx->pOut;
    +   assert( sqlite3_mutex_held(pOut->db->mutex) );
    +   if( n>(u64)pOut->db->aLimit[SQLITE_LIMIT_LENGTH] ){
    +@@ -71409,7 +78189,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_result_zeroblob64(sqlite3_context *pCtx, u
    +   sqlite3VdbeMemSetZeroBlob(pCtx->pOut, (int)n);
    +   return SQLITE_OK;
    + }
    +-SQLITE_API void SQLITE_STDCALL sqlite3_result_error_code(sqlite3_context *pCtx, int errCode){
    ++SQLITE_API void sqlite3_result_error_code(sqlite3_context *pCtx, int errCode){
    +   pCtx->isError = errCode;
    +   pCtx->fErrorOrAux = 1;
    + #ifdef SQLITE_DEBUG
    +@@ -71422,7 +78202,7 @@ SQLITE_API void SQLITE_STDCALL sqlite3_result_error_code(sqlite3_context *pCtx,
    + }
    + 
    + /* Force an SQLITE_TOOBIG error. */
    +-SQLITE_API void SQLITE_STDCALL sqlite3_result_error_toobig(sqlite3_context *pCtx){
    ++SQLITE_API void sqlite3_result_error_toobig(sqlite3_context *pCtx){
    +   assert( sqlite3_mutex_held(pCtx->pOut->db->mutex) );
    +   pCtx->isError = SQLITE_TOOBIG;
    +   pCtx->fErrorOrAux = 1;
    +@@ -71431,12 +78211,12 @@ SQLITE_API void SQLITE_STDCALL sqlite3_result_error_toobig(sqlite3_context *pCtx
    + }
    + 
    + /* An SQLITE_NOMEM error. */
    +-SQLITE_API void SQLITE_STDCALL sqlite3_result_error_nomem(sqlite3_context *pCtx){
    ++SQLITE_API void sqlite3_result_error_nomem(sqlite3_context *pCtx){
    +   assert( sqlite3_mutex_held(pCtx->pOut->db->mutex) );
    +   sqlite3VdbeMemSetNull(pCtx->pOut);
    +-  pCtx->isError = SQLITE_NOMEM;
    ++  pCtx->isError = SQLITE_NOMEM_BKPT;
    +   pCtx->fErrorOrAux = 1;
    +-  pCtx->pOut->db->mallocFailed = 1;
    ++  sqlite3OomFault(pCtx->pOut->db);
    + }
    + 
    + /*
    +@@ -71454,8 +78234,8 @@ static int doWalCallbacks(sqlite3 *db){
    +       sqlite3BtreeEnter(pBt);
    +       nEntry = sqlite3PagerWalCallback(sqlite3BtreePager(pBt));
    +       sqlite3BtreeLeave(pBt);
    +-      if( db->xWalCallback && nEntry>0 && rc==SQLITE_OK ){
    +-        rc = db->xWalCallback(db->pWalArg, db, db->aDb[i].zName, nEntry);
    ++      if( nEntry>0 && db->xWalCallback && rc==SQLITE_OK ){
    ++        rc = db->xWalCallback(db->pWalArg, db, db->aDb[i].zDbSName, nEntry);
    +       }
    +     }
    +   }
    +@@ -71510,7 +78290,7 @@ static int sqlite3Step(Vdbe *p){
    +   db = p->db;
    +   if( db->mallocFailed ){
    +     p->rc = SQLITE_NOMEM;
    +-    return SQLITE_NOMEM;
    ++    return SQLITE_NOMEM_BKPT;
    +   }
    + 
    +   if( p->pc<=0 && p->expired ){
    +@@ -71532,7 +78312,8 @@ static int sqlite3Step(Vdbe *p){
    +     );
    + 
    + #ifndef SQLITE_OMIT_TRACE
    +-    if( db->xProfile && !db->init.busy && p->zSql ){
    ++    if( (db->xProfile || (db->mTrace & SQLITE_TRACE_PROFILE)!=0)
    ++        && !db->init.busy && p->zSql ){
    +       sqlite3OsCurrentTimeInt64(db->pVfs, &p->startTime);
    +     }else{
    +       assert( p->startTime==0 );
    +@@ -71563,7 +78344,7 @@ static int sqlite3Step(Vdbe *p){
    +   if( rc!=SQLITE_ROW ) checkProfileCallback(db, p);
    + #endif
    + 
    +-  if( rc==SQLITE_DONE ){
    ++  if( rc==SQLITE_DONE && db->autoCommit ){
    +     assert( p->rc==SQLITE_OK );
    +     p->rc = doWalCallbacks(db);
    +     if( p->rc!=SQLITE_OK ){
    +@@ -71573,7 +78354,7 @@ static int sqlite3Step(Vdbe *p){
    + 
    +   db->errCode = rc;
    +   if( SQLITE_NOMEM==sqlite3ApiExit(p->db, p->rc) ){
    +-    p->rc = SQLITE_NOMEM;
    ++    p->rc = SQLITE_NOMEM_BKPT;
    +   }
    + end_of_step:
    +   /* At this point local variable rc holds the value that should be 
    +@@ -71587,8 +78368,11 @@ end_of_step:
    +        || (rc&0xff)==SQLITE_BUSY || rc==SQLITE_MISUSE
    +   );
    +   assert( (p->rc!=SQLITE_ROW && p->rc!=SQLITE_DONE) || p->rc==p->rcApp );
    +-  if( p->isPrepareV2 && rc!=SQLITE_ROW && rc!=SQLITE_DONE ){
    +-    /* If this statement was prepared using sqlite3_prepare_v2(), and an
    ++  if( (p->prepFlags & SQLITE_PREPARE_SAVESQL)!=0 
    ++   && rc!=SQLITE_ROW 
    ++   && rc!=SQLITE_DONE 
    ++  ){
    ++    /* If this statement was prepared using saved SQL and an 
    +     ** error has occurred, then return the error code in p->rc to the
    +     ** caller. Set the error code in the database handle to the same value.
    +     */ 
    +@@ -71602,9 +78386,8 @@ end_of_step:
    + ** sqlite3Step() to do most of the work.  If a schema error occurs,
    + ** call sqlite3Reprepare() and try again.
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_step(sqlite3_stmt *pStmt){
    ++SQLITE_API int sqlite3_step(sqlite3_stmt *pStmt){
    +   int rc = SQLITE_OK;      /* Result from sqlite3Step() */
    +-  int rc2 = SQLITE_OK;     /* Result from sqlite3Reprepare() */
    +   Vdbe *v = (Vdbe*)pStmt;  /* the prepared statement */
    +   int cnt = 0;             /* Counter to prevent infinite loop of reprepares */
    +   sqlite3 *db;             /* The database connection */
    +@@ -71618,32 +78401,31 @@ SQLITE_API int SQLITE_STDCALL sqlite3_step(sqlite3_stmt *pStmt){
    +   while( (rc = sqlite3Step(v))==SQLITE_SCHEMA
    +          && cnt++ < SQLITE_MAX_SCHEMA_RETRY ){
    +     int savedPc = v->pc;
    +-    rc2 = rc = sqlite3Reprepare(v);
    +-    if( rc!=SQLITE_OK) break;
    ++    rc = sqlite3Reprepare(v);
    ++    if( rc!=SQLITE_OK ){
    ++      /* This case occurs after failing to recompile an sql statement. 
    ++      ** The error message from the SQL compiler has already been loaded 
    ++      ** into the database handle. This block copies the error message 
    ++      ** from the database handle into the statement and sets the statement
    ++      ** program counter to 0 to ensure that when the statement is 
    ++      ** finalized or reset the parser error message is available via
    ++      ** sqlite3_errmsg() and sqlite3_errcode().
    ++      */
    ++      const char *zErr = (const char *)sqlite3_value_text(db->pErr); 
    ++      sqlite3DbFree(db, v->zErrMsg);
    ++      if( !db->mallocFailed ){
    ++        v->zErrMsg = sqlite3DbStrDup(db, zErr);
    ++        v->rc = rc = sqlite3ApiExit(db, rc);
    ++      } else {
    ++        v->zErrMsg = 0;
    ++        v->rc = rc = SQLITE_NOMEM_BKPT;
    ++      }
    ++      break;
    ++    }
    +     sqlite3_reset(pStmt);
    +     if( savedPc>=0 ) v->doingRerun = 1;
    +     assert( v->expired==0 );
    +   }
    +-  if( rc2!=SQLITE_OK ){
    +-    /* This case occurs after failing to recompile an sql statement. 
    +-    ** The error message from the SQL compiler has already been loaded 
    +-    ** into the database handle. This block copies the error message 
    +-    ** from the database handle into the statement and sets the statement
    +-    ** program counter to 0 to ensure that when the statement is 
    +-    ** finalized or reset the parser error message is available via
    +-    ** sqlite3_errmsg() and sqlite3_errcode().
    +-    */
    +-    const char *zErr = (const char *)sqlite3_value_text(db->pErr); 
    +-    sqlite3DbFree(db, v->zErrMsg);
    +-    if( !db->mallocFailed ){
    +-      v->zErrMsg = sqlite3DbStrDup(db, zErr);
    +-      v->rc = rc2;
    +-    } else {
    +-      v->zErrMsg = 0;
    +-      v->rc = rc = SQLITE_NOMEM;
    +-    }
    +-  }
    +-  rc = sqlite3ApiExit(db, rc);
    +   sqlite3_mutex_leave(db->mutex);
    +   return rc;
    + }
    +@@ -71653,7 +78435,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_step(sqlite3_stmt *pStmt){
    + ** Extract the user data from a sqlite3_context structure and return a
    + ** pointer to it.
    + */
    +-SQLITE_API void *SQLITE_STDCALL sqlite3_user_data(sqlite3_context *p){
    ++SQLITE_API void *sqlite3_user_data(sqlite3_context *p){
    +   assert( p && p->pFunc );
    +   return p->pFunc->pUserData;
    + }
    +@@ -71668,11 +78450,30 @@ SQLITE_API void *SQLITE_STDCALL sqlite3_user_data(sqlite3_context *p){
    + ** sqlite3_create_function16() routines that originally registered the
    + ** application defined function.
    + */
    +-SQLITE_API sqlite3 *SQLITE_STDCALL sqlite3_context_db_handle(sqlite3_context *p){
    ++SQLITE_API sqlite3 *sqlite3_context_db_handle(sqlite3_context *p){
    +   assert( p && p->pOut );
    +   return p->pOut->db;
    + }
    + 
    ++/*
    ++** If this routine is invoked from within an xColumn method of a virtual
    ++** table, then it returns true if and only if the the call is during an
    ++** UPDATE operation and the value of the column will not be modified
    ++** by the UPDATE.
    ++**
    ++** If this routine is called from any context other than within the
    ++** xColumn method of a virtual table, then the return value is meaningless
    ++** and arbitrary.
    ++**
    ++** Virtual table implements might use this routine to optimize their
    ++** performance by substituting a NULL result, or some other light-weight
    ++** value, as a signal to the xUpdate routine that the column is unchanged.
    ++*/
    ++SQLITE_API int sqlite3_vtab_nochange(sqlite3_context *p){
    ++  assert( p );
    ++  return sqlite3_value_nochange(p->pOut);
    ++}
    ++
    + /*
    + ** Return the current time for a statement.  If the current time
    + ** is requested more than once within the same run of a single prepared
    +@@ -71744,8 +78545,8 @@ static SQLITE_NOINLINE void *createAggContext(sqlite3_context *p, int nByte){
    + ** context is allocated on the first call.  Subsequent calls return the
    + ** same context that was returned on prior calls.
    + */
    +-SQLITE_API void *SQLITE_STDCALL sqlite3_aggregate_context(sqlite3_context *p, int nByte){
    +-  assert( p && p->pFunc && p->pFunc->xStep );
    ++SQLITE_API void *sqlite3_aggregate_context(sqlite3_context *p, int nByte){
    ++  assert( p && p->pFunc && p->pFunc->xFinalize );
    +   assert( sqlite3_mutex_held(p->pOut->db->mutex) );
    +   testcase( nByte<0 );
    +   if( (p->pMem->flags & MEM_Agg)==0 ){
    +@@ -71758,8 +78559,14 @@ SQLITE_API void *SQLITE_STDCALL sqlite3_aggregate_context(sqlite3_context *p, in
    + /*
    + ** Return the auxiliary data pointer, if any, for the iArg'th argument to
    + ** the user-function defined by pCtx.
    ++**
    ++** The left-most argument is 0.
    ++**
    ++** Undocumented behavior:  If iArg is negative then access a cache of
    ++** auxiliary data pointers that is available to all functions within a
    ++** single prepared statement.  The iArg values must match.
    + */
    +-SQLITE_API void *SQLITE_STDCALL sqlite3_get_auxdata(sqlite3_context *pCtx, int iArg){
    ++SQLITE_API void *sqlite3_get_auxdata(sqlite3_context *pCtx, int iArg){
    +   AuxData *pAuxData;
    + 
    +   assert( sqlite3_mutex_held(pCtx->pOut->db->mutex) );
    +@@ -71768,19 +78575,26 @@ SQLITE_API void *SQLITE_STDCALL sqlite3_get_auxdata(sqlite3_context *pCtx, int i
    + #else
    +   assert( pCtx->pVdbe!=0 );
    + #endif
    +-  for(pAuxData=pCtx->pVdbe->pAuxData; pAuxData; pAuxData=pAuxData->pNext){
    +-    if( pAuxData->iOp==pCtx->iOp && pAuxData->iArg==iArg ) break;
    ++  for(pAuxData=pCtx->pVdbe->pAuxData; pAuxData; pAuxData=pAuxData->pNextAux){
    ++    if(  pAuxData->iAuxArg==iArg && (pAuxData->iAuxOp==pCtx->iOp || iArg<0) ){
    ++      return pAuxData->pAux;
    ++    }
    +   }
    +-
    +-  return (pAuxData ? pAuxData->pAux : 0);
    ++  return 0;
    + }
    + 
    + /*
    + ** Set the auxiliary data pointer and delete function, for the iArg'th
    + ** argument to the user-function defined by pCtx. Any previous value is
    + ** deleted by calling the delete function specified when it was set.
    ++**
    ++** The left-most argument is 0.
    ++**
    ++** Undocumented behavior:  If iArg is negative then make the data available
    ++** to all functions within the current prepared statement using iArg as an
    ++** access code.
    + */
    +-SQLITE_API void SQLITE_STDCALL sqlite3_set_auxdata(
    ++SQLITE_API void sqlite3_set_auxdata(
    +   sqlite3_context *pCtx, 
    +   int iArg, 
    +   void *pAux, 
    +@@ -71790,33 +78604,34 @@ SQLITE_API void SQLITE_STDCALL sqlite3_set_auxdata(
    +   Vdbe *pVdbe = pCtx->pVdbe;
    + 
    +   assert( sqlite3_mutex_held(pCtx->pOut->db->mutex) );
    +-  if( iArg<0 ) goto failed;
    + #ifdef SQLITE_ENABLE_STAT3_OR_STAT4
    +   if( pVdbe==0 ) goto failed;
    + #else
    +   assert( pVdbe!=0 );
    + #endif
    + 
    +-  for(pAuxData=pVdbe->pAuxData; pAuxData; pAuxData=pAuxData->pNext){
    +-    if( pAuxData->iOp==pCtx->iOp && pAuxData->iArg==iArg ) break;
    ++  for(pAuxData=pVdbe->pAuxData; pAuxData; pAuxData=pAuxData->pNextAux){
    ++    if( pAuxData->iAuxArg==iArg && (pAuxData->iAuxOp==pCtx->iOp || iArg<0) ){
    ++      break;
    ++    }
    +   }
    +   if( pAuxData==0 ){
    +     pAuxData = sqlite3DbMallocZero(pVdbe->db, sizeof(AuxData));
    +     if( !pAuxData ) goto failed;
    +-    pAuxData->iOp = pCtx->iOp;
    +-    pAuxData->iArg = iArg;
    +-    pAuxData->pNext = pVdbe->pAuxData;
    ++    pAuxData->iAuxOp = pCtx->iOp;
    ++    pAuxData->iAuxArg = iArg;
    ++    pAuxData->pNextAux = pVdbe->pAuxData;
    +     pVdbe->pAuxData = pAuxData;
    +     if( pCtx->fErrorOrAux==0 ){
    +       pCtx->isError = 0;
    +       pCtx->fErrorOrAux = 1;
    +     }
    +-  }else if( pAuxData->xDelete ){
    +-    pAuxData->xDelete(pAuxData->pAux);
    ++  }else if( pAuxData->xDeleteAux ){
    ++    pAuxData->xDeleteAux(pAuxData->pAux);
    +   }
    + 
    +   pAuxData->pAux = pAux;
    +-  pAuxData->xDelete = xDelete;
    ++  pAuxData->xDeleteAux = xDelete;
    +   return;
    + 
    + failed:
    +@@ -71835,8 +78650,8 @@ failed:
    + ** implementations should keep their own counts within their aggregate
    + ** context.
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_aggregate_count(sqlite3_context *p){
    +-  assert( p && p->pMem && p->pFunc && p->pFunc->xStep );
    ++SQLITE_API int sqlite3_aggregate_count(sqlite3_context *p){
    ++  assert( p && p->pMem && p->pFunc && p->pFunc->xFinalize );
    +   return p->pMem->n;
    + }
    + #endif
    +@@ -71844,7 +78659,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_aggregate_count(sqlite3_context *p){
    + /*
    + ** Return the number of columns in the result set for the statement pStmt.
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_column_count(sqlite3_stmt *pStmt){
    ++SQLITE_API int sqlite3_column_count(sqlite3_stmt *pStmt){
    +   Vdbe *pVm = (Vdbe *)pStmt;
    +   return pVm ? pVm->nResColumn : 0;
    + }
    +@@ -71853,7 +78668,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_column_count(sqlite3_stmt *pStmt){
    + ** Return the number of values available from the current row of the
    + ** currently executing statement pStmt.
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_data_count(sqlite3_stmt *pStmt){
    ++SQLITE_API int sqlite3_data_count(sqlite3_stmt *pStmt){
    +   Vdbe *pVm = (Vdbe *)pStmt;
    +   if( pVm==0 || pVm->pResultSet==0 ) return 0;
    +   return pVm->nResColumn;
    +@@ -71907,14 +78722,13 @@ static Mem *columnMem(sqlite3_stmt *pStmt, int i){
    +   Mem *pOut;
    + 
    +   pVm = (Vdbe *)pStmt;
    +-  if( pVm && pVm->pResultSet!=0 && i<pVm->nResColumn && i>=0 ){
    +-    sqlite3_mutex_enter(pVm->db->mutex);
    ++  if( pVm==0 ) return (Mem*)columnNullValue();
    ++  assert( pVm->db );
    ++  sqlite3_mutex_enter(pVm->db->mutex);
    ++  if( pVm->pResultSet!=0 && i<pVm->nResColumn && i>=0 ){
    +     pOut = &pVm->pResultSet[i];
    +   }else{
    +-    if( pVm && ALWAYS(pVm->db) ){
    +-      sqlite3_mutex_enter(pVm->db->mutex);
    +-      sqlite3Error(pVm->db, SQLITE_RANGE);
    +-    }
    ++    sqlite3Error(pVm->db, SQLITE_RANGE);
    +     pOut = (Mem*)columnNullValue();
    +   }
    +   return pOut;
    +@@ -71947,6 +78761,8 @@ static void columnMallocFailure(sqlite3_stmt *pStmt)
    +   */
    +   Vdbe *p = (Vdbe *)pStmt;
    +   if( p ){
    ++    assert( p->db!=0 );
    ++    assert( sqlite3_mutex_held(p->db->mutex) );
    +     p->rc = sqlite3ApiExit(p->db, p->rc);
    +     sqlite3_mutex_leave(p->db->mutex);
    +   }
    +@@ -71956,7 +78772,7 @@ static void columnMallocFailure(sqlite3_stmt *pStmt)
    + ** The following routines are used to access elements of the current row
    + ** in the result set.
    + */
    +-SQLITE_API const void *SQLITE_STDCALL sqlite3_column_blob(sqlite3_stmt *pStmt, int i){
    ++SQLITE_API const void *sqlite3_column_blob(sqlite3_stmt *pStmt, int i){
    +   const void *val;
    +   val = sqlite3_value_blob( columnMem(pStmt,i) );
    +   /* Even though there is no encoding conversion, value_blob() might
    +@@ -71966,37 +78782,37 @@ SQLITE_API const void *SQLITE_STDCALL sqlite3_column_blob(sqlite3_stmt *pStmt, i
    +   columnMallocFailure(pStmt);
    +   return val;
    + }
    +-SQLITE_API int SQLITE_STDCALL sqlite3_column_bytes(sqlite3_stmt *pStmt, int i){
    ++SQLITE_API int sqlite3_column_bytes(sqlite3_stmt *pStmt, int i){
    +   int val = sqlite3_value_bytes( columnMem(pStmt,i) );
    +   columnMallocFailure(pStmt);
    +   return val;
    + }
    +-SQLITE_API int SQLITE_STDCALL sqlite3_column_bytes16(sqlite3_stmt *pStmt, int i){
    ++SQLITE_API int sqlite3_column_bytes16(sqlite3_stmt *pStmt, int i){
    +   int val = sqlite3_value_bytes16( columnMem(pStmt,i) );
    +   columnMallocFailure(pStmt);
    +   return val;
    + }
    +-SQLITE_API double SQLITE_STDCALL sqlite3_column_double(sqlite3_stmt *pStmt, int i){
    ++SQLITE_API double sqlite3_column_double(sqlite3_stmt *pStmt, int i){
    +   double val = sqlite3_value_double( columnMem(pStmt,i) );
    +   columnMallocFailure(pStmt);
    +   return val;
    + }
    +-SQLITE_API int SQLITE_STDCALL sqlite3_column_int(sqlite3_stmt *pStmt, int i){
    ++SQLITE_API int sqlite3_column_int(sqlite3_stmt *pStmt, int i){
    +   int val = sqlite3_value_int( columnMem(pStmt,i) );
    +   columnMallocFailure(pStmt);
    +   return val;
    + }
    +-SQLITE_API sqlite_int64 SQLITE_STDCALL sqlite3_column_int64(sqlite3_stmt *pStmt, int i){
    ++SQLITE_API sqlite_int64 sqlite3_column_int64(sqlite3_stmt *pStmt, int i){
    +   sqlite_int64 val = sqlite3_value_int64( columnMem(pStmt,i) );
    +   columnMallocFailure(pStmt);
    +   return val;
    + }
    +-SQLITE_API const unsigned char *SQLITE_STDCALL sqlite3_column_text(sqlite3_stmt *pStmt, int i){
    ++SQLITE_API const unsigned char *sqlite3_column_text(sqlite3_stmt *pStmt, int i){
    +   const unsigned char *val = sqlite3_value_text( columnMem(pStmt,i) );
    +   columnMallocFailure(pStmt);
    +   return val;
    + }
    +-SQLITE_API sqlite3_value *SQLITE_STDCALL sqlite3_column_value(sqlite3_stmt *pStmt, int i){
    ++SQLITE_API sqlite3_value *sqlite3_column_value(sqlite3_stmt *pStmt, int i){
    +   Mem *pOut = columnMem(pStmt, i);
    +   if( pOut->flags&MEM_Static ){
    +     pOut->flags &= ~MEM_Static;
    +@@ -72006,13 +78822,13 @@ SQLITE_API sqlite3_value *SQLITE_STDCALL sqlite3_column_value(sqlite3_stmt *pStm
    +   return (sqlite3_value *)pOut;
    + }
    + #ifndef SQLITE_OMIT_UTF16
    +-SQLITE_API const void *SQLITE_STDCALL sqlite3_column_text16(sqlite3_stmt *pStmt, int i){
    ++SQLITE_API const void *sqlite3_column_text16(sqlite3_stmt *pStmt, int i){
    +   const void *val = sqlite3_value_text16( columnMem(pStmt,i) );
    +   columnMallocFailure(pStmt);
    +   return val;
    + }
    + #endif /* SQLITE_OMIT_UTF16 */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_column_type(sqlite3_stmt *pStmt, int i){
    ++SQLITE_API int sqlite3_column_type(sqlite3_stmt *pStmt, int i){
    +   int iType = sqlite3_value_type( columnMem(pStmt,i) );
    +   columnMallocFailure(pStmt);
    +   return iType;
    +@@ -72064,7 +78880,7 @@ static const void *columnName(
    +     ** is the case, clear the mallocFailed flag and return NULL.
    +     */
    +     if( db->mallocFailed ){
    +-      db->mallocFailed = 0;
    ++      sqlite3OomClear(db);
    +       ret = 0;
    +     }
    +     sqlite3_mutex_leave(db->mutex);
    +@@ -72076,12 +78892,12 @@ static const void *columnName(
    + ** Return the name of the Nth column of the result set returned by SQL
    + ** statement pStmt.
    + */
    +-SQLITE_API const char *SQLITE_STDCALL sqlite3_column_name(sqlite3_stmt *pStmt, int N){
    ++SQLITE_API const char *sqlite3_column_name(sqlite3_stmt *pStmt, int N){
    +   return columnName(
    +       pStmt, N, (const void*(*)(Mem*))sqlite3_value_text, COLNAME_NAME);
    + }
    + #ifndef SQLITE_OMIT_UTF16
    +-SQLITE_API const void *SQLITE_STDCALL sqlite3_column_name16(sqlite3_stmt *pStmt, int N){
    ++SQLITE_API const void *sqlite3_column_name16(sqlite3_stmt *pStmt, int N){
    +   return columnName(
    +       pStmt, N, (const void*(*)(Mem*))sqlite3_value_text16, COLNAME_NAME);
    + }
    +@@ -72101,12 +78917,12 @@ SQLITE_API const void *SQLITE_STDCALL sqlite3_column_name16(sqlite3_stmt *pStmt,
    + ** Return the column declaration type (if applicable) of the 'i'th column
    + ** of the result set of SQL statement pStmt.
    + */
    +-SQLITE_API const char *SQLITE_STDCALL sqlite3_column_decltype(sqlite3_stmt *pStmt, int N){
    ++SQLITE_API const char *sqlite3_column_decltype(sqlite3_stmt *pStmt, int N){
    +   return columnName(
    +       pStmt, N, (const void*(*)(Mem*))sqlite3_value_text, COLNAME_DECLTYPE);
    + }
    + #ifndef SQLITE_OMIT_UTF16
    +-SQLITE_API const void *SQLITE_STDCALL sqlite3_column_decltype16(sqlite3_stmt *pStmt, int N){
    ++SQLITE_API const void *sqlite3_column_decltype16(sqlite3_stmt *pStmt, int N){
    +   return columnName(
    +       pStmt, N, (const void*(*)(Mem*))sqlite3_value_text16, COLNAME_DECLTYPE);
    + }
    +@@ -72119,12 +78935,12 @@ SQLITE_API const void *SQLITE_STDCALL sqlite3_column_decltype16(sqlite3_stmt *pS
    + ** NULL is returned if the result column is an expression or constant or
    + ** anything else which is not an unambiguous reference to a database column.
    + */
    +-SQLITE_API const char *SQLITE_STDCALL sqlite3_column_database_name(sqlite3_stmt *pStmt, int N){
    ++SQLITE_API const char *sqlite3_column_database_name(sqlite3_stmt *pStmt, int N){
    +   return columnName(
    +       pStmt, N, (const void*(*)(Mem*))sqlite3_value_text, COLNAME_DATABASE);
    + }
    + #ifndef SQLITE_OMIT_UTF16
    +-SQLITE_API const void *SQLITE_STDCALL sqlite3_column_database_name16(sqlite3_stmt *pStmt, int N){
    ++SQLITE_API const void *sqlite3_column_database_name16(sqlite3_stmt *pStmt, int N){
    +   return columnName(
    +       pStmt, N, (const void*(*)(Mem*))sqlite3_value_text16, COLNAME_DATABASE);
    + }
    +@@ -72135,12 +78951,12 @@ SQLITE_API const void *SQLITE_STDCALL sqlite3_column_database_name16(sqlite3_stm
    + ** NULL is returned if the result column is an expression or constant or
    + ** anything else which is not an unambiguous reference to a database column.
    + */
    +-SQLITE_API const char *SQLITE_STDCALL sqlite3_column_table_name(sqlite3_stmt *pStmt, int N){
    ++SQLITE_API const char *sqlite3_column_table_name(sqlite3_stmt *pStmt, int N){
    +   return columnName(
    +       pStmt, N, (const void*(*)(Mem*))sqlite3_value_text, COLNAME_TABLE);
    + }
    + #ifndef SQLITE_OMIT_UTF16
    +-SQLITE_API const void *SQLITE_STDCALL sqlite3_column_table_name16(sqlite3_stmt *pStmt, int N){
    ++SQLITE_API const void *sqlite3_column_table_name16(sqlite3_stmt *pStmt, int N){
    +   return columnName(
    +       pStmt, N, (const void*(*)(Mem*))sqlite3_value_text16, COLNAME_TABLE);
    + }
    +@@ -72151,12 +78967,12 @@ SQLITE_API const void *SQLITE_STDCALL sqlite3_column_table_name16(sqlite3_stmt *
    + ** NULL is returned if the result column is an expression or constant or
    + ** anything else which is not an unambiguous reference to a database column.
    + */
    +-SQLITE_API const char *SQLITE_STDCALL sqlite3_column_origin_name(sqlite3_stmt *pStmt, int N){
    ++SQLITE_API const char *sqlite3_column_origin_name(sqlite3_stmt *pStmt, int N){
    +   return columnName(
    +       pStmt, N, (const void*(*)(Mem*))sqlite3_value_text, COLNAME_COLUMN);
    + }
    + #ifndef SQLITE_OMIT_UTF16
    +-SQLITE_API const void *SQLITE_STDCALL sqlite3_column_origin_name16(sqlite3_stmt *pStmt, int N){
    ++SQLITE_API const void *sqlite3_column_origin_name16(sqlite3_stmt *pStmt, int N){
    +   return columnName(
    +       pStmt, N, (const void*(*)(Mem*))sqlite3_value_text16, COLNAME_COLUMN);
    + }
    +@@ -72212,9 +79028,8 @@ static int vdbeUnbind(Vdbe *p, int i){
    +   ** as if there had been a schema change, on the first sqlite3_step() call
    +   ** following any change to the bindings of that parameter.
    +   */
    +-  if( p->isPrepareV2 &&
    +-     ((i<32 && p->expmask & ((u32)1 << i)) || p->expmask==0xffffffff)
    +-  ){
    ++  assert( (p->prepFlags & SQLITE_PREPARE_SAVESQL)!=0 || p->expmask==0 );
    ++  if( p->expmask!=0 && (p->expmask & (i>=31 ? 0x80000000 : (u32)1<<i))!=0 ){
    +     p->expired = 1;
    +   }
    +   return SQLITE_OK;
    +@@ -72243,8 +79058,10 @@ static int bindText(
    +       if( rc==SQLITE_OK && encoding!=0 ){
    +         rc = sqlite3VdbeChangeEncoding(pVar, ENC(p->db));
    +       }
    +-      sqlite3Error(p->db, rc);
    +-      rc = sqlite3ApiExit(p->db, rc);
    ++      if( rc ){
    ++        sqlite3Error(p->db, rc);
    ++        rc = sqlite3ApiExit(p->db, rc);
    ++      }
    +     }
    +     sqlite3_mutex_leave(p->db->mutex);
    +   }else if( xDel!=SQLITE_STATIC && xDel!=SQLITE_TRANSIENT ){
    +@@ -72257,16 +79074,19 @@ static int bindText(
    + /*
    + ** Bind a blob value to an SQL statement variable.
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_bind_blob(
    ++SQLITE_API int sqlite3_bind_blob(
    +   sqlite3_stmt *pStmt, 
    +   int i, 
    +   const void *zData, 
    +   int nData, 
    +   void (*xDel)(void*)
    + ){
    ++#ifdef SQLITE_ENABLE_API_ARMOR
    ++  if( nData<0 ) return SQLITE_MISUSE_BKPT;
    ++#endif
    +   return bindText(pStmt, i, zData, nData, xDel, 0);
    + }
    +-SQLITE_API int SQLITE_STDCALL sqlite3_bind_blob64(
    ++SQLITE_API int sqlite3_bind_blob64(
    +   sqlite3_stmt *pStmt, 
    +   int i, 
    +   const void *zData, 
    +@@ -72280,7 +79100,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_bind_blob64(
    +     return bindText(pStmt, i, zData, (int)nData, xDel, 0);
    +   }
    + }
    +-SQLITE_API int SQLITE_STDCALL sqlite3_bind_double(sqlite3_stmt *pStmt, int i, double rValue){
    ++SQLITE_API int sqlite3_bind_double(sqlite3_stmt *pStmt, int i, double rValue){
    +   int rc;
    +   Vdbe *p = (Vdbe *)pStmt;
    +   rc = vdbeUnbind(p, i);
    +@@ -72290,10 +79110,10 @@ SQLITE_API int SQLITE_STDCALL sqlite3_bind_double(sqlite3_stmt *pStmt, int i, do
    +   }
    +   return rc;
    + }
    +-SQLITE_API int SQLITE_STDCALL sqlite3_bind_int(sqlite3_stmt *p, int i, int iValue){
    ++SQLITE_API int sqlite3_bind_int(sqlite3_stmt *p, int i, int iValue){
    +   return sqlite3_bind_int64(p, i, (i64)iValue);
    + }
    +-SQLITE_API int SQLITE_STDCALL sqlite3_bind_int64(sqlite3_stmt *pStmt, int i, sqlite_int64 iValue){
    ++SQLITE_API int sqlite3_bind_int64(sqlite3_stmt *pStmt, int i, sqlite_int64 iValue){
    +   int rc;
    +   Vdbe *p = (Vdbe *)pStmt;
    +   rc = vdbeUnbind(p, i);
    +@@ -72303,16 +79123,34 @@ SQLITE_API int SQLITE_STDCALL sqlite3_bind_int64(sqlite3_stmt *pStmt, int i, sql
    +   }
    +   return rc;
    + }
    +-SQLITE_API int SQLITE_STDCALL sqlite3_bind_null(sqlite3_stmt *pStmt, int i){
    ++SQLITE_API int sqlite3_bind_null(sqlite3_stmt *pStmt, int i){
    ++  int rc;
    ++  Vdbe *p = (Vdbe*)pStmt;
    ++  rc = vdbeUnbind(p, i);
    ++  if( rc==SQLITE_OK ){
    ++    sqlite3_mutex_leave(p->db->mutex);
    ++  }
    ++  return rc;
    ++}
    ++SQLITE_API int sqlite3_bind_pointer(
    ++  sqlite3_stmt *pStmt,
    ++  int i,
    ++  void *pPtr,
    ++  const char *zPTtype,
    ++  void (*xDestructor)(void*)
    ++){
    +   int rc;
    +   Vdbe *p = (Vdbe*)pStmt;
    +   rc = vdbeUnbind(p, i);
    +   if( rc==SQLITE_OK ){
    ++    sqlite3VdbeMemSetPointer(&p->aVar[i-1], pPtr, zPTtype, xDestructor);
    +     sqlite3_mutex_leave(p->db->mutex);
    ++  }else if( xDestructor ){
    ++    xDestructor(pPtr);
    +   }
    +   return rc;
    + }
    +-SQLITE_API int SQLITE_STDCALL sqlite3_bind_text( 
    ++SQLITE_API int sqlite3_bind_text( 
    +   sqlite3_stmt *pStmt, 
    +   int i, 
    +   const char *zData, 
    +@@ -72321,7 +79159,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_bind_text(
    + ){
    +   return bindText(pStmt, i, zData, nData, xDel, SQLITE_UTF8);
    + }
    +-SQLITE_API int SQLITE_STDCALL sqlite3_bind_text64( 
    ++SQLITE_API int sqlite3_bind_text64( 
    +   sqlite3_stmt *pStmt, 
    +   int i, 
    +   const char *zData, 
    +@@ -72338,7 +79176,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_bind_text64(
    +   }
    + }
    + #ifndef SQLITE_OMIT_UTF16
    +-SQLITE_API int SQLITE_STDCALL sqlite3_bind_text16(
    ++SQLITE_API int sqlite3_bind_text16(
    +   sqlite3_stmt *pStmt, 
    +   int i, 
    +   const void *zData, 
    +@@ -72348,7 +79186,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_bind_text16(
    +   return bindText(pStmt, i, zData, nData, xDel, SQLITE_UTF16NATIVE);
    + }
    + #endif /* SQLITE_OMIT_UTF16 */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_bind_value(sqlite3_stmt *pStmt, int i, const sqlite3_value *pValue){
    ++SQLITE_API int sqlite3_bind_value(sqlite3_stmt *pStmt, int i, const sqlite3_value *pValue){
    +   int rc;
    +   switch( sqlite3_value_type((sqlite3_value*)pValue) ){
    +     case SQLITE_INTEGER: {
    +@@ -72379,7 +79217,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_bind_value(sqlite3_stmt *pStmt, int i, con
    +   }
    +   return rc;
    + }
    +-SQLITE_API int SQLITE_STDCALL sqlite3_bind_zeroblob(sqlite3_stmt *pStmt, int i, int n){
    ++SQLITE_API int sqlite3_bind_zeroblob(sqlite3_stmt *pStmt, int i, int n){
    +   int rc;
    +   Vdbe *p = (Vdbe *)pStmt;
    +   rc = vdbeUnbind(p, i);
    +@@ -72389,7 +79227,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_bind_zeroblob(sqlite3_stmt *pStmt, int i,
    +   }
    +   return rc;
    + }
    +-SQLITE_API int SQLITE_STDCALL sqlite3_bind_zeroblob64(sqlite3_stmt *pStmt, int i, sqlite3_uint64 n){
    ++SQLITE_API int sqlite3_bind_zeroblob64(sqlite3_stmt *pStmt, int i, sqlite3_uint64 n){
    +   int rc;
    +   Vdbe *p = (Vdbe *)pStmt;
    +   sqlite3_mutex_enter(p->db->mutex);
    +@@ -72408,7 +79246,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_bind_zeroblob64(sqlite3_stmt *pStmt, int i
    + ** Return the number of wildcards that can be potentially bound to.
    + ** This routine is added to support DBD::SQLite.  
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_bind_parameter_count(sqlite3_stmt *pStmt){
    ++SQLITE_API int sqlite3_bind_parameter_count(sqlite3_stmt *pStmt){
    +   Vdbe *p = (Vdbe*)pStmt;
    +   return p ? p->nVar : 0;
    + }
    +@@ -72419,12 +79257,10 @@ SQLITE_API int SQLITE_STDCALL sqlite3_bind_parameter_count(sqlite3_stmt *pStmt){
    + **
    + ** The result is always UTF-8.
    + */
    +-SQLITE_API const char *SQLITE_STDCALL sqlite3_bind_parameter_name(sqlite3_stmt *pStmt, int i){
    ++SQLITE_API const char *sqlite3_bind_parameter_name(sqlite3_stmt *pStmt, int i){
    +   Vdbe *p = (Vdbe*)pStmt;
    +-  if( p==0 || i<1 || i>p->nzVar ){
    +-    return 0;
    +-  }
    +-  return p->azVar[i-1];
    ++  if( p==0 ) return 0;
    ++  return sqlite3VListNumToName(p->pVList, i);
    + }
    + 
    + /*
    +@@ -72433,21 +79269,10 @@ SQLITE_API const char *SQLITE_STDCALL sqlite3_bind_parameter_name(sqlite3_stmt *
    + ** return 0.
    + */
    + SQLITE_PRIVATE int sqlite3VdbeParameterIndex(Vdbe *p, const char *zName, int nName){
    +-  int i;
    +-  if( p==0 ){
    +-    return 0;
    +-  }
    +-  if( zName ){
    +-    for(i=0; i<p->nzVar; i++){
    +-      const char *z = p->azVar[i];
    +-      if( z && strncmp(z,zName,nName)==0 && z[nName]==0 ){
    +-        return i+1;
    +-      }
    +-    }
    +-  }
    +-  return 0;
    ++  if( p==0 || zName==0 ) return 0;
    ++  return sqlite3VListNameToNum(p->pVList, zName, nName);
    + }
    +-SQLITE_API int SQLITE_STDCALL sqlite3_bind_parameter_index(sqlite3_stmt *pStmt, const char *zName){
    ++SQLITE_API int sqlite3_bind_parameter_index(sqlite3_stmt *pStmt, const char *zName){
    +   return sqlite3VdbeParameterIndex((Vdbe*)pStmt, zName, sqlite3Strlen30(zName));
    + }
    + 
    +@@ -72481,16 +79306,18 @@ SQLITE_PRIVATE int sqlite3TransferBindings(sqlite3_stmt *pFromStmt, sqlite3_stmt
    + ** an SQLITE_ERROR is returned.  Nothing else can go wrong, so otherwise
    + ** SQLITE_OK is returned.
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_transfer_bindings(sqlite3_stmt *pFromStmt, sqlite3_stmt *pToStmt){
    ++SQLITE_API int sqlite3_transfer_bindings(sqlite3_stmt *pFromStmt, sqlite3_stmt *pToStmt){
    +   Vdbe *pFrom = (Vdbe*)pFromStmt;
    +   Vdbe *pTo = (Vdbe*)pToStmt;
    +   if( pFrom->nVar!=pTo->nVar ){
    +     return SQLITE_ERROR;
    +   }
    +-  if( pTo->isPrepareV2 && pTo->expmask ){
    ++  assert( (pTo->prepFlags & SQLITE_PREPARE_SAVESQL)!=0 || pTo->expmask==0 );
    ++  if( pTo->expmask ){
    +     pTo->expired = 1;
    +   }
    +-  if( pFrom->isPrepareV2 && pFrom->expmask ){
    ++  assert( (pFrom->prepFlags & SQLITE_PREPARE_SAVESQL)!=0 || pFrom->expmask==0 );
    ++  if( pFrom->expmask ){
    +     pFrom->expired = 1;
    +   }
    +   return sqlite3TransferBindings(pFromStmt, pToStmt);
    +@@ -72503,7 +79330,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_transfer_bindings(sqlite3_stmt *pFromStmt,
    + ** the first argument to the sqlite3_prepare() that was used to create
    + ** the statement in the first place.
    + */
    +-SQLITE_API sqlite3 *SQLITE_STDCALL sqlite3_db_handle(sqlite3_stmt *pStmt){
    ++SQLITE_API sqlite3 *sqlite3_db_handle(sqlite3_stmt *pStmt){
    +   return pStmt ? ((Vdbe*)pStmt)->db : 0;
    + }
    + 
    +@@ -72511,16 +79338,16 @@ SQLITE_API sqlite3 *SQLITE_STDCALL sqlite3_db_handle(sqlite3_stmt *pStmt){
    + ** Return true if the prepared statement is guaranteed to not modify the
    + ** database.
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_stmt_readonly(sqlite3_stmt *pStmt){
    ++SQLITE_API int sqlite3_stmt_readonly(sqlite3_stmt *pStmt){
    +   return pStmt ? ((Vdbe*)pStmt)->readOnly : 1;
    + }
    + 
    + /*
    + ** Return true if the prepared statement is in need of being reset.
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_stmt_busy(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->magic==VDBE_MAGIC_RUN && v->pc>=0;
    + }
    + 
    + /*
    +@@ -72529,7 +79356,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_stmt_busy(sqlite3_stmt *pStmt){
    + ** prepared statement for the database connection.  Return NULL if there
    + ** are no more.
    + */
    +-SQLITE_API sqlite3_stmt *SQLITE_STDCALL sqlite3_next_stmt(sqlite3 *pDb, sqlite3_stmt *pStmt){
    ++SQLITE_API sqlite3_stmt *sqlite3_next_stmt(sqlite3 *pDb, sqlite3_stmt *pStmt){
    +   sqlite3_stmt *pNext;
    + #ifdef SQLITE_ENABLE_API_ARMOR
    +   if( !sqlite3SafetyCheckOk(pDb) ){
    +@@ -72550,7 +79377,7 @@ SQLITE_API sqlite3_stmt *SQLITE_STDCALL sqlite3_next_stmt(sqlite3 *pDb, sqlite3_
    + /*
    + ** Return the value of a status counter for a prepared statement
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_stmt_status(sqlite3_stmt *pStmt, int op, int resetFlag){
    ++SQLITE_API int sqlite3_stmt_status(sqlite3_stmt *pStmt, int op, int resetFlag){
    +   Vdbe *pVdbe = (Vdbe*)pStmt;
    +   u32 v;
    + #ifdef SQLITE_ENABLE_API_ARMOR
    +@@ -72559,16 +79386,246 @@ SQLITE_API int SQLITE_STDCALL sqlite3_stmt_status(sqlite3_stmt *pStmt, int op, i
    +     return 0;
    +   }
    + #endif
    +-  v = pVdbe->aCounter[op];
    +-  if( resetFlag ) pVdbe->aCounter[op] = 0;
    ++  if( op==SQLITE_STMTSTATUS_MEMUSED ){
    ++    sqlite3 *db = pVdbe->db;
    ++    sqlite3_mutex_enter(db->mutex);
    ++    v = 0;
    ++    db->pnBytesFreed = (int*)&v;
    ++    sqlite3VdbeClearObject(db, pVdbe);
    ++    sqlite3DbFree(db, pVdbe);
    ++    db->pnBytesFreed = 0;
    ++    sqlite3_mutex_leave(db->mutex);
    ++  }else{
    ++    v = pVdbe->aCounter[op];
    ++    if( resetFlag ) pVdbe->aCounter[op] = 0;
    ++  }
    +   return (int)v;
    + }
    + 
    ++/*
    ++** Return the SQL associated with a prepared statement
    ++*/
    ++SQLITE_API const char *sqlite3_sql(sqlite3_stmt *pStmt){
    ++  Vdbe *p = (Vdbe *)pStmt;
    ++  return p ? p->zSql : 0;
    ++}
    ++
    ++/*
    ++** Return the SQL associated with a prepared statement with
    ++** bound parameters expanded.  Space to hold the returned string is
    ++** obtained from sqlite3_malloc().  The caller is responsible for
    ++** freeing the returned string by passing it to sqlite3_free().
    ++**
    ++** The SQLITE_TRACE_SIZE_LIMIT puts an upper bound on the size of
    ++** expanded bound parameters.
    ++*/
    ++SQLITE_API char *sqlite3_expanded_sql(sqlite3_stmt *pStmt){
    ++#ifdef SQLITE_OMIT_TRACE
    ++  return 0;
    ++#else
    ++  char *z = 0;
    ++  const char *zSql = sqlite3_sql(pStmt);
    ++  if( zSql ){
    ++    Vdbe *p = (Vdbe *)pStmt;
    ++    sqlite3_mutex_enter(p->db->mutex);
    ++    z = sqlite3VdbeExpandSql(p, zSql);
    ++    sqlite3_mutex_leave(p->db->mutex);
    ++  }
    ++  return z;
    ++#endif
    ++}
    ++
    ++#ifdef SQLITE_ENABLE_PREUPDATE_HOOK
    ++/*
    ++** Allocate and populate an UnpackedRecord structure based on the serialized
    ++** record in nKey/pKey. Return a pointer to the new UnpackedRecord structure
    ++** if successful, or a NULL pointer if an OOM error is encountered.
    ++*/
    ++static UnpackedRecord *vdbeUnpackRecord(
    ++  KeyInfo *pKeyInfo, 
    ++  int nKey, 
    ++  const void *pKey
    ++){
    ++  UnpackedRecord *pRet;           /* Return value */
    ++
    ++  pRet = sqlite3VdbeAllocUnpackedRecord(pKeyInfo);
    ++  if( pRet ){
    ++    memset(pRet->aMem, 0, sizeof(Mem)*(pKeyInfo->nKeyField+1));
    ++    sqlite3VdbeRecordUnpack(pKeyInfo, nKey, pKey, pRet);
    ++  }
    ++  return pRet;
    ++}
    ++
    ++/*
    ++** This function is called from within a pre-update callback to retrieve
    ++** a field of the row currently being updated or deleted.
    ++*/
    ++SQLITE_API int sqlite3_preupdate_old(sqlite3 *db, int iIdx, sqlite3_value **ppValue){
    ++  PreUpdate *p = db->pPreUpdate;
    ++  Mem *pMem;
    ++  int rc = SQLITE_OK;
    ++
    ++  /* Test that this call is being made from within an SQLITE_DELETE or
    ++  ** SQLITE_UPDATE pre-update callback, and that iIdx is within range. */
    ++  if( !p || p->op==SQLITE_INSERT ){
    ++    rc = SQLITE_MISUSE_BKPT;
    ++    goto preupdate_old_out;
    ++  }
    ++  if( p->pPk ){
    ++    iIdx = sqlite3ColumnOfIndex(p->pPk, iIdx);
    ++  }
    ++  if( iIdx>=p->pCsr->nField || iIdx<0 ){
    ++    rc = SQLITE_RANGE;
    ++    goto preupdate_old_out;
    ++  }
    ++
    ++  /* If the old.* record has not yet been loaded into memory, do so now. */
    ++  if( p->pUnpacked==0 ){
    ++    u32 nRec;
    ++    u8 *aRec;
    ++
    ++    nRec = sqlite3BtreePayloadSize(p->pCsr->uc.pCursor);
    ++    aRec = sqlite3DbMallocRaw(db, nRec);
    ++    if( !aRec ) goto preupdate_old_out;
    ++    rc = sqlite3BtreePayload(p->pCsr->uc.pCursor, 0, nRec, aRec);
    ++    if( rc==SQLITE_OK ){
    ++      p->pUnpacked = vdbeUnpackRecord(&p->keyinfo, nRec, aRec);
    ++      if( !p->pUnpacked ) rc = SQLITE_NOMEM;
    ++    }
    ++    if( rc!=SQLITE_OK ){
    ++      sqlite3DbFree(db, aRec);
    ++      goto preupdate_old_out;
    ++    }
    ++    p->aRecord = aRec;
    ++  }
    ++
    ++  pMem = *ppValue = &p->pUnpacked->aMem[iIdx];
    ++  if( iIdx==p->pTab->iPKey ){
    ++    sqlite3VdbeMemSetInt64(pMem, p->iKey1);
    ++  }else if( iIdx>=p->pUnpacked->nField ){
    ++    *ppValue = (sqlite3_value *)columnNullValue();
    ++  }else if( p->pTab->aCol[iIdx].affinity==SQLITE_AFF_REAL ){
    ++    if( pMem->flags & MEM_Int ){
    ++      sqlite3VdbeMemRealify(pMem);
    ++    }
    ++  }
    ++
    ++ preupdate_old_out:
    ++  sqlite3Error(db, rc);
    ++  return sqlite3ApiExit(db, rc);
    ++}
    ++#endif /* SQLITE_ENABLE_PREUPDATE_HOOK */
    ++
    ++#ifdef SQLITE_ENABLE_PREUPDATE_HOOK
    ++/*
    ++** This function is called from within a pre-update callback to retrieve
    ++** the number of columns in the row being updated, deleted or inserted.
    ++*/
    ++SQLITE_API int sqlite3_preupdate_count(sqlite3 *db){
    ++  PreUpdate *p = db->pPreUpdate;
    ++  return (p ? p->keyinfo.nKeyField : 0);
    ++}
    ++#endif /* SQLITE_ENABLE_PREUPDATE_HOOK */
    ++
    ++#ifdef SQLITE_ENABLE_PREUPDATE_HOOK
    ++/*
    ++** This function is designed to be called from within a pre-update callback
    ++** only. It returns zero if the change that caused the callback was made
    ++** immediately by a user SQL statement. Or, if the change was made by a
    ++** trigger program, it returns the number of trigger programs currently
    ++** on the stack (1 for a top-level trigger, 2 for a trigger fired by a 
    ++** top-level trigger etc.).
    ++**
    ++** For the purposes of the previous paragraph, a foreign key CASCADE, SET NULL
    ++** or SET DEFAULT action is considered a trigger.
    ++*/
    ++SQLITE_API int sqlite3_preupdate_depth(sqlite3 *db){
    ++  PreUpdate *p = db->pPreUpdate;
    ++  return (p ? p->v->nFrame : 0);
    ++}
    ++#endif /* SQLITE_ENABLE_PREUPDATE_HOOK */
    ++
    ++#ifdef SQLITE_ENABLE_PREUPDATE_HOOK
    ++/*
    ++** This function is called from within a pre-update callback to retrieve
    ++** a field of the row currently being updated or inserted.
    ++*/
    ++SQLITE_API int sqlite3_preupdate_new(sqlite3 *db, int iIdx, sqlite3_value **ppValue){
    ++  PreUpdate *p = db->pPreUpdate;
    ++  int rc = SQLITE_OK;
    ++  Mem *pMem;
    ++
    ++  if( !p || p->op==SQLITE_DELETE ){
    ++    rc = SQLITE_MISUSE_BKPT;
    ++    goto preupdate_new_out;
    ++  }
    ++  if( p->pPk && p->op!=SQLITE_UPDATE ){
    ++    iIdx = sqlite3ColumnOfIndex(p->pPk, iIdx);
    ++  }
    ++  if( iIdx>=p->pCsr->nField || iIdx<0 ){
    ++    rc = SQLITE_RANGE;
    ++    goto preupdate_new_out;
    ++  }
    ++
    ++  if( p->op==SQLITE_INSERT ){
    ++    /* For an INSERT, memory cell p->iNewReg contains the serialized record
    ++    ** that is being inserted. Deserialize it. */
    ++    UnpackedRecord *pUnpack = p->pNewUnpacked;
    ++    if( !pUnpack ){
    ++      Mem *pData = &p->v->aMem[p->iNewReg];
    ++      rc = ExpandBlob(pData);
    ++      if( rc!=SQLITE_OK ) goto preupdate_new_out;
    ++      pUnpack = vdbeUnpackRecord(&p->keyinfo, pData->n, pData->z);
    ++      if( !pUnpack ){
    ++        rc = SQLITE_NOMEM;
    ++        goto preupdate_new_out;
    ++      }
    ++      p->pNewUnpacked = pUnpack;
    ++    }
    ++    pMem = &pUnpack->aMem[iIdx];
    ++    if( iIdx==p->pTab->iPKey ){
    ++      sqlite3VdbeMemSetInt64(pMem, p->iKey2);
    ++    }else if( iIdx>=pUnpack->nField ){
    ++      pMem = (sqlite3_value *)columnNullValue();
    ++    }
    ++  }else{
    ++    /* For an UPDATE, memory cell (p->iNewReg+1+iIdx) contains the required
    ++    ** value. Make a copy of the cell contents and return a pointer to it.
    ++    ** It is not safe to return a pointer to the memory cell itself as the
    ++    ** caller may modify the value text encoding.
    ++    */
    ++    assert( p->op==SQLITE_UPDATE );
    ++    if( !p->aNew ){
    ++      p->aNew = (Mem *)sqlite3DbMallocZero(db, sizeof(Mem) * p->pCsr->nField);
    ++      if( !p->aNew ){
    ++        rc = SQLITE_NOMEM;
    ++        goto preupdate_new_out;
    ++      }
    ++    }
    ++    assert( iIdx>=0 && iIdx<p->pCsr->nField );
    ++    pMem = &p->aNew[iIdx];
    ++    if( pMem->flags==0 ){
    ++      if( iIdx==p->pTab->iPKey ){
    ++        sqlite3VdbeMemSetInt64(pMem, p->iKey2);
    ++      }else{
    ++        rc = sqlite3VdbeMemCopy(pMem, &p->v->aMem[p->iNewReg+1+iIdx]);
    ++        if( rc!=SQLITE_OK ) goto preupdate_new_out;
    ++      }
    ++    }
    ++  }
    ++  *ppValue = pMem;
    ++
    ++ preupdate_new_out:
    ++  sqlite3Error(db, rc);
    ++  return sqlite3ApiExit(db, rc);
    ++}
    ++#endif /* SQLITE_ENABLE_PREUPDATE_HOOK */
    ++
    + #ifdef SQLITE_ENABLE_STMT_SCANSTATUS
    + /*
    + ** Return status data for a single loop within query pStmt.
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_stmt_scanstatus(
    ++SQLITE_API int sqlite3_stmt_scanstatus(
    +   sqlite3_stmt *pStmt,            /* Prepared statement being queried */
    +   int idx,                        /* Index of loop to report on */
    +   int iScanStatusOp,              /* Which metric to return */
    +@@ -72627,7 +79684,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_stmt_scanstatus(
    + /*
    + ** Zero all counters associated with the sqlite3_stmt_scanstatus() data.
    + */
    +-SQLITE_API void SQLITE_STDCALL sqlite3_stmt_scanstatus_reset(sqlite3_stmt *pStmt){
    ++SQLITE_API void sqlite3_stmt_scanstatus_reset(sqlite3_stmt *pStmt){
    +   Vdbe *p = (Vdbe*)pStmt;
    +   memset(p->anExec, 0, p->nOp * sizeof(i64));
    + }
    +@@ -72718,10 +79775,13 @@ SQLITE_PRIVATE char *sqlite3VdbeExpandSql(
    +   int i;                   /* Loop counter */
    +   Mem *pVar;               /* Value of a host parameter */
    +   StrAccum out;            /* Accumulate the output here */
    ++#ifndef SQLITE_OMIT_UTF16
    ++  Mem utf8;                /* Used to convert UTF16 into UTF8 for display */
    ++#endif
    +   char zBase[100];         /* Initial working space */
    + 
    +   db = p->db;
    +-  sqlite3StrAccumInit(&out, db, zBase, sizeof(zBase), 
    ++  sqlite3StrAccumInit(&out, 0, zBase, sizeof(zBase), 
    +                       db->aLimit[SQLITE_LIMIT_LENGTH]);
    +   if( db->nVdbeExec>1 ){
    +     while( *zRawSql ){
    +@@ -72765,19 +79825,21 @@ SQLITE_PRIVATE char *sqlite3VdbeExpandSql(
    +       if( pVar->flags & MEM_Null ){
    +         sqlite3StrAccumAppend(&out, "NULL", 4);
    +       }else if( pVar->flags & MEM_Int ){
    +-        sqlite3XPrintf(&out, 0, "%lld", pVar->u.i);
    ++        sqlite3XPrintf(&out, "%lld", pVar->u.i);
    +       }else if( pVar->flags & MEM_Real ){
    +-        sqlite3XPrintf(&out, 0, "%!.15g", pVar->u.r);
    ++        sqlite3XPrintf(&out, "%!.15g", pVar->u.r);
    +       }else if( pVar->flags & MEM_Str ){
    +         int nOut;  /* Number of bytes of the string text to include in output */
    + #ifndef SQLITE_OMIT_UTF16
    +         u8 enc = ENC(db);
    +-        Mem utf8;
    +         if( enc!=SQLITE_UTF8 ){
    +           memset(&utf8, 0, sizeof(utf8));
    +           utf8.db = db;
    +           sqlite3VdbeMemSetStr(&utf8, pVar->z, pVar->n, enc, SQLITE_STATIC);
    +-          sqlite3VdbeChangeEncoding(&utf8, SQLITE_UTF8);
    ++          if( SQLITE_NOMEM==sqlite3VdbeChangeEncoding(&utf8, SQLITE_UTF8) ){
    ++            out.accError = STRACCUM_NOMEM;
    ++            out.nAlloc = 0;
    ++          }
    +           pVar = &utf8;
    +         }
    + #endif
    +@@ -72788,17 +79850,17 @@ SQLITE_PRIVATE char *sqlite3VdbeExpandSql(
    +           while( nOut<pVar->n && (pVar->z[nOut]&0xc0)==0x80 ){ nOut++; }
    +         }
    + #endif    
    +-        sqlite3XPrintf(&out, 0, "'%.*q'", nOut, pVar->z);
    ++        sqlite3XPrintf(&out, "'%.*q'", nOut, pVar->z);
    + #ifdef SQLITE_TRACE_SIZE_LIMIT
    +         if( nOut<pVar->n ){
    +-          sqlite3XPrintf(&out, 0, "/*+%d bytes*/", pVar->n-nOut);
    ++          sqlite3XPrintf(&out, "/*+%d bytes*/", pVar->n-nOut);
    +         }
    + #endif
    + #ifndef SQLITE_OMIT_UTF16
    +         if( enc!=SQLITE_UTF8 ) sqlite3VdbeMemRelease(&utf8);
    + #endif
    +       }else if( pVar->flags & MEM_Zero ){
    +-        sqlite3XPrintf(&out, 0, "zeroblob(%d)", pVar->u.nZero);
    ++        sqlite3XPrintf(&out, "zeroblob(%d)", pVar->u.nZero);
    +       }else{
    +         int nOut;  /* Number of bytes of the blob to include in output */
    +         assert( pVar->flags & MEM_Blob );
    +@@ -72808,17 +79870,18 @@ SQLITE_PRIVATE char *sqlite3VdbeExpandSql(
    +         if( nOut>SQLITE_TRACE_SIZE_LIMIT ) nOut = SQLITE_TRACE_SIZE_LIMIT;
    + #endif
    +         for(i=0; i<nOut; i++){
    +-          sqlite3XPrintf(&out, 0, "%02x", pVar->z[i]&0xff);
    ++          sqlite3XPrintf(&out, "%02x", pVar->z[i]&0xff);
    +         }
    +         sqlite3StrAccumAppend(&out, "'", 1);
    + #ifdef SQLITE_TRACE_SIZE_LIMIT
    +         if( nOut<pVar->n ){
    +-          sqlite3XPrintf(&out, 0, "/*+%d bytes*/", pVar->n-nOut);
    ++          sqlite3XPrintf(&out, "/*+%d bytes*/", pVar->n-nOut);
    +         }
    + #endif
    +       }
    +     }
    +   }
    ++  if( out.accError ) sqlite3StrAccumReset(&out);
    +   return sqlite3StrAccumFinish(&out);
    + }
    + 
    +@@ -72914,6 +79977,16 @@ static void updateMaxBlobsize(Mem *p){
    + }
    + #endif
    + 
    ++/*
    ++** This macro evaluates to true if either the update hook or the preupdate
    ++** hook are enabled for database connect DB.
    ++*/
    ++#ifdef SQLITE_ENABLE_PREUPDATE_HOOK
    ++# define HAS_UPDATE_HOOK(DB) ((DB)->xPreUpdateCallback||(DB)->xUpdateCallback)
    ++#else
    ++# define HAS_UPDATE_HOOK(DB) ((DB)->xUpdateCallback)
    ++#endif
    ++
    + /*
    + ** The next global variable is incremented each time the OP_Found opcode
    + ** is executed. This is used to test whether or not the foreign key
    +@@ -72929,7 +80002,7 @@ SQLITE_API int sqlite3_found_count = 0;
    + ** Test a register to see if it exceeds the current maximum blob size.
    + ** If it does, record the new maximum blob size.
    + */
    +-#if defined(SQLITE_TEST) && !defined(SQLITE_OMIT_BUILTIN_TEST)
    ++#if defined(SQLITE_TEST) && !defined(SQLITE_UNTESTABLE)
    + # define UPDATE_MAX_BLOBSIZE(P)  updateMaxBlobsize(P)
    + #else
    + # define UPDATE_MAX_BLOBSIZE(P)
    +@@ -72993,7 +80066,7 @@ SQLITE_API int sqlite3_found_count = 0;
    +        && sqlite3VdbeMemMakeWriteable(P) ){ goto no_mem;}
    + 
    + /* Return true if the cursor was opened using the OP_OpenSorter opcode. */
    +-#define isSorter(x) ((x)->pSorter!=0)
    ++#define isSorter(x) ((x)->eCurType==CURTYPE_SORTER)
    + 
    + /*
    + ** Allocate VdbeCursor number iCur.  Return a pointer to it.  Return NULL
    +@@ -73004,7 +80077,7 @@ static VdbeCursor *allocateCursor(
    +   int iCur,             /* Index of the new VdbeCursor */
    +   int nField,           /* Number of fields in the table or index */
    +   int iDb,              /* Database the cursor belongs to, or -1 */
    +-  int isBtreeCursor     /* True for B-Tree.  False for pseudo-table or vtab */
    ++  u8 eCurType           /* Type of the new cursor */
    + ){
    +   /* Find the memory cell that will be used to store the blob of memory
    +   ** required for this VdbeCursor structure. It is convenient to use a 
    +@@ -73020,33 +80093,34 @@ static VdbeCursor *allocateCursor(
    +   **     be freed lazily via the sqlite3_release_memory() API. This
    +   **     minimizes the number of malloc calls made by the system.
    +   **
    +-  ** Memory cells for cursors are allocated at the top of the address
    +-  ** space. Memory cell (p->nMem) corresponds to cursor 0. Space for
    +-  ** cursor 1 is managed by memory cell (p->nMem-1), etc.
    ++  ** The memory cell for cursor 0 is aMem[0]. The rest are allocated from
    ++  ** the top of the register space.  Cursor 1 is at Mem[p->nMem-1].
    ++  ** Cursor 2 is at Mem[p->nMem-2]. And so forth.
    +   */
    +-  Mem *pMem = &p->aMem[p->nMem-iCur];
    ++  Mem *pMem = iCur>0 ? &p->aMem[p->nMem-iCur] : p->aMem;
    + 
    +   int nByte;
    +   VdbeCursor *pCx = 0;
    +   nByte = 
    +       ROUND8(sizeof(VdbeCursor)) + 2*sizeof(u32)*nField + 
    +-      (isBtreeCursor?sqlite3BtreeCursorSize():0);
    ++      (eCurType==CURTYPE_BTREE?sqlite3BtreeCursorSize():0);
    + 
    +-  assert( iCur<p->nCursor );
    +-  if( p->apCsr[iCur] ){
    ++  assert( iCur>=0 && iCur<p->nCursor );
    ++  if( p->apCsr[iCur] ){ /*OPTIMIZATION-IF-FALSE*/
    +     sqlite3VdbeFreeCursor(p, p->apCsr[iCur]);
    +     p->apCsr[iCur] = 0;
    +   }
    +   if( SQLITE_OK==sqlite3VdbeMemClearAndResize(pMem, nByte) ){
    +     p->apCsr[iCur] = pCx = (VdbeCursor*)pMem->z;
    +-    memset(pCx, 0, sizeof(VdbeCursor));
    ++    memset(pCx, 0, offsetof(VdbeCursor,pAltCursor));
    ++    pCx->eCurType = eCurType;
    +     pCx->iDb = iDb;
    +     pCx->nField = nField;
    +     pCx->aOffset = &pCx->aType[nField];
    +-    if( isBtreeCursor ){
    +-      pCx->pCursor = (BtCursor*)
    ++    if( eCurType==CURTYPE_BTREE ){
    ++      pCx->uc.pCursor = (BtCursor*)
    +           &pMem->z[ROUND8(sizeof(VdbeCursor))+2*sizeof(u32)*nField];
    +-      sqlite3BtreeCursorZero(pCx->pCursor);
    ++      sqlite3BtreeCursorZero(pCx->uc.pCursor);
    +     }
    +   }
    +   return pCx;
    +@@ -73109,7 +80183,7 @@ static void applyAffinity(
    +   if( affinity>=SQLITE_AFF_NUMERIC ){
    +     assert( affinity==SQLITE_AFF_INTEGER || affinity==SQLITE_AFF_REAL
    +              || affinity==SQLITE_AFF_NUMERIC );
    +-    if( (pRec->flags & MEM_Int)==0 ){
    ++    if( (pRec->flags & MEM_Int)==0 ){ /*OPTIMIZATION-IF-FALSE*/
    +       if( (pRec->flags & MEM_Real)==0 ){
    +         if( pRec->flags & MEM_Str ) applyNumericAffinity(pRec,1);
    +       }else{
    +@@ -73119,10 +80193,13 @@ static void applyAffinity(
    +   }else if( affinity==SQLITE_AFF_TEXT ){
    +     /* Only attempt the conversion to TEXT if there is an integer or real
    +     ** representation (blob and NULL do not get converted) but no string
    +-    ** representation.
    +-    */
    +-    if( 0==(pRec->flags&MEM_Str) && (pRec->flags&(MEM_Real|MEM_Int)) ){
    +-      sqlite3VdbeMemStringify(pRec, enc, 1);
    ++    ** representation.  It would be harmless to repeat the conversion if 
    ++    ** there is already a string rep, but it is pointless to waste those
    ++    ** CPU cycles. */
    ++    if( 0==(pRec->flags&MEM_Str) ){ /*OPTIMIZATION-IF-FALSE*/
    ++      if( (pRec->flags&(MEM_Real|MEM_Int)) ){
    ++        sqlite3VdbeMemStringify(pRec, enc, 1);
    ++      }
    +     }
    +     pRec->flags &= ~(MEM_Real|MEM_Int);
    +   }
    +@@ -73134,7 +80211,7 @@ static void applyAffinity(
    + ** is appropriate.  But only do the conversion if it is possible without
    + ** loss of information and return the revised type of the argument.
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_value_numeric_type(sqlite3_value *pVal){
    ++SQLITE_API int sqlite3_value_numeric_type(sqlite3_value *pVal){
    +   int eType = sqlite3_value_type(pVal);
    +   if( eType==SQLITE_TEXT ){
    +     Mem *pMem = (Mem*)pVal;
    +@@ -73168,7 +80245,7 @@ static u16 SQLITE_NOINLINE computeNumericType(Mem *pMem){
    +   if( sqlite3AtoF(pMem->z, &pMem->u.r, pMem->n, pMem->enc)==0 ){
    +     return 0;
    +   }
    +-  if( sqlite3Atoi64(pMem->z, &pMem->u.i, pMem->n, pMem->enc)==SQLITE_OK ){
    ++  if( sqlite3Atoi64(pMem->z, &pMem->u.i, pMem->n, pMem->enc)==0 ){
    +     return MEM_Int;
    +   }
    +   return MEM_Real;
    +@@ -73217,9 +80294,7 @@ SQLITE_PRIVATE void sqlite3VdbeMemPrettyPrint(Mem *pMem, char *zBuf){
    +     }else{
    +       c = 's';
    +     }
    +-
    +-    sqlite3_snprintf(100, zCsr, "%c", c);
    +-    zCsr += sqlite3Strlen30(zCsr);
    ++    *(zCsr++) = c;
    +     sqlite3_snprintf(100, zCsr, "%d[", pMem->n);
    +     zCsr += sqlite3Strlen30(zCsr);
    +     for(i=0; i<16 && i<pMem->n; i++){
    +@@ -73231,9 +80306,7 @@ SQLITE_PRIVATE void sqlite3VdbeMemPrettyPrint(Mem *pMem, char *zBuf){
    +       if( z<32 || z>126 ) *zCsr++ = '.';
    +       else *zCsr++ = z;
    +     }
    +-
    +-    sqlite3_snprintf(100, zCsr, "]%s", encnames[pMem->enc]);
    +-    zCsr += sqlite3Strlen30(zCsr);
    ++    *(zCsr++) = ']';
    +     if( f & MEM_Zero ){
    +       sqlite3_snprintf(100, zCsr,"+%dz",pMem->u.nZero);
    +       zCsr += sqlite3Strlen30(zCsr);
    +@@ -73282,7 +80355,7 @@ static void memTracePrint(Mem *p){
    +   if( p->flags & MEM_Undefined ){
    +     printf(" undefined");
    +   }else if( p->flags & MEM_Null ){
    +-    printf(" NULL");
    ++    printf(p->flags & MEM_Zero ? " NULL-nochng" : " NULL");
    +   }else if( (p->flags & (MEM_Int|MEM_Str))==(MEM_Int|MEM_Str) ){
    +     printf(" si:%lld", p->u.i);
    +   }else if( p->flags & MEM_Int ){
    +@@ -73298,11 +80371,13 @@ static void memTracePrint(Mem *p){
    +     sqlite3VdbeMemPrettyPrint(p, zBuf);
    +     printf(" %s", zBuf);
    +   }
    ++  if( p->flags & MEM_Subtype ) printf(" subtype=0x%02x", p->eSubtype);
    + }
    + static void registerTrace(int iReg, Mem *p){
    +   printf("REG[%d] = ", iReg);
    +   memTracePrint(p);
    +   printf("\n");
    ++  sqlite3VdbeCheckMemInvariants(p);
    + }
    + #endif
    + 
    +@@ -73336,8 +80411,8 @@ static void registerTrace(int iReg, Mem *p){
    + ** This file contains inline asm code for retrieving "high-performance"
    + ** counters for x86 class CPUs.
    + */
    +-#ifndef _HWTIME_H_
    +-#define _HWTIME_H_
    ++#ifndef SQLITE_HWTIME_H
    ++#define SQLITE_HWTIME_H
    + 
    + /*
    + ** The following routine only works on pentium-class (or newer) processors.
    +@@ -73405,7 +80480,7 @@ SQLITE_PRIVATE   sqlite_uint64 sqlite3Hwtime(void){ return ((sqlite_uint64)0); }
    + 
    + #endif
    + 
    +-#endif /* !defined(_HWTIME_H_) */
    ++#endif /* !defined(SQLITE_HWTIME_H) */
    + 
    + /************** End of hwtime.h **********************************************/
    + /************** Continuing where we left off in vdbe.c ***********************/
    +@@ -73435,16 +80510,24 @@ static int checkSavepointCount(sqlite3 *db){
    + /*
    + ** Return the register of pOp->p2 after first preparing it to be
    + ** overwritten with an integer value.
    +-*/ 
    ++*/
    ++static SQLITE_NOINLINE Mem *out2PrereleaseWithClear(Mem *pOut){
    ++  sqlite3VdbeMemSetNull(pOut);
    ++  pOut->flags = MEM_Int;
    ++  return pOut;
    ++}
    + static Mem *out2Prerelease(Vdbe *p, VdbeOp *pOp){
    +   Mem *pOut;
    +   assert( pOp->p2>0 );
    +-  assert( pOp->p2<=(p->nMem-p->nCursor) );
    ++  assert( pOp->p2<=(p->nMem+1 - p->nCursor) );
    +   pOut = &p->aMem[pOp->p2];
    +   memAboutToChange(p, pOut);
    +-  if( VdbeMemDynamic(pOut) ) sqlite3VdbeMemSetNull(pOut);
    +-  pOut->flags = MEM_Int;
    +-  return pOut;
    ++  if( VdbeMemDynamic(pOut) ){ /*OPTIMIZATION-IF-FALSE*/
    ++    return out2PrereleaseWithClear(pOut);
    ++  }else{
    ++    pOut->flags = MEM_Int;
    ++    return pOut;
    ++  }
    + }
    + 
    + 
    +@@ -73459,23 +80542,24 @@ SQLITE_PRIVATE int sqlite3VdbeExec(
    +   Op *pOp = aOp;             /* Current operation */
    + #if defined(SQLITE_DEBUG) || defined(VDBE_PROFILE)
    +   Op *pOrigOp;               /* Value of pOp at the top of the loop */
    ++#endif
    ++#ifdef SQLITE_DEBUG
    ++  int nExtraDelete = 0;      /* Verifies FORDELETE and AUXDELETE flags */
    + #endif
    +   int rc = SQLITE_OK;        /* Value to return */
    +   sqlite3 *db = p->db;       /* The database */
    +   u8 resetSchemaOnFault = 0; /* Reset schema after an error if positive */
    +   u8 encoding = ENC(db);     /* The database encoding */
    +-  int iCompare = 0;          /* Result of last OP_Compare operation */
    ++  int iCompare = 0;          /* Result of last comparison */
    +   unsigned nVmStep = 0;      /* Number of virtual machine steps */
    + #ifndef SQLITE_OMIT_PROGRESS_CALLBACK
    +-  unsigned nProgressLimit = 0;/* Invoke xProgress() when nVmStep reaches this */
    ++  unsigned nProgressLimit;   /* Invoke xProgress() when nVmStep reaches this */
    + #endif
    +   Mem *aMem = p->aMem;       /* Copy of p->aMem */
    +   Mem *pIn1 = 0;             /* 1st input operand */
    +   Mem *pIn2 = 0;             /* 2nd input operand */
    +   Mem *pIn3 = 0;             /* 3rd input operand */
    +   Mem *pOut = 0;             /* Output operand */
    +-  int *aPermute = 0;         /* Permutation of columns for OP_Compare */
    +-  i64 lastRowid = db->lastRowid;  /* Saved value of the last insert ROWID */
    + #ifdef VDBE_PROFILE
    +   u64 start;                 /* CPU clock count at start of opcode */
    + #endif
    +@@ -73490,7 +80574,6 @@ SQLITE_PRIVATE int sqlite3VdbeExec(
    +   }
    +   assert( p->rc==SQLITE_OK || (p->rc&0xff)==SQLITE_BUSY );
    +   assert( p->bIsReader || p->readOnly!=0 );
    +-  p->rc = SQLITE_OK;
    +   p->iCurrentTime = 0;
    +   assert( p->explain==0 );
    +   p->pResultSet = 0;
    +@@ -73502,6 +80585,8 @@ SQLITE_PRIVATE int sqlite3VdbeExec(
    +     u32 iPrior = p->aCounter[SQLITE_STMTSTATUS_VM_STEP];
    +     assert( 0 < db->nProgressOps );
    +     nProgressLimit = db->nProgressOps - (iPrior % db->nProgressOps);
    ++  }else{
    ++    nProgressLimit = 0xffffffff;
    +   }
    + #endif
    + #ifdef SQLITE_DEBUG
    +@@ -73531,9 +80616,12 @@ SQLITE_PRIVATE int sqlite3VdbeExec(
    +   }
    +   sqlite3EndBenignMalloc();
    + #endif
    +-  for(pOp=&aOp[p->pc]; rc==SQLITE_OK; pOp++){
    ++  for(pOp=&aOp[p->pc]; 1; pOp++){
    ++    /* Errors are detected by individual opcodes, with an immediate
    ++    ** jumps to abort_due_to_error. */
    ++    assert( rc==SQLITE_OK );
    ++
    +     assert( pOp>=aOp && pOp<&aOp[p->nOp]);
    +-    if( db->mallocFailed ) goto no_mem;
    + #ifdef VDBE_PROFILE
    +     start = sqlite3Hwtime();
    + #endif
    +@@ -73565,37 +80653,39 @@ SQLITE_PRIVATE int sqlite3VdbeExec(
    + 
    +     /* Sanity checking on other operands */
    + #ifdef SQLITE_DEBUG
    +-    assert( pOp->opflags==sqlite3OpcodeProperty[pOp->opcode] );
    +-    if( (pOp->opflags & OPFLG_IN1)!=0 ){
    +-      assert( pOp->p1>0 );
    +-      assert( pOp->p1<=(p->nMem-p->nCursor) );
    +-      assert( memIsValid(&aMem[pOp->p1]) );
    +-      assert( sqlite3VdbeCheckMemInvariants(&aMem[pOp->p1]) );
    +-      REGISTER_TRACE(pOp->p1, &aMem[pOp->p1]);
    +-    }
    +-    if( (pOp->opflags & OPFLG_IN2)!=0 ){
    +-      assert( pOp->p2>0 );
    +-      assert( pOp->p2<=(p->nMem-p->nCursor) );
    +-      assert( memIsValid(&aMem[pOp->p2]) );
    +-      assert( sqlite3VdbeCheckMemInvariants(&aMem[pOp->p2]) );
    +-      REGISTER_TRACE(pOp->p2, &aMem[pOp->p2]);
    +-    }
    +-    if( (pOp->opflags & OPFLG_IN3)!=0 ){
    +-      assert( pOp->p3>0 );
    +-      assert( pOp->p3<=(p->nMem-p->nCursor) );
    +-      assert( memIsValid(&aMem[pOp->p3]) );
    +-      assert( sqlite3VdbeCheckMemInvariants(&aMem[pOp->p3]) );
    +-      REGISTER_TRACE(pOp->p3, &aMem[pOp->p3]);
    +-    }
    +-    if( (pOp->opflags & OPFLG_OUT2)!=0 ){
    +-      assert( pOp->p2>0 );
    +-      assert( pOp->p2<=(p->nMem-p->nCursor) );
    +-      memAboutToChange(p, &aMem[pOp->p2]);
    +-    }
    +-    if( (pOp->opflags & OPFLG_OUT3)!=0 ){
    +-      assert( pOp->p3>0 );
    +-      assert( pOp->p3<=(p->nMem-p->nCursor) );
    +-      memAboutToChange(p, &aMem[pOp->p3]);
    ++    {
    ++      u8 opProperty = sqlite3OpcodeProperty[pOp->opcode];
    ++      if( (opProperty & OPFLG_IN1)!=0 ){
    ++        assert( pOp->p1>0 );
    ++        assert( pOp->p1<=(p->nMem+1 - p->nCursor) );
    ++        assert( memIsValid(&aMem[pOp->p1]) );
    ++        assert( sqlite3VdbeCheckMemInvariants(&aMem[pOp->p1]) );
    ++        REGISTER_TRACE(pOp->p1, &aMem[pOp->p1]);
    ++      }
    ++      if( (opProperty & OPFLG_IN2)!=0 ){
    ++        assert( pOp->p2>0 );
    ++        assert( pOp->p2<=(p->nMem+1 - p->nCursor) );
    ++        assert( memIsValid(&aMem[pOp->p2]) );
    ++        assert( sqlite3VdbeCheckMemInvariants(&aMem[pOp->p2]) );
    ++        REGISTER_TRACE(pOp->p2, &aMem[pOp->p2]);
    ++      }
    ++      if( (opProperty & OPFLG_IN3)!=0 ){
    ++        assert( pOp->p3>0 );
    ++        assert( pOp->p3<=(p->nMem+1 - p->nCursor) );
    ++        assert( memIsValid(&aMem[pOp->p3]) );
    ++        assert( sqlite3VdbeCheckMemInvariants(&aMem[pOp->p3]) );
    ++        REGISTER_TRACE(pOp->p3, &aMem[pOp->p3]);
    ++      }
    ++      if( (opProperty & OPFLG_OUT2)!=0 ){
    ++        assert( pOp->p2>0 );
    ++        assert( pOp->p2<=(p->nMem+1 - p->nCursor) );
    ++        memAboutToChange(p, &aMem[pOp->p2]);
    ++      }
    ++      if( (opProperty & OPFLG_OUT3)!=0 ){
    ++        assert( pOp->p3>0 );
    ++        assert( pOp->p3<=(p->nMem+1 - p->nCursor) );
    ++        memAboutToChange(p, &aMem[pOp->p3]);
    ++      }
    +     }
    + #endif
    + #if defined(SQLITE_DEBUG) || defined(VDBE_PROFILE)
    +@@ -73656,7 +80746,7 @@ jump_to_p2_and_check_for_interrupt:
    +   pOp = &aOp[pOp->p2 - 1];
    + 
    +   /* Opcodes that are used as the bottom of a loop (OP_Next, OP_Prev,
    +-  ** OP_VNext, OP_RowSetNext, or OP_SorterNext) all jump here upon
    ++  ** OP_VNext, or OP_SorterNext) all jump here upon
    +   ** completion.  Check to see if sqlite3_interrupt() has been called
    +   ** or if the progress callback needs to be invoked. 
    +   **
    +@@ -73674,12 +80764,12 @@ check_for_interrupt:
    +   ** If the progress callback returns non-zero, exit the virtual machine with
    +   ** a return code SQLITE_ABORT.
    +   */
    +-  if( db->xProgress!=0 && nVmStep>=nProgressLimit ){
    ++  if( nVmStep>=nProgressLimit && db->xProgress!=0 ){
    +     assert( db->nProgressOps!=0 );
    +     nProgressLimit = nVmStep + db->nProgressOps - (nVmStep%db->nProgressOps);
    +     if( db->xProgress(db->pProgressArg) ){
    +       rc = SQLITE_INTERRUPT;
    +-      goto vdbe_error_halt;
    ++      goto abort_due_to_error;
    +     }
    +   }
    + #endif
    +@@ -73693,7 +80783,7 @@ check_for_interrupt:
    + ** and then jump to address P2.
    + */
    + case OP_Gosub: {            /* jump */
    +-  assert( pOp->p1>0 && pOp->p1<=(p->nMem-p->nCursor) );
    ++  assert( pOp->p1>0 && pOp->p1<=(p->nMem+1 - p->nCursor) );
    +   pIn1 = &aMem[pOp->p1];
    +   assert( VdbeMemDynamic(pIn1)==0 );
    +   memAboutToChange(p, pIn1);
    +@@ -73733,7 +80823,7 @@ case OP_Return: {           /* in1 */
    + ** See also: EndCoroutine
    + */
    + case OP_InitCoroutine: {     /* jump */
    +-  assert( pOp->p1>0 &&  pOp->p1<=(p->nMem-p->nCursor) );
    ++  assert( pOp->p1>0 &&  pOp->p1<=(p->nMem+1 - p->nCursor) );
    +   assert( pOp->p2>=0 && pOp->p2<p->nOp );
    +   assert( pOp->p3>=0 && pOp->p3<p->nOp );
    +   pOut = &aMem[pOp->p1];
    +@@ -73791,7 +80881,7 @@ case OP_Yield: {            /* in1, jump */
    + }
    + 
    + /* Opcode:  HaltIfNull  P1 P2 P3 P4 P5
    +-** Synopsis:  if r[P3]=null halt
    ++** Synopsis: if r[P3]=null halt
    + **
    + ** Check the value in register P3.  If it is NULL then Halt using
    + ** parameter P1, P2, and P4 as if this were a Halt instruction.  If the
    +@@ -73835,8 +80925,6 @@ case OP_HaltIfNull: {      /* in3 */
    + ** is the same as executing Halt.
    + */
    + case OP_Halt: {
    +-  const char *zType;
    +-  const char *zLogFmt;
    +   VdbeFrame *pFrame;
    +   int pcx;
    + 
    +@@ -73848,7 +80936,6 @@ case OP_Halt: {
    +     p->nFrame--;
    +     sqlite3VdbeSetChanges(db, p->nChange);
    +     pcx = sqlite3VdbeFrameRestore(pFrame);
    +-    lastRowid = db->lastRowid;
    +     if( pOp->p2==OE_Ignore ){
    +       /* Instruction pcx is the OP_Program that invoked the sub-program 
    +       ** currently being halted. If the p2 instruction of this OP_Halt
    +@@ -73865,34 +80952,28 @@ case OP_Halt: {
    +   p->rc = pOp->p1;
    +   p->errorAction = (u8)pOp->p2;
    +   p->pc = pcx;
    ++  assert( pOp->p5<=4 );
    +   if( p->rc ){
    +     if( pOp->p5 ){
    +       static const char * const azType[] = { "NOT NULL", "UNIQUE", "CHECK",
    +                                              "FOREIGN KEY" };
    +-      assert( pOp->p5>=1 && pOp->p5<=4 );
    +       testcase( pOp->p5==1 );
    +       testcase( pOp->p5==2 );
    +       testcase( pOp->p5==3 );
    +       testcase( pOp->p5==4 );
    +-      zType = azType[pOp->p5-1];
    ++      sqlite3VdbeError(p, "%s constraint failed", azType[pOp->p5-1]);
    ++      if( pOp->p4.z ){
    ++        p->zErrMsg = sqlite3MPrintf(db, "%z: %s", p->zErrMsg, pOp->p4.z);
    ++      }
    +     }else{
    +-      zType = 0;
    +-    }
    +-    assert( zType!=0 || pOp->p4.z!=0 );
    +-    zLogFmt = "abort at %d in [%s]: %s";
    +-    if( zType && pOp->p4.z ){
    +-      sqlite3VdbeError(p, "%s constraint failed: %s", zType, pOp->p4.z);
    +-    }else if( pOp->p4.z ){
    +       sqlite3VdbeError(p, "%s", pOp->p4.z);
    +-    }else{
    +-      sqlite3VdbeError(p, "%s constraint failed", zType);
    +     }
    +-    sqlite3_log(pOp->p1, zLogFmt, pcx, p->zSql, p->zErrMsg);
    ++    sqlite3_log(pOp->p1, "abort at %d in [%s]: %s", pcx, p->zSql, p->zErrMsg);
    +   }
    +   rc = sqlite3VdbeHalt(p);
    +   assert( rc==SQLITE_BUSY || rc==SQLITE_OK || rc==SQLITE_ERROR );
    +   if( rc==SQLITE_BUSY ){
    +-    p->rc = rc = SQLITE_BUSY;
    ++    p->rc = SQLITE_BUSY;
    +   }else{
    +     assert( rc==SQLITE_OK || (p->rc&0xff)==SQLITE_CONSTRAINT );
    +     assert( rc==SQLITE_OK || db->nDeferredCons>0 || db->nDeferredImmCons>0 );
    +@@ -73958,7 +81039,7 @@ case OP_String8: {         /* same as TK_STRING, out2 */
    + #ifndef SQLITE_OMIT_UTF16
    +   if( encoding!=SQLITE_UTF8 ){
    +     rc = sqlite3VdbeMemSetStr(pOut, pOp->p4.z, -1, SQLITE_UTF8, SQLITE_STATIC);
    +-    if( rc==SQLITE_TOOBIG ) goto too_big;
    ++    assert( rc==SQLITE_OK || rc==SQLITE_TOOBIG );
    +     if( SQLITE_OK!=sqlite3VdbeChangeEncoding(pOut, encoding) ) goto no_mem;
    +     assert( pOut->szMalloc>0 && pOut->zMalloc==pOut->z );
    +     assert( VdbeMemDynamic(pOut)==0 );
    +@@ -73971,10 +81052,12 @@ case OP_String8: {         /* same as TK_STRING, out2 */
    +     pOp->p4.z = pOut->z;
    +     pOp->p1 = pOut->n;
    +   }
    ++  testcase( rc==SQLITE_TOOBIG );
    + #endif
    +   if( pOp->p1>db->aLimit[SQLITE_LIMIT_LENGTH] ){
    +     goto too_big;
    +   }
    ++  assert( rc==SQLITE_OK );
    +   /* Fall through to the next case, OP_String */
    + }
    +   
    +@@ -73983,10 +81066,12 @@ case OP_String8: {         /* same as TK_STRING, out2 */
    + **
    + ** The string value P4 of length P1 (bytes) is stored in register P2.
    + **
    +-** If P5!=0 and the content of register P3 is greater than zero, then
    ++** If P3 is not zero and the content of register P3 is equal to P5, then
    + ** the datatype of the register P2 is converted to BLOB.  The content is
    + ** the same sequence of bytes, it is merely interpreted as a BLOB instead
    +-** of a string, as if it had been CAST.
    ++** of a string, as if it had been CAST.  In other words:
    ++**
    ++** if( P3!=0 and reg[P3]==P5 ) reg[P2] := CAST(reg[P2] as BLOB)
    + */
    + case OP_String: {          /* out2 */
    +   assert( pOp->p4.z!=0 );
    +@@ -73996,18 +81081,19 @@ case OP_String: {          /* out2 */
    +   pOut->n = pOp->p1;
    +   pOut->enc = encoding;
    +   UPDATE_MAX_BLOBSIZE(pOut);
    +-  if( pOp->p5 ){
    +-    assert( pOp->p3>0 );
    +-    assert( pOp->p3<=(p->nMem-p->nCursor) );
    ++#ifndef SQLITE_LIKE_DOESNT_MATCH_BLOBS
    ++  if( pOp->p3>0 ){
    ++    assert( pOp->p3<=(p->nMem+1 - p->nCursor) );
    +     pIn3 = &aMem[pOp->p3];
    +     assert( pIn3->flags & MEM_Int );
    +-    if( pIn3->u.i ) pOut->flags = MEM_Blob|MEM_Static|MEM_Term;
    ++    if( pIn3->u.i==pOp->p5 ) pOut->flags = MEM_Blob|MEM_Static|MEM_Term;
    +   }
    ++#endif
    +   break;
    + }
    + 
    + /* Opcode: Null P1 P2 P3 * *
    +-** Synopsis:  r[P2..P3]=NULL
    ++** Synopsis: r[P2..P3]=NULL
    + **
    + ** Write a NULL into registers P2.  If P3 greater than P2, then also write
    + ** NULL into register P3 and every register in between P2 and P3.  If P3
    +@@ -74023,20 +81109,22 @@ case OP_Null: {           /* out2 */
    +   u16 nullFlag;
    +   pOut = out2Prerelease(p, pOp);
    +   cnt = pOp->p3-pOp->p2;
    +-  assert( pOp->p3<=(p->nMem-p->nCursor) );
    ++  assert( pOp->p3<=(p->nMem+1 - p->nCursor) );
    +   pOut->flags = nullFlag = pOp->p1 ? (MEM_Null|MEM_Cleared) : MEM_Null;
    ++  pOut->n = 0;
    +   while( cnt>0 ){
    +     pOut++;
    +     memAboutToChange(p, pOut);
    +     sqlite3VdbeMemSetNull(pOut);
    +     pOut->flags = nullFlag;
    ++    pOut->n = 0;
    +     cnt--;
    +   }
    +   break;
    + }
    + 
    + /* Opcode: SoftNull P1 * * * *
    +-** Synopsis:  r[P1]=NULL
    ++** Synopsis: r[P1]=NULL
    + **
    + ** Set register P1 to have the value NULL as seen by the OP_MakeRecord
    + ** instruction, but do not free any string or blob memory associated with
    +@@ -74044,9 +81132,9 @@ case OP_Null: {           /* out2 */
    + ** previously copied using OP_SCopy, the copies will continue to be valid.
    + */
    + case OP_SoftNull: {
    +-  assert( pOp->p1>0 && pOp->p1<=(p->nMem-p->nCursor) );
    ++  assert( pOp->p1>0 && pOp->p1<=(p->nMem+1 - p->nCursor) );
    +   pOut = &aMem[pOp->p1];
    +-  pOut->flags = (pOut->flags|MEM_Null)&~MEM_Undefined;
    ++  pOut->flags = (pOut->flags&~(MEM_Undefined|MEM_AffMask))|MEM_Null;
    +   break;
    + }
    + 
    +@@ -74077,19 +81165,19 @@ case OP_Variable: {            /* out2 */
    +   Mem *pVar;       /* Value being transferred */
    + 
    +   assert( pOp->p1>0 && pOp->p1<=p->nVar );
    +-  assert( pOp->p4.z==0 || pOp->p4.z==p->azVar[pOp->p1-1] );
    ++  assert( pOp->p4.z==0 || pOp->p4.z==sqlite3VListNumToName(p->pVList,pOp->p1) );
    +   pVar = &p->aVar[pOp->p1 - 1];
    +   if( sqlite3VdbeMemTooBig(pVar) ){
    +     goto too_big;
    +   }
    +-  pOut = out2Prerelease(p, pOp);
    ++  pOut = &aMem[pOp->p2];
    +   sqlite3VdbeMemShallowCopy(pOut, pVar, MEM_Static);
    +   UPDATE_MAX_BLOBSIZE(pOut);
    +   break;
    + }
    + 
    + /* Opcode: Move P1 P2 P3 * *
    +-** Synopsis:  r[P2@P3]=r[P1@P3]
    ++** Synopsis: r[P2@P3]=r[P1@P3]
    + **
    + ** Move the P3 values in register P1..P1+P3-1 over into
    + ** registers P2..P2+P3-1.  Registers P1..P1+P3-1 are
    +@@ -74111,8 +81199,8 @@ case OP_Move: {
    +   pIn1 = &aMem[p1];
    +   pOut = &aMem[p2];
    +   do{
    +-    assert( pOut<=&aMem[(p->nMem-p->nCursor)] );
    +-    assert( pIn1<=&aMem[(p->nMem-p->nCursor)] );
    ++    assert( pOut<=&aMem[(p->nMem+1 - p->nCursor)] );
    ++    assert( pIn1<=&aMem[(p->nMem+1 - p->nCursor)] );
    +     assert( memIsValid(pIn1) );
    +     memAboutToChange(p, pOut);
    +     sqlite3VdbeMemMove(pOut, pIn1);
    +@@ -74182,8 +81270,24 @@ case OP_SCopy: {            /* out2 */
    +   break;
    + }
    + 
    ++/* Opcode: IntCopy P1 P2 * * *
    ++** Synopsis: r[P2]=r[P1]
    ++**
    ++** Transfer the integer value held in register P1 into register P2.
    ++**
    ++** This is an optimized version of SCopy that works only for integer
    ++** values.
    ++*/
    ++case OP_IntCopy: {            /* out2 */
    ++  pIn1 = &aMem[pOp->p1];
    ++  assert( (pIn1->flags & MEM_Int)!=0 );
    ++  pOut = &aMem[pOp->p2];
    ++  sqlite3VdbeMemSetInt64(pOut, pIn1->u.i);
    ++  break;
    ++}
    ++
    + /* Opcode: ResultRow P1 P2 * * *
    +-** Synopsis:  output=r[P1@P2]
    ++** Synopsis: output=r[P1@P2]
    + **
    + ** The registers P1 through P1+P2-1 contain a single row of
    + ** results. This opcode causes the sqlite3_step() call to terminate
    +@@ -74196,17 +81300,17 @@ case OP_ResultRow: {
    +   int i;
    +   assert( p->nResColumn==pOp->p2 );
    +   assert( pOp->p1>0 );
    +-  assert( pOp->p1+pOp->p2<=(p->nMem-p->nCursor)+1 );
    ++  assert( pOp->p1+pOp->p2<=(p->nMem+1 - p->nCursor)+1 );
    + 
    + #ifndef SQLITE_OMIT_PROGRESS_CALLBACK
    +   /* Run the progress counter just before returning.
    +   */
    +   if( db->xProgress!=0
    +-   && nVmStep>=nProgressLimit
    ++   && nVmStep>=nProgressLimit 
    +    && db->xProgress(db->pProgressArg)!=0
    +   ){
    +     rc = SQLITE_INTERRUPT;
    +-    goto vdbe_error_halt;
    ++    goto abort_due_to_error;
    +   }
    + #endif
    + 
    +@@ -74216,7 +81320,7 @@ case OP_ResultRow: {
    +   if( SQLITE_OK!=(rc = sqlite3VdbeCheckFk(p, 0)) ){
    +     assert( db->flags&SQLITE_CountRows );
    +     assert( p->usesStmtJournal );
    +-    break;
    ++    goto abort_due_to_error;
    +   }
    + 
    +   /* If the SQLITE_CountRows flag is set in sqlite3.flags mask, then 
    +@@ -74236,9 +81340,7 @@ case OP_ResultRow: {
    +   */
    +   assert( p->iStatement==0 || db->flags&SQLITE_CountRows );
    +   rc = sqlite3VdbeCloseStatement(p, SAVEPOINT_RELEASE);
    +-  if( NEVER(rc!=SQLITE_OK) ){
    +-    break;
    +-  }
    ++  assert( rc==SQLITE_OK );
    + 
    +   /* Invalidate all ephemeral cursor row caches */
    +   p->cacheCtr = (p->cacheCtr + 2)|1;
    +@@ -74258,6 +81360,10 @@ case OP_ResultRow: {
    +   }
    +   if( db->mallocFailed ) goto no_mem;
    + 
    ++  if( db->mTrace & SQLITE_TRACE_ROW ){
    ++    db->xTrace(SQLITE_TRACE_ROW, db->pTraceArg, p, 0);
    ++  }
    ++
    +   /* Return SQLITE_ROW
    +   */
    +   p->pc = (int)(pOp - aOp) + 1;
    +@@ -74314,14 +81420,14 @@ case OP_Concat: {           /* same as TK_CONCAT, in1, in2, out3 */
    + }
    + 
    + /* Opcode: Add P1 P2 P3 * *
    +-** Synopsis:  r[P3]=r[P1]+r[P2]
    ++** Synopsis: r[P3]=r[P1]+r[P2]
    + **
    + ** Add the value in register P1 to the value in register P2
    + ** and store the result in register P3.
    + ** If either input is NULL, the result is NULL.
    + */
    + /* Opcode: Multiply P1 P2 P3 * *
    +-** Synopsis:  r[P3]=r[P1]*r[P2]
    ++** Synopsis: r[P3]=r[P1]*r[P2]
    + **
    + **
    + ** Multiply the value in register P1 by the value in register P2
    +@@ -74329,14 +81435,14 @@ case OP_Concat: {           /* same as TK_CONCAT, in1, in2, out3 */
    + ** If either input is NULL, the result is NULL.
    + */
    + /* Opcode: Subtract P1 P2 P3 * *
    +-** Synopsis:  r[P3]=r[P2]-r[P1]
    ++** Synopsis: r[P3]=r[P2]-r[P1]
    + **
    + ** Subtract the value in register P1 from the value in register P2
    + ** and store the result in register P3.
    + ** If either input is NULL, the result is NULL.
    + */
    + /* Opcode: Divide P1 P2 P3 * *
    +-** Synopsis:  r[P3]=r[P2]/r[P1]
    ++** Synopsis: r[P3]=r[P2]/r[P1]
    + **
    + ** Divide the value in register P1 by the value in register P2
    + ** and store the result in register P3 (P3=P2/P1). If the value in 
    +@@ -74344,7 +81450,7 @@ case OP_Concat: {           /* same as TK_CONCAT, in1, in2, out3 */
    + ** NULL, the result is NULL.
    + */
    + /* Opcode: Remainder P1 P2 P3 * *
    +-** Synopsis:  r[P3]=r[P2]%r[P1]
    ++** Synopsis: r[P3]=r[P2]%r[P1]
    + **
    + ** Compute the remainder after integer register P2 is divided by 
    + ** register P1 and store the result in register P3. 
    +@@ -74371,7 +81477,6 @@ case OP_Remainder: {           /* same as TK_REM, in1, in2, out3 */
    +   type2 = numericType(pIn2);
    +   pOut = &aMem[pOp->p3];
    +   flags = pIn1->flags | pIn2->flags;
    +-  if( (flags & MEM_Null)!=0 ) goto arithmetic_result_is_null;
    +   if( (type1 & type2 & MEM_Int)!=0 ){
    +     iA = pIn1->u.i;
    +     iB = pIn2->u.i;
    +@@ -74395,6 +81500,8 @@ case OP_Remainder: {           /* same as TK_REM, in1, in2, out3 */
    +     }
    +     pOut->u.i = iB;
    +     MemSetTypeFlag(pOut, MEM_Int);
    ++  }else if( (flags & MEM_Null)!=0 ){
    ++    goto arithmetic_result_is_null;
    +   }else{
    +     bIntint = 0;
    + fp_math:
    +@@ -74442,7 +81549,7 @@ arithmetic_result_is_null:
    + 
    + /* Opcode: CollSeq P1 * * P4
    + **
    +-** P4 is a pointer to a CollSeq struct. If the next call to a user function
    ++** P4 is a pointer to a CollSeq object. If the next call to a user function
    + ** or aggregate calls sqlite3GetFuncCollSeq(), this collation sequence will
    + ** be returned. This is used by the built-in min(), max() and nullif()
    + ** functions.
    +@@ -74463,134 +81570,22 @@ case OP_CollSeq: {
    +   break;
    + }
    + 
    +-/* Opcode: Function0 P1 P2 P3 P4 P5
    +-** Synopsis: r[P3]=func(r[P2@P5])
    +-**
    +-** Invoke a user function (P4 is a pointer to a FuncDef object that
    +-** defines the function) with P5 arguments taken from register P2 and
    +-** successors.  The result of the function is stored in register P3.
    +-** Register P3 must not be one of the function inputs.
    +-**
    +-** P1 is a 32-bit bitmask indicating whether or not each argument to the 
    +-** function was determined to be constant at compile time. If the first
    +-** argument was constant then bit 0 of P1 is set. This is used to determine
    +-** whether meta data associated with a user function argument using the
    +-** sqlite3_set_auxdata() API may be safely retained until the next
    +-** invocation of this opcode.
    +-**
    +-** See also: Function, AggStep, AggFinal
    +-*/
    +-/* Opcode: Function P1 P2 P3 P4 P5
    +-** Synopsis: r[P3]=func(r[P2@P5])
    +-**
    +-** Invoke a user function (P4 is a pointer to an sqlite3_context object that
    +-** contains a pointer to the function to be run) with P5 arguments taken
    +-** from register P2 and successors.  The result of the function is stored
    +-** in register P3.  Register P3 must not be one of the function inputs.
    +-**
    +-** P1 is a 32-bit bitmask indicating whether or not each argument to the 
    +-** function was determined to be constant at compile time. If the first
    +-** argument was constant then bit 0 of P1 is set. This is used to determine
    +-** whether meta data associated with a user function argument using the
    +-** sqlite3_set_auxdata() API may be safely retained until the next
    +-** invocation of this opcode.
    +-**
    +-** SQL functions are initially coded as OP_Function0 with P4 pointing
    +-** to a FuncDef object.  But on first evaluation, the P4 operand is
    +-** automatically converted into an sqlite3_context object and the operation
    +-** changed to this OP_Function opcode.  In this way, the initialization of
    +-** the sqlite3_context object occurs only once, rather than once for each
    +-** evaluation of the function.
    +-**
    +-** See also: Function0, AggStep, AggFinal
    +-*/
    +-case OP_Function0: {
    +-  int n;
    +-  sqlite3_context *pCtx;
    +-
    +-  assert( pOp->p4type==P4_FUNCDEF );
    +-  n = pOp->p5;
    +-  assert( pOp->p3>0 && pOp->p3<=(p->nMem-p->nCursor) );
    +-  assert( n==0 || (pOp->p2>0 && pOp->p2+n<=(p->nMem-p->nCursor)+1) );
    +-  assert( pOp->p3<pOp->p2 || pOp->p3>=pOp->p2+n );
    +-  pCtx = sqlite3DbMallocRaw(db, sizeof(*pCtx) + (n-1)*sizeof(sqlite3_value*));
    +-  if( pCtx==0 ) goto no_mem;
    +-  pCtx->pOut = 0;
    +-  pCtx->pFunc = pOp->p4.pFunc;
    +-  pCtx->iOp = (int)(pOp - aOp);
    +-  pCtx->pVdbe = p;
    +-  pCtx->argc = n;
    +-  pOp->p4type = P4_FUNCCTX;
    +-  pOp->p4.pCtx = pCtx;
    +-  pOp->opcode = OP_Function;
    +-  /* Fall through into OP_Function */
    +-}
    +-case OP_Function: {
    +-  int i;
    +-  sqlite3_context *pCtx;
    +-
    +-  assert( pOp->p4type==P4_FUNCCTX );
    +-  pCtx = pOp->p4.pCtx;
    +-
    +-  /* If this function is inside of a trigger, the register array in aMem[]
    +-  ** might change from one evaluation to the next.  The next block of code
    +-  ** checks to see if the register array has changed, and if so it
    +-  ** reinitializes the relavant parts of the sqlite3_context object */
    +-  pOut = &aMem[pOp->p3];
    +-  if( pCtx->pOut != pOut ){
    +-    pCtx->pOut = pOut;
    +-    for(i=pCtx->argc-1; i>=0; i--) pCtx->argv[i] = &aMem[pOp->p2+i];
    +-  }
    +-
    +-  memAboutToChange(p, pCtx->pOut);
    +-#ifdef SQLITE_DEBUG
    +-  for(i=0; i<pCtx->argc; i++){
    +-    assert( memIsValid(pCtx->argv[i]) );
    +-    REGISTER_TRACE(pOp->p2+i, pCtx->argv[i]);
    +-  }
    +-#endif
    +-  MemSetTypeFlag(pCtx->pOut, MEM_Null);
    +-  pCtx->fErrorOrAux = 0;
    +-  db->lastRowid = lastRowid;
    +-  (*pCtx->pFunc->xFunc)(pCtx, pCtx->argc, pCtx->argv); /* IMP: R-24505-23230 */
    +-  lastRowid = db->lastRowid;  /* Remember rowid changes made by xFunc */
    +-
    +-  /* If the function returned an error, throw an exception */
    +-  if( pCtx->fErrorOrAux ){
    +-    if( pCtx->isError ){
    +-      sqlite3VdbeError(p, "%s", sqlite3_value_text(pCtx->pOut));
    +-      rc = pCtx->isError;
    +-    }
    +-    sqlite3VdbeDeleteAuxData(p, pCtx->iOp, pOp->p1);
    +-  }
    +-
    +-  /* Copy the result of the function into register P3 */
    +-  if( pOut->flags & (MEM_Str|MEM_Blob) ){
    +-    sqlite3VdbeChangeEncoding(pCtx->pOut, encoding);
    +-    if( sqlite3VdbeMemTooBig(pCtx->pOut) ) goto too_big;
    +-  }
    +-
    +-  REGISTER_TRACE(pOp->p3, pCtx->pOut);
    +-  UPDATE_MAX_BLOBSIZE(pCtx->pOut);
    +-  break;
    +-}
    +-
    + /* Opcode: BitAnd P1 P2 P3 * *
    +-** Synopsis:  r[P3]=r[P1]&r[P2]
    ++** Synopsis: r[P3]=r[P1]&r[P2]
    + **
    + ** Take the bit-wise AND of the values in register P1 and P2 and
    + ** store the result in register P3.
    + ** If either input is NULL, the result is NULL.
    + */
    + /* Opcode: BitOr P1 P2 P3 * *
    +-** Synopsis:  r[P3]=r[P1]|r[P2]
    ++** Synopsis: r[P3]=r[P1]|r[P2]
    + **
    + ** Take the bit-wise OR of the values in register P1 and P2 and
    + ** store the result in register P3.
    + ** If either input is NULL, the result is NULL.
    + */
    + /* Opcode: ShiftLeft P1 P2 P3 * *
    +-** Synopsis:  r[P3]=r[P2]<<r[P1]
    ++** Synopsis: r[P3]=r[P2]<<r[P1]
    + **
    + ** Shift the integer value in register P2 to the left by the
    + ** number of bits specified by the integer in register P1.
    +@@ -74598,7 +81593,7 @@ case OP_Function: {
    + ** If either input is NULL, the result is NULL.
    + */
    + /* Opcode: ShiftRight P1 P2 P3 * *
    +-** Synopsis:  r[P3]=r[P2]>>r[P1]
    ++** Synopsis: r[P3]=r[P2]>>r[P1]
    + **
    + ** Shift the integer value in register P2 to the right by the
    + ** number of bits specified by the integer in register P1.
    +@@ -74658,7 +81653,7 @@ case OP_ShiftRight: {           /* same as TK_RSHIFT, in1, in2, out3 */
    + }
    + 
    + /* Opcode: AddImm  P1 P2 * * *
    +-** Synopsis:  r[P1]=r[P1]+P2
    ++** Synopsis: r[P1]=r[P1]+P2
    + ** 
    + ** Add the constant P2 to the value in register P1.
    + ** The result is always an integer.
    +@@ -74724,11 +81719,11 @@ case OP_RealAffinity: {                  /* in1 */
    + ** Force the value in register P1 to be the type defined by P2.
    + ** 
    + ** <ul>
    +-** <li value="97"> TEXT
    +-** <li value="98"> BLOB
    +-** <li value="99"> NUMERIC
    +-** <li value="100"> INTEGER
    +-** <li value="101"> REAL
    ++** <li> P2=='A' &rarr; BLOB
    ++** <li> P2=='B' &rarr; TEXT
    ++** <li> P2=='C' &rarr; NUMERIC
    ++** <li> P2=='D' &rarr; INTEGER
    ++** <li> P2=='E' &rarr; REAL
    + ** </ul>
    + **
    + ** A NULL value is not changed by this routine.  It remains NULL.
    +@@ -74745,19 +81740,17 @@ case OP_Cast: {                  /* in1 */
    +   rc = ExpandBlob(pIn1);
    +   sqlite3VdbeMemCast(pIn1, pOp->p2, encoding);
    +   UPDATE_MAX_BLOBSIZE(pIn1);
    ++  if( rc ) goto abort_due_to_error;
    +   break;
    + }
    + #endif /* SQLITE_OMIT_CAST */
    + 
    +-/* Opcode: Lt P1 P2 P3 P4 P5
    +-** Synopsis: if r[P1]<r[P3] goto P2
    +-**
    +-** Compare the values in register P1 and P3.  If reg(P3)<reg(P1) then
    +-** jump to address P2.  
    ++/* Opcode: Eq P1 P2 P3 P4 P5
    ++** Synopsis: IF r[P3]==r[P1]
    + **
    +-** If the SQLITE_JUMPIFNULL bit of P5 is set and either reg(P1) or
    +-** reg(P3) is NULL then take the jump.  If the SQLITE_JUMPIFNULL 
    +-** bit is clear then fall through if either operand is NULL.
    ++** Compare the values in register P1 and P3.  If reg(P3)==reg(P1) then
    ++** jump to address P2.  Or if the SQLITE_STOREP2 flag is set in P5, then
    ++** store the result of comparison in register P2.
    + **
    + ** The SQLITE_AFF_MASK portion of P5 must be an affinity character -
    + ** SQLITE_AFF_TEXT, SQLITE_AFF_INTEGER, and so forth. An attempt is made 
    +@@ -74771,61 +81764,78 @@ case OP_Cast: {                  /* in1 */
    + ** the values are compared. If both values are blobs then memcmp() is
    + ** used to determine the results of the comparison.  If both values
    + ** are text, then the appropriate collating function specified in
    +-** P4 is  used to do the comparison.  If P4 is not specified then
    ++** P4 is used to do the comparison.  If P4 is not specified then
    + ** memcmp() is used to compare text string.  If both values are
    + ** numeric, then a numeric comparison is used. If the two values
    + ** are of different types, then numbers are considered less than
    + ** strings and strings are considered less than blobs.
    + **
    +-** If the SQLITE_STOREP2 bit of P5 is set, then do not jump.  Instead,
    +-** store a boolean result (either 0, or 1, or NULL) in register P2.
    ++** If SQLITE_NULLEQ is set in P5 then the result of comparison is always either
    ++** true or false and is never NULL.  If both operands are NULL then the result
    ++** of comparison is true.  If either operand is NULL then the result is false.
    ++** If neither operand is NULL the result is the same as it would be if
    ++** the SQLITE_NULLEQ flag were omitted from P5.
    + **
    +-** If the SQLITE_NULLEQ bit is set in P5, then NULL values are considered
    +-** equal to one another, provided that they do not have their MEM_Cleared
    +-** bit set.
    ++** If both SQLITE_STOREP2 and SQLITE_KEEPNULL flags are set then the
    ++** content of r[P2] is only changed if the new value is NULL or 0 (false).
    ++** In other words, a prior r[P2] value will not be overwritten by 1 (true).
    + */
    + /* Opcode: Ne P1 P2 P3 P4 P5
    +-** Synopsis: if r[P1]!=r[P3] goto P2
    ++** Synopsis: IF r[P3]!=r[P1]
    + **
    +-** This works just like the Lt opcode except that the jump is taken if
    +-** the operands in registers P1 and P3 are not equal.  See the Lt opcode for
    ++** This works just like the Eq opcode except that the jump is taken if
    ++** the operands in registers P1 and P3 are not equal.  See the Eq opcode for
    + ** additional information.
    + **
    +-** If SQLITE_NULLEQ is set in P5 then the result of comparison is always either
    +-** true or false and is never NULL.  If both operands are NULL then the result
    +-** of comparison is false.  If either operand is NULL then the result is true.
    +-** If neither operand is NULL the result is the same as it would be if
    +-** the SQLITE_NULLEQ flag were omitted from P5.
    ++** If both SQLITE_STOREP2 and SQLITE_KEEPNULL flags are set then the
    ++** content of r[P2] is only changed if the new value is NULL or 1 (true).
    ++** In other words, a prior r[P2] value will not be overwritten by 0 (false).
    + */
    +-/* Opcode: Eq P1 P2 P3 P4 P5
    +-** Synopsis: if r[P1]==r[P3] goto P2
    ++/* Opcode: Lt P1 P2 P3 P4 P5
    ++** Synopsis: IF r[P3]<r[P1]
    + **
    +-** This works just like the Lt opcode except that the jump is taken if
    +-** the operands in registers P1 and P3 are equal.
    +-** See the Lt opcode for additional information.
    ++** Compare the values in register P1 and P3.  If reg(P3)<reg(P1) then
    ++** jump to address P2.  Or if the SQLITE_STOREP2 flag is set in P5 store
    ++** the result of comparison (0 or 1 or NULL) into register P2.
    + **
    +-** If SQLITE_NULLEQ is set in P5 then the result of comparison is always either
    +-** true or false and is never NULL.  If both operands are NULL then the result
    +-** of comparison is true.  If either operand is NULL then the result is false.
    +-** If neither operand is NULL the result is the same as it would be if
    +-** the SQLITE_NULLEQ flag were omitted from P5.
    ++** If the SQLITE_JUMPIFNULL bit of P5 is set and either reg(P1) or
    ++** reg(P3) is NULL then the take the jump.  If the SQLITE_JUMPIFNULL 
    ++** bit is clear then fall through if either operand is NULL.
    ++**
    ++** The SQLITE_AFF_MASK portion of P5 must be an affinity character -
    ++** SQLITE_AFF_TEXT, SQLITE_AFF_INTEGER, and so forth. An attempt is made 
    ++** to coerce both inputs according to this affinity before the
    ++** comparison is made. If the SQLITE_AFF_MASK is 0x00, then numeric
    ++** affinity is used. Note that the affinity conversions are stored
    ++** back into the input registers P1 and P3.  So this opcode can cause
    ++** persistent changes to registers P1 and P3.
    ++**
    ++** Once any conversions have taken place, and neither value is NULL, 
    ++** the values are compared. If both values are blobs then memcmp() is
    ++** used to determine the results of the comparison.  If both values
    ++** are text, then the appropriate collating function specified in
    ++** P4 is  used to do the comparison.  If P4 is not specified then
    ++** memcmp() is used to compare text string.  If both values are
    ++** numeric, then a numeric comparison is used. If the two values
    ++** are of different types, then numbers are considered less than
    ++** strings and strings are considered less than blobs.
    + */
    + /* Opcode: Le P1 P2 P3 P4 P5
    +-** Synopsis: if r[P1]<=r[P3] goto P2
    ++** Synopsis: IF r[P3]<=r[P1]
    + **
    + ** This works just like the Lt opcode except that the jump is taken if
    + ** the content of register P3 is less than or equal to the content of
    + ** register P1.  See the Lt opcode for additional information.
    + */
    + /* Opcode: Gt P1 P2 P3 P4 P5
    +-** Synopsis: if r[P1]>r[P3] goto P2
    ++** Synopsis: IF r[P3]>r[P1]
    + **
    + ** This works just like the Lt opcode except that the jump is taken if
    + ** the content of register P3 is greater than the content of
    + ** register P1.  See the Lt opcode for additional information.
    + */
    + /* Opcode: Ge P1 P2 P3 P4 P5
    +-** Synopsis: if r[P1]>=r[P3] goto P2
    ++** Synopsis: IF r[P3]>=r[P1]
    + **
    + ** This works just like the Lt opcode except that the jump is taken if
    + ** the content of register P3 is greater than or equal to the content of
    +@@ -74837,7 +81847,7 @@ case OP_Lt:               /* same as TK_LT, jump, in1, in3 */
    + case OP_Le:               /* same as TK_LE, jump, in1, in3 */
    + case OP_Gt:               /* same as TK_GT, jump, in1, in3 */
    + case OP_Ge: {             /* same as TK_GE, jump, in1, in3 */
    +-  int res;            /* Result of the comparison of pIn1 against pIn3 */
    ++  int res, res2;      /* Result of the comparison of pIn1 against pIn3 */
    +   char affinity;      /* Affinity to use for comparison */
    +   u16 flags1;         /* Copy of initial value of pIn1->flags */
    +   u16 flags3;         /* Copy of initial value of pIn3->flags */
    +@@ -74856,13 +81866,12 @@ case OP_Ge: {             /* same as TK_GE, jump, in1, in3 */
    +       assert( pOp->opcode==OP_Eq || pOp->opcode==OP_Ne );
    +       assert( (flags1 & MEM_Cleared)==0 );
    +       assert( (pOp->p5 & SQLITE_JUMPIFNULL)==0 );
    +-      if( (flags1&MEM_Null)!=0
    +-       && (flags3&MEM_Null)!=0
    ++      if( (flags1&flags3&MEM_Null)!=0
    +        && (flags3&MEM_Cleared)==0
    +       ){
    +-        res = 0;  /* Results are equal */
    ++        res = 0;  /* Operands are equal */
    +       }else{
    +-        res = 1;  /* Results are not equal */
    ++        res = 1;  /* Operands are not equal */
    +       }
    +     }else{
    +       /* SQLITE_NULLEQ is clear and at least one operand is NULL,
    +@@ -74871,6 +81880,8 @@ case OP_Ge: {             /* same as TK_GE, jump, in1, in3 */
    +       */
    +       if( pOp->p5 & SQLITE_STOREP2 ){
    +         pOut = &aMem[pOp->p2];
    ++        iCompare = 1;    /* Operands are not equal */
    ++        memAboutToChange(p, pOut);
    +         MemSetTypeFlag(pOut, MEM_Null);
    +         REGISTER_TRACE(pOp->p2, pOut);
    +       }else{
    +@@ -74885,21 +81896,34 @@ case OP_Ge: {             /* same as TK_GE, jump, in1, in3 */
    +     /* Neither operand is NULL.  Do a comparison. */
    +     affinity = pOp->p5 & SQLITE_AFF_MASK;
    +     if( affinity>=SQLITE_AFF_NUMERIC ){
    +-      if( (pIn1->flags & (MEM_Int|MEM_Real|MEM_Str))==MEM_Str ){
    +-        applyNumericAffinity(pIn1,0);
    ++      if( (flags1 | flags3)&MEM_Str ){
    ++        if( (flags1 & (MEM_Int|MEM_Real|MEM_Str))==MEM_Str ){
    ++          applyNumericAffinity(pIn1,0);
    ++          testcase( flags3!=pIn3->flags ); /* Possible if pIn1==pIn3 */
    ++          flags3 = pIn3->flags;
    ++        }
    ++        if( (flags3 & (MEM_Int|MEM_Real|MEM_Str))==MEM_Str ){
    ++          applyNumericAffinity(pIn3,0);
    ++        }
    +       }
    +-      if( (pIn3->flags & (MEM_Int|MEM_Real|MEM_Str))==MEM_Str ){
    +-        applyNumericAffinity(pIn3,0);
    ++      /* Handle the common case of integer comparison here, as an
    ++      ** optimization, to avoid a call to sqlite3MemCompare() */
    ++      if( (pIn1->flags & pIn3->flags & MEM_Int)!=0 ){
    ++        if( pIn3->u.i > pIn1->u.i ){ res = +1; goto compare_op; }
    ++        if( pIn3->u.i < pIn1->u.i ){ res = -1; goto compare_op; }
    ++        res = 0;
    ++        goto compare_op;
    +       }
    +     }else if( affinity==SQLITE_AFF_TEXT ){
    +-      if( (pIn1->flags & MEM_Str)==0 && (pIn1->flags & (MEM_Int|MEM_Real))!=0 ){
    ++      if( (flags1 & MEM_Str)==0 && (flags1 & (MEM_Int|MEM_Real))!=0 ){
    +         testcase( pIn1->flags & MEM_Int );
    +         testcase( pIn1->flags & MEM_Real );
    +         sqlite3VdbeMemStringify(pIn1, encoding, 1);
    +         testcase( (flags1&MEM_Dyn) != (pIn1->flags&MEM_Dyn) );
    +         flags1 = (pIn1->flags & ~MEM_TypeMask) | (flags1 & MEM_TypeMask);
    ++        assert( pIn1!=pIn3 );
    +       }
    +-      if( (pIn3->flags & MEM_Str)==0 && (pIn3->flags & (MEM_Int|MEM_Real))!=0 ){
    ++      if( (flags3 & MEM_Str)==0 && (flags3 & (MEM_Int|MEM_Real))!=0 ){
    +         testcase( pIn3->flags & MEM_Int );
    +         testcase( pIn3->flags & MEM_Real );
    +         sqlite3VdbeMemStringify(pIn3, encoding, 1);
    +@@ -74908,24 +81932,26 @@ case OP_Ge: {             /* same as TK_GE, jump, in1, in3 */
    +       }
    +     }
    +     assert( pOp->p4type==P4_COLLSEQ || pOp->p4.pColl==0 );
    +-    if( pIn1->flags & MEM_Zero ){
    +-      sqlite3VdbeMemExpandBlob(pIn1);
    +-      flags1 &= ~MEM_Zero;
    +-    }
    +-    if( pIn3->flags & MEM_Zero ){
    +-      sqlite3VdbeMemExpandBlob(pIn3);
    +-      flags3 &= ~MEM_Zero;
    +-    }
    +-    if( db->mallocFailed ) goto no_mem;
    +     res = sqlite3MemCompare(pIn3, pIn1, pOp->p4.pColl);
    +   }
    +-  switch( pOp->opcode ){
    +-    case OP_Eq:    res = res==0;     break;
    +-    case OP_Ne:    res = res!=0;     break;
    +-    case OP_Lt:    res = res<0;      break;
    +-    case OP_Le:    res = res<=0;     break;
    +-    case OP_Gt:    res = res>0;      break;
    +-    default:       res = res>=0;     break;
    ++compare_op:
    ++  /* At this point, res is negative, zero, or positive if reg[P1] is
    ++  ** less than, equal to, or greater than reg[P3], respectively.  Compute
    ++  ** the answer to this operator in res2, depending on what the comparison
    ++  ** operator actually is.  The next block of code depends on the fact
    ++  ** that the 6 comparison operators are consecutive integers in this
    ++  ** order:  NE, EQ, GT, LE, LT, GE */
    ++  assert( OP_Eq==OP_Ne+1 ); assert( OP_Gt==OP_Ne+2 ); assert( OP_Le==OP_Ne+3 );
    ++  assert( OP_Lt==OP_Ne+4 ); assert( OP_Ge==OP_Ne+5 );
    ++  if( res<0 ){                        /* ne, eq, gt, le, lt, ge */
    ++    static const unsigned char aLTb[] = { 1,  0,  0,  1,  1,  0 };
    ++    res2 = aLTb[pOp->opcode - OP_Ne];
    ++  }else if( res==0 ){
    ++    static const unsigned char aEQb[] = { 0,  1,  0,  1,  0,  1 };
    ++    res2 = aEQb[pOp->opcode - OP_Ne];
    ++  }else{
    ++    static const unsigned char aGTb[] = { 1,  0,  1,  0,  0,  1 };
    ++    res2 = aGTb[pOp->opcode - OP_Ne];
    +   }
    + 
    +   /* Undo any changes made by applyAffinity() to the input registers. */
    +@@ -74936,32 +81962,71 @@ case OP_Ge: {             /* same as TK_GE, jump, in1, in3 */
    + 
    +   if( pOp->p5 & SQLITE_STOREP2 ){
    +     pOut = &aMem[pOp->p2];
    ++    iCompare = res;
    ++    if( (pOp->p5 & SQLITE_KEEPNULL)!=0 ){
    ++      /* The KEEPNULL flag prevents OP_Eq from overwriting a NULL with 1
    ++      ** and prevents OP_Ne from overwriting NULL with 0.  This flag
    ++      ** is only used in contexts where either:
    ++      **   (1) op==OP_Eq && (r[P2]==NULL || r[P2]==0)
    ++      **   (2) op==OP_Ne && (r[P2]==NULL || r[P2]==1)
    ++      ** Therefore it is not necessary to check the content of r[P2] for
    ++      ** NULL. */
    ++      assert( pOp->opcode==OP_Ne || pOp->opcode==OP_Eq );
    ++      assert( res2==0 || res2==1 );
    ++      testcase( res2==0 && pOp->opcode==OP_Eq );
    ++      testcase( res2==1 && pOp->opcode==OP_Eq );
    ++      testcase( res2==0 && pOp->opcode==OP_Ne );
    ++      testcase( res2==1 && pOp->opcode==OP_Ne );
    ++      if( (pOp->opcode==OP_Eq)==res2 ) break;
    ++    }
    +     memAboutToChange(p, pOut);
    +     MemSetTypeFlag(pOut, MEM_Int);
    +-    pOut->u.i = res;
    ++    pOut->u.i = res2;
    +     REGISTER_TRACE(pOp->p2, pOut);
    +   }else{
    +     VdbeBranchTaken(res!=0, (pOp->p5 & SQLITE_NULLEQ)?2:3);
    +-    if( res ){
    ++    if( res2 ){
    +       goto jump_to_p2;
    +     }
    +   }
    +   break;
    + }
    + 
    ++/* Opcode: ElseNotEq * P2 * * *
    ++**
    ++** This opcode must immediately follow an OP_Lt or OP_Gt comparison operator.
    ++** If result of an OP_Eq comparison on the same two operands
    ++** would have be NULL or false (0), then then jump to P2. 
    ++** If the result of an OP_Eq comparison on the two previous operands
    ++** would have been true (1), then fall through.
    ++*/
    ++case OP_ElseNotEq: {       /* same as TK_ESCAPE, jump */
    ++  assert( pOp>aOp );
    ++  assert( pOp[-1].opcode==OP_Lt || pOp[-1].opcode==OP_Gt );
    ++  assert( pOp[-1].p5 & SQLITE_STOREP2 );
    ++  VdbeBranchTaken(iCompare!=0, 2);
    ++  if( iCompare!=0 ) goto jump_to_p2;
    ++  break;
    ++}
    ++
    ++
    + /* Opcode: Permutation * * * P4 *
    + **
    +-** Set the permutation used by the OP_Compare operator to be the array
    +-** of integers in P4.
    ++** Set the permutation used by the OP_Compare operator in the next
    ++** instruction.  The permutation is stored in the P4 operand.
    + **
    + ** The permutation is only valid until the next OP_Compare that has
    + ** the OPFLAG_PERMUTE bit set in P5. Typically the OP_Permutation should 
    + ** occur immediately prior to the OP_Compare.
    ++**
    ++** The first integer in the P4 integer array is the length of the array
    ++** and does not become part of the permutation.
    + */
    + case OP_Permutation: {
    +   assert( pOp->p4type==P4_INTARRAY );
    +   assert( pOp->p4.ai );
    +-  aPermute = pOp->p4.ai;
    ++  assert( pOp[1].opcode==OP_Compare );
    ++  assert( pOp[1].p5 & OPFLAG_PERMUTE );
    +   break;
    + }
    + 
    +@@ -74994,23 +82059,32 @@ case OP_Compare: {
    +   int idx;
    +   CollSeq *pColl;    /* Collating sequence to use on this term */
    +   int bRev;          /* True for DESCENDING sort order */
    ++  int *aPermute;     /* The permutation */
    + 
    +-  if( (pOp->p5 & OPFLAG_PERMUTE)==0 ) aPermute = 0;
    ++  if( (pOp->p5 & OPFLAG_PERMUTE)==0 ){
    ++    aPermute = 0;
    ++  }else{
    ++    assert( pOp>aOp );
    ++    assert( pOp[-1].opcode==OP_Permutation );
    ++    assert( pOp[-1].p4type==P4_INTARRAY );
    ++    aPermute = pOp[-1].p4.ai + 1;
    ++    assert( aPermute!=0 );
    ++  }
    +   n = pOp->p3;
    +   pKeyInfo = pOp->p4.pKeyInfo;
    +   assert( n>0 );
    +   assert( pKeyInfo!=0 );
    +   p1 = pOp->p1;
    +   p2 = pOp->p2;
    +-#if SQLITE_DEBUG
    ++#ifdef SQLITE_DEBUG
    +   if( aPermute ){
    +     int k, mx = 0;
    +     for(k=0; k<n; k++) if( aPermute[k]>mx ) mx = aPermute[k];
    +-    assert( p1>0 && p1+mx<=(p->nMem-p->nCursor)+1 );
    +-    assert( p2>0 && p2+mx<=(p->nMem-p->nCursor)+1 );
    ++    assert( p1>0 && p1+mx<=(p->nMem+1 - p->nCursor)+1 );
    ++    assert( p2>0 && p2+mx<=(p->nMem+1 - p->nCursor)+1 );
    +   }else{
    +-    assert( p1>0 && p1+n<=(p->nMem-p->nCursor)+1 );
    +-    assert( p2>0 && p2+n<=(p->nMem-p->nCursor)+1 );
    ++    assert( p1>0 && p1+n<=(p->nMem+1 - p->nCursor)+1 );
    ++    assert( p2>0 && p2+n<=(p->nMem+1 - p->nCursor)+1 );
    +   }
    + #endif /* SQLITE_DEBUG */
    +   for(i=0; i<n; i++){
    +@@ -75019,7 +82093,7 @@ case OP_Compare: {
    +     assert( memIsValid(&aMem[p2+idx]) );
    +     REGISTER_TRACE(p1+idx, &aMem[p1+idx]);
    +     REGISTER_TRACE(p2+idx, &aMem[p2+idx]);
    +-    assert( i<pKeyInfo->nField );
    ++    assert( i<pKeyInfo->nKeyField );
    +     pColl = pKeyInfo->aColl[i];
    +     bRev = pKeyInfo->aSortOrder[i];
    +     iCompare = sqlite3MemCompare(&aMem[p1+idx], &aMem[p2+idx], pColl);
    +@@ -75028,7 +82102,6 @@ case OP_Compare: {
    +       break;
    +     }
    +   }
    +-  aPermute = 0;
    +   break;
    + }
    + 
    +@@ -75141,23 +82214,39 @@ case OP_BitNot: {             /* same as TK_BITNOT, in1, out2 */
    + 
    + /* Opcode: Once P1 P2 * * *
    + **
    +-** 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.
    ++** Fall through to the next instruction the first time this opcode is
    ++** encountered on each invocation of the byte-code program.  Jump to P2
    ++** on the second and all subsequent encounters during the same invocation.
    ++**
    ++** Top-level programs determine first invocation by comparing the P1
    ++** operand against the P1 operand on the OP_Init opcode at the beginning
    ++** of the program.  If the P1 values differ, then fall through and make
    ++** the P1 of this opcode equal to the P1 of OP_Init.  If P1 values are
    ++** the same then take the jump.
    + **
    +-** All "once" flags are initially cleared whenever a prepared statement
    +-** first begins to run.
    ++** For subprograms, there is a bitmask in the VdbeFrame that determines
    ++** whether or not the jump should be taken.  The bitmask is necessary
    ++** because the self-altering code trick does not work for recursive
    ++** triggers.
    + */
    + case OP_Once: {             /* jump */
    +-  assert( pOp->p1<p->nOnceFlag );
    +-  VdbeBranchTaken(p->aOnceFlag[pOp->p1]!=0, 2);
    +-  if( p->aOnceFlag[pOp->p1] ){
    +-    goto jump_to_p2;
    ++  u32 iAddr;                /* Address of this instruction */
    ++  assert( p->aOp[0].opcode==OP_Init );
    ++  if( p->pFrame ){
    ++    iAddr = (int)(pOp - p->aOp);
    ++    if( (p->pFrame->aOnce[iAddr/8] & (1<<(iAddr & 7)))!=0 ){
    ++      VdbeBranchTaken(1, 2);
    ++      goto jump_to_p2;
    ++    }
    ++    p->pFrame->aOnce[iAddr/8] |= 1<<(iAddr & 7);
    +   }else{
    +-    p->aOnceFlag[pOp->p1] = 1;
    ++    if( p->aOp[0].p1==pOp->p1 ){
    ++      VdbeBranchTaken(1, 2);
    ++      goto jump_to_p2;
    ++    }
    +   }
    ++  VdbeBranchTaken(0, 2);
    ++  pOp->p1 = p->aOp[0].p1;
    +   break;
    + }
    + 
    +@@ -75195,7 +82284,7 @@ case OP_IfNot: {            /* jump, in1 */
    + }
    + 
    + /* Opcode: IsNull P1 P2 * * *
    +-** Synopsis:  if r[P1]==NULL goto P2
    ++** Synopsis: if r[P1]==NULL goto P2
    + **
    + ** Jump to P2 if the value in register P1 is NULL.
    + */
    +@@ -75222,8 +82311,56 @@ case OP_NotNull: {            /* same as TK_NOTNULL, jump, in1 */
    +   break;
    + }
    + 
    ++/* Opcode: IfNullRow P1 P2 P3 * *
    ++** Synopsis: if P1.nullRow then r[P3]=NULL, goto P2
    ++**
    ++** Check the cursor P1 to see if it is currently pointing at a NULL row.
    ++** If it is, then set register P3 to NULL and jump immediately to P2.
    ++** If P1 is not on a NULL row, then fall through without making any
    ++** changes.
    ++*/
    ++case OP_IfNullRow: {         /* jump */
    ++  assert( pOp->p1>=0 && pOp->p1<p->nCursor );
    ++  assert( p->apCsr[pOp->p1]!=0 );
    ++  if( p->apCsr[pOp->p1]->nullRow ){
    ++    sqlite3VdbeMemSetNull(aMem + pOp->p3);
    ++    goto jump_to_p2;
    ++  }
    ++  break;
    ++}
    ++
    ++#ifdef SQLITE_ENABLE_OFFSET_SQL_FUNC
    ++/* Opcode: Offset P1 P2 P3 * *
    ++** Synopsis: r[P3] = sqlite_offset(P1)
    ++**
    ++** Store in register r[P3] the byte offset into the database file that is the
    ++** start of the payload for the record at which that cursor P1 is currently
    ++** pointing.
    ++**
    ++** P2 is the column number for the argument to the sqlite_offset() function.
    ++** This opcode does not use P2 itself, but the P2 value is used by the
    ++** code generator.  The P1, P2, and P3 operands to this opcode are the
    ++** as as for OP_Column.
    ++**
    ++** This opcode is only available if SQLite is compiled with the
    ++** -DSQLITE_ENABLE_OFFSET_SQL_FUNC option.
    ++*/
    ++case OP_Offset: {          /* out3 */
    ++  VdbeCursor *pC;    /* The VDBE cursor */
    ++  assert( pOp->p1>=0 && pOp->p1<p->nCursor );
    ++  pC = p->apCsr[pOp->p1];
    ++  pOut = &p->aMem[pOp->p3];
    ++  if( NEVER(pC==0) || pC->eCurType!=CURTYPE_BTREE ){
    ++    sqlite3VdbeMemSetNull(pOut);
    ++  }else{
    ++    sqlite3VdbeMemSetInt64(pOut, sqlite3BtreeOffset(pC->uc.pCursor));
    ++  }
    ++  break;
    ++}
    ++#endif /* SQLITE_ENABLE_OFFSET_SQL_FUNC */
    ++
    + /* Opcode: Column P1 P2 P3 P4 P5
    +-** Synopsis:  r[P3]=PX
    ++** Synopsis: r[P3]=PX
    + **
    + ** Interpret the data that cursor P1 points to as a structure built using
    + ** the MakeRecord instruction.  (See the MakeRecord opcode for additional
    +@@ -75233,7 +82370,7 @@ case OP_NotNull: {            /* same as TK_NOTNULL, jump, in1 */
    + **
    + ** The value extracted is stored in register P3.
    + **
    +-** If the column contains fewer than P2 fields, then extract a NULL.  Or,
    ++** If the record contains fewer than P2 fields, then extract a NULL.  Or,
    + ** if the P4 argument is a P4_MEM use the value of the P4 argument as
    + ** the result.
    + **
    +@@ -75242,13 +82379,12 @@ case OP_NotNull: {            /* same as TK_NOTNULL, jump, in1 */
    + ** The first OP_Column against a pseudo-table after the value of the content
    + ** register has changed should have this bit set.
    + **
    +-** If the OPFLAG_LENGTHARG and OPFLAG_TYPEOFARG bits are set on P5 when
    ++** If the OPFLAG_LENGTHARG and OPFLAG_TYPEOFARG bits are set on P5 then
    + ** the result is guaranteed to only be used as the argument of a length()
    + ** or typeof() function, respectively.  The loading of large blobs can be
    + ** skipped for length() and all content loading can be skipped for typeof().
    + */
    + case OP_Column: {
    +-  i64 payloadSize64; /* Number of bytes in the record */
    +   int p2;            /* column number to retrieve */
    +   VdbeCursor *pC;    /* The VDBE cursor */
    +   BtCursor *pCrsr;   /* The BTree cursor */
    +@@ -75260,107 +82396,102 @@ case OP_Column: {
    +   const u8 *zData;   /* Part of the record being decoded */
    +   const u8 *zHdr;    /* Next unparsed byte of the header */
    +   const u8 *zEndHdr; /* Pointer to first byte after the header */
    +-  u32 offset;        /* Offset into the data */
    +-  u32 szField;       /* Number of bytes in the content of a field */
    +-  u32 avail;         /* Number of bytes of available data */
    ++  u64 offset64;      /* 64-bit offset */
    +   u32 t;             /* A type code from the record header */
    +-  u16 fx;            /* pDest->flags value */
    +   Mem *pReg;         /* PseudoTable input register */
    + 
    ++  pC = p->apCsr[pOp->p1];
    +   p2 = pOp->p2;
    +-  assert( pOp->p3>0 && pOp->p3<=(p->nMem-p->nCursor) );
    ++
    ++  /* If the cursor cache is stale (meaning it is not currently point at
    ++  ** the correct row) then bring it up-to-date by doing the necessary 
    ++  ** B-Tree seek. */
    ++  rc = sqlite3VdbeCursorMoveto(&pC, &p2);
    ++  if( rc ) goto abort_due_to_error;
    ++
    ++  assert( pOp->p3>0 && pOp->p3<=(p->nMem+1 - p->nCursor) );
    +   pDest = &aMem[pOp->p3];
    +   memAboutToChange(p, pDest);
    +   assert( pOp->p1>=0 && pOp->p1<p->nCursor );
    +-  pC = p->apCsr[pOp->p1];
    +   assert( pC!=0 );
    +   assert( p2<pC->nField );
    +   aOffset = pC->aOffset;
    +-#ifndef SQLITE_OMIT_VIRTUALTABLE
    +-  assert( pC->pVtabCursor==0 ); /* OP_Column never called on virtual table */
    +-#endif
    +-  pCrsr = pC->pCursor;
    +-  assert( pCrsr!=0 || pC->pseudoTableReg>0 ); /* pCrsr NULL on PseudoTables */
    +-  assert( pCrsr!=0 || pC->nullRow );          /* pC->nullRow on PseudoTables */
    ++  assert( pC->eCurType!=CURTYPE_VTAB );
    ++  assert( pC->eCurType!=CURTYPE_PSEUDO || pC->nullRow );
    ++  assert( pC->eCurType!=CURTYPE_SORTER );
    + 
    +-  /* If the cursor cache is stale, bring it up-to-date */
    +-  rc = sqlite3VdbeCursorMoveto(pC);
    +-  if( rc ) goto abort_due_to_error;
    +-  if( pC->cacheStatus!=p->cacheCtr ){
    ++  if( pC->cacheStatus!=p->cacheCtr ){                /*OPTIMIZATION-IF-FALSE*/
    +     if( pC->nullRow ){
    +-      if( pCrsr==0 ){
    +-        assert( pC->pseudoTableReg>0 );
    +-        pReg = &aMem[pC->pseudoTableReg];
    ++      if( pC->eCurType==CURTYPE_PSEUDO ){
    ++        /* For the special case of as pseudo-cursor, the seekResult field
    ++        ** identifies the register that holds the record */
    ++        assert( pC->seekResult>0 );
    ++        pReg = &aMem[pC->seekResult];
    +         assert( pReg->flags & MEM_Blob );
    +         assert( memIsValid(pReg) );
    +-        pC->payloadSize = pC->szRow = avail = pReg->n;
    ++        pC->payloadSize = pC->szRow = pReg->n;
    +         pC->aRow = (u8*)pReg->z;
    +       }else{
    +         sqlite3VdbeMemSetNull(pDest);
    +         goto op_column_out;
    +       }
    +     }else{
    ++      pCrsr = pC->uc.pCursor;
    ++      assert( pC->eCurType==CURTYPE_BTREE );
    +       assert( pCrsr );
    +-      if( pC->isTable==0 ){
    +-        assert( sqlite3BtreeCursorIsValid(pCrsr) );
    +-        VVA_ONLY(rc =) sqlite3BtreeKeySize(pCrsr, &payloadSize64);
    +-        assert( rc==SQLITE_OK ); /* True because of CursorMoveto() call above */
    +-        /* sqlite3BtreeParseCellPtr() uses getVarint32() to extract the
    +-        ** payload size, so it is impossible for payloadSize64 to be
    +-        ** larger than 32 bits. */
    +-        assert( (payloadSize64 & SQLITE_MAX_U32)==(u64)payloadSize64 );
    +-        pC->aRow = sqlite3BtreeKeyFetch(pCrsr, &avail);
    +-        pC->payloadSize = (u32)payloadSize64;
    +-      }else{
    +-        assert( sqlite3BtreeCursorIsValid(pCrsr) );
    +-        VVA_ONLY(rc =) sqlite3BtreeDataSize(pCrsr, &pC->payloadSize);
    +-        assert( rc==SQLITE_OK );   /* DataSize() cannot fail */
    +-        pC->aRow = sqlite3BtreeDataFetch(pCrsr, &avail);
    +-      }
    +-      assert( avail<=65536 );  /* Maximum page size is 64KiB */
    +-      if( pC->payloadSize <= (u32)avail ){
    +-        pC->szRow = pC->payloadSize;
    +-      }else{
    +-        pC->szRow = avail;
    +-      }
    ++      assert( sqlite3BtreeCursorIsValid(pCrsr) );
    ++      pC->payloadSize = sqlite3BtreePayloadSize(pCrsr);
    ++      pC->aRow = sqlite3BtreePayloadFetch(pCrsr, &pC->szRow);
    ++      assert( pC->szRow<=pC->payloadSize );
    ++      assert( pC->szRow<=65536 );  /* Maximum page size is 64KiB */
    +       if( pC->payloadSize > (u32)db->aLimit[SQLITE_LIMIT_LENGTH] ){
    +         goto too_big;
    +       }
    +     }
    +     pC->cacheStatus = p->cacheCtr;
    +-    pC->iHdrOffset = getVarint32(pC->aRow, offset);
    ++    pC->iHdrOffset = getVarint32(pC->aRow, aOffset[0]);
    +     pC->nHdrParsed = 0;
    +-    aOffset[0] = offset;
    + 
    +-    /* Make sure a corrupt database has not given us an oversize header.
    +-    ** Do this now to avoid an oversize memory allocation.
    +-    **
    +-    ** Type entries can be between 1 and 5 bytes each.  But 4 and 5 byte
    +-    ** types use so much data space that there can only be 4096 and 32 of
    +-    ** them, respectively.  So the maximum header length results from a
    +-    ** 3-byte type for each of the maximum of 32768 columns plus three
    +-    ** extra bytes for the header length itself.  32768*3 + 3 = 98307.
    +-    */
    +-    if( offset > 98307 || offset > pC->payloadSize ){
    +-      rc = SQLITE_CORRUPT_BKPT;
    +-      goto op_column_error;
    +-    }
    + 
    +-    if( avail<offset ){
    ++    if( pC->szRow<aOffset[0] ){      /*OPTIMIZATION-IF-FALSE*/
    +       /* pC->aRow does not have to hold the entire row, but it does at least
    +       ** need to cover the header of the record.  If pC->aRow does not contain
    +       ** the complete header, then set it to zero, forcing the header to be
    +       ** dynamically allocated. */
    +       pC->aRow = 0;
    +       pC->szRow = 0;
    +-    }
    + 
    +-    /* The following goto is an optimization.  It can be omitted and
    +-    ** everything will still work.  But OP_Column is measurably faster
    +-    ** by skipping the subsequent conditional, which is always true.
    +-    */
    +-    assert( pC->nHdrParsed<=p2 );         /* Conditional skipped */
    +-    goto op_column_read_header;
    ++      /* Make sure a corrupt database has not given us an oversize header.
    ++      ** Do this now to avoid an oversize memory allocation.
    ++      **
    ++      ** Type entries can be between 1 and 5 bytes each.  But 4 and 5 byte
    ++      ** types use so much data space that there can only be 4096 and 32 of
    ++      ** them, respectively.  So the maximum header length results from a
    ++      ** 3-byte type for each of the maximum of 32768 columns plus three
    ++      ** extra bytes for the header length itself.  32768*3 + 3 = 98307.
    ++      */
    ++      if( aOffset[0] > 98307 || aOffset[0] > pC->payloadSize ){
    ++        goto op_column_corrupt;
    ++      }
    ++    }else{
    ++      /* This is an optimization.  By skipping over the first few tests
    ++      ** (ex: pC->nHdrParsed<=p2) in the next section, we achieve a
    ++      ** measurable performance gain.
    ++      **
    ++      ** This branch is taken even if aOffset[0]==0.  Such a record is never
    ++      ** generated by SQLite, and could be considered corruption, but we
    ++      ** accept it for historical reasons.  When aOffset[0]==0, the code this
    ++      ** branch jumps to reads past the end of the record, but never more
    ++      ** than a few bytes.  Even if the record occurs at the end of the page
    ++      ** content area, the "page header" comes after the page content and so
    ++      ** this overread is harmless.  Similar overreads can occur for a corrupt
    ++      ** database file.
    ++      */
    ++      zData = pC->aRow;
    ++      assert( pC->nHdrParsed<=p2 );         /* Conditional skipped */
    ++      testcase( aOffset[0]==0 );
    ++      goto op_column_read_header;
    ++    }
    +   }
    + 
    +   /* Make sure at least the first p2+1 entries of the header have been
    +@@ -75370,65 +82501,58 @@ case OP_Column: {
    +     /* If there is more header available for parsing in the record, try
    +     ** to extract additional fields up through the p2+1-th field 
    +     */
    +-    op_column_read_header:
    +     if( pC->iHdrOffset<aOffset[0] ){
    +       /* Make sure zData points to enough of the record to cover the header. */
    +       if( pC->aRow==0 ){
    +         memset(&sMem, 0, sizeof(sMem));
    +-        rc = sqlite3VdbeMemFromBtree(pCrsr, 0, aOffset[0], 
    +-                                     !pC->isTable, &sMem);
    +-        if( rc!=SQLITE_OK ){
    +-          goto op_column_error;
    +-        }
    ++        rc = sqlite3VdbeMemFromBtree(pC->uc.pCursor, 0, aOffset[0], &sMem);
    ++        if( rc!=SQLITE_OK ) goto abort_due_to_error;
    +         zData = (u8*)sMem.z;
    +       }else{
    +         zData = pC->aRow;
    +       }
    +   
    +       /* Fill in pC->aType[i] and aOffset[i] values through the p2-th field. */
    ++    op_column_read_header:
    +       i = pC->nHdrParsed;
    +-      offset = aOffset[i];
    ++      offset64 = aOffset[i];
    +       zHdr = zData + pC->iHdrOffset;
    +       zEndHdr = zData + aOffset[0];
    +-      assert( i<=p2 && zHdr<zEndHdr );
    ++      testcase( zHdr>=zEndHdr );
    +       do{
    +-        if( zHdr[0]<0x80 ){
    +-          t = zHdr[0];
    ++        if( (t = zHdr[0])<0x80 ){
    +           zHdr++;
    ++          offset64 += sqlite3VdbeOneByteSerialTypeLen(t);
    +         }else{
    +           zHdr += sqlite3GetVarint32(zHdr, &t);
    ++          offset64 += sqlite3VdbeSerialTypeLen(t);
    +         }
    +-        pC->aType[i] = t;
    +-        szField = sqlite3VdbeSerialTypeLen(t);
    +-        offset += szField;
    +-        if( offset<szField ){  /* True if offset overflows */
    +-          zHdr = &zEndHdr[1];  /* Forces SQLITE_CORRUPT return below */
    +-          break;
    +-        }
    +-        i++;
    +-        aOffset[i] = offset;
    ++        pC->aType[i++] = t;
    ++        aOffset[i] = (u32)(offset64 & 0xffffffff);
    +       }while( i<=p2 && zHdr<zEndHdr );
    +-      pC->nHdrParsed = i;
    +-      pC->iHdrOffset = (u32)(zHdr - zData);
    +-      if( pC->aRow==0 ){
    +-        sqlite3VdbeMemRelease(&sMem);
    +-        sMem.flags = MEM_Null;
    +-      }
    +-  
    ++
    +       /* The record is corrupt if any of the following are true:
    +       ** (1) the bytes of the header extend past the declared header size
    +-      **          (zHdr>zEndHdr)
    +       ** (2) the entire header was used but not all data was used
    +-      **          (zHdr==zEndHdr && offset!=pC->payloadSize)
    +       ** (3) the end of the data extends beyond the end of the record.
    +-      **          (offset > pC->payloadSize)
    +       */
    +-      if( (zHdr>=zEndHdr && (zHdr>zEndHdr || offset!=pC->payloadSize))
    +-       || (offset > pC->payloadSize)
    ++      if( (zHdr>=zEndHdr && (zHdr>zEndHdr || offset64!=pC->payloadSize))
    ++       || (offset64 > pC->payloadSize)
    +       ){
    +-        rc = SQLITE_CORRUPT_BKPT;
    +-        goto op_column_error;
    ++        if( aOffset[0]==0 ){
    ++          i = 0;
    ++          zHdr = zEndHdr;
    ++        }else{
    ++          if( pC->aRow==0 ) sqlite3VdbeMemRelease(&sMem);
    ++          goto op_column_corrupt;
    ++        }
    +       }
    ++
    ++      pC->nHdrParsed = i;
    ++      pC->iHdrOffset = (u32)(zHdr - zData);
    ++      if( pC->aRow==0 ) sqlite3VdbeMemRelease(&sMem);
    ++    }else{
    ++      t = 0;
    +     }
    + 
    +     /* If after trying to extract new entries from the header, nHdrParsed is
    +@@ -75443,6 +82567,8 @@ case OP_Column: {
    +       }
    +       goto op_column_out;
    +     }
    ++  }else{
    ++    t = pC->aType[p2];
    +   }
    + 
    +   /* Extract the content for the p2+1-th column.  Control can only
    +@@ -75452,13 +82578,37 @@ case OP_Column: {
    +   assert( p2<pC->nHdrParsed );
    +   assert( rc==SQLITE_OK );
    +   assert( sqlite3VdbeCheckMemInvariants(pDest) );
    +-  if( VdbeMemDynamic(pDest) ) sqlite3VdbeMemSetNull(pDest);
    +-  t = pC->aType[p2];
    ++  if( VdbeMemDynamic(pDest) ){
    ++    sqlite3VdbeMemSetNull(pDest);
    ++  }
    ++  assert( t==pC->aType[p2] );
    +   if( pC->szRow>=aOffset[p2+1] ){
    +     /* This is the common case where the desired content fits on the original
    +     ** page - where the content is not on an overflow page */
    +-    sqlite3VdbeSerialGet(pC->aRow+aOffset[p2], t, pDest);
    ++    zData = pC->aRow + aOffset[p2];
    ++    if( t<12 ){
    ++      sqlite3VdbeSerialGet(zData, t, pDest);
    ++    }else{
    ++      /* If the column value is a string, we need a persistent value, not
    ++      ** a MEM_Ephem value.  This branch is a fast short-cut that is equivalent
    ++      ** to calling sqlite3VdbeSerialGet() and sqlite3VdbeDeephemeralize().
    ++      */
    ++      static const u16 aFlag[] = { MEM_Blob, MEM_Str|MEM_Term };
    ++      pDest->n = len = (t-12)/2;
    ++      pDest->enc = encoding;
    ++      if( pDest->szMalloc < len+2 ){
    ++        pDest->flags = MEM_Null;
    ++        if( sqlite3VdbeMemGrow(pDest, len+2, 0) ) goto no_mem;
    ++      }else{
    ++        pDest->z = pDest->zMalloc;
    ++      }
    ++      memcpy(pDest->z, zData, len);
    ++      pDest->z[len] = 0;
    ++      pDest->z[len+1] = 0;
    ++      pDest->flags = aFlag[t&1];
    ++    }
    +   }else{
    ++    pDest->enc = encoding;
    +     /* This branch happens only when content is on overflow pages */
    +     if( ((pOp->p5 & (OPFLAG_LENGTHARG|OPFLAG_TYPEOFARG))!=0
    +           && ((t>=12 && (t&1)==0) || (pOp->p5 & OPFLAG_TYPEOFARG)!=0))
    +@@ -75469,42 +82619,35 @@ case OP_Column: {
    +       **    2. the length(X) function if X is a blob, and
    +       **    3. if the content length is zero.
    +       ** So we might as well use bogus content rather than reading
    +-      ** content from disk.  NULL will work for the value for strings
    +-      ** and blobs and whatever is in the payloadSize64 variable
    +-      ** will work for everything else. */
    +-      sqlite3VdbeSerialGet(t<=13 ? (u8*)&payloadSize64 : 0, t, pDest);
    ++      ** content from disk. 
    ++      **
    ++      ** Although sqlite3VdbeSerialGet() may read at most 8 bytes from the
    ++      ** buffer passed to it, debugging function VdbeMemPrettyPrint() may
    ++      ** read up to 16. So 16 bytes of bogus content is supplied.
    ++      */
    ++      static u8 aZero[16];  /* This is the bogus content */
    ++      sqlite3VdbeSerialGet(aZero, t, pDest);
    +     }else{
    +-      rc = sqlite3VdbeMemFromBtree(pCrsr, aOffset[p2], len, !pC->isTable,
    +-                                   pDest);
    +-      if( rc!=SQLITE_OK ){
    +-        goto op_column_error;
    +-      }
    ++      rc = sqlite3VdbeMemFromBtree(pC->uc.pCursor, aOffset[p2], len, pDest);
    ++      if( rc!=SQLITE_OK ) goto abort_due_to_error;
    +       sqlite3VdbeSerialGet((const u8*)pDest->z, t, pDest);
    +       pDest->flags &= ~MEM_Ephem;
    +     }
    +   }
    +-  pDest->enc = encoding;
    + 
    + op_column_out:
    +-  /* If the column value is an ephemeral string, go ahead and persist
    +-  ** that string in case the cursor moves before the column value is
    +-  ** used.  The following code does the equivalent of Deephemeralize()
    +-  ** but does it faster. */
    +-  if( (pDest->flags & MEM_Ephem)!=0 && pDest->z ){
    +-    fx = pDest->flags & (MEM_Str|MEM_Blob);
    +-    assert( fx!=0 );
    +-    zData = (const u8*)pDest->z;
    +-    len = pDest->n;
    +-    if( sqlite3VdbeMemClearAndResize(pDest, len+2) ) goto no_mem;
    +-    memcpy(pDest->z, zData, len);
    +-    pDest->z[len] = 0;
    +-    pDest->z[len+1] = 0;
    +-    pDest->flags = fx|MEM_Term;
    +-  }
    +-op_column_error:
    +   UPDATE_MAX_BLOBSIZE(pDest);
    +   REGISTER_TRACE(pOp->p3, pDest);
    +   break;
    ++
    ++op_column_corrupt:
    ++  if( aOp[0].p3>0 ){
    ++    pOp = &aOp[aOp[0].p3-1];
    ++    break;
    ++  }else{
    ++    rc = SQLITE_CORRUPT_BKPT;
    ++    goto abort_due_to_error;
    ++  }
    + }
    + 
    + /* Opcode: Affinity P1 P2 * P4 *
    +@@ -75512,24 +82655,24 @@ op_column_error:
    + **
    + ** Apply affinities to a range of P2 registers starting with P1.
    + **
    +-** P4 is a string that is P2 characters long. The nth character of the
    +-** string indicates the column affinity that should be used for the nth
    ++** P4 is a string that is P2 characters long. The N-th character of the
    ++** string indicates the column affinity that should be used for the N-th
    + ** memory cell in the range.
    + */
    + case OP_Affinity: {
    +   const char *zAffinity;   /* The affinity to be applied */
    +-  char cAff;               /* A single character of affinity */
    + 
    +   zAffinity = pOp->p4.z;
    +   assert( zAffinity!=0 );
    ++  assert( pOp->p2>0 );
    +   assert( zAffinity[pOp->p2]==0 );
    +   pIn1 = &aMem[pOp->p1];
    +-  while( (cAff = *(zAffinity++))!=0 ){
    +-    assert( pIn1 <= &p->aMem[(p->nMem-p->nCursor)] );
    ++  do{
    ++    assert( pIn1 <= &p->aMem[(p->nMem+1 - p->nCursor)] );
    +     assert( memIsValid(pIn1) );
    +-    applyAffinity(pIn1, cAff, encoding);
    ++    applyAffinity(pIn1, *(zAffinity++), encoding);
    +     pIn1++;
    +-  }
    ++  }while( zAffinity[0] );
    +   break;
    + }
    + 
    +@@ -75540,8 +82683,8 @@ case OP_Affinity: {
    + ** use as a data record in a database table or as a key
    + ** in an index.  The OP_Column opcode can decode the record later.
    + **
    +-** P4 may be a string that is P2 characters long.  The nth character of the
    +-** string indicates the column affinity that should be used for the nth
    ++** P4 may be a string that is P2 characters long.  The N-th character of the
    ++** string indicates the column affinity that should be used for the N-th
    + ** field of the index key.
    + **
    + ** The mapping from character to affinity is given by the SQLITE_AFF_
    +@@ -75565,7 +82708,7 @@ case OP_MakeRecord: {
    +   int file_format;       /* File format to use for encoding */
    +   int i;                 /* Space used in zNewRecord[] header */
    +   int j;                 /* Space used in zNewRecord[] content */
    +-  int len;               /* Length of a field */
    ++  u32 len;               /* Length of a field */
    + 
    +   /* Assuming the record contains N fields, the record format looks
    +   ** like this:
    +@@ -75587,7 +82730,7 @@ case OP_MakeRecord: {
    +   nZero = 0;         /* Number of zero bytes at the end of the record */
    +   nField = pOp->p1;
    +   zAffinity = pOp->p4.z;
    +-  assert( nField>0 && pOp->p2>0 && pOp->p2+nField<=(p->nMem-p->nCursor)+1 );
    ++  assert( nField>0 && pOp->p2>0 && pOp->p2+nField<=(p->nMem+1 - p->nCursor)+1 );
    +   pData0 = &aMem[nField];
    +   nField = pOp->p2;
    +   pLast = &pData0[nField-1];
    +@@ -75609,16 +82752,38 @@ case OP_MakeRecord: {
    +     }while( zAffinity[0] );
    +   }
    + 
    ++#ifdef SQLITE_ENABLE_NULL_TRIM
    ++  /* NULLs can be safely trimmed from the end of the record, as long as
    ++  ** as the schema format is 2 or more and none of the omitted columns
    ++  ** have a non-NULL default value.  Also, the record must be left with
    ++  ** at least one field.  If P5>0 then it will be one more than the
    ++  ** index of the right-most column with a non-NULL default value */
    ++  if( pOp->p5 ){
    ++    while( (pLast->flags & MEM_Null)!=0 && nField>pOp->p5 ){
    ++      pLast--;
    ++      nField--;
    ++    }
    ++  }
    ++#endif
    ++
    +   /* Loop through the elements that will make up the record to figure
    +   ** out how much space is required for the new record.
    +   */
    +   pRec = pLast;
    +   do{
    +     assert( memIsValid(pRec) );
    +-    pRec->uTemp = serial_type = sqlite3VdbeSerialType(pRec, file_format);
    +-    len = sqlite3VdbeSerialTypeLen(serial_type);
    ++    serial_type = sqlite3VdbeSerialType(pRec, file_format, &len);
    +     if( pRec->flags & MEM_Zero ){
    +-      if( nData ){
    ++      if( serial_type==0 ){
    ++        /* Values with MEM_Null and MEM_Zero are created by xColumn virtual
    ++        ** table methods that never invoke sqlite3_result_xxxxx() while
    ++        ** computing an unchanging column value in an UPDATE statement.
    ++        ** Give such values a special internal-use-only serial-type of 10
    ++        ** so that they can be passed through to xUpdate and have
    ++        ** a true sqlite3_value_nochange(). */
    ++        assert( pOp->p5==OPFLAG_NOCHNG_MAGIC || CORRUPT_DB );
    ++        serial_type = 10;
    ++      }else if( nData ){
    +         if( sqlite3VdbeMemExpandBlob(pRec) ) goto no_mem;
    +       }else{
    +         nZero += pRec->u.nZero;
    +@@ -75629,7 +82794,10 @@ case OP_MakeRecord: {
    +     testcase( serial_type==127 );
    +     testcase( serial_type==128 );
    +     nHdr += serial_type<=127 ? 1 : sqlite3VarintLen(serial_type);
    +-  }while( (--pRec)>=pData0 );
    ++    pRec->uTemp = serial_type;
    ++    if( pRec==pData0 ) break;
    ++    pRec--;
    ++  }while(1);
    + 
    +   /* EVIDENCE-OF: R-22564-11647 The header begins with a single varint
    +   ** which determines the total number of bytes in the header. The varint
    +@@ -75678,14 +82846,13 @@ case OP_MakeRecord: {
    +   assert( i==nHdr );
    +   assert( j==nByte );
    + 
    +-  assert( pOp->p3>0 && pOp->p3<=(p->nMem-p->nCursor) );
    ++  assert( pOp->p3>0 && pOp->p3<=(p->nMem+1 - p->nCursor) );
    +   pOut->n = (int)nByte;
    +   pOut->flags = MEM_Blob;
    +   if( nZero ){
    +     pOut->u.nZero = nZero;
    +     pOut->flags |= MEM_Zero;
    +   }
    +-  pOut->enc = SQLITE_UTF8;  /* In case the blob is ever converted to text */
    +   REGISTER_TRACE(pOp->p3, pOut);
    +   UPDATE_MAX_BLOBSIZE(pOut);
    +   break;
    +@@ -75702,10 +82869,12 @@ case OP_Count: {         /* out2 */
    +   i64 nEntry;
    +   BtCursor *pCrsr;
    + 
    +-  pCrsr = p->apCsr[pOp->p1]->pCursor;
    ++  assert( p->apCsr[pOp->p1]->eCurType==CURTYPE_BTREE );
    ++  pCrsr = p->apCsr[pOp->p1]->uc.pCursor;
    +   assert( pCrsr );
    +   nEntry = 0;  /* Not needed.  Only used to silence a warning. */
    +   rc = sqlite3BtreeCount(pCrsr, &nEntry);
    ++  if( rc ) goto abort_due_to_error;
    +   pOut = out2Prerelease(p, pOp);
    +   pOut->u.i = nEntry;
    +   break;
    +@@ -75762,7 +82931,7 @@ case OP_Savepoint: {
    + #endif
    + 
    +       /* Create a new savepoint structure. */
    +-      pNew = sqlite3DbMallocRaw(db, sizeof(Savepoint)+nName+1);
    ++      pNew = sqlite3DbMallocRawNN(db, sizeof(Savepoint)+nName+1);
    +       if( pNew ){
    +         pNew->zName = (char *)&pNew[1];
    +         memcpy(pNew->zName, zName, nName+1);
    +@@ -75775,7 +82944,7 @@ case OP_Savepoint: {
    +         }else{
    +           db->nSavepoint++;
    +         }
    +-    
    ++
    +         /* Link the new savepoint into the database handle's list. */
    +         pNew->pNext = db->pSavepoint;
    +         db->pSavepoint = pNew;
    +@@ -75829,7 +82998,7 @@ case OP_Savepoint: {
    +         int isSchemaChange;
    +         iSavepoint = db->nSavepoint - iSavepoint - 1;
    +         if( p1==SAVEPOINT_ROLLBACK ){
    +-          isSchemaChange = (db->flags & SQLITE_InternChanges)!=0;
    ++          isSchemaChange = (db->mDbFlags & DBFLAG_SchemaChange)!=0;
    +           for(ii=0; ii<db->nDb; ii++){
    +             rc = sqlite3BtreeTripAllCursors(db->aDb[ii].pBt,
    +                                        SQLITE_ABORT_ROLLBACK,
    +@@ -75848,7 +83017,7 @@ case OP_Savepoint: {
    +         if( isSchemaChange ){
    +           sqlite3ExpirePreparedStatements(db);
    +           sqlite3ResetAllSchemasOfConnection(db);
    +-          db->flags = (db->flags | SQLITE_InternChanges);
    ++          db->mDbFlags |= DBFLAG_SchemaChange;
    +         }
    +       }
    +   
    +@@ -75883,6 +83052,7 @@ case OP_Savepoint: {
    +       }
    +     }
    +   }
    ++  if( rc ) goto abort_due_to_error;
    + 
    +   break;
    + }
    +@@ -75899,28 +83069,27 @@ case OP_Savepoint: {
    + case OP_AutoCommit: {
    +   int desiredAutoCommit;
    +   int iRollback;
    +-  int turnOnAC;
    + 
    +   desiredAutoCommit = pOp->p1;
    +   iRollback = pOp->p2;
    +-  turnOnAC = desiredAutoCommit && !db->autoCommit;
    +   assert( desiredAutoCommit==1 || desiredAutoCommit==0 );
    +   assert( desiredAutoCommit==1 || iRollback==0 );
    +   assert( db->nVdbeActive>0 );  /* At least this one VM is active */
    +   assert( p->bIsReader );
    + 
    +-  if( turnOnAC && !iRollback && db->nVdbeWrite>0 ){
    +-    /* If this instruction implements a COMMIT and other VMs are writing
    +-    ** return an error indicating that the other VMs must complete first. 
    +-    */
    +-    sqlite3VdbeError(p, "cannot commit transaction - "
    +-                        "SQL statements in progress");
    +-    rc = SQLITE_BUSY;
    +-  }else if( desiredAutoCommit!=db->autoCommit ){
    ++  if( desiredAutoCommit!=db->autoCommit ){
    +     if( iRollback ){
    +       assert( desiredAutoCommit==1 );
    +       sqlite3RollbackAll(db, SQLITE_ABORT_ROLLBACK);
    +       db->autoCommit = 1;
    ++    }else if( desiredAutoCommit && db->nVdbeWrite>0 ){
    ++      /* If this instruction implements a COMMIT and other VMs are writing
    ++      ** return an error indicating that the other VMs must complete first. 
    ++      */
    ++      sqlite3VdbeError(p, "cannot commit transaction - "
    ++                          "SQL statements in progress");
    ++      rc = SQLITE_BUSY;
    ++      goto abort_due_to_error;
    +     }else if( (rc = sqlite3VdbeCheckFk(p, 1))!=SQLITE_OK ){
    +       goto vdbe_return;
    +     }else{
    +@@ -75947,6 +83116,7 @@ case OP_AutoCommit: {
    +                    "cannot commit - no transaction is active"));
    +          
    +     rc = SQLITE_ERROR;
    ++    goto abort_due_to_error;
    +   }
    +   break;
    + }
    +@@ -76004,12 +83174,12 @@ case OP_Transaction: {
    +     rc = sqlite3BtreeBeginTrans(pBt, pOp->p2);
    +     testcase( rc==SQLITE_BUSY_SNAPSHOT );
    +     testcase( rc==SQLITE_BUSY_RECOVERY );
    +-    if( (rc&0xff)==SQLITE_BUSY ){
    +-      p->pc = (int)(pOp - aOp);
    +-      p->rc = rc;
    +-      goto vdbe_return;
    +-    }
    +     if( rc!=SQLITE_OK ){
    ++      if( (rc&0xff)==SQLITE_BUSY ){
    ++        p->pc = (int)(pOp - aOp);
    ++        p->rc = rc;
    ++        goto vdbe_return;
    ++      }
    +       goto abort_due_to_error;
    +     }
    + 
    +@@ -76036,10 +83206,9 @@ case OP_Transaction: {
    +     }
    + 
    +     /* Gather the schema version number for checking:
    +-    ** IMPLEMENTATION-OF: R-32195-19465 The schema version is used by SQLite
    +-    ** each time a query is executed to ensure that the internal cache of the
    +-    ** schema used when compiling the SQL query matches the schema of the
    +-    ** database against which the compiled query is actually executed.
    ++    ** IMPLEMENTATION-OF: R-03189-51135 As each SQL statement runs, the schema
    ++    ** version is checked to ensure that the schema has not changed since the
    ++    ** SQL statement was prepared.
    +     */
    +     sqlite3BtreeGetMeta(pBt, BTREE_SCHEMA_VERSION, (u32 *)&iMeta);
    +     iGen = db->aDb[pOp->p1].pSchema->iGeneration;
    +@@ -76069,6 +83238,7 @@ case OP_Transaction: {
    +     p->expired = 1;
    +     rc = SQLITE_SCHEMA;
    +   }
    ++  if( rc ) goto abort_due_to_error;
    +   break;
    + }
    + 
    +@@ -76105,15 +83275,15 @@ case OP_ReadCookie: {               /* out2 */
    + 
    + /* Opcode: SetCookie P1 P2 P3 * *
    + **
    +-** Write the content of register P3 (interpreted as an integer)
    +-** into cookie number P2 of database P1.  P2==1 is the schema version.  
    +-** P2==2 is the database format. P2==3 is the recommended pager cache 
    ++** Write the integer value P3 into cookie number P2 of database P1.
    ++** P2==1 is the schema version.  P2==2 is the database format.
    ++** P2==3 is the recommended pager cache 
    + ** size, and so forth.  P1==0 is the main database file and P1==1 is the 
    + ** database file used to store temporary tables.
    + **
    + ** A transaction must be started before executing this opcode.
    + */
    +-case OP_SetCookie: {       /* in3 */
    ++case OP_SetCookie: {
    +   Db *pDb;
    +   assert( pOp->p2<SQLITE_N_BTREE_META );
    +   assert( pOp->p1>=0 && pOp->p1<db->nDb );
    +@@ -76122,17 +83292,15 @@ case OP_SetCookie: {       /* in3 */
    +   pDb = &db->aDb[pOp->p1];
    +   assert( pDb->pBt!=0 );
    +   assert( sqlite3SchemaMutexHeld(db, pOp->p1, 0) );
    +-  pIn3 = &aMem[pOp->p3];
    +-  sqlite3VdbeMemIntegerify(pIn3);
    +   /* See note about index shifting on OP_ReadCookie */
    +-  rc = sqlite3BtreeUpdateMeta(pDb->pBt, pOp->p2, (int)pIn3->u.i);
    ++  rc = sqlite3BtreeUpdateMeta(pDb->pBt, pOp->p2, pOp->p3);
    +   if( pOp->p2==BTREE_SCHEMA_VERSION ){
    +     /* When the schema cookie changes, record the new cookie internally */
    +-    pDb->pSchema->schema_cookie = (int)pIn3->u.i;
    +-    db->flags |= SQLITE_InternChanges;
    ++    pDb->pSchema->schema_cookie = pOp->p3;
    ++    db->mDbFlags |= DBFLAG_SchemaChange;
    +   }else if( pOp->p2==BTREE_FILE_FORMAT ){
    +     /* Record changes in the file format */
    +-    pDb->pSchema->file_format = (u8)pIn3->u.i;
    ++    pDb->pSchema->file_format = pOp->p3;
    +   }
    +   if( pOp->p1==1 ){
    +     /* Invalidate all prepared statements whenever the TEMP database
    +@@ -76140,6 +83308,7 @@ case OP_SetCookie: {       /* in3 */
    +     sqlite3ExpirePreparedStatements(db);
    +     p->expired = 0;
    +   }
    ++  if( rc ) goto abort_due_to_error;
    +   break;
    + }
    + 
    +@@ -76230,7 +83399,6 @@ case OP_ReopenIdx: {
    + case OP_OpenRead:
    + case OP_OpenWrite:
    + 
    +-  assert( (pOp->p5&(OPFLAG_P2ISREG|OPFLAG_BULKCSR|OPFLAG_SEEKEQ))==pOp->p5 );
    +   assert( pOp->opcode==OP_OpenWrite || pOp->p5==0 || pOp->p5==OPFLAG_SEEKEQ );
    +   assert( p->bIsReader );
    +   assert( pOp->opcode==OP_OpenRead || pOp->opcode==OP_ReopenIdx
    +@@ -76238,7 +83406,7 @@ case OP_OpenWrite:
    + 
    +   if( p->expired ){
    +     rc = SQLITE_ABORT_ROLLBACK;
    +-    break;
    ++    goto abort_due_to_error;
    +   }
    + 
    +   nField = 0;
    +@@ -76251,7 +83419,8 @@ case OP_OpenWrite:
    +   pX = pDb->pBt;
    +   assert( pX!=0 );
    +   if( pOp->opcode==OP_OpenWrite ){
    +-    wrFlag = 1;
    ++    assert( OPFLAG_FORDELETE==BTREE_FORDELETE );
    ++    wrFlag = BTREE_WRCSR | (pOp->p5 & OPFLAG_FORDELETE);
    +     assert( sqlite3SchemaMutexHeld(db, iDb, 0) );
    +     if( pDb->pSchema->file_format < p->minWriteFileFormat ){
    +       p->minWriteFileFormat = pDb->pSchema->file_format;
    +@@ -76261,38 +83430,38 @@ case OP_OpenWrite:
    +   }
    +   if( pOp->p5 & OPFLAG_P2ISREG ){
    +     assert( p2>0 );
    +-    assert( p2<=(p->nMem-p->nCursor) );
    ++    assert( p2<=(p->nMem+1 - p->nCursor) );
    +     pIn2 = &aMem[p2];
    +     assert( memIsValid(pIn2) );
    +     assert( (pIn2->flags & MEM_Int)!=0 );
    +     sqlite3VdbeMemIntegerify(pIn2);
    +     p2 = (int)pIn2->u.i;
    +-    /* The p2 value always comes from a prior OP_CreateTable opcode and
    ++    /* The p2 value always comes from a prior OP_CreateBtree opcode and
    +     ** that opcode will always set the p2 value to 2 or more or else fail.
    +     ** If there were a failure, the prepared statement would have halted
    +     ** before reaching this instruction. */
    +-    if( NEVER(p2<2) ) {
    +-      rc = SQLITE_CORRUPT_BKPT;
    +-      goto abort_due_to_error;
    +-    }
    ++    assert( p2>=2 );
    +   }
    +   if( pOp->p4type==P4_KEYINFO ){
    +     pKeyInfo = pOp->p4.pKeyInfo;
    +     assert( pKeyInfo->enc==ENC(db) );
    +     assert( pKeyInfo->db==db );
    +-    nField = pKeyInfo->nField+pKeyInfo->nXField;
    ++    nField = pKeyInfo->nAllField;
    +   }else if( pOp->p4type==P4_INT32 ){
    +     nField = pOp->p4.i;
    +   }
    +   assert( pOp->p1>=0 );
    +   assert( nField>=0 );
    +   testcase( nField==0 );  /* Table with INTEGER PRIMARY KEY and nothing else */
    +-  pCur = allocateCursor(p, pOp->p1, nField, iDb, 1);
    ++  pCur = allocateCursor(p, pOp->p1, nField, iDb, CURTYPE_BTREE);
    +   if( pCur==0 ) goto no_mem;
    +   pCur->nullRow = 1;
    +   pCur->isOrdered = 1;
    +   pCur->pgnoRoot = p2;
    +-  rc = sqlite3BtreeCursor(pX, p2, wrFlag, pKeyInfo, pCur->pCursor);
    ++#ifdef SQLITE_DEBUG
    ++  pCur->wrFlag = wrFlag;
    ++#endif
    ++  rc = sqlite3BtreeCursor(pX, p2, wrFlag, pKeyInfo, pCur->uc.pCursor);
    +   pCur->pKeyInfo = pKeyInfo;
    +   /* Set the VdbeCursor.isTable variable. Previous versions of
    +   ** SQLite used to check if the root-page flags were sane at this point
    +@@ -76303,11 +83472,47 @@ case OP_OpenWrite:
    + open_cursor_set_hints:
    +   assert( OPFLAG_BULKCSR==BTREE_BULKLOAD );
    +   assert( OPFLAG_SEEKEQ==BTREE_SEEK_EQ );
    +-  sqlite3BtreeCursorHints(pCur->pCursor,
    +-                          (pOp->p5 & (OPFLAG_BULKCSR|OPFLAG_SEEKEQ)));
    ++  testcase( pOp->p5 & OPFLAG_BULKCSR );
    ++#ifdef SQLITE_ENABLE_CURSOR_HINTS
    ++  testcase( pOp->p2 & OPFLAG_SEEKEQ );
    ++#endif
    ++  sqlite3BtreeCursorHintFlags(pCur->uc.pCursor,
    ++                               (pOp->p5 & (OPFLAG_BULKCSR|OPFLAG_SEEKEQ)));
    ++  if( rc ) goto abort_due_to_error;
    ++  break;
    ++}
    ++
    ++/* Opcode: OpenDup P1 P2 * * *
    ++**
    ++** Open a new cursor P1 that points to the same ephemeral table as
    ++** cursor P2.  The P2 cursor must have been opened by a prior OP_OpenEphemeral
    ++** opcode.  Only ephemeral cursors may be duplicated.
    ++**
    ++** Duplicate ephemeral cursors are used for self-joins of materialized views.
    ++*/
    ++case OP_OpenDup: {
    ++  VdbeCursor *pOrig;    /* The original cursor to be duplicated */
    ++  VdbeCursor *pCx;      /* The new cursor */
    ++
    ++  pOrig = p->apCsr[pOp->p2];
    ++  assert( pOrig->pBtx!=0 );  /* Only ephemeral cursors can be duplicated */
    ++
    ++  pCx = allocateCursor(p, pOp->p1, pOrig->nField, -1, CURTYPE_BTREE);
    ++  if( pCx==0 ) goto no_mem;
    ++  pCx->nullRow = 1;
    ++  pCx->isEphemeral = 1;
    ++  pCx->pKeyInfo = pOrig->pKeyInfo;
    ++  pCx->isTable = pOrig->isTable;
    ++  rc = sqlite3BtreeCursor(pOrig->pBtx, MASTER_ROOT, BTREE_WRCSR,
    ++                          pCx->pKeyInfo, pCx->uc.pCursor);
    ++  /* The sqlite3BtreeCursor() routine can only fail for the first cursor
    ++  ** opened for a database.  Since there is already an open cursor when this
    ++  ** opcode is run, the sqlite3BtreeCursor() cannot fail */
    ++  assert( rc==SQLITE_OK );
    +   break;
    + }
    + 
    ++
    + /* Opcode: OpenEphemeral P1 P2 * P4 P5
    + ** Synopsis: nColumn=P2
    + **
    +@@ -76347,14 +83552,14 @@ case OP_OpenEphemeral: {
    +       SQLITE_OPEN_TRANSIENT_DB;
    +   assert( pOp->p1>=0 );
    +   assert( pOp->p2>=0 );
    +-  pCx = allocateCursor(p, pOp->p1, pOp->p2, -1, 1);
    ++  pCx = allocateCursor(p, pOp->p1, pOp->p2, -1, CURTYPE_BTREE);
    +   if( pCx==0 ) goto no_mem;
    +   pCx->nullRow = 1;
    +   pCx->isEphemeral = 1;
    +-  rc = sqlite3BtreeOpen(db->pVfs, 0, db, &pCx->pBt, 
    ++  rc = sqlite3BtreeOpen(db->pVfs, 0, db, &pCx->pBtx, 
    +                         BTREE_OMIT_JOURNAL | BTREE_SINGLE | pOp->p5, vfsFlags);
    +   if( rc==SQLITE_OK ){
    +-    rc = sqlite3BtreeBeginTrans(pCx->pBt, 1);
    ++    rc = sqlite3BtreeBeginTrans(pCx->pBtx, 1);
    +   }
    +   if( rc==SQLITE_OK ){
    +     /* If a transient index is required, create it by calling
    +@@ -76362,23 +83567,25 @@ case OP_OpenEphemeral: {
    +     ** opening it. If a transient table is required, just use the
    +     ** automatically created table with root-page 1 (an BLOB_INTKEY table).
    +     */
    +-    if( (pKeyInfo = pOp->p4.pKeyInfo)!=0 ){
    ++    if( (pCx->pKeyInfo = pKeyInfo = pOp->p4.pKeyInfo)!=0 ){
    +       int pgno;
    +       assert( pOp->p4type==P4_KEYINFO );
    +-      rc = sqlite3BtreeCreateTable(pCx->pBt, &pgno, BTREE_BLOBKEY | pOp->p5); 
    ++      rc = sqlite3BtreeCreateTable(pCx->pBtx, &pgno, BTREE_BLOBKEY | pOp->p5); 
    +       if( rc==SQLITE_OK ){
    +         assert( pgno==MASTER_ROOT+1 );
    +         assert( pKeyInfo->db==db );
    +         assert( pKeyInfo->enc==ENC(db) );
    +-        pCx->pKeyInfo = pKeyInfo;
    +-        rc = sqlite3BtreeCursor(pCx->pBt, pgno, 1, pKeyInfo, pCx->pCursor);
    ++        rc = sqlite3BtreeCursor(pCx->pBtx, pgno, BTREE_WRCSR,
    ++                                pKeyInfo, pCx->uc.pCursor);
    +       }
    +       pCx->isTable = 0;
    +     }else{
    +-      rc = sqlite3BtreeCursor(pCx->pBt, MASTER_ROOT, 1, 0, pCx->pCursor);
    ++      rc = sqlite3BtreeCursor(pCx->pBtx, MASTER_ROOT, BTREE_WRCSR,
    ++                              0, pCx->uc.pCursor);
    +       pCx->isTable = 1;
    +     }
    +   }
    ++  if( rc ) goto abort_due_to_error;
    +   pCx->isOrdered = (pOp->p5!=BTREE_UNORDERED);
    +   break;
    + }
    +@@ -76398,12 +83605,13 @@ case OP_SorterOpen: {
    + 
    +   assert( pOp->p1>=0 );
    +   assert( pOp->p2>=0 );
    +-  pCx = allocateCursor(p, pOp->p1, pOp->p2, -1, 1);
    ++  pCx = allocateCursor(p, pOp->p1, pOp->p2, -1, CURTYPE_SORTER);
    +   if( pCx==0 ) goto no_mem;
    +   pCx->pKeyInfo = pOp->p4.pKeyInfo;
    +   assert( pCx->pKeyInfo->db==db );
    +   assert( pCx->pKeyInfo->enc==ENC(db) );
    +   rc = sqlite3VdbeSorterInit(db, pOp->p3, pCx);
    ++  if( rc ) goto abort_due_to_error;
    +   break;
    + }
    + 
    +@@ -76418,7 +83626,7 @@ case OP_SequenceTest: {
    +   VdbeCursor *pC;
    +   assert( pOp->p1>=0 && pOp->p1<p->nCursor );
    +   pC = p->apCsr[pOp->p1];
    +-  assert( pC->pSorter );
    ++  assert( isSorter(pC) );
    +   if( (pC->seqCount++)==0 ){
    +     goto jump_to_p2;
    +   }
    +@@ -76446,11 +83654,16 @@ case OP_OpenPseudo: {
    + 
    +   assert( pOp->p1>=0 );
    +   assert( pOp->p3>=0 );
    +-  pCx = allocateCursor(p, pOp->p1, pOp->p3, -1, 0);
    ++  pCx = allocateCursor(p, pOp->p1, pOp->p3, -1, CURTYPE_PSEUDO);
    +   if( pCx==0 ) goto no_mem;
    +   pCx->nullRow = 1;
    +-  pCx->pseudoTableReg = pOp->p2;
    ++  pCx->seekResult = pOp->p2;
    +   pCx->isTable = 1;
    ++  /* Give this pseudo-cursor a fake BtCursor pointer so that pCx
    ++  ** can be safely passed to sqlite3VdbeCursorMoveto().  This avoids a test
    ++  ** for pCx->eCurType==CURTYPE_BTREE inside of sqlite3VdbeCursorMoveto()
    ++  ** which is a performance optimization */
    ++  pCx->uc.pCursor = sqlite3BtreeFakeValidCursor();
    +   assert( pOp->p5==0 );
    +   break;
    + }
    +@@ -76481,7 +83694,7 @@ case OP_Close: {
    + case OP_ColumnsUsed: {
    +   VdbeCursor *pC;
    +   pC = p->apCsr[pOp->p1];
    +-  assert( pC->pCursor );
    ++  assert( pC->eCurType==CURTYPE_BTREE );
    +   pC->maskUsed = *(u64*)pOp->p4.pI64;
    +   break;
    + }
    +@@ -76499,6 +83712,13 @@ case OP_ColumnsUsed: {
    + ** 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.
    + **
    ++** If the cursor P1 was opened using the OPFLAG_SEEKEQ flag, then this
    ++** opcode will always land on a record that equally equals the key, or
    ++** else jump immediately to P2.  When the cursor is OPFLAG_SEEKEQ, this
    ++** opcode must be followed by an IdxLE opcode with the same arguments.
    ++** The IdxLE opcode will be skipped if this opcode succeeds, but the
    ++** IdxLE opcode will be used on subsequent loop iterations.
    ++**
    + ** 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.
    +@@ -76557,51 +83777,49 @@ case OP_ColumnsUsed: {
    + ** from the end toward the beginning.  In other words, the cursor is
    + ** configured to use Prev, not Next.
    + **
    ++** If the cursor P1 was opened using the OPFLAG_SEEKEQ flag, then this
    ++** opcode will always land on a record that equally equals the key, or
    ++** else jump immediately to P2.  When the cursor is OPFLAG_SEEKEQ, this
    ++** opcode must be followed by an IdxGE opcode with the same arguments.
    ++** The IdxGE opcode will be skipped if this opcode succeeds, but the
    ++** IdxGE opcode will be used on subsequent loop iterations.
    ++**
    + ** See also: Found, NotFound, SeekGt, SeekGe, SeekLt
    + */
    + case OP_SeekLT:         /* jump, in3 */
    + case OP_SeekLE:         /* jump, in3 */
    + case OP_SeekGE:         /* jump, in3 */
    + case OP_SeekGT: {       /* jump, in3 */
    +-  int res;
    +-  int oc;
    +-  VdbeCursor *pC;
    +-  UnpackedRecord r;
    +-  int nField;
    +-  i64 iKey;      /* The rowid we are to seek to */
    ++  int res;           /* Comparison result */
    ++  int oc;            /* Opcode */
    ++  VdbeCursor *pC;    /* The cursor to seek */
    ++  UnpackedRecord r;  /* The key to seek for */
    ++  int nField;        /* Number of columns or fields in the key */
    ++  i64 iKey;          /* The rowid we are to seek to */
    ++  int eqOnly;        /* Only interested in == results */
    + 
    +   assert( pOp->p1>=0 && pOp->p1<p->nCursor );
    +   assert( pOp->p2!=0 );
    +   pC = p->apCsr[pOp->p1];
    +   assert( pC!=0 );
    +-  assert( pC->pseudoTableReg==0 );
    ++  assert( pC->eCurType==CURTYPE_BTREE );
    +   assert( OP_SeekLE == OP_SeekLT+1 );
    +   assert( OP_SeekGE == OP_SeekLT+2 );
    +   assert( OP_SeekGT == OP_SeekLT+3 );
    +   assert( pC->isOrdered );
    +-  assert( pC->pCursor!=0 );
    ++  assert( pC->uc.pCursor!=0 );
    +   oc = pOp->opcode;
    ++  eqOnly = 0;
    +   pC->nullRow = 0;
    + #ifdef SQLITE_DEBUG
    +   pC->seekOp = pOp->opcode;
    + #endif
    + 
    +-  /* For a cursor with the BTREE_SEEK_EQ hint, only the OP_SeekGE and
    +-  ** OP_SeekLE opcodes are allowed, and these must be immediately followed
    +-  ** by an OP_IdxGT or OP_IdxLT opcode, respectively, with the same key.
    +-  */
    +-#ifdef SQLITE_DEBUG
    +-  if( sqlite3BtreeCursorHasHint(pC->pCursor, BTREE_SEEK_EQ) ){
    +-    assert( pOp->opcode==OP_SeekGE || pOp->opcode==OP_SeekLE );
    +-    assert( pOp[1].opcode==OP_IdxLT || pOp[1].opcode==OP_IdxGT );
    +-    assert( pOp[1].p1==pOp[0].p1 );
    +-    assert( pOp[1].p2==pOp[0].p2 );
    +-    assert( pOp[1].p3==pOp[0].p3 );
    +-    assert( pOp[1].p4.i==pOp[0].p4.i );
    +-  }
    +-#endif
    +- 
    +   if( pC->isTable ){
    ++    /* The BTREE_SEEK_EQ flag is only set on index cursors */
    ++    assert( sqlite3BtreeCursorHasHint(pC->uc.pCursor, BTREE_SEEK_EQ)==0
    ++              || CORRUPT_DB );
    ++
    +     /* 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 convert it. */
    +@@ -76644,12 +83862,26 @@ case OP_SeekGT: {       /* jump, in3 */
    +         if( (oc & 0x0001)==(OP_SeekLT & 0x0001) ) oc++;
    +       }
    +     } 
    +-    rc = sqlite3BtreeMovetoUnpacked(pC->pCursor, 0, (u64)iKey, 0, &res);
    ++    rc = sqlite3BtreeMovetoUnpacked(pC->uc.pCursor, 0, (u64)iKey, 0, &res);
    +     pC->movetoTarget = iKey;  /* Used by OP_Delete */
    +     if( rc!=SQLITE_OK ){
    +       goto abort_due_to_error;
    +     }
    +   }else{
    ++    /* For a cursor with the BTREE_SEEK_EQ hint, only the OP_SeekGE and
    ++    ** OP_SeekLE opcodes are allowed, and these must be immediately followed
    ++    ** by an OP_IdxGT or OP_IdxLT opcode, respectively, with the same key.
    ++    */
    ++    if( sqlite3BtreeCursorHasHint(pC->uc.pCursor, BTREE_SEEK_EQ) ){
    ++      eqOnly = 1;
    ++      assert( pOp->opcode==OP_SeekGE || pOp->opcode==OP_SeekLE );
    ++      assert( pOp[1].opcode==OP_IdxLT || pOp[1].opcode==OP_IdxGT );
    ++      assert( pOp[1].p1==pOp[0].p1 );
    ++      assert( pOp[1].p2==pOp[0].p2 );
    ++      assert( pOp[1].p3==pOp[0].p3 );
    ++      assert( pOp[1].p4.i==pOp[0].p4.i );
    ++    }
    ++
    +     nField = pOp->p4.i;
    +     assert( pOp->p4type==P4_INT32 );
    +     assert( nField>0 );
    +@@ -76673,11 +83905,15 @@ case OP_SeekGT: {       /* jump, in3 */
    + #ifdef SQLITE_DEBUG
    +     { int i; for(i=0; i<r.nField; i++) assert( memIsValid(&r.aMem[i]) ); }
    + #endif
    +-    ExpandBlob(r.aMem);
    +-    rc = sqlite3BtreeMovetoUnpacked(pC->pCursor, &r, 0, 0, &res);
    ++    r.eqSeen = 0;
    ++    rc = sqlite3BtreeMovetoUnpacked(pC->uc.pCursor, &r, 0, 0, &res);
    +     if( rc!=SQLITE_OK ){
    +       goto abort_due_to_error;
    +     }
    ++    if( eqOnly && r.eqSeen==0 ){
    ++      assert( res!=0 );
    ++      goto seek_not_found;
    ++    }
    +   }
    +   pC->deferredMoveto = 0;
    +   pC->cacheStatus = CACHE_STALE;
    +@@ -76687,8 +83923,15 @@ case OP_SeekGT: {       /* jump, in3 */
    +   if( oc>=OP_SeekGE ){  assert( oc==OP_SeekGE || oc==OP_SeekGT );
    +     if( res<0 || (res==0 && oc==OP_SeekGT) ){
    +       res = 0;
    +-      rc = sqlite3BtreeNext(pC->pCursor, &res);
    +-      if( rc!=SQLITE_OK ) goto abort_due_to_error;
    ++      rc = sqlite3BtreeNext(pC->uc.pCursor, 0);
    ++      if( rc!=SQLITE_OK ){
    ++        if( rc==SQLITE_DONE ){
    ++          rc = SQLITE_OK;
    ++          res = 1;
    ++        }else{
    ++          goto abort_due_to_error;
    ++        }
    ++      }
    +     }else{
    +       res = 0;
    +     }
    +@@ -76696,49 +83939,34 @@ case OP_SeekGT: {       /* jump, in3 */
    +     assert( oc==OP_SeekLT || oc==OP_SeekLE );
    +     if( res>0 || (res==0 && oc==OP_SeekLT) ){
    +       res = 0;
    +-      rc = sqlite3BtreePrevious(pC->pCursor, &res);
    +-      if( rc!=SQLITE_OK ) goto abort_due_to_error;
    ++      rc = sqlite3BtreePrevious(pC->uc.pCursor, 0);
    ++      if( rc!=SQLITE_OK ){
    ++        if( rc==SQLITE_DONE ){
    ++          rc = SQLITE_OK;
    ++          res = 1;
    ++        }else{
    ++          goto abort_due_to_error;
    ++        }
    ++      }
    +     }else{
    +       /* res might be negative because the table is empty.  Check to
    +       ** see if this is the case.
    +       */
    +-      res = sqlite3BtreeEof(pC->pCursor);
    ++      res = sqlite3BtreeEof(pC->uc.pCursor);
    +     }
    +   }
    ++seek_not_found:
    +   assert( pOp->p2>0 );
    +   VdbeBranchTaken(res!=0,2);
    +   if( res ){
    +     goto jump_to_p2;
    ++  }else if( eqOnly ){
    ++    assert( pOp[1].opcode==OP_IdxLT || pOp[1].opcode==OP_IdxGT );
    ++    pOp++; /* Skip the OP_IdxLt or OP_IdxGT that follows */
    +   }
    +   break;
    + }
    + 
    +-/* Opcode: Seek P1 P2 * * *
    +-** Synopsis:  intkey=r[P2]
    +-**
    +-** P1 is an open table cursor and P2 is a rowid integer.  Arrange
    +-** for P1 to move so that it points to the rowid given by P2.
    +-**
    +-** This is actually a deferred seek.  Nothing actually happens until
    +-** the cursor is used to read a record.  That way, if no reads
    +-** occur, no unnecessary I/O happens.
    +-*/
    +-case OP_Seek: {    /* in2 */
    +-  VdbeCursor *pC;
    +-
    +-  assert( pOp->p1>=0 && pOp->p1<p->nCursor );
    +-  pC = p->apCsr[pOp->p1];
    +-  assert( pC!=0 );
    +-  assert( pC->pCursor!=0 );
    +-  assert( pC->isTable );
    +-  pC->nullRow = 0;
    +-  pIn2 = &aMem[pOp->p2];
    +-  pC->movetoTarget = sqlite3VdbeIntValue(pIn2);
    +-  pC->deferredMoveto = 1;
    +-  break;
    +-}
    +-  
    +-
    + /* Opcode: Found P1 P2 P3 P4 *
    + ** Synopsis: key=r[P3@P4]
    + **
    +@@ -76806,10 +84034,9 @@ case OP_Found: {        /* jump, in3 */
    +   int ii;
    +   VdbeCursor *pC;
    +   int res;
    +-  char *pFree;
    ++  UnpackedRecord *pFree;
    +   UnpackedRecord *pIdxKey;
    +   UnpackedRecord r;
    +-  char aTempRec[ROUND8(sizeof(UnpackedRecord)) + sizeof(Mem)*4 + 7];
    + 
    + #ifdef SQLITE_TEST
    +   if( pOp->opcode!=OP_NoConflict ) sqlite3_found_count++;
    +@@ -76823,28 +84050,29 @@ case OP_Found: {        /* jump, in3 */
    +   pC->seekOp = pOp->opcode;
    + #endif
    +   pIn3 = &aMem[pOp->p3];
    +-  assert( pC->pCursor!=0 );
    ++  assert( pC->eCurType==CURTYPE_BTREE );
    ++  assert( pC->uc.pCursor!=0 );
    +   assert( pC->isTable==0 );
    +-  pFree = 0;
    +   if( pOp->p4.i>0 ){
    +     r.pKeyInfo = pC->pKeyInfo;
    +     r.nField = (u16)pOp->p4.i;
    +     r.aMem = pIn3;
    ++#ifdef SQLITE_DEBUG
    +     for(ii=0; ii<r.nField; ii++){
    +       assert( memIsValid(&r.aMem[ii]) );
    +-      ExpandBlob(&r.aMem[ii]);
    +-#ifdef SQLITE_DEBUG
    ++      assert( (r.aMem[ii].flags & MEM_Zero)==0 || r.aMem[ii].n==0 );
    +       if( ii ) REGISTER_TRACE(pOp->p3+ii, &r.aMem[ii]);
    +-#endif
    +     }
    ++#endif
    +     pIdxKey = &r;
    ++    pFree = 0;
    +   }else{
    +-    pIdxKey = sqlite3VdbeAllocUnpackedRecord(
    +-        pC->pKeyInfo, aTempRec, sizeof(aTempRec), &pFree
    +-    );
    +-    if( pIdxKey==0 ) goto no_mem;
    +     assert( pIn3->flags & MEM_Blob );
    +-    ExpandBlob(pIn3);
    ++    rc = ExpandBlob(pIn3);
    ++    assert( rc==SQLITE_OK || rc==SQLITE_NOMEM );
    ++    if( rc ) goto no_mem;
    ++    pFree = pIdxKey = sqlite3VdbeAllocUnpackedRecord(pC->pKeyInfo);
    ++    if( pIdxKey==0 ) goto no_mem;
    +     sqlite3VdbeRecordUnpack(pC->pKeyInfo, pIn3->n, pIn3->z, pIdxKey);
    +   }
    +   pIdxKey->default_rc = 0;
    +@@ -76860,10 +84088,10 @@ case OP_Found: {        /* jump, in3 */
    +       }
    +     }
    +   }
    +-  rc = sqlite3BtreeMovetoUnpacked(pC->pCursor, pIdxKey, 0, 0, &res);
    +-  sqlite3DbFree(db, pFree);
    ++  rc = sqlite3BtreeMovetoUnpacked(pC->uc.pCursor, pIdxKey, 0, 0, &res);
    ++  if( pFree ) sqlite3DbFreeNN(db, pFree);
    +   if( rc!=SQLITE_OK ){
    +-    break;
    ++    goto abort_due_to_error;
    +   }
    +   pC->seekResult = res;
    +   alreadyExists = (res==0);
    +@@ -76880,6 +84108,30 @@ case OP_Found: {        /* jump, in3 */
    +   break;
    + }
    + 
    ++/* Opcode: SeekRowid P1 P2 P3 * *
    ++** Synopsis: intkey=r[P3]
    ++**
    ++** P1 is the index of a cursor open on an SQL table btree (with integer
    ++** keys).  If register P3 does not contain an integer or if P1 does not
    ++** contain a record with rowid P3 then jump immediately to P2.  
    ++** Or, if P2 is 0, raise an SQLITE_CORRUPT error. If P1 does contain
    ++** a record with rowid P3 then 
    ++** leave the cursor pointing at that record and fall through to the next
    ++** instruction.
    ++**
    ++** The OP_NotExists opcode performs the same operation, but with OP_NotExists
    ++** the P3 register must be guaranteed to contain an integer value.  With this
    ++** opcode, register P3 might not contain an integer.
    ++**
    ++** 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, SeekRowid
    ++*/
    + /* Opcode: NotExists P1 P2 P3 * *
    + ** Synopsis: intkey=r[P3]
    + **
    +@@ -76890,6 +84142,10 @@ case OP_Found: {        /* jump, in3 */
    + ** leave the cursor pointing at that record and fall through to the next
    + ** instruction.
    + **
    ++** The OP_SeekRowid opcode performs the same operation but also allows the
    ++** P3 register to contain a non-integer value, in which case the jump is
    ++** always taken.  This opcode requires that P3 always contain an integer.
    ++**
    + ** The OP_NotFound opcode performs the same operation on index btrees
    + ** (with arbitrary multi-value keys).
    + **
    +@@ -76897,14 +84153,21 @@ case OP_Found: {        /* jump, in3 */
    + ** in either direction.  In other words, the Next and Prev opcodes will
    + ** not work following this opcode.
    + **
    +-** See also: Found, NotFound, NoConflict
    ++** See also: Found, NotFound, NoConflict, SeekRowid
    + */
    +-case OP_NotExists: {        /* jump, in3 */
    ++case OP_SeekRowid: {        /* jump, in3 */
    +   VdbeCursor *pC;
    +   BtCursor *pCrsr;
    +   int res;
    +   u64 iKey;
    + 
    ++  pIn3 = &aMem[pOp->p3];
    ++  if( (pIn3->flags & MEM_Int)==0 ){
    ++    applyAffinity(pIn3, SQLITE_AFF_NUMERIC, encoding);
    ++    if( (pIn3->flags & MEM_Int)==0 ) goto jump_to_p2;
    ++  }
    ++  /* Fall through into OP_NotExists */
    ++case OP_NotExists:          /* jump, in3 */
    +   pIn3 = &aMem[pOp->p3];
    +   assert( pIn3->flags & MEM_Int );
    +   assert( pOp->p1>=0 && pOp->p1<p->nCursor );
    +@@ -76914,8 +84177,8 @@ case OP_NotExists: {        /* jump, in3 */
    +   pC->seekOp = 0;
    + #endif
    +   assert( pC->isTable );
    +-  assert( pC->pseudoTableReg==0 );
    +-  pCrsr = pC->pCursor;
    ++  assert( pC->eCurType==CURTYPE_BTREE );
    ++  pCrsr = pC->uc.pCursor;
    +   assert( pCrsr!=0 );
    +   res = 0;
    +   iKey = pIn3->u.i;
    +@@ -76935,6 +84198,7 @@ case OP_NotExists: {        /* jump, in3 */
    +       goto jump_to_p2;
    +     }
    +   }
    ++  if( rc ) goto abort_due_to_error;
    +   break;
    + }
    + 
    +@@ -76949,6 +84213,7 @@ case OP_NotExists: {        /* jump, in3 */
    + case OP_Sequence: {           /* out2 */
    +   assert( pOp->p1>=0 && pOp->p1<p->nCursor );
    +   assert( p->apCsr[pOp->p1]!=0 );
    ++  assert( p->apCsr[pOp->p1]->eCurType!=CURTYPE_VTAB );
    +   pOut = out2Prerelease(p, pOp);
    +   pOut->u.i = p->apCsr[pOp->p1]->seqCount++;
    +   break;
    +@@ -76984,7 +84249,8 @@ case OP_NewRowid: {           /* out2 */
    +   assert( pOp->p1>=0 && pOp->p1<p->nCursor );
    +   pC = p->apCsr[pOp->p1];
    +   assert( pC!=0 );
    +-  assert( pC->pCursor!=0 );
    ++  assert( pC->eCurType==CURTYPE_BTREE );
    ++  assert( pC->uc.pCursor!=0 );
    +   {
    +     /* The next rowid or record number (different terms for the same
    +     ** thing) is obtained in a two-step algorithm.
    +@@ -77012,16 +84278,15 @@ case OP_NewRowid: {           /* out2 */
    + #endif
    + 
    +     if( !pC->useRandomRowid ){
    +-      rc = sqlite3BtreeLast(pC->pCursor, &res);
    ++      rc = sqlite3BtreeLast(pC->uc.pCursor, &res);
    +       if( rc!=SQLITE_OK ){
    +         goto abort_due_to_error;
    +       }
    +       if( res ){
    +         v = 1;   /* IMP: R-61914-48074 */
    +       }else{
    +-        assert( sqlite3BtreeCursorIsValid(pC->pCursor) );
    +-        rc = sqlite3BtreeKeySize(pC->pCursor, &v);
    +-        assert( rc==SQLITE_OK );   /* Cannot fail following BtreeLast() */
    ++        assert( sqlite3BtreeCursorIsValid(pC->uc.pCursor) );
    ++        v = sqlite3BtreeIntegerKey(pC->uc.pCursor);
    +         if( v>=MAX_ROWID ){
    +           pC->useRandomRowid = 1;
    +         }else{
    +@@ -77041,7 +84306,7 @@ case OP_NewRowid: {           /* out2 */
    +         pMem = &pFrame->aMem[pOp->p3];
    +       }else{
    +         /* Assert that P3 is a valid memory cell. */
    +-        assert( pOp->p3<=(p->nMem-p->nCursor) );
    ++        assert( pOp->p3<=(p->nMem+1 - p->nCursor) );
    +         pMem = &aMem[pOp->p3];
    +         memAboutToChange(p, pMem);
    +       }
    +@@ -77051,7 +84316,7 @@ case OP_NewRowid: {           /* out2 */
    +       sqlite3VdbeMemIntegerify(pMem);
    +       assert( (pMem->flags & MEM_Int)!=0 );  /* mem(P3) holds an integer */
    +       if( pMem->u.i==MAX_ROWID || pC->useRandomRowid ){
    +-        rc = SQLITE_FULL;   /* IMP: R-12275-61338 */
    ++        rc = SQLITE_FULL;   /* IMP: R-17817-00630 */
    +         goto abort_due_to_error;
    +       }
    +       if( v<pMem->u.i+1 ){
    +@@ -77071,11 +84336,12 @@ case OP_NewRowid: {           /* out2 */
    +       do{
    +         sqlite3_randomness(sizeof(v), &v);
    +         v &= (MAX_ROWID>>1); v++;  /* Ensure that v is greater than zero */
    +-      }while(  ((rc = sqlite3BtreeMovetoUnpacked(pC->pCursor, 0, (u64)v,
    ++      }while(  ((rc = sqlite3BtreeMovetoUnpacked(pC->uc.pCursor, 0, (u64)v,
    +                                                  0, &res))==SQLITE_OK)
    +             && (res==0)
    +             && (++cnt<100));
    +-      if( rc==SQLITE_OK && res==0 ){
    ++      if( rc ) goto abort_due_to_error;
    ++      if( res==0 ){
    +         rc = SQLITE_FULL;   /* IMP: R-38219-53002 */
    +         goto abort_due_to_error;
    +       }
    +@@ -77102,22 +84368,19 @@ case OP_NewRowid: {           /* out2 */
    + ** then rowid is stored for subsequent return by the
    + ** sqlite3_last_insert_rowid() function (otherwise it is unmodified).
    + **
    +-** If the OPFLAG_USESEEKRESULT flag of P5 is set and if the result of
    +-** the last seek operation (OP_NotExists) was a success, then this
    +-** operation will not attempt to find the appropriate row before doing
    +-** the insert but will instead overwrite the row that the cursor is
    +-** currently pointing to.  Presumably, the prior OP_NotExists opcode
    +-** has already positioned the cursor correctly.  This is an optimization
    +-** that boosts performance by avoiding redundant seeks.
    ++** If the OPFLAG_USESEEKRESULT flag of P5 is set, the implementation might
    ++** run faster by avoiding an unnecessary seek on cursor P1.  However,
    ++** the OPFLAG_USESEEKRESULT flag must only be set if there have been no prior
    ++** seeks on the cursor or if the most recent seek used a key equal to P3.
    + **
    + ** If the OPFLAG_ISUPDATE flag is set, then this opcode is part of an
    + ** UPDATE operation.  Otherwise (if the flag is clear) then this opcode
    + ** is part of an INSERT operation.  The difference is only important to
    + ** the update hook.
    + **
    +-** Parameter P4 may point to a string containing the table-name, or
    +-** may be NULL. If it is not NULL, then the update-hook 
    +-** (sqlite3.xUpdateCallback) is invoked following a successful insert.
    ++** Parameter P4 may point to a Table structure, or may be NULL. If it is 
    ++** not NULL, then the update-hook (sqlite3.xUpdateCallback) is invoked 
    ++** following a successful insert.
    + **
    + ** (WARNING/TODO: If P1 is a pseudo-cursor and P2 is dynamically
    + ** allocated, then ownership of P2 is transferred to the pseudo-cursor
    +@@ -77129,7 +84392,7 @@ case OP_NewRowid: {           /* out2 */
    + ** for indices is OP_IdxInsert.
    + */
    + /* Opcode: InsertInt P1 P2 P3 P4 P5
    +-** Synopsis:  intkey=P3 data=r[P2]
    ++** Synopsis: intkey=P3 data=r[P2]
    + **
    + ** This works exactly like OP_Insert except that the key is the
    + ** integer value P3, not the value of the integer stored in register P3.
    +@@ -77138,22 +84401,21 @@ case OP_Insert:
    + case OP_InsertInt: {
    +   Mem *pData;       /* MEM cell holding data for the record to be inserted */
    +   Mem *pKey;        /* MEM cell holding key  for the record */
    +-  i64 iKey;         /* The integer ROWID or key for the record to be inserted */
    +   VdbeCursor *pC;   /* Cursor to table into which insert is written */
    +-  int nZero;        /* Number of zero-bytes to append */
    +   int seekResult;   /* Result of prior seek or 0 if no USESEEKRESULT flag */
    +   const char *zDb;  /* database name - used by the update hook */
    +-  const char *zTbl; /* Table name - used by the opdate hook */
    +-  int op;           /* Opcode for update hook: SQLITE_UPDATE or SQLITE_INSERT */
    ++  Table *pTab;      /* Table structure - used by update and pre-update hooks */
    ++  BtreePayload x;   /* Payload to be inserted */
    + 
    +   pData = &aMem[pOp->p2];
    +   assert( pOp->p1>=0 && pOp->p1<p->nCursor );
    +   assert( memIsValid(pData) );
    +   pC = p->apCsr[pOp->p1];
    +   assert( pC!=0 );
    +-  assert( pC->pCursor!=0 );
    +-  assert( pC->pseudoTableReg==0 );
    +-  assert( pC->isTable );
    ++  assert( pC->eCurType==CURTYPE_BTREE );
    ++  assert( pC->uc.pCursor!=0 );
    ++  assert( (pOp->p5 & OPFLAG_ISNOOP) || pC->isTable );
    ++  assert( pOp->p4type==P4_TABLE || pOp->p4type>=P4_STATIC );
    +   REGISTER_TRACE(pOp->p2, pData);
    + 
    +   if( pOp->opcode==OP_Insert ){
    +@@ -77161,102 +84423,193 @@ case OP_InsertInt: {
    +     assert( pKey->flags & MEM_Int );
    +     assert( memIsValid(pKey) );
    +     REGISTER_TRACE(pOp->p3, pKey);
    +-    iKey = pKey->u.i;
    ++    x.nKey = pKey->u.i;
    +   }else{
    +     assert( pOp->opcode==OP_InsertInt );
    +-    iKey = pOp->p3;
    ++    x.nKey = pOp->p3;
    +   }
    + 
    +-  if( pOp->p5 & OPFLAG_NCHANGE ) p->nChange++;
    +-  if( pOp->p5 & OPFLAG_LASTROWID ) db->lastRowid = lastRowid = iKey;
    +-  if( pData->flags & MEM_Null ){
    +-    pData->z = 0;
    +-    pData->n = 0;
    ++  if( pOp->p4type==P4_TABLE && HAS_UPDATE_HOOK(db) ){
    ++    assert( pC->iDb>=0 );
    ++    zDb = db->aDb[pC->iDb].zDbSName;
    ++    pTab = pOp->p4.pTab;
    ++    assert( (pOp->p5 & OPFLAG_ISNOOP) || HasRowid(pTab) );
    +   }else{
    +-    assert( pData->flags & (MEM_Blob|MEM_Str) );
    ++    pTab = 0;
    ++    zDb = 0;  /* Not needed.  Silence a compiler warning. */
    ++  }
    ++
    ++#ifdef SQLITE_ENABLE_PREUPDATE_HOOK
    ++  /* Invoke the pre-update hook, if any */
    ++  if( pTab ){
    ++    if( db->xPreUpdateCallback && !(pOp->p5 & OPFLAG_ISUPDATE) ){
    ++      sqlite3VdbePreUpdateHook(p, pC, SQLITE_INSERT, zDb, pTab, x.nKey,pOp->p2);
    ++    }
    ++    if( db->xUpdateCallback==0 || pTab->aCol==0 ){
    ++      /* Prevent post-update hook from running in cases when it should not */
    ++      pTab = 0;
    ++    }
    +   }
    ++  if( pOp->p5 & OPFLAG_ISNOOP ) break;
    ++#endif
    ++
    ++  if( pOp->p5 & OPFLAG_NCHANGE ) p->nChange++;
    ++  if( pOp->p5 & OPFLAG_LASTROWID ) db->lastRowid = x.nKey;
    ++  assert( pData->flags & (MEM_Blob|MEM_Str) );
    ++  x.pData = pData->z;
    ++  x.nData = pData->n;
    +   seekResult = ((pOp->p5 & OPFLAG_USESEEKRESULT) ? pC->seekResult : 0);
    +   if( pData->flags & MEM_Zero ){
    +-    nZero = pData->u.nZero;
    ++    x.nZero = pData->u.nZero;
    +   }else{
    +-    nZero = 0;
    ++    x.nZero = 0;
    +   }
    +-  rc = sqlite3BtreeInsert(pC->pCursor, 0, iKey,
    +-                          pData->z, pData->n, nZero,
    +-                          (pOp->p5 & OPFLAG_APPEND)!=0, seekResult
    ++  x.pKey = 0;
    ++  rc = sqlite3BtreeInsert(pC->uc.pCursor, &x,
    ++      (pOp->p5 & (OPFLAG_APPEND|OPFLAG_SAVEPOSITION)), seekResult
    +   );
    +   pC->deferredMoveto = 0;
    +   pC->cacheStatus = CACHE_STALE;
    + 
    +   /* Invoke the update-hook if required. */
    +-  if( rc==SQLITE_OK && db->xUpdateCallback && pOp->p4.z ){
    +-    zDb = db->aDb[pC->iDb].zName;
    +-    zTbl = pOp->p4.z;
    +-    op = ((pOp->p5 & OPFLAG_ISUPDATE) ? SQLITE_UPDATE : SQLITE_INSERT);
    +-    assert( pC->isTable );
    +-    db->xUpdateCallback(db->pUpdateArg, op, zDb, zTbl, iKey);
    +-    assert( pC->iDb>=0 );
    ++  if( rc ) goto abort_due_to_error;
    ++  if( pTab ){
    ++    assert( db->xUpdateCallback!=0 );
    ++    assert( pTab->aCol!=0 );
    ++    db->xUpdateCallback(db->pUpdateArg,
    ++           (pOp->p5 & OPFLAG_ISUPDATE) ? SQLITE_UPDATE : SQLITE_INSERT,
    ++           zDb, pTab->zName, x.nKey);
    +   }
    +   break;
    + }
    + 
    +-/* Opcode: Delete P1 P2 * P4 P5
    ++/* Opcode: Delete P1 P2 P3 P4 P5
    + **
    + ** Delete the record at which the P1 cursor is currently pointing.
    + **
    +-** If the P5 parameter is non-zero, 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. As a result, in this case it is OK to delete a record from within a
    +-** Next loop. If P5 is zero, then the cursor is left in an undefined state.
    ++** If the OPFLAG_SAVEPOSITION bit of the P5 parameter is set, then
    ++** 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. As a result, in this case
    ++** it is ok to delete a record from within a Next loop. If 
    ++** OPFLAG_SAVEPOSITION bit of P5 is clear, then the cursor will be
    ++** left in an undefined state.
    ++**
    ++** If the OPFLAG_AUXDELETE bit is set on P5, that indicates that this
    ++** delete one of several associated with deleting a table row and all its
    ++** associated index entries.  Exactly one of those deletes is the "primary"
    ++** delete.  The others are all on OPFLAG_FORDELETE cursors or else are
    ++** marked with the AUXDELETE flag.
    + **
    +-** If the OPFLAG_NCHANGE flag of P2 is set, then the row change count is
    +-** incremented (otherwise not).
    ++** If the OPFLAG_NCHANGE flag of P2 (NB: P2 not P5) is set, then the row
    ++** change count is incremented (otherwise not).
    + **
    + ** P1 must not be pseudo-table.  It has to be a real table with
    + ** multiple rows.
    + **
    +-** If P4 is not NULL, then it is the name of the table that P1 is
    +-** pointing to.  The update hook will be invoked, if it exists.
    +-** If P4 is not NULL then the P1 cursor must have been positioned
    +-** using OP_NotFound prior to invoking this opcode.
    ++** If P4 is not NULL then it points to a Table object. In this case either 
    ++** the update or pre-update hook, or both, may be invoked. The P1 cursor must
    ++** have been positioned using OP_NotFound prior to invoking this opcode in 
    ++** this case. Specifically, if one is configured, the pre-update hook is 
    ++** invoked if P4 is not NULL. The update-hook is invoked if one is configured, 
    ++** P4 is not NULL, and the OPFLAG_NCHANGE flag is set in P2.
    ++**
    ++** If the OPFLAG_ISUPDATE flag is set in P2, then P3 contains the address
    ++** of the memory cell that contains the value that the rowid of the row will
    ++** be set to by the update.
    + */
    + case OP_Delete: {
    +   VdbeCursor *pC;
    +-  u8 hasUpdateCallback;
    ++  const char *zDb;
    ++  Table *pTab;
    ++  int opflags;
    + 
    ++  opflags = pOp->p2;
    +   assert( pOp->p1>=0 && pOp->p1<p->nCursor );
    +   pC = p->apCsr[pOp->p1];
    +   assert( pC!=0 );
    +-  assert( pC->pCursor!=0 );  /* Only valid for real tables, no pseudotables */
    ++  assert( pC->eCurType==CURTYPE_BTREE );
    ++  assert( pC->uc.pCursor!=0 );
    +   assert( pC->deferredMoveto==0 );
    + 
    +-  hasUpdateCallback = db->xUpdateCallback && pOp->p4.z && pC->isTable;
    +-  if( pOp->p5 && hasUpdateCallback ){
    +-    sqlite3BtreeKeySize(pC->pCursor, &pC->movetoTarget);
    ++#ifdef SQLITE_DEBUG
    ++  if( pOp->p4type==P4_TABLE && HasRowid(pOp->p4.pTab) && pOp->p5==0 ){
    ++    /* If p5 is zero, the seek operation that positioned the cursor prior to
    ++    ** OP_Delete will have also set the pC->movetoTarget field to the rowid of
    ++    ** the row that is being deleted */
    ++    i64 iKey = sqlite3BtreeIntegerKey(pC->uc.pCursor);
    ++    assert( pC->movetoTarget==iKey );
    ++  }
    ++#endif
    ++
    ++  /* If the update-hook or pre-update-hook will be invoked, set zDb to
    ++  ** the name of the db to pass as to it. Also set local pTab to a copy
    ++  ** of p4.pTab. Finally, if p5 is true, indicating that this cursor was
    ++  ** last moved with OP_Next or OP_Prev, not Seek or NotFound, set 
    ++  ** VdbeCursor.movetoTarget to the current rowid.  */
    ++  if( pOp->p4type==P4_TABLE && HAS_UPDATE_HOOK(db) ){
    ++    assert( pC->iDb>=0 );
    ++    assert( pOp->p4.pTab!=0 );
    ++    zDb = db->aDb[pC->iDb].zDbSName;
    ++    pTab = pOp->p4.pTab;
    ++    if( (pOp->p5 & OPFLAG_SAVEPOSITION)!=0 && pC->isTable ){
    ++      pC->movetoTarget = sqlite3BtreeIntegerKey(pC->uc.pCursor);
    ++    }
    ++  }else{
    ++    zDb = 0;   /* Not needed.  Silence a compiler warning. */
    ++    pTab = 0;  /* Not needed.  Silence a compiler warning. */
    +   }
    + 
    +-#ifdef SQLITE_DEBUG
    +-  /* The seek operation that positioned the cursor prior to OP_Delete will
    +-  ** have also set the pC->movetoTarget field to the rowid of the row that
    +-  ** is being deleted */
    +-  if( pOp->p4.z && pC->isTable && pOp->p5==0 ){
    +-    i64 iKey = 0;
    +-    sqlite3BtreeKeySize(pC->pCursor, &iKey);
    +-    assert( pC->movetoTarget==iKey ); 
    ++#ifdef SQLITE_ENABLE_PREUPDATE_HOOK
    ++  /* Invoke the pre-update-hook if required. */
    ++  if( db->xPreUpdateCallback && pOp->p4.pTab ){
    ++    assert( !(opflags & OPFLAG_ISUPDATE) 
    ++         || HasRowid(pTab)==0 
    ++         || (aMem[pOp->p3].flags & MEM_Int) 
    ++    );
    ++    sqlite3VdbePreUpdateHook(p, pC,
    ++        (opflags & OPFLAG_ISUPDATE) ? SQLITE_UPDATE : SQLITE_DELETE, 
    ++        zDb, pTab, pC->movetoTarget,
    ++        pOp->p3
    ++    );
    +   }
    ++  if( opflags & OPFLAG_ISNOOP ) break;
    + #endif
    +  
    +-  rc = sqlite3BtreeDelete(pC->pCursor, pOp->p5);
    ++  /* Only flags that can be set are SAVEPOISTION and AUXDELETE */ 
    ++  assert( (pOp->p5 & ~(OPFLAG_SAVEPOSITION|OPFLAG_AUXDELETE))==0 );
    ++  assert( OPFLAG_SAVEPOSITION==BTREE_SAVEPOSITION );
    ++  assert( OPFLAG_AUXDELETE==BTREE_AUXDELETE );
    ++
    ++#ifdef SQLITE_DEBUG
    ++  if( p->pFrame==0 ){
    ++    if( pC->isEphemeral==0
    ++        && (pOp->p5 & OPFLAG_AUXDELETE)==0
    ++        && (pC->wrFlag & OPFLAG_FORDELETE)==0
    ++      ){
    ++      nExtraDelete++;
    ++    }
    ++    if( pOp->p2 & OPFLAG_NCHANGE ){
    ++      nExtraDelete--;
    ++    }
    ++  }
    ++#endif
    ++
    ++  rc = sqlite3BtreeDelete(pC->uc.pCursor, pOp->p5);
    +   pC->cacheStatus = CACHE_STALE;
    ++  pC->seekResult = 0;
    ++  if( rc ) goto abort_due_to_error;
    + 
    +   /* Invoke the update-hook if required. */
    +-  if( rc==SQLITE_OK && hasUpdateCallback ){
    +-    db->xUpdateCallback(db->pUpdateArg, SQLITE_DELETE,
    +-                        db->aDb[pC->iDb].zName, pOp->p4.z, pC->movetoTarget);
    +-    assert( pC->iDb>=0 );
    ++  if( opflags & OPFLAG_NCHANGE ){
    ++    p->nChange++;
    ++    if( db->xUpdateCallback && HasRowid(pTab) ){
    ++      db->xUpdateCallback(db->pUpdateArg, SQLITE_DELETE, zDb, pTab->zName,
    ++          pC->movetoTarget);
    ++      assert( pC->iDb>=0 );
    ++    }
    +   }
    +-  if( pOp->p2 & OPFLAG_NCHANGE ) p->nChange++;
    ++
    +   break;
    + }
    + /* Opcode: ResetCount * * * * *
    +@@ -77273,7 +84626,7 @@ case OP_ResetCount: {
    + }
    + 
    + /* Opcode: SorterCompare P1 P2 P3 P4
    +-** Synopsis:  if key(P1)!=trim(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
    + ** record blob in register P3 against a prefix of the entry that 
    +@@ -77300,6 +84653,7 @@ case OP_SorterCompare: {
    +   res = 0;
    +   rc = sqlite3VdbeSorterCompare(pC, pIn3, nKeyCol, &res);
    +   VdbeBranchTaken(res!=0,2);
    ++  if( rc ) goto abort_due_to_error;
    +   if( res ) goto jump_to_p2;
    +   break;
    + };
    +@@ -77325,57 +84679,59 @@ case OP_SorterData: {
    +   rc = sqlite3VdbeSorterRowkey(pC, pOut);
    +   assert( rc!=SQLITE_OK || (pOut->flags & MEM_Blob) );
    +   assert( pOp->p1>=0 && pOp->p1<p->nCursor );
    ++  if( rc ) goto abort_due_to_error;
    +   p->apCsr[pOp->p3]->cacheStatus = CACHE_STALE;
    +   break;
    + }
    + 
    +-/* Opcode: RowData P1 P2 * * *
    ++/* Opcode: RowData P1 P2 P3 * *
    + ** Synopsis: r[P2]=data
    + **
    +-** Write into register P2 the complete row data for cursor P1.
    ++** Write into register P2 the complete row content for the row at 
    ++** which cursor P1 is currently pointing.
    + ** There is no interpretation of the data.  
    + ** It is just copied onto the P2 register exactly as 
    + ** it is found in the database file.
    + **
    ++** If cursor P1 is an index, then the content is the key of the row.
    ++** If cursor P2 is a table, then the content extracted is the data.
    ++**
    + ** If the P1 cursor must be pointing to a valid row (not a NULL row)
    + ** of a real table, not a pseudo-table.
    +-*/
    +-/* Opcode: RowKey P1 P2 * * *
    +-** Synopsis: r[P2]=key
    + **
    +-** Write into register P2 the complete row key for cursor P1.
    +-** There is no interpretation of the data.  
    +-** The key is copied onto the P2 register exactly as 
    +-** it is found in the database file.
    ++** If P3!=0 then this opcode is allowed to make an ephermeral pointer
    ++** into the database page.  That means that the content of the output
    ++** register will be invalidated as soon as the cursor moves - including
    ++** moves caused by other cursors that "save" the the current cursors
    ++** position in order that they can write to the same table.  If P3==0
    ++** then a copy of the data is made into memory.  P3!=0 is faster, but
    ++** P3==0 is safer.
    + **
    +-** If the P1 cursor must be pointing to a valid row (not a NULL row)
    +-** of a real table, not a pseudo-table.
    ++** If P3!=0 then the content of the P2 register is unsuitable for use
    ++** in OP_Result and any OP_Result will invalidate the P2 register content.
    ++** The P2 register content is invalidated by opcodes like OP_Function or
    ++** by any use of another cursor pointing to the same table.
    + */
    +-case OP_RowKey:
    + case OP_RowData: {
    +   VdbeCursor *pC;
    +   BtCursor *pCrsr;
    +   u32 n;
    +-  i64 n64;
    + 
    +-  pOut = &aMem[pOp->p2];
    +-  memAboutToChange(p, pOut);
    ++  pOut = out2Prerelease(p, pOp);
    + 
    +-  /* Note that RowKey and RowData are really exactly the same instruction */
    +   assert( pOp->p1>=0 && pOp->p1<p->nCursor );
    +   pC = p->apCsr[pOp->p1];
    +-  assert( isSorter(pC)==0 );
    +-  assert( pC->isTable || pOp->opcode!=OP_RowData );
    +-  assert( pC->isTable==0 || pOp->opcode==OP_RowData );
    +   assert( pC!=0 );
    ++  assert( pC->eCurType==CURTYPE_BTREE );
    ++  assert( isSorter(pC)==0 );
    +   assert( pC->nullRow==0 );
    +-  assert( pC->pseudoTableReg==0 );
    +-  assert( pC->pCursor!=0 );
    +-  pCrsr = pC->pCursor;
    ++  assert( pC->uc.pCursor!=0 );
    ++  pCrsr = pC->uc.pCursor;
    + 
    +-  /* The OP_RowKey and OP_RowData opcodes always follow OP_NotExists or
    +-  ** OP_Rewind/Op_Next with no intervening instructions that might invalidate
    +-  ** the cursor.  If this where not the case, on of the following assert()s
    ++  /* The OP_RowData opcodes always follow OP_NotExists or
    ++  ** OP_SeekRowid or OP_Rewind/Op_Next with no intervening instructions
    ++  ** that might invalidate the cursor.
    ++  ** If this where not the case, on of the following assert()s
    +   ** would fail.  Should this ever change (because of changes in the code
    +   ** generator) then the fix would be to insert a call to
    +   ** sqlite3VdbeCursorMoveto().
    +@@ -77387,33 +84743,14 @@ case OP_RowData: {
    +   if( rc!=SQLITE_OK ) goto abort_due_to_error;
    + #endif
    + 
    +-  if( pC->isTable==0 ){
    +-    assert( !pC->isTable );
    +-    VVA_ONLY(rc =) sqlite3BtreeKeySize(pCrsr, &n64);
    +-    assert( rc==SQLITE_OK );    /* True because of CursorMoveto() call above */
    +-    if( n64>db->aLimit[SQLITE_LIMIT_LENGTH] ){
    +-      goto too_big;
    +-    }
    +-    n = (u32)n64;
    +-  }else{
    +-    VVA_ONLY(rc =) sqlite3BtreeDataSize(pCrsr, &n);
    +-    assert( rc==SQLITE_OK );    /* DataSize() cannot fail */
    +-    if( n>(u32)db->aLimit[SQLITE_LIMIT_LENGTH] ){
    +-      goto too_big;
    +-    }
    ++  n = sqlite3BtreePayloadSize(pCrsr);
    ++  if( n>(u32)db->aLimit[SQLITE_LIMIT_LENGTH] ){
    ++    goto too_big;
    +   }
    +   testcase( n==0 );
    +-  if( sqlite3VdbeMemClearAndResize(pOut, MAX(n,32)) ){
    +-    goto no_mem;
    +-  }
    +-  pOut->n = n;
    +-  MemSetTypeFlag(pOut, MEM_Blob);
    +-  if( pC->isTable==0 ){
    +-    rc = sqlite3BtreeKey(pCrsr, 0, n, pOut->z);
    +-  }else{
    +-    rc = sqlite3BtreeData(pCrsr, 0, n, pOut->z);
    +-  }
    +-  pOut->enc = SQLITE_UTF8;  /* In case the blob is ever cast to text */
    ++  rc = sqlite3VdbeMemFromBtree(pCrsr, 0, n, pOut);
    ++  if( rc ) goto abort_due_to_error;
    ++  if( !pOp->p3 ) Deephemeralize(pOut);
    +   UPDATE_MAX_BLOBSIZE(pOut);
    +   REGISTER_TRACE(pOp->p2, pOut);
    +   break;
    +@@ -77439,30 +84776,32 @@ case OP_Rowid: {                 /* out2 */
    +   assert( pOp->p1>=0 && pOp->p1<p->nCursor );
    +   pC = p->apCsr[pOp->p1];
    +   assert( pC!=0 );
    +-  assert( pC->pseudoTableReg==0 || pC->nullRow );
    ++  assert( pC->eCurType!=CURTYPE_PSEUDO || pC->nullRow );
    +   if( pC->nullRow ){
    +     pOut->flags = MEM_Null;
    +     break;
    +   }else if( pC->deferredMoveto ){
    +     v = pC->movetoTarget;
    + #ifndef SQLITE_OMIT_VIRTUALTABLE
    +-  }else if( pC->pVtabCursor ){
    +-    pVtab = pC->pVtabCursor->pVtab;
    ++  }else if( pC->eCurType==CURTYPE_VTAB ){
    ++    assert( pC->uc.pVCur!=0 );
    ++    pVtab = pC->uc.pVCur->pVtab;
    +     pModule = pVtab->pModule;
    +     assert( pModule->xRowid );
    +-    rc = pModule->xRowid(pC->pVtabCursor, &v);
    ++    rc = pModule->xRowid(pC->uc.pVCur, &v);
    +     sqlite3VtabImportErrmsg(p, pVtab);
    ++    if( rc ) goto abort_due_to_error;
    + #endif /* SQLITE_OMIT_VIRTUALTABLE */
    +   }else{
    +-    assert( pC->pCursor!=0 );
    ++    assert( pC->eCurType==CURTYPE_BTREE );
    ++    assert( pC->uc.pCursor!=0 );
    +     rc = sqlite3VdbeCursorRestore(pC);
    +     if( rc ) goto abort_due_to_error;
    +     if( pC->nullRow ){
    +       pOut->flags = MEM_Null;
    +       break;
    +     }
    +-    rc = sqlite3BtreeKeySize(pC->pCursor, &v);
    +-    assert( rc==SQLITE_OK );  /* Always so because of CursorRestore() above */
    ++    v = sqlite3BtreeIntegerKey(pC->uc.pCursor);
    +   }
    +   pOut->u.i = v;
    +   break;
    +@@ -77482,13 +84821,24 @@ case OP_NullRow: {
    +   assert( pC!=0 );
    +   pC->nullRow = 1;
    +   pC->cacheStatus = CACHE_STALE;
    +-  if( pC->pCursor ){
    +-    sqlite3BtreeClearCursor(pC->pCursor);
    ++  if( pC->eCurType==CURTYPE_BTREE ){
    ++    assert( pC->uc.pCursor!=0 );
    ++    sqlite3BtreeClearCursor(pC->uc.pCursor);
    +   }
    +   break;
    + }
    + 
    +-/* Opcode: Last P1 P2 P3 * *
    ++/* Opcode: SeekEnd P1 * * * *
    ++**
    ++** Position cursor P1 at the end of the btree for the purpose of
    ++** appending a new entry onto the btree.
    ++**
    ++** It is assumed that the cursor is used only for appending and so
    ++** if the cursor is valid, then the cursor must already be pointing
    ++** at the end of the btree and so no changes are made to
    ++** the cursor.
    ++*/
    ++/* Opcode: Last P1 P2 * * *
    + **
    + ** 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.
    +@@ -77500,6 +84850,7 @@ case OP_NullRow: {
    + ** from the end toward the beginning.  In other words, the cursor is
    + ** configured to use Prev, not Next.
    + */
    ++case OP_SeekEnd:
    + case OP_Last: {        /* jump */
    +   VdbeCursor *pC;
    +   BtCursor *pCrsr;
    +@@ -77508,17 +84859,25 @@ case OP_Last: {        /* jump */
    +   assert( pOp->p1>=0 && pOp->p1<p->nCursor );
    +   pC = p->apCsr[pOp->p1];
    +   assert( pC!=0 );
    +-  pCrsr = pC->pCursor;
    ++  assert( pC->eCurType==CURTYPE_BTREE );
    ++  pCrsr = pC->uc.pCursor;
    +   res = 0;
    +   assert( pCrsr!=0 );
    ++#ifdef SQLITE_DEBUG
    ++  pC->seekOp = pOp->opcode;
    ++#endif
    ++  if( pOp->opcode==OP_SeekEnd ){
    ++    assert( pOp->p2==0 );
    ++    pC->seekResult = -1;
    ++    if( sqlite3BtreeCursorIsValidNN(pCrsr) ){
    ++      break;
    ++    }
    ++  }
    +   rc = sqlite3BtreeLast(pCrsr, &res);
    +   pC->nullRow = (u8)res;
    +   pC->deferredMoveto = 0;
    +   pC->cacheStatus = CACHE_STALE;
    +-  pC->seekResult = pOp->p3;
    +-#ifdef SQLITE_DEBUG
    +-  pC->seekOp = OP_Last;
    +-#endif
    ++  if( rc ) goto abort_due_to_error;
    +   if( pOp->p2>0 ){
    +     VdbeBranchTaken(res!=0,2);
    +     if( res ) goto jump_to_p2;
    +@@ -77526,7 +84885,43 @@ case OP_Last: {        /* jump */
    +   break;
    + }
    + 
    ++/* Opcode: IfSmaller P1 P2 P3 * *
    ++**
    ++** Estimate the number of rows in the table P1.  Jump to P2 if that
    ++** estimate is less than approximately 2**(0.1*P3).
    ++*/
    ++case OP_IfSmaller: {        /* jump */
    ++  VdbeCursor *pC;
    ++  BtCursor *pCrsr;
    ++  int res;
    ++  i64 sz;
    ++
    ++  assert( pOp->p1>=0 && pOp->p1<p->nCursor );
    ++  pC = p->apCsr[pOp->p1];
    ++  assert( pC!=0 );
    ++  pCrsr = pC->uc.pCursor;
    ++  assert( pCrsr );
    ++  rc = sqlite3BtreeFirst(pCrsr, &res);
    ++  if( rc ) goto abort_due_to_error;
    ++  if( res==0 ){
    ++    sz = sqlite3BtreeRowCountEst(pCrsr);
    ++    if( ALWAYS(sz>=0) && sqlite3LogEst((u64)sz)<pOp->p3 ) res = 1;
    ++  }
    ++  VdbeBranchTaken(res!=0,2);
    ++  if( res ) goto jump_to_p2;
    ++  break;
    ++}
    ++
    + 
    ++/* Opcode: SorterSort P1 P2 * * *
    ++**
    ++** After all records have been inserted into the Sorter object
    ++** identified by P1, invoke this opcode to actually do the sorting.
    ++** Jump to P2 if there are no records to be sorted.
    ++**
    ++** This opcode is an alias for OP_Sort and OP_Rewind that is used
    ++** for Sorter objects.
    ++*/
    + /* Opcode: Sort P1 P2 * * *
    + **
    + ** This opcode does exactly the same thing as OP_Rewind except that
    +@@ -77576,12 +84971,14 @@ case OP_Rewind: {        /* jump */
    +   if( isSorter(pC) ){
    +     rc = sqlite3VdbeSorterRewind(pC, &res);
    +   }else{
    +-    pCrsr = pC->pCursor;
    ++    assert( pC->eCurType==CURTYPE_BTREE );
    ++    pCrsr = pC->uc.pCursor;
    +     assert( pCrsr );
    +     rc = sqlite3BtreeFirst(pCrsr, &res);
    +     pC->deferredMoveto = 0;
    +     pC->cacheStatus = CACHE_STALE;
    +   }
    ++  if( rc ) goto abort_due_to_error;
    +   pC->nullRow = (u8)res;
    +   assert( pOp->p2>0 && pOp->p2<p->nOp );
    +   VdbeBranchTaken(res!=0,2);
    +@@ -77652,14 +85049,19 @@ case OP_Rewind: {        /* jump */
    + ** This opcode works just like Prev except that if cursor P1 is not
    + ** open it behaves a no-op.
    + */
    ++/* Opcode: SorterNext P1 P2 * * P5
    ++**
    ++** This opcode works just like OP_Next except that P1 must be a
    ++** sorter object for which the OP_SorterSort opcode has been
    ++** invoked.  This opcode advances the cursor to the next sorted
    ++** record, or jumps to P2 if there are no more sorted records.
    ++*/
    + case OP_SorterNext: {  /* jump */
    +   VdbeCursor *pC;
    +-  int res;
    + 
    +   pC = p->apCsr[pOp->p1];
    +   assert( isSorter(pC) );
    +-  res = 0;
    +-  rc = sqlite3VdbeSorterNext(db, pC, &res);
    ++  rc = sqlite3VdbeSorterNext(db, pC);
    +   goto next_tail;
    + case OP_PrevIfOpen:    /* jump */
    + case OP_NextIfOpen:    /* jump */
    +@@ -77670,12 +85072,9 @@ case OP_Next:          /* jump */
    +   assert( pOp->p1>=0 && pOp->p1<p->nCursor );
    +   assert( pOp->p5<ArraySize(p->aCounter) );
    +   pC = p->apCsr[pOp->p1];
    +-  res = pOp->p3;
    +   assert( pC!=0 );
    +   assert( pC->deferredMoveto==0 );
    +-  assert( pC->pCursor );
    +-  assert( res==0 || (res==1 && pC->isTable==0) );
    +-  testcase( res==1 );
    ++  assert( pC->eCurType==CURTYPE_BTREE );
    +   assert( pOp->opcode!=OP_Next || pOp->p4.xAdvance==sqlite3BtreeNext );
    +   assert( pOp->opcode!=OP_Prev || pOp->p4.xAdvance==sqlite3BtreePrevious );
    +   assert( pOp->opcode!=OP_NextIfOpen || pOp->p4.xAdvance==sqlite3BtreeNext );
    +@@ -77690,49 +85089,63 @@ case OP_Next:          /* jump */
    +        || pC->seekOp==OP_SeekLT || pC->seekOp==OP_SeekLE
    +        || pC->seekOp==OP_Last );
    + 
    +-  rc = pOp->p4.xAdvance(pC->pCursor, &res);
    ++  rc = pOp->p4.xAdvance(pC->uc.pCursor, pOp->p3);
    + next_tail:
    +   pC->cacheStatus = CACHE_STALE;
    +-  VdbeBranchTaken(res==0,2);
    +-  if( res==0 ){
    ++  VdbeBranchTaken(rc==SQLITE_OK,2);
    ++  if( rc==SQLITE_OK ){
    +     pC->nullRow = 0;
    +     p->aCounter[pOp->p5]++;
    + #ifdef SQLITE_TEST
    +     sqlite3_search_count++;
    + #endif
    +     goto jump_to_p2_and_check_for_interrupt;
    +-  }else{
    +-    pC->nullRow = 1;
    +   }
    ++  if( rc!=SQLITE_DONE ) goto abort_due_to_error;
    ++  rc = SQLITE_OK;
    ++  pC->nullRow = 1;
    +   goto check_for_interrupt;
    + }
    + 
    +-/* Opcode: IdxInsert P1 P2 P3 * P5
    ++/* Opcode: IdxInsert P1 P2 P3 P4 P5
    + ** Synopsis: key=r[P2]
    + **
    + ** Register P2 holds an SQL index key made using the
    + ** MakeRecord instructions.  This opcode writes that key
    + ** into the index P1.  Data for the entry is nil.
    + **
    +-** P3 is a flag that provides a hint to the b-tree layer that this
    +-** insert is likely to be an append.
    ++** If P4 is not zero, then it is the number of values in the unpacked
    ++** key of reg(P2).  In that case, P3 is the index of the first register
    ++** for the unpacked key.  The availability of the unpacked key can sometimes
    ++** be an optimization.
    ++**
    ++** If P5 has the OPFLAG_APPEND bit set, that is a hint to the b-tree layer
    ++** that this insert is likely to be an append.
    + **
    + ** If P5 has the OPFLAG_NCHANGE bit set, then the change counter is
    + ** incremented by this instruction.  If the OPFLAG_NCHANGE bit is clear,
    + ** then the change counter is unchanged.
    + **
    +-** If P5 has the OPFLAG_USESEEKRESULT bit set, then the cursor must have
    +-** just done a seek to the spot where the new entry is to be inserted.
    +-** This flag avoids doing an extra seek.
    ++** If the OPFLAG_USESEEKRESULT flag of P5 is set, the implementation might
    ++** run faster by avoiding an unnecessary seek on cursor P1.  However,
    ++** the OPFLAG_USESEEKRESULT flag must only be set if there have been no prior
    ++** seeks on the cursor or if the most recent seek used a key equivalent
    ++** to P2. 
    + **
    + ** This instruction only works for indices.  The equivalent instruction
    + ** for tables is OP_Insert.
    + */
    ++/* Opcode: SorterInsert P1 P2 * * *
    ++** Synopsis: key=r[P2]
    ++**
    ++** Register P2 holds an SQL index key made using the
    ++** MakeRecord instructions.  This opcode writes that key
    ++** into the sorter P1.  Data for the entry is nil.
    ++*/
    + case OP_SorterInsert:       /* in2 */
    + case OP_IdxInsert: {        /* in2 */
    +   VdbeCursor *pC;
    +-  int nKey;
    +-  const char *zKey;
    ++  BtreePayload x;
    + 
    +   assert( pOp->p1>=0 && pOp->p1<p->nCursor );
    +   pC = p->apCsr[pOp->p1];
    +@@ -77741,22 +85154,25 @@ case OP_IdxInsert: {        /* in2 */
    +   pIn2 = &aMem[pOp->p2];
    +   assert( pIn2->flags & MEM_Blob );
    +   if( pOp->p5 & OPFLAG_NCHANGE ) p->nChange++;
    +-  assert( pC->pCursor!=0 );
    ++  assert( pC->eCurType==CURTYPE_BTREE || pOp->opcode==OP_SorterInsert );
    +   assert( pC->isTable==0 );
    +   rc = ExpandBlob(pIn2);
    +-  if( rc==SQLITE_OK ){
    +-    if( pOp->opcode==OP_SorterInsert ){
    +-      rc = sqlite3VdbeSorterWrite(pC, pIn2);
    +-    }else{
    +-      nKey = pIn2->n;
    +-      zKey = pIn2->z;
    +-      rc = sqlite3BtreeInsert(pC->pCursor, zKey, nKey, "", 0, 0, pOp->p3, 
    +-          ((pOp->p5 & OPFLAG_USESEEKRESULT) ? pC->seekResult : 0)
    +-          );
    +-      assert( pC->deferredMoveto==0 );
    +-      pC->cacheStatus = CACHE_STALE;
    +-    }
    ++  if( rc ) goto abort_due_to_error;
    ++  if( pOp->opcode==OP_SorterInsert ){
    ++    rc = sqlite3VdbeSorterWrite(pC, pIn2);
    ++  }else{
    ++    x.nKey = pIn2->n;
    ++    x.pKey = pIn2->z;
    ++    x.aMem = aMem + pOp->p3;
    ++    x.nMem = (u16)pOp->p4.i;
    ++    rc = sqlite3BtreeInsert(pC->uc.pCursor, &x,
    ++         (pOp->p5 & (OPFLAG_APPEND|OPFLAG_SAVEPOSITION)), 
    ++        ((pOp->p5 & OPFLAG_USESEEKRESULT) ? pC->seekResult : 0)
    ++        );
    ++    assert( pC->deferredMoveto==0 );
    ++    pC->cacheStatus = CACHE_STALE;
    +   }
    ++  if( rc) goto abort_due_to_error;
    +   break;
    + }
    + 
    +@@ -77774,29 +85190,49 @@ case OP_IdxDelete: {
    +   UnpackedRecord r;
    + 
    +   assert( pOp->p3>0 );
    +-  assert( pOp->p2>0 && pOp->p2+pOp->p3<=(p->nMem-p->nCursor)+1 );
    ++  assert( pOp->p2>0 && pOp->p2+pOp->p3<=(p->nMem+1 - p->nCursor)+1 );
    +   assert( pOp->p1>=0 && pOp->p1<p->nCursor );
    +   pC = p->apCsr[pOp->p1];
    +   assert( pC!=0 );
    +-  pCrsr = pC->pCursor;
    ++  assert( pC->eCurType==CURTYPE_BTREE );
    ++  pCrsr = pC->uc.pCursor;
    +   assert( pCrsr!=0 );
    +   assert( pOp->p5==0 );
    +   r.pKeyInfo = pC->pKeyInfo;
    +   r.nField = (u16)pOp->p3;
    +   r.default_rc = 0;
    +   r.aMem = &aMem[pOp->p2];
    +-#ifdef SQLITE_DEBUG
    +-  { int i; for(i=0; i<r.nField; i++) assert( memIsValid(&r.aMem[i]) ); }
    +-#endif
    +   rc = sqlite3BtreeMovetoUnpacked(pCrsr, &r, 0, 0, &res);
    +-  if( rc==SQLITE_OK && res==0 ){
    +-    rc = sqlite3BtreeDelete(pCrsr, 0);
    ++  if( rc ) goto abort_due_to_error;
    ++  if( res==0 ){
    ++    rc = sqlite3BtreeDelete(pCrsr, BTREE_AUXDELETE);
    ++    if( rc ) goto abort_due_to_error;
    +   }
    +   assert( pC->deferredMoveto==0 );
    +   pC->cacheStatus = CACHE_STALE;
    ++  pC->seekResult = 0;
    +   break;
    + }
    + 
    ++/* Opcode: DeferredSeek P1 * P3 P4 *
    ++** Synopsis: Move P3 to P1.rowid if needed
    ++**
    ++** P1 is an open index cursor and P3 is a cursor on the corresponding
    ++** table.  This opcode does a deferred seek of the P3 table cursor
    ++** to the row that corresponds to the current row of P1.
    ++**
    ++** This is a deferred seek.  Nothing actually happens until
    ++** the cursor is used to read a record.  That way, if no reads
    ++** occur, no unnecessary I/O happens.
    ++**
    ++** P4 may be an array of integers (type P4_INTARRAY) containing
    ++** one entry for each column in the P3 table.  If array entry a(i)
    ++** is non-zero, then reading column a(i)-1 from cursor P3 is 
    ++** equivalent to performing the deferred seek and then reading column i 
    ++** from P1.  This information is stored in P3 and used to redirect
    ++** reads against P3 over to P1, thus possibly avoiding the need to
    ++** seek and read cursor P3.
    ++*/
    + /* Opcode: IdxRowid P1 P2 * * *
    + ** Synopsis: r[P2]=rowid
    + **
    +@@ -77806,36 +85242,56 @@ case OP_IdxDelete: {
    + **
    + ** See also: Rowid, MakeRecord.
    + */
    +-case OP_IdxRowid: {              /* out2 */
    +-  BtCursor *pCrsr;
    +-  VdbeCursor *pC;
    +-  i64 rowid;
    ++case OP_DeferredSeek:
    ++case OP_IdxRowid: {           /* out2 */
    ++  VdbeCursor *pC;             /* The P1 index cursor */
    ++  VdbeCursor *pTabCur;        /* The P2 table cursor (OP_DeferredSeek only) */
    ++  i64 rowid;                  /* Rowid that P1 current points to */
    + 
    +-  pOut = out2Prerelease(p, pOp);
    +   assert( pOp->p1>=0 && pOp->p1<p->nCursor );
    +   pC = p->apCsr[pOp->p1];
    +   assert( pC!=0 );
    +-  pCrsr = pC->pCursor;
    +-  assert( pCrsr!=0 );
    +-  pOut->flags = MEM_Null;
    ++  assert( pC->eCurType==CURTYPE_BTREE );
    ++  assert( pC->uc.pCursor!=0 );
    +   assert( pC->isTable==0 );
    +   assert( pC->deferredMoveto==0 );
    ++  assert( !pC->nullRow || pOp->opcode==OP_IdxRowid );
    + 
    +-  /* sqlite3VbeCursorRestore() can only fail if the record has been deleted
    +-  ** out from under the cursor.  That will never happend for an IdxRowid
    +-  ** opcode, hence the NEVER() arround the check of the return value.
    +-  */
    ++  /* The IdxRowid and Seek opcodes are combined because of the commonality
    ++  ** of sqlite3VdbeCursorRestore() and sqlite3VdbeIdxRowid(). */
    +   rc = sqlite3VdbeCursorRestore(pC);
    ++
    ++  /* sqlite3VbeCursorRestore() can only fail if the record has been deleted
    ++  ** out from under the cursor.  That will never happens for an IdxRowid
    ++  ** or Seek opcode */
    +   if( NEVER(rc!=SQLITE_OK) ) goto abort_due_to_error;
    + 
    +   if( !pC->nullRow ){
    +     rowid = 0;  /* Not needed.  Only used to silence a warning. */
    +-    rc = sqlite3VdbeIdxRowid(db, pCrsr, &rowid);
    ++    rc = sqlite3VdbeIdxRowid(db, pC->uc.pCursor, &rowid);
    +     if( rc!=SQLITE_OK ){
    +       goto abort_due_to_error;
    +     }
    +-    pOut->u.i = rowid;
    +-    pOut->flags = MEM_Int;
    ++    if( pOp->opcode==OP_DeferredSeek ){
    ++      assert( pOp->p3>=0 && pOp->p3<p->nCursor );
    ++      pTabCur = p->apCsr[pOp->p3];
    ++      assert( pTabCur!=0 );
    ++      assert( pTabCur->eCurType==CURTYPE_BTREE );
    ++      assert( pTabCur->uc.pCursor!=0 );
    ++      assert( pTabCur->isTable );
    ++      pTabCur->nullRow = 0;
    ++      pTabCur->movetoTarget = rowid;
    ++      pTabCur->deferredMoveto = 1;
    ++      assert( pOp->p4type==P4_INTARRAY || pOp->p4.ai==0 );
    ++      pTabCur->aAltMap = pOp->p4.ai;
    ++      pTabCur->pAltCursor = pC;
    ++    }else{
    ++      pOut = out2Prerelease(p, pOp);
    ++      pOut->u.i = rowid;
    ++    }
    ++  }else{
    ++    assert( pOp->opcode==OP_IdxRowid );
    ++    sqlite3VdbeMemSetNull(&aMem[pOp->p2]);
    +   }
    +   break;
    + }
    +@@ -77896,7 +85352,8 @@ case OP_IdxGE:  {       /* jump */
    +   pC = p->apCsr[pOp->p1];
    +   assert( pC!=0 );
    +   assert( pC->isOrdered );
    +-  assert( pC->pCursor!=0);
    ++  assert( pC->eCurType==CURTYPE_BTREE );
    ++  assert( pC->uc.pCursor!=0);
    +   assert( pC->deferredMoveto==0 );
    +   assert( pOp->p5==0 || pOp->p5==1 );
    +   assert( pOp->p4type==P4_INT32 );
    +@@ -77924,6 +85381,7 @@ case OP_IdxGE:  {       /* jump */
    +     res++;
    +   }
    +   VdbeBranchTaken(res>0,2);
    ++  if( rc ) goto abort_due_to_error;
    +   if( res>0 ) goto jump_to_p2;
    +   break;
    + }
    +@@ -77941,10 +85399,17 @@ case OP_IdxGE:  {       /* jump */
    + ** might be moved into the newly deleted root page in order to keep all
    + ** root pages contiguous at the beginning of the database.  The former
    + ** value of the root page that moved - its value before the move occurred -
    +-** is stored in register P2.  If no page 
    +-** movement was required (because the table being dropped was already 
    +-** the last one in the database) then a zero is stored in register P2.
    +-** If AUTOVACUUM is disabled then a zero is stored in register P2.
    ++** is stored in register P2. If no page movement was required (because the
    ++** table being dropped was already the last one in the database) then a 
    ++** zero is stored in register P2.  If AUTOVACUUM is disabled then a zero 
    ++** is stored in register P2.
    ++**
    ++** This opcode throws an error if there are any active reader VMs when
    ++** it is invoked. This is done to avoid the difficulty associated with 
    ++** updating existing cursors when a root page is moved in an AUTOVACUUM 
    ++** database. This error is thrown even if the database is not an AUTOVACUUM 
    ++** db in order to avoid introducing an incompatibility between autovacuum 
    ++** and non-autovacuum modes.
    + **
    + ** See also: Clear
    + */
    +@@ -77953,11 +85418,13 @@ case OP_Destroy: {     /* out2 */
    +   int iDb;
    + 
    +   assert( p->readOnly==0 );
    ++  assert( pOp->p1>1 );
    +   pOut = out2Prerelease(p, pOp);
    +   pOut->flags = MEM_Null;
    +   if( db->nVdbeRead > db->nVDestroy+1 ){
    +     rc = SQLITE_LOCKED;
    +     p->errorAction = OE_Abort;
    ++    goto abort_due_to_error;
    +   }else{
    +     iDb = pOp->p3;
    +     assert( DbMaskTest(p->btreeMask, iDb) );
    +@@ -77965,8 +85432,9 @@ case OP_Destroy: {     /* out2 */
    +     rc = sqlite3BtreeDropTable(db->aDb[iDb].pBt, pOp->p1, &iMoved);
    +     pOut->flags = MEM_Int;
    +     pOut->u.i = iMoved;
    ++    if( rc ) goto abort_due_to_error;
    + #ifndef SQLITE_OMIT_AUTOVACUUM
    +-    if( rc==SQLITE_OK && iMoved!=0 ){
    ++    if( iMoved!=0 ){
    +       sqlite3RootPageMoved(db, iDb, iMoved, pOp->p1);
    +       /* All OP_Destroy operations occur on the same btree */
    +       assert( resetSchemaOnFault==0 || resetSchemaOnFault==iDb+1 );
    +@@ -78012,6 +85480,7 @@ case OP_Clear: {
    +       aMem[pOp->p3].u.i += nChange;
    +     }
    +   }
    ++  if( rc ) goto abort_due_to_error;
    +   break;
    + }
    + 
    +@@ -78029,63 +85498,56 @@ case OP_ResetSorter: {
    +   assert( pOp->p1>=0 && pOp->p1<p->nCursor );
    +   pC = p->apCsr[pOp->p1];
    +   assert( pC!=0 );
    +-  if( pC->pSorter ){
    +-    sqlite3VdbeSorterReset(db, pC->pSorter);
    ++  if( isSorter(pC) ){
    ++    sqlite3VdbeSorterReset(db, pC->uc.pSorter);
    +   }else{
    ++    assert( pC->eCurType==CURTYPE_BTREE );
    +     assert( pC->isEphemeral );
    +-    rc = sqlite3BtreeClearTableOfCursor(pC->pCursor);
    ++    rc = sqlite3BtreeClearTableOfCursor(pC->uc.pCursor);
    ++    if( rc ) goto abort_due_to_error;
    +   }
    +   break;
    + }
    + 
    +-/* Opcode: CreateTable P1 P2 * * *
    +-** Synopsis: r[P2]=root iDb=P1
    +-**
    +-** Allocate a new table in the main database file if P1==0 or in the
    +-** auxiliary database file if P1==1 or in an attached database if
    +-** P1>1.  Write the root page number of the new table into
    +-** register P2
    ++/* Opcode: CreateBtree P1 P2 P3 * *
    ++** Synopsis: r[P2]=root iDb=P1 flags=P3
    + **
    +-** The difference between a table and an index is this:  A table must
    +-** have a 4-byte integer key and can have arbitrary data.  An index
    +-** has an arbitrary key but no data.
    +-**
    +-** See also: CreateIndex
    ++** Allocate a new b-tree in the main database file if P1==0 or in the
    ++** TEMP database file if P1==1 or in an attached database if
    ++** P1>1.  The P3 argument must be 1 (BTREE_INTKEY) for a rowid table
    ++** it must be 2 (BTREE_BLOBKEY) for a index or WITHOUT ROWID table.
    ++** The root page number of the new b-tree is stored in register P2.
    + */
    +-/* Opcode: CreateIndex P1 P2 * * *
    +-** Synopsis: r[P2]=root iDb=P1
    +-**
    +-** Allocate a new index in the main database file if P1==0 or in the
    +-** auxiliary database file if P1==1 or in an attached database if
    +-** P1>1.  Write the root page number of the new table into
    +-** register P2.
    +-**
    +-** See documentation on OP_CreateTable for additional information.
    +-*/
    +-case OP_CreateIndex:            /* out2 */
    +-case OP_CreateTable: {          /* out2 */
    ++case OP_CreateBtree: {          /* out2 */
    +   int pgno;
    +-  int flags;
    +   Db *pDb;
    + 
    +   pOut = out2Prerelease(p, pOp);
    +   pgno = 0;
    ++  assert( pOp->p3==BTREE_INTKEY || pOp->p3==BTREE_BLOBKEY );
    +   assert( pOp->p1>=0 && pOp->p1<db->nDb );
    +   assert( DbMaskTest(p->btreeMask, pOp->p1) );
    +   assert( p->readOnly==0 );
    +   pDb = &db->aDb[pOp->p1];
    +   assert( pDb->pBt!=0 );
    +-  if( pOp->opcode==OP_CreateTable ){
    +-    /* flags = BTREE_INTKEY; */
    +-    flags = BTREE_INTKEY;
    +-  }else{
    +-    flags = BTREE_BLOBKEY;
    +-  }
    +-  rc = sqlite3BtreeCreateTable(pDb->pBt, &pgno, flags);
    ++  rc = sqlite3BtreeCreateTable(pDb->pBt, &pgno, pOp->p3);
    ++  if( rc ) goto abort_due_to_error;
    +   pOut->u.i = pgno;
    +   break;
    + }
    + 
    ++/* Opcode: SqlExec * * * P4 *
    ++**
    ++** Run the SQL statement or statements specified in the P4 string.
    ++*/
    ++case OP_SqlExec: {
    ++  db->nSqlExec++;
    ++  rc = sqlite3_exec(db, pOp->p4.z, 0, 0, 0);
    ++  db->nSqlExec--;
    ++  if( rc ) goto abort_due_to_error;
    ++  break;
    ++}
    ++
    + /* Opcode: ParseSchema P1 * * P4 *
    + **
    + ** Read and parse all entries from the SQLITE_MASTER table of database P1
    +@@ -78114,15 +85576,15 @@ case OP_ParseSchema: {
    +   assert( iDb>=0 && iDb<db->nDb );
    +   assert( DbHasProperty(db, iDb, DB_SchemaLoaded) );
    +   /* Used to be a conditional */ {
    +-    zMaster = SCHEMA_TABLE(iDb);
    ++    zMaster = MASTER_NAME;
    +     initData.db = db;
    +     initData.iDb = pOp->p1;
    +     initData.pzErrMsg = &p->zErrMsg;
    +     zSql = sqlite3MPrintf(db,
    +        "SELECT name, rootpage, sql FROM '%q'.%s WHERE %s ORDER BY rowid",
    +-       db->aDb[iDb].zName, zMaster, pOp->p4.z);
    ++       db->aDb[iDb].zDbSName, zMaster, pOp->p4.z);
    +     if( zSql==0 ){
    +-      rc = SQLITE_NOMEM;
    ++      rc = SQLITE_NOMEM_BKPT;
    +     }else{
    +       assert( db->init.busy==0 );
    +       db->init.busy = 1;
    +@@ -78130,13 +85592,16 @@ case OP_ParseSchema: {
    +       assert( !db->mallocFailed );
    +       rc = sqlite3_exec(db, zSql, sqlite3InitCallback, &initData, 0);
    +       if( rc==SQLITE_OK ) rc = initData.rc;
    +-      sqlite3DbFree(db, zSql);
    ++      sqlite3DbFreeNN(db, zSql);
    +       db->init.busy = 0;
    +     }
    +   }
    +-  if( rc ) sqlite3ResetAllSchemasOfConnection(db);
    +-  if( rc==SQLITE_NOMEM ){
    +-    goto no_mem;
    ++  if( rc ){
    ++    sqlite3ResetAllSchemasOfConnection(db);
    ++    if( rc==SQLITE_NOMEM ){
    ++      goto no_mem;
    ++    }
    ++    goto abort_due_to_error;
    +   }
    +   break;  
    + }
    +@@ -78151,6 +85616,7 @@ case OP_ParseSchema: {
    + case OP_LoadAnalysis: {
    +   assert( pOp->p1>=0 && pOp->p1<db->nDb );
    +   rc = sqlite3AnalysisLoad(db, pOp->p1);
    ++  if( rc ) goto abort_due_to_error;
    +   break;  
    + }
    + #endif /* !defined(SQLITE_OMIT_ANALYZE) */
    +@@ -78196,20 +85662,19 @@ case OP_DropTrigger: {
    + 
    + 
    + #ifndef SQLITE_OMIT_INTEGRITY_CHECK
    +-/* Opcode: IntegrityCk P1 P2 P3 * P5
    ++/* Opcode: IntegrityCk P1 P2 P3 P4 P5
    + **
    + ** Do an analysis of the currently open database.  Store in
    + ** register P1 the text of an error message describing any problems.
    + ** If no problems are found, store a NULL in register P1.
    + **
    +-** The register P3 contains the maximum number of allowed errors.
    ++** The register P3 contains one less than the maximum number of allowed errors.
    + ** At most reg(P3) errors will be reported.
    + ** In other words, the analysis stops as soon as reg(P1) errors are 
    + ** seen.  Reg(P1) is updated with the number of errors remaining.
    + **
    +-** The root page numbers of all tables in the database are integer
    +-** stored in reg(P1), reg(P1+1), reg(P1+2), ....  There are P2 tables
    +-** total.
    ++** The root page numbers of all tables in the database are integers
    ++** stored in P4_INTARRAY argument.
    + **
    + ** If P5 is not zero, the check is done on the auxiliary database
    + ** file, not the main database file.
    +@@ -78219,37 +85684,31 @@ case OP_DropTrigger: {
    + case OP_IntegrityCk: {
    +   int nRoot;      /* Number of tables to check.  (Number of root pages.) */
    +   int *aRoot;     /* Array of rootpage numbers for tables to be checked */
    +-  int j;          /* Loop counter */
    +   int nErr;       /* Number of errors reported */
    +   char *z;        /* Text of the error report */
    +   Mem *pnErr;     /* Register keeping track of errors remaining */
    + 
    +   assert( p->bIsReader );
    +   nRoot = pOp->p2;
    ++  aRoot = pOp->p4.ai;
    +   assert( nRoot>0 );
    +-  aRoot = sqlite3DbMallocRaw(db, sizeof(int)*(nRoot+1) );
    +-  if( aRoot==0 ) goto no_mem;
    +-  assert( pOp->p3>0 && pOp->p3<=(p->nMem-p->nCursor) );
    ++  assert( aRoot[0]==nRoot );
    ++  assert( pOp->p3>0 && pOp->p3<=(p->nMem+1 - p->nCursor) );
    +   pnErr = &aMem[pOp->p3];
    +   assert( (pnErr->flags & MEM_Int)!=0 );
    +   assert( (pnErr->flags & (MEM_Str|MEM_Blob))==0 );
    +   pIn1 = &aMem[pOp->p1];
    +-  for(j=0; j<nRoot; j++){
    +-    aRoot[j] = (int)sqlite3VdbeIntValue(&pIn1[j]);
    +-  }
    +-  aRoot[j] = 0;
    +   assert( pOp->p5<db->nDb );
    +   assert( DbMaskTest(p->btreeMask, pOp->p5) );
    +-  z = sqlite3BtreeIntegrityCheck(db->aDb[pOp->p5].pBt, aRoot, nRoot,
    +-                                 (int)pnErr->u.i, &nErr);
    +-  sqlite3DbFree(db, aRoot);
    +-  pnErr->u.i -= nErr;
    ++  z = sqlite3BtreeIntegrityCheck(db->aDb[pOp->p5].pBt, &aRoot[1], nRoot,
    ++                                 (int)pnErr->u.i+1, &nErr);
    +   sqlite3VdbeMemSetNull(pIn1);
    +   if( nErr==0 ){
    +     assert( z==0 );
    +   }else if( z==0 ){
    +     goto no_mem;
    +   }else{
    ++    pnErr->u.i -= nErr-1;
    +     sqlite3VdbeMemSetStr(pIn1, z, -1, SQLITE_UTF8, sqlite3_free);
    +   }
    +   UPDATE_MAX_BLOBSIZE(pIn1);
    +@@ -78259,9 +85718,9 @@ case OP_IntegrityCk: {
    + #endif /* SQLITE_OMIT_INTEGRITY_CHECK */
    + 
    + /* Opcode: RowSetAdd P1 P2 * * *
    +-** Synopsis:  rowset(P1)=r[P2]
    ++** Synopsis: rowset(P1)=r[P2]
    + **
    +-** Insert the integer value held by register P2 into a boolean index
    ++** Insert the integer value held by register P2 into a RowSet object
    + ** held in register P1.
    + **
    + ** An assertion fails if P2 is not an integer.
    +@@ -78279,10 +85738,11 @@ case OP_RowSetAdd: {       /* in1, in2 */
    + }
    + 
    + /* Opcode: RowSetRead P1 P2 P3 * *
    +-** Synopsis:  r[P3]=rowset(P1)
    ++** Synopsis: r[P3]=rowset(P1)
    + **
    +-** Extract the smallest value from boolean index P1 and put that value into
    +-** register P3.  Or, if boolean index P1 is initially empty, leave P3
    ++** Extract the smallest value from the RowSet object in P1
    ++** and put that value into register P3.
    ++** Or, if RowSet object P1 is initially empty, leave P3
    + ** unchanged and jump to instruction P2.
    + */
    + case OP_RowSetRead: {       /* jump, in1, out3 */
    +@@ -78313,15 +85773,14 @@ case OP_RowSetRead: {       /* jump, in1, out3 */
    + ** integer in P3 into the RowSet and continue on to the
    + ** next opcode.
    + **
    +-** The RowSet object is optimized for the case where successive sets
    +-** of integers, where each set contains no duplicates. Each set
    +-** of values is identified by a unique P4 value. The first set
    +-** must have P4==0, the final set P4=-1.  P4 must be either -1 or
    +-** non-negative.  For non-negative values of P4 only the lower 4
    +-** bits are significant.
    ++** The RowSet object is optimized for the case where sets of integers
    ++** are inserted in distinct phases, which each set contains no duplicates.
    ++** Each set is identified by a unique P4 value. The first set
    ++** must have P4==0, the final set must have P4==-1, and for all other sets
    ++** must have P4>0.
    + **
    + ** This allows optimizations: (a) when P4==0 there is no need to test
    +-** the rowset object for P3, as it is guaranteed not to contain it,
    ++** the RowSet object for P3, as it is guaranteed not to contain it,
    + ** (b) when P4==-1 there is no need to insert the value, as it will
    + ** never be tested for, and (c) when a value that is part of set X is
    + ** inserted, there is no need to search to see if the same value was
    +@@ -78410,7 +85869,7 @@ case OP_Program: {        /* jump */
    +   if( p->nFrame>=db->aLimit[SQLITE_LIMIT_TRIGGER_DEPTH] ){
    +     rc = SQLITE_ERROR;
    +     sqlite3VdbeError(p, "too many levels of trigger recursion");
    +-    break;
    ++    goto abort_due_to_error;
    +   }
    + 
    +   /* Register pRt is used to store the memory required to save the state
    +@@ -78424,10 +85883,12 @@ case OP_Program: {        /* jump */
    +     ** variable nMem (and later, VdbeFrame.nChildMem) to this value.
    +     */
    +     nMem = pProgram->nMem + pProgram->nCsr;
    ++    assert( nMem>0 );
    ++    if( pProgram->nCsr==0 ) nMem++;
    +     nByte = ROUND8(sizeof(VdbeFrame))
    +               + nMem * sizeof(Mem)
    +-              + pProgram->nCsr * sizeof(VdbeCursor *)
    +-              + pProgram->nOnce * sizeof(u8);
    ++              + pProgram->nCsr * sizeof(VdbeCursor*)
    ++              + (pProgram->nOp + 7)/8;
    +     pFrame = sqlite3DbMallocZero(db, nByte);
    +     if( !pFrame ){
    +       goto no_mem;
    +@@ -78447,8 +85908,6 @@ case OP_Program: {        /* jump */
    +     pFrame->aOp = p->aOp;
    +     pFrame->nOp = p->nOp;
    +     pFrame->token = pProgram->token;
    +-    pFrame->aOnceFlag = p->aOnceFlag;
    +-    pFrame->nOnceFlag = p->nOnceFlag;
    + #ifdef SQLITE_ENABLE_STMT_SCANSTATUS
    +     pFrame->anExec = p->anExec;
    + #endif
    +@@ -78460,31 +85919,34 @@ case OP_Program: {        /* jump */
    +     }
    +   }else{
    +     pFrame = pRt->u.pFrame;
    +-    assert( pProgram->nMem+pProgram->nCsr==pFrame->nChildMem );
    ++    assert( pProgram->nMem+pProgram->nCsr==pFrame->nChildMem 
    ++        || (pProgram->nCsr==0 && pProgram->nMem+1==pFrame->nChildMem) );
    +     assert( pProgram->nCsr==pFrame->nChildCsr );
    +     assert( (int)(pOp - aOp)==pFrame->pc );
    +   }
    + 
    +   p->nFrame++;
    +   pFrame->pParent = p->pFrame;
    +-  pFrame->lastRowid = lastRowid;
    ++  pFrame->lastRowid = db->lastRowid;
    +   pFrame->nChange = p->nChange;
    +   pFrame->nDbChange = p->db->nChange;
    ++  assert( pFrame->pAuxData==0 );
    ++  pFrame->pAuxData = p->pAuxData;
    ++  p->pAuxData = 0;
    +   p->nChange = 0;
    +   p->pFrame = pFrame;
    +-  p->aMem = aMem = &VdbeFrameMem(pFrame)[-1];
    ++  p->aMem = aMem = VdbeFrameMem(pFrame);
    +   p->nMem = pFrame->nChildMem;
    +   p->nCursor = (u16)pFrame->nChildCsr;
    +-  p->apCsr = (VdbeCursor **)&aMem[p->nMem+1];
    ++  p->apCsr = (VdbeCursor **)&aMem[p->nMem];
    ++  pFrame->aOnce = (u8*)&p->apCsr[pProgram->nCsr];
    ++  memset(pFrame->aOnce, 0, (pProgram->nOp + 7)/8);
    +   p->aOp = aOp = pProgram->aOp;
    +   p->nOp = pProgram->nOp;
    +-  p->aOnceFlag = (u8 *)&p->apCsr[p->nCursor];
    +-  p->nOnceFlag = pProgram->nOnce;
    + #ifdef SQLITE_ENABLE_STMT_SCANSTATUS
    +   p->anExec = 0;
    + #endif
    +   pOp = &aOp[-1];
    +-  memset(p->aOnceFlag, 0, p->nOnceFlag);
    + 
    +   break;
    + }
    +@@ -78609,37 +86071,61 @@ case OP_IfPos: {        /* jump, in1 */
    +   break;
    + }
    + 
    +-/* Opcode: SetIfNotPos P1 P2 P3 * *
    +-** Synopsis: if r[P1]<=0 then r[P2]=P3
    ++/* Opcode: OffsetLimit P1 P2 P3 * *
    ++** Synopsis: if r[P1]>0 then r[P2]=r[P1]+max(0,r[P3]) else r[P2]=(-1)
    + **
    +-** Register P1 must contain an integer.
    +-** If the value of register P1 is not positive (if it is less than 1) then
    +-** set the value of register P2 to be the integer P3.
    ++** This opcode performs a commonly used computation associated with
    ++** LIMIT and OFFSET process.  r[P1] holds the limit counter.  r[P3]
    ++** holds the offset counter.  The opcode computes the combined value
    ++** of the LIMIT and OFFSET and stores that value in r[P2].  The r[P2]
    ++** value computed is the total number of rows that will need to be
    ++** visited in order to complete the query.
    ++**
    ++** If r[P3] is zero or negative, that means there is no OFFSET
    ++** and r[P2] is set to be the value of the LIMIT, r[P1].
    ++**
    ++** if r[P1] is zero or negative, that means there is no LIMIT
    ++** and r[P2] is set to -1. 
    ++**
    ++** Otherwise, r[P2] is set to the sum of r[P1] and r[P3].
    + */
    +-case OP_SetIfNotPos: {        /* in1, in2 */
    ++case OP_OffsetLimit: {    /* in1, out2, in3 */
    ++  i64 x;
    +   pIn1 = &aMem[pOp->p1];
    +-  assert( pIn1->flags&MEM_Int );
    +-  if( pIn1->u.i<=0 ){
    +-    pOut = out2Prerelease(p, pOp);
    +-    pOut->u.i = pOp->p3;
    ++  pIn3 = &aMem[pOp->p3];
    ++  pOut = out2Prerelease(p, pOp);
    ++  assert( pIn1->flags & MEM_Int );
    ++  assert( pIn3->flags & MEM_Int );
    ++  x = pIn1->u.i;
    ++  if( x<=0 || sqlite3AddInt64(&x, pIn3->u.i>0?pIn3->u.i:0) ){
    ++    /* If the LIMIT is less than or equal to zero, loop forever.  This
    ++    ** is documented.  But also, if the LIMIT+OFFSET exceeds 2^63 then
    ++    ** also loop forever.  This is undocumented.  In fact, one could argue
    ++    ** that the loop should terminate.  But assuming 1 billion iterations
    ++    ** per second (far exceeding the capabilities of any current hardware)
    ++    ** it would take nearly 300 years to actually reach the limit.  So
    ++    ** looping forever is a reasonable approximation. */
    ++    pOut->u.i = -1;
    ++  }else{
    ++    pOut->u.i = x;
    +   }
    +   break;
    + }
    + 
    +-/* Opcode: IfNotZero P1 P2 P3 * *
    +-** Synopsis: if r[P1]!=0 then r[P1]-=P3, goto P2
    ++/* Opcode: IfNotZero P1 P2 * * *
    ++** Synopsis: if r[P1]!=0 then r[P1]--, goto P2
    + **
    + ** Register P1 must contain an integer.  If the content of register P1 is
    +-** initially nonzero, then subtract P3 from the value in register P1 and
    +-** jump to P2.  If register P1 is initially zero, leave it unchanged
    +-** and fall through.
    ++** initially greater than zero, then decrement the value in register P1.
    ++** If it is non-zero (negative or positive) and then also jump to P2.  
    ++** If register P1 is initially zero, leave it unchanged and fall through.
    + */
    + case OP_IfNotZero: {        /* jump, in1 */
    +   pIn1 = &aMem[pOp->p1];
    +   assert( pIn1->flags&MEM_Int );
    +   VdbeBranchTaken(pIn1->u.i<0, 2);
    +   if( pIn1->u.i ){
    +-     pIn1->u.i -= pOp->p3;
    ++     if( pIn1->u.i>0 ) pIn1->u.i--;
    +      goto jump_to_p2;
    +   }
    +   break;
    +@@ -78648,34 +86134,19 @@ case OP_IfNotZero: {        /* jump, in1 */
    + /* Opcode: DecrJumpZero P1 P2 * * *
    + ** Synopsis: if (--r[P1])==0 goto P2
    + **
    +-** Register P1 must hold an integer.  Decrement the value in register P1
    +-** then jump to P2 if the new value is exactly zero.
    ++** Register P1 must hold an integer.  Decrement the value in P1
    ++** and jump to P2 if the new value is exactly zero.
    + */
    + case OP_DecrJumpZero: {      /* jump, in1 */
    +   pIn1 = &aMem[pOp->p1];
    +   assert( pIn1->flags&MEM_Int );
    +-  pIn1->u.i--;
    ++  if( pIn1->u.i>SMALLEST_INT64 ) pIn1->u.i--;
    +   VdbeBranchTaken(pIn1->u.i==0, 2);
    +   if( pIn1->u.i==0 ) goto jump_to_p2;
    +   break;
    + }
    + 
    + 
    +-/* Opcode: JumpZeroIncr P1 P2 * * *
    +-** Synopsis: if (r[P1]++)==0 ) goto P2
    +-**
    +-** The register P1 must contain an integer.  If register P1 is initially
    +-** zero, then jump to P2.  Increment register P1 regardless of whether or
    +-** not the jump is taken.
    +-*/
    +-case OP_JumpZeroIncr: {        /* jump, in1 */
    +-  pIn1 = &aMem[pOp->p1];
    +-  assert( pIn1->flags&MEM_Int );
    +-  VdbeBranchTaken(pIn1->u.i==0, 2);
    +-  if( (pIn1->u.i++)==0 ) goto jump_to_p2;
    +-  break;
    +-}
    +-
    + /* Opcode: AggStep0 * P2 P3 P4 P5
    + ** Synopsis: accum=r[P3] step(r[P2@P5])
    + **
    +@@ -78710,10 +86181,10 @@ case OP_AggStep0: {
    + 
    +   assert( pOp->p4type==P4_FUNCDEF );
    +   n = pOp->p5;
    +-  assert( pOp->p3>0 && pOp->p3<=(p->nMem-p->nCursor) );
    +-  assert( n==0 || (pOp->p2>0 && pOp->p2+n<=(p->nMem-p->nCursor)+1) );
    ++  assert( pOp->p3>0 && pOp->p3<=(p->nMem+1 - p->nCursor) );
    ++  assert( n==0 || (pOp->p2>0 && pOp->p2+n<=(p->nMem+1 - p->nCursor)+1) );
    +   assert( pOp->p3<pOp->p2 || pOp->p3>=pOp->p2+n );
    +-  pCtx = sqlite3DbMallocRaw(db, sizeof(*pCtx) + (n-1)*sizeof(sqlite3_value*));
    ++  pCtx = sqlite3DbMallocRawNN(db, sizeof(*pCtx) + (n-1)*sizeof(sqlite3_value*));
    +   if( pCtx==0 ) goto no_mem;
    +   pCtx->pMem = 0;
    +   pCtx->pFunc = pOp->p4.pFunc;
    +@@ -78756,13 +86227,14 @@ case OP_AggStep: {
    +   pCtx->pOut = &t;
    +   pCtx->fErrorOrAux = 0;
    +   pCtx->skipFlag = 0;
    +-  (pCtx->pFunc->xStep)(pCtx,pCtx->argc,pCtx->argv); /* IMP: R-24505-23230 */
    ++  (pCtx->pFunc->xSFunc)(pCtx,pCtx->argc,pCtx->argv); /* IMP: R-24505-23230 */
    +   if( pCtx->fErrorOrAux ){
    +     if( pCtx->isError ){
    +       sqlite3VdbeError(p, "%s", sqlite3_value_text(&t));
    +       rc = pCtx->isError;
    +     }
    +     sqlite3VdbeMemRelease(&t);
    ++    if( rc ) goto abort_due_to_error;
    +   }else{
    +     assert( t.flags==MEM_Null );
    +   }
    +@@ -78789,12 +86261,13 @@ case OP_AggStep: {
    + */
    + case OP_AggFinal: {
    +   Mem *pMem;
    +-  assert( pOp->p1>0 && pOp->p1<=(p->nMem-p->nCursor) );
    ++  assert( pOp->p1>0 && pOp->p1<=(p->nMem+1 - p->nCursor) );
    +   pMem = &aMem[pOp->p1];
    +   assert( (pMem->flags & ~(MEM_Null|MEM_Agg))==0 );
    +   rc = sqlite3VdbeMemFinalize(pMem, pOp->p4.pFunc);
    +   if( rc ){
    +     sqlite3VdbeError(p, "%s", sqlite3_value_text(pMem));
    ++    goto abort_due_to_error;
    +   }
    +   sqlite3VdbeChangeEncoding(pMem, encoding);
    +   UPDATE_MAX_BLOBSIZE(pMem);
    +@@ -78830,7 +86303,8 @@ case OP_Checkpoint: {
    +        || pOp->p2==SQLITE_CHECKPOINT_TRUNCATE
    +   );
    +   rc = sqlite3Checkpoint(db, pOp->p1, pOp->p2, &aRes[1], &aRes[2]);
    +-  if( rc==SQLITE_BUSY ){
    ++  if( rc ){
    ++    if( rc!=SQLITE_BUSY ) goto abort_due_to_error;
    +     rc = SQLITE_OK;
    +     aRes[0] = 1;
    +   }
    +@@ -78903,7 +86377,7 @@ case OP_JournalMode: {    /* out2 */
    +           "cannot change %s wal mode from within a transaction",
    +           (eNew==PAGER_JOURNALMODE_WAL ? "into" : "out of")
    +       );
    +-      break;
    ++      goto abort_due_to_error;
    +     }else{
    +  
    +       if( eOld==PAGER_JOURNALMODE_WAL ){
    +@@ -78912,7 +86386,7 @@ case OP_JournalMode: {    /* out2 */
    +         ** file. An EXCLUSIVE lock may still be held on the database file 
    +         ** after a successful return. 
    +         */
    +-        rc = sqlite3PagerCloseWal(pPager);
    ++        rc = sqlite3PagerCloseWal(pPager, db);
    +         if( rc==SQLITE_OK ){
    +           sqlite3PagerSetJournalMode(pPager, eNew);
    +         }
    +@@ -78933,9 +86407,7 @@ case OP_JournalMode: {    /* out2 */
    +   }
    + #endif /* ifndef SQLITE_OMIT_WAL */
    + 
    +-  if( rc ){
    +-    eNew = eOld;
    +-  }
    ++  if( rc ) eNew = eOld;
    +   eNew = sqlite3PagerSetJournalMode(pPager, eNew);
    + 
    +   pOut->flags = MEM_Str|MEM_Static|MEM_Term;
    +@@ -78943,20 +86415,21 @@ case OP_JournalMode: {    /* out2 */
    +   pOut->n = sqlite3Strlen30(pOut->z);
    +   pOut->enc = SQLITE_UTF8;
    +   sqlite3VdbeChangeEncoding(pOut, encoding);
    ++  if( rc ) goto abort_due_to_error;
    +   break;
    + };
    + #endif /* SQLITE_OMIT_PRAGMA */
    + 
    + #if !defined(SQLITE_OMIT_VACUUM) && !defined(SQLITE_OMIT_ATTACH)
    +-/* Opcode: Vacuum * * * * *
    ++/* Opcode: Vacuum P1 * * * *
    + **
    +-** Vacuum the entire database.  This opcode will cause other virtual
    +-** machines to be created and run.  It may not be called from within
    +-** a transaction.
    ++** Vacuum the entire database P1.  P1 is 0 for "main", and 2 or more
    ++** for an attached database.  The "temp" database may not be vacuumed.
    + */
    + case OP_Vacuum: {
    +   assert( p->readOnly==0 );
    +-  rc = sqlite3RunVacuum(&p->zErrMsg, db);
    ++  rc = sqlite3RunVacuum(&p->zErrMsg, db, pOp->p1);
    ++  if( rc ) goto abort_due_to_error;
    +   break;
    + }
    + #endif
    +@@ -78977,7 +86450,8 @@ case OP_IncrVacuum: {        /* jump */
    +   pBt = db->aDb[pOp->p1].pBt;
    +   rc = sqlite3BtreeIncrVacuum(pBt);
    +   VdbeBranchTaken(rc==SQLITE_DONE,2);
    +-  if( rc==SQLITE_DONE ){
    ++  if( rc ){
    ++    if( rc!=SQLITE_DONE ) goto abort_due_to_error;
    +     rc = SQLITE_OK;
    +     goto jump_to_p2;
    +   }
    +@@ -79022,15 +86496,18 @@ case OP_Expire: {
    + */
    + case OP_TableLock: {
    +   u8 isWriteLock = (u8)pOp->p3;
    +-  if( isWriteLock || 0==(db->flags&SQLITE_ReadUncommitted) ){
    ++  if( isWriteLock || 0==(db->flags&SQLITE_ReadUncommit) ){
    +     int p1 = pOp->p1; 
    +     assert( p1>=0 && p1<db->nDb );
    +     assert( DbMaskTest(p->btreeMask, p1) );
    +     assert( isWriteLock==0 || isWriteLock==1 );
    +     rc = sqlite3BtreeLockTable(db->aDb[p1].pBt, pOp->p2, isWriteLock);
    +-    if( (rc&0xFF)==SQLITE_LOCKED ){
    +-      const char *z = pOp->p4.z;
    +-      sqlite3VdbeError(p, "database table is locked: %s", z);
    ++    if( rc ){
    ++      if( (rc&0xFF)==SQLITE_LOCKED ){
    ++        const char *z = pOp->p4.z;
    ++        sqlite3VdbeError(p, "database table is locked: %s", z);
    ++      }
    ++      goto abort_due_to_error;
    +     }
    +   }
    +   break;
    +@@ -79052,6 +86529,7 @@ case OP_VBegin: {
    +   pVTab = pOp->p4.pVtab;
    +   rc = sqlite3VtabBegin(db, pVTab);
    +   if( pVTab ) sqlite3VtabImportErrmsg(p, pVTab->pVtab);
    ++  if( rc ) goto abort_due_to_error;
    +   break;
    + }
    + #endif /* SQLITE_OMIT_VIRTUALTABLE */
    +@@ -79080,6 +86558,7 @@ case OP_VCreate: {
    +     rc = sqlite3VtabCallCreate(db, pOp->p1, zTab, &p->zErrMsg);
    +   }
    +   sqlite3VdbeMemRelease(&sMem);
    ++  if( rc ) goto abort_due_to_error;
    +   break;
    + }
    + #endif /* SQLITE_OMIT_VIRTUALTABLE */
    +@@ -79094,6 +86573,7 @@ case OP_VDestroy: {
    +   db->nVDestroy++;
    +   rc = sqlite3VtabCallDestroy(db, pOp->p1, pOp->p4.z);
    +   db->nVDestroy--;
    ++  if( rc ) goto abort_due_to_error;
    +   break;
    + }
    + #endif /* SQLITE_OMIT_VIRTUALTABLE */
    +@@ -79107,35 +86587,35 @@ case OP_VDestroy: {
    + */
    + case OP_VOpen: {
    +   VdbeCursor *pCur;
    +-  sqlite3_vtab_cursor *pVtabCursor;
    ++  sqlite3_vtab_cursor *pVCur;
    +   sqlite3_vtab *pVtab;
    +   const sqlite3_module *pModule;
    + 
    +   assert( p->bIsReader );
    +   pCur = 0;
    +-  pVtabCursor = 0;
    ++  pVCur = 0;
    +   pVtab = pOp->p4.pVtab->pVtab;
    +   if( pVtab==0 || NEVER(pVtab->pModule==0) ){
    +     rc = SQLITE_LOCKED;
    +-    break;
    ++    goto abort_due_to_error;
    +   }
    +   pModule = pVtab->pModule;
    +-  rc = pModule->xOpen(pVtab, &pVtabCursor);
    ++  rc = pModule->xOpen(pVtab, &pVCur);
    +   sqlite3VtabImportErrmsg(p, pVtab);
    +-  if( SQLITE_OK==rc ){
    +-    /* Initialize sqlite3_vtab_cursor base class */
    +-    pVtabCursor->pVtab = pVtab;
    ++  if( rc ) goto abort_due_to_error;
    + 
    +-    /* Initialize vdbe cursor object */
    +-    pCur = allocateCursor(p, pOp->p1, 0, -1, 0);
    +-    if( pCur ){
    +-      pCur->pVtabCursor = pVtabCursor;
    +-      pVtab->nRef++;
    +-    }else{
    +-      assert( db->mallocFailed );
    +-      pModule->xClose(pVtabCursor);
    +-      goto no_mem;
    +-    }
    ++  /* Initialize sqlite3_vtab_cursor base class */
    ++  pVCur->pVtab = pVtab;
    ++
    ++  /* Initialize vdbe cursor object */
    ++  pCur = allocateCursor(p, pOp->p1, 0, -1, CURTYPE_VTAB);
    ++  if( pCur ){
    ++    pCur->uc.pVCur = pVCur;
    ++    pVtab->nRef++;
    ++  }else{
    ++    assert( db->mallocFailed );
    ++    pModule->xClose(pVCur);
    ++    goto no_mem;
    +   }
    +   break;
    + }
    +@@ -79167,7 +86647,7 @@ case OP_VFilter: {   /* jump */
    +   const sqlite3_module *pModule;
    +   Mem *pQuery;
    +   Mem *pArgc;
    +-  sqlite3_vtab_cursor *pVtabCursor;
    ++  sqlite3_vtab_cursor *pVCur;
    +   sqlite3_vtab *pVtab;
    +   VdbeCursor *pCur;
    +   int res;
    +@@ -79179,9 +86659,9 @@ case OP_VFilter: {   /* jump */
    +   pCur = p->apCsr[pOp->p1];
    +   assert( memIsValid(pQuery) );
    +   REGISTER_TRACE(pOp->p3, pQuery);
    +-  assert( pCur->pVtabCursor );
    +-  pVtabCursor = pCur->pVtabCursor;
    +-  pVtab = pVtabCursor->pVtab;
    ++  assert( pCur->eCurType==CURTYPE_VTAB );
    ++  pVCur = pCur->uc.pVCur;
    ++  pVtab = pVCur->pVtab;
    +   pModule = pVtab->pModule;
    + 
    +   /* Grab the index number and argc parameters */
    +@@ -79195,11 +86675,10 @@ case OP_VFilter: {   /* jump */
    +   for(i = 0; i<nArg; i++){
    +     apArg[i] = &pArgc[i+1];
    +   }
    +-  rc = pModule->xFilter(pVtabCursor, iQuery, pOp->p4.z, nArg, apArg);
    ++  rc = pModule->xFilter(pVCur, iQuery, pOp->p4.z, nArg, apArg);
    +   sqlite3VtabImportErrmsg(p, pVtab);
    +-  if( rc==SQLITE_OK ){
    +-    res = pModule->xEof(pVtabCursor);
    +-  }
    ++  if( rc ) goto abort_due_to_error;
    ++  res = pModule->xEof(pVCur);
    +   pCur->nullRow = 0;
    +   VdbeBranchTaken(res!=0,2);
    +   if( res ) goto jump_to_p2;
    +@@ -79208,12 +86687,18 @@ case OP_VFilter: {   /* jump */
    + #endif /* SQLITE_OMIT_VIRTUALTABLE */
    + 
    + #ifndef SQLITE_OMIT_VIRTUALTABLE
    +-/* Opcode: VColumn P1 P2 P3 * *
    ++/* Opcode: VColumn P1 P2 P3 * P5
    + ** Synopsis: r[P3]=vcolumn(P2)
    + **
    +-** Store the value of the P2-th column of
    +-** the row of the virtual-table that the 
    +-** P1 cursor is pointing to into register P3.
    ++** Store in register P3 the value of the P2-th column of
    ++** the current row of the virtual-table of cursor P1.
    ++**
    ++** If the VColumn opcode is being used to fetch the value of
    ++** an unchanging column during an UPDATE operation, then the P5
    ++** value is 1.  Otherwise, P5 is 0.  The P5 value is returned
    ++** by sqlite3_vtab_nochange() routine can can be used
    ++** by virtual table implementations to return special "no-change"
    ++** marks which can be more efficient, depending on the virtual table.
    + */
    + case OP_VColumn: {
    +   sqlite3_vtab *pVtab;
    +@@ -79222,21 +86707,27 @@ case OP_VColumn: {
    +   sqlite3_context sContext;
    + 
    +   VdbeCursor *pCur = p->apCsr[pOp->p1];
    +-  assert( pCur->pVtabCursor );
    +-  assert( pOp->p3>0 && pOp->p3<=(p->nMem-p->nCursor) );
    ++  assert( pCur->eCurType==CURTYPE_VTAB );
    ++  assert( pOp->p3>0 && pOp->p3<=(p->nMem+1 - p->nCursor) );
    +   pDest = &aMem[pOp->p3];
    +   memAboutToChange(p, pDest);
    +   if( pCur->nullRow ){
    +     sqlite3VdbeMemSetNull(pDest);
    +     break;
    +   }
    +-  pVtab = pCur->pVtabCursor->pVtab;
    ++  pVtab = pCur->uc.pVCur->pVtab;
    +   pModule = pVtab->pModule;
    +   assert( pModule->xColumn );
    +   memset(&sContext, 0, sizeof(sContext));
    +   sContext.pOut = pDest;
    +-  MemSetTypeFlag(pDest, MEM_Null);
    +-  rc = pModule->xColumn(pCur->pVtabCursor, &sContext, pOp->p2);
    ++  if( pOp->p5 ){
    ++    sqlite3VdbeMemSetNull(pDest);
    ++    pDest->flags = MEM_Null|MEM_Zero;
    ++    pDest->u.nZero = 0;
    ++  }else{
    ++    MemSetTypeFlag(pDest, MEM_Null);
    ++  }
    ++  rc = pModule->xColumn(pCur->uc.pVCur, &sContext, pOp->p2);
    +   sqlite3VtabImportErrmsg(p, pVtab);
    +   if( sContext.isError ){
    +     rc = sContext.isError;
    +@@ -79248,6 +86739,7 @@ case OP_VColumn: {
    +   if( sqlite3VdbeMemTooBig(pDest) ){
    +     goto too_big;
    +   }
    ++  if( rc ) goto abort_due_to_error;
    +   break;
    + }
    + #endif /* SQLITE_OMIT_VIRTUALTABLE */
    +@@ -79267,11 +86759,11 @@ case OP_VNext: {   /* jump */
    + 
    +   res = 0;
    +   pCur = p->apCsr[pOp->p1];
    +-  assert( pCur->pVtabCursor );
    ++  assert( pCur->eCurType==CURTYPE_VTAB );
    +   if( pCur->nullRow ){
    +     break;
    +   }
    +-  pVtab = pCur->pVtabCursor->pVtab;
    ++  pVtab = pCur->uc.pVCur->pVtab;
    +   pModule = pVtab->pModule;
    +   assert( pModule->xNext );
    + 
    +@@ -79281,11 +86773,10 @@ case OP_VNext: {   /* jump */
    +   ** data is available) and the error code returned when xColumn or
    +   ** some other method is next invoked on the save virtual table cursor.
    +   */
    +-  rc = pModule->xNext(pCur->pVtabCursor);
    ++  rc = pModule->xNext(pCur->uc.pVCur);
    +   sqlite3VtabImportErrmsg(p, pVtab);
    +-  if( rc==SQLITE_OK ){
    +-    res = pModule->xEof(pCur->pVtabCursor);
    +-  }
    ++  if( rc ) goto abort_due_to_error;
    ++  res = pModule->xEof(pCur->uc.pVCur);
    +   VdbeBranchTaken(!res,2);
    +   if( !res ){
    +     /* If there is data, jump to P2 */
    +@@ -79317,11 +86808,11 @@ case OP_VRename: {
    +   testcase( pName->enc==SQLITE_UTF16BE );
    +   testcase( pName->enc==SQLITE_UTF16LE );
    +   rc = sqlite3VdbeChangeEncoding(pName, SQLITE_UTF8);
    +-  if( rc==SQLITE_OK ){
    +-    rc = pVtab->pModule->xRename(pVtab, pName->z);
    +-    sqlite3VtabImportErrmsg(p, pVtab);
    +-    p->expired = 0;
    +-  }
    ++  if( rc ) goto abort_due_to_error;
    ++  rc = pVtab->pModule->xRename(pVtab, pName->z);
    ++  sqlite3VtabImportErrmsg(p, pVtab);
    ++  p->expired = 0;
    ++  if( rc ) goto abort_due_to_error;
    +   break;
    + }
    + #endif
    +@@ -79370,7 +86861,7 @@ case OP_VUpdate: {
    +   pVtab = pOp->p4.pVtab->pVtab;
    +   if( pVtab==0 || NEVER(pVtab->pModule==0) ){
    +     rc = SQLITE_LOCKED;
    +-    break;
    ++    goto abort_due_to_error;
    +   }
    +   pModule = pVtab->pModule;
    +   nArg = pOp->p2;
    +@@ -79391,7 +86882,7 @@ case OP_VUpdate: {
    +     sqlite3VtabImportErrmsg(p, pVtab);
    +     if( rc==SQLITE_OK && pOp->p1 ){
    +       assert( nArg>1 && apArg[0] && (apArg[0]->flags&MEM_Null) );
    +-      db->lastRowid = lastRowid = rowid;
    ++      db->lastRowid = rowid;
    +     }
    +     if( (rc&0xff)==SQLITE_CONSTRAINT && pOp->p4.pVtab->bConstraint ){
    +       if( pOp->p5==OE_Ignore ){
    +@@ -79402,6 +86893,7 @@ case OP_VUpdate: {
    +     }else{
    +       p->nChange++;
    +     }
    ++    if( rc ) goto abort_due_to_error;
    +   }
    +   break;
    + }
    +@@ -79445,9 +86937,130 @@ case OP_MaxPgcnt: {            /* out2 */
    + }
    + #endif
    + 
    ++/* Opcode: Function0 P1 P2 P3 P4 P5
    ++** Synopsis: r[P3]=func(r[P2@P5])
    ++**
    ++** Invoke a user function (P4 is a pointer to a FuncDef object that
    ++** defines the function) with P5 arguments taken from register P2 and
    ++** successors.  The result of the function is stored in register P3.
    ++** Register P3 must not be one of the function inputs.
    ++**
    ++** P1 is a 32-bit bitmask indicating whether or not each argument to the 
    ++** function was determined to be constant at compile time. If the first
    ++** argument was constant then bit 0 of P1 is set. This is used to determine
    ++** whether meta data associated with a user function argument using the
    ++** sqlite3_set_auxdata() API may be safely retained until the next
    ++** invocation of this opcode.
    ++**
    ++** See also: Function, AggStep, AggFinal
    ++*/
    ++/* Opcode: Function P1 P2 P3 P4 P5
    ++** Synopsis: r[P3]=func(r[P2@P5])
    ++**
    ++** Invoke a user function (P4 is a pointer to an sqlite3_context object that
    ++** contains a pointer to the function to be run) with P5 arguments taken
    ++** from register P2 and successors.  The result of the function is stored
    ++** in register P3.  Register P3 must not be one of the function inputs.
    ++**
    ++** P1 is a 32-bit bitmask indicating whether or not each argument to the 
    ++** function was determined to be constant at compile time. If the first
    ++** argument was constant then bit 0 of P1 is set. This is used to determine
    ++** whether meta data associated with a user function argument using the
    ++** sqlite3_set_auxdata() API may be safely retained until the next
    ++** invocation of this opcode.
    ++**
    ++** SQL functions are initially coded as OP_Function0 with P4 pointing
    ++** to a FuncDef object.  But on first evaluation, the P4 operand is
    ++** automatically converted into an sqlite3_context object and the operation
    ++** changed to this OP_Function opcode.  In this way, the initialization of
    ++** the sqlite3_context object occurs only once, rather than once for each
    ++** evaluation of the function.
    ++**
    ++** See also: Function0, AggStep, AggFinal
    ++*/
    ++case OP_PureFunc0:
    ++case OP_Function0: {
    ++  int n;
    ++  sqlite3_context *pCtx;
    ++
    ++  assert( pOp->p4type==P4_FUNCDEF );
    ++  n = pOp->p5;
    ++  assert( pOp->p3>0 && pOp->p3<=(p->nMem+1 - p->nCursor) );
    ++  assert( n==0 || (pOp->p2>0 && pOp->p2+n<=(p->nMem+1 - p->nCursor)+1) );
    ++  assert( pOp->p3<pOp->p2 || pOp->p3>=pOp->p2+n );
    ++  pCtx = sqlite3DbMallocRawNN(db, sizeof(*pCtx) + (n-1)*sizeof(sqlite3_value*));
    ++  if( pCtx==0 ) goto no_mem;
    ++  pCtx->pOut = 0;
    ++  pCtx->pFunc = pOp->p4.pFunc;
    ++  pCtx->iOp = (int)(pOp - aOp);
    ++  pCtx->pVdbe = p;
    ++  pCtx->argc = n;
    ++  pOp->p4type = P4_FUNCCTX;
    ++  pOp->p4.pCtx = pCtx;
    ++  assert( OP_PureFunc == OP_PureFunc0+2 );
    ++  assert( OP_Function == OP_Function0+2 );
    ++  pOp->opcode += 2;
    ++  /* Fall through into OP_Function */
    ++}
    ++case OP_PureFunc:
    ++case OP_Function: {
    ++  int i;
    ++  sqlite3_context *pCtx;
    ++
    ++  assert( pOp->p4type==P4_FUNCCTX );
    ++  pCtx = pOp->p4.pCtx;
    ++
    ++  /* If this function is inside of a trigger, the register array in aMem[]
    ++  ** might change from one evaluation to the next.  The next block of code
    ++  ** checks to see if the register array has changed, and if so it
    ++  ** reinitializes the relavant parts of the sqlite3_context object */
    ++  pOut = &aMem[pOp->p3];
    ++  if( pCtx->pOut != pOut ){
    ++    pCtx->pOut = pOut;
    ++    for(i=pCtx->argc-1; i>=0; i--) pCtx->argv[i] = &aMem[pOp->p2+i];
    ++  }
    ++
    ++  memAboutToChange(p, pOut);
    ++#ifdef SQLITE_DEBUG
    ++  for(i=0; i<pCtx->argc; i++){
    ++    assert( memIsValid(pCtx->argv[i]) );
    ++    REGISTER_TRACE(pOp->p2+i, pCtx->argv[i]);
    ++  }
    ++#endif
    ++  MemSetTypeFlag(pOut, MEM_Null);
    ++  pCtx->fErrorOrAux = 0;
    ++  (*pCtx->pFunc->xSFunc)(pCtx, pCtx->argc, pCtx->argv);/* IMP: R-24505-23230 */
    ++
    ++  /* If the function returned an error, throw an exception */
    ++  if( pCtx->fErrorOrAux ){
    ++    if( pCtx->isError ){
    ++      sqlite3VdbeError(p, "%s", sqlite3_value_text(pOut));
    ++      rc = pCtx->isError;
    ++    }
    ++    sqlite3VdbeDeleteAuxData(db, &p->pAuxData, pCtx->iOp, pOp->p1);
    ++    if( rc ) goto abort_due_to_error;
    ++  }
    ++
    ++  /* Copy the result of the function into register P3 */
    ++  if( pOut->flags & (MEM_Str|MEM_Blob) ){
    ++    sqlite3VdbeChangeEncoding(pOut, encoding);
    ++    if( sqlite3VdbeMemTooBig(pOut) ) goto too_big;
    ++  }
    + 
    +-/* Opcode: Init * P2 * P4 *
    +-** Synopsis:  Start at P2
    ++  REGISTER_TRACE(pOp->p3, pOut);
    ++  UPDATE_MAX_BLOBSIZE(pOut);
    ++  break;
    ++}
    ++
    ++/* Opcode: Trace P1 P2 * P4 *
    ++**
    ++** Write P4 on the statement trace output if statement tracing is
    ++** enabled.
    ++**
    ++** Operand P1 must be 0x7fffffff and P2 must positive.
    ++*/
    ++/* Opcode: Init P1 P2 P3 P4 *
    ++** Synopsis: Start at P2
    + **
    + ** Programs contain a single instance of this opcode as the very first
    + ** opcode.
    +@@ -79457,27 +87070,60 @@ case OP_MaxPgcnt: {            /* out2 */
    + ** Or if P4 is blank, use the string returned by sqlite3_sql().
    + **
    + ** If P2 is not zero, jump to instruction P2.
    ++**
    ++** Increment the value of P1 so that OP_Once opcodes will jump the
    ++** first time they are evaluated for this run.
    ++**
    ++** If P3 is not zero, then it is an address to jump to if an SQLITE_CORRUPT
    ++** error is encountered.
    + */
    ++case OP_Trace:
    + case OP_Init: {          /* jump */
    +   char *zTrace;
    +-  char *z;
    ++  int i;
    ++
    ++  /* If the P4 argument is not NULL, then it must be an SQL comment string.
    ++  ** The "--" string is broken up to prevent false-positives with srcck1.c.
    ++  **
    ++  ** This assert() provides evidence for:
    ++  ** EVIDENCE-OF: R-50676-09860 The callback can compute the same text that
    ++  ** would have been returned by the legacy sqlite3_trace() interface by
    ++  ** using the X argument when X begins with "--" and invoking
    ++  ** sqlite3_expanded_sql(P) otherwise.
    ++  */
    ++  assert( pOp->p4.z==0 || strncmp(pOp->p4.z, "-" "- ", 3)==0 );
    ++
    ++  /* OP_Init is always instruction 0 */
    ++  assert( pOp==p->aOp || pOp->opcode==OP_Trace );
    + 
    + #ifndef SQLITE_OMIT_TRACE
    +-  if( db->xTrace
    ++  if( (db->mTrace & (SQLITE_TRACE_STMT|SQLITE_TRACE_LEGACY))!=0
    +    && !p->doingRerun
    +    && (zTrace = (pOp->p4.z ? pOp->p4.z : p->zSql))!=0
    +   ){
    +-    z = sqlite3VdbeExpandSql(p, zTrace);
    +-    db->xTrace(db->pTraceArg, z);
    +-    sqlite3DbFree(db, z);
    ++#ifndef SQLITE_OMIT_DEPRECATED
    ++    if( db->mTrace & SQLITE_TRACE_LEGACY ){
    ++      void (*x)(void*,const char*) = (void(*)(void*,const char*))db->xTrace;
    ++      char *z = sqlite3VdbeExpandSql(p, zTrace);
    ++      x(db->pTraceArg, z);
    ++      sqlite3_free(z);
    ++    }else
    ++#endif
    ++    if( db->nVdbeExec>1 ){
    ++      char *z = sqlite3MPrintf(db, "-- %s", zTrace);
    ++      (void)db->xTrace(SQLITE_TRACE_STMT, db->pTraceArg, p, z);
    ++      sqlite3DbFree(db, z);
    ++    }else{
    ++      (void)db->xTrace(SQLITE_TRACE_STMT, db->pTraceArg, p, zTrace);
    ++    }
    +   }
    + #ifdef SQLITE_USE_FCNTL_TRACE
    +   zTrace = (pOp->p4.z ? pOp->p4.z : p->zSql);
    +   if( zTrace ){
    +-    int i;
    +-    for(i=0; i<db->nDb; i++){
    +-      if( DbMaskTest(p->btreeMask, i)==0 ) continue;
    +-      sqlite3_file_control(db, db->aDb[i].zName, SQLITE_FCNTL_TRACE, zTrace);
    ++    int j;
    ++    for(j=0; j<db->nDb; j++){
    ++      if( DbMaskTest(p->btreeMask, j)==0 ) continue;
    ++      sqlite3_file_control(db, db->aDb[j].zDbSName, SQLITE_FCNTL_TRACE, zTrace);
    +     }
    +   }
    + #endif /* SQLITE_USE_FCNTL_TRACE */
    +@@ -79489,10 +87135,41 @@ case OP_Init: {          /* jump */
    +   }
    + #endif /* SQLITE_DEBUG */
    + #endif /* SQLITE_OMIT_TRACE */
    +-  if( pOp->p2 ) goto jump_to_p2;
    +-  break;
    ++  assert( pOp->p2>0 );
    ++  if( pOp->p1>=sqlite3GlobalConfig.iOnceResetThreshold ){
    ++    if( pOp->opcode==OP_Trace ) break;
    ++    for(i=1; i<p->nOp; i++){
    ++      if( p->aOp[i].opcode==OP_Once ) p->aOp[i].p1 = 0;
    ++    }
    ++    pOp->p1 = 0;
    ++  }
    ++  pOp->p1++;
    ++  p->aCounter[SQLITE_STMTSTATUS_RUN]++;
    ++  goto jump_to_p2;
    + }
    + 
    ++#ifdef SQLITE_ENABLE_CURSOR_HINTS
    ++/* Opcode: CursorHint P1 * * P4 *
    ++**
    ++** Provide a hint to cursor P1 that it only needs to return rows that
    ++** satisfy the Expr in P4.  TK_REGISTER terms in the P4 expression refer
    ++** to values currently held in registers.  TK_COLUMN terms in the P4
    ++** expression refer to columns in the b-tree to which cursor P1 is pointing.
    ++*/
    ++case OP_CursorHint: {
    ++  VdbeCursor *pC;
    ++
    ++  assert( pOp->p1>=0 && pOp->p1<p->nCursor );
    ++  assert( pOp->p4type==P4_EXPR );
    ++  pC = p->apCsr[pOp->p1];
    ++  if( pC ){
    ++    assert( pC->eCurType==CURTYPE_BTREE );
    ++    sqlite3BtreeCursorHint(pC->uc.pCursor, BTREE_HINT_RANGE,
    ++                           pOp->p4.pExpr, aMem);
    ++  }
    ++  break;
    ++}
    ++#endif /* SQLITE_ENABLE_CURSOR_HINTS */
    + 
    + /* Opcode: Noop * * * * *
    + **
    +@@ -79536,11 +87213,12 @@ default: {          /* This is really OP_Noop and OP_Explain */
    + 
    + #ifdef SQLITE_DEBUG
    +     if( db->flags & SQLITE_VdbeTrace ){
    ++      u8 opProperty = sqlite3OpcodeProperty[pOrigOp->opcode];
    +       if( rc!=0 ) printf("rc=%d\n",rc);
    +-      if( pOrigOp->opflags & (OPFLG_OUT2) ){
    ++      if( opProperty & (OPFLG_OUT2) ){
    +         registerTrace(pOrigOp->p2, &aMem[pOrigOp->p2]);
    +       }
    +-      if( pOrigOp->opflags & OPFLG_OUT3 ){
    ++      if( opProperty & OPFLG_OUT3 ){
    +         registerTrace(pOrigOp->p3, &aMem[pOrigOp->p3]);
    +       }
    +     }
    +@@ -79551,14 +87229,19 @@ default: {          /* This is really OP_Noop and OP_Explain */
    +   /* If we reach this point, it means that execution is finished with
    +   ** an error of some kind.
    +   */
    +-vdbe_error_halt:
    ++abort_due_to_error:
    ++  if( db->mallocFailed ) rc = SQLITE_NOMEM_BKPT;
    +   assert( rc );
    ++  if( p->zErrMsg==0 && rc!=SQLITE_IOERR_NOMEM ){
    ++    sqlite3VdbeError(p, "%s", sqlite3ErrStr(rc));
    ++  }
    +   p->rc = rc;
    ++  sqlite3SystemError(db, rc);
    +   testcase( sqlite3GlobalConfig.xLog!=0 );
    +   sqlite3_log(rc, "statement aborts at %d: [%s] %s", 
    +                    (int)(pOp - aOp), p->zSql, p->zErrMsg);
    +   sqlite3VdbeHalt(p);
    +-  if( rc==SQLITE_IOERR_NOMEM ) db->mallocFailed = 1;
    ++  if( rc==SQLITE_IOERR_NOMEM ) sqlite3OomFault(db);
    +   rc = SQLITE_ERROR;
    +   if( resetSchemaOnFault>0 ){
    +     sqlite3ResetOneSchema(db, resetSchemaOnFault-1);
    +@@ -79568,10 +87251,12 @@ vdbe_error_halt:
    +   ** release the mutexes on btrees that were acquired at the
    +   ** top. */
    + vdbe_return:
    +-  db->lastRowid = lastRowid;
    +   testcase( nVmStep>0 );
    +   p->aCounter[SQLITE_STMTSTATUS_VM_STEP] += (int)nVmStep;
    +   sqlite3VdbeLeave(p);
    ++  assert( rc!=SQLITE_OK || nExtraDelete==0 
    ++       || sqlite3_strlike("DELETE%",p->zSql,0)!=0 
    ++  );
    +   return rc;
    + 
    +   /* Jump to here if a string or blob larger than SQLITE_MAX_LENGTH
    +@@ -79580,36 +87265,25 @@ vdbe_return:
    + too_big:
    +   sqlite3VdbeError(p, "string or blob too big");
    +   rc = SQLITE_TOOBIG;
    +-  goto vdbe_error_halt;
    ++  goto abort_due_to_error;
    + 
    +   /* Jump to here if a malloc() fails.
    +   */
    + no_mem:
    +-  db->mallocFailed = 1;
    ++  sqlite3OomFault(db);
    +   sqlite3VdbeError(p, "out of memory");
    +-  rc = SQLITE_NOMEM;
    +-  goto vdbe_error_halt;
    +-
    +-  /* Jump to here for any other kind of fatal error.  The "rc" variable
    +-  ** should hold the error number.
    +-  */
    +-abort_due_to_error:
    +-  assert( p->zErrMsg==0 );
    +-  if( db->mallocFailed ) rc = SQLITE_NOMEM;
    +-  if( rc!=SQLITE_IOERR_NOMEM ){
    +-    sqlite3VdbeError(p, "%s", sqlite3ErrStr(rc));
    +-  }
    +-  goto vdbe_error_halt;
    ++  rc = SQLITE_NOMEM_BKPT;
    ++  goto abort_due_to_error;
    + 
    +   /* Jump to here if the sqlite3_interrupt() API sets the interrupt
    +   ** flag.
    +   */
    + abort_due_to_interrupt:
    +   assert( db->u1.isInterrupted );
    +-  rc = SQLITE_INTERRUPT;
    ++  rc = db->mallocFailed ? SQLITE_NOMEM_BKPT : SQLITE_INTERRUPT;
    +   p->rc = rc;
    +   sqlite3VdbeError(p, "%s", sqlite3ErrStr(rc));
    +-  goto vdbe_error_halt;
    ++  goto abort_due_to_error;
    + }
    + 
    + 
    +@@ -79640,13 +87314,14 @@ abort_due_to_interrupt:
    + */
    + typedef struct Incrblob Incrblob;
    + struct Incrblob {
    +-  int flags;              /* Copy of "flags" passed to sqlite3_blob_open() */
    +   int nByte;              /* Size of open blob, in bytes */
    +   int iOffset;            /* Byte offset of blob in cursor data */
    +-  int iCol;               /* Table column this handle is open on */
    ++  u16 iCol;               /* Table column this handle is open on */
    +   BtCursor *pCsr;         /* Cursor pointing at blob row */
    +   sqlite3_stmt *pStmt;    /* Statement holding cursor open */
    +   sqlite3 *db;            /* The associated database */
    ++  char *zDb;              /* Database name */
    ++  Table *pTab;            /* Table object */
    + };
    + 
    + 
    +@@ -79672,17 +87347,28 @@ static int blobSeekToRow(Incrblob *p, sqlite3_int64 iRow, char **pzErr){
    +   char *zErr = 0;                 /* Error message */
    +   Vdbe *v = (Vdbe *)p->pStmt;
    + 
    +-  /* Set the value of the SQL statements only variable to integer iRow. 
    +-  ** This is done directly instead of using sqlite3_bind_int64() to avoid 
    +-  ** triggering asserts related to mutexes.
    ++  /* Set the value of register r[1] in the SQL statement to integer iRow. 
    ++  ** This is done directly as a performance optimization
    +   */
    +-  assert( v->aVar[0].flags&MEM_Int );
    +-  v->aVar[0].u.i = iRow;
    ++  v->aMem[1].flags = MEM_Int;
    ++  v->aMem[1].u.i = iRow;
    + 
    +-  rc = sqlite3_step(p->pStmt);
    ++  /* If the statement has been run before (and is paused at the OP_ResultRow)
    ++  ** then back it up to the point where it does the OP_NotExists.  This could
    ++  ** have been down with an extra OP_Goto, but simply setting the program
    ++  ** counter is faster. */
    ++  if( v->pc>4 ){
    ++    v->pc = 4;
    ++    assert( v->aOp[v->pc].opcode==OP_NotExists );
    ++    rc = sqlite3VdbeExec(v);
    ++  }else{
    ++    rc = sqlite3_step(p->pStmt);
    ++  }
    +   if( rc==SQLITE_ROW ){
    +     VdbeCursor *pC = v->apCsr[0];
    +-    u32 type = pC->aType[p->iCol];
    ++    u32 type = pC->nHdrParsed>p->iCol ? pC->aType[p->iCol] : 0;
    ++    testcase( pC->nHdrParsed==p->iCol );
    ++    testcase( pC->nHdrParsed==p->iCol+1 );
    +     if( type<12 ){
    +       zErr = sqlite3MPrintf(p->db, "cannot open value of type %s",
    +           type==0?"null": type==7?"real": "integer"
    +@@ -79693,7 +87379,7 @@ static int blobSeekToRow(Incrblob *p, sqlite3_int64 iRow, char **pzErr){
    +     }else{
    +       p->iOffset = pC->aType[p->iCol + pC->nField];
    +       p->nByte = sqlite3VdbeSerialTypeLen(type);
    +-      p->pCsr =  pC->pCursor;
    ++      p->pCsr =  pC->uc.pCursor;
    +       sqlite3BtreeIncrblobCursor(p->pCsr);
    +     }
    +   }
    +@@ -79721,54 +87407,22 @@ static int blobSeekToRow(Incrblob *p, sqlite3_int64 iRow, char **pzErr){
    + /*
    + ** Open a blob handle.
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_blob_open(
    ++SQLITE_API int sqlite3_blob_open(
    +   sqlite3* db,            /* The database connection */
    +   const char *zDb,        /* The attached database containing the blob */
    +   const char *zTable,     /* The table containing the blob */
    +   const char *zColumn,    /* The column containing the blob */
    +   sqlite_int64 iRow,      /* The row containing the glob */
    +-  int flags,              /* True -> read/write access, false -> read-only */
    ++  int wrFlag,             /* True -> read/write access, false -> read-only */
    +   sqlite3_blob **ppBlob   /* Handle for accessing the blob returned here */
    + ){
    +   int nAttempt = 0;
    +   int iCol;               /* Index of zColumn in row-record */
    +-
    +-  /* This VDBE program seeks a btree cursor to the identified 
    +-  ** db/table/row entry. The reason for using a vdbe program instead
    +-  ** of writing code to use the b-tree layer directly is that the
    +-  ** vdbe program will take advantage of the various transaction,
    +-  ** locking and error handling infrastructure built into the vdbe.
    +-  **
    +-  ** After seeking the cursor, the vdbe executes an OP_ResultRow.
    +-  ** Code external to the Vdbe then "borrows" the b-tree cursor and
    +-  ** uses it to implement the blob_read(), blob_write() and 
    +-  ** blob_bytes() functions.
    +-  **
    +-  ** The sqlite3_blob_close() function finalizes the vdbe program,
    +-  ** which closes the b-tree cursor and (possibly) commits the 
    +-  ** transaction.
    +-  */
    +-  static const int iLn = VDBE_OFFSET_LINENO(4);
    +-  static const VdbeOpList openBlob[] = {
    +-    /* {OP_Transaction, 0, 0, 0},  // 0: Inserted separately */
    +-    {OP_TableLock, 0, 0, 0},       /* 1: Acquire a read or write lock */
    +-    /* One of the following two instructions is replaced by an OP_Noop. */
    +-    {OP_OpenRead, 0, 0, 0},        /* 2: Open cursor 0 for reading */
    +-    {OP_OpenWrite, 0, 0, 0},       /* 3: Open cursor 0 for read/write */
    +-    {OP_Variable, 1, 1, 1},        /* 4: Push the rowid to the stack */
    +-    {OP_NotExists, 0, 10, 1},      /* 5: Seek the cursor */
    +-    {OP_Column, 0, 0, 1},          /* 6  */
    +-    {OP_ResultRow, 1, 0, 0},       /* 7  */
    +-    {OP_Goto, 0, 4, 0},            /* 8  */
    +-    {OP_Close, 0, 0, 0},           /* 9  */
    +-    {OP_Halt, 0, 0, 0},            /* 10 */
    +-  };
    +-
    +   int rc = SQLITE_OK;
    +   char *zErr = 0;
    +   Table *pTab;
    +-  Parse *pParse = 0;
    +   Incrblob *pBlob = 0;
    ++  Parse sParse;
    + 
    + #ifdef SQLITE_ENABLE_API_ARMOR
    +   if( ppBlob==0 ){
    +@@ -79781,47 +87435,46 @@ SQLITE_API int SQLITE_STDCALL sqlite3_blob_open(
    +     return SQLITE_MISUSE_BKPT;
    +   }
    + #endif
    +-  flags = !!flags;                /* flags = (flags ? 1 : 0); */
    ++  wrFlag = !!wrFlag;                /* wrFlag = (wrFlag ? 1 : 0); */
    + 
    +   sqlite3_mutex_enter(db->mutex);
    + 
    +   pBlob = (Incrblob *)sqlite3DbMallocZero(db, sizeof(Incrblob));
    +-  if( !pBlob ) goto blob_open_out;
    +-  pParse = sqlite3StackAllocRaw(db, sizeof(*pParse));
    +-  if( !pParse ) goto blob_open_out;
    +-
    +   do {
    +-    memset(pParse, 0, sizeof(Parse));
    +-    pParse->db = db;
    ++    memset(&sParse, 0, sizeof(Parse));
    ++    if( !pBlob ) goto blob_open_out;
    ++    sParse.db = db;
    +     sqlite3DbFree(db, zErr);
    +     zErr = 0;
    + 
    +     sqlite3BtreeEnterAll(db);
    +-    pTab = sqlite3LocateTable(pParse, 0, zTable, zDb);
    ++    pTab = sqlite3LocateTable(&sParse, 0, zTable, zDb);
    +     if( pTab && IsVirtual(pTab) ){
    +       pTab = 0;
    +-      sqlite3ErrorMsg(pParse, "cannot open virtual table: %s", zTable);
    ++      sqlite3ErrorMsg(&sParse, "cannot open virtual table: %s", zTable);
    +     }
    +     if( pTab && !HasRowid(pTab) ){
    +       pTab = 0;
    +-      sqlite3ErrorMsg(pParse, "cannot open table without rowid: %s", zTable);
    ++      sqlite3ErrorMsg(&sParse, "cannot open table without rowid: %s", zTable);
    +     }
    + #ifndef SQLITE_OMIT_VIEW
    +     if( pTab && pTab->pSelect ){
    +       pTab = 0;
    +-      sqlite3ErrorMsg(pParse, "cannot open view: %s", zTable);
    ++      sqlite3ErrorMsg(&sParse, "cannot open view: %s", zTable);
    +     }
    + #endif
    +     if( !pTab ){
    +-      if( pParse->zErrMsg ){
    ++      if( sParse.zErrMsg ){
    +         sqlite3DbFree(db, zErr);
    +-        zErr = pParse->zErrMsg;
    +-        pParse->zErrMsg = 0;
    ++        zErr = sParse.zErrMsg;
    ++        sParse.zErrMsg = 0;
    +       }
    +       rc = SQLITE_ERROR;
    +       sqlite3BtreeLeaveAll(db);
    +       goto blob_open_out;
    +     }
    ++    pBlob->pTab = pTab;
    ++    pBlob->zDb = db->aDb[sqlite3SchemaToIndex(db, pTab->pSchema)].zDbSName;
    + 
    +     /* Now search pTab for the exact column. */
    +     for(iCol=0; iCol<pTab->nCol; iCol++) {
    +@@ -79839,9 +87492,8 @@ SQLITE_API int SQLITE_STDCALL sqlite3_blob_open(
    + 
    +     /* If the value is being opened for writing, check that the
    +     ** column is not indexed, and that it is not part of a foreign key. 
    +-    ** It is against the rules to open a column to which either of these
    +-    ** descriptions applies for writing.  */
    +-    if( flags ){
    ++    */
    ++    if( wrFlag ){
    +       const char *zFault = 0;
    +       Index *pIdx;
    + #ifndef SQLITE_OMIT_FOREIGN_KEY
    +@@ -79879,63 +87531,93 @@ SQLITE_API int SQLITE_STDCALL sqlite3_blob_open(
    +       }
    +     }
    + 
    +-    pBlob->pStmt = (sqlite3_stmt *)sqlite3VdbeCreate(pParse);
    ++    pBlob->pStmt = (sqlite3_stmt *)sqlite3VdbeCreate(&sParse);
    +     assert( pBlob->pStmt || db->mallocFailed );
    +     if( pBlob->pStmt ){
    ++      
    ++      /* This VDBE program seeks a btree cursor to the identified 
    ++      ** db/table/row entry. The reason for using a vdbe program instead
    ++      ** of writing code to use the b-tree layer directly is that the
    ++      ** vdbe program will take advantage of the various transaction,
    ++      ** locking and error handling infrastructure built into the vdbe.
    ++      **
    ++      ** After seeking the cursor, the vdbe executes an OP_ResultRow.
    ++      ** Code external to the Vdbe then "borrows" the b-tree cursor and
    ++      ** uses it to implement the blob_read(), blob_write() and 
    ++      ** blob_bytes() functions.
    ++      **
    ++      ** The sqlite3_blob_close() function finalizes the vdbe program,
    ++      ** which closes the b-tree cursor and (possibly) commits the 
    ++      ** transaction.
    ++      */
    ++      static const int iLn = VDBE_OFFSET_LINENO(2);
    ++      static const VdbeOpList openBlob[] = {
    ++        {OP_TableLock,      0, 0, 0},  /* 0: Acquire a read or write lock */
    ++        {OP_OpenRead,       0, 0, 0},  /* 1: Open a cursor */
    ++        /* blobSeekToRow() will initialize r[1] to the desired rowid */
    ++        {OP_NotExists,      0, 5, 1},  /* 2: Seek the cursor to rowid=r[1] */
    ++        {OP_Column,         0, 0, 1},  /* 3  */
    ++        {OP_ResultRow,      1, 0, 0},  /* 4  */
    ++        {OP_Halt,           0, 0, 0},  /* 5  */
    ++      };
    +       Vdbe *v = (Vdbe *)pBlob->pStmt;
    +       int iDb = sqlite3SchemaToIndex(db, pTab->pSchema);
    ++      VdbeOp *aOp;
    + 
    +-
    +-      sqlite3VdbeAddOp4Int(v, OP_Transaction, iDb, flags, 
    ++      sqlite3VdbeAddOp4Int(v, OP_Transaction, iDb, wrFlag, 
    +                            pTab->pSchema->schema_cookie,
    +                            pTab->pSchema->iGeneration);
    +-      sqlite3VdbeChangeP5(v, 1);     
    +-      sqlite3VdbeAddOpList(v, ArraySize(openBlob), openBlob, iLn);
    ++      sqlite3VdbeChangeP5(v, 1);
    ++      assert( sqlite3VdbeCurrentAddr(v)==2 || db->mallocFailed );
    ++      aOp = sqlite3VdbeAddOpList(v, ArraySize(openBlob), openBlob, iLn);
    + 
    +       /* Make sure a mutex is held on the table to be accessed */
    +       sqlite3VdbeUsesBtree(v, iDb); 
    + 
    +-      /* Configure the OP_TableLock instruction */
    ++      if( db->mallocFailed==0 ){
    ++        assert( aOp!=0 );
    ++        /* Configure the OP_TableLock instruction */
    + #ifdef SQLITE_OMIT_SHARED_CACHE
    +-      sqlite3VdbeChangeToNoop(v, 1);
    ++        aOp[0].opcode = OP_Noop;
    + #else
    +-      sqlite3VdbeChangeP1(v, 1, iDb);
    +-      sqlite3VdbeChangeP2(v, 1, pTab->tnum);
    +-      sqlite3VdbeChangeP3(v, 1, flags);
    +-      sqlite3VdbeChangeP4(v, 1, pTab->zName, P4_TRANSIENT);
    +-#endif
    +-
    +-      /* Remove either the OP_OpenWrite or OpenRead. Set the P2 
    +-      ** parameter of the other to pTab->tnum.  */
    +-      sqlite3VdbeChangeToNoop(v, 3 - flags);
    +-      sqlite3VdbeChangeP2(v, 2 + flags, pTab->tnum);
    +-      sqlite3VdbeChangeP3(v, 2 + flags, iDb);
    +-
    +-      /* Configure the number of columns. Configure the cursor to
    +-      ** think that the table has one more column than it really
    +-      ** does. An OP_Column to retrieve this imaginary column will
    +-      ** always return an SQL NULL. This is useful because it means
    +-      ** we can invoke OP_Column to fill in the vdbe cursors type 
    +-      ** and offset cache without causing any IO.
    +-      */
    +-      sqlite3VdbeChangeP4(v, 2+flags, SQLITE_INT_TO_PTR(pTab->nCol+1),P4_INT32);
    +-      sqlite3VdbeChangeP2(v, 6, pTab->nCol);
    +-      if( !db->mallocFailed ){
    +-        pParse->nVar = 1;
    +-        pParse->nMem = 1;
    +-        pParse->nTab = 1;
    +-        sqlite3VdbeMakeReady(v, pParse);
    ++        aOp[0].p1 = iDb;
    ++        aOp[0].p2 = pTab->tnum;
    ++        aOp[0].p3 = wrFlag;
    ++        sqlite3VdbeChangeP4(v, 2, pTab->zName, P4_TRANSIENT);
    ++      }
    ++      if( db->mallocFailed==0 ){
    ++#endif
    ++
    ++        /* Remove either the OP_OpenWrite or OpenRead. Set the P2 
    ++        ** parameter of the other to pTab->tnum.  */
    ++        if( wrFlag ) aOp[1].opcode = OP_OpenWrite;
    ++        aOp[1].p2 = pTab->tnum;
    ++        aOp[1].p3 = iDb;   
    ++
    ++        /* Configure the number of columns. Configure the cursor to
    ++        ** think that the table has one more column than it really
    ++        ** does. An OP_Column to retrieve this imaginary column will
    ++        ** always return an SQL NULL. This is useful because it means
    ++        ** we can invoke OP_Column to fill in the vdbe cursors type 
    ++        ** and offset cache without causing any IO.
    ++        */
    ++        aOp[1].p4type = P4_INT32;
    ++        aOp[1].p4.i = pTab->nCol+1;
    ++        aOp[3].p2 = pTab->nCol;
    ++
    ++        sParse.nVar = 0;
    ++        sParse.nMem = 1;
    ++        sParse.nTab = 1;
    ++        sqlite3VdbeMakeReady(v, &sParse);
    +       }
    +     }
    +    
    +-    pBlob->flags = flags;
    +     pBlob->iCol = iCol;
    +     pBlob->db = db;
    +     sqlite3BtreeLeaveAll(db);
    +     if( db->mallocFailed ){
    +       goto blob_open_out;
    +     }
    +-    sqlite3_bind_int64(pBlob->pStmt, 1, iRow);
    +     rc = blobSeekToRow(pBlob, iRow, &zErr);
    +   } while( (++nAttempt)<SQLITE_MAX_SCHEMA_RETRY && rc==SQLITE_SCHEMA );
    + 
    +@@ -79948,8 +87630,7 @@ blob_open_out:
    +   }
    +   sqlite3ErrorWithMsg(db, rc, (zErr ? "%s" : 0), zErr);
    +   sqlite3DbFree(db, zErr);
    +-  sqlite3ParserReset(pParse);
    +-  sqlite3StackFree(db, pParse);
    ++  sqlite3ParserReset(&sParse);
    +   rc = sqlite3ApiExit(db, rc);
    +   sqlite3_mutex_leave(db->mutex);
    +   return rc;
    +@@ -79959,7 +87640,7 @@ blob_open_out:
    + ** Close a blob handle that was previously created using
    + ** sqlite3_blob_open().
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_blob_close(sqlite3_blob *pBlob){
    ++SQLITE_API int sqlite3_blob_close(sqlite3_blob *pBlob){
    +   Incrblob *p = (Incrblob *)pBlob;
    +   int rc;
    +   sqlite3 *db;
    +@@ -80010,6 +87691,30 @@ static int blobReadWrite(
    +     */
    +     assert( db == v->db );
    +     sqlite3BtreeEnterCursor(p->pCsr);
    ++
    ++#ifdef SQLITE_ENABLE_PREUPDATE_HOOK
    ++    if( xCall==sqlite3BtreePutData && db->xPreUpdateCallback ){
    ++      /* If a pre-update hook is registered and this is a write cursor, 
    ++      ** invoke it here. 
    ++      ** 
    ++      ** TODO: The preupdate-hook is passed SQLITE_DELETE, even though this
    ++      ** operation should really be an SQLITE_UPDATE. This is probably
    ++      ** incorrect, but is convenient because at this point the new.* values 
    ++      ** are not easily obtainable. And for the sessions module, an 
    ++      ** SQLITE_UPDATE where the PK columns do not change is handled in the 
    ++      ** same way as an SQLITE_DELETE (the SQLITE_DELETE code is actually
    ++      ** slightly more efficient). Since you cannot write to a PK column
    ++      ** using the incremental-blob API, this works. For the sessions module
    ++      ** anyhow.
    ++      */
    ++      sqlite3_int64 iKey;
    ++      iKey = sqlite3BtreeIntegerKey(p->pCsr);
    ++      sqlite3VdbePreUpdateHook(
    ++          v, v->apCsr[0], SQLITE_DELETE, p->zDb, p->pTab, iKey, -1
    ++      );
    ++    }
    ++#endif
    ++
    +     rc = xCall(p->pCsr, iOffset+p->iOffset, n, z);
    +     sqlite3BtreeLeaveCursor(p->pCsr);
    +     if( rc==SQLITE_ABORT ){
    +@@ -80028,14 +87733,14 @@ static int blobReadWrite(
    + /*
    + ** Read data from a blob handle.
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_blob_read(sqlite3_blob *pBlob, void *z, int n, int iOffset){
    +-  return blobReadWrite(pBlob, z, n, iOffset, sqlite3BtreeData);
    ++SQLITE_API int sqlite3_blob_read(sqlite3_blob *pBlob, void *z, int n, int iOffset){
    ++  return blobReadWrite(pBlob, z, n, iOffset, sqlite3BtreePayloadChecked);
    + }
    + 
    + /*
    + ** Write data to a blob handle.
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_blob_write(sqlite3_blob *pBlob, const void *z, int n, int iOffset){
    ++SQLITE_API int sqlite3_blob_write(sqlite3_blob *pBlob, const void *z, int n, int iOffset){
    +   return blobReadWrite(pBlob, (void *)z, n, iOffset, sqlite3BtreePutData);
    + }
    + 
    +@@ -80045,7 +87750,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_blob_write(sqlite3_blob *pBlob, const void
    + ** The Incrblob.nByte field is fixed for the lifetime of the Incrblob
    + ** so no mutex is required for access.
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_blob_bytes(sqlite3_blob *pBlob){
    ++SQLITE_API int sqlite3_blob_bytes(sqlite3_blob *pBlob){
    +   Incrblob *p = (Incrblob *)pBlob;
    +   return (p && p->pStmt) ? p->nByte : 0;
    + }
    +@@ -80060,7 +87765,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_blob_bytes(sqlite3_blob *pBlob){
    + ** subsequent calls to sqlite3_blob_xxx() functions (except blob_close()) 
    + ** immediately return SQLITE_ABORT.
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_blob_reopen(sqlite3_blob *pBlob, sqlite3_int64 iRow){
    ++SQLITE_API int sqlite3_blob_reopen(sqlite3_blob *pBlob, sqlite3_int64 iRow){
    +   int rc;
    +   Incrblob *p = (Incrblob *)pBlob;
    +   sqlite3 *db;
    +@@ -80636,7 +88341,7 @@ static int vdbePmaReadBlob(
    +       int nNew = MAX(128, p->nAlloc*2);
    +       while( nByte>nNew ) nNew = nNew*2;
    +       aNew = sqlite3Realloc(p->aAlloc, nNew);
    +-      if( !aNew ) return SQLITE_NOMEM;
    ++      if( !aNew ) return SQLITE_NOMEM_BKPT;
    +       p->nAlloc = nNew;
    +       p->aAlloc = aNew;
    +     }
    +@@ -80748,7 +88453,7 @@ static int vdbePmaReaderSeek(
    +     int iBuf = pReadr->iReadOff % pgsz;
    +     if( pReadr->aBuffer==0 ){
    +       pReadr->aBuffer = (u8*)sqlite3Malloc(pgsz);
    +-      if( pReadr->aBuffer==0 ) rc = SQLITE_NOMEM;
    ++      if( pReadr->aBuffer==0 ) rc = SQLITE_NOMEM_BKPT;
    +       pReadr->nBuffer = pgsz;
    +     }
    +     if( rc==SQLITE_OK && iBuf ){
    +@@ -80833,7 +88538,7 @@ static int vdbePmaReaderInit(
    + 
    +   rc = vdbePmaReaderSeek(pTask, pReadr, pFile, iStart);
    +   if( rc==SQLITE_OK ){
    +-    u64 nByte;                    /* Size of PMA in bytes */
    ++    u64 nByte = 0;                 /* Size of PMA in bytes */
    +     rc = vdbePmaReadVarint(pReadr, &nByte);
    +     pReadr->iEof = pReadr->iReadOff + nByte;
    +     *pnByte += nByte;
    +@@ -80911,15 +88616,15 @@ static int vdbeSorterCompareText(
    +   int n2;
    +   int res;
    + 
    +-  getVarint32(&p1[1], n1); n1 = (n1 - 13) / 2;
    +-  getVarint32(&p2[1], n2); n2 = (n2 - 13) / 2;
    +-  res = memcmp(v1, v2, MIN(n1, n2));
    ++  getVarint32(&p1[1], n1);
    ++  getVarint32(&p2[1], n2);
    ++  res = memcmp(v1, v2, (MIN(n1, n2) - 13)/2);
    +   if( res==0 ){
    +     res = n1 - n2;
    +   }
    + 
    +   if( res==0 ){
    +-    if( pTask->pSorter->pKeyInfo->nField>1 ){
    ++    if( pTask->pSorter->pKeyInfo->nKeyField>1 ){
    +       res = vdbeSorterCompareTail(
    +           pTask, pbKey2Cached, pKey1, nKey1, pKey2, nKey2
    +       );
    +@@ -80954,42 +88659,41 @@ static int vdbeSorterCompareInt(
    +   assert( (s1>0 && s1<7) || s1==8 || s1==9 );
    +   assert( (s2>0 && s2<7) || s2==8 || s2==9 );
    + 
    +-  if( s1>7 && s2>7 ){
    +-    res = s1 - s2;
    +-  }else{
    +-    if( s1==s2 ){
    +-      if( (*v1 ^ *v2) & 0x80 ){
    +-        /* The two values have different signs */
    +-        res = (*v1 & 0x80) ? -1 : +1;
    +-      }else{
    +-        /* The two values have the same sign. Compare using memcmp(). */
    +-        static const u8 aLen[] = {0, 1, 2, 3, 4, 6, 8 };
    +-        int i;
    +-        res = 0;
    +-        for(i=0; i<aLen[s1]; i++){
    +-          if( (res = v1[i] - v2[i]) ) break;
    ++  if( s1==s2 ){
    ++    /* The two values have the same sign. Compare using memcmp(). */
    ++    static const u8 aLen[] = {0, 1, 2, 3, 4, 6, 8, 0, 0, 0 };
    ++    const u8 n = aLen[s1];
    ++    int i;
    ++    res = 0;
    ++    for(i=0; i<n; i++){
    ++      if( (res = v1[i] - v2[i])!=0 ){
    ++        if( ((v1[0] ^ v2[0]) & 0x80)!=0 ){
    ++          res = v1[0] & 0x80 ? -1 : +1;
    +         }
    ++        break;
    +       }
    ++    }
    ++  }else if( s1>7 && s2>7 ){
    ++    res = s1 - s2;
    ++  }else{
    ++    if( s2>7 ){
    ++      res = +1;
    ++    }else if( s1>7 ){
    ++      res = -1;
    +     }else{
    +-      if( s2>7 ){
    +-        res = +1;
    +-      }else if( s1>7 ){
    +-        res = -1;
    +-      }else{
    +-        res = s1 - s2;
    +-      }
    +-      assert( res!=0 );
    ++      res = s1 - s2;
    ++    }
    ++    assert( res!=0 );
    + 
    +-      if( res>0 ){
    +-        if( *v1 & 0x80 ) res = -1;
    +-      }else{
    +-        if( *v2 & 0x80 ) res = +1;
    +-      }
    ++    if( res>0 ){
    ++      if( *v1 & 0x80 ) res = -1;
    ++    }else{
    ++      if( *v2 & 0x80 ) res = +1;
    +     }
    +   }
    + 
    +   if( res==0 ){
    +-    if( pTask->pSorter->pKeyInfo->nField>1 ){
    ++    if( pTask->pSorter->pKeyInfo->nKeyField>1 ){
    +       res = vdbeSorterCompareTail(
    +           pTask, pbKey2Cached, pKey1, nKey1, pKey2, nKey2
    +       );
    +@@ -81004,7 +88708,7 @@ static int vdbeSorterCompareInt(
    + /*
    + ** Initialize the temporary index cursor just opened as a sorter cursor.
    + **
    +-** Usually, the sorter module uses the value of (pCsr->pKeyInfo->nField)
    ++** Usually, the sorter module uses the value of (pCsr->pKeyInfo->nKeyField)
    + ** to determine the number of fields that should be compared from the
    + ** records being sorted. However, if the value passed as argument nField
    + ** is non-zero and the sorter is able to guarantee a stable sort, nField
    +@@ -81027,7 +88731,6 @@ SQLITE_PRIVATE int sqlite3VdbeSorterInit(
    + ){
    +   int pgsz;                       /* Page size of main database */
    +   int i;                          /* Used to iterate through aTask[] */
    +-  int mxCache;                    /* Cache size */
    +   VdbeSorter *pSorter;            /* The new sorter */
    +   KeyInfo *pKeyInfo;              /* Copy of pCsr->pKeyInfo with db==0 */
    +   int szKeyInfo;                  /* Size of pCsr->pKeyInfo in bytes */
    +@@ -81056,25 +88759,25 @@ SQLITE_PRIVATE int sqlite3VdbeSorterInit(
    +   }
    + #endif
    + 
    +-  assert( pCsr->pKeyInfo && pCsr->pBt==0 );
    +-  szKeyInfo = sizeof(KeyInfo) + (pCsr->pKeyInfo->nField-1)*sizeof(CollSeq*);
    ++  assert( pCsr->pKeyInfo && pCsr->pBtx==0 );
    ++  assert( pCsr->eCurType==CURTYPE_SORTER );
    ++  szKeyInfo = sizeof(KeyInfo) + (pCsr->pKeyInfo->nKeyField-1)*sizeof(CollSeq*);
    +   sz = sizeof(VdbeSorter) + nWorker * sizeof(SortSubtask);
    + 
    +   pSorter = (VdbeSorter*)sqlite3DbMallocZero(db, sz + szKeyInfo);
    +-  pCsr->pSorter = pSorter;
    ++  pCsr->uc.pSorter = pSorter;
    +   if( pSorter==0 ){
    +-    rc = SQLITE_NOMEM;
    ++    rc = SQLITE_NOMEM_BKPT;
    +   }else{
    +     pSorter->pKeyInfo = pKeyInfo = (KeyInfo*)((u8*)pSorter + sz);
    +     memcpy(pKeyInfo, pCsr->pKeyInfo, szKeyInfo);
    +     pKeyInfo->db = 0;
    +     if( nField && nWorker==0 ){
    +-      pKeyInfo->nXField += (pKeyInfo->nField - nField);
    +-      pKeyInfo->nField = nField;
    ++      pKeyInfo->nKeyField = nField;
    +     }
    +     pSorter->pgsz = pgsz = sqlite3BtreeGetPageSize(db->aDb[0].pBt);
    +     pSorter->nTask = nWorker + 1;
    +-    pSorter->iPrev = nWorker-1;
    ++    pSorter->iPrev = (u8)(nWorker - 1);
    +     pSorter->bUseThreads = (pSorter->nTask>1);
    +     pSorter->db = db;
    +     for(i=0; i<pSorter->nTask; i++){
    +@@ -81083,25 +88786,32 @@ SQLITE_PRIVATE int sqlite3VdbeSorterInit(
    +     }
    + 
    +     if( !sqlite3TempInMemory(db) ){
    ++      i64 mxCache;                /* Cache size in bytes*/
    +       u32 szPma = sqlite3GlobalConfig.szPma;
    +       pSorter->mnPmaSize = szPma * pgsz;
    ++
    +       mxCache = db->aDb[0].pSchema->cache_size;
    +-      if( mxCache<(int)szPma ) mxCache = (int)szPma;
    +-      pSorter->mxPmaSize = MIN((i64)mxCache*pgsz, SQLITE_MAX_PMASZ);
    ++      if( mxCache<0 ){
    ++        /* A negative cache-size value C indicates that the cache is abs(C)
    ++        ** KiB in size.  */
    ++        mxCache = mxCache * -1024;
    ++      }else{
    ++        mxCache = mxCache * pgsz;
    ++      }
    ++      mxCache = MIN(mxCache, SQLITE_MAX_PMASZ);
    ++      pSorter->mxPmaSize = MAX(pSorter->mnPmaSize, (int)mxCache);
    + 
    +-      /* EVIDENCE-OF: R-26747-61719 When the application provides any amount of
    +-      ** scratch memory using SQLITE_CONFIG_SCRATCH, SQLite avoids unnecessary
    +-      ** large heap allocations.
    +-      */
    +-      if( sqlite3GlobalConfig.pScratch==0 ){
    ++      /* Avoid large memory allocations if the application has requested
    ++      ** SQLITE_CONFIG_SMALL_MALLOC. */
    ++      if( sqlite3GlobalConfig.bSmallMalloc==0 ){
    +         assert( pSorter->iMemory==0 );
    +         pSorter->nMemory = pgsz;
    +         pSorter->list.aMemory = (u8*)sqlite3Malloc(pgsz);
    +-        if( !pSorter->list.aMemory ) rc = SQLITE_NOMEM;
    ++        if( !pSorter->list.aMemory ) rc = SQLITE_NOMEM_BKPT;
    +       }
    +     }
    + 
    +-    if( (pKeyInfo->nField+pKeyInfo->nXField)<13 
    ++    if( pKeyInfo->nAllField<13 
    +      && (pKeyInfo->aColl[0]==0 || pKeyInfo->aColl[0]==db->pDfltColl)
    +     ){
    +       pSorter->typeMask = SORTER_TYPE_INTEGER | SORTER_TYPE_TEXT;
    +@@ -81345,12 +89055,14 @@ SQLITE_PRIVATE void sqlite3VdbeSorterReset(sqlite3 *db, VdbeSorter *pSorter){
    + ** Free any cursor components allocated by sqlite3VdbeSorterXXX routines.
    + */
    + SQLITE_PRIVATE void sqlite3VdbeSorterClose(sqlite3 *db, VdbeCursor *pCsr){
    +-  VdbeSorter *pSorter = pCsr->pSorter;
    ++  VdbeSorter *pSorter;
    ++  assert( pCsr->eCurType==CURTYPE_SORTER );
    ++  pSorter = pCsr->uc.pSorter;
    +   if( pSorter ){
    +     sqlite3VdbeSorterReset(db, pSorter);
    +     sqlite3_free(pSorter->list.aMemory);
    +     sqlite3DbFree(db, pSorter);
    +-    pCsr->pSorter = 0;
    ++    pCsr->uc.pSorter = 0;
    +   }
    + }
    + 
    +@@ -81412,13 +89124,9 @@ static int vdbeSorterOpenTempFile(
    + */
    + static int vdbeSortAllocUnpacked(SortSubtask *pTask){
    +   if( pTask->pUnpacked==0 ){
    +-    char *pFree;
    +-    pTask->pUnpacked = sqlite3VdbeAllocUnpackedRecord(
    +-        pTask->pSorter->pKeyInfo, 0, 0, &pFree
    +-    );
    +-    assert( pTask->pUnpacked==(UnpackedRecord*)pFree );
    +-    if( pFree==0 ) return SQLITE_NOMEM;
    +-    pTask->pUnpacked->nField = pTask->pSorter->pKeyInfo->nField;
    ++    pTask->pUnpacked = sqlite3VdbeAllocUnpackedRecord(pTask->pSorter->pKeyInfo);
    ++    if( pTask->pUnpacked==0 ) return SQLITE_NOMEM_BKPT;
    ++    pTask->pUnpacked->nField = pTask->pSorter->pKeyInfo->nKeyField;
    +     pTask->pUnpacked->errCode = 0;
    +   }
    +   return SQLITE_OK;
    +@@ -81427,19 +89135,18 @@ static int vdbeSortAllocUnpacked(SortSubtask *pTask){
    + 
    + /*
    + ** Merge the two sorted lists p1 and p2 into a single list.
    +-** Set *ppOut to the head of the new list.
    + */
    +-static void vdbeSorterMerge(
    ++static SorterRecord *vdbeSorterMerge(
    +   SortSubtask *pTask,             /* Calling thread context */
    +   SorterRecord *p1,               /* First list to merge */
    +-  SorterRecord *p2,               /* Second list to merge */
    +-  SorterRecord **ppOut            /* OUT: Head of merged list */
    ++  SorterRecord *p2                /* Second list to merge */
    + ){
    +   SorterRecord *pFinal = 0;
    +   SorterRecord **pp = &pFinal;
    +   int bCached = 0;
    + 
    +-  while( p1 && p2 ){
    ++  assert( p1!=0 && p2!=0 );
    ++  for(;;){
    +     int res;
    +     res = pTask->xCompare(
    +         pTask, &bCached, SRVAL(p1), p1->nVal, SRVAL(p2), p2->nVal
    +@@ -81449,15 +89156,22 @@ static void vdbeSorterMerge(
    +       *pp = p1;
    +       pp = &p1->u.pNext;
    +       p1 = p1->u.pNext;
    ++      if( p1==0 ){
    ++        *pp = p2;
    ++        break;
    ++      }
    +     }else{
    +       *pp = p2;
    +       pp = &p2->u.pNext;
    +       p2 = p2->u.pNext;
    +       bCached = 0;
    ++      if( p2==0 ){
    ++        *pp = p1;
    ++        break;
    ++      }
    +     }
    +   }
    +-  *pp = p1 ? p1 : p2;
    +-  *ppOut = pFinal;
    ++  return pFinal;
    + }
    + 
    + /*
    +@@ -81492,7 +89206,7 @@ static int vdbeSorterSort(SortSubtask *pTask, SorterList *pList){
    + 
    +   aSlot = (SorterRecord **)sqlite3MallocZero(64 * sizeof(SorterRecord *));
    +   if( !aSlot ){
    +-    return SQLITE_NOMEM;
    ++    return SQLITE_NOMEM_BKPT;
    +   }
    + 
    +   while( p ){
    +@@ -81510,7 +89224,7 @@ static int vdbeSorterSort(SortSubtask *pTask, SorterList *pList){
    + 
    +     p->u.pNext = 0;
    +     for(i=0; aSlot[i]; i++){
    +-      vdbeSorterMerge(pTask, p, aSlot[i], &p);
    ++      p = vdbeSorterMerge(pTask, p, aSlot[i]);
    +       aSlot[i] = 0;
    +     }
    +     aSlot[i] = p;
    +@@ -81519,7 +89233,8 @@ static int vdbeSorterSort(SortSubtask *pTask, SorterList *pList){
    + 
    +   p = 0;
    +   for(i=0; i<64; i++){
    +-    vdbeSorterMerge(pTask, p, aSlot[i], &p);
    ++    if( aSlot[i]==0 ) continue;
    ++    p = p ? vdbeSorterMerge(pTask, p, aSlot[i]) : aSlot[i];
    +   }
    +   pList->pList = p;
    + 
    +@@ -81542,7 +89257,7 @@ static void vdbePmaWriterInit(
    +   memset(p, 0, sizeof(PmaWriter));
    +   p->aBuffer = (u8*)sqlite3Malloc(nBuf);
    +   if( !p->aBuffer ){
    +-    p->eFWErr = SQLITE_NOMEM;
    ++    p->eFWErr = SQLITE_NOMEM_BKPT;
    +   }else{
    +     p->iBufEnd = p->iBufStart = (iStart % nBuf);
    +     p->iWriteOff = iStart - p->iBufStart;
    +@@ -81830,7 +89545,7 @@ static int vdbeSorterFlushPMA(VdbeSorter *pSorter){
    +         pSorter->nMemory = sqlite3MallocSize(aMem);
    +       }else if( pSorter->list.aMemory ){
    +         pSorter->list.aMemory = sqlite3Malloc(pSorter->nMemory);
    +-        if( !pSorter->list.aMemory ) return SQLITE_NOMEM;
    ++        if( !pSorter->list.aMemory ) return SQLITE_NOMEM_BKPT;
    +       }
    + 
    +       rc = vdbeSorterCreateThread(pTask, vdbeSorterFlushThread, pCtx);
    +@@ -81848,15 +89563,16 @@ SQLITE_PRIVATE int sqlite3VdbeSorterWrite(
    +   const VdbeCursor *pCsr,         /* Sorter cursor */
    +   Mem *pVal                       /* Memory cell containing record */
    + ){
    +-  VdbeSorter *pSorter = pCsr->pSorter;
    ++  VdbeSorter *pSorter;
    +   int rc = SQLITE_OK;             /* Return Code */
    +   SorterRecord *pNew;             /* New list element */
    +-
    +   int bFlush;                     /* True to flush contents of memory to PMA */
    +   int nReq;                       /* Bytes of memory required */
    +   int nPMA;                       /* Bytes of PMA space required */
    +   int t;                          /* serial type of first record field */
    + 
    ++  assert( pCsr->eCurType==CURTYPE_SORTER );
    ++  pSorter = pCsr->uc.pSorter;
    +   getVarint32((const u8*)&pVal->z[1], t);
    +   if( t>0 && t<10 && t!=7 ){
    +     pSorter->typeMask &= SORTER_TYPE_INTEGER;
    +@@ -81913,27 +89629,28 @@ SQLITE_PRIVATE int sqlite3VdbeSorterWrite(
    + 
    +     if( nMin>pSorter->nMemory ){
    +       u8 *aNew;
    ++      int iListOff = (u8*)pSorter->list.pList - pSorter->list.aMemory;
    +       int nNew = pSorter->nMemory * 2;
    +       while( nNew < nMin ) nNew = nNew*2;
    +       if( nNew > pSorter->mxPmaSize ) nNew = pSorter->mxPmaSize;
    +       if( nNew < nMin ) nNew = nMin;
    + 
    +       aNew = sqlite3Realloc(pSorter->list.aMemory, nNew);
    +-      if( !aNew ) return SQLITE_NOMEM;
    +-      pSorter->list.pList = (SorterRecord*)(
    +-          aNew + ((u8*)pSorter->list.pList - pSorter->list.aMemory)
    +-      );
    ++      if( !aNew ) return SQLITE_NOMEM_BKPT;
    ++      pSorter->list.pList = (SorterRecord*)&aNew[iListOff];
    +       pSorter->list.aMemory = aNew;
    +       pSorter->nMemory = nNew;
    +     }
    + 
    +     pNew = (SorterRecord*)&pSorter->list.aMemory[pSorter->iMemory];
    +     pSorter->iMemory += ROUND8(nReq);
    +-    pNew->u.iNext = (int)((u8*)(pSorter->list.pList) - pSorter->list.aMemory);
    ++    if( pSorter->list.pList ){
    ++      pNew->u.iNext = (int)((u8*)(pSorter->list.pList) - pSorter->list.aMemory);
    ++    }
    +   }else{
    +     pNew = (SorterRecord *)sqlite3Malloc(nReq);
    +     if( pNew==0 ){
    +-      return SQLITE_NOMEM;
    ++      return SQLITE_NOMEM_BKPT;
    +     }
    +     pNew->u.pNext = pSorter->list.pList;
    +   }
    +@@ -82080,7 +89797,7 @@ static int vdbeIncrMergerNew(
    +     pTask->file2.iEof += pIncr->mxSz;
    +   }else{
    +     vdbeMergeEngineFree(pMerger);
    +-    rc = SQLITE_NOMEM;
    ++    rc = SQLITE_NOMEM_BKPT;
    +   }
    +   return rc;
    + }
    +@@ -82385,10 +90102,10 @@ static int vdbeMergeEngineLevel0(
    +   int rc = SQLITE_OK;
    + 
    +   *ppOut = pNew = vdbeMergeEngineNew(nPMA);
    +-  if( pNew==0 ) rc = SQLITE_NOMEM;
    ++  if( pNew==0 ) rc = SQLITE_NOMEM_BKPT;
    + 
    +   for(i=0; i<nPMA && rc==SQLITE_OK; i++){
    +-    i64 nDummy;
    ++    i64 nDummy = 0;
    +     PmaReader *pReadr = &pNew->aReadr[i];
    +     rc = vdbePmaReaderInit(pTask, &pTask->file, iOff, pReadr, &nDummy);
    +     iOff = pReadr->iEof;
    +@@ -82456,7 +90173,7 @@ static int vdbeSorterAddToTree(
    +     if( pReadr->pIncr==0 ){
    +       MergeEngine *pNew = vdbeMergeEngineNew(SORTER_MAX_MERGE_COUNT);
    +       if( pNew==0 ){
    +-        rc = SQLITE_NOMEM;
    ++        rc = SQLITE_NOMEM_BKPT;
    +       }else{
    +         rc = vdbeIncrMergerNew(pTask, pNew, &pReadr->pIncr);
    +       }
    +@@ -82501,7 +90218,7 @@ static int vdbeSorterMergeTreeBuild(
    +   assert( pSorter->bUseThreads || pSorter->nTask==1 );
    +   if( pSorter->nTask>1 ){
    +     pMain = vdbeMergeEngineNew(pSorter->nTask);
    +-    if( pMain==0 ) rc = SQLITE_NOMEM;
    ++    if( pMain==0 ) rc = SQLITE_NOMEM_BKPT;
    +   }
    + #endif
    + 
    +@@ -82519,7 +90236,7 @@ static int vdbeSorterMergeTreeBuild(
    +         int i;
    +         int iSeq = 0;
    +         pRoot = vdbeMergeEngineNew(SORTER_MAX_MERGE_COUNT);
    +-        if( pRoot==0 ) rc = SQLITE_NOMEM;
    ++        if( pRoot==0 ) rc = SQLITE_NOMEM_BKPT;
    +         for(i=0; i<pTask->nPMA && rc==SQLITE_OK; i += SORTER_MAX_MERGE_COUNT){
    +           MergeEngine *pMerger = 0; /* New level-0 PMA merger */
    +           int nReader;              /* Number of level-0 PMAs to merge */
    +@@ -82590,7 +90307,7 @@ static int vdbeSorterSetupMerge(VdbeSorter *pSorter){
    +       if( rc==SQLITE_OK ){
    +         pReadr = (PmaReader*)sqlite3DbMallocZero(db, sizeof(PmaReader));
    +         pSorter->pReader = pReadr;
    +-        if( pReadr==0 ) rc = SQLITE_NOMEM;
    ++        if( pReadr==0 ) rc = SQLITE_NOMEM_BKPT;
    +       }
    +       if( rc==SQLITE_OK ){
    +         rc = vdbeIncrMergerNew(pLast, pMain, &pReadr->pIncr);
    +@@ -82648,9 +90365,11 @@ static int vdbeSorterSetupMerge(VdbeSorter *pSorter){
    + ** in sorted order.
    + */
    + SQLITE_PRIVATE int sqlite3VdbeSorterRewind(const VdbeCursor *pCsr, int *pbEof){
    +-  VdbeSorter *pSorter = pCsr->pSorter;
    ++  VdbeSorter *pSorter;
    +   int rc = SQLITE_OK;             /* Return code */
    + 
    ++  assert( pCsr->eCurType==CURTYPE_SORTER );
    ++  pSorter = pCsr->uc.pSorter;
    +   assert( pSorter );
    + 
    +   /* If no data has been written to disk, then do not do so now. Instead,
    +@@ -82691,12 +90410,18 @@ SQLITE_PRIVATE int sqlite3VdbeSorterRewind(const VdbeCursor *pCsr, int *pbEof){
    + }
    + 
    + /*
    +-** Advance to the next element in the sorter.
    ++** Advance to the next element in the sorter.  Return value:
    ++**
    ++**    SQLITE_OK     success
    ++**    SQLITE_DONE   end of data
    ++**    otherwise     some kind of error.
    + */
    +-SQLITE_PRIVATE int sqlite3VdbeSorterNext(sqlite3 *db, const VdbeCursor *pCsr, int *pbEof){
    +-  VdbeSorter *pSorter = pCsr->pSorter;
    ++SQLITE_PRIVATE int sqlite3VdbeSorterNext(sqlite3 *db, const VdbeCursor *pCsr){
    ++  VdbeSorter *pSorter;
    +   int rc;                         /* Return code */
    + 
    ++  assert( pCsr->eCurType==CURTYPE_SORTER );
    ++  pSorter = pCsr->uc.pSorter;
    +   assert( pSorter->bUsePMA || (pSorter->pReader==0 && pSorter->pMerger==0) );
    +   if( pSorter->bUsePMA ){
    +     assert( pSorter->pReader==0 || pSorter->pMerger==0 );
    +@@ -82705,21 +90430,22 @@ SQLITE_PRIVATE int sqlite3VdbeSorterNext(sqlite3 *db, const VdbeCursor *pCsr, in
    + #if SQLITE_MAX_WORKER_THREADS>0
    +     if( pSorter->bUseThreads ){
    +       rc = vdbePmaReaderNext(pSorter->pReader);
    +-      *pbEof = (pSorter->pReader->pFd==0);
    ++      if( rc==SQLITE_OK && pSorter->pReader->pFd==0 ) rc = SQLITE_DONE;
    +     }else
    + #endif
    +     /*if( !pSorter->bUseThreads )*/ {
    ++      int res = 0;
    +       assert( pSorter->pMerger!=0 );
    +       assert( pSorter->pMerger->pTask==(&pSorter->aTask[0]) );
    +-      rc = vdbeMergeEngineStep(pSorter->pMerger, pbEof);
    ++      rc = vdbeMergeEngineStep(pSorter->pMerger, &res);
    ++      if( rc==SQLITE_OK && res ) rc = SQLITE_DONE;
    +     }
    +   }else{
    +     SorterRecord *pFree = pSorter->list.pList;
    +     pSorter->list.pList = pFree->u.pNext;
    +     pFree->u.pNext = 0;
    +     if( pSorter->list.aMemory==0 ) vdbeSorterRecordFree(db, pFree);
    +-    *pbEof = !pSorter->list.pList;
    +-    rc = SQLITE_OK;
    ++    rc = pSorter->list.pList ? SQLITE_OK : SQLITE_DONE;
    +   }
    +   return rc;
    + }
    +@@ -82756,12 +90482,14 @@ static void *vdbeSorterRowkey(
    + ** Copy the current sorter key into the memory cell pOut.
    + */
    + SQLITE_PRIVATE int sqlite3VdbeSorterRowkey(const VdbeCursor *pCsr, Mem *pOut){
    +-  VdbeSorter *pSorter = pCsr->pSorter;
    ++  VdbeSorter *pSorter;
    +   void *pKey; int nKey;           /* Sorter key to copy into pOut */
    + 
    ++  assert( pCsr->eCurType==CURTYPE_SORTER );
    ++  pSorter = pCsr->uc.pSorter;
    +   pKey = vdbeSorterRowkey(pSorter, &nKey);
    +   if( sqlite3VdbeMemClearAndResize(pOut, nKey) ){
    +-    return SQLITE_NOMEM;
    ++    return SQLITE_NOMEM_BKPT;
    +   }
    +   pOut->n = nKey;
    +   MemSetTypeFlag(pOut, MEM_Blob);
    +@@ -82792,17 +90520,19 @@ SQLITE_PRIVATE int sqlite3VdbeSorterCompare(
    +   int nKeyCol,                    /* Compare this many columns */
    +   int *pRes                       /* OUT: Result of comparison */
    + ){
    +-  VdbeSorter *pSorter = pCsr->pSorter;
    +-  UnpackedRecord *r2 = pSorter->pUnpacked;
    +-  KeyInfo *pKeyInfo = pCsr->pKeyInfo;
    ++  VdbeSorter *pSorter;
    ++  UnpackedRecord *r2;
    ++  KeyInfo *pKeyInfo;
    +   int i;
    +   void *pKey; int nKey;           /* Sorter key to compare pVal with */
    + 
    ++  assert( pCsr->eCurType==CURTYPE_SORTER );
    ++  pSorter = pCsr->uc.pSorter;
    ++  r2 = pSorter->pUnpacked;
    ++  pKeyInfo = pCsr->pKeyInfo;
    +   if( r2==0 ){
    +-    char *p;
    +-    r2 = pSorter->pUnpacked = sqlite3VdbeAllocUnpackedRecord(pKeyInfo,0,0,&p);
    +-    assert( pSorter->pUnpacked==(UnpackedRecord*)p );
    +-    if( r2==0 ) return SQLITE_NOMEM;
    ++    r2 = pSorter->pUnpacked = sqlite3VdbeAllocUnpackedRecord(pKeyInfo);
    ++    if( r2==0 ) return SQLITE_NOMEM_BKPT;
    +     r2->nField = nKeyCol;
    +   }
    +   assert( r2->nField==nKeyCol );
    +@@ -82821,265 +90551,6 @@ SQLITE_PRIVATE int sqlite3VdbeSorterCompare(
    + }
    + 
    + /************** End of vdbesort.c ********************************************/
    +-/************** Begin file journal.c *****************************************/
    +-/*
    +-** 2007 August 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 implements a special kind of sqlite3_file object used
    +-** by SQLite to create journal files if the atomic-write optimization
    +-** is enabled.
    +-**
    +-** The distinctive characteristic of this sqlite3_file is that the
    +-** actual on disk file is created lazily. When the file is created,
    +-** the caller specifies a buffer size for an in-memory buffer to
    +-** be used to service read() and write() requests. The actual file
    +-** on disk is not created or populated until either:
    +-**
    +-**   1) The in-memory representation grows too large for the allocated 
    +-**      buffer, or
    +-**   2) The sqlite3JournalCreate() function is called.
    +-*/
    +-#ifdef SQLITE_ENABLE_ATOMIC_WRITE
    +-/* #include "sqliteInt.h" */
    +-
    +-
    +-/*
    +-** A JournalFile object is a subclass of sqlite3_file used by
    +-** as an open file handle for journal files.
    +-*/
    +-struct JournalFile {
    +-  sqlite3_io_methods *pMethod;    /* I/O methods on journal files */
    +-  int nBuf;                       /* Size of zBuf[] in bytes */
    +-  char *zBuf;                     /* Space to buffer journal writes */
    +-  int iSize;                      /* Amount of zBuf[] currently used */
    +-  int flags;                      /* xOpen flags */
    +-  sqlite3_vfs *pVfs;              /* The "real" underlying VFS */
    +-  sqlite3_file *pReal;            /* The "real" underlying file descriptor */
    +-  const char *zJournal;           /* Name of the journal file */
    +-};
    +-typedef struct JournalFile JournalFile;
    +-
    +-/*
    +-** If it does not already exists, create and populate the on-disk file 
    +-** for JournalFile p.
    +-*/
    +-static int createFile(JournalFile *p){
    +-  int rc = SQLITE_OK;
    +-  if( !p->pReal ){
    +-    sqlite3_file *pReal = (sqlite3_file *)&p[1];
    +-    rc = sqlite3OsOpen(p->pVfs, p->zJournal, pReal, p->flags, 0);
    +-    if( rc==SQLITE_OK ){
    +-      p->pReal = pReal;
    +-      if( p->iSize>0 ){
    +-        assert(p->iSize<=p->nBuf);
    +-        rc = sqlite3OsWrite(p->pReal, p->zBuf, p->iSize, 0);
    +-      }
    +-      if( rc!=SQLITE_OK ){
    +-        /* If an error occurred while writing to the file, close it before
    +-        ** returning. This way, SQLite uses the in-memory journal data to 
    +-        ** roll back changes made to the internal page-cache before this
    +-        ** function was called.  */
    +-        sqlite3OsClose(pReal);
    +-        p->pReal = 0;
    +-      }
    +-    }
    +-  }
    +-  return rc;
    +-}
    +-
    +-/*
    +-** Close the file.
    +-*/
    +-static int jrnlClose(sqlite3_file *pJfd){
    +-  JournalFile *p = (JournalFile *)pJfd;
    +-  if( p->pReal ){
    +-    sqlite3OsClose(p->pReal);
    +-  }
    +-  sqlite3_free(p->zBuf);
    +-  return SQLITE_OK;
    +-}
    +-
    +-/*
    +-** Read data from the file.
    +-*/
    +-static int jrnlRead(
    +-  sqlite3_file *pJfd,    /* The journal file from which to read */
    +-  void *zBuf,            /* Put the results here */
    +-  int iAmt,              /* Number of bytes to read */
    +-  sqlite_int64 iOfst     /* Begin reading at this offset */
    +-){
    +-  int rc = SQLITE_OK;
    +-  JournalFile *p = (JournalFile *)pJfd;
    +-  if( p->pReal ){
    +-    rc = sqlite3OsRead(p->pReal, zBuf, iAmt, iOfst);
    +-  }else if( (iAmt+iOfst)>p->iSize ){
    +-    rc = SQLITE_IOERR_SHORT_READ;
    +-  }else{
    +-    memcpy(zBuf, &p->zBuf[iOfst], iAmt);
    +-  }
    +-  return rc;
    +-}
    +-
    +-/*
    +-** Write data to the file.
    +-*/
    +-static int jrnlWrite(
    +-  sqlite3_file *pJfd,    /* The journal file into which to write */
    +-  const void *zBuf,      /* Take data to be written from here */
    +-  int iAmt,              /* Number of bytes to write */
    +-  sqlite_int64 iOfst     /* Begin writing at this offset into the file */
    +-){
    +-  int rc = SQLITE_OK;
    +-  JournalFile *p = (JournalFile *)pJfd;
    +-  if( !p->pReal && (iOfst+iAmt)>p->nBuf ){
    +-    rc = createFile(p);
    +-  }
    +-  if( rc==SQLITE_OK ){
    +-    if( p->pReal ){
    +-      rc = sqlite3OsWrite(p->pReal, zBuf, iAmt, iOfst);
    +-    }else{
    +-      memcpy(&p->zBuf[iOfst], zBuf, iAmt);
    +-      if( p->iSize<(iOfst+iAmt) ){
    +-        p->iSize = (iOfst+iAmt);
    +-      }
    +-    }
    +-  }
    +-  return rc;
    +-}
    +-
    +-/*
    +-** Truncate the file.
    +-*/
    +-static int jrnlTruncate(sqlite3_file *pJfd, sqlite_int64 size){
    +-  int rc = SQLITE_OK;
    +-  JournalFile *p = (JournalFile *)pJfd;
    +-  if( p->pReal ){
    +-    rc = sqlite3OsTruncate(p->pReal, size);
    +-  }else if( size<p->iSize ){
    +-    p->iSize = size;
    +-  }
    +-  return rc;
    +-}
    +-
    +-/*
    +-** Sync the file.
    +-*/
    +-static int jrnlSync(sqlite3_file *pJfd, int flags){
    +-  int rc;
    +-  JournalFile *p = (JournalFile *)pJfd;
    +-  if( p->pReal ){
    +-    rc = sqlite3OsSync(p->pReal, flags);
    +-  }else{
    +-    rc = SQLITE_OK;
    +-  }
    +-  return rc;
    +-}
    +-
    +-/*
    +-** Query the size of the file in bytes.
    +-*/
    +-static int jrnlFileSize(sqlite3_file *pJfd, sqlite_int64 *pSize){
    +-  int rc = SQLITE_OK;
    +-  JournalFile *p = (JournalFile *)pJfd;
    +-  if( p->pReal ){
    +-    rc = sqlite3OsFileSize(p->pReal, pSize);
    +-  }else{
    +-    *pSize = (sqlite_int64) p->iSize;
    +-  }
    +-  return rc;
    +-}
    +-
    +-/*
    +-** Table of methods for JournalFile sqlite3_file object.
    +-*/
    +-static struct sqlite3_io_methods JournalFileMethods = {
    +-  1,             /* iVersion */
    +-  jrnlClose,     /* xClose */
    +-  jrnlRead,      /* xRead */
    +-  jrnlWrite,     /* xWrite */
    +-  jrnlTruncate,  /* xTruncate */
    +-  jrnlSync,      /* xSync */
    +-  jrnlFileSize,  /* xFileSize */
    +-  0,             /* xLock */
    +-  0,             /* xUnlock */
    +-  0,             /* xCheckReservedLock */
    +-  0,             /* xFileControl */
    +-  0,             /* xSectorSize */
    +-  0,             /* xDeviceCharacteristics */
    +-  0,             /* xShmMap */
    +-  0,             /* xShmLock */
    +-  0,             /* xShmBarrier */
    +-  0              /* xShmUnmap */
    +-};
    +-
    +-/* 
    +-** Open a journal file.
    +-*/
    +-SQLITE_PRIVATE int sqlite3JournalOpen(
    +-  sqlite3_vfs *pVfs,         /* The VFS to use for actual file I/O */
    +-  const char *zName,         /* Name of the journal file */
    +-  sqlite3_file *pJfd,        /* Preallocated, blank file handle */
    +-  int flags,                 /* Opening flags */
    +-  int nBuf                   /* Bytes buffered before opening the file */
    +-){
    +-  JournalFile *p = (JournalFile *)pJfd;
    +-  memset(p, 0, sqlite3JournalSize(pVfs));
    +-  if( nBuf>0 ){
    +-    p->zBuf = sqlite3MallocZero(nBuf);
    +-    if( !p->zBuf ){
    +-      return SQLITE_NOMEM;
    +-    }
    +-  }else{
    +-    return sqlite3OsOpen(pVfs, zName, pJfd, flags, 0);
    +-  }
    +-  p->pMethod = &JournalFileMethods;
    +-  p->nBuf = nBuf;
    +-  p->flags = flags;
    +-  p->zJournal = zName;
    +-  p->pVfs = pVfs;
    +-  return SQLITE_OK;
    +-}
    +-
    +-/*
    +-** If the argument p points to a JournalFile structure, and the underlying
    +-** file has not yet been created, create it now.
    +-*/
    +-SQLITE_PRIVATE int sqlite3JournalCreate(sqlite3_file *p){
    +-  if( p->pMethods!=&JournalFileMethods ){
    +-    return SQLITE_OK;
    +-  }
    +-  return createFile((JournalFile *)p);
    +-}
    +-
    +-/*
    +-** The file-handle passed as the only argument is guaranteed to be an open
    +-** file. It may or may not be of class JournalFile. If the file is a
    +-** JournalFile, and the underlying file on disk has not yet been opened,
    +-** return 0. Otherwise, return 1.
    +-*/
    +-SQLITE_PRIVATE int sqlite3JournalExists(sqlite3_file *p){
    +-  return (p->pMethods!=&JournalFileMethods || ((JournalFile *)p)->pReal!=0);
    +-}
    +-
    +-/* 
    +-** Return the number of bytes required to store a JournalFile that uses vfs
    +-** pVfs to create the underlying on-disk files.
    +-*/
    +-SQLITE_PRIVATE int sqlite3JournalSize(sqlite3_vfs *pVfs){
    +-  return (pVfs->szOsFile+sizeof(JournalFile));
    +-}
    +-#endif
    +-
    +-/************** End of journal.c *********************************************/
    + /************** Begin file memjournal.c **************************************/
    + /*
    + ** 2008 October 7
    +@@ -83096,6 +90567,15 @@ SQLITE_PRIVATE int sqlite3JournalSize(sqlite3_vfs *pVfs){
    + ** This file contains code use to implement an in-memory rollback journal.
    + ** The in-memory rollback journal is used to journal transactions for
    + ** ":memory:" databases and when the journal_mode=MEMORY pragma is used.
    ++**
    ++** Update:  The in-memory journal is also used to temporarily cache
    ++** smaller journals that are not critical for power-loss recovery.
    ++** For example, statement journals that are not too big will be held
    ++** entirely in memory, thus reducing the number of file I/O calls, and
    ++** more importantly, reducing temporary file creation events.  If these
    ++** journals become too large for memory, they are spilled to disk.  But
    ++** in the common case, they are usually small and no file I/O needs to
    ++** occur.
    + */
    + /* #include "sqliteInt.h" */
    + 
    +@@ -83104,24 +90584,28 @@ typedef struct MemJournal MemJournal;
    + typedef struct FilePoint FilePoint;
    + typedef struct FileChunk FileChunk;
    + 
    +-/* Space to hold the rollback journal is allocated in increments of
    +-** this many bytes.
    +-**
    +-** The size chosen is a little less than a power of two.  That way,
    +-** the FileChunk object will have a size that almost exactly fills
    +-** a power-of-two allocation.  This minimizes wasted space in power-of-two
    +-** memory allocators.
    +-*/
    +-#define JOURNAL_CHUNKSIZE ((int)(1024-sizeof(FileChunk*)))
    +-
    + /*
    + ** The rollback journal is composed of a linked list of these structures.
    ++**
    ++** The zChunk array is always at least 8 bytes in size - usually much more.
    ++** Its actual size is stored in the MemJournal.nChunkSize variable.
    + */
    + struct FileChunk {
    +   FileChunk *pNext;               /* Next chunk in the journal */
    +-  u8 zChunk[JOURNAL_CHUNKSIZE];   /* Content of this chunk */
    ++  u8 zChunk[8];                   /* Content of this chunk */
    + };
    + 
    ++/*
    ++** By default, allocate this many bytes of memory for each FileChunk object.
    ++*/
    ++#define MEMJOURNAL_DFLT_FILECHUNKSIZE 1024
    ++
    ++/*
    ++** For chunk size nChunkSize, return the number of bytes that should
    ++** be allocated for each FileChunk structure.
    ++*/
    ++#define fileChunkSize(nChunkSize) (sizeof(FileChunk) + ((nChunkSize)-8))
    ++
    + /*
    + ** An instance of this object serves as a cursor into the rollback journal.
    + ** The cursor can be either for reading or writing.
    +@@ -83132,14 +90616,22 @@ struct FilePoint {
    + };
    + 
    + /*
    +-** This subclass is a subclass of sqlite3_file.  Each open memory-journal
    ++** This structure is a subclass of sqlite3_file. Each open memory-journal
    + ** is an instance of this class.
    + */
    + struct MemJournal {
    +-  sqlite3_io_methods *pMethod;    /* Parent class. MUST BE FIRST */
    ++  const sqlite3_io_methods *pMethod; /* Parent class. MUST BE FIRST */
    ++  int nChunkSize;                 /* In-memory chunk-size */
    ++
    ++  int nSpill;                     /* Bytes of data before flushing */
    ++  int nSize;                      /* Bytes of data currently in memory */
    +   FileChunk *pFirst;              /* Head of in-memory chunk-list */
    +   FilePoint endpoint;             /* Pointer to the end of the file */
    +   FilePoint readpoint;            /* Pointer to the end of the last xRead() */
    ++
    ++  int flags;                      /* xOpen flags */
    ++  sqlite3_vfs *pVfs;              /* The "real" underlying VFS */
    ++  const char *zJournal;           /* Name of the journal file */
    + };
    + 
    + /*
    +@@ -83158,36 +90650,95 @@ static int memjrnlRead(
    +   int iChunkOffset;
    +   FileChunk *pChunk;
    + 
    +-  /* SQLite never tries to read past the end of a rollback journal file */
    +-  assert( iOfst+iAmt<=p->endpoint.iOffset );
    ++#if defined(SQLITE_ENABLE_ATOMIC_WRITE) \
    ++ || defined(SQLITE_ENABLE_BATCH_ATOMIC_WRITE)
    ++  if( (iAmt+iOfst)>p->endpoint.iOffset ){
    ++    return SQLITE_IOERR_SHORT_READ;
    ++  }
    ++#endif
    + 
    ++  assert( (iAmt+iOfst)<=p->endpoint.iOffset );
    ++  assert( p->readpoint.iOffset==0 || p->readpoint.pChunk!=0 );
    +   if( p->readpoint.iOffset!=iOfst || iOfst==0 ){
    +     sqlite3_int64 iOff = 0;
    +     for(pChunk=p->pFirst; 
    +-        ALWAYS(pChunk) && (iOff+JOURNAL_CHUNKSIZE)<=iOfst;
    ++        ALWAYS(pChunk) && (iOff+p->nChunkSize)<=iOfst;
    +         pChunk=pChunk->pNext
    +     ){
    +-      iOff += JOURNAL_CHUNKSIZE;
    ++      iOff += p->nChunkSize;
    +     }
    +   }else{
    +     pChunk = p->readpoint.pChunk;
    ++    assert( pChunk!=0 );
    +   }
    + 
    +-  iChunkOffset = (int)(iOfst%JOURNAL_CHUNKSIZE);
    ++  iChunkOffset = (int)(iOfst%p->nChunkSize);
    +   do {
    +-    int iSpace = JOURNAL_CHUNKSIZE - iChunkOffset;
    +-    int nCopy = MIN(nRead, (JOURNAL_CHUNKSIZE - iChunkOffset));
    +-    memcpy(zOut, &pChunk->zChunk[iChunkOffset], nCopy);
    ++    int iSpace = p->nChunkSize - iChunkOffset;
    ++    int nCopy = MIN(nRead, (p->nChunkSize - iChunkOffset));
    ++    memcpy(zOut, (u8*)pChunk->zChunk + iChunkOffset, nCopy);
    +     zOut += nCopy;
    +     nRead -= iSpace;
    +     iChunkOffset = 0;
    +   } while( nRead>=0 && (pChunk=pChunk->pNext)!=0 && nRead>0 );
    +-  p->readpoint.iOffset = iOfst+iAmt;
    ++  p->readpoint.iOffset = pChunk ? iOfst+iAmt : 0;
    +   p->readpoint.pChunk = pChunk;
    + 
    +   return SQLITE_OK;
    + }
    + 
    ++/*
    ++** Free the list of FileChunk structures headed at MemJournal.pFirst.
    ++*/
    ++static void memjrnlFreeChunks(MemJournal *p){
    ++  FileChunk *pIter;
    ++  FileChunk *pNext;
    ++  for(pIter=p->pFirst; pIter; pIter=pNext){
    ++    pNext = pIter->pNext;
    ++    sqlite3_free(pIter);
    ++  } 
    ++  p->pFirst = 0;
    ++}
    ++
    ++/*
    ++** Flush the contents of memory to a real file on disk.
    ++*/
    ++static int memjrnlCreateFile(MemJournal *p){
    ++  int rc;
    ++  sqlite3_file *pReal = (sqlite3_file*)p;
    ++  MemJournal copy = *p;
    ++
    ++  memset(p, 0, sizeof(MemJournal));
    ++  rc = sqlite3OsOpen(copy.pVfs, copy.zJournal, pReal, copy.flags, 0);
    ++  if( rc==SQLITE_OK ){
    ++    int nChunk = copy.nChunkSize;
    ++    i64 iOff = 0;
    ++    FileChunk *pIter;
    ++    for(pIter=copy.pFirst; pIter; pIter=pIter->pNext){
    ++      if( iOff + nChunk > copy.endpoint.iOffset ){
    ++        nChunk = copy.endpoint.iOffset - iOff;
    ++      }
    ++      rc = sqlite3OsWrite(pReal, (u8*)pIter->zChunk, nChunk, iOff);
    ++      if( rc ) break;
    ++      iOff += nChunk;
    ++    }
    ++    if( rc==SQLITE_OK ){
    ++      /* No error has occurred. Free the in-memory buffers. */
    ++      memjrnlFreeChunks(&copy);
    ++    }
    ++  }
    ++  if( rc!=SQLITE_OK ){
    ++    /* If an error occurred while creating or writing to the file, restore
    ++    ** the original before returning. This way, SQLite uses the in-memory
    ++    ** journal data to roll back changes made to the internal page-cache
    ++    ** before this function was called.  */
    ++    sqlite3OsClose(pReal);
    ++    *p = copy;
    ++  }
    ++  return rc;
    ++}
    ++
    ++
    + /*
    + ** Write data to the file.
    + */
    +@@ -83201,38 +90752,63 @@ static int memjrnlWrite(
    +   int nWrite = iAmt;
    +   u8 *zWrite = (u8 *)zBuf;
    + 
    +-  /* An in-memory journal file should only ever be appended to. Random
    +-  ** access writes are not required by sqlite.
    +-  */
    +-  assert( iOfst==p->endpoint.iOffset );
    +-  UNUSED_PARAMETER(iOfst);
    ++  /* If the file should be created now, create it and write the new data
    ++  ** into the file on disk. */
    ++  if( p->nSpill>0 && (iAmt+iOfst)>p->nSpill ){
    ++    int rc = memjrnlCreateFile(p);
    ++    if( rc==SQLITE_OK ){
    ++      rc = sqlite3OsWrite(pJfd, zBuf, iAmt, iOfst);
    ++    }
    ++    return rc;
    ++  }
    + 
    +-  while( nWrite>0 ){
    +-    FileChunk *pChunk = p->endpoint.pChunk;
    +-    int iChunkOffset = (int)(p->endpoint.iOffset%JOURNAL_CHUNKSIZE);
    +-    int iSpace = MIN(nWrite, JOURNAL_CHUNKSIZE - iChunkOffset);
    ++  /* If the contents of this write should be stored in memory */
    ++  else{
    ++    /* An in-memory journal file should only ever be appended to. Random
    ++    ** access writes are not required. The only exception to this is when
    ++    ** the in-memory journal is being used by a connection using the
    ++    ** atomic-write optimization. In this case the first 28 bytes of the
    ++    ** journal file may be written as part of committing the transaction. */ 
    ++    assert( iOfst==p->endpoint.iOffset || iOfst==0 );
    ++#if defined(SQLITE_ENABLE_ATOMIC_WRITE) \
    ++ || defined(SQLITE_ENABLE_BATCH_ATOMIC_WRITE)
    ++    if( iOfst==0 && p->pFirst ){
    ++      assert( p->nChunkSize>iAmt );
    ++      memcpy((u8*)p->pFirst->zChunk, zBuf, iAmt);
    ++    }else
    ++#else
    ++    assert( iOfst>0 || p->pFirst==0 );
    ++#endif
    ++    {
    ++      while( nWrite>0 ){
    ++        FileChunk *pChunk = p->endpoint.pChunk;
    ++        int iChunkOffset = (int)(p->endpoint.iOffset%p->nChunkSize);
    ++        int iSpace = MIN(nWrite, p->nChunkSize - iChunkOffset);
    ++
    ++        if( iChunkOffset==0 ){
    ++          /* New chunk is required to extend the file. */
    ++          FileChunk *pNew = sqlite3_malloc(fileChunkSize(p->nChunkSize));
    ++          if( !pNew ){
    ++            return SQLITE_IOERR_NOMEM_BKPT;
    ++          }
    ++          pNew->pNext = 0;
    ++          if( pChunk ){
    ++            assert( p->pFirst );
    ++            pChunk->pNext = pNew;
    ++          }else{
    ++            assert( !p->pFirst );
    ++            p->pFirst = pNew;
    ++          }
    ++          p->endpoint.pChunk = pNew;
    ++        }
    + 
    +-    if( iChunkOffset==0 ){
    +-      /* New chunk is required to extend the file. */
    +-      FileChunk *pNew = sqlite3_malloc(sizeof(FileChunk));
    +-      if( !pNew ){
    +-        return SQLITE_IOERR_NOMEM;
    ++        memcpy((u8*)p->endpoint.pChunk->zChunk + iChunkOffset, zWrite, iSpace);
    ++        zWrite += iSpace;
    ++        nWrite -= iSpace;
    ++        p->endpoint.iOffset += iSpace;
    +       }
    +-      pNew->pNext = 0;
    +-      if( pChunk ){
    +-        assert( p->pFirst );
    +-        pChunk->pNext = pNew;
    +-      }else{
    +-        assert( !p->pFirst );
    +-        p->pFirst = pNew;
    +-      }
    +-      p->endpoint.pChunk = pNew;
    ++      p->nSize = iAmt + iOfst;
    +     }
    +-
    +-    memcpy(&p->endpoint.pChunk->zChunk[iChunkOffset], zWrite, iSpace);
    +-    zWrite += iSpace;
    +-    nWrite -= iSpace;
    +-    p->endpoint.iOffset += iSpace;
    +   }
    + 
    +   return SQLITE_OK;
    +@@ -83240,19 +90816,21 @@ static int memjrnlWrite(
    + 
    + /*
    + ** Truncate the file.
    ++**
    ++** If the journal file is already on disk, truncate it there. Or, if it
    ++** is still in main memory but is being truncated to zero bytes in size,
    ++** ignore 
    + */
    + static int memjrnlTruncate(sqlite3_file *pJfd, sqlite_int64 size){
    +   MemJournal *p = (MemJournal *)pJfd;
    +-  FileChunk *pChunk;
    +-  assert(size==0);
    +-  UNUSED_PARAMETER(size);
    +-  pChunk = p->pFirst;
    +-  while( pChunk ){
    +-    FileChunk *pTmp = pChunk;
    +-    pChunk = pChunk->pNext;
    +-    sqlite3_free(pTmp);
    +-  }
    +-  sqlite3MemJournalOpen(pJfd);
    ++  if( ALWAYS(size==0) ){
    ++    memjrnlFreeChunks(p);
    ++    p->nSize = 0;
    ++    p->endpoint.pChunk = 0;
    ++    p->endpoint.iOffset = 0;
    ++    p->readpoint.pChunk = 0;
    ++    p->readpoint.iOffset = 0;
    ++  }
    +   return SQLITE_OK;
    + }
    + 
    +@@ -83260,21 +90838,19 @@ static int memjrnlTruncate(sqlite3_file *pJfd, sqlite_int64 size){
    + ** Close the file.
    + */
    + static int memjrnlClose(sqlite3_file *pJfd){
    +-  memjrnlTruncate(pJfd, 0);
    ++  MemJournal *p = (MemJournal *)pJfd;
    ++  memjrnlFreeChunks(p);
    +   return SQLITE_OK;
    + }
    + 
    +-
    + /*
    + ** Sync the file.
    + **
    +-** Syncing an in-memory journal is a no-op.  And, in fact, this routine
    +-** is never called in a working implementation.  This implementation
    +-** exists purely as a contingency, in case some malfunction in some other
    +-** part of SQLite causes Sync to be called by mistake.
    ++** If the real file has been created, call its xSync method. Otherwise, 
    ++** syncing an in-memory journal is a no-op. 
    + */
    +-static int memjrnlSync(sqlite3_file *NotUsed, int NotUsed2){
    +-  UNUSED_PARAMETER2(NotUsed, NotUsed2);
    ++static int memjrnlSync(sqlite3_file *pJfd, int flags){
    ++  UNUSED_PARAMETER2(pJfd, flags);
    +   return SQLITE_OK;
    + }
    + 
    +@@ -83313,28 +90889,102 @@ static const struct sqlite3_io_methods MemJournalMethods = {
    + };
    + 
    + /* 
    +-** Open a journal file.
    ++** Open a journal file. 
    ++**
    ++** The behaviour of the journal file depends on the value of parameter 
    ++** nSpill. If nSpill is 0, then the journal file is always create and 
    ++** accessed using the underlying VFS. If nSpill is less than zero, then
    ++** all content is always stored in main-memory. Finally, if nSpill is a
    ++** positive value, then the journal file is initially created in-memory
    ++** but may be flushed to disk later on. In this case the journal file is
    ++** flushed to disk either when it grows larger than nSpill bytes in size,
    ++** or when sqlite3JournalCreate() is called.
    ++*/
    ++SQLITE_PRIVATE int sqlite3JournalOpen(
    ++  sqlite3_vfs *pVfs,         /* The VFS to use for actual file I/O */
    ++  const char *zName,         /* Name of the journal file */
    ++  sqlite3_file *pJfd,        /* Preallocated, blank file handle */
    ++  int flags,                 /* Opening flags */
    ++  int nSpill                 /* Bytes buffered before opening the file */
    ++){
    ++  MemJournal *p = (MemJournal*)pJfd;
    ++
    ++  /* Zero the file-handle object. If nSpill was passed zero, initialize
    ++  ** it using the sqlite3OsOpen() function of the underlying VFS. In this
    ++  ** case none of the code in this module is executed as a result of calls
    ++  ** made on the journal file-handle.  */
    ++  memset(p, 0, sizeof(MemJournal));
    ++  if( nSpill==0 ){
    ++    return sqlite3OsOpen(pVfs, zName, pJfd, flags, 0);
    ++  }
    ++
    ++  if( nSpill>0 ){
    ++    p->nChunkSize = nSpill;
    ++  }else{
    ++    p->nChunkSize = 8 + MEMJOURNAL_DFLT_FILECHUNKSIZE - sizeof(FileChunk);
    ++    assert( MEMJOURNAL_DFLT_FILECHUNKSIZE==fileChunkSize(p->nChunkSize) );
    ++  }
    ++
    ++  p->pMethod = (const sqlite3_io_methods*)&MemJournalMethods;
    ++  p->nSpill = nSpill;
    ++  p->flags = flags;
    ++  p->zJournal = zName;
    ++  p->pVfs = pVfs;
    ++  return SQLITE_OK;
    ++}
    ++
    ++/*
    ++** Open an in-memory journal file.
    + */
    + SQLITE_PRIVATE void sqlite3MemJournalOpen(sqlite3_file *pJfd){
    +-  MemJournal *p = (MemJournal *)pJfd;
    +-  assert( EIGHT_BYTE_ALIGNMENT(p) );
    +-  memset(p, 0, sqlite3MemJournalSize());
    +-  p->pMethod = (sqlite3_io_methods*)&MemJournalMethods;
    ++  sqlite3JournalOpen(0, 0, pJfd, 0, -1);
    ++}
    ++
    ++#if defined(SQLITE_ENABLE_ATOMIC_WRITE) \
    ++ || defined(SQLITE_ENABLE_BATCH_ATOMIC_WRITE)
    ++/*
    ++** If the argument p points to a MemJournal structure that is not an 
    ++** in-memory-only journal file (i.e. is one that was opened with a +ve
    ++** nSpill parameter or as SQLITE_OPEN_MAIN_JOURNAL), and the underlying 
    ++** file has not yet been created, create it now.
    ++*/
    ++SQLITE_PRIVATE int sqlite3JournalCreate(sqlite3_file *pJfd){
    ++  int rc = SQLITE_OK;
    ++  MemJournal *p = (MemJournal*)pJfd;
    ++  if( p->pMethod==&MemJournalMethods && (
    ++#ifdef SQLITE_ENABLE_ATOMIC_WRITE
    ++     p->nSpill>0
    ++#else
    ++     /* While this appears to not be possible without ATOMIC_WRITE, the
    ++     ** paths are complex, so it seems prudent to leave the test in as
    ++     ** a NEVER(), in case our analysis is subtly flawed. */
    ++     NEVER(p->nSpill>0)
    ++#endif
    ++#ifdef SQLITE_ENABLE_BATCH_ATOMIC_WRITE
    ++     || (p->flags & SQLITE_OPEN_MAIN_JOURNAL)
    ++#endif
    ++  )){
    ++    rc = memjrnlCreateFile(p);
    ++  }
    ++  return rc;
    + }
    ++#endif
    + 
    + /*
    +-** Return true if the file-handle passed as an argument is 
    +-** an in-memory journal 
    ++** The file-handle passed as the only argument is open on a journal file.
    ++** Return true if this "journal file" is currently stored in heap memory,
    ++** or false otherwise.
    + */
    +-SQLITE_PRIVATE int sqlite3IsMemJournal(sqlite3_file *pJfd){
    +-  return pJfd->pMethods==&MemJournalMethods;
    ++SQLITE_PRIVATE int sqlite3JournalIsInMemory(sqlite3_file *p){
    ++  return p->pMethods==&MemJournalMethods;
    + }
    + 
    + /* 
    +-** Return the number of bytes required to store a MemJournal file descriptor.
    ++** Return the number of bytes required to store a JournalFile that uses vfs
    ++** pVfs to create the underlying on-disk files.
    + */
    +-SQLITE_PRIVATE int sqlite3MemJournalSize(void){
    +-  return sizeof(MemJournal);
    ++SQLITE_PRIVATE int sqlite3JournalSize(sqlite3_vfs *pVfs){
    ++  return MAX(pVfs->szOsFile, (int)sizeof(MemJournal));
    + }
    + 
    + /************** End of memjournal.c ******************************************/
    +@@ -83368,32 +91018,40 @@ SQLITE_PRIVATE int sqlite3MemJournalSize(void){
    + **
    + **    WRC_Continue      Continue descending down the tree.
    + **
    +-**    WRC_Prune         Do not descend into child nodes.  But allow
    ++**    WRC_Prune         Do not descend into child nodes, but allow
    + **                      the walk to continue with sibling nodes.
    + **
    + **    WRC_Abort         Do no more callbacks.  Unwind the stack and
    +-**                      return the top-level walk call.
    ++**                      return from the top-level walk call.
    + **
    + ** The return value from this routine is WRC_Abort to abandon the tree walk
    + ** and WRC_Continue to continue.
    + */
    +-SQLITE_PRIVATE int sqlite3WalkExpr(Walker *pWalker, Expr *pExpr){
    ++static SQLITE_NOINLINE int walkExpr(Walker *pWalker, Expr *pExpr){
    +   int rc;
    +-  if( pExpr==0 ) return WRC_Continue;
    +   testcase( ExprHasProperty(pExpr, EP_TokenOnly) );
    +   testcase( ExprHasProperty(pExpr, EP_Reduced) );
    +-  rc = pWalker->xExprCallback(pWalker, pExpr);
    +-  if( rc==WRC_Continue
    +-              && !ExprHasProperty(pExpr,EP_TokenOnly) ){
    +-    if( sqlite3WalkExpr(pWalker, pExpr->pLeft) ) return WRC_Abort;
    +-    if( sqlite3WalkExpr(pWalker, pExpr->pRight) ) return WRC_Abort;
    +-    if( ExprHasProperty(pExpr, EP_xIsSelect) ){
    +-      if( sqlite3WalkSelect(pWalker, pExpr->x.pSelect) ) return WRC_Abort;
    +-    }else{
    +-      if( sqlite3WalkExprList(pWalker, pExpr->x.pList) ) return WRC_Abort;
    ++  while(1){
    ++    rc = pWalker->xExprCallback(pWalker, pExpr);
    ++    if( rc ) return rc & WRC_Abort;
    ++    if( !ExprHasProperty(pExpr,(EP_TokenOnly|EP_Leaf)) ){
    ++      if( pExpr->pLeft && walkExpr(pWalker, pExpr->pLeft) ) return WRC_Abort;
    ++       assert( pExpr->x.pList==0 || pExpr->pRight==0 );
    ++      if( pExpr->pRight ){
    ++        pExpr = pExpr->pRight;
    ++        continue;
    ++      }else if( ExprHasProperty(pExpr, EP_xIsSelect) ){
    ++        if( sqlite3WalkSelect(pWalker, pExpr->x.pSelect) ) return WRC_Abort;
    ++      }else if( pExpr->x.pList ){
    ++        if( sqlite3WalkExprList(pWalker, pExpr->x.pList) ) return WRC_Abort;
    ++      }
    +     }
    ++    break;
    +   }
    +-  return rc & WRC_Abort;
    ++  return WRC_Continue;
    ++}
    ++SQLITE_PRIVATE int sqlite3WalkExpr(Walker *pWalker, Expr *pExpr){
    ++  return pExpr ? walkExpr(pWalker,pExpr) : WRC_Continue;
    + }
    + 
    + /*
    +@@ -83424,7 +91082,6 @@ SQLITE_PRIVATE int sqlite3WalkSelectExpr(Walker *pWalker, Select *p){
    +   if( sqlite3WalkExpr(pWalker, p->pHaving) ) return WRC_Abort;
    +   if( sqlite3WalkExprList(pWalker, p->pOrderBy) ) return WRC_Abort;
    +   if( sqlite3WalkExpr(pWalker, p->pLimit) ) return WRC_Abort;
    +-  if( sqlite3WalkExpr(pWalker, p->pOffset) ) return WRC_Abort;
    +   return WRC_Continue;
    + }
    + 
    +@@ -83441,16 +91098,15 @@ SQLITE_PRIVATE int sqlite3WalkSelectFrom(Walker *pWalker, Select *p){
    +   struct SrcList_item *pItem;
    + 
    +   pSrc = p->pSrc;
    +-  if( ALWAYS(pSrc) ){
    +-    for(i=pSrc->nSrc, pItem=pSrc->a; i>0; i--, pItem++){
    +-      if( sqlite3WalkSelect(pWalker, pItem->pSelect) ){
    +-        return WRC_Abort;
    +-      }
    +-      if( pItem->fg.isTabFunc
    +-       && sqlite3WalkExprList(pWalker, pItem->u1.pFuncArg)
    +-      ){
    +-        return WRC_Abort;
    +-      }
    ++  assert( pSrc!=0 );
    ++  for(i=pSrc->nSrc, pItem=pSrc->a; i>0; i--, pItem++){
    ++    if( pItem->pSelect && sqlite3WalkSelect(pWalker, pItem->pSelect) ){
    ++      return WRC_Abort;
    ++    }
    ++    if( pItem->fg.isTabFunc
    ++     && sqlite3WalkExprList(pWalker, pItem->u1.pFuncArg)
    ++    ){
    ++      return WRC_Abort;
    +     }
    +   }
    +   return WRC_Continue;
    +@@ -83463,8 +91119,9 @@ SQLITE_PRIVATE int sqlite3WalkSelectFrom(Walker *pWalker, Select *p){
    + **
    + ** If it is not NULL, the xSelectCallback() callback is invoked before
    + ** the walk of the expressions and FROM clause. The xSelectCallback2()
    +-** method, if it is not NULL, is invoked following the walk of the 
    +-** expressions and FROM clause.
    ++** method is invoked following the walk of the expressions and FROM clause,
    ++** but only if both xSelectCallback and xSelectCallback2 are both non-NULL
    ++** and if the expressions and FROM clause both return WRC_Continue;
    + **
    + ** Return WRC_Continue under normal conditions.  Return WRC_Abort if
    + ** there is an abort request.
    +@@ -83474,29 +91131,22 @@ SQLITE_PRIVATE int sqlite3WalkSelectFrom(Walker *pWalker, Select *p){
    + */
    + SQLITE_PRIVATE int sqlite3WalkSelect(Walker *pWalker, Select *p){
    +   int rc;
    +-  if( p==0 || (pWalker->xSelectCallback==0 && pWalker->xSelectCallback2==0) ){
    +-    return WRC_Continue;
    +-  }
    +-  rc = WRC_Continue;
    +-  pWalker->walkerDepth++;
    +-  while( p ){
    +-    if( pWalker->xSelectCallback ){
    +-       rc = pWalker->xSelectCallback(pWalker, p);
    +-       if( rc ) break;
    +-    }
    ++  if( p==0 ) return WRC_Continue;
    ++  if( pWalker->xSelectCallback==0 ) return WRC_Continue;
    ++  do{
    ++    rc = pWalker->xSelectCallback(pWalker, p);
    ++    if( rc ) return rc & WRC_Abort;
    +     if( sqlite3WalkSelectExpr(pWalker, p)
    +      || sqlite3WalkSelectFrom(pWalker, p)
    +     ){
    +-      pWalker->walkerDepth--;
    +       return WRC_Abort;
    +     }
    +     if( pWalker->xSelectCallback2 ){
    +       pWalker->xSelectCallback2(pWalker, p);
    +     }
    +     p = p->pPrior;
    +-  }
    +-  pWalker->walkerDepth--;
    +-  return rc & WRC_Abort;
    ++  }while( p!=0 );
    ++  return WRC_Continue;
    + }
    + 
    + /************** End of walker.c **********************************************/
    +@@ -83518,8 +91168,6 @@ SQLITE_PRIVATE int sqlite3WalkSelect(Walker *pWalker, Select *p){
    + ** table and column.
    + */
    + /* #include "sqliteInt.h" */
    +-/* #include <stdlib.h> */
    +-/* #include <string.h> */
    + 
    + /*
    + ** Walk the expression tree pExpr and increase the aggregate function
    +@@ -83724,8 +91372,8 @@ static int lookupName(
    +       zDb = 0;
    +     }else{
    +       for(i=0; i<db->nDb; i++){
    +-        assert( db->aDb[i].zName );
    +-        if( sqlite3StrICmp(db->aDb[i].zName,zDb)==0 ){
    ++        assert( db->aDb[i].zDbSName );
    ++        if( sqlite3StrICmp(db->aDb[i].zDbSName,zDb)==0 ){
    +           pSchema = db->aDb[i].pSchema;
    +           break;
    +         }
    +@@ -83734,7 +91382,8 @@ static int lookupName(
    +   }
    + 
    +   /* Start at the inner-most context and move outward until a match is found */
    +-  while( pNC && cnt==0 ){
    ++  assert( pNC && cnt==0 );
    ++  do{
    +     ExprList *pEList;
    +     SrcList *pSrcList = pNC->pSrcList;
    + 
    +@@ -83831,7 +91480,6 @@ static int lookupName(
    +         }
    +         if( iCol>=pTab->nCol && sqlite3IsRowid(zCol) && VisibleRowid(pTab) ){
    +           /* IMP: R-51414-32910 */
    +-          /* IMP: R-44911-55124 */
    +           iCol = -1;
    +         }
    +         if( iCol<pTab->nCol ){
    +@@ -83866,7 +91514,7 @@ static int lookupName(
    +      && VisibleRowid(pMatch->pTab)
    +     ){
    +       cnt = 1;
    +-      pExpr->iColumn = -1;     /* IMP: R-44911-55124 */
    ++      pExpr->iColumn = -1;
    +       pExpr->affinity = SQLITE_AFF_INTEGER;
    +     }
    + 
    +@@ -83904,6 +91552,10 @@ static int lookupName(
    +             sqlite3ErrorMsg(pParse, "misuse of aliased aggregate %s", zAs);
    +             return WRC_Abort;
    +           }
    ++          if( sqlite3ExprVectorSize(pOrig)!=1 ){
    ++            sqlite3ErrorMsg(pParse, "row value misused");
    ++            return WRC_Abort;
    ++          }
    +           resolveAlias(pParse, pEList, j, pExpr, "", nSubquery);
    +           cnt = 1;
    +           pMatch = 0;
    +@@ -83916,11 +91568,11 @@ static int lookupName(
    +     /* Advance to the next name context.  The loop will exit when either
    +     ** we have a match (cnt>0) or when we run out of name contexts.
    +     */
    +-    if( cnt==0 ){
    +-      pNC = pNC->pNext;
    +-      nSubquery++;
    +-    }
    +-  }
    ++    if( cnt ) break;
    ++    pNC = pNC->pNext;
    ++    nSubquery++;
    ++  }while( pNC );
    ++
    + 
    +   /*
    +   ** If X and Y are NULL (in other words if only the column name Z is
    +@@ -83979,6 +91631,7 @@ static int lookupName(
    +   sqlite3ExprDelete(db, pExpr->pRight);
    +   pExpr->pRight = 0;
    +   pExpr->op = (isTrigger ? TK_TRIGGER : TK_COLUMN);
    ++  ExprSetProperty(pExpr, EP_Leaf);
    + lookupname_end:
    +   if( cnt==1 ){
    +     assert( pNC!=0 );
    +@@ -84017,7 +91670,6 @@ SQLITE_PRIVATE Expr *sqlite3CreateColumnExpr(sqlite3 *db, SrcList *pSrc, int iSr
    +       testcase( iCol==BMS-1 );
    +       pItem->colUsed |= ((Bitmask)1)<<(iCol>=BMS ? BMS-1 : iCol);
    +     }
    +-    ExprSetProperty(p, EP_Resolved);
    +   }
    +   return p;
    + }
    +@@ -84077,8 +91729,6 @@ static int resolveExprStep(Walker *pWalker, Expr *pExpr){
    +   pParse = pNC->pParse;
    +   assert( pParse==pWalker->pParse );
    + 
    +-  if( ExprHasProperty(pExpr, EP_Resolved) ) return WRC_Prune;
    +-  ExprSetProperty(pExpr, EP_Resolved);
    + #ifndef NDEBUG
    +   if( pNC->pSrcList && pNC->pSrcList->nAlloc>0 ){
    +     SrcList *pSrcList = pNC->pSrcList;
    +@@ -84099,7 +91749,8 @@ static int resolveExprStep(Walker *pWalker, Expr *pExpr){
    +       SrcList *pSrcList = pNC->pSrcList;
    +       struct SrcList_item *pItem;
    +       assert( pSrcList && pSrcList->nSrc==1 );
    +-      pItem = pSrcList->a; 
    ++      pItem = pSrcList->a;
    ++      assert( HasRowid(pItem->pTab) && pItem->pTab->pSelect==0 );
    +       pExpr->op = TK_COLUMN;
    +       pExpr->pTab = pItem->pTab;
    +       pExpr->iTable = pItem->iCursor;
    +@@ -84110,34 +91761,38 @@ static int resolveExprStep(Walker *pWalker, Expr *pExpr){
    + #endif /* defined(SQLITE_ENABLE_UPDATE_DELETE_LIMIT)
    +           && !defined(SQLITE_OMIT_SUBQUERY) */
    + 
    +-    /* A lone identifier is the name of a column.
    +-    */
    +-    case TK_ID: {
    +-      return lookupName(pParse, 0, 0, pExpr->u.zToken, pNC, pExpr);
    +-    }
    +-  
    +-    /* A table name and column name:     ID.ID
    ++    /* A column name:                    ID
    ++    ** Or table name and column name:    ID.ID
    +     ** Or a database, table and column:  ID.ID.ID
    ++    **
    ++    ** The TK_ID and TK_OUT cases are combined so that there will only
    ++    ** be one call to lookupName().  Then the compiler will in-line 
    ++    ** lookupName() for a size reduction and performance increase.
    +     */
    ++    case TK_ID:
    +     case TK_DOT: {
    +       const char *zColumn;
    +       const char *zTable;
    +       const char *zDb;
    +       Expr *pRight;
    + 
    +-      /* if( pSrcList==0 ) break; */
    +-      notValid(pParse, pNC, "the \".\" operator", NC_IdxExpr);
    +-      /*notValid(pParse, pNC, "the \".\" operator", NC_PartIdx|NC_IsCheck, 1);*/
    +-      pRight = pExpr->pRight;
    +-      if( pRight->op==TK_ID ){
    ++      if( pExpr->op==TK_ID ){
    +         zDb = 0;
    +-        zTable = pExpr->pLeft->u.zToken;
    +-        zColumn = pRight->u.zToken;
    ++        zTable = 0;
    ++        zColumn = pExpr->u.zToken;
    +       }else{
    +-        assert( pRight->op==TK_DOT );
    +-        zDb = pExpr->pLeft->u.zToken;
    +-        zTable = pRight->pLeft->u.zToken;
    +-        zColumn = pRight->pRight->u.zToken;
    ++        notValid(pParse, pNC, "the \".\" operator", NC_IdxExpr);
    ++        pRight = pExpr->pRight;
    ++        if( pRight->op==TK_ID ){
    ++          zDb = 0;
    ++          zTable = pExpr->pLeft->u.zToken;
    ++          zColumn = pRight->u.zToken;
    ++        }else{
    ++          assert( pRight->op==TK_DOT );
    ++          zDb = pExpr->pLeft->u.zToken;
    ++          zTable = pRight->pLeft->u.zToken;
    ++          zColumn = pRight->pRight->u.zToken;
    ++        }
    +       }
    +       return lookupName(pParse, zDb, zTable, zColumn, pNC, pExpr);
    +     }
    +@@ -84150,26 +91805,24 @@ static int resolveExprStep(Walker *pWalker, Expr *pExpr){
    +       int no_such_func = 0;       /* True if no such function exists */
    +       int wrong_num_args = 0;     /* True if wrong number of arguments */
    +       int is_agg = 0;             /* True if is an aggregate function */
    +-      int auth;                   /* Authorization to use the function */
    +       int nId;                    /* Number of characters in function name */
    +       const char *zId;            /* The function name. */
    +       FuncDef *pDef;              /* Information about the function */
    +       u8 enc = ENC(pParse->db);   /* The database encoding */
    + 
    +       assert( !ExprHasProperty(pExpr, EP_xIsSelect) );
    +-      notValid(pParse, pNC, "functions", NC_PartIdx);
    +       zId = pExpr->u.zToken;
    +       nId = sqlite3Strlen30(zId);
    +-      pDef = sqlite3FindFunction(pParse->db, zId, nId, n, enc, 0);
    ++      pDef = sqlite3FindFunction(pParse->db, zId, n, enc, 0);
    +       if( pDef==0 ){
    +-        pDef = sqlite3FindFunction(pParse->db, zId, nId, -2, enc, 0);
    ++        pDef = sqlite3FindFunction(pParse->db, zId, -2, enc, 0);
    +         if( pDef==0 ){
    +           no_such_func = 1;
    +         }else{
    +           wrong_num_args = 1;
    +         }
    +       }else{
    +-        is_agg = pDef->xFunc==0;
    ++        is_agg = pDef->xFinalize!=0;
    +         if( pDef->funcFlags & SQLITE_FUNC_UNLIKELY ){
    +           ExprSetProperty(pExpr, EP_Unlikely|EP_Skip);
    +           if( n==2 ){
    +@@ -84194,15 +91847,17 @@ static int resolveExprStep(Walker *pWalker, Expr *pExpr){
    +           }             
    +         }
    + #ifndef SQLITE_OMIT_AUTHORIZATION
    +-        auth = sqlite3AuthCheck(pParse, SQLITE_FUNCTION, 0, pDef->zName, 0);
    +-        if( auth!=SQLITE_OK ){
    +-          if( auth==SQLITE_DENY ){
    +-            sqlite3ErrorMsg(pParse, "not authorized to use function: %s",
    +-                                    pDef->zName);
    +-            pNC->nErr++;
    ++        {
    ++          int auth = sqlite3AuthCheck(pParse, SQLITE_FUNCTION, 0,pDef->zName,0);
    ++          if( auth!=SQLITE_OK ){
    ++            if( auth==SQLITE_DENY ){
    ++              sqlite3ErrorMsg(pParse, "not authorized to use function: %s",
    ++                                      pDef->zName);
    ++              pNC->nErr++;
    ++            }
    ++            pExpr->op = TK_NULL;
    ++            return WRC_Prune;
    +           }
    +-          pExpr->op = TK_NULL;
    +-          return WRC_Prune;
    +         }
    + #endif
    +         if( pDef->funcFlags & (SQLITE_FUNC_CONSTANT|SQLITE_FUNC_SLOCHNG) ){
    +@@ -84215,14 +91870,19 @@ static int resolveExprStep(Walker *pWalker, Expr *pExpr){
    +           /* Date/time functions that use 'now', and other functions like
    +           ** sqlite_version() that might change over time cannot be used
    +           ** in an index. */
    +-          notValid(pParse, pNC, "non-deterministic functions", NC_IdxExpr);
    ++          notValid(pParse, pNC, "non-deterministic functions",
    ++                   NC_IdxExpr|NC_PartIdx);
    +         }
    +       }
    +       if( is_agg && (pNC->ncFlags & NC_AllowAgg)==0 ){
    +         sqlite3ErrorMsg(pParse, "misuse of aggregate function %.*s()", nId,zId);
    +         pNC->nErr++;
    +         is_agg = 0;
    +-      }else if( no_such_func && pParse->db->init.busy==0 ){
    ++      }else if( no_such_func && pParse->db->init.busy==0
    ++#ifdef SQLITE_ENABLE_UNKNOWN_SQL_FUNCTION
    ++                && pParse->explain==0
    ++#endif
    ++      ){
    +         sqlite3ErrorMsg(pParse, "no such function: %.*s", nId, zId);
    +         pNC->nErr++;
    +       }else if( wrong_num_args ){
    +@@ -84267,6 +91927,7 @@ static int resolveExprStep(Walker *pWalker, Expr *pExpr){
    +         assert( pNC->nRef>=nRef );
    +         if( nRef!=pNC->nRef ){
    +           ExprSetProperty(pExpr, EP_VarSelect);
    ++          pNC->ncFlags |= NC_VarSelect;
    +         }
    +       }
    +       break;
    +@@ -84275,6 +91936,42 @@ static int resolveExprStep(Walker *pWalker, Expr *pExpr){
    +       notValid(pParse, pNC, "parameters", NC_IsCheck|NC_PartIdx|NC_IdxExpr);
    +       break;
    +     }
    ++    case TK_BETWEEN:
    ++    case TK_EQ:
    ++    case TK_NE:
    ++    case TK_LT:
    ++    case TK_LE:
    ++    case TK_GT:
    ++    case TK_GE:
    ++    case TK_IS:
    ++    case TK_ISNOT: {
    ++      int nLeft, nRight;
    ++      if( pParse->db->mallocFailed ) break;
    ++      assert( pExpr->pLeft!=0 );
    ++      nLeft = sqlite3ExprVectorSize(pExpr->pLeft);
    ++      if( pExpr->op==TK_BETWEEN ){
    ++        nRight = sqlite3ExprVectorSize(pExpr->x.pList->a[0].pExpr);
    ++        if( nRight==nLeft ){
    ++          nRight = sqlite3ExprVectorSize(pExpr->x.pList->a[1].pExpr);
    ++        }
    ++      }else{
    ++        assert( pExpr->pRight!=0 );
    ++        nRight = sqlite3ExprVectorSize(pExpr->pRight);
    ++      }
    ++      if( nLeft!=nRight ){
    ++        testcase( pExpr->op==TK_EQ );
    ++        testcase( pExpr->op==TK_NE );
    ++        testcase( pExpr->op==TK_LT );
    ++        testcase( pExpr->op==TK_LE );
    ++        testcase( pExpr->op==TK_GT );
    ++        testcase( pExpr->op==TK_GE );
    ++        testcase( pExpr->op==TK_IS );
    ++        testcase( pExpr->op==TK_ISNOT );
    ++        testcase( pExpr->op==TK_BETWEEN );
    ++        sqlite3ErrorMsg(pParse, "row value misused");
    ++      }
    ++      break; 
    ++    }
    +   }
    +   return (pParse->nErr || pParse->db->mallocFailed) ? WRC_Abort : WRC_Continue;
    + }
    +@@ -84365,7 +92062,7 @@ static int resolveOrderByTermToExprList(
    +   ** result-set entry.
    +   */
    +   for(i=0; i<pEList->nExpr; i++){
    +-    if( sqlite3ExprCompare(pEList->a[i].pExpr, pE, -1)<2 ){
    ++    if( sqlite3ExprCompare(0, pEList->a[i].pExpr, pE, -1)<2 ){
    +       return i+1;
    +     }
    +   }
    +@@ -84416,12 +92113,10 @@ static int resolveCompoundOrderBy(
    +   pOrderBy = pSelect->pOrderBy;
    +   if( pOrderBy==0 ) return 0;
    +   db = pParse->db;
    +-#if SQLITE_MAX_COLUMN
    +   if( pOrderBy->nExpr>db->aLimit[SQLITE_LIMIT_COLUMN] ){
    +     sqlite3ErrorMsg(pParse, "too many terms in ORDER BY clause");
    +     return 1;
    +   }
    +-#endif
    +   for(i=0; i<pOrderBy->nExpr; i++){
    +     pOrderBy->a[i].done = 0;
    +   }
    +@@ -84513,12 +92208,10 @@ SQLITE_PRIVATE int sqlite3ResolveOrderGroupBy(
    +   struct ExprList_item *pItem;
    + 
    +   if( pOrderBy==0 || pParse->db->mallocFailed ) return 0;
    +-#if SQLITE_MAX_COLUMN
    +   if( pOrderBy->nExpr>db->aLimit[SQLITE_LIMIT_COLUMN] ){
    +     sqlite3ErrorMsg(pParse, "too many terms in %s BY clause", zType);
    +     return 1;
    +   }
    +-#endif
    +   pEList = pSelect->pEList;
    +   assert( pEList!=0 );  /* sqlite3SelectNew() guarantees this */
    +   for(i=0, pItem=pOrderBy->a; i<pOrderBy->nExpr; i++, pItem++){
    +@@ -84599,7 +92292,7 @@ static int resolveOrderGroupBy(
    +       return 1;
    +     }
    +     for(j=0; j<pSelect->pEList->nExpr; j++){
    +-      if( sqlite3ExprCompare(pE, pSelect->pEList->a[j].pExpr, -1)==0 ){
    ++      if( sqlite3ExprCompare(0, pE, pSelect->pEList->a[j].pExpr, -1)==0 ){
    +         pItem->u.x.iOrderByCol = j+1;
    +       }
    +     }
    +@@ -84656,8 +92349,7 @@ static int resolveSelectStep(Walker *pWalker, Select *p){
    +     */
    +     memset(&sNC, 0, sizeof(sNC));
    +     sNC.pParse = pParse;
    +-    if( sqlite3ResolveExprNames(&sNC, p->pLimit) ||
    +-        sqlite3ResolveExprNames(&sNC, p->pOffset) ){
    ++    if( sqlite3ResolveExprNames(&sNC, p->pLimit) ){
    +       return WRC_Abort;
    +     }
    + 
    +@@ -84885,35 +92577,29 @@ SQLITE_PRIVATE int sqlite3ResolveExprNames(
    +   u16 savedHasAgg;
    +   Walker w;
    + 
    +-  if( pExpr==0 ) return 0;
    +-#if SQLITE_MAX_EXPR_DEPTH>0
    +-  {
    +-    Parse *pParse = pNC->pParse;
    +-    if( sqlite3ExprCheckHeight(pParse, pExpr->nHeight+pNC->pParse->nHeight) ){
    +-      return 1;
    +-    }
    +-    pParse->nHeight += pExpr->nHeight;
    +-  }
    +-#endif
    ++  if( pExpr==0 ) return SQLITE_OK;
    +   savedHasAgg = pNC->ncFlags & (NC_HasAgg|NC_MinMaxAgg);
    +   pNC->ncFlags &= ~(NC_HasAgg|NC_MinMaxAgg);
    +-  memset(&w, 0, sizeof(w));
    ++  w.pParse = pNC->pParse;
    +   w.xExprCallback = resolveExprStep;
    +   w.xSelectCallback = resolveSelectStep;
    +-  w.pParse = pNC->pParse;
    ++  w.xSelectCallback2 = 0;
    +   w.u.pNC = pNC;
    ++#if SQLITE_MAX_EXPR_DEPTH>0
    ++  w.pParse->nHeight += pExpr->nHeight;
    ++  if( sqlite3ExprCheckHeight(w.pParse, w.pParse->nHeight) ){
    ++    return SQLITE_ERROR;
    ++  }
    ++#endif
    +   sqlite3WalkExpr(&w, pExpr);
    + #if SQLITE_MAX_EXPR_DEPTH>0
    +-  pNC->pParse->nHeight -= pExpr->nHeight;
    ++  w.pParse->nHeight -= pExpr->nHeight;
    + #endif
    +-  if( pNC->nErr>0 || w.pParse->nErr>0 ){
    +-    ExprSetProperty(pExpr, EP_Error);
    +-  }
    +   if( pNC->ncFlags & NC_HasAgg ){
    +     ExprSetProperty(pExpr, EP_Agg);
    +   }
    +   pNC->ncFlags |= savedHasAgg;
    +-  return ExprHasProperty(pExpr, EP_Error);
    ++  return pNC->nErr>0 || w.pParse->nErr>0;
    + }
    + 
    + /*
    +@@ -84926,9 +92612,10 @@ SQLITE_PRIVATE int sqlite3ResolveExprListNames(
    +   ExprList *pList         /* The expression list to be analyzed. */
    + ){
    +   int i;
    +-  assert( pList!=0 );
    +-  for(i=0; i<pList->nExpr; i++){
    +-    if( sqlite3ResolveExprNames(pNC, pList->a[i].pExpr) ) return WRC_Abort;
    ++  if( pList ){
    ++    for(i=0; i<pList->nExpr; i++){
    ++      if( sqlite3ResolveExprNames(pNC, pList->a[i].pExpr) ) return WRC_Abort;
    ++    }
    +   }
    +   return WRC_Continue;
    + }
    +@@ -84953,9 +92640,9 @@ SQLITE_PRIVATE void sqlite3ResolveSelectNames(
    +   Walker w;
    + 
    +   assert( p!=0 );
    +-  memset(&w, 0, sizeof(w));
    +   w.xExprCallback = resolveExprStep;
    +   w.xSelectCallback = resolveSelectStep;
    ++  w.xSelectCallback2 = 0;
    +   w.pParse = pParse;
    +   w.u.pNC = pOuterNC;
    +   sqlite3WalkSelect(&w, p);
    +@@ -85014,6 +92701,18 @@ SQLITE_PRIVATE void sqlite3ResolveSelfReference(
    + */
    + /* #include "sqliteInt.h" */
    + 
    ++/* Forward declarations */
    ++static void exprCodeBetween(Parse*,Expr*,int,void(*)(Parse*,Expr*,int,int),int);
    ++static int exprCodeVector(Parse *pParse, Expr *p, int *piToFree);
    ++
    ++/*
    ++** Return the affinity character for a single column of a table.
    ++*/
    ++SQLITE_PRIVATE char sqlite3TableColumnAffinity(Table *pTab, int iCol){
    ++  assert( iCol<pTab->nCol );
    ++  return iCol>=0 ? pTab->aCol[iCol].affinity : SQLITE_AFF_INTEGER;
    ++}
    ++
    + /*
    + ** Return the 'affinity' of the expression pExpr if any.
    + **
    +@@ -85039,21 +92738,21 @@ SQLITE_PRIVATE char sqlite3ExprAffinity(Expr *pExpr){
    +     assert( pExpr->flags&EP_xIsSelect );
    +     return sqlite3ExprAffinity(pExpr->x.pSelect->pEList->a[0].pExpr);
    +   }
    ++  if( op==TK_REGISTER ) op = pExpr->op2;
    + #ifndef SQLITE_OMIT_CAST
    +   if( op==TK_CAST ){
    +     assert( !ExprHasProperty(pExpr, EP_IntValue) );
    +     return sqlite3AffinityType(pExpr->u.zToken, 0);
    +   }
    + #endif
    +-  if( (op==TK_AGG_COLUMN || op==TK_COLUMN || op==TK_REGISTER) 
    +-   && pExpr->pTab!=0
    +-  ){
    +-    /* op==TK_REGISTER && pExpr->pTab!=0 happens when pExpr was originally
    +-    ** a TK_COLUMN but was previously evaluated and cached in a register */
    +-    int j = pExpr->iColumn;
    +-    if( j<0 ) return SQLITE_AFF_INTEGER;
    +-    assert( pExpr->pTab && j<pExpr->pTab->nCol );
    +-    return pExpr->pTab->aCol[j].affinity;
    ++  if( (op==TK_AGG_COLUMN || op==TK_COLUMN) && pExpr->pTab ){
    ++    return sqlite3TableColumnAffinity(pExpr->pTab, pExpr->iColumn);
    ++  }
    ++  if( op==TK_SELECT_COLUMN ){
    ++    assert( pExpr->pLeft->flags&EP_xIsSelect );
    ++    return sqlite3ExprAffinity(
    ++        pExpr->pLeft->x.pSelect->pEList->a[pExpr->iColumn].pExpr
    ++    );
    +   }
    +   return pExpr->affinity;
    + }
    +@@ -85085,8 +92784,7 @@ SQLITE_PRIVATE Expr *sqlite3ExprAddCollateToken(
    + SQLITE_PRIVATE Expr *sqlite3ExprAddCollateString(Parse *pParse, Expr *pExpr, const char *zC){
    +   Token s;
    +   assert( zC!=0 );
    +-  s.z = zC;
    +-  s.n = sqlite3Strlen30(s.z);
    ++  sqlite3TokenInit(&s, (char*)zC);
    +   return sqlite3ExprAddCollateToken(pParse, pExpr, &s, 0);
    + }
    + 
    +@@ -85113,6 +92811,11 @@ SQLITE_PRIVATE Expr *sqlite3ExprSkipCollate(Expr *pExpr){
    + ** Return the collation sequence for the expression pExpr. If
    + ** there is no defined collating sequence, return NULL.
    + **
    ++** See also: sqlite3ExprNNCollSeq()
    ++**
    ++** The sqlite3ExprNNCollSeq() works the same exact that it returns the
    ++** default collation if pExpr has no defined collation.
    ++**
    + ** The collating sequence might be determined by a COLLATE operator
    + ** or by the presence of a column with a defined collating sequence.
    + ** COLLATE operators take first precedence.  Left operands take
    +@@ -85177,6 +92880,32 @@ SQLITE_PRIVATE CollSeq *sqlite3ExprCollSeq(Parse *pParse, Expr *pExpr){
    +   return pColl;
    + }
    + 
    ++/*
    ++** Return the collation sequence for the expression pExpr. If
    ++** there is no defined collating sequence, return a pointer to the
    ++** defautl collation sequence.
    ++**
    ++** See also: sqlite3ExprCollSeq()
    ++**
    ++** The sqlite3ExprCollSeq() routine works the same except that it
    ++** returns NULL if there is no defined collation.
    ++*/
    ++SQLITE_PRIVATE CollSeq *sqlite3ExprNNCollSeq(Parse *pParse, Expr *pExpr){
    ++  CollSeq *p = sqlite3ExprCollSeq(pParse, pExpr);
    ++  if( p==0 ) p = pParse->db->pDfltColl;
    ++  assert( p!=0 );
    ++  return p;
    ++}
    ++
    ++/*
    ++** Return TRUE if the two expressions have equivalent collating sequences.
    ++*/
    ++SQLITE_PRIVATE int sqlite3ExprCollSeqMatch(Parse *pParse, Expr *pE1, Expr *pE2){
    ++  CollSeq *pColl1 = sqlite3ExprNNCollSeq(pParse, pE1);
    ++  CollSeq *pColl2 = sqlite3ExprNNCollSeq(pParse, pE2);
    ++  return sqlite3StrICmp(pColl1->zName, pColl2->zName)==0;
    ++}
    ++
    + /*
    + ** pExpr is an operand of a comparison operator.  aff2 is the
    + ** type affinity of the other operand.  This routine returns the
    +@@ -85220,7 +92949,7 @@ static char comparisonAffinity(Expr *pExpr){
    +     aff = sqlite3CompareAffinity(pExpr->pRight, aff);
    +   }else if( ExprHasProperty(pExpr, EP_xIsSelect) ){
    +     aff = sqlite3CompareAffinity(pExpr->x.pSelect->pEList->a[0].pExpr, aff);
    +-  }else if( !aff ){
    ++  }else if( aff==0 ){
    +     aff = SQLITE_AFF_BLOB;
    +   }
    +   return aff;
    +@@ -85310,6 +93039,270 @@ static int codeCompare(
    +   return addr;
    + }
    + 
    ++/*
    ++** Return true if expression pExpr is a vector, or false otherwise.
    ++**
    ++** A vector is defined as any expression that results in two or more
    ++** columns of result.  Every TK_VECTOR node is an vector because the
    ++** parser will not generate a TK_VECTOR with fewer than two entries.
    ++** But a TK_SELECT might be either a vector or a scalar. It is only
    ++** considered a vector if it has two or more result columns.
    ++*/
    ++SQLITE_PRIVATE int sqlite3ExprIsVector(Expr *pExpr){
    ++  return sqlite3ExprVectorSize(pExpr)>1;
    ++}
    ++
    ++/*
    ++** If the expression passed as the only argument is of type TK_VECTOR 
    ++** return the number of expressions in the vector. Or, if the expression
    ++** is a sub-select, return the number of columns in the sub-select. For
    ++** any other type of expression, return 1.
    ++*/
    ++SQLITE_PRIVATE int sqlite3ExprVectorSize(Expr *pExpr){
    ++  u8 op = pExpr->op;
    ++  if( op==TK_REGISTER ) op = pExpr->op2;
    ++  if( op==TK_VECTOR ){
    ++    return pExpr->x.pList->nExpr;
    ++  }else if( op==TK_SELECT ){
    ++    return pExpr->x.pSelect->pEList->nExpr;
    ++  }else{
    ++    return 1;
    ++  }
    ++}
    ++
    ++/*
    ++** Return a pointer to a subexpression of pVector that is the i-th
    ++** column of the vector (numbered starting with 0).  The caller must
    ++** ensure that i is within range.
    ++**
    ++** If pVector is really a scalar (and "scalar" here includes subqueries
    ++** that return a single column!) then return pVector unmodified.
    ++**
    ++** pVector retains ownership of the returned subexpression.
    ++**
    ++** If the vector is a (SELECT ...) then the expression returned is
    ++** just the expression for the i-th term of the result set, and may
    ++** not be ready for evaluation because the table cursor has not yet
    ++** been positioned.
    ++*/
    ++SQLITE_PRIVATE Expr *sqlite3VectorFieldSubexpr(Expr *pVector, int i){
    ++  assert( i<sqlite3ExprVectorSize(pVector) );
    ++  if( sqlite3ExprIsVector(pVector) ){
    ++    assert( pVector->op2==0 || pVector->op==TK_REGISTER );
    ++    if( pVector->op==TK_SELECT || pVector->op2==TK_SELECT ){
    ++      return pVector->x.pSelect->pEList->a[i].pExpr;
    ++    }else{
    ++      return pVector->x.pList->a[i].pExpr;
    ++    }
    ++  }
    ++  return pVector;
    ++}
    ++
    ++/*
    ++** Compute and return a new Expr object which when passed to
    ++** sqlite3ExprCode() will generate all necessary code to compute
    ++** the iField-th column of the vector expression pVector.
    ++**
    ++** It is ok for pVector to be a scalar (as long as iField==0).  
    ++** In that case, this routine works like sqlite3ExprDup().
    ++**
    ++** The caller owns the returned Expr object and is responsible for
    ++** ensuring that the returned value eventually gets freed.
    ++**
    ++** The caller retains ownership of pVector.  If pVector is a TK_SELECT,
    ++** then the returned object will reference pVector and so pVector must remain
    ++** valid for the life of the returned object.  If pVector is a TK_VECTOR
    ++** or a scalar expression, then it can be deleted as soon as this routine
    ++** returns.
    ++**
    ++** A trick to cause a TK_SELECT pVector to be deleted together with
    ++** the returned Expr object is to attach the pVector to the pRight field
    ++** of the returned TK_SELECT_COLUMN Expr object.
    ++*/
    ++SQLITE_PRIVATE Expr *sqlite3ExprForVectorField(
    ++  Parse *pParse,       /* Parsing context */
    ++  Expr *pVector,       /* The vector.  List of expressions or a sub-SELECT */
    ++  int iField           /* Which column of the vector to return */
    ++){
    ++  Expr *pRet;
    ++  if( pVector->op==TK_SELECT ){
    ++    assert( pVector->flags & EP_xIsSelect );
    ++    /* The TK_SELECT_COLUMN Expr node:
    ++    **
    ++    ** pLeft:           pVector containing TK_SELECT.  Not deleted.
    ++    ** pRight:          not used.  But recursively deleted.
    ++    ** iColumn:         Index of a column in pVector
    ++    ** iTable:          0 or the number of columns on the LHS of an assignment
    ++    ** pLeft->iTable:   First in an array of register holding result, or 0
    ++    **                  if the result is not yet computed.
    ++    **
    ++    ** sqlite3ExprDelete() specifically skips the recursive delete of
    ++    ** pLeft on TK_SELECT_COLUMN nodes.  But pRight is followed, so pVector
    ++    ** can be attached to pRight to cause this node to take ownership of
    ++    ** pVector.  Typically there will be multiple TK_SELECT_COLUMN nodes
    ++    ** with the same pLeft pointer to the pVector, but only one of them
    ++    ** will own the pVector.
    ++    */
    ++    pRet = sqlite3PExpr(pParse, TK_SELECT_COLUMN, 0, 0);
    ++    if( pRet ){
    ++      pRet->iColumn = iField;
    ++      pRet->pLeft = pVector;
    ++    }
    ++    assert( pRet==0 || pRet->iTable==0 );
    ++  }else{
    ++    if( pVector->op==TK_VECTOR ) pVector = pVector->x.pList->a[iField].pExpr;
    ++    pRet = sqlite3ExprDup(pParse->db, pVector, 0);
    ++  }
    ++  return pRet;
    ++}
    ++
    ++/*
    ++** If expression pExpr is of type TK_SELECT, generate code to evaluate
    ++** it. Return the register in which the result is stored (or, if the 
    ++** sub-select returns more than one column, the first in an array
    ++** of registers in which the result is stored).
    ++**
    ++** If pExpr is not a TK_SELECT expression, return 0.
    ++*/
    ++static int exprCodeSubselect(Parse *pParse, Expr *pExpr){
    ++  int reg = 0;
    ++#ifndef SQLITE_OMIT_SUBQUERY
    ++  if( pExpr->op==TK_SELECT ){
    ++    reg = sqlite3CodeSubselect(pParse, pExpr, 0, 0);
    ++  }
    ++#endif
    ++  return reg;
    ++}
    ++
    ++/*
    ++** Argument pVector points to a vector expression - either a TK_VECTOR
    ++** or TK_SELECT that returns more than one column. This function returns
    ++** the register number of a register that contains the value of
    ++** element iField of the vector.
    ++**
    ++** If pVector is a TK_SELECT expression, then code for it must have 
    ++** already been generated using the exprCodeSubselect() routine. In this
    ++** case parameter regSelect should be the first in an array of registers
    ++** containing the results of the sub-select. 
    ++**
    ++** If pVector is of type TK_VECTOR, then code for the requested field
    ++** is generated. In this case (*pRegFree) may be set to the number of
    ++** a temporary register to be freed by the caller before returning.
    ++**
    ++** Before returning, output parameter (*ppExpr) is set to point to the
    ++** Expr object corresponding to element iElem of the vector.
    ++*/
    ++static int exprVectorRegister(
    ++  Parse *pParse,                  /* Parse context */
    ++  Expr *pVector,                  /* Vector to extract element from */
    ++  int iField,                     /* Field to extract from pVector */
    ++  int regSelect,                  /* First in array of registers */
    ++  Expr **ppExpr,                  /* OUT: Expression element */
    ++  int *pRegFree                   /* OUT: Temp register to free */
    ++){
    ++  u8 op = pVector->op;
    ++  assert( op==TK_VECTOR || op==TK_REGISTER || op==TK_SELECT );
    ++  if( op==TK_REGISTER ){
    ++    *ppExpr = sqlite3VectorFieldSubexpr(pVector, iField);
    ++    return pVector->iTable+iField;
    ++  }
    ++  if( op==TK_SELECT ){
    ++    *ppExpr = pVector->x.pSelect->pEList->a[iField].pExpr;
    ++     return regSelect+iField;
    ++  }
    ++  *ppExpr = pVector->x.pList->a[iField].pExpr;
    ++  return sqlite3ExprCodeTemp(pParse, *ppExpr, pRegFree);
    ++}
    ++
    ++/*
    ++** Expression pExpr is a comparison between two vector values. Compute
    ++** the result of the comparison (1, 0, or NULL) and write that
    ++** result into register dest.
    ++**
    ++** The caller must satisfy the following preconditions:
    ++**
    ++**    if pExpr->op==TK_IS:      op==TK_EQ and p5==SQLITE_NULLEQ
    ++**    if pExpr->op==TK_ISNOT:   op==TK_NE and p5==SQLITE_NULLEQ
    ++**    otherwise:                op==pExpr->op and p5==0
    ++*/
    ++static void codeVectorCompare(
    ++  Parse *pParse,        /* Code generator context */
    ++  Expr *pExpr,          /* The comparison operation */
    ++  int dest,             /* Write results into this register */
    ++  u8 op,                /* Comparison operator */
    ++  u8 p5                 /* SQLITE_NULLEQ or zero */
    ++){
    ++  Vdbe *v = pParse->pVdbe;
    ++  Expr *pLeft = pExpr->pLeft;
    ++  Expr *pRight = pExpr->pRight;
    ++  int nLeft = sqlite3ExprVectorSize(pLeft);
    ++  int i;
    ++  int regLeft = 0;
    ++  int regRight = 0;
    ++  u8 opx = op;
    ++  int addrDone = sqlite3VdbeMakeLabel(v);
    ++
    ++  if( nLeft!=sqlite3ExprVectorSize(pRight) ){
    ++    sqlite3ErrorMsg(pParse, "row value misused");
    ++    return;
    ++  }
    ++  assert( pExpr->op==TK_EQ || pExpr->op==TK_NE 
    ++       || pExpr->op==TK_IS || pExpr->op==TK_ISNOT 
    ++       || pExpr->op==TK_LT || pExpr->op==TK_GT 
    ++       || pExpr->op==TK_LE || pExpr->op==TK_GE 
    ++  );
    ++  assert( pExpr->op==op || (pExpr->op==TK_IS && op==TK_EQ)
    ++            || (pExpr->op==TK_ISNOT && op==TK_NE) );
    ++  assert( p5==0 || pExpr->op!=op );
    ++  assert( p5==SQLITE_NULLEQ || pExpr->op==op );
    ++
    ++  p5 |= SQLITE_STOREP2;
    ++  if( opx==TK_LE ) opx = TK_LT;
    ++  if( opx==TK_GE ) opx = TK_GT;
    ++
    ++  regLeft = exprCodeSubselect(pParse, pLeft);
    ++  regRight = exprCodeSubselect(pParse, pRight);
    ++
    ++  for(i=0; 1 /*Loop exits by "break"*/; i++){
    ++    int regFree1 = 0, regFree2 = 0;
    ++    Expr *pL, *pR; 
    ++    int r1, r2;
    ++    assert( i>=0 && i<nLeft );
    ++    if( i>0 ) sqlite3ExprCachePush(pParse);
    ++    r1 = exprVectorRegister(pParse, pLeft, i, regLeft, &pL, &regFree1);
    ++    r2 = exprVectorRegister(pParse, pRight, i, regRight, &pR, &regFree2);
    ++    codeCompare(pParse, pL, pR, opx, r1, r2, dest, p5);
    ++    testcase(op==OP_Lt); VdbeCoverageIf(v,op==OP_Lt);
    ++    testcase(op==OP_Le); VdbeCoverageIf(v,op==OP_Le);
    ++    testcase(op==OP_Gt); VdbeCoverageIf(v,op==OP_Gt);
    ++    testcase(op==OP_Ge); VdbeCoverageIf(v,op==OP_Ge);
    ++    testcase(op==OP_Eq); VdbeCoverageIf(v,op==OP_Eq);
    ++    testcase(op==OP_Ne); VdbeCoverageIf(v,op==OP_Ne);
    ++    sqlite3ReleaseTempReg(pParse, regFree1);
    ++    sqlite3ReleaseTempReg(pParse, regFree2);
    ++    if( i>0 ) sqlite3ExprCachePop(pParse);
    ++    if( i==nLeft-1 ){
    ++      break;
    ++    }
    ++    if( opx==TK_EQ ){
    ++      sqlite3VdbeAddOp2(v, OP_IfNot, dest, addrDone); VdbeCoverage(v);
    ++      p5 |= SQLITE_KEEPNULL;
    ++    }else if( opx==TK_NE ){
    ++      sqlite3VdbeAddOp2(v, OP_If, dest, addrDone); VdbeCoverage(v);
    ++      p5 |= SQLITE_KEEPNULL;
    ++    }else{
    ++      assert( op==TK_LT || op==TK_GT || op==TK_LE || op==TK_GE );
    ++      sqlite3VdbeAddOp2(v, OP_ElseNotEq, 0, addrDone);
    ++      VdbeCoverageIf(v, op==TK_LT);
    ++      VdbeCoverageIf(v, op==TK_GT);
    ++      VdbeCoverageIf(v, op==TK_LE);
    ++      VdbeCoverageIf(v, op==TK_GE);
    ++      if( i==nLeft-2 ) opx = op;
    ++    }
    ++  }
    ++  sqlite3VdbeResolveLabel(v, addrDone);
    ++}
    ++
    + #if SQLITE_MAX_EXPR_DEPTH>0
    + /*
    + ** Check that argument nHeight is less than or equal to the maximum
    +@@ -85352,16 +93345,15 @@ static void heightOfExprList(ExprList *p, int *pnHeight){
    +     }
    +   }
    + }
    +-static void heightOfSelect(Select *p, int *pnHeight){
    +-  if( p ){
    ++static void heightOfSelect(Select *pSelect, int *pnHeight){
    ++  Select *p;
    ++  for(p=pSelect; p; p=p->pPrior){
    +     heightOfExpr(p->pWhere, pnHeight);
    +     heightOfExpr(p->pHaving, pnHeight);
    +     heightOfExpr(p->pLimit, pnHeight);
    +-    heightOfExpr(p->pOffset, pnHeight);
    +     heightOfExprList(p->pEList, pnHeight);
    +     heightOfExprList(p->pGroupBy, pnHeight);
    +     heightOfExprList(p->pOrderBy, pnHeight);
    +-    heightOfSelect(p->pPrior, pnHeight);
    +   }
    + }
    + 
    +@@ -85445,7 +93437,7 @@ SQLITE_PRIVATE void sqlite3ExprSetHeightAndFlags(Parse *pParse, Expr *p){
    + ** is allocated to hold the integer text and the dequote flag is ignored.
    + */
    + SQLITE_PRIVATE Expr *sqlite3ExprAlloc(
    +-  sqlite3 *db,            /* Handle for sqlite3DbMallocZero() (may be null) */
    ++  sqlite3 *db,            /* Handle for sqlite3DbMallocRawNN() */
    +   int op,                 /* Expression opcode */
    +   const Token *pToken,    /* Token argument.  Might be NULL */
    +   int dequote             /* True to dequote */
    +@@ -85454,6 +93446,7 @@ SQLITE_PRIVATE Expr *sqlite3ExprAlloc(
    +   int nExtra = 0;
    +   int iValue = 0;
    + 
    ++  assert( db!=0 );
    +   if( pToken ){
    +     if( op!=TK_INTEGER || pToken->z==0
    +           || sqlite3GetInt32(pToken->z, &iValue)==0 ){
    +@@ -85461,24 +93454,23 @@ SQLITE_PRIVATE Expr *sqlite3ExprAlloc(
    +       assert( iValue>=0 );
    +     }
    +   }
    +-  pNew = sqlite3DbMallocZero(db, sizeof(Expr)+nExtra);
    ++  pNew = sqlite3DbMallocRawNN(db, sizeof(Expr)+nExtra);
    +   if( pNew ){
    ++    memset(pNew, 0, sizeof(Expr));
    +     pNew->op = (u8)op;
    +     pNew->iAgg = -1;
    +     if( pToken ){
    +       if( nExtra==0 ){
    +-        pNew->flags |= EP_IntValue;
    ++        pNew->flags |= EP_IntValue|EP_Leaf;
    +         pNew->u.iValue = iValue;
    +       }else{
    +-        int c;
    +         pNew->u.zToken = (char*)&pNew[1];
    +         assert( pToken->z!=0 || pToken->n==0 );
    +         if( pToken->n ) memcpy(pNew->u.zToken, pToken->z, pToken->n);
    +         pNew->u.zToken[pToken->n] = 0;
    +-        if( dequote && nExtra>=3 
    +-             && ((c = pToken->z[0])=='\'' || c=='"' || c=='[' || c=='`') ){
    ++        if( dequote && sqlite3Isquote(pNew->u.zToken[0]) ){
    ++          if( pNew->u.zToken[0]=='"' ) pNew->flags |= EP_DblQuoted;
    +           sqlite3Dequote(pNew->u.zToken);
    +-          if( c=='"' ) pNew->flags |= EP_DblQuoted;
    +         }
    +       }
    +     }
    +@@ -85500,7 +93492,7 @@ SQLITE_PRIVATE Expr *sqlite3Expr(
    + ){
    +   Token x;
    +   x.z = zToken;
    +-  x.n = zToken ? sqlite3Strlen30(zToken) : 0;
    ++  x.n = sqlite3Strlen30(zToken);
    +   return sqlite3ExprAlloc(db, op, &x, 0);
    + }
    + 
    +@@ -85544,15 +93536,19 @@ SQLITE_PRIVATE Expr *sqlite3PExpr(
    +   Parse *pParse,          /* Parsing context */
    +   int op,                 /* Expression opcode */
    +   Expr *pLeft,            /* Left operand */
    +-  Expr *pRight,           /* Right operand */
    +-  const Token *pToken     /* Argument token */
    ++  Expr *pRight            /* Right operand */
    + ){
    +   Expr *p;
    +-  if( op==TK_AND && pLeft && pRight && pParse->nErr==0 ){
    ++  if( op==TK_AND && pParse->nErr==0 ){
    +     /* Take advantage of short-circuit false optimization for AND */
    +     p = sqlite3ExprAnd(pParse->db, pLeft, pRight);
    +   }else{
    +-    p = sqlite3ExprAlloc(pParse->db, op, pToken, 1);
    ++    p = sqlite3DbMallocRawNN(pParse->db, sizeof(Expr));
    ++    if( p ){
    ++      memset(p, 0, sizeof(Expr));
    ++      p->op = op & TKFLG_MASK;
    ++      p->iAgg = -1;
    ++    }
    +     sqlite3ExprAttachSubtrees(pParse->db, p, pLeft, pRight);
    +   }
    +   if( p ) {
    +@@ -85561,6 +93557,22 @@ SQLITE_PRIVATE Expr *sqlite3PExpr(
    +   return p;
    + }
    + 
    ++/*
    ++** Add pSelect to the Expr.x.pSelect field.  Or, if pExpr is NULL (due
    ++** do a memory allocation failure) then delete the pSelect object.
    ++*/
    ++SQLITE_PRIVATE void sqlite3PExprAddSelect(Parse *pParse, Expr *pExpr, Select *pSelect){
    ++  if( pExpr ){
    ++    pExpr->x.pSelect = pSelect;
    ++    ExprSetProperty(pExpr, EP_xIsSelect|EP_Subquery);
    ++    sqlite3ExprSetHeightAndFlags(pParse, pExpr);
    ++  }else{
    ++    assert( pParse->db->mallocFailed );
    ++    sqlite3SelectDelete(pParse->db, pSelect);
    ++  }
    ++}
    ++
    ++
    + /*
    + ** If the expression is always either TRUE or FALSE (respectively),
    + ** then return 1.  If one cannot determine the truth value of the
    +@@ -85626,6 +93638,7 @@ SQLITE_PRIVATE Expr *sqlite3ExprFunction(Parse *pParse, ExprList *pList, Token *
    +     return 0;
    +   }
    +   pNew->x.pList = pList;
    ++  ExprSetProperty(pNew, EP_HasFunc);
    +   assert( !ExprHasProperty(pNew, EP_xIsSelect) );
    +   sqlite3ExprSetHeightAndFlags(pParse, pNew);
    +   return pNew;
    +@@ -85639,7 +93652,7 @@ SQLITE_PRIVATE Expr *sqlite3ExprFunction(Parse *pParse, ExprList *pList, Token *
    + ** variable number.
    + **
    + ** Wildcards of the form "?nnn" are assigned the number "nnn".  We make
    +-** sure "nnn" is not too be to avoid a denial of service attack when
    ++** sure "nnn" is not too big to avoid a denial of service attack when
    + ** the SQL statement comes from an external source.
    + **
    + ** Wildcards of the form ":aaa", "@aaa", or "$aaa" are assigned the same number
    +@@ -85647,28 +93660,34 @@ SQLITE_PRIVATE Expr *sqlite3ExprFunction(Parse *pParse, ExprList *pList, Token *
    + ** instance of the wildcard, the next sequential variable number is
    + ** assigned.
    + */
    +-SQLITE_PRIVATE void sqlite3ExprAssignVarNumber(Parse *pParse, Expr *pExpr){
    ++SQLITE_PRIVATE void sqlite3ExprAssignVarNumber(Parse *pParse, Expr *pExpr, u32 n){
    +   sqlite3 *db = pParse->db;
    +   const char *z;
    ++  ynVar x;
    + 
    +   if( pExpr==0 ) return;
    +   assert( !ExprHasProperty(pExpr, EP_IntValue|EP_Reduced|EP_TokenOnly) );
    +   z = pExpr->u.zToken;
    +   assert( z!=0 );
    +   assert( z[0]!=0 );
    ++  assert( n==(u32)sqlite3Strlen30(z) );
    +   if( z[1]==0 ){
    +     /* Wildcard of the form "?".  Assign the next variable number */
    +     assert( z[0]=='?' );
    +-    pExpr->iColumn = (ynVar)(++pParse->nVar);
    ++    x = (ynVar)(++pParse->nVar);
    +   }else{
    +-    ynVar x = 0;
    +-    u32 n = sqlite3Strlen30(z);
    ++    int doAdd = 0;
    +     if( z[0]=='?' ){
    +       /* Wildcard of the form "?nnn".  Convert "nnn" to an integer and
    +       ** use it as the variable number */
    +       i64 i;
    +-      int bOk = 0==sqlite3Atoi64(&z[1], &i, n-1, SQLITE_UTF8);
    +-      pExpr->iColumn = x = (ynVar)i;
    ++      int bOk;
    ++      if( n==2 ){ /*OPTIMIZATION-IF-TRUE*/
    ++        i = z[1]-'0';  /* The common case of ?N for a single digit N */
    ++        bOk = 1;
    ++      }else{
    ++        bOk = 0==sqlite3Atoi64(&z[1], &i, n-1, SQLITE_UTF8);
    ++      }
    +       testcase( i==0 );
    +       testcase( i==1 );
    +       testcase( i==db->aLimit[SQLITE_LIMIT_VARIABLE_NUMBER]-1 );
    +@@ -85676,41 +93695,32 @@ SQLITE_PRIVATE void sqlite3ExprAssignVarNumber(Parse *pParse, Expr *pExpr){
    +       if( bOk==0 || i<1 || i>db->aLimit[SQLITE_LIMIT_VARIABLE_NUMBER] ){
    +         sqlite3ErrorMsg(pParse, "variable number must be between ?1 and ?%d",
    +             db->aLimit[SQLITE_LIMIT_VARIABLE_NUMBER]);
    +-        x = 0;
    ++        return;
    +       }
    +-      if( i>pParse->nVar ){
    +-        pParse->nVar = (int)i;
    ++      x = (ynVar)i;
    ++      if( x>pParse->nVar ){
    ++        pParse->nVar = (int)x;
    ++        doAdd = 1;
    ++      }else if( sqlite3VListNumToName(pParse->pVList, x)==0 ){
    ++        doAdd = 1;
    +       }
    +     }else{
    +       /* Wildcards like ":aaa", "$aaa" or "@aaa".  Reuse the same variable
    +       ** number as the prior appearance of the same name, or if the name
    +       ** has never appeared before, reuse the same variable number
    +       */
    +-      ynVar i;
    +-      for(i=0; i<pParse->nzVar; i++){
    +-        if( pParse->azVar[i] && strcmp(pParse->azVar[i],z)==0 ){
    +-          pExpr->iColumn = x = (ynVar)i+1;
    +-          break;
    +-        }
    ++      x = (ynVar)sqlite3VListNameToNum(pParse->pVList, z, n);
    ++      if( x==0 ){
    ++        x = (ynVar)(++pParse->nVar);
    ++        doAdd = 1;
    +       }
    +-      if( x==0 ) x = pExpr->iColumn = (ynVar)(++pParse->nVar);
    +     }
    +-    if( x>0 ){
    +-      if( x>pParse->nzVar ){
    +-        char **a;
    +-        a = sqlite3DbRealloc(db, pParse->azVar, x*sizeof(a[0]));
    +-        if( a==0 ) return;  /* Error reported through db->mallocFailed */
    +-        pParse->azVar = a;
    +-        memset(&a[pParse->nzVar], 0, (x-pParse->nzVar)*sizeof(a[0]));
    +-        pParse->nzVar = x;
    +-      }
    +-      if( z[0]!='?' || pParse->azVar[x-1]==0 ){
    +-        sqlite3DbFree(db, pParse->azVar[x-1]);
    +-        pParse->azVar[x-1] = sqlite3DbStrNDup(db, z, n);
    +-      }
    ++    if( doAdd ){
    ++      pParse->pVList = sqlite3VListAdd(db, pParse->pVList, z, n, x);
    +     }
    +-  } 
    +-  if( !pParse->nErr && pParse->nVar>db->aLimit[SQLITE_LIMIT_VARIABLE_NUMBER] ){
    ++  }
    ++  pExpr->iColumn = x;
    ++  if( x>db->aLimit[SQLITE_LIMIT_VARIABLE_NUMBER] ){
    +     sqlite3ErrorMsg(pParse, "too many SQL variables");
    +   }
    + }
    +@@ -85718,26 +93728,37 @@ SQLITE_PRIVATE void sqlite3ExprAssignVarNumber(Parse *pParse, Expr *pExpr){
    + /*
    + ** Recursively delete an expression tree.
    + */
    +-SQLITE_PRIVATE void sqlite3ExprDelete(sqlite3 *db, Expr *p){
    +-  if( p==0 ) return;
    ++static SQLITE_NOINLINE void sqlite3ExprDeleteNN(sqlite3 *db, Expr *p){
    ++  assert( p!=0 );
    +   /* Sanity check: Assert that the IntValue is non-negative if it exists */
    +   assert( !ExprHasProperty(p, EP_IntValue) || p->u.iValue>=0 );
    +-  if( !ExprHasProperty(p, EP_TokenOnly) ){
    ++#ifdef SQLITE_DEBUG
    ++  if( ExprHasProperty(p, EP_Leaf) && !ExprHasProperty(p, EP_TokenOnly) ){
    ++    assert( p->pLeft==0 );
    ++    assert( p->pRight==0 );
    ++    assert( p->x.pSelect==0 );
    ++  }
    ++#endif
    ++  if( !ExprHasProperty(p, (EP_TokenOnly|EP_Leaf)) ){
    +     /* The Expr.x union is never used at the same time as Expr.pRight */
    +     assert( p->x.pList==0 || p->pRight==0 );
    +-    sqlite3ExprDelete(db, p->pLeft);
    +-    sqlite3ExprDelete(db, p->pRight);
    +-    if( ExprHasProperty(p, EP_MemToken) ) sqlite3DbFree(db, p->u.zToken);
    +-    if( ExprHasProperty(p, EP_xIsSelect) ){
    ++    if( p->pLeft && p->op!=TK_SELECT_COLUMN ) sqlite3ExprDeleteNN(db, p->pLeft);
    ++    if( p->pRight ){
    ++      sqlite3ExprDeleteNN(db, p->pRight);
    ++    }else if( ExprHasProperty(p, EP_xIsSelect) ){
    +       sqlite3SelectDelete(db, p->x.pSelect);
    +     }else{
    +       sqlite3ExprListDelete(db, p->x.pList);
    +     }
    +   }
    ++  if( ExprHasProperty(p, EP_MemToken) ) sqlite3DbFree(db, p->u.zToken);
    +   if( !ExprHasProperty(p, EP_Static) ){
    +-    sqlite3DbFree(db, p);
    ++    sqlite3DbFreeNN(db, p);
    +   }
    + }
    ++SQLITE_PRIVATE void sqlite3ExprDelete(sqlite3 *db, Expr *p){
    ++  if( p ) sqlite3ExprDeleteNN(db, p);
    ++}
    + 
    + /*
    + ** Return the number of bytes allocated for the expression structure 
    +@@ -85789,7 +93810,7 @@ static int dupedExprStructSize(Expr *p, int flags){
    +   assert( flags==EXPRDUP_REDUCE || flags==0 ); /* Only one flag value allowed */
    +   assert( EXPR_FULLSIZE<=0xfff );
    +   assert( (0xfff & (EP_Reduced|EP_TokenOnly))==0 );
    +-  if( 0==(flags&EXPRDUP_REDUCE) ){
    ++  if( 0==flags || p->op==TK_SELECT_COLUMN ){
    +     nSize = EXPR_FULLSIZE;
    +   }else{
    +     assert( !ExprHasProperty(p, EP_TokenOnly|EP_Reduced) );
    +@@ -85851,84 +93872,94 @@ static int dupedExprSize(Expr *p, int flags){
    + ** if any. Before returning, *pzBuffer is set to the first byte past the
    + ** portion of the buffer copied into by this function.
    + */
    +-static Expr *exprDup(sqlite3 *db, Expr *p, int flags, u8 **pzBuffer){
    +-  Expr *pNew = 0;                      /* Value to return */
    +-  if( p ){
    +-    const int isReduced = (flags&EXPRDUP_REDUCE);
    +-    u8 *zAlloc;
    +-    u32 staticFlag = 0;
    ++static Expr *exprDup(sqlite3 *db, Expr *p, int dupFlags, u8 **pzBuffer){
    ++  Expr *pNew;           /* Value to return */
    ++  u8 *zAlloc;           /* Memory space from which to build Expr object */
    ++  u32 staticFlag;       /* EP_Static if space not obtained from malloc */
    + 
    +-    assert( pzBuffer==0 || isReduced );
    ++  assert( db!=0 );
    ++  assert( p );
    ++  assert( dupFlags==0 || dupFlags==EXPRDUP_REDUCE );
    ++  assert( pzBuffer==0 || dupFlags==EXPRDUP_REDUCE );
    + 
    +-    /* Figure out where to write the new Expr structure. */
    +-    if( pzBuffer ){
    +-      zAlloc = *pzBuffer;
    +-      staticFlag = EP_Static;
    ++  /* Figure out where to write the new Expr structure. */
    ++  if( pzBuffer ){
    ++    zAlloc = *pzBuffer;
    ++    staticFlag = EP_Static;
    ++  }else{
    ++    zAlloc = sqlite3DbMallocRawNN(db, dupedExprSize(p, dupFlags));
    ++    staticFlag = 0;
    ++  }
    ++  pNew = (Expr *)zAlloc;
    ++
    ++  if( pNew ){
    ++    /* Set nNewSize to the size allocated for the structure pointed to
    ++    ** by pNew. This is either EXPR_FULLSIZE, EXPR_REDUCEDSIZE or
    ++    ** EXPR_TOKENONLYSIZE. nToken is set to the number of bytes consumed
    ++    ** by the copy of the p->u.zToken string (if any).
    ++    */
    ++    const unsigned nStructSize = dupedExprStructSize(p, dupFlags);
    ++    const int nNewSize = nStructSize & 0xfff;
    ++    int nToken;
    ++    if( !ExprHasProperty(p, EP_IntValue) && p->u.zToken ){
    ++      nToken = sqlite3Strlen30(p->u.zToken) + 1;
    +     }else{
    +-      zAlloc = sqlite3DbMallocRaw(db, dupedExprSize(p, flags));
    ++      nToken = 0;
    +     }
    +-    pNew = (Expr *)zAlloc;
    +-
    +-    if( pNew ){
    +-      /* Set nNewSize to the size allocated for the structure pointed to
    +-      ** by pNew. This is either EXPR_FULLSIZE, EXPR_REDUCEDSIZE or
    +-      ** EXPR_TOKENONLYSIZE. nToken is set to the number of bytes consumed
    +-      ** by the copy of the p->u.zToken string (if any).
    +-      */
    +-      const unsigned nStructSize = dupedExprStructSize(p, flags);
    +-      const int nNewSize = nStructSize & 0xfff;
    +-      int nToken;
    +-      if( !ExprHasProperty(p, EP_IntValue) && p->u.zToken ){
    +-        nToken = sqlite3Strlen30(p->u.zToken) + 1;
    +-      }else{
    +-        nToken = 0;
    +-      }
    +-      if( isReduced ){
    +-        assert( ExprHasProperty(p, EP_Reduced)==0 );
    +-        memcpy(zAlloc, p, nNewSize);
    +-      }else{
    +-        int nSize = exprStructSize(p);
    +-        memcpy(zAlloc, p, nSize);
    ++    if( dupFlags ){
    ++      assert( ExprHasProperty(p, EP_Reduced)==0 );
    ++      memcpy(zAlloc, p, nNewSize);
    ++    }else{
    ++      u32 nSize = (u32)exprStructSize(p);
    ++      memcpy(zAlloc, p, nSize);
    ++      if( nSize<EXPR_FULLSIZE ){ 
    +         memset(&zAlloc[nSize], 0, EXPR_FULLSIZE-nSize);
    +       }
    ++    }
    + 
    +-      /* Set the EP_Reduced, EP_TokenOnly, and EP_Static flags appropriately. */
    +-      pNew->flags &= ~(EP_Reduced|EP_TokenOnly|EP_Static|EP_MemToken);
    +-      pNew->flags |= nStructSize & (EP_Reduced|EP_TokenOnly);
    +-      pNew->flags |= staticFlag;
    ++    /* Set the EP_Reduced, EP_TokenOnly, and EP_Static flags appropriately. */
    ++    pNew->flags &= ~(EP_Reduced|EP_TokenOnly|EP_Static|EP_MemToken);
    ++    pNew->flags |= nStructSize & (EP_Reduced|EP_TokenOnly);
    ++    pNew->flags |= staticFlag;
    + 
    +-      /* Copy the p->u.zToken string, if any. */
    +-      if( nToken ){
    +-        char *zToken = pNew->u.zToken = (char*)&zAlloc[nNewSize];
    +-        memcpy(zToken, p->u.zToken, nToken);
    +-      }
    ++    /* Copy the p->u.zToken string, if any. */
    ++    if( nToken ){
    ++      char *zToken = pNew->u.zToken = (char*)&zAlloc[nNewSize];
    ++      memcpy(zToken, p->u.zToken, nToken);
    ++    }
    + 
    +-      if( 0==((p->flags|pNew->flags) & EP_TokenOnly) ){
    +-        /* Fill in the pNew->x.pSelect or pNew->x.pList member. */
    +-        if( ExprHasProperty(p, EP_xIsSelect) ){
    +-          pNew->x.pSelect = sqlite3SelectDup(db, p->x.pSelect, isReduced);
    +-        }else{
    +-          pNew->x.pList = sqlite3ExprListDup(db, p->x.pList, isReduced);
    +-        }
    ++    if( 0==((p->flags|pNew->flags) & (EP_TokenOnly|EP_Leaf)) ){
    ++      /* Fill in the pNew->x.pSelect or pNew->x.pList member. */
    ++      if( ExprHasProperty(p, EP_xIsSelect) ){
    ++        pNew->x.pSelect = sqlite3SelectDup(db, p->x.pSelect, dupFlags);
    ++      }else{
    ++        pNew->x.pList = sqlite3ExprListDup(db, p->x.pList, dupFlags);
    +       }
    ++    }
    + 
    +-      /* Fill in pNew->pLeft and pNew->pRight. */
    +-      if( ExprHasProperty(pNew, EP_Reduced|EP_TokenOnly) ){
    +-        zAlloc += dupedExprNodeSize(p, flags);
    +-        if( ExprHasProperty(pNew, EP_Reduced) ){
    +-          pNew->pLeft = exprDup(db, p->pLeft, EXPRDUP_REDUCE, &zAlloc);
    +-          pNew->pRight = exprDup(db, p->pRight, EXPRDUP_REDUCE, &zAlloc);
    +-        }
    +-        if( pzBuffer ){
    +-          *pzBuffer = zAlloc;
    +-        }
    +-      }else{
    +-        if( !ExprHasProperty(p, EP_TokenOnly) ){
    ++    /* Fill in pNew->pLeft and pNew->pRight. */
    ++    if( ExprHasProperty(pNew, EP_Reduced|EP_TokenOnly) ){
    ++      zAlloc += dupedExprNodeSize(p, dupFlags);
    ++      if( !ExprHasProperty(pNew, EP_TokenOnly|EP_Leaf) ){
    ++        pNew->pLeft = p->pLeft ?
    ++                      exprDup(db, p->pLeft, EXPRDUP_REDUCE, &zAlloc) : 0;
    ++        pNew->pRight = p->pRight ?
    ++                       exprDup(db, p->pRight, EXPRDUP_REDUCE, &zAlloc) : 0;
    ++      }
    ++      if( pzBuffer ){
    ++        *pzBuffer = zAlloc;
    ++      }
    ++    }else{
    ++      if( !ExprHasProperty(p, EP_TokenOnly|EP_Leaf) ){
    ++        if( pNew->op==TK_SELECT_COLUMN ){
    ++          pNew->pLeft = p->pLeft;
    ++          assert( p->iColumn==0 || p->pRight==0 );
    ++          assert( p->pRight==0  || p->pRight==p->pLeft );
    ++        }else{
    +           pNew->pLeft = sqlite3ExprDup(db, p->pLeft, 0);
    +-          pNew->pRight = sqlite3ExprDup(db, p->pRight, 0);
    +         }
    ++        pNew->pRight = sqlite3ExprDup(db, p->pRight, 0);
    +       }
    +-
    +     }
    +   }
    +   return pNew;
    +@@ -85979,26 +94010,41 @@ static With *withDup(sqlite3 *db, With *p){
    + ** part of the in-memory representation of the database schema.
    + */
    + SQLITE_PRIVATE Expr *sqlite3ExprDup(sqlite3 *db, Expr *p, int flags){
    +-  return exprDup(db, p, flags, 0);
    ++  assert( flags==0 || flags==EXPRDUP_REDUCE );
    ++  return p ? exprDup(db, p, flags, 0) : 0;
    + }
    + SQLITE_PRIVATE ExprList *sqlite3ExprListDup(sqlite3 *db, ExprList *p, int flags){
    +   ExprList *pNew;
    +   struct ExprList_item *pItem, *pOldItem;
    +   int i;
    ++  Expr *pPriorSelectCol = 0;
    ++  assert( db!=0 );
    +   if( p==0 ) return 0;
    +-  pNew = sqlite3DbMallocRaw(db, sizeof(*pNew) );
    ++  pNew = sqlite3DbMallocRawNN(db, sqlite3DbMallocSize(db, p));
    +   if( pNew==0 ) return 0;
    +-  pNew->nExpr = i = p->nExpr;
    +-  if( (flags & EXPRDUP_REDUCE)==0 ) for(i=1; i<p->nExpr; i+=i){}
    +-  pNew->a = pItem = sqlite3DbMallocRaw(db,  i*sizeof(p->a[0]) );
    +-  if( pItem==0 ){
    +-    sqlite3DbFree(db, pNew);
    +-    return 0;
    +-  } 
    ++  pNew->nExpr = p->nExpr;
    ++  pItem = pNew->a;
    +   pOldItem = p->a;
    +   for(i=0; i<p->nExpr; i++, pItem++, pOldItem++){
    +     Expr *pOldExpr = pOldItem->pExpr;
    ++    Expr *pNewExpr;
    +     pItem->pExpr = sqlite3ExprDup(db, pOldExpr, flags);
    ++    if( pOldExpr 
    ++     && pOldExpr->op==TK_SELECT_COLUMN
    ++     && (pNewExpr = pItem->pExpr)!=0 
    ++    ){
    ++      assert( pNewExpr->iColumn==0 || i>0 );
    ++      if( pNewExpr->iColumn==0 ){
    ++        assert( pOldExpr->pLeft==pOldExpr->pRight );
    ++        pPriorSelectCol = pNewExpr->pLeft = pNewExpr->pRight;
    ++      }else{
    ++        assert( i>0 );
    ++        assert( pItem[-1].pExpr!=0 );
    ++        assert( pNewExpr->iColumn==pItem[-1].pExpr->iColumn+1 );
    ++        assert( pPriorSelectCol==pItem[-1].pExpr->pLeft );
    ++        pNewExpr->pLeft = pPriorSelectCol;
    ++      }
    ++    }
    +     pItem->zName = sqlite3DbStrDup(db, pOldItem->zName);
    +     pItem->zSpan = sqlite3DbStrDup(db, pOldItem->zSpan);
    +     pItem->sortOrder = pOldItem->sortOrder;
    +@@ -86021,9 +94067,10 @@ SQLITE_PRIVATE SrcList *sqlite3SrcListDup(sqlite3 *db, SrcList *p, int flags){
    +   SrcList *pNew;
    +   int i;
    +   int nByte;
    ++  assert( db!=0 );
    +   if( p==0 ) return 0;
    +   nByte = sizeof(*p) + (p->nSrc>0 ? sizeof(p->a[0]) * (p->nSrc-1) : 0);
    +-  pNew = sqlite3DbMallocRaw(db, nByte );
    ++  pNew = sqlite3DbMallocRawNN(db, nByte );
    +   if( pNew==0 ) return 0;
    +   pNew->nSrc = pNew->nAlloc = p->nSrc;
    +   for(i=0; i<p->nSrc; i++){
    +@@ -86048,7 +94095,7 @@ SQLITE_PRIVATE SrcList *sqlite3SrcListDup(sqlite3 *db, SrcList *p, int flags){
    +     }
    +     pTab = pNewItem->pTab = pOldItem->pTab;
    +     if( pTab ){
    +-      pTab->nRef++;
    ++      pTab->nTabRef++;
    +     }
    +     pNewItem->pSelect = sqlite3SelectDup(db, pOldItem->pSelect, flags);
    +     pNewItem->pOn = sqlite3ExprDup(db, pOldItem->pOn, flags);
    +@@ -86060,13 +94107,14 @@ SQLITE_PRIVATE SrcList *sqlite3SrcListDup(sqlite3 *db, SrcList *p, int flags){
    + SQLITE_PRIVATE IdList *sqlite3IdListDup(sqlite3 *db, IdList *p){
    +   IdList *pNew;
    +   int i;
    ++  assert( db!=0 );
    +   if( p==0 ) return 0;
    +-  pNew = sqlite3DbMallocRaw(db, sizeof(*pNew) );
    ++  pNew = sqlite3DbMallocRawNN(db, sizeof(*pNew) );
    +   if( pNew==0 ) return 0;
    +   pNew->nId = p->nId;
    +-  pNew->a = sqlite3DbMallocRaw(db, p->nId*sizeof(p->a[0]) );
    ++  pNew->a = sqlite3DbMallocRawNN(db, p->nId*sizeof(p->a[0]) );
    +   if( pNew->a==0 ){
    +-    sqlite3DbFree(db, pNew);
    ++    sqlite3DbFreeNN(db, pNew);
    +     return 0;
    +   }
    +   /* Note that because the size of the allocation for p->a[] is not
    +@@ -86080,32 +94128,40 @@ SQLITE_PRIVATE IdList *sqlite3IdListDup(sqlite3 *db, IdList *p){
    +   }
    +   return pNew;
    + }
    +-SQLITE_PRIVATE Select *sqlite3SelectDup(sqlite3 *db, Select *p, int flags){
    +-  Select *pNew, *pPrior;
    +-  if( p==0 ) return 0;
    +-  pNew = sqlite3DbMallocRaw(db, sizeof(*p) );
    +-  if( pNew==0 ) return 0;
    +-  pNew->pEList = sqlite3ExprListDup(db, p->pEList, flags);
    +-  pNew->pSrc = sqlite3SrcListDup(db, p->pSrc, flags);
    +-  pNew->pWhere = sqlite3ExprDup(db, p->pWhere, flags);
    +-  pNew->pGroupBy = sqlite3ExprListDup(db, p->pGroupBy, flags);
    +-  pNew->pHaving = sqlite3ExprDup(db, p->pHaving, flags);
    +-  pNew->pOrderBy = sqlite3ExprListDup(db, p->pOrderBy, flags);
    +-  pNew->op = p->op;
    +-  pNew->pPrior = pPrior = sqlite3SelectDup(db, p->pPrior, flags);
    +-  if( pPrior ) pPrior->pNext = pNew;
    +-  pNew->pNext = 0;
    +-  pNew->pLimit = sqlite3ExprDup(db, p->pLimit, flags);
    +-  pNew->pOffset = sqlite3ExprDup(db, p->pOffset, flags);
    +-  pNew->iLimit = 0;
    +-  pNew->iOffset = 0;
    +-  pNew->selFlags = p->selFlags & ~SF_UsesEphemeral;
    +-  pNew->addrOpenEphm[0] = -1;
    +-  pNew->addrOpenEphm[1] = -1;
    +-  pNew->nSelectRow = p->nSelectRow;
    +-  pNew->pWith = withDup(db, p->pWith);
    +-  sqlite3SelectSetName(pNew, p->zSelName);
    +-  return pNew;
    ++SQLITE_PRIVATE Select *sqlite3SelectDup(sqlite3 *db, Select *pDup, int flags){
    ++  Select *pRet = 0;
    ++  Select *pNext = 0;
    ++  Select **pp = &pRet;
    ++  Select *p;
    ++
    ++  assert( db!=0 );
    ++  for(p=pDup; p; p=p->pPrior){
    ++    Select *pNew = sqlite3DbMallocRawNN(db, sizeof(*p) );
    ++    if( pNew==0 ) break;
    ++    pNew->pEList = sqlite3ExprListDup(db, p->pEList, flags);
    ++    pNew->pSrc = sqlite3SrcListDup(db, p->pSrc, flags);
    ++    pNew->pWhere = sqlite3ExprDup(db, p->pWhere, flags);
    ++    pNew->pGroupBy = sqlite3ExprListDup(db, p->pGroupBy, flags);
    ++    pNew->pHaving = sqlite3ExprDup(db, p->pHaving, flags);
    ++    pNew->pOrderBy = sqlite3ExprListDup(db, p->pOrderBy, flags);
    ++    pNew->op = p->op;
    ++    pNew->pNext = pNext;
    ++    pNew->pPrior = 0;
    ++    pNew->pLimit = sqlite3ExprDup(db, p->pLimit, flags);
    ++    pNew->iLimit = 0;
    ++    pNew->iOffset = 0;
    ++    pNew->selFlags = p->selFlags & ~SF_UsesEphemeral;
    ++    pNew->addrOpenEphm[0] = -1;
    ++    pNew->addrOpenEphm[1] = -1;
    ++    pNew->nSelectRow = p->nSelectRow;
    ++    pNew->pWith = withDup(db, p->pWith);
    ++    sqlite3SelectSetName(pNew, p->zSelName);
    ++    *pp = pNew;
    ++    pp = &pNew->pPrior;
    ++    pNext = pNew;
    ++  }
    ++
    ++  return pRet;
    + }
    + #else
    + SQLITE_PRIVATE Select *sqlite3SelectDup(sqlite3 *db, Select *p, int flags){
    +@@ -86119,6 +94175,13 @@ SQLITE_PRIVATE Select *sqlite3SelectDup(sqlite3 *db, Select *p, int flags){
    + ** Add a new element to the end of an expression list.  If pList is
    + ** initially NULL, then create a new expression list.
    + **
    ++** The pList argument must be either NULL or a pointer to an ExprList
    ++** obtained from a prior call to sqlite3ExprListAppend().  This routine
    ++** may not be used with an ExprList obtained from sqlite3ExprListDup().
    ++** Reason:  This routine assumes that the number of slots in pList->a[]
    ++** is a power of two.  That is true for sqlite3ExprListAppend() returns
    ++** but is not necessarily true from the return value of sqlite3ExprListDup().
    ++**
    + ** If a memory allocation error occurs, the entire list is freed and
    + ** NULL is returned.  If non-NULL is returned, then it is guaranteed
    + ** that the new entry was successfully appended.
    +@@ -86128,29 +94191,29 @@ SQLITE_PRIVATE ExprList *sqlite3ExprListAppend(
    +   ExprList *pList,        /* List to which to append. Might be NULL */
    +   Expr *pExpr             /* Expression to be appended. Might be NULL */
    + ){
    ++  struct ExprList_item *pItem;
    +   sqlite3 *db = pParse->db;
    ++  assert( db!=0 );
    +   if( pList==0 ){
    +-    pList = sqlite3DbMallocZero(db, sizeof(ExprList) );
    ++    pList = sqlite3DbMallocRawNN(db, sizeof(ExprList) );
    +     if( pList==0 ){
    +       goto no_mem;
    +     }
    +-    pList->a = sqlite3DbMallocRaw(db, sizeof(pList->a[0]));
    +-    if( pList->a==0 ) goto no_mem;
    ++    pList->nExpr = 0;
    +   }else if( (pList->nExpr & (pList->nExpr-1))==0 ){
    +-    struct ExprList_item *a;
    +-    assert( pList->nExpr>0 );
    +-    a = sqlite3DbRealloc(db, pList->a, pList->nExpr*2*sizeof(pList->a[0]));
    +-    if( a==0 ){
    ++    ExprList *pNew;
    ++    pNew = sqlite3DbRealloc(db, pList, 
    ++             sizeof(*pList)+(2*pList->nExpr - 1)*sizeof(pList->a[0]));
    ++    if( pNew==0 ){
    +       goto no_mem;
    +     }
    +-    pList->a = a;
    +-  }
    +-  assert( pList->a!=0 );
    +-  if( 1 ){
    +-    struct ExprList_item *pItem = &pList->a[pList->nExpr++];
    +-    memset(pItem, 0, sizeof(*pItem));
    +-    pItem->pExpr = pExpr;
    ++    pList = pNew;
    +   }
    ++  pItem = &pList->a[pList->nExpr++];
    ++  assert( offsetof(struct ExprList_item,zName)==sizeof(pItem->pExpr) );
    ++  assert( offsetof(struct ExprList_item,pExpr)==0 );
    ++  memset(&pItem->zName,0,sizeof(*pItem)-offsetof(struct ExprList_item,zName));
    ++  pItem->pExpr = pExpr;
    +   return pList;
    + 
    + no_mem:     
    +@@ -86160,6 +94223,74 @@ no_mem:
    +   return 0;
    + }
    + 
    ++/*
    ++** pColumns and pExpr form a vector assignment which is part of the SET
    ++** clause of an UPDATE statement.  Like this:
    ++**
    ++**        (a,b,c) = (expr1,expr2,expr3)
    ++** Or:    (a,b,c) = (SELECT x,y,z FROM ....)
    ++**
    ++** For each term of the vector assignment, append new entries to the
    ++** expression list pList.  In the case of a subquery on the RHS, append
    ++** TK_SELECT_COLUMN expressions.
    ++*/
    ++SQLITE_PRIVATE ExprList *sqlite3ExprListAppendVector(
    ++  Parse *pParse,         /* Parsing context */
    ++  ExprList *pList,       /* List to which to append. Might be NULL */
    ++  IdList *pColumns,      /* List of names of LHS of the assignment */
    ++  Expr *pExpr            /* Vector expression to be appended. Might be NULL */
    ++){
    ++  sqlite3 *db = pParse->db;
    ++  int n;
    ++  int i;
    ++  int iFirst = pList ? pList->nExpr : 0;
    ++  /* pColumns can only be NULL due to an OOM but an OOM will cause an
    ++  ** exit prior to this routine being invoked */
    ++  if( NEVER(pColumns==0) ) goto vector_append_error;
    ++  if( pExpr==0 ) goto vector_append_error;
    ++
    ++  /* If the RHS is a vector, then we can immediately check to see that 
    ++  ** the size of the RHS and LHS match.  But if the RHS is a SELECT, 
    ++  ** wildcards ("*") in the result set of the SELECT must be expanded before
    ++  ** we can do the size check, so defer the size check until code generation.
    ++  */
    ++  if( pExpr->op!=TK_SELECT && pColumns->nId!=(n=sqlite3ExprVectorSize(pExpr)) ){
    ++    sqlite3ErrorMsg(pParse, "%d columns assigned %d values",
    ++                    pColumns->nId, n);
    ++    goto vector_append_error;
    ++  }
    ++
    ++  for(i=0; i<pColumns->nId; i++){
    ++    Expr *pSubExpr = sqlite3ExprForVectorField(pParse, pExpr, i);
    ++    pList = sqlite3ExprListAppend(pParse, pList, pSubExpr);
    ++    if( pList ){
    ++      assert( pList->nExpr==iFirst+i+1 );
    ++      pList->a[pList->nExpr-1].zName = pColumns->a[i].zName;
    ++      pColumns->a[i].zName = 0;
    ++    }
    ++  }
    ++
    ++  if( !db->mallocFailed && pExpr->op==TK_SELECT && ALWAYS(pList!=0) ){
    ++    Expr *pFirst = pList->a[iFirst].pExpr;
    ++    assert( pFirst!=0 );
    ++    assert( pFirst->op==TK_SELECT_COLUMN );
    ++     
    ++    /* Store the SELECT statement in pRight so it will be deleted when
    ++    ** sqlite3ExprListDelete() is called */
    ++    pFirst->pRight = pExpr;
    ++    pExpr = 0;
    ++
    ++    /* Remember the size of the LHS in iTable so that we can check that
    ++    ** the RHS and LHS sizes match during code generation. */
    ++    pFirst->iTable = pColumns->nId;
    ++  }
    ++
    ++vector_append_error:
    ++  sqlite3ExprDelete(db, pExpr);
    ++  sqlite3IdListDelete(db, pColumns);
    ++  return pList;
    ++}
    ++
    + /*
    + ** Set the sort order for the last element on the given ExprList.
    + */
    +@@ -86195,7 +94326,7 @@ SQLITE_PRIVATE void sqlite3ExprListSetName(
    +     pItem = &pList->a[pList->nExpr-1];
    +     assert( pItem->zName==0 );
    +     pItem->zName = sqlite3DbStrNDup(pParse->db, pName->z, pName->n);
    +-    if( dequote && pItem->zName ) sqlite3Dequote(pItem->zName);
    ++    if( dequote ) sqlite3Dequote(pItem->zName);
    +   }
    + }
    + 
    +@@ -86210,17 +94341,16 @@ SQLITE_PRIVATE void sqlite3ExprListSetName(
    + SQLITE_PRIVATE void sqlite3ExprListSetSpan(
    +   Parse *pParse,          /* Parsing context */
    +   ExprList *pList,        /* List to which to add the span. */
    +-  ExprSpan *pSpan         /* The span to be added */
    ++  const char *zStart,     /* Start of the span */
    ++  const char *zEnd        /* End of the span */
    + ){
    +   sqlite3 *db = pParse->db;
    +   assert( pList!=0 || db->mallocFailed!=0 );
    +   if( pList ){
    +     struct ExprList_item *pItem = &pList->a[pList->nExpr-1];
    +     assert( pList->nExpr>0 );
    +-    assert( db->mallocFailed || pItem->pExpr==pSpan->pExpr );
    +     sqlite3DbFree(db, pItem->zSpan);
    +-    pItem->zSpan = sqlite3DbStrNDup(db, (char*)pSpan->zStart,
    +-                                    (int)(pSpan->zEnd - pSpan->zStart));
    ++    pItem->zSpan = sqlite3DbSpanDup(db, zStart, zEnd);
    +   }
    + }
    + 
    +@@ -86244,18 +94374,20 @@ SQLITE_PRIVATE void sqlite3ExprListCheckLength(
    + /*
    + ** Delete an entire expression list.
    + */
    +-SQLITE_PRIVATE void sqlite3ExprListDelete(sqlite3 *db, ExprList *pList){
    +-  int i;
    +-  struct ExprList_item *pItem;
    +-  if( pList==0 ) return;
    +-  assert( pList->a!=0 || pList->nExpr==0 );
    +-  for(pItem=pList->a, i=0; i<pList->nExpr; i++, pItem++){
    ++static SQLITE_NOINLINE void exprListDeleteNN(sqlite3 *db, ExprList *pList){
    ++  int i = pList->nExpr;
    ++  struct ExprList_item *pItem =  pList->a;
    ++  assert( pList->nExpr>0 );
    ++  do{
    +     sqlite3ExprDelete(db, pItem->pExpr);
    +     sqlite3DbFree(db, pItem->zName);
    +     sqlite3DbFree(db, pItem->zSpan);
    +-  }
    +-  sqlite3DbFree(db, pList->a);
    +-  sqlite3DbFree(db, pList);
    ++    pItem++;
    ++  }while( --i>0 );
    ++  sqlite3DbFreeNN(db, pList);
    ++}
    ++SQLITE_PRIVATE void sqlite3ExprListDelete(sqlite3 *db, ExprList *pList){
    ++  if( pList ) exprListDeleteNN(db, pList);
    + }
    + 
    + /*
    +@@ -86265,15 +94397,28 @@ SQLITE_PRIVATE void sqlite3ExprListDelete(sqlite3 *db, ExprList *pList){
    + SQLITE_PRIVATE u32 sqlite3ExprListFlags(const ExprList *pList){
    +   int i;
    +   u32 m = 0;
    +-  if( pList ){
    +-    for(i=0; i<pList->nExpr; i++){
    +-       Expr *pExpr = pList->a[i].pExpr;
    +-       if( ALWAYS(pExpr) ) m |= pExpr->flags;
    +-    }
    ++  assert( pList!=0 );
    ++  for(i=0; i<pList->nExpr; i++){
    ++     Expr *pExpr = pList->a[i].pExpr;
    ++     assert( pExpr!=0 );
    ++     m |= pExpr->flags;
    +   }
    +   return m;
    + }
    + 
    ++/*
    ++** This is a SELECT-node callback for the expression walker that
    ++** always "fails".  By "fail" in this case, we mean set
    ++** pWalker->eCode to zero and abort.
    ++**
    ++** This callback is used by multiple expression walkers.
    ++*/
    ++SQLITE_PRIVATE int sqlite3SelectWalkFail(Walker *pWalker, Select *NotUsed){
    ++  UNUSED_PARAMETER(NotUsed);
    ++  pWalker->eCode = 0;
    ++  return WRC_Abort;
    ++}
    ++
    + /*
    + ** These routines are Walker callbacks used to check expressions to
    + ** see if they are "constant" for some definition of constant.  The
    +@@ -86330,10 +94475,12 @@ static int exprNodeIsConstant(Walker *pWalker, Expr *pExpr){
    +       testcase( pExpr->op==TK_AGG_COLUMN );
    +       if( pWalker->eCode==3 && pExpr->iTable==pWalker->u.iCur ){
    +         return WRC_Continue;
    +-      }else{
    +-        pWalker->eCode = 0;
    +-        return WRC_Abort;
    +       }
    ++      /* Fall through */
    ++    case TK_IF_NULL_ROW:
    ++      testcase( pExpr->op==TK_IF_NULL_ROW );
    ++      pWalker->eCode = 0;
    ++      return WRC_Abort;
    +     case TK_VARIABLE:
    +       if( pWalker->eCode==5 ){
    +         /* Silently convert bound parameters that appear inside of CREATE
    +@@ -86348,22 +94495,19 @@ static int exprNodeIsConstant(Walker *pWalker, Expr *pExpr){
    +       }
    +       /* Fall through */
    +     default:
    +-      testcase( pExpr->op==TK_SELECT ); /* selectNodeIsConstant will disallow */
    +-      testcase( pExpr->op==TK_EXISTS ); /* selectNodeIsConstant will disallow */
    ++      testcase( pExpr->op==TK_SELECT ); /* sqlite3SelectWalkFail will disallow */
    ++      testcase( pExpr->op==TK_EXISTS ); /* sqlite3SelectWalkFail will disallow */
    +       return WRC_Continue;
    +   }
    + }
    +-static int selectNodeIsConstant(Walker *pWalker, Select *NotUsed){
    +-  UNUSED_PARAMETER(NotUsed);
    +-  pWalker->eCode = 0;
    +-  return WRC_Abort;
    +-}
    + static int exprIsConst(Expr *p, int initFlag, int iCur){
    +   Walker w;
    +-  memset(&w, 0, sizeof(w));
    +   w.eCode = initFlag;
    +   w.xExprCallback = exprNodeIsConstant;
    +-  w.xSelectCallback = selectNodeIsConstant;
    ++  w.xSelectCallback = sqlite3SelectWalkFail;
    ++#ifdef SQLITE_DEBUG
    ++  w.xSelectCallback2 = sqlite3SelectWalkAssert2;
    ++#endif
    +   w.u.iCur = iCur;
    +   sqlite3WalkExpr(&w, p);
    +   return w.eCode;
    +@@ -86401,6 +94545,65 @@ SQLITE_PRIVATE int sqlite3ExprIsTableConstant(Expr *p, int iCur){
    +   return exprIsConst(p, 3, iCur);
    + }
    + 
    ++
    ++/*
    ++** sqlite3WalkExpr() callback used by sqlite3ExprIsConstantOrGroupBy().
    ++*/
    ++static int exprNodeIsConstantOrGroupBy(Walker *pWalker, Expr *pExpr){
    ++  ExprList *pGroupBy = pWalker->u.pGroupBy;
    ++  int i;
    ++
    ++  /* Check if pExpr is identical to any GROUP BY term. If so, consider
    ++  ** it constant.  */
    ++  for(i=0; i<pGroupBy->nExpr; i++){
    ++    Expr *p = pGroupBy->a[i].pExpr;
    ++    if( sqlite3ExprCompare(0, pExpr, p, -1)<2 ){
    ++      CollSeq *pColl = sqlite3ExprNNCollSeq(pWalker->pParse, p);
    ++      if( sqlite3_stricmp("BINARY", pColl->zName)==0 ){
    ++        return WRC_Prune;
    ++      }
    ++    }
    ++  }
    ++
    ++  /* Check if pExpr is a sub-select. If so, consider it variable. */
    ++  if( ExprHasProperty(pExpr, EP_xIsSelect) ){
    ++    pWalker->eCode = 0;
    ++    return WRC_Abort;
    ++  }
    ++
    ++  return exprNodeIsConstant(pWalker, pExpr);
    ++}
    ++
    ++/*
    ++** Walk the expression tree passed as the first argument. Return non-zero
    ++** if the expression consists entirely of constants or copies of terms 
    ++** in pGroupBy that sort with the BINARY collation sequence.
    ++**
    ++** This routine is used to determine if a term of the HAVING clause can
    ++** be promoted into the WHERE clause.  In order for such a promotion to work,
    ++** the value of the HAVING clause term must be the same for all members of
    ++** a "group".  The requirement that the GROUP BY term must be BINARY
    ++** assumes that no other collating sequence will have a finer-grained
    ++** grouping than binary.  In other words (A=B COLLATE binary) implies
    ++** A=B in every other collating sequence.  The requirement that the
    ++** GROUP BY be BINARY is stricter than necessary.  It would also work
    ++** to promote HAVING clauses that use the same alternative collating
    ++** sequence as the GROUP BY term, but that is much harder to check,
    ++** alternative collating sequences are uncommon, and this is only an
    ++** optimization, so we take the easy way out and simply require the
    ++** GROUP BY to use the BINARY collating sequence.
    ++*/
    ++SQLITE_PRIVATE int sqlite3ExprIsConstantOrGroupBy(Parse *pParse, Expr *p, ExprList *pGroupBy){
    ++  Walker w;
    ++  w.eCode = 1;
    ++  w.xExprCallback = exprNodeIsConstantOrGroupBy;
    ++  w.xSelectCallback = 0;
    ++  w.u.pGroupBy = pGroupBy;
    ++  w.pParse = pParse;
    ++  sqlite3WalkExpr(&w, p);
    ++  return w.eCode;
    ++}
    ++
    + /*
    + ** Walk an expression tree.  Return non-zero if the expression is constant
    + ** or a function call with constant arguments.  Return and 0 if there
    +@@ -86415,6 +94618,24 @@ SQLITE_PRIVATE int sqlite3ExprIsConstantOrFunction(Expr *p, u8 isInit){
    +   return exprIsConst(p, 4+isInit, 0);
    + }
    + 
    ++#ifdef SQLITE_ENABLE_CURSOR_HINTS
    ++/*
    ++** Walk an expression tree.  Return 1 if the expression contains a
    ++** subquery of some kind.  Return 0 if there are no subqueries.
    ++*/
    ++SQLITE_PRIVATE int sqlite3ExprContainsSubquery(Expr *p){
    ++  Walker w;
    ++  w.eCode = 1;
    ++  w.xExprCallback = sqlite3ExprWalkNoop;
    ++  w.xSelectCallback = sqlite3SelectWalkFail;
    ++#ifdef SQLITE_DEBUG
    ++  w.xSelectCallback2 = sqlite3SelectWalkAssert2;
    ++#endif
    ++  sqlite3WalkExpr(&w, p);
    ++  return w.eCode==0;
    ++}
    ++#endif
    ++
    + /*
    + ** If the expression p codes a constant integer that is small enough
    + ** to fit in a 32-bit integer, return 1 and put the value of the integer
    +@@ -86423,6 +94644,7 @@ SQLITE_PRIVATE int sqlite3ExprIsConstantOrFunction(Expr *p, u8 isInit){
    + */
    + SQLITE_PRIVATE int sqlite3ExprIsInteger(Expr *p, int *pValue){
    +   int rc = 0;
    ++  if( p==0 ) return 0;  /* Can only happen following on OOM */
    + 
    +   /* If an expression is an integer literal that fits in a signed 32-bit
    +   ** integer, then the EP_IntValue flag will have already been set */
    +@@ -86478,8 +94700,8 @@ SQLITE_PRIVATE int sqlite3ExprCanBeNull(const Expr *p){
    +     case TK_BLOB:
    +       return 0;
    +     case TK_COLUMN:
    +-      assert( p->pTab!=0 );
    +       return ExprHasProperty(p, EP_CanBeNull) ||
    ++             p->pTab==0 ||  /* Reference to column of index on expression */
    +              (p->iColumn>=0 && p->pTab->aCol[p->iColumn].notNull==0);
    +     default:
    +       return 1;
    +@@ -86537,23 +94759,22 @@ SQLITE_PRIVATE int sqlite3IsRowid(const char *z){
    + }
    + 
    + /*
    +-** Return true if we are able to the IN operator optimization on a
    +-** query of the form
    +-**
    +-**       x IN (SELECT ...)
    +-**
    +-** Where the SELECT... clause is as specified by the parameter to this
    +-** routine.
    +-**
    +-** The Select object passed in has already been preprocessed and no
    +-** errors have been found.
    ++** pX is the RHS of an IN operator.  If pX is a SELECT statement 
    ++** that can be simplified to a direct table access, then return
    ++** a pointer to the SELECT statement.  If pX is not a SELECT statement,
    ++** or if the SELECT statement needs to be manifested into a transient
    ++** table, then return NULL.
    + */
    + #ifndef SQLITE_OMIT_SUBQUERY
    +-static int isCandidateForInOpt(Select *p){
    ++static Select *isCandidateForInOpt(Expr *pX){
    ++  Select *p;
    +   SrcList *pSrc;
    +   ExprList *pEList;
    +   Table *pTab;
    +-  if( p==0 ) return 0;                   /* right-hand side of IN is SELECT */
    ++  int i;
    ++  if( !ExprHasProperty(pX, EP_xIsSelect) ) return 0;  /* Not a subquery */
    ++  if( ExprHasProperty(pX, EP_VarSelect)  ) return 0;  /* Correlated subq */
    ++  p = pX->x.pSelect;
    +   if( p->pPrior ) return 0;              /* Not a compound SELECT */
    +   if( p->selFlags & (SF_Distinct|SF_Aggregate) ){
    +     testcase( (p->selFlags & (SF_Distinct|SF_Aggregate))==SF_Distinct );
    +@@ -86562,32 +94783,28 @@ static int isCandidateForInOpt(Select *p){
    +   }
    +   assert( p->pGroupBy==0 );              /* Has no GROUP BY clause */
    +   if( p->pLimit ) return 0;              /* Has no LIMIT clause */
    +-  assert( p->pOffset==0 );               /* No LIMIT means no OFFSET */
    +   if( p->pWhere ) return 0;              /* Has no WHERE clause */
    +   pSrc = p->pSrc;
    +   assert( pSrc!=0 );
    +   if( pSrc->nSrc!=1 ) return 0;          /* Single term in FROM clause */
    +   if( pSrc->a[0].pSelect ) return 0;     /* FROM is not a subquery or view */
    +   pTab = pSrc->a[0].pTab;
    +-  if( NEVER(pTab==0) ) return 0;
    ++  assert( pTab!=0 );
    +   assert( pTab->pSelect==0 );            /* FROM clause is not a view */
    +   if( IsVirtual(pTab) ) return 0;        /* FROM clause not a virtual table */
    +   pEList = p->pEList;
    +-  if( pEList->nExpr!=1 ) return 0;       /* One column in the result set */
    +-  if( pEList->a[0].pExpr->op!=TK_COLUMN ) return 0; /* Result is a column */
    +-  return 1;
    ++  assert( pEList!=0 );
    ++  /* All SELECT results must be columns. */
    ++  for(i=0; i<pEList->nExpr; i++){
    ++    Expr *pRes = pEList->a[i].pExpr;
    ++    if( pRes->op!=TK_COLUMN ) return 0;
    ++    assert( pRes->iTable==pSrc->a[0].iCursor );  /* Not a correlated subquery */
    ++  }
    ++  return p;
    + }
    + #endif /* SQLITE_OMIT_SUBQUERY */
    + 
    +-/*
    +-** Code an OP_Once instruction and allocate space for its flag. Return the 
    +-** address of the new instruction.
    +-*/
    +-SQLITE_PRIVATE int sqlite3CodeOnce(Parse *pParse){
    +-  Vdbe *v = sqlite3GetVdbe(pParse);      /* Virtual machine being coded */
    +-  return sqlite3VdbeAddOp1(v, OP_Once, pParse->nOnce++);
    +-}
    +-
    ++#ifndef SQLITE_OMIT_SUBQUERY
    + /*
    + ** 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
    +@@ -86603,6 +94820,7 @@ static void sqlite3SetHasNullFlag(Vdbe *v, int iCur, int regHasNull){
    +   VdbeComment((v, "first_entry_in(%d)", iCur));
    +   sqlite3VdbeJumpHere(v, addr1);
    + }
    ++#endif
    + 
    + 
    + #ifndef SQLITE_OMIT_SUBQUERY
    +@@ -86647,30 +94865,29 @@ static int sqlite3InRhsIsConstant(Expr *pIn){
    + ** An existing b-tree might be used if the RHS expression pX is a simple
    + ** subquery such as:
    + **
    +-**     SELECT <column> FROM <table>
    ++**     SELECT <column1>, <column2>... FROM <table>
    + **
    + ** 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 ephemeral table instead of an
    + ** existing table.
    + **
    +-** 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.
    ++** The inFlags parameter must contain, at a minimum, one of the bits
    ++** IN_INDEX_MEMBERSHIP or IN_INDEX_LOOP but not both.  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 <column> is guaranteed
    +-** to be unique - either because it is an INTEGER PRIMARY KEY or it
    +-** has a UNIQUE constraint or UNIQUE index.
    ++** An epheremal table will be created unless the selected columns are guaranteed
    ++** to be unique - either because it is an INTEGER PRIMARY KEY or due to
    ++** a UNIQUE constraint or index.
    + **
    + ** 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 <column> is an INTEGER PRIMARY KEY or an index can 
    +-** be found with <column> as its left-most column.
    ++** be used unless <columns> is a single INTEGER PRIMARY KEY column or an 
    ++** index can be found with the specified <columns> as its left-most.
    + **
    + ** 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
    +@@ -86691,9 +94908,26 @@ static int sqlite3InRhsIsConstant(Expr *pIn){
    + ** 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.
    ++**
    ++** If the aiMap parameter is not NULL, it must point to an array containing
    ++** one element for each column returned by the SELECT statement on the RHS
    ++** of the IN(...) operator. The i'th entry of the array is populated with the
    ++** offset of the index column that matches the i'th column returned by the
    ++** SELECT. For example, if the expression and selected index are:
    ++**
    ++**   (?,?,?) IN (SELECT a, b, c FROM t1)
    ++**   CREATE INDEX i1 ON t1(b, c, a);
    ++**
    ++** then aiMap[] is populated with {2, 0, 1}.
    + */
    + #ifndef SQLITE_OMIT_SUBQUERY
    +-SQLITE_PRIVATE int sqlite3FindInIndex(Parse *pParse, Expr *pX, u32 inFlags, int *prRhsHasNull){
    ++SQLITE_PRIVATE int sqlite3FindInIndex(
    ++  Parse *pParse,             /* Parsing context */
    ++  Expr *pX,                  /* The right-hand side (RHS) of the IN operator */
    ++  u32 inFlags,               /* IN_INDEX_LOOP, _MEMBERSHIP, and/or _NOOP_OK */
    ++  int *prRhsHasNull,         /* Register holding NULL status.  See notes */
    ++  int *aiMap                 /* Mapping from Index fields to RHS fields */
    ++){
    +   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 */
    +@@ -86703,38 +94937,46 @@ SQLITE_PRIVATE int sqlite3FindInIndex(Parse *pParse, Expr *pX, u32 inFlags, int
    +   assert( pX->op==TK_IN );
    +   mustBeUnique = (inFlags & IN_INDEX_LOOP)!=0;
    + 
    ++  /* If the RHS of this IN(...) operator is a SELECT, and if it matters 
    ++  ** whether or not the SELECT result contains NULL values, check whether
    ++  ** or not NULL is actually possible (it may not be, for example, due 
    ++  ** to NOT NULL constraints in the schema). If no NULL values are possible,
    ++  ** set prRhsHasNull to 0 before continuing.  */
    ++  if( prRhsHasNull && (pX->flags & EP_xIsSelect) ){
    ++    int i;
    ++    ExprList *pEList = pX->x.pSelect->pEList;
    ++    for(i=0; i<pEList->nExpr; i++){
    ++      if( sqlite3ExprCanBeNull(pEList->a[i].pExpr) ) break;
    ++    }
    ++    if( i==pEList->nExpr ){
    ++      prRhsHasNull = 0;
    ++    }
    ++  }
    ++
    +   /* Check to see if an existing table or index can be used to
    +   ** satisfy the query.  This is preferable to generating a new 
    +-  ** ephemeral table.
    +-  */
    +-  p = (ExprHasProperty(pX, EP_xIsSelect) ? pX->x.pSelect : 0);
    +-  if( pParse->nErr==0 && isCandidateForInOpt(p) ){
    ++  ** ephemeral table.  */
    ++  if( pParse->nErr==0 && (p = isCandidateForInOpt(pX))!=0 ){
    +     sqlite3 *db = pParse->db;              /* Database connection */
    +     Table *pTab;                           /* Table <table>. */
    +-    Expr *pExpr;                           /* Expression <column> */
    +-    i16 iCol;                              /* Index of column <column> */
    +     i16 iDb;                               /* Database idx for pTab */
    ++    ExprList *pEList = p->pEList;
    ++    int nExpr = pEList->nExpr;
    + 
    +-    assert( p );                        /* Because of isCandidateForInOpt(p) */
    +     assert( p->pEList!=0 );             /* Because of isCandidateForInOpt(p) */
    +     assert( p->pEList->a[0].pExpr!=0 ); /* Because of isCandidateForInOpt(p) */
    +     assert( p->pSrc!=0 );               /* Because of isCandidateForInOpt(p) */
    +     pTab = p->pSrc->a[0].pTab;
    +-    pExpr = p->pEList->a[0].pExpr;
    +-    iCol = (i16)pExpr->iColumn;
    +-   
    ++
    +     /* Code an OP_Transaction and OP_TableLock for <table>. */
    +     iDb = sqlite3SchemaToIndex(db, pTab->pSchema);
    +     sqlite3CodeVerifySchema(pParse, iDb);
    +     sqlite3TableLock(pParse, iDb, pTab->tnum, 0, pTab->zName);
    + 
    +-    /* This function is only called from two places. In both cases the vdbe
    +-    ** has already been allocated. So assume sqlite3GetVdbe() is always
    +-    ** successful here.
    +-    */
    +-    assert(v);
    +-    if( iCol<0 ){
    +-      int iAddr = sqlite3CodeOnce(pParse);
    ++    assert(v);  /* sqlite3GetVdbe() has always been previously called */
    ++    if( nExpr==1 && pEList->a[0].pExpr->iColumn<0 ){
    ++      /* The "x IN (SELECT rowid FROM table)" case */
    ++      int iAddr = sqlite3VdbeAddOp0(v, OP_Once);
    +       VdbeCoverage(v);
    + 
    +       sqlite3OpenTable(pParse, iTab, iDb, pTab, OP_OpenRead);
    +@@ -86743,44 +94985,114 @@ SQLITE_PRIVATE int sqlite3FindInIndex(Parse *pParse, Expr *pX, u32 inFlags, int
    +       sqlite3VdbeJumpHere(v, iAddr);
    +     }else{
    +       Index *pIdx;                         /* Iterator variable */
    ++      int affinity_ok = 1;
    ++      int i;
    + 
    +-      /* The collation sequence used by the comparison. If an index is to
    +-      ** be used in place of a temp-table, it must be ordered according
    +-      ** to this collation sequence.  */
    +-      CollSeq *pReq = sqlite3BinaryCompareCollSeq(pParse, pX->pLeft, pExpr);
    +-
    +-      /* Check that the affinity that will be used to perform the 
    +-      ** comparison is the same as the affinity of the column. If
    +-      ** it is not, it is not possible to use any index.
    +-      */
    +-      int affinity_ok = sqlite3IndexAffinityOk(pX, pTab->aCol[iCol].affinity);
    +-
    +-      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 && IsUniqueIndex(pIdx)))
    +-        ){
    +-          int iAddr = sqlite3CodeOnce(pParse); VdbeCoverage(v);
    +-          sqlite3VdbeAddOp3(v, OP_OpenRead, iTab, pIdx->tnum, iDb);
    +-          sqlite3VdbeSetP4KeyInfo(pParse, pIdx);
    +-          VdbeComment((v, "%s", pIdx->zName));
    +-          assert( IN_INDEX_INDEX_DESC == IN_INDEX_INDEX_ASC+1 );
    +-          eType = IN_INDEX_INDEX_ASC + pIdx->aSortOrder[0];
    +-
    +-          if( prRhsHasNull && !pTab->aCol[iCol].notNull ){
    +-            *prRhsHasNull = ++pParse->nMem;
    +-            sqlite3SetHasNullFlag(v, iTab, *prRhsHasNull);
    ++      /* Check that the affinity that will be used to perform each 
    ++      ** comparison is the same as the affinity of each column in table
    ++      ** on the RHS of the IN operator.  If it not, it is not possible to
    ++      ** use any index of the RHS table.  */
    ++      for(i=0; i<nExpr && affinity_ok; i++){
    ++        Expr *pLhs = sqlite3VectorFieldSubexpr(pX->pLeft, i);
    ++        int iCol = pEList->a[i].pExpr->iColumn;
    ++        char idxaff = sqlite3TableColumnAffinity(pTab,iCol); /* RHS table */
    ++        char cmpaff = sqlite3CompareAffinity(pLhs, idxaff);
    ++        testcase( cmpaff==SQLITE_AFF_BLOB );
    ++        testcase( cmpaff==SQLITE_AFF_TEXT );
    ++        switch( cmpaff ){
    ++          case SQLITE_AFF_BLOB:
    ++            break;
    ++          case SQLITE_AFF_TEXT:
    ++            /* sqlite3CompareAffinity() only returns TEXT if one side or the
    ++            ** other has no affinity and the other side is TEXT.  Hence,
    ++            ** the only way for cmpaff to be TEXT is for idxaff to be TEXT
    ++            ** and for the term on the LHS of the IN to have no affinity. */
    ++            assert( idxaff==SQLITE_AFF_TEXT );
    ++            break;
    ++          default:
    ++            affinity_ok = sqlite3IsNumericAffinity(idxaff);
    ++        }
    ++      }
    ++
    ++      if( affinity_ok ){
    ++        /* Search for an existing index that will work for this IN operator */
    ++        for(pIdx=pTab->pIndex; pIdx && eType==0; pIdx=pIdx->pNext){
    ++          Bitmask colUsed;      /* Columns of the index used */
    ++          Bitmask mCol;         /* Mask for the current column */
    ++          if( pIdx->nColumn<nExpr ) continue;
    ++          /* Maximum nColumn is BMS-2, not BMS-1, so that we can compute
    ++          ** BITMASK(nExpr) without overflowing */
    ++          testcase( pIdx->nColumn==BMS-2 );
    ++          testcase( pIdx->nColumn==BMS-1 );
    ++          if( pIdx->nColumn>=BMS-1 ) continue;
    ++          if( mustBeUnique ){
    ++            if( pIdx->nKeyCol>nExpr
    ++             ||(pIdx->nColumn>nExpr && !IsUniqueIndex(pIdx))
    ++            ){
    ++              continue;  /* This index is not unique over the IN RHS columns */
    ++            }
    +           }
    +-          sqlite3VdbeJumpHere(v, iAddr);
    +-        }
    +-      }
    +-    }
    +-  }
    ++  
    ++          colUsed = 0;   /* Columns of index used so far */
    ++          for(i=0; i<nExpr; i++){
    ++            Expr *pLhs = sqlite3VectorFieldSubexpr(pX->pLeft, i);
    ++            Expr *pRhs = pEList->a[i].pExpr;
    ++            CollSeq *pReq = sqlite3BinaryCompareCollSeq(pParse, pLhs, pRhs);
    ++            int j;
    ++  
    ++            assert( pReq!=0 || pRhs->iColumn==XN_ROWID || pParse->nErr );
    ++            for(j=0; j<nExpr; j++){
    ++              if( pIdx->aiColumn[j]!=pRhs->iColumn ) continue;
    ++              assert( pIdx->azColl[j] );
    ++              if( pReq!=0 && sqlite3StrICmp(pReq->zName, pIdx->azColl[j])!=0 ){
    ++                continue;
    ++              }
    ++              break;
    ++            }
    ++            if( j==nExpr ) break;
    ++            mCol = MASKBIT(j);
    ++            if( mCol & colUsed ) break; /* Each column used only once */
    ++            colUsed |= mCol;
    ++            if( aiMap ) aiMap[i] = j;
    ++          }
    ++  
    ++          assert( i==nExpr || colUsed!=(MASKBIT(nExpr)-1) );
    ++          if( colUsed==(MASKBIT(nExpr)-1) ){
    ++            /* If we reach this point, that means the index pIdx is usable */
    ++            int iAddr = sqlite3VdbeAddOp0(v, OP_Once); VdbeCoverage(v);
    ++#ifndef SQLITE_OMIT_EXPLAIN
    ++            sqlite3VdbeAddOp4(v, OP_Explain, 0, 0, 0,
    ++              sqlite3MPrintf(db, "USING INDEX %s FOR IN-OPERATOR",pIdx->zName),
    ++              P4_DYNAMIC);
    ++#endif
    ++            sqlite3VdbeAddOp3(v, OP_OpenRead, iTab, pIdx->tnum, iDb);
    ++            sqlite3VdbeSetP4KeyInfo(pParse, pIdx);
    ++            VdbeComment((v, "%s", pIdx->zName));
    ++            assert( IN_INDEX_INDEX_DESC == IN_INDEX_INDEX_ASC+1 );
    ++            eType = IN_INDEX_INDEX_ASC + pIdx->aSortOrder[0];
    ++  
    ++            if( prRhsHasNull ){
    ++#ifdef SQLITE_ENABLE_COLUMN_USED_MASK
    ++              i64 mask = (1<<nExpr)-1;
    ++              sqlite3VdbeAddOp4Dup8(v, OP_ColumnsUsed, 
    ++                  iTab, 0, 0, (u8*)&mask, P4_INT64);
    ++#endif
    ++              *prRhsHasNull = ++pParse->nMem;
    ++              if( nExpr==1 ){
    ++                sqlite3SetHasNullFlag(v, iTab, *prRhsHasNull);
    ++              }
    ++            }
    ++            sqlite3VdbeJumpHere(v, iAddr);
    ++          }
    ++        } /* End loop over indexes */
    ++      } /* End if( affinity_ok ) */
    ++    } /* End if not an rowid index */
    ++  } /* End attempt to optimize using an index */
    + 
    +   /* 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,
    ++  ** and the RHS is not constant or has two or fewer terms,
    +   ** then it is not worth creating an ephemeral table to evaluate
    +   ** the IN operator so return IN_INDEX_NOOP.
    +   */
    +@@ -86791,7 +95103,6 @@ SQLITE_PRIVATE int sqlite3FindInIndex(Parse *pParse, Expr *pX, u32 inFlags, int
    +   ){
    +     eType = IN_INDEX_NOOP;
    +   }
    +-     
    + 
    +   if( eType==0 ){
    +     /* Could not find an existing table or index to use as the RHS b-tree.
    +@@ -86813,10 +95124,85 @@ SQLITE_PRIVATE int sqlite3FindInIndex(Parse *pParse, Expr *pX, u32 inFlags, int
    +   }else{
    +     pX->iTable = iTab;
    +   }
    ++
    ++  if( aiMap && eType!=IN_INDEX_INDEX_ASC && eType!=IN_INDEX_INDEX_DESC ){
    ++    int i, n;
    ++    n = sqlite3ExprVectorSize(pX->pLeft);
    ++    for(i=0; i<n; i++) aiMap[i] = i;
    ++  }
    +   return eType;
    + }
    + #endif
    + 
    ++#ifndef SQLITE_OMIT_SUBQUERY
    ++/*
    ++** Argument pExpr is an (?, ?...) IN(...) expression. This 
    ++** function allocates and returns a nul-terminated string containing 
    ++** the affinities to be used for each column of the comparison.
    ++**
    ++** It is the responsibility of the caller to ensure that the returned
    ++** string is eventually freed using sqlite3DbFree().
    ++*/
    ++static char *exprINAffinity(Parse *pParse, Expr *pExpr){
    ++  Expr *pLeft = pExpr->pLeft;
    ++  int nVal = sqlite3ExprVectorSize(pLeft);
    ++  Select *pSelect = (pExpr->flags & EP_xIsSelect) ? pExpr->x.pSelect : 0;
    ++  char *zRet;
    ++
    ++  assert( pExpr->op==TK_IN );
    ++  zRet = sqlite3DbMallocRaw(pParse->db, nVal+1);
    ++  if( zRet ){
    ++    int i;
    ++    for(i=0; i<nVal; i++){
    ++      Expr *pA = sqlite3VectorFieldSubexpr(pLeft, i);
    ++      char a = sqlite3ExprAffinity(pA);
    ++      if( pSelect ){
    ++        zRet[i] = sqlite3CompareAffinity(pSelect->pEList->a[i].pExpr, a);
    ++      }else{
    ++        zRet[i] = a;
    ++      }
    ++    }
    ++    zRet[nVal] = '\0';
    ++  }
    ++  return zRet;
    ++}
    ++#endif
    ++
    ++#ifndef SQLITE_OMIT_SUBQUERY
    ++/*
    ++** Load the Parse object passed as the first argument with an error 
    ++** message of the form:
    ++**
    ++**   "sub-select returns N columns - expected M"
    ++*/   
    ++SQLITE_PRIVATE void sqlite3SubselectError(Parse *pParse, int nActual, int nExpect){
    ++  const char *zFmt = "sub-select returns %d columns - expected %d";
    ++  sqlite3ErrorMsg(pParse, zFmt, nActual, nExpect);
    ++}
    ++#endif
    ++
    ++/*
    ++** Expression pExpr is a vector that has been used in a context where
    ++** it is not permitted. If pExpr is a sub-select vector, this routine 
    ++** loads the Parse object with a message of the form:
    ++**
    ++**   "sub-select returns N columns - expected 1"
    ++**
    ++** Or, if it is a regular scalar vector:
    ++**
    ++**   "row value misused"
    ++*/   
    ++SQLITE_PRIVATE void sqlite3VectorErrorMsg(Parse *pParse, Expr *pExpr){
    ++#ifndef SQLITE_OMIT_SUBQUERY
    ++  if( pExpr->flags & EP_xIsSelect ){
    ++    sqlite3SubselectError(pParse, pExpr->x.pSelect->pEList->nExpr, 1);
    ++  }else
    ++#endif
    ++  {
    ++    sqlite3ErrorMsg(pParse, "row value misused");
    ++  }
    ++}
    ++
    + /*
    + ** Generate code for scalar subqueries used as a subquery expression, EXISTS,
    + ** or IN operators.  Examples:
    +@@ -86842,7 +95228,9 @@ SQLITE_PRIVATE int sqlite3FindInIndex(Parse *pParse, Expr *pX, u32 inFlags, int
    + ** 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.
    ++** result.  For a multi-column SELECT, the result is stored in a contiguous
    ++** array of registers and the return value is the register of the left-most
    ++** result column.  Return 0 for IN operators or if an error occurs.
    + */
    + #ifndef SQLITE_OMIT_SUBQUERY
    + SQLITE_PRIVATE int sqlite3CodeSubselect(
    +@@ -86857,8 +95245,8 @@ SQLITE_PRIVATE int sqlite3CodeSubselect(
    +   if( NEVER(v==0) ) return 0;
    +   sqlite3ExprCachePush(pParse);
    + 
    +-  /* This code must be run in its entirety every time it is encountered
    +-  ** if any of the following is true:
    ++  /* The evaluation of the IN/EXISTS/SELECT must be repeated every time it
    ++  ** is encountered if any of the following is true:
    +   **
    +   **    *  The right-hand side is a correlated subquery
    +   **    *  The right-hand side is an expression list containing variables
    +@@ -86868,14 +95256,15 @@ SQLITE_PRIVATE int sqlite3CodeSubselect(
    +   ** save the results, and reuse the same result on subsequent invocations.
    +   */
    +   if( !ExprHasProperty(pExpr, EP_VarSelect) ){
    +-    jmpIfDynamic = sqlite3CodeOnce(pParse); VdbeCoverage(v);
    ++    jmpIfDynamic = sqlite3VdbeAddOp0(v, OP_Once); VdbeCoverage(v);
    +   }
    + 
    + #ifndef SQLITE_OMIT_EXPLAIN
    +   if( pParse->explain==2 ){
    +-    char *zMsg = sqlite3MPrintf(
    +-        pParse->db, "EXECUTE %s%s SUBQUERY %d", jmpIfDynamic>=0?"":"CORRELATED ",
    +-        pExpr->op==TK_IN?"LIST":"SCALAR", pParse->iNextSelectId
    ++    char *zMsg = sqlite3MPrintf(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);
    +   }
    +@@ -86883,17 +95272,18 @@ SQLITE_PRIVATE int sqlite3CodeSubselect(
    + 
    +   switch( pExpr->op ){
    +     case TK_IN: {
    +-      char affinity;              /* Affinity of the LHS of the IN */
    +       int addr;                   /* Address of OP_OpenEphemeral instruction */
    +       Expr *pLeft = pExpr->pLeft; /* the LHS of the IN operator */
    +       KeyInfo *pKeyInfo = 0;      /* Key information */
    +-
    +-      affinity = sqlite3ExprAffinity(pLeft);
    ++      int nVal;                   /* Size of vector pLeft */
    ++      
    ++      nVal = sqlite3ExprVectorSize(pLeft);
    ++      assert( !isRowid || nVal==1 );
    + 
    +       /* Whether this is an 'x IN(SELECT...)' or an 'x IN(<exprlist>)'
    +       ** expression it is handled the same way.  An ephemeral table is 
    +-      ** filled with single-field index keys representing the results
    +-      ** from the SELECT or the <exprlist>.
    ++      ** filled with index keys representing the results from the 
    ++      ** SELECT or the <exprlist>.
    +       **
    +       ** If the 'x' expression is a column value, or the SELECT...
    +       ** statement returns a column value, then the affinity of that
    +@@ -86904,8 +95294,9 @@ SQLITE_PRIVATE int sqlite3CodeSubselect(
    +       ** is used.
    +       */
    +       pExpr->iTable = pParse->nTab++;
    +-      addr = sqlite3VdbeAddOp2(v, OP_OpenEphemeral, pExpr->iTable, !isRowid);
    +-      pKeyInfo = isRowid ? 0 : sqlite3KeyInfoAlloc(pParse->db, 1, 1);
    ++      addr = sqlite3VdbeAddOp2(v, OP_OpenEphemeral, 
    ++          pExpr->iTable, (isRowid?0:nVal));
    ++      pKeyInfo = isRowid ? 0 : sqlite3KeyInfoAlloc(pParse->db, nVal, 1);
    + 
    +       if( ExprHasProperty(pExpr, EP_xIsSelect) ){
    +         /* Case 1:     expr IN (SELECT ...)
    +@@ -86914,27 +95305,36 @@ SQLITE_PRIVATE int sqlite3CodeSubselect(
    +         ** table allocated and opened above.
    +         */
    +         Select *pSelect = pExpr->x.pSelect;
    +-        SelectDest dest;
    +-        ExprList *pEList;
    ++        ExprList *pEList = pSelect->pEList;
    + 
    +         assert( !isRowid );
    +-        sqlite3SelectDestInit(&dest, SRT_Set, pExpr->iTable);
    +-        dest.affSdst = (u8)affinity;
    +-        assert( (pExpr->iTable&0x0000FFFF)==pExpr->iTable );
    +-        pSelect->iLimit = 0;
    +-        testcase( pSelect->selFlags & SF_Distinct );
    +-        testcase( pKeyInfo==0 ); /* Caused by OOM in sqlite3KeyInfoAlloc() */
    +-        if( sqlite3Select(pParse, pSelect, &dest) ){
    +-          sqlite3KeyInfoUnref(pKeyInfo);
    +-          return 0;
    ++        /* If the LHS and RHS of the IN operator do not match, that
    ++        ** error will have been caught long before we reach this point. */
    ++        if( ALWAYS(pEList->nExpr==nVal) ){
    ++          SelectDest dest;
    ++          int i;
    ++          sqlite3SelectDestInit(&dest, SRT_Set, pExpr->iTable);
    ++          dest.zAffSdst = exprINAffinity(pParse, pExpr);
    ++          pSelect->iLimit = 0;
    ++          testcase( pSelect->selFlags & SF_Distinct );
    ++          testcase( pKeyInfo==0 ); /* Caused by OOM in sqlite3KeyInfoAlloc() */
    ++          if( sqlite3Select(pParse, pSelect, &dest) ){
    ++            sqlite3DbFree(pParse->db, dest.zAffSdst);
    ++            sqlite3KeyInfoUnref(pKeyInfo);
    ++            return 0;
    ++          }
    ++          sqlite3DbFree(pParse->db, dest.zAffSdst);
    ++          assert( pKeyInfo!=0 ); /* OOM will cause exit after sqlite3Select() */
    ++          assert( pEList!=0 );
    ++          assert( pEList->nExpr>0 );
    ++          assert( sqlite3KeyInfoIsWriteable(pKeyInfo) );
    ++          for(i=0; i<nVal; i++){
    ++            Expr *p = sqlite3VectorFieldSubexpr(pLeft, i);
    ++            pKeyInfo->aColl[i] = sqlite3BinaryCompareCollSeq(
    ++                pParse, p, pEList->a[i].pExpr
    ++            );
    ++          }
    +         }
    +-        pEList = pSelect->pEList;
    +-        assert( pKeyInfo!=0 ); /* OOM will cause exit after sqlite3Select() */
    +-        assert( pEList!=0 );
    +-        assert( pEList->nExpr>0 );
    +-        assert( sqlite3KeyInfoIsWriteable(pKeyInfo) );
    +-        pKeyInfo->aColl[0] = sqlite3BinaryCompareCollSeq(pParse, pExpr->pLeft,
    +-                                                         pEList->a[0].pExpr);
    +       }else if( ALWAYS(pExpr->x.pList!=0) ){
    +         /* Case 2:     expr IN (exprlist)
    +         **
    +@@ -86943,11 +95343,13 @@ SQLITE_PRIVATE int sqlite3CodeSubselect(
    +         ** that columns affinity when building index keys. If <expr> is not
    +         ** a column, use numeric affinity.
    +         */
    ++        char affinity;            /* Affinity of the LHS of the IN */
    +         int i;
    +         ExprList *pList = pExpr->x.pList;
    +         struct ExprList_item *pItem;
    +         int r1, r2, r3;
    + 
    ++        affinity = sqlite3ExprAffinity(pLeft);
    +         if( !affinity ){
    +           affinity = SQLITE_AFF_BLOB;
    +         }
    +@@ -86959,7 +95361,7 @@ SQLITE_PRIVATE int sqlite3CodeSubselect(
    +         /* Loop through each expression in <exprlist>. */
    +         r1 = sqlite3GetTempReg(pParse);
    +         r2 = sqlite3GetTempReg(pParse);
    +-        if( isRowid ) sqlite3VdbeAddOp2(v, OP_Null, 0, r2);
    ++        if( isRowid ) sqlite3VdbeAddOp4(v, OP_Blob, 0, r2, 0, "", P4_STATIC);
    +         for(i=pList->nExpr, pItem=pList->a; i>0; i--, pItem++){
    +           Expr *pE2 = pItem->pExpr;
    +           int iValToIns;
    +@@ -86987,7 +95389,7 @@ SQLITE_PRIVATE int sqlite3CodeSubselect(
    +             }else{
    +               sqlite3VdbeAddOp4(v, OP_MakeRecord, r3, 1, r2, &affinity, 1);
    +               sqlite3ExprCacheAffinityChange(pParse, r3, 1);
    +-              sqlite3VdbeAddOp2(v, OP_IdxInsert, pExpr->iTable, r2);
    ++              sqlite3VdbeAddOp4Int(v, OP_IdxInsert, pExpr->iTable, r2, r3, 1);
    +             }
    +           }
    +         }
    +@@ -87003,37 +95405,52 @@ SQLITE_PRIVATE int sqlite3CodeSubselect(
    +     case TK_EXISTS:
    +     case TK_SELECT:
    +     default: {
    +-      /* If this has to be a scalar SELECT.  Generate code to put the
    +-      ** value of this select in a memory cell and record the number
    +-      ** of the memory cell in iColumn.  If this is an EXISTS, write
    +-      ** an integer 0 (not exists) or 1 (exists) into a memory cell
    +-      ** and record that memory cell in iColumn.
    ++      /* Case 3:    (SELECT ... FROM ...)
    ++      **     or:    EXISTS(SELECT ... FROM ...)
    ++      **
    ++      ** For a SELECT, generate code to put the values for all columns of
    ++      ** the first row into an array of registers and return the index of
    ++      ** the first register.
    ++      **
    ++      ** If this is an EXISTS, write an integer 0 (not exists) or 1 (exists)
    ++      ** into a register and return that register number.
    ++      **
    ++      ** In both cases, the query is augmented with "LIMIT 1".  Any 
    ++      ** preexisting limit is discarded in place of the new LIMIT 1.
    +       */
    +       Select *pSel;                         /* SELECT statement to encode */
    +-      SelectDest dest;                      /* How to deal with SELECt result */
    ++      SelectDest dest;                      /* How to deal with SELECT result */
    ++      int nReg;                             /* Registers to allocate */
    ++      Expr *pLimit;                         /* New limit expression */
    + 
    +       testcase( pExpr->op==TK_EXISTS );
    +       testcase( pExpr->op==TK_SELECT );
    +       assert( pExpr->op==TK_EXISTS || pExpr->op==TK_SELECT );
    +-
    +       assert( ExprHasProperty(pExpr, EP_xIsSelect) );
    ++
    +       pSel = pExpr->x.pSelect;
    +-      sqlite3SelectDestInit(&dest, 0, ++pParse->nMem);
    ++      nReg = pExpr->op==TK_SELECT ? pSel->pEList->nExpr : 1;
    ++      sqlite3SelectDestInit(&dest, 0, pParse->nMem+1);
    ++      pParse->nMem += nReg;
    +       if( pExpr->op==TK_SELECT ){
    +         dest.eDest = SRT_Mem;
    +         dest.iSdst = dest.iSDParm;
    +-        sqlite3VdbeAddOp2(v, OP_Null, 0, dest.iSDParm);
    ++        dest.nSdst = nReg;
    ++        sqlite3VdbeAddOp3(v, OP_Null, 0, dest.iSDParm, dest.iSDParm+nReg-1);
    +         VdbeComment((v, "Init subquery result"));
    +       }else{
    +         dest.eDest = SRT_Exists;
    +         sqlite3VdbeAddOp2(v, OP_Integer, 0, dest.iSDParm);
    +         VdbeComment((v, "Init EXISTS result"));
    +       }
    +-      sqlite3ExprDelete(pParse->db, pSel->pLimit);
    +-      pSel->pLimit = sqlite3PExpr(pParse, TK_INTEGER, 0, 0,
    +-                                  &sqlite3IntTokens[1]);
    ++      pLimit = sqlite3ExprAlloc(pParse->db, TK_INTEGER,&sqlite3IntTokens[1], 0);
    ++      if( pSel->pLimit ){
    ++        sqlite3ExprDelete(pParse->db, pSel->pLimit->pLeft);
    ++        pSel->pLimit->pLeft = pLimit;
    ++      }else{
    ++        pSel->pLimit = sqlite3PExpr(pParse, TK_LIMIT, pLimit, 0);
    ++      }
    +       pSel->iLimit = 0;
    +-      pSel->selFlags &= ~SF_MultiValue;
    +       if( sqlite3Select(pParse, pSel, &dest) ){
    +         return 0;
    +       }
    +@@ -87056,6 +95473,28 @@ SQLITE_PRIVATE int sqlite3CodeSubselect(
    + }
    + #endif /* SQLITE_OMIT_SUBQUERY */
    + 
    ++#ifndef SQLITE_OMIT_SUBQUERY
    ++/*
    ++** Expr pIn is an IN(...) expression. This function checks that the 
    ++** sub-select on the RHS of the IN() operator has the same number of 
    ++** columns as the vector on the LHS. Or, if the RHS of the IN() is not 
    ++** a sub-query, that the LHS is a vector of size 1.
    ++*/
    ++SQLITE_PRIVATE int sqlite3ExprCheckIN(Parse *pParse, Expr *pIn){
    ++  int nVector = sqlite3ExprVectorSize(pIn->pLeft);
    ++  if( (pIn->flags & EP_xIsSelect) ){
    ++    if( nVector!=pIn->x.pSelect->pEList->nExpr ){
    ++      sqlite3SubselectError(pParse, pIn->x.pSelect->pEList->nExpr, nVector);
    ++      return 1;
    ++    }
    ++  }else if( nVector!=1 ){
    ++    sqlite3VectorErrorMsg(pParse, pIn->pLeft);
    ++    return 1;
    ++  }
    ++  return 0;
    ++}
    ++#endif
    ++
    + #ifndef SQLITE_OMIT_SUBQUERY
    + /*
    + ** Generate code for an IN expression.
    +@@ -87063,16 +95502,24 @@ SQLITE_PRIVATE int sqlite3CodeSubselect(
    + **      x IN (SELECT ...)
    + **      x IN (value, value, ...)
    + **
    +-** The left-hand side (LHS) is a scalar expression.  The right-hand side (RHS)
    +-** is an array of zero or more values.  The expression is true if the LHS is
    +-** contained within the RHS.  The value of the expression is unknown (NULL)
    +-** if the LHS is NULL or if the LHS is not contained within the RHS and the
    +-** RHS contains one or more NULL values.
    ++** The left-hand side (LHS) is a scalar or vector expression.  The 
    ++** right-hand side (RHS) is an array of zero or more scalar values, or a
    ++** subquery.  If the RHS is a subquery, the number of result columns must
    ++** match the number of columns in the vector on the LHS.  If the RHS is
    ++** a list of values, the LHS must be a scalar. 
    ++**
    ++** The IN operator is true if the LHS value is contained within the RHS.
    ++** The result is false if the LHS is definitely not in the RHS.  The 
    ++** result is NULL if the presence of the LHS in the RHS cannot be 
    ++** determined due to NULLs.
    + **
    + ** 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.
    ++**
    ++** See the separate in-operator.md documentation file in the canonical
    ++** SQLite source tree for additional information.
    + */
    + static void sqlite3ExprCodeIN(
    +   Parse *pParse,        /* Parsing and code generating context */
    +@@ -87081,36 +95528,83 @@ static void sqlite3ExprCodeIN(
    +   int destIfNull        /* Jump here if the results are unknown due to NULLs */
    + ){
    +   int rRhsHasNull = 0;  /* Register that is true if RHS contains NULL values */
    +-  char affinity;        /* Comparison affinity to use */
    +   int eType;            /* Type of the RHS */
    +-  int r1;               /* Temporary use register */
    ++  int rLhs;             /* Register(s) holding the LHS values */
    ++  int rLhsOrig;         /* LHS values prior to reordering by aiMap[] */
    +   Vdbe *v;              /* Statement under construction */
    ++  int *aiMap = 0;       /* Map from vector field to index column */
    ++  char *zAff = 0;       /* Affinity string for comparisons */
    ++  int nVector;          /* Size of vectors for this IN operator */
    ++  int iDummy;           /* Dummy parameter to exprCodeVector() */
    ++  Expr *pLeft;          /* The LHS of the IN operator */
    ++  int i;                /* loop counter */
    ++  int destStep2;        /* Where to jump when NULLs seen in step 2 */
    ++  int destStep6 = 0;    /* Start of code for Step 6 */
    ++  int addrTruthOp;      /* Address of opcode that determines the IN is true */
    ++  int destNotNull;      /* Jump here if a comparison is not true in step 6 */
    ++  int addrTop;          /* Top of the step-6 loop */ 
    ++
    ++  pLeft = pExpr->pLeft;
    ++  if( sqlite3ExprCheckIN(pParse, pExpr) ) return;
    ++  zAff = exprINAffinity(pParse, pExpr);
    ++  nVector = sqlite3ExprVectorSize(pExpr->pLeft);
    ++  aiMap = (int*)sqlite3DbMallocZero(
    ++      pParse->db, nVector*(sizeof(int) + sizeof(char)) + 1
    ++  );
    ++  if( pParse->db->mallocFailed ) goto sqlite3ExprCodeIN_oom_error;
    + 
    +-  /* Compute the RHS.   After this step, the table with cursor
    +-  ** pExpr->iTable will contains the values that make up the RHS.
    +-  */
    ++  /* Attempt to compute the RHS. After this step, if anything other than
    ++  ** IN_INDEX_NOOP is returned, the table opened ith cursor pExpr->iTable 
    ++  ** contains the values that make up the RHS. If IN_INDEX_NOOP is returned,
    ++  ** the RHS has not yet been coded.  */
    +   v = pParse->pVdbe;
    +   assert( v!=0 );       /* OOM detected prior to this routine */
    +   VdbeNoopComment((v, "begin IN expr"));
    +   eType = sqlite3FindInIndex(pParse, pExpr,
    +                              IN_INDEX_MEMBERSHIP | IN_INDEX_NOOP_OK,
    +-                             destIfFalse==destIfNull ? 0 : &rRhsHasNull);
    ++                             destIfFalse==destIfNull ? 0 : &rRhsHasNull, aiMap);
    + 
    +-  /* Figure out the affinity to use to create a key from the results
    +-  ** of the expression. affinityStr stores a static string suitable for
    +-  ** P4 of OP_MakeRecord.
    +-  */
    +-  affinity = comparisonAffinity(pExpr);
    ++  assert( pParse->nErr || nVector==1 || eType==IN_INDEX_EPH
    ++       || eType==IN_INDEX_INDEX_ASC || eType==IN_INDEX_INDEX_DESC 
    ++  );
    ++#ifdef SQLITE_DEBUG
    ++  /* Confirm that aiMap[] contains nVector integer values between 0 and
    ++  ** nVector-1. */
    ++  for(i=0; i<nVector; i++){
    ++    int j, cnt;
    ++    for(cnt=j=0; j<nVector; j++) if( aiMap[j]==i ) cnt++;
    ++    assert( cnt==1 );
    ++  }
    ++#endif
    + 
    +-  /* Code the LHS, the <expr> from "<expr> IN (...)".
    ++  /* Code the LHS, the <expr> from "<expr> IN (...)". If the LHS is a 
    ++  ** vector, then it is stored in an array of nVector registers starting 
    ++  ** at r1.
    ++  **
    ++  ** sqlite3FindInIndex() might have reordered the fields of the LHS vector
    ++  ** so that the fields are in the same order as an existing index.   The
    ++  ** aiMap[] array contains a mapping from the original LHS field order to
    ++  ** the field order that matches the RHS index.
    +   */
    +   sqlite3ExprCachePush(pParse);
    +-  r1 = sqlite3GetTempReg(pParse);
    +-  sqlite3ExprCode(pParse, pExpr->pLeft, r1);
    ++  rLhsOrig = exprCodeVector(pParse, pLeft, &iDummy);
    ++  for(i=0; i<nVector && aiMap[i]==i; i++){} /* Are LHS fields reordered? */
    ++  if( i==nVector ){
    ++    /* LHS fields are not reordered */
    ++    rLhs = rLhsOrig;
    ++  }else{
    ++    /* Need to reorder the LHS fields according to aiMap */
    ++    rLhs = sqlite3GetTempRange(pParse, nVector);
    ++    for(i=0; i<nVector; i++){
    ++      sqlite3VdbeAddOp3(v, OP_Copy, rLhsOrig+i, rLhs+aiMap[i], 0);
    ++    }
    ++  }
    + 
    +   /* If sqlite3FindInIndex() did not find or create an index that is
    +   ** suitable for evaluating the IN operator, then evaluate using a
    +   ** sequence of comparisons.
    ++  **
    ++  ** This is step (1) in the in-operator.md optimized algorithm.
    +   */
    +   if( eType==IN_INDEX_NOOP ){
    +     ExprList *pList = pExpr->x.pList;
    +@@ -87122,7 +95616,7 @@ static void sqlite3ExprCodeIN(
    +     assert( !ExprHasProperty(pExpr, EP_xIsSelect) );
    +     if( destIfNull!=destIfFalse ){
    +       regCkNull = sqlite3GetTempReg(pParse);
    +-      sqlite3VdbeAddOp3(v, OP_BitAnd, r1, r1, regCkNull);
    ++      sqlite3VdbeAddOp3(v, OP_BitAnd, rLhs, rLhs, regCkNull);
    +     }
    +     for(ii=0; ii<pList->nExpr; ii++){
    +       r2 = sqlite3ExprCodeTemp(pParse, pList->a[ii].pExpr, &regToFree);
    +@@ -87130,16 +95624,16 @@ static void sqlite3ExprCodeIN(
    +         sqlite3VdbeAddOp3(v, OP_BitAnd, regCkNull, r2, regCkNull);
    +       }
    +       if( ii<pList->nExpr-1 || destIfNull!=destIfFalse ){
    +-        sqlite3VdbeAddOp4(v, OP_Eq, r1, labelOk, r2,
    ++        sqlite3VdbeAddOp4(v, OP_Eq, rLhs, labelOk, r2,
    +                           (void*)pColl, P4_COLLSEQ);
    +         VdbeCoverageIf(v, ii<pList->nExpr-1);
    +         VdbeCoverageIf(v, ii==pList->nExpr-1);
    +-        sqlite3VdbeChangeP5(v, affinity);
    ++        sqlite3VdbeChangeP5(v, zAff[0]);
    +       }else{
    +         assert( destIfNull==destIfFalse );
    +-        sqlite3VdbeAddOp4(v, OP_Ne, r1, destIfFalse, r2,
    ++        sqlite3VdbeAddOp4(v, OP_Ne, rLhs, destIfFalse, r2,
    +                           (void*)pColl, P4_COLLSEQ); VdbeCoverage(v);
    +-        sqlite3VdbeChangeP5(v, affinity | SQLITE_JUMPIFNULL);
    ++        sqlite3VdbeChangeP5(v, zAff[0] | SQLITE_JUMPIFNULL);
    +       }
    +       sqlite3ReleaseTempReg(pParse, regToFree);
    +     }
    +@@ -87149,78 +95643,113 @@ static void sqlite3ExprCodeIN(
    +     }
    +     sqlite3VdbeResolveLabel(v, labelOk);
    +     sqlite3ReleaseTempReg(pParse, regCkNull);
    ++    goto sqlite3ExprCodeIN_finished;
    ++  }
    ++
    ++  /* Step 2: Check to see if the LHS contains any NULL columns.  If the
    ++  ** LHS does contain NULLs then the result must be either FALSE or NULL.
    ++  ** We will then skip the binary search of the RHS.
    ++  */
    ++  if( destIfNull==destIfFalse ){
    ++    destStep2 = destIfFalse;
    +   }else{
    +-  
    +-    /* If the LHS is NULL, then the result is either false or NULL depending
    +-    ** on whether the RHS is empty or not, respectively.
    +-    */
    +-    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);
    +-        sqlite3VdbeGoto(v, destIfNull);
    +-        sqlite3VdbeJumpHere(v, addr1);
    +-      }
    +-    }
    +-  
    +-    if( eType==IN_INDEX_ROWID ){
    +-      /* In this case, the RHS is the ROWID of table b-tree
    +-      */
    +-      sqlite3VdbeAddOp2(v, OP_MustBeInt, r1, destIfFalse); VdbeCoverage(v);
    +-      sqlite3VdbeAddOp3(v, OP_NotExists, pExpr->iTable, destIfFalse, r1);
    ++    destStep2 = destStep6 = sqlite3VdbeMakeLabel(v);
    ++  }
    ++  for(i=0; i<nVector; i++){
    ++    Expr *p = sqlite3VectorFieldSubexpr(pExpr->pLeft, i);
    ++    if( sqlite3ExprCanBeNull(p) ){
    ++      sqlite3VdbeAddOp2(v, OP_IsNull, rLhs+i, destStep2);
    +       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.
    +-      */
    +-      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 addr1;
    +-  
    +-        /* 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.
    +-        */
    +-        addr1 = sqlite3VdbeAddOp4Int(v, OP_Found, pExpr->iTable, 0, r1, 1);
    +-        VdbeCoverage(v);
    +-        sqlite3VdbeAddOp2(v, OP_IsNull, rRhsHasNull, destIfNull);
    +-        VdbeCoverage(v);
    +-        sqlite3VdbeGoto(v, destIfFalse);
    +-        sqlite3VdbeJumpHere(v, addr1);
    +-      }
    +     }
    +   }
    +-  sqlite3ReleaseTempReg(pParse, r1);
    ++
    ++  /* Step 3.  The LHS is now known to be non-NULL.  Do the binary search
    ++  ** of the RHS using the LHS as a probe.  If found, the result is
    ++  ** true.
    ++  */
    ++  if( eType==IN_INDEX_ROWID ){
    ++    /* In this case, the RHS is the ROWID of table b-tree and so we also
    ++    ** know that the RHS is non-NULL.  Hence, we combine steps 3 and 4
    ++    ** into a single opcode. */
    ++    sqlite3VdbeAddOp3(v, OP_SeekRowid, pExpr->iTable, destIfFalse, rLhs);
    ++    VdbeCoverage(v);
    ++    addrTruthOp = sqlite3VdbeAddOp0(v, OP_Goto);  /* Return True */
    ++  }else{
    ++    sqlite3VdbeAddOp4(v, OP_Affinity, rLhs, nVector, 0, zAff, nVector);
    ++    if( destIfFalse==destIfNull ){
    ++      /* Combine Step 3 and Step 5 into a single opcode */
    ++      sqlite3VdbeAddOp4Int(v, OP_NotFound, pExpr->iTable, destIfFalse,
    ++                           rLhs, nVector); VdbeCoverage(v);
    ++      goto sqlite3ExprCodeIN_finished;
    ++    }
    ++    /* Ordinary Step 3, for the case where FALSE and NULL are distinct */
    ++    addrTruthOp = sqlite3VdbeAddOp4Int(v, OP_Found, pExpr->iTable, 0,
    ++                                      rLhs, nVector); VdbeCoverage(v);
    ++  }
    ++
    ++  /* Step 4.  If the RHS is known to be non-NULL and we did not find
    ++  ** an match on the search above, then the result must be FALSE.
    ++  */
    ++  if( rRhsHasNull && nVector==1 ){
    ++    sqlite3VdbeAddOp2(v, OP_NotNull, rRhsHasNull, destIfFalse);
    ++    VdbeCoverage(v);
    ++  }
    ++
    ++  /* Step 5.  If we do not care about the difference between NULL and
    ++  ** FALSE, then just return false. 
    ++  */
    ++  if( destIfFalse==destIfNull ) sqlite3VdbeGoto(v, destIfFalse);
    ++
    ++  /* Step 6: Loop through rows of the RHS.  Compare each row to the LHS.
    ++  ** If any comparison is NULL, then the result is NULL.  If all
    ++  ** comparisons are FALSE then the final result is FALSE.
    ++  **
    ++  ** For a scalar LHS, it is sufficient to check just the first row
    ++  ** of the RHS.
    ++  */
    ++  if( destStep6 ) sqlite3VdbeResolveLabel(v, destStep6);
    ++  addrTop = sqlite3VdbeAddOp2(v, OP_Rewind, pExpr->iTable, destIfFalse);
    ++  VdbeCoverage(v);
    ++  if( nVector>1 ){
    ++    destNotNull = sqlite3VdbeMakeLabel(v);
    ++  }else{
    ++    /* For nVector==1, combine steps 6 and 7 by immediately returning
    ++    ** FALSE if the first comparison is not NULL */
    ++    destNotNull = destIfFalse;
    ++  }
    ++  for(i=0; i<nVector; i++){
    ++    Expr *p;
    ++    CollSeq *pColl;
    ++    int r3 = sqlite3GetTempReg(pParse);
    ++    p = sqlite3VectorFieldSubexpr(pLeft, i);
    ++    pColl = sqlite3ExprCollSeq(pParse, p);
    ++    sqlite3VdbeAddOp3(v, OP_Column, pExpr->iTable, i, r3);
    ++    sqlite3VdbeAddOp4(v, OP_Ne, rLhs+i, destNotNull, r3,
    ++                      (void*)pColl, P4_COLLSEQ);
    ++    VdbeCoverage(v);
    ++    sqlite3ReleaseTempReg(pParse, r3);
    ++  }
    ++  sqlite3VdbeAddOp2(v, OP_Goto, 0, destIfNull);
    ++  if( nVector>1 ){
    ++    sqlite3VdbeResolveLabel(v, destNotNull);
    ++    sqlite3VdbeAddOp2(v, OP_Next, pExpr->iTable, addrTop+1);
    ++    VdbeCoverage(v);
    ++
    ++    /* Step 7:  If we reach this point, we know that the result must
    ++    ** be false. */
    ++    sqlite3VdbeAddOp2(v, OP_Goto, 0, destIfFalse);
    ++  }
    ++
    ++  /* Jumps here in order to return true. */
    ++  sqlite3VdbeJumpHere(v, addrTruthOp);
    ++
    ++sqlite3ExprCodeIN_finished:
    ++  if( rLhs!=rLhsOrig ) sqlite3ReleaseTempReg(pParse, rLhs);
    +   sqlite3ExprCachePop(pParse);
    +   VdbeComment((v, "end IN expr"));
    ++sqlite3ExprCodeIN_oom_error:
    ++  sqlite3DbFree(pParse->db, aiMap);
    ++  sqlite3DbFree(pParse->db, zAff);
    + }
    + #endif /* SQLITE_OMIT_SUBQUERY */
    + 
    +@@ -87264,35 +95793,38 @@ static void codeInteger(Parse *pParse, Expr *pExpr, int negFlag, int iMem){
    +     const char *z = pExpr->u.zToken;
    +     assert( z!=0 );
    +     c = sqlite3DecOrHexToI64(z, &value);
    +-    if( c==0 || (c==2 && negFlag) ){
    +-      if( negFlag ){ value = c==2 ? SMALLEST_INT64 : -value; }
    +-      sqlite3VdbeAddOp4Dup8(v, OP_Int64, 0, iMem, 0, (u8*)&value, P4_INT64);
    +-    }else{
    ++    if( (c==3 && !negFlag) || (c==2) || (negFlag && value==SMALLEST_INT64)){
    + #ifdef SQLITE_OMIT_FLOATING_POINT
    +       sqlite3ErrorMsg(pParse, "oversized integer: %s%s", negFlag ? "-" : "", z);
    + #else
    + #ifndef SQLITE_OMIT_HEX_INTEGER
    +       if( sqlite3_strnicmp(z,"0x",2)==0 ){
    +-        sqlite3ErrorMsg(pParse, "hex literal too big: %s", z);
    ++        sqlite3ErrorMsg(pParse, "hex literal too big: %s%s", negFlag?"-":"",z);
    +       }else
    + #endif
    +       {
    +         codeReal(v, z, negFlag, iMem);
    +       }
    + #endif
    ++    }else{
    ++      if( negFlag ){ value = c==3 ? SMALLEST_INT64 : -value; }
    ++      sqlite3VdbeAddOp4Dup8(v, OP_Int64, 0, iMem, 0, (u8*)&value, P4_INT64);
    +     }
    +   }
    + }
    + 
    + /*
    +-** Clear a cache entry.
    ++** Erase column-cache entry number i
    + */
    +-static void cacheEntryClear(Parse *pParse, struct yColCache *p){
    +-  if( p->tempReg ){
    ++static void cacheEntryClear(Parse *pParse, int i){
    ++  if( pParse->aColCache[i].tempReg ){
    +     if( pParse->nTempReg<ArraySize(pParse->aTempReg) ){
    +-      pParse->aTempReg[pParse->nTempReg++] = p->iReg;
    ++      pParse->aTempReg[pParse->nTempReg++] = pParse->aColCache[i].iReg;
    +     }
    +-    p->tempReg = 0;
    ++  }
    ++  pParse->nColCache--;
    ++  if( i<pParse->nColCache ){
    ++    pParse->aColCache[i] = pParse->aColCache[pParse->nColCache];
    +   }
    + }
    + 
    +@@ -87323,43 +95855,33 @@ SQLITE_PRIVATE void sqlite3ExprCacheStore(Parse *pParse, int iTab, int iCol, int
    +   ** that the object will never already be in cache.  Verify this guarantee.
    +   */
    + #ifndef NDEBUG
    +-  for(i=0, p=pParse->aColCache; i<SQLITE_N_COLCACHE; i++, p++){
    +-    assert( p->iReg==0 || p->iTable!=iTab || p->iColumn!=iCol );
    ++  for(i=0, p=pParse->aColCache; i<pParse->nColCache; i++, p++){
    ++    assert( p->iTable!=iTab || p->iColumn!=iCol );
    +   }
    + #endif
    + 
    +-  /* Find an empty slot and replace it */
    +-  for(i=0, p=pParse->aColCache; i<SQLITE_N_COLCACHE; i++, p++){
    +-    if( p->iReg==0 ){
    +-      p->iLevel = pParse->iCacheLevel;
    +-      p->iTable = iTab;
    +-      p->iColumn = iCol;
    +-      p->iReg = iReg;
    +-      p->tempReg = 0;
    +-      p->lru = pParse->iCacheCnt++;
    +-      return;
    +-    }
    +-  }
    +-
    +-  /* Replace the last recently used */
    +-  minLru = 0x7fffffff;
    +-  idxLru = -1;
    +-  for(i=0, p=pParse->aColCache; i<SQLITE_N_COLCACHE; i++, p++){
    +-    if( p->lru<minLru ){
    +-      idxLru = i;
    +-      minLru = p->lru;
    ++  /* If the cache is already full, delete the least recently used entry */
    ++  if( pParse->nColCache>=SQLITE_N_COLCACHE ){
    ++    minLru = 0x7fffffff;
    ++    idxLru = -1;
    ++    for(i=0, p=pParse->aColCache; i<SQLITE_N_COLCACHE; i++, p++){
    ++      if( p->lru<minLru ){
    ++        idxLru = i;
    ++        minLru = p->lru;
    ++      }
    +     }
    +-  }
    +-  if( ALWAYS(idxLru>=0) ){
    +     p = &pParse->aColCache[idxLru];
    +-    p->iLevel = pParse->iCacheLevel;
    +-    p->iTable = iTab;
    +-    p->iColumn = iCol;
    +-    p->iReg = iReg;
    +-    p->tempReg = 0;
    +-    p->lru = pParse->iCacheCnt++;
    +-    return;
    ++  }else{
    ++    p = &pParse->aColCache[pParse->nColCache++];
    +   }
    ++
    ++  /* Add the new entry to the end of the cache */
    ++  p->iLevel = pParse->iCacheLevel;
    ++  p->iTable = iTab;
    ++  p->iColumn = iCol;
    ++  p->iReg = iReg;
    ++  p->tempReg = 0;
    ++  p->lru = pParse->iCacheCnt++;
    + }
    + 
    + /*
    +@@ -87367,14 +95889,13 @@ SQLITE_PRIVATE void sqlite3ExprCacheStore(Parse *pParse, int iTab, int iCol, int
    + ** Purge the range of registers from the column cache.
    + */
    + SQLITE_PRIVATE void sqlite3ExprCacheRemove(Parse *pParse, int iReg, int nReg){
    +-  int i;
    +-  int iLast = iReg + nReg - 1;
    +-  struct yColCache *p;
    +-  for(i=0, p=pParse->aColCache; i<SQLITE_N_COLCACHE; i++, p++){
    +-    int r = p->iReg;
    +-    if( r>=iReg && r<=iLast ){
    +-      cacheEntryClear(pParse, p);
    +-      p->iReg = 0;
    ++  int i = 0;
    ++  while( i<pParse->nColCache ){
    ++    struct yColCache *p = &pParse->aColCache[i];
    ++    if( p->iReg >= iReg && p->iReg < iReg+nReg ){
    ++      cacheEntryClear(pParse, i);
    ++    }else{
    ++      i++;
    +     }
    +   }
    + }
    +@@ -87399,8 +95920,7 @@ SQLITE_PRIVATE void sqlite3ExprCachePush(Parse *pParse){
    + ** the cache to the state it was in prior the most recent Push.
    + */
    + SQLITE_PRIVATE void sqlite3ExprCachePop(Parse *pParse){
    +-  int i;
    +-  struct yColCache *p;
    ++  int i = 0;
    +   assert( pParse->iCacheLevel>=1 );
    +   pParse->iCacheLevel--;
    + #ifdef SQLITE_DEBUG
    +@@ -87408,10 +95928,11 @@ SQLITE_PRIVATE void sqlite3ExprCachePop(Parse *pParse){
    +     printf("POP  to %d\n", pParse->iCacheLevel);
    +   }
    + #endif
    +-  for(i=0, p=pParse->aColCache; i<SQLITE_N_COLCACHE; i++, p++){
    +-    if( p->iReg && p->iLevel>pParse->iCacheLevel ){
    +-      cacheEntryClear(pParse, p);
    +-      p->iReg = 0;
    ++  while( i<pParse->nColCache ){
    ++    if( pParse->aColCache[i].iLevel>pParse->iCacheLevel ){
    ++      cacheEntryClear(pParse, i);
    ++    }else{
    ++      i++;
    +     }
    +   }
    + }
    +@@ -87425,7 +95946,7 @@ SQLITE_PRIVATE void sqlite3ExprCachePop(Parse *pParse){
    + static void sqlite3ExprCachePinRegister(Parse *pParse, int iReg){
    +   int i;
    +   struct yColCache *p;
    +-  for(i=0, p=pParse->aColCache; i<SQLITE_N_COLCACHE; i++, p++){
    ++  for(i=0, p=pParse->aColCache; i<pParse->nColCache; i++, p++){
    +     if( p->iReg==iReg ){
    +       p->tempReg = 0;
    +     }
    +@@ -87446,8 +95967,9 @@ SQLITE_PRIVATE void sqlite3ExprCodeLoadIndexColumn(
    +   if( iTabCol==XN_EXPR ){
    +     assert( pIdx->aColExpr );
    +     assert( pIdx->aColExpr->nExpr>iIdxCol );
    +-    pParse->iSelfTab = iTabCur;
    +-    sqlite3ExprCode(pParse, pIdx->aColExpr->a[iIdxCol].pExpr, regOut);
    ++    pParse->iSelfTab = iTabCur + 1;
    ++    sqlite3ExprCodeCopy(pParse, pIdx->aColExpr->a[iIdxCol].pExpr, regOut);
    ++    pParse->iSelfTab = 0;
    +   }else{
    +     sqlite3ExprCodeGetColumnOfTable(pParse->pVdbe, pIdx->pTable, iTabCur,
    +                                     iTabCol, regOut);
    +@@ -87464,12 +95986,16 @@ SQLITE_PRIVATE void sqlite3ExprCodeGetColumnOfTable(
    +   int iCol,       /* Index of the column to extract */
    +   int regOut      /* Extract the value into this register */
    + ){
    ++  if( pTab==0 ){
    ++    sqlite3VdbeAddOp3(v, OP_Column, iTabCur, iCol, regOut);
    ++    return;
    ++  }
    +   if( iCol<0 || iCol==pTab->iPKey ){
    +     sqlite3VdbeAddOp2(v, OP_Rowid, iTabCur, regOut);
    +   }else{
    +     int op = IsVirtual(pTab) ? OP_VColumn : OP_Column;
    +     int x = iCol;
    +-    if( !HasRowid(pTab) ){
    ++    if( !HasRowid(pTab) && !IsVirtual(pTab) ){
    +       x = sqlite3ColumnOfIndex(sqlite3PrimaryKeyIndex(pTab), iCol);
    +     }
    +     sqlite3VdbeAddOp3(v, op, iTabCur, x, regOut);
    +@@ -87481,9 +96007,12 @@ SQLITE_PRIVATE void sqlite3ExprCodeGetColumnOfTable(
    + 
    + /*
    + ** Generate code that will extract the iColumn-th column from
    +-** table pTab and store the column value in a register.  An effort
    +-** is made to store the column value in register iReg, but this is
    +-** not guaranteed.  The location of the column value is returned.
    ++** table pTab and store the column value in a register. 
    ++**
    ++** An effort is made to store the column value in register iReg.  This
    ++** is not garanteeed for GetColumn() - the result can be stored in
    ++** any register.  But the result is guaranteed to land in register iReg
    ++** for GetColumnToReg().
    + **
    + ** There must be an open cursor to pTab in iTable when this routine
    + ** is called.  If iColumn<0 then code is generated that extracts the rowid.
    +@@ -87494,14 +96023,14 @@ SQLITE_PRIVATE int sqlite3ExprCodeGetColumn(
    +   int iColumn,     /* Index of the table column */
    +   int iTable,      /* The cursor pointing to the table */
    +   int iReg,        /* Store results here */
    +-  u8 p5            /* P5 value for OP_Column */
    ++  u8 p5            /* P5 value for OP_Column + FLAGS */
    + ){
    +   Vdbe *v = pParse->pVdbe;
    +   int i;
    +   struct yColCache *p;
    + 
    +-  for(i=0, p=pParse->aColCache; i<SQLITE_N_COLCACHE; i++, p++){
    +-    if( p->iReg>0 && p->iTable==iTable && p->iColumn==iColumn ){
    ++  for(i=0, p=pParse->aColCache; i<pParse->nColCache; i++, p++){
    ++    if( p->iTable==iTable && p->iColumn==iColumn ){
    +       p->lru = pParse->iCacheCnt++;
    +       sqlite3ExprCachePinRegister(pParse, p->iReg);
    +       return p->iReg;
    +@@ -87516,25 +96045,37 @@ SQLITE_PRIVATE int sqlite3ExprCodeGetColumn(
    +   }
    +   return iReg;
    + }
    ++SQLITE_PRIVATE void sqlite3ExprCodeGetColumnToReg(
    ++  Parse *pParse,   /* Parsing and code generating context */
    ++  Table *pTab,     /* Description of the table we are reading from */
    ++  int iColumn,     /* Index of the table column */
    ++  int iTable,      /* The cursor pointing to the table */
    ++  int iReg         /* Store results here */
    ++){
    ++  int r1 = sqlite3ExprCodeGetColumn(pParse, pTab, iColumn, iTable, iReg, 0);
    ++  if( r1!=iReg ) sqlite3VdbeAddOp2(pParse->pVdbe, OP_SCopy, r1, iReg);
    ++}
    ++
    + 
    + /*
    + ** Clear all column cache entries.
    + */
    + SQLITE_PRIVATE void sqlite3ExprCacheClear(Parse *pParse){
    +   int i;
    +-  struct yColCache *p;
    + 
    +-#if SQLITE_DEBUG
    ++#ifdef SQLITE_DEBUG
    +   if( pParse->db->flags & SQLITE_VdbeAddopTrace ){
    +     printf("CLEAR\n");
    +   }
    + #endif
    +-  for(i=0, p=pParse->aColCache; i<SQLITE_N_COLCACHE; i++, p++){
    +-    if( p->iReg ){
    +-      cacheEntryClear(pParse, p);
    +-      p->iReg = 0;
    ++  for(i=0; i<pParse->nColCache; i++){
    ++    if( pParse->aColCache[i].tempReg
    ++     && pParse->nTempReg<ArraySize(pParse->aTempReg)
    ++    ){
    ++       pParse->aTempReg[pParse->nTempReg++] = pParse->aColCache[i].iReg;
    +     }
    +   }
    ++  pParse->nColCache = 0;
    + }
    + 
    + /*
    +@@ -87566,7 +96107,7 @@ SQLITE_PRIVATE void sqlite3ExprCodeMove(Parse *pParse, int iFrom, int iTo, int n
    + static int usedAsColumnCache(Parse *pParse, int iFrom, int iTo){
    +   int i;
    +   struct yColCache *p;
    +-  for(i=0, p=pParse->aColCache; i<SQLITE_N_COLCACHE; i++, p++){
    ++  for(i=0, p=pParse->aColCache; i<pParse->nColCache; i++, p++){
    +     int r = p->iReg;
    +     if( r>=iFrom && r<=iTo ) return 1;    /*NO_TEST*/
    +   }
    +@@ -87574,8 +96115,11 @@ static int usedAsColumnCache(Parse *pParse, int iFrom, int iTo){
    + }
    + #endif /* SQLITE_DEBUG || SQLITE_COVERAGE_TEST */
    + 
    ++
    + /*
    +-** Convert an expression node to a TK_REGISTER
    ++** Convert a scalar expression node to a TK_REGISTER referencing
    ++** register iReg.  The caller must ensure that iReg already contains
    ++** the correct value for the expression.
    + */
    + static void exprToRegister(Expr *p, int iReg){
    +   p->op2 = p->op;
    +@@ -87584,6 +96128,42 @@ static void exprToRegister(Expr *p, int iReg){
    +   ExprClearProperty(p, EP_Skip);
    + }
    + 
    ++/*
    ++** Evaluate an expression (either a vector or a scalar expression) and store
    ++** the result in continguous temporary registers.  Return the index of
    ++** the first register used to store the result.
    ++**
    ++** If the returned result register is a temporary scalar, then also write
    ++** that register number into *piFreeable.  If the returned result register
    ++** is not a temporary or if the expression is a vector set *piFreeable
    ++** to 0.
    ++*/
    ++static int exprCodeVector(Parse *pParse, Expr *p, int *piFreeable){
    ++  int iResult;
    ++  int nResult = sqlite3ExprVectorSize(p);
    ++  if( nResult==1 ){
    ++    iResult = sqlite3ExprCodeTemp(pParse, p, piFreeable);
    ++  }else{
    ++    *piFreeable = 0;
    ++    if( p->op==TK_SELECT ){
    ++#if SQLITE_OMIT_SUBQUERY
    ++      iResult = 0;
    ++#else
    ++      iResult = sqlite3CodeSubselect(pParse, p, 0, 0);
    ++#endif
    ++    }else{
    ++      int i;
    ++      iResult = pParse->nMem+1;
    ++      pParse->nMem += nResult;
    ++      for(i=0; i<nResult; i++){
    ++        sqlite3ExprCodeFactorable(pParse, p->x.pList->a[i].pExpr, i+iResult);
    ++      }
    ++    }
    ++  }
    ++  return iResult;
    ++}
    ++
    ++
    + /*
    + ** Generate code into the current Vdbe to evaluate the given
    + ** expression.  Attempt to store the results in register "target".
    +@@ -87601,9 +96181,9 @@ SQLITE_PRIVATE int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target)
    +   int inReg = target;       /* Results stored in register inReg */
    +   int regFree1 = 0;         /* If non-zero free this temporary register */
    +   int regFree2 = 0;         /* If non-zero free this temporary register */
    +-  int r1, r2, r3, r4;       /* Various register numbers */
    +-  sqlite3 *db = pParse->db; /* The database connection */
    ++  int r1, r2;               /* Various register numbers */
    +   Expr tempX;               /* Temporary expression node */
    ++  int p5 = 0;
    + 
    +   assert( target>0 && target<=pParse->nMem );
    +   if( v==0 ){
    +@@ -87622,52 +96202,49 @@ SQLITE_PRIVATE int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target)
    +       struct AggInfo_col *pCol = &pAggInfo->aCol[pExpr->iAgg];
    +       if( !pAggInfo->directMode ){
    +         assert( pCol->iMem>0 );
    +-        inReg = pCol->iMem;
    +-        break;
    ++        return pCol->iMem;
    +       }else if( pAggInfo->useSortingIdx ){
    +         sqlite3VdbeAddOp3(v, OP_Column, pAggInfo->sortingIdxPTab,
    +                               pCol->iSorterColumn, target);
    +-        break;
    ++        return target;
    +       }
    +       /* Otherwise, fall thru into the TK_COLUMN case */
    +     }
    +     case TK_COLUMN: {
    +       int iTab = pExpr->iTable;
    +       if( iTab<0 ){
    +-        if( pParse->ckBase>0 ){
    ++        if( pParse->iSelfTab<0 ){
    +           /* Generating CHECK constraints or inserting into partial index */
    +-          inReg = pExpr->iColumn + pParse->ckBase;
    +-          break;
    ++          return pExpr->iColumn - pParse->iSelfTab;
    +         }else{
    +           /* Coding an expression that is part of an index where column names
    +           ** in the index refer to the table to which the index belongs */
    +-          iTab = pParse->iSelfTab;
    ++          iTab = pParse->iSelfTab - 1;
    +         }
    +       }
    +-      inReg = sqlite3ExprCodeGetColumn(pParse, pExpr->pTab,
    ++      return sqlite3ExprCodeGetColumn(pParse, pExpr->pTab,
    +                                pExpr->iColumn, iTab, target,
    +                                pExpr->op2);
    +-      break;
    +     }
    +     case TK_INTEGER: {
    +       codeInteger(pParse, pExpr, 0, target);
    +-      break;
    ++      return target;
    +     }
    + #ifndef SQLITE_OMIT_FLOATING_POINT
    +     case TK_FLOAT: {
    +       assert( !ExprHasProperty(pExpr, EP_IntValue) );
    +       codeReal(v, pExpr->u.zToken, 0, target);
    +-      break;
    ++      return target;
    +     }
    + #endif
    +     case TK_STRING: {
    +       assert( !ExprHasProperty(pExpr, EP_IntValue) );
    +       sqlite3VdbeLoadString(v, target, pExpr->u.zToken);
    +-      break;
    ++      return target;
    +     }
    +     case TK_NULL: {
    +       sqlite3VdbeAddOp2(v, OP_Null, 0, target);
    +-      break;
    ++      return target;
    +     }
    + #ifndef SQLITE_OMIT_BLOB_LITERAL
    +     case TK_BLOB: {
    +@@ -87682,7 +96259,7 @@ SQLITE_PRIVATE int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target)
    +       assert( z[n]=='\'' );
    +       zBlob = sqlite3HexToBlob(sqlite3VdbeDb(v), z, n);
    +       sqlite3VdbeAddOp4(v, OP_Blob, n/2, target, 0, zBlob, P4_DYNAMIC);
    +-      break;
    ++      return target;
    +     }
    + #endif
    +     case TK_VARIABLE: {
    +@@ -87691,15 +96268,15 @@ SQLITE_PRIVATE int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target)
    +       assert( pExpr->u.zToken[0]!=0 );
    +       sqlite3VdbeAddOp2(v, OP_Variable, pExpr->iColumn, target);
    +       if( pExpr->u.zToken[1]!=0 ){
    +-        assert( pExpr->u.zToken[0]=='?' 
    +-             || strcmp(pExpr->u.zToken, pParse->azVar[pExpr->iColumn-1])==0 );
    +-        sqlite3VdbeChangeP4(v, -1, pParse->azVar[pExpr->iColumn-1], P4_STATIC);
    ++        const char *z = sqlite3VListNumToName(pParse->pVList, pExpr->iColumn);
    ++        assert( pExpr->u.zToken[0]=='?' || strcmp(pExpr->u.zToken, z)==0 );
    ++        pParse->pVList[0] = 0; /* Indicate VList may no longer be enlarged */
    ++        sqlite3VdbeAppendP4(v, (char*)z, P4_STATIC);
    +       }
    +-      break;
    ++      return target;
    +     }
    +     case TK_REGISTER: {
    +-      inReg = pExpr->iTable;
    +-      break;
    ++      return pExpr->iTable;
    +     }
    + #ifndef SQLITE_OMIT_CAST
    +     case TK_CAST: {
    +@@ -87713,42 +96290,37 @@ SQLITE_PRIVATE int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target)
    +                         sqlite3AffinityType(pExpr->u.zToken, 0));
    +       testcase( usedAsColumnCache(pParse, inReg, inReg) );
    +       sqlite3ExprCacheAffinityChange(pParse, inReg, 1);
    +-      break;
    ++      return inReg;
    +     }
    + #endif /* SQLITE_OMIT_CAST */
    ++    case TK_IS:
    ++    case TK_ISNOT:
    ++      op = (op==TK_IS) ? TK_EQ : TK_NE;
    ++      p5 = SQLITE_NULLEQ;
    ++      /* fall-through */
    +     case TK_LT:
    +     case TK_LE:
    +     case TK_GT:
    +     case TK_GE:
    +     case TK_NE:
    +     case TK_EQ: {
    +-      r1 = sqlite3ExprCodeTemp(pParse, pExpr->pLeft, &regFree1);
    +-      r2 = sqlite3ExprCodeTemp(pParse, pExpr->pRight, &regFree2);
    +-      codeCompare(pParse, pExpr->pLeft, pExpr->pRight, op,
    +-                  r1, r2, inReg, SQLITE_STOREP2);
    +-      assert(TK_LT==OP_Lt); testcase(op==OP_Lt); VdbeCoverageIf(v,op==OP_Lt);
    +-      assert(TK_LE==OP_Le); testcase(op==OP_Le); VdbeCoverageIf(v,op==OP_Le);
    +-      assert(TK_GT==OP_Gt); testcase(op==OP_Gt); VdbeCoverageIf(v,op==OP_Gt);
    +-      assert(TK_GE==OP_Ge); testcase(op==OP_Ge); VdbeCoverageIf(v,op==OP_Ge);
    +-      assert(TK_EQ==OP_Eq); testcase(op==OP_Eq); VdbeCoverageIf(v,op==OP_Eq);
    +-      assert(TK_NE==OP_Ne); testcase(op==OP_Ne); VdbeCoverageIf(v,op==OP_Ne);
    +-      testcase( regFree1==0 );
    +-      testcase( regFree2==0 );
    +-      break;
    +-    }
    +-    case TK_IS:
    +-    case TK_ISNOT: {
    +-      testcase( op==TK_IS );
    +-      testcase( op==TK_ISNOT );
    +-      r1 = sqlite3ExprCodeTemp(pParse, pExpr->pLeft, &regFree1);
    +-      r2 = sqlite3ExprCodeTemp(pParse, pExpr->pRight, &regFree2);
    +-      op = (op==TK_IS) ? TK_EQ : TK_NE;
    +-      codeCompare(pParse, pExpr->pLeft, pExpr->pRight, op,
    +-                  r1, r2, inReg, SQLITE_STOREP2 | SQLITE_NULLEQ);
    +-      VdbeCoverageIf(v, op==TK_EQ);
    +-      VdbeCoverageIf(v, op==TK_NE);
    +-      testcase( regFree1==0 );
    +-      testcase( regFree2==0 );
    ++      Expr *pLeft = pExpr->pLeft;
    ++      if( sqlite3ExprIsVector(pLeft) ){
    ++        codeVectorCompare(pParse, pExpr, target, op, p5);
    ++      }else{
    ++        r1 = sqlite3ExprCodeTemp(pParse, pLeft, &regFree1);
    ++        r2 = sqlite3ExprCodeTemp(pParse, pExpr->pRight, &regFree2);
    ++        codeCompare(pParse, pLeft, pExpr->pRight, op,
    ++            r1, r2, inReg, SQLITE_STOREP2 | p5);
    ++        assert(TK_LT==OP_Lt); testcase(op==OP_Lt); VdbeCoverageIf(v,op==OP_Lt);
    ++        assert(TK_LE==OP_Le); testcase(op==OP_Le); VdbeCoverageIf(v,op==OP_Le);
    ++        assert(TK_GT==OP_Gt); testcase(op==OP_Gt); VdbeCoverageIf(v,op==OP_Gt);
    ++        assert(TK_GE==OP_Ge); testcase(op==OP_Ge); VdbeCoverageIf(v,op==OP_Ge);
    ++        assert(TK_EQ==OP_Eq); testcase(op==OP_Eq); VdbeCoverageIf(v,op==OP_Eq);
    ++        assert(TK_NE==OP_Ne); testcase(op==OP_Ne); VdbeCoverageIf(v,op==OP_Ne);
    ++        testcase( regFree1==0 );
    ++        testcase( regFree2==0 );
    ++      }
    +       break;
    +     }
    +     case TK_AND:
    +@@ -87786,10 +96358,12 @@ SQLITE_PRIVATE int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target)
    +       assert( pLeft );
    +       if( pLeft->op==TK_INTEGER ){
    +         codeInteger(pParse, pLeft, 1, target);
    ++        return target;
    + #ifndef SQLITE_OMIT_FLOATING_POINT
    +       }else if( pLeft->op==TK_FLOAT ){
    +         assert( !ExprHasProperty(pExpr, EP_IntValue) );
    +         codeReal(v, pLeft->u.zToken, 1, target);
    ++        return target;
    + #endif
    +       }else{
    +         tempX.op = TK_INTEGER;
    +@@ -87800,7 +96374,6 @@ SQLITE_PRIVATE int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target)
    +         sqlite3VdbeAddOp3(v, OP_Subtract, r2, r1, target);
    +         testcase( regFree2==0 );
    +       }
    +-      inReg = target;
    +       break;
    +     }
    +     case TK_BITNOT:
    +@@ -87809,7 +96382,6 @@ SQLITE_PRIVATE int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target)
    +       assert( TK_NOT==OP_Not );         testcase( op==TK_NOT );
    +       r1 = sqlite3ExprCodeTemp(pParse, pExpr->pLeft, &regFree1);
    +       testcase( regFree1==0 );
    +-      inReg = target;
    +       sqlite3VdbeAddOp2(v, op, r1, inReg);
    +       break;
    +     }
    +@@ -87834,7 +96406,7 @@ SQLITE_PRIVATE int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target)
    +         assert( !ExprHasProperty(pExpr, EP_IntValue) );
    +         sqlite3ErrorMsg(pParse, "misuse of aggregate: %s()", pExpr->u.zToken);
    +       }else{
    +-        inReg = pInfo->aFunc[pExpr->iAgg].iMem;
    ++        return pInfo->aFunc[pExpr->iAgg].iMem;
    +       }
    +       break;
    +     }
    +@@ -87842,13 +96414,18 @@ SQLITE_PRIVATE int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target)
    +       ExprList *pFarg;       /* List of function arguments */
    +       int nFarg;             /* Number of function arguments */
    +       FuncDef *pDef;         /* The function definition object */
    +-      int nId;               /* Length of the function name in bytes */
    +       const char *zId;       /* The function name */
    +       u32 constMask = 0;     /* Mask of function arguments that are constant */
    +       int i;                 /* Loop counter */
    ++      sqlite3 *db = pParse->db;  /* The database connection */
    +       u8 enc = ENC(db);      /* The text encoding used by this database */
    +       CollSeq *pColl = 0;    /* A collating sequence */
    + 
    ++      if( ConstFactorOk(pParse) && sqlite3ExprIsConstantNotJoin(pExpr) ){
    ++        /* SQL functions can be expensive. So try to move constant functions
    ++        ** out of the inner loop, even if that means an extra OP_Copy. */
    ++        return sqlite3ExprCodeAtInit(pParse, pExpr, -1);
    ++      }
    +       assert( !ExprHasProperty(pExpr, EP_xIsSelect) );
    +       if( ExprHasProperty(pExpr, EP_TokenOnly) ){
    +         pFarg = 0;
    +@@ -87858,10 +96435,14 @@ SQLITE_PRIVATE int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target)
    +       nFarg = pFarg ? pFarg->nExpr : 0;
    +       assert( !ExprHasProperty(pExpr, EP_IntValue) );
    +       zId = pExpr->u.zToken;
    +-      nId = sqlite3Strlen30(zId);
    +-      pDef = sqlite3FindFunction(db, zId, nId, nFarg, enc, 0);
    +-      if( pDef==0 || pDef->xFunc==0 ){
    +-        sqlite3ErrorMsg(pParse, "unknown function: %.*s()", nId, zId);
    ++      pDef = sqlite3FindFunction(db, zId, nFarg, enc, 0);
    ++#ifdef SQLITE_ENABLE_UNKNOWN_SQL_FUNCTION
    ++      if( pDef==0 && pParse->explain ){
    ++        pDef = sqlite3FindFunction(db, "unknown", nFarg, enc, 0);
    ++      }
    ++#endif
    ++      if( pDef==0 || pDef->xFinalize!=0 ){
    ++        sqlite3ErrorMsg(pParse, "unknown function: %s()", zId);
    +         break;
    +       }
    + 
    +@@ -87890,9 +96471,24 @@ SQLITE_PRIVATE int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target)
    +       */
    +       if( pDef->funcFlags & SQLITE_FUNC_UNLIKELY ){
    +         assert( nFarg>=1 );
    +-        inReg = sqlite3ExprCodeTarget(pParse, pFarg->a[0].pExpr, target);
    +-        break;
    ++        return sqlite3ExprCodeTarget(pParse, pFarg->a[0].pExpr, target);
    ++      }
    ++
    ++#ifdef SQLITE_DEBUG
    ++      /* The AFFINITY() function evaluates to a string that describes
    ++      ** the type affinity of the argument.  This is used for testing of
    ++      ** the SQLite type logic.
    ++      */
    ++      if( pDef->funcFlags & SQLITE_FUNC_AFFINITY ){
    ++        const char *azAff[] = { "blob", "text", "numeric", "integer", "real" };
    ++        char aff;
    ++        assert( nFarg==1 );
    ++        aff = sqlite3ExprAffinity(pFarg->a[0].pExpr);
    ++        sqlite3VdbeLoadString(v, target, 
    ++                              aff ? azAff[aff-SQLITE_AFF_BLOB] : "none");
    ++        return target;
    +       }
    ++#endif
    + 
    +       for(i=0; i<nFarg; i++){
    +         if( i<32 && sqlite3ExprIsConstant(pFarg->a[i].pExpr) ){
    +@@ -87960,22 +96556,53 @@ SQLITE_PRIVATE int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target)
    +         if( !pColl ) pColl = db->pDfltColl; 
    +         sqlite3VdbeAddOp4(v, OP_CollSeq, 0, 0, 0, (char *)pColl, P4_COLLSEQ);
    +       }
    +-      sqlite3VdbeAddOp4(v, OP_Function0, constMask, r1, target,
    +-                        (char*)pDef, P4_FUNCDEF);
    +-      sqlite3VdbeChangeP5(v, (u8)nFarg);
    ++#ifdef SQLITE_ENABLE_OFFSET_SQL_FUNC
    ++      if( pDef->funcFlags & SQLITE_FUNC_OFFSET ){
    ++        Expr *pArg = pFarg->a[0].pExpr;
    ++        if( pArg->op==TK_COLUMN ){
    ++          sqlite3VdbeAddOp3(v, OP_Offset, pArg->iTable, pArg->iColumn, target);
    ++        }else{
    ++          sqlite3VdbeAddOp2(v, OP_Null, 0, target);
    ++        }
    ++      }else
    ++#endif
    ++      {
    ++        sqlite3VdbeAddOp4(v, pParse->iSelfTab ? OP_PureFunc0 : OP_Function0,
    ++                          constMask, r1, target, (char*)pDef, P4_FUNCDEF);
    ++        sqlite3VdbeChangeP5(v, (u8)nFarg);
    ++      }
    +       if( nFarg && constMask==0 ){
    +         sqlite3ReleaseTempRange(pParse, r1, nFarg);
    +       }
    +-      break;
    ++      return target;
    +     }
    + #ifndef SQLITE_OMIT_SUBQUERY
    +     case TK_EXISTS:
    +     case TK_SELECT: {
    ++      int nCol;
    +       testcase( op==TK_EXISTS );
    +       testcase( op==TK_SELECT );
    +-      inReg = sqlite3CodeSubselect(pParse, pExpr, 0, 0);
    ++      if( op==TK_SELECT && (nCol = pExpr->x.pSelect->pEList->nExpr)!=1 ){
    ++        sqlite3SubselectError(pParse, nCol, 1);
    ++      }else{
    ++        return sqlite3CodeSubselect(pParse, pExpr, 0, 0);
    ++      }
    +       break;
    +     }
    ++    case TK_SELECT_COLUMN: {
    ++      int n;
    ++      if( pExpr->pLeft->iTable==0 ){
    ++        pExpr->pLeft->iTable = sqlite3CodeSubselect(pParse, pExpr->pLeft, 0, 0);
    ++      }
    ++      assert( pExpr->iTable==0 || pExpr->pLeft->op==TK_SELECT );
    ++      if( pExpr->iTable
    ++       && pExpr->iTable!=(n = sqlite3ExprVectorSize(pExpr->pLeft)) 
    ++      ){
    ++        sqlite3ErrorMsg(pParse, "%d columns assigned %d values",
    ++                                pExpr->iTable, n);
    ++      }
    ++      return pExpr->pLeft->iTable + pExpr->iColumn;
    ++    }
    +     case TK_IN: {
    +       int destIfFalse = sqlite3VdbeMakeLabel(v);
    +       int destIfNull = sqlite3VdbeMakeLabel(v);
    +@@ -87985,7 +96612,7 @@ SQLITE_PRIVATE int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target)
    +       sqlite3VdbeResolveLabel(v, destIfFalse);
    +       sqlite3VdbeAddOp2(v, OP_AddImm, target, 0);
    +       sqlite3VdbeResolveLabel(v, destIfNull);
    +-      break;
    ++      return target;
    +     }
    + #endif /* SQLITE_OMIT_SUBQUERY */
    + 
    +@@ -88002,34 +96629,13 @@ SQLITE_PRIVATE int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target)
    +     ** Z is stored in pExpr->pList->a[1].pExpr.
    +     */
    +     case TK_BETWEEN: {
    +-      Expr *pLeft = pExpr->pLeft;
    +-      struct ExprList_item *pLItem = pExpr->x.pList->a;
    +-      Expr *pRight = pLItem->pExpr;
    +-
    +-      r1 = sqlite3ExprCodeTemp(pParse, pLeft, &regFree1);
    +-      r2 = sqlite3ExprCodeTemp(pParse, pRight, &regFree2);
    +-      testcase( regFree1==0 );
    +-      testcase( regFree2==0 );
    +-      r3 = sqlite3GetTempReg(pParse);
    +-      r4 = sqlite3GetTempReg(pParse);
    +-      codeCompare(pParse, pLeft, pRight, OP_Ge,
    +-                  r1, r2, r3, SQLITE_STOREP2);  VdbeCoverage(v);
    +-      pLItem++;
    +-      pRight = pLItem->pExpr;
    +-      sqlite3ReleaseTempReg(pParse, regFree2);
    +-      r2 = sqlite3ExprCodeTemp(pParse, pRight, &regFree2);
    +-      testcase( regFree2==0 );
    +-      codeCompare(pParse, pLeft, pRight, OP_Le, r1, r2, r4, SQLITE_STOREP2);
    +-      VdbeCoverage(v);
    +-      sqlite3VdbeAddOp3(v, OP_And, r3, r4, target);
    +-      sqlite3ReleaseTempReg(pParse, r3);
    +-      sqlite3ReleaseTempReg(pParse, r4);
    +-      break;
    ++      exprCodeBetween(pParse, pExpr, target, 0, 0);
    ++      return target;
    +     }
    ++    case TK_SPAN:
    +     case TK_COLLATE: 
    +     case TK_UPLUS: {
    +-      inReg = sqlite3ExprCodeTarget(pParse, pExpr->pLeft, target);
    +-      break;
    ++      return sqlite3ExprCodeTarget(pParse, pExpr->pLeft, target);
    +     }
    + 
    +     case TK_TRIGGER: {
    +@@ -88088,6 +96694,21 @@ SQLITE_PRIVATE int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target)
    +       break;
    +     }
    + 
    ++    case TK_VECTOR: {
    ++      sqlite3ErrorMsg(pParse, "row value misused");
    ++      break;
    ++    }
    ++
    ++    case TK_IF_NULL_ROW: {
    ++      int addrINR;
    ++      addrINR = sqlite3VdbeAddOp1(v, OP_IfNullRow, pExpr->iTable);
    ++      sqlite3ExprCachePush(pParse);
    ++      inReg = sqlite3ExprCodeTarget(pParse, pExpr->pLeft, target);
    ++      sqlite3ExprCachePop(pParse);
    ++      sqlite3VdbeJumpHere(v, addrINR);
    ++      sqlite3VdbeChangeP3(v, addrINR, inReg);
    ++      break;
    ++    }
    + 
    +     /*
    +     ** Form A:
    +@@ -88131,8 +96752,9 @@ SQLITE_PRIVATE int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target)
    +       if( (pX = pExpr->pLeft)!=0 ){
    +         tempX = *pX;
    +         testcase( pX->op==TK_COLUMN );
    +-        exprToRegister(&tempX, sqlite3ExprCodeTemp(pParse, pX, &regFree1));
    ++        exprToRegister(&tempX, exprCodeVector(pParse, &tempX, &regFree1));
    +         testcase( regFree1==0 );
    ++        memset(&opCompare, 0, sizeof(opCompare));
    +         opCompare.op = TK_EQ;
    +         opCompare.pLeft = &tempX;
    +         pTest = &opCompare;
    +@@ -88166,7 +96788,7 @@ SQLITE_PRIVATE int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target)
    +       }else{
    +         sqlite3VdbeAddOp2(v, OP_Null, 0, target);
    +       }
    +-      assert( db->mallocFailed || pParse->nErr>0 
    ++      assert( pParse->db->mallocFailed || pParse->nErr>0 
    +            || pParse->iCacheLevel==iCacheLevel );
    +       sqlite3VdbeResolveLabel(v, endLabel);
    +       break;
    +@@ -88207,24 +96829,40 @@ SQLITE_PRIVATE int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target)
    + 
    + /*
    + ** Factor out the code of the given expression to initialization time.
    ++**
    ++** If regDest>=0 then the result is always stored in that register and the
    ++** result is not reusable.  If regDest<0 then this routine is free to 
    ++** store the value whereever it wants.  The register where the expression 
    ++** is stored is returned.  When regDest<0, two identical expressions will
    ++** code to the same register.
    + */
    +-SQLITE_PRIVATE void sqlite3ExprCodeAtInit(
    ++SQLITE_PRIVATE int sqlite3ExprCodeAtInit(
    +   Parse *pParse,    /* Parsing context */
    +   Expr *pExpr,      /* The expression to code when the VDBE initializes */
    +-  int regDest,      /* Store the value in this register */
    +-  u8 reusable       /* True if this expression is reusable */
    ++  int regDest       /* Store the value in this register */
    + ){
    +   ExprList *p;
    +   assert( ConstFactorOk(pParse) );
    +   p = pParse->pConstExpr;
    ++  if( regDest<0 && p ){
    ++    struct ExprList_item *pItem;
    ++    int i;
    ++    for(pItem=p->a, i=p->nExpr; i>0; pItem++, i--){
    ++      if( pItem->reusable && sqlite3ExprCompare(0,pItem->pExpr,pExpr,-1)==0 ){
    ++        return pItem->u.iConstExprReg;
    ++      }
    ++    }
    ++  }
    +   pExpr = sqlite3ExprDup(pParse->db, pExpr, 0);
    +   p = sqlite3ExprListAppend(pParse, p, pExpr);
    +   if( p ){
    +      struct ExprList_item *pItem = &p->a[p->nExpr-1];
    ++     pItem->reusable = regDest<0;
    ++     if( regDest<0 ) regDest = ++pParse->nMem;
    +      pItem->u.iConstExprReg = regDest;
    +-     pItem->reusable = reusable;
    +   }
    +   pParse->pConstExpr = p;
    ++  return regDest;
    + }
    + 
    + /*
    +@@ -88247,19 +96885,8 @@ SQLITE_PRIVATE int sqlite3ExprCodeTemp(Parse *pParse, Expr *pExpr, int *pReg){
    +    && pExpr->op!=TK_REGISTER
    +    && sqlite3ExprIsConstantNotJoin(pExpr)
    +   ){
    +-    ExprList *p = pParse->pConstExpr;
    +-    int i;
    +     *pReg  = 0;
    +-    if( p ){
    +-      struct ExprList_item *pItem;
    +-      for(pItem=p->a, i=p->nExpr; i>0; pItem++, i--){
    +-        if( pItem->reusable && sqlite3ExprCompare(pItem->pExpr,pExpr,-1)==0 ){
    +-          return pItem->u.iConstExprReg;
    +-        }
    +-      }
    +-    }
    +-    r2 = ++pParse->nMem;
    +-    sqlite3ExprCodeAtInit(pParse, pExpr, r2, 1);
    ++    r2 = sqlite3ExprCodeAtInit(pParse, pExpr, -1);
    +   }else{
    +     int r1 = sqlite3GetTempReg(pParse);
    +     r2 = sqlite3ExprCodeTarget(pParse, pExpr, r1);
    +@@ -88286,13 +96913,25 @@ SQLITE_PRIVATE void sqlite3ExprCode(Parse *pParse, Expr *pExpr, int target){
    +     sqlite3VdbeAddOp2(pParse->pVdbe, OP_Copy, pExpr->iTable, target);
    +   }else{
    +     inReg = sqlite3ExprCodeTarget(pParse, pExpr, target);
    +-    assert( pParse->pVdbe || pParse->db->mallocFailed );
    ++    assert( pParse->pVdbe!=0 || pParse->db->mallocFailed );
    +     if( inReg!=target && pParse->pVdbe ){
    +       sqlite3VdbeAddOp2(pParse->pVdbe, OP_SCopy, inReg, target);
    +     }
    +   }
    + }
    + 
    ++/*
    ++** Make a transient copy of expression pExpr and then code it using
    ++** sqlite3ExprCode().  This routine works just like sqlite3ExprCode()
    ++** except that the input expression is guaranteed to be unchanged.
    ++*/
    ++SQLITE_PRIVATE void sqlite3ExprCodeCopy(Parse *pParse, Expr *pExpr, int target){
    ++  sqlite3 *db = pParse->db;
    ++  pExpr = sqlite3ExprDup(db, pExpr, 0);
    ++  if( !db->mallocFailed ) sqlite3ExprCode(pParse, pExpr, target);
    ++  sqlite3ExprDelete(db, pExpr);
    ++}
    ++
    + /*
    + ** Generate code that will evaluate expression pExpr and store the
    + ** results in register target.  The results are guaranteed to appear
    +@@ -88301,7 +96940,7 @@ SQLITE_PRIVATE void sqlite3ExprCode(Parse *pParse, Expr *pExpr, int target){
    + */
    + SQLITE_PRIVATE void sqlite3ExprCodeFactorable(Parse *pParse, Expr *pExpr, int target){
    +   if( pParse->okConstFactor && sqlite3ExprIsConstant(pExpr) ){
    +-    sqlite3ExprCodeAtInit(pParse, pExpr, target, 0);
    ++    sqlite3ExprCodeAtInit(pParse, pExpr, target);
    +   }else{
    +     sqlite3ExprCode(pParse, pExpr, target);
    +   }
    +@@ -88335,13 +96974,21 @@ SQLITE_PRIVATE void sqlite3ExprCodeAndCache(Parse *pParse, Expr *pExpr, int targ
    + ** Generate code that pushes the value of every element of the given
    + ** expression list into a sequence of registers beginning at target.
    + **
    +-** Return the number of elements evaluated.
    ++** Return the number of elements evaluated.  The number returned will
    ++** usually be pList->nExpr but might be reduced if SQLITE_ECEL_OMITREF
    ++** is defined.
    + **
    + ** The SQLITE_ECEL_DUP flag prevents the arguments from being
    + ** filled using OP_SCopy.  OP_Copy must be used instead.
    + **
    + ** The SQLITE_ECEL_FACTOR argument allows constant arguments to be
    + ** factored out into initialization code.
    ++**
    ++** The SQLITE_ECEL_REF flag means that expressions in the list with
    ++** ExprList.a[].u.x.iOrderByCol>0 have already been evaluated and stored
    ++** in registers at srcReg, and so the value can be copied from there.
    ++** If SQLITE_ECEL_OMITREF is also set, then the values with u.x.iOrderByCol>0
    ++** are simply omitted rather than being copied from srcReg.
    + */
    + SQLITE_PRIVATE int sqlite3ExprCodeExprList(
    +   Parse *pParse,     /* Parsing context */
    +@@ -88361,10 +97008,15 @@ SQLITE_PRIVATE int sqlite3ExprCodeExprList(
    +   if( !ConstFactorOk(pParse) ) flags &= ~SQLITE_ECEL_FACTOR;
    +   for(pItem=pList->a, i=0; i<n; i++, pItem++){
    +     Expr *pExpr = pItem->pExpr;
    +-    if( (flags & SQLITE_ECEL_REF)!=0 && (j = pList->a[i].u.x.iOrderByCol)>0 ){
    +-      sqlite3VdbeAddOp2(v, copyOp, j+srcReg-1, target+i);
    ++    if( (flags & SQLITE_ECEL_REF)!=0 && (j = pItem->u.x.iOrderByCol)>0 ){
    ++      if( flags & SQLITE_ECEL_OMITREF ){
    ++        i--;
    ++        n--;
    ++      }else{
    ++        sqlite3VdbeAddOp2(v, copyOp, j+srcReg-1, target+i);
    ++      }
    +     }else if( (flags & SQLITE_ECEL_FACTOR)!=0 && sqlite3ExprIsConstant(pExpr) ){
    +-      sqlite3ExprCodeAtInit(pParse, pExpr, target+i, 0);
    ++      sqlite3ExprCodeAtInit(pParse, pExpr, target+i);
    +     }else{
    +       int inReg = sqlite3ExprCodeTarget(pParse, pExpr, target+i);
    +       if( inReg!=target+i ){
    +@@ -88395,20 +97047,33 @@ SQLITE_PRIVATE int sqlite3ExprCodeExprList(
    + **
    + ** Code it as such, taking care to do the common subexpression
    + ** elimination of x.
    ++**
    ++** The xJumpIf parameter determines details:
    ++**
    ++**    NULL:                   Store the boolean result in reg[dest]
    ++**    sqlite3ExprIfTrue:      Jump to dest if true
    ++**    sqlite3ExprIfFalse:     Jump to dest if false
    ++**
    ++** The jumpIfNull parameter is ignored if xJumpIf is NULL.
    + */
    + static void exprCodeBetween(
    +   Parse *pParse,    /* Parsing and code generating context */
    +   Expr *pExpr,      /* The BETWEEN expression */
    +-  int dest,         /* Jump here if the jump is taken */
    +-  int jumpIfTrue,   /* Take the jump if the BETWEEN is true */
    ++  int dest,         /* Jump destination or storage location */
    ++  void (*xJump)(Parse*,Expr*,int,int), /* Action to take */
    +   int jumpIfNull    /* Take the jump if the BETWEEN is NULL */
    + ){
    +-  Expr exprAnd;     /* The AND operator in  x>=y AND x<=z  */
    ++ Expr exprAnd;     /* The AND operator in  x>=y AND x<=z  */
    +   Expr compLeft;    /* The  x>=y  term */
    +   Expr compRight;   /* The  x<=z  term */
    +   Expr exprX;       /* The  x  subexpression */
    +   int regFree1 = 0; /* Temporary use register */
    + 
    ++
    ++  memset(&compLeft, 0, sizeof(Expr));
    ++  memset(&compRight, 0, sizeof(Expr));
    ++  memset(&exprAnd, 0, sizeof(Expr));
    ++
    +   assert( !ExprHasProperty(pExpr, EP_xIsSelect) );
    +   exprX = *pExpr->pLeft;
    +   exprAnd.op = TK_AND;
    +@@ -88420,23 +97085,30 @@ static void exprCodeBetween(
    +   compRight.op = TK_LE;
    +   compRight.pLeft = &exprX;
    +   compRight.pRight = pExpr->x.pList->a[1].pExpr;
    +-  exprToRegister(&exprX, sqlite3ExprCodeTemp(pParse, &exprX, &regFree1));
    +-  if( jumpIfTrue ){
    +-    sqlite3ExprIfTrue(pParse, &exprAnd, dest, jumpIfNull);
    +-  }else{
    +-    sqlite3ExprIfFalse(pParse, &exprAnd, dest, jumpIfNull);
    ++  exprToRegister(&exprX, exprCodeVector(pParse, &exprX, &regFree1));
    ++  if( xJump ){
    ++    xJump(pParse, &exprAnd, dest, jumpIfNull);
    ++  }else{
    ++    /* Mark the expression is being from the ON or USING clause of a join
    ++    ** so that the sqlite3ExprCodeTarget() routine will not attempt to move
    ++    ** it into the Parse.pConstExpr list.  We should use a new bit for this,
    ++    ** for clarity, but we are out of bits in the Expr.flags field so we
    ++    ** have to reuse the EP_FromJoin bit.  Bummer. */
    ++    exprX.flags |= EP_FromJoin;
    ++    sqlite3ExprCodeTarget(pParse, &exprAnd, dest);
    +   }
    +   sqlite3ReleaseTempReg(pParse, regFree1);
    + 
    +   /* Ensure adequate test coverage */
    +-  testcase( jumpIfTrue==0 && jumpIfNull==0 && regFree1==0 );
    +-  testcase( jumpIfTrue==0 && jumpIfNull==0 && regFree1!=0 );
    +-  testcase( jumpIfTrue==0 && jumpIfNull!=0 && regFree1==0 );
    +-  testcase( jumpIfTrue==0 && jumpIfNull!=0 && regFree1!=0 );
    +-  testcase( jumpIfTrue!=0 && jumpIfNull==0 && regFree1==0 );
    +-  testcase( jumpIfTrue!=0 && jumpIfNull==0 && regFree1!=0 );
    +-  testcase( jumpIfTrue!=0 && jumpIfNull!=0 && regFree1==0 );
    +-  testcase( jumpIfTrue!=0 && jumpIfNull!=0 && regFree1!=0 );
    ++  testcase( xJump==sqlite3ExprIfTrue  && jumpIfNull==0 && regFree1==0 );
    ++  testcase( xJump==sqlite3ExprIfTrue  && jumpIfNull==0 && regFree1!=0 );
    ++  testcase( xJump==sqlite3ExprIfTrue  && jumpIfNull!=0 && regFree1==0 );
    ++  testcase( xJump==sqlite3ExprIfTrue  && jumpIfNull!=0 && regFree1!=0 );
    ++  testcase( xJump==sqlite3ExprIfFalse && jumpIfNull==0 && regFree1==0 );
    ++  testcase( xJump==sqlite3ExprIfFalse && jumpIfNull==0 && regFree1!=0 );
    ++  testcase( xJump==sqlite3ExprIfFalse && jumpIfNull!=0 && regFree1==0 );
    ++  testcase( xJump==sqlite3ExprIfFalse && jumpIfNull!=0 && regFree1!=0 );
    ++  testcase( xJump==0 );
    + }
    + 
    + /*
    +@@ -88488,12 +97160,20 @@ SQLITE_PRIVATE void sqlite3ExprIfTrue(Parse *pParse, Expr *pExpr, int dest, int
    +       sqlite3ExprIfFalse(pParse, pExpr->pLeft, dest, jumpIfNull);
    +       break;
    +     }
    ++    case TK_IS:
    ++    case TK_ISNOT:
    ++      testcase( op==TK_IS );
    ++      testcase( op==TK_ISNOT );
    ++      op = (op==TK_IS) ? TK_EQ : TK_NE;
    ++      jumpIfNull = SQLITE_NULLEQ;
    ++      /* Fall thru */
    +     case TK_LT:
    +     case TK_LE:
    +     case TK_GT:
    +     case TK_GE:
    +     case TK_NE:
    +     case TK_EQ: {
    ++      if( sqlite3ExprIsVector(pExpr->pLeft) ) goto default_expr;
    +       testcase( jumpIfNull==0 );
    +       r1 = sqlite3ExprCodeTemp(pParse, pExpr->pLeft, &regFree1);
    +       r2 = sqlite3ExprCodeTemp(pParse, pExpr->pRight, &regFree2);
    +@@ -88503,23 +97183,12 @@ SQLITE_PRIVATE void sqlite3ExprIfTrue(Parse *pParse, Expr *pExpr, int dest, int
    +       assert(TK_LE==OP_Le); testcase(op==OP_Le); VdbeCoverageIf(v,op==OP_Le);
    +       assert(TK_GT==OP_Gt); testcase(op==OP_Gt); VdbeCoverageIf(v,op==OP_Gt);
    +       assert(TK_GE==OP_Ge); testcase(op==OP_Ge); VdbeCoverageIf(v,op==OP_Ge);
    +-      assert(TK_EQ==OP_Eq); testcase(op==OP_Eq); VdbeCoverageIf(v,op==OP_Eq);
    +-      assert(TK_NE==OP_Ne); testcase(op==OP_Ne); VdbeCoverageIf(v,op==OP_Ne);
    +-      testcase( regFree1==0 );
    +-      testcase( regFree2==0 );
    +-      break;
    +-    }
    +-    case TK_IS:
    +-    case TK_ISNOT: {
    +-      testcase( op==TK_IS );
    +-      testcase( op==TK_ISNOT );
    +-      r1 = sqlite3ExprCodeTemp(pParse, pExpr->pLeft, &regFree1);
    +-      r2 = sqlite3ExprCodeTemp(pParse, pExpr->pRight, &regFree2);
    +-      op = (op==TK_IS) ? TK_EQ : TK_NE;
    +-      codeCompare(pParse, pExpr->pLeft, pExpr->pRight, op,
    +-                  r1, r2, dest, SQLITE_NULLEQ);
    +-      VdbeCoverageIf(v, op==TK_EQ);
    +-      VdbeCoverageIf(v, op==TK_NE);
    ++      assert(TK_EQ==OP_Eq); testcase(op==OP_Eq);
    ++      VdbeCoverageIf(v, op==OP_Eq && jumpIfNull==SQLITE_NULLEQ);
    ++      VdbeCoverageIf(v, op==OP_Eq && jumpIfNull!=SQLITE_NULLEQ);
    ++      assert(TK_NE==OP_Ne); testcase(op==OP_Ne);
    ++      VdbeCoverageIf(v, op==OP_Ne && jumpIfNull==SQLITE_NULLEQ);
    ++      VdbeCoverageIf(v, op==OP_Ne && jumpIfNull!=SQLITE_NULLEQ);
    +       testcase( regFree1==0 );
    +       testcase( regFree2==0 );
    +       break;
    +@@ -88537,7 +97206,7 @@ SQLITE_PRIVATE void sqlite3ExprIfTrue(Parse *pParse, Expr *pExpr, int dest, int
    +     }
    +     case TK_BETWEEN: {
    +       testcase( jumpIfNull==0 );
    +-      exprCodeBetween(pParse, pExpr, dest, 1, jumpIfNull);
    ++      exprCodeBetween(pParse, pExpr, dest, sqlite3ExprIfTrue, jumpIfNull);
    +       break;
    +     }
    + #ifndef SQLITE_OMIT_SUBQUERY
    +@@ -88551,6 +97220,7 @@ SQLITE_PRIVATE void sqlite3ExprIfTrue(Parse *pParse, Expr *pExpr, int dest, int
    +     }
    + #endif
    +     default: {
    ++    default_expr:
    +       if( exprAlwaysTrue(pExpr) ){
    +         sqlite3VdbeGoto(v, dest);
    +       }else if( exprAlwaysFalse(pExpr) ){
    +@@ -88644,12 +97314,20 @@ SQLITE_PRIVATE void sqlite3ExprIfFalse(Parse *pParse, Expr *pExpr, int dest, int
    +       sqlite3ExprIfTrue(pParse, pExpr->pLeft, dest, jumpIfNull);
    +       break;
    +     }
    ++    case TK_IS:
    ++    case TK_ISNOT:
    ++      testcase( pExpr->op==TK_IS );
    ++      testcase( pExpr->op==TK_ISNOT );
    ++      op = (pExpr->op==TK_IS) ? TK_NE : TK_EQ;
    ++      jumpIfNull = SQLITE_NULLEQ;
    ++      /* Fall thru */
    +     case TK_LT:
    +     case TK_LE:
    +     case TK_GT:
    +     case TK_GE:
    +     case TK_NE:
    +     case TK_EQ: {
    ++      if( sqlite3ExprIsVector(pExpr->pLeft) ) goto default_expr;
    +       testcase( jumpIfNull==0 );
    +       r1 = sqlite3ExprCodeTemp(pParse, pExpr->pLeft, &regFree1);
    +       r2 = sqlite3ExprCodeTemp(pParse, pExpr->pRight, &regFree2);
    +@@ -88659,23 +97337,12 @@ SQLITE_PRIVATE void sqlite3ExprIfFalse(Parse *pParse, Expr *pExpr, int dest, int
    +       assert(TK_LE==OP_Le); testcase(op==OP_Le); VdbeCoverageIf(v,op==OP_Le);
    +       assert(TK_GT==OP_Gt); testcase(op==OP_Gt); VdbeCoverageIf(v,op==OP_Gt);
    +       assert(TK_GE==OP_Ge); testcase(op==OP_Ge); VdbeCoverageIf(v,op==OP_Ge);
    +-      assert(TK_EQ==OP_Eq); testcase(op==OP_Eq); VdbeCoverageIf(v,op==OP_Eq);
    +-      assert(TK_NE==OP_Ne); testcase(op==OP_Ne); VdbeCoverageIf(v,op==OP_Ne);
    +-      testcase( regFree1==0 );
    +-      testcase( regFree2==0 );
    +-      break;
    +-    }
    +-    case TK_IS:
    +-    case TK_ISNOT: {
    +-      testcase( pExpr->op==TK_IS );
    +-      testcase( pExpr->op==TK_ISNOT );
    +-      r1 = sqlite3ExprCodeTemp(pParse, pExpr->pLeft, &regFree1);
    +-      r2 = sqlite3ExprCodeTemp(pParse, pExpr->pRight, &regFree2);
    +-      op = (pExpr->op==TK_IS) ? TK_NE : TK_EQ;
    +-      codeCompare(pParse, pExpr->pLeft, pExpr->pRight, op,
    +-                  r1, r2, dest, SQLITE_NULLEQ);
    +-      VdbeCoverageIf(v, op==TK_EQ);
    +-      VdbeCoverageIf(v, op==TK_NE);
    ++      assert(TK_EQ==OP_Eq); testcase(op==OP_Eq);
    ++      VdbeCoverageIf(v, op==OP_Eq && jumpIfNull!=SQLITE_NULLEQ);
    ++      VdbeCoverageIf(v, op==OP_Eq && jumpIfNull==SQLITE_NULLEQ);
    ++      assert(TK_NE==OP_Ne); testcase(op==OP_Ne);
    ++      VdbeCoverageIf(v, op==OP_Ne && jumpIfNull!=SQLITE_NULLEQ);
    ++      VdbeCoverageIf(v, op==OP_Ne && jumpIfNull==SQLITE_NULLEQ);
    +       testcase( regFree1==0 );
    +       testcase( regFree2==0 );
    +       break;
    +@@ -88691,7 +97358,7 @@ SQLITE_PRIVATE void sqlite3ExprIfFalse(Parse *pParse, Expr *pExpr, int dest, int
    +     }
    +     case TK_BETWEEN: {
    +       testcase( jumpIfNull==0 );
    +-      exprCodeBetween(pParse, pExpr, dest, 0, jumpIfNull);
    ++      exprCodeBetween(pParse, pExpr, dest, sqlite3ExprIfFalse, jumpIfNull);
    +       break;
    +     }
    + #ifndef SQLITE_OMIT_SUBQUERY
    +@@ -88707,6 +97374,7 @@ SQLITE_PRIVATE void sqlite3ExprIfFalse(Parse *pParse, Expr *pExpr, int dest, int
    +     }
    + #endif
    +     default: {
    ++    default_expr: 
    +       if( exprAlwaysFalse(pExpr) ){
    +         sqlite3VdbeGoto(v, dest);
    +       }else if( exprAlwaysTrue(pExpr) ){
    +@@ -88739,6 +97407,41 @@ SQLITE_PRIVATE void sqlite3ExprIfFalseDup(Parse *pParse, Expr *pExpr, int dest,i
    +   sqlite3ExprDelete(db, pCopy);
    + }
    + 
    ++/*
    ++** Expression pVar is guaranteed to be an SQL variable. pExpr may be any
    ++** type of expression.
    ++**
    ++** If pExpr is a simple SQL value - an integer, real, string, blob
    ++** or NULL value - then the VDBE currently being prepared is configured
    ++** to re-prepare each time a new value is bound to variable pVar.
    ++**
    ++** Additionally, if pExpr is a simple SQL value and the value is the
    ++** same as that currently bound to variable pVar, non-zero is returned.
    ++** Otherwise, if the values are not the same or if pExpr is not a simple
    ++** SQL value, zero is returned.
    ++*/
    ++static int exprCompareVariable(Parse *pParse, Expr *pVar, Expr *pExpr){
    ++  int res = 0;
    ++  int iVar;
    ++  sqlite3_value *pL, *pR = 0;
    ++  
    ++  sqlite3ValueFromExpr(pParse->db, pExpr, SQLITE_UTF8, SQLITE_AFF_BLOB, &pR);
    ++  if( pR ){
    ++    iVar = pVar->iColumn;
    ++    sqlite3VdbeSetVarmask(pParse->pVdbe, iVar);
    ++    pL = sqlite3VdbeGetBoundValue(pParse->pReprepare, iVar, SQLITE_AFF_BLOB);
    ++    if( pL ){
    ++      if( sqlite3_value_type(pL)==SQLITE_TEXT ){
    ++        sqlite3_value_text(pL); /* Make sure the encoding is UTF-8 */
    ++      }
    ++      res =  0==sqlite3MemCompare(pL, pR, 0);
    ++    }
    ++    sqlite3ValueFree(pR);
    ++    sqlite3ValueFree(pL);
    ++  }
    ++
    ++  return res;
    ++}
    + 
    + /*
    + ** Do a deep comparison of two expression trees.  Return 0 if the two
    +@@ -88761,12 +97464,22 @@ SQLITE_PRIVATE void sqlite3ExprIfFalseDup(Parse *pParse, Expr *pExpr, int dest,i
    + ** this routine is used, it does not hurt to get an extra 2 - that
    + ** just might result in some slightly slower code.  But returning
    + ** an incorrect 0 or 1 could lead to a malfunction.
    ++**
    ++** If pParse is not NULL then TK_VARIABLE terms in pA with bindings in
    ++** pParse->pReprepare can be matched against literals in pB.  The 
    ++** pParse->pVdbe->expmask bitmask is updated for each variable referenced.
    ++** If pParse is NULL (the normal case) then any TK_VARIABLE term in 
    ++** Argument pParse should normally be NULL. If it is not NULL and pA or
    ++** pB causes a return value of 2.
    + */
    +-SQLITE_PRIVATE int sqlite3ExprCompare(Expr *pA, Expr *pB, int iTab){
    ++SQLITE_PRIVATE int sqlite3ExprCompare(Parse *pParse, Expr *pA, Expr *pB, int iTab){
    +   u32 combinedFlags;
    +   if( pA==0 || pB==0 ){
    +     return pB==pA ? 0 : 2;
    +   }
    ++  if( pParse && pA->op==TK_VARIABLE && exprCompareVariable(pParse, pA, pB) ){
    ++    return 0;
    ++  }
    +   combinedFlags = pA->flags | pB->flags;
    +   if( combinedFlags & EP_IntValue ){
    +     if( (pA->flags&pB->flags&EP_IntValue)!=0 && pA->u.iValue==pB->u.iValue ){
    +@@ -88775,15 +97488,15 @@ SQLITE_PRIVATE int sqlite3ExprCompare(Expr *pA, Expr *pB, int iTab){
    +     return 2;
    +   }
    +   if( pA->op!=pB->op ){
    +-    if( pA->op==TK_COLLATE && sqlite3ExprCompare(pA->pLeft, pB, iTab)<2 ){
    ++    if( pA->op==TK_COLLATE && sqlite3ExprCompare(pParse, pA->pLeft,pB,iTab)<2 ){
    +       return 1;
    +     }
    +-    if( pB->op==TK_COLLATE && sqlite3ExprCompare(pA, pB->pLeft, iTab)<2 ){
    ++    if( pB->op==TK_COLLATE && sqlite3ExprCompare(pParse, pA,pB->pLeft,iTab)<2 ){
    +       return 1;
    +     }
    +     return 2;
    +   }
    +-  if( pA->op!=TK_COLUMN && ALWAYS(pA->op!=TK_AGG_COLUMN) && pA->u.zToken ){
    ++  if( pA->op!=TK_COLUMN && pA->op!=TK_AGG_COLUMN && pA->u.zToken ){
    +     if( pA->op==TK_FUNCTION ){
    +       if( sqlite3StrICmp(pA->u.zToken,pB->u.zToken)!=0 ) return 2;
    +     }else if( strcmp(pA->u.zToken,pB->u.zToken)!=0 ){
    +@@ -88793,8 +97506,8 @@ SQLITE_PRIVATE int sqlite3ExprCompare(Expr *pA, Expr *pB, int iTab){
    +   if( (pA->flags & EP_Distinct)!=(pB->flags & EP_Distinct) ) return 2;
    +   if( ALWAYS((combinedFlags & EP_TokenOnly)==0) ){
    +     if( combinedFlags & EP_xIsSelect ) return 2;
    +-    if( sqlite3ExprCompare(pA->pLeft, pB->pLeft, iTab) ) return 2;
    +-    if( sqlite3ExprCompare(pA->pRight, pB->pRight, iTab) ) return 2;
    ++    if( sqlite3ExprCompare(pParse, pA->pLeft, pB->pLeft, iTab) ) return 2;
    ++    if( sqlite3ExprCompare(pParse, pA->pRight, pB->pRight, iTab) ) return 2;
    +     if( sqlite3ExprListCompare(pA->x.pList, pB->x.pList, iTab) ) return 2;
    +     if( ALWAYS((combinedFlags & EP_Reduced)==0) && pA->op!=TK_STRING ){
    +       if( pA->iColumn!=pB->iColumn ) return 2;
    +@@ -88829,11 +97542,22 @@ SQLITE_PRIVATE int sqlite3ExprListCompare(ExprList *pA, ExprList *pB, int iTab){
    +     Expr *pExprA = pA->a[i].pExpr;
    +     Expr *pExprB = pB->a[i].pExpr;
    +     if( pA->a[i].sortOrder!=pB->a[i].sortOrder ) return 1;
    +-    if( sqlite3ExprCompare(pExprA, pExprB, iTab) ) return 1;
    ++    if( sqlite3ExprCompare(0, pExprA, pExprB, iTab) ) return 1;
    +   }
    +   return 0;
    + }
    + 
    ++/*
    ++** Like sqlite3ExprCompare() except COLLATE operators at the top-level
    ++** are ignored.
    ++*/
    ++SQLITE_PRIVATE int sqlite3ExprCompareSkip(Expr *pA, Expr *pB, int iTab){
    ++  return sqlite3ExprCompare(0,
    ++             sqlite3ExprSkipCollate(pA),
    ++             sqlite3ExprSkipCollate(pB),
    ++             iTab);
    ++}
    ++
    + /*
    + ** Return true if we can prove the pE2 will always be true if pE1 is
    + ** true.  Return false if we cannot complete the proof or if pE2 might
    +@@ -88850,29 +97574,88 @@ SQLITE_PRIVATE int sqlite3ExprListCompare(ExprList *pA, ExprList *pB, int iTab){
    + ** When comparing TK_COLUMN nodes between pE1 and pE2, if pE2 has
    + ** Expr.iTable<0 then assume a table number given by iTab.
    + **
    ++** If pParse is not NULL, then the values of bound variables in pE1 are 
    ++** compared against literal values in pE2 and pParse->pVdbe->expmask is
    ++** modified to record which bound variables are referenced.  If pParse 
    ++** is NULL, then false will be returned if pE1 contains any bound variables.
    ++**
    + ** When in doubt, return false.  Returning true might give a performance
    + ** improvement.  Returning false might cause a performance reduction, but
    + ** it will always give the correct answer and is hence always safe.
    + */
    +-SQLITE_PRIVATE int sqlite3ExprImpliesExpr(Expr *pE1, Expr *pE2, int iTab){
    +-  if( sqlite3ExprCompare(pE1, pE2, iTab)==0 ){
    ++SQLITE_PRIVATE int sqlite3ExprImpliesExpr(Parse *pParse, Expr *pE1, Expr *pE2, int iTab){
    ++  if( sqlite3ExprCompare(pParse, pE1, pE2, iTab)==0 ){
    +     return 1;
    +   }
    +   if( pE2->op==TK_OR
    +-   && (sqlite3ExprImpliesExpr(pE1, pE2->pLeft, iTab)
    +-             || sqlite3ExprImpliesExpr(pE1, pE2->pRight, iTab) )
    ++   && (sqlite3ExprImpliesExpr(pParse, pE1, pE2->pLeft, iTab)
    ++             || sqlite3ExprImpliesExpr(pParse, pE1, pE2->pRight, iTab) )
    +   ){
    +     return 1;
    +   }
    +-  if( pE2->op==TK_NOTNULL
    +-   && sqlite3ExprCompare(pE1->pLeft, pE2->pLeft, iTab)==0
    +-   && (pE1->op!=TK_ISNULL && pE1->op!=TK_IS)
    +-  ){
    +-    return 1;
    ++  if( pE2->op==TK_NOTNULL && pE1->op!=TK_ISNULL && pE1->op!=TK_IS ){
    ++    Expr *pX = sqlite3ExprSkipCollate(pE1->pLeft);
    ++    testcase( pX!=pE1->pLeft );
    ++    if( sqlite3ExprCompare(pParse, pX, pE2->pLeft, iTab)==0 ) return 1;
    +   }
    +   return 0;
    + }
    + 
    ++/*
    ++** An instance of the following structure is used by the tree walker
    ++** to determine if an expression can be evaluated by reference to the
    ++** index only, without having to do a search for the corresponding
    ++** table entry.  The IdxCover.pIdx field is the index.  IdxCover.iCur
    ++** is the cursor for the table.
    ++*/
    ++struct IdxCover {
    ++  Index *pIdx;     /* The index to be tested for coverage */
    ++  int iCur;        /* Cursor number for the table corresponding to the index */
    ++};
    ++
    ++/*
    ++** Check to see if there are references to columns in table 
    ++** pWalker->u.pIdxCover->iCur can be satisfied using the index
    ++** pWalker->u.pIdxCover->pIdx.
    ++*/
    ++static int exprIdxCover(Walker *pWalker, Expr *pExpr){
    ++  if( pExpr->op==TK_COLUMN
    ++   && pExpr->iTable==pWalker->u.pIdxCover->iCur
    ++   && sqlite3ColumnOfIndex(pWalker->u.pIdxCover->pIdx, pExpr->iColumn)<0
    ++  ){
    ++    pWalker->eCode = 1;
    ++    return WRC_Abort;
    ++  }
    ++  return WRC_Continue;
    ++}
    ++
    ++/*
    ++** Determine if an index pIdx on table with cursor iCur contains will
    ++** the expression pExpr.  Return true if the index does cover the
    ++** expression and false if the pExpr expression references table columns
    ++** that are not found in the index pIdx.
    ++**
    ++** An index covering an expression means that the expression can be
    ++** evaluated using only the index and without having to lookup the
    ++** corresponding table entry.
    ++*/
    ++SQLITE_PRIVATE int sqlite3ExprCoveredByIndex(
    ++  Expr *pExpr,        /* The index to be tested */
    ++  int iCur,           /* The cursor number for the corresponding table */
    ++  Index *pIdx         /* The index that might be used for coverage */
    ++){
    ++  Walker w;
    ++  struct IdxCover xcov;
    ++  memset(&w, 0, sizeof(w));
    ++  xcov.iCur = iCur;
    ++  xcov.pIdx = pIdx;
    ++  w.xExprCallback = exprIdxCover;
    ++  w.u.pIdxCover = &xcov;
    ++  sqlite3WalkExpr(&w, pExpr);
    ++  return !w.eCode;
    ++}
    ++
    ++
    + /*
    + ** An instance of the following structure is used by the tree walker
    + ** to count references to table columns in the arguments of an 
    +@@ -88921,8 +97704,8 @@ SQLITE_PRIVATE int sqlite3FunctionUsesThisSrc(Expr *pExpr, SrcList *pSrcList){
    +   Walker w;
    +   struct SrcCount cnt;
    +   assert( pExpr->op==TK_AGG_FUNCTION );
    +-  memset(&w, 0, sizeof(w));
    +   w.xExprCallback = exprSrcCount;
    ++  w.xSelectCallback = 0;
    +   w.u.pSrcCount = &cnt;
    +   cnt.pSrc = pSrcList;
    +   cnt.nThis = 0;
    +@@ -89054,7 +97837,7 @@ static int analyzeAggregate(Walker *pWalker, Expr *pExpr){
    +         */
    +         struct AggInfo_func *pItem = pAggInfo->aFunc;
    +         for(i=0; i<pAggInfo->nFunc; i++, pItem++){
    +-          if( sqlite3ExprCompare(pItem->pExpr, pExpr, -1)==0 ){
    ++          if( sqlite3ExprCompare(0, pItem->pExpr, pExpr, -1)==0 ){
    +             break;
    +           }
    +         }
    +@@ -89070,7 +97853,7 @@ static int analyzeAggregate(Walker *pWalker, Expr *pExpr){
    +             pItem->iMem = ++pParse->nMem;
    +             assert( !ExprHasProperty(pExpr, EP_IntValue) );
    +             pItem->pFunc = sqlite3FindFunction(pParse->db,
    +-                   pExpr->u.zToken, sqlite3Strlen30(pExpr->u.zToken),
    ++                   pExpr->u.zToken, 
    +                    pExpr->x.pList ? pExpr->x.pList->nExpr : 0, enc, 0);
    +             if( pExpr->flags & EP_Distinct ){
    +               pItem->iDistinct = pParse->nTab++;
    +@@ -89094,10 +97877,14 @@ static int analyzeAggregate(Walker *pWalker, Expr *pExpr){
    +   return WRC_Continue;
    + }
    + static int analyzeAggregatesInSelect(Walker *pWalker, Select *pSelect){
    +-  UNUSED_PARAMETER(pWalker);
    +   UNUSED_PARAMETER(pSelect);
    ++  pWalker->walkerDepth++;
    +   return WRC_Continue;
    + }
    ++static void analyzeAggregatesInSelectEnd(Walker *pWalker, Select *pSelect){
    ++  UNUSED_PARAMETER(pSelect);
    ++  pWalker->walkerDepth--;
    ++}
    + 
    + /*
    + ** Analyze the pExpr expression looking for aggregate functions and
    +@@ -89110,9 +97897,10 @@ static int analyzeAggregatesInSelect(Walker *pWalker, Select *pSelect){
    + */
    + SQLITE_PRIVATE void sqlite3ExprAnalyzeAggregates(NameContext *pNC, Expr *pExpr){
    +   Walker w;
    +-  memset(&w, 0, sizeof(w));
    +   w.xExprCallback = analyzeAggregate;
    +   w.xSelectCallback = analyzeAggregatesInSelect;
    ++  w.xSelectCallback2 = analyzeAggregatesInSelectEnd;
    ++  w.walkerDepth = 0;
    +   w.u.pNC = pNC;
    +   assert( pNC->pSrcList!=0 );
    +   sqlite3WalkExpr(&w, pExpr);
    +@@ -89156,7 +97944,7 @@ SQLITE_PRIVATE void sqlite3ReleaseTempReg(Parse *pParse, int iReg){
    +   if( iReg && pParse->nTempReg<ArraySize(pParse->aTempReg) ){
    +     int i;
    +     struct yColCache *p;
    +-    for(i=0, p=pParse->aColCache; i<SQLITE_N_COLCACHE; i++, p++){
    ++    for(i=0, p=pParse->aColCache; i<pParse->nColCache; i++, p++){
    +       if( p->iReg==iReg ){
    +         p->tempReg = 1;
    +         return;
    +@@ -89167,10 +97955,11 @@ SQLITE_PRIVATE void sqlite3ReleaseTempReg(Parse *pParse, int iReg){
    + }
    + 
    + /*
    +-** Allocate or deallocate a block of nReg consecutive registers
    ++** Allocate or deallocate a block of nReg consecutive registers.
    + */
    + SQLITE_PRIVATE int sqlite3GetTempRange(Parse *pParse, int nReg){
    +   int i, n;
    ++  if( nReg==1 ) return sqlite3GetTempReg(pParse);
    +   i = pParse->iRangeReg;
    +   n = pParse->nRangeReg;
    +   if( nReg<=n ){
    +@@ -89184,6 +97973,10 @@ SQLITE_PRIVATE int sqlite3GetTempRange(Parse *pParse, int nReg){
    +   return i;
    + }
    + SQLITE_PRIVATE void sqlite3ReleaseTempRange(Parse *pParse, int iReg, int nReg){
    ++  if( nReg==1 ){
    ++    sqlite3ReleaseTempReg(pParse, iReg);
    ++    return;
    ++  }
    +   sqlite3ExprCacheRemove(pParse, iReg, nReg);
    +   if( nReg>pParse->nRangeReg ){
    +     pParse->nRangeReg = nReg;
    +@@ -89199,6 +97992,29 @@ SQLITE_PRIVATE void sqlite3ClearTempRegCache(Parse *pParse){
    +   pParse->nRangeReg = 0;
    + }
    + 
    ++/*
    ++** Validate that no temporary register falls within the range of
    ++** iFirst..iLast, inclusive.  This routine is only call from within assert()
    ++** statements.
    ++*/
    ++#ifdef SQLITE_DEBUG
    ++SQLITE_PRIVATE int sqlite3NoTempsInRange(Parse *pParse, int iFirst, int iLast){
    ++  int i;
    ++  if( pParse->nRangeReg>0
    ++   && pParse->iRangeReg+pParse->nRangeReg > iFirst
    ++   && pParse->iRangeReg <= iLast
    ++  ){
    ++     return 0;
    ++  }
    ++  for(i=0; i<pParse->nTempReg; i++){
    ++    if( pParse->aTempReg[i]>=iFirst && pParse->aTempReg[i]<=iLast ){
    ++      return 0;
    ++    }
    ++  }
    ++  return 1;
    ++}
    ++#endif /* SQLITE_DEBUG */
    ++
    + /************** End of expr.c ************************************************/
    + /************** Begin file alter.c *******************************************/
    + /*
    +@@ -89432,7 +98248,7 @@ static void renameTriggerFunc(
    + ** Register built-in functions used to help implement ALTER TABLE
    + */
    + SQLITE_PRIVATE void sqlite3AlterFunctions(void){
    +-  static SQLITE_WSD FuncDef aAlterTableFuncs[] = {
    ++  static FuncDef aAlterTableFuncs[] = {
    +     FUNCTION(sqlite_rename_table,   2, 0, 0, renameTableFunc),
    + #ifndef SQLITE_OMIT_TRIGGER
    +     FUNCTION(sqlite_rename_trigger, 2, 0, 0, renameTriggerFunc),
    +@@ -89441,13 +98257,7 @@ SQLITE_PRIVATE void sqlite3AlterFunctions(void){
    +     FUNCTION(sqlite_rename_parent,  3, 0, 0, renameParentFunc),
    + #endif
    +   };
    +-  int i;
    +-  FuncDefHash *pHash = &GLOBAL(FuncDefHash, sqlite3GlobalFunctions);
    +-  FuncDef *aFunc = (FuncDef*)&GLOBAL(FuncDef, aAlterTableFuncs);
    +-
    +-  for(i=0; i<ArraySize(aAlterTableFuncs); i++){
    +-    sqlite3FuncDefInsert(pHash, &aFunc[i]);
    +-  }
    ++  sqlite3InsertBuiltinFuncs(aAlterTableFuncs, ArraySize(aAlterTableFuncs));
    + }
    + 
    + /*
    +@@ -89584,7 +98394,7 @@ static void reloadTableSchema(Parse *pParse, Table *pTab, const char *zName){
    + ** Or, if zName is not a system table, zero is returned.
    + */
    + static int isSystemTable(Parse *pParse, const char *zName){
    +-  if( sqlite3Strlen30(zName)>6 && 0==sqlite3StrNICmp(zName, "sqlite_", 7) ){
    ++  if( 0==sqlite3StrNICmp(zName, "sqlite_", 7) ){
    +     sqlite3ErrorMsg(pParse, "table %s may not be altered", zName);
    +     return 1;
    +   }
    +@@ -89612,9 +98422,9 @@ SQLITE_PRIVATE void sqlite3AlterRenameTable(
    +   char *zWhere = 0;         /* Where clause to locate temp triggers */
    + #endif
    +   VTable *pVTab = 0;        /* Non-zero if this is a v-tab with an xRename() */
    +-  int savedDbFlags;         /* Saved value of db->flags */
    ++  u32 savedDbFlags;         /* Saved value of db->mDbFlags */
    + 
    +-  savedDbFlags = db->flags;  
    ++  savedDbFlags = db->mDbFlags;  
    +   if( NEVER(db->mallocFailed) ) goto exit_rename_table;
    +   assert( pSrc->nSrc==1 );
    +   assert( sqlite3BtreeHoldsAllMutexes(pParse->db) );
    +@@ -89622,8 +98432,8 @@ SQLITE_PRIVATE void sqlite3AlterRenameTable(
    +   pTab = sqlite3LocateTableItem(pParse, 0, &pSrc->a[0]);
    +   if( !pTab ) goto exit_rename_table;
    +   iDb = sqlite3SchemaToIndex(pParse->db, pTab->pSchema);
    +-  zDb = db->aDb[iDb].zName;
    +-  db->flags |= SQLITE_PreferBuiltin;
    ++  zDb = db->aDb[iDb].zDbSName;
    ++  db->mDbFlags |= DBFLAG_PreferBuiltin;
    + 
    +   /* Get a NULL terminated version of the new table name. */
    +   zName = sqlite3NameFromToken(db, pName);
    +@@ -89713,7 +98523,7 @@ SQLITE_PRIVATE void sqlite3AlterRenameTable(
    +       sqlite3NestedParse(pParse, 
    +           "UPDATE \"%w\".%s SET "
    +               "sql = sqlite_rename_parent(sql, %Q, %Q) "
    +-              "WHERE %s;", zDb, SCHEMA_TABLE(iDb), zTabName, zName, zWhere);
    ++              "WHERE %s;", zDb, MASTER_NAME, zTabName, zName, zWhere);
    +       sqlite3DbFree(db, zWhere);
    +     }
    +   }
    +@@ -89737,7 +98547,7 @@ SQLITE_PRIVATE void sqlite3AlterRenameTable(
    +             "ELSE name END "
    +       "WHERE tbl_name=%Q COLLATE nocase AND "
    +           "(type='table' OR type='index' OR type='trigger');", 
    +-      zDb, SCHEMA_TABLE(iDb), zName, zName, zName, 
    ++      zDb, MASTER_NAME, zName, zName, zName, 
    + #ifndef SQLITE_OMIT_TRIGGER
    +       zName,
    + #endif
    +@@ -89788,34 +98598,7 @@ SQLITE_PRIVATE void sqlite3AlterRenameTable(
    + exit_rename_table:
    +   sqlite3SrcListDelete(db, pSrc);
    +   sqlite3DbFree(db, zName);
    +-  db->flags = savedDbFlags;
    +-}
    +-
    +-
    +-/*
    +-** Generate code to make sure the file format number is at least minFormat.
    +-** The generated code will increase the file format number if necessary.
    +-*/
    +-SQLITE_PRIVATE void sqlite3MinimumFileFormat(Parse *pParse, int iDb, int minFormat){
    +-  Vdbe *v;
    +-  v = sqlite3GetVdbe(pParse);
    +-  /* The VDBE should have been allocated before this routine is called.
    +-  ** If that allocation failed, we would have quit before reaching this
    +-  ** point */
    +-  if( ALWAYS(v) ){
    +-    int r1 = sqlite3GetTempReg(pParse);
    +-    int r2 = sqlite3GetTempReg(pParse);
    +-    int addr1;
    +-    sqlite3VdbeAddOp3(v, OP_ReadCookie, iDb, r1, BTREE_FILE_FORMAT);
    +-    sqlite3VdbeUsesBtree(v, iDb);
    +-    sqlite3VdbeAddOp2(v, OP_Integer, minFormat, r2);
    +-    addr1 = sqlite3VdbeAddOp3(v, OP_Ge, r2, 0, r1);
    +-    sqlite3VdbeChangeP5(v, SQLITE_NOTNULL); VdbeCoverage(v);
    +-    sqlite3VdbeAddOp3(v, OP_SetCookie, iDb, BTREE_FILE_FORMAT, r2);
    +-    sqlite3VdbeJumpHere(v, addr1);
    +-    sqlite3ReleaseTempReg(pParse, r1);
    +-    sqlite3ReleaseTempReg(pParse, r2);
    +-  }
    ++  db->mDbFlags = savedDbFlags;
    + }
    + 
    + /*
    +@@ -89836,15 +98619,18 @@ SQLITE_PRIVATE void sqlite3AlterFinishAddColumn(Parse *pParse, Token *pColDef){
    +   Column *pCol;             /* The new column */
    +   Expr *pDflt;              /* Default value for the new column */
    +   sqlite3 *db;              /* The database connection; */
    ++  Vdbe *v = pParse->pVdbe;  /* The prepared statement under construction */
    ++  int r1;                   /* Temporary registers */
    + 
    +   db = pParse->db;
    +   if( pParse->nErr || db->mallocFailed ) return;
    ++  assert( v!=0 );
    +   pNew = pParse->pNewTable;
    +   assert( pNew );
    + 
    +   assert( sqlite3BtreeHoldsAllMutexes(db) );
    +   iDb = sqlite3SchemaToIndex(db, pNew->pSchema);
    +-  zDb = db->aDb[iDb].zName;
    ++  zDb = db->aDb[iDb].zDbSName;
    +   zTab = &pNew->zName[16];  /* Skip the "sqlite_altertab_" prefix on the name */
    +   pCol = &pNew->aCol[pNew->nCol-1];
    +   pDflt = pCol->pDflt;
    +@@ -89862,7 +98648,8 @@ SQLITE_PRIVATE void sqlite3AlterFinishAddColumn(Parse *pParse, Token *pColDef){
    +   ** literal NULL, then set pDflt to 0. This simplifies checking
    +   ** for an SQL NULL default below.
    +   */
    +-  if( pDflt && pDflt->op==TK_NULL ){
    ++  assert( pDflt==0 || pDflt->op==TK_SPAN );
    ++  if( pDflt && pDflt->pLeft->op==TK_NULL ){
    +     pDflt = 0;
    +   }
    + 
    +@@ -89898,7 +98685,7 @@ SQLITE_PRIVATE void sqlite3AlterFinishAddColumn(Parse *pParse, Token *pColDef){
    +     rc = sqlite3ValueFromExpr(db, pDflt, SQLITE_UTF8, SQLITE_AFF_BLOB, &pVal);
    +     assert( rc==SQLITE_OK || rc==SQLITE_NOMEM );
    +     if( rc!=SQLITE_OK ){
    +-      db->mallocFailed = 1;
    ++      assert( db->mallocFailed == 1 );
    +       return;
    +     }
    +     if( !pVal ){
    +@@ -89912,27 +98699,34 @@ SQLITE_PRIVATE void sqlite3AlterFinishAddColumn(Parse *pParse, Token *pColDef){
    +   zCol = sqlite3DbStrNDup(db, (char*)pColDef->z, pColDef->n);
    +   if( zCol ){
    +     char *zEnd = &zCol[pColDef->n-1];
    +-    int savedDbFlags = db->flags;
    ++    u32 savedDbFlags = db->mDbFlags;
    +     while( zEnd>zCol && (*zEnd==';' || sqlite3Isspace(*zEnd)) ){
    +       *zEnd-- = '\0';
    +     }
    +-    db->flags |= SQLITE_PreferBuiltin;
    ++    db->mDbFlags |= DBFLAG_PreferBuiltin;
    +     sqlite3NestedParse(pParse, 
    +         "UPDATE \"%w\".%s SET "
    +           "sql = substr(sql,1,%d) || ', ' || %Q || substr(sql,%d) "
    +         "WHERE type = 'table' AND name = %Q", 
    +-      zDb, SCHEMA_TABLE(iDb), pNew->addColOffset, zCol, pNew->addColOffset+1,
    ++      zDb, MASTER_NAME, pNew->addColOffset, zCol, pNew->addColOffset+1,
    +       zTab
    +     );
    +     sqlite3DbFree(db, zCol);
    +-    db->flags = savedDbFlags;
    ++    db->mDbFlags = savedDbFlags;
    +   }
    + 
    +-  /* If the default value of the new column is NULL, then set the file
    +-  ** format to 2. If the default value of the new column is not NULL,
    +-  ** the file format becomes 3.
    ++  /* Make sure the schema version is at least 3.  But do not upgrade
    ++  ** from less than 3 to 4, as that will corrupt any preexisting DESC
    ++  ** index.
    +   */
    +-  sqlite3MinimumFileFormat(pParse, iDb, pDflt ? 3 : 2);
    ++  r1 = sqlite3GetTempReg(pParse);
    ++  sqlite3VdbeAddOp3(v, OP_ReadCookie, iDb, r1, BTREE_FILE_FORMAT);
    ++  sqlite3VdbeUsesBtree(v, iDb);
    ++  sqlite3VdbeAddOp2(v, OP_AddImm, r1, -2);
    ++  sqlite3VdbeAddOp2(v, OP_IfPos, r1, sqlite3VdbeCurrentAddr(v)+2);
    ++  VdbeCoverage(v);
    ++  sqlite3VdbeAddOp3(v, OP_SetCookie, iDb, BTREE_FILE_FORMAT, 3);
    ++  sqlite3ReleaseTempReg(pParse, r1);
    + 
    +   /* Reload the schema of the modified table. */
    +   reloadTableSchema(pParse, pTab, pTab->zName);
    +@@ -89998,7 +98792,7 @@ SQLITE_PRIVATE void sqlite3AlterBeginAddColumn(Parse *pParse, SrcList *pSrc){
    +   pNew = (Table*)sqlite3DbMallocZero(db, sizeof(Table));
    +   if( !pNew ) goto exit_begin_add_column;
    +   pParse->pNewTable = pNew;
    +-  pNew->nRef = 1;
    ++  pNew->nTabRef = 1;
    +   pNew->nCol = pTab->nCol;
    +   assert( pNew->nCol>0 );
    +   nAlloc = (((pNew->nCol-1)/8)*8)+8;
    +@@ -90006,7 +98800,7 @@ SQLITE_PRIVATE void sqlite3AlterBeginAddColumn(Parse *pParse, SrcList *pSrc){
    +   pNew->aCol = (Column*)sqlite3DbMallocZero(db, sizeof(Column)*nAlloc);
    +   pNew->zName = sqlite3MPrintf(db, "sqlite_altertab_%s", pTab->zName);
    +   if( !pNew->aCol || !pNew->zName ){
    +-    db->mallocFailed = 1;
    ++    assert( db->mallocFailed );
    +     goto exit_begin_add_column;
    +   }
    +   memcpy(pNew->aCol, pTab->aCol, sizeof(Column)*pNew->nCol);
    +@@ -90014,13 +98808,11 @@ SQLITE_PRIVATE void sqlite3AlterBeginAddColumn(Parse *pParse, SrcList *pSrc){
    +     Column *pCol = &pNew->aCol[i];
    +     pCol->zName = sqlite3DbStrDup(db, pCol->zName);
    +     pCol->zColl = 0;
    +-    pCol->zType = 0;
    +     pCol->pDflt = 0;
    +-    pCol->zDflt = 0;
    +   }
    +   pNew->pSchema = db->aDb[iDb].pSchema;
    +   pNew->addColOffset = pTab->addColOffset;
    +-  pNew->nRef = 1;
    ++  pNew->nTabRef = 1;
    + 
    +   /* Begin a transaction and increment the schema cookie.  */
    +   sqlite3BeginWriteOperation(pParse, 0, iDb);
    +@@ -90248,14 +99040,14 @@ static void openStatTable(
    +   for(i=0; i<ArraySize(aTable); i++){
    +     const char *zTab = aTable[i].zName;
    +     Table *pStat;
    +-    if( (pStat = sqlite3FindTable(db, zTab, pDb->zName))==0 ){
    ++    if( (pStat = sqlite3FindTable(db, zTab, pDb->zDbSName))==0 ){
    +       if( aTable[i].zCols ){
    +         /* The sqlite_statN table does not exist. Create it. Note that a 
    +         ** side-effect of the CREATE TABLE statement is to leave the rootpage 
    +         ** of the new table in register pParse->regRoot. This is important 
    +         ** because the OpenWrite opcode below will be needing it. */
    +         sqlite3NestedParse(pParse,
    +-            "CREATE TABLE %Q.%s(%s)", pDb->zName, zTab, aTable[i].zCols
    ++            "CREATE TABLE %Q.%s(%s)", pDb->zDbSName, zTab, aTable[i].zCols
    +         );
    +         aRoot[i] = pParse->regRoot;
    +         aCreateTbl[i] = OPFLAG_P2ISREG;
    +@@ -90270,8 +99062,12 @@ static void openStatTable(
    +       if( zWhere ){
    +         sqlite3NestedParse(pParse,
    +            "DELETE FROM %Q.%s WHERE %s=%Q",
    +-           pDb->zName, zTab, zWhereType, zWhere
    ++           pDb->zDbSName, zTab, zWhereType, zWhere
    +         );
    ++#ifdef SQLITE_ENABLE_PREUPDATE_HOOK
    ++      }else if( db->xPreUpdateCallback ){
    ++        sqlite3NestedParse(pParse, "DELETE FROM %Q.%s", pDb->zDbSName, zTab);
    ++#endif
    +       }else{
    +         /* The sqlite_stat[134] table already exists.  Delete all rows. */
    +         sqlite3VdbeAddOp2(v, OP_Clear, aRoot[i], iDb);
    +@@ -90328,6 +99124,7 @@ struct Stat4Accum {
    +   Stat4Sample *aBest;       /* Array of nCol best samples */
    +   int iMin;                 /* Index in a[] of entry with minimum score */
    +   int nSample;              /* Current number of samples */
    ++  int nMaxEqZero;           /* Max leading 0 in anEq[] for any a[] entry */
    +   int iGet;                 /* Index of current sample accessed by stat_get() */
    +   Stat4Sample *a;           /* Array of mxSample Stat4Sample objects */
    +   sqlite3 *db;              /* Database connection, for malloc() */
    +@@ -90351,7 +99148,7 @@ static void sampleClear(sqlite3 *db, Stat4Sample *p){
    + static void sampleSetRowid(sqlite3 *db, Stat4Sample *p, int n, const u8 *pData){
    +   assert( db!=0 );
    +   if( p->nRowid ) sqlite3DbFree(db, p->u.aRowid);
    +-  p->u.aRowid = sqlite3DbMallocRaw(db, n);
    ++  p->u.aRowid = sqlite3DbMallocRawNN(db, n);
    +   if( p->u.aRowid ){
    +     p->nRowid = n;
    +     memcpy(p->u.aRowid, pData, n);
    +@@ -90516,12 +99313,10 @@ static const FuncDef statInitFuncdef = {
    +   SQLITE_UTF8,     /* funcFlags */
    +   0,               /* pUserData */
    +   0,               /* pNext */
    +-  statInit,        /* xFunc */
    +-  0,               /* xStep */
    ++  statInit,        /* xSFunc */
    +   0,               /* xFinalize */
    +   "stat_init",     /* zName */
    +-  0,               /* pHash */
    +-  0                /* pDestructor */
    ++  {0}
    + };
    + 
    + #ifdef SQLITE_ENABLE_STAT4
    +@@ -90594,6 +99389,13 @@ static void sampleInsert(Stat4Accum *p, Stat4Sample *pNew, int nEqZero){
    +   assert( IsStat4 || nEqZero==0 );
    + 
    + #ifdef SQLITE_ENABLE_STAT4
    ++  /* Stat4Accum.nMaxEqZero is set to the maximum number of leading 0
    ++  ** values in the anEq[] array of any sample in Stat4Accum.a[]. In
    ++  ** other words, if nMaxEqZero is n, then it is guaranteed that there
    ++  ** are no samples with Stat4Sample.anEq[m]==0 for (m>=n). */
    ++  if( nEqZero>p->nMaxEqZero ){
    ++    p->nMaxEqZero = nEqZero;
    ++  }
    +   if( pNew->isPSample==0 ){
    +     Stat4Sample *pUpgrade = 0;
    +     assert( pNew->anEq[pNew->iCol]>0 );
    +@@ -90691,12 +99493,22 @@ static void samplePushPrevious(Stat4Accum *p, int iChng){
    +     }
    +   }
    + 
    +-  /* Update the anEq[] fields of any samples already collected. */
    ++  /* Check that no sample contains an anEq[] entry with an index of
    ++  ** p->nMaxEqZero or greater set to zero. */
    +   for(i=p->nSample-1; i>=0; i--){
    +     int j;
    +-    for(j=iChng; j<p->nCol; j++){
    +-      if( p->a[i].anEq[j]==0 ) p->a[i].anEq[j] = p->current.anEq[j];
    ++    for(j=p->nMaxEqZero; j<p->nCol; j++) assert( p->a[i].anEq[j]>0 );
    ++  }
    ++
    ++  /* Update the anEq[] fields of any samples already collected. */
    ++  if( iChng<p->nMaxEqZero ){
    ++    for(i=p->nSample-1; i>=0; i--){
    ++      int j;
    ++      for(j=iChng; j<p->nCol; j++){
    ++        if( p->a[i].anEq[j]==0 ) p->a[i].anEq[j] = p->current.anEq[j];
    ++      }
    +     }
    ++    p->nMaxEqZero = iChng;
    +   }
    + #endif
    + 
    +@@ -90817,12 +99629,10 @@ static const FuncDef statPushFuncdef = {
    +   SQLITE_UTF8,     /* funcFlags */
    +   0,               /* pUserData */
    +   0,               /* pNext */
    +-  statPush,        /* xFunc */
    +-  0,               /* xStep */
    ++  statPush,        /* xSFunc */
    +   0,               /* xFinalize */
    +   "stat_push",     /* zName */
    +-  0,               /* pHash */
    +-  0                /* pDestructor */
    ++  {0}
    + };
    + 
    + #define STAT_GET_STAT1 0          /* "stat" column of stat1 table */
    +@@ -90839,6 +99649,12 @@ static const FuncDef statPushFuncdef = {
    + ** The content to returned is determined by the parameter J
    + ** which is one of the STAT_GET_xxxx values defined above.
    + **
    ++** The stat_get(P,J) function is not available to generic SQL.  It is
    ++** inserted as part of a manually constructed bytecode program.  (See
    ++** the callStatGet() routine below.)  It is guaranteed that the P
    ++** parameter will always be a poiner to a Stat4Accum object, never a
    ++** NULL.
    ++**
    + ** If neither STAT3 nor STAT4 are enabled, then J is always
    + ** STAT_GET_STAT1 and is hence omitted and this routine becomes
    + ** a one-parameter function, stat_get(P), that always returns the
    +@@ -90964,12 +99780,10 @@ static const FuncDef statGetFuncdef = {
    +   SQLITE_UTF8,     /* funcFlags */
    +   0,               /* pUserData */
    +   0,               /* pNext */
    +-  statGet,         /* xFunc */
    +-  0,               /* xStep */
    ++  statGet,         /* xSFunc */
    +   0,               /* xFinalize */
    +   "stat_get",      /* zName */
    +-  0,               /* pHash */
    +-  0                /* pDestructor */
    ++  {0}
    + };
    + 
    + static void callStatGet(Vdbe *v, int regStat4, int iParam, int regOut){
    +@@ -90981,8 +99795,8 @@ static void callStatGet(Vdbe *v, int regStat4, int iParam, int regOut){
    + #else
    +   UNUSED_PARAMETER( iParam );
    + #endif
    +-  sqlite3VdbeAddOp3(v, OP_Function0, 0, regStat4, regOut);
    +-  sqlite3VdbeChangeP4(v, -1, (char*)&statGetFuncdef, P4_FUNCDEF);
    ++  sqlite3VdbeAddOp4(v, OP_Function0, 0, regStat4, regOut,
    ++                    (char*)&statGetFuncdef, P4_FUNCDEF);
    +   sqlite3VdbeChangeP5(v, 1 + IsStat34);
    + }
    + 
    +@@ -91018,6 +99832,9 @@ static void analyzeOneTable(
    +   int regIdxname = iMem++;     /* Register containing index name */
    +   int regStat1 = iMem++;       /* Value for the stat column of sqlite_stat1 */
    +   int regPrev = iMem;          /* MUST BE LAST (see below) */
    ++#ifdef SQLITE_ENABLE_PREUPDATE_HOOK
    ++  Table *pStat1 = 0; 
    ++#endif
    + 
    +   pParse->nMem = MAX(pParse->nMem, iMem);
    +   v = sqlite3GetVdbe(pParse);
    +@@ -91028,7 +99845,7 @@ static void analyzeOneTable(
    +     /* Do not gather statistics on views or virtual tables */
    +     return;
    +   }
    +-  if( sqlite3_strnicmp(pTab->zName, "sqlite_", 7)==0 ){
    ++  if( sqlite3_strlike("sqlite_%", pTab->zName, 0)==0 ){
    +     /* Do not gather statistics on system tables */
    +     return;
    +   }
    +@@ -91038,11 +99855,23 @@ static void analyzeOneTable(
    +   assert( sqlite3SchemaMutexHeld(db, iDb, 0) );
    + #ifndef SQLITE_OMIT_AUTHORIZATION
    +   if( sqlite3AuthCheck(pParse, SQLITE_ANALYZE, pTab->zName, 0,
    +-      db->aDb[iDb].zName ) ){
    ++      db->aDb[iDb].zDbSName ) ){
    +     return;
    +   }
    + #endif
    + 
    ++#ifdef SQLITE_ENABLE_PREUPDATE_HOOK
    ++  if( db->xPreUpdateCallback ){
    ++    pStat1 = (Table*)sqlite3DbMallocZero(db, sizeof(Table) + 13);
    ++    if( pStat1==0 ) return;
    ++    pStat1->zName = (char*)&pStat1[1];
    ++    memcpy(pStat1->zName, "sqlite_stat1", 13);
    ++    pStat1->nCol = 3;
    ++    pStat1->iPKey = -1;
    ++    sqlite3VdbeAddOp4(pParse->pVdbe, OP_Noop, 0, 0, 0,(char*)pStat1,P4_DYNBLOB);
    ++  }
    ++#endif
    ++
    +   /* Establish a read-lock on the table at the shared-cache level. 
    +   ** Open a read-only cursor on the table. Also allocate a cursor number
    +   ** to use for scanning indexes (iIdxCur). No index cursor is opened at
    +@@ -91136,8 +99965,8 @@ static void analyzeOneTable(
    + #endif
    +     sqlite3VdbeAddOp2(v, OP_Integer, nCol, regStat4+1);
    +     sqlite3VdbeAddOp2(v, OP_Integer, pIdx->nKeyCol, regStat4+2);
    +-    sqlite3VdbeAddOp3(v, OP_Function0, 0, regStat4+1, regStat4);
    +-    sqlite3VdbeChangeP4(v, -1, (char*)&statInitFuncdef, P4_FUNCDEF);
    ++    sqlite3VdbeAddOp4(v, OP_Function0, 0, regStat4+1, regStat4,
    ++                     (char*)&statInitFuncdef, P4_FUNCDEF);
    +     sqlite3VdbeChangeP5(v, 2+IsStat34);
    + 
    +     /* Implementation of the following:
    +@@ -91156,7 +99985,7 @@ static void analyzeOneTable(
    +     if( nColTest>0 ){
    +       int endDistinctTest = sqlite3VdbeMakeLabel(v);
    +       int *aGotoChng;               /* Array of jump instruction addresses */
    +-      aGotoChng = sqlite3DbMallocRaw(db, sizeof(int)*nColTest);
    ++      aGotoChng = sqlite3DbMallocRawNN(db, sizeof(int)*nColTest);
    +       if( aGotoChng==0 ) continue;
    + 
    +       /*
    +@@ -91224,7 +100053,7 @@ static void analyzeOneTable(
    +       regKey = sqlite3GetTempRange(pParse, pPk->nKeyCol);
    +       for(j=0; j<pPk->nKeyCol; j++){
    +         k = sqlite3ColumnOfIndex(pIdx, pPk->aiColumn[j]);
    +-        assert( k>=0 && k<pTab->nCol );
    ++        assert( k>=0 && k<pIdx->nColumn );
    +         sqlite3VdbeAddOp3(v, OP_Column, iIdxCur, k, regKey+j);
    +         VdbeComment((v, "%s", pTab->aCol[pPk->aiColumn[j]].zName));
    +       }
    +@@ -91233,8 +100062,8 @@ static void analyzeOneTable(
    +     }
    + #endif
    +     assert( regChng==(regStat4+1) );
    +-    sqlite3VdbeAddOp3(v, OP_Function0, 1, regStat4, regTemp);
    +-    sqlite3VdbeChangeP4(v, -1, (char*)&statPushFuncdef, P4_FUNCDEF);
    ++    sqlite3VdbeAddOp4(v, OP_Function0, 1, regStat4, regTemp,
    ++                     (char*)&statPushFuncdef, P4_FUNCDEF);
    +     sqlite3VdbeChangeP5(v, 2+IsStat34);
    +     sqlite3VdbeAddOp2(v, OP_Next, iIdxCur, addrNextRow); VdbeCoverage(v);
    + 
    +@@ -91244,6 +100073,9 @@ static void analyzeOneTable(
    +     sqlite3VdbeAddOp4(v, OP_MakeRecord, regTabname, 3, regTemp, "BBB", 0);
    +     sqlite3VdbeAddOp2(v, OP_NewRowid, iStatCur, regNewRowid);
    +     sqlite3VdbeAddOp3(v, OP_Insert, iStatCur, regTemp, regNewRowid);
    ++#ifdef SQLITE_ENABLE_PREUPDATE_HOOK
    ++    sqlite3VdbeChangeP4(v, -1, (char*)pStat1, P4_TABLE);
    ++#endif
    +     sqlite3VdbeChangeP5(v, OPFLAG_APPEND);
    + 
    +     /* Add the entries to the stat3 or stat4 table. */
    +@@ -91307,6 +100139,9 @@ static void analyzeOneTable(
    +     sqlite3VdbeAddOp2(v, OP_NewRowid, iStatCur, regNewRowid);
    +     sqlite3VdbeAddOp3(v, OP_Insert, iStatCur, regTemp, regNewRowid);
    +     sqlite3VdbeChangeP5(v, OPFLAG_APPEND);
    ++#ifdef SQLITE_ENABLE_PREUPDATE_HOOK
    ++    sqlite3VdbeChangeP4(v, -1, (char*)pStat1, P4_TABLE);
    ++#endif
    +     sqlite3VdbeJumpHere(v, jZeroRows);
    +   }
    + }
    +@@ -91408,27 +100243,14 @@ SQLITE_PRIVATE void sqlite3Analyze(Parse *pParse, Token *pName1, Token *pName2){
    +       if( i==1 ) continue;  /* Do not analyze the TEMP database */
    +       analyzeDatabase(pParse, i);
    +     }
    +-  }else if( pName2->n==0 ){
    +-    /* Form 2:  Analyze the database or table named */
    +-    iDb = sqlite3FindDb(db, pName1);
    +-    if( iDb>=0 ){
    +-      analyzeDatabase(pParse, iDb);
    +-    }else{
    +-      z = sqlite3NameFromToken(db, pName1);
    +-      if( z ){
    +-        if( (pIdx = sqlite3FindIndex(db, z, 0))!=0 ){
    +-          analyzeTable(pParse, pIdx->pTable, pIdx);
    +-        }else if( (pTab = sqlite3LocateTable(pParse, 0, z, 0))!=0 ){
    +-          analyzeTable(pParse, pTab, 0);
    +-        }
    +-        sqlite3DbFree(db, z);
    +-      }
    +-    }
    ++  }else if( pName2->n==0 && (iDb = sqlite3FindDb(db, pName1))>=0 ){
    ++    /* Analyze the schema named as the argument */
    ++    analyzeDatabase(pParse, iDb);
    +   }else{
    +-    /* Form 3: Analyze the fully qualified table name */
    ++    /* Form 3: Analyze the table or index named as an argument */
    +     iDb = sqlite3TwoPartName(pParse, pName1, pName2, &pTableName);
    +     if( iDb>=0 ){
    +-      zDb = db->aDb[iDb].zName;
    ++      zDb = pName2->n ? db->aDb[iDb].zDbSName : 0;
    +       z = sqlite3NameFromToken(db, pTableName);
    +       if( z ){
    +         if( (pIdx = sqlite3FindIndex(db, z, zDb))!=0 ){
    +@@ -91438,10 +100260,11 @@ SQLITE_PRIVATE void sqlite3Analyze(Parse *pParse, Token *pName1, Token *pName2){
    +         }
    +         sqlite3DbFree(db, z);
    +       }
    +-    }   
    ++    }
    ++  }
    ++  if( db->nSqlExec==0 && (v = sqlite3GetVdbe(pParse))!=0 ){
    ++    sqlite3VdbeAddOp0(v, OP_Expire);
    +   }
    +-  v = sqlite3GetVdbe(pParse);
    +-  if( v ) sqlite3VdbeAddOp0(v, OP_Expire);
    + }
    + 
    + /*
    +@@ -91564,13 +100387,17 @@ static int analysisLoader(void *pData, int argc, char **argv, char **NotUsed){
    +     ** the old data with the new instead of allocating a new array.  */
    +     if( pIndex->aiRowEst==0 ){
    +       pIndex->aiRowEst = (tRowcnt*)sqlite3MallocZero(sizeof(tRowcnt) * nCol);
    +-      if( pIndex->aiRowEst==0 ) pInfo->db->mallocFailed = 1;
    ++      if( pIndex->aiRowEst==0 ) sqlite3OomFault(pInfo->db);
    +     }
    +     aiRowEst = pIndex->aiRowEst;
    + #endif
    +     pIndex->bUnordered = 0;
    +     decodeIntArray((char*)z, nCol, aiRowEst, pIndex->aiRowLogEst, pIndex);
    +-    if( pIndex->pPartIdxWhere==0 ) pTable->nRowLogEst = pIndex->aiRowLogEst[0];
    ++    pIndex->hasStat1 = 1;
    ++    if( pIndex->pPartIdxWhere==0 ){
    ++      pTable->nRowLogEst = pIndex->aiRowLogEst[0];
    ++      pTable->tabFlags |= TF_HasStat1;
    ++    }
    +   }else{
    +     Index fakeIdx;
    +     fakeIdx.szIdxRow = pTable->szTabRow;
    +@@ -91579,6 +100406,7 @@ static int analysisLoader(void *pData, int argc, char **argv, char **NotUsed){
    + #endif
    +     decodeIntArray((char*)z, 1, 0, &pTable->nRowLogEst, &fakeIdx);
    +     pTable->szTabRow = fakeIdx.szIdxRow;
    ++    pTable->tabFlags |= TF_HasStat1;
    +   }
    + 
    +   return 0;
    +@@ -91659,7 +100487,7 @@ static void initAvgEq(Index *pIdx){
    +         }
    +       }
    + 
    +-      if( nDist100>nSum100 ){
    ++      if( nDist100>nSum100 && sumEq<nRow ){
    +         avgEq = ((i64)100 * (nRow - sumEq))/(nDist100 - nSum100);
    +       }
    +       if( avgEq==0 ) avgEq = 1;
    +@@ -91711,10 +100539,10 @@ static int loadStatTbl(
    +   Index *pPrevIdx = 0;          /* Previous index in the loop */
    +   IndexSample *pSample;         /* A slot in pIdx->aSample[] */
    + 
    +-  assert( db->lookaside.bEnabled==0 );
    ++  assert( db->lookaside.bDisable );
    +   zSql = sqlite3MPrintf(db, zSql1, zDb);
    +   if( !zSql ){
    +-    return SQLITE_NOMEM;
    ++    return SQLITE_NOMEM_BKPT;
    +   }
    +   rc = sqlite3_prepare(db, zSql, -1, &pStmt, 0);
    +   sqlite3DbFree(db, zSql);
    +@@ -91754,7 +100582,7 @@ static int loadStatTbl(
    +     pIdx->aSample = sqlite3DbMallocZero(db, nByte);
    +     if( pIdx->aSample==0 ){
    +       sqlite3_finalize(pStmt);
    +-      return SQLITE_NOMEM;
    ++      return SQLITE_NOMEM_BKPT;
    +     }
    +     pSpace = (tRowcnt*)&pIdx->aSample[nSample];
    +     pIdx->aAvgEq = pSpace; pSpace += nIdxCol;
    +@@ -91770,7 +100598,7 @@ static int loadStatTbl(
    + 
    +   zSql = sqlite3MPrintf(db, zSql2, zDb);
    +   if( !zSql ){
    +-    return SQLITE_NOMEM;
    ++    return SQLITE_NOMEM_BKPT;
    +   }
    +   rc = sqlite3_prepare(db, zSql, -1, &pStmt, 0);
    +   sqlite3DbFree(db, zSql);
    +@@ -91808,9 +100636,11 @@ static int loadStatTbl(
    +     pSample->p = sqlite3DbMallocZero(db, pSample->n + 2);
    +     if( pSample->p==0 ){
    +       sqlite3_finalize(pStmt);
    +-      return SQLITE_NOMEM;
    ++      return SQLITE_NOMEM_BKPT;
    ++    }
    ++    if( pSample->n ){
    ++      memcpy(pSample->p, sqlite3_column_blob(pStmt, 4), pSample->n);
    +     }
    +-    memcpy(pSample->p, sqlite3_column_blob(pStmt, 4), pSample->n);
    +     pIdx->nSample++;
    +   }
    +   rc = sqlite3_finalize(pStmt);
    +@@ -91825,7 +100655,7 @@ static int loadStatTbl(
    + static int loadStat4(sqlite3 *db, const char *zDb){
    +   int rc = SQLITE_OK;             /* Result codes from subroutines */
    + 
    +-  assert( db->lookaside.bEnabled==0 );
    ++  assert( db->lookaside.bDisable );
    +   if( sqlite3FindTable(db, "sqlite_stat4", zDb) ){
    +     rc = loadStatTbl(db, 0,
    +       "SELECT idx,count(*) FROM %Q.sqlite_stat4 GROUP BY idx", 
    +@@ -91870,49 +100700,56 @@ SQLITE_PRIVATE int sqlite3AnalysisLoad(sqlite3 *db, int iDb){
    +   analysisInfo sInfo;
    +   HashElem *i;
    +   char *zSql;
    +-  int rc;
    ++  int rc = SQLITE_OK;
    ++  Schema *pSchema = db->aDb[iDb].pSchema;
    + 
    +   assert( iDb>=0 && iDb<db->nDb );
    +   assert( db->aDb[iDb].pBt!=0 );
    + 
    +   /* Clear any prior statistics */
    +   assert( sqlite3SchemaMutexHeld(db, iDb, 0) );
    +-  for(i=sqliteHashFirst(&db->aDb[iDb].pSchema->idxHash);i;i=sqliteHashNext(i)){
    ++  for(i=sqliteHashFirst(&pSchema->tblHash); i; i=sqliteHashNext(i)){
    ++    Table *pTab = sqliteHashData(i);
    ++    pTab->tabFlags &= ~TF_HasStat1;
    ++  }
    ++  for(i=sqliteHashFirst(&pSchema->idxHash); i; i=sqliteHashNext(i)){
    +     Index *pIdx = sqliteHashData(i);
    +-    sqlite3DefaultRowEst(pIdx);
    ++    pIdx->hasStat1 = 0;
    + #ifdef SQLITE_ENABLE_STAT3_OR_STAT4
    +     sqlite3DeleteIndexSamples(db, pIdx);
    +     pIdx->aSample = 0;
    + #endif
    +   }
    + 
    +-  /* Check to make sure the sqlite_stat1 table exists */
    ++  /* Load new statistics out of the sqlite_stat1 table */
    +   sInfo.db = db;
    +-  sInfo.zDatabase = db->aDb[iDb].zName;
    +-  if( sqlite3FindTable(db, "sqlite_stat1", sInfo.zDatabase)==0 ){
    +-    return SQLITE_ERROR;
    ++  sInfo.zDatabase = db->aDb[iDb].zDbSName;
    ++  if( sqlite3FindTable(db, "sqlite_stat1", sInfo.zDatabase)!=0 ){
    ++    zSql = sqlite3MPrintf(db, 
    ++        "SELECT tbl,idx,stat FROM %Q.sqlite_stat1", sInfo.zDatabase);
    ++    if( zSql==0 ){
    ++      rc = SQLITE_NOMEM_BKPT;
    ++    }else{
    ++      rc = sqlite3_exec(db, zSql, analysisLoader, &sInfo, 0);
    ++      sqlite3DbFree(db, zSql);
    ++    }
    +   }
    + 
    +-  /* Load new statistics out of the sqlite_stat1 table */
    +-  zSql = sqlite3MPrintf(db, 
    +-      "SELECT tbl,idx,stat FROM %Q.sqlite_stat1", sInfo.zDatabase);
    +-  if( zSql==0 ){
    +-    rc = SQLITE_NOMEM;
    +-  }else{
    +-    rc = sqlite3_exec(db, zSql, analysisLoader, &sInfo, 0);
    +-    sqlite3DbFree(db, zSql);
    ++  /* Set appropriate defaults on all indexes not in the sqlite_stat1 table */
    ++  assert( sqlite3SchemaMutexHeld(db, iDb, 0) );
    ++  for(i=sqliteHashFirst(&pSchema->idxHash); i; i=sqliteHashNext(i)){
    ++    Index *pIdx = sqliteHashData(i);
    ++    if( !pIdx->hasStat1 ) sqlite3DefaultRowEst(pIdx);
    +   }
    + 
    +-
    +   /* Load the statistics from the sqlite_stat4 table. */
    + #ifdef SQLITE_ENABLE_STAT3_OR_STAT4
    +   if( rc==SQLITE_OK && OptimizationEnabled(db, SQLITE_Stat34) ){
    +-    int lookasideEnabled = db->lookaside.bEnabled;
    +-    db->lookaside.bEnabled = 0;
    ++    db->lookaside.bDisable++;
    +     rc = loadStat4(db, sInfo.zDatabase);
    +-    db->lookaside.bEnabled = lookasideEnabled;
    ++    db->lookaside.bDisable--;
    +   }
    +-  for(i=sqliteHashFirst(&db->aDb[iDb].pSchema->idxHash);i;i=sqliteHashNext(i)){
    ++  for(i=sqliteHashFirst(&pSchema->idxHash); i; i=sqliteHashNext(i)){
    +     Index *pIdx = sqliteHashData(i);
    +     sqlite3_free(pIdx->aiRowEst);
    +     pIdx->aiRowEst = 0;
    +@@ -91920,7 +100757,7 @@ SQLITE_PRIVATE int sqlite3AnalysisLoad(sqlite3 *db, int iDb){
    + #endif
    + 
    +   if( rc==SQLITE_NOMEM ){
    +-    db->mallocFailed = 1;
    ++    sqlite3OomFault(db);
    +   }
    +   return rc;
    + }
    +@@ -92001,7 +100838,8 @@ static void attachFunc(
    +   char *zPath = 0;
    +   char *zErr = 0;
    +   unsigned int flags;
    +-  Db *aNew;
    ++  Db *aNew;                 /* New array of Db pointers */
    ++  Db *pNew;                 /* Db object for the newly attached database */
    +   char *zErrDyn = 0;
    +   sqlite3_vfs *pVfs;
    + 
    +@@ -92024,12 +100862,8 @@ static void attachFunc(
    +     );
    +     goto attach_error;
    +   }
    +-  if( !db->autoCommit ){
    +-    zErrDyn = sqlite3MPrintf(db, "cannot ATTACH database within transaction");
    +-    goto attach_error;
    +-  }
    +   for(i=0; i<db->nDb; i++){
    +-    char *z = db->aDb[i].zName;
    ++    char *z = db->aDb[i].zDbSName;
    +     assert( z && zName );
    +     if( sqlite3StrICmp(z, zName)==0 ){
    +       zErrDyn = sqlite3MPrintf(db, "database %s is already in use", zName);
    +@@ -92041,7 +100875,7 @@ static void attachFunc(
    +   ** hash tables.
    +   */
    +   if( db->aDb==db->aDbStatic ){
    +-    aNew = sqlite3DbMallocRaw(db, sizeof(db->aDb[0])*3 );
    ++    aNew = sqlite3DbMallocRawNN(db, sizeof(db->aDb[0])*3 );
    +     if( aNew==0 ) return;
    +     memcpy(aNew, db->aDb, sizeof(db->aDb[0])*2);
    +   }else{
    +@@ -92049,8 +100883,8 @@ static void attachFunc(
    +     if( aNew==0 ) return;
    +   }
    +   db->aDb = aNew;
    +-  aNew = &db->aDb[db->nDb];
    +-  memset(aNew, 0, sizeof(*aNew));
    ++  pNew = &db->aDb[db->nDb];
    ++  memset(pNew, 0, sizeof(*pNew));
    + 
    +   /* Open the database file. If the btree is successfully opened, use
    +   ** it to obtain the database schema. At this point the schema may
    +@@ -92059,43 +100893,45 @@ static void attachFunc(
    +   flags = db->openFlags;
    +   rc = sqlite3ParseUri(db->pVfs->zName, zFile, &flags, &pVfs, &zPath, &zErr);
    +   if( rc!=SQLITE_OK ){
    +-    if( rc==SQLITE_NOMEM ) db->mallocFailed = 1;
    ++    if( rc==SQLITE_NOMEM ) sqlite3OomFault(db);
    +     sqlite3_result_error(context, zErr, -1);
    +     sqlite3_free(zErr);
    +     return;
    +   }
    +   assert( pVfs );
    +   flags |= SQLITE_OPEN_MAIN_DB;
    +-  rc = sqlite3BtreeOpen(pVfs, zPath, db, &aNew->pBt, 0, flags);
    ++  rc = sqlite3BtreeOpen(pVfs, zPath, db, &pNew->pBt, 0, flags);
    +   sqlite3_free( zPath );
    +   db->nDb++;
    ++  db->skipBtreeMutex = 0;
    +   if( rc==SQLITE_CONSTRAINT ){
    +     rc = SQLITE_ERROR;
    +     zErrDyn = sqlite3MPrintf(db, "database is already attached");
    +   }else if( rc==SQLITE_OK ){
    +     Pager *pPager;
    +-    aNew->pSchema = sqlite3SchemaGet(db, aNew->pBt);
    +-    if( !aNew->pSchema ){
    +-      rc = SQLITE_NOMEM;
    +-    }else if( aNew->pSchema->file_format && aNew->pSchema->enc!=ENC(db) ){
    ++    pNew->pSchema = sqlite3SchemaGet(db, pNew->pBt);
    ++    if( !pNew->pSchema ){
    ++      rc = SQLITE_NOMEM_BKPT;
    ++    }else if( pNew->pSchema->file_format && pNew->pSchema->enc!=ENC(db) ){
    +       zErrDyn = sqlite3MPrintf(db, 
    +         "attached databases must use the same text encoding as main database");
    +       rc = SQLITE_ERROR;
    +     }
    +-    sqlite3BtreeEnter(aNew->pBt);
    +-    pPager = sqlite3BtreePager(aNew->pBt);
    ++    sqlite3BtreeEnter(pNew->pBt);
    ++    pPager = sqlite3BtreePager(pNew->pBt);
    +     sqlite3PagerLockingMode(pPager, db->dfltLockMode);
    +-    sqlite3BtreeSecureDelete(aNew->pBt,
    ++    sqlite3BtreeSecureDelete(pNew->pBt,
    +                              sqlite3BtreeSecureDelete(db->aDb[0].pBt,-1) );
    + #ifndef SQLITE_OMIT_PAGER_PRAGMAS
    +-    sqlite3BtreeSetPagerFlags(aNew->pBt, 3 | (db->flags & PAGER_FLAGS_MASK));
    ++    sqlite3BtreeSetPagerFlags(pNew->pBt,
    ++                      PAGER_SYNCHRONOUS_FULL | (db->flags & PAGER_FLAGS_MASK));
    + #endif
    +-    sqlite3BtreeLeave(aNew->pBt);
    ++    sqlite3BtreeLeave(pNew->pBt);
    +   }
    +-  aNew->safety_level = 3;
    +-  aNew->zName = sqlite3DbStrDup(db, zName);
    +-  if( rc==SQLITE_OK && aNew->zName==0 ){
    +-    rc = SQLITE_NOMEM;
    ++  pNew->safety_level = SQLITE_DEFAULT_SYNCHRONOUS+1;
    ++  pNew->zDbSName = sqlite3DbStrDup(db, zName);
    ++  if( rc==SQLITE_OK && pNew->zDbSName==0 ){
    ++    rc = SQLITE_NOMEM_BKPT;
    +   }
    + 
    + 
    +@@ -92123,7 +100959,7 @@ static void attachFunc(
    +       case SQLITE_NULL:
    +         /* No key specified.  Use the key from the main database */
    +         sqlite3CodecGetKey(db, 0, (void**)&zKey, &nKey);
    +-        if( nKey>0 || sqlite3BtreeGetOptimalReserve(db->aDb[0].pBt)>0 ){
    ++        if( nKey || sqlite3BtreeGetOptimalReserve(db->aDb[0].pBt)>0 ){
    +           rc = sqlite3CodecAttach(db, db->nDb-1, zKey, nKey);
    +         }
    +         break;
    +@@ -92161,7 +100997,7 @@ static void attachFunc(
    +     sqlite3ResetAllSchemasOfConnection(db);
    +     db->nDb = iDb;
    +     if( rc==SQLITE_NOMEM || rc==SQLITE_IOERR_NOMEM ){
    +-      db->mallocFailed = 1;
    ++      sqlite3OomFault(db);
    +       sqlite3DbFree(db, zErrDyn);
    +       zErrDyn = sqlite3MPrintf(db, "out of memory");
    +     }else if( zErrDyn==0 ){
    +@@ -92206,7 +101042,7 @@ static void detachFunc(
    +   for(i=0; i<db->nDb; i++){
    +     pDb = &db->aDb[i];
    +     if( pDb->pBt==0 ) continue;
    +-    if( sqlite3StrICmp(pDb->zName, zName)==0 ) break;
    ++    if( sqlite3StrICmp(pDb->zDbSName, zName)==0 ) break;
    +   }
    + 
    +   if( i>=db->nDb ){
    +@@ -92217,11 +101053,6 @@ static void detachFunc(
    +     sqlite3_snprintf(sizeof(zErr),zErr, "cannot detach database %s", zName);
    +     goto detach_error;
    +   }
    +-  if( !db->autoCommit ){
    +-    sqlite3_snprintf(sizeof(zErr), zErr,
    +-                     "cannot DETACH database within transaction");
    +-    goto detach_error;
    +-  }
    +   if( sqlite3BtreeIsInReadTrans(pDb->pBt) || sqlite3BtreeIsInBackup(pDb->pBt) ){
    +     sqlite3_snprintf(sizeof(zErr),zErr, "database %s is locked", zName);
    +     goto detach_error;
    +@@ -92256,6 +101087,7 @@ static void codeAttach(
    +   sqlite3* db = pParse->db;
    +   int regArgs;
    + 
    ++  if( pParse->nErr ) goto attach_end;
    +   memset(&sName, 0, sizeof(NameContext));
    +   sName.pParse = pParse;
    + 
    +@@ -92291,11 +101123,11 @@ static void codeAttach(
    + 
    +   assert( v || db->mallocFailed );
    +   if( v ){
    +-    sqlite3VdbeAddOp3(v, OP_Function0, 0, regArgs+3-pFunc->nArg, regArgs+3);
    ++    sqlite3VdbeAddOp4(v, OP_Function0, 0, regArgs+3-pFunc->nArg, regArgs+3,
    ++                      (char *)pFunc, P4_FUNCDEF);
    +     assert( pFunc->nArg==-1 || (pFunc->nArg&0xff)==pFunc->nArg );
    +     sqlite3VdbeChangeP5(v, (u8)(pFunc->nArg));
    +-    sqlite3VdbeChangeP4(v, -1, (char *)pFunc, P4_FUNCDEF);
    +-
    ++ 
    +     /* Code an OP_Expire. For an ATTACH statement, set P1 to true (expire this
    +     ** statement only). For DETACH, set it to false (expire all existing
    +     ** statements).
    +@@ -92320,12 +101152,10 @@ SQLITE_PRIVATE void sqlite3Detach(Parse *pParse, Expr *pDbname){
    +     SQLITE_UTF8,      /* funcFlags */
    +     0,                /* pUserData */
    +     0,                /* pNext */
    +-    detachFunc,       /* xFunc */
    +-    0,                /* xStep */
    ++    detachFunc,       /* xSFunc */
    +     0,                /* xFinalize */
    +     "sqlite_detach",  /* zName */
    +-    0,                /* pHash */
    +-    0                 /* pDestructor */
    ++    {0}
    +   };
    +   codeAttach(pParse, SQLITE_DETACH, &detach_func, pDbname, 0, 0, pDbname);
    + }
    +@@ -92341,12 +101171,10 @@ SQLITE_PRIVATE void sqlite3Attach(Parse *pParse, Expr *p, Expr *pDbname, Expr *p
    +     SQLITE_UTF8,      /* funcFlags */
    +     0,                /* pUserData */
    +     0,                /* pNext */
    +-    attachFunc,       /* xFunc */
    +-    0,                /* xStep */
    ++    attachFunc,       /* xSFunc */
    +     0,                /* xFinalize */
    +     "sqlite_attach",  /* zName */
    +-    0,                /* pHash */
    +-    0                 /* pDestructor */
    ++    {0}
    +   };
    +   codeAttach(pParse, SQLITE_ATTACH, &attach_func, p, p, pDbname, pKey);
    + }
    +@@ -92368,7 +101196,7 @@ SQLITE_PRIVATE void sqlite3FixInit(
    +   db = pParse->db;
    +   assert( db->nDb>iDb );
    +   pFix->pParse = pParse;
    +-  pFix->zDb = db->aDb[iDb].zName;
    ++  pFix->zDb = db->aDb[iDb].zDbSName;
    +   pFix->pSchema = db->aDb[iDb].pSchema;
    +   pFix->zType = zType;
    +   pFix->pName = pName;
    +@@ -92445,9 +101273,6 @@ SQLITE_PRIVATE int sqlite3FixSelect(
    +     if( sqlite3FixExpr(pFix, pSelect->pLimit) ){
    +       return 1;
    +     }
    +-    if( sqlite3FixExpr(pFix, pSelect->pOffset) ){
    +-      return 1;
    +-    }
    +     pSelect = pSelect->pPrior;
    +   }
    +   return 0;
    +@@ -92465,7 +101290,7 @@ SQLITE_PRIVATE int sqlite3FixExpr(
    +         return 1;
    +       }
    +     }
    +-    if( ExprHasProperty(pExpr, EP_TokenOnly) ) break;
    ++    if( ExprHasProperty(pExpr, EP_TokenOnly|EP_Leaf) ) break;
    +     if( ExprHasProperty(pExpr, EP_xIsSelect) ){
    +       if( sqlite3FixSelect(pFix, pExpr->x.pSelect) ) return 1;
    +     }else{
    +@@ -92586,7 +101411,7 @@ SQLITE_PRIVATE int sqlite3FixTriggerStep(
    + ** Setting the auth function to NULL disables this hook.  The default
    + ** setting of the auth function is NULL.
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_set_authorizer(
    ++SQLITE_API int sqlite3_set_authorizer(
    +   sqlite3 *db,
    +   int (*xAuth)(void*,int,const char*,const char*,const char*,const char*),
    +   void *pArg
    +@@ -92626,21 +101451,20 @@ SQLITE_PRIVATE int sqlite3AuthReadCol(
    +   const char *zCol,               /* Column name */
    +   int iDb                         /* Index of containing database. */
    + ){
    +-  sqlite3 *db = pParse->db;       /* Database handle */
    +-  char *zDb = db->aDb[iDb].zName; /* Name of attached database */
    +-  int rc;                         /* Auth callback return code */
    ++  sqlite3 *db = pParse->db;          /* Database handle */
    ++  char *zDb = db->aDb[iDb].zDbSName; /* Schema name of attached database */
    ++  int rc;                            /* Auth callback return code */
    + 
    ++  if( db->init.busy ) return SQLITE_OK;
    +   rc = db->xAuth(db->pAuthArg, SQLITE_READ, zTab,zCol,zDb,pParse->zAuthContext
    + #ifdef SQLITE_USER_AUTHENTICATION
    +                  ,db->auth.zAuthUser
    + #endif
    +                 );
    +   if( rc==SQLITE_DENY ){
    +-    if( db->nDb>2 || iDb!=0 ){
    +-      sqlite3ErrorMsg(pParse, "access to %s.%s.%s is prohibited",zDb,zTab,zCol);
    +-    }else{
    +-      sqlite3ErrorMsg(pParse, "access to %s.%s is prohibited", zTab, zCol);
    +-    }
    ++    char *z = sqlite3_mprintf("%s.%s", zTab, zCol);
    ++    if( db->nDb>2 || iDb!=0 ) z = sqlite3_mprintf("%s.%z", zDb, z);
    ++    sqlite3ErrorMsg(pParse, "access to %z is prohibited", z);
    +     pParse->rc = SQLITE_AUTH;
    +   }else if( rc!=SQLITE_IGNORE && rc!=SQLITE_OK ){
    +     sqliteAuthBadReturnCode(pParse);
    +@@ -92734,6 +101558,18 @@ SQLITE_PRIVATE int sqlite3AuthCheck(
    +   if( db->xAuth==0 ){
    +     return SQLITE_OK;
    +   }
    ++
    ++  /* EVIDENCE-OF: R-43249-19882 The third through sixth parameters to the
    ++  ** callback are either NULL pointers or zero-terminated strings that
    ++  ** contain additional details about the action to be authorized.
    ++  **
    ++  ** The following testcase() macros show that any of the 3rd through 6th
    ++  ** parameters can be either NULL or a string. */
    ++  testcase( zArg1==0 );
    ++  testcase( zArg2==0 );
    ++  testcase( zArg3==0 );
    ++  testcase( pParse->zAuthContext==0 );
    ++
    +   rc = db->xAuth(db->pAuthArg, code, zArg1, zArg2, zArg3, pParse->zAuthContext
    + #ifdef SQLITE_USER_AUTHENTICATION
    +                  ,db->auth.zAuthUser
    +@@ -92806,25 +101642,16 @@ SQLITE_PRIVATE void sqlite3AuthContextPop(AuthContext *pContext){
    + */
    + /* #include "sqliteInt.h" */
    + 
    +-/*
    +-** This routine is called when a new SQL statement is beginning to
    +-** be parsed.  Initialize the pParse structure as needed.
    +-*/
    +-SQLITE_PRIVATE void sqlite3BeginParse(Parse *pParse, int explainFlag){
    +-  pParse->explain = (u8)explainFlag;
    +-  pParse->nVar = 0;
    +-}
    +-
    + #ifndef SQLITE_OMIT_SHARED_CACHE
    + /*
    + ** The TableLock structure is only used by the sqlite3TableLock() and
    + ** codeTableLocks() functions.
    + */
    + struct TableLock {
    +-  int iDb;             /* The database containing the table to be locked */
    +-  int iTab;            /* The root page of the table to be locked */
    +-  u8 isWriteLock;      /* True for write lock.  False for a read lock */
    +-  const char *zName;   /* Name of the table */
    ++  int iDb;               /* The database containing the table to be locked */
    ++  int iTab;              /* The root page of the table to be locked */
    ++  u8 isWriteLock;        /* True for write lock.  False for a read lock */
    ++  const char *zLockName; /* Name of the table */
    + };
    + 
    + /*
    +@@ -92850,6 +101677,8 @@ SQLITE_PRIVATE void sqlite3TableLock(
    +   TableLock *p;
    +   assert( iDb>=0 );
    + 
    ++  if( iDb==1 ) return;
    ++  if( !sqlite3BtreeSharable(pParse->db->aDb[iDb].pBt) ) return;
    +   for(i=0; i<pToplevel->nTableLock; i++){
    +     p = &pToplevel->aTableLock[i];
    +     if( p->iDb==iDb && p->iTab==iTab ){
    +@@ -92866,10 +101695,10 @@ SQLITE_PRIVATE void sqlite3TableLock(
    +     p->iDb = iDb;
    +     p->iTab = iTab;
    +     p->isWriteLock = isWriteLock;
    +-    p->zName = zName;
    ++    p->zLockName = zName;
    +   }else{
    +     pToplevel->nTableLock = 0;
    +-    pToplevel->db->mallocFailed = 1;
    ++    sqlite3OomFault(pToplevel->db);
    +   }
    + }
    + 
    +@@ -92888,7 +101717,7 @@ static void codeTableLocks(Parse *pParse){
    +     TableLock *p = &pParse->aTableLock[i];
    +     int p1 = p->iDb;
    +     sqlite3VdbeAddOp4(pVdbe, OP_TableLock, p1, p->iTab, p->isWriteLock,
    +-                      p->zName, P4_STATIC);
    ++                      p->zLockName, P4_STATIC);
    +   }
    + }
    + #else
    +@@ -92937,15 +101766,14 @@ SQLITE_PRIVATE void sqlite3FinishCoding(Parse *pParse){
    +   assert( !pParse->isMultiWrite 
    +        || sqlite3VdbeAssertMayAbort(v, pParse->mayAbort));
    +   if( v ){
    +-    while( sqlite3VdbeDeletePriorOpcode(v, OP_Close) ){}
    +     sqlite3VdbeAddOp0(v, OP_Halt);
    + 
    + #if SQLITE_USER_AUTHENTICATION
    +     if( pParse->nTableLock>0 && db->init.busy==0 ){
    +       sqlite3UserAuthInit(db);
    +       if( db->auth.authLevel<UAUTH_User ){
    +-        pParse->rc = SQLITE_AUTH_USER;
    +         sqlite3ErrorMsg(pParse, "user not authenticated");
    ++        pParse->rc = SQLITE_AUTH_USER;
    +         return;
    +       }
    +     }
    +@@ -92964,14 +101792,16 @@ SQLITE_PRIVATE void sqlite3FinishCoding(Parse *pParse){
    +       assert( sqlite3VdbeGetOp(v, 0)->opcode==OP_Init );
    +       sqlite3VdbeJumpHere(v, 0);
    +       for(iDb=0; iDb<db->nDb; iDb++){
    ++        Schema *pSchema;
    +         if( DbMaskTest(pParse->cookieMask, iDb)==0 ) continue;
    +         sqlite3VdbeUsesBtree(v, iDb);
    ++        pSchema = db->aDb[iDb].pSchema;
    +         sqlite3VdbeAddOp4Int(v,
    +           OP_Transaction,                    /* Opcode */
    +           iDb,                               /* P1 */
    +           DbMaskTest(pParse->writeMask,iDb), /* P2 */
    +-          pParse->cookieValue[iDb],          /* P3 */
    +-          db->aDb[iDb].pSchema->iGeneration  /* P4 */
    ++          pSchema->schema_cookie,            /* P3 */
    ++          pSchema->iGeneration               /* P4 */
    +         );
    +         if( db->init.busy==0 ) sqlite3VdbeChangeP5(v, 1);
    +         VdbeComment((v,
    +@@ -93019,15 +101849,9 @@ SQLITE_PRIVATE void sqlite3FinishCoding(Parse *pParse){
    +     if( pParse->pAinc!=0 && pParse->nTab==0 ) pParse->nTab = 1;
    +     sqlite3VdbeMakeReady(v, pParse);
    +     pParse->rc = SQLITE_DONE;
    +-    pParse->colNamesSet = 0;
    +   }else{
    +     pParse->rc = SQLITE_ERROR;
    +   }
    +-  pParse->nTab = 0;
    +-  pParse->nMem = 0;
    +-  pParse->nSet = 0;
    +-  pParse->nVar = 0;
    +-  DbMaskZero(pParse->cookieMask);
    + }
    + 
    + /*
    +@@ -93047,8 +101871,7 @@ SQLITE_PRIVATE void sqlite3NestedParse(Parse *pParse, const char *zFormat, ...){
    +   char *zSql;
    +   char *zErrMsg = 0;
    +   sqlite3 *db = pParse->db;
    +-# define SAVE_SZ  (sizeof(Parse) - offsetof(Parse,nVar))
    +-  char saveBuf[SAVE_SZ];
    ++  char saveBuf[PARSE_TAIL_SZ];
    + 
    +   if( pParse->nErr ) return;
    +   assert( pParse->nested<10 );  /* Nesting should only be of limited depth */
    +@@ -93059,12 +101882,12 @@ SQLITE_PRIVATE void sqlite3NestedParse(Parse *pParse, const char *zFormat, ...){
    +     return;   /* A malloc must have failed */
    +   }
    +   pParse->nested++;
    +-  memcpy(saveBuf, &pParse->nVar, SAVE_SZ);
    +-  memset(&pParse->nVar, 0, SAVE_SZ);
    ++  memcpy(saveBuf, PARSE_TAIL(pParse), PARSE_TAIL_SZ);
    ++  memset(PARSE_TAIL(pParse), 0, PARSE_TAIL_SZ);
    +   sqlite3RunParser(pParse, zSql, &zErrMsg);
    +   sqlite3DbFree(db, zErrMsg);
    +   sqlite3DbFree(db, zSql);
    +-  memcpy(&pParse->nVar, saveBuf, SAVE_SZ);
    ++  memcpy(PARSE_TAIL(pParse), saveBuf, PARSE_TAIL_SZ);
    +   pParse->nested--;
    + }
    + 
    +@@ -93103,14 +101926,22 @@ SQLITE_PRIVATE Table *sqlite3FindTable(sqlite3 *db, const char *zName, const cha
    +     return 0;
    +   }
    + #endif
    +-  for(i=OMIT_TEMPDB; i<db->nDb; i++){
    +-    int j = (i<2) ? i^1 : i;   /* Search TEMP before MAIN */
    +-    if( zDatabase!=0 && sqlite3StrICmp(zDatabase, db->aDb[j].zName) ) continue;
    +-    assert( sqlite3SchemaMutexHeld(db, j, 0) );
    +-    p = sqlite3HashFind(&db->aDb[j].pSchema->tblHash, zName);
    +-    if( p ) break;
    ++  while(1){
    ++    for(i=OMIT_TEMPDB; i<db->nDb; i++){
    ++      int j = (i<2) ? i^1 : i;   /* Search TEMP before MAIN */
    ++      if( zDatabase==0 || sqlite3StrICmp(zDatabase, db->aDb[j].zDbSName)==0 ){
    ++        assert( sqlite3SchemaMutexHeld(db, j, 0) );
    ++        p = sqlite3HashFind(&db->aDb[j].pSchema->tblHash, zName);
    ++        if( p ) return p;
    ++      }
    ++    }
    ++    /* Not found.  If the name we were looking for was temp.sqlite_master
    ++    ** then change the name to sqlite_temp_master and try again. */
    ++    if( sqlite3StrICmp(zName, MASTER_NAME)!=0 ) break;
    ++    if( sqlite3_stricmp(zDatabase, db->aDb[1].zDbSName)!=0 ) break;
    ++    zName = TEMP_MASTER_NAME;
    +   }
    +-  return p;
    ++  return 0;
    + }
    + 
    + /*
    +@@ -93125,7 +101956,7 @@ SQLITE_PRIVATE Table *sqlite3FindTable(sqlite3 *db, const char *zName, const cha
    + */
    + SQLITE_PRIVATE Table *sqlite3LocateTable(
    +   Parse *pParse,         /* context in which to report errors */
    +-  int isView,            /* True if looking for a VIEW rather than a TABLE */
    ++  u32 flags,             /* LOCATE_VIEW or LOCATE_NOERR */
    +   const char *zName,     /* Name of the table we are looking for */
    +   const char *zDbase     /* Name of the database.  Might be NULL */
    + ){
    +@@ -93139,31 +101970,31 @@ SQLITE_PRIVATE Table *sqlite3LocateTable(
    + 
    +   p = sqlite3FindTable(pParse->db, zName, zDbase);
    +   if( p==0 ){
    +-    const char *zMsg = isView ? "no such view" : "no such table";
    ++    const char *zMsg = flags & LOCATE_VIEW ? "no such view" : "no such table";
    + #ifndef SQLITE_OMIT_VIRTUALTABLE
    +     if( sqlite3FindDbName(pParse->db, zDbase)<1 ){
    +       /* If zName is the not the name of a table in the schema created using
    +       ** CREATE, then check to see if it is the name of an virtual table that
    +       ** can be an eponymous virtual table. */
    +       Module *pMod = (Module*)sqlite3HashFind(&pParse->db->aModule, zName);
    ++      if( pMod==0 && sqlite3_strnicmp(zName, "pragma_", 7)==0 ){
    ++        pMod = sqlite3PragmaVtabRegister(pParse->db, zName);
    ++      }
    +       if( pMod && sqlite3VtabEponymousTableInit(pParse, pMod) ){
    +         return pMod->pEpoTab;
    +       }
    +     }
    + #endif
    +-    if( zDbase ){
    +-      sqlite3ErrorMsg(pParse, "%s: %s.%s", zMsg, zDbase, zName);
    +-    }else{
    +-      sqlite3ErrorMsg(pParse, "%s: %s", zMsg, zName);
    ++    if( (flags & LOCATE_NOERR)==0 ){
    ++      if( zDbase ){
    ++        sqlite3ErrorMsg(pParse, "%s: %s.%s", zMsg, zDbase, zName);
    ++      }else{
    ++        sqlite3ErrorMsg(pParse, "%s: %s", zMsg, zName);
    ++      }
    ++      pParse->checkSchema = 1;
    +     }
    +-    pParse->checkSchema = 1;
    +   }
    +-#if SQLITE_USER_AUTHENTICATION
    +-  else if( pParse->db->auth.authLevel<UAUTH_User ){
    +-    sqlite3ErrorMsg(pParse, "user not authenticated");
    +-    p = 0;
    +-  }
    +-#endif
    ++
    +   return p;
    + }
    + 
    +@@ -93178,18 +102009,18 @@ SQLITE_PRIVATE Table *sqlite3LocateTable(
    + */
    + SQLITE_PRIVATE Table *sqlite3LocateTableItem(
    +   Parse *pParse, 
    +-  int isView, 
    ++  u32 flags,
    +   struct SrcList_item *p
    + ){
    +   const char *zDb;
    +   assert( p->pSchema==0 || p->zDatabase==0 );
    +   if( p->pSchema ){
    +     int iDb = sqlite3SchemaToIndex(pParse->db, p->pSchema);
    +-    zDb = pParse->db->aDb[iDb].zName;
    ++    zDb = pParse->db->aDb[iDb].zDbSName;
    +   }else{
    +     zDb = p->zDatabase;
    +   }
    +-  return sqlite3LocateTable(pParse, isView, p->zName, zDb);
    ++  return sqlite3LocateTable(pParse, flags, p->zName, zDb);
    + }
    + 
    + /*
    +@@ -93213,7 +102044,7 @@ SQLITE_PRIVATE Index *sqlite3FindIndex(sqlite3 *db, const char *zName, const cha
    +     int j = (i<2) ? i^1 : i;  /* Search TEMP before MAIN */
    +     Schema *pSchema = db->aDb[j].pSchema;
    +     assert( pSchema );
    +-    if( zDb && sqlite3StrICmp(zDb, db->aDb[j].zName) ) continue;
    ++    if( zDb && sqlite3StrICmp(zDb, db->aDb[j].zDbSName) ) continue;
    +     assert( sqlite3SchemaMutexHeld(db, j, 0) );
    +     p = sqlite3HashFind(&pSchema->idxHash, zName);
    +     if( p ) break;
    +@@ -93231,7 +102062,7 @@ static void freeIndex(sqlite3 *db, Index *p){
    +   sqlite3ExprDelete(db, p->pPartIdxWhere);
    +   sqlite3ExprListDelete(db, p->aColExpr);
    +   sqlite3DbFree(db, p->zColAff);
    +-  if( p->isResized ) sqlite3DbFree(db, p->azColl);
    ++  if( p->isResized ) sqlite3DbFree(db, (void *)p->azColl);
    + #ifdef SQLITE_ENABLE_STAT3_OR_STAT4
    +   sqlite3_free(p->aiRowEst);
    + #endif
    +@@ -93266,7 +102097,7 @@ SQLITE_PRIVATE void sqlite3UnlinkAndDeleteIndex(sqlite3 *db, int iDb, const char
    +     }
    +     freeIndex(db, pIndex);
    +   }
    +-  db->flags |= SQLITE_InternChanges;
    ++  db->mDbFlags |= DBFLAG_SchemaChange;
    + }
    + 
    + /*
    +@@ -93282,8 +102113,8 @@ SQLITE_PRIVATE void sqlite3CollapseDatabaseArray(sqlite3 *db){
    +   for(i=j=2; i<db->nDb; i++){
    +     struct Db *pDb = &db->aDb[i];
    +     if( pDb->pBt==0 ){
    +-      sqlite3DbFree(db, pDb->zName);
    +-      pDb->zName = 0;
    ++      sqlite3DbFree(db, pDb->zDbSName);
    ++      pDb->zDbSName = 0;
    +       continue;
    +     }
    +     if( j<i ){
    +@@ -93291,7 +102122,6 @@ SQLITE_PRIVATE void sqlite3CollapseDatabaseArray(sqlite3 *db){
    +     }
    +     j++;
    +   }
    +-  memset(&db->aDb[j], 0, (db->nDb-j)*sizeof(db->aDb[j]));
    +   db->nDb = j;
    +   if( db->nDb<=2 && db->aDb!=db->aDbStatic ){
    +     memcpy(db->aDbStatic, db->aDb, 2*sizeof(db->aDb[0]));
    +@@ -93302,28 +102132,26 @@ SQLITE_PRIVATE void sqlite3CollapseDatabaseArray(sqlite3 *db){
    + 
    + /*
    + ** Reset the schema for the database at index iDb.  Also reset the
    +-** TEMP schema.
    ++** TEMP schema.  The reset is deferred if db->nSchemaLock is not zero.
    ++** Deferred resets may be run by calling with iDb<0.
    + */
    + SQLITE_PRIVATE void sqlite3ResetOneSchema(sqlite3 *db, int iDb){
    +-  Db *pDb;
    ++  int i;
    +   assert( iDb<db->nDb );
    + 
    +-  /* Case 1:  Reset the single schema identified by iDb */
    +-  pDb = &db->aDb[iDb];
    +-  assert( sqlite3SchemaMutexHeld(db, iDb, 0) );
    +-  assert( pDb->pSchema!=0 );
    +-  sqlite3SchemaClear(pDb->pSchema);
    ++  if( iDb>=0 ){
    ++    assert( sqlite3SchemaMutexHeld(db, iDb, 0) );
    ++    DbSetProperty(db, iDb, DB_ResetWanted);
    ++    DbSetProperty(db, 1, DB_ResetWanted);
    ++  }
    + 
    +-  /* If any database other than TEMP is reset, then also reset TEMP
    +-  ** since TEMP might be holding triggers that reference tables in the
    +-  ** other database.
    +-  */
    +-  if( iDb!=1 ){
    +-    pDb = &db->aDb[1];
    +-    assert( pDb->pSchema!=0 );
    +-    sqlite3SchemaClear(pDb->pSchema);
    ++  if( db->nSchemaLock==0 ){
    ++    for(i=0; i<db->nDb; i++){
    ++      if( DbHasProperty(db, i, DB_ResetWanted) ){
    ++        sqlite3SchemaClear(db->aDb[i].pSchema);
    ++      }
    ++    }
    +   }
    +-  return;
    + }
    + 
    + /*
    +@@ -93333,13 +102161,14 @@ SQLITE_PRIVATE void sqlite3ResetOneSchema(sqlite3 *db, int iDb){
    + SQLITE_PRIVATE void sqlite3ResetAllSchemasOfConnection(sqlite3 *db){
    +   int i;
    +   sqlite3BtreeEnterAll(db);
    ++  assert( db->nSchemaLock==0 );
    +   for(i=0; i<db->nDb; i++){
    +     Db *pDb = &db->aDb[i];
    +     if( pDb->pSchema ){
    +       sqlite3SchemaClear(pDb->pSchema);
    +     }
    +   }
    +-  db->flags &= ~SQLITE_InternChanges;
    ++  db->mDbFlags &= ~DBFLAG_SchemaChange;
    +   sqlite3VtabUnlockList(db);
    +   sqlite3BtreeLeaveAll(db);
    +   sqlite3CollapseDatabaseArray(db);
    +@@ -93349,7 +102178,7 @@ SQLITE_PRIVATE void sqlite3ResetAllSchemasOfConnection(sqlite3 *db){
    + ** This routine is called when a commit occurs.
    + */
    + SQLITE_PRIVATE void sqlite3CommitInternalChanges(sqlite3 *db){
    +-  db->flags &= ~SQLITE_InternChanges;
    ++  db->mDbFlags &= ~DBFLAG_SchemaChange;
    + }
    + 
    + /*
    +@@ -93364,8 +102193,6 @@ SQLITE_PRIVATE void sqlite3DeleteColumnNames(sqlite3 *db, Table *pTable){
    +     for(i=0; i<pTable->nCol; i++, pCol++){
    +       sqlite3DbFree(db, pCol->zName);
    +       sqlite3ExprDelete(db, pCol->pDflt);
    +-      sqlite3DbFree(db, pCol->zDflt);
    +-      sqlite3DbFree(db, pCol->zType);
    +       sqlite3DbFree(db, pCol->zColl);
    +     }
    +     sqlite3DbFree(db, pTable->aCol);
    +@@ -93387,27 +102214,25 @@ SQLITE_PRIVATE void sqlite3DeleteColumnNames(sqlite3 *db, Table *pTable){
    + ** db parameter can be used with db->pnBytesFreed to measure the memory
    + ** used by the Table object.
    + */
    +-SQLITE_PRIVATE void sqlite3DeleteTable(sqlite3 *db, Table *pTable){
    ++static void SQLITE_NOINLINE deleteTable(sqlite3 *db, Table *pTable){
    +   Index *pIndex, *pNext;
    +-  TESTONLY( int nLookaside; ) /* Used to verify lookaside not used for schema */
    +-
    +-  assert( !pTable || pTable->nRef>0 );
    +-
    +-  /* Do not delete the table until the reference count reaches zero. */
    +-  if( !pTable ) return;
    +-  if( ((!db || db->pnBytesFreed==0) && (--pTable->nRef)>0) ) return;
    + 
    ++#ifdef SQLITE_DEBUG
    +   /* Record the number of outstanding lookaside allocations in schema Tables
    +   ** prior to doing any free() operations.  Since schema Tables do not use
    +   ** lookaside, this number should not change. */
    +-  TESTONLY( nLookaside = (db && (pTable->tabFlags & TF_Ephemeral)==0) ?
    +-                         db->lookaside.nOut : 0 );
    ++  int nLookaside = 0;
    ++  if( db && (pTable->tabFlags & TF_Ephemeral)==0 ){
    ++    nLookaside = sqlite3LookasideUsed(db, 0);
    ++  }
    ++#endif
    + 
    +   /* Delete all indices associated with this table. */
    +   for(pIndex = pTable->pIndex; pIndex; pIndex=pNext){
    +     pNext = pIndex->pNext;
    +-    assert( pIndex->pSchema==pTable->pSchema );
    +-    if( !db || db->pnBytesFreed==0 ){
    ++    assert( pIndex->pSchema==pTable->pSchema
    ++         || (IsVirtual(pTable) && pIndex->idxType!=SQLITE_IDXTYPE_APPDEF) );
    ++    if( (db==0 || db->pnBytesFreed==0) && !IsVirtual(pTable) ){
    +       char *zName = pIndex->zName; 
    +       TESTONLY ( Index *pOld = ) sqlite3HashInsert(
    +          &pIndex->pSchema->idxHash, zName, 0
    +@@ -93434,9 +102259,16 @@ SQLITE_PRIVATE void sqlite3DeleteTable(sqlite3 *db, Table *pTable){
    +   sqlite3DbFree(db, pTable);
    + 
    +   /* Verify that no lookaside memory was used by schema tables */
    +-  assert( nLookaside==0 || nLookaside==db->lookaside.nOut );
    ++  assert( nLookaside==0 || nLookaside==sqlite3LookasideUsed(db,0) );
    ++}
    ++SQLITE_PRIVATE void sqlite3DeleteTable(sqlite3 *db, Table *pTable){
    ++  /* Do not delete the table until the reference count reaches zero. */
    ++  if( !pTable ) return;
    ++  if( ((!db || db->pnBytesFreed==0) && (--pTable->nTabRef)>0) ) return;
    ++  deleteTable(db, pTable);
    + }
    + 
    ++
    + /*
    + ** Unlink the given table from the hash tables and the delete the
    + ** table structure with all its indices and foreign keys.
    +@@ -93453,7 +102285,7 @@ SQLITE_PRIVATE void sqlite3UnlinkAndDeleteTable(sqlite3 *db, int iDb, const char
    +   pDb = &db->aDb[iDb];
    +   p = sqlite3HashInsert(&pDb->pSchema->tblHash, zTabName, 0);
    +   sqlite3DeleteTable(db, p);
    +-  db->flags |= SQLITE_InternChanges;
    ++  db->mDbFlags |= DBFLAG_SchemaChange;
    + }
    + 
    + /*
    +@@ -93486,7 +102318,7 @@ SQLITE_PRIVATE char *sqlite3NameFromToken(sqlite3 *db, Token *pName){
    + */
    + SQLITE_PRIVATE void sqlite3OpenMasterTable(Parse *p, int iDb){
    +   Vdbe *v = sqlite3GetVdbe(p);
    +-  sqlite3TableLock(p, iDb, MASTER_ROOT, 1, SCHEMA_TABLE(iDb));
    ++  sqlite3TableLock(p, iDb, MASTER_ROOT, 1, MASTER_NAME);
    +   sqlite3VdbeAddOp4Int(v, OP_OpenWrite, 0, MASTER_ROOT, iDb, 5);
    +   if( p->nTab==0 ){
    +     p->nTab = 1;
    +@@ -93503,12 +102335,11 @@ SQLITE_PRIVATE int sqlite3FindDbName(sqlite3 *db, const char *zName){
    +   int i = -1;         /* Database number */
    +   if( zName ){
    +     Db *pDb;
    +-    int n = sqlite3Strlen30(zName);
    +     for(i=(db->nDb-1), pDb=&db->aDb[i]; i>=0; i--, pDb--){
    +-      if( (!OMIT_TEMPDB || i!=1 ) && n==sqlite3Strlen30(pDb->zName) && 
    +-          0==sqlite3StrICmp(pDb->zName, zName) ){
    +-        break;
    +-      }
    ++      if( 0==sqlite3_stricmp(pDb->zDbSName, zName) ) break;
    ++      /* "main" is always an acceptable alias for the primary database
    ++      ** even if it has been renamed using SQLITE_DBCONFIG_MAINDBNAME. */
    ++      if( i==0 && 0==sqlite3_stricmp("main", zName) ) break;
    +     }
    +   }
    +   return i;
    +@@ -93554,7 +102385,8 @@ SQLITE_PRIVATE int sqlite3TwoPartName(
    +   int iDb;                    /* Database holding the object */
    +   sqlite3 *db = pParse->db;
    + 
    +-  if( ALWAYS(pName2!=0) && pName2->n>0 ){
    ++  assert( pName2!=0 );
    ++  if( pName2->n>0 ){
    +     if( db->init.busy ) {
    +       sqlite3ErrorMsg(pParse, "corrupt database");
    +       return -1;
    +@@ -93566,7 +102398,8 @@ SQLITE_PRIVATE int sqlite3TwoPartName(
    +       return -1;
    +     }
    +   }else{
    +-    assert( db->init.iDb==0 || db->init.busy );
    ++    assert( db->init.iDb==0 || db->init.busy
    ++             || (db->mDbFlags & DBFLAG_Vacuum)!=0);
    +     iDb = db->init.iDb;
    +     *pUnqual = pName1;
    +   }
    +@@ -93643,62 +102476,46 @@ SQLITE_PRIVATE void sqlite3StartTable(
    +   int iDb;         /* Database number to create the table in */
    +   Token *pName;    /* Unqualified name of the table to create */
    + 
    +-  /* The table or view name to create is passed to this routine via tokens
    +-  ** pName1 and pName2. If the table name was fully qualified, for example:
    +-  **
    +-  ** CREATE TABLE xxx.yyy (...);
    +-  ** 
    +-  ** Then pName1 is set to "xxx" and pName2 "yyy". On the other hand if
    +-  ** the table name is not fully qualified, i.e.:
    +-  **
    +-  ** CREATE TABLE yyy(...);
    +-  **
    +-  ** Then pName1 is set to "yyy" and pName2 is "".
    +-  **
    +-  ** The call below sets the pName pointer to point at the token (pName1 or
    +-  ** pName2) that stores the unqualified table name. The variable iDb is
    +-  ** set to the index of the database that the table or view is to be
    +-  ** created in.
    +-  */
    +-  iDb = sqlite3TwoPartName(pParse, pName1, pName2, &pName);
    +-  if( iDb<0 ) return;
    +-  if( !OMIT_TEMPDB && isTemp && pName2->n>0 && iDb!=1 ){
    +-    /* If creating a temp table, the name may not be qualified. Unless 
    +-    ** the database name is "temp" anyway.  */
    +-    sqlite3ErrorMsg(pParse, "temporary table name must be unqualified");
    +-    return;
    ++  if( db->init.busy && db->init.newTnum==1 ){
    ++    /* Special case:  Parsing the sqlite_master or sqlite_temp_master schema */
    ++    iDb = db->init.iDb;
    ++    zName = sqlite3DbStrDup(db, SCHEMA_TABLE(iDb));
    ++    pName = pName1;
    ++  }else{
    ++    /* The common case */
    ++    iDb = sqlite3TwoPartName(pParse, pName1, pName2, &pName);
    ++    if( iDb<0 ) return;
    ++    if( !OMIT_TEMPDB && isTemp && pName2->n>0 && iDb!=1 ){
    ++      /* If creating a temp table, the name may not be qualified. Unless 
    ++      ** the database name is "temp" anyway.  */
    ++      sqlite3ErrorMsg(pParse, "temporary table name must be unqualified");
    ++      return;
    ++    }
    ++    if( !OMIT_TEMPDB && isTemp ) iDb = 1;
    ++    zName = sqlite3NameFromToken(db, pName);
    +   }
    +-  if( !OMIT_TEMPDB && isTemp ) iDb = 1;
    +-
    +   pParse->sNameToken = *pName;
    +-  zName = sqlite3NameFromToken(db, pName);
    +   if( zName==0 ) return;
    +   if( SQLITE_OK!=sqlite3CheckObjectName(pParse, zName) ){
    +     goto begin_table_error;
    +   }
    +   if( db->init.iDb==1 ) isTemp = 1;
    + #ifndef SQLITE_OMIT_AUTHORIZATION
    +-  assert( (isTemp & 1)==isTemp );
    ++  assert( isTemp==0 || isTemp==1 );
    ++  assert( isView==0 || isView==1 );
    +   {
    +-    int code;
    +-    char *zDb = db->aDb[iDb].zName;
    ++    static const u8 aCode[] = {
    ++       SQLITE_CREATE_TABLE,
    ++       SQLITE_CREATE_TEMP_TABLE,
    ++       SQLITE_CREATE_VIEW,
    ++       SQLITE_CREATE_TEMP_VIEW
    ++    };
    ++    char *zDb = db->aDb[iDb].zDbSName;
    +     if( sqlite3AuthCheck(pParse, SQLITE_INSERT, SCHEMA_TABLE(isTemp), 0, zDb) ){
    +       goto begin_table_error;
    +     }
    +-    if( isView ){
    +-      if( !OMIT_TEMPDB && isTemp ){
    +-        code = SQLITE_CREATE_TEMP_VIEW;
    +-      }else{
    +-        code = SQLITE_CREATE_VIEW;
    +-      }
    +-    }else{
    +-      if( !OMIT_TEMPDB && isTemp ){
    +-        code = SQLITE_CREATE_TEMP_TABLE;
    +-      }else{
    +-        code = SQLITE_CREATE_TABLE;
    +-      }
    +-    }
    +-    if( !isVirtual && sqlite3AuthCheck(pParse, code, zName, 0, zDb) ){
    ++    if( !isVirtual && sqlite3AuthCheck(pParse, (int)aCode[isTemp+2*isView],
    ++                                       zName, 0, zDb) ){
    +       goto begin_table_error;
    +     }
    +   }
    +@@ -93712,7 +102529,7 @@ SQLITE_PRIVATE void sqlite3StartTable(
    +   ** collisions.
    +   */
    +   if( !IN_DECLARE_VTAB ){
    +-    char *zDb = db->aDb[iDb].zName;
    ++    char *zDb = db->aDb[iDb].zDbSName;
    +     if( SQLITE_OK!=sqlite3ReadSchema(pParse) ){
    +       goto begin_table_error;
    +     }
    +@@ -93734,16 +102551,20 @@ SQLITE_PRIVATE void sqlite3StartTable(
    + 
    +   pTable = sqlite3DbMallocZero(db, sizeof(Table));
    +   if( pTable==0 ){
    +-    db->mallocFailed = 1;
    +-    pParse->rc = SQLITE_NOMEM;
    ++    assert( db->mallocFailed );
    ++    pParse->rc = SQLITE_NOMEM_BKPT;
    +     pParse->nErr++;
    +     goto begin_table_error;
    +   }
    +   pTable->zName = zName;
    +   pTable->iPKey = -1;
    +   pTable->pSchema = db->aDb[iDb].pSchema;
    +-  pTable->nRef = 1;
    ++  pTable->nTabRef = 1;
    ++#ifdef SQLITE_DEFAULT_ROWEST
    ++  pTable->nRowLogEst = sqlite3LogEst(SQLITE_DEFAULT_ROWEST);
    ++#else
    +   pTable->nRowLogEst = 200; assert( 200==sqlite3LogEst(1048576) );
    ++#endif
    +   assert( pParse->pNewTable==0 );
    +   pParse->pNewTable = pTable;
    + 
    +@@ -93791,10 +102612,8 @@ SQLITE_PRIVATE void sqlite3StartTable(
    +     addr1 = sqlite3VdbeAddOp1(v, OP_If, reg3); VdbeCoverage(v);
    +     fileFormat = (db->flags & SQLITE_LegacyFileFmt)!=0 ?
    +                   1 : SQLITE_MAX_FILE_FORMAT;
    +-    sqlite3VdbeAddOp2(v, OP_Integer, fileFormat, reg3);
    +-    sqlite3VdbeAddOp3(v, OP_SetCookie, iDb, BTREE_FILE_FORMAT, reg3);
    +-    sqlite3VdbeAddOp2(v, OP_Integer, ENC(db), reg3);
    +-    sqlite3VdbeAddOp3(v, OP_SetCookie, iDb, BTREE_TEXT_ENCODING, reg3);
    ++    sqlite3VdbeAddOp3(v, OP_SetCookie, iDb, BTREE_FILE_FORMAT, fileFormat);
    ++    sqlite3VdbeAddOp3(v, OP_SetCookie, iDb, BTREE_TEXT_ENCODING, ENC(db));
    +     sqlite3VdbeJumpHere(v, addr1);
    + 
    +     /* This just creates a place-holder record in the sqlite_master table.
    +@@ -93812,7 +102631,8 @@ SQLITE_PRIVATE void sqlite3StartTable(
    +     }else
    + #endif
    +     {
    +-      pParse->addrCrTab = sqlite3VdbeAddOp2(v, OP_CreateTable, iDb, reg2);
    ++      pParse->addrCrTab =
    ++         sqlite3VdbeAddOp3(v, OP_CreateBtree, iDb, reg2, BTREE_INTKEY);
    +     }
    +     sqlite3OpenMasterTable(pParse, iDb);
    +     sqlite3VdbeAddOp2(v, OP_NewRowid, 0, reg1);
    +@@ -93831,18 +102651,19 @@ begin_table_error:
    +   return;
    + }
    + 
    +-/*
    +-** This macro is used to compare two strings in a case-insensitive manner.
    +-** It is slightly faster than calling sqlite3StrICmp() directly, but
    +-** produces larger code.
    +-**
    +-** WARNING: This macro is not compatible with the strcmp() family. It
    +-** returns true if the two strings are equal, otherwise false.
    ++/* Set properties of a table column based on the (magical)
    ++** name of the column.
    + */
    +-#define STRICMP(x, y) (\
    +-sqlite3UpperToLower[*(unsigned char *)(x)]==   \
    +-sqlite3UpperToLower[*(unsigned char *)(y)]     \
    +-&& sqlite3StrICmp((x)+1,(y)+1)==0 )
    ++#if SQLITE_ENABLE_HIDDEN_COLUMNS
    ++SQLITE_PRIVATE void sqlite3ColumnPropertiesFromName(Table *pTab, Column *pCol){
    ++  if( sqlite3_strnicmp(pCol->zName, "__hidden__", 10)==0 ){
    ++    pCol->colFlags |= COLFLAG_HIDDEN;
    ++  }else if( pTab && pCol!=pTab->aCol && (pCol[-1].colFlags & COLFLAG_HIDDEN) ){
    ++    pTab->tabFlags |= TF_OOOHidden;
    ++  }
    ++}
    ++#endif
    ++
    + 
    + /*
    + ** Add a new column to the table currently being constructed.
    +@@ -93852,23 +102673,25 @@ sqlite3UpperToLower[*(unsigned char *)(y)]     \
    + ** first to get things going.  Then this routine is called for each
    + ** column.
    + */
    +-SQLITE_PRIVATE void sqlite3AddColumn(Parse *pParse, Token *pName){
    ++SQLITE_PRIVATE void sqlite3AddColumn(Parse *pParse, Token *pName, Token *pType){
    +   Table *p;
    +   int i;
    +   char *z;
    ++  char *zType;
    +   Column *pCol;
    +   sqlite3 *db = pParse->db;
    +   if( (p = pParse->pNewTable)==0 ) return;
    +-#if SQLITE_MAX_COLUMN
    +   if( p->nCol+1>db->aLimit[SQLITE_LIMIT_COLUMN] ){
    +     sqlite3ErrorMsg(pParse, "too many columns on %s", p->zName);
    +     return;
    +   }
    +-#endif
    +-  z = sqlite3NameFromToken(db, pName);
    ++  z = sqlite3DbMallocRaw(db, pName->n + pType->n + 2);
    +   if( z==0 ) return;
    ++  memcpy(z, pName->z, pName->n);
    ++  z[pName->n] = 0;
    ++  sqlite3Dequote(z);
    +   for(i=0; i<p->nCol; i++){
    +-    if( STRICMP(z, p->aCol[i].zName) ){
    ++    if( sqlite3_stricmp(z, p->aCol[i].zName)==0 ){
    +       sqlite3ErrorMsg(pParse, "duplicate column name: %s", z);
    +       sqlite3DbFree(db, z);
    +       return;
    +@@ -93886,14 +102709,23 @@ SQLITE_PRIVATE void sqlite3AddColumn(Parse *pParse, Token *pName){
    +   pCol = &p->aCol[p->nCol];
    +   memset(pCol, 0, sizeof(p->aCol[0]));
    +   pCol->zName = z;
    ++  sqlite3ColumnPropertiesFromName(p, pCol);
    +  
    +-  /* If there is no type specified, columns have the default affinity
    +-  ** 'BLOB'. If there is a type specified, then sqlite3AddColumnType() will
    +-  ** be called next to set pCol->affinity correctly.
    +-  */
    +-  pCol->affinity = SQLITE_AFF_BLOB;
    +-  pCol->szEst = 1;
    ++  if( pType->n==0 ){
    ++    /* If there is no type specified, columns have the default affinity
    ++    ** 'BLOB'. */
    ++    pCol->affinity = SQLITE_AFF_BLOB;
    ++    pCol->szEst = 1;
    ++  }else{
    ++    zType = z + sqlite3Strlen30(z) + 1;
    ++    memcpy(zType, pType->z, pType->n);
    ++    zType[pType->n] = 0;
    ++    sqlite3Dequote(zType);
    ++    pCol->affinity = sqlite3AffinityType(zType, &pCol->szEst);
    ++    pCol->colFlags |= COLFLAG_HASTYPE;
    ++  }
    +   p->nCol++;
    ++  pParse->constraintName.n = 0;
    + }
    + 
    + /*
    +@@ -93907,6 +102739,7 @@ SQLITE_PRIVATE void sqlite3AddNotNull(Parse *pParse, int onError){
    +   p = pParse->pNewTable;
    +   if( p==0 || NEVER(p->nCol<1) ) return;
    +   p->aCol[p->nCol-1].notNull = (u8)onError;
    ++  p->tabFlags |= TF_HasNotNull;
    + }
    + 
    + /*
    +@@ -93939,7 +102772,7 @@ SQLITE_PRIVATE char sqlite3AffinityType(const char *zIn, u8 *pszEst){
    +   char aff = SQLITE_AFF_NUMERIC;
    +   const char *zChar = 0;
    + 
    +-  if( zIn==0 ) return aff;
    ++  assert( zIn!=0 );
    +   while( zIn[0] ){
    +     h = (h<<8) + sqlite3UpperToLower[(*zIn)&0xff];
    +     zIn++;
    +@@ -93996,28 +102829,6 @@ SQLITE_PRIVATE char sqlite3AffinityType(const char *zIn, u8 *pszEst){
    +   return aff;
    + }
    + 
    +-/*
    +-** This routine is called by the parser while in the middle of
    +-** parsing a CREATE TABLE statement.  The pFirst token is the first
    +-** token in the sequence of tokens that describe the type of the
    +-** column currently under construction.   pLast is the last token
    +-** in the sequence.  Use this information to construct a string
    +-** that contains the typename of the column and store that string
    +-** in zType.
    +-*/ 
    +-SQLITE_PRIVATE void sqlite3AddColumnType(Parse *pParse, Token *pType){
    +-  Table *p;
    +-  Column *pCol;
    +-
    +-  p = pParse->pNewTable;
    +-  if( p==0 || NEVER(p->nCol<1) ) return;
    +-  pCol = &p->aCol[p->nCol-1];
    +-  assert( pCol->zType==0 || CORRUPT_DB );
    +-  sqlite3DbFree(pParse->db, pCol->zType);
    +-  pCol->zType = sqlite3NameFromToken(pParse->db, pType);
    +-  pCol->affinity = sqlite3AffinityType(pCol->zType, &pCol->szEst);
    +-}
    +-
    + /*
    + ** The expression is the default value for the most recently added column
    + ** of the table currently under construction.
    +@@ -94028,29 +102839,37 @@ SQLITE_PRIVATE void sqlite3AddColumnType(Parse *pParse, Token *pType){
    + ** This routine is called by the parser while in the middle of
    + ** parsing a CREATE TABLE statement.
    + */
    +-SQLITE_PRIVATE void sqlite3AddDefaultValue(Parse *pParse, ExprSpan *pSpan){
    ++SQLITE_PRIVATE void sqlite3AddDefaultValue(
    ++  Parse *pParse,           /* Parsing context */
    ++  Expr *pExpr,             /* The parsed expression of the default value */
    ++  const char *zStart,      /* Start of the default value text */
    ++  const char *zEnd         /* First character past end of defaut value text */
    ++){
    +   Table *p;
    +   Column *pCol;
    +   sqlite3 *db = pParse->db;
    +   p = pParse->pNewTable;
    +   if( p!=0 ){
    +     pCol = &(p->aCol[p->nCol-1]);
    +-    if( !sqlite3ExprIsConstantOrFunction(pSpan->pExpr, db->init.busy) ){
    ++    if( !sqlite3ExprIsConstantOrFunction(pExpr, db->init.busy) ){
    +       sqlite3ErrorMsg(pParse, "default value of column [%s] is not constant",
    +           pCol->zName);
    +     }else{
    +       /* A copy of pExpr is used instead of the original, as pExpr contains
    +-      ** tokens that point to volatile memory. The 'span' of the expression
    +-      ** is required by pragma table_info.
    ++      ** tokens that point to volatile memory.	
    +       */
    ++      Expr x;
    +       sqlite3ExprDelete(db, pCol->pDflt);
    +-      pCol->pDflt = sqlite3ExprDup(db, pSpan->pExpr, EXPRDUP_REDUCE);
    +-      sqlite3DbFree(db, pCol->zDflt);
    +-      pCol->zDflt = sqlite3DbStrNDup(db, (char*)pSpan->zStart,
    +-                                     (int)(pSpan->zEnd - pSpan->zStart));
    ++      memset(&x, 0, sizeof(x));
    ++      x.op = TK_SPAN;
    ++      x.u.zToken = sqlite3DbSpanDup(db, zStart, zEnd);
    ++      x.pLeft = pExpr;
    ++      x.flags = EP_Skip;
    ++      pCol->pDflt = sqlite3ExprDup(db, &x, EXPRDUP_REDUCE);
    ++      sqlite3DbFree(db, x.u.zToken);
    +     }
    +   }
    +-  sqlite3ExprDelete(db, pSpan->pExpr);
    ++  sqlite3ExprDelete(db, pExpr);
    + }
    + 
    + /*
    +@@ -94103,10 +102922,10 @@ SQLITE_PRIVATE void sqlite3AddPrimaryKey(
    +   int sortOrder     /* SQLITE_SO_ASC or SQLITE_SO_DESC */
    + ){
    +   Table *pTab = pParse->pNewTable;
    +-  char *zType = 0;
    ++  Column *pCol = 0;
    +   int iCol = -1, i;
    +   int nTerm;
    +-  if( pTab==0 || IN_DECLARE_VTAB ) goto primary_key_exit;
    ++  if( pTab==0 ) goto primary_key_exit;
    +   if( pTab->tabFlags & TF_HasPrimaryKey ){
    +     sqlite3ErrorMsg(pParse, 
    +       "table \"%s\" has more than one primary key", pTab->zName);
    +@@ -94115,8 +102934,8 @@ SQLITE_PRIVATE void sqlite3AddPrimaryKey(
    +   pTab->tabFlags |= TF_HasPrimaryKey;
    +   if( pList==0 ){
    +     iCol = pTab->nCol - 1;
    +-    pTab->aCol[iCol].colFlags |= COLFLAG_PRIMKEY;
    +-    zType = pTab->aCol[iCol].zType;
    ++    pCol = &pTab->aCol[iCol];
    ++    pCol->colFlags |= COLFLAG_PRIMKEY;
    +     nTerm = 1;
    +   }else{
    +     nTerm = pList->nExpr;
    +@@ -94128,8 +102947,8 @@ SQLITE_PRIVATE void sqlite3AddPrimaryKey(
    +         const char *zCName = pCExpr->u.zToken;
    +         for(iCol=0; iCol<pTab->nCol; iCol++){
    +           if( sqlite3StrICmp(zCName, pTab->aCol[iCol].zName)==0 ){
    +-            pTab->aCol[iCol].colFlags |= COLFLAG_PRIMKEY;
    +-            zType = pTab->aCol[iCol].zType;
    ++            pCol = &pTab->aCol[iCol];
    ++            pCol->colFlags |= COLFLAG_PRIMKEY;
    +             break;
    +           }
    +         }
    +@@ -94137,7 +102956,8 @@ SQLITE_PRIVATE void sqlite3AddPrimaryKey(
    +     }
    +   }
    +   if( nTerm==1
    +-   && zType && sqlite3StrICmp(zType, "INTEGER")==0
    ++   && pCol
    ++   && sqlite3StrICmp(sqlite3ColumnType(pCol,""), "INTEGER")==0
    +    && sortOrder!=SQLITE_SO_DESC
    +   ){
    +     pTab->iPKey = iCol;
    +@@ -94151,12 +102971,8 @@ SQLITE_PRIVATE void sqlite3AddPrimaryKey(
    +        "INTEGER PRIMARY KEY");
    + #endif
    +   }else{
    +-    Index *p;
    +-    p = sqlite3CreateIndex(pParse, 0, 0, 0, pList, onError, 0,
    +-                           0, sortOrder, 0);
    +-    if( p ){
    +-      p->idxType = SQLITE_IDXTYPE_PRIMARYKEY;
    +-    }
    ++    sqlite3CreateIndex(pParse, 0, 0, 0, pList, onError, 0,
    ++                           0, sortOrder, 0, SQLITE_IDXTYPE_PRIMARYKEY);
    +     pList = 0;
    +   }
    + 
    +@@ -94275,15 +103091,16 @@ SQLITE_PRIVATE CollSeq *sqlite3LocateCollSeq(Parse *pParse, const char *zName){
    + ** set back to prior value.  But schema changes are infrequent
    + ** and the probability of hitting the same cookie value is only
    + ** 1 chance in 2^32.  So we're safe enough.
    ++**
    ++** IMPLEMENTATION-OF: R-34230-56049 SQLite automatically increments
    ++** the schema-version whenever the schema changes.
    + */
    + SQLITE_PRIVATE void sqlite3ChangeCookie(Parse *pParse, int iDb){
    +-  int r1 = sqlite3GetTempReg(pParse);
    +   sqlite3 *db = pParse->db;
    +   Vdbe *v = pParse->pVdbe;
    +   assert( sqlite3SchemaMutexHeld(db, iDb, 0) );
    +-  sqlite3VdbeAddOp2(v, OP_Integer, db->aDb[iDb].pSchema->schema_cookie+1, r1);
    +-  sqlite3VdbeAddOp3(v, OP_SetCookie, iDb, BTREE_SCHEMA_VERSION, r1);
    +-  sqlite3ReleaseTempReg(pParse, r1);
    ++  sqlite3VdbeAddOp3(v, OP_SetCookie, iDb, BTREE_SCHEMA_VERSION, 
    ++                    db->aDb[iDb].pSchema->schema_cookie+1);
    + }
    + 
    + /*
    +@@ -94365,7 +103182,7 @@ static char *createTableStmt(sqlite3 *db, Table *p){
    +   n += 35 + 6*p->nCol;
    +   zStmt = sqlite3DbMallocRaw(0, n);
    +   if( zStmt==0 ){
    +-    db->mallocFailed = 1;
    ++    sqlite3OomFault(db);
    +     return 0;
    +   }
    +   sqlite3_snprintf(n, zStmt, "CREATE TABLE ");
    +@@ -94418,9 +103235,9 @@ static int resizeIndexObject(sqlite3 *db, Index *pIdx, int N){
    +   assert( pIdx->isResized==0 );
    +   nByte = (sizeof(char*) + sizeof(i16) + 1)*N;
    +   zExtra = sqlite3DbMallocZero(db, nByte);
    +-  if( zExtra==0 ) return SQLITE_NOMEM;
    ++  if( zExtra==0 ) return SQLITE_NOMEM_BKPT;
    +   memcpy(zExtra, pIdx->azColl, sizeof(char*)*pIdx->nColumn);
    +-  pIdx->azColl = (char**)zExtra;
    ++  pIdx->azColl = (const char**)zExtra;
    +   zExtra += sizeof(char*)*N;
    +   memcpy(zExtra, pIdx->aiColumn, sizeof(i16)*pIdx->nColumn);
    +   pIdx->aiColumn = (i16*)zExtra;
    +@@ -94475,21 +103292,22 @@ static int hasColumn(const i16 *aiCol, int nCol, int x){
    + ** are appropriate for a WITHOUT ROWID table instead of a rowid table.
    + ** Changes include:
    + **
    +-**     (1)  Convert the OP_CreateTable into an OP_CreateIndex.  There is
    +-**          no rowid btree for a WITHOUT ROWID.  Instead, the canonical
    +-**          data storage is a covering index btree.
    +-**     (2)  Bypass the creation of the sqlite_master table entry
    ++**     (1)  Set all columns of the PRIMARY KEY schema object to be NOT NULL.
    ++**     (2)  Convert P3 parameter of the OP_CreateBtree from BTREE_INTKEY 
    ++**          into BTREE_BLOBKEY.
    ++**     (3)  Bypass the creation of the sqlite_master table entry
    + **          for the PRIMARY KEY as the primary key index is now
    + **          identified by the sqlite_master table entry of the table itself.
    +-**     (3)  Set the Index.tnum of the PRIMARY KEY Index object in the
    ++**     (4)  Set the Index.tnum of the PRIMARY KEY Index object in the
    + **          schema to the rootpage from the main table.
    +-**     (4)  Set all columns of the PRIMARY KEY schema object to be NOT NULL.
    + **     (5)  Add all table columns to the PRIMARY KEY Index object
    + **          so that the PRIMARY KEY is a covering index.  The surplus
    +-**          columns are part of KeyInfo.nXField and are not used for
    ++**          columns are part of KeyInfo.nAllField and are not used for
    + **          sorting or lookup or uniqueness checks.
    + **     (6)  Replace the rowid tail on all automatically generated UNIQUE
    + **          indices with the PRIMARY KEY columns.
    ++**
    ++** For virtual tables, only (1) is performed.
    + */
    + static void convertToWithoutRowidTable(Parse *pParse, Table *pTab){
    +   Index *pIdx;
    +@@ -94499,13 +103317,26 @@ static void convertToWithoutRowidTable(Parse *pParse, Table *pTab){
    +   sqlite3 *db = pParse->db;
    +   Vdbe *v = pParse->pVdbe;
    + 
    +-  /* Convert the OP_CreateTable opcode that would normally create the
    +-  ** root-page for the table into an OP_CreateIndex opcode.  The index
    +-  ** created will become the PRIMARY KEY index.
    ++  /* Mark every PRIMARY KEY column as NOT NULL (except for imposter tables)
    ++  */
    ++  if( !db->init.imposterTable ){
    ++    for(i=0; i<pTab->nCol; i++){
    ++      if( (pTab->aCol[i].colFlags & COLFLAG_PRIMKEY)!=0 ){
    ++        pTab->aCol[i].notNull = OE_Abort;
    ++      }
    ++    }
    ++  }
    ++
    ++  /* The remaining transformations only apply to b-tree tables, not to
    ++  ** virtual tables */
    ++  if( IN_DECLARE_VTAB ) return;
    ++
    ++  /* Convert the P3 operand of the OP_CreateBtree opcode from BTREE_INTKEY
    ++  ** into BTREE_BLOBKEY.
    +   */
    +   if( pParse->addrCrTab ){
    +     assert( v );
    +-    sqlite3VdbeChangeOpcode(v, pParse->addrCrTab, OP_CreateIndex);
    ++    sqlite3VdbeChangeP3(v, pParse->addrCrTab, BTREE_BLOBKEY);
    +   }
    + 
    +   /* Locate the PRIMARY KEY index.  Or, if this table was originally
    +@@ -94514,29 +103345,20 @@ static void convertToWithoutRowidTable(Parse *pParse, Table *pTab){
    +   if( pTab->iPKey>=0 ){
    +     ExprList *pList;
    +     Token ipkToken;
    +-    ipkToken.z = pTab->aCol[pTab->iPKey].zName;
    +-    ipkToken.n = sqlite3Strlen30(ipkToken.z);
    ++    sqlite3TokenInit(&ipkToken, pTab->aCol[pTab->iPKey].zName);
    +     pList = sqlite3ExprListAppend(pParse, 0, 
    +                   sqlite3ExprAlloc(db, TK_ID, &ipkToken, 0));
    +     if( pList==0 ) return;
    +     pList->a[0].sortOrder = pParse->iPkSortOrder;
    +     assert( pParse->pNewTable==pTab );
    +-    pPk = sqlite3CreateIndex(pParse, 0, 0, 0, pList, pTab->keyConf, 0, 0, 0, 0);
    +-    if( pPk==0 ) return;
    +-    pPk->idxType = SQLITE_IDXTYPE_PRIMARYKEY;
    ++    sqlite3CreateIndex(pParse, 0, 0, 0, pList, pTab->keyConf, 0, 0, 0, 0,
    ++                       SQLITE_IDXTYPE_PRIMARYKEY);
    ++    if( db->mallocFailed ) return;
    ++    pPk = sqlite3PrimaryKeyIndex(pTab);
    +     pTab->iPKey = -1;
    +   }else{
    +     pPk = sqlite3PrimaryKeyIndex(pTab);
    + 
    +-    /* Bypass the creation of the PRIMARY KEY btree and the sqlite_master
    +-    ** table entry. This is only required if currently generating VDBE
    +-    ** code for a CREATE TABLE (not when parsing one as part of reading
    +-    ** a database schema).  */
    +-    if( v ){
    +-      assert( db->init.busy==0 );
    +-      sqlite3VdbeChangeOpcode(v, pPk->tnum, OP_Goto);
    +-    }
    +-
    +     /*
    +     ** Remove all redundant columns from the PRIMARY KEY.  For example, change
    +     ** "PRIMARY KEY(a,b,a,b,c,b,c,d)" into just "PRIMARY KEY(a,b,c,d)".  Later
    +@@ -94551,17 +103373,18 @@ static void convertToWithoutRowidTable(Parse *pParse, Table *pTab){
    +     }
    +     pPk->nKeyCol = j;
    +   }
    +-  pPk->isCovering = 1;
    +   assert( pPk!=0 );
    ++  pPk->isCovering = 1;
    ++  if( !db->init.imposterTable ) pPk->uniqNotNull = 1;
    +   nPk = pPk->nKeyCol;
    + 
    +-  /* Make sure every column of the PRIMARY KEY is NOT NULL.  (Except,
    +-  ** do not enforce this for imposter tables.) */
    +-  if( !db->init.imposterTable ){
    +-    for(i=0; i<nPk; i++){
    +-      pTab->aCol[pPk->aiColumn[i]].notNull = 1;
    +-    }
    +-    pPk->uniqNotNull = 1;
    ++  /* Bypass the creation of the PRIMARY KEY btree and the sqlite_master
    ++  ** table entry. This is only required if currently generating VDBE
    ++  ** code for a CREATE TABLE (not when parsing one as part of reading
    ++  ** a database schema).  */
    ++  if( v && pPk->tnum>0 ){
    ++    assert( db->init.busy==0 );
    ++    sqlite3VdbeChangeOpcode(v, pPk->tnum, OP_Goto);
    +   }
    + 
    +   /* The root page of the PRIMARY KEY is the table root page */
    +@@ -94601,7 +103424,7 @@ static void convertToWithoutRowidTable(Parse *pParse, Table *pTab){
    +       if( !hasColumn(pPk->aiColumn, j, i) ){
    +         assert( j<pPk->nColumn );
    +         pPk->aiColumn[j] = i;
    +-        pPk->azColl[j] = "BINARY";
    ++        pPk->azColl[j] = sqlite3StrBINARY;
    +         j++;
    +       }
    +     }
    +@@ -94658,9 +103481,13 @@ SQLITE_PRIVATE void sqlite3EndTable(
    +   ** So do not write to the disk again.  Extract the root page number
    +   ** for the table from the db->init.newTnum field.  (The page number
    +   ** should have been put there by the sqliteOpenCb routine.)
    ++  **
    ++  ** If the root page number is 1, that means this is the sqlite_master
    ++  ** table itself.  So mark it read-only.
    +   */
    +   if( db->init.busy ){
    +     p->tnum = db->init.newTnum;
    ++    if( p->tnum==1 ) p->tabFlags |= TF_Readonly;
    +   }
    + 
    +   /* Special processing for WITHOUT ROWID Tables */
    +@@ -94759,10 +103586,6 @@ SQLITE_PRIVATE void sqlite3EndTable(
    +       pParse->nTab = 2;
    +       addrTop = sqlite3VdbeCurrentAddr(v) + 1;
    +       sqlite3VdbeAddOp3(v, OP_InitCoroutine, regYield, 0, addrTop);
    +-      sqlite3SelectDestInit(&dest, SRT_Coroutine, regYield);
    +-      sqlite3Select(pParse, pSelect, &dest);
    +-      sqlite3VdbeAddOp1(v, OP_EndCoroutine, regYield);
    +-      sqlite3VdbeJumpHere(v, addrTop - 1);
    +       if( pParse->nErr ) return;
    +       pSelTab = sqlite3ResultSetOfSelect(pParse, pSelect);
    +       if( pSelTab==0 ) return;
    +@@ -94772,6 +103595,11 @@ SQLITE_PRIVATE void sqlite3EndTable(
    +       pSelTab->nCol = 0;
    +       pSelTab->aCol = 0;
    +       sqlite3DeleteTable(db, pSelTab);
    ++      sqlite3SelectDestInit(&dest, SRT_Coroutine, regYield);
    ++      sqlite3Select(pParse, pSelect, &dest);
    ++      if( pParse->nErr ) return;
    ++      sqlite3VdbeEndCoroutine(v, regYield);
    ++      sqlite3VdbeJumpHere(v, addrTop - 1);
    +       addrInsLoop = sqlite3VdbeAddOp1(v, OP_Yield, dest.iSDParm);
    +       VdbeCoverage(v);
    +       sqlite3VdbeAddOp3(v, OP_MakeRecord, dest.iSdst, dest.nSdst, regRec);
    +@@ -94803,7 +103631,7 @@ SQLITE_PRIVATE void sqlite3EndTable(
    +       "UPDATE %Q.%s "
    +          "SET type='%s', name=%Q, tbl_name=%Q, rootpage=#%d, sql=%Q "
    +        "WHERE rowid=#%d",
    +-      db->aDb[iDb].zName, SCHEMA_TABLE(iDb),
    ++      db->aDb[iDb].zDbSName, MASTER_NAME,
    +       zType,
    +       p->zName,
    +       p->zName,
    +@@ -94818,13 +103646,13 @@ SQLITE_PRIVATE void sqlite3EndTable(
    +     /* Check to see if we need to create an sqlite_sequence table for
    +     ** keeping track of autoincrement keys.
    +     */
    +-    if( p->tabFlags & TF_Autoincrement ){
    ++    if( (p->tabFlags & TF_Autoincrement)!=0 ){
    +       Db *pDb = &db->aDb[iDb];
    +       assert( sqlite3SchemaMutexHeld(db, iDb, 0) );
    +       if( pDb->pSchema->pSeqTab==0 ){
    +         sqlite3NestedParse(pParse,
    +           "CREATE TABLE %Q.sqlite_sequence(name,seq)",
    +-          pDb->zName
    ++          pDb->zDbSName
    +         );
    +       }
    +     }
    +@@ -94845,11 +103673,11 @@ SQLITE_PRIVATE void sqlite3EndTable(
    +     pOld = sqlite3HashInsert(&pSchema->tblHash, p->zName, p);
    +     if( pOld ){
    +       assert( p==pOld );  /* Malloc must have failed inside HashInsert() */
    +-      db->mallocFailed = 1;
    ++      sqlite3OomFault(db);
    +       return;
    +     }
    +     pParse->pNewTable = 0;
    +-    db->flags |= SQLITE_InternChanges;
    ++    db->mDbFlags |= DBFLAG_SchemaChange;
    + 
    + #ifndef SQLITE_OMIT_ALTERTABLE
    +     if( !p->pSelect ){
    +@@ -94914,7 +103742,7 @@ SQLITE_PRIVATE void sqlite3CreateView(
    +   ** the end.
    +   */
    +   sEnd = pParse->sLastToken;
    +-  assert( sEnd.z[0]!=0 );
    ++  assert( sEnd.z[0]!=0 || sEnd.n==0 );
    +   if( sEnd.z[0]!=';' ){
    +     sEnd.z += sEnd.n;
    +   }
    +@@ -94948,14 +103776,21 @@ SQLITE_PRIVATE int sqlite3ViewGetColumnNames(Parse *pParse, Table *pTable){
    +   int nErr = 0;     /* Number of errors encountered */
    +   int n;            /* Temporarily holds the number of cursors assigned */
    +   sqlite3 *db = pParse->db;  /* Database connection for malloc errors */
    ++#ifndef SQLITE_OMIT_VIRTUALTABLE	
    ++  int rc;
    ++#endif
    ++#ifndef SQLITE_OMIT_AUTHORIZATION
    +   sqlite3_xauth xAuth;       /* Saved xAuth pointer */
    +-  u8 bEnabledLA;             /* Saved db->lookaside.bEnabled state */
    ++#endif
    + 
    +   assert( pTable );
    + 
    + #ifndef SQLITE_OMIT_VIRTUALTABLE
    +-  if( sqlite3VtabCallConnect(pParse, pTable) ){
    +-    return SQLITE_ERROR;
    ++  db->nSchemaLock++;
    ++  rc = sqlite3VtabCallConnect(pParse, pTable);
    ++  db->nSchemaLock--;
    ++  if( rc ){
    ++    return 1;
    +   }
    +   if( IsVirtual(pTable) ) return 0;
    + #endif
    +@@ -94995,45 +103830,56 @@ SQLITE_PRIVATE int sqlite3ViewGetColumnNames(Parse *pParse, Table *pTable){
    +   ** statement that defines the view.
    +   */
    +   assert( pTable->pSelect );
    +-  bEnabledLA = db->lookaside.bEnabled;
    +-  if( pTable->pCheck ){
    +-    db->lookaside.bEnabled = 0;
    +-    sqlite3ColumnsFromExprList(pParse, pTable->pCheck, 
    +-                               &pTable->nCol, &pTable->aCol);
    +-  }else{
    +-    pSel = sqlite3SelectDup(db, pTable->pSelect, 0);
    +-    if( pSel ){
    +-      n = pParse->nTab;
    +-      sqlite3SrcListAssignCursors(pParse, pSel->pSrc);
    +-      pTable->nCol = -1;
    +-      db->lookaside.bEnabled = 0;
    ++  pSel = sqlite3SelectDup(db, pTable->pSelect, 0);
    ++  if( pSel ){
    ++    n = pParse->nTab;
    ++    sqlite3SrcListAssignCursors(pParse, pSel->pSrc);
    ++    pTable->nCol = -1;
    ++    db->lookaside.bDisable++;
    + #ifndef SQLITE_OMIT_AUTHORIZATION
    +-      xAuth = db->xAuth;
    +-      db->xAuth = 0;
    +-      pSelTab = sqlite3ResultSetOfSelect(pParse, pSel);
    +-      db->xAuth = xAuth;
    ++    xAuth = db->xAuth;
    ++    db->xAuth = 0;
    ++    pSelTab = sqlite3ResultSetOfSelect(pParse, pSel);
    ++    db->xAuth = xAuth;
    + #else
    +-      pSelTab = sqlite3ResultSetOfSelect(pParse, pSel);
    +-#endif
    +-      pParse->nTab = n;
    +-      if( pSelTab ){
    +-        assert( pTable->aCol==0 );
    +-        pTable->nCol = pSelTab->nCol;
    +-        pTable->aCol = pSelTab->aCol;
    +-        pSelTab->nCol = 0;
    +-        pSelTab->aCol = 0;
    +-        sqlite3DeleteTable(db, pSelTab);
    +-        assert( sqlite3SchemaMutexHeld(db, 0, pTable->pSchema) );
    +-      }else{
    +-        pTable->nCol = 0;
    +-        nErr++;
    ++    pSelTab = sqlite3ResultSetOfSelect(pParse, pSel);
    ++#endif
    ++    pParse->nTab = n;
    ++    if( pTable->pCheck ){
    ++      /* CREATE VIEW name(arglist) AS ...
    ++      ** The names of the columns in the table are taken from
    ++      ** arglist which is stored in pTable->pCheck.  The pCheck field
    ++      ** normally holds CHECK constraints on an ordinary table, but for
    ++      ** a VIEW it holds the list of column names.
    ++      */
    ++      sqlite3ColumnsFromExprList(pParse, pTable->pCheck, 
    ++                                 &pTable->nCol, &pTable->aCol);
    ++      if( db->mallocFailed==0 
    ++       && pParse->nErr==0
    ++       && pTable->nCol==pSel->pEList->nExpr
    ++      ){
    ++        sqlite3SelectAddColumnTypeAndCollation(pParse, pTable, pSel);
    +       }
    +-      sqlite3SelectDelete(db, pSel);
    +-    } else {
    ++    }else if( pSelTab ){
    ++      /* CREATE VIEW name AS...  without an argument list.  Construct
    ++      ** the column names from the SELECT statement that defines the view.
    ++      */
    ++      assert( pTable->aCol==0 );
    ++      pTable->nCol = pSelTab->nCol;
    ++      pTable->aCol = pSelTab->aCol;
    ++      pSelTab->nCol = 0;
    ++      pSelTab->aCol = 0;
    ++      assert( sqlite3SchemaMutexHeld(db, 0, pTable->pSchema) );
    ++    }else{
    ++      pTable->nCol = 0;
    +       nErr++;
    +     }
    ++    sqlite3DeleteTable(db, pSelTab);
    ++    sqlite3SelectDelete(db, pSel);
    ++    db->lookaside.bDisable--;
    ++  } else {
    ++    nErr++;
    +   }
    +-  db->lookaside.bEnabled = bEnabledLA;
    +   pTable->pSchema->schemaFlags |= DB_UnresetViews;
    + #endif /* SQLITE_OMIT_VIEW */
    +   return nErr;  
    +@@ -95113,6 +103959,7 @@ SQLITE_PRIVATE void sqlite3RootPageMoved(sqlite3 *db, int iDb, int iFrom, int iT
    + static void destroyRootPage(Parse *pParse, int iTable, int iDb){
    +   Vdbe *v = sqlite3GetVdbe(pParse);
    +   int r1 = sqlite3GetTempReg(pParse);
    ++  assert( iTable>1 );
    +   sqlite3VdbeAddOp3(v, OP_Destroy, iTable, r1, iDb);
    +   sqlite3MayAbort(pParse);
    + #ifndef SQLITE_OMIT_AUTOVACUUM
    +@@ -95127,7 +103974,7 @@ static void destroyRootPage(Parse *pParse, int iTable, int iDb){
    +   */
    +   sqlite3NestedParse(pParse, 
    +      "UPDATE %Q.%s SET rootpage=%d WHERE #%d AND rootpage=#%d",
    +-     pParse->db->aDb[iDb].zName, SCHEMA_TABLE(iDb), iTable, r1, r1);
    ++     pParse->db->aDb[iDb].zDbSName, MASTER_NAME, iTable, r1, r1);
    + #endif
    +   sqlite3ReleaseTempReg(pParse, r1);
    + }
    +@@ -95139,14 +103986,6 @@ static void destroyRootPage(Parse *pParse, int iTable, int iDb){
    + ** is also added (this can happen with an auto-vacuum database).
    + */
    + static void destroyTable(Parse *pParse, Table *pTab){
    +-#ifdef SQLITE_OMIT_AUTOVACUUM
    +-  Index *pIdx;
    +-  int iDb = sqlite3SchemaToIndex(pParse->db, pTab->pSchema);
    +-  destroyRootPage(pParse, pTab->tnum, iDb);
    +-  for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){
    +-    destroyRootPage(pParse, pIdx->tnum, iDb);
    +-  }
    +-#else
    +   /* If the database may be auto-vacuum capable (if SQLITE_OMIT_AUTOVACUUM
    +   ** is not defined), then it is important to call OP_Destroy on the
    +   ** table and index root-pages in order, starting with the numerically 
    +@@ -95189,7 +104028,6 @@ static void destroyTable(Parse *pParse, Table *pTab){
    +       iDestroyed = iLargest;
    +     }
    +   }
    +-#endif
    + }
    + 
    + /*
    +@@ -95203,7 +104041,7 @@ static void sqlite3ClearStatTables(
    +   const char *zName      /* Name of index or table */
    + ){
    +   int i;
    +-  const char *zDbName = pParse->db->aDb[iDb].zName;
    ++  const char *zDbName = pParse->db->aDb[iDb].zDbSName;
    +   for(i=1; i<=4; i++){
    +     char zTab[24];
    +     sqlite3_snprintf(sizeof(zTab),zTab,"sqlite_stat%d",i);
    +@@ -95256,7 +104094,7 @@ SQLITE_PRIVATE void sqlite3CodeDropTable(Parse *pParse, Table *pTab, int iDb, in
    +   if( pTab->tabFlags & TF_Autoincrement ){
    +     sqlite3NestedParse(pParse,
    +       "DELETE FROM %Q.sqlite_sequence WHERE name=%Q",
    +-      pDb->zName, pTab->zName
    ++      pDb->zDbSName, pTab->zName
    +     );
    +   }
    + #endif
    +@@ -95270,7 +104108,7 @@ SQLITE_PRIVATE void sqlite3CodeDropTable(Parse *pParse, Table *pTab, int iDb, in
    +   */
    +   sqlite3NestedParse(pParse, 
    +       "DELETE FROM %Q.%s WHERE tbl_name=%Q and type!='trigger'",
    +-      pDb->zName, SCHEMA_TABLE(iDb), pTab->zName);
    ++      pDb->zDbSName, MASTER_NAME, pTab->zName);
    +   if( !isView && !IsVirtual(pTab) ){
    +     destroyTable(pParse, pTab);
    +   }
    +@@ -95303,6 +104141,7 @@ SQLITE_PRIVATE void sqlite3DropTable(Parse *pParse, SrcList *pName, int isView,
    +   assert( pName->nSrc==1 );
    +   if( sqlite3ReadSchema(pParse) ) goto exit_drop_table;
    +   if( noErr ) db->suppressErr++;
    ++  assert( isView==0 || isView==LOCATE_VIEW );
    +   pTab = sqlite3LocateTableItem(pParse, isView, &pName->a[0]);
    +   if( noErr ) db->suppressErr--;
    + 
    +@@ -95323,7 +104162,7 @@ SQLITE_PRIVATE void sqlite3DropTable(Parse *pParse, SrcList *pName, int isView,
    +   {
    +     int code;
    +     const char *zTab = SCHEMA_TABLE(iDb);
    +-    const char *zDb = db->aDb[iDb].zName;
    ++    const char *zDb = db->aDb[iDb].zDbSName;
    +     const char *zArg2 = 0;
    +     if( sqlite3AuthCheck(pParse, SQLITE_DELETE, zTab, 0, zDb)){
    +       goto exit_drop_table;
    +@@ -95498,7 +104337,7 @@ SQLITE_PRIVATE void sqlite3CreateForeignKey(
    +       pFKey->zTo, (void *)pFKey
    +   );
    +   if( pNextTo==pFKey ){
    +-    db->mallocFailed = 1;
    ++    sqlite3OomFault(db);
    +     goto fk_end;
    +   }
    +   if( pNextTo ){
    +@@ -95564,7 +104403,7 @@ static void sqlite3RefillIndex(Parse *pParse, Index *pIndex, int memRootPage){
    + 
    + #ifndef SQLITE_OMIT_AUTHORIZATION
    +   if( sqlite3AuthCheck(pParse, SQLITE_REINDEX, pIndex->zName, 0,
    +-      db->aDb[iDb].zName ) ){
    ++      db->aDb[iDb].zDbSName ) ){
    +     return;
    +   }
    + #endif
    +@@ -95580,6 +104419,7 @@ static void sqlite3RefillIndex(Parse *pParse, Index *pIndex, int memRootPage){
    +     tnum = pIndex->tnum;
    +   }
    +   pKey = sqlite3KeyInfoOfIndex(pParse, pIndex);
    ++  assert( pKey!=0 || db->mallocFailed || pParse->nErr );
    + 
    +   /* Open the sorter cursor if we are to use one. */
    +   iSorter = pParse->nTab++;
    +@@ -95603,8 +104443,7 @@ static void sqlite3RefillIndex(Parse *pParse, Index *pIndex, int memRootPage){
    +   sqlite3VdbeChangeP5(v, OPFLAG_BULKCSR|((memRootPage>=0)?OPFLAG_P2ISREG:0));
    + 
    +   addr1 = sqlite3VdbeAddOp2(v, OP_SorterSort, iSorter, 0); VdbeCoverage(v);
    +-  assert( pKey!=0 || db->mallocFailed || pParse->nErr );
    +-  if( IsUniqueIndex(pIndex) && pKey!=0 ){
    ++  if( IsUniqueIndex(pIndex) ){
    +     int j2 = sqlite3VdbeCurrentAddr(v) + 3;
    +     sqlite3VdbeGoto(v, j2);
    +     addr2 = sqlite3VdbeCurrentAddr(v);
    +@@ -95615,8 +104454,8 @@ static void sqlite3RefillIndex(Parse *pParse, Index *pIndex, int memRootPage){
    +     addr2 = sqlite3VdbeCurrentAddr(v);
    +   }
    +   sqlite3VdbeAddOp3(v, OP_SorterData, iSorter, regRecord, iIdx);
    +-  sqlite3VdbeAddOp3(v, OP_Last, iIdx, 0, -1);
    +-  sqlite3VdbeAddOp3(v, OP_IdxInsert, iIdx, regRecord, 0);
    ++  sqlite3VdbeAddOp1(v, OP_SeekEnd, iIdx);
    ++  sqlite3VdbeAddOp2(v, OP_IdxInsert, iIdx, regRecord);
    +   sqlite3VdbeChangeP5(v, OPFLAG_USESEEKRESULT);
    +   sqlite3ReleaseTempReg(pParse, regRecord);
    +   sqlite3VdbeAddOp2(v, OP_SorterNext, iSorter, addr2); VdbeCoverage(v);
    +@@ -95651,7 +104490,7 @@ SQLITE_PRIVATE Index *sqlite3AllocateIndexObject(
    +   p = sqlite3DbMallocZero(db, nByte + nExtra);
    +   if( p ){
    +     char *pExtra = ((char*)p)+ROUND8(sizeof(Index));
    +-    p->azColl = (char**)pExtra;       pExtra += ROUND8(sizeof(char*)*nCol);
    ++    p->azColl = (const 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;
    +@@ -95673,12 +104512,8 @@ SQLITE_PRIVATE Index *sqlite3AllocateIndexObject(
    + ** pList is a list of columns to be indexed.  pList will be NULL if this
    + ** is a primary key or unique-constraint on the most recent column added
    + ** to the table currently under construction.  
    +-**
    +-** 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.idxType==SQLITE_IDXTYPE_PRIMARYKEY)
    + */
    +-SQLITE_PRIVATE Index *sqlite3CreateIndex(
    ++SQLITE_PRIVATE void sqlite3CreateIndex(
    +   Parse *pParse,     /* All information about this parse */
    +   Token *pName1,     /* First part of index name. May be NULL */
    +   Token *pName2,     /* Second part of index name. May be NULL */
    +@@ -95688,9 +104523,9 @@ SQLITE_PRIVATE Index *sqlite3CreateIndex(
    +   Token *pStart,     /* The CREATE token that begins this statement */
    +   Expr *pPIWhere,    /* WHERE clause for partial indices */
    +   int sortOrder,     /* Sort order of primary key when pList==NULL */
    +-  int ifNotExist     /* Omit error if index already exists */
    ++  int ifNotExist,    /* Omit error if index already exists */
    ++  u8 idxType         /* The index type */
    + ){
    +-  Index *pRet = 0;     /* Pointer to return */
    +   Table *pTab = 0;     /* Table to be indexed */
    +   Index *pIndex = 0;   /* The index to be created */
    +   char *zName = 0;     /* Name of the index */
    +@@ -95708,7 +104543,10 @@ SQLITE_PRIVATE Index *sqlite3CreateIndex(
    +   char *zExtra = 0;                /* Extra space after the Index object */
    +   Index *pPk = 0;      /* PRIMARY KEY index for WITHOUT ROWID tables */
    + 
    +-  if( db->mallocFailed || IN_DECLARE_VTAB || pParse->nErr>0 ){
    ++  if( db->mallocFailed || pParse->nErr>0 ){
    ++    goto exit_create_index;
    ++  }
    ++  if( IN_DECLARE_VTAB && idxType!=SQLITE_IDXTYPE_PRIMARYKEY ){
    +     goto exit_create_index;
    +   }
    +   if( SQLITE_OK!=sqlite3ReadSchema(pParse) ){
    +@@ -95817,7 +104655,7 @@ SQLITE_PRIVATE Index *sqlite3CreateIndex(
    +         goto exit_create_index;
    +       }
    +     }
    +-    if( sqlite3FindIndex(db, zName, pDb->zName)!=0 ){
    ++    if( sqlite3FindIndex(db, zName, pDb->zDbSName)!=0 ){
    +       if( !ifNotExist ){
    +         sqlite3ErrorMsg(pParse, "index %s already exists", zName);
    +       }else{
    +@@ -95834,13 +104672,20 @@ SQLITE_PRIVATE Index *sqlite3CreateIndex(
    +     if( zName==0 ){
    +       goto exit_create_index;
    +     }
    ++
    ++    /* Automatic index names generated from within sqlite3_declare_vtab()
    ++    ** must have names that are distinct from normal automatic index names.
    ++    ** The following statement converts "sqlite3_autoindex..." into
    ++    ** "sqlite3_butoindex..." in order to make the names distinct.
    ++    ** The "vtab_err.test" test demonstrates the need of this statement. */
    ++    if( IN_DECLARE_VTAB ) zName[7]++;
    +   }
    + 
    +   /* Check for authorization to create an index.
    +   */
    + #ifndef SQLITE_OMIT_AUTHORIZATION
    +   {
    +-    const char *zDb = pDb->zName;
    ++    const char *zDb = pDb->zDbSName;
    +     if( sqlite3AuthCheck(pParse, SQLITE_INSERT, SCHEMA_TABLE(iDb), 0, zDb) ){
    +       goto exit_create_index;
    +     }
    +@@ -95858,8 +104703,7 @@ SQLITE_PRIVATE Index *sqlite3CreateIndex(
    +   */
    +   if( pList==0 ){
    +     Token prevCol;
    +-    prevCol.z = pTab->aCol[pTab->nCol-1].zName;
    +-    prevCol.n = sqlite3Strlen30(prevCol.z);
    ++    sqlite3TokenInit(&prevCol, pTab->aCol[pTab->nCol-1].zName);
    +     pList = sqlite3ExprListAppend(pParse, 0,
    +               sqlite3ExprAlloc(db, TK_ID, &prevCol, 0));
    +     if( pList==0 ) goto exit_create_index;
    +@@ -95898,7 +104742,7 @@ SQLITE_PRIVATE Index *sqlite3CreateIndex(
    +   pIndex->pTable = pTab;
    +   pIndex->onError = (u8)onError;
    +   pIndex->uniqNotNull = onError!=OE_None;
    +-  pIndex->idxType = pName ? SQLITE_IDXTYPE_APPDEF : SQLITE_IDXTYPE_UNIQUE;
    ++  pIndex->idxType = idxType;
    +   pIndex->pSchema = db->aDb[iDb].pSchema;
    +   pIndex->nKeyCol = pList->nExpr;
    +   if( pPIWhere ){
    +@@ -95928,7 +104772,7 @@ SQLITE_PRIVATE Index *sqlite3CreateIndex(
    +   for(i=0, pListItem=pList->a; i<pList->nExpr; i++, pListItem++){
    +     Expr *pCExpr;                  /* The i-th index expression */
    +     int requestedSortOrder;        /* ASC or DESC on the i-th expression */
    +-    char *zColl;                   /* Collation sequence name */
    ++    const char *zColl;             /* Collation sequence name */
    + 
    +     sqlite3StringToId(pListItem->pExpr);
    +     sqlite3ResolveSelfReference(pParse, pTab, NC_IdxExpr, pListItem->pExpr, 0);
    +@@ -95974,7 +104818,7 @@ SQLITE_PRIVATE Index *sqlite3CreateIndex(
    +     }else if( j>=0 ){
    +       zColl = pTab->aCol[j].zColl;
    +     }
    +-    if( !zColl ) zColl = "BINARY";
    ++    if( !zColl ) zColl = sqlite3StrBINARY;
    +     if( !db->init.busy && !sqlite3LocateCollSeq(pParse, zColl) ){
    +       goto exit_create_index;
    +     }
    +@@ -96003,11 +104847,25 @@ SQLITE_PRIVATE Index *sqlite3CreateIndex(
    +     assert( i==pIndex->nColumn );
    +   }else{
    +     pIndex->aiColumn[i] = XN_ROWID;
    +-    pIndex->azColl[i] = "BINARY";
    ++    pIndex->azColl[i] = sqlite3StrBINARY;
    +   }
    +   sqlite3DefaultRowEst(pIndex);
    +   if( pParse->pNewTable==0 ) estimateIndexWidth(pIndex);
    + 
    ++  /* If this index contains every column of its table, then mark
    ++  ** it as a covering index */
    ++  assert( HasRowid(pTab) 
    ++      || pTab->iPKey<0 || sqlite3ColumnOfIndex(pIndex, pTab->iPKey)>=0 );
    ++  if( pTblName!=0 && pIndex->nColumn>=pTab->nCol ){
    ++    pIndex->isCovering = 1;
    ++    for(j=0; j<pTab->nCol; j++){
    ++      if( j==pTab->iPKey ) continue;
    ++      if( sqlite3ColumnOfIndex(pIndex,j)>=0 ) continue;
    ++      pIndex->isCovering = 0;
    ++      break;
    ++    }
    ++  }
    ++
    +   if( pTab==pParse->pNewTable ){
    +     /* This routine has been called to create an automatic index as a
    +     ** result of a PRIMARY KEY or UNIQUE clause on a column definition, or
    +@@ -96045,7 +104903,7 @@ SQLITE_PRIVATE Index *sqlite3CreateIndex(
    +         if( pIdx->aiColumn[k]!=pIndex->aiColumn[k] ) break;
    +         z1 = pIdx->azColl[k];
    +         z2 = pIndex->azColl[k];
    +-        if( z1!=z2 && sqlite3StrICmp(z1, z2) ) break;
    ++        if( sqlite3StrICmp(z1, z2) ) break;
    +       }
    +       if( k==pIdx->nKeyCol ){
    +         if( pIdx->onError!=pIndex->onError ){
    +@@ -96064,7 +104922,7 @@ SQLITE_PRIVATE Index *sqlite3CreateIndex(
    +             pIdx->onError = pIndex->onError;
    +           }
    +         }
    +-        pRet = pIdx;
    ++        if( idxType==SQLITE_IDXTYPE_PRIMARYKEY ) pIdx->idxType = idxType;
    +         goto exit_create_index;
    +       }
    +     }
    +@@ -96076,15 +104934,16 @@ SQLITE_PRIVATE Index *sqlite3CreateIndex(
    +   assert( pParse->nErr==0 );
    +   if( db->init.busy ){
    +     Index *p;
    ++    assert( !IN_DECLARE_VTAB );
    +     assert( sqlite3SchemaMutexHeld(db, 0, pIndex->pSchema) );
    +     p = sqlite3HashInsert(&pIndex->pSchema->idxHash, 
    +                           pIndex->zName, pIndex);
    +     if( p ){
    +       assert( p==pIndex );  /* Malloc must have failed */
    +-      db->mallocFailed = 1;
    ++      sqlite3OomFault(db);
    +       goto exit_create_index;
    +     }
    +-    db->flags |= SQLITE_InternChanges;
    ++    db->mDbFlags |= DBFLAG_SchemaChange;
    +     if( pTblName!=0 ){
    +       pIndex->tnum = db->init.newTnum;
    +     }
    +@@ -96120,7 +104979,7 @@ SQLITE_PRIVATE Index *sqlite3CreateIndex(
    +     ** that case the convertToWithoutRowidTable() routine will replace
    +     ** the Noop with a Goto to jump over the VDBE code generated below. */
    +     pIndex->tnum = sqlite3VdbeAddOp0(v, OP_Noop);
    +-    sqlite3VdbeAddOp2(v, OP_CreateIndex, iDb, iMem);
    ++    sqlite3VdbeAddOp3(v, OP_CreateBtree, iDb, iMem, BTREE_BLOBKEY);
    + 
    +     /* Gather the complete text of the CREATE INDEX statement into
    +     ** the zStmt variable
    +@@ -96141,7 +105000,7 @@ SQLITE_PRIVATE Index *sqlite3CreateIndex(
    +     */
    +     sqlite3NestedParse(pParse, 
    +         "INSERT INTO %Q.%s VALUES('index',%Q,%Q,#%d,%Q);",
    +-        db->aDb[iDb].zName, SCHEMA_TABLE(iDb),
    ++        db->aDb[iDb].zDbSName, MASTER_NAME,
    +         pIndex->zName,
    +         pTab->zName,
    +         iMem,
    +@@ -96157,7 +105016,7 @@ SQLITE_PRIVATE Index *sqlite3CreateIndex(
    +       sqlite3ChangeCookie(pParse, iDb);
    +       sqlite3VdbeAddParseSchemaOp(v, iDb,
    +          sqlite3MPrintf(db, "name='%q' AND type='index'", pIndex->zName));
    +-      sqlite3VdbeAddOp1(v, OP_Expire, 0);
    ++      sqlite3VdbeAddOp0(v, OP_Expire);
    +     }
    + 
    +     sqlite3VdbeJumpHere(v, pIndex->tnum);
    +@@ -96182,7 +105041,6 @@ SQLITE_PRIVATE Index *sqlite3CreateIndex(
    +       pIndex->pNext = pOther->pNext;
    +       pOther->pNext = pIndex;
    +     }
    +-    pRet = pIndex;
    +     pIndex = 0;
    +   }
    + 
    +@@ -96193,7 +105051,6 @@ exit_create_index:
    +   sqlite3ExprListDelete(db, pList);
    +   sqlite3SrcListDelete(db, pTblName);
    +   sqlite3DbFree(db, zName);
    +-  return pRet;
    + }
    + 
    + /*
    +@@ -96221,11 +105078,15 @@ SQLITE_PRIVATE void sqlite3DefaultRowEst(Index *pIdx){
    +   int nCopy = MIN(ArraySize(aVal), pIdx->nKeyCol);
    +   int i;
    + 
    ++  /* Indexes with default row estimates should not have stat1 data */
    ++  assert( !pIdx->hasStat1 );
    ++
    +   /* 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.  */
    ++  ** number of rows in the table, or half the number of rows in the table
    ++  ** for a partial index.   But do not let the estimate drop below 10. */
    +   a[0] = pIdx->pTable->nRowLogEst;
    +-  if( a[0]<33 ) a[0] = 33;        assert( 33==sqlite3LogEst(10) );
    ++  if( pIdx->pPartIdxWhere!=0 ) a[0] -= 10;  assert( 10==sqlite3LogEst(2) );
    ++  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.  */
    +@@ -96276,7 +105137,7 @@ SQLITE_PRIVATE void sqlite3DropIndex(Parse *pParse, SrcList *pName, int ifExists
    +   {
    +     int code = SQLITE_DROP_INDEX;
    +     Table *pTab = pIndex->pTable;
    +-    const char *zDb = db->aDb[iDb].zName;
    ++    const char *zDb = db->aDb[iDb].zDbSName;
    +     const char *zTab = SCHEMA_TABLE(iDb);
    +     if( sqlite3AuthCheck(pParse, SQLITE_DELETE, zTab, 0, zDb) ){
    +       goto exit_drop_index;
    +@@ -96294,7 +105155,7 @@ SQLITE_PRIVATE void sqlite3DropIndex(Parse *pParse, SrcList *pName, int ifExists
    +     sqlite3BeginWriteOperation(pParse, 1, iDb);
    +     sqlite3NestedParse(pParse,
    +        "DELETE FROM %Q.%s WHERE name=%Q AND type='index'",
    +-       db->aDb[iDb].zName, SCHEMA_TABLE(iDb), pIndex->zName
    ++       db->aDb[iDb].zDbSName, MASTER_NAME, pIndex->zName
    +     );
    +     sqlite3ClearStatTables(pParse, iDb, "idx", pIndex->zName);
    +     sqlite3ChangeCookie(pParse, iDb);
    +@@ -96385,7 +105246,7 @@ SQLITE_PRIVATE void sqlite3IdListDelete(sqlite3 *db, IdList *pList){
    +     sqlite3DbFree(db, pList->a[i].zName);
    +   }
    +   sqlite3DbFree(db, pList->a);
    +-  sqlite3DbFree(db, pList);
    ++  sqlite3DbFreeNN(db, pList);
    + }
    + 
    + /*
    +@@ -96437,7 +105298,7 @@ SQLITE_PRIVATE SrcList *sqlite3SrcListEnlarge(
    +   /* Allocate additional space if needed */
    +   if( (u32)pSrc->nSrc+nExtra>pSrc->nAlloc ){
    +     SrcList *pNew;
    +-    int nAlloc = pSrc->nSrc+nExtra;
    ++    int nAlloc = pSrc->nSrc*2+nExtra;
    +     int nGot;
    +     pNew = sqlite3DbRealloc(db, pSrc,
    +                sizeof(*pSrc) + (nAlloc-1)*sizeof(pSrc->a[0]) );
    +@@ -96510,12 +105371,17 @@ SQLITE_PRIVATE SrcList *sqlite3SrcListAppend(
    + ){
    +   struct SrcList_item *pItem;
    +   assert( pDatabase==0 || pTable!=0 );  /* Cannot have C without B */
    ++  assert( db!=0 );
    +   if( pList==0 ){
    +-    pList = sqlite3DbMallocZero(db, sizeof(SrcList) );
    ++    pList = sqlite3DbMallocRawNN(db, sizeof(SrcList) );
    +     if( pList==0 ) return 0;
    +     pList->nAlloc = 1;
    ++    pList->nSrc = 1;
    ++    memset(&pList->a[0], 0, sizeof(pList->a[0]));
    ++    pList->a[0].iCursor = -1;
    ++  }else{
    ++    pList = sqlite3SrcListEnlarge(db, pList, 1, pList->nSrc);
    +   }
    +-  pList = sqlite3SrcListEnlarge(db, pList, 1, pList->nSrc);
    +   if( db->mallocFailed ){
    +     sqlite3SrcListDelete(db, pList);
    +     return 0;
    +@@ -96525,12 +105391,12 @@ SQLITE_PRIVATE SrcList *sqlite3SrcListAppend(
    +     pDatabase = 0;
    +   }
    +   if( pDatabase ){
    +-    Token *pTemp = pDatabase;
    +-    pDatabase = pTable;
    +-    pTable = pTemp;
    ++    pItem->zName = sqlite3NameFromToken(db, pDatabase);
    ++    pItem->zDatabase = sqlite3NameFromToken(db, pTable);
    ++  }else{
    ++    pItem->zName = sqlite3NameFromToken(db, pTable);
    ++    pItem->zDatabase = 0;
    +   }
    +-  pItem->zName = sqlite3NameFromToken(db, pTable);
    +-  pItem->zDatabase = sqlite3NameFromToken(db, pDatabase);
    +   return pList;
    + }
    + 
    +@@ -96570,7 +105436,7 @@ SQLITE_PRIVATE void sqlite3SrcListDelete(sqlite3 *db, SrcList *pList){
    +     sqlite3ExprDelete(db, pItem->pOn);
    +     sqlite3IdListDelete(db, pItem->pUsing);
    +   }
    +-  sqlite3DbFree(db, pList);
    ++  sqlite3DbFreeNN(db, pList);
    + }
    + 
    + /*
    +@@ -96608,9 +105474,10 @@ SQLITE_PRIVATE SrcList *sqlite3SrcListAppendFromTerm(
    +     goto append_from_error;
    +   }
    +   p = sqlite3SrcListAppend(db, p, pTable, pDatabase);
    +-  if( p==0 || NEVER(p->nSrc==0) ){
    ++  if( p==0 ){
    +     goto append_from_error;
    +   }
    ++  assert( p->nSrc>0 );
    +   pItem = &p->a[p->nSrc-1];
    +   assert( pAlias!=0 );
    +   if( pAlias->n ){
    +@@ -96635,8 +105502,10 @@ SQLITE_PRIVATE SrcList *sqlite3SrcListAppendFromTerm(
    + */
    + SQLITE_PRIVATE void sqlite3SrcListIndexedBy(Parse *pParse, SrcList *p, Token *pIndexedBy){
    +   assert( pIndexedBy!=0 );
    +-  if( p && ALWAYS(p->nSrc>0) ){
    +-    struct SrcList_item *pItem = &p->a[p->nSrc-1];
    ++  if( p && pIndexedBy->n>0 ){
    ++    struct SrcList_item *pItem;
    ++    assert( p->nSrc>0 );
    ++    pItem = &p->a[p->nSrc-1];
    +     assert( pItem->fg.notIndexed==0 );
    +     assert( pItem->fg.isIndexedBy==0 );
    +     assert( pItem->fg.isTabFunc==0 );
    +@@ -96646,7 +105515,7 @@ SQLITE_PRIVATE void sqlite3SrcListIndexedBy(Parse *pParse, SrcList *p, Token *pI
    +       pItem->fg.notIndexed = 1;
    +     }else{
    +       pItem->u1.zIndexedBy = sqlite3NameFromToken(pParse->db, pIndexedBy);
    +-      pItem->fg.isIndexedBy = (pItem->u1.zIndexedBy!=0);
    ++      pItem->fg.isIndexedBy = 1;
    +     }
    +   }
    + }
    +@@ -96656,7 +105525,7 @@ SQLITE_PRIVATE void sqlite3SrcListIndexedBy(Parse *pParse, SrcList *p, Token *pI
    + ** table-valued-function.
    + */
    + SQLITE_PRIVATE void sqlite3SrcListFuncArgs(Parse *pParse, SrcList *p, ExprList *pList){
    +-  if( p && pList ){
    ++  if( p ){
    +     struct SrcList_item *pItem = &p->a[p->nSrc-1];
    +     assert( pItem->fg.notIndexed==0 );
    +     assert( pItem->fg.isIndexedBy==0 );
    +@@ -96694,7 +105563,7 @@ SQLITE_PRIVATE void sqlite3SrcListShiftJoinType(SrcList *p){
    + }
    + 
    + /*
    +-** Begin a transaction
    ++** Generate VDBE code for a BEGIN statement.
    + */
    + SQLITE_PRIVATE void sqlite3BeginTransaction(Parse *pParse, int type){
    +   sqlite3 *db;
    +@@ -96704,7 +105573,6 @@ SQLITE_PRIVATE void sqlite3BeginTransaction(Parse *pParse, int type){
    +   assert( pParse!=0 );
    +   db = pParse->db;
    +   assert( db!=0 );
    +-/*  if( db->aDb[0].pBt==0 ) return; */
    +   if( sqlite3AuthCheck(pParse, SQLITE_TRANSACTION, "BEGIN", 0, 0) ){
    +     return;
    +   }
    +@@ -96716,40 +105584,29 @@ SQLITE_PRIVATE void sqlite3BeginTransaction(Parse *pParse, int type){
    +       sqlite3VdbeUsesBtree(v, i);
    +     }
    +   }
    +-  sqlite3VdbeAddOp2(v, OP_AutoCommit, 0, 0);
    +-}
    +-
    +-/*
    +-** Commit a transaction
    +-*/
    +-SQLITE_PRIVATE void sqlite3CommitTransaction(Parse *pParse){
    +-  Vdbe *v;
    +-
    +-  assert( pParse!=0 );
    +-  assert( pParse->db!=0 );
    +-  if( sqlite3AuthCheck(pParse, SQLITE_TRANSACTION, "COMMIT", 0, 0) ){
    +-    return;
    +-  }
    +-  v = sqlite3GetVdbe(pParse);
    +-  if( v ){
    +-    sqlite3VdbeAddOp2(v, OP_AutoCommit, 1, 0);
    +-  }
    ++  sqlite3VdbeAddOp0(v, OP_AutoCommit);
    + }
    + 
    + /*
    +-** Rollback a transaction
    ++** Generate VDBE code for a COMMIT or ROLLBACK statement.
    ++** Code for ROLLBACK is generated if eType==TK_ROLLBACK.  Otherwise
    ++** code is generated for a COMMIT.
    + */
    +-SQLITE_PRIVATE void sqlite3RollbackTransaction(Parse *pParse){
    ++SQLITE_PRIVATE void sqlite3EndTransaction(Parse *pParse, int eType){
    +   Vdbe *v;
    ++  int isRollback;
    + 
    +   assert( pParse!=0 );
    +   assert( pParse->db!=0 );
    +-  if( sqlite3AuthCheck(pParse, SQLITE_TRANSACTION, "ROLLBACK", 0, 0) ){
    ++  assert( eType==TK_COMMIT || eType==TK_END || eType==TK_ROLLBACK );
    ++  isRollback = eType==TK_ROLLBACK;
    ++  if( sqlite3AuthCheck(pParse, SQLITE_TRANSACTION, 
    ++       isRollback ? "ROLLBACK" : "COMMIT", 0, 0) ){
    +     return;
    +   }
    +   v = sqlite3GetVdbe(pParse);
    +   if( v ){
    +-    sqlite3VdbeAddOp2(v, OP_AutoCommit, 1, 1);
    ++    sqlite3VdbeAddOp2(v, OP_AutoCommit, 1, isRollback);
    +   }
    + }
    + 
    +@@ -96799,7 +105656,7 @@ SQLITE_PRIVATE int sqlite3OpenTempDatabase(Parse *pParse){
    +     db->aDb[1].pBt = pBt;
    +     assert( db->aDb[1].pSchema );
    +     if( SQLITE_NOMEM==sqlite3BtreeSetPageSize(pBt, db->nextPagesize, -1, 0) ){
    +-      db->mallocFailed = 1;
    ++      sqlite3OomFault(db);
    +       return 1;
    +     }
    +   }
    +@@ -96814,15 +105671,13 @@ SQLITE_PRIVATE int sqlite3OpenTempDatabase(Parse *pParse){
    + */
    + SQLITE_PRIVATE void sqlite3CodeVerifySchema(Parse *pParse, int iDb){
    +   Parse *pToplevel = sqlite3ParseToplevel(pParse);
    +-  sqlite3 *db = pToplevel->db;
    + 
    +-  assert( iDb>=0 && iDb<db->nDb );
    +-  assert( db->aDb[iDb].pBt!=0 || iDb==1 );
    ++  assert( iDb>=0 && iDb<pParse->db->nDb );
    ++  assert( pParse->db->aDb[iDb].pBt!=0 || iDb==1 );
    +   assert( iDb<SQLITE_MAX_ATTACHED+2 );
    +-  assert( sqlite3SchemaMutexHeld(db, iDb, 0) );
    ++  assert( sqlite3SchemaMutexHeld(pParse->db, iDb, 0) );
    +   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);
    +     }
    +@@ -96838,7 +105693,7 @@ SQLITE_PRIVATE void sqlite3CodeVerifyNamedSchema(Parse *pParse, const char *zDb)
    +   int i;
    +   for(i=0; i<db->nDb; i++){
    +     Db *pDb = &db->aDb[i];
    +-    if( pDb->pBt && (!zDb || 0==sqlite3StrICmp(zDb, pDb->zName)) ){
    ++    if( pDb->pBt && (!zDb || 0==sqlite3StrICmp(zDb, pDb->zDbSName)) ){
    +       sqlite3CodeVerifySchema(pParse, i);
    +     }
    +   }
    +@@ -96916,7 +105771,7 @@ SQLITE_PRIVATE void sqlite3HaltConstraint(
    +     sqlite3MayAbort(pParse);
    +   }
    +   sqlite3VdbeAddOp4(v, OP_Halt, errCode, onError, 0, p4, p4type);
    +-  if( p5Errmsg ) sqlite3VdbeChangeP5(v, p5Errmsg);
    ++  sqlite3VdbeChangeP5(v, p5Errmsg);
    + }
    + 
    + /*
    +@@ -96934,14 +105789,16 @@ SQLITE_PRIVATE void sqlite3UniqueConstraint(
    + 
    +   sqlite3StrAccumInit(&errMsg, pParse->db, 0, 0, 200);
    +   if( pIdx->aColExpr ){
    +-    sqlite3XPrintf(&errMsg, 0, "index '%q'", pIdx->zName);
    ++    sqlite3XPrintf(&errMsg, "index '%q'", pIdx->zName);
    +   }else{
    +     for(j=0; j<pIdx->nKeyCol; j++){
    +       char *zCol;
    +       assert( pIdx->aiColumn[j]>=0 );
    +       zCol = pTab->aCol[pIdx->aiColumn[j]].zName;
    +       if( j ) sqlite3StrAccumAppend(&errMsg, ", ", 2);
    +-      sqlite3XPrintf(&errMsg, 0, "%s.%s", pTab->zName, zCol);
    ++      sqlite3StrAccumAppendAll(&errMsg, pTab->zName);
    ++      sqlite3StrAccumAppend(&errMsg, ".", 1);
    ++      sqlite3StrAccumAppendAll(&errMsg, zCol);
    +     }
    +   }
    +   zErr = sqlite3StrAccumFinish(&errMsg);
    +@@ -97085,7 +105942,7 @@ SQLITE_PRIVATE void sqlite3Reindex(Parse *pParse, Token *pName1, Token *pName2){
    +   if( iDb<0 ) return;
    +   z = sqlite3NameFromToken(db, pObjName);
    +   if( z==0 ) return;
    +-  zDb = db->aDb[iDb].zName;
    ++  zDb = db->aDb[iDb].zDbSName;
    +   pTab = sqlite3FindTable(db, z, zDb);
    +   if( pTab ){
    +     reindexTable(pParse, pTab, 0);
    +@@ -97106,10 +105963,6 @@ SQLITE_PRIVATE void sqlite3Reindex(Parse *pParse, Token *pName1, Token *pName2){
    + /*
    + ** Return a KeyInfo structure that is appropriate for the given Index.
    + **
    +-** The KeyInfo structure for an index is cached in the Index object.
    +-** So there might be multiple references to the returned pointer.  The
    +-** caller should not try to modify the KeyInfo object.
    +-**
    + ** The caller should invoke sqlite3KeyInfoUnref() on the returned object
    + ** when it has finished using it.
    + */
    +@@ -97127,13 +105980,24 @@ SQLITE_PRIVATE KeyInfo *sqlite3KeyInfoOfIndex(Parse *pParse, Index *pIdx){
    +   if( pKey ){
    +     assert( sqlite3KeyInfoIsWriteable(pKey) );
    +     for(i=0; i<nCol; i++){
    +-      char *zColl = pIdx->azColl[i];
    +-      assert( zColl!=0 );
    +-      pKey->aColl[i] = strcmp(zColl,"BINARY")==0 ? 0 :
    ++      const char *zColl = pIdx->azColl[i];
    ++      pKey->aColl[i] = zColl==sqlite3StrBINARY ? 0 :
    +                         sqlite3LocateCollSeq(pParse, zColl);
    +       pKey->aSortOrder[i] = pIdx->aSortOrder[i];
    +     }
    +     if( pParse->nErr ){
    ++      assert( pParse->rc==SQLITE_ERROR_MISSING_COLLSEQ );
    ++      if( pIdx->bNoQuery==0 ){
    ++        /* Deactivate the index because it contains an unknown collating
    ++        ** sequence.  The only way to reactive the index is to reload the
    ++        ** schema.  Adding the missing collating sequence later does not
    ++        ** reactive the index.  The application had the chance to register
    ++        ** the missing index using the collation-needed callback.  For
    ++        ** simplicity, SQLite will not give the application a second chance.
    ++        */
    ++        pIdx->bNoQuery = 1;
    ++        pParse->rc = SQLITE_ERROR_RETRY;
    ++      }
    +       sqlite3KeyInfoUnref(pKey);
    +       pKey = 0;
    +     }
    +@@ -97175,10 +106039,9 @@ SQLITE_PRIVATE With *sqlite3WithAdd(
    +   }else{
    +     pNew = sqlite3DbMallocZero(db, sizeof(*pWith));
    +   }
    +-  assert( zName!=0 || pNew==0 );
    +-  assert( db->mallocFailed==0 || pNew==0 );
    ++  assert( (pNew!=0 && zName!=0) || db->mallocFailed );
    + 
    +-  if( pNew==0 ){
    ++  if( db->mallocFailed ){
    +     sqlite3ExprListDelete(db, pArglist);
    +     sqlite3SelectDelete(db, pQuery);
    +     sqlite3DbFree(db, zName);
    +@@ -97320,6 +106183,7 @@ SQLITE_PRIVATE CollSeq *sqlite3GetCollSeq(
    +   assert( !p || p->xCmp );
    +   if( p==0 ){
    +     sqlite3ErrorMsg(pParse, "no such collation sequence: %s", zName);
    ++    pParse->rc = SQLITE_ERROR_MISSING_COLLSEQ;
    +   }
    +   return p;
    + }
    +@@ -97336,7 +106200,7 @@ SQLITE_PRIVATE CollSeq *sqlite3GetCollSeq(
    + ** from the main database is substituted, if one is available.
    + */
    + SQLITE_PRIVATE int sqlite3CheckCollSeq(Parse *pParse, CollSeq *pColl){
    +-  if( pColl ){
    ++  if( pColl && pColl->xCmp==0 ){
    +     const char *zName = pColl->zName;
    +     sqlite3 *db = pParse->db;
    +     CollSeq *p = sqlite3GetCollSeq(pParse, ENC(db), pColl, zName);
    +@@ -97372,8 +106236,8 @@ static CollSeq *findCollSeqEntry(
    +   pColl = sqlite3HashFind(&db->aCollSeq, zName);
    + 
    +   if( 0==pColl && create ){
    +-    int nName = sqlite3Strlen30(zName);
    +-    pColl = sqlite3DbMallocZero(db, 3*sizeof(*pColl) + nName + 1);
    ++    int nName = sqlite3Strlen30(zName) + 1;
    ++    pColl = sqlite3DbMallocZero(db, 3*sizeof(*pColl) + nName);
    +     if( pColl ){
    +       CollSeq *pDel = 0;
    +       pColl[0].zName = (char*)&pColl[3];
    +@@ -97383,7 +106247,6 @@ static CollSeq *findCollSeqEntry(
    +       pColl[2].zName = (char*)&pColl[3];
    +       pColl[2].enc = SQLITE_UTF16BE;
    +       memcpy(pColl[0].zName, zName, nName);
    +-      pColl[0].zName[nName] = 0;
    +       pDel = sqlite3HashInsert(&db->aCollSeq, pColl[0].zName, pColl);
    + 
    +       /* If a malloc() failure occurred in sqlite3HashInsert(), it will 
    +@@ -97392,7 +106255,7 @@ static CollSeq *findCollSeqEntry(
    +       */
    +       assert( pDel==0 || pDel==pColl );
    +       if( pDel!=0 ){
    +-        db->mallocFailed = 1;
    ++        sqlite3OomFault(db);
    +         sqlite3DbFree(db, pDel);
    +         pColl = 0;
    +       }
    +@@ -97458,8 +106321,8 @@ SQLITE_PRIVATE CollSeq *sqlite3FindCollSeq(
    + ** 5: UTF16 byte order conversion required - argument count matches exactly
    + ** 6: Perfect match:  encoding and argument count match exactly.
    + **
    +-** If nArg==(-2) then any function with a non-null xStep or xFunc is
    +-** a perfect match and any function with both xStep and xFunc NULL is
    ++** If nArg==(-2) then any function with a non-null xSFunc is
    ++** a perfect match and any function with xSFunc NULL is
    + ** a non-match.
    + */
    + #define FUNC_PERFECT_MATCH 6  /* The score for a perfect match */
    +@@ -97471,7 +106334,7 @@ static int matchQuality(
    +   int match;
    + 
    +   /* nArg of -2 is a special case */
    +-  if( nArg==(-2) ) return (p->xFunc==0 && p->xStep==0) ? 0 : FUNC_PERFECT_MATCH;
    ++  if( nArg==(-2) ) return (p->xSFunc==0) ? 0 : FUNC_PERFECT_MATCH;
    + 
    +   /* Wrong number of arguments means "no match" */
    +   if( p->nArg!=nArg && p->nArg>=0 ) return 0;
    +@@ -97499,14 +106362,12 @@ static int matchQuality(
    + ** a pointer to the matching FuncDef if found, or 0 if there is no match.
    + */
    + static FuncDef *functionSearch(
    +-  FuncDefHash *pHash,  /* Hash table to search */
    +   int h,               /* Hash of the name */
    +-  const char *zFunc,   /* Name of function */
    +-  int nFunc            /* Number of bytes in zFunc */
    ++  const char *zFunc    /* Name of function */
    + ){
    +   FuncDef *p;
    +-  for(p=pHash->a[h]; p; p=p->pHash){
    +-    if( sqlite3StrNICmp(p->zName, zFunc, nFunc)==0 && p->zName[nFunc]==0 ){
    ++  for(p=sqlite3BuiltinFunctions.a[h]; p; p=p->u.pHash){
    ++    if( sqlite3StrICmp(p->zName, zFunc)==0 ){
    +       return p;
    +     }
    +   }
    +@@ -97516,23 +106377,27 @@ static FuncDef *functionSearch(
    + /*
    + ** Insert a new FuncDef into a FuncDefHash hash table.
    + */
    +-SQLITE_PRIVATE void sqlite3FuncDefInsert(
    +-  FuncDefHash *pHash,  /* The hash table into which to insert */
    +-  FuncDef *pDef        /* The function definition to insert */
    ++SQLITE_PRIVATE void sqlite3InsertBuiltinFuncs(
    ++  FuncDef *aDef,      /* List of global functions to be inserted */
    ++  int nDef            /* Length of the apDef[] list */
    + ){
    +-  FuncDef *pOther;
    +-  int nName = sqlite3Strlen30(pDef->zName);
    +-  u8 c1 = (u8)pDef->zName[0];
    +-  int h = (sqlite3UpperToLower[c1] + nName) % ArraySize(pHash->a);
    +-  pOther = functionSearch(pHash, h, pDef->zName, nName);
    +-  if( pOther ){
    +-    assert( pOther!=pDef && pOther->pNext!=pDef );
    +-    pDef->pNext = pOther->pNext;
    +-    pOther->pNext = pDef;
    +-  }else{
    +-    pDef->pNext = 0;
    +-    pDef->pHash = pHash->a[h];
    +-    pHash->a[h] = pDef;
    ++  int i;
    ++  for(i=0; i<nDef; i++){
    ++    FuncDef *pOther;
    ++    const char *zName = aDef[i].zName;
    ++    int nName = sqlite3Strlen30(zName);
    ++    int h = (zName[0] + nName) % SQLITE_FUNC_HASH_SZ;
    ++    assert( zName[0]>='a' && zName[0]<='z' );
    ++    pOther = functionSearch(h, zName);
    ++    if( pOther ){
    ++      assert( pOther!=&aDef[i] && pOther->pNext!=&aDef[i] );
    ++      aDef[i].pNext = pOther->pNext;
    ++      pOther->pNext = &aDef[i];
    ++    }else{
    ++      aDef[i].pNext = 0;
    ++      aDef[i].u.pHash = sqlite3BuiltinFunctions.a[h];
    ++      sqlite3BuiltinFunctions.a[h] = &aDef[i];
    ++    }
    +   }
    + }
    +   
    +@@ -97549,7 +106414,7 @@ SQLITE_PRIVATE void sqlite3FuncDefInsert(
    + ** no matching function previously existed.
    + **
    + ** If nArg is -2, then the first valid function found is returned.  A
    +-** function is valid if either xFunc or xStep is non-zero.  The nArg==(-2)
    ++** function is valid if xSFunc is non-zero.  The nArg==(-2)
    + ** case is used to see if zName is a valid function name for some number
    + ** of arguments.  If nArg is -2, then createFlag must be 0.
    + **
    +@@ -97559,8 +106424,7 @@ SQLITE_PRIVATE void sqlite3FuncDefInsert(
    + */
    + SQLITE_PRIVATE FuncDef *sqlite3FindFunction(
    +   sqlite3 *db,       /* An open database */
    +-  const char *zName, /* Name of the function.  Not null-terminated */
    +-  int nName,         /* Number of characters in the name */
    ++  const char *zName, /* Name of the function.  zero-terminated */
    +   int nArg,          /* Number of arguments.  -1 means any number */
    +   u8 enc,            /* Preferred text encoding */
    +   u8 createFlag      /* Create new entry if true and does not otherwise exist */
    +@@ -97569,14 +106433,15 @@ SQLITE_PRIVATE FuncDef *sqlite3FindFunction(
    +   FuncDef *pBest = 0; /* Best match found so far */
    +   int bestScore = 0;  /* Score of best match */
    +   int h;              /* Hash value */
    ++  int nName;          /* Length of the name */
    + 
    +   assert( nArg>=(-2) );
    +   assert( nArg>=(-1) || createFlag==0 );
    +-  h = (sqlite3UpperToLower[(u8)zName[0]] + nName) % ArraySize(db->aFunc.a);
    ++  nName = sqlite3Strlen30(zName);
    + 
    +   /* First search for a match amongst the application-defined functions.
    +   */
    +-  p = functionSearch(&db->aFunc, h, zName, nName);
    ++  p = (FuncDef*)sqlite3HashFind(&db->aFunc, zName);
    +   while( p ){
    +     int score = matchQuality(p, nArg, enc);
    +     if( score>bestScore ){
    +@@ -97588,7 +106453,7 @@ SQLITE_PRIVATE FuncDef *sqlite3FindFunction(
    + 
    +   /* If no match is found, search the built-in functions.
    +   **
    +-  ** If the SQLITE_PreferBuiltin flag is set, then search the built-in
    ++  ** If the DBFLAG_PreferBuiltin flag is set, then search the built-in
    +   ** functions even if a prior app-defined function was found.  And give
    +   ** priority to built-in functions.
    +   **
    +@@ -97598,10 +106463,10 @@ SQLITE_PRIVATE FuncDef *sqlite3FindFunction(
    +   ** new function.  But the FuncDefs for built-in functions are read-only.
    +   ** So we must not search for built-ins when creating a new function.
    +   */ 
    +-  if( !createFlag && (pBest==0 || (db->flags & SQLITE_PreferBuiltin)!=0) ){
    +-    FuncDefHash *pHash = &GLOBAL(FuncDefHash, sqlite3GlobalFunctions);
    ++  if( !createFlag && (pBest==0 || (db->mDbFlags & DBFLAG_PreferBuiltin)!=0) ){
    +     bestScore = 0;
    +-    p = functionSearch(pHash, h, zName, nName);
    ++    h = (sqlite3UpperToLower[(u8)zName[0]] + nName) % SQLITE_FUNC_HASH_SZ;
    ++    p = functionSearch(h, zName);
    +     while( p ){
    +       int score = matchQuality(p, nArg, enc);
    +       if( score>bestScore ){
    +@@ -97618,15 +106483,22 @@ SQLITE_PRIVATE FuncDef *sqlite3FindFunction(
    +   */
    +   if( createFlag && bestScore<FUNC_PERFECT_MATCH && 
    +       (pBest = sqlite3DbMallocZero(db, sizeof(*pBest)+nName+1))!=0 ){
    +-    pBest->zName = (char *)&pBest[1];
    ++    FuncDef *pOther;
    ++    pBest->zName = (const char*)&pBest[1];
    +     pBest->nArg = (u16)nArg;
    +     pBest->funcFlags = enc;
    +-    memcpy(pBest->zName, zName, nName);
    +-    pBest->zName[nName] = 0;
    +-    sqlite3FuncDefInsert(&db->aFunc, pBest);
    ++    memcpy((char*)&pBest[1], zName, nName+1);
    ++    pOther = (FuncDef*)sqlite3HashInsert(&db->aFunc, pBest->zName, pBest);
    ++    if( pOther==pBest ){
    ++      sqlite3DbFree(db, pBest);
    ++      sqlite3OomFault(db);
    ++      return 0;
    ++    }else{
    ++      pBest->pNext = pOther;
    ++    }
    +   }
    + 
    +-  if( pBest && (pBest->xStep || pBest->xFunc || createFlag) ){
    ++  if( pBest && (pBest->xSFunc || createFlag) ){
    +     return pBest;
    +   }
    +   return 0;
    +@@ -97664,8 +106536,8 @@ SQLITE_PRIVATE void sqlite3SchemaClear(void *p){
    +   pSchema->pSeqTab = 0;
    +   if( pSchema->schemaFlags & DB_SchemaLoaded ){
    +     pSchema->iGeneration++;
    +-    pSchema->schemaFlags &= ~DB_SchemaLoaded;
    +   }
    ++  pSchema->schemaFlags &= ~(DB_SchemaLoaded|DB_ResetWanted);
    + }
    + 
    + /*
    +@@ -97680,7 +106552,7 @@ SQLITE_PRIVATE Schema *sqlite3SchemaGet(sqlite3 *db, Btree *pBt){
    +     p = (Schema *)sqlite3DbMallocZero(0, sizeof(Schema));
    +   }
    +   if( !p ){
    +-    db->mallocFailed = 1;
    ++    sqlite3OomFault(db);
    +   }else if ( 0==p->file_format ){
    +     sqlite3HashInit(&p->tblHash);
    +     sqlite3HashInit(&p->idxHash);
    +@@ -97731,7 +106603,7 @@ SQLITE_PRIVATE Table *sqlite3SrcListLookup(Parse *pParse, SrcList *pSrc){
    +   sqlite3DeleteTable(pParse->db, pItem->pTab);
    +   pItem->pTab = pTab;
    +   if( pTab ){
    +-    pTab->nRef++;
    ++    pTab->nTabRef++;
    +   }
    +   if( sqlite3IndexedByLookup(pParse, pItem) ){
    +     pTab = 0;
    +@@ -97785,6 +106657,8 @@ SQLITE_PRIVATE void sqlite3MaterializeView(
    +   Parse *pParse,       /* Parsing context */
    +   Table *pView,        /* View definition */
    +   Expr *pWhere,        /* Optional WHERE clause to be added */
    ++  ExprList *pOrderBy,  /* Optional ORDER BY clause */
    ++  Expr *pLimit,        /* Optional LIMIT clause */
    +   int iCur             /* Cursor number for ephemeral table */
    + ){
    +   SelectDest dest;
    +@@ -97797,11 +106671,12 @@ SQLITE_PRIVATE void sqlite3MaterializeView(
    +   if( pFrom ){
    +     assert( pFrom->nSrc==1 );
    +     pFrom->a[0].zName = sqlite3DbStrDup(db, pView->zName);
    +-    pFrom->a[0].zDatabase = sqlite3DbStrDup(db, db->aDb[iDb].zName);
    ++    pFrom->a[0].zDatabase = sqlite3DbStrDup(db, db->aDb[iDb].zDbSName);
    +     assert( pFrom->a[0].pOn==0 );
    +     assert( pFrom->a[0].pUsing==0 );
    +   }
    +-  pSel = sqlite3SelectNew(pParse, 0, pFrom, pWhere, 0, 0, 0, 0, 0, 0);
    ++  pSel = sqlite3SelectNew(pParse, 0, pFrom, pWhere, 0, 0, pOrderBy, 
    ++                          SF_IncludeHidden, pLimit);
    +   sqlite3SelectDestInit(&dest, SRT_EphemTab, iCur);
    +   sqlite3Select(pParse, pSel, &dest);
    +   sqlite3SelectDelete(db, pSel);
    +@@ -97823,29 +106698,29 @@ SQLITE_PRIVATE Expr *sqlite3LimitWhere(
    +   Expr *pWhere,                /* The WHERE clause.  May be null */
    +   ExprList *pOrderBy,          /* The ORDER BY clause.  May be null */
    +   Expr *pLimit,                /* The LIMIT clause.  May be null */
    +-  Expr *pOffset,               /* The OFFSET clause.  May be null */
    +   char *zStmtType              /* Either DELETE or UPDATE.  For err msgs. */
    + ){
    +-  Expr *pWhereRowid = NULL;    /* WHERE rowid .. */
    ++  sqlite3 *db = pParse->db;
    ++  Expr *pLhs = NULL;           /* LHS of IN(SELECT...) operator */
    +   Expr *pInClause = NULL;      /* WHERE rowid IN ( select ) */
    +-  Expr *pSelectRowid = NULL;   /* SELECT rowid ... */
    +   ExprList *pEList = NULL;     /* Expression list contaning only pSelectRowid */
    +   SrcList *pSelectSrc = NULL;  /* SELECT rowid FROM x ... (dup of pSrc) */
    +   Select *pSelect = NULL;      /* Complete SELECT tree */
    ++  Table *pTab;
    + 
    +   /* Check that there isn't an ORDER BY without a LIMIT clause.
    +   */
    +-  if( pOrderBy && (pLimit == 0) ) {
    ++  if( pOrderBy && pLimit==0 ) {
    +     sqlite3ErrorMsg(pParse, "ORDER BY without LIMIT on %s", zStmtType);
    +-    goto limit_where_cleanup_2;
    ++    sqlite3ExprDelete(pParse->db, pWhere);
    ++    sqlite3ExprListDelete(pParse->db, pOrderBy);
    ++    return 0;
    +   }
    + 
    +   /* We only need to generate a select expression if there
    +   ** is a limit/offset term to enforce.
    +   */
    +   if( pLimit == 0 ) {
    +-    /* if pLimit is null, pOffset will always be null as well. */
    +-    assert( pOffset == 0 );
    +     return pWhere;
    +   }
    + 
    +@@ -97858,46 +106733,47 @@ SQLITE_PRIVATE Expr *sqlite3LimitWhere(
    +   **   );
    +   */
    + 
    +-  pSelectRowid = sqlite3PExpr(pParse, TK_ROW, 0, 0, 0);
    +-  if( pSelectRowid == 0 ) goto limit_where_cleanup_2;
    +-  pEList = sqlite3ExprListAppend(pParse, 0, pSelectRowid);
    +-  if( pEList == 0 ) goto limit_where_cleanup_2;
    ++  pTab = pSrc->a[0].pTab;
    ++  if( HasRowid(pTab) ){
    ++    pLhs = sqlite3PExpr(pParse, TK_ROW, 0, 0);
    ++    pEList = sqlite3ExprListAppend(
    ++        pParse, 0, sqlite3PExpr(pParse, TK_ROW, 0, 0)
    ++    );
    ++  }else{
    ++    Index *pPk = sqlite3PrimaryKeyIndex(pTab);
    ++    if( pPk->nKeyCol==1 ){
    ++      const char *zName = pTab->aCol[pPk->aiColumn[0]].zName;
    ++      pLhs = sqlite3Expr(db, TK_ID, zName);
    ++      pEList = sqlite3ExprListAppend(pParse, 0, sqlite3Expr(db, TK_ID, zName));
    ++    }else{
    ++      int i;
    ++      for(i=0; i<pPk->nKeyCol; i++){
    ++        Expr *p = sqlite3Expr(db, TK_ID, pTab->aCol[pPk->aiColumn[i]].zName);
    ++        pEList = sqlite3ExprListAppend(pParse, pEList, p);
    ++      }
    ++      pLhs = sqlite3PExpr(pParse, TK_VECTOR, 0, 0);
    ++      if( pLhs ){
    ++        pLhs->x.pList = sqlite3ExprListDup(db, pEList, 0);
    ++      }
    ++    }
    ++  }
    + 
    +   /* duplicate the FROM clause as it is needed by both the DELETE/UPDATE tree
    +   ** and the SELECT subtree. */
    ++  pSrc->a[0].pTab = 0;
    +   pSelectSrc = sqlite3SrcListDup(pParse->db, pSrc, 0);
    +-  if( pSelectSrc == 0 ) {
    +-    sqlite3ExprListDelete(pParse->db, pEList);
    +-    goto limit_where_cleanup_2;
    +-  }
    ++  pSrc->a[0].pTab = pTab;
    ++  pSrc->a[0].pIBIndex = 0;
    + 
    +   /* generate the SELECT expression tree. */
    +-  pSelect = sqlite3SelectNew(pParse,pEList,pSelectSrc,pWhere,0,0,
    +-                             pOrderBy,0,pLimit,pOffset);
    +-  if( pSelect == 0 ) return 0;
    ++  pSelect = sqlite3SelectNew(pParse, pEList, pSelectSrc, pWhere, 0 ,0, 
    ++      pOrderBy,0,pLimit
    ++  );
    + 
    +   /* now generate the new WHERE rowid IN clause for the DELETE/UDPATE */
    +-  pWhereRowid = sqlite3PExpr(pParse, TK_ROW, 0, 0, 0);
    +-  if( pWhereRowid == 0 ) goto limit_where_cleanup_1;
    +-  pInClause = sqlite3PExpr(pParse, TK_IN, pWhereRowid, 0, 0);
    +-  if( pInClause == 0 ) goto limit_where_cleanup_1;
    +-
    +-  pInClause->x.pSelect = pSelect;
    +-  pInClause->flags |= EP_xIsSelect;
    +-  sqlite3ExprSetHeightAndFlags(pParse, pInClause);
    ++  pInClause = sqlite3PExpr(pParse, TK_IN, pLhs, 0);
    ++  sqlite3PExprAddSelect(pParse, pInClause, pSelect);
    +   return pInClause;
    +-
    +-  /* something went wrong. clean up anything allocated. */
    +-limit_where_cleanup_1:
    +-  sqlite3SelectDelete(pParse->db, pSelect);
    +-  return 0;
    +-
    +-limit_where_cleanup_2:
    +-  sqlite3ExprDelete(pParse->db, pWhere);
    +-  sqlite3ExprListDelete(pParse->db, pOrderBy);
    +-  sqlite3ExprDelete(pParse->db, pLimit);
    +-  sqlite3ExprDelete(pParse->db, pOffset);
    +-  return 0;
    + }
    + #endif /* defined(SQLITE_ENABLE_UPDATE_DELETE_LIMIT) */
    +        /*      && !defined(SQLITE_OMIT_SUBQUERY) */
    +@@ -97912,11 +106788,12 @@ limit_where_cleanup_2:
    + SQLITE_PRIVATE void sqlite3DeleteFrom(
    +   Parse *pParse,         /* The parser context */
    +   SrcList *pTabList,     /* The table from which we should delete things */
    +-  Expr *pWhere           /* The WHERE clause.  May be null */
    ++  Expr *pWhere,          /* The WHERE clause.  May be null */
    ++  ExprList *pOrderBy,    /* ORDER BY clause. May be null */
    ++  Expr *pLimit           /* LIMIT clause. May be null */
    + ){
    +   Vdbe *v;               /* The virtual database engine */
    +   Table *pTab;           /* The table from which records will be deleted */
    +-  const char *zDb;       /* Name of database holding pTab */
    +   int i;                 /* Loop counter */
    +   WhereInfo *pWInfo;     /* Information about the WHERE clause */
    +   Index *pIdx;           /* For looping over indices of the table */
    +@@ -97943,11 +106820,12 @@ SQLITE_PRIVATE void sqlite3DeleteFrom(
    +   int addrBypass = 0;    /* Address of jump over the delete logic */
    +   int addrLoop = 0;      /* Top of the delete loop */
    +   int addrEphOpen = 0;   /* Instruction to open the Ephemeral table */
    ++  int bComplex;          /* True if there are triggers or FKs or
    ++                         ** subqueries in the WHERE clause */
    +  
    + #ifndef SQLITE_OMIT_TRIGGER
    +   int isView;                  /* True if attempting to delete from a view */
    +   Trigger *pTrigger;           /* List of table triggers, if required */
    +-  int bComplex;                /* True if there are either triggers or FKs */
    + #endif
    + 
    +   memset(&sContext, 0, sizeof(sContext));
    +@@ -97957,6 +106835,7 @@ SQLITE_PRIVATE void sqlite3DeleteFrom(
    +   }
    +   assert( pTabList->nSrc==1 );
    + 
    ++
    +   /* Locate the table which we want to delete.  This table has to be
    +   ** put in an SrcList structure because some of the subroutines we
    +   ** will be calling are designed to work with multiple tables and expect
    +@@ -97971,17 +106850,26 @@ SQLITE_PRIVATE void sqlite3DeleteFrom(
    + #ifndef SQLITE_OMIT_TRIGGER
    +   pTrigger = sqlite3TriggersExist(pParse, pTab, TK_DELETE, 0, 0);
    +   isView = pTab->pSelect!=0;
    +-  bComplex = pTrigger || sqlite3FkRequired(pParse, pTab, 0, 0);
    + #else
    + # define pTrigger 0
    + # define isView 0
    +-# define bComplex 0
    + #endif
    ++  bComplex = pTrigger || sqlite3FkRequired(pParse, pTab, 0, 0);
    + #ifdef SQLITE_OMIT_VIEW
    + # undef isView
    + # define isView 0
    + #endif
    + 
    ++#ifdef SQLITE_ENABLE_UPDATE_DELETE_LIMIT
    ++  if( !isView ){
    ++    pWhere = sqlite3LimitWhere(
    ++        pParse, pTabList, pWhere, pOrderBy, pLimit, "DELETE"
    ++    );
    ++    pOrderBy = 0;
    ++    pLimit = 0;
    ++  }
    ++#endif
    ++
    +   /* If pTab is really a view, make sure it has been initialized.
    +   */
    +   if( sqlite3ViewGetColumnNames(pParse, pTab) ){
    +@@ -97993,8 +106881,8 @@ SQLITE_PRIVATE void sqlite3DeleteFrom(
    +   }
    +   iDb = sqlite3SchemaToIndex(db, pTab->pSchema);
    +   assert( iDb<db->nDb );
    +-  zDb = db->aDb[iDb].zName;
    +-  rcauth = sqlite3AuthCheck(pParse, SQLITE_DELETE, pTab->zName, 0, zDb);
    ++  rcauth = sqlite3AuthCheck(pParse, SQLITE_DELETE, pTab->zName, 0, 
    ++                            db->aDb[iDb].zDbSName);
    +   assert( rcauth==SQLITE_OK || rcauth==SQLITE_DENY || rcauth==SQLITE_IGNORE );
    +   if( rcauth==SQLITE_DENY ){
    +     goto delete_from_cleanup;
    +@@ -98029,8 +106917,12 @@ SQLITE_PRIVATE void sqlite3DeleteFrom(
    +   */
    + #if !defined(SQLITE_OMIT_VIEW) && !defined(SQLITE_OMIT_TRIGGER)
    +   if( isView ){
    +-    sqlite3MaterializeView(pParse, pTab, pWhere, iTabCur);
    ++    sqlite3MaterializeView(pParse, pTab, 
    ++        pWhere, pOrderBy, pLimit, iTabCur
    ++    );
    +     iDataCur = iIdxCur = iTabCur;
    ++    pOrderBy = 0;
    ++    pLimit = 0;
    +   }
    + #endif
    + 
    +@@ -98055,11 +106947,21 @@ SQLITE_PRIVATE void sqlite3DeleteFrom(
    +   /* Special case: A DELETE without a WHERE clause deletes everything.
    +   ** It is easier just to erase the whole table. Prior to version 3.6.5,
    +   ** this optimization caused the row change count (the value returned by 
    +-  ** API function sqlite3_count_changes) to be set incorrectly.  */
    ++  ** API function sqlite3_count_changes) to be set incorrectly.
    ++  **
    ++  ** The "rcauth==SQLITE_OK" terms is the
    ++  ** IMPLEMENTATION-OF: R-17228-37124 If the action code is SQLITE_DELETE and
    ++  ** the callback returns SQLITE_IGNORE then the DELETE operation proceeds but
    ++  ** the truncate optimization is disabled and all rows are deleted
    ++  ** individually.
    ++  */
    +   if( rcauth==SQLITE_OK
    +    && pWhere==0
    +    && !bComplex
    +    && !IsVirtual(pTab)
    ++#ifdef SQLITE_ENABLE_PREUPDATE_HOOK
    ++   && db->xPreUpdateCallback==0
    ++#endif
    +   ){
    +     assert( !isView );
    +     sqlite3TableLock(pParse, iDb, pTab->tnum, 1, pTab->zName);
    +@@ -98074,7 +106976,8 @@ SQLITE_PRIVATE void sqlite3DeleteFrom(
    +   }else
    + #endif /* SQLITE_OMIT_TRUNCATE_OPTIMIZATION */
    +   {
    +-    u16 wcf = WHERE_ONEPASS_DESIRED|WHERE_DUPLICATES_OK;
    ++    u16 wcf = WHERE_ONEPASS_DESIRED|WHERE_DUPLICATES_OK|WHERE_SEEK_TABLE;
    ++    if( sNC.ncFlags & NC_VarSelect ) bComplex = 1;
    +     wcf |= (bComplex ? 0 : WHERE_ONEPASS_MULTIROW);
    +     if( HasRowid(pTab) ){
    +       /* For a rowid table, initialize the RowSet to an empty set */
    +@@ -98133,7 +107036,7 @@ SQLITE_PRIVATE void sqlite3DeleteFrom(
    +       ** one, so just keep it in its register(s) and fall through to the
    +       ** delete code.  */
    +       nKey = nPk; /* OP_Found will use an unpacked key */
    +-      aToOpen = sqlite3DbMallocRaw(db, nIdx+2);
    ++      aToOpen = sqlite3DbMallocRawNN(db, nIdx+2);
    +       if( aToOpen==0 ){
    +         sqlite3WhereEnd(pWInfo);
    +         goto delete_from_cleanup;
    +@@ -98150,10 +107053,10 @@ SQLITE_PRIVATE void sqlite3DeleteFrom(
    +         nKey = 0;   /* Zero tells OP_Found to use a composite key */
    +         sqlite3VdbeAddOp4(v, OP_MakeRecord, iPk, nPk, iKey,
    +             sqlite3IndexAffinityStr(pParse->db, pPk), nPk);
    +-        sqlite3VdbeAddOp2(v, OP_IdxInsert, iEphCur, iKey);
    ++        sqlite3VdbeAddOp4Int(v, OP_IdxInsert, iEphCur, iKey, iPk, nPk);
    +       }else{
    +         /* Add the rowid of the row to be deleted to the RowSet */
    +-        nKey = 1;  /* OP_Seek always uses a single rowid */
    ++        nKey = 1;  /* OP_DeferredSeek always uses a single rowid */
    +         sqlite3VdbeAddOp2(v, OP_RowSetAdd, iRowSet, iKey);
    +       }
    +     }
    +@@ -98174,11 +107077,11 @@ SQLITE_PRIVATE void sqlite3DeleteFrom(
    +     if( !isView ){
    +       int iAddrOnce = 0;
    +       if( eOnePass==ONEPASS_MULTI ){
    +-        iAddrOnce = sqlite3CodeOnce(pParse); VdbeCoverage(v);
    ++        iAddrOnce = sqlite3VdbeAddOp0(v, OP_Once); VdbeCoverage(v);
    +       }
    +       testcase( IsVirtual(pTab) );
    +-      sqlite3OpenTableAndIndices(pParse, pTab, OP_OpenWrite, iTabCur, aToOpen,
    +-                                 &iDataCur, &iIdxCur);
    ++      sqlite3OpenTableAndIndices(pParse, pTab, OP_OpenWrite, OPFLAG_FORDELETE,
    ++                                 iTabCur, aToOpen, &iDataCur, &iIdxCur);
    +       assert( pPk || IsVirtual(pTab) || iDataCur==iTabCur );
    +       assert( pPk || IsVirtual(pTab) || iIdxCur==iDataCur+1 );
    +       if( eOnePass==ONEPASS_MULTI ) sqlite3VdbeJumpHere(v, iAddrOnce);
    +@@ -98196,7 +107099,11 @@ SQLITE_PRIVATE void sqlite3DeleteFrom(
    +       }
    +     }else if( pPk ){
    +       addrLoop = sqlite3VdbeAddOp1(v, OP_Rewind, iEphCur); VdbeCoverage(v);
    +-      sqlite3VdbeAddOp2(v, OP_RowKey, iEphCur, iKey);
    ++      if( IsVirtual(pTab) ){
    ++        sqlite3VdbeAddOp3(v, OP_Column, iEphCur, 0, iKey);
    ++      }else{
    ++        sqlite3VdbeAddOp2(v, OP_RowData, iEphCur, iKey);
    ++      }
    +       assert( nKey==0 );  /* OP_Found will use a composite key */
    +     }else{
    +       addrLoop = sqlite3VdbeAddOp3(v, OP_RowSetRead, iRowSet, 0, iKey);
    +@@ -98220,12 +107127,8 @@ SQLITE_PRIVATE void sqlite3DeleteFrom(
    + #endif
    +     {
    +       int count = (pParse->nested==0);    /* True to count changes */
    +-      int iIdxNoSeek = -1;
    +-      if( bComplex==0 && aiCurOnePass[1]!=iDataCur ){
    +-        iIdxNoSeek = aiCurOnePass[1];
    +-      }
    +       sqlite3GenerateRowDelete(pParse, pTab, pTrigger, iDataCur, iIdxCur,
    +-          iKey, nKey, count, OE_Default, eOnePass, iIdxNoSeek);
    ++          iKey, nKey, count, OE_Default, eOnePass, aiCurOnePass[1]);
    +     }
    +   
    +     /* End of the loop over all rowids/primary-keys. */
    +@@ -98239,14 +107142,6 @@ SQLITE_PRIVATE void sqlite3DeleteFrom(
    +       sqlite3VdbeGoto(v, addrLoop);
    +       sqlite3VdbeJumpHere(v, addrLoop);
    +     }     
    +-  
    +-    /* Close the cursors open on the table and its indexes. */
    +-    if( !isView && !IsVirtual(pTab) ){
    +-      if( !pPk ) sqlite3VdbeAddOp1(v, OP_Close, iDataCur);
    +-      for(i=0, pIdx=pTab->pIndex; pIdx; i++, pIdx=pIdx->pNext){
    +-        sqlite3VdbeAddOp1(v, OP_Close, iIdxCur + i);
    +-      }
    +-    }
    +   } /* End non-truncate path */
    + 
    +   /* Update the sqlite_sequence table by storing the content of the
    +@@ -98271,6 +107166,10 @@ delete_from_cleanup:
    +   sqlite3AuthContextPop(&sContext);
    +   sqlite3SrcListDelete(db, pTabList);
    +   sqlite3ExprDelete(db, pWhere);
    ++#if defined(SQLITE_ENABLE_UPDATE_DELETE_LIMIT) 
    ++  sqlite3ExprListDelete(db, pOrderBy);
    ++  sqlite3ExprDelete(db, pLimit);
    ++#endif
    +   sqlite3DbFree(db, aToOpen);
    +   return;
    + }
    +@@ -98313,15 +107212,17 @@ delete_from_cleanup:
    + **
    + **   If eMode is ONEPASS_MULTI, then this call is being made as part
    + **   of a ONEPASS delete that affects multiple rows. In this case, if 
    +-**   iIdxNoSeek is a valid cursor number (>=0), then its position should
    +-**   be preserved following the delete operation. Or, if iIdxNoSeek is not
    +-**   a valid cursor number, the position of iDataCur should be preserved
    +-**   instead.
    ++**   iIdxNoSeek is a valid cursor number (>=0) and is not the same as
    ++**   iDataCur, then its position should be preserved following the delete
    ++**   operation. Or, if iIdxNoSeek is not a valid cursor number, the
    ++**   position of iDataCur should be preserved instead.
    + **
    + ** iIdxNoSeek:
    +-**   If iIdxNoSeek is a valid cursor number (>=0), then it identifies an
    +-**   index cursor (from within array of cursors starting at iIdxCur) that
    +-**   already points to the index entry to be deleted.
    ++**   If iIdxNoSeek is a valid cursor number (>=0) not equal to iDataCur,
    ++**   then it identifies an index cursor (from within array of cursors
    ++**   starting at iIdxCur) that already points to the index entry to be deleted.
    ++**   Except, this optimization is disabled if there are BEFORE triggers since
    ++**   the trigger body might have moved the cursor.
    + */
    + SQLITE_PRIVATE void sqlite3GenerateRowDelete(
    +   Parse *pParse,     /* Parsing context */
    +@@ -98392,13 +107293,18 @@ SQLITE_PRIVATE void sqlite3GenerateRowDelete(
    + 
    +     /* If any BEFORE triggers were coded, then seek the cursor to the 
    +     ** row to be deleted again. It may be that the BEFORE triggers moved
    +-    ** the cursor or of already deleted the row that the cursor was
    ++    ** the cursor or already deleted the row that the cursor was
    +     ** pointing to.
    ++    **
    ++    ** Also disable the iIdxNoSeek optimization since the BEFORE trigger
    ++    ** may have moved that cursor.
    +     */
    +     if( addrStart<sqlite3VdbeCurrentAddr(v) ){
    +       sqlite3VdbeAddOp4Int(v, opSeek, iDataCur, iLabel, iPk, nPk);
    +       VdbeCoverageIf(v, opSeek==OP_NotExists);
    +       VdbeCoverageIf(v, opSeek==OP_NotFound);
    ++      testcase( iIdxNoSeek>=0 );
    ++      iIdxNoSeek = -1;
    +     }
    + 
    +     /* Do FK processing. This call checks that any FK constraints that
    +@@ -98409,17 +107315,29 @@ SQLITE_PRIVATE void sqlite3GenerateRowDelete(
    + 
    +   /* Delete the index and table entries. Skip this step if pTab is really
    +   ** a view (in which case the only effect of the DELETE statement is to
    +-  ** fire the INSTEAD OF triggers).  */ 
    ++  ** fire the INSTEAD OF triggers).  
    ++  **
    ++  ** If variable 'count' is non-zero, then this OP_Delete instruction should
    ++  ** invoke the update-hook. The pre-update-hook, on the other hand should
    ++  ** be invoked unless table pTab is a system table. The difference is that
    ++  ** the update-hook is not invoked for rows removed by REPLACE, but the 
    ++  ** pre-update-hook is.
    ++  */ 
    +   if( pTab->pSelect==0 ){
    ++    u8 p5 = 0;
    +     sqlite3GenerateRowIndexDelete(pParse, pTab, iDataCur, iIdxCur,0,iIdxNoSeek);
    +     sqlite3VdbeAddOp2(v, OP_Delete, iDataCur, (count?OPFLAG_NCHANGE:0));
    +-    if( count ){
    +-      sqlite3VdbeChangeP4(v, -1, pTab->zName, P4_TRANSIENT);
    ++    if( pParse->nested==0 || 0==sqlite3_stricmp(pTab->zName, "sqlite_stat1") ){
    ++      sqlite3VdbeAppendP4(v, (char*)pTab, P4_TABLE);
    +     }
    +-    if( iIdxNoSeek>=0 ){
    ++    if( eMode!=ONEPASS_OFF ){
    ++      sqlite3VdbeChangeP5(v, OPFLAG_AUXDELETE);
    ++    }
    ++    if( iIdxNoSeek>=0 && iIdxNoSeek!=iDataCur ){
    +       sqlite3VdbeAddOp1(v, OP_Delete, iIdxNoSeek);
    +     }
    +-    sqlite3VdbeChangeP5(v, eMode==ONEPASS_MULTI);
    ++    if( eMode==ONEPASS_MULTI ) p5 |= OPFLAG_SAVEPOSITION;
    ++    sqlite3VdbeChangeP5(v, p5);
    +   }
    + 
    +   /* Do any ON CASCADE, SET NULL or SET DEFAULT operations required to
    +@@ -98539,10 +107457,11 @@ SQLITE_PRIVATE int sqlite3GenerateIndexKey(
    +   if( piPartIdxLabel ){
    +     if( pIdx->pPartIdxWhere ){
    +       *piPartIdxLabel = sqlite3VdbeMakeLabel(v);
    +-      pParse->iSelfTab = iDataCur;
    ++      pParse->iSelfTab = iDataCur + 1;
    +       sqlite3ExprCachePush(pParse);
    +       sqlite3ExprIfFalseDup(pParse, pIdx->pPartIdxWhere, *piPartIdxLabel, 
    +                             SQLITE_JUMPIFNULL);
    ++      pParse->iSelfTab = 0;
    +     }else{
    +       *piPartIdxLabel = 0;
    +     }
    +@@ -98569,6 +107488,10 @@ SQLITE_PRIVATE int sqlite3GenerateIndexKey(
    +   }
    +   if( regOut ){
    +     sqlite3VdbeAddOp3(v, OP_MakeRecord, regBase, nCol, regOut);
    ++    if( pIdx->pTable->pSelect ){
    ++      const char *zAff = sqlite3IndexAffinityStr(pParse->db, pIdx);
    ++      sqlite3VdbeChangeP4(v, -1, zAff, P4_TRANSIENT);
    ++    }
    +   }
    +   sqlite3ReleaseTempRange(pParse, regBase, nCol);
    +   return regBase;
    +@@ -98666,16 +107589,20 @@ static void typeofFunc(
    +   int NotUsed,
    +   sqlite3_value **argv
    + ){
    +-  const char *z = 0;
    ++  static const char *azType[] = { "integer", "real", "text", "blob", "null" };
    ++  int i = sqlite3_value_type(argv[0]) - 1;
    +   UNUSED_PARAMETER(NotUsed);
    +-  switch( sqlite3_value_type(argv[0]) ){
    +-    case SQLITE_INTEGER: z = "integer"; break;
    +-    case SQLITE_TEXT:    z = "text";    break;
    +-    case SQLITE_FLOAT:   z = "real";    break;
    +-    case SQLITE_BLOB:    z = "blob";    break;
    +-    default:             z = "null";    break;
    +-  }
    +-  sqlite3_result_text(context, z, -1, SQLITE_STATIC);
    ++  assert( i>=0 && i<ArraySize(azType) );
    ++  assert( SQLITE_INTEGER==1 );
    ++  assert( SQLITE_FLOAT==2 );
    ++  assert( SQLITE_TEXT==3 );
    ++  assert( SQLITE_BLOB==4 );
    ++  assert( SQLITE_NULL==5 );
    ++  /* EVIDENCE-OF: R-01470-60482 The sqlite3_value_type(V) interface returns
    ++  ** the datatype code for the initial datatype of the sqlite3_value object
    ++  ** V. The returned value is one of SQLITE_INTEGER, SQLITE_FLOAT,
    ++  ** SQLITE_TEXT, SQLITE_BLOB, or SQLITE_NULL. */
    ++  sqlite3_result_text(context, azType[i], -1, SQLITE_STATIC);
    + }
    + 
    + 
    +@@ -98790,23 +107717,26 @@ static void instrFunc(
    +   if( typeHaystack==SQLITE_NULL || typeNeedle==SQLITE_NULL ) return;
    +   nHaystack = sqlite3_value_bytes(argv[0]);
    +   nNeedle = sqlite3_value_bytes(argv[1]);
    +-  if( typeHaystack==SQLITE_BLOB && typeNeedle==SQLITE_BLOB ){
    +-    zHaystack = sqlite3_value_blob(argv[0]);
    +-    zNeedle = sqlite3_value_blob(argv[1]);
    +-    isText = 0;
    +-  }else{
    +-    zHaystack = sqlite3_value_text(argv[0]);
    +-    zNeedle = sqlite3_value_text(argv[1]);
    +-    isText = 1;
    +-  }
    +-  while( nNeedle<=nHaystack && memcmp(zHaystack, zNeedle, nNeedle)!=0 ){
    +-    N++;
    +-    do{
    +-      nHaystack--;
    +-      zHaystack++;
    +-    }while( isText && (zHaystack[0]&0xc0)==0x80 );
    ++  if( nNeedle>0 ){
    ++    if( typeHaystack==SQLITE_BLOB && typeNeedle==SQLITE_BLOB ){
    ++      zHaystack = sqlite3_value_blob(argv[0]);
    ++      zNeedle = sqlite3_value_blob(argv[1]);
    ++      isText = 0;
    ++    }else{
    ++      zHaystack = sqlite3_value_text(argv[0]);
    ++      zNeedle = sqlite3_value_text(argv[1]);
    ++      isText = 1;
    ++    }
    ++    if( zNeedle==0 || (nHaystack && zHaystack==0) ) return;
    ++    while( nNeedle<=nHaystack && memcmp(zHaystack, zNeedle, nNeedle)!=0 ){
    ++      N++;
    ++      do{
    ++        nHaystack--;
    ++        zHaystack++;
    ++      }while( isText && (zHaystack[0]&0xc0)==0x80 );
    ++    }
    ++    if( nNeedle>nHaystack ) N = 0;
    +   }
    +-  if( nNeedle>nHaystack ) N = 0;
    +   sqlite3_result_int(context, N);
    + }
    + 
    +@@ -98829,7 +107759,8 @@ static void printfFunc(
    +     x.nUsed = 0;
    +     x.apArg = argv+1;
    +     sqlite3StrAccumInit(&str, db, 0, 0, db->aLimit[SQLITE_LIMIT_LENGTH]);
    +-    sqlite3XPrintf(&str, SQLITE_PRINTF_SQLFUNC, zFormat, &x);
    ++    str.printfFlags = SQLITE_PRINTF_SQLFUNC;
    ++    sqlite3XPrintf(&str, zFormat, &x);
    +     n = str.nChar;
    +     sqlite3_result_text(context, sqlite3StrAccumFinish(&str), n,
    +                         SQLITE_DYNAMIC);
    +@@ -99157,10 +108088,10 @@ static void total_changes(
    + ** A structure defining how to do GLOB-style comparisons.
    + */
    + struct compareInfo {
    +-  u8 matchAll;
    +-  u8 matchOne;
    +-  u8 matchSet;
    +-  u8 noCase;
    ++  u8 matchAll;          /* "*" or "%" */
    ++  u8 matchOne;          /* "?" or "_" */
    ++  u8 matchSet;          /* "[" or 0 */
    ++  u8 noCase;            /* true to ignore case differences */
    + };
    + 
    + /*
    +@@ -99185,9 +108116,19 @@ static const struct compareInfo likeInfoNorm = { '%', '_',   0, 1 };
    + static const struct compareInfo likeInfoAlt = { '%', '_',   0, 0 };
    + 
    + /*
    +-** Compare two UTF-8 strings for equality where the first string can
    +-** potentially be a "glob" or "like" expression.  Return true (1) if they
    +-** are the same and false (0) if they are different.
    ++** Possible error returns from patternMatch()
    ++*/
    ++#define SQLITE_MATCH             0
    ++#define SQLITE_NOMATCH           1
    ++#define SQLITE_NOWILDCARDMATCH   2
    ++
    ++/*
    ++** Compare two UTF-8 strings for equality where the first string is
    ++** a GLOB or LIKE expression.  Return values:
    ++**
    ++**    SQLITE_MATCH:            Match
    ++**    SQLITE_NOMATCH:          No match
    ++**    SQLITE_NOWILDCARDMATCH:  No match in spite of having * or % wildcards.
    + **
    + ** Globbing rules:
    + **
    +@@ -99223,22 +108164,14 @@ static int patternCompare(
    +   const u8 *zPattern,              /* The glob pattern */
    +   const u8 *zString,               /* The string to compare against the glob */
    +   const struct compareInfo *pInfo, /* Information about how to do the compare */
    +-  u32 esc                          /* The escape character */
    ++  u32 matchOther                   /* The escape char (LIKE) or '[' (GLOB) */
    + ){
    +   u32 c, c2;                       /* Next pattern and input string chars */
    +   u32 matchOne = pInfo->matchOne;  /* "?" or "_" */
    +   u32 matchAll = pInfo->matchAll;  /* "*" or "%" */
    +-  u32 matchOther;                  /* "[" or the escape character */
    +   u8 noCase = pInfo->noCase;       /* True if uppercase==lowercase */
    +   const u8 *zEscaped = 0;          /* One past the last escaped input char */
    +   
    +-  /* The GLOB operator does not have an ESCAPE clause.  And LIKE does not
    +-  ** have the matchSet operator.  So we either have to look for one or
    +-  ** the other, never both.  Hence the single variable matchOther is used
    +-  ** to store the one we have to look for.
    +-  */
    +-  matchOther = esc ? esc : pInfo->matchSet;
    +-
    +   while( (c = Utf8Read(zPattern))!=0 ){
    +     if( c==matchAll ){  /* Match "*" */
    +       /* Skip over multiple "*" characters in the pattern.  If there
    +@@ -99246,30 +108179,31 @@ static int patternCompare(
    +       ** single character of the input string for each "?" skipped */
    +       while( (c=Utf8Read(zPattern)) == matchAll || c == matchOne ){
    +         if( c==matchOne && sqlite3Utf8Read(&zString)==0 ){
    +-          return 0;
    ++          return SQLITE_NOWILDCARDMATCH;
    +         }
    +       }
    +       if( c==0 ){
    +-        return 1;   /* "*" at the end of the pattern matches */
    ++        return SQLITE_MATCH;   /* "*" at the end of the pattern matches */
    +       }else if( c==matchOther ){
    +-        if( esc ){
    ++        if( pInfo->matchSet==0 ){
    +           c = sqlite3Utf8Read(&zPattern);
    +-          if( c==0 ) return 0;
    ++          if( c==0 ) return SQLITE_NOWILDCARDMATCH;
    +         }else{
    +           /* "[...]" immediately follows the "*".  We have to do a slow
    +           ** recursive search in this case, but it is an unusual case. */
    +           assert( matchOther<0x80 );  /* '[' is a single-byte character */
    +-          while( *zString
    +-                 && patternCompare(&zPattern[-1],zString,pInfo,esc)==0 ){
    ++          while( *zString ){
    ++            int bMatch = patternCompare(&zPattern[-1],zString,pInfo,matchOther);
    ++            if( bMatch!=SQLITE_NOMATCH ) return bMatch;
    +             SQLITE_SKIP_UTF8(zString);
    +           }
    +-          return *zString!=0;
    ++          return SQLITE_NOWILDCARDMATCH;
    +         }
    +       }
    + 
    +       /* At this point variable c contains the first character of the
    +       ** pattern string past the "*".  Search in the input string for the
    +-      ** first matching character and recursively contine the match from
    ++      ** first matching character and recursively continue the match from
    +       ** that point.
    +       **
    +       ** For a case-insensitive search, set variable cx to be the same as
    +@@ -99277,36 +108211,44 @@ static int patternCompare(
    +       ** c or cx.
    +       */
    +       if( c<=0x80 ){
    +-        u32 cx;
    ++        char zStop[3];
    ++        int bMatch;
    +         if( noCase ){
    +-          cx = sqlite3Toupper(c);
    +-          c = sqlite3Tolower(c);
    ++          zStop[0] = sqlite3Toupper(c);
    ++          zStop[1] = sqlite3Tolower(c);
    ++          zStop[2] = 0;
    +         }else{
    +-          cx = c;
    ++          zStop[0] = c;
    ++          zStop[1] = 0;
    +         }
    +-        while( (c2 = *(zString++))!=0 ){
    +-          if( c2!=c && c2!=cx ) continue;
    +-          if( patternCompare(zPattern,zString,pInfo,esc) ) return 1;
    ++        while(1){
    ++          zString += strcspn((const char*)zString, zStop);
    ++          if( zString[0]==0 ) break;
    ++          zString++;
    ++          bMatch = patternCompare(zPattern,zString,pInfo,matchOther);
    ++          if( bMatch!=SQLITE_NOMATCH ) return bMatch;
    +         }
    +       }else{
    ++        int bMatch;
    +         while( (c2 = Utf8Read(zString))!=0 ){
    +           if( c2!=c ) continue;
    +-          if( patternCompare(zPattern,zString,pInfo,esc) ) return 1;
    ++          bMatch = patternCompare(zPattern,zString,pInfo,matchOther);
    ++          if( bMatch!=SQLITE_NOMATCH ) return bMatch;
    +         }
    +       }
    +-      return 0;
    ++      return SQLITE_NOWILDCARDMATCH;
    +     }
    +     if( c==matchOther ){
    +-      if( esc ){
    ++      if( pInfo->matchSet==0 ){
    +         c = sqlite3Utf8Read(&zPattern);
    +-        if( c==0 ) return 0;
    ++        if( c==0 ) return SQLITE_NOMATCH;
    +         zEscaped = zPattern;
    +       }else{
    +         u32 prior_c = 0;
    +         int seen = 0;
    +         int invert = 0;
    +         c = sqlite3Utf8Read(&zString);
    +-        if( c==0 ) return 0;
    ++        if( c==0 ) return SQLITE_NOMATCH;
    +         c2 = sqlite3Utf8Read(&zPattern);
    +         if( c2=='^' ){
    +           invert = 1;
    +@@ -99330,27 +108272,36 @@ static int patternCompare(
    +           c2 = sqlite3Utf8Read(&zPattern);
    +         }
    +         if( c2==0 || (seen ^ invert)==0 ){
    +-          return 0;
    ++          return SQLITE_NOMATCH;
    +         }
    +         continue;
    +       }
    +     }
    +     c2 = Utf8Read(zString);
    +     if( c==c2 ) continue;
    +-    if( noCase && c<0x80 && c2<0x80 && sqlite3Tolower(c)==sqlite3Tolower(c2) ){
    ++    if( noCase  && sqlite3Tolower(c)==sqlite3Tolower(c2) && c<0x80 && c2<0x80 ){
    +       continue;
    +     }
    +     if( c==matchOne && zPattern!=zEscaped && c2!=0 ) continue;
    +-    return 0;
    ++    return SQLITE_NOMATCH;
    +   }
    +-  return *zString==0;
    ++  return *zString==0 ? SQLITE_MATCH : SQLITE_NOMATCH;
    ++}
    ++
    ++/*
    ++** The sqlite3_strglob() interface.  Return 0 on a match (like strcmp()) and
    ++** non-zero if there is no match.
    ++*/
    ++SQLITE_API int sqlite3_strglob(const char *zGlobPattern, const char *zString){
    ++  return patternCompare((u8*)zGlobPattern, (u8*)zString, &globInfo, '[');
    + }
    + 
    + /*
    +-** The sqlite3_strglob() interface.
    ++** The sqlite3_strlike() interface.  Return 0 on a match and non-zero for
    ++** a miss - like strcmp().
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_strglob(const char *zGlobPattern, const char *zString){
    +-  return patternCompare((u8*)zGlobPattern, (u8*)zString, &globInfo, 0)==0;
    ++SQLITE_API int sqlite3_strlike(const char *zPattern, const char *zStr, unsigned int esc){
    ++  return patternCompare((u8*)zPattern, (u8*)zStr, &likeInfoNorm, esc);
    + }
    + 
    + /*
    +@@ -99381,10 +108332,22 @@ static void likeFunc(
    +   sqlite3_value **argv
    + ){
    +   const unsigned char *zA, *zB;
    +-  u32 escape = 0;
    ++  u32 escape;
    +   int nPat;
    +   sqlite3 *db = sqlite3_context_db_handle(context);
    ++  struct compareInfo *pInfo = sqlite3_user_data(context);
    + 
    ++#ifdef SQLITE_LIKE_DOESNT_MATCH_BLOBS
    ++  if( sqlite3_value_type(argv[0])==SQLITE_BLOB
    ++   || sqlite3_value_type(argv[1])==SQLITE_BLOB
    ++  ){
    ++#ifdef SQLITE_TEST
    ++    sqlite3_like_count++;
    ++#endif
    ++    sqlite3_result_int(context, 0);
    ++    return;
    ++  }
    ++#endif
    +   zB = sqlite3_value_text(argv[0]);
    +   zA = sqlite3_value_text(argv[1]);
    + 
    +@@ -99412,14 +108375,15 @@ static void likeFunc(
    +       return;
    +     }
    +     escape = sqlite3Utf8Read(&zEsc);
    ++  }else{
    ++    escape = pInfo->matchSet;
    +   }
    +   if( zA && zB ){
    +-    struct compareInfo *pInfo = sqlite3_user_data(context);
    + #ifdef SQLITE_TEST
    +     sqlite3_like_count++;
    + #endif
    +-    
    +-    sqlite3_result_int(context, patternCompare(zB, zA, pInfo, escape));
    ++    sqlite3_result_int(context,
    ++                      patternCompare(zB, zA, pInfo, escape)==SQLITE_MATCH);
    +   }
    + }
    + 
    +@@ -99894,6 +108858,26 @@ static void trimFunc(
    + }
    + 
    + 
    ++#ifdef SQLITE_ENABLE_UNKNOWN_SQL_FUNCTION
    ++/*
    ++** The "unknown" function is automatically substituted in place of
    ++** any unrecognized function name when doing an EXPLAIN or EXPLAIN QUERY PLAN
    ++** when the SQLITE_ENABLE_UNKNOWN_FUNCTION compile-time option is used.
    ++** When the "sqlite3" command-line shell is built using this functionality,
    ++** that allows an EXPLAIN or EXPLAIN QUERY PLAN for complex queries
    ++** involving application-defined functions to be examined in a generic
    ++** sqlite3 shell.
    ++*/
    ++static void unknownFunc(
    ++  sqlite3_context *context,
    ++  int argc,
    ++  sqlite3_value **argv
    ++){
    ++  /* no-op */
    ++}
    ++#endif /*SQLITE_ENABLE_UNKNOWN_SQL_FUNCTION*/
    ++
    ++
    + /* IMP: R-25361-16150 This function is omitted from SQLite by default. It
    + ** is only available if the SQLITE_SOUNDEX compile-time option is used
    + ** when SQLite is built.
    +@@ -99964,6 +108948,14 @@ static void loadExt(sqlite3_context *context, int argc, sqlite3_value **argv){
    +   sqlite3 *db = sqlite3_context_db_handle(context);
    +   char *zErrMsg = 0;
    + 
    ++  /* Disallow the load_extension() SQL function unless the SQLITE_LoadExtFunc
    ++  ** flag is set.  See the sqlite3_enable_load_extension() API.
    ++  */
    ++  if( (db->flags & SQLITE_LoadExtFunc)==0 ){
    ++    sqlite3_result_error(context, "not authorized", -1);
    ++    return;
    ++  }
    ++
    +   if( argc==2 ){
    +     zProc = (const char *)sqlite3_value_text(argv[1]);
    +   }else{
    +@@ -100162,7 +109154,7 @@ static void groupConcatStep(
    +         zSep = ",";
    +         nSep = 1;
    +       }
    +-      if( nSep ) sqlite3StrAccumAppend(pAccum, zSep, nSep);
    ++      if( zSep ) sqlite3StrAccumAppend(pAccum, zSep, nSep);
    +     }
    +     zVal = (char*)sqlite3_value_text(argv[0]);
    +     nVal = sqlite3_value_bytes(argv[0]);
    +@@ -100189,11 +109181,11 @@ static void groupConcatFinalize(sqlite3_context *context){
    + ** of the built-in functions above are part of the global function set.
    + ** This routine only deals with those that are not global.
    + */
    +-SQLITE_PRIVATE void sqlite3RegisterBuiltinFunctions(sqlite3 *db){
    ++SQLITE_PRIVATE void sqlite3RegisterPerConnectionBuiltinFunctions(sqlite3 *db){
    +   int rc = sqlite3_overload_function(db, "MATCH", 2);
    +   assert( rc==SQLITE_NOMEM || rc==SQLITE_OK );
    +   if( rc==SQLITE_NOMEM ){
    +-    db->mallocFailed = 1;
    ++    sqlite3OomFault(db);
    +   }
    + }
    + 
    +@@ -100202,8 +109194,7 @@ SQLITE_PRIVATE void sqlite3RegisterBuiltinFunctions(sqlite3 *db){
    + */
    + static void setLikeOptFlag(sqlite3 *db, const char *zName, u8 flagVal){
    +   FuncDef *pDef;
    +-  pDef = sqlite3FindFunction(db, zName, sqlite3Strlen30(zName),
    +-                             2, SQLITE_UTF8, 0);
    ++  pDef = sqlite3FindFunction(db, zName, 2, SQLITE_UTF8, 0);
    +   if( ALWAYS(pDef) ){
    +     pDef->funcFlags |= flagVal;
    +   }
    +@@ -100233,9 +109224,14 @@ SQLITE_PRIVATE void sqlite3RegisterLikeFunctions(sqlite3 *db, int caseSensitive)
    + /*
    + ** pExpr points to an expression which implements a function.  If
    + ** it is appropriate to apply the LIKE optimization to that function
    +-** then set aWc[0] through aWc[2] to the wildcard characters and
    +-** return TRUE.  If the function is not a LIKE-style function then
    +-** return FALSE.
    ++** then set aWc[0] through aWc[2] to the wildcard characters and the
    ++** escape character and then return TRUE.  If the function is not a 
    ++** LIKE-style function then return FALSE.
    ++**
    ++** The expression "a LIKE b ESCAPE c" is only considered a valid LIKE
    ++** operator if c is a string literal that is exactly one byte in length.
    ++** That one byte is stored in aWc[3].  aWc[3] is set to zero if there is
    ++** no ESCAPE clause.
    + **
    + ** *pIsNocase is set to true if uppercase and lowercase are equivalent for
    + ** the function (default for LIKE).  If the function makes the distinction
    +@@ -100244,19 +109240,26 @@ SQLITE_PRIVATE void sqlite3RegisterLikeFunctions(sqlite3 *db, int caseSensitive)
    + */
    + SQLITE_PRIVATE int sqlite3IsLikeFunction(sqlite3 *db, Expr *pExpr, int *pIsNocase, char *aWc){
    +   FuncDef *pDef;
    +-  if( pExpr->op!=TK_FUNCTION 
    +-   || !pExpr->x.pList 
    +-   || pExpr->x.pList->nExpr!=2
    +-  ){
    ++  int nExpr;
    ++  if( pExpr->op!=TK_FUNCTION || !pExpr->x.pList ){
    +     return 0;
    +   }
    +   assert( !ExprHasProperty(pExpr, EP_xIsSelect) );
    +-  pDef = sqlite3FindFunction(db, pExpr->u.zToken, 
    +-                             sqlite3Strlen30(pExpr->u.zToken),
    +-                             2, SQLITE_UTF8, 0);
    ++  nExpr = pExpr->x.pList->nExpr;
    ++  pDef = sqlite3FindFunction(db, pExpr->u.zToken, nExpr, SQLITE_UTF8, 0);
    +   if( NEVER(pDef==0) || (pDef->funcFlags & SQLITE_FUNC_LIKE)==0 ){
    +     return 0;
    +   }
    ++  if( nExpr<3 ){
    ++    aWc[3] = 0;
    ++  }else{
    ++    Expr *pEscape = pExpr->x.pList->a[2].pExpr;
    ++    char *zEscape;
    ++    if( pEscape->op!=TK_STRING ) return 0;
    ++    zEscape = pEscape->u.zToken;
    ++    if( zEscape[0]==0 || zEscape[1]!=0 ) return 0;
    ++    aWc[3] = zEscape[0];
    ++  }
    + 
    +   /* The memcpy() statement assumes that the wildcard characters are
    +   ** the first three statements in the compareInfo structure.  The
    +@@ -100277,7 +109280,7 @@ SQLITE_PRIVATE int sqlite3IsLikeFunction(sqlite3 *db, Expr *pExpr, int *pIsNocas
    + **
    + ** After this routine runs
    + */
    +-SQLITE_PRIVATE void sqlite3RegisterGlobalFunctions(void){
    ++SQLITE_PRIVATE void sqlite3RegisterBuiltinFunctions(void){
    +   /*
    +   ** The following array holds FuncDef structures for all of the functions
    +   ** defined in this file.
    +@@ -100285,8 +109288,34 @@ SQLITE_PRIVATE void sqlite3RegisterGlobalFunctions(void){
    +   ** The array cannot be constant since changes are made to the
    +   ** FuncDef.pHash elements at start-time.  The elements of this array
    +   ** are read-only after initialization is complete.
    ++  **
    ++  ** For peak efficiency, put the most frequently used function last.
    +   */
    +-  static SQLITE_WSD FuncDef aBuiltinFunc[] = {
    ++  static FuncDef aBuiltinFunc[] = {
    ++#ifdef SQLITE_SOUNDEX
    ++    FUNCTION(soundex,            1, 0, 0, soundexFunc      ),
    ++#endif
    ++#ifndef SQLITE_OMIT_LOAD_EXTENSION
    ++    VFUNCTION(load_extension,    1, 0, 0, loadExt          ),
    ++    VFUNCTION(load_extension,    2, 0, 0, loadExt          ),
    ++#endif
    ++#if SQLITE_USER_AUTHENTICATION
    ++    FUNCTION(sqlite_crypt,       2, 0, 0, sqlite3CryptFunc ),
    ++#endif
    ++#ifndef SQLITE_OMIT_COMPILEOPTION_DIAGS
    ++    DFUNCTION(sqlite_compileoption_used,1, 0, 0, compileoptionusedFunc  ),
    ++    DFUNCTION(sqlite_compileoption_get, 1, 0, 0, compileoptiongetFunc  ),
    ++#endif /* SQLITE_OMIT_COMPILEOPTION_DIAGS */
    ++    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),
    ++#ifdef SQLITE_DEBUG
    ++    FUNCTION2(affinity,          1, 0, 0, noopFunc,  SQLITE_FUNC_AFFINITY),
    ++#endif
    ++#ifdef SQLITE_ENABLE_OFFSET_SQL_FUNC
    ++    FUNCTION2(sqlite_offset,     1, 0, 0, noopFunc,  SQLITE_FUNC_OFFSET|
    ++                                                     SQLITE_FUNC_TYPEOF),
    ++#endif
    +     FUNCTION(ltrim,              1, 1, 0, trimFunc         ),
    +     FUNCTION(ltrim,              2, 1, 0, trimFunc         ),
    +     FUNCTION(rtrim,              1, 2, 0, trimFunc         ),
    +@@ -100304,8 +109333,6 @@ SQLITE_PRIVATE void sqlite3RegisterGlobalFunctions(void){
    +     FUNCTION2(typeof,            1, 0, 0, typeofFunc,  SQLITE_FUNC_TYPEOF),
    +     FUNCTION2(length,            1, 0, 0, lengthFunc,  SQLITE_FUNC_LENGTH),
    +     FUNCTION(instr,              2, 0, 0, instrFunc        ),
    +-    FUNCTION(substr,             2, 0, 0, substrFunc       ),
    +-    FUNCTION(substr,             3, 0, 0, substrFunc       ),
    +     FUNCTION(printf,            -1, 0, 0, printfFunc       ),
    +     FUNCTION(unicode,            1, 0, 0, unicodeFunc      ),
    +     FUNCTION(char,              -1, 0, 0, charFunc         ),
    +@@ -100316,40 +109343,22 @@ SQLITE_PRIVATE void sqlite3RegisterGlobalFunctions(void){
    + #endif
    +     FUNCTION(upper,              1, 0, 0, upperFunc        ),
    +     FUNCTION(lower,              1, 0, 0, lowerFunc        ),
    +-    FUNCTION(coalesce,           1, 0, 0, 0                ),
    +-    FUNCTION(coalesce,           0, 0, 0, 0                ),
    +-    FUNCTION2(coalesce,         -1, 0, 0, noopFunc,  SQLITE_FUNC_COALESCE),
    +     FUNCTION(hex,                1, 0, 0, hexFunc          ),
    +     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       ),
    +     DFUNCTION(sqlite_version,    0, 0, 0, versionFunc      ),
    +     DFUNCTION(sqlite_source_id,  0, 0, 0, sourceidFunc     ),
    +     FUNCTION(sqlite_log,         2, 0, 0, errlogFunc       ),
    +-#if SQLITE_USER_AUTHENTICATION
    +-    FUNCTION(sqlite_crypt,       2, 0, 0, sqlite3CryptFunc ),
    +-#endif
    +-#ifndef SQLITE_OMIT_COMPILEOPTION_DIAGS
    +-    DFUNCTION(sqlite_compileoption_used,1, 0, 0, compileoptionusedFunc  ),
    +-    DFUNCTION(sqlite_compileoption_get, 1, 0, 0, compileoptiongetFunc  ),
    +-#endif /* SQLITE_OMIT_COMPILEOPTION_DIAGS */
    +     FUNCTION(quote,              1, 0, 0, quoteFunc        ),
    +     VFUNCTION(last_insert_rowid, 0, 0, 0, last_insert_rowid),
    +     VFUNCTION(changes,           0, 0, 0, changes          ),
    +     VFUNCTION(total_changes,     0, 0, 0, total_changes    ),
    +     FUNCTION(replace,            3, 0, 0, replaceFunc      ),
    +     FUNCTION(zeroblob,           1, 0, 0, zeroblobFunc     ),
    +-  #ifdef SQLITE_SOUNDEX
    +-    FUNCTION(soundex,            1, 0, 0, soundexFunc      ),
    +-  #endif
    +-  #ifndef SQLITE_OMIT_LOAD_EXTENSION
    +-    VFUNCTION(load_extension,    1, 0, 0, loadExt          ),
    +-    VFUNCTION(load_extension,    2, 0, 0, loadExt          ),
    +-  #endif
    ++    FUNCTION(substr,             2, 0, 0, substrFunc       ),
    ++    FUNCTION(substr,             3, 0, 0, substrFunc       ),
    +     AGGREGATE(sum,               1, 0, 0, sumStep,         sumFinalize    ),
    +     AGGREGATE(total,             1, 0, 0, sumStep,         totalFinalize    ),
    +     AGGREGATE(avg,               1, 0, 0, sumStep,         avgFinalize    ),
    +@@ -100360,28 +109369,43 @@ SQLITE_PRIVATE void sqlite3RegisterGlobalFunctions(void){
    +     AGGREGATE(group_concat,      2, 0, 0, groupConcatStep, groupConcatFinalize),
    +   
    +     LIKEFUNC(glob, 2, &globInfo, SQLITE_FUNC_LIKE|SQLITE_FUNC_CASE),
    +-  #ifdef SQLITE_CASE_SENSITIVE_LIKE
    ++#ifdef SQLITE_CASE_SENSITIVE_LIKE
    +     LIKEFUNC(like, 2, &likeInfoAlt, SQLITE_FUNC_LIKE|SQLITE_FUNC_CASE),
    +     LIKEFUNC(like, 3, &likeInfoAlt, SQLITE_FUNC_LIKE|SQLITE_FUNC_CASE),
    +-  #else
    ++#else
    +     LIKEFUNC(like, 2, &likeInfoNorm, SQLITE_FUNC_LIKE),
    +     LIKEFUNC(like, 3, &likeInfoNorm, SQLITE_FUNC_LIKE),
    +-  #endif
    ++#endif
    ++#ifdef SQLITE_ENABLE_UNKNOWN_SQL_FUNCTION
    ++    FUNCTION(unknown,           -1, 0, 0, unknownFunc      ),
    ++#endif
    ++    FUNCTION(coalesce,           1, 0, 0, 0                ),
    ++    FUNCTION(coalesce,           0, 0, 0, 0                ),
    ++    FUNCTION2(coalesce,         -1, 0, 0, noopFunc,  SQLITE_FUNC_COALESCE),
    +   };
    +-
    +-  int i;
    +-  FuncDefHash *pHash = &GLOBAL(FuncDefHash, sqlite3GlobalFunctions);
    +-  FuncDef *aFunc = (FuncDef*)&GLOBAL(FuncDef, aBuiltinFunc);
    +-
    +-  for(i=0; i<ArraySize(aBuiltinFunc); i++){
    +-    sqlite3FuncDefInsert(pHash, &aFunc[i]);
    +-  }
    +-  sqlite3RegisterDateTimeFunctions();
    + #ifndef SQLITE_OMIT_ALTERTABLE
    +   sqlite3AlterFunctions();
    + #endif
    + #if defined(SQLITE_ENABLE_STAT3) || defined(SQLITE_ENABLE_STAT4)
    +   sqlite3AnalyzeFunctions();
    ++#endif
    ++  sqlite3RegisterDateTimeFunctions();
    ++  sqlite3InsertBuiltinFuncs(aBuiltinFunc, ArraySize(aBuiltinFunc));
    ++
    ++#if 0  /* Enable to print out how the built-in functions are hashed */
    ++  {
    ++    int i;
    ++    FuncDef *p;
    ++    for(i=0; i<SQLITE_FUNC_HASH_SZ; i++){
    ++      printf("FUNC-HASH %02d:", i);
    ++      for(p=sqlite3BuiltinFunctions.a[i]; p; p=p->u.pHash){
    ++        int n = sqlite3Strlen30(p->zName);
    ++        int h = p->zName[0] + n;
    ++        printf(" %s(%d)", p->zName, h);
    ++      }
    ++      printf("\n");
    ++    }
    ++  }
    + #endif
    + }
    + 
    +@@ -100608,13 +109632,13 @@ SQLITE_PRIVATE int sqlite3FkLocateIndex(
    +     }
    +   }else if( paiCol ){
    +     assert( nCol>1 );
    +-    aiCol = (int *)sqlite3DbMallocRaw(pParse->db, nCol*sizeof(int));
    ++    aiCol = (int *)sqlite3DbMallocRawNN(pParse->db, nCol*sizeof(int));
    +     if( !aiCol ) return 1;
    +     *paiCol = aiCol;
    +   }
    + 
    +   for(pIdx=pParent->pIndex; pIdx; pIdx=pIdx->pNext){
    +-    if( pIdx->nKeyCol==nCol && IsUniqueIndex(pIdx) ){ 
    ++    if( pIdx->nKeyCol==nCol && IsUniqueIndex(pIdx) && pIdx->pPartIdxWhere==0 ){ 
    +       /* 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.  */
    +@@ -100638,7 +109662,7 @@ SQLITE_PRIVATE int sqlite3FkLocateIndex(
    +         int i, j;
    +         for(i=0; i<nCol; i++){
    +           i16 iCol = pIdx->aiColumn[i];     /* Index of column in parent tbl */
    +-          char *zDfltColl;                  /* Def. collation for column */
    ++          const char *zDfltColl;            /* Def. collation for column */
    +           char *zIdxCol;                    /* Name of indexed column */
    + 
    +           if( iCol<0 ) break; /* No foreign keys against expression indexes */
    +@@ -100647,9 +109671,7 @@ SQLITE_PRIVATE int sqlite3FkLocateIndex(
    +           ** the default collation sequence for the column, this index is
    +           ** unusable. Bail out early in this case.  */
    +           zDfltColl = pParent->aCol[iCol].zColl;
    +-          if( !zDfltColl ){
    +-            zDfltColl = "BINARY";
    +-          }
    ++          if( !zDfltColl ) zDfltColl = sqlite3StrBINARY;
    +           if( sqlite3StrICmp(pIdx->azColl[i], zDfltColl) ) break;
    + 
    +           zIdxCol = pParent->aCol[iCol].zName;
    +@@ -100975,7 +109997,7 @@ static void fkScanChildren(
    +     assert( iCol>=0 );
    +     zCol = pFKey->pFrom->aCol[iCol].zName;
    +     pRight = sqlite3Expr(db, TK_ID, zCol);
    +-    pEq = sqlite3PExpr(pParse, TK_EQ, pLeft, pRight, 0);
    ++    pEq = sqlite3PExpr(pParse, TK_EQ, pLeft, pRight);
    +     pWhere = sqlite3ExprAnd(db, pWhere, pEq);
    +   }
    + 
    +@@ -100997,7 +110019,7 @@ static void fkScanChildren(
    +     if( HasRowid(pTab) ){
    +       pLeft = exprTableRegister(pParse, pTab, regData, -1);
    +       pRight = exprTableColumn(db, pTab, pSrc->a[0].iCursor, -1);
    +-      pNe = sqlite3PExpr(pParse, TK_NE, pLeft, pRight, 0);
    ++      pNe = sqlite3PExpr(pParse, TK_NE, pLeft, pRight);
    +     }else{
    +       Expr *pEq, *pAll = 0;
    +       Index *pPk = sqlite3PrimaryKeyIndex(pTab);
    +@@ -101007,10 +110029,10 @@ static void fkScanChildren(
    +         assert( iCol>=0 );
    +         pLeft = exprTableRegister(pParse, pTab, regData, iCol);
    +         pRight = exprTableColumn(db, pTab, pSrc->a[0].iCursor, iCol);
    +-        pEq = sqlite3PExpr(pParse, TK_EQ, pLeft, pRight, 0);
    ++        pEq = sqlite3PExpr(pParse, TK_EQ, pLeft, pRight);
    +         pAll = sqlite3ExprAnd(db, pAll, pEq);
    +       }
    +-      pNe = sqlite3PExpr(pParse, TK_NOT, pAll, 0, 0);
    ++      pNe = sqlite3PExpr(pParse, TK_NOT, pAll, 0);
    +     }
    +     pWhere = sqlite3ExprAnd(db, pWhere, pNe);
    +   }
    +@@ -101024,10 +110046,12 @@ static void fkScanChildren(
    +   /* Create VDBE to loop through the entries in pSrc that match the WHERE
    +   ** clause. For each row found, increment either the deferred or immediate
    +   ** foreign key constraint counter. */
    +-  pWInfo = sqlite3WhereBegin(pParse, pSrc, pWhere, 0, 0, 0, 0);
    +-  sqlite3VdbeAddOp2(v, OP_FkCounter, pFKey->isDeferred, nIncr);
    +-  if( pWInfo ){
    +-    sqlite3WhereEnd(pWInfo);
    ++  if( pParse->nErr==0 ){
    ++    pWInfo = sqlite3WhereBegin(pParse, pSrc, pWhere, 0, 0, 0, 0);
    ++    sqlite3VdbeAddOp2(v, OP_FkCounter, pFKey->isDeferred, nIncr);
    ++    if( pWInfo ){
    ++      sqlite3WhereEnd(pWInfo);
    ++    }
    +   }
    + 
    +   /* Clean up the WHERE clause constructed above. */
    +@@ -101114,7 +110138,7 @@ SQLITE_PRIVATE void sqlite3FkDropTable(Parse *pParse, SrcList *pName, Table *pTa
    +     }
    + 
    +     pParse->disableTriggers = 1;
    +-    sqlite3DeleteFrom(pParse, sqlite3SrcListDup(db, pName, 0), 0);
    ++    sqlite3DeleteFrom(pParse, sqlite3SrcListDup(db, pName, 0), 0, 0, 0);
    +     pParse->disableTriggers = 0;
    + 
    +     /* If the DELETE has generated immediate foreign key constraint 
    +@@ -101262,7 +110286,7 @@ SQLITE_PRIVATE void sqlite3FkCheck(
    +   if( (db->flags&SQLITE_ForeignKeys)==0 ) return;
    + 
    +   iDb = sqlite3SchemaToIndex(db, pTab->pSchema);
    +-  zDb = db->aDb[iDb].zName;
    ++  zDb = db->aDb[iDb].zDbSName;
    + 
    +   /* Loop through all the foreign key constraints for which pTab is the
    +   ** child table (the table that the foreign key definition is part of).  */
    +@@ -101398,7 +110422,7 @@ SQLITE_PRIVATE void sqlite3FkCheck(
    +       struct SrcList_item *pItem = pSrc->a;
    +       pItem->pTab = pFKey->pFrom;
    +       pItem->zName = pFKey->pFrom->zName;
    +-      pItem->pTab->nRef++;
    ++      pItem->pTab->nTabRef++;
    +       pItem->iCursor = pParse->nTab++;
    +   
    +       if( regNew!=0 ){
    +@@ -101478,8 +110502,16 @@ SQLITE_PRIVATE u32 sqlite3FkOldmask(
    + ** UPDATE statement modifies the rowid fields of the table.
    + **
    + ** If any foreign key processing will be required, this function returns
    +-** true. If there is no foreign key related processing, this function 
    +-** returns false.
    ++** non-zero. If there is no foreign key related processing, this function 
    ++** returns zero.
    ++**
    ++** For an UPDATE, this function returns 2 if:
    ++**
    ++**   * There are any FKs for which pTab is the child and the parent table, or
    ++**   * the UPDATE modifies one or more parent keys for which the action is
    ++**     not "NO ACTION" (i.e. is CASCADE, SET DEFAULT or SET NULL).
    ++**
    ++** Or, assuming some other foreign key processing is required, 1.
    + */
    + SQLITE_PRIVATE int sqlite3FkRequired(
    +   Parse *pParse,                  /* Parse context */
    +@@ -101487,12 +110519,13 @@ SQLITE_PRIVATE int sqlite3FkRequired(
    +   int *aChange,                   /* Non-NULL for UPDATE operations */
    +   int chngRowid                   /* True for UPDATE that affects rowid */
    + ){
    ++  int eRet = 0;
    +   if( pParse->db->flags&SQLITE_ForeignKeys ){
    +     if( !aChange ){
    +       /* A DELETE operation. Foreign key processing is required if the 
    +       ** table in question is either the child or parent table for any 
    +       ** foreign key constraint.  */
    +-      return (sqlite3FkReferences(pTab) || pTab->pFKey);
    ++      eRet = (sqlite3FkReferences(pTab) || pTab->pFKey);
    +     }else{
    +       /* This is an UPDATE. Foreign key processing is only required if the
    +       ** operation modifies one or more child or parent key columns. */
    +@@ -101500,16 +110533,22 @@ SQLITE_PRIVATE int sqlite3FkRequired(
    + 
    +       /* Check if any child key columns are being modified. */
    +       for(p=pTab->pFKey; p; p=p->pNextFrom){
    +-        if( fkChildIsModified(pTab, p, aChange, chngRowid) ) return 1;
    ++        if( 0==sqlite3_stricmp(pTab->zName, p->zTo) ) return 2;
    ++        if( fkChildIsModified(pTab, p, aChange, chngRowid) ){
    ++          eRet = 1;
    ++        }
    +       }
    + 
    +       /* Check if any parent key columns are being modified. */
    +       for(p=sqlite3FkReferences(pTab); p; p=p->pNextTo){
    +-        if( fkParentIsModified(pTab, p, aChange, chngRowid) ) return 1;
    ++        if( fkParentIsModified(pTab, p, aChange, chngRowid) ){
    ++          if( p->aAction[1]!=OE_None ) return 2;
    ++          eRet = 1;
    ++        }
    +       }
    +     }
    +   }
    +-  return 0;
    ++  return eRet;
    + }
    + 
    + /*
    +@@ -101553,10 +110592,12 @@ static Trigger *fkActionTrigger(
    +   int iAction = (pChanges!=0);    /* 1 for UPDATE, 0 for DELETE */
    + 
    +   action = pFKey->aAction[iAction];
    ++  if( action==OE_Restrict && (db->flags & SQLITE_DeferFKs) ){
    ++    return 0;
    ++  }
    +   pTrigger = pFKey->apTrigger[iAction];
    + 
    +   if( action!=OE_None && !pTrigger ){
    +-    u8 enableLookaside;           /* Copy of db->lookaside.bEnabled */
    +     char const *zFrom;            /* Name of child table */
    +     int nFrom;                    /* Length in bytes of zFrom */
    +     Index *pIdx = 0;              /* Parent key index for this FK */
    +@@ -101583,11 +110624,9 @@ static Trigger *fkActionTrigger(
    +       assert( iFromCol>=0 );
    +       assert( pIdx!=0 || (pTab->iPKey>=0 && pTab->iPKey<pTab->nCol) );
    +       assert( pIdx==0 || pIdx->aiColumn[i]>=0 );
    +-      tToCol.z = pTab->aCol[pIdx ? pIdx->aiColumn[i] : pTab->iPKey].zName;
    +-      tFromCol.z = pFKey->pFrom->aCol[iFromCol].zName;
    +-
    +-      tToCol.n = sqlite3Strlen30(tToCol.z);
    +-      tFromCol.n = sqlite3Strlen30(tFromCol.z);
    ++      sqlite3TokenInit(&tToCol,
    ++                   pTab->aCol[pIdx ? pIdx->aiColumn[i] : pTab->iPKey].zName);
    ++      sqlite3TokenInit(&tFromCol, pFKey->pFrom->aCol[iFromCol].zName);
    + 
    +       /* Create the expression "OLD.zToCol = zFromCol". It is important
    +       ** that the "OLD.zToCol" term is on the LHS of the = operator, so
    +@@ -101596,10 +110635,9 @@ static Trigger *fkActionTrigger(
    +       pEq = sqlite3PExpr(pParse, TK_EQ,
    +           sqlite3PExpr(pParse, TK_DOT, 
    +             sqlite3ExprAlloc(db, TK_ID, &tOld, 0),
    +-            sqlite3ExprAlloc(db, TK_ID, &tToCol, 0)
    +-          , 0),
    ++            sqlite3ExprAlloc(db, TK_ID, &tToCol, 0)),
    +           sqlite3ExprAlloc(db, TK_ID, &tFromCol, 0)
    +-      , 0);
    ++      );
    +       pWhere = sqlite3ExprAnd(db, pWhere, pEq);
    + 
    +       /* For ON UPDATE, construct the next term of the WHEN clause.
    +@@ -101611,13 +110649,11 @@ static Trigger *fkActionTrigger(
    +         pEq = sqlite3PExpr(pParse, TK_IS,
    +             sqlite3PExpr(pParse, TK_DOT, 
    +               sqlite3ExprAlloc(db, TK_ID, &tOld, 0),
    +-              sqlite3ExprAlloc(db, TK_ID, &tToCol, 0),
    +-              0),
    ++              sqlite3ExprAlloc(db, TK_ID, &tToCol, 0)),
    +             sqlite3PExpr(pParse, TK_DOT, 
    +               sqlite3ExprAlloc(db, TK_ID, &tNew, 0),
    +-              sqlite3ExprAlloc(db, TK_ID, &tToCol, 0),
    +-              0),
    +-            0);
    ++              sqlite3ExprAlloc(db, TK_ID, &tToCol, 0))
    ++            );
    +         pWhen = sqlite3ExprAnd(db, pWhen, pEq);
    +       }
    +   
    +@@ -101626,17 +110662,16 @@ static Trigger *fkActionTrigger(
    +         if( action==OE_Cascade ){
    +           pNew = sqlite3PExpr(pParse, TK_DOT, 
    +             sqlite3ExprAlloc(db, TK_ID, &tNew, 0),
    +-            sqlite3ExprAlloc(db, TK_ID, &tToCol, 0)
    +-          , 0);
    ++            sqlite3ExprAlloc(db, TK_ID, &tToCol, 0));
    +         }else if( action==OE_SetDflt ){
    +           Expr *pDflt = pFKey->pFrom->aCol[iFromCol].pDflt;
    +           if( pDflt ){
    +             pNew = sqlite3ExprDup(db, pDflt, 0);
    +           }else{
    +-            pNew = sqlite3PExpr(pParse, TK_NULL, 0, 0, 0);
    ++            pNew = sqlite3ExprAlloc(db, TK_NULL, 0, 0);
    +           }
    +         }else{
    +-          pNew = sqlite3PExpr(pParse, TK_NULL, 0, 0, 0);
    ++          pNew = sqlite3ExprAlloc(db, TK_NULL, 0, 0);
    +         }
    +         pList = sqlite3ExprListAppend(pParse, pList, pNew);
    +         sqlite3ExprListSetName(pParse, pList, &tFromCol, 0);
    +@@ -101661,14 +110696,13 @@ static Trigger *fkActionTrigger(
    +           sqlite3ExprListAppend(pParse, 0, pRaise),
    +           sqlite3SrcListAppend(db, 0, &tFrom, 0),
    +           pWhere,
    +-          0, 0, 0, 0, 0, 0
    ++          0, 0, 0, 0, 0
    +       );
    +       pWhere = 0;
    +     }
    + 
    +     /* Disable lookaside memory allocation */
    +-    enableLookaside = db->lookaside.bEnabled;
    +-    db->lookaside.bEnabled = 0;
    ++    db->lookaside.bDisable++;
    + 
    +     pTrigger = (Trigger *)sqlite3DbMallocZero(db, 
    +         sizeof(Trigger) +         /* struct Trigger */
    +@@ -101684,13 +110718,13 @@ static Trigger *fkActionTrigger(
    +       pStep->pExprList = sqlite3ExprListDup(db, pList, EXPRDUP_REDUCE);
    +       pStep->pSelect = sqlite3SelectDup(db, pSelect, EXPRDUP_REDUCE);
    +       if( pWhen ){
    +-        pWhen = sqlite3PExpr(pParse, TK_NOT, pWhen, 0, 0);
    ++        pWhen = sqlite3PExpr(pParse, TK_NOT, pWhen, 0);
    +         pTrigger->pWhen = sqlite3ExprDup(db, pWhen, EXPRDUP_REDUCE);
    +       }
    +     }
    + 
    +     /* Re-enable the lookaside buffer, if it was disabled earlier. */
    +-    db->lookaside.bEnabled = enableLookaside;
    ++    db->lookaside.bDisable--;
    + 
    +     sqlite3ExprDelete(db, pWhere);
    +     sqlite3ExprDelete(db, pWhen);
    +@@ -101764,7 +110798,8 @@ SQLITE_PRIVATE void sqlite3FkDelete(sqlite3 *db, Table *pTab){
    +   FKey *pFKey;                    /* Iterator variable */
    +   FKey *pNext;                    /* Copy of pFKey->pNextFrom */
    + 
    +-  assert( db==0 || sqlite3SchemaMutexHeld(db, 0, pTab->pSchema) );
    ++  assert( db==0 || IsVirtual(pTab)
    ++         || sqlite3SchemaMutexHeld(db, 0, pTab->pSchema) );
    +   for(pFKey=pTab->pFKey; pFKey; pFKey=pNext){
    + 
    +     /* Remove the FK from the fkeyHash hash table. */
    +@@ -101885,7 +110920,7 @@ SQLITE_PRIVATE const char *sqlite3IndexAffinityStr(sqlite3 *db, Index *pIdx){
    +     Table *pTab = pIdx->pTable;
    +     pIdx->zColAff = (char *)sqlite3DbMallocRaw(0, pIdx->nColumn+1);
    +     if( !pIdx->zColAff ){
    +-      db->mallocFailed = 1;
    ++      sqlite3OomFault(db);
    +       return 0;
    +     }
    +     for(n=0; n<pIdx->nColumn; n++){
    +@@ -101936,7 +110971,7 @@ SQLITE_PRIVATE void sqlite3TableAffinity(Vdbe *v, Table *pTab, int iReg){
    +     sqlite3 *db = sqlite3VdbeDb(v);
    +     zColAff = (char *)sqlite3DbMallocRaw(0, pTab->nCol+1);
    +     if( !zColAff ){
    +-      db->mallocFailed = 1;
    ++      sqlite3OomFault(db);
    +       return;
    +     }
    + 
    +@@ -102002,7 +111037,9 @@ static int readsTable(Parse *p, int iDb, Table *pTab){
    + /*
    + ** Locate or create an AutoincInfo structure associated with table pTab
    + ** which is in database iDb.  Return the register number for the register
    +-** that holds the maximum rowid.
    ++** that holds the maximum rowid.  Return zero if pTab is not an AUTOINCREMENT
    ++** table.  (Also return zero when doing a VACUUM since we do not want to
    ++** update the AUTOINCREMENT counters during a VACUUM.)
    + **
    + ** There is at most one AutoincInfo structure per table even if the
    + ** same table is autoincremented multiple times due to inserts within
    +@@ -102025,14 +111062,16 @@ static int autoIncBegin(
    +   Table *pTab         /* The table we are writing to */
    + ){
    +   int memId = 0;      /* Register holding maximum rowid */
    +-  if( pTab->tabFlags & TF_Autoincrement ){
    ++  if( (pTab->tabFlags & TF_Autoincrement)!=0
    ++   && (pParse->db->mDbFlags & DBFLAG_Vacuum)==0
    ++  ){
    +     Parse *pToplevel = sqlite3ParseToplevel(pParse);
    +     AutoincInfo *pInfo;
    + 
    +     pInfo = pToplevel->pAinc;
    +     while( pInfo && pInfo->pTab!=pTab ){ pInfo = pInfo->pNext; }
    +     if( pInfo==0 ){
    +-      pInfo = sqlite3DbMallocRaw(pParse->db, sizeof(*pInfo));
    ++      pInfo = sqlite3DbMallocRawNN(pParse->db, sizeof(*pInfo));
    +       if( pInfo==0 ) return 0;
    +       pInfo->pNext = pToplevel->pAinc;
    +       pToplevel->pAinc = pInfo;
    +@@ -102056,7 +111095,6 @@ SQLITE_PRIVATE void sqlite3AutoincrementBegin(Parse *pParse){
    +   sqlite3 *db = pParse->db;  /* The database connection */
    +   Db *pDb;                   /* Database only autoinc table */
    +   int memId;                 /* Register holding max rowid */
    +-  int addr;                  /* A VDBE address */
    +   Vdbe *v = pParse->pVdbe;   /* VDBE under construction */
    + 
    +   /* This routine is never called during trigger-generation.  It is
    +@@ -102066,33 +111104,46 @@ SQLITE_PRIVATE void sqlite3AutoincrementBegin(Parse *pParse){
    + 
    +   assert( v );   /* We failed long ago if this is not so */
    +   for(p = pParse->pAinc; p; p = p->pNext){
    ++    static const int iLn = VDBE_OFFSET_LINENO(2);
    ++    static const VdbeOpList autoInc[] = {
    ++      /* 0  */ {OP_Null,    0,  0, 0},
    ++      /* 1  */ {OP_Rewind,  0,  9, 0},
    ++      /* 2  */ {OP_Column,  0,  0, 0},
    ++      /* 3  */ {OP_Ne,      0,  7, 0},
    ++      /* 4  */ {OP_Rowid,   0,  0, 0},
    ++      /* 5  */ {OP_Column,  0,  1, 0},
    ++      /* 6  */ {OP_Goto,    0,  9, 0},
    ++      /* 7  */ {OP_Next,    0,  2, 0},
    ++      /* 8  */ {OP_Integer, 0,  0, 0},
    ++      /* 9  */ {OP_Close,   0,  0, 0} 
    ++    };
    ++    VdbeOp *aOp;
    +     pDb = &db->aDb[p->iDb];
    +     memId = p->regCtr;
    +     assert( sqlite3SchemaMutexHeld(db, 0, pDb->pSchema) );
    +     sqlite3OpenTable(pParse, 0, p->iDb, pDb->pSchema->pSeqTab, OP_OpenRead);
    +-    sqlite3VdbeAddOp3(v, OP_Null, 0, memId, memId+1);
    +-    addr = sqlite3VdbeCurrentAddr(v);
    +     sqlite3VdbeLoadString(v, memId-1, p->pTab->zName);
    +-    sqlite3VdbeAddOp2(v, OP_Rewind, 0, addr+9); VdbeCoverage(v);
    +-    sqlite3VdbeAddOp3(v, OP_Column, 0, 0, memId);
    +-    sqlite3VdbeAddOp3(v, OP_Ne, memId-1, addr+7, memId); VdbeCoverage(v);
    +-    sqlite3VdbeChangeP5(v, SQLITE_JUMPIFNULL);
    +-    sqlite3VdbeAddOp2(v, OP_Rowid, 0, memId+1);
    +-    sqlite3VdbeAddOp3(v, OP_Column, 0, 1, memId);
    +-    sqlite3VdbeGoto(v, addr+9);
    +-    sqlite3VdbeAddOp2(v, OP_Next, 0, addr+2); VdbeCoverage(v);
    +-    sqlite3VdbeAddOp2(v, OP_Integer, 0, memId);
    +-    sqlite3VdbeAddOp0(v, OP_Close);
    ++    aOp = sqlite3VdbeAddOpList(v, ArraySize(autoInc), autoInc, iLn);
    ++    if( aOp==0 ) break;
    ++    aOp[0].p2 = memId;
    ++    aOp[0].p3 = memId+1;
    ++    aOp[2].p3 = memId;
    ++    aOp[3].p1 = memId-1;
    ++    aOp[3].p3 = memId;
    ++    aOp[3].p5 = SQLITE_JUMPIFNULL;
    ++    aOp[4].p2 = memId+1;
    ++    aOp[5].p3 = memId;
    ++    aOp[8].p2 = memId;
    +   }
    + }
    + 
    + /*
    + ** Update the maximum rowid for an autoincrement calculation.
    + **
    +-** This routine should be called when the top of the stack holds a
    ++** This routine should be called when the regRowid register holds a
    + ** new rowid that is about to be inserted.  If that new rowid is
    + ** larger than the maximum rowid in the memId memory cell, then the
    +-** memory cell is updated.  The stack is unchanged.
    ++** memory cell is updated.
    + */
    + static void autoIncStep(Parse *pParse, int memId, int regRowid){
    +   if( memId>0 ){
    +@@ -102107,31 +111158,44 @@ static void autoIncStep(Parse *pParse, int memId, int regRowid){
    + ** table (either directly or through triggers) needs to call this
    + ** routine just before the "exit" code.
    + */
    +-SQLITE_PRIVATE void sqlite3AutoincrementEnd(Parse *pParse){
    ++static SQLITE_NOINLINE void autoIncrementEnd(Parse *pParse){
    +   AutoincInfo *p;
    +   Vdbe *v = pParse->pVdbe;
    +   sqlite3 *db = pParse->db;
    + 
    +   assert( v );
    +   for(p = pParse->pAinc; p; p = p->pNext){
    ++    static const int iLn = VDBE_OFFSET_LINENO(2);
    ++    static const VdbeOpList autoIncEnd[] = {
    ++      /* 0 */ {OP_NotNull,     0, 2, 0},
    ++      /* 1 */ {OP_NewRowid,    0, 0, 0},
    ++      /* 2 */ {OP_MakeRecord,  0, 2, 0},
    ++      /* 3 */ {OP_Insert,      0, 0, 0},
    ++      /* 4 */ {OP_Close,       0, 0, 0}
    ++    };
    ++    VdbeOp *aOp;
    +     Db *pDb = &db->aDb[p->iDb];
    +-    int addr1;
    +     int iRec;
    +     int memId = p->regCtr;
    + 
    +     iRec = sqlite3GetTempReg(pParse);
    +     assert( sqlite3SchemaMutexHeld(db, 0, pDb->pSchema) );
    +     sqlite3OpenTable(pParse, 0, p->iDb, pDb->pSchema->pSeqTab, OP_OpenWrite);
    +-    addr1 = sqlite3VdbeAddOp1(v, OP_NotNull, memId+1); VdbeCoverage(v);
    +-    sqlite3VdbeAddOp2(v, OP_NewRowid, 0, memId+1);
    +-    sqlite3VdbeJumpHere(v, addr1);
    +-    sqlite3VdbeAddOp3(v, OP_MakeRecord, memId-1, 2, iRec);
    +-    sqlite3VdbeAddOp3(v, OP_Insert, 0, iRec, memId+1);
    +-    sqlite3VdbeChangeP5(v, OPFLAG_APPEND);
    +-    sqlite3VdbeAddOp0(v, OP_Close);
    ++    aOp = sqlite3VdbeAddOpList(v, ArraySize(autoIncEnd), autoIncEnd, iLn);
    ++    if( aOp==0 ) break;
    ++    aOp[0].p1 = memId+1;
    ++    aOp[1].p2 = memId+1;
    ++    aOp[2].p1 = memId-1;
    ++    aOp[2].p3 = iRec;
    ++    aOp[3].p2 = iRec;
    ++    aOp[3].p3 = memId+1;
    ++    aOp[3].p5 = OPFLAG_APPEND;
    +     sqlite3ReleaseTempReg(pParse, iRec);
    +   }
    + }
    ++SQLITE_PRIVATE void sqlite3AutoincrementEnd(Parse *pParse){
    ++  if( pParse->pAinc ) autoIncrementEnd(pParse);
    ++}
    + #else
    + /*
    + ** If SQLITE_OMIT_AUTOINCREMENT is defined, then the three routines
    +@@ -102257,9 +111321,7 @@ SQLITE_PRIVATE void sqlite3Insert(
    + ){
    +   sqlite3 *db;          /* The main database structure */
    +   Table *pTab;          /* The table to insert into.  aka TABLE */
    +-  char *zTab;           /* Name of the table into which we are inserting */
    +-  const char *zDb;      /* Name of the database holding this table */
    +-  int i, j, idx;        /* Loop counters */
    ++  int i, j;             /* Loop counters */
    +   Vdbe *v;              /* Generate code into this virtual machine */
    +   Index *pIdx;          /* For looping over indices of the table */
    +   int nColumn;          /* Number of columns in the data */
    +@@ -102273,7 +111335,6 @@ SQLITE_PRIVATE void sqlite3Insert(
    +   int addrCont = 0;     /* Top of insert loop. Label "C" in templates 3 and 4 */
    +   SelectDest dest;      /* Destination for SELECT on rhs of INSERT */
    +   int iDb;              /* Index of database holding TABLE */
    +-  Db *pDb;              /* The database containing table being inserted into */
    +   u8 useTempTable = 0;  /* Store SELECT results in intermediate table */
    +   u8 appendFlag = 0;    /* True if the insert is likely to be an append */
    +   u8 withoutRowid;      /* 0 for normal table.  1 for WITHOUT ROWID table */
    +@@ -102296,10 +111357,10 @@ SQLITE_PRIVATE void sqlite3Insert(
    + #endif
    + 
    +   db = pParse->db;
    +-  memset(&dest, 0, sizeof(dest));
    +   if( pParse->nErr || db->mallocFailed ){
    +     goto insert_cleanup;
    +   }
    ++  dest.iSDParm = 0;  /* Suppress a harmless compiler warning */
    + 
    +   /* If the Select object is really just a simple VALUES() list with a
    +   ** single row (the common case) then keep that one row of values
    +@@ -102315,17 +111376,14 @@ SQLITE_PRIVATE void sqlite3Insert(
    +   /* Locate the table into which we will be inserting new information.
    +   */
    +   assert( pTabList->nSrc==1 );
    +-  zTab = pTabList->a[0].zName;
    +-  if( NEVER(zTab==0) ) goto insert_cleanup;
    +   pTab = sqlite3SrcListLookup(pParse, pTabList);
    +   if( pTab==0 ){
    +     goto insert_cleanup;
    +   }
    +   iDb = sqlite3SchemaToIndex(db, pTab->pSchema);
    +   assert( iDb<db->nDb );
    +-  pDb = &db->aDb[iDb];
    +-  zDb = pDb->zName;
    +-  if( sqlite3AuthCheck(pParse, SQLITE_INSERT, pTab->zName, 0, zDb) ){
    ++  if( sqlite3AuthCheck(pParse, SQLITE_INSERT, pTab->zName, 0,
    ++                       db->aDb[iDb].zDbSName) ){
    +     goto insert_cleanup;
    +   }
    +   withoutRowid = !HasRowid(pTab);
    +@@ -102462,7 +111520,7 @@ SQLITE_PRIVATE void sqlite3Insert(
    +     rc = sqlite3Select(pParse, pSelect, &dest);
    +     regFromSelect = dest.iSdst;
    +     if( rc || db->mallocFailed || pParse->nErr ) goto insert_cleanup;
    +-    sqlite3VdbeAddOp1(v, OP_EndCoroutine, regYield);
    ++    sqlite3VdbeEndCoroutine(v, regYield);
    +     sqlite3VdbeJumpHere(v, addrTop - 1);                       /* label B: */
    +     assert( pSelect->pEList );
    +     nColumn = pSelect->pEList->nExpr;
    +@@ -102538,10 +111596,8 @@ SQLITE_PRIVATE void sqlite3Insert(
    +   /* Make sure the number of columns in the source data matches the number
    +   ** of columns to be inserted into the table.
    +   */
    +-  if( IsVirtual(pTab) ){
    +-    for(i=0; i<pTab->nCol; i++){
    +-      nHidden += (IsHiddenColumn(&pTab->aCol[i]) ? 1 : 0);
    +-    }
    ++  for(i=0; i<pTab->nCol; i++){
    ++    nHidden += (IsHiddenColumn(&pTab->aCol[i]) ? 1 : 0);
    +   }
    +   if( pColumn==0 && nColumn && nColumn!=(pTab->nCol-nHidden) ){
    +     sqlite3ErrorMsg(pParse, 
    +@@ -102564,14 +111620,16 @@ SQLITE_PRIVATE void sqlite3Insert(
    +   /* If this is not a view, open the table and and all indices */
    +   if( !isView ){
    +     int nIdx;
    +-    nIdx = sqlite3OpenTableAndIndices(pParse, pTab, OP_OpenWrite, -1, 0,
    ++    nIdx = sqlite3OpenTableAndIndices(pParse, pTab, OP_OpenWrite, 0, -1, 0,
    +                                       &iDataCur, &iIdxCur);
    +-    aRegIdx = sqlite3DbMallocRaw(db, sizeof(int)*(nIdx+1));
    ++    aRegIdx = sqlite3DbMallocRawNN(db, sizeof(int)*(nIdx+1));
    +     if( aRegIdx==0 ){
    +       goto insert_cleanup;
    +     }
    +-    for(i=0; i<nIdx; i++){
    ++    for(i=0, pIdx=pTab->pIndex; i<nIdx; pIdx=pIdx->pNext, i++){
    ++      assert( pIdx );
    +       aRegIdx[i] = ++pParse->nMem;
    ++      pParse->nMem += pIdx->nColumn;
    +     }
    +   }
    + 
    +@@ -102637,15 +111695,14 @@ SQLITE_PRIVATE void sqlite3Insert(
    + 
    +     /* Create the new column data
    +     */
    +-    for(i=0; i<pTab->nCol; i++){
    +-      if( pColumn==0 ){
    +-        j = i;
    +-      }else{
    ++    for(i=j=0; i<pTab->nCol; i++){
    ++      if( pColumn ){
    +         for(j=0; j<pColumn->nId; j++){
    +           if( pColumn->a[j].idx==i ) break;
    +         }
    +       }
    +-      if( (!useTempTable && !pList) || (pColumn && j>=pColumn->nId) ){
    ++      if( (!useTempTable && !pList) || (pColumn && j>=pColumn->nId)
    ++            || (pColumn==0 && IsOrdinaryHiddenColumn(&pTab->aCol[i])) ){
    +         sqlite3ExprCode(pParse, pTab->aCol[i].pDflt, regCols+i+1);
    +       }else if( useTempTable ){
    +         sqlite3VdbeAddOp3(v, OP_Column, srcTab, j, regCols+i+1); 
    +@@ -102653,6 +111710,7 @@ SQLITE_PRIVATE void sqlite3Insert(
    +         assert( pSelect==0 ); /* Otherwise useTempTable is true */
    +         sqlite3ExprCodeAndCache(pParse, pList->a[j].pExpr, regCols+i+1);
    +       }
    ++      if( pColumn==0 && !IsOrdinaryHiddenColumn(&pTab->aCol[i]) ) j++;
    +     }
    + 
    +     /* If this is an INSERT on a view with an INSTEAD OF INSERT trigger,
    +@@ -102688,7 +111746,8 @@ SQLITE_PRIVATE void sqlite3Insert(
    +         VdbeOp *pOp;
    +         sqlite3ExprCode(pParse, pList->a[ipkColumn].pExpr, regRowid);
    +         pOp = sqlite3VdbeGetOp(v, -1);
    +-        if( ALWAYS(pOp) && pOp->opcode==OP_Null && !IsVirtual(pTab) ){
    ++        assert( pOp!=0 );
    ++        if( pOp->opcode==OP_Null && !IsVirtual(pTab) ){
    +           appendFlag = 1;
    +           pOp->opcode = OP_NewRowid;
    +           pOp->p1 = iDataCur;
    +@@ -102736,7 +111795,6 @@ SQLITE_PRIVATE void sqlite3Insert(
    +       }
    +       if( pColumn==0 ){
    +         if( IsHiddenColumn(&pTab->aCol[i]) ){
    +-          assert( IsVirtual(pTab) );
    +           j = -1;
    +           nHidden++;
    +         }else{
    +@@ -102774,12 +111832,26 @@ SQLITE_PRIVATE void sqlite3Insert(
    + #endif
    +     {
    +       int isReplace;    /* Set to true if constraints may cause a replace */
    ++      int bUseSeek;     /* True to use OPFLAG_SEEKRESULT */
    +       sqlite3GenerateConstraintChecks(pParse, pTab, aRegIdx, iDataCur, iIdxCur,
    +-          regIns, 0, ipkColumn>=0, onError, endOfLoop, &isReplace
    ++          regIns, 0, ipkColumn>=0, onError, endOfLoop, &isReplace, 0
    +       );
    +       sqlite3FkCheck(pParse, pTab, 0, regIns, 0, 0);
    ++
    ++      /* Set the OPFLAG_USESEEKRESULT flag if either (a) there are no REPLACE
    ++      ** constraints or (b) there are no triggers and this table is not a
    ++      ** parent table in a foreign key constraint. It is safe to set the
    ++      ** flag in the second case as if any REPLACE constraint is hit, an
    ++      ** OP_Delete or OP_IdxDelete instruction will be executed on each 
    ++      ** cursor that is disturbed. And these instructions both clear the
    ++      ** VdbeCursor.seekResult variable, disabling the OPFLAG_USESEEKRESULT
    ++      ** functionality.  */
    ++      bUseSeek = (isReplace==0 || (pTrigger==0 &&
    ++          ((db->flags & SQLITE_ForeignKeys)==0 || sqlite3FkReferences(pTab)==0)
    ++      ));
    +       sqlite3CompleteInsertion(pParse, pTab, iDataCur, iIdxCur,
    +-                               regIns, aRegIdx, 0, appendFlag, isReplace==0);
    ++          regIns, aRegIdx, 0, appendFlag, bUseSeek
    ++      );
    +     }
    +   }
    + 
    +@@ -102808,14 +111880,6 @@ SQLITE_PRIVATE void sqlite3Insert(
    +     sqlite3VdbeJumpHere(v, addrInsTop);
    +   }
    + 
    +-  if( !IsVirtual(pTab) && !isView ){
    +-    /* Close all tables opened */
    +-    if( iDataCur<iIdxCur ) sqlite3VdbeAddOp1(v, OP_Close, iDataCur);
    +-    for(idx=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, idx++){
    +-      sqlite3VdbeAddOp1(v, OP_Close, idx+iIdxCur);
    +-    }
    +-  }
    +-
    + insert_end:
    +   /* Update the sqlite_sequence table by storing the content of the
    +   ** maximum rowid counter values recorded while inserting into
    +@@ -102857,6 +111921,59 @@ insert_cleanup:
    +  #undef tmask
    + #endif
    + 
    ++/*
    ++** Meanings of bits in of pWalker->eCode for checkConstraintUnchanged()
    ++*/
    ++#define CKCNSTRNT_COLUMN   0x01    /* CHECK constraint uses a changing column */
    ++#define CKCNSTRNT_ROWID    0x02    /* CHECK constraint references the ROWID */
    ++
    ++/* This is the Walker callback from checkConstraintUnchanged().  Set
    ++** bit 0x01 of pWalker->eCode if
    ++** pWalker->eCode to 0 if this expression node references any of the
    ++** columns that are being modifed by an UPDATE statement.
    ++*/
    ++static int checkConstraintExprNode(Walker *pWalker, Expr *pExpr){
    ++  if( pExpr->op==TK_COLUMN ){
    ++    assert( pExpr->iColumn>=0 || pExpr->iColumn==-1 );
    ++    if( pExpr->iColumn>=0 ){
    ++      if( pWalker->u.aiCol[pExpr->iColumn]>=0 ){
    ++        pWalker->eCode |= CKCNSTRNT_COLUMN;
    ++      }
    ++    }else{
    ++      pWalker->eCode |= CKCNSTRNT_ROWID;
    ++    }
    ++  }
    ++  return WRC_Continue;
    ++}
    ++
    ++/*
    ++** pExpr is a CHECK constraint on a row that is being UPDATE-ed.  The
    ++** only columns that are modified by the UPDATE are those for which
    ++** aiChng[i]>=0, and also the ROWID is modified if chngRowid is true.
    ++**
    ++** Return true if CHECK constraint pExpr does not use any of the
    ++** changing columns (or the rowid if it is changing).  In other words,
    ++** return true if this CHECK constraint can be skipped when validating
    ++** the new row in the UPDATE statement.
    ++*/
    ++static int checkConstraintUnchanged(Expr *pExpr, int *aiChng, int chngRowid){
    ++  Walker w;
    ++  memset(&w, 0, sizeof(w));
    ++  w.eCode = 0;
    ++  w.xExprCallback = checkConstraintExprNode;
    ++  w.u.aiCol = aiChng;
    ++  sqlite3WalkExpr(&w, pExpr);
    ++  if( !chngRowid ){
    ++    testcase( (w.eCode & CKCNSTRNT_ROWID)!=0 );
    ++    w.eCode &= ~CKCNSTRNT_ROWID;
    ++  }
    ++  testcase( w.eCode==0 );
    ++  testcase( w.eCode==CKCNSTRNT_COLUMN );
    ++  testcase( w.eCode==CKCNSTRNT_ROWID );
    ++  testcase( w.eCode==(CKCNSTRNT_ROWID|CKCNSTRNT_COLUMN) );
    ++  return !w.eCode;
    ++}
    ++
    + /*
    + ** Generate code to do constraint checks prior to an INSERT or an UPDATE
    + ** on table pTab.
    +@@ -102951,7 +112068,8 @@ SQLITE_PRIVATE void sqlite3GenerateConstraintChecks(
    +   u8 pkChng,           /* Non-zero if the rowid or PRIMARY KEY changed */
    +   u8 overrideError,    /* Override onError to this if not OE_Default */
    +   int ignoreDest,      /* Jump to this label on an OE_Ignore resolution */
    +-  int *pbMayReplace    /* OUT: Set to true if constraint may cause a replace */
    ++  int *pbMayReplace,   /* OUT: Set to true if constraint may cause a replace */
    ++  int *aiChng          /* column i is unchanged if aiChng[i]<0 */
    + ){
    +   Vdbe *v;             /* VDBE under constrution */
    +   Index *pIdx;         /* Pointer to one of the indices */
    +@@ -102968,7 +112086,6 @@ SQLITE_PRIVATE void sqlite3GenerateConstraintChecks(
    +   int ipkBottom = 0;   /* Bottom of the rowid change constraint check */
    +   u8 isUpdate;         /* True if this is an UPDATE operation */
    +   u8 bAffinityDone = 0;  /* True if the OP_Affinity operation has been run */
    +-  int regRowid = -1;   /* Register holding ROWID value */
    + 
    +   isUpdate = regOldData!=0;
    +   db = pParse->db;
    +@@ -102997,10 +112114,14 @@ SQLITE_PRIVATE void sqlite3GenerateConstraintChecks(
    +   */
    +   for(i=0; i<nCol; i++){
    +     if( i==pTab->iPKey ){
    ++      continue;        /* ROWID is never NULL */
    ++    }
    ++    if( aiChng && aiChng[i]<0 ){
    ++      /* Don't bother checking for NOT NULL on columns that do not change */
    +       continue;
    +     }
    +     onError = pTab->aCol[i].notNull;
    +-    if( onError==OE_None ) continue;
    ++    if( onError==OE_None ) continue;  /* This column is allowed to be NULL */
    +     if( overrideError!=OE_Default ){
    +       onError = overrideError;
    +     }else if( onError==OE_Default ){
    +@@ -103019,8 +112140,9 @@ SQLITE_PRIVATE void sqlite3GenerateConstraintChecks(
    +       case OE_Fail: {
    +         char *zMsg = sqlite3MPrintf(db, "%s.%s", pTab->zName,
    +                                     pTab->aCol[i].zName);
    +-        sqlite3VdbeAddOp4(v, OP_HaltIfNull, SQLITE_CONSTRAINT_NOTNULL, onError,
    +-                          regNewData+1+i, zMsg, P4_DYNAMIC);
    ++        sqlite3VdbeAddOp3(v, OP_HaltIfNull, SQLITE_CONSTRAINT_NOTNULL, onError,
    ++                          regNewData+1+i);
    ++        sqlite3VdbeAppendP4(v, zMsg, P4_DYNAMIC);
    +         sqlite3VdbeChangeP5(v, P5_ConstraintNotNull);
    +         VdbeCoverage(v);
    +         break;
    +@@ -103046,11 +112168,14 @@ SQLITE_PRIVATE void sqlite3GenerateConstraintChecks(
    + #ifndef SQLITE_OMIT_CHECK
    +   if( pTab->pCheck && (db->flags & SQLITE_IgnoreChecks)==0 ){
    +     ExprList *pCheck = pTab->pCheck;
    +-    pParse->ckBase = regNewData+1;
    ++    pParse->iSelfTab = -(regNewData+1);
    +     onError = overrideError!=OE_Default ? overrideError : OE_Abort;
    +     for(i=0; i<pCheck->nExpr; i++){
    +-      int allOk = sqlite3VdbeMakeLabel(v);
    +-      sqlite3ExprIfTrue(pParse, pCheck->a[i].pExpr, allOk, SQLITE_JUMPIFNULL);
    ++      int allOk;
    ++      Expr *pExpr = pCheck->a[i].pExpr;
    ++      if( aiChng && checkConstraintUnchanged(pExpr, aiChng, pkChng) ) continue;
    ++      allOk = sqlite3VdbeMakeLabel(v);
    ++      sqlite3ExprIfTrue(pParse, pExpr, allOk, SQLITE_JUMPIFNULL);
    +       if( onError==OE_Ignore ){
    +         sqlite3VdbeGoto(v, ignoreDest);
    +       }else{
    +@@ -103063,6 +112188,7 @@ SQLITE_PRIVATE void sqlite3GenerateConstraintChecks(
    +       }
    +       sqlite3VdbeResolveLabel(v, allOk);
    +     }
    ++    pParse->iSelfTab = 0;
    +   }
    + #endif /* !defined(SQLITE_OMIT_CHECK) */
    + 
    +@@ -103081,7 +112207,7 @@ SQLITE_PRIVATE void sqlite3GenerateConstraintChecks(
    +     }
    + 
    +     if( isUpdate ){
    +-      /* pkChng!=0 does not mean that the rowid has change, only that
    ++      /* pkChng!=0 does not mean that the rowid has changed, only that
    +       ** it might have changed.  Skip the conflict logic below if the rowid
    +       ** is unchanged. */
    +       sqlite3VdbeAddOp3(v, OP_Eq, regNewData, addrRowidOk, regOldData);
    +@@ -103150,9 +112276,18 @@ SQLITE_PRIVATE void sqlite3GenerateConstraintChecks(
    +         if( pTrigger || sqlite3FkRequired(pParse, pTab, 0, 0) ){
    +           sqlite3MultiWrite(pParse);
    +           sqlite3GenerateRowDelete(pParse, pTab, pTrigger, iDataCur, iIdxCur,
    +-                                   regNewData, 1, 0, OE_Replace,
    +-                                   ONEPASS_SINGLE, -1);
    ++                                   regNewData, 1, 0, OE_Replace, 1, -1);
    +         }else{
    ++#ifdef SQLITE_ENABLE_PREUPDATE_HOOK
    ++          if( HasRowid(pTab) ){
    ++            /* This OP_Delete opcode fires the pre-update-hook only. It does
    ++            ** not modify the b-tree. It is more efficient to let the coming
    ++            ** OP_Insert replace the existing entry than it is to delete the
    ++            ** existing entry and then insert a new one. */
    ++            sqlite3VdbeAddOp2(v, OP_Delete, iDataCur, OPFLAG_ISNOOP);
    ++            sqlite3VdbeAppendP4(v, pTab, P4_TABLE);
    ++          }
    ++#endif /* SQLITE_ENABLE_PREUPDATE_HOOK */
    +           if( pTab->pIndex ){
    +             sqlite3MultiWrite(pParse);
    +             sqlite3GenerateRowIndexDelete(pParse, pTab, iDataCur, iIdxCur,0,-1);
    +@@ -103198,39 +112333,39 @@ SQLITE_PRIVATE void sqlite3GenerateConstraintChecks(
    +     /* Skip partial indices for which the WHERE clause is not true */
    +     if( pIdx->pPartIdxWhere ){
    +       sqlite3VdbeAddOp2(v, OP_Null, 0, aRegIdx[ix]);
    +-      pParse->ckBase = regNewData+1;
    ++      pParse->iSelfTab = -(regNewData+1);
    +       sqlite3ExprIfFalseDup(pParse, pIdx->pPartIdxWhere, addrUniqueOk,
    +                             SQLITE_JUMPIFNULL);
    +-      pParse->ckBase = 0;
    ++      pParse->iSelfTab = 0;
    +     }
    + 
    +     /* Create a record for this index entry as it should appear after
    +     ** the insert or update.  Store that record in the aRegIdx[ix] register
    +     */
    +-    regIdx = sqlite3GetTempRange(pParse, pIdx->nColumn);
    ++    regIdx = aRegIdx[ix]+1;
    +     for(i=0; i<pIdx->nColumn; i++){
    +       int iField = pIdx->aiColumn[i];
    +       int x;
    +       if( iField==XN_EXPR ){
    +-        pParse->ckBase = regNewData+1;
    +-        sqlite3ExprCode(pParse, pIdx->aColExpr->a[i].pExpr, regIdx+i);
    +-        pParse->ckBase = 0;
    ++        pParse->iSelfTab = -(regNewData+1);
    ++        sqlite3ExprCodeCopy(pParse, pIdx->aColExpr->a[i].pExpr, regIdx+i);
    ++        pParse->iSelfTab = 0;
    +         VdbeComment((v, "%s column %d", pIdx->zName, i));
    +       }else{
    +         if( iField==XN_ROWID || iField==pTab->iPKey ){
    +-          if( regRowid==regIdx+i ) continue; /* ROWID already in regIdx+i */
    +           x = regNewData;
    +-          regRowid =  pIdx->pPartIdxWhere ? -1 : regIdx+i;
    +         }else{
    +           x = iField + regNewData + 1;
    +         }
    +-        sqlite3VdbeAddOp2(v, OP_SCopy, x, regIdx+i);
    ++        sqlite3VdbeAddOp2(v, iField<0 ? OP_IntCopy : OP_SCopy, x, regIdx+i);
    +         VdbeComment((v, "%s", iField<0 ? "rowid" : pTab->aCol[iField].zName));
    +       }
    +     }
    +     sqlite3VdbeAddOp3(v, OP_MakeRecord, regIdx, pIdx->nColumn, aRegIdx[ix]);
    +     VdbeComment((v, "for %s", pIdx->zName));
    +-    sqlite3ExprCacheAffinityChange(pParse, regIdx, pIdx->nColumn);
    ++#ifdef SQLITE_ENABLE_NULL_TRIM
    ++    if( pIdx->idxType==2 ) sqlite3SetMakeRecordP5(v, pIdx->pTable);
    ++#endif
    + 
    +     /* In an UPDATE operation, if this index is the PRIMARY KEY index 
    +     ** of a WITHOUT ROWID table and there has been no change the
    +@@ -103244,7 +112379,6 @@ SQLITE_PRIVATE void sqlite3GenerateConstraintChecks(
    +     /* Find out what action to take in case there is a uniqueness conflict */
    +     onError = pIdx->onError;
    +     if( onError==OE_None ){ 
    +-      sqlite3ReleaseTempRange(pParse, regIdx, pIdx->nColumn);
    +       sqlite3VdbeResolveLabel(v, addrUniqueOk);
    +       continue;  /* pIdx is not a UNIQUE index */
    +     }
    +@@ -103253,8 +112387,28 @@ SQLITE_PRIVATE void sqlite3GenerateConstraintChecks(
    +     }else if( onError==OE_Default ){
    +       onError = OE_Abort;
    +     }
    +-    
    ++
    ++    /* Collision detection may be omitted if all of the following are true:
    ++    **   (1) The conflict resolution algorithm is REPLACE
    ++    **   (2) The table is a WITHOUT ROWID table
    ++    **   (3) There are no secondary indexes on the table
    ++    **   (4) No delete triggers need to be fired if there is a conflict
    ++    **   (5) No FK constraint counters need to be updated if a conflict occurs.
    ++    */ 
    ++    if( (ix==0 && pIdx->pNext==0)                   /* Condition 3 */
    ++     && pPk==pIdx                                   /* Condition 2 */
    ++     && onError==OE_Replace                         /* Condition 1 */
    ++     && ( 0==(db->flags&SQLITE_RecTriggers) ||      /* Condition 4 */
    ++          0==sqlite3TriggersExist(pParse, pTab, TK_DELETE, 0, 0))
    ++     && ( 0==(db->flags&SQLITE_ForeignKeys) ||      /* Condition 5 */
    ++         (0==pTab->pFKey && 0==sqlite3FkReferences(pTab)))
    ++    ){
    ++      sqlite3VdbeResolveLabel(v, addrUniqueOk);
    ++      continue;
    ++    }
    ++
    +     /* Check to see if the new index entry will be unique */
    ++    sqlite3ExprCachePush(pParse);
    +     sqlite3VdbeAddOp4Int(v, OP_NoConflict, iThisCur, addrUniqueOk,
    +                          regIdx, pIdx->nKeyCol); VdbeCoverage(v);
    + 
    +@@ -103337,13 +112491,13 @@ SQLITE_PRIVATE void sqlite3GenerateConstraintChecks(
    +         }
    +         sqlite3GenerateRowDelete(pParse, pTab, pTrigger, iDataCur, iIdxCur,
    +             regR, nPkField, 0, OE_Replace,
    +-            (pIdx==pPk ? ONEPASS_SINGLE : ONEPASS_OFF), -1);
    ++            (pIdx==pPk ? ONEPASS_SINGLE : ONEPASS_OFF), iThisCur);
    +         seenReplace = 1;
    +         break;
    +       }
    +     }
    +     sqlite3VdbeResolveLabel(v, addrUniqueOk);
    +-    sqlite3ReleaseTempRange(pParse, regIdx, pIdx->nColumn);
    ++    sqlite3ExprCachePop(pParse);
    +     if( regR!=regIdx ) sqlite3ReleaseTempRange(pParse, regR, nPkField);
    +   }
    +   if( ipkTop ){
    +@@ -103355,6 +112509,28 @@ SQLITE_PRIVATE void sqlite3GenerateConstraintChecks(
    +   VdbeModuleComment((v, "END: GenCnstCks(%d)", seenReplace));
    + }
    + 
    ++#ifdef SQLITE_ENABLE_NULL_TRIM
    ++/*
    ++** Change the P5 operand on the last opcode (which should be an OP_MakeRecord)
    ++** to be the number of columns in table pTab that must not be NULL-trimmed.
    ++**
    ++** Or if no columns of pTab may be NULL-trimmed, leave P5 at zero.
    ++*/
    ++SQLITE_PRIVATE void sqlite3SetMakeRecordP5(Vdbe *v, Table *pTab){
    ++  u16 i;
    ++
    ++  /* Records with omitted columns are only allowed for schema format
    ++  ** version 2 and later (SQLite version 3.1.4, 2005-02-20). */
    ++  if( pTab->pSchema->file_format<2 ) return;
    ++
    ++  for(i=pTab->nCol-1; i>0; i--){
    ++    if( pTab->aCol[i].pDflt!=0 ) break;
    ++    if( pTab->aCol[i].colFlags & COLFLAG_PRIMKEY ) break;
    ++  }
    ++  sqlite3VdbeChangeP5(v, i+1);
    ++}
    ++#endif
    ++
    + /*
    + ** This routine generates code to finish the INSERT or UPDATE operation
    + ** that was started by a prior call to sqlite3GenerateConstraintChecks.
    +@@ -103371,7 +112547,7 @@ SQLITE_PRIVATE void sqlite3CompleteInsertion(
    +   int iIdxCur,        /* First index cursor */
    +   int regNewData,     /* Range of content */
    +   int *aRegIdx,       /* Register used by each index.  0 for unused indices */
    +-  int isUpdate,       /* True for UPDATE, False for INSERT */
    ++  int update_flags,   /* True for UPDATE, False for INSERT */
    +   int appendBias,     /* True if this is likely to be an append */
    +   int useSeekResult   /* True to set the USESEEKRESULT flag on OP_[Idx]Insert */
    + ){
    +@@ -103383,6 +112559,11 @@ SQLITE_PRIVATE void sqlite3CompleteInsertion(
    +   int i;              /* Loop counter */
    +   u8 bAffinityDone = 0; /* True if OP_Affinity has been run already */
    + 
    ++  assert( update_flags==0
    ++       || update_flags==OPFLAG_ISUPDATE
    ++       || update_flags==(OPFLAG_ISUPDATE|OPFLAG_SAVEPOSITION)
    ++  );
    ++
    +   v = sqlite3GetVdbe(pParse);
    +   assert( v!=0 );
    +   assert( pTab->pSelect==0 );  /* This table is not a VIEW */
    +@@ -103393,26 +112574,39 @@ SQLITE_PRIVATE void sqlite3CompleteInsertion(
    +       sqlite3VdbeAddOp2(v, OP_IsNull, aRegIdx[i], sqlite3VdbeCurrentAddr(v)+2);
    +       VdbeCoverage(v);
    +     }
    +-    sqlite3VdbeAddOp2(v, OP_IdxInsert, iIdxCur+i, aRegIdx[i]);
    +-    pik_flags = 0;
    +-    if( useSeekResult ) pik_flags = OPFLAG_USESEEKRESULT;
    ++    pik_flags = (useSeekResult ? OPFLAG_USESEEKRESULT : 0);
    +     if( IsPrimaryKeyIndex(pIdx) && !HasRowid(pTab) ){
    +       assert( pParse->nested==0 );
    +       pik_flags |= OPFLAG_NCHANGE;
    ++      pik_flags |= (update_flags & OPFLAG_SAVEPOSITION);
    ++#ifdef SQLITE_ENABLE_PREUPDATE_HOOK
    ++      if( update_flags==0 ){
    ++        sqlite3VdbeAddOp4(v, OP_InsertInt, 
    ++            iIdxCur+i, aRegIdx[i], 0, (char*)pTab, P4_TABLE
    ++        );
    ++        sqlite3VdbeChangeP5(v, OPFLAG_ISNOOP);
    ++      }
    ++#endif
    +     }
    +-    if( pik_flags )  sqlite3VdbeChangeP5(v, pik_flags);
    ++    sqlite3VdbeAddOp4Int(v, OP_IdxInsert, iIdxCur+i, aRegIdx[i],
    ++                         aRegIdx[i]+1,
    ++                         pIdx->uniqNotNull ? pIdx->nKeyCol: pIdx->nColumn);
    ++    sqlite3VdbeChangeP5(v, pik_flags);
    +   }
    +   if( !HasRowid(pTab) ) return;
    +   regData = regNewData + 1;
    +   regRec = sqlite3GetTempReg(pParse);
    +   sqlite3VdbeAddOp3(v, OP_MakeRecord, regData, pTab->nCol, regRec);
    +-  if( !bAffinityDone ) sqlite3TableAffinity(v, pTab, 0);
    +-  sqlite3ExprCacheAffinityChange(pParse, regData, pTab->nCol);
    ++  sqlite3SetMakeRecordP5(v, pTab);
    ++  if( !bAffinityDone ){
    ++    sqlite3TableAffinity(v, pTab, 0);
    ++    sqlite3ExprCacheAffinityChange(pParse, regData, pTab->nCol);
    ++  }
    +   if( pParse->nested ){
    +     pik_flags = 0;
    +   }else{
    +     pik_flags = OPFLAG_NCHANGE;
    +-    pik_flags |= (isUpdate?OPFLAG_ISUPDATE:OPFLAG_LASTROWID);
    ++    pik_flags |= (update_flags?update_flags:OPFLAG_LASTROWID);
    +   }
    +   if( appendBias ){
    +     pik_flags |= OPFLAG_APPEND;
    +@@ -103422,7 +112616,7 @@ SQLITE_PRIVATE void sqlite3CompleteInsertion(
    +   }
    +   sqlite3VdbeAddOp3(v, OP_Insert, iDataCur, regRec, regNewData);
    +   if( !pParse->nested ){
    +-    sqlite3VdbeChangeP4(v, -1, pTab->zName, P4_TRANSIENT);
    ++    sqlite3VdbeAppendP4(v, pTab, P4_TABLE);
    +   }
    +   sqlite3VdbeChangeP5(v, pik_flags);
    + }
    +@@ -103452,6 +112646,7 @@ SQLITE_PRIVATE int sqlite3OpenTableAndIndices(
    +   Parse *pParse,   /* Parsing context */
    +   Table *pTab,     /* Table to be opened */
    +   int op,          /* OP_OpenRead or OP_OpenWrite */
    ++  u8 p5,           /* P5 value for OP_Open* opcodes (except on WITHOUT ROWID) */
    +   int iBase,       /* Use this for the table cursor, if there is one */
    +   u8 *aToOpen,     /* If not NULL: boolean for each table and index */
    +   int *piDataCur,  /* Write the database source cursor number here */
    +@@ -103464,6 +112659,7 @@ SQLITE_PRIVATE int sqlite3OpenTableAndIndices(
    +   Vdbe *v;
    + 
    +   assert( op==OP_OpenRead || op==OP_OpenWrite );
    ++  assert( op==OP_OpenWrite || p5==0 );
    +   if( IsVirtual(pTab) ){
    +     /* This routine is a no-op for virtual tables. Leave the output
    +     ** variables *piDataCur and *piIdxCur uninitialized so that valgrind
    +@@ -103485,12 +112681,14 @@ SQLITE_PRIVATE int sqlite3OpenTableAndIndices(
    +   for(i=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, i++){
    +     int iIdxCur = iBase++;
    +     assert( pIdx->pSchema==pTab->pSchema );
    +-    if( IsPrimaryKeyIndex(pIdx) && !HasRowid(pTab) && piDataCur ){
    +-      *piDataCur = iIdxCur;
    ++    if( IsPrimaryKeyIndex(pIdx) && !HasRowid(pTab) ){
    ++      if( piDataCur ) *piDataCur = iIdxCur;
    ++      p5 = 0;
    +     }
    +     if( aToOpen==0 || aToOpen[i+1] ){
    +       sqlite3VdbeAddOp3(v, op, iIdxCur, pIdx->tnum, iDb);
    +       sqlite3VdbeSetP4KeyInfo(pParse, pIdx);
    ++      sqlite3VdbeChangeP5(v, p5);
    +       VdbeComment((v, "%s", pIdx->zName));
    +     }
    +   }
    +@@ -103511,20 +112709,6 @@ SQLITE_API int sqlite3_xferopt_count;
    + 
    + 
    + #ifndef SQLITE_OMIT_XFER_OPT
    +-/*
    +-** Check to collation names to see if they are compatible.
    +-*/
    +-static int xferCompatibleCollation(const char *z1, const char *z2){
    +-  if( z1==0 ){
    +-    return z2==0;
    +-  }
    +-  if( z2==0 ){
    +-    return 0;
    +-  }
    +-  return sqlite3StrICmp(z1, z2)==0;
    +-}
    +-
    +-
    + /*
    + ** Check to see if index pSrc is compatible as a source of data
    + ** for index pDest in an insert transfer optimization.  The rules
    +@@ -103552,7 +112736,7 @@ static int xferCompatibleIndex(Index *pDest, Index *pSrc){
    +     }
    +     if( pSrc->aiColumn[i]==XN_EXPR ){
    +       assert( pSrc->aColExpr!=0 && pDest->aColExpr!=0 );
    +-      if( sqlite3ExprCompare(pSrc->aColExpr->a[i].pExpr,
    ++      if( sqlite3ExprCompare(0, pSrc->aColExpr->a[i].pExpr,
    +                              pDest->aColExpr->a[i].pExpr, -1)!=0 ){
    +         return 0;   /* Different expressions in the index */
    +       }
    +@@ -103560,11 +112744,11 @@ static int xferCompatibleIndex(Index *pDest, Index *pSrc){
    +     if( pSrc->aSortOrder[i]!=pDest->aSortOrder[i] ){
    +       return 0;   /* Different sort orders */
    +     }
    +-    if( !xferCompatibleCollation(pSrc->azColl[i],pDest->azColl[i]) ){
    ++    if( sqlite3_stricmp(pSrc->azColl[i],pDest->azColl[i])!=0 ){
    +       return 0;   /* Different collating sequences */
    +     }
    +   }
    +-  if( sqlite3ExprCompare(pSrc->pPartIdxWhere, pDest->pPartIdxWhere, -1) ){
    ++  if( sqlite3ExprCompare(0, pSrc->pPartIdxWhere, pDest->pPartIdxWhere, -1) ){
    +     return 0;     /* Different WHERE clauses */
    +   }
    + 
    +@@ -103633,7 +112817,7 @@ static int xferOptimization(
    +     return 0;   /* tab1 must not have triggers */
    +   }
    + #ifndef SQLITE_OMIT_VIRTUALTABLE
    +-  if( pDest->tabFlags & TF_Virtual ){
    ++  if( IsVirtual(pDest) ){
    +     return 0;   /* tab1 must not be a virtual table */
    +   }
    + #endif
    +@@ -103662,7 +112846,6 @@ static int xferOptimization(
    +   if( pSelect->pLimit ){
    +     return 0;   /* SELECT may not have a LIMIT clause */
    +   }
    +-  assert( pSelect->pOffset==0 );  /* Must be so if pLimit==0 */
    +   if( pSelect->pPrior ){
    +     return 0;   /* SELECT may not be a compound query */
    +   }
    +@@ -103675,7 +112858,7 @@ static int xferOptimization(
    +     return 0;   /* The result set must have exactly one column */
    +   }
    +   assert( pEList->a[0].pExpr );
    +-  if( pEList->a[0].pExpr->op!=TK_ALL ){
    ++  if( pEList->a[0].pExpr->op!=TK_ASTERISK ){
    +     return 0;   /* The result set must be the special operator "*" */
    +   }
    + 
    +@@ -103695,7 +112878,7 @@ static int xferOptimization(
    +     return 0;   /* source and destination must both be WITHOUT ROWID or not */
    +   }
    + #ifndef SQLITE_OMIT_VIRTUALTABLE
    +-  if( pSrc->tabFlags & TF_Virtual ){
    ++  if( IsVirtual(pSrc) ){
    +     return 0;   /* tab2 must not be a virtual table */
    +   }
    + #endif
    +@@ -103711,21 +112894,32 @@ static int xferOptimization(
    +   for(i=0; i<pDest->nCol; i++){
    +     Column *pDestCol = &pDest->aCol[i];
    +     Column *pSrcCol = &pSrc->aCol[i];
    ++#ifdef SQLITE_ENABLE_HIDDEN_COLUMNS
    ++    if( (db->mDbFlags & DBFLAG_Vacuum)==0 
    ++     && (pDestCol->colFlags | pSrcCol->colFlags) & COLFLAG_HIDDEN 
    ++    ){
    ++      return 0;    /* Neither table may have __hidden__ columns */
    ++    }
    ++#endif
    +     if( pDestCol->affinity!=pSrcCol->affinity ){
    +       return 0;    /* Affinity must be the same on all columns */
    +     }
    +-    if( !xferCompatibleCollation(pDestCol->zColl, pSrcCol->zColl) ){
    ++    if( sqlite3_stricmp(pDestCol->zColl, pSrcCol->zColl)!=0 ){
    +       return 0;    /* Collating sequence must be the same on all columns */
    +     }
    +     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 */
    ++    if( i>0 ){
    ++      assert( pDestCol->pDflt==0 || pDestCol->pDflt->op==TK_SPAN );
    ++      assert( pSrcCol->pDflt==0 || pSrcCol->pDflt->op==TK_SPAN );
    ++      if( (pDestCol->pDflt==0)!=(pSrcCol->pDflt==0) 
    ++       || (pDestCol->pDflt && strcmp(pDestCol->pDflt->u.zToken,
    ++                                       pSrcCol->pDflt->u.zToken)!=0)
    ++      ){
    ++        return 0;    /* Default values must be the same for all columns */
    ++      }
    +     }
    +   }
    +   for(pDestIdx=pDest->pIndex; pDestIdx; pDestIdx=pDestIdx->pNext){
    +@@ -103777,15 +112971,15 @@ static int xferOptimization(
    +   regRowid = sqlite3GetTempReg(pParse);
    +   sqlite3OpenTable(pParse, iDest, iDbDest, pDest, OP_OpenWrite);
    +   assert( HasRowid(pDest) || destHasUniqueIdx );
    +-  if( (db->flags & SQLITE_Vacuum)==0 && (
    ++  if( (db->mDbFlags & DBFLAG_Vacuum)==0 && (
    +       (pDest->iPKey<0 && pDest->pIndex!=0)          /* (1) */
    +    || destHasUniqueIdx                              /* (2) */
    +    || (onError!=OE_Abort && onError!=OE_Rollback)   /* (3) */
    +   )){
    +     /* In some circumstances, we are able to run the xfer optimization
    +     ** only if the destination table is initially empty. Unless the
    +-    ** SQLITE_Vacuum flag is set, this block generates code to make
    +-    ** that determination. If SQLITE_Vacuum is set, then the destination
    ++    ** DBFLAG_Vacuum flag is set, this block generates code to make
    ++    ** that determination. If DBFLAG_Vacuum is set, then the destination
    +     ** table is always empty.
    +     **
    +     ** Conditions under which the destination must be empty:
    +@@ -103804,6 +112998,7 @@ static int xferOptimization(
    +     sqlite3VdbeJumpHere(v, addr1);
    +   }
    +   if( HasRowid(pSrc) ){
    ++    u8 insFlags;
    +     sqlite3OpenTable(pParse, iSrc, iDbSrc, pSrc, OP_OpenRead);
    +     emptySrcTest = sqlite3VdbeAddOp2(v, OP_Rewind, iSrc, 0); VdbeCoverage(v);
    +     if( pDest->iPKey>=0 ){
    +@@ -103819,10 +113014,17 @@ static int xferOptimization(
    +       addr1 = sqlite3VdbeAddOp2(v, OP_Rowid, iSrc, regRowid);
    +       assert( (pDest->tabFlags & TF_Autoincrement)==0 );
    +     }
    +-    sqlite3VdbeAddOp2(v, OP_RowData, iSrc, regData);
    +-    sqlite3VdbeAddOp3(v, OP_Insert, iDest, regData, regRowid);
    +-    sqlite3VdbeChangeP5(v, OPFLAG_NCHANGE|OPFLAG_LASTROWID|OPFLAG_APPEND);
    +-    sqlite3VdbeChangeP4(v, -1, pDest->zName, 0);
    ++    sqlite3VdbeAddOp3(v, OP_RowData, iSrc, regData, 1);
    ++    if( db->mDbFlags & DBFLAG_Vacuum ){
    ++      sqlite3VdbeAddOp1(v, OP_SeekEnd, iDest);
    ++      insFlags = OPFLAG_NCHANGE|OPFLAG_LASTROWID|
    ++                           OPFLAG_APPEND|OPFLAG_USESEEKRESULT;
    ++    }else{
    ++      insFlags = OPFLAG_NCHANGE|OPFLAG_LASTROWID|OPFLAG_APPEND;
    ++    }
    ++    sqlite3VdbeAddOp4(v, OP_Insert, iDest, regData, regRowid,
    ++                      (char*)pDest, P4_TABLE);
    ++    sqlite3VdbeChangeP5(v, insFlags);
    +     sqlite3VdbeAddOp2(v, OP_Next, iSrc, addr1); VdbeCoverage(v);
    +     sqlite3VdbeAddOp2(v, OP_Close, iSrc, 0);
    +     sqlite3VdbeAddOp2(v, OP_Close, iDest, 0);
    +@@ -103844,14 +113046,14 @@ static int xferOptimization(
    +     sqlite3VdbeChangeP5(v, OPFLAG_BULKCSR);
    +     VdbeComment((v, "%s", pDestIdx->zName));
    +     addr1 = sqlite3VdbeAddOp2(v, OP_Rewind, iSrc, 0); VdbeCoverage(v);
    +-    sqlite3VdbeAddOp2(v, OP_RowKey, iSrc, regData);
    +-    if( db->flags & SQLITE_Vacuum ){
    ++    sqlite3VdbeAddOp3(v, OP_RowData, iSrc, regData, 1);
    ++    if( db->mDbFlags & DBFLAG_Vacuum ){
    +       /* This INSERT command is part of a VACUUM operation, which guarantees
    +       ** that the destination table is empty. If all indexed columns use
    +       ** collation sequence BINARY, then it can also be assumed that the
    +       ** index will be populated by inserting keys in strictly sorted 
    +       ** order. In this case, instead of seeking within the b-tree as part
    +-      ** of every OP_IdxInsert opcode, an OP_Last is added before the
    ++      ** of every OP_IdxInsert opcode, an OP_SeekEnd is added before the
    +       ** OP_IdxInsert to seek to the point within the b-tree where each key 
    +       ** should be inserted. This is faster.
    +       **
    +@@ -103861,20 +113063,19 @@ static int xferOptimization(
    +       ** a VACUUM command. In that case keys may not be written in strictly
    +       ** sorted order.  */
    +       for(i=0; i<pSrcIdx->nColumn; i++){
    +-        char *zColl = pSrcIdx->azColl[i];
    +-        assert( zColl!=0 );
    +-        if( sqlite3_stricmp("BINARY", zColl) ) break;
    ++        const char *zColl = pSrcIdx->azColl[i];
    ++        if( sqlite3_stricmp(sqlite3StrBINARY, zColl) ) break;
    +       }
    +       if( i==pSrcIdx->nColumn ){
    +         idxInsFlags = OPFLAG_USESEEKRESULT;
    +-        sqlite3VdbeAddOp3(v, OP_Last, iDest, 0, -1);
    ++        sqlite3VdbeAddOp1(v, OP_SeekEnd, iDest);
    +       }
    +     }
    +     if( !HasRowid(pSrc) && pDestIdx->idxType==2 ){
    +       idxInsFlags |= OPFLAG_NCHANGE;
    +     }
    +-    sqlite3VdbeAddOp3(v, OP_IdxInsert, iDest, regData, 1);
    +-    sqlite3VdbeChangeP5(v, idxInsFlags);
    ++    sqlite3VdbeAddOp2(v, OP_IdxInsert, iDest, regData);
    ++    sqlite3VdbeChangeP5(v, idxInsFlags|OPFLAG_APPEND);
    +     sqlite3VdbeAddOp2(v, OP_Next, iSrc, addr1+1); VdbeCoverage(v);
    +     sqlite3VdbeJumpHere(v, addr1);
    +     sqlite3VdbeAddOp2(v, OP_Close, iSrc, 0);
    +@@ -103884,6 +113085,7 @@ static int xferOptimization(
    +   sqlite3ReleaseTempReg(pParse, regRowid);
    +   sqlite3ReleaseTempReg(pParse, regData);
    +   if( emptyDestTest ){
    ++    sqlite3AutoincrementEnd(pParse);
    +     sqlite3VdbeAddOp2(v, OP_Halt, SQLITE_OK, 0);
    +     sqlite3VdbeJumpHere(v, emptyDestTest);
    +     sqlite3VdbeAddOp2(v, OP_Close, iDest, 0);
    +@@ -103925,7 +113127,7 @@ static int xferOptimization(
    + ** argument to xCallback().  If xCallback=NULL then no callback
    + ** is invoked, even for queries.
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_exec(
    ++SQLITE_API int sqlite3_exec(
    +   sqlite3 *db,                /* The database on which the SQL executes */
    +   const char *zSql,           /* The SQL to be executed */
    +   sqlite3_callback xCallback, /* Invoke this callback routine */
    +@@ -103971,7 +113173,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_exec(
    +           (SQLITE_DONE==rc && !callbackIsInit
    +                            && db->flags&SQLITE_NullCallback)) ){
    +         if( !callbackIsInit ){
    +-          azCols = sqlite3DbMallocZero(db, 2*nCol*sizeof(const char*) + 1);
    ++          azCols = sqlite3DbMallocRaw(db, (2*nCol+1)*sizeof(const char*));
    +           if( azCols==0 ){
    +             goto exec_out;
    +           }
    +@@ -103988,10 +113190,11 @@ SQLITE_API int SQLITE_STDCALL sqlite3_exec(
    +           for(i=0; i<nCol; i++){
    +             azVals[i] = (char *)sqlite3_column_text(pStmt, i);
    +             if( !azVals[i] && sqlite3_column_type(pStmt, i)!=SQLITE_NULL ){
    +-              db->mallocFailed = 1;
    ++              sqlite3OomFault(db);
    +               goto exec_out;
    +             }
    +           }
    ++          azVals[i] = 0;
    +         }
    +         if( xCallback(pArg, nCol, azVals, azCols) ){
    +           /* EVIDENCE-OF: R-38229-40159 If the callback function to
    +@@ -104024,12 +113227,9 @@ exec_out:
    + 
    +   rc = sqlite3ApiExit(db, rc);
    +   if( rc!=SQLITE_OK && pzErrMsg ){
    +-    int nErrMsg = 1 + sqlite3Strlen30(sqlite3_errmsg(db));
    +-    *pzErrMsg = sqlite3Malloc(nErrMsg);
    +-    if( *pzErrMsg ){
    +-      memcpy(*pzErrMsg, sqlite3_errmsg(db), nErrMsg);
    +-    }else{
    +-      rc = SQLITE_NOMEM;
    ++    *pzErrMsg = sqlite3DbStrDup(0, sqlite3_errmsg(db));
    ++    if( *pzErrMsg==0 ){
    ++      rc = SQLITE_NOMEM_BKPT;
    +       sqlite3Error(db, SQLITE_NOMEM);
    +     }
    +   }else if( pzErrMsg ){
    +@@ -104080,12 +113280,10 @@ exec_out:
    + ** as extensions by SQLite should #include this file instead of 
    + ** sqlite3.h.
    + */
    +-#ifndef _SQLITE3EXT_H_
    +-#define _SQLITE3EXT_H_
    ++#ifndef SQLITE3EXT_H
    ++#define SQLITE3EXT_H
    + /* #include "sqlite3.h" */
    + 
    +-typedef struct sqlite3_api_routines sqlite3_api_routines;
    +-
    + /*
    + ** The following structure holds pointers to all of the SQLite API
    + ** routines.
    +@@ -104201,7 +113399,7 @@ struct sqlite3_api_routines {
    +   int  (*set_authorizer)(sqlite3*,int(*)(void*,int,const char*,const char*,
    +                          const char*,const char*),void*);
    +   void  (*set_auxdata)(sqlite3_context*,int,void*,void (*)(void*));
    +-  char * (*snprintf)(int,char*,const char*,...);
    ++  char * (*xsnprintf)(int,char*,const char*,...);
    +   int  (*step)(sqlite3_stmt*);
    +   int  (*table_column_metadata)(sqlite3*,const char*,const char*,const char*,
    +                                 char const**,char const**,int*,int*,int*);
    +@@ -104313,7 +113511,7 @@ struct sqlite3_api_routines {
    +   int (*uri_boolean)(const char*,const char*,int);
    +   sqlite3_int64 (*uri_int64)(const char*,const char*,sqlite3_int64);
    +   const char *(*uri_parameter)(const char*,const char*);
    +-  char *(*vsnprintf)(int,char*,const char*,va_list);
    ++  char *(*xvsnprintf)(int,char*,const char*,va_list);
    +   int (*wal_checkpoint_v2)(sqlite3*,const char*,int,int*,int*);
    +   /* Version 3.8.7 and later */
    +   int (*auto_extension)(void(*)(void));
    +@@ -104340,8 +113538,40 @@ struct sqlite3_api_routines {
    +   /* Version 3.9.0 and later */
    +   unsigned int (*value_subtype)(sqlite3_value*);
    +   void (*result_subtype)(sqlite3_context*,unsigned int);
    ++  /* Version 3.10.0 and later */
    ++  int (*status64)(int,sqlite3_int64*,sqlite3_int64*,int);
    ++  int (*strlike)(const char*,const char*,unsigned int);
    ++  int (*db_cacheflush)(sqlite3*);
    ++  /* Version 3.12.0 and later */
    ++  int (*system_errno)(sqlite3*);
    ++  /* Version 3.14.0 and later */
    ++  int (*trace_v2)(sqlite3*,unsigned,int(*)(unsigned,void*,void*,void*),void*);
    ++  char *(*expanded_sql)(sqlite3_stmt*);
    ++  /* Version 3.18.0 and later */
    ++  void (*set_last_insert_rowid)(sqlite3*,sqlite3_int64);
    ++  /* Version 3.20.0 and later */
    ++  int (*prepare_v3)(sqlite3*,const char*,int,unsigned int,
    ++                    sqlite3_stmt**,const char**);
    ++  int (*prepare16_v3)(sqlite3*,const void*,int,unsigned int,
    ++                      sqlite3_stmt**,const void**);
    ++  int (*bind_pointer)(sqlite3_stmt*,int,void*,const char*,void(*)(void*));
    ++  void (*result_pointer)(sqlite3_context*,void*,const char*,void(*)(void*));
    ++  void *(*value_pointer)(sqlite3_value*,const char*);
    ++  int (*vtab_nochange)(sqlite3_context*);
    ++  int (*value_nochange)(sqlite3_value*);
    ++  const char *(*vtab_collation)(sqlite3_index_info*,int);
    + };
    + 
    ++/*
    ++** This is the function signature used for all extension entry points.  It
    ++** is also defined in the file "loadext.c".
    ++*/
    ++typedef int (*sqlite3_loadext_entry)(
    ++  sqlite3 *db,                       /* Handle to the database. */
    ++  char **pzErrMsg,                   /* Used to set error string on failure. */
    ++  const sqlite3_api_routines *pThunk /* Extension API function pointers. */
    ++);
    ++
    + /*
    + ** The following macros redefine the API routines so that they are
    + ** redirected through the global sqlite3_api structure.
    +@@ -104456,7 +113686,7 @@ struct sqlite3_api_routines {
    + #define sqlite3_rollback_hook          sqlite3_api->rollback_hook
    + #define sqlite3_set_authorizer         sqlite3_api->set_authorizer
    + #define sqlite3_set_auxdata            sqlite3_api->set_auxdata
    +-#define sqlite3_snprintf               sqlite3_api->snprintf
    ++#define sqlite3_snprintf               sqlite3_api->xsnprintf
    + #define sqlite3_step                   sqlite3_api->step
    + #define sqlite3_table_column_metadata  sqlite3_api->table_column_metadata
    + #define sqlite3_thread_cleanup         sqlite3_api->thread_cleanup
    +@@ -104480,7 +113710,7 @@ struct sqlite3_api_routines {
    + #define sqlite3_value_text16le         sqlite3_api->value_text16le
    + #define sqlite3_value_type             sqlite3_api->value_type
    + #define sqlite3_vmprintf               sqlite3_api->vmprintf
    +-#define sqlite3_vsnprintf              sqlite3_api->vsnprintf
    ++#define sqlite3_vsnprintf              sqlite3_api->xvsnprintf
    + #define sqlite3_overload_function      sqlite3_api->overload_function
    + #define sqlite3_prepare_v2             sqlite3_api->prepare_v2
    + #define sqlite3_prepare16_v2           sqlite3_api->prepare16_v2
    +@@ -104556,7 +113786,7 @@ struct sqlite3_api_routines {
    + #define sqlite3_uri_boolean            sqlite3_api->uri_boolean
    + #define sqlite3_uri_int64              sqlite3_api->uri_int64
    + #define sqlite3_uri_parameter          sqlite3_api->uri_parameter
    +-#define sqlite3_uri_vsnprintf          sqlite3_api->vsnprintf
    ++#define sqlite3_uri_vsnprintf          sqlite3_api->xvsnprintf
    + #define sqlite3_wal_checkpoint_v2      sqlite3_api->wal_checkpoint_v2
    + /* Version 3.8.7 and later */
    + #define sqlite3_auto_extension         sqlite3_api->auto_extension
    +@@ -104579,6 +113809,27 @@ struct sqlite3_api_routines {
    + /* Version 3.9.0 and later */
    + #define sqlite3_value_subtype          sqlite3_api->value_subtype
    + #define sqlite3_result_subtype         sqlite3_api->result_subtype
    ++/* Version 3.10.0 and later */
    ++#define sqlite3_status64               sqlite3_api->status64
    ++#define sqlite3_strlike                sqlite3_api->strlike
    ++#define sqlite3_db_cacheflush          sqlite3_api->db_cacheflush
    ++/* Version 3.12.0 and later */
    ++#define sqlite3_system_errno           sqlite3_api->system_errno
    ++/* Version 3.14.0 and later */
    ++#define sqlite3_trace_v2               sqlite3_api->trace_v2
    ++#define sqlite3_expanded_sql           sqlite3_api->expanded_sql
    ++/* Version 3.18.0 and later */
    ++#define sqlite3_set_last_insert_rowid  sqlite3_api->set_last_insert_rowid
    ++/* Version 3.20.0 and later */
    ++#define sqlite3_prepare_v3             sqlite3_api->prepare_v3
    ++#define sqlite3_prepare16_v3           sqlite3_api->prepare16_v3
    ++#define sqlite3_bind_pointer           sqlite3_api->bind_pointer
    ++#define sqlite3_result_pointer         sqlite3_api->result_pointer
    ++#define sqlite3_value_pointer          sqlite3_api->value_pointer
    ++/* Version 3.22.0 and later */
    ++#define sqlite3_vtab_nochange          sqlite3_api->vtab_nochange
    ++#define sqlite3_value_nochange         sqltie3_api->value_nochange
    ++#define sqlite3_vtab_collation         sqltie3_api->vtab_collation
    + #endif /* !defined(SQLITE_CORE) && !defined(SQLITE_OMIT_LOAD_EXTENSION) */
    + 
    + #if !defined(SQLITE_CORE) && !defined(SQLITE_OMIT_LOAD_EXTENSION)
    +@@ -104596,15 +113847,13 @@ struct sqlite3_api_routines {
    + # define SQLITE_EXTENSION_INIT3     /*no-op*/
    + #endif
    + 
    +-#endif /* _SQLITE3EXT_H_ */
    ++#endif /* SQLITE3EXT_H */
    + 
    + /************** End of sqlite3ext.h ******************************************/
    + /************** Continuing where we left off in loadext.c ********************/
    + /* #include "sqliteInt.h" */
    +-/* #include <string.h> */
    + 
    + #ifndef SQLITE_OMIT_LOAD_EXTENSION
    +-
    + /*
    + ** Some API routines are omitted when various features are
    + ** excluded from a build of SQLite.  Substitute a NULL pointer
    +@@ -104636,6 +113885,7 @@ struct sqlite3_api_routines {
    + # define sqlite3_open16                 0
    + # define sqlite3_prepare16              0
    + # define sqlite3_prepare16_v2           0
    ++# define sqlite3_prepare16_v3           0
    + # define sqlite3_result_error16         0
    + # define sqlite3_result_text16          0
    + # define sqlite3_result_text16be        0
    +@@ -104674,7 +113924,7 @@ struct sqlite3_api_routines {
    + # define sqlite3_enable_shared_cache 0
    + #endif
    + 
    +-#ifdef SQLITE_OMIT_TRACE
    ++#if defined(SQLITE_OMIT_TRACE) || defined(SQLITE_OMIT_DEPRECATED)
    + # define sqlite3_profile       0
    + # define sqlite3_trace         0
    + #endif
    +@@ -104694,6 +113944,10 @@ struct sqlite3_api_routines {
    + #define sqlite3_blob_reopen    0
    + #endif
    + 
    ++#if defined(SQLITE_OMIT_TRACE)
    ++# define sqlite3_trace_v2      0
    ++#endif
    ++
    + /*
    + ** The following structure contains pointers to all SQLite API routines.
    + ** A pointer to this structure is passed into extensions when they are
    +@@ -104993,7 +114247,28 @@ static const sqlite3_api_routines sqlite3Apis = {
    +   sqlite3_bind_zeroblob64,
    +   /* Version 3.9.0 and later */
    +   sqlite3_value_subtype,
    +-  sqlite3_result_subtype
    ++  sqlite3_result_subtype,
    ++  /* Version 3.10.0 and later */
    ++  sqlite3_status64,
    ++  sqlite3_strlike,
    ++  sqlite3_db_cacheflush,
    ++  /* Version 3.12.0 and later */
    ++  sqlite3_system_errno,
    ++  /* Version 3.14.0 and later */
    ++  sqlite3_trace_v2,
    ++  sqlite3_expanded_sql,
    ++  /* Version 3.18.0 and later */
    ++  sqlite3_set_last_insert_rowid,
    ++  /* Version 3.20.0 and later */
    ++  sqlite3_prepare_v3,
    ++  sqlite3_prepare16_v3,
    ++  sqlite3_bind_pointer,
    ++  sqlite3_result_pointer,
    ++  sqlite3_value_pointer,
    ++  /* Version 3.22.0 and later */
    ++  sqlite3_vtab_nochange,
    ++  sqlite3_value_nochange,
    ++  sqlite3_vtab_collation
    + };
    + 
    + /*
    +@@ -105016,13 +114291,14 @@ static int sqlite3LoadExtension(
    + ){
    +   sqlite3_vfs *pVfs = db->pVfs;
    +   void *handle;
    +-  int (*xInit)(sqlite3*,char**,const sqlite3_api_routines*);
    ++  sqlite3_loadext_entry xInit;
    +   char *zErrmsg = 0;
    +   const char *zEntry;
    +   char *zAltEntry = 0;
    +   void **aHandle;
    +   u64 nMsg = 300 + sqlite3Strlen30(zFile);
    +   int ii;
    ++  int rc;
    + 
    +   /* Shared library endings to try if zFile cannot be loaded as written */
    +   static const char *azEndings[] = {
    +@@ -105041,8 +114317,9 @@ static int sqlite3LoadExtension(
    +   /* Ticket #1863.  To avoid a creating security problems for older
    +   ** applications that relink against newer versions of SQLite, the
    +   ** ability to run load_extension is turned off by default.  One
    +-  ** must call sqlite3_enable_load_extension() to turn on extension
    +-  ** loading.  Otherwise you get the following error.
    ++  ** must call either sqlite3_enable_load_extension(db) or
    ++  ** sqlite3_db_config(db, SQLITE_DBCONFIG_ENABLE_LOAD_EXTENSION, 1, 0)
    ++  ** to turn on extension loading.
    +   */
    +   if( (db->flags & SQLITE_LoadExtension)==0 ){
    +     if( pzErrMsg ){
    +@@ -105057,8 +114334,10 @@ static int sqlite3LoadExtension(
    + #if SQLITE_OS_UNIX || SQLITE_OS_WIN
    +   for(ii=0; ii<ArraySize(azEndings) && handle==0; ii++){
    +     char *zAltFile = sqlite3_mprintf("%s.%s", zFile, azEndings[ii]);
    +-    if( zAltFile==0 ) return SQLITE_NOMEM;
    +-    handle = sqlite3OsDlOpen(pVfs, zAltFile);
    ++    int bExists = 0;
    ++    if( zAltFile==0 ) return SQLITE_NOMEM_BKPT;
    ++    sqlite3OsAccess(pVfs, zAltFile, SQLITE_ACCESS_EXISTS, &bExists);
    ++    if( bExists )  handle = sqlite3OsDlOpen(pVfs, zAltFile);
    +     sqlite3_free(zAltFile);
    +   }
    + #endif
    +@@ -105073,8 +114352,7 @@ static int sqlite3LoadExtension(
    +     }
    +     return SQLITE_ERROR;
    +   }
    +-  xInit = (int(*)(sqlite3*,char**,const sqlite3_api_routines*))
    +-                   sqlite3OsDlSym(pVfs, handle, zEntry);
    ++  xInit = (sqlite3_loadext_entry)sqlite3OsDlSym(pVfs, handle, zEntry);
    + 
    +   /* If no entry point was specified and the default legacy
    +   ** entry point name "sqlite3_extension_init" was not found, then
    +@@ -105093,7 +114371,7 @@ static int sqlite3LoadExtension(
    +     zAltEntry = sqlite3_malloc64(ncFile+30);
    +     if( zAltEntry==0 ){
    +       sqlite3OsDlClose(pVfs, handle);
    +-      return SQLITE_NOMEM;
    ++      return SQLITE_NOMEM_BKPT;
    +     }
    +     memcpy(zAltEntry, "sqlite3_", 8);
    +     for(iFile=ncFile-1; iFile>=0 && zFile[iFile]!='/'; iFile--){}
    +@@ -105106,8 +114384,7 @@ static int sqlite3LoadExtension(
    +     }
    +     memcpy(zAltEntry+iEntry, "_init", 6);
    +     zEntry = zAltEntry;
    +-    xInit = (int(*)(sqlite3*,char**,const sqlite3_api_routines*))
    +-                     sqlite3OsDlSym(pVfs, handle, zEntry);
    ++    xInit = (sqlite3_loadext_entry)sqlite3OsDlSym(pVfs, handle, zEntry);
    +   }
    +   if( xInit==0 ){
    +     if( pzErrMsg ){
    +@@ -105124,7 +114401,9 @@ static int sqlite3LoadExtension(
    +     return SQLITE_ERROR;
    +   }
    +   sqlite3_free(zAltEntry);
    +-  if( xInit(db, &zErrmsg, &sqlite3Apis) ){
    ++  rc = xInit(db, &zErrmsg, &sqlite3Apis);
    ++  if( rc ){
    ++    if( rc==SQLITE_OK_LOAD_PERMANENTLY ) return SQLITE_OK;
    +     if( pzErrMsg ){
    +       *pzErrMsg = sqlite3_mprintf("error during initialization: %s", zErrmsg);
    +     }
    +@@ -105136,7 +114415,7 @@ static int sqlite3LoadExtension(
    +   /* Append the new shared library handle to the db->aExtension array. */
    +   aHandle = sqlite3DbMallocZero(db, sizeof(handle)*(db->nExtension+1));
    +   if( aHandle==0 ){
    +-    return SQLITE_NOMEM;
    ++    return SQLITE_NOMEM_BKPT;
    +   }
    +   if( db->nExtension>0 ){
    +     memcpy(aHandle, db->aExtension, sizeof(handle)*db->nExtension);
    +@@ -105147,7 +114426,7 @@ static int sqlite3LoadExtension(
    +   db->aExtension[db->nExtension++] = handle;
    +   return SQLITE_OK;
    + }
    +-SQLITE_API int SQLITE_STDCALL sqlite3_load_extension(
    ++SQLITE_API int sqlite3_load_extension(
    +   sqlite3 *db,          /* Load the extension into this database connection */
    +   const char *zFile,    /* Name of the shared library containing extension */
    +   const char *zProc,    /* Entry point.  Use "sqlite3_extension_init" if 0 */
    +@@ -105178,29 +114457,18 @@ SQLITE_PRIVATE void sqlite3CloseExtensions(sqlite3 *db){
    + ** Enable or disable extension loading.  Extension loading is disabled by
    + ** default so as not to open security holes in older applications.
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_enable_load_extension(sqlite3 *db, int onoff){
    ++SQLITE_API int sqlite3_enable_load_extension(sqlite3 *db, int onoff){
    +   sqlite3_mutex_enter(db->mutex);
    +   if( onoff ){
    +-    db->flags |= SQLITE_LoadExtension;
    ++    db->flags |= SQLITE_LoadExtension|SQLITE_LoadExtFunc;
    +   }else{
    +-    db->flags &= ~SQLITE_LoadExtension;
    ++    db->flags &= ~(SQLITE_LoadExtension|SQLITE_LoadExtFunc);
    +   }
    +   sqlite3_mutex_leave(db->mutex);
    +   return SQLITE_OK;
    + }
    + 
    +-#endif /* SQLITE_OMIT_LOAD_EXTENSION */
    +-
    +-/*
    +-** The auto-extension code added regardless of whether or not extension
    +-** loading is supported.  We need a dummy sqlite3Apis pointer for that
    +-** code if regular extension loading is not available.  This is that
    +-** dummy pointer.
    +-*/
    +-#ifdef SQLITE_OMIT_LOAD_EXTENSION
    +-static const sqlite3_api_routines sqlite3Apis;
    +-#endif
    +-
    ++#endif /* !defined(SQLITE_OMIT_LOAD_EXTENSION) */
    + 
    + /*
    + ** The following object holds the list of automatically loaded
    +@@ -105235,7 +114503,9 @@ static SQLITE_WSD struct sqlite3AutoExtList {
    + ** Register a statically linked extension that is automatically
    + ** loaded by every new database connection.
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_auto_extension(void (*xInit)(void)){
    ++SQLITE_API int sqlite3_auto_extension(
    ++  void (*xInit)(void)
    ++){
    +   int rc = SQLITE_OK;
    + #ifndef SQLITE_OMIT_AUTOINIT
    +   rc = sqlite3_initialize();
    +@@ -105258,7 +114528,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_auto_extension(void (*xInit)(void)){
    +       void (**aNew)(void);
    +       aNew = sqlite3_realloc64(wsdAutoext.aExt, nByte);
    +       if( aNew==0 ){
    +-        rc = SQLITE_NOMEM;
    ++        rc = SQLITE_NOMEM_BKPT;
    +       }else{
    +         wsdAutoext.aExt = aNew;
    +         wsdAutoext.aExt[wsdAutoext.nExt] = xInit;
    +@@ -105280,7 +114550,9 @@ SQLITE_API int SQLITE_STDCALL sqlite3_auto_extension(void (*xInit)(void)){
    + ** Return 1 if xInit was found on the list and removed.  Return 0 if xInit
    + ** was not on the list.
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_cancel_auto_extension(void (*xInit)(void)){
    ++SQLITE_API int sqlite3_cancel_auto_extension(
    ++  void (*xInit)(void)
    ++){
    + #if SQLITE_THREADSAFE
    +   sqlite3_mutex *mutex = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MASTER);
    + #endif
    +@@ -105303,7 +114575,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_cancel_auto_extension(void (*xInit)(void))
    + /*
    + ** Reset the automatic extension loading mechanism.
    + */
    +-SQLITE_API void SQLITE_STDCALL sqlite3_reset_auto_extension(void){
    ++SQLITE_API void sqlite3_reset_auto_extension(void){
    + #ifndef SQLITE_OMIT_AUTOINIT
    +   if( sqlite3_initialize()==SQLITE_OK )
    + #endif
    +@@ -105329,7 +114601,7 @@ SQLITE_PRIVATE void sqlite3AutoLoadExtensions(sqlite3 *db){
    +   u32 i;
    +   int go = 1;
    +   int rc;
    +-  int (*xInit)(sqlite3*,char**,const sqlite3_api_routines*);
    ++  sqlite3_loadext_entry xInit;
    + 
    +   wsdAutoextInit;
    +   if( wsdAutoext.nExt==0 ){
    +@@ -105340,18 +114612,22 @@ SQLITE_PRIVATE void sqlite3AutoLoadExtensions(sqlite3 *db){
    +     char *zErrmsg;
    + #if SQLITE_THREADSAFE
    +     sqlite3_mutex *mutex = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MASTER);
    ++#endif
    ++#ifdef SQLITE_OMIT_LOAD_EXTENSION
    ++    const sqlite3_api_routines *pThunk = 0;
    ++#else
    ++    const sqlite3_api_routines *pThunk = &sqlite3Apis;
    + #endif
    +     sqlite3_mutex_enter(mutex);
    +     if( i>=wsdAutoext.nExt ){
    +       xInit = 0;
    +       go = 0;
    +     }else{
    +-      xInit = (int(*)(sqlite3*,char**,const sqlite3_api_routines*))
    +-              wsdAutoext.aExt[i];
    ++      xInit = (sqlite3_loadext_entry)wsdAutoext.aExt[i];
    +     }
    +     sqlite3_mutex_leave(mutex);
    +     zErrmsg = 0;
    +-    if( xInit && (rc = xInit(db, &zErrmsg, &sqlite3Apis))!=0 ){
    ++    if( xInit && (rc = xInit(db, &zErrmsg, pThunk))!=0 ){
    +       sqlite3ErrorWithMsg(db, rc,
    +             "automatic extension loading failed: %s", zErrmsg);
    +       go = 0;
    +@@ -105399,472 +114675,658 @@ SQLITE_PRIVATE void sqlite3AutoLoadExtensions(sqlite3 *db){
    + ** ../tool/mkpragmatab.tcl.  To update the set of pragmas, edit
    + ** that script and rerun it.
    + */
    ++
    ++/* The various pragma types */
    + #define PragTyp_HEADER_VALUE                   0
    + #define PragTyp_AUTO_VACUUM                    1
    + #define PragTyp_FLAG                           2
    + #define PragTyp_BUSY_TIMEOUT                   3
    + #define PragTyp_CACHE_SIZE                     4
    +-#define PragTyp_CASE_SENSITIVE_LIKE            5
    +-#define PragTyp_COLLATION_LIST                 6
    +-#define PragTyp_COMPILE_OPTIONS                7
    +-#define PragTyp_DATA_STORE_DIRECTORY           8
    +-#define PragTyp_DATABASE_LIST                  9
    +-#define PragTyp_DEFAULT_CACHE_SIZE            10
    +-#define PragTyp_ENCODING                      11
    +-#define PragTyp_FOREIGN_KEY_CHECK             12
    +-#define PragTyp_FOREIGN_KEY_LIST              13
    +-#define PragTyp_INCREMENTAL_VACUUM            14
    +-#define PragTyp_INDEX_INFO                    15
    +-#define PragTyp_INDEX_LIST                    16
    +-#define PragTyp_INTEGRITY_CHECK               17
    +-#define PragTyp_JOURNAL_MODE                  18
    +-#define PragTyp_JOURNAL_SIZE_LIMIT            19
    +-#define PragTyp_LOCK_PROXY_FILE               20
    +-#define PragTyp_LOCKING_MODE                  21
    +-#define PragTyp_PAGE_COUNT                    22
    +-#define PragTyp_MMAP_SIZE                     23
    +-#define PragTyp_PAGE_SIZE                     24
    +-#define PragTyp_SECURE_DELETE                 25
    +-#define PragTyp_SHRINK_MEMORY                 26
    +-#define PragTyp_SOFT_HEAP_LIMIT               27
    +-#define PragTyp_STATS                         28
    +-#define PragTyp_SYNCHRONOUS                   29
    +-#define PragTyp_TABLE_INFO                    30
    +-#define PragTyp_TEMP_STORE                    31
    +-#define PragTyp_TEMP_STORE_DIRECTORY          32
    +-#define PragTyp_THREADS                       33
    +-#define PragTyp_WAL_AUTOCHECKPOINT            34
    +-#define PragTyp_WAL_CHECKPOINT                35
    +-#define PragTyp_ACTIVATE_EXTENSIONS           36
    +-#define PragTyp_HEXKEY                        37
    +-#define PragTyp_KEY                           38
    +-#define PragTyp_REKEY                         39
    +-#define PragTyp_LOCK_STATUS                   40
    +-#define PragTyp_PARSER_TRACE                  41
    +-#define PragFlag_NeedSchema           0x01
    +-#define PragFlag_ReadOnly             0x02
    +-static const struct sPragmaNames {
    +-  const char *const zName;  /* Name of pragma */
    +-  u8 ePragTyp;              /* PragTyp_XXX value */
    +-  u8 mPragFlag;             /* Zero or more PragFlag_XXX values */
    +-  u32 iArg;                 /* Extra argument */
    +-} aPragmaNames[] = {
    ++#define PragTyp_CACHE_SPILL                    5
    ++#define PragTyp_CASE_SENSITIVE_LIKE            6
    ++#define PragTyp_COLLATION_LIST                 7
    ++#define PragTyp_COMPILE_OPTIONS                8
    ++#define PragTyp_DATA_STORE_DIRECTORY           9
    ++#define PragTyp_DATABASE_LIST                 10
    ++#define PragTyp_DEFAULT_CACHE_SIZE            11
    ++#define PragTyp_ENCODING                      12
    ++#define PragTyp_FOREIGN_KEY_CHECK             13
    ++#define PragTyp_FOREIGN_KEY_LIST              14
    ++#define PragTyp_FUNCTION_LIST                 15
    ++#define PragTyp_INCREMENTAL_VACUUM            16
    ++#define PragTyp_INDEX_INFO                    17
    ++#define PragTyp_INDEX_LIST                    18
    ++#define PragTyp_INTEGRITY_CHECK               19
    ++#define PragTyp_JOURNAL_MODE                  20
    ++#define PragTyp_JOURNAL_SIZE_LIMIT            21
    ++#define PragTyp_LOCK_PROXY_FILE               22
    ++#define PragTyp_LOCKING_MODE                  23
    ++#define PragTyp_PAGE_COUNT                    24
    ++#define PragTyp_MMAP_SIZE                     25
    ++#define PragTyp_MODULE_LIST                   26
    ++#define PragTyp_OPTIMIZE                      27
    ++#define PragTyp_PAGE_SIZE                     28
    ++#define PragTyp_PRAGMA_LIST                   29
    ++#define PragTyp_SECURE_DELETE                 30
    ++#define PragTyp_SHRINK_MEMORY                 31
    ++#define PragTyp_SOFT_HEAP_LIMIT               32
    ++#define PragTyp_SYNCHRONOUS                   33
    ++#define PragTyp_TABLE_INFO                    34
    ++#define PragTyp_TEMP_STORE                    35
    ++#define PragTyp_TEMP_STORE_DIRECTORY          36
    ++#define PragTyp_THREADS                       37
    ++#define PragTyp_WAL_AUTOCHECKPOINT            38
    ++#define PragTyp_WAL_CHECKPOINT                39
    ++#define PragTyp_ACTIVATE_EXTENSIONS           40
    ++#define PragTyp_HEXKEY                        41
    ++#define PragTyp_KEY                           42
    ++#define PragTyp_REKEY                         43
    ++#define PragTyp_LOCK_STATUS                   44
    ++#define PragTyp_PARSER_TRACE                  45
    ++#define PragTyp_STATS                         46
    ++
    ++/* Property flags associated with various pragma. */
    ++#define PragFlg_NeedSchema 0x01 /* Force schema load before running */
    ++#define PragFlg_NoColumns  0x02 /* OP_ResultRow called with zero columns */
    ++#define PragFlg_NoColumns1 0x04 /* zero columns if RHS argument is present */
    ++#define PragFlg_ReadOnly   0x08 /* Read-only HEADER_VALUE */
    ++#define PragFlg_Result0    0x10 /* Acts as query when no argument */
    ++#define PragFlg_Result1    0x20 /* Acts as query when has one argument */
    ++#define PragFlg_SchemaOpt  0x40 /* Schema restricts name search if present */
    ++#define PragFlg_SchemaReq  0x80 /* Schema required - "main" is default */
    ++
    ++/* Names of columns for pragmas that return multi-column result
    ++** or that return single-column results where the name of the
    ++** result column is different from the name of the pragma
    ++*/
    ++static const char *const pragCName[] = {
    ++  /*   0 */ "cache_size",  /* Used by: default_cache_size */
    ++  /*   1 */ "cid",         /* Used by: table_info */
    ++  /*   2 */ "name",       
    ++  /*   3 */ "type",       
    ++  /*   4 */ "notnull",    
    ++  /*   5 */ "dflt_value", 
    ++  /*   6 */ "pk",         
    ++  /*   7 */ "tbl",         /* Used by: stats */
    ++  /*   8 */ "idx",        
    ++  /*   9 */ "wdth",       
    ++  /*  10 */ "hght",       
    ++  /*  11 */ "flgs",       
    ++  /*  12 */ "seqno",       /* Used by: index_info */
    ++  /*  13 */ "cid",        
    ++  /*  14 */ "name",       
    ++  /*  15 */ "seqno",       /* Used by: index_xinfo */
    ++  /*  16 */ "cid",        
    ++  /*  17 */ "name",       
    ++  /*  18 */ "desc",       
    ++  /*  19 */ "coll",       
    ++  /*  20 */ "key",        
    ++  /*  21 */ "seq",         /* Used by: index_list */
    ++  /*  22 */ "name",       
    ++  /*  23 */ "unique",     
    ++  /*  24 */ "origin",     
    ++  /*  25 */ "partial",    
    ++  /*  26 */ "seq",         /* Used by: database_list */
    ++  /*  27 */ "name",       
    ++  /*  28 */ "file",       
    ++  /*  29 */ "name",        /* Used by: function_list */
    ++  /*  30 */ "builtin",    
    ++  /*  31 */ "name",        /* Used by: module_list pragma_list */
    ++  /*  32 */ "seq",         /* Used by: collation_list */
    ++  /*  33 */ "name",       
    ++  /*  34 */ "id",          /* Used by: foreign_key_list */
    ++  /*  35 */ "seq",        
    ++  /*  36 */ "table",      
    ++  /*  37 */ "from",       
    ++  /*  38 */ "to",         
    ++  /*  39 */ "on_update",  
    ++  /*  40 */ "on_delete",  
    ++  /*  41 */ "match",      
    ++  /*  42 */ "table",       /* Used by: foreign_key_check */
    ++  /*  43 */ "rowid",      
    ++  /*  44 */ "parent",     
    ++  /*  45 */ "fkid",       
    ++  /*  46 */ "busy",        /* Used by: wal_checkpoint */
    ++  /*  47 */ "log",        
    ++  /*  48 */ "checkpointed",
    ++  /*  49 */ "timeout",     /* Used by: busy_timeout */
    ++  /*  50 */ "database",    /* Used by: lock_status */
    ++  /*  51 */ "status",     
    ++};
    ++
    ++/* Definitions of all built-in pragmas */
    ++typedef struct PragmaName {
    ++  const char *const zName; /* Name of pragma */
    ++  u8 ePragTyp;             /* PragTyp_XXX value */
    ++  u8 mPragFlg;             /* Zero or more PragFlg_XXX values */
    ++  u8 iPragCName;           /* Start of column names in pragCName[] */
    ++  u8 nPragCName;           /* Num of col names. 0 means use pragma name */
    ++  u32 iArg;                /* Extra argument */
    ++} PragmaName;
    ++static const PragmaName aPragmaName[] = {
    + #if defined(SQLITE_HAS_CODEC) || defined(SQLITE_ENABLE_CEROD)
    +-  { /* zName:     */ "activate_extensions",
    +-    /* ePragTyp:  */ PragTyp_ACTIVATE_EXTENSIONS,
    +-    /* ePragFlag: */ 0,
    +-    /* iArg:      */ 0 },
    ++ {/* zName:     */ "activate_extensions",
    ++  /* ePragTyp:  */ PragTyp_ACTIVATE_EXTENSIONS,
    ++  /* ePragFlg:  */ 0,
    ++  /* ColNames:  */ 0, 0,
    ++  /* iArg:      */ 0 },
    + #endif
    + #if !defined(SQLITE_OMIT_SCHEMA_VERSION_PRAGMAS)
    +-  { /* zName:     */ "application_id",
    +-    /* ePragTyp:  */ PragTyp_HEADER_VALUE,
    +-    /* ePragFlag: */ 0,
    +-    /* iArg:      */ BTREE_APPLICATION_ID },
    ++ {/* zName:     */ "application_id",
    ++  /* ePragTyp:  */ PragTyp_HEADER_VALUE,
    ++  /* ePragFlg:  */ PragFlg_NoColumns1|PragFlg_Result0,
    ++  /* ColNames:  */ 0, 0,
    ++  /* iArg:      */ BTREE_APPLICATION_ID },
    + #endif
    + #if !defined(SQLITE_OMIT_AUTOVACUUM)
    +-  { /* zName:     */ "auto_vacuum",
    +-    /* ePragTyp:  */ PragTyp_AUTO_VACUUM,
    +-    /* ePragFlag: */ PragFlag_NeedSchema,
    +-    /* iArg:      */ 0 },
    ++ {/* zName:     */ "auto_vacuum",
    ++  /* ePragTyp:  */ PragTyp_AUTO_VACUUM,
    ++  /* ePragFlg:  */ PragFlg_NeedSchema|PragFlg_Result0|PragFlg_SchemaReq|PragFlg_NoColumns1,
    ++  /* ColNames:  */ 0, 0,
    ++  /* iArg:      */ 0 },
    + #endif
    + #if !defined(SQLITE_OMIT_FLAG_PRAGMAS)
    + #if !defined(SQLITE_OMIT_AUTOMATIC_INDEX)
    +-  { /* zName:     */ "automatic_index",
    +-    /* ePragTyp:  */ PragTyp_FLAG,
    +-    /* ePragFlag: */ 0,
    +-    /* iArg:      */ SQLITE_AutoIndex },
    +-#endif
    +-#endif
    +-  { /* zName:     */ "busy_timeout",
    +-    /* ePragTyp:  */ PragTyp_BUSY_TIMEOUT,
    +-    /* ePragFlag: */ 0,
    +-    /* iArg:      */ 0 },
    ++ {/* zName:     */ "automatic_index",
    ++  /* ePragTyp:  */ PragTyp_FLAG,
    ++  /* ePragFlg:  */ PragFlg_Result0|PragFlg_NoColumns1,
    ++  /* ColNames:  */ 0, 0,
    ++  /* iArg:      */ SQLITE_AutoIndex },
    ++#endif
    ++#endif
    ++ {/* zName:     */ "busy_timeout",
    ++  /* ePragTyp:  */ PragTyp_BUSY_TIMEOUT,
    ++  /* ePragFlg:  */ PragFlg_Result0,
    ++  /* ColNames:  */ 49, 1,
    ++  /* iArg:      */ 0 },
    + #if !defined(SQLITE_OMIT_PAGER_PRAGMAS)
    +-  { /* zName:     */ "cache_size",
    +-    /* ePragTyp:  */ PragTyp_CACHE_SIZE,
    +-    /* ePragFlag: */ 0,
    +-    /* iArg:      */ 0 },
    ++ {/* zName:     */ "cache_size",
    ++  /* ePragTyp:  */ PragTyp_CACHE_SIZE,
    ++  /* ePragFlg:  */ PragFlg_NeedSchema|PragFlg_Result0|PragFlg_SchemaReq|PragFlg_NoColumns1,
    ++  /* ColNames:  */ 0, 0,
    ++  /* iArg:      */ 0 },
    + #endif
    + #if !defined(SQLITE_OMIT_FLAG_PRAGMAS)
    +-  { /* zName:     */ "cache_spill",
    +-    /* ePragTyp:  */ PragTyp_FLAG,
    +-    /* ePragFlag: */ 0,
    +-    /* iArg:      */ SQLITE_CacheSpill },
    +-#endif
    +-  { /* zName:     */ "case_sensitive_like",
    +-    /* ePragTyp:  */ PragTyp_CASE_SENSITIVE_LIKE,
    +-    /* ePragFlag: */ 0,
    +-    /* iArg:      */ 0 },
    +-  { /* zName:     */ "cell_size_check",
    +-    /* ePragTyp:  */ PragTyp_FLAG,
    +-    /* ePragFlag: */ 0,
    +-    /* iArg:      */ SQLITE_CellSizeCk },
    ++ {/* zName:     */ "cache_spill",
    ++  /* ePragTyp:  */ PragTyp_CACHE_SPILL,
    ++  /* ePragFlg:  */ PragFlg_Result0|PragFlg_SchemaReq|PragFlg_NoColumns1,
    ++  /* ColNames:  */ 0, 0,
    ++  /* iArg:      */ 0 },
    ++#endif
    ++ {/* zName:     */ "case_sensitive_like",
    ++  /* ePragTyp:  */ PragTyp_CASE_SENSITIVE_LIKE,
    ++  /* ePragFlg:  */ PragFlg_NoColumns,
    ++  /* ColNames:  */ 0, 0,
    ++  /* iArg:      */ 0 },
    ++ {/* zName:     */ "cell_size_check",
    ++  /* ePragTyp:  */ PragTyp_FLAG,
    ++  /* ePragFlg:  */ PragFlg_Result0|PragFlg_NoColumns1,
    ++  /* ColNames:  */ 0, 0,
    ++  /* iArg:      */ SQLITE_CellSizeCk },
    + #if !defined(SQLITE_OMIT_FLAG_PRAGMAS)
    +-  { /* zName:     */ "checkpoint_fullfsync",
    +-    /* ePragTyp:  */ PragTyp_FLAG,
    +-    /* ePragFlag: */ 0,
    +-    /* iArg:      */ SQLITE_CkptFullFSync },
    ++ {/* zName:     */ "checkpoint_fullfsync",
    ++  /* ePragTyp:  */ PragTyp_FLAG,
    ++  /* ePragFlg:  */ PragFlg_Result0|PragFlg_NoColumns1,
    ++  /* ColNames:  */ 0, 0,
    ++  /* iArg:      */ SQLITE_CkptFullFSync },
    + #endif
    + #if !defined(SQLITE_OMIT_SCHEMA_PRAGMAS)
    +-  { /* zName:     */ "collation_list",
    +-    /* ePragTyp:  */ PragTyp_COLLATION_LIST,
    +-    /* ePragFlag: */ 0,
    +-    /* iArg:      */ 0 },
    ++ {/* zName:     */ "collation_list",
    ++  /* ePragTyp:  */ PragTyp_COLLATION_LIST,
    ++  /* ePragFlg:  */ PragFlg_Result0,
    ++  /* ColNames:  */ 32, 2,
    ++  /* iArg:      */ 0 },
    + #endif
    + #if !defined(SQLITE_OMIT_COMPILEOPTION_DIAGS)
    +-  { /* zName:     */ "compile_options",
    +-    /* ePragTyp:  */ PragTyp_COMPILE_OPTIONS,
    +-    /* ePragFlag: */ 0,
    +-    /* iArg:      */ 0 },
    ++ {/* zName:     */ "compile_options",
    ++  /* ePragTyp:  */ PragTyp_COMPILE_OPTIONS,
    ++  /* ePragFlg:  */ PragFlg_Result0,
    ++  /* ColNames:  */ 0, 0,
    ++  /* iArg:      */ 0 },
    + #endif
    + #if !defined(SQLITE_OMIT_FLAG_PRAGMAS)
    +-  { /* zName:     */ "count_changes",
    +-    /* ePragTyp:  */ PragTyp_FLAG,
    +-    /* ePragFlag: */ 0,
    +-    /* iArg:      */ SQLITE_CountRows },
    ++ {/* zName:     */ "count_changes",
    ++  /* ePragTyp:  */ PragTyp_FLAG,
    ++  /* ePragFlg:  */ PragFlg_Result0|PragFlg_NoColumns1,
    ++  /* ColNames:  */ 0, 0,
    ++  /* iArg:      */ SQLITE_CountRows },
    + #endif
    + #if !defined(SQLITE_OMIT_PAGER_PRAGMAS) && SQLITE_OS_WIN
    +-  { /* zName:     */ "data_store_directory",
    +-    /* ePragTyp:  */ PragTyp_DATA_STORE_DIRECTORY,
    +-    /* ePragFlag: */ 0,
    +-    /* iArg:      */ 0 },
    ++ {/* zName:     */ "data_store_directory",
    ++  /* ePragTyp:  */ PragTyp_DATA_STORE_DIRECTORY,
    ++  /* ePragFlg:  */ PragFlg_NoColumns1,
    ++  /* ColNames:  */ 0, 0,
    ++  /* iArg:      */ 0 },
    + #endif
    + #if !defined(SQLITE_OMIT_SCHEMA_VERSION_PRAGMAS)
    +-  { /* zName:     */ "data_version",
    +-    /* ePragTyp:  */ PragTyp_HEADER_VALUE,
    +-    /* ePragFlag: */ PragFlag_ReadOnly,
    +-    /* iArg:      */ BTREE_DATA_VERSION },
    ++ {/* zName:     */ "data_version",
    ++  /* ePragTyp:  */ PragTyp_HEADER_VALUE,
    ++  /* ePragFlg:  */ PragFlg_ReadOnly|PragFlg_Result0,
    ++  /* ColNames:  */ 0, 0,
    ++  /* iArg:      */ BTREE_DATA_VERSION },
    + #endif
    + #if !defined(SQLITE_OMIT_SCHEMA_PRAGMAS)
    +-  { /* zName:     */ "database_list",
    +-    /* ePragTyp:  */ PragTyp_DATABASE_LIST,
    +-    /* ePragFlag: */ PragFlag_NeedSchema,
    +-    /* iArg:      */ 0 },
    ++ {/* zName:     */ "database_list",
    ++  /* ePragTyp:  */ PragTyp_DATABASE_LIST,
    ++  /* ePragFlg:  */ PragFlg_NeedSchema|PragFlg_Result0,
    ++  /* ColNames:  */ 26, 3,
    ++  /* iArg:      */ 0 },
    + #endif
    + #if !defined(SQLITE_OMIT_PAGER_PRAGMAS) && !defined(SQLITE_OMIT_DEPRECATED)
    +-  { /* zName:     */ "default_cache_size",
    +-    /* ePragTyp:  */ PragTyp_DEFAULT_CACHE_SIZE,
    +-    /* ePragFlag: */ PragFlag_NeedSchema,
    +-    /* iArg:      */ 0 },
    ++ {/* zName:     */ "default_cache_size",
    ++  /* ePragTyp:  */ PragTyp_DEFAULT_CACHE_SIZE,
    ++  /* ePragFlg:  */ PragFlg_NeedSchema|PragFlg_Result0|PragFlg_SchemaReq|PragFlg_NoColumns1,
    ++  /* ColNames:  */ 0, 1,
    ++  /* iArg:      */ 0 },
    + #endif
    + #if !defined(SQLITE_OMIT_FLAG_PRAGMAS)
    + #if !defined(SQLITE_OMIT_FOREIGN_KEY) && !defined(SQLITE_OMIT_TRIGGER)
    +-  { /* zName:     */ "defer_foreign_keys",
    +-    /* ePragTyp:  */ PragTyp_FLAG,
    +-    /* ePragFlag: */ 0,
    +-    /* iArg:      */ SQLITE_DeferFKs },
    ++ {/* zName:     */ "defer_foreign_keys",
    ++  /* ePragTyp:  */ PragTyp_FLAG,
    ++  /* ePragFlg:  */ PragFlg_Result0|PragFlg_NoColumns1,
    ++  /* ColNames:  */ 0, 0,
    ++  /* iArg:      */ SQLITE_DeferFKs },
    + #endif
    + #endif
    + #if !defined(SQLITE_OMIT_FLAG_PRAGMAS)
    +-  { /* zName:     */ "empty_result_callbacks",
    +-    /* ePragTyp:  */ PragTyp_FLAG,
    +-    /* ePragFlag: */ 0,
    +-    /* iArg:      */ SQLITE_NullCallback },
    ++ {/* zName:     */ "empty_result_callbacks",
    ++  /* ePragTyp:  */ PragTyp_FLAG,
    ++  /* ePragFlg:  */ PragFlg_Result0|PragFlg_NoColumns1,
    ++  /* ColNames:  */ 0, 0,
    ++  /* iArg:      */ SQLITE_NullCallback },
    + #endif
    + #if !defined(SQLITE_OMIT_UTF16)
    +-  { /* zName:     */ "encoding",
    +-    /* ePragTyp:  */ PragTyp_ENCODING,
    +-    /* ePragFlag: */ 0,
    +-    /* iArg:      */ 0 },
    ++ {/* zName:     */ "encoding",
    ++  /* ePragTyp:  */ PragTyp_ENCODING,
    ++  /* ePragFlg:  */ PragFlg_Result0|PragFlg_NoColumns1,
    ++  /* ColNames:  */ 0, 0,
    ++  /* iArg:      */ 0 },
    + #endif
    + #if !defined(SQLITE_OMIT_FOREIGN_KEY) && !defined(SQLITE_OMIT_TRIGGER)
    +-  { /* zName:     */ "foreign_key_check",
    +-    /* ePragTyp:  */ PragTyp_FOREIGN_KEY_CHECK,
    +-    /* ePragFlag: */ PragFlag_NeedSchema,
    +-    /* iArg:      */ 0 },
    ++ {/* zName:     */ "foreign_key_check",
    ++  /* ePragTyp:  */ PragTyp_FOREIGN_KEY_CHECK,
    ++  /* ePragFlg:  */ PragFlg_NeedSchema|PragFlg_Result0,
    ++  /* ColNames:  */ 42, 4,
    ++  /* iArg:      */ 0 },
    + #endif
    + #if !defined(SQLITE_OMIT_FOREIGN_KEY)
    +-  { /* zName:     */ "foreign_key_list",
    +-    /* ePragTyp:  */ PragTyp_FOREIGN_KEY_LIST,
    +-    /* ePragFlag: */ PragFlag_NeedSchema,
    +-    /* iArg:      */ 0 },
    ++ {/* zName:     */ "foreign_key_list",
    ++  /* ePragTyp:  */ PragTyp_FOREIGN_KEY_LIST,
    ++  /* ePragFlg:  */ PragFlg_NeedSchema|PragFlg_Result1|PragFlg_SchemaOpt,
    ++  /* ColNames:  */ 34, 8,
    ++  /* iArg:      */ 0 },
    + #endif
    + #if !defined(SQLITE_OMIT_FLAG_PRAGMAS)
    + #if !defined(SQLITE_OMIT_FOREIGN_KEY) && !defined(SQLITE_OMIT_TRIGGER)
    +-  { /* zName:     */ "foreign_keys",
    +-    /* ePragTyp:  */ PragTyp_FLAG,
    +-    /* ePragFlag: */ 0,
    +-    /* iArg:      */ SQLITE_ForeignKeys },
    ++ {/* zName:     */ "foreign_keys",
    ++  /* ePragTyp:  */ PragTyp_FLAG,
    ++  /* ePragFlg:  */ PragFlg_Result0|PragFlg_NoColumns1,
    ++  /* ColNames:  */ 0, 0,
    ++  /* iArg:      */ SQLITE_ForeignKeys },
    + #endif
    + #endif
    + #if !defined(SQLITE_OMIT_SCHEMA_VERSION_PRAGMAS)
    +-  { /* zName:     */ "freelist_count",
    +-    /* ePragTyp:  */ PragTyp_HEADER_VALUE,
    +-    /* ePragFlag: */ PragFlag_ReadOnly,
    +-    /* iArg:      */ BTREE_FREE_PAGE_COUNT },
    ++ {/* zName:     */ "freelist_count",
    ++  /* ePragTyp:  */ PragTyp_HEADER_VALUE,
    ++  /* ePragFlg:  */ PragFlg_ReadOnly|PragFlg_Result0,
    ++  /* ColNames:  */ 0, 0,
    ++  /* iArg:      */ BTREE_FREE_PAGE_COUNT },
    + #endif
    + #if !defined(SQLITE_OMIT_FLAG_PRAGMAS)
    +-  { /* zName:     */ "full_column_names",
    +-    /* ePragTyp:  */ PragTyp_FLAG,
    +-    /* ePragFlag: */ 0,
    +-    /* iArg:      */ SQLITE_FullColNames },
    +-  { /* zName:     */ "fullfsync",
    +-    /* ePragTyp:  */ PragTyp_FLAG,
    +-    /* ePragFlag: */ 0,
    +-    /* iArg:      */ SQLITE_FullFSync },
    ++ {/* zName:     */ "full_column_names",
    ++  /* ePragTyp:  */ PragTyp_FLAG,
    ++  /* ePragFlg:  */ PragFlg_Result0|PragFlg_NoColumns1,
    ++  /* ColNames:  */ 0, 0,
    ++  /* iArg:      */ SQLITE_FullColNames },
    ++ {/* zName:     */ "fullfsync",
    ++  /* ePragTyp:  */ PragTyp_FLAG,
    ++  /* ePragFlg:  */ PragFlg_Result0|PragFlg_NoColumns1,
    ++  /* ColNames:  */ 0, 0,
    ++  /* iArg:      */ SQLITE_FullFSync },
    ++#endif
    ++#if !defined(SQLITE_OMIT_SCHEMA_PRAGMAS)
    ++#if defined(SQLITE_INTROSPECTION_PRAGMAS)
    ++ {/* zName:     */ "function_list",
    ++  /* ePragTyp:  */ PragTyp_FUNCTION_LIST,
    ++  /* ePragFlg:  */ PragFlg_Result0,
    ++  /* ColNames:  */ 29, 2,
    ++  /* iArg:      */ 0 },
    ++#endif
    + #endif
    + #if defined(SQLITE_HAS_CODEC)
    +-  { /* zName:     */ "hexkey",
    +-    /* ePragTyp:  */ PragTyp_HEXKEY,
    +-    /* ePragFlag: */ 0,
    +-    /* iArg:      */ 0 },
    +-  { /* zName:     */ "hexrekey",
    +-    /* ePragTyp:  */ PragTyp_HEXKEY,
    +-    /* ePragFlag: */ 0,
    +-    /* iArg:      */ 0 },
    ++ {/* zName:     */ "hexkey",
    ++  /* ePragTyp:  */ PragTyp_HEXKEY,
    ++  /* ePragFlg:  */ 0,
    ++  /* ColNames:  */ 0, 0,
    ++  /* iArg:      */ 0 },
    ++ {/* zName:     */ "hexrekey",
    ++  /* ePragTyp:  */ PragTyp_HEXKEY,
    ++  /* ePragFlg:  */ 0,
    ++  /* ColNames:  */ 0, 0,
    ++  /* iArg:      */ 0 },
    + #endif
    + #if !defined(SQLITE_OMIT_FLAG_PRAGMAS)
    + #if !defined(SQLITE_OMIT_CHECK)
    +-  { /* zName:     */ "ignore_check_constraints",
    +-    /* ePragTyp:  */ PragTyp_FLAG,
    +-    /* ePragFlag: */ 0,
    +-    /* iArg:      */ SQLITE_IgnoreChecks },
    ++ {/* zName:     */ "ignore_check_constraints",
    ++  /* ePragTyp:  */ PragTyp_FLAG,
    ++  /* ePragFlg:  */ PragFlg_Result0|PragFlg_NoColumns1,
    ++  /* ColNames:  */ 0, 0,
    ++  /* iArg:      */ SQLITE_IgnoreChecks },
    + #endif
    + #endif
    + #if !defined(SQLITE_OMIT_AUTOVACUUM)
    +-  { /* zName:     */ "incremental_vacuum",
    +-    /* ePragTyp:  */ PragTyp_INCREMENTAL_VACUUM,
    +-    /* ePragFlag: */ PragFlag_NeedSchema,
    +-    /* iArg:      */ 0 },
    ++ {/* zName:     */ "incremental_vacuum",
    ++  /* ePragTyp:  */ PragTyp_INCREMENTAL_VACUUM,
    ++  /* ePragFlg:  */ PragFlg_NeedSchema|PragFlg_NoColumns,
    ++  /* ColNames:  */ 0, 0,
    ++  /* iArg:      */ 0 },
    + #endif
    + #if !defined(SQLITE_OMIT_SCHEMA_PRAGMAS)
    +-  { /* zName:     */ "index_info",
    +-    /* ePragTyp:  */ PragTyp_INDEX_INFO,
    +-    /* ePragFlag: */ PragFlag_NeedSchema,
    +-    /* iArg:      */ 0 },
    +-  { /* zName:     */ "index_list",
    +-    /* ePragTyp:  */ PragTyp_INDEX_LIST,
    +-    /* ePragFlag: */ PragFlag_NeedSchema,
    +-    /* iArg:      */ 0 },
    +-  { /* zName:     */ "index_xinfo",
    +-    /* ePragTyp:  */ PragTyp_INDEX_INFO,
    +-    /* ePragFlag: */ PragFlag_NeedSchema,
    +-    /* iArg:      */ 1 },
    ++ {/* zName:     */ "index_info",
    ++  /* ePragTyp:  */ PragTyp_INDEX_INFO,
    ++  /* ePragFlg:  */ PragFlg_NeedSchema|PragFlg_Result1|PragFlg_SchemaOpt,
    ++  /* ColNames:  */ 12, 3,
    ++  /* iArg:      */ 0 },
    ++ {/* zName:     */ "index_list",
    ++  /* ePragTyp:  */ PragTyp_INDEX_LIST,
    ++  /* ePragFlg:  */ PragFlg_NeedSchema|PragFlg_Result1|PragFlg_SchemaOpt,
    ++  /* ColNames:  */ 21, 5,
    ++  /* iArg:      */ 0 },
    ++ {/* zName:     */ "index_xinfo",
    ++  /* ePragTyp:  */ PragTyp_INDEX_INFO,
    ++  /* ePragFlg:  */ PragFlg_NeedSchema|PragFlg_Result1|PragFlg_SchemaOpt,
    ++  /* ColNames:  */ 15, 6,
    ++  /* iArg:      */ 1 },
    + #endif
    + #if !defined(SQLITE_OMIT_INTEGRITY_CHECK)
    +-  { /* zName:     */ "integrity_check",
    +-    /* ePragTyp:  */ PragTyp_INTEGRITY_CHECK,
    +-    /* ePragFlag: */ PragFlag_NeedSchema,
    +-    /* iArg:      */ 0 },
    ++ {/* zName:     */ "integrity_check",
    ++  /* ePragTyp:  */ PragTyp_INTEGRITY_CHECK,
    ++  /* ePragFlg:  */ PragFlg_NeedSchema|PragFlg_Result0|PragFlg_Result1,
    ++  /* ColNames:  */ 0, 0,
    ++  /* iArg:      */ 0 },
    + #endif
    + #if !defined(SQLITE_OMIT_PAGER_PRAGMAS)
    +-  { /* zName:     */ "journal_mode",
    +-    /* ePragTyp:  */ PragTyp_JOURNAL_MODE,
    +-    /* ePragFlag: */ PragFlag_NeedSchema,
    +-    /* iArg:      */ 0 },
    +-  { /* zName:     */ "journal_size_limit",
    +-    /* ePragTyp:  */ PragTyp_JOURNAL_SIZE_LIMIT,
    +-    /* ePragFlag: */ 0,
    +-    /* iArg:      */ 0 },
    ++ {/* zName:     */ "journal_mode",
    ++  /* ePragTyp:  */ PragTyp_JOURNAL_MODE,
    ++  /* ePragFlg:  */ PragFlg_NeedSchema|PragFlg_Result0|PragFlg_SchemaReq,
    ++  /* ColNames:  */ 0, 0,
    ++  /* iArg:      */ 0 },
    ++ {/* zName:     */ "journal_size_limit",
    ++  /* ePragTyp:  */ PragTyp_JOURNAL_SIZE_LIMIT,
    ++  /* ePragFlg:  */ PragFlg_Result0|PragFlg_SchemaReq,
    ++  /* ColNames:  */ 0, 0,
    ++  /* iArg:      */ 0 },
    + #endif
    + #if defined(SQLITE_HAS_CODEC)
    +-  { /* zName:     */ "key",
    +-    /* ePragTyp:  */ PragTyp_KEY,
    +-    /* ePragFlag: */ 0,
    +-    /* iArg:      */ 0 },
    ++ {/* zName:     */ "key",
    ++  /* ePragTyp:  */ PragTyp_KEY,
    ++  /* ePragFlg:  */ 0,
    ++  /* ColNames:  */ 0, 0,
    ++  /* iArg:      */ 0 },
    + #endif
    + #if !defined(SQLITE_OMIT_FLAG_PRAGMAS)
    +-  { /* zName:     */ "legacy_file_format",
    +-    /* ePragTyp:  */ PragTyp_FLAG,
    +-    /* ePragFlag: */ 0,
    +-    /* iArg:      */ SQLITE_LegacyFileFmt },
    ++ {/* zName:     */ "legacy_file_format",
    ++  /* ePragTyp:  */ PragTyp_FLAG,
    ++  /* ePragFlg:  */ PragFlg_Result0|PragFlg_NoColumns1,
    ++  /* ColNames:  */ 0, 0,
    ++  /* iArg:      */ SQLITE_LegacyFileFmt },
    + #endif
    + #if !defined(SQLITE_OMIT_PAGER_PRAGMAS) && SQLITE_ENABLE_LOCKING_STYLE
    +-  { /* zName:     */ "lock_proxy_file",
    +-    /* ePragTyp:  */ PragTyp_LOCK_PROXY_FILE,
    +-    /* ePragFlag: */ 0,
    +-    /* iArg:      */ 0 },
    ++ {/* zName:     */ "lock_proxy_file",
    ++  /* ePragTyp:  */ PragTyp_LOCK_PROXY_FILE,
    ++  /* ePragFlg:  */ PragFlg_NoColumns1,
    ++  /* ColNames:  */ 0, 0,
    ++  /* iArg:      */ 0 },
    + #endif
    + #if defined(SQLITE_DEBUG) || defined(SQLITE_TEST)
    +-  { /* zName:     */ "lock_status",
    +-    /* ePragTyp:  */ PragTyp_LOCK_STATUS,
    +-    /* ePragFlag: */ 0,
    +-    /* iArg:      */ 0 },
    ++ {/* zName:     */ "lock_status",
    ++  /* ePragTyp:  */ PragTyp_LOCK_STATUS,
    ++  /* ePragFlg:  */ PragFlg_Result0,
    ++  /* ColNames:  */ 50, 2,
    ++  /* iArg:      */ 0 },
    + #endif
    + #if !defined(SQLITE_OMIT_PAGER_PRAGMAS)
    +-  { /* zName:     */ "locking_mode",
    +-    /* ePragTyp:  */ PragTyp_LOCKING_MODE,
    +-    /* ePragFlag: */ 0,
    +-    /* iArg:      */ 0 },
    +-  { /* zName:     */ "max_page_count",
    +-    /* ePragTyp:  */ PragTyp_PAGE_COUNT,
    +-    /* ePragFlag: */ PragFlag_NeedSchema,
    +-    /* iArg:      */ 0 },
    +-  { /* zName:     */ "mmap_size",
    +-    /* ePragTyp:  */ PragTyp_MMAP_SIZE,
    +-    /* ePragFlag: */ 0,
    +-    /* iArg:      */ 0 },
    +-  { /* zName:     */ "page_count",
    +-    /* ePragTyp:  */ PragTyp_PAGE_COUNT,
    +-    /* ePragFlag: */ PragFlag_NeedSchema,
    +-    /* iArg:      */ 0 },
    +-  { /* zName:     */ "page_size",
    +-    /* ePragTyp:  */ PragTyp_PAGE_SIZE,
    +-    /* ePragFlag: */ 0,
    +-    /* iArg:      */ 0 },
    ++ {/* zName:     */ "locking_mode",
    ++  /* ePragTyp:  */ PragTyp_LOCKING_MODE,
    ++  /* ePragFlg:  */ PragFlg_Result0|PragFlg_SchemaReq,
    ++  /* ColNames:  */ 0, 0,
    ++  /* iArg:      */ 0 },
    ++ {/* zName:     */ "max_page_count",
    ++  /* ePragTyp:  */ PragTyp_PAGE_COUNT,
    ++  /* ePragFlg:  */ PragFlg_NeedSchema|PragFlg_Result0|PragFlg_SchemaReq,
    ++  /* ColNames:  */ 0, 0,
    ++  /* iArg:      */ 0 },
    ++ {/* zName:     */ "mmap_size",
    ++  /* ePragTyp:  */ PragTyp_MMAP_SIZE,
    ++  /* ePragFlg:  */ 0,
    ++  /* ColNames:  */ 0, 0,
    ++  /* iArg:      */ 0 },
    + #endif
    +-#if defined(SQLITE_DEBUG)
    +-  { /* zName:     */ "parser_trace",
    +-    /* ePragTyp:  */ PragTyp_PARSER_TRACE,
    +-    /* ePragFlag: */ 0,
    +-    /* iArg:      */ 0 },
    ++#if !defined(SQLITE_OMIT_SCHEMA_PRAGMAS)
    ++#if !defined(SQLITE_OMIT_VIRTUALTABLE)
    ++#if defined(SQLITE_INTROSPECTION_PRAGMAS)
    ++ {/* zName:     */ "module_list",
    ++  /* ePragTyp:  */ PragTyp_MODULE_LIST,
    ++  /* ePragFlg:  */ PragFlg_Result0,
    ++  /* ColNames:  */ 31, 1,
    ++  /* iArg:      */ 0 },
    ++#endif
    ++#endif
    ++#endif
    ++ {/* zName:     */ "optimize",
    ++  /* ePragTyp:  */ PragTyp_OPTIMIZE,
    ++  /* ePragFlg:  */ PragFlg_Result1|PragFlg_NeedSchema,
    ++  /* ColNames:  */ 0, 0,
    ++  /* iArg:      */ 0 },
    ++#if !defined(SQLITE_OMIT_PAGER_PRAGMAS)
    ++ {/* zName:     */ "page_count",
    ++  /* ePragTyp:  */ PragTyp_PAGE_COUNT,
    ++  /* ePragFlg:  */ PragFlg_NeedSchema|PragFlg_Result0|PragFlg_SchemaReq,
    ++  /* ColNames:  */ 0, 0,
    ++  /* iArg:      */ 0 },
    ++ {/* zName:     */ "page_size",
    ++  /* ePragTyp:  */ PragTyp_PAGE_SIZE,
    ++  /* ePragFlg:  */ PragFlg_Result0|PragFlg_SchemaReq|PragFlg_NoColumns1,
    ++  /* ColNames:  */ 0, 0,
    ++  /* iArg:      */ 0 },
    ++#endif
    ++#if defined(SQLITE_DEBUG) && !defined(SQLITE_OMIT_PARSER_TRACE)
    ++ {/* zName:     */ "parser_trace",
    ++  /* ePragTyp:  */ PragTyp_PARSER_TRACE,
    ++  /* ePragFlg:  */ 0,
    ++  /* ColNames:  */ 0, 0,
    ++  /* iArg:      */ 0 },
    ++#endif
    ++#if defined(SQLITE_INTROSPECTION_PRAGMAS)
    ++ {/* zName:     */ "pragma_list",
    ++  /* ePragTyp:  */ PragTyp_PRAGMA_LIST,
    ++  /* ePragFlg:  */ PragFlg_Result0,
    ++  /* ColNames:  */ 31, 1,
    ++  /* iArg:      */ 0 },
    + #endif
    + #if !defined(SQLITE_OMIT_FLAG_PRAGMAS)
    +-  { /* zName:     */ "query_only",
    +-    /* ePragTyp:  */ PragTyp_FLAG,
    +-    /* ePragFlag: */ 0,
    +-    /* iArg:      */ SQLITE_QueryOnly },
    ++ {/* zName:     */ "query_only",
    ++  /* ePragTyp:  */ PragTyp_FLAG,
    ++  /* ePragFlg:  */ PragFlg_Result0|PragFlg_NoColumns1,
    ++  /* ColNames:  */ 0, 0,
    ++  /* iArg:      */ SQLITE_QueryOnly },
    + #endif
    + #if !defined(SQLITE_OMIT_INTEGRITY_CHECK)
    +-  { /* zName:     */ "quick_check",
    +-    /* ePragTyp:  */ PragTyp_INTEGRITY_CHECK,
    +-    /* ePragFlag: */ PragFlag_NeedSchema,
    +-    /* iArg:      */ 0 },
    ++ {/* zName:     */ "quick_check",
    ++  /* ePragTyp:  */ PragTyp_INTEGRITY_CHECK,
    ++  /* ePragFlg:  */ PragFlg_NeedSchema|PragFlg_Result0|PragFlg_Result1,
    ++  /* ColNames:  */ 0, 0,
    ++  /* iArg:      */ 0 },
    + #endif
    + #if !defined(SQLITE_OMIT_FLAG_PRAGMAS)
    +-  { /* zName:     */ "read_uncommitted",
    +-    /* ePragTyp:  */ PragTyp_FLAG,
    +-    /* ePragFlag: */ 0,
    +-    /* iArg:      */ SQLITE_ReadUncommitted },
    +-  { /* zName:     */ "recursive_triggers",
    +-    /* ePragTyp:  */ PragTyp_FLAG,
    +-    /* ePragFlag: */ 0,
    +-    /* iArg:      */ SQLITE_RecTriggers },
    ++ {/* zName:     */ "read_uncommitted",
    ++  /* ePragTyp:  */ PragTyp_FLAG,
    ++  /* ePragFlg:  */ PragFlg_Result0|PragFlg_NoColumns1,
    ++  /* ColNames:  */ 0, 0,
    ++  /* iArg:      */ SQLITE_ReadUncommit },
    ++ {/* zName:     */ "recursive_triggers",
    ++  /* ePragTyp:  */ PragTyp_FLAG,
    ++  /* ePragFlg:  */ PragFlg_Result0|PragFlg_NoColumns1,
    ++  /* ColNames:  */ 0, 0,
    ++  /* iArg:      */ SQLITE_RecTriggers },
    + #endif
    + #if defined(SQLITE_HAS_CODEC)
    +-  { /* zName:     */ "rekey",
    +-    /* ePragTyp:  */ PragTyp_REKEY,
    +-    /* ePragFlag: */ 0,
    +-    /* iArg:      */ 0 },
    ++ {/* zName:     */ "rekey",
    ++  /* ePragTyp:  */ PragTyp_REKEY,
    ++  /* ePragFlg:  */ 0,
    ++  /* ColNames:  */ 0, 0,
    ++  /* iArg:      */ 0 },
    + #endif
    + #if !defined(SQLITE_OMIT_FLAG_PRAGMAS)
    +-  { /* zName:     */ "reverse_unordered_selects",
    +-    /* ePragTyp:  */ PragTyp_FLAG,
    +-    /* ePragFlag: */ 0,
    +-    /* iArg:      */ SQLITE_ReverseOrder },
    ++ {/* zName:     */ "reverse_unordered_selects",
    ++  /* ePragTyp:  */ PragTyp_FLAG,
    ++  /* ePragFlg:  */ PragFlg_Result0|PragFlg_NoColumns1,
    ++  /* ColNames:  */ 0, 0,
    ++  /* iArg:      */ SQLITE_ReverseOrder },
    + #endif
    + #if !defined(SQLITE_OMIT_SCHEMA_VERSION_PRAGMAS)
    +-  { /* zName:     */ "schema_version",
    +-    /* ePragTyp:  */ PragTyp_HEADER_VALUE,
    +-    /* ePragFlag: */ 0,
    +-    /* iArg:      */ BTREE_SCHEMA_VERSION },
    ++ {/* zName:     */ "schema_version",
    ++  /* ePragTyp:  */ PragTyp_HEADER_VALUE,
    ++  /* ePragFlg:  */ PragFlg_NoColumns1|PragFlg_Result0,
    ++  /* ColNames:  */ 0, 0,
    ++  /* iArg:      */ BTREE_SCHEMA_VERSION },
    + #endif
    + #if !defined(SQLITE_OMIT_PAGER_PRAGMAS)
    +-  { /* zName:     */ "secure_delete",
    +-    /* ePragTyp:  */ PragTyp_SECURE_DELETE,
    +-    /* ePragFlag: */ 0,
    +-    /* iArg:      */ 0 },
    ++ {/* zName:     */ "secure_delete",
    ++  /* ePragTyp:  */ PragTyp_SECURE_DELETE,
    ++  /* ePragFlg:  */ PragFlg_Result0,
    ++  /* ColNames:  */ 0, 0,
    ++  /* iArg:      */ 0 },
    + #endif
    + #if !defined(SQLITE_OMIT_FLAG_PRAGMAS)
    +-  { /* zName:     */ "short_column_names",
    +-    /* ePragTyp:  */ PragTyp_FLAG,
    +-    /* ePragFlag: */ 0,
    +-    /* iArg:      */ SQLITE_ShortColNames },
    +-#endif
    +-  { /* zName:     */ "shrink_memory",
    +-    /* ePragTyp:  */ PragTyp_SHRINK_MEMORY,
    +-    /* ePragFlag: */ 0,
    +-    /* iArg:      */ 0 },
    +-  { /* zName:     */ "soft_heap_limit",
    +-    /* ePragTyp:  */ PragTyp_SOFT_HEAP_LIMIT,
    +-    /* ePragFlag: */ 0,
    +-    /* iArg:      */ 0 },
    ++ {/* zName:     */ "short_column_names",
    ++  /* ePragTyp:  */ PragTyp_FLAG,
    ++  /* ePragFlg:  */ PragFlg_Result0|PragFlg_NoColumns1,
    ++  /* ColNames:  */ 0, 0,
    ++  /* iArg:      */ SQLITE_ShortColNames },
    ++#endif
    ++ {/* zName:     */ "shrink_memory",
    ++  /* ePragTyp:  */ PragTyp_SHRINK_MEMORY,
    ++  /* ePragFlg:  */ PragFlg_NoColumns,
    ++  /* ColNames:  */ 0, 0,
    ++  /* iArg:      */ 0 },
    ++ {/* zName:     */ "soft_heap_limit",
    ++  /* ePragTyp:  */ PragTyp_SOFT_HEAP_LIMIT,
    ++  /* ePragFlg:  */ PragFlg_Result0,
    ++  /* ColNames:  */ 0, 0,
    ++  /* iArg:      */ 0 },
    + #if !defined(SQLITE_OMIT_FLAG_PRAGMAS)
    + #if defined(SQLITE_DEBUG)
    +-  { /* zName:     */ "sql_trace",
    +-    /* ePragTyp:  */ PragTyp_FLAG,
    +-    /* ePragFlag: */ 0,
    +-    /* iArg:      */ SQLITE_SqlTrace },
    ++ {/* zName:     */ "sql_trace",
    ++  /* ePragTyp:  */ PragTyp_FLAG,
    ++  /* ePragFlg:  */ PragFlg_Result0|PragFlg_NoColumns1,
    ++  /* ColNames:  */ 0, 0,
    ++  /* iArg:      */ SQLITE_SqlTrace },
    + #endif
    + #endif
    +-#if !defined(SQLITE_OMIT_SCHEMA_PRAGMAS)
    +-  { /* zName:     */ "stats",
    +-    /* ePragTyp:  */ PragTyp_STATS,
    +-    /* ePragFlag: */ PragFlag_NeedSchema,
    +-    /* iArg:      */ 0 },
    ++#if !defined(SQLITE_OMIT_SCHEMA_PRAGMAS) && defined(SQLITE_DEBUG)
    ++ {/* zName:     */ "stats",
    ++  /* ePragTyp:  */ PragTyp_STATS,
    ++  /* ePragFlg:  */ PragFlg_NeedSchema|PragFlg_Result0|PragFlg_SchemaReq,
    ++  /* ColNames:  */ 7, 5,
    ++  /* iArg:      */ 0 },
    + #endif
    + #if !defined(SQLITE_OMIT_PAGER_PRAGMAS)
    +-  { /* zName:     */ "synchronous",
    +-    /* ePragTyp:  */ PragTyp_SYNCHRONOUS,
    +-    /* ePragFlag: */ PragFlag_NeedSchema,
    +-    /* iArg:      */ 0 },
    ++ {/* zName:     */ "synchronous",
    ++  /* ePragTyp:  */ PragTyp_SYNCHRONOUS,
    ++  /* ePragFlg:  */ PragFlg_NeedSchema|PragFlg_Result0|PragFlg_SchemaReq|PragFlg_NoColumns1,
    ++  /* ColNames:  */ 0, 0,
    ++  /* iArg:      */ 0 },
    + #endif
    + #if !defined(SQLITE_OMIT_SCHEMA_PRAGMAS)
    +-  { /* zName:     */ "table_info",
    +-    /* ePragTyp:  */ PragTyp_TABLE_INFO,
    +-    /* ePragFlag: */ PragFlag_NeedSchema,
    +-    /* iArg:      */ 0 },
    ++ {/* zName:     */ "table_info",
    ++  /* ePragTyp:  */ PragTyp_TABLE_INFO,
    ++  /* ePragFlg:  */ PragFlg_NeedSchema|PragFlg_Result1|PragFlg_SchemaOpt,
    ++  /* ColNames:  */ 1, 6,
    ++  /* iArg:      */ 0 },
    + #endif
    + #if !defined(SQLITE_OMIT_PAGER_PRAGMAS)
    +-  { /* zName:     */ "temp_store",
    +-    /* ePragTyp:  */ PragTyp_TEMP_STORE,
    +-    /* ePragFlag: */ 0,
    +-    /* iArg:      */ 0 },
    +-  { /* zName:     */ "temp_store_directory",
    +-    /* ePragTyp:  */ PragTyp_TEMP_STORE_DIRECTORY,
    +-    /* ePragFlag: */ 0,
    +-    /* iArg:      */ 0 },
    +-#endif
    +-  { /* zName:     */ "threads",
    +-    /* ePragTyp:  */ PragTyp_THREADS,
    +-    /* ePragFlag: */ 0,
    +-    /* iArg:      */ 0 },
    ++ {/* zName:     */ "temp_store",
    ++  /* ePragTyp:  */ PragTyp_TEMP_STORE,
    ++  /* ePragFlg:  */ PragFlg_Result0|PragFlg_NoColumns1,
    ++  /* ColNames:  */ 0, 0,
    ++  /* iArg:      */ 0 },
    ++ {/* zName:     */ "temp_store_directory",
    ++  /* ePragTyp:  */ PragTyp_TEMP_STORE_DIRECTORY,
    ++  /* ePragFlg:  */ PragFlg_NoColumns1,
    ++  /* ColNames:  */ 0, 0,
    ++  /* iArg:      */ 0 },
    ++#endif
    ++ {/* zName:     */ "threads",
    ++  /* ePragTyp:  */ PragTyp_THREADS,
    ++  /* ePragFlg:  */ PragFlg_Result0,
    ++  /* ColNames:  */ 0, 0,
    ++  /* iArg:      */ 0 },
    + #if !defined(SQLITE_OMIT_SCHEMA_VERSION_PRAGMAS)
    +-  { /* zName:     */ "user_version",
    +-    /* ePragTyp:  */ PragTyp_HEADER_VALUE,
    +-    /* ePragFlag: */ 0,
    +-    /* iArg:      */ BTREE_USER_VERSION },
    ++ {/* zName:     */ "user_version",
    ++  /* ePragTyp:  */ PragTyp_HEADER_VALUE,
    ++  /* ePragFlg:  */ PragFlg_NoColumns1|PragFlg_Result0,
    ++  /* ColNames:  */ 0, 0,
    ++  /* iArg:      */ BTREE_USER_VERSION },
    + #endif
    + #if !defined(SQLITE_OMIT_FLAG_PRAGMAS)
    + #if defined(SQLITE_DEBUG)
    +-  { /* zName:     */ "vdbe_addoptrace",
    +-    /* ePragTyp:  */ PragTyp_FLAG,
    +-    /* ePragFlag: */ 0,
    +-    /* iArg:      */ SQLITE_VdbeAddopTrace },
    +-  { /* zName:     */ "vdbe_debug",
    +-    /* ePragTyp:  */ PragTyp_FLAG,
    +-    /* ePragFlag: */ 0,
    +-    /* iArg:      */ SQLITE_SqlTrace|SQLITE_VdbeListing|SQLITE_VdbeTrace },
    +-  { /* zName:     */ "vdbe_eqp",
    +-    /* ePragTyp:  */ PragTyp_FLAG,
    +-    /* ePragFlag: */ 0,
    +-    /* iArg:      */ SQLITE_VdbeEQP },
    +-  { /* zName:     */ "vdbe_listing",
    +-    /* ePragTyp:  */ PragTyp_FLAG,
    +-    /* ePragFlag: */ 0,
    +-    /* iArg:      */ SQLITE_VdbeListing },
    +-  { /* zName:     */ "vdbe_trace",
    +-    /* ePragTyp:  */ PragTyp_FLAG,
    +-    /* ePragFlag: */ 0,
    +-    /* iArg:      */ SQLITE_VdbeTrace },
    ++ {/* zName:     */ "vdbe_addoptrace",
    ++  /* ePragTyp:  */ PragTyp_FLAG,
    ++  /* ePragFlg:  */ PragFlg_Result0|PragFlg_NoColumns1,
    ++  /* ColNames:  */ 0, 0,
    ++  /* iArg:      */ SQLITE_VdbeAddopTrace },
    ++ {/* zName:     */ "vdbe_debug",
    ++  /* ePragTyp:  */ PragTyp_FLAG,
    ++  /* ePragFlg:  */ PragFlg_Result0|PragFlg_NoColumns1,
    ++  /* ColNames:  */ 0, 0,
    ++  /* iArg:      */ SQLITE_SqlTrace|SQLITE_VdbeListing|SQLITE_VdbeTrace },
    ++ {/* zName:     */ "vdbe_eqp",
    ++  /* ePragTyp:  */ PragTyp_FLAG,
    ++  /* ePragFlg:  */ PragFlg_Result0|PragFlg_NoColumns1,
    ++  /* ColNames:  */ 0, 0,
    ++  /* iArg:      */ SQLITE_VdbeEQP },
    ++ {/* zName:     */ "vdbe_listing",
    ++  /* ePragTyp:  */ PragTyp_FLAG,
    ++  /* ePragFlg:  */ PragFlg_Result0|PragFlg_NoColumns1,
    ++  /* ColNames:  */ 0, 0,
    ++  /* iArg:      */ SQLITE_VdbeListing },
    ++ {/* zName:     */ "vdbe_trace",
    ++  /* ePragTyp:  */ PragTyp_FLAG,
    ++  /* ePragFlg:  */ PragFlg_Result0|PragFlg_NoColumns1,
    ++  /* ColNames:  */ 0, 0,
    ++  /* iArg:      */ SQLITE_VdbeTrace },
    + #endif
    + #endif
    + #if !defined(SQLITE_OMIT_WAL)
    +-  { /* zName:     */ "wal_autocheckpoint",
    +-    /* ePragTyp:  */ PragTyp_WAL_AUTOCHECKPOINT,
    +-    /* ePragFlag: */ 0,
    +-    /* iArg:      */ 0 },
    +-  { /* zName:     */ "wal_checkpoint",
    +-    /* ePragTyp:  */ PragTyp_WAL_CHECKPOINT,
    +-    /* ePragFlag: */ PragFlag_NeedSchema,
    +-    /* iArg:      */ 0 },
    ++ {/* zName:     */ "wal_autocheckpoint",
    ++  /* ePragTyp:  */ PragTyp_WAL_AUTOCHECKPOINT,
    ++  /* ePragFlg:  */ 0,
    ++  /* ColNames:  */ 0, 0,
    ++  /* iArg:      */ 0 },
    ++ {/* zName:     */ "wal_checkpoint",
    ++  /* ePragTyp:  */ PragTyp_WAL_CHECKPOINT,
    ++  /* ePragFlg:  */ PragFlg_NeedSchema,
    ++  /* ColNames:  */ 46, 3,
    ++  /* iArg:      */ 0 },
    + #endif
    + #if !defined(SQLITE_OMIT_FLAG_PRAGMAS)
    +-  { /* zName:     */ "writable_schema",
    +-    /* ePragTyp:  */ PragTyp_FLAG,
    +-    /* ePragFlag: */ 0,
    +-    /* iArg:      */ SQLITE_WriteSchema|SQLITE_RecoveryMode },
    ++ {/* zName:     */ "writable_schema",
    ++  /* ePragTyp:  */ PragTyp_FLAG,
    ++  /* ePragFlg:  */ PragFlg_Result0|PragFlg_NoColumns1,
    ++  /* ColNames:  */ 0, 0,
    ++  /* iArg:      */ SQLITE_WriteSchema },
    + #endif
    + };
    +-/* Number of pragmas: 60 on by default, 73 total. */
    ++/* Number of pragmas: 60 on by default, 77 total. */
    + 
    + /************** End of pragma.h **********************************************/
    + /************** Continuing where we left off in pragma.c *********************/
    + 
    + /*
    + ** Interpret the given string as a safety level.  Return 0 for OFF,
    +-** 1 for ON or NORMAL and 2 for FULL.  Return 1 for an empty or 
    +-** unrecognized string argument.  The FULL option is disallowed
    ++** 1 for ON or NORMAL, 2 for FULL, and 3 for EXTRA.  Return 1 for an empty or 
    ++** unrecognized string argument.  The FULL and EXTRA option is disallowed
    + ** if the omitFull parameter it 1.
    + **
    + ** Note that the values returned are one less that the values that
    +@@ -105873,18 +115335,21 @@ static const struct sPragmaNames {
    + ** and older scripts may have used numbers 0 for OFF and 1 for ON.
    + */
    + 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};
    +-  static const u8 iLength[] = {2, 2, 3, 5, 3, 4, 4};
    +-  static const u8 iValue[] =  {1, 0, 0, 0, 1, 1, 2};
    ++                             /* 123456789 123456789 123 */
    ++  static const char zText[] = "onoffalseyestruextrafull";
    ++  static const u8 iOffset[] = {0, 1, 2,  4,    9,  12,  15,   20};
    ++  static const u8 iLength[] = {2, 2, 3,  5,    3,   4,   5,    4};
    ++  static const u8 iValue[] =  {1, 0, 0,  0,    1,   1,   3,    2};
    ++                            /* on no off false yes true extra full */
    +   int i, n;
    +   if( sqlite3Isdigit(*z) ){
    +     return (u8)sqlite3Atoi(z);
    +   }
    +   n = sqlite3Strlen30(z);
    +-  for(i=0; i<ArraySize(iLength)-omitFull; i++){
    +-    if( iLength[i]==n && sqlite3StrNICmp(&zText[iOffset[i]],z,n)==0 ){
    ++  for(i=0; i<ArraySize(iLength); i++){
    ++    if( iLength[i]==n && sqlite3StrNICmp(&zText[iOffset[i]],z,n)==0
    ++     && (!omitFull || iValue[i]<=1)
    ++    ){
    +       return iValue[i];
    +     }
    +   }
    +@@ -105991,29 +115456,29 @@ static int changeTempStorage(Parse *pParse, const char *zStorageType){
    + #endif /* SQLITE_PAGER_PRAGMAS */
    + 
    + /*
    +-** Set the names of the first N columns to the values in azCol[]
    ++** Set result column names for a pragma.
    + */
    +-static void setAllColumnNames(
    +-  Vdbe *v,               /* The query under construction */
    +-  int N,                 /* Number of columns */
    +-  const char **azCol     /* Names of columns */
    ++static void setPragmaResultColumnNames(
    ++  Vdbe *v,                     /* The query under construction */
    ++  const PragmaName *pPragma    /* The pragma */
    + ){
    +-  int i;
    +-  sqlite3VdbeSetNumCols(v, N);
    +-  for(i=0; i<N; i++){
    +-    sqlite3VdbeSetColName(v, i, COLNAME_NAME, azCol[i], SQLITE_STATIC);
    ++  u8 n = pPragma->nPragCName;
    ++  sqlite3VdbeSetNumCols(v, n==0 ? 1 : n);
    ++  if( n==0 ){
    ++    sqlite3VdbeSetColName(v, 0, COLNAME_NAME, pPragma->zName, SQLITE_STATIC);
    ++  }else{
    ++    int i, j;
    ++    for(i=0, j=pPragma->iPragCName; i<n; i++, j++){
    ++      sqlite3VdbeSetColName(v, i, COLNAME_NAME, pragCName[j], SQLITE_STATIC);
    ++    }
    +   }
    + }
    +-static void setOneColumnName(Vdbe *v, const char *z){
    +-  setAllColumnNames(v, 1, &z);
    +-}
    + 
    + /*
    + ** Generate code to return a single integer value.
    + */
    +-static void returnSingleInt(Vdbe *v, const char *zLabel, i64 value){
    ++static void returnSingleInt(Vdbe *v, i64 value){
    +   sqlite3VdbeAddOp4Dup8(v, OP_Int64, 0, 1, 0, (const u8*)&value, P4_INT64);
    +-  setOneColumnName(v, zLabel);
    +   sqlite3VdbeAddOp2(v, OP_ResultRow, 1, 1);
    + }
    + 
    +@@ -106022,12 +115487,10 @@ static void returnSingleInt(Vdbe *v, const char *zLabel, i64 value){
    + */
    + static void returnSingleText(
    +   Vdbe *v,                /* Prepared statement under construction */
    +-  const char *zLabel,     /* Name of the result column */
    +   const char *zValue      /* Value to be returned */
    + ){
    +   if( zValue ){
    +     sqlite3VdbeLoadString(v, 1, (const char*)zValue);
    +-    setOneColumnName(v, zLabel);
    +     sqlite3VdbeAddOp2(v, OP_ResultRow, 1, 1);
    +   }
    + }
    +@@ -106105,12 +115568,48 @@ SQLITE_PRIVATE const char *sqlite3JournalModename(int eMode){
    +   return azModeName[eMode];
    + }
    + 
    ++/*
    ++** Locate a pragma in the aPragmaName[] array.
    ++*/
    ++static const PragmaName *pragmaLocate(const char *zName){
    ++  int upr, lwr, mid = 0, rc;
    ++  lwr = 0;
    ++  upr = ArraySize(aPragmaName)-1;
    ++  while( lwr<=upr ){
    ++    mid = (lwr+upr)/2;
    ++    rc = sqlite3_stricmp(zName, aPragmaName[mid].zName);
    ++    if( rc==0 ) break;
    ++    if( rc<0 ){
    ++      upr = mid - 1;
    ++    }else{
    ++      lwr = mid + 1;
    ++    }
    ++  }
    ++  return lwr>upr ? 0 : &aPragmaName[mid];
    ++}
    ++
    ++/*
    ++** Helper subroutine for PRAGMA integrity_check:
    ++**
    ++** Generate code to output a single-column result row with a value of the
    ++** string held in register 3.  Decrement the result count in register 1
    ++** and halt if the maximum number of result rows have been issued.
    ++*/
    ++static int integrityCheckResultRow(Vdbe *v){
    ++  int addr;
    ++  sqlite3VdbeAddOp2(v, OP_ResultRow, 3, 1);
    ++  addr = sqlite3VdbeAddOp3(v, OP_IfPos, 1, sqlite3VdbeCurrentAddr(v)+2, 1);
    ++  VdbeCoverage(v);
    ++  sqlite3VdbeAddOp0(v, OP_Halt);
    ++  return addr;
    ++}
    ++
    + /*
    + ** Process a pragma statement.  
    + **
    + ** Pragmas are of this form:
    + **
    +-**      PRAGMA [database.]id [= value]
    ++**      PRAGMA [schema.]id [= value]
    + **
    + ** The identifier might also be a string.  The value is a string, and
    + ** identifier, or a number.  If minusFlag is true, then the value is
    +@@ -106122,8 +115621,8 @@ SQLITE_PRIVATE const char *sqlite3JournalModename(int eMode){
    + */
    + SQLITE_PRIVATE void sqlite3Pragma(
    +   Parse *pParse, 
    +-  Token *pId1,        /* First part of [database.]id field */
    +-  Token *pId2,        /* Second part of [database.]id field, or NULL */
    ++  Token *pId1,        /* First part of [schema.]id field */
    ++  Token *pId2,        /* Second part of [schema.]id field, or NULL */
    +   Token *pValue,      /* Token for <value>, or NULL */
    +   int minusFlag       /* True if a '-' sign preceded <value> */
    + ){
    +@@ -106133,18 +115632,17 @@ SQLITE_PRIVATE void sqlite3Pragma(
    +   Token *pId;            /* Pointer to <id> token */
    +   char *aFcntl[4];       /* Argument to SQLITE_FCNTL_PRAGMA */
    +   int iDb;               /* Database index for <database> */
    +-  int lwr, upr, mid = 0;       /* Binary search bounds */
    +   int rc;                      /* return value form SQLITE_FCNTL_PRAGMA */
    +   sqlite3 *db = pParse->db;    /* The database connection */
    +   Db *pDb;                     /* The specific database being pragmaed */
    +   Vdbe *v = sqlite3GetVdbe(pParse);  /* Prepared statement */
    +-  const struct sPragmaNames *pPragma;
    ++  const PragmaName *pPragma;   /* The pragma */
    + 
    +   if( v==0 ) return;
    +   sqlite3VdbeRunOnlyOnce(v);
    +   pParse->nMem = 2;
    + 
    +-  /* Interpret the [database.] part of the pragma statement. iDb is the
    ++  /* Interpret the [schema.] part of the pragma statement. iDb is the
    +   ** index of the database this pragma is being applied to in db.aDb[]. */
    +   iDb = sqlite3TwoPartName(pParse, pId1, pId2, &pId);
    +   if( iDb<0 ) return;
    +@@ -106166,7 +115664,7 @@ SQLITE_PRIVATE void sqlite3Pragma(
    +   }
    + 
    +   assert( pId2 );
    +-  zDb = pId2->n>0 ? pDb->zName : 0;
    ++  zDb = pId2->n>0 ? pDb->zDbSName : 0;
    +   if( sqlite3AuthCheck(pParse, SQLITE_PRAGMA, zLeft, zRight, zDb) ){
    +     goto pragma_out;
    +   }
    +@@ -106193,7 +115691,9 @@ SQLITE_PRIVATE void sqlite3Pragma(
    +   db->busyHandler.nBusy = 0;
    +   rc = sqlite3_file_control(db, zDb, SQLITE_FCNTL_PRAGMA, (void*)aFcntl);
    +   if( rc==SQLITE_OK ){
    +-    returnSingleText(v, "result", aFcntl[0]);
    ++    sqlite3VdbeSetNumCols(v, 1);
    ++    sqlite3VdbeSetColName(v, 0, COLNAME_NAME, aFcntl[0], SQLITE_TRANSIENT);
    ++    returnSingleText(v, aFcntl[0]);
    +     sqlite3_free(aFcntl[0]);
    +     goto pragma_out;
    +   }
    +@@ -106208,33 +115708,28 @@ SQLITE_PRIVATE void sqlite3Pragma(
    +   }
    + 
    +   /* Locate the pragma in the lookup table */
    +-  lwr = 0;
    +-  upr = ArraySize(aPragmaNames)-1;
    +-  while( lwr<=upr ){
    +-    mid = (lwr+upr)/2;
    +-    rc = sqlite3_stricmp(zLeft, aPragmaNames[mid].zName);
    +-    if( rc==0 ) break;
    +-    if( rc<0 ){
    +-      upr = mid - 1;
    +-    }else{
    +-      lwr = mid + 1;
    +-    }
    +-  }
    +-  if( lwr>upr ) goto pragma_out;
    +-  pPragma = &aPragmaNames[mid];
    ++  pPragma = pragmaLocate(zLeft);
    ++  if( pPragma==0 ) goto pragma_out;
    + 
    +   /* Make sure the database schema is loaded if the pragma requires that */
    +-  if( (pPragma->mPragFlag & PragFlag_NeedSchema)!=0 ){
    ++  if( (pPragma->mPragFlg & PragFlg_NeedSchema)!=0 ){
    +     if( sqlite3ReadSchema(pParse) ) goto pragma_out;
    +   }
    + 
    ++  /* Register the result column names for pragmas that return results */
    ++  if( (pPragma->mPragFlg & PragFlg_NoColumns)==0 
    ++   && ((pPragma->mPragFlg & PragFlg_NoColumns1)==0 || zRight==0)
    ++  ){
    ++    setPragmaResultColumnNames(v, pPragma);
    ++  }
    ++
    +   /* Jump to the appropriate pragma handler */
    +   switch( pPragma->ePragTyp ){
    +   
    + #if !defined(SQLITE_OMIT_PAGER_PRAGMAS) && !defined(SQLITE_OMIT_DEPRECATED)
    +   /*
    +-  **  PRAGMA [database.]default_cache_size
    +-  **  PRAGMA [database.]default_cache_size=N
    ++  **  PRAGMA [schema.]default_cache_size
    ++  **  PRAGMA [schema.]default_cache_size=N
    +   **
    +   ** The first form reports the current persistent setting for the
    +   ** page cache size.  The value returned is the maximum number of
    +@@ -106261,20 +115756,20 @@ SQLITE_PRIVATE void sqlite3Pragma(
    +       { OP_Noop,        0, 0,        0},
    +       { OP_ResultRow,   1, 1,        0},
    +     };
    +-    int addr;
    ++    VdbeOp *aOp;
    +     sqlite3VdbeUsesBtree(v, iDb);
    +     if( !zRight ){
    +-      setOneColumnName(v, "cache_size");
    +       pParse->nMem += 2;
    +-      addr = sqlite3VdbeAddOpList(v, ArraySize(getCacheSize), getCacheSize,iLn);
    +-      sqlite3VdbeChangeP1(v, addr, iDb);
    +-      sqlite3VdbeChangeP1(v, addr+1, iDb);
    +-      sqlite3VdbeChangeP1(v, addr+6, SQLITE_DEFAULT_CACHE_SIZE);
    ++      sqlite3VdbeVerifyNoMallocRequired(v, ArraySize(getCacheSize));
    ++      aOp = sqlite3VdbeAddOpList(v, ArraySize(getCacheSize), getCacheSize, iLn);
    ++      if( ONLY_IF_REALLOC_STRESS(aOp==0) ) break;
    ++      aOp[0].p1 = iDb;
    ++      aOp[1].p1 = iDb;
    ++      aOp[6].p1 = SQLITE_DEFAULT_CACHE_SIZE;
    +     }else{
    +       int size = sqlite3AbsInt32(sqlite3Atoi(zRight));
    +       sqlite3BeginWriteOperation(pParse, 0, iDb);
    +-      sqlite3VdbeAddOp2(v, OP_Integer, size, 1);
    +-      sqlite3VdbeAddOp3(v, OP_SetCookie, iDb, BTREE_DEFAULT_CACHE_SIZE, 1);
    ++      sqlite3VdbeAddOp3(v, OP_SetCookie, iDb, BTREE_DEFAULT_CACHE_SIZE, size);
    +       assert( sqlite3SchemaMutexHeld(db, iDb, 0) );
    +       pDb->pSchema->cache_size = size;
    +       sqlite3BtreeSetCacheSize(pDb->pBt, pDb->pSchema->cache_size);
    +@@ -106285,8 +115780,8 @@ SQLITE_PRIVATE void sqlite3Pragma(
    + 
    + #if !defined(SQLITE_OMIT_PAGER_PRAGMAS)
    +   /*
    +-  **  PRAGMA [database.]page_size
    +-  **  PRAGMA [database.]page_size=N
    ++  **  PRAGMA [schema.]page_size
    ++  **  PRAGMA [schema.]page_size=N
    +   **
    +   ** The first form reports the current setting for the
    +   ** database page size in bytes.  The second form sets the
    +@@ -106298,33 +115793,37 @@ SQLITE_PRIVATE void sqlite3Pragma(
    +     assert( pBt!=0 );
    +     if( !zRight ){
    +       int size = ALWAYS(pBt) ? sqlite3BtreeGetPageSize(pBt) : 0;
    +-      returnSingleInt(v, "page_size", size);
    ++      returnSingleInt(v, size);
    +     }else{
    +       /* Malloc may fail when setting the page-size, as there is an internal
    +       ** buffer that the pager module resizes using sqlite3_realloc().
    +       */
    +       db->nextPagesize = sqlite3Atoi(zRight);
    +       if( SQLITE_NOMEM==sqlite3BtreeSetPageSize(pBt, db->nextPagesize,-1,0) ){
    +-        db->mallocFailed = 1;
    ++        sqlite3OomFault(db);
    +       }
    +     }
    +     break;
    +   }
    + 
    +   /*
    +-  **  PRAGMA [database.]secure_delete
    +-  **  PRAGMA [database.]secure_delete=ON/OFF
    ++  **  PRAGMA [schema.]secure_delete
    ++  **  PRAGMA [schema.]secure_delete=ON/OFF/FAST
    +   **
    +   ** The first form reports the current setting for the
    +   ** secure_delete flag.  The second form changes the secure_delete
    +-  ** flag setting and reports thenew value.
    ++  ** flag setting and reports the new value.
    +   */
    +   case PragTyp_SECURE_DELETE: {
    +     Btree *pBt = pDb->pBt;
    +     int b = -1;
    +     assert( pBt!=0 );
    +     if( zRight ){
    +-      b = sqlite3GetBoolean(zRight, 0);
    ++      if( sqlite3_stricmp(zRight, "fast")==0 ){
    ++        b = 2;
    ++      }else{
    ++        b = sqlite3GetBoolean(zRight, 0);
    ++      }
    +     }
    +     if( pId2->n==0 && b>=0 ){
    +       int ii;
    +@@ -106333,13 +115832,13 @@ SQLITE_PRIVATE void sqlite3Pragma(
    +       }
    +     }
    +     b = sqlite3BtreeSecureDelete(pBt, b);
    +-    returnSingleInt(v, "secure_delete", b);
    ++    returnSingleInt(v, b);
    +     break;
    +   }
    + 
    +   /*
    +-  **  PRAGMA [database.]max_page_count
    +-  **  PRAGMA [database.]max_page_count=N
    ++  **  PRAGMA [schema.]max_page_count
    ++  **  PRAGMA [schema.]max_page_count=N
    +   **
    +   ** The first form reports the current setting for the
    +   ** maximum number of pages in the database file.  The 
    +@@ -106350,7 +115849,7 @@ SQLITE_PRIVATE void sqlite3Pragma(
    +   ** change.  The only purpose is to provide an easy way to test
    +   ** the sqlite3AbsInt32() function.
    +   **
    +-  **  PRAGMA [database.]page_count
    ++  **  PRAGMA [schema.]page_count
    +   **
    +   ** Return the number of pages in the specified database.
    +   */
    +@@ -106365,14 +115864,12 @@ SQLITE_PRIVATE void sqlite3Pragma(
    +                         sqlite3AbsInt32(sqlite3Atoi(zRight)));
    +     }
    +     sqlite3VdbeAddOp2(v, OP_ResultRow, iReg, 1);
    +-    sqlite3VdbeSetNumCols(v, 1);
    +-    sqlite3VdbeSetColName(v, 0, COLNAME_NAME, zLeft, SQLITE_TRANSIENT);
    +     break;
    +   }
    + 
    +   /*
    +-  **  PRAGMA [database.]locking_mode
    +-  **  PRAGMA [database.]locking_mode = (normal|exclusive)
    ++  **  PRAGMA [schema.]locking_mode
    ++  **  PRAGMA [schema.]locking_mode = (normal|exclusive)
    +   */
    +   case PragTyp_LOCKING_MODE: {
    +     const char *zRet = "normal";
    +@@ -106412,20 +115909,19 @@ SQLITE_PRIVATE void sqlite3Pragma(
    +     if( eMode==PAGER_LOCKINGMODE_EXCLUSIVE ){
    +       zRet = "exclusive";
    +     }
    +-    returnSingleText(v, "locking_mode", zRet);
    ++    returnSingleText(v, zRet);
    +     break;
    +   }
    + 
    +   /*
    +-  **  PRAGMA [database.]journal_mode
    +-  **  PRAGMA [database.]journal_mode =
    ++  **  PRAGMA [schema.]journal_mode
    ++  **  PRAGMA [schema.]journal_mode =
    +   **                      (delete|persist|off|truncate|memory|wal|off)
    +   */
    +   case PragTyp_JOURNAL_MODE: {
    +     int eMode;        /* One of the PAGER_JOURNALMODE_XXX symbols */
    +     int ii;           /* Loop counter */
    + 
    +-    setOneColumnName(v, "journal_mode");
    +     if( zRight==0 ){
    +       /* If there is no "=MODE" part of the pragma, do a query for the
    +       ** current mode */
    +@@ -106458,8 +115954,8 @@ SQLITE_PRIVATE void sqlite3Pragma(
    +   }
    + 
    +   /*
    +-  **  PRAGMA [database.]journal_size_limit
    +-  **  PRAGMA [database.]journal_size_limit=N
    ++  **  PRAGMA [schema.]journal_size_limit
    ++  **  PRAGMA [schema.]journal_size_limit=N
    +   **
    +   ** Get or set the size limit on rollback journal files.
    +   */
    +@@ -106471,15 +115967,15 @@ SQLITE_PRIVATE void sqlite3Pragma(
    +       if( iLimit<-1 ) iLimit = -1;
    +     }
    +     iLimit = sqlite3PagerJournalSizeLimit(pPager, iLimit);
    +-    returnSingleInt(v, "journal_size_limit", iLimit);
    ++    returnSingleInt(v, iLimit);
    +     break;
    +   }
    + 
    + #endif /* SQLITE_OMIT_PAGER_PRAGMAS */
    + 
    +   /*
    +-  **  PRAGMA [database.]auto_vacuum
    +-  **  PRAGMA [database.]auto_vacuum=N
    ++  **  PRAGMA [schema.]auto_vacuum
    ++  **  PRAGMA [schema.]auto_vacuum=N
    +   **
    +   ** Get or set the value of the database 'auto-vacuum' parameter.
    +   ** The value is one of:  0 NONE 1 FULL 2 INCREMENTAL
    +@@ -106489,7 +115985,7 @@ SQLITE_PRIVATE void sqlite3Pragma(
    +     Btree *pBt = pDb->pBt;
    +     assert( pBt!=0 );
    +     if( !zRight ){
    +-      returnSingleInt(v, "auto_vacuum", sqlite3BtreeGetAutoVacuum(pBt));
    ++      returnSingleInt(v, sqlite3BtreeGetAutoVacuum(pBt));
    +     }else{
    +       int eAuto = getAutoVacuum(zRight);
    +       assert( eAuto>=0 && eAuto<=2 );
    +@@ -106512,16 +116008,18 @@ SQLITE_PRIVATE void sqlite3Pragma(
    +           { OP_ReadCookie,     0,         1,         BTREE_LARGEST_ROOT_PAGE},
    +           { OP_If,             1,         0,                 0},    /* 2 */
    +           { OP_Halt,           SQLITE_OK, OE_Abort,          0},    /* 3 */
    +-          { OP_Integer,        0,         1,                 0},    /* 4 */
    +-          { OP_SetCookie,      0,         BTREE_INCR_VACUUM, 1},    /* 5 */
    ++          { OP_SetCookie,      0,         BTREE_INCR_VACUUM, 0},    /* 4 */
    +         };
    +-        int iAddr;
    +-        iAddr = sqlite3VdbeAddOpList(v, ArraySize(setMeta6), setMeta6, iLn);
    +-        sqlite3VdbeChangeP1(v, iAddr, iDb);
    +-        sqlite3VdbeChangeP1(v, iAddr+1, iDb);
    +-        sqlite3VdbeChangeP2(v, iAddr+2, iAddr+4);
    +-        sqlite3VdbeChangeP1(v, iAddr+4, eAuto-1);
    +-        sqlite3VdbeChangeP1(v, iAddr+5, iDb);
    ++        VdbeOp *aOp;
    ++        int iAddr = sqlite3VdbeCurrentAddr(v);
    ++        sqlite3VdbeVerifyNoMallocRequired(v, ArraySize(setMeta6));
    ++        aOp = sqlite3VdbeAddOpList(v, ArraySize(setMeta6), setMeta6, iLn);
    ++        if( ONLY_IF_REALLOC_STRESS(aOp==0) ) break;
    ++        aOp[0].p1 = iDb;
    ++        aOp[1].p1 = iDb;
    ++        aOp[2].p2 = iAddr+4;
    ++        aOp[4].p1 = iDb;
    ++        aOp[4].p3 = eAuto - 1;
    +         sqlite3VdbeUsesBtree(v, iDb);
    +       }
    +     }
    +@@ -106530,7 +116028,7 @@ SQLITE_PRIVATE void sqlite3Pragma(
    + #endif
    + 
    +   /*
    +-  **  PRAGMA [database.]incremental_vacuum(N)
    ++  **  PRAGMA [schema.]incremental_vacuum(N)
    +   **
    +   ** Do N steps of incremental vacuuming on a database.
    +   */
    +@@ -106553,8 +116051,8 @@ SQLITE_PRIVATE void sqlite3Pragma(
    + 
    + #ifndef SQLITE_OMIT_PAGER_PRAGMAS
    +   /*
    +-  **  PRAGMA [database.]cache_size
    +-  **  PRAGMA [database.]cache_size=N
    ++  **  PRAGMA [schema.]cache_size
    ++  **  PRAGMA [schema.]cache_size=N
    +   **
    +   ** The first form reports the current local setting for the
    +   ** page cache size. The second form sets the local
    +@@ -106566,19 +116064,60 @@ SQLITE_PRIVATE void sqlite3Pragma(
    +   case PragTyp_CACHE_SIZE: {
    +     assert( sqlite3SchemaMutexHeld(db, iDb, 0) );
    +     if( !zRight ){
    +-      if( sqlite3ReadSchema(pParse) ) goto pragma_out;
    +-      returnSingleInt(v, "cache_size", pDb->pSchema->cache_size);
    ++      returnSingleInt(v, pDb->pSchema->cache_size);
    +     }else{
    +       int size = sqlite3Atoi(zRight);
    +       pDb->pSchema->cache_size = size;
    +       sqlite3BtreeSetCacheSize(pDb->pBt, pDb->pSchema->cache_size);
    +-      if( sqlite3ReadSchema(pParse) ) goto pragma_out;
    +     }
    +     break;
    +   }
    + 
    +   /*
    +-  **  PRAGMA [database.]mmap_size(N)
    ++  **  PRAGMA [schema.]cache_spill
    ++  **  PRAGMA cache_spill=BOOLEAN
    ++  **  PRAGMA [schema.]cache_spill=N
    ++  **
    ++  ** The first form reports the current local setting for the
    ++  ** page cache spill size. The second form turns cache spill on
    ++  ** or off.  When turnning cache spill on, the size is set to the
    ++  ** current cache_size.  The third form sets a spill size that
    ++  ** may be different form the cache size.
    ++  ** If N is positive then that is the
    ++  ** number of pages in the cache.  If N is negative, then the
    ++  ** number of pages is adjusted so that the cache uses -N kibibytes
    ++  ** of memory.
    ++  **
    ++  ** If the number of cache_spill pages is less then the number of
    ++  ** cache_size pages, no spilling occurs until the page count exceeds
    ++  ** the number of cache_size pages.
    ++  **
    ++  ** The cache_spill=BOOLEAN setting applies to all attached schemas,
    ++  ** not just the schema specified.
    ++  */
    ++  case PragTyp_CACHE_SPILL: {
    ++    assert( sqlite3SchemaMutexHeld(db, iDb, 0) );
    ++    if( !zRight ){
    ++      returnSingleInt(v,
    ++         (db->flags & SQLITE_CacheSpill)==0 ? 0 : 
    ++            sqlite3BtreeSetSpillSize(pDb->pBt,0));
    ++    }else{
    ++      int size = 1;
    ++      if( sqlite3GetInt32(zRight, &size) ){
    ++        sqlite3BtreeSetSpillSize(pDb->pBt, size);
    ++      }
    ++      if( sqlite3GetBoolean(zRight, size!=0) ){
    ++        db->flags |= SQLITE_CacheSpill;
    ++      }else{
    ++        db->flags &= ~SQLITE_CacheSpill;
    ++      }
    ++      setAllPagerFlags(db);
    ++    }
    ++    break;
    ++  }
    ++
    ++  /*
    ++  **  PRAGMA [schema.]mmap_size(N)
    +   **
    +   ** Used to set mapping size limit. The mapping size limit is
    +   ** used to limit the aggregate size of all memory mapped regions of the
    +@@ -106613,7 +116152,7 @@ SQLITE_PRIVATE void sqlite3Pragma(
    +     rc = SQLITE_OK;
    + #endif
    +     if( rc==SQLITE_OK ){
    +-      returnSingleInt(v, "mmap_size", sz);
    ++      returnSingleInt(v, sz);
    +     }else if( rc!=SQLITE_NOTFOUND ){
    +       pParse->nErr++;
    +       pParse->rc = rc;
    +@@ -106634,7 +116173,7 @@ SQLITE_PRIVATE void sqlite3Pragma(
    +   */
    +   case PragTyp_TEMP_STORE: {
    +     if( !zRight ){
    +-      returnSingleInt(v, "temp_store", db->temp_store);
    ++      returnSingleInt(v, db->temp_store);
    +     }else{
    +       changeTempStorage(pParse, zRight);
    +     }
    +@@ -106653,7 +116192,7 @@ SQLITE_PRIVATE void sqlite3Pragma(
    +   */
    +   case PragTyp_TEMP_STORE_DIRECTORY: {
    +     if( !zRight ){
    +-      returnSingleText(v, "temp_store_directory", sqlite3_temp_directory);
    ++      returnSingleText(v, sqlite3_temp_directory);
    +     }else{
    + #ifndef SQLITE_OMIT_WSD
    +       if( zRight[0] ){
    +@@ -106697,7 +116236,7 @@ SQLITE_PRIVATE void sqlite3Pragma(
    +   */
    +   case PragTyp_DATA_STORE_DIRECTORY: {
    +     if( !zRight ){
    +-      returnSingleText(v, "data_store_directory", sqlite3_data_directory);
    ++      returnSingleText(v, sqlite3_data_directory);
    +     }else{
    + #ifndef SQLITE_OMIT_WSD
    +       if( zRight[0] ){
    +@@ -106722,8 +116261,8 @@ SQLITE_PRIVATE void sqlite3Pragma(
    + 
    + #if SQLITE_ENABLE_LOCKING_STYLE
    +   /*
    +-  **   PRAGMA [database.]lock_proxy_file
    +-  **   PRAGMA [database.]lock_proxy_file = ":auto:"|"lock_file_path"
    ++  **   PRAGMA [schema.]lock_proxy_file
    ++  **   PRAGMA [schema.]lock_proxy_file = ":auto:"|"lock_file_path"
    +   **
    +   ** Return or set the value of the lock_proxy_file flag.  Changing
    +   ** the value sets a specific file to be used for database access locks.
    +@@ -106736,7 +116275,7 @@ SQLITE_PRIVATE void sqlite3Pragma(
    +       sqlite3_file *pFile = sqlite3PagerFile(pPager);
    +       sqlite3OsFileControlHint(pFile, SQLITE_GET_LOCKPROXYFILE, 
    +                            &proxy_file_path);
    +-      returnSingleText(v, "lock_proxy_file", proxy_file_path);
    ++      returnSingleText(v, proxy_file_path);
    +     }else{
    +       Pager *pPager = sqlite3BtreePager(pDb->pBt);
    +       sqlite3_file *pFile = sqlite3PagerFile(pPager);
    +@@ -106758,8 +116297,8 @@ SQLITE_PRIVATE void sqlite3Pragma(
    + #endif /* SQLITE_ENABLE_LOCKING_STYLE */      
    +     
    +   /*
    +-  **   PRAGMA [database.]synchronous
    +-  **   PRAGMA [database.]synchronous=OFF|ON|NORMAL|FULL
    ++  **   PRAGMA [schema.]synchronous
    ++  **   PRAGMA [schema.]synchronous=OFF|ON|NORMAL|FULL|EXTRA
    +   **
    +   ** Return or set the local value of the synchronous flag.  Changing
    +   ** the local value does not make changes to the disk file and the
    +@@ -106768,15 +116307,16 @@ SQLITE_PRIVATE void sqlite3Pragma(
    +   */
    +   case PragTyp_SYNCHRONOUS: {
    +     if( !zRight ){
    +-      returnSingleInt(v, "synchronous", pDb->safety_level-1);
    ++      returnSingleInt(v, pDb->safety_level-1);
    +     }else{
    +       if( !db->autoCommit ){
    +         sqlite3ErrorMsg(pParse, 
    +             "Safety level may not be changed inside a transaction");
    +-      }else{
    ++      }else if( iDb!=1 ){
    +         int iLevel = (getSafetyLevel(zRight,0,1)+1) & PAGER_SYNCHRONOUS_MASK;
    +         if( iLevel==0 ) iLevel = 1;
    +         pDb->safety_level = iLevel;
    ++        pDb->bSyncSet = 1;
    +         setAllPagerFlags(db);
    +       }
    +     }
    +@@ -106787,7 +116327,8 @@ SQLITE_PRIVATE void sqlite3Pragma(
    + #ifndef SQLITE_OMIT_FLAG_PRAGMAS
    +   case PragTyp_FLAG: {
    +     if( zRight==0 ){
    +-      returnSingleInt(v, pPragma->zName, (db->flags & pPragma->iArg)!=0 );
    ++      setPragmaResultColumnNames(v, pPragma);
    ++      returnSingleInt(v, (db->flags & pPragma->iArg)!=0 );
    +     }else{
    +       int mask = pPragma->iArg;    /* Mask of bits to set or clear. */
    +       if( db->autoCommit==0 ){
    +@@ -106813,7 +116354,7 @@ SQLITE_PRIVATE void sqlite3Pragma(
    +       ** compiler (eg. count_changes). So add an opcode to expire all
    +       ** compiled SQL statements after modifying a pragma value.
    +       */
    +-      sqlite3VdbeAddOp2(v, OP_Expire, 0, 0);
    ++      sqlite3VdbeAddOp0(v, OP_Expire);
    +       setAllPagerFlags(db);
    +     }
    +     break;
    +@@ -106832,21 +116373,18 @@ SQLITE_PRIVATE void sqlite3Pragma(
    +   ** type:       Column declaration type.
    +   ** notnull:    True if 'NOT NULL' is part of column declaration
    +   ** dflt_value: The default value for the column, if any.
    ++  ** pk:         Non-zero for PK fields.
    +   */
    +   case PragTyp_TABLE_INFO: if( zRight ){
    +     Table *pTab;
    +-    pTab = sqlite3FindTable(db, zRight, zDb);
    ++    pTab = sqlite3LocateTable(pParse, LOCATE_NOERR, zRight, zDb);
    +     if( pTab ){
    +-      static const char *azCol[] = {
    +-         "cid", "name", "type", "notnull", "dflt_value", "pk"
    +-      };
    +       int i, k;
    +       int nHidden = 0;
    +       Column *pCol;
    +       Index *pPk = sqlite3PrimaryKeyIndex(pTab);
    +       pParse->nMem = 6;
    +       sqlite3CodeVerifySchema(pParse, iDb);
    +-      setAllColumnNames(v, 6, azCol); assert( 6==ArraySize(azCol) );
    +       sqlite3ViewGetColumnNames(pParse, pTab);
    +       for(i=0, pCol=pTab->aCol; i<pTab->nCol; i++, pCol++){
    +         if( IsHiddenColumn(pCol) ){
    +@@ -106860,54 +116398,51 @@ SQLITE_PRIVATE void sqlite3Pragma(
    +         }else{
    +           for(k=1; k<=pTab->nCol && pPk->aiColumn[k-1]!=i; k++){}
    +         }
    ++        assert( pCol->pDflt==0 || pCol->pDflt->op==TK_SPAN );
    +         sqlite3VdbeMultiLoad(v, 1, "issisi",
    +                i-nHidden,
    +                pCol->zName,
    +-               pCol->zType ? pCol->zType : "",
    ++               sqlite3ColumnType(pCol,""),
    +                pCol->notNull ? 1 : 0,
    +-               pCol->zDflt,
    ++               pCol->pDflt ? pCol->pDflt->u.zToken : 0,
    +                k);
    +-        sqlite3VdbeAddOp2(v, OP_ResultRow, 1, 6);
    +       }
    +     }
    +   }
    +   break;
    + 
    ++#ifdef SQLITE_DEBUG
    +   case PragTyp_STATS: {
    +-    static const char *azCol[] = { "table", "index", "width", "height" };
    +     Index *pIdx;
    +     HashElem *i;
    +-    v = sqlite3GetVdbe(pParse);
    +-    pParse->nMem = 4;
    ++    pParse->nMem = 5;
    +     sqlite3CodeVerifySchema(pParse, iDb);
    +-    setAllColumnNames(v, 4, azCol);  assert( 4==ArraySize(azCol) );
    +     for(i=sqliteHashFirst(&pDb->pSchema->tblHash); i; i=sqliteHashNext(i)){
    +       Table *pTab = sqliteHashData(i);
    +-      sqlite3VdbeMultiLoad(v, 1, "ssii",
    ++      sqlite3VdbeMultiLoad(v, 1, "ssiii",
    +            pTab->zName,
    +            0,
    +-           (int)sqlite3LogEstToInt(pTab->szTabRow),
    +-           (int)sqlite3LogEstToInt(pTab->nRowLogEst));
    +-      sqlite3VdbeAddOp2(v, OP_ResultRow, 1, 4);
    ++           pTab->szTabRow,
    ++           pTab->nRowLogEst,
    ++           pTab->tabFlags);
    +       for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){
    +-        sqlite3VdbeMultiLoad(v, 2, "sii",
    ++        sqlite3VdbeMultiLoad(v, 2, "siiiX",
    +            pIdx->zName,
    +-           (int)sqlite3LogEstToInt(pIdx->szIdxRow),
    +-           (int)sqlite3LogEstToInt(pIdx->aiRowLogEst[0]));
    +-        sqlite3VdbeAddOp2(v, OP_ResultRow, 1, 4);
    ++           pIdx->szIdxRow,
    ++           pIdx->aiRowLogEst[0],
    ++           pIdx->hasStat1);
    ++        sqlite3VdbeAddOp2(v, OP_ResultRow, 1, 5);
    +       }
    +     }
    +   }
    +   break;
    ++#endif
    + 
    +   case PragTyp_INDEX_INFO: if( zRight ){
    +     Index *pIdx;
    +     Table *pTab;
    +     pIdx = sqlite3FindIndex(db, zRight, zDb);
    +     if( pIdx ){
    +-      static const char *azCol[] = {
    +-         "seqno", "cid", "name", "desc", "coll", "key"
    +-      };
    +       int i;
    +       int mx;
    +       if( pPragma->iArg ){
    +@@ -106921,14 +116456,13 @@ SQLITE_PRIVATE void sqlite3Pragma(
    +       }
    +       pTab = pIdx->pTable;
    +       sqlite3CodeVerifySchema(pParse, iDb);
    +-      assert( pParse->nMem<=ArraySize(azCol) );
    +-      setAllColumnNames(v, pParse->nMem, azCol);
    ++      assert( pParse->nMem<=pPragma->nPragCName );
    +       for(i=0; i<mx; i++){
    +         i16 cnum = pIdx->aiColumn[i];
    +-        sqlite3VdbeMultiLoad(v, 1, "iis", i, cnum,
    ++        sqlite3VdbeMultiLoad(v, 1, "iisX", i, cnum,
    +                              cnum<0 ? 0 : pTab->aCol[cnum].zName);
    +         if( pPragma->iArg ){
    +-          sqlite3VdbeMultiLoad(v, 4, "isi",
    ++          sqlite3VdbeMultiLoad(v, 4, "isiX",
    +             pIdx->aSortOrder[i],
    +             pIdx->azColl[i],
    +             i<pIdx->nKeyCol);
    +@@ -106945,13 +116479,8 @@ SQLITE_PRIVATE void sqlite3Pragma(
    +     int i;
    +     pTab = sqlite3FindTable(db, zRight, zDb);
    +     if( pTab ){
    +-      static const char *azCol[] = {
    +-        "seq", "name", "unique", "origin", "partial"
    +-      };
    +-      v = sqlite3GetVdbe(pParse);
    +       pParse->nMem = 5;
    +       sqlite3CodeVerifySchema(pParse, iDb);
    +-      setAllColumnNames(v, 5, azCol);  assert( 5==ArraySize(azCol) );
    +       for(pIdx=pTab->pIndex, i=0; pIdx; pIdx=pIdx->pNext, i++){
    +         const char *azOrigin[] = { "c", "u", "pk" };
    +         sqlite3VdbeMultiLoad(v, 1, "isisi",
    +@@ -106960,42 +116489,75 @@ SQLITE_PRIVATE void sqlite3Pragma(
    +            IsUniqueIndex(pIdx),
    +            azOrigin[pIdx->idxType],
    +            pIdx->pPartIdxWhere!=0);
    +-        sqlite3VdbeAddOp2(v, OP_ResultRow, 1, 5);
    +       }
    +     }
    +   }
    +   break;
    + 
    +   case PragTyp_DATABASE_LIST: {
    +-    static const char *azCol[] = { "seq", "name", "file" };
    +     int i;
    +     pParse->nMem = 3;
    +-    setAllColumnNames(v, 3, azCol); assert( 3==ArraySize(azCol) );
    +     for(i=0; i<db->nDb; i++){
    +       if( db->aDb[i].pBt==0 ) continue;
    +-      assert( db->aDb[i].zName!=0 );
    ++      assert( db->aDb[i].zDbSName!=0 );
    +       sqlite3VdbeMultiLoad(v, 1, "iss",
    +          i,
    +-         db->aDb[i].zName,
    ++         db->aDb[i].zDbSName,
    +          sqlite3BtreeGetFilename(db->aDb[i].pBt));
    +-      sqlite3VdbeAddOp2(v, OP_ResultRow, 1, 3);
    +     }
    +   }
    +   break;
    + 
    +   case PragTyp_COLLATION_LIST: {
    +-    static const char *azCol[] = { "seq", "name" };
    +     int i = 0;
    +     HashElem *p;
    +     pParse->nMem = 2;
    +-    setAllColumnNames(v, 2, azCol); assert( 2==ArraySize(azCol) );
    +     for(p=sqliteHashFirst(&db->aCollSeq); p; p=sqliteHashNext(p)){
    +       CollSeq *pColl = (CollSeq *)sqliteHashData(p);
    +       sqlite3VdbeMultiLoad(v, 1, "is", i++, pColl->zName);
    +-      sqlite3VdbeAddOp2(v, OP_ResultRow, 1, 2);
    +     }
    +   }
    +   break;
    ++
    ++#ifdef SQLITE_INTROSPECTION_PRAGMAS
    ++  case PragTyp_FUNCTION_LIST: {
    ++    int i;
    ++    HashElem *j;
    ++    FuncDef *p;
    ++    pParse->nMem = 2;
    ++    for(i=0; i<SQLITE_FUNC_HASH_SZ; i++){
    ++      for(p=sqlite3BuiltinFunctions.a[i]; p; p=p->u.pHash ){
    ++        sqlite3VdbeMultiLoad(v, 1, "si", p->zName, 1);
    ++      }
    ++    }
    ++    for(j=sqliteHashFirst(&db->aFunc); j; j=sqliteHashNext(j)){
    ++      p = (FuncDef*)sqliteHashData(j);
    ++      sqlite3VdbeMultiLoad(v, 1, "si", p->zName, 0);
    ++    }
    ++  }
    ++  break;
    ++
    ++#ifndef SQLITE_OMIT_VIRTUALTABLE
    ++  case PragTyp_MODULE_LIST: {
    ++    HashElem *j;
    ++    pParse->nMem = 1;
    ++    for(j=sqliteHashFirst(&db->aModule); j; j=sqliteHashNext(j)){
    ++      Module *pMod = (Module*)sqliteHashData(j);
    ++      sqlite3VdbeMultiLoad(v, 1, "s", pMod->zName);
    ++    }
    ++  }
    ++  break;
    ++#endif /* SQLITE_OMIT_VIRTUALTABLE */
    ++
    ++  case PragTyp_PRAGMA_LIST: {
    ++    int i;
    ++    for(i=0; i<ArraySize(aPragmaName); i++){
    ++      sqlite3VdbeMultiLoad(v, 1, "s", aPragmaName[i].zName);
    ++    }
    ++  }
    ++  break;
    ++#endif /* SQLITE_INTROSPECTION_PRAGMAS */
    ++
    + #endif /* SQLITE_OMIT_SCHEMA_PRAGMAS */
    + 
    + #ifndef SQLITE_OMIT_FOREIGN_KEY
    +@@ -107004,17 +116566,11 @@ SQLITE_PRIVATE void sqlite3Pragma(
    +     Table *pTab;
    +     pTab = sqlite3FindTable(db, zRight, zDb);
    +     if( pTab ){
    +-      v = sqlite3GetVdbe(pParse);
    +       pFK = pTab->pFKey;
    +       if( pFK ){
    +-        static const char *azCol[] = {
    +-           "id", "seq", "table", "from", "to", "on_update", "on_delete",
    +-           "match"
    +-        };
    +         int i = 0; 
    +         pParse->nMem = 8;
    +         sqlite3CodeVerifySchema(pParse, iDb);
    +-        setAllColumnNames(v, 8, azCol); assert( 8==ArraySize(azCol) );
    +         while(pFK){
    +           int j;
    +           for(j=0; j<pFK->nCol; j++){
    +@@ -107027,7 +116583,6 @@ SQLITE_PRIVATE void sqlite3Pragma(
    +                    actionName(pFK->aAction[1]),  /* ON UPDATE */
    +                    actionName(pFK->aAction[0]),  /* ON DELETE */
    +                    "NONE");
    +-            sqlite3VdbeAddOp2(v, OP_ResultRow, 1, 8);
    +           }
    +           ++i;
    +           pFK = pFK->pNextFrom;
    +@@ -107055,14 +116610,11 @@ SQLITE_PRIVATE void sqlite3Pragma(
    +     int addrTop;           /* Top of a loop checking foreign keys */
    +     int addrOk;            /* Jump here if the key is OK */
    +     int *aiCols;           /* child to parent column mapping */
    +-    static const char *azCol[] = { "table", "rowid", "parent", "fkid" };
    + 
    +     regResult = pParse->nMem+1;
    +     pParse->nMem += 4;
    +     regKey = ++pParse->nMem;
    +     regRow = ++pParse->nMem;
    +-    v = sqlite3GetVdbe(pParse);
    +-    setAllColumnNames(v, 4, azCol); assert( 4==ArraySize(azCol) );
    +     sqlite3CodeVerifySchema(pParse, iDb);
    +     k = sqliteHashFirst(&db->aDb[iDb].pSchema->tblHash);
    +     while( k ){
    +@@ -107109,36 +116661,38 @@ SQLITE_PRIVATE void sqlite3Pragma(
    +           assert( x==0 );
    +         }
    +         addrOk = sqlite3VdbeMakeLabel(v);
    +-        if( pParent && pIdx==0 ){
    +-          int iKey = pFK->aCol[0].iFrom;
    +-          assert( iKey>=0 && iKey<pTab->nCol );
    +-          if( iKey!=pTab->iPKey ){
    +-            sqlite3VdbeAddOp3(v, OP_Column, 0, iKey, regRow);
    +-            sqlite3ColumnDefault(v, pTab, iKey, regRow);
    +-            sqlite3VdbeAddOp2(v, OP_IsNull, regRow, addrOk); VdbeCoverage(v);
    +-            sqlite3VdbeAddOp2(v, OP_MustBeInt, regRow, 
    +-               sqlite3VdbeCurrentAddr(v)+3); VdbeCoverage(v);
    +-          }else{
    +-            sqlite3VdbeAddOp2(v, OP_Rowid, 0, regRow);
    +-          }
    +-          sqlite3VdbeAddOp3(v, OP_NotExists, i, 0, regRow); VdbeCoverage(v);
    ++
    ++        /* Generate code to read the child key values into registers
    ++        ** regRow..regRow+n. If any of the child key values are NULL, this 
    ++        ** row cannot cause an FK violation. Jump directly to addrOk in 
    ++        ** this case. */
    ++        for(j=0; j<pFK->nCol; j++){
    ++          int iCol = aiCols ? aiCols[j] : pFK->aCol[j].iFrom;
    ++          sqlite3ExprCodeGetColumnOfTable(v, pTab, 0, iCol, regRow+j);
    ++          sqlite3VdbeAddOp2(v, OP_IsNull, regRow+j, addrOk); VdbeCoverage(v);
    ++        }
    ++
    ++        /* Generate code to query the parent index for a matching parent
    ++        ** key. If a match is found, jump to addrOk. */
    ++        if( pIdx ){
    ++          sqlite3VdbeAddOp4(v, OP_MakeRecord, regRow, pFK->nCol, regKey,
    ++              sqlite3IndexAffinityStr(db,pIdx), pFK->nCol);
    ++          sqlite3VdbeAddOp4Int(v, OP_Found, i, addrOk, regKey, 0);
    ++          VdbeCoverage(v);
    ++        }else if( pParent ){
    ++          int jmp = sqlite3VdbeCurrentAddr(v)+2;
    ++          sqlite3VdbeAddOp3(v, OP_SeekRowid, i, jmp, regRow); VdbeCoverage(v);
    +           sqlite3VdbeGoto(v, addrOk);
    +-          sqlite3VdbeJumpHere(v, sqlite3VdbeCurrentAddr(v)-2);
    ++          assert( pFK->nCol==1 );
    ++        }
    ++
    ++        /* Generate code to report an FK violation to the caller. */
    ++        if( HasRowid(pTab) ){
    ++          sqlite3VdbeAddOp2(v, OP_Rowid, 0, regResult+1);
    +         }else{
    +-          for(j=0; j<pFK->nCol; j++){
    +-            sqlite3ExprCodeGetColumnOfTable(v, pTab, 0,
    +-                            aiCols ? aiCols[j] : pFK->aCol[j].iFrom, regRow+j);
    +-            sqlite3VdbeAddOp2(v, OP_IsNull, regRow+j, addrOk); VdbeCoverage(v);
    +-          }
    +-          if( pParent ){
    +-            sqlite3VdbeAddOp4(v, OP_MakeRecord, regRow, pFK->nCol, regKey,
    +-                              sqlite3IndexAffinityStr(db,pIdx), pFK->nCol);
    +-            sqlite3VdbeAddOp4Int(v, OP_Found, i, addrOk, regKey, 0);
    +-            VdbeCoverage(v);
    +-          }
    ++          sqlite3VdbeAddOp2(v, OP_Null, 0, regResult+1);
    +         }
    +-        sqlite3VdbeAddOp2(v, OP_Rowid, 0, regResult+1);
    +-        sqlite3VdbeMultiLoad(v, regResult+2, "si", pFK->zTo, i-1);
    ++        sqlite3VdbeMultiLoad(v, regResult+2, "siX", pFK->zTo, i-1);
    +         sqlite3VdbeAddOp2(v, OP_ResultRow, regResult, 4);
    +         sqlite3VdbeResolveLabel(v, addrOk);
    +         sqlite3DbFree(db, aiCols);
    +@@ -107155,7 +116709,7 @@ SQLITE_PRIVATE void sqlite3Pragma(
    +   case PragTyp_PARSER_TRACE: {
    +     if( zRight ){
    +       if( sqlite3GetBoolean(zRight, 0) ){
    +-        sqlite3ParserTrace(stderr, "parser: ");
    ++        sqlite3ParserTrace(stdout, "parser: ");
    +       }else{
    +         sqlite3ParserTrace(0, 0);
    +       }
    +@@ -107179,25 +116733,21 @@ SQLITE_PRIVATE void sqlite3Pragma(
    + #endif
    + 
    + #ifndef SQLITE_OMIT_INTEGRITY_CHECK
    +-  /* Pragma "quick_check" is reduced version of 
    ++  /*    PRAGMA integrity_check
    ++  **    PRAGMA integrity_check(N)
    ++  **    PRAGMA quick_check
    ++  **    PRAGMA quick_check(N)
    ++  **
    ++  ** Verify the integrity of the database.
    ++  **
    ++  ** The "quick_check" is reduced version of 
    +   ** integrity_check designed to detect most database corruption
    +-  ** without most of the overhead of a full integrity-check.
    ++  ** without the overhead of cross-checking indexes.  Quick_check
    ++  ** is linear time wherease integrity_check is O(NlogN).
    +   */
    +   case PragTyp_INTEGRITY_CHECK: {
    +     int i, j, addr, mxErr;
    + 
    +-    /* Code that appears at the end of the integrity check.  If no error
    +-    ** messages have been generated, output OK.  Otherwise output the
    +-    ** error message
    +-    */
    +-    static const int iLn = VDBE_OFFSET_LINENO(2);
    +-    static const VdbeOpList endCode[] = {
    +-      { OP_AddImm,      1, 0,        0},    /* 0 */
    +-      { OP_If,          1, 0,        0},    /* 1 */
    +-      { OP_String8,     0, 3,        0},    /* 2 */
    +-      { OP_ResultRow,   3, 1,        0},
    +-    };
    +-
    +     int isQuick = (sqlite3Tolower(zLeft[0])=='q');
    + 
    +     /* If the PRAGMA command was of the form "PRAGMA <db>.integrity_check",
    +@@ -107215,7 +116765,6 @@ SQLITE_PRIVATE void sqlite3Pragma(
    + 
    +     /* Initialize the VDBE program */
    +     pParse->nMem = 6;
    +-    setOneColumnName(v, "integrity_check");
    + 
    +     /* Set the maximum error count */
    +     mxErr = SQLITE_INTEGRITY_CHECK_ERROR_MAX;
    +@@ -107225,63 +116774,66 @@ SQLITE_PRIVATE void sqlite3Pragma(
    +         mxErr = SQLITE_INTEGRITY_CHECK_ERROR_MAX;
    +       }
    +     }
    +-    sqlite3VdbeAddOp2(v, OP_Integer, mxErr, 1);  /* reg[1] holds errors left */
    ++    sqlite3VdbeAddOp2(v, OP_Integer, mxErr-1, 1); /* reg[1] holds errors left */
    + 
    +     /* Do an integrity check on each database file */
    +     for(i=0; i<db->nDb; i++){
    +-      HashElem *x;
    +-      Hash *pTbls;
    +-      int cnt = 0;
    ++      HashElem *x;     /* For looping over tables in the schema */
    ++      Hash *pTbls;     /* Set of all tables in the schema */
    ++      int *aRoot;      /* Array of root page numbers of all btrees */
    ++      int cnt = 0;     /* Number of entries in aRoot[] */
    ++      int mxIdx = 0;   /* Maximum number of indexes for any table */
    + 
    +       if( OMIT_TEMPDB && i==1 ) continue;
    +       if( iDb>=0 && i!=iDb ) continue;
    + 
    +       sqlite3CodeVerifySchema(pParse, i);
    +-      addr = sqlite3VdbeAddOp1(v, OP_IfPos, 1); /* Halt if out of errors */
    +-      VdbeCoverage(v);
    +-      sqlite3VdbeAddOp2(v, OP_Halt, 0, 0);
    +-      sqlite3VdbeJumpHere(v, addr);
    + 
    +       /* Do an integrity check of the B-Tree
    +       **
    +-      ** Begin by filling registers 2, 3, ... with the root pages numbers
    ++      ** Begin by finding the root pages numbers
    +       ** for all tables and indices in the database.
    +       */
    +       assert( sqlite3SchemaMutexHeld(db, i, 0) );
    +       pTbls = &db->aDb[i].pSchema->tblHash;
    +-      for(x=sqliteHashFirst(pTbls); x; x=sqliteHashNext(x)){
    ++      for(cnt=0, x=sqliteHashFirst(pTbls); x; x=sqliteHashNext(x)){
    ++        Table *pTab = sqliteHashData(x);  /* Current table */
    ++        Index *pIdx;                      /* An index on pTab */
    ++        int nIdx;                         /* Number of indexes on pTab */
    ++        if( HasRowid(pTab) ) cnt++;
    ++        for(nIdx=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, nIdx++){ cnt++; }
    ++        if( nIdx>mxIdx ) mxIdx = nIdx;
    ++      }
    ++      aRoot = sqlite3DbMallocRawNN(db, sizeof(int)*(cnt+1));
    ++      if( aRoot==0 ) break;
    ++      for(cnt=0, x=sqliteHashFirst(pTbls); x; x=sqliteHashNext(x)){
    +         Table *pTab = sqliteHashData(x);
    +         Index *pIdx;
    +-        if( HasRowid(pTab) ){
    +-          sqlite3VdbeAddOp2(v, OP_Integer, pTab->tnum, 2+cnt);
    +-          VdbeComment((v, "%s", pTab->zName));
    +-          cnt++;
    +-        }
    ++        if( HasRowid(pTab) ) aRoot[++cnt] = pTab->tnum;
    +         for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){
    +-          sqlite3VdbeAddOp2(v, OP_Integer, pIdx->tnum, 2+cnt);
    +-          VdbeComment((v, "%s", pIdx->zName));
    +-          cnt++;
    ++          aRoot[++cnt] = pIdx->tnum;
    +         }
    +       }
    ++      aRoot[0] = cnt;
    + 
    +       /* Make sure sufficient number of registers have been allocated */
    +-      pParse->nMem = MAX( pParse->nMem, cnt+8 );
    ++      pParse->nMem = MAX( pParse->nMem, 8+mxIdx );
    ++      sqlite3ClearTempRegCache(pParse);
    + 
    +       /* Do the b-tree integrity checks */
    +-      sqlite3VdbeAddOp3(v, OP_IntegrityCk, 2, cnt, 1);
    ++      sqlite3VdbeAddOp4(v, OP_IntegrityCk, 2, cnt, 1, (char*)aRoot,P4_INTARRAY);
    +       sqlite3VdbeChangeP5(v, (u8)i);
    +       addr = sqlite3VdbeAddOp1(v, OP_IsNull, 2); VdbeCoverage(v);
    +       sqlite3VdbeAddOp4(v, OP_String8, 0, 3, 0,
    +-         sqlite3MPrintf(db, "*** in database %s ***\n", db->aDb[i].zName),
    ++         sqlite3MPrintf(db, "*** in database %s ***\n", db->aDb[i].zDbSName),
    +          P4_DYNAMIC);
    +-      sqlite3VdbeAddOp3(v, OP_Move, 2, 4, 1);
    +-      sqlite3VdbeAddOp3(v, OP_Concat, 4, 3, 2);
    +-      sqlite3VdbeAddOp2(v, OP_ResultRow, 2, 1);
    ++      sqlite3VdbeAddOp3(v, OP_Concat, 2, 3, 3);
    ++      integrityCheckResultRow(v);
    +       sqlite3VdbeJumpHere(v, addr);
    + 
    +       /* Make sure all the indices are constructed correctly.
    +       */
    +-      for(x=sqliteHashFirst(pTbls); x && !isQuick; x=sqliteHashNext(x)){
    ++      for(x=sqliteHashFirst(pTbls); x; x=sqliteHashNext(x)){
    +         Table *pTab = sqliteHashData(x);
    +         Index *pIdx, *pPk;
    +         Index *pPrior = 0;
    +@@ -107289,115 +116841,156 @@ SQLITE_PRIVATE void sqlite3Pragma(
    +         int iDataCur, iIdxCur;
    +         int r1 = -1;
    + 
    +-        if( pTab->pIndex==0 ) continue;
    ++        if( pTab->tnum<1 ) continue;  /* Skip VIEWs or VIRTUAL TABLEs */
    +         pPk = HasRowid(pTab) ? 0 : sqlite3PrimaryKeyIndex(pTab);
    +-        addr = sqlite3VdbeAddOp1(v, OP_IfPos, 1);  /* Stop if out of errors */
    +-        VdbeCoverage(v);
    +-        sqlite3VdbeAddOp2(v, OP_Halt, 0, 0);
    +-        sqlite3VdbeJumpHere(v, addr);
    +         sqlite3ExprCacheClear(pParse);
    +-        sqlite3OpenTableAndIndices(pParse, pTab, OP_OpenRead,
    ++        sqlite3OpenTableAndIndices(pParse, pTab, OP_OpenRead, 0,
    +                                    1, 0, &iDataCur, &iIdxCur);
    ++        /* reg[7] counts the number of entries in the table.
    ++        ** reg[8+i] counts the number of entries in the i-th index 
    ++        */
    +         sqlite3VdbeAddOp2(v, OP_Integer, 0, 7);
    +         for(j=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, j++){
    +           sqlite3VdbeAddOp2(v, OP_Integer, 0, 8+j); /* index entries counter */
    +         }
    +-        pParse->nMem = MAX(pParse->nMem, 8+j);
    ++        assert( pParse->nMem>=8+j );
    ++        assert( sqlite3NoTempsInRange(pParse,1,7+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; j<pTab->nCol; j++){
    +           char *zErr;
    +-          int jmp2, jmp3;
    ++          int jmp2;
    +           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);
    ++          integrityCheckResultRow(v);
    +           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, 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 */
    +-          /* 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 */
    +-          sqlite3VdbeLoadString(v, 3, "row ");
    +-          sqlite3VdbeAddOp3(v, OP_Concat, 7, 3, 3);
    +-          sqlite3VdbeLoadString(v, 4, " missing from index ");
    +-          sqlite3VdbeAddOp3(v, OP_Concat, 4, 3, 3);
    +-          jmp5 = sqlite3VdbeLoadString(v, 4, pIdx->zName);
    +-          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, jmp2);
    +-          /* 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; kk<pIdx->nKeyCol; kk++){
    +-              int iCol = pIdx->aiColumn[kk];
    +-              assert( iCol!=XN_ROWID && iCol<pTab->nCol );
    +-              if( iCol>=0 && pTab->aCol[iCol].notNull ) continue;
    +-              sqlite3VdbeAddOp2(v, OP_IsNull, r1+kk, uniqOk);
    +-              VdbeCoverage(v);
    ++        /* Verify CHECK constraints */
    ++        if( pTab->pCheck && (db->flags & SQLITE_IgnoreChecks)==0 ){
    ++          ExprList *pCheck = sqlite3ExprListDup(db, pTab->pCheck, 0);
    ++          if( db->mallocFailed==0 ){
    ++            int addrCkFault = sqlite3VdbeMakeLabel(v);
    ++            int addrCkOk = sqlite3VdbeMakeLabel(v);
    ++            char *zErr;
    ++            int k;
    ++            pParse->iSelfTab = iDataCur + 1;
    ++            sqlite3ExprCachePush(pParse);
    ++            for(k=pCheck->nExpr-1; k>0; k--){
    ++              sqlite3ExprIfFalse(pParse, pCheck->a[k].pExpr, addrCkFault, 0);
    +             }
    +-            jmp6 = sqlite3VdbeAddOp1(v, OP_Next, iIdxCur+j); VdbeCoverage(v);
    +-            sqlite3VdbeGoto(v, 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 */
    +-            sqlite3VdbeLoadString(v, 3, "non-unique entry in index ");
    +-            sqlite3VdbeGoto(v, jmp5);
    +-            sqlite3VdbeResolveLabel(v, uniqOk);
    ++            sqlite3ExprIfTrue(pParse, pCheck->a[0].pExpr, addrCkOk, 
    ++                SQLITE_JUMPIFNULL);
    ++            sqlite3VdbeResolveLabel(v, addrCkFault);
    ++            pParse->iSelfTab = 0;
    ++            zErr = sqlite3MPrintf(db, "CHECK constraint failed in %s",
    ++                pTab->zName);
    ++            sqlite3VdbeAddOp4(v, OP_String8, 0, 3, 0, zErr, P4_DYNAMIC);
    ++            integrityCheckResultRow(v);
    ++            sqlite3VdbeResolveLabel(v, addrCkOk);
    ++            sqlite3ExprCachePop(pParse);
    ++          }
    ++          sqlite3ExprListDelete(db, pCheck);
    ++        }
    ++        if( !isQuick ){ /* Omit the remaining tests for quick_check */
    ++          /* Sanity check on record header decoding */
    ++          sqlite3VdbeAddOp3(v, OP_Column, iDataCur, pTab->nCol-1, 3);
    ++          sqlite3VdbeChangeP5(v, OPFLAG_TYPEOFARG);
    ++          /* Validate index entries for the current row */
    ++          for(j=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, j++){
    ++            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 */
    ++            /* Verify that an index entry exists for the current table row */
    ++            jmp2 = sqlite3VdbeAddOp4Int(v, OP_Found, iIdxCur+j, ckUniq, r1,
    ++                                        pIdx->nColumn); VdbeCoverage(v);
    ++            sqlite3VdbeLoadString(v, 3, "row ");
    ++            sqlite3VdbeAddOp3(v, OP_Concat, 7, 3, 3);
    ++            sqlite3VdbeLoadString(v, 4, " missing from index ");
    ++            sqlite3VdbeAddOp3(v, OP_Concat, 4, 3, 3);
    ++            jmp5 = sqlite3VdbeLoadString(v, 4, pIdx->zName);
    ++            sqlite3VdbeAddOp3(v, OP_Concat, 4, 3, 3);
    ++            jmp4 = integrityCheckResultRow(v);
    ++            sqlite3VdbeJumpHere(v, jmp2);
    ++            /* 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; kk<pIdx->nKeyCol; kk++){
    ++                int iCol = pIdx->aiColumn[kk];
    ++                assert( iCol!=XN_ROWID && iCol<pTab->nCol );
    ++                if( iCol>=0 && pTab->aCol[iCol].notNull ) continue;
    ++                sqlite3VdbeAddOp2(v, OP_IsNull, r1+kk, uniqOk);
    ++                VdbeCoverage(v);
    ++              }
    ++              jmp6 = sqlite3VdbeAddOp1(v, OP_Next, iIdxCur+j); VdbeCoverage(v);
    ++              sqlite3VdbeGoto(v, uniqOk);
    ++              sqlite3VdbeJumpHere(v, jmp6);
    ++              sqlite3VdbeAddOp4Int(v, OP_IdxGT, iIdxCur+j, uniqOk, r1,
    ++                                   pIdx->nKeyCol); VdbeCoverage(v);
    ++              sqlite3VdbeLoadString(v, 3, "non-unique entry in index ");
    ++              sqlite3VdbeGoto(v, jmp5);
    ++              sqlite3VdbeResolveLabel(v, uniqOk);
    ++            }
    ++            sqlite3VdbeJumpHere(v, jmp4);
    ++            sqlite3ResolvePartIdxLabel(pParse, jmp3);
    +           }
    +-          sqlite3VdbeJumpHere(v, jmp4);
    +-          sqlite3ResolvePartIdxLabel(pParse, jmp3);
    +         }
    +         sqlite3VdbeAddOp2(v, OP_Next, iDataCur, loopTop); VdbeCoverage(v);
    +         sqlite3VdbeJumpHere(v, loopTop-1);
    + #ifndef SQLITE_OMIT_BTREECOUNT
    +-        sqlite3VdbeLoadString(v, 2, "wrong # of entries in index ");
    +-        for(j=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, j++){
    +-          if( pPk==pIdx ) continue;
    +-          addr = sqlite3VdbeCurrentAddr(v);
    +-          sqlite3VdbeAddOp2(v, OP_IfPos, 1, addr+2); VdbeCoverage(v);
    +-          sqlite3VdbeAddOp2(v, OP_Halt, 0, 0);
    +-          sqlite3VdbeAddOp2(v, OP_Count, iIdxCur+j, 3);
    +-          sqlite3VdbeAddOp3(v, OP_Eq, 8+j, addr+8, 3); VdbeCoverage(v);
    +-          sqlite3VdbeChangeP5(v, SQLITE_NOTNULL);
    +-          sqlite3VdbeAddOp2(v, OP_AddImm, 1, -1);
    +-          sqlite3VdbeLoadString(v, 3, pIdx->zName);
    +-          sqlite3VdbeAddOp3(v, OP_Concat, 3, 2, 7);
    +-          sqlite3VdbeAddOp2(v, OP_ResultRow, 7, 1);
    ++        if( !isQuick ){
    ++          sqlite3VdbeLoadString(v, 2, "wrong # of entries in index ");
    ++          for(j=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, j++){
    ++            if( pPk==pIdx ) continue;
    ++            sqlite3VdbeAddOp2(v, OP_Count, iIdxCur+j, 3);
    ++            addr = sqlite3VdbeAddOp3(v, OP_Eq, 8+j, 0, 3); VdbeCoverage(v);
    ++            sqlite3VdbeChangeP5(v, SQLITE_NOTNULL);
    ++            sqlite3VdbeLoadString(v, 4, pIdx->zName);
    ++            sqlite3VdbeAddOp3(v, OP_Concat, 4, 2, 3);
    ++            integrityCheckResultRow(v);
    ++            sqlite3VdbeJumpHere(v, addr);
    ++          }
    +         }
    + #endif /* SQLITE_OMIT_BTREECOUNT */
    +       } 
    +     }
    +-    addr = sqlite3VdbeAddOpList(v, ArraySize(endCode), endCode, iLn);
    +-    sqlite3VdbeChangeP2(v, addr, -mxErr);
    +-    sqlite3VdbeJumpHere(v, addr+1);
    +-    sqlite3VdbeChangeP4(v, addr+2, "ok", P4_STATIC);
    ++    {
    ++      static const int iLn = VDBE_OFFSET_LINENO(2);
    ++      static const VdbeOpList endCode[] = {
    ++        { OP_AddImm,      1, 0,        0},    /* 0 */
    ++        { OP_IfNotZero,   1, 4,        0},    /* 1 */
    ++        { OP_String8,     0, 3,        0},    /* 2 */
    ++        { OP_ResultRow,   3, 1,        0},    /* 3 */
    ++        { OP_Halt,        0, 0,        0},    /* 4 */
    ++        { OP_String8,     0, 3,        0},    /* 5 */
    ++        { OP_Goto,        0, 3,        0},    /* 6 */
    ++      };
    ++      VdbeOp *aOp;
    ++
    ++      aOp = sqlite3VdbeAddOpList(v, ArraySize(endCode), endCode, iLn);
    ++      if( aOp ){
    ++        aOp[0].p2 = 1-mxErr;
    ++        aOp[2].p4type = P4_STATIC;
    ++        aOp[2].p4.z = "ok";
    ++        aOp[5].p4type = P4_STATIC;
    ++        aOp[5].p4.z = (char*)sqlite3ErrStr(SQLITE_CORRUPT);
    ++      }
    ++      sqlite3VdbeChangeP3(v, 0, sqlite3VdbeCurrentAddr(v)-2);
    ++    }
    +   }
    +   break;
    + #endif /* SQLITE_OMIT_INTEGRITY_CHECK */
    +@@ -107446,7 +117039,7 @@ SQLITE_PRIVATE void sqlite3Pragma(
    +       assert( encnames[SQLITE_UTF8].enc==SQLITE_UTF8 );
    +       assert( encnames[SQLITE_UTF16LE].enc==SQLITE_UTF16LE );
    +       assert( encnames[SQLITE_UTF16BE].enc==SQLITE_UTF16BE );
    +-      returnSingleText(v, "encoding", encnames[ENC(pParse->db)].zName);
    ++      returnSingleText(v, encnames[ENC(pParse->db)].zName);
    +     }else{                        /* "PRAGMA encoding = XXX" */
    +       /* Only change the value of sqlite.enc if the database handle is not
    +       ** initialized. If the main database exists, the new sqlite.enc value
    +@@ -107475,16 +117068,18 @@ SQLITE_PRIVATE void sqlite3Pragma(
    + 
    + #ifndef SQLITE_OMIT_SCHEMA_VERSION_PRAGMAS
    +   /*
    +-  **   PRAGMA [database.]schema_version
    +-  **   PRAGMA [database.]schema_version = <integer>
    ++  **   PRAGMA [schema.]schema_version
    ++  **   PRAGMA [schema.]schema_version = <integer>
    +   **
    +-  **   PRAGMA [database.]user_version
    +-  **   PRAGMA [database.]user_version = <integer>
    ++  **   PRAGMA [schema.]user_version
    ++  **   PRAGMA [schema.]user_version = <integer>
    +   **
    +-  **   PRAGMA [database.]freelist_count = <integer>
    ++  **   PRAGMA [schema.]freelist_count
    +   **
    +-  **   PRAGMA [database.]application_id
    +-  **   PRAGMA [database.]application_id = <integer>
    ++  **   PRAGMA [schema.]data_version
    ++  **
    ++  **   PRAGMA [schema.]application_id
    ++  **   PRAGMA [schema.]application_id = <integer>
    +   **
    +   ** The pragma's schema_version and user_version are used to set or get
    +   ** the value of the schema-version and user-version, respectively. Both
    +@@ -107507,18 +117102,20 @@ SQLITE_PRIVATE void sqlite3Pragma(
    +   case PragTyp_HEADER_VALUE: {
    +     int iCookie = pPragma->iArg;  /* Which cookie to read or write */
    +     sqlite3VdbeUsesBtree(v, iDb);
    +-    if( zRight && (pPragma->mPragFlag & PragFlag_ReadOnly)==0 ){
    ++    if( zRight && (pPragma->mPragFlg & PragFlg_ReadOnly)==0 ){
    +       /* Write the specified cookie value */
    +       static const VdbeOpList setCookie[] = {
    +         { OP_Transaction,    0,  1,  0},    /* 0 */
    +-        { OP_Integer,        0,  1,  0},    /* 1 */
    +-        { OP_SetCookie,      0,  0,  1},    /* 2 */
    ++        { OP_SetCookie,      0,  0,  0},    /* 1 */
    +       };
    +-      int addr = sqlite3VdbeAddOpList(v, ArraySize(setCookie), setCookie, 0);
    +-      sqlite3VdbeChangeP1(v, addr, iDb);
    +-      sqlite3VdbeChangeP1(v, addr+1, sqlite3Atoi(zRight));
    +-      sqlite3VdbeChangeP1(v, addr+2, iDb);
    +-      sqlite3VdbeChangeP2(v, addr+2, iCookie);
    ++      VdbeOp *aOp;
    ++      sqlite3VdbeVerifyNoMallocRequired(v, ArraySize(setCookie));
    ++      aOp = sqlite3VdbeAddOpList(v, ArraySize(setCookie), setCookie, 0);
    ++      if( ONLY_IF_REALLOC_STRESS(aOp==0) ) break;
    ++      aOp[0].p1 = iDb;
    ++      aOp[1].p1 = iDb;
    ++      aOp[1].p2 = iCookie;
    ++      aOp[1].p3 = sqlite3Atoi(zRight);
    +     }else{
    +       /* Read the specified cookie value */
    +       static const VdbeOpList readCookie[] = {
    +@@ -107526,12 +117123,14 @@ SQLITE_PRIVATE void sqlite3Pragma(
    +         { OP_ReadCookie,      0,  1,  0},    /* 1 */
    +         { OP_ResultRow,       1,  1,  0}
    +       };
    +-      int addr = sqlite3VdbeAddOpList(v, ArraySize(readCookie), readCookie, 0);
    +-      sqlite3VdbeChangeP1(v, addr, iDb);
    +-      sqlite3VdbeChangeP1(v, addr+1, iDb);
    +-      sqlite3VdbeChangeP3(v, addr+1, iCookie);
    +-      sqlite3VdbeSetNumCols(v, 1);
    +-      sqlite3VdbeSetColName(v, 0, COLNAME_NAME, zLeft, SQLITE_TRANSIENT);
    ++      VdbeOp *aOp;
    ++      sqlite3VdbeVerifyNoMallocRequired(v, ArraySize(readCookie));
    ++      aOp = sqlite3VdbeAddOpList(v, ArraySize(readCookie),readCookie,0);
    ++      if( ONLY_IF_REALLOC_STRESS(aOp==0) ) break;
    ++      aOp[0].p1 = iDb;
    ++      aOp[1].p1 = iDb;
    ++      aOp[1].p3 = iCookie;
    ++      sqlite3VdbeReusable(v);
    +     }
    +   }
    +   break;
    +@@ -107548,23 +117147,22 @@ SQLITE_PRIVATE void sqlite3Pragma(
    +     int i = 0;
    +     const char *zOpt;
    +     pParse->nMem = 1;
    +-    setOneColumnName(v, "compile_option");
    +     while( (zOpt = sqlite3_compileoption_get(i++))!=0 ){
    +       sqlite3VdbeLoadString(v, 1, zOpt);
    +       sqlite3VdbeAddOp2(v, OP_ResultRow, 1, 1);
    +     }
    ++    sqlite3VdbeReusable(v);
    +   }
    +   break;
    + #endif /* SQLITE_OMIT_COMPILEOPTION_DIAGS */
    + 
    + #ifndef SQLITE_OMIT_WAL
    +   /*
    +-  **   PRAGMA [database.]wal_checkpoint = passive|full|restart|truncate
    ++  **   PRAGMA [schema.]wal_checkpoint = passive|full|restart|truncate
    +   **
    +   ** Checkpoint the database.
    +   */
    +   case PragTyp_WAL_CHECKPOINT: {
    +-    static const char *azCol[] = { "busy", "log", "checkpointed" };
    +     int iBt = (pId2->z?iDb:SQLITE_MAX_ATTACHED);
    +     int eMode = SQLITE_CHECKPOINT_PASSIVE;
    +     if( zRight ){
    +@@ -107576,7 +117174,6 @@ SQLITE_PRIVATE void sqlite3Pragma(
    +         eMode = SQLITE_CHECKPOINT_TRUNCATE;
    +       }
    +     }
    +-    setAllColumnNames(v, 3, azCol);  assert( 3==ArraySize(azCol) );
    +     pParse->nMem = 3;
    +     sqlite3VdbeAddOp3(v, OP_Checkpoint, iBt, eMode, 1);
    +     sqlite3VdbeAddOp2(v, OP_ResultRow, 1, 3);
    +@@ -107595,7 +117192,7 @@ SQLITE_PRIVATE void sqlite3Pragma(
    +     if( zRight ){
    +       sqlite3_wal_autocheckpoint(db, sqlite3Atoi(zRight));
    +     }
    +-    returnSingleInt(v, "wal_autocheckpoint", 
    ++    returnSingleInt(v, 
    +        db->xWalCallback==sqlite3WalDefaultHook ? 
    +            SQLITE_PTR_TO_INT(db->pWalArg) : 0);
    +   }
    +@@ -107614,6 +117211,119 @@ SQLITE_PRIVATE void sqlite3Pragma(
    +     break;
    +   }
    + 
    ++  /*
    ++  **  PRAGMA optimize
    ++  **  PRAGMA optimize(MASK)
    ++  **  PRAGMA schema.optimize
    ++  **  PRAGMA schema.optimize(MASK)
    ++  **
    ++  ** Attempt to optimize the database.  All schemas are optimized in the first
    ++  ** two forms, and only the specified schema is optimized in the latter two.
    ++  **
    ++  ** The details of optimizations performed by this pragma are expected
    ++  ** to change and improve over time.  Applications should anticipate that
    ++  ** this pragma will perform new optimizations in future releases.
    ++  **
    ++  ** The optional argument is a bitmask of optimizations to perform:
    ++  **
    ++  **    0x0001    Debugging mode.  Do not actually perform any optimizations
    ++  **              but instead return one line of text for each optimization
    ++  **              that would have been done.  Off by default.
    ++  **
    ++  **    0x0002    Run ANALYZE on tables that might benefit.  On by default.
    ++  **              See below for additional information.
    ++  **
    ++  **    0x0004    (Not yet implemented) Record usage and performance 
    ++  **              information from the current session in the
    ++  **              database file so that it will be available to "optimize"
    ++  **              pragmas run by future database connections.
    ++  **
    ++  **    0x0008    (Not yet implemented) Create indexes that might have
    ++  **              been helpful to recent queries
    ++  **
    ++  ** The default MASK is and always shall be 0xfffe.  0xfffe means perform all
    ++  ** of the optimizations listed above except Debug Mode, including new
    ++  ** optimizations that have not yet been invented.  If new optimizations are
    ++  ** ever added that should be off by default, those off-by-default 
    ++  ** optimizations will have bitmasks of 0x10000 or larger.
    ++  **
    ++  ** DETERMINATION OF WHEN TO RUN ANALYZE
    ++  **
    ++  ** In the current implementation, a table is analyzed if only if all of
    ++  ** the following are true:
    ++  **
    ++  ** (1) MASK bit 0x02 is set.
    ++  **
    ++  ** (2) The query planner used sqlite_stat1-style statistics for one or
    ++  **     more indexes of the table at some point during the lifetime of
    ++  **     the current connection.
    ++  **
    ++  ** (3) One or more indexes of the table are currently unanalyzed OR
    ++  **     the number of rows in the table has increased by 25 times or more
    ++  **     since the last time ANALYZE was run.
    ++  **
    ++  ** The rules for when tables are analyzed are likely to change in
    ++  ** future releases.
    ++  */
    ++  case PragTyp_OPTIMIZE: {
    ++    int iDbLast;           /* Loop termination point for the schema loop */
    ++    int iTabCur;           /* Cursor for a table whose size needs checking */
    ++    HashElem *k;           /* Loop over tables of a schema */
    ++    Schema *pSchema;       /* The current schema */
    ++    Table *pTab;           /* A table in the schema */
    ++    Index *pIdx;           /* An index of the table */
    ++    LogEst szThreshold;    /* Size threshold above which reanalysis is needd */
    ++    char *zSubSql;         /* SQL statement for the OP_SqlExec opcode */
    ++    u32 opMask;            /* Mask of operations to perform */
    ++
    ++    if( zRight ){
    ++      opMask = (u32)sqlite3Atoi(zRight);
    ++      if( (opMask & 0x02)==0 ) break;
    ++    }else{
    ++      opMask = 0xfffe;
    ++    }
    ++    iTabCur = pParse->nTab++;
    ++    for(iDbLast = zDb?iDb:db->nDb-1; iDb<=iDbLast; iDb++){
    ++      if( iDb==1 ) continue;
    ++      sqlite3CodeVerifySchema(pParse, iDb);
    ++      pSchema = db->aDb[iDb].pSchema;
    ++      for(k=sqliteHashFirst(&pSchema->tblHash); k; k=sqliteHashNext(k)){
    ++        pTab = (Table*)sqliteHashData(k);
    ++
    ++        /* If table pTab has not been used in a way that would benefit from
    ++        ** having analysis statistics during the current session, then skip it.
    ++        ** This also has the effect of skipping virtual tables and views */
    ++        if( (pTab->tabFlags & TF_StatsUsed)==0 ) continue;
    ++
    ++        /* Reanalyze if the table is 25 times larger than the last analysis */
    ++        szThreshold = pTab->nRowLogEst + 46; assert( sqlite3LogEst(25)==46 );
    ++        for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){
    ++          if( !pIdx->hasStat1 ){
    ++            szThreshold = 0; /* Always analyze if any index lacks statistics */
    ++            break;
    ++          }
    ++        }
    ++        if( szThreshold ){
    ++          sqlite3OpenTable(pParse, iTabCur, iDb, pTab, OP_OpenRead);
    ++          sqlite3VdbeAddOp3(v, OP_IfSmaller, iTabCur, 
    ++                         sqlite3VdbeCurrentAddr(v)+2+(opMask&1), szThreshold);
    ++          VdbeCoverage(v);
    ++        }
    ++        zSubSql = sqlite3MPrintf(db, "ANALYZE \"%w\".\"%w\"",
    ++                                 db->aDb[iDb].zDbSName, pTab->zName);
    ++        if( opMask & 0x01 ){
    ++          int r1 = sqlite3GetTempReg(pParse);
    ++          sqlite3VdbeAddOp4(v, OP_String8, 0, r1, 0, zSubSql, P4_DYNAMIC);
    ++          sqlite3VdbeAddOp2(v, OP_ResultRow, r1, 1);
    ++        }else{
    ++          sqlite3VdbeAddOp4(v, OP_SqlExec, 0, 0, 0, zSubSql, P4_DYNAMIC);
    ++        }
    ++      }
    ++    }
    ++    sqlite3VdbeAddOp0(v, OP_Expire);
    ++    break;
    ++  }
    ++
    +   /*
    +   **   PRAGMA busy_timeout
    +   **   PRAGMA busy_timeout = N
    +@@ -107628,7 +117338,7 @@ SQLITE_PRIVATE void sqlite3Pragma(
    +     if( zRight ){
    +       sqlite3_busy_timeout(db, sqlite3Atoi(zRight));
    +     }
    +-    returnSingleInt(v, "timeout",  db->busyTimeout);
    ++    returnSingleInt(v, db->busyTimeout);
    +     break;
    +   }
    + 
    +@@ -107648,7 +117358,7 @@ SQLITE_PRIVATE void sqlite3Pragma(
    +     if( zRight && sqlite3DecOrHexToI64(zRight, &N)==SQLITE_OK ){
    +       sqlite3_soft_heap_limit64(N);
    +     }
    +-    returnSingleInt(v, "soft_heap_limit",  sqlite3_soft_heap_limit64(-1));
    ++    returnSingleInt(v, sqlite3_soft_heap_limit64(-1));
    +     break;
    +   }
    + 
    +@@ -107667,8 +117377,7 @@ SQLITE_PRIVATE void sqlite3Pragma(
    +     ){
    +       sqlite3_limit(db, SQLITE_LIMIT_WORKER_THREADS, (int)(N&0x7fffffff));
    +     }
    +-    returnSingleInt(v, "threads",
    +-                    sqlite3_limit(db, SQLITE_LIMIT_WORKER_THREADS, -1));
    ++    returnSingleInt(v, sqlite3_limit(db, SQLITE_LIMIT_WORKER_THREADS, -1));
    +     break;
    +   }
    + 
    +@@ -107680,24 +117389,21 @@ SQLITE_PRIVATE void sqlite3Pragma(
    +     static const char *const azLockName[] = {
    +       "unlocked", "shared", "reserved", "pending", "exclusive"
    +     };
    +-    static const char *azCol[] = { "database", "status" };
    +     int i;
    +-    setAllColumnNames(v, 2, azCol); assert( 2==ArraySize(azCol) );
    +     pParse->nMem = 2;
    +     for(i=0; i<db->nDb; i++){
    +       Btree *pBt;
    +       const char *zState = "unknown";
    +       int j;
    +-      if( db->aDb[i].zName==0 ) continue;
    ++      if( db->aDb[i].zDbSName==0 ) continue;
    +       pBt = db->aDb[i].pBt;
    +       if( pBt==0 || sqlite3BtreePager(pBt)==0 ){
    +         zState = "closed";
    +-      }else if( sqlite3_file_control(db, i ? db->aDb[i].zName : 0, 
    ++      }else if( sqlite3_file_control(db, i ? db->aDb[i].zDbSName : 0, 
    +                                      SQLITE_FCNTL_LOCKSTATE, &j)==SQLITE_OK ){
    +          zState = azLockName[j];
    +       }
    +-      sqlite3VdbeMultiLoad(v, 1, "ss", db->aDb[i].zName, zState);
    +-      sqlite3VdbeAddOp2(v, OP_ResultRow, 1, 2);
    ++      sqlite3VdbeMultiLoad(v, 1, "ss", db->aDb[i].zDbSName, zState);
    +     }
    +     break;
    +   }
    +@@ -107748,10 +117454,329 @@ SQLITE_PRIVATE void sqlite3Pragma(
    + 
    +   } /* End of the PRAGMA switch */
    + 
    ++  /* The following block is a no-op unless SQLITE_DEBUG is defined. Its only
    ++  ** purpose is to execute assert() statements to verify that if the
    ++  ** PragFlg_NoColumns1 flag is set and the caller specified an argument
    ++  ** to the PRAGMA, the implementation has not added any OP_ResultRow 
    ++  ** instructions to the VM.  */
    ++  if( (pPragma->mPragFlg & PragFlg_NoColumns1) && zRight ){
    ++    sqlite3VdbeVerifyNoResultRow(v);
    ++  }
    ++
    + pragma_out:
    +   sqlite3DbFree(db, zLeft);
    +   sqlite3DbFree(db, zRight);
    + }
    ++#ifndef SQLITE_OMIT_VIRTUALTABLE
    ++/*****************************************************************************
    ++** Implementation of an eponymous virtual table that runs a pragma.
    ++**
    ++*/
    ++typedef struct PragmaVtab PragmaVtab;
    ++typedef struct PragmaVtabCursor PragmaVtabCursor;
    ++struct PragmaVtab {
    ++  sqlite3_vtab base;        /* Base class.  Must be first */
    ++  sqlite3 *db;              /* The database connection to which it belongs */
    ++  const PragmaName *pName;  /* Name of the pragma */
    ++  u8 nHidden;               /* Number of hidden columns */
    ++  u8 iHidden;               /* Index of the first hidden column */
    ++};
    ++struct PragmaVtabCursor {
    ++  sqlite3_vtab_cursor base; /* Base class.  Must be first */
    ++  sqlite3_stmt *pPragma;    /* The pragma statement to run */
    ++  sqlite_int64 iRowid;      /* Current rowid */
    ++  char *azArg[2];           /* Value of the argument and schema */
    ++};
    ++
    ++/* 
    ++** Pragma virtual table module xConnect method.
    ++*/
    ++static int pragmaVtabConnect(
    ++  sqlite3 *db,
    ++  void *pAux,
    ++  int argc, const char *const*argv,
    ++  sqlite3_vtab **ppVtab,
    ++  char **pzErr
    ++){
    ++  const PragmaName *pPragma = (const PragmaName*)pAux;
    ++  PragmaVtab *pTab = 0;
    ++  int rc;
    ++  int i, j;
    ++  char cSep = '(';
    ++  StrAccum acc;
    ++  char zBuf[200];
    ++
    ++  UNUSED_PARAMETER(argc);
    ++  UNUSED_PARAMETER(argv);
    ++  sqlite3StrAccumInit(&acc, 0, zBuf, sizeof(zBuf), 0);
    ++  sqlite3StrAccumAppendAll(&acc, "CREATE TABLE x");
    ++  for(i=0, j=pPragma->iPragCName; i<pPragma->nPragCName; i++, j++){
    ++    sqlite3XPrintf(&acc, "%c\"%s\"", cSep, pragCName[j]);
    ++    cSep = ',';
    ++  }
    ++  if( i==0 ){
    ++    sqlite3XPrintf(&acc, "(\"%s\"", pPragma->zName);
    ++    cSep = ',';
    ++    i++;
    ++  }
    ++  j = 0;
    ++  if( pPragma->mPragFlg & PragFlg_Result1 ){
    ++    sqlite3StrAccumAppendAll(&acc, ",arg HIDDEN");
    ++    j++;
    ++  }
    ++  if( pPragma->mPragFlg & (PragFlg_SchemaOpt|PragFlg_SchemaReq) ){
    ++    sqlite3StrAccumAppendAll(&acc, ",schema HIDDEN");
    ++    j++;
    ++  }
    ++  sqlite3StrAccumAppend(&acc, ")", 1);
    ++  sqlite3StrAccumFinish(&acc);
    ++  assert( strlen(zBuf) < sizeof(zBuf)-1 );
    ++  rc = sqlite3_declare_vtab(db, zBuf);
    ++  if( rc==SQLITE_OK ){
    ++    pTab = (PragmaVtab*)sqlite3_malloc(sizeof(PragmaVtab));
    ++    if( pTab==0 ){
    ++      rc = SQLITE_NOMEM;
    ++    }else{
    ++      memset(pTab, 0, sizeof(PragmaVtab));
    ++      pTab->pName = pPragma;
    ++      pTab->db = db;
    ++      pTab->iHidden = i;
    ++      pTab->nHidden = j;
    ++    }
    ++  }else{
    ++    *pzErr = sqlite3_mprintf("%s", sqlite3_errmsg(db));
    ++  }
    ++
    ++  *ppVtab = (sqlite3_vtab*)pTab;
    ++  return rc;
    ++}
    ++
    ++/* 
    ++** Pragma virtual table module xDisconnect method.
    ++*/
    ++static int pragmaVtabDisconnect(sqlite3_vtab *pVtab){
    ++  PragmaVtab *pTab = (PragmaVtab*)pVtab;
    ++  sqlite3_free(pTab);
    ++  return SQLITE_OK;
    ++}
    ++
    ++/* Figure out the best index to use to search a pragma virtual table.
    ++**
    ++** There are not really any index choices.  But we want to encourage the
    ++** query planner to give == constraints on as many hidden parameters as
    ++** possible, and especially on the first hidden parameter.  So return a
    ++** high cost if hidden parameters are unconstrained.
    ++*/
    ++static int pragmaVtabBestIndex(sqlite3_vtab *tab, sqlite3_index_info *pIdxInfo){
    ++  PragmaVtab *pTab = (PragmaVtab*)tab;
    ++  const struct sqlite3_index_constraint *pConstraint;
    ++  int i, j;
    ++  int seen[2];
    ++
    ++  pIdxInfo->estimatedCost = (double)1;
    ++  if( pTab->nHidden==0 ){ return SQLITE_OK; }
    ++  pConstraint = pIdxInfo->aConstraint;
    ++  seen[0] = 0;
    ++  seen[1] = 0;
    ++  for(i=0; i<pIdxInfo->nConstraint; i++, pConstraint++){
    ++    if( pConstraint->usable==0 ) continue;
    ++    if( pConstraint->op!=SQLITE_INDEX_CONSTRAINT_EQ ) continue;
    ++    if( pConstraint->iColumn < pTab->iHidden ) continue;
    ++    j = pConstraint->iColumn - pTab->iHidden;
    ++    assert( j < 2 );
    ++    seen[j] = i+1;
    ++  }
    ++  if( seen[0]==0 ){
    ++    pIdxInfo->estimatedCost = (double)2147483647;
    ++    pIdxInfo->estimatedRows = 2147483647;
    ++    return SQLITE_OK;
    ++  }
    ++  j = seen[0]-1;
    ++  pIdxInfo->aConstraintUsage[j].argvIndex = 1;
    ++  pIdxInfo->aConstraintUsage[j].omit = 1;
    ++  if( seen[1]==0 ) return SQLITE_OK;
    ++  pIdxInfo->estimatedCost = (double)20;
    ++  pIdxInfo->estimatedRows = 20;
    ++  j = seen[1]-1;
    ++  pIdxInfo->aConstraintUsage[j].argvIndex = 2;
    ++  pIdxInfo->aConstraintUsage[j].omit = 1;
    ++  return SQLITE_OK;
    ++}
    ++
    ++/* Create a new cursor for the pragma virtual table */
    ++static int pragmaVtabOpen(sqlite3_vtab *pVtab, sqlite3_vtab_cursor **ppCursor){
    ++  PragmaVtabCursor *pCsr;
    ++  pCsr = (PragmaVtabCursor*)sqlite3_malloc(sizeof(*pCsr));
    ++  if( pCsr==0 ) return SQLITE_NOMEM;
    ++  memset(pCsr, 0, sizeof(PragmaVtabCursor));
    ++  pCsr->base.pVtab = pVtab;
    ++  *ppCursor = &pCsr->base;
    ++  return SQLITE_OK;
    ++}
    ++
    ++/* Clear all content from pragma virtual table cursor. */
    ++static void pragmaVtabCursorClear(PragmaVtabCursor *pCsr){
    ++  int i;
    ++  sqlite3_finalize(pCsr->pPragma);
    ++  pCsr->pPragma = 0;
    ++  for(i=0; i<ArraySize(pCsr->azArg); i++){
    ++    sqlite3_free(pCsr->azArg[i]);
    ++    pCsr->azArg[i] = 0;
    ++  }
    ++}
    ++
    ++/* Close a pragma virtual table cursor */
    ++static int pragmaVtabClose(sqlite3_vtab_cursor *cur){
    ++  PragmaVtabCursor *pCsr = (PragmaVtabCursor*)cur;
    ++  pragmaVtabCursorClear(pCsr);
    ++  sqlite3_free(pCsr);
    ++  return SQLITE_OK;
    ++}
    ++
    ++/* Advance the pragma virtual table cursor to the next row */
    ++static int pragmaVtabNext(sqlite3_vtab_cursor *pVtabCursor){
    ++  PragmaVtabCursor *pCsr = (PragmaVtabCursor*)pVtabCursor;
    ++  int rc = SQLITE_OK;
    ++
    ++  /* Increment the xRowid value */
    ++  pCsr->iRowid++;
    ++  assert( pCsr->pPragma );
    ++  if( SQLITE_ROW!=sqlite3_step(pCsr->pPragma) ){
    ++    rc = sqlite3_finalize(pCsr->pPragma);
    ++    pCsr->pPragma = 0;
    ++    pragmaVtabCursorClear(pCsr);
    ++  }
    ++  return rc;
    ++}
    ++
    ++/* 
    ++** Pragma virtual table module xFilter method.
    ++*/
    ++static int pragmaVtabFilter(
    ++  sqlite3_vtab_cursor *pVtabCursor, 
    ++  int idxNum, const char *idxStr,
    ++  int argc, sqlite3_value **argv
    ++){
    ++  PragmaVtabCursor *pCsr = (PragmaVtabCursor*)pVtabCursor;
    ++  PragmaVtab *pTab = (PragmaVtab*)(pVtabCursor->pVtab);
    ++  int rc;
    ++  int i, j;
    ++  StrAccum acc;
    ++  char *zSql;
    ++
    ++  UNUSED_PARAMETER(idxNum);
    ++  UNUSED_PARAMETER(idxStr);
    ++  pragmaVtabCursorClear(pCsr);
    ++  j = (pTab->pName->mPragFlg & PragFlg_Result1)!=0 ? 0 : 1;
    ++  for(i=0; i<argc; i++, j++){
    ++    const char *zText = (const char*)sqlite3_value_text(argv[i]);
    ++    assert( j<ArraySize(pCsr->azArg) );
    ++    assert( pCsr->azArg[j]==0 );
    ++    if( zText ){
    ++      pCsr->azArg[j] = sqlite3_mprintf("%s", zText);
    ++      if( pCsr->azArg[j]==0 ){
    ++        return SQLITE_NOMEM;
    ++      }
    ++    }
    ++  }
    ++  sqlite3StrAccumInit(&acc, 0, 0, 0, pTab->db->aLimit[SQLITE_LIMIT_SQL_LENGTH]);
    ++  sqlite3StrAccumAppendAll(&acc, "PRAGMA ");
    ++  if( pCsr->azArg[1] ){
    ++    sqlite3XPrintf(&acc, "%Q.", pCsr->azArg[1]);
    ++  }
    ++  sqlite3StrAccumAppendAll(&acc, pTab->pName->zName);
    ++  if( pCsr->azArg[0] ){
    ++    sqlite3XPrintf(&acc, "=%Q", pCsr->azArg[0]);
    ++  }
    ++  zSql = sqlite3StrAccumFinish(&acc);
    ++  if( zSql==0 ) return SQLITE_NOMEM;
    ++  rc = sqlite3_prepare_v2(pTab->db, zSql, -1, &pCsr->pPragma, 0);
    ++  sqlite3_free(zSql);
    ++  if( rc!=SQLITE_OK ){
    ++    pTab->base.zErrMsg = sqlite3_mprintf("%s", sqlite3_errmsg(pTab->db));
    ++    return rc;
    ++  }
    ++  return pragmaVtabNext(pVtabCursor);
    ++}
    ++
    ++/*
    ++** Pragma virtual table module xEof method.
    ++*/
    ++static int pragmaVtabEof(sqlite3_vtab_cursor *pVtabCursor){
    ++  PragmaVtabCursor *pCsr = (PragmaVtabCursor*)pVtabCursor;
    ++  return (pCsr->pPragma==0);
    ++}
    ++
    ++/* The xColumn method simply returns the corresponding column from
    ++** the PRAGMA.  
    ++*/
    ++static int pragmaVtabColumn(
    ++  sqlite3_vtab_cursor *pVtabCursor, 
    ++  sqlite3_context *ctx, 
    ++  int i
    ++){
    ++  PragmaVtabCursor *pCsr = (PragmaVtabCursor*)pVtabCursor;
    ++  PragmaVtab *pTab = (PragmaVtab*)(pVtabCursor->pVtab);
    ++  if( i<pTab->iHidden ){
    ++    sqlite3_result_value(ctx, sqlite3_column_value(pCsr->pPragma, i));
    ++  }else{
    ++    sqlite3_result_text(ctx, pCsr->azArg[i-pTab->iHidden],-1,SQLITE_TRANSIENT);
    ++  }
    ++  return SQLITE_OK;
    ++}
    ++
    ++/* 
    ++** Pragma virtual table module xRowid method.
    ++*/
    ++static int pragmaVtabRowid(sqlite3_vtab_cursor *pVtabCursor, sqlite_int64 *p){
    ++  PragmaVtabCursor *pCsr = (PragmaVtabCursor*)pVtabCursor;
    ++  *p = pCsr->iRowid;
    ++  return SQLITE_OK;
    ++}
    ++
    ++/* The pragma virtual table object */
    ++static const sqlite3_module pragmaVtabModule = {
    ++  0,                           /* iVersion */
    ++  0,                           /* xCreate - create a table */
    ++  pragmaVtabConnect,           /* xConnect - connect to an existing table */
    ++  pragmaVtabBestIndex,         /* xBestIndex - Determine search strategy */
    ++  pragmaVtabDisconnect,        /* xDisconnect - Disconnect from a table */
    ++  0,                           /* xDestroy - Drop a table */
    ++  pragmaVtabOpen,              /* xOpen - open a cursor */
    ++  pragmaVtabClose,             /* xClose - close a cursor */
    ++  pragmaVtabFilter,            /* xFilter - configure scan constraints */
    ++  pragmaVtabNext,              /* xNext - advance a cursor */
    ++  pragmaVtabEof,               /* xEof */
    ++  pragmaVtabColumn,            /* xColumn - read data */
    ++  pragmaVtabRowid,             /* xRowid - read data */
    ++  0,                           /* xUpdate - write data */
    ++  0,                           /* xBegin - begin transaction */
    ++  0,                           /* xSync - sync transaction */
    ++  0,                           /* xCommit - commit transaction */
    ++  0,                           /* xRollback - rollback transaction */
    ++  0,                           /* xFindFunction - function overloading */
    ++  0,                           /* xRename - rename the table */
    ++  0,                           /* xSavepoint */
    ++  0,                           /* xRelease */
    ++  0                            /* xRollbackTo */
    ++};
    ++
    ++/*
    ++** Check to see if zTabName is really the name of a pragma.  If it is,
    ++** then register an eponymous virtual table for that pragma and return
    ++** a pointer to the Module object for the new virtual table.
    ++*/
    ++SQLITE_PRIVATE Module *sqlite3PragmaVtabRegister(sqlite3 *db, const char *zName){
    ++  const PragmaName *pName;
    ++  assert( sqlite3_strnicmp(zName, "pragma_", 7)==0 );
    ++  pName = pragmaLocate(zName+7);
    ++  if( pName==0 ) return 0;
    ++  if( (pName->mPragFlg & (PragFlg_Result0|PragFlg_Result1))==0 ) return 0;
    ++  assert( sqlite3HashFind(&db->aModule, zName)==0 );
    ++  return sqlite3VtabCreateModule(db, zName, &pragmaVtabModule, (void*)pName, 0);
    ++}
    ++
    ++#endif /* SQLITE_OMIT_VIRTUALTABLE */
    + 
    + #endif /* SQLITE_OMIT_PRAGMA */
    + 
    +@@ -107784,16 +117809,15 @@ static void corruptSchema(
    +   const char *zExtra   /* Error information */
    + ){
    +   sqlite3 *db = pData->db;
    +-  if( !db->mallocFailed && (db->flags & SQLITE_RecoveryMode)==0 ){
    ++  if( !db->mallocFailed && (db->flags & SQLITE_WriteSchema)==0 ){
    +     char *z;
    +     if( zObj==0 ) zObj = "?";
    +-    z = sqlite3_mprintf("malformed database schema (%s)", zObj);
    +-    if( z && zExtra ) z = sqlite3_mprintf("%z - %s", z, zExtra);
    ++    z = sqlite3MPrintf(db, "malformed database schema (%s)", zObj);
    ++    if( zExtra ) z = sqlite3MPrintf(db, "%z - %s", z, zExtra);
    +     sqlite3DbFree(db, *pData->pzErrMsg);
    +     *pData->pzErrMsg = z;
    +-    if( z==0 ) db->mallocFailed = 1;
    +   }
    +-  pData->rc = db->mallocFailed ? SQLITE_NOMEM : SQLITE_CORRUPT_BKPT;
    ++  pData->rc = db->mallocFailed ? SQLITE_NOMEM_BKPT : SQLITE_CORRUPT_BKPT;
    + }
    + 
    + /*
    +@@ -107833,6 +117857,7 @@ SQLITE_PRIVATE int sqlite3InitCallback(void *pInit, int argc, char **argv, char
    +     ** structures that describe the table, index, or view.
    +     */
    +     int rc;
    ++    u8 saved_iDb = db->init.iDb;
    +     sqlite3_stmt *pStmt;
    +     TESTONLY(int rcp);            /* Return code from sqlite3_prepare() */
    + 
    +@@ -107843,14 +117868,15 @@ SQLITE_PRIVATE int sqlite3InitCallback(void *pInit, int argc, char **argv, char
    +     TESTONLY(rcp = ) sqlite3_prepare(db, argv[2], -1, &pStmt, 0);
    +     rc = db->errCode;
    +     assert( (rc&0xFF)==(rcp&0xFF) );
    +-    db->init.iDb = 0;
    ++    db->init.iDb = saved_iDb;
    ++    assert( saved_iDb==0 || (db->mDbFlags & DBFLAG_Vacuum)!=0 );
    +     if( SQLITE_OK!=rc ){
    +       if( db->init.orphanTrigger ){
    +         assert( iDb==1 );
    +       }else{
    +         pData->rc = rc;
    +         if( rc==SQLITE_NOMEM ){
    +-          db->mallocFailed = 1;
    ++          sqlite3OomFault(db);
    +         }else if( rc!=SQLITE_INTERRUPT && (rc&0xFF)!=SQLITE_LOCKED ){
    +           corruptSchema(pData, argv[0], sqlite3_errmsg(db));
    +         }
    +@@ -107867,7 +117893,7 @@ SQLITE_PRIVATE int sqlite3InitCallback(void *pInit, int argc, char **argv, char
    +     ** to do here is record the root page number for that index.
    +     */
    +     Index *pIndex;
    +-    pIndex = sqlite3FindIndex(db, argv[0], db->aDb[iDb].zName);
    ++    pIndex = sqlite3FindIndex(db, argv[0], db->aDb[iDb].zDbSName);
    +     if( pIndex==0 ){
    +       /* This can occur if there exists an index on a TEMP table which
    +       ** has the same name as another index on a permanent index.  Since
    +@@ -107896,61 +117922,29 @@ static int sqlite3InitOne(sqlite3 *db, int iDb, char **pzErrMsg){
    + #ifndef SQLITE_OMIT_DEPRECATED
    +   int size;
    + #endif
    +-  Table *pTab;
    +   Db *pDb;
    +   char const *azArg[4];
    +   int meta[5];
    +   InitData initData;
    +-  char const *zMasterSchema;
    +-  char const *zMasterName;
    ++  const char *zMasterName;
    +   int openedTransaction = 0;
    + 
    +-  /*
    +-  ** The master database table has a structure like this
    +-  */
    +-  static const char master_schema[] = 
    +-     "CREATE TABLE sqlite_master(\n"
    +-     "  type text,\n"
    +-     "  name text,\n"
    +-     "  tbl_name text,\n"
    +-     "  rootpage integer,\n"
    +-     "  sql text\n"
    +-     ")"
    +-  ;
    +-#ifndef SQLITE_OMIT_TEMPDB
    +-  static const char temp_master_schema[] = 
    +-     "CREATE TEMP TABLE sqlite_temp_master(\n"
    +-     "  type text,\n"
    +-     "  name text,\n"
    +-     "  tbl_name text,\n"
    +-     "  rootpage integer,\n"
    +-     "  sql text\n"
    +-     ")"
    +-  ;
    +-#else
    +-  #define temp_master_schema 0
    +-#endif
    +-
    +   assert( iDb>=0 && iDb<db->nDb );
    +   assert( db->aDb[iDb].pSchema );
    +   assert( sqlite3_mutex_held(db->mutex) );
    +   assert( iDb==1 || sqlite3BtreeHoldsMutex(db->aDb[iDb].pBt) );
    + 
    +-  /* zMasterSchema and zInitScript are set to point at the master schema
    +-  ** and initialisation script appropriate for the database being
    +-  ** initialized. zMasterName is the name of the master table.
    +-  */
    +-  if( !OMIT_TEMPDB && iDb==1 ){
    +-    zMasterSchema = temp_master_schema;
    +-  }else{
    +-    zMasterSchema = master_schema;
    +-  }
    +-  zMasterName = SCHEMA_TABLE(iDb);
    ++  db->init.busy = 1;
    + 
    +-  /* Construct the schema tables.  */
    +-  azArg[0] = zMasterName;
    ++  /* Construct the in-memory representation schema tables (sqlite_master or
    ++  ** sqlite_temp_master) by invoking the parser directly.  The appropriate
    ++  ** table name will be inserted automatically by the parser so we can just
    ++  ** use the abbreviation "x" here.  The parser will also automatically tag
    ++  ** the schema table as read-only. */
    ++  azArg[0] = zMasterName = SCHEMA_TABLE(iDb);
    +   azArg[1] = "1";
    +-  azArg[2] = zMasterSchema;
    ++  azArg[2] = "CREATE TABLE x(type text,name text,tbl_name text,"
    ++                            "rootpage int,sql text)";
    +   azArg[3] = 0;
    +   initData.db = db;
    +   initData.iDb = iDb;
    +@@ -107961,19 +117955,15 @@ static int sqlite3InitOne(sqlite3 *db, int iDb, char **pzErrMsg){
    +     rc = initData.rc;
    +     goto error_out;
    +   }
    +-  pTab = sqlite3FindTable(db, zMasterName, db->aDb[iDb].zName);
    +-  if( ALWAYS(pTab) ){
    +-    pTab->tabFlags |= TF_Readonly;
    +-  }
    + 
    +   /* Create a cursor to hold the database open
    +   */
    +   pDb = &db->aDb[iDb];
    +   if( pDb->pBt==0 ){
    +-    if( !OMIT_TEMPDB && ALWAYS(iDb==1) ){
    +-      DbSetProperty(db, 1, DB_SchemaLoaded);
    +-    }
    +-    return SQLITE_OK;
    ++    assert( iDb==1 );
    ++    DbSetProperty(db, 1, DB_SchemaLoaded);
    ++    rc = SQLITE_OK;
    ++    goto error_out;
    +   }
    + 
    +   /* If there is not already a read-only (or read-write) transaction opened
    +@@ -108064,7 +118054,7 @@ static int sqlite3InitOne(sqlite3 *db, int iDb, char **pzErrMsg){
    +   }
    +   if( pDb->pSchema->file_format>SQLITE_MAX_FILE_FORMAT ){
    +     sqlite3SetString(pzErrMsg, db, "unsupported file format");
    +-    rc = SQLITE_CORRUPT_BKPT; // Android Change from "rc = SQLITE_ERROR;"
    ++    rc = SQLITE_CORRUPT_BKPT; // Android Change from "rc = SQLITE_ERROR;";
    +     goto initone_error_out;
    +   }
    + 
    +@@ -108083,8 +118073,8 @@ static int sqlite3InitOne(sqlite3 *db, int iDb, char **pzErrMsg){
    +   {
    +     char *zSql;
    +     zSql = sqlite3MPrintf(db, 
    +-        "SELECT name, rootpage, sql FROM '%q'.%s ORDER BY rowid",
    +-        db->aDb[iDb].zName, zMasterName);
    ++        "SELECT name, rootpage, sql FROM \"%w\".%s ORDER BY rowid",
    ++        db->aDb[iDb].zDbSName, zMasterName);
    + #ifndef SQLITE_OMIT_AUTHORIZATION
    +     {
    +       sqlite3_xauth xAuth;
    +@@ -108105,11 +118095,11 @@ static int sqlite3InitOne(sqlite3 *db, int iDb, char **pzErrMsg){
    + #endif
    +   }
    +   if( db->mallocFailed ){
    +-    rc = SQLITE_NOMEM;
    ++    rc = SQLITE_NOMEM_BKPT;
    +     sqlite3ResetAllSchemasOfConnection(db);
    +   }
    +-  if( rc==SQLITE_OK || (db->flags&SQLITE_RecoveryMode)){
    +-    /* Black magic: If the SQLITE_RecoveryMode flag is set, then consider
    ++  if( rc==SQLITE_OK || (db->flags&SQLITE_WriteSchema)){
    ++    /* Black magic: If the SQLITE_WriteSchema flag is set, then consider
    +     ** the schema loaded, even if errors occurred. In this situation the 
    +     ** current sqlite3_prepare() operation will fail, but the following one
    +     ** will attempt to compile the supplied statement against whatever subset
    +@@ -108132,9 +118122,13 @@ initone_error_out:
    +   sqlite3BtreeLeave(pDb->pBt);
    + 
    + error_out:
    +-  if( rc==SQLITE_NOMEM || rc==SQLITE_IOERR_NOMEM ){
    +-    db->mallocFailed = 1;
    ++  if( rc ){
    ++    if( rc==SQLITE_NOMEM || rc==SQLITE_IOERR_NOMEM ){
    ++      sqlite3OomFault(db);
    ++    }
    ++    sqlite3ResetOneSchema(db, iDb);
    +   }
    ++  db->init.busy = 0;
    +   return rc;
    + }
    + 
    +@@ -108150,42 +118144,29 @@ error_out:
    + */
    + SQLITE_PRIVATE int sqlite3Init(sqlite3 *db, char **pzErrMsg){
    +   int i, rc;
    +-  int commit_internal = !(db->flags&SQLITE_InternChanges);
    ++  int commit_internal = !(db->mDbFlags&DBFLAG_SchemaChange);
    +   
    +   assert( sqlite3_mutex_held(db->mutex) );
    +   assert( sqlite3BtreeHoldsMutex(db->aDb[0].pBt) );
    +   assert( db->init.busy==0 );
    +-  rc = SQLITE_OK;
    +-  db->init.busy = 1;
    +   ENC(db) = SCHEMA_ENC(db);
    +-  for(i=0; rc==SQLITE_OK && i<db->nDb; i++){
    +-    if( DbHasProperty(db, i, DB_SchemaLoaded) || i==1 ) continue;
    +-    rc = sqlite3InitOne(db, i, pzErrMsg);
    +-    if( rc ){
    +-      sqlite3ResetOneSchema(db, i);
    +-    }
    ++  assert( db->nDb>0 );
    ++  /* Do the main schema first */
    ++  if( !DbHasProperty(db, 0, DB_SchemaLoaded) ){
    ++    rc = sqlite3InitOne(db, 0, pzErrMsg);
    ++    if( rc ) return rc;
    +   }
    +-
    +-  /* Once all the other databases have been initialized, load the schema
    +-  ** for the TEMP database. This is loaded last, as the TEMP database
    +-  ** schema may contain references to objects in other databases.
    +-  */
    +-#ifndef SQLITE_OMIT_TEMPDB
    +-  assert( db->nDb>1 );
    +-  if( rc==SQLITE_OK && !DbHasProperty(db, 1, DB_SchemaLoaded) ){
    +-    rc = sqlite3InitOne(db, 1, pzErrMsg);
    +-    if( rc ){
    +-      sqlite3ResetOneSchema(db, 1);
    ++  /* All other schemas after the main schema. The "temp" schema must be last */
    ++  for(i=db->nDb-1; i>0; i--){
    ++    if( !DbHasProperty(db, i, DB_SchemaLoaded) ){
    ++      rc = sqlite3InitOne(db, i, pzErrMsg);
    ++      if( rc ) return rc;
    +     }
    +   }
    +-#endif
    +-
    +-  db->init.busy = 0;
    +-  if( rc==SQLITE_OK && commit_internal ){
    ++  if( commit_internal ){
    +     sqlite3CommitInternalChanges(db);
    +   }
    +-
    +-  return rc; 
    ++  return SQLITE_OK;
    + }
    + 
    + /*
    +@@ -108231,7 +118212,7 @@ static void schemaIsValid(Parse *pParse){
    +     if( !sqlite3BtreeIsInReadTrans(pBt) ){
    +       rc = sqlite3BtreeBeginTrans(pBt, 0);
    +       if( rc==SQLITE_NOMEM || rc==SQLITE_IOERR_NOMEM ){
    +-        db->mallocFailed = 1;
    ++        sqlite3OomFault(db);
    +       }
    +       if( rc!=SQLITE_OK ) return;
    +       openedTransaction = 1;
    +@@ -108276,7 +118257,8 @@ SQLITE_PRIVATE int sqlite3SchemaToIndex(sqlite3 *db, Schema *pSchema){
    +   */
    +   assert( sqlite3_mutex_held(db->mutex) );
    +   if( pSchema ){
    +-    for(i=0; ALWAYS(i<db->nDb); i++){
    ++    for(i=0; 1; i++){
    ++      assert( i<db->nDb );
    +       if( db->aDb[i].pSchema==pSchema ){
    +         break;
    +       }
    +@@ -108290,11 +118272,14 @@ SQLITE_PRIVATE int sqlite3SchemaToIndex(sqlite3 *db, Schema *pSchema){
    + ** Free all memory allocations in the pParse object
    + */
    + SQLITE_PRIVATE void sqlite3ParserReset(Parse *pParse){
    +-  if( pParse ){
    +-    sqlite3 *db = pParse->db;
    +-    sqlite3DbFree(db, pParse->aLabel);
    +-    sqlite3ExprListDelete(db, pParse->pConstExpr);
    ++  sqlite3 *db = pParse->db;
    ++  sqlite3DbFree(db, pParse->aLabel);
    ++  sqlite3ExprListDelete(db, pParse->pConstExpr);
    ++  if( db ){
    ++    assert( db->lookaside.bDisable >= pParse->disableLookaside );
    ++    db->lookaside.bDisable -= pParse->disableLookaside;
    +   }
    ++  pParse->disableLookaside = 0;
    + }
    + 
    + /*
    +@@ -108304,27 +118289,31 @@ static int sqlite3Prepare(
    +   sqlite3 *db,              /* Database handle. */
    +   const char *zSql,         /* UTF-8 encoded SQL statement. */
    +   int nBytes,               /* Length of zSql in bytes. */
    +-  int saveSqlFlag,          /* True to copy SQL text into the sqlite3_stmt */
    ++  u32 prepFlags,            /* Zero or more SQLITE_PREPARE_* flags */
    +   Vdbe *pReprepare,         /* VM being reprepared */
    +   sqlite3_stmt **ppStmt,    /* OUT: A pointer to the prepared statement */
    +   const char **pzTail       /* OUT: End of parsed string */
    + ){
    +-  Parse *pParse;            /* Parsing context */
    +   char *zErrMsg = 0;        /* Error message */
    +   int rc = SQLITE_OK;       /* Result code */
    +   int i;                    /* Loop counter */
    ++  Parse sParse;             /* Parsing context */
    + 
    +-  /* Allocate the parsing context */
    +-  pParse = sqlite3StackAllocZero(db, sizeof(*pParse));
    +-  if( pParse==0 ){
    +-    rc = SQLITE_NOMEM;
    +-    goto end_prepare;
    +-  }
    +-  pParse->pReprepare = pReprepare;
    ++  memset(&sParse, 0, PARSE_HDR_SZ);
    ++  memset(PARSE_TAIL(&sParse), 0, PARSE_TAIL_SZ);
    ++  sParse.pReprepare = pReprepare;
    +   assert( ppStmt && *ppStmt==0 );
    +-  assert( !db->mallocFailed );
    ++  /* assert( !db->mallocFailed ); // not true with SQLITE_USE_ALLOCA */
    +   assert( sqlite3_mutex_held(db->mutex) );
    + 
    ++  /* For a long-term use prepared statement avoid the use of
    ++  ** lookaside memory.
    ++  */
    ++  if( prepFlags & SQLITE_PREPARE_PERSISTENT ){
    ++    sParse.disableLookaside++;
    ++    db->lookaside.bDisable++;
    ++  }
    ++
    +   /* Check to verify that it is possible to get a read lock on all
    +   ** database schemas.  The inability to get a read lock indicates that
    +   ** some other database connection is holding a write-lock, which in
    +@@ -108354,9 +118343,9 @@ static int sqlite3Prepare(
    +       assert( sqlite3BtreeHoldsMutex(pBt) );
    +       rc = sqlite3BtreeSchemaLocked(pBt);
    +       if( rc ){
    +-        const char *zDb = db->aDb[i].zName;
    ++        const char *zDb = db->aDb[i].zDbSName;
    +         sqlite3ErrorWithMsg(db, rc, "database schema is locked: %s", zDb);
    +-        testcase( db->flags & SQLITE_ReadUncommitted );
    ++        testcase( db->flags & SQLITE_ReadUncommit );
    +         goto end_prepare;
    +       }
    +     }
    +@@ -108364,8 +118353,7 @@ static int sqlite3Prepare(
    + 
    +   sqlite3VtabUnlockList(db);
    + 
    +-  pParse->db = db;
    +-  pParse->nQueryLoop = 0;  /* Logarithmic, so 0 really means 1 */
    ++  sParse.db = db;
    +   if( nBytes>=0 && (nBytes==0 || zSql[nBytes-1]!=0) ){
    +     char *zSqlCopy;
    +     int mxLen = db->aLimit[SQLITE_LIMIT_SQL_LENGTH];
    +@@ -108378,64 +118366,60 @@ static int sqlite3Prepare(
    +     }
    +     zSqlCopy = sqlite3DbStrNDup(db, zSql, nBytes);
    +     if( zSqlCopy ){
    +-      sqlite3RunParser(pParse, zSqlCopy, &zErrMsg);
    ++      sqlite3RunParser(&sParse, zSqlCopy, &zErrMsg);
    ++      sParse.zTail = &zSql[sParse.zTail-zSqlCopy];
    +       sqlite3DbFree(db, zSqlCopy);
    +-      pParse->zTail = &zSql[pParse->zTail-zSqlCopy];
    +     }else{
    +-      pParse->zTail = &zSql[nBytes];
    ++      sParse.zTail = &zSql[nBytes];
    +     }
    +   }else{
    +-    sqlite3RunParser(pParse, zSql, &zErrMsg);
    ++    sqlite3RunParser(&sParse, zSql, &zErrMsg);
    +   }
    +-  assert( 0==pParse->nQueryLoop );
    ++  assert( 0==sParse.nQueryLoop );
    + 
    +-  if( db->mallocFailed ){
    +-    pParse->rc = SQLITE_NOMEM;
    +-  }
    +-  if( pParse->rc==SQLITE_DONE ) pParse->rc = SQLITE_OK;
    +-  if( pParse->checkSchema ){
    +-    schemaIsValid(pParse);
    ++  if( sParse.rc==SQLITE_DONE ) sParse.rc = SQLITE_OK;
    ++  if( sParse.checkSchema ){
    ++    schemaIsValid(&sParse);
    +   }
    +   if( db->mallocFailed ){
    +-    pParse->rc = SQLITE_NOMEM;
    ++    sParse.rc = SQLITE_NOMEM_BKPT;
    +   }
    +   if( pzTail ){
    +-    *pzTail = pParse->zTail;
    ++    *pzTail = sParse.zTail;
    +   }
    +-  rc = pParse->rc;
    ++  rc = sParse.rc;
    + 
    + #ifndef SQLITE_OMIT_EXPLAIN
    +-  if( rc==SQLITE_OK && pParse->pVdbe && pParse->explain ){
    ++  if( rc==SQLITE_OK && sParse.pVdbe && sParse.explain ){
    +     static const char * const azColName[] = {
    +        "addr", "opcode", "p1", "p2", "p3", "p4", "p5", "comment",
    +        "selectid", "order", "from", "detail"
    +     };
    +     int iFirst, mx;
    +-    if( pParse->explain==2 ){
    +-      sqlite3VdbeSetNumCols(pParse->pVdbe, 4);
    ++    if( sParse.explain==2 ){
    ++      sqlite3VdbeSetNumCols(sParse.pVdbe, 4);
    +       iFirst = 8;
    +       mx = 12;
    +     }else{
    +-      sqlite3VdbeSetNumCols(pParse->pVdbe, 8);
    ++      sqlite3VdbeSetNumCols(sParse.pVdbe, 8);
    +       iFirst = 0;
    +       mx = 8;
    +     }
    +     for(i=iFirst; i<mx; i++){
    +-      sqlite3VdbeSetColName(pParse->pVdbe, i-iFirst, COLNAME_NAME,
    ++      sqlite3VdbeSetColName(sParse.pVdbe, i-iFirst, COLNAME_NAME,
    +                             azColName[i], SQLITE_STATIC);
    +     }
    +   }
    + #endif
    + 
    +   if( db->init.busy==0 ){
    +-    Vdbe *pVdbe = pParse->pVdbe;
    +-    sqlite3VdbeSetSql(pVdbe, zSql, (int)(pParse->zTail-zSql), saveSqlFlag);
    ++    sqlite3VdbeSetSql(sParse.pVdbe, zSql, (int)(sParse.zTail-zSql), prepFlags);
    +   }
    +-  if( pParse->pVdbe && (rc!=SQLITE_OK || db->mallocFailed) ){
    +-    sqlite3VdbeFinalize(pParse->pVdbe);
    ++  if( sParse.pVdbe && (rc!=SQLITE_OK || db->mallocFailed) ){
    ++    sqlite3VdbeFinalize(sParse.pVdbe);
    +     assert(!(*ppStmt));
    +   }else{
    +-    *ppStmt = (sqlite3_stmt*)pParse->pVdbe;
    ++    *ppStmt = (sqlite3_stmt*)sParse.pVdbe;
    +   }
    + 
    +   if( zErrMsg ){
    +@@ -108446,30 +118430,28 @@ static int sqlite3Prepare(
    +   }
    + 
    +   /* Delete any TriggerPrg structures allocated while parsing this statement. */
    +-  while( pParse->pTriggerPrg ){
    +-    TriggerPrg *pT = pParse->pTriggerPrg;
    +-    pParse->pTriggerPrg = pT->pNext;
    ++  while( sParse.pTriggerPrg ){
    ++    TriggerPrg *pT = sParse.pTriggerPrg;
    ++    sParse.pTriggerPrg = pT->pNext;
    +     sqlite3DbFree(db, pT);
    +   }
    + 
    + end_prepare:
    + 
    +-  sqlite3ParserReset(pParse);
    +-  sqlite3StackFree(db, pParse);
    +-  rc = sqlite3ApiExit(db, rc);
    +-  assert( (rc&db->errMask)==rc );
    ++  sqlite3ParserReset(&sParse);
    +   return rc;
    + }
    + static int sqlite3LockAndPrepare(
    +   sqlite3 *db,              /* Database handle. */
    +   const char *zSql,         /* UTF-8 encoded SQL statement. */
    +   int nBytes,               /* Length of zSql in bytes. */
    +-  int saveSqlFlag,          /* True to copy SQL text into the sqlite3_stmt */
    ++  u32 prepFlags,            /* Zero or more SQLITE_PREPARE_* flags */
    +   Vdbe *pOld,               /* VM being reprepared */
    +   sqlite3_stmt **ppStmt,    /* OUT: A pointer to the prepared statement */
    +   const char **pzTail       /* OUT: End of parsed string */
    + ){
    +   int rc;
    ++  int cnt = 0;
    + 
    + #ifdef SQLITE_ENABLE_API_ARMOR
    +   if( ppStmt==0 ) return SQLITE_MISUSE_BKPT;
    +@@ -108480,14 +118462,18 @@ static int sqlite3LockAndPrepare(
    +   }
    +   sqlite3_mutex_enter(db->mutex);
    +   sqlite3BtreeEnterAll(db);
    +-  rc = sqlite3Prepare(db, zSql, nBytes, saveSqlFlag, pOld, ppStmt, pzTail);
    +-  if( rc==SQLITE_SCHEMA ){
    +-    sqlite3_finalize(*ppStmt);
    +-    rc = sqlite3Prepare(db, zSql, nBytes, saveSqlFlag, pOld, ppStmt, pzTail);
    +-  }
    ++  do{
    ++    /* Make multiple attempts to compile the SQL, until it either succeeds
    ++    ** or encounters a permanent error.  A schema problem after one schema
    ++    ** reset is considered a permanent error. */
    ++    rc = sqlite3Prepare(db, zSql, nBytes, prepFlags, pOld, ppStmt, pzTail);
    ++    assert( rc==SQLITE_OK || *ppStmt==0 );
    ++  }while( rc==SQLITE_ERROR_RETRY
    ++       || (rc==SQLITE_SCHEMA && (sqlite3ResetOneSchema(db,-1), cnt++)==0) );
    +   sqlite3BtreeLeaveAll(db);
    ++  rc = sqlite3ApiExit(db, rc);
    ++  assert( (rc&db->errMask)==rc );
    +   sqlite3_mutex_leave(db->mutex);
    +-  assert( rc==SQLITE_OK || *ppStmt==0 );
    +   return rc;
    + }
    + 
    +@@ -108504,16 +118490,18 @@ SQLITE_PRIVATE int sqlite3Reprepare(Vdbe *p){
    +   sqlite3_stmt *pNew;
    +   const char *zSql;
    +   sqlite3 *db;
    ++  u8 prepFlags;
    + 
    +   assert( sqlite3_mutex_held(sqlite3VdbeDb(p)->mutex) );
    +   zSql = sqlite3_sql((sqlite3_stmt *)p);
    +   assert( zSql!=0 );  /* Reprepare only called for prepare_v2() statements */
    +   db = sqlite3VdbeDb(p);
    +   assert( sqlite3_mutex_held(db->mutex) );
    +-  rc = sqlite3LockAndPrepare(db, zSql, -1, 0, p, &pNew, 0);
    ++  prepFlags = sqlite3VdbePrepareFlags(p);
    ++  rc = sqlite3LockAndPrepare(db, zSql, -1, prepFlags, p, &pNew, 0);
    +   if( rc ){
    +     if( rc==SQLITE_NOMEM ){
    +-      db->mallocFailed = 1;
    ++      sqlite3OomFault(db);
    +     }
    +     assert( pNew==0 );
    +     return rc;
    +@@ -108536,7 +118524,7 @@ SQLITE_PRIVATE int sqlite3Reprepare(Vdbe *p){
    + ** and the statement is automatically recompiled if an schema change
    + ** occurs.
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_prepare(
    ++SQLITE_API int sqlite3_prepare(
    +   sqlite3 *db,              /* Database handle. */
    +   const char *zSql,         /* UTF-8 encoded SQL statement. */
    +   int nBytes,               /* Length of zSql in bytes. */
    +@@ -108548,7 +118536,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_prepare(
    +   assert( rc==SQLITE_OK || ppStmt==0 || *ppStmt==0 );  /* VERIFY: F13021 */
    +   return rc;
    + }
    +-SQLITE_API int SQLITE_STDCALL sqlite3_prepare_v2(
    ++SQLITE_API int sqlite3_prepare_v2(
    +   sqlite3 *db,              /* Database handle. */
    +   const char *zSql,         /* UTF-8 encoded SQL statement. */
    +   int nBytes,               /* Length of zSql in bytes. */
    +@@ -108556,8 +118544,36 @@ SQLITE_API int SQLITE_STDCALL sqlite3_prepare_v2(
    +   const char **pzTail       /* OUT: End of parsed string */
    + ){
    +   int rc;
    +-  rc = sqlite3LockAndPrepare(db,zSql,nBytes,1,0,ppStmt,pzTail);
    +-  assert( rc==SQLITE_OK || ppStmt==0 || *ppStmt==0 );  /* VERIFY: F13021 */
    ++  /* EVIDENCE-OF: R-37923-12173 The sqlite3_prepare_v2() interface works
    ++  ** exactly the same as sqlite3_prepare_v3() with a zero prepFlags
    ++  ** parameter.
    ++  **
    ++  ** Proof in that the 5th parameter to sqlite3LockAndPrepare is 0 */
    ++  rc = sqlite3LockAndPrepare(db,zSql,nBytes,SQLITE_PREPARE_SAVESQL,0,
    ++                             ppStmt,pzTail);
    ++  assert( rc==SQLITE_OK || ppStmt==0 || *ppStmt==0 );
    ++  return rc;
    ++}
    ++SQLITE_API int sqlite3_prepare_v3(
    ++  sqlite3 *db,              /* Database handle. */
    ++  const char *zSql,         /* UTF-8 encoded SQL statement. */
    ++  int nBytes,               /* Length of zSql in bytes. */
    ++  unsigned int prepFlags,   /* Zero or more SQLITE_PREPARE_* flags */
    ++  sqlite3_stmt **ppStmt,    /* OUT: A pointer to the prepared statement */
    ++  const char **pzTail       /* OUT: End of parsed string */
    ++){
    ++  int rc;
    ++  /* EVIDENCE-OF: R-56861-42673 sqlite3_prepare_v3() differs from
    ++  ** sqlite3_prepare_v2() only in having the extra prepFlags parameter,
    ++  ** which is a bit array consisting of zero or more of the
    ++  ** SQLITE_PREPARE_* flags.
    ++  **
    ++  ** Proof by comparison to the implementation of sqlite3_prepare_v2()
    ++  ** directly above. */
    ++  rc = sqlite3LockAndPrepare(db,zSql,nBytes,
    ++                 SQLITE_PREPARE_SAVESQL|(prepFlags&SQLITE_PREPARE_MASK),
    ++                 0,ppStmt,pzTail);
    ++  assert( rc==SQLITE_OK || ppStmt==0 || *ppStmt==0 );
    +   return rc;
    + }
    + 
    +@@ -108570,7 +118586,7 @@ static int sqlite3Prepare16(
    +   sqlite3 *db,              /* Database handle. */ 
    +   const void *zSql,         /* UTF-16 encoded SQL statement. */
    +   int nBytes,               /* Length of zSql in bytes. */
    +-  int saveSqlFlag,          /* True to save SQL text into the sqlite3_stmt */
    ++  u32 prepFlags,            /* Zero or more SQLITE_PREPARE_* flags */
    +   sqlite3_stmt **ppStmt,    /* OUT: A pointer to the prepared statement */
    +   const void **pzTail       /* OUT: End of parsed string */
    + ){
    +@@ -108598,7 +118614,7 @@ static int sqlite3Prepare16(
    +   sqlite3_mutex_enter(db->mutex);
    +   zSql8 = sqlite3Utf16to8(db, zSql, nBytes, SQLITE_UTF16NATIVE);
    +   if( zSql8 ){
    +-    rc = sqlite3LockAndPrepare(db, zSql8, -1, saveSqlFlag, 0, ppStmt, &zTail8);
    ++    rc = sqlite3LockAndPrepare(db, zSql8, -1, prepFlags, 0, ppStmt, &zTail8);
    +   }
    + 
    +   if( zTail8 && pzTail ){
    +@@ -108624,7 +118640,7 @@ static int sqlite3Prepare16(
    + ** and the statement is automatically recompiled if an schema change
    + ** occurs.
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_prepare16(
    ++SQLITE_API int sqlite3_prepare16(
    +   sqlite3 *db,              /* Database handle. */ 
    +   const void *zSql,         /* UTF-16 encoded SQL statement. */
    +   int nBytes,               /* Length of zSql in bytes. */
    +@@ -108636,7 +118652,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_prepare16(
    +   assert( rc==SQLITE_OK || ppStmt==0 || *ppStmt==0 );  /* VERIFY: F13021 */
    +   return rc;
    + }
    +-SQLITE_API int SQLITE_STDCALL sqlite3_prepare16_v2(
    ++SQLITE_API int sqlite3_prepare16_v2(
    +   sqlite3 *db,              /* Database handle. */ 
    +   const void *zSql,         /* UTF-16 encoded SQL statement. */
    +   int nBytes,               /* Length of zSql in bytes. */
    +@@ -108644,7 +118660,22 @@ SQLITE_API int SQLITE_STDCALL sqlite3_prepare16_v2(
    +   const void **pzTail       /* OUT: End of parsed string */
    + ){
    +   int rc;
    +-  rc = sqlite3Prepare16(db,zSql,nBytes,1,ppStmt,pzTail);
    ++  rc = sqlite3Prepare16(db,zSql,nBytes,SQLITE_PREPARE_SAVESQL,ppStmt,pzTail);
    ++  assert( rc==SQLITE_OK || ppStmt==0 || *ppStmt==0 );  /* VERIFY: F13021 */
    ++  return rc;
    ++}
    ++SQLITE_API int sqlite3_prepare16_v3(
    ++  sqlite3 *db,              /* Database handle. */ 
    ++  const void *zSql,         /* UTF-16 encoded SQL statement. */
    ++  int nBytes,               /* Length of zSql in bytes. */
    ++  unsigned int prepFlags,   /* Zero or more SQLITE_PREPARE_* flags */
    ++  sqlite3_stmt **ppStmt,    /* OUT: A pointer to the prepared statement */
    ++  const void **pzTail       /* OUT: End of parsed string */
    ++){
    ++  int rc;
    ++  rc = sqlite3Prepare16(db,zSql,nBytes,
    ++         SQLITE_PREPARE_SAVESQL|(prepFlags&SQLITE_PREPARE_MASK),
    ++         ppStmt,pzTail);
    +   assert( rc==SQLITE_OK || ppStmt==0 || *ppStmt==0 );  /* VERIFY: F13021 */
    +   return rc;
    + }
    +@@ -108709,7 +118740,9 @@ struct SortCtx {
    +   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 */
    ++  int labelDone;        /* Jump here when done, ex: LIMIT reached */
    +   u8 sortFlags;         /* Zero or more SORTFLAG_* bits */
    ++  u8 bOrderedInnerLoop; /* ORDER BY correctly sorts the inner loop */
    + };
    + #define SORTFLAG_UseSorter  0x01   /* Use SorterOpen instead of OpenEphemeral */
    + 
    +@@ -108727,9 +118760,8 @@ static void clearSelect(sqlite3 *db, Select *p, int bFree){
    +     sqlite3ExprDelete(db, p->pHaving);
    +     sqlite3ExprListDelete(db, p->pOrderBy);
    +     sqlite3ExprDelete(db, p->pLimit);
    +-    sqlite3ExprDelete(db, p->pOffset);
    +-    sqlite3WithDelete(db, p->pWith);
    +-    if( bFree ) sqlite3DbFree(db, p);
    ++    if( OK_IF_ALWAYS_TRUE(p->pWith) ) sqlite3WithDelete(db, p->pWith);
    ++    if( bFree ) sqlite3DbFreeNN(db, p);
    +     p = pPrior;
    +     bFree = 1;
    +   }
    +@@ -108741,7 +118773,7 @@ static void clearSelect(sqlite3 *db, Select *p, int bFree){
    + SQLITE_PRIVATE void sqlite3SelectDestInit(SelectDest *pDest, int eDest, int iParm){
    +   pDest->eDest = (u8)eDest;
    +   pDest->iSDParm = iParm;
    +-  pDest->affSdst = 0;
    ++  pDest->zAffSdst = 0;
    +   pDest->iSdst = 0;
    +   pDest->nSdst = 0;
    + }
    +@@ -108759,38 +118791,43 @@ SQLITE_PRIVATE Select *sqlite3SelectNew(
    +   ExprList *pGroupBy,   /* the GROUP BY clause */
    +   Expr *pHaving,        /* the HAVING clause */
    +   ExprList *pOrderBy,   /* the ORDER BY clause */
    +-  u16 selFlags,         /* Flag parameters, such as SF_Distinct */
    +-  Expr *pLimit,         /* LIMIT value.  NULL means not used */
    +-  Expr *pOffset         /* OFFSET value.  NULL means no offset */
    ++  u32 selFlags,         /* Flag parameters, such as SF_Distinct */
    ++  Expr *pLimit          /* LIMIT value.  NULL means not used */
    + ){
    +   Select *pNew;
    +   Select standin;
    +-  sqlite3 *db = pParse->db;
    +-  pNew = sqlite3DbMallocZero(db, sizeof(*pNew) );
    ++  pNew = sqlite3DbMallocRawNN(pParse->db, sizeof(*pNew) );
    +   if( pNew==0 ){
    +-    assert( db->mallocFailed );
    ++    assert( pParse->db->mallocFailed );
    +     pNew = &standin;
    +-    memset(pNew, 0, sizeof(*pNew));
    +   }
    +   if( pEList==0 ){
    +-    pEList = sqlite3ExprListAppend(pParse, 0, sqlite3Expr(db,TK_ALL,0));
    ++    pEList = sqlite3ExprListAppend(pParse, 0,
    ++                                   sqlite3Expr(pParse->db,TK_ASTERISK,0));
    +   }
    +   pNew->pEList = pEList;
    +-  if( pSrc==0 ) pSrc = sqlite3DbMallocZero(db, sizeof(*pSrc));
    ++  pNew->op = TK_SELECT;
    ++  pNew->selFlags = selFlags;
    ++  pNew->iLimit = 0;
    ++  pNew->iOffset = 0;
    ++#if SELECTTRACE_ENABLED
    ++  pNew->zSelName[0] = 0;
    ++#endif
    ++  pNew->addrOpenEphm[0] = -1;
    ++  pNew->addrOpenEphm[1] = -1;
    ++  pNew->nSelectRow = 0;
    ++  if( pSrc==0 ) pSrc = sqlite3DbMallocZero(pParse->db, sizeof(*pSrc));
    +   pNew->pSrc = pSrc;
    +   pNew->pWhere = pWhere;
    +   pNew->pGroupBy = pGroupBy;
    +   pNew->pHaving = pHaving;
    +   pNew->pOrderBy = pOrderBy;
    +-  pNew->selFlags = selFlags;
    +-  pNew->op = TK_SELECT;
    ++  pNew->pPrior = 0;
    ++  pNew->pNext = 0;
    +   pNew->pLimit = pLimit;
    +-  pNew->pOffset = pOffset;
    +-  assert( pOffset==0 || pLimit!=0 || pParse->nErr>0 || db->mallocFailed!=0 );
    +-  pNew->addrOpenEphm[0] = -1;
    +-  pNew->addrOpenEphm[1] = -1;
    +-  if( db->mallocFailed ) {
    +-    clearSelect(db, pNew, pNew!=&standin);
    ++  pNew->pWith = 0;
    ++  if( pParse->db->mallocFailed ) {
    ++    clearSelect(pParse->db, pNew, pNew!=&standin);
    +     pNew = 0;
    +   }else{
    +     assert( pNew->pSrc!=0 || pParse->nErr>0 );
    +@@ -108815,7 +118852,7 @@ SQLITE_PRIVATE void sqlite3SelectSetName(Select *p, const char *zName){
    + ** Delete the given Select structure and all of its substructures.
    + */
    + SQLITE_PRIVATE void sqlite3SelectDelete(sqlite3 *db, Select *p){
    +-  clearSelect(db, p, 1);
    ++  if( OK_IF_ALWAYS_TRUE(p) ) clearSelect(db, p, 1);
    + }
    + 
    + /*
    +@@ -108979,7 +119016,7 @@ static void addWhereTerm(
    +   pE1 = sqlite3CreateColumnExpr(db, pSrc, iLeft, iColLeft);
    +   pE2 = sqlite3CreateColumnExpr(db, pSrc, iRight, iColRight);
    + 
    +-  pEq = sqlite3PExpr(pParse, TK_EQ, pE1, pE2, 0);
    ++  pEq = sqlite3PExpr(pParse, TK_EQ, pE1, pE2);
    +   if( pEq && isOuterJoin ){
    +     ExprSetProperty(pEq, EP_FromJoin);
    +     assert( !ExprHasProperty(pEq, EP_TokenOnly|EP_Reduced) );
    +@@ -109056,11 +119093,10 @@ static int sqliteProcessJoin(Parse *pParse, Select *p){
    +   pLeft = &pSrc->a[0];
    +   pRight = &pLeft[1];
    +   for(i=0; i<pSrc->nSrc-1; i++, pRight++, pLeft++){
    +-    Table *pLeftTab = pLeft->pTab;
    +     Table *pRightTab = pRight->pTab;
    +     int isOuter;
    + 
    +-    if( NEVER(pLeftTab==0 || pRightTab==0) ) continue;
    ++    if( NEVER(pLeft->pTab==0 || pRightTab==0) ) continue;
    +     isOuter = (pRight->fg.jointype & JT_OUTER)!=0;
    + 
    +     /* When the NATURAL keyword is present, add WHERE clause terms for
    +@@ -109163,9 +119199,10 @@ static void pushOntoSorter(
    +   int regRecord = ++pParse->nMem;                  /* Assembled sorter record */
    +   int nOBSat = pSort->nOBSat;                      /* ORDER BY terms to skip */
    +   int op;                            /* Opcode to add sorter record to sorter */
    ++  int iLimit;                        /* LIMIT counter */
    + 
    +   assert( bSeq==0 || bSeq==1 );
    +-  assert( nData==1 || regData==regOrigData );
    ++  assert( nData==1 || regData==regOrigData || regOrigData==0 );
    +   if( nPrefixReg ){
    +     assert( nPrefixReg==nExpr+bSeq );
    +     regBase = regData - nExpr - bSeq;
    +@@ -109173,15 +119210,17 @@ static void pushOntoSorter(
    +     regBase = pParse->nMem + 1;
    +     pParse->nMem += nBase;
    +   }
    ++  assert( pSelect->iOffset==0 || pSelect->iLimit!=0 );
    ++  iLimit = pSelect->iOffset ? pSelect->iOffset+1 : pSelect->iLimit;
    ++  pSort->labelDone = sqlite3VdbeMakeLabel(v);
    +   sqlite3ExprCodeExprList(pParse, pSort->pOrderBy, regBase, regOrigData,
    +-                          SQLITE_ECEL_DUP|SQLITE_ECEL_REF);
    ++                          SQLITE_ECEL_DUP | (regOrigData? SQLITE_ECEL_REF : 0));
    +   if( bSeq ){
    +     sqlite3VdbeAddOp2(v, OP_Sequence, pSort->iECursor, regBase+nExpr);
    +   }
    +-  if( nPrefixReg==0 ){
    ++  if( nPrefixReg==0 && nData>0 ){
    +     sqlite3ExprCodeMove(pParse, regData, regBase+nExpr+bSeq, nData);
    +   }
    +-
    +   sqlite3VdbeAddOp3(v, OP_MakeRecord, regBase+nOBSat, nBase-nOBSat, regRecord);
    +   if( nOBSat>0 ){
    +     int regPrevKey;   /* The first nOBSat columns of the previous row */
    +@@ -109205,17 +119244,21 @@ static void pushOntoSorter(
    +     if( pParse->db->mallocFailed ) return;
    +     pOp->p2 = nKey + nData;
    +     pKI = pOp->p4.pKeyInfo;
    +-    memset(pKI->aSortOrder, 0, pKI->nField); /* Makes OP_Jump below testable */
    ++    memset(pKI->aSortOrder, 0, pKI->nKeyField); /* Makes OP_Jump testable */
    +     sqlite3VdbeChangeP4(v, -1, (char*)pKI, P4_KEYINFO);
    +-    testcase( pKI->nXField>2 );
    ++    testcase( pKI->nAllField > pKI->nKeyField+2 );
    +     pOp->p4.pKeyInfo = keyInfoFromExprList(pParse, pSort->pOrderBy, nOBSat,
    +-                                           pKI->nXField-1);
    ++                                           pKI->nAllField-pKI->nKeyField-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);
    ++    if( iLimit ){
    ++      sqlite3VdbeAddOp2(v, OP_IfNot, iLimit, pSort->labelDone);
    ++      VdbeCoverage(v);
    ++    }
    +     sqlite3VdbeJumpHere(v, addrFirst);
    +     sqlite3ExprCodeMove(pParse, regBase, regPrevKey, pSort->nOBSat);
    +     sqlite3VdbeJumpHere(v, addrJmp);
    +@@ -109225,18 +119268,34 @@ static void pushOntoSorter(
    +   }else{
    +     op = OP_IdxInsert;
    +   }
    +-  sqlite3VdbeAddOp2(v, op, pSort->iECursor, regRecord);
    +-  if( pSelect->iLimit ){
    ++  sqlite3VdbeAddOp4Int(v, op, pSort->iECursor, regRecord,
    ++                       regBase+nOBSat, nBase-nOBSat);
    ++  if( iLimit ){
    +     int addr;
    +-    int iLimit;
    +-    if( pSelect->iOffset ){
    +-      iLimit = pSelect->iOffset+1;
    +-    }else{
    +-      iLimit = pSelect->iLimit;
    +-    }
    +-    addr = sqlite3VdbeAddOp3(v, OP_IfNotZero, iLimit, 0, 1); VdbeCoverage(v);
    ++    int r1 = 0;
    ++    /* Fill the sorter until it contains LIMIT+OFFSET entries.  (The iLimit
    ++    ** register is initialized with value of LIMIT+OFFSET.)  After the sorter
    ++    ** fills up, delete the least entry in the sorter after each insert.
    ++    ** Thus we never hold more than the LIMIT+OFFSET rows in memory at once */
    ++    addr = sqlite3VdbeAddOp1(v, OP_IfNotZero, iLimit); VdbeCoverage(v);
    +     sqlite3VdbeAddOp1(v, OP_Last, pSort->iECursor);
    ++    if( pSort->bOrderedInnerLoop ){
    ++      r1 = ++pParse->nMem;
    ++      sqlite3VdbeAddOp3(v, OP_Column, pSort->iECursor, nExpr, r1);
    ++      VdbeComment((v, "seq"));
    ++    }
    +     sqlite3VdbeAddOp1(v, OP_Delete, pSort->iECursor);
    ++    if( pSort->bOrderedInnerLoop ){
    ++      /* If the inner loop is driven by an index such that values from
    ++      ** the same iteration of the inner loop are in sorted order, then
    ++      ** immediately jump to the next iteration of an inner loop if the
    ++      ** entry from the current iteration does not fit into the top
    ++      ** LIMIT+OFFSET entries of the sorter. */
    ++      int iBrk = sqlite3VdbeCurrentAddr(v) + 2;
    ++      sqlite3VdbeAddOp3(v, OP_Eq, regBase+nExpr, iBrk, r1);
    ++      sqlite3VdbeChangeP5(v, SQLITE_NULLEQ);
    ++      VdbeCoverage(v);
    ++    }
    +     sqlite3VdbeJumpHere(v, addr);
    +   }
    + }
    +@@ -109278,48 +119337,24 @@ static void codeDistinct(
    +   r1 = sqlite3GetTempReg(pParse);
    +   sqlite3VdbeAddOp4Int(v, OP_Found, iTab, addrRepeat, iMem, N); VdbeCoverage(v);
    +   sqlite3VdbeAddOp3(v, OP_MakeRecord, iMem, N, r1);
    +-  sqlite3VdbeAddOp2(v, OP_IdxInsert, iTab, r1);
    ++  sqlite3VdbeAddOp4Int(v, OP_IdxInsert, iTab, r1, iMem, N);
    ++  sqlite3VdbeChangeP5(v, OPFLAG_USESEEKRESULT);
    +   sqlite3ReleaseTempReg(pParse, r1);
    + }
    + 
    +-#ifndef SQLITE_OMIT_SUBQUERY
    +-/*
    +-** Generate an error message when a SELECT is used within a subexpression
    +-** (example:  "a IN (SELECT * FROM table)") but it has more than 1 result
    +-** column.  We do this in a subroutine because the error used to occur
    +-** in multiple places.  (The error only occurs in one place now, but we
    +-** retain the subroutine to minimize code disruption.)
    +-*/
    +-static int checkForMultiColumnSelectError(
    +-  Parse *pParse,       /* Parse context. */
    +-  SelectDest *pDest,   /* Destination of SELECT results */
    +-  int nExpr            /* Number of result columns returned by SELECT */
    +-){
    +-  int eDest = pDest->eDest;
    +-  if( nExpr>1 && (eDest==SRT_Mem || eDest==SRT_Set) ){
    +-    sqlite3ErrorMsg(pParse, "only a single result allowed for "
    +-       "a SELECT that is part of an expression");
    +-    return 1;
    +-  }else{
    +-    return 0;
    +-  }
    +-}
    +-#endif
    +-
    + /*
    + ** This routine generates the code for the inside of the inner loop
    + ** of a SELECT.
    + **
    +-** If srcTab is negative, then the pEList expressions
    ++** If srcTab is negative, then the p->pEList expressions
    + ** are evaluated in order to get the data for this row.  If srcTab is
    +-** zero or more, then data is pulled from srcTab and pEList is used only 
    +-** to get number columns and the datatype for each column.
    ++** zero or more, then data is pulled from srcTab and p->pEList is used only 
    ++** to get the number of columns and the collation sequence for each column.
    + */
    + static void selectInnerLoop(
    +   Parse *pParse,          /* The parser context */
    +   Select *p,              /* The complete select statement being coded */
    +-  ExprList *pEList,       /* List of values being extracted */
    +-  int srcTab,             /* Pull data from this table */
    ++  int srcTab,             /* Pull data from this table if non-negative */
    +   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 */
    +@@ -109328,15 +119363,22 @@ static void selectInnerLoop(
    + ){
    +   Vdbe *v = pParse->pVdbe;
    +   int i;
    +-  int hasDistinct;        /* True if the DISTINCT keyword is present */
    +-  int regResult;              /* Start of memory holding result set */
    ++  int hasDistinct;            /* True if the DISTINCT keyword is present */
    +   int eDest = pDest->eDest;   /* How to dispose of results */
    +   int iParm = pDest->iSDParm; /* First argument to disposal method */
    +   int nResultCol;             /* Number of result columns */
    +   int nPrefixReg = 0;         /* Number of extra registers before regResult */
    + 
    ++  /* Usually, regResult is the first cell in an array of memory cells
    ++  ** containing the current result row. In this case regOrig is set to the
    ++  ** same value. However, if the results are being sent to the sorter, the
    ++  ** values for any expressions that are also part of the sort-key are omitted
    ++  ** from this array. In this case regOrig is set to zero.  */
    ++  int regResult;              /* Start of memory holding current results */
    ++  int regOrig;                /* Start of memory holding full result (or 0) */
    ++
    +   assert( v );
    +-  assert( pEList!=0 );
    ++  assert( p->pEList!=0 );
    +   hasDistinct = pDistinct ? pDistinct->eTnctType : WHERE_DISTINCT_NOOP;
    +   if( pSort && pSort->pOrderBy==0 ) pSort = 0;
    +   if( pSort==0 && !hasDistinct ){
    +@@ -109346,7 +119388,7 @@ static void selectInnerLoop(
    + 
    +   /* Pull the requested columns.
    +   */
    +-  nResultCol = pEList->nExpr;
    ++  nResultCol = p->pEList->nExpr;
    + 
    +   if( pDest->iSdst==0 ){
    +     if( pSort ){
    +@@ -109365,11 +119407,11 @@ static void selectInnerLoop(
    +     pParse->nMem += nResultCol;
    +   }
    +   pDest->nSdst = nResultCol;
    +-  regResult = pDest->iSdst;
    ++  regOrig = regResult = pDest->iSdst;
    +   if( srcTab>=0 ){
    +     for(i=0; i<nResultCol; i++){
    +       sqlite3VdbeAddOp3(v, OP_Column, srcTab, i, regResult+i);
    +-      VdbeComment((v, "%s", pEList->a[i].zName));
    ++      VdbeComment((v, "%s", p->pEList->a[i].zName));
    +     }
    +   }else if( eDest!=SRT_Exists ){
    +     /* If the destination is an EXISTS(...) expression, the actual
    +@@ -109381,7 +119423,26 @@ static void selectInnerLoop(
    +     }else{
    +       ecelFlags = 0;
    +     }
    +-    sqlite3ExprCodeExprList(pParse, pEList, regResult, 0, ecelFlags);
    ++    if( pSort && hasDistinct==0 && eDest!=SRT_EphemTab && eDest!=SRT_Table ){
    ++      /* For each expression in p->pEList that is a copy of an expression in
    ++      ** the ORDER BY clause (pSort->pOrderBy), set the associated 
    ++      ** iOrderByCol value to one more than the index of the ORDER BY 
    ++      ** expression within the sort-key that pushOntoSorter() will generate.
    ++      ** This allows the p->pEList field to be omitted from the sorted record,
    ++      ** saving space and CPU cycles.  */
    ++      ecelFlags |= (SQLITE_ECEL_OMITREF|SQLITE_ECEL_REF);
    ++      for(i=pSort->nOBSat; i<pSort->pOrderBy->nExpr; i++){
    ++        int j;
    ++        if( (j = pSort->pOrderBy->a[i].u.x.iOrderByCol)>0 ){
    ++          p->pEList->a[j-1].u.x.iOrderByCol = i+1-pSort->nOBSat;
    ++        }
    ++      }
    ++      regOrig = 0;
    ++      assert( eDest==SRT_Set || eDest==SRT_Mem 
    ++           || eDest==SRT_Coroutine || eDest==SRT_Output );
    ++    }
    ++    nResultCol = sqlite3ExprCodeExprList(pParse,p->pEList,regResult,
    ++                                         0,ecelFlags);
    +   }
    + 
    +   /* If the DISTINCT keyword was present on the SELECT statement
    +@@ -109413,7 +119474,7 @@ static void selectInnerLoop(
    + 
    +         iJump = sqlite3VdbeCurrentAddr(v) + nResultCol;
    +         for(i=0; i<nResultCol; i++){
    +-          CollSeq *pColl = sqlite3ExprCollSeq(pParse, pEList->a[i].pExpr);
    ++          CollSeq *pColl = sqlite3ExprCollSeq(pParse, p->pEList->a[i].pExpr);
    +           if( i<nResultCol-1 ){
    +             sqlite3VdbeAddOp3(v, OP_Ne, regResult+i, iJump, regPrev+i);
    +             VdbeCoverage(v);
    +@@ -109455,7 +119516,7 @@ static void selectInnerLoop(
    +       int r1;
    +       r1 = sqlite3GetTempReg(pParse);
    +       sqlite3VdbeAddOp3(v, OP_MakeRecord, regResult, nResultCol, r1);
    +-      sqlite3VdbeAddOp2(v, OP_IdxInsert, iParm, r1);
    ++      sqlite3VdbeAddOp4Int(v, OP_IdxInsert, iParm, r1, regResult, nResultCol);
    +       sqlite3ReleaseTempReg(pParse, r1);
    +       break;
    +     }
    +@@ -109492,7 +119553,7 @@ 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);
    ++        sqlite3VdbeAddOp4Int(v, OP_IdxInsert, iParm+1, r1,regResult,nResultCol);
    +         assert( pSort==0 );
    +       }
    + #endif
    +@@ -109515,20 +119576,20 @@ static void selectInnerLoop(
    +     ** item into the set table with bogus data.
    +     */
    +     case SRT_Set: {
    +-      assert( nResultCol==1 );
    +-      pDest->affSdst =
    +-                  sqlite3CompareAffinity(pEList->a[0].pExpr, pDest->affSdst);
    +       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, pSort, p, regResult, regResult, 1, nPrefixReg);
    ++        pushOntoSorter(
    ++            pParse, pSort, p, regResult, regOrig, nResultCol, nPrefixReg);
    +       }else{
    +         int r1 = sqlite3GetTempReg(pParse);
    +-        sqlite3VdbeAddOp4(v, OP_MakeRecord, regResult,1,r1, &pDest->affSdst, 1);
    +-        sqlite3ExprCacheAffinityChange(pParse, regResult, 1);
    +-        sqlite3VdbeAddOp2(v, OP_IdxInsert, iParm, r1);
    ++        assert( sqlite3Strlen30(pDest->zAffSdst)==nResultCol );
    ++        sqlite3VdbeAddOp4(v, OP_MakeRecord, regResult, nResultCol, 
    ++            r1, pDest->zAffSdst, nResultCol);
    ++        sqlite3ExprCacheAffinityChange(pParse, regResult, nResultCol);
    ++        sqlite3VdbeAddOp4Int(v, OP_IdxInsert, iParm, r1, regResult, nResultCol);
    +         sqlite3ReleaseTempReg(pParse, r1);
    +       }
    +       break;
    +@@ -109543,14 +119604,16 @@ static void selectInnerLoop(
    +     }
    + 
    +     /* If this is a scalar select that is part of an expression, then
    +-    ** store the results in the appropriate memory cell and break out
    +-    ** of the scan loop.
    ++    ** store the results in the appropriate memory cell or array of 
    ++    ** memory cells and break out of the scan loop.
    +     */
    +     case SRT_Mem: {
    +-      assert( nResultCol==1 );
    +       if( pSort ){
    +-        pushOntoSorter(pParse, pSort, p, regResult, regResult, 1, nPrefixReg);
    ++        assert( nResultCol<=pDest->nSdst );
    ++        pushOntoSorter(
    ++            pParse, pSort, p, regResult, regOrig, nResultCol, nPrefixReg);
    +       }else{
    ++        assert( nResultCol==pDest->nSdst );
    +         assert( regResult==iParm );
    +         /* The LIMIT clause will jump out of the loop for us */
    +       }
    +@@ -109563,7 +119626,7 @@ static void selectInnerLoop(
    +       testcase( eDest==SRT_Coroutine );
    +       testcase( eDest==SRT_Output );
    +       if( pSort ){
    +-        pushOntoSorter(pParse, pSort, p, regResult, regResult, nResultCol,
    ++        pushOntoSorter(pParse, pSort, p, regResult, regOrig, nResultCol,
    +                        nPrefixReg);
    +       }else if( eDest==SRT_Coroutine ){
    +         sqlite3VdbeAddOp1(v, OP_Yield, pDest->iSDParm);
    +@@ -109613,7 +119676,7 @@ static void selectInnerLoop(
    +       }
    +       sqlite3VdbeAddOp2(v, OP_Sequence, iParm, r2+nKey);
    +       sqlite3VdbeAddOp3(v, OP_MakeRecord, r2, nKey+2, r1);
    +-      sqlite3VdbeAddOp2(v, OP_IdxInsert, iParm, r1);
    ++      sqlite3VdbeAddOp4Int(v, OP_IdxInsert, iParm, r1, r2, nKey+2);
    +       if( addrTest ) sqlite3VdbeJumpHere(v, addrTest);
    +       sqlite3ReleaseTempReg(pParse, r1);
    +       sqlite3ReleaseTempRange(pParse, r2, nKey+2);
    +@@ -109650,17 +119713,18 @@ static void selectInnerLoop(
    + ** X extra columns.
    + */
    + SQLITE_PRIVATE KeyInfo *sqlite3KeyInfoAlloc(sqlite3 *db, int N, int X){
    +-  KeyInfo *p = sqlite3DbMallocZero(0, 
    +-                   sizeof(KeyInfo) + (N+X)*(sizeof(CollSeq*)+1));
    ++  int nExtra = (N+X)*(sizeof(CollSeq*)+1) - sizeof(CollSeq*);
    ++  KeyInfo *p = sqlite3DbMallocRawNN(db, sizeof(KeyInfo) + nExtra);
    +   if( p ){
    +     p->aSortOrder = (u8*)&p->aColl[N+X];
    +-    p->nField = (u16)N;
    +-    p->nXField = (u16)X;
    ++    p->nKeyField = (u16)N;
    ++    p->nAllField = (u16)(N+X);
    +     p->enc = ENC(db);
    +     p->db = db;
    +     p->nRef = 1;
    ++    memset(&p[1], 0, nExtra);
    +   }else{
    +-    db->mallocFailed = 1;
    ++    sqlite3OomFault(db);
    +   }
    +   return p;
    + }
    +@@ -109672,7 +119736,7 @@ SQLITE_PRIVATE void sqlite3KeyInfoUnref(KeyInfo *p){
    +   if( p ){
    +     assert( p->nRef>0 );
    +     p->nRef--;
    +-    if( p->nRef==0 ) sqlite3DbFree(0, p);
    ++    if( p->nRef==0 ) sqlite3DbFreeNN(p->db, p);
    +   }
    + }
    + 
    +@@ -109728,10 +119792,7 @@ static KeyInfo *keyInfoFromExprList(
    +   if( pInfo ){
    +     assert( sqlite3KeyInfoIsWriteable(pInfo) );
    +     for(i=iStart, pItem=pList->a+iStart; i<nExpr; i++, pItem++){
    +-      CollSeq *pColl;
    +-      pColl = sqlite3ExprCollSeq(pParse, pItem->pExpr);
    +-      if( !pColl ) pColl = db->pDfltColl;
    +-      pInfo->aColl[i-iStart] = pColl;
    ++      pInfo->aColl[i-iStart] = sqlite3ExprNNCollSeq(pParse, pItem->pExpr);
    +       pInfo->aSortOrder[i-iStart] = pItem->sortOrder;
    +     }
    +   }
    +@@ -109837,7 +119898,7 @@ static void generateSortTail(
    +   SelectDest *pDest /* Write the sorted results here */
    + ){
    +   Vdbe *v = pParse->pVdbe;                     /* The prepared statement */
    +-  int addrBreak = sqlite3VdbeMakeLabel(v);     /* Jump here to exit loop */
    ++  int addrBreak = pSort->labelDone;            /* Jump here to exit loop */
    +   int addrContinue = sqlite3VdbeMakeLabel(v);  /* Jump here for next cycle */
    +   int addr;
    +   int addrOnce = 0;
    +@@ -109847,36 +119908,36 @@ static void generateSortTail(
    +   int iParm = pDest->iSDParm;
    +   int regRow;
    +   int regRowid;
    ++  int iCol;
    +   int nKey;
    +   int iSortTab;                   /* Sorter cursor to read from */
    +   int nSortData;                  /* Trailing values to read from sorter */
    +   int i;
    +   int bSeq;                       /* True if sorter record includes seq. no. */
    +-#ifdef SQLITE_ENABLE_EXPLAIN_COMMENTS
    +   struct ExprList_item *aOutEx = p->pEList->a;
    +-#endif
    + 
    ++  assert( addrBreak<0 );
    +   if( pSort->labelBkOut ){
    +     sqlite3VdbeAddOp2(v, OP_Gosub, pSort->regReturn, pSort->labelBkOut);
    +     sqlite3VdbeGoto(v, addrBreak);
    +     sqlite3VdbeResolveLabel(v, pSort->labelBkOut);
    +   }
    +   iTab = pSort->iECursor;
    +-  if( eDest==SRT_Output || eDest==SRT_Coroutine ){
    ++  if( eDest==SRT_Output || eDest==SRT_Coroutine || eDest==SRT_Mem ){
    +     regRowid = 0;
    +     regRow = pDest->iSdst;
    +     nSortData = nColumn;
    +   }else{
    +     regRowid = sqlite3GetTempReg(pParse);
    +-    regRow = sqlite3GetTempReg(pParse);
    +-    nSortData = 1;
    ++    regRow = sqlite3GetTempRange(pParse, nColumn);
    ++    nSortData = nColumn;
    +   }
    +   nKey = pOrderBy->nExpr - pSort->nOBSat;
    +   if( pSort->sortFlags & SORTFLAG_UseSorter ){
    +     int regSortOut = ++pParse->nMem;
    +     iSortTab = pParse->nTab++;
    +     if( pSort->labelBkOut ){
    +-      addrOnce = sqlite3CodeOnce(pParse); VdbeCoverage(v);
    ++      addrOnce = sqlite3VdbeAddOp0(v, OP_Once); VdbeCoverage(v);
    +     }
    +     sqlite3VdbeAddOp3(v, OP_OpenPseudo, iSortTab, regSortOut, nKey+1+nSortData);
    +     if( addrOnce ) sqlite3VdbeJumpHere(v, addrOnce);
    +@@ -109891,11 +119952,18 @@ static void generateSortTail(
    +     iSortTab = iTab;
    +     bSeq = 1;
    +   }
    +-  for(i=0; i<nSortData; i++){
    +-    sqlite3VdbeAddOp3(v, OP_Column, iSortTab, nKey+bSeq+i, regRow+i);
    ++  for(i=0, iCol=nKey+bSeq; i<nSortData; i++){
    ++    int iRead;
    ++    if( aOutEx[i].u.x.iOrderByCol ){
    ++      iRead = aOutEx[i].u.x.iOrderByCol-1;
    ++    }else{
    ++      iRead = iCol++;
    ++    }
    ++    sqlite3VdbeAddOp3(v, OP_Column, iSortTab, iRead, regRow+i);
    +     VdbeComment((v, "%s", aOutEx[i].zName ? aOutEx[i].zName : aOutEx[i].zSpan));
    +   }
    +   switch( eDest ){
    ++    case SRT_Table:
    +     case SRT_EphemTab: {
    +       sqlite3VdbeAddOp2(v, OP_NewRowid, iParm, regRowid);
    +       sqlite3VdbeAddOp3(v, OP_Insert, iParm, regRow, regRowid);
    +@@ -109904,16 +119972,14 @@ static void generateSortTail(
    +     }
    + #ifndef SQLITE_OMIT_SUBQUERY
    +     case SRT_Set: {
    +-      assert( nColumn==1 );
    +-      sqlite3VdbeAddOp4(v, OP_MakeRecord, regRow, 1, regRowid,
    +-                        &pDest->affSdst, 1);
    +-      sqlite3ExprCacheAffinityChange(pParse, regRow, 1);
    +-      sqlite3VdbeAddOp2(v, OP_IdxInsert, iParm, regRowid);
    ++      assert( nColumn==sqlite3Strlen30(pDest->zAffSdst) );
    ++      sqlite3VdbeAddOp4(v, OP_MakeRecord, regRow, nColumn, regRowid,
    ++                        pDest->zAffSdst, nColumn);
    ++      sqlite3ExprCacheAffinityChange(pParse, regRow, nColumn);
    ++      sqlite3VdbeAddOp4Int(v, OP_IdxInsert, iParm, regRowid, regRow, nColumn);
    +       break;
    +     }
    +     case SRT_Mem: {
    +-      assert( nColumn==1 );
    +-      sqlite3ExprCodeMove(pParse, regRow, iParm, 1);
    +       /* The LIMIT clause will terminate the loop for us */
    +       break;
    +     }
    +@@ -109932,7 +119998,11 @@ static void generateSortTail(
    +     }
    +   }
    +   if( regRowid ){
    +-    sqlite3ReleaseTempReg(pParse, regRow);
    ++    if( eDest==SRT_Set ){
    ++      sqlite3ReleaseTempRange(pParse, regRow, nColumn);
    ++    }else{
    ++      sqlite3ReleaseTempReg(pParse, regRow);
    ++    }
    +     sqlite3ReleaseTempReg(pParse, regRowid);
    +   }
    +   /* The bottom of the loop
    +@@ -109972,32 +120042,34 @@ static void generateSortTail(
    + ** the SQLITE_ENABLE_COLUMN_METADATA compile-time option is used.
    + */
    + #ifdef SQLITE_ENABLE_COLUMN_METADATA
    +-# define columnType(A,B,C,D,E,F) columnTypeImpl(A,B,C,D,E,F)
    ++# define columnType(A,B,C,D,E) columnTypeImpl(A,B,C,D,E)
    + #else /* if !defined(SQLITE_ENABLE_COLUMN_METADATA) */
    +-# define columnType(A,B,C,D,E,F) columnTypeImpl(A,B,F)
    ++# define columnType(A,B,C,D,E) columnTypeImpl(A,B)
    + #endif
    + static const char *columnTypeImpl(
    +   NameContext *pNC, 
    ++#ifndef SQLITE_ENABLE_COLUMN_METADATA
    ++  Expr *pExpr
    ++#else
    +   Expr *pExpr,
    +-#ifdef SQLITE_ENABLE_COLUMN_METADATA
    +   const char **pzOrigDb,
    +   const char **pzOrigTab,
    +-  const char **pzOrigCol,
    ++  const char **pzOrigCol
    + #endif
    +-  u8 *pEstWidth
    + ){
    +   char const *zType = 0;
    +   int j;
    +-  u8 estWidth = 1;
    + #ifdef SQLITE_ENABLE_COLUMN_METADATA
    +   char const *zOrigDb = 0;
    +   char const *zOrigTab = 0;
    +   char const *zOrigCol = 0;
    + #endif
    + 
    +-  if( NEVER(pExpr==0) || pNC->pSrcList==0 ) return 0;
    ++  assert( pExpr!=0 );
    ++  assert( pNC->pSrcList!=0 );
    ++  assert( pExpr->op!=TK_AGG_COLUMN );  /* This routine runes before aggregates
    ++                                       ** are processed */
    +   switch( pExpr->op ){
    +-    case TK_AGG_COLUMN:
    +     case TK_COLUMN: {
    +       /* The expression is a column. Locate the table the column is being
    +       ** extracted from in NameContext.pSrcList. This table may be real
    +@@ -110006,8 +120078,6 @@ static const char *columnTypeImpl(
    +       Table *pTab = 0;            /* Table structure column is extracted from */
    +       Select *pS = 0;             /* Select the column is extracted from */
    +       int iCol = pExpr->iColumn;  /* Index of column in pTab */
    +-      testcase( pExpr->op==TK_AGG_COLUMN );
    +-      testcase( pExpr->op==TK_COLUMN );
    +       while( pNC && !pTab ){
    +         SrcList *pTabList = pNC->pSrcList;
    +         for(j=0;j<pTabList->nSrc && pTabList->a[j].iCursor!=pExpr->iTable;j++);
    +@@ -110046,46 +120116,42 @@ static const char *columnTypeImpl(
    +         ** of the SELECT statement. Return the declaration type and origin
    +         ** data for the result-set column of the sub-select.
    +         */
    +-        if( iCol>=0 && ALWAYS(iCol<pS->pEList->nExpr) ){
    ++        if( iCol>=0 && iCol<pS->pEList->nExpr ){
    +           /* If iCol is less than zero, then the expression requests the
    +           ** rowid of the sub-select or view. This expression is legal (see 
    +           ** test case misc2.2.2) - it always evaluates to NULL.
    +-          **
    +-          ** The ALWAYS() is because iCol>=pS->pEList->nExpr will have been
    +-          ** caught already by name resolution.
    +           */
    +           NameContext sNC;
    +           Expr *p = pS->pEList->a[iCol].pExpr;
    +           sNC.pSrcList = pS->pSrc;
    +           sNC.pNext = pNC;
    +           sNC.pParse = pNC->pParse;
    +-          zType = columnType(&sNC, p,&zOrigDb,&zOrigTab,&zOrigCol, &estWidth); 
    ++          zType = columnType(&sNC, p,&zOrigDb,&zOrigTab,&zOrigCol); 
    +         }
    +-      }else if( pTab->pSchema ){
    +-        /* A real table */
    ++      }else{
    ++        /* A real table or a CTE table */
    +         assert( !pS );
    +-        if( iCol<0 ) iCol = pTab->iPKey;
    +-        assert( iCol==-1 || (iCol>=0 && iCol<pTab->nCol) );
    + #ifdef SQLITE_ENABLE_COLUMN_METADATA
    ++        if( iCol<0 ) iCol = pTab->iPKey;
    ++        assert( iCol==XN_ROWID || (iCol>=0 && iCol<pTab->nCol) );
    +         if( iCol<0 ){
    +           zType = "INTEGER";
    +           zOrigCol = "rowid";
    +         }else{
    +-          zType = pTab->aCol[iCol].zType;
    +           zOrigCol = pTab->aCol[iCol].zName;
    +-          estWidth = pTab->aCol[iCol].szEst;
    ++          zType = sqlite3ColumnType(&pTab->aCol[iCol],0);
    +         }
    +         zOrigTab = pTab->zName;
    +-        if( pNC->pParse ){
    ++        if( pNC->pParse && pTab->pSchema ){
    +           int iDb = sqlite3SchemaToIndex(pNC->pParse->db, pTab->pSchema);
    +-          zOrigDb = pNC->pParse->db->aDb[iDb].zName;
    ++          zOrigDb = pNC->pParse->db->aDb[iDb].zDbSName;
    +         }
    + #else
    ++        assert( iCol==XN_ROWID || (iCol>=0 && iCol<pTab->nCol) );
    +         if( iCol<0 ){
    +           zType = "INTEGER";
    +         }else{
    +-          zType = pTab->aCol[iCol].zType;
    +-          estWidth = pTab->aCol[iCol].szEst;
    ++          zType = sqlite3ColumnType(&pTab->aCol[iCol],0);
    +         }
    + #endif
    +       }
    +@@ -110104,7 +120170,7 @@ static const char *columnTypeImpl(
    +       sNC.pSrcList = pS->pSrc;
    +       sNC.pNext = pNC;
    +       sNC.pParse = pNC->pParse;
    +-      zType = columnType(&sNC, p, &zOrigDb, &zOrigTab, &zOrigCol, &estWidth); 
    ++      zType = columnType(&sNC, p, &zOrigDb, &zOrigTab, &zOrigCol); 
    +       break;
    +     }
    + #endif
    +@@ -110118,7 +120184,6 @@ static const char *columnTypeImpl(
    +     *pzOrigCol = zOrigCol;
    +   }
    + #endif
    +-  if( pEstWidth ) *pEstWidth = estWidth;
    +   return zType;
    + }
    + 
    +@@ -110137,6 +120202,7 @@ static void generateColumnTypes(
    +   NameContext sNC;
    +   sNC.pSrcList = pTabList;
    +   sNC.pParse = pParse;
    ++  sNC.pNext = 0;
    +   for(i=0; i<pEList->nExpr; i++){
    +     Expr *p = pEList->a[i].pExpr;
    +     const char *zType;
    +@@ -110144,7 +120210,7 @@ static void generateColumnTypes(
    +     const char *zOrigDb = 0;
    +     const char *zOrigTab = 0;
    +     const char *zOrigCol = 0;
    +-    zType = columnType(&sNC, p, &zOrigDb, &zOrigTab, &zOrigCol, 0);
    ++    zType = columnType(&sNC, p, &zOrigDb, &zOrigTab, &zOrigCol);
    + 
    +     /* The vdbe must make its own copy of the column-type and other 
    +     ** column specific strings, in case the schema is reset before this
    +@@ -110154,27 +120220,56 @@ static void generateColumnTypes(
    +     sqlite3VdbeSetColName(v, i, COLNAME_TABLE, zOrigTab, SQLITE_TRANSIENT);
    +     sqlite3VdbeSetColName(v, i, COLNAME_COLUMN, zOrigCol, SQLITE_TRANSIENT);
    + #else
    +-    zType = columnType(&sNC, p, 0, 0, 0, 0);
    ++    zType = columnType(&sNC, p, 0, 0, 0);
    + #endif
    +     sqlite3VdbeSetColName(v, i, COLNAME_DECLTYPE, zType, SQLITE_TRANSIENT);
    +   }
    + #endif /* !defined(SQLITE_OMIT_DECLTYPE) */
    + }
    + 
    ++
    + /*
    +-** Generate code that will tell the VDBE the names of columns
    +-** in the result set.  This information is used to provide the
    +-** azCol[] values in the callback.
    ++** Compute the column names for a SELECT statement.
    ++**
    ++** The only guarantee that SQLite makes about column names is that if the
    ++** column has an AS clause assigning it a name, that will be the name used.
    ++** That is the only documented guarantee.  However, countless applications
    ++** developed over the years have made baseless assumptions about column names
    ++** and will break if those assumptions changes.  Hence, use extreme caution
    ++** when modifying this routine to avoid breaking legacy.
    ++**
    ++** See Also: sqlite3ColumnsFromExprList()
    ++**
    ++** The PRAGMA short_column_names and PRAGMA full_column_names settings are
    ++** deprecated.  The default setting is short=ON, full=OFF.  99.9% of all
    ++** applications should operate this way.  Nevertheless, we need to support the
    ++** other modes for legacy:
    ++**
    ++**    short=OFF, full=OFF:      Column name is the text of the expression has it
    ++**                              originally appears in the SELECT statement.  In
    ++**                              other words, the zSpan of the result expression.
    ++**
    ++**    short=ON, full=OFF:       (This is the default setting).  If the result
    ++**                              refers directly to a table column, then the
    ++**                              result column name is just the table column
    ++**                              name: COLUMN.  Otherwise use zSpan.
    ++**
    ++**    full=ON, short=ANY:       If the result refers directly to a table column,
    ++**                              then the result column name with the table name
    ++**                              prefix, ex: TABLE.COLUMN.  Otherwise use zSpan.
    + */
    + static void generateColumnNames(
    +   Parse *pParse,      /* Parser context */
    +-  SrcList *pTabList,  /* List of tables */
    +-  ExprList *pEList    /* Expressions defining the result set */
    ++  Select *pSelect     /* Generate column names for this SELECT statement */
    + ){
    +   Vdbe *v = pParse->pVdbe;
    +-  int i, j;
    ++  int i;
    ++  Table *pTab;
    ++  SrcList *pTabList;
    ++  ExprList *pEList;
    +   sqlite3 *db = pParse->db;
    +-  int fullNames, shortNames;
    ++  int fullName;    /* TABLE.COLUMN if no AS clause and is a direct table ref */
    ++  int srcName;     /* COLUMN or TABLE.COLUMN if no AS clause and is direct */
    + 
    + #ifndef SQLITE_OMIT_EXPLAIN
    +   /* If this is an EXPLAIN, skip this step */
    +@@ -110183,27 +120278,33 @@ static void generateColumnNames(
    +   }
    + #endif
    + 
    +-  if( pParse->colNamesSet || NEVER(v==0) || db->mallocFailed ) return;
    ++  if( pParse->colNamesSet || db->mallocFailed ) return;
    ++  /* Column names are determined by the left-most term of a compound select */
    ++  while( pSelect->pPrior ) pSelect = pSelect->pPrior;
    ++  SELECTTRACE(1,pParse,pSelect,("generating column names\n"));
    ++  pTabList = pSelect->pSrc;
    ++  pEList = pSelect->pEList;
    ++  assert( v!=0 );
    ++  assert( pTabList!=0 );
    +   pParse->colNamesSet = 1;
    +-  fullNames = (db->flags & SQLITE_FullColNames)!=0;
    +-  shortNames = (db->flags & SQLITE_ShortColNames)!=0;
    ++  fullName = (db->flags & SQLITE_FullColNames)!=0;
    ++  srcName = (db->flags & SQLITE_ShortColNames)!=0 || fullName;
    +   sqlite3VdbeSetNumCols(v, pEList->nExpr);
    +   for(i=0; i<pEList->nExpr; i++){
    +-    Expr *p;
    +-    p = pEList->a[i].pExpr;
    +-    if( NEVER(p==0) ) continue;
    ++    Expr *p = pEList->a[i].pExpr;
    ++
    ++    assert( p!=0 );
    ++    assert( p->op!=TK_AGG_COLUMN );  /* Agg processing has not run yet */
    ++    assert( p->op!=TK_COLUMN || p->pTab!=0 ); /* Covering idx not yet coded */
    +     if( pEList->a[i].zName ){
    ++      /* An AS clause always takes first priority */
    +       char *zName = pEList->a[i].zName;
    +       sqlite3VdbeSetColName(v, i, COLNAME_NAME, zName, SQLITE_TRANSIENT);
    +-    }else if( (p->op==TK_COLUMN || p->op==TK_AGG_COLUMN) && pTabList ){
    +-      Table *pTab;
    ++    }else if( srcName && p->op==TK_COLUMN ){
    +       char *zCol;
    +       int iCol = p->iColumn;
    +-      for(j=0; ALWAYS(j<pTabList->nSrc); j++){
    +-        if( pTabList->a[j].iCursor==p->iTable ) break;
    +-      }
    +-      assert( j<pTabList->nSrc );
    +-      pTab = pTabList->a[j].pTab;
    ++      pTab = p->pTab;
    ++      assert( pTab!=0 );
    +       if( iCol<0 ) iCol = pTab->iPKey;
    +       assert( iCol==-1 || (iCol>=0 && iCol<pTab->nCol) );
    +       if( iCol<0 ){
    +@@ -110211,10 +120312,7 @@ static void generateColumnNames(
    +       }else{
    +         zCol = pTab->aCol[iCol].zName;
    +       }
    +-      if( !shortNames && !fullNames ){
    +-        sqlite3VdbeSetColName(v, i, COLNAME_NAME, 
    +-            sqlite3DbStrDup(db, pEList->a[i].zSpan), SQLITE_DYNAMIC);
    +-      }else if( fullNames ){
    ++      if( fullName ){
    +         char *zName = 0;
    +         zName = sqlite3MPrintf(db, "%s.%s", pTab->zName, zCol);
    +         sqlite3VdbeSetColName(v, i, COLNAME_NAME, zName, SQLITE_DYNAMIC);
    +@@ -110242,6 +120340,15 @@ static void generateColumnNames(
    + **
    + ** Return SQLITE_OK on success.  If a memory allocation error occurs,
    + ** store NULL in *paCol and 0 in *pnCol and return SQLITE_NOMEM.
    ++**
    ++** The only guarantee that SQLite makes about column names is that if the
    ++** column has an AS clause assigning it a name, that will be the name used.
    ++** That is the only documented guarantee.  However, countless applications
    ++** developed over the years have made baseless assumptions about column names
    ++** and will break if those assumptions changes.  Hence, use extreme caution
    ++** when modifying this routine to avoid breaking legacy.
    ++**
    ++** See Also: generateColumnNames()
    + */
    + SQLITE_PRIVATE int sqlite3ColumnsFromExprList(
    +   Parse *pParse,          /* Parsing context */
    +@@ -110251,78 +120358,80 @@ SQLITE_PRIVATE int sqlite3ColumnsFromExprList(
    + ){
    +   sqlite3 *db = pParse->db;   /* Database connection */
    +   int i, j;                   /* Loop counters */
    +-  int cnt;                    /* Index added to make the name unique */
    ++  u32 cnt;                    /* Index added to make the name unique */
    +   Column *aCol, *pCol;        /* For looping over result columns */
    +   int nCol;                   /* Number of columns in the result set */
    +-  Expr *p;                    /* Expression for a single result column */
    +   char *zName;                /* Column name */
    +   int nName;                  /* Size of name in zName[] */
    ++  Hash ht;                    /* Hash table of column names */
    + 
    ++  sqlite3HashInit(&ht);
    +   if( pEList ){
    +     nCol = pEList->nExpr;
    +     aCol = sqlite3DbMallocZero(db, sizeof(aCol[0])*nCol);
    +     testcase( aCol==0 );
    ++    if( nCol>32767 ) nCol = 32767;
    +   }else{
    +     nCol = 0;
    +     aCol = 0;
    +   }
    ++  assert( nCol==(i16)nCol );
    +   *pnCol = nCol;
    +   *paCol = aCol;
    + 
    +-  for(i=0, pCol=aCol; i<nCol; i++, pCol++){
    ++  for(i=0, pCol=aCol; i<nCol && !db->mallocFailed; i++, pCol++){
    +     /* Get an appropriate name for the column
    +     */
    +-    p = sqlite3ExprSkipCollate(pEList->a[i].pExpr);
    +     if( (zName = pEList->a[i].zName)!=0 ){
    +       /* If the column contains an "AS <name>" phrase, use <name> as the name */
    +-      zName = sqlite3DbStrDup(db, zName);
    +     }else{
    +-      Expr *pColExpr = p;  /* The expression that is the result column name */
    +-      Table *pTab;         /* Table associated with this expression */
    ++      Expr *pColExpr = sqlite3ExprSkipCollate(pEList->a[i].pExpr);
    +       while( pColExpr->op==TK_DOT ){
    +         pColExpr = pColExpr->pRight;
    +         assert( pColExpr!=0 );
    +       }
    +-      if( pColExpr->op==TK_COLUMN && ALWAYS(pColExpr->pTab!=0) ){
    ++      assert( pColExpr->op!=TK_AGG_COLUMN );
    ++      if( pColExpr->op==TK_COLUMN ){
    +         /* For columns use the column name name */
    +         int iCol = pColExpr->iColumn;
    +-        pTab = pColExpr->pTab;
    ++        Table *pTab = pColExpr->pTab;
    ++        assert( pTab!=0 );
    +         if( iCol<0 ) iCol = pTab->iPKey;
    +-        zName = sqlite3MPrintf(db, "%s",
    +-                 iCol>=0 ? pTab->aCol[iCol].zName : "rowid");
    ++        zName = iCol>=0 ? pTab->aCol[iCol].zName : "rowid";
    +       }else if( pColExpr->op==TK_ID ){
    +         assert( !ExprHasProperty(pColExpr, EP_IntValue) );
    +-        zName = sqlite3MPrintf(db, "%s", pColExpr->u.zToken);
    ++        zName = pColExpr->u.zToken;
    +       }else{
    +         /* Use the original text of the column expression as its name */
    +-        zName = sqlite3MPrintf(db, "%s", pEList->a[i].zSpan);
    ++        zName = pEList->a[i].zSpan;
    +       }
    +     }
    +-    if( db->mallocFailed ){
    +-      sqlite3DbFree(db, zName);
    +-      break;
    ++    if( zName ){
    ++      zName = sqlite3DbStrDup(db, zName);
    ++    }else{
    ++      zName = sqlite3MPrintf(db,"column%d",i+1);
    +     }
    + 
    +     /* Make sure the column name is unique.  If the name is not unique,
    +     ** append an integer to the name so that it becomes unique.
    +     */
    +-    nName = sqlite3Strlen30(zName);
    +-    for(j=cnt=0; j<i; j++){
    +-      if( sqlite3StrICmp(aCol[j].zName, zName)==0 ){
    +-        char *zNewName;
    +-        int k;
    +-        for(k=nName-1; k>1 && sqlite3Isdigit(zName[k]); k--){}
    +-        if( k>=0 && zName[k]==':' ) nName = k;
    +-        zName[nName] = 0;
    +-        zNewName = sqlite3MPrintf(db, "%s:%d", zName, ++cnt);
    +-        sqlite3DbFree(db, zName);
    +-        zName = zNewName;
    +-        j = -1;
    +-        if( zName==0 ) break;
    ++    cnt = 0;
    ++    while( zName && sqlite3HashFind(&ht, zName)!=0 ){
    ++      nName = sqlite3Strlen30(zName);
    ++      if( nName>0 ){
    ++        for(j=nName-1; j>0 && sqlite3Isdigit(zName[j]); j--){}
    ++        if( zName[j]==':' ) nName = j;
    +       }
    ++      zName = sqlite3MPrintf(db, "%.*z:%u", nName, zName, ++cnt);
    ++      if( cnt>3 ) sqlite3_randomness(sizeof(cnt), &cnt);
    +     }
    +     pCol->zName = zName;
    ++    sqlite3ColumnPropertiesFromName(0, pCol);
    ++    if( zName && sqlite3HashInsert(&ht, zName, pCol)==pCol ){
    ++      sqlite3OomFault(db);
    ++    }
    +   }
    ++  sqlite3HashClear(&ht);
    +   if( db->mallocFailed ){
    +     for(j=0; j<i; j++){
    +       sqlite3DbFree(db, aCol[j].zName);
    +@@ -110330,7 +120439,7 @@ SQLITE_PRIVATE int sqlite3ColumnsFromExprList(
    +     sqlite3DbFree(db, aCol);
    +     *paCol = 0;
    +     *pnCol = 0;
    +-    return SQLITE_NOMEM;
    ++    return SQLITE_NOMEM_BKPT;
    +   }
    +   return SQLITE_OK;
    + }
    +@@ -110346,7 +120455,7 @@ SQLITE_PRIVATE int sqlite3ColumnsFromExprList(
    + ** This routine requires that all identifiers in the SELECT
    + ** statement be resolved.
    + */
    +-static void selectAddColumnTypeAndCollation(
    ++SQLITE_PRIVATE void sqlite3SelectAddColumnTypeAndCollation(
    +   Parse *pParse,        /* Parsing contexts */
    +   Table *pTab,          /* Add column type information to this table */
    +   Select *pSelect       /* SELECT used to determine types and collations */
    +@@ -110358,7 +120467,6 @@ static void selectAddColumnTypeAndCollation(
    +   int i;
    +   Expr *p;
    +   struct ExprList_item *a;
    +-  u64 szAll = 0;
    + 
    +   assert( pSelect!=0 );
    +   assert( (pSelect->selFlags & SF_Resolved)!=0 );
    +@@ -110368,20 +120476,28 @@ static void selectAddColumnTypeAndCollation(
    +   sNC.pSrcList = pSelect->pSrc;
    +   a = pSelect->pEList->a;
    +   for(i=0, pCol=pTab->aCol; i<pTab->nCol; i++, pCol++){
    ++    const char *zType;
    ++    int n, m;
    +     p = a[i].pExpr;
    +-    if( pCol->zType==0 ){
    +-      pCol->zType = sqlite3DbStrDup(db, 
    +-                        columnType(&sNC, p,0,0,0, &pCol->szEst));
    +-    }
    +-    szAll += pCol->szEst;
    ++    zType = columnType(&sNC, p, 0, 0, 0);
    ++    /* pCol->szEst = ... // Column size est for SELECT tables never used */
    +     pCol->affinity = sqlite3ExprAffinity(p);
    ++    if( zType ){
    ++      m = sqlite3Strlen30(zType);
    ++      n = sqlite3Strlen30(pCol->zName);
    ++      pCol->zName = sqlite3DbReallocOrFree(db, pCol->zName, n+m+2);
    ++      if( pCol->zName ){
    ++        memcpy(&pCol->zName[n+1], zType, m+1);
    ++        pCol->colFlags |= COLFLAG_HASTYPE;
    ++      }
    ++    }
    +     if( pCol->affinity==0 ) pCol->affinity = SQLITE_AFF_BLOB;
    +     pColl = sqlite3ExprCollSeq(pParse, p);
    +     if( pColl && pCol->zColl==0 ){
    +       pCol->zColl = sqlite3DbStrDup(db, pColl->zName);
    +     }
    +   }
    +-  pTab->szTabRow = sqlite3LogEst(szAll*4);
    ++  pTab->szTabRow = 1; /* Any non-zero value works */
    + }
    + 
    + /*
    +@@ -110406,12 +120522,12 @@ SQLITE_PRIVATE Table *sqlite3ResultSetOfSelect(Parse *pParse, Select *pSelect){
    +   }
    +   /* The sqlite3ResultSetOfSelect() is only used n contexts where lookaside
    +   ** is disabled */
    +-  assert( db->lookaside.bEnabled==0 );
    +-  pTab->nRef = 1;
    ++  assert( db->lookaside.bDisable );
    ++  pTab->nTabRef = 1;
    +   pTab->zName = 0;
    +   pTab->nRowLogEst = 200; assert( 200==sqlite3LogEst(1048576) );
    +   sqlite3ColumnsFromExprList(pParse, pSelect->pEList, &pTab->nCol, &pTab->aCol);
    +-  selectAddColumnTypeAndCollation(pParse, pTab, pSelect);
    ++  sqlite3SelectAddColumnTypeAndCollation(pParse, pTab, pSelect);
    +   pTab->iPKey = -1;
    +   if( db->mallocFailed ){
    +     sqlite3DeleteTable(db, pTab);
    +@@ -110425,24 +120541,21 @@ SQLITE_PRIVATE Table *sqlite3ResultSetOfSelect(Parse *pParse, Select *pSelect){
    + ** If an error occurs, return NULL and leave a message in pParse.
    + */
    + SQLITE_PRIVATE Vdbe *sqlite3GetVdbe(Parse *pParse){
    +-  Vdbe *v = pParse->pVdbe;
    +-  if( v==0 ){
    +-    v = pParse->pVdbe = sqlite3VdbeCreate(pParse);
    +-    if( v ) sqlite3VdbeAddOp0(v, OP_Init);
    +-    if( pParse->pToplevel==0
    +-     && OptimizationEnabled(pParse->db,SQLITE_FactorOutConst)
    +-    ){
    +-      pParse->okConstFactor = 1;
    +-    }
    +-
    ++  if( pParse->pVdbe ){
    ++    return pParse->pVdbe;
    +   }
    +-  return v;
    ++  if( pParse->pToplevel==0
    ++   && OptimizationEnabled(pParse->db,SQLITE_FactorOutConst)
    ++  ){
    ++    pParse->okConstFactor = 1;
    ++  }
    ++  return sqlite3VdbeCreate(pParse);
    + }
    + 
    + 
    + /*
    + ** Compute the iLimit and iOffset fields of the SELECT based on the
    +-** pLimit and pOffset expressions.  pLimit and pOffset hold the expressions
    ++** pLimit expressions.  pLimit->pLeft and pLimit->pRight hold the expressions
    + ** that appear in the original SQL statement after the LIMIT and OFFSET
    + ** keywords.  Or NULL if those keywords are omitted. iLimit and iOffset 
    + ** are the integer memory register numbers for counters used to compute 
    +@@ -110450,15 +120563,15 @@ SQLITE_PRIVATE Vdbe *sqlite3GetVdbe(Parse *pParse){
    + ** iLimit and iOffset are negative.
    + **
    + ** This routine changes the values of iLimit and iOffset only if
    +-** a limit or offset is defined by pLimit and pOffset.  iLimit and
    +-** iOffset should have been preset to appropriate default values (zero)
    ++** a limit or offset is defined by pLimit->pLeft and pLimit->pRight.  iLimit
    ++** and iOffset should have been preset to appropriate default values (zero)
    + ** prior to calling this routine.
    + **
    + ** The iOffset register (if it exists) is initialized to the value
    + ** of the OFFSET.  The iLimit register is initialized to LIMIT.  Register
    + ** iOffset+1 is initialized to LIMIT+OFFSET.
    + **
    +-** Only if pLimit!=0 or pOffset!=0 do the limit registers get
    ++** Only if pLimit->pLeft!=0 do the limit registers get
    + ** redefined.  The UNION ALL operator uses this property to force
    + ** the reuse of the same limit and offset registers across multiple
    + ** SELECT statements.
    +@@ -110468,6 +120581,8 @@ static void computeLimitRegisters(Parse *pParse, Select *p, int iBreak){
    +   int iLimit = 0;
    +   int iOffset;
    +   int n;
    ++  Expr *pLimit = p->pLimit;
    ++
    +   if( p->iLimit ) return;
    + 
    +   /* 
    +@@ -110477,35 +120592,35 @@ static void computeLimitRegisters(Parse *pParse, Select *p, int iBreak){
    +   ** no rows.
    +   */
    +   sqlite3ExprCacheClear(pParse);
    +-  assert( p->pOffset==0 || p->pLimit!=0 );
    +-  if( p->pLimit ){
    ++  if( pLimit ){
    ++    assert( pLimit->op==TK_LIMIT );
    ++    assert( pLimit->pLeft!=0 );
    +     p->iLimit = iLimit = ++pParse->nMem;
    +     v = sqlite3GetVdbe(pParse);
    +     assert( v!=0 );
    +-    if( sqlite3ExprIsInteger(p->pLimit, &n) ){
    ++    if( sqlite3ExprIsInteger(pLimit->pLeft, &n) ){
    +       sqlite3VdbeAddOp2(v, OP_Integer, n, iLimit);
    +       VdbeComment((v, "LIMIT counter"));
    +       if( n==0 ){
    +         sqlite3VdbeGoto(v, iBreak);
    +-      }else if( n>=0 && p->nSelectRow>(u64)n ){
    +-        p->nSelectRow = n;
    ++      }else if( n>=0 && p->nSelectRow>sqlite3LogEst((u64)n) ){
    ++        p->nSelectRow = sqlite3LogEst((u64)n);
    ++        p->selFlags |= SF_FixedLimit;
    +       }
    +     }else{
    +-      sqlite3ExprCode(pParse, p->pLimit, iLimit);
    ++      sqlite3ExprCode(pParse, pLimit->pLeft, iLimit);
    +       sqlite3VdbeAddOp1(v, OP_MustBeInt, iLimit); VdbeCoverage(v);
    +       VdbeComment((v, "LIMIT counter"));
    +       sqlite3VdbeAddOp2(v, OP_IfNot, iLimit, iBreak); VdbeCoverage(v);
    +     }
    +-    if( p->pOffset ){
    ++    if( pLimit->pRight ){
    +       p->iOffset = iOffset = ++pParse->nMem;
    +       pParse->nMem++;   /* Allocate an extra register for limit+offset */
    +-      sqlite3ExprCode(pParse, p->pOffset, iOffset);
    ++      sqlite3ExprCode(pParse, pLimit->pRight, iOffset);
    +       sqlite3VdbeAddOp1(v, OP_MustBeInt, iOffset); VdbeCoverage(v);
    +       VdbeComment((v, "OFFSET counter"));
    +-      sqlite3VdbeAddOp3(v, OP_SetIfNotPos, iOffset, iOffset, 0);
    +-      sqlite3VdbeAddOp3(v, OP_Add, iLimit, iOffset, iOffset+1);
    ++      sqlite3VdbeAddOp3(v, OP_OffsetLimit, iLimit, iOffset+1, iOffset);
    +       VdbeComment((v, "LIMIT+OFFSET"));
    +-      sqlite3VdbeAddOp3(v, OP_SetIfNotPos, iLimit, iOffset+1, -1);
    +     }
    +   }
    + }
    +@@ -110631,7 +120746,7 @@ static void generateWithRecursiveQuery(
    +   int i;                        /* Loop counter */
    +   int rc;                       /* Result code */
    +   ExprList *pOrderBy;           /* The ORDER BY clause */
    +-  Expr *pLimit, *pOffset;       /* Saved LIMIT and OFFSET */
    ++  Expr *pLimit;                 /* Saved LIMIT and OFFSET */
    +   int regLimit, regOffset;      /* Registers used by LIMIT and OFFSET */
    + 
    +   /* Obtain authorization to do a recursive query */
    +@@ -110639,12 +120754,12 @@ static void generateWithRecursiveQuery(
    + 
    +   /* Process the LIMIT and OFFSET clauses, if they exist */
    +   addrBreak = sqlite3VdbeMakeLabel(v);
    ++  p->nSelectRow = 320;  /* 4 billion rows */
    +   computeLimitRegisters(pParse, p, addrBreak);
    +   pLimit = p->pLimit;
    +-  pOffset = p->pOffset;
    +   regLimit = p->iLimit;
    +   regOffset = p->iOffset;
    +-  p->pLimit = p->pOffset = 0;
    ++  p->pLimit = 0;
    +   p->iLimit = p->iOffset = 0;
    +   pOrderBy = p->pOrderBy;
    + 
    +@@ -110709,7 +120824,7 @@ static void generateWithRecursiveQuery(
    +   /* Output the single row in Current */
    +   addrCont = sqlite3VdbeMakeLabel(v);
    +   codeOffset(v, regOffset, addrCont);
    +-  selectInnerLoop(pParse, p, p->pEList, iCurrent,
    ++  selectInnerLoop(pParse, p, iCurrent,
    +       0, 0, pDest, addrCont, addrBreak);
    +   if( regLimit ){
    +     sqlite3VdbeAddOp2(v, OP_DecrJumpZero, regLimit, addrBreak);
    +@@ -110737,7 +120852,6 @@ end_of_recursive_query:
    +   sqlite3ExprListDelete(pParse->db, p->pOrderBy);
    +   p->pOrderBy = pOrderBy;
    +   p->pLimit = pLimit;
    +-  p->pOffset = pOffset;
    +   return;
    + }
    + #endif /* SQLITE_OMIT_CTE */
    +@@ -110756,9 +120870,14 @@ static int multiSelectOrderBy(
    + ** on a VALUES clause.
    + **
    + ** Because the Select object originates from a VALUES clause:
    +-**   (1) It has no LIMIT or OFFSET
    ++**   (1) There is no LIMIT or OFFSET or else there is a LIMIT of exactly 1
    + **   (2) All terms are UNION ALL
    + **   (3) There is no ORDER BY clause
    ++**
    ++** The "LIMIT of exactly 1" case of condition (1) comes about when a VALUES
    ++** clause occurs within scalar expression (ex: "SELECT (VALUES(1),(2),(3))").
    ++** The sqlite3CodeSubselect will have added the LIMIT 1 clause in tht case.
    ++** Since the limit is exactly 1, we only need to evalutes the left-most VALUES.
    + */
    + static int multiSelectValues(
    +   Parse *pParse,        /* Parsing context */
    +@@ -110766,14 +120885,13 @@ static int multiSelectValues(
    +   SelectDest *pDest     /* What to do with query results */
    + ){
    +   Select *pPrior;
    ++  Select *pRightmost = p;
    +   int nRow = 1;
    +   int rc = 0;
    +   assert( p->selFlags & SF_MultiValue );
    +   do{
    +     assert( p->selFlags & SF_Values );
    +     assert( p->op==TK_ALL || (p->op==TK_SELECT && p->pPrior==0) );
    +-    assert( p->pLimit==0 );
    +-    assert( p->pOffset==0 );
    +     assert( p->pNext==0 || p->pEList->nExpr==p->pNext->pEList->nExpr );
    +     if( p->pPrior==0 ) break;
    +     assert( p->pPrior->pNext==p );
    +@@ -110785,7 +120903,7 @@ static int multiSelectValues(
    +     p->pPrior = 0;
    +     rc = sqlite3Select(pParse, p, pDest);
    +     p->pPrior = pPrior;
    +-    if( rc ) break;
    ++    if( rc || pRightmost->pLimit ) break;
    +     p->nSelectRow = nRow;
    +     p = p->pNext;
    +   }
    +@@ -110847,15 +120965,9 @@ static int multiSelect(
    +   db = pParse->db;
    +   pPrior = p->pPrior;
    +   dest = *pDest;
    +-  if( pPrior->pOrderBy ){
    +-    sqlite3ErrorMsg(pParse,"ORDER BY clause should come after %s not before",
    +-      selectOpName(p->op));
    +-    rc = 1;
    +-    goto multi_select_end;
    +-  }
    +-  if( pPrior->pLimit ){
    +-    sqlite3ErrorMsg(pParse,"LIMIT clause should come after %s not before",
    +-      selectOpName(p->op));
    ++  if( pPrior->pOrderBy || pPrior->pLimit ){
    ++    sqlite3ErrorMsg(pParse,"%s clause should come after %s not before",
    ++      pPrior->pOrderBy!=0 ? "ORDER BY" : "LIMIT", selectOpName(p->op));
    +     rc = 1;
    +     goto multi_select_end;
    +   }
    +@@ -110868,7 +120980,6 @@ static int multiSelect(
    +   if( dest.eDest==SRT_EphemTab ){
    +     assert( p->pEList );
    +     sqlite3VdbeAddOp2(v, OP_OpenEphemeral, dest.iSDParm, p->pEList->nExpr);
    +-    sqlite3VdbeChangeP5(v, BTREE_UNORDERED);
    +     dest.eDest = SRT_Table;
    +   }
    + 
    +@@ -110907,11 +121018,9 @@ static int multiSelect(
    +       pPrior->iLimit = p->iLimit;
    +       pPrior->iOffset = p->iOffset;
    +       pPrior->pLimit = p->pLimit;
    +-      pPrior->pOffset = p->pOffset;
    +       explainSetInteger(iSub1, pParse->iNextSelectId);
    +       rc = sqlite3Select(pParse, pPrior, &dest);
    +       p->pLimit = 0;
    +-      p->pOffset = 0;
    +       if( rc ){
    +         goto multi_select_end;
    +       }
    +@@ -110922,9 +121031,8 @@ static int multiSelect(
    +         addr = sqlite3VdbeAddOp1(v, OP_IfNot, p->iLimit); VdbeCoverage(v);
    +         VdbeComment((v, "Jump ahead if LIMIT reached"));
    +         if( p->iOffset ){
    +-          sqlite3VdbeAddOp3(v, OP_SetIfNotPos, p->iOffset, p->iOffset, 0);
    +-          sqlite3VdbeAddOp3(v, OP_Add, p->iLimit, p->iOffset, p->iOffset+1);
    +-          sqlite3VdbeAddOp3(v, OP_SetIfNotPos, p->iLimit, p->iOffset+1, -1);
    ++          sqlite3VdbeAddOp3(v, OP_OffsetLimit,
    ++                            p->iLimit, p->iOffset+1, p->iOffset);
    +         }
    +       }
    +       explainSetInteger(iSub2, pParse->iNextSelectId);
    +@@ -110932,12 +121040,12 @@ static int multiSelect(
    +       testcase( rc!=SQLITE_OK );
    +       pDelete = p->pPrior;
    +       p->pPrior = pPrior;
    +-      p->nSelectRow += pPrior->nSelectRow;
    ++      p->nSelectRow = sqlite3LogEstAdd(p->nSelectRow, pPrior->nSelectRow);
    +       if( pPrior->pLimit
    +-       && sqlite3ExprIsInteger(pPrior->pLimit, &nLimit)
    +-       && nLimit>0 && p->nSelectRow > (u64)nLimit 
    ++       && sqlite3ExprIsInteger(pPrior->pLimit->pLeft, &nLimit)
    ++       && nLimit>0 && p->nSelectRow > sqlite3LogEst((u64)nLimit) 
    +       ){
    +-        p->nSelectRow = nLimit;
    ++        p->nSelectRow = sqlite3LogEst((u64)nLimit);
    +       }
    +       if( addr ){
    +         sqlite3VdbeJumpHere(v, addr);
    +@@ -110949,7 +121057,7 @@ static int multiSelect(
    +       int unionTab;    /* Cursor number of the temporary table holding result */
    +       u8 op = 0;       /* One of the SRT_ operations to apply to self */
    +       int priorOp;     /* The SRT_ operation to apply to prior selects */
    +-      Expr *pLimit, *pOffset; /* Saved values of p->nLimit and p->nOffset */
    ++      Expr *pLimit;    /* Saved values of p->nLimit  */
    +       int addr;
    +       SelectDest uniondest;
    + 
    +@@ -110961,7 +121069,6 @@ static int multiSelect(
    +         ** right.
    +         */
    +         assert( p->pLimit==0 );      /* Not allowed on leftward elements */
    +-        assert( p->pOffset==0 );     /* Not allowed on leftward elements */
    +         unionTab = dest.iSDParm;
    +       }else{
    +         /* We will need to create our own temporary table to hold the
    +@@ -110997,8 +121104,6 @@ static int multiSelect(
    +       p->pPrior = 0;
    +       pLimit = p->pLimit;
    +       p->pLimit = 0;
    +-      pOffset = p->pOffset;
    +-      p->pOffset = 0;
    +       uniondest.eDest = op;
    +       explainSetInteger(iSub2, pParse->iNextSelectId);
    +       rc = sqlite3Select(pParse, p, &uniondest);
    +@@ -111009,10 +121114,11 @@ static int multiSelect(
    +       pDelete = p->pPrior;
    +       p->pPrior = pPrior;
    +       p->pOrderBy = 0;
    +-      if( p->op==TK_UNION ) p->nSelectRow += pPrior->nSelectRow;
    ++      if( p->op==TK_UNION ){
    ++        p->nSelectRow = sqlite3LogEstAdd(p->nSelectRow, pPrior->nSelectRow);
    ++      }
    +       sqlite3ExprDelete(db, p->pLimit);
    +       p->pLimit = pLimit;
    +-      p->pOffset = pOffset;
    +       p->iLimit = 0;
    +       p->iOffset = 0;
    + 
    +@@ -111023,17 +121129,12 @@ static int multiSelect(
    +       if( dest.eDest!=priorOp ){
    +         int iCont, iBreak, iStart;
    +         assert( p->pEList );
    +-        if( dest.eDest==SRT_Output ){
    +-          Select *pFirst = p;
    +-          while( pFirst->pPrior ) pFirst = pFirst->pPrior;
    +-          generateColumnNames(pParse, 0, pFirst->pEList);
    +-        }
    +         iBreak = sqlite3VdbeMakeLabel(v);
    +         iCont = sqlite3VdbeMakeLabel(v);
    +         computeLimitRegisters(pParse, p, iBreak);
    +         sqlite3VdbeAddOp2(v, OP_Rewind, unionTab, iBreak); VdbeCoverage(v);
    +         iStart = sqlite3VdbeCurrentAddr(v);
    +-        selectInnerLoop(pParse, p, p->pEList, unionTab,
    ++        selectInnerLoop(pParse, p, unionTab,
    +                         0, 0, &dest, iCont, iBreak);
    +         sqlite3VdbeResolveLabel(v, iCont);
    +         sqlite3VdbeAddOp2(v, OP_Next, unionTab, iStart); VdbeCoverage(v);
    +@@ -111045,7 +121146,7 @@ static int multiSelect(
    +     default: assert( p->op==TK_INTERSECT ); {
    +       int tab1, tab2;
    +       int iCont, iBreak, iStart;
    +-      Expr *pLimit, *pOffset;
    ++      Expr *pLimit;
    +       int addr;
    +       SelectDest intersectdest;
    +       int r1;
    +@@ -111081,8 +121182,6 @@ static int multiSelect(
    +       p->pPrior = 0;
    +       pLimit = p->pLimit;
    +       p->pLimit = 0;
    +-      pOffset = p->pOffset;
    +-      p->pOffset = 0;
    +       intersectdest.iSDParm = tab2;
    +       explainSetInteger(iSub2, pParse->iNextSelectId);
    +       rc = sqlite3Select(pParse, p, &intersectdest);
    +@@ -111092,26 +121191,20 @@ static int multiSelect(
    +       if( p->nSelectRow>pPrior->nSelectRow ) p->nSelectRow = pPrior->nSelectRow;
    +       sqlite3ExprDelete(db, p->pLimit);
    +       p->pLimit = pLimit;
    +-      p->pOffset = pOffset;
    + 
    +       /* Generate code to take the intersection of the two temporary
    +       ** tables.
    +       */
    +       assert( p->pEList );
    +-      if( dest.eDest==SRT_Output ){
    +-        Select *pFirst = p;
    +-        while( pFirst->pPrior ) pFirst = pFirst->pPrior;
    +-        generateColumnNames(pParse, 0, pFirst->pEList);
    +-      }
    +       iBreak = sqlite3VdbeMakeLabel(v);
    +       iCont = sqlite3VdbeMakeLabel(v);
    +       computeLimitRegisters(pParse, p, iBreak);
    +       sqlite3VdbeAddOp2(v, OP_Rewind, tab1, iBreak); VdbeCoverage(v);
    +       r1 = sqlite3GetTempReg(pParse);
    +-      iStart = sqlite3VdbeAddOp2(v, OP_RowKey, tab1, r1);
    ++      iStart = sqlite3VdbeAddOp2(v, OP_RowData, tab1, r1);
    +       sqlite3VdbeAddOp4Int(v, OP_NotFound, tab2, iCont, r1, 0); VdbeCoverage(v);
    +       sqlite3ReleaseTempReg(pParse, r1);
    +-      selectInnerLoop(pParse, p, p->pEList, tab1,
    ++      selectInnerLoop(pParse, p, tab1,
    +                       0, 0, &dest, iCont, iBreak);
    +       sqlite3VdbeResolveLabel(v, iCont);
    +       sqlite3VdbeAddOp2(v, OP_Next, tab1, iStart); VdbeCoverage(v);
    +@@ -111144,7 +121237,7 @@ static int multiSelect(
    +     nCol = p->pEList->nExpr;
    +     pKeyInfo = sqlite3KeyInfoAlloc(db, nCol, 1);
    +     if( !pKeyInfo ){
    +-      rc = SQLITE_NOMEM;
    ++      rc = SQLITE_NOMEM_BKPT;
    +       goto multi_select_end;
    +     }
    +     for(i=0, apColl=pKeyInfo->aColl; i<nCol; i++, apColl++){
    +@@ -111266,19 +121359,17 @@ static int generateOutputSubroutine(
    +     }
    + 
    + #ifndef SQLITE_OMIT_SUBQUERY
    +-    /* If we are creating a set for an "expr IN (SELECT ...)" construct,
    +-    ** then there should be a single item on the stack.  Write this
    +-    ** item into the set table with bogus data.
    ++    /* If we are creating a set for an "expr IN (SELECT ...)".
    +     */
    +     case SRT_Set: {
    +       int r1;
    +-      assert( pIn->nSdst==1 || pParse->nErr>0 );
    +-      pDest->affSdst = 
    +-         sqlite3CompareAffinity(p->pEList->a[0].pExpr, pDest->affSdst);
    ++      testcase( pIn->nSdst>1 );
    +       r1 = sqlite3GetTempReg(pParse);
    +-      sqlite3VdbeAddOp4(v, OP_MakeRecord, pIn->iSdst, 1, r1, &pDest->affSdst,1);
    +-      sqlite3ExprCacheAffinityChange(pParse, pIn->iSdst, 1);
    +-      sqlite3VdbeAddOp2(v, OP_IdxInsert, pDest->iSDParm, r1);
    ++      sqlite3VdbeAddOp4(v, OP_MakeRecord, pIn->iSdst, pIn->nSdst, 
    ++          r1, pDest->zAffSdst, pIn->nSdst);
    ++      sqlite3ExprCacheAffinityChange(pParse, pIn->iSdst, pIn->nSdst);
    ++      sqlite3VdbeAddOp4Int(v, OP_IdxInsert, pDest->iSDParm, r1,
    ++                           pIn->iSdst, pIn->nSdst);
    +       sqlite3ReleaseTempReg(pParse, r1);
    +       break;
    +     }
    +@@ -111499,10 +121590,10 @@ static int multiSelectOrderBy(
    +       }
    +       if( j==nOrderBy ){
    +         Expr *pNew = sqlite3Expr(db, TK_INTEGER, 0);
    +-        if( pNew==0 ) return SQLITE_NOMEM;
    ++        if( pNew==0 ) return SQLITE_NOMEM_BKPT;
    +         pNew->flags |= EP_IntValue;
    +         pNew->u.iValue = i;
    +-        pOrderBy = sqlite3ExprListAppend(pParse, pOrderBy, pNew);
    ++        p->pOrderBy = pOrderBy = sqlite3ExprListAppend(pParse, pOrderBy, pNew);
    +         if( pOrderBy ) pOrderBy->a[nOrderBy++].u.x.iOrderByCol = (u16)i;
    +       }
    +     }
    +@@ -111515,10 +121606,11 @@ static int multiSelectOrderBy(
    +   ** to the right and the left are evaluated, they use the correct
    +   ** collation.
    +   */
    +-  aPermute = sqlite3DbMallocRaw(db, sizeof(int)*nOrderBy);
    ++  aPermute = sqlite3DbMallocRawNN(db, sizeof(int)*(nOrderBy + 1));
    +   if( aPermute ){
    +     struct ExprList_item *pItem;
    +-    for(i=0, pItem=pOrderBy->a; i<nOrderBy; i++, pItem++){
    ++    aPermute[0] = nOrderBy;
    ++    for(i=1, pItem=pOrderBy->a; i<=nOrderBy; i++, pItem++){
    +       assert( pItem->u.x.iOrderByCol>0 );
    +       assert( pItem->u.x.iOrderByCol<=p->pEList->nExpr );
    +       aPermute[i] = pItem->u.x.iOrderByCol - 1;
    +@@ -111577,8 +121669,6 @@ static int multiSelectOrderBy(
    +   }
    +   sqlite3ExprDelete(db, p->pLimit);
    +   p->pLimit = 0;
    +-  sqlite3ExprDelete(db, p->pOffset);
    +-  p->pOffset = 0;
    + 
    +   regAddrA = ++pParse->nMem;
    +   regAddrB = ++pParse->nMem;
    +@@ -111596,7 +121686,7 @@ static int multiSelectOrderBy(
    +   pPrior->iLimit = regLimitA;
    +   explainSetInteger(iSub1, pParse->iNextSelectId);
    +   sqlite3Select(pParse, pPrior, &destA);
    +-  sqlite3VdbeAddOp1(v, OP_EndCoroutine, regAddrA);
    ++  sqlite3VdbeEndCoroutine(v, regAddrA);
    +   sqlite3VdbeJumpHere(v, addr1);
    + 
    +   /* Generate a coroutine to evaluate the SELECT statement on 
    +@@ -111613,7 +121703,7 @@ static int multiSelectOrderBy(
    +   sqlite3Select(pParse, p, &destB);
    +   p->iLimit = savedLimit;
    +   p->iOffset = savedOffset;
    +-  sqlite3VdbeAddOp1(v, OP_EndCoroutine, regAddrB);
    ++  sqlite3VdbeEndCoroutine(v, regAddrB);
    + 
    +   /* Generate a subroutine that outputs the current row of the A
    +   ** select as the next output row of the compound select.
    +@@ -111645,7 +121735,7 @@ static int multiSelectOrderBy(
    +     addrEofA_noB = sqlite3VdbeAddOp2(v, OP_Yield, regAddrB, labelEnd);
    +                                      VdbeCoverage(v);
    +     sqlite3VdbeGoto(v, addrEofA);
    +-    p->nSelectRow += pPrior->nSelectRow;
    ++    p->nSelectRow = sqlite3LogEstAdd(p->nSelectRow, pPrior->nSelectRow);
    +   }
    + 
    +   /* Generate a subroutine to run when the results from select B
    +@@ -111711,14 +121801,6 @@ static int multiSelectOrderBy(
    +   */
    +   sqlite3VdbeResolveLabel(v, labelEnd);
    + 
    +-  /* Set the number of output columns
    +-  */
    +-  if( pDest->eDest==SRT_Output ){
    +-    Select *pFirst = pPrior;
    +-    while( pFirst->pPrior ) pFirst = pFirst->pPrior;
    +-    generateColumnNames(pParse, 0, pFirst->pEList);
    +-  }
    +-
    +   /* Reassembly the compound query so that it will be freed correctly
    +   ** by the calling function */
    +   if( p->pPrior ){
    +@@ -111735,9 +121817,24 @@ static int multiSelectOrderBy(
    + #endif
    + 
    + #if !defined(SQLITE_OMIT_SUBQUERY) || !defined(SQLITE_OMIT_VIEW)
    ++
    ++/* An instance of the SubstContext object describes an substitution edit
    ++** to be performed on a parse tree.
    ++**
    ++** All references to columns in table iTable are to be replaced by corresponding
    ++** expressions in pEList.
    ++*/
    ++typedef struct SubstContext {
    ++  Parse *pParse;            /* The parsing context */
    ++  int iTable;               /* Replace references to this table */
    ++  int iNewTable;            /* New table number */
    ++  int isLeftJoin;           /* Add TK_IF_NULL_ROW opcodes on each replacement */
    ++  ExprList *pEList;         /* Replacement expressions */
    ++} SubstContext;
    ++
    + /* Forward Declarations */
    +-static void substExprList(sqlite3*, ExprList*, int, ExprList*);
    +-static void substSelect(sqlite3*, Select *, int, ExprList*, int);
    ++static void substExprList(SubstContext*, ExprList*);
    ++static void substSelect(SubstContext*, Select*, int);
    + 
    + /*
    + ** Scan through the expression pExpr.  Replace every reference to
    +@@ -111748,74 +121845,97 @@ static void substSelect(sqlite3*, Select *, int, ExprList*, int);
    + ** This routine is part of the flattening procedure.  A subquery
    + ** whose result set is defined by pEList appears as entry in the
    + ** FROM clause of a SELECT such that the VDBE cursor assigned to that
    +-** FORM clause entry is iTable.  This routine make the necessary 
    ++** FORM clause entry is iTable.  This routine makes the necessary 
    + ** changes to pExpr so that it refers directly to the source table
    + ** of the subquery rather the result set of the subquery.
    + */
    + static Expr *substExpr(
    +-  sqlite3 *db,        /* Report malloc errors to this connection */
    +-  Expr *pExpr,        /* Expr in which substitution occurs */
    +-  int iTable,         /* Table to be substituted */
    +-  ExprList *pEList    /* Substitute expressions */
    ++  SubstContext *pSubst,  /* Description of the substitution */
    ++  Expr *pExpr            /* Expr in which substitution occurs */
    + ){
    +   if( pExpr==0 ) return 0;
    +-  if( pExpr->op==TK_COLUMN && pExpr->iTable==iTable ){
    ++  if( ExprHasProperty(pExpr, EP_FromJoin)
    ++   && pExpr->iRightJoinTable==pSubst->iTable
    ++  ){
    ++    pExpr->iRightJoinTable = pSubst->iNewTable;
    ++  }
    ++  if( pExpr->op==TK_COLUMN && pExpr->iTable==pSubst->iTable ){
    +     if( pExpr->iColumn<0 ){
    +       pExpr->op = TK_NULL;
    +     }else{
    +       Expr *pNew;
    +-      assert( pEList!=0 && pExpr->iColumn<pEList->nExpr );
    ++      Expr *pCopy = pSubst->pEList->a[pExpr->iColumn].pExpr;
    ++      Expr ifNullRow;
    ++      assert( pSubst->pEList!=0 && pExpr->iColumn<pSubst->pEList->nExpr );
    +       assert( pExpr->pLeft==0 && pExpr->pRight==0 );
    +-      pNew = sqlite3ExprDup(db, pEList->a[pExpr->iColumn].pExpr, 0);
    +-      sqlite3ExprDelete(db, pExpr);
    +-      pExpr = pNew;
    ++      if( sqlite3ExprIsVector(pCopy) ){
    ++        sqlite3VectorErrorMsg(pSubst->pParse, pCopy);
    ++      }else{
    ++        sqlite3 *db = pSubst->pParse->db;
    ++        if( pSubst->isLeftJoin && pCopy->op!=TK_COLUMN ){
    ++          memset(&ifNullRow, 0, sizeof(ifNullRow));
    ++          ifNullRow.op = TK_IF_NULL_ROW;
    ++          ifNullRow.pLeft = pCopy;
    ++          ifNullRow.iTable = pSubst->iNewTable;
    ++          pCopy = &ifNullRow;
    ++        }
    ++        pNew = sqlite3ExprDup(db, pCopy, 0);
    ++        if( pNew && pSubst->isLeftJoin ){
    ++          ExprSetProperty(pNew, EP_CanBeNull);
    ++        }
    ++        if( pNew && ExprHasProperty(pExpr,EP_FromJoin) ){
    ++          pNew->iRightJoinTable = pExpr->iRightJoinTable;
    ++          ExprSetProperty(pNew, EP_FromJoin);
    ++        }
    ++        sqlite3ExprDelete(db, pExpr);
    ++        pExpr = pNew;
    ++      }
    +     }
    +   }else{
    +-    pExpr->pLeft = substExpr(db, pExpr->pLeft, iTable, pEList);
    +-    pExpr->pRight = substExpr(db, pExpr->pRight, iTable, pEList);
    ++    if( pExpr->op==TK_IF_NULL_ROW && pExpr->iTable==pSubst->iTable ){
    ++      pExpr->iTable = pSubst->iNewTable;
    ++    }
    ++    pExpr->pLeft = substExpr(pSubst, pExpr->pLeft);
    ++    pExpr->pRight = substExpr(pSubst, pExpr->pRight);
    +     if( ExprHasProperty(pExpr, EP_xIsSelect) ){
    +-      substSelect(db, pExpr->x.pSelect, iTable, pEList, 1);
    ++      substSelect(pSubst, pExpr->x.pSelect, 1);
    +     }else{
    +-      substExprList(db, pExpr->x.pList, iTable, pEList);
    ++      substExprList(pSubst, pExpr->x.pList);
    +     }
    +   }
    +   return pExpr;
    + }
    + static void substExprList(
    +-  sqlite3 *db,         /* Report malloc errors here */
    +-  ExprList *pList,     /* List to scan and in which to make substitutes */
    +-  int iTable,          /* Table to be substituted */
    +-  ExprList *pEList     /* Substitute values */
    ++  SubstContext *pSubst, /* Description of the substitution */
    ++  ExprList *pList       /* List to scan and in which to make substitutes */
    + ){
    +   int i;
    +   if( pList==0 ) return;
    +   for(i=0; i<pList->nExpr; i++){
    +-    pList->a[i].pExpr = substExpr(db, pList->a[i].pExpr, iTable, pEList);
    ++    pList->a[i].pExpr = substExpr(pSubst, pList->a[i].pExpr);
    +   }
    + }
    + static void substSelect(
    +-  sqlite3 *db,         /* Report malloc errors here */
    +-  Select *p,           /* SELECT statement in which to make substitutions */
    +-  int iTable,          /* Table to be replaced */
    +-  ExprList *pEList,    /* Substitute values */
    +-  int doPrior          /* Do substitutes on p->pPrior too */
    ++  SubstContext *pSubst, /* Description of the substitution */
    ++  Select *p,            /* SELECT statement in which to make substitutions */
    ++  int doPrior           /* Do substitutes on p->pPrior too */
    + ){
    +   SrcList *pSrc;
    +   struct SrcList_item *pItem;
    +   int i;
    +   if( !p ) return;
    +   do{
    +-    substExprList(db, p->pEList, iTable, pEList);
    +-    substExprList(db, p->pGroupBy, iTable, pEList);
    +-    substExprList(db, p->pOrderBy, iTable, pEList);
    +-    p->pHaving = substExpr(db, p->pHaving, iTable, pEList);
    +-    p->pWhere = substExpr(db, p->pWhere, iTable, pEList);
    ++    substExprList(pSubst, p->pEList);
    ++    substExprList(pSubst, p->pGroupBy);
    ++    substExprList(pSubst, p->pOrderBy);
    ++    p->pHaving = substExpr(pSubst, p->pHaving);
    ++    p->pWhere = substExpr(pSubst, p->pWhere);
    +     pSrc = p->pSrc;
    +     assert( pSrc!=0 );
    +     for(i=pSrc->nSrc, pItem=pSrc->a; i>0; i--, pItem++){
    +-      substSelect(db, pItem->pSelect, iTable, pEList, 1);
    ++      substSelect(pSubst, pItem->pSelect, 1);
    +       if( pItem->fg.isTabFunc ){
    +-        substExprList(db, pItem->u1.pFuncArg, iTable, pEList);
    ++        substExprList(pSubst, pItem->u1.pFuncArg);
    +       }
    +     }
    +   }while( doPrior && (p = p->pPrior)!=0 );
    +@@ -111849,66 +121969,74 @@ static void substSelect(
    + ** exist on the table t1, a complete scan of the data might be
    + ** avoided.
    + **
    +-** Flattening is only attempted if all of the following are true:
    ++** Flattening is subject to the following constraints:
    + **
    +-**   (1)  The subquery and the outer query do not both use aggregates.
    ++**  (**)  We no longer attempt to flatten aggregate subqueries. Was:
    ++**        The subquery and the outer query cannot both be aggregates.
    + **
    +-**   (2)  The subquery is not an aggregate or (2a) the outer query is not a join
    +-**        and (2b) the outer query does not use subqueries other than the one
    +-**        FROM-clause subquery that is a candidate for flattening.  (2b is
    +-**        due to ticket [2f7170d73bf9abf80] from 2015-02-09.)
    ++**  (**)  We no longer attempt to flatten aggregate subqueries. Was:
    ++**        (2) If the subquery is an aggregate then
    ++**        (2a) the outer query must not be a join and
    ++**        (2b) the outer query must not use subqueries
    ++**             other than the one FROM-clause subquery that is a candidate
    ++**             for flattening.  (This is due to ticket [2f7170d73bf9abf80]
    ++**             from 2015-02-09.)
    + **
    +-**   (3)  The subquery is not the right operand of a left outer join
    +-**        (Originally ticket #306.  Strengthened by ticket #3300)
    ++**   (3)  If the subquery is the right operand of a LEFT JOIN then
    ++**        (3a) the subquery may not be a join and
    ++**        (3b) the FROM clause of the subquery may not contain a virtual
    ++**             table and
    ++**        (3c) the outer query may not be an aggregate.
    + **
    +-**   (4)  The subquery is not DISTINCT.
    ++**   (4)  The subquery can not be DISTINCT.
    + **
    + **  (**)  At one point restrictions (4) and (5) defined a subset of DISTINCT
    + **        sub-queries that were excluded from this optimization. Restriction 
    + **        (4) has since been expanded to exclude all DISTINCT subqueries.
    + **
    +-**   (6)  The subquery does not use aggregates or the outer query is not
    +-**        DISTINCT.
    ++**  (**)  We no longer attempt to flatten aggregate subqueries.  Was:
    ++**        If the subquery is aggregate, the outer query may not be DISTINCT.
    + **
    +-**   (7)  The subquery has a FROM clause.  TODO:  For subqueries without
    +-**        A FROM clause, consider adding a FROM close with the special
    ++**   (7)  The subquery must have a FROM clause.  TODO:  For subqueries without
    ++**        A FROM clause, consider adding a FROM clause with the special
    + **        table sqlite_once that consists of a single row containing a
    + **        single NULL.
    + **
    +-**   (8)  The subquery does not use LIMIT or the outer query is not a join.
    ++**   (8)  If the subquery uses LIMIT then the outer query may not be a join.
    + **
    +-**   (9)  The subquery does not use LIMIT or the outer query does not use
    +-**        aggregates.
    ++**   (9)  If the subquery uses LIMIT then the outer query may not be aggregate.
    + **
    + **  (**)  Restriction (10) was removed from the code on 2005-02-05 but we
    + **        accidently carried the comment forward until 2014-09-15.  Original
    +-**        text: "The subquery does not use aggregates or the outer query 
    +-**        does not use LIMIT."
    ++**        constraint: "If the subquery is aggregate then the outer query 
    ++**        may not use LIMIT."
    + **
    +-**  (11)  The subquery and the outer query do not both have ORDER BY clauses.
    ++**  (11)  The subquery and the outer query may not both have ORDER BY clauses.
    + **
    + **  (**)  Not implemented.  Subsumed into restriction (3).  Was previously
    + **        a separate restriction deriving from ticket #350.
    + **
    +-**  (13)  The subquery and outer query do not both use LIMIT.
    ++**  (13)  The subquery and outer query may not both use LIMIT.
    + **
    +-**  (14)  The subquery does not use OFFSET.
    ++**  (14)  The subquery may not use OFFSET.
    + **
    +-**  (15)  The outer query is not part of a compound select or the
    +-**        subquery does not have a LIMIT clause.
    ++**  (15)  If the outer query is part of a compound select, then the
    ++**        subquery may not use LIMIT.
    + **        (See ticket #2339 and ticket [02a8e81d44]).
    + **
    +-**  (16)  The outer query is not an aggregate or the subquery does
    +-**        not contain ORDER BY.  (Ticket #2942)  This used to not matter
    ++**  (16)  If the outer query is aggregate, then the subquery may not
    ++**        use ORDER BY.  (Ticket #2942)  This used to not matter
    + **        until we introduced the group_concat() function.  
    + **
    +-**  (17)  The sub-query is not a compound select, or it is a UNION ALL 
    +-**        compound clause made up entirely of non-aggregate queries, and 
    +-**        the parent query:
    +-**
    +-**          * is not itself part of a compound select,
    +-**          * is not an aggregate or DISTINCT query, and
    +-**          * is not a join
    ++**  (17)  If the subquery is a compound select, then
    ++**        (17a) all compound operators must be a UNION ALL, and
    ++**        (17b) no terms within the subquery compound may be aggregate
    ++**              or DISTINCT, and
    ++**        (17c) every term within the subquery compound must have a FROM clause
    ++**        (17d) the outer query may not be
    ++**              (17d1) aggregate, or
    ++**              (17d2) DISTINCT, or
    ++**              (17d3) a join.
    + **
    + **        The parent and sub-query may contain WHERE clauses. Subject to
    + **        rules (11), (13) and (14), they may also contain ORDER BY,
    +@@ -111924,10 +122052,10 @@ static void substSelect(
    + **        syntax error and return a detailed message.
    + **
    + **  (18)  If the sub-query is a compound select, then all terms of the
    +-**        ORDER by clause of the parent must be simple references to 
    ++**        ORDER BY clause of the parent must be simple references to 
    + **        columns of the sub-query.
    + **
    +-**  (19)  The subquery does not use LIMIT or the outer query does not
    ++**  (19)  If the subquery uses LIMIT then the outer query may not
    + **        have a WHERE clause.
    + **
    + **  (20)  If the sub-query is a compound select, then it must not use
    +@@ -111936,17 +122064,19 @@ static void substSelect(
    + **        appear as unmodified result columns in the outer query.  But we
    + **        have other optimizations in mind to deal with that case.
    + **
    +-**  (21)  The subquery does not use LIMIT or the outer query is not
    ++**  (21)  If the subquery uses LIMIT then the outer query may not be
    + **        DISTINCT.  (See ticket [752e1646fc]).
    + **
    +-**  (22)  The subquery is not a recursive CTE.
    ++**  (22)  The subquery may not be a recursive CTE.
    + **
    +-**  (23)  The parent is not a recursive CTE, or the sub-query is not a
    +-**        compound query. This restriction is because transforming the
    ++**  (**)  Subsumed into restriction (17d3).  Was: If the outer query is
    ++**        a recursive CTE, then the sub-query may not be a compound query.
    ++**        This restriction is because transforming the
    + **        parent to a compound query confuses the code that handles
    + **        recursive queries in multiSelect().
    + **
    +-**  (24)  The subquery is not an aggregate that uses the built-in min() or 
    ++**  (**)  We no longer attempt to flatten aggregate subqueries.  Was:
    ++**        The subquery may not be an aggregate that uses the built-in min() or 
    + **        or max() functions.  (Without this restriction, a query like:
    + **        "SELECT x FROM (SELECT max(y), x FROM t1)" would not necessarily
    + **        return the value X for which Y was maximal.)
    +@@ -111954,7 +122084,7 @@ static void substSelect(
    + **
    + ** In this routine, the "p" parameter is a pointer to the outer query.
    + ** The subquery is p->pSrc->a[iFrom].  isAgg is true if the outer query
    +-** uses aggregates and subqueryIsAgg is true if the subquery uses aggregates.
    ++** uses aggregates.
    + **
    + ** If flattening is not attempted, this routine is a no-op and returns 0.
    + ** If flattening is attempted this routine returns 1.
    +@@ -111966,8 +122096,7 @@ static int flattenSubquery(
    +   Parse *pParse,       /* Parsing context */
    +   Select *p,           /* The parent or outer SELECT statement */
    +   int iFrom,           /* Index in p->pSrc->a[] of the inner subquery */
    +-  int isAgg,           /* True if outer SELECT uses aggregate functions */
    +-  int subqueryIsAgg    /* True if the subquery uses aggregate functions */
    ++  int isAgg            /* True if outer SELECT uses aggregate functions */
    + ){
    +   const char *zSavedAuthContext = pParse->zAuthContext;
    +   Select *pParent;    /* Current UNION ALL term of the other query */
    +@@ -111975,8 +122104,9 @@ static int flattenSubquery(
    +   Select *pSub1;      /* Pointer to the rightmost select in sub-query */
    +   SrcList *pSrc;      /* The FROM clause of the outer query */
    +   SrcList *pSubSrc;   /* The FROM clause of the subquery */
    +-  ExprList *pList;    /* The result set of the outer query */
    +   int iParent;        /* VDBE cursor number of the pSub result set temp table */
    ++  int iNewParent = -1;/* Replacement table for iParent */
    ++  int isLeftJoin = 0; /* True if pSub is the right side of a LEFT JOIN */    
    +   int i;              /* Loop counter */
    +   Expr *pWhere;                    /* The WHERE clause */
    +   struct SrcList_item *pSubitem;   /* The subquery */
    +@@ -111985,7 +122115,7 @@ static int flattenSubquery(
    +   /* Check to see if flattening is permitted.  Return 0 if not.
    +   */
    +   assert( p!=0 );
    +-  assert( p->pPrior==0 );  /* Unable to flatten compound queries */
    ++  assert( p->pPrior==0 );
    +   if( OptimizationDisabled(db, SQLITE_QueryFlattener) ) return 0;
    +   pSrc = p->pSrc;
    +   assert( pSrc && iFrom>=0 && iFrom<pSrc->nSrc );
    +@@ -111993,17 +122123,7 @@ static int flattenSubquery(
    +   iParent = pSubitem->iCursor;
    +   pSub = pSubitem->pSelect;
    +   assert( pSub!=0 );
    +-  if( subqueryIsAgg ){
    +-    if( isAgg ) return 0;                                /* Restriction (1)   */
    +-    if( pSrc->nSrc>1 ) return 0;                         /* Restriction (2a)  */
    +-    if( (p->pWhere && ExprHasProperty(p->pWhere,EP_Subquery))
    +-     || (sqlite3ExprListFlags(p->pEList) & EP_Subquery)!=0
    +-     || (sqlite3ExprListFlags(p->pOrderBy) & EP_Subquery)!=0
    +-    ){
    +-      return 0;                                          /* Restriction (2b)  */
    +-    }
    +-  }
    +-    
    ++
    +   pSubSrc = pSub->pSrc;
    +   assert( pSubSrc );
    +   /* Prior to version 3.1.2, when LIMIT and OFFSET had to be simple constants,
    +@@ -112012,18 +122132,15 @@ static int flattenSubquery(
    +   ** became arbitrary expressions, we were forced to add restrictions (13)
    +   ** and (14). */
    +   if( pSub->pLimit && p->pLimit ) return 0;              /* Restriction (13) */
    +-  if( pSub->pOffset ) return 0;                          /* Restriction (14) */
    ++  if( pSub->pLimit && pSub->pLimit->pRight ) return 0;   /* Restriction (14) */
    +   if( (p->selFlags & SF_Compound)!=0 && pSub->pLimit ){
    +     return 0;                                            /* Restriction (15) */
    +   }
    +   if( pSubSrc->nSrc==0 ) return 0;                       /* Restriction (7)  */
    +-  if( pSub->selFlags & SF_Distinct ) return 0;           /* Restriction (5)  */
    ++  if( pSub->selFlags & SF_Distinct ) return 0;           /* Restriction (4)  */
    +   if( pSub->pLimit && (pSrc->nSrc>1 || isAgg) ){
    +      return 0;         /* Restrictions (8)(9) */
    +   }
    +-  if( (p->selFlags & SF_Distinct)!=0 && subqueryIsAgg ){
    +-     return 0;         /* Restriction (6)  */
    +-  }
    +   if( p->pOrderBy && pSub->pOrderBy ){
    +      return 0;                                           /* Restriction (11) */
    +   }
    +@@ -112032,19 +122149,14 @@ static int flattenSubquery(
    +   if( pSub->pLimit && (p->selFlags & SF_Distinct)!=0 ){
    +      return 0;         /* Restriction (21) */
    +   }
    +-  testcase( pSub->selFlags & SF_Recursive );
    +-  testcase( pSub->selFlags & SF_MinMaxAgg );
    +-  if( pSub->selFlags & (SF_Recursive|SF_MinMaxAgg) ){
    +-    return 0; /* Restrictions (22) and (24) */
    +-  }
    +-  if( (p->selFlags & SF_Recursive) && pSub->pPrior ){
    +-    return 0; /* Restriction (23) */
    ++  if( pSub->selFlags & (SF_Recursive) ){
    ++    return 0; /* Restrictions (22) */
    +   }
    + 
    +-  /* OBSOLETE COMMENT 1:
    +-  ** Restriction 3:  If the subquery is a join, make sure the subquery is 
    +-  ** not used as the right operand of an outer join.  Examples of why this
    +-  ** is not allowed:
    ++  /*
    ++  ** If the subquery is the right operand of a LEFT JOIN, then the
    ++  ** subquery may not be a join itself (3a). Example of why this is not
    ++  ** allowed:
    +   **
    +   **         t1 LEFT OUTER JOIN (t2 JOIN t3)
    +   **
    +@@ -112054,56 +122166,57 @@ static int flattenSubquery(
    +   **
    +   ** which is not at all the same thing.
    +   **
    +-  ** OBSOLETE COMMENT 2:
    +-  ** Restriction 12:  If the subquery is the right operand of a left outer
    +-  ** join, make sure the subquery has no WHERE clause.
    +-  ** An examples of why this is not allowed:
    +-  **
    +-  **         t1 LEFT OUTER JOIN (SELECT * FROM t2 WHERE t2.x>0)
    +-  **
    +-  ** If we flatten the above, we would get
    +-  **
    +-  **         (t1 LEFT OUTER JOIN t2) WHERE t2.x>0
    ++  ** If the subquery is the right operand of a LEFT JOIN, then the outer
    ++  ** query cannot be an aggregate. (3c)  This is an artifact of the way
    ++  ** aggregates are processed - there is no mechanism to determine if
    ++  ** the LEFT JOIN table should be all-NULL.
    +   **
    +-  ** But the t2.x>0 test will always fail on a NULL row of t2, which
    +-  ** effectively converts the OUTER JOIN into an INNER JOIN.
    +-  **
    +-  ** THIS OVERRIDES OBSOLETE COMMENTS 1 AND 2 ABOVE:
    +-  ** Ticket #3300 shows that flattening the right term of a LEFT JOIN
    +-  ** is fraught with danger.  Best to avoid the whole thing.  If the
    +-  ** subquery is the right term of a LEFT JOIN, then do not flatten.
    ++  ** See also tickets #306, #350, and #3300.
    +   */
    +   if( (pSubitem->fg.jointype & JT_OUTER)!=0 ){
    +-    return 0;
    ++    isLeftJoin = 1;
    ++    if( pSubSrc->nSrc>1 || isAgg || IsVirtual(pSubSrc->a[0].pTab) ){
    ++      /*  (3a)             (3c)     (3b) */
    ++      return 0;
    ++    }
    +   }
    ++#ifdef SQLITE_EXTRA_IFNULLROW
    ++  else if( iFrom>0 && !isAgg ){
    ++    /* Setting isLeftJoin to -1 causes OP_IfNullRow opcodes to be generated for
    ++    ** every reference to any result column from subquery in a join, even
    ++    ** though they are not necessary.  This will stress-test the OP_IfNullRow 
    ++    ** opcode. */
    ++    isLeftJoin = -1;
    ++  }
    ++#endif
    + 
    +-  /* Restriction 17: If the sub-query is a compound SELECT, then it must
    ++  /* Restriction (17): If the sub-query is a compound SELECT, then it must
    +   ** use only the UNION ALL operator. And none of the simple select queries
    +   ** that make up the compound SELECT are allowed to be aggregate or distinct
    +   ** queries.
    +   */
    +   if( pSub->pPrior ){
    +     if( pSub->pOrderBy ){
    +-      return 0;  /* Restriction 20 */
    ++      return 0;  /* Restriction (20) */
    +     }
    +     if( isAgg || (p->selFlags & SF_Distinct)!=0 || pSrc->nSrc!=1 ){
    +-      return 0;
    ++      return 0; /* (17d1), (17d2), or (17d3) */
    +     }
    +     for(pSub1=pSub; pSub1; pSub1=pSub1->pPrior){
    +       testcase( (pSub1->selFlags & (SF_Distinct|SF_Aggregate))==SF_Distinct );
    +       testcase( (pSub1->selFlags & (SF_Distinct|SF_Aggregate))==SF_Aggregate );
    +       assert( pSub->pSrc!=0 );
    +       assert( pSub->pEList->nExpr==pSub1->pEList->nExpr );
    +-      if( (pSub1->selFlags & (SF_Distinct|SF_Aggregate))!=0
    +-       || (pSub1->pPrior && pSub1->op!=TK_ALL) 
    +-       || pSub1->pSrc->nSrc<1
    ++      if( (pSub1->selFlags & (SF_Distinct|SF_Aggregate))!=0    /* (17b) */
    ++       || (pSub1->pPrior && pSub1->op!=TK_ALL)                 /* (17a) */
    ++       || pSub1->pSrc->nSrc<1                                  /* (17c) */
    +       ){
    +         return 0;
    +       }
    +       testcase( pSub1->pSrc->nSrc>1 );
    +     }
    + 
    +-    /* Restriction 18. */
    ++    /* Restriction (18). */
    +     if( p->pOrderBy ){
    +       int ii;
    +       for(ii=0; ii<p->pOrderBy->nExpr; ii++){
    +@@ -112112,6 +122225,14 @@ static int flattenSubquery(
    +     }
    +   }
    + 
    ++  /* Ex-restriction (23):
    ++  ** The only way that the recursive part of a CTE can contain a compound
    ++  ** subquery is for the subquery to be one term of a join.  But if the
    ++  ** subquery is a join, then the flattening has already been stopped by
    ++  ** restriction (17d3)
    ++  */
    ++  assert( (p->selFlags & SF_Recursive)==0 || pSub->pPrior==0 );
    ++
    +   /***** If we reach this point, flattening is permitted. *****/
    +   SELECTTRACE(1,pParse,p,("flatten %s.%p from term %d\n",
    +                    pSub->zSelName, pSub, iFrom));
    +@@ -112159,16 +122280,13 @@ static int flattenSubquery(
    +     Select *pNew;
    +     ExprList *pOrderBy = p->pOrderBy;
    +     Expr *pLimit = p->pLimit;
    +-    Expr *pOffset = p->pOffset;
    +     Select *pPrior = p->pPrior;
    +     p->pOrderBy = 0;
    +     p->pSrc = 0;
    +     p->pPrior = 0;
    +     p->pLimit = 0;
    +-    p->pOffset = 0;
    +     pNew = sqlite3SelectDup(db, p, 0);
    +     sqlite3SelectSetName(pNew, pSub->zSelName);
    +-    p->pOffset = pOffset;
    +     p->pLimit = pLimit;
    +     p->pOrderBy = pOrderBy;
    +     p->pSrc = pSrc;
    +@@ -112212,12 +122330,12 @@ static int flattenSubquery(
    +   */
    +   if( ALWAYS(pSubitem->pTab!=0) ){
    +     Table *pTabToDel = pSubitem->pTab;
    +-    if( pTabToDel->nRef==1 ){
    ++    if( pTabToDel->nTabRef==1 ){
    +       Parse *pToplevel = sqlite3ParseToplevel(pParse);
    +       pTabToDel->pNextZombie = pToplevel->pZombieTab;
    +       pToplevel->pZombieTab = pTabToDel;
    +     }else{
    +-      pTabToDel->nRef--;
    ++      pTabToDel->nTabRef--;
    +     }
    +     pSubitem->pTab = 0;
    +   }
    +@@ -112281,7 +122399,9 @@ static int flattenSubquery(
    +     */
    +     for(i=0; i<nSubSrc; i++){
    +       sqlite3IdListDelete(db, pSrc->a[i+iFrom].pUsing);
    ++      assert( pSrc->a[i+iFrom].fg.isTabFunc==0 );
    +       pSrc->a[i+iFrom] = pSubSrc->a[i];
    ++      iNewParent = pSubSrc->a[i].iCursor;
    +       memset(&pSubSrc->a[i], 0, sizeof(pSubSrc->a[i]));
    +     }
    +     pSrc->a[iFrom].fg.jointype = jointype;
    +@@ -112298,14 +122418,6 @@ static int flattenSubquery(
    +     ** We look at every expression in the outer query and every place we see
    +     ** "a" we substitute "x*3" and every place we see "b" we substitute "y+10".
    +     */
    +-    pList = pParent->pEList;
    +-    for(i=0; i<pList->nExpr; i++){
    +-      if( pList->a[i].zName==0 ){
    +-        char *zName = sqlite3DbStrDup(db, pList->a[i].zSpan);
    +-        sqlite3Dequote(zName);
    +-        pList->a[i].zName = zName;
    +-      }
    +-    }
    +     if( pSub->pOrderBy ){
    +       /* At this point, any non-zero iOrderByCol values indicate that the
    +       ** ORDER BY column expression is identical to the iOrderByCol'th
    +@@ -112327,18 +122439,19 @@ static int flattenSubquery(
    +       pSub->pOrderBy = 0;
    +     }
    +     pWhere = sqlite3ExprDup(db, pSub->pWhere, 0);
    +-    if( subqueryIsAgg ){
    +-      assert( pParent->pHaving==0 );
    +-      pParent->pHaving = pParent->pWhere;
    +-      pParent->pWhere = pWhere;
    +-      pParent->pHaving = sqlite3ExprAnd(db, pParent->pHaving, 
    +-                                  sqlite3ExprDup(db, pSub->pHaving, 0));
    +-      assert( pParent->pGroupBy==0 );
    +-      pParent->pGroupBy = sqlite3ExprListDup(db, pSub->pGroupBy, 0);
    +-    }else{
    +-      pParent->pWhere = sqlite3ExprAnd(db, pParent->pWhere, pWhere);
    +-    }
    +-    substSelect(db, pParent, iParent, pSub->pEList, 0);
    ++    if( isLeftJoin>0 ){
    ++      setJoinExpr(pWhere, iNewParent);
    ++    }
    ++    pParent->pWhere = sqlite3ExprAnd(db, pWhere, pParent->pWhere);
    ++    if( db->mallocFailed==0 ){
    ++      SubstContext x;
    ++      x.pParse = pParse;
    ++      x.iTable = iParent;
    ++      x.iNewTable = iNewParent;
    ++      x.isLeftJoin = isLeftJoin;
    ++      x.pEList = pSub->pEList;
    ++      substSelect(&x, pParent, 0);
    ++    }
    +   
    +     /* The flattened query is distinct if either the inner or the
    +     ** outer query is distinct. 
    +@@ -112392,9 +122505,13 @@ static int flattenSubquery(
    + **
    + ** Do not attempt this optimization if:
    + **
    +-**   (1) The inner query is an aggregate.  (In that case, we'd really want
    +-**       to copy the outer WHERE-clause terms onto the HAVING clause of the
    +-**       inner query.  But they probably won't help there so do not bother.)
    ++**   (1) (** This restriction was removed on 2017-09-29.  We used to
    ++**           disallow this optimization for aggregate subqueries, but now
    ++**           it is allowed by putting the extra terms on the HAVING clause.
    ++**           The added HAVING clause is pointless if the subquery lacks
    ++**           a GROUP BY clause.  But such a HAVING clause is also harmless
    ++**           so there does not appear to be any reason to add extra logic
    ++**           to suppress it. **)
    + **
    + **   (2) The inner query is the recursive part of a common table expression.
    + **
    +@@ -112412,7 +122529,7 @@ static int flattenSubquery(
    + ** terms are duplicated into the subquery.
    + */
    + static int pushDownWhereTerms(
    +-  sqlite3 *db,          /* The database connection (for malloc()) */
    ++  Parse *pParse,        /* Parse context (for malloc() and error reporting) */
    +   Select *pSubq,        /* The subquery whose WHERE clause is to be augmented */
    +   Expr *pWhere,         /* The WHERE clause of the outer query */
    +   int iCursor           /* Cursor number of the subquery */
    +@@ -112420,23 +122537,45 @@ static int pushDownWhereTerms(
    +   Expr *pNew;
    +   int nChng = 0;
    +   if( pWhere==0 ) return 0;
    +-  if( (pSubq->selFlags & (SF_Aggregate|SF_Recursive))!=0 ){
    +-     return 0; /* restrictions (1) and (2) */
    ++  if( pSubq->selFlags & SF_Recursive ) return 0;  /* restriction (2) */
    ++
    ++#ifdef SQLITE_DEBUG
    ++  /* Only the first term of a compound can have a WITH clause.  But make
    ++  ** sure no other terms are marked SF_Recursive in case something changes
    ++  ** in the future.
    ++  */
    ++  {
    ++    Select *pX;  
    ++    for(pX=pSubq; pX; pX=pX->pPrior){
    ++      assert( (pX->selFlags & (SF_Recursive))==0 );
    ++    }
    +   }
    ++#endif
    ++
    +   if( pSubq->pLimit!=0 ){
    +-     return 0; /* restriction (3) */
    ++    return 0; /* restriction (3) */
    +   }
    +   while( pWhere->op==TK_AND ){
    +-    nChng += pushDownWhereTerms(db, pSubq, pWhere->pRight, iCursor);
    ++    nChng += pushDownWhereTerms(pParse, pSubq, pWhere->pRight, iCursor);
    +     pWhere = pWhere->pLeft;
    +   }
    +-  if( ExprHasProperty(pWhere,EP_FromJoin) ) return 0; /* restriction 5 */
    ++  if( ExprHasProperty(pWhere,EP_FromJoin) ) return 0; /* restriction (5) */
    +   if( sqlite3ExprIsTableConstant(pWhere, iCursor) ){
    +     nChng++;
    +     while( pSubq ){
    +-      pNew = sqlite3ExprDup(db, pWhere, 0);
    +-      pNew = substExpr(db, pNew, iCursor, pSubq->pEList);
    +-      pSubq->pWhere = sqlite3ExprAnd(db, pSubq->pWhere, pNew);
    ++      SubstContext x;
    ++      pNew = sqlite3ExprDup(pParse->db, pWhere, 0);
    ++      x.pParse = pParse;
    ++      x.iTable = iCursor;
    ++      x.iNewTable = iCursor;
    ++      x.isLeftJoin = 0;
    ++      x.pEList = pSubq->pEList;
    ++      pNew = substExpr(&x, pNew);
    ++      if( pSubq->selFlags & SF_Aggregate ){
    ++        pSubq->pHaving = sqlite3ExprAnd(pParse->db, pSubq->pHaving, pNew);
    ++      }else{
    ++        pSubq->pWhere = sqlite3ExprAnd(pParse->db, pSubq->pWhere, pNew);
    ++      }
    +       pSubq = pSubq->pPrior;
    +     }
    +   }
    +@@ -112445,42 +122584,44 @@ static int pushDownWhereTerms(
    + #endif /* !defined(SQLITE_OMIT_SUBQUERY) || !defined(SQLITE_OMIT_VIEW) */
    + 
    + /*
    +-** Based on the contents of the AggInfo structure indicated by the first
    +-** argument, this function checks if the following are true:
    ++** The pFunc is the only aggregate function in the query.  Check to see
    ++** if the query is a candidate for the min/max optimization. 
    + **
    +-**    * the query contains just a single aggregate function,
    +-**    * the aggregate function is either min() or max(), and
    +-**    * the argument to the aggregate function is a column value.
    ++** If the query is a candidate for the min/max optimization, then set
    ++** *ppMinMax to be an ORDER BY clause to be used for the optimization
    ++** and return either WHERE_ORDERBY_MIN or WHERE_ORDERBY_MAX depending on
    ++** whether pFunc is a min() or max() function.
    + **
    +-** If all of the above are true, then WHERE_ORDERBY_MIN or WHERE_ORDERBY_MAX
    +-** is returned as appropriate. Also, *ppMinMax is set to point to the 
    +-** list of arguments passed to the aggregate before returning.
    ++** If the query is not a candidate for the min/max optimization, return
    ++** WHERE_ORDERBY_NORMAL (which must be zero).
    + **
    +-** Or, if the conditions above are not met, *ppMinMax is set to 0 and
    +-** WHERE_ORDERBY_NORMAL is returned.
    ++** This routine must be called after aggregate functions have been
    ++** located but before their arguments have been subjected to aggregate
    ++** analysis.
    + */
    +-static u8 minMaxQuery(AggInfo *pAggInfo, ExprList **ppMinMax){
    +-  int eRet = WHERE_ORDERBY_NORMAL;          /* Return value */
    +-
    +-  *ppMinMax = 0;
    +-  if( pAggInfo->nFunc==1 ){
    +-    Expr *pExpr = pAggInfo->aFunc[0].pExpr; /* Aggregate function */
    +-    ExprList *pEList = pExpr->x.pList;      /* Arguments to agg function */
    +-
    +-    assert( pExpr->op==TK_AGG_FUNCTION );
    +-    if( pEList && pEList->nExpr==1 && pEList->a[0].pExpr->op==TK_AGG_COLUMN ){
    +-      const char *zFunc = pExpr->u.zToken;
    +-      if( sqlite3StrICmp(zFunc, "min")==0 ){
    +-        eRet = WHERE_ORDERBY_MIN;
    +-        *ppMinMax = pEList;
    +-      }else if( sqlite3StrICmp(zFunc, "max")==0 ){
    +-        eRet = WHERE_ORDERBY_MAX;
    +-        *ppMinMax = pEList;
    +-      }
    +-    }
    +-  }
    +-
    +-  assert( *ppMinMax==0 || (*ppMinMax)->nExpr==1 );
    ++static u8 minMaxQuery(sqlite3 *db, Expr *pFunc, ExprList **ppMinMax){
    ++  int eRet = WHERE_ORDERBY_NORMAL;      /* Return value */
    ++  ExprList *pEList = pFunc->x.pList;    /* Arguments to agg function */
    ++  const char *zFunc;                    /* Name of aggregate function pFunc */
    ++  ExprList *pOrderBy;
    ++  u8 sortOrder;
    ++
    ++  assert( *ppMinMax==0 );
    ++  assert( pFunc->op==TK_AGG_FUNCTION );
    ++  if( pEList==0 || pEList->nExpr!=1 ) return eRet;
    ++  zFunc = pFunc->u.zToken;
    ++  if( sqlite3StrICmp(zFunc, "min")==0 ){
    ++    eRet = WHERE_ORDERBY_MIN;
    ++    sortOrder = SQLITE_SO_ASC;
    ++  }else if( sqlite3StrICmp(zFunc, "max")==0 ){
    ++    eRet = WHERE_ORDERBY_MAX;
    ++    sortOrder = SQLITE_SO_DESC;
    ++  }else{
    ++    return eRet;
    ++  }
    ++  *ppMinMax = pOrderBy = sqlite3ExprListDup(db, pEList, 0);
    ++  assert( pOrderBy!=0 || db->mallocFailed );
    ++  if( pOrderBy ) pOrderBy->a[0].sortOrder = sortOrder;
    +   return eRet;
    + }
    + 
    +@@ -112596,7 +122737,7 @@ static int convertCompoundSelectToSubquery(Walker *pWalker, Select *p){
    +   if( pNewSrc==0 ) return WRC_Abort;
    +   *pNew = *p;
    +   p->pSrc = pNewSrc;
    +-  p->pEList = sqlite3ExprListAppend(pParse, 0, sqlite3Expr(db, TK_ALL, 0));
    ++  p->pEList = sqlite3ExprListAppend(pParse, 0, sqlite3Expr(db, TK_ASTERISK, 0));
    +   p->op = TK_SELECT;
    +   p->pWhere = 0;
    +   pNew->pGroupBy = 0;
    +@@ -112611,10 +122752,22 @@ static int convertCompoundSelectToSubquery(Walker *pWalker, Select *p){
    +   assert( pNew->pPrior!=0 );
    +   pNew->pPrior->pNext = pNew;
    +   pNew->pLimit = 0;
    +-  pNew->pOffset = 0;
    +   return WRC_Continue;
    + }
    + 
    ++/*
    ++** Check to see if the FROM clause term pFrom has table-valued function
    ++** arguments.  If it does, leave an error message in pParse and return
    ++** non-zero, since pFrom is not allowed to be a table-valued function.
    ++*/
    ++static int cannotBeFunction(Parse *pParse, struct SrcList_item *pFrom){
    ++  if( pFrom->fg.isTabFunc ){
    ++    sqlite3ErrorMsg(pParse, "'%s' is not a function", pFrom->zName);
    ++    return 1;
    ++  }
    ++  return 0;
    ++}
    ++
    + #ifndef SQLITE_OMIT_CTE
    + /*
    + ** Argument pWith (which may be NULL) points to a linked list of nested 
    +@@ -112627,7 +122780,7 @@ static int convertCompoundSelectToSubquery(Walker *pWalker, Select *p){
    + ** object that the returned CTE belongs to.
    + */
    + static struct Cte *searchWith(
    +-  With *pWith,                    /* Current outermost WITH clause */
    ++  With *pWith,                    /* Current innermost WITH clause */
    +   struct SrcList_item *pItem,     /* FROM clause element to resolve */
    +   With **ppContext                /* OUT: WITH clause return value belongs to */
    + ){
    +@@ -112658,11 +122811,12 @@ static struct Cte *searchWith(
    + ** statement with which it is associated.
    + */
    + SQLITE_PRIVATE void sqlite3WithPush(Parse *pParse, With *pWith, u8 bFree){
    +-  assert( bFree==0 || pParse->pWith==0 );
    ++  assert( bFree==0 || (pParse->pWith==0 && pParse->pWithToFree==0) );
    +   if( pWith ){
    ++    assert( pParse->pWith!=pWith );
    +     pWith->pOuter = pParse->pWith;
    +     pParse->pWith = pWith;
    +-    pParse->bFreeWith = bFree;
    ++    if( bFree ) pParse->pWithToFree = pWith;
    +   }
    + }
    + 
    +@@ -112709,17 +122863,18 @@ static int withExpand(
    +       sqlite3ErrorMsg(pParse, pCte->zCteErr, pCte->zName);
    +       return SQLITE_ERROR;
    +     }
    ++    if( cannotBeFunction(pParse, pFrom) ) return SQLITE_ERROR;
    + 
    +     assert( pFrom->pTab==0 );
    +     pFrom->pTab = pTab = sqlite3DbMallocZero(db, sizeof(Table));
    +     if( pTab==0 ) return WRC_Abort;
    +-    pTab->nRef = 1;
    ++    pTab->nTabRef = 1;
    +     pTab->zName = sqlite3DbStrDup(db, pCte->zName);
    +     pTab->iPKey = -1;
    +     pTab->nRowLogEst = 200; assert( 200==sqlite3LogEst(1048576) );
    +     pTab->tabFlags |= TF_Ephemeral | TF_NoVisibleRowid;
    +     pFrom->pSelect = sqlite3SelectDup(db, pCte->pSelect, 0);
    +-    if( db->mallocFailed ) return SQLITE_NOMEM;
    ++    if( db->mallocFailed ) return SQLITE_NOMEM_BKPT;
    +     assert( pFrom->pSelect );
    + 
    +     /* Check if this is a recursive CTE. */
    +@@ -112736,25 +122891,35 @@ static int withExpand(
    +           ){
    +           pItem->pTab = pTab;
    +           pItem->fg.isRecursive = 1;
    +-          pTab->nRef++;
    ++          pTab->nTabRef++;
    +           pSel->selFlags |= SF_Recursive;
    +         }
    +       }
    +     }
    + 
    +     /* Only one recursive reference is permitted. */ 
    +-    if( pTab->nRef>2 ){
    ++    if( pTab->nTabRef>2 ){
    +       sqlite3ErrorMsg(
    +           pParse, "multiple references to recursive table: %s", pCte->zName
    +       );
    +       return SQLITE_ERROR;
    +     }
    +-    assert( pTab->nRef==1 || ((pSel->selFlags&SF_Recursive) && pTab->nRef==2 ));
    ++    assert( pTab->nTabRef==1 || 
    ++            ((pSel->selFlags&SF_Recursive) && pTab->nTabRef==2 ));
    + 
    +     pCte->zCteErr = "circular reference: %s";
    +     pSavedWith = pParse->pWith;
    +     pParse->pWith = pWith;
    +-    sqlite3WalkSelect(pWalker, bMayRecursive ? pSel->pPrior : pSel);
    ++    if( bMayRecursive ){
    ++      Select *pPrior = pSel->pPrior;
    ++      assert( pPrior->pWith==0 );
    ++      pPrior->pWith = pSel->pWith;
    ++      sqlite3WalkSelect(pWalker, pPrior);
    ++      pPrior->pWith = 0;
    ++    }else{
    ++      sqlite3WalkSelect(pWalker, pSel);
    ++    }
    ++    pParse->pWith = pWith;
    + 
    +     for(pLeft=pSel; pLeft->pPrior; pLeft=pLeft->pPrior);
    +     pEList = pLeft->pEList;
    +@@ -112797,10 +122962,12 @@ static int withExpand(
    + */
    + static void selectPopWith(Walker *pWalker, Select *p){
    +   Parse *pParse = pWalker->pParse;
    +-  With *pWith = findRightmost(p)->pWith;
    +-  if( pWith!=0 ){
    +-    assert( pParse->pWith==pWith );
    +-    pParse->pWith = pWith->pOuter;
    ++  if( OK_IF_ALWAYS_TRUE(pParse->pWith) && p->pPrior==0 ){
    ++    With *pWith = findRightmost(p)->pWith;
    ++    if( pWith!=0 ){
    ++      assert( pParse->pWith==pWith );
    ++      pParse->pWith = pWith->pOuter;
    ++    }
    +   }
    + }
    + #else
    +@@ -112840,18 +123007,20 @@ static int selectExpander(Walker *pWalker, Select *p){
    +   sqlite3 *db = pParse->db;
    +   Expr *pE, *pRight, *pExpr;
    +   u16 selFlags = p->selFlags;
    ++  u32 elistFlags = 0;
    + 
    +   p->selFlags |= SF_Expanded;
    +   if( db->mallocFailed  ){
    +     return WRC_Abort;
    +   }
    +-  if( NEVER(p->pSrc==0) || (selFlags & SF_Expanded)!=0 ){
    ++  assert( p->pSrc!=0 );
    ++  if( (selFlags & SF_Expanded)!=0 ){
    +     return WRC_Prune;
    +   }
    +   pTabList = p->pSrc;
    +   pEList = p->pEList;
    +-  if( pWalker->xSelectCallback2==selectPopWith ){
    +-    sqlite3WithPush(pParse, findRightmost(p)->pWith, 0);
    ++  if( OK_IF_ALWAYS_TRUE(p->pWith) ){
    ++    sqlite3WithPush(pParse, p->pWith, 0);
    +   }
    + 
    +   /* Make sure cursor numbers have been assigned to all entries in
    +@@ -112881,8 +123050,12 @@ static int selectExpander(Walker *pWalker, Select *p){
    +       if( sqlite3WalkSelect(pWalker, pSel) ) return WRC_Abort;
    +       pFrom->pTab = pTab = sqlite3DbMallocZero(db, sizeof(Table));
    +       if( pTab==0 ) return WRC_Abort;
    +-      pTab->nRef = 1;
    +-      pTab->zName = sqlite3MPrintf(db, "sqlite_sq_%p", (void*)pTab);
    ++      pTab->nTabRef = 1;
    ++      if( pFrom->zAlias ){
    ++        pTab->zName = sqlite3DbStrDup(db, pFrom->zAlias);
    ++      }else{
    ++        pTab->zName = sqlite3MPrintf(db, "subquery_%p", (void*)pTab);
    ++      }
    +       while( pSel->pPrior ){ pSel = pSel->pPrior; }
    +       sqlite3ColumnsFromExprList(pParse, pSel->pEList,&pTab->nCol,&pTab->aCol);
    +       pTab->iPKey = -1;
    +@@ -112894,22 +123067,21 @@ static int selectExpander(Walker *pWalker, Select *p){
    +       assert( pFrom->pTab==0 );
    +       pFrom->pTab = pTab = sqlite3LocateTableItem(pParse, 0, pFrom);
    +       if( pTab==0 ) return WRC_Abort;
    +-      if( pTab->nRef==0xffff ){
    ++      if( pTab->nTabRef>=0xffff ){
    +         sqlite3ErrorMsg(pParse, "too many references to \"%s\": max 65535",
    +            pTab->zName);
    +         pFrom->pTab = 0;
    +         return WRC_Abort;
    +       }
    +-      pTab->nRef++;
    ++      pTab->nTabRef++;
    ++      if( !IsVirtual(pTab) && cannotBeFunction(pParse, pFrom) ){
    ++        return WRC_Abort;
    ++      }
    + #if !defined(SQLITE_OMIT_VIEW) || !defined (SQLITE_OMIT_VIRTUALTABLE)
    +-      if( pTab->pSelect || IsVirtual(pTab) ){
    ++      if( IsVirtual(pTab) || pTab->pSelect ){
    +         i16 nCol;
    +         if( sqlite3ViewGetColumnNames(pParse, pTab) ) return WRC_Abort;
    +         assert( pFrom->pSelect==0 );
    +-        if( pFrom->fg.isTabFunc && !IsVirtual(pTab) ){
    +-          sqlite3ErrorMsg(pParse, "'%s' is not a function", pTab->zName);
    +-          return WRC_Abort;
    +-        }
    +         pFrom->pSelect = sqlite3SelectDup(db, pTab->pSelect, 0);
    +         sqlite3SelectSetName(pFrom->pSelect, pTab->zName);
    +         nCol = pTab->nCol;
    +@@ -112935,19 +123107,21 @@ static int selectExpander(Walker *pWalker, Select *p){
    +   /* For every "*" that occurs in the column list, insert the names of
    +   ** all columns in all tables.  And for every TABLE.* insert the names
    +   ** of all columns in TABLE.  The parser inserted a special expression
    +-  ** with the TK_ALL operator for each "*" that it found in the column list.
    +-  ** The following code just has to locate the TK_ALL expressions and expand
    +-  ** each one to the list of all columns in all tables.
    ++  ** with the TK_ASTERISK operator for each "*" that it found in the column
    ++  ** list.  The following code just has to locate the TK_ASTERISK
    ++  ** expressions and expand each one to the list of all columns in
    ++  ** all tables.
    +   **
    +   ** The first loop just checks to see if there are any "*" operators
    +   ** that need expanding.
    +   */
    +   for(k=0; k<pEList->nExpr; k++){
    +     pE = pEList->a[k].pExpr;
    +-    if( pE->op==TK_ALL ) break;
    ++    if( pE->op==TK_ASTERISK ) break;
    +     assert( pE->op!=TK_DOT || pE->pRight!=0 );
    +     assert( pE->op!=TK_DOT || (pE->pLeft!=0 && pE->pLeft->op==TK_ID) );
    +-    if( pE->op==TK_DOT && pE->pRight->op==TK_ALL ) break;
    ++    if( pE->op==TK_DOT && pE->pRight->op==TK_ASTERISK ) break;
    ++    elistFlags |= pE->flags;
    +   }
    +   if( k<pEList->nExpr ){
    +     /*
    +@@ -112963,9 +123137,12 @@ static int selectExpander(Walker *pWalker, Select *p){
    + 
    +     for(k=0; k<pEList->nExpr; k++){
    +       pE = a[k].pExpr;
    ++      elistFlags |= pE->flags;
    +       pRight = pE->pRight;
    +       assert( pE->op!=TK_DOT || pRight!=0 );
    +-      if( pE->op!=TK_ALL && (pE->op!=TK_DOT || pRight->op!=TK_ALL) ){
    ++      if( pE->op!=TK_ASTERISK
    ++       && (pE->op!=TK_DOT || pRight->op!=TK_ASTERISK)
    ++      ){
    +         /* This particular expression does not need to be expanded.
    +         */
    +         pNew = sqlite3ExprListAppend(pParse, pNew, a[k].pExpr);
    +@@ -113002,7 +123179,7 @@ static int selectExpander(Walker *pWalker, Select *p){
    +               continue;
    +             }
    +             iDb = sqlite3SchemaToIndex(db, pTab->pSchema);
    +-            zSchemaName = iDb>=0 ? db->aDb[iDb].zName : "*";
    ++            zSchemaName = iDb>=0 ? db->aDb[iDb].zDbSName : "*";
    +           }
    +           for(j=0; j<pTab->nCol; j++){
    +             char *zName = pTab->aCol[j].zName;
    +@@ -113017,12 +123194,13 @@ static int selectExpander(Walker *pWalker, Select *p){
    +               continue;
    +             }
    + 
    +-            /* If a column is marked as 'hidden' (currently only possible
    +-            ** for virtual tables), do not include it in the expanded
    +-            ** result-set list.
    ++            /* If a column is marked as 'hidden', omit it from the expanded
    ++            ** result-set list unless the SELECT has the SF_IncludeHidden
    ++            ** bit set.
    +             */
    +-            if( IsHiddenColumn(&pTab->aCol[j]) ){
    +-              assert(IsVirtual(pTab));
    ++            if( (p->selFlags & SF_IncludeHidden)==0
    ++             && IsHiddenColumn(&pTab->aCol[j]) 
    ++            ){
    +               continue;
    +             }
    +             tableSeen = 1;
    +@@ -113047,10 +123225,10 @@ static int selectExpander(Walker *pWalker, Select *p){
    +             if( longNames || pTabList->nSrc>1 ){
    +               Expr *pLeft;
    +               pLeft = sqlite3Expr(db, TK_ID, zTabName);
    +-              pExpr = sqlite3PExpr(pParse, TK_DOT, pLeft, pRight, 0);
    ++              pExpr = sqlite3PExpr(pParse, TK_DOT, pLeft, pRight);
    +               if( zSchemaName ){
    +                 pLeft = sqlite3Expr(db, TK_ID, zSchemaName);
    +-                pExpr = sqlite3PExpr(pParse, TK_DOT, pLeft, pExpr, 0);
    ++                pExpr = sqlite3PExpr(pParse, TK_DOT, pLeft, pExpr);
    +               }
    +               if( longNames ){
    +                 zColname = sqlite3MPrintf(db, "%s.%s", zTabName, zName);
    +@@ -113060,8 +123238,7 @@ static int selectExpander(Walker *pWalker, Select *p){
    +               pExpr = pRight;
    +             }
    +             pNew = sqlite3ExprListAppend(pParse, pNew, pExpr);
    +-            sColname.z = zColname;
    +-            sColname.n = sqlite3Strlen30(zColname);
    ++            sqlite3TokenInit(&sColname, zColname);
    +             sqlite3ExprListSetName(pParse, pNew, &sColname, 0);
    +             if( pNew && (p->selFlags & SF_NestedFrom)!=0 ){
    +               struct ExprList_item *pX = &pNew->a[pNew->nExpr-1];
    +@@ -113090,11 +123267,15 @@ static int selectExpander(Walker *pWalker, Select *p){
    +     sqlite3ExprListDelete(db, pEList);
    +     p->pEList = pNew;
    +   }
    +-#if SQLITE_MAX_COLUMN
    +-  if( p->pEList && p->pEList->nExpr>db->aLimit[SQLITE_LIMIT_COLUMN] ){
    +-    sqlite3ErrorMsg(pParse, "too many columns in result set");
    ++  if( p->pEList ){
    ++    if( p->pEList->nExpr>db->aLimit[SQLITE_LIMIT_COLUMN] ){
    ++      sqlite3ErrorMsg(pParse, "too many columns in result set");
    ++      return WRC_Abort;
    ++    }
    ++    if( (elistFlags & (EP_HasFunc|EP_Subquery))!=0 ){
    ++      p->selFlags |= SF_ComplexResult;
    ++    }
    +   }
    +-#endif
    +   return WRC_Continue;
    + }
    + 
    +@@ -113107,11 +123288,30 @@ static int selectExpander(Walker *pWalker, Select *p){
    + ** Walker.xSelectCallback is set to do something useful for every 
    + ** subquery in the parser tree.
    + */
    +-static int exprWalkNoop(Walker *NotUsed, Expr *NotUsed2){
    ++SQLITE_PRIVATE int sqlite3ExprWalkNoop(Walker *NotUsed, Expr *NotUsed2){
    ++  UNUSED_PARAMETER2(NotUsed, NotUsed2);
    ++  return WRC_Continue;
    ++}
    ++
    ++/*
    ++** No-op routine for the parse-tree walker for SELECT statements.
    ++** subquery in the parser tree.
    ++*/
    ++SQLITE_PRIVATE int sqlite3SelectWalkNoop(Walker *NotUsed, Select *NotUsed2){
    +   UNUSED_PARAMETER2(NotUsed, NotUsed2);
    +   return WRC_Continue;
    + }
    + 
    ++#if SQLITE_DEBUG
    ++/*
    ++** Always assert.  This xSelectCallback2 implementation proves that the
    ++** xSelectCallback2 is never invoked.
    ++*/
    ++SQLITE_PRIVATE void sqlite3SelectWalkAssert2(Walker *NotUsed, Select *NotUsed2){
    ++  UNUSED_PARAMETER2(NotUsed, NotUsed2);
    ++  assert( 0 );
    ++}
    ++#endif
    + /*
    + ** This routine "expands" a SELECT statement and all of its subqueries.
    + ** For additional information on what it means to "expand" a SELECT
    +@@ -113127,17 +123327,15 @@ static int exprWalkNoop(Walker *NotUsed, Expr *NotUsed2){
    + */
    + static void sqlite3SelectExpand(Parse *pParse, Select *pSelect){
    +   Walker w;
    +-  memset(&w, 0, sizeof(w));
    +-  w.xExprCallback = exprWalkNoop;
    ++  w.xExprCallback = sqlite3ExprWalkNoop;
    +   w.pParse = pParse;
    +-  if( pParse->hasCompound ){
    ++  if( OK_IF_ALWAYS_TRUE(pParse->hasCompound) ){
    +     w.xSelectCallback = convertCompoundSelectToSubquery;
    ++    w.xSelectCallback2 = 0;
    +     sqlite3WalkSelect(&w, pSelect);
    +   }
    +   w.xSelectCallback = selectExpander;
    +-  if( (pSelect->selFlags & SF_MultiValue)==0 ){
    +-    w.xSelectCallback2 = selectPopWith;
    +-  }
    ++  w.xSelectCallback2 = selectPopWith;
    +   sqlite3WalkSelect(&w, pSelect);
    + }
    + 
    +@@ -113175,7 +123373,7 @@ static void selectAddSubqueryTypeInfo(Walker *pWalker, Select *p){
    +       Select *pSel = pFrom->pSelect;
    +       if( pSel ){
    +         while( pSel->pPrior ) pSel = pSel->pPrior;
    +-        selectAddColumnTypeAndCollation(pParse, pTab, pSel);
    ++        sqlite3SelectAddColumnTypeAndCollation(pParse, pTab, pSel);
    +       }
    +     }
    +   }
    +@@ -113193,9 +123391,9 @@ static void selectAddSubqueryTypeInfo(Walker *pWalker, Select *p){
    + static void sqlite3SelectAddTypeInfo(Parse *pParse, Select *pSelect){
    + #ifndef SQLITE_OMIT_SUBQUERY
    +   Walker w;
    +-  memset(&w, 0, sizeof(w));
    ++  w.xSelectCallback = sqlite3SelectWalkNoop;
    +   w.xSelectCallback2 = selectAddSubqueryTypeInfo;
    +-  w.xExprCallback = exprWalkNoop;
    ++  w.xExprCallback = sqlite3ExprWalkNoop;
    +   w.pParse = pParse;
    +   sqlite3WalkSelect(&w, pSelect);
    + #endif
    +@@ -113219,15 +123417,13 @@ SQLITE_PRIVATE void sqlite3SelectPrep(
    +   Select *p,             /* The SELECT statement being coded. */
    +   NameContext *pOuterNC  /* Name context for container */
    + ){
    +-  sqlite3 *db;
    +-  if( NEVER(p==0) ) return;
    +-  db = pParse->db;
    +-  if( db->mallocFailed ) return;
    ++  assert( p!=0 || pParse->db->mallocFailed );
    ++  if( pParse->db->mallocFailed ) return;
    +   if( p->selFlags & SF_HasTypeInfo ) return;
    +   sqlite3SelectExpand(pParse, p);
    +-  if( pParse->nErr || db->mallocFailed ) return;
    ++  if( pParse->nErr || pParse->db->mallocFailed ) return;
    +   sqlite3ResolveSelectNames(pParse, p, pOuterNC);
    +-  if( pParse->nErr || db->mallocFailed ) return;
    ++  if( pParse->nErr || pParse->db->mallocFailed ) return;
    +   sqlite3SelectAddTypeInfo(pParse, p);
    + }
    + 
    +@@ -113287,8 +123483,8 @@ static void finalizeAggFunctions(Parse *pParse, AggInfo *pAggInfo){
    +   for(i=0, pF=pAggInfo->aFunc; i<pAggInfo->nFunc; i++, pF++){
    +     ExprList *pList = pF->pExpr->x.pList;
    +     assert( !ExprHasProperty(pF->pExpr, EP_xIsSelect) );
    +-    sqlite3VdbeAddOp4(v, OP_AggFinal, pF->iMem, pList ? pList->nExpr : 0, 0,
    +-                      (void*)pF->pFunc, P4_FUNCDEF);
    ++    sqlite3VdbeAddOp2(v, OP_AggFinal, pF->iMem, pList ? pList->nExpr : 0);
    ++    sqlite3VdbeAppendP4(v, pF->pFunc, P4_FUNCDEF);
    +   }
    + }
    + 
    +@@ -113339,8 +123535,8 @@ static void updateAccumulator(Parse *pParse, AggInfo *pAggInfo){
    +       if( regHit==0 && pAggInfo->nAccumulator ) regHit = ++pParse->nMem;
    +       sqlite3VdbeAddOp4(v, OP_CollSeq, regHit, 0, 0, (char *)pColl, P4_COLLSEQ);
    +     }
    +-    sqlite3VdbeAddOp4(v, OP_AggStep0, 0, regAgg, pF->iMem,
    +-                      (void*)pF->pFunc, P4_FUNCDEF);
    ++    sqlite3VdbeAddOp3(v, OP_AggStep0, 0, regAgg, pF->iMem);
    ++    sqlite3VdbeAppendP4(v, pF->pFunc, P4_FUNCDEF);
    +     sqlite3VdbeChangeP5(v, (u8)nArg);
    +     sqlite3ExprCacheAffinityChange(pParse, regAgg, nArg);
    +     sqlite3ReleaseTempRange(pParse, regAgg, nArg);
    +@@ -113400,6 +123596,187 @@ static void explainSimpleCount(
    + # define explainSimpleCount(a,b,c)
    + #endif
    + 
    ++/*
    ++** Context object for havingToWhereExprCb().
    ++*/
    ++struct HavingToWhereCtx {
    ++  Expr **ppWhere;
    ++  ExprList *pGroupBy;
    ++};
    ++
    ++/*
    ++** sqlite3WalkExpr() callback used by havingToWhere().
    ++**
    ++** If the node passed to the callback is a TK_AND node, return 
    ++** WRC_Continue to tell sqlite3WalkExpr() to iterate through child nodes.
    ++**
    ++** Otherwise, return WRC_Prune. In this case, also check if the 
    ++** sub-expression matches the criteria for being moved to the WHERE
    ++** clause. If so, add it to the WHERE clause and replace the sub-expression
    ++** within the HAVING expression with a constant "1".
    ++*/
    ++static int havingToWhereExprCb(Walker *pWalker, Expr *pExpr){
    ++  if( pExpr->op!=TK_AND ){
    ++    struct HavingToWhereCtx *p = pWalker->u.pHavingCtx;
    ++    if( sqlite3ExprIsConstantOrGroupBy(pWalker->pParse, pExpr, p->pGroupBy) ){
    ++      sqlite3 *db = pWalker->pParse->db;
    ++      Expr *pNew = sqlite3ExprAlloc(db, TK_INTEGER, &sqlite3IntTokens[1], 0);
    ++      if( pNew ){
    ++        Expr *pWhere = *(p->ppWhere);
    ++        SWAP(Expr, *pNew, *pExpr);
    ++        pNew = sqlite3ExprAnd(db, pWhere, pNew);
    ++        *(p->ppWhere) = pNew;
    ++      }
    ++    }
    ++    return WRC_Prune;
    ++  }
    ++  return WRC_Continue;
    ++}
    ++
    ++/*
    ++** Transfer eligible terms from the HAVING clause of a query, which is
    ++** processed after grouping, to the WHERE clause, which is processed before
    ++** grouping. For example, the query:
    ++**
    ++**   SELECT * FROM <tables> WHERE a=? GROUP BY b HAVING b=? AND c=?
    ++**
    ++** can be rewritten as:
    ++**
    ++**   SELECT * FROM <tables> WHERE a=? AND b=? GROUP BY b HAVING c=?
    ++**
    ++** A term of the HAVING expression is eligible for transfer if it consists
    ++** entirely of constants and expressions that are also GROUP BY terms that
    ++** use the "BINARY" collation sequence.
    ++*/
    ++static void havingToWhere(
    ++  Parse *pParse,
    ++  ExprList *pGroupBy,
    ++  Expr *pHaving, 
    ++  Expr **ppWhere
    ++){
    ++  struct HavingToWhereCtx sCtx;
    ++  Walker sWalker;
    ++
    ++  sCtx.ppWhere = ppWhere;
    ++  sCtx.pGroupBy = pGroupBy;
    ++
    ++  memset(&sWalker, 0, sizeof(sWalker));
    ++  sWalker.pParse = pParse;
    ++  sWalker.xExprCallback = havingToWhereExprCb;
    ++  sWalker.u.pHavingCtx = &sCtx;
    ++  sqlite3WalkExpr(&sWalker, pHaving);
    ++}
    ++
    ++/*
    ++** Check to see if the pThis entry of pTabList is a self-join of a prior view.
    ++** If it is, then return the SrcList_item for the prior view.  If it is not,
    ++** then return 0.
    ++*/
    ++static struct SrcList_item *isSelfJoinView(
    ++  SrcList *pTabList,           /* Search for self-joins in this FROM clause */
    ++  struct SrcList_item *pThis   /* Search for prior reference to this subquery */
    ++){
    ++  struct SrcList_item *pItem;
    ++  for(pItem = pTabList->a; pItem<pThis; pItem++){
    ++    if( pItem->pSelect==0 ) continue;
    ++    if( pItem->fg.viaCoroutine ) continue;
    ++    if( pItem->zName==0 ) continue;
    ++    if( sqlite3_stricmp(pItem->zDatabase, pThis->zDatabase)!=0 ) continue;
    ++    if( sqlite3_stricmp(pItem->zName, pThis->zName)!=0 ) continue;
    ++    if( sqlite3ExprCompare(0, 
    ++          pThis->pSelect->pWhere, pItem->pSelect->pWhere, -1) 
    ++    ){
    ++      /* The view was modified by some other optimization such as
    ++      ** pushDownWhereTerms() */
    ++      continue;
    ++    }
    ++    return pItem;
    ++  }
    ++  return 0;
    ++}
    ++
    ++#ifdef SQLITE_COUNTOFVIEW_OPTIMIZATION
    ++/*
    ++** Attempt to transform a query of the form
    ++**
    ++**    SELECT count(*) FROM (SELECT x FROM t1 UNION ALL SELECT y FROM t2)
    ++**
    ++** Into this:
    ++**
    ++**    SELECT (SELECT count(*) FROM t1)+(SELECT count(*) FROM t2)
    ++**
    ++** The transformation only works if all of the following are true:
    ++**
    ++**   *  The subquery is a UNION ALL of two or more terms
    ++**   *  There is no WHERE or GROUP BY or HAVING clauses on the subqueries
    ++**   *  The outer query is a simple count(*)
    ++**
    ++** Return TRUE if the optimization is undertaken.
    ++*/
    ++static int countOfViewOptimization(Parse *pParse, Select *p){
    ++  Select *pSub, *pPrior;
    ++  Expr *pExpr;
    ++  Expr *pCount;
    ++  sqlite3 *db;
    ++  if( (p->selFlags & SF_Aggregate)==0 ) return 0;   /* This is an aggregate */
    ++  if( p->pEList->nExpr!=1 ) return 0;               /* Single result column */
    ++  pExpr = p->pEList->a[0].pExpr;
    ++  if( pExpr->op!=TK_AGG_FUNCTION ) return 0;        /* Result is an aggregate */
    ++  if( sqlite3_stricmp(pExpr->u.zToken,"count") ) return 0;  /* Is count() */
    ++  if( pExpr->x.pList!=0 ) return 0;                 /* Must be count(*) */
    ++  if( p->pSrc->nSrc!=1 ) return 0;                  /* One table in FROM  */
    ++  pSub = p->pSrc->a[0].pSelect;
    ++  if( pSub==0 ) return 0;                           /* The FROM is a subquery */
    ++  if( pSub->pPrior==0 ) return 0;                   /* Must be a compound ry */
    ++  do{
    ++    if( pSub->op!=TK_ALL && pSub->pPrior ) return 0;  /* Must be UNION ALL */
    ++    if( pSub->pWhere ) return 0;                      /* No WHERE clause */
    ++    if( pSub->selFlags & SF_Aggregate ) return 0;     /* Not an aggregate */
    ++    pSub = pSub->pPrior;                              /* Repeat over compound */
    ++  }while( pSub );
    ++
    ++  /* If we reach this point then it is OK to perform the transformation */
    ++
    ++  db = pParse->db;
    ++  pCount = pExpr;
    ++  pExpr = 0;
    ++  pSub = p->pSrc->a[0].pSelect;
    ++  p->pSrc->a[0].pSelect = 0;
    ++  sqlite3SrcListDelete(db, p->pSrc);
    ++  p->pSrc = sqlite3DbMallocZero(pParse->db, sizeof(*p->pSrc));
    ++  while( pSub ){
    ++    Expr *pTerm;
    ++    pPrior = pSub->pPrior;
    ++    pSub->pPrior = 0;
    ++    pSub->pNext = 0;
    ++    pSub->selFlags |= SF_Aggregate;
    ++    pSub->selFlags &= ~SF_Compound;
    ++    pSub->nSelectRow = 0;
    ++    sqlite3ExprListDelete(db, pSub->pEList);
    ++    pTerm = pPrior ? sqlite3ExprDup(db, pCount, 0) : pCount;
    ++    pSub->pEList = sqlite3ExprListAppend(pParse, 0, pTerm);
    ++    pTerm = sqlite3PExpr(pParse, TK_SELECT, 0, 0);
    ++    sqlite3PExprAddSelect(pParse, pTerm, pSub);
    ++    if( pExpr==0 ){
    ++      pExpr = pTerm;
    ++    }else{
    ++      pExpr = sqlite3PExpr(pParse, TK_PLUS, pTerm, pExpr);
    ++    }
    ++    pSub = pPrior;
    ++  }
    ++  p->pEList->a[0].pExpr = pExpr;
    ++  p->selFlags &= ~SF_Aggregate;
    ++
    ++#if SELECTTRACE_ENABLED
    ++  if( sqlite3SelectTrace & 0x400 ){
    ++    SELECTTRACE(0x400,pParse,p,("After count-of-view optimization:\n"));
    ++    sqlite3TreeViewSelect(0, p, 0);
    ++  }
    ++#endif
    ++  return 1;
    ++}
    ++#endif /* SQLITE_COUNTOFVIEW_OPTIMIZATION */
    ++
    + /*
    + ** Generate code for the SELECT statement given in the p argument.  
    + **
    +@@ -113433,6 +123810,8 @@ SQLITE_PRIVATE int sqlite3Select(
    +   AggInfo sAggInfo;      /* Information used by aggregate queries */
    +   int iEnd;              /* Address of the end of the query */
    +   sqlite3 *db;           /* The database connection */
    ++  ExprList *pMinMaxOrderBy = 0;  /* Added ORDER BY for min/max queries */
    ++  u8 minMaxFlag;                 /* Flag for min/max queries */
    + 
    + #ifndef SQLITE_OMIT_EXPLAIN
    +   int iRestoreSelectId = pParse->iSelectId;
    +@@ -113484,15 +123863,13 @@ SQLITE_PRIVATE int sqlite3Select(
    +   }
    + #endif
    + 
    +-
    +-  /* If writing to memory or generating a set
    +-  ** only a single column may be output.
    +-  */
    +-#ifndef SQLITE_OMIT_SUBQUERY
    +-  if( checkForMultiColumnSelectError(pParse, pDest, p->pEList->nExpr) ){
    +-    goto select_end;
    ++  /* Get a pointer the VDBE under construction, allocating a new VDBE if one
    ++  ** does not already exist */
    ++  v = sqlite3GetVdbe(pParse);
    ++  if( v==0 ) goto select_end;
    ++  if( pDest->eDest==SRT_Output ){
    ++    generateColumnNames(pParse, p);
    +   }
    +-#endif
    + 
    +   /* Try to flatten subqueries in the FROM clause up into the main query
    +   */
    +@@ -113500,7 +123877,6 @@ SQLITE_PRIVATE int sqlite3Select(
    +   for(i=0; !p->pPrior && i<pTabList->nSrc; i++){
    +     struct SrcList_item *pItem = &pTabList->a[i];
    +     Select *pSub = pItem->pSelect;
    +-    int isAggSub;
    +     Table *pTab = pItem->pTab;
    +     if( pSub==0 ) continue;
    + 
    +@@ -113512,13 +123888,45 @@ SQLITE_PRIVATE int sqlite3Select(
    +       goto select_end;
    +     }
    + 
    +-    isAggSub = (pSub->selFlags & SF_Aggregate)!=0;
    +-    if( flattenSubquery(pParse, p, i, isAgg, isAggSub) ){
    ++    /* Do not try to flatten an aggregate subquery.
    ++    **
    ++    ** Flattening an aggregate subquery is only possible if the outer query
    ++    ** is not a join.  But if the outer query is not a join, then the subquery
    ++    ** will be implemented as a co-routine and there is no advantage to
    ++    ** flattening in that case.
    ++    */
    ++    if( (pSub->selFlags & SF_Aggregate)!=0 ) continue;
    ++    assert( pSub->pGroupBy==0 );
    ++
    ++    /* If the outer query contains a "complex" result set (that is,
    ++    ** if the result set of the outer query uses functions or subqueries)
    ++    ** and if the subquery contains an ORDER BY clause and if
    ++    ** it will be implemented as a co-routine, then do not flatten.  This
    ++    ** restriction allows SQL constructs like this:
    ++    **
    ++    **  SELECT expensive_function(x)
    ++    **    FROM (SELECT x FROM tab ORDER BY y LIMIT 10);
    ++    **
    ++    ** The expensive_function() is only computed on the 10 rows that
    ++    ** are output, rather than every row of the table.
    ++    **
    ++    ** The requirement that the outer query have a complex result set
    ++    ** means that flattening does occur on simpler SQL constraints without
    ++    ** the expensive_function() like:
    ++    **
    ++    **  SELECT x FROM (SELECT x FROM tab ORDER BY y LIMIT 10);
    ++    */
    ++    if( pSub->pOrderBy!=0
    ++     && i==0
    ++     && (p->selFlags & SF_ComplexResult)!=0
    ++     && (pTabList->nSrc==1
    ++         || (pTabList->a[1].fg.jointype&(JT_LEFT|JT_CROSS))!=0)
    ++    ){
    ++      continue;
    ++    }
    ++
    ++    if( flattenSubquery(pParse, p, i, isAgg) ){
    +       /* This subquery can be absorbed into its parent. */
    +-      if( isAggSub ){
    +-        isAgg = 1;
    +-        p->selFlags |= SF_Aggregate;
    +-      }
    +       i = -1;
    +     }
    +     pTabList = p->pSrc;
    +@@ -113529,11 +123937,6 @@ SQLITE_PRIVATE int sqlite3Select(
    +   }
    + #endif
    + 
    +-  /* Get a pointer the VDBE under construction, allocating a new VDBE if one
    +-  ** does not already exist */
    +-  v = sqlite3GetVdbe(pParse);
    +-  if( v==0 ) goto select_end;
    +-
    + #ifndef SQLITE_OMIT_COMPOUND_SELECT
    +   /* Handle compound SELECT statements using the separate multiSelect()
    +   ** procedure.
    +@@ -113549,13 +123952,42 @@ SQLITE_PRIVATE int sqlite3Select(
    +   }
    + #endif
    + 
    +-  /* Generate code for all sub-queries in the FROM clause
    ++  /* For each term in the FROM clause, do two things:
    ++  ** (1) Authorized unreferenced tables
    ++  ** (2) Generate code for all sub-queries
    +   */
    +-#if !defined(SQLITE_OMIT_SUBQUERY) || !defined(SQLITE_OMIT_VIEW)
    +   for(i=0; i<pTabList->nSrc; i++){
    +     struct SrcList_item *pItem = &pTabList->a[i];
    +     SelectDest dest;
    +-    Select *pSub = pItem->pSelect;
    ++    Select *pSub;
    ++#if !defined(SQLITE_OMIT_SUBQUERY) || !defined(SQLITE_OMIT_VIEW)
    ++    const char *zSavedAuthContext;
    ++#endif
    ++
    ++    /* Issue SQLITE_READ authorizations with a fake column name for any
    ++    ** tables that are referenced but from which no values are extracted.
    ++    ** Examples of where these kinds of null SQLITE_READ authorizations
    ++    ** would occur:
    ++    **
    ++    **     SELECT count(*) FROM t1;   -- SQLITE_READ t1.""
    ++    **     SELECT t1.* FROM t1, t2;   -- SQLITE_READ t2.""
    ++    **
    ++    ** The fake column name is an empty string.  It is possible for a table to
    ++    ** have a column named by the empty string, in which case there is no way to
    ++    ** distinguish between an unreferenced table and an actual reference to the
    ++    ** "" column. The original design was for the fake column name to be a NULL,
    ++    ** which would be unambiguous.  But legacy authorization callbacks might
    ++    ** assume the column name is non-NULL and segfault.  The use of an empty
    ++    ** string for the fake column name seems safer.
    ++    */
    ++    if( pItem->colUsed==0 ){
    ++      sqlite3AuthCheck(pParse, SQLITE_READ, pItem->zName, "", pItem->zDatabase);
    ++    }
    ++
    ++#if !defined(SQLITE_OMIT_SUBQUERY) || !defined(SQLITE_OMIT_VIEW)
    ++    /* Generate code for all sub-queries in the FROM clause
    ++    */
    ++    pSub = pItem->pSelect;
    +     if( pSub==0 ) continue;
    + 
    +     /* Sometimes the code for a subquery will be generated more than
    +@@ -113566,6 +123998,10 @@ SQLITE_PRIVATE int sqlite3Select(
    +     ** to be invoked again. */
    +     if( pItem->addrFillSub ){
    +       if( pItem->fg.viaCoroutine==0 ){
    ++        /* The subroutine that manifests the view might be a one-time routine,
    ++        ** or it might need to be rerun on each iteration because it
    ++        ** encodes a correlated subquery. */
    ++        testcase( sqlite3VdbeGetOp(v, pItem->addrFillSub)->opcode==OP_Once );
    +         sqlite3VdbeAddOp2(v, OP_Gosub, pItem->regReturn, pItem->addrFillSub);
    +       }
    +       continue;
    +@@ -113584,7 +124020,7 @@ SQLITE_PRIVATE int sqlite3Select(
    +     ** inside the subquery.  This can help the subquery to run more efficiently.
    +     */
    +     if( (pItem->fg.jointype & JT_OUTER)==0
    +-     && pushDownWhereTerms(db, pSub, p->pWhere, pItem->iCursor)
    ++     && pushDownWhereTerms(pParse, pSub, p->pWhere, pItem->iCursor)
    +     ){
    + #if SELECTTRACE_ENABLED
    +       if( sqlite3SelectTrace & 0x100 ){
    +@@ -113594,16 +124030,27 @@ SQLITE_PRIVATE int sqlite3Select(
    + #endif
    +     }
    + 
    ++    zSavedAuthContext = pParse->zAuthContext;
    ++    pParse->zAuthContext = pItem->zName;
    ++
    +     /* Generate code to implement the subquery
    ++    **
    ++    ** The subquery is implemented as a co-routine if the subquery is
    ++    ** guaranteed to be the outer loop (so that it does not need to be
    ++    ** computed more than once)
    ++    **
    ++    ** TODO: Are there other reasons beside (1) to use a co-routine
    ++    ** implementation?
    +     */
    +-    if( pTabList->nSrc==1
    +-     && (p->selFlags & SF_All)==0
    +-     && OptimizationEnabled(db, SQLITE_SubqCoroutine)
    ++    if( i==0
    ++     && (pTabList->nSrc==1
    ++            || (pTabList->a[1].fg.jointype&(JT_LEFT|JT_CROSS))!=0)  /* (1) */
    +     ){
    +       /* Implement a co-routine that will return a single row of the result
    +       ** set on each invocation.
    +       */
    +       int addrTop = sqlite3VdbeCurrentAddr(v)+1;
    ++     
    +       pItem->regReturn = ++pParse->nMem;
    +       sqlite3VdbeAddOp3(v, OP_InitCoroutine, pItem->regReturn, 0, addrTop);
    +       VdbeComment((v, "%s", pItem->pTab->zName));
    +@@ -113611,10 +124058,10 @@ SQLITE_PRIVATE int sqlite3Select(
    +       sqlite3SelectDestInit(&dest, SRT_Coroutine, pItem->regReturn);
    +       explainSetInteger(pItem->iSelectId, (u8)pParse->iNextSelectId);
    +       sqlite3Select(pParse, pSub, &dest);
    +-      pItem->pTab->nRowLogEst = sqlite3LogEst(pSub->nSelectRow);
    ++      pItem->pTab->nRowLogEst = pSub->nSelectRow;
    +       pItem->fg.viaCoroutine = 1;
    +       pItem->regResult = dest.iSdst;
    +-      sqlite3VdbeAddOp1(v, OP_EndCoroutine, pItem->regReturn);
    ++      sqlite3VdbeEndCoroutine(v, pItem->regReturn);
    +       sqlite3VdbeJumpHere(v, addrTop-1);
    +       sqlite3ClearTempRegCache(pParse);
    +     }else{
    +@@ -113626,6 +124073,8 @@ SQLITE_PRIVATE int sqlite3Select(
    +       int topAddr;
    +       int onceAddr = 0;
    +       int retAddr;
    ++      struct SrcList_item *pPrior;
    ++
    +       assert( pItem->addrFillSub==0 );
    +       pItem->regReturn = ++pParse->nMem;
    +       topAddr = sqlite3VdbeAddOp2(v, OP_Integer, 0, pItem->regReturn);
    +@@ -113634,15 +124083,23 @@ SQLITE_PRIVATE int sqlite3Select(
    +         /* If the subquery is not correlated and if we are not inside of
    +         ** a trigger, then we only need to compute the value of the subquery
    +         ** once. */
    +-        onceAddr = sqlite3CodeOnce(pParse); VdbeCoverage(v);
    ++        onceAddr = sqlite3VdbeAddOp0(v, OP_Once); VdbeCoverage(v);
    +         VdbeComment((v, "materialize \"%s\"", pItem->pTab->zName));
    +       }else{
    +         VdbeNoopComment((v, "materialize \"%s\"", pItem->pTab->zName));
    +       }
    +-      sqlite3SelectDestInit(&dest, SRT_EphemTab, pItem->iCursor);
    +-      explainSetInteger(pItem->iSelectId, (u8)pParse->iNextSelectId);
    +-      sqlite3Select(pParse, pSub, &dest);
    +-      pItem->pTab->nRowLogEst = sqlite3LogEst(pSub->nSelectRow);
    ++      pPrior = isSelfJoinView(pTabList, pItem);
    ++      if( pPrior ){
    ++        sqlite3VdbeAddOp2(v, OP_OpenDup, pItem->iCursor, pPrior->iCursor);
    ++        explainSetInteger(pItem->iSelectId, pPrior->iSelectId);
    ++        assert( pPrior->pSelect!=0 );
    ++        pSub->nSelectRow = pPrior->pSelect->nSelectRow;
    ++      }else{
    ++        sqlite3SelectDestInit(&dest, SRT_EphemTab, pItem->iCursor);
    ++        explainSetInteger(pItem->iSelectId, (u8)pParse->iNextSelectId);
    ++        sqlite3Select(pParse, pSub, &dest);
    ++      }
    ++      pItem->pTab->nRowLogEst = pSub->nSelectRow;
    +       if( onceAddr ) sqlite3VdbeJumpHere(v, onceAddr);
    +       retAddr = sqlite3VdbeAddOp1(v, OP_Return, pItem->regReturn);
    +       VdbeComment((v, "end %s", pItem->pTab->zName));
    +@@ -113651,8 +124108,9 @@ SQLITE_PRIVATE int sqlite3Select(
    +     }
    +     if( db->mallocFailed ) goto select_end;
    +     pParse->nHeight -= sqlite3SelectExprHeight(p);
    +-  }
    ++    pParse->zAuthContext = zSavedAuthContext;
    + #endif
    ++  }
    + 
    +   /* Various elements of the SELECT copied into local variables for
    +   ** convenience */
    +@@ -113669,6 +124127,16 @@ SQLITE_PRIVATE int sqlite3Select(
    +   }
    + #endif
    + 
    ++#ifdef SQLITE_COUNTOFVIEW_OPTIMIZATION
    ++  if( OptimizationEnabled(db, SQLITE_QueryFlattener|SQLITE_CountOfView)
    ++   && countOfViewOptimization(pParse, p)
    ++  ){
    ++    if( db->mallocFailed ) goto select_end;
    ++    pEList = p->pEList;
    ++    pTabList = p->pSrc;
    ++  }
    ++#endif
    ++
    +   /* 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:
    +@@ -113693,6 +124161,13 @@ SQLITE_PRIVATE int sqlite3Select(
    +     ** the sDistinct.isTnct is still set.  Hence, isTnct represents the
    +     ** original setting of the SF_Distinct flag, not the current setting */
    +     assert( sDistinct.isTnct );
    ++
    ++#if SELECTTRACE_ENABLED
    ++    if( sqlite3SelectTrace & 0x400 ){
    ++      SELECTTRACE(0x400,pParse,p,("Transform DISTINCT into GROUP BY:\n"));
    ++      sqlite3TreeViewSelect(0, p, 0);
    ++    }
    ++#endif
    +   }
    + 
    +   /* If there is an ORDER BY clause, then create an ephemeral index to
    +@@ -113725,7 +124200,9 @@ SQLITE_PRIVATE int sqlite3Select(
    +   /* Set the limiter.
    +   */
    +   iEnd = sqlite3VdbeMakeLabel(v);
    +-  p->nSelectRow = LARGEST_INT64;
    ++  if( (p->selFlags & SF_FixedLimit)==0 ){
    ++    p->nSelectRow = 320;  /* 4 billion rows */
    ++  }
    +   computeLimitRegisters(pParse, p, iEnd);
    +   if( p->iLimit==0 && sSort.addrSortIndex>=0 ){
    +     sqlite3VdbeChangeOpcode(v, sSort.addrSortIndex, OP_SorterOpen);
    +@@ -113749,10 +124226,12 @@ SQLITE_PRIVATE int sqlite3Select(
    +   if( !isAgg && pGroupBy==0 ){
    +     /* No aggregate functions and no GROUP BY clause */
    +     u16 wctrlFlags = (sDistinct.isTnct ? WHERE_WANT_DISTINCT : 0);
    ++    assert( WHERE_USE_LIMIT==SF_FixedLimit );
    ++    wctrlFlags |= p->selFlags & SF_FixedLimit;
    + 
    +     /* Begin the database scan. */
    +     pWInfo = sqlite3WhereBegin(pParse, pTabList, pWhere, sSort.pOrderBy,
    +-                               p->pEList, wctrlFlags, 0);
    ++                               p->pEList, wctrlFlags, p->nSelectRow);
    +     if( pWInfo==0 ) goto select_end;
    +     if( sqlite3WhereOutputRowCount(pWInfo) < p->nSelectRow ){
    +       p->nSelectRow = sqlite3WhereOutputRowCount(pWInfo);
    +@@ -113762,6 +124241,7 @@ SQLITE_PRIVATE int sqlite3Select(
    +     }
    +     if( sSort.pOrderBy ){
    +       sSort.nOBSat = sqlite3WhereIsOrdered(pWInfo);
    ++      sSort.bOrderedInnerLoop = sqlite3WhereOrderedInnerLoop(pWInfo);
    +       if( sSort.nOBSat==sSort.pOrderBy->nExpr ){
    +         sSort.pOrderBy = 0;
    +       }
    +@@ -113776,7 +124256,8 @@ SQLITE_PRIVATE int sqlite3Select(
    +     }
    + 
    +     /* Use the standard inner loop. */
    +-    selectInnerLoop(pParse, p, pEList, -1, &sSort, &sDistinct, pDest,
    ++    assert( p->pEList==pEList );
    ++    selectInnerLoop(pParse, p, -1, &sSort, &sDistinct, pDest,
    +                     sqlite3WhereContinueLabel(pWInfo),
    +                     sqlite3WhereBreakLabel(pWInfo));
    + 
    +@@ -113812,9 +124293,11 @@ SQLITE_PRIVATE int sqlite3Select(
    +       for(k=pGroupBy->nExpr, pItem=pGroupBy->a; k>0; k--, pItem++){
    +         pItem->u.x.iAlias = 0;
    +       }
    +-      if( p->nSelectRow>100 ) p->nSelectRow = 100;
    ++      assert( 66==sqlite3LogEst(100) );
    ++      if( p->nSelectRow>66 ) p->nSelectRow = 66;
    +     }else{
    +-      p->nSelectRow = 1;
    ++      assert( 0==sqlite3LogEst(1) );
    ++      p->nSelectRow = 0;
    +     }
    + 
    +     /* If there is both a GROUP BY and an ORDER BY clause and they are
    +@@ -113846,9 +124329,19 @@ SQLITE_PRIVATE int sqlite3Select(
    +     sqlite3ExprAnalyzeAggList(&sNC, pEList);
    +     sqlite3ExprAnalyzeAggList(&sNC, sSort.pOrderBy);
    +     if( pHaving ){
    ++      if( pGroupBy ){
    ++        assert( pWhere==p->pWhere );
    ++        havingToWhere(pParse, pGroupBy, pHaving, &p->pWhere);
    ++        pWhere = p->pWhere;
    ++      }
    +       sqlite3ExprAnalyzeAggregates(&sNC, pHaving);
    +     }
    +     sAggInfo.nAccumulator = sAggInfo.nColumn;
    ++    if( p->pGroupBy==0 && p->pHaving==0 && sAggInfo.nFunc==1 ){
    ++      minMaxFlag = minMaxQuery(db, sAggInfo.aFunc[0].pExpr, &pMinMaxOrderBy);
    ++    }else{
    ++      minMaxFlag = WHERE_ORDERBY_NORMAL;
    ++    }
    +     for(i=0; i<sAggInfo.nFunc; i++){
    +       assert( !ExprHasProperty(sAggInfo.aFunc[i].pExpr, EP_xIsSelect) );
    +       sNC.ncFlags |= NC_InAggFunc;
    +@@ -113857,6 +124350,24 @@ SQLITE_PRIVATE int sqlite3Select(
    +     }
    +     sAggInfo.mxReg = pParse->nMem;
    +     if( db->mallocFailed ) goto select_end;
    ++#if SELECTTRACE_ENABLED
    ++    if( sqlite3SelectTrace & 0x400 ){
    ++      int ii;
    ++      SELECTTRACE(0x400,pParse,p,("After aggregate analysis:\n"));
    ++      sqlite3TreeViewSelect(0, p, 0);
    ++      for(ii=0; ii<sAggInfo.nColumn; ii++){
    ++        sqlite3DebugPrintf("agg-column[%d] iMem=%d\n",
    ++            ii, sAggInfo.aCol[ii].iMem);
    ++        sqlite3TreeViewExpr(0, sAggInfo.aCol[ii].pExpr, 0);
    ++      }
    ++      for(ii=0; ii<sAggInfo.nFunc; ii++){
    ++        sqlite3DebugPrintf("agg-func[%d]: iMem=%d\n",
    ++            ii, sAggInfo.aFunc[ii].iMem);
    ++        sqlite3TreeViewExpr(0, sAggInfo.aFunc[ii].pExpr, 0);
    ++      }
    ++    }
    ++#endif
    ++
    + 
    +     /* Processing for aggregates with GROUP BY is very different and
    +     ** much more complex than aggregates without a GROUP BY.
    +@@ -113950,13 +124461,8 @@ SQLITE_PRIVATE int sqlite3Select(
    +           struct AggInfo_col *pCol = &sAggInfo.aCol[i];
    +           if( pCol->iSorterColumn>=j ){
    +             int r1 = j + regBase;
    +-            int r2;
    +-
    +-            r2 = sqlite3ExprCodeGetColumn(pParse, 
    +-                               pCol->pTab, pCol->iColumn, pCol->iTable, r1, 0);
    +-            if( r1!=r2 ){
    +-              sqlite3VdbeAddOp2(v, OP_SCopy, r2, r1);
    +-            }
    ++            sqlite3ExprCodeGetColumnToReg(pParse, 
    ++                               pCol->pTab, pCol->iColumn, pCol->iTable, r1);
    +             j++;
    +           }
    +         }
    +@@ -114077,7 +124583,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, &sSort,
    ++      selectInnerLoop(pParse, p, -1, &sSort,
    +                       &sDistinct, pDest,
    +                       addrOutputRow+1, addrSetAbort);
    +       sqlite3VdbeAddOp1(v, OP_Return, regOutputRow);
    +@@ -114091,7 +124597,6 @@ SQLITE_PRIVATE int sqlite3Select(
    +      
    +     } /* endif pGroupBy.  Begin aggregate queries without GROUP BY: */
    +     else {
    +-      ExprList *pDel = 0;
    + #ifndef SQLITE_OMIT_BTREECOUNT
    +       Table *pTab;
    +       if( (pTab = isSimpleCount(p, &sAggInfo))!=0 ){
    +@@ -114153,66 +124658,31 @@ SQLITE_PRIVATE int sqlite3Select(
    +       }else
    + #endif /* SQLITE_OMIT_BTREECOUNT */
    +       {
    +-        /* Check if the query is of one of the following forms:
    +-        **
    +-        **   SELECT min(x) FROM ...
    +-        **   SELECT max(x) FROM ...
    +-        **
    +-        ** If it is, then ask the code in where.c to attempt to sort results
    +-        ** as if there was an "ORDER ON x" or "ORDER ON x DESC" clause. 
    +-        ** If where.c is able to produce results sorted in this order, then
    +-        ** add vdbe code to break out of the processing loop after the 
    +-        ** first iteration (since the first iteration of the loop is 
    +-        ** guaranteed to operate on the row with the minimum or maximum 
    +-        ** value of x, the only row required).
    +-        **
    +-        ** A special flag must be passed to sqlite3WhereBegin() to slightly
    +-        ** modify behavior as follows:
    +-        **
    +-        **   + If the query is a "SELECT min(x)", then the loop coded by
    +-        **     where.c should not iterate over any values with a NULL value
    +-        **     for x.
    +-        **
    +-        **   + The optimizer code in where.c (the thing that decides which
    +-        **     index or indices to use) should place a different priority on 
    +-        **     satisfying the 'ORDER BY' clause than it does in other cases.
    +-        **     Refer to code and comments in where.c for details.
    +-        */
    +-        ExprList *pMinMax = 0;
    +-        u8 flag = WHERE_ORDERBY_NORMAL;
    +-        
    +-        assert( p->pGroupBy==0 );
    +-        assert( flag==0 );
    +-        if( p->pHaving==0 ){
    +-          flag = minMaxQuery(&sAggInfo, &pMinMax);
    +-        }
    +-        assert( flag==0 || (pMinMax!=0 && pMinMax->nExpr==1) );
    +-
    +-        if( flag ){
    +-          pMinMax = sqlite3ExprListDup(db, pMinMax, 0);
    +-          pDel = pMinMax;
    +-          if( pMinMax && !db->mallocFailed ){
    +-            pMinMax->a[0].sortOrder = flag!=WHERE_ORDERBY_MIN ?1:0;
    +-            pMinMax->a[0].pExpr->op = TK_COLUMN;
    +-          }
    +-        }
    +-  
    +         /* This case runs if the aggregate has no GROUP BY clause.  The
    +         ** processing is much simpler since there is only a single row
    +         ** of output.
    +         */
    ++        assert( p->pGroupBy==0 );
    +         resetAccumulator(pParse, &sAggInfo);
    +-        pWInfo = sqlite3WhereBegin(pParse, pTabList, pWhere, pMinMax,0,flag,0);
    ++
    ++        /* If this query is a candidate for the min/max optimization, then
    ++        ** minMaxFlag will have been previously set to either
    ++        ** WHERE_ORDERBY_MIN or WHERE_ORDERBY_MAX and pMinMaxOrderBy will
    ++        ** be an appropriate ORDER BY expression for the optimization.
    ++        */
    ++        assert( minMaxFlag==WHERE_ORDERBY_NORMAL || pMinMaxOrderBy!=0 );
    ++        assert( pMinMaxOrderBy==0 || pMinMaxOrderBy->nExpr==1 );
    ++
    ++        pWInfo = sqlite3WhereBegin(pParse, pTabList, pWhere, pMinMaxOrderBy,
    ++                                   0, minMaxFlag, 0);
    +         if( pWInfo==0 ){
    +-          sqlite3ExprListDelete(db, pDel);
    +           goto select_end;
    +         }
    +         updateAccumulator(pParse, &sAggInfo);
    +-        assert( pMinMax==0 || pMinMax->nExpr==1 );
    +         if( sqlite3WhereIsOrdered(pWInfo)>0 ){
    +           sqlite3VdbeGoto(v, sqlite3WhereBreakLabel(pWInfo));
    +           VdbeComment((v, "%s() by index",
    +-                (flag==WHERE_ORDERBY_MIN?"min":"max")));
    ++                (minMaxFlag==WHERE_ORDERBY_MIN?"min":"max")));
    +         }
    +         sqlite3WhereEnd(pWInfo);
    +         finalizeAggFunctions(pParse, &sAggInfo);
    +@@ -114220,9 +124690,8 @@ SQLITE_PRIVATE int sqlite3Select(
    + 
    +       sSort.pOrderBy = 0;
    +       sqlite3ExprIfFalse(pParse, pHaving, addrEnd, SQLITE_JUMPIFNULL);
    +-      selectInnerLoop(pParse, p, p->pEList, -1, 0, 0, 
    ++      selectInnerLoop(pParse, p, -1, 0, 0, 
    +                       pDest, addrEnd, addrEnd);
    +-      sqlite3ExprListDelete(db, pDel);
    +     }
    +     sqlite3VdbeResolveLabel(v, addrEnd);
    +     
    +@@ -114254,13 +124723,7 @@ SQLITE_PRIVATE int sqlite3Select(
    +   */
    + select_end:
    +   explainSetInteger(pParse->iSelectId, iRestoreSelectId);
    +-
    +-  /* Identify column names if results of the SELECT are to be output.
    +-  */
    +-  if( rc==SQLITE_OK && pDest->eDest==SRT_Output ){
    +-    generateColumnNames(pParse, pTabList, pEList);
    +-  }
    +-
    ++  sqlite3ExprListDelete(db, pMinMaxOrderBy);
    +   sqlite3DbFree(db, sAggInfo.aCol);
    +   sqlite3DbFree(db, sAggInfo.aFunc);
    + #if SELECTTRACE_ENABLED
    +@@ -114291,8 +124754,6 @@ select_end:
    + ** if they are not used.
    + */
    + /* #include "sqliteInt.h" */
    +-/* #include <stdlib.h> */
    +-/* #include <string.h> */
    + 
    + #ifndef SQLITE_OMIT_GET_TABLE
    + 
    +@@ -114375,7 +124836,7 @@ static int sqlite3_get_table_cb(void *pArg, int nCol, char **argv, char **colv){
    +   return 0;
    + 
    + malloc_failed:
    +-  p->rc = SQLITE_NOMEM;
    ++  p->rc = SQLITE_NOMEM_BKPT;
    +   return 1;
    + }
    + 
    +@@ -114389,7 +124850,7 @@ malloc_failed:
    + ** Instead, the entire table should be passed to sqlite3_free_table() when
    + ** the calling procedure is finished using it.
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_get_table(
    ++SQLITE_API int sqlite3_get_table(
    +   sqlite3 *db,                /* The database on which the SQL executes */
    +   const char *zSql,           /* The SQL to be executed */
    +   char ***pazResult,          /* Write the result table here */
    +@@ -114416,7 +124877,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_get_table(
    +   res.azResult = sqlite3_malloc64(sizeof(char*)*res.nAlloc );
    +   if( res.azResult==0 ){
    +      db->errCode = SQLITE_NOMEM;
    +-     return SQLITE_NOMEM;
    ++     return SQLITE_NOMEM_BKPT;
    +   }
    +   res.azResult[0] = 0;
    +   rc = sqlite3_exec(db, zSql, sqlite3_get_table_cb, &res, pzErrMsg);
    +@@ -114445,7 +124906,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_get_table(
    +     if( azNew==0 ){
    +       sqlite3_free_table(&res.azResult[1]);
    +       db->errCode = SQLITE_NOMEM;
    +-      return SQLITE_NOMEM;
    ++      return SQLITE_NOMEM_BKPT;
    +     }
    +     res.azResult = azNew;
    +   }
    +@@ -114458,7 +124919,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_get_table(
    + /*
    + ** This routine frees the space the sqlite3_get_table() malloced.
    + */
    +-SQLITE_API void SQLITE_STDCALL sqlite3_free_table(
    ++SQLITE_API void sqlite3_free_table(
    +   char **azResult            /* Result returned from sqlite3_get_table() */
    + ){
    +   if( azResult ){
    +@@ -114502,6 +124963,7 @@ SQLITE_PRIVATE void sqlite3DeleteTriggerStep(sqlite3 *db, TriggerStep *pTriggerS
    +     sqlite3ExprListDelete(db, pTmp->pExprList);
    +     sqlite3SelectDelete(db, pTmp->pSelect);
    +     sqlite3IdListDelete(db, pTmp->pIdList);
    ++    sqlite3DbFree(db, pTmp->zSpan);
    + 
    +     sqlite3DbFree(db, pTmp);
    +   }
    +@@ -114573,7 +125035,6 @@ SQLITE_PRIVATE void sqlite3BeginTrigger(
    +   int iDb;                /* The database to store the trigger in */
    +   Token *pName;           /* The unqualified db name */
    +   DbFixer sFix;           /* State vector for the DB fixer */
    +-  int iTabDb;             /* Index of the database holding pTab */
    + 
    +   assert( pName1!=0 );   /* pName1->z might be NULL, but not pName1 itself */
    +   assert( pName2!=0 );
    +@@ -114686,13 +125147,13 @@ SQLITE_PRIVATE void sqlite3BeginTrigger(
    +         " trigger on table: %S", pTableName, 0);
    +     goto trigger_cleanup;
    +   }
    +-  iTabDb = sqlite3SchemaToIndex(db, pTab->pSchema);
    + 
    + #ifndef SQLITE_OMIT_AUTHORIZATION
    +   {
    ++    int iTabDb = sqlite3SchemaToIndex(db, pTab->pSchema);
    +     int code = SQLITE_CREATE_TRIGGER;
    +-    const char *zDb = db->aDb[iTabDb].zName;
    +-    const char *zDbTrig = isTemp ? db->aDb[1].zName : zDb;
    ++    const char *zDb = db->aDb[iTabDb].zDbSName;
    ++    const char *zDbTrig = isTemp ? db->aDb[1].zDbSName : zDb;
    +     if( iTabDb==1 || isTemp ) code = SQLITE_CREATE_TEMP_TRIGGER;
    +     if( sqlite3AuthCheck(pParse, code, zName, pTab->zName, zDbTrig) ){
    +       goto trigger_cleanup;
    +@@ -114764,8 +125225,7 @@ SQLITE_PRIVATE void sqlite3FinishTrigger(
    +     pStepList->pTrig = pTrig;
    +     pStepList = pStepList->pNext;
    +   }
    +-  nameToken.z = pTrig->zName;
    +-  nameToken.n = sqlite3Strlen30(nameToken.z);
    ++  sqlite3TokenInit(&nameToken, pTrig->zName);
    +   sqlite3FixInit(&sFix, pParse, iDb, "trigger", &nameToken);
    +   if( sqlite3FixTriggerStep(&sFix, pTrig->step_list) 
    +    || sqlite3FixExpr(&sFix, pTrig->pWhen) 
    +@@ -114785,9 +125245,10 @@ SQLITE_PRIVATE void sqlite3FinishTrigger(
    +     if( v==0 ) goto triggerfinish_cleanup;
    +     sqlite3BeginWriteOperation(pParse, 0, iDb);
    +     z = sqlite3DbStrNDup(db, (char*)pAll->z, pAll->n);
    ++    testcase( z==0 );
    +     sqlite3NestedParse(pParse,
    +        "INSERT INTO %Q.%s VALUES('trigger',%Q,%Q,0,'CREATE TRIGGER %q')",
    +-       db->aDb[iDb].zName, SCHEMA_TABLE(iDb), zName,
    ++       db->aDb[iDb].zDbSName, MASTER_NAME, zName,
    +        pTrig->table, z);
    +     sqlite3DbFree(db, z);
    +     sqlite3ChangeCookie(pParse, iDb);
    +@@ -114801,7 +125262,7 @@ SQLITE_PRIVATE void sqlite3FinishTrigger(
    +     assert( sqlite3SchemaMutexHeld(db, iDb, 0) );
    +     pTrig = sqlite3HashInsert(pHash, zName, pTrig);
    +     if( pTrig ){
    +-      db->mallocFailed = 1;
    ++      sqlite3OomFault(db);
    +     }else if( pLink->pSchema==pLink->pTabSchema ){
    +       Table *pTab;
    +       pTab = sqlite3HashFind(&pLink->pTabSchema->tblHash, pLink->table);
    +@@ -114817,6 +125278,17 @@ triggerfinish_cleanup:
    +   sqlite3DeleteTriggerStep(db, pStepList);
    + }
    + 
    ++/*
    ++** Duplicate a range of text from an SQL statement, then convert all
    ++** whitespace characters into ordinary space characters.
    ++*/
    ++static char *triggerSpanDup(sqlite3 *db, const char *zStart, const char *zEnd){
    ++  char *z = sqlite3DbSpanDup(db, zStart, zEnd);
    ++  int i;
    ++  if( z ) for(i=0; z[i]; i++) if( sqlite3Isspace(z[i]) ) z[i] = ' ';
    ++  return z;
    ++}    
    ++
    + /*
    + ** Turn a SELECT statement (that the pSelect parameter points to) into
    + ** a trigger step.  Return a pointer to a TriggerStep structure.
    +@@ -114824,7 +125296,12 @@ triggerfinish_cleanup:
    + ** The parser calls this routine when it finds a SELECT statement in
    + ** body of a TRIGGER.  
    + */
    +-SQLITE_PRIVATE TriggerStep *sqlite3TriggerSelectStep(sqlite3 *db, Select *pSelect){
    ++SQLITE_PRIVATE TriggerStep *sqlite3TriggerSelectStep(
    ++  sqlite3 *db,                /* Database connection */
    ++  Select *pSelect,            /* The SELECT statement */
    ++  const char *zStart,         /* Start of SQL text */
    ++  const char *zEnd            /* End of SQL text */
    ++){
    +   TriggerStep *pTriggerStep = sqlite3DbMallocZero(db, sizeof(TriggerStep));
    +   if( pTriggerStep==0 ) {
    +     sqlite3SelectDelete(db, pSelect);
    +@@ -114833,6 +125310,7 @@ SQLITE_PRIVATE TriggerStep *sqlite3TriggerSelectStep(sqlite3 *db, Select *pSelec
    +   pTriggerStep->op = TK_SELECT;
    +   pTriggerStep->pSelect = pSelect;
    +   pTriggerStep->orconf = OE_Default;
    ++  pTriggerStep->zSpan = triggerSpanDup(db, zStart, zEnd);
    +   return pTriggerStep;
    + }
    + 
    +@@ -114845,7 +125323,9 @@ SQLITE_PRIVATE TriggerStep *sqlite3TriggerSelectStep(sqlite3 *db, Select *pSelec
    + static TriggerStep *triggerStepAllocate(
    +   sqlite3 *db,                /* Database connection */
    +   u8 op,                      /* Trigger opcode */
    +-  Token *pName                /* The target name */
    ++  Token *pName,               /* The target name */
    ++  const char *zStart,         /* Start of SQL text */
    ++  const char *zEnd            /* End of SQL text */
    + ){
    +   TriggerStep *pTriggerStep;
    + 
    +@@ -114856,6 +125336,7 @@ static TriggerStep *triggerStepAllocate(
    +     sqlite3Dequote(z);
    +     pTriggerStep->zTarget = z;
    +     pTriggerStep->op = op;
    ++    pTriggerStep->zSpan = triggerSpanDup(db, zStart, zEnd);
    +   }
    +   return pTriggerStep;
    + }
    +@@ -114872,13 +125353,15 @@ SQLITE_PRIVATE TriggerStep *sqlite3TriggerInsertStep(
    +   Token *pTableName,  /* Name of the table into which we insert */
    +   IdList *pColumn,    /* List of columns in pTableName to insert into */
    +   Select *pSelect,    /* A SELECT statement that supplies values */
    +-  u8 orconf           /* The conflict algorithm (OE_Abort, OE_Replace, etc.) */
    ++  u8 orconf,          /* The conflict algorithm (OE_Abort, OE_Replace, etc.) */
    ++  const char *zStart, /* Start of SQL text */
    ++  const char *zEnd    /* End of SQL text */
    + ){
    +   TriggerStep *pTriggerStep;
    + 
    +   assert(pSelect != 0 || db->mallocFailed);
    + 
    +-  pTriggerStep = triggerStepAllocate(db, TK_INSERT, pTableName);
    ++  pTriggerStep = triggerStepAllocate(db, TK_INSERT, pTableName, zStart, zEnd);
    +   if( pTriggerStep ){
    +     pTriggerStep->pSelect = sqlite3SelectDup(db, pSelect, EXPRDUP_REDUCE);
    +     pTriggerStep->pIdList = pColumn;
    +@@ -114901,11 +125384,13 @@ SQLITE_PRIVATE TriggerStep *sqlite3TriggerUpdateStep(
    +   Token *pTableName,   /* Name of the table to be updated */
    +   ExprList *pEList,    /* The SET clause: list of column and new values */
    +   Expr *pWhere,        /* The WHERE clause */
    +-  u8 orconf            /* The conflict algorithm. (OE_Abort, OE_Ignore, etc) */
    ++  u8 orconf,           /* The conflict algorithm. (OE_Abort, OE_Ignore, etc) */
    ++  const char *zStart,  /* Start of SQL text */
    ++  const char *zEnd     /* End of SQL text */
    + ){
    +   TriggerStep *pTriggerStep;
    + 
    +-  pTriggerStep = triggerStepAllocate(db, TK_UPDATE, pTableName);
    ++  pTriggerStep = triggerStepAllocate(db, TK_UPDATE, pTableName, zStart, zEnd);
    +   if( pTriggerStep ){
    +     pTriggerStep->pExprList = sqlite3ExprListDup(db, pEList, EXPRDUP_REDUCE);
    +     pTriggerStep->pWhere = sqlite3ExprDup(db, pWhere, EXPRDUP_REDUCE);
    +@@ -114924,11 +125409,13 @@ SQLITE_PRIVATE TriggerStep *sqlite3TriggerUpdateStep(
    + SQLITE_PRIVATE TriggerStep *sqlite3TriggerDeleteStep(
    +   sqlite3 *db,            /* Database connection */
    +   Token *pTableName,      /* The table from which rows are deleted */
    +-  Expr *pWhere            /* The WHERE clause */
    ++  Expr *pWhere,           /* The WHERE clause */
    ++  const char *zStart,     /* Start of SQL text */
    ++  const char *zEnd        /* End of SQL text */
    + ){
    +   TriggerStep *pTriggerStep;
    + 
    +-  pTriggerStep = triggerStepAllocate(db, TK_DELETE, pTableName);
    ++  pTriggerStep = triggerStepAllocate(db, TK_DELETE, pTableName, zStart, zEnd);
    +   if( pTriggerStep ){
    +     pTriggerStep->pWhere = sqlite3ExprDup(db, pWhere, EXPRDUP_REDUCE);
    +     pTriggerStep->orconf = OE_Default;
    +@@ -114976,7 +125463,7 @@ SQLITE_PRIVATE void sqlite3DropTrigger(Parse *pParse, SrcList *pName, int noErr)
    +   assert( zDb!=0 || sqlite3BtreeHoldsAllMutexes(db) );
    +   for(i=OMIT_TEMPDB; i<db->nDb; i++){
    +     int j = (i<2) ? i^1 : i;  /* Search TEMP before MAIN */
    +-    if( zDb && sqlite3StrICmp(db->aDb[j].zName, zDb) ) continue;
    ++    if( zDb && sqlite3StrICmp(db->aDb[j].zDbSName, zDb) ) continue;
    +     assert( sqlite3SchemaMutexHeld(db, j, 0) );
    +     pTrigger = sqlite3HashFind(&(db->aDb[j].pSchema->trigHash), zName);
    +     if( pTrigger ) break;
    +@@ -115022,7 +125509,7 @@ SQLITE_PRIVATE void sqlite3DropTriggerPtr(Parse *pParse, Trigger *pTrigger){
    + #ifndef SQLITE_OMIT_AUTHORIZATION
    +   {
    +     int code = SQLITE_DROP_TRIGGER;
    +-    const char *zDb = db->aDb[iDb].zName;
    ++    const char *zDb = db->aDb[iDb].zDbSName;
    +     const char *zTab = SCHEMA_TABLE(iDb);
    +     if( iDb==1 ) code = SQLITE_DROP_TEMP_TRIGGER;
    +     if( sqlite3AuthCheck(pParse, code, pTrigger->zName, pTable->zName, zDb) ||
    +@@ -115036,31 +125523,12 @@ SQLITE_PRIVATE void sqlite3DropTriggerPtr(Parse *pParse, Trigger *pTrigger){
    +   */
    +   assert( pTable!=0 );
    +   if( (v = sqlite3GetVdbe(pParse))!=0 ){
    +-    int base;
    +-    static const int iLn = VDBE_OFFSET_LINENO(2);
    +-    static const VdbeOpList dropTrigger[] = {
    +-      { OP_Rewind,     0, ADDR(9),  0},
    +-      { OP_String8,    0, 1,        0}, /* 1 */
    +-      { OP_Column,     0, 1,        2},
    +-      { OP_Ne,         2, ADDR(8),  1},
    +-      { OP_String8,    0, 1,        0}, /* 4: "trigger" */
    +-      { OP_Column,     0, 0,        2},
    +-      { OP_Ne,         2, ADDR(8),  1},
    +-      { OP_Delete,     0, 0,        0},
    +-      { OP_Next,       0, ADDR(1),  0}, /* 8 */
    +-    };
    +-
    +-    sqlite3BeginWriteOperation(pParse, 0, iDb);
    +-    sqlite3OpenMasterTable(pParse, iDb);
    +-    base = sqlite3VdbeAddOpList(v,  ArraySize(dropTrigger), dropTrigger, iLn);
    +-    sqlite3VdbeChangeP4(v, base+1, pTrigger->zName, P4_TRANSIENT);
    +-    sqlite3VdbeChangeP4(v, base+4, "trigger", P4_STATIC);
    ++    sqlite3NestedParse(pParse,
    ++       "DELETE FROM %Q.%s WHERE name=%Q AND type='trigger'",
    ++       db->aDb[iDb].zDbSName, MASTER_NAME, pTrigger->zName
    ++    );
    +     sqlite3ChangeCookie(pParse, iDb);
    +-    sqlite3VdbeAddOp2(v, OP_Close, 0, 0);
    +     sqlite3VdbeAddOp4(v, OP_DropTrigger, iDb, 0, 0, pTrigger->zName, 0);
    +-    if( pParse->nMem<3 ){
    +-      pParse->nMem = 3;
    +-    }
    +   }
    + }
    + 
    +@@ -115082,7 +125550,7 @@ SQLITE_PRIVATE void sqlite3UnlinkAndDeleteTrigger(sqlite3 *db, int iDb, const ch
    +       *pp = (*pp)->pNext;
    +     }
    +     sqlite3DeleteTrigger(db, pTrigger);
    +-    db->flags |= SQLITE_InternChanges;
    ++    db->mDbFlags |= DBFLAG_SchemaChange;
    +   }
    + }
    + 
    +@@ -115160,8 +125628,10 @@ static SrcList *targetSrcList(
    +     pSrc->a[pSrc->nSrc-1].zName = sqlite3DbStrDup(db, pStep->zTarget);
    +     iDb = sqlite3SchemaToIndex(db, pStep->pTrig->pSchema);
    +     if( iDb==0 || iDb>=2 ){
    ++      const char *zDb;
    +       assert( iDb<db->nDb );
    +-      pSrc->a[pSrc->nSrc-1].zDatabase = sqlite3DbStrDup(db, db->aDb[iDb].zName);
    ++      zDb = db->aDb[iDb].zDbSName;
    ++      pSrc->a[pSrc->nSrc-1].zDatabase =  sqlite3DbStrDup(db, zDb);
    +     }
    +   }
    +   return pSrc;
    +@@ -115200,13 +125670,21 @@ static int codeTriggerProgram(
    +     pParse->eOrconf = (orconf==OE_Default)?pStep->orconf:(u8)orconf;
    +     assert( pParse->okConstFactor==0 );
    + 
    ++#ifndef SQLITE_OMIT_TRACE
    ++    if( pStep->zSpan ){
    ++      sqlite3VdbeAddOp4(v, OP_Trace, 0x7fffffff, 1, 0,
    ++                        sqlite3MPrintf(db, "-- %s", pStep->zSpan),
    ++                        P4_DYNAMIC);
    ++    }
    ++#endif
    ++
    +     switch( pStep->op ){
    +       case TK_UPDATE: {
    +         sqlite3Update(pParse, 
    +           targetSrcList(pParse, pStep),
    +           sqlite3ExprListDup(db, pStep->pExprList, 0), 
    +           sqlite3ExprDup(db, pStep->pWhere, 0), 
    +-          pParse->eOrconf
    ++          pParse->eOrconf, 0, 0
    +         );
    +         break;
    +       }
    +@@ -115222,7 +125700,7 @@ static int codeTriggerProgram(
    +       case TK_DELETE: {
    +         sqlite3DeleteFrom(pParse, 
    +           targetSrcList(pParse, pStep),
    +-          sqlite3ExprDup(db, pStep->pWhere, 0)
    ++          sqlite3ExprDup(db, pStep->pWhere, 0), 0, 0
    +         );
    +         break;
    +       }
    +@@ -115340,9 +125818,11 @@ static TriggerPrg *codeRowTrigger(
    +       pTab->zName
    +     ));
    + #ifndef SQLITE_OMIT_TRACE
    +-    sqlite3VdbeChangeP4(v, -1, 
    +-      sqlite3MPrintf(db, "-- TRIGGER %s", pTrigger->zName), P4_DYNAMIC
    +-    );
    ++    if( pTrigger->zName ){
    ++      sqlite3VdbeChangeP4(v, -1, 
    ++        sqlite3MPrintf(db, "-- TRIGGER %s", pTrigger->zName), P4_DYNAMIC
    ++      );
    ++    }
    + #endif
    + 
    +     /* If one was specified, code the WHEN clause. If it evaluates to false
    +@@ -115370,12 +125850,11 @@ static TriggerPrg *codeRowTrigger(
    +     VdbeComment((v, "End: %s.%s", pTrigger->zName, onErrorText(orconf)));
    + 
    +     transferParseError(pParse, pSubParse);
    +-    if( db->mallocFailed==0 ){
    ++    if( db->mallocFailed==0 && pParse->nErr==0 ){
    +       pProgram->aOp = sqlite3VdbeTakeOpArray(v, &pProgram->nOp, &pTop->nMaxArg);
    +     }
    +     pProgram->nMem = pSubParse->nMem;
    +     pProgram->nCsr = pSubParse->nTab;
    +-    pProgram->nOnce = pSubParse->nOnce;
    +     pProgram->token = (void *)pTrigger;
    +     pPrg->aColmask[0] = pSubParse->oldmask;
    +     pPrg->aColmask[1] = pSubParse->newmask;
    +@@ -115448,8 +125927,8 @@ SQLITE_PRIVATE void sqlite3CodeRowTriggerDirect(
    +   if( pPrg ){
    +     int bRecursive = (p->zName && 0==(pParse->db->flags&SQLITE_RecTriggers));
    + 
    +-    sqlite3VdbeAddOp3(v, OP_Program, reg, ignoreJump, ++pParse->nMem);
    +-    sqlite3VdbeChangeP4(v, -1, (const char *)pPrg->pProgram, P4_SUBPROGRAM);
    ++    sqlite3VdbeAddOp4(v, OP_Program, reg, ignoreJump, ++pParse->nMem,
    ++                      (const char *)pPrg->pProgram, P4_SUBPROGRAM);
    +     VdbeComment(
    +         (v, "Call: %s.%s", (p->zName?p->zName:"fkey"), onErrorText(orconf)));
    + 
    +@@ -115668,14 +126147,14 @@ SQLITE_PRIVATE void sqlite3ColumnDefault(Vdbe *v, Table *pTab, int i, int iReg){
    +     sqlite3ValueFromExpr(sqlite3VdbeDb(v), pCol->pDflt, enc, 
    +                          pCol->affinity, &pValue);
    +     if( pValue ){
    +-      sqlite3VdbeChangeP4(v, -1, (const char *)pValue, P4_MEM);
    ++      sqlite3VdbeAppendP4(v, pValue, P4_MEM);
    +     }
    ++  }
    + #ifndef SQLITE_OMIT_FLOATING_POINT
    +-    if( pTab->aCol[i].affinity==SQLITE_AFF_REAL ){
    +-      sqlite3VdbeAddOp1(v, OP_RealAffinity, iReg);
    +-    }
    +-#endif
    ++  if( pTab->aCol[i].affinity==SQLITE_AFF_REAL ){
    ++    sqlite3VdbeAddOp1(v, OP_RealAffinity, iReg);
    +   }
    ++#endif
    + }
    + 
    + /*
    +@@ -115690,7 +126169,9 @@ SQLITE_PRIVATE void sqlite3Update(
    +   SrcList *pTabList,     /* The table in which we should change things */
    +   ExprList *pChanges,    /* Things to be changed */
    +   Expr *pWhere,          /* The WHERE clause.  May be null */
    +-  int onError            /* How to handle constraint errors */
    ++  int onError,           /* How to handle constraint errors */
    ++  ExprList *pOrderBy,    /* ORDER BY clause. May be null */
    ++  Expr *pLimit           /* LIMIT clause. May be null */
    + ){
    +   int i, j;              /* Loop counters */
    +   Table *pTab;           /* The table to be updated */
    +@@ -115704,7 +126185,7 @@ SQLITE_PRIVATE void sqlite3Update(
    +   int iDataCur;          /* Cursor for the canonical data btree */
    +   int iIdxCur;           /* Cursor for the first index */
    +   sqlite3 *db;           /* The database structure */
    +-  int *aRegIdx = 0;      /* One register assigned to each index to be updated */
    ++  int *aRegIdx = 0;      /* First register in array assigned to each index */
    +   int *aXRef = 0;        /* aXRef[i] is the index in pChanges->a[] of the
    +                          ** an expression for the i-th column of the table.
    +                          ** aXRef[i]==-1 if the i-th column is not changed. */
    +@@ -115716,10 +126197,11 @@ SQLITE_PRIVATE void sqlite3Update(
    +   AuthContext sContext;  /* The authorization context */
    +   NameContext sNC;       /* The name-context to resolve expressions in */
    +   int iDb;               /* Database containing the table being updated */
    +-  int okOnePass;         /* True for one-pass algorithm without the FIFO */
    ++  int eOnePass;          /* ONEPASS_XXX value from where.c */
    +   int hasFK;             /* True if foreign key processing is required */
    +   int labelBreak;        /* Jump here to break out of UPDATE loop */
    +   int labelContinue;     /* Jump here to continue next step of UPDATE loop */
    ++  int flags;             /* Flags for sqlite3WhereBegin() */
    + 
    + #ifndef SQLITE_OMIT_TRIGGER
    +   int isView;            /* True when updating a view (INSTEAD OF trigger) */
    +@@ -115730,6 +126212,10 @@ SQLITE_PRIVATE void sqlite3Update(
    +   int iEph = 0;          /* Ephemeral table holding all primary key values */
    +   int nKey = 0;          /* Number of elements in regKey for WITHOUT ROWID */
    +   int aiCurOnePass[2];   /* The write cursors opened by WHERE_ONEPASS */
    ++  int addrOpen = 0;      /* Address of OP_OpenEphemeral */
    ++  int iPk = 0;           /* First of nPk cells holding PRIMARY KEY value */
    ++  i16 nPk = 0;           /* Number of components of the PRIMARY KEY */
    ++  int bReplace = 0;      /* True if REPLACE conflict resolution might happen */
    + 
    +   /* Register Allocations */
    +   int regRowCount = 0;   /* A count of rows changed */
    +@@ -115770,6 +126256,16 @@ SQLITE_PRIVATE void sqlite3Update(
    + # define isView 0
    + #endif
    + 
    ++#ifdef SQLITE_ENABLE_UPDATE_DELETE_LIMIT
    ++  if( !isView ){
    ++    pWhere = sqlite3LimitWhere(
    ++        pParse, pTabList, pWhere, pOrderBy, pLimit, "UPDATE"
    ++    );
    ++    pOrderBy = 0;
    ++    pLimit = 0;
    ++  }
    ++#endif
    ++
    +   if( sqlite3ViewGetColumnNames(pParse, pTab) ){
    +     goto update_cleanup;
    +   }
    +@@ -115796,7 +126292,7 @@ SQLITE_PRIVATE void sqlite3Update(
    +   /* Allocate space for aXRef[], aRegIdx[], and aToOpen[].  
    +   ** Initialize aXRef[] and aToOpen[] to their default values.
    +   */
    +-  aXRef = sqlite3DbMallocRaw(db, sizeof(int) * (pTab->nCol+nIdx) + nIdx+2 );
    ++  aXRef = sqlite3DbMallocRawNN(db, sizeof(int) * (pTab->nCol+nIdx) + nIdx+2 );
    +   if( aXRef==0 ) goto update_cleanup;
    +   aRegIdx = aXRef+pTab->nCol;
    +   aToOpen = (u8*)(aRegIdx+nIdx);
    +@@ -115848,7 +126344,7 @@ SQLITE_PRIVATE void sqlite3Update(
    +       int rc;
    +       rc = sqlite3AuthCheck(pParse, SQLITE_UPDATE, pTab->zName,
    +                             j<0 ? "ROWID" : pTab->aCol[j].zName,
    +-                            db->aDb[iDb].zName);
    ++                            db->aDb[iDb].zDbSName);
    +       if( rc==SQLITE_DENY ){
    +         goto update_cleanup;
    +       }else if( rc==SQLITE_IGNORE ){
    +@@ -115862,10 +126358,12 @@ SQLITE_PRIVATE void sqlite3Update(
    +   assert( chngPk==0 || chngPk==1 );
    +   chngKey = chngRowid + chngPk;
    + 
    +-  /* The SET expressions are not actually used inside the WHERE loop.
    +-  ** So reset the colUsed mask
    ++  /* The SET expressions are not actually used inside the WHERE loop.  
    ++  ** So reset the colUsed mask. Unless this is a virtual table. In that
    ++  ** case, set all bits of the colUsed mask (to ensure that the virtual
    ++  ** table implementation makes all columns available).
    +   */
    +-  pTabList->a[0].colUsed = 0;
    ++  pTabList->a[0].colUsed = IsVirtual(pTab) ? ALLBITS : 0;
    + 
    +   hasFK = sqlite3FkRequired(pParse, pTab, aXRef, chngKey);
    + 
    +@@ -115877,14 +126375,21 @@ SQLITE_PRIVATE void sqlite3Update(
    +   */
    +   for(j=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, j++){
    +     int reg;
    +-    if( chngKey || hasFK || pIdx->pPartIdxWhere || pIdx==pPk ){
    ++    if( chngKey || hasFK>1 || pIdx->pPartIdxWhere || pIdx==pPk ){
    +       reg = ++pParse->nMem;
    ++      pParse->nMem += pIdx->nColumn;
    +     }else{
    +       reg = 0;
    +       for(i=0; i<pIdx->nKeyCol; i++){
    +         i16 iIdxCol = pIdx->aiColumn[i];
    +         if( iIdxCol<0 || aXRef[iIdxCol]>=0 ){
    +           reg = ++pParse->nMem;
    ++          pParse->nMem += pIdx->nColumn;
    ++          if( (onError==OE_Replace)
    ++           || (onError==OE_Default && pIdx->onError==OE_Replace) 
    ++          ){
    ++            bReplace = 1;
    ++          }
    +           break;
    +         }
    +       }
    +@@ -115892,6 +126397,11 @@ SQLITE_PRIVATE void sqlite3Update(
    +     if( reg==0 ) aToOpen[j+1] = 0;
    +     aRegIdx[j] = reg;
    +   }
    ++  if( bReplace ){
    ++    /* If REPLACE conflict resolution might be invoked, open cursors on all 
    ++    ** indexes in case they are needed to delete records.  */
    ++    memset(aToOpen, 1, nIdx+1);
    ++  }
    + 
    +   /* Begin generating code. */
    +   v = sqlite3GetVdbe(pParse);
    +@@ -115924,7 +126434,11 @@ SQLITE_PRIVATE void sqlite3Update(
    +   */
    + #if !defined(SQLITE_OMIT_VIEW) && !defined(SQLITE_OMIT_TRIGGER)
    +   if( isView ){
    +-    sqlite3MaterializeView(pParse, pTab, pWhere, iDataCur);
    ++    sqlite3MaterializeView(pParse, pTab, 
    ++        pWhere, pOrderBy, pLimit, iDataCur
    ++    );
    ++    pOrderBy = 0;
    ++    pLimit = 0;
    +   }
    + #endif
    + 
    +@@ -115944,109 +126458,130 @@ SQLITE_PRIVATE void sqlite3Update(
    +   }
    + #endif
    + 
    +-  /* Begin the database scan
    +-  */
    ++  /* Initialize the count of updated rows */
    ++  if( (db->flags & SQLITE_CountRows) && !pParse->pTriggerTab ){
    ++    regRowCount = ++pParse->nMem;
    ++    sqlite3VdbeAddOp2(v, OP_Integer, 0, regRowCount);
    ++  }
    ++
    +   if( HasRowid(pTab) ){
    +     sqlite3VdbeAddOp3(v, OP_Null, 0, regRowSet, regOldRowid);
    +-    pWInfo = sqlite3WhereBegin(
    +-        pParse, pTabList, pWhere, 0, 0, WHERE_ONEPASS_DESIRED, iIdxCur
    +-    );
    +-    if( pWInfo==0 ) goto update_cleanup;
    +-    okOnePass = sqlite3WhereOkOnePass(pWInfo, aiCurOnePass);
    +-  
    +-    /* Remember the rowid of every item to be updated.
    +-    */
    +-    sqlite3VdbeAddOp2(v, OP_Rowid, iDataCur, regOldRowid);
    +-    if( !okOnePass ){
    +-      sqlite3VdbeAddOp2(v, OP_RowSetAdd, regRowSet, regOldRowid);
    +-    }
    +-  
    +-    /* End the database scan loop.
    +-    */
    +-    sqlite3WhereEnd(pWInfo);
    +   }else{
    +-    int iPk;         /* First of nPk memory cells holding PRIMARY KEY value */
    +-    i16 nPk;         /* Number of components of the PRIMARY KEY */
    +-    int addrOpen;    /* Address of the OpenEphemeral instruction */
    +-
    +     assert( pPk!=0 );
    +     nPk = pPk->nKeyCol;
    +     iPk = pParse->nMem+1;
    +     pParse->nMem += nPk;
    +     regKey = ++pParse->nMem;
    +     iEph = pParse->nTab++;
    ++
    +     sqlite3VdbeAddOp2(v, OP_Null, 0, iPk);
    +     addrOpen = sqlite3VdbeAddOp2(v, OP_OpenEphemeral, iEph, nPk);
    +     sqlite3VdbeSetP4KeyInfo(pParse, pPk);
    +-    pWInfo = sqlite3WhereBegin(pParse, pTabList, pWhere, 0, 0, 
    +-                               WHERE_ONEPASS_DESIRED, iIdxCur);
    +-    if( pWInfo==0 ) goto update_cleanup;
    +-    okOnePass = sqlite3WhereOkOnePass(pWInfo, aiCurOnePass);
    ++  }
    ++
    ++  /* Begin the database scan. 
    ++  **
    ++  ** Do not consider a single-pass strategy for a multi-row update if
    ++  ** there are any triggers or foreign keys to process, or rows may
    ++  ** be deleted as a result of REPLACE conflict handling. Any of these
    ++  ** things might disturb a cursor being used to scan through the table
    ++  ** or index, causing a single-pass approach to malfunction.  */
    ++  flags = WHERE_ONEPASS_DESIRED|WHERE_SEEK_UNIQ_TABLE;
    ++  if( !pParse->nested && !pTrigger && !hasFK && !chngKey && !bReplace ){
    ++    flags |= WHERE_ONEPASS_MULTIROW;
    ++  }
    ++  pWInfo = sqlite3WhereBegin(pParse, pTabList, pWhere, 0, 0, flags, iIdxCur);
    ++  if( pWInfo==0 ) goto update_cleanup;
    ++
    ++  /* A one-pass strategy that might update more than one row may not
    ++  ** be used if any column of the index used for the scan is being
    ++  ** updated. Otherwise, if there is an index on "b", statements like
    ++  ** the following could create an infinite loop:
    ++  **
    ++  **   UPDATE t1 SET b=b+1 WHERE b>?
    ++  **
    ++  ** Fall back to ONEPASS_OFF if where.c has selected a ONEPASS_MULTI
    ++  ** strategy that uses an index for which one or more columns are being
    ++  ** updated.  */
    ++  eOnePass = sqlite3WhereOkOnePass(pWInfo, aiCurOnePass);
    ++  if( eOnePass==ONEPASS_MULTI ){
    ++    int iCur = aiCurOnePass[1];
    ++    if( iCur>=0 && iCur!=iDataCur && aToOpen[iCur-iBaseCur] ){
    ++      eOnePass = ONEPASS_OFF;
    ++    }
    ++    assert( iCur!=iDataCur || !HasRowid(pTab) );
    ++  }
    ++  
    ++  if( HasRowid(pTab) ){
    ++    /* Read the rowid of the current row of the WHERE scan. In ONEPASS_OFF
    ++    ** mode, write the rowid into the FIFO. In either of the one-pass modes,
    ++    ** leave it in register regOldRowid.  */
    ++    sqlite3VdbeAddOp2(v, OP_Rowid, iDataCur, regOldRowid);
    ++    if( eOnePass==ONEPASS_OFF ){
    ++      sqlite3VdbeAddOp2(v, OP_RowSetAdd, regRowSet, regOldRowid);
    ++    }
    ++  }else{
    ++    /* Read the PK of the current row into an array of registers. In
    ++    ** ONEPASS_OFF mode, serialize the array into a record and store it in
    ++    ** the ephemeral table. Or, in ONEPASS_SINGLE or MULTI mode, change
    ++    ** the OP_OpenEphemeral instruction to a Noop (the ephemeral table 
    ++    ** is not required) and leave the PK fields in the array of registers.  */
    +     for(i=0; i<nPk; i++){
    +       assert( pPk->aiColumn[i]>=0 );
    +-      sqlite3ExprCodeGetColumnOfTable(v, pTab, iDataCur, pPk->aiColumn[i],
    +-                                      iPk+i);
    ++      sqlite3ExprCodeGetColumnOfTable(v, pTab, iDataCur,pPk->aiColumn[i],iPk+i);
    +     }
    +-    if( okOnePass ){
    ++    if( eOnePass ){
    +       sqlite3VdbeChangeToNoop(v, addrOpen);
    +       nKey = nPk;
    +       regKey = iPk;
    +     }else{
    +       sqlite3VdbeAddOp4(v, OP_MakeRecord, iPk, nPk, regKey,
    +                         sqlite3IndexAffinityStr(db, pPk), nPk);
    +-      sqlite3VdbeAddOp2(v, OP_IdxInsert, iEph, regKey);
    ++      sqlite3VdbeAddOp4Int(v, OP_IdxInsert, iEph, regKey, iPk, nPk);
    +     }
    +-    sqlite3WhereEnd(pWInfo);
    +   }
    + 
    +-  /* Initialize the count of updated rows
    +-  */
    +-  if( (db->flags & SQLITE_CountRows) && !pParse->pTriggerTab ){
    +-    regRowCount = ++pParse->nMem;
    +-    sqlite3VdbeAddOp2(v, OP_Integer, 0, regRowCount);
    ++  if( eOnePass!=ONEPASS_MULTI ){
    ++    sqlite3WhereEnd(pWInfo);
    +   }
    + 
    +   labelBreak = sqlite3VdbeMakeLabel(v);
    +   if( !isView ){
    +-    /* 
    +-    ** Open every index that needs updating.  Note that if any
    +-    ** index could potentially invoke a REPLACE conflict resolution 
    +-    ** action, then we need to open all indices because we might need
    +-    ** to be deleting some records.
    +-    */
    +-    if( onError==OE_Replace ){
    +-      memset(aToOpen, 1, nIdx+1);
    +-    }else{
    +-      for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){
    +-        if( pIdx->onError==OE_Replace ){
    +-          memset(aToOpen, 1, nIdx+1);
    +-          break;
    +-        }
    +-      }
    +-    }
    +-    if( okOnePass ){
    ++    int addrOnce = 0;
    ++
    ++    /* Open every index that needs updating. */
    ++    if( eOnePass!=ONEPASS_OFF ){
    +       if( aiCurOnePass[0]>=0 ) aToOpen[aiCurOnePass[0]-iBaseCur] = 0;
    +       if( aiCurOnePass[1]>=0 ) aToOpen[aiCurOnePass[1]-iBaseCur] = 0;
    +     }
    +-    sqlite3OpenTableAndIndices(pParse, pTab, OP_OpenWrite, iBaseCur, aToOpen,
    ++
    ++    if( eOnePass==ONEPASS_MULTI && (nIdx-(aiCurOnePass[1]>=0))>0 ){
    ++      addrOnce = sqlite3VdbeAddOp0(v, OP_Once); VdbeCoverage(v);
    ++    }
    ++    sqlite3OpenTableAndIndices(pParse, pTab, OP_OpenWrite, 0, iBaseCur, aToOpen,
    +                                0, 0);
    ++    if( addrOnce ) sqlite3VdbeJumpHere(v, addrOnce);
    +   }
    + 
    +   /* Top of the update loop */
    +-  if( okOnePass ){
    +-    if( aToOpen[iDataCur-iBaseCur] && !isView ){
    ++  if( eOnePass!=ONEPASS_OFF ){
    ++    if( !isView && aiCurOnePass[0]!=iDataCur && aiCurOnePass[1]!=iDataCur ){
    +       assert( pPk );
    +       sqlite3VdbeAddOp4Int(v, OP_NotFound, iDataCur, labelBreak, regKey, nKey);
    +       VdbeCoverageNeverTaken(v);
    +     }
    +-    labelContinue = labelBreak;
    ++    if( eOnePass==ONEPASS_SINGLE ){
    ++      labelContinue = labelBreak;
    ++    }else{
    ++      labelContinue = sqlite3VdbeMakeLabel(v);
    ++    }
    +     sqlite3VdbeAddOp2(v, OP_IsNull, pPk ? regKey : regOldRowid, labelBreak);
    +     VdbeCoverageIf(v, pPk==0);
    +     VdbeCoverageIf(v, pPk!=0);
    +   }else if( pPk ){
    +     labelContinue = sqlite3VdbeMakeLabel(v);
    +     sqlite3VdbeAddOp2(v, OP_Rewind, iEph, labelBreak); VdbeCoverage(v);
    +-    addrTop = sqlite3VdbeAddOp2(v, OP_RowKey, iEph, regKey);
    ++    addrTop = sqlite3VdbeAddOp2(v, OP_RowData, iEph, regKey);
    +     sqlite3VdbeAddOp4Int(v, OP_NotFound, iDataCur, labelContinue, regKey, 0);
    +     VdbeCoverage(v);
    +   }else{
    +@@ -116121,7 +126656,7 @@ SQLITE_PRIVATE void sqlite3Update(
    +         */
    +         testcase( i==31 );
    +         testcase( i==32 );
    +-        sqlite3ExprCodeGetColumnOfTable(v, pTab, iDataCur, i, regNew+i);
    ++        sqlite3ExprCodeGetColumnToReg(pParse, pTab, i, iDataCur, regNew+i);
    +       }else{
    +         sqlite3VdbeAddOp2(v, OP_Null, 0, regNew+i);
    +       }
    +@@ -116164,12 +126699,12 @@ SQLITE_PRIVATE void sqlite3Update(
    + 
    +   if( !isView ){
    +     int addr1 = 0;        /* Address of jump instruction */
    +-    int bReplace = 0;     /* True if REPLACE conflict resolution might happen */
    + 
    +     /* Do constraint checks. */
    +     assert( regOldRowid>0 );
    +     sqlite3GenerateConstraintChecks(pParse, pTab, aRegIdx, iDataCur, iIdxCur,
    +-        regNewRowid, regOldRowid, chngKey, onError, labelContinue, &bReplace);
    ++        regNewRowid, regOldRowid, chngKey, onError, labelContinue, &bReplace,
    ++        aXRef);
    + 
    +     /* Do FK constraint checks. */
    +     if( hasFK ){
    +@@ -116186,11 +126721,34 @@ SQLITE_PRIVATE void sqlite3Update(
    +       VdbeCoverageNeverTaken(v);
    +     }
    +     sqlite3GenerateRowIndexDelete(pParse, pTab, iDataCur, iIdxCur, aRegIdx, -1);
    +-  
    +-    /* If changing the record number, delete the old record.  */
    +-    if( hasFK || chngKey || pPk!=0 ){
    ++
    ++    /* If changing the rowid value, or if there are foreign key constraints
    ++    ** to process, delete the old record. Otherwise, add a noop OP_Delete
    ++    ** to invoke the pre-update hook.
    ++    **
    ++    ** That (regNew==regnewRowid+1) is true is also important for the 
    ++    ** pre-update hook. If the caller invokes preupdate_new(), the returned
    ++    ** value is copied from memory cell (regNewRowid+1+iCol), where iCol
    ++    ** is the column index supplied by the user.
    ++    */
    ++    assert( regNew==regNewRowid+1 );
    ++#ifdef SQLITE_ENABLE_PREUPDATE_HOOK
    ++    sqlite3VdbeAddOp3(v, OP_Delete, iDataCur,
    ++        OPFLAG_ISUPDATE | ((hasFK>1 || chngKey) ? 0 : OPFLAG_ISNOOP),
    ++        regNewRowid
    ++    );
    ++    if( eOnePass==ONEPASS_MULTI ){
    ++      assert( hasFK==0 && chngKey==0 );
    ++      sqlite3VdbeChangeP5(v, OPFLAG_SAVEPOSITION);
    ++    }
    ++    if( !pParse->nested ){
    ++      sqlite3VdbeAppendP4(v, pTab, P4_TABLE);
    ++    }
    ++#else
    ++    if( hasFK>1 || chngKey ){
    +       sqlite3VdbeAddOp2(v, OP_Delete, iDataCur, 0);
    +     }
    ++#endif
    +     if( bReplace || chngKey ){
    +       sqlite3VdbeJumpHere(v, addr1);
    +     }
    +@@ -116200,8 +126758,11 @@ SQLITE_PRIVATE void sqlite3Update(
    +     }
    +   
    +     /* Insert the new index entries and the new record. */
    +-    sqlite3CompleteInsertion(pParse, pTab, iDataCur, iIdxCur,
    +-                             regNewRowid, aRegIdx, 1, 0, 0);
    ++    sqlite3CompleteInsertion(
    ++        pParse, pTab, iDataCur, iIdxCur, regNewRowid, aRegIdx, 
    ++        OPFLAG_ISUPDATE | (eOnePass==ONEPASS_MULTI ? OPFLAG_SAVEPOSITION : 0), 
    ++        0, 0
    ++    );
    + 
    +     /* Do any ON CASCADE, SET NULL or SET DEFAULT operations required to
    +     ** handle rows (possibly in other tables) that refer via a foreign key
    +@@ -116223,8 +126784,11 @@ SQLITE_PRIVATE void sqlite3Update(
    +   /* Repeat the above with the next record to be updated, until
    +   ** all record selected by the WHERE clause have been updated.
    +   */
    +-  if( okOnePass ){
    ++  if( eOnePass==ONEPASS_SINGLE ){
    +     /* Nothing to do at end-of-loop for a single-pass */
    ++  }else if( eOnePass==ONEPASS_MULTI ){
    ++    sqlite3VdbeResolveLabel(v, labelContinue);
    ++    sqlite3WhereEnd(pWInfo);
    +   }else if( pPk ){
    +     sqlite3VdbeResolveLabel(v, labelContinue);
    +     sqlite3VdbeAddOp2(v, OP_Next, iEph, addrTop); VdbeCoverage(v);
    +@@ -116233,15 +126797,6 @@ SQLITE_PRIVATE void sqlite3Update(
    +   }
    +   sqlite3VdbeResolveLabel(v, labelBreak);
    + 
    +-  /* Close all tables */
    +-  for(i=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, i++){
    +-    assert( aRegIdx );
    +-    if( aToOpen[i+1] ){
    +-      sqlite3VdbeAddOp2(v, OP_Close, iIdxCur+i, 0);
    +-    }
    +-  }
    +-  if( iDataCur<iIdxCur ) sqlite3VdbeAddOp2(v, OP_Close, iDataCur, 0);
    +-
    +   /* Update the sqlite_sequence table by storing the content of the
    +   ** maximum rowid counter values recorded while inserting into
    +   ** autoincrement tables.
    +@@ -116267,6 +126822,10 @@ update_cleanup:
    +   sqlite3SrcListDelete(db, pTabList);
    +   sqlite3ExprListDelete(db, pChanges);
    +   sqlite3ExprDelete(db, pWhere);
    ++#if defined(SQLITE_ENABLE_UPDATE_DELETE_LIMIT) 
    ++  sqlite3ExprListDelete(db, pOrderBy);
    ++  sqlite3ExprDelete(db, pLimit);
    ++#endif
    +   return;
    + }
    + /* Make sure "isView" and other macros defined above are undefined. Otherwise
    +@@ -116326,7 +126885,7 @@ static void updateVirtualTable(
    +   int bOnePass;                   /* True to use onepass strategy */
    +   int addr;                       /* Address of OP_OpenEphemeral */
    + 
    +-  /* Allocate nArg registers to martial the arguments to VUpdate. Then
    ++  /* Allocate nArg registers in which to gather the arguments for VUpdate. Then
    +   ** create and open the ephemeral table in which the records created from
    +   ** these arguments will be temporarily stored. */
    +   assert( v );
    +@@ -116342,19 +126901,31 @@ static void updateVirtualTable(
    +   if( pWInfo==0 ) return;
    + 
    +   /* Populate the argument registers. */
    +-  sqlite3VdbeAddOp2(v, OP_Rowid, iCsr, regArg);
    +-  if( pRowid ){
    +-    sqlite3ExprCode(pParse, pRowid, regArg+1);
    +-  }else{
    +-    sqlite3VdbeAddOp2(v, OP_Rowid, iCsr, regArg+1);
    +-  }
    +   for(i=0; i<pTab->nCol; i++){
    +     if( aXRef[i]>=0 ){
    +       sqlite3ExprCode(pParse, pChanges->a[aXRef[i]].pExpr, regArg+2+i);
    +     }else{
    +       sqlite3VdbeAddOp3(v, OP_VColumn, iCsr, i, regArg+2+i);
    ++      sqlite3VdbeChangeP5(v, 1); /* Enable sqlite3_vtab_nochange() */
    +     }
    +   }
    ++  if( HasRowid(pTab) ){
    ++    sqlite3VdbeAddOp2(v, OP_Rowid, iCsr, regArg);
    ++    if( pRowid ){
    ++      sqlite3ExprCode(pParse, pRowid, regArg+1);
    ++    }else{
    ++      sqlite3VdbeAddOp2(v, OP_Rowid, iCsr, regArg+1);
    ++    }
    ++  }else{
    ++    Index *pPk;   /* PRIMARY KEY index */
    ++    i16 iPk;      /* PRIMARY KEY column */
    ++    pPk = sqlite3PrimaryKeyIndex(pTab);
    ++    assert( pPk!=0 );
    ++    assert( pPk->nKeyCol==1 );
    ++    iPk = pPk->aiColumn[0];
    ++    sqlite3VdbeAddOp3(v, OP_VColumn, iCsr, iPk, regArg);
    ++    sqlite3VdbeAddOp2(v, OP_SCopy, regArg+2+iPk, regArg+1);
    ++  }
    + 
    +   bOnePass = sqlite3WhereOkOnePass(pWInfo, aDummy);
    + 
    +@@ -116370,6 +126941,11 @@ static void updateVirtualTable(
    +     /* Create a record from the argument register contents and insert it into
    +     ** the ephemeral table. */
    +     sqlite3VdbeAddOp3(v, OP_MakeRecord, regArg, nArg, regRec);
    ++#ifdef SQLITE_DEBUG
    ++    /* Signal an assert() within OP_MakeRecord that it is allowed to
    ++    ** accept no-change records with serial_type 10 */
    ++    sqlite3VdbeChangeP5(v, OPFLAG_NOCHNG_MAGIC);
    ++#endif
    +     sqlite3VdbeAddOp2(v, OP_NewRowid, ephemTab, regRowid);
    +     sqlite3VdbeAddOp3(v, OP_Insert, ephemTab, regRec, regRowid);
    +   }
    +@@ -116427,57 +127003,52 @@ static void updateVirtualTable(
    + /* #include "vdbeInt.h" */
    + 
    + #if !defined(SQLITE_OMIT_VACUUM) && !defined(SQLITE_OMIT_ATTACH)
    +-/*
    +-** Finalize a prepared statement.  If there was an error, store the
    +-** text of the error message in *pzErrMsg.  Return the result code.
    +-*/
    +-static int vacuumFinalize(sqlite3 *db, sqlite3_stmt *pStmt, char **pzErrMsg){
    +-  int rc;
    +-  rc = sqlite3VdbeFinalize((Vdbe*)pStmt);
    +-  if( rc ){
    +-    sqlite3SetString(pzErrMsg, db, sqlite3_errmsg(db));
    +-  }
    +-  return rc;
    +-}
    + 
    + /*
    +-** Execute zSql on database db. Return an error code.
    ++** Execute zSql on database db.
    ++**
    ++** If zSql returns rows, then each row will have exactly one
    ++** column.  (This will only happen if zSql begins with "SELECT".)
    ++** Take each row of result and call execSql() again recursively.
    ++**
    ++** The execSqlF() routine does the same thing, except it accepts
    ++** a format string as its third argument
    + */
    + static int execSql(sqlite3 *db, char **pzErrMsg, const char *zSql){
    +-  sqlite3_stmt *pStmt;
    +-  VVA_ONLY( int rc; )
    +-  if( !zSql ){
    +-    return SQLITE_NOMEM;
    +-  }
    +-  if( SQLITE_OK!=sqlite3_prepare(db, zSql, -1, &pStmt, 0) ){
    +-    sqlite3SetString(pzErrMsg, db, sqlite3_errmsg(db));
    +-    return sqlite3_errcode(db);
    +-  }
    +-  VVA_ONLY( rc = ) sqlite3_step(pStmt);
    +-  assert( rc!=SQLITE_ROW || (db->flags&SQLITE_CountRows) );
    +-  return vacuumFinalize(db, pStmt, pzErrMsg);
    +-}
    +-
    +-/*
    +-** Execute zSql on database db. The statement returns exactly
    +-** one column. Execute this as SQL on the same database.
    +-*/
    +-static int execExecSql(sqlite3 *db, char **pzErrMsg, const char *zSql){
    +   sqlite3_stmt *pStmt;
    +   int rc;
    + 
    +-  rc = sqlite3_prepare(db, zSql, -1, &pStmt, 0);
    ++  /* printf("SQL: [%s]\n", zSql); fflush(stdout); */
    ++  rc = sqlite3_prepare_v2(db, zSql, -1, &pStmt, 0);
    +   if( rc!=SQLITE_OK ) return rc;
    +-
    +-  while( SQLITE_ROW==sqlite3_step(pStmt) ){
    +-    rc = execSql(db, pzErrMsg, (char*)sqlite3_column_text(pStmt, 0));
    +-    if( rc!=SQLITE_OK ){
    +-      vacuumFinalize(db, pStmt, pzErrMsg);
    +-      return rc;
    ++  while( SQLITE_ROW==(rc = sqlite3_step(pStmt)) ){
    ++    const char *zSubSql = (const char*)sqlite3_column_text(pStmt,0);
    ++    assert( sqlite3_strnicmp(zSql,"SELECT",6)==0 );
    ++    if( zSubSql ){
    ++      assert( zSubSql[0]!='S' );
    ++      rc = execSql(db, pzErrMsg, zSubSql);
    ++      if( rc!=SQLITE_OK ) break;
    +     }
    +   }
    +-
    +-  return vacuumFinalize(db, pStmt, pzErrMsg);
    ++  assert( rc!=SQLITE_ROW );
    ++  if( rc==SQLITE_DONE ) rc = SQLITE_OK;
    ++  if( rc ){
    ++    sqlite3SetString(pzErrMsg, db, sqlite3_errmsg(db));
    ++  }
    ++  (void)sqlite3_finalize(pStmt);
    ++  return rc;
    ++}
    ++static int execSqlF(sqlite3 *db, char **pzErrMsg, const char *zSql, ...){
    ++  char *z;
    ++  va_list ap;
    ++  int rc;
    ++  va_start(ap, zSql);
    ++  z = sqlite3VMPrintf(db, zSql, ap);
    ++  va_end(ap);
    ++  if( z==0 ) return SQLITE_NOMEM;
    ++  rc = execSql(db, pzErrMsg, z);
    ++  sqlite3DbFree(db, z);
    ++  return rc;
    + }
    + 
    + /*
    +@@ -116510,11 +127081,29 @@ static int execExecSql(sqlite3 *db, char **pzErrMsg, const char *zSql){
    + ** transient would cause the database file to appear to be deleted
    + ** following reboot.
    + */
    +-SQLITE_PRIVATE void sqlite3Vacuum(Parse *pParse){
    ++SQLITE_PRIVATE void sqlite3Vacuum(Parse *pParse, Token *pNm){
    +   Vdbe *v = sqlite3GetVdbe(pParse);
    +-  if( v ){
    +-    sqlite3VdbeAddOp2(v, OP_Vacuum, 0, 0);
    +-    sqlite3VdbeUsesBtree(v, 0);
    ++  int iDb = 0;
    ++  if( v==0 ) return;
    ++  if( pNm ){
    ++#ifndef SQLITE_BUG_COMPATIBLE_20160819
    ++    /* Default behavior:  Report an error if the argument to VACUUM is
    ++    ** not recognized */
    ++    iDb = sqlite3TwoPartName(pParse, pNm, pNm, &pNm);
    ++    if( iDb<0 ) return;
    ++#else
    ++    /* When SQLITE_BUG_COMPATIBLE_20160819 is defined, unrecognized arguments
    ++    ** to VACUUM are silently ignored.  This is a back-out of a bug fix that
    ++    ** occurred on 2016-08-19 (https://www.sqlite.org/src/info/083f9e6270).
    ++    ** The buggy behavior is required for binary compatibility with some
    ++    ** legacy applications. */
    ++    iDb = sqlite3FindDb(pParse->db, pNm);
    ++    if( iDb<0 ) iDb = 0;
    ++#endif
    ++  }
    ++  if( iDb!=1 ){
    ++    sqlite3VdbeAddOp1(v, OP_Vacuum, iDb);
    ++    sqlite3VdbeUsesBtree(v, iDb);
    +   }
    +   return;
    + }
    +@@ -116522,19 +127111,20 @@ SQLITE_PRIVATE void sqlite3Vacuum(Parse *pParse){
    + /*
    + ** This routine implements the OP_Vacuum opcode of the VDBE.
    + */
    +-SQLITE_PRIVATE int sqlite3RunVacuum(char **pzErrMsg, sqlite3 *db){
    ++SQLITE_PRIVATE int sqlite3RunVacuum(char **pzErrMsg, sqlite3 *db, int iDb){
    +   int rc = SQLITE_OK;     /* Return code from service routines */
    +   Btree *pMain;           /* The database being vacuumed */
    +   Btree *pTemp;           /* The temporary database we vacuum into */
    +-  char *zSql = 0;         /* SQL statements */
    +-  int saved_flags;        /* Saved value of the db->flags */
    ++  u16 saved_mDbFlags;     /* Saved value of db->mDbFlags */
    ++  u32 saved_flags;        /* Saved value of db->flags */
    +   int saved_nChange;      /* Saved value of db->nChange */
    +   int saved_nTotalChange; /* Saved value of db->nTotalChange */
    +-  void (*saved_xTrace)(void*,const char*);  /* Saved db->xTrace */
    ++  u8 saved_mTrace;        /* Saved trace settings */
    +   Db *pDb = 0;            /* Database to detach at end of vacuum */
    +   int isMemDb;            /* True if vacuuming a :memory: database */
    +   int nRes;               /* Bytes of reserved space at the end of each page */
    +   int nDb;                /* Number of attached databases */
    ++  const char *zDbMain;    /* Schema name of database to vacuum */
    + 
    +   if( !db->autoCommit ){
    +     sqlite3SetString(pzErrMsg, db, "cannot VACUUM from within a transaction");
    +@@ -116549,14 +127139,17 @@ SQLITE_PRIVATE int sqlite3RunVacuum(char **pzErrMsg, sqlite3 *db){
    +   ** restored before returning. Then set the writable-schema flag, and
    +   ** disable CHECK and foreign key constraints.  */
    +   saved_flags = db->flags;
    ++  saved_mDbFlags = db->mDbFlags;
    +   saved_nChange = db->nChange;
    +   saved_nTotalChange = db->nTotalChange;
    +-  saved_xTrace = db->xTrace;
    +-  db->flags |= SQLITE_WriteSchema | SQLITE_IgnoreChecks | SQLITE_PreferBuiltin;
    +-  db->flags &= ~(SQLITE_ForeignKeys | SQLITE_ReverseOrder);
    +-  db->xTrace = 0;
    +-
    +-  pMain = db->aDb[0].pBt;
    ++  saved_mTrace = db->mTrace;
    ++  db->flags |= SQLITE_WriteSchema | SQLITE_IgnoreChecks;
    ++  db->mDbFlags |= DBFLAG_PreferBuiltin | DBFLAG_Vacuum;
    ++  db->flags &= ~(SQLITE_ForeignKeys | SQLITE_ReverseOrder | SQLITE_CountRows);
    ++  db->mTrace = 0;
    ++
    ++  zDbMain = db->aDb[iDb].zDbSName;
    ++  pMain = db->aDb[iDb].pBt;
    +   isMemDb = sqlite3PagerIsMemdb(sqlite3BtreePager(pMain));
    + 
    +   /* Attach the temporary database as 'vacuum_db'. The synchronous pragma
    +@@ -116574,18 +127167,12 @@ SQLITE_PRIVATE int sqlite3RunVacuum(char **pzErrMsg, sqlite3 *db){
    +   ** to write the journal header file.
    +   */
    +   nDb = db->nDb;
    +-  if( sqlite3TempInMemory(db) ){
    +-    zSql = "ATTACH ':memory:' AS vacuum_db;";
    +-  }else{
    +-    zSql = "ATTACH '' AS vacuum_db;";
    +-  }
    +-  rc = execSql(db, pzErrMsg, zSql);
    +-  if( db->nDb>nDb ){
    +-    pDb = &db->aDb[db->nDb-1];
    +-    assert( strcmp(pDb->zName,"vacuum_db")==0 );
    +-  }
    ++  rc = execSql(db, pzErrMsg, "ATTACH''AS vacuum_db");
    +   if( rc!=SQLITE_OK ) goto end_of_vacuum;
    +-  pTemp = db->aDb[db->nDb-1].pBt;
    ++  assert( (db->nDb-1)==nDb );
    ++  pDb = &db->aDb[nDb];
    ++  assert( strcmp(pDb->zDbSName,"vacuum_db")==0 );
    ++  pTemp = pDb->pBt;
    + 
    +   /* The call to execSql() to attach the temp database has left the file
    +   ** locked (as there was more than one active statement when the transaction
    +@@ -116601,19 +127188,20 @@ SQLITE_PRIVATE int sqlite3RunVacuum(char **pzErrMsg, sqlite3 *db){
    +     extern void sqlite3CodecGetKey(sqlite3*, int, void**, int*);
    +     int nKey;
    +     char *zKey;
    +-    sqlite3CodecGetKey(db, 0, (void**)&zKey, &nKey);
    ++    sqlite3CodecGetKey(db, iDb, (void**)&zKey, &nKey);
    +     if( nKey ) db->nextPagesize = 0;
    +   }
    + #endif
    + 
    +-  rc = execSql(db, pzErrMsg, "PRAGMA vacuum_db.synchronous=OFF");
    +-  if( rc!=SQLITE_OK ) goto end_of_vacuum;
    ++  sqlite3BtreeSetCacheSize(pTemp, db->aDb[iDb].pSchema->cache_size);
    ++  sqlite3BtreeSetSpillSize(pTemp, sqlite3BtreeSetSpillSize(pMain,0));
    ++  sqlite3BtreeSetPagerFlags(pTemp, PAGER_SYNCHRONOUS_OFF|PAGER_CACHESPILL);
    + 
    +   /* Begin a transaction and take an exclusive lock on the main database
    +   ** file. This is done before the sqlite3BtreeGetPageSize(pMain) call below,
    +   ** to ensure that we do not try to change the page-size on a WAL database.
    +   */
    +-  rc = execSql(db, pzErrMsg, "BEGIN;");
    ++  rc = execSql(db, pzErrMsg, "BEGIN");
    +   if( rc!=SQLITE_OK ) goto end_of_vacuum;
    +   rc = sqlite3BtreeBeginTrans(pMain, 2);
    +   if( rc!=SQLITE_OK ) goto end_of_vacuum;
    +@@ -116628,7 +127216,7 @@ SQLITE_PRIVATE int sqlite3RunVacuum(char **pzErrMsg, sqlite3 *db){
    +    || (!isMemDb && sqlite3BtreeSetPageSize(pTemp, db->nextPagesize, nRes, 0))
    +    || NEVER(db->mallocFailed)
    +   ){
    +-    rc = SQLITE_NOMEM;
    ++    rc = SQLITE_NOMEM_BKPT;
    +     goto end_of_vacuum;
    +   }
    + 
    +@@ -116640,64 +127228,48 @@ SQLITE_PRIVATE int sqlite3RunVacuum(char **pzErrMsg, sqlite3 *db){
    +   /* Query the schema of the main database. Create a mirror schema
    +   ** in the temporary database.
    +   */
    +-  rc = execExecSql(db, pzErrMsg,
    +-      "SELECT 'CREATE TABLE vacuum_db.' || substr(sql,14) "
    +-      "  FROM sqlite_master WHERE type='table' AND name!='sqlite_sequence'"
    +-      "   AND coalesce(rootpage,1)>0"
    ++  db->init.iDb = nDb; /* force new CREATE statements into vacuum_db */
    ++  rc = execSqlF(db, pzErrMsg,
    ++      "SELECT sql FROM \"%w\".sqlite_master"
    ++      " WHERE type='table'AND name<>'sqlite_sequence'"
    ++      " AND coalesce(rootpage,1)>0",
    ++      zDbMain
    +   );
    +   if( rc!=SQLITE_OK ) goto end_of_vacuum;
    +-  rc = execExecSql(db, pzErrMsg,
    +-      "SELECT 'CREATE INDEX vacuum_db.' || substr(sql,14)"
    +-      "  FROM sqlite_master WHERE sql LIKE 'CREATE INDEX %' ");
    +-  if( rc!=SQLITE_OK ) goto end_of_vacuum;
    +-  rc = execExecSql(db, pzErrMsg,
    +-      "SELECT 'CREATE UNIQUE INDEX vacuum_db.' || substr(sql,21) "
    +-      "  FROM sqlite_master WHERE sql LIKE 'CREATE UNIQUE INDEX %'");
    ++  rc = execSqlF(db, pzErrMsg,
    ++      "SELECT sql FROM \"%w\".sqlite_master"
    ++      " WHERE type='index' AND length(sql)>10",
    ++      zDbMain
    ++  );
    +   if( rc!=SQLITE_OK ) goto end_of_vacuum;
    ++  db->init.iDb = 0;
    + 
    +   /* Loop through the tables in the main database. For each, do
    +   ** an "INSERT INTO vacuum_db.xxx SELECT * FROM main.xxx;" to copy
    +   ** the contents to the temporary database.
    +   */
    +-  assert( (db->flags & SQLITE_Vacuum)==0 );
    +-  db->flags |= SQLITE_Vacuum;
    +-  rc = execExecSql(db, pzErrMsg,
    +-      "SELECT 'INSERT INTO vacuum_db.' || quote(name) "
    +-      "|| ' SELECT * FROM main.' || quote(name) || ';'"
    +-      "FROM main.sqlite_master "
    +-      "WHERE type = 'table' AND name!='sqlite_sequence' "
    +-      "  AND coalesce(rootpage,1)>0"
    ++  rc = execSqlF(db, pzErrMsg,
    ++      "SELECT'INSERT INTO vacuum_db.'||quote(name)"
    ++      "||' SELECT*FROM\"%w\".'||quote(name)"
    ++      "FROM vacuum_db.sqlite_master "
    ++      "WHERE type='table'AND coalesce(rootpage,1)>0",
    ++      zDbMain
    +   );
    +-  assert( (db->flags & SQLITE_Vacuum)!=0 );
    +-  db->flags &= ~SQLITE_Vacuum;
    ++  assert( (db->mDbFlags & DBFLAG_Vacuum)!=0 );
    ++  db->mDbFlags &= ~DBFLAG_Vacuum;
    +   if( rc!=SQLITE_OK ) goto end_of_vacuum;
    + 
    +-  /* Copy over the sequence table
    +-  */
    +-  rc = execExecSql(db, pzErrMsg,
    +-      "SELECT 'DELETE FROM vacuum_db.' || quote(name) || ';' "
    +-      "FROM vacuum_db.sqlite_master WHERE name='sqlite_sequence' "
    +-  );
    +-  if( rc!=SQLITE_OK ) goto end_of_vacuum;
    +-  rc = execExecSql(db, pzErrMsg,
    +-      "SELECT 'INSERT INTO vacuum_db.' || quote(name) "
    +-      "|| ' SELECT * FROM main.' || quote(name) || ';' "
    +-      "FROM vacuum_db.sqlite_master WHERE name=='sqlite_sequence';"
    +-  );
    +-  if( rc!=SQLITE_OK ) goto end_of_vacuum;
    +-
    +-
    +   /* Copy the triggers, views, and virtual tables from the main database
    +   ** over to the temporary database.  None of these objects has any
    +   ** associated storage, so all we have to do is copy their entries
    +   ** from the SQLITE_MASTER table.
    +   */
    +-  rc = execSql(db, pzErrMsg,
    +-      "INSERT INTO vacuum_db.sqlite_master "
    +-      "  SELECT type, name, tbl_name, rootpage, sql"
    +-      "    FROM main.sqlite_master"
    +-      "   WHERE type='view' OR type='trigger'"
    +-      "      OR (type='table' AND rootpage=0)"
    ++  rc = execSqlF(db, pzErrMsg,
    ++      "INSERT INTO vacuum_db.sqlite_master"
    ++      " SELECT*FROM \"%w\".sqlite_master"
    ++      " WHERE type IN('view','trigger')"
    ++      " OR(type='table'AND rootpage=0)",
    ++      zDbMain
    +   );
    +   if( rc ) goto end_of_vacuum;
    + 
    +@@ -116751,10 +127323,12 @@ SQLITE_PRIVATE int sqlite3RunVacuum(char **pzErrMsg, sqlite3 *db){
    + 
    + end_of_vacuum:
    +   /* Restore the original value of db->flags */
    ++  db->init.iDb = 0;
    ++  db->mDbFlags = saved_mDbFlags;
    +   db->flags = saved_flags;
    +   db->nChange = saved_nChange;
    +   db->nTotalChange = saved_nTotalChange;
    +-  db->xTrace = saved_xTrace;
    ++  db->mTrace = saved_mTrace;
    +   sqlite3BtreeSetPageSize(pMain, -1, -1, 1);
    + 
    +   /* Currently there is an SQL level transaction open on the vacuum
    +@@ -116813,6 +127387,43 @@ struct VtabCtx {
    +   int bDeclared;      /* True after sqlite3_declare_vtab() is called */
    + };
    + 
    ++/*
    ++** Construct and install a Module object for a virtual table.  When this
    ++** routine is called, it is guaranteed that all appropriate locks are held
    ++** and the module is not already part of the connection.
    ++*/
    ++SQLITE_PRIVATE Module *sqlite3VtabCreateModule(
    ++  sqlite3 *db,                    /* Database in which module is registered */
    ++  const char *zName,              /* Name assigned to this module */
    ++  const sqlite3_module *pModule,  /* The definition of the module */
    ++  void *pAux,                     /* Context pointer for xCreate/xConnect */
    ++  void (*xDestroy)(void *)        /* Module destructor function */
    ++){
    ++  Module *pMod;
    ++  int nName = sqlite3Strlen30(zName);
    ++  pMod = (Module *)sqlite3Malloc(sizeof(Module) + nName + 1);
    ++  if( pMod==0 ){
    ++    sqlite3OomFault(db);
    ++  }else{
    ++    Module *pDel;
    ++    char *zCopy = (char *)(&pMod[1]);
    ++    memcpy(zCopy, zName, nName+1);
    ++    pMod->zName = zCopy;
    ++    pMod->pModule = pModule;
    ++    pMod->pAux = pAux;
    ++    pMod->xDestroy = xDestroy;
    ++    pMod->pEpoTab = 0;
    ++    pDel = (Module *)sqlite3HashInsert(&db->aModule,zCopy,(void*)pMod);
    ++    assert( pDel==0 || pDel==pMod );
    ++    if( pDel ){
    ++      sqlite3OomFault(db);
    ++      sqlite3DbFree(db, pDel);
    ++      pMod = 0;
    ++    }
    ++  }
    ++  return pMod;
    ++}
    ++
    + /*
    + ** The actual function that does the work of creating a new module.
    + ** This function implements the sqlite3_create_module() and
    +@@ -116826,35 +127437,15 @@ static int createModule(
    +   void (*xDestroy)(void *)        /* Module destructor function */
    + ){
    +   int rc = SQLITE_OK;
    +-  int nName;
    + 
    +   sqlite3_mutex_enter(db->mutex);
    +-  nName = sqlite3Strlen30(zName);
    +   if( sqlite3HashFind(&db->aModule, zName) ){
    +     rc = SQLITE_MISUSE_BKPT;
    +   }else{
    +-    Module *pMod;
    +-    pMod = (Module *)sqlite3DbMallocRaw(db, sizeof(Module) + nName + 1);
    +-    if( pMod ){
    +-      Module *pDel;
    +-      char *zCopy = (char *)(&pMod[1]);
    +-      memcpy(zCopy, zName, nName+1);
    +-      pMod->zName = zCopy;
    +-      pMod->pModule = pModule;
    +-      pMod->pAux = pAux;
    +-      pMod->xDestroy = xDestroy;
    +-      pMod->pEpoTab = 0;
    +-      pDel = (Module *)sqlite3HashInsert(&db->aModule,zCopy,(void*)pMod);
    +-      assert( pDel==0 || pDel==pMod );
    +-      if( pDel ){
    +-        db->mallocFailed = 1;
    +-        sqlite3DbFree(db, pDel);
    +-      }
    +-    }
    ++    (void)sqlite3VtabCreateModule(db, zName, pModule, pAux, xDestroy);
    +   }
    +   rc = sqlite3ApiExit(db, rc);
    +   if( rc!=SQLITE_OK && xDestroy ) xDestroy(pAux);
    +-
    +   sqlite3_mutex_leave(db->mutex);
    +   return rc;
    + }
    +@@ -116863,7 +127454,7 @@ static int createModule(
    + /*
    + ** External API function used to create a new virtual-table module.
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_create_module(
    ++SQLITE_API int sqlite3_create_module(
    +   sqlite3 *db,                    /* Database in which module is registered */
    +   const char *zName,              /* Name assigned to this module */
    +   const sqlite3_module *pModule,  /* The definition of the module */
    +@@ -116878,7 +127469,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_create_module(
    + /*
    + ** External API function used to create a new virtual-table module.
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_create_module_v2(
    ++SQLITE_API int sqlite3_create_module_v2(
    +   sqlite3 *db,                    /* Database in which module is registered */
    +   const char *zName,              /* Name assigned to this module */
    +   const sqlite3_module *pModule,  /* The definition of the module */
    +@@ -117109,8 +127700,7 @@ SQLITE_PRIVATE void sqlite3VtabBeginParse(
    +   iDb = sqlite3SchemaToIndex(db, pTable->pSchema);
    +   assert( iDb>=0 );
    + 
    +-  pTable->tabFlags |= TF_Virtual;
    +-  pTable->nModuleArg = 0;
    ++  assert( pTable->nModuleArg==0 );
    +   addModuleArgument(db, pTable, sqlite3NameFromToken(db, pModuleName));
    +   addModuleArgument(db, pTable, 0);
    +   addModuleArgument(db, pTable, sqlite3DbStrDup(db, pTable->zName));
    +@@ -117129,7 +127719,7 @@ SQLITE_PRIVATE void sqlite3VtabBeginParse(
    +   */
    +   if( pTable->azModuleArg ){
    +     sqlite3AuthCheck(pParse, SQLITE_CREATE_VTABLE, pTable->zName, 
    +-            pTable->azModuleArg[0], pParse->db->aDb[iDb].zName);
    ++            pTable->azModuleArg[0], pParse->db->aDb[iDb].zDbSName);
    +   }
    + #endif
    + }
    +@@ -117193,7 +127783,7 @@ SQLITE_PRIVATE void sqlite3VtabFinishParse(Parse *pParse, Token *pEnd){
    +       "UPDATE %Q.%s "
    +          "SET type='table', name=%Q, tbl_name=%Q, rootpage=0, sql=%Q "
    +        "WHERE rowid=#%d",
    +-      db->aDb[iDb].zName, SCHEMA_TABLE(iDb),
    ++      db->aDb[iDb].zDbSName, MASTER_NAME,
    +       pTab->zName,
    +       pTab->zName,
    +       zStmt,
    +@@ -117203,7 +127793,7 @@ SQLITE_PRIVATE void sqlite3VtabFinishParse(Parse *pParse, Token *pEnd){
    +     v = sqlite3GetVdbe(pParse);
    +     sqlite3ChangeCookie(pParse, iDb);
    + 
    +-    sqlite3VdbeAddOp2(v, OP_Expire, 0, 0);
    ++    sqlite3VdbeAddOp0(v, OP_Expire);
    +     zWhere = sqlite3MPrintf(db, "name='%q' AND type='table'", pTab->zName);
    +     sqlite3VdbeAddParseSchemaOp(v, iDb, zWhere);
    + 
    +@@ -117224,7 +127814,7 @@ SQLITE_PRIVATE void sqlite3VtabFinishParse(Parse *pParse, Token *pEnd){
    +     assert( sqlite3SchemaMutexHeld(db, 0, pSchema) );
    +     pOld = sqlite3HashInsert(&pSchema->tblHash, zName, pTab);
    +     if( pOld ){
    +-      db->mallocFailed = 1;
    ++      sqlite3OomFault(db);
    +       assert( pTab==pOld );  /* Malloc must have failed inside HashInsert() */
    +       return;
    +     }
    +@@ -117289,21 +127879,22 @@ static int vtabCallConstructor(
    +     }
    +   }
    + 
    +-  zModuleName = sqlite3MPrintf(db, "%s", pTab->zName);
    ++  zModuleName = sqlite3DbStrDup(db, pTab->zName);
    +   if( !zModuleName ){
    +-    return SQLITE_NOMEM;
    ++    return SQLITE_NOMEM_BKPT;
    +   }
    + 
    +-  pVTable = sqlite3DbMallocZero(db, sizeof(VTable));
    ++  pVTable = sqlite3MallocZero(sizeof(VTable));
    +   if( !pVTable ){
    ++    sqlite3OomFault(db);
    +     sqlite3DbFree(db, zModuleName);
    +-    return SQLITE_NOMEM;
    ++    return SQLITE_NOMEM_BKPT;
    +   }
    +   pVTable->db = db;
    +   pVTable->pMod = pMod;
    + 
    +   iDb = sqlite3SchemaToIndex(db, pTab->pSchema);
    +-  pTab->azModuleArg[1] = db->aDb[iDb].zName;
    ++  pTab->azModuleArg[1] = db->aDb[iDb].zDbSName;
    + 
    +   /* Invoke the virtual table constructor */
    +   assert( &db->pVtabCtx );
    +@@ -117315,7 +127906,7 @@ static int vtabCallConstructor(
    +   db->pVtabCtx = &sCtx;
    +   rc = xConstruct(db, pMod->pAux, nArg, azArg, &pVTable->pVtab, &zErr);
    +   db->pVtabCtx = sCtx.pPrior;
    +-  if( rc==SQLITE_NOMEM ) db->mallocFailed = 1;
    ++  if( rc==SQLITE_NOMEM ) sqlite3OomFault(db);
    +   assert( sCtx.pTab==pTab );
    + 
    +   if( SQLITE_OK!=rc ){
    +@@ -117349,22 +127940,16 @@ static int vtabCallConstructor(
    +       pTab->pVTable = pVTable;
    + 
    +       for(iCol=0; iCol<pTab->nCol; iCol++){
    +-        char *zType = pTab->aCol[iCol].zType;
    ++        char *zType = sqlite3ColumnType(&pTab->aCol[iCol], "");
    +         int nType;
    +         int i = 0;
    +-        if( !zType ){
    +-          pTab->tabFlags |= oooHidden;
    +-          continue;
    +-        }
    +         nType = sqlite3Strlen30(zType);
    +-        if( sqlite3StrNICmp("hidden", zType, 6)||(zType[6] && zType[6]!=' ') ){
    +-          for(i=0; i<nType; i++){
    +-            if( (0==sqlite3StrNICmp(" hidden", &zType[i], 7))
    +-             && (zType[i+7]=='\0' || zType[i+7]==' ')
    +-            ){
    +-              i++;
    +-              break;
    +-            }
    ++        for(i=0; i<nType; i++){
    ++          if( 0==sqlite3StrNICmp("hidden", &zType[i], 6)
    ++           && (i==0 || zType[i-1]==' ')
    ++           && (zType[i+6]=='\0' || zType[i+6]==' ')
    ++          ){
    ++            break;
    +           }
    +         }
    +         if( i<nType ){
    +@@ -117404,7 +127989,7 @@ SQLITE_PRIVATE int sqlite3VtabCallConnect(Parse *pParse, Table *pTab){
    +   int rc;
    + 
    +   assert( pTab );
    +-  if( (pTab->tabFlags & TF_Virtual)==0 || sqlite3GetVTable(db, pTab) ){
    ++  if( !IsVirtual(pTab) || sqlite3GetVTable(db, pTab) ){
    +     return SQLITE_OK;
    +   }
    + 
    +@@ -117421,6 +128006,7 @@ SQLITE_PRIVATE int sqlite3VtabCallConnect(Parse *pParse, Table *pTab){
    +     rc = vtabCallConstructor(db, pTab, pMod, pMod->pModule->xConnect, &zErr);
    +     if( rc!=SQLITE_OK ){
    +       sqlite3ErrorMsg(pParse, "%s", zErr);
    ++      pParse->rc = rc;
    +     }
    +     sqlite3DbFree(db, zErr);
    +   }
    +@@ -117440,7 +128026,7 @@ static int growVTrans(sqlite3 *db){
    +     int nBytes = sizeof(sqlite3_vtab *) * (db->nVTrans + ARRAY_INCR);
    +     aVTrans = sqlite3DbRealloc(db, (void *)db->aVTrans, nBytes);
    +     if( !aVTrans ){
    +-      return SQLITE_NOMEM;
    ++      return SQLITE_NOMEM_BKPT;
    +     }
    +     memset(&aVTrans[db->nVTrans], 0, sizeof(sqlite3_vtab *)*ARRAY_INCR);
    +     db->aVTrans = aVTrans;
    +@@ -117463,7 +128049,7 @@ static void addToVTrans(sqlite3 *db, VTable *pVTab){
    + ** This function is invoked by the vdbe to call the xCreate method
    + ** of the virtual table named zTab in database iDb. 
    + **
    +-** If an error occurs, *pzErr is set to point an an English language
    ++** If an error occurs, *pzErr is set to point to an English language
    + ** description of the error and an SQLITE_XXX error code is returned.
    + ** In this case the caller must call sqlite3DbFree(db, ) on *pzErr.
    + */
    +@@ -117473,8 +128059,8 @@ SQLITE_PRIVATE int sqlite3VtabCallCreate(sqlite3 *db, int iDb, const char *zTab,
    +   Module *pMod;
    +   const char *zMod;
    + 
    +-  pTab = sqlite3FindTable(db, zTab, db->aDb[iDb].zName);
    +-  assert( pTab && (pTab->tabFlags & TF_Virtual)!=0 && !pTab->pVTable );
    ++  pTab = sqlite3FindTable(db, zTab, db->aDb[iDb].zDbSName);
    ++  assert( pTab && IsVirtual(pTab) && !pTab->pVTable );
    + 
    +   /* Locate the required virtual table module */
    +   zMod = pTab->azModuleArg[0];
    +@@ -117508,12 +128094,12 @@ SQLITE_PRIVATE int sqlite3VtabCallCreate(sqlite3 *db, int iDb, const char *zTab,
    + ** valid to call this function from within the xCreate() or xConnect() of a
    + ** virtual table module.
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_declare_vtab(sqlite3 *db, const char *zCreateTable){
    ++SQLITE_API int sqlite3_declare_vtab(sqlite3 *db, const char *zCreateTable){
    +   VtabCtx *pCtx;
    +-  Parse *pParse;
    +   int rc = SQLITE_OK;
    +   Table *pTab;
    +   char *zErr = 0;
    ++  Parse sParse;
    + 
    + #ifdef SQLITE_ENABLE_API_ARMOR
    +   if( !sqlite3SafetyCheckOk(db) || zCreateTable==0 ){
    +@@ -117528,43 +128114,57 @@ SQLITE_API int SQLITE_STDCALL sqlite3_declare_vtab(sqlite3 *db, const char *zCre
    +     return SQLITE_MISUSE_BKPT;
    +   }
    +   pTab = pCtx->pTab;
    +-  assert( (pTab->tabFlags & TF_Virtual)!=0 );
    ++  assert( IsVirtual(pTab) );
    + 
    +-  pParse = sqlite3StackAllocZero(db, sizeof(*pParse));
    +-  if( pParse==0 ){
    +-    rc = SQLITE_NOMEM;
    +-  }else{
    +-    pParse->declareVtab = 1;
    +-    pParse->db = db;
    +-    pParse->nQueryLoop = 1;
    +-  
    +-    if( SQLITE_OK==sqlite3RunParser(pParse, zCreateTable, &zErr) 
    +-     && pParse->pNewTable
    +-     && !db->mallocFailed
    +-     && !pParse->pNewTable->pSelect
    +-     && (pParse->pNewTable->tabFlags & TF_Virtual)==0
    +-    ){
    +-      if( !pTab->aCol ){
    +-        pTab->aCol = pParse->pNewTable->aCol;
    +-        pTab->nCol = pParse->pNewTable->nCol;
    +-        pParse->pNewTable->nCol = 0;
    +-        pParse->pNewTable->aCol = 0;
    ++  memset(&sParse, 0, sizeof(sParse));
    ++  sParse.declareVtab = 1;
    ++  sParse.db = db;
    ++  sParse.nQueryLoop = 1;
    ++  if( SQLITE_OK==sqlite3RunParser(&sParse, zCreateTable, &zErr) 
    ++   && sParse.pNewTable
    ++   && !db->mallocFailed
    ++   && !sParse.pNewTable->pSelect
    ++   && !IsVirtual(sParse.pNewTable)
    ++  ){
    ++    if( !pTab->aCol ){
    ++      Table *pNew = sParse.pNewTable;
    ++      Index *pIdx;
    ++      pTab->aCol = pNew->aCol;
    ++      pTab->nCol = pNew->nCol;
    ++      pTab->tabFlags |= pNew->tabFlags & (TF_WithoutRowid|TF_NoVisibleRowid);
    ++      pNew->nCol = 0;
    ++      pNew->aCol = 0;
    ++      assert( pTab->pIndex==0 );
    ++      assert( HasRowid(pNew) || sqlite3PrimaryKeyIndex(pNew)!=0 );
    ++      if( !HasRowid(pNew)
    ++       && pCtx->pVTable->pMod->pModule->xUpdate!=0
    ++       && sqlite3PrimaryKeyIndex(pNew)->nKeyCol!=1
    ++      ){
    ++        /* WITHOUT ROWID virtual tables must either be read-only (xUpdate==0)
    ++        ** or else must have a single-column PRIMARY KEY */
    ++        rc = SQLITE_ERROR;
    ++      }
    ++      pIdx = pNew->pIndex;
    ++      if( pIdx ){
    ++        assert( pIdx->pNext==0 );
    ++        pTab->pIndex = pIdx;
    ++        pNew->pIndex = 0;
    ++        pIdx->pTable = pTab;
    +       }
    +-      pCtx->bDeclared = 1;
    +-    }else{
    +-      sqlite3ErrorWithMsg(db, SQLITE_ERROR, (zErr ? "%s" : 0), zErr);
    +-      sqlite3DbFree(db, zErr);
    +-      rc = SQLITE_ERROR;
    +-    }
    +-    pParse->declareVtab = 0;
    +-  
    +-    if( pParse->pVdbe ){
    +-      sqlite3VdbeFinalize(pParse->pVdbe);
    +     }
    +-    sqlite3DeleteTable(db, pParse->pNewTable);
    +-    sqlite3ParserReset(pParse);
    +-    sqlite3StackFree(db, pParse);
    ++    pCtx->bDeclared = 1;
    ++  }else{
    ++    sqlite3ErrorWithMsg(db, SQLITE_ERROR, (zErr ? "%s" : 0), zErr);
    ++    sqlite3DbFree(db, zErr);
    ++    rc = SQLITE_ERROR;
    +   }
    ++  sParse.declareVtab = 0;
    ++
    ++  if( sParse.pVdbe ){
    ++    sqlite3VdbeFinalize(sParse.pVdbe);
    ++  }
    ++  sqlite3DeleteTable(db, sParse.pNewTable);
    ++  sqlite3ParserReset(&sParse);
    + 
    +   assert( (rc&0xff)==rc );
    +   rc = sqlite3ApiExit(db, rc);
    +@@ -117583,8 +128183,8 @@ SQLITE_PRIVATE int sqlite3VtabCallDestroy(sqlite3 *db, int iDb, const char *zTab
    +   int rc = SQLITE_OK;
    +   Table *pTab;
    + 
    +-  pTab = sqlite3FindTable(db, zTab, db->aDb[iDb].zName);
    +-  if( ALWAYS(pTab!=0 && pTab->pVTable!=0) ){
    ++  pTab = sqlite3FindTable(db, zTab, db->aDb[iDb].zDbSName);
    ++  if( pTab!=0 && ALWAYS(pTab->pVTable!=0) ){
    +     VTable *p;
    +     int (*xDestroy)(sqlite3_vtab *);
    +     for(p=pTab->pVTable; p; p=p->pNext){
    +@@ -117724,7 +128324,10 @@ SQLITE_PRIVATE int sqlite3VtabBegin(sqlite3 *db, VTable *pVTab){
    +       if( rc==SQLITE_OK ){
    +         int iSvpt = db->nStatement + db->nSavepoint;
    +         addToVTrans(db, pVTab);
    +-        if( iSvpt ) rc = sqlite3VtabSavepoint(db, SAVEPOINT_BEGIN, iSvpt-1);
    ++        if( iSvpt && pModule->xSavepoint ){
    ++          pVTab->iSavepoint = iSvpt;
    ++          rc = pModule->xSavepoint(pVTab->pVtab, iSvpt-1);
    ++        }
    +       }
    +     }
    +   }
    +@@ -117801,7 +128404,7 @@ SQLITE_PRIVATE FuncDef *sqlite3VtabOverloadFunction(
    +   Table *pTab;
    +   sqlite3_vtab *pVtab;
    +   sqlite3_module *pMod;
    +-  void (*xFunc)(sqlite3_context*,int,sqlite3_value**) = 0;
    ++  void (*xSFunc)(sqlite3_context*,int,sqlite3_value**) = 0;
    +   void *pArg = 0;
    +   FuncDef *pNew;
    +   int rc = 0;
    +@@ -117813,8 +128416,8 @@ SQLITE_PRIVATE FuncDef *sqlite3VtabOverloadFunction(
    +   if( NEVER(pExpr==0) ) return pDef;
    +   if( pExpr->op!=TK_COLUMN ) return pDef;
    +   pTab = pExpr->pTab;
    +-  if( NEVER(pTab==0) ) return pDef;
    +-  if( (pTab->tabFlags & TF_Virtual)==0 ) return pDef;
    ++  if( pTab==0 ) return pDef;
    ++  if( !IsVirtual(pTab) ) return pDef;
    +   pVtab = sqlite3GetVTable(db, pTab)->pVtab;
    +   assert( pVtab!=0 );
    +   assert( pVtab->pModule!=0 );
    +@@ -117829,7 +128432,7 @@ SQLITE_PRIVATE FuncDef *sqlite3VtabOverloadFunction(
    +     for(z=(unsigned char*)zLowerName; *z; z++){
    +       *z = sqlite3UpperToLower[*z];
    +     }
    +-    rc = pMod->xFindFunction(pVtab, nArg, zLowerName, &xFunc, &pArg);
    ++    rc = pMod->xFindFunction(pVtab, nArg, zLowerName, &xSFunc, &pArg);
    +     sqlite3DbFree(db, zLowerName);
    +   }
    +   if( rc==0 ){
    +@@ -117844,9 +128447,9 @@ SQLITE_PRIVATE FuncDef *sqlite3VtabOverloadFunction(
    +     return pDef;
    +   }
    +   *pNew = *pDef;
    +-  pNew->zName = (char *)&pNew[1];
    +-  memcpy(pNew->zName, pDef->zName, sqlite3Strlen30(pDef->zName)+1);
    +-  pNew->xFunc = xFunc;
    ++  pNew->zName = (const char*)&pNew[1];
    ++  memcpy((char*)&pNew[1], pDef->zName, sqlite3Strlen30(pDef->zName)+1);
    ++  pNew->xSFunc = xSFunc;
    +   pNew->pUserData = pArg;
    +   pNew->funcFlags |= SQLITE_FUNC_EPHEM;
    +   return pNew;
    +@@ -117873,12 +128476,12 @@ SQLITE_PRIVATE void sqlite3VtabMakeWritable(Parse *pParse, Table *pTab){
    +     pToplevel->apVtabLock = apVtabLock;
    +     pToplevel->apVtabLock[pToplevel->nVtabLock++] = pTab;
    +   }else{
    +-    pToplevel->db->mallocFailed = 1;
    ++    sqlite3OomFault(pToplevel->db);
    +   }
    + }
    + 
    + /*
    +-** Check to see if virtual tale module pMod can be have an eponymous
    ++** Check to see if virtual table module pMod can be have an eponymous
    + ** virtual table instance.  If it can, create one if one does not already
    + ** exist. Return non-zero if the eponymous virtual table instance exists
    + ** when this routine returns, and return zero if it does not exist.
    +@@ -117895,21 +128498,21 @@ SQLITE_PRIVATE int sqlite3VtabEponymousTableInit(Parse *pParse, Module *pMod){
    +   const sqlite3_module *pModule = pMod->pModule;
    +   Table *pTab;
    +   char *zErr = 0;
    +-  int nName;
    +   int rc;
    +   sqlite3 *db = pParse->db;
    +   if( pMod->pEpoTab ) return 1;
    +   if( pModule->xCreate!=0 && pModule->xCreate!=pModule->xConnect ) return 0;
    +-  nName = sqlite3Strlen30(pMod->zName) + 1;
    +-  pTab = sqlite3DbMallocZero(db, sizeof(Table) + nName);
    ++  pTab = sqlite3DbMallocZero(db, sizeof(Table));
    +   if( pTab==0 ) return 0;
    ++  pTab->zName = sqlite3DbStrDup(db, pMod->zName);
    ++  if( pTab->zName==0 ){
    ++    sqlite3DbFree(db, pTab);
    ++    return 0;
    ++  }
    +   pMod->pEpoTab = pTab;
    +-  pTab->zName = (char*)&pTab[1];
    +-  memcpy(pTab->zName, pMod->zName, nName);
    +-  pTab->nRef = 1;
    ++  pTab->nTabRef = 1;
    +   pTab->pSchema = db->aDb[0].pSchema;
    +-  pTab->tabFlags |= TF_Virtual;
    +-  pTab->nModuleArg = 0;
    ++  assert( pTab->nModuleArg==0 );
    +   pTab->iPKey = -1;
    +   addModuleArgument(db, pTab, sqlite3DbStrDup(db, pTab->zName));
    +   addModuleArgument(db, pTab, 0);
    +@@ -117931,9 +128534,11 @@ SQLITE_PRIVATE int sqlite3VtabEponymousTableInit(Parse *pParse, Module *pMod){
    + SQLITE_PRIVATE void sqlite3VtabEponymousTableClear(sqlite3 *db, Module *pMod){
    +   Table *pTab = pMod->pEpoTab;
    +   if( pTab!=0 ){
    +-    sqlite3DeleteColumnNames(db, pTab);
    +-    sqlite3VtabClear(db, pTab);
    +-    sqlite3DbFree(db, pTab);
    ++    /* Mark the table as Ephemeral prior to deleting it, so that the
    ++    ** sqlite3DeleteTable() routine will know that it is not stored in 
    ++    ** the schema. */
    ++    pTab->tabFlags |= TF_Ephemeral;
    ++    sqlite3DeleteTable(db, pTab);
    +     pMod->pEpoTab = 0;
    +   }
    + }
    +@@ -117945,7 +128550,7 @@ SQLITE_PRIVATE void sqlite3VtabEponymousTableClear(sqlite3 *db, Module *pMod){
    + ** The results of this routine are undefined unless it is called from
    + ** within an xUpdate method.
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_vtab_on_conflict(sqlite3 *db){
    ++SQLITE_API int sqlite3_vtab_on_conflict(sqlite3 *db){
    +   static const unsigned char aMap[] = { 
    +     SQLITE_ROLLBACK, SQLITE_ABORT, SQLITE_FAIL, SQLITE_IGNORE, SQLITE_REPLACE 
    +   };
    +@@ -117963,7 +128568,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_vtab_on_conflict(sqlite3 *db){
    + ** the SQLite core with additional information about the behavior
    + ** of the virtual table being implemented.
    + */
    +-SQLITE_API int SQLITE_CDECL sqlite3_vtab_config(sqlite3 *db, int op, ...){
    ++SQLITE_API int sqlite3_vtab_config(sqlite3 *db, int op, ...){
    +   va_list ap;
    +   int rc = SQLITE_OK;
    + 
    +@@ -117978,7 +128583,7 @@ SQLITE_API int SQLITE_CDECL sqlite3_vtab_config(sqlite3 *db, int op, ...){
    +       if( !p ){
    +         rc = SQLITE_MISUSE_BKPT;
    +       }else{
    +-        assert( p->pTab==0 || (p->pTab->tabFlags & TF_Virtual)!=0 );
    ++        assert( p->pTab==0 || IsVirtual(p->pTab) );
    +         p->pVTable->bConstraint = (u8)va_arg(ap, int);
    +       }
    +       break;
    +@@ -118091,8 +128696,10 @@ struct WhereLevel {
    +   int addrCont;         /* Jump here to continue with the next loop cycle */
    +   int addrFirst;        /* First instruction of interior of the loop */
    +   int addrBody;         /* Beginning of the body of this loop */
    +-  int iLikeRepCntr;     /* LIKE range processing counter register */
    ++#ifndef SQLITE_LIKE_DOESNT_MATCH_BLOBS
    ++  u32 iLikeRepCntr;     /* LIKE range processing counter register (times 2) */
    +   int addrLikeRep;      /* LIKE range processing address */
    ++#endif
    +   u8 iFrom;             /* Which entry in the FROM clause */
    +   u8 op, p3, p5;        /* Opcode, P3 & P5 of the opcode that ends the loop */
    +   int p1, p2;           /* Operands of the opcode used to ends the loop */
    +@@ -118142,6 +128749,9 @@ struct WhereLoop {
    +   union {
    +     struct {               /* Information for internal btree tables */
    +       u16 nEq;               /* Number of equality constraints */
    ++      u16 nBtm;              /* Size of BTM vector */
    ++      u16 nTop;              /* Size of TOP vector */
    ++      u16 nIdxCol;           /* Index column used for ORDER BY */
    +       Index *pIndex;         /* Index used, or NULL */
    +     } btree;
    +     struct {               /* Information for virtual tables */
    +@@ -118264,18 +128874,20 @@ struct WherePath {
    + */
    + struct WhereTerm {
    +   Expr *pExpr;            /* Pointer to the subexpression that is this term */
    ++  WhereClause *pWC;       /* The clause this term is part of */
    ++  LogEst truthProb;       /* Probability of truth for this expression */
    ++  u16 wtFlags;            /* TERM_xxx bit flags.  See below */
    ++  u16 eOperator;          /* A WO_xx value describing <op> */
    ++  u8 nChild;              /* Number of children that must disable us */
    ++  u8 eMatchOp;            /* Op for vtab MATCH/LIKE/GLOB/REGEXP terms */
    +   int iParent;            /* Disable pWC->a[iParent] when this term disabled */
    +   int leftCursor;         /* Cursor number of X in "X <op> <expr>" */
    ++  int iField;             /* Field in (?,?,?) IN (SELECT...) vector */
    +   union {
    +     int leftColumn;         /* Column number of X in "X <op> <expr>" */
    +     WhereOrInfo *pOrInfo;   /* Extra information if (eOperator & WO_OR)!=0 */
    +     WhereAndInfo *pAndInfo; /* Extra information if (eOperator& WO_AND)!=0 */
    +   } u;
    +-  LogEst truthProb;       /* Probability of truth for this expression */
    +-  u16 eOperator;          /* A WO_xx value describing <op> */
    +-  u16 wtFlags;            /* TERM_xxx bit flags.  See below */
    +-  u8 nChild;              /* Number of children that must disable us */
    +-  WhereClause *pWC;       /* The clause this term is part of */
    +   Bitmask prereqRight;    /* Bitmask of tables used by pExpr->pRight */
    +   Bitmask prereqAll;      /* Bitmask of tables referenced by pExpr */
    + };
    +@@ -118299,6 +128911,7 @@ struct WhereTerm {
    + #define TERM_LIKECOND   0x200  /* Conditionally this LIKE operator term */
    + #define TERM_LIKE       0x400  /* The original LIKE operator */
    + #define TERM_IS         0x800  /* Term.pExpr is an IS operator */
    ++#define TERM_VARSELECT  0x1000 /* Term.pExpr contains a correlated sub-query */
    + 
    + /*
    + ** An instance of the WhereScan object is used as an iterator for locating
    +@@ -118307,7 +128920,7 @@ struct WhereTerm {
    + struct WhereScan {
    +   WhereClause *pOrigWC;      /* Original, innermost WhereClause */
    +   WhereClause *pWC;          /* WhereClause currently being scanned */
    +-  char *zCollName;           /* Required collating sequence, if not NULL */
    ++  const char *zCollName;     /* Required collating sequence, if not NULL */
    +   Expr *pIdxExpr;            /* Search for this index expression */
    +   char idxaff;               /* Must match this affinity, if zCollName!=NULL */
    +   unsigned char nEquiv;      /* Number of entries in aEquiv[] */
    +@@ -118388,6 +129001,7 @@ struct WhereAndInfo {
    + ** no gaps.
    + */
    + struct WhereMaskSet {
    ++  int bVarSelect;               /* Used by sqlite3WhereExprUsage() */
    +   int n;                        /* Number of assigned cursor values */
    +   int ix[BMS];                  /* Cursor assigned to each bit */
    + };
    +@@ -118411,8 +129025,13 @@ struct WhereLoopBuilder {
    +   UnpackedRecord *pRec;     /* Probe for stat4 (if required) */
    +   int nRecValid;            /* Number of valid fields currently in pRec */
    + #endif
    ++  unsigned int bldFlags;    /* SQLITE_BLDF_* flags */
    + };
    + 
    ++/* Allowed values for WhereLoopBuider.bldFlags */
    ++#define SQLITE_BLDF_INDEXED  0x0001   /* An index is used */
    ++#define SQLITE_BLDF_UNIQUE   0x0002   /* All keys of a UNIQUE index used */
    ++
    + /*
    + ** The WHERE clause processing routine has two halves.  The
    + ** first part does the start of the WHERE loop and the second
    +@@ -118427,24 +129046,27 @@ struct WhereInfo {
    +   Parse *pParse;            /* Parsing and code generating context */
    +   SrcList *pTabList;        /* List of tables in the join */
    +   ExprList *pOrderBy;       /* The ORDER BY clause or NULL */
    +-  ExprList *pResultSet;     /* Result set. DISTINCT operates on these */
    +-  WhereLoop *pLoops;        /* List of all WhereLoop objects */
    +-  Bitmask revMask;          /* Mask of ORDER BY terms that need reversing */
    +-  LogEst nRowOut;           /* Estimated number of output rows */
    ++  ExprList *pResultSet;     /* Result set of the query */
    ++  Expr *pWhere;             /* The complete WHERE clause */
    ++  LogEst iLimit;            /* LIMIT if wctrlFlags has WHERE_USE_LIMIT */
    ++  int aiCurOnePass[2];      /* OP_OpenWrite cursors for the ONEPASS opt */
    ++  int iContinue;            /* Jump here to continue with next record */
    ++  int iBreak;               /* Jump here to break out of the loop */
    ++  int savedNQueryLoop;      /* pParse->nQueryLoop outside the WHERE loop */
    +   u16 wctrlFlags;           /* Flags originally passed to sqlite3WhereBegin() */
    ++  u8 nLevel;                /* Number of nested loop */
    +   i8 nOBSat;                /* Number of ORDER BY terms satisfied by indices */
    +   u8 sorted;                /* True if really sorted (not just grouped) */
    +   u8 eOnePass;              /* ONEPASS_OFF, or _SINGLE, or _MULTI */
    +   u8 untestedTerms;         /* Not all WHERE terms resolved by outer loop */
    +-  u8 eDistinct;             /* One of the WHERE_DISTINCT_* values below */
    +-  u8 nLevel;                /* Number of nested loop */
    ++  u8 eDistinct;             /* One of the WHERE_DISTINCT_* values */
    ++  u8 bOrderedInnerLoop;     /* True if only the inner-most loop is ordered */
    +   int iTop;                 /* The very beginning of the WHERE loop */
    +-  int iContinue;            /* Jump here to continue with next record */
    +-  int iBreak;               /* Jump here to break out of the loop */
    +-  int savedNQueryLoop;      /* pParse->nQueryLoop outside the WHERE loop */
    +-  int aiCurOnePass[2];      /* OP_OpenWrite cursors for the ONEPASS opt */
    +-  WhereMaskSet sMaskSet;    /* Map cursor numbers to bitmasks */
    ++  WhereLoop *pLoops;        /* List of all WhereLoop objects */
    ++  Bitmask revMask;          /* Mask of ORDER BY terms that need reversing */
    ++  LogEst nRowOut;           /* Estimated number of output rows */
    +   WhereClause sWC;          /* Decomposition of the WHERE clause */
    ++  WhereMaskSet sMaskSet;    /* Map cursor numbers to bitmasks */
    +   WhereLevel a[1];          /* Information about each nest loop in WHERE */
    + };
    + 
    +@@ -118454,6 +129076,9 @@ struct WhereInfo {
    + ** where.c:
    + */
    + SQLITE_PRIVATE Bitmask sqlite3WhereGetMask(WhereMaskSet*,int);
    ++#ifdef WHERETRACE_ENABLED
    ++SQLITE_PRIVATE void sqlite3WhereClausePrint(WhereClause *pWC);
    ++#endif
    + SQLITE_PRIVATE WhereTerm *sqlite3WhereFindTerm(
    +   WhereClause *pWC,     /* The WHERE clause to be searched */
    +   int iCur,             /* Cursor number of LHS */
    +@@ -118510,6 +129135,13 @@ SQLITE_PRIVATE void sqlite3WhereTabFuncArgs(Parse*, struct SrcList_item*, WhereC
    + ** operators that are of interest to the query planner.  An
    + ** OR-ed combination of these values can be used when searching for
    + ** particular WhereTerms within a WhereClause.
    ++**
    ++** Value constraints:
    ++**     WO_EQ    == SQLITE_INDEX_CONSTRAINT_EQ
    ++**     WO_LT    == SQLITE_INDEX_CONSTRAINT_LT
    ++**     WO_LE    == SQLITE_INDEX_CONSTRAINT_LE
    ++**     WO_GT    == SQLITE_INDEX_CONSTRAINT_GT
    ++**     WO_GE    == SQLITE_INDEX_CONSTRAINT_GE
    + */
    + #define WO_IN     0x0001
    + #define WO_EQ     0x0002
    +@@ -118517,7 +129149,7 @@ SQLITE_PRIVATE void sqlite3WhereTabFuncArgs(Parse*, struct SrcList_item*, WhereC
    + #define WO_LE     (WO_EQ<<(TK_LE-TK_EQ))
    + #define WO_GT     (WO_EQ<<(TK_GT-TK_EQ))
    + #define WO_GE     (WO_EQ<<(TK_GE-TK_EQ))
    +-#define WO_MATCH  0x0040
    ++#define WO_AUX    0x0040       /* Op useful to virtual tables only */
    + #define WO_IS     0x0080
    + #define WO_ISNULL 0x0100
    + #define WO_OR     0x0200       /* Two or more OR-connected terms */
    +@@ -118557,6 +129189,17 @@ SQLITE_PRIVATE void sqlite3WhereTabFuncArgs(Parse*, struct SrcList_item*, WhereC
    + /************** Continuing where we left off in wherecode.c ******************/
    + 
    + #ifndef SQLITE_OMIT_EXPLAIN
    ++
    ++/*
    ++** Return the name of the i-th column of the pIdx index.
    ++*/
    ++static const char *explainIndexColumnName(Index *pIdx, int i){
    ++  i = pIdx->aiColumn[i];
    ++  if( i==XN_EXPR ) return "<expr>";
    ++  if( i==XN_ROWID ) return "rowid";
    ++  return pIdx->pTable->aCol[i].zName;
    ++}
    ++
    + /*
    + ** This routine is a helper for explainIndexRange() below
    + **
    +@@ -118567,24 +129210,32 @@ SQLITE_PRIVATE void sqlite3WhereTabFuncArgs(Parse*, struct SrcList_item*, WhereC
    + */
    + static void explainAppendTerm(
    +   StrAccum *pStr,             /* The text expression being built */
    +-  int iTerm,                  /* Index of this term.  First is zero */
    +-  const char *zColumn,        /* Name of the column */
    ++  Index *pIdx,                /* Index to read column names from */
    ++  int nTerm,                  /* Number of terms */
    ++  int iTerm,                  /* Zero-based index of first term. */
    ++  int bAnd,                   /* Non-zero to append " AND " */
    +   const char *zOp             /* Name of the operator */
    + ){
    +-  if( iTerm ) sqlite3StrAccumAppend(pStr, " AND ", 5);
    +-  sqlite3StrAccumAppendAll(pStr, zColumn);
    ++  int i;
    ++
    ++  assert( nTerm>=1 );
    ++  if( bAnd ) sqlite3StrAccumAppend(pStr, " AND ", 5);
    ++
    ++  if( nTerm>1 ) sqlite3StrAccumAppend(pStr, "(", 1);
    ++  for(i=0; i<nTerm; i++){
    ++    if( i ) sqlite3StrAccumAppend(pStr, ",", 1);
    ++    sqlite3StrAccumAppendAll(pStr, explainIndexColumnName(pIdx, iTerm+i));
    ++  }
    ++  if( nTerm>1 ) sqlite3StrAccumAppend(pStr, ")", 1);
    ++
    +   sqlite3StrAccumAppend(pStr, zOp, 1);
    +-  sqlite3StrAccumAppend(pStr, "?", 1);
    +-}
    + 
    +-/*
    +-** Return the name of the i-th column of the pIdx index.
    +-*/
    +-static const char *explainIndexColumnName(Index *pIdx, int i){
    +-  i = pIdx->aiColumn[i];
    +-  if( i==XN_EXPR ) return "<expr>";
    +-  if( i==XN_ROWID ) return "rowid";
    +-  return pIdx->pTable->aCol[i].zName;
    ++  if( nTerm>1 ) sqlite3StrAccumAppend(pStr, "(", 1);
    ++  for(i=0; i<nTerm; i++){
    ++    if( i ) sqlite3StrAccumAppend(pStr, ",", 1);
    ++    sqlite3StrAccumAppend(pStr, "?", 1);
    ++  }
    ++  if( nTerm>1 ) sqlite3StrAccumAppend(pStr, ")", 1);
    + }
    + 
    + /*
    +@@ -118612,17 +129263,16 @@ static void explainIndexRange(StrAccum *pStr, WhereLoop *pLoop){
    +   for(i=0; i<nEq; i++){
    +     const char *z = explainIndexColumnName(pIndex, i);
    +     if( i ) sqlite3StrAccumAppend(pStr, " AND ", 5);
    +-    sqlite3XPrintf(pStr, 0, i>=nSkip ? "%s=?" : "ANY(%s)", z);
    ++    sqlite3XPrintf(pStr, i>=nSkip ? "%s=?" : "ANY(%s)", z);
    +   }
    + 
    +   j = i;
    +   if( pLoop->wsFlags&WHERE_BTM_LIMIT ){
    +-    const char *z = explainIndexColumnName(pIndex, i);
    +-    explainAppendTerm(pStr, i++, z, ">");
    ++    explainAppendTerm(pStr, pIndex, pLoop->u.btree.nBtm, j, i, ">");
    ++    i = 1;
    +   }
    +   if( pLoop->wsFlags&WHERE_TOP_LIMIT ){
    +-    const char *z = explainIndexColumnName(pIndex, j);
    +-    explainAppendTerm(pStr, i, z, "<");
    ++    explainAppendTerm(pStr, pIndex, pLoop->u.btree.nTop, j, i, "<");
    +   }
    +   sqlite3StrAccumAppend(pStr, ")", 1);
    + }
    +@@ -118646,7 +129296,7 @@ SQLITE_PRIVATE int sqlite3WhereExplainOneScan(
    + ){
    +   int ret = 0;
    + #if !defined(SQLITE_DEBUG) && !defined(SQLITE_ENABLE_STMT_SCANSTATUS)
    +-  if( pParse->explain==2 )
    ++  if( sqlite3ParseToplevel(pParse)->explain==2 )
    + #endif
    +   {
    +     struct SrcList_item *pItem = &pTabList->a[pLevel->iFrom];
    +@@ -118662,7 +129312,7 @@ SQLITE_PRIVATE int sqlite3WhereExplainOneScan(
    + 
    +     pLoop = pLevel->pWLoop;
    +     flags = pLoop->wsFlags;
    +-    if( (flags&WHERE_MULTI_OR) || (wctrlFlags&WHERE_ONETABLE_ONLY) ) return 0;
    ++    if( (flags&WHERE_MULTI_OR) || (wctrlFlags&WHERE_OR_SUBCLAUSE) ) return 0;
    + 
    +     isSearch = (flags&(WHERE_BTM_LIMIT|WHERE_TOP_LIMIT))!=0
    +             || ((flags&WHERE_VIRTUALTABLE)==0 && (pLoop->u.btree.nEq>0))
    +@@ -118671,13 +129321,13 @@ SQLITE_PRIVATE int sqlite3WhereExplainOneScan(
    +     sqlite3StrAccumInit(&str, db, zBuf, sizeof(zBuf), SQLITE_MAX_LENGTH);
    +     sqlite3StrAccumAppendAll(&str, isSearch ? "SEARCH" : "SCAN");
    +     if( pItem->pSelect ){
    +-      sqlite3XPrintf(&str, 0, " SUBQUERY %d", pItem->iSelectId);
    ++      sqlite3XPrintf(&str, " SUBQUERY %d", pItem->iSelectId);
    +     }else{
    +-      sqlite3XPrintf(&str, 0, " TABLE %s", pItem->zName);
    ++      sqlite3XPrintf(&str, " TABLE %s", pItem->zName);
    +     }
    + 
    +     if( pItem->zAlias ){
    +-      sqlite3XPrintf(&str, 0, " AS %s", pItem->zAlias);
    ++      sqlite3XPrintf(&str, " AS %s", pItem->zAlias);
    +     }
    +     if( (flags & (WHERE_IPK|WHERE_VIRTUALTABLE))==0 ){
    +       const char *zFmt = 0;
    +@@ -118701,7 +129351,7 @@ SQLITE_PRIVATE int sqlite3WhereExplainOneScan(
    +       }
    +       if( zFmt ){
    +         sqlite3StrAccumAppend(&str, " USING ", 7);
    +-        sqlite3XPrintf(&str, 0, zFmt, pIdx->zName);
    ++        sqlite3XPrintf(&str, zFmt, pIdx->zName);
    +         explainIndexRange(&str, pLoop);
    +       }
    +     }else if( (flags & WHERE_IPK)!=0 && (flags & WHERE_CONSTRAINT)!=0 ){
    +@@ -118716,17 +129366,17 @@ SQLITE_PRIVATE int sqlite3WhereExplainOneScan(
    +         assert( flags&WHERE_TOP_LIMIT);
    +         zRangeOp = "<";
    +       }
    +-      sqlite3XPrintf(&str, 0, " USING INTEGER PRIMARY KEY (rowid%s?)",zRangeOp);
    ++      sqlite3XPrintf(&str, " USING INTEGER PRIMARY KEY (rowid%s?)",zRangeOp);
    +     }
    + #ifndef SQLITE_OMIT_VIRTUALTABLE
    +     else if( (flags & WHERE_VIRTUALTABLE)!=0 ){
    +-      sqlite3XPrintf(&str, 0, " VIRTUAL TABLE INDEX %d:%s",
    ++      sqlite3XPrintf(&str, " VIRTUAL TABLE INDEX %d:%s",
    +                   pLoop->u.vtab.idxNum, pLoop->u.vtab.idxStr);
    +     }
    + #endif
    + #ifdef SQLITE_EXPLAIN_ESTIMATED_ROWS
    +     if( pLoop->nOut>=10 ){
    +-      sqlite3XPrintf(&str, 0, " (~%llu rows)", sqlite3LogEstToInt(pLoop->nOut));
    ++      sqlite3XPrintf(&str, " (~%llu rows)", sqlite3LogEstToInt(pLoop->nOut));
    +     }else{
    +       sqlite3StrAccumAppend(&str, " (~1 row)", 9);
    +     }
    +@@ -118812,8 +129462,8 @@ SQLITE_PRIVATE void sqlite3WhereAddScanStatus(
    + */
    + static void disableTerm(WhereLevel *pLevel, WhereTerm *pTerm){
    +   int nLoop = 0;
    +-  while( pTerm
    +-      && (pTerm->wtFlags & TERM_CODED)==0
    ++  assert( pTerm!=0 );
    ++  while( (pTerm->wtFlags & TERM_CODED)==0
    +       && (pLevel->iLeftJoin==0 || ExprHasProperty(pTerm->pExpr, EP_FromJoin))
    +       && (pLevel->notReady & pTerm->prereqAll)==0
    +   ){
    +@@ -118824,6 +129474,7 @@ static void disableTerm(WhereLevel *pLevel, WhereTerm *pTerm){
    +     }
    +     if( pTerm->iParent<0 ) break;
    +     pTerm = &pTerm->pWC->a[pTerm->iParent];
    ++    assert( pTerm!=0 );
    +     pTerm->nChild--;
    +     if( pTerm->nChild!=0 ) break;
    +     nLoop++;
    +@@ -118863,22 +129514,146 @@ static void codeApplyAffinity(Parse *pParse, int base, int n, char *zAff){
    + 
    +   /* Code the OP_Affinity opcode if there is anything left to do. */
    +   if( n>0 ){
    +-    sqlite3VdbeAddOp2(v, OP_Affinity, base, n);
    +-    sqlite3VdbeChangeP4(v, -1, zAff, n);
    ++    sqlite3VdbeAddOp4(v, OP_Affinity, base, n, 0, zAff, n);
    +     sqlite3ExprCacheAffinityChange(pParse, base, n);
    +   }
    + }
    + 
    ++/*
    ++** Expression pRight, which is the RHS of a comparison operation, is 
    ++** either a vector of n elements or, if n==1, a scalar expression.
    ++** Before the comparison operation, affinity zAff is to be applied
    ++** to the pRight values. This function modifies characters within the
    ++** affinity string to SQLITE_AFF_BLOB if either:
    ++**
    ++**   * the comparison will be performed with no affinity, or
    ++**   * the affinity change in zAff is guaranteed not to change the value.
    ++*/
    ++static void updateRangeAffinityStr(
    ++  Expr *pRight,                   /* RHS of comparison */
    ++  int n,                          /* Number of vector elements in comparison */
    ++  char *zAff                      /* Affinity string to modify */
    ++){
    ++  int i;
    ++  for(i=0; i<n; i++){
    ++    Expr *p = sqlite3VectorFieldSubexpr(pRight, i);
    ++    if( sqlite3CompareAffinity(p, zAff[i])==SQLITE_AFF_BLOB
    ++     || sqlite3ExprNeedsNoAffinityChange(p, zAff[i])
    ++    ){
    ++      zAff[i] = SQLITE_AFF_BLOB;
    ++    }
    ++  }
    ++}
    ++
    ++
    ++/*
    ++** pX is an expression of the form:  (vector) IN (SELECT ...)
    ++** In other words, it is a vector IN operator with a SELECT clause on the
    ++** LHS.  But not all terms in the vector are indexable and the terms might
    ++** not be in the correct order for indexing.
    ++**
    ++** This routine makes a copy of the input pX expression and then adjusts
    ++** the vector on the LHS with corresponding changes to the SELECT so that
    ++** the vector contains only index terms and those terms are in the correct
    ++** order.  The modified IN expression is returned.  The caller is responsible
    ++** for deleting the returned expression.
    ++**
    ++** Example:
    ++**
    ++**    CREATE TABLE t1(a,b,c,d,e,f);
    ++**    CREATE INDEX t1x1 ON t1(e,c);
    ++**    SELECT * FROM t1 WHERE (a,b,c,d,e) IN (SELECT v,w,x,y,z FROM t2)
    ++**                           \_______________________________________/
    ++**                                     The pX expression
    ++**
    ++** Since only columns e and c can be used with the index, in that order,
    ++** the modified IN expression that is returned will be:
    ++**
    ++**        (e,c) IN (SELECT z,x FROM t2)
    ++**
    ++** The reduced pX is different from the original (obviously) and thus is
    ++** only used for indexing, to improve performance.  The original unaltered
    ++** IN expression must also be run on each output row for correctness.
    ++*/
    ++static Expr *removeUnindexableInClauseTerms(
    ++  Parse *pParse,        /* The parsing context */
    ++  int iEq,              /* Look at loop terms starting here */
    ++  WhereLoop *pLoop,     /* The current loop */
    ++  Expr *pX              /* The IN expression to be reduced */
    ++){
    ++  sqlite3 *db = pParse->db;
    ++  Expr *pNew = sqlite3ExprDup(db, pX, 0);
    ++  if( db->mallocFailed==0 ){
    ++    ExprList *pOrigRhs = pNew->x.pSelect->pEList;  /* Original unmodified RHS */
    ++    ExprList *pOrigLhs = pNew->pLeft->x.pList;     /* Original unmodified LHS */
    ++    ExprList *pRhs = 0;         /* New RHS after modifications */
    ++    ExprList *pLhs = 0;         /* New LHS after mods */
    ++    int i;                      /* Loop counter */
    ++    Select *pSelect;            /* Pointer to the SELECT on the RHS */
    ++
    ++    for(i=iEq; i<pLoop->nLTerm; i++){
    ++      if( pLoop->aLTerm[i]->pExpr==pX ){
    ++        int iField = pLoop->aLTerm[i]->iField - 1;
    ++        assert( pOrigRhs->a[iField].pExpr!=0 );
    ++        pRhs = sqlite3ExprListAppend(pParse, pRhs, pOrigRhs->a[iField].pExpr);
    ++        pOrigRhs->a[iField].pExpr = 0;
    ++        assert( pOrigLhs->a[iField].pExpr!=0 );
    ++        pLhs = sqlite3ExprListAppend(pParse, pLhs, pOrigLhs->a[iField].pExpr);
    ++        pOrigLhs->a[iField].pExpr = 0;
    ++      }
    ++    }
    ++    sqlite3ExprListDelete(db, pOrigRhs);
    ++    sqlite3ExprListDelete(db, pOrigLhs);
    ++    pNew->pLeft->x.pList = pLhs;
    ++    pNew->x.pSelect->pEList = pRhs;
    ++    if( pLhs && pLhs->nExpr==1 ){
    ++      /* Take care here not to generate a TK_VECTOR containing only a
    ++      ** single value. Since the parser never creates such a vector, some
    ++      ** of the subroutines do not handle this case.  */
    ++      Expr *p = pLhs->a[0].pExpr;
    ++      pLhs->a[0].pExpr = 0;
    ++      sqlite3ExprDelete(db, pNew->pLeft);
    ++      pNew->pLeft = p;
    ++    }
    ++    pSelect = pNew->x.pSelect;
    ++    if( pSelect->pOrderBy ){
    ++      /* If the SELECT statement has an ORDER BY clause, zero the 
    ++      ** iOrderByCol variables. These are set to non-zero when an 
    ++      ** ORDER BY term exactly matches one of the terms of the 
    ++      ** result-set. Since the result-set of the SELECT statement may
    ++      ** have been modified or reordered, these variables are no longer 
    ++      ** set correctly.  Since setting them is just an optimization, 
    ++      ** it's easiest just to zero them here.  */
    ++      ExprList *pOrderBy = pSelect->pOrderBy;
    ++      for(i=0; i<pOrderBy->nExpr; i++){
    ++        pOrderBy->a[i].u.x.iOrderByCol = 0;
    ++      }
    ++    }
    ++
    ++#if 0
    ++    printf("For indexing, change the IN expr:\n");
    ++    sqlite3TreeViewExpr(0, pX, 0);
    ++    printf("Into:\n");
    ++    sqlite3TreeViewExpr(0, pNew, 0);
    ++#endif
    ++  }
    ++  return pNew;
    ++}
    ++
    + 
    + /*
    + ** Generate code for a single equality term of the WHERE clause.  An equality
    + ** term can be either X=expr or X IN (...).   pTerm is the term to be 
    + ** coded.
    + **
    +-** The current value for the constraint is left in register iReg.
    ++** The current value for the constraint is left in a register, the index
    ++** of which is returned.  An attempt is made store the result in iTarget but
    ++** this is only guaranteed for TK_ISNULL and TK_IN constraints.  If the
    ++** constraint is a TK_EQ or TK_IS, then the current value might be left in
    ++** some other register and it is the caller's responsibility to compensate.
    + **
    +-** For a constraint of the form X=expr, the expression is evaluated and its
    +-** result is left on the stack.  For constraints of the form X IN (...)
    ++** For a constraint of the form X=expr, the expression is evaluated in
    ++** straight-line code.  For constraints of the form X IN (...)
    + ** this routine sets up a loop that will iterate over all values of X.
    + */
    + static int codeEqualityTerm(
    +@@ -118893,6 +129668,7 @@ static int codeEqualityTerm(
    +   Vdbe *v = pParse->pVdbe;
    +   int iReg;                  /* Register holding results */
    + 
    ++  assert( pLevel->pWLoop->aLTerm[iEq]==pTerm );
    +   assert( iTarget>0 );
    +   if( pX->op==TK_EQ || pX->op==TK_IS ){
    +     iReg = sqlite3ExprCodeTarget(pParse, pX->pRight, iTarget);
    +@@ -118901,10 +129677,13 @@ static int codeEqualityTerm(
    +     sqlite3VdbeAddOp2(v, OP_Null, 0, iReg);
    + #ifndef SQLITE_OMIT_SUBQUERY
    +   }else{
    +-    int eType;
    ++    int eType = IN_INDEX_NOOP;
    +     int iTab;
    +     struct InLoop *pIn;
    +     WhereLoop *pLoop = pLevel->pWLoop;
    ++    int i;
    ++    int nEq = 0;
    ++    int *aiMap = 0;
    + 
    +     if( (pLoop->wsFlags & WHERE_VIRTUALTABLE)==0
    +       && pLoop->u.btree.pIndex!=0
    +@@ -118916,7 +129695,33 @@ static int codeEqualityTerm(
    +     }
    +     assert( pX->op==TK_IN );
    +     iReg = iTarget;
    +-    eType = sqlite3FindInIndex(pParse, pX, IN_INDEX_LOOP, 0);
    ++
    ++    for(i=0; i<iEq; i++){
    ++      if( pLoop->aLTerm[i] && pLoop->aLTerm[i]->pExpr==pX ){
    ++        disableTerm(pLevel, pTerm);
    ++        return iTarget;
    ++      }
    ++    }
    ++    for(i=iEq;i<pLoop->nLTerm; i++){
    ++      assert( pLoop->aLTerm[i]!=0 );
    ++      if( pLoop->aLTerm[i]->pExpr==pX ) nEq++;
    ++    }
    ++
    ++    if( (pX->flags & EP_xIsSelect)==0 || pX->x.pSelect->pEList->nExpr==1 ){
    ++      eType = sqlite3FindInIndex(pParse, pX, IN_INDEX_LOOP, 0, 0);
    ++    }else{
    ++      sqlite3 *db = pParse->db;
    ++      pX = removeUnindexableInClauseTerms(pParse, iEq, pLoop, pX);
    ++
    ++      if( !db->mallocFailed ){
    ++        aiMap = (int*)sqlite3DbMallocZero(pParse->db, sizeof(int)*nEq);
    ++        eType = sqlite3FindInIndex(pParse, pX, IN_INDEX_LOOP, 0, aiMap);
    ++        pTerm->pExpr->iTable = pX->iTable;
    ++      }
    ++      sqlite3ExprDelete(db, pX);
    ++      pX = pTerm->pExpr;
    ++    }
    ++
    +     if( eType==IN_INDEX_INDEX_DESC ){
    +       testcase( bRev );
    +       bRev = !bRev;
    +@@ -118926,28 +129731,45 @@ static int codeEqualityTerm(
    +     VdbeCoverageIf(v, bRev);
    +     VdbeCoverageIf(v, !bRev);
    +     assert( (pLoop->wsFlags & WHERE_MULTI_OR)==0 );
    ++
    +     pLoop->wsFlags |= WHERE_IN_ABLE;
    +     if( pLevel->u.in.nIn==0 ){
    +       pLevel->addrNxt = sqlite3VdbeMakeLabel(v);
    +     }
    +-    pLevel->u.in.nIn++;
    ++
    ++    i = pLevel->u.in.nIn;
    ++    pLevel->u.in.nIn += nEq;
    +     pLevel->u.in.aInLoop =
    +        sqlite3DbReallocOrFree(pParse->db, pLevel->u.in.aInLoop,
    +                               sizeof(pLevel->u.in.aInLoop[0])*pLevel->u.in.nIn);
    +     pIn = pLevel->u.in.aInLoop;
    +     if( pIn ){
    +-      pIn += pLevel->u.in.nIn - 1;
    +-      pIn->iCur = iTab;
    +-      if( eType==IN_INDEX_ROWID ){
    +-        pIn->addrInTop = sqlite3VdbeAddOp2(v, OP_Rowid, iTab, iReg);
    +-      }else{
    +-        pIn->addrInTop = sqlite3VdbeAddOp3(v, OP_Column, iTab, 0, iReg);
    ++      int iMap = 0;               /* Index in aiMap[] */
    ++      pIn += i;
    ++      for(i=iEq;i<pLoop->nLTerm; i++){
    ++        if( pLoop->aLTerm[i]->pExpr==pX ){
    ++          int iOut = iReg + i - iEq;
    ++          if( eType==IN_INDEX_ROWID ){
    ++            testcase( nEq>1 );  /* Happens with a UNIQUE index on ROWID */
    ++            pIn->addrInTop = sqlite3VdbeAddOp2(v, OP_Rowid, iTab, iOut);
    ++          }else{
    ++            int iCol = aiMap ? aiMap[iMap++] : 0;
    ++            pIn->addrInTop = sqlite3VdbeAddOp3(v,OP_Column,iTab, iCol, iOut);
    ++          }
    ++          sqlite3VdbeAddOp1(v, OP_IsNull, iOut); VdbeCoverage(v);
    ++          if( i==iEq ){
    ++            pIn->iCur = iTab;
    ++            pIn->eEndLoopOp = bRev ? OP_PrevIfOpen : OP_NextIfOpen;
    ++          }else{
    ++            pIn->eEndLoopOp = OP_Noop;
    ++          }
    ++          pIn++;
    ++        }
    +       }
    +-      pIn->eEndLoopOp = bRev ? OP_PrevIfOpen : OP_NextIfOpen;
    +-      sqlite3VdbeAddOp1(v, OP_IsNull, iReg); VdbeCoverage(v);
    +     }else{
    +       pLevel->u.in.nIn = 0;
    +     }
    ++    sqlite3DbFree(pParse->db, aiMap);
    + #endif
    +   }
    +   disableTerm(pLevel, pTerm);
    +@@ -119032,9 +129854,7 @@ static int codeAllEqualityTerms(
    +   pParse->nMem += nReg;
    + 
    +   zAff = sqlite3DbStrDup(pParse->db,sqlite3IndexAffinityStr(pParse->db,pIdx));
    +-  if( !zAff ){
    +-    pParse->db->mallocFailed = 1;
    +-  }
    ++  assert( zAff!=0 || pParse->db->mallocFailed );
    + 
    +   if( nSkip ){
    +     int iIdxCur = pLevel->iIdxCur;
    +@@ -119075,9 +129895,15 @@ static int codeAllEqualityTerms(
    +         sqlite3VdbeAddOp2(v, OP_SCopy, r1, regBase+j);
    +       }
    +     }
    +-    testcase( pTerm->eOperator & WO_ISNULL );
    +-    testcase( pTerm->eOperator & WO_IN );
    +-    if( (pTerm->eOperator & (WO_ISNULL|WO_IN))==0 ){
    ++    if( pTerm->eOperator & WO_IN ){
    ++      if( pTerm->pExpr->flags & EP_xIsSelect ){
    ++        /* No affinity ever needs to be (or should be) applied to a value
    ++        ** from the RHS of an "? IN (SELECT ...)" expression. The 
    ++        ** sqlite3FindInIndex() routine has already ensured that the 
    ++        ** affinity of the comparison has been applied to the value.  */
    ++        if( zAff ) zAff[j] = SQLITE_AFF_BLOB;
    ++      }
    ++    }else if( (pTerm->eOperator & WO_ISNULL)==0 ){
    +       Expr *pRight = pTerm->pExpr->pRight;
    +       if( (pTerm->wtFlags & TERM_IS)==0 && sqlite3ExprCanBeNull(pRight) ){
    +         sqlite3VdbeAddOp2(v, OP_IsNull, regBase+j, pLevel->addrBrk);
    +@@ -119097,17 +129923,23 @@ static int codeAllEqualityTerms(
    +   return regBase;
    + }
    + 
    ++#ifndef SQLITE_LIKE_DOESNT_MATCH_BLOBS
    + /*
    +-** If the most recently coded instruction is a constant range contraint
    +-** that originated from the LIKE optimization, then change the P3 to be
    +-** pLoop->iLikeRepCntr and set P5.
    ++** If the most recently coded instruction is a constant range constraint
    ++** (a string literal) that originated from the LIKE optimization, then 
    ++** set P3 and P5 on the OP_String opcode so that the string will be cast
    ++** to a BLOB at appropriate times.
    + **
    + ** The LIKE optimization trys to evaluate "x LIKE 'abc%'" as a range
    + ** expression: "x>='ABC' AND x<'abd'".  But this requires that the range
    + ** scan loop run twice, once for strings and a second time for BLOBs.
    + ** The OP_String opcodes on the second pass convert the upper and lower
    +-** bound string contants to blobs.  This routine makes the necessary changes
    ++** bound string constants to blobs.  This routine makes the necessary changes
    + ** to the OP_String opcodes for that to happen.
    ++**
    ++** Except, of course, if SQLITE_LIKE_DOESNT_MATCH_BLOBS is defined, then
    ++** only the one pass through the string space is required, so this routine
    ++** becomes a no-op.
    + */
    + static void whereLikeOptimizationStringFixup(
    +   Vdbe *v,                /* prepared statement under construction */
    +@@ -119121,11 +129953,374 @@ static void whereLikeOptimizationStringFixup(
    +     assert( pOp!=0 );
    +     assert( pOp->opcode==OP_String8 
    +             || pTerm->pWC->pWInfo->pParse->db->mallocFailed );
    +-    pOp->p3 = pLevel->iLikeRepCntr;
    +-    pOp->p5 = 1;
    ++    pOp->p3 = (int)(pLevel->iLikeRepCntr>>1);  /* Register holding counter */
    ++    pOp->p5 = (u8)(pLevel->iLikeRepCntr&1);    /* ASC or DESC */
    ++  }
    ++}
    ++#else
    ++# define whereLikeOptimizationStringFixup(A,B,C)
    ++#endif
    ++
    ++#ifdef SQLITE_ENABLE_CURSOR_HINTS
    ++/*
    ++** Information is passed from codeCursorHint() down to individual nodes of
    ++** the expression tree (by sqlite3WalkExpr()) using an instance of this
    ++** structure.
    ++*/
    ++struct CCurHint {
    ++  int iTabCur;    /* Cursor for the main table */
    ++  int iIdxCur;    /* Cursor for the index, if pIdx!=0.  Unused otherwise */
    ++  Index *pIdx;    /* The index used to access the table */
    ++};
    ++
    ++/*
    ++** This function is called for every node of an expression that is a candidate
    ++** for a cursor hint on an index cursor.  For TK_COLUMN nodes that reference
    ++** the table CCurHint.iTabCur, verify that the same column can be
    ++** accessed through the index.  If it cannot, then set pWalker->eCode to 1.
    ++*/
    ++static int codeCursorHintCheckExpr(Walker *pWalker, Expr *pExpr){
    ++  struct CCurHint *pHint = pWalker->u.pCCurHint;
    ++  assert( pHint->pIdx!=0 );
    ++  if( pExpr->op==TK_COLUMN
    ++   && pExpr->iTable==pHint->iTabCur
    ++   && sqlite3ColumnOfIndex(pHint->pIdx, pExpr->iColumn)<0
    ++  ){
    ++    pWalker->eCode = 1;
    ++  }
    ++  return WRC_Continue;
    ++}
    ++
    ++/*
    ++** Test whether or not expression pExpr, which was part of a WHERE clause,
    ++** should be included in the cursor-hint for a table that is on the rhs
    ++** of a LEFT JOIN. Set Walker.eCode to non-zero before returning if the 
    ++** expression is not suitable.
    ++**
    ++** An expression is unsuitable if it might evaluate to non NULL even if
    ++** a TK_COLUMN node that does affect the value of the expression is set
    ++** to NULL. For example:
    ++**
    ++**   col IS NULL
    ++**   col IS NOT NULL
    ++**   coalesce(col, 1)
    ++**   CASE WHEN col THEN 0 ELSE 1 END
    ++*/
    ++static int codeCursorHintIsOrFunction(Walker *pWalker, Expr *pExpr){
    ++  if( pExpr->op==TK_IS 
    ++   || pExpr->op==TK_ISNULL || pExpr->op==TK_ISNOT 
    ++   || pExpr->op==TK_NOTNULL || pExpr->op==TK_CASE 
    ++  ){
    ++    pWalker->eCode = 1;
    ++  }else if( pExpr->op==TK_FUNCTION ){
    ++    int d1;
    ++    char d2[4];
    ++    if( 0==sqlite3IsLikeFunction(pWalker->pParse->db, pExpr, &d1, d2) ){
    ++      pWalker->eCode = 1;
    ++    }
    ++  }
    ++
    ++  return WRC_Continue;
    ++}
    ++
    ++
    ++/*
    ++** This function is called on every node of an expression tree used as an
    ++** argument to the OP_CursorHint instruction. If the node is a TK_COLUMN
    ++** that accesses any table other than the one identified by
    ++** CCurHint.iTabCur, then do the following:
    ++**
    ++**   1) allocate a register and code an OP_Column instruction to read 
    ++**      the specified column into the new register, and
    ++**
    ++**   2) transform the expression node to a TK_REGISTER node that reads 
    ++**      from the newly populated register.
    ++**
    ++** Also, if the node is a TK_COLUMN that does access the table idenified
    ++** by pCCurHint.iTabCur, and an index is being used (which we will
    ++** know because CCurHint.pIdx!=0) then transform the TK_COLUMN into
    ++** an access of the index rather than the original table.
    ++*/
    ++static int codeCursorHintFixExpr(Walker *pWalker, Expr *pExpr){
    ++  int rc = WRC_Continue;
    ++  struct CCurHint *pHint = pWalker->u.pCCurHint;
    ++  if( pExpr->op==TK_COLUMN ){
    ++    if( pExpr->iTable!=pHint->iTabCur ){
    ++      Vdbe *v = pWalker->pParse->pVdbe;
    ++      int reg = ++pWalker->pParse->nMem;   /* Register for column value */
    ++      sqlite3ExprCodeGetColumnOfTable(
    ++          v, pExpr->pTab, pExpr->iTable, pExpr->iColumn, reg
    ++      );
    ++      pExpr->op = TK_REGISTER;
    ++      pExpr->iTable = reg;
    ++    }else if( pHint->pIdx!=0 ){
    ++      pExpr->iTable = pHint->iIdxCur;
    ++      pExpr->iColumn = sqlite3ColumnOfIndex(pHint->pIdx, pExpr->iColumn);
    ++      assert( pExpr->iColumn>=0 );
    ++    }
    ++  }else if( pExpr->op==TK_AGG_FUNCTION ){
    ++    /* An aggregate function in the WHERE clause of a query means this must
    ++    ** be a correlated sub-query, and expression pExpr is an aggregate from
    ++    ** the parent context. Do not walk the function arguments in this case.
    ++    **
    ++    ** todo: It should be possible to replace this node with a TK_REGISTER
    ++    ** expression, as the result of the expression must be stored in a 
    ++    ** register at this point. The same holds for TK_AGG_COLUMN nodes. */
    ++    rc = WRC_Prune;
    ++  }
    ++  return rc;
    ++}
    ++
    ++/*
    ++** Insert an OP_CursorHint instruction if it is appropriate to do so.
    ++*/
    ++static void codeCursorHint(
    ++  struct SrcList_item *pTabItem,  /* FROM clause item */
    ++  WhereInfo *pWInfo,    /* The where clause */
    ++  WhereLevel *pLevel,   /* Which loop to provide hints for */
    ++  WhereTerm *pEndRange  /* Hint this end-of-scan boundary term if not NULL */
    ++){
    ++  Parse *pParse = pWInfo->pParse;
    ++  sqlite3 *db = pParse->db;
    ++  Vdbe *v = pParse->pVdbe;
    ++  Expr *pExpr = 0;
    ++  WhereLoop *pLoop = pLevel->pWLoop;
    ++  int iCur;
    ++  WhereClause *pWC;
    ++  WhereTerm *pTerm;
    ++  int i, j;
    ++  struct CCurHint sHint;
    ++  Walker sWalker;
    ++
    ++  if( OptimizationDisabled(db, SQLITE_CursorHints) ) return;
    ++  iCur = pLevel->iTabCur;
    ++  assert( iCur==pWInfo->pTabList->a[pLevel->iFrom].iCursor );
    ++  sHint.iTabCur = iCur;
    ++  sHint.iIdxCur = pLevel->iIdxCur;
    ++  sHint.pIdx = pLoop->u.btree.pIndex;
    ++  memset(&sWalker, 0, sizeof(sWalker));
    ++  sWalker.pParse = pParse;
    ++  sWalker.u.pCCurHint = &sHint;
    ++  pWC = &pWInfo->sWC;
    ++  for(i=0; i<pWC->nTerm; i++){
    ++    pTerm = &pWC->a[i];
    ++    if( pTerm->wtFlags & (TERM_VIRTUAL|TERM_CODED) ) continue;
    ++    if( pTerm->prereqAll & pLevel->notReady ) continue;
    ++
    ++    /* Any terms specified as part of the ON(...) clause for any LEFT 
    ++    ** JOIN for which the current table is not the rhs are omitted
    ++    ** from the cursor-hint. 
    ++    **
    ++    ** If this table is the rhs of a LEFT JOIN, "IS" or "IS NULL" terms 
    ++    ** that were specified as part of the WHERE clause must be excluded.
    ++    ** This is to address the following:
    ++    **
    ++    **   SELECT ... t1 LEFT JOIN t2 ON (t1.a=t2.b) WHERE t2.c IS NULL;
    ++    **
    ++    ** Say there is a single row in t2 that matches (t1.a=t2.b), but its
    ++    ** t2.c values is not NULL. If the (t2.c IS NULL) constraint is 
    ++    ** pushed down to the cursor, this row is filtered out, causing
    ++    ** SQLite to synthesize a row of NULL values. Which does match the
    ++    ** WHERE clause, and so the query returns a row. Which is incorrect.
    ++    **
    ++    ** For the same reason, WHERE terms such as:
    ++    **
    ++    **   WHERE 1 = (t2.c IS NULL)
    ++    **
    ++    ** are also excluded. See codeCursorHintIsOrFunction() for details.
    ++    */
    ++    if( pTabItem->fg.jointype & JT_LEFT ){
    ++      Expr *pExpr = pTerm->pExpr;
    ++      if( !ExprHasProperty(pExpr, EP_FromJoin) 
    ++       || pExpr->iRightJoinTable!=pTabItem->iCursor
    ++      ){
    ++        sWalker.eCode = 0;
    ++        sWalker.xExprCallback = codeCursorHintIsOrFunction;
    ++        sqlite3WalkExpr(&sWalker, pTerm->pExpr);
    ++        if( sWalker.eCode ) continue;
    ++      }
    ++    }else{
    ++      if( ExprHasProperty(pTerm->pExpr, EP_FromJoin) ) continue;
    ++    }
    ++
    ++    /* All terms in pWLoop->aLTerm[] except pEndRange are used to initialize
    ++    ** the cursor.  These terms are not needed as hints for a pure range
    ++    ** scan (that has no == terms) so omit them. */
    ++    if( pLoop->u.btree.nEq==0 && pTerm!=pEndRange ){
    ++      for(j=0; j<pLoop->nLTerm && pLoop->aLTerm[j]!=pTerm; j++){}
    ++      if( j<pLoop->nLTerm ) continue;
    ++    }
    ++
    ++    /* No subqueries or non-deterministic functions allowed */
    ++    if( sqlite3ExprContainsSubquery(pTerm->pExpr) ) continue;
    ++
    ++    /* For an index scan, make sure referenced columns are actually in
    ++    ** the index. */
    ++    if( sHint.pIdx!=0 ){
    ++      sWalker.eCode = 0;
    ++      sWalker.xExprCallback = codeCursorHintCheckExpr;
    ++      sqlite3WalkExpr(&sWalker, pTerm->pExpr);
    ++      if( sWalker.eCode ) continue;
    ++    }
    ++
    ++    /* If we survive all prior tests, that means this term is worth hinting */
    ++    pExpr = sqlite3ExprAnd(db, pExpr, sqlite3ExprDup(db, pTerm->pExpr, 0));
    ++  }
    ++  if( pExpr!=0 ){
    ++    sWalker.xExprCallback = codeCursorHintFixExpr;
    ++    sqlite3WalkExpr(&sWalker, pExpr);
    ++    sqlite3VdbeAddOp4(v, OP_CursorHint, 
    ++                      (sHint.pIdx ? sHint.iIdxCur : sHint.iTabCur), 0, 0,
    ++                      (const char*)pExpr, P4_EXPR);
    ++  }
    ++}
    ++#else
    ++# define codeCursorHint(A,B,C,D)  /* No-op */
    ++#endif /* SQLITE_ENABLE_CURSOR_HINTS */
    ++
    ++/*
    ++** Cursor iCur is open on an intkey b-tree (a table). Register iRowid contains
    ++** a rowid value just read from cursor iIdxCur, open on index pIdx. This
    ++** function generates code to do a deferred seek of cursor iCur to the 
    ++** rowid stored in register iRowid.
    ++**
    ++** Normally, this is just:
    ++**
    ++**   OP_DeferredSeek $iCur $iRowid
    ++**
    ++** However, if the scan currently being coded is a branch of an OR-loop and
    ++** the statement currently being coded is a SELECT, then P3 of OP_DeferredSeek
    ++** is set to iIdxCur and P4 is set to point to an array of integers
    ++** containing one entry for each column of the table cursor iCur is open 
    ++** on. For each table column, if the column is the i'th column of the 
    ++** index, then the corresponding array entry is set to (i+1). If the column
    ++** does not appear in the index at all, the array entry is set to 0.
    ++*/
    ++static void codeDeferredSeek(
    ++  WhereInfo *pWInfo,              /* Where clause context */
    ++  Index *pIdx,                    /* Index scan is using */
    ++  int iCur,                       /* Cursor for IPK b-tree */
    ++  int iIdxCur                     /* Index cursor */
    ++){
    ++  Parse *pParse = pWInfo->pParse; /* Parse context */
    ++  Vdbe *v = pParse->pVdbe;        /* Vdbe to generate code within */
    ++
    ++  assert( iIdxCur>0 );
    ++  assert( pIdx->aiColumn[pIdx->nColumn-1]==-1 );
    ++  
    ++  sqlite3VdbeAddOp3(v, OP_DeferredSeek, iIdxCur, 0, iCur);
    ++  if( (pWInfo->wctrlFlags & WHERE_OR_SUBCLAUSE)
    ++   && DbMaskAllZero(sqlite3ParseToplevel(pParse)->writeMask)
    ++  ){
    ++    int i;
    ++    Table *pTab = pIdx->pTable;
    ++    int *ai = (int*)sqlite3DbMallocZero(pParse->db, sizeof(int)*(pTab->nCol+1));
    ++    if( ai ){
    ++      ai[0] = pTab->nCol;
    ++      for(i=0; i<pIdx->nColumn-1; i++){
    ++        assert( pIdx->aiColumn[i]<pTab->nCol );
    ++        if( pIdx->aiColumn[i]>=0 ) ai[pIdx->aiColumn[i]+1] = i+1;
    ++      }
    ++      sqlite3VdbeChangeP4(v, -1, (char*)ai, P4_INTARRAY);
    ++    }
    ++  }
    ++}
    ++
    ++/*
    ++** If the expression passed as the second argument is a vector, generate
    ++** code to write the first nReg elements of the vector into an array
    ++** of registers starting with iReg.
    ++**
    ++** If the expression is not a vector, then nReg must be passed 1. In
    ++** this case, generate code to evaluate the expression and leave the
    ++** result in register iReg.
    ++*/
    ++static void codeExprOrVector(Parse *pParse, Expr *p, int iReg, int nReg){
    ++  assert( nReg>0 );
    ++  if( p && sqlite3ExprIsVector(p) ){
    ++#ifndef SQLITE_OMIT_SUBQUERY
    ++    if( (p->flags & EP_xIsSelect) ){
    ++      Vdbe *v = pParse->pVdbe;
    ++      int iSelect = sqlite3CodeSubselect(pParse, p, 0, 0);
    ++      sqlite3VdbeAddOp3(v, OP_Copy, iSelect, iReg, nReg-1);
    ++    }else
    ++#endif
    ++    {
    ++      int i;
    ++      ExprList *pList = p->x.pList;
    ++      assert( nReg<=pList->nExpr );
    ++      for(i=0; i<nReg; i++){
    ++        sqlite3ExprCode(pParse, pList->a[i].pExpr, iReg+i);
    ++      }
    ++    }
    ++  }else{
    ++    assert( nReg==1 );
    ++    sqlite3ExprCode(pParse, p, iReg);
    +   }
    + }
    + 
    ++/* An instance of the IdxExprTrans object carries information about a
    ++** mapping from an expression on table columns into a column in an index
    ++** down through the Walker.
    ++*/
    ++typedef struct IdxExprTrans {
    ++  Expr *pIdxExpr;    /* The index expression */
    ++  int iTabCur;       /* The cursor of the corresponding table */
    ++  int iIdxCur;       /* The cursor for the index */
    ++  int iIdxCol;       /* The column for the index */
    ++} IdxExprTrans;
    ++
    ++/* The walker node callback used to transform matching expressions into
    ++** a reference to an index column for an index on an expression.
    ++**
    ++** If pExpr matches, then transform it into a reference to the index column
    ++** that contains the value of pExpr.
    ++*/
    ++static int whereIndexExprTransNode(Walker *p, Expr *pExpr){
    ++  IdxExprTrans *pX = p->u.pIdxTrans;
    ++  if( sqlite3ExprCompare(0, pExpr, pX->pIdxExpr, pX->iTabCur)==0 ){
    ++    pExpr->op = TK_COLUMN;
    ++    pExpr->iTable = pX->iIdxCur;
    ++    pExpr->iColumn = pX->iIdxCol;
    ++    pExpr->pTab = 0;
    ++    return WRC_Prune;
    ++  }else{
    ++    return WRC_Continue;
    ++  }
    ++}
    ++
    ++/*
    ++** For an indexes on expression X, locate every instance of expression X
    ++** in pExpr and change that subexpression into a reference to the appropriate
    ++** column of the index.
    ++*/
    ++static void whereIndexExprTrans(
    ++  Index *pIdx,      /* The Index */
    ++  int iTabCur,      /* Cursor of the table that is being indexed */
    ++  int iIdxCur,      /* Cursor of the index itself */
    ++  WhereInfo *pWInfo /* Transform expressions in this WHERE clause */
    ++){
    ++  int iIdxCol;               /* Column number of the index */
    ++  ExprList *aColExpr;        /* Expressions that are indexed */
    ++  Walker w;
    ++  IdxExprTrans x;
    ++  aColExpr = pIdx->aColExpr;
    ++  if( aColExpr==0 ) return;  /* Not an index on expressions */
    ++  memset(&w, 0, sizeof(w));
    ++  w.xExprCallback = whereIndexExprTransNode;
    ++  w.u.pIdxTrans = &x;
    ++  x.iTabCur = iTabCur;
    ++  x.iIdxCur = iIdxCur;
    ++  for(iIdxCol=0; iIdxCol<aColExpr->nExpr; iIdxCol++){
    ++    if( pIdx->aiColumn[iIdxCol]!=XN_EXPR ) continue;
    ++    assert( aColExpr->a[iIdxCol].pExpr!=0 );
    ++    x.iIdxCol = iIdxCol;
    ++    x.pIdxExpr = aColExpr->a[iIdxCol].pExpr;
    ++    sqlite3WalkExpr(&w, pWInfo->pWhere);
    ++    sqlite3WalkExprList(&w, pWInfo->pOrderBy);
    ++    sqlite3WalkExprList(&w, pWInfo->pResultSet);
    ++  }
    ++}
    + 
    + /*
    + ** Generate code for the start of the iLevel-th loop in the WHERE clause
    +@@ -119150,9 +130345,12 @@ SQLITE_PRIVATE Bitmask sqlite3WhereCodeOneLoopStart(
    +   Vdbe *v;                        /* The prepared stmt under constructions */
    +   struct SrcList_item *pTabItem;  /* FROM clause term being coded */
    +   int addrBrk;                    /* Jump here to break out of the loop */
    ++  int addrHalt;                   /* addrBrk for the outermost loop */
    +   int addrCont;                   /* Jump here to continue with next cycle */
    +   int iRowidReg = 0;        /* Rowid is stored in this register, if not zero */
    +   int iReleaseReg = 0;      /* Temp register to free before returning */
    ++  Index *pIdx = 0;          /* Index used by loop (if any) */
    ++  int iLoop;                /* Iteration of constraint generator loop */
    + 
    +   pParse = pWInfo->pParse;
    +   v = pParse->pVdbe;
    +@@ -119165,7 +130363,7 @@ SQLITE_PRIVATE Bitmask sqlite3WhereCodeOneLoopStart(
    +   pLevel->notReady = notReady & ~sqlite3WhereGetMask(&pWInfo->sMaskSet, iCur);
    +   bRev = (pWInfo->revMask>>iLevel)&1;
    +   omitTable = (pLoop->wsFlags & WHERE_IDX_ONLY)!=0 
    +-           && (pWInfo->wctrlFlags & WHERE_FORCE_TABLE)==0;
    ++           && (pWInfo->wctrlFlags & WHERE_OR_SUBCLAUSE)==0;
    +   VdbeModuleComment((v, "Begin WHERE-loop%d: %s",iLevel,pTabItem->pTab->zName));
    + 
    +   /* Create labels for the "break" and "continue" instructions
    +@@ -119191,6 +130389,11 @@ SQLITE_PRIVATE Bitmask sqlite3WhereCodeOneLoopStart(
    +     VdbeComment((v, "init LEFT JOIN no-match flag"));
    +   }
    + 
    ++  /* Compute a safe address to jump to if we discover that the table for
    ++  ** this loop is empty and can never contribute content. */
    ++  for(j=iLevel; j>0 && pWInfo->a[j].iLeftJoin==0; j--){}
    ++  addrHalt = pWInfo->a[j].addrBrk;
    ++
    +   /* Special case of a FROM clause subquery implemented as a co-routine */
    +   if( pTabItem->fg.viaCoroutine ){
    +     int regYield = pTabItem->regReturn;
    +@@ -119209,6 +130412,7 @@ SQLITE_PRIVATE Bitmask sqlite3WhereCodeOneLoopStart(
    +     int iReg;   /* P3 Value for OP_VFilter */
    +     int addrNotFound;
    +     int nConstraint = pLoop->nLTerm;
    ++    int iIn;    /* Counter for IN constraints */
    + 
    +     sqlite3ExprCachePush(pParse);
    +     iReg = sqlite3GetTempRange(pParse, nConstraint+2);
    +@@ -119216,30 +130420,73 @@ SQLITE_PRIVATE Bitmask sqlite3WhereCodeOneLoopStart(
    +     for(j=0; j<nConstraint; j++){
    +       int iTarget = iReg+j+2;
    +       pTerm = pLoop->aLTerm[j];
    +-      if( pTerm==0 ) continue;
    ++      if( NEVER(pTerm==0) ) continue;
    +       if( pTerm->eOperator & WO_IN ){
    +         codeEqualityTerm(pParse, pTerm, pLevel, j, bRev, iTarget);
    +         addrNotFound = pLevel->addrNxt;
    +       }else{
    +-        sqlite3ExprCode(pParse, pTerm->pExpr->pRight, iTarget);
    ++        Expr *pRight = pTerm->pExpr->pRight;
    ++        codeExprOrVector(pParse, pRight, iTarget, 1);
    +       }
    +     }
    +     sqlite3VdbeAddOp2(v, OP_Integer, pLoop->u.vtab.idxNum, iReg);
    +     sqlite3VdbeAddOp2(v, OP_Integer, nConstraint, iReg+1);
    +     sqlite3VdbeAddOp4(v, OP_VFilter, iCur, addrNotFound, iReg,
    +                       pLoop->u.vtab.idxStr,
    +-                      pLoop->u.vtab.needFree ? P4_MPRINTF : P4_STATIC);
    ++                      pLoop->u.vtab.needFree ? P4_DYNAMIC : P4_STATIC);
    +     VdbeCoverage(v);
    +     pLoop->u.vtab.needFree = 0;
    +-    for(j=0; j<nConstraint && j<16; j++){
    +-      if( (pLoop->u.vtab.omitMask>>j)&1 ){
    +-        disableTerm(pLevel, pLoop->aLTerm[j]);
    +-      }
    +-    }
    +     pLevel->p1 = iCur;
    +     pLevel->op = pWInfo->eOnePass ? OP_Noop : OP_VNext;
    +     pLevel->p2 = sqlite3VdbeCurrentAddr(v);
    +-    sqlite3ReleaseTempRange(pParse, iReg, nConstraint+2);
    ++    iIn = pLevel->u.in.nIn;
    ++    for(j=nConstraint-1; j>=0; j--){
    ++      pTerm = pLoop->aLTerm[j];
    ++      if( j<16 && (pLoop->u.vtab.omitMask>>j)&1 ){
    ++        disableTerm(pLevel, pTerm);
    ++      }else if( (pTerm->eOperator & WO_IN)!=0 ){
    ++        Expr *pCompare;  /* The comparison operator */
    ++        Expr *pRight;    /* RHS of the comparison */
    ++        VdbeOp *pOp;     /* Opcode to access the value of the IN constraint */
    ++
    ++        /* Reload the constraint value into reg[iReg+j+2].  The same value
    ++        ** was loaded into the same register prior to the OP_VFilter, but
    ++        ** the xFilter implementation might have changed the datatype or
    ++        ** encoding of the value in the register, so it *must* be reloaded. */
    ++        assert( pLevel->u.in.aInLoop!=0 || db->mallocFailed );
    ++        if( !db->mallocFailed ){
    ++          assert( iIn>0 );
    ++          pOp = sqlite3VdbeGetOp(v, pLevel->u.in.aInLoop[--iIn].addrInTop);
    ++          assert( pOp->opcode==OP_Column || pOp->opcode==OP_Rowid );
    ++          assert( pOp->opcode!=OP_Column || pOp->p3==iReg+j+2 );
    ++          assert( pOp->opcode!=OP_Rowid || pOp->p2==iReg+j+2 );
    ++          testcase( pOp->opcode==OP_Rowid );
    ++          sqlite3VdbeAddOp3(v, pOp->opcode, pOp->p1, pOp->p2, pOp->p3);
    ++        }
    ++
    ++        /* Generate code that will continue to the next row if 
    ++        ** the IN constraint is not satisfied */
    ++        pCompare = sqlite3PExpr(pParse, TK_EQ, 0, 0);
    ++        assert( pCompare!=0 || db->mallocFailed );
    ++        if( pCompare ){
    ++          pCompare->pLeft = pTerm->pExpr->pLeft;
    ++          pCompare->pRight = pRight = sqlite3Expr(db, TK_REGISTER, 0);
    ++          if( pRight ){
    ++            pRight->iTable = iReg+j+2;
    ++            sqlite3ExprIfFalse(pParse, pCompare, pLevel->addrCont, 0);
    ++          }
    ++          pCompare->pLeft = 0;
    ++          sqlite3ExprDelete(db, pCompare);
    ++        }
    ++      }
    ++    }
    ++    /* These registers need to be preserved in case there is an IN operator
    ++    ** loop.  So we could deallocate the registers here (and potentially
    ++    ** reuse them later) if (pLoop->wsFlags & WHERE_IN_ABLE)==0.  But it seems
    ++    ** simpler and safer to simply not reuse the registers.
    ++    **
    ++    **    sqlite3ReleaseTempRange(pParse, iReg, nConstraint+2);
    ++    */
    +     sqlite3ExprCachePop(pParse);
    +   }else
    + #endif /* SQLITE_OMIT_VIRTUALTABLE */
    +@@ -119262,8 +130509,7 @@ SQLITE_PRIVATE Bitmask sqlite3WhereCodeOneLoopStart(
    +     iRowidReg = codeEqualityTerm(pParse, pTerm, pLevel, 0, bRev, iReleaseReg);
    +     if( iRowidReg!=iReleaseReg ) sqlite3ReleaseTempReg(pParse, iReleaseReg);
    +     addrNxt = pLevel->addrNxt;
    +-    sqlite3VdbeAddOp2(v, OP_MustBeInt, iRowidReg, addrNxt); VdbeCoverage(v);
    +-    sqlite3VdbeAddOp3(v, OP_NotExists, iCur, addrNxt, iRowidReg);
    ++    sqlite3VdbeAddOp3(v, OP_SeekRowid, iCur, addrNxt, iRowidReg);
    +     VdbeCoverage(v);
    +     sqlite3ExprCacheAffinityChange(pParse, iRowidReg, 1);
    +     sqlite3ExprCacheStore(pParse, iCur, -1, iRowidReg);
    +@@ -119290,9 +130536,11 @@ SQLITE_PRIVATE Bitmask sqlite3WhereCodeOneLoopStart(
    +       pStart = pEnd;
    +       pEnd = pTerm;
    +     }
    ++    codeCursorHint(pTabItem, pWInfo, pLevel, pEnd);
    +     if( pStart ){
    +       Expr *pX;             /* The expression that defines the start bound */
    +       int r1, rTemp;        /* Registers for holding the start boundary */
    ++      int op;               /* Cursor seek operation */
    + 
    +       /* The following constant maps TK_xx codes into corresponding 
    +       ** seek opcodes.  It depends on a particular ordering of TK_xx
    +@@ -119312,8 +130560,16 @@ SQLITE_PRIVATE Bitmask sqlite3WhereCodeOneLoopStart(
    +       pX = pStart->pExpr;
    +       assert( pX!=0 );
    +       testcase( pStart->leftCursor!=iCur ); /* transitive constraints */
    +-      r1 = sqlite3ExprCodeTemp(pParse, pX->pRight, &rTemp);
    +-      sqlite3VdbeAddOp3(v, aMoveOp[pX->op-TK_GT], iCur, addrBrk, r1);
    ++      if( sqlite3ExprIsVector(pX->pRight) ){
    ++        r1 = rTemp = sqlite3GetTempReg(pParse);
    ++        codeExprOrVector(pParse, pX->pRight, r1, 1);
    ++        op = aMoveOp[(pX->op - TK_GT) | 0x0001];
    ++      }else{
    ++        r1 = sqlite3ExprCodeTemp(pParse, pX->pRight, &rTemp);
    ++        disableTerm(pLevel, pStart);
    ++        op = aMoveOp[(pX->op - TK_GT)];
    ++      }
    ++      sqlite3VdbeAddOp3(v, op, iCur, addrBrk, r1);
    +       VdbeComment((v, "pk"));
    +       VdbeCoverageIf(v, pX->op==TK_GT);
    +       VdbeCoverageIf(v, pX->op==TK_LE);
    +@@ -119321,9 +130577,8 @@ SQLITE_PRIVATE Bitmask sqlite3WhereCodeOneLoopStart(
    +       VdbeCoverageIf(v, pX->op==TK_GE);
    +       sqlite3ExprCacheAffinityChange(pParse, r1, 1);
    +       sqlite3ReleaseTempReg(pParse, rTemp);
    +-      disableTerm(pLevel, pStart);
    +     }else{
    +-      sqlite3VdbeAddOp2(v, bRev ? OP_Last : OP_Rewind, iCur, addrBrk);
    ++      sqlite3VdbeAddOp2(v, bRev ? OP_Last : OP_Rewind, iCur, addrHalt);
    +       VdbeCoverageIf(v, bRev==0);
    +       VdbeCoverageIf(v, bRev!=0);
    +     }
    +@@ -119335,13 +130590,17 @@ SQLITE_PRIVATE Bitmask sqlite3WhereCodeOneLoopStart(
    +       testcase( pEnd->leftCursor!=iCur ); /* Transitive constraints */
    +       testcase( pEnd->wtFlags & TERM_VIRTUAL );
    +       memEndValue = ++pParse->nMem;
    +-      sqlite3ExprCode(pParse, pX->pRight, memEndValue);
    +-      if( pX->op==TK_LT || pX->op==TK_GT ){
    ++      codeExprOrVector(pParse, pX->pRight, memEndValue, 1);
    ++      if( 0==sqlite3ExprIsVector(pX->pRight) 
    ++       && (pX->op==TK_LT || pX->op==TK_GT) 
    ++      ){
    +         testOp = bRev ? OP_Le : OP_Ge;
    +       }else{
    +         testOp = bRev ? OP_Lt : OP_Gt;
    +       }
    +-      disableTerm(pLevel, pEnd);
    ++      if( 0==sqlite3ExprIsVector(pX->pRight) ){
    ++        disableTerm(pLevel, pEnd);
    ++      }
    +     }
    +     start = sqlite3VdbeCurrentAddr(v);
    +     pLevel->op = bRev ? OP_Prev : OP_Next;
    +@@ -119408,6 +130667,8 @@ SQLITE_PRIVATE Bitmask sqlite3WhereCodeOneLoopStart(
    +       OP_IdxLT,            /* 3: (end_constraints &&  bRev &&  endEq) */
    +     };
    +     u16 nEq = pLoop->u.btree.nEq;     /* Number of == or IN terms */
    ++    u16 nBtm = pLoop->u.btree.nBtm;   /* Length of BTM vector */
    ++    u16 nTop = pLoop->u.btree.nTop;   /* Length of TOP vector */
    +     int regBase;                 /* Base register holding constraint values */
    +     WhereTerm *pRangeStart = 0;  /* Inequality constraint at range start */
    +     WhereTerm *pRangeEnd = 0;    /* Inequality constraint at range end */
    +@@ -119415,12 +130676,11 @@ SQLITE_PRIVATE Bitmask sqlite3WhereCodeOneLoopStart(
    +     int endEq;                   /* True if range end uses ==, >= or <= */
    +     int start_constraints;       /* Start of range is constrained */
    +     int nConstraint;             /* Number of constraint terms */
    +-    Index *pIdx;                 /* The index we will be using */
    +     int iIdxCur;                 /* The VDBE cursor for the index */
    +     int nExtraReg = 0;           /* Number of extra registers needed */
    +     int op;                      /* Instruction opcode */
    +     char *zStartAff;             /* Affinity for start of range constraint */
    +-    char cEndAff = 0;            /* Affinity for end of range constraint */
    ++    char *zEndAff = 0;           /* Affinity for end of range constraint */
    +     u8 bSeekPastNull = 0;        /* True to seek past initial nulls */
    +     u8 bStopAtNull = 0;          /* Add condition to terminate at NULLs */
    + 
    +@@ -119454,44 +130714,40 @@ SQLITE_PRIVATE Bitmask sqlite3WhereCodeOneLoopStart(
    +     j = nEq;
    +     if( pLoop->wsFlags & WHERE_BTM_LIMIT ){
    +       pRangeStart = pLoop->aLTerm[j++];
    +-      nExtraReg = 1;
    ++      nExtraReg = MAX(nExtraReg, pLoop->u.btree.nBtm);
    +       /* Like optimization range constraints always occur in pairs */
    +       assert( (pRangeStart->wtFlags & TERM_LIKEOPT)==0 || 
    +               (pLoop->wsFlags & WHERE_TOP_LIMIT)!=0 );
    +     }
    +     if( pLoop->wsFlags & WHERE_TOP_LIMIT ){
    +       pRangeEnd = pLoop->aLTerm[j++];
    +-      nExtraReg = 1;
    ++      nExtraReg = MAX(nExtraReg, pLoop->u.btree.nTop);
    ++#ifndef SQLITE_LIKE_DOESNT_MATCH_BLOBS
    +       if( (pRangeEnd->wtFlags & TERM_LIKEOPT)!=0 ){
    +         assert( pRangeStart!=0 );                     /* LIKE opt constraints */
    +         assert( pRangeStart->wtFlags & TERM_LIKEOPT );   /* occur in pairs */
    +-        pLevel->iLikeRepCntr = ++pParse->nMem;
    +-        testcase( bRev );
    +-        testcase( pIdx->aSortOrder[nEq]==SQLITE_SO_DESC );
    +-        sqlite3VdbeAddOp2(v, OP_Integer,
    +-                          bRev ^ (pIdx->aSortOrder[nEq]==SQLITE_SO_DESC),
    +-                          pLevel->iLikeRepCntr);
    ++        pLevel->iLikeRepCntr = (u32)++pParse->nMem;
    ++        sqlite3VdbeAddOp2(v, OP_Integer, 1, (int)pLevel->iLikeRepCntr);
    +         VdbeComment((v, "LIKE loop counter"));
    +         pLevel->addrLikeRep = sqlite3VdbeCurrentAddr(v);
    ++        /* iLikeRepCntr actually stores 2x the counter register number.  The
    ++        ** bottom bit indicates whether the search order is ASC or DESC. */
    ++        testcase( bRev );
    ++        testcase( pIdx->aSortOrder[nEq]==SQLITE_SO_DESC );
    ++        assert( (bRev & ~1)==0 );
    ++        pLevel->iLikeRepCntr <<=1;
    ++        pLevel->iLikeRepCntr |= bRev ^ (pIdx->aSortOrder[nEq]==SQLITE_SO_DESC);
    +       }
    +-      if( pRangeStart==0
    +-       && (j = pIdx->aiColumn[nEq])>=0 
    +-       && pIdx->pTable->aCol[j].notNull==0
    +-      ){
    +-        bSeekPastNull = 1;
    ++#endif
    ++      if( pRangeStart==0 ){
    ++        j = pIdx->aiColumn[nEq];
    ++        if( (j>=0 && pIdx->pTable->aCol[j].notNull==0) || j==XN_EXPR ){
    ++          bSeekPastNull = 1;
    ++        }
    +       }
    +     }
    +     assert( pRangeEnd==0 || (pRangeEnd->wtFlags & TERM_VNULL)==0 );
    + 
    +-    /* Generate code to evaluate all constraint terms using == or IN
    +-    ** and store the values of those terms in an array of registers
    +-    ** starting at regBase.
    +-    */
    +-    regBase = codeAllEqualityTerms(pParse,pLevel,bRev,nExtraReg,&zStartAff);
    +-    assert( zStartAff==0 || sqlite3Strlen30(zStartAff)>=nEq );
    +-    if( zStartAff ) cEndAff = zStartAff[nEq];
    +-    addrNxt = pLevel->addrNxt;
    +-
    +     /* If we are doing a reverse order scan on an ascending index, or
    +     ** a forward order scan on a descending index, interchange the 
    +     ** start and end terms (pRangeStart and pRangeEnd).
    +@@ -119501,8 +130757,21 @@ SQLITE_PRIVATE Bitmask sqlite3WhereCodeOneLoopStart(
    +     ){
    +       SWAP(WhereTerm *, pRangeEnd, pRangeStart);
    +       SWAP(u8, bSeekPastNull, bStopAtNull);
    ++      SWAP(u8, nBtm, nTop);
    +     }
    + 
    ++    /* Generate code to evaluate all constraint terms using == or IN
    ++    ** and store the values of those terms in an array of registers
    ++    ** starting at regBase.
    ++    */
    ++    codeCursorHint(pTabItem, pWInfo, pLevel, pRangeEnd);
    ++    regBase = codeAllEqualityTerms(pParse,pLevel,bRev,nExtraReg,&zStartAff);
    ++    assert( zStartAff==0 || sqlite3Strlen30(zStartAff)>=nEq );
    ++    if( zStartAff && nTop ){
    ++      zEndAff = sqlite3DbStrDup(db, &zStartAff[nEq]);
    ++    }
    ++    addrNxt = pLevel->addrNxt;
    ++
    +     testcase( pRangeStart && (pRangeStart->eOperator & WO_LE)!=0 );
    +     testcase( pRangeStart && (pRangeStart->eOperator & WO_GE)!=0 );
    +     testcase( pRangeEnd && (pRangeEnd->eOperator & WO_LE)!=0 );
    +@@ -119515,7 +130784,7 @@ SQLITE_PRIVATE Bitmask sqlite3WhereCodeOneLoopStart(
    +     nConstraint = nEq;
    +     if( pRangeStart ){
    +       Expr *pRight = pRangeStart->pExpr->pRight;
    +-      sqlite3ExprCode(pParse, pRight, regBase+nEq);
    ++      codeExprOrVector(pParse, pRight, regBase+nEq, nBtm);
    +       whereLikeOptimizationStringFixup(v, pLevel, pRangeStart);
    +       if( (pRangeStart->wtFlags & TERM_VNULL)==0
    +        && sqlite3ExprCanBeNull(pRight)
    +@@ -119524,18 +130793,16 @@ SQLITE_PRIVATE Bitmask sqlite3WhereCodeOneLoopStart(
    +         VdbeCoverage(v);
    +       }
    +       if( zStartAff ){
    +-        if( sqlite3CompareAffinity(pRight, zStartAff[nEq])==SQLITE_AFF_BLOB){
    +-          /* Since the comparison is to be performed with no conversions
    +-          ** applied to the operands, set the affinity to apply to pRight to 
    +-          ** SQLITE_AFF_BLOB.  */
    +-          zStartAff[nEq] = SQLITE_AFF_BLOB;
    +-        }
    +-        if( sqlite3ExprNeedsNoAffinityChange(pRight, zStartAff[nEq]) ){
    +-          zStartAff[nEq] = SQLITE_AFF_BLOB;
    +-        }
    ++        updateRangeAffinityStr(pRight, nBtm, &zStartAff[nEq]);
    +       }  
    +-      nConstraint++;
    ++      nConstraint += nBtm;
    +       testcase( pRangeStart->wtFlags & TERM_VIRTUAL );
    ++      if( sqlite3ExprIsVector(pRight)==0 ){
    ++        disableTerm(pLevel, pRangeStart);
    ++      }else{
    ++        startEq = 1;
    ++      }
    ++      bSeekPastNull = 0;
    +     }else if( bSeekPastNull ){
    +       sqlite3VdbeAddOp2(v, OP_Null, 0, regBase+nEq);
    +       nConstraint++;
    +@@ -119543,16 +130810,22 @@ SQLITE_PRIVATE Bitmask sqlite3WhereCodeOneLoopStart(
    +       start_constraints = 1;
    +     }
    +     codeApplyAffinity(pParse, regBase, nConstraint - bSeekPastNull, zStartAff);
    +-    op = aStartOp[(start_constraints<<2) + (startEq<<1) + bRev];
    +-    assert( op!=0 );
    +-    sqlite3VdbeAddOp4Int(v, op, iIdxCur, addrNxt, regBase, nConstraint);
    +-    VdbeCoverage(v);
    +-    VdbeCoverageIf(v, op==OP_Rewind);  testcase( op==OP_Rewind );
    +-    VdbeCoverageIf(v, op==OP_Last);    testcase( op==OP_Last );
    +-    VdbeCoverageIf(v, op==OP_SeekGT);  testcase( op==OP_SeekGT );
    +-    VdbeCoverageIf(v, op==OP_SeekGE);  testcase( op==OP_SeekGE );
    +-    VdbeCoverageIf(v, op==OP_SeekLE);  testcase( op==OP_SeekLE );
    +-    VdbeCoverageIf(v, op==OP_SeekLT);  testcase( op==OP_SeekLT );
    ++    if( pLoop->nSkip>0 && nConstraint==pLoop->nSkip ){
    ++      /* The skip-scan logic inside the call to codeAllEqualityConstraints()
    ++      ** above has already left the cursor sitting on the correct row,
    ++      ** so no further seeking is needed */
    ++    }else{
    ++      op = aStartOp[(start_constraints<<2) + (startEq<<1) + bRev];
    ++      assert( op!=0 );
    ++      sqlite3VdbeAddOp4Int(v, op, iIdxCur, addrNxt, regBase, nConstraint);
    ++      VdbeCoverage(v);
    ++      VdbeCoverageIf(v, op==OP_Rewind);  testcase( op==OP_Rewind );
    ++      VdbeCoverageIf(v, op==OP_Last);    testcase( op==OP_Last );
    ++      VdbeCoverageIf(v, op==OP_SeekGT);  testcase( op==OP_SeekGT );
    ++      VdbeCoverageIf(v, op==OP_SeekGE);  testcase( op==OP_SeekGE );
    ++      VdbeCoverageIf(v, op==OP_SeekLE);  testcase( op==OP_SeekLE );
    ++      VdbeCoverageIf(v, op==OP_SeekLT);  testcase( op==OP_SeekLT );
    ++    }
    + 
    +     /* Load the value for the inequality constraint at the end of the
    +     ** range (if any).
    +@@ -119561,7 +130834,7 @@ SQLITE_PRIVATE Bitmask sqlite3WhereCodeOneLoopStart(
    +     if( pRangeEnd ){
    +       Expr *pRight = pRangeEnd->pExpr->pRight;
    +       sqlite3ExprCacheRemove(pParse, regBase+nEq, 1);
    +-      sqlite3ExprCode(pParse, pRight, regBase+nEq);
    ++      codeExprOrVector(pParse, pRight, regBase+nEq, nTop);
    +       whereLikeOptimizationStringFixup(v, pLevel, pRangeEnd);
    +       if( (pRangeEnd->wtFlags & TERM_VNULL)==0
    +        && sqlite3ExprCanBeNull(pRight)
    +@@ -119569,19 +130842,28 @@ SQLITE_PRIVATE Bitmask sqlite3WhereCodeOneLoopStart(
    +         sqlite3VdbeAddOp2(v, OP_IsNull, regBase+nEq, addrNxt);
    +         VdbeCoverage(v);
    +       }
    +-      if( sqlite3CompareAffinity(pRight, cEndAff)!=SQLITE_AFF_BLOB
    +-       && !sqlite3ExprNeedsNoAffinityChange(pRight, cEndAff)
    +-      ){
    +-        codeApplyAffinity(pParse, regBase+nEq, 1, &cEndAff);
    ++      if( zEndAff ){
    ++        updateRangeAffinityStr(pRight, nTop, zEndAff);
    ++        codeApplyAffinity(pParse, regBase+nEq, nTop, zEndAff);
    ++      }else{
    ++        assert( pParse->db->mallocFailed );
    +       }
    +-      nConstraint++;
    ++      nConstraint += nTop;
    +       testcase( pRangeEnd->wtFlags & TERM_VIRTUAL );
    ++
    ++      if( sqlite3ExprIsVector(pRight)==0 ){
    ++        disableTerm(pLevel, pRangeEnd);
    ++      }else{
    ++        endEq = 1;
    ++      }
    +     }else if( bStopAtNull ){
    +       sqlite3VdbeAddOp2(v, OP_Null, 0, regBase+nEq);
    ++      sqlite3ExprCacheRemove(pParse, regBase+nEq, 1);
    +       endEq = 0;
    +       nConstraint++;
    +     }
    +     sqlite3DbFree(db, zStartAff);
    ++    sqlite3DbFree(db, zEndAff);
    + 
    +     /* Top of the loop body */
    +     pLevel->p2 = sqlite3VdbeCurrentAddr(v);
    +@@ -119597,19 +130879,20 @@ SQLITE_PRIVATE Bitmask sqlite3WhereCodeOneLoopStart(
    +     }
    + 
    +     /* Seek the table cursor, if required */
    +-    disableTerm(pLevel, pRangeStart);
    +-    disableTerm(pLevel, pRangeEnd);
    +     if( omitTable ){
    +       /* pIdx is a covering index.  No need to access the main table. */
    +     }else if( HasRowid(pIdx->pTable) ){
    +-      iRowidReg = ++pParse->nMem;
    +-      sqlite3VdbeAddOp2(v, OP_IdxRowid, iIdxCur, iRowidReg);
    +-      sqlite3ExprCacheStore(pParse, iCur, -1, iRowidReg);
    +-      if( pWInfo->eOnePass!=ONEPASS_OFF ){
    ++      if( (pWInfo->wctrlFlags & WHERE_SEEK_TABLE) || (
    ++          (pWInfo->wctrlFlags & WHERE_SEEK_UNIQ_TABLE) 
    ++       && (pWInfo->eOnePass==ONEPASS_SINGLE)
    ++      )){
    ++        iRowidReg = ++pParse->nMem;
    ++        sqlite3VdbeAddOp2(v, OP_IdxRowid, iIdxCur, iRowidReg);
    ++        sqlite3ExprCacheStore(pParse, iCur, -1, iRowidReg);
    +         sqlite3VdbeAddOp3(v, OP_NotExists, iCur, 0, iRowidReg);
    +         VdbeCoverage(v);
    +       }else{
    +-        sqlite3VdbeAddOp2(v, OP_Seek, iCur, iRowidReg);  /* Deferred seek */
    ++        codeDeferredSeek(pWInfo, pIdx, iCur, iIdxCur);
    +       }
    +     }else if( iCur!=iIdxCur ){
    +       Index *pPk = sqlite3PrimaryKeyIndex(pIdx->pTable);
    +@@ -119622,9 +130905,14 @@ SQLITE_PRIVATE Bitmask sqlite3WhereCodeOneLoopStart(
    +                            iRowidReg, pPk->nKeyCol); VdbeCoverage(v);
    +     }
    + 
    +-    /* Record the instruction used to terminate the loop. Disable 
    +-    ** WHERE clause terms made redundant by the index range scan.
    ++    /* If pIdx is an index on one or more expressions, then look through
    ++    ** all the expressions in pWInfo and try to transform matching expressions
    ++    ** into reference to index columns.
    +     */
    ++    whereIndexExprTrans(pIdx, iCur, iIdxCur, pWInfo);
    ++
    ++
    ++    /* Record the instruction used to terminate the loop. */
    +     if( pLoop->wsFlags & WHERE_ONEROW ){
    +       pLevel->op = OP_Noop;
    +     }else if( bRev ){
    +@@ -119639,6 +130927,7 @@ SQLITE_PRIVATE Bitmask sqlite3WhereCodeOneLoopStart(
    +     }else{
    +       assert( pLevel->p5==0 );
    +     }
    ++    if( omitTable ) pIdx = 0;
    +   }else
    + 
    + #ifndef SQLITE_OMIT_OR_OPTIMIZATION
    +@@ -119701,7 +130990,7 @@ SQLITE_PRIVATE Bitmask sqlite3WhereCodeOneLoopStart(
    +     u16 wctrlFlags;                    /* Flags for sub-WHERE clause */
    +     Expr *pAndExpr = 0;                /* An ".. AND (...)" expression */
    +     Table *pTab = pTabItem->pTab;
    +-   
    ++
    +     pTerm = pLoop->aLTerm[0];
    +     assert( pTerm!=0 );
    +     assert( pTerm->eOperator & WO_OR );
    +@@ -119778,14 +131067,16 @@ SQLITE_PRIVATE Bitmask sqlite3WhereCodeOneLoopStart(
    +         Expr *pExpr = pWC->a[iTerm].pExpr;
    +         if( &pWC->a[iTerm] == pTerm ) continue;
    +         if( ExprHasProperty(pExpr, EP_FromJoin) ) continue;
    +-        if( (pWC->a[iTerm].wtFlags & TERM_VIRTUAL)!=0 ) continue;
    ++        testcase( pWC->a[iTerm].wtFlags & TERM_VIRTUAL );
    ++        testcase( pWC->a[iTerm].wtFlags & TERM_CODED );
    ++        if( (pWC->a[iTerm].wtFlags & (TERM_VIRTUAL|TERM_CODED))!=0 ) continue;
    +         if( (pWC->a[iTerm].eOperator & WO_ALL)==0 ) continue;
    +         testcase( pWC->a[iTerm].wtFlags & TERM_ORINFO );
    +         pExpr = sqlite3ExprDup(db, pExpr, 0);
    +         pAndExpr = sqlite3ExprAnd(db, pAndExpr, pExpr);
    +       }
    +       if( pAndExpr ){
    +-        pAndExpr = sqlite3PExpr(pParse, TK_AND, 0, pAndExpr, 0);
    ++        pAndExpr = sqlite3PExpr(pParse, TK_AND|TKFLG_DONTFOLD, 0, pAndExpr);
    +       }
    +     }
    + 
    +@@ -119793,10 +131084,7 @@ SQLITE_PRIVATE Bitmask sqlite3WhereCodeOneLoopStart(
    +     ** 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_FORCE_TABLE
    +-                | WHERE_ONETABLE_ONLY
    +-                | WHERE_NO_AUTOINDEX;
    ++    wctrlFlags =  WHERE_OR_SUBCLAUSE | (pWInfo->wctrlFlags & WHERE_SEEK_TABLE);
    +     for(ii=0; ii<pOrWc->nTerm; ii++){
    +       WhereTerm *pOrTerm = &pOrWc->a[ii];
    +       if( pOrTerm->leftCursor==iCur || (pOrTerm->eOperator & WO_AND)!=0 ){
    +@@ -119841,11 +131129,7 @@ SQLITE_PRIVATE Bitmask sqlite3WhereCodeOneLoopStart(
    +               r = sqlite3GetTempRange(pParse, nPk);
    +               for(iPk=0; iPk<nPk; iPk++){
    +                 int iCol = pPk->aiColumn[iPk];
    +-                int rx;
    +-                rx = sqlite3ExprCodeGetColumn(pParse, pTab, iCol, iCur,r+iPk,0);
    +-                if( rx!=r+iPk ){
    +-                  sqlite3VdbeAddOp2(v, OP_SCopy, rx, r+iPk);
    +-                }
    ++                sqlite3ExprCodeGetColumnToReg(pParse, pTab, iCol, iCur, r+iPk);
    +               }
    + 
    +               /* Check if the temp table already contains this key. If so,
    +@@ -119865,7 +131149,8 @@ SQLITE_PRIVATE Bitmask sqlite3WhereCodeOneLoopStart(
    +               }
    +               if( iSet>=0 ){
    +                 sqlite3VdbeAddOp3(v, OP_MakeRecord, r, nPk, regRowid);
    +-                sqlite3VdbeAddOp3(v, OP_IdxInsert, regRowset, regRowid, 0);
    ++                sqlite3VdbeAddOp4Int(v, OP_IdxInsert, regRowset, regRowid,
    ++                                     r, nPk);
    +                 if( iSet ) sqlite3VdbeChangeP5(v, OPFLAG_USESEEKRESULT);
    +               }
    + 
    +@@ -119908,7 +131193,6 @@ SQLITE_PRIVATE Bitmask sqlite3WhereCodeOneLoopStart(
    +           ){
    +             assert( pSubWInfo->a[0].iIdxCur==iCovCur );
    +             pCov = pSubLoop->u.btree.pIndex;
    +-            wctrlFlags |= WHERE_REOPEN_IDX;
    +           }else{
    +             pCov = 0;
    +           }
    +@@ -119945,9 +131229,10 @@ SQLITE_PRIVATE Bitmask sqlite3WhereCodeOneLoopStart(
    +       ** a pseudo-cursor.  No need to Rewind or Next such cursors. */
    +       pLevel->op = OP_Noop;
    +     }else{
    ++      codeCursorHint(pTabItem, pWInfo, pLevel, 0);
    +       pLevel->op = aStep[bRev];
    +       pLevel->p1 = iCur;
    +-      pLevel->p2 = 1 + sqlite3VdbeAddOp2(v, aStart[bRev], iCur, addrBrk);
    ++      pLevel->p2 = 1 + sqlite3VdbeAddOp2(v, aStart[bRev], iCur, addrHalt);
    +       VdbeCoverageIf(v, bRev==0);
    +       VdbeCoverageIf(v, bRev!=0);
    +       pLevel->p5 = SQLITE_STMTSTATUS_FULLSCAN_STEP;
    +@@ -119960,33 +131245,75 @@ SQLITE_PRIVATE Bitmask sqlite3WhereCodeOneLoopStart(
    + 
    +   /* Insert code to test every subexpression that can be completely
    +   ** computed using the current set of tables.
    ++  **
    ++  ** This loop may run between one and three times, depending on the
    ++  ** constraints to be generated. The value of stack variable iLoop
    ++  ** determines the constraints coded by each iteration, as follows:
    ++  **
    ++  ** iLoop==1: Code only expressions that are entirely covered by pIdx.
    ++  ** iLoop==2: Code remaining expressions that do not contain correlated
    ++  **           sub-queries.  
    ++  ** iLoop==3: Code all remaining expressions.
    ++  **
    ++  ** An effort is made to skip unnecessary iterations of the loop.
    +   */
    +-  for(pTerm=pWC->a, j=pWC->nTerm; j>0; j--, pTerm++){
    +-    Expr *pE;
    +-    int skipLikeAddr = 0;
    +-    testcase( pTerm->wtFlags & TERM_VIRTUAL );
    +-    testcase( pTerm->wtFlags & TERM_CODED );
    +-    if( pTerm->wtFlags & (TERM_VIRTUAL|TERM_CODED) ) continue;
    +-    if( (pTerm->prereqAll & pLevel->notReady)!=0 ){
    +-      testcase( pWInfo->untestedTerms==0
    +-               && (pWInfo->wctrlFlags & WHERE_ONETABLE_ONLY)!=0 );
    +-      pWInfo->untestedTerms = 1;
    +-      continue;
    +-    }
    +-    pE = pTerm->pExpr;
    +-    assert( pE!=0 );
    +-    if( pLevel->iLeftJoin && !ExprHasProperty(pE, EP_FromJoin) ){
    +-      continue;
    +-    }
    +-    if( pTerm->wtFlags & TERM_LIKECOND ){
    +-      assert( pLevel->iLikeRepCntr>0 );
    +-      skipLikeAddr = sqlite3VdbeAddOp1(v, OP_IfNot, pLevel->iLikeRepCntr);
    +-      VdbeCoverage(v);
    ++  iLoop = (pIdx ? 1 : 2);
    ++  do{
    ++    int iNext = 0;                /* Next value for iLoop */
    ++    for(pTerm=pWC->a, j=pWC->nTerm; j>0; j--, pTerm++){
    ++      Expr *pE;
    ++      int skipLikeAddr = 0;
    ++      testcase( pTerm->wtFlags & TERM_VIRTUAL );
    ++      testcase( pTerm->wtFlags & TERM_CODED );
    ++      if( pTerm->wtFlags & (TERM_VIRTUAL|TERM_CODED) ) continue;
    ++      if( (pTerm->prereqAll & pLevel->notReady)!=0 ){
    ++        testcase( pWInfo->untestedTerms==0
    ++            && (pWInfo->wctrlFlags & WHERE_OR_SUBCLAUSE)!=0 );
    ++        pWInfo->untestedTerms = 1;
    ++        continue;
    ++      }
    ++      pE = pTerm->pExpr;
    ++      assert( pE!=0 );
    ++      if( pLevel->iLeftJoin && !ExprHasProperty(pE, EP_FromJoin) ){
    ++        continue;
    ++      }
    ++      
    ++      if( iLoop==1 && !sqlite3ExprCoveredByIndex(pE, pLevel->iTabCur, pIdx) ){
    ++        iNext = 2;
    ++        continue;
    ++      }
    ++      if( iLoop<3 && (pTerm->wtFlags & TERM_VARSELECT) ){
    ++        if( iNext==0 ) iNext = 3;
    ++        continue;
    ++      }
    ++
    ++      if( pTerm->wtFlags & TERM_LIKECOND ){
    ++        /* If the TERM_LIKECOND flag is set, that means that the range search
    ++        ** is sufficient to guarantee that the LIKE operator is true, so we
    ++        ** can skip the call to the like(A,B) function.  But this only works
    ++        ** for strings.  So do not skip the call to the function on the pass
    ++        ** that compares BLOBs. */
    ++#ifdef SQLITE_LIKE_DOESNT_MATCH_BLOBS
    ++        continue;
    ++#else
    ++        u32 x = pLevel->iLikeRepCntr;
    ++        assert( x>0 );
    ++        skipLikeAddr = sqlite3VdbeAddOp1(v, (x&1)?OP_IfNot:OP_If, (int)(x>>1));
    ++        VdbeCoverage(v);
    ++#endif
    ++      }
    ++#ifdef WHERETRACE_ENABLED /* 0xffff */
    ++      if( sqlite3WhereTrace ){
    ++        VdbeNoopComment((v, "WhereTerm[%d] (%p) priority=%d",
    ++                         pWC->nTerm-j, pTerm, iLoop));
    ++      }
    ++#endif
    ++      sqlite3ExprIfFalse(pParse, pE, addrCont, SQLITE_JUMPIFNULL);
    ++      if( skipLikeAddr ) sqlite3VdbeJumpHere(v, skipLikeAddr);
    ++      pTerm->wtFlags |= TERM_CODED;
    +     }
    +-    sqlite3ExprIfFalse(pParse, pE, addrCont, SQLITE_JUMPIFNULL);
    +-    if( skipLikeAddr ) sqlite3VdbeJumpHere(v, skipLikeAddr);
    +-    pTerm->wtFlags |= TERM_CODED;
    +-  }
    ++    iLoop = iNext;
    ++  }while( iLoop>0 );
    + 
    +   /* Insert code to test for implied constraints based on transitivity
    +   ** of the "==" operator.
    +@@ -119997,7 +131324,7 @@ SQLITE_PRIVATE Bitmask sqlite3WhereCodeOneLoopStart(
    +   ** the implied "t1.a=123" constraint.
    +   */
    +   for(pTerm=pWC->a, j=pWC->nTerm; j>0; j--, pTerm++){
    +-    Expr *pE, *pEAlt;
    ++    Expr *pE, sEAlt;
    +     WhereTerm *pAlt;
    +     if( pTerm->wtFlags & (TERM_VIRTUAL|TERM_CODED) ) continue;
    +     if( (pTerm->eOperator & (WO_EQ|WO_IS))==0 ) continue;
    +@@ -120015,13 +131342,9 @@ SQLITE_PRIVATE Bitmask sqlite3WhereCodeOneLoopStart(
    +     testcase( pAlt->eOperator & WO_IS );
    +     testcase( pAlt->eOperator & WO_IN );
    +     VdbeModuleComment((v, "begin transitive constraint"));
    +-    pEAlt = sqlite3StackAllocRaw(db, sizeof(*pEAlt));
    +-    if( pEAlt ){
    +-      *pEAlt = *pAlt->pExpr;
    +-      pEAlt->pLeft = pE->pLeft;
    +-      sqlite3ExprIfFalse(pParse, pEAlt, addrCont, SQLITE_JUMPIFNULL);
    +-      sqlite3StackFree(db, pEAlt);
    +-    }
    ++    sEAlt = *pAlt->pExpr;
    ++    sEAlt.pLeft = pE->pLeft;
    ++    sqlite3ExprIfFalse(pParse, &sEAlt, addrCont, SQLITE_JUMPIFNULL);
    +   }
    + 
    +   /* For a LEFT OUTER JOIN, generate code that will record the fact that
    +@@ -120117,7 +131440,7 @@ static int whereClauseInsert(WhereClause *pWC, Expr *p, u16 wtFlags){
    +   if( pWC->nTerm>=pWC->nSlot ){
    +     WhereTerm *pOld = pWC->a;
    +     sqlite3 *db = pWC->pWInfo->pParse->db;
    +-    pWC->a = sqlite3DbMallocRaw(db, sizeof(pWC->a[0])*pWC->nSlot*2 );
    ++    pWC->a = sqlite3DbMallocRawNN(db, sizeof(pWC->a[0])*pWC->nSlot*2 );
    +     if( pWC->a==0 ){
    +       if( wtFlags & TERM_DYNAMIC ){
    +         sqlite3ExprDelete(db, p);
    +@@ -120130,7 +131453,6 @@ static int whereClauseInsert(WhereClause *pWC, Expr *p, u16 wtFlags){
    +       sqlite3DbFree(db, pOld);
    +     }
    +     pWC->nSlot = sqlite3DbMallocSize(db, pWC->a)/sizeof(pWC->a[0]);
    +-    memset(&pWC->a[pWC->nTerm], 0, sizeof(pWC->a[0])*(pWC->nSlot-pWC->nTerm));
    +   }
    +   pTerm = &pWC->a[idx = pWC->nTerm++];
    +   if( p && ExprHasProperty(p, EP_Unlikely) ){
    +@@ -120142,13 +131464,15 @@ static int whereClauseInsert(WhereClause *pWC, Expr *p, u16 wtFlags){
    +   pTerm->wtFlags = wtFlags;
    +   pTerm->pWC = pWC;
    +   pTerm->iParent = -1;
    ++  memset(&pTerm->eOperator, 0,
    ++         sizeof(WhereTerm) - offsetof(WhereTerm,eOperator));
    +   return idx;
    + }
    + 
    + /*
    + ** Return TRUE if the given operator is one of the operators that is
    + ** allowed for an indexable WHERE clause term.  The allowed operators are
    +-** "=", "<", ">", "<=", ">=", "IN", and "IS NULL"
    ++** "=", "<", ">", "<=", ">=", "IN", "IS", and "IS NULL"
    + */
    + static int allowedOp(int op){
    +   assert( TK_GT>TK_EQ && TK_GT<TK_GE );
    +@@ -120246,15 +131570,16 @@ static int isLikeOrGlob(
    +   int *pisComplete, /* True if the only wildcard is % in the last character */
    +   int *pnoCase      /* True if uppercase is equivalent to lowercase */
    + ){
    +-  const char *z = 0;         /* String on RHS of LIKE operator */
    ++  const u8 *z = 0;         /* String on RHS of LIKE operator */
    +   Expr *pRight, *pLeft;      /* Right and left size of LIKE operator */
    +   ExprList *pList;           /* List of operands to the LIKE operator */
    +   int c;                     /* One character in z[] */
    +   int cnt;                   /* Number of non-wildcard prefix characters */
    +-  char wc[3];                /* Wildcard characters */
    ++  char wc[4];                /* Wildcard characters */
    +   sqlite3 *db = pParse->db;  /* Database connection */
    +   sqlite3_value *pVal = 0;
    +   int op;                    /* Opcode of pRight */
    ++  int rc;                    /* Result code to return */
    + 
    +   if( !sqlite3IsLikeFunction(db, pExpr, pnoCase, wc) ){
    +     return 0;
    +@@ -120264,41 +131589,75 @@ static int isLikeOrGlob(
    + #endif
    +   pList = pExpr->x.pList;
    +   pLeft = pList->a[1].pExpr;
    +-  if( pLeft->op!=TK_COLUMN 
    +-   || sqlite3ExprAffinity(pLeft)!=SQLITE_AFF_TEXT 
    +-   || IsVirtual(pLeft->pTab)  /* Value might be numeric */
    +-  ){
    +-    /* IMP: R-02065-49465 The left-hand side of the LIKE or GLOB operator must
    +-    ** be the name of an indexed column with TEXT affinity. */
    +-    return 0;
    +-  }
    +-  assert( pLeft->iColumn!=(-1) ); /* Because IPK never has AFF_TEXT */
    + 
    +   pRight = sqlite3ExprSkipCollate(pList->a[0].pExpr);
    +   op = pRight->op;
    +-  if( op==TK_VARIABLE ){
    ++  if( op==TK_VARIABLE && (db->flags & SQLITE_EnableQPSG)==0 ){
    +     Vdbe *pReprepare = pParse->pReprepare;
    +     int iCol = pRight->iColumn;
    +     pVal = sqlite3VdbeGetBoundValue(pReprepare, iCol, SQLITE_AFF_BLOB);
    +     if( pVal && sqlite3_value_type(pVal)==SQLITE_TEXT ){
    +-      z = (char *)sqlite3_value_text(pVal);
    ++      z = sqlite3_value_text(pVal);
    +     }
    +     sqlite3VdbeSetVarmask(pParse->pVdbe, iCol);
    +     assert( pRight->op==TK_VARIABLE || pRight->op==TK_REGISTER );
    +   }else if( op==TK_STRING ){
    +-    z = pRight->u.zToken;
    ++    z = (u8*)pRight->u.zToken;
    +   }
    +   if( z ){
    ++
    ++    /* If the RHS begins with a digit or a minus sign, then the LHS must
    ++    ** be an ordinary column (not a virtual table column) with TEXT affinity.
    ++    ** Otherwise the LHS might be numeric and "lhs >= rhs" would be false
    ++    ** even though "lhs LIKE rhs" is true.  But if the RHS does not start
    ++    ** with a digit or '-', then "lhs LIKE rhs" will always be false if
    ++    ** the LHS is numeric and so the optimization still works.
    ++    */
    ++    if( sqlite3Isdigit(z[0]) || z[0]=='-' ){
    ++      if( pLeft->op!=TK_COLUMN 
    ++       || sqlite3ExprAffinity(pLeft)!=SQLITE_AFF_TEXT 
    ++       || IsVirtual(pLeft->pTab)  /* Value might be numeric */
    ++      ){
    ++        sqlite3ValueFree(pVal);
    ++        return 0;
    ++      }
    ++    }
    ++
    ++    /* Count the number of prefix characters prior to the first wildcard */
    +     cnt = 0;
    +     while( (c=z[cnt])!=0 && c!=wc[0] && c!=wc[1] && c!=wc[2] ){
    +       cnt++;
    ++      if( c==wc[3] && z[cnt]!=0 ) cnt++;
    +     }
    ++
    ++    /* The optimization is possible only if (1) the pattern does not begin
    ++    ** with a wildcard and if (2) the non-wildcard prefix does not end with
    ++    ** an (illegal 0xff) character.  The second condition is necessary so
    ++    ** that we can increment the prefix key to find an upper bound for the
    ++    ** range search. 
    ++    */
    +     if( cnt!=0 && 255!=(u8)z[cnt-1] ){
    +       Expr *pPrefix;
    ++
    ++      /* A "complete" match if the pattern ends with "*" or "%" */
    +       *pisComplete = c==wc[0] && z[cnt+1]==0;
    +-      pPrefix = sqlite3Expr(db, TK_STRING, z);
    +-      if( pPrefix ) pPrefix->u.zToken[cnt] = 0;
    ++
    ++      /* Get the pattern prefix.  Remove all escapes from the prefix. */
    ++      pPrefix = sqlite3Expr(db, TK_STRING, (char*)z);
    ++      if( pPrefix ){
    ++        int iFrom, iTo;
    ++        char *zNew = pPrefix->u.zToken;
    ++        zNew[cnt] = 0;
    ++        for(iFrom=iTo=0; iFrom<cnt; iFrom++){
    ++          if( zNew[iFrom]==wc[3] ) iFrom++;
    ++          zNew[iTo++] = zNew[iFrom];
    ++        }
    ++        zNew[iTo] = 0;
    ++      }
    +       *ppPrefix = pPrefix;
    ++
    ++      /* If the RHS pattern is a bound parameter, make arrangements to
    ++      ** reprepare the statement when that parameter is rebound */
    +       if( op==TK_VARIABLE ){
    +         Vdbe *v = pParse->pVdbe;
    +         sqlite3VdbeSetVarmask(v, pRight->iColumn);
    +@@ -120320,39 +131679,95 @@ static int isLikeOrGlob(
    +     }
    +   }
    + 
    ++  rc = (z!=0);
    +   sqlite3ValueFree(pVal);
    +-  return (z!=0);
    ++  return rc;
    + }
    + #endif /* SQLITE_OMIT_LIKE_OPTIMIZATION */
    + 
    + 
    + #ifndef SQLITE_OMIT_VIRTUALTABLE
    + /*
    +-** Check to see if the given expression is of the form
    +-**
    +-**         column MATCH expr
    +-**
    +-** If it is then return TRUE.  If not, return FALSE.
    +-*/
    +-static int isMatchOfColumn(
    +-  Expr *pExpr      /* Test this expression */
    +-){
    +-  ExprList *pList;
    ++** Check to see if the pExpr expression is a form that needs to be passed
    ++** to the xBestIndex method of virtual tables.  Forms of interest include:
    ++**
    ++**          Expression                   Virtual Table Operator
    ++**          -----------------------      ---------------------------------
    ++**      1.  column MATCH expr            SQLITE_INDEX_CONSTRAINT_MATCH
    ++**      2.  column GLOB expr             SQLITE_INDEX_CONSTRAINT_GLOB
    ++**      3.  column LIKE expr             SQLITE_INDEX_CONSTRAINT_LIKE
    ++**      4.  column REGEXP expr           SQLITE_INDEX_CONSTRAINT_REGEXP
    ++**      5.  column != expr               SQLITE_INDEX_CONSTRAINT_NE
    ++**      6.  expr != column               SQLITE_INDEX_CONSTRAINT_NE
    ++**      7.  column IS NOT expr           SQLITE_INDEX_CONSTRAINT_ISNOT
    ++**      8.  expr IS NOT column           SQLITE_INDEX_CONSTRAINT_ISNOT
    ++**      9.  column IS NOT NULL           SQLITE_INDEX_CONSTRAINT_ISNOTNULL
    ++**
    ++** In every case, "column" must be a column of a virtual table.  If there
    ++** is a match, set *ppLeft to the "column" expression, set *ppRight to the 
    ++** "expr" expression (even though in forms (6) and (8) the column is on the
    ++** right and the expression is on the left).  Also set *peOp2 to the
    ++** appropriate virtual table operator.  The return value is 1 or 2 if there
    ++** is a match.  The usual return is 1, but if the RHS is also a column
    ++** of virtual table in forms (5) or (7) then return 2.
    ++**
    ++** If the expression matches none of the patterns above, return 0.
    ++*/
    ++static int isAuxiliaryVtabOperator(
    ++  Expr *pExpr,                    /* Test this expression */
    ++  unsigned char *peOp2,           /* OUT: 0 for MATCH, or else an op2 value */
    ++  Expr **ppLeft,                  /* Column expression to left of MATCH/op2 */
    ++  Expr **ppRight                  /* Expression to left of MATCH/op2 */
    ++){
    ++  if( pExpr->op==TK_FUNCTION ){
    ++    static const struct Op2 {
    ++      const char *zOp;
    ++      unsigned char eOp2;
    ++    } aOp[] = {
    ++      { "match",  SQLITE_INDEX_CONSTRAINT_MATCH },
    ++      { "glob",   SQLITE_INDEX_CONSTRAINT_GLOB },
    ++      { "like",   SQLITE_INDEX_CONSTRAINT_LIKE },
    ++      { "regexp", SQLITE_INDEX_CONSTRAINT_REGEXP }
    ++    };
    ++    ExprList *pList;
    ++    Expr *pCol;                     /* Column reference */
    ++    int i;
    + 
    +-  if( pExpr->op!=TK_FUNCTION ){
    +-    return 0;
    +-  }
    +-  if( sqlite3StrICmp(pExpr->u.zToken,"match")!=0 ){
    +-    return 0;
    +-  }
    +-  pList = pExpr->x.pList;
    +-  if( pList->nExpr!=2 ){
    +-    return 0;
    +-  }
    +-  if( pList->a[1].pExpr->op != TK_COLUMN ){
    +-    return 0;
    ++    pList = pExpr->x.pList;
    ++    if( pList==0 || pList->nExpr!=2 ){
    ++      return 0;
    ++    }
    ++    pCol = pList->a[1].pExpr;
    ++    if( pCol->op!=TK_COLUMN || !IsVirtual(pCol->pTab) ){
    ++      return 0;
    ++    }
    ++    for(i=0; i<ArraySize(aOp); i++){
    ++      if( sqlite3StrICmp(pExpr->u.zToken, aOp[i].zOp)==0 ){
    ++        *peOp2 = aOp[i].eOp2;
    ++        *ppRight = pList->a[0].pExpr;
    ++        *ppLeft = pCol;
    ++        return 1;
    ++      }
    ++    }
    ++  }else if( pExpr->op==TK_NE || pExpr->op==TK_ISNOT || pExpr->op==TK_NOTNULL ){
    ++    int res = 0;
    ++    Expr *pLeft = pExpr->pLeft;
    ++    Expr *pRight = pExpr->pRight;
    ++    if( pLeft->op==TK_COLUMN && IsVirtual(pLeft->pTab) ){
    ++      res++;
    ++    }
    ++    if( pRight && pRight->op==TK_COLUMN && IsVirtual(pRight->pTab) ){
    ++      res++;
    ++      SWAP(Expr*, pLeft, pRight);
    ++    }
    ++    *ppLeft = pLeft;
    ++    *ppRight = pRight;
    ++    if( pExpr->op==TK_NE ) *peOp2 = SQLITE_INDEX_CONSTRAINT_NE;
    ++    if( pExpr->op==TK_ISNOT ) *peOp2 = SQLITE_INDEX_CONSTRAINT_ISNOT;
    ++    if( pExpr->op==TK_NOTNULL ) *peOp2 = SQLITE_INDEX_CONSTRAINT_ISNOTNULL;
    ++    return res;
    +   }
    +-  return 1;
    ++  return 0;
    + }
    + #endif /* SQLITE_OMIT_VIRTUALTABLE */
    + 
    +@@ -120429,8 +131844,8 @@ static void whereCombineDisjuncts(
    +    && (eOp & (WO_EQ|WO_GT|WO_GE))!=eOp ) return;
    +   assert( pOne->pExpr->pLeft!=0 && pOne->pExpr->pRight!=0 );
    +   assert( pTwo->pExpr->pLeft!=0 && pTwo->pExpr->pRight!=0 );
    +-  if( sqlite3ExprCompare(pOne->pExpr->pLeft, pTwo->pExpr->pLeft, -1) ) return;
    +-  if( sqlite3ExprCompare(pOne->pExpr->pRight, pTwo->pExpr->pRight, -1) )return;
    ++  if( sqlite3ExprCompare(0,pOne->pExpr->pLeft, pTwo->pExpr->pLeft, -1) ) return;
    ++  if( sqlite3ExprCompare(0,pOne->pExpr->pRight, pTwo->pExpr->pRight,-1) )return;
    +   /* If we reach this point, it means the two subterms can be combined */
    +   if( (eOp & (eOp-1))!=0 ){
    +     if( eOp & (WO_LT|WO_LE) ){
    +@@ -120565,6 +131980,7 @@ static void exprAnalyzeOrTerm(
    +   if( pOrInfo==0 ) return;
    +   pTerm->wtFlags |= TERM_ORINFO;
    +   pOrWc = &pOrInfo->wc;
    ++  memset(pOrWc->aStatic, 0, sizeof(pOrWc->aStatic));
    +   sqlite3WhereClauseInit(pOrWc, pWInfo);
    +   sqlite3WhereSplit(pOrWc, pExpr, TK_OR);
    +   sqlite3WhereExprAnalyze(pSrc, pOrWc);
    +@@ -120581,7 +131997,7 @@ static void exprAnalyzeOrTerm(
    +       WhereAndInfo *pAndInfo;
    +       assert( (pOrTerm->wtFlags & (TERM_ANDINFO|TERM_ORINFO))==0 );
    +       chngToIN = 0;
    +-      pAndInfo = sqlite3DbMallocRaw(db, sizeof(*pAndInfo));
    ++      pAndInfo = sqlite3DbMallocRawNN(db, sizeof(*pAndInfo));
    +       if( pAndInfo ){
    +         WhereClause *pAndWC;
    +         WhereTerm *pAndTerm;
    +@@ -120591,15 +132007,17 @@ static void exprAnalyzeOrTerm(
    +         pOrTerm->wtFlags |= TERM_ANDINFO;
    +         pOrTerm->eOperator = WO_AND;
    +         pAndWC = &pAndInfo->wc;
    ++        memset(pAndWC->aStatic, 0, sizeof(pAndWC->aStatic));
    +         sqlite3WhereClauseInit(pAndWC, pWC->pWInfo);
    +         sqlite3WhereSplit(pAndWC, pOrTerm->pExpr, TK_AND);
    +         sqlite3WhereExprAnalyze(pSrc, pAndWC);
    +         pAndWC->pOuter = pWC;
    +-        testcase( db->mallocFailed );
    +         if( !db->mallocFailed ){
    +           for(j=0, pAndTerm=pAndWC->a; j<pAndWC->nTerm; j++, pAndTerm++){
    +             assert( pAndTerm->pExpr );
    +-            if( allowedOp(pAndTerm->pExpr->op) ){
    ++            if( allowedOp(pAndTerm->pExpr->op) 
    ++             || pAndTerm->eOperator==WO_AUX
    ++            ){
    +               b |= sqlite3WhereGetMask(&pWInfo->sMaskSet, pAndTerm->leftCursor);
    +             }
    +           }
    +@@ -120762,7 +132180,7 @@ static void exprAnalyzeOrTerm(
    +       }
    +       assert( pLeft!=0 );
    +       pDup = sqlite3ExprDup(db, pLeft, 0);
    +-      pNew = sqlite3PExpr(pParse, TK_IN, pDup, 0, 0);
    ++      pNew = sqlite3PExpr(pParse, TK_IN, pDup, 0);
    +       if( pNew ){
    +         int idxNew;
    +         transferJoinMarkings(pNew, pExpr);
    +@@ -120800,7 +132218,6 @@ static void exprAnalyzeOrTerm(
    + static int termIsEquivalence(Parse *pParse, Expr *pExpr){
    +   char aff1, aff2;
    +   CollSeq *pColl;
    +-  const char *zColl1, *zColl2;
    +   if( !OptimizationEnabled(pParse->db, SQLITE_Transitive) ) return 0;
    +   if( pExpr->op!=TK_EQ && pExpr->op!=TK_IS ) return 0;
    +   if( ExprHasProperty(pExpr, EP_FromJoin) ) return 0;
    +@@ -120813,13 +132230,7 @@ static int termIsEquivalence(Parse *pParse, Expr *pExpr){
    +   }
    +   pColl = sqlite3BinaryCompareCollSeq(pParse, pExpr->pLeft, pExpr->pRight);
    +   if( pColl==0 || sqlite3StrICmp(pColl->zName, "BINARY")==0 ) return 1;
    +-  pColl = sqlite3ExprCollSeq(pParse, pExpr->pLeft);
    +-  /* Since pLeft and pRight are both a column references, their collating
    +-  ** sequence should always be defined. */
    +-  zColl1 = ALWAYS(pColl) ? pColl->zName : 0;
    +-  pColl = sqlite3ExprCollSeq(pParse, pExpr->pRight);
    +-  zColl2 = ALWAYS(pColl) ? pColl->zName : 0;
    +-  return sqlite3StrICmp(zColl1, zColl2)==0;
    ++  return sqlite3ExprCollSeqMatch(pParse, pExpr->pLeft, pExpr->pRight);
    + }
    + 
    + /*
    +@@ -120852,46 +132263,65 @@ static Bitmask exprSelectUsage(WhereMaskSet *pMaskSet, Select *pS){
    + ** Expression pExpr is one operand of a comparison operator that might
    + ** be useful for indexing.  This routine checks to see if pExpr appears
    + ** in any index.  Return TRUE (1) if pExpr is an indexed term and return
    +-** FALSE (0) if not.  If TRUE is returned, also set *piCur to the cursor
    +-** number of the table that is indexed and *piColumn to the column number
    +-** of the column that is indexed, or -2 if an expression is being indexed.
    ++** FALSE (0) if not.  If TRUE is returned, also set aiCurCol[0] to the cursor
    ++** number of the table that is indexed and aiCurCol[1] to the column number
    ++** of the column that is indexed, or XN_EXPR (-2) if an expression is being
    ++** indexed.
    + **
    + ** If pExpr is a TK_COLUMN column reference, then this routine always returns
    + ** true even if that particular column is not indexed, because the column
    + ** might be added to an automatic index later.
    + */
    +-static int exprMightBeIndexed(
    ++static SQLITE_NOINLINE int exprMightBeIndexed2(
    +   SrcList *pFrom,        /* The FROM clause */
    +   Bitmask mPrereq,       /* Bitmask of FROM clause terms referenced by pExpr */
    +-  Expr *pExpr,           /* An operand of a comparison operator */
    +-  int *piCur,            /* Write the referenced table cursor number here */
    +-  int *piColumn          /* Write the referenced table column number here */
    ++  int *aiCurCol,         /* Write the referenced table cursor and column here */
    ++  Expr *pExpr            /* An operand of a comparison operator */
    + ){
    +   Index *pIdx;
    +   int i;
    +   int iCur;
    +-  if( pExpr->op==TK_COLUMN ){
    +-    *piCur = pExpr->iTable;
    +-    *piColumn = pExpr->iColumn;
    +-    return 1;
    +-  }
    +-  if( mPrereq==0 ) return 0;                 /* No table references */
    +-  if( (mPrereq&(mPrereq-1))!=0 ) return 0;   /* Refs more than one table */
    +   for(i=0; mPrereq>1; i++, mPrereq>>=1){}
    +   iCur = pFrom->a[i].iCursor;
    +   for(pIdx=pFrom->a[i].pTab->pIndex; pIdx; pIdx=pIdx->pNext){
    +     if( pIdx->aColExpr==0 ) continue;
    +     for(i=0; i<pIdx->nKeyCol; i++){
    +-      if( pIdx->aiColumn[i]!=(-2) ) continue;
    +-      if( sqlite3ExprCompare(pExpr, pIdx->aColExpr->a[i].pExpr, iCur)==0 ){
    +-        *piCur = iCur;
    +-        *piColumn = -2;
    ++      if( pIdx->aiColumn[i]!=XN_EXPR ) continue;
    ++      if( sqlite3ExprCompareSkip(pExpr, pIdx->aColExpr->a[i].pExpr, iCur)==0 ){
    ++        aiCurCol[0] = iCur;
    ++        aiCurCol[1] = XN_EXPR;
    +         return 1;
    +       }
    +     }
    +   }
    +   return 0;
    + }
    ++static int exprMightBeIndexed(
    ++  SrcList *pFrom,        /* The FROM clause */
    ++  Bitmask mPrereq,       /* Bitmask of FROM clause terms referenced by pExpr */
    ++  int *aiCurCol,         /* Write the referenced table cursor & column here */
    ++  Expr *pExpr,           /* An operand of a comparison operator */
    ++  int op                 /* The specific comparison operator */
    ++){
    ++  /* If this expression is a vector to the left or right of a 
    ++  ** inequality constraint (>, <, >= or <=), perform the processing 
    ++  ** on the first element of the vector.  */
    ++  assert( TK_GT+1==TK_LE && TK_GT+2==TK_LT && TK_GT+3==TK_GE );
    ++  assert( TK_IS<TK_GE && TK_ISNULL<TK_GE && TK_IN<TK_GE );
    ++  assert( op<=TK_GE );
    ++  if( pExpr->op==TK_VECTOR && (op>=TK_GT && ALWAYS(op<=TK_GE)) ){
    ++    pExpr = pExpr->x.pList->a[0].pExpr;
    ++  }
    ++
    ++  if( pExpr->op==TK_COLUMN ){
    ++    aiCurCol[0] = pExpr->iTable;
    ++    aiCurCol[1] = pExpr->iColumn;
    ++    return 1;
    ++  }
    ++  if( mPrereq==0 ) return 0;                 /* No table references */
    ++  if( (mPrereq&(mPrereq-1))!=0 ) return 0;   /* Refs more than one table */
    ++  return exprMightBeIndexed2(pFrom,mPrereq,aiCurCol,pExpr);
    ++}
    + 
    + /*
    + ** The input to this routine is an WhereTerm structure with only the
    +@@ -120929,6 +132359,8 @@ static void exprAnalyze(
    +   int op;                          /* Top-level operator.  pExpr->op */
    +   Parse *pParse = pWInfo->pParse;  /* Parsing context */
    +   sqlite3 *db = pParse->db;        /* Database connection */
    ++  unsigned char eOp2 = 0;          /* op2 value for LIKE/REGEXP/GLOB */
    ++  int nLeft;                       /* Number of elements on left side vector */
    + 
    +   if( db->mallocFailed ){
    +     return;
    +@@ -120941,6 +132373,7 @@ static void exprAnalyze(
    +   op = pExpr->op;
    +   if( op==TK_IN ){
    +     assert( pExpr->pRight==0 );
    ++    if( sqlite3ExprCheckIN(pParse, pExpr) ) return;
    +     if( ExprHasProperty(pExpr, EP_xIsSelect) ){
    +       pTerm->prereqRight = exprSelectUsage(pMaskSet, pExpr->x.pSelect);
    +     }else{
    +@@ -120951,34 +132384,48 @@ static void exprAnalyze(
    +   }else{
    +     pTerm->prereqRight = sqlite3WhereExprUsage(pMaskSet, pExpr->pRight);
    +   }
    ++  pMaskSet->bVarSelect = 0;
    +   prereqAll = sqlite3WhereExprUsage(pMaskSet, pExpr);
    ++  if( pMaskSet->bVarSelect ) pTerm->wtFlags |= TERM_VARSELECT;
    +   if( ExprHasProperty(pExpr, EP_FromJoin) ){
    +     Bitmask x = sqlite3WhereGetMask(pMaskSet, pExpr->iRightJoinTable);
    +     prereqAll |= x;
    +     extraRight = x-1;  /* ON clause terms may not be used with an index
    +                        ** on left table of a LEFT JOIN.  Ticket #3015 */
    ++    if( (prereqAll>>1)>=x ){
    ++      sqlite3ErrorMsg(pParse, "ON clause references tables to its right");
    ++      return;
    ++    }
    +   }
    +   pTerm->prereqAll = prereqAll;
    +   pTerm->leftCursor = -1;
    +   pTerm->iParent = -1;
    +   pTerm->eOperator = 0;
    +   if( allowedOp(op) ){
    +-    int iCur, iColumn;
    ++    int aiCurCol[2];
    +     Expr *pLeft = sqlite3ExprSkipCollate(pExpr->pLeft);
    +     Expr *pRight = sqlite3ExprSkipCollate(pExpr->pRight);
    +     u16 opMask = (pTerm->prereqRight & prereqLeft)==0 ? WO_ALL : WO_EQUIV;
    +-    if( exprMightBeIndexed(pSrc, prereqLeft, pLeft, &iCur, &iColumn) ){
    +-      pTerm->leftCursor = iCur;
    +-      pTerm->u.leftColumn = iColumn;
    ++
    ++    if( pTerm->iField>0 ){
    ++      assert( op==TK_IN );
    ++      assert( pLeft->op==TK_VECTOR );
    ++      pLeft = pLeft->x.pList->a[pTerm->iField-1].pExpr;
    ++    }
    ++
    ++    if( exprMightBeIndexed(pSrc, prereqLeft, aiCurCol, pLeft, op) ){
    ++      pTerm->leftCursor = aiCurCol[0];
    ++      pTerm->u.leftColumn = aiCurCol[1];
    +       pTerm->eOperator = operatorMask(op) & opMask;
    +     }
    +     if( op==TK_IS ) pTerm->wtFlags |= TERM_IS;
    +     if( pRight 
    +-     && exprMightBeIndexed(pSrc, pTerm->prereqRight, pRight, &iCur, &iColumn)
    ++     && exprMightBeIndexed(pSrc, pTerm->prereqRight, aiCurCol, pRight, op)
    +     ){
    +       WhereTerm *pNew;
    +       Expr *pDup;
    +       u16 eExtraOp = 0;        /* Extra bits for pNew->eOperator */
    ++      assert( pTerm->iField==0 );
    +       if( pTerm->leftCursor>=0 ){
    +         int idxNew;
    +         pDup = sqlite3ExprDup(db, pExpr, 0);
    +@@ -121003,8 +132450,8 @@ static void exprAnalyze(
    +         pNew = pTerm;
    +       }
    +       exprCommute(pParse, pDup);
    +-      pNew->leftCursor = iCur;
    +-      pNew->u.leftColumn = iColumn;
    ++      pNew->leftCursor = aiCurCol[0];
    ++      pNew->u.leftColumn = aiCurCol[1];
    +       testcase( (prereqLeft | extraRight) != prereqLeft );
    +       pNew->prereqRight = prereqLeft | extraRight;
    +       pNew->prereqAll = prereqAll;
    +@@ -121039,7 +132486,7 @@ static void exprAnalyze(
    +       int idxNew;
    +       pNewExpr = sqlite3PExpr(pParse, ops[i], 
    +                              sqlite3ExprDup(db, pExpr->pLeft, 0),
    +-                             sqlite3ExprDup(db, pList->a[i].pExpr, 0), 0);
    ++                             sqlite3ExprDup(db, pList->a[i].pExpr, 0));
    +       transferJoinMarkings(pNewExpr, pExpr);
    +       idxNew = whereClauseInsert(pWC, pNewExpr, TERM_VIRTUAL|TERM_DYNAMIC);
    +       testcase( idxNew==0 );
    +@@ -121124,7 +132571,7 @@ static void exprAnalyze(
    +     pNewExpr1 = sqlite3ExprDup(db, pLeft, 0);
    +     pNewExpr1 = sqlite3PExpr(pParse, TK_GE,
    +            sqlite3ExprAddCollateString(pParse,pNewExpr1,zCollSeqName),
    +-           pStr1, 0);
    ++           pStr1);
    +     transferJoinMarkings(pNewExpr1, pExpr);
    +     idxNew1 = whereClauseInsert(pWC, pNewExpr1, wtFlags);
    +     testcase( idxNew1==0 );
    +@@ -121132,7 +132579,7 @@ static void exprAnalyze(
    +     pNewExpr2 = sqlite3ExprDup(db, pLeft, 0);
    +     pNewExpr2 = sqlite3PExpr(pParse, TK_LT,
    +            sqlite3ExprAddCollateString(pParse,pNewExpr2,zCollSeqName),
    +-           pStr2, 0);
    ++           pStr2);
    +     transferJoinMarkings(pNewExpr2, pExpr);
    +     idxNew2 = whereClauseInsert(pWC, pNewExpr2, wtFlags);
    +     testcase( idxNew2==0 );
    +@@ -121146,40 +132593,102 @@ static void exprAnalyze(
    + #endif /* SQLITE_OMIT_LIKE_OPTIMIZATION */
    + 
    + #ifndef SQLITE_OMIT_VIRTUALTABLE
    +-  /* Add a WO_MATCH auxiliary term to the constraint set if the
    +-  ** current expression is of the form:  column MATCH expr.
    ++  /* Add a WO_AUX auxiliary term to the constraint set if the
    ++  ** current expression is of the form "column OP expr" where OP
    ++  ** is an operator that gets passed into virtual tables but which is
    ++  ** not normally optimized for ordinary tables.  In other words, OP
    ++  ** is one of MATCH, LIKE, GLOB, REGEXP, !=, IS, IS NOT, or NOT NULL.
    +   ** This information is used by the xBestIndex methods of
    +   ** virtual tables.  The native query optimizer does not attempt
    +   ** to do anything with MATCH functions.
    +   */
    +-  if( isMatchOfColumn(pExpr) ){
    +-    int idxNew;
    +-    Expr *pRight, *pLeft;
    +-    WhereTerm *pNewTerm;
    +-    Bitmask prereqColumn, prereqExpr;
    ++  if( pWC->op==TK_AND ){
    ++    Expr *pRight = 0, *pLeft = 0;
    ++    int res = isAuxiliaryVtabOperator(pExpr, &eOp2, &pLeft, &pRight);
    ++    while( res-- > 0 ){
    ++      int idxNew;
    ++      WhereTerm *pNewTerm;
    ++      Bitmask prereqColumn, prereqExpr;
    ++
    ++      prereqExpr = sqlite3WhereExprUsage(pMaskSet, pRight);
    ++      prereqColumn = sqlite3WhereExprUsage(pMaskSet, pLeft);
    ++      if( (prereqExpr & prereqColumn)==0 ){
    ++        Expr *pNewExpr;
    ++        pNewExpr = sqlite3PExpr(pParse, TK_MATCH, 
    ++            0, sqlite3ExprDup(db, pRight, 0));
    ++        if( ExprHasProperty(pExpr, EP_FromJoin) && pNewExpr ){
    ++          ExprSetProperty(pNewExpr, EP_FromJoin);
    ++        }
    ++        idxNew = whereClauseInsert(pWC, pNewExpr, TERM_VIRTUAL|TERM_DYNAMIC);
    ++        testcase( idxNew==0 );
    ++        pNewTerm = &pWC->a[idxNew];
    ++        pNewTerm->prereqRight = prereqExpr;
    ++        pNewTerm->leftCursor = pLeft->iTable;
    ++        pNewTerm->u.leftColumn = pLeft->iColumn;
    ++        pNewTerm->eOperator = WO_AUX;
    ++        pNewTerm->eMatchOp = eOp2;
    ++        markTermAsChild(pWC, idxNew, idxTerm);
    ++        pTerm = &pWC->a[idxTerm];
    ++        pTerm->wtFlags |= TERM_COPIED;
    ++        pNewTerm->prereqAll = pTerm->prereqAll;
    ++      }
    ++      SWAP(Expr*, pLeft, pRight);
    ++    }
    ++  }
    ++#endif /* SQLITE_OMIT_VIRTUALTABLE */
    + 
    +-    pRight = pExpr->x.pList->a[0].pExpr;
    +-    pLeft = pExpr->x.pList->a[1].pExpr;
    +-    prereqExpr = sqlite3WhereExprUsage(pMaskSet, pRight);
    +-    prereqColumn = sqlite3WhereExprUsage(pMaskSet, pLeft);
    +-    if( (prereqExpr & prereqColumn)==0 ){
    +-      Expr *pNewExpr;
    +-      pNewExpr = sqlite3PExpr(pParse, TK_MATCH, 
    +-                              0, sqlite3ExprDup(db, pRight, 0), 0);
    +-      idxNew = whereClauseInsert(pWC, pNewExpr, TERM_VIRTUAL|TERM_DYNAMIC);
    +-      testcase( idxNew==0 );
    +-      pNewTerm = &pWC->a[idxNew];
    +-      pNewTerm->prereqRight = prereqExpr;
    +-      pNewTerm->leftCursor = pLeft->iTable;
    +-      pNewTerm->u.leftColumn = pLeft->iColumn;
    +-      pNewTerm->eOperator = WO_MATCH;
    ++  /* If there is a vector == or IS term - e.g. "(a, b) == (?, ?)" - create
    ++  ** new terms for each component comparison - "a = ?" and "b = ?".  The
    ++  ** new terms completely replace the original vector comparison, which is
    ++  ** no longer used.
    ++  **
    ++  ** This is only required if at least one side of the comparison operation
    ++  ** is not a sub-select.  */
    ++  if( pWC->op==TK_AND 
    ++  && (pExpr->op==TK_EQ || pExpr->op==TK_IS)
    ++  && (nLeft = sqlite3ExprVectorSize(pExpr->pLeft))>1
    ++  && sqlite3ExprVectorSize(pExpr->pRight)==nLeft
    ++  && ( (pExpr->pLeft->flags & EP_xIsSelect)==0 
    ++    || (pExpr->pRight->flags & EP_xIsSelect)==0)
    ++  ){
    ++    int i;
    ++    for(i=0; i<nLeft; i++){
    ++      int idxNew;
    ++      Expr *pNew;
    ++      Expr *pLeft = sqlite3ExprForVectorField(pParse, pExpr->pLeft, i);
    ++      Expr *pRight = sqlite3ExprForVectorField(pParse, pExpr->pRight, i);
    ++
    ++      pNew = sqlite3PExpr(pParse, pExpr->op, pLeft, pRight);
    ++      transferJoinMarkings(pNew, pExpr);
    ++      idxNew = whereClauseInsert(pWC, pNew, TERM_DYNAMIC);
    ++      exprAnalyze(pSrc, pWC, idxNew);
    ++    }
    ++    pTerm = &pWC->a[idxTerm];
    ++    pTerm->wtFlags = TERM_CODED|TERM_VIRTUAL;  /* Disable the original */
    ++    pTerm->eOperator = 0;
    ++  }
    ++
    ++  /* If there is a vector IN term - e.g. "(a, b) IN (SELECT ...)" - create
    ++  ** a virtual term for each vector component. The expression object
    ++  ** used by each such virtual term is pExpr (the full vector IN(...) 
    ++  ** expression). The WhereTerm.iField variable identifies the index within
    ++  ** the vector on the LHS that the virtual term represents.
    ++  **
    ++  ** This only works if the RHS is a simple SELECT, not a compound
    ++  */
    ++  if( pWC->op==TK_AND && pExpr->op==TK_IN && pTerm->iField==0
    ++   && pExpr->pLeft->op==TK_VECTOR
    ++   && pExpr->x.pSelect->pPrior==0
    ++  ){
    ++    int i;
    ++    for(i=0; i<sqlite3ExprVectorSize(pExpr->pLeft); i++){
    ++      int idxNew;
    ++      idxNew = whereClauseInsert(pWC, pExpr, TERM_VIRTUAL);
    ++      pWC->a[idxNew].iField = i+1;
    ++      exprAnalyze(pSrc, pWC, idxNew);
    +       markTermAsChild(pWC, idxNew, idxTerm);
    +-      pTerm = &pWC->a[idxTerm];
    +-      pTerm->wtFlags |= TERM_COPIED;
    +-      pNewTerm->prereqAll = pTerm->prereqAll;
    +     }
    +   }
    +-#endif /* SQLITE_OMIT_VIRTUALTABLE */
    + 
    + #ifdef SQLITE_ENABLE_STAT3_OR_STAT4
    +   /* When sqlite_stat3 histogram data is available an operator of the
    +@@ -121201,7 +132710,7 @@ static void exprAnalyze(
    + 
    +     pNewExpr = sqlite3PExpr(pParse, TK_GT,
    +                             sqlite3ExprDup(db, pLeft, 0),
    +-                            sqlite3PExpr(pParse, TK_NULL, 0, 0, 0), 0);
    ++                            sqlite3ExprAlloc(db, TK_NULL, 0, 0));
    + 
    +     idxNew = whereClauseInsert(pWC, pNewExpr,
    +                               TERM_VIRTUAL|TERM_DYNAMIC|TERM_VNULL);
    +@@ -121222,6 +132731,8 @@ static void exprAnalyze(
    +   /* Prevent ON clause terms of a LEFT JOIN from being used to drive
    +   ** an index for tables to the left of the join.
    +   */
    ++  testcase( pTerm!=&pWC->a[idxTerm] );
    ++  pTerm = &pWC->a[idxTerm];
    +   pTerm->prereqRight |= extraRight;
    + }
    + 
    +@@ -121275,7 +132786,8 @@ SQLITE_PRIVATE void sqlite3WhereClauseInit(
    + 
    + /*
    + ** Deallocate a WhereClause structure.  The WhereClause structure
    +-** itself is not freed.  This routine is the inverse of sqlite3WhereClauseInit().
    ++** itself is not freed.  This routine is the inverse of
    ++** sqlite3WhereClauseInit().
    + */
    + SQLITE_PRIVATE void sqlite3WhereClauseClear(WhereClause *pWC){
    +   int i;
    +@@ -121303,17 +132815,21 @@ SQLITE_PRIVATE void sqlite3WhereClauseClear(WhereClause *pWC){
    + ** tree.
    + */
    + SQLITE_PRIVATE Bitmask sqlite3WhereExprUsage(WhereMaskSet *pMaskSet, Expr *p){
    +-  Bitmask mask = 0;
    ++  Bitmask mask;
    +   if( p==0 ) return 0;
    +   if( p->op==TK_COLUMN ){
    +-    mask = sqlite3WhereGetMask(pMaskSet, p->iTable);
    +-    return mask;
    +-  }
    +-  mask = sqlite3WhereExprUsage(pMaskSet, p->pRight);
    +-  mask |= sqlite3WhereExprUsage(pMaskSet, p->pLeft);
    +-  if( ExprHasProperty(p, EP_xIsSelect) ){
    ++    return sqlite3WhereGetMask(pMaskSet, p->iTable);
    ++  }
    ++  mask = (p->op==TK_IF_NULL_ROW) ? sqlite3WhereGetMask(pMaskSet, p->iTable) : 0;
    ++  assert( !ExprHasProperty(p, EP_TokenOnly) );
    ++  if( p->pLeft ) mask |= sqlite3WhereExprUsage(pMaskSet, p->pLeft);
    ++  if( p->pRight ){
    ++    mask |= sqlite3WhereExprUsage(pMaskSet, p->pRight);
    ++    assert( p->x.pList==0 );
    ++  }else if( ExprHasProperty(p, EP_xIsSelect) ){
    ++    if( ExprHasProperty(p, EP_VarSelect) ) pMaskSet->bVarSelect = 1;
    +     mask |= exprSelectUsage(pMaskSet, p->x.pSelect);
    +-  }else{
    ++  }else if( p->x.pList ){
    +     mask |= sqlite3WhereExprListUsage(pMaskSet, p->x.pList);
    +   }
    +   return mask;
    +@@ -121369,21 +132885,21 @@ SQLITE_PRIVATE void sqlite3WhereTabFuncArgs(
    +   pTab = pItem->pTab;
    +   assert( pTab!=0 );
    +   pArgs = pItem->u1.pFuncArg;
    +-  assert( pArgs!=0 );
    ++  if( pArgs==0 ) return;
    +   for(j=k=0; j<pArgs->nExpr; j++){
    +-    while( k<pTab->nCol && (pTab->aCol[k].colFlags & COLFLAG_HIDDEN)==0 ){ k++; }
    ++    while( k<pTab->nCol && (pTab->aCol[k].colFlags & COLFLAG_HIDDEN)==0 ){k++;}
    +     if( k>=pTab->nCol ){
    +       sqlite3ErrorMsg(pParse, "too many arguments on %s() - max %d",
    +                       pTab->zName, j);
    +       return;
    +     }
    +-    pColRef = sqlite3PExpr(pParse, TK_COLUMN, 0, 0, 0);
    ++    pColRef = sqlite3ExprAlloc(pParse->db, TK_COLUMN, 0, 0);
    +     if( pColRef==0 ) return;
    +     pColRef->iTable = pItem->iCursor;
    +     pColRef->iColumn = k++;
    +     pColRef->pTab = pTab;
    +     pTerm = sqlite3PExpr(pParse, TK_EQ, pColRef,
    +-                         sqlite3ExprDup(pParse->db, pArgs->a[j].pExpr, 0), 0);
    ++                         sqlite3ExprDup(pParse->db, pArgs->a[j].pExpr, 0));
    +     whereClauseInsert(pWC, pTerm, TERM_DYNAMIC);
    +   }
    + }
    +@@ -121411,6 +132927,21 @@ SQLITE_PRIVATE void sqlite3WhereTabFuncArgs(
    + /* #include "sqliteInt.h" */
    + /* #include "whereInt.h" */
    + 
    ++/*
    ++** Extra information appended to the end of sqlite3_index_info but not
    ++** visible to the xBestIndex function, at least not directly.  The
    ++** sqlite3_vtab_collation() interface knows how to reach it, however.
    ++**
    ++** This object is not an API and can be changed from one release to the
    ++** next.  As long as allocateIndexInfo() and sqlite3_vtab_collation()
    ++** agree on the structure, all will be well.
    ++*/
    ++typedef struct HiddenIndexInfo HiddenIndexInfo;
    ++struct HiddenIndexInfo {
    ++  WhereClause *pWC;   /* The Where clause being analyzed */
    ++  Parse *pParse;      /* The parsing context */
    ++};
    ++
    + /* Forward declaration of methods */
    + static int whereLoopResize(sqlite3*, WhereLoop*, int);
    + 
    +@@ -121423,8 +132954,8 @@ static int whereLoopResize(sqlite3*, WhereLoop*, int);
    + /*
    + ** Return the estimated number of output rows from a WHERE clause
    + */
    +-SQLITE_PRIVATE u64 sqlite3WhereOutputRowCount(WhereInfo *pWInfo){
    +-  return sqlite3LogEstToInt(pWInfo->nRowOut);
    ++SQLITE_PRIVATE LogEst sqlite3WhereOutputRowCount(WhereInfo *pWInfo){
    ++  return pWInfo->nRowOut;
    + }
    + 
    + /*
    +@@ -121443,6 +132974,18 @@ SQLITE_PRIVATE int sqlite3WhereIsOrdered(WhereInfo *pWInfo){
    +   return pWInfo->nOBSat;
    + }
    + 
    ++/*
    ++** Return TRUE if the innermost loop of the WHERE clause implementation
    ++** returns rows in ORDER BY order for complete run of the inner loop.
    ++**
    ++** Across multiple iterations of outer loops, the output rows need not be
    ++** sorted.  As long as rows are sorted for just the innermost loop, this
    ++** routine can return TRUE.
    ++*/
    ++SQLITE_PRIVATE int sqlite3WhereOrderedInnerLoop(WhereInfo *pWInfo){
    ++  return pWInfo->bOrderedInnerLoop;
    ++}
    ++
    + /*
    + ** Return the VDBE address or label to jump to in order to continue
    + ** immediately with the next row of a WHERE clause.
    +@@ -121578,16 +133121,19 @@ static WhereTerm *whereScanNext(WhereScan *pScan){
    +   WhereTerm *pTerm;    /* The term being tested */
    +   int k = pScan->k;    /* Where to start scanning */
    + 
    +-  while( pScan->iEquiv<=pScan->nEquiv ){
    +-    iCur = pScan->aiCur[pScan->iEquiv-1];
    ++  assert( pScan->iEquiv<=pScan->nEquiv );
    ++  pWC = pScan->pWC;
    ++  while(1){
    +     iColumn = pScan->aiColumn[pScan->iEquiv-1];
    +-    if( iColumn==XN_EXPR && pScan->pIdxExpr==0 ) return 0;
    +-    while( (pWC = pScan->pWC)!=0 ){
    ++    iCur = pScan->aiCur[pScan->iEquiv-1];
    ++    assert( pWC!=0 );
    ++    do{
    +       for(pTerm=pWC->a+k; k<pWC->nTerm; k++, pTerm++){
    +         if( pTerm->leftCursor==iCur
    +          && pTerm->u.leftColumn==iColumn
    +          && (iColumn!=XN_EXPR
    +-             || sqlite3ExprCompare(pTerm->pExpr->pLeft,pScan->pIdxExpr,iCur)==0)
    ++             || sqlite3ExprCompareSkip(pTerm->pExpr->pLeft,
    ++                                       pScan->pIdxExpr,iCur)==0)
    +          && (pScan->iEquiv<=1 || !ExprHasProperty(pTerm->pExpr, EP_FromJoin))
    +         ){
    +           if( (pTerm->eOperator & WO_EQUIV)!=0
    +@@ -121632,15 +133178,17 @@ static WhereTerm *whereScanNext(WhereScan *pScan){
    +               testcase( pTerm->eOperator & WO_IS );
    +               continue;
    +             }
    ++            pScan->pWC = pWC;
    +             pScan->k = k+1;
    +             return pTerm;
    +           }
    +         }
    +       }
    +-      pScan->pWC = pScan->pWC->pOuter;
    ++      pWC = pWC->pOuter;
    +       k = 0;
    +-    }
    +-    pScan->pWC = pScan->pOrigWC;
    ++    }while( pWC!=0 );
    ++    if( pScan->iEquiv>=pScan->nEquiv ) break;
    ++    pWC = pScan->pOrigWC;
    +     k = 0;
    +     pScan->iEquiv++;
    +   }
    +@@ -121653,7 +133201,10 @@ static WhereTerm *whereScanNext(WhereScan *pScan){
    + **
    + ** The scanner will be searching the WHERE clause pWC.  It will look
    + ** for terms of the form "X <op> <expr>" where X is column iColumn of table
    +-** iCur.  The <op> must be one of the operators described by opMask.
    ++** iCur.   Or if pIdx!=0 then X is column iColumn of index pIdx.  pIdx
    ++** must be one of the indexes of table iCur.
    ++**
    ++** The <op> must be one of the operators described by opMask.
    + **
    + ** If the search is for X and the WHERE clause contains terms of the
    + ** form X=Y then this routine might also return terms of the form
    +@@ -121671,23 +133222,25 @@ static WhereTerm *whereScanInit(
    +   u32 opMask,             /* Operator(s) to scan for */
    +   Index *pIdx             /* Must be compatible with this index */
    + ){
    +-  int j = 0;
    +-
    +-  /* memset(pScan, 0, sizeof(*pScan)); */
    +   pScan->pOrigWC = pWC;
    +   pScan->pWC = pWC;
    +   pScan->pIdxExpr = 0;
    ++  pScan->idxaff = 0;
    ++  pScan->zCollName = 0;
    +   if( pIdx ){
    +-    j = iColumn;
    ++    int j = iColumn;
    +     iColumn = pIdx->aiColumn[j];
    +-    if( iColumn==XN_EXPR ) pScan->pIdxExpr = pIdx->aColExpr->a[j].pExpr;
    +-  }
    +-  if( pIdx && iColumn>=0 ){
    +-    pScan->idxaff = pIdx->pTable->aCol[iColumn].affinity;
    +-    pScan->zCollName = pIdx->azColl[j];
    +-  }else{
    +-    pScan->idxaff = 0;
    +-    pScan->zCollName = 0;
    ++    if( iColumn==XN_EXPR ){
    ++      pScan->pIdxExpr = pIdx->aColExpr->a[j].pExpr;
    ++      pScan->zCollName = pIdx->azColl[j];
    ++    }else if( iColumn==pIdx->pTable->iPKey ){
    ++      iColumn = XN_ROWID;
    ++    }else if( iColumn>=0 ){
    ++      pScan->idxaff = pIdx->pTable->aCol[iColumn].affinity;
    ++      pScan->zCollName = pIdx->azColl[j];
    ++    }
    ++  }else if( iColumn==XN_EXPR ){
    ++    return 0;
    +   }
    +   pScan->opMask = opMask;
    +   pScan->k = 0;
    +@@ -121700,11 +133253,12 @@ static WhereTerm *whereScanInit(
    + 
    + /*
    + ** Search for a term in the WHERE clause that is of the form "X <op> <expr>"
    +-** where X is a reference to the iColumn of table iCur and <op> is one of
    +-** the WO_xx operator codes specified by the op parameter.
    +-** Return a pointer to the term.  Return 0 if not found.
    ++** where X is a reference to the iColumn of table iCur or of index pIdx
    ++** if pIdx!=0 and <op> is one of the WO_xx operator codes specified by
    ++** the op parameter.  Return a pointer to the term.  Return 0 if not found.
    + **
    +-** If pIdx!=0 then search for terms matching the iColumn-th column of pIdx
    ++** If pIdx!=0 then it must be one of the indexes of table iCur.  
    ++** Search for terms matching the iColumn-th column of pIdx
    + ** rather than the iColumn-th column of table iCur.
    + **
    + ** The term returned might by Y=<expr> if there is another constraint in
    +@@ -121772,8 +133326,8 @@ static int findIndexCol(
    +      && p->iColumn==pIdx->aiColumn[iCol]
    +      && p->iTable==iBase
    +     ){
    +-      CollSeq *pColl = sqlite3ExprCollSeq(pParse, pList->a[i].pExpr);
    +-      if( pColl && 0==sqlite3StrICmp(pColl->zName, zColl) ){
    ++      CollSeq *pColl = sqlite3ExprNNCollSeq(pParse, pList->a[i].pExpr);
    ++      if( 0==sqlite3StrICmp(pColl->zName, zColl) ){
    +         return i;
    +       }
    +     }
    +@@ -121886,14 +133440,16 @@ static LogEst estLog(LogEst N){
    + ** value stored in its output register.
    + */
    + static void translateColumnToCopy(
    +-  Vdbe *v,            /* The VDBE containing code to translate */
    ++  Parse *pParse,      /* Parsing context */
    +   int iStart,         /* Translate from this opcode to the end */
    +   int iTabCur,        /* OP_Column/OP_Rowid references to this table */
    +   int iRegister,      /* The first column is in this register */
    +   int bIncrRowid      /* If non-zero, transform OP_rowid to OP_AddImm(1) */
    + ){
    ++  Vdbe *v = pParse->pVdbe;
    +   VdbeOp *pOp = sqlite3VdbeGetOp(v, iStart);
    +   int iEnd = sqlite3VdbeCurrentAddr(v);
    ++  if( pParse->db->mallocFailed ) return;
    +   for(; iStart<iEnd; iStart++, pOp++){
    +     if( pOp->p1!=iTabCur ) continue;
    +     if( pOp->opcode==OP_Column ){
    +@@ -121975,6 +133531,15 @@ static int termCanDriveIndex(
    +   char aff;
    +   if( pTerm->leftCursor!=pSrc->iCursor ) return 0;
    +   if( (pTerm->eOperator & (WO_EQ|WO_IS))==0 ) return 0;
    ++  if( (pSrc->fg.jointype & JT_LEFT) 
    ++   && !ExprHasProperty(pTerm->pExpr, EP_FromJoin)
    ++   && (pTerm->eOperator & WO_IS)
    ++  ){
    ++    /* Cannot use an IS term from the WHERE clause as an index driver for
    ++    ** the RHS of a LEFT JOIN. Such a term can only be used if it is from
    ++    ** the ON clause.  */
    ++    return 0;
    ++  }
    +   if( (pTerm->prereqRight & notReady)!=0 ) return 0;
    +   if( pTerm->u.leftColumn<0 ) return 0;
    +   aff = pSrc->pTab->aCol[pTerm->u.leftColumn].affinity;
    +@@ -122019,14 +133584,14 @@ static void constructAutomaticIndex(
    +   Expr *pPartial = 0;         /* Partial Index Expression */
    +   int iContinue = 0;          /* Jump here to skip excluded rows */
    +   struct SrcList_item *pTabItem;  /* FROM clause term being indexed */
    +-  int addrCounter;            /* Address where integer counter is initialized */
    ++  int addrCounter = 0;        /* Address where integer counter is initialized */
    +   int regBase;                /* Array of registers where record is assembled */
    + 
    +   /* Generate code to skip over the creation and initialization of the
    +   ** transient index on 2nd and subsequent iterations of the loop. */
    +   v = pParse->pVdbe;
    +   assert( v!=0 );
    +-  addrInit = sqlite3CodeOnce(pParse); VdbeCoverage(v);
    ++  addrInit = sqlite3VdbeAddOp0(v, OP_Once); VdbeCoverage(v);
    + 
    +   /* Count the number of columns that will be added to the index
    +   ** and used to match WHERE clause constraints */
    +@@ -122110,7 +133675,7 @@ static void constructAutomaticIndex(
    +         idxCols |= cMask;
    +         pIdx->aiColumn[n] = pTerm->u.leftColumn;
    +         pColl = sqlite3BinaryCompareCollSeq(pParse, pX->pLeft, pX->pRight);
    +-        pIdx->azColl[n] = pColl ? pColl->zName : "BINARY";
    ++        pIdx->azColl[n] = pColl ? pColl->zName : sqlite3StrBINARY;
    +         n++;
    +       }
    +     }
    +@@ -122122,20 +133687,20 @@ static void constructAutomaticIndex(
    +   for(i=0; i<mxBitCol; i++){
    +     if( extraCols & MASKBIT(i) ){
    +       pIdx->aiColumn[n] = i;
    +-      pIdx->azColl[n] = "BINARY";
    ++      pIdx->azColl[n] = sqlite3StrBINARY;
    +       n++;
    +     }
    +   }
    +   if( pSrc->colUsed & MASKBIT(BMS-1) ){
    +     for(i=BMS-1; i<pTable->nCol; i++){
    +       pIdx->aiColumn[n] = i;
    +-      pIdx->azColl[n] = "BINARY";
    ++      pIdx->azColl[n] = sqlite3StrBINARY;
    +       n++;
    +     }
    +   }
    +   assert( n==nKeyCol );
    +   pIdx->aiColumn[n] = XN_ROWID;
    +-  pIdx->azColl[n] = "BINARY";
    ++  pIdx->azColl[n] = sqlite3StrBINARY;
    + 
    +   /* Create the automatic index */
    +   assert( pLevel->iIdxCur>=0 );
    +@@ -122171,7 +133736,9 @@ static void constructAutomaticIndex(
    +   if( pPartial ) sqlite3VdbeResolveLabel(v, iContinue);
    +   if( pTabItem->fg.viaCoroutine ){
    +     sqlite3VdbeChangeP2(v, addrCounter, regBase+n);
    +-    translateColumnToCopy(v, addrTop, pLevel->iTabCur, pTabItem->regResult, 1);
    ++    testcase( pParse->db->mallocFailed );
    ++    translateColumnToCopy(pParse, addrTop, pLevel->iTabCur,
    ++                          pTabItem->regResult, 1);
    +     sqlite3VdbeGoto(v, addrTop);
    +     pTabItem->fg.viaCoroutine = 0;
    +   }else{
    +@@ -122197,20 +133764,23 @@ end_auto_index_create:
    + ** by passing the pointer returned by this function to sqlite3_free().
    + */
    + static sqlite3_index_info *allocateIndexInfo(
    +-  Parse *pParse,
    +-  WhereClause *pWC,
    ++  Parse *pParse,                  /* The parsing context */
    ++  WhereClause *pWC,               /* The WHERE clause being analyzed */
    +   Bitmask mUnusable,              /* Ignore terms with these prereqs */
    +-  struct SrcList_item *pSrc,
    +-  ExprList *pOrderBy
    ++  struct SrcList_item *pSrc,      /* The FROM clause term that is the vtab */
    ++  ExprList *pOrderBy,             /* The ORDER BY clause */
    ++  u16 *pmNoOmit                   /* Mask of terms not to omit */
    + ){
    +   int i, j;
    +   int nTerm;
    +   struct sqlite3_index_constraint *pIdxCons;
    +   struct sqlite3_index_orderby *pIdxOrderBy;
    +   struct sqlite3_index_constraint_usage *pUsage;
    ++  struct HiddenIndexInfo *pHidden;
    +   WhereTerm *pTerm;
    +   int nOrderBy;
    +   sqlite3_index_info *pIdxInfo;
    ++  u16 mNoOmit = 0;
    + 
    +   /* Count the number of possible WHERE clause constraints referring
    +   ** to this virtual table */
    +@@ -122222,7 +133792,7 @@ static sqlite3_index_info *allocateIndexInfo(
    +     testcase( pTerm->eOperator & WO_ISNULL );
    +     testcase( pTerm->eOperator & WO_IS );
    +     testcase( pTerm->eOperator & WO_ALL );
    +-    if( (pTerm->eOperator & ~(WO_ISNULL|WO_EQUIV|WO_IS))==0 ) continue;
    ++    if( (pTerm->eOperator & ~(WO_EQUIV))==0 ) continue;
    +     if( pTerm->wtFlags & TERM_VNULL ) continue;
    +     assert( pTerm->u.leftColumn>=(-1) );
    +     nTerm++;
    +@@ -122248,7 +133818,7 @@ static sqlite3_index_info *allocateIndexInfo(
    +   */
    +   pIdxInfo = sqlite3DbMallocZero(pParse->db, sizeof(*pIdxInfo)
    +                            + (sizeof(*pIdxCons) + sizeof(*pUsage))*nTerm
    +-                           + sizeof(*pIdxOrderBy)*nOrderBy );
    ++                           + sizeof(*pIdxOrderBy)*nOrderBy + sizeof(*pHidden) );
    +   if( pIdxInfo==0 ){
    +     sqlite3ErrorMsg(pParse, "out of memory");
    +     return 0;
    +@@ -122259,7 +133829,8 @@ static sqlite3_index_info *allocateIndexInfo(
    +   ** changing them.  We have to do some funky casting in order to
    +   ** initialize those fields.
    +   */
    +-  pIdxCons = (struct sqlite3_index_constraint*)&pIdxInfo[1];
    ++  pHidden = (struct HiddenIndexInfo*)&pIdxInfo[1];
    ++  pIdxCons = (struct sqlite3_index_constraint*)&pHidden[1];
    +   pIdxOrderBy = (struct sqlite3_index_orderby*)&pIdxCons[nTerm];
    +   pUsage = (struct sqlite3_index_constraint_usage*)&pIdxOrderBy[nOrderBy];
    +   *(int*)&pIdxInfo->nConstraint = nTerm;
    +@@ -122269,8 +133840,10 @@ static sqlite3_index_info *allocateIndexInfo(
    +   *(struct sqlite3_index_constraint_usage**)&pIdxInfo->aConstraintUsage =
    +                                                                    pUsage;
    + 
    ++  pHidden->pWC = pWC;
    ++  pHidden->pParse = pParse;
    +   for(i=j=0, pTerm=pWC->a; i<pWC->nTerm; i++, pTerm++){
    +-    u8 op;
    ++    u16 op;
    +     if( pTerm->leftCursor != pSrc->iCursor ) continue;
    +     if( pTerm->prereqRight & mUnusable ) continue;
    +     assert( IsPowerOfTwo(pTerm->eOperator & ~WO_EQUIV) );
    +@@ -122278,24 +133851,42 @@ static sqlite3_index_info *allocateIndexInfo(
    +     testcase( pTerm->eOperator & WO_IS );
    +     testcase( pTerm->eOperator & WO_ISNULL );
    +     testcase( pTerm->eOperator & WO_ALL );
    +-    if( (pTerm->eOperator & ~(WO_ISNULL|WO_EQUIV|WO_IS))==0 ) continue;
    ++    if( (pTerm->eOperator & ~(WO_EQUIV))==0 ) continue;
    +     if( pTerm->wtFlags & TERM_VNULL ) continue;
    +     assert( pTerm->u.leftColumn>=(-1) );
    +     pIdxCons[j].iColumn = pTerm->u.leftColumn;
    +     pIdxCons[j].iTermOffset = i;
    +-    op = (u8)pTerm->eOperator & WO_ALL;
    ++    op = pTerm->eOperator & WO_ALL;
    +     if( op==WO_IN ) op = WO_EQ;
    +-    pIdxCons[j].op = op;
    +-    /* The direct assignment in the previous line is possible only because
    +-    ** the WO_ and SQLITE_INDEX_CONSTRAINT_ codes are identical.  The
    +-    ** following asserts verify this fact. */
    +-    assert( WO_EQ==SQLITE_INDEX_CONSTRAINT_EQ );
    +-    assert( WO_LT==SQLITE_INDEX_CONSTRAINT_LT );
    +-    assert( WO_LE==SQLITE_INDEX_CONSTRAINT_LE );
    +-    assert( WO_GT==SQLITE_INDEX_CONSTRAINT_GT );
    +-    assert( WO_GE==SQLITE_INDEX_CONSTRAINT_GE );
    +-    assert( WO_MATCH==SQLITE_INDEX_CONSTRAINT_MATCH );
    +-    assert( pTerm->eOperator & (WO_IN|WO_EQ|WO_LT|WO_LE|WO_GT|WO_GE|WO_MATCH) );
    ++    if( op==WO_AUX ){
    ++      pIdxCons[j].op = pTerm->eMatchOp;
    ++    }else if( op & (WO_ISNULL|WO_IS) ){
    ++      if( op==WO_ISNULL ){
    ++        pIdxCons[j].op = SQLITE_INDEX_CONSTRAINT_ISNULL;
    ++      }else{
    ++        pIdxCons[j].op = SQLITE_INDEX_CONSTRAINT_IS;
    ++      }
    ++    }else{
    ++      pIdxCons[j].op = (u8)op;
    ++      /* The direct assignment in the previous line is possible only because
    ++      ** the WO_ and SQLITE_INDEX_CONSTRAINT_ codes are identical.  The
    ++      ** following asserts verify this fact. */
    ++      assert( WO_EQ==SQLITE_INDEX_CONSTRAINT_EQ );
    ++      assert( WO_LT==SQLITE_INDEX_CONSTRAINT_LT );
    ++      assert( WO_LE==SQLITE_INDEX_CONSTRAINT_LE );
    ++      assert( WO_GT==SQLITE_INDEX_CONSTRAINT_GT );
    ++      assert( WO_GE==SQLITE_INDEX_CONSTRAINT_GE );
    ++      assert( pTerm->eOperator&(WO_IN|WO_EQ|WO_LT|WO_LE|WO_GT|WO_GE|WO_AUX) );
    ++
    ++      if( op & (WO_LT|WO_LE|WO_GT|WO_GE)
    ++       && sqlite3ExprIsVector(pTerm->pExpr->pRight) 
    ++      ){
    ++        if( i<16 ) mNoOmit |= (1 << i);
    ++        if( op==WO_LT ) pIdxCons[j].op = WO_LE;
    ++        if( op==WO_GT ) pIdxCons[j].op = WO_GE;
    ++      }
    ++    }
    ++
    +     j++;
    +   }
    +   for(i=0; i<nOrderBy; i++){
    +@@ -122304,6 +133895,7 @@ static sqlite3_index_info *allocateIndexInfo(
    +     pIdxOrderBy[i].desc = pOrderBy->a[i].sortOrder;
    +   }
    + 
    ++  *pmNoOmit = mNoOmit;
    +   return pIdxInfo;
    + }
    + 
    +@@ -122323,7 +133915,6 @@ static sqlite3_index_info *allocateIndexInfo(
    + */
    + static int vtabBestIndex(Parse *pParse, Table *pTab, sqlite3_index_info *p){
    +   sqlite3_vtab *pVtab = sqlite3GetVTable(pParse->db, pTab)->pVtab;
    +-  int i;
    +   int rc;
    + 
    +   TRACE_IDX_INPUTS(p);
    +@@ -122332,7 +133923,7 @@ static int vtabBestIndex(Parse *pParse, Table *pTab, sqlite3_index_info *p){
    + 
    +   if( rc!=SQLITE_OK ){
    +     if( rc==SQLITE_NOMEM ){
    +-      pParse->db->mallocFailed = 1;
    ++      sqlite3OomFault(pParse->db);
    +     }else if( !pVtab->zErrMsg ){
    +       sqlite3ErrorMsg(pParse, "%s", sqlite3ErrStr(rc));
    +     }else{
    +@@ -122342,12 +133933,16 @@ static int vtabBestIndex(Parse *pParse, Table *pTab, sqlite3_index_info *p){
    +   sqlite3_free(pVtab->zErrMsg);
    +   pVtab->zErrMsg = 0;
    + 
    ++#if 0
    ++  /* This error is now caught by the caller.
    ++  ** Search for "xBestIndex malfunction" below */
    +   for(i=0; i<p->nConstraint; i++){
    +     if( !p->aConstraint[i].usable && p->aConstraintUsage[i].argvIndex>0 ){
    +       sqlite3ErrorMsg(pParse, 
    +           "table %s: xBestIndex returned an invalid plan", pTab->zName);
    +     }
    +   }
    ++#endif
    + 
    +   return pParse->nErr;
    + }
    +@@ -122539,7 +134134,7 @@ static int whereKeyStats(
    +       iGap = iGap/3;
    +     }
    +     aStat[0] = iLower + iGap;
    +-    aStat[1] = pIdx->aAvgEq[iCol];
    ++    aStat[1] = pIdx->aAvgEq[nField-1];
    +   }
    + 
    +   /* Restore the pRec->nField value before returning.  */
    +@@ -122576,7 +134171,7 @@ static LogEst whereRangeAdjust(WhereTerm *pTerm, LogEst nNew){
    + /*
    + ** Return the affinity for a single column of an index.
    + */
    +-static char sqlite3IndexColumnAffinity(sqlite3 *db, Index *pIdx, int iCol){
    ++SQLITE_PRIVATE char sqlite3IndexColumnAffinity(sqlite3 *db, Index *pIdx, int iCol){
    +   assert( iCol>=0 && iCol<pIdx->nColumn );
    +   if( !pIdx->zColAff ){
    +     if( sqlite3IndexAffinityStr(db, pIdx)==0 ) return SQLITE_AFF_BLOB;
    +@@ -122753,7 +134348,8 @@ static int whereRangeScanEst(
    +     if( nEq==pBuilder->nRecValid ){
    +       UnpackedRecord *pRec = pBuilder->pRec;
    +       tRowcnt a[2];
    +-      u8 aff;
    ++      int nBtm = pLoop->u.btree.nBtm;
    ++      int nTop = pLoop->u.btree.nTop;
    + 
    +       /* 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
    +@@ -122783,8 +134379,6 @@ static int whereRangeScanEst(
    +         testcase( pRec->nField!=pBuilder->nRecValid );
    +         pRec->nField = pBuilder->nRecValid;
    +       }
    +-      aff = sqlite3IndexColumnAffinity(pParse->db, p, nEq);
    +-      assert( nEq!=p->nKeyCol || aff==SQLITE_AFF_INTEGER );
    +       /* Determine iLower and iUpper using ($P) only. */
    +       if( nEq==0 ){
    +         iLower = 0;
    +@@ -122803,17 +134397,20 @@ static int whereRangeScanEst(
    +       if( p->aSortOrder[nEq] ){
    +         /* The roles of pLower and pUpper are swapped for a DESC index */
    +         SWAP(WhereTerm*, pLower, pUpper);
    ++        SWAP(int, nBtm, nTop);
    +       }
    + 
    +       /* If possible, improve on the iLower estimate using ($P:$L). */
    +       if( pLower ){
    +-        int bOk;                    /* True if value is extracted from pExpr */
    ++        int n;                    /* Values extracted from pExpr */
    +         Expr *pExpr = pLower->pExpr->pRight;
    +-        rc = sqlite3Stat4ProbeSetValue(pParse, p, &pRec, pExpr, aff, nEq, &bOk);
    +-        if( rc==SQLITE_OK && bOk ){
    ++        rc = sqlite3Stat4ProbeSetValue(pParse, p, &pRec, pExpr, nBtm, nEq, &n);
    ++        if( rc==SQLITE_OK && n ){
    +           tRowcnt iNew;
    ++          u16 mask = WO_GT|WO_LE;
    ++          if( sqlite3ExprVectorSize(pExpr)>n ) mask = (WO_LE|WO_LT);
    +           iLwrIdx = whereKeyStats(pParse, p, pRec, 0, a);
    +-          iNew = a[0] + ((pLower->eOperator & (WO_GT|WO_LE)) ? a[1] : 0);
    ++          iNew = a[0] + ((pLower->eOperator & mask) ? a[1] : 0);
    +           if( iNew>iLower ) iLower = iNew;
    +           nOut--;
    +           pLower = 0;
    +@@ -122822,13 +134419,15 @@ static int whereRangeScanEst(
    + 
    +       /* If possible, improve on the iUpper estimate using ($P:$U). */
    +       if( pUpper ){
    +-        int bOk;                    /* True if value is extracted from pExpr */
    ++        int n;                    /* Values extracted from pExpr */
    +         Expr *pExpr = pUpper->pExpr->pRight;
    +-        rc = sqlite3Stat4ProbeSetValue(pParse, p, &pRec, pExpr, aff, nEq, &bOk);
    +-        if( rc==SQLITE_OK && bOk ){
    ++        rc = sqlite3Stat4ProbeSetValue(pParse, p, &pRec, pExpr, nTop, nEq, &n);
    ++        if( rc==SQLITE_OK && n ){
    +           tRowcnt iNew;
    ++          u16 mask = WO_GT|WO_LE;
    ++          if( sqlite3ExprVectorSize(pExpr)>n ) mask = (WO_LE|WO_LT);
    +           iUprIdx = whereKeyStats(pParse, p, pRec, 1, a);
    +-          iNew = a[0] + ((pUpper->eOperator & (WO_GT|WO_LE)) ? a[1] : 0);
    ++          iNew = a[0] + ((pUpper->eOperator & mask) ? a[1] : 0);
    +           if( iNew<iUpper ) iUpper = iNew;
    +           nOut--;
    +           pUpper = 0;
    +@@ -122918,7 +134517,6 @@ static int whereEqualScanEst(
    +   Index *p = pBuilder->pNew->u.btree.pIndex;
    +   int nEq = pBuilder->pNew->u.btree.nEq;
    +   UnpackedRecord *pRec = pBuilder->pRec;
    +-  u8 aff;                   /* Column affinity */
    +   int rc;                   /* Subfunction return code */
    +   tRowcnt a[2];             /* Statistics */
    +   int bOk;
    +@@ -122942,15 +134540,15 @@ static int whereEqualScanEst(
    +     return SQLITE_OK;
    +   }
    + 
    +-  aff = sqlite3IndexColumnAffinity(pParse->db, p, nEq-1);
    +-  rc = sqlite3Stat4ProbeSetValue(pParse, p, &pRec, pExpr, aff, nEq-1, &bOk);
    ++  rc = sqlite3Stat4ProbeSetValue(pParse, p, &pRec, pExpr, 1, nEq-1, &bOk);
    +   pBuilder->pRec = pRec;
    +   if( rc!=SQLITE_OK ) return rc;
    +   if( bOk==0 ) return SQLITE_NOTFOUND;
    +   pBuilder->nRecValid = nEq;
    + 
    +   whereKeyStats(pParse, p, pRec, 0, a);
    +-  WHERETRACE(0x10,("equality scan regions: %d\n", (int)a[1]));
    ++  WHERETRACE(0x10,("equality scan regions %s(%d): %d\n",
    ++                   p->zName, nEq-1, (int)a[1]));
    +   *pnRow = a[1];
    +   
    +   return rc;
    +@@ -123016,30 +134614,58 @@ static void whereTermPrint(WhereTerm *pTerm, int iTerm){
    +     sqlite3DebugPrintf("TERM-%-3d NULL\n", iTerm);
    +   }else{
    +     char zType[4];
    ++    char zLeft[50];
    +     memcpy(zType, "...", 4);
    +     if( pTerm->wtFlags & TERM_VIRTUAL ) zType[0] = 'V';
    +     if( pTerm->eOperator & WO_EQUIV  ) zType[1] = 'E';
    +     if( ExprHasProperty(pTerm->pExpr, EP_FromJoin) ) zType[2] = 'L';
    ++    if( pTerm->eOperator & WO_SINGLE ){
    ++      sqlite3_snprintf(sizeof(zLeft),zLeft,"left={%d:%d}",
    ++                       pTerm->leftCursor, pTerm->u.leftColumn);
    ++    }else if( (pTerm->eOperator & WO_OR)!=0 && pTerm->u.pOrInfo!=0 ){
    ++      sqlite3_snprintf(sizeof(zLeft),zLeft,"indexable=0x%lld", 
    ++                       pTerm->u.pOrInfo->indexable);
    ++    }else{
    ++      sqlite3_snprintf(sizeof(zLeft),zLeft,"left=%d", pTerm->leftCursor);
    ++    }
    +     sqlite3DebugPrintf(
    +-       "TERM-%-3d %p %s cursor=%-3d prob=%-3d op=0x%03x wtFlags=0x%04x\n",
    +-       iTerm, pTerm, zType, pTerm->leftCursor, pTerm->truthProb,
    ++       "TERM-%-3d %p %s %-12s prob=%-3d op=0x%03x wtFlags=0x%04x",
    ++       iTerm, pTerm, zType, zLeft, pTerm->truthProb,
    +        pTerm->eOperator, pTerm->wtFlags);
    ++    if( pTerm->iField ){
    ++      sqlite3DebugPrintf(" iField=%d\n", pTerm->iField);
    ++    }else{
    ++      sqlite3DebugPrintf("\n");
    ++    }
    +     sqlite3TreeViewExpr(0, pTerm->pExpr, 0);
    +   }
    + }
    + #endif
    + 
    ++#ifdef WHERETRACE_ENABLED
    ++/*
    ++** Show the complete content of a WhereClause
    ++*/
    ++SQLITE_PRIVATE void sqlite3WhereClausePrint(WhereClause *pWC){
    ++  int i;
    ++  for(i=0; i<pWC->nTerm; i++){
    ++    whereTermPrint(&pWC->a[i], i);
    ++  }
    ++}
    ++#endif
    ++
    + #ifdef WHERETRACE_ENABLED
    + /*
    + ** Print a WhereLoop object for debugging purposes
    + */
    + static void whereLoopPrint(WhereLoop *p, WhereClause *pWC){
    +   WhereInfo *pWInfo = pWC->pWInfo;
    +-  int nb = 1+(pWInfo->pTabList->nSrc+7)/8;
    ++  int nb = 1+(pWInfo->pTabList->nSrc+3)/4;
    +   struct SrcList_item *pItem = pWInfo->pTabList->a + p->iTab;
    +   Table *pTab = pItem->pTab;
    ++  Bitmask mAll = (((Bitmask)1)<<(nb*4)) - 1;
    +   sqlite3DebugPrintf("%c%2d.%0*llx.%0*llx", p->cId,
    +-                     p->iTab, nb, p->maskSelf, nb, p->prereq);
    ++                     p->iTab, nb, p->maskSelf, nb, p->prereq & mAll);
    +   sqlite3DebugPrintf(" %12s",
    +                      pItem->zAlias ? pItem->zAlias : pTab->zName);
    +   if( (p->wsFlags & WHERE_VIRTUALTABLE)==0 ){
    +@@ -123102,7 +134728,7 @@ static void whereLoopClearUnion(sqlite3 *db, WhereLoop *p){
    +       p->u.vtab.idxStr = 0;
    +     }else if( (p->wsFlags & WHERE_AUTO_INDEX)!=0 && p->u.btree.pIndex!=0 ){
    +       sqlite3DbFree(db, p->u.btree.pIndex->zColAff);
    +-      sqlite3DbFree(db, p->u.btree.pIndex);
    ++      sqlite3DbFreeNN(db, p->u.btree.pIndex);
    +       p->u.btree.pIndex = 0;
    +     }
    +   }
    +@@ -123112,7 +134738,7 @@ static void whereLoopClearUnion(sqlite3 *db, WhereLoop *p){
    + ** Deallocate internal memory used by a WhereLoop object
    + */
    + static void whereLoopClear(sqlite3 *db, WhereLoop *p){
    +-  if( p->aLTerm!=p->aLTermSpace ) sqlite3DbFree(db, p->aLTerm);
    ++  if( p->aLTerm!=p->aLTermSpace ) sqlite3DbFreeNN(db, p->aLTerm);
    +   whereLoopClearUnion(db, p);
    +   whereLoopInit(p);
    + }
    +@@ -123124,10 +134750,10 @@ static int whereLoopResize(sqlite3 *db, WhereLoop *p, int n){
    +   WhereTerm **paNew;
    +   if( p->nLSlot>=n ) return SQLITE_OK;
    +   n = (n+7)&~7;
    +-  paNew = sqlite3DbMallocRaw(db, sizeof(p->aLTerm[0])*n);
    +-  if( paNew==0 ) return SQLITE_NOMEM;
    ++  paNew = sqlite3DbMallocRawNN(db, sizeof(p->aLTerm[0])*n);
    ++  if( paNew==0 ) return SQLITE_NOMEM_BKPT;
    +   memcpy(paNew, p->aLTerm, sizeof(p->aLTerm[0])*p->nLSlot);
    +-  if( p->aLTerm!=p->aLTermSpace ) sqlite3DbFree(db, p->aLTerm);
    ++  if( p->aLTerm!=p->aLTermSpace ) sqlite3DbFreeNN(db, p->aLTerm);
    +   p->aLTerm = paNew;
    +   p->nLSlot = n;
    +   return SQLITE_OK;
    +@@ -123140,7 +134766,7 @@ static int whereLoopXfer(sqlite3 *db, WhereLoop *pTo, WhereLoop *pFrom){
    +   whereLoopClearUnion(db, pTo);
    +   if( whereLoopResize(db, pTo, pFrom->nLTerm) ){
    +     memset(&pTo->u, 0, sizeof(pTo->u));
    +-    return SQLITE_NOMEM;
    ++    return SQLITE_NOMEM_BKPT;
    +   }
    +   memcpy(pTo, pFrom, WHERE_LOOP_XFER_SZ);
    +   memcpy(pTo->aLTerm, pFrom->aLTerm, pTo->nLTerm*sizeof(pTo->aLTerm[0]));
    +@@ -123157,47 +134783,47 @@ static int whereLoopXfer(sqlite3 *db, WhereLoop *pTo, WhereLoop *pFrom){
    + */
    + static void whereLoopDelete(sqlite3 *db, WhereLoop *p){
    +   whereLoopClear(db, p);
    +-  sqlite3DbFree(db, p);
    ++  sqlite3DbFreeNN(db, p);
    + }
    + 
    + /*
    + ** Free a WhereInfo structure
    + */
    + static void whereInfoFree(sqlite3 *db, WhereInfo *pWInfo){
    +-  if( ALWAYS(pWInfo) ){
    +-    int i;
    +-    for(i=0; i<pWInfo->nLevel; i++){
    +-      WhereLevel *pLevel = &pWInfo->a[i];
    +-      if( pLevel->pWLoop && (pLevel->pWLoop->wsFlags & WHERE_IN_ABLE) ){
    +-        sqlite3DbFree(db, pLevel->u.in.aInLoop);
    +-      }
    +-    }
    +-    sqlite3WhereClauseClear(&pWInfo->sWC);
    +-    while( pWInfo->pLoops ){
    +-      WhereLoop *p = pWInfo->pLoops;
    +-      pWInfo->pLoops = p->pNextLoop;
    +-      whereLoopDelete(db, p);
    ++  int i;
    ++  assert( pWInfo!=0 );
    ++  for(i=0; i<pWInfo->nLevel; i++){
    ++    WhereLevel *pLevel = &pWInfo->a[i];
    ++    if( pLevel->pWLoop && (pLevel->pWLoop->wsFlags & WHERE_IN_ABLE) ){
    ++      sqlite3DbFree(db, pLevel->u.in.aInLoop);
    +     }
    +-    sqlite3DbFree(db, pWInfo);
    +   }
    ++  sqlite3WhereClauseClear(&pWInfo->sWC);
    ++  while( pWInfo->pLoops ){
    ++    WhereLoop *p = pWInfo->pLoops;
    ++    pWInfo->pLoops = p->pNextLoop;
    ++    whereLoopDelete(db, p);
    ++  }
    ++  sqlite3DbFreeNN(db, pWInfo);
    + }
    + 
    + /*
    + ** Return TRUE if all of the following are true:
    + **
    + **   (1)  X has the same or lower cost that Y
    +-**   (2)  X is a proper subset of Y
    +-**   (3)  X skips at least as many columns as 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.
    ++**   (2)  X uses fewer WHERE clause terms than Y
    ++**   (3)  Every WHERE clause term used by X is also used by Y
    ++**   (4)  X skips at least as many columns as Y
    ++**   (5)  If X is a covering index, than Y is too
    + **
    ++** Conditions (2) and (3) mean that X is a "proper subset" of 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.  The third rule
    ++** relationship is inverted and needs to be adjusted.  Constraint (4)
    + ** was added because if X uses skip-scan less than Y it still might
    +-** deserve a lower cost even if it is a proper subset of Y.
    ++** deserve a lower cost even if it is a proper subset of Y.  Constraint (5)
    ++** was added because a covering index probably deserves to have a lower cost
    ++** than a non-covering index even if it is a proper subset.
    + */
    + static int whereLoopCheaperProperSubset(
    +   const WhereLoop *pX,       /* First WhereLoop to compare */
    +@@ -123219,6 +134845,10 @@ static int whereLoopCheaperProperSubset(
    +     }
    +     if( j<0 ) return 0;  /* X not a subset of Y since term X[i] not used by Y */
    +   }
    ++  if( (pX->wsFlags&WHERE_IDX_ONLY)!=0 
    ++   && (pY->wsFlags&WHERE_IDX_ONLY)==0 ){
    ++    return 0;  /* Constraint (5) */
    ++  }
    +   return 1;  /* All conditions meet */
    + }
    + 
    +@@ -123261,16 +134891,17 @@ static void whereLoopAdjustCost(const WhereLoop *p, WhereLoop *pTemplate){
    + 
    + /*
    + ** Search the list of WhereLoops in *ppPrev looking for one that can be
    +-** supplanted by pTemplate.
    ++** replaced 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.
    ++** Return NULL if pTemplate does not belong on the WhereLoop list.
    ++** In other words if pTemplate ought to be dropped from further consideration.
    + **
    +-** If pX is a WhereLoop that pTemplate can supplant, then return the
    ++** If pX is a WhereLoop that pTemplate can replace, 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.
    ++** If pTemplate cannot replace any existing element of the list but needs
    ++** to be added to the list as a new entry, then return a pointer to the
    ++** tail of the list.
    + */
    + static WhereLoop **whereLoopFindLesser(
    +   WhereLoop **ppPrev,
    +@@ -123364,6 +134995,7 @@ static int whereLoopInsert(WhereLoopBuilder *pBuilder, WhereLoop *pTemplate){
    +   WhereLoop **ppPrev, *p;
    +   WhereInfo *pWInfo = pBuilder->pWInfo;
    +   sqlite3 *db = pWInfo->pParse->db;
    ++  int rc;
    + 
    +   /* If pBuilder->pOrSet is defined, then only keep track of the costs
    +   ** and prereqs.
    +@@ -123414,15 +135046,17 @@ static int whereLoopInsert(WhereLoopBuilder *pBuilder, WhereLoop *pTemplate){
    +     if( p!=0 ){
    +       sqlite3DebugPrintf("replace: ");
    +       whereLoopPrint(p, pBuilder->pWC);
    ++      sqlite3DebugPrintf("   with: ");
    ++    }else{
    ++      sqlite3DebugPrintf("    add: ");
    +     }
    +-    sqlite3DebugPrintf("    add: ");
    +     whereLoopPrint(pTemplate, pBuilder->pWC);
    +   }
    + #endif
    +   if( p==0 ){
    +     /* Allocate a new WhereLoop to add to the end of the list */
    +-    *ppPrev = p = sqlite3DbMallocRaw(db, sizeof(WhereLoop));
    +-    if( p==0 ) return SQLITE_NOMEM;
    ++    *ppPrev = p = sqlite3DbMallocRawNN(db, sizeof(WhereLoop));
    ++    if( p==0 ) return SQLITE_NOMEM_BKPT;
    +     whereLoopInit(p);
    +     p->pNextLoop = 0;
    +   }else{
    +@@ -123446,14 +135080,14 @@ static int whereLoopInsert(WhereLoopBuilder *pBuilder, WhereLoop *pTemplate){
    +       whereLoopDelete(db, pToDel);
    +     }
    +   }
    +-  whereLoopXfer(db, p, pTemplate);
    ++  rc = whereLoopXfer(db, p, pTemplate);
    +   if( (p->wsFlags & WHERE_VIRTUALTABLE)==0 ){
    +     Index *pIndex = p->u.btree.pIndex;
    +     if( pIndex && pIndex->tnum==0 ){
    +       p->u.btree.pIndex = 0;
    +     }
    +   }
    +-  return SQLITE_OK;
    ++  return rc;
    + }
    + 
    + /*
    +@@ -123531,6 +135165,72 @@ static void whereLoopOutputAdjust(
    +   if( pLoop->nOut > nRow-iReduce )  pLoop->nOut = nRow - iReduce;
    + }
    + 
    ++/* 
    ++** Term pTerm is a vector range comparison operation. The first comparison
    ++** in the vector can be optimized using column nEq of the index. This
    ++** function returns the total number of vector elements that can be used
    ++** as part of the range comparison.
    ++**
    ++** For example, if the query is:
    ++**
    ++**   WHERE a = ? AND (b, c, d) > (?, ?, ?)
    ++**
    ++** and the index:
    ++**
    ++**   CREATE INDEX ... ON (a, b, c, d, e)
    ++**
    ++** then this function would be invoked with nEq=1. The value returned in
    ++** this case is 3.
    ++*/
    ++static int whereRangeVectorLen(
    ++  Parse *pParse,       /* Parsing context */
    ++  int iCur,            /* Cursor open on pIdx */
    ++  Index *pIdx,         /* The index to be used for a inequality constraint */
    ++  int nEq,             /* Number of prior equality constraints on same index */
    ++  WhereTerm *pTerm     /* The vector inequality constraint */
    ++){
    ++  int nCmp = sqlite3ExprVectorSize(pTerm->pExpr->pLeft);
    ++  int i;
    ++
    ++  nCmp = MIN(nCmp, (pIdx->nColumn - nEq));
    ++  for(i=1; i<nCmp; i++){
    ++    /* Test if comparison i of pTerm is compatible with column (i+nEq) 
    ++    ** of the index. If not, exit the loop.  */
    ++    char aff;                     /* Comparison affinity */
    ++    char idxaff = 0;              /* Indexed columns affinity */
    ++    CollSeq *pColl;               /* Comparison collation sequence */
    ++    Expr *pLhs = pTerm->pExpr->pLeft->x.pList->a[i].pExpr;
    ++    Expr *pRhs = pTerm->pExpr->pRight;
    ++    if( pRhs->flags & EP_xIsSelect ){
    ++      pRhs = pRhs->x.pSelect->pEList->a[i].pExpr;
    ++    }else{
    ++      pRhs = pRhs->x.pList->a[i].pExpr;
    ++    }
    ++
    ++    /* Check that the LHS of the comparison is a column reference to
    ++    ** the right column of the right source table. And that the sort
    ++    ** order of the index column is the same as the sort order of the
    ++    ** leftmost index column.  */
    ++    if( pLhs->op!=TK_COLUMN 
    ++     || pLhs->iTable!=iCur 
    ++     || pLhs->iColumn!=pIdx->aiColumn[i+nEq] 
    ++     || pIdx->aSortOrder[i+nEq]!=pIdx->aSortOrder[nEq]
    ++    ){
    ++      break;
    ++    }
    ++
    ++    testcase( pLhs->iColumn==XN_ROWID );
    ++    aff = sqlite3CompareAffinity(pRhs, sqlite3ExprAffinity(pLhs));
    ++    idxaff = sqlite3TableColumnAffinity(pIdx->pTable, pLhs->iColumn);
    ++    if( aff!=idxaff ) break;
    ++
    ++    pColl = sqlite3BinaryCompareCollSeq(pParse, pLhs, pRhs);
    ++    if( pColl==0 ) break;
    ++    if( sqlite3StrICmp(pColl->zName, pIdx->azColl[i+nEq]) ) break;
    ++  }
    ++  return i;
    ++}
    ++
    + /*
    + ** Adjust the cost C by the costMult facter T.  This only occurs if
    + ** compiled with -DSQLITE_ENABLE_COSTMULT
    +@@ -123569,6 +135269,8 @@ static int whereLoopAddBtreeIndex(
    +   Bitmask saved_prereq;           /* Original value of pNew->prereq */
    +   u16 saved_nLTerm;               /* Original value of pNew->nLTerm */
    +   u16 saved_nEq;                  /* Original value of pNew->u.btree.nEq */
    ++  u16 saved_nBtm;                 /* Original value of pNew->u.btree.nBtm */
    ++  u16 saved_nTop;                 /* Original value of pNew->u.btree.nTop */
    +   u16 saved_nSkip;                /* Original value of pNew->nSkip */
    +   u32 saved_wsFlags;              /* Original value of pNew->wsFlags */
    +   LogEst saved_nOut;              /* Original value of pNew->nOut */
    +@@ -123578,15 +135280,16 @@ static int whereLoopAddBtreeIndex(
    +   WhereTerm *pTop = 0, *pBtm = 0; /* Top and bottom range constraints */
    + 
    +   pNew = pBuilder->pNew;
    +-  if( db->mallocFailed ) return SQLITE_NOMEM;
    ++  if( db->mallocFailed ) return SQLITE_NOMEM_BKPT;
    ++  WHERETRACE(0x800, ("BEGIN addBtreeIdx(%s), nEq=%d\n",
    ++                     pProbe->zName, pNew->u.btree.nEq));
    + 
    +   assert( (pNew->wsFlags & WHERE_VIRTUALTABLE)==0 );
    +   assert( (pNew->wsFlags & WHERE_TOP_LIMIT)==0 );
    +   if( pNew->wsFlags & WHERE_BTM_LIMIT ){
    +     opMask = WO_LT|WO_LE;
    +-  }else if( /*pProbe->tnum<=0 ||*/ (pSrc->fg.jointype & JT_LEFT)!=0 ){
    +-    opMask = WO_EQ|WO_IN|WO_GT|WO_GE|WO_LT|WO_LE;
    +   }else{
    ++    assert( pNew->u.btree.nBtm==0 );
    +     opMask = WO_EQ|WO_IN|WO_GT|WO_GE|WO_LT|WO_LE|WO_ISNULL|WO_IS;
    +   }
    +   if( pProbe->bUnordered ) opMask &= ~(WO_GT|WO_GE|WO_LT|WO_LE);
    +@@ -123594,6 +135297,8 @@ static int whereLoopAddBtreeIndex(
    +   assert( pNew->u.btree.nEq<pProbe->nColumn );
    + 
    +   saved_nEq = pNew->u.btree.nEq;
    ++  saved_nBtm = pNew->u.btree.nBtm;
    ++  saved_nTop = pNew->u.btree.nTop;
    +   saved_nSkip = pNew->nSkip;
    +   saved_nLTerm = pNew->nLTerm;
    +   saved_wsFlags = pNew->wsFlags;
    +@@ -123623,8 +135328,27 @@ static int whereLoopAddBtreeIndex(
    +     ** to mix with a lower range bound from some other source */
    +     if( pTerm->wtFlags & TERM_LIKEOPT && pTerm->eOperator==WO_LT ) continue;
    + 
    ++    /* Do not allow IS constraints from the WHERE clause to be used by the
    ++    ** right table of a LEFT JOIN.  Only constraints in the ON clause are
    ++    ** allowed */
    ++    if( (pSrc->fg.jointype & JT_LEFT)!=0
    ++     && !ExprHasProperty(pTerm->pExpr, EP_FromJoin)
    ++     && (eOp & (WO_IS|WO_ISNULL))!=0
    ++    ){
    ++      testcase( eOp & WO_IS );
    ++      testcase( eOp & WO_ISNULL );
    ++      continue;
    ++    }
    ++
    ++    if( IsUniqueIndex(pProbe) && saved_nEq==pProbe->nKeyCol-1 ){
    ++      pBuilder->bldFlags |= SQLITE_BLDF_UNIQUE;
    ++    }else{
    ++      pBuilder->bldFlags |= SQLITE_BLDF_INDEXED;
    ++    }
    +     pNew->wsFlags = saved_wsFlags;
    +     pNew->u.btree.nEq = saved_nEq;
    ++    pNew->u.btree.nBtm = saved_nBtm;
    ++    pNew->u.btree.nTop = saved_nTop;
    +     pNew->nLTerm = saved_nLTerm;
    +     if( whereLoopResize(db, pNew, pNew->nLTerm+1) ) break; /* OOM */
    +     pNew->aLTerm[pNew->nLTerm++] = pTerm;
    +@@ -123641,20 +135365,29 @@ static int whereLoopAddBtreeIndex(
    +       pNew->wsFlags |= WHERE_COLUMN_IN;
    +       if( ExprHasProperty(pExpr, EP_xIsSelect) ){
    +         /* "x IN (SELECT ...)":  TUNING: the SELECT returns 25 rows */
    ++        int i;
    +         nIn = 46;  assert( 46==sqlite3LogEst(25) );
    ++
    ++        /* The expression may actually be of the form (x, y) IN (SELECT...).
    ++        ** In this case there is a separate term for each of (x) and (y).
    ++        ** However, the nIn multiplier should only be applied once, not once
    ++        ** for each such term. The following loop checks that pTerm is the
    ++        ** first such term in use, and sets nIn back to 0 if it is not. */
    ++        for(i=0; i<pNew->nLTerm-1; i++){
    ++          if( pNew->aLTerm[i] && pNew->aLTerm[i]->pExpr==pExpr ) nIn = 0;
    ++        }
    +       }else if( ALWAYS(pExpr->x.pList && pExpr->x.pList->nExpr) ){
    +         /* "x IN (value, value, ...)" */
    +         nIn = sqlite3LogEst(pExpr->x.pList->nExpr);
    ++        assert( nIn>0 );  /* RHS always has 2 or more terms...  The parser
    ++                          ** changes "x IN (?)" into "x=?". */
    +       }
    +-      assert( nIn>0 );  /* RHS always has 2 or more terms...  The parser
    +-                        ** changes "x IN (?)" into "x=?". */
    +-
    +     }else if( eOp & (WO_EQ|WO_IS) ){
    +       int iCol = pProbe->aiColumn[saved_nEq];
    +       pNew->wsFlags |= WHERE_COLUMN_EQ;
    +       assert( saved_nEq==pNew->u.btree.nEq );
    +       if( iCol==XN_ROWID 
    +-       || (iCol>0 && nInMul==0 && saved_nEq==pProbe->nKeyCol-1)
    ++       || (iCol>=0 && nInMul==0 && saved_nEq==pProbe->nKeyCol-1)
    +       ){
    +         if( iCol>=0 && pProbe->uniqNotNull==0 ){
    +           pNew->wsFlags |= WHERE_UNQ_WANTED;
    +@@ -123668,6 +135401,9 @@ static int whereLoopAddBtreeIndex(
    +       testcase( eOp & WO_GT );
    +       testcase( eOp & WO_GE );
    +       pNew->wsFlags |= WHERE_COLUMN_RANGE|WHERE_BTM_LIMIT;
    ++      pNew->u.btree.nBtm = whereRangeVectorLen(
    ++          pParse, pSrc->iCursor, pProbe, saved_nEq, pTerm
    ++      );
    +       pBtm = pTerm;
    +       pTop = 0;
    +       if( pTerm->wtFlags & TERM_LIKEOPT ){
    +@@ -123680,12 +135416,16 @@ static int whereLoopAddBtreeIndex(
    +         if( whereLoopResize(db, pNew, pNew->nLTerm+1) ) break; /* OOM */
    +         pNew->aLTerm[pNew->nLTerm++] = pTop;
    +         pNew->wsFlags |= WHERE_TOP_LIMIT;
    ++        pNew->u.btree.nTop = 1;
    +       }
    +     }else{
    +       assert( eOp & (WO_LT|WO_LE) );
    +       testcase( eOp & WO_LT );
    +       testcase( eOp & WO_LE );
    +       pNew->wsFlags |= WHERE_COLUMN_RANGE|WHERE_TOP_LIMIT;
    ++      pNew->u.btree.nTop = whereRangeVectorLen(
    ++          pParse, pSrc->iCursor, pProbe, saved_nEq, pTerm
    ++      );
    +       pTop = pTerm;
    +       pBtm = (pNew->wsFlags & WHERE_BTM_LIMIT)!=0 ?
    +                      pNew->aLTerm[pNew->nLTerm-2] : 0;
    +@@ -123785,6 +135525,8 @@ static int whereLoopAddBtreeIndex(
    +   }
    +   pNew->prereq = saved_prereq;
    +   pNew->u.btree.nEq = saved_nEq;
    ++  pNew->u.btree.nBtm = saved_nBtm;
    ++  pNew->u.btree.nTop = saved_nTop;
    +   pNew->nSkip = saved_nSkip;
    +   pNew->wsFlags = saved_wsFlags;
    +   pNew->nOut = saved_nOut;
    +@@ -123824,6 +135566,8 @@ static int whereLoopAddBtreeIndex(
    +     pNew->wsFlags = saved_wsFlags;
    +   }
    + 
    ++  WHERETRACE(0x800, ("END addBtreeIdx(%s), nEq=%d, rc=%d\n",
    ++                      pProbe->zName, saved_nEq, rc));
    +   return rc;
    + }
    + 
    +@@ -123856,7 +135600,7 @@ static int indexMightHelpWithOrderBy(
    +     }else if( (aColExpr = pIndex->aColExpr)!=0 ){
    +       for(jj=0; jj<pIndex->nKeyCol; jj++){
    +         if( pIndex->aiColumn[jj]!=XN_EXPR ) continue;
    +-        if( sqlite3ExprCompare(pExpr,aColExpr->a[jj].pExpr,iCursor)==0 ){
    ++        if( sqlite3ExprCompareSkip(pExpr,aColExpr->a[jj].pExpr,iCursor)==0 ){
    +           return 1;
    +         }
    +       }
    +@@ -123889,14 +135633,16 @@ static Bitmask columnsInIndex(Index *pIdx){
    + static int whereUsablePartialIndex(int iTab, WhereClause *pWC, Expr *pWhere){
    +   int i;
    +   WhereTerm *pTerm;
    ++  Parse *pParse = pWC->pWInfo->pParse;
    +   while( pWhere->op==TK_AND ){
    +     if( !whereUsablePartialIndex(iTab,pWC,pWhere->pLeft) ) return 0;
    +     pWhere = pWhere->pRight;
    +   }
    ++  if( pParse->db->flags & SQLITE_EnableQPSG ) pParse = 0;
    +   for(i=0, pTerm=pWC->a; i<pWC->nTerm; i++, pTerm++){
    +     Expr *pExpr = pTerm->pExpr;
    +-    if( sqlite3ExprImpliesExpr(pExpr, pWhere, iTab) 
    +-     && (!ExprHasProperty(pExpr, EP_FromJoin) || pExpr->iRightJoinTable==iTab)
    ++    if( (!ExprHasProperty(pExpr, EP_FromJoin) || pExpr->iRightJoinTable==iTab)
    ++     && sqlite3ExprImpliesExpr(pParse, pExpr, pWhere, iTab) 
    +     ){
    +       return 1;
    +     }
    +@@ -123906,7 +135652,7 @@ 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
    ++** is identified 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
    +@@ -123942,7 +135688,7 @@ static int whereUsablePartialIndex(int iTab, WhereClause *pWC, Expr *pWhere){
    + */
    + static int whereLoopAddBtree(
    +   WhereLoopBuilder *pBuilder, /* WHERE clause information */
    +-  Bitmask mExtra              /* Extra prerequesites for using this table */
    ++  Bitmask mPrereq             /* Extra prerequesites for using this table */
    + ){
    +   WhereInfo *pWInfo;          /* WHERE analysis context */
    +   Index *pProbe;              /* An index we are evaluating */
    +@@ -124003,7 +135749,7 @@ static int whereLoopAddBtree(
    + #ifndef SQLITE_OMIT_AUTOMATIC_INDEX
    +   /* Automatic indexes */
    +   if( !pBuilder->pOrSet      /* Not part of an OR optimization */
    +-   && (pWInfo->wctrlFlags & WHERE_NO_AUTOINDEX)==0
    ++   && (pWInfo->wctrlFlags & WHERE_OR_SUBCLAUSE)==0
    +    && (pWInfo->pParse->db->flags & SQLITE_AutoIndex)!=0
    +    && pSrc->pIBIndex==0      /* Has no INDEXED BY clause */
    +    && !pSrc->fg.notIndexed   /* Has no NOT INDEXED clause */
    +@@ -124035,6 +135781,7 @@ static int whereLoopAddBtree(
    +           pNew->rSetup += 24;
    +         }
    +         ApplyCostMultiplier(pNew->rSetup, pTab->costMult);
    ++        if( pNew->rSetup<0 ) pNew->rSetup = 0;
    +         /* 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 knowing how selective the index will ultimately be.  It would
    +@@ -124042,28 +135789,33 @@ static int whereLoopAddBtree(
    +         pNew->nOut = 43;  assert( 43==sqlite3LogEst(20) );
    +         pNew->rRun = sqlite3LogEstAdd(rLogSize,pNew->nOut);
    +         pNew->wsFlags = WHERE_AUTO_INDEX;
    +-        pNew->prereq = mExtra | pTerm->prereqRight;
    ++        pNew->prereq = mPrereq | pTerm->prereqRight;
    +         rc = whereLoopInsert(pBuilder, pNew);
    +       }
    +     }
    +   }
    + #endif /* SQLITE_OMIT_AUTOMATIC_INDEX */
    + 
    +-  /* Loop over all indices
    +-  */
    +-  for(; rc==SQLITE_OK && pProbe; pProbe=pProbe->pNext, iSortIdx++){
    ++  /* Loop over all indices. If there was an INDEXED BY clause, then only 
    ++  ** consider index pProbe.  */
    ++  for(; rc==SQLITE_OK && pProbe; 
    ++      pProbe=(pSrc->pIBIndex ? 0 : pProbe->pNext), iSortIdx++
    ++  ){
    +     if( pProbe->pPartIdxWhere!=0
    +      && !whereUsablePartialIndex(pSrc->iCursor, pWC, pProbe->pPartIdxWhere) ){
    +       testcase( pNew->iTab!=pSrc->iCursor );  /* See ticket [98d973b8f5] */
    +       continue;  /* Partial index inappropriate for this query */
    +     }
    ++    if( pProbe->bNoQuery ) continue;
    +     rSize = pProbe->aiRowLogEst[0];
    +     pNew->u.btree.nEq = 0;
    ++    pNew->u.btree.nBtm = 0;
    ++    pNew->u.btree.nTop = 0;
    +     pNew->nSkip = 0;
    +     pNew->nLTerm = 0;
    +     pNew->iSortIdx = 0;
    +     pNew->rSetup = 0;
    +-    pNew->prereq = mExtra;
    ++    pNew->prereq = mPrereq;
    +     pNew->nOut = rSize;
    +     pNew->u.btree.pIndex = pProbe;
    +     b = indexMightHelpWithOrderBy(pBuilder, pProbe, pSrc->iCursor);
    +@@ -124095,6 +135847,7 @@ static int whereLoopAddBtree(
    +       /* Full scan via index */
    +       if( b
    +        || !HasRowid(pTab)
    ++       || pProbe->pPartIdxWhere!=0
    +        || ( m==0
    +          && pProbe->bUnordered==0
    +          && (pProbe->szIdxRow<pTab->szTabRow)
    +@@ -124107,11 +135860,34 @@ static int whereLoopAddBtree(
    + 
    +         /* 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).  */
    ++        ** index and table rows. */
    +         pNew->rRun = rSize + 1 + (15*pProbe->szIdxRow)/pTab->szTabRow;
    +         if( m!=0 ){
    +-          pNew->rRun = sqlite3LogEstAdd(pNew->rRun, rSize+16);
    ++          /* If this is a non-covering index scan, add in the cost of
    ++          ** doing table lookups.  The cost will be 3x the number of
    ++          ** lookups.  Take into account WHERE clause terms that can be
    ++          ** satisfied using just the index, and that do not require a
    ++          ** table lookup. */
    ++          LogEst nLookup = rSize + 16;  /* Base cost:  N*3 */
    ++          int ii;
    ++          int iCur = pSrc->iCursor;
    ++          WhereClause *pWC2 = &pWInfo->sWC;
    ++          for(ii=0; ii<pWC2->nTerm; ii++){
    ++            WhereTerm *pTerm = &pWC2->a[ii];
    ++            if( !sqlite3ExprCoveredByIndex(pTerm->pExpr, iCur, pProbe) ){
    ++              break;
    ++            }
    ++            /* pTerm can be evaluated using just the index.  So reduce
    ++            ** the expected number of table lookups accordingly */
    ++            if( pTerm->truthProb<=0 ){
    ++              nLookup += pTerm->truthProb;
    ++            }else{
    ++              nLookup--;
    ++              if( pTerm->eOperator & (WO_EQ|WO_IS) ) nLookup -= 19;
    ++            }
    ++          }
    ++          
    ++          pNew->rRun = sqlite3LogEstAdd(pNew->rRun, nLookup);
    +         }
    +         ApplyCostMultiplier(pNew->rRun, pTab->costMult);
    +         whereLoopOutputAdjust(pWC, pNew, rSize);
    +@@ -124121,27 +135897,202 @@ static int whereLoopAddBtree(
    +       }
    +     }
    + 
    ++    pBuilder->bldFlags = 0;
    +     rc = whereLoopAddBtreeIndex(pBuilder, pSrc, pProbe, 0);
    ++    if( pBuilder->bldFlags==SQLITE_BLDF_INDEXED ){
    ++      /* If a non-unique index is used, or if a prefix of the key for
    ++      ** unique index is used (making the index functionally non-unique)
    ++      ** then the sqlite_stat1 data becomes important for scoring the
    ++      ** plan */
    ++      pTab->tabFlags |= TF_StatsUsed;
    ++    }
    + #ifdef SQLITE_ENABLE_STAT3_OR_STAT4
    +     sqlite3Stat4ProbeFree(pBuilder->pRec);
    +     pBuilder->nRecValid = 0;
    +     pBuilder->pRec = 0;
    + #endif
    +-
    +-    /* If there was an INDEXED BY clause, then only that one index is
    +-    ** considered. */
    +-    if( pSrc->pIBIndex ) break;
    +   }
    +   return rc;
    + }
    + 
    + #ifndef SQLITE_OMIT_VIRTUALTABLE
    ++
    ++/*
    ++** Argument pIdxInfo is already populated with all constraints that may
    ++** be used by the virtual table identified by pBuilder->pNew->iTab. This
    ++** function marks a subset of those constraints usable, invokes the
    ++** xBestIndex method and adds the returned plan to pBuilder.
    ++**
    ++** A constraint is marked usable if:
    ++**
    ++**   * Argument mUsable indicates that its prerequisites are available, and
    ++**
    ++**   * It is not one of the operators specified in the mExclude mask passed
    ++**     as the fourth argument (which in practice is either WO_IN or 0).
    ++**
    ++** Argument mPrereq is a mask of tables that must be scanned before the
    ++** virtual table in question. These are added to the plans prerequisites
    ++** before it is added to pBuilder.
    ++**
    ++** Output parameter *pbIn is set to true if the plan added to pBuilder
    ++** uses one or more WO_IN terms, or false otherwise.
    ++*/
    ++static int whereLoopAddVirtualOne(
    ++  WhereLoopBuilder *pBuilder,
    ++  Bitmask mPrereq,                /* Mask of tables that must be used. */
    ++  Bitmask mUsable,                /* Mask of usable tables */
    ++  u16 mExclude,                   /* Exclude terms using these operators */
    ++  sqlite3_index_info *pIdxInfo,   /* Populated object for xBestIndex */
    ++  u16 mNoOmit,                    /* Do not omit these constraints */
    ++  int *pbIn                       /* OUT: True if plan uses an IN(...) op */
    ++){
    ++  WhereClause *pWC = pBuilder->pWC;
    ++  struct sqlite3_index_constraint *pIdxCons;
    ++  struct sqlite3_index_constraint_usage *pUsage = pIdxInfo->aConstraintUsage;
    ++  int i;
    ++  int mxTerm;
    ++  int rc = SQLITE_OK;
    ++  WhereLoop *pNew = pBuilder->pNew;
    ++  Parse *pParse = pBuilder->pWInfo->pParse;
    ++  struct SrcList_item *pSrc = &pBuilder->pWInfo->pTabList->a[pNew->iTab];
    ++  int nConstraint = pIdxInfo->nConstraint;
    ++
    ++  assert( (mUsable & mPrereq)==mPrereq );
    ++  *pbIn = 0;
    ++  pNew->prereq = mPrereq;
    ++
    ++  /* Set the usable flag on the subset of constraints identified by 
    ++  ** arguments mUsable and mExclude. */
    ++  pIdxCons = *(struct sqlite3_index_constraint**)&pIdxInfo->aConstraint;
    ++  for(i=0; i<nConstraint; i++, pIdxCons++){
    ++    WhereTerm *pTerm = &pWC->a[pIdxCons->iTermOffset];
    ++    pIdxCons->usable = 0;
    ++    if( (pTerm->prereqRight & mUsable)==pTerm->prereqRight 
    ++     && (pTerm->eOperator & mExclude)==0
    ++    ){
    ++      pIdxCons->usable = 1;
    ++    }
    ++  }
    ++
    ++  /* Initialize the output fields of the sqlite3_index_info structure */
    ++  memset(pUsage, 0, sizeof(pUsage[0])*nConstraint);
    ++  assert( pIdxInfo->needToFreeIdxStr==0 );
    ++  pIdxInfo->idxStr = 0;
    ++  pIdxInfo->idxNum = 0;
    ++  pIdxInfo->orderByConsumed = 0;
    ++  pIdxInfo->estimatedCost = SQLITE_BIG_DBL / (double)2;
    ++  pIdxInfo->estimatedRows = 25;
    ++  pIdxInfo->idxFlags = 0;
    ++  pIdxInfo->colUsed = (sqlite3_int64)pSrc->colUsed;
    ++
    ++  /* Invoke the virtual table xBestIndex() method */
    ++  rc = vtabBestIndex(pParse, pSrc->pTab, pIdxInfo);
    ++  if( rc ) return rc;
    ++
    ++  mxTerm = -1;
    ++  assert( pNew->nLSlot>=nConstraint );
    ++  for(i=0; i<nConstraint; i++) pNew->aLTerm[i] = 0;
    ++  pNew->u.vtab.omitMask = 0;
    ++  pIdxCons = *(struct sqlite3_index_constraint**)&pIdxInfo->aConstraint;
    ++  for(i=0; i<nConstraint; i++, pIdxCons++){
    ++    int iTerm;
    ++    if( (iTerm = pUsage[i].argvIndex - 1)>=0 ){
    ++      WhereTerm *pTerm;
    ++      int j = pIdxCons->iTermOffset;
    ++      if( iTerm>=nConstraint
    ++       || j<0
    ++       || j>=pWC->nTerm
    ++       || pNew->aLTerm[iTerm]!=0
    ++       || pIdxCons->usable==0
    ++      ){
    ++        rc = SQLITE_ERROR;
    ++        sqlite3ErrorMsg(pParse,"%s.xBestIndex malfunction",pSrc->pTab->zName);
    ++        return rc;
    ++      }
    ++      testcase( iTerm==nConstraint-1 );
    ++      testcase( j==0 );
    ++      testcase( j==pWC->nTerm-1 );
    ++      pTerm = &pWC->a[j];
    ++      pNew->prereq |= pTerm->prereqRight;
    ++      assert( iTerm<pNew->nLSlot );
    ++      pNew->aLTerm[iTerm] = pTerm;
    ++      if( iTerm>mxTerm ) mxTerm = iTerm;
    ++      testcase( iTerm==15 );
    ++      testcase( iTerm==16 );
    ++      if( iTerm<16 && pUsage[i].omit ) pNew->u.vtab.omitMask |= 1<<iTerm;
    ++      if( (pTerm->eOperator & WO_IN)!=0 ){
    ++        /* A virtual table that is constrained by an IN clause may not
    ++        ** consume the ORDER BY clause because (1) the order of IN terms
    ++        ** is not necessarily related to the order of output terms and
    ++        ** (2) Multiple outputs from a single IN value will not merge
    ++        ** together.  */
    ++        pIdxInfo->orderByConsumed = 0;
    ++        pIdxInfo->idxFlags &= ~SQLITE_INDEX_SCAN_UNIQUE;
    ++        *pbIn = 1; assert( (mExclude & WO_IN)==0 );
    ++      }
    ++    }
    ++  }
    ++  pNew->u.vtab.omitMask &= ~mNoOmit;
    ++
    ++  pNew->nLTerm = mxTerm+1;
    ++  assert( pNew->nLTerm<=pNew->nLSlot );
    ++  pNew->u.vtab.idxNum = pIdxInfo->idxNum;
    ++  pNew->u.vtab.needFree = pIdxInfo->needToFreeIdxStr;
    ++  pIdxInfo->needToFreeIdxStr = 0;
    ++  pNew->u.vtab.idxStr = pIdxInfo->idxStr;
    ++  pNew->u.vtab.isOrdered = (i8)(pIdxInfo->orderByConsumed ?
    ++      pIdxInfo->nOrderBy : 0);
    ++  pNew->rSetup = 0;
    ++  pNew->rRun = sqlite3LogEstFromDouble(pIdxInfo->estimatedCost);
    ++  pNew->nOut = sqlite3LogEst(pIdxInfo->estimatedRows);
    ++
    ++  /* Set the WHERE_ONEROW flag if the xBestIndex() method indicated
    ++  ** that the scan will visit at most one row. Clear it otherwise. */
    ++  if( pIdxInfo->idxFlags & SQLITE_INDEX_SCAN_UNIQUE ){
    ++    pNew->wsFlags |= WHERE_ONEROW;
    ++  }else{
    ++    pNew->wsFlags &= ~WHERE_ONEROW;
    ++  }
    ++  rc = whereLoopInsert(pBuilder, pNew);
    ++  if( pNew->u.vtab.needFree ){
    ++    sqlite3_free(pNew->u.vtab.idxStr);
    ++    pNew->u.vtab.needFree = 0;
    ++  }
    ++  WHERETRACE(0xffff, ("  bIn=%d prereqIn=%04llx prereqOut=%04llx\n",
    ++                      *pbIn, (sqlite3_uint64)mPrereq,
    ++                      (sqlite3_uint64)(pNew->prereq & ~mPrereq)));
    ++
    ++  return rc;
    ++}
    ++
    ++/*
    ++** If this function is invoked from within an xBestIndex() callback, it
    ++** returns a pointer to a buffer containing the name of the collation
    ++** sequence associated with element iCons of the sqlite3_index_info.aConstraint
    ++** array. Or, if iCons is out of range or there is no active xBestIndex
    ++** call, return NULL.
    ++*/
    ++SQLITE_API const char *sqlite3_vtab_collation(sqlite3_index_info *pIdxInfo, int iCons){
    ++  HiddenIndexInfo *pHidden = (HiddenIndexInfo*)&pIdxInfo[1];
    ++  const char *zRet = 0;
    ++  if( iCons>=0 && iCons<pIdxInfo->nConstraint ){
    ++    CollSeq *pC = 0;
    ++    int iTerm = pIdxInfo->aConstraint[iCons].iTermOffset;
    ++    Expr *pX = pHidden->pWC->a[iTerm].pExpr;
    ++    if( pX->pLeft ){
    ++      pC = sqlite3BinaryCompareCollSeq(pHidden->pParse, pX->pLeft, pX->pRight);
    ++    }
    ++    zRet = (pC ? pC->zName : "BINARY");
    ++  }
    ++  return zRet;
    ++}
    ++
    + /*
    + ** Add all WhereLoop objects for a table of the join identified by
    + ** pBuilder->pNew->iTab.  That table is guaranteed to be a virtual table.
    + **
    +-** If there are no LEFT or CROSS JOIN joins in the query, both mExtra and
    +-** mUnusable are set to 0. Otherwise, mExtra is a mask of all FROM clause
    ++** If there are no LEFT or CROSS JOIN joins in the query, both mPrereq and
    ++** mUnusable are set to 0. Otherwise, mPrereq is a mask of all FROM clause
    + ** entries that occur before the virtual table in the FROM clause and are
    + ** separated from it by at least one LEFT or CROSS JOIN. Similarly, the
    + ** mUnusable mask contains all FROM clause entries that occur after the
    +@@ -124152,187 +136103,128 @@ static int whereLoopAddBtree(
    + **
    + **   ... FROM t1, t2 LEFT JOIN t3, t4, vt CROSS JOIN t5, t6;
    + **
    +-** then mExtra corresponds to (t1, t2) and mUnusable to (t5, t6).
    ++** then mPrereq corresponds to (t1, t2) and mUnusable to (t5, t6).
    + **
    +-** All the tables in mExtra must be scanned before the current virtual 
    ++** All the tables in mPrereq must be scanned before the current virtual 
    + ** table. So any terms for which all prerequisites are satisfied by 
    +-** mExtra may be specified as "usable" in all calls to xBestIndex. 
    ++** mPrereq may be specified as "usable" in all calls to xBestIndex. 
    + ** Conversely, all tables in mUnusable must be scanned after the current
    + ** virtual table, so any terms for which the prerequisites overlap with
    + ** mUnusable should always be configured as "not-usable" for xBestIndex.
    + */
    + static int whereLoopAddVirtual(
    +   WhereLoopBuilder *pBuilder,  /* WHERE clause information */
    +-  Bitmask mExtra,              /* Tables that must be scanned before this one */
    ++  Bitmask mPrereq,             /* Tables that must be scanned before this one */
    +   Bitmask mUnusable            /* Tables that must be scanned after this one */
    + ){
    ++  int rc = SQLITE_OK;          /* Return code */
    +   WhereInfo *pWInfo;           /* WHERE analysis context */
    +   Parse *pParse;               /* The parsing context */
    +   WhereClause *pWC;            /* The WHERE clause */
    +   struct SrcList_item *pSrc;   /* The FROM clause term to search */
    +-  Table *pTab;
    +-  sqlite3 *db;
    +-  sqlite3_index_info *pIdxInfo;
    +-  struct sqlite3_index_constraint *pIdxCons;
    +-  struct sqlite3_index_constraint_usage *pUsage;
    +-  WhereTerm *pTerm;
    +-  int i, j;
    +-  int iTerm, mxTerm;
    +-  int nConstraint;
    +-  int seenIn = 0;              /* True if an IN operator is seen */
    +-  int seenVar = 0;             /* True if a non-constant constraint is seen */
    +-  int iPhase;                  /* 0: const w/o IN, 1: const, 2: no IN,  2: IN */
    ++  sqlite3_index_info *p;       /* Object to pass to xBestIndex() */
    ++  int nConstraint;             /* Number of constraints in p */
    ++  int bIn;                     /* True if plan uses IN(...) operator */
    +   WhereLoop *pNew;
    +-  int rc = SQLITE_OK;
    ++  Bitmask mBest;               /* Tables used by best possible plan */
    ++  u16 mNoOmit;
    + 
    +-  assert( (mExtra & mUnusable)==0 );
    ++  assert( (mPrereq & mUnusable)==0 );
    +   pWInfo = pBuilder->pWInfo;
    +   pParse = pWInfo->pParse;
    +-  db = pParse->db;
    +   pWC = pBuilder->pWC;
    +   pNew = pBuilder->pNew;
    +   pSrc = &pWInfo->pTabList->a[pNew->iTab];
    +-  pTab = pSrc->pTab;
    +-  assert( IsVirtual(pTab) );
    +-  pIdxInfo = allocateIndexInfo(pParse, pWC, mUnusable, pSrc,pBuilder->pOrderBy);
    +-  if( pIdxInfo==0 ) return SQLITE_NOMEM;
    +-  pNew->prereq = 0;
    ++  assert( IsVirtual(pSrc->pTab) );
    ++  p = allocateIndexInfo(pParse, pWC, mUnusable, pSrc, pBuilder->pOrderBy, 
    ++      &mNoOmit);
    ++  if( p==0 ) return SQLITE_NOMEM_BKPT;
    +   pNew->rSetup = 0;
    +   pNew->wsFlags = WHERE_VIRTUALTABLE;
    +   pNew->nLTerm = 0;
    +   pNew->u.vtab.needFree = 0;
    +-  pUsage = pIdxInfo->aConstraintUsage;
    +-  nConstraint = pIdxInfo->nConstraint;
    +-  if( whereLoopResize(db, pNew, nConstraint) ){
    +-    sqlite3DbFree(db, pIdxInfo);
    +-    return SQLITE_NOMEM;
    +-  }
    +-
    +-  for(iPhase=0; iPhase<=3; iPhase++){
    +-    if( !seenIn && (iPhase&1)!=0 ){
    +-      iPhase++;
    +-      if( iPhase>3 ) break;
    +-    }
    +-    if( !seenVar && iPhase>1 ) break;
    +-    pIdxCons = *(struct sqlite3_index_constraint**)&pIdxInfo->aConstraint;
    +-    for(i=0; i<pIdxInfo->nConstraint; i++, pIdxCons++){
    +-      j = pIdxCons->iTermOffset;
    +-      pTerm = &pWC->a[j];
    +-      switch( iPhase ){
    +-        case 0:    /* Constants without IN operator */
    +-          pIdxCons->usable = 0;
    +-          if( (pTerm->eOperator & WO_IN)!=0 ){
    +-            seenIn = 1;
    +-          }
    +-          if( (pTerm->prereqRight & ~mExtra)!=0 ){
    +-            seenVar = 1;
    +-          }else if( (pTerm->eOperator & WO_IN)==0 ){
    +-            pIdxCons->usable = 1;
    +-          }
    +-          break;
    +-        case 1:    /* Constants with IN operators */
    +-          assert( seenIn );
    +-          pIdxCons->usable = (pTerm->prereqRight & ~mExtra)==0;
    +-          break;
    +-        case 2:    /* Variables without IN */
    +-          assert( seenVar );
    +-          pIdxCons->usable = (pTerm->eOperator & WO_IN)==0;
    +-          break;
    +-        default:   /* Variables with IN */
    +-          assert( seenVar && seenIn );
    +-          pIdxCons->usable = 1;
    +-          break;
    ++  nConstraint = p->nConstraint;
    ++  if( whereLoopResize(pParse->db, pNew, nConstraint) ){
    ++    sqlite3DbFree(pParse->db, p);
    ++    return SQLITE_NOMEM_BKPT;
    ++  }
    ++
    ++  /* First call xBestIndex() with all constraints usable. */
    ++  WHERETRACE(0x40, ("  VirtualOne: all usable\n"));
    ++  rc = whereLoopAddVirtualOne(pBuilder, mPrereq, ALLBITS, 0, p, mNoOmit, &bIn);
    ++
    ++  /* If the call to xBestIndex() with all terms enabled produced a plan
    ++  ** that does not require any source tables (IOW: a plan with mBest==0),
    ++  ** then there is no point in making any further calls to xBestIndex() 
    ++  ** since they will all return the same result (if the xBestIndex()
    ++  ** implementation is sane). */
    ++  if( rc==SQLITE_OK && (mBest = (pNew->prereq & ~mPrereq))!=0 ){
    ++    int seenZero = 0;             /* True if a plan with no prereqs seen */
    ++    int seenZeroNoIN = 0;         /* Plan with no prereqs and no IN(...) seen */
    ++    Bitmask mPrev = 0;
    ++    Bitmask mBestNoIn = 0;
    ++
    ++    /* If the plan produced by the earlier call uses an IN(...) term, call
    ++    ** xBestIndex again, this time with IN(...) terms disabled. */
    ++    if( bIn ){
    ++      WHERETRACE(0x40, ("  VirtualOne: all usable w/o IN\n"));
    ++      rc = whereLoopAddVirtualOne(
    ++          pBuilder, mPrereq, ALLBITS, WO_IN, p, mNoOmit, &bIn);
    ++      assert( bIn==0 );
    ++      mBestNoIn = pNew->prereq & ~mPrereq;
    ++      if( mBestNoIn==0 ){
    ++        seenZero = 1;
    ++        seenZeroNoIN = 1;
    ++      }
    ++    }
    ++
    ++    /* Call xBestIndex once for each distinct value of (prereqRight & ~mPrereq) 
    ++    ** in the set of terms that apply to the current virtual table.  */
    ++    while( rc==SQLITE_OK ){
    ++      int i;
    ++      Bitmask mNext = ALLBITS;
    ++      assert( mNext>0 );
    ++      for(i=0; i<nConstraint; i++){
    ++        Bitmask mThis = (
    ++            pWC->a[p->aConstraint[i].iTermOffset].prereqRight & ~mPrereq
    ++        );
    ++        if( mThis>mPrev && mThis<mNext ) mNext = mThis;
    ++      }
    ++      mPrev = mNext;
    ++      if( mNext==ALLBITS ) break;
    ++      if( mNext==mBest || mNext==mBestNoIn ) continue;
    ++      WHERETRACE(0x40, ("  VirtualOne: mPrev=%04llx mNext=%04llx\n",
    ++                       (sqlite3_uint64)mPrev, (sqlite3_uint64)mNext));
    ++      rc = whereLoopAddVirtualOne(
    ++          pBuilder, mPrereq, mNext|mPrereq, 0, p, mNoOmit, &bIn);
    ++      if( pNew->prereq==mPrereq ){
    ++        seenZero = 1;
    ++        if( bIn==0 ) seenZeroNoIN = 1;
    +       }
    +     }
    +-    memset(pUsage, 0, sizeof(pUsage[0])*pIdxInfo->nConstraint);
    +-    if( pIdxInfo->needToFreeIdxStr ) sqlite3_free(pIdxInfo->idxStr);
    +-    pIdxInfo->idxStr = 0;
    +-    pIdxInfo->idxNum = 0;
    +-    pIdxInfo->needToFreeIdxStr = 0;
    +-    pIdxInfo->orderByConsumed = 0;
    +-    pIdxInfo->estimatedCost = SQLITE_BIG_DBL / (double)2;
    +-    pIdxInfo->estimatedRows = 25;
    +-    pIdxInfo->idxFlags = 0;
    +-    rc = vtabBestIndex(pParse, pTab, pIdxInfo);
    +-    if( rc ) goto whereLoopAddVtab_exit;
    +-    pIdxCons = *(struct sqlite3_index_constraint**)&pIdxInfo->aConstraint;
    +-    pNew->prereq = mExtra;
    +-    mxTerm = -1;
    +-    assert( pNew->nLSlot>=nConstraint );
    +-    for(i=0; i<nConstraint; i++) pNew->aLTerm[i] = 0;
    +-    pNew->u.vtab.omitMask = 0;
    +-    for(i=0; i<nConstraint; i++, pIdxCons++){
    +-      if( (iTerm = pUsage[i].argvIndex - 1)>=0 ){
    +-        j = pIdxCons->iTermOffset;
    +-        if( iTerm>=nConstraint
    +-         || j<0
    +-         || j>=pWC->nTerm
    +-         || pNew->aLTerm[iTerm]!=0
    +-        ){
    +-          rc = SQLITE_ERROR;
    +-          sqlite3ErrorMsg(pParse, "%s.xBestIndex() malfunction", pTab->zName);
    +-          goto whereLoopAddVtab_exit;
    +-        }
    +-        testcase( iTerm==nConstraint-1 );
    +-        testcase( j==0 );
    +-        testcase( j==pWC->nTerm-1 );
    +-        pTerm = &pWC->a[j];
    +-        pNew->prereq |= pTerm->prereqRight;
    +-        assert( iTerm<pNew->nLSlot );
    +-        pNew->aLTerm[iTerm] = pTerm;
    +-        if( iTerm>mxTerm ) mxTerm = iTerm;
    +-        testcase( iTerm==15 );
    +-        testcase( iTerm==16 );
    +-        if( iTerm<16 && pUsage[i].omit ) pNew->u.vtab.omitMask |= 1<<iTerm;
    +-        if( (pTerm->eOperator & WO_IN)!=0 ){
    +-          if( pUsage[i].omit==0 ){
    +-            /* Do not attempt to use an IN constraint if the virtual table
    +-            ** says that the equivalent EQ constraint cannot be safely omitted.
    +-            ** If we do attempt to use such a constraint, some rows might be
    +-            ** repeated in the output. */
    +-            break;
    +-          }
    +-          /* A virtual table that is constrained by an IN clause may not
    +-          ** consume the ORDER BY clause because (1) the order of IN terms
    +-          ** is not necessarily related to the order of output terms and
    +-          ** (2) Multiple outputs from a single IN value will not merge
    +-          ** together.  */
    +-          pIdxInfo->orderByConsumed = 0;
    +-          pIdxInfo->idxFlags &= ~SQLITE_INDEX_SCAN_UNIQUE;
    +-        }
    +-      }
    +-    }
    +-    if( i>=nConstraint ){
    +-      pNew->nLTerm = mxTerm+1;
    +-      assert( pNew->nLTerm<=pNew->nLSlot );
    +-      pNew->u.vtab.idxNum = pIdxInfo->idxNum;
    +-      pNew->u.vtab.needFree = pIdxInfo->needToFreeIdxStr;
    +-      pIdxInfo->needToFreeIdxStr = 0;
    +-      pNew->u.vtab.idxStr = pIdxInfo->idxStr;
    +-      pNew->u.vtab.isOrdered = (i8)(pIdxInfo->orderByConsumed ?
    +-                                      pIdxInfo->nOrderBy : 0);
    +-      pNew->rSetup = 0;
    +-      pNew->rRun = sqlite3LogEstFromDouble(pIdxInfo->estimatedCost);
    +-      pNew->nOut = sqlite3LogEst(pIdxInfo->estimatedRows);
    + 
    +-      /* Set the WHERE_ONEROW flag if the xBestIndex() method indicated
    +-      ** that the scan will visit at most one row. Clear it otherwise. */
    +-      if( pIdxInfo->idxFlags & SQLITE_INDEX_SCAN_UNIQUE ){
    +-        pNew->wsFlags |= WHERE_ONEROW;
    +-      }else{
    +-        pNew->wsFlags &= ~WHERE_ONEROW;
    +-      }
    +-      whereLoopInsert(pBuilder, pNew);
    +-      if( pNew->u.vtab.needFree ){
    +-        sqlite3_free(pNew->u.vtab.idxStr);
    +-        pNew->u.vtab.needFree = 0;
    +-      }
    ++    /* If the calls to xBestIndex() in the above loop did not find a plan
    ++    ** that requires no source tables at all (i.e. one guaranteed to be
    ++    ** usable), make a call here with all source tables disabled */
    ++    if( rc==SQLITE_OK && seenZero==0 ){
    ++      WHERETRACE(0x40, ("  VirtualOne: all disabled\n"));
    ++      rc = whereLoopAddVirtualOne(
    ++          pBuilder, mPrereq, mPrereq, 0, p, mNoOmit, &bIn);
    ++      if( bIn==0 ) seenZeroNoIN = 1;
    +     }
    +-  }  
    + 
    +-whereLoopAddVtab_exit:
    +-  if( pIdxInfo->needToFreeIdxStr ) sqlite3_free(pIdxInfo->idxStr);
    +-  sqlite3DbFree(db, pIdxInfo);
    ++    /* If the calls to xBestIndex() have so far failed to find a plan
    ++    ** that requires no source tables at all and does not use an IN(...)
    ++    ** operator, make a final call to obtain one here.  */
    ++    if( rc==SQLITE_OK && seenZeroNoIN==0 ){
    ++      WHERETRACE(0x40, ("  VirtualOne: all disabled and w/o IN\n"));
    ++      rc = whereLoopAddVirtualOne(
    ++          pBuilder, mPrereq, mPrereq, WO_IN, p, mNoOmit, &bIn);
    ++    }
    ++  }
    ++
    ++  if( p->needToFreeIdxStr ) sqlite3_free(p->idxStr);
    ++  sqlite3DbFreeNN(pParse->db, p);
    +   return rc;
    + }
    + #endif /* SQLITE_OMIT_VIRTUALTABLE */
    +@@ -124343,7 +136235,7 @@ whereLoopAddVtab_exit:
    + */
    + static int whereLoopAddOr(
    +   WhereLoopBuilder *pBuilder, 
    +-  Bitmask mExtra, 
    ++  Bitmask mPrereq, 
    +   Bitmask mUnusable
    + ){
    +   WhereInfo *pWInfo = pBuilder->pWInfo;
    +@@ -124397,21 +136289,19 @@ static int whereLoopAddOr(
    +         WHERETRACE(0x200, ("OR-term %d of %p has %d subterms:\n", 
    +                    (int)(pOrTerm-pOrWC->a), pTerm, sSubBuild.pWC->nTerm));
    +         if( sqlite3WhereTrace & 0x400 ){
    +-          for(i=0; i<sSubBuild.pWC->nTerm; i++){
    +-            whereTermPrint(&sSubBuild.pWC->a[i], i);
    +-          }
    ++          sqlite3WhereClausePrint(sSubBuild.pWC);
    +         }
    + #endif
    + #ifndef SQLITE_OMIT_VIRTUALTABLE
    +         if( IsVirtual(pItem->pTab) ){
    +-          rc = whereLoopAddVirtual(&sSubBuild, mExtra, mUnusable);
    ++          rc = whereLoopAddVirtual(&sSubBuild, mPrereq, mUnusable);
    +         }else
    + #endif
    +         {
    +-          rc = whereLoopAddBtree(&sSubBuild, mExtra);
    ++          rc = whereLoopAddBtree(&sSubBuild, mPrereq);
    +         }
    +         if( rc==SQLITE_OK ){
    +-          rc = whereLoopAddOr(&sSubBuild, mExtra, mUnusable);
    ++          rc = whereLoopAddOr(&sSubBuild, mPrereq, mUnusable);
    +         }
    +         assert( rc==SQLITE_OK || sCur.n==0 );
    +         if( sCur.n==0 ){
    +@@ -124468,7 +136358,7 @@ static int whereLoopAddOr(
    + */
    + static int whereLoopAddAll(WhereLoopBuilder *pBuilder){
    +   WhereInfo *pWInfo = pBuilder->pWInfo;
    +-  Bitmask mExtra = 0;
    ++  Bitmask mPrereq = 0;
    +   Bitmask mPrior = 0;
    +   int iTab;
    +   SrcList *pTabList = pWInfo->pTabList;
    +@@ -124489,9 +136379,10 @@ static int whereLoopAddAll(WhereLoopBuilder *pBuilder){
    +     if( ((pItem->fg.jointype|priorJointype) & (JT_LEFT|JT_CROSS))!=0 ){
    +       /* This condition is true when pItem is the FROM clause term on the
    +       ** right-hand-side of a LEFT or CROSS JOIN.  */
    +-      mExtra = mPrior;
    ++      mPrereq = mPrior;
    +     }
    +     priorJointype = pItem->fg.jointype;
    ++#ifndef SQLITE_OMIT_VIRTUALTABLE
    +     if( IsVirtual(pItem->pTab) ){
    +       struct SrcList_item *p;
    +       for(p=&pItem[1]; p<pEnd; p++){
    +@@ -124499,12 +136390,14 @@ static int whereLoopAddAll(WhereLoopBuilder *pBuilder){
    +           mUnusable |= sqlite3WhereGetMask(&pWInfo->sMaskSet, p->iCursor);
    +         }
    +       }
    +-      rc = whereLoopAddVirtual(pBuilder, mExtra, mUnusable);
    +-    }else{
    +-      rc = whereLoopAddBtree(pBuilder, mExtra);
    ++      rc = whereLoopAddVirtual(pBuilder, mPrereq, mUnusable);
    ++    }else
    ++#endif /* SQLITE_OMIT_VIRTUALTABLE */
    ++    {
    ++      rc = whereLoopAddBtree(pBuilder, mPrereq);
    +     }
    +     if( rc==SQLITE_OK ){
    +-      rc = whereLoopAddOr(pBuilder, mExtra, mUnusable);
    ++      rc = whereLoopAddOr(pBuilder, mPrereq, mUnusable);
    +     }
    +     mPrior |= pNew->maskSelf;
    +     if( rc || db->mallocFailed ) break;
    +@@ -124515,7 +136408,7 @@ static int whereLoopAddAll(WhereLoopBuilder *pBuilder){
    + }
    + 
    + /*
    +-** Examine a WherePath (with the addition of the extra WhereLoop of the 5th
    ++** Examine a WherePath (with the addition of the extra WhereLoop of the 6th
    + ** parameters) to see if it outputs rows in the requested ORDER BY
    + ** (or GROUP BY) without requiring a separate sort operation.  Return N:
    + ** 
    +@@ -124535,7 +136428,7 @@ 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 */
    +-  u16 wctrlFlags,       /* Might contain WHERE_GROUPBY or WHERE_DISTINCTBY */
    ++  u16 wctrlFlags,       /* WHERE_GROUPBY or _DISTINCTBY or _ORDERBY_LIMIT */
    +   u16 nLoop,            /* Number of entries in pPath->aLoop[] */
    +   WhereLoop *pLast,     /* Add this WhereLoop to the end of pPath->aLoop[] */
    +   Bitmask *pRevMask     /* OUT: Mask of WhereLoops to run in reverse order */
    +@@ -124546,6 +136439,7 @@ static i8 wherePathSatisfiesOrderBy(
    +   u8 isOrderDistinct;   /* All prior WhereLoops are order-distinct */
    +   u8 distinctColumns;   /* True if the loop has UNIQUE NOT NULL columns */
    +   u8 isMatch;           /* iColumn matches a term of the ORDER BY clause */
    ++  u16 eqOpMask;         /* Allowed equality operators */
    +   u16 nKeyCol;          /* Number of key columns in pIndex */
    +   u16 nColumn;          /* Total number of ordered columns in the index */
    +   u16 nOrderBy;         /* Number terms in the ORDER BY clause */
    +@@ -124596,12 +136490,21 @@ static i8 wherePathSatisfiesOrderBy(
    +   obDone = MASKBIT(nOrderBy)-1;
    +   orderDistinctMask = 0;
    +   ready = 0;
    ++  eqOpMask = WO_EQ | WO_IS | WO_ISNULL;
    ++  if( wctrlFlags & WHERE_ORDERBY_LIMIT ) eqOpMask |= WO_IN;
    +   for(iLoop=0; isOrderDistinct && obSat<obDone && iLoop<=nLoop; iLoop++){
    +     if( iLoop>0 ) ready |= pLoop->maskSelf;
    +-    pLoop = iLoop<nLoop ? pPath->aLoop[iLoop] : pLast;
    ++    if( iLoop<nLoop ){
    ++      pLoop = pPath->aLoop[iLoop];
    ++      if( wctrlFlags & WHERE_ORDERBY_LIMIT ) continue;
    ++    }else{
    ++      pLoop = pLast;
    ++    }
    +     if( pLoop->wsFlags & WHERE_VIRTUALTABLE ){
    +       if( pLoop->u.vtab.isOrdered ) obSat = obDone;
    +       break;
    ++    }else{
    ++      pLoop->u.btree.nIdxCol = 0;
    +     }
    +     iCur = pWInfo->pTabList->a[pLoop->iTab].iCursor;
    + 
    +@@ -124616,17 +136519,21 @@ static i8 wherePathSatisfiesOrderBy(
    +       if( pOBExpr->op!=TK_COLUMN ) continue;
    +       if( pOBExpr->iTable!=iCur ) continue;
    +       pTerm = sqlite3WhereFindTerm(&pWInfo->sWC, iCur, pOBExpr->iColumn,
    +-                       ~ready, WO_EQ|WO_ISNULL|WO_IS, 0);
    ++                       ~ready, eqOpMask, 0);
    +       if( pTerm==0 ) continue;
    ++      if( pTerm->eOperator==WO_IN ){
    ++        /* IN terms are only valid for sorting in the ORDER BY LIMIT 
    ++        ** optimization, and then only if they are actually used
    ++        ** by the query plan */
    ++        assert( wctrlFlags & WHERE_ORDERBY_LIMIT );
    ++        for(j=0; j<pLoop->nLTerm && pTerm!=pLoop->aLTerm[j]; j++){}
    ++        if( j>=pLoop->nLTerm ) continue;
    ++      }
    +       if( (pTerm->eOperator&(WO_EQ|WO_IS))!=0 && pOBExpr->iColumn>=0 ){
    +-        const char *z1, *z2;
    +-        pColl = sqlite3ExprCollSeq(pWInfo->pParse, pOrderBy->a[i].pExpr);
    +-        if( !pColl ) pColl = db->pDfltColl;
    +-        z1 = pColl->zName;
    +-        pColl = sqlite3ExprCollSeq(pWInfo->pParse, pTerm->pExpr);
    +-        if( !pColl ) pColl = db->pDfltColl;
    +-        z2 = pColl->zName;
    +-        if( sqlite3StrICmp(z1, z2)!=0 ) continue;
    ++        if( sqlite3ExprCollSeqMatch(pWInfo->pParse, 
    ++                  pOrderBy->a[i].pExpr, pTerm->pExpr)==0 ){
    ++          continue;
    ++        }
    +         testcase( pTerm->pExpr->op==TK_IS );
    +       }
    +       obSat |= MASKBIT(i);
    +@@ -124654,18 +136561,42 @@ static i8 wherePathSatisfiesOrderBy(
    +       rev = revSet = 0;
    +       distinctColumns = 0;
    +       for(j=0; j<nColumn; j++){
    +-        u8 bOnce;   /* True to run the ORDER BY search loop */
    ++        u8 bOnce = 1; /* True to run the ORDER BY search loop */
    + 
    +-        /* Skip over == and IS NULL terms */
    +-        if( j<pLoop->u.btree.nEq
    +-         && pLoop->nSkip==0
    +-         && ((i = pLoop->aLTerm[j]->eOperator) & (WO_EQ|WO_ISNULL|WO_IS))!=0
    +-        ){
    +-          if( i & WO_ISNULL ){
    +-            testcase( isOrderDistinct );
    +-            isOrderDistinct = 0;
    ++        assert( j>=pLoop->u.btree.nEq 
    ++            || (pLoop->aLTerm[j]==0)==(j<pLoop->nSkip)
    ++        );
    ++        if( j<pLoop->u.btree.nEq && j>=pLoop->nSkip ){
    ++          u16 eOp = pLoop->aLTerm[j]->eOperator;
    ++
    ++          /* Skip over == and IS and ISNULL terms.  (Also skip IN terms when
    ++          ** doing WHERE_ORDERBY_LIMIT processing). 
    ++          **
    ++          ** If the current term is a column of an ((?,?) IN (SELECT...)) 
    ++          ** expression for which the SELECT returns more than one column,
    ++          ** check that it is the only column used by this loop. Otherwise,
    ++          ** if it is one of two or more, none of the columns can be
    ++          ** considered to match an ORDER BY term.  */
    ++          if( (eOp & eqOpMask)!=0 ){
    ++            if( eOp & WO_ISNULL ){
    ++              testcase( isOrderDistinct );
    ++              isOrderDistinct = 0;
    ++            }
    ++            continue;  
    ++          }else if( ALWAYS(eOp & WO_IN) ){
    ++            /* ALWAYS() justification: eOp is an equality operator due to the
    ++            ** j<pLoop->u.btree.nEq constraint above.  Any equality other
    ++            ** than WO_IN is captured by the previous "if".  So this one
    ++            ** always has to be WO_IN. */
    ++            Expr *pX = pLoop->aLTerm[j]->pExpr;
    ++            for(i=j+1; i<pLoop->u.btree.nEq; i++){
    ++              if( pLoop->aLTerm[i]->pExpr==pX ){
    ++                assert( (pLoop->aLTerm[i]->eOperator & WO_IN) );
    ++                bOnce = 0;
    ++                break;
    ++              }
    ++            }
    +           }
    +-          continue;  
    +         }
    + 
    +         /* Get the column number in the table (iColumn) and sort order
    +@@ -124674,7 +136605,7 @@ static i8 wherePathSatisfiesOrderBy(
    +         if( pIndex ){
    +           iColumn = pIndex->aiColumn[j];
    +           revIdx = pIndex->aSortOrder[j];
    +-          if( iColumn==pIndex->pTable->iPKey ) iColumn = -1;
    ++          if( iColumn==pIndex->pTable->iPKey ) iColumn = XN_ROWID;
    +         }else{
    +           iColumn = XN_ROWID;
    +           revIdx = 0;
    +@@ -124694,7 +136625,6 @@ static i8 wherePathSatisfiesOrderBy(
    +         /* Find the ORDER BY term that corresponds to the j-th column
    +         ** of the index and mark that ORDER BY term off 
    +         */
    +-        bOnce = 1;
    +         isMatch = 0;
    +         for(i=0; bOnce && i<nOrderBy; i++){
    +           if( MASKBIT(i) & obSat ) continue;
    +@@ -124702,20 +136632,21 @@ static i8 wherePathSatisfiesOrderBy(
    +           testcase( wctrlFlags & WHERE_GROUPBY );
    +           testcase( wctrlFlags & WHERE_DISTINCTBY );
    +           if( (wctrlFlags & (WHERE_GROUPBY|WHERE_DISTINCTBY))==0 ) bOnce = 0;
    +-          if( iColumn>=(-1) ){
    ++          if( iColumn>=XN_ROWID ){
    +             if( pOBExpr->op!=TK_COLUMN ) continue;
    +             if( pOBExpr->iTable!=iCur ) continue;
    +             if( pOBExpr->iColumn!=iColumn ) continue;
    +           }else{
    +-            if( sqlite3ExprCompare(pOBExpr,pIndex->aColExpr->a[j].pExpr,iCur) ){
    ++            Expr *pIdxExpr = pIndex->aColExpr->a[j].pExpr;
    ++            if( sqlite3ExprCompareSkip(pOBExpr, pIdxExpr, iCur) ){
    +               continue;
    +             }
    +           }
    +-          if( iColumn>=0 ){
    +-            pColl = sqlite3ExprCollSeq(pWInfo->pParse, pOrderBy->a[i].pExpr);
    +-            if( !pColl ) pColl = db->pDfltColl;
    ++          if( iColumn!=XN_ROWID ){
    ++            pColl = sqlite3ExprNNCollSeq(pWInfo->pParse, pOrderBy->a[i].pExpr);
    +             if( sqlite3StrICmp(pColl->zName, pIndex->azColl[j])!=0 ) continue;
    +           }
    ++          pLoop->u.btree.nIdxCol = j+1;
    +           isMatch = 1;
    +           break;
    +         }
    +@@ -124731,7 +136662,7 @@ static i8 wherePathSatisfiesOrderBy(
    +           }
    +         }
    +         if( isMatch ){
    +-          if( iColumn<0 ){
    ++          if( iColumn==XN_ROWID ){
    +             testcase( distinctColumns==0 );
    +             distinctColumns = 1;
    +           }
    +@@ -124847,15 +136778,14 @@ static LogEst whereSortingCost(
    +   LogEst rScale, rSortCost;
    +   assert( nOrderBy>0 && 66==sqlite3LogEst(100) );
    +   rScale = sqlite3LogEst((nOrderBy-nSorted)*100/nOrderBy) - 66;
    +-  rSortCost = nRow + estLog(nRow) + rScale + 16;
    ++  rSortCost = 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;
    ++  /* Multiple by log(M) where M is the number of output rows.
    ++  ** Use the LIMIT for M if it is smaller */
    ++  if( (pWInfo->wctrlFlags & WHERE_USE_LIMIT)!=0 && pWInfo->iLimit<nRow ){
    ++    nRow = pWInfo->iLimit;
    +   }
    +-
    ++  rSortCost += estLog(nRow);
    +   return rSortCost;
    + }
    + 
    +@@ -124917,8 +136847,8 @@ static int wherePathSolver(WhereInfo *pWInfo, LogEst nRowEst){
    +   /* 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;
    ++  pSpace = sqlite3DbMallocRawNN(db, nSpace);
    ++  if( pSpace==0 ) return SQLITE_NOMEM_BKPT;
    +   aTo = (WherePath*)pSpace;
    +   aFrom = aTo+mxChoice;
    +   memset(aFrom, 0, sizeof(aFrom[0]));
    +@@ -124973,6 +136903,12 @@ static int wherePathSolver(WhereInfo *pWInfo, LogEst nRowEst){
    + 
    +         if( (pWLoop->prereq & ~pFrom->maskLoop)!=0 ) continue;
    +         if( (pWLoop->maskSelf & pFrom->maskLoop)!=0 ) continue;
    ++        if( (pWLoop->wsFlags & WHERE_AUTO_INDEX)!=0 && pFrom->nRow<10 ){
    ++          /* Do not use an automatic index if the this loop is expected
    ++          ** to run less than 2 times. */
    ++          assert( 10==sqlite3LogEst(2) );
    ++          continue;
    ++        }
    +         /* At this point, pWLoop is a candidate to be the next loop. 
    +         ** Compute its cost */
    +         rUnsorted = sqlite3LogEstAdd(pWLoop->rSetup,pWLoop->rRun + pFrom->nRow);
    +@@ -125000,6 +136936,7 @@ static int wherePathSolver(WhereInfo *pWInfo, LogEst nRowEst){
    +                rUnsorted, rCost));
    +         }else{
    +           rCost = rUnsorted;
    ++          rUnsorted -= 2;  /* TUNING:  Slight bias in favor of no-sort plans */
    +         }
    + 
    +         /* Check to see if pWLoop should be added to the set of
    +@@ -125031,8 +136968,8 @@ static int wherePathSolver(WhereInfo *pWInfo, LogEst nRowEst){
    +             ** 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,
    ++              sqlite3DebugPrintf("Skip   %s cost=%-3d,%3d,%3d order=%c\n",
    ++                  wherePathName(pFrom, iLoop, pWLoop), rCost, nOut, rUnsorted,
    +                   isOrdered>=0 ? isOrdered+'0' : '?');
    +             }
    + #endif
    +@@ -125050,26 +136987,36 @@ static int wherePathSolver(WhereInfo *pWInfo, LogEst nRowEst){
    +           pTo = &aTo[jj];
    + #ifdef WHERETRACE_ENABLED /* 0x4 */
    +           if( sqlite3WhereTrace&0x4 ){
    +-            sqlite3DebugPrintf("New    %s cost=%-3d,%3d order=%c\n",
    +-                wherePathName(pFrom, iLoop, pWLoop), rCost, nOut,
    ++            sqlite3DebugPrintf("New    %s cost=%-3d,%3d,%3d order=%c\n",
    ++                wherePathName(pFrom, iLoop, pWLoop), rCost, nOut, rUnsorted,
    +                 isOrdered>=0 ? isOrdered+'0' : '?');
    +           }
    + #endif
    +         }else{
    +           /* 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
    ++          ** same set of loops and has the same isOrdered setting as the
    +           ** candidate path.  Check to see if the candidate should replace
    +-          ** pTo or if the candidate should be skipped */
    +-          if( pTo->rCost<rCost || (pTo->rCost==rCost && pTo->nRow<=nOut) ){
    ++          ** pTo or if the candidate should be skipped.
    ++          ** 
    ++          ** The conditional is an expanded vector comparison equivalent to:
    ++          **   (pTo->rCost,pTo->nRow,pTo->rUnsorted) <= (rCost,nOut,rUnsorted)
    ++          */
    ++          if( pTo->rCost<rCost 
    ++           || (pTo->rCost==rCost
    ++               && (pTo->nRow<nOut
    ++                   || (pTo->nRow==nOut && pTo->rUnsorted<=rUnsorted)
    ++                  )
    ++              )
    ++          ){
    + #ifdef WHERETRACE_ENABLED /* 0x4 */
    +             if( sqlite3WhereTrace&0x4 ){
    +               sqlite3DebugPrintf(
    +-                  "Skip   %s cost=%-3d,%3d order=%c",
    +-                  wherePathName(pFrom, iLoop, pWLoop), rCost, nOut,
    ++                  "Skip   %s cost=%-3d,%3d,%3d order=%c",
    ++                  wherePathName(pFrom, iLoop, pWLoop), rCost, nOut, rUnsorted,
    +                   isOrdered>=0 ? isOrdered+'0' : '?');
    +-              sqlite3DebugPrintf("   vs %s cost=%-3d,%d order=%c\n",
    ++              sqlite3DebugPrintf("   vs %s cost=%-3d,%3d,%3d order=%c\n",
    +                   wherePathName(pTo, iLoop+1, 0), pTo->rCost, pTo->nRow,
    +-                  pTo->isOrdered>=0 ? pTo->isOrdered+'0' : '?');
    ++                  pTo->rUnsorted, pTo->isOrdered>=0 ? pTo->isOrdered+'0' : '?');
    +             }
    + #endif
    +             /* Discard the candidate path from further consideration */
    +@@ -125082,12 +137029,12 @@ static int wherePathSolver(WhereInfo *pWInfo, LogEst nRowEst){
    + #ifdef WHERETRACE_ENABLED /* 0x4 */
    +           if( sqlite3WhereTrace&0x4 ){
    +             sqlite3DebugPrintf(
    +-                "Update %s cost=%-3d,%3d order=%c",
    +-                wherePathName(pFrom, iLoop, pWLoop), rCost, nOut,
    ++                "Update %s cost=%-3d,%3d,%3d order=%c",
    ++                wherePathName(pFrom, iLoop, pWLoop), rCost, nOut, rUnsorted,
    +                 isOrdered>=0 ? isOrdered+'0' : '?');
    +-            sqlite3DebugPrintf("  was %s cost=%-3d,%3d order=%c\n",
    ++            sqlite3DebugPrintf("  was %s cost=%-3d,%3d,%3d order=%c\n",
    +                 wherePathName(pTo, iLoop+1, 0), pTo->rCost, pTo->nRow,
    +-                pTo->isOrdered>=0 ? pTo->isOrdered+'0' : '?');
    ++                pTo->rUnsorted, pTo->isOrdered>=0 ? pTo->isOrdered+'0' : '?');
    +           }
    + #endif
    +         }
    +@@ -125142,7 +137089,7 @@ static int wherePathSolver(WhereInfo *pWInfo, LogEst nRowEst){
    + 
    +   if( nFrom==0 ){
    +     sqlite3ErrorMsg(pParse, "no query solution");
    +-    sqlite3DbFree(db, pSpace);
    ++    sqlite3DbFreeNN(db, pSpace);
    +     return SQLITE_ERROR;
    +   }
    +   
    +@@ -125178,8 +137125,26 @@ static int wherePathSolver(WhereInfo *pWInfo, LogEst nRowEst){
    +       }
    +     }else{
    +       pWInfo->nOBSat = pFrom->isOrdered;
    +-      if( pWInfo->nOBSat<0 ) pWInfo->nOBSat = 0;
    +       pWInfo->revMask = pFrom->revLoop;
    ++      if( pWInfo->nOBSat<=0 ){
    ++        pWInfo->nOBSat = 0;
    ++        if( nLoop>0 ){
    ++          u32 wsFlags = pFrom->aLoop[nLoop-1]->wsFlags;
    ++          if( (wsFlags & WHERE_ONEROW)==0 
    ++           && (wsFlags&(WHERE_IPK|WHERE_COLUMN_IN))!=(WHERE_IPK|WHERE_COLUMN_IN)
    ++          ){
    ++            Bitmask m = 0;
    ++            int rc = wherePathSatisfiesOrderBy(pWInfo, pWInfo->pOrderBy, pFrom,
    ++                      WHERE_ORDERBY_LIMIT, nLoop-1, pFrom->aLoop[nLoop-1], &m);
    ++            testcase( wsFlags & WHERE_IPK );
    ++            testcase( wsFlags & WHERE_COLUMN_IN );
    ++            if( rc==pWInfo->pOrderBy->nExpr ){
    ++              pWInfo->bOrderedInnerLoop = 1;
    ++              pWInfo->revMask = m;
    ++            }
    ++          }
    ++        }
    ++      }
    +     }
    +     if( (pWInfo->wctrlFlags & WHERE_SORTBYGROUP)
    +         && pWInfo->nOBSat==pWInfo->pOrderBy->nExpr && nLoop>0
    +@@ -125200,7 +137165,7 @@ static int wherePathSolver(WhereInfo *pWInfo, LogEst nRowEst){
    +   pWInfo->nRowOut = pFrom->nRow;
    + 
    +   /* Free temporary memory and return success */
    +-  sqlite3DbFree(db, pSpace);
    ++  sqlite3DbFreeNN(db, pSpace);
    +   return SQLITE_OK;
    + }
    + 
    +@@ -125225,9 +137190,9 @@ static int whereShortCut(WhereLoopBuilder *pBuilder){
    +   int j;
    +   Table *pTab;
    +   Index *pIdx;
    +-  
    ++
    +   pWInfo = pBuilder->pWInfo;
    +-  if( pWInfo->wctrlFlags & WHERE_FORCE_TABLE ) return 0;
    ++  if( pWInfo->wctrlFlags & WHERE_OR_SUBCLAUSE ) return 0;
    +   assert( pWInfo->pTabList->nSrc>=1 );
    +   pItem = pWInfo->pTabList->a;
    +   pTab = pItem->pTab;
    +@@ -125278,7 +137243,8 @@ static int whereShortCut(WhereLoopBuilder *pBuilder){
    +   if( pLoop->wsFlags ){
    +     pLoop->nOut = (LogEst)1;
    +     pWInfo->a[0].pWLoop = pLoop;
    +-    pLoop->maskSelf = sqlite3WhereGetMask(&pWInfo->sMaskSet, iCur);
    ++    assert( pWInfo->sMaskSet.n==1 && iCur==pWInfo->sMaskSet.ix[0] );
    ++    pLoop->maskSelf = 1; /* sqlite3WhereGetMask(&pWInfo->sMaskSet, iCur); */
    +     pWInfo->a[0].iTabCur = iCur;
    +     pWInfo->nRowOut = 1;
    +     if( pWInfo->pOrderBy ) pWInfo->nOBSat =  pWInfo->pOrderBy->nExpr;
    +@@ -125293,6 +137259,32 @@ static int whereShortCut(WhereLoopBuilder *pBuilder){
    +   return 0;
    + }
    + 
    ++/*
    ++** Helper function for exprIsDeterministic().
    ++*/
    ++static int exprNodeIsDeterministic(Walker *pWalker, Expr *pExpr){
    ++  if( pExpr->op==TK_FUNCTION && ExprHasProperty(pExpr, EP_ConstFunc)==0 ){
    ++    pWalker->eCode = 0;
    ++    return WRC_Abort;
    ++  }
    ++  return WRC_Continue;
    ++}
    ++
    ++/*
    ++** Return true if the expression contains no non-deterministic SQL 
    ++** functions. Do not consider non-deterministic SQL functions that are 
    ++** part of sub-select statements.
    ++*/
    ++static int exprIsDeterministic(Expr *p){
    ++  Walker w;
    ++  memset(&w, 0, sizeof(w));
    ++  w.eCode = 1;
    ++  w.xExprCallback = exprNodeIsDeterministic;
    ++  w.xSelectCallback = sqlite3SelectWalkFail;
    ++  sqlite3WalkExpr(&w, p);
    ++  return w.eCode;
    ++}
    ++
    + /*
    + ** Generate the beginning of the loop used for WHERE clause processing.
    + ** The return value is a pointer to an opaque structure that contains
    +@@ -125374,7 +137366,7 @@ static int whereShortCut(WhereLoopBuilder *pBuilder){
    + ** is called from an UPDATE or DELETE statement, then pOrderBy is NULL.
    + **
    + ** The iIdxCur parameter is the cursor number of an index.  If 
    +-** WHERE_ONETABLE_ONLY is set, iIdxCur is the cursor number of an index
    ++** WHERE_OR_SUBCLAUSE is set, iIdxCur is the cursor number of an index
    + ** to use for OR clause processing.  The WHERE clause should use this
    + ** specific cursor.  If WHERE_ONEPASS_DESIRED is set, then iIdxCur is
    + ** the first cursor in an array of cursors for all indices.  iIdxCur should
    +@@ -125382,13 +137374,14 @@ static int whereShortCut(WhereLoopBuilder *pBuilder){
    + ** used.
    + */
    + 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 (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 */
    ++  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 (or GROUP BY) clause, or NULL */
    ++  ExprList *pResultSet,   /* Query result set.  Req'd for DISTINCT */
    ++  u16 wctrlFlags,         /* The WHERE_* flags defined in sqliteInt.h */
    ++  int iAuxArg             /* If WHERE_OR_SUBCLAUSE is set, index cursor number
    ++                          ** If WHERE_USE_LIMIT, then the limit amount */
    + ){
    +   int nByteWInfo;            /* Num. bytes allocated for WhereInfo struct */
    +   int nTabList;              /* Number of elements in pTabList */
    +@@ -125402,12 +137395,17 @@ SQLITE_PRIVATE WhereInfo *sqlite3WhereBegin(
    +   int ii;                    /* Loop counter */
    +   sqlite3 *db;               /* Database connection */
    +   int rc;                    /* Return code */
    ++  u8 bFordelete = 0;         /* OPFLAG_FORDELETE or zero, as appropriate */
    + 
    +   assert( (wctrlFlags & WHERE_ONEPASS_MULTIROW)==0 || (
    +         (wctrlFlags & WHERE_ONEPASS_DESIRED)!=0 
    +-     && (wctrlFlags & WHERE_OMIT_OPEN_CLOSE)==0 
    ++     && (wctrlFlags & WHERE_OR_SUBCLAUSE)==0 
    +   ));
    + 
    ++  /* Only one of WHERE_OR_SUBCLAUSE or WHERE_USE_LIMIT */
    ++  assert( (wctrlFlags & WHERE_OR_SUBCLAUSE)==0
    ++            || (wctrlFlags & WHERE_USE_LIMIT)==0 );
    ++
    +   /* Variable initialization */
    +   db = pParse->db;
    +   memset(&sWLB, 0, sizeof(sWLB));
    +@@ -125433,11 +137431,11 @@ SQLITE_PRIVATE WhereInfo *sqlite3WhereBegin(
    +   }
    + 
    +   /* This function normally generates a nested loop for all tables in 
    +-  ** pTabList.  But if the WHERE_ONETABLE_ONLY flag is set, then we should
    ++  ** pTabList.  But if the WHERE_OR_SUBCLAUSE flag is set, then we should
    +   ** only generate code for the first table in pTabList and assume that
    +   ** any cursors associated with subsequent tables are uninitialized.
    +   */
    +-  nTabList = (wctrlFlags & WHERE_ONETABLE_ONLY) ? 1 : pTabList->nSrc;
    ++  nTabList = (wctrlFlags & WHERE_OR_SUBCLAUSE) ? 1 : pTabList->nSrc;
    + 
    +   /* Allocate and initialize the WhereInfo structure that will become the
    +   ** return value. A single allocation is used to store the WhereInfo
    +@@ -125447,21 +137445,26 @@ SQLITE_PRIVATE WhereInfo *sqlite3WhereBegin(
    +   ** some architectures. Hence the ROUND8() below.
    +   */
    +   nByteWInfo = ROUND8(sizeof(WhereInfo)+(nTabList-1)*sizeof(WhereLevel));
    +-  pWInfo = sqlite3DbMallocZero(db, nByteWInfo + sizeof(WhereLoop));
    ++  pWInfo = sqlite3DbMallocRawNN(db, nByteWInfo + sizeof(WhereLoop));
    +   if( db->mallocFailed ){
    +     sqlite3DbFree(db, pWInfo);
    +     pWInfo = 0;
    +     goto whereBeginError;
    +   }
    +-  pWInfo->aiCurOnePass[0] = pWInfo->aiCurOnePass[1] = -1;
    +-  pWInfo->nLevel = nTabList;
    +   pWInfo->pParse = pParse;
    +   pWInfo->pTabList = pTabList;
    +   pWInfo->pOrderBy = pOrderBy;
    ++  pWInfo->pWhere = pWhere;
    +   pWInfo->pResultSet = pResultSet;
    ++  pWInfo->aiCurOnePass[0] = pWInfo->aiCurOnePass[1] = -1;
    ++  pWInfo->nLevel = nTabList;
    +   pWInfo->iBreak = pWInfo->iContinue = sqlite3VdbeMakeLabel(v);
    +   pWInfo->wctrlFlags = wctrlFlags;
    ++  pWInfo->iLimit = iAuxArg;
    +   pWInfo->savedNQueryLoop = pParse->nQueryLoop;
    ++  memset(&pWInfo->nOBSat, 0, 
    ++         offsetof(WhereInfo,sWC) - offsetof(WhereInfo,nOBSat));
    ++  memset(&pWInfo->a[0], 0, sizeof(WhereLoop)+nTabList*sizeof(WhereLevel));
    +   assert( pWInfo->eOnePass==ONEPASS_OFF );  /* ONEPASS defaults to OFF */
    +   pMaskSet = &pWInfo->sMaskSet;
    +   sWLB.pWInfo = pWInfo;
    +@@ -125480,17 +137483,6 @@ SQLITE_PRIVATE WhereInfo *sqlite3WhereBegin(
    +   sqlite3WhereClauseInit(&pWInfo->sWC, pWInfo);
    +   sqlite3WhereSplit(&pWInfo->sWC, pWhere, TK_AND);
    +     
    +-  /* Special case: a WHERE clause that is constant.  Evaluate the
    +-  ** expression and either jump over all of the code or fall thru.
    +-  */
    +-  for(ii=0; ii<sWLB.pWC->nTerm; ii++){
    +-    if( nTabList==0 || sqlite3ExprIsConstantNotJoin(sWLB.pWC->a[ii].pExpr) ){
    +-      sqlite3ExprIfFalse(pParse, sWLB.pWC->a[ii].pExpr, pWInfo->iBreak,
    +-                         SQLITE_JUMPIFNULL);
    +-      sWLB.pWC->a[ii].wtFlags |= TERM_CODED;
    +-    }
    +-  }
    +-
    +   /* Special case: No FROM clause
    +   */
    +   if( nTabList==0 ){
    +@@ -125498,36 +137490,60 @@ SQLITE_PRIVATE WhereInfo *sqlite3WhereBegin(
    +     if( wctrlFlags & WHERE_WANT_DISTINCT ){
    +       pWInfo->eDistinct = WHERE_DISTINCT_UNIQUE;
    +     }
    ++  }else{
    ++    /* Assign a bit from the bitmask to every term in the FROM clause.
    ++    **
    ++    ** The N-th term of the FROM clause is assigned a bitmask of 1<<N.
    ++    **
    ++    ** The rule of the previous sentence ensures thta if X is the bitmask for
    ++    ** a table T, then X-1 is the bitmask for all other tables to the left of T.
    ++    ** Knowing the bitmask for all tables to the left of a left join is
    ++    ** important.  Ticket #3015.
    ++    **
    ++    ** Note that bitmasks are created for all pTabList->nSrc tables in
    ++    ** pTabList, not just the first nTabList tables.  nTabList is normally
    ++    ** equal to pTabList->nSrc but might be shortened to 1 if the
    ++    ** WHERE_OR_SUBCLAUSE flag is set.
    ++    */
    ++    ii = 0;
    ++    do{
    ++      createMask(pMaskSet, pTabList->a[ii].iCursor);
    ++      sqlite3WhereTabFuncArgs(pParse, &pTabList->a[ii], &pWInfo->sWC);
    ++    }while( (++ii)<pTabList->nSrc );
    ++  #ifdef SQLITE_DEBUG
    ++    {
    ++      Bitmask mx = 0;
    ++      for(ii=0; ii<pTabList->nSrc; ii++){
    ++        Bitmask m = sqlite3WhereGetMask(pMaskSet, pTabList->a[ii].iCursor);
    ++        assert( m>=mx );
    ++        mx = m;
    ++      }
    ++    }
    ++  #endif
    +   }
    ++  
    ++  /* Analyze all of the subexpressions. */
    ++  sqlite3WhereExprAnalyze(pTabList, &pWInfo->sWC);
    ++  if( db->mallocFailed ) goto whereBeginError;
    + 
    +-  /* Assign a bit from the bitmask to every term in the FROM clause.
    +-  **
    +-  ** The N-th term of the FROM clause is assigned a bitmask of 1<<N.
    ++  /* Special case: WHERE terms that do not refer to any tables in the join
    ++  ** (constant expressions). Evaluate each such term, and jump over all the
    ++  ** generated code if the result is not true.  
    +   **
    +-  ** The rule of the previous sentence ensures thta if X is the bitmask for
    +-  ** a table T, then X-1 is the bitmask for all other tables to the left of T.
    +-  ** Knowing the bitmask for all tables to the left of a left join is
    +-  ** important.  Ticket #3015.
    ++  ** Do not do this if the expression contains non-deterministic functions
    ++  ** that are not within a sub-select. This is not strictly required, but
    ++  ** preserves SQLite's legacy behaviour in the following two cases:
    +   **
    +-  ** Note that bitmasks are created for all pTabList->nSrc tables in
    +-  ** pTabList, not just the first nTabList tables.  nTabList is normally
    +-  ** equal to pTabList->nSrc but might be shortened to 1 if the
    +-  ** WHERE_ONETABLE_ONLY flag is set.
    ++  **   FROM ... WHERE random()>0;           -- eval random() once per row
    ++  **   FROM ... WHERE (SELECT random())>0;  -- eval random() once overall
    +   */
    +-  for(ii=0; ii<pTabList->nSrc; ii++){
    +-    createMask(pMaskSet, pTabList->a[ii].iCursor);
    +-    sqlite3WhereTabFuncArgs(pParse, &pTabList->a[ii], &pWInfo->sWC);
    +-  }
    +-#ifdef SQLITE_DEBUG
    +-  for(ii=0; ii<pTabList->nSrc; ii++){
    +-    Bitmask m = sqlite3WhereGetMask(pMaskSet, pTabList->a[ii].iCursor);
    +-    assert( m==MASKBIT(ii) );
    ++  for(ii=0; ii<sWLB.pWC->nTerm; ii++){
    ++    WhereTerm *pT = &sWLB.pWC->a[ii];
    ++    if( pT->prereqAll==0 && (nTabList==0 || exprIsDeterministic(pT->pExpr)) ){
    ++      sqlite3ExprIfFalse(pParse, pT->pExpr, pWInfo->iBreak, SQLITE_JUMPIFNULL);
    ++      pT->wtFlags |= TERM_CODED;
    ++    }
    +   }
    +-#endif
    +-
    +-  /* Analyze all of the subexpressions. */
    +-  sqlite3WhereExprAnalyze(pTabList, &pWInfo->sWC);
    +-  if( db->mallocFailed ) goto whereBeginError;
    + 
    +   if( wctrlFlags & WHERE_WANT_DISTINCT ){
    +     if( isDistinctRedundant(pParse, pTabList, &pWInfo->sWC, pResultSet) ){
    +@@ -125541,14 +137557,16 @@ SQLITE_PRIVATE WhereInfo *sqlite3WhereBegin(
    +   }
    + 
    +   /* Construct the WhereLoop objects */
    +-  WHERETRACE(0xffff,("*** Optimizer Start *** (wctrlFlags: 0x%x)\n",
    +-             wctrlFlags));
    + #if defined(WHERETRACE_ENABLED)
    +-  if( sqlite3WhereTrace & 0x100 ){ /* Display all terms of the WHERE clause */
    +-    int i;
    +-    for(i=0; i<sWLB.pWC->nTerm; i++){
    +-      whereTermPrint(&sWLB.pWC->a[i], i);
    ++  if( sqlite3WhereTrace & 0xffff ){
    ++    sqlite3DebugPrintf("*** Optimizer Start *** (wctrlFlags: 0x%x",wctrlFlags);
    ++    if( wctrlFlags & WHERE_USE_LIMIT ){
    ++      sqlite3DebugPrintf(", limit: %d", iAuxArg);
    +     }
    ++    sqlite3DebugPrintf(")\n");
    ++  }
    ++  if( sqlite3WhereTrace & 0x100 ){ /* Display all terms of the WHERE clause */
    ++    sqlite3WhereClausePrint(sWLB.pWC);
    +   }
    + #endif
    + 
    +@@ -125563,7 +137581,7 @@ SQLITE_PRIVATE WhereInfo *sqlite3WhereBegin(
    +       static const char zLabel[] = "0123456789abcdefghijklmnopqrstuvwyxz"
    +                                              "ABCDEFGHIJKLMNOPQRSTUVWYXZ";
    +       for(p=pWInfo->pLoops, i=0; p; p=p->pNextLoop, i++){
    +-        p->cId = zLabel[i%sizeof(zLabel)];
    ++        p->cId = zLabel[i%(sizeof(zLabel)-1)];
    +         whereLoopPrint(p, sWLB.pWC);
    +       }
    +     }
    +@@ -125577,7 +137595,7 @@ SQLITE_PRIVATE WhereInfo *sqlite3WhereBegin(
    +     }
    +   }
    +   if( pWInfo->pOrderBy==0 && (db->flags & SQLITE_ReverseOrder)!=0 ){
    +-     pWInfo->revMask = (Bitmask)(-1);
    ++     pWInfo->revMask = ALLBITS;
    +   }
    +   if( pParse->nErr || NEVER(db->mallocFailed) ){
    +     goto whereBeginError;
    +@@ -125608,35 +137626,80 @@ SQLITE_PRIVATE WhereInfo *sqlite3WhereBegin(
    +     }
    +   }
    + #endif
    +-  /* Attempt to omit tables from the join that do not effect the result */
    ++
    ++  /* Attempt to omit tables from the join that do not affect the result.
    ++  ** For a table to not affect the result, the following must be true:
    ++  **
    ++  **   1) The query must not be an aggregate.
    ++  **   2) The table must be the RHS of a LEFT JOIN.
    ++  **   3) Either the query must be DISTINCT, or else the ON or USING clause
    ++  **      must contain a constraint that limits the scan of the table to 
    ++  **      at most a single row.
    ++  **   4) The table must not be referenced by any part of the query apart
    ++  **      from its own USING or ON clause.
    ++  **
    ++  ** For example, given:
    ++  **
    ++  **     CREATE TABLE t1(ipk INTEGER PRIMARY KEY, v1);
    ++  **     CREATE TABLE t2(ipk INTEGER PRIMARY KEY, v2);
    ++  **     CREATE TABLE t3(ipk INTEGER PRIMARY KEY, v3);
    ++  **
    ++  ** then table t2 can be omitted from the following:
    ++  **
    ++  **     SELECT v1, v3 FROM t1 
    ++  **       LEFT JOIN t2 USING (t1.ipk=t2.ipk)
    ++  **       LEFT JOIN t3 USING (t1.ipk=t3.ipk)
    ++  **
    ++  ** or from:
    ++  **
    ++  **     SELECT DISTINCT v1, v3 FROM t1 
    ++  **       LEFT JOIN t2
    ++  **       LEFT JOIN t3 USING (t1.ipk=t3.ipk)
    ++  */
    ++  notReady = ~(Bitmask)0;
    +   if( pWInfo->nLevel>=2
    +-   && pResultSet!=0
    ++   && pResultSet!=0               /* guarantees condition (1) above */
    +    && OptimizationEnabled(db, SQLITE_OmitNoopJoin)
    +   ){
    ++    int i;
    +     Bitmask tabUsed = sqlite3WhereExprListUsage(pMaskSet, pResultSet);
    +     if( sWLB.pOrderBy ){
    +       tabUsed |= sqlite3WhereExprListUsage(pMaskSet, sWLB.pOrderBy);
    +     }
    +-    while( pWInfo->nLevel>=2 ){
    ++    for(i=pWInfo->nLevel-1; i>=1; i--){
    +       WhereTerm *pTerm, *pEnd;
    +-      pLoop = pWInfo->a[pWInfo->nLevel-1].pWLoop;
    +-      if( (pWInfo->pTabList->a[pLoop->iTab].fg.jointype & JT_LEFT)==0 ) break;
    ++      struct SrcList_item *pItem;
    ++      pLoop = pWInfo->a[i].pWLoop;
    ++      pItem = &pWInfo->pTabList->a[pLoop->iTab];
    ++      if( (pItem->fg.jointype & JT_LEFT)==0 ) continue;
    +       if( (wctrlFlags & WHERE_WANT_DISTINCT)==0
    +        && (pLoop->wsFlags & WHERE_ONEROW)==0
    +       ){
    +-        break;
    ++        continue;
    +       }
    +-      if( (tabUsed & pLoop->maskSelf)!=0 ) break;
    ++      if( (tabUsed & pLoop->maskSelf)!=0 ) continue;
    +       pEnd = sWLB.pWC->a + sWLB.pWC->nTerm;
    +       for(pTerm=sWLB.pWC->a; pTerm<pEnd; pTerm++){
    +-        if( (pTerm->prereqAll & pLoop->maskSelf)!=0
    +-         && !ExprHasProperty(pTerm->pExpr, EP_FromJoin)
    +-        ){
    +-          break;
    ++        if( (pTerm->prereqAll & pLoop->maskSelf)!=0 ){
    ++          if( !ExprHasProperty(pTerm->pExpr, EP_FromJoin)
    ++           || pTerm->pExpr->iRightJoinTable!=pItem->iCursor
    ++          ){
    ++            break;
    ++          }
    +         }
    +       }
    +-      if( pTerm<pEnd ) break;
    ++      if( pTerm<pEnd ) continue;
    +       WHERETRACE(0xffff, ("-> drop loop %c not used\n", pLoop->cId));
    ++      notReady &= ~pLoop->maskSelf;
    ++      for(pTerm=sWLB.pWC->a; pTerm<pEnd; pTerm++){
    ++        if( (pTerm->prereqAll & pLoop->maskSelf)!=0 ){
    ++          pTerm->wtFlags |= TERM_CODED;
    ++        }
    ++      }
    ++      if( i!=pWInfo->nLevel-1 ){
    ++        int nByte = (pWInfo->nLevel-1-i) * sizeof(WhereLevel);
    ++        memmove(&pWInfo->a[i], &pWInfo->a[i+1], nByte);
    ++      }
    +       pWInfo->nLevel--;
    +       nTabList--;
    +     }
    +@@ -125646,19 +137709,38 @@ SQLITE_PRIVATE WhereInfo *sqlite3WhereBegin(
    + 
    +   /* If the caller is an UPDATE or DELETE statement that is requesting
    +   ** to use a one-pass algorithm, determine if this is appropriate.
    +-  ** The one-pass algorithm only works if the WHERE clause constrains
    +-  ** the statement to update or delete a single row.
    ++  **
    ++  ** A one-pass approach can be used if the caller has requested one
    ++  ** and either (a) the scan visits at most one row or (b) each
    ++  ** of the following are true:
    ++  **
    ++  **   * the caller has indicated that a one-pass approach can be used
    ++  **     with multiple rows (by setting WHERE_ONEPASS_MULTIROW), and
    ++  **   * the table is not a virtual table, and
    ++  **   * either the scan does not use the OR optimization or the caller
    ++  **     is a DELETE operation (WHERE_DUPLICATES_OK is only specified
    ++  **     for DELETE).
    ++  **
    ++  ** The last qualification is because an UPDATE statement uses
    ++  ** WhereInfo.aiCurOnePass[1] to determine whether or not it really can
    ++  ** use a one-pass approach, and this is not set accurately for scans
    ++  ** that use the OR optimization.
    +   */
    +   assert( (wctrlFlags & WHERE_ONEPASS_DESIRED)==0 || pWInfo->nLevel==1 );
    +   if( (wctrlFlags & WHERE_ONEPASS_DESIRED)!=0 ){
    +     int wsFlags = pWInfo->a[0].pWLoop->wsFlags;
    +     int bOnerow = (wsFlags & WHERE_ONEROW)!=0;
    +-    if( bOnerow || ( (wctrlFlags & WHERE_ONEPASS_MULTIROW)
    +-       && 0==(wsFlags & WHERE_VIRTUALTABLE)
    ++    if( bOnerow || (
    ++        0!=(wctrlFlags & WHERE_ONEPASS_MULTIROW)
    ++     && 0==(wsFlags & WHERE_VIRTUALTABLE)
    ++     && (0==(wsFlags & WHERE_MULTI_OR) || (wctrlFlags & WHERE_DUPLICATES_OK))
    +     )){
    +       pWInfo->eOnePass = bOnerow ? ONEPASS_SINGLE : ONEPASS_MULTI;
    +-      if( HasRowid(pTabList->a[0].pTab) ){
    +-        pWInfo->a[0].pWLoop->wsFlags &= ~WHERE_IDX_ONLY;
    ++      if( HasRowid(pTabList->a[0].pTab) && (wsFlags & WHERE_IDX_ONLY) ){
    ++        if( wctrlFlags & WHERE_ONEPASS_MULTIROW ){
    ++          bFordelete = OPFLAG_FORDELETE;
    ++        }
    ++        pWInfo->a[0].pWLoop->wsFlags = (wsFlags & ~WHERE_IDX_ONLY);
    +       }
    +     }
    +   }
    +@@ -125688,7 +137770,7 @@ SQLITE_PRIVATE WhereInfo *sqlite3WhereBegin(
    +     }else
    + #endif
    +     if( (pLoop->wsFlags & WHERE_IDX_ONLY)==0
    +-         && (wctrlFlags & WHERE_OMIT_OPEN_CLOSE)==0 ){
    ++         && (wctrlFlags & WHERE_OR_SUBCLAUSE)==0 ){
    +       int op = OP_OpenRead;
    +       if( pWInfo->eOnePass!=ONEPASS_OFF ){
    +         op = OP_OpenWrite;
    +@@ -125702,10 +137784,17 @@ SQLITE_PRIVATE WhereInfo *sqlite3WhereBegin(
    +         Bitmask b = pTabItem->colUsed;
    +         int n = 0;
    +         for(; b; b=b>>1, n++){}
    +-        sqlite3VdbeChangeP4(v, sqlite3VdbeCurrentAddr(v)-1, 
    +-                            SQLITE_INT_TO_PTR(n), P4_INT32);
    ++        sqlite3VdbeChangeP4(v, -1, SQLITE_INT_TO_PTR(n), P4_INT32);
    +         assert( n<=pTab->nCol );
    +       }
    ++#ifdef SQLITE_ENABLE_CURSOR_HINTS
    ++      if( pLoop->u.btree.pIndex!=0 ){
    ++        sqlite3VdbeChangeP5(v, OPFLAG_SEEKEQ|bFordelete);
    ++      }else
    ++#endif
    ++      {
    ++        sqlite3VdbeChangeP5(v, bFordelete);
    ++      }
    + #ifdef SQLITE_ENABLE_COLUMN_USED_MASK
    +       sqlite3VdbeAddOp4Dup8(v, OP_ColumnsUsed, pTabItem->iCursor, 0, 0,
    +                             (const u8*)&pTabItem->colUsed, P4_INT64);
    +@@ -125717,10 +137806,10 @@ SQLITE_PRIVATE WhereInfo *sqlite3WhereBegin(
    +       Index *pIx = pLoop->u.btree.pIndex;
    +       int iIndexCur;
    +       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 );
    ++      /* iAuxArg is always set to a positive value if ONEPASS is possible */
    ++      assert( iAuxArg!=0 || (pWInfo->wctrlFlags & WHERE_ONEPASS_DESIRED)==0 );
    +       if( !HasRowid(pTab) && IsPrimaryKeyIndex(pIx)
    +-       && (wctrlFlags & WHERE_ONETABLE_ONLY)!=0
    ++       && (wctrlFlags & WHERE_OR_SUBCLAUSE)!=0
    +       ){
    +         /* This is one term of an OR-optimization using the PRIMARY KEY of a
    +         ** WITHOUT ROWID table.  No need for a separate index */
    +@@ -125728,7 +137817,7 @@ SQLITE_PRIVATE WhereInfo *sqlite3WhereBegin(
    +         op = 0;
    +       }else if( pWInfo->eOnePass!=ONEPASS_OFF ){
    +         Index *pJ = pTabItem->pTab->pIndex;
    +-        iIndexCur = iIdxCur;
    ++        iIndexCur = iAuxArg;
    +         assert( wctrlFlags & WHERE_ONEPASS_DESIRED );
    +         while( ALWAYS(pJ) && pJ!=pIx ){
    +           iIndexCur++;
    +@@ -125736,9 +137825,9 @@ SQLITE_PRIVATE WhereInfo *sqlite3WhereBegin(
    +         }
    +         op = OP_OpenWrite;
    +         pWInfo->aiCurOnePass[1] = iIndexCur;
    +-      }else if( iIdxCur && (wctrlFlags & WHERE_ONETABLE_ONLY)!=0 ){
    +-        iIndexCur = iIdxCur;
    +-        if( wctrlFlags & WHERE_REOPEN_IDX ) op = OP_ReopenIdx;
    ++      }else if( iAuxArg && (wctrlFlags & WHERE_OR_SUBCLAUSE)!=0 ){
    ++        iIndexCur = iAuxArg;
    ++        op = OP_ReopenIdx;
    +       }else{
    +         iIndexCur = pParse->nTab++;
    +       }
    +@@ -125751,6 +137840,7 @@ SQLITE_PRIVATE WhereInfo *sqlite3WhereBegin(
    +         if( (pLoop->wsFlags & WHERE_CONSTRAINT)!=0
    +          && (pLoop->wsFlags & (WHERE_COLUMN_RANGE|WHERE_SKIPSCAN))==0
    +          && (pWInfo->wctrlFlags&WHERE_ORDERBY_MIN)==0
    ++         && pWInfo->eDistinct!=WHERE_DISTINCT_ORDERED
    +         ){
    +           sqlite3VdbeChangeP5(v, OPFLAG_SEEKEQ); /* Hint to COMDB2 */
    +         }
    +@@ -125781,7 +137871,6 @@ SQLITE_PRIVATE WhereInfo *sqlite3WhereBegin(
    +   ** loop below generates code for a single nested loop of the VM
    +   ** program.
    +   */
    +-  notReady = ~(Bitmask)0;
    +   for(ii=0; ii<nTabList; ii++){
    +     int addrExplain;
    +     int wsFlags;
    +@@ -125800,7 +137889,7 @@ SQLITE_PRIVATE WhereInfo *sqlite3WhereBegin(
    +     pLevel->addrBody = sqlite3VdbeCurrentAddr(v);
    +     notReady = sqlite3WhereCodeOneLoopStart(pWInfo, ii, notReady);
    +     pWInfo->iContinue = pLevel->addrCont;
    +-    if( (wsFlags&WHERE_MULTI_OR)==0 && (wctrlFlags&WHERE_ONETABLE_ONLY)==0 ){
    ++    if( (wsFlags&WHERE_MULTI_OR)==0 && (wctrlFlags&WHERE_OR_SUBCLAUSE)==0 ){
    +       sqlite3WhereAddScanStatus(v, pTabList, pLevel, addrExplain);
    +     }
    +   }
    +@@ -125839,14 +137928,44 @@ SQLITE_PRIVATE void sqlite3WhereEnd(WhereInfo *pWInfo){
    +     int addr;
    +     pLevel = &pWInfo->a[i];
    +     pLoop = pLevel->pWLoop;
    +-    sqlite3VdbeResolveLabel(v, pLevel->addrCont);
    +     if( pLevel->op!=OP_Noop ){
    ++#ifndef SQLITE_DISABLE_SKIPAHEAD_DISTINCT
    ++      int addrSeek = 0;
    ++      Index *pIdx;
    ++      int n;
    ++      if( pWInfo->eDistinct==WHERE_DISTINCT_ORDERED
    ++       && i==pWInfo->nLevel-1  /* Ticket [ef9318757b152e3] 2017-10-21 */
    ++       && (pLoop->wsFlags & WHERE_INDEXED)!=0
    ++       && (pIdx = pLoop->u.btree.pIndex)->hasStat1
    ++       && (n = pLoop->u.btree.nIdxCol)>0
    ++       && pIdx->aiRowLogEst[n]>=36
    ++      ){
    ++        int r1 = pParse->nMem+1;
    ++        int j, op;
    ++        for(j=0; j<n; j++){
    ++          sqlite3VdbeAddOp3(v, OP_Column, pLevel->iIdxCur, j, r1+j);
    ++        }
    ++        pParse->nMem += n+1;
    ++        op = pLevel->op==OP_Prev ? OP_SeekLT : OP_SeekGT;
    ++        addrSeek = sqlite3VdbeAddOp4Int(v, op, pLevel->iIdxCur, 0, r1, n);
    ++        VdbeCoverageIf(v, op==OP_SeekLT);
    ++        VdbeCoverageIf(v, op==OP_SeekGT);
    ++        sqlite3VdbeAddOp2(v, OP_Goto, 1, pLevel->p2);
    ++      }
    ++#endif /* SQLITE_DISABLE_SKIPAHEAD_DISTINCT */
    ++      /* The common case: Advance to the next row */
    ++      sqlite3VdbeResolveLabel(v, pLevel->addrCont);
    +       sqlite3VdbeAddOp3(v, pLevel->op, pLevel->p1, pLevel->p2, pLevel->p3);
    +       sqlite3VdbeChangeP5(v, pLevel->p5);
    +       VdbeCoverage(v);
    +       VdbeCoverageIf(v, pLevel->op==OP_Next);
    +       VdbeCoverageIf(v, pLevel->op==OP_Prev);
    +       VdbeCoverageIf(v, pLevel->op==OP_VNext);
    ++#ifndef SQLITE_DISABLE_SKIPAHEAD_DISTINCT
    ++      if( addrSeek ) sqlite3VdbeJumpHere(v, addrSeek);
    ++#endif
    ++    }else{
    ++      sqlite3VdbeResolveLabel(v, pLevel->addrCont);
    +     }
    +     if( pLoop->wsFlags & WHERE_IN_ABLE && pLevel->u.in.nIn>0 ){
    +       struct InLoop *pIn;
    +@@ -125854,10 +137973,12 @@ SQLITE_PRIVATE void sqlite3WhereEnd(WhereInfo *pWInfo){
    +       sqlite3VdbeResolveLabel(v, pLevel->addrNxt);
    +       for(j=pLevel->u.in.nIn, pIn=&pLevel->u.in.aInLoop[j-1]; j>0; j--, pIn--){
    +         sqlite3VdbeJumpHere(v, pIn->addrInTop+1);
    +-        sqlite3VdbeAddOp2(v, pIn->eEndLoopOp, pIn->iCur, pIn->addrInTop);
    +-        VdbeCoverage(v);
    +-        VdbeCoverageIf(v, pIn->eEndLoopOp==OP_PrevIfOpen);
    +-        VdbeCoverageIf(v, pIn->eEndLoopOp==OP_NextIfOpen);
    ++        if( pIn->eEndLoopOp!=OP_Noop ){
    ++          sqlite3VdbeAddOp2(v, pIn->eEndLoopOp, pIn->iCur, pIn->addrInTop);
    ++          VdbeCoverage(v);
    ++          VdbeCoverageIf(v, pIn->eEndLoopOp==OP_PrevIfOpen);
    ++          VdbeCoverageIf(v, pIn->eEndLoopOp==OP_NextIfOpen);
    ++        }
    +         sqlite3VdbeJumpHere(v, pIn->addrInTop-1);
    +       }
    +     }
    +@@ -125868,24 +137989,24 @@ SQLITE_PRIVATE void sqlite3WhereEnd(WhereInfo *pWInfo){
    +       sqlite3VdbeJumpHere(v, pLevel->addrSkip);
    +       sqlite3VdbeJumpHere(v, pLevel->addrSkip-2);
    +     }
    ++#ifndef SQLITE_LIKE_DOESNT_MATCH_BLOBS
    +     if( pLevel->addrLikeRep ){
    +-      int op;
    +-      if( sqlite3VdbeGetOp(v, pLevel->addrLikeRep-1)->p1 ){
    +-        op = OP_DecrJumpZero;
    +-      }else{
    +-        op = OP_JumpZeroIncr;
    +-      }
    +-      sqlite3VdbeAddOp2(v, op, pLevel->iLikeRepCntr, pLevel->addrLikeRep);
    ++      sqlite3VdbeAddOp2(v, OP_DecrJumpZero, (int)(pLevel->iLikeRepCntr>>1),
    ++                        pLevel->addrLikeRep);
    +       VdbeCoverage(v);
    +     }
    ++#endif
    +     if( pLevel->iLeftJoin ){
    ++      int ws = pLoop->wsFlags;
    +       addr = sqlite3VdbeAddOp1(v, OP_IfPos, pLevel->iLeftJoin); VdbeCoverage(v);
    +-      assert( (pLoop->wsFlags & WHERE_IDX_ONLY)==0
    +-           || (pLoop->wsFlags & WHERE_INDEXED)!=0 );
    +-      if( (pLoop->wsFlags & WHERE_IDX_ONLY)==0 ){
    +-        sqlite3VdbeAddOp1(v, OP_NullRow, pTabList->a[i].iCursor);
    ++      assert( (ws & WHERE_IDX_ONLY)==0 || (ws & WHERE_INDEXED)!=0 );
    ++      if( (ws & WHERE_IDX_ONLY)==0 ){
    ++        assert( pLevel->iTabCur==pTabList->a[pLevel->iFrom].iCursor );
    ++        sqlite3VdbeAddOp1(v, OP_NullRow, pLevel->iTabCur);
    +       }
    +-      if( pLoop->wsFlags & WHERE_INDEXED ){
    ++      if( (ws & WHERE_INDEXED) 
    ++       || ((ws & WHERE_MULTI_OR) && pLevel->u.pCovidx) 
    ++      ){
    +         sqlite3VdbeAddOp1(v, OP_NullRow, pLevel->iIdxCur);
    +       }
    +       if( pLevel->op==OP_Return ){
    +@@ -125918,33 +138039,13 @@ SQLITE_PRIVATE void sqlite3WhereEnd(WhereInfo *pWInfo){
    +     ** the co-routine into OP_Copy of result contained in a register.
    +     ** OP_Rowid becomes OP_Null.
    +     */
    +-    if( pTabItem->fg.viaCoroutine && !db->mallocFailed ){
    +-      translateColumnToCopy(v, pLevel->addrBody, pLevel->iTabCur,
    ++    if( pTabItem->fg.viaCoroutine ){
    ++      testcase( pParse->db->mallocFailed );
    ++      translateColumnToCopy(pParse, pLevel->addrBody, pLevel->iTabCur,
    +                             pTabItem->regResult, 0);
    +       continue;
    +     }
    + 
    +-    /* Close all of the cursors that were opened by sqlite3WhereBegin.
    +-    ** Except, do not close cursors that will be reused by the OR optimization
    +-    ** (WHERE_OMIT_OPEN_CLOSE).  And do not close the OP_OpenWrite cursors
    +-    ** created for the ONEPASS optimization.
    +-    */
    +-    if( (pTab->tabFlags & TF_Ephemeral)==0
    +-     && pTab->pSelect==0
    +-     && (pWInfo->wctrlFlags & WHERE_OMIT_OPEN_CLOSE)==0
    +-    ){
    +-      int ws = pLoop->wsFlags;
    +-      if( pWInfo->eOnePass==ONEPASS_OFF && (ws & WHERE_IDX_ONLY)==0 ){
    +-        sqlite3VdbeAddOp1(v, OP_Close, pTabItem->iCursor);
    +-      }
    +-      if( (ws & WHERE_INDEXED)!=0
    +-       && (ws & (WHERE_IPK|WHERE_AUTO_INDEX))==0 
    +-       && pLevel->iIdxCur!=pWInfo->aiCurOnePass[1]
    +-      ){
    +-        sqlite3VdbeAddOp1(v, OP_Close, pLevel->iIdxCur);
    +-      }
    +-    }
    +-
    +     /* If this scan uses an index, make VDBE code substitutions to read data
    +     ** from the index instead of from the table where possible.  In some cases
    +     ** this optimization prevents the table from ever being read, which can
    +@@ -125970,7 +138071,11 @@ SQLITE_PRIVATE void sqlite3WhereEnd(WhereInfo *pWInfo){
    +       pOp = sqlite3VdbeGetOp(v, k);
    +       for(; k<last; k++, pOp++){
    +         if( pOp->p1!=pLevel->iTabCur ) continue;
    +-        if( pOp->opcode==OP_Column ){
    ++        if( pOp->opcode==OP_Column
    ++#ifdef SQLITE_ENABLE_OFFSET_SQL_FUNC
    ++         || pOp->opcode==OP_Offset
    ++#endif
    ++        ){
    +           int x = pOp->p2;
    +           assert( pIdx->pTable==pTab );
    +           if( !HasRowid(pTab) ){
    +@@ -125983,10 +138088,13 @@ SQLITE_PRIVATE void sqlite3WhereEnd(WhereInfo *pWInfo){
    +             pOp->p2 = x;
    +             pOp->p1 = pLevel->iIdxCur;
    +           }
    +-          assert( (pLoop->wsFlags & WHERE_IDX_ONLY)==0 || x>=0 );
    ++          assert( (pLoop->wsFlags & WHERE_IDX_ONLY)==0 || x>=0 
    ++              || pWInfo->eOnePass );
    +         }else if( pOp->opcode==OP_Rowid ){
    +           pOp->p1 = pLevel->iIdxCur;
    +           pOp->opcode = OP_IdxRowid;
    ++        }else if( pOp->opcode==OP_IfNullRow ){
    ++          pOp->p1 = pLevel->iIdxCur;
    +         }
    +       }
    +     }
    +@@ -126001,18 +138109,32 @@ SQLITE_PRIVATE void sqlite3WhereEnd(WhereInfo *pWInfo){
    + 
    + /************** End of where.c ***********************************************/
    + /************** Begin file parse.c *******************************************/
    +-/* Driver template for the LEMON parser generator.
    +-** The author disclaims copyright to this source code.
    ++/*
    ++** 2000-05-29
    ++**
    ++** 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.
    ++**
    ++*************************************************************************
    ++** Driver template for the LEMON parser generator.
    + **
    +-** This version of "lempar.c" is modified, slightly, for use by SQLite.
    +-** The only modifications are the addition of a couple of NEVER()
    +-** macros to disable tests that are needed in the case of a general
    +-** LALR(1) grammar but which are always false in the
    +-** specific grammar used by SQLite.
    ++** The "lemon" program processes an LALR(1) input grammar file, then uses
    ++** this template to construct a parser.  The "lemon" program inserts text
    ++** at each "%%" line.  Also, any "P-a-r-s-e" identifer prefix (without the
    ++** interstitial "-" characters) contained in this template is changed into
    ++** the value of the %name directive from the grammar.  Otherwise, the content
    ++** of this template is copied straight through into the generate parser
    ++** source file.
    ++**
    ++** The following is the concatenation of all %include directives from the
    ++** input grammar file:
    + */
    +-/* First off, code is included that follows the "include" declaration
    +-** in the input grammar file. */
    + /* #include <stdio.h> */
    ++/************ Begin %include sections from the grammar ************************/
    + 
    + /* #include "sqliteInt.h" */
    + 
    +@@ -126028,22 +138150,29 @@ SQLITE_PRIVATE void sqlite3WhereEnd(WhereInfo *pWInfo){
    + #define yytestcase(X) testcase(X)
    + 
    + /*
    +-** An instance of this structure holds information about the
    +-** LIMIT clause of a SELECT statement.
    ++** Indicate that sqlite3ParserFree() will never be called with a null
    ++** pointer.
    + */
    +-struct LimitVal {
    +-  Expr *pLimit;    /* The LIMIT expression.  NULL if there is no limit */
    +-  Expr *pOffset;   /* The OFFSET expression.  NULL if there is none */
    +-};
    ++#define YYPARSEFREENEVERNULL 1
    + 
    + /*
    +-** An instance of this structure is used to store the LIKE,
    +-** GLOB, NOT LIKE, and NOT GLOB operators.
    ++** In the amalgamation, the parse.c file generated by lemon and the
    ++** tokenize.c file are concatenated.  In that case, sqlite3RunParser()
    ++** has access to the the size of the yyParser object and so the parser
    ++** engine can be allocated from stack.  In that case, only the
    ++** sqlite3ParserInit() and sqlite3ParserFinalize() routines are invoked
    ++** and the sqlite3ParserAlloc() and sqlite3ParserFree() routines can be
    ++** omitted.
    + */
    +-struct LikeOp {
    +-  Token eOperator;  /* "like" or "glob" or "regexp" */
    +-  int bNot;         /* True if the NOT keyword is present */
    +-};
    ++#ifdef SQLITE_AMALGAMATION
    ++# define sqlite3Parser_ENGINEALWAYSONSTACK 1
    ++#endif
    ++
    ++/*
    ++** Alternative datatype for the argument to the malloc() routine passed
    ++** into sqlite3ParserAlloc().  The default is size_t.
    ++*/
    ++#define YYMALLOCARGTYPE  u64
    + 
    + /*
    + ** An instance of the following structure describes the event of a
    +@@ -126057,9 +138186,13 @@ struct LikeOp {
    + struct TrigEvent { int a; IdList * b; };
    + 
    + /*
    +-** An instance of this structure holds the ATTACH key and the key type.
    ++** Disable lookaside memory allocation for objects that might be
    ++** shared across database connections.
    + */
    +-struct AttachKey { int type;  Token key; };
    ++static void disableLookaside(Parse *pParse){
    ++  pParse->disableLookaside++;
    ++  pParse->db->lookaside.bDisable++;
    ++}
    + 
    + 
    +   /*
    +@@ -126084,79 +138217,43 @@ struct AttachKey { int type;  Token key; };
    +     }
    +   }
    + 
    +-  /* This is a utility routine used to set the ExprSpan.zStart and
    +-  ** ExprSpan.zEnd values of pOut so that the span covers the complete
    +-  ** range of text beginning with pStart and going to the end of pEnd.
    +-  */
    +-  static void spanSet(ExprSpan *pOut, Token *pStart, Token *pEnd){
    +-    pOut->zStart = pStart->z;
    +-    pOut->zEnd = &pEnd->z[pEnd->n];
    +-  }
    + 
    +   /* Construct a new Expr object from a single identifier.  Use the
    +   ** new Expr to populate pOut.  Set the span of pOut to be the identifier
    +   ** that created the expression.
    +   */
    +-  static void spanExpr(ExprSpan *pOut, Parse *pParse, int op, Token *pValue){
    +-    pOut->pExpr = sqlite3PExpr(pParse, op, 0, 0, pValue);
    +-    pOut->zStart = pValue->z;
    +-    pOut->zEnd = &pValue->z[pValue->n];
    +-  }
    +-
    +-  /* This routine constructs a binary expression node out of two ExprSpan
    +-  ** objects and uses the result to populate a new ExprSpan object.
    +-  */
    +-  static void spanBinaryExpr(
    +-    ExprSpan *pOut,     /* Write the result here */
    +-    Parse *pParse,      /* The parsing context.  Errors accumulate here */
    +-    int op,             /* The binary operation */
    +-    ExprSpan *pLeft,    /* The left operand */
    +-    ExprSpan *pRight    /* The right operand */
    +-  ){
    +-    pOut->pExpr = sqlite3PExpr(pParse, op, pLeft->pExpr, pRight->pExpr, 0);
    +-    pOut->zStart = pLeft->zStart;
    +-    pOut->zEnd = pRight->zEnd;
    ++  static Expr *tokenExpr(Parse *pParse, int op, Token t){
    ++    Expr *p = sqlite3DbMallocRawNN(pParse->db, sizeof(Expr)+t.n+1);
    ++    if( p ){
    ++      memset(p, 0, sizeof(Expr));
    ++      p->op = (u8)op;
    ++      p->flags = EP_Leaf;
    ++      p->iAgg = -1;
    ++      p->u.zToken = (char*)&p[1];
    ++      memcpy(p->u.zToken, t.z, t.n);
    ++      p->u.zToken[t.n] = 0;
    ++      if( sqlite3Isquote(p->u.zToken[0]) ){
    ++        if( p->u.zToken[0]=='"' ) p->flags |= EP_DblQuoted;
    ++        sqlite3Dequote(p->u.zToken);
    ++      }
    ++#if SQLITE_MAX_EXPR_DEPTH>0
    ++      p->nHeight = 1;
    ++#endif  
    ++    }
    ++    return p;
    +   }
    + 
    +-  /* Construct an expression node for a unary postfix operator
    +-  */
    +-  static void spanUnaryPostfix(
    +-    ExprSpan *pOut,        /* Write the new expression node here */
    +-    Parse *pParse,         /* Parsing context to record errors */
    +-    int op,                /* The operator */
    +-    ExprSpan *pOperand,    /* The operand */
    +-    Token *pPostOp         /* The operand token for setting the span */
    +-  ){
    +-    pOut->pExpr = sqlite3PExpr(pParse, op, pOperand->pExpr, 0, 0);
    +-    pOut->zStart = pOperand->zStart;
    +-    pOut->zEnd = &pPostOp->z[pPostOp->n];
    +-  }                           
    +-
    +   /* A routine to convert a binary TK_IS or TK_ISNOT expression into a
    +   ** unary TK_ISNULL or TK_NOTNULL expression. */
    +   static void binaryToUnaryIfNull(Parse *pParse, Expr *pY, Expr *pA, int op){
    +     sqlite3 *db = pParse->db;
    +-    if( pY && pA && pY->op==TK_NULL ){
    ++    if( pA && pY && pY->op==TK_NULL ){
    +       pA->op = (u8)op;
    +       sqlite3ExprDelete(db, pA->pRight);
    +       pA->pRight = 0;
    +     }
    +   }
    + 
    +-  /* Construct an expression node for a unary prefix operator
    +-  */
    +-  static void spanUnaryPrefix(
    +-    ExprSpan *pOut,        /* Write the new expression node here */
    +-    Parse *pParse,         /* Parsing context to record errors */
    +-    int op,                /* The operator */
    +-    ExprSpan *pOperand,    /* The operand */
    +-    Token *pPreOp         /* The operand token for setting the span */
    +-  ){
    +-    pOut->pExpr = sqlite3PExpr(pParse, op, pOperand->pExpr, 0, 0);
    +-    pOut->zStart = pPreOp->z;
    +-    pOut->zEnd = pOperand->zEnd;
    +-  }
    +-
    +   /* Add a single new term to an ExprList that is used to store a
    +   ** list of identifiers.  Report an error if the ID list contains
    +   ** a COLLATE clause or an ASC or DESC keyword, except ignore the
    +@@ -126179,44 +138276,42 @@ struct AttachKey { int type;  Token key; };
    +     sqlite3ExprListSetName(pParse, p, pIdToken, 1);
    +     return p;
    +   }
    +-/* Next is all token values, in a form suitable for use by makeheaders.
    +-** This section will be null unless lemon is run with the -m switch.
    +-*/
    +-/* 
    +-** These constants (all generated automatically by the parser generator)
    +-** specify the various kinds of tokens (terminals) that the parser
    +-** understands. 
    +-**
    +-** Each symbol here is a terminal symbol in the grammar.
    +-*/
    +-/* Make sure the INTERFACE macro is defined.
    +-*/
    +-#ifndef INTERFACE
    +-# define INTERFACE 1
    +-#endif
    +-/* The next thing included is series of defines which control
    ++/**************** End of %include directives **********************************/
    ++/* These constants specify the various numeric values for terminal symbols
    ++** in a format understandable to "makeheaders".  This section is blank unless
    ++** "lemon" is run with the "-m" command-line option.
    ++***************** Begin makeheaders token definitions *************************/
    ++/**************** End makeheaders token definitions ***************************/
    ++
    ++/* The next sections is a series of control #defines.
    + ** various aspects of the generated parser.
    +-**    YYCODETYPE         is the data type used for storing terminal
    +-**                       and nonterminal numbers.  "unsigned char" is
    +-**                       used if there are fewer than 250 terminals
    +-**                       and nonterminals.  "int" is used otherwise.
    +-**    YYNOCODE           is a number of type YYCODETYPE which corresponds
    +-**                       to no legal terminal or nonterminal number.  This
    +-**                       number is used to fill in empty slots of the hash 
    +-**                       table.
    ++**    YYCODETYPE         is the data type used to store the integer codes
    ++**                       that represent terminal and non-terminal symbols.
    ++**                       "unsigned char" is used if there are fewer than
    ++**                       256 symbols.  Larger types otherwise.
    ++**    YYNOCODE           is a number of type YYCODETYPE that is not used for
    ++**                       any terminal or nonterminal symbol.
    + **    YYFALLBACK         If defined, this indicates that one or more tokens
    +-**                       have fall-back values which should be used if the
    +-**                       original value of the token will not parse.
    +-**    YYACTIONTYPE       is the data type used for storing terminal
    +-**                       and nonterminal numbers.  "unsigned char" is
    +-**                       used if there are fewer than 250 rules and
    +-**                       states combined.  "int" is used otherwise.
    +-**    sqlite3ParserTOKENTYPE     is the data type used for minor tokens given 
    +-**                       directly to the parser from the tokenizer.
    +-**    YYMINORTYPE        is the data type used for all minor tokens.
    ++**                       (also known as: "terminal symbols") have fall-back
    ++**                       values which should be used if the original symbol
    ++**                       would not parse.  This permits keywords to sometimes
    ++**                       be used as identifiers, for example.
    ++**    YYACTIONTYPE       is the data type used for "action codes" - numbers
    ++**                       that indicate what to do in response to the next
    ++**                       token.
    ++**    sqlite3ParserTOKENTYPE     is the data type used for minor type for terminal
    ++**                       symbols.  Background: A "minor type" is a semantic
    ++**                       value associated with a terminal or non-terminal
    ++**                       symbols.  For example, for an "ID" terminal symbol,
    ++**                       the minor type might be the name of the identifier.
    ++**                       Each non-terminal can have a different minor type.
    ++**                       Terminal symbols all have the same minor type, though.
    ++**                       This macros defines the minor type for terminal 
    ++**                       symbols.
    ++**    YYMINORTYPE        is the data type used for all minor types.
    + **                       This is typically a union of many types, one of
    + **                       which is sqlite3ParserTOKENTYPE.  The entry in the union
    +-**                       for base tokens is called "yy0".
    ++**                       for terminal symbols is called "yy0".
    + **    YYSTACKDEPTH       is the maximum depth of the parser's stack.  If
    + **                       zero the stack is dynamically sized using realloc()
    + **    sqlite3ParserARG_SDECL     A static variable declaration for the %extra_argument
    +@@ -126227,37 +138322,39 @@ struct AttachKey { int type;  Token key; };
    + **                       defined, then do no error processing.
    + **    YYNSTATE           the combined number of states.
    + **    YYNRULE            the number of rules in the grammar
    ++**    YYNTOKEN           Number of terminal symbols
    + **    YY_MAX_SHIFT       Maximum value for shift actions
    + **    YY_MIN_SHIFTREDUCE Minimum value for shift-reduce actions
    + **    YY_MAX_SHIFTREDUCE Maximum value for shift-reduce actions
    +-**    YY_MIN_REDUCE      Maximum value for reduce actions
    + **    YY_ERROR_ACTION    The yy_action[] code for syntax error
    + **    YY_ACCEPT_ACTION   The yy_action[] code for accept
    + **    YY_NO_ACTION       The yy_action[] code for no-op
    ++**    YY_MIN_REDUCE      Minimum value for reduce actions
    ++**    YY_MAX_REDUCE      Maximum value for reduce actions
    + */
    ++#ifndef INTERFACE
    ++# define INTERFACE 1
    ++#endif
    ++/************* Begin control #defines *****************************************/
    + #define YYCODETYPE unsigned char
    +-#define YYNOCODE 254
    ++#define YYNOCODE 253
    + #define YYACTIONTYPE unsigned short int
    +-#define YYWILDCARD 70
    ++#define YYWILDCARD 83
    + #define sqlite3ParserTOKENTYPE Token
    + typedef union {
    +   int yyinit;
    +   sqlite3ParserTOKENTYPE yy0;
    +-  Select* yy3;
    +-  ExprList* yy14;
    +-  With* yy59;
    +-  SrcList* yy65;
    +-  struct LikeOp yy96;
    +-  Expr* yy132;
    +-  u8 yy186;
    +-  int yy328;
    +-  ExprSpan yy346;
    +-  struct TrigEvent yy378;
    +-  u16 yy381;
    +-  IdList* yy408;
    +-  struct {int value; int mask;} yy429;
    +-  TriggerStep* yy473;
    +-  struct LimitVal yy476;
    ++  int yy4;
    ++  struct TrigEvent yy90;
    ++  TriggerStep* yy203;
    ++  struct {int value; int mask;} yy215;
    ++  SrcList* yy259;
    ++  Expr* yy314;
    ++  ExprList* yy322;
    ++  const char* yy336;
    ++  IdList* yy384;
    ++  Select* yy387;
    ++  With* yy451;
    + } YYMINORTYPE;
    + #ifndef YYSTACKDEPTH
    + #define YYSTACKDEPTH 100
    +@@ -126267,20 +138364,18 @@ typedef union {
    + #define sqlite3ParserARG_FETCH Parse *pParse = yypParser->pParse
    + #define sqlite3ParserARG_STORE yypParser->pParse = pParse
    + #define YYFALLBACK 1
    +-#define YYNSTATE             436
    +-#define YYNRULE              328
    +-#define YY_MAX_SHIFT         435
    +-#define YY_MIN_SHIFTREDUCE   649
    +-#define YY_MAX_SHIFTREDUCE   976
    +-#define YY_MIN_REDUCE        977
    +-#define YY_MAX_REDUCE        1304
    +-#define YY_ERROR_ACTION      1305
    +-#define YY_ACCEPT_ACTION     1306
    +-#define YY_NO_ACTION         1307
    +-
    +-/* The yyzerominor constant is used to initialize instances of
    +-** YYMINORTYPE objects to zero. */
    +-static const YYMINORTYPE yyzerominor = { 0 };
    ++#define YYNSTATE             466
    ++#define YYNRULE              330
    ++#define YYNTOKEN             143
    ++#define YY_MAX_SHIFT         465
    ++#define YY_MIN_SHIFTREDUCE   675
    ++#define YY_MAX_SHIFTREDUCE   1004
    ++#define YY_ERROR_ACTION      1005
    ++#define YY_ACCEPT_ACTION     1006
    ++#define YY_NO_ACTION         1007
    ++#define YY_MIN_REDUCE        1008
    ++#define YY_MAX_REDUCE        1337
    ++/************* End control #defines *******************************************/
    + 
    + /* Define the yytestcase() macro to be a no-op if is not already defined
    + ** otherwise.
    +@@ -126309,9 +138404,6 @@ static const YYMINORTYPE yyzerominor = { 0 };
    + **   N between YY_MIN_SHIFTREDUCE       Shift to an arbitrary state then
    + **     and YY_MAX_SHIFTREDUCE           reduce by rule N-YY_MIN_SHIFTREDUCE.
    + **
    +-**   N between YY_MIN_REDUCE            Reduce by rule N-YY_MIN_REDUCE
    +-**     and YY_MAX_REDUCE
    +-
    + **   N == YY_ERROR_ACTION               A syntax error has occurred.
    + **
    + **   N == YY_ACCEPT_ACTION              The parser accepts its input.
    +@@ -126319,21 +138411,22 @@ static const YYMINORTYPE yyzerominor = { 0 };
    + **   N == YY_NO_ACTION                  No such action.  Denotes unused
    + **                                      slots in the yy_action[] table.
    + **
    ++**   N between YY_MIN_REDUCE            Reduce by rule N-YY_MIN_REDUCE
    ++**     and YY_MAX_REDUCE
    ++**
    + ** The action table is constructed as a single large table named yy_action[].
    +-** Given state S and lookahead X, the action is computed as
    ++** Given state S and lookahead X, the action is computed as either:
    + **
    +-**      yy_action[ yy_shift_ofst[S] + X ]
    ++**    (A)   N = yy_action[ yy_shift_ofst[S] + X ]
    ++**    (B)   N = yy_default[S]
    + **
    +-** If the index value yy_shift_ofst[S]+X is out of range or if the value
    +-** yy_lookahead[yy_shift_ofst[S]+X] is not equal to X or if yy_shift_ofst[S]
    +-** is equal to YY_SHIFT_USE_DFLT, it means that the action is not in the table
    +-** and that yy_default[S] should be used instead.  
    ++** The (A) formula is preferred.  The B formula is used instead if
    ++** yy_lookahead[yy_shift_ofst[S]+X] is not equal to X.
    + **
    +-** The formula above is for computing the action when the lookahead is
    ++** The formulas above are for computing the action when the lookahead is
    + ** a terminal symbol.  If the lookahead is a non-terminal (as occurs after
    + ** a reduce action) then the yy_reduce_ofst[] array is used in place of
    +-** the yy_shift_ofst[] array and YY_REDUCE_USE_DFLT is used in place of
    +-** YY_SHIFT_USE_DFLT.
    ++** the yy_shift_ofst[] array.
    + **
    + ** The following are the tables generated in this section:
    + **
    +@@ -126345,451 +138438,481 @@ static const YYMINORTYPE yyzerominor = { 0 };
    + **  yy_reduce_ofst[]   For each state, the offset into yy_action for
    + **                     shifting non-terminals after a reduce.
    + **  yy_default[]       Default action for each state.
    +-*/
    +-#define YY_ACTTAB_COUNT (1501)
    ++**
    ++*********** Begin parsing tables **********************************************/
    ++#define YY_ACTTAB_COUNT (1541)
    + static const YYACTIONTYPE yy_action[] = {
    +- /*     0 */   311, 1306,  145,  651,    2,  192,  652,  338,  780,   92,
    +- /*    10 */    92,   92,   92,   85,   90,   90,   90,   90,   89,   89,
    +- /*    20 */    88,   88,   88,   87,  335,   88,   88,   88,   87,  335,
    +- /*    30 */   327,  856,  856,   92,   92,   92,   92,  776,   90,   90,
    +- /*    40 */    90,   90,   89,   89,   88,   88,   88,   87,  335,   86,
    +- /*    50 */    83,  166,   93,   94,   84,  868,  871,  860,  860,   91,
    +- /*    60 */    91,   92,   92,   92,   92,  335,   90,   90,   90,   90,
    +- /*    70 */    89,   89,   88,   88,   88,   87,  335,  311,  780,   90,
    +- /*    80 */    90,   90,   90,   89,   89,   88,   88,   88,   87,  335,
    +- /*    90 */   123,  808,  689,  689,  689,  689,  112,  230,  430,  257,
    +- /*   100 */   809,  698,  430,   86,   83,  166,  324,   55,  856,  856,
    +- /*   110 */   201,  158,  276,  387,  271,  386,  188,  689,  689,  828,
    +- /*   120 */   833,   49,  944,  269,  833,   49,  123,   87,  335,   93,
    +- /*   130 */    94,   84,  868,  871,  860,  860,   91,   91,   92,   92,
    +- /*   140 */    92,   92,  342,   90,   90,   90,   90,   89,   89,   88,
    +- /*   150 */    88,   88,   87,  335,  311,  328,  333,  332,  701,  408,
    +- /*   160 */   394,   69,  690,  691,  690,  691,  715,  910,  251,  354,
    +- /*   170 */   250,  698,  704,  430,  908,  430,  909,   89,   89,   88,
    +- /*   180 */    88,   88,   87,  335,  391,  856,  856,  690,  691,  183,
    +- /*   190 */    95,  340,  384,  381,  380,  833,   31,  833,   49,  912,
    +- /*   200 */   912,  333,  332,  379,  123,  311,   93,   94,   84,  868,
    +- /*   210 */   871,  860,  860,   91,   91,   92,   92,   92,   92,  114,
    +- /*   220 */    90,   90,   90,   90,   89,   89,   88,   88,   88,   87,
    +- /*   230 */   335,  430,  408,  399,  435,  657,  856,  856,  346,   57,
    +- /*   240 */   232,  828,  109,   20,  912,  912,  231,  393,  937,  760,
    +- /*   250 */    97,  751,  752,  833,   49,  708,  708,   93,   94,   84,
    +- /*   260 */   868,  871,  860,  860,   91,   91,   92,   92,   92,   92,
    +- /*   270 */   707,   90,   90,   90,   90,   89,   89,   88,   88,   88,
    +- /*   280 */    87,  335,  311,  114,   22,  706,  688,   58,  408,  390,
    +- /*   290 */   251,  349,  240,  749,  752,  689,  689,  847,  685,  115,
    +- /*   300 */    21,  231,  393,  689,  689,  697,  183,  355,  430,  384,
    +- /*   310 */   381,  380,  192,  856,  856,  780,  123,  160,  159,  223,
    +- /*   320 */   379,  738,   25,  315,  362,  841,  143,  689,  689,  835,
    +- /*   330 */   833,   48,  339,  937,   93,   94,   84,  868,  871,  860,
    +- /*   340 */   860,   91,   91,   92,   92,   92,   92,  914,   90,   90,
    +- /*   350 */    90,   90,   89,   89,   88,   88,   88,   87,  335,  311,
    +- /*   360 */   840,  840,  840,  266,  430,  690,  691,  778,  114, 1300,
    +- /*   370 */  1300,  430,    1,  690,  691,  697,  688,  689,  689,  689,
    +- /*   380 */   689,  689,  689,  287,  298,  780,  833,   10,  686,  115,
    +- /*   390 */   856,  856,  355,  833,   10,  828,  366,  690,  691,  363,
    +- /*   400 */   321,   76,  123,   74,   23,  737,  807,  323,  356,  353,
    +- /*   410 */   847,   93,   94,   84,  868,  871,  860,  860,   91,   91,
    +- /*   420 */    92,   92,   92,   92,  940,   90,   90,   90,   90,   89,
    +- /*   430 */    89,   88,   88,   88,   87,  335,  311,  806,  841,  429,
    +- /*   440 */   713,  941,  835,  430,  251,  354,  250,  690,  691,  690,
    +- /*   450 */   691,  690,  691,   86,   83,  166,   24,  942,  151,  753,
    +- /*   460 */   285,  907,  403,  907,  164,  833,   10,  856,  856,  965,
    +- /*   470 */   306,  754,  679,  840,  840,  840,  795,  216,  794,  222,
    +- /*   480 */   906,  344,  906,  904,   86,   83,  166,  286,   93,   94,
    +- /*   490 */    84,  868,  871,  860,  860,   91,   91,   92,   92,   92,
    +- /*   500 */    92,  430,   90,   90,   90,   90,   89,   89,   88,   88,
    +- /*   510 */    88,   87,  335,  311,  430,  724,  352,  705,  427,  699,
    +- /*   520 */   700,  376,  210,  833,   49,  793,  397,  857,  857,  940,
    +- /*   530 */   213,  762,  727,  334,  699,  700,  833,   10,   86,   83,
    +- /*   540 */   166,  345,  396,  902,  856,  856,  941,  385,  833,    9,
    +- /*   550 */   406,  869,  872,  187,  890,  728,  347,  398,  404,  977,
    +- /*   560 */   652,  338,  942,  954,  413,   93,   94,   84,  868,  871,
    +- /*   570 */   860,  860,   91,   91,   92,   92,   92,   92,  861,   90,
    +- /*   580 */    90,   90,   90,   89,   89,   88,   88,   88,   87,  335,
    +- /*   590 */   311, 1219,  114,  430,  834,  430,    5,  165,  192,  688,
    +- /*   600 */   832,  780,  430,  723,  430,  234,  325,  189,  163,  316,
    +- /*   610 */   356,  955,  115,  235,  269,  833,   35,  833,   36,  747,
    +- /*   620 */   720,  856,  856,  793,  833,   12,  833,   27,  745,  174,
    +- /*   630 */   968, 1290,  968, 1291, 1290,  310, 1291,  693,  317,  245,
    +- /*   640 */   264,  311,   93,   94,   84,  868,  871,  860,  860,   91,
    +- /*   650 */    91,   92,   92,   92,   92,  832,   90,   90,   90,   90,
    +- /*   660 */    89,   89,   88,   88,   88,   87,  335,  430,  320,  213,
    +- /*   670 */   762,  780,  856,  856,  920,  920,  369,  257,  966,  220,
    +- /*   680 */   966,  396,  663,  664,  665,  242,  259,  244,  262,  833,
    +- /*   690 */    37,  650,    2,   93,   94,   84,  868,  871,  860,  860,
    +- /*   700 */    91,   91,   92,   92,   92,   92,  430,   90,   90,   90,
    +- /*   710 */    90,   89,   89,   88,   88,   88,   87,  335,  311,  430,
    +- /*   720 */   239,  430,  917,  368,  430,  238,  916,  793,  833,   38,
    +- /*   730 */   430,  825,  430,   66,  430,  392,  430,  766,  766,  430,
    +- /*   740 */   367,  833,   39,  833,   28,  430,  833,   29,   68,  856,
    +- /*   750 */   856,  900,  833,   40,  833,   41,  833,   42,  833,   11,
    +- /*   760 */    72,  833,   43,  243,  305,  970,  114,  833,   99,  961,
    +- /*   770 */    93,   94,   84,  868,  871,  860,  860,   91,   91,   92,
    +- /*   780 */    92,   92,   92,  430,   90,   90,   90,   90,   89,   89,
    +- /*   790 */    88,   88,   88,   87,  335,  311,  430,  361,  430,  165,
    +- /*   800 */   147,  430,  186,  185,  184,  833,   44,  430,  289,  430,
    +- /*   810 */   246,  430,  971,  430,  212,  163,  430,  357,  833,   45,
    +- /*   820 */   833,   32,  932,  833,   46,  793,  856,  856,  718,  833,
    +- /*   830 */    47,  833,   33,  833,  117,  833,  118,   75,  833,  119,
    +- /*   840 */   288,  305,  967,  214,  935,  322,  311,   93,   94,   84,
    +- /*   850 */   868,  871,  860,  860,   91,   91,   92,   92,   92,   92,
    +- /*   860 */   430,   90,   90,   90,   90,   89,   89,   88,   88,   88,
    +- /*   870 */    87,  335,  430,  832,  426,  317,  288,  856,  856,  114,
    +- /*   880 */   763,  257,  833,   53,  930,  219,  364,  257,  257,  971,
    +- /*   890 */   361,  396,  257,  257,  833,   34,  257,  311,   93,   94,
    +- /*   900 */    84,  868,  871,  860,  860,   91,   91,   92,   92,   92,
    +- /*   910 */    92,  430,   90,   90,   90,   90,   89,   89,   88,   88,
    +- /*   920 */    88,   87,  335,  430,  217,  318,  124,  253,  856,  856,
    +- /*   930 */   218,  943,  257,  833,  100,  898,  759,  774,  361,  755,
    +- /*   940 */   423,  329,  758, 1017,  289,  833,   50,  682,  311,   93,
    +- /*   950 */    82,   84,  868,  871,  860,  860,   91,   91,   92,   92,
    +- /*   960 */    92,   92,  430,   90,   90,   90,   90,   89,   89,   88,
    +- /*   970 */    88,   88,   87,  335,  430,  256,  419,  114,  249,  856,
    +- /*   980 */   856,  331,  114,  400,  833,  101,  359,  187, 1064,  726,
    +- /*   990 */   725,  739,  401,  416,  420,  360,  833,  102,  424,  311,
    +- /*  1000 */   258,   94,   84,  868,  871,  860,  860,   91,   91,   92,
    +- /*  1010 */    92,   92,   92,  430,   90,   90,   90,   90,   89,   89,
    +- /*  1020 */    88,   88,   88,   87,  335,  430,  221,  261,  114,  114,
    +- /*  1030 */   856,  856,  808,  114,  156,  833,   98,  772,  733,  734,
    +- /*  1040 */   275,  809,  771,  316,  263,  265,  960,  833,  116,  307,
    +- /*  1050 */   741,  274,  722,   84,  868,  871,  860,  860,   91,   91,
    +- /*  1060 */    92,   92,   92,   92,  430,   90,   90,   90,   90,   89,
    +- /*  1070 */    89,   88,   88,   88,   87,  335,   80,  425,  830,    3,
    +- /*  1080 */  1214,  191,  430,  721,  336,  336,  833,  113,  252,   80,
    +- /*  1090 */   425,   68,    3,  913,  913,  428,  270,  336,  336,  430,
    +- /*  1100 */   377,  784,  430,  197,  833,  106,  430,  716,  428,  430,
    +- /*  1110 */   267,  430,  897,   68,  414,  430,  769,  409,  430,   71,
    +- /*  1120 */   430,  833,  105,  123,  833,  103,  847,  414,  833,   49,
    +- /*  1130 */   843,  833,  104,  833,   52,  800,  123,  833,   54,  847,
    +- /*  1140 */   833,   51,  833,   26,  831,  802,   77,   78,  191,  389,
    +- /*  1150 */   430,  372,  114,   79,  432,  431,  911,  911,  835,   77,
    +- /*  1160 */    78,  779,  893,  408,  410,  197,   79,  432,  431,  791,
    +- /*  1170 */   226,  835,  833,   30,  772,   80,  425,  716,    3,  771,
    +- /*  1180 */   411,  412,  897,  336,  336,  290,  291,  839,  703,  840,
    +- /*  1190 */   840,  840,  842,   19,  428,  695,  684,  672,  111,  671,
    +- /*  1200 */   843,  673,  840,  840,  840,  842,   19,  207,  661,  278,
    +- /*  1210 */   148,  304,  280,  414,  282,    6,  822,  348,  248,  241,
    +- /*  1220 */   358,  934,  720,   80,  425,  847,    3,  161,  382,  273,
    +- /*  1230 */   284,  336,  336,  415,  296,  958,  895,  894,  157,  674,
    +- /*  1240 */   107,  194,  428,  948,  135,   77,   78,  777,  953,  951,
    +- /*  1250 */    56,  319,   79,  432,  431,  121,   66,  835,   59,  128,
    +- /*  1260 */   146,  414,  350,  130,  351,  819,  131,  132,  133,  375,
    +- /*  1270 */   173,  149,  138,  847,  936,  365,  178,   70,  425,  827,
    +- /*  1280 */     3,  889,   62,  371,  915,  336,  336,  792,  840,  840,
    +- /*  1290 */   840,  842,   19,   77,   78,  208,  428,  144,  179,  373,
    +- /*  1300 */    79,  432,  431,  255,  180,  835,  260,  675,  181,  308,
    +- /*  1310 */   388,  744,  326,  743,  742,  414,  731,  718,  712,  402,
    +- /*  1320 */   309,  711,  788,   65,  277,  272,  789,  847,  730,  710,
    +- /*  1330 */   709,  279,  193,  787,  281,  876,  840,  840,  840,  842,
    +- /*  1340 */    19,  786,  283,   73,  418,  330,  422,   77,   78,  227,
    +- /*  1350 */    96,  407,   67,  405,   79,  432,  431,  292,  228,  835,
    +- /*  1360 */   215,  202,  229,  293,  767,  303,  302,  301,  204,  299,
    +- /*  1370 */   294,  295,  676,    7,  681,  433,  669,  206,  110,  224,
    +- /*  1380 */   203,  205,  434,  667,  666,  658,  120,  168,  656,  237,
    +- /*  1390 */   840,  840,  840,  842,   19,  337,  155,  233,  236,  341,
    +- /*  1400 */   167,  905,  108,  313,  903,  826,  314,  125,  126,  127,
    +- /*  1410 */   129,  170,  247,  756,  172,  928,  134,  136,  171,   60,
    +- /*  1420 */    61,  123,  169,  137,  175,  933,  176,  927,    8,   13,
    +- /*  1430 */   177,  254,  191,  918,  139,  370,  924,  140,  678,  150,
    +- /*  1440 */   374,  274,  182,  378,  141,  122,   63,   14,  383,  729,
    +- /*  1450 */   268,   15,   64,  225,  846,  845,  874,   16,  765,  770,
    +- /*  1460 */     4,  162,  209,  395,  211,  142,  878,  796,  801,  312,
    +- /*  1470 */   190,   71,   68,  875,  873,  939,  199,  938,   17,  195,
    +- /*  1480 */    18,  196,  417,  975,  152,  653,  976,  198,  153,  421,
    +- /*  1490 */   877,  154,  200,  844,  696,   81,  343,  297, 1019, 1018,
    +- /*  1500 */   300,
    ++ /*     0 */  1006,  156,  156,    2, 1302,   90,   87,  179,   90,   87,
    ++ /*    10 */   179,  460, 1048,  460,  465, 1010,  460,  333, 1130,  335,
    ++ /*    20 */   246,  330,  112,  303,  439, 1258,  304,  419, 1129, 1087,
    ++ /*    30 */    72,  798,   50,   50,   50,   50,  331,   30,   30,  799,
    ++ /*    40 */   951,  364,  371,   97,   98,   88,  983,  983,  859,  862,
    ++ /*    50 */   851,  851,   95,   95,   96,   96,   96,   96,  120,  371,
    ++ /*    60 */   370,  120,  348,   22,   90,   87,  179,  438,  423,  438,
    ++ /*    70 */   440,  335,  420,  385,   90,   87,  179,  116,   73,  163,
    ++ /*    80 */   848,  848,  860,  863,   94,   94,   94,   94,   93,   93,
    ++ /*    90 */    92,   92,   92,   91,  361,   97,   98,   88,  983,  983,
    ++ /*   100 */   859,  862,  851,  851,   95,   95,   96,   96,   96,   96,
    ++ /*   110 */   718,  365,  339,   93,   93,   92,   92,   92,   91,  361,
    ++ /*   120 */    99,  371,  453,  335,   94,   94,   94,   94,   93,   93,
    ++ /*   130 */    92,   92,   92,   91,  361,  852,   94,   94,   94,   94,
    ++ /*   140 */    93,   93,   92,   92,   92,   91,  361,   97,   98,   88,
    ++ /*   150 */   983,  983,  859,  862,  851,  851,   95,   95,   96,   96,
    ++ /*   160 */    96,   96,   92,   92,   92,   91,  361,  838,  132,  195,
    ++ /*   170 */    58,  244,  412,  409,  408,  335,  457,  457,  457,  304,
    ++ /*   180 */    59,  332,  831,  407,  394,  962,  830,  391,   94,   94,
    ++ /*   190 */    94,   94,   93,   93,   92,   92,   92,   91,  361,   97,
    ++ /*   200 */    98,   88,  983,  983,  859,  862,  851,  851,   95,   95,
    ++ /*   210 */    96,   96,   96,   96,  426,  357,  460,  830,  830,  832,
    ++ /*   220 */    91,  361,  962,  963,  964,  195,  459,  335,  412,  409,
    ++ /*   230 */   408,  280,  361,  820,  132,   11,   11,   50,   50,  407,
    ++ /*   240 */    94,   94,   94,   94,   93,   93,   92,   92,   92,   91,
    ++ /*   250 */   361,   97,   98,   88,  983,  983,  859,  862,  851,  851,
    ++ /*   260 */    95,   95,   96,   96,   96,   96,  460,  221,  460,  264,
    ++ /*   270 */   375,  254,  438,  428, 1276, 1276,  383, 1074, 1053,  335,
    ++ /*   280 */   245,  422,  299,  713,  271,  271, 1074,   50,   50,   50,
    ++ /*   290 */    50,  962,   94,   94,   94,   94,   93,   93,   92,   92,
    ++ /*   300 */    92,   91,  361,   97,   98,   88,  983,  983,  859,  862,
    ++ /*   310 */   851,  851,   95,   95,   96,   96,   96,   96,   90,   87,
    ++ /*   320 */   179, 1306,  438,  437,  438,  418,  368,  253,  962,  963,
    ++ /*   330 */   964,  335,  360,  360,  360,  706,  359,  358,  324,  962,
    ++ /*   340 */  1281,  951,  364,  230,   94,   94,   94,   94,   93,   93,
    ++ /*   350 */    92,   92,   92,   91,  361,   97,   98,   88,  983,  983,
    ++ /*   360 */   859,  862,  851,  851,   95,   95,   96,   96,   96,   96,
    ++ /*   370 */   769,  460,  120,  226,  226,  366,  962,  963,  964, 1089,
    ++ /*   380 */   990,  900,  990,  335, 1057,  425,  421,  839,  759,  759,
    ++ /*   390 */   425,  427,   50,   50,  432,  381,   94,   94,   94,   94,
    ++ /*   400 */    93,   93,   92,   92,   92,   91,  361,   97,   98,   88,
    ++ /*   410 */   983,  983,  859,  862,  851,  851,   95,   95,   96,   96,
    ++ /*   420 */    96,   96,  460,  259,  460,  120,  117,  354,  942, 1332,
    ++ /*   430 */   942, 1333, 1332,  278, 1333,  335,  680,  681,  682,  825,
    ++ /*   440 */   201,  176,  303,   50,   50,   49,   49,  404,   94,   94,
    ++ /*   450 */    94,   94,   93,   93,   92,   92,   92,   91,  361,   97,
    ++ /*   460 */    98,   88,  983,  983,  859,  862,  851,  851,   95,   95,
    ++ /*   470 */    96,   96,   96,   96,  199,  460,  380,  265,  433,  380,
    ++ /*   480 */   265,  383,  256,  158,  258,  319, 1003,  335,  155,  940,
    ++ /*   490 */   177,  940,  273,  379,  276,  322,   34,   34,  302,  962,
    ++ /*   500 */    94,   94,   94,   94,   93,   93,   92,   92,   92,   91,
    ++ /*   510 */   361,   97,   98,   88,  983,  983,  859,  862,  851,  851,
    ++ /*   520 */    95,   95,   96,   96,   96,   96,  905,  905,  397,  460,
    ++ /*   530 */   301,  158,  101,  319,  941,  340,  962,  963,  964,  313,
    ++ /*   540 */   283,  449,  335,  327,  146, 1266, 1004,  257,  234,  248,
    ++ /*   550 */    35,   35,   94,   94,   94,   94,   93,   93,   92,   92,
    ++ /*   560 */    92,   91,  361,  709,  785, 1227,   97,   98,   88,  983,
    ++ /*   570 */   983,  859,  862,  851,  851,   95,   95,   96,   96,   96,
    ++ /*   580 */    96,  962, 1227, 1229,  245,  422,  838,  198,  197,  196,
    ++ /*   590 */  1079, 1079, 1077, 1077, 1004, 1334,  320,  335,  172,  171,
    ++ /*   600 */   709,  831,  159,  271,  271,  830,   76,   94,   94,   94,
    ++ /*   610 */    94,   93,   93,   92,   92,   92,   91,  361,  962,  963,
    ++ /*   620 */   964,   97,   98,   88,  983,  983,  859,  862,  851,  851,
    ++ /*   630 */    95,   95,   96,   96,   96,   96,  830,  830,  832, 1157,
    ++ /*   640 */  1157,  199, 1157,  173, 1227,  231,  232, 1282,    2,  335,
    ++ /*   650 */   271,  764,  271,  820,  271,  271,  763,  389,  389,  389,
    ++ /*   660 */   132,   79,   94,   94,   94,   94,   93,   93,   92,   92,
    ++ /*   670 */    92,   91,  361,   97,   98,   88,  983,  983,  859,  862,
    ++ /*   680 */   851,  851,   95,   95,   96,   96,   96,   96,  460,  264,
    ++ /*   690 */   223,  460, 1257,  783, 1223, 1157, 1086, 1082,   80,  271,
    ++ /*   700 */    78,  335,  340, 1031,  341,  344,  345,  902,  346,   10,
    ++ /*   710 */    10,  902,   25,   25,   94,   94,   94,   94,   93,   93,
    ++ /*   720 */    92,   92,   92,   91,  361,   97,   86,   88,  983,  983,
    ++ /*   730 */   859,  862,  851,  851,   95,   95,   96,   96,   96,   96,
    ++ /*   740 */  1157,  270,  395,  117,  233,  263,  235,   70,  456,  341,
    ++ /*   750 */   225,  176,  335, 1305,  342,  133,  736,  966,  980,  249,
    ++ /*   760 */  1150,  396,  325, 1085, 1028,  178,   94,   94,   94,   94,
    ++ /*   770 */    93,   93,   92,   92,   92,   91,  361,   98,   88,  983,
    ++ /*   780 */   983,  859,  862,  851,  851,   95,   95,   96,   96,   96,
    ++ /*   790 */    96,  783,  783,  132,  120,  966,  120,  120,  120,  798,
    ++ /*   800 */   252,  937,  335,  353,  321,  429,  355,  799,  822,  692,
    ++ /*   810 */   390,  203,  446,  450,  372,  716,  454,   94,   94,   94,
    ++ /*   820 */    94,   93,   93,   92,   92,   92,   91,  361,   88,  983,
    ++ /*   830 */   983,  859,  862,  851,  851,   95,   95,   96,   96,   96,
    ++ /*   840 */    96,   84,  455, 1225,    3, 1209,  120,  120,  382,  387,
    ++ /*   850 */   120,  203, 1271,  716,  384,  168,  266,  203,  458,   72,
    ++ /*   860 */   260, 1246,   84,  455,  178,    3,  378,   94,   94,   94,
    ++ /*   870 */    94,   93,   93,   92,   92,   92,   91,  361,  350,  458,
    ++ /*   880 */  1245,  362,  430,  213,  228,  290,  415,  285,  414,  200,
    ++ /*   890 */   783,  882,  444,  726,  725,  405,  283,  921,  209,  921,
    ++ /*   900 */   281,  132,  362,   72,  838,  289,  147,  733,  734,  392,
    ++ /*   910 */    81,   82,  922,  444,  922,  267,  288,   83,  362,  462,
    ++ /*   920 */   461,  272,  132,  830,   23,  838,  388,  923, 1216,  923,
    ++ /*   930 */  1056,   81,   82,   84,  455,  899,    3,  899,   83,  362,
    ++ /*   940 */   462,  461,  761,  962,  830,   75,    1,  443,  275,  747,
    ++ /*   950 */   458,    5,  962,  204,  830,  830,  832,  833,   18,  748,
    ++ /*   960 */   229,  962,  277,   19,  153,  317,  317,  316,  216,  314,
    ++ /*   970 */   279,  460,  689,  362, 1055,  830,  830,  832,  833,   18,
    ++ /*   980 */   962,  963,  964,  962,  444,  181,  460,  251,  981,  962,
    ++ /*   990 */   963,  964,    8,    8,   20,  250,  838, 1070,  962,  963,
    ++ /*  1000 */   964,  417,   81,   82,  768,  204,  347,   36,   36,   83,
    ++ /*  1010 */   362,  462,  461, 1054,  284,  830,   84,  455, 1123,    3,
    ++ /*  1020 */   962,  963,  964,  460,  183,  962,  981,  764,  889, 1107,
    ++ /*  1030 */   460,  184,  763,  458,  132,  182,   74,  455,  460,    3,
    ++ /*  1040 */   981,  898,  834,  898,    8,    8,  830,  830,  832,  833,
    ++ /*  1050 */    18,    8,    8,  458,  219, 1156,  362, 1103,  349,    8,
    ++ /*  1060 */     8,  240,  962,  963,  964,  236,  889,  444,  792,  336,
    ++ /*  1070 */   158,  203,  885,  435,  700,  209,  362,  114,  981,  838,
    ++ /*  1080 */   834,  227,  334, 1114,  441,   81,   82,  444,  442,  305,
    ++ /*  1090 */   784,  306,   83,  362,  462,  461,  369, 1162,  830,  838,
    ++ /*  1100 */   460, 1037,  237, 1030,  237,   81,   82,    7,   96,   96,
    ++ /*  1110 */    96,   96,   83,  362,  462,  461, 1019, 1018,  830, 1020,
    ++ /*  1120 */  1289,   37,   37,  400,   96,   96,   96,   96,   89,  830,
    ++ /*  1130 */   830,  832,  833,   18, 1100,  318,  962,  292,   94,   94,
    ++ /*  1140 */    94,   94,   93,   93,   92,   92,   92,   91,  361,  830,
    ++ /*  1150 */   830,  832,  833,   18,   94,   94,   94,   94,   93,   93,
    ++ /*  1160 */    92,   92,   92,   91,  361,  359,  358,  226,  226,  727,
    ++ /*  1170 */   294,  296,  460,  962,  963,  964,  460,  989,  160,  425,
    ++ /*  1180 */   170, 1295,  262,  460,  987,  374,  988,  386, 1145,  255,
    ++ /*  1190 */   326,  460,  373,   38,   38,  410,  174,   39,   39,  413,
    ++ /*  1200 */   460,  287,  460, 1053,   40,   40,  298,  728, 1220,  990,
    ++ /*  1210 */   445,  990,   26,   26, 1219,  460,  311,  460,  169, 1292,
    ++ /*  1220 */   460,   27,   27,   29,   29,  998,  460,  206,  135,  995,
    ++ /*  1230 */  1265, 1263,  460,   57,   60,  460,   41,   41,   42,   42,
    ++ /*  1240 */   460,   43,   43,  460,  343,  351,  460,    9,    9,  460,
    ++ /*  1250 */   144,  460,  130,   44,   44,  460,  103,  103,  460,  137,
    ++ /*  1260 */    70,   45,   45,  460,   46,   46,  460,   31,   31, 1142,
    ++ /*  1270 */    47,   47,   48,   48,  460,  376,   32,   32,  460,  122,
    ++ /*  1280 */   122,  460,  157,  460,  123,  123,  139,  124,  124,  460,
    ++ /*  1290 */   186,  460,  377,  460,  115,   54,   54,  460,  403,   33,
    ++ /*  1300 */    33,  460,  104,  104,   51,   51,  460,  161,  460,  140,
    ++ /*  1310 */   105,  105,  106,  106,  102,  102,  460,  141,  121,  121,
    ++ /*  1320 */   460,  142,  119,  119,  190,  460, 1152,  110,  110,  109,
    ++ /*  1330 */   109,  702,  460,  148,  393,   65,  460,  107,  107,  460,
    ++ /*  1340 */   323,  108,  108,  399,  460, 1234,   53,   53, 1214,  269,
    ++ /*  1350 */   154,  416, 1115,   55,   55,  220,  401,   52,   52,  191,
    ++ /*  1360 */    24,   24,  274,  192,  193,   28,   28, 1021,  328,  702,
    ++ /*  1370 */  1073,  352, 1072,  718, 1071,  431, 1111, 1064,  329, 1045,
    ++ /*  1380 */    69,  205,    6,  291, 1044,  286, 1112, 1043, 1304, 1110,
    ++ /*  1390 */   293,  300,  295,  297, 1063, 1200, 1109,   77,  241,  448,
    ++ /*  1400 */   356,  452,  436,  100,  214,   71,  434, 1027, 1093,   21,
    ++ /*  1410 */   463,  242,  243,  957,  215,  217,  218,  464,  309,  307,
    ++ /*  1420 */   308,  310, 1016,  125, 1250, 1251, 1011, 1249,  126,  127,
    ++ /*  1430 */  1248,  113,  676,  337,  238,  338,  134,  363,  167, 1041,
    ++ /*  1440 */  1040,   56,  247,  367,  180,  897,  111,  895,  136, 1038,
    ++ /*  1450 */   818,  128,  138,  750,  261,  911,  185,  143,  145,   61,
    ++ /*  1460 */    62,   63,   64,  129,  914,  187,  188,  910,  118,   12,
    ++ /*  1470 */   189,  903,  268,  992,  203,  162,  398,  150,  149,  691,
    ++ /*  1480 */   402,  288,  194,  406,  151,  411,   66,   13,  729,  239,
    ++ /*  1490 */   282,   14,   67,  131,  837,  836,  865,  758,   15,    4,
    ++ /*  1500 */    68,  762,  175,  222,  224,  424,  152,  869,  791,  202,
    ++ /*  1510 */   786,   75,   72,  880,  866,  864,   16,   17,  920,  207,
    ++ /*  1520 */   919,  208,  447,  946,  164,  211,  947,  210,  165,  451,
    ++ /*  1530 */   868,  166,  315,  835,  701,   85,  212, 1297,  312,  952,
    ++ /*  1540 */  1296,
    + };
    + static const YYCODETYPE yy_lookahead[] = {
    +- /*     0 */    19,  144,  145,  146,  147,   24,    1,    2,   27,   80,
    +- /*    10 */    81,   82,   83,   84,   85,   86,   87,   88,   89,   90,
    +- /*    20 */    91,   92,   93,   94,   95,   91,   92,   93,   94,   95,
    +- /*    30 */    19,   50,   51,   80,   81,   82,   83,  212,   85,   86,
    +- /*    40 */    87,   88,   89,   90,   91,   92,   93,   94,   95,  224,
    +- /*    50 */   225,  226,   71,   72,   73,   74,   75,   76,   77,   78,
    +- /*    60 */    79,   80,   81,   82,   83,   95,   85,   86,   87,   88,
    +- /*    70 */    89,   90,   91,   92,   93,   94,   95,   19,   97,   85,
    +- /*    80 */    86,   87,   88,   89,   90,   91,   92,   93,   94,   95,
    +- /*    90 */    66,   33,   27,   28,   27,   28,   22,  201,  152,  152,
    +- /*   100 */    42,   27,  152,  224,  225,  226,   95,  211,   50,   51,
    +- /*   110 */    99,  100,  101,  102,  103,  104,  105,   27,   28,   59,
    +- /*   120 */   174,  175,  243,  112,  174,  175,   66,   94,   95,   71,
    +- /*   130 */    72,   73,   74,   75,   76,   77,   78,   79,   80,   81,
    +- /*   140 */    82,   83,  195,   85,   86,   87,   88,   89,   90,   91,
    +- /*   150 */    92,   93,   94,   95,   19,  209,   89,   90,  173,  209,
    +- /*   160 */   210,   26,   97,   98,   97,   98,  181,  100,  108,  109,
    +- /*   170 */   110,   97,  174,  152,  107,  152,  109,   89,   90,   91,
    +- /*   180 */    92,   93,   94,   95,  163,   50,   51,   97,   98,   99,
    +- /*   190 */    55,  244,  102,  103,  104,  174,  175,  174,  175,  132,
    +- /*   200 */   133,   89,   90,  113,   66,   19,   71,   72,   73,   74,
    +- /*   210 */    75,   76,   77,   78,   79,   80,   81,   82,   83,  198,
    +- /*   220 */    85,   86,   87,   88,   89,   90,   91,   92,   93,   94,
    +- /*   230 */    95,  152,  209,  210,  148,  149,   50,   51,  100,   53,
    +- /*   240 */   154,   59,  156,   22,  132,  133,  119,  120,  163,  163,
    +- /*   250 */    22,  192,  193,  174,  175,   27,   28,   71,   72,   73,
    +- /*   260 */    74,   75,   76,   77,   78,   79,   80,   81,   82,   83,
    +- /*   270 */   174,   85,   86,   87,   88,   89,   90,   91,   92,   93,
    +- /*   280 */    94,   95,   19,  198,  198,  174,  152,   24,  209,  210,
    +- /*   290 */   108,  109,  110,  192,  193,   27,   28,   69,  164,  165,
    +- /*   300 */    79,  119,  120,   27,   28,   27,   99,  222,  152,  102,
    +- /*   310 */   103,  104,   24,   50,   51,   27,   66,   89,   90,  185,
    +- /*   320 */   113,  187,   22,  157,  239,   97,   58,   27,   28,  101,
    +- /*   330 */   174,  175,  246,  163,   71,   72,   73,   74,   75,   76,
    +- /*   340 */    77,   78,   79,   80,   81,   82,   83,   11,   85,   86,
    +- /*   350 */    87,   88,   89,   90,   91,   92,   93,   94,   95,   19,
    +- /*   360 */   132,  133,  134,   23,  152,   97,   98,   91,  198,  119,
    +- /*   370 */   120,  152,   22,   97,   98,   97,  152,   27,   28,   27,
    +- /*   380 */    28,   27,   28,  227,  160,   97,  174,  175,  164,  165,
    +- /*   390 */    50,   51,  222,  174,  175,   59,  230,   97,   98,  233,
    +- /*   400 */   188,  137,   66,  139,  234,  187,  177,  188,  152,  239,
    +- /*   410 */    69,   71,   72,   73,   74,   75,   76,   77,   78,   79,
    +- /*   420 */    80,   81,   82,   83,   12,   85,   86,   87,   88,   89,
    +- /*   430 */    90,   91,   92,   93,   94,   95,   19,  177,   97,  152,
    +- /*   440 */    23,   29,  101,  152,  108,  109,  110,   97,   98,   97,
    +- /*   450 */    98,   97,   98,  224,  225,  226,   22,   45,   24,   47,
    +- /*   460 */   152,  152,  152,  152,  152,  174,  175,   50,   51,  249,
    +- /*   470 */   250,   59,   21,  132,  133,  134,  124,  221,  124,  188,
    +- /*   480 */   171,  172,  171,  172,  224,  225,  226,  152,   71,   72,
    +- /*   490 */    73,   74,   75,   76,   77,   78,   79,   80,   81,   82,
    +- /*   500 */    83,  152,   85,   86,   87,   88,   89,   90,   91,   92,
    +- /*   510 */    93,   94,   95,   19,  152,  183,   65,   23,  170,  171,
    +- /*   520 */   172,   19,   23,  174,  175,   26,  152,   50,   51,   12,
    +- /*   530 */   196,  197,   37,  170,  171,  172,  174,  175,  224,  225,
    +- /*   540 */   226,  232,  208,  232,   50,   51,   29,   52,  174,  175,
    +- /*   550 */   188,   74,   75,   51,  103,   60,  222,  163,  209,    0,
    +- /*   560 */     1,    2,   45,  152,   47,   71,   72,   73,   74,   75,
    +- /*   570 */    76,   77,   78,   79,   80,   81,   82,   83,  101,   85,
    +- /*   580 */    86,   87,   88,   89,   90,   91,   92,   93,   94,   95,
    +- /*   590 */    19,  140,  198,  152,   23,  152,   22,   98,   24,  152,
    +- /*   600 */   152,   27,  152,  183,  152,  152,  111,  213,  214,  107,
    +- /*   610 */   152,  164,  165,  152,  112,  174,  175,  174,  175,  181,
    +- /*   620 */   182,   50,   51,  124,  174,  175,  174,  175,  190,   26,
    +- /*   630 */    22,   23,   22,   23,   26,  166,   26,  168,  169,   16,
    +- /*   640 */    16,   19,   71,   72,   73,   74,   75,   76,   77,   78,
    +- /*   650 */    79,   80,   81,   82,   83,  152,   85,   86,   87,   88,
    +- /*   660 */    89,   90,   91,   92,   93,   94,   95,  152,  220,  196,
    +- /*   670 */   197,   97,   50,   51,  108,  109,  110,  152,   70,  221,
    +- /*   680 */    70,  208,    7,    8,    9,   62,   62,   64,   64,  174,
    +- /*   690 */   175,  146,  147,   71,   72,   73,   74,   75,   76,   77,
    +- /*   700 */    78,   79,   80,   81,   82,   83,  152,   85,   86,   87,
    +- /*   710 */    88,   89,   90,   91,   92,   93,   94,   95,   19,  152,
    +- /*   720 */   195,  152,   31,  220,  152,  152,   35,   26,  174,  175,
    +- /*   730 */   152,  163,  152,  130,  152,  115,  152,  117,  118,  152,
    +- /*   740 */    49,  174,  175,  174,  175,  152,  174,  175,   26,   50,
    +- /*   750 */    51,  152,  174,  175,  174,  175,  174,  175,  174,  175,
    +- /*   760 */   138,  174,  175,  140,   22,   23,  198,  174,  175,  152,
    +- /*   770 */    71,   72,   73,   74,   75,   76,   77,   78,   79,   80,
    +- /*   780 */    81,   82,   83,  152,   85,   86,   87,   88,   89,   90,
    +- /*   790 */    91,   92,   93,   94,   95,   19,  152,  152,  152,   98,
    +- /*   800 */    24,  152,  108,  109,  110,  174,  175,  152,  152,  152,
    +- /*   810 */   152,  152,   70,  152,  213,  214,  152,  152,  174,  175,
    +- /*   820 */   174,  175,  152,  174,  175,  124,   50,   51,  106,  174,
    +- /*   830 */   175,  174,  175,  174,  175,  174,  175,  138,  174,  175,
    +- /*   840 */   152,   22,   23,   22,  163,  189,   19,   71,   72,   73,
    +- /*   850 */    74,   75,   76,   77,   78,   79,   80,   81,   82,   83,
    +- /*   860 */   152,   85,   86,   87,   88,   89,   90,   91,   92,   93,
    +- /*   870 */    94,   95,  152,  152,  168,  169,  152,   50,   51,  198,
    +- /*   880 */   197,  152,  174,  175,  152,  240,  152,  152,  152,   70,
    +- /*   890 */   152,  208,  152,  152,  174,  175,  152,   19,   71,   72,
    +- /*   900 */    73,   74,   75,   76,   77,   78,   79,   80,   81,   82,
    +- /*   910 */    83,  152,   85,   86,   87,   88,   89,   90,   91,   92,
    +- /*   920 */    93,   94,   95,  152,  195,  247,  248,  152,   50,   51,
    +- /*   930 */   195,  195,  152,  174,  175,  195,  195,   26,  152,  195,
    +- /*   940 */   252,  220,  163,  122,  152,  174,  175,  163,   19,   71,
    +- /*   950 */    72,   73,   74,   75,   76,   77,   78,   79,   80,   81,
    +- /*   960 */    82,   83,  152,   85,   86,   87,   88,   89,   90,   91,
    +- /*   970 */    92,   93,   94,   95,  152,  195,  252,  198,  240,   50,
    +- /*   980 */    51,  189,  198,   19,  174,  175,   19,   51,   23,  100,
    +- /*   990 */   101,   26,   28,  163,  163,   28,  174,  175,  163,   19,
    +- /*  1000 */   152,   72,   73,   74,   75,   76,   77,   78,   79,   80,
    +- /*  1010 */    81,   82,   83,  152,   85,   86,   87,   88,   89,   90,
    +- /*  1020 */    91,   92,   93,   94,   95,  152,  240,  152,  198,  198,
    +- /*  1030 */    50,   51,   33,  198,  123,  174,  175,  116,    7,    8,
    +- /*  1040 */   101,   42,  121,  107,  152,  152,   23,  174,  175,   26,
    +- /*  1050 */   152,  112,  183,   73,   74,   75,   76,   77,   78,   79,
    +- /*  1060 */    80,   81,   82,   83,  152,   85,   86,   87,   88,   89,
    +- /*  1070 */    90,   91,   92,   93,   94,   95,   19,   20,   23,   22,
    +- /*  1080 */    23,   26,  152,  152,   27,   28,  174,  175,   23,   19,
    +- /*  1090 */    20,   26,   22,  132,  133,   38,  152,   27,   28,  152,
    +- /*  1100 */    23,  215,  152,   26,  174,  175,  152,   27,   38,  152,
    +- /*  1110 */    23,  152,   27,   26,   57,  152,   23,  163,  152,   26,
    +- /*  1120 */   152,  174,  175,   66,  174,  175,   69,   57,  174,  175,
    +- /*  1130 */    27,  174,  175,  174,  175,  152,   66,  174,  175,   69,
    +- /*  1140 */   174,  175,  174,  175,  152,   23,   89,   90,   26,   91,
    +- /*  1150 */   152,  236,  198,   96,   97,   98,  132,  133,  101,   89,
    +- /*  1160 */    90,  152,   23,  209,  210,   26,   96,   97,   98,  152,
    +- /*  1170 */   212,  101,  174,  175,  116,   19,   20,   97,   22,  121,
    +- /*  1180 */   152,  193,   97,   27,   28,  152,  152,  152,  152,  132,
    +- /*  1190 */   133,  134,  135,  136,   38,   23,  152,  152,   26,  152,
    +- /*  1200 */    97,  152,  132,  133,  134,  135,  136,  235,  152,  212,
    +- /*  1210 */   199,  150,  212,   57,  212,  200,  203,  216,  241,  216,
    +- /*  1220 */   241,  203,  182,   19,   20,   69,   22,  186,  178,  177,
    +- /*  1230 */   216,   27,   28,  229,  202,   39,  177,  177,  200,  155,
    +- /*  1240 */   245,  122,   38,   41,   22,   89,   90,   91,  159,  159,
    +- /*  1250 */   242,  159,   96,   97,   98,   71,  130,  101,  242,  191,
    +- /*  1260 */   223,   57,   18,  194,  159,  203,  194,  194,  194,   18,
    +- /*  1270 */   158,  223,  191,   69,  203,  159,  158,   19,   20,  191,
    +- /*  1280 */    22,  203,  137,   46,  238,   27,   28,  159,  132,  133,
    +- /*  1290 */   134,  135,  136,   89,   90,  159,   38,   22,  158,  179,
    +- /*  1300 */    96,   97,   98,  237,  158,  101,  159,  159,  158,  179,
    +- /*  1310 */   107,  176,   48,  176,  176,   57,  184,  106,  176,  125,
    +- /*  1320 */   179,  178,  218,  107,  217,  176,  218,   69,  184,  176,
    +- /*  1330 */   176,  217,  159,  218,  217,  159,  132,  133,  134,  135,
    +- /*  1340 */   136,  218,  217,  137,  179,   95,  179,   89,   90,  228,
    +- /*  1350 */   129,  126,  128,  127,   96,   97,   98,  206,  231,  101,
    +- /*  1360 */     5,   25,  231,  205,  207,   10,   11,   12,   13,   14,
    +- /*  1370 */   204,  203,   17,   26,  162,  161,   13,    6,  180,  180,
    +- /*  1380 */   153,  153,  151,  151,  151,  151,  167,   32,    4,   34,
    +- /*  1390 */   132,  133,  134,  135,  136,    3,   22,  142,   43,   68,
    +- /*  1400 */    15,   23,   16,  251,   23,  120,  251,  248,  131,  111,
    +- /*  1410 */   123,   56,   16,   20,  125,    1,  123,  131,   63,   79,
    +- /*  1420 */    79,   66,   67,  111,   36,   28,  122,    1,    5,   22,
    +- /*  1430 */   107,  140,   26,   54,   54,   44,   61,  107,   20,   24,
    +- /*  1440 */    19,  112,  105,   53,   22,   40,   22,   22,   53,   30,
    +- /*  1450 */    23,   22,   22,   53,   23,   23,   23,   22,  116,   23,
    +- /*  1460 */    22,  122,   23,   26,   23,   22,   11,  124,   28,  114,
    +- /*  1470 */    36,   26,   26,   23,   23,   23,  122,   23,   36,   26,
    +- /*  1480 */    36,   22,   24,   23,   22,    1,   23,   26,   22,   24,
    +- /*  1490 */    23,   22,  122,   23,   23,   22,  141,   23,  122,  122,
    +- /*  1500 */    15,
    ++ /*     0 */   144,  145,  146,  147,  172,  222,  223,  224,  222,  223,
    ++ /*    10 */   224,  152,  180,  152,  148,  149,  152,  173,  176,   19,
    ++ /*    20 */   154,  173,  156,  152,  163,  242,  152,  163,  176,  163,
    ++ /*    30 */    26,   31,  173,  174,  173,  174,  173,  173,  174,   39,
    ++ /*    40 */     1,    2,  152,   43,   44,   45,   46,   47,   48,   49,
    ++ /*    50 */    50,   51,   52,   53,   54,   55,   56,   57,  197,  169,
    ++ /*    60 */   170,  197,  188,  197,  222,  223,  224,  208,  209,  208,
    ++ /*    70 */   209,   19,  208,  152,  222,  223,  224,   22,   26,   24,
    ++ /*    80 */    46,   47,   48,   49,   84,   85,   86,   87,   88,   89,
    ++ /*    90 */    90,   91,   92,   93,   94,   43,   44,   45,   46,   47,
    ++ /*   100 */    48,   49,   50,   51,   52,   53,   54,   55,   56,   57,
    ++ /*   110 */   106,  245,  157,   88,   89,   90,   91,   92,   93,   94,
    ++ /*   120 */    68,  231,  251,   19,   84,   85,   86,   87,   88,   89,
    ++ /*   130 */    90,   91,   92,   93,   94,  101,   84,   85,   86,   87,
    ++ /*   140 */    88,   89,   90,   91,   92,   93,   94,   43,   44,   45,
    ++ /*   150 */    46,   47,   48,   49,   50,   51,   52,   53,   54,   55,
    ++ /*   160 */    56,   57,   90,   91,   92,   93,   94,   82,   79,   99,
    ++ /*   170 */    66,  200,  102,  103,  104,   19,  168,  169,  170,  152,
    ++ /*   180 */    24,  210,   97,  113,  229,   59,  101,  232,   84,   85,
    ++ /*   190 */    86,   87,   88,   89,   90,   91,   92,   93,   94,   43,
    ++ /*   200 */    44,   45,   46,   47,   48,   49,   50,   51,   52,   53,
    ++ /*   210 */    54,   55,   56,   57,  152,  188,  152,  132,  133,  134,
    ++ /*   220 */    93,   94,   96,   97,   98,   99,  152,   19,  102,  103,
    ++ /*   230 */   104,   23,   94,   72,   79,  173,  174,  173,  174,  113,
    ++ /*   240 */    84,   85,   86,   87,   88,   89,   90,   91,   92,   93,
    ++ /*   250 */    94,   43,   44,   45,   46,   47,   48,   49,   50,   51,
    ++ /*   260 */    52,   53,   54,   55,   56,   57,  152,  171,  152,  108,
    ++ /*   270 */   109,  110,  208,  209,  119,  120,  152,  180,  181,   19,
    ++ /*   280 */   119,  120,  152,   23,  152,  152,  189,  173,  174,  173,
    ++ /*   290 */   174,   59,   84,   85,   86,   87,   88,   89,   90,   91,
    ++ /*   300 */    92,   93,   94,   43,   44,   45,   46,   47,   48,   49,
    ++ /*   310 */    50,   51,   52,   53,   54,   55,   56,   57,  222,  223,
    ++ /*   320 */   224,  186,  208,  209,  208,  209,  194,  194,   96,   97,
    ++ /*   330 */    98,   19,  168,  169,  170,   23,   88,   89,  163,   59,
    ++ /*   340 */     0,    1,    2,  219,   84,   85,   86,   87,   88,   89,
    ++ /*   350 */    90,   91,   92,   93,   94,   43,   44,   45,   46,   47,
    ++ /*   360 */    48,   49,   50,   51,   52,   53,   54,   55,   56,   57,
    ++ /*   370 */    90,  152,  197,  195,  196,  243,   96,   97,   98,  196,
    ++ /*   380 */   132,   11,  134,   19,  182,  207,  115,   23,  117,  118,
    ++ /*   390 */   207,  163,  173,  174,  152,  220,   84,   85,   86,   87,
    ++ /*   400 */    88,   89,   90,   91,   92,   93,   94,   43,   44,   45,
    ++ /*   410 */    46,   47,   48,   49,   50,   51,   52,   53,   54,   55,
    ++ /*   420 */    56,   57,  152,   16,  152,  197,  171,  208,   22,   23,
    ++ /*   430 */    22,   23,   26,   16,   26,   19,    7,    8,    9,   23,
    ++ /*   440 */   212,  213,  152,  173,  174,  173,  174,   19,   84,   85,
    ++ /*   450 */    86,   87,   88,   89,   90,   91,   92,   93,   94,   43,
    ++ /*   460 */    44,   45,   46,   47,   48,   49,   50,   51,   52,   53,
    ++ /*   470 */    54,   55,   56,   57,   46,  152,  109,  110,  208,  109,
    ++ /*   480 */   110,  152,   75,  152,   77,   22,   23,   19,  233,   83,
    ++ /*   490 */   152,   83,   75,  238,   77,  164,  173,  174,  226,   59,
    ++ /*   500 */    84,   85,   86,   87,   88,   89,   90,   91,   92,   93,
    ++ /*   510 */    94,   43,   44,   45,   46,   47,   48,   49,   50,   51,
    ++ /*   520 */    52,   53,   54,   55,   56,   57,  108,  109,  110,  152,
    ++ /*   530 */   152,  152,   22,   22,   23,  107,   96,   97,   98,  160,
    ++ /*   540 */   112,  251,   19,  164,   22,  152,   83,  140,  219,  152,
    ++ /*   550 */   173,  174,   84,   85,   86,   87,   88,   89,   90,   91,
    ++ /*   560 */    92,   93,   94,   59,  124,  152,   43,   44,   45,   46,
    ++ /*   570 */    47,   48,   49,   50,   51,   52,   53,   54,   55,   56,
    ++ /*   580 */    57,   59,  169,  170,  119,  120,   82,  108,  109,  110,
    ++ /*   590 */   191,  192,  191,  192,   83,  248,  249,   19,   88,   89,
    ++ /*   600 */    96,   97,   24,  152,  152,  101,  138,   84,   85,   86,
    ++ /*   610 */    87,   88,   89,   90,   91,   92,   93,   94,   96,   97,
    ++ /*   620 */    98,   43,   44,   45,   46,   47,   48,   49,   50,   51,
    ++ /*   630 */    52,   53,   54,   55,   56,   57,  132,  133,  134,  152,
    ++ /*   640 */   152,   46,  152,   26,  231,  194,  194,  146,  147,   19,
    ++ /*   650 */   152,  116,  152,   72,  152,  152,  121,  152,  152,  152,
    ++ /*   660 */    79,  138,   84,   85,   86,   87,   88,   89,   90,   91,
    ++ /*   670 */    92,   93,   94,   43,   44,   45,   46,   47,   48,   49,
    ++ /*   680 */    50,   51,   52,   53,   54,   55,   56,   57,  152,  108,
    ++ /*   690 */    23,  152,  194,   26,  194,  152,  194,  194,  137,  152,
    ++ /*   700 */   139,   19,  107,  166,  167,  218,  218,   29,  218,  173,
    ++ /*   710 */   174,   33,  173,  174,   84,   85,   86,   87,   88,   89,
    ++ /*   720 */    90,   91,   92,   93,   94,   43,   44,   45,   46,   47,
    ++ /*   730 */    48,   49,   50,   51,   52,   53,   54,   55,   56,   57,
    ++ /*   740 */   152,  194,   64,  171,  239,  239,  239,  130,  166,  167,
    ++ /*   750 */   212,  213,   19,   23,  246,  247,   26,   59,   26,  152,
    ++ /*   760 */   163,  218,  163,  163,  163,   98,   84,   85,   86,   87,
    ++ /*   770 */    88,   89,   90,   91,   92,   93,   94,   44,   45,   46,
    ++ /*   780 */    47,   48,   49,   50,   51,   52,   53,   54,   55,   56,
    ++ /*   790 */    57,  124,   26,   79,  197,   97,  197,  197,  197,   31,
    ++ /*   800 */   152,   23,   19,   19,   26,   19,  218,   39,   23,   21,
    ++ /*   810 */   238,   26,  163,  163,  100,   59,  163,   84,   85,   86,
    ++ /*   820 */    87,   88,   89,   90,   91,   92,   93,   94,   45,   46,
    ++ /*   830 */    47,   48,   49,   50,   51,   52,   53,   54,   55,   56,
    ++ /*   840 */    57,   19,   20,  152,   22,   23,  197,  197,   23,   19,
    ++ /*   850 */   197,   26,  152,   97,   23,  123,   23,   26,   36,   26,
    ++ /*   860 */   152,  152,   19,   20,   98,   22,   78,   84,   85,   86,
    ++ /*   870 */    87,   88,   89,   90,   91,   92,   93,   94,   94,   36,
    ++ /*   880 */   152,   59,   96,   99,  100,  101,  102,  103,  104,  105,
    ++ /*   890 */   124,  103,   70,  100,  101,   23,  112,   12,   26,   12,
    ++ /*   900 */    23,   79,   59,   26,   82,  101,   22,    7,    8,  152,
    ++ /*   910 */    88,   89,   27,   70,   27,  152,  112,   95,   96,   97,
    ++ /*   920 */    98,  152,   79,  101,   22,   82,   96,   42,  140,   42,
    ++ /*   930 */   182,   88,   89,   19,   20,  132,   22,  134,   95,   96,
    ++ /*   940 */    97,   98,   23,   59,  101,   26,   22,   62,  152,   62,
    ++ /*   950 */    36,   22,   59,   24,  132,  133,  134,  135,  136,   72,
    ++ /*   960 */     5,   59,  152,   22,   71,   10,   11,   12,   13,   14,
    ++ /*   970 */   152,  152,   17,   59,  182,  132,  133,  134,  135,  136,
    ++ /*   980 */    96,   97,   98,   59,   70,   30,  152,   32,   59,   96,
    ++ /*   990 */    97,   98,  173,  174,   53,   40,   82,  152,   96,   97,
    ++ /*  1000 */    98,   90,   88,   89,   90,   24,  187,  173,  174,   95,
    ++ /*  1010 */    96,   97,   98,  152,  152,  101,   19,   20,  152,   22,
    ++ /*  1020 */    96,   97,   98,  152,   69,   59,   97,  116,   59,  214,
    ++ /*  1030 */   152,   76,  121,   36,   79,   80,   19,   20,  152,   22,
    ++ /*  1040 */    59,  132,   59,  134,  173,  174,  132,  133,  134,  135,
    ++ /*  1050 */   136,  173,  174,   36,  234,  152,   59,  152,  187,  173,
    ++ /*  1060 */   174,  211,   96,   97,   98,  187,   97,   70,   23,  114,
    ++ /*  1070 */   152,   26,   23,  187,   23,   26,   59,   26,   97,   82,
    ++ /*  1080 */    97,   22,  164,  152,  152,   88,   89,   70,  192,  152,
    ++ /*  1090 */   124,  152,   95,   96,   97,   98,  141,  152,  101,   82,
    ++ /*  1100 */   152,  152,  184,  152,  186,   88,   89,  199,   54,   55,
    ++ /*  1110 */    56,   57,   95,   96,   97,   98,  152,  152,  101,  152,
    ++ /*  1120 */   152,  173,  174,  235,   54,   55,   56,   57,   58,  132,
    ++ /*  1130 */   133,  134,  135,  136,  211,  150,   59,  211,   84,   85,
    ++ /*  1140 */    86,   87,   88,   89,   90,   91,   92,   93,   94,  132,
    ++ /*  1150 */   133,  134,  135,  136,   84,   85,   86,   87,   88,   89,
    ++ /*  1160 */    90,   91,   92,   93,   94,   88,   89,  195,  196,   35,
    ++ /*  1170 */   211,  211,  152,   96,   97,   98,  152,  100,  198,  207,
    ++ /*  1180 */   171,  122,  240,  152,  107,  215,  109,  240,  202,  215,
    ++ /*  1190 */   202,  152,  220,  173,  174,  177,  185,  173,  174,   65,
    ++ /*  1200 */   152,  176,  152,  181,  173,  174,  215,   73,  176,  132,
    ++ /*  1210 */   228,  134,  173,  174,  176,  152,  201,  152,  199,  155,
    ++ /*  1220 */   152,  173,  174,  173,  174,   60,  152,  122,  244,   38,
    ++ /*  1230 */   159,  159,  152,  241,  241,  152,  173,  174,  173,  174,
    ++ /*  1240 */   152,  173,  174,  152,  159,  111,  152,  173,  174,  152,
    ++ /*  1250 */    22,  152,   43,  173,  174,  152,  173,  174,  152,  190,
    ++ /*  1260 */   130,  173,  174,  152,  173,  174,  152,  173,  174,  202,
    ++ /*  1270 */   173,  174,  173,  174,  152,   18,  173,  174,  152,  173,
    ++ /*  1280 */   174,  152,  221,  152,  173,  174,  193,  173,  174,  152,
    ++ /*  1290 */   158,  152,  159,  152,   22,  173,  174,  152,   18,  173,
    ++ /*  1300 */   174,  152,  173,  174,  173,  174,  152,  221,  152,  193,
    ++ /*  1310 */   173,  174,  173,  174,  173,  174,  152,  193,  173,  174,
    ++ /*  1320 */   152,  193,  173,  174,  158,  152,  190,  173,  174,  173,
    ++ /*  1330 */   174,   59,  152,  190,  159,  137,  152,  173,  174,  152,
    ++ /*  1340 */   202,  173,  174,   61,  152,  237,  173,  174,  202,  236,
    ++ /*  1350 */    22,  107,  159,  173,  174,  159,  178,  173,  174,  158,
    ++ /*  1360 */   173,  174,  159,  158,  158,  173,  174,  159,  178,   97,
    ++ /*  1370 */   175,   63,  175,  106,  175,  125,  217,  183,  178,  175,
    ++ /*  1380 */   107,  159,   22,  216,  177,  175,  217,  175,  175,  217,
    ++ /*  1390 */   216,  159,  216,  216,  183,  225,  217,  137,  227,  178,
    ++ /*  1400 */    94,  178,  126,  129,   25,  128,  127,  162,  206,   26,
    ++ /*  1410 */   161,  230,  230,   13,  153,  153,    6,  151,  203,  205,
    ++ /*  1420 */   204,  202,  151,  165,  171,  171,  151,  171,  165,  165,
    ++ /*  1430 */   171,  179,    4,  250,  179,  250,  247,    3,   22,  171,
    ++ /*  1440 */   171,  171,  142,   81,   15,   23,   16,   23,  131,  171,
    ++ /*  1450 */   120,  111,  123,   20,   16,    1,  125,  123,  131,   53,
    ++ /*  1460 */    53,   53,   53,  111,   96,   34,  122,    1,    5,   22,
    ++ /*  1470 */   107,   67,  140,   74,   26,   24,   41,  107,   67,   20,
    ++ /*  1480 */    19,  112,  105,   66,   22,   66,   22,   22,   28,   66,
    ++ /*  1490 */    23,   22,   22,   37,   23,   23,   23,  116,   22,   22,
    ++ /*  1500 */    26,   23,  122,   23,   23,   26,   22,   11,   96,   34,
    ++ /*  1510 */   124,   26,   26,   23,   23,   23,   34,   34,   23,   26,
    ++ /*  1520 */    23,   22,   24,   23,   22,  122,   23,   26,   22,   24,
    ++ /*  1530 */    23,   22,   15,   23,   23,   22,  122,  122,   23,    1,
    ++ /*  1540 */   122,  252,  252,  252,  252,  252,  252,  252,  252,  252,
    ++ /*  1550 */   252,  252,  252,  252,  252,  252,  252,  252,  252,  252,
    ++ /*  1560 */   252,  252,  252,  252,  252,  252,  252,  252,  252,  252,
    ++ /*  1570 */   252,  252,  252,  252,  252,  252,  252,  252,  252,  252,
    ++ /*  1580 */   252,  252,  252,  252,  252,  252,  252,  252,  252,  252,
    ++ /*  1590 */   252,  252,  252,  252,  252,  252,  252,  252,  252,  252,
    ++ /*  1600 */   252,  252,  252,  252,  252,  252,  252,  252,  252,  252,
    ++ /*  1610 */   252,  252,  252,  252,  252,  252,  252,  252,  252,  252,
    ++ /*  1620 */   252,  252,  252,  252,  252,  252,  252,  252,  252,  252,
    ++ /*  1630 */   252,  252,  252,  252,  252,  252,  252,  252,  252,  252,
    ++ /*  1640 */   252,  252,  252,  252,  252,  252,  252,  252,  252,  252,
    ++ /*  1650 */   252,  252,  252,  252,  252,  252,  252,  252,  252,  252,
    ++ /*  1660 */   252,  252,  252,  252,  252,  252,  252,  252,  252,  252,
    ++ /*  1670 */   252,  252,  252,  252,  252,  252,  252,  252,  252,  252,
    ++ /*  1680 */   252,  252,  252,  252,
    + };
    +-#define YY_SHIFT_USE_DFLT (-72)
    +-#define YY_SHIFT_COUNT (435)
    +-#define YY_SHIFT_MIN   (-71)
    +-#define YY_SHIFT_MAX   (1485)
    +-static const short yy_shift_ofst[] = {
    +- /*     0 */     5, 1057, 1355, 1070, 1204, 1204, 1204,   90,   60,  -19,
    +- /*    10 */    58,   58,  186, 1204, 1204, 1204, 1204, 1204, 1204, 1204,
    +- /*    20 */    67,   67,  182,  336,   65,  250,  135,  263,  340,  417,
    +- /*    30 */   494,  571,  622,  699,  776,  827,  827,  827,  827,  827,
    +- /*    40 */   827,  827,  827,  827,  827,  827,  827,  827,  827,  827,
    +- /*    50 */   878,  827,  929,  980,  980, 1156, 1204, 1204, 1204, 1204,
    +- /*    60 */  1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204,
    +- /*    70 */  1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204,
    +- /*    80 */  1204, 1204, 1204, 1204, 1258, 1204, 1204, 1204, 1204, 1204,
    +- /*    90 */  1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204,  -71,  -47,
    +- /*   100 */   -47,  -47,  -47,  -47,   -6,   88,  -66,   65,   65,  451,
    +- /*   110 */   502,  112,  112,   33,  127,  278,  -30,  -72,  -72,  -72,
    +- /*   120 */    11,  412,  412,  268,  608,  610,   65,   65,   65,   65,
    +- /*   130 */    65,   65,   65,   65,   65,   65,   65,   65,   65,   65,
    +- /*   140 */    65,   65,   65,   65,   65,  559,  138,  278,  127,   24,
    +- /*   150 */    24,   24,   24,   24,   24,  -72,  -72,  -72,  228,  341,
    +- /*   160 */   341,  207,  276,  300,  352,  354,  350,   65,   65,   65,
    +- /*   170 */    65,   65,   65,   65,   65,   65,   65,   65,   65,   65,
    +- /*   180 */    65,   65,   65,   65,  495,  495,  495,   65,   65,  499,
    +- /*   190 */    65,   65,   65,  574,   65,   65,  517,   65,   65,   65,
    +- /*   200 */    65,   65,   65,   65,   65,   65,   65,  566,  691,  288,
    +- /*   210 */   288,  288,  701,  620, 1058,  675,  603,  964,  964,  967,
    +- /*   220 */   603,  967,  722,  965,  936,  999,  964,  264,  999,  999,
    +- /*   230 */   911,  921,  434, 1196, 1119, 1119, 1202, 1202, 1119, 1222,
    +- /*   240 */  1184, 1126, 1244, 1244, 1244, 1244, 1119, 1251, 1126, 1222,
    +- /*   250 */  1184, 1184, 1126, 1119, 1251, 1145, 1237, 1119, 1119, 1251,
    +- /*   260 */  1275, 1119, 1251, 1119, 1251, 1275, 1203, 1203, 1203, 1264,
    +- /*   270 */  1275, 1203, 1211, 1203, 1264, 1203, 1203, 1194, 1216, 1194,
    +- /*   280 */  1216, 1194, 1216, 1194, 1216, 1119, 1119, 1206, 1275, 1250,
    +- /*   290 */  1250, 1275, 1221, 1225, 1224, 1226, 1126, 1336, 1347, 1363,
    +- /*   300 */  1363, 1371, 1371, 1371, 1371,  -72,  -72,  -72,  -72,  -72,
    +- /*   310 */   -72,  477,  623,  742,  819,  624,  694,   74, 1023,  221,
    +- /*   320 */  1055, 1065, 1077, 1087, 1080,  889, 1031,  939, 1093, 1122,
    +- /*   330 */  1085, 1139,  961, 1024, 1172, 1103,  821, 1384, 1392, 1374,
    +- /*   340 */  1255, 1385, 1331, 1386, 1378, 1381, 1285, 1277, 1298, 1287,
    +- /*   350 */  1393, 1289, 1396, 1414, 1293, 1286, 1340, 1341, 1312, 1397,
    +- /*   360 */  1388, 1304, 1426, 1423, 1407, 1323, 1291, 1379, 1406, 1380,
    +- /*   370 */  1375, 1391, 1330, 1415, 1418, 1421, 1329, 1337, 1422, 1390,
    +- /*   380 */  1424, 1425, 1427, 1429, 1395, 1419, 1430, 1400, 1405, 1431,
    +- /*   390 */  1432, 1433, 1342, 1435, 1436, 1438, 1437, 1339, 1439, 1441,
    +- /*   400 */  1440, 1434, 1443, 1343, 1445, 1442, 1446, 1444, 1445, 1450,
    +- /*   410 */  1451, 1452, 1453, 1454, 1459, 1455, 1460, 1462, 1458, 1461,
    +- /*   420 */  1463, 1466, 1465, 1461, 1467, 1469, 1470, 1471, 1473, 1354,
    +- /*   430 */  1370, 1376, 1377, 1474, 1485, 1484,
    ++#define YY_SHIFT_COUNT    (465)
    ++#define YY_SHIFT_MIN      (0)
    ++#define YY_SHIFT_MAX      (1538)
    ++static const unsigned short int yy_shift_ofst[] = {
    ++ /*     0 */    39,  822,  955,  843,  997,  997,  997,  997,    0,    0,
    ++ /*    10 */   104,  630,  997,  997,  997,  997,  997,  997,  997, 1077,
    ++ /*    20 */  1077,  126,  161,  155,   52,  156,  208,  260,  312,  364,
    ++ /*    30 */   416,  468,  523,  578,  630,  630,  630,  630,  630,  630,
    ++ /*    40 */   630,  630,  630,  630,  630,  630,  630,  630,  630,  630,
    ++ /*    50 */   630,  682,  630,  733,  783,  783,  914,  997,  997,  997,
    ++ /*    60 */   997,  997,  997,  997,  997,  997,  997,  997,  997,  997,
    ++ /*    70 */   997,  997,  997,  997,  997,  997,  997,  997,  997,  997,
    ++ /*    80 */   997,  997,  997,  997,  997,  997,  997,  997, 1017,  997,
    ++ /*    90 */   997,  997,  997,  997,  997,  997,  997,  997,  997,  997,
    ++ /*   100 */   997,  997, 1070, 1054, 1054, 1054, 1054, 1054,   40,   25,
    ++ /*   110 */    72,  232,  788,  428,  248,  248,  232,  581,  367,  127,
    ++ /*   120 */   465,  138, 1541, 1541, 1541,  784,  784,  784,  522,  522,
    ++ /*   130 */   887,  887,  893,  406,  408,  232,  232,  232,  232,  232,
    ++ /*   140 */   232,  232,  232,  232,  232,  232,  232,  232,  232,  232,
    ++ /*   150 */   232,  232,  232,  232,  232,  370,  340,  714,  698,  698,
    ++ /*   160 */   465,   89,   89,   89,   89,   89,   89, 1541, 1541, 1541,
    ++ /*   170 */   504,   85,   85,  884,   70,  280,  902,  440,  966,  924,
    ++ /*   180 */   232,  232,  232,  232,  232,  232,  232,  232,  232,  232,
    ++ /*   190 */   232,  232,  232,  232,  232,  232, 1134, 1134, 1134,  232,
    ++ /*   200 */   232,  667,  232,  232,  232,  929,  232,  232,  885,  232,
    ++ /*   210 */   232,  232,  232,  232,  232,  232,  232,  232,  232,  418,
    ++ /*   220 */   678,  981,  981,  981,  981,  766,  271,  911,  510,  429,
    ++ /*   230 */   617,  786,  786,  830,  617,  830,    4,  730,  595,  768,
    ++ /*   240 */   786,  561,  768,  768,  732,  535,   55, 1165, 1105, 1105,
    ++ /*   250 */  1191, 1191, 1105, 1228, 1209, 1130, 1257, 1257, 1257, 1257,
    ++ /*   260 */  1105, 1280, 1130, 1228, 1209, 1209, 1130, 1105, 1280, 1198,
    ++ /*   270 */  1282, 1105, 1105, 1280, 1328, 1105, 1280, 1105, 1280, 1328,
    ++ /*   280 */  1244, 1244, 1244, 1308, 1328, 1244, 1267, 1244, 1308, 1244,
    ++ /*   290 */  1244, 1250, 1273, 1250, 1273, 1250, 1273, 1250, 1273, 1105,
    ++ /*   300 */  1360, 1105, 1260, 1328, 1306, 1306, 1328, 1274, 1276, 1277,
    ++ /*   310 */  1279, 1130, 1379, 1383, 1400, 1400, 1410, 1410, 1410, 1541,
    ++ /*   320 */  1541, 1541, 1541, 1541, 1541, 1541, 1541, 1541, 1541, 1541,
    ++ /*   330 */  1541, 1541, 1541, 1541, 1541,   34,  407,  463,  511,  417,
    ++ /*   340 */   479, 1272,  778,  941,  785,  825,  831,  833,  872,  877,
    ++ /*   350 */   756,  793,  900,  804,  919, 1045,  969, 1049,  803,  909,
    ++ /*   360 */  1051,  983, 1059, 1428, 1434, 1416, 1300, 1429, 1362, 1430,
    ++ /*   370 */  1422, 1424, 1330, 1317, 1340, 1329, 1433, 1331, 1438, 1454,
    ++ /*   380 */  1334, 1327, 1406, 1407, 1408, 1409, 1352, 1368, 1431, 1344,
    ++ /*   390 */  1466, 1463, 1447, 1363, 1332, 1404, 1448, 1411, 1399, 1435,
    ++ /*   400 */  1370, 1451, 1459, 1461, 1369, 1377, 1462, 1417, 1464, 1465,
    ++ /*   410 */  1467, 1469, 1419, 1460, 1470, 1423, 1456, 1471, 1472, 1473,
    ++ /*   420 */  1474, 1381, 1476, 1478, 1477, 1479, 1380, 1480, 1481, 1412,
    ++ /*   430 */  1475, 1484, 1386, 1485, 1482, 1486, 1483, 1490, 1485, 1491,
    ++ /*   440 */  1492, 1495, 1493, 1497, 1499, 1496, 1500, 1502, 1498, 1501,
    ++ /*   450 */  1503, 1506, 1505, 1501, 1507, 1509, 1510, 1511, 1513, 1403,
    ++ /*   460 */  1414, 1415, 1418, 1515, 1517, 1538,
    + };
    +-#define YY_REDUCE_USE_DFLT (-176)
    +-#define YY_REDUCE_COUNT (310)
    +-#define YY_REDUCE_MIN   (-175)
    +-#define YY_REDUCE_MAX   (1234)
    ++#define YY_REDUCE_COUNT (334)
    ++#define YY_REDUCE_MIN   (-217)
    ++#define YY_REDUCE_MAX   (1278)
    + static const short yy_reduce_ofst[] = {
    +- /*     0 */  -143,  954,   86,   21,  -50,   23,   79,  134,  170, -175,
    +- /*    10 */   229,  260, -121,  212,  219,  291,  -54,  349,  362,  156,
    +- /*    20 */   309,  311,  334,   85,  224,  394,  314,  314,  314,  314,
    +- /*    30 */   314,  314,  314,  314,  314,  314,  314,  314,  314,  314,
    +- /*    40 */   314,  314,  314,  314,  314,  314,  314,  314,  314,  314,
    +- /*    50 */   314,  314,  314,  314,  314,  374,  441,  443,  450,  452,
    +- /*    60 */   515,  554,  567,  569,  572,  578,  580,  582,  584,  587,
    +- /*    70 */   593,  631,  644,  646,  649,  655,  657,  659,  661,  664,
    +- /*    80 */   708,  720,  759,  771,  810,  822,  861,  873,  912,  930,
    +- /*    90 */   947,  950,  957,  959,  963,  966,  968,  998,  314,  314,
    +- /*   100 */   314,  314,  314,  314,  314,  314,  314,  447,  -53,  166,
    +- /*   110 */   438,  348,  363,  314,  473,  469,  314,  314,  314,  314,
    +- /*   120 */   -15,   59,  101,  688,  220,  220,  525,  256,  729,  735,
    +- /*   130 */   736,  740,  741,  744,  645,  448,  738,  458,  786,  503,
    +- /*   140 */   780,  656,  721,  724,  792,  545,  568,  706,  683,  681,
    +- /*   150 */   779,  784,  830,  831,  835,  678,  601, -104,   -2,   96,
    +- /*   160 */   111,  218,  287,  308,  310,  312,  335,  411,  453,  461,
    +- /*   170 */   573,  599,  617,  658,  665,  670,  732,  734,  775,  848,
    +- /*   180 */   875,  892,  893,  898,  332,  420,  869,  931,  944,  886,
    +- /*   190 */   983,  992, 1009,  958, 1017, 1028,  988, 1033, 1034, 1035,
    +- /*   200 */   287, 1036, 1044, 1045, 1047, 1049, 1056,  915,  972,  997,
    +- /*   210 */  1000, 1002,  886, 1011, 1015, 1061, 1013, 1001, 1003,  977,
    +- /*   220 */  1018,  979, 1050, 1041, 1040, 1052, 1014, 1004, 1059, 1060,
    +- /*   230 */  1032, 1038, 1084,  995, 1089, 1090, 1008, 1016, 1092, 1037,
    +- /*   240 */  1068, 1062, 1069, 1072, 1073, 1074, 1105, 1112, 1071, 1048,
    +- /*   250 */  1081, 1088, 1078, 1116, 1118, 1046, 1066, 1128, 1136, 1140,
    +- /*   260 */  1120, 1147, 1146, 1148, 1150, 1130, 1135, 1137, 1138, 1132,
    +- /*   270 */  1141, 1142, 1143, 1149, 1144, 1153, 1154, 1104, 1107, 1108,
    +- /*   280 */  1114, 1115, 1117, 1123, 1125, 1173, 1176, 1121, 1165, 1127,
    +- /*   290 */  1131, 1167, 1157, 1151, 1158, 1166, 1168, 1212, 1214, 1227,
    +- /*   300 */  1228, 1231, 1232, 1233, 1234, 1152, 1155, 1159, 1198, 1199,
    +- /*   310 */  1219,
    ++ /*     0 */  -144, -139, -134, -136, -141,   64,  114,  116, -158, -148,
    ++ /*    10 */  -217,   96,  819,  871,  878,  219,  270,  886,  272, -110,
    ++ /*    20 */   413,  918,  972,  228, -214, -214, -214, -214, -214, -214,
    ++ /*    30 */  -214, -214, -214, -214, -214, -214, -214, -214, -214, -214,
    ++ /*    40 */  -214, -214, -214, -214, -214, -214, -214, -214, -214, -214,
    ++ /*    50 */  -214, -214, -214, -214, -214, -214,   62,  323,  377,  536,
    ++ /*    60 */   539,  834,  948, 1020, 1024, 1031, 1039, 1048, 1050, 1063,
    ++ /*    70 */  1065, 1068, 1074, 1080, 1083, 1088, 1091, 1094, 1097, 1099,
    ++ /*    80 */  1103, 1106, 1111, 1114, 1122, 1126, 1129, 1131, 1137, 1139,
    ++ /*    90 */  1141, 1145, 1149, 1154, 1156, 1164, 1168, 1173, 1180, 1184,
    ++ /*   100 */  1187, 1192, -214, -214, -214, -214, -214, -214, -214, -214,
    ++ /*   110 */  -214,  132,  -45,   97,    8,  164,  379,  175,  255, -214,
    ++ /*   120 */   178, -214, -214, -214, -214, -168, -168, -168,  124,  329,
    ++ /*   130 */   399,  401, -129,  347,  347,  331,  133,  451,  452,  498,
    ++ /*   140 */   500,  502,  503,  505,  487,  506,  488,  490,  507,  543,
    ++ /*   150 */   547, -126,  588,  290,   27,  572,  501,  597,  537,  582,
    ++ /*   160 */   183,  599,  600,  601,  649,  650,  653,  508,  538,  -29,
    ++ /*   170 */  -156, -152, -137,  -79,  135,   74,  130,  242,  338,  378,
    ++ /*   180 */   393,  397,  607,  648,  691,  700,  708,  709,  728,  757,
    ++ /*   190 */   763,  769,  796,  810,  818,  845,  202,  748,  792,  861,
    ++ /*   200 */   862,  815,  866,  903,  905,  850,  931,  932,  896,  937,
    ++ /*   210 */   939,  945,   74,  949,  951,  964,  965,  967,  968,  888,
    ++ /*   220 */   820,  923,  926,  959,  960,  815,  980,  908, 1009,  985,
    ++ /*   230 */   986,  970,  974,  942,  988,  947, 1018, 1011, 1022, 1025,
    ++ /*   240 */   991,  982, 1032, 1038, 1015, 1019, 1064,  984, 1071, 1072,
    ++ /*   250 */   992,  993, 1085, 1061, 1069, 1067, 1093, 1116, 1124, 1128,
    ++ /*   260 */  1133, 1132, 1138, 1086, 1136, 1143, 1146, 1175, 1166, 1108,
    ++ /*   270 */  1113, 1193, 1196, 1201, 1178, 1203, 1205, 1208, 1206, 1190,
    ++ /*   280 */  1195, 1197, 1199, 1194, 1200, 1204, 1207, 1210, 1211, 1212,
    ++ /*   290 */  1213, 1159, 1167, 1169, 1174, 1172, 1176, 1179, 1177, 1222,
    ++ /*   300 */  1170, 1232, 1171, 1221, 1181, 1182, 1223, 1202, 1214, 1216,
    ++ /*   310 */  1215, 1219, 1245, 1249, 1261, 1262, 1266, 1271, 1275, 1183,
    ++ /*   320 */  1185, 1189, 1258, 1253, 1254, 1256, 1259, 1263, 1252, 1255,
    ++ /*   330 */  1268, 1269, 1270, 1278, 1264,
    + };
    + static const YYACTIONTYPE yy_default[] = {
    +- /*     0 */   982, 1300, 1300, 1300, 1214, 1214, 1214, 1305, 1300, 1109,
    +- /*    10 */  1138, 1138, 1274, 1305, 1305, 1305, 1305, 1305, 1305, 1212,
    +- /*    20 */  1305, 1305, 1305, 1300, 1305, 1113, 1144, 1305, 1305, 1305,
    +- /*    30 */  1305, 1305, 1305, 1305, 1305, 1273, 1275, 1152, 1151, 1254,
    +- /*    40 */  1125, 1149, 1142, 1146, 1215, 1208, 1209, 1207, 1211, 1216,
    +- /*    50 */  1305, 1145, 1177, 1192, 1176, 1305, 1305, 1305, 1305, 1305,
    +- /*    60 */  1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305,
    +- /*    70 */  1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305,
    +- /*    80 */  1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305,
    +- /*    90 */  1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1186, 1191,
    +- /*   100 */  1198, 1190, 1187, 1179, 1178, 1180, 1181, 1305, 1305, 1008,
    +- /*   110 */  1074, 1305, 1305, 1182, 1305, 1020, 1183, 1195, 1194, 1193,
    +- /*   120 */  1015, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305,
    +- /*   130 */  1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305,
    +- /*   140 */  1305, 1305, 1305, 1305, 1305,  982, 1300, 1305, 1305, 1300,
    +- /*   150 */  1300, 1300, 1300, 1300, 1300, 1292, 1113, 1103, 1305, 1305,
    +- /*   160 */  1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1280, 1278,
    +- /*   170 */  1305, 1227, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305,
    +- /*   180 */  1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305,
    +- /*   190 */  1305, 1305, 1305, 1109, 1305, 1305, 1305, 1305, 1305, 1305,
    +- /*   200 */  1305, 1305, 1305, 1305, 1305, 1305,  988, 1305, 1247, 1109,
    +- /*   210 */  1109, 1109, 1111, 1089, 1101,  990, 1148, 1127, 1127, 1259,
    +- /*   220 */  1148, 1259, 1045, 1068, 1042, 1138, 1127, 1210, 1138, 1138,
    +- /*   230 */  1110, 1101, 1305, 1285, 1118, 1118, 1277, 1277, 1118, 1157,
    +- /*   240 */  1078, 1148, 1085, 1085, 1085, 1085, 1118, 1005, 1148, 1157,
    +- /*   250 */  1078, 1078, 1148, 1118, 1005, 1253, 1251, 1118, 1118, 1005,
    +- /*   260 */  1220, 1118, 1005, 1118, 1005, 1220, 1076, 1076, 1076, 1060,
    +- /*   270 */  1220, 1076, 1045, 1076, 1060, 1076, 1076, 1131, 1126, 1131,
    +- /*   280 */  1126, 1131, 1126, 1131, 1126, 1118, 1118, 1305, 1220, 1224,
    +- /*   290 */  1224, 1220, 1143, 1132, 1141, 1139, 1148, 1011, 1063,  998,
    +- /*   300 */   998,  987,  987,  987,  987, 1297, 1297, 1292, 1047, 1047,
    +- /*   310 */  1030, 1305, 1305, 1305, 1305, 1305, 1305, 1022, 1305, 1229,
    +- /*   320 */  1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305,
    +- /*   330 */  1305, 1305, 1305, 1305, 1305, 1305, 1164, 1305,  983, 1287,
    +- /*   340 */  1305, 1305, 1284, 1305, 1305, 1305, 1305, 1305, 1305, 1305,
    +- /*   350 */  1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305,
    +- /*   360 */  1305, 1257, 1305, 1305, 1305, 1305, 1305, 1305, 1250, 1249,
    +- /*   370 */  1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305,
    +- /*   380 */  1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305,
    +- /*   390 */  1305, 1305, 1092, 1305, 1305, 1305, 1096, 1305, 1305, 1305,
    +- /*   400 */  1305, 1305, 1305, 1305, 1140, 1305, 1133, 1305, 1213, 1305,
    +- /*   410 */  1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1302,
    +- /*   420 */  1305, 1305, 1305, 1301, 1305, 1305, 1305, 1305, 1305, 1166,
    +- /*   430 */  1305, 1165, 1169, 1305,  996, 1305,
    ++ /*     0 */  1286, 1276, 1276, 1276, 1209, 1209, 1209, 1209, 1133, 1133,
    ++ /*    10 */  1260, 1036, 1005, 1005, 1005, 1005, 1005, 1005, 1208, 1005,
    ++ /*    20 */  1005, 1005, 1005, 1108, 1139, 1005, 1005, 1005, 1005, 1210,
    ++ /*    30 */  1211, 1005, 1005, 1005, 1259, 1261, 1149, 1148, 1147, 1146,
    ++ /*    40 */  1242, 1120, 1144, 1137, 1141, 1210, 1204, 1205, 1203, 1207,
    ++ /*    50 */  1211, 1005, 1140, 1174, 1188, 1173, 1005, 1005, 1005, 1005,
    ++ /*    60 */  1005, 1005, 1005, 1005, 1005, 1005, 1005, 1005, 1005, 1005,
    ++ /*    70 */  1005, 1005, 1005, 1005, 1005, 1005, 1005, 1005, 1005, 1005,
    ++ /*    80 */  1005, 1005, 1005, 1005, 1005, 1005, 1005, 1005, 1005, 1005,
    ++ /*    90 */  1005, 1005, 1005, 1005, 1005, 1005, 1005, 1005, 1005, 1005,
    ++ /*   100 */  1005, 1005, 1182, 1187, 1194, 1186, 1183, 1176, 1175, 1177,
    ++ /*   110 */  1178, 1005, 1026, 1075, 1005, 1005, 1005, 1276, 1036, 1179,
    ++ /*   120 */  1005, 1180, 1191, 1190, 1189, 1267, 1294, 1293, 1005, 1005,
    ++ /*   130 */  1005, 1005, 1005, 1005, 1005, 1005, 1005, 1005, 1005, 1005,
    ++ /*   140 */  1005, 1005, 1005, 1005, 1005, 1005, 1005, 1005, 1005, 1005,
    ++ /*   150 */  1005, 1005, 1005, 1005, 1005, 1036, 1286, 1276, 1032, 1032,
    ++ /*   160 */  1005, 1276, 1276, 1276, 1276, 1276, 1276, 1272, 1108, 1099,
    ++ /*   170 */  1005, 1005, 1005, 1005, 1005, 1005, 1005, 1005, 1005, 1005,
    ++ /*   180 */  1005, 1264, 1262, 1005, 1224, 1005, 1005, 1005, 1005, 1005,
    ++ /*   190 */  1005, 1005, 1005, 1005, 1005, 1005, 1005, 1005, 1005, 1005,
    ++ /*   200 */  1005, 1005, 1005, 1005, 1005, 1104, 1005, 1005, 1005, 1005,
    ++ /*   210 */  1005, 1005, 1005, 1005, 1005, 1005, 1005, 1005, 1288, 1005,
    ++ /*   220 */  1237, 1104, 1104, 1104, 1104, 1106, 1088, 1098, 1036, 1012,
    ++ /*   230 */  1143, 1122, 1122, 1327, 1143, 1327, 1050, 1308, 1047, 1133,
    ++ /*   240 */  1122, 1206, 1133, 1133, 1105, 1098, 1005, 1330, 1113, 1113,
    ++ /*   250 */  1329, 1329, 1113, 1154, 1078, 1143, 1084, 1084, 1084, 1084,
    ++ /*   260 */  1113, 1023, 1143, 1154, 1078, 1078, 1143, 1113, 1023, 1241,
    ++ /*   270 */  1324, 1113, 1113, 1023, 1217, 1113, 1023, 1113, 1023, 1217,
    ++ /*   280 */  1076, 1076, 1076, 1065, 1217, 1076, 1050, 1076, 1065, 1076,
    ++ /*   290 */  1076, 1126, 1121, 1126, 1121, 1126, 1121, 1126, 1121, 1113,
    ++ /*   300 */  1212, 1113, 1005, 1217, 1221, 1221, 1217, 1138, 1127, 1136,
    ++ /*   310 */  1134, 1143, 1029, 1068, 1291, 1291, 1287, 1287, 1287, 1335,
    ++ /*   320 */  1335, 1272, 1303, 1036, 1036, 1036, 1036, 1303, 1052, 1052,
    ++ /*   330 */  1036, 1036, 1036, 1036, 1303, 1005, 1005, 1005, 1005, 1005,
    ++ /*   340 */  1005, 1298, 1005, 1226, 1005, 1005, 1005, 1005, 1005, 1005,
    ++ /*   350 */  1005, 1005, 1005, 1005, 1005, 1005, 1005, 1005, 1005, 1005,
    ++ /*   360 */  1005, 1005, 1159, 1005, 1008, 1269, 1005, 1005, 1268, 1005,
    ++ /*   370 */  1005, 1005, 1005, 1005, 1005, 1005, 1005, 1005, 1005, 1005,
    ++ /*   380 */  1005, 1005, 1005, 1005, 1005, 1005, 1005, 1005, 1005, 1326,
    ++ /*   390 */  1005, 1005, 1005, 1005, 1005, 1005, 1240, 1239, 1005, 1005,
    ++ /*   400 */  1005, 1005, 1005, 1005, 1005, 1005, 1005, 1005, 1005, 1005,
    ++ /*   410 */  1005, 1005, 1005, 1005, 1005, 1005, 1005, 1005, 1005, 1005,
    ++ /*   420 */  1005, 1090, 1005, 1005, 1005, 1312, 1005, 1005, 1005, 1005,
    ++ /*   430 */  1005, 1005, 1005, 1135, 1005, 1128, 1005, 1005, 1317, 1005,
    ++ /*   440 */  1005, 1005, 1005, 1005, 1005, 1005, 1005, 1005, 1005, 1278,
    ++ /*   450 */  1005, 1005, 1005, 1277, 1005, 1005, 1005, 1005, 1005, 1161,
    ++ /*   460 */  1005, 1160, 1164, 1005, 1017, 1005,
    + };
    ++/********** End of lemon-generated parsing tables *****************************/
    + 
    +-/* The next table maps tokens into fallback tokens.  If a construct
    +-** like the following:
    ++/* The next table maps tokens (terminal symbols) into fallback tokens.  
    ++** If a construct like the following:
    + ** 
    + **      %fallback ID X Y Z.
    + **
    +@@ -126797,79 +138920,96 @@ static const YYACTIONTYPE yy_default[] = {
    + ** and Z.  Whenever one of the tokens X, Y, or Z is input to the parser
    + ** but it does not parse, the type of the token is changed to ID and
    + ** the parse is retried before an error is thrown.
    ++**
    ++** This feature can be used, for example, to cause some keywords in a language
    ++** to revert to identifiers if they keyword does not apply in the context where
    ++** it appears.
    + */
    + #ifdef YYFALLBACK
    + static const YYCODETYPE yyFallback[] = {
    +     0,  /*          $ => nothing */
    +     0,  /*       SEMI => nothing */
    +-   27,  /*    EXPLAIN => ID */
    +-   27,  /*      QUERY => ID */
    +-   27,  /*       PLAN => ID */
    +-   27,  /*      BEGIN => ID */
    ++   59,  /*    EXPLAIN => ID */
    ++   59,  /*      QUERY => ID */
    ++   59,  /*       PLAN => ID */
    ++   59,  /*      BEGIN => ID */
    +     0,  /* TRANSACTION => nothing */
    +-   27,  /*   DEFERRED => ID */
    +-   27,  /*  IMMEDIATE => ID */
    +-   27,  /*  EXCLUSIVE => ID */
    ++   59,  /*   DEFERRED => ID */
    ++   59,  /*  IMMEDIATE => ID */
    ++   59,  /*  EXCLUSIVE => ID */
    +     0,  /*     COMMIT => nothing */
    +-   27,  /*        END => ID */
    +-   27,  /*   ROLLBACK => ID */
    +-   27,  /*  SAVEPOINT => ID */
    +-   27,  /*    RELEASE => ID */
    ++   59,  /*        END => ID */
    ++   59,  /*   ROLLBACK => ID */
    ++   59,  /*  SAVEPOINT => ID */
    ++   59,  /*    RELEASE => ID */
    +     0,  /*         TO => nothing */
    +     0,  /*      TABLE => nothing */
    +     0,  /*     CREATE => nothing */
    +-   27,  /*         IF => ID */
    ++   59,  /*         IF => ID */
    +     0,  /*        NOT => nothing */
    +     0,  /*     EXISTS => nothing */
    +-   27,  /*       TEMP => ID */
    ++   59,  /*       TEMP => ID */
    +     0,  /*         LP => nothing */
    +     0,  /*         RP => nothing */
    +     0,  /*         AS => nothing */
    +-   27,  /*    WITHOUT => ID */
    ++   59,  /*    WITHOUT => ID */
    +     0,  /*      COMMA => nothing */
    ++   59,  /*      ABORT => ID */
    ++   59,  /*     ACTION => ID */
    ++   59,  /*      AFTER => ID */
    ++   59,  /*    ANALYZE => ID */
    ++   59,  /*        ASC => ID */
    ++   59,  /*     ATTACH => ID */
    ++   59,  /*     BEFORE => ID */
    ++   59,  /*         BY => ID */
    ++   59,  /*    CASCADE => ID */
    ++   59,  /*       CAST => ID */
    ++   59,  /*   CONFLICT => ID */
    ++   59,  /*   DATABASE => ID */
    ++   59,  /*       DESC => ID */
    ++   59,  /*     DETACH => ID */
    ++   59,  /*       EACH => ID */
    ++   59,  /*       FAIL => ID */
    ++    0,  /*         OR => nothing */
    ++    0,  /*        AND => nothing */
    ++    0,  /*         IS => nothing */
    ++   59,  /*      MATCH => ID */
    ++   59,  /*    LIKE_KW => ID */
    ++    0,  /*    BETWEEN => nothing */
    ++    0,  /*         IN => nothing */
    ++    0,  /*     ISNULL => nothing */
    ++    0,  /*    NOTNULL => nothing */
    ++    0,  /*         NE => nothing */
    ++    0,  /*         EQ => nothing */
    ++    0,  /*         GT => nothing */
    ++    0,  /*         LE => nothing */
    ++    0,  /*         LT => nothing */
    ++    0,  /*         GE => nothing */
    ++    0,  /*     ESCAPE => nothing */
    +     0,  /*         ID => nothing */
    +-    0,  /*    INDEXED => nothing */
    +-   27,  /*      ABORT => ID */
    +-   27,  /*     ACTION => ID */
    +-   27,  /*      AFTER => ID */
    +-   27,  /*    ANALYZE => ID */
    +-   27,  /*        ASC => ID */
    +-   27,  /*     ATTACH => ID */
    +-   27,  /*     BEFORE => ID */
    +-   27,  /*         BY => ID */
    +-   27,  /*    CASCADE => ID */
    +-   27,  /*       CAST => ID */
    +-   27,  /*   COLUMNKW => ID */
    +-   27,  /*   CONFLICT => ID */
    +-   27,  /*   DATABASE => ID */
    +-   27,  /*       DESC => ID */
    +-   27,  /*     DETACH => ID */
    +-   27,  /*       EACH => ID */
    +-   27,  /*       FAIL => ID */
    +-   27,  /*        FOR => ID */
    +-   27,  /*     IGNORE => ID */
    +-   27,  /*  INITIALLY => ID */
    +-   27,  /*    INSTEAD => ID */
    +-   27,  /*    LIKE_KW => ID */
    +-   27,  /*      MATCH => ID */
    +-   27,  /*         NO => ID */
    +-   27,  /*        KEY => ID */
    +-   27,  /*         OF => ID */
    +-   27,  /*     OFFSET => ID */
    +-   27,  /*     PRAGMA => ID */
    +-   27,  /*      RAISE => ID */
    +-   27,  /*  RECURSIVE => ID */
    +-   27,  /*    REPLACE => ID */
    +-   27,  /*   RESTRICT => ID */
    +-   27,  /*        ROW => ID */
    +-   27,  /*    TRIGGER => ID */
    +-   27,  /*     VACUUM => ID */
    +-   27,  /*       VIEW => ID */
    +-   27,  /*    VIRTUAL => ID */
    +-   27,  /*       WITH => ID */
    +-   27,  /*    REINDEX => ID */
    +-   27,  /*     RENAME => ID */
    +-   27,  /*   CTIME_KW => ID */
    ++   59,  /*   COLUMNKW => ID */
    ++   59,  /*        FOR => ID */
    ++   59,  /*     IGNORE => ID */
    ++   59,  /*  INITIALLY => ID */
    ++   59,  /*    INSTEAD => ID */
    ++   59,  /*         NO => ID */
    ++   59,  /*        KEY => ID */
    ++   59,  /*         OF => ID */
    ++   59,  /*     OFFSET => ID */
    ++   59,  /*     PRAGMA => ID */
    ++   59,  /*      RAISE => ID */
    ++   59,  /*  RECURSIVE => ID */
    ++   59,  /*    REPLACE => ID */
    ++   59,  /*   RESTRICT => ID */
    ++   59,  /*        ROW => ID */
    ++   59,  /*    TRIGGER => ID */
    ++   59,  /*     VACUUM => ID */
    ++   59,  /*       VIEW => ID */
    ++   59,  /*    VIRTUAL => ID */
    ++   59,  /*       WITH => ID */
    ++   59,  /*    REINDEX => ID */
    ++   59,  /*     RENAME => ID */
    ++   59,  /*   CTIME_KW => ID */
    + };
    + #endif /* YYFALLBACK */
    + 
    +@@ -126901,17 +139041,21 @@ typedef struct yyStackEntry yyStackEntry;
    + /* The state of the parser is completely contained in an instance of
    + ** the following structure */
    + struct yyParser {
    +-  int yyidx;                    /* Index of top element in stack */
    ++  yyStackEntry *yytos;          /* Pointer to top element of the stack */
    + #ifdef YYTRACKMAXSTACKDEPTH
    +-  int yyidxMax;                 /* Maximum value of yyidx */
    ++  int yyhwm;                    /* High-water mark of the stack */
    + #endif
    ++#ifndef YYNOERRORRECOVERY
    +   int yyerrcnt;                 /* Shifts left before out of the error */
    ++#endif
    +   sqlite3ParserARG_SDECL                /* A place to hold %extra_argument */
    + #if YYSTACKDEPTH<=0
    +   int yystksz;                  /* Current side of the stack */
    +   yyStackEntry *yystack;        /* The parser's stack */
    ++  yyStackEntry yystk0;          /* First stack entry */
    + #else
    +   yyStackEntry yystack[YYSTACKDEPTH];  /* The parser's stack */
    ++  yyStackEntry *yystackEnd;            /* Last entry in the stack */
    + #endif
    + };
    + typedef struct yyParser yyParser;
    +@@ -126948,436 +139092,673 @@ SQLITE_PRIVATE void sqlite3ParserTrace(FILE *TraceFILE, char *zTracePrompt){
    + }
    + #endif /* NDEBUG */
    + 
    +-#ifndef NDEBUG
    ++#if defined(YYCOVERAGE) || !defined(NDEBUG)
    + /* For tracing shifts, the names of all terminals and nonterminals
    + ** are required.  The following table supplies these names */
    + static const char *const yyTokenName[] = { 
    +-  "$",             "SEMI",          "EXPLAIN",       "QUERY",       
    +-  "PLAN",          "BEGIN",         "TRANSACTION",   "DEFERRED",    
    +-  "IMMEDIATE",     "EXCLUSIVE",     "COMMIT",        "END",         
    +-  "ROLLBACK",      "SAVEPOINT",     "RELEASE",       "TO",          
    +-  "TABLE",         "CREATE",        "IF",            "NOT",         
    +-  "EXISTS",        "TEMP",          "LP",            "RP",          
    +-  "AS",            "WITHOUT",       "COMMA",         "ID",          
    +-  "INDEXED",       "ABORT",         "ACTION",        "AFTER",       
    +-  "ANALYZE",       "ASC",           "ATTACH",        "BEFORE",      
    +-  "BY",            "CASCADE",       "CAST",          "COLUMNKW",    
    +-  "CONFLICT",      "DATABASE",      "DESC",          "DETACH",      
    +-  "EACH",          "FAIL",          "FOR",           "IGNORE",      
    +-  "INITIALLY",     "INSTEAD",       "LIKE_KW",       "MATCH",       
    +-  "NO",            "KEY",           "OF",            "OFFSET",      
    +-  "PRAGMA",        "RAISE",         "RECURSIVE",     "REPLACE",     
    +-  "RESTRICT",      "ROW",           "TRIGGER",       "VACUUM",      
    +-  "VIEW",          "VIRTUAL",       "WITH",          "REINDEX",     
    +-  "RENAME",        "CTIME_KW",      "ANY",           "OR",          
    +-  "AND",           "IS",            "BETWEEN",       "IN",          
    +-  "ISNULL",        "NOTNULL",       "NE",            "EQ",          
    +-  "GT",            "LE",            "LT",            "GE",          
    +-  "ESCAPE",        "BITAND",        "BITOR",         "LSHIFT",      
    +-  "RSHIFT",        "PLUS",          "MINUS",         "STAR",        
    +-  "SLASH",         "REM",           "CONCAT",        "COLLATE",     
    +-  "BITNOT",        "STRING",        "JOIN_KW",       "CONSTRAINT",  
    +-  "DEFAULT",       "NULL",          "PRIMARY",       "UNIQUE",      
    +-  "CHECK",         "REFERENCES",    "AUTOINCR",      "ON",          
    +-  "INSERT",        "DELETE",        "UPDATE",        "SET",         
    +-  "DEFERRABLE",    "FOREIGN",       "DROP",          "UNION",       
    +-  "ALL",           "EXCEPT",        "INTERSECT",     "SELECT",      
    +-  "VALUES",        "DISTINCT",      "DOT",           "FROM",        
    +-  "JOIN",          "USING",         "ORDER",         "GROUP",       
    +-  "HAVING",        "LIMIT",         "WHERE",         "INTO",        
    +-  "INTEGER",       "FLOAT",         "BLOB",          "VARIABLE",    
    +-  "CASE",          "WHEN",          "THEN",          "ELSE",        
    +-  "INDEX",         "ALTER",         "ADD",           "error",       
    +-  "input",         "cmdlist",       "ecmd",          "explain",     
    +-  "cmdx",          "cmd",           "transtype",     "trans_opt",   
    +-  "nm",            "savepoint_opt",  "create_table",  "create_table_args",
    +-  "createkw",      "temp",          "ifnotexists",   "dbnm",        
    +-  "columnlist",    "conslist_opt",  "table_options",  "select",      
    +-  "column",        "columnid",      "type",          "carglist",    
    +-  "typetoken",     "typename",      "signed",        "plus_num",    
    +-  "minus_num",     "ccons",         "term",          "expr",        
    +-  "onconf",        "sortorder",     "autoinc",       "eidlist_opt", 
    +-  "refargs",       "defer_subclause",  "refarg",        "refact",      
    +-  "init_deferred_pred_opt",  "conslist",      "tconscomma",    "tcons",       
    +-  "sortlist",      "eidlist",       "defer_subclause_opt",  "orconf",      
    +-  "resolvetype",   "raisetype",     "ifexists",      "fullname",    
    +-  "selectnowith",  "oneselect",     "with",          "multiselect_op",
    +-  "distinct",      "selcollist",    "from",          "where_opt",   
    +-  "groupby_opt",   "having_opt",    "orderby_opt",   "limit_opt",   
    +-  "values",        "nexprlist",     "exprlist",      "sclp",        
    +-  "as",            "seltablist",    "stl_prefix",    "joinop",      
    +-  "indexed_opt",   "on_opt",        "using_opt",     "joinop2",     
    +-  "idlist",        "setlist",       "insert_cmd",    "idlist_opt",  
    +-  "likeop",        "between_op",    "in_op",         "case_operand",
    +-  "case_exprlist",  "case_else",     "uniqueflag",    "collate",     
    +-  "nmnum",         "trigger_decl",  "trigger_cmd_list",  "trigger_time",
    +-  "trigger_event",  "foreach_clause",  "when_clause",   "trigger_cmd", 
    +-  "trnm",          "tridxby",       "database_kw_opt",  "key_opt",     
    +-  "add_column_fullname",  "kwcolumn_opt",  "create_vtab",   "vtabarglist", 
    +-  "vtabarg",       "vtabargtoken",  "lp",            "anylist",     
    +-  "wqlist",      
    ++  /*    0 */ "$",
    ++  /*    1 */ "SEMI",
    ++  /*    2 */ "EXPLAIN",
    ++  /*    3 */ "QUERY",
    ++  /*    4 */ "PLAN",
    ++  /*    5 */ "BEGIN",
    ++  /*    6 */ "TRANSACTION",
    ++  /*    7 */ "DEFERRED",
    ++  /*    8 */ "IMMEDIATE",
    ++  /*    9 */ "EXCLUSIVE",
    ++  /*   10 */ "COMMIT",
    ++  /*   11 */ "END",
    ++  /*   12 */ "ROLLBACK",
    ++  /*   13 */ "SAVEPOINT",
    ++  /*   14 */ "RELEASE",
    ++  /*   15 */ "TO",
    ++  /*   16 */ "TABLE",
    ++  /*   17 */ "CREATE",
    ++  /*   18 */ "IF",
    ++  /*   19 */ "NOT",
    ++  /*   20 */ "EXISTS",
    ++  /*   21 */ "TEMP",
    ++  /*   22 */ "LP",
    ++  /*   23 */ "RP",
    ++  /*   24 */ "AS",
    ++  /*   25 */ "WITHOUT",
    ++  /*   26 */ "COMMA",
    ++  /*   27 */ "ABORT",
    ++  /*   28 */ "ACTION",
    ++  /*   29 */ "AFTER",
    ++  /*   30 */ "ANALYZE",
    ++  /*   31 */ "ASC",
    ++  /*   32 */ "ATTACH",
    ++  /*   33 */ "BEFORE",
    ++  /*   34 */ "BY",
    ++  /*   35 */ "CASCADE",
    ++  /*   36 */ "CAST",
    ++  /*   37 */ "CONFLICT",
    ++  /*   38 */ "DATABASE",
    ++  /*   39 */ "DESC",
    ++  /*   40 */ "DETACH",
    ++  /*   41 */ "EACH",
    ++  /*   42 */ "FAIL",
    ++  /*   43 */ "OR",
    ++  /*   44 */ "AND",
    ++  /*   45 */ "IS",
    ++  /*   46 */ "MATCH",
    ++  /*   47 */ "LIKE_KW",
    ++  /*   48 */ "BETWEEN",
    ++  /*   49 */ "IN",
    ++  /*   50 */ "ISNULL",
    ++  /*   51 */ "NOTNULL",
    ++  /*   52 */ "NE",
    ++  /*   53 */ "EQ",
    ++  /*   54 */ "GT",
    ++  /*   55 */ "LE",
    ++  /*   56 */ "LT",
    ++  /*   57 */ "GE",
    ++  /*   58 */ "ESCAPE",
    ++  /*   59 */ "ID",
    ++  /*   60 */ "COLUMNKW",
    ++  /*   61 */ "FOR",
    ++  /*   62 */ "IGNORE",
    ++  /*   63 */ "INITIALLY",
    ++  /*   64 */ "INSTEAD",
    ++  /*   65 */ "NO",
    ++  /*   66 */ "KEY",
    ++  /*   67 */ "OF",
    ++  /*   68 */ "OFFSET",
    ++  /*   69 */ "PRAGMA",
    ++  /*   70 */ "RAISE",
    ++  /*   71 */ "RECURSIVE",
    ++  /*   72 */ "REPLACE",
    ++  /*   73 */ "RESTRICT",
    ++  /*   74 */ "ROW",
    ++  /*   75 */ "TRIGGER",
    ++  /*   76 */ "VACUUM",
    ++  /*   77 */ "VIEW",
    ++  /*   78 */ "VIRTUAL",
    ++  /*   79 */ "WITH",
    ++  /*   80 */ "REINDEX",
    ++  /*   81 */ "RENAME",
    ++  /*   82 */ "CTIME_KW",
    ++  /*   83 */ "ANY",
    ++  /*   84 */ "BITAND",
    ++  /*   85 */ "BITOR",
    ++  /*   86 */ "LSHIFT",
    ++  /*   87 */ "RSHIFT",
    ++  /*   88 */ "PLUS",
    ++  /*   89 */ "MINUS",
    ++  /*   90 */ "STAR",
    ++  /*   91 */ "SLASH",
    ++  /*   92 */ "REM",
    ++  /*   93 */ "CONCAT",
    ++  /*   94 */ "COLLATE",
    ++  /*   95 */ "BITNOT",
    ++  /*   96 */ "INDEXED",
    ++  /*   97 */ "STRING",
    ++  /*   98 */ "JOIN_KW",
    ++  /*   99 */ "CONSTRAINT",
    ++  /*  100 */ "DEFAULT",
    ++  /*  101 */ "NULL",
    ++  /*  102 */ "PRIMARY",
    ++  /*  103 */ "UNIQUE",
    ++  /*  104 */ "CHECK",
    ++  /*  105 */ "REFERENCES",
    ++  /*  106 */ "AUTOINCR",
    ++  /*  107 */ "ON",
    ++  /*  108 */ "INSERT",
    ++  /*  109 */ "DELETE",
    ++  /*  110 */ "UPDATE",
    ++  /*  111 */ "SET",
    ++  /*  112 */ "DEFERRABLE",
    ++  /*  113 */ "FOREIGN",
    ++  /*  114 */ "DROP",
    ++  /*  115 */ "UNION",
    ++  /*  116 */ "ALL",
    ++  /*  117 */ "EXCEPT",
    ++  /*  118 */ "INTERSECT",
    ++  /*  119 */ "SELECT",
    ++  /*  120 */ "VALUES",
    ++  /*  121 */ "DISTINCT",
    ++  /*  122 */ "DOT",
    ++  /*  123 */ "FROM",
    ++  /*  124 */ "JOIN",
    ++  /*  125 */ "USING",
    ++  /*  126 */ "ORDER",
    ++  /*  127 */ "GROUP",
    ++  /*  128 */ "HAVING",
    ++  /*  129 */ "LIMIT",
    ++  /*  130 */ "WHERE",
    ++  /*  131 */ "INTO",
    ++  /*  132 */ "FLOAT",
    ++  /*  133 */ "BLOB",
    ++  /*  134 */ "INTEGER",
    ++  /*  135 */ "VARIABLE",
    ++  /*  136 */ "CASE",
    ++  /*  137 */ "WHEN",
    ++  /*  138 */ "THEN",
    ++  /*  139 */ "ELSE",
    ++  /*  140 */ "INDEX",
    ++  /*  141 */ "ALTER",
    ++  /*  142 */ "ADD",
    ++  /*  143 */ "error",
    ++  /*  144 */ "input",
    ++  /*  145 */ "cmdlist",
    ++  /*  146 */ "ecmd",
    ++  /*  147 */ "explain",
    ++  /*  148 */ "cmdx",
    ++  /*  149 */ "cmd",
    ++  /*  150 */ "transtype",
    ++  /*  151 */ "trans_opt",
    ++  /*  152 */ "nm",
    ++  /*  153 */ "savepoint_opt",
    ++  /*  154 */ "create_table",
    ++  /*  155 */ "create_table_args",
    ++  /*  156 */ "createkw",
    ++  /*  157 */ "temp",
    ++  /*  158 */ "ifnotexists",
    ++  /*  159 */ "dbnm",
    ++  /*  160 */ "columnlist",
    ++  /*  161 */ "conslist_opt",
    ++  /*  162 */ "table_options",
    ++  /*  163 */ "select",
    ++  /*  164 */ "columnname",
    ++  /*  165 */ "carglist",
    ++  /*  166 */ "typetoken",
    ++  /*  167 */ "typename",
    ++  /*  168 */ "signed",
    ++  /*  169 */ "plus_num",
    ++  /*  170 */ "minus_num",
    ++  /*  171 */ "scanpt",
    ++  /*  172 */ "ccons",
    ++  /*  173 */ "term",
    ++  /*  174 */ "expr",
    ++  /*  175 */ "onconf",
    ++  /*  176 */ "sortorder",
    ++  /*  177 */ "autoinc",
    ++  /*  178 */ "eidlist_opt",
    ++  /*  179 */ "refargs",
    ++  /*  180 */ "defer_subclause",
    ++  /*  181 */ "refarg",
    ++  /*  182 */ "refact",
    ++  /*  183 */ "init_deferred_pred_opt",
    ++  /*  184 */ "conslist",
    ++  /*  185 */ "tconscomma",
    ++  /*  186 */ "tcons",
    ++  /*  187 */ "sortlist",
    ++  /*  188 */ "eidlist",
    ++  /*  189 */ "defer_subclause_opt",
    ++  /*  190 */ "orconf",
    ++  /*  191 */ "resolvetype",
    ++  /*  192 */ "raisetype",
    ++  /*  193 */ "ifexists",
    ++  /*  194 */ "fullname",
    ++  /*  195 */ "selectnowith",
    ++  /*  196 */ "oneselect",
    ++  /*  197 */ "with",
    ++  /*  198 */ "multiselect_op",
    ++  /*  199 */ "distinct",
    ++  /*  200 */ "selcollist",
    ++  /*  201 */ "from",
    ++  /*  202 */ "where_opt",
    ++  /*  203 */ "groupby_opt",
    ++  /*  204 */ "having_opt",
    ++  /*  205 */ "orderby_opt",
    ++  /*  206 */ "limit_opt",
    ++  /*  207 */ "values",
    ++  /*  208 */ "nexprlist",
    ++  /*  209 */ "exprlist",
    ++  /*  210 */ "sclp",
    ++  /*  211 */ "as",
    ++  /*  212 */ "seltablist",
    ++  /*  213 */ "stl_prefix",
    ++  /*  214 */ "joinop",
    ++  /*  215 */ "indexed_opt",
    ++  /*  216 */ "on_opt",
    ++  /*  217 */ "using_opt",
    ++  /*  218 */ "idlist",
    ++  /*  219 */ "setlist",
    ++  /*  220 */ "insert_cmd",
    ++  /*  221 */ "idlist_opt",
    ++  /*  222 */ "likeop",
    ++  /*  223 */ "between_op",
    ++  /*  224 */ "in_op",
    ++  /*  225 */ "paren_exprlist",
    ++  /*  226 */ "case_operand",
    ++  /*  227 */ "case_exprlist",
    ++  /*  228 */ "case_else",
    ++  /*  229 */ "uniqueflag",
    ++  /*  230 */ "collate",
    ++  /*  231 */ "nmnum",
    ++  /*  232 */ "trigger_decl",
    ++  /*  233 */ "trigger_cmd_list",
    ++  /*  234 */ "trigger_time",
    ++  /*  235 */ "trigger_event",
    ++  /*  236 */ "foreach_clause",
    ++  /*  237 */ "when_clause",
    ++  /*  238 */ "trigger_cmd",
    ++  /*  239 */ "trnm",
    ++  /*  240 */ "tridxby",
    ++  /*  241 */ "database_kw_opt",
    ++  /*  242 */ "key_opt",
    ++  /*  243 */ "add_column_fullname",
    ++  /*  244 */ "kwcolumn_opt",
    ++  /*  245 */ "create_vtab",
    ++  /*  246 */ "vtabarglist",
    ++  /*  247 */ "vtabarg",
    ++  /*  248 */ "vtabargtoken",
    ++  /*  249 */ "lp",
    ++  /*  250 */ "anylist",
    ++  /*  251 */ "wqlist",
    + };
    +-#endif /* NDEBUG */
    ++#endif /* defined(YYCOVERAGE) || !defined(NDEBUG) */
    + 
    + #ifndef NDEBUG
    + /* For tracing reduce actions, the names of all rules are required.
    + */
    + static const char *const yyRuleName[] = {
    +- /*   0 */ "input ::= cmdlist",
    +- /*   1 */ "cmdlist ::= cmdlist ecmd",
    +- /*   2 */ "cmdlist ::= ecmd",
    +- /*   3 */ "ecmd ::= SEMI",
    +- /*   4 */ "ecmd ::= explain cmdx SEMI",
    +- /*   5 */ "explain ::=",
    +- /*   6 */ "explain ::= EXPLAIN",
    +- /*   7 */ "explain ::= EXPLAIN QUERY PLAN",
    +- /*   8 */ "cmdx ::= cmd",
    +- /*   9 */ "cmd ::= BEGIN transtype trans_opt",
    +- /*  10 */ "trans_opt ::=",
    +- /*  11 */ "trans_opt ::= TRANSACTION",
    +- /*  12 */ "trans_opt ::= TRANSACTION nm",
    +- /*  13 */ "transtype ::=",
    +- /*  14 */ "transtype ::= DEFERRED",
    +- /*  15 */ "transtype ::= IMMEDIATE",
    +- /*  16 */ "transtype ::= EXCLUSIVE",
    +- /*  17 */ "cmd ::= COMMIT trans_opt",
    +- /*  18 */ "cmd ::= END trans_opt",
    +- /*  19 */ "cmd ::= ROLLBACK trans_opt",
    +- /*  20 */ "savepoint_opt ::= SAVEPOINT",
    +- /*  21 */ "savepoint_opt ::=",
    +- /*  22 */ "cmd ::= SAVEPOINT nm",
    +- /*  23 */ "cmd ::= RELEASE savepoint_opt nm",
    +- /*  24 */ "cmd ::= ROLLBACK trans_opt TO savepoint_opt nm",
    +- /*  25 */ "cmd ::= create_table create_table_args",
    +- /*  26 */ "create_table ::= createkw temp TABLE ifnotexists nm dbnm",
    +- /*  27 */ "createkw ::= CREATE",
    +- /*  28 */ "ifnotexists ::=",
    +- /*  29 */ "ifnotexists ::= IF NOT EXISTS",
    +- /*  30 */ "temp ::= TEMP",
    +- /*  31 */ "temp ::=",
    +- /*  32 */ "create_table_args ::= LP columnlist conslist_opt RP table_options",
    +- /*  33 */ "create_table_args ::= AS select",
    +- /*  34 */ "table_options ::=",
    +- /*  35 */ "table_options ::= WITHOUT nm",
    +- /*  36 */ "columnlist ::= columnlist COMMA column",
    +- /*  37 */ "columnlist ::= column",
    +- /*  38 */ "column ::= columnid type carglist",
    +- /*  39 */ "columnid ::= nm",
    +- /*  40 */ "nm ::= ID|INDEXED",
    +- /*  41 */ "nm ::= STRING",
    +- /*  42 */ "nm ::= JOIN_KW",
    +- /*  43 */ "type ::=",
    +- /*  44 */ "type ::= typetoken",
    +- /*  45 */ "typetoken ::= typename",
    +- /*  46 */ "typetoken ::= typename LP signed RP",
    +- /*  47 */ "typetoken ::= typename LP signed COMMA signed RP",
    +- /*  48 */ "typename ::= ID|STRING",
    +- /*  49 */ "typename ::= typename ID|STRING",
    +- /*  50 */ "signed ::= plus_num",
    +- /*  51 */ "signed ::= minus_num",
    +- /*  52 */ "carglist ::= carglist ccons",
    +- /*  53 */ "carglist ::=",
    +- /*  54 */ "ccons ::= CONSTRAINT nm",
    +- /*  55 */ "ccons ::= DEFAULT term",
    +- /*  56 */ "ccons ::= DEFAULT LP expr RP",
    +- /*  57 */ "ccons ::= DEFAULT PLUS term",
    +- /*  58 */ "ccons ::= DEFAULT MINUS term",
    +- /*  59 */ "ccons ::= DEFAULT ID|INDEXED",
    +- /*  60 */ "ccons ::= NULL onconf",
    +- /*  61 */ "ccons ::= NOT NULL onconf",
    +- /*  62 */ "ccons ::= PRIMARY KEY sortorder onconf autoinc",
    +- /*  63 */ "ccons ::= UNIQUE onconf",
    +- /*  64 */ "ccons ::= CHECK LP expr RP",
    +- /*  65 */ "ccons ::= REFERENCES nm eidlist_opt refargs",
    +- /*  66 */ "ccons ::= defer_subclause",
    +- /*  67 */ "ccons ::= COLLATE ID|STRING",
    +- /*  68 */ "autoinc ::=",
    +- /*  69 */ "autoinc ::= AUTOINCR",
    +- /*  70 */ "refargs ::=",
    +- /*  71 */ "refargs ::= refargs refarg",
    +- /*  72 */ "refarg ::= MATCH nm",
    +- /*  73 */ "refarg ::= ON INSERT refact",
    +- /*  74 */ "refarg ::= ON DELETE refact",
    +- /*  75 */ "refarg ::= ON UPDATE refact",
    +- /*  76 */ "refact ::= SET NULL",
    +- /*  77 */ "refact ::= SET DEFAULT",
    +- /*  78 */ "refact ::= CASCADE",
    +- /*  79 */ "refact ::= RESTRICT",
    +- /*  80 */ "refact ::= NO ACTION",
    +- /*  81 */ "defer_subclause ::= NOT DEFERRABLE init_deferred_pred_opt",
    +- /*  82 */ "defer_subclause ::= DEFERRABLE init_deferred_pred_opt",
    +- /*  83 */ "init_deferred_pred_opt ::=",
    +- /*  84 */ "init_deferred_pred_opt ::= INITIALLY DEFERRED",
    +- /*  85 */ "init_deferred_pred_opt ::= INITIALLY IMMEDIATE",
    +- /*  86 */ "conslist_opt ::=",
    +- /*  87 */ "conslist_opt ::= COMMA conslist",
    +- /*  88 */ "conslist ::= conslist tconscomma tcons",
    +- /*  89 */ "conslist ::= tcons",
    +- /*  90 */ "tconscomma ::= COMMA",
    +- /*  91 */ "tconscomma ::=",
    +- /*  92 */ "tcons ::= CONSTRAINT nm",
    +- /*  93 */ "tcons ::= PRIMARY KEY LP sortlist autoinc RP onconf",
    +- /*  94 */ "tcons ::= UNIQUE LP sortlist RP onconf",
    +- /*  95 */ "tcons ::= CHECK LP expr RP onconf",
    +- /*  96 */ "tcons ::= FOREIGN KEY LP eidlist RP REFERENCES nm eidlist_opt refargs defer_subclause_opt",
    +- /*  97 */ "defer_subclause_opt ::=",
    +- /*  98 */ "defer_subclause_opt ::= defer_subclause",
    +- /*  99 */ "onconf ::=",
    +- /* 100 */ "onconf ::= ON CONFLICT resolvetype",
    +- /* 101 */ "orconf ::=",
    +- /* 102 */ "orconf ::= OR resolvetype",
    +- /* 103 */ "resolvetype ::= raisetype",
    +- /* 104 */ "resolvetype ::= IGNORE",
    +- /* 105 */ "resolvetype ::= REPLACE",
    +- /* 106 */ "cmd ::= DROP TABLE ifexists fullname",
    +- /* 107 */ "ifexists ::= IF EXISTS",
    +- /* 108 */ "ifexists ::=",
    +- /* 109 */ "cmd ::= createkw temp VIEW ifnotexists nm dbnm eidlist_opt AS select",
    +- /* 110 */ "cmd ::= DROP VIEW ifexists fullname",
    +- /* 111 */ "cmd ::= select",
    +- /* 112 */ "select ::= with selectnowith",
    +- /* 113 */ "selectnowith ::= oneselect",
    +- /* 114 */ "selectnowith ::= selectnowith multiselect_op oneselect",
    +- /* 115 */ "multiselect_op ::= UNION",
    +- /* 116 */ "multiselect_op ::= UNION ALL",
    +- /* 117 */ "multiselect_op ::= EXCEPT|INTERSECT",
    +- /* 118 */ "oneselect ::= SELECT distinct selcollist from where_opt groupby_opt having_opt orderby_opt limit_opt",
    +- /* 119 */ "oneselect ::= values",
    +- /* 120 */ "values ::= VALUES LP nexprlist RP",
    +- /* 121 */ "values ::= values COMMA LP exprlist RP",
    +- /* 122 */ "distinct ::= DISTINCT",
    +- /* 123 */ "distinct ::= ALL",
    +- /* 124 */ "distinct ::=",
    +- /* 125 */ "sclp ::= selcollist COMMA",
    +- /* 126 */ "sclp ::=",
    +- /* 127 */ "selcollist ::= sclp expr as",
    +- /* 128 */ "selcollist ::= sclp STAR",
    +- /* 129 */ "selcollist ::= sclp nm DOT STAR",
    +- /* 130 */ "as ::= AS nm",
    +- /* 131 */ "as ::= ID|STRING",
    +- /* 132 */ "as ::=",
    +- /* 133 */ "from ::=",
    +- /* 134 */ "from ::= FROM seltablist",
    +- /* 135 */ "stl_prefix ::= seltablist joinop",
    +- /* 136 */ "stl_prefix ::=",
    +- /* 137 */ "seltablist ::= stl_prefix nm dbnm as indexed_opt on_opt using_opt",
    +- /* 138 */ "seltablist ::= stl_prefix nm dbnm LP exprlist RP as on_opt using_opt",
    +- /* 139 */ "seltablist ::= stl_prefix LP select RP as on_opt using_opt",
    +- /* 140 */ "seltablist ::= stl_prefix LP seltablist RP as on_opt using_opt",
    +- /* 141 */ "dbnm ::=",
    +- /* 142 */ "dbnm ::= DOT nm",
    +- /* 143 */ "fullname ::= nm dbnm",
    +- /* 144 */ "joinop ::= COMMA|JOIN",
    +- /* 145 */ "joinop ::= JOIN_KW JOIN",
    +- /* 146 */ "joinop ::= JOIN_KW nm JOIN",
    +- /* 147 */ "joinop ::= JOIN_KW nm nm JOIN",
    +- /* 148 */ "on_opt ::= ON expr",
    +- /* 149 */ "on_opt ::=",
    +- /* 150 */ "indexed_opt ::=",
    +- /* 151 */ "indexed_opt ::= INDEXED BY nm",
    +- /* 152 */ "indexed_opt ::= NOT INDEXED",
    +- /* 153 */ "using_opt ::= USING LP idlist RP",
    +- /* 154 */ "using_opt ::=",
    +- /* 155 */ "orderby_opt ::=",
    +- /* 156 */ "orderby_opt ::= ORDER BY sortlist",
    +- /* 157 */ "sortlist ::= sortlist COMMA expr sortorder",
    +- /* 158 */ "sortlist ::= expr sortorder",
    +- /* 159 */ "sortorder ::= ASC",
    +- /* 160 */ "sortorder ::= DESC",
    +- /* 161 */ "sortorder ::=",
    +- /* 162 */ "groupby_opt ::=",
    +- /* 163 */ "groupby_opt ::= GROUP BY nexprlist",
    +- /* 164 */ "having_opt ::=",
    +- /* 165 */ "having_opt ::= HAVING expr",
    +- /* 166 */ "limit_opt ::=",
    +- /* 167 */ "limit_opt ::= LIMIT expr",
    +- /* 168 */ "limit_opt ::= LIMIT expr OFFSET expr",
    +- /* 169 */ "limit_opt ::= LIMIT expr COMMA expr",
    +- /* 170 */ "cmd ::= with DELETE FROM fullname indexed_opt where_opt",
    +- /* 171 */ "where_opt ::=",
    +- /* 172 */ "where_opt ::= WHERE expr",
    +- /* 173 */ "cmd ::= with UPDATE orconf fullname indexed_opt SET setlist where_opt",
    +- /* 174 */ "setlist ::= setlist COMMA nm EQ expr",
    +- /* 175 */ "setlist ::= nm EQ expr",
    +- /* 176 */ "cmd ::= with insert_cmd INTO fullname idlist_opt select",
    +- /* 177 */ "cmd ::= with insert_cmd INTO fullname idlist_opt DEFAULT VALUES",
    +- /* 178 */ "insert_cmd ::= INSERT orconf",
    +- /* 179 */ "insert_cmd ::= REPLACE",
    +- /* 180 */ "idlist_opt ::=",
    +- /* 181 */ "idlist_opt ::= LP idlist RP",
    +- /* 182 */ "idlist ::= idlist COMMA nm",
    +- /* 183 */ "idlist ::= nm",
    +- /* 184 */ "expr ::= term",
    +- /* 185 */ "expr ::= LP expr RP",
    +- /* 186 */ "term ::= NULL",
    +- /* 187 */ "expr ::= ID|INDEXED",
    +- /* 188 */ "expr ::= JOIN_KW",
    +- /* 189 */ "expr ::= nm DOT nm",
    +- /* 190 */ "expr ::= nm DOT nm DOT nm",
    +- /* 191 */ "term ::= INTEGER|FLOAT|BLOB",
    +- /* 192 */ "term ::= STRING",
    +- /* 193 */ "expr ::= VARIABLE",
    +- /* 194 */ "expr ::= expr COLLATE ID|STRING",
    +- /* 195 */ "expr ::= CAST LP expr AS typetoken RP",
    +- /* 196 */ "expr ::= ID|INDEXED LP distinct exprlist RP",
    +- /* 197 */ "expr ::= ID|INDEXED LP STAR RP",
    +- /* 198 */ "term ::= CTIME_KW",
    +- /* 199 */ "expr ::= expr AND expr",
    +- /* 200 */ "expr ::= expr OR expr",
    +- /* 201 */ "expr ::= expr LT|GT|GE|LE expr",
    +- /* 202 */ "expr ::= expr EQ|NE expr",
    +- /* 203 */ "expr ::= expr BITAND|BITOR|LSHIFT|RSHIFT expr",
    +- /* 204 */ "expr ::= expr PLUS|MINUS expr",
    +- /* 205 */ "expr ::= expr STAR|SLASH|REM expr",
    +- /* 206 */ "expr ::= expr CONCAT expr",
    +- /* 207 */ "likeop ::= LIKE_KW|MATCH",
    +- /* 208 */ "likeop ::= NOT LIKE_KW|MATCH",
    +- /* 209 */ "expr ::= expr likeop expr",
    +- /* 210 */ "expr ::= expr likeop expr ESCAPE expr",
    +- /* 211 */ "expr ::= expr ISNULL|NOTNULL",
    +- /* 212 */ "expr ::= expr NOT NULL",
    +- /* 213 */ "expr ::= expr IS expr",
    +- /* 214 */ "expr ::= expr IS NOT expr",
    +- /* 215 */ "expr ::= NOT expr",
    +- /* 216 */ "expr ::= BITNOT expr",
    +- /* 217 */ "expr ::= MINUS expr",
    +- /* 218 */ "expr ::= PLUS expr",
    +- /* 219 */ "between_op ::= BETWEEN",
    +- /* 220 */ "between_op ::= NOT BETWEEN",
    +- /* 221 */ "expr ::= expr between_op expr AND expr",
    +- /* 222 */ "in_op ::= IN",
    +- /* 223 */ "in_op ::= NOT IN",
    +- /* 224 */ "expr ::= expr in_op LP exprlist RP",
    +- /* 225 */ "expr ::= LP select RP",
    +- /* 226 */ "expr ::= expr in_op LP select RP",
    +- /* 227 */ "expr ::= expr in_op nm dbnm",
    +- /* 228 */ "expr ::= EXISTS LP select RP",
    +- /* 229 */ "expr ::= CASE case_operand case_exprlist case_else END",
    +- /* 230 */ "case_exprlist ::= case_exprlist WHEN expr THEN expr",
    +- /* 231 */ "case_exprlist ::= WHEN expr THEN expr",
    +- /* 232 */ "case_else ::= ELSE expr",
    +- /* 233 */ "case_else ::=",
    +- /* 234 */ "case_operand ::= expr",
    +- /* 235 */ "case_operand ::=",
    +- /* 236 */ "exprlist ::= nexprlist",
    +- /* 237 */ "exprlist ::=",
    +- /* 238 */ "nexprlist ::= nexprlist COMMA expr",
    +- /* 239 */ "nexprlist ::= expr",
    +- /* 240 */ "cmd ::= createkw uniqueflag INDEX ifnotexists nm dbnm ON nm LP sortlist RP where_opt",
    +- /* 241 */ "uniqueflag ::= UNIQUE",
    +- /* 242 */ "uniqueflag ::=",
    +- /* 243 */ "eidlist_opt ::=",
    +- /* 244 */ "eidlist_opt ::= LP eidlist RP",
    +- /* 245 */ "eidlist ::= eidlist COMMA nm collate sortorder",
    +- /* 246 */ "eidlist ::= nm collate sortorder",
    +- /* 247 */ "collate ::=",
    +- /* 248 */ "collate ::= COLLATE ID|STRING",
    +- /* 249 */ "cmd ::= DROP INDEX ifexists fullname",
    +- /* 250 */ "cmd ::= VACUUM",
    +- /* 251 */ "cmd ::= VACUUM nm",
    +- /* 252 */ "cmd ::= PRAGMA nm dbnm",
    +- /* 253 */ "cmd ::= PRAGMA nm dbnm EQ nmnum",
    +- /* 254 */ "cmd ::= PRAGMA nm dbnm LP nmnum RP",
    +- /* 255 */ "cmd ::= PRAGMA nm dbnm EQ minus_num",
    +- /* 256 */ "cmd ::= PRAGMA nm dbnm LP minus_num RP",
    +- /* 257 */ "nmnum ::= plus_num",
    +- /* 258 */ "nmnum ::= nm",
    +- /* 259 */ "nmnum ::= ON",
    +- /* 260 */ "nmnum ::= DELETE",
    +- /* 261 */ "nmnum ::= DEFAULT",
    +- /* 262 */ "plus_num ::= PLUS INTEGER|FLOAT",
    +- /* 263 */ "plus_num ::= INTEGER|FLOAT",
    +- /* 264 */ "minus_num ::= MINUS INTEGER|FLOAT",
    +- /* 265 */ "cmd ::= createkw trigger_decl BEGIN trigger_cmd_list END",
    +- /* 266 */ "trigger_decl ::= temp TRIGGER ifnotexists nm dbnm trigger_time trigger_event ON fullname foreach_clause when_clause",
    +- /* 267 */ "trigger_time ::= BEFORE",
    +- /* 268 */ "trigger_time ::= AFTER",
    +- /* 269 */ "trigger_time ::= INSTEAD OF",
    +- /* 270 */ "trigger_time ::=",
    +- /* 271 */ "trigger_event ::= DELETE|INSERT",
    +- /* 272 */ "trigger_event ::= UPDATE",
    +- /* 273 */ "trigger_event ::= UPDATE OF idlist",
    +- /* 274 */ "foreach_clause ::=",
    +- /* 275 */ "foreach_clause ::= FOR EACH ROW",
    +- /* 276 */ "when_clause ::=",
    +- /* 277 */ "when_clause ::= WHEN expr",
    +- /* 278 */ "trigger_cmd_list ::= trigger_cmd_list trigger_cmd SEMI",
    +- /* 279 */ "trigger_cmd_list ::= trigger_cmd SEMI",
    +- /* 280 */ "trnm ::= nm",
    +- /* 281 */ "trnm ::= nm DOT nm",
    +- /* 282 */ "tridxby ::=",
    +- /* 283 */ "tridxby ::= INDEXED BY nm",
    +- /* 284 */ "tridxby ::= NOT INDEXED",
    +- /* 285 */ "trigger_cmd ::= UPDATE orconf trnm tridxby SET setlist where_opt",
    +- /* 286 */ "trigger_cmd ::= insert_cmd INTO trnm idlist_opt select",
    +- /* 287 */ "trigger_cmd ::= DELETE FROM trnm tridxby where_opt",
    +- /* 288 */ "trigger_cmd ::= select",
    +- /* 289 */ "expr ::= RAISE LP IGNORE RP",
    +- /* 290 */ "expr ::= RAISE LP raisetype COMMA nm RP",
    +- /* 291 */ "raisetype ::= ROLLBACK",
    +- /* 292 */ "raisetype ::= ABORT",
    +- /* 293 */ "raisetype ::= FAIL",
    +- /* 294 */ "cmd ::= DROP TRIGGER ifexists fullname",
    +- /* 295 */ "cmd ::= ATTACH database_kw_opt expr AS expr key_opt",
    +- /* 296 */ "cmd ::= DETACH database_kw_opt expr",
    +- /* 297 */ "key_opt ::=",
    +- /* 298 */ "key_opt ::= KEY expr",
    +- /* 299 */ "database_kw_opt ::= DATABASE",
    +- /* 300 */ "database_kw_opt ::=",
    +- /* 301 */ "cmd ::= REINDEX",
    +- /* 302 */ "cmd ::= REINDEX nm dbnm",
    +- /* 303 */ "cmd ::= ANALYZE",
    +- /* 304 */ "cmd ::= ANALYZE nm dbnm",
    +- /* 305 */ "cmd ::= ALTER TABLE fullname RENAME TO nm",
    +- /* 306 */ "cmd ::= ALTER TABLE add_column_fullname ADD kwcolumn_opt column",
    +- /* 307 */ "add_column_fullname ::= fullname",
    +- /* 308 */ "kwcolumn_opt ::=",
    +- /* 309 */ "kwcolumn_opt ::= COLUMNKW",
    +- /* 310 */ "cmd ::= create_vtab",
    +- /* 311 */ "cmd ::= create_vtab LP vtabarglist RP",
    +- /* 312 */ "create_vtab ::= createkw VIRTUAL TABLE ifnotexists nm dbnm USING nm",
    +- /* 313 */ "vtabarglist ::= vtabarg",
    +- /* 314 */ "vtabarglist ::= vtabarglist COMMA vtabarg",
    +- /* 315 */ "vtabarg ::=",
    +- /* 316 */ "vtabarg ::= vtabarg vtabargtoken",
    +- /* 317 */ "vtabargtoken ::= ANY",
    +- /* 318 */ "vtabargtoken ::= lp anylist RP",
    +- /* 319 */ "lp ::= LP",
    +- /* 320 */ "anylist ::=",
    +- /* 321 */ "anylist ::= anylist LP anylist RP",
    +- /* 322 */ "anylist ::= anylist ANY",
    +- /* 323 */ "with ::=",
    +- /* 324 */ "with ::= WITH wqlist",
    +- /* 325 */ "with ::= WITH RECURSIVE wqlist",
    +- /* 326 */ "wqlist ::= nm eidlist_opt AS LP select RP",
    +- /* 327 */ "wqlist ::= wqlist COMMA nm eidlist_opt AS LP select RP",
    ++ /*   0 */ "explain ::= EXPLAIN",
    ++ /*   1 */ "explain ::= EXPLAIN QUERY PLAN",
    ++ /*   2 */ "cmdx ::= cmd",
    ++ /*   3 */ "cmd ::= BEGIN transtype trans_opt",
    ++ /*   4 */ "transtype ::=",
    ++ /*   5 */ "transtype ::= DEFERRED",
    ++ /*   6 */ "transtype ::= IMMEDIATE",
    ++ /*   7 */ "transtype ::= EXCLUSIVE",
    ++ /*   8 */ "cmd ::= COMMIT|END trans_opt",
    ++ /*   9 */ "cmd ::= ROLLBACK trans_opt",
    ++ /*  10 */ "cmd ::= SAVEPOINT nm",
    ++ /*  11 */ "cmd ::= RELEASE savepoint_opt nm",
    ++ /*  12 */ "cmd ::= ROLLBACK trans_opt TO savepoint_opt nm",
    ++ /*  13 */ "create_table ::= createkw temp TABLE ifnotexists nm dbnm",
    ++ /*  14 */ "createkw ::= CREATE",
    ++ /*  15 */ "ifnotexists ::=",
    ++ /*  16 */ "ifnotexists ::= IF NOT EXISTS",
    ++ /*  17 */ "temp ::= TEMP",
    ++ /*  18 */ "temp ::=",
    ++ /*  19 */ "create_table_args ::= LP columnlist conslist_opt RP table_options",
    ++ /*  20 */ "create_table_args ::= AS select",
    ++ /*  21 */ "table_options ::=",
    ++ /*  22 */ "table_options ::= WITHOUT nm",
    ++ /*  23 */ "columnname ::= nm typetoken",
    ++ /*  24 */ "typetoken ::=",
    ++ /*  25 */ "typetoken ::= typename LP signed RP",
    ++ /*  26 */ "typetoken ::= typename LP signed COMMA signed RP",
    ++ /*  27 */ "typename ::= typename ID|STRING",
    ++ /*  28 */ "scanpt ::=",
    ++ /*  29 */ "ccons ::= CONSTRAINT nm",
    ++ /*  30 */ "ccons ::= DEFAULT scanpt term scanpt",
    ++ /*  31 */ "ccons ::= DEFAULT LP expr RP",
    ++ /*  32 */ "ccons ::= DEFAULT PLUS term scanpt",
    ++ /*  33 */ "ccons ::= DEFAULT MINUS term scanpt",
    ++ /*  34 */ "ccons ::= DEFAULT scanpt ID|INDEXED",
    ++ /*  35 */ "ccons ::= NOT NULL onconf",
    ++ /*  36 */ "ccons ::= PRIMARY KEY sortorder onconf autoinc",
    ++ /*  37 */ "ccons ::= UNIQUE onconf",
    ++ /*  38 */ "ccons ::= CHECK LP expr RP",
    ++ /*  39 */ "ccons ::= REFERENCES nm eidlist_opt refargs",
    ++ /*  40 */ "ccons ::= defer_subclause",
    ++ /*  41 */ "ccons ::= COLLATE ID|STRING",
    ++ /*  42 */ "autoinc ::=",
    ++ /*  43 */ "autoinc ::= AUTOINCR",
    ++ /*  44 */ "refargs ::=",
    ++ /*  45 */ "refargs ::= refargs refarg",
    ++ /*  46 */ "refarg ::= MATCH nm",
    ++ /*  47 */ "refarg ::= ON INSERT refact",
    ++ /*  48 */ "refarg ::= ON DELETE refact",
    ++ /*  49 */ "refarg ::= ON UPDATE refact",
    ++ /*  50 */ "refact ::= SET NULL",
    ++ /*  51 */ "refact ::= SET DEFAULT",
    ++ /*  52 */ "refact ::= CASCADE",
    ++ /*  53 */ "refact ::= RESTRICT",
    ++ /*  54 */ "refact ::= NO ACTION",
    ++ /*  55 */ "defer_subclause ::= NOT DEFERRABLE init_deferred_pred_opt",
    ++ /*  56 */ "defer_subclause ::= DEFERRABLE init_deferred_pred_opt",
    ++ /*  57 */ "init_deferred_pred_opt ::=",
    ++ /*  58 */ "init_deferred_pred_opt ::= INITIALLY DEFERRED",
    ++ /*  59 */ "init_deferred_pred_opt ::= INITIALLY IMMEDIATE",
    ++ /*  60 */ "conslist_opt ::=",
    ++ /*  61 */ "tconscomma ::= COMMA",
    ++ /*  62 */ "tcons ::= CONSTRAINT nm",
    ++ /*  63 */ "tcons ::= PRIMARY KEY LP sortlist autoinc RP onconf",
    ++ /*  64 */ "tcons ::= UNIQUE LP sortlist RP onconf",
    ++ /*  65 */ "tcons ::= CHECK LP expr RP onconf",
    ++ /*  66 */ "tcons ::= FOREIGN KEY LP eidlist RP REFERENCES nm eidlist_opt refargs defer_subclause_opt",
    ++ /*  67 */ "defer_subclause_opt ::=",
    ++ /*  68 */ "onconf ::=",
    ++ /*  69 */ "onconf ::= ON CONFLICT resolvetype",
    ++ /*  70 */ "orconf ::=",
    ++ /*  71 */ "orconf ::= OR resolvetype",
    ++ /*  72 */ "resolvetype ::= IGNORE",
    ++ /*  73 */ "resolvetype ::= REPLACE",
    ++ /*  74 */ "cmd ::= DROP TABLE ifexists fullname",
    ++ /*  75 */ "ifexists ::= IF EXISTS",
    ++ /*  76 */ "ifexists ::=",
    ++ /*  77 */ "cmd ::= createkw temp VIEW ifnotexists nm dbnm eidlist_opt AS select",
    ++ /*  78 */ "cmd ::= DROP VIEW ifexists fullname",
    ++ /*  79 */ "cmd ::= select",
    ++ /*  80 */ "select ::= with selectnowith",
    ++ /*  81 */ "selectnowith ::= selectnowith multiselect_op oneselect",
    ++ /*  82 */ "multiselect_op ::= UNION",
    ++ /*  83 */ "multiselect_op ::= UNION ALL",
    ++ /*  84 */ "multiselect_op ::= EXCEPT|INTERSECT",
    ++ /*  85 */ "oneselect ::= SELECT distinct selcollist from where_opt groupby_opt having_opt orderby_opt limit_opt",
    ++ /*  86 */ "values ::= VALUES LP nexprlist RP",
    ++ /*  87 */ "values ::= values COMMA LP exprlist RP",
    ++ /*  88 */ "distinct ::= DISTINCT",
    ++ /*  89 */ "distinct ::= ALL",
    ++ /*  90 */ "distinct ::=",
    ++ /*  91 */ "sclp ::=",
    ++ /*  92 */ "selcollist ::= sclp scanpt expr scanpt as",
    ++ /*  93 */ "selcollist ::= sclp scanpt STAR",
    ++ /*  94 */ "selcollist ::= sclp scanpt nm DOT STAR",
    ++ /*  95 */ "as ::= AS nm",
    ++ /*  96 */ "as ::=",
    ++ /*  97 */ "from ::=",
    ++ /*  98 */ "from ::= FROM seltablist",
    ++ /*  99 */ "stl_prefix ::= seltablist joinop",
    ++ /* 100 */ "stl_prefix ::=",
    ++ /* 101 */ "seltablist ::= stl_prefix nm dbnm as indexed_opt on_opt using_opt",
    ++ /* 102 */ "seltablist ::= stl_prefix nm dbnm LP exprlist RP as on_opt using_opt",
    ++ /* 103 */ "seltablist ::= stl_prefix LP select RP as on_opt using_opt",
    ++ /* 104 */ "seltablist ::= stl_prefix LP seltablist RP as on_opt using_opt",
    ++ /* 105 */ "dbnm ::=",
    ++ /* 106 */ "dbnm ::= DOT nm",
    ++ /* 107 */ "fullname ::= nm dbnm",
    ++ /* 108 */ "joinop ::= COMMA|JOIN",
    ++ /* 109 */ "joinop ::= JOIN_KW JOIN",
    ++ /* 110 */ "joinop ::= JOIN_KW nm JOIN",
    ++ /* 111 */ "joinop ::= JOIN_KW nm nm JOIN",
    ++ /* 112 */ "on_opt ::= ON expr",
    ++ /* 113 */ "on_opt ::=",
    ++ /* 114 */ "indexed_opt ::=",
    ++ /* 115 */ "indexed_opt ::= INDEXED BY nm",
    ++ /* 116 */ "indexed_opt ::= NOT INDEXED",
    ++ /* 117 */ "using_opt ::= USING LP idlist RP",
    ++ /* 118 */ "using_opt ::=",
    ++ /* 119 */ "orderby_opt ::=",
    ++ /* 120 */ "orderby_opt ::= ORDER BY sortlist",
    ++ /* 121 */ "sortlist ::= sortlist COMMA expr sortorder",
    ++ /* 122 */ "sortlist ::= expr sortorder",
    ++ /* 123 */ "sortorder ::= ASC",
    ++ /* 124 */ "sortorder ::= DESC",
    ++ /* 125 */ "sortorder ::=",
    ++ /* 126 */ "groupby_opt ::=",
    ++ /* 127 */ "groupby_opt ::= GROUP BY nexprlist",
    ++ /* 128 */ "having_opt ::=",
    ++ /* 129 */ "having_opt ::= HAVING expr",
    ++ /* 130 */ "limit_opt ::=",
    ++ /* 131 */ "limit_opt ::= LIMIT expr",
    ++ /* 132 */ "limit_opt ::= LIMIT expr OFFSET expr",
    ++ /* 133 */ "limit_opt ::= LIMIT expr COMMA expr",
    ++ /* 134 */ "cmd ::= with DELETE FROM fullname indexed_opt where_opt",
    ++ /* 135 */ "where_opt ::=",
    ++ /* 136 */ "where_opt ::= WHERE expr",
    ++ /* 137 */ "cmd ::= with UPDATE orconf fullname indexed_opt SET setlist where_opt",
    ++ /* 138 */ "setlist ::= setlist COMMA nm EQ expr",
    ++ /* 139 */ "setlist ::= setlist COMMA LP idlist RP EQ expr",
    ++ /* 140 */ "setlist ::= nm EQ expr",
    ++ /* 141 */ "setlist ::= LP idlist RP EQ expr",
    ++ /* 142 */ "cmd ::= with insert_cmd INTO fullname idlist_opt select",
    ++ /* 143 */ "cmd ::= with insert_cmd INTO fullname idlist_opt DEFAULT VALUES",
    ++ /* 144 */ "insert_cmd ::= INSERT orconf",
    ++ /* 145 */ "insert_cmd ::= REPLACE",
    ++ /* 146 */ "idlist_opt ::=",
    ++ /* 147 */ "idlist_opt ::= LP idlist RP",
    ++ /* 148 */ "idlist ::= idlist COMMA nm",
    ++ /* 149 */ "idlist ::= nm",
    ++ /* 150 */ "expr ::= LP expr RP",
    ++ /* 151 */ "expr ::= ID|INDEXED",
    ++ /* 152 */ "expr ::= JOIN_KW",
    ++ /* 153 */ "expr ::= nm DOT nm",
    ++ /* 154 */ "expr ::= nm DOT nm DOT nm",
    ++ /* 155 */ "term ::= NULL|FLOAT|BLOB",
    ++ /* 156 */ "term ::= STRING",
    ++ /* 157 */ "term ::= INTEGER",
    ++ /* 158 */ "expr ::= VARIABLE",
    ++ /* 159 */ "expr ::= expr COLLATE ID|STRING",
    ++ /* 160 */ "expr ::= CAST LP expr AS typetoken RP",
    ++ /* 161 */ "expr ::= ID|INDEXED LP distinct exprlist RP",
    ++ /* 162 */ "expr ::= ID|INDEXED LP STAR RP",
    ++ /* 163 */ "term ::= CTIME_KW",
    ++ /* 164 */ "expr ::= LP nexprlist COMMA expr RP",
    ++ /* 165 */ "expr ::= expr AND expr",
    ++ /* 166 */ "expr ::= expr OR expr",
    ++ /* 167 */ "expr ::= expr LT|GT|GE|LE expr",
    ++ /* 168 */ "expr ::= expr EQ|NE expr",
    ++ /* 169 */ "expr ::= expr BITAND|BITOR|LSHIFT|RSHIFT expr",
    ++ /* 170 */ "expr ::= expr PLUS|MINUS expr",
    ++ /* 171 */ "expr ::= expr STAR|SLASH|REM expr",
    ++ /* 172 */ "expr ::= expr CONCAT expr",
    ++ /* 173 */ "likeop ::= NOT LIKE_KW|MATCH",
    ++ /* 174 */ "expr ::= expr likeop expr",
    ++ /* 175 */ "expr ::= expr likeop expr ESCAPE expr",
    ++ /* 176 */ "expr ::= expr ISNULL|NOTNULL",
    ++ /* 177 */ "expr ::= expr NOT NULL",
    ++ /* 178 */ "expr ::= expr IS expr",
    ++ /* 179 */ "expr ::= expr IS NOT expr",
    ++ /* 180 */ "expr ::= NOT expr",
    ++ /* 181 */ "expr ::= BITNOT expr",
    ++ /* 182 */ "expr ::= MINUS expr",
    ++ /* 183 */ "expr ::= PLUS expr",
    ++ /* 184 */ "between_op ::= BETWEEN",
    ++ /* 185 */ "between_op ::= NOT BETWEEN",
    ++ /* 186 */ "expr ::= expr between_op expr AND expr",
    ++ /* 187 */ "in_op ::= IN",
    ++ /* 188 */ "in_op ::= NOT IN",
    ++ /* 189 */ "expr ::= expr in_op LP exprlist RP",
    ++ /* 190 */ "expr ::= LP select RP",
    ++ /* 191 */ "expr ::= expr in_op LP select RP",
    ++ /* 192 */ "expr ::= expr in_op nm dbnm paren_exprlist",
    ++ /* 193 */ "expr ::= EXISTS LP select RP",
    ++ /* 194 */ "expr ::= CASE case_operand case_exprlist case_else END",
    ++ /* 195 */ "case_exprlist ::= case_exprlist WHEN expr THEN expr",
    ++ /* 196 */ "case_exprlist ::= WHEN expr THEN expr",
    ++ /* 197 */ "case_else ::= ELSE expr",
    ++ /* 198 */ "case_else ::=",
    ++ /* 199 */ "case_operand ::= expr",
    ++ /* 200 */ "case_operand ::=",
    ++ /* 201 */ "exprlist ::=",
    ++ /* 202 */ "nexprlist ::= nexprlist COMMA expr",
    ++ /* 203 */ "nexprlist ::= expr",
    ++ /* 204 */ "paren_exprlist ::=",
    ++ /* 205 */ "paren_exprlist ::= LP exprlist RP",
    ++ /* 206 */ "cmd ::= createkw uniqueflag INDEX ifnotexists nm dbnm ON nm LP sortlist RP where_opt",
    ++ /* 207 */ "uniqueflag ::= UNIQUE",
    ++ /* 208 */ "uniqueflag ::=",
    ++ /* 209 */ "eidlist_opt ::=",
    ++ /* 210 */ "eidlist_opt ::= LP eidlist RP",
    ++ /* 211 */ "eidlist ::= eidlist COMMA nm collate sortorder",
    ++ /* 212 */ "eidlist ::= nm collate sortorder",
    ++ /* 213 */ "collate ::=",
    ++ /* 214 */ "collate ::= COLLATE ID|STRING",
    ++ /* 215 */ "cmd ::= DROP INDEX ifexists fullname",
    ++ /* 216 */ "cmd ::= VACUUM",
    ++ /* 217 */ "cmd ::= VACUUM nm",
    ++ /* 218 */ "cmd ::= PRAGMA nm dbnm",
    ++ /* 219 */ "cmd ::= PRAGMA nm dbnm EQ nmnum",
    ++ /* 220 */ "cmd ::= PRAGMA nm dbnm LP nmnum RP",
    ++ /* 221 */ "cmd ::= PRAGMA nm dbnm EQ minus_num",
    ++ /* 222 */ "cmd ::= PRAGMA nm dbnm LP minus_num RP",
    ++ /* 223 */ "plus_num ::= PLUS INTEGER|FLOAT",
    ++ /* 224 */ "minus_num ::= MINUS INTEGER|FLOAT",
    ++ /* 225 */ "cmd ::= createkw trigger_decl BEGIN trigger_cmd_list END",
    ++ /* 226 */ "trigger_decl ::= temp TRIGGER ifnotexists nm dbnm trigger_time trigger_event ON fullname foreach_clause when_clause",
    ++ /* 227 */ "trigger_time ::= BEFORE|AFTER",
    ++ /* 228 */ "trigger_time ::= INSTEAD OF",
    ++ /* 229 */ "trigger_time ::=",
    ++ /* 230 */ "trigger_event ::= DELETE|INSERT",
    ++ /* 231 */ "trigger_event ::= UPDATE",
    ++ /* 232 */ "trigger_event ::= UPDATE OF idlist",
    ++ /* 233 */ "when_clause ::=",
    ++ /* 234 */ "when_clause ::= WHEN expr",
    ++ /* 235 */ "trigger_cmd_list ::= trigger_cmd_list trigger_cmd SEMI",
    ++ /* 236 */ "trigger_cmd_list ::= trigger_cmd SEMI",
    ++ /* 237 */ "trnm ::= nm DOT nm",
    ++ /* 238 */ "tridxby ::= INDEXED BY nm",
    ++ /* 239 */ "tridxby ::= NOT INDEXED",
    ++ /* 240 */ "trigger_cmd ::= UPDATE orconf trnm tridxby SET setlist where_opt scanpt",
    ++ /* 241 */ "trigger_cmd ::= scanpt insert_cmd INTO trnm idlist_opt select scanpt",
    ++ /* 242 */ "trigger_cmd ::= DELETE FROM trnm tridxby where_opt scanpt",
    ++ /* 243 */ "trigger_cmd ::= scanpt select scanpt",
    ++ /* 244 */ "expr ::= RAISE LP IGNORE RP",
    ++ /* 245 */ "expr ::= RAISE LP raisetype COMMA nm RP",
    ++ /* 246 */ "raisetype ::= ROLLBACK",
    ++ /* 247 */ "raisetype ::= ABORT",
    ++ /* 248 */ "raisetype ::= FAIL",
    ++ /* 249 */ "cmd ::= DROP TRIGGER ifexists fullname",
    ++ /* 250 */ "cmd ::= ATTACH database_kw_opt expr AS expr key_opt",
    ++ /* 251 */ "cmd ::= DETACH database_kw_opt expr",
    ++ /* 252 */ "key_opt ::=",
    ++ /* 253 */ "key_opt ::= KEY expr",
    ++ /* 254 */ "cmd ::= REINDEX",
    ++ /* 255 */ "cmd ::= REINDEX nm dbnm",
    ++ /* 256 */ "cmd ::= ANALYZE",
    ++ /* 257 */ "cmd ::= ANALYZE nm dbnm",
    ++ /* 258 */ "cmd ::= ALTER TABLE fullname RENAME TO nm",
    ++ /* 259 */ "cmd ::= ALTER TABLE add_column_fullname ADD kwcolumn_opt columnname carglist",
    ++ /* 260 */ "add_column_fullname ::= fullname",
    ++ /* 261 */ "cmd ::= create_vtab",
    ++ /* 262 */ "cmd ::= create_vtab LP vtabarglist RP",
    ++ /* 263 */ "create_vtab ::= createkw VIRTUAL TABLE ifnotexists nm dbnm USING nm",
    ++ /* 264 */ "vtabarg ::=",
    ++ /* 265 */ "vtabargtoken ::= ANY",
    ++ /* 266 */ "vtabargtoken ::= lp anylist RP",
    ++ /* 267 */ "lp ::= LP",
    ++ /* 268 */ "with ::=",
    ++ /* 269 */ "with ::= WITH wqlist",
    ++ /* 270 */ "with ::= WITH RECURSIVE wqlist",
    ++ /* 271 */ "wqlist ::= nm eidlist_opt AS LP select RP",
    ++ /* 272 */ "wqlist ::= wqlist COMMA nm eidlist_opt AS LP select RP",
    ++ /* 273 */ "input ::= cmdlist",
    ++ /* 274 */ "cmdlist ::= cmdlist ecmd",
    ++ /* 275 */ "cmdlist ::= ecmd",
    ++ /* 276 */ "ecmd ::= SEMI",
    ++ /* 277 */ "ecmd ::= explain cmdx SEMI",
    ++ /* 278 */ "explain ::=",
    ++ /* 279 */ "trans_opt ::=",
    ++ /* 280 */ "trans_opt ::= TRANSACTION",
    ++ /* 281 */ "trans_opt ::= TRANSACTION nm",
    ++ /* 282 */ "savepoint_opt ::= SAVEPOINT",
    ++ /* 283 */ "savepoint_opt ::=",
    ++ /* 284 */ "cmd ::= create_table create_table_args",
    ++ /* 285 */ "columnlist ::= columnlist COMMA columnname carglist",
    ++ /* 286 */ "columnlist ::= columnname carglist",
    ++ /* 287 */ "nm ::= ID|INDEXED",
    ++ /* 288 */ "nm ::= STRING",
    ++ /* 289 */ "nm ::= JOIN_KW",
    ++ /* 290 */ "typetoken ::= typename",
    ++ /* 291 */ "typename ::= ID|STRING",
    ++ /* 292 */ "signed ::= plus_num",
    ++ /* 293 */ "signed ::= minus_num",
    ++ /* 294 */ "carglist ::= carglist ccons",
    ++ /* 295 */ "carglist ::=",
    ++ /* 296 */ "ccons ::= NULL onconf",
    ++ /* 297 */ "conslist_opt ::= COMMA conslist",
    ++ /* 298 */ "conslist ::= conslist tconscomma tcons",
    ++ /* 299 */ "conslist ::= tcons",
    ++ /* 300 */ "tconscomma ::=",
    ++ /* 301 */ "defer_subclause_opt ::= defer_subclause",
    ++ /* 302 */ "resolvetype ::= raisetype",
    ++ /* 303 */ "selectnowith ::= oneselect",
    ++ /* 304 */ "oneselect ::= values",
    ++ /* 305 */ "sclp ::= selcollist COMMA",
    ++ /* 306 */ "as ::= ID|STRING",
    ++ /* 307 */ "expr ::= term",
    ++ /* 308 */ "likeop ::= LIKE_KW|MATCH",
    ++ /* 309 */ "exprlist ::= nexprlist",
    ++ /* 310 */ "nmnum ::= plus_num",
    ++ /* 311 */ "nmnum ::= nm",
    ++ /* 312 */ "nmnum ::= ON",
    ++ /* 313 */ "nmnum ::= DELETE",
    ++ /* 314 */ "nmnum ::= DEFAULT",
    ++ /* 315 */ "plus_num ::= INTEGER|FLOAT",
    ++ /* 316 */ "foreach_clause ::=",
    ++ /* 317 */ "foreach_clause ::= FOR EACH ROW",
    ++ /* 318 */ "trnm ::= nm",
    ++ /* 319 */ "tridxby ::=",
    ++ /* 320 */ "database_kw_opt ::= DATABASE",
    ++ /* 321 */ "database_kw_opt ::=",
    ++ /* 322 */ "kwcolumn_opt ::=",
    ++ /* 323 */ "kwcolumn_opt ::= COLUMNKW",
    ++ /* 324 */ "vtabarglist ::= vtabarg",
    ++ /* 325 */ "vtabarglist ::= vtabarglist COMMA vtabarg",
    ++ /* 326 */ "vtabarg ::= vtabarg vtabargtoken",
    ++ /* 327 */ "anylist ::=",
    ++ /* 328 */ "anylist ::= anylist LP anylist RP",
    ++ /* 329 */ "anylist ::= anylist ANY",
    + };
    + #endif /* NDEBUG */
    + 
    + 
    + #if YYSTACKDEPTH<=0
    + /*
    +-** Try to increase the size of the parser stack.
    ++** Try to increase the size of the parser stack.  Return the number
    ++** of errors.  Return 0 on success.
    + */
    +-static void yyGrowStack(yyParser *p){
    ++static int yyGrowStack(yyParser *p){
    +   int newSize;
    ++  int idx;
    +   yyStackEntry *pNew;
    + 
    +   newSize = p->yystksz*2 + 100;
    +-  pNew = realloc(p->yystack, newSize*sizeof(pNew[0]));
    ++  idx = p->yytos ? (int)(p->yytos - p->yystack) : 0;
    ++  if( p->yystack==&p->yystk0 ){
    ++    pNew = malloc(newSize*sizeof(pNew[0]));
    ++    if( pNew ) pNew[0] = p->yystk0;
    ++  }else{
    ++    pNew = realloc(p->yystack, newSize*sizeof(pNew[0]));
    ++  }
    +   if( pNew ){
    +     p->yystack = pNew;
    +-    p->yystksz = newSize;
    ++    p->yytos = &p->yystack[idx];
    + #ifndef NDEBUG
    +     if( yyTraceFILE ){
    +-      fprintf(yyTraceFILE,"%sStack grows to %d entries!\n",
    +-              yyTracePrompt, p->yystksz);
    ++      fprintf(yyTraceFILE,"%sStack grows from %d to %d entries.\n",
    ++              yyTracePrompt, p->yystksz, newSize);
    +     }
    + #endif
    ++    p->yystksz = newSize;
    +   }
    ++  return pNew==0; 
    + }
    + #endif
    + 
    ++/* Datatype of the argument to the memory allocated passed as the
    ++** second argument to sqlite3ParserAlloc() below.  This can be changed by
    ++** putting an appropriate #define in the %include section of the input
    ++** grammar.
    ++*/
    ++#ifndef YYMALLOCARGTYPE
    ++# define YYMALLOCARGTYPE size_t
    ++#endif
    ++
    ++/* Initialize a new parser that has already been allocated.
    ++*/
    ++SQLITE_PRIVATE void sqlite3ParserInit(void *yypParser){
    ++  yyParser *pParser = (yyParser*)yypParser;
    ++#ifdef YYTRACKMAXSTACKDEPTH
    ++  pParser->yyhwm = 0;
    ++#endif
    ++#if YYSTACKDEPTH<=0
    ++  pParser->yytos = NULL;
    ++  pParser->yystack = NULL;
    ++  pParser->yystksz = 0;
    ++  if( yyGrowStack(pParser) ){
    ++    pParser->yystack = &pParser->yystk0;
    ++    pParser->yystksz = 1;
    ++  }
    ++#endif
    ++#ifndef YYNOERRORRECOVERY
    ++  pParser->yyerrcnt = -1;
    ++#endif
    ++  pParser->yytos = pParser->yystack;
    ++  pParser->yystack[0].stateno = 0;
    ++  pParser->yystack[0].major = 0;
    ++#if YYSTACKDEPTH>0
    ++  pParser->yystackEnd = &pParser->yystack[YYSTACKDEPTH-1];
    ++#endif
    ++}
    ++
    ++#ifndef sqlite3Parser_ENGINEALWAYSONSTACK
    + /* 
    + ** This function allocates a new parser.
    + ** The only argument is a pointer to a function which works like
    +@@ -127390,27 +139771,21 @@ static void yyGrowStack(yyParser *p){
    + ** A pointer to a parser.  This pointer is used in subsequent calls
    + ** to sqlite3Parser and sqlite3ParserFree.
    + */
    +-SQLITE_PRIVATE void *sqlite3ParserAlloc(void *(*mallocProc)(u64)){
    ++SQLITE_PRIVATE void *sqlite3ParserAlloc(void *(*mallocProc)(YYMALLOCARGTYPE)){
    +   yyParser *pParser;
    +-  pParser = (yyParser*)(*mallocProc)( (u64)sizeof(yyParser) );
    +-  if( pParser ){
    +-    pParser->yyidx = -1;
    +-#ifdef YYTRACKMAXSTACKDEPTH
    +-    pParser->yyidxMax = 0;
    +-#endif
    +-#if YYSTACKDEPTH<=0
    +-    pParser->yystack = NULL;
    +-    pParser->yystksz = 0;
    +-    yyGrowStack(pParser);
    +-#endif
    +-  }
    ++  pParser = (yyParser*)(*mallocProc)( (YYMALLOCARGTYPE)sizeof(yyParser) );
    ++  if( pParser ) sqlite3ParserInit(pParser);
    +   return pParser;
    + }
    ++#endif /* sqlite3Parser_ENGINEALWAYSONSTACK */
    ++
    + 
    +-/* The following function deletes the value associated with a
    +-** symbol.  The symbol can be either a terminal or nonterminal.
    +-** "yymajor" is the symbol code, and "yypminor" is a pointer to
    +-** the value.
    ++/* The following function deletes the "minor type" or semantic value
    ++** associated with a symbol.  The symbol can be either a terminal
    ++** or nonterminal. "yymajor" is the symbol code, and "yypminor" is
    ++** a pointer to the value to be deleted.  The code used to do the 
    ++** deletions is derived from the %destructor and/or %token_destructor
    ++** directives of the input grammar.
    + */
    + static void yy_destructor(
    +   yyParser *yypParser,    /* The parser */
    +@@ -127426,81 +139801,80 @@ static void yy_destructor(
    +     ** being destroyed before it is finished parsing.
    +     **
    +     ** Note: during a reduce, the only symbols destroyed are those
    +-    ** which appear on the RHS of the rule, but which are not used
    ++    ** which appear on the RHS of the rule, but which are *not* used
    +     ** inside the C code.
    +     */
    ++/********* Begin destructor definitions ***************************************/
    +     case 163: /* select */
    +-    case 196: /* selectnowith */
    +-    case 197: /* oneselect */
    +-    case 208: /* values */
    +-{
    +-sqlite3SelectDelete(pParse->db, (yypminor->yy3));
    +-}
    +-      break;
    +-    case 174: /* term */
    +-    case 175: /* expr */
    ++    case 195: /* selectnowith */
    ++    case 196: /* oneselect */
    ++    case 207: /* values */
    + {
    +-sqlite3ExprDelete(pParse->db, (yypminor->yy346).pExpr);
    ++sqlite3SelectDelete(pParse->db, (yypminor->yy387));
    + }
    +       break;
    +-    case 179: /* eidlist_opt */
    +-    case 188: /* sortlist */
    +-    case 189: /* eidlist */
    +-    case 201: /* selcollist */
    +-    case 204: /* groupby_opt */
    +-    case 206: /* orderby_opt */
    +-    case 209: /* nexprlist */
    +-    case 210: /* exprlist */
    +-    case 211: /* sclp */
    +-    case 221: /* setlist */
    +-    case 228: /* case_exprlist */
    ++    case 173: /* term */
    ++    case 174: /* expr */
    ++    case 202: /* where_opt */
    ++    case 204: /* having_opt */
    ++    case 216: /* on_opt */
    ++    case 226: /* case_operand */
    ++    case 228: /* case_else */
    ++    case 237: /* when_clause */
    ++    case 242: /* key_opt */
    + {
    +-sqlite3ExprListDelete(pParse->db, (yypminor->yy14));
    ++sqlite3ExprDelete(pParse->db, (yypminor->yy314));
    + }
    +       break;
    +-    case 195: /* fullname */
    +-    case 202: /* from */
    +-    case 213: /* seltablist */
    +-    case 214: /* stl_prefix */
    ++    case 178: /* eidlist_opt */
    ++    case 187: /* sortlist */
    ++    case 188: /* eidlist */
    ++    case 200: /* selcollist */
    ++    case 203: /* groupby_opt */
    ++    case 205: /* orderby_opt */
    ++    case 208: /* nexprlist */
    ++    case 209: /* exprlist */
    ++    case 210: /* sclp */
    ++    case 219: /* setlist */
    ++    case 225: /* paren_exprlist */
    ++    case 227: /* case_exprlist */
    + {
    +-sqlite3SrcListDelete(pParse->db, (yypminor->yy65));
    ++sqlite3ExprListDelete(pParse->db, (yypminor->yy322));
    + }
    +       break;
    +-    case 198: /* with */
    +-    case 252: /* wqlist */
    ++    case 194: /* fullname */
    ++    case 201: /* from */
    ++    case 212: /* seltablist */
    ++    case 213: /* stl_prefix */
    + {
    +-sqlite3WithDelete(pParse->db, (yypminor->yy59));
    ++sqlite3SrcListDelete(pParse->db, (yypminor->yy259));
    + }
    +       break;
    +-    case 203: /* where_opt */
    +-    case 205: /* having_opt */
    +-    case 217: /* on_opt */
    +-    case 227: /* case_operand */
    +-    case 229: /* case_else */
    +-    case 238: /* when_clause */
    +-    case 243: /* key_opt */
    ++    case 197: /* with */
    ++    case 251: /* wqlist */
    + {
    +-sqlite3ExprDelete(pParse->db, (yypminor->yy132));
    ++sqlite3WithDelete(pParse->db, (yypminor->yy451));
    + }
    +       break;
    +-    case 218: /* using_opt */
    +-    case 220: /* idlist */
    +-    case 223: /* idlist_opt */
    ++    case 217: /* using_opt */
    ++    case 218: /* idlist */
    ++    case 221: /* idlist_opt */
    + {
    +-sqlite3IdListDelete(pParse->db, (yypminor->yy408));
    ++sqlite3IdListDelete(pParse->db, (yypminor->yy384));
    + }
    +       break;
    +-    case 234: /* trigger_cmd_list */
    +-    case 239: /* trigger_cmd */
    ++    case 233: /* trigger_cmd_list */
    ++    case 238: /* trigger_cmd */
    + {
    +-sqlite3DeleteTriggerStep(pParse->db, (yypminor->yy473));
    ++sqlite3DeleteTriggerStep(pParse->db, (yypminor->yy203));
    + }
    +       break;
    +-    case 236: /* trigger_event */
    ++    case 235: /* trigger_event */
    + {
    +-sqlite3IdListDelete(pParse->db, (yypminor->yy378).b);
    ++sqlite3IdListDelete(pParse->db, (yypminor->yy90).b);
    + }
    +       break;
    ++/********* End destructor definitions *****************************************/
    +     default:  break;   /* If no destructor action specified: do nothing */
    +   }
    + }
    +@@ -127510,55 +139884,53 @@ sqlite3IdListDelete(pParse->db, (yypminor->yy378).b);
    + **
    + ** If there is a destructor routine associated with the token which
    + ** is popped from the stack, then call it.
    +-**
    +-** Return the major token number for the symbol popped.
    + */
    +-static int yy_pop_parser_stack(yyParser *pParser){
    +-  YYCODETYPE yymajor;
    +-  yyStackEntry *yytos = &pParser->yystack[pParser->yyidx];
    +-
    +-  /* There is no mechanism by which the parser stack can be popped below
    +-  ** empty in SQLite.  */
    +-  assert( pParser->yyidx>=0 );
    ++static void yy_pop_parser_stack(yyParser *pParser){
    ++  yyStackEntry *yytos;
    ++  assert( pParser->yytos!=0 );
    ++  assert( pParser->yytos > pParser->yystack );
    ++  yytos = pParser->yytos--;
    + #ifndef NDEBUG
    +-  if( yyTraceFILE && pParser->yyidx>=0 ){
    ++  if( yyTraceFILE ){
    +     fprintf(yyTraceFILE,"%sPopping %s\n",
    +       yyTracePrompt,
    +       yyTokenName[yytos->major]);
    +   }
    + #endif
    +-  yymajor = yytos->major;
    +-  yy_destructor(pParser, yymajor, &yytos->minor);
    +-  pParser->yyidx--;
    +-  return yymajor;
    ++  yy_destructor(pParser, yytos->major, &yytos->minor);
    + }
    + 
    ++/*
    ++** Clear all secondary memory allocations from the parser
    ++*/
    ++SQLITE_PRIVATE void sqlite3ParserFinalize(void *p){
    ++  yyParser *pParser = (yyParser*)p;
    ++  while( pParser->yytos>pParser->yystack ) yy_pop_parser_stack(pParser);
    ++#if YYSTACKDEPTH<=0
    ++  if( pParser->yystack!=&pParser->yystk0 ) free(pParser->yystack);
    ++#endif
    ++}
    ++
    ++#ifndef sqlite3Parser_ENGINEALWAYSONSTACK
    + /* 
    +-** Deallocate and destroy a parser.  Destructors are all called for
    ++** Deallocate and destroy a parser.  Destructors are called for
    + ** all stack elements before shutting the parser down.
    + **
    +-** Inputs:
    +-** <ul>
    +-** <li>  A pointer to the parser.  This should be a pointer
    +-**       obtained from sqlite3ParserAlloc.
    +-** <li>  A pointer to a function used to reclaim memory obtained
    +-**       from malloc.
    +-** </ul>
    ++** If the YYPARSEFREENEVERNULL macro exists (for example because it
    ++** is defined in a %include section of the input grammar) then it is
    ++** assumed that the input pointer is never NULL.
    + */
    + SQLITE_PRIVATE void sqlite3ParserFree(
    +   void *p,                    /* The parser to be deleted */
    +   void (*freeProc)(void*)     /* Function used to reclaim memory */
    + ){
    +-  yyParser *pParser = (yyParser*)p;
    +-  /* In SQLite, we never try to destroy a parser that was not successfully
    +-  ** created in the first place. */
    +-  if( NEVER(pParser==0) ) return;
    +-  while( pParser->yyidx>=0 ) yy_pop_parser_stack(pParser);
    +-#if YYSTACKDEPTH<=0
    +-  free(pParser->yystack);
    ++#ifndef YYPARSEFREENEVERNULL
    ++  if( p==0 ) return;
    + #endif
    +-  (*freeProc)((void*)pParser);
    ++  sqlite3ParserFinalize(p);
    ++  (*freeProc)(p);
    + }
    ++#endif /* sqlite3Parser_ENGINEALWAYSONSTACK */
    + 
    + /*
    + ** Return the peak depth of the stack for a parser.
    +@@ -127566,33 +139938,70 @@ SQLITE_PRIVATE void sqlite3ParserFree(
    + #ifdef YYTRACKMAXSTACKDEPTH
    + SQLITE_PRIVATE int sqlite3ParserStackPeak(void *p){
    +   yyParser *pParser = (yyParser*)p;
    +-  return pParser->yyidxMax;
    ++  return pParser->yyhwm;
    ++}
    ++#endif
    ++
    ++/* This array of booleans keeps track of the parser statement
    ++** coverage.  The element yycoverage[X][Y] is set when the parser
    ++** is in state X and has a lookahead token Y.  In a well-tested
    ++** systems, every element of this matrix should end up being set.
    ++*/
    ++#if defined(YYCOVERAGE)
    ++static unsigned char yycoverage[YYNSTATE][YYNTOKEN];
    ++#endif
    ++
    ++/*
    ++** Write into out a description of every state/lookahead combination that
    ++**
    ++**   (1)  has not been used by the parser, and
    ++**   (2)  is not a syntax error.
    ++**
    ++** Return the number of missed state/lookahead combinations.
    ++*/
    ++#if defined(YYCOVERAGE)
    ++SQLITE_PRIVATE int sqlite3ParserCoverage(FILE *out){
    ++  int stateno, iLookAhead, i;
    ++  int nMissed = 0;
    ++  for(stateno=0; stateno<YYNSTATE; stateno++){
    ++    i = yy_shift_ofst[stateno];
    ++    for(iLookAhead=0; iLookAhead<YYNTOKEN; iLookAhead++){
    ++      if( yy_lookahead[i+iLookAhead]!=iLookAhead ) continue;
    ++      if( yycoverage[stateno][iLookAhead]==0 ) nMissed++;
    ++      if( out ){
    ++        fprintf(out,"State %d lookahead %s %s\n", stateno,
    ++                yyTokenName[iLookAhead],
    ++                yycoverage[stateno][iLookAhead] ? "ok" : "missed");
    ++      }
    ++    }
    ++  }
    ++  return nMissed;
    + }
    + #endif
    + 
    + /*
    + ** Find the appropriate action for a parser given the terminal
    + ** look-ahead token iLookAhead.
    +-**
    +-** If the look-ahead token is YYNOCODE, then check to see if the action is
    +-** independent of the look-ahead.  If it is, return the action, otherwise
    +-** return YY_NO_ACTION.
    + */
    +-static int yy_find_shift_action(
    ++static unsigned int yy_find_shift_action(
    +   yyParser *pParser,        /* The parser */
    +   YYCODETYPE iLookAhead     /* The look-ahead token */
    + ){
    +   int i;
    +-  int stateno = pParser->yystack[pParser->yyidx].stateno;
    ++  int stateno = pParser->yytos->stateno;
    +  
    +-  if( stateno>=YY_MIN_REDUCE ) return stateno;
    ++  if( stateno>YY_MAX_SHIFT ) return stateno;
    +   assert( stateno <= YY_SHIFT_COUNT );
    +-  i = yy_shift_ofst[stateno];
    +-  if( i==YY_SHIFT_USE_DFLT ) return yy_default[stateno];
    +-  assert( iLookAhead!=YYNOCODE );
    +-  i += iLookAhead;
    +-  if( i<0 || i>=YY_ACTTAB_COUNT || yy_lookahead[i]!=iLookAhead ){
    +-    if( iLookAhead>0 ){
    ++#if defined(YYCOVERAGE)
    ++  yycoverage[stateno][iLookAhead] = 1;
    ++#endif
    ++  do{
    ++    i = yy_shift_ofst[stateno];
    ++    assert( i>=0 && i+YYNTOKEN<=sizeof(yy_lookahead)/sizeof(yy_lookahead[0]) );
    ++    assert( iLookAhead!=YYNOCODE );
    ++    assert( iLookAhead < YYNTOKEN );
    ++    i += iLookAhead;
    ++    if( yy_lookahead[i]!=iLookAhead ){
    + #ifdef YYFALLBACK
    +       YYCODETYPE iFallback;            /* Fallback token */
    +       if( iLookAhead<sizeof(yyFallback)/sizeof(yyFallback[0])
    +@@ -127603,7 +140012,9 @@ static int yy_find_shift_action(
    +              yyTracePrompt, yyTokenName[iLookAhead], yyTokenName[iFallback]);
    +         }
    + #endif
    +-        return yy_find_shift_action(pParser, iFallback);
    ++        assert( yyFallback[iFallback]==0 ); /* Fallback loop must terminate */
    ++        iLookAhead = iFallback;
    ++        continue;
    +       }
    + #endif
    + #ifdef YYWILDCARD
    +@@ -127616,32 +140027,29 @@ static int yy_find_shift_action(
    + #if YY_SHIFT_MAX+YYWILDCARD>=YY_ACTTAB_COUNT
    +           j<YY_ACTTAB_COUNT &&
    + #endif
    +-          yy_lookahead[j]==YYWILDCARD
    ++          yy_lookahead[j]==YYWILDCARD && iLookAhead>0
    +         ){
    + #ifndef NDEBUG
    +           if( yyTraceFILE ){
    +             fprintf(yyTraceFILE, "%sWILDCARD %s => %s\n",
    +-               yyTracePrompt, yyTokenName[iLookAhead], yyTokenName[YYWILDCARD]);
    ++               yyTracePrompt, yyTokenName[iLookAhead],
    ++               yyTokenName[YYWILDCARD]);
    +           }
    + #endif /* NDEBUG */
    +           return yy_action[j];
    +         }
    +       }
    + #endif /* YYWILDCARD */
    ++      return yy_default[stateno];
    ++    }else{
    ++      return yy_action[i];
    +     }
    +-    return yy_default[stateno];
    +-  }else{
    +-    return yy_action[i];
    +-  }
    ++  }while(1);
    + }
    + 
    + /*
    + ** Find the appropriate action for a parser given the non-terminal
    + ** look-ahead token iLookAhead.
    +-**
    +-** If the look-ahead token is YYNOCODE, then check to see if the action is
    +-** independent of the look-ahead.  If it is, return the action, otherwise
    +-** return YY_NO_ACTION.
    + */
    + static int yy_find_reduce_action(
    +   int stateno,              /* Current state number */
    +@@ -127656,7 +140064,6 @@ static int yy_find_reduce_action(
    +   assert( stateno<=YY_REDUCE_COUNT );
    + #endif
    +   i = yy_reduce_ofst[stateno];
    +-  assert( i!=YY_REDUCE_USE_DFLT );
    +   assert( iLookAhead!=YYNOCODE );
    +   i += iLookAhead;
    + #ifdef YYERRORSYMBOL
    +@@ -127673,20 +140080,20 @@ static int yy_find_reduce_action(
    + /*
    + ** The following routine is called if the stack overflows.
    + */
    +-static void yyStackOverflow(yyParser *yypParser, YYMINORTYPE *yypMinor){
    ++static void yyStackOverflow(yyParser *yypParser){
    +    sqlite3ParserARG_FETCH;
    +-   yypParser->yyidx--;
    + #ifndef NDEBUG
    +    if( yyTraceFILE ){
    +      fprintf(yyTraceFILE,"%sStack Overflow!\n",yyTracePrompt);
    +    }
    + #endif
    +-   while( yypParser->yyidx>=0 ) yy_pop_parser_stack(yypParser);
    ++   while( yypParser->yytos>yypParser->yystack ) yy_pop_parser_stack(yypParser);
    +    /* Here code is inserted which will execute if the parser
    +    ** stack every overflows */
    ++/******** Begin %stack_overflow code ******************************************/
    + 
    +-  UNUSED_PARAMETER(yypMinor); /* Silence some compiler warnings */
    +   sqlite3ErrorMsg(pParse, "parser stack overflow");
    ++/******** End %stack_overflow code ********************************************/
    +    sqlite3ParserARG_STORE; /* Suppress warning about unused %extra_argument var */
    + }
    + 
    +@@ -127694,396 +140101,402 @@ static void yyStackOverflow(yyParser *yypParser, YYMINORTYPE *yypMinor){
    + ** Print tracing information for a SHIFT action
    + */
    + #ifndef NDEBUG
    +-static void yyTraceShift(yyParser *yypParser, int yyNewState){
    ++static void yyTraceShift(yyParser *yypParser, int yyNewState, const char *zTag){
    +   if( yyTraceFILE ){
    +-    int i;
    +     if( yyNewState<YYNSTATE ){
    +-      fprintf(yyTraceFILE,"%sShift %d\n",yyTracePrompt,yyNewState);
    +-      fprintf(yyTraceFILE,"%sStack:",yyTracePrompt);
    +-      for(i=1; i<=yypParser->yyidx; i++)
    +-        fprintf(yyTraceFILE," %s",yyTokenName[yypParser->yystack[i].major]);
    +-      fprintf(yyTraceFILE,"\n");
    ++      fprintf(yyTraceFILE,"%s%s '%s', go to state %d\n",
    ++         yyTracePrompt, zTag, yyTokenName[yypParser->yytos->major],
    ++         yyNewState);
    +     }else{
    +-      fprintf(yyTraceFILE,"%sShift *\n",yyTracePrompt);
    ++      fprintf(yyTraceFILE,"%s%s '%s', pending reduce %d\n",
    ++         yyTracePrompt, zTag, yyTokenName[yypParser->yytos->major],
    ++         yyNewState - YY_MIN_REDUCE);
    +     }
    +   }
    + }
    + #else
    +-# define yyTraceShift(X,Y)
    ++# define yyTraceShift(X,Y,Z)
    + #endif
    + 
    + /*
    +-** Perform a shift action.  Return the number of errors.
    ++** Perform a shift action.
    + */
    + static void yy_shift(
    +   yyParser *yypParser,          /* The parser to be shifted */
    +   int yyNewState,               /* The new state to shift in */
    +   int yyMajor,                  /* The major token to shift in */
    +-  YYMINORTYPE *yypMinor         /* Pointer to the minor token to shift in */
    ++  sqlite3ParserTOKENTYPE yyMinor        /* The minor token to shift in */
    + ){
    +   yyStackEntry *yytos;
    +-  yypParser->yyidx++;
    ++  yypParser->yytos++;
    + #ifdef YYTRACKMAXSTACKDEPTH
    +-  if( yypParser->yyidx>yypParser->yyidxMax ){
    +-    yypParser->yyidxMax = yypParser->yyidx;
    ++  if( (int)(yypParser->yytos - yypParser->yystack)>yypParser->yyhwm ){
    ++    yypParser->yyhwm++;
    ++    assert( yypParser->yyhwm == (int)(yypParser->yytos - yypParser->yystack) );
    +   }
    + #endif
    + #if YYSTACKDEPTH>0 
    +-  if( yypParser->yyidx>=YYSTACKDEPTH ){
    +-    yyStackOverflow(yypParser, yypMinor);
    ++  if( yypParser->yytos>yypParser->yystackEnd ){
    ++    yypParser->yytos--;
    ++    yyStackOverflow(yypParser);
    +     return;
    +   }
    + #else
    +-  if( yypParser->yyidx>=yypParser->yystksz ){
    +-    yyGrowStack(yypParser);
    +-    if( yypParser->yyidx>=yypParser->yystksz ){
    +-      yyStackOverflow(yypParser, yypMinor);
    ++  if( yypParser->yytos>=&yypParser->yystack[yypParser->yystksz] ){
    ++    if( yyGrowStack(yypParser) ){
    ++      yypParser->yytos--;
    ++      yyStackOverflow(yypParser);
    +       return;
    +     }
    +   }
    + #endif
    +-  yytos = &yypParser->yystack[yypParser->yyidx];
    ++  if( yyNewState > YY_MAX_SHIFT ){
    ++    yyNewState += YY_MIN_REDUCE - YY_MIN_SHIFTREDUCE;
    ++  }
    ++  yytos = yypParser->yytos;
    +   yytos->stateno = (YYACTIONTYPE)yyNewState;
    +   yytos->major = (YYCODETYPE)yyMajor;
    +-  yytos->minor = *yypMinor;
    +-  yyTraceShift(yypParser, yyNewState);
    ++  yytos->minor.yy0 = yyMinor;
    ++  yyTraceShift(yypParser, yyNewState, "Shift");
    + }
    + 
    + /* The following table contains information about every rule that
    + ** is used during the reduce.
    + */
    + static const struct {
    +-  YYCODETYPE lhs;         /* Symbol on the left-hand side of the rule */
    +-  unsigned char nrhs;     /* Number of right-hand side symbols in the rule */
    ++  YYCODETYPE lhs;       /* Symbol on the left-hand side of the rule */
    ++  signed char nrhs;     /* Negative of the number of RHS symbols in the rule */
    + } yyRuleInfo[] = {
    +-  { 144, 1 },
    +-  { 145, 2 },
    +-  { 145, 1 },
    +-  { 146, 1 },
    +-  { 146, 3 },
    +-  { 147, 0 },
    +-  { 147, 1 },
    +-  { 147, 3 },
    +-  { 148, 1 },
    +-  { 149, 3 },
    +-  { 151, 0 },
    +-  { 151, 1 },
    +-  { 151, 2 },
    +-  { 150, 0 },
    +-  { 150, 1 },
    +-  { 150, 1 },
    +-  { 150, 1 },
    +-  { 149, 2 },
    +-  { 149, 2 },
    +-  { 149, 2 },
    +-  { 153, 1 },
    +-  { 153, 0 },
    +-  { 149, 2 },
    +-  { 149, 3 },
    +-  { 149, 5 },
    +-  { 149, 2 },
    +-  { 154, 6 },
    +-  { 156, 1 },
    +-  { 158, 0 },
    +-  { 158, 3 },
    +-  { 157, 1 },
    +-  { 157, 0 },
    +-  { 155, 5 },
    +-  { 155, 2 },
    +-  { 162, 0 },
    +-  { 162, 2 },
    +-  { 160, 3 },
    +-  { 160, 1 },
    +-  { 164, 3 },
    +-  { 165, 1 },
    +-  { 152, 1 },
    +-  { 152, 1 },
    +-  { 152, 1 },
    +-  { 166, 0 },
    +-  { 166, 1 },
    +-  { 168, 1 },
    +-  { 168, 4 },
    +-  { 168, 6 },
    +-  { 169, 1 },
    +-  { 169, 2 },
    +-  { 170, 1 },
    +-  { 170, 1 },
    +-  { 167, 2 },
    +-  { 167, 0 },
    +-  { 173, 2 },
    +-  { 173, 2 },
    +-  { 173, 4 },
    +-  { 173, 3 },
    +-  { 173, 3 },
    +-  { 173, 2 },
    +-  { 173, 2 },
    +-  { 173, 3 },
    +-  { 173, 5 },
    +-  { 173, 2 },
    +-  { 173, 4 },
    +-  { 173, 4 },
    +-  { 173, 1 },
    +-  { 173, 2 },
    +-  { 178, 0 },
    +-  { 178, 1 },
    +-  { 180, 0 },
    +-  { 180, 2 },
    +-  { 182, 2 },
    +-  { 182, 3 },
    +-  { 182, 3 },
    +-  { 182, 3 },
    +-  { 183, 2 },
    +-  { 183, 2 },
    +-  { 183, 1 },
    +-  { 183, 1 },
    +-  { 183, 2 },
    +-  { 181, 3 },
    +-  { 181, 2 },
    +-  { 184, 0 },
    +-  { 184, 2 },
    +-  { 184, 2 },
    +-  { 161, 0 },
    +-  { 161, 2 },
    +-  { 185, 3 },
    +-  { 185, 1 },
    +-  { 186, 1 },
    +-  { 186, 0 },
    +-  { 187, 2 },
    +-  { 187, 7 },
    +-  { 187, 5 },
    +-  { 187, 5 },
    +-  { 187, 10 },
    +-  { 190, 0 },
    +-  { 190, 1 },
    +-  { 176, 0 },
    +-  { 176, 3 },
    +-  { 191, 0 },
    +-  { 191, 2 },
    +-  { 192, 1 },
    +-  { 192, 1 },
    +-  { 192, 1 },
    +-  { 149, 4 },
    +-  { 194, 2 },
    +-  { 194, 0 },
    +-  { 149, 9 },
    +-  { 149, 4 },
    +-  { 149, 1 },
    +-  { 163, 2 },
    +-  { 196, 1 },
    +-  { 196, 3 },
    +-  { 199, 1 },
    +-  { 199, 2 },
    +-  { 199, 1 },
    +-  { 197, 9 },
    +-  { 197, 1 },
    +-  { 208, 4 },
    +-  { 208, 5 },
    +-  { 200, 1 },
    +-  { 200, 1 },
    +-  { 200, 0 },
    +-  { 211, 2 },
    +-  { 211, 0 },
    +-  { 201, 3 },
    +-  { 201, 2 },
    +-  { 201, 4 },
    +-  { 212, 2 },
    +-  { 212, 1 },
    +-  { 212, 0 },
    +-  { 202, 0 },
    +-  { 202, 2 },
    +-  { 214, 2 },
    +-  { 214, 0 },
    +-  { 213, 7 },
    +-  { 213, 9 },
    +-  { 213, 7 },
    +-  { 213, 7 },
    +-  { 159, 0 },
    +-  { 159, 2 },
    +-  { 195, 2 },
    +-  { 215, 1 },
    +-  { 215, 2 },
    +-  { 215, 3 },
    +-  { 215, 4 },
    +-  { 217, 2 },
    +-  { 217, 0 },
    +-  { 216, 0 },
    +-  { 216, 3 },
    +-  { 216, 2 },
    +-  { 218, 4 },
    +-  { 218, 0 },
    +-  { 206, 0 },
    +-  { 206, 3 },
    +-  { 188, 4 },
    +-  { 188, 2 },
    +-  { 177, 1 },
    +-  { 177, 1 },
    +-  { 177, 0 },
    +-  { 204, 0 },
    +-  { 204, 3 },
    +-  { 205, 0 },
    +-  { 205, 2 },
    +-  { 207, 0 },
    +-  { 207, 2 },
    +-  { 207, 4 },
    +-  { 207, 4 },
    +-  { 149, 6 },
    +-  { 203, 0 },
    +-  { 203, 2 },
    +-  { 149, 8 },
    +-  { 221, 5 },
    +-  { 221, 3 },
    +-  { 149, 6 },
    +-  { 149, 7 },
    +-  { 222, 2 },
    +-  { 222, 1 },
    +-  { 223, 0 },
    +-  { 223, 3 },
    +-  { 220, 3 },
    +-  { 220, 1 },
    +-  { 175, 1 },
    +-  { 175, 3 },
    +-  { 174, 1 },
    +-  { 175, 1 },
    +-  { 175, 1 },
    +-  { 175, 3 },
    +-  { 175, 5 },
    +-  { 174, 1 },
    +-  { 174, 1 },
    +-  { 175, 1 },
    +-  { 175, 3 },
    +-  { 175, 6 },
    +-  { 175, 5 },
    +-  { 175, 4 },
    +-  { 174, 1 },
    +-  { 175, 3 },
    +-  { 175, 3 },
    +-  { 175, 3 },
    +-  { 175, 3 },
    +-  { 175, 3 },
    +-  { 175, 3 },
    +-  { 175, 3 },
    +-  { 175, 3 },
    +-  { 224, 1 },
    +-  { 224, 2 },
    +-  { 175, 3 },
    +-  { 175, 5 },
    +-  { 175, 2 },
    +-  { 175, 3 },
    +-  { 175, 3 },
    +-  { 175, 4 },
    +-  { 175, 2 },
    +-  { 175, 2 },
    +-  { 175, 2 },
    +-  { 175, 2 },
    +-  { 225, 1 },
    +-  { 225, 2 },
    +-  { 175, 5 },
    +-  { 226, 1 },
    +-  { 226, 2 },
    +-  { 175, 5 },
    +-  { 175, 3 },
    +-  { 175, 5 },
    +-  { 175, 4 },
    +-  { 175, 4 },
    +-  { 175, 5 },
    +-  { 228, 5 },
    +-  { 228, 4 },
    +-  { 229, 2 },
    +-  { 229, 0 },
    +-  { 227, 1 },
    +-  { 227, 0 },
    +-  { 210, 1 },
    +-  { 210, 0 },
    +-  { 209, 3 },
    +-  { 209, 1 },
    +-  { 149, 12 },
    +-  { 230, 1 },
    +-  { 230, 0 },
    +-  { 179, 0 },
    +-  { 179, 3 },
    +-  { 189, 5 },
    +-  { 189, 3 },
    +-  { 231, 0 },
    +-  { 231, 2 },
    +-  { 149, 4 },
    +-  { 149, 1 },
    +-  { 149, 2 },
    +-  { 149, 3 },
    +-  { 149, 5 },
    +-  { 149, 6 },
    +-  { 149, 5 },
    +-  { 149, 6 },
    +-  { 232, 1 },
    +-  { 232, 1 },
    +-  { 232, 1 },
    +-  { 232, 1 },
    +-  { 232, 1 },
    +-  { 171, 2 },
    +-  { 171, 1 },
    +-  { 172, 2 },
    +-  { 149, 5 },
    +-  { 233, 11 },
    +-  { 235, 1 },
    +-  { 235, 1 },
    +-  { 235, 2 },
    +-  { 235, 0 },
    +-  { 236, 1 },
    +-  { 236, 1 },
    +-  { 236, 3 },
    +-  { 237, 0 },
    +-  { 237, 3 },
    +-  { 238, 0 },
    +-  { 238, 2 },
    +-  { 234, 3 },
    +-  { 234, 2 },
    +-  { 240, 1 },
    +-  { 240, 3 },
    +-  { 241, 0 },
    +-  { 241, 3 },
    +-  { 241, 2 },
    +-  { 239, 7 },
    +-  { 239, 5 },
    +-  { 239, 5 },
    +-  { 239, 1 },
    +-  { 175, 4 },
    +-  { 175, 6 },
    +-  { 193, 1 },
    +-  { 193, 1 },
    +-  { 193, 1 },
    +-  { 149, 4 },
    +-  { 149, 6 },
    +-  { 149, 3 },
    +-  { 243, 0 },
    +-  { 243, 2 },
    +-  { 242, 1 },
    +-  { 242, 0 },
    +-  { 149, 1 },
    +-  { 149, 3 },
    +-  { 149, 1 },
    +-  { 149, 3 },
    +-  { 149, 6 },
    +-  { 149, 6 },
    +-  { 244, 1 },
    +-  { 245, 0 },
    +-  { 245, 1 },
    +-  { 149, 1 },
    +-  { 149, 4 },
    +-  { 246, 8 },
    +-  { 247, 1 },
    +-  { 247, 3 },
    +-  { 248, 0 },
    +-  { 248, 2 },
    +-  { 249, 1 },
    +-  { 249, 3 },
    +-  { 250, 1 },
    +-  { 251, 0 },
    +-  { 251, 4 },
    +-  { 251, 2 },
    +-  { 198, 0 },
    +-  { 198, 2 },
    +-  { 198, 3 },
    +-  { 252, 6 },
    +-  { 252, 8 },
    ++  {  147,   -1 }, /* (0) explain ::= EXPLAIN */
    ++  {  147,   -3 }, /* (1) explain ::= EXPLAIN QUERY PLAN */
    ++  {  148,   -1 }, /* (2) cmdx ::= cmd */
    ++  {  149,   -3 }, /* (3) cmd ::= BEGIN transtype trans_opt */
    ++  {  150,    0 }, /* (4) transtype ::= */
    ++  {  150,   -1 }, /* (5) transtype ::= DEFERRED */
    ++  {  150,   -1 }, /* (6) transtype ::= IMMEDIATE */
    ++  {  150,   -1 }, /* (7) transtype ::= EXCLUSIVE */
    ++  {  149,   -2 }, /* (8) cmd ::= COMMIT|END trans_opt */
    ++  {  149,   -2 }, /* (9) cmd ::= ROLLBACK trans_opt */
    ++  {  149,   -2 }, /* (10) cmd ::= SAVEPOINT nm */
    ++  {  149,   -3 }, /* (11) cmd ::= RELEASE savepoint_opt nm */
    ++  {  149,   -5 }, /* (12) cmd ::= ROLLBACK trans_opt TO savepoint_opt nm */
    ++  {  154,   -6 }, /* (13) create_table ::= createkw temp TABLE ifnotexists nm dbnm */
    ++  {  156,   -1 }, /* (14) createkw ::= CREATE */
    ++  {  158,    0 }, /* (15) ifnotexists ::= */
    ++  {  158,   -3 }, /* (16) ifnotexists ::= IF NOT EXISTS */
    ++  {  157,   -1 }, /* (17) temp ::= TEMP */
    ++  {  157,    0 }, /* (18) temp ::= */
    ++  {  155,   -5 }, /* (19) create_table_args ::= LP columnlist conslist_opt RP table_options */
    ++  {  155,   -2 }, /* (20) create_table_args ::= AS select */
    ++  {  162,    0 }, /* (21) table_options ::= */
    ++  {  162,   -2 }, /* (22) table_options ::= WITHOUT nm */
    ++  {  164,   -2 }, /* (23) columnname ::= nm typetoken */
    ++  {  166,    0 }, /* (24) typetoken ::= */
    ++  {  166,   -4 }, /* (25) typetoken ::= typename LP signed RP */
    ++  {  166,   -6 }, /* (26) typetoken ::= typename LP signed COMMA signed RP */
    ++  {  167,   -2 }, /* (27) typename ::= typename ID|STRING */
    ++  {  171,    0 }, /* (28) scanpt ::= */
    ++  {  172,   -2 }, /* (29) ccons ::= CONSTRAINT nm */
    ++  {  172,   -4 }, /* (30) ccons ::= DEFAULT scanpt term scanpt */
    ++  {  172,   -4 }, /* (31) ccons ::= DEFAULT LP expr RP */
    ++  {  172,   -4 }, /* (32) ccons ::= DEFAULT PLUS term scanpt */
    ++  {  172,   -4 }, /* (33) ccons ::= DEFAULT MINUS term scanpt */
    ++  {  172,   -3 }, /* (34) ccons ::= DEFAULT scanpt ID|INDEXED */
    ++  {  172,   -3 }, /* (35) ccons ::= NOT NULL onconf */
    ++  {  172,   -5 }, /* (36) ccons ::= PRIMARY KEY sortorder onconf autoinc */
    ++  {  172,   -2 }, /* (37) ccons ::= UNIQUE onconf */
    ++  {  172,   -4 }, /* (38) ccons ::= CHECK LP expr RP */
    ++  {  172,   -4 }, /* (39) ccons ::= REFERENCES nm eidlist_opt refargs */
    ++  {  172,   -1 }, /* (40) ccons ::= defer_subclause */
    ++  {  172,   -2 }, /* (41) ccons ::= COLLATE ID|STRING */
    ++  {  177,    0 }, /* (42) autoinc ::= */
    ++  {  177,   -1 }, /* (43) autoinc ::= AUTOINCR */
    ++  {  179,    0 }, /* (44) refargs ::= */
    ++  {  179,   -2 }, /* (45) refargs ::= refargs refarg */
    ++  {  181,   -2 }, /* (46) refarg ::= MATCH nm */
    ++  {  181,   -3 }, /* (47) refarg ::= ON INSERT refact */
    ++  {  181,   -3 }, /* (48) refarg ::= ON DELETE refact */
    ++  {  181,   -3 }, /* (49) refarg ::= ON UPDATE refact */
    ++  {  182,   -2 }, /* (50) refact ::= SET NULL */
    ++  {  182,   -2 }, /* (51) refact ::= SET DEFAULT */
    ++  {  182,   -1 }, /* (52) refact ::= CASCADE */
    ++  {  182,   -1 }, /* (53) refact ::= RESTRICT */
    ++  {  182,   -2 }, /* (54) refact ::= NO ACTION */
    ++  {  180,   -3 }, /* (55) defer_subclause ::= NOT DEFERRABLE init_deferred_pred_opt */
    ++  {  180,   -2 }, /* (56) defer_subclause ::= DEFERRABLE init_deferred_pred_opt */
    ++  {  183,    0 }, /* (57) init_deferred_pred_opt ::= */
    ++  {  183,   -2 }, /* (58) init_deferred_pred_opt ::= INITIALLY DEFERRED */
    ++  {  183,   -2 }, /* (59) init_deferred_pred_opt ::= INITIALLY IMMEDIATE */
    ++  {  161,    0 }, /* (60) conslist_opt ::= */
    ++  {  185,   -1 }, /* (61) tconscomma ::= COMMA */
    ++  {  186,   -2 }, /* (62) tcons ::= CONSTRAINT nm */
    ++  {  186,   -7 }, /* (63) tcons ::= PRIMARY KEY LP sortlist autoinc RP onconf */
    ++  {  186,   -5 }, /* (64) tcons ::= UNIQUE LP sortlist RP onconf */
    ++  {  186,   -5 }, /* (65) tcons ::= CHECK LP expr RP onconf */
    ++  {  186,  -10 }, /* (66) tcons ::= FOREIGN KEY LP eidlist RP REFERENCES nm eidlist_opt refargs defer_subclause_opt */
    ++  {  189,    0 }, /* (67) defer_subclause_opt ::= */
    ++  {  175,    0 }, /* (68) onconf ::= */
    ++  {  175,   -3 }, /* (69) onconf ::= ON CONFLICT resolvetype */
    ++  {  190,    0 }, /* (70) orconf ::= */
    ++  {  190,   -2 }, /* (71) orconf ::= OR resolvetype */
    ++  {  191,   -1 }, /* (72) resolvetype ::= IGNORE */
    ++  {  191,   -1 }, /* (73) resolvetype ::= REPLACE */
    ++  {  149,   -4 }, /* (74) cmd ::= DROP TABLE ifexists fullname */
    ++  {  193,   -2 }, /* (75) ifexists ::= IF EXISTS */
    ++  {  193,    0 }, /* (76) ifexists ::= */
    ++  {  149,   -9 }, /* (77) cmd ::= createkw temp VIEW ifnotexists nm dbnm eidlist_opt AS select */
    ++  {  149,   -4 }, /* (78) cmd ::= DROP VIEW ifexists fullname */
    ++  {  149,   -1 }, /* (79) cmd ::= select */
    ++  {  163,   -2 }, /* (80) select ::= with selectnowith */
    ++  {  195,   -3 }, /* (81) selectnowith ::= selectnowith multiselect_op oneselect */
    ++  {  198,   -1 }, /* (82) multiselect_op ::= UNION */
    ++  {  198,   -2 }, /* (83) multiselect_op ::= UNION ALL */
    ++  {  198,   -1 }, /* (84) multiselect_op ::= EXCEPT|INTERSECT */
    ++  {  196,   -9 }, /* (85) oneselect ::= SELECT distinct selcollist from where_opt groupby_opt having_opt orderby_opt limit_opt */
    ++  {  207,   -4 }, /* (86) values ::= VALUES LP nexprlist RP */
    ++  {  207,   -5 }, /* (87) values ::= values COMMA LP exprlist RP */
    ++  {  199,   -1 }, /* (88) distinct ::= DISTINCT */
    ++  {  199,   -1 }, /* (89) distinct ::= ALL */
    ++  {  199,    0 }, /* (90) distinct ::= */
    ++  {  210,    0 }, /* (91) sclp ::= */
    ++  {  200,   -5 }, /* (92) selcollist ::= sclp scanpt expr scanpt as */
    ++  {  200,   -3 }, /* (93) selcollist ::= sclp scanpt STAR */
    ++  {  200,   -5 }, /* (94) selcollist ::= sclp scanpt nm DOT STAR */
    ++  {  211,   -2 }, /* (95) as ::= AS nm */
    ++  {  211,    0 }, /* (96) as ::= */
    ++  {  201,    0 }, /* (97) from ::= */
    ++  {  201,   -2 }, /* (98) from ::= FROM seltablist */
    ++  {  213,   -2 }, /* (99) stl_prefix ::= seltablist joinop */
    ++  {  213,    0 }, /* (100) stl_prefix ::= */
    ++  {  212,   -7 }, /* (101) seltablist ::= stl_prefix nm dbnm as indexed_opt on_opt using_opt */
    ++  {  212,   -9 }, /* (102) seltablist ::= stl_prefix nm dbnm LP exprlist RP as on_opt using_opt */
    ++  {  212,   -7 }, /* (103) seltablist ::= stl_prefix LP select RP as on_opt using_opt */
    ++  {  212,   -7 }, /* (104) seltablist ::= stl_prefix LP seltablist RP as on_opt using_opt */
    ++  {  159,    0 }, /* (105) dbnm ::= */
    ++  {  159,   -2 }, /* (106) dbnm ::= DOT nm */
    ++  {  194,   -2 }, /* (107) fullname ::= nm dbnm */
    ++  {  214,   -1 }, /* (108) joinop ::= COMMA|JOIN */
    ++  {  214,   -2 }, /* (109) joinop ::= JOIN_KW JOIN */
    ++  {  214,   -3 }, /* (110) joinop ::= JOIN_KW nm JOIN */
    ++  {  214,   -4 }, /* (111) joinop ::= JOIN_KW nm nm JOIN */
    ++  {  216,   -2 }, /* (112) on_opt ::= ON expr */
    ++  {  216,    0 }, /* (113) on_opt ::= */
    ++  {  215,    0 }, /* (114) indexed_opt ::= */
    ++  {  215,   -3 }, /* (115) indexed_opt ::= INDEXED BY nm */
    ++  {  215,   -2 }, /* (116) indexed_opt ::= NOT INDEXED */
    ++  {  217,   -4 }, /* (117) using_opt ::= USING LP idlist RP */
    ++  {  217,    0 }, /* (118) using_opt ::= */
    ++  {  205,    0 }, /* (119) orderby_opt ::= */
    ++  {  205,   -3 }, /* (120) orderby_opt ::= ORDER BY sortlist */
    ++  {  187,   -4 }, /* (121) sortlist ::= sortlist COMMA expr sortorder */
    ++  {  187,   -2 }, /* (122) sortlist ::= expr sortorder */
    ++  {  176,   -1 }, /* (123) sortorder ::= ASC */
    ++  {  176,   -1 }, /* (124) sortorder ::= DESC */
    ++  {  176,    0 }, /* (125) sortorder ::= */
    ++  {  203,    0 }, /* (126) groupby_opt ::= */
    ++  {  203,   -3 }, /* (127) groupby_opt ::= GROUP BY nexprlist */
    ++  {  204,    0 }, /* (128) having_opt ::= */
    ++  {  204,   -2 }, /* (129) having_opt ::= HAVING expr */
    ++  {  206,    0 }, /* (130) limit_opt ::= */
    ++  {  206,   -2 }, /* (131) limit_opt ::= LIMIT expr */
    ++  {  206,   -4 }, /* (132) limit_opt ::= LIMIT expr OFFSET expr */
    ++  {  206,   -4 }, /* (133) limit_opt ::= LIMIT expr COMMA expr */
    ++  {  149,   -6 }, /* (134) cmd ::= with DELETE FROM fullname indexed_opt where_opt */
    ++  {  202,    0 }, /* (135) where_opt ::= */
    ++  {  202,   -2 }, /* (136) where_opt ::= WHERE expr */
    ++  {  149,   -8 }, /* (137) cmd ::= with UPDATE orconf fullname indexed_opt SET setlist where_opt */
    ++  {  219,   -5 }, /* (138) setlist ::= setlist COMMA nm EQ expr */
    ++  {  219,   -7 }, /* (139) setlist ::= setlist COMMA LP idlist RP EQ expr */
    ++  {  219,   -3 }, /* (140) setlist ::= nm EQ expr */
    ++  {  219,   -5 }, /* (141) setlist ::= LP idlist RP EQ expr */
    ++  {  149,   -6 }, /* (142) cmd ::= with insert_cmd INTO fullname idlist_opt select */
    ++  {  149,   -7 }, /* (143) cmd ::= with insert_cmd INTO fullname idlist_opt DEFAULT VALUES */
    ++  {  220,   -2 }, /* (144) insert_cmd ::= INSERT orconf */
    ++  {  220,   -1 }, /* (145) insert_cmd ::= REPLACE */
    ++  {  221,    0 }, /* (146) idlist_opt ::= */
    ++  {  221,   -3 }, /* (147) idlist_opt ::= LP idlist RP */
    ++  {  218,   -3 }, /* (148) idlist ::= idlist COMMA nm */
    ++  {  218,   -1 }, /* (149) idlist ::= nm */
    ++  {  174,   -3 }, /* (150) expr ::= LP expr RP */
    ++  {  174,   -1 }, /* (151) expr ::= ID|INDEXED */
    ++  {  174,   -1 }, /* (152) expr ::= JOIN_KW */
    ++  {  174,   -3 }, /* (153) expr ::= nm DOT nm */
    ++  {  174,   -5 }, /* (154) expr ::= nm DOT nm DOT nm */
    ++  {  173,   -1 }, /* (155) term ::= NULL|FLOAT|BLOB */
    ++  {  173,   -1 }, /* (156) term ::= STRING */
    ++  {  173,   -1 }, /* (157) term ::= INTEGER */
    ++  {  174,   -1 }, /* (158) expr ::= VARIABLE */
    ++  {  174,   -3 }, /* (159) expr ::= expr COLLATE ID|STRING */
    ++  {  174,   -6 }, /* (160) expr ::= CAST LP expr AS typetoken RP */
    ++  {  174,   -5 }, /* (161) expr ::= ID|INDEXED LP distinct exprlist RP */
    ++  {  174,   -4 }, /* (162) expr ::= ID|INDEXED LP STAR RP */
    ++  {  173,   -1 }, /* (163) term ::= CTIME_KW */
    ++  {  174,   -5 }, /* (164) expr ::= LP nexprlist COMMA expr RP */
    ++  {  174,   -3 }, /* (165) expr ::= expr AND expr */
    ++  {  174,   -3 }, /* (166) expr ::= expr OR expr */
    ++  {  174,   -3 }, /* (167) expr ::= expr LT|GT|GE|LE expr */
    ++  {  174,   -3 }, /* (168) expr ::= expr EQ|NE expr */
    ++  {  174,   -3 }, /* (169) expr ::= expr BITAND|BITOR|LSHIFT|RSHIFT expr */
    ++  {  174,   -3 }, /* (170) expr ::= expr PLUS|MINUS expr */
    ++  {  174,   -3 }, /* (171) expr ::= expr STAR|SLASH|REM expr */
    ++  {  174,   -3 }, /* (172) expr ::= expr CONCAT expr */
    ++  {  222,   -2 }, /* (173) likeop ::= NOT LIKE_KW|MATCH */
    ++  {  174,   -3 }, /* (174) expr ::= expr likeop expr */
    ++  {  174,   -5 }, /* (175) expr ::= expr likeop expr ESCAPE expr */
    ++  {  174,   -2 }, /* (176) expr ::= expr ISNULL|NOTNULL */
    ++  {  174,   -3 }, /* (177) expr ::= expr NOT NULL */
    ++  {  174,   -3 }, /* (178) expr ::= expr IS expr */
    ++  {  174,   -4 }, /* (179) expr ::= expr IS NOT expr */
    ++  {  174,   -2 }, /* (180) expr ::= NOT expr */
    ++  {  174,   -2 }, /* (181) expr ::= BITNOT expr */
    ++  {  174,   -2 }, /* (182) expr ::= MINUS expr */
    ++  {  174,   -2 }, /* (183) expr ::= PLUS expr */
    ++  {  223,   -1 }, /* (184) between_op ::= BETWEEN */
    ++  {  223,   -2 }, /* (185) between_op ::= NOT BETWEEN */
    ++  {  174,   -5 }, /* (186) expr ::= expr between_op expr AND expr */
    ++  {  224,   -1 }, /* (187) in_op ::= IN */
    ++  {  224,   -2 }, /* (188) in_op ::= NOT IN */
    ++  {  174,   -5 }, /* (189) expr ::= expr in_op LP exprlist RP */
    ++  {  174,   -3 }, /* (190) expr ::= LP select RP */
    ++  {  174,   -5 }, /* (191) expr ::= expr in_op LP select RP */
    ++  {  174,   -5 }, /* (192) expr ::= expr in_op nm dbnm paren_exprlist */
    ++  {  174,   -4 }, /* (193) expr ::= EXISTS LP select RP */
    ++  {  174,   -5 }, /* (194) expr ::= CASE case_operand case_exprlist case_else END */
    ++  {  227,   -5 }, /* (195) case_exprlist ::= case_exprlist WHEN expr THEN expr */
    ++  {  227,   -4 }, /* (196) case_exprlist ::= WHEN expr THEN expr */
    ++  {  228,   -2 }, /* (197) case_else ::= ELSE expr */
    ++  {  228,    0 }, /* (198) case_else ::= */
    ++  {  226,   -1 }, /* (199) case_operand ::= expr */
    ++  {  226,    0 }, /* (200) case_operand ::= */
    ++  {  209,    0 }, /* (201) exprlist ::= */
    ++  {  208,   -3 }, /* (202) nexprlist ::= nexprlist COMMA expr */
    ++  {  208,   -1 }, /* (203) nexprlist ::= expr */
    ++  {  225,    0 }, /* (204) paren_exprlist ::= */
    ++  {  225,   -3 }, /* (205) paren_exprlist ::= LP exprlist RP */
    ++  {  149,  -12 }, /* (206) cmd ::= createkw uniqueflag INDEX ifnotexists nm dbnm ON nm LP sortlist RP where_opt */
    ++  {  229,   -1 }, /* (207) uniqueflag ::= UNIQUE */
    ++  {  229,    0 }, /* (208) uniqueflag ::= */
    ++  {  178,    0 }, /* (209) eidlist_opt ::= */
    ++  {  178,   -3 }, /* (210) eidlist_opt ::= LP eidlist RP */
    ++  {  188,   -5 }, /* (211) eidlist ::= eidlist COMMA nm collate sortorder */
    ++  {  188,   -3 }, /* (212) eidlist ::= nm collate sortorder */
    ++  {  230,    0 }, /* (213) collate ::= */
    ++  {  230,   -2 }, /* (214) collate ::= COLLATE ID|STRING */
    ++  {  149,   -4 }, /* (215) cmd ::= DROP INDEX ifexists fullname */
    ++  {  149,   -1 }, /* (216) cmd ::= VACUUM */
    ++  {  149,   -2 }, /* (217) cmd ::= VACUUM nm */
    ++  {  149,   -3 }, /* (218) cmd ::= PRAGMA nm dbnm */
    ++  {  149,   -5 }, /* (219) cmd ::= PRAGMA nm dbnm EQ nmnum */
    ++  {  149,   -6 }, /* (220) cmd ::= PRAGMA nm dbnm LP nmnum RP */
    ++  {  149,   -5 }, /* (221) cmd ::= PRAGMA nm dbnm EQ minus_num */
    ++  {  149,   -6 }, /* (222) cmd ::= PRAGMA nm dbnm LP minus_num RP */
    ++  {  169,   -2 }, /* (223) plus_num ::= PLUS INTEGER|FLOAT */
    ++  {  170,   -2 }, /* (224) minus_num ::= MINUS INTEGER|FLOAT */
    ++  {  149,   -5 }, /* (225) cmd ::= createkw trigger_decl BEGIN trigger_cmd_list END */
    ++  {  232,  -11 }, /* (226) trigger_decl ::= temp TRIGGER ifnotexists nm dbnm trigger_time trigger_event ON fullname foreach_clause when_clause */
    ++  {  234,   -1 }, /* (227) trigger_time ::= BEFORE|AFTER */
    ++  {  234,   -2 }, /* (228) trigger_time ::= INSTEAD OF */
    ++  {  234,    0 }, /* (229) trigger_time ::= */
    ++  {  235,   -1 }, /* (230) trigger_event ::= DELETE|INSERT */
    ++  {  235,   -1 }, /* (231) trigger_event ::= UPDATE */
    ++  {  235,   -3 }, /* (232) trigger_event ::= UPDATE OF idlist */
    ++  {  237,    0 }, /* (233) when_clause ::= */
    ++  {  237,   -2 }, /* (234) when_clause ::= WHEN expr */
    ++  {  233,   -3 }, /* (235) trigger_cmd_list ::= trigger_cmd_list trigger_cmd SEMI */
    ++  {  233,   -2 }, /* (236) trigger_cmd_list ::= trigger_cmd SEMI */
    ++  {  239,   -3 }, /* (237) trnm ::= nm DOT nm */
    ++  {  240,   -3 }, /* (238) tridxby ::= INDEXED BY nm */
    ++  {  240,   -2 }, /* (239) tridxby ::= NOT INDEXED */
    ++  {  238,   -8 }, /* (240) trigger_cmd ::= UPDATE orconf trnm tridxby SET setlist where_opt scanpt */
    ++  {  238,   -7 }, /* (241) trigger_cmd ::= scanpt insert_cmd INTO trnm idlist_opt select scanpt */
    ++  {  238,   -6 }, /* (242) trigger_cmd ::= DELETE FROM trnm tridxby where_opt scanpt */
    ++  {  238,   -3 }, /* (243) trigger_cmd ::= scanpt select scanpt */
    ++  {  174,   -4 }, /* (244) expr ::= RAISE LP IGNORE RP */
    ++  {  174,   -6 }, /* (245) expr ::= RAISE LP raisetype COMMA nm RP */
    ++  {  192,   -1 }, /* (246) raisetype ::= ROLLBACK */
    ++  {  192,   -1 }, /* (247) raisetype ::= ABORT */
    ++  {  192,   -1 }, /* (248) raisetype ::= FAIL */
    ++  {  149,   -4 }, /* (249) cmd ::= DROP TRIGGER ifexists fullname */
    ++  {  149,   -6 }, /* (250) cmd ::= ATTACH database_kw_opt expr AS expr key_opt */
    ++  {  149,   -3 }, /* (251) cmd ::= DETACH database_kw_opt expr */
    ++  {  242,    0 }, /* (252) key_opt ::= */
    ++  {  242,   -2 }, /* (253) key_opt ::= KEY expr */
    ++  {  149,   -1 }, /* (254) cmd ::= REINDEX */
    ++  {  149,   -3 }, /* (255) cmd ::= REINDEX nm dbnm */
    ++  {  149,   -1 }, /* (256) cmd ::= ANALYZE */
    ++  {  149,   -3 }, /* (257) cmd ::= ANALYZE nm dbnm */
    ++  {  149,   -6 }, /* (258) cmd ::= ALTER TABLE fullname RENAME TO nm */
    ++  {  149,   -7 }, /* (259) cmd ::= ALTER TABLE add_column_fullname ADD kwcolumn_opt columnname carglist */
    ++  {  243,   -1 }, /* (260) add_column_fullname ::= fullname */
    ++  {  149,   -1 }, /* (261) cmd ::= create_vtab */
    ++  {  149,   -4 }, /* (262) cmd ::= create_vtab LP vtabarglist RP */
    ++  {  245,   -8 }, /* (263) create_vtab ::= createkw VIRTUAL TABLE ifnotexists nm dbnm USING nm */
    ++  {  247,    0 }, /* (264) vtabarg ::= */
    ++  {  248,   -1 }, /* (265) vtabargtoken ::= ANY */
    ++  {  248,   -3 }, /* (266) vtabargtoken ::= lp anylist RP */
    ++  {  249,   -1 }, /* (267) lp ::= LP */
    ++  {  197,    0 }, /* (268) with ::= */
    ++  {  197,   -2 }, /* (269) with ::= WITH wqlist */
    ++  {  197,   -3 }, /* (270) with ::= WITH RECURSIVE wqlist */
    ++  {  251,   -6 }, /* (271) wqlist ::= nm eidlist_opt AS LP select RP */
    ++  {  251,   -8 }, /* (272) wqlist ::= wqlist COMMA nm eidlist_opt AS LP select RP */
    ++  {  144,   -1 }, /* (273) input ::= cmdlist */
    ++  {  145,   -2 }, /* (274) cmdlist ::= cmdlist ecmd */
    ++  {  145,   -1 }, /* (275) cmdlist ::= ecmd */
    ++  {  146,   -1 }, /* (276) ecmd ::= SEMI */
    ++  {  146,   -3 }, /* (277) ecmd ::= explain cmdx SEMI */
    ++  {  147,    0 }, /* (278) explain ::= */
    ++  {  151,    0 }, /* (279) trans_opt ::= */
    ++  {  151,   -1 }, /* (280) trans_opt ::= TRANSACTION */
    ++  {  151,   -2 }, /* (281) trans_opt ::= TRANSACTION nm */
    ++  {  153,   -1 }, /* (282) savepoint_opt ::= SAVEPOINT */
    ++  {  153,    0 }, /* (283) savepoint_opt ::= */
    ++  {  149,   -2 }, /* (284) cmd ::= create_table create_table_args */
    ++  {  160,   -4 }, /* (285) columnlist ::= columnlist COMMA columnname carglist */
    ++  {  160,   -2 }, /* (286) columnlist ::= columnname carglist */
    ++  {  152,   -1 }, /* (287) nm ::= ID|INDEXED */
    ++  {  152,   -1 }, /* (288) nm ::= STRING */
    ++  {  152,   -1 }, /* (289) nm ::= JOIN_KW */
    ++  {  166,   -1 }, /* (290) typetoken ::= typename */
    ++  {  167,   -1 }, /* (291) typename ::= ID|STRING */
    ++  {  168,   -1 }, /* (292) signed ::= plus_num */
    ++  {  168,   -1 }, /* (293) signed ::= minus_num */
    ++  {  165,   -2 }, /* (294) carglist ::= carglist ccons */
    ++  {  165,    0 }, /* (295) carglist ::= */
    ++  {  172,   -2 }, /* (296) ccons ::= NULL onconf */
    ++  {  161,   -2 }, /* (297) conslist_opt ::= COMMA conslist */
    ++  {  184,   -3 }, /* (298) conslist ::= conslist tconscomma tcons */
    ++  {  184,   -1 }, /* (299) conslist ::= tcons */
    ++  {  185,    0 }, /* (300) tconscomma ::= */
    ++  {  189,   -1 }, /* (301) defer_subclause_opt ::= defer_subclause */
    ++  {  191,   -1 }, /* (302) resolvetype ::= raisetype */
    ++  {  195,   -1 }, /* (303) selectnowith ::= oneselect */
    ++  {  196,   -1 }, /* (304) oneselect ::= values */
    ++  {  210,   -2 }, /* (305) sclp ::= selcollist COMMA */
    ++  {  211,   -1 }, /* (306) as ::= ID|STRING */
    ++  {  174,   -1 }, /* (307) expr ::= term */
    ++  {  222,   -1 }, /* (308) likeop ::= LIKE_KW|MATCH */
    ++  {  209,   -1 }, /* (309) exprlist ::= nexprlist */
    ++  {  231,   -1 }, /* (310) nmnum ::= plus_num */
    ++  {  231,   -1 }, /* (311) nmnum ::= nm */
    ++  {  231,   -1 }, /* (312) nmnum ::= ON */
    ++  {  231,   -1 }, /* (313) nmnum ::= DELETE */
    ++  {  231,   -1 }, /* (314) nmnum ::= DEFAULT */
    ++  {  169,   -1 }, /* (315) plus_num ::= INTEGER|FLOAT */
    ++  {  236,    0 }, /* (316) foreach_clause ::= */
    ++  {  236,   -3 }, /* (317) foreach_clause ::= FOR EACH ROW */
    ++  {  239,   -1 }, /* (318) trnm ::= nm */
    ++  {  240,    0 }, /* (319) tridxby ::= */
    ++  {  241,   -1 }, /* (320) database_kw_opt ::= DATABASE */
    ++  {  241,    0 }, /* (321) database_kw_opt ::= */
    ++  {  244,    0 }, /* (322) kwcolumn_opt ::= */
    ++  {  244,   -1 }, /* (323) kwcolumn_opt ::= COLUMNKW */
    ++  {  246,   -1 }, /* (324) vtabarglist ::= vtabarg */
    ++  {  246,   -3 }, /* (325) vtabarglist ::= vtabarglist COMMA vtabarg */
    ++  {  247,   -2 }, /* (326) vtabarg ::= vtabarg vtabargtoken */
    ++  {  250,    0 }, /* (327) anylist ::= */
    ++  {  250,   -4 }, /* (328) anylist ::= anylist LP anylist RP */
    ++  {  250,   -2 }, /* (329) anylist ::= anylist ANY */
    + };
    + 
    + static void yy_accept(yyParser*);  /* Forward Declaration */
    +@@ -128091,44 +140504,66 @@ static void yy_accept(yyParser*);  /* Forward Declaration */
    + /*
    + ** Perform a reduce action and the shift that must immediately
    + ** follow the reduce.
    ++**
    ++** The yyLookahead and yyLookaheadToken parameters provide reduce actions
    ++** access to the lookahead token (if any).  The yyLookahead will be YYNOCODE
    ++** if the lookahead token has already been consumed.  As this procedure is
    ++** only called from one place, optimizing compilers will in-line it, which
    ++** means that the extra parameters have no performance impact.
    + */
    + static void yy_reduce(
    +   yyParser *yypParser,         /* The parser */
    +-  int yyruleno                 /* Number of the rule by which to reduce */
    ++  unsigned int yyruleno,       /* Number of the rule by which to reduce */
    ++  int yyLookahead,             /* Lookahead token, or YYNOCODE if none */
    ++  sqlite3ParserTOKENTYPE yyLookaheadToken  /* Value of the lookahead token */
    + ){
    +   int yygoto;                     /* The next state */
    +   int yyact;                      /* The next action */
    +-  YYMINORTYPE yygotominor;        /* The LHS of the rule reduced */
    +   yyStackEntry *yymsp;            /* The top of the parser's stack */
    +   int yysize;                     /* Amount to pop the stack */
    +   sqlite3ParserARG_FETCH;
    +-  yymsp = &yypParser->yystack[yypParser->yyidx];
    ++  (void)yyLookahead;
    ++  (void)yyLookaheadToken;
    ++  yymsp = yypParser->yytos;
    + #ifndef NDEBUG
    +-  if( yyTraceFILE && yyruleno>=0 
    +-        && yyruleno<(int)(sizeof(yyRuleName)/sizeof(yyRuleName[0])) ){
    ++  if( yyTraceFILE && yyruleno<(int)(sizeof(yyRuleName)/sizeof(yyRuleName[0])) ){
    +     yysize = yyRuleInfo[yyruleno].nrhs;
    +-    fprintf(yyTraceFILE, "%sReduce [%s] -> state %d.\n", yyTracePrompt,
    +-      yyRuleName[yyruleno], yymsp[-yysize].stateno);
    ++    if( yysize ){
    ++      fprintf(yyTraceFILE, "%sReduce %d [%s], go to state %d.\n",
    ++        yyTracePrompt,
    ++        yyruleno, yyRuleName[yyruleno], yymsp[yysize].stateno);
    ++    }else{
    ++      fprintf(yyTraceFILE, "%sReduce %d [%s].\n",
    ++        yyTracePrompt, yyruleno, yyRuleName[yyruleno]);
    ++    }
    +   }
    + #endif /* NDEBUG */
    + 
    +-  /* Silence complaints from purify about yygotominor being uninitialized
    +-  ** in some cases when it is copied into the stack after the following
    +-  ** switch.  yygotominor is uninitialized when a rule reduces that does
    +-  ** not set the value of its left-hand side nonterminal.  Leaving the
    +-  ** value of the nonterminal uninitialized is utterly harmless as long
    +-  ** as the value is never used.  So really the only thing this code
    +-  ** accomplishes is to quieten purify.  
    +-  **
    +-  ** 2007-01-16:  The wireshark project (www.wireshark.org) reports that
    +-  ** without this code, their parser segfaults.  I'm not sure what there
    +-  ** parser is doing to make this happen.  This is the second bug report
    +-  ** from wireshark this week.  Clearly they are stressing Lemon in ways
    +-  ** that it has not been previously stressed...  (SQLite ticket #2172)
    +-  */
    +-  /*memset(&yygotominor, 0, sizeof(yygotominor));*/
    +-  yygotominor = yyzerominor;
    +-
    ++  /* Check that the stack is large enough to grow by a single entry
    ++  ** if the RHS of the rule is empty.  This ensures that there is room
    ++  ** enough on the stack to push the LHS value */
    ++  if( yyRuleInfo[yyruleno].nrhs==0 ){
    ++#ifdef YYTRACKMAXSTACKDEPTH
    ++    if( (int)(yypParser->yytos - yypParser->yystack)>yypParser->yyhwm ){
    ++      yypParser->yyhwm++;
    ++      assert( yypParser->yyhwm == (int)(yypParser->yytos - yypParser->yystack));
    ++    }
    ++#endif
    ++#if YYSTACKDEPTH>0 
    ++    if( yypParser->yytos>=yypParser->yystackEnd ){
    ++      yyStackOverflow(yypParser);
    ++      return;
    ++    }
    ++#else
    ++    if( yypParser->yytos>=&yypParser->yystack[yypParser->yystksz-1] ){
    ++      if( yyGrowStack(yypParser) ){
    ++        yyStackOverflow(yypParser);
    ++        return;
    ++      }
    ++      yymsp = yypParser->yytos;
    ++    }
    ++#endif
    ++  }
    + 
    +   switch( yyruleno ){
    +   /* Beginning here are the reduction cases.  A typical example
    +@@ -128139,354 +140574,323 @@ static void yy_reduce(
    +   **  #line <lineno> <thisfile>
    +   **     break;
    +   */
    +-      case 5: /* explain ::= */
    +-{ sqlite3BeginParse(pParse, 0); }
    +-        break;
    +-      case 6: /* explain ::= EXPLAIN */
    +-{ sqlite3BeginParse(pParse, 1); }
    ++/********** Begin reduce actions **********************************************/
    ++        YYMINORTYPE yylhsminor;
    ++      case 0: /* explain ::= EXPLAIN */
    ++{ pParse->explain = 1; }
    +         break;
    +-      case 7: /* explain ::= EXPLAIN QUERY PLAN */
    +-{ sqlite3BeginParse(pParse, 2); }
    ++      case 1: /* explain ::= EXPLAIN QUERY PLAN */
    ++{ pParse->explain = 2; }
    +         break;
    +-      case 8: /* cmdx ::= cmd */
    ++      case 2: /* cmdx ::= cmd */
    + { sqlite3FinishCoding(pParse); }
    +         break;
    +-      case 9: /* cmd ::= BEGIN transtype trans_opt */
    +-{sqlite3BeginTransaction(pParse, yymsp[-1].minor.yy328);}
    ++      case 3: /* cmd ::= BEGIN transtype trans_opt */
    ++{sqlite3BeginTransaction(pParse, yymsp[-1].minor.yy4);}
    +         break;
    +-      case 13: /* transtype ::= */
    +-{yygotominor.yy328 = TK_DEFERRED;}
    ++      case 4: /* transtype ::= */
    ++{yymsp[1].minor.yy4 = TK_DEFERRED;}
    +         break;
    +-      case 14: /* transtype ::= DEFERRED */
    +-      case 15: /* transtype ::= IMMEDIATE */ yytestcase(yyruleno==15);
    +-      case 16: /* transtype ::= EXCLUSIVE */ yytestcase(yyruleno==16);
    +-      case 115: /* multiselect_op ::= UNION */ yytestcase(yyruleno==115);
    +-      case 117: /* multiselect_op ::= EXCEPT|INTERSECT */ yytestcase(yyruleno==117);
    +-{yygotominor.yy328 = yymsp[0].major;}
    ++      case 5: /* transtype ::= DEFERRED */
    ++      case 6: /* transtype ::= IMMEDIATE */ yytestcase(yyruleno==6);
    ++      case 7: /* transtype ::= EXCLUSIVE */ yytestcase(yyruleno==7);
    ++{yymsp[0].minor.yy4 = yymsp[0].major; /*A-overwrites-X*/}
    +         break;
    +-      case 17: /* cmd ::= COMMIT trans_opt */
    +-      case 18: /* cmd ::= END trans_opt */ yytestcase(yyruleno==18);
    +-{sqlite3CommitTransaction(pParse);}
    ++      case 8: /* cmd ::= COMMIT|END trans_opt */
    ++      case 9: /* cmd ::= ROLLBACK trans_opt */ yytestcase(yyruleno==9);
    ++{sqlite3EndTransaction(pParse,yymsp[-1].major);}
    +         break;
    +-      case 19: /* cmd ::= ROLLBACK trans_opt */
    +-{sqlite3RollbackTransaction(pParse);}
    +-        break;
    +-      case 22: /* cmd ::= SAVEPOINT nm */
    ++      case 10: /* cmd ::= SAVEPOINT nm */
    + {
    +   sqlite3Savepoint(pParse, SAVEPOINT_BEGIN, &yymsp[0].minor.yy0);
    + }
    +         break;
    +-      case 23: /* cmd ::= RELEASE savepoint_opt nm */
    ++      case 11: /* cmd ::= RELEASE savepoint_opt nm */
    + {
    +   sqlite3Savepoint(pParse, SAVEPOINT_RELEASE, &yymsp[0].minor.yy0);
    + }
    +         break;
    +-      case 24: /* cmd ::= ROLLBACK trans_opt TO savepoint_opt nm */
    ++      case 12: /* cmd ::= ROLLBACK trans_opt TO savepoint_opt nm */
    + {
    +   sqlite3Savepoint(pParse, SAVEPOINT_ROLLBACK, &yymsp[0].minor.yy0);
    + }
    +         break;
    +-      case 26: /* create_table ::= createkw temp TABLE ifnotexists nm dbnm */
    ++      case 13: /* create_table ::= createkw temp TABLE ifnotexists nm dbnm */
    + {
    +-   sqlite3StartTable(pParse,&yymsp[-1].minor.yy0,&yymsp[0].minor.yy0,yymsp[-4].minor.yy328,0,0,yymsp[-2].minor.yy328);
    ++   sqlite3StartTable(pParse,&yymsp[-1].minor.yy0,&yymsp[0].minor.yy0,yymsp[-4].minor.yy4,0,0,yymsp[-2].minor.yy4);
    + }
    +         break;
    +-      case 27: /* createkw ::= CREATE */
    +-{
    +-  pParse->db->lookaside.bEnabled = 0;
    +-  yygotominor.yy0 = yymsp[0].minor.yy0;
    +-}
    ++      case 14: /* createkw ::= CREATE */
    ++{disableLookaside(pParse);}
    ++        break;
    ++      case 15: /* ifnotexists ::= */
    ++      case 18: /* temp ::= */ yytestcase(yyruleno==18);
    ++      case 21: /* table_options ::= */ yytestcase(yyruleno==21);
    ++      case 42: /* autoinc ::= */ yytestcase(yyruleno==42);
    ++      case 57: /* init_deferred_pred_opt ::= */ yytestcase(yyruleno==57);
    ++      case 67: /* defer_subclause_opt ::= */ yytestcase(yyruleno==67);
    ++      case 76: /* ifexists ::= */ yytestcase(yyruleno==76);
    ++      case 90: /* distinct ::= */ yytestcase(yyruleno==90);
    ++      case 213: /* collate ::= */ yytestcase(yyruleno==213);
    ++{yymsp[1].minor.yy4 = 0;}
    +         break;
    +-      case 28: /* ifnotexists ::= */
    +-      case 31: /* temp ::= */ yytestcase(yyruleno==31);
    +-      case 68: /* autoinc ::= */ yytestcase(yyruleno==68);
    +-      case 81: /* defer_subclause ::= NOT DEFERRABLE init_deferred_pred_opt */ yytestcase(yyruleno==81);
    +-      case 83: /* init_deferred_pred_opt ::= */ yytestcase(yyruleno==83);
    +-      case 85: /* init_deferred_pred_opt ::= INITIALLY IMMEDIATE */ yytestcase(yyruleno==85);
    +-      case 97: /* defer_subclause_opt ::= */ yytestcase(yyruleno==97);
    +-      case 108: /* ifexists ::= */ yytestcase(yyruleno==108);
    +-      case 219: /* between_op ::= BETWEEN */ yytestcase(yyruleno==219);
    +-      case 222: /* in_op ::= IN */ yytestcase(yyruleno==222);
    +-      case 247: /* collate ::= */ yytestcase(yyruleno==247);
    +-{yygotominor.yy328 = 0;}
    ++      case 16: /* ifnotexists ::= IF NOT EXISTS */
    ++{yymsp[-2].minor.yy4 = 1;}
    +         break;
    +-      case 29: /* ifnotexists ::= IF NOT EXISTS */
    +-      case 30: /* temp ::= TEMP */ yytestcase(yyruleno==30);
    +-      case 69: /* autoinc ::= AUTOINCR */ yytestcase(yyruleno==69);
    +-      case 84: /* init_deferred_pred_opt ::= INITIALLY DEFERRED */ yytestcase(yyruleno==84);
    +-      case 107: /* ifexists ::= IF EXISTS */ yytestcase(yyruleno==107);
    +-      case 220: /* between_op ::= NOT BETWEEN */ yytestcase(yyruleno==220);
    +-      case 223: /* in_op ::= NOT IN */ yytestcase(yyruleno==223);
    +-      case 248: /* collate ::= COLLATE ID|STRING */ yytestcase(yyruleno==248);
    +-{yygotominor.yy328 = 1;}
    ++      case 17: /* temp ::= TEMP */
    ++      case 43: /* autoinc ::= AUTOINCR */ yytestcase(yyruleno==43);
    ++{yymsp[0].minor.yy4 = 1;}
    +         break;
    +-      case 32: /* create_table_args ::= LP columnlist conslist_opt RP table_options */
    ++      case 19: /* create_table_args ::= LP columnlist conslist_opt RP table_options */
    + {
    +-  sqlite3EndTable(pParse,&yymsp[-2].minor.yy0,&yymsp[-1].minor.yy0,yymsp[0].minor.yy186,0);
    ++  sqlite3EndTable(pParse,&yymsp[-2].minor.yy0,&yymsp[-1].minor.yy0,yymsp[0].minor.yy4,0);
    + }
    +         break;
    +-      case 33: /* create_table_args ::= AS select */
    ++      case 20: /* create_table_args ::= AS select */
    + {
    +-  sqlite3EndTable(pParse,0,0,0,yymsp[0].minor.yy3);
    +-  sqlite3SelectDelete(pParse->db, yymsp[0].minor.yy3);
    ++  sqlite3EndTable(pParse,0,0,0,yymsp[0].minor.yy387);
    ++  sqlite3SelectDelete(pParse->db, yymsp[0].minor.yy387);
    + }
    +         break;
    +-      case 34: /* table_options ::= */
    +-{yygotominor.yy186 = 0;}
    +-        break;
    +-      case 35: /* table_options ::= WITHOUT nm */
    ++      case 22: /* table_options ::= WITHOUT nm */
    + {
    +   if( yymsp[0].minor.yy0.n==5 && sqlite3_strnicmp(yymsp[0].minor.yy0.z,"rowid",5)==0 ){
    +-    yygotominor.yy186 = TF_WithoutRowid | TF_NoVisibleRowid;
    ++    yymsp[-1].minor.yy4 = TF_WithoutRowid | TF_NoVisibleRowid;
    +   }else{
    +-    yygotominor.yy186 = 0;
    ++    yymsp[-1].minor.yy4 = 0;
    +     sqlite3ErrorMsg(pParse, "unknown table option: %.*s", yymsp[0].minor.yy0.n, yymsp[0].minor.yy0.z);
    +   }
    + }
    +         break;
    +-      case 38: /* column ::= columnid type carglist */
    +-{
    +-  yygotominor.yy0.z = yymsp[-2].minor.yy0.z;
    +-  yygotominor.yy0.n = (int)(pParse->sLastToken.z-yymsp[-2].minor.yy0.z) + pParse->sLastToken.n;
    +-}
    ++      case 23: /* columnname ::= nm typetoken */
    ++{sqlite3AddColumn(pParse,&yymsp[-1].minor.yy0,&yymsp[0].minor.yy0);}
    ++        break;
    ++      case 24: /* typetoken ::= */
    ++      case 60: /* conslist_opt ::= */ yytestcase(yyruleno==60);
    ++      case 96: /* as ::= */ yytestcase(yyruleno==96);
    ++{yymsp[1].minor.yy0.n = 0; yymsp[1].minor.yy0.z = 0;}
    +         break;
    +-      case 39: /* columnid ::= nm */
    ++      case 25: /* typetoken ::= typename LP signed RP */
    + {
    +-  sqlite3AddColumn(pParse,&yymsp[0].minor.yy0);
    +-  yygotominor.yy0 = yymsp[0].minor.yy0;
    +-  pParse->constraintName.n = 0;
    ++  yymsp[-3].minor.yy0.n = (int)(&yymsp[0].minor.yy0.z[yymsp[0].minor.yy0.n] - yymsp[-3].minor.yy0.z);
    + }
    +         break;
    +-      case 40: /* nm ::= ID|INDEXED */
    +-      case 41: /* nm ::= STRING */ yytestcase(yyruleno==41);
    +-      case 42: /* nm ::= JOIN_KW */ yytestcase(yyruleno==42);
    +-      case 45: /* typetoken ::= typename */ yytestcase(yyruleno==45);
    +-      case 48: /* typename ::= ID|STRING */ yytestcase(yyruleno==48);
    +-      case 130: /* as ::= AS nm */ yytestcase(yyruleno==130);
    +-      case 131: /* as ::= ID|STRING */ yytestcase(yyruleno==131);
    +-      case 142: /* dbnm ::= DOT nm */ yytestcase(yyruleno==142);
    +-      case 151: /* indexed_opt ::= INDEXED BY nm */ yytestcase(yyruleno==151);
    +-      case 257: /* nmnum ::= plus_num */ yytestcase(yyruleno==257);
    +-      case 258: /* nmnum ::= nm */ yytestcase(yyruleno==258);
    +-      case 259: /* nmnum ::= ON */ yytestcase(yyruleno==259);
    +-      case 260: /* nmnum ::= DELETE */ yytestcase(yyruleno==260);
    +-      case 261: /* nmnum ::= DEFAULT */ yytestcase(yyruleno==261);
    +-      case 262: /* plus_num ::= PLUS INTEGER|FLOAT */ yytestcase(yyruleno==262);
    +-      case 263: /* plus_num ::= INTEGER|FLOAT */ yytestcase(yyruleno==263);
    +-      case 264: /* minus_num ::= MINUS INTEGER|FLOAT */ yytestcase(yyruleno==264);
    +-      case 280: /* trnm ::= nm */ yytestcase(yyruleno==280);
    +-{yygotominor.yy0 = yymsp[0].minor.yy0;}
    +-        break;
    +-      case 44: /* type ::= typetoken */
    +-{sqlite3AddColumnType(pParse,&yymsp[0].minor.yy0);}
    +-        break;
    +-      case 46: /* typetoken ::= typename LP signed RP */
    ++      case 26: /* typetoken ::= typename LP signed COMMA signed RP */
    + {
    +-  yygotominor.yy0.z = yymsp[-3].minor.yy0.z;
    +-  yygotominor.yy0.n = (int)(&yymsp[0].minor.yy0.z[yymsp[0].minor.yy0.n] - yymsp[-3].minor.yy0.z);
    ++  yymsp[-5].minor.yy0.n = (int)(&yymsp[0].minor.yy0.z[yymsp[0].minor.yy0.n] - yymsp[-5].minor.yy0.z);
    + }
    +         break;
    +-      case 47: /* typetoken ::= typename LP signed COMMA signed RP */
    ++      case 27: /* typename ::= typename ID|STRING */
    ++{yymsp[-1].minor.yy0.n=yymsp[0].minor.yy0.n+(int)(yymsp[0].minor.yy0.z-yymsp[-1].minor.yy0.z);}
    ++        break;
    ++      case 28: /* scanpt ::= */
    + {
    +-  yygotominor.yy0.z = yymsp[-5].minor.yy0.z;
    +-  yygotominor.yy0.n = (int)(&yymsp[0].minor.yy0.z[yymsp[0].minor.yy0.n] - yymsp[-5].minor.yy0.z);
    ++  assert( yyLookahead!=YYNOCODE );
    ++  yymsp[1].minor.yy336 = yyLookaheadToken.z;
    + }
    +         break;
    +-      case 49: /* typename ::= typename ID|STRING */
    +-{yygotominor.yy0.z=yymsp[-1].minor.yy0.z; yygotominor.yy0.n=yymsp[0].minor.yy0.n+(int)(yymsp[0].minor.yy0.z-yymsp[-1].minor.yy0.z);}
    +-        break;
    +-      case 54: /* ccons ::= CONSTRAINT nm */
    +-      case 92: /* tcons ::= CONSTRAINT nm */ yytestcase(yyruleno==92);
    ++      case 29: /* ccons ::= CONSTRAINT nm */
    ++      case 62: /* tcons ::= CONSTRAINT nm */ yytestcase(yyruleno==62);
    + {pParse->constraintName = yymsp[0].minor.yy0;}
    +         break;
    +-      case 55: /* ccons ::= DEFAULT term */
    +-      case 57: /* ccons ::= DEFAULT PLUS term */ yytestcase(yyruleno==57);
    +-{sqlite3AddDefaultValue(pParse,&yymsp[0].minor.yy346);}
    ++      case 30: /* ccons ::= DEFAULT scanpt term scanpt */
    ++{sqlite3AddDefaultValue(pParse,yymsp[-1].minor.yy314,yymsp[-2].minor.yy336,yymsp[0].minor.yy336);}
    +         break;
    +-      case 56: /* ccons ::= DEFAULT LP expr RP */
    +-{sqlite3AddDefaultValue(pParse,&yymsp[-1].minor.yy346);}
    ++      case 31: /* ccons ::= DEFAULT LP expr RP */
    ++{sqlite3AddDefaultValue(pParse,yymsp[-1].minor.yy314,yymsp[-2].minor.yy0.z+1,yymsp[0].minor.yy0.z);}
    +         break;
    +-      case 58: /* ccons ::= DEFAULT MINUS term */
    ++      case 32: /* ccons ::= DEFAULT PLUS term scanpt */
    ++{sqlite3AddDefaultValue(pParse,yymsp[-1].minor.yy314,yymsp[-2].minor.yy0.z,yymsp[0].minor.yy336);}
    ++        break;
    ++      case 33: /* ccons ::= DEFAULT MINUS term scanpt */
    + {
    +-  ExprSpan v;
    +-  v.pExpr = sqlite3PExpr(pParse, TK_UMINUS, yymsp[0].minor.yy346.pExpr, 0, 0);
    +-  v.zStart = yymsp[-1].minor.yy0.z;
    +-  v.zEnd = yymsp[0].minor.yy346.zEnd;
    +-  sqlite3AddDefaultValue(pParse,&v);
    ++  Expr *p = sqlite3PExpr(pParse, TK_UMINUS, yymsp[-1].minor.yy314, 0);
    ++  sqlite3AddDefaultValue(pParse,p,yymsp[-2].minor.yy0.z,yymsp[0].minor.yy336);
    + }
    +         break;
    +-      case 59: /* ccons ::= DEFAULT ID|INDEXED */
    ++      case 34: /* ccons ::= DEFAULT scanpt ID|INDEXED */
    + {
    +-  ExprSpan v;
    +-  spanExpr(&v, pParse, TK_STRING, &yymsp[0].minor.yy0);
    +-  sqlite3AddDefaultValue(pParse,&v);
    ++  Expr *p = tokenExpr(pParse, TK_STRING, yymsp[0].minor.yy0);
    ++  sqlite3AddDefaultValue(pParse,p,yymsp[0].minor.yy0.z,yymsp[0].minor.yy0.z+yymsp[0].minor.yy0.n);
    + }
    +         break;
    +-      case 61: /* ccons ::= NOT NULL onconf */
    +-{sqlite3AddNotNull(pParse, yymsp[0].minor.yy328);}
    ++      case 35: /* ccons ::= NOT NULL onconf */
    ++{sqlite3AddNotNull(pParse, yymsp[0].minor.yy4);}
    +         break;
    +-      case 62: /* ccons ::= PRIMARY KEY sortorder onconf autoinc */
    +-{sqlite3AddPrimaryKey(pParse,0,yymsp[-1].minor.yy328,yymsp[0].minor.yy328,yymsp[-2].minor.yy328);}
    ++      case 36: /* ccons ::= PRIMARY KEY sortorder onconf autoinc */
    ++{sqlite3AddPrimaryKey(pParse,0,yymsp[-1].minor.yy4,yymsp[0].minor.yy4,yymsp[-2].minor.yy4);}
    +         break;
    +-      case 63: /* ccons ::= UNIQUE onconf */
    +-{sqlite3CreateIndex(pParse,0,0,0,0,yymsp[0].minor.yy328,0,0,0,0);}
    ++      case 37: /* ccons ::= UNIQUE onconf */
    ++{sqlite3CreateIndex(pParse,0,0,0,0,yymsp[0].minor.yy4,0,0,0,0,
    ++                                   SQLITE_IDXTYPE_UNIQUE);}
    +         break;
    +-      case 64: /* ccons ::= CHECK LP expr RP */
    +-{sqlite3AddCheckConstraint(pParse,yymsp[-1].minor.yy346.pExpr);}
    ++      case 38: /* ccons ::= CHECK LP expr RP */
    ++{sqlite3AddCheckConstraint(pParse,yymsp[-1].minor.yy314);}
    +         break;
    +-      case 65: /* ccons ::= REFERENCES nm eidlist_opt refargs */
    +-{sqlite3CreateForeignKey(pParse,0,&yymsp[-2].minor.yy0,yymsp[-1].minor.yy14,yymsp[0].minor.yy328);}
    ++      case 39: /* ccons ::= REFERENCES nm eidlist_opt refargs */
    ++{sqlite3CreateForeignKey(pParse,0,&yymsp[-2].minor.yy0,yymsp[-1].minor.yy322,yymsp[0].minor.yy4);}
    +         break;
    +-      case 66: /* ccons ::= defer_subclause */
    +-{sqlite3DeferForeignKey(pParse,yymsp[0].minor.yy328);}
    ++      case 40: /* ccons ::= defer_subclause */
    ++{sqlite3DeferForeignKey(pParse,yymsp[0].minor.yy4);}
    +         break;
    +-      case 67: /* ccons ::= COLLATE ID|STRING */
    ++      case 41: /* ccons ::= COLLATE ID|STRING */
    + {sqlite3AddCollateType(pParse, &yymsp[0].minor.yy0);}
    +         break;
    +-      case 70: /* refargs ::= */
    +-{ yygotominor.yy328 = OE_None*0x0101; /* EV: R-19803-45884 */}
    ++      case 44: /* refargs ::= */
    ++{ yymsp[1].minor.yy4 = OE_None*0x0101; /* EV: R-19803-45884 */}
    ++        break;
    ++      case 45: /* refargs ::= refargs refarg */
    ++{ yymsp[-1].minor.yy4 = (yymsp[-1].minor.yy4 & ~yymsp[0].minor.yy215.mask) | yymsp[0].minor.yy215.value; }
    +         break;
    +-      case 71: /* refargs ::= refargs refarg */
    +-{ yygotominor.yy328 = (yymsp[-1].minor.yy328 & ~yymsp[0].minor.yy429.mask) | yymsp[0].minor.yy429.value; }
    ++      case 46: /* refarg ::= MATCH nm */
    ++{ yymsp[-1].minor.yy215.value = 0;     yymsp[-1].minor.yy215.mask = 0x000000; }
    +         break;
    +-      case 72: /* refarg ::= MATCH nm */
    +-      case 73: /* refarg ::= ON INSERT refact */ yytestcase(yyruleno==73);
    +-{ yygotominor.yy429.value = 0;     yygotominor.yy429.mask = 0x000000; }
    ++      case 47: /* refarg ::= ON INSERT refact */
    ++{ yymsp[-2].minor.yy215.value = 0;     yymsp[-2].minor.yy215.mask = 0x000000; }
    +         break;
    +-      case 74: /* refarg ::= ON DELETE refact */
    +-{ yygotominor.yy429.value = yymsp[0].minor.yy328;     yygotominor.yy429.mask = 0x0000ff; }
    ++      case 48: /* refarg ::= ON DELETE refact */
    ++{ yymsp[-2].minor.yy215.value = yymsp[0].minor.yy4;     yymsp[-2].minor.yy215.mask = 0x0000ff; }
    +         break;
    +-      case 75: /* refarg ::= ON UPDATE refact */
    +-{ yygotominor.yy429.value = yymsp[0].minor.yy328<<8;  yygotominor.yy429.mask = 0x00ff00; }
    ++      case 49: /* refarg ::= ON UPDATE refact */
    ++{ yymsp[-2].minor.yy215.value = yymsp[0].minor.yy4<<8;  yymsp[-2].minor.yy215.mask = 0x00ff00; }
    +         break;
    +-      case 76: /* refact ::= SET NULL */
    +-{ yygotominor.yy328 = OE_SetNull;  /* EV: R-33326-45252 */}
    ++      case 50: /* refact ::= SET NULL */
    ++{ yymsp[-1].minor.yy4 = OE_SetNull;  /* EV: R-33326-45252 */}
    +         break;
    +-      case 77: /* refact ::= SET DEFAULT */
    +-{ yygotominor.yy328 = OE_SetDflt;  /* EV: R-33326-45252 */}
    ++      case 51: /* refact ::= SET DEFAULT */
    ++{ yymsp[-1].minor.yy4 = OE_SetDflt;  /* EV: R-33326-45252 */}
    +         break;
    +-      case 78: /* refact ::= CASCADE */
    +-{ yygotominor.yy328 = OE_Cascade;  /* EV: R-33326-45252 */}
    ++      case 52: /* refact ::= CASCADE */
    ++{ yymsp[0].minor.yy4 = OE_Cascade;  /* EV: R-33326-45252 */}
    +         break;
    +-      case 79: /* refact ::= RESTRICT */
    +-{ yygotominor.yy328 = OE_Restrict; /* EV: R-33326-45252 */}
    ++      case 53: /* refact ::= RESTRICT */
    ++{ yymsp[0].minor.yy4 = OE_Restrict; /* EV: R-33326-45252 */}
    +         break;
    +-      case 80: /* refact ::= NO ACTION */
    +-{ yygotominor.yy328 = OE_None;     /* EV: R-33326-45252 */}
    ++      case 54: /* refact ::= NO ACTION */
    ++{ yymsp[-1].minor.yy4 = OE_None;     /* EV: R-33326-45252 */}
    +         break;
    +-      case 82: /* defer_subclause ::= DEFERRABLE init_deferred_pred_opt */
    +-      case 98: /* defer_subclause_opt ::= defer_subclause */ yytestcase(yyruleno==98);
    +-      case 100: /* onconf ::= ON CONFLICT resolvetype */ yytestcase(yyruleno==100);
    +-      case 103: /* resolvetype ::= raisetype */ yytestcase(yyruleno==103);
    +-{yygotominor.yy328 = yymsp[0].minor.yy328;}
    ++      case 55: /* defer_subclause ::= NOT DEFERRABLE init_deferred_pred_opt */
    ++{yymsp[-2].minor.yy4 = 0;}
    +         break;
    +-      case 86: /* conslist_opt ::= */
    +-{yygotominor.yy0.n = 0; yygotominor.yy0.z = 0;}
    ++      case 56: /* defer_subclause ::= DEFERRABLE init_deferred_pred_opt */
    ++      case 71: /* orconf ::= OR resolvetype */ yytestcase(yyruleno==71);
    ++      case 144: /* insert_cmd ::= INSERT orconf */ yytestcase(yyruleno==144);
    ++{yymsp[-1].minor.yy4 = yymsp[0].minor.yy4;}
    +         break;
    +-      case 87: /* conslist_opt ::= COMMA conslist */
    +-{yygotominor.yy0 = yymsp[-1].minor.yy0;}
    ++      case 58: /* init_deferred_pred_opt ::= INITIALLY DEFERRED */
    ++      case 75: /* ifexists ::= IF EXISTS */ yytestcase(yyruleno==75);
    ++      case 185: /* between_op ::= NOT BETWEEN */ yytestcase(yyruleno==185);
    ++      case 188: /* in_op ::= NOT IN */ yytestcase(yyruleno==188);
    ++      case 214: /* collate ::= COLLATE ID|STRING */ yytestcase(yyruleno==214);
    ++{yymsp[-1].minor.yy4 = 1;}
    +         break;
    +-      case 90: /* tconscomma ::= COMMA */
    ++      case 59: /* init_deferred_pred_opt ::= INITIALLY IMMEDIATE */
    ++{yymsp[-1].minor.yy4 = 0;}
    ++        break;
    ++      case 61: /* tconscomma ::= COMMA */
    + {pParse->constraintName.n = 0;}
    +         break;
    +-      case 93: /* tcons ::= PRIMARY KEY LP sortlist autoinc RP onconf */
    +-{sqlite3AddPrimaryKey(pParse,yymsp[-3].minor.yy14,yymsp[0].minor.yy328,yymsp[-2].minor.yy328,0);}
    ++      case 63: /* tcons ::= PRIMARY KEY LP sortlist autoinc RP onconf */
    ++{sqlite3AddPrimaryKey(pParse,yymsp[-3].minor.yy322,yymsp[0].minor.yy4,yymsp[-2].minor.yy4,0);}
    +         break;
    +-      case 94: /* tcons ::= UNIQUE LP sortlist RP onconf */
    +-{sqlite3CreateIndex(pParse,0,0,0,yymsp[-2].minor.yy14,yymsp[0].minor.yy328,0,0,0,0);}
    ++      case 64: /* tcons ::= UNIQUE LP sortlist RP onconf */
    ++{sqlite3CreateIndex(pParse,0,0,0,yymsp[-2].minor.yy322,yymsp[0].minor.yy4,0,0,0,0,
    ++                                       SQLITE_IDXTYPE_UNIQUE);}
    +         break;
    +-      case 95: /* tcons ::= CHECK LP expr RP onconf */
    +-{sqlite3AddCheckConstraint(pParse,yymsp[-2].minor.yy346.pExpr);}
    ++      case 65: /* tcons ::= CHECK LP expr RP onconf */
    ++{sqlite3AddCheckConstraint(pParse,yymsp[-2].minor.yy314);}
    +         break;
    +-      case 96: /* tcons ::= FOREIGN KEY LP eidlist RP REFERENCES nm eidlist_opt refargs defer_subclause_opt */
    ++      case 66: /* tcons ::= FOREIGN KEY LP eidlist RP REFERENCES nm eidlist_opt refargs defer_subclause_opt */
    + {
    +-    sqlite3CreateForeignKey(pParse, yymsp[-6].minor.yy14, &yymsp[-3].minor.yy0, yymsp[-2].minor.yy14, yymsp[-1].minor.yy328);
    +-    sqlite3DeferForeignKey(pParse, yymsp[0].minor.yy328);
    ++    sqlite3CreateForeignKey(pParse, yymsp[-6].minor.yy322, &yymsp[-3].minor.yy0, yymsp[-2].minor.yy322, yymsp[-1].minor.yy4);
    ++    sqlite3DeferForeignKey(pParse, yymsp[0].minor.yy4);
    + }
    +         break;
    +-      case 99: /* onconf ::= */
    +-{yygotominor.yy328 = OE_Default;}
    +-        break;
    +-      case 101: /* orconf ::= */
    +-{yygotominor.yy186 = OE_Default;}
    ++      case 68: /* onconf ::= */
    ++      case 70: /* orconf ::= */ yytestcase(yyruleno==70);
    ++{yymsp[1].minor.yy4 = OE_Default;}
    +         break;
    +-      case 102: /* orconf ::= OR resolvetype */
    +-{yygotominor.yy186 = (u8)yymsp[0].minor.yy328;}
    ++      case 69: /* onconf ::= ON CONFLICT resolvetype */
    ++{yymsp[-2].minor.yy4 = yymsp[0].minor.yy4;}
    +         break;
    +-      case 104: /* resolvetype ::= IGNORE */
    +-{yygotominor.yy328 = OE_Ignore;}
    ++      case 72: /* resolvetype ::= IGNORE */
    ++{yymsp[0].minor.yy4 = OE_Ignore;}
    +         break;
    +-      case 105: /* resolvetype ::= REPLACE */
    +-{yygotominor.yy328 = OE_Replace;}
    ++      case 73: /* resolvetype ::= REPLACE */
    ++      case 145: /* insert_cmd ::= REPLACE */ yytestcase(yyruleno==145);
    ++{yymsp[0].minor.yy4 = OE_Replace;}
    +         break;
    +-      case 106: /* cmd ::= DROP TABLE ifexists fullname */
    ++      case 74: /* cmd ::= DROP TABLE ifexists fullname */
    + {
    +-  sqlite3DropTable(pParse, yymsp[0].minor.yy65, 0, yymsp[-1].minor.yy328);
    ++  sqlite3DropTable(pParse, yymsp[0].minor.yy259, 0, yymsp[-1].minor.yy4);
    + }
    +         break;
    +-      case 109: /* cmd ::= createkw temp VIEW ifnotexists nm dbnm eidlist_opt AS select */
    ++      case 77: /* cmd ::= createkw temp VIEW ifnotexists nm dbnm eidlist_opt AS select */
    + {
    +-  sqlite3CreateView(pParse, &yymsp[-8].minor.yy0, &yymsp[-4].minor.yy0, &yymsp[-3].minor.yy0, yymsp[-2].minor.yy14, yymsp[0].minor.yy3, yymsp[-7].minor.yy328, yymsp[-5].minor.yy328);
    ++  sqlite3CreateView(pParse, &yymsp[-8].minor.yy0, &yymsp[-4].minor.yy0, &yymsp[-3].minor.yy0, yymsp[-2].minor.yy322, yymsp[0].minor.yy387, yymsp[-7].minor.yy4, yymsp[-5].minor.yy4);
    + }
    +         break;
    +-      case 110: /* cmd ::= DROP VIEW ifexists fullname */
    ++      case 78: /* cmd ::= DROP VIEW ifexists fullname */
    + {
    +-  sqlite3DropTable(pParse, yymsp[0].minor.yy65, 1, yymsp[-1].minor.yy328);
    ++  sqlite3DropTable(pParse, yymsp[0].minor.yy259, 1, yymsp[-1].minor.yy4);
    + }
    +         break;
    +-      case 111: /* cmd ::= select */
    ++      case 79: /* cmd ::= select */
    + {
    +   SelectDest dest = {SRT_Output, 0, 0, 0, 0, 0};
    +-  sqlite3Select(pParse, yymsp[0].minor.yy3, &dest);
    +-  sqlite3SelectDelete(pParse->db, yymsp[0].minor.yy3);
    ++  sqlite3Select(pParse, yymsp[0].minor.yy387, &dest);
    ++  sqlite3SelectDelete(pParse->db, yymsp[0].minor.yy387);
    + }
    +         break;
    +-      case 112: /* select ::= with selectnowith */
    ++      case 80: /* select ::= with selectnowith */
    + {
    +-  Select *p = yymsp[0].minor.yy3;
    ++  Select *p = yymsp[0].minor.yy387;
    +   if( p ){
    +-    p->pWith = yymsp[-1].minor.yy59;
    ++    p->pWith = yymsp[-1].minor.yy451;
    +     parserDoubleLinkSelect(pParse, p);
    +   }else{
    +-    sqlite3WithDelete(pParse->db, yymsp[-1].minor.yy59);
    ++    sqlite3WithDelete(pParse->db, yymsp[-1].minor.yy451);
    +   }
    +-  yygotominor.yy3 = p;
    ++  yymsp[-1].minor.yy387 = p; /*A-overwrites-W*/
    + }
    +         break;
    +-      case 113: /* selectnowith ::= oneselect */
    +-      case 119: /* oneselect ::= values */ yytestcase(yyruleno==119);
    +-{yygotominor.yy3 = yymsp[0].minor.yy3;}
    +-        break;
    +-      case 114: /* selectnowith ::= selectnowith multiselect_op oneselect */
    ++      case 81: /* selectnowith ::= selectnowith multiselect_op oneselect */
    + {
    +-  Select *pRhs = yymsp[0].minor.yy3;
    +-  Select *pLhs = yymsp[-2].minor.yy3;
    ++  Select *pRhs = yymsp[0].minor.yy387;
    ++  Select *pLhs = yymsp[-2].minor.yy387;
    +   if( pRhs && pRhs->pPrior ){
    +     SrcList *pFrom;
    +     Token x;
    +     x.n = 0;
    +     parserDoubleLinkSelect(pParse, pRhs);
    +     pFrom = sqlite3SrcListAppendFromTerm(pParse,0,0,0,&x,pRhs,0,0);
    +-    pRhs = sqlite3SelectNew(pParse,0,pFrom,0,0,0,0,0,0,0);
    ++    pRhs = sqlite3SelectNew(pParse,0,pFrom,0,0,0,0,0,0);
    +   }
    +   if( pRhs ){
    +-    pRhs->op = (u8)yymsp[-1].minor.yy328;
    ++    pRhs->op = (u8)yymsp[-1].minor.yy4;
    +     pRhs->pPrior = pLhs;
    +     if( ALWAYS(pLhs) ) pLhs->selFlags &= ~SF_MultiValue;
    +     pRhs->selFlags &= ~SF_MultiValue;
    +-    if( yymsp[-1].minor.yy328!=TK_ALL ) pParse->hasCompound = 1;
    ++    if( yymsp[-1].minor.yy4!=TK_ALL ) pParse->hasCompound = 1;
    +   }else{
    +     sqlite3SelectDelete(pParse->db, pLhs);
    +   }
    +-  yygotominor.yy3 = pRhs;
    ++  yymsp[-2].minor.yy387 = pRhs;
    + }
    +         break;
    +-      case 116: /* multiselect_op ::= UNION ALL */
    +-{yygotominor.yy328 = TK_ALL;}
    ++      case 82: /* multiselect_op ::= UNION */
    ++      case 84: /* multiselect_op ::= EXCEPT|INTERSECT */ yytestcase(yyruleno==84);
    ++{yymsp[0].minor.yy4 = yymsp[0].major; /*A-overwrites-OP*/}
    ++        break;
    ++      case 83: /* multiselect_op ::= UNION ALL */
    ++{yymsp[-1].minor.yy4 = TK_ALL;}
    +         break;
    +-      case 118: /* oneselect ::= SELECT distinct selcollist from where_opt groupby_opt having_opt orderby_opt limit_opt */
    ++      case 85: /* oneselect ::= SELECT distinct selcollist from where_opt groupby_opt having_opt orderby_opt limit_opt */
    + {
    +-  yygotominor.yy3 = sqlite3SelectNew(pParse,yymsp[-6].minor.yy14,yymsp[-5].minor.yy65,yymsp[-4].minor.yy132,yymsp[-3].minor.yy14,yymsp[-2].minor.yy132,yymsp[-1].minor.yy14,yymsp[-7].minor.yy381,yymsp[0].minor.yy476.pLimit,yymsp[0].minor.yy476.pOffset);
    ++#if SELECTTRACE_ENABLED
    ++  Token s = yymsp[-8].minor.yy0; /*A-overwrites-S*/
    ++#endif
    ++  yymsp[-8].minor.yy387 = sqlite3SelectNew(pParse,yymsp[-6].minor.yy322,yymsp[-5].minor.yy259,yymsp[-4].minor.yy314,yymsp[-3].minor.yy322,yymsp[-2].minor.yy314,yymsp[-1].minor.yy322,yymsp[-7].minor.yy4,yymsp[0].minor.yy314);
    + #if SELECTTRACE_ENABLED
    +   /* Populate the Select.zSelName[] string that is used to help with
    +   ** query planner debugging, to differentiate between multiple Select
    +@@ -128497,455 +140901,468 @@ static void yy_reduce(
    +   ** comment to be the zSelName value.  Otherwise, the label is #N where
    +   ** is an integer that is incremented with each SELECT statement seen.
    +   */
    +-  if( yygotominor.yy3!=0 ){
    +-    const char *z = yymsp[-8].minor.yy0.z+6;
    ++  if( yymsp[-8].minor.yy387!=0 ){
    ++    const char *z = s.z+6;
    +     int i;
    +-    sqlite3_snprintf(sizeof(yygotominor.yy3->zSelName), yygotominor.yy3->zSelName, "#%d",
    ++    sqlite3_snprintf(sizeof(yymsp[-8].minor.yy387->zSelName), yymsp[-8].minor.yy387->zSelName, "#%d",
    +                      ++pParse->nSelect);
    +     while( z[0]==' ' ) z++;
    +     if( z[0]=='/' && z[1]=='*' ){
    +       z += 2;
    +       while( z[0]==' ' ) z++;
    +       for(i=0; sqlite3Isalnum(z[i]); i++){}
    +-      sqlite3_snprintf(sizeof(yygotominor.yy3->zSelName), yygotominor.yy3->zSelName, "%.*s", i, z);
    ++      sqlite3_snprintf(sizeof(yymsp[-8].minor.yy387->zSelName), yymsp[-8].minor.yy387->zSelName, "%.*s", i, z);
    +     }
    +   }
    + #endif /* SELECTRACE_ENABLED */
    + }
    +         break;
    +-      case 120: /* values ::= VALUES LP nexprlist RP */
    ++      case 86: /* values ::= VALUES LP nexprlist RP */
    + {
    +-  yygotominor.yy3 = sqlite3SelectNew(pParse,yymsp[-1].minor.yy14,0,0,0,0,0,SF_Values,0,0);
    ++  yymsp[-3].minor.yy387 = sqlite3SelectNew(pParse,yymsp[-1].minor.yy322,0,0,0,0,0,SF_Values,0);
    + }
    +         break;
    +-      case 121: /* values ::= values COMMA LP exprlist RP */
    ++      case 87: /* values ::= values COMMA LP exprlist RP */
    + {
    +-  Select *pRight, *pLeft = yymsp[-4].minor.yy3;
    +-  pRight = sqlite3SelectNew(pParse,yymsp[-1].minor.yy14,0,0,0,0,0,SF_Values|SF_MultiValue,0,0);
    ++  Select *pRight, *pLeft = yymsp[-4].minor.yy387;
    ++  pRight = sqlite3SelectNew(pParse,yymsp[-1].minor.yy322,0,0,0,0,0,SF_Values|SF_MultiValue,0);
    +   if( ALWAYS(pLeft) ) pLeft->selFlags &= ~SF_MultiValue;
    +   if( pRight ){
    +     pRight->op = TK_ALL;
    +-    pLeft = yymsp[-4].minor.yy3;
    +     pRight->pPrior = pLeft;
    +-    yygotominor.yy3 = pRight;
    ++    yymsp[-4].minor.yy387 = pRight;
    +   }else{
    +-    yygotominor.yy3 = pLeft;
    ++    yymsp[-4].minor.yy387 = pLeft;
    +   }
    + }
    +         break;
    +-      case 122: /* distinct ::= DISTINCT */
    +-{yygotominor.yy381 = SF_Distinct;}
    +-        break;
    +-      case 123: /* distinct ::= ALL */
    +-{yygotominor.yy381 = SF_All;}
    +-        break;
    +-      case 124: /* distinct ::= */
    +-{yygotominor.yy381 = 0;}
    ++      case 88: /* distinct ::= DISTINCT */
    ++{yymsp[0].minor.yy4 = SF_Distinct;}
    +         break;
    +-      case 125: /* sclp ::= selcollist COMMA */
    +-      case 244: /* eidlist_opt ::= LP eidlist RP */ yytestcase(yyruleno==244);
    +-{yygotominor.yy14 = yymsp[-1].minor.yy14;}
    ++      case 89: /* distinct ::= ALL */
    ++{yymsp[0].minor.yy4 = SF_All;}
    +         break;
    +-      case 126: /* sclp ::= */
    +-      case 155: /* orderby_opt ::= */ yytestcase(yyruleno==155);
    +-      case 162: /* groupby_opt ::= */ yytestcase(yyruleno==162);
    +-      case 237: /* exprlist ::= */ yytestcase(yyruleno==237);
    +-      case 243: /* eidlist_opt ::= */ yytestcase(yyruleno==243);
    +-{yygotominor.yy14 = 0;}
    ++      case 91: /* sclp ::= */
    ++      case 119: /* orderby_opt ::= */ yytestcase(yyruleno==119);
    ++      case 126: /* groupby_opt ::= */ yytestcase(yyruleno==126);
    ++      case 201: /* exprlist ::= */ yytestcase(yyruleno==201);
    ++      case 204: /* paren_exprlist ::= */ yytestcase(yyruleno==204);
    ++      case 209: /* eidlist_opt ::= */ yytestcase(yyruleno==209);
    ++{yymsp[1].minor.yy322 = 0;}
    +         break;
    +-      case 127: /* selcollist ::= sclp expr as */
    ++      case 92: /* selcollist ::= sclp scanpt expr scanpt as */
    + {
    +-   yygotominor.yy14 = sqlite3ExprListAppend(pParse, yymsp[-2].minor.yy14, yymsp[-1].minor.yy346.pExpr);
    +-   if( yymsp[0].minor.yy0.n>0 ) sqlite3ExprListSetName(pParse, yygotominor.yy14, &yymsp[0].minor.yy0, 1);
    +-   sqlite3ExprListSetSpan(pParse,yygotominor.yy14,&yymsp[-1].minor.yy346);
    ++   yymsp[-4].minor.yy322 = sqlite3ExprListAppend(pParse, yymsp[-4].minor.yy322, yymsp[-2].minor.yy314);
    ++   if( yymsp[0].minor.yy0.n>0 ) sqlite3ExprListSetName(pParse, yymsp[-4].minor.yy322, &yymsp[0].minor.yy0, 1);
    ++   sqlite3ExprListSetSpan(pParse,yymsp[-4].minor.yy322,yymsp[-3].minor.yy336,yymsp[-1].minor.yy336);
    + }
    +         break;
    +-      case 128: /* selcollist ::= sclp STAR */
    ++      case 93: /* selcollist ::= sclp scanpt STAR */
    + {
    +-  Expr *p = sqlite3Expr(pParse->db, TK_ALL, 0);
    +-  yygotominor.yy14 = sqlite3ExprListAppend(pParse, yymsp[-1].minor.yy14, p);
    ++  Expr *p = sqlite3Expr(pParse->db, TK_ASTERISK, 0);
    ++  yymsp[-2].minor.yy322 = sqlite3ExprListAppend(pParse, yymsp[-2].minor.yy322, p);
    + }
    +         break;
    +-      case 129: /* selcollist ::= sclp nm DOT STAR */
    ++      case 94: /* selcollist ::= sclp scanpt nm DOT STAR */
    + {
    +-  Expr *pRight = sqlite3PExpr(pParse, TK_ALL, 0, 0, &yymsp[0].minor.yy0);
    +-  Expr *pLeft = sqlite3PExpr(pParse, TK_ID, 0, 0, &yymsp[-2].minor.yy0);
    +-  Expr *pDot = sqlite3PExpr(pParse, TK_DOT, pLeft, pRight, 0);
    +-  yygotominor.yy14 = sqlite3ExprListAppend(pParse,yymsp[-3].minor.yy14, pDot);
    ++  Expr *pRight = sqlite3PExpr(pParse, TK_ASTERISK, 0, 0);
    ++  Expr *pLeft = sqlite3ExprAlloc(pParse->db, TK_ID, &yymsp[-2].minor.yy0, 1);
    ++  Expr *pDot = sqlite3PExpr(pParse, TK_DOT, pLeft, pRight);
    ++  yymsp[-4].minor.yy322 = sqlite3ExprListAppend(pParse,yymsp[-4].minor.yy322, pDot);
    + }
    +         break;
    +-      case 132: /* as ::= */
    +-{yygotominor.yy0.n = 0;}
    ++      case 95: /* as ::= AS nm */
    ++      case 106: /* dbnm ::= DOT nm */ yytestcase(yyruleno==106);
    ++      case 223: /* plus_num ::= PLUS INTEGER|FLOAT */ yytestcase(yyruleno==223);
    ++      case 224: /* minus_num ::= MINUS INTEGER|FLOAT */ yytestcase(yyruleno==224);
    ++{yymsp[-1].minor.yy0 = yymsp[0].minor.yy0;}
    +         break;
    +-      case 133: /* from ::= */
    +-{yygotominor.yy65 = sqlite3DbMallocZero(pParse->db, sizeof(*yygotominor.yy65));}
    ++      case 97: /* from ::= */
    ++{yymsp[1].minor.yy259 = sqlite3DbMallocZero(pParse->db, sizeof(*yymsp[1].minor.yy259));}
    +         break;
    +-      case 134: /* from ::= FROM seltablist */
    ++      case 98: /* from ::= FROM seltablist */
    + {
    +-  yygotominor.yy65 = yymsp[0].minor.yy65;
    +-  sqlite3SrcListShiftJoinType(yygotominor.yy65);
    ++  yymsp[-1].minor.yy259 = yymsp[0].minor.yy259;
    ++  sqlite3SrcListShiftJoinType(yymsp[-1].minor.yy259);
    + }
    +         break;
    +-      case 135: /* stl_prefix ::= seltablist joinop */
    ++      case 99: /* stl_prefix ::= seltablist joinop */
    + {
    +-   yygotominor.yy65 = yymsp[-1].minor.yy65;
    +-   if( ALWAYS(yygotominor.yy65 && yygotominor.yy65->nSrc>0) ) yygotominor.yy65->a[yygotominor.yy65->nSrc-1].fg.jointype = (u8)yymsp[0].minor.yy328;
    ++   if( ALWAYS(yymsp[-1].minor.yy259 && yymsp[-1].minor.yy259->nSrc>0) ) yymsp[-1].minor.yy259->a[yymsp[-1].minor.yy259->nSrc-1].fg.jointype = (u8)yymsp[0].minor.yy4;
    + }
    +         break;
    +-      case 136: /* stl_prefix ::= */
    +-{yygotominor.yy65 = 0;}
    ++      case 100: /* stl_prefix ::= */
    ++{yymsp[1].minor.yy259 = 0;}
    +         break;
    +-      case 137: /* seltablist ::= stl_prefix nm dbnm as indexed_opt on_opt using_opt */
    ++      case 101: /* seltablist ::= stl_prefix nm dbnm as indexed_opt on_opt using_opt */
    + {
    +-  yygotominor.yy65 = sqlite3SrcListAppendFromTerm(pParse,yymsp[-6].minor.yy65,&yymsp[-5].minor.yy0,&yymsp[-4].minor.yy0,&yymsp[-3].minor.yy0,0,yymsp[-1].minor.yy132,yymsp[0].minor.yy408);
    +-  sqlite3SrcListIndexedBy(pParse, yygotominor.yy65, &yymsp[-2].minor.yy0);
    ++  yymsp[-6].minor.yy259 = sqlite3SrcListAppendFromTerm(pParse,yymsp[-6].minor.yy259,&yymsp[-5].minor.yy0,&yymsp[-4].minor.yy0,&yymsp[-3].minor.yy0,0,yymsp[-1].minor.yy314,yymsp[0].minor.yy384);
    ++  sqlite3SrcListIndexedBy(pParse, yymsp[-6].minor.yy259, &yymsp[-2].minor.yy0);
    + }
    +         break;
    +-      case 138: /* seltablist ::= stl_prefix nm dbnm LP exprlist RP as on_opt using_opt */
    ++      case 102: /* seltablist ::= stl_prefix nm dbnm LP exprlist RP as on_opt using_opt */
    + {
    +-  yygotominor.yy65 = sqlite3SrcListAppendFromTerm(pParse,yymsp[-8].minor.yy65,&yymsp[-7].minor.yy0,&yymsp[-6].minor.yy0,&yymsp[-2].minor.yy0,0,yymsp[-1].minor.yy132,yymsp[0].minor.yy408);
    +-  sqlite3SrcListFuncArgs(pParse, yygotominor.yy65, yymsp[-4].minor.yy14);
    ++  yymsp[-8].minor.yy259 = sqlite3SrcListAppendFromTerm(pParse,yymsp[-8].minor.yy259,&yymsp[-7].minor.yy0,&yymsp[-6].minor.yy0,&yymsp[-2].minor.yy0,0,yymsp[-1].minor.yy314,yymsp[0].minor.yy384);
    ++  sqlite3SrcListFuncArgs(pParse, yymsp[-8].minor.yy259, yymsp[-4].minor.yy322);
    + }
    +         break;
    +-      case 139: /* seltablist ::= stl_prefix LP select RP as on_opt using_opt */
    ++      case 103: /* seltablist ::= stl_prefix LP select RP as on_opt using_opt */
    + {
    +-    yygotominor.yy65 = sqlite3SrcListAppendFromTerm(pParse,yymsp[-6].minor.yy65,0,0,&yymsp[-2].minor.yy0,yymsp[-4].minor.yy3,yymsp[-1].minor.yy132,yymsp[0].minor.yy408);
    ++    yymsp[-6].minor.yy259 = sqlite3SrcListAppendFromTerm(pParse,yymsp[-6].minor.yy259,0,0,&yymsp[-2].minor.yy0,yymsp[-4].minor.yy387,yymsp[-1].minor.yy314,yymsp[0].minor.yy384);
    +   }
    +         break;
    +-      case 140: /* seltablist ::= stl_prefix LP seltablist RP as on_opt using_opt */
    ++      case 104: /* seltablist ::= stl_prefix LP seltablist RP as on_opt using_opt */
    + {
    +-    if( yymsp[-6].minor.yy65==0 && yymsp[-2].minor.yy0.n==0 && yymsp[-1].minor.yy132==0 && yymsp[0].minor.yy408==0 ){
    +-      yygotominor.yy65 = yymsp[-4].minor.yy65;
    +-    }else if( yymsp[-4].minor.yy65->nSrc==1 ){
    +-      yygotominor.yy65 = sqlite3SrcListAppendFromTerm(pParse,yymsp[-6].minor.yy65,0,0,&yymsp[-2].minor.yy0,0,yymsp[-1].minor.yy132,yymsp[0].minor.yy408);
    +-      if( yygotominor.yy65 ){
    +-        struct SrcList_item *pNew = &yygotominor.yy65->a[yygotominor.yy65->nSrc-1];
    +-        struct SrcList_item *pOld = yymsp[-4].minor.yy65->a;
    ++    if( yymsp[-6].minor.yy259==0 && yymsp[-2].minor.yy0.n==0 && yymsp[-1].minor.yy314==0 && yymsp[0].minor.yy384==0 ){
    ++      yymsp[-6].minor.yy259 = yymsp[-4].minor.yy259;
    ++    }else if( yymsp[-4].minor.yy259->nSrc==1 ){
    ++      yymsp[-6].minor.yy259 = sqlite3SrcListAppendFromTerm(pParse,yymsp[-6].minor.yy259,0,0,&yymsp[-2].minor.yy0,0,yymsp[-1].minor.yy314,yymsp[0].minor.yy384);
    ++      if( yymsp[-6].minor.yy259 ){
    ++        struct SrcList_item *pNew = &yymsp[-6].minor.yy259->a[yymsp[-6].minor.yy259->nSrc-1];
    ++        struct SrcList_item *pOld = yymsp[-4].minor.yy259->a;
    +         pNew->zName = pOld->zName;
    +         pNew->zDatabase = pOld->zDatabase;
    +         pNew->pSelect = pOld->pSelect;
    +         pOld->zName = pOld->zDatabase = 0;
    +         pOld->pSelect = 0;
    +       }
    +-      sqlite3SrcListDelete(pParse->db, yymsp[-4].minor.yy65);
    ++      sqlite3SrcListDelete(pParse->db, yymsp[-4].minor.yy259);
    +     }else{
    +       Select *pSubquery;
    +-      sqlite3SrcListShiftJoinType(yymsp[-4].minor.yy65);
    +-      pSubquery = sqlite3SelectNew(pParse,0,yymsp[-4].minor.yy65,0,0,0,0,SF_NestedFrom,0,0);
    +-      yygotominor.yy65 = sqlite3SrcListAppendFromTerm(pParse,yymsp[-6].minor.yy65,0,0,&yymsp[-2].minor.yy0,pSubquery,yymsp[-1].minor.yy132,yymsp[0].minor.yy408);
    ++      sqlite3SrcListShiftJoinType(yymsp[-4].minor.yy259);
    ++      pSubquery = sqlite3SelectNew(pParse,0,yymsp[-4].minor.yy259,0,0,0,0,SF_NestedFrom,0);
    ++      yymsp[-6].minor.yy259 = sqlite3SrcListAppendFromTerm(pParse,yymsp[-6].minor.yy259,0,0,&yymsp[-2].minor.yy0,pSubquery,yymsp[-1].minor.yy314,yymsp[0].minor.yy384);
    +     }
    +   }
    +         break;
    +-      case 141: /* dbnm ::= */
    +-      case 150: /* indexed_opt ::= */ yytestcase(yyruleno==150);
    +-{yygotominor.yy0.z=0; yygotominor.yy0.n=0;}
    ++      case 105: /* dbnm ::= */
    ++      case 114: /* indexed_opt ::= */ yytestcase(yyruleno==114);
    ++{yymsp[1].minor.yy0.z=0; yymsp[1].minor.yy0.n=0;}
    +         break;
    +-      case 143: /* fullname ::= nm dbnm */
    +-{yygotominor.yy65 = sqlite3SrcListAppend(pParse->db,0,&yymsp[-1].minor.yy0,&yymsp[0].minor.yy0);}
    ++      case 107: /* fullname ::= nm dbnm */
    ++{yymsp[-1].minor.yy259 = sqlite3SrcListAppend(pParse->db,0,&yymsp[-1].minor.yy0,&yymsp[0].minor.yy0); /*A-overwrites-X*/}
    +         break;
    +-      case 144: /* joinop ::= COMMA|JOIN */
    +-{ yygotominor.yy328 = JT_INNER; }
    ++      case 108: /* joinop ::= COMMA|JOIN */
    ++{ yymsp[0].minor.yy4 = JT_INNER; }
    +         break;
    +-      case 145: /* joinop ::= JOIN_KW JOIN */
    +-{ yygotominor.yy328 = sqlite3JoinType(pParse,&yymsp[-1].minor.yy0,0,0); }
    ++      case 109: /* joinop ::= JOIN_KW JOIN */
    ++{yymsp[-1].minor.yy4 = sqlite3JoinType(pParse,&yymsp[-1].minor.yy0,0,0);  /*X-overwrites-A*/}
    +         break;
    +-      case 146: /* joinop ::= JOIN_KW nm JOIN */
    +-{ yygotominor.yy328 = sqlite3JoinType(pParse,&yymsp[-2].minor.yy0,&yymsp[-1].minor.yy0,0); }
    ++      case 110: /* joinop ::= JOIN_KW nm JOIN */
    ++{yymsp[-2].minor.yy4 = sqlite3JoinType(pParse,&yymsp[-2].minor.yy0,&yymsp[-1].minor.yy0,0); /*X-overwrites-A*/}
    +         break;
    +-      case 147: /* joinop ::= JOIN_KW nm nm JOIN */
    +-{ yygotominor.yy328 = sqlite3JoinType(pParse,&yymsp[-3].minor.yy0,&yymsp[-2].minor.yy0,&yymsp[-1].minor.yy0); }
    ++      case 111: /* joinop ::= JOIN_KW nm nm JOIN */
    ++{yymsp[-3].minor.yy4 = sqlite3JoinType(pParse,&yymsp[-3].minor.yy0,&yymsp[-2].minor.yy0,&yymsp[-1].minor.yy0);/*X-overwrites-A*/}
    +         break;
    +-      case 148: /* on_opt ::= ON expr */
    +-      case 165: /* having_opt ::= HAVING expr */ yytestcase(yyruleno==165);
    +-      case 172: /* where_opt ::= WHERE expr */ yytestcase(yyruleno==172);
    +-      case 232: /* case_else ::= ELSE expr */ yytestcase(yyruleno==232);
    +-      case 234: /* case_operand ::= expr */ yytestcase(yyruleno==234);
    +-{yygotominor.yy132 = yymsp[0].minor.yy346.pExpr;}
    ++      case 112: /* on_opt ::= ON expr */
    ++      case 129: /* having_opt ::= HAVING expr */ yytestcase(yyruleno==129);
    ++      case 136: /* where_opt ::= WHERE expr */ yytestcase(yyruleno==136);
    ++      case 197: /* case_else ::= ELSE expr */ yytestcase(yyruleno==197);
    ++{yymsp[-1].minor.yy314 = yymsp[0].minor.yy314;}
    +         break;
    +-      case 149: /* on_opt ::= */
    +-      case 164: /* having_opt ::= */ yytestcase(yyruleno==164);
    +-      case 171: /* where_opt ::= */ yytestcase(yyruleno==171);
    +-      case 233: /* case_else ::= */ yytestcase(yyruleno==233);
    +-      case 235: /* case_operand ::= */ yytestcase(yyruleno==235);
    +-{yygotominor.yy132 = 0;}
    ++      case 113: /* on_opt ::= */
    ++      case 128: /* having_opt ::= */ yytestcase(yyruleno==128);
    ++      case 130: /* limit_opt ::= */ yytestcase(yyruleno==130);
    ++      case 135: /* where_opt ::= */ yytestcase(yyruleno==135);
    ++      case 198: /* case_else ::= */ yytestcase(yyruleno==198);
    ++      case 200: /* case_operand ::= */ yytestcase(yyruleno==200);
    ++{yymsp[1].minor.yy314 = 0;}
    +         break;
    +-      case 152: /* indexed_opt ::= NOT INDEXED */
    +-{yygotominor.yy0.z=0; yygotominor.yy0.n=1;}
    ++      case 115: /* indexed_opt ::= INDEXED BY nm */
    ++{yymsp[-2].minor.yy0 = yymsp[0].minor.yy0;}
    +         break;
    +-      case 153: /* using_opt ::= USING LP idlist RP */
    +-      case 181: /* idlist_opt ::= LP idlist RP */ yytestcase(yyruleno==181);
    +-{yygotominor.yy408 = yymsp[-1].minor.yy408;}
    ++      case 116: /* indexed_opt ::= NOT INDEXED */
    ++{yymsp[-1].minor.yy0.z=0; yymsp[-1].minor.yy0.n=1;}
    +         break;
    +-      case 154: /* using_opt ::= */
    +-      case 180: /* idlist_opt ::= */ yytestcase(yyruleno==180);
    +-{yygotominor.yy408 = 0;}
    ++      case 117: /* using_opt ::= USING LP idlist RP */
    ++{yymsp[-3].minor.yy384 = yymsp[-1].minor.yy384;}
    +         break;
    +-      case 156: /* orderby_opt ::= ORDER BY sortlist */
    +-      case 163: /* groupby_opt ::= GROUP BY nexprlist */ yytestcase(yyruleno==163);
    +-      case 236: /* exprlist ::= nexprlist */ yytestcase(yyruleno==236);
    +-{yygotominor.yy14 = yymsp[0].minor.yy14;}
    ++      case 118: /* using_opt ::= */
    ++      case 146: /* idlist_opt ::= */ yytestcase(yyruleno==146);
    ++{yymsp[1].minor.yy384 = 0;}
    +         break;
    +-      case 157: /* sortlist ::= sortlist COMMA expr sortorder */
    ++      case 120: /* orderby_opt ::= ORDER BY sortlist */
    ++      case 127: /* groupby_opt ::= GROUP BY nexprlist */ yytestcase(yyruleno==127);
    ++{yymsp[-2].minor.yy322 = yymsp[0].minor.yy322;}
    ++        break;
    ++      case 121: /* sortlist ::= sortlist COMMA expr sortorder */
    + {
    +-  yygotominor.yy14 = sqlite3ExprListAppend(pParse,yymsp[-3].minor.yy14,yymsp[-1].minor.yy346.pExpr);
    +-  sqlite3ExprListSetSortOrder(yygotominor.yy14,yymsp[0].minor.yy328);
    ++  yymsp[-3].minor.yy322 = sqlite3ExprListAppend(pParse,yymsp[-3].minor.yy322,yymsp[-1].minor.yy314);
    ++  sqlite3ExprListSetSortOrder(yymsp[-3].minor.yy322,yymsp[0].minor.yy4);
    + }
    +         break;
    +-      case 158: /* sortlist ::= expr sortorder */
    ++      case 122: /* sortlist ::= expr sortorder */
    + {
    +-  yygotominor.yy14 = sqlite3ExprListAppend(pParse,0,yymsp[-1].minor.yy346.pExpr);
    +-  sqlite3ExprListSetSortOrder(yygotominor.yy14,yymsp[0].minor.yy328);
    ++  yymsp[-1].minor.yy322 = sqlite3ExprListAppend(pParse,0,yymsp[-1].minor.yy314); /*A-overwrites-Y*/
    ++  sqlite3ExprListSetSortOrder(yymsp[-1].minor.yy322,yymsp[0].minor.yy4);
    + }
    +         break;
    +-      case 159: /* sortorder ::= ASC */
    +-{yygotominor.yy328 = SQLITE_SO_ASC;}
    +-        break;
    +-      case 160: /* sortorder ::= DESC */
    +-{yygotominor.yy328 = SQLITE_SO_DESC;}
    ++      case 123: /* sortorder ::= ASC */
    ++{yymsp[0].minor.yy4 = SQLITE_SO_ASC;}
    +         break;
    +-      case 161: /* sortorder ::= */
    +-{yygotominor.yy328 = SQLITE_SO_UNDEFINED;}
    ++      case 124: /* sortorder ::= DESC */
    ++{yymsp[0].minor.yy4 = SQLITE_SO_DESC;}
    +         break;
    +-      case 166: /* limit_opt ::= */
    +-{yygotominor.yy476.pLimit = 0; yygotominor.yy476.pOffset = 0;}
    ++      case 125: /* sortorder ::= */
    ++{yymsp[1].minor.yy4 = SQLITE_SO_UNDEFINED;}
    +         break;
    +-      case 167: /* limit_opt ::= LIMIT expr */
    +-{yygotominor.yy476.pLimit = yymsp[0].minor.yy346.pExpr; yygotominor.yy476.pOffset = 0;}
    ++      case 131: /* limit_opt ::= LIMIT expr */
    ++{yymsp[-1].minor.yy314 = sqlite3PExpr(pParse,TK_LIMIT,yymsp[0].minor.yy314,0);}
    +         break;
    +-      case 168: /* limit_opt ::= LIMIT expr OFFSET expr */
    +-{yygotominor.yy476.pLimit = yymsp[-2].minor.yy346.pExpr; yygotominor.yy476.pOffset = yymsp[0].minor.yy346.pExpr;}
    ++      case 132: /* limit_opt ::= LIMIT expr OFFSET expr */
    ++{yymsp[-3].minor.yy314 = sqlite3PExpr(pParse,TK_LIMIT,yymsp[-2].minor.yy314,yymsp[0].minor.yy314);}
    +         break;
    +-      case 169: /* limit_opt ::= LIMIT expr COMMA expr */
    +-{yygotominor.yy476.pOffset = yymsp[-2].minor.yy346.pExpr; yygotominor.yy476.pLimit = yymsp[0].minor.yy346.pExpr;}
    ++      case 133: /* limit_opt ::= LIMIT expr COMMA expr */
    ++{yymsp[-3].minor.yy314 = sqlite3PExpr(pParse,TK_LIMIT,yymsp[0].minor.yy314,yymsp[-2].minor.yy314);}
    +         break;
    +-      case 170: /* cmd ::= with DELETE FROM fullname indexed_opt where_opt */
    ++      case 134: /* cmd ::= with DELETE FROM fullname indexed_opt where_opt */
    + {
    +-  sqlite3WithPush(pParse, yymsp[-5].minor.yy59, 1);
    +-  sqlite3SrcListIndexedBy(pParse, yymsp[-2].minor.yy65, &yymsp[-1].minor.yy0);
    +-  sqlite3DeleteFrom(pParse,yymsp[-2].minor.yy65,yymsp[0].minor.yy132);
    ++  sqlite3WithPush(pParse, yymsp[-5].minor.yy451, 1);
    ++  sqlite3SrcListIndexedBy(pParse, yymsp[-2].minor.yy259, &yymsp[-1].minor.yy0);
    ++  sqlite3DeleteFrom(pParse,yymsp[-2].minor.yy259,yymsp[0].minor.yy314,0,0);
    + }
    +         break;
    +-      case 173: /* cmd ::= with UPDATE orconf fullname indexed_opt SET setlist where_opt */
    ++      case 137: /* cmd ::= with UPDATE orconf fullname indexed_opt SET setlist where_opt */
    + {
    +-  sqlite3WithPush(pParse, yymsp[-7].minor.yy59, 1);
    +-  sqlite3SrcListIndexedBy(pParse, yymsp[-4].minor.yy65, &yymsp[-3].minor.yy0);
    +-  sqlite3ExprListCheckLength(pParse,yymsp[-1].minor.yy14,"set list"); 
    +-  sqlite3Update(pParse,yymsp[-4].minor.yy65,yymsp[-1].minor.yy14,yymsp[0].minor.yy132,yymsp[-5].minor.yy186);
    ++  sqlite3WithPush(pParse, yymsp[-7].minor.yy451, 1);
    ++  sqlite3SrcListIndexedBy(pParse, yymsp[-4].minor.yy259, &yymsp[-3].minor.yy0);
    ++  sqlite3ExprListCheckLength(pParse,yymsp[-1].minor.yy322,"set list"); 
    ++  sqlite3Update(pParse,yymsp[-4].minor.yy259,yymsp[-1].minor.yy322,yymsp[0].minor.yy314,yymsp[-5].minor.yy4,0,0);
    + }
    +         break;
    +-      case 174: /* setlist ::= setlist COMMA nm EQ expr */
    ++      case 138: /* setlist ::= setlist COMMA nm EQ expr */
    + {
    +-  yygotominor.yy14 = sqlite3ExprListAppend(pParse, yymsp[-4].minor.yy14, yymsp[0].minor.yy346.pExpr);
    +-  sqlite3ExprListSetName(pParse, yygotominor.yy14, &yymsp[-2].minor.yy0, 1);
    ++  yymsp[-4].minor.yy322 = sqlite3ExprListAppend(pParse, yymsp[-4].minor.yy322, yymsp[0].minor.yy314);
    ++  sqlite3ExprListSetName(pParse, yymsp[-4].minor.yy322, &yymsp[-2].minor.yy0, 1);
    + }
    +         break;
    +-      case 175: /* setlist ::= nm EQ expr */
    ++      case 139: /* setlist ::= setlist COMMA LP idlist RP EQ expr */
    + {
    +-  yygotominor.yy14 = sqlite3ExprListAppend(pParse, 0, yymsp[0].minor.yy346.pExpr);
    +-  sqlite3ExprListSetName(pParse, yygotominor.yy14, &yymsp[-2].minor.yy0, 1);
    ++  yymsp[-6].minor.yy322 = sqlite3ExprListAppendVector(pParse, yymsp[-6].minor.yy322, yymsp[-3].minor.yy384, yymsp[0].minor.yy314);
    + }
    +         break;
    +-      case 176: /* cmd ::= with insert_cmd INTO fullname idlist_opt select */
    ++      case 140: /* setlist ::= nm EQ expr */
    + {
    +-  sqlite3WithPush(pParse, yymsp[-5].minor.yy59, 1);
    +-  sqlite3Insert(pParse, yymsp[-2].minor.yy65, yymsp[0].minor.yy3, yymsp[-1].minor.yy408, yymsp[-4].minor.yy186);
    ++  yylhsminor.yy322 = sqlite3ExprListAppend(pParse, 0, yymsp[0].minor.yy314);
    ++  sqlite3ExprListSetName(pParse, yylhsminor.yy322, &yymsp[-2].minor.yy0, 1);
    + }
    ++  yymsp[-2].minor.yy322 = yylhsminor.yy322;
    +         break;
    +-      case 177: /* cmd ::= with insert_cmd INTO fullname idlist_opt DEFAULT VALUES */
    ++      case 141: /* setlist ::= LP idlist RP EQ expr */
    + {
    +-  sqlite3WithPush(pParse, yymsp[-6].minor.yy59, 1);
    +-  sqlite3Insert(pParse, yymsp[-3].minor.yy65, 0, yymsp[-2].minor.yy408, yymsp[-5].minor.yy186);
    ++  yymsp[-4].minor.yy322 = sqlite3ExprListAppendVector(pParse, 0, yymsp[-3].minor.yy384, yymsp[0].minor.yy314);
    + }
    +         break;
    +-      case 178: /* insert_cmd ::= INSERT orconf */
    +-{yygotominor.yy186 = yymsp[0].minor.yy186;}
    ++      case 142: /* cmd ::= with insert_cmd INTO fullname idlist_opt select */
    ++{
    ++  sqlite3WithPush(pParse, yymsp[-5].minor.yy451, 1);
    ++  sqlite3Insert(pParse, yymsp[-2].minor.yy259, yymsp[0].minor.yy387, yymsp[-1].minor.yy384, yymsp[-4].minor.yy4);
    ++}
    +         break;
    +-      case 179: /* insert_cmd ::= REPLACE */
    +-{yygotominor.yy186 = OE_Replace;}
    ++      case 143: /* cmd ::= with insert_cmd INTO fullname idlist_opt DEFAULT VALUES */
    ++{
    ++  sqlite3WithPush(pParse, yymsp[-6].minor.yy451, 1);
    ++  sqlite3Insert(pParse, yymsp[-3].minor.yy259, 0, yymsp[-2].minor.yy384, yymsp[-5].minor.yy4);
    ++}
    +         break;
    +-      case 182: /* idlist ::= idlist COMMA nm */
    +-{yygotominor.yy408 = sqlite3IdListAppend(pParse->db,yymsp[-2].minor.yy408,&yymsp[0].minor.yy0);}
    ++      case 147: /* idlist_opt ::= LP idlist RP */
    ++{yymsp[-2].minor.yy384 = yymsp[-1].minor.yy384;}
    +         break;
    +-      case 183: /* idlist ::= nm */
    +-{yygotominor.yy408 = sqlite3IdListAppend(pParse->db,0,&yymsp[0].minor.yy0);}
    ++      case 148: /* idlist ::= idlist COMMA nm */
    ++{yymsp[-2].minor.yy384 = sqlite3IdListAppend(pParse->db,yymsp[-2].minor.yy384,&yymsp[0].minor.yy0);}
    +         break;
    +-      case 184: /* expr ::= term */
    +-{yygotominor.yy346 = yymsp[0].minor.yy346;}
    ++      case 149: /* idlist ::= nm */
    ++{yymsp[0].minor.yy384 = sqlite3IdListAppend(pParse->db,0,&yymsp[0].minor.yy0); /*A-overwrites-Y*/}
    +         break;
    +-      case 185: /* expr ::= LP expr RP */
    +-{yygotominor.yy346.pExpr = yymsp[-1].minor.yy346.pExpr; spanSet(&yygotominor.yy346,&yymsp[-2].minor.yy0,&yymsp[0].minor.yy0);}
    ++      case 150: /* expr ::= LP expr RP */
    ++{yymsp[-2].minor.yy314 = yymsp[-1].minor.yy314;}
    +         break;
    +-      case 186: /* term ::= NULL */
    +-      case 191: /* term ::= INTEGER|FLOAT|BLOB */ yytestcase(yyruleno==191);
    +-      case 192: /* term ::= STRING */ yytestcase(yyruleno==192);
    +-{spanExpr(&yygotominor.yy346, pParse, yymsp[0].major, &yymsp[0].minor.yy0);}
    ++      case 151: /* expr ::= ID|INDEXED */
    ++      case 152: /* expr ::= JOIN_KW */ yytestcase(yyruleno==152);
    ++{yymsp[0].minor.yy314=tokenExpr(pParse,TK_ID,yymsp[0].minor.yy0); /*A-overwrites-X*/}
    +         break;
    +-      case 187: /* expr ::= ID|INDEXED */
    +-      case 188: /* expr ::= JOIN_KW */ yytestcase(yyruleno==188);
    +-{spanExpr(&yygotominor.yy346, pParse, TK_ID, &yymsp[0].minor.yy0);}
    ++      case 153: /* expr ::= nm DOT nm */
    ++{
    ++  Expr *temp1 = sqlite3ExprAlloc(pParse->db, TK_ID, &yymsp[-2].minor.yy0, 1);
    ++  Expr *temp2 = sqlite3ExprAlloc(pParse->db, TK_ID, &yymsp[0].minor.yy0, 1);
    ++  yylhsminor.yy314 = sqlite3PExpr(pParse, TK_DOT, temp1, temp2);
    ++}
    ++  yymsp[-2].minor.yy314 = yylhsminor.yy314;
    +         break;
    +-      case 189: /* expr ::= nm DOT nm */
    ++      case 154: /* expr ::= nm DOT nm DOT nm */
    + {
    +-  Expr *temp1 = sqlite3PExpr(pParse, TK_ID, 0, 0, &yymsp[-2].minor.yy0);
    +-  Expr *temp2 = sqlite3PExpr(pParse, TK_ID, 0, 0, &yymsp[0].minor.yy0);
    +-  yygotominor.yy346.pExpr = sqlite3PExpr(pParse, TK_DOT, temp1, temp2, 0);
    +-  spanSet(&yygotominor.yy346,&yymsp[-2].minor.yy0,&yymsp[0].minor.yy0);
    ++  Expr *temp1 = sqlite3ExprAlloc(pParse->db, TK_ID, &yymsp[-4].minor.yy0, 1);
    ++  Expr *temp2 = sqlite3ExprAlloc(pParse->db, TK_ID, &yymsp[-2].minor.yy0, 1);
    ++  Expr *temp3 = sqlite3ExprAlloc(pParse->db, TK_ID, &yymsp[0].minor.yy0, 1);
    ++  Expr *temp4 = sqlite3PExpr(pParse, TK_DOT, temp2, temp3);
    ++  yylhsminor.yy314 = sqlite3PExpr(pParse, TK_DOT, temp1, temp4);
    + }
    ++  yymsp[-4].minor.yy314 = yylhsminor.yy314;
    ++        break;
    ++      case 155: /* term ::= NULL|FLOAT|BLOB */
    ++      case 156: /* term ::= STRING */ yytestcase(yyruleno==156);
    ++{yymsp[0].minor.yy314=tokenExpr(pParse,yymsp[0].major,yymsp[0].minor.yy0); /*A-overwrites-X*/}
    +         break;
    +-      case 190: /* expr ::= nm DOT nm DOT nm */
    ++      case 157: /* term ::= INTEGER */
    + {
    +-  Expr *temp1 = sqlite3PExpr(pParse, TK_ID, 0, 0, &yymsp[-4].minor.yy0);
    +-  Expr *temp2 = sqlite3PExpr(pParse, TK_ID, 0, 0, &yymsp[-2].minor.yy0);
    +-  Expr *temp3 = sqlite3PExpr(pParse, TK_ID, 0, 0, &yymsp[0].minor.yy0);
    +-  Expr *temp4 = sqlite3PExpr(pParse, TK_DOT, temp2, temp3, 0);
    +-  yygotominor.yy346.pExpr = sqlite3PExpr(pParse, TK_DOT, temp1, temp4, 0);
    +-  spanSet(&yygotominor.yy346,&yymsp[-4].minor.yy0,&yymsp[0].minor.yy0);
    ++  yylhsminor.yy314 = sqlite3ExprAlloc(pParse->db, TK_INTEGER, &yymsp[0].minor.yy0, 1);
    + }
    ++  yymsp[0].minor.yy314 = yylhsminor.yy314;
    +         break;
    +-      case 193: /* expr ::= VARIABLE */
    ++      case 158: /* expr ::= VARIABLE */
    + {
    +-  if( yymsp[0].minor.yy0.n>=2 && yymsp[0].minor.yy0.z[0]=='#' && sqlite3Isdigit(yymsp[0].minor.yy0.z[1]) ){
    ++  if( !(yymsp[0].minor.yy0.z[0]=='#' && sqlite3Isdigit(yymsp[0].minor.yy0.z[1])) ){
    ++    u32 n = yymsp[0].minor.yy0.n;
    ++    yymsp[0].minor.yy314 = tokenExpr(pParse, TK_VARIABLE, yymsp[0].minor.yy0);
    ++    sqlite3ExprAssignVarNumber(pParse, yymsp[0].minor.yy314, n);
    ++  }else{
    +     /* When doing a nested parse, one can include terms in an expression
    +     ** that look like this:   #1 #2 ...  These terms refer to registers
    +     ** in the virtual machine.  #N is the N-th register. */
    ++    Token t = yymsp[0].minor.yy0; /*A-overwrites-X*/
    ++    assert( t.n>=2 );
    +     if( pParse->nested==0 ){
    +-      sqlite3ErrorMsg(pParse, "near \"%T\": syntax error", &yymsp[0].minor.yy0);
    +-      yygotominor.yy346.pExpr = 0;
    ++      sqlite3ErrorMsg(pParse, "near \"%T\": syntax error", &t);
    ++      yymsp[0].minor.yy314 = 0;
    +     }else{
    +-      yygotominor.yy346.pExpr = sqlite3PExpr(pParse, TK_REGISTER, 0, 0, &yymsp[0].minor.yy0);
    +-      if( yygotominor.yy346.pExpr ) sqlite3GetInt32(&yymsp[0].minor.yy0.z[1], &yygotominor.yy346.pExpr->iTable);
    ++      yymsp[0].minor.yy314 = sqlite3PExpr(pParse, TK_REGISTER, 0, 0);
    ++      if( yymsp[0].minor.yy314 ) sqlite3GetInt32(&t.z[1], &yymsp[0].minor.yy314->iTable);
    +     }
    +-  }else{
    +-    spanExpr(&yygotominor.yy346, pParse, TK_VARIABLE, &yymsp[0].minor.yy0);
    +-    sqlite3ExprAssignVarNumber(pParse, yygotominor.yy346.pExpr);
    +   }
    +-  spanSet(&yygotominor.yy346, &yymsp[0].minor.yy0, &yymsp[0].minor.yy0);
    + }
    +         break;
    +-      case 194: /* expr ::= expr COLLATE ID|STRING */
    ++      case 159: /* expr ::= expr COLLATE ID|STRING */
    + {
    +-  yygotominor.yy346.pExpr = sqlite3ExprAddCollateToken(pParse, yymsp[-2].minor.yy346.pExpr, &yymsp[0].minor.yy0, 1);
    +-  yygotominor.yy346.zStart = yymsp[-2].minor.yy346.zStart;
    +-  yygotominor.yy346.zEnd = &yymsp[0].minor.yy0.z[yymsp[0].minor.yy0.n];
    ++  yymsp[-2].minor.yy314 = sqlite3ExprAddCollateToken(pParse, yymsp[-2].minor.yy314, &yymsp[0].minor.yy0, 1);
    + }
    +         break;
    +-      case 195: /* expr ::= CAST LP expr AS typetoken RP */
    ++      case 160: /* expr ::= CAST LP expr AS typetoken RP */
    + {
    +-  yygotominor.yy346.pExpr = sqlite3PExpr(pParse, TK_CAST, yymsp[-3].minor.yy346.pExpr, 0, &yymsp[-1].minor.yy0);
    +-  spanSet(&yygotominor.yy346,&yymsp[-5].minor.yy0,&yymsp[0].minor.yy0);
    ++  yymsp[-5].minor.yy314 = sqlite3ExprAlloc(pParse->db, TK_CAST, &yymsp[-1].minor.yy0, 1);
    ++  sqlite3ExprAttachSubtrees(pParse->db, yymsp[-5].minor.yy314, yymsp[-3].minor.yy314, 0);
    + }
    +         break;
    +-      case 196: /* expr ::= ID|INDEXED LP distinct exprlist RP */
    ++      case 161: /* expr ::= ID|INDEXED LP distinct exprlist RP */
    + {
    +-  if( yymsp[-1].minor.yy14 && yymsp[-1].minor.yy14->nExpr>pParse->db->aLimit[SQLITE_LIMIT_FUNCTION_ARG] ){
    ++  if( yymsp[-1].minor.yy322 && yymsp[-1].minor.yy322->nExpr>pParse->db->aLimit[SQLITE_LIMIT_FUNCTION_ARG] ){
    +     sqlite3ErrorMsg(pParse, "too many arguments on function %T", &yymsp[-4].minor.yy0);
    +   }
    +-  yygotominor.yy346.pExpr = sqlite3ExprFunction(pParse, yymsp[-1].minor.yy14, &yymsp[-4].minor.yy0);
    +-  spanSet(&yygotominor.yy346,&yymsp[-4].minor.yy0,&yymsp[0].minor.yy0);
    +-  if( yymsp[-2].minor.yy381==SF_Distinct && yygotominor.yy346.pExpr ){
    +-    yygotominor.yy346.pExpr->flags |= EP_Distinct;
    ++  yylhsminor.yy314 = sqlite3ExprFunction(pParse, yymsp[-1].minor.yy322, &yymsp[-4].minor.yy0);
    ++  if( yymsp[-2].minor.yy4==SF_Distinct && yylhsminor.yy314 ){
    ++    yylhsminor.yy314->flags |= EP_Distinct;
    +   }
    + }
    ++  yymsp[-4].minor.yy314 = yylhsminor.yy314;
    +         break;
    +-      case 197: /* expr ::= ID|INDEXED LP STAR RP */
    ++      case 162: /* expr ::= ID|INDEXED LP STAR RP */
    + {
    +-  yygotominor.yy346.pExpr = sqlite3ExprFunction(pParse, 0, &yymsp[-3].minor.yy0);
    +-  spanSet(&yygotominor.yy346,&yymsp[-3].minor.yy0,&yymsp[0].minor.yy0);
    ++  yylhsminor.yy314 = sqlite3ExprFunction(pParse, 0, &yymsp[-3].minor.yy0);
    + }
    ++  yymsp[-3].minor.yy314 = yylhsminor.yy314;
    +         break;
    +-      case 198: /* term ::= CTIME_KW */
    ++      case 163: /* term ::= CTIME_KW */
    + {
    +-  yygotominor.yy346.pExpr = sqlite3ExprFunction(pParse, 0, &yymsp[0].minor.yy0);
    +-  spanSet(&yygotominor.yy346, &yymsp[0].minor.yy0, &yymsp[0].minor.yy0);
    ++  yylhsminor.yy314 = sqlite3ExprFunction(pParse, 0, &yymsp[0].minor.yy0);
    + }
    ++  yymsp[0].minor.yy314 = yylhsminor.yy314;
    +         break;
    +-      case 199: /* expr ::= expr AND expr */
    +-      case 200: /* expr ::= expr OR expr */ yytestcase(yyruleno==200);
    +-      case 201: /* expr ::= expr LT|GT|GE|LE expr */ yytestcase(yyruleno==201);
    +-      case 202: /* expr ::= expr EQ|NE expr */ yytestcase(yyruleno==202);
    +-      case 203: /* expr ::= expr BITAND|BITOR|LSHIFT|RSHIFT expr */ yytestcase(yyruleno==203);
    +-      case 204: /* expr ::= expr PLUS|MINUS expr */ yytestcase(yyruleno==204);
    +-      case 205: /* expr ::= expr STAR|SLASH|REM expr */ yytestcase(yyruleno==205);
    +-      case 206: /* expr ::= expr CONCAT expr */ yytestcase(yyruleno==206);
    +-{spanBinaryExpr(&yygotominor.yy346,pParse,yymsp[-1].major,&yymsp[-2].minor.yy346,&yymsp[0].minor.yy346);}
    ++      case 164: /* expr ::= LP nexprlist COMMA expr RP */
    ++{
    ++  ExprList *pList = sqlite3ExprListAppend(pParse, yymsp[-3].minor.yy322, yymsp[-1].minor.yy314);
    ++  yymsp[-4].minor.yy314 = sqlite3PExpr(pParse, TK_VECTOR, 0, 0);
    ++  if( yymsp[-4].minor.yy314 ){
    ++    yymsp[-4].minor.yy314->x.pList = pList;
    ++  }else{
    ++    sqlite3ExprListDelete(pParse->db, pList);
    ++  }
    ++}
    +         break;
    +-      case 207: /* likeop ::= LIKE_KW|MATCH */
    +-{yygotominor.yy96.eOperator = yymsp[0].minor.yy0; yygotominor.yy96.bNot = 0;}
    ++      case 165: /* expr ::= expr AND expr */
    ++      case 166: /* expr ::= expr OR expr */ yytestcase(yyruleno==166);
    ++      case 167: /* expr ::= expr LT|GT|GE|LE expr */ yytestcase(yyruleno==167);
    ++      case 168: /* expr ::= expr EQ|NE expr */ yytestcase(yyruleno==168);
    ++      case 169: /* expr ::= expr BITAND|BITOR|LSHIFT|RSHIFT expr */ yytestcase(yyruleno==169);
    ++      case 170: /* expr ::= expr PLUS|MINUS expr */ yytestcase(yyruleno==170);
    ++      case 171: /* expr ::= expr STAR|SLASH|REM expr */ yytestcase(yyruleno==171);
    ++      case 172: /* expr ::= expr CONCAT expr */ yytestcase(yyruleno==172);
    ++{yymsp[-2].minor.yy314=sqlite3PExpr(pParse,yymsp[-1].major,yymsp[-2].minor.yy314,yymsp[0].minor.yy314);}
    +         break;
    +-      case 208: /* likeop ::= NOT LIKE_KW|MATCH */
    +-{yygotominor.yy96.eOperator = yymsp[0].minor.yy0; yygotominor.yy96.bNot = 1;}
    ++      case 173: /* likeop ::= NOT LIKE_KW|MATCH */
    ++{yymsp[-1].minor.yy0=yymsp[0].minor.yy0; yymsp[-1].minor.yy0.n|=0x80000000; /*yymsp[-1].minor.yy0-overwrite-yymsp[0].minor.yy0*/}
    +         break;
    +-      case 209: /* expr ::= expr likeop expr */
    ++      case 174: /* expr ::= expr likeop expr */
    + {
    +   ExprList *pList;
    +-  pList = sqlite3ExprListAppend(pParse,0, yymsp[0].minor.yy346.pExpr);
    +-  pList = sqlite3ExprListAppend(pParse,pList, yymsp[-2].minor.yy346.pExpr);
    +-  yygotominor.yy346.pExpr = sqlite3ExprFunction(pParse, pList, &yymsp[-1].minor.yy96.eOperator);
    +-  if( yymsp[-1].minor.yy96.bNot ) yygotominor.yy346.pExpr = sqlite3PExpr(pParse, TK_NOT, yygotominor.yy346.pExpr, 0, 0);
    +-  yygotominor.yy346.zStart = yymsp[-2].minor.yy346.zStart;
    +-  yygotominor.yy346.zEnd = yymsp[0].minor.yy346.zEnd;
    +-  if( yygotominor.yy346.pExpr ) yygotominor.yy346.pExpr->flags |= EP_InfixFunc;
    ++  int bNot = yymsp[-1].minor.yy0.n & 0x80000000;
    ++  yymsp[-1].minor.yy0.n &= 0x7fffffff;
    ++  pList = sqlite3ExprListAppend(pParse,0, yymsp[0].minor.yy314);
    ++  pList = sqlite3ExprListAppend(pParse,pList, yymsp[-2].minor.yy314);
    ++  yymsp[-2].minor.yy314 = sqlite3ExprFunction(pParse, pList, &yymsp[-1].minor.yy0);
    ++  if( bNot ) yymsp[-2].minor.yy314 = sqlite3PExpr(pParse, TK_NOT, yymsp[-2].minor.yy314, 0);
    ++  if( yymsp[-2].minor.yy314 ) yymsp[-2].minor.yy314->flags |= EP_InfixFunc;
    + }
    +         break;
    +-      case 210: /* expr ::= expr likeop expr ESCAPE expr */
    ++      case 175: /* expr ::= expr likeop expr ESCAPE expr */
    + {
    +   ExprList *pList;
    +-  pList = sqlite3ExprListAppend(pParse,0, yymsp[-2].minor.yy346.pExpr);
    +-  pList = sqlite3ExprListAppend(pParse,pList, yymsp[-4].minor.yy346.pExpr);
    +-  pList = sqlite3ExprListAppend(pParse,pList, yymsp[0].minor.yy346.pExpr);
    +-  yygotominor.yy346.pExpr = sqlite3ExprFunction(pParse, pList, &yymsp[-3].minor.yy96.eOperator);
    +-  if( yymsp[-3].minor.yy96.bNot ) yygotominor.yy346.pExpr = sqlite3PExpr(pParse, TK_NOT, yygotominor.yy346.pExpr, 0, 0);
    +-  yygotominor.yy346.zStart = yymsp[-4].minor.yy346.zStart;
    +-  yygotominor.yy346.zEnd = yymsp[0].minor.yy346.zEnd;
    +-  if( yygotominor.yy346.pExpr ) yygotominor.yy346.pExpr->flags |= EP_InfixFunc;
    ++  int bNot = yymsp[-3].minor.yy0.n & 0x80000000;
    ++  yymsp[-3].minor.yy0.n &= 0x7fffffff;
    ++  pList = sqlite3ExprListAppend(pParse,0, yymsp[-2].minor.yy314);
    ++  pList = sqlite3ExprListAppend(pParse,pList, yymsp[-4].minor.yy314);
    ++  pList = sqlite3ExprListAppend(pParse,pList, yymsp[0].minor.yy314);
    ++  yymsp[-4].minor.yy314 = sqlite3ExprFunction(pParse, pList, &yymsp[-3].minor.yy0);
    ++  if( bNot ) yymsp[-4].minor.yy314 = sqlite3PExpr(pParse, TK_NOT, yymsp[-4].minor.yy314, 0);
    ++  if( yymsp[-4].minor.yy314 ) yymsp[-4].minor.yy314->flags |= EP_InfixFunc;
    + }
    +         break;
    +-      case 211: /* expr ::= expr ISNULL|NOTNULL */
    +-{spanUnaryPostfix(&yygotominor.yy346,pParse,yymsp[0].major,&yymsp[-1].minor.yy346,&yymsp[0].minor.yy0);}
    ++      case 176: /* expr ::= expr ISNULL|NOTNULL */
    ++{yymsp[-1].minor.yy314 = sqlite3PExpr(pParse,yymsp[0].major,yymsp[-1].minor.yy314,0);}
    +         break;
    +-      case 212: /* expr ::= expr NOT NULL */
    +-{spanUnaryPostfix(&yygotominor.yy346,pParse,TK_NOTNULL,&yymsp[-2].minor.yy346,&yymsp[0].minor.yy0);}
    ++      case 177: /* expr ::= expr NOT NULL */
    ++{yymsp[-2].minor.yy314 = sqlite3PExpr(pParse,TK_NOTNULL,yymsp[-2].minor.yy314,0);}
    +         break;
    +-      case 213: /* expr ::= expr IS expr */
    ++      case 178: /* expr ::= expr IS expr */
    + {
    +-  spanBinaryExpr(&yygotominor.yy346,pParse,TK_IS,&yymsp[-2].minor.yy346,&yymsp[0].minor.yy346);
    +-  binaryToUnaryIfNull(pParse, yymsp[0].minor.yy346.pExpr, yygotominor.yy346.pExpr, TK_ISNULL);
    ++  yymsp[-2].minor.yy314 = sqlite3PExpr(pParse,TK_IS,yymsp[-2].minor.yy314,yymsp[0].minor.yy314);
    ++  binaryToUnaryIfNull(pParse, yymsp[0].minor.yy314, yymsp[-2].minor.yy314, TK_ISNULL);
    + }
    +         break;
    +-      case 214: /* expr ::= expr IS NOT expr */
    ++      case 179: /* expr ::= expr IS NOT expr */
    + {
    +-  spanBinaryExpr(&yygotominor.yy346,pParse,TK_ISNOT,&yymsp[-3].minor.yy346,&yymsp[0].minor.yy346);
    +-  binaryToUnaryIfNull(pParse, yymsp[0].minor.yy346.pExpr, yygotominor.yy346.pExpr, TK_NOTNULL);
    ++  yymsp[-3].minor.yy314 = sqlite3PExpr(pParse,TK_ISNOT,yymsp[-3].minor.yy314,yymsp[0].minor.yy314);
    ++  binaryToUnaryIfNull(pParse, yymsp[0].minor.yy314, yymsp[-3].minor.yy314, TK_NOTNULL);
    + }
    +         break;
    +-      case 215: /* expr ::= NOT expr */
    +-      case 216: /* expr ::= BITNOT expr */ yytestcase(yyruleno==216);
    +-{spanUnaryPrefix(&yygotominor.yy346,pParse,yymsp[-1].major,&yymsp[0].minor.yy346,&yymsp[-1].minor.yy0);}
    ++      case 180: /* expr ::= NOT expr */
    ++      case 181: /* expr ::= BITNOT expr */ yytestcase(yyruleno==181);
    ++{yymsp[-1].minor.yy314 = sqlite3PExpr(pParse, yymsp[-1].major, yymsp[0].minor.yy314, 0);/*A-overwrites-B*/}
    ++        break;
    ++      case 182: /* expr ::= MINUS expr */
    ++{yymsp[-1].minor.yy314 = sqlite3PExpr(pParse, TK_UMINUS, yymsp[0].minor.yy314, 0);}
    +         break;
    +-      case 217: /* expr ::= MINUS expr */
    +-{spanUnaryPrefix(&yygotominor.yy346,pParse,TK_UMINUS,&yymsp[0].minor.yy346,&yymsp[-1].minor.yy0);}
    ++      case 183: /* expr ::= PLUS expr */
    ++{yymsp[-1].minor.yy314 = sqlite3PExpr(pParse, TK_UPLUS, yymsp[0].minor.yy314, 0);}
    +         break;
    +-      case 218: /* expr ::= PLUS expr */
    +-{spanUnaryPrefix(&yygotominor.yy346,pParse,TK_UPLUS,&yymsp[0].minor.yy346,&yymsp[-1].minor.yy0);}
    ++      case 184: /* between_op ::= BETWEEN */
    ++      case 187: /* in_op ::= IN */ yytestcase(yyruleno==187);
    ++{yymsp[0].minor.yy4 = 0;}
    +         break;
    +-      case 221: /* expr ::= expr between_op expr AND expr */
    ++      case 186: /* expr ::= expr between_op expr AND expr */
    + {
    +-  ExprList *pList = sqlite3ExprListAppend(pParse,0, yymsp[-2].minor.yy346.pExpr);
    +-  pList = sqlite3ExprListAppend(pParse,pList, yymsp[0].minor.yy346.pExpr);
    +-  yygotominor.yy346.pExpr = sqlite3PExpr(pParse, TK_BETWEEN, yymsp[-4].minor.yy346.pExpr, 0, 0);
    +-  if( yygotominor.yy346.pExpr ){
    +-    yygotominor.yy346.pExpr->x.pList = pList;
    ++  ExprList *pList = sqlite3ExprListAppend(pParse,0, yymsp[-2].minor.yy314);
    ++  pList = sqlite3ExprListAppend(pParse,pList, yymsp[0].minor.yy314);
    ++  yymsp[-4].minor.yy314 = sqlite3PExpr(pParse, TK_BETWEEN, yymsp[-4].minor.yy314, 0);
    ++  if( yymsp[-4].minor.yy314 ){
    ++    yymsp[-4].minor.yy314->x.pList = pList;
    +   }else{
    +     sqlite3ExprListDelete(pParse->db, pList);
    +   } 
    +-  if( yymsp[-3].minor.yy328 ) yygotominor.yy346.pExpr = sqlite3PExpr(pParse, TK_NOT, yygotominor.yy346.pExpr, 0, 0);
    +-  yygotominor.yy346.zStart = yymsp[-4].minor.yy346.zStart;
    +-  yygotominor.yy346.zEnd = yymsp[0].minor.yy346.zEnd;
    ++  if( yymsp[-3].minor.yy4 ) yymsp[-4].minor.yy314 = sqlite3PExpr(pParse, TK_NOT, yymsp[-4].minor.yy314, 0);
    + }
    +         break;
    +-      case 224: /* expr ::= expr in_op LP exprlist RP */
    ++      case 189: /* expr ::= expr in_op LP exprlist RP */
    + {
    +-    if( yymsp[-1].minor.yy14==0 ){
    ++    if( yymsp[-1].minor.yy322==0 ){
    +       /* Expressions of the form
    +       **
    +       **      expr1 IN ()
    +@@ -128954,9 +141371,9 @@ static void yy_reduce(
    +       ** simplify to constants 0 (false) and 1 (true), respectively,
    +       ** regardless of the value of expr1.
    +       */
    +-      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 ){
    ++      sqlite3ExprDelete(pParse->db, yymsp[-4].minor.yy314);
    ++      yymsp[-4].minor.yy314 = sqlite3ExprAlloc(pParse->db, TK_INTEGER,&sqlite3IntTokens[yymsp[-3].minor.yy4],1);
    ++    }else if( yymsp[-1].minor.yy322->nExpr==1 ){
    +       /* Expressions of the form:
    +       **
    +       **      expr1 IN (?1)
    +@@ -128973,423 +141390,414 @@ static void yy_reduce(
    +       ** 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);
    ++      Expr *pRHS = yymsp[-1].minor.yy322->a[0].pExpr;
    ++      yymsp[-1].minor.yy322->a[0].pExpr = 0;
    ++      sqlite3ExprListDelete(pParse->db, yymsp[-1].minor.yy322);
    +       /* 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);
    ++      yymsp[-4].minor.yy314 = sqlite3PExpr(pParse, yymsp[-3].minor.yy4 ? TK_NE : TK_EQ, yymsp[-4].minor.yy314, pRHS);
    +     }else{
    +-      yygotominor.yy346.pExpr = sqlite3PExpr(pParse, TK_IN, yymsp[-4].minor.yy346.pExpr, 0, 0);
    +-      if( yygotominor.yy346.pExpr ){
    +-        yygotominor.yy346.pExpr->x.pList = yymsp[-1].minor.yy14;
    +-        sqlite3ExprSetHeightAndFlags(pParse, yygotominor.yy346.pExpr);
    ++      yymsp[-4].minor.yy314 = sqlite3PExpr(pParse, TK_IN, yymsp[-4].minor.yy314, 0);
    ++      if( yymsp[-4].minor.yy314 ){
    ++        yymsp[-4].minor.yy314->x.pList = yymsp[-1].minor.yy322;
    ++        sqlite3ExprSetHeightAndFlags(pParse, yymsp[-4].minor.yy314);
    +       }else{
    +-        sqlite3ExprListDelete(pParse->db, yymsp[-1].minor.yy14);
    ++        sqlite3ExprListDelete(pParse->db, yymsp[-1].minor.yy322);
    +       }
    +-      if( yymsp[-3].minor.yy328 ) yygotominor.yy346.pExpr = sqlite3PExpr(pParse, TK_NOT, yygotominor.yy346.pExpr, 0, 0);
    ++      if( yymsp[-3].minor.yy4 ) yymsp[-4].minor.yy314 = sqlite3PExpr(pParse, TK_NOT, yymsp[-4].minor.yy314, 0);
    +     }
    +-    yygotominor.yy346.zStart = yymsp[-4].minor.yy346.zStart;
    +-    yygotominor.yy346.zEnd = &yymsp[0].minor.yy0.z[yymsp[0].minor.yy0.n];
    +   }
    +         break;
    +-      case 225: /* expr ::= LP select RP */
    ++      case 190: /* expr ::= LP select RP */
    + {
    +-    yygotominor.yy346.pExpr = sqlite3PExpr(pParse, TK_SELECT, 0, 0, 0);
    +-    if( yygotominor.yy346.pExpr ){
    +-      yygotominor.yy346.pExpr->x.pSelect = yymsp[-1].minor.yy3;
    +-      ExprSetProperty(yygotominor.yy346.pExpr, EP_xIsSelect|EP_Subquery);
    +-      sqlite3ExprSetHeightAndFlags(pParse, yygotominor.yy346.pExpr);
    +-    }else{
    +-      sqlite3SelectDelete(pParse->db, yymsp[-1].minor.yy3);
    +-    }
    +-    yygotominor.yy346.zStart = yymsp[-2].minor.yy0.z;
    +-    yygotominor.yy346.zEnd = &yymsp[0].minor.yy0.z[yymsp[0].minor.yy0.n];
    ++    yymsp[-2].minor.yy314 = sqlite3PExpr(pParse, TK_SELECT, 0, 0);
    ++    sqlite3PExprAddSelect(pParse, yymsp[-2].minor.yy314, yymsp[-1].minor.yy387);
    +   }
    +         break;
    +-      case 226: /* expr ::= expr in_op LP select RP */
    ++      case 191: /* expr ::= expr in_op LP select RP */
    + {
    +-    yygotominor.yy346.pExpr = sqlite3PExpr(pParse, TK_IN, yymsp[-4].minor.yy346.pExpr, 0, 0);
    +-    if( yygotominor.yy346.pExpr ){
    +-      yygotominor.yy346.pExpr->x.pSelect = yymsp[-1].minor.yy3;
    +-      ExprSetProperty(yygotominor.yy346.pExpr, EP_xIsSelect|EP_Subquery);
    +-      sqlite3ExprSetHeightAndFlags(pParse, yygotominor.yy346.pExpr);
    +-    }else{
    +-      sqlite3SelectDelete(pParse->db, yymsp[-1].minor.yy3);
    +-    }
    +-    if( yymsp[-3].minor.yy328 ) yygotominor.yy346.pExpr = sqlite3PExpr(pParse, TK_NOT, yygotominor.yy346.pExpr, 0, 0);
    +-    yygotominor.yy346.zStart = yymsp[-4].minor.yy346.zStart;
    +-    yygotominor.yy346.zEnd = &yymsp[0].minor.yy0.z[yymsp[0].minor.yy0.n];
    ++    yymsp[-4].minor.yy314 = sqlite3PExpr(pParse, TK_IN, yymsp[-4].minor.yy314, 0);
    ++    sqlite3PExprAddSelect(pParse, yymsp[-4].minor.yy314, yymsp[-1].minor.yy387);
    ++    if( yymsp[-3].minor.yy4 ) yymsp[-4].minor.yy314 = sqlite3PExpr(pParse, TK_NOT, yymsp[-4].minor.yy314, 0);
    +   }
    +         break;
    +-      case 227: /* expr ::= expr in_op nm dbnm */
    ++      case 192: /* expr ::= expr in_op nm dbnm paren_exprlist */
    + {
    +-    SrcList *pSrc = sqlite3SrcListAppend(pParse->db, 0,&yymsp[-1].minor.yy0,&yymsp[0].minor.yy0);
    +-    yygotominor.yy346.pExpr = sqlite3PExpr(pParse, TK_IN, yymsp[-3].minor.yy346.pExpr, 0, 0);
    +-    if( yygotominor.yy346.pExpr ){
    +-      yygotominor.yy346.pExpr->x.pSelect = sqlite3SelectNew(pParse, 0,pSrc,0,0,0,0,0,0,0);
    +-      ExprSetProperty(yygotominor.yy346.pExpr, EP_xIsSelect|EP_Subquery);
    +-      sqlite3ExprSetHeightAndFlags(pParse, yygotominor.yy346.pExpr);
    +-    }else{
    +-      sqlite3SrcListDelete(pParse->db, pSrc);
    +-    }
    +-    if( yymsp[-2].minor.yy328 ) yygotominor.yy346.pExpr = sqlite3PExpr(pParse, TK_NOT, yygotominor.yy346.pExpr, 0, 0);
    +-    yygotominor.yy346.zStart = yymsp[-3].minor.yy346.zStart;
    +-    yygotominor.yy346.zEnd = yymsp[0].minor.yy0.z ? &yymsp[0].minor.yy0.z[yymsp[0].minor.yy0.n] : &yymsp[-1].minor.yy0.z[yymsp[-1].minor.yy0.n];
    ++    SrcList *pSrc = sqlite3SrcListAppend(pParse->db, 0,&yymsp[-2].minor.yy0,&yymsp[-1].minor.yy0);
    ++    Select *pSelect = sqlite3SelectNew(pParse, 0,pSrc,0,0,0,0,0,0);
    ++    if( yymsp[0].minor.yy322 )  sqlite3SrcListFuncArgs(pParse, pSelect ? pSrc : 0, yymsp[0].minor.yy322);
    ++    yymsp[-4].minor.yy314 = sqlite3PExpr(pParse, TK_IN, yymsp[-4].minor.yy314, 0);
    ++    sqlite3PExprAddSelect(pParse, yymsp[-4].minor.yy314, pSelect);
    ++    if( yymsp[-3].minor.yy4 ) yymsp[-4].minor.yy314 = sqlite3PExpr(pParse, TK_NOT, yymsp[-4].minor.yy314, 0);
    +   }
    +         break;
    +-      case 228: /* expr ::= EXISTS LP select RP */
    ++      case 193: /* expr ::= EXISTS LP select RP */
    + {
    +-    Expr *p = yygotominor.yy346.pExpr = sqlite3PExpr(pParse, TK_EXISTS, 0, 0, 0);
    +-    if( p ){
    +-      p->x.pSelect = yymsp[-1].minor.yy3;
    +-      ExprSetProperty(p, EP_xIsSelect|EP_Subquery);
    +-      sqlite3ExprSetHeightAndFlags(pParse, p);
    +-    }else{
    +-      sqlite3SelectDelete(pParse->db, yymsp[-1].minor.yy3);
    +-    }
    +-    yygotominor.yy346.zStart = yymsp[-3].minor.yy0.z;
    +-    yygotominor.yy346.zEnd = &yymsp[0].minor.yy0.z[yymsp[0].minor.yy0.n];
    ++    Expr *p;
    ++    p = yymsp[-3].minor.yy314 = sqlite3PExpr(pParse, TK_EXISTS, 0, 0);
    ++    sqlite3PExprAddSelect(pParse, p, yymsp[-1].minor.yy387);
    +   }
    +         break;
    +-      case 229: /* expr ::= CASE case_operand case_exprlist case_else END */
    ++      case 194: /* expr ::= CASE case_operand case_exprlist case_else END */
    + {
    +-  yygotominor.yy346.pExpr = sqlite3PExpr(pParse, TK_CASE, yymsp[-3].minor.yy132, 0, 0);
    +-  if( yygotominor.yy346.pExpr ){
    +-    yygotominor.yy346.pExpr->x.pList = yymsp[-1].minor.yy132 ? sqlite3ExprListAppend(pParse,yymsp[-2].minor.yy14,yymsp[-1].minor.yy132) : yymsp[-2].minor.yy14;
    +-    sqlite3ExprSetHeightAndFlags(pParse, yygotominor.yy346.pExpr);
    ++  yymsp[-4].minor.yy314 = sqlite3PExpr(pParse, TK_CASE, yymsp[-3].minor.yy314, 0);
    ++  if( yymsp[-4].minor.yy314 ){
    ++    yymsp[-4].minor.yy314->x.pList = yymsp[-1].minor.yy314 ? sqlite3ExprListAppend(pParse,yymsp[-2].minor.yy322,yymsp[-1].minor.yy314) : yymsp[-2].minor.yy322;
    ++    sqlite3ExprSetHeightAndFlags(pParse, yymsp[-4].minor.yy314);
    +   }else{
    +-    sqlite3ExprListDelete(pParse->db, yymsp[-2].minor.yy14);
    +-    sqlite3ExprDelete(pParse->db, yymsp[-1].minor.yy132);
    ++    sqlite3ExprListDelete(pParse->db, yymsp[-2].minor.yy322);
    ++    sqlite3ExprDelete(pParse->db, yymsp[-1].minor.yy314);
    +   }
    +-  yygotominor.yy346.zStart = yymsp[-4].minor.yy0.z;
    +-  yygotominor.yy346.zEnd = &yymsp[0].minor.yy0.z[yymsp[0].minor.yy0.n];
    + }
    +         break;
    +-      case 230: /* case_exprlist ::= case_exprlist WHEN expr THEN expr */
    ++      case 195: /* case_exprlist ::= case_exprlist WHEN expr THEN expr */
    + {
    +-  yygotominor.yy14 = sqlite3ExprListAppend(pParse,yymsp[-4].minor.yy14, yymsp[-2].minor.yy346.pExpr);
    +-  yygotominor.yy14 = sqlite3ExprListAppend(pParse,yygotominor.yy14, yymsp[0].minor.yy346.pExpr);
    ++  yymsp[-4].minor.yy322 = sqlite3ExprListAppend(pParse,yymsp[-4].minor.yy322, yymsp[-2].minor.yy314);
    ++  yymsp[-4].minor.yy322 = sqlite3ExprListAppend(pParse,yymsp[-4].minor.yy322, yymsp[0].minor.yy314);
    + }
    +         break;
    +-      case 231: /* case_exprlist ::= WHEN expr THEN expr */
    ++      case 196: /* case_exprlist ::= WHEN expr THEN expr */
    + {
    +-  yygotominor.yy14 = sqlite3ExprListAppend(pParse,0, yymsp[-2].minor.yy346.pExpr);
    +-  yygotominor.yy14 = sqlite3ExprListAppend(pParse,yygotominor.yy14, yymsp[0].minor.yy346.pExpr);
    ++  yymsp[-3].minor.yy322 = sqlite3ExprListAppend(pParse,0, yymsp[-2].minor.yy314);
    ++  yymsp[-3].minor.yy322 = sqlite3ExprListAppend(pParse,yymsp[-3].minor.yy322, yymsp[0].minor.yy314);
    + }
    +         break;
    +-      case 238: /* nexprlist ::= nexprlist COMMA expr */
    +-{yygotominor.yy14 = sqlite3ExprListAppend(pParse,yymsp[-2].minor.yy14,yymsp[0].minor.yy346.pExpr);}
    ++      case 199: /* case_operand ::= expr */
    ++{yymsp[0].minor.yy314 = yymsp[0].minor.yy314; /*A-overwrites-X*/}
    ++        break;
    ++      case 202: /* nexprlist ::= nexprlist COMMA expr */
    ++{yymsp[-2].minor.yy322 = sqlite3ExprListAppend(pParse,yymsp[-2].minor.yy322,yymsp[0].minor.yy314);}
    +         break;
    +-      case 239: /* nexprlist ::= expr */
    +-{yygotominor.yy14 = sqlite3ExprListAppend(pParse,0,yymsp[0].minor.yy346.pExpr);}
    ++      case 203: /* nexprlist ::= expr */
    ++{yymsp[0].minor.yy322 = sqlite3ExprListAppend(pParse,0,yymsp[0].minor.yy314); /*A-overwrites-Y*/}
    +         break;
    +-      case 240: /* cmd ::= createkw uniqueflag INDEX ifnotexists nm dbnm ON nm LP sortlist RP where_opt */
    ++      case 205: /* paren_exprlist ::= LP exprlist RP */
    ++      case 210: /* eidlist_opt ::= LP eidlist RP */ yytestcase(yyruleno==210);
    ++{yymsp[-2].minor.yy322 = yymsp[-1].minor.yy322;}
    ++        break;
    ++      case 206: /* cmd ::= createkw uniqueflag INDEX ifnotexists nm dbnm ON nm LP sortlist RP where_opt */
    + {
    +   sqlite3CreateIndex(pParse, &yymsp[-7].minor.yy0, &yymsp[-6].minor.yy0, 
    +-                     sqlite3SrcListAppend(pParse->db,0,&yymsp[-4].minor.yy0,0), yymsp[-2].minor.yy14, yymsp[-10].minor.yy328,
    +-                      &yymsp[-11].minor.yy0, yymsp[0].minor.yy132, SQLITE_SO_ASC, yymsp[-8].minor.yy328);
    ++                     sqlite3SrcListAppend(pParse->db,0,&yymsp[-4].minor.yy0,0), yymsp[-2].minor.yy322, yymsp[-10].minor.yy4,
    ++                      &yymsp[-11].minor.yy0, yymsp[0].minor.yy314, SQLITE_SO_ASC, yymsp[-8].minor.yy4, SQLITE_IDXTYPE_APPDEF);
    + }
    +         break;
    +-      case 241: /* uniqueflag ::= UNIQUE */
    +-      case 292: /* raisetype ::= ABORT */ yytestcase(yyruleno==292);
    +-{yygotominor.yy328 = OE_Abort;}
    ++      case 207: /* uniqueflag ::= UNIQUE */
    ++      case 247: /* raisetype ::= ABORT */ yytestcase(yyruleno==247);
    ++{yymsp[0].minor.yy4 = OE_Abort;}
    +         break;
    +-      case 242: /* uniqueflag ::= */
    +-{yygotominor.yy328 = OE_None;}
    ++      case 208: /* uniqueflag ::= */
    ++{yymsp[1].minor.yy4 = OE_None;}
    +         break;
    +-      case 245: /* eidlist ::= eidlist COMMA nm collate sortorder */
    ++      case 211: /* eidlist ::= eidlist COMMA nm collate sortorder */
    + {
    +-  yygotominor.yy14 = parserAddExprIdListTerm(pParse, yymsp[-4].minor.yy14, &yymsp[-2].minor.yy0, yymsp[-1].minor.yy328, yymsp[0].minor.yy328);
    ++  yymsp[-4].minor.yy322 = parserAddExprIdListTerm(pParse, yymsp[-4].minor.yy322, &yymsp[-2].minor.yy0, yymsp[-1].minor.yy4, yymsp[0].minor.yy4);
    + }
    +         break;
    +-      case 246: /* eidlist ::= nm collate sortorder */
    ++      case 212: /* eidlist ::= nm collate sortorder */
    + {
    +-  yygotominor.yy14 = parserAddExprIdListTerm(pParse, 0, &yymsp[-2].minor.yy0, yymsp[-1].minor.yy328, yymsp[0].minor.yy328);
    ++  yymsp[-2].minor.yy322 = parserAddExprIdListTerm(pParse, 0, &yymsp[-2].minor.yy0, yymsp[-1].minor.yy4, yymsp[0].minor.yy4); /*A-overwrites-Y*/
    + }
    +         break;
    +-      case 249: /* cmd ::= DROP INDEX ifexists fullname */
    +-{sqlite3DropIndex(pParse, yymsp[0].minor.yy65, yymsp[-1].minor.yy328);}
    ++      case 215: /* cmd ::= DROP INDEX ifexists fullname */
    ++{sqlite3DropIndex(pParse, yymsp[0].minor.yy259, yymsp[-1].minor.yy4);}
    ++        break;
    ++      case 216: /* cmd ::= VACUUM */
    ++{sqlite3Vacuum(pParse,0);}
    +         break;
    +-      case 250: /* cmd ::= VACUUM */
    +-      case 251: /* cmd ::= VACUUM nm */ yytestcase(yyruleno==251);
    +-{sqlite3Vacuum(pParse);}
    ++      case 217: /* cmd ::= VACUUM nm */
    ++{sqlite3Vacuum(pParse,&yymsp[0].minor.yy0);}
    +         break;
    +-      case 252: /* cmd ::= PRAGMA nm dbnm */
    ++      case 218: /* cmd ::= PRAGMA nm dbnm */
    + {sqlite3Pragma(pParse,&yymsp[-1].minor.yy0,&yymsp[0].minor.yy0,0,0);}
    +         break;
    +-      case 253: /* cmd ::= PRAGMA nm dbnm EQ nmnum */
    ++      case 219: /* cmd ::= PRAGMA nm dbnm EQ nmnum */
    + {sqlite3Pragma(pParse,&yymsp[-3].minor.yy0,&yymsp[-2].minor.yy0,&yymsp[0].minor.yy0,0);}
    +         break;
    +-      case 254: /* cmd ::= PRAGMA nm dbnm LP nmnum RP */
    ++      case 220: /* cmd ::= PRAGMA nm dbnm LP nmnum RP */
    + {sqlite3Pragma(pParse,&yymsp[-4].minor.yy0,&yymsp[-3].minor.yy0,&yymsp[-1].minor.yy0,0);}
    +         break;
    +-      case 255: /* cmd ::= PRAGMA nm dbnm EQ minus_num */
    ++      case 221: /* cmd ::= PRAGMA nm dbnm EQ minus_num */
    + {sqlite3Pragma(pParse,&yymsp[-3].minor.yy0,&yymsp[-2].minor.yy0,&yymsp[0].minor.yy0,1);}
    +         break;
    +-      case 256: /* cmd ::= PRAGMA nm dbnm LP minus_num RP */
    ++      case 222: /* cmd ::= PRAGMA nm dbnm LP minus_num RP */
    + {sqlite3Pragma(pParse,&yymsp[-4].minor.yy0,&yymsp[-3].minor.yy0,&yymsp[-1].minor.yy0,1);}
    +         break;
    +-      case 265: /* cmd ::= createkw trigger_decl BEGIN trigger_cmd_list END */
    ++      case 225: /* cmd ::= createkw trigger_decl BEGIN trigger_cmd_list END */
    + {
    +   Token all;
    +   all.z = yymsp[-3].minor.yy0.z;
    +   all.n = (int)(yymsp[0].minor.yy0.z - yymsp[-3].minor.yy0.z) + yymsp[0].minor.yy0.n;
    +-  sqlite3FinishTrigger(pParse, yymsp[-1].minor.yy473, &all);
    ++  sqlite3FinishTrigger(pParse, yymsp[-1].minor.yy203, &all);
    + }
    +         break;
    +-      case 266: /* trigger_decl ::= temp TRIGGER ifnotexists nm dbnm trigger_time trigger_event ON fullname foreach_clause when_clause */
    ++      case 226: /* trigger_decl ::= temp TRIGGER ifnotexists nm dbnm trigger_time trigger_event ON fullname foreach_clause when_clause */
    + {
    +-  sqlite3BeginTrigger(pParse, &yymsp[-7].minor.yy0, &yymsp[-6].minor.yy0, yymsp[-5].minor.yy328, yymsp[-4].minor.yy378.a, yymsp[-4].minor.yy378.b, yymsp[-2].minor.yy65, yymsp[0].minor.yy132, yymsp[-10].minor.yy328, yymsp[-8].minor.yy328);
    +-  yygotominor.yy0 = (yymsp[-6].minor.yy0.n==0?yymsp[-7].minor.yy0:yymsp[-6].minor.yy0);
    ++  sqlite3BeginTrigger(pParse, &yymsp[-7].minor.yy0, &yymsp[-6].minor.yy0, yymsp[-5].minor.yy4, yymsp[-4].minor.yy90.a, yymsp[-4].minor.yy90.b, yymsp[-2].minor.yy259, yymsp[0].minor.yy314, yymsp[-10].minor.yy4, yymsp[-8].minor.yy4);
    ++  yymsp[-10].minor.yy0 = (yymsp[-6].minor.yy0.n==0?yymsp[-7].minor.yy0:yymsp[-6].minor.yy0); /*A-overwrites-T*/
    + }
    +         break;
    +-      case 267: /* trigger_time ::= BEFORE */
    +-      case 270: /* trigger_time ::= */ yytestcase(yyruleno==270);
    +-{ yygotominor.yy328 = TK_BEFORE; }
    ++      case 227: /* trigger_time ::= BEFORE|AFTER */
    ++{ yymsp[0].minor.yy4 = yymsp[0].major; /*A-overwrites-X*/ }
    +         break;
    +-      case 268: /* trigger_time ::= AFTER */
    +-{ yygotominor.yy328 = TK_AFTER;  }
    ++      case 228: /* trigger_time ::= INSTEAD OF */
    ++{ yymsp[-1].minor.yy4 = TK_INSTEAD;}
    +         break;
    +-      case 269: /* trigger_time ::= INSTEAD OF */
    +-{ yygotominor.yy328 = TK_INSTEAD;}
    ++      case 229: /* trigger_time ::= */
    ++{ yymsp[1].minor.yy4 = TK_BEFORE; }
    +         break;
    +-      case 271: /* trigger_event ::= DELETE|INSERT */
    +-      case 272: /* trigger_event ::= UPDATE */ yytestcase(yyruleno==272);
    +-{yygotominor.yy378.a = yymsp[0].major; yygotominor.yy378.b = 0;}
    ++      case 230: /* trigger_event ::= DELETE|INSERT */
    ++      case 231: /* trigger_event ::= UPDATE */ yytestcase(yyruleno==231);
    ++{yymsp[0].minor.yy90.a = yymsp[0].major; /*A-overwrites-X*/ yymsp[0].minor.yy90.b = 0;}
    +         break;
    +-      case 273: /* trigger_event ::= UPDATE OF idlist */
    +-{yygotominor.yy378.a = TK_UPDATE; yygotominor.yy378.b = yymsp[0].minor.yy408;}
    ++      case 232: /* trigger_event ::= UPDATE OF idlist */
    ++{yymsp[-2].minor.yy90.a = TK_UPDATE; yymsp[-2].minor.yy90.b = yymsp[0].minor.yy384;}
    +         break;
    +-      case 276: /* when_clause ::= */
    +-      case 297: /* key_opt ::= */ yytestcase(yyruleno==297);
    +-{ yygotominor.yy132 = 0; }
    ++      case 233: /* when_clause ::= */
    ++      case 252: /* key_opt ::= */ yytestcase(yyruleno==252);
    ++{ yymsp[1].minor.yy314 = 0; }
    +         break;
    +-      case 277: /* when_clause ::= WHEN expr */
    +-      case 298: /* key_opt ::= KEY expr */ yytestcase(yyruleno==298);
    +-{ yygotominor.yy132 = yymsp[0].minor.yy346.pExpr; }
    ++      case 234: /* when_clause ::= WHEN expr */
    ++      case 253: /* key_opt ::= KEY expr */ yytestcase(yyruleno==253);
    ++{ yymsp[-1].minor.yy314 = yymsp[0].minor.yy314; }
    +         break;
    +-      case 278: /* trigger_cmd_list ::= trigger_cmd_list trigger_cmd SEMI */
    ++      case 235: /* trigger_cmd_list ::= trigger_cmd_list trigger_cmd SEMI */
    + {
    +-  assert( yymsp[-2].minor.yy473!=0 );
    +-  yymsp[-2].minor.yy473->pLast->pNext = yymsp[-1].minor.yy473;
    +-  yymsp[-2].minor.yy473->pLast = yymsp[-1].minor.yy473;
    +-  yygotominor.yy473 = yymsp[-2].minor.yy473;
    ++  assert( yymsp[-2].minor.yy203!=0 );
    ++  yymsp[-2].minor.yy203->pLast->pNext = yymsp[-1].minor.yy203;
    ++  yymsp[-2].minor.yy203->pLast = yymsp[-1].minor.yy203;
    + }
    +         break;
    +-      case 279: /* trigger_cmd_list ::= trigger_cmd SEMI */
    ++      case 236: /* trigger_cmd_list ::= trigger_cmd SEMI */
    + { 
    +-  assert( yymsp[-1].minor.yy473!=0 );
    +-  yymsp[-1].minor.yy473->pLast = yymsp[-1].minor.yy473;
    +-  yygotominor.yy473 = yymsp[-1].minor.yy473;
    ++  assert( yymsp[-1].minor.yy203!=0 );
    ++  yymsp[-1].minor.yy203->pLast = yymsp[-1].minor.yy203;
    + }
    +         break;
    +-      case 281: /* trnm ::= nm DOT nm */
    ++      case 237: /* trnm ::= nm DOT nm */
    + {
    +-  yygotominor.yy0 = yymsp[0].minor.yy0;
    ++  yymsp[-2].minor.yy0 = yymsp[0].minor.yy0;
    +   sqlite3ErrorMsg(pParse, 
    +         "qualified table names are not allowed on INSERT, UPDATE, and DELETE "
    +         "statements within triggers");
    + }
    +         break;
    +-      case 283: /* tridxby ::= INDEXED BY nm */
    ++      case 238: /* tridxby ::= INDEXED BY nm */
    + {
    +   sqlite3ErrorMsg(pParse,
    +         "the INDEXED BY clause is not allowed on UPDATE or DELETE statements "
    +         "within triggers");
    + }
    +         break;
    +-      case 284: /* tridxby ::= NOT INDEXED */
    ++      case 239: /* tridxby ::= NOT INDEXED */
    + {
    +   sqlite3ErrorMsg(pParse,
    +         "the NOT INDEXED clause is not allowed on UPDATE or DELETE statements "
    +         "within triggers");
    + }
    +         break;
    +-      case 285: /* trigger_cmd ::= UPDATE orconf trnm tridxby SET setlist where_opt */
    +-{ yygotominor.yy473 = sqlite3TriggerUpdateStep(pParse->db, &yymsp[-4].minor.yy0, yymsp[-1].minor.yy14, yymsp[0].minor.yy132, yymsp[-5].minor.yy186); }
    ++      case 240: /* trigger_cmd ::= UPDATE orconf trnm tridxby SET setlist where_opt scanpt */
    ++{yylhsminor.yy203 = sqlite3TriggerUpdateStep(pParse->db, &yymsp[-5].minor.yy0, yymsp[-2].minor.yy322, yymsp[-1].minor.yy314, yymsp[-6].minor.yy4, yymsp[-7].minor.yy0.z, yymsp[0].minor.yy336);}
    ++  yymsp[-7].minor.yy203 = yylhsminor.yy203;
    +         break;
    +-      case 286: /* trigger_cmd ::= insert_cmd INTO trnm idlist_opt select */
    +-{yygotominor.yy473 = sqlite3TriggerInsertStep(pParse->db, &yymsp[-2].minor.yy0, yymsp[-1].minor.yy408, yymsp[0].minor.yy3, yymsp[-4].minor.yy186);}
    ++      case 241: /* trigger_cmd ::= scanpt insert_cmd INTO trnm idlist_opt select scanpt */
    ++{yylhsminor.yy203 = sqlite3TriggerInsertStep(pParse->db,&yymsp[-3].minor.yy0,yymsp[-2].minor.yy384,yymsp[-1].minor.yy387,yymsp[-5].minor.yy4,yymsp[-6].minor.yy336,yymsp[0].minor.yy336);/*yylhsminor.yy203-overwrites-yymsp[-5].minor.yy4*/}
    ++  yymsp[-6].minor.yy203 = yylhsminor.yy203;
    +         break;
    +-      case 287: /* trigger_cmd ::= DELETE FROM trnm tridxby where_opt */
    +-{yygotominor.yy473 = sqlite3TriggerDeleteStep(pParse->db, &yymsp[-2].minor.yy0, yymsp[0].minor.yy132);}
    ++      case 242: /* trigger_cmd ::= DELETE FROM trnm tridxby where_opt scanpt */
    ++{yylhsminor.yy203 = sqlite3TriggerDeleteStep(pParse->db, &yymsp[-3].minor.yy0, yymsp[-1].minor.yy314, yymsp[-5].minor.yy0.z, yymsp[0].minor.yy336);}
    ++  yymsp[-5].minor.yy203 = yylhsminor.yy203;
    +         break;
    +-      case 288: /* trigger_cmd ::= select */
    +-{yygotominor.yy473 = sqlite3TriggerSelectStep(pParse->db, yymsp[0].minor.yy3); }
    ++      case 243: /* trigger_cmd ::= scanpt select scanpt */
    ++{yylhsminor.yy203 = sqlite3TriggerSelectStep(pParse->db, yymsp[-1].minor.yy387, yymsp[-2].minor.yy336, yymsp[0].minor.yy336); /*yylhsminor.yy203-overwrites-yymsp[-1].minor.yy387*/}
    ++  yymsp[-2].minor.yy203 = yylhsminor.yy203;
    +         break;
    +-      case 289: /* expr ::= RAISE LP IGNORE RP */
    ++      case 244: /* expr ::= RAISE LP IGNORE RP */
    + {
    +-  yygotominor.yy346.pExpr = sqlite3PExpr(pParse, TK_RAISE, 0, 0, 0); 
    +-  if( yygotominor.yy346.pExpr ){
    +-    yygotominor.yy346.pExpr->affinity = OE_Ignore;
    ++  yymsp[-3].minor.yy314 = sqlite3PExpr(pParse, TK_RAISE, 0, 0); 
    ++  if( yymsp[-3].minor.yy314 ){
    ++    yymsp[-3].minor.yy314->affinity = OE_Ignore;
    +   }
    +-  yygotominor.yy346.zStart = yymsp[-3].minor.yy0.z;
    +-  yygotominor.yy346.zEnd = &yymsp[0].minor.yy0.z[yymsp[0].minor.yy0.n];
    + }
    +         break;
    +-      case 290: /* expr ::= RAISE LP raisetype COMMA nm RP */
    ++      case 245: /* expr ::= RAISE LP raisetype COMMA nm RP */
    + {
    +-  yygotominor.yy346.pExpr = sqlite3PExpr(pParse, TK_RAISE, 0, 0, &yymsp[-1].minor.yy0); 
    +-  if( yygotominor.yy346.pExpr ) {
    +-    yygotominor.yy346.pExpr->affinity = (char)yymsp[-3].minor.yy328;
    ++  yymsp[-5].minor.yy314 = sqlite3ExprAlloc(pParse->db, TK_RAISE, &yymsp[-1].minor.yy0, 1); 
    ++  if( yymsp[-5].minor.yy314 ) {
    ++    yymsp[-5].minor.yy314->affinity = (char)yymsp[-3].minor.yy4;
    +   }
    +-  yygotominor.yy346.zStart = yymsp[-5].minor.yy0.z;
    +-  yygotominor.yy346.zEnd = &yymsp[0].minor.yy0.z[yymsp[0].minor.yy0.n];
    + }
    +         break;
    +-      case 291: /* raisetype ::= ROLLBACK */
    +-{yygotominor.yy328 = OE_Rollback;}
    ++      case 246: /* raisetype ::= ROLLBACK */
    ++{yymsp[0].minor.yy4 = OE_Rollback;}
    +         break;
    +-      case 293: /* raisetype ::= FAIL */
    +-{yygotominor.yy328 = OE_Fail;}
    ++      case 248: /* raisetype ::= FAIL */
    ++{yymsp[0].minor.yy4 = OE_Fail;}
    +         break;
    +-      case 294: /* cmd ::= DROP TRIGGER ifexists fullname */
    ++      case 249: /* cmd ::= DROP TRIGGER ifexists fullname */
    + {
    +-  sqlite3DropTrigger(pParse,yymsp[0].minor.yy65,yymsp[-1].minor.yy328);
    ++  sqlite3DropTrigger(pParse,yymsp[0].minor.yy259,yymsp[-1].minor.yy4);
    + }
    +         break;
    +-      case 295: /* cmd ::= ATTACH database_kw_opt expr AS expr key_opt */
    ++      case 250: /* cmd ::= ATTACH database_kw_opt expr AS expr key_opt */
    + {
    +-  sqlite3Attach(pParse, yymsp[-3].minor.yy346.pExpr, yymsp[-1].minor.yy346.pExpr, yymsp[0].minor.yy132);
    ++  sqlite3Attach(pParse, yymsp[-3].minor.yy314, yymsp[-1].minor.yy314, yymsp[0].minor.yy314);
    + }
    +         break;
    +-      case 296: /* cmd ::= DETACH database_kw_opt expr */
    ++      case 251: /* cmd ::= DETACH database_kw_opt expr */
    + {
    +-  sqlite3Detach(pParse, yymsp[0].minor.yy346.pExpr);
    ++  sqlite3Detach(pParse, yymsp[0].minor.yy314);
    + }
    +         break;
    +-      case 301: /* cmd ::= REINDEX */
    ++      case 254: /* cmd ::= REINDEX */
    + {sqlite3Reindex(pParse, 0, 0);}
    +         break;
    +-      case 302: /* cmd ::= REINDEX nm dbnm */
    ++      case 255: /* cmd ::= REINDEX nm dbnm */
    + {sqlite3Reindex(pParse, &yymsp[-1].minor.yy0, &yymsp[0].minor.yy0);}
    +         break;
    +-      case 303: /* cmd ::= ANALYZE */
    ++      case 256: /* cmd ::= ANALYZE */
    + {sqlite3Analyze(pParse, 0, 0);}
    +         break;
    +-      case 304: /* cmd ::= ANALYZE nm dbnm */
    ++      case 257: /* cmd ::= ANALYZE nm dbnm */
    + {sqlite3Analyze(pParse, &yymsp[-1].minor.yy0, &yymsp[0].minor.yy0);}
    +         break;
    +-      case 305: /* cmd ::= ALTER TABLE fullname RENAME TO nm */
    ++      case 258: /* cmd ::= ALTER TABLE fullname RENAME TO nm */
    + {
    +-  sqlite3AlterRenameTable(pParse,yymsp[-3].minor.yy65,&yymsp[0].minor.yy0);
    ++  sqlite3AlterRenameTable(pParse,yymsp[-3].minor.yy259,&yymsp[0].minor.yy0);
    + }
    +         break;
    +-      case 306: /* cmd ::= ALTER TABLE add_column_fullname ADD kwcolumn_opt column */
    ++      case 259: /* cmd ::= ALTER TABLE add_column_fullname ADD kwcolumn_opt columnname carglist */
    + {
    +-  sqlite3AlterFinishAddColumn(pParse, &yymsp[0].minor.yy0);
    ++  yymsp[-1].minor.yy0.n = (int)(pParse->sLastToken.z-yymsp[-1].minor.yy0.z) + pParse->sLastToken.n;
    ++  sqlite3AlterFinishAddColumn(pParse, &yymsp[-1].minor.yy0);
    + }
    +         break;
    +-      case 307: /* add_column_fullname ::= fullname */
    ++      case 260: /* add_column_fullname ::= fullname */
    + {
    +-  pParse->db->lookaside.bEnabled = 0;
    +-  sqlite3AlterBeginAddColumn(pParse, yymsp[0].minor.yy65);
    ++  disableLookaside(pParse);
    ++  sqlite3AlterBeginAddColumn(pParse, yymsp[0].minor.yy259);
    + }
    +         break;
    +-      case 310: /* cmd ::= create_vtab */
    ++      case 261: /* cmd ::= create_vtab */
    + {sqlite3VtabFinishParse(pParse,0);}
    +         break;
    +-      case 311: /* cmd ::= create_vtab LP vtabarglist RP */
    ++      case 262: /* cmd ::= create_vtab LP vtabarglist RP */
    + {sqlite3VtabFinishParse(pParse,&yymsp[0].minor.yy0);}
    +         break;
    +-      case 312: /* create_vtab ::= createkw VIRTUAL TABLE ifnotexists nm dbnm USING nm */
    ++      case 263: /* create_vtab ::= createkw VIRTUAL TABLE ifnotexists nm dbnm USING nm */
    + {
    +-    sqlite3VtabBeginParse(pParse, &yymsp[-3].minor.yy0, &yymsp[-2].minor.yy0, &yymsp[0].minor.yy0, yymsp[-4].minor.yy328);
    ++    sqlite3VtabBeginParse(pParse, &yymsp[-3].minor.yy0, &yymsp[-2].minor.yy0, &yymsp[0].minor.yy0, yymsp[-4].minor.yy4);
    + }
    +         break;
    +-      case 315: /* vtabarg ::= */
    ++      case 264: /* vtabarg ::= */
    + {sqlite3VtabArgInit(pParse);}
    +         break;
    +-      case 317: /* vtabargtoken ::= ANY */
    +-      case 318: /* vtabargtoken ::= lp anylist RP */ yytestcase(yyruleno==318);
    +-      case 319: /* lp ::= LP */ yytestcase(yyruleno==319);
    ++      case 265: /* vtabargtoken ::= ANY */
    ++      case 266: /* vtabargtoken ::= lp anylist RP */ yytestcase(yyruleno==266);
    ++      case 267: /* lp ::= LP */ yytestcase(yyruleno==267);
    + {sqlite3VtabArgExtend(pParse,&yymsp[0].minor.yy0);}
    +         break;
    +-      case 323: /* with ::= */
    +-{yygotominor.yy59 = 0;}
    ++      case 268: /* with ::= */
    ++{yymsp[1].minor.yy451 = 0;}
    +         break;
    +-      case 324: /* with ::= WITH wqlist */
    +-      case 325: /* with ::= WITH RECURSIVE wqlist */ yytestcase(yyruleno==325);
    +-{ yygotominor.yy59 = yymsp[0].minor.yy59; }
    ++      case 269: /* with ::= WITH wqlist */
    ++{ yymsp[-1].minor.yy451 = yymsp[0].minor.yy451; }
    +         break;
    +-      case 326: /* wqlist ::= nm eidlist_opt AS LP select RP */
    ++      case 270: /* with ::= WITH RECURSIVE wqlist */
    ++{ yymsp[-2].minor.yy451 = yymsp[0].minor.yy451; }
    ++        break;
    ++      case 271: /* wqlist ::= nm eidlist_opt AS LP select RP */
    + {
    +-  yygotominor.yy59 = sqlite3WithAdd(pParse, 0, &yymsp[-5].minor.yy0, yymsp[-4].minor.yy14, yymsp[-1].minor.yy3);
    ++  yymsp[-5].minor.yy451 = sqlite3WithAdd(pParse, 0, &yymsp[-5].minor.yy0, yymsp[-4].minor.yy322, yymsp[-1].minor.yy387); /*A-overwrites-X*/
    + }
    +         break;
    +-      case 327: /* wqlist ::= wqlist COMMA nm eidlist_opt AS LP select RP */
    ++      case 272: /* wqlist ::= wqlist COMMA nm eidlist_opt AS LP select RP */
    + {
    +-  yygotominor.yy59 = sqlite3WithAdd(pParse, yymsp[-7].minor.yy59, &yymsp[-5].minor.yy0, yymsp[-4].minor.yy14, yymsp[-1].minor.yy3);
    ++  yymsp[-7].minor.yy451 = sqlite3WithAdd(pParse, yymsp[-7].minor.yy451, &yymsp[-5].minor.yy0, yymsp[-4].minor.yy322, yymsp[-1].minor.yy387);
    + }
    +         break;
    +       default:
    +-      /* (0) input ::= cmdlist */ yytestcase(yyruleno==0);
    +-      /* (1) cmdlist ::= cmdlist ecmd */ yytestcase(yyruleno==1);
    +-      /* (2) cmdlist ::= ecmd */ yytestcase(yyruleno==2);
    +-      /* (3) ecmd ::= SEMI */ yytestcase(yyruleno==3);
    +-      /* (4) ecmd ::= explain cmdx SEMI */ yytestcase(yyruleno==4);
    +-      /* (10) trans_opt ::= */ yytestcase(yyruleno==10);
    +-      /* (11) trans_opt ::= TRANSACTION */ yytestcase(yyruleno==11);
    +-      /* (12) trans_opt ::= TRANSACTION nm */ yytestcase(yyruleno==12);
    +-      /* (20) savepoint_opt ::= SAVEPOINT */ yytestcase(yyruleno==20);
    +-      /* (21) savepoint_opt ::= */ yytestcase(yyruleno==21);
    +-      /* (25) cmd ::= create_table create_table_args */ yytestcase(yyruleno==25);
    +-      /* (36) columnlist ::= columnlist COMMA column */ yytestcase(yyruleno==36);
    +-      /* (37) columnlist ::= column */ yytestcase(yyruleno==37);
    +-      /* (43) type ::= */ yytestcase(yyruleno==43);
    +-      /* (50) signed ::= plus_num */ yytestcase(yyruleno==50);
    +-      /* (51) signed ::= minus_num */ yytestcase(yyruleno==51);
    +-      /* (52) carglist ::= carglist ccons */ yytestcase(yyruleno==52);
    +-      /* (53) carglist ::= */ yytestcase(yyruleno==53);
    +-      /* (60) ccons ::= NULL onconf */ yytestcase(yyruleno==60);
    +-      /* (88) conslist ::= conslist tconscomma tcons */ yytestcase(yyruleno==88);
    +-      /* (89) conslist ::= tcons */ yytestcase(yyruleno==89);
    +-      /* (91) tconscomma ::= */ yytestcase(yyruleno==91);
    +-      /* (274) foreach_clause ::= */ yytestcase(yyruleno==274);
    +-      /* (275) foreach_clause ::= FOR EACH ROW */ yytestcase(yyruleno==275);
    +-      /* (282) tridxby ::= */ yytestcase(yyruleno==282);
    +-      /* (299) database_kw_opt ::= DATABASE */ yytestcase(yyruleno==299);
    +-      /* (300) database_kw_opt ::= */ yytestcase(yyruleno==300);
    +-      /* (308) kwcolumn_opt ::= */ yytestcase(yyruleno==308);
    +-      /* (309) kwcolumn_opt ::= COLUMNKW */ yytestcase(yyruleno==309);
    +-      /* (313) vtabarglist ::= vtabarg */ yytestcase(yyruleno==313);
    +-      /* (314) vtabarglist ::= vtabarglist COMMA vtabarg */ yytestcase(yyruleno==314);
    +-      /* (316) vtabarg ::= vtabarg vtabargtoken */ yytestcase(yyruleno==316);
    +-      /* (320) anylist ::= */ yytestcase(yyruleno==320);
    +-      /* (321) anylist ::= anylist LP anylist RP */ yytestcase(yyruleno==321);
    +-      /* (322) anylist ::= anylist ANY */ yytestcase(yyruleno==322);
    ++      /* (273) input ::= cmdlist */ yytestcase(yyruleno==273);
    ++      /* (274) cmdlist ::= cmdlist ecmd */ yytestcase(yyruleno==274);
    ++      /* (275) cmdlist ::= ecmd (OPTIMIZED OUT) */ assert(yyruleno!=275);
    ++      /* (276) ecmd ::= SEMI */ yytestcase(yyruleno==276);
    ++      /* (277) ecmd ::= explain cmdx SEMI */ yytestcase(yyruleno==277);
    ++      /* (278) explain ::= */ yytestcase(yyruleno==278);
    ++      /* (279) trans_opt ::= */ yytestcase(yyruleno==279);
    ++      /* (280) trans_opt ::= TRANSACTION */ yytestcase(yyruleno==280);
    ++      /* (281) trans_opt ::= TRANSACTION nm */ yytestcase(yyruleno==281);
    ++      /* (282) savepoint_opt ::= SAVEPOINT */ yytestcase(yyruleno==282);
    ++      /* (283) savepoint_opt ::= */ yytestcase(yyruleno==283);
    ++      /* (284) cmd ::= create_table create_table_args */ yytestcase(yyruleno==284);
    ++      /* (285) columnlist ::= columnlist COMMA columnname carglist */ yytestcase(yyruleno==285);
    ++      /* (286) columnlist ::= columnname carglist */ yytestcase(yyruleno==286);
    ++      /* (287) nm ::= ID|INDEXED */ yytestcase(yyruleno==287);
    ++      /* (288) nm ::= STRING */ yytestcase(yyruleno==288);
    ++      /* (289) nm ::= JOIN_KW */ yytestcase(yyruleno==289);
    ++      /* (290) typetoken ::= typename */ yytestcase(yyruleno==290);
    ++      /* (291) typename ::= ID|STRING */ yytestcase(yyruleno==291);
    ++      /* (292) signed ::= plus_num (OPTIMIZED OUT) */ assert(yyruleno!=292);
    ++      /* (293) signed ::= minus_num (OPTIMIZED OUT) */ assert(yyruleno!=293);
    ++      /* (294) carglist ::= carglist ccons */ yytestcase(yyruleno==294);
    ++      /* (295) carglist ::= */ yytestcase(yyruleno==295);
    ++      /* (296) ccons ::= NULL onconf */ yytestcase(yyruleno==296);
    ++      /* (297) conslist_opt ::= COMMA conslist */ yytestcase(yyruleno==297);
    ++      /* (298) conslist ::= conslist tconscomma tcons */ yytestcase(yyruleno==298);
    ++      /* (299) conslist ::= tcons (OPTIMIZED OUT) */ assert(yyruleno!=299);
    ++      /* (300) tconscomma ::= */ yytestcase(yyruleno==300);
    ++      /* (301) defer_subclause_opt ::= defer_subclause (OPTIMIZED OUT) */ assert(yyruleno!=301);
    ++      /* (302) resolvetype ::= raisetype (OPTIMIZED OUT) */ assert(yyruleno!=302);
    ++      /* (303) selectnowith ::= oneselect (OPTIMIZED OUT) */ assert(yyruleno!=303);
    ++      /* (304) oneselect ::= values */ yytestcase(yyruleno==304);
    ++      /* (305) sclp ::= selcollist COMMA */ yytestcase(yyruleno==305);
    ++      /* (306) as ::= ID|STRING */ yytestcase(yyruleno==306);
    ++      /* (307) expr ::= term (OPTIMIZED OUT) */ assert(yyruleno!=307);
    ++      /* (308) likeop ::= LIKE_KW|MATCH */ yytestcase(yyruleno==308);
    ++      /* (309) exprlist ::= nexprlist */ yytestcase(yyruleno==309);
    ++      /* (310) nmnum ::= plus_num (OPTIMIZED OUT) */ assert(yyruleno!=310);
    ++      /* (311) nmnum ::= nm (OPTIMIZED OUT) */ assert(yyruleno!=311);
    ++      /* (312) nmnum ::= ON */ yytestcase(yyruleno==312);
    ++      /* (313) nmnum ::= DELETE */ yytestcase(yyruleno==313);
    ++      /* (314) nmnum ::= DEFAULT */ yytestcase(yyruleno==314);
    ++      /* (315) plus_num ::= INTEGER|FLOAT */ yytestcase(yyruleno==315);
    ++      /* (316) foreach_clause ::= */ yytestcase(yyruleno==316);
    ++      /* (317) foreach_clause ::= FOR EACH ROW */ yytestcase(yyruleno==317);
    ++      /* (318) trnm ::= nm */ yytestcase(yyruleno==318);
    ++      /* (319) tridxby ::= */ yytestcase(yyruleno==319);
    ++      /* (320) database_kw_opt ::= DATABASE */ yytestcase(yyruleno==320);
    ++      /* (321) database_kw_opt ::= */ yytestcase(yyruleno==321);
    ++      /* (322) kwcolumn_opt ::= */ yytestcase(yyruleno==322);
    ++      /* (323) kwcolumn_opt ::= COLUMNKW */ yytestcase(yyruleno==323);
    ++      /* (324) vtabarglist ::= vtabarg */ yytestcase(yyruleno==324);
    ++      /* (325) vtabarglist ::= vtabarglist COMMA vtabarg */ yytestcase(yyruleno==325);
    ++      /* (326) vtabarg ::= vtabarg vtabargtoken */ yytestcase(yyruleno==326);
    ++      /* (327) anylist ::= */ yytestcase(yyruleno==327);
    ++      /* (328) anylist ::= anylist LP anylist RP */ yytestcase(yyruleno==328);
    ++      /* (329) anylist ::= anylist ANY */ yytestcase(yyruleno==329);
    +         break;
    ++/********** End reduce actions ************************************************/
    +   };
    +-  assert( yyruleno>=0 && yyruleno<sizeof(yyRuleInfo)/sizeof(yyRuleInfo[0]) );
    ++  assert( yyruleno<sizeof(yyRuleInfo)/sizeof(yyRuleInfo[0]) );
    +   yygoto = yyRuleInfo[yyruleno].lhs;
    +   yysize = yyRuleInfo[yyruleno].nrhs;
    +-  yypParser->yyidx -= yysize;
    +-  yyact = yy_find_reduce_action(yymsp[-yysize].stateno,(YYCODETYPE)yygoto);
    +-  if( yyact <= YY_MAX_SHIFTREDUCE ){
    +-    if( yyact>YY_MAX_SHIFT ) yyact += YY_MIN_REDUCE - YY_MIN_SHIFTREDUCE;
    +-    /* If the reduce action popped at least
    +-    ** one element off the stack, then we can push the new element back
    +-    ** onto the stack here, and skip the stack overflow test in yy_shift().
    +-    ** That gives a significant speed improvement. */
    +-    if( yysize ){
    +-      yypParser->yyidx++;
    +-      yymsp -= yysize-1;
    +-      yymsp->stateno = (YYACTIONTYPE)yyact;
    +-      yymsp->major = (YYCODETYPE)yygoto;
    +-      yymsp->minor = yygotominor;
    +-      yyTraceShift(yypParser, yyact);
    +-    }else{
    +-      yy_shift(yypParser,yyact,yygoto,&yygotominor);
    +-    }
    +-  }else{
    +-    assert( yyact == YY_ACCEPT_ACTION );
    +-    yy_accept(yypParser);
    +-  }
    ++  yyact = yy_find_reduce_action(yymsp[yysize].stateno,(YYCODETYPE)yygoto);
    ++
    ++  /* There are no SHIFTREDUCE actions on nonterminals because the table
    ++  ** generator has simplified them to pure REDUCE actions. */
    ++  assert( !(yyact>YY_MAX_SHIFT && yyact<=YY_MAX_SHIFTREDUCE) );
    ++
    ++  /* It is not possible for a REDUCE to be followed by an error */
    ++  assert( yyact!=YY_ERROR_ACTION );
    ++
    ++  yymsp += yysize+1;
    ++  yypParser->yytos = yymsp;
    ++  yymsp->stateno = (YYACTIONTYPE)yyact;
    ++  yymsp->major = (YYCODETYPE)yygoto;
    ++  yyTraceShift(yypParser, yyact, "... then shift");
    + }
    + 
    + /*
    +@@ -129405,9 +141813,11 @@ static void yy_parse_failed(
    +     fprintf(yyTraceFILE,"%sFail!\n",yyTracePrompt);
    +   }
    + #endif
    +-  while( yypParser->yyidx>=0 ) yy_pop_parser_stack(yypParser);
    ++  while( yypParser->yytos>yypParser->yystack ) yy_pop_parser_stack(yypParser);
    +   /* Here code is inserted which will be executed whenever the
    +   ** parser fails */
    ++/************ Begin %parse_failure code ***************************************/
    ++/************ End %parse_failure code *****************************************/
    +   sqlite3ParserARG_STORE; /* Suppress warning about unused %extra_argument variable */
    + }
    + #endif /* YYNOERRORRECOVERY */
    +@@ -129418,14 +141828,19 @@ static void yy_parse_failed(
    + static void yy_syntax_error(
    +   yyParser *yypParser,           /* The parser */
    +   int yymajor,                   /* The major type of the error token */
    +-  YYMINORTYPE yyminor            /* The minor type of the error token */
    ++  sqlite3ParserTOKENTYPE yyminor         /* The minor type of the error token */
    + ){
    +   sqlite3ParserARG_FETCH;
    +-#define TOKEN (yyminor.yy0)
    ++#define TOKEN yyminor
    ++/************ Begin %syntax_error code ****************************************/
    + 
    +   UNUSED_PARAMETER(yymajor);  /* Silence some compiler warnings */
    +-  assert( TOKEN.z[0] );  /* The tokenizer always gives us a token */
    +-  sqlite3ErrorMsg(pParse, "near \"%T\": syntax error", &TOKEN);
    ++  if( TOKEN.z[0] ){
    ++    sqlite3ErrorMsg(pParse, "near \"%T\": syntax error", &TOKEN);
    ++  }else{
    ++    sqlite3ErrorMsg(pParse, "incomplete input");
    ++  }
    ++/************ End %syntax_error code ******************************************/
    +   sqlite3ParserARG_STORE; /* Suppress warning about unused %extra_argument variable */
    + }
    + 
    +@@ -129441,9 +141856,14 @@ static void yy_accept(
    +     fprintf(yyTraceFILE,"%sAccept!\n",yyTracePrompt);
    +   }
    + #endif
    +-  while( yypParser->yyidx>=0 ) yy_pop_parser_stack(yypParser);
    ++#ifndef YYNOERRORRECOVERY
    ++  yypParser->yyerrcnt = -1;
    ++#endif
    ++  assert( yypParser->yytos==yypParser->yystack );
    +   /* Here code is inserted which will be executed whenever the
    +   ** parser accepts */
    ++/*********** Begin %parse_accept code *****************************************/
    ++/*********** End %parse_accept code *******************************************/
    +   sqlite3ParserARG_STORE; /* Suppress warning about unused %extra_argument variable */
    + }
    + 
    +@@ -129473,7 +141893,7 @@ SQLITE_PRIVATE void sqlite3Parser(
    +   sqlite3ParserARG_PDECL               /* Optional %extra_argument parameter */
    + ){
    +   YYMINORTYPE yyminorunion;
    +-  int yyact;            /* The parser action. */
    ++  unsigned int yyact;   /* The parser action. */
    + #if !defined(YYERRORSYMBOL) && !defined(YYNOERRORRECOVERY)
    +   int yyendofinput;     /* True if we are at the end of input */
    + #endif
    +@@ -129482,23 +141902,8 @@ SQLITE_PRIVATE void sqlite3Parser(
    + #endif
    +   yyParser *yypParser;  /* The parser */
    + 
    +-  /* (re)initialize the parser, if necessary */
    +   yypParser = (yyParser*)yyp;
    +-  if( yypParser->yyidx<0 ){
    +-#if YYSTACKDEPTH<=0
    +-    if( yypParser->yystksz <=0 ){
    +-      /*memset(&yyminorunion, 0, sizeof(yyminorunion));*/
    +-      yyminorunion = yyzerominor;
    +-      yyStackOverflow(yypParser, &yyminorunion);
    +-      return;
    +-    }
    +-#endif
    +-    yypParser->yyidx = 0;
    +-    yypParser->yyerrcnt = -1;
    +-    yypParser->yystack[0].stateno = 0;
    +-    yypParser->yystack[0].major = 0;
    +-  }
    +-  yyminorunion.yy0 = yyminor;
    ++  assert( yypParser->yytos!=0 );
    + #if !defined(YYERRORSYMBOL) && !defined(YYNOERRORRECOVERY)
    +   yyendofinput = (yymajor==0);
    + #endif
    +@@ -129506,21 +141911,34 @@ SQLITE_PRIVATE void sqlite3Parser(
    + 
    + #ifndef NDEBUG
    +   if( yyTraceFILE ){
    +-    fprintf(yyTraceFILE,"%sInput %s\n",yyTracePrompt,yyTokenName[yymajor]);
    ++    int stateno = yypParser->yytos->stateno;
    ++    if( stateno < YY_MIN_REDUCE ){
    ++      fprintf(yyTraceFILE,"%sInput '%s' in state %d\n",
    ++              yyTracePrompt,yyTokenName[yymajor],stateno);
    ++    }else{
    ++      fprintf(yyTraceFILE,"%sInput '%s' with pending reduce %d\n",
    ++              yyTracePrompt,yyTokenName[yymajor],stateno-YY_MIN_REDUCE);
    ++    }
    +   }
    + #endif
    + 
    +   do{
    +     yyact = yy_find_shift_action(yypParser,(YYCODETYPE)yymajor);
    +-    if( yyact <= YY_MAX_SHIFTREDUCE ){
    +-      if( yyact > YY_MAX_SHIFT ) yyact += YY_MIN_REDUCE - YY_MIN_SHIFTREDUCE;
    +-      yy_shift(yypParser,yyact,yymajor,&yyminorunion);
    ++    if( yyact >= YY_MIN_REDUCE ){
    ++      yy_reduce(yypParser,yyact-YY_MIN_REDUCE,yymajor,yyminor);
    ++    }else if( yyact <= YY_MAX_SHIFTREDUCE ){
    ++      yy_shift(yypParser,yyact,yymajor,yyminor);
    ++#ifndef YYNOERRORRECOVERY
    +       yypParser->yyerrcnt--;
    ++#endif
    +       yymajor = YYNOCODE;
    +-    }else if( yyact <= YY_MAX_REDUCE ){
    +-      yy_reduce(yypParser,yyact-YY_MIN_REDUCE);
    ++    }else if( yyact==YY_ACCEPT_ACTION ){
    ++      yypParser->yytos--;
    ++      yy_accept(yypParser);
    ++      return;
    +     }else{
    +       assert( yyact == YY_ERROR_ACTION );
    ++      yyminorunion.yy0 = yyminor;
    + #ifdef YYERRORSYMBOL
    +       int yymx;
    + #endif
    +@@ -129550,9 +141968,9 @@ SQLITE_PRIVATE void sqlite3Parser(
    +       **
    +       */
    +       if( yypParser->yyerrcnt<0 ){
    +-        yy_syntax_error(yypParser,yymajor,yyminorunion);
    ++        yy_syntax_error(yypParser,yymajor,yyminor);
    +       }
    +-      yymx = yypParser->yystack[yypParser->yyidx].major;
    ++      yymx = yypParser->yytos->major;
    +       if( yymx==YYERRORSYMBOL || yyerrorhit ){
    + #ifndef NDEBUG
    +         if( yyTraceFILE ){
    +@@ -129560,26 +141978,26 @@ SQLITE_PRIVATE void sqlite3Parser(
    +              yyTracePrompt,yyTokenName[yymajor]);
    +         }
    + #endif
    +-        yy_destructor(yypParser, (YYCODETYPE)yymajor,&yyminorunion);
    ++        yy_destructor(yypParser, (YYCODETYPE)yymajor, &yyminorunion);
    +         yymajor = YYNOCODE;
    +       }else{
    +-         while(
    +-          yypParser->yyidx >= 0 &&
    +-          yymx != YYERRORSYMBOL &&
    +-          (yyact = yy_find_reduce_action(
    +-                        yypParser->yystack[yypParser->yyidx].stateno,
    ++        while( yypParser->yytos >= yypParser->yystack
    ++            && yymx != YYERRORSYMBOL
    ++            && (yyact = yy_find_reduce_action(
    ++                        yypParser->yytos->stateno,
    +                         YYERRORSYMBOL)) >= YY_MIN_REDUCE
    +         ){
    +           yy_pop_parser_stack(yypParser);
    +         }
    +-        if( yypParser->yyidx < 0 || yymajor==0 ){
    ++        if( yypParser->yytos < yypParser->yystack || yymajor==0 ){
    +           yy_destructor(yypParser,(YYCODETYPE)yymajor,&yyminorunion);
    +           yy_parse_failed(yypParser);
    ++#ifndef YYNOERRORRECOVERY
    ++          yypParser->yyerrcnt = -1;
    ++#endif
    +           yymajor = YYNOCODE;
    +         }else if( yymx!=YYERRORSYMBOL ){
    +-          YYMINORTYPE u2;
    +-          u2.YYERRSYMDT = 0;
    +-          yy_shift(yypParser,yyact,YYERRORSYMBOL,&u2);
    ++          yy_shift(yypParser,yyact,YYERRORSYMBOL,yyminor);
    +         }
    +       }
    +       yypParser->yyerrcnt = 3;
    +@@ -129592,7 +142010,7 @@ SQLITE_PRIVATE void sqlite3Parser(
    +       ** Applications can set this macro (for example inside %include) if
    +       ** they intend to abandon the parse upon the first syntax error seen.
    +       */
    +-      yy_syntax_error(yypParser,yymajor,yyminorunion);
    ++      yy_syntax_error(yypParser,yymajor, yyminor);
    +       yy_destructor(yypParser,(YYCODETYPE)yymajor,&yyminorunion);
    +       yymajor = YYNOCODE;
    +       
    +@@ -129607,20 +142025,30 @@ SQLITE_PRIVATE void sqlite3Parser(
    +       ** three input tokens have been successfully shifted.
    +       */
    +       if( yypParser->yyerrcnt<=0 ){
    +-        yy_syntax_error(yypParser,yymajor,yyminorunion);
    ++        yy_syntax_error(yypParser,yymajor, yyminor);
    +       }
    +       yypParser->yyerrcnt = 3;
    +       yy_destructor(yypParser,(YYCODETYPE)yymajor,&yyminorunion);
    +       if( yyendofinput ){
    +         yy_parse_failed(yypParser);
    ++#ifndef YYNOERRORRECOVERY
    ++        yypParser->yyerrcnt = -1;
    ++#endif
    +       }
    +       yymajor = YYNOCODE;
    + #endif
    +     }
    +-  }while( yymajor!=YYNOCODE && yypParser->yyidx>=0 );
    ++  }while( yymajor!=YYNOCODE && yypParser->yytos>yypParser->yystack );
    + #ifndef NDEBUG
    +   if( yyTraceFILE ){
    +-    fprintf(yyTraceFILE,"%sReturn\n",yyTracePrompt);
    ++    yyStackEntry *i;
    ++    char cDiv = '[';
    ++    fprintf(yyTraceFILE,"%sReturn. Stack=",yyTracePrompt);
    ++    for(i=&yypParser->yystack[1]; i<=yypParser->yytos; i++){
    ++      fprintf(yyTraceFILE,"%c%s", cDiv, yyTokenName[i->major]);
    ++      cDiv = ' ';
    ++    }
    ++    fprintf(yyTraceFILE,"]\n");
    +   }
    + #endif
    +   return;
    +@@ -129648,12 +142076,92 @@ SQLITE_PRIVATE void sqlite3Parser(
    + /* #include "sqliteInt.h" */
    + /* #include <stdlib.h> */
    + 
    ++/* Character classes for tokenizing
    ++**
    ++** In the sqlite3GetToken() function, a switch() on aiClass[c] is implemented
    ++** using a lookup table, whereas a switch() directly on c uses a binary search.
    ++** The lookup table is much faster.  To maximize speed, and to ensure that
    ++** a lookup table is used, all of the classes need to be small integers and
    ++** all of them need to be used within the switch.
    ++*/
    ++#define CC_X          0    /* The letter 'x', or start of BLOB literal */
    ++#define CC_KYWD       1    /* Alphabetics or '_'.  Usable in a keyword */
    ++#define CC_ID         2    /* unicode characters usable in IDs */
    ++#define CC_DIGIT      3    /* Digits */
    ++#define CC_DOLLAR     4    /* '$' */
    ++#define CC_VARALPHA   5    /* '@', '#', ':'.  Alphabetic SQL variables */
    ++#define CC_VARNUM     6    /* '?'.  Numeric SQL variables */
    ++#define CC_SPACE      7    /* Space characters */
    ++#define CC_QUOTE      8    /* '"', '\'', or '`'.  String literals, quoted ids */
    ++#define CC_QUOTE2     9    /* '['.   [...] style quoted ids */
    ++#define CC_PIPE      10    /* '|'.   Bitwise OR or concatenate */
    ++#define CC_MINUS     11    /* '-'.  Minus or SQL-style comment */
    ++#define CC_LT        12    /* '<'.  Part of < or <= or <> */
    ++#define CC_GT        13    /* '>'.  Part of > or >= */
    ++#define CC_EQ        14    /* '='.  Part of = or == */
    ++#define CC_BANG      15    /* '!'.  Part of != */
    ++#define CC_SLASH     16    /* '/'.  / or c-style comment */
    ++#define CC_LP        17    /* '(' */
    ++#define CC_RP        18    /* ')' */
    ++#define CC_SEMI      19    /* ';' */
    ++#define CC_PLUS      20    /* '+' */
    ++#define CC_STAR      21    /* '*' */
    ++#define CC_PERCENT   22    /* '%' */
    ++#define CC_COMMA     23    /* ',' */
    ++#define CC_AND       24    /* '&' */
    ++#define CC_TILDA     25    /* '~' */
    ++#define CC_DOT       26    /* '.' */
    ++#define CC_ILLEGAL   27    /* Illegal character */
    ++
    ++static const unsigned char aiClass[] = {
    ++#ifdef SQLITE_ASCII
    ++/*         x0  x1  x2  x3  x4  x5  x6  x7  x8  x9  xa  xb  xc  xd  xe  xf */
    ++/* 0x */   27, 27, 27, 27, 27, 27, 27, 27, 27,  7,  7, 27,  7,  7, 27, 27,
    ++/* 1x */   27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27,
    ++/* 2x */    7, 15,  8,  5,  4, 22, 24,  8, 17, 18, 21, 20, 23, 11, 26, 16,
    ++/* 3x */    3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  5, 19, 12, 14, 13,  6,
    ++/* 4x */    5,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,
    ++/* 5x */    1,  1,  1,  1,  1,  1,  1,  1,  0,  1,  1,  9, 27, 27, 27,  1,
    ++/* 6x */    8,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,
    ++/* 7x */    1,  1,  1,  1,  1,  1,  1,  1,  0,  1,  1, 27, 10, 27, 25, 27,
    ++/* 8x */    2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,
    ++/* 9x */    2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,
    ++/* Ax */    2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,
    ++/* Bx */    2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,
    ++/* Cx */    2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,
    ++/* Dx */    2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,
    ++/* Ex */    2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,
    ++/* Fx */    2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2
    ++#endif
    ++#ifdef SQLITE_EBCDIC
    ++/*         x0  x1  x2  x3  x4  x5  x6  x7  x8  x9  xa  xb  xc  xd  xe  xf */
    ++/* 0x */   27, 27, 27, 27, 27,  7, 27, 27, 27, 27, 27, 27,  7,  7, 27, 27,
    ++/* 1x */   27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27,
    ++/* 2x */   27, 27, 27, 27, 27,  7, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27,
    ++/* 3x */   27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27,
    ++/* 4x */    7, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 26, 12, 17, 20, 10,
    ++/* 5x */   24, 27, 27, 27, 27, 27, 27, 27, 27, 27, 15,  4, 21, 18, 19, 27,
    ++/* 6x */   11, 16, 27, 27, 27, 27, 27, 27, 27, 27, 27, 23, 22,  1, 13,  6,
    ++/* 7x */   27, 27, 27, 27, 27, 27, 27, 27, 27,  8,  5,  5,  5,  8, 14,  8,
    ++/* 8x */   27,  1,  1,  1,  1,  1,  1,  1,  1,  1, 27, 27, 27, 27, 27, 27,
    ++/* 9x */   27,  1,  1,  1,  1,  1,  1,  1,  1,  1, 27, 27, 27, 27, 27, 27,
    ++/* Ax */   27, 25,  1,  1,  1,  1,  1,  0,  1,  1, 27, 27, 27, 27, 27, 27,
    ++/* Bx */   27, 27, 27, 27, 27, 27, 27, 27, 27, 27,  9, 27, 27, 27, 27, 27,
    ++/* Cx */   27,  1,  1,  1,  1,  1,  1,  1,  1,  1, 27, 27, 27, 27, 27, 27,
    ++/* Dx */   27,  1,  1,  1,  1,  1,  1,  1,  1,  1, 27, 27, 27, 27, 27, 27,
    ++/* Ex */   27, 27,  1,  1,  1,  1,  1,  0,  1,  1, 27, 27, 27, 27, 27, 27,
    ++/* Fx */    3,  3,  3,  3,  3,  3,  3,  3,  3,  3, 27, 27, 27, 27, 27, 27,
    ++#endif
    ++};
    ++
    + /*
    +-** The charMap() macro maps alphabetic characters into their
    ++** The charMap() macro maps alphabetic characters (only) into their
    + ** lower-case ASCII equivalent.  On ASCII machines, this is just
    + ** an upper-to-lower case map.  On EBCDIC machines we also need
    +-** to adjust the encoding.  Only alphabetic characters and underscores
    +-** need to be translated.
    ++** to adjust the encoding.  The mapping is only valid for alphabetics
    ++** which are the only characters for which this feature is used. 
    ++**
    ++** Used by keywordhash.h
    + */
    + #ifdef SQLITE_ASCII
    + # define charMap(X) sqlite3UpperToLower[(unsigned char)X]
    +@@ -129687,7 +142195,7 @@ const unsigned char ebcdicToAscii[] = {
    + ** returned.  If the input is not a keyword, TK_ID is returned.
    + **
    + ** The implementation of this routine was generated by a program,
    +-** mkkeywordhash.h, located in the tool subdirectory of the distribution.
    ++** mkkeywordhash.c, located in the tool subdirectory of the distribution.
    + ** The output of the mkkeywordhash.c program is written into a file
    + ** named keywordhash.h and then included into this source file by
    + ** the #include below.
    +@@ -129708,133 +142216,152 @@ const unsigned char ebcdicToAscii[] = {
    + ** on platforms with limited memory.
    + */
    + /* Hash score: 182 */
    +-static int keywordCode(const char *z, int n){
    +-  /* zText[] encodes 834 bytes of keywords in 554 bytes */
    +-  /*   REINDEXEDESCAPEACHECKEYBEFOREIGNOREGEXPLAINSTEADDATABASELECT       */
    +-  /*   ABLEFTHENDEFERRABLELSEXCEPTRANSACTIONATURALTERAISEXCLUSIVE         */
    +-  /*   XISTSAVEPOINTERSECTRIGGEREFERENCESCONSTRAINTOFFSETEMPORARY         */
    +-  /*   UNIQUERYWITHOUTERELEASEATTACHAVINGROUPDATEBEGINNERECURSIVE         */
    +-  /*   BETWEENOTNULLIKECASCADELETECASECOLLATECREATECURRENT_DATEDETACH     */
    +-  /*   IMMEDIATEJOINSERTMATCHPLANALYZEPRAGMABORTVALUESVIRTUALIMITWHEN     */
    +-  /*   WHERENAMEAFTEREPLACEANDEFAULTAUTOINCREMENTCASTCOLUMNCOMMIT         */
    +-  /*   CONFLICTCROSSCURRENT_TIMESTAMPRIMARYDEFERREDISTINCTDROPFAIL        */
    +-  /*   FROMFULLGLOBYIFISNULLORDERESTRICTRIGHTROLLBACKROWUNIONUSING        */
    +-  /*   VACUUMVIEWINITIALLY                                                */
    +-  static const char zText[553] = {
    +-    'R','E','I','N','D','E','X','E','D','E','S','C','A','P','E','A','C','H',
    +-    'E','C','K','E','Y','B','E','F','O','R','E','I','G','N','O','R','E','G',
    +-    'E','X','P','L','A','I','N','S','T','E','A','D','D','A','T','A','B','A',
    +-    'S','E','L','E','C','T','A','B','L','E','F','T','H','E','N','D','E','F',
    +-    'E','R','R','A','B','L','E','L','S','E','X','C','E','P','T','R','A','N',
    +-    'S','A','C','T','I','O','N','A','T','U','R','A','L','T','E','R','A','I',
    +-    'S','E','X','C','L','U','S','I','V','E','X','I','S','T','S','A','V','E',
    +-    'P','O','I','N','T','E','R','S','E','C','T','R','I','G','G','E','R','E',
    +-    'F','E','R','E','N','C','E','S','C','O','N','S','T','R','A','I','N','T',
    +-    'O','F','F','S','E','T','E','M','P','O','R','A','R','Y','U','N','I','Q',
    +-    'U','E','R','Y','W','I','T','H','O','U','T','E','R','E','L','E','A','S',
    +-    'E','A','T','T','A','C','H','A','V','I','N','G','R','O','U','P','D','A',
    +-    'T','E','B','E','G','I','N','N','E','R','E','C','U','R','S','I','V','E',
    +-    'B','E','T','W','E','E','N','O','T','N','U','L','L','I','K','E','C','A',
    +-    'S','C','A','D','E','L','E','T','E','C','A','S','E','C','O','L','L','A',
    +-    'T','E','C','R','E','A','T','E','C','U','R','R','E','N','T','_','D','A',
    +-    'T','E','D','E','T','A','C','H','I','M','M','E','D','I','A','T','E','J',
    +-    'O','I','N','S','E','R','T','M','A','T','C','H','P','L','A','N','A','L',
    +-    'Y','Z','E','P','R','A','G','M','A','B','O','R','T','V','A','L','U','E',
    +-    'S','V','I','R','T','U','A','L','I','M','I','T','W','H','E','N','W','H',
    +-    'E','R','E','N','A','M','E','A','F','T','E','R','E','P','L','A','C','E',
    +-    'A','N','D','E','F','A','U','L','T','A','U','T','O','I','N','C','R','E',
    +-    'M','E','N','T','C','A','S','T','C','O','L','U','M','N','C','O','M','M',
    +-    'I','T','C','O','N','F','L','I','C','T','C','R','O','S','S','C','U','R',
    +-    'R','E','N','T','_','T','I','M','E','S','T','A','M','P','R','I','M','A',
    +-    'R','Y','D','E','F','E','R','R','E','D','I','S','T','I','N','C','T','D',
    +-    'R','O','P','F','A','I','L','F','R','O','M','F','U','L','L','G','L','O',
    +-    'B','Y','I','F','I','S','N','U','L','L','O','R','D','E','R','E','S','T',
    +-    'R','I','C','T','R','I','G','H','T','R','O','L','L','B','A','C','K','R',
    +-    'O','W','U','N','I','O','N','U','S','I','N','G','V','A','C','U','U','M',
    +-    'V','I','E','W','I','N','I','T','I','A','L','L','Y',
    +-  };
    +-  static const unsigned char aHash[127] = {
    +-      76, 105, 117,  74,   0,  45,   0,   0,  82,   0,  77,   0,   0,
    +-      42,  12,  78,  15,   0, 116,  85,  54, 112,   0,  19,   0,   0,
    +-     121,   0, 119, 115,   0,  22,  93,   0,   9,   0,   0,  70,  71,
    +-       0,  69,   6,   0,  48,  90, 102,   0, 118, 101,   0,   0,  44,
    +-       0, 103,  24,   0,  17,   0, 122,  53,  23,   0,   5, 110,  25,
    +-      96,   0,   0, 124, 106,  60, 123,  57,  28,  55,   0,  91,   0,
    +-     100,  26,   0,  99,   0,   0,   0,  95,  92,  97,  88, 109,  14,
    +-      39, 108,   0,  81,   0,  18,  89, 111,  32,   0, 120,  80, 113,
    +-      62,  46,  84,   0,   0,  94,  40,  59, 114,   0,  36,   0,   0,
    +-      29,   0,  86,  63,  64,   0,  20,  61,   0,  56,
    +-  };
    +-  static const unsigned char aNext[124] = {
    +-       0,   0,   0,   0,   4,   0,   0,   0,   0,   0,   0,   0,   0,
    +-       0,   2,   0,   0,   0,   0,   0,   0,  13,   0,   0,   0,   0,
    +-       0,   7,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
    +-       0,   0,   0,   0,  33,   0,  21,   0,   0,   0,   0,   0,  50,
    +-       0,  43,   3,  47,   0,   0,   0,   0,  30,   0,  58,   0,  38,
    +-       0,   0,   0,   1,  66,   0,   0,  67,   0,  41,   0,   0,   0,
    +-       0,   0,   0,  49,  65,   0,   0,   0,   0,  31,  52,  16,  34,
    +-      10,   0,   0,   0,   0,   0,   0,   0,  11,  72,  79,   0,   8,
    +-       0, 104,  98,   0, 107,   0,  87,   0,  75,  51,   0,  27,  37,
    +-      73,  83,   0,  35,  68,   0,   0,
    +-  };
    +-  static const unsigned char aLen[124] = {
    +-       7,   7,   5,   4,   6,   4,   5,   3,   6,   7,   3,   6,   6,
    +-       7,   7,   3,   8,   2,   6,   5,   4,   4,   3,  10,   4,   6,
    +-      11,   6,   2,   7,   5,   5,   9,   6,   9,   9,   7,  10,  10,
    +-       4,   6,   2,   3,   9,   4,   2,   6,   5,   7,   4,   5,   7,
    +-       6,   6,   5,   6,   5,   5,   9,   7,   7,   3,   2,   4,   4,
    +-       7,   3,   6,   4,   7,   6,  12,   6,   9,   4,   6,   5,   4,
    +-       7,   6,   5,   6,   7,   5,   4,   5,   6,   5,   7,   3,   7,
    +-      13,   2,   2,   4,   6,   6,   8,   5,  17,  12,   7,   8,   8,
    +-       2,   4,   4,   4,   4,   4,   2,   2,   6,   5,   8,   5,   8,
    +-       3,   5,   5,   6,   4,   9,   3,
    +-  };
    +-  static const unsigned short int aOffset[124] = {
    +-       0,   2,   2,   8,   9,  14,  16,  20,  23,  25,  25,  29,  33,
    +-      36,  41,  46,  48,  53,  54,  59,  62,  65,  67,  69,  78,  81,
    +-      86,  91,  95,  96, 101, 105, 109, 117, 122, 128, 136, 142, 152,
    +-     159, 162, 162, 165, 167, 167, 171, 176, 179, 184, 184, 188, 192,
    +-     199, 204, 209, 212, 218, 221, 225, 234, 240, 240, 240, 243, 246,
    +-     250, 251, 255, 261, 265, 272, 278, 290, 296, 305, 307, 313, 318,
    +-     320, 327, 332, 337, 343, 349, 354, 358, 361, 367, 371, 378, 380,
    +-     387, 389, 391, 400, 404, 410, 416, 424, 429, 429, 445, 452, 459,
    +-     460, 467, 471, 475, 479, 483, 486, 488, 490, 496, 500, 508, 513,
    +-     521, 524, 529, 534, 540, 544, 549,
    +-  };
    +-  static const unsigned char aCode[124] = {
    +-    TK_REINDEX,    TK_INDEXED,    TK_INDEX,      TK_DESC,       TK_ESCAPE,     
    +-    TK_EACH,       TK_CHECK,      TK_KEY,        TK_BEFORE,     TK_FOREIGN,    
    +-    TK_FOR,        TK_IGNORE,     TK_LIKE_KW,    TK_EXPLAIN,    TK_INSTEAD,    
    +-    TK_ADD,        TK_DATABASE,   TK_AS,         TK_SELECT,     TK_TABLE,      
    +-    TK_JOIN_KW,    TK_THEN,       TK_END,        TK_DEFERRABLE, TK_ELSE,       
    +-    TK_EXCEPT,     TK_TRANSACTION,TK_ACTION,     TK_ON,         TK_JOIN_KW,    
    +-    TK_ALTER,      TK_RAISE,      TK_EXCLUSIVE,  TK_EXISTS,     TK_SAVEPOINT,  
    +-    TK_INTERSECT,  TK_TRIGGER,    TK_REFERENCES, TK_CONSTRAINT, TK_INTO,       
    +-    TK_OFFSET,     TK_OF,         TK_SET,        TK_TEMP,       TK_TEMP,       
    +-    TK_OR,         TK_UNIQUE,     TK_QUERY,      TK_WITHOUT,    TK_WITH,       
    +-    TK_JOIN_KW,    TK_RELEASE,    TK_ATTACH,     TK_HAVING,     TK_GROUP,      
    +-    TK_UPDATE,     TK_BEGIN,      TK_JOIN_KW,    TK_RECURSIVE,  TK_BETWEEN,    
    +-    TK_NOTNULL,    TK_NOT,        TK_NO,         TK_NULL,       TK_LIKE_KW,    
    +-    TK_CASCADE,    TK_ASC,        TK_DELETE,     TK_CASE,       TK_COLLATE,    
    +-    TK_CREATE,     TK_CTIME_KW,   TK_DETACH,     TK_IMMEDIATE,  TK_JOIN,       
    +-    TK_INSERT,     TK_MATCH,      TK_PLAN,       TK_ANALYZE,    TK_PRAGMA,     
    +-    TK_ABORT,      TK_VALUES,     TK_VIRTUAL,    TK_LIMIT,      TK_WHEN,       
    +-    TK_WHERE,      TK_RENAME,     TK_AFTER,      TK_REPLACE,    TK_AND,        
    +-    TK_DEFAULT,    TK_AUTOINCR,   TK_TO,         TK_IN,         TK_CAST,       
    +-    TK_COLUMNKW,   TK_COMMIT,     TK_CONFLICT,   TK_JOIN_KW,    TK_CTIME_KW,   
    +-    TK_CTIME_KW,   TK_PRIMARY,    TK_DEFERRED,   TK_DISTINCT,   TK_IS,         
    +-    TK_DROP,       TK_FAIL,       TK_FROM,       TK_JOIN_KW,    TK_LIKE_KW,    
    +-    TK_BY,         TK_IF,         TK_ISNULL,     TK_ORDER,      TK_RESTRICT,   
    +-    TK_JOIN_KW,    TK_ROLLBACK,   TK_ROW,        TK_UNION,      TK_USING,      
    +-    TK_VACUUM,     TK_VIEW,       TK_INITIALLY,  TK_ALL,        
    +-  };
    +-  int h, i;
    +-  if( n<2 ) return TK_ID;
    +-  h = ((charMap(z[0])*4) ^
    +-      (charMap(z[n-1])*3) ^
    +-      n) % 127;
    +-  for(i=((int)aHash[h])-1; i>=0; i=((int)aNext[i])-1){
    +-    if( aLen[i]==n && sqlite3StrNICmp(&zText[aOffset[i]],z,n)==0 ){
    ++/* zKWText[] encodes 834 bytes of keyword text in 554 bytes */
    ++/*   REINDEXEDESCAPEACHECKEYBEFOREIGNOREGEXPLAINSTEADDATABASELECT       */
    ++/*   ABLEFTHENDEFERRABLELSEXCEPTRANSACTIONATURALTERAISEXCLUSIVE         */
    ++/*   XISTSAVEPOINTERSECTRIGGEREFERENCESCONSTRAINTOFFSETEMPORARY         */
    ++/*   UNIQUERYWITHOUTERELEASEATTACHAVINGROUPDATEBEGINNERECURSIVE         */
    ++/*   BETWEENOTNULLIKECASCADELETECASECOLLATECREATECURRENT_DATEDETACH     */
    ++/*   IMMEDIATEJOINSERTMATCHPLANALYZEPRAGMABORTVALUESVIRTUALIMITWHEN     */
    ++/*   WHERENAMEAFTEREPLACEANDEFAULTAUTOINCREMENTCASTCOLUMNCOMMIT         */
    ++/*   CONFLICTCROSSCURRENT_TIMESTAMPRIMARYDEFERREDISTINCTDROPFAIL        */
    ++/*   FROMFULLGLOBYIFISNULLORDERESTRICTRIGHTROLLBACKROWUNIONUSING        */
    ++/*   VACUUMVIEWINITIALLY                                                */
    ++static const char zKWText[553] = {
    ++  'R','E','I','N','D','E','X','E','D','E','S','C','A','P','E','A','C','H',
    ++  'E','C','K','E','Y','B','E','F','O','R','E','I','G','N','O','R','E','G',
    ++  'E','X','P','L','A','I','N','S','T','E','A','D','D','A','T','A','B','A',
    ++  'S','E','L','E','C','T','A','B','L','E','F','T','H','E','N','D','E','F',
    ++  'E','R','R','A','B','L','E','L','S','E','X','C','E','P','T','R','A','N',
    ++  'S','A','C','T','I','O','N','A','T','U','R','A','L','T','E','R','A','I',
    ++  'S','E','X','C','L','U','S','I','V','E','X','I','S','T','S','A','V','E',
    ++  'P','O','I','N','T','E','R','S','E','C','T','R','I','G','G','E','R','E',
    ++  'F','E','R','E','N','C','E','S','C','O','N','S','T','R','A','I','N','T',
    ++  'O','F','F','S','E','T','E','M','P','O','R','A','R','Y','U','N','I','Q',
    ++  'U','E','R','Y','W','I','T','H','O','U','T','E','R','E','L','E','A','S',
    ++  'E','A','T','T','A','C','H','A','V','I','N','G','R','O','U','P','D','A',
    ++  'T','E','B','E','G','I','N','N','E','R','E','C','U','R','S','I','V','E',
    ++  'B','E','T','W','E','E','N','O','T','N','U','L','L','I','K','E','C','A',
    ++  'S','C','A','D','E','L','E','T','E','C','A','S','E','C','O','L','L','A',
    ++  'T','E','C','R','E','A','T','E','C','U','R','R','E','N','T','_','D','A',
    ++  'T','E','D','E','T','A','C','H','I','M','M','E','D','I','A','T','E','J',
    ++  'O','I','N','S','E','R','T','M','A','T','C','H','P','L','A','N','A','L',
    ++  'Y','Z','E','P','R','A','G','M','A','B','O','R','T','V','A','L','U','E',
    ++  'S','V','I','R','T','U','A','L','I','M','I','T','W','H','E','N','W','H',
    ++  'E','R','E','N','A','M','E','A','F','T','E','R','E','P','L','A','C','E',
    ++  'A','N','D','E','F','A','U','L','T','A','U','T','O','I','N','C','R','E',
    ++  'M','E','N','T','C','A','S','T','C','O','L','U','M','N','C','O','M','M',
    ++  'I','T','C','O','N','F','L','I','C','T','C','R','O','S','S','C','U','R',
    ++  'R','E','N','T','_','T','I','M','E','S','T','A','M','P','R','I','M','A',
    ++  'R','Y','D','E','F','E','R','R','E','D','I','S','T','I','N','C','T','D',
    ++  'R','O','P','F','A','I','L','F','R','O','M','F','U','L','L','G','L','O',
    ++  'B','Y','I','F','I','S','N','U','L','L','O','R','D','E','R','E','S','T',
    ++  'R','I','C','T','R','I','G','H','T','R','O','L','L','B','A','C','K','R',
    ++  'O','W','U','N','I','O','N','U','S','I','N','G','V','A','C','U','U','M',
    ++  'V','I','E','W','I','N','I','T','I','A','L','L','Y',
    ++};
    ++/* aKWHash[i] is the hash value for the i-th keyword */
    ++static const unsigned char aKWHash[127] = {
    ++    76, 105, 117,  74,   0,  45,   0,   0,  82,   0,  77,   0,   0,
    ++    42,  12,  78,  15,   0, 116,  85,  54, 112,   0,  19,   0,   0,
    ++   121,   0, 119, 115,   0,  22,  93,   0,   9,   0,   0,  70,  71,
    ++     0,  69,   6,   0,  48,  90, 102,   0, 118, 101,   0,   0,  44,
    ++     0, 103,  24,   0,  17,   0, 122,  53,  23,   0,   5, 110,  25,
    ++    96,   0,   0, 124, 106,  60, 123,  57,  28,  55,   0,  91,   0,
    ++   100,  26,   0,  99,   0,   0,   0,  95,  92,  97,  88, 109,  14,
    ++    39, 108,   0,  81,   0,  18,  89, 111,  32,   0, 120,  80, 113,
    ++    62,  46,  84,   0,   0,  94,  40,  59, 114,   0,  36,   0,   0,
    ++    29,   0,  86,  63,  64,   0,  20,  61,   0,  56,
    ++};
    ++/* aKWNext[] forms the hash collision chain.  If aKWHash[i]==0
    ++** then the i-th keyword has no more hash collisions.  Otherwise,
    ++** the next keyword with the same hash is aKWHash[i]-1. */
    ++static const unsigned char aKWNext[124] = {
    ++     0,   0,   0,   0,   4,   0,   0,   0,   0,   0,   0,   0,   0,
    ++     0,   2,   0,   0,   0,   0,   0,   0,  13,   0,   0,   0,   0,
    ++     0,   7,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
    ++     0,   0,   0,   0,  33,   0,  21,   0,   0,   0,   0,   0,  50,
    ++     0,  43,   3,  47,   0,   0,   0,   0,  30,   0,  58,   0,  38,
    ++     0,   0,   0,   1,  66,   0,   0,  67,   0,  41,   0,   0,   0,
    ++     0,   0,   0,  49,  65,   0,   0,   0,   0,  31,  52,  16,  34,
    ++    10,   0,   0,   0,   0,   0,   0,   0,  11,  72,  79,   0,   8,
    ++     0, 104,  98,   0, 107,   0,  87,   0,  75,  51,   0,  27,  37,
    ++    73,  83,   0,  35,  68,   0,   0,
    ++};
    ++/* aKWLen[i] is the length (in bytes) of the i-th keyword */
    ++static const unsigned char aKWLen[124] = {
    ++     7,   7,   5,   4,   6,   4,   5,   3,   6,   7,   3,   6,   6,
    ++     7,   7,   3,   8,   2,   6,   5,   4,   4,   3,  10,   4,   6,
    ++    11,   6,   2,   7,   5,   5,   9,   6,   9,   9,   7,  10,  10,
    ++     4,   6,   2,   3,   9,   4,   2,   6,   5,   7,   4,   5,   7,
    ++     6,   6,   5,   6,   5,   5,   9,   7,   7,   3,   2,   4,   4,
    ++     7,   3,   6,   4,   7,   6,  12,   6,   9,   4,   6,   5,   4,
    ++     7,   6,   5,   6,   7,   5,   4,   5,   6,   5,   7,   3,   7,
    ++    13,   2,   2,   4,   6,   6,   8,   5,  17,  12,   7,   8,   8,
    ++     2,   4,   4,   4,   4,   4,   2,   2,   6,   5,   8,   5,   8,
    ++     3,   5,   5,   6,   4,   9,   3,
    ++};
    ++/* aKWOffset[i] is the index into zKWText[] of the start of
    ++** the text for the i-th keyword. */
    ++static const unsigned short int aKWOffset[124] = {
    ++     0,   2,   2,   8,   9,  14,  16,  20,  23,  25,  25,  29,  33,
    ++    36,  41,  46,  48,  53,  54,  59,  62,  65,  67,  69,  78,  81,
    ++    86,  91,  95,  96, 101, 105, 109, 117, 122, 128, 136, 142, 152,
    ++   159, 162, 162, 165, 167, 167, 171, 176, 179, 184, 184, 188, 192,
    ++   199, 204, 209, 212, 218, 221, 225, 234, 240, 240, 240, 243, 246,
    ++   250, 251, 255, 261, 265, 272, 278, 290, 296, 305, 307, 313, 318,
    ++   320, 327, 332, 337, 343, 349, 354, 358, 361, 367, 371, 378, 380,
    ++   387, 389, 391, 400, 404, 410, 416, 424, 429, 429, 445, 452, 459,
    ++   460, 467, 471, 475, 479, 483, 486, 488, 490, 496, 500, 508, 513,
    ++   521, 524, 529, 534, 540, 544, 549,
    ++};
    ++/* aKWCode[i] is the parser symbol code for the i-th keyword */
    ++static const unsigned char aKWCode[124] = {
    ++  TK_REINDEX,    TK_INDEXED,    TK_INDEX,      TK_DESC,       TK_ESCAPE,     
    ++  TK_EACH,       TK_CHECK,      TK_KEY,        TK_BEFORE,     TK_FOREIGN,    
    ++  TK_FOR,        TK_IGNORE,     TK_LIKE_KW,    TK_EXPLAIN,    TK_INSTEAD,    
    ++  TK_ADD,        TK_DATABASE,   TK_AS,         TK_SELECT,     TK_TABLE,      
    ++  TK_JOIN_KW,    TK_THEN,       TK_END,        TK_DEFERRABLE, TK_ELSE,       
    ++  TK_EXCEPT,     TK_TRANSACTION,TK_ACTION,     TK_ON,         TK_JOIN_KW,    
    ++  TK_ALTER,      TK_RAISE,      TK_EXCLUSIVE,  TK_EXISTS,     TK_SAVEPOINT,  
    ++  TK_INTERSECT,  TK_TRIGGER,    TK_REFERENCES, TK_CONSTRAINT, TK_INTO,       
    ++  TK_OFFSET,     TK_OF,         TK_SET,        TK_TEMP,       TK_TEMP,       
    ++  TK_OR,         TK_UNIQUE,     TK_QUERY,      TK_WITHOUT,    TK_WITH,       
    ++  TK_JOIN_KW,    TK_RELEASE,    TK_ATTACH,     TK_HAVING,     TK_GROUP,      
    ++  TK_UPDATE,     TK_BEGIN,      TK_JOIN_KW,    TK_RECURSIVE,  TK_BETWEEN,    
    ++  TK_NOTNULL,    TK_NOT,        TK_NO,         TK_NULL,       TK_LIKE_KW,    
    ++  TK_CASCADE,    TK_ASC,        TK_DELETE,     TK_CASE,       TK_COLLATE,    
    ++  TK_CREATE,     TK_CTIME_KW,   TK_DETACH,     TK_IMMEDIATE,  TK_JOIN,       
    ++  TK_INSERT,     TK_MATCH,      TK_PLAN,       TK_ANALYZE,    TK_PRAGMA,     
    ++  TK_ABORT,      TK_VALUES,     TK_VIRTUAL,    TK_LIMIT,      TK_WHEN,       
    ++  TK_WHERE,      TK_RENAME,     TK_AFTER,      TK_REPLACE,    TK_AND,        
    ++  TK_DEFAULT,    TK_AUTOINCR,   TK_TO,         TK_IN,         TK_CAST,       
    ++  TK_COLUMNKW,   TK_COMMIT,     TK_CONFLICT,   TK_JOIN_KW,    TK_CTIME_KW,   
    ++  TK_CTIME_KW,   TK_PRIMARY,    TK_DEFERRED,   TK_DISTINCT,   TK_IS,         
    ++  TK_DROP,       TK_FAIL,       TK_FROM,       TK_JOIN_KW,    TK_LIKE_KW,    
    ++  TK_BY,         TK_IF,         TK_ISNULL,     TK_ORDER,      TK_RESTRICT,   
    ++  TK_JOIN_KW,    TK_ROLLBACK,   TK_ROW,        TK_UNION,      TK_USING,      
    ++  TK_VACUUM,     TK_VIEW,       TK_INITIALLY,  TK_ALL,        
    ++};
    ++/* Check to see if z[0..n-1] is a keyword. If it is, write the
    ++** parser symbol code for that keyword into *pType.  Always
    ++** return the integer n (the length of the token). */
    ++static int keywordCode(const char *z, int n, int *pType){
    ++  int i, j;
    ++  const char *zKW;
    ++  if( n>=2 ){
    ++    i = ((charMap(z[0])*4) ^ (charMap(z[n-1])*3) ^ n) % 127;
    ++    for(i=((int)aKWHash[i])-1; i>=0; i=((int)aKWNext[i])-1){
    ++      if( aKWLen[i]!=n ) continue;
    ++      j = 0;
    ++      zKW = &zKWText[aKWOffset[i]];
    ++#ifdef SQLITE_ASCII
    ++      while( j<n && (z[j]&~0x20)==zKW[j] ){ j++; }
    ++#endif
    ++#ifdef SQLITE_EBCDIC
    ++      while( j<n && toupper(z[j])==zKW[j] ){ j++; }
    ++#endif
    ++      if( j<n ) continue;
    +       testcase( i==0 ); /* REINDEX */
    +       testcase( i==1 ); /* INDEXED */
    +       testcase( i==2 ); /* INDEX */
    +@@ -129959,13 +142486,16 @@ static int keywordCode(const char *z, int n){
    +       testcase( i==121 ); /* VIEW */
    +       testcase( i==122 ); /* INITIALLY */
    +       testcase( i==123 ); /* ALL */
    +-      return aCode[i];
    ++      *pType = aKWCode[i];
    ++      break;
    +     }
    +   }
    +-  return TK_ID;
    ++  return n;
    + }
    + SQLITE_PRIVATE int sqlite3KeywordCode(const unsigned char *z, int n){
    +-  return keywordCode((char*)z, n);
    ++  int id = TK_ID;
    ++  keywordCode((char*)z, n, &id);
    ++  return id;
    + }
    + #define SQLITE_N_KEYWORD 124
    + 
    +@@ -130018,13 +142548,15 @@ SQLITE_PRIVATE int sqlite3IsIdChar(u8 c){ return IdChar(c); }
    + 
    + 
    + /*
    +-** Return the length of the token that begins at z[0]. 
    ++** Return the length (in bytes) of the token that begins at z[0]. 
    + ** Store the token type in *tokenType before returning.
    + */
    + SQLITE_PRIVATE int sqlite3GetToken(const unsigned char *z, int *tokenType){
    +   int i, c;
    +-  switch( *z ){
    +-    case ' ': case '\t': case '\n': case '\f': case '\r': {
    ++  switch( aiClass[*z] ){  /* Switch on the character-class of the first byte
    ++                          ** of the token. See the comment on the CC_ defines
    ++                          ** above. */
    ++    case CC_SPACE: {
    +       testcase( z[0]==' ' );
    +       testcase( z[0]=='\t' );
    +       testcase( z[0]=='\n' );
    +@@ -130034,7 +142566,7 @@ SQLITE_PRIVATE int sqlite3GetToken(const unsigned char *z, int *tokenType){
    +       *tokenType = TK_SPACE;
    +       return i;
    +     }
    +-    case '-': {
    ++    case CC_MINUS: {
    +       if( z[1]=='-' ){
    +         for(i=2; (c=z[i])!=0 && c!='\n'; i++){}
    +         *tokenType = TK_SPACE;   /* IMP: R-22934-25134 */
    +@@ -130043,27 +142575,27 @@ SQLITE_PRIVATE int sqlite3GetToken(const unsigned char *z, int *tokenType){
    +       *tokenType = TK_MINUS;
    +       return 1;
    +     }
    +-    case '(': {
    ++    case CC_LP: {
    +       *tokenType = TK_LP;
    +       return 1;
    +     }
    +-    case ')': {
    ++    case CC_RP: {
    +       *tokenType = TK_RP;
    +       return 1;
    +     }
    +-    case ';': {
    ++    case CC_SEMI: {
    +       *tokenType = TK_SEMI;
    +       return 1;
    +     }
    +-    case '+': {
    ++    case CC_PLUS: {
    +       *tokenType = TK_PLUS;
    +       return 1;
    +     }
    +-    case '*': {
    ++    case CC_STAR: {
    +       *tokenType = TK_STAR;
    +       return 1;
    +     }
    +-    case '/': {
    ++    case CC_SLASH: {
    +       if( z[1]!='*' || z[2]==0 ){
    +         *tokenType = TK_SLASH;
    +         return 1;
    +@@ -130073,15 +142605,15 @@ SQLITE_PRIVATE int sqlite3GetToken(const unsigned char *z, int *tokenType){
    +       *tokenType = TK_SPACE;   /* IMP: R-22934-25134 */
    +       return i;
    +     }
    +-    case '%': {
    ++    case CC_PERCENT: {
    +       *tokenType = TK_REM;
    +       return 1;
    +     }
    +-    case '=': {
    ++    case CC_EQ: {
    +       *tokenType = TK_EQ;
    +       return 1 + (z[1]=='=');
    +     }
    +-    case '<': {
    ++    case CC_LT: {
    +       if( (c=z[1])=='=' ){
    +         *tokenType = TK_LE;
    +         return 2;
    +@@ -130096,7 +142628,7 @@ SQLITE_PRIVATE int sqlite3GetToken(const unsigned char *z, int *tokenType){
    +         return 1;
    +       }
    +     }
    +-    case '>': {
    ++    case CC_GT: {
    +       if( (c=z[1])=='=' ){
    +         *tokenType = TK_GE;
    +         return 2;
    +@@ -130108,16 +142640,16 @@ SQLITE_PRIVATE int sqlite3GetToken(const unsigned char *z, int *tokenType){
    +         return 1;
    +       }
    +     }
    +-    case '!': {
    ++    case CC_BANG: {
    +       if( z[1]!='=' ){
    +         *tokenType = TK_ILLEGAL;
    +-        return 2;
    ++        return 1;
    +       }else{
    +         *tokenType = TK_NE;
    +         return 2;
    +       }
    +     }
    +-    case '|': {
    ++    case CC_PIPE: {
    +       if( z[1]!='|' ){
    +         *tokenType = TK_BITOR;
    +         return 1;
    +@@ -130126,21 +142658,19 @@ SQLITE_PRIVATE int sqlite3GetToken(const unsigned char *z, int *tokenType){
    +         return 2;
    +       }
    +     }
    +-    case ',': {
    ++    case CC_COMMA: {
    +       *tokenType = TK_COMMA;
    +       return 1;
    +     }
    +-    case '&': {
    ++    case CC_AND: {
    +       *tokenType = TK_BITAND;
    +       return 1;
    +     }
    +-    case '~': {
    ++    case CC_TILDA: {
    +       *tokenType = TK_BITNOT;
    +       return 1;
    +     }
    +-    case '`':
    +-    case '\'':
    +-    case '"': {
    ++    case CC_QUOTE: {
    +       int delim = z[0];
    +       testcase( delim=='`' );
    +       testcase( delim=='\'' );
    +@@ -130165,7 +142695,7 @@ SQLITE_PRIVATE int sqlite3GetToken(const unsigned char *z, int *tokenType){
    +         return i;
    +       }
    +     }
    +-    case '.': {
    ++    case CC_DOT: {
    + #ifndef SQLITE_OMIT_FLOATING_POINT
    +       if( !sqlite3Isdigit(z[1]) )
    + #endif
    +@@ -130176,8 +142706,7 @@ SQLITE_PRIVATE int sqlite3GetToken(const unsigned char *z, int *tokenType){
    +       /* If the next character is a digit, this is a floating point
    +       ** number that begins with ".".  Fall thru into the next case */
    +     }
    +-    case '0': case '1': case '2': case '3': case '4':
    +-    case '5': case '6': case '7': case '8': case '9': {
    ++    case CC_DIGIT: {
    +       testcase( z[0]=='0' );  testcase( z[0]=='1' );  testcase( z[0]=='2' );
    +       testcase( z[0]=='3' );  testcase( z[0]=='4' );  testcase( z[0]=='5' );
    +       testcase( z[0]=='6' );  testcase( z[0]=='7' );  testcase( z[0]=='8' );
    +@@ -130212,22 +142741,18 @@ SQLITE_PRIVATE int sqlite3GetToken(const unsigned char *z, int *tokenType){
    +       }
    +       return i;
    +     }
    +-    case '[': {
    ++    case CC_QUOTE2: {
    +       for(i=1, c=z[0]; c!=']' && (c=z[i])!=0; i++){}
    +       *tokenType = c==']' ? TK_ID : TK_ILLEGAL;
    +       return i;
    +     }
    +-    case '?': {
    ++    case CC_VARNUM: {
    +       *tokenType = TK_VARIABLE;
    +       for(i=1; sqlite3Isdigit(z[i]); i++){}
    +       return i;
    +     }
    +-#ifndef SQLITE_OMIT_TCL_VARIABLE
    +-    case '$':
    +-#endif
    +-    case '@':  /* For compatibility with MS SQL Server */
    +-    case '#':
    +-    case ':': {
    ++    case CC_DOLLAR:
    ++    case CC_VARALPHA: {
    +       int n = 0;
    +       testcase( z[0]=='$' );  testcase( z[0]=='@' );
    +       testcase( z[0]==':' );  testcase( z[0]=='#' );
    +@@ -130256,8 +142781,20 @@ SQLITE_PRIVATE int sqlite3GetToken(const unsigned char *z, int *tokenType){
    +       if( n==0 ) *tokenType = TK_ILLEGAL;
    +       return i;
    +     }
    ++    case CC_KYWD: {
    ++      for(i=1; aiClass[z[i]]<=CC_KYWD; i++){}
    ++      if( IdChar(z[i]) ){
    ++        /* This token started out using characters that can appear in keywords,
    ++        ** but z[i] is a character not allowed within keywords, so this must
    ++        ** be an identifier instead */
    ++        i++;
    ++        break;
    ++      }
    ++      *tokenType = TK_ID;
    ++      return keywordCode((char*)z, i, tokenType);
    ++    }
    ++    case CC_X: {
    + #ifndef SQLITE_OMIT_BLOB_LITERAL
    +-    case 'x': case 'X': {
    +       testcase( z[0]=='x' ); testcase( z[0]=='X' );
    +       if( z[1]=='\'' ){
    +         *tokenType = TK_BLOB;
    +@@ -130269,20 +142806,22 @@ SQLITE_PRIVATE int sqlite3GetToken(const unsigned char *z, int *tokenType){
    +         if( z[i] ) i++;
    +         return i;
    +       }
    +-      /* Otherwise fall through to the next case */
    +-    }
    + #endif
    ++      /* If it is not a BLOB literal, then it must be an ID, since no
    ++      ** SQL keywords start with the letter 'x'.  Fall through */
    ++    }
    ++    case CC_ID: {
    ++      i = 1;
    ++      break;
    ++    }
    +     default: {
    +-      if( !IdChar(*z) ){
    +-        break;
    +-      }
    +-      for(i=1; IdChar(z[i]); i++){}
    +-      *tokenType = keywordCode((char*)z, i);
    +-      return i;
    ++      *tokenType = TK_ILLEGAL;
    ++      return 1;
    +     }
    +   }
    +-  *tokenType = TK_ILLEGAL;
    +-  return 1;
    ++  while( IdChar(z[i]) ){ i++; }
    ++  *tokenType = TK_ID;
    ++  return i;
    + }
    + 
    + /*
    +@@ -130294,13 +142833,15 @@ SQLITE_PRIVATE int sqlite3GetToken(const unsigned char *z, int *tokenType){
    + */
    + SQLITE_PRIVATE int sqlite3RunParser(Parse *pParse, const char *zSql, char **pzErrMsg){
    +   int nErr = 0;                   /* Number of errors encountered */
    +-  int i;                          /* Loop counter */
    +   void *pEngine;                  /* The LEMON-generated LALR(1) parser */
    ++  int n = 0;                      /* Length of the next token token */
    +   int tokenType;                  /* type of the next token */
    +   int lastTokenParsed = -1;       /* type of the previous token */
    +-  u8 enableLookaside;             /* Saved value of db->lookaside.bEnabled */
    +   sqlite3 *db = pParse->db;       /* The database connection */
    +   int mxSqlLen;                   /* Max length of an SQL string */
    ++#ifdef sqlite3Parser_ENGINEALWAYSONSTACK
    ++  yyParser sEngine;    /* Space to hold the Lemon-generated Parser object */
    ++#endif
    + 
    +   assert( zSql!=0 );
    +   mxSqlLen = db->aLimit[SQLITE_LIMIT_SQL_LENGTH];
    +@@ -130309,81 +142850,78 @@ SQLITE_PRIVATE int sqlite3RunParser(Parse *pParse, const char *zSql, char **pzEr
    +   }
    +   pParse->rc = SQLITE_OK;
    +   pParse->zTail = zSql;
    +-  i = 0;
    +   assert( pzErrMsg!=0 );
    +   /* sqlite3ParserTrace(stdout, "parser: "); */
    ++#ifdef sqlite3Parser_ENGINEALWAYSONSTACK
    ++  pEngine = &sEngine;
    ++  sqlite3ParserInit(pEngine);
    ++#else
    +   pEngine = sqlite3ParserAlloc(sqlite3Malloc);
    +   if( pEngine==0 ){
    +-    db->mallocFailed = 1;
    +-    return SQLITE_NOMEM;
    ++    sqlite3OomFault(db);
    ++    return SQLITE_NOMEM_BKPT;
    +   }
    ++#endif
    +   assert( pParse->pNewTable==0 );
    +   assert( pParse->pNewTrigger==0 );
    +   assert( pParse->nVar==0 );
    +-  assert( pParse->nzVar==0 );
    +-  assert( pParse->azVar==0 );
    +-  enableLookaside = db->lookaside.bEnabled;
    +-  if( db->lookaside.pStart ) db->lookaside.bEnabled = 1;
    +-  while( !db->mallocFailed && zSql[i]!=0 ){
    +-    assert( i>=0 );
    +-    pParse->sLastToken.z = &zSql[i];
    +-    pParse->sLastToken.n = sqlite3GetToken((unsigned char*)&zSql[i],&tokenType);
    +-    i += pParse->sLastToken.n;
    +-    if( i>mxSqlLen ){
    +-      pParse->rc = SQLITE_TOOBIG;
    +-      break;
    +-    }
    +-    switch( tokenType ){
    +-      case TK_SPACE: {
    +-        if( db->u1.isInterrupted ){
    +-          sqlite3ErrorMsg(pParse, "interrupt");
    +-          pParse->rc = SQLITE_INTERRUPT;
    +-          goto abort_parse;
    +-        }
    ++  assert( pParse->pVList==0 );
    ++  while( 1 ){
    ++    if( zSql[0]!=0 ){
    ++      n = sqlite3GetToken((u8*)zSql, &tokenType);
    ++      mxSqlLen -= n;
    ++      if( mxSqlLen<0 ){
    ++        pParse->rc = SQLITE_TOOBIG;
    +         break;
    +       }
    +-      case TK_ILLEGAL: {
    +-        sqlite3ErrorMsg(pParse, "unrecognized token: \"%T\"",
    +-                        &pParse->sLastToken);
    +-        goto abort_parse;
    ++    }else{
    ++      /* Upon reaching the end of input, call the parser two more times
    ++      ** with tokens TK_SEMI and 0, in that order. */
    ++      if( lastTokenParsed==TK_SEMI ){
    ++        tokenType = 0;
    ++      }else if( lastTokenParsed==0 ){
    ++        break;
    ++      }else{
    ++        tokenType = TK_SEMI;
    +       }
    +-      case TK_SEMI: {
    +-        pParse->zTail = &zSql[i];
    +-        /* Fall thru into the default case */
    ++      n = 0;
    ++    }
    ++    if( tokenType>=TK_SPACE ){
    ++      assert( tokenType==TK_SPACE || tokenType==TK_ILLEGAL );
    ++      if( db->u1.isInterrupted ){
    ++        pParse->rc = SQLITE_INTERRUPT;
    ++        break;
    +       }
    +-      default: {
    +-        sqlite3Parser(pEngine, tokenType, pParse->sLastToken, pParse);
    +-        lastTokenParsed = tokenType;
    +-        if( pParse->rc!=SQLITE_OK ){
    +-          goto abort_parse;
    +-        }
    ++      if( tokenType==TK_ILLEGAL ){
    ++        sqlite3ErrorMsg(pParse, "unrecognized token: \"%.*s\"", n, zSql);
    +         break;
    +       }
    ++      zSql += n;
    ++    }else{
    ++      pParse->sLastToken.z = zSql;
    ++      pParse->sLastToken.n = n;
    ++      sqlite3Parser(pEngine, tokenType, pParse->sLastToken, pParse);
    ++      lastTokenParsed = tokenType;
    ++      zSql += n;
    ++      if( pParse->rc!=SQLITE_OK || db->mallocFailed ) break;
    +     }
    +   }
    +-abort_parse:
    +   assert( nErr==0 );
    +-  if( pParse->rc==SQLITE_OK && db->mallocFailed==0 ){
    +-    assert( zSql[i]==0 );
    +-    if( lastTokenParsed!=TK_SEMI ){
    +-      sqlite3Parser(pEngine, TK_SEMI, pParse->sLastToken, pParse);
    +-      pParse->zTail = &zSql[i];
    +-    }
    +-    if( pParse->rc==SQLITE_OK && db->mallocFailed==0 ){
    +-      sqlite3Parser(pEngine, 0, pParse->sLastToken, pParse);
    +-    }
    +-  }
    ++  pParse->zTail = zSql;
    + #ifdef YYTRACKMAXSTACKDEPTH
    +   sqlite3_mutex_enter(sqlite3MallocMutex());
    +-  sqlite3StatusSet(SQLITE_STATUS_PARSER_STACK,
    ++  sqlite3StatusHighwater(SQLITE_STATUS_PARSER_STACK,
    +       sqlite3ParserStackPeak(pEngine)
    +   );
    +   sqlite3_mutex_leave(sqlite3MallocMutex());
    + #endif /* YYDEBUG */
    ++#ifdef sqlite3Parser_ENGINEALWAYSONSTACK
    ++  sqlite3ParserFinalize(pEngine);
    ++#else
    +   sqlite3ParserFree(pEngine, sqlite3_free);
    +-  db->lookaside.bEnabled = enableLookaside;
    ++#endif
    +   if( db->mallocFailed ){
    +-    pParse->rc = SQLITE_NOMEM;
    ++    pParse->rc = SQLITE_NOMEM_BKPT;
    +   }
    +   if( pParse->rc!=SQLITE_OK && pParse->rc!=SQLITE_DONE && pParse->zErrMsg==0 ){
    +     pParse->zErrMsg = sqlite3MPrintf(db, "%s", sqlite3ErrStr(pParse->rc));
    +@@ -130418,14 +142956,13 @@ abort_parse:
    +     sqlite3DeleteTable(db, pParse->pNewTable);
    +   }
    + 
    +-  if( pParse->bFreeWith ) sqlite3WithDelete(db, pParse->pWith);
    ++  if( pParse->pWithToFree ) sqlite3WithDelete(db, pParse->pWithToFree);
    +   sqlite3DeleteTrigger(db, pParse->pNewTrigger);
    +-  for(i=pParse->nzVar-1; i>=0; i--) sqlite3DbFree(db, pParse->azVar[i]);
    +-  sqlite3DbFree(db, pParse->azVar);
    ++  sqlite3DbFree(db, pParse->pVList);
    +   while( pParse->pAinc ){
    +     AutoincInfo *p = pParse->pAinc;
    +     pParse->pAinc = p->pNext;
    +-    sqlite3DbFree(db, p);
    ++    sqlite3DbFreeNN(db, p);
    +   }
    +   while( pParse->pZombieTab ){
    +     Table *p = pParse->pZombieTab;
    +@@ -130541,7 +143078,7 @@ SQLITE_PRIVATE const char sqlite3IsEbcdicIdChar[];
    + ** to recognize the end of a trigger can be omitted.  All we have to do
    + ** is look for a semicolon that is not part of an string or comment.
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_complete(const char *zSql){
    ++SQLITE_API int sqlite3_complete(const char *zSql){
    +   u8 state = 0;   /* Current state, using numbers defined in header comment */
    +   u8 token;       /* Value of the next token */
    + 
    +@@ -130706,7 +143243,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_complete(const char *zSql){
    + ** above, except that the parameter is required to be UTF-16 encoded, not
    + ** UTF-8.
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_complete16(const void *zSql){
    ++SQLITE_API int sqlite3_complete16(const void *zSql){
    +   sqlite3_value *pVal;
    +   char const *zSql8;
    +   int rc;
    +@@ -130721,7 +143258,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_complete16(const void *zSql){
    +   if( zSql8 ){
    +     rc = sqlite3_complete(zSql8);
    +   }else{
    +-    rc = SQLITE_NOMEM;
    ++    rc = SQLITE_NOMEM_BKPT;
    +   }
    +   sqlite3ValueFree(pVal);
    +   return rc & 0xff;
    +@@ -130802,6 +143339,10 @@ SQLITE_PRIVATE int sqlite3Fts3Init(sqlite3 *db);
    + */
    + /* #include "sqlite3.h" */
    + 
    ++#ifdef SQLITE_OMIT_VIRTUALTABLE
    ++# undef SQLITE_ENABLE_RTREE
    ++#endif
    ++
    + #if 0
    + extern "C" {
    + #endif  /* __cplusplus */
    +@@ -130815,7 +143356,7 @@ SQLITE_PRIVATE int sqlite3RtreeInit(sqlite3 *db);
    + /************** End of rtree.h ***********************************************/
    + /************** Continuing where we left off in main.c ***********************/
    + #endif
    +-#ifdef SQLITE_ENABLE_ICU
    ++#if defined(SQLITE_ENABLE_ICU) || defined(SQLITE_ENABLE_ICU_COLLATIONS)
    + /************** Include sqliteicu.h in the middle of main.c ******************/
    + /************** Begin file sqliteicu.h ***************************************/
    + /*
    +@@ -130852,6 +143393,9 @@ SQLITE_PRIVATE int sqlite3IcuInit(sqlite3 *db);
    + #ifdef SQLITE_ENABLE_JSON1
    + SQLITE_PRIVATE int sqlite3Json1Init(sqlite3*);
    + #endif
    ++#ifdef SQLITE_ENABLE_STMTVTAB
    ++SQLITE_PRIVATE int sqlite3StmtVtabInit(sqlite3*);
    ++#endif
    + #ifdef SQLITE_ENABLE_FTS5
    + SQLITE_PRIVATE int sqlite3Fts5Init(sqlite3*);
    + #endif
    +@@ -130866,24 +143410,26 @@ SQLITE_API const char sqlite3_version[] = SQLITE_VERSION;
    + /* IMPLEMENTATION-OF: R-53536-42575 The sqlite3_libversion() function returns
    + ** a pointer to the to the sqlite3_version[] string constant. 
    + */
    +-SQLITE_API const char *SQLITE_STDCALL sqlite3_libversion(void){ return sqlite3_version; }
    ++SQLITE_API const char *sqlite3_libversion(void){ return sqlite3_version; }
    + 
    +-/* IMPLEMENTATION-OF: R-63124-39300 The sqlite3_sourceid() function returns a
    ++/* IMPLEMENTATION-OF: R-25063-23286 The sqlite3_sourceid() function returns a
    + ** pointer to a string constant whose value is the same as the
    +-** SQLITE_SOURCE_ID C preprocessor macro. 
    ++** SQLITE_SOURCE_ID C preprocessor macro. Except if SQLite is built using
    ++** an edited copy of the amalgamation, then the last four characters of
    ++** the hash might be different from SQLITE_SOURCE_ID.
    + */
    +-SQLITE_API const char *SQLITE_STDCALL sqlite3_sourceid(void){ return SQLITE_SOURCE_ID; }
    ++/* SQLITE_API const char *sqlite3_sourceid(void){ return SQLITE_SOURCE_ID; } */
    + 
    + /* IMPLEMENTATION-OF: R-35210-63508 The sqlite3_libversion_number() function
    + ** returns an integer equal to SQLITE_VERSION_NUMBER.
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_libversion_number(void){ return SQLITE_VERSION_NUMBER; }
    ++SQLITE_API int sqlite3_libversion_number(void){ return SQLITE_VERSION_NUMBER; }
    + 
    + /* IMPLEMENTATION-OF: R-20790-14025 The sqlite3_threadsafe() function returns
    + ** zero if and only if SQLite was compiled with mutexing code omitted due to
    + ** the SQLITE_THREADSAFE compile-time option being set to 0.
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_threadsafe(void){ return SQLITE_THREADSAFE; }
    ++SQLITE_API int sqlite3_threadsafe(void){ return SQLITE_THREADSAFE; }
    + 
    + /*
    + ** When compiling the test fixture or with debugging enabled (on Win32),
    +@@ -130956,7 +143502,7 @@ SQLITE_API char *sqlite3_data_directory = 0;
    + **    *  Recursive calls to this routine from thread X return immediately
    + **       without blocking.
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_initialize(void){
    ++SQLITE_API int sqlite3_initialize(void){
    +   MUTEX_LOGIC( sqlite3_mutex *pMaster; )       /* The main static mutex */
    +   int rc;                                      /* Result code */
    + #ifdef SQLITE_EXTRA_INIT
    +@@ -131011,7 +143557,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_initialize(void){
    +       sqlite3GlobalConfig.pInitMutex =
    +            sqlite3MutexAlloc(SQLITE_MUTEX_RECURSIVE);
    +       if( sqlite3GlobalConfig.bCoreMutex && !sqlite3GlobalConfig.pInitMutex ){
    +-        rc = SQLITE_NOMEM;
    ++        rc = SQLITE_NOMEM_BKPT;
    +       }
    +     }
    +   }
    +@@ -131042,10 +143588,15 @@ SQLITE_API int SQLITE_STDCALL sqlite3_initialize(void){
    +   */
    +   sqlite3_mutex_enter(sqlite3GlobalConfig.pInitMutex);
    +   if( sqlite3GlobalConfig.isInit==0 && sqlite3GlobalConfig.inProgress==0 ){
    +-    FuncDefHash *pHash = &GLOBAL(FuncDefHash, sqlite3GlobalFunctions);
    +     sqlite3GlobalConfig.inProgress = 1;
    +-    memset(pHash, 0, sizeof(sqlite3GlobalFunctions));
    +-    sqlite3RegisterGlobalFunctions();
    ++#ifdef SQLITE_ENABLE_SQLLOG
    ++    {
    ++      extern void sqlite3_init_sqllog(void);
    ++      sqlite3_init_sqllog();
    ++    }
    ++#endif
    ++    memset(&sqlite3BuiltinFunctions, 0, sizeof(sqlite3BuiltinFunctions));
    ++    sqlite3RegisterBuiltinFunctions();
    +     if( sqlite3GlobalConfig.isPCacheInit==0 ){
    +       rc = sqlite3PcacheInitialize();
    +     }
    +@@ -131117,7 +143668,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_initialize(void){
    + ** on when SQLite is already shut down.  If SQLite is already shut down
    + ** when this routine is invoked, then this routine is a harmless no-op.
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_shutdown(void){
    ++SQLITE_API int sqlite3_shutdown(void){
    + #ifdef SQLITE_OMIT_WSD
    +   int rc = sqlite3_wsd_init(4096, 24);
    +   if( rc!=SQLITE_OK ){
    +@@ -131171,7 +143722,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_shutdown(void){
    + ** threadsafe.  Failure to heed these warnings can lead to unpredictable
    + ** behavior.
    + */
    +-SQLITE_API int SQLITE_CDECL sqlite3_config(int op, ...){
    ++SQLITE_API int sqlite3_config(int op, ...){
    +   va_list ap;
    +   int rc = SQLITE_OK;
    + 
    +@@ -131252,20 +143803,15 @@ SQLITE_API int SQLITE_CDECL sqlite3_config(int op, ...){
    +       sqlite3GlobalConfig.bMemstat = va_arg(ap, int);
    +       break;
    +     }
    +-    case SQLITE_CONFIG_SCRATCH: {
    +-      /* EVIDENCE-OF: R-08404-60887 There are three arguments to
    +-      ** SQLITE_CONFIG_SCRATCH: A pointer an 8-byte aligned memory buffer from
    +-      ** which the scratch allocations will be drawn, the size of each scratch
    +-      ** allocation (sz), and the maximum number of scratch allocations (N). */
    +-      sqlite3GlobalConfig.pScratch = va_arg(ap, void*);
    +-      sqlite3GlobalConfig.szScratch = va_arg(ap, int);
    +-      sqlite3GlobalConfig.nScratch = va_arg(ap, int);
    ++    case SQLITE_CONFIG_SMALL_MALLOC: {
    ++      sqlite3GlobalConfig.bSmallMalloc = va_arg(ap, int);
    +       break;
    +     }
    +     case SQLITE_CONFIG_PAGECACHE: {
    +-      /* EVIDENCE-OF: R-31408-40510 There are three arguments to
    +-      ** SQLITE_CONFIG_PAGECACHE: A pointer to 8-byte aligned memory, the size
    +-      ** of each page buffer (sz), and the number of pages (N). */
    ++      /* EVIDENCE-OF: R-18761-36601 There are three arguments to
    ++      ** SQLITE_CONFIG_PAGECACHE: A pointer to 8-byte aligned memory (pMem),
    ++      ** the size of each page cache line (sz), and the number of cache lines
    ++      ** (N). */
    +       sqlite3GlobalConfig.pPage = va_arg(ap, void*);
    +       sqlite3GlobalConfig.szPage = va_arg(ap, int);
    +       sqlite3GlobalConfig.nPage = va_arg(ap, int);
    +@@ -131451,6 +143997,11 @@ SQLITE_API int SQLITE_CDECL sqlite3_config(int op, ...){
    +       break;
    +     }
    + 
    ++    case SQLITE_CONFIG_STMTJRNL_SPILL: {
    ++      sqlite3GlobalConfig.nStmtSpill = va_arg(ap, int);
    ++      break;
    ++    }
    ++
    +     default: {
    +       rc = SQLITE_ERROR;
    +       break;
    +@@ -131474,7 +144025,8 @@ SQLITE_API int SQLITE_CDECL sqlite3_config(int op, ...){
    + static int setupLookaside(sqlite3 *db, void *pBuf, int sz, int cnt){
    + #ifndef SQLITE_OMIT_LOOKASIDE
    +   void *pStart;
    +-  if( db->lookaside.nOut ){
    ++  
    ++  if( sqlite3LookasideUsed(db,0)>0 ){
    +     return SQLITE_BUSY;
    +   }
    +   /* Free any existing lookaside buffer for this handle before
    +@@ -131502,26 +144054,29 @@ static int setupLookaside(sqlite3 *db, void *pBuf, int sz, int cnt){
    +     pStart = pBuf;
    +   }
    +   db->lookaside.pStart = pStart;
    ++  db->lookaside.pInit = 0;
    +   db->lookaside.pFree = 0;
    +   db->lookaside.sz = (u16)sz;
    +   if( pStart ){
    +     int i;
    +     LookasideSlot *p;
    +     assert( sz > (int)sizeof(LookasideSlot*) );
    ++    db->lookaside.nSlot = cnt;
    +     p = (LookasideSlot*)pStart;
    +     for(i=cnt-1; i>=0; i--){
    +-      p->pNext = db->lookaside.pFree;
    +-      db->lookaside.pFree = p;
    ++      p->pNext = db->lookaside.pInit;
    ++      db->lookaside.pInit = p;
    +       p = (LookasideSlot*)&((u8*)p)[sz];
    +     }
    +     db->lookaside.pEnd = p;
    +-    db->lookaside.bEnabled = 1;
    ++    db->lookaside.bDisable = 0;
    +     db->lookaside.bMalloced = pBuf==0 ?1:0;
    +   }else{
    +     db->lookaside.pStart = db;
    +     db->lookaside.pEnd = db;
    +-    db->lookaside.bEnabled = 0;
    ++    db->lookaside.bDisable = 1;
    +     db->lookaside.bMalloced = 0;
    ++    db->lookaside.nSlot = 0;
    +   }
    + #endif /* SQLITE_OMIT_LOOKASIDE */
    +   return SQLITE_OK;
    +@@ -131530,7 +144085,7 @@ static int setupLookaside(sqlite3 *db, void *pBuf, int sz, int cnt){
    + /*
    + ** Return the mutex associated with a database connection.
    + */
    +-SQLITE_API sqlite3_mutex *SQLITE_STDCALL sqlite3_db_mutex(sqlite3 *db){
    ++SQLITE_API sqlite3_mutex *sqlite3_db_mutex(sqlite3 *db){
    + #ifdef SQLITE_ENABLE_API_ARMOR
    +   if( !sqlite3SafetyCheckOk(db) ){
    +     (void)SQLITE_MISUSE_BKPT;
    +@@ -131544,7 +144099,7 @@ SQLITE_API sqlite3_mutex *SQLITE_STDCALL sqlite3_db_mutex(sqlite3 *db){
    + ** Free up as much memory as we can from the given database
    + ** connection.
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_db_release_memory(sqlite3 *db){
    ++SQLITE_API int sqlite3_db_release_memory(sqlite3 *db){
    +   int i;
    + 
    + #ifdef SQLITE_ENABLE_API_ARMOR
    +@@ -131564,14 +144119,51 @@ SQLITE_API int SQLITE_STDCALL sqlite3_db_release_memory(sqlite3 *db){
    +   return SQLITE_OK;
    + }
    + 
    ++/*
    ++** Flush any dirty pages in the pager-cache for any attached database
    ++** to disk.
    ++*/
    ++SQLITE_API int sqlite3_db_cacheflush(sqlite3 *db){
    ++  int i;
    ++  int rc = SQLITE_OK;
    ++  int bSeenBusy = 0;
    ++
    ++#ifdef SQLITE_ENABLE_API_ARMOR
    ++  if( !sqlite3SafetyCheckOk(db) ) return SQLITE_MISUSE_BKPT;
    ++#endif
    ++  sqlite3_mutex_enter(db->mutex);
    ++  sqlite3BtreeEnterAll(db);
    ++  for(i=0; rc==SQLITE_OK && i<db->nDb; i++){
    ++    Btree *pBt = db->aDb[i].pBt;
    ++    if( pBt && sqlite3BtreeIsInTrans(pBt) ){
    ++      Pager *pPager = sqlite3BtreePager(pBt);
    ++      rc = sqlite3PagerFlush(pPager);
    ++      if( rc==SQLITE_BUSY ){
    ++        bSeenBusy = 1;
    ++        rc = SQLITE_OK;
    ++      }
    ++    }
    ++  }
    ++  sqlite3BtreeLeaveAll(db);
    ++  sqlite3_mutex_leave(db->mutex);
    ++  return ((rc==SQLITE_OK && bSeenBusy) ? SQLITE_BUSY : rc);
    ++}
    ++
    + /*
    + ** Configuration settings for an individual database connection
    + */
    +-SQLITE_API int SQLITE_CDECL sqlite3_db_config(sqlite3 *db, int op, ...){
    ++SQLITE_API int sqlite3_db_config(sqlite3 *db, int op, ...){
    +   va_list ap;
    +   int rc;
    +   va_start(ap, op);
    +   switch( op ){
    ++    case SQLITE_DBCONFIG_MAINDBNAME: {
    ++      /* IMP: R-06824-28531 */
    ++      /* IMP: R-36257-52125 */
    ++      db->aDb[0].zDbSName = va_arg(ap,char*);
    ++      rc = SQLITE_OK;
    ++      break;
    ++    }
    +     case SQLITE_DBCONFIG_LOOKASIDE: {
    +       void *pBuf = va_arg(ap, void*); /* IMP: R-26835-10964 */
    +       int sz = va_arg(ap, int);       /* IMP: R-47871-25994 */
    +@@ -131584,8 +144176,13 @@ SQLITE_API int SQLITE_CDECL sqlite3_db_config(sqlite3 *db, int op, ...){
    +         int op;      /* The opcode */
    +         u32 mask;    /* Mask of the bit in sqlite3.flags to set/clear */
    +       } aFlagOp[] = {
    +-        { SQLITE_DBCONFIG_ENABLE_FKEY,    SQLITE_ForeignKeys    },
    +-        { SQLITE_DBCONFIG_ENABLE_TRIGGER, SQLITE_EnableTrigger  },
    ++        { SQLITE_DBCONFIG_ENABLE_FKEY,           SQLITE_ForeignKeys    },
    ++        { SQLITE_DBCONFIG_ENABLE_TRIGGER,        SQLITE_EnableTrigger  },
    ++        { SQLITE_DBCONFIG_ENABLE_FTS3_TOKENIZER, SQLITE_Fts3Tokenizer  },
    ++        { SQLITE_DBCONFIG_ENABLE_LOAD_EXTENSION, SQLITE_LoadExtension  },
    ++        { SQLITE_DBCONFIG_NO_CKPT_ON_CLOSE,      SQLITE_NoCkptOnClose  },
    ++        { SQLITE_DBCONFIG_ENABLE_QPSG,           SQLITE_EnableQPSG     },
    ++        { SQLITE_DBCONFIG_TRIGGER_EQP,           SQLITE_TriggerEQP     },
    +       };
    +       unsigned int i;
    +       rc = SQLITE_ERROR; /* IMP: R-42790-23372 */
    +@@ -131593,7 +144190,7 @@ SQLITE_API int SQLITE_CDECL sqlite3_db_config(sqlite3 *db, int op, ...){
    +         if( aFlagOp[i].op==op ){
    +           int onoff = va_arg(ap, int);
    +           int *pRes = va_arg(ap, int*);
    +-          int oldFlags = db->flags;
    ++          u32 oldFlags = db->flags;
    +           if( onoff>0 ){
    +             db->flags |= aFlagOp[i].mask;
    +           }else if( onoff==0 ){
    +@@ -131642,6 +144239,7 @@ static int binCollFunc(
    +   /* EVIDENCE-OF: R-65033-28449 The built-in BINARY collation compares
    +   ** strings byte by byte using the memcmp() function from the standard C
    +   ** library. */
    ++  assert( pKey1 && pKey2 );
    +   rc = memcmp(pKey1, pKey2, n);
    +   if( rc==0 ){
    +     if( padFlag
    +@@ -131686,7 +144284,7 @@ static int nocaseCollatingFunc(
    + /*
    + ** Return the ROWID of the most recent insert
    + */
    +-SQLITE_API sqlite_int64 SQLITE_STDCALL sqlite3_last_insert_rowid(sqlite3 *db){
    ++SQLITE_API sqlite_int64 sqlite3_last_insert_rowid(sqlite3 *db){
    + #ifdef SQLITE_ENABLE_API_ARMOR
    +   if( !sqlite3SafetyCheckOk(db) ){
    +     (void)SQLITE_MISUSE_BKPT;
    +@@ -131696,10 +144294,25 @@ SQLITE_API sqlite_int64 SQLITE_STDCALL sqlite3_last_insert_rowid(sqlite3 *db){
    +   return db->lastRowid;
    + }
    + 
    ++/*
    ++** Set the value returned by the sqlite3_last_insert_rowid() API function.
    ++*/
    ++SQLITE_API void sqlite3_set_last_insert_rowid(sqlite3 *db, sqlite3_int64 iRowid){
    ++#ifdef SQLITE_ENABLE_API_ARMOR
    ++  if( !sqlite3SafetyCheckOk(db) ){
    ++    (void)SQLITE_MISUSE_BKPT;
    ++    return;
    ++  }
    ++#endif
    ++  sqlite3_mutex_enter(db->mutex);
    ++  db->lastRowid = iRowid;
    ++  sqlite3_mutex_leave(db->mutex);
    ++}
    ++
    + /*
    + ** Return the number of changes in the most recent call to sqlite3_exec().
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_changes(sqlite3 *db){
    ++SQLITE_API int sqlite3_changes(sqlite3 *db){
    + #ifdef SQLITE_ENABLE_API_ARMOR
    +   if( !sqlite3SafetyCheckOk(db) ){
    +     (void)SQLITE_MISUSE_BKPT;
    +@@ -131712,7 +144325,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_changes(sqlite3 *db){
    + /*
    + ** Return the number of changes since the database handle was opened.
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_total_changes(sqlite3 *db){
    ++SQLITE_API int sqlite3_total_changes(sqlite3 *db){
    + #ifdef SQLITE_ENABLE_API_ARMOR
    +   if( !sqlite3SafetyCheckOk(db) ){
    +     (void)SQLITE_MISUSE_BKPT;
    +@@ -131745,7 +144358,7 @@ SQLITE_PRIVATE void sqlite3CloseSavepoints(sqlite3 *db){
    + ** with SQLITE_ANY as the encoding.
    + */
    + static void functionDestroy(sqlite3 *db, FuncDef *p){
    +-  FuncDestructor *pDestructor = p->pDestructor;
    ++  FuncDestructor *pDestructor = p->u.pDestructor;
    +   if( pDestructor ){
    +     pDestructor->nRef--;
    +     if( pDestructor->nRef==0 ){
    +@@ -131814,6 +144427,9 @@ static int sqlite3Close(sqlite3 *db, int forceZombie){
    +     return SQLITE_MISUSE_BKPT;
    +   }
    +   sqlite3_mutex_enter(db->mutex);
    ++  if( db->mTrace & SQLITE_TRACE_CLOSE ){
    ++    db->xTrace(SQLITE_TRACE_CLOSE, db->pTraceArg, db, 0);
    ++  }
    + 
    +   /* Force xDisconnect calls on all virtual tables */
    +   disconnectAllVtab(db);
    +@@ -131860,8 +144476,8 @@ static int sqlite3Close(sqlite3 *db, int forceZombie){
    + ** unclosed resources, and arranges for deallocation when the last
    + ** prepare statement or sqlite3_backup closes.
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_close(sqlite3 *db){ return sqlite3Close(db,0); }
    +-SQLITE_API int SQLITE_STDCALL sqlite3_close_v2(sqlite3 *db){ return sqlite3Close(db,1); }
    ++SQLITE_API int sqlite3_close(sqlite3 *db){ return sqlite3Close(db,0); }
    ++SQLITE_API int sqlite3_close_v2(sqlite3 *db){ return sqlite3Close(db,1); }
    + 
    + 
    + /*
    +@@ -131927,18 +144543,17 @@ SQLITE_PRIVATE void sqlite3LeaveMutexAndCloseZombie(sqlite3 *db){
    +   */
    +   sqlite3ConnectionClosed(db);
    + 
    +-  for(j=0; j<ArraySize(db->aFunc.a); j++){
    +-    FuncDef *pNext, *pHash, *p;
    +-    for(p=db->aFunc.a[j]; p; p=pHash){
    +-      pHash = p->pHash;
    +-      while( p ){
    +-        functionDestroy(db, p);
    +-        pNext = p->pNext;
    +-        sqlite3DbFree(db, p);
    +-        p = pNext;
    +-      }
    +-    }
    ++  for(i=sqliteHashFirst(&db->aFunc); i; i=sqliteHashNext(i)){
    ++    FuncDef *pNext, *p;
    ++    p = sqliteHashData(i);
    ++    do{
    ++      functionDestroy(db, p);
    ++      pNext = p->pNext;
    ++      sqlite3DbFree(db, p);
    ++      p = pNext;
    ++    }while( p );
    +   }
    ++  sqlite3HashClear(&db->aFunc);
    +   for(i=sqliteHashFirst(&db->aCollSeq); i; i=sqliteHashNext(i)){
    +     CollSeq *pColl = (CollSeq *)sqliteHashData(i);
    +     /* Invoke any destructors registered for collation sequence user data. */
    +@@ -131982,7 +144597,7 @@ SQLITE_PRIVATE void sqlite3LeaveMutexAndCloseZombie(sqlite3 *db){
    +   sqlite3_mutex_leave(db->mutex);
    +   db->magic = SQLITE_MAGIC_CLOSED;
    +   sqlite3_mutex_free(db->mutex);
    +-  assert( db->lookaside.nOut==0 );  /* Fails on a lookaside memory leak */
    ++  assert( sqlite3LookasideUsed(db,0)==0 );
    +   if( db->lookaside.bMalloced ){
    +     sqlite3_free(db->lookaside.pStart);
    +   }
    +@@ -132010,7 +144625,7 @@ SQLITE_PRIVATE void sqlite3RollbackAll(sqlite3 *db, int tripCode){
    +   ** the database rollback and schema reset, which can cause false
    +   ** corruption reports in some cases.  */
    +   sqlite3BtreeEnterAll(db);
    +-  schemaChange = (db->flags & SQLITE_InternChanges)!=0 && db->init.busy==0;
    ++  schemaChange = (db->mDbFlags & DBFLAG_SchemaChange)!=0 && db->init.busy==0;
    + 
    +   for(i=0; i<db->nDb; i++){
    +     Btree *p = db->aDb[i].pBt;
    +@@ -132024,7 +144639,7 @@ SQLITE_PRIVATE void sqlite3RollbackAll(sqlite3 *db, int tripCode){
    +   sqlite3VtabRollback(db);
    +   sqlite3EndBenignMalloc();
    + 
    +-  if( (db->flags&SQLITE_InternChanges)!=0 && db->init.busy==0 ){
    ++  if( (db->mDbFlags&DBFLAG_SchemaChange)!=0 && db->init.busy==0 ){
    +     sqlite3ExpirePreparedStatements(db);
    +     sqlite3ResetAllSchemasOfConnection(db);
    +   }
    +@@ -132065,9 +144680,10 @@ SQLITE_PRIVATE const char *sqlite3ErrName(int rc){
    +       case SQLITE_NOMEM:              zName = "SQLITE_NOMEM";             break;
    +       case SQLITE_READONLY:           zName = "SQLITE_READONLY";          break;
    +       case SQLITE_READONLY_RECOVERY:  zName = "SQLITE_READONLY_RECOVERY"; break;
    +-      case SQLITE_READONLY_CANTLOCK:  zName = "SQLITE_READONLY_CANTLOCK"; break;
    ++      case SQLITE_READONLY_CANTINIT:  zName = "SQLITE_READONLY_CANTINIT"; break;
    +       case SQLITE_READONLY_ROLLBACK:  zName = "SQLITE_READONLY_ROLLBACK"; break;
    +       case SQLITE_READONLY_DBMOVED:   zName = "SQLITE_READONLY_DBMOVED";  break;
    ++      case SQLITE_READONLY_DIRECTORY: zName = "SQLITE_READONLY_DIRECTORY";break;
    +       case SQLITE_INTERRUPT:          zName = "SQLITE_INTERRUPT";         break;
    +       case SQLITE_IOERR:              zName = "SQLITE_IOERR";             break;
    +       case SQLITE_IOERR_READ:         zName = "SQLITE_IOERR_READ";        break;
    +@@ -132157,10 +144773,10 @@ SQLITE_PRIVATE const char *sqlite3ErrName(int rc){
    + SQLITE_PRIVATE const char *sqlite3ErrStr(int rc){
    +   static const char* const aMsg[] = {
    +     /* SQLITE_OK          */ "not an error",
    +-    /* SQLITE_ERROR       */ "SQL logic error or missing database",
    ++    /* SQLITE_ERROR       */ "SQL logic error",
    +     /* SQLITE_INTERNAL    */ 0,
    +     /* SQLITE_PERM        */ "access permission denied",
    +-    /* SQLITE_ABORT       */ "callback requested query abort",
    ++    /* SQLITE_ABORT       */ "query aborted",
    +     /* SQLITE_BUSY        */ "database is locked",
    +     /* SQLITE_LOCKED      */ "database table is locked",
    +     /* SQLITE_NOMEM       */ "out of memory",
    +@@ -132172,17 +144788,21 @@ SQLITE_PRIVATE const char *sqlite3ErrStr(int rc){
    +     /* SQLITE_FULL        */ "database or disk is full",
    +     /* SQLITE_CANTOPEN    */ "unable to open database file",
    +     /* SQLITE_PROTOCOL    */ "locking protocol",
    +-    /* SQLITE_EMPTY       */ "table contains no data",
    ++    /* SQLITE_EMPTY       */ 0,
    +     /* SQLITE_SCHEMA      */ "database schema has changed",
    +     /* SQLITE_TOOBIG      */ "string or blob too big",
    +     /* SQLITE_CONSTRAINT  */ "constraint failed",
    +     /* SQLITE_MISMATCH    */ "datatype mismatch",
    +-    /* SQLITE_MISUSE      */ "library routine called out of sequence",
    ++    /* SQLITE_MISUSE      */ "bad parameter or other API misuse",
    ++#ifdef SQLITE_DISABLE_LFS
    +     /* SQLITE_NOLFS       */ "large file support is disabled",
    ++#else
    ++    /* SQLITE_NOLFS       */ 0,
    ++#endif
    +     /* SQLITE_AUTH        */ "authorization denied",
    +-    /* SQLITE_FORMAT      */ "auxiliary database format error",
    +-    /* SQLITE_RANGE       */ "bind or column index out of range",
    +-    /* SQLITE_NOTADB      */ "file is encrypted or is not a database",
    ++    /* SQLITE_FORMAT      */ 0,
    ++    /* SQLITE_RANGE       */ "column index out of range",
    ++    /* SQLITE_NOTADB      */ "file is not a database",
    +   };
    +   const char *zErr = "unknown error";
    +   switch( rc ){
    +@@ -132269,7 +144889,7 @@ SQLITE_PRIVATE int sqlite3InvokeBusyHandler(BusyHandler *p){
    + ** This routine sets the busy callback for an Sqlite database to the
    + ** given callback function with the given argument.
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_busy_handler(
    ++SQLITE_API int sqlite3_busy_handler(
    +   sqlite3 *db,
    +   int (*xBusy)(void*,int),
    +   void *pArg
    +@@ -132292,7 +144912,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_busy_handler(
    + ** given callback function with the given argument. The progress callback will
    + ** be invoked every nOps opcodes.
    + */
    +-SQLITE_API void SQLITE_STDCALL sqlite3_progress_handler(
    ++SQLITE_API void sqlite3_progress_handler(
    +   sqlite3 *db, 
    +   int nOps,
    +   int (*xProgress)(void*), 
    +@@ -132323,7 +144943,7 @@ SQLITE_API void SQLITE_STDCALL sqlite3_progress_handler(
    + ** This routine installs a default busy handler that waits for the
    + ** specified number of milliseconds before returning 0.
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_busy_timeout(sqlite3 *db, int ms){
    ++SQLITE_API int sqlite3_busy_timeout(sqlite3 *db, int ms){
    + #ifdef SQLITE_ENABLE_API_ARMOR
    +   if( !sqlite3SafetyCheckOk(db) ) return SQLITE_MISUSE_BKPT;
    + #endif
    +@@ -132339,9 +144959,9 @@ SQLITE_API int SQLITE_STDCALL sqlite3_busy_timeout(sqlite3 *db, int ms){
    + /*
    + ** Cause any pending operation to stop at its earliest opportunity.
    + */
    +-SQLITE_API void SQLITE_STDCALL sqlite3_interrupt(sqlite3 *db){
    ++SQLITE_API void sqlite3_interrupt(sqlite3 *db){
    + #ifdef SQLITE_ENABLE_API_ARMOR
    +-  if( !sqlite3SafetyCheckOk(db) ){
    ++  if( !sqlite3SafetyCheckOk(db) && (db==0 || db->magic!=SQLITE_MAGIC_ZOMBIE) ){
    +     (void)SQLITE_MISUSE_BKPT;
    +     return;
    +   }
    +@@ -132362,7 +144982,7 @@ SQLITE_PRIVATE int sqlite3CreateFunc(
    +   int nArg,
    +   int enc,
    +   void *pUserData,
    +-  void (*xFunc)(sqlite3_context*,int,sqlite3_value **),
    ++  void (*xSFunc)(sqlite3_context*,int,sqlite3_value **),
    +   void (*xStep)(sqlite3_context*,int,sqlite3_value **),
    +   void (*xFinal)(sqlite3_context*),
    +   FuncDestructor *pDestructor
    +@@ -132373,9 +144993,9 @@ SQLITE_PRIVATE int sqlite3CreateFunc(
    + 
    +   assert( sqlite3_mutex_held(db->mutex) );
    +   if( zFunctionName==0 ||
    +-      (xFunc && (xFinal || xStep)) || 
    +-      (!xFunc && (xFinal && !xStep)) ||
    +-      (!xFunc && (!xFinal && xStep)) ||
    ++      (xSFunc && (xFinal || xStep)) || 
    ++      (!xSFunc && (xFinal && !xStep)) ||
    ++      (!xSFunc && (!xFinal && xStep)) ||
    +       (nArg<-1 || nArg>SQLITE_MAX_FUNCTION_ARG) ||
    +       (255<(nName = sqlite3Strlen30( zFunctionName))) ){
    +     return SQLITE_MISUSE_BKPT;
    +@@ -132398,10 +145018,10 @@ SQLITE_PRIVATE int sqlite3CreateFunc(
    +   }else if( enc==SQLITE_ANY ){
    +     int rc;
    +     rc = sqlite3CreateFunc(db, zFunctionName, nArg, SQLITE_UTF8|extraFlags,
    +-         pUserData, xFunc, xStep, xFinal, pDestructor);
    ++         pUserData, xSFunc, xStep, xFinal, pDestructor);
    +     if( rc==SQLITE_OK ){
    +       rc = sqlite3CreateFunc(db, zFunctionName, nArg, SQLITE_UTF16LE|extraFlags,
    +-          pUserData, xFunc, xStep, xFinal, pDestructor);
    ++          pUserData, xSFunc, xStep, xFinal, pDestructor);
    +     }
    +     if( rc!=SQLITE_OK ){
    +       return rc;
    +@@ -132417,7 +145037,7 @@ SQLITE_PRIVATE int sqlite3CreateFunc(
    +   ** is being overridden/deleted but there are no active VMs, allow the
    +   ** operation to continue but invalidate all precompiled statements.
    +   */
    +-  p = sqlite3FindFunction(db, zFunctionName, nName, nArg, (u8)enc, 0);
    ++  p = sqlite3FindFunction(db, zFunctionName, nArg, (u8)enc, 0);
    +   if( p && (p->funcFlags & SQLITE_FUNC_ENCMASK)==enc && p->nArg==nArg ){
    +     if( db->nVdbeActive ){
    +       sqlite3ErrorWithMsg(db, SQLITE_BUSY, 
    +@@ -132429,10 +145049,10 @@ SQLITE_PRIVATE int sqlite3CreateFunc(
    +     }
    +   }
    + 
    +-  p = sqlite3FindFunction(db, zFunctionName, nName, nArg, (u8)enc, 1);
    ++  p = sqlite3FindFunction(db, zFunctionName, nArg, (u8)enc, 1);
    +   assert(p || db->mallocFailed);
    +   if( !p ){
    +-    return SQLITE_NOMEM;
    ++    return SQLITE_NOMEM_BKPT;
    +   }
    + 
    +   /* If an older version of the function with a configured destructor is
    +@@ -132442,11 +145062,10 @@ SQLITE_PRIVATE int sqlite3CreateFunc(
    +   if( pDestructor ){
    +     pDestructor->nRef++;
    +   }
    +-  p->pDestructor = pDestructor;
    ++  p->u.pDestructor = pDestructor;
    +   p->funcFlags = (p->funcFlags & SQLITE_FUNC_ENCMASK) | extraFlags;
    +   testcase( p->funcFlags & SQLITE_DETERMINISTIC );
    +-  p->xFunc = xFunc;
    +-  p->xStep = xStep;
    ++  p->xSFunc = xSFunc ? xSFunc : xStep;
    +   p->xFinalize = xFinal;
    +   p->pUserData = pUserData;
    +   p->nArg = (u16)nArg;
    +@@ -132456,27 +145075,27 @@ SQLITE_PRIVATE int sqlite3CreateFunc(
    + /*
    + ** Create new user functions.
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_create_function(
    ++SQLITE_API int sqlite3_create_function(
    +   sqlite3 *db,
    +   const char *zFunc,
    +   int nArg,
    +   int enc,
    +   void *p,
    +-  void (*xFunc)(sqlite3_context*,int,sqlite3_value **),
    ++  void (*xSFunc)(sqlite3_context*,int,sqlite3_value **),
    +   void (*xStep)(sqlite3_context*,int,sqlite3_value **),
    +   void (*xFinal)(sqlite3_context*)
    + ){
    +-  return sqlite3_create_function_v2(db, zFunc, nArg, enc, p, xFunc, xStep,
    ++  return sqlite3_create_function_v2(db, zFunc, nArg, enc, p, xSFunc, xStep,
    +                                     xFinal, 0);
    + }
    + 
    +-SQLITE_API int SQLITE_STDCALL sqlite3_create_function_v2(
    ++SQLITE_API int sqlite3_create_function_v2(
    +   sqlite3 *db,
    +   const char *zFunc,
    +   int nArg,
    +   int enc,
    +   void *p,
    +-  void (*xFunc)(sqlite3_context*,int,sqlite3_value **),
    ++  void (*xSFunc)(sqlite3_context*,int,sqlite3_value **),
    +   void (*xStep)(sqlite3_context*,int,sqlite3_value **),
    +   void (*xFinal)(sqlite3_context*),
    +   void (*xDestroy)(void *)
    +@@ -132499,7 +145118,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_create_function_v2(
    +     pArg->xDestroy = xDestroy;
    +     pArg->pUserData = p;
    +   }
    +-  rc = sqlite3CreateFunc(db, zFunc, nArg, enc, p, xFunc, xStep, xFinal, pArg);
    ++  rc = sqlite3CreateFunc(db, zFunc, nArg, enc, p, xSFunc, xStep, xFinal, pArg);
    +   if( pArg && pArg->nRef==0 ){
    +     assert( rc!=SQLITE_OK );
    +     xDestroy(p);
    +@@ -132513,13 +145132,13 @@ SQLITE_API int SQLITE_STDCALL sqlite3_create_function_v2(
    + }
    + 
    + #ifndef SQLITE_OMIT_UTF16
    +-SQLITE_API int SQLITE_STDCALL sqlite3_create_function16(
    ++SQLITE_API int sqlite3_create_function16(
    +   sqlite3 *db,
    +   const void *zFunctionName,
    +   int nArg,
    +   int eTextRep,
    +   void *p,
    +-  void (*xFunc)(sqlite3_context*,int,sqlite3_value**),
    ++  void (*xSFunc)(sqlite3_context*,int,sqlite3_value**),
    +   void (*xStep)(sqlite3_context*,int,sqlite3_value**),
    +   void (*xFinal)(sqlite3_context*)
    + ){
    +@@ -132532,7 +145151,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_create_function16(
    +   sqlite3_mutex_enter(db->mutex);
    +   assert( !db->mallocFailed );
    +   zFunc8 = sqlite3Utf16to8(db, zFunctionName, -1, SQLITE_UTF16NATIVE);
    +-  rc = sqlite3CreateFunc(db, zFunc8, nArg, eTextRep, p, xFunc, xStep, xFinal,0);
    ++  rc = sqlite3CreateFunc(db, zFunc8, nArg, eTextRep, p, xSFunc,xStep,xFinal,0);
    +   sqlite3DbFree(db, zFunc8);
    +   rc = sqlite3ApiExit(db, rc);
    +   sqlite3_mutex_leave(db->mutex);
    +@@ -132553,12 +145172,11 @@ SQLITE_API int SQLITE_STDCALL sqlite3_create_function16(
    + ** A global function must exist in order for name resolution to work
    + ** properly.
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_overload_function(
    ++SQLITE_API int sqlite3_overload_function(
    +   sqlite3 *db,
    +   const char *zName,
    +   int nArg
    + ){
    +-  int nName = sqlite3Strlen30(zName);
    +   int rc = SQLITE_OK;
    + 
    + #ifdef SQLITE_ENABLE_API_ARMOR
    +@@ -132567,7 +145185,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_overload_function(
    +   }
    + #endif
    +   sqlite3_mutex_enter(db->mutex);
    +-  if( sqlite3FindFunction(db, zName, nName, nArg, SQLITE_UTF8, 0)==0 ){
    ++  if( sqlite3FindFunction(db, zName, nArg, SQLITE_UTF8, 0)==0 ){
    +     rc = sqlite3CreateFunc(db, zName, nArg, SQLITE_UTF8,
    +                            0, sqlite3InvalidFunction, 0, 0, 0);
    +   }
    +@@ -132585,7 +145203,8 @@ SQLITE_API int SQLITE_STDCALL sqlite3_overload_function(
    + ** trace is a pointer to a function that is invoked at the start of each
    + ** SQL statement.
    + */
    +-SQLITE_API void *SQLITE_STDCALL sqlite3_trace(sqlite3 *db, void (*xTrace)(void*,const char*), void *pArg){
    ++#ifndef SQLITE_OMIT_DEPRECATED
    ++SQLITE_API void *sqlite3_trace(sqlite3 *db, void(*xTrace)(void*,const char*), void *pArg){
    +   void *pOld;
    + 
    + #ifdef SQLITE_ENABLE_API_ARMOR
    +@@ -132596,11 +145215,38 @@ SQLITE_API void *SQLITE_STDCALL sqlite3_trace(sqlite3 *db, void (*xTrace)(void*,
    + #endif
    +   sqlite3_mutex_enter(db->mutex);
    +   pOld = db->pTraceArg;
    +-  db->xTrace = xTrace;
    ++  db->mTrace = xTrace ? SQLITE_TRACE_LEGACY : 0;
    ++  db->xTrace = (int(*)(u32,void*,void*,void*))xTrace;
    +   db->pTraceArg = pArg;
    +   sqlite3_mutex_leave(db->mutex);
    +   return pOld;
    + }
    ++#endif /* SQLITE_OMIT_DEPRECATED */
    ++
    ++/* Register a trace callback using the version-2 interface.
    ++*/
    ++SQLITE_API int sqlite3_trace_v2(
    ++  sqlite3 *db,                               /* Trace this connection */
    ++  unsigned mTrace,                           /* Mask of events to be traced */
    ++  int(*xTrace)(unsigned,void*,void*,void*),  /* Callback to invoke */
    ++  void *pArg                                 /* Context */
    ++){
    ++#ifdef SQLITE_ENABLE_API_ARMOR
    ++  if( !sqlite3SafetyCheckOk(db) ){
    ++    return SQLITE_MISUSE_BKPT;
    ++  }
    ++#endif
    ++  sqlite3_mutex_enter(db->mutex);
    ++  if( mTrace==0 ) xTrace = 0;
    ++  if( xTrace==0 ) mTrace = 0;
    ++  db->mTrace = mTrace;
    ++  db->xTrace = xTrace;
    ++  db->pTraceArg = pArg;
    ++  sqlite3_mutex_leave(db->mutex);
    ++  return SQLITE_OK;
    ++}
    ++
    ++#ifndef SQLITE_OMIT_DEPRECATED
    + /*
    + ** Register a profile function.  The pArg from the previously registered 
    + ** profile function is returned.  
    +@@ -132609,7 +145255,7 @@ SQLITE_API void *SQLITE_STDCALL sqlite3_trace(sqlite3 *db, void (*xTrace)(void*,
    + ** profile is a pointer to a function that is invoked at the conclusion of
    + ** each SQL statement that is run.
    + */
    +-SQLITE_API void *SQLITE_STDCALL sqlite3_profile(
    ++SQLITE_API void *sqlite3_profile(
    +   sqlite3 *db,
    +   void (*xProfile)(void*,const char*,sqlite_uint64),
    +   void *pArg
    +@@ -132629,6 +145275,7 @@ SQLITE_API void *SQLITE_STDCALL sqlite3_profile(
    +   sqlite3_mutex_leave(db->mutex);
    +   return pOld;
    + }
    ++#endif /* SQLITE_OMIT_DEPRECATED */
    + #endif /* SQLITE_OMIT_TRACE */
    + 
    + /*
    +@@ -132636,7 +145283,7 @@ SQLITE_API void *SQLITE_STDCALL sqlite3_profile(
    + ** If the invoked function returns non-zero, then the commit becomes a
    + ** rollback.
    + */
    +-SQLITE_API void *SQLITE_STDCALL sqlite3_commit_hook(
    ++SQLITE_API void *sqlite3_commit_hook(
    +   sqlite3 *db,              /* Attach the hook to this database */
    +   int (*xCallback)(void*),  /* Function to invoke on each commit */
    +   void *pArg                /* Argument to the function */
    +@@ -132661,7 +145308,7 @@ SQLITE_API void *SQLITE_STDCALL sqlite3_commit_hook(
    + ** Register a callback to be invoked each time a row is updated,
    + ** inserted or deleted using this database connection.
    + */
    +-SQLITE_API void *SQLITE_STDCALL sqlite3_update_hook(
    ++SQLITE_API void *sqlite3_update_hook(
    +   sqlite3 *db,              /* Attach the hook to this database */
    +   void (*xCallback)(void*,int,char const *,char const *,sqlite_int64),
    +   void *pArg                /* Argument to the function */
    +@@ -132686,7 +145333,7 @@ SQLITE_API void *SQLITE_STDCALL sqlite3_update_hook(
    + ** Register a callback to be invoked each time a transaction is rolled
    + ** back by this database connection.
    + */
    +-SQLITE_API void *SQLITE_STDCALL sqlite3_rollback_hook(
    ++SQLITE_API void *sqlite3_rollback_hook(
    +   sqlite3 *db,              /* Attach the hook to this database */
    +   void (*xCallback)(void*), /* Callback function */
    +   void *pArg                /* Argument to the function */
    +@@ -132707,6 +145354,27 @@ SQLITE_API void *SQLITE_STDCALL sqlite3_rollback_hook(
    +   return pRet;
    + }
    + 
    ++#ifdef SQLITE_ENABLE_PREUPDATE_HOOK
    ++/*
    ++** Register a callback to be invoked each time a row is updated,
    ++** inserted or deleted using this database connection.
    ++*/
    ++SQLITE_API void *sqlite3_preupdate_hook(
    ++  sqlite3 *db,              /* Attach the hook to this database */
    ++  void(*xCallback)(         /* Callback function */
    ++    void*,sqlite3*,int,char const*,char const*,sqlite3_int64,sqlite3_int64),
    ++  void *pArg                /* First callback argument */
    ++){
    ++  void *pRet;
    ++  sqlite3_mutex_enter(db->mutex);
    ++  pRet = db->pPreUpdateArg;
    ++  db->xPreUpdateCallback = xCallback;
    ++  db->pPreUpdateArg = pArg;
    ++  sqlite3_mutex_leave(db->mutex);
    ++  return pRet;
    ++}
    ++#endif /* SQLITE_ENABLE_PREUPDATE_HOOK */
    ++
    + #ifndef SQLITE_OMIT_WAL
    + /*
    + ** The sqlite3_wal_hook() callback registered by sqlite3_wal_autocheckpoint().
    +@@ -132740,7 +145408,7 @@ SQLITE_PRIVATE int sqlite3WalDefaultHook(
    + ** using sqlite3_wal_hook() disables the automatic checkpoint mechanism
    + ** configured by this function.
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_wal_autocheckpoint(sqlite3 *db, int nFrame){
    ++SQLITE_API int sqlite3_wal_autocheckpoint(sqlite3 *db, int nFrame){
    + #ifdef SQLITE_OMIT_WAL
    +   UNUSED_PARAMETER(db);
    +   UNUSED_PARAMETER(nFrame);
    +@@ -132761,7 +145429,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_wal_autocheckpoint(sqlite3 *db, int nFrame
    + ** Register a callback to be invoked each time a transaction is written
    + ** into the write-ahead-log by this database connection.
    + */
    +-SQLITE_API void *SQLITE_STDCALL sqlite3_wal_hook(
    ++SQLITE_API void *sqlite3_wal_hook(
    +   sqlite3 *db,                    /* Attach the hook to this db handle */
    +   int(*xCallback)(void *, sqlite3*, const char*, int),
    +   void *pArg                      /* First argument passed to xCallback() */
    +@@ -132788,7 +145456,7 @@ SQLITE_API void *SQLITE_STDCALL sqlite3_wal_hook(
    + /*
    + ** Checkpoint database zDb.
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_wal_checkpoint_v2(
    ++SQLITE_API int sqlite3_wal_checkpoint_v2(
    +   sqlite3 *db,                    /* Database handle */
    +   const char *zDb,                /* Name of attached database (or NULL) */
    +   int eMode,                      /* SQLITE_CHECKPOINT_* value */
    +@@ -132832,6 +145500,13 @@ SQLITE_API int SQLITE_STDCALL sqlite3_wal_checkpoint_v2(
    +     sqlite3Error(db, rc);
    +   }
    +   rc = sqlite3ApiExit(db, rc);
    ++
    ++  /* If there are no active statements, clear the interrupt flag at this
    ++  ** point.  */
    ++  if( db->nVdbeActive==0 ){
    ++    db->u1.isInterrupted = 0;
    ++  }
    ++
    +   sqlite3_mutex_leave(db->mutex);
    +   return rc;
    + #endif
    +@@ -132843,7 +145518,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_wal_checkpoint_v2(
    + ** to contains a zero-length string, all attached databases are 
    + ** checkpointed.
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_wal_checkpoint(sqlite3 *db, const char *zDb){
    ++SQLITE_API int sqlite3_wal_checkpoint(sqlite3 *db, const char *zDb){
    +   /* EVIDENCE-OF: R-41613-20553 The sqlite3_wal_checkpoint(D,X) is equivalent to
    +   ** sqlite3_wal_checkpoint_v2(D,X,SQLITE_CHECKPOINT_PASSIVE,0,0). */
    +   return sqlite3_wal_checkpoint_v2(db,zDb,SQLITE_CHECKPOINT_PASSIVE,0,0);
    +@@ -132867,7 +145542,8 @@ SQLITE_API int SQLITE_STDCALL sqlite3_wal_checkpoint(sqlite3 *db, const char *zD
    + ** checkpointed. If an error is encountered it is returned immediately -
    + ** no attempt is made to checkpoint any remaining databases.
    + **
    +-** Parameter eMode is one of SQLITE_CHECKPOINT_PASSIVE, FULL or RESTART.
    ++** Parameter eMode is one of SQLITE_CHECKPOINT_PASSIVE, FULL, RESTART
    ++** or TRUNCATE.
    + */
    + SQLITE_PRIVATE int sqlite3Checkpoint(sqlite3 *db, int iDb, int eMode, int *pnLog, int *pnCkpt){
    +   int rc = SQLITE_OK;             /* Return code */
    +@@ -132934,17 +145610,17 @@ SQLITE_PRIVATE int sqlite3TempInMemory(const sqlite3 *db){
    + ** Return UTF-8 encoded English language explanation of the most recent
    + ** error.
    + */
    +-SQLITE_API const char *SQLITE_STDCALL sqlite3_errmsg(sqlite3 *db){
    ++SQLITE_API const char *sqlite3_errmsg(sqlite3 *db){
    +   const char *z;
    +   if( !db ){
    +-    return sqlite3ErrStr(SQLITE_NOMEM);
    ++    return sqlite3ErrStr(SQLITE_NOMEM_BKPT);
    +   }
    +   if( !sqlite3SafetyCheckSickOrOk(db) ){
    +     return sqlite3ErrStr(SQLITE_MISUSE_BKPT);
    +   }
    +   sqlite3_mutex_enter(db->mutex);
    +   if( db->mallocFailed ){
    +-    z = sqlite3ErrStr(SQLITE_NOMEM);
    ++    z = sqlite3ErrStr(SQLITE_NOMEM_BKPT);
    +   }else{
    +     testcase( db->pErr==0 );
    +     z = (char*)sqlite3_value_text(db->pErr);
    +@@ -132962,17 +145638,14 @@ SQLITE_API const char *SQLITE_STDCALL sqlite3_errmsg(sqlite3 *db){
    + ** Return UTF-16 encoded English language explanation of the most recent
    + ** error.
    + */
    +-SQLITE_API const void *SQLITE_STDCALL sqlite3_errmsg16(sqlite3 *db){
    ++SQLITE_API const void *sqlite3_errmsg16(sqlite3 *db){
    +   static const u16 outOfMem[] = {
    +     'o', 'u', 't', ' ', 'o', 'f', ' ', 'm', 'e', 'm', 'o', 'r', 'y', 0
    +   };
    +   static const u16 misuse[] = {
    +-    'l', 'i', 'b', 'r', 'a', 'r', 'y', ' ', 
    +-    'r', 'o', 'u', 't', 'i', 'n', 'e', ' ', 
    +-    'c', 'a', 'l', 'l', 'e', 'd', ' ', 
    +-    'o', 'u', 't', ' ', 
    +-    'o', 'f', ' ', 
    +-    's', 'e', 'q', 'u', 'e', 'n', 'c', 'e', 0
    ++    'b', 'a', 'd', ' ', 'p', 'a', 'r', 'a', 'm', 'e', 't', 'e', 'r', ' ',
    ++    'o', 'r', ' ', 'o', 't', 'h', 'e', 'r', ' ', 'A', 'P', 'I', ' ',
    ++    'm', 'i', 's', 'u', 's', 'e', 0
    +   };
    + 
    +   const void *z;
    +@@ -132996,7 +145669,7 @@ SQLITE_API const void *SQLITE_STDCALL sqlite3_errmsg16(sqlite3 *db){
    +     ** be cleared before returning. Do this directly, instead of via
    +     ** sqlite3ApiExit(), to avoid setting the database handle error message.
    +     */
    +-    db->mallocFailed = 0;
    ++    sqlite3OomClear(db);
    +   }
    +   sqlite3_mutex_leave(db->mutex);
    +   return z;
    +@@ -133007,31 +145680,34 @@ SQLITE_API const void *SQLITE_STDCALL sqlite3_errmsg16(sqlite3 *db){
    + ** Return the most recent error code generated by an SQLite routine. If NULL is
    + ** passed to this function, we assume a malloc() failed during sqlite3_open().
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_errcode(sqlite3 *db){
    ++SQLITE_API int sqlite3_errcode(sqlite3 *db){
    +   if( db && !sqlite3SafetyCheckSickOrOk(db) ){
    +     return SQLITE_MISUSE_BKPT;
    +   }
    +   if( !db || db->mallocFailed ){
    +-    return SQLITE_NOMEM;
    ++    return SQLITE_NOMEM_BKPT;
    +   }
    +   return db->errCode & db->errMask;
    + }
    +-SQLITE_API int SQLITE_STDCALL sqlite3_extended_errcode(sqlite3 *db){
    ++SQLITE_API int sqlite3_extended_errcode(sqlite3 *db){
    +   if( db && !sqlite3SafetyCheckSickOrOk(db) ){
    +     return SQLITE_MISUSE_BKPT;
    +   }
    +   if( !db || db->mallocFailed ){
    +-    return SQLITE_NOMEM;
    ++    return SQLITE_NOMEM_BKPT;
    +   }
    +   return db->errCode;
    + }
    ++SQLITE_API int sqlite3_system_errno(sqlite3 *db){
    ++  return db ? db->iSysErrno : 0;
    ++}  
    + 
    + /*
    + ** Return a string that describes the kind of error specified in the
    + ** argument.  For now, this simply calls the internal sqlite3ErrStr()
    + ** function.
    + */
    +-SQLITE_API const char *SQLITE_STDCALL sqlite3_errstr(int rc){
    ++SQLITE_API const char *sqlite3_errstr(int rc){
    +   return sqlite3ErrStr(rc);
    + }
    + 
    +@@ -133101,7 +145777,7 @@ static int createCollation(
    +   }
    + 
    +   pColl = sqlite3FindCollSeq(db, (u8)enc2, zName, 1);
    +-  if( pColl==0 ) return SQLITE_NOMEM;
    ++  if( pColl==0 ) return SQLITE_NOMEM_BKPT;
    +   pColl->xCmp = xCompare;
    +   pColl->pUser = pCtx;
    +   pColl->xDel = xDel;
    +@@ -133149,8 +145825,8 @@ static const int aHardLimit[] = {
    + #if SQLITE_MAX_VDBE_OP<40
    + # error SQLITE_MAX_VDBE_OP must be at least 40
    + #endif
    +-#if SQLITE_MAX_FUNCTION_ARG<0 || SQLITE_MAX_FUNCTION_ARG>1000
    +-# error SQLITE_MAX_FUNCTION_ARG must be between 0 and 1000
    ++#if SQLITE_MAX_FUNCTION_ARG<0 || SQLITE_MAX_FUNCTION_ARG>127
    ++# error SQLITE_MAX_FUNCTION_ARG must be between 0 and 127
    + #endif
    + #if SQLITE_MAX_ATTACHED<0 || SQLITE_MAX_ATTACHED>125
    + # error SQLITE_MAX_ATTACHED must be between 0 and 125
    +@@ -133179,7 +145855,7 @@ static const int aHardLimit[] = {
    + ** It merely prevents new constructs that exceed the limit
    + ** from forming.
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_limit(sqlite3 *db, int limitId, int newLimit){
    ++SQLITE_API int sqlite3_limit(sqlite3 *db, int limitId, int newLimit){
    +   int oldLimit;
    + 
    + #ifdef SQLITE_ENABLE_API_ARMOR
    +@@ -133280,7 +145956,7 @@ SQLITE_PRIVATE int sqlite3ParseUri(
    + 
    +     for(iIn=0; iIn<nUri; iIn++) nByte += (zUri[iIn]=='&');
    +     zFile = sqlite3_malloc64(nByte);
    +-    if( !zFile ) return SQLITE_NOMEM;
    ++    if( !zFile ) return SQLITE_NOMEM_BKPT;
    + 
    +     iIn = 5;
    + #ifdef SQLITE_ALLOW_URI_AUTHORITY
    +@@ -133331,6 +146007,7 @@ SQLITE_PRIVATE int sqlite3ParseUri(
    + 
    +         assert( octet>=0 && octet<256 );
    +         if( octet==0 ){
    ++#ifndef SQLITE_ENABLE_URI_00_ERROR
    +           /* This branch is taken when "%00" appears within the URI. In this
    +           ** case we ignore all text in the remainder of the path, name or
    +           ** value currently being parsed. So ignore the current character
    +@@ -133343,6 +146020,12 @@ SQLITE_PRIVATE int sqlite3ParseUri(
    +             iIn++;
    +           }
    +           continue;
    ++#else
    ++          /* If ENABLE_URI_00_ERROR is defined, "%00" in a URI is an error. */
    ++          *pzErrMsg = sqlite3_mprintf("unexpected %%00 in uri");
    ++          rc = SQLITE_ERROR;
    ++          goto parse_uri_out;
    ++#endif
    +         }
    +         c = octet;
    +       }else if( eState==1 && (c=='&' || c=='=') ){
    +@@ -133446,8 +146129,10 @@ SQLITE_PRIVATE int sqlite3ParseUri(
    + 
    +   }else{
    +     zFile = sqlite3_malloc64(nUri+2);
    +-    if( !zFile ) return SQLITE_NOMEM;
    +-    memcpy(zFile, zUri, nUri);
    ++    if( !zFile ) return SQLITE_NOMEM_BKPT;
    ++    if( nUri ){
    ++      memcpy(zFile, zUri, nUri);
    ++    }
    +     zFile[nUri] = '\0';
    +     zFile[nUri+1] = '\0';
    +     flags &= ~SQLITE_OPEN_URI;
    +@@ -133495,26 +146180,6 @@ static int openDatabase(
    +   if( rc ) return rc;
    + #endif
    + 
    +-  /* Only allow sensible combinations of bits in the flags argument.  
    +-  ** Throw an error if any non-sense combination is used.  If we
    +-  ** do not block illegal combinations here, it could trigger
    +-  ** assert() statements in deeper layers.  Sensible combinations
    +-  ** are:
    +-  **
    +-  **  1:  SQLITE_OPEN_READONLY
    +-  **  2:  SQLITE_OPEN_READWRITE
    +-  **  6:  SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE
    +-  */
    +-  assert( SQLITE_OPEN_READONLY  == 0x01 );
    +-  assert( SQLITE_OPEN_READWRITE == 0x02 );
    +-  assert( SQLITE_OPEN_CREATE    == 0x04 );
    +-  testcase( (1<<(flags&7))==0x02 ); /* READONLY */
    +-  testcase( (1<<(flags&7))==0x04 ); /* READWRITE */
    +-  testcase( (1<<(flags&7))==0x40 ); /* READWRITE | CREATE */
    +-  if( ((1<<(flags&7)) & 0x46)==0 ){
    +-    return SQLITE_MISUSE_BKPT;  /* IMP: R-65497-44594 */
    +-  }
    +-
    +   if( sqlite3GlobalConfig.bCoreMutex==0 ){
    +     isThreadsafe = 0;
    +   }else if( flags & SQLITE_OPEN_NOMUTEX ){
    +@@ -133524,6 +146189,7 @@ static int openDatabase(
    +   }else{
    +     isThreadsafe = sqlite3GlobalConfig.bFullMutex;
    +   }
    ++
    +   if( flags & SQLITE_OPEN_PRIVATECACHE ){
    +     flags &= ~SQLITE_OPEN_SHAREDCACHE;
    +   }else if( sqlite3GlobalConfig.sharedCacheEnabled ){
    +@@ -133556,13 +146222,20 @@ static int openDatabase(
    +   /* Allocate the sqlite data structure */
    +   db = sqlite3MallocZero( sizeof(sqlite3) );
    +   if( db==0 ) goto opendb_out;
    +-  if( isThreadsafe ){
    ++  if( isThreadsafe 
    ++#ifdef SQLITE_ENABLE_MULTITHREADED_CHECKS
    ++   || sqlite3GlobalConfig.bCoreMutex
    ++#endif
    ++  ){
    +     db->mutex = sqlite3MutexAlloc(SQLITE_MUTEX_RECURSIVE);
    +     if( db->mutex==0 ){
    +       sqlite3_free(db);
    +       db = 0;
    +       goto opendb_out;
    +     }
    ++    if( isThreadsafe==0 ){
    ++      sqlite3MutexWarnOnContention(db->mutex);
    ++    }
    +   }
    +   sqlite3_mutex_enter(db->mutex);
    +   db->errMask = 0xff;
    +@@ -133602,6 +146275,12 @@ static int openDatabase(
    + #endif
    + #if defined(SQLITE_ENABLE_OVERSIZE_CELL_CHECK)
    +                  | SQLITE_CellSizeCk
    ++#endif
    ++#if defined(SQLITE_ENABLE_FTS3_TOKENIZER)
    ++                 | SQLITE_Fts3Tokenizer
    ++#endif
    ++#if defined(SQLITE_ENABLE_QPSG)
    ++                 | SQLITE_EnableQPSG
    + #endif
    +       ;
    +   sqlite3HashInit(&db->aCollSeq);
    +@@ -133616,9 +146295,9 @@ static int openDatabase(
    +   ** EVIDENCE-OF: R-52786-44878 SQLite defines three built-in collating
    +   ** functions:
    +   */
    +-  createCollation(db, "BINARY", SQLITE_UTF8, 0, binCollFunc, 0);
    +-  createCollation(db, "BINARY", SQLITE_UTF16BE, 0, binCollFunc, 0);
    +-  createCollation(db, "BINARY", SQLITE_UTF16LE, 0, binCollFunc, 0);
    ++  createCollation(db, sqlite3StrBINARY, SQLITE_UTF8, 0, binCollFunc, 0);
    ++  createCollation(db, sqlite3StrBINARY, SQLITE_UTF16BE, 0, binCollFunc, 0);
    ++  createCollation(db, sqlite3StrBINARY, SQLITE_UTF16LE, 0, binCollFunc, 0);
    +   createCollation(db, "NOCASE", SQLITE_UTF8, 0, nocaseCollatingFunc, 0);
    +   createCollation(db, "RTRIM", SQLITE_UTF8, (void*)1, binCollFunc, 0);
    +   if( db->mallocFailed ){
    +@@ -133627,14 +146306,35 @@ static int openDatabase(
    +   /* EVIDENCE-OF: R-08308-17224 The default collating function for all
    +   ** strings is BINARY. 
    +   */
    +-  db->pDfltColl = sqlite3FindCollSeq(db, SQLITE_UTF8, "BINARY", 0);
    ++  db->pDfltColl = sqlite3FindCollSeq(db, SQLITE_UTF8, sqlite3StrBINARY, 0);
    +   assert( db->pDfltColl!=0 );
    + 
    +-  /* Parse the filename/URI argument. */
    ++  /* Parse the filename/URI argument
    ++  **
    ++  ** Only allow sensible combinations of bits in the flags argument.  
    ++  ** Throw an error if any non-sense combination is used.  If we
    ++  ** do not block illegal combinations here, it could trigger
    ++  ** assert() statements in deeper layers.  Sensible combinations
    ++  ** are:
    ++  **
    ++  **  1:  SQLITE_OPEN_READONLY
    ++  **  2:  SQLITE_OPEN_READWRITE
    ++  **  6:  SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE
    ++  */
    +   db->openFlags = flags;
    +-  rc = sqlite3ParseUri(zVfs, zFilename, &flags, &db->pVfs, &zOpen, &zErrMsg);
    ++  assert( SQLITE_OPEN_READONLY  == 0x01 );
    ++  assert( SQLITE_OPEN_READWRITE == 0x02 );
    ++  assert( SQLITE_OPEN_CREATE    == 0x04 );
    ++  testcase( (1<<(flags&7))==0x02 ); /* READONLY */
    ++  testcase( (1<<(flags&7))==0x04 ); /* READWRITE */
    ++  testcase( (1<<(flags&7))==0x40 ); /* READWRITE | CREATE */
    ++  if( ((1<<(flags&7)) & 0x46)==0 ){
    ++    rc = SQLITE_MISUSE_BKPT;  /* IMP: R-65497-44594 */
    ++  }else{
    ++    rc = sqlite3ParseUri(zVfs, zFilename, &flags, &db->pVfs, &zOpen, &zErrMsg);
    ++  }
    +   if( rc!=SQLITE_OK ){
    +-    if( rc==SQLITE_NOMEM ) db->mallocFailed = 1;
    ++    if( rc==SQLITE_NOMEM ) sqlite3OomFault(db);
    +     sqlite3ErrorWithMsg(db, rc, zErrMsg ? "%s" : 0, zErrMsg);
    +     sqlite3_free(zErrMsg);
    +     goto opendb_out;
    +@@ -133645,7 +146345,7 @@ static int openDatabase(
    +                         flags | SQLITE_OPEN_MAIN_DB);
    +   if( rc!=SQLITE_OK ){
    +     if( rc==SQLITE_IOERR_NOMEM ){
    +-      rc = SQLITE_NOMEM;
    ++      rc = SQLITE_NOMEM_BKPT;
    +     }
    +     sqlite3Error(db, rc);
    +     goto opendb_out;
    +@@ -133656,13 +146356,13 @@ static int openDatabase(
    +   sqlite3BtreeLeave(db->aDb[0].pBt);
    +   db->aDb[1].pSchema = sqlite3SchemaGet(db, 0);
    + 
    +-  /* The default safety_level for the main database is 'full'; for the temp
    +-  ** database it is 'NONE'. This matches the pager layer defaults.  
    ++  /* The default safety_level for the main database is FULL; for the temp
    ++  ** database it is OFF. This matches the pager layer defaults.  
    +   */
    +-  db->aDb[0].zName = "main";
    +-  db->aDb[0].safety_level = 3;
    +-  db->aDb[1].zName = "temp";
    +-  db->aDb[1].safety_level = 1;
    ++  db->aDb[0].zDbSName = "main";
    ++  db->aDb[0].safety_level = SQLITE_DEFAULT_SYNCHRONOUS+1;
    ++  db->aDb[1].zDbSName = "temp";
    ++  db->aDb[1].safety_level = PAGER_SYNCHRONOUS_OFF;
    + 
    +   db->magic = SQLITE_MAGIC_OPEN;
    +   if( db->mallocFailed ){
    +@@ -133674,12 +146374,21 @@ static int openDatabase(
    +   ** is accessed.
    +   */
    +   sqlite3Error(db, SQLITE_OK);
    +-  sqlite3RegisterBuiltinFunctions(db);
    ++  sqlite3RegisterPerConnectionBuiltinFunctions(db);
    ++  rc = sqlite3_errcode(db);
    ++
    ++#ifdef SQLITE_ENABLE_FTS5
    ++  /* Register any built-in FTS5 module before loading the automatic
    ++  ** extensions. This allows automatic extensions to register FTS5 
    ++  ** tokenizers and auxiliary functions.  */
    ++  if( !db->mallocFailed && rc==SQLITE_OK ){
    ++    rc = sqlite3Fts5Init(db);
    ++  }
    ++#endif
    + 
    +   /* Load automatic extensions - extensions that have been registered
    +   ** using the sqlite3_automatic_extension() API.
    +   */
    +-  rc = sqlite3_errcode(db);
    +   if( rc==SQLITE_OK ){
    +     sqlite3AutoLoadExtensions(db);
    +     rc = sqlite3_errcode(db);
    +@@ -133708,13 +146417,7 @@ static int openDatabase(
    +   }
    + #endif
    + 
    +-#ifdef SQLITE_ENABLE_FTS5
    +-  if( !db->mallocFailed && rc==SQLITE_OK ){
    +-    rc = sqlite3Fts5Init(db);
    +-  }
    +-#endif
    +-
    +-#ifdef SQLITE_ENABLE_ICU
    ++#if defined(SQLITE_ENABLE_ICU) || defined(SQLITE_ENABLE_ICU_COLLATIONS)
    +   if( !db->mallocFailed && rc==SQLITE_OK ){
    +     rc = sqlite3IcuInit(db);
    +   }
    +@@ -133726,6 +146429,12 @@ static int openDatabase(
    +   }
    + #endif
    + 
    ++#ifdef SQLITE_ENABLE_DBPAGE_VTAB
    ++  if( !db->mallocFailed && rc==SQLITE_OK){
    ++    rc = sqlite3DbpageRegister(db);
    ++  }
    ++#endif
    ++
    + #ifdef SQLITE_ENABLE_DBSTAT_VTAB
    +   if( !db->mallocFailed && rc==SQLITE_OK){
    +     rc = sqlite3DbstatRegister(db);
    +@@ -133738,6 +146447,12 @@ static int openDatabase(
    +   }
    + #endif
    + 
    ++#ifdef SQLITE_ENABLE_STMTVTAB
    ++  if( !db->mallocFailed && rc==SQLITE_OK){
    ++    rc = sqlite3StmtVtabInit(db);
    ++  }
    ++#endif
    ++
    +   /* -DSQLITE_DEFAULT_LOCKING_MODE=1 makes EXCLUSIVE the default locking
    +   ** mode.  -DSQLITE_DEFAULT_LOCKING_MODE=0 make NORMAL the default locking
    +   ** mode.  Doing nothing at all also makes NORMAL the default.
    +@@ -133757,7 +146472,6 @@ static int openDatabase(
    +   sqlite3_wal_autocheckpoint(db, SQLITE_DEFAULT_WAL_AUTOCHECKPOINT);
    + 
    + opendb_out:
    +-  sqlite3_free(zOpen);
    +   if( db ){
    +     assert( db->mutex!=0 || isThreadsafe==0
    +            || sqlite3GlobalConfig.bFullMutex==0 );
    +@@ -133779,20 +146493,38 @@ opendb_out:
    +     sqlite3GlobalConfig.xSqllog(pArg, db, zFilename, 0);
    +   }
    + #endif
    ++#if defined(SQLITE_HAS_CODEC)
    ++  if( rc==SQLITE_OK ){
    ++    const char *zKey;
    ++    if( (zKey = sqlite3_uri_parameter(zOpen, "hexkey"))!=0 && zKey[0] ){
    ++      u8 iByte;
    ++      int i;
    ++      char zDecoded[40];
    ++      for(i=0, iByte=0; i<sizeof(zDecoded)*2 && sqlite3Isxdigit(zKey[i]); i++){
    ++        iByte = (iByte<<4) + sqlite3HexToInt(zKey[i]);
    ++        if( (i&1)!=0 ) zDecoded[i/2] = iByte;
    ++      }
    ++      sqlite3_key_v2(db, 0, zDecoded, i/2);
    ++    }else if( (zKey = sqlite3_uri_parameter(zOpen, "key"))!=0 ){
    ++      sqlite3_key_v2(db, 0, zKey, sqlite3Strlen30(zKey));
    ++    }
    ++  }
    ++#endif
    ++  sqlite3_free(zOpen);
    +   return rc & 0xff;
    + }
    + 
    + /*
    + ** Open a new database handle.
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_open(
    ++SQLITE_API int sqlite3_open(
    +   const char *zFilename, 
    +   sqlite3 **ppDb 
    + ){
    +   return openDatabase(zFilename, ppDb,
    +                       SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE, 0);
    + }
    +-SQLITE_API int SQLITE_STDCALL sqlite3_open_v2(
    ++SQLITE_API int sqlite3_open_v2(
    +   const char *filename,   /* Database filename (UTF-8) */
    +   sqlite3 **ppDb,         /* OUT: SQLite db handle */
    +   int flags,              /* Flags */
    +@@ -133805,7 +146537,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_open_v2(
    + /*
    + ** Open a new database handle.
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_open16(
    ++SQLITE_API int sqlite3_open16(
    +   const void *zFilename, 
    +   sqlite3 **ppDb
    + ){
    +@@ -133833,7 +146565,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_open16(
    +       SCHEMA_ENC(*ppDb) = ENC(*ppDb) = SQLITE_UTF16NATIVE;
    +     }
    +   }else{
    +-    rc = SQLITE_NOMEM;
    ++    rc = SQLITE_NOMEM_BKPT;
    +   }
    +   sqlite3ValueFree(pVal);
    + 
    +@@ -133844,7 +146576,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_open16(
    + /*
    + ** Register a new collation sequence with the database handle db.
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_create_collation(
    ++SQLITE_API int sqlite3_create_collation(
    +   sqlite3* db, 
    +   const char *zName, 
    +   int enc, 
    +@@ -133857,7 +146589,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_create_collation(
    + /*
    + ** Register a new collation sequence with the database handle db.
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_create_collation_v2(
    ++SQLITE_API int sqlite3_create_collation_v2(
    +   sqlite3* db, 
    +   const char *zName, 
    +   int enc, 
    +@@ -133882,7 +146614,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_create_collation_v2(
    + /*
    + ** Register a new collation sequence with the database handle db.
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_create_collation16(
    ++SQLITE_API int sqlite3_create_collation16(
    +   sqlite3* db, 
    +   const void *zName,
    +   int enc, 
    +@@ -133912,7 +146644,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_create_collation16(
    + ** Register a collation sequence factory callback with the database handle
    + ** db. Replace any previously installed collation sequence factory.
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_collation_needed(
    ++SQLITE_API int sqlite3_collation_needed(
    +   sqlite3 *db, 
    +   void *pCollNeededArg, 
    +   void(*xCollNeeded)(void*,sqlite3*,int eTextRep,const char*)
    +@@ -133933,7 +146665,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_collation_needed(
    + ** Register a collation sequence factory callback with the database handle
    + ** db. Replace any previously installed collation sequence factory.
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_collation_needed16(
    ++SQLITE_API int sqlite3_collation_needed16(
    +   sqlite3 *db, 
    +   void *pCollNeededArg, 
    +   void(*xCollNeeded16)(void*,sqlite3*,int eTextRep,const void*)
    +@@ -133955,7 +146687,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_collation_needed16(
    + ** This function is now an anachronism. It used to be used to recover from a
    + ** malloc() failure, but SQLite now does this automatically.
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_global_recover(void){
    ++SQLITE_API int sqlite3_global_recover(void){
    +   return SQLITE_OK;
    + }
    + #endif
    +@@ -133966,7 +146698,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_global_recover(void){
    + ** by default.  Autocommit is disabled by a BEGIN statement and reenabled
    + ** by the next COMMIT or ROLLBACK.
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_get_autocommit(sqlite3 *db){
    ++SQLITE_API int sqlite3_get_autocommit(sqlite3 *db){
    + #ifdef SQLITE_ENABLE_API_ARMOR
    +   if( !sqlite3SafetyCheckOk(db) ){
    +     (void)SQLITE_MISUSE_BKPT;
    +@@ -133978,7 +146710,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_get_autocommit(sqlite3 *db){
    + 
    + /*
    + ** The following routines are substitutes for constants SQLITE_CORRUPT,
    +-** SQLITE_MISUSE, SQLITE_CANTOPEN, SQLITE_IOERR and possibly other error
    ++** SQLITE_MISUSE, SQLITE_CANTOPEN, SQLITE_NOMEM and possibly other error
    + ** constants.  They serve two purposes:
    + **
    + **   1.  Serve as a convenient place to set a breakpoint in a debugger
    +@@ -133987,28 +146719,39 @@ SQLITE_API int SQLITE_STDCALL sqlite3_get_autocommit(sqlite3 *db){
    + **   2.  Invoke sqlite3_log() to provide the source code location where
    + **       a low-level error is first detected.
    + */
    ++SQLITE_PRIVATE int sqlite3ReportError(int iErr, int lineno, const char *zType){
    ++  sqlite3_log(iErr, "%s at line %d of [%.10s]",
    ++              zType, lineno, 20+sqlite3_sourceid());
    ++  return iErr;
    ++}
    + SQLITE_PRIVATE int sqlite3CorruptError(int lineno){
    +   testcase( sqlite3GlobalConfig.xLog!=0 );
    +-  sqlite3_log(SQLITE_CORRUPT,
    +-              "database corruption at line %d of [%.10s]",
    +-              lineno, 20+sqlite3_sourceid());
    +-  return SQLITE_CORRUPT;
    ++  return sqlite3ReportError(SQLITE_CORRUPT, lineno, "database corruption");
    + }
    + SQLITE_PRIVATE int sqlite3MisuseError(int lineno){
    +   testcase( sqlite3GlobalConfig.xLog!=0 );
    +-  sqlite3_log(SQLITE_MISUSE, 
    +-              "misuse at line %d of [%.10s]",
    +-              lineno, 20+sqlite3_sourceid());
    +-  return SQLITE_MISUSE;
    ++  return sqlite3ReportError(SQLITE_MISUSE, lineno, "misuse");
    + }
    + SQLITE_PRIVATE int sqlite3CantopenError(int lineno){
    +   testcase( sqlite3GlobalConfig.xLog!=0 );
    +-  sqlite3_log(SQLITE_CANTOPEN, 
    +-              "cannot open file at line %d of [%.10s]",
    +-              lineno, 20+sqlite3_sourceid());
    +-  return SQLITE_CANTOPEN;
    ++  return sqlite3ReportError(SQLITE_CANTOPEN, lineno, "cannot open file");
    + }
    +-
    ++#ifdef SQLITE_DEBUG
    ++SQLITE_PRIVATE int sqlite3CorruptPgnoError(int lineno, Pgno pgno){
    ++  char zMsg[100];
    ++  sqlite3_snprintf(sizeof(zMsg), zMsg, "database corruption page %d", pgno);
    ++  testcase( sqlite3GlobalConfig.xLog!=0 );
    ++  return sqlite3ReportError(SQLITE_CORRUPT, lineno, zMsg);
    ++}
    ++SQLITE_PRIVATE int sqlite3NomemError(int lineno){
    ++  testcase( sqlite3GlobalConfig.xLog!=0 );
    ++  return sqlite3ReportError(SQLITE_NOMEM, lineno, "OOM");
    ++}
    ++SQLITE_PRIVATE int sqlite3IoerrnomemError(int lineno){
    ++  testcase( sqlite3GlobalConfig.xLog!=0 );
    ++  return sqlite3ReportError(SQLITE_IOERR_NOMEM, lineno, "I/O OOM error");
    ++}
    ++#endif
    + 
    + #ifndef SQLITE_OMIT_DEPRECATED
    + /*
    +@@ -134018,7 +146761,7 @@ SQLITE_PRIVATE int sqlite3CantopenError(int lineno){
    + ** SQLite no longer uses thread-specific data so this routine is now a
    + ** no-op.  It is retained for historical compatibility.
    + */
    +-SQLITE_API void SQLITE_STDCALL sqlite3_thread_cleanup(void){
    ++SQLITE_API void sqlite3_thread_cleanup(void){
    + }
    + #endif
    + 
    +@@ -134026,7 +146769,7 @@ SQLITE_API void SQLITE_STDCALL sqlite3_thread_cleanup(void){
    + ** Return meta information about a specific column of a database table.
    + ** See comment in sqlite3.h (sqlite.h.in) for details.
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_table_column_metadata(
    ++SQLITE_API int sqlite3_table_column_metadata(
    +   sqlite3 *db,                /* Connection handle */
    +   const char *zDbName,        /* Database name or NULL */
    +   const char *zTableName,     /* Table name */
    +@@ -134102,7 +146845,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_table_column_metadata(
    +   **        explicitly declared column. Copy meta information from *pCol.
    +   */ 
    +   if( pCol ){
    +-    zDataType = pCol->zType;
    ++    zDataType = sqlite3ColumnType(pCol,0);
    +     zCollSeq = pCol->zColl;
    +     notnull = pCol->notNull!=0;
    +     primarykey  = (pCol->colFlags & COLFLAG_PRIMKEY)!=0;
    +@@ -134112,7 +146855,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_table_column_metadata(
    +     primarykey = 1;
    +   }
    +   if( !zCollSeq ){
    +-    zCollSeq = "BINARY";
    ++    zCollSeq = sqlite3StrBINARY;
    +   }
    + 
    + error_out:
    +@@ -134144,7 +146887,7 @@ error_out:
    + /*
    + ** Sleep for a little while.  Return the amount of time slept.
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_sleep(int ms){
    ++SQLITE_API int sqlite3_sleep(int ms){
    +   sqlite3_vfs *pVfs;
    +   int rc;
    +   pVfs = sqlite3_vfs_find(0);
    +@@ -134160,7 +146903,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_sleep(int ms){
    + /*
    + ** Enable or disable the extended result codes.
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_extended_result_codes(sqlite3 *db, int onoff){
    ++SQLITE_API int sqlite3_extended_result_codes(sqlite3 *db, int onoff){
    + #ifdef SQLITE_ENABLE_API_ARMOR
    +   if( !sqlite3SafetyCheckOk(db) ) return SQLITE_MISUSE_BKPT;
    + #endif
    +@@ -134173,7 +146916,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_extended_result_codes(sqlite3 *db, int ono
    + /*
    + ** Invoke the xFileControl method on a particular database.
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_file_control(sqlite3 *db, const char *zDbName, int op, void *pArg){
    ++SQLITE_API int sqlite3_file_control(sqlite3 *db, const char *zDbName, int op, void *pArg){
    +   int rc = SQLITE_ERROR;
    +   Btree *pBtree;
    + 
    +@@ -134193,6 +146936,12 @@ SQLITE_API int SQLITE_STDCALL sqlite3_file_control(sqlite3 *db, const char *zDbN
    +     if( op==SQLITE_FCNTL_FILE_POINTER ){
    +       *(sqlite3_file**)pArg = fd;
    +       rc = SQLITE_OK;
    ++    }else if( op==SQLITE_FCNTL_VFS_POINTER ){
    ++      *(sqlite3_vfs**)pArg = sqlite3PagerVfs(pPager);
    ++      rc = SQLITE_OK;
    ++    }else if( op==SQLITE_FCNTL_JOURNAL_POINTER ){
    ++      *(sqlite3_file**)pArg = sqlite3PagerJrnlFile(pPager);
    ++      rc = SQLITE_OK;
    +     }else if( fd->pMethods ){
    +       rc = sqlite3OsFileControl(fd, op, pArg);
    +     }else{
    +@@ -134207,9 +146956,9 @@ SQLITE_API int SQLITE_STDCALL sqlite3_file_control(sqlite3 *db, const char *zDbN
    + /*
    + ** Interface to the testing logic.
    + */
    +-SQLITE_API int SQLITE_CDECL sqlite3_test_control(int op, ...){
    ++SQLITE_API int sqlite3_test_control(int op, ...){
    +   int rc = 0;
    +-#ifdef SQLITE_OMIT_BUILTIN_TEST
    ++#ifdef SQLITE_UNTESTABLE
    +   UNUSED_PARAMETER(op);
    + #else
    +   va_list ap;
    +@@ -134333,7 +147082,7 @@ SQLITE_API int SQLITE_CDECL sqlite3_test_control(int op, ...){
    +     */
    +     case SQLITE_TESTCTRL_ASSERT: {
    +       volatile int x = 0;
    +-      assert( (x = va_arg(ap,int))!=0 );
    ++      assert( /*side-effects-ok*/ (x = va_arg(ap,int))!=0 );
    +       rc = x;
    +       break;
    +     }
    +@@ -134345,7 +147094,7 @@ SQLITE_API int SQLITE_CDECL sqlite3_test_control(int op, ...){
    +     ** This action provides a run-time test to see how the ALWAYS and
    +     ** NEVER macros were defined at compile-time.
    +     **
    +-    ** The return value is ALWAYS(X).  
    ++    ** The return value is ALWAYS(X) if X is true, or 0 if X is false.
    +     **
    +     ** The recommended test is X==2.  If the return value is 2, that means
    +     ** ALWAYS() and NEVER() are both no-op pass-through macros, which is the
    +@@ -134368,7 +147117,7 @@ SQLITE_API int SQLITE_CDECL sqlite3_test_control(int op, ...){
    +     */
    +     case SQLITE_TESTCTRL_ALWAYS: {
    +       int x = va_arg(ap,int);
    +-      rc = ALWAYS(x);
    ++      rc = x ? ALWAYS(x) : 0;
    +       break;
    +     }
    + 
    +@@ -134435,22 +147184,6 @@ SQLITE_API int SQLITE_CDECL sqlite3_test_control(int op, ...){
    +     }
    + #endif 
    + 
    +-    /* sqlite3_test_control(SQLITE_TESTCTRL_SCRATCHMALLOC, sz, &pNew, pFree);
    +-    **
    +-    ** Pass pFree into sqlite3ScratchFree(). 
    +-    ** If sz>0 then allocate a scratch buffer into pNew.  
    +-    */
    +-    case SQLITE_TESTCTRL_SCRATCHMALLOC: {
    +-      void *pFree, **ppNew;
    +-      int sz;
    +-      sz = va_arg(ap, int);
    +-      ppNew = va_arg(ap, void**);
    +-      pFree = va_arg(ap, void*);
    +-      if( sz ) *ppNew = sqlite3ScratchMalloc(sz);
    +-      sqlite3ScratchFree(pFree);
    +-      break;
    +-    }
    +-
    +     /*   sqlite3_test_control(SQLITE_TESTCTRL_LOCALTIME_FAULT, int onoff);
    +     **
    +     ** If parameter onoff is non-zero, configure the wrappers so that all
    +@@ -134475,6 +147208,15 @@ SQLITE_API int SQLITE_CDECL sqlite3_test_control(int op, ...){
    +       break;
    +     }
    + 
    ++    /* Set the threshold at which OP_Once counters reset back to zero.
    ++    ** By default this is 0x7ffffffe (over 2 billion), but that value is
    ++    ** too big to test in a reasonable amount of time, so this control is
    ++    ** provided to set a small and easily reachable reset value.
    ++    */
    ++    case SQLITE_TESTCTRL_ONCE_RESET_THRESHOLD: {
    ++      sqlite3GlobalConfig.iOnceResetThreshold = va_arg(ap, int);
    ++      break;
    ++    }
    + 
    +     /*   sqlite3_test_control(SQLITE_TESTCTRL_VDBE_COVERAGE, xCallback, ptr);
    +     **
    +@@ -134535,9 +147277,25 @@ SQLITE_API int SQLITE_CDECL sqlite3_test_control(int op, ...){
    +       sqlite3_mutex_leave(db->mutex);
    +       break;
    +     }
    ++
    ++#if defined(YYCOVERAGE)
    ++    /*  sqlite3_test_control(SQLITE_TESTCTRL_PARSER_COVERAGE, FILE *out)
    ++    **
    ++    ** This test control (only available when SQLite is compiled with
    ++    ** -DYYCOVERAGE) writes a report onto "out" that shows all
    ++    ** state/lookahead combinations in the parser state machine
    ++    ** which are never exercised.  If any state is missed, make the
    ++    ** return code SQLITE_ERROR.
    ++    */
    ++    case SQLITE_TESTCTRL_PARSER_COVERAGE: {
    ++      FILE *out = va_arg(ap, FILE*);
    ++      if( sqlite3ParserCoverage(out) ) rc = SQLITE_ERROR;
    ++      break;
    ++    }
    ++#endif /* defined(YYCOVERAGE) */
    +   }
    +   va_end(ap);
    +-#endif /* SQLITE_OMIT_BUILTIN_TEST */
    ++#endif /* SQLITE_UNTESTABLE */
    +   return rc;
    + }
    + 
    +@@ -134552,7 +147310,7 @@ SQLITE_API int SQLITE_CDECL sqlite3_test_control(int op, ...){
    + ** parameter if it exists.  If the parameter does not exist, this routine
    + ** returns a NULL pointer.
    + */
    +-SQLITE_API const char *SQLITE_STDCALL sqlite3_uri_parameter(const char *zFilename, const char *zParam){
    ++SQLITE_API const char *sqlite3_uri_parameter(const char *zFilename, const char *zParam){
    +   if( zFilename==0 || zParam==0 ) return 0;
    +   zFilename += sqlite3Strlen30(zFilename) + 1;
    +   while( zFilename[0] ){
    +@@ -134567,7 +147325,7 @@ SQLITE_API const char *SQLITE_STDCALL sqlite3_uri_parameter(const char *zFilenam
    + /*
    + ** Return a boolean value for a query parameter.
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_uri_boolean(const char *zFilename, const char *zParam, int bDflt){
    ++SQLITE_API int sqlite3_uri_boolean(const char *zFilename, const char *zParam, int bDflt){
    +   const char *z = sqlite3_uri_parameter(zFilename, zParam);
    +   bDflt = bDflt!=0;
    +   return z ? sqlite3GetBoolean(z, bDflt) : bDflt;
    +@@ -134576,14 +147334,14 @@ SQLITE_API int SQLITE_STDCALL sqlite3_uri_boolean(const char *zFilename, const c
    + /*
    + ** Return a 64-bit integer value for a query parameter.
    + */
    +-SQLITE_API sqlite3_int64 SQLITE_STDCALL sqlite3_uri_int64(
    ++SQLITE_API sqlite3_int64 sqlite3_uri_int64(
    +   const char *zFilename,    /* Filename as passed to xOpen */
    +   const char *zParam,       /* URI parameter sought */
    +   sqlite3_int64 bDflt       /* return if parameter is missing */
    + ){
    +   const char *z = sqlite3_uri_parameter(zFilename, zParam);
    +   sqlite3_int64 v;
    +-  if( z && sqlite3DecOrHexToI64(z, &v)==SQLITE_OK ){
    ++  if( z && sqlite3DecOrHexToI64(z, &v)==0 ){
    +     bDflt = v;
    +   }
    +   return bDflt;
    +@@ -134593,22 +147351,15 @@ SQLITE_API sqlite3_int64 SQLITE_STDCALL sqlite3_uri_int64(
    + ** Return the Btree pointer identified by zDbName.  Return NULL if not found.
    + */
    + SQLITE_PRIVATE Btree *sqlite3DbNameToBtree(sqlite3 *db, const char *zDbName){
    +-  int i;
    +-  for(i=0; i<db->nDb; i++){
    +-    if( db->aDb[i].pBt
    +-     && (zDbName==0 || sqlite3StrICmp(zDbName, db->aDb[i].zName)==0)
    +-    ){
    +-      return db->aDb[i].pBt;
    +-    }
    +-  }
    +-  return 0;
    ++  int iDb = zDbName ? sqlite3FindDbName(db, zDbName) : 0;
    ++  return iDb<0 ? 0 : db->aDb[iDb].pBt;
    + }
    + 
    + /*
    + ** Return the filename of the database associated with a database
    + ** connection.
    + */
    +-SQLITE_API const char *SQLITE_STDCALL sqlite3_db_filename(sqlite3 *db, const char *zDbName){
    ++SQLITE_API const char *sqlite3_db_filename(sqlite3 *db, const char *zDbName){
    +   Btree *pBt;
    + #ifdef SQLITE_ENABLE_API_ARMOR
    +   if( !sqlite3SafetyCheckOk(db) ){
    +@@ -134624,7 +147375,7 @@ SQLITE_API const char *SQLITE_STDCALL sqlite3_db_filename(sqlite3 *db, const cha
    + ** Return 1 if database is read-only or 0 if read/write.  Return -1 if
    + ** no such database exists.
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_db_readonly(sqlite3 *db, const char *zDbName){
    ++SQLITE_API int sqlite3_db_readonly(sqlite3 *db, const char *zDbName){
    +   Btree *pBt;
    + #ifdef SQLITE_ENABLE_API_ARMOR
    +   if( !sqlite3SafetyCheckOk(db) ){
    +@@ -134636,6 +147387,173 @@ SQLITE_API int SQLITE_STDCALL sqlite3_db_readonly(sqlite3 *db, const char *zDbNa
    +   return pBt ? sqlite3BtreeIsReadonly(pBt) : -1;
    + }
    + 
    ++#ifdef SQLITE_ENABLE_SNAPSHOT
    ++/*
    ++** Obtain a snapshot handle for the snapshot of database zDb currently 
    ++** being read by handle db.
    ++*/
    ++SQLITE_API int sqlite3_snapshot_get(
    ++  sqlite3 *db, 
    ++  const char *zDb,
    ++  sqlite3_snapshot **ppSnapshot
    ++){
    ++  int rc = SQLITE_ERROR;
    ++#ifndef SQLITE_OMIT_WAL
    ++
    ++#ifdef SQLITE_ENABLE_API_ARMOR
    ++  if( !sqlite3SafetyCheckOk(db) ){
    ++    return SQLITE_MISUSE_BKPT;
    ++  }
    ++#endif
    ++  sqlite3_mutex_enter(db->mutex);
    ++
    ++  if( db->autoCommit==0 ){
    ++    int iDb = sqlite3FindDbName(db, zDb);
    ++    if( iDb==0 || iDb>1 ){
    ++      Btree *pBt = db->aDb[iDb].pBt;
    ++      if( 0==sqlite3BtreeIsInTrans(pBt) ){
    ++        rc = sqlite3BtreeBeginTrans(pBt, 0);
    ++        if( rc==SQLITE_OK ){
    ++          rc = sqlite3PagerSnapshotGet(sqlite3BtreePager(pBt), ppSnapshot);
    ++        }
    ++      }
    ++    }
    ++  }
    ++
    ++  sqlite3_mutex_leave(db->mutex);
    ++#endif   /* SQLITE_OMIT_WAL */
    ++  return rc;
    ++}
    ++
    ++/*
    ++** Open a read-transaction on the snapshot idendified by pSnapshot.
    ++*/
    ++SQLITE_API int sqlite3_snapshot_open(
    ++  sqlite3 *db, 
    ++  const char *zDb, 
    ++  sqlite3_snapshot *pSnapshot
    ++){
    ++  int rc = SQLITE_ERROR;
    ++#ifndef SQLITE_OMIT_WAL
    ++
    ++#ifdef SQLITE_ENABLE_API_ARMOR
    ++  if( !sqlite3SafetyCheckOk(db) ){
    ++    return SQLITE_MISUSE_BKPT;
    ++  }
    ++#endif
    ++  sqlite3_mutex_enter(db->mutex);
    ++  if( db->autoCommit==0 ){
    ++    int iDb;
    ++    iDb = sqlite3FindDbName(db, zDb);
    ++    if( iDb==0 || iDb>1 ){
    ++      Btree *pBt = db->aDb[iDb].pBt;
    ++      if( 0==sqlite3BtreeIsInReadTrans(pBt) ){
    ++        rc = sqlite3PagerSnapshotOpen(sqlite3BtreePager(pBt), pSnapshot);
    ++        if( rc==SQLITE_OK ){
    ++          rc = sqlite3BtreeBeginTrans(pBt, 0);
    ++          sqlite3PagerSnapshotOpen(sqlite3BtreePager(pBt), 0);
    ++        }
    ++      }
    ++    }
    ++  }
    ++
    ++  sqlite3_mutex_leave(db->mutex);
    ++#endif   /* SQLITE_OMIT_WAL */
    ++  return rc;
    ++}
    ++
    ++/*
    ++** Recover as many snapshots as possible from the wal file associated with
    ++** schema zDb of database db.
    ++*/
    ++SQLITE_API int sqlite3_snapshot_recover(sqlite3 *db, const char *zDb){
    ++  int rc = SQLITE_ERROR;
    ++  int iDb;
    ++#ifndef SQLITE_OMIT_WAL
    ++
    ++#ifdef SQLITE_ENABLE_API_ARMOR
    ++  if( !sqlite3SafetyCheckOk(db) ){
    ++    return SQLITE_MISUSE_BKPT;
    ++  }
    ++#endif
    ++
    ++  sqlite3_mutex_enter(db->mutex);
    ++  iDb = sqlite3FindDbName(db, zDb);
    ++  if( iDb==0 || iDb>1 ){
    ++    Btree *pBt = db->aDb[iDb].pBt;
    ++    if( 0==sqlite3BtreeIsInReadTrans(pBt) ){
    ++      rc = sqlite3BtreeBeginTrans(pBt, 0);
    ++      if( rc==SQLITE_OK ){
    ++        rc = sqlite3PagerSnapshotRecover(sqlite3BtreePager(pBt));
    ++        sqlite3BtreeCommit(pBt);
    ++      }
    ++    }
    ++  }
    ++  sqlite3_mutex_leave(db->mutex);
    ++#endif   /* SQLITE_OMIT_WAL */
    ++  return rc;
    ++}
    ++
    ++/*
    ++** Free a snapshot handle obtained from sqlite3_snapshot_get().
    ++*/
    ++SQLITE_API void sqlite3_snapshot_free(sqlite3_snapshot *pSnapshot){
    ++  sqlite3_free(pSnapshot);
    ++}
    ++#endif /* SQLITE_ENABLE_SNAPSHOT */
    ++
    ++#ifndef SQLITE_OMIT_COMPILEOPTION_DIAGS
    ++/*
    ++** Given the name of a compile-time option, return true if that option
    ++** was used and false if not.
    ++**
    ++** The name can optionally begin with "SQLITE_" but the "SQLITE_" prefix
    ++** is not required for a match.
    ++*/
    ++SQLITE_API int sqlite3_compileoption_used(const char *zOptName){
    ++  int i, n;
    ++  int nOpt;
    ++  const char **azCompileOpt;
    ++ 
    ++#if SQLITE_ENABLE_API_ARMOR
    ++  if( zOptName==0 ){
    ++    (void)SQLITE_MISUSE_BKPT;
    ++    return 0;
    ++  }
    ++#endif
    ++
    ++  azCompileOpt = sqlite3CompileOptions(&nOpt);
    ++
    ++  if( sqlite3StrNICmp(zOptName, "SQLITE_", 7)==0 ) zOptName += 7;
    ++  n = sqlite3Strlen30(zOptName);
    ++
    ++  /* Since nOpt is normally in single digits, a linear search is 
    ++  ** adequate. No need for a binary search. */
    ++  for(i=0; i<nOpt; i++){
    ++    if( sqlite3StrNICmp(zOptName, azCompileOpt[i], n)==0
    ++     && sqlite3IsIdChar((unsigned char)azCompileOpt[i][n])==0
    ++    ){
    ++      return 1;
    ++    }
    ++  }
    ++  return 0;
    ++}
    ++
    ++/*
    ++** Return the N-th compile-time option string.  If N is out of range,
    ++** return a NULL pointer.
    ++*/
    ++SQLITE_API const char *sqlite3_compileoption_get(int N){
    ++  int nOpt;
    ++  const char **azCompileOpt;
    ++  azCompileOpt = sqlite3CompileOptions(&nOpt);
    ++  if( N>=0 && N<nOpt ){
    ++    return azCompileOpt[N];
    ++  }
    ++  return 0;
    ++}
    ++#endif /* SQLITE_OMIT_COMPILEOPTION_DIAGS */
    ++
    + /************** End of main.c ************************************************/
    + /************** Begin file notify.c ******************************************/
    + /*
    +@@ -134785,7 +147703,7 @@ static void leaveMutex(void){
    + ** on the same "db".  If xNotify==0 then any prior callbacks are immediately
    + ** cancelled.
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_unlock_notify(
    ++SQLITE_API int sqlite3_unlock_notify(
    +   sqlite3 *db,
    +   void (*xNotify)(void **, int),
    +   void *pArg
    +@@ -135285,6 +148203,12 @@ SQLITE_PRIVATE void sqlite3ConnectionClosed(sqlite3 *db){
    + # define NDEBUG 1
    + #endif
    + 
    ++/* FTS3/FTS4 require virtual tables */
    ++#ifdef SQLITE_OMIT_VIRTUALTABLE
    ++# undef SQLITE_ENABLE_FTS3
    ++# undef SQLITE_ENABLE_FTS4
    ++#endif
    ++
    + /*
    + ** FTS4 is really an extension for FTS3.  It is enabled using the
    + ** SQLITE_ENABLE_FTS3 macro.  But to avoid confusion we also all
    +@@ -135772,6 +148696,7 @@ struct Fts3Table {
    +   ** statements is run and reset within a single virtual table API call. 
    +   */
    +   sqlite3_stmt *aStmt[40];
    ++  sqlite3_stmt *pSeekStmt;        /* Cache for fts3CursorSeekStmt() */
    + 
    +   char *zReadExprlist;
    +   char *zWriteExprlist;
    +@@ -135841,6 +148766,7 @@ struct Fts3Cursor {
    +   i16 eSearch;                    /* Search strategy (see below) */
    +   u8 isEof;                       /* True if at End Of Results */
    +   u8 isRequireSeek;               /* True if must seek pStmt to %_content row */
    ++  u8 bSeekStmt;                   /* True if pStmt is a seek */
    +   sqlite3_stmt *pStmt;            /* Prepared statement in use by the cursor */
    +   Fts3Expr *pExpr;                /* Parsed MATCH query string */
    +   int iLangid;                    /* Language being queried for */
    +@@ -136220,8 +149146,9 @@ SQLITE_PRIVATE int sqlite3Fts3PutVarint(char *p, sqlite_int64 v){
    + ** Return the number of bytes read, or 0 on error.
    + ** The value is stored in *v.
    + */
    +-SQLITE_PRIVATE int sqlite3Fts3GetVarint(const char *p, sqlite_int64 *v){
    +-  const char *pStart = p;
    ++SQLITE_PRIVATE int sqlite3Fts3GetVarint(const char *pBuf, sqlite_int64 *v){
    ++  const unsigned char *p = (const unsigned char*)pBuf;
    ++  const unsigned char *pStart = p;
    +   u32 a;
    +   u64 b;
    +   int shift;
    +@@ -136242,8 +149169,8 @@ SQLITE_PRIVATE int sqlite3Fts3GetVarint(const char *p, sqlite_int64 *v){
    + }
    + 
    + /*
    +-** Similar to sqlite3Fts3GetVarint(), except that the output is truncated to a
    +-** 32-bit integer before it is returned.
    ++** Similar to sqlite3Fts3GetVarint(), except that the output is truncated to 
    ++** a non-negative 32-bit integer before it is returned.
    + */
    + SQLITE_PRIVATE int sqlite3Fts3GetVarint32(const char *p, int *pi){
    +   u32 a;
    +@@ -136259,7 +149186,9 @@ SQLITE_PRIVATE int sqlite3Fts3GetVarint32(const char *p, int *pi){
    +   GETVARINT_STEP(a, p, 14, 0x3FFF,   0x200000, *pi, 3);
    +   GETVARINT_STEP(a, p, 21, 0x1FFFFF, 0x10000000, *pi, 4);
    +   a = (a & 0x0FFFFFFF );
    +-  *pi = (int)(a | ((u32)(*p & 0x0F) << 28));
    ++  *pi = (int)(a | ((u32)(*p & 0x07) << 28));
    ++  assert( 0==(a & 0x80000000) );
    ++  assert( *pi>=0 );
    +   return 5;
    + }
    + 
    +@@ -136363,6 +149292,7 @@ static int fts3DisconnectMethod(sqlite3_vtab *pVtab){
    +   assert( p->pSegments==0 );
    + 
    +   /* Free any prepared statements held */
    ++  sqlite3_finalize(p->pSeekStmt);
    +   for(i=0; i<SizeofArray(p->aStmt); i++){
    +     sqlite3_finalize(p->aStmt[i]);
    +   }
    +@@ -137088,65 +150018,66 @@ static int fts3InitVtab(
    +             break;
    +           }
    +         }
    +-        if( iOpt==SizeofArray(aFts4Opt) ){
    +-          sqlite3Fts3ErrMsg(pzErr, "unrecognized parameter: %s", z);
    +-          rc = SQLITE_ERROR;
    +-        }else{
    +-          switch( iOpt ){
    +-            case 0:               /* MATCHINFO */
    +-              if( strlen(zVal)!=4 || sqlite3_strnicmp(zVal, "fts3", 4) ){
    +-                sqlite3Fts3ErrMsg(pzErr, "unrecognized matchinfo: %s", zVal);
    +-                rc = SQLITE_ERROR;
    +-              }
    +-              bNoDocsize = 1;
    +-              break;
    ++        switch( iOpt ){
    ++          case 0:               /* MATCHINFO */
    ++            if( strlen(zVal)!=4 || sqlite3_strnicmp(zVal, "fts3", 4) ){
    ++              sqlite3Fts3ErrMsg(pzErr, "unrecognized matchinfo: %s", zVal);
    ++              rc = SQLITE_ERROR;
    ++            }
    ++            bNoDocsize = 1;
    ++            break;
    + 
    +-            case 1:               /* PREFIX */
    +-              sqlite3_free(zPrefix);
    +-              zPrefix = zVal;
    +-              zVal = 0;
    +-              break;
    ++          case 1:               /* PREFIX */
    ++            sqlite3_free(zPrefix);
    ++            zPrefix = zVal;
    ++            zVal = 0;
    ++            break;
    + 
    +-            case 2:               /* COMPRESS */
    +-              sqlite3_free(zCompress);
    +-              zCompress = zVal;
    +-              zVal = 0;
    +-              break;
    ++          case 2:               /* COMPRESS */
    ++            sqlite3_free(zCompress);
    ++            zCompress = zVal;
    ++            zVal = 0;
    ++            break;
    + 
    +-            case 3:               /* UNCOMPRESS */
    +-              sqlite3_free(zUncompress);
    +-              zUncompress = zVal;
    +-              zVal = 0;
    +-              break;
    ++          case 3:               /* UNCOMPRESS */
    ++            sqlite3_free(zUncompress);
    ++            zUncompress = zVal;
    ++            zVal = 0;
    ++            break;
    + 
    +-            case 4:               /* ORDER */
    +-              if( (strlen(zVal)!=3 || sqlite3_strnicmp(zVal, "asc", 3)) 
    +-               && (strlen(zVal)!=4 || sqlite3_strnicmp(zVal, "desc", 4)) 
    +-              ){
    +-                sqlite3Fts3ErrMsg(pzErr, "unrecognized order: %s", zVal);
    +-                rc = SQLITE_ERROR;
    +-              }
    +-              bDescIdx = (zVal[0]=='d' || zVal[0]=='D');
    +-              break;
    ++          case 4:               /* ORDER */
    ++            if( (strlen(zVal)!=3 || sqlite3_strnicmp(zVal, "asc", 3)) 
    ++             && (strlen(zVal)!=4 || sqlite3_strnicmp(zVal, "desc", 4)) 
    ++            ){
    ++              sqlite3Fts3ErrMsg(pzErr, "unrecognized order: %s", zVal);
    ++              rc = SQLITE_ERROR;
    ++            }
    ++            bDescIdx = (zVal[0]=='d' || zVal[0]=='D');
    ++            break;
    + 
    +-            case 5:              /* CONTENT */
    +-              sqlite3_free(zContent);
    +-              zContent = zVal;
    +-              zVal = 0;
    +-              break;
    ++          case 5:              /* CONTENT */
    ++            sqlite3_free(zContent);
    ++            zContent = zVal;
    ++            zVal = 0;
    ++            break;
    + 
    +-            case 6:              /* LANGUAGEID */
    +-              assert( iOpt==6 );
    +-              sqlite3_free(zLanguageid);
    +-              zLanguageid = zVal;
    +-              zVal = 0;
    +-              break;
    ++          case 6:              /* LANGUAGEID */
    ++            assert( iOpt==6 );
    ++            sqlite3_free(zLanguageid);
    ++            zLanguageid = zVal;
    ++            zVal = 0;
    ++            break;
    + 
    +-            case 7:              /* NOTINDEXED */
    +-              azNotindexed[nNotindexed++] = zVal;
    +-              zVal = 0;
    +-              break;
    +-          }
    ++          case 7:              /* NOTINDEXED */
    ++            azNotindexed[nNotindexed++] = zVal;
    ++            zVal = 0;
    ++            break;
    ++
    ++          default:
    ++            assert( iOpt==SizeofArray(aFts4Opt) );
    ++            sqlite3Fts3ErrMsg(pzErr, "unrecognized parameter: %s", z);
    ++            rc = SQLITE_ERROR;
    ++            break;
    +         }
    +         sqlite3_free(zVal);
    +       }
    +@@ -137234,9 +150165,9 @@ static int fts3InitVtab(
    +   p->pTokenizer = pTokenizer;
    +   p->nMaxPendingData = FTS3_MAX_PENDING_DATA;
    +   p->bHasDocsize = (isFts4 && bNoDocsize==0);
    +-  p->bHasStat = isFts4;
    +-  p->bFts4 = isFts4;
    +-  p->bDescIdx = bDescIdx;
    ++  p->bHasStat = (u8)isFts4;
    ++  p->bFts4 = (u8)isFts4;
    ++  p->bDescIdx = (u8)bDescIdx;
    +   p->nAutoincrmerge = 0xff;   /* 0xff means setting unknown */
    +   p->zContentTbl = zContent;
    +   p->zLanguageid = zLanguageid;
    +@@ -137267,7 +150198,9 @@ static int fts3InitVtab(
    +     char *z; 
    +     int n = 0;
    +     z = (char *)sqlite3Fts3NextToken(aCol[iCol], &n);
    +-    memcpy(zCsr, z, n);
    ++    if( n>0 ){
    ++      memcpy(zCsr, z, n);
    ++    }
    +     zCsr[n] = '\0';
    +     sqlite3Fts3Dequote(zCsr);
    +     p->azColumn[iCol] = zCsr;
    +@@ -137551,6 +150484,39 @@ static int fts3OpenMethod(sqlite3_vtab *pVTab, sqlite3_vtab_cursor **ppCsr){
    +   return SQLITE_OK;
    + }
    + 
    ++/*
    ++** Finalize the statement handle at pCsr->pStmt.
    ++**
    ++** Or, if that statement handle is one created by fts3CursorSeekStmt(),
    ++** and the Fts3Table.pSeekStmt slot is currently NULL, save the statement
    ++** pointer there instead of finalizing it.
    ++*/
    ++static void fts3CursorFinalizeStmt(Fts3Cursor *pCsr){
    ++  if( pCsr->bSeekStmt ){
    ++    Fts3Table *p = (Fts3Table *)pCsr->base.pVtab;
    ++    if( p->pSeekStmt==0 ){
    ++      p->pSeekStmt = pCsr->pStmt;
    ++      sqlite3_reset(pCsr->pStmt);
    ++      pCsr->pStmt = 0;
    ++    }
    ++    pCsr->bSeekStmt = 0;
    ++  }
    ++  sqlite3_finalize(pCsr->pStmt);
    ++}
    ++
    ++/*
    ++** Free all resources currently held by the cursor passed as the only
    ++** argument.
    ++*/
    ++static void fts3ClearCursor(Fts3Cursor *pCsr){
    ++  fts3CursorFinalizeStmt(pCsr);
    ++  sqlite3Fts3FreeDeferredTokens(pCsr);
    ++  sqlite3_free(pCsr->aDoclist);
    ++  sqlite3Fts3MIBufferFree(pCsr->pMIBuffer);
    ++  sqlite3Fts3ExprFree(pCsr->pExpr);
    ++  memset(&(&pCsr->base)[1], 0, sizeof(Fts3Cursor)-sizeof(sqlite3_vtab_cursor));
    ++}
    ++
    + /*
    + ** Close the cursor.  For additional information see the documentation
    + ** on the xClose method of the virtual table interface.
    +@@ -137558,11 +150524,7 @@ static int fts3OpenMethod(sqlite3_vtab *pVTab, sqlite3_vtab_cursor **ppCsr){
    + static int fts3CloseMethod(sqlite3_vtab_cursor *pCursor){
    +   Fts3Cursor *pCsr = (Fts3Cursor *)pCursor;
    +   assert( ((Fts3Table *)pCsr->base.pVtab)->pSegments==0 );
    +-  sqlite3_finalize(pCsr->pStmt);
    +-  sqlite3Fts3ExprFree(pCsr->pExpr);
    +-  sqlite3Fts3FreeDeferredTokens(pCsr);
    +-  sqlite3_free(pCsr->aDoclist);
    +-  sqlite3Fts3MIBufferFree(pCsr->pMIBuffer);
    ++  fts3ClearCursor(pCsr);
    +   assert( ((Fts3Table *)pCsr->base.pVtab)->pSegments==0 );
    +   sqlite3_free(pCsr);
    +   return SQLITE_OK;
    +@@ -137576,20 +150538,23 @@ static int fts3CloseMethod(sqlite3_vtab_cursor *pCursor){
    + **
    + ** (or the equivalent for a content=xxx table) and set pCsr->pStmt to
    + ** it. If an error occurs, return an SQLite error code.
    +-**
    +-** Otherwise, set *ppStmt to point to pCsr->pStmt and return SQLITE_OK.
    + */
    +-static int fts3CursorSeekStmt(Fts3Cursor *pCsr, sqlite3_stmt **ppStmt){
    ++static int fts3CursorSeekStmt(Fts3Cursor *pCsr){
    +   int rc = SQLITE_OK;
    +   if( pCsr->pStmt==0 ){
    +     Fts3Table *p = (Fts3Table *)pCsr->base.pVtab;
    +     char *zSql;
    +-    zSql = sqlite3_mprintf("SELECT %s WHERE rowid = ?", p->zReadExprlist);
    +-    if( !zSql ) return SQLITE_NOMEM;
    +-    rc = sqlite3_prepare_v2(p->db, zSql, -1, &pCsr->pStmt, 0);
    +-    sqlite3_free(zSql);
    ++    if( p->pSeekStmt ){
    ++      pCsr->pStmt = p->pSeekStmt;
    ++      p->pSeekStmt = 0;
    ++    }else{
    ++      zSql = sqlite3_mprintf("SELECT %s WHERE rowid = ?", p->zReadExprlist);
    ++      if( !zSql ) return SQLITE_NOMEM;
    ++      rc = sqlite3_prepare_v3(p->db, zSql,-1,SQLITE_PREPARE_PERSISTENT,&pCsr->pStmt,0);
    ++      sqlite3_free(zSql);
    ++    }
    ++    if( rc==SQLITE_OK ) pCsr->bSeekStmt = 1;
    +   }
    +-  *ppStmt = pCsr->pStmt;
    +   return rc;
    + }
    + 
    +@@ -137601,9 +150566,7 @@ static int fts3CursorSeekStmt(Fts3Cursor *pCsr, sqlite3_stmt **ppStmt){
    + static int fts3CursorSeek(sqlite3_context *pContext, Fts3Cursor *pCsr){
    +   int rc = SQLITE_OK;
    +   if( pCsr->isRequireSeek ){
    +-    sqlite3_stmt *pStmt = 0;
    +-
    +-    rc = fts3CursorSeekStmt(pCsr, &pStmt);
    ++    rc = fts3CursorSeekStmt(pCsr);
    +     if( rc==SQLITE_OK ){
    +       sqlite3_bind_int64(pCsr->pStmt, 1, pCsr->iPrevId);
    +       pCsr->isRequireSeek = 0;
    +@@ -137655,7 +150618,7 @@ static int fts3ScanInteriorNode(
    +   const char *zCsr = zNode;       /* Cursor to iterate through node */
    +   const char *zEnd = &zCsr[nNode];/* End of interior node buffer */
    +   char *zBuffer = 0;              /* Buffer to load terms into */
    +-  int nAlloc = 0;                 /* Size of allocated buffer */
    ++  i64 nAlloc = 0;                 /* Size of allocated buffer */
    +   int isFirstTerm = 1;            /* True when processing first term on page */
    +   sqlite3_int64 iChild;           /* Block id of child node to descend to */
    + 
    +@@ -137692,14 +150655,15 @@ static int fts3ScanInteriorNode(
    +     isFirstTerm = 0;
    +     zCsr += fts3GetVarint32(zCsr, &nSuffix);
    +     
    +-    if( nPrefix<0 || nSuffix<0 || &zCsr[nSuffix]>zEnd ){
    ++    assert( nPrefix>=0 && nSuffix>=0 );
    ++    if( nPrefix>zCsr-zNode || nSuffix>zEnd-zCsr ){
    +       rc = FTS_CORRUPT_VTAB;
    +       goto finish_scan;
    +     }
    +-    if( nPrefix+nSuffix>nAlloc ){
    ++    if( (i64)nPrefix+nSuffix>nAlloc ){
    +       char *zNew;
    +-      nAlloc = (nPrefix+nSuffix) * 2;
    +-      zNew = (char *)sqlite3_realloc(zBuffer, nAlloc);
    ++      nAlloc = ((i64)nPrefix+nSuffix) * 2;
    ++      zNew = (char *)sqlite3_realloc64(zBuffer, nAlloc);
    +       if( !zNew ){
    +         rc = SQLITE_NOMEM;
    +         goto finish_scan;
    +@@ -138502,7 +151466,7 @@ SQLITE_PRIVATE int sqlite3Fts3FirstFilter(
    +     fts3ColumnlistCopy(0, &p);
    +   }
    + 
    +-  while( p<pEnd && *p==0x01 ){
    ++  while( p<pEnd ){
    +     sqlite3_int64 iCol;
    +     p++;
    +     p += sqlite3Fts3GetVarint(p, &iCol);
    +@@ -139061,11 +152025,7 @@ static int fts3FilterMethod(
    +   assert( iIdx==nVal );
    + 
    +   /* In case the cursor has been used before, clear it now. */
    +-  sqlite3_finalize(pCsr->pStmt);
    +-  sqlite3_free(pCsr->aDoclist);
    +-  sqlite3Fts3MIBufferFree(pCsr->pMIBuffer);
    +-  sqlite3Fts3ExprFree(pCsr->pExpr);
    +-  memset(&pCursor[1], 0, sizeof(Fts3Cursor)-sizeof(sqlite3_vtab_cursor));
    ++  fts3ClearCursor(pCsr);
    + 
    +   /* Set the lower and upper bounds on docids to return */
    +   pCsr->iMinDocid = fts3DocidRange(pDocidGe, SMALLEST_INT64);
    +@@ -139123,13 +152083,13 @@ static int fts3FilterMethod(
    +       );
    +     }
    +     if( zSql ){
    +-      rc = sqlite3_prepare_v2(p->db, zSql, -1, &pCsr->pStmt, 0);
    ++      rc = sqlite3_prepare_v3(p->db,zSql,-1,SQLITE_PREPARE_PERSISTENT,&pCsr->pStmt,0);
    +       sqlite3_free(zSql);
    +     }else{
    +       rc = SQLITE_NOMEM;
    +     }
    +   }else if( eSearch==FTS3_DOCID_SEARCH ){
    +-    rc = fts3CursorSeekStmt(pCsr, &pCsr->pStmt);
    ++    rc = fts3CursorSeekStmt(pCsr);
    +     if( rc==SQLITE_OK ){
    +       rc = sqlite3_bind_value(pCsr->pStmt, 1, pCons);
    +     }
    +@@ -139144,7 +152104,12 @@ static int fts3FilterMethod(
    + ** routine to find out if it has reached the end of a result set.
    + */
    + static int fts3EofMethod(sqlite3_vtab_cursor *pCursor){
    +-  return ((Fts3Cursor *)pCursor)->isEof;
    ++  Fts3Cursor *pCsr = (Fts3Cursor*)pCursor;
    ++  if( pCsr->isEof ){
    ++    fts3ClearCursor(pCsr);
    ++    pCsr->isEof = 1;
    ++  }
    ++  return pCsr->isEof;
    + }
    + 
    + /* 
    +@@ -139182,33 +152147,37 @@ static int fts3ColumnMethod(
    +   /* The column value supplied by SQLite must be in range. */
    +   assert( iCol>=0 && iCol<=p->nColumn+2 );
    + 
    +-  if( iCol==p->nColumn+1 ){
    +-    /* This call is a request for the "docid" column. Since "docid" is an 
    +-    ** alias for "rowid", use the xRowid() method to obtain the value.
    +-    */
    +-    sqlite3_result_int64(pCtx, pCsr->iPrevId);
    +-  }else if( iCol==p->nColumn ){
    +-    /* The extra column whose name is the same as the table.
    +-    ** Return a blob which is a pointer to the cursor.  */
    +-    sqlite3_result_blob(pCtx, &pCsr, sizeof(pCsr), SQLITE_TRANSIENT);
    +-  }else if( iCol==p->nColumn+2 && pCsr->pExpr ){
    +-    sqlite3_result_int64(pCtx, pCsr->iLangid);
    +-  }else{
    +-    /* The requested column is either a user column (one that contains 
    +-    ** indexed data), or the language-id column.  */
    +-    rc = fts3CursorSeek(0, pCsr);
    ++  switch( iCol-p->nColumn ){
    ++    case 0:
    ++      /* The special 'table-name' column */
    ++      sqlite3_result_pointer(pCtx, pCsr, "fts3cursor", 0);
    ++      break;
    + 
    +-    if( rc==SQLITE_OK ){
    +-      if( iCol==p->nColumn+2 ){
    +-        int iLangid = 0;
    +-        if( p->zLanguageid ){
    +-          iLangid = sqlite3_column_int(pCsr->pStmt, p->nColumn+1);
    +-        }
    +-        sqlite3_result_int(pCtx, iLangid);
    +-      }else if( sqlite3_data_count(pCsr->pStmt)>(iCol+1) ){
    ++    case 1:
    ++      /* The docid column */
    ++      sqlite3_result_int64(pCtx, pCsr->iPrevId);
    ++      break;
    ++
    ++    case 2:
    ++      if( pCsr->pExpr ){
    ++        sqlite3_result_int64(pCtx, pCsr->iLangid);
    ++        break;
    ++      }else if( p->zLanguageid==0 ){
    ++        sqlite3_result_int(pCtx, 0);
    ++        break;
    ++      }else{
    ++        iCol = p->nColumn;
    ++        /* fall-through */
    ++      }
    ++
    ++    default:
    ++      /* A user column. Or, if this is a full-table scan, possibly the
    ++      ** language-id column. Seek the cursor. */
    ++      rc = fts3CursorSeek(0, pCsr);
    ++      if( rc==SQLITE_OK && sqlite3_data_count(pCsr->pStmt)-1>iCol ){
    +         sqlite3_result_value(pCtx, sqlite3_column_value(pCsr->pStmt, iCol+1));
    +       }
    +-    }
    ++      break;
    +   }
    + 
    +   assert( ((Fts3Table *)pCsr->base.pVtab)->pSegments==0 );
    +@@ -139257,8 +152226,10 @@ static int fts3SyncMethod(sqlite3_vtab *pVtab){
    +   const u32 nMinMerge = 64;       /* Minimum amount of incr-merge work to do */
    + 
    +   Fts3Table *p = (Fts3Table*)pVtab;
    +-  int rc = sqlite3Fts3PendingTermsFlush(p);
    ++  int rc;
    ++  i64 iLastRowid = sqlite3_last_insert_rowid(p->db);
    + 
    ++  rc = sqlite3Fts3PendingTermsFlush(p);
    +   if( rc==SQLITE_OK 
    +    && p->nLeafAdd>(nMinMerge/16) 
    +    && p->nAutoincrmerge && p->nAutoincrmerge!=0xff
    +@@ -139273,6 +152244,7 @@ static int fts3SyncMethod(sqlite3_vtab *pVtab){
    +     if( A>(int)nMinMerge ) rc = sqlite3Fts3Incrmerge(p, A, p->nAutoincrmerge);
    +   }
    +   sqlite3Fts3SegmentsClose(p);
    ++  sqlite3_set_last_insert_rowid(p->db, iLastRowid);
    +   return rc;
    + }
    + 
    +@@ -139285,17 +152257,11 @@ static int fts3SyncMethod(sqlite3_vtab *pVtab){
    + 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);
    ++    char *zTbl = sqlite3_mprintf("%s_stat", p->zName);
    ++    if( zTbl ){
    ++      int res = sqlite3_table_column_metadata(p->db, p->zDb, zTbl, 0,0,0,0,0,0);
    ++      sqlite3_free(zTbl);
    ++      p->bHasStat = (res==SQLITE_OK);
    +     }else{
    +       rc = SQLITE_NOMEM;
    +     }
    +@@ -139402,18 +152368,17 @@ static int fts3FunctionArg(
    +   sqlite3_value *pVal,            /* argv[0] passed to function */
    +   Fts3Cursor **ppCsr              /* OUT: Store cursor handle here */
    + ){
    +-  Fts3Cursor *pRet;
    +-  if( sqlite3_value_type(pVal)!=SQLITE_BLOB 
    +-   || sqlite3_value_bytes(pVal)!=sizeof(Fts3Cursor *)
    +-  ){
    ++  int rc;
    ++  *ppCsr = (Fts3Cursor*)sqlite3_value_pointer(pVal, "fts3cursor");
    ++  if( (*ppCsr)!=0 ){
    ++    rc = SQLITE_OK;
    ++  }else{
    +     char *zErr = sqlite3_mprintf("illegal first argument to %s", zFunc);
    +     sqlite3_result_error(pContext, zErr, -1);
    +     sqlite3_free(zErr);
    +-    return SQLITE_ERROR;
    ++    rc = SQLITE_ERROR;
    +   }
    +-  memcpy(&pRet, sqlite3_value_blob(pVal), sizeof(Fts3Cursor *));
    +-  *ppCsr = pRet;
    +-  return SQLITE_OK;
    ++  return rc;
    + }
    + 
    + /*
    +@@ -139800,7 +152765,7 @@ SQLITE_PRIVATE int sqlite3Fts3Init(sqlite3 *db){
    + #endif
    + 
    +   /* Create the virtual table wrapper around the hash-table and overload 
    +-  ** the two scalar functions. If this is successful, register the
    ++  ** the four scalar functions. If this is successful, register the
    +   ** module with sqlite.
    +   */
    +   if( SQLITE_OK==rc 
    +@@ -139825,7 +152790,7 @@ SQLITE_PRIVATE int sqlite3Fts3Init(sqlite3 *db){
    + #endif
    +     rc = sqlite3_create_module_v2(
    +         db, "fts3", &fts3Module, (void *)pHash, hashDestroy
    +-        );
    ++    );
    +     if( rc==SQLITE_OK ){
    +       rc = sqlite3_create_module_v2(
    +           db, "fts4", &fts3Module, (void *)pHash, 0
    +@@ -140395,7 +153360,7 @@ static int fts3EvalIncrPhraseNext(
    +   ** one incremental token. In which case the bIncr flag is set. */
    +   assert( p->bIncr==1 );
    + 
    +-  if( p->nToken==1 && p->bIncr ){
    ++  if( p->nToken==1 ){
    +     rc = sqlite3Fts3MsrIncrNext(pTab, p->aToken[0].pSegcsr, 
    +         &pDL->iDocid, &pDL->pList, &pDL->nList
    +     );
    +@@ -140628,6 +153593,7 @@ static void fts3EvalTokenCosts(
    + ** the number of overflow pages consumed by a record B bytes in size.
    + */
    + static int fts3EvalAverageDocsize(Fts3Cursor *pCsr, int *pnPage){
    ++  int rc = SQLITE_OK;
    +   if( pCsr->nRowAvg==0 ){
    +     /* The average document size, which is required to calculate the cost
    +     ** of each doclist, has not yet been determined. Read the required 
    +@@ -140640,7 +153606,6 @@ static int fts3EvalAverageDocsize(Fts3Cursor *pCsr, int *pnPage){
    +     ** data stored in all rows of each column of the table, from left
    +     ** to right.
    +     */
    +-    int rc;
    +     Fts3Table *p = (Fts3Table*)pCsr->base.pVtab;
    +     sqlite3_stmt *pStmt;
    +     sqlite3_int64 nDoc = 0;
    +@@ -140667,11 +153632,10 @@ static int fts3EvalAverageDocsize(Fts3Cursor *pCsr, int *pnPage){
    +     pCsr->nRowAvg = (int)(((nByte / nDoc) + p->nPgsz) / p->nPgsz);
    +     assert( pCsr->nRowAvg>0 ); 
    +     rc = sqlite3_reset(pStmt);
    +-    if( rc!=SQLITE_OK ) return rc;
    +   }
    + 
    +   *pnPage = pCsr->nRowAvg;
    +-  return SQLITE_OK;
    ++  return rc;
    + }
    + 
    + /*
    +@@ -141021,7 +153985,8 @@ static void fts3EvalNextRow(
    +           pExpr->iDocid = pLeft->iDocid;
    +           pExpr->bEof = (pLeft->bEof || pRight->bEof);
    +           if( pExpr->eType==FTSQUERY_NEAR && pExpr->bEof ){
    +-            if( pRight->pPhrase && pRight->pPhrase->doclist.aAll ){
    ++            assert( pRight->eType==FTSQUERY_PHRASE );
    ++            if( pRight->pPhrase->doclist.aAll ){
    +               Fts3Doclist *pDl = &pRight->pPhrase->doclist;
    +               while( *pRc==SQLITE_OK && pRight->bEof==0 ){
    +                 memset(pDl->pList, 0, pDl->nList);
    +@@ -141050,7 +154015,7 @@ static void fts3EvalNextRow(
    + 
    +         if( pRight->bEof || (pLeft->bEof==0 && iCmp<0) ){
    +           fts3EvalNextRow(pCsr, pLeft, pRc);
    +-        }else if( pLeft->bEof || (pRight->bEof==0 && iCmp>0) ){
    ++        }else if( pLeft->bEof || iCmp>0 ){
    +           fts3EvalNextRow(pCsr, pRight, pRc);
    +         }else{
    +           fts3EvalNextRow(pCsr, pLeft, pRc);
    +@@ -141142,7 +154107,6 @@ static int fts3EvalNearTest(Fts3Expr *pExpr, int *pRc){
    +   */
    +   if( *pRc==SQLITE_OK 
    +    && pExpr->eType==FTSQUERY_NEAR 
    +-   && pExpr->bEof==0
    +    && (pExpr->pParent==0 || pExpr->pParent->eType!=FTSQUERY_NEAR)
    +   ){
    +     Fts3Expr *p; 
    +@@ -141151,42 +154115,39 @@ static int fts3EvalNearTest(Fts3Expr *pExpr, int *pRc){
    + 
    +     /* Allocate temporary working space. */
    +     for(p=pExpr; p->pLeft; p=p->pLeft){
    ++      assert( p->pRight->pPhrase->doclist.nList>0 );
    +       nTmp += p->pRight->pPhrase->doclist.nList;
    +     }
    +     nTmp += p->pPhrase->doclist.nList;
    +-    if( nTmp==0 ){
    ++    aTmp = sqlite3_malloc(nTmp*2);
    ++    if( !aTmp ){
    ++      *pRc = SQLITE_NOMEM;
    +       res = 0;
    +     }else{
    +-      aTmp = sqlite3_malloc(nTmp*2);
    +-      if( !aTmp ){
    +-        *pRc = SQLITE_NOMEM;
    +-        res = 0;
    +-      }else{
    +-        char *aPoslist = p->pPhrase->doclist.pList;
    +-        int nToken = p->pPhrase->nToken;
    +-
    +-        for(p=p->pParent;res && p && p->eType==FTSQUERY_NEAR; p=p->pParent){
    +-          Fts3Phrase *pPhrase = p->pRight->pPhrase;
    +-          int nNear = p->nNear;
    +-          res = fts3EvalNearTrim(nNear, aTmp, &aPoslist, &nToken, pPhrase);
    +-        }
    +-
    +-        aPoslist = pExpr->pRight->pPhrase->doclist.pList;
    +-        nToken = pExpr->pRight->pPhrase->nToken;
    +-        for(p=pExpr->pLeft; p && res; p=p->pLeft){
    +-          int nNear;
    +-          Fts3Phrase *pPhrase;
    +-          assert( p->pParent && p->pParent->pLeft==p );
    +-          nNear = p->pParent->nNear;
    +-          pPhrase = (
    +-              p->eType==FTSQUERY_NEAR ? p->pRight->pPhrase : p->pPhrase
    +-              );
    +-          res = fts3EvalNearTrim(nNear, aTmp, &aPoslist, &nToken, pPhrase);
    +-        }
    ++      char *aPoslist = p->pPhrase->doclist.pList;
    ++      int nToken = p->pPhrase->nToken;
    ++
    ++      for(p=p->pParent;res && p && p->eType==FTSQUERY_NEAR; p=p->pParent){
    ++        Fts3Phrase *pPhrase = p->pRight->pPhrase;
    ++        int nNear = p->nNear;
    ++        res = fts3EvalNearTrim(nNear, aTmp, &aPoslist, &nToken, pPhrase);
    +       }
    + 
    +-      sqlite3_free(aTmp);
    ++      aPoslist = pExpr->pRight->pPhrase->doclist.pList;
    ++      nToken = pExpr->pRight->pPhrase->nToken;
    ++      for(p=pExpr->pLeft; p && res; p=p->pLeft){
    ++        int nNear;
    ++        Fts3Phrase *pPhrase;
    ++        assert( p->pParent && p->pParent->pLeft==p );
    ++        nNear = p->pParent->nNear;
    ++        pPhrase = (
    ++            p->eType==FTSQUERY_NEAR ? p->pRight->pPhrase : p->pPhrase
    ++        );
    ++        res = fts3EvalNearTrim(nNear, aTmp, &aPoslist, &nToken, pPhrase);
    ++      }
    +     }
    ++
    ++    sqlite3_free(aTmp);
    +   }
    + 
    +   return res;
    +@@ -141794,7 +154755,7 @@ SQLITE_PRIVATE int sqlite3Fts3Corrupt(){
    + #ifdef _WIN32
    + __declspec(dllexport)
    + #endif
    +-SQLITE_API int SQLITE_STDCALL sqlite3_fts3_init(
    ++SQLITE_API int sqlite3_fts3_init(
    +   sqlite3 *db, 
    +   char **pzErrMsg,
    +   const sqlite3_api_routines *pApi
    +@@ -144755,6 +157716,18 @@ SQLITE_PRIVATE void sqlite3Fts3PorterTokenizerModule(
    + /* #include <assert.h> */
    + /* #include <string.h> */
    + 
    ++/*
    ++** Return true if the two-argument version of fts3_tokenizer()
    ++** has been activated via a prior call to sqlite3_db_config(db,
    ++** SQLITE_DBCONFIG_ENABLE_FTS3_TOKENIZER, 1, 0);
    ++*/
    ++static int fts3TokenizerEnabled(sqlite3_context *context){
    ++  sqlite3 *db = sqlite3_context_db_handle(context);
    ++  int isEnabled = 0;
    ++  sqlite3_db_config(db,SQLITE_DBCONFIG_ENABLE_FTS3_TOKENIZER,-1,&isEnabled);
    ++  return isEnabled;
    ++}
    ++
    + /*
    + ** Implementation of the SQL scalar function for accessing the underlying 
    + ** hash table. This function may be called as follows:
    +@@ -144775,7 +157748,7 @@ SQLITE_PRIVATE void sqlite3Fts3PorterTokenizerModule(
    + ** is a blob containing the pointer stored as the hash data corresponding
    + ** to string <key-name> (after the hash-table is updated, if applicable).
    + */
    +-static void scalarFunc(
    ++static void fts3TokenizerFunc(
    +   sqlite3_context *context,
    +   int argc,
    +   sqlite3_value **argv
    +@@ -144793,16 +157766,20 @@ static void scalarFunc(
    +   nName = sqlite3_value_bytes(argv[0])+1;
    + 
    +   if( argc==2 ){
    +-    void *pOld;
    +-    int n = sqlite3_value_bytes(argv[1]);
    +-    if( zName==0 || n!=sizeof(pPtr) ){
    +-      sqlite3_result_error(context, "argument type mismatch", -1);
    +-      return;
    +-    }
    +-    pPtr = *(void **)sqlite3_value_blob(argv[1]);
    +-    pOld = sqlite3Fts3HashInsert(pHash, (void *)zName, nName, pPtr);
    +-    if( pOld==pPtr ){
    +-      sqlite3_result_error(context, "out of memory", -1);
    ++    if( fts3TokenizerEnabled(context) ){
    ++      void *pOld;
    ++      int n = sqlite3_value_bytes(argv[1]);
    ++      if( zName==0 || n!=sizeof(pPtr) ){
    ++        sqlite3_result_error(context, "argument type mismatch", -1);
    ++        return;
    ++      }
    ++      pPtr = *(void **)sqlite3_value_blob(argv[1]);
    ++      pOld = sqlite3Fts3HashInsert(pHash, (void *)zName, nName, pPtr);
    ++      if( pOld==pPtr ){
    ++        sqlite3_result_error(context, "out of memory", -1);
    ++      }
    ++    }else{
    ++      sqlite3_result_error(context, "fts3tokenize disabled", -1);
    +       return;
    +     }
    +   }else{
    +@@ -144816,7 +157793,6 @@ static void scalarFunc(
    +       return;
    +     }
    +   }
    +-
    +   sqlite3_result_blob(context, (void *)&pPtr, sizeof(pPtr), SQLITE_TRANSIENT);
    + }
    + 
    +@@ -144935,7 +157911,11 @@ SQLITE_PRIVATE int sqlite3Fts3InitTokenizer(
    + 
    + #ifdef SQLITE_TEST
    + 
    +-#include <tcl.h>
    ++#if defined(INCLUDE_SQLITE_TCL_H)
    ++#  include "sqlite_tcl.h"
    ++#else
    ++#  include "tcl.h"
    ++#endif
    + /* #include <string.h> */
    + 
    + /*
    +@@ -145076,6 +158056,7 @@ int registerTokenizer(
    +   return sqlite3_finalize(pStmt);
    + }
    + 
    ++
    + static
    + int queryTokenizer(
    +   sqlite3 *db, 
    +@@ -145146,11 +158127,13 @@ static void intTestFunc(
    +   assert( 0==strcmp(sqlite3_errmsg(db), "unknown tokenizer: nosuchtokenizer") );
    + 
    +   /* Test the storage function */
    +-  rc = registerTokenizer(db, "nosuchtokenizer", p1);
    +-  assert( rc==SQLITE_OK );
    +-  rc = queryTokenizer(db, "nosuchtokenizer", &p2);
    +-  assert( rc==SQLITE_OK );
    +-  assert( p2==p1 );
    ++  if( fts3TokenizerEnabled(context) ){
    ++    rc = registerTokenizer(db, "nosuchtokenizer", p1);
    ++    assert( rc==SQLITE_OK );
    ++    rc = queryTokenizer(db, "nosuchtokenizer", &p2);
    ++    assert( rc==SQLITE_OK );
    ++    assert( p2==p1 );
    ++  }
    + 
    +   sqlite3_result_text(context, "ok", -1, SQLITE_STATIC);
    + }
    +@@ -145166,7 +158149,7 @@ static void intTestFunc(
    + **    sqlite3Fts3HashInit(pHash, FTS3_HASH_STRING, 1);
    + **
    + ** This function adds a scalar function (see header comment above
    +-** scalarFunc() in this file for details) and, if ENABLE_TABLE is
    ++** fts3TokenizerFunc() in this file for details) and, if ENABLE_TABLE is
    + ** defined at compilation time, a temporary virtual table (see header 
    + ** comment above struct HashTableVtab) to the database schema. Both 
    + ** provide read/write access to the contents of *pHash.
    +@@ -145195,10 +158178,10 @@ SQLITE_PRIVATE int sqlite3Fts3InitHashTable(
    + #endif
    + 
    +   if( SQLITE_OK==rc ){
    +-    rc = sqlite3_create_function(db, zName, 1, any, p, scalarFunc, 0, 0);
    ++    rc = sqlite3_create_function(db, zName, 1, any, p, fts3TokenizerFunc, 0, 0);
    +   }
    +   if( SQLITE_OK==rc ){
    +-    rc = sqlite3_create_function(db, zName, 2, any, p, scalarFunc, 0, 0);
    ++    rc = sqlite3_create_function(db, zName, 2, any, p, fts3TokenizerFunc, 0, 0);
    +   }
    + #ifdef SQLITE_TEST
    +   if( SQLITE_OK==rc ){
    +@@ -146250,7 +159233,8 @@ static int fts3SqlStmt(
    + ** of the oldest level in the db that contains at least ? segments. Or,
    + ** if no level in the FTS index contains more than ? segments, the statement
    + ** returns zero rows.  */
    +-/* 28 */ "SELECT level FROM %Q.'%q_segdir' GROUP BY level HAVING count(*)>=?"
    ++/* 28 */ "SELECT level, count(*) AS cnt FROM %Q.'%q_segdir' "
    ++         "  GROUP BY level HAVING cnt>=?"
    +          "  ORDER BY (level %% 1024) ASC LIMIT 1",
    + 
    + /* Estimate the upper limit on the number of leaf nodes in a new segment
    +@@ -146323,7 +159307,8 @@ static int fts3SqlStmt(
    +     if( !zSql ){
    +       rc = SQLITE_NOMEM;
    +     }else{
    +-      rc = sqlite3_prepare_v2(p->db, zSql, -1, &pStmt, NULL);
    ++      rc = sqlite3_prepare_v3(p->db, zSql, -1, SQLITE_PREPARE_PERSISTENT,
    ++                              &pStmt, NULL);
    +       sqlite3_free(zSql);
    +       assert( rc==SQLITE_OK || pStmt==0 );
    +       p->aStmt[eStmt] = pStmt;
    +@@ -147289,15 +160274,19 @@ static int fts3SegReaderNext(
    +   ** safe (no risk of overread) even if the node data is corrupted. */
    +   pNext += fts3GetVarint32(pNext, &nPrefix);
    +   pNext += fts3GetVarint32(pNext, &nSuffix);
    +-  if( nPrefix<0 || nSuffix<=0 
    +-   || &pNext[nSuffix]>&pReader->aNode[pReader->nNode] 
    ++  if( nSuffix<=0
    ++   || (&pReader->aNode[pReader->nNode] - pNext)<nSuffix
    ++   || nPrefix>pReader->nTermAlloc
    +   ){
    +     return FTS_CORRUPT_VTAB;
    +   }
    + 
    +-  if( nPrefix+nSuffix>pReader->nTermAlloc ){
    +-    int nNew = (nPrefix+nSuffix)*2;
    +-    char *zNew = sqlite3_realloc(pReader->zTerm, nNew);
    ++  /* Both nPrefix and nSuffix were read by fts3GetVarint32() and so are
    ++  ** between 0 and 0x7FFFFFFF. But the sum of the two may cause integer
    ++  ** overflow - hence the (i64) casts.  */
    ++  if( (i64)nPrefix+nSuffix>(i64)pReader->nTermAlloc ){
    ++    i64 nNew = ((i64)nPrefix+nSuffix)*2;
    ++    char *zNew = sqlite3_realloc64(pReader->zTerm, nNew);
    +     if( !zNew ){
    +       return SQLITE_NOMEM;
    +     }
    +@@ -147319,7 +160308,7 @@ static int fts3SegReaderNext(
    +   ** b-tree node. And that the final byte of the doclist is 0x00. If either 
    +   ** of these statements is untrue, then the data structure is corrupt.
    +   */
    +-  if( &pReader->aDoclist[pReader->nDoclist]>&pReader->aNode[pReader->nNode] 
    ++  if( (&pReader->aNode[pReader->nNode] - pReader->aDoclist)<pReader->nDoclist
    +    || (pReader->nPopulate==0 && pReader->aDoclist[pReader->nDoclist-1])
    +   ){
    +     return FTS_CORRUPT_VTAB;
    +@@ -149111,7 +162100,7 @@ static int fts3SegmentMerge(
    +     ** segment. The level of the new segment is equal to the numerically
    +     ** greatest segment level currently present in the database for this
    +     ** index. The idx of the new segment is always 0.  */
    +-    if( csr.nSegment==1 ){
    ++    if( csr.nSegment==1 && 0==fts3SegReaderIsPending(csr.apSegment[0]) ){
    +       rc = SQLITE_DONE;
    +       goto finished;
    +     }
    +@@ -149642,6 +162631,9 @@ static int nodeReaderNext(NodeReader *p){
    +     }
    +     p->iOff += fts3GetVarint32(&p->aNode[p->iOff], &nSuffix);
    + 
    ++    if( nPrefix>p->iOff || nSuffix>p->nNode-p->iOff ){
    ++      return SQLITE_CORRUPT_VTAB;
    ++    }
    +     blobGrowBuffer(&p->term, nPrefix+nSuffix, &rc);
    +     if( rc==SQLITE_OK ){
    +       memcpy(&p->term.a[nPrefix], &p->aNode[p->iOff], nSuffix);
    +@@ -149649,6 +162641,9 @@ static int nodeReaderNext(NodeReader *p){
    +       p->iOff += nSuffix;
    +       if( p->iChild==0 ){
    +         p->iOff += fts3GetVarint32(&p->aNode[p->iOff], &p->nDoclist);
    ++        if( (p->nNode-p->iOff)<p->nDoclist ){
    ++          return SQLITE_CORRUPT_VTAB;
    ++        }
    +         p->aDoclist = &p->aNode[p->iOff];
    +         p->iOff += p->nDoclist;
    +       }
    +@@ -149656,7 +162651,6 @@ static int nodeReaderNext(NodeReader *p){
    +   }
    + 
    +   assert( p->iOff<=p->nNode );
    +-
    +   return rc;
    + }
    + 
    +@@ -150753,10 +163747,11 @@ SQLITE_PRIVATE int sqlite3Fts3Incrmerge(Fts3Table *p, int nMerge, int nMin){
    +     ** set nSeg to -1.
    +     */
    +     rc = fts3SqlStmt(p, SQL_FIND_MERGE_LEVEL, &pFindLevel, 0);
    +-    sqlite3_bind_int(pFindLevel, 1, nMin);
    ++    sqlite3_bind_int(pFindLevel, 1, MAX(2, nMin));
    +     if( sqlite3_step(pFindLevel)==SQLITE_ROW ){
    +       iAbsLevel = sqlite3_column_int64(pFindLevel, 0);
    +-      nSeg = nMin;
    ++      nSeg = sqlite3_column_int(pFindLevel, 1);
    ++      assert( nSeg>=2 );
    +     }else{
    +       nSeg = -1;
    +     }
    +@@ -150871,11 +163866,14 @@ SQLITE_PRIVATE int sqlite3Fts3Incrmerge(Fts3Table *p, int nMerge, int nMin){
    + ** Convert the text beginning at *pz into an integer and return
    + ** its value.  Advance *pz to point to the first character past
    + ** the integer.
    ++**
    ++** This function used for parameters to merge= and incrmerge=
    ++** commands. 
    + */
    + static int fts3Getint(const char **pz){
    +   const char *z = *pz;
    +   int i = 0;
    +-  while( (*z)>='0' && (*z)<='9' ) i = 10*i + *(z++) - '0';
    ++  while( (*z)>='0' && (*z)<='9' && i<214748363 ) i = 10*i + *(z++) - '0';
    +   *pz = z;
    +   return i;
    + }
    +@@ -153441,16 +166439,16 @@ static int unicodeAddExceptions(
    + ){
    +   const unsigned char *z = (const unsigned char *)zIn;
    +   const unsigned char *zTerm = &z[nIn];
    +-  int iCode;
    ++  unsigned int iCode;
    +   int nEntry = 0;
    + 
    +   assert( bAlnum==0 || bAlnum==1 );
    + 
    +   while( z<zTerm ){
    +     READ_UTF8(z, zTerm, iCode);
    +-    assert( (sqlite3FtsUnicodeIsalnum(iCode) & 0xFFFFFFFE)==0 );
    +-    if( sqlite3FtsUnicodeIsalnum(iCode)!=bAlnum 
    +-     && sqlite3FtsUnicodeIsdiacritic(iCode)==0 
    ++    assert( (sqlite3FtsUnicodeIsalnum((int)iCode) & 0xFFFFFFFE)==0 );
    ++    if( sqlite3FtsUnicodeIsalnum((int)iCode)!=bAlnum 
    ++     && sqlite3FtsUnicodeIsdiacritic((int)iCode)==0 
    +     ){
    +       nEntry++;
    +     }
    +@@ -153467,13 +166465,13 @@ static int unicodeAddExceptions(
    +     z = (const unsigned char *)zIn;
    +     while( z<zTerm ){
    +       READ_UTF8(z, zTerm, iCode);
    +-      if( sqlite3FtsUnicodeIsalnum(iCode)!=bAlnum 
    +-       && sqlite3FtsUnicodeIsdiacritic(iCode)==0
    ++      if( sqlite3FtsUnicodeIsalnum((int)iCode)!=bAlnum 
    ++       && sqlite3FtsUnicodeIsdiacritic((int)iCode)==0
    +       ){
    +         int i, j;
    +-        for(i=0; i<nNew && aNew[i]<iCode; i++);
    ++        for(i=0; i<nNew && aNew[i]<(int)iCode; i++);
    +         for(j=nNew; j>i; j--) aNew[j] = aNew[j-1];
    +-        aNew[i] = iCode;
    ++        aNew[i] = (int)iCode;
    +         nNew++;
    +       }
    +     }
    +@@ -153623,7 +166621,7 @@ static int unicodeNext(
    + ){
    +   unicode_cursor *pCsr = (unicode_cursor *)pC;
    +   unicode_tokenizer *p = ((unicode_tokenizer *)pCsr->base.pTokenizer);
    +-  int iCode = 0;
    ++  unsigned int iCode = 0;
    +   char *zOut;
    +   const unsigned char *z = &pCsr->aInput[pCsr->iOff];
    +   const unsigned char *zStart = z;
    +@@ -153635,7 +166633,7 @@ static int unicodeNext(
    +   ** the input.  */
    +   while( z<zTerm ){
    +     READ_UTF8(z, zTerm, iCode);
    +-    if( unicodeIsAlnum(p, iCode) ) break;
    ++    if( unicodeIsAlnum(p, (int)iCode) ) break;
    +     zStart = z;
    +   }
    +   if( zStart>=zTerm ) return SQLITE_DONE;
    +@@ -153655,7 +166653,7 @@ static int unicodeNext(
    + 
    +     /* Write the folded case of the last character read to the output */
    +     zEnd = z;
    +-    iOut = sqlite3FtsUnicodeFold(iCode, p->bRemoveDiacritic);
    ++    iOut = sqlite3FtsUnicodeFold((int)iCode, p->bRemoveDiacritic);
    +     if( iOut ){
    +       WRITE_UTF8(zOut, iOut);
    +     }
    +@@ -153663,8 +166661,8 @@ static int unicodeNext(
    +     /* If the cursor is not at EOF, read the next character */
    +     if( z>=zTerm ) break;
    +     READ_UTF8(z, zTerm, iCode);
    +-  }while( unicodeIsAlnum(p, iCode) 
    +-       || sqlite3FtsUnicodeIsdiacritic(iCode)
    ++  }while( unicodeIsAlnum(p, (int)iCode) 
    ++       || sqlite3FtsUnicodeIsdiacritic((int)iCode)
    +   );
    + 
    +   /* Set the output variables and return. */
    +@@ -153828,9 +166826,9 @@ SQLITE_PRIVATE int sqlite3FtsUnicodeIsalnum(int c){
    +     0xFFFFFFFF, 0xFC00FFFF, 0xF8000001, 0xF8000001,
    +   };
    + 
    +-  if( c<128 ){
    +-    return ( (aAscii[c >> 5] & (1 << (c & 0x001F)))==0 );
    +-  }else if( c<(1<<22) ){
    ++  if( (unsigned int)c<128 ){
    ++    return ( (aAscii[c >> 5] & ((unsigned int)1 << (c & 0x001F)))==0 );
    ++  }else if( (unsigned int)c<(1<<22) ){
    +     unsigned int key = (((unsigned int)c)<<10) | 0x000003FF;
    +     int iRes = 0;
    +     int iHi = sizeof(aEntry)/sizeof(aEntry[0]) - 1;
    +@@ -154023,16 +167021,17 @@ SQLITE_PRIVATE int sqlite3FtsUnicodeFold(int c, int bRemoveDiacritic){
    + 
    +   int ret = c;
    + 
    +-  assert( c>=0 );
    +   assert( sizeof(unsigned short)==2 && sizeof(unsigned char)==1 );
    + 
    +   if( c<128 ){
    +     if( c>='A' && c<='Z' ) ret = c + ('a' - 'A');
    +   }else if( c<65536 ){
    ++    const struct TableEntry *p;
    +     int iHi = sizeof(aEntry)/sizeof(aEntry[0]) - 1;
    +     int iLo = 0;
    +     int iRes = -1;
    + 
    ++    assert( c>aEntry[0].iCode );
    +     while( iHi>=iLo ){
    +       int iTest = (iHi + iLo) / 2;
    +       int cmp = (c - aEntry[iTest].iCode);
    +@@ -154043,14 +167042,12 @@ SQLITE_PRIVATE int sqlite3FtsUnicodeFold(int c, int bRemoveDiacritic){
    +         iHi = iTest-1;
    +       }
    +     }
    +-    assert( iRes<0 || c>=aEntry[iRes].iCode );
    + 
    +-    if( iRes>=0 ){
    +-      const struct TableEntry *p = &aEntry[iRes];
    +-      if( c<(p->iCode + p->nRange) && 0==(0x01 & p->flags & (p->iCode ^ c)) ){
    +-        ret = (c + (aiOff[p->flags>>1])) & 0x0000FFFF;
    +-        assert( ret>0 );
    +-      }
    ++    assert( iRes>=0 && c>=aEntry[iRes].iCode );
    ++    p = &aEntry[iRes];
    ++    if( c<(p->iCode + p->nRange) && 0==(0x01 & p->flags & (p->iCode ^ c)) ){
    ++      ret = (c + (aiOff[p->flags>>1])) & 0x0000FFFF;
    ++      assert( ret>0 );
    +     }
    + 
    +     if( bRemoveDiacritic ) ret = remove_diacritic(ret);
    +@@ -154121,7 +167118,8 @@ SQLITE_PRIVATE int sqlite3FtsUnicodeFold(int c, int bRemoveDiacritic){
    + **      child page.
    + */
    + 
    +-#if !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_RTREE)
    ++#if !defined(SQLITE_CORE) \
    ++  || (defined(SQLITE_ENABLE_RTREE) && !defined(SQLITE_OMIT_VIRTUALTABLE))
    + 
    + #ifndef SQLITE_CORE
    + /*   #include "sqlite3ext.h" */
    +@@ -154137,6 +167135,7 @@ SQLITE_PRIVATE int sqlite3FtsUnicodeFold(int c, int bRemoveDiacritic){
    + #ifndef SQLITE_AMALGAMATION
    + #include "sqlite3rtree.h"
    + typedef sqlite3_int64 i64;
    ++typedef sqlite3_uint64 u64;
    + typedef unsigned char u8;
    + typedef unsigned short u16;
    + typedef unsigned int u32;
    +@@ -154185,13 +167184,16 @@ struct Rtree {
    +   sqlite3 *db;                /* Host database connection */
    +   int iNodeSize;              /* Size in bytes of each node in the node table */
    +   u8 nDim;                    /* Number of dimensions */
    ++  u8 nDim2;                   /* Twice the number of dimensions */
    +   u8 eCoordType;              /* RTREE_COORD_REAL32 or RTREE_COORD_INT32 */
    +   u8 nBytesPerCell;           /* Bytes consumed per cell */
    ++  u8 inWrTrans;               /* True if inside write transaction */
    +   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 */ 
    +-  int nBusy;                  /* Current number of users of this structure */
    ++  u32 nBusy;                  /* Current number of users of this structure */
    +   i64 nRowEst;                /* Estimated number of rows in this table */
    ++  u32 nCursor;                /* Number of open cursors */
    + 
    +   /* List of nodes removed during a CondenseTree operation. List is
    +   ** linked together via the pointer normally used for hash chains -
    +@@ -154201,8 +167203,10 @@ struct Rtree {
    +   RtreeNode *pDeleted;
    +   int iReinsertHeight;        /* Height of sub-trees Reinsert() has run on */
    + 
    ++  /* Blob I/O on xxx_node */
    ++  sqlite3_blob *pNodeBlob;
    ++
    +   /* Statements to read/write/delete a record from xxx_node */
    +-  sqlite3_stmt *pReadNode;
    +   sqlite3_stmt *pWriteNode;
    +   sqlite3_stmt *pDeleteNode;
    + 
    +@@ -154272,7 +167276,7 @@ struct RtreeSearchPoint {
    + ** The smallest possible node-size is (512-64)==448 bytes. And the largest
    + ** supported cell size is 48 bytes (8 byte rowid + ten 4 byte coordinates).
    + ** Therefore all non-root nodes must contain at least 3 entries. Since 
    +-** 2^40 is greater than 2^64, an r-tree structure always has a depth of
    ++** 3^40 is greater than 2^64, an r-tree structure always has a depth of
    + ** 40 or less.
    + */
    + #define RTREE_MAX_DEPTH 40
    +@@ -154402,14 +167406,6 @@ struct RtreeGeomCallback {
    +   void *pContext;
    + };
    + 
    +-
    +-/*
    +-** Value for the first field of every RtreeMatchArg object. The MATCH
    +-** operator tests that the first field of a blob operand matches this
    +-** value to avoid operating on invalid blobs (which could cause a segfault).
    +-*/
    +-#define RTREE_GEOMETRY_MAGIC 0x891245AB
    +-
    + /*
    + ** An instance of this structure (in the form of a BLOB) is returned by
    + ** the SQL functions that sqlite3_rtree_geometry_callback() and
    +@@ -154417,7 +167413,7 @@ struct RtreeGeomCallback {
    + ** operand to the MATCH operator of an R-Tree.
    + */
    + struct RtreeMatchArg {
    +-  u32 magic;                  /* Always RTREE_GEOMETRY_MAGIC */
    ++  u32 iSize;                  /* Size of this object */
    +   RtreeGeomCallback cb;       /* Info about the callback functions */
    +   int nParam;                 /* Number of parameters to the SQL function */
    +   sqlite3_value **apSqlParam; /* Original SQL parameter values */
    +@@ -154431,6 +167427,58 @@ struct RtreeMatchArg {
    + # define MIN(x,y) ((x) > (y) ? (y) : (x))
    + #endif
    + 
    ++/* What version of GCC is being used.  0 means GCC is not being used .
    ++** Note that the GCC_VERSION macro will also be set correctly when using
    ++** clang, since clang works hard to be gcc compatible.  So the gcc
    ++** optimizations will also work when compiling with clang.
    ++*/
    ++#ifndef GCC_VERSION
    ++#if defined(__GNUC__) && !defined(SQLITE_DISABLE_INTRINSIC)
    ++# define GCC_VERSION (__GNUC__*1000000+__GNUC_MINOR__*1000+__GNUC_PATCHLEVEL__)
    ++#else
    ++# define GCC_VERSION 0
    ++#endif
    ++#endif
    ++
    ++/* The testcase() macro should already be defined in the amalgamation.  If
    ++** it is not, make it a no-op.
    ++*/
    ++#ifndef SQLITE_AMALGAMATION
    ++# define testcase(X)
    ++#endif
    ++
    ++/*
    ++** Macros to determine whether the machine is big or little endian,
    ++** 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.
    ++*/
    ++#ifndef SQLITE_BYTEORDER
    ++#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__)
    ++# define SQLITE_BYTEORDER    1234
    ++#elif defined(sparc)    || defined(__ppc__)
    ++# define SQLITE_BYTEORDER    4321
    ++#else
    ++# define SQLITE_BYTEORDER    0     /* 0 means "unknown at compile-time" */
    ++#endif
    ++#endif
    ++
    ++
    ++/* What version of MSVC is being used.  0 means MSVC is not being used */
    ++#ifndef MSVC_VERSION
    ++#if defined(_MSC_VER) && !defined(SQLITE_DISABLE_INTRINSIC)
    ++# define MSVC_VERSION _MSC_VER
    ++#else
    ++# define MSVC_VERSION 0
    ++#endif
    ++#endif
    ++
    + /*
    + ** Functions to deserialize a 16 bit integer, 32 bit real number and
    + ** 64 bit integer. The deserialized value is returned.
    +@@ -154439,24 +167487,47 @@ static int readInt16(u8 *p){
    +   return (p[0]<<8) + p[1];
    + }
    + static void readCoord(u8 *p, RtreeCoord *pCoord){
    ++  assert( ((((char*)p) - (char*)0)&3)==0 );  /* p is always 4-byte aligned */
    ++#if SQLITE_BYTEORDER==1234 && MSVC_VERSION>=1300
    ++  pCoord->u = _byteswap_ulong(*(u32*)p);
    ++#elif SQLITE_BYTEORDER==1234 && GCC_VERSION>=4003000
    ++  pCoord->u = __builtin_bswap32(*(u32*)p);
    ++#elif SQLITE_BYTEORDER==4321
    ++  pCoord->u = *(u32*)p;
    ++#else
    +   pCoord->u = (
    +     (((u32)p[0]) << 24) + 
    +     (((u32)p[1]) << 16) + 
    +     (((u32)p[2]) <<  8) + 
    +     (((u32)p[3]) <<  0)
    +   );
    ++#endif
    + }
    + static i64 readInt64(u8 *p){
    +-  return (
    +-    (((i64)p[0]) << 56) + 
    +-    (((i64)p[1]) << 48) + 
    +-    (((i64)p[2]) << 40) + 
    +-    (((i64)p[3]) << 32) + 
    +-    (((i64)p[4]) << 24) + 
    +-    (((i64)p[5]) << 16) + 
    +-    (((i64)p[6]) <<  8) + 
    +-    (((i64)p[7]) <<  0)
    ++#if SQLITE_BYTEORDER==1234 && MSVC_VERSION>=1300
    ++  u64 x;
    ++  memcpy(&x, p, 8);
    ++  return (i64)_byteswap_uint64(x);
    ++#elif SQLITE_BYTEORDER==1234 && GCC_VERSION>=4003000
    ++  u64 x;
    ++  memcpy(&x, p, 8);
    ++  return (i64)__builtin_bswap64(x);
    ++#elif SQLITE_BYTEORDER==4321
    ++  i64 x;
    ++  memcpy(&x, p, 8);
    ++  return x;
    ++#else
    ++  return (i64)(
    ++    (((u64)p[0]) << 56) + 
    ++    (((u64)p[1]) << 48) + 
    ++    (((u64)p[2]) << 40) + 
    ++    (((u64)p[3]) << 32) + 
    ++    (((u64)p[4]) << 24) + 
    ++    (((u64)p[5]) << 16) + 
    ++    (((u64)p[6]) <<  8) + 
    ++    (((u64)p[7]) <<  0)
    +   );
    ++#endif
    + }
    + 
    + /*
    +@@ -154464,23 +167535,43 @@ static i64 readInt64(u8 *p){
    + ** 64 bit integer. The value returned is the number of bytes written
    + ** to the argument buffer (always 2, 4 and 8 respectively).
    + */
    +-static int writeInt16(u8 *p, int i){
    ++static void writeInt16(u8 *p, int i){
    +   p[0] = (i>> 8)&0xFF;
    +   p[1] = (i>> 0)&0xFF;
    +-  return 2;
    + }
    + static int writeCoord(u8 *p, RtreeCoord *pCoord){
    +   u32 i;
    ++  assert( ((((char*)p) - (char*)0)&3)==0 );  /* p is always 4-byte aligned */
    +   assert( sizeof(RtreeCoord)==4 );
    +   assert( sizeof(u32)==4 );
    ++#if SQLITE_BYTEORDER==1234 && GCC_VERSION>=4003000
    ++  i = __builtin_bswap32(pCoord->u);
    ++  memcpy(p, &i, 4);
    ++#elif SQLITE_BYTEORDER==1234 && MSVC_VERSION>=1300
    ++  i = _byteswap_ulong(pCoord->u);
    ++  memcpy(p, &i, 4);
    ++#elif SQLITE_BYTEORDER==4321
    ++  i = pCoord->u;
    ++  memcpy(p, &i, 4);
    ++#else
    +   i = pCoord->u;
    +   p[0] = (i>>24)&0xFF;
    +   p[1] = (i>>16)&0xFF;
    +   p[2] = (i>> 8)&0xFF;
    +   p[3] = (i>> 0)&0xFF;
    ++#endif
    +   return 4;
    + }
    + static int writeInt64(u8 *p, i64 i){
    ++#if SQLITE_BYTEORDER==1234 && GCC_VERSION>=4003000
    ++  i = (i64)__builtin_bswap64((u64)i);
    ++  memcpy(p, &i, 8);
    ++#elif SQLITE_BYTEORDER==1234 && MSVC_VERSION>=1300
    ++  i = (i64)_byteswap_uint64((u64)i);
    ++  memcpy(p, &i, 8);
    ++#elif SQLITE_BYTEORDER==4321
    ++  memcpy(p, &i, 8);
    ++#else
    +   p[0] = (i>>56)&0xFF;
    +   p[1] = (i>>48)&0xFF;
    +   p[2] = (i>>40)&0xFF;
    +@@ -154489,6 +167580,7 @@ static int writeInt64(u8 *p, i64 i){
    +   p[5] = (i>>16)&0xFF;
    +   p[6] = (i>> 8)&0xFF;
    +   p[7] = (i>> 0)&0xFF;
    ++#endif
    +   return 8;
    + }
    + 
    +@@ -154571,6 +167663,17 @@ static RtreeNode *nodeNew(Rtree *pRtree, RtreeNode *pParent){
    +   return pNode;
    + }
    + 
    ++/*
    ++** Clear the Rtree.pNodeBlob object
    ++*/
    ++static void nodeBlobReset(Rtree *pRtree){
    ++  if( pRtree->pNodeBlob && pRtree->inWrTrans==0 && pRtree->nCursor==0 ){
    ++    sqlite3_blob *pBlob = pRtree->pNodeBlob;
    ++    pRtree->pNodeBlob = 0;
    ++    sqlite3_blob_close(pBlob);
    ++  }
    ++}
    ++
    + /*
    + ** Obtain a reference to an r-tree node.
    + */
    +@@ -154580,9 +167683,8 @@ static int nodeAcquire(
    +   RtreeNode *pParent,        /* Either the parent node or NULL */
    +   RtreeNode **ppNode         /* OUT: Acquired node */
    + ){
    +-  int rc;
    +-  int rc2 = SQLITE_OK;
    +-  RtreeNode *pNode;
    ++  int rc = SQLITE_OK;
    ++  RtreeNode *pNode = 0;
    + 
    +   /* Check if the requested node is already in the hash table. If so,
    +   ** increase its reference count and return it.
    +@@ -154598,28 +167700,45 @@ static int nodeAcquire(
    +     return SQLITE_OK;
    +   }
    + 
    +-  sqlite3_bind_int64(pRtree->pReadNode, 1, iNode);
    +-  rc = sqlite3_step(pRtree->pReadNode);
    +-  if( rc==SQLITE_ROW ){
    +-    const u8 *zBlob = sqlite3_column_blob(pRtree->pReadNode, 0);
    +-    if( pRtree->iNodeSize==sqlite3_column_bytes(pRtree->pReadNode, 0) ){
    +-      pNode = (RtreeNode *)sqlite3_malloc(sizeof(RtreeNode)+pRtree->iNodeSize);
    +-      if( !pNode ){
    +-        rc2 = SQLITE_NOMEM;
    +-      }else{
    +-        pNode->pParent = pParent;
    +-        pNode->zData = (u8 *)&pNode[1];
    +-        pNode->nRef = 1;
    +-        pNode->iNode = iNode;
    +-        pNode->isDirty = 0;
    +-        pNode->pNext = 0;
    +-        memcpy(pNode->zData, zBlob, pRtree->iNodeSize);
    +-        nodeReference(pParent);
    +-      }
    ++  if( pRtree->pNodeBlob ){
    ++    sqlite3_blob *pBlob = pRtree->pNodeBlob;
    ++    pRtree->pNodeBlob = 0;
    ++    rc = sqlite3_blob_reopen(pBlob, iNode);
    ++    pRtree->pNodeBlob = pBlob;
    ++    if( rc ){
    ++      nodeBlobReset(pRtree);
    ++      if( rc==SQLITE_NOMEM ) return SQLITE_NOMEM;
    ++    }
    ++  }
    ++  if( pRtree->pNodeBlob==0 ){
    ++    char *zTab = sqlite3_mprintf("%s_node", pRtree->zName);
    ++    if( zTab==0 ) return SQLITE_NOMEM;
    ++    rc = sqlite3_blob_open(pRtree->db, pRtree->zDb, zTab, "data", iNode, 0,
    ++                           &pRtree->pNodeBlob);
    ++    sqlite3_free(zTab);
    ++  }
    ++  if( rc ){
    ++    nodeBlobReset(pRtree);
    ++    *ppNode = 0;
    ++    /* If unable to open an sqlite3_blob on the desired row, that can only
    ++    ** be because the shadow tables hold erroneous data. */
    ++    if( rc==SQLITE_ERROR ) rc = SQLITE_CORRUPT_VTAB;
    ++  }else if( pRtree->iNodeSize==sqlite3_blob_bytes(pRtree->pNodeBlob) ){
    ++    pNode = (RtreeNode *)sqlite3_malloc(sizeof(RtreeNode)+pRtree->iNodeSize);
    ++    if( !pNode ){
    ++      rc = SQLITE_NOMEM;
    ++    }else{
    ++      pNode->pParent = pParent;
    ++      pNode->zData = (u8 *)&pNode[1];
    ++      pNode->nRef = 1;
    ++      pNode->iNode = iNode;
    ++      pNode->isDirty = 0;
    ++      pNode->pNext = 0;
    ++      rc = sqlite3_blob_read(pRtree->pNodeBlob, pNode->zData,
    ++                             pRtree->iNodeSize, 0);
    ++      nodeReference(pParent);
    +     }
    +   }
    +-  rc = sqlite3_reset(pRtree->pReadNode);
    +-  if( rc==SQLITE_OK ) rc = rc2;
    + 
    +   /* If the root node was just loaded, set pRtree->iDepth to the height
    +   ** of the r-tree structure. A height of zero means all data is stored on
    +@@ -154671,7 +167790,7 @@ static void nodeOverwriteCell(
    +   int ii;
    +   u8 *p = &pNode->zData[4 + pRtree->nBytesPerCell*iCell];
    +   p += writeInt64(p, pCell->iRowid);
    +-  for(ii=0; ii<(pRtree->nDim*2); ii++){
    ++  for(ii=0; ii<pRtree->nDim2; ii++){
    +     p += writeCoord(p, &pCell->aCoord[ii]);
    +   }
    +   pNode->isDirty = 1;
    +@@ -154805,13 +167924,16 @@ static void nodeGetCell(
    + ){
    +   u8 *pData;
    +   RtreeCoord *pCoord;
    +-  int ii;
    ++  int ii = 0;
    +   pCell->iRowid = nodeGetRowid(pRtree, pNode, iCell);
    +   pData = pNode->zData + (12 + pRtree->nBytesPerCell*iCell);
    +   pCoord = pCell->aCoord;
    +-  for(ii=0; ii<pRtree->nDim*2; ii++){
    +-    readCoord(&pData[ii*4], &pCoord[ii]);
    +-  }
    ++  do{
    ++    readCoord(pData, &pCoord[ii]);
    ++    readCoord(pData+4, &pCoord[ii+1]);
    ++    pData += 8;
    ++    ii += 2;
    ++  }while( ii<pRtree->nDim2 );
    + }
    + 
    + 
    +@@ -154862,7 +167984,9 @@ static void rtreeReference(Rtree *pRtree){
    + static void rtreeRelease(Rtree *pRtree){
    +   pRtree->nBusy--;
    +   if( pRtree->nBusy==0 ){
    +-    sqlite3_finalize(pRtree->pReadNode);
    ++    pRtree->inWrTrans = 0;
    ++    pRtree->nCursor = 0;
    ++    nodeBlobReset(pRtree);
    +     sqlite3_finalize(pRtree->pWriteNode);
    +     sqlite3_finalize(pRtree->pDeleteNode);
    +     sqlite3_finalize(pRtree->pReadRowid);
    +@@ -154900,6 +168024,7 @@ static int rtreeDestroy(sqlite3_vtab *pVtab){
    +   if( !zCreate ){
    +     rc = SQLITE_NOMEM;
    +   }else{
    ++    nodeBlobReset(pRtree);
    +     rc = sqlite3_exec(pRtree->db, zCreate, 0, 0, 0);
    +     sqlite3_free(zCreate);
    +   }
    +@@ -154915,6 +168040,7 @@ static int rtreeDestroy(sqlite3_vtab *pVtab){
    + */
    + static int rtreeOpen(sqlite3_vtab *pVTab, sqlite3_vtab_cursor **ppCursor){
    +   int rc = SQLITE_NOMEM;
    ++  Rtree *pRtree = (Rtree *)pVTab;
    +   RtreeCursor *pCsr;
    + 
    +   pCsr = (RtreeCursor *)sqlite3_malloc(sizeof(RtreeCursor));
    +@@ -154922,6 +168048,7 @@ static int rtreeOpen(sqlite3_vtab *pVTab, sqlite3_vtab_cursor **ppCursor){
    +     memset(pCsr, 0, sizeof(RtreeCursor));
    +     pCsr->base.pVtab = pVTab;
    +     rc = SQLITE_OK;
    ++    pRtree->nCursor++;
    +   }
    +   *ppCursor = (sqlite3_vtab_cursor *)pCsr;
    + 
    +@@ -154954,10 +168081,13 @@ static int rtreeClose(sqlite3_vtab_cursor *cur){
    +   Rtree *pRtree = (Rtree *)(cur->pVtab);
    +   int ii;
    +   RtreeCursor *pCsr = (RtreeCursor *)cur;
    ++  assert( pRtree->nCursor>0 );
    +   freeCursorConstraints(pCsr);
    +   sqlite3_free(pCsr->aPoint);
    +   for(ii=0; ii<RTREE_CACHE_SZ; ii++) nodeRelease(pRtree, pCsr->aNode[ii]);
    +   sqlite3_free(pCsr);
    ++  pRtree->nCursor--;
    ++  nodeBlobReset(pRtree);
    +   return SQLITE_OK;
    + }
    + 
    +@@ -154980,15 +168110,22 @@ static int rtreeEof(sqlite3_vtab_cursor *cur){
    + ** false.  a[] is the four bytes of the on-disk record to be decoded.
    + ** Store the results in "r".
    + **
    +-** 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.
    ++** There are five versions of this macro.  The last one is generic.  The
    ++** other four are various architectures-specific optimizations.
    + */
    +-#if defined(SQLITE_BYTEORDER) && SQLITE_BYTEORDER==1234
    ++#if SQLITE_BYTEORDER==1234 && MSVC_VERSION>=1300
    ++#define RTREE_DECODE_COORD(eInt, a, r) {                        \
    ++    RtreeCoord c;    /* Coordinate decoded */                   \
    ++    c.u = _byteswap_ulong(*(u32*)a);                            \
    ++    r = eInt ? (sqlite3_rtree_dbl)c.i : (sqlite3_rtree_dbl)c.f; \
    ++}
    ++#elif SQLITE_BYTEORDER==1234 && GCC_VERSION>=4003000
    ++#define RTREE_DECODE_COORD(eInt, a, r) {                        \
    ++    RtreeCoord c;    /* Coordinate decoded */                   \
    ++    c.u = __builtin_bswap32(*(u32*)a);                          \
    ++    r = eInt ? (sqlite3_rtree_dbl)c.i : (sqlite3_rtree_dbl)c.f; \
    ++}
    ++#elif SQLITE_BYTEORDER==1234
    + #define RTREE_DECODE_COORD(eInt, a, r) {                        \
    +     RtreeCoord c;    /* Coordinate decoded */                   \
    +     memcpy(&c.u,a,4);                                           \
    +@@ -154996,7 +168133,7 @@ static int rtreeEof(sqlite3_vtab_cursor *cur){
    +           ((c.u&0xff)<<24)|((c.u&0xff00)<<8);                   \
    +     r = eInt ? (sqlite3_rtree_dbl)c.i : (sqlite3_rtree_dbl)c.f; \
    + }
    +-#elif defined(SQLITE_BYTEORDER) && SQLITE_BYTEORDER==4321
    ++#elif SQLITE_BYTEORDER==4321
    + #define RTREE_DECODE_COORD(eInt, a, r) {                        \
    +     RtreeCoord c;    /* Coordinate decoded */                   \
    +     memcpy(&c.u,a,4);                                           \
    +@@ -155023,10 +168160,10 @@ static int rtreeCallbackConstraint(
    +   sqlite3_rtree_dbl *prScore,    /* OUT: score for the cell */
    +   int *peWithin                  /* OUT: visibility of the cell */
    + ){
    +-  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 */
    ++  RtreeCoord c;                                       /* Translator union */
    +   sqlite3_rtree_dbl aCoord[RTREE_MAX_DIMENSIONS*2];   /* Decoded coordinates */
    + 
    +   assert( pConstraint->op==RTREE_MATCH || pConstraint->op==RTREE_QUERY );
    +@@ -155036,13 +168173,41 @@ static int rtreeCallbackConstraint(
    +     pInfo->iRowid = readInt64(pCellData);
    +   }
    +   pCellData += 8;
    +-  for(i=0; i<nCoord; i++, pCellData += 4){
    +-    RTREE_DECODE_COORD(eInt, pCellData, aCoord[i]);
    ++#ifndef SQLITE_RTREE_INT_ONLY
    ++  if( eInt==0 ){
    ++    switch( nCoord ){
    ++      case 10:  readCoord(pCellData+36, &c); aCoord[9] = c.f;
    ++                readCoord(pCellData+32, &c); aCoord[8] = c.f;
    ++      case 8:   readCoord(pCellData+28, &c); aCoord[7] = c.f;
    ++                readCoord(pCellData+24, &c); aCoord[6] = c.f;
    ++      case 6:   readCoord(pCellData+20, &c); aCoord[5] = c.f;
    ++                readCoord(pCellData+16, &c); aCoord[4] = c.f;
    ++      case 4:   readCoord(pCellData+12, &c); aCoord[3] = c.f;
    ++                readCoord(pCellData+8,  &c); aCoord[2] = c.f;
    ++      default:  readCoord(pCellData+4,  &c); aCoord[1] = c.f;
    ++                readCoord(pCellData,    &c); aCoord[0] = c.f;
    ++    }
    ++  }else
    ++#endif
    ++  {
    ++    switch( nCoord ){
    ++      case 10:  readCoord(pCellData+36, &c); aCoord[9] = c.i;
    ++                readCoord(pCellData+32, &c); aCoord[8] = c.i;
    ++      case 8:   readCoord(pCellData+28, &c); aCoord[7] = c.i;
    ++                readCoord(pCellData+24, &c); aCoord[6] = c.i;
    ++      case 6:   readCoord(pCellData+20, &c); aCoord[5] = c.i;
    ++                readCoord(pCellData+16, &c); aCoord[4] = c.i;
    ++      case 4:   readCoord(pCellData+12, &c); aCoord[3] = c.i;
    ++                readCoord(pCellData+8,  &c); aCoord[2] = c.i;
    ++      default:  readCoord(pCellData+4,  &c); aCoord[1] = c.i;
    ++                readCoord(pCellData,    &c); aCoord[0] = c.i;
    ++    }
    +   }
    +   if( pConstraint->op==RTREE_MATCH ){
    ++    int eWithin = 0;
    +     rc = pConstraint->u.xGeom((sqlite3_rtree_geometry*)pInfo,
    +-                              nCoord, aCoord, &i);
    +-    if( i==0 ) *peWithin = NOT_WITHIN;
    ++                              nCoord, aCoord, &eWithin);
    ++    if( eWithin==0 ) *peWithin = NOT_WITHIN;
    +     *prScore = RTREE_ZERO;
    +   }else{
    +     pInfo->aCoord = aCoord;
    +@@ -155078,6 +168243,7 @@ static void rtreeNonleafConstraint(
    + 
    +   assert(p->op==RTREE_LE || p->op==RTREE_LT || p->op==RTREE_GE 
    +       || p->op==RTREE_GT || p->op==RTREE_EQ );
    ++  assert( ((((char*)pCellData) - (char*)0)&3)==0 );  /* 4-byte aligned */
    +   switch( p->op ){
    +     case RTREE_LE:
    +     case RTREE_LT:
    +@@ -155118,6 +168284,7 @@ static void rtreeLeafConstraint(
    +   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;
    ++  assert( ((((char*)pCellData) - (char*)0)&3)==0 );  /* 4-byte aligned */
    +   RTREE_DECODE_COORD(eInt, pCellData, xN);
    +   switch( p->op ){
    +     case RTREE_LE: if( xN <= p->u.rValue ) return;  break;
    +@@ -155186,7 +168353,7 @@ static int rtreeSearchPointCompare(
    + }
    + 
    + /*
    +-** Interchange to search points in a cursor.
    ++** Interchange two search points in a cursor.
    + */
    + static void rtreeSearchPointSwap(RtreeCursor *p, int i, int j){
    +   RtreeSearchPoint t = p->aPoint[i];
    +@@ -155434,7 +168601,7 @@ static int rtreeStepToLeaf(RtreeCursor *pCur){
    +       if( rScore<RTREE_ZERO ) rScore = RTREE_ZERO;
    +       p = rtreeSearchPointNew(pCur, rScore, x.iLevel);
    +       if( p==0 ) return SQLITE_NOMEM;
    +-      p->eWithin = eWithin;
    ++      p->eWithin = (u8)eWithin;
    +       p->id = x.id;
    +       p->iCell = x.iCell;
    +       RTREE_QUEUE_TRACE(pCur, "PUSH-S:");
    +@@ -155493,7 +168660,6 @@ static int rtreeColumn(sqlite3_vtab_cursor *cur, sqlite3_context *ctx, int i){
    +   if( i==0 ){
    +     sqlite3_result_int64(ctx, nodeGetRowid(pRtree, pNode, p->iCell));
    +   }else{
    +-    if( rc ) return rc;
    +     nodeGetCoord(pRtree, pNode, p->iCell, i-1, &c);
    + #ifndef SQLITE_RTREE_INT_ONLY
    +     if( pRtree->eCoordType==RTREE_COORD_REAL32 ){
    +@@ -155542,33 +168708,17 @@ static int findLeafNode(
    + ** operator.
    + */
    + static int deserializeGeometry(sqlite3_value *pValue, RtreeConstraint *pCons){
    +-  RtreeMatchArg *pBlob;              /* BLOB returned by geometry function */
    ++  RtreeMatchArg *pBlob, *pSrc;       /* 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;
    +-
    +-  /* Check that the blob is roughly the right size. */
    +-  nBlob = sqlite3_value_bytes(pValue);
    +-  if( nBlob<(int)sizeof(RtreeMatchArg) ){
    +-    return SQLITE_ERROR;
    +-  }
    +-
    +-  pInfo = (sqlite3_rtree_query_info*)sqlite3_malloc( sizeof(*pInfo)+nBlob );
    ++  pSrc = sqlite3_value_pointer(pValue, "RtreeMatchArg");
    ++  if( pSrc==0 ) return SQLITE_ERROR;
    ++  pInfo = (sqlite3_rtree_query_info*)
    ++                sqlite3_malloc64( sizeof(*pInfo)+pSrc->iSize );
    +   if( !pInfo ) return SQLITE_NOMEM;
    +   memset(pInfo, 0, sizeof(*pInfo));
    +   pBlob = (RtreeMatchArg*)&pInfo[1];
    +-
    +-  memcpy(pBlob, sqlite3_value_blob(pValue), nBlob);
    +-  nExpected = (int)(sizeof(RtreeMatchArg) +
    +-                    pBlob->nParam*sizeof(sqlite3_value*) +
    +-                    (pBlob->nParam-1)*sizeof(RtreeDValue));
    +-  if( pBlob->magic!=RTREE_GEOMETRY_MAGIC || nBlob!=nExpected ){
    +-    sqlite3_free(pInfo);
    +-    return SQLITE_ERROR;
    +-  }
    ++  memcpy(pBlob, pSrc, pSrc->iSize);
    +   pInfo->pContext = pBlob->cb.pContext;
    +   pInfo->nParam = pBlob->nParam;
    +   pInfo->aParam = pBlob->aParam;
    +@@ -155611,7 +168761,7 @@ static int rtreeFilter(
    +   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 */
    ++    RtreeSearchPoint *p;     /* Search point for the leaf */
    +     i64 iRowid = sqlite3_value_int64(argv[0]);
    +     i64 iNode = 0;
    +     rc = findLeafNode(pRtree, iRowid, &pLeaf, &iNode);
    +@@ -155622,7 +168772,7 @@ static int rtreeFilter(
    +       p->id = iNode;
    +       p->eWithin = PARTLY_WITHIN;
    +       rc = nodeRowidIndex(pRtree, pLeaf, iRowid, &iCell);
    +-      p->iCell = iCell;
    ++      p->iCell = (u8)iCell;
    +       RTREE_QUEUE_TRACE(pCsr, "PUSH-F1:");
    +     }else{
    +       pCsr->atEOF = 1;
    +@@ -155655,7 +168805,7 @@ static int rtreeFilter(
    +             if( rc!=SQLITE_OK ){
    +               break;
    +             }
    +-            p->pInfo->nCoord = pRtree->nDim*2;
    ++            p->pInfo->nCoord = pRtree->nDim2;
    +             p->pInfo->anQueue = pCsr->anQueue;
    +             p->pInfo->mxLevel = pRtree->iDepth + 1;
    +           }else{
    +@@ -155670,7 +168820,7 @@ static int rtreeFilter(
    +     }
    +     if( rc==SQLITE_OK ){
    +       RtreeSearchPoint *pNew;
    +-      pNew = rtreeSearchPointNew(pCsr, RTREE_ZERO, pRtree->iDepth+1);
    ++      pNew = rtreeSearchPointNew(pCsr, RTREE_ZERO, (u8)(pRtree->iDepth+1));
    +       if( pNew==0 ) return SQLITE_NOMEM;
    +       pNew->id = 1;
    +       pNew->iCell = 0;
    +@@ -155688,19 +168838,6 @@ static int rtreeFilter(
    +   return rc;
    + }
    + 
    +-/*
    +-** Set the pIdxInfo->estimatedRows variable to nRow. Unless this
    +-** extension is currently being used by a version of SQLite too old to
    +-** support estimatedRows. In that case this function is a no-op.
    +-*/
    +-static void setEstimatedRows(sqlite3_index_info *pIdxInfo, i64 nRow){
    +-#if SQLITE_VERSION_NUMBER>=3008002
    +-  if( sqlite3_libversion_number()>=3008002 ){
    +-    pIdxInfo->estimatedRows = nRow;
    +-  }
    +-#endif
    +-}
    +-
    + /*
    + ** Rtree virtual table module xBestIndex method. There are three
    + ** table scan strategies to choose from (in order from most to 
    +@@ -155780,7 +168917,7 @@ static int rtreeBestIndex(sqlite3_vtab *tab, sqlite3_index_info *pIdxInfo){
    +       ** a single row.
    +       */ 
    +       pIdxInfo->estimatedCost = 30.0;
    +-      setEstimatedRows(pIdxInfo, 1);
    ++      pIdxInfo->estimatedRows = 1;
    +       return SQLITE_OK;
    +     }
    + 
    +@@ -155798,7 +168935,7 @@ static int rtreeBestIndex(sqlite3_vtab *tab, sqlite3_index_info *pIdxInfo){
    +           break;
    +       }
    +       zIdxStr[iIdx++] = op;
    +-      zIdxStr[iIdx++] = p->iColumn - 1 + '0';
    ++      zIdxStr[iIdx++] = (char)(p->iColumn - 1 + '0');
    +       pIdxInfo->aConstraintUsage[ii].argvIndex = (iIdx/2);
    +       pIdxInfo->aConstraintUsage[ii].omit = 1;
    +     }
    +@@ -155810,9 +168947,9 @@ static int rtreeBestIndex(sqlite3_vtab *tab, sqlite3_index_info *pIdxInfo){
    +     return SQLITE_NOMEM;
    +   }
    + 
    +-  nRow = pRtree->nRowEst / (iIdx + 1);
    ++  nRow = pRtree->nRowEst >> (iIdx/2);
    +   pIdxInfo->estimatedCost = (double)6.0 * (double)nRow;
    +-  setEstimatedRows(pIdxInfo, nRow);
    ++  pIdxInfo->estimatedRows = nRow;
    + 
    +   return rc;
    + }
    +@@ -155822,9 +168959,26 @@ static int rtreeBestIndex(sqlite3_vtab *tab, sqlite3_index_info *pIdxInfo){
    + */
    + static RtreeDValue cellArea(Rtree *pRtree, RtreeCell *p){
    +   RtreeDValue area = (RtreeDValue)1;
    +-  int ii;
    +-  for(ii=0; ii<(pRtree->nDim*2); ii+=2){
    +-    area = (area * (DCOORD(p->aCoord[ii+1]) - DCOORD(p->aCoord[ii])));
    ++  assert( pRtree->nDim>=1 && pRtree->nDim<=5 );
    ++#ifndef SQLITE_RTREE_INT_ONLY
    ++  if( pRtree->eCoordType==RTREE_COORD_REAL32 ){
    ++    switch( pRtree->nDim ){
    ++      case 5:  area  = p->aCoord[9].f - p->aCoord[8].f;
    ++      case 4:  area *= p->aCoord[7].f - p->aCoord[6].f;
    ++      case 3:  area *= p->aCoord[5].f - p->aCoord[4].f;
    ++      case 2:  area *= p->aCoord[3].f - p->aCoord[2].f;
    ++      default: area *= p->aCoord[1].f - p->aCoord[0].f;
    ++    }
    ++  }else
    ++#endif
    ++  {
    ++    switch( pRtree->nDim ){
    ++      case 5:  area  = p->aCoord[9].i - p->aCoord[8].i;
    ++      case 4:  area *= p->aCoord[7].i - p->aCoord[6].i;
    ++      case 3:  area *= p->aCoord[5].i - p->aCoord[4].i;
    ++      case 2:  area *= p->aCoord[3].i - p->aCoord[2].i;
    ++      default: area *= p->aCoord[1].i - p->aCoord[0].i;
    ++    }
    +   }
    +   return area;
    + }
    +@@ -155834,11 +168988,12 @@ static RtreeDValue cellArea(Rtree *pRtree, RtreeCell *p){
    + ** of the objects size in each dimension.
    + */
    + static RtreeDValue cellMargin(Rtree *pRtree, RtreeCell *p){
    +-  RtreeDValue margin = (RtreeDValue)0;
    +-  int ii;
    +-  for(ii=0; ii<(pRtree->nDim*2); ii+=2){
    ++  RtreeDValue margin = 0;
    ++  int ii = pRtree->nDim2 - 2;
    ++  do{
    +     margin += (DCOORD(p->aCoord[ii+1]) - DCOORD(p->aCoord[ii]));
    +-  }
    ++    ii -= 2;
    ++  }while( ii>=0 );
    +   return margin;
    + }
    + 
    +@@ -155846,17 +169001,19 @@ static RtreeDValue cellMargin(Rtree *pRtree, RtreeCell *p){
    + ** Store the union of cells p1 and p2 in p1.
    + */
    + static void cellUnion(Rtree *pRtree, RtreeCell *p1, RtreeCell *p2){
    +-  int ii;
    ++  int ii = 0;
    +   if( pRtree->eCoordType==RTREE_COORD_REAL32 ){
    +-    for(ii=0; ii<(pRtree->nDim*2); ii+=2){
    ++    do{
    +       p1->aCoord[ii].f = MIN(p1->aCoord[ii].f, p2->aCoord[ii].f);
    +       p1->aCoord[ii+1].f = MAX(p1->aCoord[ii+1].f, p2->aCoord[ii+1].f);
    +-    }
    ++      ii += 2;
    ++    }while( ii<pRtree->nDim2 );
    +   }else{
    +-    for(ii=0; ii<(pRtree->nDim*2); ii+=2){
    ++    do{
    +       p1->aCoord[ii].i = MIN(p1->aCoord[ii].i, p2->aCoord[ii].i);
    +       p1->aCoord[ii+1].i = MAX(p1->aCoord[ii+1].i, p2->aCoord[ii+1].i);
    +-    }
    ++      ii += 2;
    ++    }while( ii<pRtree->nDim2 );
    +   }
    + }
    + 
    +@@ -155867,7 +169024,7 @@ static void cellUnion(Rtree *pRtree, RtreeCell *p1, RtreeCell *p2){
    + static int cellContains(Rtree *pRtree, RtreeCell *p1, RtreeCell *p2){
    +   int ii;
    +   int isInt = (pRtree->eCoordType==RTREE_COORD_INT32);
    +-  for(ii=0; ii<(pRtree->nDim*2); ii+=2){
    ++  for(ii=0; ii<pRtree->nDim2; ii+=2){
    +     RtreeCoord *a1 = &p1->aCoord[ii];
    +     RtreeCoord *a2 = &p2->aCoord[ii];
    +     if( (!isInt && (a2[0].f<a1[0].f || a2[1].f>a1[1].f)) 
    +@@ -155902,7 +169059,7 @@ static RtreeDValue cellOverlap(
    +   for(ii=0; ii<nCell; ii++){
    +     int jj;
    +     RtreeDValue o = (RtreeDValue)1;
    +-    for(jj=0; jj<(pRtree->nDim*2); jj+=2){
    ++    for(jj=0; jj<pRtree->nDim2; 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]));
    +@@ -155931,7 +169088,7 @@ static int ChooseLeaf(
    + ){
    +   int rc;
    +   int ii;
    +-  RtreeNode *pNode;
    ++  RtreeNode *pNode = 0;
    +   rc = nodeAcquire(pRtree, 1, 0, &pNode);
    + 
    +   for(ii=0; rc==SQLITE_OK && ii<(pRtree->iDepth-iHeight); ii++){
    +@@ -156763,7 +169920,7 @@ static int rtreeDeleteRowid(Rtree *pRtree, sqlite3_int64 iDelete){
    +   int rc;                         /* Return code */
    +   RtreeNode *pLeaf = 0;           /* Leaf node containing record iDelete */
    +   int iCell;                      /* Index of iDelete cell in pLeaf */
    +-  RtreeNode *pRoot;               /* Root node of rtree structure */
    ++  RtreeNode *pRoot = 0;           /* Root node of rtree structure */
    + 
    + 
    +   /* Obtain a reference to the root node to initialize Rtree.iDepth */
    +@@ -156806,7 +169963,7 @@ static int rtreeDeleteRowid(Rtree *pRtree, sqlite3_int64 iDelete){
    +   */
    +   if( rc==SQLITE_OK && pRtree->iDepth>0 && NCELL(pRoot)==1 ){
    +     int rc2;
    +-    RtreeNode *pChild;
    ++    RtreeNode *pChild = 0;
    +     i64 iChild = nodeGetRowid(pRtree, pRoot, 0);
    +     rc = nodeAcquire(pRtree, iChild, pRoot, &pChild);
    +     if( rc==SQLITE_OK ){
    +@@ -156869,6 +170026,53 @@ static RtreeValue rtreeValueUp(sqlite3_value *v){
    + }
    + #endif /* !defined(SQLITE_RTREE_INT_ONLY) */
    + 
    ++/*
    ++** A constraint has failed while inserting a row into an rtree table. 
    ++** Assuming no OOM error occurs, this function sets the error message 
    ++** (at pRtree->base.zErrMsg) to an appropriate value and returns
    ++** SQLITE_CONSTRAINT.
    ++**
    ++** Parameter iCol is the index of the leftmost column involved in the
    ++** constraint failure. If it is 0, then the constraint that failed is
    ++** the unique constraint on the id column. Otherwise, it is the rtree
    ++** (c1<=c2) constraint on columns iCol and iCol+1 that has failed.
    ++**
    ++** If an OOM occurs, SQLITE_NOMEM is returned instead of SQLITE_CONSTRAINT.
    ++*/
    ++static int rtreeConstraintError(Rtree *pRtree, int iCol){
    ++  sqlite3_stmt *pStmt = 0;
    ++  char *zSql; 
    ++  int rc;
    ++
    ++  assert( iCol==0 || iCol%2 );
    ++  zSql = sqlite3_mprintf("SELECT * FROM %Q.%Q", pRtree->zDb, pRtree->zName);
    ++  if( zSql ){
    ++    rc = sqlite3_prepare_v2(pRtree->db, zSql, -1, &pStmt, 0);
    ++  }else{
    ++    rc = SQLITE_NOMEM;
    ++  }
    ++  sqlite3_free(zSql);
    ++
    ++  if( rc==SQLITE_OK ){
    ++    if( iCol==0 ){
    ++      const char *zCol = sqlite3_column_name(pStmt, 0);
    ++      pRtree->base.zErrMsg = sqlite3_mprintf(
    ++          "UNIQUE constraint failed: %s.%s", pRtree->zName, zCol
    ++      );
    ++    }else{
    ++      const char *zCol1 = sqlite3_column_name(pStmt, iCol);
    ++      const char *zCol2 = sqlite3_column_name(pStmt, iCol+1);
    ++      pRtree->base.zErrMsg = sqlite3_mprintf(
    ++          "rtree constraint failed: %s.(%s<=%s)", pRtree->zName, zCol1, zCol2
    ++      );
    ++    }
    ++  }
    ++
    ++  sqlite3_finalize(pStmt);
    ++  return (rc==SQLITE_OK ? SQLITE_CONSTRAINT : rc);
    ++}
    ++
    ++
    + 
    + /*
    + ** The xUpdate method for rtree module virtual tables.
    +@@ -156911,7 +170115,7 @@ static int rtreeUpdate(
    +     ** This problem was discovered after years of use, so we silently ignore
    +     ** these kinds of misdeclared tables to avoid breaking any legacy.
    +     */
    +-    assert( nData<=(pRtree->nDim*2 + 3) );
    ++    assert( nData<=(pRtree->nDim2 + 3) );
    + 
    + #ifndef SQLITE_RTREE_INT_ONLY
    +     if( pRtree->eCoordType==RTREE_COORD_REAL32 ){
    +@@ -156919,7 +170123,7 @@ static int rtreeUpdate(
    +         cell.aCoord[ii].f = rtreeValueDown(azData[ii+3]);
    +         cell.aCoord[ii+1].f = rtreeValueUp(azData[ii+4]);
    +         if( cell.aCoord[ii].f>cell.aCoord[ii+1].f ){
    +-          rc = SQLITE_CONSTRAINT;
    ++          rc = rtreeConstraintError(pRtree, ii+1);
    +           goto constraint;
    +         }
    +       }
    +@@ -156930,7 +170134,7 @@ static int rtreeUpdate(
    +         cell.aCoord[ii].i = sqlite3_value_int(azData[ii+3]);
    +         cell.aCoord[ii+1].i = sqlite3_value_int(azData[ii+4]);
    +         if( cell.aCoord[ii].i>cell.aCoord[ii+1].i ){
    +-          rc = SQLITE_CONSTRAINT;
    ++          rc = rtreeConstraintError(pRtree, ii+1);
    +           goto constraint;
    +         }
    +       }
    +@@ -156951,7 +170155,7 @@ static int rtreeUpdate(
    +           if( sqlite3_vtab_on_conflict(pRtree->db)==SQLITE_REPLACE ){
    +             rc = rtreeDeleteRowid(pRtree, cell.iRowid);
    +           }else{
    +-            rc = SQLITE_CONSTRAINT;
    ++            rc = rtreeConstraintError(pRtree, 0);
    +             goto constraint;
    +           }
    +         }
    +@@ -157001,6 +170205,27 @@ constraint:
    +   return rc;
    + }
    + 
    ++/*
    ++** Called when a transaction starts.
    ++*/
    ++static int rtreeBeginTransaction(sqlite3_vtab *pVtab){
    ++  Rtree *pRtree = (Rtree *)pVtab;
    ++  assert( pRtree->inWrTrans==0 );
    ++  pRtree->inWrTrans++;
    ++  return SQLITE_OK;
    ++}
    ++
    ++/*
    ++** Called when a transaction completes (either by COMMIT or ROLLBACK).
    ++** The sqlite3_blob object should be released at this point.
    ++*/
    ++static int rtreeEndTransaction(sqlite3_vtab *pVtab){
    ++  Rtree *pRtree = (Rtree *)pVtab;
    ++  pRtree->inWrTrans = 0;
    ++  nodeBlobReset(pRtree);
    ++  return SQLITE_OK;
    ++}
    ++
    + /*
    + ** The xRename method for rtree module virtual tables.
    + */
    +@@ -157016,12 +170241,37 @@ static int rtreeRename(sqlite3_vtab *pVtab, const char *zNewName){
    +     , pRtree->zDb, pRtree->zName, zNewName
    +   );
    +   if( zSql ){
    ++    nodeBlobReset(pRtree);
    +     rc = sqlite3_exec(pRtree->db, zSql, 0, 0, 0);
    +     sqlite3_free(zSql);
    +   }
    +   return rc;
    + }
    + 
    ++/*
    ++** The xSavepoint method.
    ++**
    ++** This module does not need to do anything to support savepoints. However,
    ++** it uses this hook to close any open blob handle. This is done because a 
    ++** DROP TABLE command - which fortunately always opens a savepoint - cannot 
    ++** succeed if there are any open blob handles. i.e. if the blob handle were
    ++** not closed here, the following would fail:
    ++**
    ++**   BEGIN;
    ++**     INSERT INTO rtree...
    ++**     DROP TABLE <tablename>;    -- Would fail with SQLITE_LOCKED
    ++**   COMMIT;
    ++*/
    ++static int rtreeSavepoint(sqlite3_vtab *pVtab, int iSavepoint){
    ++  Rtree *pRtree = (Rtree *)pVtab;
    ++  int iwt = pRtree->inWrTrans;
    ++  UNUSED_PARAMETER(iSavepoint);
    ++  pRtree->inWrTrans = 0;
    ++  nodeBlobReset(pRtree);
    ++  pRtree->inWrTrans = iwt;
    ++  return SQLITE_OK;
    ++}
    ++
    + /*
    + ** This function populates the pRtree->nRowEst variable with an estimate
    + ** of the number of rows in the virtual table. If possible, this is based
    +@@ -157034,6 +170284,13 @@ static int rtreeQueryStat1(sqlite3 *db, Rtree *pRtree){
    +   int rc;
    +   i64 nRow = 0;
    + 
    ++  rc = sqlite3_table_column_metadata(
    ++      db, pRtree->zDb, "sqlite_stat1",0,0,0,0,0,0
    ++  );
    ++  if( rc!=SQLITE_OK ){
    ++    pRtree->nRowEst = RTREE_DEFAULT_ROWEST;
    ++    return rc==SQLITE_ERROR ? SQLITE_OK : rc;
    ++  }
    +   zSql = sqlite3_mprintf(zFmt, pRtree->zDb, pRtree->zName);
    +   if( zSql==0 ){
    +     rc = SQLITE_NOMEM;
    +@@ -157060,7 +170317,7 @@ static int rtreeQueryStat1(sqlite3 *db, Rtree *pRtree){
    + }
    + 
    + static sqlite3_module rtreeModule = {
    +-  0,                          /* iVersion */
    ++  2,                          /* iVersion */
    +   rtreeCreate,                /* xCreate - create a table */
    +   rtreeConnect,               /* xConnect - connect to an existing table */
    +   rtreeBestIndex,             /* xBestIndex - Determine search strategy */
    +@@ -157074,15 +170331,15 @@ static sqlite3_module rtreeModule = {
    +   rtreeColumn,                /* xColumn - read data */
    +   rtreeRowid,                 /* xRowid - read data */
    +   rtreeUpdate,                /* xUpdate - write data */
    +-  0,                          /* xBegin - begin transaction */
    +-  0,                          /* xSync - sync transaction */
    +-  0,                          /* xCommit - commit transaction */
    +-  0,                          /* xRollback - rollback transaction */
    ++  rtreeBeginTransaction,      /* xBegin - begin transaction */
    ++  rtreeEndTransaction,        /* xSync - sync transaction */
    ++  rtreeEndTransaction,        /* xCommit - commit transaction */
    ++  rtreeEndTransaction,        /* xRollback - rollback transaction */
    +   0,                          /* xFindFunction - function overloading */
    +   rtreeRename,                /* xRename - rename the table */
    +-  0,                          /* xSavepoint */
    ++  rtreeSavepoint,             /* xSavepoint */
    +   0,                          /* xRelease */
    +-  0                           /* xRollbackTo */
    ++  0,                          /* xRollbackTo */
    + };
    + 
    + static int rtreeSqlInit(
    +@@ -157094,10 +170351,9 @@ static int rtreeSqlInit(
    + ){
    +   int rc = SQLITE_OK;
    + 
    +-  #define N_STATEMENT 9
    ++  #define N_STATEMENT 8
    +   static const char *azSql[N_STATEMENT] = {
    +-    /* Read and write the xxx_node table */
    +-    "SELECT data FROM '%q'.'%q_node' WHERE nodeno = :1",
    ++    /* Write the xxx_node table */
    +     "INSERT OR REPLACE INTO '%q'.'%q_node' VALUES(:1, :2)",
    +     "DELETE FROM '%q'.'%q_node' WHERE nodeno = :1",
    + 
    +@@ -157135,21 +170391,21 @@ static int rtreeSqlInit(
    +     }
    +   }
    + 
    +-  appStmt[0] = &pRtree->pReadNode;
    +-  appStmt[1] = &pRtree->pWriteNode;
    +-  appStmt[2] = &pRtree->pDeleteNode;
    +-  appStmt[3] = &pRtree->pReadRowid;
    +-  appStmt[4] = &pRtree->pWriteRowid;
    +-  appStmt[5] = &pRtree->pDeleteRowid;
    +-  appStmt[6] = &pRtree->pReadParent;
    +-  appStmt[7] = &pRtree->pWriteParent;
    +-  appStmt[8] = &pRtree->pDeleteParent;
    ++  appStmt[0] = &pRtree->pWriteNode;
    ++  appStmt[1] = &pRtree->pDeleteNode;
    ++  appStmt[2] = &pRtree->pReadRowid;
    ++  appStmt[3] = &pRtree->pWriteRowid;
    ++  appStmt[4] = &pRtree->pDeleteRowid;
    ++  appStmt[5] = &pRtree->pReadParent;
    ++  appStmt[6] = &pRtree->pWriteParent;
    ++  appStmt[7] = &pRtree->pDeleteParent;
    + 
    +   rc = rtreeQueryStat1(db, pRtree);
    +   for(i=0; i<N_STATEMENT && rc==SQLITE_OK; i++){
    +     char *zSql = sqlite3_mprintf(azSql[i], zDb, zPrefix);
    +     if( zSql ){
    +-      rc = sqlite3_prepare_v2(db, zSql, -1, appStmt[i], 0); 
    ++      rc = sqlite3_prepare_v3(db, zSql, -1, SQLITE_PREPARE_PERSISTENT,
    ++                              appStmt[i], 0); 
    +     }else{
    +       rc = SQLITE_NOMEM;
    +     }
    +@@ -157224,6 +170480,10 @@ static int getNodeSize(
    +     rc = getIntFromStmt(db, zSql, &pRtree->iNodeSize);
    +     if( rc!=SQLITE_OK ){
    +       *pzErr = sqlite3_mprintf("%s", sqlite3_errmsg(db));
    ++    }else if( pRtree->iNodeSize<(512-64) ){
    ++      rc = SQLITE_CORRUPT_VTAB;
    ++      *pzErr = sqlite3_mprintf("undersize RTree blobs in \"%q_node\"",
    ++                               pRtree->zName);
    +     }
    +   }
    + 
    +@@ -157281,9 +170541,10 @@ static int rtreeInit(
    +   pRtree->base.pModule = &rtreeModule;
    +   pRtree->zDb = (char *)&pRtree[1];
    +   pRtree->zName = &pRtree->zDb[nDb+1];
    +-  pRtree->nDim = (argc-4)/2;
    +-  pRtree->nBytesPerCell = 8 + pRtree->nDim*4*2;
    +-  pRtree->eCoordType = eCoordType;
    ++  pRtree->nDim = (u8)((argc-4)/2);
    ++  pRtree->nDim2 = pRtree->nDim*2;
    ++  pRtree->nBytesPerCell = 8 + pRtree->nDim2*4;
    ++  pRtree->eCoordType = (u8)eCoordType;
    +   memcpy(pRtree->zDb, argv[1], nDb);
    +   memcpy(pRtree->zName, argv[2], nName);
    + 
    +@@ -157356,7 +170617,8 @@ static void rtreenode(sqlite3_context *ctx, int nArg, sqlite3_value **apArg){
    +   UNUSED_PARAMETER(nArg);
    +   memset(&node, 0, sizeof(RtreeNode));
    +   memset(&tree, 0, sizeof(Rtree));
    +-  tree.nDim = sqlite3_value_int(apArg[0]);
    ++  tree.nDim = (u8)sqlite3_value_int(apArg[0]);
    ++  tree.nDim2 = tree.nDim*2;
    +   tree.nBytesPerCell = 8 + 8 * tree.nDim;
    +   node.zData = (u8 *)sqlite3_value_blob(apArg[1]);
    + 
    +@@ -157369,7 +170631,7 @@ static void rtreenode(sqlite3_context *ctx, int nArg, sqlite3_value **apArg){
    +     nodeGetCell(&tree, &node, ii, &cell);
    +     sqlite3_snprintf(512-nCell,&zCell[nCell],"%lld", cell.iRowid);
    +     nCell = (int)strlen(zCell);
    +-    for(jj=0; jj<tree.nDim*2; jj++){
    ++    for(jj=0; jj<tree.nDim2; jj++){
    + #ifndef SQLITE_RTREE_INT_ONLY
    +       sqlite3_snprintf(512-nCell,&zCell[nCell], " %g",
    +                        (double)cell.aCoord[jj].f);
    +@@ -157413,6 +170675,463 @@ static void rtreedepth(sqlite3_context *ctx, int nArg, sqlite3_value **apArg){
    +   }
    + }
    + 
    ++/*
    ++** Context object passed between the various routines that make up the
    ++** implementation of integrity-check function rtreecheck().
    ++*/
    ++typedef struct RtreeCheck RtreeCheck;
    ++struct RtreeCheck {
    ++  sqlite3 *db;                    /* Database handle */
    ++  const char *zDb;                /* Database containing rtree table */
    ++  const char *zTab;               /* Name of rtree table */
    ++  int bInt;                       /* True for rtree_i32 table */
    ++  int nDim;                       /* Number of dimensions for this rtree tbl */
    ++  sqlite3_stmt *pGetNode;         /* Statement used to retrieve nodes */
    ++  sqlite3_stmt *aCheckMapping[2]; /* Statements to query %_parent/%_rowid */
    ++  int nLeaf;                      /* Number of leaf cells in table */
    ++  int nNonLeaf;                   /* Number of non-leaf cells in table */
    ++  int rc;                         /* Return code */
    ++  char *zReport;                  /* Message to report */
    ++  int nErr;                       /* Number of lines in zReport */
    ++};
    ++
    ++#define RTREE_CHECK_MAX_ERROR 100
    ++
    ++/*
    ++** Reset SQL statement pStmt. If the sqlite3_reset() call returns an error,
    ++** and RtreeCheck.rc==SQLITE_OK, set RtreeCheck.rc to the error code.
    ++*/
    ++static void rtreeCheckReset(RtreeCheck *pCheck, sqlite3_stmt *pStmt){
    ++  int rc = sqlite3_reset(pStmt);
    ++  if( pCheck->rc==SQLITE_OK ) pCheck->rc = rc;
    ++}
    ++
    ++/*
    ++** The second and subsequent arguments to this function are a format string
    ++** and printf style arguments. This function formats the string and attempts
    ++** to compile it as an SQL statement.
    ++**
    ++** If successful, a pointer to the new SQL statement is returned. Otherwise,
    ++** NULL is returned and an error code left in RtreeCheck.rc.
    ++*/
    ++static sqlite3_stmt *rtreeCheckPrepare(
    ++  RtreeCheck *pCheck,             /* RtreeCheck object */
    ++  const char *zFmt, ...           /* Format string and trailing args */
    ++){
    ++  va_list ap;
    ++  char *z;
    ++  sqlite3_stmt *pRet = 0;
    ++
    ++  va_start(ap, zFmt);
    ++  z = sqlite3_vmprintf(zFmt, ap);
    ++
    ++  if( pCheck->rc==SQLITE_OK ){
    ++    if( z==0 ){
    ++      pCheck->rc = SQLITE_NOMEM;
    ++    }else{
    ++      pCheck->rc = sqlite3_prepare_v2(pCheck->db, z, -1, &pRet, 0);
    ++    }
    ++  }
    ++
    ++  sqlite3_free(z);
    ++  va_end(ap);
    ++  return pRet;
    ++}
    ++
    ++/*
    ++** The second and subsequent arguments to this function are a printf()
    ++** style format string and arguments. This function formats the string and
    ++** appends it to the report being accumuated in pCheck.
    ++*/
    ++static void rtreeCheckAppendMsg(RtreeCheck *pCheck, const char *zFmt, ...){
    ++  va_list ap;
    ++  va_start(ap, zFmt);
    ++  if( pCheck->rc==SQLITE_OK && pCheck->nErr<RTREE_CHECK_MAX_ERROR ){
    ++    char *z = sqlite3_vmprintf(zFmt, ap);
    ++    if( z==0 ){
    ++      pCheck->rc = SQLITE_NOMEM;
    ++    }else{
    ++      pCheck->zReport = sqlite3_mprintf("%z%s%z", 
    ++          pCheck->zReport, (pCheck->zReport ? "\n" : ""), z
    ++      );
    ++      if( pCheck->zReport==0 ){
    ++        pCheck->rc = SQLITE_NOMEM;
    ++      }
    ++    }
    ++    pCheck->nErr++;
    ++  }
    ++  va_end(ap);
    ++}
    ++
    ++/*
    ++** This function is a no-op if there is already an error code stored
    ++** in the RtreeCheck object indicated by the first argument. NULL is
    ++** returned in this case.
    ++**
    ++** Otherwise, the contents of rtree table node iNode are loaded from
    ++** the database and copied into a buffer obtained from sqlite3_malloc().
    ++** If no error occurs, a pointer to the buffer is returned and (*pnNode)
    ++** is set to the size of the buffer in bytes.
    ++**
    ++** Or, if an error does occur, NULL is returned and an error code left
    ++** in the RtreeCheck object. The final value of *pnNode is undefined in
    ++** this case.
    ++*/
    ++static u8 *rtreeCheckGetNode(RtreeCheck *pCheck, i64 iNode, int *pnNode){
    ++  u8 *pRet = 0;                   /* Return value */
    ++
    ++  assert( pCheck->rc==SQLITE_OK );
    ++  if( pCheck->pGetNode==0 ){
    ++    pCheck->pGetNode = rtreeCheckPrepare(pCheck,
    ++        "SELECT data FROM %Q.'%q_node' WHERE nodeno=?", 
    ++        pCheck->zDb, pCheck->zTab
    ++    );
    ++  }
    ++
    ++  if( pCheck->rc==SQLITE_OK ){
    ++    sqlite3_bind_int64(pCheck->pGetNode, 1, iNode);
    ++    if( sqlite3_step(pCheck->pGetNode)==SQLITE_ROW ){
    ++      int nNode = sqlite3_column_bytes(pCheck->pGetNode, 0);
    ++      const u8 *pNode = (const u8*)sqlite3_column_blob(pCheck->pGetNode, 0);
    ++      pRet = sqlite3_malloc(nNode);
    ++      if( pRet==0 ){
    ++        pCheck->rc = SQLITE_NOMEM;
    ++      }else{
    ++        memcpy(pRet, pNode, nNode);
    ++        *pnNode = nNode;
    ++      }
    ++    }
    ++    rtreeCheckReset(pCheck, pCheck->pGetNode);
    ++    if( pCheck->rc==SQLITE_OK && pRet==0 ){
    ++      rtreeCheckAppendMsg(pCheck, "Node %lld missing from database", iNode);
    ++    }
    ++  }
    ++
    ++  return pRet;
    ++}
    ++
    ++/*
    ++** This function is used to check that the %_parent (if bLeaf==0) or %_rowid
    ++** (if bLeaf==1) table contains a specified entry. The schemas of the
    ++** two tables are:
    ++**
    ++**   CREATE TABLE %_parent(nodeno INTEGER PRIMARY KEY, parentnode INTEGER)
    ++**   CREATE TABLE %_rowid(rowid INTEGER PRIMARY KEY, nodeno INTEGER)
    ++**
    ++** In both cases, this function checks that there exists an entry with
    ++** IPK value iKey and the second column set to iVal.
    ++**
    ++*/
    ++static void rtreeCheckMapping(
    ++  RtreeCheck *pCheck,             /* RtreeCheck object */
    ++  int bLeaf,                      /* True for a leaf cell, false for interior */
    ++  i64 iKey,                       /* Key for mapping */
    ++  i64 iVal                        /* Expected value for mapping */
    ++){
    ++  int rc;
    ++  sqlite3_stmt *pStmt;
    ++  const char *azSql[2] = {
    ++    "SELECT parentnode FROM %Q.'%q_parent' WHERE nodeno=?",
    ++    "SELECT nodeno FROM %Q.'%q_rowid' WHERE rowid=?"
    ++  };
    ++
    ++  assert( bLeaf==0 || bLeaf==1 );
    ++  if( pCheck->aCheckMapping[bLeaf]==0 ){
    ++    pCheck->aCheckMapping[bLeaf] = rtreeCheckPrepare(pCheck,
    ++        azSql[bLeaf], pCheck->zDb, pCheck->zTab
    ++    );
    ++  }
    ++  if( pCheck->rc!=SQLITE_OK ) return;
    ++
    ++  pStmt = pCheck->aCheckMapping[bLeaf];
    ++  sqlite3_bind_int64(pStmt, 1, iKey);
    ++  rc = sqlite3_step(pStmt);
    ++  if( rc==SQLITE_DONE ){
    ++    rtreeCheckAppendMsg(pCheck, "Mapping (%lld -> %lld) missing from %s table",
    ++        iKey, iVal, (bLeaf ? "%_rowid" : "%_parent")
    ++    );
    ++  }else if( rc==SQLITE_ROW ){
    ++    i64 ii = sqlite3_column_int64(pStmt, 0);
    ++    if( ii!=iVal ){
    ++      rtreeCheckAppendMsg(pCheck, 
    ++          "Found (%lld -> %lld) in %s table, expected (%lld -> %lld)",
    ++          iKey, ii, (bLeaf ? "%_rowid" : "%_parent"), iKey, iVal
    ++      );
    ++    }
    ++  }
    ++  rtreeCheckReset(pCheck, pStmt);
    ++}
    ++
    ++/*
    ++** Argument pCell points to an array of coordinates stored on an rtree page.
    ++** This function checks that the coordinates are internally consistent (no
    ++** x1>x2 conditions) and adds an error message to the RtreeCheck object
    ++** if they are not.
    ++**
    ++** Additionally, if pParent is not NULL, then it is assumed to point to
    ++** the array of coordinates on the parent page that bound the page 
    ++** containing pCell. In this case it is also verified that the two
    ++** sets of coordinates are mutually consistent and an error message added
    ++** to the RtreeCheck object if they are not.
    ++*/
    ++static void rtreeCheckCellCoord(
    ++  RtreeCheck *pCheck, 
    ++  i64 iNode,                      /* Node id to use in error messages */
    ++  int iCell,                      /* Cell number to use in error messages */
    ++  u8 *pCell,                      /* Pointer to cell coordinates */
    ++  u8 *pParent                     /* Pointer to parent coordinates */
    ++){
    ++  RtreeCoord c1, c2;
    ++  RtreeCoord p1, p2;
    ++  int i;
    ++
    ++  for(i=0; i<pCheck->nDim; i++){
    ++    readCoord(&pCell[4*2*i], &c1);
    ++    readCoord(&pCell[4*(2*i + 1)], &c2);
    ++
    ++    /* printf("%e, %e\n", c1.u.f, c2.u.f); */
    ++    if( pCheck->bInt ? c1.i>c2.i : c1.f>c2.f ){
    ++      rtreeCheckAppendMsg(pCheck, 
    ++          "Dimension %d of cell %d on node %lld is corrupt", i, iCell, iNode
    ++      );
    ++    }
    ++
    ++    if( pParent ){
    ++      readCoord(&pParent[4*2*i], &p1);
    ++      readCoord(&pParent[4*(2*i + 1)], &p2);
    ++
    ++      if( (pCheck->bInt ? c1.i<p1.i : c1.f<p1.f) 
    ++       || (pCheck->bInt ? c2.i>p2.i : c2.f>p2.f)
    ++      ){
    ++        rtreeCheckAppendMsg(pCheck, 
    ++            "Dimension %d of cell %d on node %lld is corrupt relative to parent"
    ++            , i, iCell, iNode
    ++        );
    ++      }
    ++    }
    ++  }
    ++}
    ++
    ++/*
    ++** Run rtreecheck() checks on node iNode, which is at depth iDepth within
    ++** the r-tree structure. Argument aParent points to the array of coordinates
    ++** that bound node iNode on the parent node.
    ++**
    ++** If any problems are discovered, an error message is appended to the
    ++** report accumulated in the RtreeCheck object.
    ++*/
    ++static void rtreeCheckNode(
    ++  RtreeCheck *pCheck,
    ++  int iDepth,                     /* Depth of iNode (0==leaf) */
    ++  u8 *aParent,                    /* Buffer containing parent coords */
    ++  i64 iNode                       /* Node to check */
    ++){
    ++  u8 *aNode = 0;
    ++  int nNode = 0;
    ++
    ++  assert( iNode==1 || aParent!=0 );
    ++  assert( pCheck->nDim>0 );
    ++
    ++  aNode = rtreeCheckGetNode(pCheck, iNode, &nNode);
    ++  if( aNode ){
    ++    if( nNode<4 ){
    ++      rtreeCheckAppendMsg(pCheck, 
    ++          "Node %lld is too small (%d bytes)", iNode, nNode
    ++      );
    ++    }else{
    ++      int nCell;                  /* Number of cells on page */
    ++      int i;                      /* Used to iterate through cells */
    ++      if( aParent==0 ){
    ++        iDepth = readInt16(aNode);
    ++        if( iDepth>RTREE_MAX_DEPTH ){
    ++          rtreeCheckAppendMsg(pCheck, "Rtree depth out of range (%d)", iDepth);
    ++          sqlite3_free(aNode);
    ++          return;
    ++        }
    ++      }
    ++      nCell = readInt16(&aNode[2]);
    ++      if( (4 + nCell*(8 + pCheck->nDim*2*4))>nNode ){
    ++        rtreeCheckAppendMsg(pCheck, 
    ++            "Node %lld is too small for cell count of %d (%d bytes)", 
    ++            iNode, nCell, nNode
    ++        );
    ++      }else{
    ++        for(i=0; i<nCell; i++){
    ++          u8 *pCell = &aNode[4 + i*(8 + pCheck->nDim*2*4)];
    ++          i64 iVal = readInt64(pCell);
    ++          rtreeCheckCellCoord(pCheck, iNode, i, &pCell[8], aParent);
    ++
    ++          if( iDepth>0 ){
    ++            rtreeCheckMapping(pCheck, 0, iVal, iNode);
    ++            rtreeCheckNode(pCheck, iDepth-1, &pCell[8], iVal);
    ++            pCheck->nNonLeaf++;
    ++          }else{
    ++            rtreeCheckMapping(pCheck, 1, iVal, iNode);
    ++            pCheck->nLeaf++;
    ++          }
    ++        }
    ++      }
    ++    }
    ++    sqlite3_free(aNode);
    ++  }
    ++}
    ++
    ++/*
    ++** The second argument to this function must be either "_rowid" or
    ++** "_parent". This function checks that the number of entries in the
    ++** %_rowid or %_parent table is exactly nExpect. If not, it adds
    ++** an error message to the report in the RtreeCheck object indicated
    ++** by the first argument.
    ++*/
    ++static void rtreeCheckCount(RtreeCheck *pCheck, const char *zTbl, i64 nExpect){
    ++  if( pCheck->rc==SQLITE_OK ){
    ++    sqlite3_stmt *pCount;
    ++    pCount = rtreeCheckPrepare(pCheck, "SELECT count(*) FROM %Q.'%q%s'",
    ++        pCheck->zDb, pCheck->zTab, zTbl
    ++    );
    ++    if( pCount ){
    ++      if( sqlite3_step(pCount)==SQLITE_ROW ){
    ++        i64 nActual = sqlite3_column_int64(pCount, 0);
    ++        if( nActual!=nExpect ){
    ++          rtreeCheckAppendMsg(pCheck, "Wrong number of entries in %%%s table"
    ++              " - expected %lld, actual %lld" , zTbl, nExpect, nActual
    ++          );
    ++        }
    ++      }
    ++      pCheck->rc = sqlite3_finalize(pCount);
    ++    }
    ++  }
    ++}
    ++
    ++/*
    ++** This function does the bulk of the work for the rtree integrity-check.
    ++** It is called by rtreecheck(), which is the SQL function implementation.
    ++*/
    ++static int rtreeCheckTable(
    ++  sqlite3 *db,                    /* Database handle to access db through */
    ++  const char *zDb,                /* Name of db ("main", "temp" etc.) */
    ++  const char *zTab,               /* Name of rtree table to check */
    ++  char **pzReport                 /* OUT: sqlite3_malloc'd report text */
    ++){
    ++  RtreeCheck check;               /* Common context for various routines */
    ++  sqlite3_stmt *pStmt = 0;        /* Used to find column count of rtree table */
    ++  int bEnd = 0;                   /* True if transaction should be closed */
    ++
    ++  /* Initialize the context object */
    ++  memset(&check, 0, sizeof(check));
    ++  check.db = db;
    ++  check.zDb = zDb;
    ++  check.zTab = zTab;
    ++
    ++  /* If there is not already an open transaction, open one now. This is
    ++  ** to ensure that the queries run as part of this integrity-check operate
    ++  ** on a consistent snapshot.  */
    ++  if( sqlite3_get_autocommit(db) ){
    ++    check.rc = sqlite3_exec(db, "BEGIN", 0, 0, 0);
    ++    bEnd = 1;
    ++  }
    ++
    ++  /* Find number of dimensions in the rtree table. */
    ++  pStmt = rtreeCheckPrepare(&check, "SELECT * FROM %Q.%Q", zDb, zTab);
    ++  if( pStmt ){
    ++    int rc;
    ++    check.nDim = (sqlite3_column_count(pStmt) - 1) / 2;
    ++    if( check.nDim<1 ){
    ++      rtreeCheckAppendMsg(&check, "Schema corrupt or not an rtree");
    ++    }else if( SQLITE_ROW==sqlite3_step(pStmt) ){
    ++      check.bInt = (sqlite3_column_type(pStmt, 1)==SQLITE_INTEGER);
    ++    }
    ++    rc = sqlite3_finalize(pStmt);
    ++    if( rc!=SQLITE_CORRUPT ) check.rc = rc;
    ++  }
    ++
    ++  /* Do the actual integrity-check */
    ++  if( check.nDim>=1 ){
    ++    if( check.rc==SQLITE_OK ){
    ++      rtreeCheckNode(&check, 0, 0, 1);
    ++    }
    ++    rtreeCheckCount(&check, "_rowid", check.nLeaf);
    ++    rtreeCheckCount(&check, "_parent", check.nNonLeaf);
    ++  }
    ++
    ++  /* Finalize SQL statements used by the integrity-check */
    ++  sqlite3_finalize(check.pGetNode);
    ++  sqlite3_finalize(check.aCheckMapping[0]);
    ++  sqlite3_finalize(check.aCheckMapping[1]);
    ++
    ++  /* If one was opened, close the transaction */
    ++  if( bEnd ){
    ++    int rc = sqlite3_exec(db, "END", 0, 0, 0);
    ++    if( check.rc==SQLITE_OK ) check.rc = rc;
    ++  }
    ++  *pzReport = check.zReport;
    ++  return check.rc;
    ++}
    ++
    ++/*
    ++** Usage:
    ++**
    ++**   rtreecheck(<rtree-table>);
    ++**   rtreecheck(<database>, <rtree-table>);
    ++**
    ++** Invoking this SQL function runs an integrity-check on the named rtree
    ++** table. The integrity-check verifies the following:
    ++**
    ++**   1. For each cell in the r-tree structure (%_node table), that:
    ++**
    ++**       a) for each dimension, (coord1 <= coord2).
    ++**
    ++**       b) unless the cell is on the root node, that the cell is bounded
    ++**          by the parent cell on the parent node.
    ++**
    ++**       c) for leaf nodes, that there is an entry in the %_rowid 
    ++**          table corresponding to the cell's rowid value that 
    ++**          points to the correct node.
    ++**
    ++**       d) for cells on non-leaf nodes, that there is an entry in the 
    ++**          %_parent table mapping from the cell's child node to the
    ++**          node that it resides on.
    ++**
    ++**   2. That there are the same number of entries in the %_rowid table
    ++**      as there are leaf cells in the r-tree structure, and that there
    ++**      is a leaf cell that corresponds to each entry in the %_rowid table.
    ++**
    ++**   3. That there are the same number of entries in the %_parent table
    ++**      as there are non-leaf cells in the r-tree structure, and that 
    ++**      there is a non-leaf cell that corresponds to each entry in the 
    ++**      %_parent table.
    ++*/
    ++static void rtreecheck(
    ++  sqlite3_context *ctx, 
    ++  int nArg, 
    ++  sqlite3_value **apArg
    ++){
    ++  if( nArg!=1 && nArg!=2 ){
    ++    sqlite3_result_error(ctx, 
    ++        "wrong number of arguments to function rtreecheck()", -1
    ++    );
    ++  }else{
    ++    int rc;
    ++    char *zReport = 0;
    ++    const char *zDb = (const char*)sqlite3_value_text(apArg[0]);
    ++    const char *zTab;
    ++    if( nArg==1 ){
    ++      zTab = zDb;
    ++      zDb = "main";
    ++    }else{
    ++      zTab = (const char*)sqlite3_value_text(apArg[1]);
    ++    }
    ++    rc = rtreeCheckTable(sqlite3_context_db_handle(ctx), zDb, zTab, &zReport);
    ++    if( rc==SQLITE_OK ){
    ++      sqlite3_result_text(ctx, zReport ? zReport : "ok", -1, SQLITE_TRANSIENT);
    ++    }else{
    ++      sqlite3_result_error_code(ctx, rc);
    ++    }
    ++    sqlite3_free(zReport);
    ++  }
    ++}
    ++
    ++
    + /*
    + ** Register the r-tree module with database handle db. This creates the
    + ** virtual table module "rtree" and the debugging/analysis scalar 
    +@@ -157426,6 +171145,9 @@ SQLITE_PRIVATE int sqlite3RtreeInit(sqlite3 *db){
    +   if( rc==SQLITE_OK ){
    +     rc = sqlite3_create_function(db, "rtreedepth", 1, utf8, 0,rtreedepth, 0, 0);
    +   }
    ++  if( rc==SQLITE_OK ){
    ++    rc = sqlite3_create_function(db, "rtreecheck", -1, utf8, 0,rtreecheck, 0,0);
    ++  }
    +   if( rc==SQLITE_OK ){
    + #ifdef SQLITE_RTREE_INT_ONLY
    +     void *c = (void *)RTREE_COORD_INT32;
    +@@ -157494,7 +171216,7 @@ static void geomCallback(sqlite3_context *ctx, int nArg, sqlite3_value **aArg){
    +     sqlite3_result_error_nomem(ctx);
    +   }else{
    +     int i;
    +-    pBlob->magic = RTREE_GEOMETRY_MAGIC;
    ++    pBlob->iSize = nBlob;
    +     pBlob->cb = pGeomCtx[0];
    +     pBlob->apSqlParam = (sqlite3_value**)&pBlob->aParam[nArg];
    +     pBlob->nParam = nArg;
    +@@ -157511,7 +171233,7 @@ static void geomCallback(sqlite3_context *ctx, int nArg, sqlite3_value **aArg){
    +       sqlite3_result_error_nomem(ctx);
    +       rtreeMatchArgFree(pBlob);
    +     }else{
    +-      sqlite3_result_blob(ctx, pBlob, nBlob, rtreeMatchArgFree);
    ++      sqlite3_result_pointer(ctx, pBlob, "RtreeMatchArg", rtreeMatchArgFree);
    +     }
    +   }
    + }
    +@@ -157519,7 +171241,7 @@ 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 SQLITE_STDCALL sqlite3_rtree_geometry_callback(
    ++SQLITE_API int sqlite3_rtree_geometry_callback(
    +   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 */
    +@@ -157543,7 +171265,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_rtree_geometry_callback(
    + ** Register a new 2nd-generation geometry function for use with the
    + ** r-tree MATCH operator.
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_rtree_query_callback(
    ++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 */
    +@@ -157568,7 +171290,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_rtree_query_callback(
    + #ifdef _WIN32
    + __declspec(dllexport)
    + #endif
    +-SQLITE_API int SQLITE_STDCALL sqlite3_rtree_init(
    ++SQLITE_API int sqlite3_rtree_init(
    +   sqlite3 *db,
    +   char **pzErrMsg,
    +   const sqlite3_api_routines *pApi
    +@@ -157612,7 +171334,9 @@ SQLITE_API int SQLITE_STDCALL sqlite3_rtree_init(
    + **     provide case-independent matching.
    + */
    + 
    +-#if !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_ICU)
    ++#if !defined(SQLITE_CORE)                  \
    ++ || defined(SQLITE_ENABLE_ICU)             \
    ++ || defined(SQLITE_ENABLE_ICU_COLLATIONS)
    + 
    + /* Include ICU headers */
    + #include <unicode/utypes.h>
    +@@ -157629,6 +171353,26 @@ SQLITE_API int SQLITE_STDCALL sqlite3_rtree_init(
    + /*   #include "sqlite3.h" */
    + #endif
    + 
    ++/*
    ++** This function is called when an ICU function called from within
    ++** the implementation of an SQL scalar function returns an error.
    ++**
    ++** The scalar function context passed as the first argument is 
    ++** loaded with an error message based on the following two args.
    ++*/
    ++static void icuFunctionError(
    ++  sqlite3_context *pCtx,       /* SQLite scalar function context */
    ++  const char *zName,           /* Name of ICU function that failed */
    ++  UErrorCode e                 /* Error code returned by ICU function */
    ++){
    ++  char zBuf[128];
    ++  sqlite3_snprintf(128, zBuf, "ICU error: %s(): %s", zName, u_errorName(e));
    ++  zBuf[127] = '\0';
    ++  sqlite3_result_error(pCtx, zBuf, -1);
    ++}
    ++
    ++#if !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_ICU)
    ++
    + /*
    + ** Maximum length (in bytes) of the pattern in a LIKE or GLOB
    + ** operator.
    +@@ -157644,6 +171388,38 @@ static void xFree(void *p){
    +   sqlite3_free(p);
    + }
    + 
    ++/*
    ++** This lookup table is used to help decode the first byte of
    ++** a multi-byte UTF8 character. It is copied here from SQLite source
    ++** code file utf8.c.
    ++*/
    ++static const unsigned char icuUtf8Trans1[] = {
    ++  0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
    ++  0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
    ++  0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
    ++  0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
    ++  0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
    ++  0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
    ++  0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
    ++  0x00, 0x01, 0x02, 0x03, 0x00, 0x01, 0x00, 0x00,
    ++};
    ++
    ++#define SQLITE_ICU_READ_UTF8(zIn, c)                       \
    ++  c = *(zIn++);                                            \
    ++  if( c>=0xc0 ){                                           \
    ++    c = icuUtf8Trans1[c-0xc0];                             \
    ++    while( (*zIn & 0xc0)==0x80 ){                          \
    ++      c = (c<<6) + (0x3f & *(zIn++));                      \
    ++    }                                                      \
    ++  }
    ++
    ++#define SQLITE_ICU_SKIP_UTF8(zIn)                          \
    ++  assert( *zIn );                                          \
    ++  if( *(zIn++)>=0xc0 ){                                    \
    ++    while( (*zIn & 0xc0)==0x80 ){zIn++;}                   \
    ++  }
    ++
    ++
    + /*
    + ** Compare two UTF-8 strings for equality where the first string is
    + ** a "LIKE" expression. Return true (1) if they are the same and 
    +@@ -157654,19 +171430,17 @@ static int icuLikeCompare(
    +   const uint8_t *zString,    /* The UTF-8 string to compare against */
    +   const UChar32 uEsc         /* The escape character */
    + ){
    +-  static const int MATCH_ONE = (UChar32)'_';
    +-  static const int MATCH_ALL = (UChar32)'%';
    +-
    +-  int iPattern = 0;       /* Current byte index in zPattern */
    +-  int iString = 0;        /* Current byte index in zString */
    ++  static const uint32_t MATCH_ONE = (uint32_t)'_';
    ++  static const uint32_t MATCH_ALL = (uint32_t)'%';
    + 
    +   int prevEscape = 0;     /* True if the previous character was uEsc */
    + 
    +-  while( zPattern[iPattern]!=0 ){
    ++  while( 1 ){
    + 
    +     /* Read (and consume) the next character from the input pattern. */
    +-    UChar32 uPattern;
    +-    U8_NEXT_UNSAFE(zPattern, iPattern, uPattern);
    ++    uint32_t uPattern;
    ++    SQLITE_ICU_READ_UTF8(zPattern, uPattern);
    ++    if( uPattern==0 ) break;
    + 
    +     /* There are now 4 possibilities:
    +     **
    +@@ -157683,39 +171457,39 @@ static int icuLikeCompare(
    +       ** MATCH_ALL. For each MATCH_ONE, skip one character in the 
    +       ** test string.
    +       */
    +-      while( (c=zPattern[iPattern]) == MATCH_ALL || c == MATCH_ONE ){
    ++      while( (c=*zPattern) == MATCH_ALL || c == MATCH_ONE ){
    +         if( c==MATCH_ONE ){
    +-          if( zString[iString]==0 ) return 0;
    +-          U8_FWD_1_UNSAFE(zString, iString);
    ++          if( *zString==0 ) return 0;
    ++          SQLITE_ICU_SKIP_UTF8(zString);
    +         }
    +-        iPattern++;
    ++        zPattern++;
    +       }
    + 
    +-      if( zPattern[iPattern]==0 ) return 1;
    ++      if( *zPattern==0 ) return 1;
    + 
    +-      while( zString[iString] ){
    +-        if( icuLikeCompare(&zPattern[iPattern], &zString[iString], uEsc) ){
    ++      while( *zString ){
    ++        if( icuLikeCompare(zPattern, zString, uEsc) ){
    +           return 1;
    +         }
    +-        U8_FWD_1_UNSAFE(zString, iString);
    ++        SQLITE_ICU_SKIP_UTF8(zString);
    +       }
    +       return 0;
    + 
    +     }else if( !prevEscape && uPattern==MATCH_ONE ){
    +       /* Case 2. */
    +-      if( zString[iString]==0 ) return 0;
    +-      U8_FWD_1_UNSAFE(zString, iString);
    ++      if( *zString==0 ) return 0;
    ++      SQLITE_ICU_SKIP_UTF8(zString);
    + 
    +-    }else if( !prevEscape && uPattern==uEsc){
    ++    }else if( !prevEscape && uPattern==(uint32_t)uEsc){
    +       /* Case 3. */
    +       prevEscape = 1;
    + 
    +     }else{
    +       /* Case 4. */
    +-      UChar32 uString;
    +-      U8_NEXT_UNSAFE(zString, iString, uString);
    +-      uString = u_foldCase(uString, U_FOLD_CASE_DEFAULT);
    +-      uPattern = u_foldCase(uPattern, U_FOLD_CASE_DEFAULT);
    ++      uint32_t uString;
    ++      SQLITE_ICU_READ_UTF8(zString, uString);
    ++      uString = (uint32_t)u_foldCase((UChar32)uString, U_FOLD_CASE_DEFAULT);
    ++      uPattern = (uint32_t)u_foldCase((UChar32)uPattern, U_FOLD_CASE_DEFAULT);
    +       if( uString!=uPattern ){
    +         return 0;
    +       }
    +@@ -157723,7 +171497,7 @@ static int icuLikeCompare(
    +     }
    +   }
    + 
    +-  return zString[iString]==0;
    ++  return *zString==0;
    + }
    + 
    + /*
    +@@ -157778,24 +171552,6 @@ static void icuLikeFunc(
    +   }
    + }
    + 
    +-/*
    +-** This function is called when an ICU function called from within
    +-** the implementation of an SQL scalar function returns an error.
    +-**
    +-** The scalar function context passed as the first argument is 
    +-** loaded with an error message based on the following two args.
    +-*/
    +-static void icuFunctionError(
    +-  sqlite3_context *pCtx,       /* SQLite scalar function context */
    +-  const char *zName,           /* Name of ICU function that failed */
    +-  UErrorCode e                 /* Error code returned by ICU function */
    +-){
    +-  char zBuf[128];
    +-  sqlite3_snprintf(128, zBuf, "ICU error: %s(): %s", zName, u_errorName(e));
    +-  zBuf[127] = '\0';
    +-  sqlite3_result_error(pCtx, zBuf, -1);
    +-}
    +-
    + /*
    + ** Function to delete compiled regexp objects. Registered as
    + ** a destructor function with sqlite3_set_auxdata().
    +@@ -157903,20 +171659,22 @@ static void icuRegexpFunc(sqlite3_context *p, int nArg, sqlite3_value **apArg){
    + ** of upper() or lower().
    + **
    + **     lower('I', 'en_us') -> 'i'
    +-**     lower('I', 'tr_tr') -> 'ı' (small dotless i)
    ++**     lower('I', 'tr_tr') -> '\u131' (small dotless i)
    + **
    + ** http://www.icu-project.org/userguide/posix.html#case_mappings
    + */
    + static void icuCaseFunc16(sqlite3_context *p, int nArg, sqlite3_value **apArg){
    +-  const UChar *zInput;
    +-  UChar *zOutput;
    +-  int nInput;
    +-  int nOutput;
    +-
    +-  UErrorCode status = U_ZERO_ERROR;
    ++  const UChar *zInput;            /* Pointer to input string */
    ++  UChar *zOutput = 0;             /* Pointer to output buffer */
    ++  int nInput;                     /* Size of utf-16 input string in bytes */
    ++  int nOut;                       /* Size of output buffer in bytes */
    ++  int cnt;
    ++  int bToUpper;                   /* True for toupper(), false for tolower() */
    ++  UErrorCode status;
    +   const char *zLocale = 0;
    + 
    +   assert(nArg==1 || nArg==2);
    ++  bToUpper = (sqlite3_user_data(p)!=0);
    +   if( nArg==2 ){
    +     zLocale = (const char *)sqlite3_value_text(apArg[1]);
    +   }
    +@@ -157925,28 +171683,42 @@ static void icuCaseFunc16(sqlite3_context *p, int nArg, sqlite3_value **apArg){
    +   if( !zInput ){
    +     return;
    +   }
    +-  nInput = sqlite3_value_bytes16(apArg[0]);
    +-
    +-  nOutput = nInput * 2 + 2;
    +-  zOutput = sqlite3_malloc(nOutput);
    +-  if( !zOutput ){
    ++  nOut = nInput = sqlite3_value_bytes16(apArg[0]);
    ++  if( nOut==0 ){
    ++    sqlite3_result_text16(p, "", 0, SQLITE_STATIC);
    +     return;
    +   }
    + 
    +-  if( sqlite3_user_data(p) ){
    +-    u_strToUpper(zOutput, nOutput/2, zInput, nInput/2, zLocale, &status);
    +-  }else{
    +-    u_strToLower(zOutput, nOutput/2, zInput, nInput/2, zLocale, &status);
    +-  }
    ++  for(cnt=0; cnt<2; cnt++){
    ++    UChar *zNew = sqlite3_realloc(zOutput, nOut);
    ++    if( zNew==0 ){
    ++      sqlite3_free(zOutput);
    ++      sqlite3_result_error_nomem(p);
    ++      return;
    ++    }
    ++    zOutput = zNew;
    ++    status = U_ZERO_ERROR;
    ++    if( bToUpper ){
    ++      nOut = 2*u_strToUpper(zOutput,nOut/2,zInput,nInput/2,zLocale,&status);
    ++    }else{
    ++      nOut = 2*u_strToLower(zOutput,nOut/2,zInput,nInput/2,zLocale,&status);
    ++    }
    + 
    +-  if( !U_SUCCESS(status) ){
    +-    icuFunctionError(p, "u_strToLower()/u_strToUpper", status);
    ++    if( U_SUCCESS(status) ){
    ++      sqlite3_result_text16(p, zOutput, nOut, xFree);
    ++    }else if( status==U_BUFFER_OVERFLOW_ERROR ){
    ++      assert( cnt==0 );
    ++      continue;
    ++    }else{
    ++      icuFunctionError(p, bToUpper ? "u_strToUpper" : "u_strToLower", status);
    ++    }
    +     return;
    +   }
    +-
    +-  sqlite3_result_text16(p, zOutput, -1, xFree);
    ++  assert( 0 );     /* Unreachable */
    + }
    + 
    ++#endif /* !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_ICU) */
    ++
    + /*
    + ** Collation sequence destructor function. The pCtx argument points to
    + ** a UCollator structure previously allocated using ucol_open().
    +@@ -158033,38 +171805,37 @@ static void icuLoadCollation(
    + ** Register the ICU extension functions with database db.
    + */
    + SQLITE_PRIVATE int sqlite3IcuInit(sqlite3 *db){
    +-  struct IcuScalar {
    ++  static const struct IcuScalar {
    +     const char *zName;                        /* Function name */
    +-    int nArg;                                 /* Number of arguments */
    +-    int enc;                                  /* Optimal text encoding */
    +-    void *pContext;                           /* sqlite3_user_data() context */
    ++    unsigned char nArg;                       /* Number of arguments */
    ++    unsigned short enc;                       /* Optimal text encoding */
    ++    unsigned char iContext;                   /* sqlite3_user_data() context */
    +     void (*xFunc)(sqlite3_context*,int,sqlite3_value**);
    +   } scalars[] = {
    +-    {"regexp", 2, SQLITE_ANY,          0, icuRegexpFunc},
    +-
    +-    {"lower",  1, SQLITE_UTF16,        0, icuCaseFunc16},
    +-    {"lower",  2, SQLITE_UTF16,        0, icuCaseFunc16},
    +-    {"upper",  1, SQLITE_UTF16, (void*)1, icuCaseFunc16},
    +-    {"upper",  2, SQLITE_UTF16, (void*)1, icuCaseFunc16},
    +-
    +-    {"lower",  1, SQLITE_UTF8,         0, icuCaseFunc16},
    +-    {"lower",  2, SQLITE_UTF8,         0, icuCaseFunc16},
    +-    {"upper",  1, SQLITE_UTF8,  (void*)1, icuCaseFunc16},
    +-    {"upper",  2, SQLITE_UTF8,  (void*)1, icuCaseFunc16},
    +-
    +-    {"like",   2, SQLITE_UTF8,         0, icuLikeFunc},
    +-    {"like",   3, SQLITE_UTF8,         0, icuLikeFunc},
    +-
    +-    {"icu_load_collation",  2, SQLITE_UTF8, (void*)db, icuLoadCollation},
    ++    {"icu_load_collation",  2, SQLITE_UTF8,                1, icuLoadCollation},
    ++#if !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_ICU)
    ++    {"regexp", 2, SQLITE_ANY|SQLITE_DETERMINISTIC,         0, icuRegexpFunc},
    ++    {"lower",  1, SQLITE_UTF16|SQLITE_DETERMINISTIC,       0, icuCaseFunc16},
    ++    {"lower",  2, SQLITE_UTF16|SQLITE_DETERMINISTIC,       0, icuCaseFunc16},
    ++    {"upper",  1, SQLITE_UTF16|SQLITE_DETERMINISTIC,       1, icuCaseFunc16},
    ++    {"upper",  2, SQLITE_UTF16|SQLITE_DETERMINISTIC,       1, icuCaseFunc16},
    ++    {"lower",  1, SQLITE_UTF8|SQLITE_DETERMINISTIC,        0, icuCaseFunc16},
    ++    {"lower",  2, SQLITE_UTF8|SQLITE_DETERMINISTIC,        0, icuCaseFunc16},
    ++    {"upper",  1, SQLITE_UTF8|SQLITE_DETERMINISTIC,        1, icuCaseFunc16},
    ++    {"upper",  2, SQLITE_UTF8|SQLITE_DETERMINISTIC,        1, icuCaseFunc16},
    ++    {"like",   2, SQLITE_UTF8|SQLITE_DETERMINISTIC,        0, icuLikeFunc},
    ++    {"like",   3, SQLITE_UTF8|SQLITE_DETERMINISTIC,        0, icuLikeFunc},
    ++#endif /* !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_ICU) */
    +   };
    +-
    +   int rc = SQLITE_OK;
    +   int i;
    +-
    ++  
    +   for(i=0; rc==SQLITE_OK && i<(int)(sizeof(scalars)/sizeof(scalars[0])); i++){
    +-    struct IcuScalar *p = &scalars[i];
    ++    const struct IcuScalar *p = &scalars[i];
    +     rc = sqlite3_create_function(
    +-        db, p->zName, p->nArg, p->enc, p->pContext, p->xFunc, 0, 0
    ++        db, p->zName, p->nArg, p->enc, 
    ++        p->iContext ? (void*)db : (void*)0,
    ++        p->xFunc, 0, 0
    +     );
    +   }
    + 
    +@@ -158075,7 +171846,7 @@ SQLITE_PRIVATE int sqlite3IcuInit(sqlite3 *db){
    + #ifdef _WIN32
    + __declspec(dllexport)
    + #endif
    +-SQLITE_API int SQLITE_STDCALL sqlite3_icu_init(
    ++SQLITE_API int sqlite3_icu_init(
    +   sqlite3 *db, 
    +   char **pzErrMsg,
    +   const sqlite3_api_routines *pApi
    +@@ -158551,7 +172322,7 @@ SQLITE_PRIVATE void sqlite3Fts3IcuTokenizerModule(
    + ** may also be named data<integer>_<target>, where <integer> is any sequence
    + ** of zero or more numeric characters (0-9). This can be significant because
    + ** tables within the RBU database are always processed in order sorted by 
    +-** name. By judicious selection of the the <integer> portion of the names
    ++** name. By judicious selection of the <integer> portion of the names
    + ** of the RBU tables the user can therefore control the order in which they
    + ** are processed. This can be useful, for example, to ensure that "external
    + ** content" FTS4 tables are updated before their underlying content tables.
    +@@ -158755,12 +172526,72 @@ typedef struct sqlite3rbu sqlite3rbu;
    + ** not work out of the box with zipvfs. Refer to the comment describing
    + ** the zipvfs_create_vfs() API below for details on using RBU with zipvfs.
    + */
    +-SQLITE_API sqlite3rbu *SQLITE_STDCALL sqlite3rbu_open(
    ++SQLITE_API sqlite3rbu *sqlite3rbu_open(
    +   const char *zTarget, 
    +   const char *zRbu,
    +   const char *zState
    + );
    + 
    ++/*
    ++** Open an RBU handle to perform an RBU vacuum on database file zTarget.
    ++** An RBU vacuum is similar to SQLite's built-in VACUUM command, except
    ++** that it can be suspended and resumed like an RBU update.
    ++**
    ++** The second argument to this function identifies a database in which 
    ++** to store the state of the RBU vacuum operation if it is suspended. The 
    ++** first time sqlite3rbu_vacuum() is called, to start an RBU vacuum
    ++** operation, the state database should either not exist or be empty
    ++** (contain no tables). If an RBU vacuum is suspended by calling 
    ++** sqlite3rbu_close() on the RBU handle before sqlite3rbu_step() has
    ++** returned SQLITE_DONE, the vacuum state is stored in the state database. 
    ++** The vacuum can be resumed by calling this function to open a new RBU
    ++** handle specifying the same target and state databases.
    ++**
    ++** If the second argument passed to this function is NULL, then the
    ++** name of the state database is "<database>-vacuum", where <database>
    ++** is the name of the target database file. In this case, on UNIX, if the
    ++** state database is not already present in the file-system, it is created
    ++** with the same permissions as the target db is made.
    ++**
    ++** This function does not delete the state database after an RBU vacuum
    ++** is completed, even if it created it. However, if the call to
    ++** sqlite3rbu_close() returns any value other than SQLITE_OK, the contents
    ++** of the state tables within the state database are zeroed. This way,
    ++** the next call to sqlite3rbu_vacuum() opens a handle that starts a 
    ++** new RBU vacuum operation.
    ++**
    ++** As with sqlite3rbu_open(), Zipvfs users should rever to the comment
    ++** describing the sqlite3rbu_create_vfs() API function below for 
    ++** a description of the complications associated with using RBU with 
    ++** zipvfs databases.
    ++*/
    ++SQLITE_API sqlite3rbu *sqlite3rbu_vacuum(
    ++  const char *zTarget, 
    ++  const char *zState
    ++);
    ++
    ++/*
    ++** Configure a limit for the amount of temp space that may be used by
    ++** the RBU handle passed as the first argument. The new limit is specified
    ++** in bytes by the second parameter. If it is positive, the limit is updated.
    ++** If the second parameter to this function is passed zero, then the limit
    ++** is removed entirely. If the second parameter is negative, the limit is
    ++** not modified (this is useful for querying the current limit).
    ++**
    ++** In all cases the returned value is the current limit in bytes (zero 
    ++** indicates unlimited).
    ++**
    ++** If the temp space limit is exceeded during operation, an SQLITE_FULL
    ++** error is returned.
    ++*/
    ++SQLITE_API sqlite3_int64 sqlite3rbu_temp_size_limit(sqlite3rbu*, sqlite3_int64);
    ++
    ++/*
    ++** Return the current amount of temp file space, in bytes, currently used by 
    ++** the RBU handle passed as the only argument.
    ++*/
    ++SQLITE_API sqlite3_int64 sqlite3rbu_temp_size(sqlite3rbu*);
    ++
    + /*
    + ** Internally, each RBU connection uses a separate SQLite database 
    + ** connection to access the target and rbu update databases. This
    +@@ -158788,8 +172619,11 @@ SQLITE_API sqlite3rbu *SQLITE_STDCALL sqlite3rbu_open(
    + ** If an error has occurred, either while opening or stepping the RBU object,
    + ** this function may return NULL. The error code and message may be collected
    + ** when sqlite3rbu_close() is called.
    ++**
    ++** Database handles returned by this function remain valid until the next
    ++** call to any sqlite3rbu_xxx() function other than sqlite3rbu_db().
    + */
    +-SQLITE_API sqlite3 *SQLITE_STDCALL sqlite3rbu_db(sqlite3rbu*, int bRbu);
    ++SQLITE_API sqlite3 *sqlite3rbu_db(sqlite3rbu*, int bRbu);
    + 
    + /*
    + ** Do some work towards applying the RBU update to the target db. 
    +@@ -158803,7 +172637,7 @@ SQLITE_API sqlite3 *SQLITE_STDCALL sqlite3rbu_db(sqlite3rbu*, int bRbu);
    + ** SQLITE_OK, all subsequent calls on the same RBU handle are no-ops
    + ** that immediately return the same value.
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3rbu_step(sqlite3rbu *pRbu);
    ++SQLITE_API int sqlite3rbu_step(sqlite3rbu *pRbu);
    + 
    + /*
    + ** Force RBU to save its state to disk.
    +@@ -158815,7 +172649,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3rbu_step(sqlite3rbu *pRbu);
    + **
    + ** SQLITE_OK is returned if successful, or an SQLite error code otherwise.
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3rbu_savestate(sqlite3rbu *pRbu);
    ++SQLITE_API int sqlite3rbu_savestate(sqlite3rbu *pRbu);
    + 
    + /*
    + ** Close an RBU handle. 
    +@@ -158826,23 +172660,103 @@ SQLITE_API int SQLITE_STDCALL sqlite3rbu_savestate(sqlite3rbu *pRbu);
    + **
    + ** If an error has already occurred as part of an sqlite3rbu_step()
    + ** or sqlite3rbu_open() call, or if one occurs within this function, an
    +-** SQLite error code is returned. Additionally, *pzErrmsg may be set to
    +-** point to a buffer containing a utf-8 formatted English language error
    +-** message. It is the responsibility of the caller to eventually free any 
    +-** such buffer using sqlite3_free().
    ++** SQLite error code is returned. Additionally, if pzErrmsg is not NULL,
    ++** *pzErrmsg may be set to point to a buffer containing a utf-8 formatted
    ++** English language error message. It is the responsibility of the caller to
    ++** eventually free any such buffer using sqlite3_free().
    + **
    + ** Otherwise, if no error occurs, this function returns SQLITE_OK if the
    + ** update has been partially applied, or SQLITE_DONE if it has been 
    + ** completely applied.
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3rbu_close(sqlite3rbu *pRbu, char **pzErrmsg);
    ++SQLITE_API int sqlite3rbu_close(sqlite3rbu *pRbu, char **pzErrmsg);
    + 
    + /*
    + ** Return the total number of key-value operations (inserts, deletes or 
    + ** updates) that have been performed on the target database since the
    + ** current RBU update was started.
    + */
    +-SQLITE_API sqlite3_int64 SQLITE_STDCALL sqlite3rbu_progress(sqlite3rbu *pRbu);
    ++SQLITE_API sqlite3_int64 sqlite3rbu_progress(sqlite3rbu *pRbu);
    ++
    ++/*
    ++** Obtain permyriadage (permyriadage is to 10000 as percentage is to 100) 
    ++** progress indications for the two stages of an RBU update. This API may
    ++** be useful for driving GUI progress indicators and similar.
    ++**
    ++** An RBU update is divided into two stages:
    ++**
    ++**   * Stage 1, in which changes are accumulated in an oal/wal file, and
    ++**   * Stage 2, in which the contents of the wal file are copied into the
    ++**     main database.
    ++**
    ++** The update is visible to non-RBU clients during stage 2. During stage 1
    ++** non-RBU reader clients may see the original database.
    ++**
    ++** If this API is called during stage 2 of the update, output variable 
    ++** (*pnOne) is set to 10000 to indicate that stage 1 has finished and (*pnTwo)
    ++** to a value between 0 and 10000 to indicate the permyriadage progress of
    ++** stage 2. A value of 5000 indicates that stage 2 is half finished, 
    ++** 9000 indicates that it is 90% finished, and so on.
    ++**
    ++** If this API is called during stage 1 of the update, output variable 
    ++** (*pnTwo) is set to 0 to indicate that stage 2 has not yet started. The
    ++** value to which (*pnOne) is set depends on whether or not the RBU 
    ++** database contains an "rbu_count" table. The rbu_count table, if it 
    ++** exists, must contain the same columns as the following:
    ++**
    ++**   CREATE TABLE rbu_count(tbl TEXT PRIMARY KEY, cnt INTEGER) WITHOUT ROWID;
    ++**
    ++** There must be one row in the table for each source (data_xxx) table within
    ++** the RBU database. The 'tbl' column should contain the name of the source
    ++** table. The 'cnt' column should contain the number of rows within the
    ++** source table.
    ++**
    ++** If the rbu_count table is present and populated correctly and this
    ++** API is called during stage 1, the *pnOne output variable is set to the
    ++** permyriadage progress of the same stage. If the rbu_count table does
    ++** not exist, then (*pnOne) is set to -1 during stage 1. If the rbu_count
    ++** table exists but is not correctly populated, the value of the *pnOne
    ++** output variable during stage 1 is undefined.
    ++*/
    ++SQLITE_API void sqlite3rbu_bp_progress(sqlite3rbu *pRbu, int *pnOne, int*pnTwo);
    ++
    ++/*
    ++** Obtain an indication as to the current stage of an RBU update or vacuum.
    ++** This function always returns one of the SQLITE_RBU_STATE_XXX constants
    ++** defined in this file. Return values should be interpreted as follows:
    ++**
    ++** SQLITE_RBU_STATE_OAL:
    ++**   RBU is currently building a *-oal file. The next call to sqlite3rbu_step()
    ++**   may either add further data to the *-oal file, or compute data that will
    ++**   be added by a subsequent call.
    ++**
    ++** SQLITE_RBU_STATE_MOVE:
    ++**   RBU has finished building the *-oal file. The next call to sqlite3rbu_step()
    ++**   will move the *-oal file to the equivalent *-wal path. If the current
    ++**   operation is an RBU update, then the updated version of the database
    ++**   file will become visible to ordinary SQLite clients following the next
    ++**   call to sqlite3rbu_step().
    ++**
    ++** SQLITE_RBU_STATE_CHECKPOINT:
    ++**   RBU is currently performing an incremental checkpoint. The next call to
    ++**   sqlite3rbu_step() will copy a page of data from the *-wal file into
    ++**   the target database file.
    ++**
    ++** SQLITE_RBU_STATE_DONE:
    ++**   The RBU operation has finished. Any subsequent calls to sqlite3rbu_step()
    ++**   will immediately return SQLITE_DONE.
    ++**
    ++** SQLITE_RBU_STATE_ERROR:
    ++**   An error has occurred. Any subsequent calls to sqlite3rbu_step() will
    ++**   immediately return the SQLite error code associated with the error.
    ++*/
    ++#define SQLITE_RBU_STATE_OAL        1
    ++#define SQLITE_RBU_STATE_MOVE       2
    ++#define SQLITE_RBU_STATE_CHECKPOINT 3
    ++#define SQLITE_RBU_STATE_DONE       4
    ++#define SQLITE_RBU_STATE_ERROR      5
    ++
    ++SQLITE_API int sqlite3rbu_state(sqlite3rbu *pRbu);
    + 
    + /*
    + ** Create an RBU VFS named zName that accesses the underlying file-system
    +@@ -158886,7 +172800,7 @@ SQLITE_API sqlite3_int64 SQLITE_STDCALL sqlite3rbu_progress(sqlite3rbu *pRbu);
    + ** file-system via "rbu" all the time, even if it only uses RBU functionality 
    + ** occasionally.
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3rbu_create_vfs(const char *zName, const char *zParent);
    ++SQLITE_API int sqlite3rbu_create_vfs(const char *zName, const char *zParent);
    + 
    + /*
    + ** Deregister and destroy an RBU vfs created by an earlier call to
    +@@ -158896,7 +172810,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3rbu_create_vfs(const char *zName, const cha
    + ** before all database handles that use it have been closed, the results
    + ** are undefined.
    + */
    +-SQLITE_API void SQLITE_STDCALL sqlite3rbu_destroy_vfs(const char *zName);
    ++SQLITE_API void sqlite3rbu_destroy_vfs(const char *zName);
    + 
    + #if 0
    + }  /* end of the 'extern "C"' block */
    +@@ -158914,6 +172828,13 @@ SQLITE_API void SQLITE_STDCALL sqlite3rbu_destroy_vfs(const char *zName);
    + /* Maximum number of prepared UPDATE statements held by this module */
    + #define SQLITE_RBU_UPDATE_CACHESIZE 16
    + 
    ++/* Delta checksums disabled by default.  Compile with -DRBU_ENABLE_DELTA_CKSUM
    ++** to enable checksum verification.
    ++*/
    ++#ifndef RBU_ENABLE_DELTA_CKSUM
    ++# define RBU_ENABLE_DELTA_CKSUM 0
    ++#endif
    ++
    + /*
    + ** Swap two objects of type TYPE.
    + */
    +@@ -158965,14 +172886,15 @@ SQLITE_API void SQLITE_STDCALL sqlite3rbu_destroy_vfs(const char *zName);
    + ** RBU_STATE_OALSZ:
    + **   Valid if STAGE==1. The size in bytes of the *-oal file.
    + */
    +-#define RBU_STATE_STAGE       1
    +-#define RBU_STATE_TBL         2
    +-#define RBU_STATE_IDX         3
    +-#define RBU_STATE_ROW         4
    +-#define RBU_STATE_PROGRESS    5
    +-#define RBU_STATE_CKPT        6
    +-#define RBU_STATE_COOKIE      7
    +-#define RBU_STATE_OALSZ       8
    ++#define RBU_STATE_STAGE        1
    ++#define RBU_STATE_TBL          2
    ++#define RBU_STATE_IDX          3
    ++#define RBU_STATE_ROW          4
    ++#define RBU_STATE_PROGRESS     5
    ++#define RBU_STATE_CKPT         6
    ++#define RBU_STATE_COOKIE       7
    ++#define RBU_STATE_OALSZ        8
    ++#define RBU_STATE_PHASEONESTEP 9
    + 
    + #define RBU_STAGE_OAL         1
    + #define RBU_STAGE_MOVE        2
    +@@ -158993,6 +172915,7 @@ typedef struct RbuUpdateStmt RbuUpdateStmt;
    + 
    + #if !defined(SQLITE_AMALGAMATION)
    + typedef unsigned int u32;
    ++typedef unsigned short u16;
    + typedef unsigned char u8;
    + typedef sqlite3_int64 i64;
    + #endif
    +@@ -159006,6 +172929,8 @@ typedef sqlite3_int64 i64;
    + #define WAL_LOCK_CKPT   1
    + #define WAL_LOCK_READ0  3
    + 
    ++#define SQLITE_FCNTL_RBUCNT    5149216
    ++
    + /*
    + ** A structure to store values read from the rbu_state table in memory.
    + */
    +@@ -159018,6 +172943,7 @@ struct RbuState {
    +   i64 nProgress;
    +   u32 iCookie;
    +   i64 iOalSz;
    ++  i64 nPhaseOneStep;
    + };
    + 
    + struct RbuUpdateStmt {
    +@@ -159062,6 +172988,7 @@ struct RbuObjIter {
    +   int iTnum;                      /* Root page of current object */
    +   int iPkTnum;                    /* If eType==EXTERNAL, root of PK index */
    +   int bUnique;                    /* Current index is unique */
    ++  int nIndex;                     /* Number of aux. indexes on table zTbl */
    + 
    +   /* Statements created by rbuObjIterPrepareAll() */
    +   int nCol;                       /* Number of columns in current object */
    +@@ -159098,10 +173025,11 @@ struct RbuObjIter {
    + */
    + #define RBU_INSERT     1          /* Insert on a main table b-tree */
    + #define RBU_DELETE     2          /* Delete a row from a main table b-tree */
    +-#define RBU_IDX_DELETE 3          /* Delete a row from an aux. index b-tree */
    +-#define RBU_IDX_INSERT 4          /* Insert on an aux. index b-tree */
    +-#define RBU_UPDATE     5          /* Update a row in a main table b-tree */
    ++#define RBU_REPLACE    3          /* Delete and then insert a row */
    ++#define RBU_IDX_DELETE 4          /* Delete a row from an aux. index b-tree */
    ++#define RBU_IDX_INSERT 5          /* Insert on an aux. index b-tree */
    + 
    ++#define RBU_UPDATE     6          /* Update a row in a main table b-tree */
    + 
    + /*
    + ** A single step of an incremental checkpoint - frame iWalFrame of the wal
    +@@ -159114,6 +173042,43 @@ struct RbuFrame {
    + 
    + /*
    + ** RBU handle.
    ++**
    ++** nPhaseOneStep:
    ++**   If the RBU database contains an rbu_count table, this value is set to
    ++**   a running estimate of the number of b-tree operations required to 
    ++**   finish populating the *-oal file. This allows the sqlite3_bp_progress()
    ++**   API to calculate the permyriadage progress of populating the *-oal file
    ++**   using the formula:
    ++**
    ++**     permyriadage = (10000 * nProgress) / nPhaseOneStep
    ++**
    ++**   nPhaseOneStep is initialized to the sum of:
    ++**
    ++**     nRow * (nIndex + 1)
    ++**
    ++**   for all source tables in the RBU database, where nRow is the number
    ++**   of rows in the source table and nIndex the number of indexes on the
    ++**   corresponding target database table.
    ++**
    ++**   This estimate is accurate if the RBU update consists entirely of
    ++**   INSERT operations. However, it is inaccurate if:
    ++**
    ++**     * the RBU update contains any UPDATE operations. If the PK specified
    ++**       for an UPDATE operation does not exist in the target table, then
    ++**       no b-tree operations are required on index b-trees. Or if the 
    ++**       specified PK does exist, then (nIndex*2) such operations are
    ++**       required (one delete and one insert on each index b-tree).
    ++**
    ++**     * the RBU update contains any DELETE operations for which the specified
    ++**       PK does not exist. In this case no operations are required on index
    ++**       b-trees.
    ++**
    ++**     * the RBU update contains REPLACE operations. These are similar to
    ++**       UPDATE operations.
    ++**
    ++**   nPhaseOneStep is updated to account for the conditions above during the
    ++**   first pass of each source table. The updated nPhaseOneStep value is
    ++**   stored in the rbu_state table if the RBU update is suspended.
    + */
    + struct sqlite3rbu {
    +   int eStage;                     /* Value of RBU_STATE_STAGE field */
    +@@ -159130,7 +173095,9 @@ struct sqlite3rbu {
    +   RbuObjIter objiter;             /* Iterator for skipping through tbl/idx */
    +   const char *zVfsName;           /* Name of automatically created rbu vfs */
    +   rbu_file *pTargetFd;            /* File handle open on target db */
    ++  int nPagePerSector;             /* Pages per sector for pTargetFd */
    +   i64 iOalSz;
    ++  i64 nPhaseOneStep;
    + 
    +   /* The following state variables are used as part of the incremental
    +   ** checkpoint stage (eStage==RBU_STAGE_CKPT). See comments surrounding
    +@@ -159143,31 +173110,49 @@ struct sqlite3rbu {
    +   int pgsz;
    +   u8 *aBuf;
    +   i64 iWalCksum;
    ++  i64 szTemp;                     /* Current size of all temp files in use */
    ++  i64 szTempLimit;                /* Total size limit for temp files */
    ++
    ++  /* Used in RBU vacuum mode only */
    ++  int nRbu;                       /* Number of RBU VFS in the stack */
    ++  rbu_file *pRbuFd;               /* Fd for main db of dbRbu */
    + };
    + 
    + /*
    + ** An rbu VFS is implemented using an instance of this structure.
    ++**
    ++** Variable pRbu is only non-NULL for automatically created RBU VFS objects.
    ++** It is NULL for RBU VFS objects created explicitly using
    ++** sqlite3rbu_create_vfs(). It is used to track the total amount of temp
    ++** space used by the RBU handle.
    + */
    + struct rbu_vfs {
    +   sqlite3_vfs base;               /* rbu VFS shim methods */
    +   sqlite3_vfs *pRealVfs;          /* Underlying VFS */
    +   sqlite3_mutex *mutex;           /* Mutex to protect pMain */
    +-  rbu_file *pMain;                /* Linked list of main db files */
    ++  sqlite3rbu *pRbu;               /* Owner RBU object */
    ++  rbu_file *pMain;                /* List of main db files */
    ++  rbu_file *pMainRbu;             /* List of main db files with pRbu!=0 */
    + };
    + 
    + /*
    + ** Each file opened by an rbu VFS is represented by an instance of
    + ** the following structure.
    ++**
    ++** If this is a temporary file (pRbu!=0 && flags&DELETE_ON_CLOSE), variable
    ++** "sz" is set to the current size of the database file.
    + */
    + struct rbu_file {
    +   sqlite3_file base;              /* sqlite3_file methods */
    +   sqlite3_file *pReal;            /* Underlying file handle */
    +   rbu_vfs *pRbuVfs;               /* Pointer to the rbu_vfs object */
    +   sqlite3rbu *pRbu;               /* Pointer to rbu object (rbu target only) */
    ++  i64 sz;                         /* Size of file in bytes (temp only) */
    + 
    +   int openFlags;                  /* Flags this file was opened with */
    +   u32 iCookie;                    /* Cookie value for main db files */
    +   u8 iWriteVer;                   /* "write-version" value for main db files */
    ++  u8 bNolock;                     /* True to fail EXCLUSIVE locks */
    + 
    +   int nShm;                       /* Number of entries in apShm[] array */
    +   char **apShm;                   /* Array of mmap'd *-shm regions */
    +@@ -159176,8 +173161,14 @@ struct rbu_file {
    +   const char *zWal;               /* Wal filename for this main db file */
    +   rbu_file *pWalFd;               /* Wal file descriptor for this main db */
    +   rbu_file *pMainNext;            /* Next MAIN_DB file */
    ++  rbu_file *pMainRbuNext;         /* Next MAIN_DB file with pRbu!=0 */
    + };
    + 
    ++/*
    ++** True for an RBU vacuum handle, or false otherwise.
    ++*/
    ++#define rbuIsVacuum(p) ((p)->zTarget==0)
    ++
    + 
    + /*************************************************************************
    + ** The following three functions, found below:
    +@@ -159220,6 +173211,7 @@ static unsigned int rbuDeltaGetInt(const char **pz, int *pLen){
    +   return v;
    + }
    + 
    ++#if RBU_ENABLE_DELTA_CKSUM
    + /*
    + ** Compute a 32-bit checksum on the N-byte buffer.  Return the result.
    + */
    +@@ -159254,6 +173246,7 @@ static unsigned int rbuDeltaChecksum(const char *zIn, size_t N){
    +   }
    +   return sum3;
    + }
    ++#endif
    + 
    + /*
    + ** Apply a delta.
    +@@ -159284,7 +173277,7 @@ static int rbuDeltaApply(
    + ){
    +   unsigned int limit;
    +   unsigned int total = 0;
    +-#ifndef FOSSIL_OMIT_DELTA_CKSUM_TEST
    ++#if RBU_ENABLE_DELTA_CKSUM
    +   char *zOrigOut = zOut;
    + #endif
    + 
    +@@ -159339,7 +173332,7 @@ static int rbuDeltaApply(
    +       case ';': {
    +         zDelta++; lenDelta--;
    +         zOut[0] = 0;
    +-#ifndef FOSSIL_OMIT_DELTA_CKSUM_TEST
    ++#if RBU_ENABLE_DELTA_CKSUM
    +         if( cnt!=rbuDeltaChecksum(zOrigOut, total) ){
    +           /* ERROR:  bad checksum */
    +           return -1;
    +@@ -159626,8 +173619,11 @@ static int rbuObjIterNext(sqlite3rbu *p, RbuObjIter *pIter){
    + 
    + /*
    + ** The implementation of the rbu_target_name() SQL function. This function
    +-** accepts one argument - the name of a table in the RBU database. If the
    +-** table name matches the pattern:
    ++** accepts one or two arguments. The first argument is the name of a table -
    ++** the name of a table in the RBU database.  The second, if it is present, is 1
    ++** for a view or 0 for a table. 
    ++**
    ++** For a non-vacuum RBU handle, if the table name matches the pattern:
    + **
    + **     data[0-9]_<name>
    + **
    +@@ -159638,21 +173634,33 @@ static int rbuObjIterNext(sqlite3rbu *p, RbuObjIter *pIter){
    + **     "data_t1"     -> "t1"
    + **     "data0123_t2" -> "t2"
    + **     "dataAB_t3"   -> NULL
    ++**
    ++** For an rbu vacuum handle, a copy of the first argument is returned if
    ++** the second argument is either missing or 0 (not a view).
    + */
    + static void rbuTargetNameFunc(
    +-  sqlite3_context *context,
    ++  sqlite3_context *pCtx,
    +   int argc,
    +   sqlite3_value **argv
    + ){
    ++  sqlite3rbu *p = sqlite3_user_data(pCtx);
    +   const char *zIn;
    +-  assert( argc==1 );
    ++  assert( argc==1 || argc==2 );
    + 
    +   zIn = (const char*)sqlite3_value_text(argv[0]);
    +-  if( zIn && strlen(zIn)>4 && memcmp("data", zIn, 4)==0 ){
    +-    int i;
    +-    for(i=4; zIn[i]>='0' && zIn[i]<='9'; i++);
    +-    if( zIn[i]=='_' && zIn[i+1] ){
    +-      sqlite3_result_text(context, &zIn[i+1], -1, SQLITE_STATIC);
    ++  if( zIn ){
    ++    if( rbuIsVacuum(p) ){
    ++      if( argc==1 || 0==sqlite3_value_int(argv[1]) ){
    ++        sqlite3_result_text(pCtx, zIn, -1, SQLITE_STATIC);
    ++      }
    ++    }else{
    ++      if( strlen(zIn)>4 && memcmp("data", zIn, 4)==0 ){
    ++        int i;
    ++        for(i=4; zIn[i]>='0' && zIn[i]<='9'; i++);
    ++        if( zIn[i]=='_' && zIn[i+1] ){
    ++          sqlite3_result_text(pCtx, &zIn[i+1], -1, SQLITE_STATIC);
    ++        }
    ++      }
    +     }
    +   }
    + }
    +@@ -159669,11 +173677,14 @@ static int rbuObjIterFirst(sqlite3rbu *p, RbuObjIter *pIter){
    +   int rc;
    +   memset(pIter, 0, sizeof(RbuObjIter));
    + 
    +-  rc = prepareAndCollectError(p->dbRbu, &pIter->pTblIter, &p->zErrmsg, 
    +-      "SELECT rbu_target_name(name) AS target, name FROM sqlite_master "
    ++  rc = prepareFreeAndCollectError(p->dbRbu, &pIter->pTblIter, &p->zErrmsg, 
    ++    sqlite3_mprintf(
    ++      "SELECT rbu_target_name(name, type='view') AS target, name "
    ++      "FROM sqlite_master "
    +       "WHERE type IN ('table', 'view') AND target IS NOT NULL "
    ++      " %s "
    +       "ORDER BY name"
    +-  );
    ++  , rbuIsVacuum(p) ? "AND rootpage!=0 AND rootpage IS NOT NULL" : ""));
    + 
    +   if( rc==SQLITE_OK ){
    +     rc = prepareAndCollectError(p->dbMain, &pIter->pIdxIter, &p->zErrmsg,
    +@@ -159753,7 +173764,7 @@ static void *rbuMalloc(sqlite3rbu *p, int nByte){
    +   void *pRet = 0;
    +   if( p->rc==SQLITE_OK ){
    +     assert( nByte>0 );
    +-    pRet = sqlite3_malloc(nByte);
    ++    pRet = sqlite3_malloc64(nByte);
    +     if( pRet==0 ){
    +       p->rc = SQLITE_NOMEM;
    +     }else{
    +@@ -159799,8 +173810,8 @@ static char *rbuStrndup(const char *zStr, int *pRc){
    + 
    +   assert( *pRc==SQLITE_OK );
    +   if( zStr ){
    +-    int nCopy = strlen(zStr) + 1;
    +-    zRet = (char*)sqlite3_malloc(nCopy);
    ++    size_t nCopy = strlen(zStr) + 1;
    ++    zRet = (char*)sqlite3_malloc64(nCopy);
    +     if( zRet ){
    +       memcpy(zRet, zStr, nCopy);
    +     }else{
    +@@ -159961,6 +173972,7 @@ static void rbuObjIterCacheIndexedCols(sqlite3rbu *p, RbuObjIter *pIter){
    +     );
    +   }
    + 
    ++  pIter->nIndex = 0;
    +   while( p->rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pList) ){
    +     const char *zIdx = (const char*)sqlite3_column_text(pList, 1);
    +     sqlite3_stmt *pXInfo = 0;
    +@@ -159974,6 +173986,12 @@ static void rbuObjIterCacheIndexedCols(sqlite3rbu *p, RbuObjIter *pIter){
    +     }
    +     rbuFinalize(p, pXInfo);
    +     bIndex = 1;
    ++    pIter->nIndex++;
    ++  }
    ++
    ++  if( pIter->eType==RBU_PK_WITHOUT_ROWID ){
    ++    /* "PRAGMA index_list" includes the main PK b-tree */
    ++    pIter->nIndex--;
    +   }
    + 
    +   rbuFinalize(p, pList);
    +@@ -160039,6 +174057,7 @@ static int rbuObjIterCacheTableInfo(sqlite3rbu *p, RbuObjIter *pIter){
    +     pStmt = 0;
    + 
    +     if( p->rc==SQLITE_OK
    ++     && rbuIsVacuum(p)==0
    +      && bRbuRowid!=(pIter->eType==RBU_PK_VTAB || pIter->eType==RBU_PK_NONE)
    +     ){
    +       p->rc = SQLITE_ERROR;
    +@@ -160087,6 +174106,7 @@ static int rbuObjIterCacheTableInfo(sqlite3rbu *p, RbuObjIter *pIter){
    +     rbuFinalize(p, pStmt);
    +     rbuObjIterCacheIndexedCols(p, pIter);
    +     assert( pIter->eType!=RBU_PK_VTAB || pIter->abIndexed==0 );
    ++    assert( pIter->eType!=RBU_PK_VTAB || pIter->nIndex==0 );
    +   }
    + 
    +   return p->rc;
    +@@ -160177,6 +174197,8 @@ static char *rbuObjIterGetIndexCols(
    +         for(i=0; pIter->abTblPk[i]==0; i++);
    +         assert( i<pIter->nTblCol );
    +         zCol = pIter->azTblCol[i];
    ++      }else if( rbuIsVacuum(p) ){
    ++        zCol = "_rowid_";
    +       }else{
    +         zCol = "rbu_rowid";
    +       }
    +@@ -160518,7 +174540,7 @@ static void rbuCreateImposterTable2(sqlite3rbu *p, RbuObjIter *pIter){
    +         int iCid = sqlite3_column_int(pXInfo, 1);
    +         int bDesc = sqlite3_column_int(pXInfo, 3);
    +         const char *zCollate = (const char*)sqlite3_column_text(pXInfo, 4);
    +-        zCols = rbuMPrintf(p, "%z%sc%d %s COLLATE %s", zCols, zComma, 
    ++        zCols = rbuMPrintf(p, "%z%sc%d %s COLLATE %Q", zCols, zComma,
    +             iCid, pIter->azTblType[iCid], zCollate
    +         );
    +         zPk = rbuMPrintf(p, "%z%sc%d%s", zPk, zComma, iCid, bDesc?" DESC":"");
    +@@ -160579,7 +174601,7 @@ static void rbuCreateImposterTable(sqlite3rbu *p, RbuObjIter *pIter){
    +         ** "PRIMARY KEY" to the imposter table column declaration. */
    +         zPk = "PRIMARY KEY ";
    +       }
    +-      zSql = rbuMPrintf(p, "%z%s\"%w\" %s %sCOLLATE %s%s", 
    ++      zSql = rbuMPrintf(p, "%z%s\"%w\" %s %sCOLLATE %Q%s",
    +           zSql, zComma, zCol, pIter->azTblType[iCol], zPk, zColl,
    +           (pIter->abNotNull[iCol] ? " NOT NULL" : "")
    +       );
    +@@ -160640,6 +174662,14 @@ static void rbuTmpInsertFunc(
    +   int rc = SQLITE_OK;
    +   int i;
    + 
    ++  assert( sqlite3_value_int(apVal[0])!=0
    ++      || p->objiter.eType==RBU_PK_EXTERNAL 
    ++      || p->objiter.eType==RBU_PK_NONE 
    ++  );
    ++  if( sqlite3_value_int(apVal[0])!=0 ){
    ++    p->nPhaseOneStep += p->objiter.nIndex;
    ++  }
    ++
    +   for(i=0; rc==SQLITE_OK && i<nVal; i++){
    +     rc = sqlite3_bind_value(p->objiter.pTmpInsert, i+1, apVal[i]);
    +   }
    +@@ -160709,7 +174739,7 @@ static int rbuObjIterPrepareAll(
    +       }
    + 
    +       /* And to delete index entries */
    +-      if( p->rc==SQLITE_OK ){
    ++      if( rbuIsVacuum(p)==0 && p->rc==SQLITE_OK ){
    +         p->rc = prepareFreeAndCollectError(
    +             p->dbMain, &pIter->pDelete, &p->zErrmsg,
    +           sqlite3_mprintf("DELETE FROM \"rbu_imp_%w\" WHERE %s", zTbl, zWhere)
    +@@ -160719,6 +174749,15 @@ static int rbuObjIterPrepareAll(
    +       /* Create the SELECT statement to read keys in sorted order */
    +       if( p->rc==SQLITE_OK ){
    +         char *zSql;
    ++        if( rbuIsVacuum(p) ){
    ++          zSql = sqlite3_mprintf(
    ++              "SELECT %s, 0 AS rbu_control FROM '%q' ORDER BY %s%s",
    ++              zCollist, 
    ++              pIter->zDataTbl,
    ++              zCollist, zLimit
    ++          );
    ++        }else
    ++
    +         if( pIter->eType==RBU_PK_EXTERNAL || pIter->eType==RBU_PK_NONE ){
    +           zSql = sqlite3_mprintf(
    +               "SELECT %s, rbu_control FROM %s.'rbu_tmp_%q' ORDER BY %s%s",
    +@@ -160727,13 +174766,13 @@ static int rbuObjIterPrepareAll(
    +           );
    +         }else{
    +           zSql = sqlite3_mprintf(
    ++              "SELECT %s, rbu_control FROM %s.'rbu_tmp_%q' "
    ++              "UNION ALL "
    +               "SELECT %s, rbu_control FROM '%q' "
    +               "WHERE typeof(rbu_control)='integer' AND rbu_control!=1 "
    +-              "UNION ALL "
    +-              "SELECT %s, rbu_control FROM %s.'rbu_tmp_%q' "
    +               "ORDER BY %s%s",
    +-              zCollist, pIter->zDataTbl, 
    +               zCollist, p->zStateDb, pIter->zDataTbl, 
    ++              zCollist, pIter->zDataTbl, 
    +               zCollist, zLimit
    +           );
    +         }
    +@@ -160745,7 +174784,9 @@ static int rbuObjIterPrepareAll(
    +       sqlite3_free(zWhere);
    +       sqlite3_free(zBind);
    +     }else{
    +-      int bRbuRowid = (pIter->eType==RBU_PK_VTAB || pIter->eType==RBU_PK_NONE);
    ++      int bRbuRowid = (pIter->eType==RBU_PK_VTAB)
    ++                    ||(pIter->eType==RBU_PK_NONE)
    ++                    ||(pIter->eType==RBU_PK_EXTERNAL && rbuIsVacuum(p));
    +       const char *zTbl = pIter->zTbl;       /* Table this step applies to */
    +       const char *zWrite;                   /* Imposter table name */
    + 
    +@@ -160772,8 +174813,10 @@ static int rbuObjIterPrepareAll(
    +         );
    +       }
    + 
    +-      /* Create the DELETE statement to write to the target PK b-tree */
    +-      if( p->rc==SQLITE_OK ){
    ++      /* Create the DELETE statement to write to the target PK b-tree.
    ++      ** Because it only performs INSERT operations, this is not required for
    ++      ** an rbu vacuum handle.  */
    ++      if( rbuIsVacuum(p)==0 && p->rc==SQLITE_OK ){
    +         p->rc = prepareFreeAndCollectError(p->dbMain, &pIter->pDelete, pz,
    +             sqlite3_mprintf(
    +               "DELETE FROM \"%s%w\" WHERE %s", zWrite, zTbl, zWhere
    +@@ -160781,7 +174824,7 @@ static int rbuObjIterPrepareAll(
    +         );
    +       }
    + 
    +-      if( pIter->abIndexed ){
    ++      if( rbuIsVacuum(p)==0 && pIter->abIndexed ){
    +         const char *zRbuRowid = "";
    +         if( pIter->eType==RBU_PK_EXTERNAL || pIter->eType==RBU_PK_NONE ){
    +           zRbuRowid = ", rbu_rowid";
    +@@ -160799,17 +174842,17 @@ static int rbuObjIterPrepareAll(
    +         rbuMPrintfExec(p, p->dbMain,
    +             "CREATE TEMP TRIGGER rbu_delete_tr BEFORE DELETE ON \"%s%w\" "
    +             "BEGIN "
    +-            "  SELECT rbu_tmp_insert(2, %s);"
    ++            "  SELECT rbu_tmp_insert(3, %s);"
    +             "END;"
    + 
    +             "CREATE TEMP TRIGGER rbu_update1_tr BEFORE UPDATE ON \"%s%w\" "
    +             "BEGIN "
    +-            "  SELECT rbu_tmp_insert(2, %s);"
    ++            "  SELECT rbu_tmp_insert(3, %s);"
    +             "END;"
    + 
    +             "CREATE TEMP TRIGGER rbu_update2_tr AFTER UPDATE ON \"%s%w\" "
    +             "BEGIN "
    +-            "  SELECT rbu_tmp_insert(3, %s);"
    ++            "  SELECT rbu_tmp_insert(4, %s);"
    +             "END;",
    +             zWrite, zTbl, zOldlist,
    +             zWrite, zTbl, zOldlist,
    +@@ -160831,10 +174874,16 @@ static int rbuObjIterPrepareAll(
    + 
    +       /* Create the SELECT statement to read keys from data_xxx */
    +       if( p->rc==SQLITE_OK ){
    ++        const char *zRbuRowid = "";
    ++        if( bRbuRowid ){
    ++          zRbuRowid = rbuIsVacuum(p) ? ",_rowid_ " : ",rbu_rowid";
    ++        }
    +         p->rc = prepareFreeAndCollectError(p->dbRbu, &pIter->pSelect, pz,
    +             sqlite3_mprintf(
    +-              "SELECT %s, rbu_control%s FROM '%q'%s", 
    +-              zCollist, (bRbuRowid ? ", rbu_rowid" : ""), 
    ++              "SELECT %s,%s rbu_control%s FROM '%q'%s", 
    ++              zCollist, 
    ++              (rbuIsVacuum(p) ? "0 AS " : ""),
    ++              zRbuRowid,
    +               pIter->zDataTbl, zLimit
    +             )
    +         );
    +@@ -160929,11 +174978,15 @@ static int rbuGetUpdateStmt(
    +   return p->rc;
    + }
    + 
    +-static sqlite3 *rbuOpenDbhandle(sqlite3rbu *p, const char *zName){
    ++static sqlite3 *rbuOpenDbhandle(
    ++  sqlite3rbu *p, 
    ++  const char *zName, 
    ++  int bUseVfs
    ++){
    +   sqlite3 *db = 0;
    +   if( p->rc==SQLITE_OK ){
    +     const int flags = SQLITE_OPEN_READWRITE|SQLITE_OPEN_CREATE|SQLITE_OPEN_URI;
    +-    p->rc = sqlite3_open_v2(zName, &db, flags, p->zVfsName);
    ++    p->rc = sqlite3_open_v2(zName, &db, flags, bUseVfs ? p->zVfsName : 0);
    +     if( p->rc ){
    +       p->zErrmsg = sqlite3_mprintf("%s", sqlite3_errmsg(db));
    +       sqlite3_close(db);
    +@@ -160943,17 +174996,113 @@ static sqlite3 *rbuOpenDbhandle(sqlite3rbu *p, const char *zName){
    +   return db;
    + }
    + 
    ++/*
    ++** Free an RbuState object allocated by rbuLoadState().
    ++*/
    ++static void rbuFreeState(RbuState *p){
    ++  if( p ){
    ++    sqlite3_free(p->zTbl);
    ++    sqlite3_free(p->zIdx);
    ++    sqlite3_free(p);
    ++  }
    ++}
    ++
    ++/*
    ++** Allocate an RbuState object and load the contents of the rbu_state 
    ++** table into it. Return a pointer to the new object. It is the 
    ++** responsibility of the caller to eventually free the object using
    ++** sqlite3_free().
    ++**
    ++** If an error occurs, leave an error code and message in the rbu handle
    ++** and return NULL.
    ++*/
    ++static RbuState *rbuLoadState(sqlite3rbu *p){
    ++  RbuState *pRet = 0;
    ++  sqlite3_stmt *pStmt = 0;
    ++  int rc;
    ++  int rc2;
    ++
    ++  pRet = (RbuState*)rbuMalloc(p, sizeof(RbuState));
    ++  if( pRet==0 ) return 0;
    ++
    ++  rc = prepareFreeAndCollectError(p->dbRbu, &pStmt, &p->zErrmsg, 
    ++      sqlite3_mprintf("SELECT k, v FROM %s.rbu_state", p->zStateDb)
    ++  );
    ++  while( rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pStmt) ){
    ++    switch( sqlite3_column_int(pStmt, 0) ){
    ++      case RBU_STATE_STAGE:
    ++        pRet->eStage = sqlite3_column_int(pStmt, 1);
    ++        if( pRet->eStage!=RBU_STAGE_OAL
    ++         && pRet->eStage!=RBU_STAGE_MOVE
    ++         && pRet->eStage!=RBU_STAGE_CKPT
    ++        ){
    ++          p->rc = SQLITE_CORRUPT;
    ++        }
    ++        break;
    ++
    ++      case RBU_STATE_TBL:
    ++        pRet->zTbl = rbuStrndup((char*)sqlite3_column_text(pStmt, 1), &rc);
    ++        break;
    ++
    ++      case RBU_STATE_IDX:
    ++        pRet->zIdx = rbuStrndup((char*)sqlite3_column_text(pStmt, 1), &rc);
    ++        break;
    ++
    ++      case RBU_STATE_ROW:
    ++        pRet->nRow = sqlite3_column_int(pStmt, 1);
    ++        break;
    ++
    ++      case RBU_STATE_PROGRESS:
    ++        pRet->nProgress = sqlite3_column_int64(pStmt, 1);
    ++        break;
    ++
    ++      case RBU_STATE_CKPT:
    ++        pRet->iWalCksum = sqlite3_column_int64(pStmt, 1);
    ++        break;
    ++
    ++      case RBU_STATE_COOKIE:
    ++        pRet->iCookie = (u32)sqlite3_column_int64(pStmt, 1);
    ++        break;
    ++
    ++      case RBU_STATE_OALSZ:
    ++        pRet->iOalSz = (u32)sqlite3_column_int64(pStmt, 1);
    ++        break;
    ++
    ++      case RBU_STATE_PHASEONESTEP:
    ++        pRet->nPhaseOneStep = sqlite3_column_int64(pStmt, 1);
    ++        break;
    ++
    ++      default:
    ++        rc = SQLITE_CORRUPT;
    ++        break;
    ++    }
    ++  }
    ++  rc2 = sqlite3_finalize(pStmt);
    ++  if( rc==SQLITE_OK ) rc = rc2;
    ++
    ++  p->rc = rc;
    ++  return pRet;
    ++}
    ++
    ++
    + /*
    + ** Open the database handle and attach the RBU database as "rbu". If an
    + ** error occurs, leave an error code and message in the RBU handle.
    + */
    +-static void rbuOpenDatabase(sqlite3rbu *p){
    +-  assert( p->rc==SQLITE_OK );
    +-  assert( p->dbMain==0 && p->dbRbu==0 );
    ++static void rbuOpenDatabase(sqlite3rbu *p, int *pbRetry){
    ++  assert( p->rc || (p->dbMain==0 && p->dbRbu==0) );
    ++  assert( p->rc || rbuIsVacuum(p) || p->zTarget!=0 );
    + 
    +-  p->eStage = 0;
    +-  p->dbMain = rbuOpenDbhandle(p, p->zTarget);
    +-  p->dbRbu = rbuOpenDbhandle(p, p->zRbu);
    ++  /* Open the RBU database */
    ++  p->dbRbu = rbuOpenDbhandle(p, p->zRbu, 1);
    ++
    ++  if( p->rc==SQLITE_OK && rbuIsVacuum(p) ){
    ++    sqlite3_file_control(p->dbRbu, "main", SQLITE_FCNTL_RBUCNT, (void*)p);
    ++    if( p->zState==0 ){
    ++      const char *zFile = sqlite3_db_filename(p->dbRbu, "main");
    ++      p->zState = rbuMPrintf(p, "file://%s-vacuum?modeof=%s", zFile, zFile);
    ++    }
    ++  }
    + 
    +   /* If using separate RBU and state databases, attach the state database to
    +   ** the RBU db handle now.  */
    +@@ -160964,6 +175113,105 @@ static void rbuOpenDatabase(sqlite3rbu *p){
    +     memcpy(p->zStateDb, "main", 4);
    +   }
    + 
    ++#if 0
    ++  if( p->rc==SQLITE_OK && rbuIsVacuum(p) ){
    ++    p->rc = sqlite3_exec(p->dbRbu, "BEGIN", 0, 0, 0);
    ++  }
    ++#endif
    ++
    ++  /* If it has not already been created, create the rbu_state table */
    ++  rbuMPrintfExec(p, p->dbRbu, RBU_CREATE_STATE, p->zStateDb);
    ++
    ++#if 0
    ++  if( rbuIsVacuum(p) ){
    ++    if( p->rc==SQLITE_OK ){
    ++      int rc2;
    ++      int bOk = 0;
    ++      sqlite3_stmt *pCnt = 0;
    ++      p->rc = prepareAndCollectError(p->dbRbu, &pCnt, &p->zErrmsg,
    ++          "SELECT count(*) FROM stat.sqlite_master"
    ++      );
    ++      if( p->rc==SQLITE_OK 
    ++       && sqlite3_step(pCnt)==SQLITE_ROW
    ++       && 1==sqlite3_column_int(pCnt, 0)
    ++      ){
    ++        bOk = 1;
    ++      }
    ++      rc2 = sqlite3_finalize(pCnt);
    ++      if( p->rc==SQLITE_OK ) p->rc = rc2;
    ++
    ++      if( p->rc==SQLITE_OK && bOk==0 ){
    ++        p->rc = SQLITE_ERROR;
    ++        p->zErrmsg = sqlite3_mprintf("invalid state database");
    ++      }
    ++    
    ++      if( p->rc==SQLITE_OK ){
    ++        p->rc = sqlite3_exec(p->dbRbu, "COMMIT", 0, 0, 0);
    ++      }
    ++    }
    ++  }
    ++#endif
    ++
    ++  if( p->rc==SQLITE_OK && rbuIsVacuum(p) ){
    ++    int bOpen = 0;
    ++    int rc;
    ++    p->nRbu = 0;
    ++    p->pRbuFd = 0;
    ++    rc = sqlite3_file_control(p->dbRbu, "main", SQLITE_FCNTL_RBUCNT, (void*)p);
    ++    if( rc!=SQLITE_NOTFOUND ) p->rc = rc;
    ++    if( p->eStage>=RBU_STAGE_MOVE ){
    ++      bOpen = 1;
    ++    }else{
    ++      RbuState *pState = rbuLoadState(p);
    ++      if( pState ){
    ++        bOpen = (pState->eStage>=RBU_STAGE_MOVE);
    ++        rbuFreeState(pState);
    ++      }
    ++    }
    ++    if( bOpen ) p->dbMain = rbuOpenDbhandle(p, p->zRbu, p->nRbu<=1);
    ++  }
    ++
    ++  p->eStage = 0;
    ++  if( p->rc==SQLITE_OK && p->dbMain==0 ){
    ++    if( !rbuIsVacuum(p) ){
    ++      p->dbMain = rbuOpenDbhandle(p, p->zTarget, 1);
    ++    }else if( p->pRbuFd->pWalFd ){
    ++      if( pbRetry ){
    ++        p->pRbuFd->bNolock = 0;
    ++        sqlite3_close(p->dbRbu);
    ++        sqlite3_close(p->dbMain);
    ++        p->dbMain = 0;
    ++        p->dbRbu = 0;
    ++        *pbRetry = 1;
    ++        return;
    ++      }
    ++      p->rc = SQLITE_ERROR;
    ++      p->zErrmsg = sqlite3_mprintf("cannot vacuum wal mode database");
    ++    }else{
    ++      char *zTarget;
    ++      char *zExtra = 0;
    ++      if( strlen(p->zRbu)>=5 && 0==memcmp("file:", p->zRbu, 5) ){
    ++        zExtra = &p->zRbu[5];
    ++        while( *zExtra ){
    ++          if( *zExtra++=='?' ) break;
    ++        }
    ++        if( *zExtra=='\0' ) zExtra = 0;
    ++      }
    ++
    ++      zTarget = sqlite3_mprintf("file:%s-vacuum?rbu_memory=1%s%s", 
    ++          sqlite3_db_filename(p->dbRbu, "main"),
    ++          (zExtra==0 ? "" : "&"), (zExtra==0 ? "" : zExtra)
    ++      );
    ++
    ++      if( zTarget==0 ){
    ++        p->rc = SQLITE_NOMEM;
    ++        return;
    ++      }
    ++      p->dbMain = rbuOpenDbhandle(p, zTarget, p->nRbu<=1);
    ++      sqlite3_free(zTarget);
    ++    }
    ++  }
    ++
    +   if( p->rc==SQLITE_OK ){
    +     p->rc = sqlite3_create_function(p->dbMain, 
    +         "rbu_tmp_insert", -1, SQLITE_UTF8, (void*)p, rbuTmpInsertFunc, 0, 0
    +@@ -160978,7 +175226,7 @@ static void rbuOpenDatabase(sqlite3rbu *p){
    + 
    +   if( p->rc==SQLITE_OK ){
    +     p->rc = sqlite3_create_function(p->dbRbu, 
    +-        "rbu_target_name", 1, SQLITE_UTF8, (void*)p, rbuTargetNameFunc, 0, 0
    ++        "rbu_target_name", -1, SQLITE_UTF8, (void*)p, rbuTargetNameFunc, 0, 0
    +     );
    +   }
    + 
    +@@ -161027,9 +175275,9 @@ static void rbuFileSuffix3(const char *zBase, char *z){
    + #endif
    +   {
    +     int i, sz;
    +-    sz = sqlite3Strlen30(z);
    ++    sz = (int)strlen(z)&0xffffff;
    +     for(i=sz-1; i>0 && z[i]!='/' && z[i]!='.'; i--){}
    +-    if( z[i]=='.' && ALWAYS(sz>i+4) ) memmove(&z[i+1], &z[sz-3], 4);
    ++    if( z[i]=='.' && sz>i+4 ) memmove(&z[i+1], &z[sz-3], 4);
    +   }
    + #endif
    + }
    +@@ -161117,16 +175365,35 @@ static void rbuSetupCheckpoint(sqlite3rbu *p, RbuState *pState){
    +     if( rc2!=SQLITE_INTERNAL ) p->rc = rc2;
    +   }
    + 
    +-  if( p->rc==SQLITE_OK ){
    ++  if( p->rc==SQLITE_OK && p->nFrame>0 ){
    +     p->eStage = RBU_STAGE_CKPT;
    +     p->nStep = (pState ? pState->nRow : 0);
    +     p->aBuf = rbuMalloc(p, p->pgsz);
    +     p->iWalCksum = rbuShmChecksum(p);
    +   }
    + 
    +-  if( p->rc==SQLITE_OK && pState && pState->iWalCksum!=p->iWalCksum ){
    +-    p->rc = SQLITE_DONE;
    +-    p->eStage = RBU_STAGE_DONE;
    ++  if( p->rc==SQLITE_OK ){
    ++    if( p->nFrame==0 || (pState && pState->iWalCksum!=p->iWalCksum) ){
    ++      p->rc = SQLITE_DONE;
    ++      p->eStage = RBU_STAGE_DONE;
    ++    }else{
    ++      int nSectorSize;
    ++      sqlite3_file *pDb = p->pTargetFd->pReal;
    ++      sqlite3_file *pWal = p->pTargetFd->pWalFd->pReal;
    ++      assert( p->nPagePerSector==0 );
    ++      nSectorSize = pDb->pMethods->xSectorSize(pDb);
    ++      if( nSectorSize>p->pgsz ){
    ++        p->nPagePerSector = nSectorSize / p->pgsz;
    ++      }else{
    ++        p->nPagePerSector = 1;
    ++      }
    ++
    ++      /* Call xSync() on the wal file. This causes SQLite to sync the 
    ++      ** directory in which the target database and the wal file reside, in 
    ++      ** case it has not been synced since the rename() call in 
    ++      ** rbuMoveOalFile(). */
    ++      p->rc = pWal->pMethods->xSync(pWal, SQLITE_SYNC_NORMAL);
    ++    }
    +   }
    + }
    + 
    +@@ -161148,7 +175415,7 @@ static int rbuCaptureWalRead(sqlite3rbu *pRbu, i64 iOff, int iAmt){
    +   if( pRbu->nFrame==pRbu->nFrameAlloc ){
    +     int nNew = (pRbu->nFrameAlloc ? pRbu->nFrameAlloc : 64) * 2;
    +     RbuFrame *aNew;
    +-    aNew = (RbuFrame*)sqlite3_realloc(pRbu->aFrame, nNew * sizeof(RbuFrame));
    ++    aNew = (RbuFrame*)sqlite3_realloc64(pRbu->aFrame, nNew * sizeof(RbuFrame));
    +     if( aNew==0 ) return SQLITE_NOMEM;
    +     pRbu->aFrame = aNew;
    +     pRbu->nFrameAlloc = nNew;
    +@@ -161213,7 +175480,7 @@ static LPWSTR rbuWinUtf8ToUnicode(const char *zFilename){
    +   if( nChar==0 ){
    +     return 0;
    +   }
    +-  zWideFilename = sqlite3_malloc( nChar*sizeof(zWideFilename[0]) );
    ++  zWideFilename = sqlite3_malloc64( nChar*sizeof(zWideFilename[0]) );
    +   if( zWideFilename==0 ){
    +     return 0;
    +   }
    +@@ -161237,9 +175504,15 @@ static LPWSTR rbuWinUtf8ToUnicode(const char *zFilename){
    + */
    + static void rbuMoveOalFile(sqlite3rbu *p){
    +   const char *zBase = sqlite3_db_filename(p->dbMain, "main");
    ++  const char *zMove = zBase;
    ++  char *zOal;
    ++  char *zWal;
    + 
    +-  char *zWal = sqlite3_mprintf("%s-wal", zBase);
    +-  char *zOal = sqlite3_mprintf("%s-oal", zBase);
    ++  if( rbuIsVacuum(p) ){
    ++    zMove = sqlite3_db_filename(p->dbRbu, "main");
    ++  }
    ++  zOal = sqlite3_mprintf("%s-oal", zMove);
    ++  zWal = sqlite3_mprintf("%s-wal", zMove);
    + 
    +   assert( p->eStage==RBU_STAGE_MOVE );
    +   assert( p->rc==SQLITE_OK && p->zErrmsg==0 );
    +@@ -161260,8 +175533,8 @@ static void rbuMoveOalFile(sqlite3rbu *p){
    + 
    +       /* Re-open the databases. */
    +       rbuObjIterFinalize(&p->objiter);
    +-      sqlite3_close(p->dbMain);
    +       sqlite3_close(p->dbRbu);
    ++      sqlite3_close(p->dbMain);
    +       p->dbMain = 0;
    +       p->dbRbu = 0;
    + 
    +@@ -161293,7 +175566,7 @@ static void rbuMoveOalFile(sqlite3rbu *p){
    + #endif
    + 
    +       if( p->rc==SQLITE_OK ){
    +-        rbuOpenDatabase(p);
    ++        rbuOpenDatabase(p, 0);
    +         rbuSetupCheckpoint(p, 0);
    +       }
    +     }
    +@@ -161327,14 +175600,12 @@ static int rbuStepType(sqlite3rbu *p, const char **pzMask){
    +   switch( sqlite3_column_type(p->objiter.pSelect, iCol) ){
    +     case SQLITE_INTEGER: {
    +       int iVal = sqlite3_column_int(p->objiter.pSelect, iCol);
    +-      if( iVal==0 ){
    +-        res = RBU_INSERT;
    +-      }else if( iVal==1 ){
    +-        res = RBU_DELETE;
    +-      }else if( iVal==2 ){
    +-        res = RBU_IDX_DELETE;
    +-      }else if( iVal==3 ){
    +-        res = RBU_IDX_INSERT;
    ++      switch( iVal ){
    ++        case 0: res = RBU_INSERT;     break;
    ++        case 1: res = RBU_DELETE;     break;
    ++        case 2: res = RBU_REPLACE;    break;
    ++        case 3: res = RBU_IDX_DELETE; break;
    ++        case 4: res = RBU_IDX_INSERT; break;
    +       }
    +       break;
    +     }
    +@@ -161373,6 +175644,83 @@ static void assertColumnName(sqlite3_stmt *pStmt, int iCol, const char *zName){
    + # define assertColumnName(x,y,z)
    + #endif
    + 
    ++/*
    ++** Argument eType must be one of RBU_INSERT, RBU_DELETE, RBU_IDX_INSERT or
    ++** RBU_IDX_DELETE. This function performs the work of a single
    ++** sqlite3rbu_step() call for the type of operation specified by eType.
    ++*/
    ++static void rbuStepOneOp(sqlite3rbu *p, int eType){
    ++  RbuObjIter *pIter = &p->objiter;
    ++  sqlite3_value *pVal;
    ++  sqlite3_stmt *pWriter;
    ++  int i;
    ++
    ++  assert( p->rc==SQLITE_OK );
    ++  assert( eType!=RBU_DELETE || pIter->zIdx==0 );
    ++  assert( eType==RBU_DELETE || eType==RBU_IDX_DELETE
    ++       || eType==RBU_INSERT || eType==RBU_IDX_INSERT
    ++  );
    ++
    ++  /* If this is a delete, decrement nPhaseOneStep by nIndex. If the DELETE
    ++  ** statement below does actually delete a row, nPhaseOneStep will be
    ++  ** incremented by the same amount when SQL function rbu_tmp_insert()
    ++  ** is invoked by the trigger.  */
    ++  if( eType==RBU_DELETE ){
    ++    p->nPhaseOneStep -= p->objiter.nIndex;
    ++  }
    ++
    ++  if( eType==RBU_IDX_DELETE || eType==RBU_DELETE ){
    ++    pWriter = pIter->pDelete;
    ++  }else{
    ++    pWriter = pIter->pInsert;
    ++  }
    ++
    ++  for(i=0; i<pIter->nCol; i++){
    ++    /* If this is an INSERT into a table b-tree and the table has an
    ++    ** explicit INTEGER PRIMARY KEY, check that this is not an attempt
    ++    ** to write a NULL into the IPK column. That is not permitted.  */
    ++    if( eType==RBU_INSERT 
    ++     && pIter->zIdx==0 && pIter->eType==RBU_PK_IPK && pIter->abTblPk[i] 
    ++     && sqlite3_column_type(pIter->pSelect, i)==SQLITE_NULL
    ++    ){
    ++      p->rc = SQLITE_MISMATCH;
    ++      p->zErrmsg = sqlite3_mprintf("datatype mismatch");
    ++      return;
    ++    }
    ++
    ++    if( eType==RBU_DELETE && pIter->abTblPk[i]==0 ){
    ++      continue;
    ++    }
    ++
    ++    pVal = sqlite3_column_value(pIter->pSelect, i);
    ++    p->rc = sqlite3_bind_value(pWriter, i+1, pVal);
    ++    if( p->rc ) return;
    ++  }
    ++  if( pIter->zIdx==0 ){
    ++    if( pIter->eType==RBU_PK_VTAB 
    ++     || pIter->eType==RBU_PK_NONE 
    ++     || (pIter->eType==RBU_PK_EXTERNAL && rbuIsVacuum(p)) 
    ++    ){
    ++      /* For a virtual table, or a table with no primary key, the 
    ++      ** SELECT statement is:
    ++      **
    ++      **   SELECT <cols>, rbu_control, rbu_rowid FROM ....
    ++      **
    ++      ** Hence column_value(pIter->nCol+1).
    ++      */
    ++      assertColumnName(pIter->pSelect, pIter->nCol+1, 
    ++          rbuIsVacuum(p) ? "rowid" : "rbu_rowid"
    ++      );
    ++      pVal = sqlite3_column_value(pIter->pSelect, pIter->nCol+1);
    ++      p->rc = sqlite3_bind_value(pWriter, pIter->nCol+1, pVal);
    ++    }
    ++  }
    ++  if( p->rc==SQLITE_OK ){
    ++    sqlite3_step(pWriter);
    ++    p->rc = resetAndCollectError(pWriter, &p->zErrmsg);
    ++  }
    ++}
    ++
    + /*
    + ** This function does the work for an sqlite3rbu_step() call.
    + **
    +@@ -161387,78 +175735,36 @@ static void assertColumnName(sqlite3_stmt *pStmt, int iCol, const char *zName){
    + static int rbuStep(sqlite3rbu *p){
    +   RbuObjIter *pIter = &p->objiter;
    +   const char *zMask = 0;
    +-  int i;
    +   int eType = rbuStepType(p, &zMask);
    + 
    +   if( eType ){
    ++    assert( eType==RBU_INSERT     || eType==RBU_DELETE
    ++         || eType==RBU_REPLACE    || eType==RBU_IDX_DELETE
    ++         || eType==RBU_IDX_INSERT || eType==RBU_UPDATE
    ++    );
    +     assert( eType!=RBU_UPDATE || pIter->zIdx==0 );
    + 
    +-    if( pIter->zIdx==0 && eType==RBU_IDX_DELETE ){
    ++    if( pIter->zIdx==0 && (eType==RBU_IDX_DELETE || eType==RBU_IDX_INSERT) ){
    +       rbuBadControlError(p);
    +     }
    +-    else if( 
    +-        eType==RBU_INSERT 
    +-     || eType==RBU_DELETE
    +-     || eType==RBU_IDX_DELETE 
    +-     || eType==RBU_IDX_INSERT
    +-    ){
    +-      sqlite3_value *pVal;
    +-      sqlite3_stmt *pWriter;
    +-
    +-      assert( eType!=RBU_UPDATE );
    +-      assert( eType!=RBU_DELETE || pIter->zIdx==0 );
    +-
    +-      if( eType==RBU_IDX_DELETE || eType==RBU_DELETE ){
    +-        pWriter = pIter->pDelete;
    +-      }else{
    +-        pWriter = pIter->pInsert;
    +-      }
    +-
    +-      for(i=0; i<pIter->nCol; i++){
    +-        /* If this is an INSERT into a table b-tree and the table has an
    +-        ** explicit INTEGER PRIMARY KEY, check that this is not an attempt
    +-        ** to write a NULL into the IPK column. That is not permitted.  */
    +-        if( eType==RBU_INSERT 
    +-         && pIter->zIdx==0 && pIter->eType==RBU_PK_IPK && pIter->abTblPk[i] 
    +-         && sqlite3_column_type(pIter->pSelect, i)==SQLITE_NULL
    +-        ){
    +-          p->rc = SQLITE_MISMATCH;
    +-          p->zErrmsg = sqlite3_mprintf("datatype mismatch");
    +-          goto step_out;
    +-        }
    +-
    +-        if( eType==RBU_DELETE && pIter->abTblPk[i]==0 ){
    +-          continue;
    +-        }
    +-
    +-        pVal = sqlite3_column_value(pIter->pSelect, i);
    +-        p->rc = sqlite3_bind_value(pWriter, i+1, pVal);
    +-        if( p->rc ) goto step_out;
    +-      }
    +-      if( pIter->zIdx==0
    +-       && (pIter->eType==RBU_PK_VTAB || pIter->eType==RBU_PK_NONE) 
    +-      ){
    +-        /* For a virtual table, or a table with no primary key, the 
    +-        ** SELECT statement is:
    +-        **
    +-        **   SELECT <cols>, rbu_control, rbu_rowid FROM ....
    +-        **
    +-        ** Hence column_value(pIter->nCol+1).
    +-        */
    +-        assertColumnName(pIter->pSelect, pIter->nCol+1, "rbu_rowid");
    +-        pVal = sqlite3_column_value(pIter->pSelect, pIter->nCol+1);
    +-        p->rc = sqlite3_bind_value(pWriter, pIter->nCol+1, pVal);
    ++    else if( eType==RBU_REPLACE ){
    ++      if( pIter->zIdx==0 ){
    ++        p->nPhaseOneStep += p->objiter.nIndex;
    ++        rbuStepOneOp(p, RBU_DELETE);
    +       }
    +-      if( p->rc==SQLITE_OK ){
    +-        sqlite3_step(pWriter);
    +-        p->rc = resetAndCollectError(pWriter, &p->zErrmsg);
    +-      }
    +-    }else{
    ++      if( p->rc==SQLITE_OK ) rbuStepOneOp(p, RBU_INSERT);
    ++    }
    ++    else if( eType!=RBU_UPDATE ){
    ++      rbuStepOneOp(p, eType);
    ++    }
    ++    else{
    +       sqlite3_value *pVal;
    +       sqlite3_stmt *pUpdate = 0;
    +       assert( eType==RBU_UPDATE );
    ++      p->nPhaseOneStep -= p->objiter.nIndex;
    +       rbuGetUpdateStmt(p, pIter, zMask, &pUpdate);
    +       if( pUpdate ){
    ++        int i;
    +         for(i=0; p->rc==SQLITE_OK && i<pIter->nCol; i++){
    +           char c = zMask[pIter->aiSrcOrder[i]];
    +           pVal = sqlite3_column_value(pIter->pSelect, i);
    +@@ -161481,20 +175787,23 @@ static int rbuStep(sqlite3rbu *p){
    +       }
    +     }
    +   }
    +-
    +- step_out:
    +   return p->rc;
    + }
    + 
    + /*
    + ** Increment the schema cookie of the main database opened by p->dbMain.
    ++**
    ++** Or, if this is an RBU vacuum, set the schema cookie of the main db
    ++** opened by p->dbMain to one more than the schema cookie of the main
    ++** db opened by p->dbRbu.
    + */
    + static void rbuIncrSchemaCookie(sqlite3rbu *p){
    +   if( p->rc==SQLITE_OK ){
    ++    sqlite3 *dbread = (rbuIsVacuum(p) ? p->dbRbu : p->dbMain);
    +     int iCookie = 1000000;
    +     sqlite3_stmt *pStmt;
    + 
    +-    p->rc = prepareAndCollectError(p->dbMain, &pStmt, &p->zErrmsg, 
    ++    p->rc = prepareAndCollectError(dbread, &pStmt, &p->zErrmsg, 
    +         "PRAGMA schema_version"
    +     );
    +     if( p->rc==SQLITE_OK ){
    +@@ -161522,6 +175831,7 @@ static void rbuIncrSchemaCookie(sqlite3rbu *p){
    + static void rbuSaveState(sqlite3rbu *p, int eStage){
    +   if( p->rc==SQLITE_OK || p->rc==SQLITE_DONE ){
    +     sqlite3_stmt *pInsert = 0;
    ++    rbu_file *pFd = (rbuIsVacuum(p) ? p->pRbuFd : p->pTargetFd);
    +     int rc;
    + 
    +     assert( p->zErrmsg==0 );
    +@@ -161535,6 +175845,7 @@ static void rbuSaveState(sqlite3rbu *p, int eStage){
    +           "(%d, %d), "
    +           "(%d, %lld), "
    +           "(%d, %lld), "
    ++          "(%d, %lld), "
    +           "(%d, %lld) ",
    +           p->zStateDb,
    +           RBU_STATE_STAGE, eStage,
    +@@ -161543,8 +175854,9 @@ static void rbuSaveState(sqlite3rbu *p, int eStage){
    +           RBU_STATE_ROW, p->nStep, 
    +           RBU_STATE_PROGRESS, p->nProgress,
    +           RBU_STATE_CKPT, p->iWalCksum,
    +-          RBU_STATE_COOKIE, (i64)p->pTargetFd->iCookie,
    +-          RBU_STATE_OALSZ, p->iOalSz
    ++          RBU_STATE_COOKIE, (i64)pFd->iCookie,
    ++          RBU_STATE_OALSZ, p->iOalSz,
    ++          RBU_STATE_PHASEONESTEP, p->nPhaseOneStep
    +       )
    +     );
    +     assert( pInsert==0 || rc==SQLITE_OK );
    +@@ -161558,21 +175870,116 @@ static void rbuSaveState(sqlite3rbu *p, int eStage){
    + }
    + 
    + 
    ++/*
    ++** The second argument passed to this function is the name of a PRAGMA 
    ++** setting - "page_size", "auto_vacuum", "user_version" or "application_id".
    ++** This function executes the following on sqlite3rbu.dbRbu:
    ++**
    ++**   "PRAGMA main.$zPragma"
    ++**
    ++** where $zPragma is the string passed as the second argument, then
    ++** on sqlite3rbu.dbMain:
    ++**
    ++**   "PRAGMA main.$zPragma = $val"
    ++**
    ++** where $val is the value returned by the first PRAGMA invocation.
    ++**
    ++** In short, it copies the value  of the specified PRAGMA setting from
    ++** dbRbu to dbMain.
    ++*/
    ++static void rbuCopyPragma(sqlite3rbu *p, const char *zPragma){
    ++  if( p->rc==SQLITE_OK ){
    ++    sqlite3_stmt *pPragma = 0;
    ++    p->rc = prepareFreeAndCollectError(p->dbRbu, &pPragma, &p->zErrmsg, 
    ++        sqlite3_mprintf("PRAGMA main.%s", zPragma)
    ++    );
    ++    if( p->rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pPragma) ){
    ++      p->rc = rbuMPrintfExec(p, p->dbMain, "PRAGMA main.%s = %d",
    ++          zPragma, sqlite3_column_int(pPragma, 0)
    ++      );
    ++    }
    ++    rbuFinalize(p, pPragma);
    ++  }
    ++}
    ++
    ++/*
    ++** The RBU handle passed as the only argument has just been opened and 
    ++** the state database is empty. If this RBU handle was opened for an
    ++** RBU vacuum operation, create the schema in the target db.
    ++*/
    ++static void rbuCreateTargetSchema(sqlite3rbu *p){
    ++  sqlite3_stmt *pSql = 0;
    ++  sqlite3_stmt *pInsert = 0;
    ++
    ++  assert( rbuIsVacuum(p) );
    ++  p->rc = sqlite3_exec(p->dbMain, "PRAGMA writable_schema=1", 0,0, &p->zErrmsg);
    ++  if( p->rc==SQLITE_OK ){
    ++    p->rc = prepareAndCollectError(p->dbRbu, &pSql, &p->zErrmsg, 
    ++      "SELECT sql FROM sqlite_master WHERE sql!='' AND rootpage!=0"
    ++      " AND name!='sqlite_sequence' "
    ++      " ORDER BY type DESC"
    ++    );
    ++  }
    ++
    ++  while( p->rc==SQLITE_OK && sqlite3_step(pSql)==SQLITE_ROW ){
    ++    const char *zSql = (const char*)sqlite3_column_text(pSql, 0);
    ++    p->rc = sqlite3_exec(p->dbMain, zSql, 0, 0, &p->zErrmsg);
    ++  }
    ++  rbuFinalize(p, pSql);
    ++  if( p->rc!=SQLITE_OK ) return;
    ++
    ++  if( p->rc==SQLITE_OK ){
    ++    p->rc = prepareAndCollectError(p->dbRbu, &pSql, &p->zErrmsg, 
    ++        "SELECT * FROM sqlite_master WHERE rootpage=0 OR rootpage IS NULL" 
    ++    );
    ++  }
    ++
    ++  if( p->rc==SQLITE_OK ){
    ++    p->rc = prepareAndCollectError(p->dbMain, &pInsert, &p->zErrmsg, 
    ++        "INSERT INTO sqlite_master VALUES(?,?,?,?,?)"
    ++    );
    ++  }
    ++
    ++  while( p->rc==SQLITE_OK && sqlite3_step(pSql)==SQLITE_ROW ){
    ++    int i;
    ++    for(i=0; i<5; i++){
    ++      sqlite3_bind_value(pInsert, i+1, sqlite3_column_value(pSql, i));
    ++    }
    ++    sqlite3_step(pInsert);
    ++    p->rc = sqlite3_reset(pInsert);
    ++  }
    ++  if( p->rc==SQLITE_OK ){
    ++    p->rc = sqlite3_exec(p->dbMain, "PRAGMA writable_schema=0",0,0,&p->zErrmsg);
    ++  }
    ++
    ++  rbuFinalize(p, pSql);
    ++  rbuFinalize(p, pInsert);
    ++}
    ++
    + /*
    + ** Step the RBU object.
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3rbu_step(sqlite3rbu *p){
    ++SQLITE_API int sqlite3rbu_step(sqlite3rbu *p){
    +   if( p ){
    +     switch( p->eStage ){
    +       case RBU_STAGE_OAL: {
    +         RbuObjIter *pIter = &p->objiter;
    ++
    ++        /* If this is an RBU vacuum operation and the state table was empty
    ++        ** when this handle was opened, create the target database schema. */
    ++        if( rbuIsVacuum(p) && p->nProgress==0 && p->rc==SQLITE_OK ){
    ++          rbuCreateTargetSchema(p);
    ++          rbuCopyPragma(p, "user_version");
    ++          rbuCopyPragma(p, "application_id");
    ++        }
    ++
    +         while( p->rc==SQLITE_OK && pIter->zTbl ){
    + 
    +           if( pIter->bCleanup ){
    +             /* Clean up the rbu_tmp_xxx table for the previous table. It 
    +             ** cannot be dropped as there are currently active SQL statements.
    +             ** But the contents can be deleted.  */
    +-            if( pIter->abIndexed ){
    ++            if( rbuIsVacuum(p)==0 && pIter->abIndexed ){
    +               rbuMPrintfExec(p, p->dbRbu, 
    +                   "DELETE FROM %s.'rbu_tmp_%q'", p->zStateDb, pIter->zDataTbl
    +               );
    +@@ -161641,9 +176048,26 @@ SQLITE_API int SQLITE_STDCALL sqlite3rbu_step(sqlite3rbu *p){
    +               p->rc = SQLITE_DONE;
    +             }
    +           }else{
    +-            RbuFrame *pFrame = &p->aFrame[p->nStep];
    +-            rbuCheckpointFrame(p, pFrame);
    +-            p->nStep++;
    ++            /* At one point the following block copied a single frame from the
    ++            ** wal file to the database file. So that one call to sqlite3rbu_step()
    ++            ** checkpointed a single frame. 
    ++            **
    ++            ** However, if the sector-size is larger than the page-size, and the
    ++            ** application calls sqlite3rbu_savestate() or close() immediately
    ++            ** after this step, then rbu_step() again, then a power failure occurs,
    ++            ** then the database page written here may be damaged. Work around
    ++            ** this by checkpointing frames until the next page in the aFrame[]
    ++            ** lies on a different disk sector to the current one. */
    ++            u32 iSector;
    ++            do{
    ++              RbuFrame *pFrame = &p->aFrame[p->nStep];
    ++              iSector = (pFrame->iDbPage-1) / p->nPagePerSector;
    ++              rbuCheckpointFrame(p, pFrame);
    ++              p->nStep++;
    ++            }while( p->nStep<p->nFrame 
    ++                 && iSector==((p->aFrame[p->nStep].iDbPage-1) / p->nPagePerSector)
    ++                 && p->rc==SQLITE_OK
    ++            );
    +           }
    +           p->nProgress++;
    +         }
    +@@ -161659,90 +176083,6 @@ SQLITE_API int SQLITE_STDCALL sqlite3rbu_step(sqlite3rbu *p){
    +   }
    + }
    + 
    +-/*
    +-** Free an RbuState object allocated by rbuLoadState().
    +-*/
    +-static void rbuFreeState(RbuState *p){
    +-  if( p ){
    +-    sqlite3_free(p->zTbl);
    +-    sqlite3_free(p->zIdx);
    +-    sqlite3_free(p);
    +-  }
    +-}
    +-
    +-/*
    +-** Allocate an RbuState object and load the contents of the rbu_state 
    +-** table into it. Return a pointer to the new object. It is the 
    +-** responsibility of the caller to eventually free the object using
    +-** sqlite3_free().
    +-**
    +-** If an error occurs, leave an error code and message in the rbu handle
    +-** and return NULL.
    +-*/
    +-static RbuState *rbuLoadState(sqlite3rbu *p){
    +-  RbuState *pRet = 0;
    +-  sqlite3_stmt *pStmt = 0;
    +-  int rc;
    +-  int rc2;
    +-
    +-  pRet = (RbuState*)rbuMalloc(p, sizeof(RbuState));
    +-  if( pRet==0 ) return 0;
    +-
    +-  rc = prepareFreeAndCollectError(p->dbRbu, &pStmt, &p->zErrmsg, 
    +-      sqlite3_mprintf("SELECT k, v FROM %s.rbu_state", p->zStateDb)
    +-  );
    +-  while( rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pStmt) ){
    +-    switch( sqlite3_column_int(pStmt, 0) ){
    +-      case RBU_STATE_STAGE:
    +-        pRet->eStage = sqlite3_column_int(pStmt, 1);
    +-        if( pRet->eStage!=RBU_STAGE_OAL
    +-         && pRet->eStage!=RBU_STAGE_MOVE
    +-         && pRet->eStage!=RBU_STAGE_CKPT
    +-        ){
    +-          p->rc = SQLITE_CORRUPT;
    +-        }
    +-        break;
    +-
    +-      case RBU_STATE_TBL:
    +-        pRet->zTbl = rbuStrndup((char*)sqlite3_column_text(pStmt, 1), &rc);
    +-        break;
    +-
    +-      case RBU_STATE_IDX:
    +-        pRet->zIdx = rbuStrndup((char*)sqlite3_column_text(pStmt, 1), &rc);
    +-        break;
    +-
    +-      case RBU_STATE_ROW:
    +-        pRet->nRow = sqlite3_column_int(pStmt, 1);
    +-        break;
    +-
    +-      case RBU_STATE_PROGRESS:
    +-        pRet->nProgress = sqlite3_column_int64(pStmt, 1);
    +-        break;
    +-
    +-      case RBU_STATE_CKPT:
    +-        pRet->iWalCksum = sqlite3_column_int64(pStmt, 1);
    +-        break;
    +-
    +-      case RBU_STATE_COOKIE:
    +-        pRet->iCookie = (u32)sqlite3_column_int64(pStmt, 1);
    +-        break;
    +-
    +-      case RBU_STATE_OALSZ:
    +-        pRet->iOalSz = (u32)sqlite3_column_int64(pStmt, 1);
    +-        break;
    +-
    +-      default:
    +-        rc = SQLITE_CORRUPT;
    +-        break;
    +-    }
    +-  }
    +-  rc2 = sqlite3_finalize(pStmt);
    +-  if( rc==SQLITE_OK ) rc = rc2;
    +-
    +-  p->rc = rc;
    +-  return pRet;
    +-}
    +-
    + /*
    + ** Compare strings z1 and z2, returning 0 if they are identical, or non-zero
    + ** otherwise. Either or both argument may be NULL. Two NULL values are
    +@@ -161824,6 +176164,7 @@ static void rbuCreateVfs(sqlite3rbu *p){
    +     sqlite3_vfs *pVfs = sqlite3_vfs_find(zRnd);
    +     assert( pVfs );
    +     p->zVfsName = pVfs->zName;
    ++    ((rbu_vfs*)pVfs)->pRbu = p;
    +   }
    + }
    + 
    +@@ -161839,19 +176180,111 @@ static void rbuDeleteVfs(sqlite3rbu *p){
    + }
    + 
    + /*
    +-** Open and return a new RBU handle. 
    ++** This user-defined SQL function is invoked with a single argument - the
    ++** name of a table expected to appear in the target database. It returns
    ++** the number of auxilliary indexes on the table.
    + */
    +-SQLITE_API sqlite3rbu *SQLITE_STDCALL sqlite3rbu_open(
    ++static void rbuIndexCntFunc(
    ++  sqlite3_context *pCtx, 
    ++  int nVal,
    ++  sqlite3_value **apVal
    ++){
    ++  sqlite3rbu *p = (sqlite3rbu*)sqlite3_user_data(pCtx);
    ++  sqlite3_stmt *pStmt = 0;
    ++  char *zErrmsg = 0;
    ++  int rc;
    ++
    ++  assert( nVal==1 );
    ++  
    ++  rc = prepareFreeAndCollectError(p->dbMain, &pStmt, &zErrmsg, 
    ++      sqlite3_mprintf("SELECT count(*) FROM sqlite_master "
    ++        "WHERE type='index' AND tbl_name = %Q", sqlite3_value_text(apVal[0]))
    ++  );
    ++  if( rc!=SQLITE_OK ){
    ++    sqlite3_result_error(pCtx, zErrmsg, -1);
    ++  }else{
    ++    int nIndex = 0;
    ++    if( SQLITE_ROW==sqlite3_step(pStmt) ){
    ++      nIndex = sqlite3_column_int(pStmt, 0);
    ++    }
    ++    rc = sqlite3_finalize(pStmt);
    ++    if( rc==SQLITE_OK ){
    ++      sqlite3_result_int(pCtx, nIndex);
    ++    }else{
    ++      sqlite3_result_error(pCtx, sqlite3_errmsg(p->dbMain), -1);
    ++    }
    ++  }
    ++
    ++  sqlite3_free(zErrmsg);
    ++}
    ++
    ++/*
    ++** If the RBU database contains the rbu_count table, use it to initialize
    ++** the sqlite3rbu.nPhaseOneStep variable. The schema of the rbu_count table
    ++** is assumed to contain the same columns as:
    ++**
    ++**   CREATE TABLE rbu_count(tbl TEXT PRIMARY KEY, cnt INTEGER) WITHOUT ROWID;
    ++**
    ++** There should be one row in the table for each data_xxx table in the
    ++** database. The 'tbl' column should contain the name of a data_xxx table,
    ++** and the cnt column the number of rows it contains.
    ++**
    ++** sqlite3rbu.nPhaseOneStep is initialized to the sum of (1 + nIndex) * cnt
    ++** for all rows in the rbu_count table, where nIndex is the number of 
    ++** indexes on the corresponding target database table.
    ++*/
    ++static void rbuInitPhaseOneSteps(sqlite3rbu *p){
    ++  if( p->rc==SQLITE_OK ){
    ++    sqlite3_stmt *pStmt = 0;
    ++    int bExists = 0;                /* True if rbu_count exists */
    ++
    ++    p->nPhaseOneStep = -1;
    ++
    ++    p->rc = sqlite3_create_function(p->dbRbu, 
    ++        "rbu_index_cnt", 1, SQLITE_UTF8, (void*)p, rbuIndexCntFunc, 0, 0
    ++    );
    ++  
    ++    /* Check for the rbu_count table. If it does not exist, or if an error
    ++    ** occurs, nPhaseOneStep will be left set to -1. */
    ++    if( p->rc==SQLITE_OK ){
    ++      p->rc = prepareAndCollectError(p->dbRbu, &pStmt, &p->zErrmsg,
    ++          "SELECT 1 FROM sqlite_master WHERE tbl_name = 'rbu_count'"
    ++      );
    ++    }
    ++    if( p->rc==SQLITE_OK ){
    ++      if( SQLITE_ROW==sqlite3_step(pStmt) ){
    ++        bExists = 1;
    ++      }
    ++      p->rc = sqlite3_finalize(pStmt);
    ++    }
    ++  
    ++    if( p->rc==SQLITE_OK && bExists ){
    ++      p->rc = prepareAndCollectError(p->dbRbu, &pStmt, &p->zErrmsg,
    ++          "SELECT sum(cnt * (1 + rbu_index_cnt(rbu_target_name(tbl))))"
    ++          "FROM rbu_count"
    ++      );
    ++      if( p->rc==SQLITE_OK ){
    ++        if( SQLITE_ROW==sqlite3_step(pStmt) ){
    ++          p->nPhaseOneStep = sqlite3_column_int64(pStmt, 0);
    ++        }
    ++        p->rc = sqlite3_finalize(pStmt);
    ++      }
    ++    }
    ++  }
    ++}
    ++
    ++
    ++static sqlite3rbu *openRbuHandle(
    +   const char *zTarget, 
    +   const char *zRbu,
    +   const char *zState
    + ){
    +   sqlite3rbu *p;
    +-  int nTarget = strlen(zTarget);
    +-  int nRbu = strlen(zRbu);
    +-  int nState = zState ? strlen(zState) : 0;
    ++  size_t nTarget = zTarget ? strlen(zTarget) : 0;
    ++  size_t nRbu = strlen(zRbu);
    ++  size_t nByte = sizeof(sqlite3rbu) + nTarget+1 + nRbu+1;
    + 
    +-  p = (sqlite3rbu*)sqlite3_malloc(sizeof(sqlite3rbu)+nTarget+1+nRbu+1+nState+1);
    ++  p = (sqlite3rbu*)sqlite3_malloc64(nByte);
    +   if( p ){
    +     RbuState *pState = 0;
    + 
    +@@ -161859,21 +176292,34 @@ SQLITE_API sqlite3rbu *SQLITE_STDCALL sqlite3rbu_open(
    +     memset(p, 0, sizeof(sqlite3rbu));
    +     rbuCreateVfs(p);
    + 
    +-    /* Open the target database */
    ++    /* Open the target, RBU and state databases */
    +     if( p->rc==SQLITE_OK ){
    +-      p->zTarget = (char*)&p[1];
    +-      memcpy(p->zTarget, zTarget, nTarget+1);
    +-      p->zRbu = &p->zTarget[nTarget+1];
    ++      char *pCsr = (char*)&p[1];
    ++      int bRetry = 0;
    ++      if( zTarget ){
    ++        p->zTarget = pCsr;
    ++        memcpy(p->zTarget, zTarget, nTarget+1);
    ++        pCsr += nTarget+1;
    ++      }
    ++      p->zRbu = pCsr;
    +       memcpy(p->zRbu, zRbu, nRbu+1);
    ++      pCsr += nRbu+1;
    +       if( zState ){
    +-        p->zState = &p->zRbu[nRbu+1];
    +-        memcpy(p->zState, zState, nState+1);
    ++        p->zState = rbuMPrintf(p, "%s", zState);
    +       }
    +-      rbuOpenDatabase(p);
    +-    }
    + 
    +-    /* If it has not already been created, create the rbu_state table */
    +-    rbuMPrintfExec(p, p->dbRbu, RBU_CREATE_STATE, p->zStateDb);
    ++      /* If the first attempt to open the database file fails and the bRetry
    ++      ** flag it set, this means that the db was not opened because it seemed
    ++      ** to be a wal-mode db. But, this may have happened due to an earlier
    ++      ** RBU vacuum operation leaving an old wal file in the directory.
    ++      ** If this is the case, it will have been checkpointed and deleted
    ++      ** when the handle was closed and a second attempt to open the 
    ++      ** database may succeed.  */
    ++      rbuOpenDatabase(p, &bRetry);
    ++      if( bRetry ){
    ++        rbuOpenDatabase(p, 0);
    ++      }
    ++    }
    + 
    +     if( p->rc==SQLITE_OK ){
    +       pState = rbuLoadState(p);
    +@@ -161882,9 +176328,11 @@ SQLITE_API sqlite3rbu *SQLITE_STDCALL sqlite3rbu_open(
    + 
    +         if( pState->eStage==0 ){ 
    +           rbuDeleteOalFile(p);
    ++          rbuInitPhaseOneSteps(p);
    +           p->eStage = RBU_STAGE_OAL;
    +         }else{
    +           p->eStage = pState->eStage;
    ++          p->nPhaseOneStep = pState->nPhaseOneStep;
    +         }
    +         p->nProgress = pState->nProgress;
    +         p->iOalSz = pState->iOalSz;
    +@@ -161902,38 +176350,27 @@ SQLITE_API sqlite3rbu *SQLITE_STDCALL sqlite3rbu_open(
    +       }
    +     }
    + 
    +-    if( p->rc==SQLITE_OK
    ++    if( p->rc==SQLITE_OK 
    +      && (p->eStage==RBU_STAGE_OAL || p->eStage==RBU_STAGE_MOVE)
    +-     && pState->eStage!=0 && p->pTargetFd->iCookie!=pState->iCookie
    +-    ){   
    +-      /* At this point (pTargetFd->iCookie) contains the value of the
    +-      ** change-counter cookie (the thing that gets incremented when a 
    +-      ** transaction is committed in rollback mode) currently stored on 
    +-      ** page 1 of the database file. */
    +-      p->rc = SQLITE_BUSY;
    +-      p->zErrmsg = sqlite3_mprintf("database modified during rbu update");
    ++     && pState->eStage!=0
    ++    ){
    ++      rbu_file *pFd = (rbuIsVacuum(p) ? p->pRbuFd : p->pTargetFd);
    ++      if( pFd->iCookie!=pState->iCookie ){   
    ++        /* At this point (pTargetFd->iCookie) contains the value of the
    ++        ** change-counter cookie (the thing that gets incremented when a 
    ++        ** transaction is committed in rollback mode) currently stored on 
    ++        ** page 1 of the database file. */
    ++        p->rc = SQLITE_BUSY;
    ++        p->zErrmsg = sqlite3_mprintf("database modified during rbu %s",
    ++            (rbuIsVacuum(p) ? "vacuum" : "update")
    ++        );
    ++      }
    +     }
    + 
    +     if( p->rc==SQLITE_OK ){
    +       if( p->eStage==RBU_STAGE_OAL ){
    +         sqlite3 *db = p->dbMain;
    +-
    +-        /* Open transactions both databases. The *-oal file is opened or
    +-        ** created at this point. */
    +-        p->rc = sqlite3_exec(db, "BEGIN IMMEDIATE", 0, 0, &p->zErrmsg);
    +-        if( p->rc==SQLITE_OK ){
    +-          p->rc = sqlite3_exec(p->dbRbu, "BEGIN IMMEDIATE", 0, 0, &p->zErrmsg);
    +-        }
    +-
    +-        /* Check if the main database is a zipvfs db. If it is, set the upper
    +-        ** level pager to use "journal_mode=off". This prevents it from 
    +-        ** generating a large journal using a temp file.  */
    +-        if( p->rc==SQLITE_OK ){
    +-          int frc = sqlite3_file_control(db, "main", SQLITE_FCNTL_ZIPVFS, 0);
    +-          if( frc==SQLITE_OK ){
    +-            p->rc = sqlite3_exec(db, "PRAGMA journal_mode=off",0,0,&p->zErrmsg);
    +-          }
    +-        }
    ++        p->rc = sqlite3_exec(p->dbRbu, "BEGIN", 0, 0, &p->zErrmsg);
    + 
    +         /* Point the object iterator at the first object */
    +         if( p->rc==SQLITE_OK ){
    +@@ -161944,12 +176381,34 @@ SQLITE_API sqlite3rbu *SQLITE_STDCALL sqlite3rbu_open(
    +         ** update finished.  */
    +         if( p->rc==SQLITE_OK && p->objiter.zTbl==0 ){
    +           p->rc = SQLITE_DONE;
    +-        }
    ++          p->eStage = RBU_STAGE_DONE;
    ++        }else{
    ++          if( p->rc==SQLITE_OK && pState->eStage==0 && rbuIsVacuum(p) ){
    ++            rbuCopyPragma(p, "page_size");
    ++            rbuCopyPragma(p, "auto_vacuum");
    ++          }
    + 
    +-        if( p->rc==SQLITE_OK ){
    +-          rbuSetupOal(p, pState);
    +-        }
    ++          /* Open transactions both databases. The *-oal file is opened or
    ++          ** created at this point. */
    ++          if( p->rc==SQLITE_OK ){
    ++            p->rc = sqlite3_exec(db, "BEGIN IMMEDIATE", 0, 0, &p->zErrmsg);
    ++          }
    ++
    ++          /* Check if the main database is a zipvfs db. If it is, set the upper
    ++          ** level pager to use "journal_mode=off". This prevents it from 
    ++          ** generating a large journal using a temp file.  */
    ++          if( p->rc==SQLITE_OK ){
    ++            int frc = sqlite3_file_control(db, "main", SQLITE_FCNTL_ZIPVFS, 0);
    ++            if( frc==SQLITE_OK ){
    ++              p->rc = sqlite3_exec(
    ++                db, "PRAGMA journal_mode=off",0,0,&p->zErrmsg);
    ++            }
    ++          }
    + 
    ++          if( p->rc==SQLITE_OK ){
    ++            rbuSetupOal(p, pState);
    ++          }
    ++        }
    +       }else if( p->eStage==RBU_STAGE_MOVE ){
    +         /* no-op */
    +       }else if( p->eStage==RBU_STAGE_CKPT ){
    +@@ -161967,11 +176426,49 @@ SQLITE_API sqlite3rbu *SQLITE_STDCALL sqlite3rbu_open(
    +   return p;
    + }
    + 
    ++/*
    ++** Allocate and return an RBU handle with all fields zeroed except for the
    ++** error code, which is set to SQLITE_MISUSE.
    ++*/
    ++static sqlite3rbu *rbuMisuseError(void){
    ++  sqlite3rbu *pRet;
    ++  pRet = sqlite3_malloc64(sizeof(sqlite3rbu));
    ++  if( pRet ){
    ++    memset(pRet, 0, sizeof(sqlite3rbu));
    ++    pRet->rc = SQLITE_MISUSE;
    ++  }
    ++  return pRet;
    ++}
    ++
    ++/*
    ++** Open and return a new RBU handle. 
    ++*/
    ++SQLITE_API sqlite3rbu *sqlite3rbu_open(
    ++  const char *zTarget, 
    ++  const char *zRbu,
    ++  const char *zState
    ++){
    ++  if( zTarget==0 || zRbu==0 ){ return rbuMisuseError(); }
    ++  /* TODO: Check that zTarget and zRbu are non-NULL */
    ++  return openRbuHandle(zTarget, zRbu, zState);
    ++}
    ++
    ++/*
    ++** Open a handle to begin or resume an RBU VACUUM operation.
    ++*/
    ++SQLITE_API sqlite3rbu *sqlite3rbu_vacuum(
    ++  const char *zTarget, 
    ++  const char *zState
    ++){
    ++  if( zTarget==0 ){ return rbuMisuseError(); }
    ++  /* TODO: Check that both arguments are non-NULL */
    ++  return openRbuHandle(0, zTarget, zState);
    ++}
    + 
    + /*
    + ** Return the database handle used by pRbu.
    + */
    +-SQLITE_API sqlite3 *SQLITE_STDCALL sqlite3rbu_db(sqlite3rbu *pRbu, int bRbu){
    ++SQLITE_API sqlite3 *sqlite3rbu_db(sqlite3rbu *pRbu, int bRbu){
    +   sqlite3 *db = 0;
    +   if( pRbu ){
    +     db = (bRbu ? pRbu->dbRbu : pRbu->dbMain);
    +@@ -161987,8 +176484,8 @@ SQLITE_API sqlite3 *SQLITE_STDCALL sqlite3rbu_db(sqlite3rbu *pRbu, int bRbu){
    + */
    + static void rbuEditErrmsg(sqlite3rbu *p){
    +   if( p->rc==SQLITE_CONSTRAINT && p->zErrmsg ){
    +-    int i;
    +-    int nErrmsg = strlen(p->zErrmsg);
    ++    unsigned int i;
    ++    size_t nErrmsg = strlen(p->zErrmsg);
    +     for(i=0; i<(nErrmsg-8); i++){
    +       if( memcmp(&p->zErrmsg[i], "rbu_imp_", 8)==0 ){
    +         int nDel = 8;
    +@@ -162003,7 +176500,7 @@ static void rbuEditErrmsg(sqlite3rbu *p){
    + /*
    + ** Close the RBU handle.
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3rbu_close(sqlite3rbu *p, char **pzErrmsg){
    ++SQLITE_API int sqlite3rbu_close(sqlite3rbu *p, char **pzErrmsg){
    +   int rc;
    +   if( p ){
    + 
    +@@ -162012,6 +176509,12 @@ SQLITE_API int SQLITE_STDCALL sqlite3rbu_close(sqlite3rbu *p, char **pzErrmsg){
    +       p->rc = sqlite3_exec(p->dbMain, "COMMIT", 0, 0, &p->zErrmsg);
    +     }
    + 
    ++    /* Sync the db file if currently doing an incremental checkpoint */
    ++    if( p->rc==SQLITE_OK && p->eStage==RBU_STAGE_CKPT ){
    ++      sqlite3_file *pDb = p->pTargetFd->pReal;
    ++      p->rc = pDb->pMethods->xSync(pDb, SQLITE_SYNC_NORMAL);
    ++    }
    ++
    +     rbuSaveState(p, p->eStage);
    + 
    +     if( p->rc==SQLITE_OK && p->eStage==RBU_STAGE_OAL ){
    +@@ -162021,16 +176524,32 @@ SQLITE_API int SQLITE_STDCALL sqlite3rbu_close(sqlite3rbu *p, char **pzErrmsg){
    +     /* Close any open statement handles. */
    +     rbuObjIterFinalize(&p->objiter);
    + 
    ++    /* If this is an RBU vacuum handle and the vacuum has either finished
    ++    ** successfully or encountered an error, delete the contents of the 
    ++    ** state table. This causes the next call to sqlite3rbu_vacuum() 
    ++    ** specifying the current target and state databases to start a new
    ++    ** vacuum from scratch.  */
    ++    if( rbuIsVacuum(p) && p->rc!=SQLITE_OK && p->dbRbu ){
    ++      int rc2 = sqlite3_exec(p->dbRbu, "DELETE FROM stat.rbu_state", 0, 0, 0);
    ++      if( p->rc==SQLITE_DONE && rc2!=SQLITE_OK ) p->rc = rc2;
    ++    }
    ++
    +     /* Close the open database handle and VFS object. */
    +-    sqlite3_close(p->dbMain);
    +     sqlite3_close(p->dbRbu);
    ++    sqlite3_close(p->dbMain);
    ++    assert( p->szTemp==0 );
    +     rbuDeleteVfs(p);
    +     sqlite3_free(p->aBuf);
    +     sqlite3_free(p->aFrame);
    + 
    +     rbuEditErrmsg(p);
    +     rc = p->rc;
    +-    *pzErrmsg = p->zErrmsg;
    ++    if( pzErrmsg ){
    ++      *pzErrmsg = p->zErrmsg;
    ++    }else{
    ++      sqlite3_free(p->zErrmsg);
    ++    }
    ++    sqlite3_free(p->zState);
    +     sqlite3_free(p);
    +   }else{
    +     rc = SQLITE_NOMEM;
    +@@ -162044,13 +176563,79 @@ SQLITE_API int SQLITE_STDCALL sqlite3rbu_close(sqlite3rbu *p, char **pzErrmsg){
    + ** updates) that have been performed on the target database since the
    + ** current RBU update was started.
    + */
    +-SQLITE_API sqlite3_int64 SQLITE_STDCALL sqlite3rbu_progress(sqlite3rbu *pRbu){
    ++SQLITE_API sqlite3_int64 sqlite3rbu_progress(sqlite3rbu *pRbu){
    +   return pRbu->nProgress;
    + }
    + 
    +-SQLITE_API int SQLITE_STDCALL sqlite3rbu_savestate(sqlite3rbu *p){
    ++/*
    ++** Return permyriadage progress indications for the two main stages of
    ++** an RBU update.
    ++*/
    ++SQLITE_API void sqlite3rbu_bp_progress(sqlite3rbu *p, int *pnOne, int *pnTwo){
    ++  const int MAX_PROGRESS = 10000;
    ++  switch( p->eStage ){
    ++    case RBU_STAGE_OAL:
    ++      if( p->nPhaseOneStep>0 ){
    ++        *pnOne = (int)(MAX_PROGRESS * (i64)p->nProgress/(i64)p->nPhaseOneStep);
    ++      }else{
    ++        *pnOne = -1;
    ++      }
    ++      *pnTwo = 0;
    ++      break;
    ++
    ++    case RBU_STAGE_MOVE:
    ++      *pnOne = MAX_PROGRESS;
    ++      *pnTwo = 0;
    ++      break;
    ++
    ++    case RBU_STAGE_CKPT:
    ++      *pnOne = MAX_PROGRESS;
    ++      *pnTwo = (int)(MAX_PROGRESS * (i64)p->nStep / (i64)p->nFrame);
    ++      break;
    ++
    ++    case RBU_STAGE_DONE:
    ++      *pnOne = MAX_PROGRESS;
    ++      *pnTwo = MAX_PROGRESS;
    ++      break;
    ++
    ++    default:
    ++      assert( 0 );
    ++  }
    ++}
    ++
    ++/*
    ++** Return the current state of the RBU vacuum or update operation.
    ++*/
    ++SQLITE_API int sqlite3rbu_state(sqlite3rbu *p){
    ++  int aRes[] = {
    ++    0, SQLITE_RBU_STATE_OAL, SQLITE_RBU_STATE_MOVE,
    ++    0, SQLITE_RBU_STATE_CHECKPOINT, SQLITE_RBU_STATE_DONE
    ++  };
    ++
    ++  assert( RBU_STAGE_OAL==1 );
    ++  assert( RBU_STAGE_MOVE==2 );
    ++  assert( RBU_STAGE_CKPT==4 );
    ++  assert( RBU_STAGE_DONE==5 );
    ++  assert( aRes[RBU_STAGE_OAL]==SQLITE_RBU_STATE_OAL );
    ++  assert( aRes[RBU_STAGE_MOVE]==SQLITE_RBU_STATE_MOVE );
    ++  assert( aRes[RBU_STAGE_CKPT]==SQLITE_RBU_STATE_CHECKPOINT );
    ++  assert( aRes[RBU_STAGE_DONE]==SQLITE_RBU_STATE_DONE );
    ++
    ++  if( p->rc!=SQLITE_OK && p->rc!=SQLITE_DONE ){
    ++    return SQLITE_RBU_STATE_ERROR;
    ++  }else{
    ++    assert( p->rc!=SQLITE_DONE || p->eStage==RBU_STAGE_DONE );
    ++    assert( p->eStage==RBU_STAGE_OAL
    ++         || p->eStage==RBU_STAGE_MOVE
    ++         || p->eStage==RBU_STAGE_CKPT
    ++         || p->eStage==RBU_STAGE_DONE
    ++    );
    ++    return aRes[p->eStage];
    ++  }
    ++}
    ++
    ++SQLITE_API int sqlite3rbu_savestate(sqlite3rbu *p){
    +   int rc = p->rc;
    +-  
    +   if( rc==SQLITE_DONE ) return SQLITE_OK;
    + 
    +   assert( p->eStage>=RBU_STAGE_OAL && p->eStage<=RBU_STAGE_DONE );
    +@@ -162059,6 +176644,12 @@ SQLITE_API int SQLITE_STDCALL sqlite3rbu_savestate(sqlite3rbu *p){
    +     if( rc==SQLITE_OK ) rc = sqlite3_exec(p->dbMain, "COMMIT", 0, 0, 0);
    +   }
    + 
    ++  /* Sync the db file */
    ++  if( rc==SQLITE_OK && p->eStage==RBU_STAGE_CKPT ){
    ++    sqlite3_file *pDb = p->pTargetFd->pReal;
    ++    rc = pDb->pMethods->xSync(pDb, SQLITE_SYNC_NORMAL);
    ++  }
    ++
    +   p->rc = rc;
    +   rbuSaveState(p, p->eStage);
    +   rc = p->rc;
    +@@ -162134,6 +176725,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3rbu_savestate(sqlite3rbu *p){
    + */
    + 
    + static void rbuUnlockShm(rbu_file *p){
    ++  assert( p->openFlags & SQLITE_OPEN_MAIN_DB );
    +   if( p->pRbu ){
    +     int (*xShmLock)(sqlite3_file*,int,int,int) = p->pReal->pMethods->xShmLock;
    +     int i;
    +@@ -162146,6 +176738,81 @@ static void rbuUnlockShm(rbu_file *p){
    +   }
    + }
    + 
    ++/*
    ++*/
    ++static int rbuUpdateTempSize(rbu_file *pFd, sqlite3_int64 nNew){
    ++  sqlite3rbu *pRbu = pFd->pRbu;
    ++  i64 nDiff = nNew - pFd->sz;
    ++  pRbu->szTemp += nDiff;
    ++  pFd->sz = nNew;
    ++  assert( pRbu->szTemp>=0 );
    ++  if( pRbu->szTempLimit && pRbu->szTemp>pRbu->szTempLimit ) return SQLITE_FULL;
    ++  return SQLITE_OK;
    ++}
    ++
    ++/*
    ++** Add an item to the main-db lists, if it is not already present.
    ++**
    ++** There are two main-db lists. One for all file descriptors, and one
    ++** for all file descriptors with rbu_file.pDb!=0. If the argument has
    ++** rbu_file.pDb!=0, then it is assumed to already be present on the
    ++** main list and is only added to the pDb!=0 list.
    ++*/
    ++static void rbuMainlistAdd(rbu_file *p){
    ++  rbu_vfs *pRbuVfs = p->pRbuVfs;
    ++  rbu_file *pIter;
    ++  assert( (p->openFlags & SQLITE_OPEN_MAIN_DB) );
    ++  sqlite3_mutex_enter(pRbuVfs->mutex);
    ++  if( p->pRbu==0 ){
    ++    for(pIter=pRbuVfs->pMain; pIter; pIter=pIter->pMainNext);
    ++    p->pMainNext = pRbuVfs->pMain;
    ++    pRbuVfs->pMain = p;
    ++  }else{
    ++    for(pIter=pRbuVfs->pMainRbu; pIter && pIter!=p; pIter=pIter->pMainRbuNext){}
    ++    if( pIter==0 ){
    ++      p->pMainRbuNext = pRbuVfs->pMainRbu;
    ++      pRbuVfs->pMainRbu = p;
    ++    }
    ++  }
    ++  sqlite3_mutex_leave(pRbuVfs->mutex);
    ++}
    ++
    ++/*
    ++** Remove an item from the main-db lists.
    ++*/
    ++static void rbuMainlistRemove(rbu_file *p){
    ++  rbu_file **pp;
    ++  sqlite3_mutex_enter(p->pRbuVfs->mutex);
    ++  for(pp=&p->pRbuVfs->pMain; *pp && *pp!=p; pp=&((*pp)->pMainNext)){}
    ++  if( *pp ) *pp = p->pMainNext;
    ++  p->pMainNext = 0;
    ++  for(pp=&p->pRbuVfs->pMainRbu; *pp && *pp!=p; pp=&((*pp)->pMainRbuNext)){}
    ++  if( *pp ) *pp = p->pMainRbuNext;
    ++  p->pMainRbuNext = 0;
    ++  sqlite3_mutex_leave(p->pRbuVfs->mutex);
    ++}
    ++
    ++/*
    ++** Given that zWal points to a buffer containing a wal file name passed to
    ++** either the xOpen() or xAccess() VFS method, search the main-db list for
    ++** a file-handle opened by the same database connection on the corresponding
    ++** database file.
    ++**
    ++** If parameter bRbu is true, only search for file-descriptors with
    ++** rbu_file.pDb!=0.
    ++*/
    ++static rbu_file *rbuFindMaindb(rbu_vfs *pRbuVfs, const char *zWal, int bRbu){
    ++  rbu_file *pDb;
    ++  sqlite3_mutex_enter(pRbuVfs->mutex);
    ++  if( bRbu ){
    ++    for(pDb=pRbuVfs->pMainRbu; pDb && pDb->zWal!=zWal; pDb=pDb->pMainRbuNext){}
    ++  }else{
    ++    for(pDb=pRbuVfs->pMain; pDb && pDb->zWal!=zWal; pDb=pDb->pMainNext){}
    ++  }
    ++  sqlite3_mutex_leave(pRbuVfs->mutex);
    ++  return pDb;
    ++}
    ++
    + /*
    + ** Close an rbu file.
    + */
    +@@ -162163,14 +176830,14 @@ static int rbuVfsClose(sqlite3_file *pFile){
    +   sqlite3_free(p->zDel);
    + 
    +   if( p->openFlags & SQLITE_OPEN_MAIN_DB ){
    +-    rbu_file **pp;
    +-    sqlite3_mutex_enter(p->pRbuVfs->mutex);
    +-    for(pp=&p->pRbuVfs->pMain; *pp!=p; pp=&((*pp)->pMainNext));
    +-    *pp = p->pMainNext;
    +-    sqlite3_mutex_leave(p->pRbuVfs->mutex);
    ++    rbuMainlistRemove(p);
    +     rbuUnlockShm(p);
    +     p->pReal->pMethods->xShmUnmap(p->pReal, 0);
    +   }
    ++  else if( (p->openFlags & SQLITE_OPEN_DELETEONCLOSE) && p->pRbu ){
    ++    rbuUpdateTempSize(p, 0);
    ++  }
    ++  assert( p->pMainNext==0 && p->pRbuVfs->pMain!=p );
    + 
    +   /* Close the underlying file handle */
    +   rc = p->pReal->pMethods->xClose(p->pReal);
    +@@ -162189,6 +176856,22 @@ static u32 rbuGetU32(u8 *aBuf){
    +        + ((u32)aBuf[3]);
    + }
    + 
    ++/*
    ++** Write an unsigned 32-bit value in big-endian format to the supplied
    ++** buffer.
    ++*/
    ++static void rbuPutU32(u8 *aBuf, u32 iVal){
    ++  aBuf[0] = (iVal >> 24) & 0xFF;
    ++  aBuf[1] = (iVal >> 16) & 0xFF;
    ++  aBuf[2] = (iVal >>  8) & 0xFF;
    ++  aBuf[3] = (iVal >>  0) & 0xFF;
    ++}
    ++
    ++static void rbuPutU16(u8 *aBuf, u16 iVal){
    ++  aBuf[0] = (iVal >>  8) & 0xFF;
    ++  aBuf[1] = (iVal >>  0) & 0xFF;
    ++}
    ++
    + /*
    + ** Read data from an rbuVfs-file.
    + */
    +@@ -162214,6 +176897,35 @@ static int rbuVfsRead(
    +       memset(zBuf, 0, iAmt);
    +     }else{
    +       rc = p->pReal->pMethods->xRead(p->pReal, zBuf, iAmt, iOfst);
    ++#if 1
    ++      /* If this is being called to read the first page of the target 
    ++      ** database as part of an rbu vacuum operation, synthesize the 
    ++      ** contents of the first page if it does not yet exist. Otherwise,
    ++      ** SQLite will not check for a *-wal file.  */
    ++      if( pRbu && rbuIsVacuum(pRbu) 
    ++          && rc==SQLITE_IOERR_SHORT_READ && iOfst==0
    ++          && (p->openFlags & SQLITE_OPEN_MAIN_DB)
    ++          && pRbu->rc==SQLITE_OK
    ++      ){
    ++        sqlite3_file *pFd = (sqlite3_file*)pRbu->pRbuFd;
    ++        rc = pFd->pMethods->xRead(pFd, zBuf, iAmt, iOfst);
    ++        if( rc==SQLITE_OK ){
    ++          u8 *aBuf = (u8*)zBuf;
    ++          u32 iRoot = rbuGetU32(&aBuf[52]) ? 1 : 0;
    ++          rbuPutU32(&aBuf[52], iRoot);      /* largest root page number */
    ++          rbuPutU32(&aBuf[36], 0);          /* number of free pages */
    ++          rbuPutU32(&aBuf[32], 0);          /* first page on free list trunk */
    ++          rbuPutU32(&aBuf[28], 1);          /* size of db file in pages */
    ++          rbuPutU32(&aBuf[24], pRbu->pRbuFd->iCookie+1);  /* Change counter */
    ++
    ++          if( iAmt>100 ){
    ++            memset(&aBuf[100], 0, iAmt-100);
    ++            rbuPutU16(&aBuf[105], iAmt & 0xFFFF);
    ++            aBuf[100] = 0x0D;
    ++          }
    ++        }
    ++      }
    ++#endif
    +     }
    +     if( rc==SQLITE_OK && iOfst==0 && (p->openFlags & SQLITE_OPEN_MAIN_DB) ){
    +       /* These look like magic numbers. But they are stable, as they are part
    +@@ -162243,11 +176955,19 @@ static int rbuVfsWrite(
    +     assert( p->openFlags & SQLITE_OPEN_MAIN_DB );
    +     rc = rbuCaptureDbWrite(p->pRbu, iOfst);
    +   }else{
    +-    if( pRbu && pRbu->eStage==RBU_STAGE_OAL 
    +-     && (p->openFlags & SQLITE_OPEN_WAL) 
    +-     && iOfst>=pRbu->iOalSz
    +-    ){
    +-      pRbu->iOalSz = iAmt + iOfst;
    ++    if( pRbu ){
    ++      if( pRbu->eStage==RBU_STAGE_OAL 
    ++       && (p->openFlags & SQLITE_OPEN_WAL) 
    ++       && iOfst>=pRbu->iOalSz
    ++      ){
    ++        pRbu->iOalSz = iAmt + iOfst;
    ++      }else if( p->openFlags & SQLITE_OPEN_DELETEONCLOSE ){
    ++        i64 szNew = iAmt+iOfst;
    ++        if( szNew>p->sz ){
    ++          rc = rbuUpdateTempSize(p, szNew);
    ++          if( rc!=SQLITE_OK ) return rc;
    ++        }
    ++      }
    +     }
    +     rc = p->pReal->pMethods->xWrite(p->pReal, zBuf, iAmt, iOfst);
    +     if( rc==SQLITE_OK && iOfst==0 && (p->openFlags & SQLITE_OPEN_MAIN_DB) ){
    +@@ -162266,6 +176986,10 @@ static int rbuVfsWrite(
    + */
    + static int rbuVfsTruncate(sqlite3_file *pFile, sqlite_int64 size){
    +   rbu_file *p = (rbu_file*)pFile;
    ++  if( (p->openFlags & SQLITE_OPEN_DELETEONCLOSE) && p->pRbu ){
    ++    int rc = rbuUpdateTempSize(p, size);
    ++    if( rc!=SQLITE_OK ) return rc;
    ++  }
    +   return p->pReal->pMethods->xTruncate(p->pReal, size);
    + }
    + 
    +@@ -162288,7 +177012,20 @@ static int rbuVfsSync(sqlite3_file *pFile, int flags){
    + */
    + static int rbuVfsFileSize(sqlite3_file *pFile, sqlite_int64 *pSize){
    +   rbu_file *p = (rbu_file *)pFile;
    +-  return p->pReal->pMethods->xFileSize(p->pReal, pSize);
    ++  int rc;
    ++  rc = p->pReal->pMethods->xFileSize(p->pReal, pSize);
    ++
    ++  /* If this is an RBU vacuum operation and this is the target database,
    ++  ** pretend that it has at least one page. Otherwise, SQLite will not
    ++  ** check for the existance of a *-wal file. rbuVfsRead() contains 
    ++  ** similar logic.  */
    ++  if( rc==SQLITE_OK && *pSize==0 
    ++   && p->pRbu && rbuIsVacuum(p->pRbu) 
    ++   && (p->openFlags & SQLITE_OPEN_MAIN_DB)
    ++  ){
    ++    *pSize = 1024;
    ++  }
    ++  return rc;
    + }
    + 
    + /*
    +@@ -162300,7 +177037,9 @@ static int rbuVfsLock(sqlite3_file *pFile, int eLock){
    +   int rc = SQLITE_OK;
    + 
    +   assert( p->openFlags & (SQLITE_OPEN_MAIN_DB|SQLITE_OPEN_TEMP_DB) );
    +-  if( pRbu && eLock==SQLITE_LOCK_EXCLUSIVE && pRbu->eStage!=RBU_STAGE_DONE ){
    ++  if( eLock==SQLITE_LOCK_EXCLUSIVE 
    ++   && (p->bNolock || (pRbu && pRbu->eStage!=RBU_STAGE_DONE))
    ++  ){
    +     /* Do not allow EXCLUSIVE locks. Preventing SQLite from taking this 
    +     ** prevents it from checkpointing the database from sqlite3_close(). */
    +     rc = SQLITE_BUSY;
    +@@ -162357,12 +177096,21 @@ static int rbuVfsFileControl(sqlite3_file *pFile, int op, void *pArg){
    +       }else if( rc==SQLITE_NOTFOUND ){
    +         pRbu->pTargetFd = p;
    +         p->pRbu = pRbu;
    ++        if( p->openFlags & SQLITE_OPEN_MAIN_DB ){
    ++          rbuMainlistAdd(p);
    ++        }
    +         if( p->pWalFd ) p->pWalFd->pRbu = pRbu;
    +         rc = SQLITE_OK;
    +       }
    +     }
    +     return rc;
    +   }
    ++  else if( op==SQLITE_FCNTL_RBUCNT ){
    ++    sqlite3rbu *pRbu = (sqlite3rbu*)pArg;
    ++    pRbu->nRbu++;
    ++    pRbu->pRbuFd = p;
    ++    p->bNolock = 1;
    ++  }
    + 
    +   rc = xControl(p->pReal, op, pArg);
    +   if( rc==SQLITE_OK && op==SQLITE_FCNTL_VFSNAME ){
    +@@ -162452,7 +177200,7 @@ static int rbuVfsShmMap(
    +   if( eStage==RBU_STAGE_OAL || eStage==RBU_STAGE_MOVE ){
    +     if( iRegion<=p->nShm ){
    +       int nByte = (iRegion+1) * sizeof(char*);
    +-      char **apNew = (char**)sqlite3_realloc(p->apShm, nByte);
    ++      char **apNew = (char**)sqlite3_realloc64(p->apShm, nByte);
    +       if( apNew==0 ){
    +         rc = SQLITE_NOMEM;
    +       }else{
    +@@ -162463,7 +177211,7 @@ static int rbuVfsShmMap(
    +     }
    + 
    +     if( rc==SQLITE_OK && p->apShm[iRegion]==0 ){
    +-      char *pNew = (char*)sqlite3_malloc(szRegion);
    ++      char *pNew = (char*)sqlite3_malloc64(szRegion);
    +       if( pNew==0 ){
    +         rc = SQLITE_NOMEM;
    +       }else{
    +@@ -162512,18 +177260,31 @@ static int rbuVfsShmUnmap(sqlite3_file *pFile, int delFlag){
    +   return rc;
    + }
    + 
    +-/*
    +-** Given that zWal points to a buffer containing a wal file name passed to 
    +-** either the xOpen() or xAccess() VFS method, return a pointer to the
    +-** file-handle opened by the same database connection on the corresponding
    +-** database file.
    +-*/
    +-static rbu_file *rbuFindMaindb(rbu_vfs *pRbuVfs, const char *zWal){
    +-  rbu_file *pDb;
    +-  sqlite3_mutex_enter(pRbuVfs->mutex);
    +-  for(pDb=pRbuVfs->pMain; pDb && pDb->zWal!=zWal; pDb=pDb->pMainNext);
    +-  sqlite3_mutex_leave(pRbuVfs->mutex);
    +-  return pDb;
    ++/* 
    ++** A main database named zName has just been opened. The following 
    ++** function returns a pointer to a buffer owned by SQLite that contains
    ++** the name of the *-wal file this db connection will use. SQLite
    ++** happens to pass a pointer to this buffer when using xAccess()
    ++** or xOpen() to operate on the *-wal file.  
    ++*/
    ++static const char *rbuMainToWal(const char *zName, int flags){
    ++  int n = (int)strlen(zName);
    ++  const char *z = &zName[n];
    ++  if( flags & SQLITE_OPEN_URI ){
    ++    int odd = 0;
    ++    while( 1 ){
    ++      if( z[0]==0 ){
    ++        odd = 1 - odd;
    ++        if( odd && z[1]==0 ) break;
    ++      }
    ++      z++;
    ++    }
    ++    z += 2;
    ++  }else{
    ++    while( *z==0 ) z++;
    ++  }
    ++  z += (n + 8 + 1);
    ++  return z;
    + }
    + 
    + /*
    +@@ -162561,6 +177322,7 @@ static int rbuVfsOpen(
    +   rbu_file *pFd = (rbu_file *)pFile;
    +   int rc = SQLITE_OK;
    +   const char *zOpen = zName;
    ++  int oflags = flags;
    + 
    +   memset(pFd, 0, sizeof(rbu_file));
    +   pFd->pReal = (sqlite3_file*)&pFd[1];
    +@@ -162573,36 +177335,27 @@ static int rbuVfsOpen(
    +       ** the name of the *-wal file this db connection will use. SQLite
    +       ** happens to pass a pointer to this buffer when using xAccess()
    +       ** or xOpen() to operate on the *-wal file.  */
    +-      int n = strlen(zName);
    +-      const char *z = &zName[n];
    +-      if( flags & SQLITE_OPEN_URI ){
    +-        int odd = 0;
    +-        while( 1 ){
    +-          if( z[0]==0 ){
    +-            odd = 1 - odd;
    +-            if( odd && z[1]==0 ) break;
    +-          }
    +-          z++;
    +-        }
    +-        z += 2;
    +-      }else{
    +-        while( *z==0 ) z++;
    +-      }
    +-      z += (n + 8 + 1);
    +-      pFd->zWal = z;
    ++      pFd->zWal = rbuMainToWal(zName, flags);
    +     }
    +     else if( flags & SQLITE_OPEN_WAL ){
    +-      rbu_file *pDb = rbuFindMaindb(pRbuVfs, zName);
    ++      rbu_file *pDb = rbuFindMaindb(pRbuVfs, zName, 0);
    +       if( pDb ){
    +         if( pDb->pRbu && pDb->pRbu->eStage==RBU_STAGE_OAL ){
    +           /* This call is to open a *-wal file. Intead, open the *-oal. This
    +           ** code ensures that the string passed to xOpen() is terminated by a
    +           ** pair of '\0' bytes in case the VFS attempts to extract a URI 
    +           ** parameter from it.  */
    +-          int nCopy = strlen(zName);
    +-          char *zCopy = sqlite3_malloc(nCopy+2);
    ++          const char *zBase = zName;
    ++          size_t nCopy;
    ++          char *zCopy;
    ++          if( rbuIsVacuum(pDb->pRbu) ){
    ++            zBase = sqlite3_db_filename(pDb->pRbu->dbRbu, "main");
    ++            zBase = rbuMainToWal(zBase, SQLITE_OPEN_URI);
    ++          }
    ++          nCopy = strlen(zBase);
    ++          zCopy = sqlite3_malloc64(nCopy+2);
    +           if( zCopy ){
    +-            memcpy(zCopy, zName, nCopy);
    ++            memcpy(zCopy, zBase, nCopy);
    +             zCopy[nCopy-3] = 'o';
    +             zCopy[nCopy] = '\0';
    +             zCopy[nCopy+1] = '\0';
    +@@ -162615,10 +177368,21 @@ static int rbuVfsOpen(
    +         pDb->pWalFd = pFd;
    +       }
    +     }
    ++  }else{
    ++    pFd->pRbu = pRbuVfs->pRbu;
    ++  }
    ++
    ++  if( oflags & SQLITE_OPEN_MAIN_DB 
    ++   && sqlite3_uri_boolean(zName, "rbu_memory", 0) 
    ++  ){
    ++    assert( oflags & SQLITE_OPEN_MAIN_DB );
    ++    oflags =  SQLITE_OPEN_TEMP_DB | SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE |
    ++              SQLITE_OPEN_EXCLUSIVE | SQLITE_OPEN_DELETEONCLOSE;
    ++    zOpen = 0;
    +   }
    + 
    +   if( rc==SQLITE_OK ){
    +-    rc = pRealVfs->xOpen(pRealVfs, zOpen, pFd->pReal, flags, pOutFlags);
    ++    rc = pRealVfs->xOpen(pRealVfs, zOpen, pFd->pReal, oflags, pOutFlags);
    +   }
    +   if( pFd->pReal->pMethods ){
    +     /* The xOpen() operation has succeeded. Set the sqlite3_file.pMethods
    +@@ -162626,10 +177390,7 @@ static int rbuVfsOpen(
    +     ** mutex protected linked list of all such files.  */
    +     pFile->pMethods = &rbuvfs_io_methods;
    +     if( flags & SQLITE_OPEN_MAIN_DB ){
    +-      sqlite3_mutex_enter(pRbuVfs->mutex);
    +-      pFd->pMainNext = pRbuVfs->pMain;
    +-      pRbuVfs->pMain = pFd;
    +-      sqlite3_mutex_leave(pRbuVfs->mutex);
    ++      rbuMainlistAdd(pFd);
    +     }
    +   }else{
    +     sqlite3_free(pFd->zDel);
    +@@ -162677,12 +177438,14 @@ static int rbuVfsAccess(
    +   **      file opened instead.
    +   */
    +   if( rc==SQLITE_OK && flags==SQLITE_ACCESS_EXISTS ){
    +-    rbu_file *pDb = rbuFindMaindb(pRbuVfs, zPath);
    ++    rbu_file *pDb = rbuFindMaindb(pRbuVfs, zPath, 1);
    +     if( pDb && pDb->pRbu && pDb->pRbu->eStage==RBU_STAGE_OAL ){
    +       if( *pResOut ){
    +         rc = SQLITE_CANTOPEN;
    +       }else{
    +-        *pResOut = 1;
    ++        sqlite3_int64 sz = 0;
    ++        rc = rbuVfsFileSize(&pDb->base, &sz);
    ++        *pResOut = (sz>0);
    +       }
    +     }
    +   }
    +@@ -162782,7 +177545,7 @@ static int rbuVfsGetLastError(sqlite3_vfs *pVfs, int a, char *b){
    + ** Deregister and destroy an RBU vfs created by an earlier call to
    + ** sqlite3rbu_create_vfs().
    + */
    +-SQLITE_API void SQLITE_STDCALL sqlite3rbu_destroy_vfs(const char *zName){
    ++SQLITE_API void sqlite3rbu_destroy_vfs(const char *zName){
    +   sqlite3_vfs *pVfs = sqlite3_vfs_find(zName);
    +   if( pVfs && pVfs->xOpen==rbuVfsOpen ){
    +     sqlite3_mutex_free(((rbu_vfs*)pVfs)->mutex);
    +@@ -162796,7 +177559,7 @@ SQLITE_API void SQLITE_STDCALL sqlite3rbu_destroy_vfs(const char *zName){
    + ** via existing VFS zParent. The new object is registered as a non-default
    + ** VFS with SQLite before returning.
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3rbu_create_vfs(const char *zName, const char *zParent){
    ++SQLITE_API int sqlite3rbu_create_vfs(const char *zName, const char *zParent){
    + 
    +   /* Template for VFS */
    +   static sqlite3_vfs vfs_template = {
    +@@ -162829,13 +177592,13 @@ SQLITE_API int SQLITE_STDCALL sqlite3rbu_create_vfs(const char *zName, const cha
    +   };
    + 
    +   rbu_vfs *pNew = 0;              /* Newly allocated VFS */
    +-  int nName;
    +   int rc = SQLITE_OK;
    ++  size_t nName;
    ++  size_t nByte;
    + 
    +-  int nByte;
    +   nName = strlen(zName);
    +   nByte = sizeof(rbu_vfs) + nName + 1;
    +-  pNew = (rbu_vfs*)sqlite3_malloc(nByte);
    ++  pNew = (rbu_vfs*)sqlite3_malloc64(nByte);
    +   if( pNew==0 ){
    +     rc = SQLITE_NOMEM;
    +   }else{
    +@@ -162871,6 +177634,20 @@ SQLITE_API int SQLITE_STDCALL sqlite3rbu_create_vfs(const char *zName, const cha
    +   return rc;
    + }
    + 
    ++/*
    ++** Configure the aggregate temp file size limit for this RBU handle.
    ++*/
    ++SQLITE_API sqlite3_int64 sqlite3rbu_temp_size_limit(sqlite3rbu *pRbu, sqlite3_int64 n){
    ++  if( n>=0 ){
    ++    pRbu->szTempLimit = n;
    ++  }
    ++  return pRbu->szTempLimit;
    ++}
    ++
    ++SQLITE_API sqlite3_int64 sqlite3rbu_temp_size(sqlite3rbu *pRbu){
    ++  return pRbu->szTemp;
    ++}
    ++
    + 
    + /**************************************************************************/
    + 
    +@@ -162938,10 +177715,10 @@ SQLITE_API int SQLITE_STDCALL sqlite3rbu_create_vfs(const char *zName, const cha
    + */
    + #define VTAB_SCHEMA                                                         \
    +   "CREATE TABLE xx( "                                                       \
    +-  "  name       STRING,           /* Name of table or index */"             \
    +-  "  path       INTEGER,          /* Path to page from root */"             \
    ++  "  name       TEXT,             /* Name of table or index */"             \
    ++  "  path       TEXT,             /* Path to page from root */"             \
    +   "  pageno     INTEGER,          /* Page number */"                        \
    +-  "  pagetype   STRING,           /* 'internal', 'leaf' or 'overflow' */"   \
    ++  "  pagetype   TEXT,             /* 'internal', 'leaf' or 'overflow' */"   \
    +   "  ncell      INTEGER,          /* Cells on page (0 for overflow) */"     \
    +   "  payload    INTEGER,          /* Bytes of payload on this page */"      \
    +   "  unused     INTEGER,          /* Bytes of unused space on this page */" \
    +@@ -163029,7 +177806,9 @@ static int statConnect(
    +   int iDb;
    + 
    +   if( argc>=4 ){
    +-    iDb = sqlite3FindDbName(db, argv[3]);
    ++    Token nm;
    ++    sqlite3TokenInit(&nm, (char*)argv[3]);
    ++    iDb = sqlite3FindDb(db, &nm);
    +     if( iDb<0 ){
    +       *pzErr = sqlite3_mprintf("no such database: %s", argv[3]);
    +       return SQLITE_ERROR;
    +@@ -163040,7 +177819,7 @@ static int statConnect(
    +   rc = sqlite3_declare_vtab(db, VTAB_SCHEMA);
    +   if( rc==SQLITE_OK ){
    +     pTab = (StatTable *)sqlite3_malloc64(sizeof(StatTable));
    +-    if( pTab==0 ) rc = SQLITE_NOMEM;
    ++    if( pTab==0 ) rc = SQLITE_NOMEM_BKPT;
    +   }
    + 
    +   assert( rc==SQLITE_OK || pTab==0 );
    +@@ -163121,7 +177900,7 @@ static int statOpen(sqlite3_vtab *pVTab, sqlite3_vtab_cursor **ppCursor){
    + 
    +   pCsr = (StatCursor *)sqlite3_malloc64(sizeof(StatCursor));
    +   if( pCsr==0 ){
    +-    return SQLITE_NOMEM;
    ++    return SQLITE_NOMEM_BKPT;
    +   }else{
    +     memset(pCsr, 0, sizeof(StatCursor));
    +     pCsr->base.pVtab = pVTab;
    +@@ -163227,7 +178006,7 @@ static int statDecodePage(Btree *pBt, StatPage *p){
    +     nUsable = szPage - sqlite3BtreeGetReserveNoMutex(pBt);
    +     sqlite3BtreeLeave(pBt);
    +     p->aCell = sqlite3_malloc64((p->nCell+1) * sizeof(StatCell));
    +-    if( p->aCell==0 ) return SQLITE_NOMEM;
    ++    if( p->aCell==0 ) return SQLITE_NOMEM_BKPT;
    +     memset(p->aCell, 0, (p->nCell+1) * sizeof(StatCell));
    + 
    +     for(i=0; i<p->nCell; i++){
    +@@ -163260,13 +178039,13 @@ static int statDecodePage(Btree *pBt, StatPage *p){
    +           pCell->nLastOvfl = (nPayload-nLocal) - (nOvfl-1) * (nUsable-4);
    +           pCell->nOvfl = nOvfl;
    +           pCell->aOvfl = sqlite3_malloc64(sizeof(u32)*nOvfl);
    +-          if( pCell->aOvfl==0 ) return SQLITE_NOMEM;
    ++          if( pCell->aOvfl==0 ) return SQLITE_NOMEM_BKPT;
    +           pCell->aOvfl[0] = sqlite3Get4byte(&aData[iOff+nLocal]);
    +           for(j=1; j<nOvfl; j++){
    +             int rc;
    +             u32 iPrev = pCell->aOvfl[j-1];
    +             DbPage *pPg = 0;
    +-            rc = sqlite3PagerGet(sqlite3BtreePager(pBt), iPrev, &pPg);
    ++            rc = sqlite3PagerGet(sqlite3BtreePager(pBt), iPrev, &pPg, 0);
    +             if( rc!=SQLITE_OK ){
    +               assert( pPg==0 );
    +               return rc;
    +@@ -163334,12 +178113,12 @@ statNextRestart:
    +         pCsr->isEof = 1;
    +         return sqlite3_reset(pCsr->pStmt);
    +       }
    +-      rc = sqlite3PagerGet(pPager, iRoot, &pCsr->aPage[0].pPg);
    ++      rc = sqlite3PagerGet(pPager, iRoot, &pCsr->aPage[0].pPg, 0);
    +       pCsr->aPage[0].iPgno = iRoot;
    +       pCsr->aPage[0].iCell = 0;
    +       pCsr->aPage[0].zPath = z = sqlite3_mprintf("/");
    +       pCsr->iPage = 0;
    +-      if( z==0 ) rc = SQLITE_NOMEM;
    ++      if( z==0 ) rc = SQLITE_NOMEM_BKPT;
    +     }else{
    +       pCsr->isEof = 1;
    +       return sqlite3_reset(pCsr->pStmt);
    +@@ -163374,7 +178153,7 @@ statNextRestart:
    +         }
    +         pCell->iOvfl++;
    +         statSizeAndOffset(pCsr);
    +-        return z==0 ? SQLITE_NOMEM : SQLITE_OK;
    ++        return z==0 ? SQLITE_NOMEM_BKPT : SQLITE_OK;
    +       }
    +       if( p->iRightChildPg ) break;
    +       p->iCell++;
    +@@ -163394,11 +178173,11 @@ statNextRestart:
    +     }else{
    +       p[1].iPgno = p->aCell[p->iCell].iChildPg;
    +     }
    +-    rc = sqlite3PagerGet(pPager, p[1].iPgno, &p[1].pPg);
    ++    rc = sqlite3PagerGet(pPager, p[1].iPgno, &p[1].pPg, 0);
    +     p[1].iCell = 0;
    +     p[1].zPath = z = sqlite3_mprintf("%s%.3x/", p->zPath, p->iCell);
    +     p->iCell++;
    +-    if( z==0 ) rc = SQLITE_NOMEM;
    ++    if( z==0 ) rc = SQLITE_NOMEM_BKPT;
    +   }
    + 
    + 
    +@@ -163432,7 +178211,7 @@ statNextRestart:
    +       pCsr->nUnused = p->nUnused;
    +       pCsr->nMxPayload = p->nMxPayload;
    +       pCsr->zPath = z = sqlite3_mprintf("%s", p->zPath);
    +-      if( z==0 ) rc = SQLITE_NOMEM;
    ++      if( z==0 ) rc = SQLITE_NOMEM_BKPT;
    +       nPayload = 0;
    +       for(i=0; i<p->nCell; i++){
    +         nPayload += p->aCell[i].nLocal;
    +@@ -163466,7 +178245,7 @@ static int statFilter(
    +     if( pCsr->iDb<0 ){
    +       sqlite3_free(pCursor->pVtab->zErrMsg);
    +       pCursor->pVtab->zErrMsg = sqlite3_mprintf("no such schema: %s", zDbase);
    +-      return pCursor->pVtab->zErrMsg ? SQLITE_ERROR : SQLITE_NOMEM;
    ++      return pCursor->pVtab->zErrMsg ? SQLITE_ERROR : SQLITE_NOMEM_BKPT;
    +     }
    +   }else{
    +     pCsr->iDb = pTab->iDb;
    +@@ -163480,9 +178259,9 @@ static int statFilter(
    +       "  UNION ALL  "
    +       "SELECT name, rootpage, type"
    +       "  FROM \"%w\".%s WHERE rootpage!=0"
    +-      "  ORDER BY name", pTab->db->aDb[pCsr->iDb].zName, zMaster);
    ++      "  ORDER BY name", pTab->db->aDb[pCsr->iDb].zDbSName, zMaster);
    +   if( zSql==0 ){
    +-    return SQLITE_NOMEM;
    ++    return SQLITE_NOMEM_BKPT;
    +   }else{
    +     rc = sqlite3_prepare_v2(pTab->db, zSql, -1, &pCsr->pStmt, 0);
    +     sqlite3_free(zSql);
    +@@ -163534,7 +178313,7 @@ static int statColumn(
    +     default: {          /* schema */
    +       sqlite3 *db = sqlite3_context_db_handle(ctx);
    +       int iDb = pCsr->iDb;
    +-      sqlite3_result_text(ctx, db->aDb[iDb].zName, -1, SQLITE_STATIC);
    ++      sqlite3_result_text(ctx, db->aDb[iDb].zDbSName, -1, SQLITE_STATIC);
    +       break;
    +     }
    +   }
    +@@ -163572,6 +178351,9 @@ SQLITE_PRIVATE int sqlite3DbstatRegister(sqlite3 *db){
    +     0,                            /* xRollback */
    +     0,                            /* xFindMethod */
    +     0,                            /* xRename */
    ++    0,                            /* xSavepoint */
    ++    0,                            /* xRelease */
    ++    0,                            /* xRollbackTo */
    +   };
    +   return sqlite3_create_module(db, "dbstat", &dbstat_module, 0);
    + }
    +@@ -163580,9 +178362,9 @@ SQLITE_PRIVATE int sqlite3DbstatRegister(sqlite3 *db){ return SQLITE_OK; }
    + #endif /* SQLITE_ENABLE_DBSTAT_VTAB */
    + 
    + /************** End of dbstat.c **********************************************/
    +-/************** Begin file json1.c *******************************************/
    ++/************** Begin file dbpage.c ******************************************/
    + /*
    +-** 2015-08-12
    ++** 2017-10-11
    + **
    + ** The author disclaims copyright to this source code.  In place of
    + ** a legal notice, here is a blessing:
    +@@ -163593,710 +178375,6002 @@ SQLITE_PRIVATE int sqlite3DbstatRegister(sqlite3 *db){ return SQLITE_OK; }
    + **
    + ******************************************************************************
    + **
    +-** This SQLite extension implements JSON functions.  The interface is
    +-** modeled after MySQL JSON functions:
    ++** This file contains an implementation of the "sqlite_dbpage" virtual table.
    + **
    +-**     https://dev.mysql.com/doc/refman/5.7/en/json.html
    ++** The sqlite_dbpage virtual table is used to read or write whole raw
    ++** pages of the database file.  The pager interface is used so that 
    ++** uncommitted changes and changes recorded in the WAL file are correctly
    ++** retrieved.
    + **
    +-** For the time being, all JSON is stored as pure text.  (We might add
    +-** a JSONB type in the future which stores a binary encoding of JSON in
    +-** a BLOB, but there is no support for JSONB in the current implementation.
    +-** This implementation parses JSON text at 250 MB/s, so it is hard to see
    +-** how JSONB might improve on that.)
    ++** Usage example:
    ++**
    ++**    SELECT data FROM sqlite_dbpage('aux1') WHERE pgno=123;
    ++**
    ++** This is an eponymous virtual table so it does not need to be created before
    ++** use.  The optional argument to the sqlite_dbpage() table name is the
    ++** schema for the database file that is to be read.  The default schema is
    ++** "main".
    ++**
    ++** The data field of sqlite_dbpage table can be updated.  The new
    ++** value must be a BLOB which is the correct page size, otherwise the
    ++** update fails.  Rows may not be deleted or inserted.
    + */
    +-#if !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_JSON1)
    +-#if !defined(_SQLITEINT_H_)
    +-/* #include "sqlite3ext.h" */
    +-#endif
    +-SQLITE_EXTENSION_INIT1
    +-/* #include <assert.h> */
    +-/* #include <string.h> */
    +-/* #include <stdlib.h> */
    +-/* #include <stdarg.h> */
    + 
    +-#define UNUSED_PARAM(X)  (void)(X)
    +-
    +-#ifndef LARGEST_INT64
    +-# define LARGEST_INT64  (0xffffffff|(((sqlite3_int64)0x7fffffff)<<32))
    +-# define SMALLEST_INT64 (((sqlite3_int64)-1) - LARGEST_INT64)
    +-#endif
    ++/* #include "sqliteInt.h"   ** Requires access to internal data structures ** */
    ++#if (defined(SQLITE_ENABLE_DBPAGE_VTAB) || defined(SQLITE_TEST)) \
    ++    && !defined(SQLITE_OMIT_VIRTUALTABLE)
    + 
    +-/*
    +-** Versions of isspace(), isalnum() and isdigit() to which it is safe
    +-** to pass signed char values.
    +-*/
    +-#ifdef sqlite3Isdigit
    +-   /* Use the SQLite core versions if this routine is part of the
    +-   ** SQLite amalgamation */
    +-#  define safe_isdigit(x) sqlite3Isdigit(x)
    +-#  define safe_isalnum(x) sqlite3Isalnum(x)
    +-#else
    +-   /* Use the standard library for separate compilation */
    +-#include <ctype.h>  /* amalgamator: keep */
    +-#  define safe_isdigit(x) isdigit((unsigned char)(x))
    +-#  define safe_isalnum(x) isalnum((unsigned char)(x))
    +-#endif
    ++typedef struct DbpageTable DbpageTable;
    ++typedef struct DbpageCursor DbpageCursor;
    + 
    +-/*
    +-** Growing our own isspace() routine this way is twice as fast as
    +-** the library isspace() function, resulting in a 7% overall performance
    +-** increase for the parser.  (Ubuntu14.10 gcc 4.8.4 x64 with -Os).
    +-*/
    +-static const char jsonIsSpace[] = {
    +-  0, 0, 0, 0, 0, 0, 0, 0,     0, 1, 1, 0, 0, 1, 0, 0,
    +-  0, 0, 0, 0, 0, 0, 0, 0,     0, 0, 0, 0, 0, 0, 0, 0,
    +-  1, 0, 0, 0, 0, 0, 0, 0,     0, 0, 0, 0, 0, 0, 0, 0,
    +-  0, 0, 0, 0, 0, 0, 0, 0,     0, 0, 0, 0, 0, 0, 0, 0,
    +-  0, 0, 0, 0, 0, 0, 0, 0,     0, 0, 0, 0, 0, 0, 0, 0,
    +-  0, 0, 0, 0, 0, 0, 0, 0,     0, 0, 0, 0, 0, 0, 0, 0,
    +-  0, 0, 0, 0, 0, 0, 0, 0,     0, 0, 0, 0, 0, 0, 0, 0,
    +-  0, 0, 0, 0, 0, 0, 0, 0,     0, 0, 0, 0, 0, 0, 0, 0,
    +-  0, 0, 0, 0, 0, 0, 0, 0,     0, 0, 0, 0, 0, 0, 0, 0,
    +-  0, 0, 0, 0, 0, 0, 0, 0,     0, 0, 0, 0, 0, 0, 0, 0,
    +-  0, 0, 0, 0, 0, 0, 0, 0,     0, 0, 0, 0, 0, 0, 0, 0,
    +-  0, 0, 0, 0, 0, 0, 0, 0,     0, 0, 0, 0, 0, 0, 0, 0,
    +-  0, 0, 0, 0, 0, 0, 0, 0,     0, 0, 0, 0, 0, 0, 0, 0,
    +-  0, 0, 0, 0, 0, 0, 0, 0,     0, 0, 0, 0, 0, 0, 0, 0,
    +-  0, 0, 0, 0, 0, 0, 0, 0,     0, 0, 0, 0, 0, 0, 0, 0,
    +-  0, 0, 0, 0, 0, 0, 0, 0,     0, 0, 0, 0, 0, 0, 0, 0,
    ++struct DbpageCursor {
    ++  sqlite3_vtab_cursor base;       /* Base class.  Must be first */
    ++  int pgno;                       /* Current page number */
    ++  int mxPgno;                     /* Last page to visit on this scan */
    ++  Pager *pPager;                  /* Pager being read/written */
    ++  DbPage *pPage1;                 /* Page 1 of the database */
    ++  int iDb;                        /* Index of database to analyze */
    ++  int szPage;                     /* Size of each page in bytes */
    + };
    +-#define safe_isspace(x) (jsonIsSpace[(unsigned char)x])
    +-
    +-#ifndef SQLITE_AMALGAMATION
    +-  /* Unsigned integer types.  These are already defined in the sqliteInt.h,
    +-  ** but the definitions need to be repeated for separate compilation. */
    +-  typedef sqlite3_uint64 u64;
    +-  typedef unsigned int u32;
    +-  typedef unsigned char u8;
    +-#endif
    + 
    +-/* Objects */
    +-typedef struct JsonString JsonString;
    +-typedef struct JsonNode JsonNode;
    +-typedef struct JsonParse JsonParse;
    +-
    +-/* An instance of this object represents a JSON string
    +-** under construction.  Really, this is a generic string accumulator
    +-** that can be and is used to create strings other than JSON.
    +-*/
    +-struct JsonString {
    +-  sqlite3_context *pCtx;   /* Function context - put error messages here */
    +-  char *zBuf;              /* Append JSON content here */
    +-  u64 nAlloc;              /* Bytes of storage available in zBuf[] */
    +-  u64 nUsed;               /* Bytes of zBuf[] currently used */
    +-  u8 bStatic;              /* True if zBuf is static space */
    +-  u8 bErr;                 /* True if an error has been encountered */
    +-  char zSpace[100];        /* Initial static space */
    ++struct DbpageTable {
    ++  sqlite3_vtab base;              /* Base class.  Must be first */
    ++  sqlite3 *db;                    /* The database */
    + };
    + 
    +-/* JSON type values
    +-*/
    +-#define JSON_NULL     0
    +-#define JSON_TRUE     1
    +-#define JSON_FALSE    2
    +-#define JSON_INT      3
    +-#define JSON_REAL     4
    +-#define JSON_STRING   5
    +-#define JSON_ARRAY    6
    +-#define JSON_OBJECT   7
    ++/* Columns */
    ++#define DBPAGE_COLUMN_PGNO    0
    ++#define DBPAGE_COLUMN_DATA    1
    ++#define DBPAGE_COLUMN_SCHEMA  2
    + 
    +-/* The "subtype" set for JSON values */
    +-#define JSON_SUBTYPE  74    /* Ascii for "J" */
    + 
    +-/*
    +-** Names of the various JSON types:
    +-*/
    +-static const char * const jsonType[] = {
    +-  "null", "true", "false", "integer", "real", "text", "array", "object"
    +-};
    + 
    +-/* Bit values for the JsonNode.jnFlag field
    ++/*
    ++** Connect to or create a dbpagevfs virtual table.
    + */
    +-#define JNODE_RAW     0x01         /* Content is raw, not JSON encoded */
    +-#define JNODE_ESCAPE  0x02         /* Content is text with \ escapes */
    +-#define JNODE_REMOVE  0x04         /* Do not output */
    +-#define JNODE_REPLACE 0x08         /* Replace with JsonNode.iVal */
    +-#define JNODE_APPEND  0x10         /* More ARRAY/OBJECT entries at u.iAppend */
    +-#define JNODE_LABEL   0x20         /* Is a label of an object */
    +-
    ++static int dbpageConnect(
    ++  sqlite3 *db,
    ++  void *pAux,
    ++  int argc, const char *const*argv,
    ++  sqlite3_vtab **ppVtab,
    ++  char **pzErr
    ++){
    ++  DbpageTable *pTab = 0;
    ++  int rc = SQLITE_OK;
    + 
    +-/* A single node of parsed JSON
    +-*/
    +-struct JsonNode {
    +-  u8 eType;              /* One of the JSON_ type values */
    +-  u8 jnFlags;            /* JNODE flags */
    +-  u8 iVal;               /* Replacement value when JNODE_REPLACE */
    +-  u32 n;                 /* Bytes of content, or number of sub-nodes */
    +-  union {
    +-    const char *zJContent; /* Content for INT, REAL, and STRING */
    +-    u32 iAppend;           /* More terms for ARRAY and OBJECT */
    +-    u32 iKey;              /* Key for ARRAY objects in json_tree() */
    +-  } u;
    +-};
    ++  rc = sqlite3_declare_vtab(db, 
    ++          "CREATE TABLE x(pgno INTEGER PRIMARY KEY, data BLOB, schema HIDDEN)");
    ++  if( rc==SQLITE_OK ){
    ++    pTab = (DbpageTable *)sqlite3_malloc64(sizeof(DbpageTable));
    ++    if( pTab==0 ) rc = SQLITE_NOMEM_BKPT;
    ++  }
    + 
    +-/* A completely parsed JSON string
    +-*/
    +-struct JsonParse {
    +-  u32 nNode;         /* Number of slots of aNode[] used */
    +-  u32 nAlloc;        /* Number of slots of aNode[] allocated */
    +-  JsonNode *aNode;   /* Array of nodes containing the parse */
    +-  const char *zJson; /* Original JSON string */
    +-  u32 *aUp;          /* Index of parent of each node */
    +-  u8 oom;            /* Set to true if out of memory */
    +-  u8 nErr;           /* Number of errors seen */
    +-};
    ++  assert( rc==SQLITE_OK || pTab==0 );
    ++  if( rc==SQLITE_OK ){
    ++    memset(pTab, 0, sizeof(DbpageTable));
    ++    pTab->db = db;
    ++  }
    + 
    +-/**************************************************************************
    +-** Utility routines for dealing with JsonString objects
    +-**************************************************************************/
    ++  *ppVtab = (sqlite3_vtab*)pTab;
    ++  return rc;
    ++}
    + 
    +-/* Set the JsonString object to an empty string
    ++/*
    ++** Disconnect from or destroy a dbpagevfs virtual table.
    + */
    +-static void jsonZero(JsonString *p){
    +-  p->zBuf = p->zSpace;
    +-  p->nAlloc = sizeof(p->zSpace);
    +-  p->nUsed = 0;
    +-  p->bStatic = 1;
    ++static int dbpageDisconnect(sqlite3_vtab *pVtab){
    ++  sqlite3_free(pVtab);
    ++  return SQLITE_OK;
    + }
    + 
    +-/* Initialize the JsonString object
    ++/*
    ++** idxNum:
    ++**
    ++**     0     schema=main, full table scan
    ++**     1     schema=main, pgno=?1
    ++**     2     schema=?1, full table scan
    ++**     3     schema=?1, pgno=?2
    + */
    +-static void jsonInit(JsonString *p, sqlite3_context *pCtx){
    +-  p->pCtx = pCtx;
    +-  p->bErr = 0;
    +-  jsonZero(p);
    +-}
    ++static int dbpageBestIndex(sqlite3_vtab *tab, sqlite3_index_info *pIdxInfo){
    ++  int i;
    ++  int iPlan = 0;
    + 
    ++  /* If there is a schema= constraint, it must be honored.  Report a
    ++  ** ridiculously large estimated cost if the schema= constraint is
    ++  ** unavailable
    ++  */
    ++  for(i=0; i<pIdxInfo->nConstraint; i++){
    ++    struct sqlite3_index_constraint *p = &pIdxInfo->aConstraint[i];
    ++    if( p->iColumn!=DBPAGE_COLUMN_SCHEMA ) continue;
    ++    if( p->op!=SQLITE_INDEX_CONSTRAINT_EQ ) continue;
    ++    if( !p->usable ){
    ++      /* No solution.  Use the default SQLITE_BIG_DBL cost */
    ++      pIdxInfo->estimatedRows = 0x7fffffff;
    ++      return SQLITE_OK;
    ++    }
    ++    iPlan = 2;
    ++    pIdxInfo->aConstraintUsage[i].argvIndex = 1;
    ++    pIdxInfo->aConstraintUsage[i].omit = 1;
    ++    break;
    ++  }
    + 
    +-/* Free all allocated memory and reset the JsonString object back to its
    +-** initial state.
    +-*/
    +-static void jsonReset(JsonString *p){
    +-  if( !p->bStatic ) sqlite3_free(p->zBuf);
    +-  jsonZero(p);
    +-}
    ++  /* If we reach this point, it means that either there is no schema=
    ++  ** constraint (in which case we use the "main" schema) or else the
    ++  ** schema constraint was accepted.  Lower the estimated cost accordingly
    ++  */
    ++  pIdxInfo->estimatedCost = 1.0e6;
    + 
    ++  /* Check for constraints against pgno */
    ++  for(i=0; i<pIdxInfo->nConstraint; i++){
    ++    struct sqlite3_index_constraint *p = &pIdxInfo->aConstraint[i];
    ++    if( p->usable && p->iColumn<=0 && p->op==SQLITE_INDEX_CONSTRAINT_EQ ){
    ++      pIdxInfo->estimatedRows = 1;
    ++      pIdxInfo->idxFlags = SQLITE_INDEX_SCAN_UNIQUE;
    ++      pIdxInfo->estimatedCost = 1.0;
    ++      pIdxInfo->aConstraintUsage[i].argvIndex = iPlan ? 2 : 1;
    ++      pIdxInfo->aConstraintUsage[i].omit = 1;
    ++      iPlan |= 1;
    ++      break;
    ++    }
    ++  }
    ++  pIdxInfo->idxNum = iPlan;
    + 
    +-/* Report an out-of-memory (OOM) condition 
    +-*/
    +-static void jsonOom(JsonString *p){
    +-  p->bErr = 1;
    +-  sqlite3_result_error_nomem(p->pCtx);
    +-  jsonReset(p);
    ++  if( pIdxInfo->nOrderBy>=1
    ++   && pIdxInfo->aOrderBy[0].iColumn<=0
    ++   && pIdxInfo->aOrderBy[0].desc==0
    ++  ){
    ++    pIdxInfo->orderByConsumed = 1;
    ++  }
    ++  return SQLITE_OK;
    + }
    + 
    +-/* Enlarge pJson->zBuf so that it can hold at least N more bytes.
    +-** Return zero on success.  Return non-zero on an OOM error
    ++/*
    ++** Open a new dbpagevfs cursor.
    + */
    +-static int jsonGrow(JsonString *p, u32 N){
    +-  u64 nTotal = N<p->nAlloc ? p->nAlloc*2 : p->nAlloc+N+10;
    +-  char *zNew;
    +-  if( p->bStatic ){
    +-    if( p->bErr ) return 1;
    +-    zNew = sqlite3_malloc64(nTotal);
    +-    if( zNew==0 ){
    +-      jsonOom(p);
    +-      return SQLITE_NOMEM;
    +-    }
    +-    memcpy(zNew, p->zBuf, (size_t)p->nUsed);
    +-    p->zBuf = zNew;
    +-    p->bStatic = 0;
    ++static int dbpageOpen(sqlite3_vtab *pVTab, sqlite3_vtab_cursor **ppCursor){
    ++  DbpageCursor *pCsr;
    ++
    ++  pCsr = (DbpageCursor *)sqlite3_malloc64(sizeof(DbpageCursor));
    ++  if( pCsr==0 ){
    ++    return SQLITE_NOMEM_BKPT;
    +   }else{
    +-    zNew = sqlite3_realloc64(p->zBuf, nTotal);
    +-    if( zNew==0 ){
    +-      jsonOom(p);
    +-      return SQLITE_NOMEM;
    +-    }
    +-    p->zBuf = zNew;
    ++    memset(pCsr, 0, sizeof(DbpageCursor));
    ++    pCsr->base.pVtab = pVTab;
    ++    pCsr->pgno = -1;
    +   }
    +-  p->nAlloc = nTotal;
    ++
    ++  *ppCursor = (sqlite3_vtab_cursor *)pCsr;
    +   return SQLITE_OK;
    + }
    + 
    +-/* Append N bytes from zIn onto the end of the JsonString string.
    ++/*
    ++** Close a dbpagevfs cursor.
    + */
    +-static void jsonAppendRaw(JsonString *p, const char *zIn, u32 N){
    +-  if( (N+p->nUsed >= p->nAlloc) && jsonGrow(p,N)!=0 ) return;
    +-  memcpy(p->zBuf+p->nUsed, zIn, N);
    +-  p->nUsed += N;
    ++static int dbpageClose(sqlite3_vtab_cursor *pCursor){
    ++  DbpageCursor *pCsr = (DbpageCursor *)pCursor;
    ++  if( pCsr->pPage1 ) sqlite3PagerUnrefPageOne(pCsr->pPage1);
    ++  sqlite3_free(pCsr);
    ++  return SQLITE_OK;
    + }
    + 
    +-/* Append formatted text (not to exceed N bytes) to the JsonString.
    ++/*
    ++** Move a dbpagevfs cursor to the next entry in the file.
    + */
    +-static void jsonPrintf(int N, JsonString *p, const char *zFormat, ...){
    +-  va_list ap;
    +-  if( (p->nUsed + N >= p->nAlloc) && jsonGrow(p, N) ) return;
    +-  va_start(ap, zFormat);
    +-  sqlite3_vsnprintf(N, p->zBuf+p->nUsed, zFormat, ap);
    +-  va_end(ap);
    +-  p->nUsed += (int)strlen(p->zBuf+p->nUsed);
    ++static int dbpageNext(sqlite3_vtab_cursor *pCursor){
    ++  int rc = SQLITE_OK;
    ++  DbpageCursor *pCsr = (DbpageCursor *)pCursor;
    ++  pCsr->pgno++;
    ++  return rc;
    + }
    + 
    +-/* Append a single character
    +-*/
    +-static void jsonAppendChar(JsonString *p, char c){
    +-  if( p->nUsed>=p->nAlloc && jsonGrow(p,1)!=0 ) return;
    +-  p->zBuf[p->nUsed++] = c;
    ++static int dbpageEof(sqlite3_vtab_cursor *pCursor){
    ++  DbpageCursor *pCsr = (DbpageCursor *)pCursor;
    ++  return pCsr->pgno > pCsr->mxPgno;
    + }
    + 
    +-/* Append a comma separator to the output buffer, if the previous
    +-** character is not '[' or '{'.
    ++/*
    ++** idxNum:
    ++**
    ++**     0     schema=main, full table scan
    ++**     1     schema=main, pgno=?1
    ++**     2     schema=?1, full table scan
    ++**     3     schema=?1, pgno=?2
    ++**
    ++** idxStr is not used
    + */
    +-static void jsonAppendSeparator(JsonString *p){
    +-  char c;
    +-  if( p->nUsed==0 ) return;
    +-  c = p->zBuf[p->nUsed-1];
    +-  if( c!='[' && c!='{' ) jsonAppendChar(p, ',');
    +-}
    ++static int dbpageFilter(
    ++  sqlite3_vtab_cursor *pCursor, 
    ++  int idxNum, const char *idxStr,
    ++  int argc, sqlite3_value **argv
    ++){
    ++  DbpageCursor *pCsr = (DbpageCursor *)pCursor;
    ++  DbpageTable *pTab = (DbpageTable *)pCursor->pVtab;
    ++  int rc;
    ++  sqlite3 *db = pTab->db;
    ++  Btree *pBt;
    + 
    +-/* Append the N-byte string in zIn to the end of the JsonString string
    +-** under construction.  Enclose the string in "..." and escape
    +-** any double-quotes or backslash characters contained within the
    +-** string.
    +-*/
    +-static void jsonAppendString(JsonString *p, const char *zIn, u32 N){
    +-  u32 i;
    +-  if( (N+p->nUsed+2 >= p->nAlloc) && jsonGrow(p,N+2)!=0 ) return;
    +-  p->zBuf[p->nUsed++] = '"';
    +-  for(i=0; i<N; i++){
    +-    char c = zIn[i];
    +-    if( c=='"' || c=='\\' ){
    +-      if( (p->nUsed+N+3-i > p->nAlloc) && jsonGrow(p,N+3-i)!=0 ) return;
    +-      p->zBuf[p->nUsed++] = '\\';
    ++  /* Default setting is no rows of result */
    ++  pCsr->pgno = 1; 
    ++  pCsr->mxPgno = 0;
    ++
    ++  if( idxNum & 2 ){
    ++    const char *zSchema;
    ++    assert( argc>=1 );
    ++    zSchema = (const char*)sqlite3_value_text(argv[0]);
    ++    pCsr->iDb = sqlite3FindDbName(db, zSchema);
    ++    if( pCsr->iDb<0 ) return SQLITE_OK;
    ++  }else{
    ++    pCsr->iDb = 0;
    ++  }
    ++  pBt = db->aDb[pCsr->iDb].pBt;
    ++  if( pBt==0 ) return SQLITE_OK;
    ++  pCsr->pPager = sqlite3BtreePager(pBt);
    ++  pCsr->szPage = sqlite3BtreeGetPageSize(pBt);
    ++  pCsr->mxPgno = sqlite3BtreeLastPage(pBt);
    ++  if( idxNum & 1 ){
    ++    assert( argc>(idxNum>>1) );
    ++    pCsr->pgno = sqlite3_value_int(argv[idxNum>>1]);
    ++    if( pCsr->pgno<1 || pCsr->pgno>pCsr->mxPgno ){
    ++      pCsr->pgno = 1;
    ++      pCsr->mxPgno = 0;
    ++    }else{
    ++      pCsr->mxPgno = pCsr->pgno;
    +     }
    +-    p->zBuf[p->nUsed++] = c;
    ++  }else{
    ++    assert( pCsr->pgno==1 );
    +   }
    +-  p->zBuf[p->nUsed++] = '"';
    +-  assert( p->nUsed<p->nAlloc );
    ++  if( pCsr->pPage1 ) sqlite3PagerUnrefPageOne(pCsr->pPage1);
    ++  rc = sqlite3PagerGet(pCsr->pPager, 1, &pCsr->pPage1, 0);
    ++  return rc;
    + }
    + 
    +-/*
    +-** Append a function parameter value to the JSON string under 
    +-** construction.
    +-*/
    +-static void jsonAppendValue(
    +-  JsonString *p,                 /* Append to this JSON string */
    +-  sqlite3_value *pValue          /* Value to append */
    ++static int dbpageColumn(
    ++  sqlite3_vtab_cursor *pCursor, 
    ++  sqlite3_context *ctx, 
    ++  int i
    + ){
    +-  switch( sqlite3_value_type(pValue) ){
    +-    case SQLITE_NULL: {
    +-      jsonAppendRaw(p, "null", 4);
    +-      break;
    +-    }
    +-    case SQLITE_INTEGER:
    +-    case SQLITE_FLOAT: {
    +-      const char *z = (const char*)sqlite3_value_text(pValue);
    +-      u32 n = (u32)sqlite3_value_bytes(pValue);
    +-      jsonAppendRaw(p, z, n);
    ++  DbpageCursor *pCsr = (DbpageCursor *)pCursor;
    ++  int rc = SQLITE_OK;
    ++  switch( i ){
    ++    case 0: {           /* pgno */
    ++      sqlite3_result_int(ctx, pCsr->pgno);
    +       break;
    +     }
    +-    case SQLITE_TEXT: {
    +-      const char *z = (const char*)sqlite3_value_text(pValue);
    +-      u32 n = (u32)sqlite3_value_bytes(pValue);
    +-      if( sqlite3_value_subtype(pValue)==JSON_SUBTYPE ){
    +-        jsonAppendRaw(p, z, n);
    +-      }else{
    +-        jsonAppendString(p, z, n);
    ++    case 1: {           /* data */
    ++      DbPage *pDbPage = 0;
    ++      rc = sqlite3PagerGet(pCsr->pPager, pCsr->pgno, (DbPage**)&pDbPage, 0);
    ++      if( rc==SQLITE_OK ){
    ++        sqlite3_result_blob(ctx, sqlite3PagerGetData(pDbPage), pCsr->szPage,
    ++                            SQLITE_TRANSIENT);
    +       }
    ++      sqlite3PagerUnref(pDbPage);
    +       break;
    +     }
    +-    default: {
    +-      if( p->bErr==0 ){
    +-        sqlite3_result_error(p->pCtx, "JSON cannot hold BLOB values", -1);
    +-        p->bErr = 1;
    +-        jsonReset(p);
    +-      }
    ++    default: {          /* schema */
    ++      sqlite3 *db = sqlite3_context_db_handle(ctx);
    ++      sqlite3_result_text(ctx, db->aDb[pCsr->iDb].zDbSName, -1, SQLITE_STATIC);
    +       break;
    +     }
    +   }
    ++  return SQLITE_OK;
    + }
    + 
    ++static int dbpageRowid(sqlite3_vtab_cursor *pCursor, sqlite_int64 *pRowid){
    ++  DbpageCursor *pCsr = (DbpageCursor *)pCursor;
    ++  *pRowid = pCsr->pgno;
    ++  return SQLITE_OK;
    ++}
    + 
    +-/* Make the JSON in p the result of the SQL function.
    ++static int dbpageUpdate(
    ++  sqlite3_vtab *pVtab,
    ++  int argc,
    ++  sqlite3_value **argv,
    ++  sqlite_int64 *pRowid
    ++){
    ++  DbpageTable *pTab = (DbpageTable *)pVtab;
    ++  Pgno pgno;
    ++  DbPage *pDbPage = 0;
    ++  int rc = SQLITE_OK;
    ++  char *zErr = 0;
    ++  const char *zSchema;
    ++  int iDb;
    ++  Btree *pBt;
    ++  Pager *pPager;
    ++  int szPage;
    ++
    ++  if( argc==1 ){
    ++    zErr = "cannot delete";
    ++    goto update_fail;
    ++  }
    ++  pgno = sqlite3_value_int(argv[0]);
    ++  if( (Pgno)sqlite3_value_int(argv[1])!=pgno ){
    ++    zErr = "cannot insert";
    ++    goto update_fail;
    ++  }
    ++  zSchema = (const char*)sqlite3_value_text(argv[4]);
    ++  iDb = zSchema ? sqlite3FindDbName(pTab->db, zSchema) : -1;
    ++  if( iDb<0 ){
    ++    zErr = "no such schema";
    ++    goto update_fail;
    ++  }
    ++  pBt = pTab->db->aDb[iDb].pBt;
    ++  if( pgno<1 || pBt==0 || pgno>(int)sqlite3BtreeLastPage(pBt) ){
    ++    zErr = "bad page number";
    ++    goto update_fail;
    ++  }
    ++  szPage = sqlite3BtreeGetPageSize(pBt);
    ++  if( sqlite3_value_type(argv[3])!=SQLITE_BLOB 
    ++   || sqlite3_value_bytes(argv[3])!=szPage
    ++  ){
    ++    zErr = "bad page value";
    ++    goto update_fail;
    ++  }
    ++  pPager = sqlite3BtreePager(pBt);
    ++  rc = sqlite3PagerGet(pPager, pgno, (DbPage**)&pDbPage, 0);
    ++  if( rc==SQLITE_OK ){
    ++    rc = sqlite3PagerWrite(pDbPage);
    ++    if( rc==SQLITE_OK ){
    ++      memcpy(sqlite3PagerGetData(pDbPage),
    ++             sqlite3_value_blob(argv[3]),
    ++             szPage);
    ++    }
    ++  }
    ++  sqlite3PagerUnref(pDbPage);
    ++  return rc;
    ++
    ++update_fail:
    ++  sqlite3_free(pVtab->zErrMsg);
    ++  pVtab->zErrMsg = sqlite3_mprintf("%s", zErr);
    ++  return SQLITE_ERROR;
    ++}
    ++
    ++/* Since we do not know in advance which database files will be
    ++** written by the sqlite_dbpage virtual table, start a write transaction
    ++** on them all.
    + */
    +-static void jsonResult(JsonString *p){
    +-  if( p->bErr==0 ){
    +-    sqlite3_result_text64(p->pCtx, p->zBuf, p->nUsed, 
    +-                          p->bStatic ? SQLITE_TRANSIENT : sqlite3_free,
    +-                          SQLITE_UTF8);
    +-    jsonZero(p);
    ++static int dbpageBegin(sqlite3_vtab *pVtab){
    ++  DbpageTable *pTab = (DbpageTable *)pVtab;
    ++  sqlite3 *db = pTab->db;
    ++  int i;
    ++  for(i=0; i<db->nDb; i++){
    ++    Btree *pBt = db->aDb[i].pBt;
    ++    if( pBt ) sqlite3BtreeBeginTrans(pBt, 1);
    +   }
    +-  assert( p->bStatic );
    ++  return SQLITE_OK;
    + }
    + 
    +-/**************************************************************************
    +-** Utility routines for dealing with JsonNode and JsonParse objects
    +-**************************************************************************/
    + 
    + /*
    +-** Return the number of consecutive JsonNode slots need to represent
    +-** the parsed JSON at pNode.  The minimum answer is 1.  For ARRAY and
    +-** OBJECT types, the number might be larger.
    ++** Invoke this routine to register the "dbpage" virtual table module
    ++*/
    ++SQLITE_PRIVATE int sqlite3DbpageRegister(sqlite3 *db){
    ++  static sqlite3_module dbpage_module = {
    ++    0,                            /* iVersion */
    ++    dbpageConnect,                /* xCreate */
    ++    dbpageConnect,                /* xConnect */
    ++    dbpageBestIndex,              /* xBestIndex */
    ++    dbpageDisconnect,             /* xDisconnect */
    ++    dbpageDisconnect,             /* xDestroy */
    ++    dbpageOpen,                   /* xOpen - open a cursor */
    ++    dbpageClose,                  /* xClose - close a cursor */
    ++    dbpageFilter,                 /* xFilter - configure scan constraints */
    ++    dbpageNext,                   /* xNext - advance a cursor */
    ++    dbpageEof,                    /* xEof - check for end of scan */
    ++    dbpageColumn,                 /* xColumn - read data */
    ++    dbpageRowid,                  /* xRowid - read data */
    ++    dbpageUpdate,                 /* xUpdate */
    ++    dbpageBegin,                  /* xBegin */
    ++    0,                            /* xSync */
    ++    0,                            /* xCommit */
    ++    0,                            /* xRollback */
    ++    0,                            /* xFindMethod */
    ++    0,                            /* xRename */
    ++    0,                            /* xSavepoint */
    ++    0,                            /* xRelease */
    ++    0,                            /* xRollbackTo */
    ++  };
    ++  return sqlite3_create_module(db, "sqlite_dbpage", &dbpage_module, 0);
    ++}
    ++#elif defined(SQLITE_ENABLE_DBPAGE_VTAB)
    ++SQLITE_PRIVATE int sqlite3DbpageRegister(sqlite3 *db){ return SQLITE_OK; }
    ++#endif /* SQLITE_ENABLE_DBSTAT_VTAB */
    ++
    ++/************** End of dbpage.c **********************************************/
    ++/************** Begin file sqlite3session.c **********************************/
    ++
    ++#if defined(SQLITE_ENABLE_SESSION) && defined(SQLITE_ENABLE_PREUPDATE_HOOK)
    ++/* #include "sqlite3session.h" */
    ++/* #include <assert.h> */
    ++/* #include <string.h> */
    ++
    ++#ifndef SQLITE_AMALGAMATION
    ++/* # include "sqliteInt.h" */
    ++/* # include "vdbeInt.h" */
    ++#endif
    ++
    ++typedef struct SessionTable SessionTable;
    ++typedef struct SessionChange SessionChange;
    ++typedef struct SessionBuffer SessionBuffer;
    ++typedef struct SessionInput SessionInput;
    ++
    ++/*
    ++** Minimum chunk size used by streaming versions of functions.
    ++*/
    ++#ifndef SESSIONS_STRM_CHUNK_SIZE
    ++# ifdef SQLITE_TEST
    ++#   define SESSIONS_STRM_CHUNK_SIZE 64
    ++# else
    ++#   define SESSIONS_STRM_CHUNK_SIZE 1024
    ++# endif
    ++#endif
    ++
    ++typedef struct SessionHook SessionHook;
    ++struct SessionHook {
    ++  void *pCtx;
    ++  int (*xOld)(void*,int,sqlite3_value**);
    ++  int (*xNew)(void*,int,sqlite3_value**);
    ++  int (*xCount)(void*);
    ++  int (*xDepth)(void*);
    ++};
    ++
    ++/*
    ++** Session handle structure.
    ++*/
    ++struct sqlite3_session {
    ++  sqlite3 *db;                    /* Database handle session is attached to */
    ++  char *zDb;                      /* Name of database session is attached to */
    ++  int bEnable;                    /* True if currently recording */
    ++  int bIndirect;                  /* True if all changes are indirect */
    ++  int bAutoAttach;                /* True to auto-attach tables */
    ++  int rc;                         /* Non-zero if an error has occurred */
    ++  void *pFilterCtx;               /* First argument to pass to xTableFilter */
    ++  int (*xTableFilter)(void *pCtx, const char *zTab);
    ++  sqlite3_value *pZeroBlob;       /* Value containing X'' */
    ++  sqlite3_session *pNext;         /* Next session object on same db. */
    ++  SessionTable *pTable;           /* List of attached tables */
    ++  SessionHook hook;               /* APIs to grab new and old data with */
    ++};
    ++
    ++/*
    ++** Instances of this structure are used to build strings or binary records.
    ++*/
    ++struct SessionBuffer {
    ++  u8 *aBuf;                       /* Pointer to changeset buffer */
    ++  int nBuf;                       /* Size of buffer aBuf */
    ++  int nAlloc;                     /* Size of allocation containing aBuf */
    ++};
    ++
    ++/*
    ++** An object of this type is used internally as an abstraction for 
    ++** input data. Input data may be supplied either as a single large buffer
    ++** (e.g. sqlite3changeset_start()) or using a stream function (e.g.
    ++**  sqlite3changeset_start_strm()).
    ++*/
    ++struct SessionInput {
    ++  int bNoDiscard;                 /* If true, discard no data */
    ++  int iCurrent;                   /* Offset in aData[] of current change */
    ++  int iNext;                      /* Offset in aData[] of next change */
    ++  u8 *aData;                      /* Pointer to buffer containing changeset */
    ++  int nData;                      /* Number of bytes in aData */
    ++
    ++  SessionBuffer buf;              /* Current read buffer */
    ++  int (*xInput)(void*, void*, int*);        /* Input stream call (or NULL) */
    ++  void *pIn;                                /* First argument to xInput */
    ++  int bEof;                       /* Set to true after xInput finished */
    ++};
    ++
    ++/*
    ++** Structure for changeset iterators.
    ++*/
    ++struct sqlite3_changeset_iter {
    ++  SessionInput in;                /* Input buffer or stream */
    ++  SessionBuffer tblhdr;           /* Buffer to hold apValue/zTab/abPK/ */
    ++  int bPatchset;                  /* True if this is a patchset */
    ++  int rc;                         /* Iterator error code */
    ++  sqlite3_stmt *pConflict;        /* Points to conflicting row, if any */
    ++  char *zTab;                     /* Current table */
    ++  int nCol;                       /* Number of columns in zTab */
    ++  int op;                         /* Current operation */
    ++  int bIndirect;                  /* True if current change was indirect */
    ++  u8 *abPK;                       /* Primary key array */
    ++  sqlite3_value **apValue;        /* old.* and new.* values */
    ++};
    ++
    ++/*
    ++** Each session object maintains a set of the following structures, one
    ++** for each table the session object is monitoring. The structures are
    ++** stored in a linked list starting at sqlite3_session.pTable.
    + **
    +-** Appended elements are not counted.  The value returned is the number
    +-** by which the JsonNode counter should increment in order to go to the
    +-** next peer value.
    ++** The keys of the SessionTable.aChange[] hash table are all rows that have
    ++** been modified in any way since the session object was attached to the
    ++** table.
    ++**
    ++** The data associated with each hash-table entry is a structure containing
    ++** a subset of the initial values that the modified row contained at the
    ++** start of the session. Or no initial values if the row was inserted.
    ++*/
    ++struct SessionTable {
    ++  SessionTable *pNext;
    ++  char *zName;                    /* Local name of table */
    ++  int nCol;                       /* Number of columns in table zName */
    ++  int bStat1;                     /* True if this is sqlite_stat1 */
    ++  const char **azCol;             /* Column names */
    ++  u8 *abPK;                       /* Array of primary key flags */
    ++  int nEntry;                     /* Total number of entries in hash table */
    ++  int nChange;                    /* Size of apChange[] array */
    ++  SessionChange **apChange;       /* Hash table buckets */
    ++};
    ++
    ++/* 
    ++** RECORD FORMAT:
    ++**
    ++** The following record format is similar to (but not compatible with) that 
    ++** used in SQLite database files. This format is used as part of the 
    ++** change-set binary format, and so must be architecture independent.
    ++**
    ++** Unlike the SQLite database record format, each field is self-contained -
    ++** there is no separation of header and data. Each field begins with a
    ++** single byte describing its type, as follows:
    ++**
    ++**       0x00: Undefined value.
    ++**       0x01: Integer value.
    ++**       0x02: Real value.
    ++**       0x03: Text value.
    ++**       0x04: Blob value.
    ++**       0x05: SQL NULL value.
    ++**
    ++** Note that the above match the definitions of SQLITE_INTEGER, SQLITE_TEXT
    ++** and so on in sqlite3.h. For undefined and NULL values, the field consists
    ++** only of the single type byte. For other types of values, the type byte
    ++** is followed by:
    ++**
    ++**   Text values:
    ++**     A varint containing the number of bytes in the value (encoded using
    ++**     UTF-8). Followed by a buffer containing the UTF-8 representation
    ++**     of the text value. There is no nul terminator.
    ++**
    ++**   Blob values:
    ++**     A varint containing the number of bytes in the value, followed by
    ++**     a buffer containing the value itself.
    ++**
    ++**   Integer values:
    ++**     An 8-byte big-endian integer value.
    ++**
    ++**   Real values:
    ++**     An 8-byte big-endian IEEE 754-2008 real value.
    ++**
    ++** Varint values are encoded in the same way as varints in the SQLite 
    ++** record format.
    ++**
    ++** CHANGESET FORMAT:
    ++**
    ++** A changeset is a collection of DELETE, UPDATE and INSERT operations on
    ++** one or more tables. Operations on a single table are grouped together,
    ++** but may occur in any order (i.e. deletes, updates and inserts are all
    ++** mixed together).
    ++**
    ++** Each group of changes begins with a table header:
    ++**
    ++**   1 byte: Constant 0x54 (capital 'T')
    ++**   Varint: Number of columns in the table.
    ++**   nCol bytes: 0x01 for PK columns, 0x00 otherwise.
    ++**   N bytes: Unqualified table name (encoded using UTF-8). Nul-terminated.
    ++**
    ++** Followed by one or more changes to the table.
    ++**
    ++**   1 byte: Either SQLITE_INSERT (0x12), UPDATE (0x17) or DELETE (0x09).
    ++**   1 byte: The "indirect-change" flag.
    ++**   old.* record: (delete and update only)
    ++**   new.* record: (insert and update only)
    ++**
    ++** The "old.*" and "new.*" records, if present, are N field records in the
    ++** format described above under "RECORD FORMAT", where N is the number of
    ++** columns in the table. The i'th field of each record is associated with
    ++** the i'th column of the table, counting from left to right in the order
    ++** in which columns were declared in the CREATE TABLE statement.
    ++**
    ++** The new.* record that is part of each INSERT change contains the values
    ++** that make up the new row. Similarly, the old.* record that is part of each
    ++** DELETE change contains the values that made up the row that was deleted 
    ++** from the database. In the changeset format, the records that are part
    ++** of INSERT or DELETE changes never contain any undefined (type byte 0x00)
    ++** fields.
    ++**
    ++** Within the old.* record associated with an UPDATE change, all fields
    ++** associated with table columns that are not PRIMARY KEY columns and are
    ++** not modified by the UPDATE change are set to "undefined". Other fields
    ++** are set to the values that made up the row before the UPDATE that the
    ++** change records took place. Within the new.* record, fields associated 
    ++** with table columns modified by the UPDATE change contain the new 
    ++** values. Fields associated with table columns that are not modified
    ++** are set to "undefined".
    ++**
    ++** PATCHSET FORMAT:
    ++**
    ++** A patchset is also a collection of changes. It is similar to a changeset,
    ++** but leaves undefined those fields that are not useful if no conflict
    ++** resolution is required when applying the changeset.
    ++**
    ++** Each group of changes begins with a table header:
    ++**
    ++**   1 byte: Constant 0x50 (capital 'P')
    ++**   Varint: Number of columns in the table.
    ++**   nCol bytes: 0x01 for PK columns, 0x00 otherwise.
    ++**   N bytes: Unqualified table name (encoded using UTF-8). Nul-terminated.
    ++**
    ++** Followed by one or more changes to the table.
    ++**
    ++**   1 byte: Either SQLITE_INSERT (0x12), UPDATE (0x17) or DELETE (0x09).
    ++**   1 byte: The "indirect-change" flag.
    ++**   single record: (PK fields for DELETE, PK and modified fields for UPDATE,
    ++**                   full record for INSERT).
    ++**
    ++** As in the changeset format, each field of the single record that is part
    ++** of a patchset change is associated with the correspondingly positioned
    ++** table column, counting from left to right within the CREATE TABLE 
    ++** statement.
    ++**
    ++** For a DELETE change, all fields within the record except those associated
    ++** with PRIMARY KEY columns are set to "undefined". The PRIMARY KEY fields
    ++** contain the values identifying the row to delete.
    ++**
    ++** For an UPDATE change, all fields except those associated with PRIMARY KEY
    ++** columns and columns that are modified by the UPDATE are set to "undefined".
    ++** PRIMARY KEY fields contain the values identifying the table row to update,
    ++** and fields associated with modified columns contain the new column values.
    ++**
    ++** The records associated with INSERT changes are in the same format as for
    ++** changesets. It is not possible for a record associated with an INSERT
    ++** change to contain a field set to "undefined".
    + */
    +-static u32 jsonNodeSize(JsonNode *pNode){
    +-  return pNode->eType>=JSON_ARRAY ? pNode->n+1 : 1;
    ++
    ++/*
    ++** For each row modified during a session, there exists a single instance of
    ++** this structure stored in a SessionTable.aChange[] hash table.
    ++*/
    ++struct SessionChange {
    ++  int op;                         /* One of UPDATE, DELETE, INSERT */
    ++  int bIndirect;                  /* True if this change is "indirect" */
    ++  int nRecord;                    /* Number of bytes in buffer aRecord[] */
    ++  u8 *aRecord;                    /* Buffer containing old.* record */
    ++  SessionChange *pNext;           /* For hash-table collisions */
    ++};
    ++
    ++/*
    ++** Write a varint with value iVal into the buffer at aBuf. Return the 
    ++** number of bytes written.
    ++*/
    ++static int sessionVarintPut(u8 *aBuf, int iVal){
    ++  return putVarint32(aBuf, iVal);
    + }
    + 
    + /*
    +-** Reclaim all memory allocated by a JsonParse object.  But do not
    +-** delete the JsonParse object itself.
    ++** Return the number of bytes required to store value iVal as a varint.
    + */
    +-static void jsonParseReset(JsonParse *pParse){
    +-  sqlite3_free(pParse->aNode);
    +-  pParse->aNode = 0;
    +-  pParse->nNode = 0;
    +-  pParse->nAlloc = 0;
    +-  sqlite3_free(pParse->aUp);
    +-  pParse->aUp = 0;
    ++static int sessionVarintLen(int iVal){
    ++  return sqlite3VarintLen(iVal);
    + }
    + 
    + /*
    +-** Convert the JsonNode pNode into a pure JSON string and
    +-** append to pOut.  Subsubstructure is also included.  Return
    +-** the number of JsonNode objects that are encoded.
    ++** Read a varint value from aBuf[] into *piVal. Return the number of 
    ++** bytes read.
    + */
    +-static void jsonRenderNode(
    +-  JsonNode *pNode,               /* The node to render */
    +-  JsonString *pOut,              /* Write JSON here */
    +-  sqlite3_value **aReplace       /* Replacement values */
    ++static int sessionVarintGet(u8 *aBuf, int *piVal){
    ++  return getVarint32(aBuf, *piVal);
    ++}
    ++
    ++/* Load an unaligned and unsigned 32-bit integer */
    ++#define SESSION_UINT32(x) (((u32)(x)[0]<<24)|((x)[1]<<16)|((x)[2]<<8)|(x)[3])
    ++
    ++/*
    ++** Read a 64-bit big-endian integer value from buffer aRec[]. Return
    ++** the value read.
    ++*/
    ++static sqlite3_int64 sessionGetI64(u8 *aRec){
    ++  u64 x = SESSION_UINT32(aRec);
    ++  u32 y = SESSION_UINT32(aRec+4);
    ++  x = (x<<32) + y;
    ++  return (sqlite3_int64)x;
    ++}
    ++
    ++/*
    ++** Write a 64-bit big-endian integer value to the buffer aBuf[].
    ++*/
    ++static void sessionPutI64(u8 *aBuf, sqlite3_int64 i){
    ++  aBuf[0] = (i>>56) & 0xFF;
    ++  aBuf[1] = (i>>48) & 0xFF;
    ++  aBuf[2] = (i>>40) & 0xFF;
    ++  aBuf[3] = (i>>32) & 0xFF;
    ++  aBuf[4] = (i>>24) & 0xFF;
    ++  aBuf[5] = (i>>16) & 0xFF;
    ++  aBuf[6] = (i>> 8) & 0xFF;
    ++  aBuf[7] = (i>> 0) & 0xFF;
    ++}
    ++
    ++/*
    ++** This function is used to serialize the contents of value pValue (see
    ++** comment titled "RECORD FORMAT" above).
    ++**
    ++** If it is non-NULL, the serialized form of the value is written to 
    ++** buffer aBuf. *pnWrite is set to the number of bytes written before
    ++** returning. Or, if aBuf is NULL, the only thing this function does is
    ++** set *pnWrite.
    ++**
    ++** If no error occurs, SQLITE_OK is returned. Or, if an OOM error occurs
    ++** within a call to sqlite3_value_text() (may fail if the db is utf-16)) 
    ++** SQLITE_NOMEM is returned.
    ++*/
    ++static int sessionSerializeValue(
    ++  u8 *aBuf,                       /* If non-NULL, write serialized value here */
    ++  sqlite3_value *pValue,          /* Value to serialize */
    ++  int *pnWrite                    /* IN/OUT: Increment by bytes written */
    + ){
    +-  switch( pNode->eType ){
    +-    default: {
    +-      assert( pNode->eType==JSON_NULL );
    +-      jsonAppendRaw(pOut, "null", 4);
    +-      break;
    +-    }
    +-    case JSON_TRUE: {
    +-      jsonAppendRaw(pOut, "true", 4);
    +-      break;
    +-    }
    +-    case JSON_FALSE: {
    +-      jsonAppendRaw(pOut, "false", 5);
    +-      break;
    +-    }
    +-    case JSON_STRING: {
    +-      if( pNode->jnFlags & JNODE_RAW ){
    +-        jsonAppendString(pOut, pNode->u.zJContent, pNode->n);
    ++  int nByte;                      /* Size of serialized value in bytes */
    ++
    ++  if( pValue ){
    ++    int eType;                    /* Value type (SQLITE_NULL, TEXT etc.) */
    ++  
    ++    eType = sqlite3_value_type(pValue);
    ++    if( aBuf ) aBuf[0] = eType;
    ++  
    ++    switch( eType ){
    ++      case SQLITE_NULL: 
    ++        nByte = 1;
    +         break;
    +-      }
    +-      /* Fall through into the next case */
    +-    }
    +-    case JSON_REAL:
    +-    case JSON_INT: {
    +-      jsonAppendRaw(pOut, pNode->u.zJContent, pNode->n);
    +-      break;
    +-    }
    +-    case JSON_ARRAY: {
    +-      u32 j = 1;
    +-      jsonAppendChar(pOut, '[');
    +-      for(;;){
    +-        while( j<=pNode->n ){
    +-          if( pNode[j].jnFlags & (JNODE_REMOVE|JNODE_REPLACE) ){
    +-            if( pNode[j].jnFlags & JNODE_REPLACE ){
    +-              jsonAppendSeparator(pOut);
    +-              jsonAppendValue(pOut, aReplace[pNode[j].iVal]);
    +-            }
    ++  
    ++      case SQLITE_INTEGER: 
    ++      case SQLITE_FLOAT:
    ++        if( aBuf ){
    ++          /* TODO: SQLite does something special to deal with mixed-endian
    ++          ** floating point values (e.g. ARM7). This code probably should
    ++          ** too.  */
    ++          u64 i;
    ++          if( eType==SQLITE_INTEGER ){
    ++            i = (u64)sqlite3_value_int64(pValue);
    +           }else{
    +-            jsonAppendSeparator(pOut);
    +-            jsonRenderNode(&pNode[j], pOut, aReplace);
    ++            double r;
    ++            assert( sizeof(double)==8 && sizeof(u64)==8 );
    ++            r = sqlite3_value_double(pValue);
    ++            memcpy(&i, &r, 8);
    +           }
    +-          j += jsonNodeSize(&pNode[j]);
    ++          sessionPutI64(&aBuf[1], i);
    +         }
    +-        if( (pNode->jnFlags & JNODE_APPEND)==0 ) break;
    +-        pNode = &pNode[pNode->u.iAppend];
    +-        j = 1;
    +-      }
    +-      jsonAppendChar(pOut, ']');
    +-      break;
    +-    }
    +-    case JSON_OBJECT: {
    +-      u32 j = 1;
    +-      jsonAppendChar(pOut, '{');
    +-      for(;;){
    +-        while( j<=pNode->n ){
    +-          if( (pNode[j+1].jnFlags & JNODE_REMOVE)==0 ){
    +-            jsonAppendSeparator(pOut);
    +-            jsonRenderNode(&pNode[j], pOut, aReplace);
    +-            jsonAppendChar(pOut, ':');
    +-            if( pNode[j+1].jnFlags & JNODE_REPLACE ){
    +-              jsonAppendValue(pOut, aReplace[pNode[j+1].iVal]);
    +-            }else{
    +-              jsonRenderNode(&pNode[j+1], pOut, aReplace);
    +-            }
    +-          }
    +-          j += 1 + jsonNodeSize(&pNode[j+1]);
    ++        nByte = 9; 
    ++        break;
    ++  
    ++      default: {
    ++        u8 *z;
    ++        int n;
    ++        int nVarint;
    ++  
    ++        assert( eType==SQLITE_TEXT || eType==SQLITE_BLOB );
    ++        if( eType==SQLITE_TEXT ){
    ++          z = (u8 *)sqlite3_value_text(pValue);
    ++        }else{
    ++          z = (u8 *)sqlite3_value_blob(pValue);
    +         }
    +-        if( (pNode->jnFlags & JNODE_APPEND)==0 ) break;
    +-        pNode = &pNode[pNode->u.iAppend];
    +-        j = 1;
    ++        n = sqlite3_value_bytes(pValue);
    ++        if( z==0 && (eType!=SQLITE_BLOB || n>0) ) return SQLITE_NOMEM;
    ++        nVarint = sessionVarintLen(n);
    ++  
    ++        if( aBuf ){
    ++          sessionVarintPut(&aBuf[1], n);
    ++          if( n ) memcpy(&aBuf[nVarint + 1], z, n);
    ++        }
    ++  
    ++        nByte = 1 + nVarint + n;
    ++        break;
    +       }
    +-      jsonAppendChar(pOut, '}');
    +-      break;
    +     }
    ++  }else{
    ++    nByte = 1;
    ++    if( aBuf ) aBuf[0] = '\0';
    +   }
    ++
    ++  if( pnWrite ) *pnWrite += nByte;
    ++  return SQLITE_OK;
    + }
    + 
    ++
    + /*
    +-** Return a JsonNode and all its descendents as a JSON string.
    ++** This macro is used to calculate hash key values for data structures. In
    ++** order to use this macro, the entire data structure must be represented
    ++** as a series of unsigned integers. In order to calculate a hash-key value
    ++** for a data structure represented as three such integers, the macro may
    ++** then be used as follows:
    ++**
    ++**    int hash_key_value;
    ++**    hash_key_value = HASH_APPEND(0, <value 1>);
    ++**    hash_key_value = HASH_APPEND(hash_key_value, <value 2>);
    ++**    hash_key_value = HASH_APPEND(hash_key_value, <value 3>);
    ++**
    ++** In practice, the data structures this macro is used for are the primary
    ++** key values of modified rows.
    + */
    +-static void jsonReturnJson(
    +-  JsonNode *pNode,            /* Node to return */
    +-  sqlite3_context *pCtx,      /* Return value for this function */
    +-  sqlite3_value **aReplace    /* Array of replacement values */
    +-){
    +-  JsonString s;
    +-  jsonInit(&s, pCtx);
    +-  jsonRenderNode(pNode, &s, aReplace);
    +-  jsonResult(&s);
    +-  sqlite3_result_subtype(pCtx, JSON_SUBTYPE);
    ++#define HASH_APPEND(hash, add) ((hash) << 3) ^ (hash) ^ (unsigned int)(add)
    ++
    ++/*
    ++** Append the hash of the 64-bit integer passed as the second argument to the
    ++** hash-key value passed as the first. Return the new hash-key value.
    ++*/
    ++static unsigned int sessionHashAppendI64(unsigned int h, i64 i){
    ++  h = HASH_APPEND(h, i & 0xFFFFFFFF);
    ++  return HASH_APPEND(h, (i>>32)&0xFFFFFFFF);
    + }
    + 
    + /*
    +-** Make the JsonNode the return value of the function.
    ++** Append the hash of the blob passed via the second and third arguments to 
    ++** the hash-key value passed as the first. Return the new hash-key value.
    + */
    +-static void jsonReturn(
    +-  JsonNode *pNode,            /* Node to return */
    +-  sqlite3_context *pCtx,      /* Return value for this function */
    +-  sqlite3_value **aReplace    /* Array of replacement values */
    ++static unsigned int sessionHashAppendBlob(unsigned int h, int n, const u8 *z){
    ++  int i;
    ++  for(i=0; i<n; i++) h = HASH_APPEND(h, z[i]);
    ++  return h;
    ++}
    ++
    ++/*
    ++** Append the hash of the data type passed as the second argument to the
    ++** hash-key value passed as the first. Return the new hash-key value.
    ++*/
    ++static unsigned int sessionHashAppendType(unsigned int h, int eType){
    ++  return HASH_APPEND(h, eType);
    ++}
    ++
    ++/*
    ++** This function may only be called from within a pre-update callback.
    ++** It calculates a hash based on the primary key values of the old.* or 
    ++** new.* row currently available and, assuming no error occurs, writes it to
    ++** *piHash before returning. If the primary key contains one or more NULL
    ++** values, *pbNullPK is set to true before returning.
    ++**
    ++** If an error occurs, an SQLite error code is returned and the final values
    ++** of *piHash asn *pbNullPK are undefined. Otherwise, SQLITE_OK is returned
    ++** and the output variables are set as described above.
    ++*/
    ++static int sessionPreupdateHash(
    ++  sqlite3_session *pSession,      /* Session object that owns pTab */
    ++  SessionTable *pTab,             /* Session table handle */
    ++  int bNew,                       /* True to hash the new.* PK */
    ++  int *piHash,                    /* OUT: Hash value */
    ++  int *pbNullPK                   /* OUT: True if there are NULL values in PK */
    + ){
    +-  switch( pNode->eType ){
    +-    default: {
    +-      assert( pNode->eType==JSON_NULL );
    +-      sqlite3_result_null(pCtx);
    +-      break;
    +-    }
    +-    case JSON_TRUE: {
    +-      sqlite3_result_int(pCtx, 1);
    +-      break;
    +-    }
    +-    case JSON_FALSE: {
    +-      sqlite3_result_int(pCtx, 0);
    +-      break;
    +-    }
    +-    case JSON_INT: {
    +-      sqlite3_int64 i = 0;
    +-      const char *z = pNode->u.zJContent;
    +-      if( z[0]=='-' ){ z++; }
    +-      while( z[0]>='0' && z[0]<='9' ){
    +-        unsigned v = *(z++) - '0';
    +-        if( i>=LARGEST_INT64/10 ){
    +-          if( i>LARGEST_INT64/10 ) goto int_as_real;
    +-          if( z[0]>='0' && z[0]<='9' ) goto int_as_real;
    +-          if( v==9 ) goto int_as_real;
    +-          if( v==8 ){
    +-            if( pNode->u.zJContent[0]=='-' ){
    +-              sqlite3_result_int64(pCtx, SMALLEST_INT64);
    +-              goto int_done;
    +-            }else{
    +-              goto int_as_real;
    +-            }
    +-          }
    +-        }
    +-        i = i*10 + v;
    +-      }
    +-      if( pNode->u.zJContent[0]=='-' ){ i = -i; }
    +-      sqlite3_result_int64(pCtx, i);
    +-      int_done:
    +-      break;
    +-      int_as_real: /* fall through to real */;
    +-    }
    +-    case JSON_REAL: {
    +-      double r;
    +-#ifdef SQLITE_AMALGAMATION
    +-      const char *z = pNode->u.zJContent;
    +-      sqlite3AtoF(z, &r, sqlite3Strlen30(z), SQLITE_UTF8);
    +-#else
    +-      r = strtod(pNode->u.zJContent, 0);
    +-#endif
    +-      sqlite3_result_double(pCtx, r);
    +-      break;
    +-    }
    +-    case JSON_STRING: {
    +-#if 0 /* Never happens because JNODE_RAW is only set by json_set(),
    +-      ** json_insert() and json_replace() and those routines do not
    +-      ** call jsonReturn() */
    +-      if( pNode->jnFlags & JNODE_RAW ){
    +-        sqlite3_result_text(pCtx, pNode->u.zJContent, pNode->n,
    +-                            SQLITE_TRANSIENT);
    +-      }else 
    +-#endif
    +-      assert( (pNode->jnFlags & JNODE_RAW)==0 );
    +-      if( (pNode->jnFlags & JNODE_ESCAPE)==0 ){
    +-        /* JSON formatted without any backslash-escapes */
    +-        sqlite3_result_text(pCtx, pNode->u.zJContent+1, pNode->n-2,
    +-                            SQLITE_TRANSIENT);
    ++  unsigned int h = 0;             /* Hash value to return */
    ++  int i;                          /* Used to iterate through columns */
    ++
    ++  assert( *pbNullPK==0 );
    ++  assert( pTab->nCol==pSession->hook.xCount(pSession->hook.pCtx) );
    ++  for(i=0; i<pTab->nCol; i++){
    ++    if( pTab->abPK[i] ){
    ++      int rc;
    ++      int eType;
    ++      sqlite3_value *pVal;
    ++
    ++      if( bNew ){
    ++        rc = pSession->hook.xNew(pSession->hook.pCtx, i, &pVal);
    +       }else{
    +-        /* Translate JSON formatted string into raw text */
    +-        u32 i;
    +-        u32 n = pNode->n;
    +-        const char *z = pNode->u.zJContent;
    +-        char *zOut;
    +-        u32 j;
    +-        zOut = sqlite3_malloc( n+1 );
    +-        if( zOut==0 ){
    +-          sqlite3_result_error_nomem(pCtx);
    +-          break;
    ++        rc = pSession->hook.xOld(pSession->hook.pCtx, i, &pVal);
    ++      }
    ++      if( rc!=SQLITE_OK ) return rc;
    ++
    ++      eType = sqlite3_value_type(pVal);
    ++      h = sessionHashAppendType(h, eType);
    ++      if( eType==SQLITE_INTEGER || eType==SQLITE_FLOAT ){
    ++        i64 iVal;
    ++        if( eType==SQLITE_INTEGER ){
    ++          iVal = sqlite3_value_int64(pVal);
    ++        }else{
    ++          double rVal = sqlite3_value_double(pVal);
    ++          assert( sizeof(iVal)==8 && sizeof(rVal)==8 );
    ++          memcpy(&iVal, &rVal, 8);
    +         }
    +-        for(i=1, j=0; i<n-1; i++){
    +-          char c = z[i];
    +-          if( c!='\\' ){
    +-            zOut[j++] = c;
    +-          }else{
    +-            c = z[++i];
    +-            if( c=='u' ){
    +-              u32 v = 0, k;
    +-              for(k=0; k<4 && i<n-2; i++, k++){
    +-                c = z[i+1];
    +-                if( c>='0' && c<='9' ) v = v*16 + c - '0';
    +-                else if( c>='A' && c<='F' ) v = v*16 + c - 'A' + 10;
    +-                else if( c>='a' && c<='f' ) v = v*16 + c - 'a' + 10;
    +-                else break;
    +-              }
    +-              if( v==0 ) break;
    +-              if( v<=0x7f ){
    +-                zOut[j++] = (char)v;
    +-              }else if( v<=0x7ff ){
    +-                zOut[j++] = (char)(0xc0 | (v>>6));
    +-                zOut[j++] = 0x80 | (v&0x3f);
    +-              }else{
    +-                zOut[j++] = (char)(0xe0 | (v>>12));
    +-                zOut[j++] = 0x80 | ((v>>6)&0x3f);
    +-                zOut[j++] = 0x80 | (v&0x3f);
    +-              }
    +-            }else{
    +-              if( c=='b' ){
    +-                c = '\b';
    +-              }else if( c=='f' ){
    +-                c = '\f';
    +-              }else if( c=='n' ){
    +-                c = '\n';
    +-              }else if( c=='r' ){
    +-                c = '\r';
    +-              }else if( c=='t' ){
    +-                c = '\t';
    +-              }
    +-              zOut[j++] = c;
    +-            }
    +-          }
    ++        h = sessionHashAppendI64(h, iVal);
    ++      }else if( eType==SQLITE_TEXT || eType==SQLITE_BLOB ){
    ++        const u8 *z;
    ++        int n;
    ++        if( eType==SQLITE_TEXT ){
    ++          z = (const u8 *)sqlite3_value_text(pVal);
    ++        }else{
    ++          z = (const u8 *)sqlite3_value_blob(pVal);
    +         }
    +-        zOut[j] = 0;
    +-        sqlite3_result_text(pCtx, zOut, j, sqlite3_free);
    ++        n = sqlite3_value_bytes(pVal);
    ++        if( !z && (eType!=SQLITE_BLOB || n>0) ) return SQLITE_NOMEM;
    ++        h = sessionHashAppendBlob(h, n, z);
    ++      }else{
    ++        assert( eType==SQLITE_NULL );
    ++        assert( pTab->bStat1==0 || i!=1 );
    ++        *pbNullPK = 1;
    +       }
    +-      break;
    +-    }
    +-    case JSON_ARRAY:
    +-    case JSON_OBJECT: {
    +-      jsonReturnJson(pNode, pCtx, aReplace);
    +-      break;
    +     }
    +   }
    ++
    ++  *piHash = (h % pTab->nChange);
    ++  return SQLITE_OK;
    + }
    + 
    +-/* Forward reference */
    +-static int jsonParseAddNode(JsonParse*,u32,u32,const char*);
    ++/*
    ++** The buffer that the argument points to contains a serialized SQL value.
    ++** Return the number of bytes of space occupied by the value (including
    ++** the type byte).
    ++*/
    ++static int sessionSerialLen(u8 *a){
    ++  int e = *a;
    ++  int n;
    ++  if( e==0 ) return 1;
    ++  if( e==SQLITE_NULL ) return 1;
    ++  if( e==SQLITE_INTEGER || e==SQLITE_FLOAT ) return 9;
    ++  return sessionVarintGet(&a[1], &n) + 1 + n;
    ++}
    + 
    + /*
    +-** A macro to hint to the compiler that a function should not be
    +-** inlined.
    ++** Based on the primary key values stored in change aRecord, calculate a
    ++** hash key. Assume the has table has nBucket buckets. The hash keys
    ++** calculated by this function are compatible with those calculated by
    ++** sessionPreupdateHash().
    ++**
    ++** The bPkOnly argument is non-zero if the record at aRecord[] is from
    ++** a patchset DELETE. In this case the non-PK fields are omitted entirely.
    + */
    +-#if defined(__GNUC__)
    +-#  define JSON_NOINLINE  __attribute__((noinline))
    +-#elif defined(_MSC_VER) && _MSC_VER>=1310
    +-#  define JSON_NOINLINE  __declspec(noinline)
    +-#else
    +-#  define JSON_NOINLINE
    +-#endif
    ++static unsigned int sessionChangeHash(
    ++  SessionTable *pTab,             /* Table handle */
    ++  int bPkOnly,                    /* Record consists of PK fields only */
    ++  u8 *aRecord,                    /* Change record */
    ++  int nBucket                     /* Assume this many buckets in hash table */
    ++){
    ++  unsigned int h = 0;             /* Value to return */
    ++  int i;                          /* Used to iterate through columns */
    ++  u8 *a = aRecord;                /* Used to iterate through change record */
    + 
    ++  for(i=0; i<pTab->nCol; i++){
    ++    int eType = *a;
    ++    int isPK = pTab->abPK[i];
    ++    if( bPkOnly && isPK==0 ) continue;
    ++
    ++    /* It is not possible for eType to be SQLITE_NULL here. The session 
    ++    ** module does not record changes for rows with NULL values stored in
    ++    ** primary key columns. */
    ++    assert( eType==SQLITE_INTEGER || eType==SQLITE_FLOAT 
    ++         || eType==SQLITE_TEXT || eType==SQLITE_BLOB 
    ++         || eType==SQLITE_NULL || eType==0 
    ++    );
    ++    assert( !isPK || (eType!=0 && eType!=SQLITE_NULL) );
    ++
    ++    if( isPK ){
    ++      a++;
    ++      h = sessionHashAppendType(h, eType);
    ++      if( eType==SQLITE_INTEGER || eType==SQLITE_FLOAT ){
    ++        h = sessionHashAppendI64(h, sessionGetI64(a));
    ++        a += 8;
    ++      }else{
    ++        int n; 
    ++        a += sessionVarintGet(a, &n);
    ++        h = sessionHashAppendBlob(h, n, a);
    ++        a += n;
    ++      }
    ++    }else{
    ++      a += sessionSerialLen(a);
    ++    }
    ++  }
    ++  return (h % nBucket);
    ++}
    + 
    +-static JSON_NOINLINE int jsonParseAddNodeExpand(
    +-  JsonParse *pParse,        /* Append the node to this object */
    +-  u32 eType,                /* Node type */
    +-  u32 n,                    /* Content size or sub-node count */
    +-  const char *zContent      /* Content */
    ++/*
    ++** Arguments aLeft and aRight are pointers to change records for table pTab.
    ++** This function returns true if the two records apply to the same row (i.e.
    ++** have the same values stored in the primary key columns), or false 
    ++** otherwise.
    ++*/
    ++static int sessionChangeEqual(
    ++  SessionTable *pTab,             /* Table used for PK definition */
    ++  int bLeftPkOnly,                /* True if aLeft[] contains PK fields only */
    ++  u8 *aLeft,                      /* Change record */
    ++  int bRightPkOnly,               /* True if aRight[] contains PK fields only */
    ++  u8 *aRight                      /* Change record */
    + ){
    +-  u32 nNew;
    +-  JsonNode *pNew;
    +-  assert( pParse->nNode>=pParse->nAlloc );
    +-  if( pParse->oom ) return -1;
    +-  nNew = pParse->nAlloc*2 + 10;
    +-  pNew = sqlite3_realloc(pParse->aNode, sizeof(JsonNode)*nNew);
    +-  if( pNew==0 ){
    +-    pParse->oom = 1;
    +-    return -1;
    ++  u8 *a1 = aLeft;                 /* Cursor to iterate through aLeft */
    ++  u8 *a2 = aRight;                /* Cursor to iterate through aRight */
    ++  int iCol;                       /* Used to iterate through table columns */
    ++
    ++  for(iCol=0; iCol<pTab->nCol; iCol++){
    ++    if( pTab->abPK[iCol] ){
    ++      int n1 = sessionSerialLen(a1);
    ++      int n2 = sessionSerialLen(a2);
    ++
    ++      if( pTab->abPK[iCol] && (n1!=n2 || memcmp(a1, a2, n1)) ){
    ++        return 0;
    ++      }
    ++      a1 += n1;
    ++      a2 += n2;
    ++    }else{
    ++      if( bLeftPkOnly==0 ) a1 += sessionSerialLen(a1);
    ++      if( bRightPkOnly==0 ) a2 += sessionSerialLen(a2);
    ++    }
    +   }
    +-  pParse->nAlloc = nNew;
    +-  pParse->aNode = pNew;
    +-  assert( pParse->nNode<pParse->nAlloc );
    +-  return jsonParseAddNode(pParse, eType, n, zContent);
    ++
    ++  return 1;
    + }
    + 
    + /*
    +-** Create a new JsonNode instance based on the arguments and append that
    +-** instance to the JsonParse.  Return the index in pParse->aNode[] of the
    +-** new node, or -1 if a memory allocation fails.
    ++** Arguments aLeft and aRight both point to buffers containing change
    ++** records with nCol columns. This function "merges" the two records into
    ++** a single records which is written to the buffer at *paOut. *paOut is
    ++** then set to point to one byte after the last byte written before 
    ++** returning.
    ++**
    ++** The merging of records is done as follows: For each column, if the 
    ++** aRight record contains a value for the column, copy the value from
    ++** their. Otherwise, if aLeft contains a value, copy it. If neither
    ++** record contains a value for a given column, then neither does the
    ++** output record.
    + */
    +-static int jsonParseAddNode(
    +-  JsonParse *pParse,        /* Append the node to this object */
    +-  u32 eType,                /* Node type */
    +-  u32 n,                    /* Content size or sub-node count */
    +-  const char *zContent      /* Content */
    ++static void sessionMergeRecord(
    ++  u8 **paOut, 
    ++  int nCol,
    ++  u8 *aLeft,
    ++  u8 *aRight
    + ){
    +-  JsonNode *p;
    +-  if( pParse->nNode>=pParse->nAlloc ){
    +-    return jsonParseAddNodeExpand(pParse, eType, n, zContent);
    ++  u8 *a1 = aLeft;                 /* Cursor used to iterate through aLeft */
    ++  u8 *a2 = aRight;                /* Cursor used to iterate through aRight */
    ++  u8 *aOut = *paOut;              /* Output cursor */
    ++  int iCol;                       /* Used to iterate from 0 to nCol */
    ++
    ++  for(iCol=0; iCol<nCol; iCol++){
    ++    int n1 = sessionSerialLen(a1);
    ++    int n2 = sessionSerialLen(a2);
    ++    if( *a2 ){
    ++      memcpy(aOut, a2, n2);
    ++      aOut += n2;
    ++    }else{
    ++      memcpy(aOut, a1, n1);
    ++      aOut += n1;
    ++    }
    ++    a1 += n1;
    ++    a2 += n2;
    +   }
    +-  p = &pParse->aNode[pParse->nNode];
    +-  p->eType = (u8)eType;
    +-  p->jnFlags = 0;
    +-  p->iVal = 0;
    +-  p->n = n;
    +-  p->u.zJContent = zContent;
    +-  return pParse->nNode++;
    ++
    ++  *paOut = aOut;
    + }
    + 
    + /*
    +-** Parse a single JSON value which begins at pParse->zJson[i].  Return the
    +-** index of the first character past the end of the value parsed.
    ++** This is a helper function used by sessionMergeUpdate().
    ++**
    ++** When this function is called, both *paOne and *paTwo point to a value 
    ++** within a change record. Before it returns, both have been advanced so 
    ++** as to point to the next value in the record.
    ++**
    ++** If, when this function is called, *paTwo points to a valid value (i.e.
    ++** *paTwo[0] is not 0x00 - the "no value" placeholder), a copy of the *paTwo
    ++** pointer is returned and *pnVal is set to the number of bytes in the 
    ++** serialized value. Otherwise, a copy of *paOne is returned and *pnVal
    ++** set to the number of bytes in the value at *paOne. If *paOne points
    ++** to the "no value" placeholder, *pnVal is set to 1. In other words:
    ++**
    ++**   if( *paTwo is valid ) return *paTwo;
    ++**   return *paOne;
    + **
    +-** Return negative for a syntax error.  Special cases:  return -2 if the
    +-** first non-whitespace character is '}' and return -3 if the first
    +-** non-whitespace character is ']'.
    + */
    +-static int jsonParseValue(JsonParse *pParse, u32 i){
    +-  char c;
    +-  u32 j;
    +-  int iThis;
    +-  int x;
    +-  JsonNode *pNode;
    +-  while( safe_isspace(pParse->zJson[i]) ){ i++; }
    +-  if( (c = pParse->zJson[i])=='{' ){
    +-    /* Parse object */
    +-    iThis = jsonParseAddNode(pParse, JSON_OBJECT, 0, 0);
    +-    if( iThis<0 ) return -1;
    +-    for(j=i+1;;j++){
    +-      while( safe_isspace(pParse->zJson[j]) ){ j++; }
    +-      x = jsonParseValue(pParse, j);
    +-      if( x<0 ){
    +-        if( x==(-2) && pParse->nNode==(u32)iThis+1 ) return j+1;
    +-        return -1;
    +-      }
    +-      if( pParse->oom ) return -1;
    +-      pNode = &pParse->aNode[pParse->nNode-1];
    +-      if( pNode->eType!=JSON_STRING ) return -1;
    +-      pNode->jnFlags |= JNODE_LABEL;
    +-      j = x;
    +-      while( safe_isspace(pParse->zJson[j]) ){ j++; }
    +-      if( pParse->zJson[j]!=':' ) return -1;
    +-      j++;
    +-      x = jsonParseValue(pParse, j);
    ++static u8 *sessionMergeValue(
    ++  u8 **paOne,                     /* IN/OUT: Left-hand buffer pointer */
    ++  u8 **paTwo,                     /* IN/OUT: Right-hand buffer pointer */
    ++  int *pnVal                      /* OUT: Bytes in returned value */
    ++){
    ++  u8 *a1 = *paOne;
    ++  u8 *a2 = *paTwo;
    ++  u8 *pRet = 0;
    ++  int n1;
    ++
    ++  assert( a1 );
    ++  if( a2 ){
    ++    int n2 = sessionSerialLen(a2);
    ++    if( *a2 ){
    ++      *pnVal = n2;
    ++      pRet = a2;
    ++    }
    ++    *paTwo = &a2[n2];
    ++  }
    ++
    ++  n1 = sessionSerialLen(a1);
    ++  if( pRet==0 ){
    ++    *pnVal = n1;
    ++    pRet = a1;
    ++  }
    ++  *paOne = &a1[n1];
    ++
    ++  return pRet;
    ++}
    ++
    ++/*
    ++** This function is used by changeset_concat() to merge two UPDATE changes
    ++** on the same row.
    ++*/
    ++static int sessionMergeUpdate(
    ++  u8 **paOut,                     /* IN/OUT: Pointer to output buffer */
    ++  SessionTable *pTab,             /* Table change pertains to */
    ++  int bPatchset,                  /* True if records are patchset records */
    ++  u8 *aOldRecord1,                /* old.* record for first change */
    ++  u8 *aOldRecord2,                /* old.* record for second change */
    ++  u8 *aNewRecord1,                /* new.* record for first change */
    ++  u8 *aNewRecord2                 /* new.* record for second change */
    ++){
    ++  u8 *aOld1 = aOldRecord1;
    ++  u8 *aOld2 = aOldRecord2;
    ++  u8 *aNew1 = aNewRecord1;
    ++  u8 *aNew2 = aNewRecord2;
    ++
    ++  u8 *aOut = *paOut;
    ++  int i;
    ++
    ++  if( bPatchset==0 ){
    ++    int bRequired = 0;
    ++
    ++    assert( aOldRecord1 && aNewRecord1 );
    ++
    ++    /* Write the old.* vector first. */
    ++    for(i=0; i<pTab->nCol; i++){
    ++      int nOld;
    ++      u8 *aOld;
    ++      int nNew;
    ++      u8 *aNew;
    ++
    ++      aOld = sessionMergeValue(&aOld1, &aOld2, &nOld);
    ++      aNew = sessionMergeValue(&aNew1, &aNew2, &nNew);
    ++      if( pTab->abPK[i] || nOld!=nNew || memcmp(aOld, aNew, nNew) ){
    ++        if( pTab->abPK[i]==0 ) bRequired = 1;
    ++        memcpy(aOut, aOld, nOld);
    ++        aOut += nOld;
    ++      }else{
    ++        *(aOut++) = '\0';
    ++      }
    ++    }
    ++
    ++    if( !bRequired ) return 0;
    ++  }
    ++
    ++  /* Write the new.* vector */
    ++  aOld1 = aOldRecord1;
    ++  aOld2 = aOldRecord2;
    ++  aNew1 = aNewRecord1;
    ++  aNew2 = aNewRecord2;
    ++  for(i=0; i<pTab->nCol; i++){
    ++    int nOld;
    ++    u8 *aOld;
    ++    int nNew;
    ++    u8 *aNew;
    ++
    ++    aOld = sessionMergeValue(&aOld1, &aOld2, &nOld);
    ++    aNew = sessionMergeValue(&aNew1, &aNew2, &nNew);
    ++    if( bPatchset==0 
    ++     && (pTab->abPK[i] || (nOld==nNew && 0==memcmp(aOld, aNew, nNew))) 
    ++    ){
    ++      *(aOut++) = '\0';
    ++    }else{
    ++      memcpy(aOut, aNew, nNew);
    ++      aOut += nNew;
    ++    }
    ++  }
    ++
    ++  *paOut = aOut;
    ++  return 1;
    ++}
    ++
    ++/*
    ++** This function is only called from within a pre-update-hook callback.
    ++** It determines if the current pre-update-hook change affects the same row
    ++** as the change stored in argument pChange. If so, it returns true. Otherwise
    ++** if the pre-update-hook does not affect the same row as pChange, it returns
    ++** false.
    ++*/
    ++static int sessionPreupdateEqual(
    ++  sqlite3_session *pSession,      /* Session object that owns SessionTable */
    ++  SessionTable *pTab,             /* Table associated with change */
    ++  SessionChange *pChange,         /* Change to compare to */
    ++  int op                          /* Current pre-update operation */
    ++){
    ++  int iCol;                       /* Used to iterate through columns */
    ++  u8 *a = pChange->aRecord;       /* Cursor used to scan change record */
    ++
    ++  assert( op==SQLITE_INSERT || op==SQLITE_UPDATE || op==SQLITE_DELETE );
    ++  for(iCol=0; iCol<pTab->nCol; iCol++){
    ++    if( !pTab->abPK[iCol] ){
    ++      a += sessionSerialLen(a);
    ++    }else{
    ++      sqlite3_value *pVal;        /* Value returned by preupdate_new/old */
    ++      int rc;                     /* Error code from preupdate_new/old */
    ++      int eType = *a++;           /* Type of value from change record */
    ++
    ++      /* The following calls to preupdate_new() and preupdate_old() can not
    ++      ** fail. This is because they cache their return values, and by the
    ++      ** time control flows to here they have already been called once from
    ++      ** within sessionPreupdateHash(). The first two asserts below verify
    ++      ** this (that the method has already been called). */
    ++      if( op==SQLITE_INSERT ){
    ++        /* assert( db->pPreUpdate->pNewUnpacked || db->pPreUpdate->aNew ); */
    ++        rc = pSession->hook.xNew(pSession->hook.pCtx, iCol, &pVal);
    ++      }else{
    ++        /* assert( db->pPreUpdate->pUnpacked ); */
    ++        rc = pSession->hook.xOld(pSession->hook.pCtx, iCol, &pVal);
    ++      }
    ++      assert( rc==SQLITE_OK );
    ++      if( sqlite3_value_type(pVal)!=eType ) return 0;
    ++
    ++      /* A SessionChange object never has a NULL value in a PK column */
    ++      assert( eType==SQLITE_INTEGER || eType==SQLITE_FLOAT
    ++           || eType==SQLITE_BLOB    || eType==SQLITE_TEXT
    ++      );
    ++
    ++      if( eType==SQLITE_INTEGER || eType==SQLITE_FLOAT ){
    ++        i64 iVal = sessionGetI64(a);
    ++        a += 8;
    ++        if( eType==SQLITE_INTEGER ){
    ++          if( sqlite3_value_int64(pVal)!=iVal ) return 0;
    ++        }else{
    ++          double rVal;
    ++          assert( sizeof(iVal)==8 && sizeof(rVal)==8 );
    ++          memcpy(&rVal, &iVal, 8);
    ++          if( sqlite3_value_double(pVal)!=rVal ) return 0;
    ++        }
    ++      }else{
    ++        int n;
    ++        const u8 *z;
    ++        a += sessionVarintGet(a, &n);
    ++        if( sqlite3_value_bytes(pVal)!=n ) return 0;
    ++        if( eType==SQLITE_TEXT ){
    ++          z = sqlite3_value_text(pVal);
    ++        }else{
    ++          z = sqlite3_value_blob(pVal);
    ++        }
    ++        if( memcmp(a, z, n) ) return 0;
    ++        a += n;
    ++      }
    ++    }
    ++  }
    ++
    ++  return 1;
    ++}
    ++
    ++/*
    ++** If required, grow the hash table used to store changes on table pTab 
    ++** (part of the session pSession). If a fatal OOM error occurs, set the
    ++** session object to failed and return SQLITE_ERROR. Otherwise, return
    ++** SQLITE_OK.
    ++**
    ++** It is possible that a non-fatal OOM error occurs in this function. In
    ++** that case the hash-table does not grow, but SQLITE_OK is returned anyway.
    ++** Growing the hash table in this case is a performance optimization only,
    ++** it is not required for correct operation.
    ++*/
    ++static int sessionGrowHash(int bPatchset, SessionTable *pTab){
    ++  if( pTab->nChange==0 || pTab->nEntry>=(pTab->nChange/2) ){
    ++    int i;
    ++    SessionChange **apNew;
    ++    int nNew = (pTab->nChange ? pTab->nChange : 128) * 2;
    ++
    ++    apNew = (SessionChange **)sqlite3_malloc(sizeof(SessionChange *) * nNew);
    ++    if( apNew==0 ){
    ++      if( pTab->nChange==0 ){
    ++        return SQLITE_ERROR;
    ++      }
    ++      return SQLITE_OK;
    ++    }
    ++    memset(apNew, 0, sizeof(SessionChange *) * nNew);
    ++
    ++    for(i=0; i<pTab->nChange; i++){
    ++      SessionChange *p;
    ++      SessionChange *pNext;
    ++      for(p=pTab->apChange[i]; p; p=pNext){
    ++        int bPkOnly = (p->op==SQLITE_DELETE && bPatchset);
    ++        int iHash = sessionChangeHash(pTab, bPkOnly, p->aRecord, nNew);
    ++        pNext = p->pNext;
    ++        p->pNext = apNew[iHash];
    ++        apNew[iHash] = p;
    ++      }
    ++    }
    ++
    ++    sqlite3_free(pTab->apChange);
    ++    pTab->nChange = nNew;
    ++    pTab->apChange = apNew;
    ++  }
    ++
    ++  return SQLITE_OK;
    ++}
    ++
    ++/*
    ++** This function queries the database for the names of the columns of table
    ++** zThis, in schema zDb.
    ++**
    ++** Otherwise, if they are not NULL, variable *pnCol is set to the number
    ++** of columns in the database table and variable *pzTab is set to point to a
    ++** nul-terminated copy of the table name. *pazCol (if not NULL) is set to
    ++** point to an array of pointers to column names. And *pabPK (again, if not
    ++** NULL) is set to point to an array of booleans - true if the corresponding
    ++** column is part of the primary key.
    ++**
    ++** For example, if the table is declared as:
    ++**
    ++**     CREATE TABLE tbl1(w, x, y, z, PRIMARY KEY(w, z));
    ++**
    ++** Then the four output variables are populated as follows:
    ++**
    ++**     *pnCol  = 4
    ++**     *pzTab  = "tbl1"
    ++**     *pazCol = {"w", "x", "y", "z"}
    ++**     *pabPK  = {1, 0, 0, 1}
    ++**
    ++** All returned buffers are part of the same single allocation, which must
    ++** be freed using sqlite3_free() by the caller
    ++*/
    ++static int sessionTableInfo(
    ++  sqlite3 *db,                    /* Database connection */
    ++  const char *zDb,                /* Name of attached database (e.g. "main") */
    ++  const char *zThis,              /* Table name */
    ++  int *pnCol,                     /* OUT: number of columns */
    ++  const char **pzTab,             /* OUT: Copy of zThis */
    ++  const char ***pazCol,           /* OUT: Array of column names for table */
    ++  u8 **pabPK                      /* OUT: Array of booleans - true for PK col */
    ++){
    ++  char *zPragma;
    ++  sqlite3_stmt *pStmt;
    ++  int rc;
    ++  int nByte;
    ++  int nDbCol = 0;
    ++  int nThis;
    ++  int i;
    ++  u8 *pAlloc = 0;
    ++  char **azCol = 0;
    ++  u8 *abPK = 0;
    ++
    ++  assert( pazCol && pabPK );
    ++
    ++  nThis = sqlite3Strlen30(zThis);
    ++  if( nThis==12 && 0==sqlite3_stricmp("sqlite_stat1", zThis) ){
    ++    rc = sqlite3_table_column_metadata(db, zDb, zThis, 0, 0, 0, 0, 0, 0);
    ++    if( rc==SQLITE_OK ){
    ++      /* For sqlite_stat1, pretend that (tbl,idx) is the PRIMARY KEY. */
    ++      zPragma = sqlite3_mprintf(
    ++          "SELECT 0, 'tbl',  '', 0, '', 1     UNION ALL "
    ++          "SELECT 1, 'idx',  '', 0, '', 2     UNION ALL "
    ++          "SELECT 2, 'stat', '', 0, '', 0"
    ++      );
    ++    }else if( rc==SQLITE_ERROR ){
    ++      zPragma = sqlite3_mprintf("");
    ++    }else{
    ++      return rc;
    ++    }
    ++  }else{
    ++    zPragma = sqlite3_mprintf("PRAGMA '%q'.table_info('%q')", zDb, zThis);
    ++  }
    ++  if( !zPragma ) return SQLITE_NOMEM;
    ++
    ++  rc = sqlite3_prepare_v2(db, zPragma, -1, &pStmt, 0);
    ++  sqlite3_free(zPragma);
    ++  if( rc!=SQLITE_OK ) return rc;
    ++
    ++  nByte = nThis + 1;
    ++  while( SQLITE_ROW==sqlite3_step(pStmt) ){
    ++    nByte += sqlite3_column_bytes(pStmt, 1);
    ++    nDbCol++;
    ++  }
    ++  rc = sqlite3_reset(pStmt);
    ++
    ++  if( rc==SQLITE_OK ){
    ++    nByte += nDbCol * (sizeof(const char *) + sizeof(u8) + 1);
    ++    pAlloc = sqlite3_malloc(nByte);
    ++    if( pAlloc==0 ){
    ++      rc = SQLITE_NOMEM;
    ++    }
    ++  }
    ++  if( rc==SQLITE_OK ){
    ++    azCol = (char **)pAlloc;
    ++    pAlloc = (u8 *)&azCol[nDbCol];
    ++    abPK = (u8 *)pAlloc;
    ++    pAlloc = &abPK[nDbCol];
    ++    if( pzTab ){
    ++      memcpy(pAlloc, zThis, nThis+1);
    ++      *pzTab = (char *)pAlloc;
    ++      pAlloc += nThis+1;
    ++    }
    ++  
    ++    i = 0;
    ++    while( SQLITE_ROW==sqlite3_step(pStmt) ){
    ++      int nName = sqlite3_column_bytes(pStmt, 1);
    ++      const unsigned char *zName = sqlite3_column_text(pStmt, 1);
    ++      if( zName==0 ) break;
    ++      memcpy(pAlloc, zName, nName+1);
    ++      azCol[i] = (char *)pAlloc;
    ++      pAlloc += nName+1;
    ++      abPK[i] = sqlite3_column_int(pStmt, 5);
    ++      i++;
    ++    }
    ++    rc = sqlite3_reset(pStmt);
    ++  
    ++  }
    ++
    ++  /* If successful, populate the output variables. Otherwise, zero them and
    ++  ** free any allocation made. An error code will be returned in this case.
    ++  */
    ++  if( rc==SQLITE_OK ){
    ++    *pazCol = (const char **)azCol;
    ++    *pabPK = abPK;
    ++    *pnCol = nDbCol;
    ++  }else{
    ++    *pazCol = 0;
    ++    *pabPK = 0;
    ++    *pnCol = 0;
    ++    if( pzTab ) *pzTab = 0;
    ++    sqlite3_free(azCol);
    ++  }
    ++  sqlite3_finalize(pStmt);
    ++  return rc;
    ++}
    ++
    ++/*
    ++** This function is only called from within a pre-update handler for a
    ++** write to table pTab, part of session pSession. If this is the first
    ++** write to this table, initalize the SessionTable.nCol, azCol[] and
    ++** abPK[] arrays accordingly.
    ++**
    ++** If an error occurs, an error code is stored in sqlite3_session.rc and
    ++** non-zero returned. Or, if no error occurs but the table has no primary
    ++** key, sqlite3_session.rc is left set to SQLITE_OK and non-zero returned to
    ++** indicate that updates on this table should be ignored. SessionTable.abPK 
    ++** is set to NULL in this case.
    ++*/
    ++static int sessionInitTable(sqlite3_session *pSession, SessionTable *pTab){
    ++  if( pTab->nCol==0 ){
    ++    u8 *abPK;
    ++    assert( pTab->azCol==0 || pTab->abPK==0 );
    ++    pSession->rc = sessionTableInfo(pSession->db, pSession->zDb, 
    ++        pTab->zName, &pTab->nCol, 0, &pTab->azCol, &abPK
    ++    );
    ++    if( pSession->rc==SQLITE_OK ){
    ++      int i;
    ++      for(i=0; i<pTab->nCol; i++){
    ++        if( abPK[i] ){
    ++          pTab->abPK = abPK;
    ++          break;
    ++        }
    ++      }
    ++      if( 0==sqlite3_stricmp("sqlite_stat1", pTab->zName) ){
    ++        pTab->bStat1 = 1;
    ++      }
    ++    }
    ++  }
    ++  return (pSession->rc || pTab->abPK==0);
    ++}
    ++
    ++/*
    ++** Versions of the four methods in object SessionHook for use with the
    ++** sqlite_stat1 table. The purpose of this is to substitute a zero-length
    ++** blob each time a NULL value is read from the "idx" column of the
    ++** sqlite_stat1 table.
    ++*/
    ++typedef struct SessionStat1Ctx SessionStat1Ctx;
    ++struct SessionStat1Ctx {
    ++  SessionHook hook;
    ++  sqlite3_session *pSession;
    ++};
    ++static int sessionStat1Old(void *pCtx, int iCol, sqlite3_value **ppVal){
    ++  SessionStat1Ctx *p = (SessionStat1Ctx*)pCtx;
    ++  sqlite3_value *pVal = 0;
    ++  int rc = p->hook.xOld(p->hook.pCtx, iCol, &pVal);
    ++  if( rc==SQLITE_OK && iCol==1 && sqlite3_value_type(pVal)==SQLITE_NULL ){
    ++    pVal = p->pSession->pZeroBlob;
    ++  }
    ++  *ppVal = pVal;
    ++  return rc;
    ++}
    ++static int sessionStat1New(void *pCtx, int iCol, sqlite3_value **ppVal){
    ++  SessionStat1Ctx *p = (SessionStat1Ctx*)pCtx;
    ++  sqlite3_value *pVal = 0;
    ++  int rc = p->hook.xNew(p->hook.pCtx, iCol, &pVal);
    ++  if( rc==SQLITE_OK && iCol==1 && sqlite3_value_type(pVal)==SQLITE_NULL ){
    ++    pVal = p->pSession->pZeroBlob;
    ++  }
    ++  *ppVal = pVal;
    ++  return rc;
    ++}
    ++static int sessionStat1Count(void *pCtx){
    ++  SessionStat1Ctx *p = (SessionStat1Ctx*)pCtx;
    ++  return p->hook.xCount(p->hook.pCtx);
    ++}
    ++static int sessionStat1Depth(void *pCtx){
    ++  SessionStat1Ctx *p = (SessionStat1Ctx*)pCtx;
    ++  return p->hook.xDepth(p->hook.pCtx);
    ++}
    ++
    ++
    ++/*
    ++** This function is only called from with a pre-update-hook reporting a 
    ++** change on table pTab (attached to session pSession). The type of change
    ++** (UPDATE, INSERT, DELETE) is specified by the first argument.
    ++**
    ++** Unless one is already present or an error occurs, an entry is added
    ++** to the changed-rows hash table associated with table pTab.
    ++*/
    ++static void sessionPreupdateOneChange(
    ++  int op,                         /* One of SQLITE_UPDATE, INSERT, DELETE */
    ++  sqlite3_session *pSession,      /* Session object pTab is attached to */
    ++  SessionTable *pTab              /* Table that change applies to */
    ++){
    ++  int iHash; 
    ++  int bNull = 0; 
    ++  int rc = SQLITE_OK;
    ++  SessionStat1Ctx stat1;
    ++
    ++  if( pSession->rc ) return;
    ++
    ++  /* Load table details if required */
    ++  if( sessionInitTable(pSession, pTab) ) return;
    ++
    ++  /* Check the number of columns in this xPreUpdate call matches the 
    ++  ** number of columns in the table.  */
    ++  if( pTab->nCol!=pSession->hook.xCount(pSession->hook.pCtx) ){
    ++    pSession->rc = SQLITE_SCHEMA;
    ++    return;
    ++  }
    ++
    ++  /* Grow the hash table if required */
    ++  if( sessionGrowHash(0, pTab) ){
    ++    pSession->rc = SQLITE_NOMEM;
    ++    return;
    ++  }
    ++
    ++  if( pTab->bStat1 ){
    ++    stat1.hook = pSession->hook;
    ++    stat1.pSession = pSession;
    ++    pSession->hook.pCtx = (void*)&stat1;
    ++    pSession->hook.xNew = sessionStat1New;
    ++    pSession->hook.xOld = sessionStat1Old;
    ++    pSession->hook.xCount = sessionStat1Count;
    ++    pSession->hook.xDepth = sessionStat1Depth;
    ++    if( pSession->pZeroBlob==0 ){
    ++      sqlite3_value *p = sqlite3ValueNew(0);
    ++      if( p==0 ){
    ++        rc = SQLITE_NOMEM;
    ++        goto error_out;
    ++      }
    ++      sqlite3ValueSetStr(p, 0, "", 0, SQLITE_STATIC);
    ++      pSession->pZeroBlob = p;
    ++    }
    ++  }
    ++
    ++  /* Calculate the hash-key for this change. If the primary key of the row
    ++  ** includes a NULL value, exit early. Such changes are ignored by the
    ++  ** session module. */
    ++  rc = sessionPreupdateHash(pSession, pTab, op==SQLITE_INSERT, &iHash, &bNull);
    ++  if( rc!=SQLITE_OK ) goto error_out;
    ++
    ++  if( bNull==0 ){
    ++    /* Search the hash table for an existing record for this row. */
    ++    SessionChange *pC;
    ++    for(pC=pTab->apChange[iHash]; pC; pC=pC->pNext){
    ++      if( sessionPreupdateEqual(pSession, pTab, pC, op) ) break;
    ++    }
    ++
    ++    if( pC==0 ){
    ++      /* Create a new change object containing all the old values (if
    ++      ** this is an SQLITE_UPDATE or SQLITE_DELETE), or just the PK
    ++      ** values (if this is an INSERT). */
    ++      SessionChange *pChange; /* New change object */
    ++      int nByte;              /* Number of bytes to allocate */
    ++      int i;                  /* Used to iterate through columns */
    ++  
    ++      assert( rc==SQLITE_OK );
    ++      pTab->nEntry++;
    ++  
    ++      /* Figure out how large an allocation is required */
    ++      nByte = sizeof(SessionChange);
    ++      for(i=0; i<pTab->nCol; i++){
    ++        sqlite3_value *p = 0;
    ++        if( op!=SQLITE_INSERT ){
    ++          TESTONLY(int trc = ) pSession->hook.xOld(pSession->hook.pCtx, i, &p);
    ++          assert( trc==SQLITE_OK );
    ++        }else if( pTab->abPK[i] ){
    ++          TESTONLY(int trc = ) pSession->hook.xNew(pSession->hook.pCtx, i, &p);
    ++          assert( trc==SQLITE_OK );
    ++        }
    ++
    ++        /* This may fail if SQLite value p contains a utf-16 string that must
    ++        ** be converted to utf-8 and an OOM error occurs while doing so. */
    ++        rc = sessionSerializeValue(0, p, &nByte);
    ++        if( rc!=SQLITE_OK ) goto error_out;
    ++      }
    ++  
    ++      /* Allocate the change object */
    ++      pChange = (SessionChange *)sqlite3_malloc(nByte);
    ++      if( !pChange ){
    ++        rc = SQLITE_NOMEM;
    ++        goto error_out;
    ++      }else{
    ++        memset(pChange, 0, sizeof(SessionChange));
    ++        pChange->aRecord = (u8 *)&pChange[1];
    ++      }
    ++  
    ++      /* Populate the change object. None of the preupdate_old(),
    ++      ** preupdate_new() or SerializeValue() calls below may fail as all
    ++      ** required values and encodings have already been cached in memory.
    ++      ** It is not possible for an OOM to occur in this block. */
    ++      nByte = 0;
    ++      for(i=0; i<pTab->nCol; i++){
    ++        sqlite3_value *p = 0;
    ++        if( op!=SQLITE_INSERT ){
    ++          pSession->hook.xOld(pSession->hook.pCtx, i, &p);
    ++        }else if( pTab->abPK[i] ){
    ++          pSession->hook.xNew(pSession->hook.pCtx, i, &p);
    ++        }
    ++        sessionSerializeValue(&pChange->aRecord[nByte], p, &nByte);
    ++      }
    ++
    ++      /* Add the change to the hash-table */
    ++      if( pSession->bIndirect || pSession->hook.xDepth(pSession->hook.pCtx) ){
    ++        pChange->bIndirect = 1;
    ++      }
    ++      pChange->nRecord = nByte;
    ++      pChange->op = op;
    ++      pChange->pNext = pTab->apChange[iHash];
    ++      pTab->apChange[iHash] = pChange;
    ++
    ++    }else if( pC->bIndirect ){
    ++      /* If the existing change is considered "indirect", but this current
    ++      ** change is "direct", mark the change object as direct. */
    ++      if( pSession->hook.xDepth(pSession->hook.pCtx)==0 
    ++       && pSession->bIndirect==0 
    ++      ){
    ++        pC->bIndirect = 0;
    ++      }
    ++    }
    ++  }
    ++
    ++  /* If an error has occurred, mark the session object as failed. */
    ++ error_out:
    ++  if( pTab->bStat1 ){
    ++    pSession->hook = stat1.hook;
    ++  }
    ++  if( rc!=SQLITE_OK ){
    ++    pSession->rc = rc;
    ++  }
    ++}
    ++
    ++static int sessionFindTable(
    ++  sqlite3_session *pSession, 
    ++  const char *zName,
    ++  SessionTable **ppTab
    ++){
    ++  int rc = SQLITE_OK;
    ++  int nName = sqlite3Strlen30(zName);
    ++  SessionTable *pRet;
    ++
    ++  /* Search for an existing table */
    ++  for(pRet=pSession->pTable; pRet; pRet=pRet->pNext){
    ++    if( 0==sqlite3_strnicmp(pRet->zName, zName, nName+1) ) break;
    ++  }
    ++
    ++  if( pRet==0 && pSession->bAutoAttach ){
    ++    /* If there is a table-filter configured, invoke it. If it returns 0,
    ++    ** do not automatically add the new table. */
    ++    if( pSession->xTableFilter==0
    ++     || pSession->xTableFilter(pSession->pFilterCtx, zName) 
    ++    ){
    ++      rc = sqlite3session_attach(pSession, zName);
    ++      if( rc==SQLITE_OK ){
    ++        for(pRet=pSession->pTable; pRet->pNext; pRet=pRet->pNext);
    ++        assert( 0==sqlite3_strnicmp(pRet->zName, zName, nName+1) );
    ++      }
    ++    }
    ++  }
    ++
    ++  assert( rc==SQLITE_OK || pRet==0 );
    ++  *ppTab = pRet;
    ++  return rc;
    ++}
    ++
    ++/*
    ++** The 'pre-update' hook registered by this module with SQLite databases.
    ++*/
    ++static void xPreUpdate(
    ++  void *pCtx,                     /* Copy of third arg to preupdate_hook() */
    ++  sqlite3 *db,                    /* Database handle */
    ++  int op,                         /* SQLITE_UPDATE, DELETE or INSERT */
    ++  char const *zDb,                /* Database name */
    ++  char const *zName,              /* Table name */
    ++  sqlite3_int64 iKey1,            /* Rowid of row about to be deleted/updated */
    ++  sqlite3_int64 iKey2             /* New rowid value (for a rowid UPDATE) */
    ++){
    ++  sqlite3_session *pSession;
    ++  int nDb = sqlite3Strlen30(zDb);
    ++
    ++  assert( sqlite3_mutex_held(db->mutex) );
    ++
    ++  for(pSession=(sqlite3_session *)pCtx; pSession; pSession=pSession->pNext){
    ++    SessionTable *pTab;
    ++
    ++    /* If this session is attached to a different database ("main", "temp" 
    ++    ** etc.), or if it is not currently enabled, there is nothing to do. Skip 
    ++    ** to the next session object attached to this database. */
    ++    if( pSession->bEnable==0 ) continue;
    ++    if( pSession->rc ) continue;
    ++    if( sqlite3_strnicmp(zDb, pSession->zDb, nDb+1) ) continue;
    ++
    ++    pSession->rc = sessionFindTable(pSession, zName, &pTab);
    ++    if( pTab ){
    ++      assert( pSession->rc==SQLITE_OK );
    ++      sessionPreupdateOneChange(op, pSession, pTab);
    ++      if( op==SQLITE_UPDATE ){
    ++        sessionPreupdateOneChange(SQLITE_INSERT, pSession, pTab);
    ++      }
    ++    }
    ++  }
    ++}
    ++
    ++/*
    ++** The pre-update hook implementations.
    ++*/
    ++static int sessionPreupdateOld(void *pCtx, int iVal, sqlite3_value **ppVal){
    ++  return sqlite3_preupdate_old((sqlite3*)pCtx, iVal, ppVal);
    ++}
    ++static int sessionPreupdateNew(void *pCtx, int iVal, sqlite3_value **ppVal){
    ++  return sqlite3_preupdate_new((sqlite3*)pCtx, iVal, ppVal);
    ++}
    ++static int sessionPreupdateCount(void *pCtx){
    ++  return sqlite3_preupdate_count((sqlite3*)pCtx);
    ++}
    ++static int sessionPreupdateDepth(void *pCtx){
    ++  return sqlite3_preupdate_depth((sqlite3*)pCtx);
    ++}
    ++
    ++/*
    ++** Install the pre-update hooks on the session object passed as the only
    ++** argument.
    ++*/
    ++static void sessionPreupdateHooks(
    ++  sqlite3_session *pSession
    ++){
    ++  pSession->hook.pCtx = (void*)pSession->db;
    ++  pSession->hook.xOld = sessionPreupdateOld;
    ++  pSession->hook.xNew = sessionPreupdateNew;
    ++  pSession->hook.xCount = sessionPreupdateCount;
    ++  pSession->hook.xDepth = sessionPreupdateDepth;
    ++}
    ++
    ++typedef struct SessionDiffCtx SessionDiffCtx;
    ++struct SessionDiffCtx {
    ++  sqlite3_stmt *pStmt;
    ++  int nOldOff;
    ++};
    ++
    ++/*
    ++** The diff hook implementations.
    ++*/
    ++static int sessionDiffOld(void *pCtx, int iVal, sqlite3_value **ppVal){
    ++  SessionDiffCtx *p = (SessionDiffCtx*)pCtx;
    ++  *ppVal = sqlite3_column_value(p->pStmt, iVal+p->nOldOff);
    ++  return SQLITE_OK;
    ++}
    ++static int sessionDiffNew(void *pCtx, int iVal, sqlite3_value **ppVal){
    ++  SessionDiffCtx *p = (SessionDiffCtx*)pCtx;
    ++  *ppVal = sqlite3_column_value(p->pStmt, iVal);
    ++   return SQLITE_OK;
    ++}
    ++static int sessionDiffCount(void *pCtx){
    ++  SessionDiffCtx *p = (SessionDiffCtx*)pCtx;
    ++  return p->nOldOff ? p->nOldOff : sqlite3_column_count(p->pStmt);
    ++}
    ++static int sessionDiffDepth(void *pCtx){
    ++  return 0;
    ++}
    ++
    ++/*
    ++** Install the diff hooks on the session object passed as the only
    ++** argument.
    ++*/
    ++static void sessionDiffHooks(
    ++  sqlite3_session *pSession,
    ++  SessionDiffCtx *pDiffCtx
    ++){
    ++  pSession->hook.pCtx = (void*)pDiffCtx;
    ++  pSession->hook.xOld = sessionDiffOld;
    ++  pSession->hook.xNew = sessionDiffNew;
    ++  pSession->hook.xCount = sessionDiffCount;
    ++  pSession->hook.xDepth = sessionDiffDepth;
    ++}
    ++
    ++static char *sessionExprComparePK(
    ++  int nCol,
    ++  const char *zDb1, const char *zDb2, 
    ++  const char *zTab,
    ++  const char **azCol, u8 *abPK
    ++){
    ++  int i;
    ++  const char *zSep = "";
    ++  char *zRet = 0;
    ++
    ++  for(i=0; i<nCol; i++){
    ++    if( abPK[i] ){
    ++      zRet = sqlite3_mprintf("%z%s\"%w\".\"%w\".\"%w\"=\"%w\".\"%w\".\"%w\"",
    ++          zRet, zSep, zDb1, zTab, azCol[i], zDb2, zTab, azCol[i]
    ++      );
    ++      zSep = " AND ";
    ++      if( zRet==0 ) break;
    ++    }
    ++  }
    ++
    ++  return zRet;
    ++}
    ++
    ++static char *sessionExprCompareOther(
    ++  int nCol,
    ++  const char *zDb1, const char *zDb2, 
    ++  const char *zTab,
    ++  const char **azCol, u8 *abPK
    ++){
    ++  int i;
    ++  const char *zSep = "";
    ++  char *zRet = 0;
    ++  int bHave = 0;
    ++
    ++  for(i=0; i<nCol; i++){
    ++    if( abPK[i]==0 ){
    ++      bHave = 1;
    ++      zRet = sqlite3_mprintf(
    ++          "%z%s\"%w\".\"%w\".\"%w\" IS NOT \"%w\".\"%w\".\"%w\"",
    ++          zRet, zSep, zDb1, zTab, azCol[i], zDb2, zTab, azCol[i]
    ++      );
    ++      zSep = " OR ";
    ++      if( zRet==0 ) break;
    ++    }
    ++  }
    ++
    ++  if( bHave==0 ){
    ++    assert( zRet==0 );
    ++    zRet = sqlite3_mprintf("0");
    ++  }
    ++
    ++  return zRet;
    ++}
    ++
    ++static char *sessionSelectFindNew(
    ++  int nCol,
    ++  const char *zDb1,      /* Pick rows in this db only */
    ++  const char *zDb2,      /* But not in this one */
    ++  const char *zTbl,      /* Table name */
    ++  const char *zExpr
    ++){
    ++  char *zRet = sqlite3_mprintf(
    ++      "SELECT * FROM \"%w\".\"%w\" WHERE NOT EXISTS ("
    ++      "  SELECT 1 FROM \"%w\".\"%w\" WHERE %s"
    ++      ")",
    ++      zDb1, zTbl, zDb2, zTbl, zExpr
    ++  );
    ++  return zRet;
    ++}
    ++
    ++static int sessionDiffFindNew(
    ++  int op,
    ++  sqlite3_session *pSession,
    ++  SessionTable *pTab,
    ++  const char *zDb1,
    ++  const char *zDb2,
    ++  char *zExpr
    ++){
    ++  int rc = SQLITE_OK;
    ++  char *zStmt = sessionSelectFindNew(pTab->nCol, zDb1, zDb2, pTab->zName,zExpr);
    ++
    ++  if( zStmt==0 ){
    ++    rc = SQLITE_NOMEM;
    ++  }else{
    ++    sqlite3_stmt *pStmt;
    ++    rc = sqlite3_prepare(pSession->db, zStmt, -1, &pStmt, 0);
    ++    if( rc==SQLITE_OK ){
    ++      SessionDiffCtx *pDiffCtx = (SessionDiffCtx*)pSession->hook.pCtx;
    ++      pDiffCtx->pStmt = pStmt;
    ++      pDiffCtx->nOldOff = 0;
    ++      while( SQLITE_ROW==sqlite3_step(pStmt) ){
    ++        sessionPreupdateOneChange(op, pSession, pTab);
    ++      }
    ++      rc = sqlite3_finalize(pStmt);
    ++    }
    ++    sqlite3_free(zStmt);
    ++  }
    ++
    ++  return rc;
    ++}
    ++
    ++static int sessionDiffFindModified(
    ++  sqlite3_session *pSession, 
    ++  SessionTable *pTab, 
    ++  const char *zFrom, 
    ++  const char *zExpr
    ++){
    ++  int rc = SQLITE_OK;
    ++
    ++  char *zExpr2 = sessionExprCompareOther(pTab->nCol,
    ++      pSession->zDb, zFrom, pTab->zName, pTab->azCol, pTab->abPK
    ++  );
    ++  if( zExpr2==0 ){
    ++    rc = SQLITE_NOMEM;
    ++  }else{
    ++    char *zStmt = sqlite3_mprintf(
    ++        "SELECT * FROM \"%w\".\"%w\", \"%w\".\"%w\" WHERE %s AND (%z)",
    ++        pSession->zDb, pTab->zName, zFrom, pTab->zName, zExpr, zExpr2
    ++    );
    ++    if( zStmt==0 ){
    ++      rc = SQLITE_NOMEM;
    ++    }else{
    ++      sqlite3_stmt *pStmt;
    ++      rc = sqlite3_prepare(pSession->db, zStmt, -1, &pStmt, 0);
    ++
    ++      if( rc==SQLITE_OK ){
    ++        SessionDiffCtx *pDiffCtx = (SessionDiffCtx*)pSession->hook.pCtx;
    ++        pDiffCtx->pStmt = pStmt;
    ++        pDiffCtx->nOldOff = pTab->nCol;
    ++        while( SQLITE_ROW==sqlite3_step(pStmt) ){
    ++          sessionPreupdateOneChange(SQLITE_UPDATE, pSession, pTab);
    ++        }
    ++        rc = sqlite3_finalize(pStmt);
    ++      }
    ++      sqlite3_free(zStmt);
    ++    }
    ++  }
    ++
    ++  return rc;
    ++}
    ++
    ++SQLITE_API int sqlite3session_diff(
    ++  sqlite3_session *pSession,
    ++  const char *zFrom,
    ++  const char *zTbl,
    ++  char **pzErrMsg
    ++){
    ++  const char *zDb = pSession->zDb;
    ++  int rc = pSession->rc;
    ++  SessionDiffCtx d;
    ++
    ++  memset(&d, 0, sizeof(d));
    ++  sessionDiffHooks(pSession, &d);
    ++
    ++  sqlite3_mutex_enter(sqlite3_db_mutex(pSession->db));
    ++  if( pzErrMsg ) *pzErrMsg = 0;
    ++  if( rc==SQLITE_OK ){
    ++    char *zExpr = 0;
    ++    sqlite3 *db = pSession->db;
    ++    SessionTable *pTo;            /* Table zTbl */
    ++
    ++    /* Locate and if necessary initialize the target table object */
    ++    rc = sessionFindTable(pSession, zTbl, &pTo);
    ++    if( pTo==0 ) goto diff_out;
    ++    if( sessionInitTable(pSession, pTo) ){
    ++      rc = pSession->rc;
    ++      goto diff_out;
    ++    }
    ++
    ++    /* Check the table schemas match */
    ++    if( rc==SQLITE_OK ){
    ++      int bHasPk = 0;
    ++      int bMismatch = 0;
    ++      int nCol;                   /* Columns in zFrom.zTbl */
    ++      u8 *abPK;
    ++      const char **azCol = 0;
    ++      rc = sessionTableInfo(db, zFrom, zTbl, &nCol, 0, &azCol, &abPK);
    ++      if( rc==SQLITE_OK ){
    ++        if( pTo->nCol!=nCol ){
    ++          bMismatch = 1;
    ++        }else{
    ++          int i;
    ++          for(i=0; i<nCol; i++){
    ++            if( pTo->abPK[i]!=abPK[i] ) bMismatch = 1;
    ++            if( sqlite3_stricmp(azCol[i], pTo->azCol[i]) ) bMismatch = 1;
    ++            if( abPK[i] ) bHasPk = 1;
    ++          }
    ++        }
    ++      }
    ++      sqlite3_free((char*)azCol);
    ++      if( bMismatch ){
    ++        *pzErrMsg = sqlite3_mprintf("table schemas do not match");
    ++        rc = SQLITE_SCHEMA;
    ++      }
    ++      if( bHasPk==0 ){
    ++        /* Ignore tables with no primary keys */
    ++        goto diff_out;
    ++      }
    ++    }
    ++
    ++    if( rc==SQLITE_OK ){
    ++      zExpr = sessionExprComparePK(pTo->nCol, 
    ++          zDb, zFrom, pTo->zName, pTo->azCol, pTo->abPK
    ++      );
    ++    }
    ++
    ++    /* Find new rows */
    ++    if( rc==SQLITE_OK ){
    ++      rc = sessionDiffFindNew(SQLITE_INSERT, pSession, pTo, zDb, zFrom, zExpr);
    ++    }
    ++
    ++    /* Find old rows */
    ++    if( rc==SQLITE_OK ){
    ++      rc = sessionDiffFindNew(SQLITE_DELETE, pSession, pTo, zFrom, zDb, zExpr);
    ++    }
    ++
    ++    /* Find modified rows */
    ++    if( rc==SQLITE_OK ){
    ++      rc = sessionDiffFindModified(pSession, pTo, zFrom, zExpr);
    ++    }
    ++
    ++    sqlite3_free(zExpr);
    ++  }
    ++
    ++ diff_out:
    ++  sessionPreupdateHooks(pSession);
    ++  sqlite3_mutex_leave(sqlite3_db_mutex(pSession->db));
    ++  return rc;
    ++}
    ++
    ++/*
    ++** Create a session object. This session object will record changes to
    ++** database zDb attached to connection db.
    ++*/
    ++SQLITE_API int sqlite3session_create(
    ++  sqlite3 *db,                    /* Database handle */
    ++  const char *zDb,                /* Name of db (e.g. "main") */
    ++  sqlite3_session **ppSession     /* OUT: New session object */
    ++){
    ++  sqlite3_session *pNew;          /* Newly allocated session object */
    ++  sqlite3_session *pOld;          /* Session object already attached to db */
    ++  int nDb = sqlite3Strlen30(zDb); /* Length of zDb in bytes */
    ++
    ++  /* Zero the output value in case an error occurs. */
    ++  *ppSession = 0;
    ++
    ++  /* Allocate and populate the new session object. */
    ++  pNew = (sqlite3_session *)sqlite3_malloc(sizeof(sqlite3_session) + nDb + 1);
    ++  if( !pNew ) return SQLITE_NOMEM;
    ++  memset(pNew, 0, sizeof(sqlite3_session));
    ++  pNew->db = db;
    ++  pNew->zDb = (char *)&pNew[1];
    ++  pNew->bEnable = 1;
    ++  memcpy(pNew->zDb, zDb, nDb+1);
    ++  sessionPreupdateHooks(pNew);
    ++
    ++  /* Add the new session object to the linked list of session objects 
    ++  ** attached to database handle $db. Do this under the cover of the db
    ++  ** handle mutex.  */
    ++  sqlite3_mutex_enter(sqlite3_db_mutex(db));
    ++  pOld = (sqlite3_session*)sqlite3_preupdate_hook(db, xPreUpdate, (void*)pNew);
    ++  pNew->pNext = pOld;
    ++  sqlite3_mutex_leave(sqlite3_db_mutex(db));
    ++
    ++  *ppSession = pNew;
    ++  return SQLITE_OK;
    ++}
    ++
    ++/*
    ++** Free the list of table objects passed as the first argument. The contents
    ++** of the changed-rows hash tables are also deleted.
    ++*/
    ++static void sessionDeleteTable(SessionTable *pList){
    ++  SessionTable *pNext;
    ++  SessionTable *pTab;
    ++
    ++  for(pTab=pList; pTab; pTab=pNext){
    ++    int i;
    ++    pNext = pTab->pNext;
    ++    for(i=0; i<pTab->nChange; i++){
    ++      SessionChange *p;
    ++      SessionChange *pNextChange;
    ++      for(p=pTab->apChange[i]; p; p=pNextChange){
    ++        pNextChange = p->pNext;
    ++        sqlite3_free(p);
    ++      }
    ++    }
    ++    sqlite3_free((char*)pTab->azCol);  /* cast works around VC++ bug */
    ++    sqlite3_free(pTab->apChange);
    ++    sqlite3_free(pTab);
    ++  }
    ++}
    ++
    ++/*
    ++** Delete a session object previously allocated using sqlite3session_create().
    ++*/
    ++SQLITE_API void sqlite3session_delete(sqlite3_session *pSession){
    ++  sqlite3 *db = pSession->db;
    ++  sqlite3_session *pHead;
    ++  sqlite3_session **pp;
    ++
    ++  /* Unlink the session from the linked list of sessions attached to the
    ++  ** database handle. Hold the db mutex while doing so.  */
    ++  sqlite3_mutex_enter(sqlite3_db_mutex(db));
    ++  pHead = (sqlite3_session*)sqlite3_preupdate_hook(db, 0, 0);
    ++  for(pp=&pHead; ALWAYS((*pp)!=0); pp=&((*pp)->pNext)){
    ++    if( (*pp)==pSession ){
    ++      *pp = (*pp)->pNext;
    ++      if( pHead ) sqlite3_preupdate_hook(db, xPreUpdate, (void*)pHead);
    ++      break;
    ++    }
    ++  }
    ++  sqlite3_mutex_leave(sqlite3_db_mutex(db));
    ++  sqlite3ValueFree(pSession->pZeroBlob);
    ++
    ++  /* Delete all attached table objects. And the contents of their 
    ++  ** associated hash-tables. */
    ++  sessionDeleteTable(pSession->pTable);
    ++
    ++  /* Free the session object itself. */
    ++  sqlite3_free(pSession);
    ++}
    ++
    ++/*
    ++** Set a table filter on a Session Object.
    ++*/
    ++SQLITE_API void sqlite3session_table_filter(
    ++  sqlite3_session *pSession, 
    ++  int(*xFilter)(void*, const char*),
    ++  void *pCtx                      /* First argument passed to xFilter */
    ++){
    ++  pSession->bAutoAttach = 1;
    ++  pSession->pFilterCtx = pCtx;
    ++  pSession->xTableFilter = xFilter;
    ++}
    ++
    ++/*
    ++** Attach a table to a session. All subsequent changes made to the table
    ++** while the session object is enabled will be recorded.
    ++**
    ++** Only tables that have a PRIMARY KEY defined may be attached. It does
    ++** not matter if the PRIMARY KEY is an "INTEGER PRIMARY KEY" (rowid alias)
    ++** or not.
    ++*/
    ++SQLITE_API int sqlite3session_attach(
    ++  sqlite3_session *pSession,      /* Session object */
    ++  const char *zName               /* Table name */
    ++){
    ++  int rc = SQLITE_OK;
    ++  sqlite3_mutex_enter(sqlite3_db_mutex(pSession->db));
    ++
    ++  if( !zName ){
    ++    pSession->bAutoAttach = 1;
    ++  }else{
    ++    SessionTable *pTab;           /* New table object (if required) */
    ++    int nName;                    /* Number of bytes in string zName */
    ++
    ++    /* First search for an existing entry. If one is found, this call is
    ++    ** a no-op. Return early. */
    ++    nName = sqlite3Strlen30(zName);
    ++    for(pTab=pSession->pTable; pTab; pTab=pTab->pNext){
    ++      if( 0==sqlite3_strnicmp(pTab->zName, zName, nName+1) ) break;
    ++    }
    ++
    ++    if( !pTab ){
    ++      /* Allocate new SessionTable object. */
    ++      pTab = (SessionTable *)sqlite3_malloc(sizeof(SessionTable) + nName + 1);
    ++      if( !pTab ){
    ++        rc = SQLITE_NOMEM;
    ++      }else{
    ++        /* Populate the new SessionTable object and link it into the list.
    ++        ** The new object must be linked onto the end of the list, not 
    ++        ** simply added to the start of it in order to ensure that tables
    ++        ** appear in the correct order when a changeset or patchset is
    ++        ** eventually generated. */
    ++        SessionTable **ppTab;
    ++        memset(pTab, 0, sizeof(SessionTable));
    ++        pTab->zName = (char *)&pTab[1];
    ++        memcpy(pTab->zName, zName, nName+1);
    ++        for(ppTab=&pSession->pTable; *ppTab; ppTab=&(*ppTab)->pNext);
    ++        *ppTab = pTab;
    ++      }
    ++    }
    ++  }
    ++
    ++  sqlite3_mutex_leave(sqlite3_db_mutex(pSession->db));
    ++  return rc;
    ++}
    ++
    ++/*
    ++** Ensure that there is room in the buffer to append nByte bytes of data.
    ++** If not, use sqlite3_realloc() to grow the buffer so that there is.
    ++**
    ++** If successful, return zero. Otherwise, if an OOM condition is encountered,
    ++** set *pRc to SQLITE_NOMEM and return non-zero.
    ++*/
    ++static int sessionBufferGrow(SessionBuffer *p, int nByte, int *pRc){
    ++  if( *pRc==SQLITE_OK && p->nAlloc-p->nBuf<nByte ){
    ++    u8 *aNew;
    ++    int nNew = p->nAlloc ? p->nAlloc : 128;
    ++    do {
    ++      nNew = nNew*2;
    ++    }while( nNew<(p->nBuf+nByte) );
    ++
    ++    aNew = (u8 *)sqlite3_realloc(p->aBuf, nNew);
    ++    if( 0==aNew ){
    ++      *pRc = SQLITE_NOMEM;
    ++    }else{
    ++      p->aBuf = aNew;
    ++      p->nAlloc = nNew;
    ++    }
    ++  }
    ++  return (*pRc!=SQLITE_OK);
    ++}
    ++
    ++/*
    ++** Append the value passed as the second argument to the buffer passed
    ++** as the first.
    ++**
    ++** This function is a no-op if *pRc is non-zero when it is called.
    ++** Otherwise, if an error occurs, *pRc is set to an SQLite error code
    ++** before returning.
    ++*/
    ++static void sessionAppendValue(SessionBuffer *p, sqlite3_value *pVal, int *pRc){
    ++  int rc = *pRc;
    ++  if( rc==SQLITE_OK ){
    ++    int nByte = 0;
    ++    rc = sessionSerializeValue(0, pVal, &nByte);
    ++    sessionBufferGrow(p, nByte, &rc);
    ++    if( rc==SQLITE_OK ){
    ++      rc = sessionSerializeValue(&p->aBuf[p->nBuf], pVal, 0);
    ++      p->nBuf += nByte;
    ++    }else{
    ++      *pRc = rc;
    ++    }
    ++  }
    ++}
    ++
    ++/*
    ++** This function is a no-op if *pRc is other than SQLITE_OK when it is 
    ++** called. Otherwise, append a single byte to the buffer. 
    ++**
    ++** If an OOM condition is encountered, set *pRc to SQLITE_NOMEM before
    ++** returning.
    ++*/
    ++static void sessionAppendByte(SessionBuffer *p, u8 v, int *pRc){
    ++  if( 0==sessionBufferGrow(p, 1, pRc) ){
    ++    p->aBuf[p->nBuf++] = v;
    ++  }
    ++}
    ++
    ++/*
    ++** This function is a no-op if *pRc is other than SQLITE_OK when it is 
    ++** called. Otherwise, append a single varint to the buffer. 
    ++**
    ++** If an OOM condition is encountered, set *pRc to SQLITE_NOMEM before
    ++** returning.
    ++*/
    ++static void sessionAppendVarint(SessionBuffer *p, int v, int *pRc){
    ++  if( 0==sessionBufferGrow(p, 9, pRc) ){
    ++    p->nBuf += sessionVarintPut(&p->aBuf[p->nBuf], v);
    ++  }
    ++}
    ++
    ++/*
    ++** This function is a no-op if *pRc is other than SQLITE_OK when it is 
    ++** called. Otherwise, append a blob of data to the buffer. 
    ++**
    ++** If an OOM condition is encountered, set *pRc to SQLITE_NOMEM before
    ++** returning.
    ++*/
    ++static void sessionAppendBlob(
    ++  SessionBuffer *p, 
    ++  const u8 *aBlob, 
    ++  int nBlob, 
    ++  int *pRc
    ++){
    ++  if( nBlob>0 && 0==sessionBufferGrow(p, nBlob, pRc) ){
    ++    memcpy(&p->aBuf[p->nBuf], aBlob, nBlob);
    ++    p->nBuf += nBlob;
    ++  }
    ++}
    ++
    ++/*
    ++** This function is a no-op if *pRc is other than SQLITE_OK when it is 
    ++** called. Otherwise, append a string to the buffer. All bytes in the string
    ++** up to (but not including) the nul-terminator are written to the buffer.
    ++**
    ++** If an OOM condition is encountered, set *pRc to SQLITE_NOMEM before
    ++** returning.
    ++*/
    ++static void sessionAppendStr(
    ++  SessionBuffer *p, 
    ++  const char *zStr, 
    ++  int *pRc
    ++){
    ++  int nStr = sqlite3Strlen30(zStr);
    ++  if( 0==sessionBufferGrow(p, nStr, pRc) ){
    ++    memcpy(&p->aBuf[p->nBuf], zStr, nStr);
    ++    p->nBuf += nStr;
    ++  }
    ++}
    ++
    ++/*
    ++** This function is a no-op if *pRc is other than SQLITE_OK when it is 
    ++** called. Otherwise, append the string representation of integer iVal
    ++** to the buffer. No nul-terminator is written.
    ++**
    ++** If an OOM condition is encountered, set *pRc to SQLITE_NOMEM before
    ++** returning.
    ++*/
    ++static void sessionAppendInteger(
    ++  SessionBuffer *p,               /* Buffer to append to */
    ++  int iVal,                       /* Value to write the string rep. of */
    ++  int *pRc                        /* IN/OUT: Error code */
    ++){
    ++  char aBuf[24];
    ++  sqlite3_snprintf(sizeof(aBuf)-1, aBuf, "%d", iVal);
    ++  sessionAppendStr(p, aBuf, pRc);
    ++}
    ++
    ++/*
    ++** This function is a no-op if *pRc is other than SQLITE_OK when it is 
    ++** called. Otherwise, append the string zStr enclosed in quotes (") and
    ++** with any embedded quote characters escaped to the buffer. No 
    ++** nul-terminator byte is written.
    ++**
    ++** If an OOM condition is encountered, set *pRc to SQLITE_NOMEM before
    ++** returning.
    ++*/
    ++static void sessionAppendIdent(
    ++  SessionBuffer *p,               /* Buffer to a append to */
    ++  const char *zStr,               /* String to quote, escape and append */
    ++  int *pRc                        /* IN/OUT: Error code */
    ++){
    ++  int nStr = sqlite3Strlen30(zStr)*2 + 2 + 1;
    ++  if( 0==sessionBufferGrow(p, nStr, pRc) ){
    ++    char *zOut = (char *)&p->aBuf[p->nBuf];
    ++    const char *zIn = zStr;
    ++    *zOut++ = '"';
    ++    while( *zIn ){
    ++      if( *zIn=='"' ) *zOut++ = '"';
    ++      *zOut++ = *(zIn++);
    ++    }
    ++    *zOut++ = '"';
    ++    p->nBuf = (int)((u8 *)zOut - p->aBuf);
    ++  }
    ++}
    ++
    ++/*
    ++** This function is a no-op if *pRc is other than SQLITE_OK when it is
    ++** called. Otherwse, it appends the serialized version of the value stored
    ++** in column iCol of the row that SQL statement pStmt currently points
    ++** to to the buffer.
    ++*/
    ++static void sessionAppendCol(
    ++  SessionBuffer *p,               /* Buffer to append to */
    ++  sqlite3_stmt *pStmt,            /* Handle pointing to row containing value */
    ++  int iCol,                       /* Column to read value from */
    ++  int *pRc                        /* IN/OUT: Error code */
    ++){
    ++  if( *pRc==SQLITE_OK ){
    ++    int eType = sqlite3_column_type(pStmt, iCol);
    ++    sessionAppendByte(p, (u8)eType, pRc);
    ++    if( eType==SQLITE_INTEGER || eType==SQLITE_FLOAT ){
    ++      sqlite3_int64 i;
    ++      u8 aBuf[8];
    ++      if( eType==SQLITE_INTEGER ){
    ++        i = sqlite3_column_int64(pStmt, iCol);
    ++      }else{
    ++        double r = sqlite3_column_double(pStmt, iCol);
    ++        memcpy(&i, &r, 8);
    ++      }
    ++      sessionPutI64(aBuf, i);
    ++      sessionAppendBlob(p, aBuf, 8, pRc);
    ++    }
    ++    if( eType==SQLITE_BLOB || eType==SQLITE_TEXT ){
    ++      u8 *z;
    ++      int nByte;
    ++      if( eType==SQLITE_BLOB ){
    ++        z = (u8 *)sqlite3_column_blob(pStmt, iCol);
    ++      }else{
    ++        z = (u8 *)sqlite3_column_text(pStmt, iCol);
    ++      }
    ++      nByte = sqlite3_column_bytes(pStmt, iCol);
    ++      if( z || (eType==SQLITE_BLOB && nByte==0) ){
    ++        sessionAppendVarint(p, nByte, pRc);
    ++        sessionAppendBlob(p, z, nByte, pRc);
    ++      }else{
    ++        *pRc = SQLITE_NOMEM;
    ++      }
    ++    }
    ++  }
    ++}
    ++
    ++/*
    ++**
    ++** This function appends an update change to the buffer (see the comments 
    ++** under "CHANGESET FORMAT" at the top of the file). An update change 
    ++** consists of:
    ++**
    ++**   1 byte:  SQLITE_UPDATE (0x17)
    ++**   n bytes: old.* record (see RECORD FORMAT)
    ++**   m bytes: new.* record (see RECORD FORMAT)
    ++**
    ++** The SessionChange object passed as the third argument contains the
    ++** values that were stored in the row when the session began (the old.*
    ++** values). The statement handle passed as the second argument points
    ++** at the current version of the row (the new.* values).
    ++**
    ++** If all of the old.* values are equal to their corresponding new.* value
    ++** (i.e. nothing has changed), then no data at all is appended to the buffer.
    ++**
    ++** Otherwise, the old.* record contains all primary key values and the 
    ++** original values of any fields that have been modified. The new.* record 
    ++** contains the new values of only those fields that have been modified.
    ++*/ 
    ++static int sessionAppendUpdate(
    ++  SessionBuffer *pBuf,            /* Buffer to append to */
    ++  int bPatchset,                  /* True for "patchset", 0 for "changeset" */
    ++  sqlite3_stmt *pStmt,            /* Statement handle pointing at new row */
    ++  SessionChange *p,               /* Object containing old values */
    ++  u8 *abPK                        /* Boolean array - true for PK columns */
    ++){
    ++  int rc = SQLITE_OK;
    ++  SessionBuffer buf2 = {0,0,0}; /* Buffer to accumulate new.* record in */
    ++  int bNoop = 1;                /* Set to zero if any values are modified */
    ++  int nRewind = pBuf->nBuf;     /* Set to zero if any values are modified */
    ++  int i;                        /* Used to iterate through columns */
    ++  u8 *pCsr = p->aRecord;        /* Used to iterate through old.* values */
    ++
    ++  sessionAppendByte(pBuf, SQLITE_UPDATE, &rc);
    ++  sessionAppendByte(pBuf, p->bIndirect, &rc);
    ++  for(i=0; i<sqlite3_column_count(pStmt); i++){
    ++    int bChanged = 0;
    ++    int nAdvance;
    ++    int eType = *pCsr;
    ++    switch( eType ){
    ++      case SQLITE_NULL:
    ++        nAdvance = 1;
    ++        if( sqlite3_column_type(pStmt, i)!=SQLITE_NULL ){
    ++          bChanged = 1;
    ++        }
    ++        break;
    ++
    ++      case SQLITE_FLOAT:
    ++      case SQLITE_INTEGER: {
    ++        nAdvance = 9;
    ++        if( eType==sqlite3_column_type(pStmt, i) ){
    ++          sqlite3_int64 iVal = sessionGetI64(&pCsr[1]);
    ++          if( eType==SQLITE_INTEGER ){
    ++            if( iVal==sqlite3_column_int64(pStmt, i) ) break;
    ++          }else{
    ++            double dVal;
    ++            memcpy(&dVal, &iVal, 8);
    ++            if( dVal==sqlite3_column_double(pStmt, i) ) break;
    ++          }
    ++        }
    ++        bChanged = 1;
    ++        break;
    ++      }
    ++
    ++      default: {
    ++        int n;
    ++        int nHdr = 1 + sessionVarintGet(&pCsr[1], &n);
    ++        assert( eType==SQLITE_TEXT || eType==SQLITE_BLOB );
    ++        nAdvance = nHdr + n;
    ++        if( eType==sqlite3_column_type(pStmt, i) 
    ++         && n==sqlite3_column_bytes(pStmt, i) 
    ++         && (n==0 || 0==memcmp(&pCsr[nHdr], sqlite3_column_blob(pStmt, i), n))
    ++        ){
    ++          break;
    ++        }
    ++        bChanged = 1;
    ++      }
    ++    }
    ++
    ++    /* If at least one field has been modified, this is not a no-op. */
    ++    if( bChanged ) bNoop = 0;
    ++
    ++    /* Add a field to the old.* record. This is omitted if this modules is
    ++    ** currently generating a patchset. */
    ++    if( bPatchset==0 ){
    ++      if( bChanged || abPK[i] ){
    ++        sessionAppendBlob(pBuf, pCsr, nAdvance, &rc);
    ++      }else{
    ++        sessionAppendByte(pBuf, 0, &rc);
    ++      }
    ++    }
    ++
    ++    /* Add a field to the new.* record. Or the only record if currently
    ++    ** generating a patchset.  */
    ++    if( bChanged || (bPatchset && abPK[i]) ){
    ++      sessionAppendCol(&buf2, pStmt, i, &rc);
    ++    }else{
    ++      sessionAppendByte(&buf2, 0, &rc);
    ++    }
    ++
    ++    pCsr += nAdvance;
    ++  }
    ++
    ++  if( bNoop ){
    ++    pBuf->nBuf = nRewind;
    ++  }else{
    ++    sessionAppendBlob(pBuf, buf2.aBuf, buf2.nBuf, &rc);
    ++  }
    ++  sqlite3_free(buf2.aBuf);
    ++
    ++  return rc;
    ++}
    ++
    ++/*
    ++** Append a DELETE change to the buffer passed as the first argument. Use
    ++** the changeset format if argument bPatchset is zero, or the patchset
    ++** format otherwise.
    ++*/
    ++static int sessionAppendDelete(
    ++  SessionBuffer *pBuf,            /* Buffer to append to */
    ++  int bPatchset,                  /* True for "patchset", 0 for "changeset" */
    ++  SessionChange *p,               /* Object containing old values */
    ++  int nCol,                       /* Number of columns in table */
    ++  u8 *abPK                        /* Boolean array - true for PK columns */
    ++){
    ++  int rc = SQLITE_OK;
    ++
    ++  sessionAppendByte(pBuf, SQLITE_DELETE, &rc);
    ++  sessionAppendByte(pBuf, p->bIndirect, &rc);
    ++
    ++  if( bPatchset==0 ){
    ++    sessionAppendBlob(pBuf, p->aRecord, p->nRecord, &rc);
    ++  }else{
    ++    int i;
    ++    u8 *a = p->aRecord;
    ++    for(i=0; i<nCol; i++){
    ++      u8 *pStart = a;
    ++      int eType = *a++;
    ++
    ++      switch( eType ){
    ++        case 0:
    ++        case SQLITE_NULL:
    ++          assert( abPK[i]==0 );
    ++          break;
    ++
    ++        case SQLITE_FLOAT:
    ++        case SQLITE_INTEGER:
    ++          a += 8;
    ++          break;
    ++
    ++        default: {
    ++          int n;
    ++          a += sessionVarintGet(a, &n);
    ++          a += n;
    ++          break;
    ++        }
    ++      }
    ++      if( abPK[i] ){
    ++        sessionAppendBlob(pBuf, pStart, (int)(a-pStart), &rc);
    ++      }
    ++    }
    ++    assert( (a - p->aRecord)==p->nRecord );
    ++  }
    ++
    ++  return rc;
    ++}
    ++
    ++/*
    ++** Formulate and prepare a SELECT statement to retrieve a row from table
    ++** zTab in database zDb based on its primary key. i.e.
    ++**
    ++**   SELECT * FROM zDb.zTab WHERE pk1 = ? AND pk2 = ? AND ...
    ++*/
    ++static int sessionSelectStmt(
    ++  sqlite3 *db,                    /* Database handle */
    ++  const char *zDb,                /* Database name */
    ++  const char *zTab,               /* Table name */
    ++  int nCol,                       /* Number of columns in table */
    ++  const char **azCol,             /* Names of table columns */
    ++  u8 *abPK,                       /* PRIMARY KEY  array */
    ++  sqlite3_stmt **ppStmt           /* OUT: Prepared SELECT statement */
    ++){
    ++  int rc = SQLITE_OK;
    ++  char *zSql = 0;
    ++  int nSql = -1;
    ++
    ++  if( 0==sqlite3_stricmp("sqlite_stat1", zTab) ){
    ++    zSql = sqlite3_mprintf(
    ++        "SELECT tbl, ?2, stat FROM %Q.sqlite_stat1 WHERE tbl IS ?1 AND "
    ++        "idx IS (CASE WHEN ?2=X'' THEN NULL ELSE ?2 END)", zDb
    ++    );
    ++  }else{
    ++    int i;
    ++    const char *zSep = "";
    ++    SessionBuffer buf = {0, 0, 0};
    ++
    ++    sessionAppendStr(&buf, "SELECT * FROM ", &rc);
    ++    sessionAppendIdent(&buf, zDb, &rc);
    ++    sessionAppendStr(&buf, ".", &rc);
    ++    sessionAppendIdent(&buf, zTab, &rc);
    ++    sessionAppendStr(&buf, " WHERE ", &rc);
    ++    for(i=0; i<nCol; i++){
    ++      if( abPK[i] ){
    ++        sessionAppendStr(&buf, zSep, &rc);
    ++        sessionAppendIdent(&buf, azCol[i], &rc);
    ++        sessionAppendStr(&buf, " IS ?", &rc);
    ++        sessionAppendInteger(&buf, i+1, &rc);
    ++        zSep = " AND ";
    ++      }
    ++    }
    ++    zSql = (char*)buf.aBuf;
    ++    nSql = buf.nBuf;
    ++  }
    ++
    ++  if( rc==SQLITE_OK ){
    ++    rc = sqlite3_prepare_v2(db, zSql, nSql, ppStmt, 0);
    ++  }
    ++  sqlite3_free(zSql);
    ++  return rc;
    ++}
    ++
    ++/*
    ++** Bind the PRIMARY KEY values from the change passed in argument pChange
    ++** to the SELECT statement passed as the first argument. The SELECT statement
    ++** is as prepared by function sessionSelectStmt().
    ++**
    ++** Return SQLITE_OK if all PK values are successfully bound, or an SQLite
    ++** error code (e.g. SQLITE_NOMEM) otherwise.
    ++*/
    ++static int sessionSelectBind(
    ++  sqlite3_stmt *pSelect,          /* SELECT from sessionSelectStmt() */
    ++  int nCol,                       /* Number of columns in table */
    ++  u8 *abPK,                       /* PRIMARY KEY array */
    ++  SessionChange *pChange          /* Change structure */
    ++){
    ++  int i;
    ++  int rc = SQLITE_OK;
    ++  u8 *a = pChange->aRecord;
    ++
    ++  for(i=0; i<nCol && rc==SQLITE_OK; i++){
    ++    int eType = *a++;
    ++
    ++    switch( eType ){
    ++      case 0:
    ++      case SQLITE_NULL:
    ++        assert( abPK[i]==0 );
    ++        break;
    ++
    ++      case SQLITE_INTEGER: {
    ++        if( abPK[i] ){
    ++          i64 iVal = sessionGetI64(a);
    ++          rc = sqlite3_bind_int64(pSelect, i+1, iVal);
    ++        }
    ++        a += 8;
    ++        break;
    ++      }
    ++
    ++      case SQLITE_FLOAT: {
    ++        if( abPK[i] ){
    ++          double rVal;
    ++          i64 iVal = sessionGetI64(a);
    ++          memcpy(&rVal, &iVal, 8);
    ++          rc = sqlite3_bind_double(pSelect, i+1, rVal);
    ++        }
    ++        a += 8;
    ++        break;
    ++      }
    ++
    ++      case SQLITE_TEXT: {
    ++        int n;
    ++        a += sessionVarintGet(a, &n);
    ++        if( abPK[i] ){
    ++          rc = sqlite3_bind_text(pSelect, i+1, (char *)a, n, SQLITE_TRANSIENT);
    ++        }
    ++        a += n;
    ++        break;
    ++      }
    ++
    ++      default: {
    ++        int n;
    ++        assert( eType==SQLITE_BLOB );
    ++        a += sessionVarintGet(a, &n);
    ++        if( abPK[i] ){
    ++          rc = sqlite3_bind_blob(pSelect, i+1, a, n, SQLITE_TRANSIENT);
    ++        }
    ++        a += n;
    ++        break;
    ++      }
    ++    }
    ++  }
    ++
    ++  return rc;
    ++}
    ++
    ++/*
    ++** This function is a no-op if *pRc is set to other than SQLITE_OK when it
    ++** is called. Otherwise, append a serialized table header (part of the binary 
    ++** changeset format) to buffer *pBuf. If an error occurs, set *pRc to an
    ++** SQLite error code before returning.
    ++*/
    ++static void sessionAppendTableHdr(
    ++  SessionBuffer *pBuf,            /* Append header to this buffer */
    ++  int bPatchset,                  /* Use the patchset format if true */
    ++  SessionTable *pTab,             /* Table object to append header for */
    ++  int *pRc                        /* IN/OUT: Error code */
    ++){
    ++  /* Write a table header */
    ++  sessionAppendByte(pBuf, (bPatchset ? 'P' : 'T'), pRc);
    ++  sessionAppendVarint(pBuf, pTab->nCol, pRc);
    ++  sessionAppendBlob(pBuf, pTab->abPK, pTab->nCol, pRc);
    ++  sessionAppendBlob(pBuf, (u8 *)pTab->zName, (int)strlen(pTab->zName)+1, pRc);
    ++}
    ++
    ++/*
    ++** Generate either a changeset (if argument bPatchset is zero) or a patchset
    ++** (if it is non-zero) based on the current contents of the session object
    ++** passed as the first argument.
    ++**
    ++** If no error occurs, SQLITE_OK is returned and the new changeset/patchset
    ++** stored in output variables *pnChangeset and *ppChangeset. Or, if an error
    ++** occurs, an SQLite error code is returned and both output variables set 
    ++** to 0.
    ++*/
    ++static int sessionGenerateChangeset(
    ++  sqlite3_session *pSession,      /* Session object */
    ++  int bPatchset,                  /* True for patchset, false for changeset */
    ++  int (*xOutput)(void *pOut, const void *pData, int nData),
    ++  void *pOut,                     /* First argument for xOutput */
    ++  int *pnChangeset,               /* OUT: Size of buffer at *ppChangeset */
    ++  void **ppChangeset              /* OUT: Buffer containing changeset */
    ++){
    ++  sqlite3 *db = pSession->db;     /* Source database handle */
    ++  SessionTable *pTab;             /* Used to iterate through attached tables */
    ++  SessionBuffer buf = {0,0,0};    /* Buffer in which to accumlate changeset */
    ++  int rc;                         /* Return code */
    ++
    ++  assert( xOutput==0 || (pnChangeset==0 && ppChangeset==0 ) );
    ++
    ++  /* Zero the output variables in case an error occurs. If this session
    ++  ** object is already in the error state (sqlite3_session.rc != SQLITE_OK),
    ++  ** this call will be a no-op.  */
    ++  if( xOutput==0 ){
    ++    *pnChangeset = 0;
    ++    *ppChangeset = 0;
    ++  }
    ++
    ++  if( pSession->rc ) return pSession->rc;
    ++  rc = sqlite3_exec(pSession->db, "SAVEPOINT changeset", 0, 0, 0);
    ++  if( rc!=SQLITE_OK ) return rc;
    ++
    ++  sqlite3_mutex_enter(sqlite3_db_mutex(db));
    ++
    ++  for(pTab=pSession->pTable; rc==SQLITE_OK && pTab; pTab=pTab->pNext){
    ++    if( pTab->nEntry ){
    ++      const char *zName = pTab->zName;
    ++      int nCol;                   /* Number of columns in table */
    ++      u8 *abPK;                   /* Primary key array */
    ++      const char **azCol = 0;     /* Table columns */
    ++      int i;                      /* Used to iterate through hash buckets */
    ++      sqlite3_stmt *pSel = 0;     /* SELECT statement to query table pTab */
    ++      int nRewind = buf.nBuf;     /* Initial size of write buffer */
    ++      int nNoop;                  /* Size of buffer after writing tbl header */
    ++
    ++      /* Check the table schema is still Ok. */
    ++      rc = sessionTableInfo(db, pSession->zDb, zName, &nCol, 0, &azCol, &abPK);
    ++      if( !rc && (pTab->nCol!=nCol || memcmp(abPK, pTab->abPK, nCol)) ){
    ++        rc = SQLITE_SCHEMA;
    ++      }
    ++
    ++      /* Write a table header */
    ++      sessionAppendTableHdr(&buf, bPatchset, pTab, &rc);
    ++
    ++      /* Build and compile a statement to execute: */
    ++      if( rc==SQLITE_OK ){
    ++        rc = sessionSelectStmt(
    ++            db, pSession->zDb, zName, nCol, azCol, abPK, &pSel);
    ++      }
    ++
    ++      nNoop = buf.nBuf;
    ++      for(i=0; i<pTab->nChange && rc==SQLITE_OK; i++){
    ++        SessionChange *p;         /* Used to iterate through changes */
    ++
    ++        for(p=pTab->apChange[i]; rc==SQLITE_OK && p; p=p->pNext){
    ++          rc = sessionSelectBind(pSel, nCol, abPK, p);
    ++          if( rc!=SQLITE_OK ) continue;
    ++          if( sqlite3_step(pSel)==SQLITE_ROW ){
    ++            if( p->op==SQLITE_INSERT ){
    ++              int iCol;
    ++              sessionAppendByte(&buf, SQLITE_INSERT, &rc);
    ++              sessionAppendByte(&buf, p->bIndirect, &rc);
    ++              for(iCol=0; iCol<nCol; iCol++){
    ++                sessionAppendCol(&buf, pSel, iCol, &rc);
    ++              }
    ++            }else{
    ++              rc = sessionAppendUpdate(&buf, bPatchset, pSel, p, abPK);
    ++            }
    ++          }else if( p->op!=SQLITE_INSERT ){
    ++            rc = sessionAppendDelete(&buf, bPatchset, p, nCol, abPK);
    ++          }
    ++          if( rc==SQLITE_OK ){
    ++            rc = sqlite3_reset(pSel);
    ++          }
    ++
    ++          /* If the buffer is now larger than SESSIONS_STRM_CHUNK_SIZE, pass
    ++          ** its contents to the xOutput() callback. */
    ++          if( xOutput 
    ++           && rc==SQLITE_OK 
    ++           && buf.nBuf>nNoop 
    ++           && buf.nBuf>SESSIONS_STRM_CHUNK_SIZE 
    ++          ){
    ++            rc = xOutput(pOut, (void*)buf.aBuf, buf.nBuf);
    ++            nNoop = -1;
    ++            buf.nBuf = 0;
    ++          }
    ++
    ++        }
    ++      }
    ++
    ++      sqlite3_finalize(pSel);
    ++      if( buf.nBuf==nNoop ){
    ++        buf.nBuf = nRewind;
    ++      }
    ++      sqlite3_free((char*)azCol);  /* cast works around VC++ bug */
    ++    }
    ++  }
    ++
    ++  if( rc==SQLITE_OK ){
    ++    if( xOutput==0 ){
    ++      *pnChangeset = buf.nBuf;
    ++      *ppChangeset = buf.aBuf;
    ++      buf.aBuf = 0;
    ++    }else if( buf.nBuf>0 ){
    ++      rc = xOutput(pOut, (void*)buf.aBuf, buf.nBuf);
    ++    }
    ++  }
    ++
    ++  sqlite3_free(buf.aBuf);
    ++  sqlite3_exec(db, "RELEASE changeset", 0, 0, 0);
    ++  sqlite3_mutex_leave(sqlite3_db_mutex(db));
    ++  return rc;
    ++}
    ++
    ++/*
    ++** Obtain a changeset object containing all changes recorded by the 
    ++** session object passed as the first argument.
    ++**
    ++** It is the responsibility of the caller to eventually free the buffer 
    ++** using sqlite3_free().
    ++*/
    ++SQLITE_API int sqlite3session_changeset(
    ++  sqlite3_session *pSession,      /* Session object */
    ++  int *pnChangeset,               /* OUT: Size of buffer at *ppChangeset */
    ++  void **ppChangeset              /* OUT: Buffer containing changeset */
    ++){
    ++  return sessionGenerateChangeset(pSession, 0, 0, 0, pnChangeset, ppChangeset);
    ++}
    ++
    ++/*
    ++** Streaming version of sqlite3session_changeset().
    ++*/
    ++SQLITE_API int sqlite3session_changeset_strm(
    ++  sqlite3_session *pSession,
    ++  int (*xOutput)(void *pOut, const void *pData, int nData),
    ++  void *pOut
    ++){
    ++  return sessionGenerateChangeset(pSession, 0, xOutput, pOut, 0, 0);
    ++}
    ++
    ++/*
    ++** Streaming version of sqlite3session_patchset().
    ++*/
    ++SQLITE_API int sqlite3session_patchset_strm(
    ++  sqlite3_session *pSession,
    ++  int (*xOutput)(void *pOut, const void *pData, int nData),
    ++  void *pOut
    ++){
    ++  return sessionGenerateChangeset(pSession, 1, xOutput, pOut, 0, 0);
    ++}
    ++
    ++/*
    ++** Obtain a patchset object containing all changes recorded by the 
    ++** session object passed as the first argument.
    ++**
    ++** It is the responsibility of the caller to eventually free the buffer 
    ++** using sqlite3_free().
    ++*/
    ++SQLITE_API int sqlite3session_patchset(
    ++  sqlite3_session *pSession,      /* Session object */
    ++  int *pnPatchset,                /* OUT: Size of buffer at *ppChangeset */
    ++  void **ppPatchset               /* OUT: Buffer containing changeset */
    ++){
    ++  return sessionGenerateChangeset(pSession, 1, 0, 0, pnPatchset, ppPatchset);
    ++}
    ++
    ++/*
    ++** Enable or disable the session object passed as the first argument.
    ++*/
    ++SQLITE_API int sqlite3session_enable(sqlite3_session *pSession, int bEnable){
    ++  int ret;
    ++  sqlite3_mutex_enter(sqlite3_db_mutex(pSession->db));
    ++  if( bEnable>=0 ){
    ++    pSession->bEnable = bEnable;
    ++  }
    ++  ret = pSession->bEnable;
    ++  sqlite3_mutex_leave(sqlite3_db_mutex(pSession->db));
    ++  return ret;
    ++}
    ++
    ++/*
    ++** Enable or disable the session object passed as the first argument.
    ++*/
    ++SQLITE_API int sqlite3session_indirect(sqlite3_session *pSession, int bIndirect){
    ++  int ret;
    ++  sqlite3_mutex_enter(sqlite3_db_mutex(pSession->db));
    ++  if( bIndirect>=0 ){
    ++    pSession->bIndirect = bIndirect;
    ++  }
    ++  ret = pSession->bIndirect;
    ++  sqlite3_mutex_leave(sqlite3_db_mutex(pSession->db));
    ++  return ret;
    ++}
    ++
    ++/*
    ++** Return true if there have been no changes to monitored tables recorded
    ++** by the session object passed as the only argument.
    ++*/
    ++SQLITE_API int sqlite3session_isempty(sqlite3_session *pSession){
    ++  int ret = 0;
    ++  SessionTable *pTab;
    ++
    ++  sqlite3_mutex_enter(sqlite3_db_mutex(pSession->db));
    ++  for(pTab=pSession->pTable; pTab && ret==0; pTab=pTab->pNext){
    ++    ret = (pTab->nEntry>0);
    ++  }
    ++  sqlite3_mutex_leave(sqlite3_db_mutex(pSession->db));
    ++
    ++  return (ret==0);
    ++}
    ++
    ++/*
    ++** Do the work for either sqlite3changeset_start() or start_strm().
    ++*/
    ++static int sessionChangesetStart(
    ++  sqlite3_changeset_iter **pp,    /* OUT: Changeset iterator handle */
    ++  int (*xInput)(void *pIn, void *pData, int *pnData),
    ++  void *pIn,
    ++  int nChangeset,                 /* Size of buffer pChangeset in bytes */
    ++  void *pChangeset                /* Pointer to buffer containing changeset */
    ++){
    ++  sqlite3_changeset_iter *pRet;   /* Iterator to return */
    ++  int nByte;                      /* Number of bytes to allocate for iterator */
    ++
    ++  assert( xInput==0 || (pChangeset==0 && nChangeset==0) );
    ++
    ++  /* Zero the output variable in case an error occurs. */
    ++  *pp = 0;
    ++
    ++  /* Allocate and initialize the iterator structure. */
    ++  nByte = sizeof(sqlite3_changeset_iter);
    ++  pRet = (sqlite3_changeset_iter *)sqlite3_malloc(nByte);
    ++  if( !pRet ) return SQLITE_NOMEM;
    ++  memset(pRet, 0, sizeof(sqlite3_changeset_iter));
    ++  pRet->in.aData = (u8 *)pChangeset;
    ++  pRet->in.nData = nChangeset;
    ++  pRet->in.xInput = xInput;
    ++  pRet->in.pIn = pIn;
    ++  pRet->in.bEof = (xInput ? 0 : 1);
    ++
    ++  /* Populate the output variable and return success. */
    ++  *pp = pRet;
    ++  return SQLITE_OK;
    ++}
    ++
    ++/*
    ++** Create an iterator used to iterate through the contents of a changeset.
    ++*/
    ++SQLITE_API int sqlite3changeset_start(
    ++  sqlite3_changeset_iter **pp,    /* OUT: Changeset iterator handle */
    ++  int nChangeset,                 /* Size of buffer pChangeset in bytes */
    ++  void *pChangeset                /* Pointer to buffer containing changeset */
    ++){
    ++  return sessionChangesetStart(pp, 0, 0, nChangeset, pChangeset);
    ++}
    ++
    ++/*
    ++** Streaming version of sqlite3changeset_start().
    ++*/
    ++SQLITE_API int sqlite3changeset_start_strm(
    ++  sqlite3_changeset_iter **pp,    /* OUT: Changeset iterator handle */
    ++  int (*xInput)(void *pIn, void *pData, int *pnData),
    ++  void *pIn
    ++){
    ++  return sessionChangesetStart(pp, xInput, pIn, 0, 0);
    ++}
    ++
    ++/*
    ++** If the SessionInput object passed as the only argument is a streaming
    ++** object and the buffer is full, discard some data to free up space.
    ++*/
    ++static void sessionDiscardData(SessionInput *pIn){
    ++  if( pIn->bEof && pIn->xInput && pIn->iNext>=SESSIONS_STRM_CHUNK_SIZE ){
    ++    int nMove = pIn->buf.nBuf - pIn->iNext;
    ++    assert( nMove>=0 );
    ++    if( nMove>0 ){
    ++      memmove(pIn->buf.aBuf, &pIn->buf.aBuf[pIn->iNext], nMove);
    ++    }
    ++    pIn->buf.nBuf -= pIn->iNext;
    ++    pIn->iNext = 0;
    ++    pIn->nData = pIn->buf.nBuf;
    ++  }
    ++}
    ++
    ++/*
    ++** Ensure that there are at least nByte bytes available in the buffer. Or,
    ++** if there are not nByte bytes remaining in the input, that all available
    ++** data is in the buffer.
    ++**
    ++** Return an SQLite error code if an error occurs, or SQLITE_OK otherwise.
    ++*/
    ++static int sessionInputBuffer(SessionInput *pIn, int nByte){
    ++  int rc = SQLITE_OK;
    ++  if( pIn->xInput ){
    ++    while( !pIn->bEof && (pIn->iNext+nByte)>=pIn->nData && rc==SQLITE_OK ){
    ++      int nNew = SESSIONS_STRM_CHUNK_SIZE;
    ++
    ++      if( pIn->bNoDiscard==0 ) sessionDiscardData(pIn);
    ++      if( SQLITE_OK==sessionBufferGrow(&pIn->buf, nNew, &rc) ){
    ++        rc = pIn->xInput(pIn->pIn, &pIn->buf.aBuf[pIn->buf.nBuf], &nNew);
    ++        if( nNew==0 ){
    ++          pIn->bEof = 1;
    ++        }else{
    ++          pIn->buf.nBuf += nNew;
    ++        }
    ++      }
    ++
    ++      pIn->aData = pIn->buf.aBuf;
    ++      pIn->nData = pIn->buf.nBuf;
    ++    }
    ++  }
    ++  return rc;
    ++}
    ++
    ++/*
    ++** When this function is called, *ppRec points to the start of a record
    ++** that contains nCol values. This function advances the pointer *ppRec
    ++** until it points to the byte immediately following that record.
    ++*/
    ++static void sessionSkipRecord(
    ++  u8 **ppRec,                     /* IN/OUT: Record pointer */
    ++  int nCol                        /* Number of values in record */
    ++){
    ++  u8 *aRec = *ppRec;
    ++  int i;
    ++  for(i=0; i<nCol; i++){
    ++    int eType = *aRec++;
    ++    if( eType==SQLITE_TEXT || eType==SQLITE_BLOB ){
    ++      int nByte;
    ++      aRec += sessionVarintGet((u8*)aRec, &nByte);
    ++      aRec += nByte;
    ++    }else if( eType==SQLITE_INTEGER || eType==SQLITE_FLOAT ){
    ++      aRec += 8;
    ++    }
    ++  }
    ++
    ++  *ppRec = aRec;
    ++}
    ++
    ++/*
    ++** This function sets the value of the sqlite3_value object passed as the
    ++** first argument to a copy of the string or blob held in the aData[] 
    ++** buffer. SQLITE_OK is returned if successful, or SQLITE_NOMEM if an OOM
    ++** error occurs.
    ++*/
    ++static int sessionValueSetStr(
    ++  sqlite3_value *pVal,            /* Set the value of this object */
    ++  u8 *aData,                      /* Buffer containing string or blob data */
    ++  int nData,                      /* Size of buffer aData[] in bytes */
    ++  u8 enc                          /* String encoding (0 for blobs) */
    ++){
    ++  /* In theory this code could just pass SQLITE_TRANSIENT as the final
    ++  ** argument to sqlite3ValueSetStr() and have the copy created 
    ++  ** automatically. But doing so makes it difficult to detect any OOM
    ++  ** error. Hence the code to create the copy externally. */
    ++  u8 *aCopy = sqlite3_malloc(nData+1);
    ++  if( aCopy==0 ) return SQLITE_NOMEM;
    ++  memcpy(aCopy, aData, nData);
    ++  sqlite3ValueSetStr(pVal, nData, (char*)aCopy, enc, sqlite3_free);
    ++  return SQLITE_OK;
    ++}
    ++
    ++/*
    ++** Deserialize a single record from a buffer in memory. See "RECORD FORMAT"
    ++** for details.
    ++**
    ++** When this function is called, *paChange points to the start of the record
    ++** to deserialize. Assuming no error occurs, *paChange is set to point to
    ++** one byte after the end of the same record before this function returns.
    ++** If the argument abPK is NULL, then the record contains nCol values. Or,
    ++** if abPK is other than NULL, then the record contains only the PK fields
    ++** (in other words, it is a patchset DELETE record).
    ++**
    ++** If successful, each element of the apOut[] array (allocated by the caller)
    ++** is set to point to an sqlite3_value object containing the value read
    ++** from the corresponding position in the record. If that value is not
    ++** included in the record (i.e. because the record is part of an UPDATE change
    ++** and the field was not modified), the corresponding element of apOut[] is
    ++** set to NULL.
    ++**
    ++** It is the responsibility of the caller to free all sqlite_value structures
    ++** using sqlite3_free().
    ++**
    ++** If an error occurs, an SQLite error code (e.g. SQLITE_NOMEM) is returned.
    ++** The apOut[] array may have been partially populated in this case.
    ++*/
    ++static int sessionReadRecord(
    ++  SessionInput *pIn,              /* Input data */
    ++  int nCol,                       /* Number of values in record */
    ++  u8 *abPK,                       /* Array of primary key flags, or NULL */
    ++  sqlite3_value **apOut           /* Write values to this array */
    ++){
    ++  int i;                          /* Used to iterate through columns */
    ++  int rc = SQLITE_OK;
    ++
    ++  for(i=0; i<nCol && rc==SQLITE_OK; i++){
    ++    int eType = 0;                /* Type of value (SQLITE_NULL, TEXT etc.) */
    ++    if( abPK && abPK[i]==0 ) continue;
    ++    rc = sessionInputBuffer(pIn, 9);
    ++    if( rc==SQLITE_OK ){
    ++      eType = pIn->aData[pIn->iNext++];
    ++    }
    ++
    ++    assert( apOut[i]==0 );
    ++    if( eType ){
    ++      apOut[i] = sqlite3ValueNew(0);
    ++      if( !apOut[i] ) rc = SQLITE_NOMEM;
    ++    }
    ++
    ++    if( rc==SQLITE_OK ){
    ++      u8 *aVal = &pIn->aData[pIn->iNext];
    ++      if( eType==SQLITE_TEXT || eType==SQLITE_BLOB ){
    ++        int nByte;
    ++        pIn->iNext += sessionVarintGet(aVal, &nByte);
    ++        rc = sessionInputBuffer(pIn, nByte);
    ++        if( rc==SQLITE_OK ){
    ++          u8 enc = (eType==SQLITE_TEXT ? SQLITE_UTF8 : 0);
    ++          rc = sessionValueSetStr(apOut[i],&pIn->aData[pIn->iNext],nByte,enc);
    ++        }
    ++        pIn->iNext += nByte;
    ++      }
    ++      if( eType==SQLITE_INTEGER || eType==SQLITE_FLOAT ){
    ++        sqlite3_int64 v = sessionGetI64(aVal);
    ++        if( eType==SQLITE_INTEGER ){
    ++          sqlite3VdbeMemSetInt64(apOut[i], v);
    ++        }else{
    ++          double d;
    ++          memcpy(&d, &v, 8);
    ++          sqlite3VdbeMemSetDouble(apOut[i], d);
    ++        }
    ++        pIn->iNext += 8;
    ++      }
    ++    }
    ++  }
    ++
    ++  return rc;
    ++}
    ++
    ++/*
    ++** The input pointer currently points to the second byte of a table-header.
    ++** Specifically, to the following:
    ++**
    ++**   + number of columns in table (varint)
    ++**   + array of PK flags (1 byte per column),
    ++**   + table name (nul terminated).
    ++**
    ++** This function ensures that all of the above is present in the input 
    ++** buffer (i.e. that it can be accessed without any calls to xInput()).
    ++** If successful, SQLITE_OK is returned. Otherwise, an SQLite error code.
    ++** The input pointer is not moved.
    ++*/
    ++static int sessionChangesetBufferTblhdr(SessionInput *pIn, int *pnByte){
    ++  int rc = SQLITE_OK;
    ++  int nCol = 0;
    ++  int nRead = 0;
    ++
    ++  rc = sessionInputBuffer(pIn, 9);
    ++  if( rc==SQLITE_OK ){
    ++    nRead += sessionVarintGet(&pIn->aData[pIn->iNext + nRead], &nCol);
    ++    rc = sessionInputBuffer(pIn, nRead+nCol+100);
    ++    nRead += nCol;
    ++  }
    ++
    ++  while( rc==SQLITE_OK ){
    ++    while( (pIn->iNext + nRead)<pIn->nData && pIn->aData[pIn->iNext + nRead] ){
    ++      nRead++;
    ++    }
    ++    if( (pIn->iNext + nRead)<pIn->nData ) break;
    ++    rc = sessionInputBuffer(pIn, nRead + 100);
    ++  }
    ++  *pnByte = nRead+1;
    ++  return rc;
    ++}
    ++
    ++/*
    ++** The input pointer currently points to the first byte of the first field
    ++** of a record consisting of nCol columns. This function ensures the entire
    ++** record is buffered. It does not move the input pointer.
    ++**
    ++** If successful, SQLITE_OK is returned and *pnByte is set to the size of
    ++** the record in bytes. Otherwise, an SQLite error code is returned. The
    ++** final value of *pnByte is undefined in this case.
    ++*/
    ++static int sessionChangesetBufferRecord(
    ++  SessionInput *pIn,              /* Input data */
    ++  int nCol,                       /* Number of columns in record */
    ++  int *pnByte                     /* OUT: Size of record in bytes */
    ++){
    ++  int rc = SQLITE_OK;
    ++  int nByte = 0;
    ++  int i;
    ++  for(i=0; rc==SQLITE_OK && i<nCol; i++){
    ++    int eType;
    ++    rc = sessionInputBuffer(pIn, nByte + 10);
    ++    if( rc==SQLITE_OK ){
    ++      eType = pIn->aData[pIn->iNext + nByte++];
    ++      if( eType==SQLITE_TEXT || eType==SQLITE_BLOB ){
    ++        int n;
    ++        nByte += sessionVarintGet(&pIn->aData[pIn->iNext+nByte], &n);
    ++        nByte += n;
    ++        rc = sessionInputBuffer(pIn, nByte);
    ++      }else if( eType==SQLITE_INTEGER || eType==SQLITE_FLOAT ){
    ++        nByte += 8;
    ++      }
    ++    }
    ++  }
    ++  *pnByte = nByte;
    ++  return rc;
    ++}
    ++
    ++/*
    ++** The input pointer currently points to the second byte of a table-header.
    ++** Specifically, to the following:
    ++**
    ++**   + number of columns in table (varint)
    ++**   + array of PK flags (1 byte per column),
    ++**   + table name (nul terminated).
    ++**
    ++** This function decodes the table-header and populates the p->nCol, 
    ++** p->zTab and p->abPK[] variables accordingly. The p->apValue[] array is 
    ++** also allocated or resized according to the new value of p->nCol. The
    ++** input pointer is left pointing to the byte following the table header.
    ++**
    ++** If successful, SQLITE_OK is returned. Otherwise, an SQLite error code
    ++** is returned and the final values of the various fields enumerated above
    ++** are undefined.
    ++*/
    ++static int sessionChangesetReadTblhdr(sqlite3_changeset_iter *p){
    ++  int rc;
    ++  int nCopy;
    ++  assert( p->rc==SQLITE_OK );
    ++
    ++  rc = sessionChangesetBufferTblhdr(&p->in, &nCopy);
    ++  if( rc==SQLITE_OK ){
    ++    int nByte;
    ++    int nVarint;
    ++    nVarint = sessionVarintGet(&p->in.aData[p->in.iNext], &p->nCol);
    ++    nCopy -= nVarint;
    ++    p->in.iNext += nVarint;
    ++    nByte = p->nCol * sizeof(sqlite3_value*) * 2 + nCopy;
    ++    p->tblhdr.nBuf = 0;
    ++    sessionBufferGrow(&p->tblhdr, nByte, &rc);
    ++  }
    ++
    ++  if( rc==SQLITE_OK ){
    ++    int iPK = sizeof(sqlite3_value*)*p->nCol*2;
    ++    memset(p->tblhdr.aBuf, 0, iPK);
    ++    memcpy(&p->tblhdr.aBuf[iPK], &p->in.aData[p->in.iNext], nCopy);
    ++    p->in.iNext += nCopy;
    ++  }
    ++
    ++  p->apValue = (sqlite3_value**)p->tblhdr.aBuf;
    ++  p->abPK = (u8*)&p->apValue[p->nCol*2];
    ++  p->zTab = (char*)&p->abPK[p->nCol];
    ++  return (p->rc = rc);
    ++}
    ++
    ++/*
    ++** Advance the changeset iterator to the next change.
    ++**
    ++** If both paRec and pnRec are NULL, then this function works like the public
    ++** API sqlite3changeset_next(). If SQLITE_ROW is returned, then the
    ++** sqlite3changeset_new() and old() APIs may be used to query for values.
    ++**
    ++** Otherwise, if paRec and pnRec are not NULL, then a pointer to the change
    ++** record is written to *paRec before returning and the number of bytes in
    ++** the record to *pnRec.
    ++**
    ++** Either way, this function returns SQLITE_ROW if the iterator is 
    ++** successfully advanced to the next change in the changeset, an SQLite 
    ++** error code if an error occurs, or SQLITE_DONE if there are no further 
    ++** changes in the changeset.
    ++*/
    ++static int sessionChangesetNext(
    ++  sqlite3_changeset_iter *p,      /* Changeset iterator */
    ++  u8 **paRec,                     /* If non-NULL, store record pointer here */
    ++  int *pnRec                      /* If non-NULL, store size of record here */
    ++){
    ++  int i;
    ++  u8 op;
    ++
    ++  assert( (paRec==0 && pnRec==0) || (paRec && pnRec) );
    ++
    ++  /* If the iterator is in the error-state, return immediately. */
    ++  if( p->rc!=SQLITE_OK ) return p->rc;
    ++
    ++  /* Free the current contents of p->apValue[], if any. */
    ++  if( p->apValue ){
    ++    for(i=0; i<p->nCol*2; i++){
    ++      sqlite3ValueFree(p->apValue[i]);
    ++    }
    ++    memset(p->apValue, 0, sizeof(sqlite3_value*)*p->nCol*2);
    ++  }
    ++
    ++  /* Make sure the buffer contains at least 10 bytes of input data, or all
    ++  ** remaining data if there are less than 10 bytes available. This is
    ++  ** sufficient either for the 'T' or 'P' byte and the varint that follows
    ++  ** it, or for the two single byte values otherwise. */
    ++  p->rc = sessionInputBuffer(&p->in, 2);
    ++  if( p->rc!=SQLITE_OK ) return p->rc;
    ++
    ++  /* If the iterator is already at the end of the changeset, return DONE. */
    ++  if( p->in.iNext>=p->in.nData ){
    ++    return SQLITE_DONE;
    ++  }
    ++
    ++  sessionDiscardData(&p->in);
    ++  p->in.iCurrent = p->in.iNext;
    ++
    ++  op = p->in.aData[p->in.iNext++];
    ++  while( op=='T' || op=='P' ){
    ++    p->bPatchset = (op=='P');
    ++    if( sessionChangesetReadTblhdr(p) ) return p->rc;
    ++    if( (p->rc = sessionInputBuffer(&p->in, 2)) ) return p->rc;
    ++    p->in.iCurrent = p->in.iNext;
    ++    if( p->in.iNext>=p->in.nData ) return SQLITE_DONE;
    ++    op = p->in.aData[p->in.iNext++];
    ++  }
    ++
    ++  p->op = op;
    ++  p->bIndirect = p->in.aData[p->in.iNext++];
    ++  if( p->op!=SQLITE_UPDATE && p->op!=SQLITE_DELETE && p->op!=SQLITE_INSERT ){
    ++    return (p->rc = SQLITE_CORRUPT_BKPT);
    ++  }
    ++
    ++  if( paRec ){ 
    ++    int nVal;                     /* Number of values to buffer */
    ++    if( p->bPatchset==0 && op==SQLITE_UPDATE ){
    ++      nVal = p->nCol * 2;
    ++    }else if( p->bPatchset && op==SQLITE_DELETE ){
    ++      nVal = 0;
    ++      for(i=0; i<p->nCol; i++) if( p->abPK[i] ) nVal++;
    ++    }else{
    ++      nVal = p->nCol;
    ++    }
    ++    p->rc = sessionChangesetBufferRecord(&p->in, nVal, pnRec);
    ++    if( p->rc!=SQLITE_OK ) return p->rc;
    ++    *paRec = &p->in.aData[p->in.iNext];
    ++    p->in.iNext += *pnRec;
    ++  }else{
    ++
    ++    /* If this is an UPDATE or DELETE, read the old.* record. */
    ++    if( p->op!=SQLITE_INSERT && (p->bPatchset==0 || p->op==SQLITE_DELETE) ){
    ++      u8 *abPK = p->bPatchset ? p->abPK : 0;
    ++      p->rc = sessionReadRecord(&p->in, p->nCol, abPK, p->apValue);
    ++      if( p->rc!=SQLITE_OK ) return p->rc;
    ++    }
    ++
    ++    /* If this is an INSERT or UPDATE, read the new.* record. */
    ++    if( p->op!=SQLITE_DELETE ){
    ++      p->rc = sessionReadRecord(&p->in, p->nCol, 0, &p->apValue[p->nCol]);
    ++      if( p->rc!=SQLITE_OK ) return p->rc;
    ++    }
    ++
    ++    if( p->bPatchset && p->op==SQLITE_UPDATE ){
    ++      /* If this is an UPDATE that is part of a patchset, then all PK and
    ++      ** modified fields are present in the new.* record. The old.* record
    ++      ** is currently completely empty. This block shifts the PK fields from
    ++      ** new.* to old.*, to accommodate the code that reads these arrays.  */
    ++      for(i=0; i<p->nCol; i++){
    ++        assert( p->apValue[i]==0 );
    ++        assert( p->abPK[i]==0 || p->apValue[i+p->nCol] );
    ++        if( p->abPK[i] ){
    ++          p->apValue[i] = p->apValue[i+p->nCol];
    ++          p->apValue[i+p->nCol] = 0;
    ++        }
    ++      }
    ++    }
    ++  }
    ++
    ++  return SQLITE_ROW;
    ++}
    ++
    ++/*
    ++** Advance an iterator created by sqlite3changeset_start() to the next
    ++** change in the changeset. This function may return SQLITE_ROW, SQLITE_DONE
    ++** or SQLITE_CORRUPT.
    ++**
    ++** This function may not be called on iterators passed to a conflict handler
    ++** callback by changeset_apply().
    ++*/
    ++SQLITE_API int sqlite3changeset_next(sqlite3_changeset_iter *p){
    ++  return sessionChangesetNext(p, 0, 0);
    ++}
    ++
    ++/*
    ++** The following function extracts information on the current change
    ++** from a changeset iterator. It may only be called after changeset_next()
    ++** has returned SQLITE_ROW.
    ++*/
    ++SQLITE_API int sqlite3changeset_op(
    ++  sqlite3_changeset_iter *pIter,  /* Iterator handle */
    ++  const char **pzTab,             /* OUT: Pointer to table name */
    ++  int *pnCol,                     /* OUT: Number of columns in table */
    ++  int *pOp,                       /* OUT: SQLITE_INSERT, DELETE or UPDATE */
    ++  int *pbIndirect                 /* OUT: True if change is indirect */
    ++){
    ++  *pOp = pIter->op;
    ++  *pnCol = pIter->nCol;
    ++  *pzTab = pIter->zTab;
    ++  if( pbIndirect ) *pbIndirect = pIter->bIndirect;
    ++  return SQLITE_OK;
    ++}
    ++
    ++/*
    ++** Return information regarding the PRIMARY KEY and number of columns in
    ++** the database table affected by the change that pIter currently points
    ++** to. This function may only be called after changeset_next() returns
    ++** SQLITE_ROW.
    ++*/
    ++SQLITE_API int sqlite3changeset_pk(
    ++  sqlite3_changeset_iter *pIter,  /* Iterator object */
    ++  unsigned char **pabPK,          /* OUT: Array of boolean - true for PK cols */
    ++  int *pnCol                      /* OUT: Number of entries in output array */
    ++){
    ++  *pabPK = pIter->abPK;
    ++  if( pnCol ) *pnCol = pIter->nCol;
    ++  return SQLITE_OK;
    ++}
    ++
    ++/*
    ++** This function may only be called while the iterator is pointing to an
    ++** SQLITE_UPDATE or SQLITE_DELETE change (see sqlite3changeset_op()).
    ++** Otherwise, SQLITE_MISUSE is returned.
    ++**
    ++** It sets *ppValue to point to an sqlite3_value structure containing the
    ++** iVal'th value in the old.* record. Or, if that particular value is not
    ++** included in the record (because the change is an UPDATE and the field
    ++** was not modified and is not a PK column), set *ppValue to NULL.
    ++**
    ++** If value iVal is out-of-range, SQLITE_RANGE is returned and *ppValue is
    ++** not modified. Otherwise, SQLITE_OK.
    ++*/
    ++SQLITE_API int sqlite3changeset_old(
    ++  sqlite3_changeset_iter *pIter,  /* Changeset iterator */
    ++  int iVal,                       /* Index of old.* value to retrieve */
    ++  sqlite3_value **ppValue         /* OUT: Old value (or NULL pointer) */
    ++){
    ++  if( pIter->op!=SQLITE_UPDATE && pIter->op!=SQLITE_DELETE ){
    ++    return SQLITE_MISUSE;
    ++  }
    ++  if( iVal<0 || iVal>=pIter->nCol ){
    ++    return SQLITE_RANGE;
    ++  }
    ++  *ppValue = pIter->apValue[iVal];
    ++  return SQLITE_OK;
    ++}
    ++
    ++/*
    ++** This function may only be called while the iterator is pointing to an
    ++** SQLITE_UPDATE or SQLITE_INSERT change (see sqlite3changeset_op()).
    ++** Otherwise, SQLITE_MISUSE is returned.
    ++**
    ++** It sets *ppValue to point to an sqlite3_value structure containing the
    ++** iVal'th value in the new.* record. Or, if that particular value is not
    ++** included in the record (because the change is an UPDATE and the field
    ++** was not modified), set *ppValue to NULL.
    ++**
    ++** If value iVal is out-of-range, SQLITE_RANGE is returned and *ppValue is
    ++** not modified. Otherwise, SQLITE_OK.
    ++*/
    ++SQLITE_API int sqlite3changeset_new(
    ++  sqlite3_changeset_iter *pIter,  /* Changeset iterator */
    ++  int iVal,                       /* Index of new.* value to retrieve */
    ++  sqlite3_value **ppValue         /* OUT: New value (or NULL pointer) */
    ++){
    ++  if( pIter->op!=SQLITE_UPDATE && pIter->op!=SQLITE_INSERT ){
    ++    return SQLITE_MISUSE;
    ++  }
    ++  if( iVal<0 || iVal>=pIter->nCol ){
    ++    return SQLITE_RANGE;
    ++  }
    ++  *ppValue = pIter->apValue[pIter->nCol+iVal];
    ++  return SQLITE_OK;
    ++}
    ++
    ++/*
    ++** The following two macros are used internally. They are similar to the
    ++** sqlite3changeset_new() and sqlite3changeset_old() functions, except that
    ++** they omit all error checking and return a pointer to the requested value.
    ++*/
    ++#define sessionChangesetNew(pIter, iVal) (pIter)->apValue[(pIter)->nCol+(iVal)]
    ++#define sessionChangesetOld(pIter, iVal) (pIter)->apValue[(iVal)]
    ++
    ++/*
    ++** This function may only be called with a changeset iterator that has been
    ++** passed to an SQLITE_CHANGESET_DATA or SQLITE_CHANGESET_CONFLICT 
    ++** conflict-handler function. Otherwise, SQLITE_MISUSE is returned.
    ++**
    ++** If successful, *ppValue is set to point to an sqlite3_value structure
    ++** containing the iVal'th value of the conflicting record.
    ++**
    ++** If value iVal is out-of-range or some other error occurs, an SQLite error
    ++** code is returned. Otherwise, SQLITE_OK.
    ++*/
    ++SQLITE_API int sqlite3changeset_conflict(
    ++  sqlite3_changeset_iter *pIter,  /* Changeset iterator */
    ++  int iVal,                       /* Index of conflict record value to fetch */
    ++  sqlite3_value **ppValue         /* OUT: Value from conflicting row */
    ++){
    ++  if( !pIter->pConflict ){
    ++    return SQLITE_MISUSE;
    ++  }
    ++  if( iVal<0 || iVal>=pIter->nCol ){
    ++    return SQLITE_RANGE;
    ++  }
    ++  *ppValue = sqlite3_column_value(pIter->pConflict, iVal);
    ++  return SQLITE_OK;
    ++}
    ++
    ++/*
    ++** This function may only be called with an iterator passed to an
    ++** SQLITE_CHANGESET_FOREIGN_KEY conflict handler callback. In this case
    ++** it sets the output variable to the total number of known foreign key
    ++** violations in the destination database and returns SQLITE_OK.
    ++**
    ++** In all other cases this function returns SQLITE_MISUSE.
    ++*/
    ++SQLITE_API int sqlite3changeset_fk_conflicts(
    ++  sqlite3_changeset_iter *pIter,  /* Changeset iterator */
    ++  int *pnOut                      /* OUT: Number of FK violations */
    ++){
    ++  if( pIter->pConflict || pIter->apValue ){
    ++    return SQLITE_MISUSE;
    ++  }
    ++  *pnOut = pIter->nCol;
    ++  return SQLITE_OK;
    ++}
    ++
    ++
    ++/*
    ++** Finalize an iterator allocated with sqlite3changeset_start().
    ++**
    ++** This function may not be called on iterators passed to a conflict handler
    ++** callback by changeset_apply().
    ++*/
    ++SQLITE_API int sqlite3changeset_finalize(sqlite3_changeset_iter *p){
    ++  int rc = SQLITE_OK;
    ++  if( p ){
    ++    int i;                        /* Used to iterate through p->apValue[] */
    ++    rc = p->rc;
    ++    if( p->apValue ){
    ++      for(i=0; i<p->nCol*2; i++) sqlite3ValueFree(p->apValue[i]);
    ++    }
    ++    sqlite3_free(p->tblhdr.aBuf);
    ++    sqlite3_free(p->in.buf.aBuf);
    ++    sqlite3_free(p);
    ++  }
    ++  return rc;
    ++}
    ++
    ++static int sessionChangesetInvert(
    ++  SessionInput *pInput,           /* Input changeset */
    ++  int (*xOutput)(void *pOut, const void *pData, int nData),
    ++  void *pOut,
    ++  int *pnInverted,                /* OUT: Number of bytes in output changeset */
    ++  void **ppInverted               /* OUT: Inverse of pChangeset */
    ++){
    ++  int rc = SQLITE_OK;             /* Return value */
    ++  SessionBuffer sOut;             /* Output buffer */
    ++  int nCol = 0;                   /* Number of cols in current table */
    ++  u8 *abPK = 0;                   /* PK array for current table */
    ++  sqlite3_value **apVal = 0;      /* Space for values for UPDATE inversion */
    ++  SessionBuffer sPK = {0, 0, 0};  /* PK array for current table */
    ++
    ++  /* Initialize the output buffer */
    ++  memset(&sOut, 0, sizeof(SessionBuffer));
    ++
    ++  /* Zero the output variables in case an error occurs. */
    ++  if( ppInverted ){
    ++    *ppInverted = 0;
    ++    *pnInverted = 0;
    ++  }
    ++
    ++  while( 1 ){
    ++    u8 eType;
    ++
    ++    /* Test for EOF. */
    ++    if( (rc = sessionInputBuffer(pInput, 2)) ) goto finished_invert;
    ++    if( pInput->iNext>=pInput->nData ) break;
    ++    eType = pInput->aData[pInput->iNext];
    ++
    ++    switch( eType ){
    ++      case 'T': {
    ++        /* A 'table' record consists of:
    ++        **
    ++        **   * A constant 'T' character,
    ++        **   * Number of columns in said table (a varint),
    ++        **   * An array of nCol bytes (sPK),
    ++        **   * A nul-terminated table name.
    ++        */
    ++        int nByte;
    ++        int nVar;
    ++        pInput->iNext++;
    ++        if( (rc = sessionChangesetBufferTblhdr(pInput, &nByte)) ){
    ++          goto finished_invert;
    ++        }
    ++        nVar = sessionVarintGet(&pInput->aData[pInput->iNext], &nCol);
    ++        sPK.nBuf = 0;
    ++        sessionAppendBlob(&sPK, &pInput->aData[pInput->iNext+nVar], nCol, &rc);
    ++        sessionAppendByte(&sOut, eType, &rc);
    ++        sessionAppendBlob(&sOut, &pInput->aData[pInput->iNext], nByte, &rc);
    ++        if( rc ) goto finished_invert;
    ++
    ++        pInput->iNext += nByte;
    ++        sqlite3_free(apVal);
    ++        apVal = 0;
    ++        abPK = sPK.aBuf;
    ++        break;
    ++      }
    ++
    ++      case SQLITE_INSERT:
    ++      case SQLITE_DELETE: {
    ++        int nByte;
    ++        int bIndirect = pInput->aData[pInput->iNext+1];
    ++        int eType2 = (eType==SQLITE_DELETE ? SQLITE_INSERT : SQLITE_DELETE);
    ++        pInput->iNext += 2;
    ++        assert( rc==SQLITE_OK );
    ++        rc = sessionChangesetBufferRecord(pInput, nCol, &nByte);
    ++        sessionAppendByte(&sOut, eType2, &rc);
    ++        sessionAppendByte(&sOut, bIndirect, &rc);
    ++        sessionAppendBlob(&sOut, &pInput->aData[pInput->iNext], nByte, &rc);
    ++        pInput->iNext += nByte;
    ++        if( rc ) goto finished_invert;
    ++        break;
    ++      }
    ++
    ++      case SQLITE_UPDATE: {
    ++        int iCol;
    ++
    ++        if( 0==apVal ){
    ++          apVal = (sqlite3_value **)sqlite3_malloc(sizeof(apVal[0])*nCol*2);
    ++          if( 0==apVal ){
    ++            rc = SQLITE_NOMEM;
    ++            goto finished_invert;
    ++          }
    ++          memset(apVal, 0, sizeof(apVal[0])*nCol*2);
    ++        }
    ++
    ++        /* Write the header for the new UPDATE change. Same as the original. */
    ++        sessionAppendByte(&sOut, eType, &rc);
    ++        sessionAppendByte(&sOut, pInput->aData[pInput->iNext+1], &rc);
    ++
    ++        /* Read the old.* and new.* records for the update change. */
    ++        pInput->iNext += 2;
    ++        rc = sessionReadRecord(pInput, nCol, 0, &apVal[0]);
    ++        if( rc==SQLITE_OK ){
    ++          rc = sessionReadRecord(pInput, nCol, 0, &apVal[nCol]);
    ++        }
    ++
    ++        /* Write the new old.* record. Consists of the PK columns from the
    ++        ** original old.* record, and the other values from the original
    ++        ** new.* record. */
    ++        for(iCol=0; iCol<nCol; iCol++){
    ++          sqlite3_value *pVal = apVal[iCol + (abPK[iCol] ? 0 : nCol)];
    ++          sessionAppendValue(&sOut, pVal, &rc);
    ++        }
    ++
    ++        /* Write the new new.* record. Consists of a copy of all values
    ++        ** from the original old.* record, except for the PK columns, which
    ++        ** are set to "undefined". */
    ++        for(iCol=0; iCol<nCol; iCol++){
    ++          sqlite3_value *pVal = (abPK[iCol] ? 0 : apVal[iCol]);
    ++          sessionAppendValue(&sOut, pVal, &rc);
    ++        }
    ++
    ++        for(iCol=0; iCol<nCol*2; iCol++){
    ++          sqlite3ValueFree(apVal[iCol]);
    ++        }
    ++        memset(apVal, 0, sizeof(apVal[0])*nCol*2);
    ++        if( rc!=SQLITE_OK ){
    ++          goto finished_invert;
    ++        }
    ++
    ++        break;
    ++      }
    ++
    ++      default:
    ++        rc = SQLITE_CORRUPT_BKPT;
    ++        goto finished_invert;
    ++    }
    ++
    ++    assert( rc==SQLITE_OK );
    ++    if( xOutput && sOut.nBuf>=SESSIONS_STRM_CHUNK_SIZE ){
    ++      rc = xOutput(pOut, sOut.aBuf, sOut.nBuf);
    ++      sOut.nBuf = 0;
    ++      if( rc!=SQLITE_OK ) goto finished_invert;
    ++    }
    ++  }
    ++
    ++  assert( rc==SQLITE_OK );
    ++  if( pnInverted ){
    ++    *pnInverted = sOut.nBuf;
    ++    *ppInverted = sOut.aBuf;
    ++    sOut.aBuf = 0;
    ++  }else if( sOut.nBuf>0 ){
    ++    rc = xOutput(pOut, sOut.aBuf, sOut.nBuf);
    ++  }
    ++
    ++ finished_invert:
    ++  sqlite3_free(sOut.aBuf);
    ++  sqlite3_free(apVal);
    ++  sqlite3_free(sPK.aBuf);
    ++  return rc;
    ++}
    ++
    ++
    ++/*
    ++** Invert a changeset object.
    ++*/
    ++SQLITE_API int sqlite3changeset_invert(
    ++  int nChangeset,                 /* Number of bytes in input */
    ++  const void *pChangeset,         /* Input changeset */
    ++  int *pnInverted,                /* OUT: Number of bytes in output changeset */
    ++  void **ppInverted               /* OUT: Inverse of pChangeset */
    ++){
    ++  SessionInput sInput;
    ++
    ++  /* Set up the input stream */
    ++  memset(&sInput, 0, sizeof(SessionInput));
    ++  sInput.nData = nChangeset;
    ++  sInput.aData = (u8*)pChangeset;
    ++
    ++  return sessionChangesetInvert(&sInput, 0, 0, pnInverted, ppInverted);
    ++}
    ++
    ++/*
    ++** Streaming version of sqlite3changeset_invert().
    ++*/
    ++SQLITE_API int sqlite3changeset_invert_strm(
    ++  int (*xInput)(void *pIn, void *pData, int *pnData),
    ++  void *pIn,
    ++  int (*xOutput)(void *pOut, const void *pData, int nData),
    ++  void *pOut
    ++){
    ++  SessionInput sInput;
    ++  int rc;
    ++
    ++  /* Set up the input stream */
    ++  memset(&sInput, 0, sizeof(SessionInput));
    ++  sInput.xInput = xInput;
    ++  sInput.pIn = pIn;
    ++
    ++  rc = sessionChangesetInvert(&sInput, xOutput, pOut, 0, 0);
    ++  sqlite3_free(sInput.buf.aBuf);
    ++  return rc;
    ++}
    ++
    ++typedef struct SessionApplyCtx SessionApplyCtx;
    ++struct SessionApplyCtx {
    ++  sqlite3 *db;
    ++  sqlite3_stmt *pDelete;          /* DELETE statement */
    ++  sqlite3_stmt *pUpdate;          /* UPDATE statement */
    ++  sqlite3_stmt *pInsert;          /* INSERT statement */
    ++  sqlite3_stmt *pSelect;          /* SELECT statement */
    ++  int nCol;                       /* Size of azCol[] and abPK[] arrays */
    ++  const char **azCol;             /* Array of column names */
    ++  u8 *abPK;                       /* Boolean array - true if column is in PK */
    ++  int bStat1;                     /* True if table is sqlite_stat1 */
    ++  int bDeferConstraints;          /* True to defer constraints */
    ++  SessionBuffer constraints;      /* Deferred constraints are stored here */
    ++};
    ++
    ++/*
    ++** Formulate a statement to DELETE a row from database db. Assuming a table
    ++** structure like this:
    ++**
    ++**     CREATE TABLE x(a, b, c, d, PRIMARY KEY(a, c));
    ++**
    ++** The DELETE statement looks like this:
    ++**
    ++**     DELETE FROM x WHERE a = :1 AND c = :3 AND (:5 OR b IS :2 AND d IS :4)
    ++**
    ++** Variable :5 (nCol+1) is a boolean. It should be set to 0 if we require
    ++** matching b and d values, or 1 otherwise. The second case comes up if the
    ++** conflict handler is invoked with NOTFOUND and returns CHANGESET_REPLACE.
    ++**
    ++** If successful, SQLITE_OK is returned and SessionApplyCtx.pDelete is left
    ++** pointing to the prepared version of the SQL statement.
    ++*/
    ++static int sessionDeleteRow(
    ++  sqlite3 *db,                    /* Database handle */
    ++  const char *zTab,               /* Table name */
    ++  SessionApplyCtx *p              /* Session changeset-apply context */
    ++){
    ++  int i;
    ++  const char *zSep = "";
    ++  int rc = SQLITE_OK;
    ++  SessionBuffer buf = {0, 0, 0};
    ++  int nPk = 0;
    ++
    ++  sessionAppendStr(&buf, "DELETE FROM ", &rc);
    ++  sessionAppendIdent(&buf, zTab, &rc);
    ++  sessionAppendStr(&buf, " WHERE ", &rc);
    ++
    ++  for(i=0; i<p->nCol; i++){
    ++    if( p->abPK[i] ){
    ++      nPk++;
    ++      sessionAppendStr(&buf, zSep, &rc);
    ++      sessionAppendIdent(&buf, p->azCol[i], &rc);
    ++      sessionAppendStr(&buf, " = ?", &rc);
    ++      sessionAppendInteger(&buf, i+1, &rc);
    ++      zSep = " AND ";
    ++    }
    ++  }
    ++
    ++  if( nPk<p->nCol ){
    ++    sessionAppendStr(&buf, " AND (?", &rc);
    ++    sessionAppendInteger(&buf, p->nCol+1, &rc);
    ++    sessionAppendStr(&buf, " OR ", &rc);
    ++
    ++    zSep = "";
    ++    for(i=0; i<p->nCol; i++){
    ++      if( !p->abPK[i] ){
    ++        sessionAppendStr(&buf, zSep, &rc);
    ++        sessionAppendIdent(&buf, p->azCol[i], &rc);
    ++        sessionAppendStr(&buf, " IS ?", &rc);
    ++        sessionAppendInteger(&buf, i+1, &rc);
    ++        zSep = "AND ";
    ++      }
    ++    }
    ++    sessionAppendStr(&buf, ")", &rc);
    ++  }
    ++
    ++  if( rc==SQLITE_OK ){
    ++    rc = sqlite3_prepare_v2(db, (char *)buf.aBuf, buf.nBuf, &p->pDelete, 0);
    ++  }
    ++  sqlite3_free(buf.aBuf);
    ++
    ++  return rc;
    ++}
    ++
    ++/*
    ++** Formulate and prepare a statement to UPDATE a row from database db. 
    ++** Assuming a table structure like this:
    ++**
    ++**     CREATE TABLE x(a, b, c, d, PRIMARY KEY(a, c));
    ++**
    ++** The UPDATE statement looks like this:
    ++**
    ++**     UPDATE x SET
    ++**     a = CASE WHEN ?2  THEN ?3  ELSE a END,
    ++**     b = CASE WHEN ?5  THEN ?6  ELSE b END,
    ++**     c = CASE WHEN ?8  THEN ?9  ELSE c END,
    ++**     d = CASE WHEN ?11 THEN ?12 ELSE d END
    ++**     WHERE a = ?1 AND c = ?7 AND (?13 OR 
    ++**       (?5==0 OR b IS ?4) AND (?11==0 OR d IS ?10) AND
    ++**     )
    ++**
    ++** For each column in the table, there are three variables to bind:
    ++**
    ++**     ?(i*3+1)    The old.* value of the column, if any.
    ++**     ?(i*3+2)    A boolean flag indicating that the value is being modified.
    ++**     ?(i*3+3)    The new.* value of the column, if any.
    ++**
    ++** Also, a boolean flag that, if set to true, causes the statement to update
    ++** a row even if the non-PK values do not match. This is required if the
    ++** conflict-handler is invoked with CHANGESET_DATA and returns
    ++** CHANGESET_REPLACE. This is variable "?(nCol*3+1)".
    ++**
    ++** If successful, SQLITE_OK is returned and SessionApplyCtx.pUpdate is left
    ++** pointing to the prepared version of the SQL statement.
    ++*/
    ++static int sessionUpdateRow(
    ++  sqlite3 *db,                    /* Database handle */
    ++  const char *zTab,               /* Table name */
    ++  SessionApplyCtx *p              /* Session changeset-apply context */
    ++){
    ++  int rc = SQLITE_OK;
    ++  int i;
    ++  const char *zSep = "";
    ++  SessionBuffer buf = {0, 0, 0};
    ++
    ++  /* Append "UPDATE tbl SET " */
    ++  sessionAppendStr(&buf, "UPDATE ", &rc);
    ++  sessionAppendIdent(&buf, zTab, &rc);
    ++  sessionAppendStr(&buf, " SET ", &rc);
    ++
    ++  /* Append the assignments */
    ++  for(i=0; i<p->nCol; i++){
    ++    sessionAppendStr(&buf, zSep, &rc);
    ++    sessionAppendIdent(&buf, p->azCol[i], &rc);
    ++    sessionAppendStr(&buf, " = CASE WHEN ?", &rc);
    ++    sessionAppendInteger(&buf, i*3+2, &rc);
    ++    sessionAppendStr(&buf, " THEN ?", &rc);
    ++    sessionAppendInteger(&buf, i*3+3, &rc);
    ++    sessionAppendStr(&buf, " ELSE ", &rc);
    ++    sessionAppendIdent(&buf, p->azCol[i], &rc);
    ++    sessionAppendStr(&buf, " END", &rc);
    ++    zSep = ", ";
    ++  }
    ++
    ++  /* Append the PK part of the WHERE clause */
    ++  sessionAppendStr(&buf, " WHERE ", &rc);
    ++  for(i=0; i<p->nCol; i++){
    ++    if( p->abPK[i] ){
    ++      sessionAppendIdent(&buf, p->azCol[i], &rc);
    ++      sessionAppendStr(&buf, " = ?", &rc);
    ++      sessionAppendInteger(&buf, i*3+1, &rc);
    ++      sessionAppendStr(&buf, " AND ", &rc);
    ++    }
    ++  }
    ++
    ++  /* Append the non-PK part of the WHERE clause */
    ++  sessionAppendStr(&buf, " (?", &rc);
    ++  sessionAppendInteger(&buf, p->nCol*3+1, &rc);
    ++  sessionAppendStr(&buf, " OR 1", &rc);
    ++  for(i=0; i<p->nCol; i++){
    ++    if( !p->abPK[i] ){
    ++      sessionAppendStr(&buf, " AND (?", &rc);
    ++      sessionAppendInteger(&buf, i*3+2, &rc);
    ++      sessionAppendStr(&buf, "=0 OR ", &rc);
    ++      sessionAppendIdent(&buf, p->azCol[i], &rc);
    ++      sessionAppendStr(&buf, " IS ?", &rc);
    ++      sessionAppendInteger(&buf, i*3+1, &rc);
    ++      sessionAppendStr(&buf, ")", &rc);
    ++    }
    ++  }
    ++  sessionAppendStr(&buf, ")", &rc);
    ++
    ++  if( rc==SQLITE_OK ){
    ++    rc = sqlite3_prepare_v2(db, (char *)buf.aBuf, buf.nBuf, &p->pUpdate, 0);
    ++  }
    ++  sqlite3_free(buf.aBuf);
    ++
    ++  return rc;
    ++}
    ++
    ++
    ++/*
    ++** Formulate and prepare an SQL statement to query table zTab by primary
    ++** key. Assuming the following table structure:
    ++**
    ++**     CREATE TABLE x(a, b, c, d, PRIMARY KEY(a, c));
    ++**
    ++** The SELECT statement looks like this:
    ++**
    ++**     SELECT * FROM x WHERE a = ?1 AND c = ?3
    ++**
    ++** If successful, SQLITE_OK is returned and SessionApplyCtx.pSelect is left
    ++** pointing to the prepared version of the SQL statement.
    ++*/
    ++static int sessionSelectRow(
    ++  sqlite3 *db,                    /* Database handle */
    ++  const char *zTab,               /* Table name */
    ++  SessionApplyCtx *p              /* Session changeset-apply context */
    ++){
    ++  return sessionSelectStmt(
    ++      db, "main", zTab, p->nCol, p->azCol, p->abPK, &p->pSelect);
    ++}
    ++
    ++/*
    ++** Formulate and prepare an INSERT statement to add a record to table zTab.
    ++** For example:
    ++**
    ++**     INSERT INTO main."zTab" VALUES(?1, ?2, ?3 ...);
    ++**
    ++** If successful, SQLITE_OK is returned and SessionApplyCtx.pInsert is left
    ++** pointing to the prepared version of the SQL statement.
    ++*/
    ++static int sessionInsertRow(
    ++  sqlite3 *db,                    /* Database handle */
    ++  const char *zTab,               /* Table name */
    ++  SessionApplyCtx *p              /* Session changeset-apply context */
    ++){
    ++  int rc = SQLITE_OK;
    ++  int i;
    ++  SessionBuffer buf = {0, 0, 0};
    ++
    ++  sessionAppendStr(&buf, "INSERT INTO main.", &rc);
    ++  sessionAppendIdent(&buf, zTab, &rc);
    ++  sessionAppendStr(&buf, "(", &rc);
    ++  for(i=0; i<p->nCol; i++){
    ++    if( i!=0 ) sessionAppendStr(&buf, ", ", &rc);
    ++    sessionAppendIdent(&buf, p->azCol[i], &rc);
    ++  }
    ++
    ++  sessionAppendStr(&buf, ") VALUES(?", &rc);
    ++  for(i=1; i<p->nCol; i++){
    ++    sessionAppendStr(&buf, ", ?", &rc);
    ++  }
    ++  sessionAppendStr(&buf, ")", &rc);
    ++
    ++  if( rc==SQLITE_OK ){
    ++    rc = sqlite3_prepare_v2(db, (char *)buf.aBuf, buf.nBuf, &p->pInsert, 0);
    ++  }
    ++  sqlite3_free(buf.aBuf);
    ++  return rc;
    ++}
    ++
    ++static int sessionPrepare(sqlite3 *db, sqlite3_stmt **pp, const char *zSql){
    ++  return sqlite3_prepare_v2(db, zSql, -1, pp, 0);
    ++}
    ++
    ++/*
    ++** Prepare statements for applying changes to the sqlite_stat1 table.
    ++** These are similar to those created by sessionSelectRow(),
    ++** sessionInsertRow(), sessionUpdateRow() and sessionDeleteRow() for 
    ++** other tables.
    ++*/
    ++static int sessionStat1Sql(sqlite3 *db, SessionApplyCtx *p){
    ++  int rc = sessionSelectRow(db, "sqlite_stat1", p);
    ++  if( rc==SQLITE_OK ){
    ++    rc = sessionPrepare(db, &p->pInsert,
    ++        "INSERT INTO main.sqlite_stat1 VALUES(?1, "
    ++        "CASE WHEN length(?2)=0 AND typeof(?2)='blob' THEN NULL ELSE ?2 END, "
    ++        "?3)"
    ++    );
    ++  }
    ++  if( rc==SQLITE_OK ){
    ++    rc = sessionPrepare(db, &p->pUpdate,
    ++        "UPDATE main.sqlite_stat1 SET "
    ++        "tbl = CASE WHEN ?2 THEN ?3 ELSE tbl END, "
    ++        "idx = CASE WHEN ?5 THEN ?6 ELSE idx END, "
    ++        "stat = CASE WHEN ?8 THEN ?9 ELSE stat END  "
    ++        "WHERE tbl=?1 AND idx IS "
    ++        "CASE WHEN length(?4)=0 AND typeof(?4)='blob' THEN NULL ELSE ?4 END "
    ++        "AND (?10 OR ?8=0 OR stat IS ?7)"
    ++    );
    ++  }
    ++  if( rc==SQLITE_OK ){
    ++    rc = sessionPrepare(db, &p->pDelete,
    ++        "DELETE FROM main.sqlite_stat1 WHERE tbl=?1 AND idx IS "
    ++        "CASE WHEN length(?2)=0 AND typeof(?2)='blob' THEN NULL ELSE ?2 END "
    ++        "AND (?4 OR stat IS ?3)"
    ++    );
    ++  }
    ++  assert( rc==SQLITE_OK );
    ++  return rc;
    ++}
    ++
    ++/*
    ++** A wrapper around sqlite3_bind_value() that detects an extra problem. 
    ++** See comments in the body of this function for details.
    ++*/
    ++static int sessionBindValue(
    ++  sqlite3_stmt *pStmt,            /* Statement to bind value to */
    ++  int i,                          /* Parameter number to bind to */
    ++  sqlite3_value *pVal             /* Value to bind */
    ++){
    ++  int eType = sqlite3_value_type(pVal);
    ++  /* COVERAGE: The (pVal->z==0) branch is never true using current versions
    ++  ** of SQLite. If a malloc fails in an sqlite3_value_xxx() function, either
    ++  ** the (pVal->z) variable remains as it was or the type of the value is
    ++  ** set to SQLITE_NULL.  */
    ++  if( (eType==SQLITE_TEXT || eType==SQLITE_BLOB) && pVal->z==0 ){
    ++    /* This condition occurs when an earlier OOM in a call to
    ++    ** sqlite3_value_text() or sqlite3_value_blob() (perhaps from within
    ++    ** a conflict-handler) has zeroed the pVal->z pointer. Return NOMEM. */
    ++    return SQLITE_NOMEM;
    ++  }
    ++  return sqlite3_bind_value(pStmt, i, pVal);
    ++}
    ++
    ++/*
    ++** Iterator pIter must point to an SQLITE_INSERT entry. This function 
    ++** transfers new.* values from the current iterator entry to statement
    ++** pStmt. The table being inserted into has nCol columns.
    ++**
    ++** New.* value $i from the iterator is bound to variable ($i+1) of 
    ++** statement pStmt. If parameter abPK is NULL, all values from 0 to (nCol-1)
    ++** are transfered to the statement. Otherwise, if abPK is not NULL, it points
    ++** to an array nCol elements in size. In this case only those values for 
    ++** which abPK[$i] is true are read from the iterator and bound to the 
    ++** statement.
    ++**
    ++** An SQLite error code is returned if an error occurs. Otherwise, SQLITE_OK.
    ++*/
    ++static int sessionBindRow(
    ++  sqlite3_changeset_iter *pIter,  /* Iterator to read values from */
    ++  int(*xValue)(sqlite3_changeset_iter *, int, sqlite3_value **),
    ++  int nCol,                       /* Number of columns */
    ++  u8 *abPK,                       /* If not NULL, bind only if true */
    ++  sqlite3_stmt *pStmt             /* Bind values to this statement */
    ++){
    ++  int i;
    ++  int rc = SQLITE_OK;
    ++
    ++  /* Neither sqlite3changeset_old or sqlite3changeset_new can fail if the
    ++  ** argument iterator points to a suitable entry. Make sure that xValue 
    ++  ** is one of these to guarantee that it is safe to ignore the return 
    ++  ** in the code below. */
    ++  assert( xValue==sqlite3changeset_old || xValue==sqlite3changeset_new );
    ++
    ++  for(i=0; rc==SQLITE_OK && i<nCol; i++){
    ++    if( !abPK || abPK[i] ){
    ++      sqlite3_value *pVal;
    ++      (void)xValue(pIter, i, &pVal);
    ++      rc = sessionBindValue(pStmt, i+1, pVal);
    ++    }
    ++  }
    ++  return rc;
    ++}
    ++
    ++/*
    ++** SQL statement pSelect is as generated by the sessionSelectRow() function.
    ++** This function binds the primary key values from the change that changeset
    ++** iterator pIter points to to the SELECT and attempts to seek to the table
    ++** entry. If a row is found, the SELECT statement left pointing at the row 
    ++** and SQLITE_ROW is returned. Otherwise, if no row is found and no error
    ++** has occured, the statement is reset and SQLITE_OK is returned. If an
    ++** error occurs, the statement is reset and an SQLite error code is returned.
    ++**
    ++** If this function returns SQLITE_ROW, the caller must eventually reset() 
    ++** statement pSelect. If any other value is returned, the statement does
    ++** not require a reset().
    ++**
    ++** If the iterator currently points to an INSERT record, bind values from the
    ++** new.* record to the SELECT statement. Or, if it points to a DELETE or
    ++** UPDATE, bind values from the old.* record. 
    ++*/
    ++static int sessionSeekToRow(
    ++  sqlite3 *db,                    /* Database handle */
    ++  sqlite3_changeset_iter *pIter,  /* Changeset iterator */
    ++  u8 *abPK,                       /* Primary key flags array */
    ++  sqlite3_stmt *pSelect           /* SELECT statement from sessionSelectRow() */
    ++){
    ++  int rc;                         /* Return code */
    ++  int nCol;                       /* Number of columns in table */
    ++  int op;                         /* Changset operation (SQLITE_UPDATE etc.) */
    ++  const char *zDummy;             /* Unused */
    ++
    ++  sqlite3changeset_op(pIter, &zDummy, &nCol, &op, 0);
    ++  rc = sessionBindRow(pIter, 
    ++      op==SQLITE_INSERT ? sqlite3changeset_new : sqlite3changeset_old,
    ++      nCol, abPK, pSelect
    ++  );
    ++
    ++  if( rc==SQLITE_OK ){
    ++    rc = sqlite3_step(pSelect);
    ++    if( rc!=SQLITE_ROW ) rc = sqlite3_reset(pSelect);
    ++  }
    ++
    ++  return rc;
    ++}
    ++
    ++/*
    ++** Invoke the conflict handler for the change that the changeset iterator
    ++** currently points to.
    ++**
    ++** Argument eType must be either CHANGESET_DATA or CHANGESET_CONFLICT.
    ++** If argument pbReplace is NULL, then the type of conflict handler invoked
    ++** depends solely on eType, as follows:
    ++**
    ++**    eType value                 Value passed to xConflict
    ++**    -------------------------------------------------
    ++**    CHANGESET_DATA              CHANGESET_NOTFOUND
    ++**    CHANGESET_CONFLICT          CHANGESET_CONSTRAINT
    ++**
    ++** Or, if pbReplace is not NULL, then an attempt is made to find an existing
    ++** record with the same primary key as the record about to be deleted, updated
    ++** or inserted. If such a record can be found, it is available to the conflict
    ++** handler as the "conflicting" record. In this case the type of conflict
    ++** handler invoked is as follows:
    ++**
    ++**    eType value         PK Record found?   Value passed to xConflict
    ++**    ----------------------------------------------------------------
    ++**    CHANGESET_DATA      Yes                CHANGESET_DATA
    ++**    CHANGESET_DATA      No                 CHANGESET_NOTFOUND
    ++**    CHANGESET_CONFLICT  Yes                CHANGESET_CONFLICT
    ++**    CHANGESET_CONFLICT  No                 CHANGESET_CONSTRAINT
    ++**
    ++** If pbReplace is not NULL, and a record with a matching PK is found, and
    ++** the conflict handler function returns SQLITE_CHANGESET_REPLACE, *pbReplace
    ++** is set to non-zero before returning SQLITE_OK.
    ++**
    ++** If the conflict handler returns SQLITE_CHANGESET_ABORT, SQLITE_ABORT is
    ++** returned. Or, if the conflict handler returns an invalid value, 
    ++** SQLITE_MISUSE. If the conflict handler returns SQLITE_CHANGESET_OMIT,
    ++** this function returns SQLITE_OK.
    ++*/
    ++static int sessionConflictHandler(
    ++  int eType,                      /* Either CHANGESET_DATA or CONFLICT */
    ++  SessionApplyCtx *p,             /* changeset_apply() context */
    ++  sqlite3_changeset_iter *pIter,  /* Changeset iterator */
    ++  int(*xConflict)(void *, int, sqlite3_changeset_iter*),
    ++  void *pCtx,                     /* First argument for conflict handler */
    ++  int *pbReplace                  /* OUT: Set to true if PK row is found */
    ++){
    ++  int res = 0;                    /* Value returned by conflict handler */
    ++  int rc;
    ++  int nCol;
    ++  int op;
    ++  const char *zDummy;
    ++
    ++  sqlite3changeset_op(pIter, &zDummy, &nCol, &op, 0);
    ++
    ++  assert( eType==SQLITE_CHANGESET_CONFLICT || eType==SQLITE_CHANGESET_DATA );
    ++  assert( SQLITE_CHANGESET_CONFLICT+1==SQLITE_CHANGESET_CONSTRAINT );
    ++  assert( SQLITE_CHANGESET_DATA+1==SQLITE_CHANGESET_NOTFOUND );
    ++
    ++  /* Bind the new.* PRIMARY KEY values to the SELECT statement. */
    ++  if( pbReplace ){
    ++    rc = sessionSeekToRow(p->db, pIter, p->abPK, p->pSelect);
    ++  }else{
    ++    rc = SQLITE_OK;
    ++  }
    ++
    ++  if( rc==SQLITE_ROW ){
    ++    /* There exists another row with the new.* primary key. */
    ++    pIter->pConflict = p->pSelect;
    ++    res = xConflict(pCtx, eType, pIter);
    ++    pIter->pConflict = 0;
    ++    rc = sqlite3_reset(p->pSelect);
    ++  }else if( rc==SQLITE_OK ){
    ++    if( p->bDeferConstraints && eType==SQLITE_CHANGESET_CONFLICT ){
    ++      /* Instead of invoking the conflict handler, append the change blob
    ++      ** to the SessionApplyCtx.constraints buffer. */
    ++      u8 *aBlob = &pIter->in.aData[pIter->in.iCurrent];
    ++      int nBlob = pIter->in.iNext - pIter->in.iCurrent;
    ++      sessionAppendBlob(&p->constraints, aBlob, nBlob, &rc);
    ++      res = SQLITE_CHANGESET_OMIT;
    ++    }else{
    ++      /* No other row with the new.* primary key. */
    ++      res = xConflict(pCtx, eType+1, pIter);
    ++      if( res==SQLITE_CHANGESET_REPLACE ) rc = SQLITE_MISUSE;
    ++    }
    ++  }
    ++
    ++  if( rc==SQLITE_OK ){
    ++    switch( res ){
    ++      case SQLITE_CHANGESET_REPLACE:
    ++        assert( pbReplace );
    ++        *pbReplace = 1;
    ++        break;
    ++
    ++      case SQLITE_CHANGESET_OMIT:
    ++        break;
    ++
    ++      case SQLITE_CHANGESET_ABORT:
    ++        rc = SQLITE_ABORT;
    ++        break;
    ++
    ++      default:
    ++        rc = SQLITE_MISUSE;
    ++        break;
    ++    }
    ++  }
    ++
    ++  return rc;
    ++}
    ++
    ++/*
    ++** Attempt to apply the change that the iterator passed as the first argument
    ++** currently points to to the database. If a conflict is encountered, invoke
    ++** the conflict handler callback.
    ++**
    ++** If argument pbRetry is NULL, then ignore any CHANGESET_DATA conflict. If
    ++** one is encountered, update or delete the row with the matching primary key
    ++** instead. Or, if pbRetry is not NULL and a CHANGESET_DATA conflict occurs,
    ++** invoke the conflict handler. If it returns CHANGESET_REPLACE, set *pbRetry
    ++** to true before returning. In this case the caller will invoke this function
    ++** again, this time with pbRetry set to NULL.
    ++**
    ++** If argument pbReplace is NULL and a CHANGESET_CONFLICT conflict is 
    ++** encountered invoke the conflict handler with CHANGESET_CONSTRAINT instead.
    ++** Or, if pbReplace is not NULL, invoke it with CHANGESET_CONFLICT. If such
    ++** an invocation returns SQLITE_CHANGESET_REPLACE, set *pbReplace to true
    ++** before retrying. In this case the caller attempts to remove the conflicting
    ++** row before invoking this function again, this time with pbReplace set 
    ++** to NULL.
    ++**
    ++** If any conflict handler returns SQLITE_CHANGESET_ABORT, this function
    ++** returns SQLITE_ABORT. Otherwise, if no error occurs, SQLITE_OK is 
    ++** returned.
    ++*/
    ++static int sessionApplyOneOp(
    ++  sqlite3_changeset_iter *pIter,  /* Changeset iterator */
    ++  SessionApplyCtx *p,             /* changeset_apply() context */
    ++  int(*xConflict)(void *, int, sqlite3_changeset_iter *),
    ++  void *pCtx,                     /* First argument for the conflict handler */
    ++  int *pbReplace,                 /* OUT: True to remove PK row and retry */
    ++  int *pbRetry                    /* OUT: True to retry. */
    ++){
    ++  const char *zDummy;
    ++  int op;
    ++  int nCol;
    ++  int rc = SQLITE_OK;
    ++
    ++  assert( p->pDelete && p->pUpdate && p->pInsert && p->pSelect );
    ++  assert( p->azCol && p->abPK );
    ++  assert( !pbReplace || *pbReplace==0 );
    ++
    ++  sqlite3changeset_op(pIter, &zDummy, &nCol, &op, 0);
    ++
    ++  if( op==SQLITE_DELETE ){
    ++
    ++    /* Bind values to the DELETE statement. If conflict handling is required,
    ++    ** bind values for all columns and set bound variable (nCol+1) to true.
    ++    ** Or, if conflict handling is not required, bind just the PK column
    ++    ** values and, if it exists, set (nCol+1) to false. Conflict handling
    ++    ** is not required if:
    ++    **
    ++    **   * this is a patchset, or
    ++    **   * (pbRetry==0), or
    ++    **   * all columns of the table are PK columns (in this case there is
    ++    **     no (nCol+1) variable to bind to).
    ++    */
    ++    u8 *abPK = (pIter->bPatchset ? p->abPK : 0);
    ++    rc = sessionBindRow(pIter, sqlite3changeset_old, nCol, abPK, p->pDelete);
    ++    if( rc==SQLITE_OK && sqlite3_bind_parameter_count(p->pDelete)>nCol ){
    ++      rc = sqlite3_bind_int(p->pDelete, nCol+1, (pbRetry==0 || abPK));
    ++    }
    ++    if( rc!=SQLITE_OK ) return rc;
    ++
    ++    sqlite3_step(p->pDelete);
    ++    rc = sqlite3_reset(p->pDelete);
    ++    if( rc==SQLITE_OK && sqlite3_changes(p->db)==0 ){
    ++      rc = sessionConflictHandler(
    ++          SQLITE_CHANGESET_DATA, p, pIter, xConflict, pCtx, pbRetry
    ++      );
    ++    }else if( (rc&0xff)==SQLITE_CONSTRAINT ){
    ++      rc = sessionConflictHandler(
    ++          SQLITE_CHANGESET_CONFLICT, p, pIter, xConflict, pCtx, 0
    ++      );
    ++    }
    ++
    ++  }else if( op==SQLITE_UPDATE ){
    ++    int i;
    ++
    ++    /* Bind values to the UPDATE statement. */
    ++    for(i=0; rc==SQLITE_OK && i<nCol; i++){
    ++      sqlite3_value *pOld = sessionChangesetOld(pIter, i);
    ++      sqlite3_value *pNew = sessionChangesetNew(pIter, i);
    ++
    ++      sqlite3_bind_int(p->pUpdate, i*3+2, !!pNew);
    ++      if( pOld ){
    ++        rc = sessionBindValue(p->pUpdate, i*3+1, pOld);
    ++      }
    ++      if( rc==SQLITE_OK && pNew ){
    ++        rc = sessionBindValue(p->pUpdate, i*3+3, pNew);
    ++      }
    ++    }
    ++    if( rc==SQLITE_OK ){
    ++      sqlite3_bind_int(p->pUpdate, nCol*3+1, pbRetry==0 || pIter->bPatchset);
    ++    }
    ++    if( rc!=SQLITE_OK ) return rc;
    ++
    ++    /* Attempt the UPDATE. In the case of a NOTFOUND or DATA conflict,
    ++    ** the result will be SQLITE_OK with 0 rows modified. */
    ++    sqlite3_step(p->pUpdate);
    ++    rc = sqlite3_reset(p->pUpdate);
    ++
    ++    if( rc==SQLITE_OK && sqlite3_changes(p->db)==0 ){
    ++      /* A NOTFOUND or DATA error. Search the table to see if it contains
    ++      ** a row with a matching primary key. If so, this is a DATA conflict.
    ++      ** Otherwise, if there is no primary key match, it is a NOTFOUND. */
    ++
    ++      rc = sessionConflictHandler(
    ++          SQLITE_CHANGESET_DATA, p, pIter, xConflict, pCtx, pbRetry
    ++      );
    ++
    ++    }else if( (rc&0xff)==SQLITE_CONSTRAINT ){
    ++      /* This is always a CONSTRAINT conflict. */
    ++      rc = sessionConflictHandler(
    ++          SQLITE_CHANGESET_CONFLICT, p, pIter, xConflict, pCtx, 0
    ++      );
    ++    }
    ++
    ++  }else{
    ++    assert( op==SQLITE_INSERT );
    ++    if( p->bStat1 ){
    ++      /* Check if there is a conflicting row. For sqlite_stat1, this needs
    ++      ** to be done using a SELECT, as there is no PRIMARY KEY in the 
    ++      ** database schema to throw an exception if a duplicate is inserted.  */
    ++      rc = sessionSeekToRow(p->db, pIter, p->abPK, p->pSelect);
    ++      if( rc==SQLITE_ROW ){
    ++        rc = SQLITE_CONSTRAINT;
    ++        sqlite3_reset(p->pSelect);
    ++      }
    ++    }
    ++
    ++    if( rc==SQLITE_OK ){
    ++      rc = sessionBindRow(pIter, sqlite3changeset_new, nCol, 0, p->pInsert);
    ++      if( rc!=SQLITE_OK ) return rc;
    ++
    ++      sqlite3_step(p->pInsert);
    ++      rc = sqlite3_reset(p->pInsert);
    ++    }
    ++
    ++    if( (rc&0xff)==SQLITE_CONSTRAINT ){
    ++      rc = sessionConflictHandler(
    ++          SQLITE_CHANGESET_CONFLICT, p, pIter, xConflict, pCtx, pbReplace
    ++      );
    ++    }
    ++  }
    ++
    ++  return rc;
    ++}
    ++
    ++/*
    ++** Attempt to apply the change that the iterator passed as the first argument
    ++** currently points to to the database. If a conflict is encountered, invoke
    ++** the conflict handler callback.
    ++**
    ++** The difference between this function and sessionApplyOne() is that this
    ++** function handles the case where the conflict-handler is invoked and 
    ++** returns SQLITE_CHANGESET_REPLACE - indicating that the change should be
    ++** retried in some manner.
    ++*/
    ++static int sessionApplyOneWithRetry(
    ++  sqlite3 *db,                    /* Apply change to "main" db of this handle */
    ++  sqlite3_changeset_iter *pIter,  /* Changeset iterator to read change from */
    ++  SessionApplyCtx *pApply,        /* Apply context */
    ++  int(*xConflict)(void*, int, sqlite3_changeset_iter*),
    ++  void *pCtx                      /* First argument passed to xConflict */
    ++){
    ++  int bReplace = 0;
    ++  int bRetry = 0;
    ++  int rc;
    ++
    ++  rc = sessionApplyOneOp(pIter, pApply, xConflict, pCtx, &bReplace, &bRetry);
    ++  assert( rc==SQLITE_OK || (bRetry==0 && bReplace==0) );
    ++
    ++  /* If the bRetry flag is set, the change has not been applied due to an
    ++  ** SQLITE_CHANGESET_DATA problem (i.e. this is an UPDATE or DELETE and
    ++  ** a row with the correct PK is present in the db, but one or more other
    ++  ** fields do not contain the expected values) and the conflict handler 
    ++  ** returned SQLITE_CHANGESET_REPLACE. In this case retry the operation,
    ++  ** but pass NULL as the final argument so that sessionApplyOneOp() ignores
    ++  ** the SQLITE_CHANGESET_DATA problem.  */
    ++  if( bRetry ){
    ++    assert( pIter->op==SQLITE_UPDATE || pIter->op==SQLITE_DELETE );
    ++    rc = sessionApplyOneOp(pIter, pApply, xConflict, pCtx, 0, 0);
    ++  }
    ++
    ++  /* If the bReplace flag is set, the change is an INSERT that has not
    ++  ** been performed because the database already contains a row with the
    ++  ** specified primary key and the conflict handler returned
    ++  ** SQLITE_CHANGESET_REPLACE. In this case remove the conflicting row
    ++  ** before reattempting the INSERT.  */
    ++  else if( bReplace ){
    ++    assert( pIter->op==SQLITE_INSERT );
    ++    rc = sqlite3_exec(db, "SAVEPOINT replace_op", 0, 0, 0);
    ++    if( rc==SQLITE_OK ){
    ++      rc = sessionBindRow(pIter, 
    ++          sqlite3changeset_new, pApply->nCol, pApply->abPK, pApply->pDelete);
    ++      sqlite3_bind_int(pApply->pDelete, pApply->nCol+1, 1);
    ++    }
    ++    if( rc==SQLITE_OK ){
    ++      sqlite3_step(pApply->pDelete);
    ++      rc = sqlite3_reset(pApply->pDelete);
    ++    }
    ++    if( rc==SQLITE_OK ){
    ++      rc = sessionApplyOneOp(pIter, pApply, xConflict, pCtx, 0, 0);
    ++    }
    ++    if( rc==SQLITE_OK ){
    ++      rc = sqlite3_exec(db, "RELEASE replace_op", 0, 0, 0);
    ++    }
    ++  }
    ++
    ++  return rc;
    ++}
    ++
    ++/*
    ++** Retry the changes accumulated in the pApply->constraints buffer.
    ++*/
    ++static int sessionRetryConstraints(
    ++  sqlite3 *db, 
    ++  int bPatchset,
    ++  const char *zTab,
    ++  SessionApplyCtx *pApply,
    ++  int(*xConflict)(void*, int, sqlite3_changeset_iter*),
    ++  void *pCtx                      /* First argument passed to xConflict */
    ++){
    ++  int rc = SQLITE_OK;
    ++
    ++  while( pApply->constraints.nBuf ){
    ++    sqlite3_changeset_iter *pIter2 = 0;
    ++    SessionBuffer cons = pApply->constraints;
    ++    memset(&pApply->constraints, 0, sizeof(SessionBuffer));
    ++
    ++    rc = sessionChangesetStart(&pIter2, 0, 0, cons.nBuf, cons.aBuf);
    ++    if( rc==SQLITE_OK ){
    ++      int nByte = 2*pApply->nCol*sizeof(sqlite3_value*);
    ++      int rc2;
    ++      pIter2->bPatchset = bPatchset;
    ++      pIter2->zTab = (char*)zTab;
    ++      pIter2->nCol = pApply->nCol;
    ++      pIter2->abPK = pApply->abPK;
    ++      sessionBufferGrow(&pIter2->tblhdr, nByte, &rc);
    ++      pIter2->apValue = (sqlite3_value**)pIter2->tblhdr.aBuf;
    ++      if( rc==SQLITE_OK ) memset(pIter2->apValue, 0, nByte);
    ++
    ++      while( rc==SQLITE_OK && SQLITE_ROW==sqlite3changeset_next(pIter2) ){
    ++        rc = sessionApplyOneWithRetry(db, pIter2, pApply, xConflict, pCtx);
    ++      }
    ++
    ++      rc2 = sqlite3changeset_finalize(pIter2);
    ++      if( rc==SQLITE_OK ) rc = rc2;
    ++    }
    ++    assert( pApply->bDeferConstraints || pApply->constraints.nBuf==0 );
    ++
    ++    sqlite3_free(cons.aBuf);
    ++    if( rc!=SQLITE_OK ) break;
    ++    if( pApply->constraints.nBuf>=cons.nBuf ){
    ++      /* No progress was made on the last round. */
    ++      pApply->bDeferConstraints = 0;
    ++    }
    ++  }
    ++
    ++  return rc;
    ++}
    ++
    ++/*
    ++** Argument pIter is a changeset iterator that has been initialized, but
    ++** not yet passed to sqlite3changeset_next(). This function applies the 
    ++** changeset to the main database attached to handle "db". The supplied
    ++** conflict handler callback is invoked to resolve any conflicts encountered
    ++** while applying the change.
    ++*/
    ++static int sessionChangesetApply(
    ++  sqlite3 *db,                    /* Apply change to "main" db of this handle */
    ++  sqlite3_changeset_iter *pIter,  /* Changeset to apply */
    ++  int(*xFilter)(
    ++    void *pCtx,                   /* Copy of sixth arg to _apply() */
    ++    const char *zTab              /* Table name */
    ++  ),
    ++  int(*xConflict)(
    ++    void *pCtx,                   /* Copy of fifth arg to _apply() */
    ++    int eConflict,                /* DATA, MISSING, CONFLICT, CONSTRAINT */
    ++    sqlite3_changeset_iter *p     /* Handle describing change and conflict */
    ++  ),
    ++  void *pCtx                      /* First argument passed to xConflict */
    ++){
    ++  int schemaMismatch = 0;
    ++  int rc;                         /* Return code */
    ++  const char *zTab = 0;           /* Name of current table */
    ++  int nTab = 0;                   /* Result of sqlite3Strlen30(zTab) */
    ++  SessionApplyCtx sApply;         /* changeset_apply() context object */
    ++  int bPatchset;
    ++
    ++  assert( xConflict!=0 );
    ++
    ++  pIter->in.bNoDiscard = 1;
    ++  memset(&sApply, 0, sizeof(sApply));
    ++  sqlite3_mutex_enter(sqlite3_db_mutex(db));
    ++  rc = sqlite3_exec(db, "SAVEPOINT changeset_apply", 0, 0, 0);
    ++  if( rc==SQLITE_OK ){
    ++    rc = sqlite3_exec(db, "PRAGMA defer_foreign_keys = 1", 0, 0, 0);
    ++  }
    ++  while( rc==SQLITE_OK && SQLITE_ROW==sqlite3changeset_next(pIter) ){
    ++    int nCol;
    ++    int op;
    ++    const char *zNew;
    ++    
    ++    sqlite3changeset_op(pIter, &zNew, &nCol, &op, 0);
    ++
    ++    if( zTab==0 || sqlite3_strnicmp(zNew, zTab, nTab+1) ){
    ++      u8 *abPK;
    ++
    ++      rc = sessionRetryConstraints(
    ++          db, pIter->bPatchset, zTab, &sApply, xConflict, pCtx
    ++      );
    ++      if( rc!=SQLITE_OK ) break;
    ++
    ++      sqlite3_free((char*)sApply.azCol);  /* cast works around VC++ bug */
    ++      sqlite3_finalize(sApply.pDelete);
    ++      sqlite3_finalize(sApply.pUpdate); 
    ++      sqlite3_finalize(sApply.pInsert);
    ++      sqlite3_finalize(sApply.pSelect);
    ++      memset(&sApply, 0, sizeof(sApply));
    ++      sApply.db = db;
    ++      sApply.bDeferConstraints = 1;
    ++
    ++      /* If an xFilter() callback was specified, invoke it now. If the 
    ++      ** xFilter callback returns zero, skip this table. If it returns
    ++      ** non-zero, proceed. */
    ++      schemaMismatch = (xFilter && (0==xFilter(pCtx, zNew)));
    ++      if( schemaMismatch ){
    ++        zTab = sqlite3_mprintf("%s", zNew);
    ++        if( zTab==0 ){
    ++          rc = SQLITE_NOMEM;
    ++          break;
    ++        }
    ++        nTab = (int)strlen(zTab);
    ++        sApply.azCol = (const char **)zTab;
    ++      }else{
    ++        int nMinCol = 0;
    ++        int i;
    ++
    ++        sqlite3changeset_pk(pIter, &abPK, 0);
    ++        rc = sessionTableInfo(
    ++            db, "main", zNew, &sApply.nCol, &zTab, &sApply.azCol, &sApply.abPK
    ++        );
    ++        if( rc!=SQLITE_OK ) break;
    ++        for(i=0; i<sApply.nCol; i++){
    ++          if( sApply.abPK[i] ) nMinCol = i+1;
    ++        }
    ++  
    ++        if( sApply.nCol==0 ){
    ++          schemaMismatch = 1;
    ++          sqlite3_log(SQLITE_SCHEMA, 
    ++              "sqlite3changeset_apply(): no such table: %s", zTab
    ++          );
    ++        }
    ++        else if( sApply.nCol<nCol ){
    ++          schemaMismatch = 1;
    ++          sqlite3_log(SQLITE_SCHEMA, 
    ++              "sqlite3changeset_apply(): table %s has %d columns, "
    ++              "expected %d or more", 
    ++              zTab, sApply.nCol, nCol
    ++          );
    ++        }
    ++        else if( nCol<nMinCol || memcmp(sApply.abPK, abPK, nCol)!=0 ){
    ++          schemaMismatch = 1;
    ++          sqlite3_log(SQLITE_SCHEMA, "sqlite3changeset_apply(): "
    ++              "primary key mismatch for table %s", zTab
    ++          );
    ++        }
    ++        else{
    ++          sApply.nCol = nCol;
    ++          if( 0==sqlite3_stricmp(zTab, "sqlite_stat1") ){
    ++            if( (rc = sessionStat1Sql(db, &sApply) ) ){
    ++              break;
    ++            }
    ++            sApply.bStat1 = 1;
    ++          }else{
    ++            if((rc = sessionSelectRow(db, zTab, &sApply))
    ++                || (rc = sessionUpdateRow(db, zTab, &sApply))
    ++                || (rc = sessionDeleteRow(db, zTab, &sApply))
    ++                || (rc = sessionInsertRow(db, zTab, &sApply))
    ++              ){
    ++              break;
    ++            }
    ++            sApply.bStat1 = 0;
    ++          }
    ++        }
    ++        nTab = sqlite3Strlen30(zTab);
    ++      }
    ++    }
    ++
    ++    /* If there is a schema mismatch on the current table, proceed to the
    ++    ** next change. A log message has already been issued. */
    ++    if( schemaMismatch ) continue;
    ++
    ++    rc = sessionApplyOneWithRetry(db, pIter, &sApply, xConflict, pCtx);
    ++  }
    ++
    ++  bPatchset = pIter->bPatchset;
    ++  if( rc==SQLITE_OK ){
    ++    rc = sqlite3changeset_finalize(pIter);
    ++  }else{
    ++    sqlite3changeset_finalize(pIter);
    ++  }
    ++
    ++  if( rc==SQLITE_OK ){
    ++    rc = sessionRetryConstraints(db, bPatchset, zTab, &sApply, xConflict, pCtx);
    ++  }
    ++
    ++  if( rc==SQLITE_OK ){
    ++    int nFk, notUsed;
    ++    sqlite3_db_status(db, SQLITE_DBSTATUS_DEFERRED_FKS, &nFk, &notUsed, 0);
    ++    if( nFk!=0 ){
    ++      int res = SQLITE_CHANGESET_ABORT;
    ++      sqlite3_changeset_iter sIter;
    ++      memset(&sIter, 0, sizeof(sIter));
    ++      sIter.nCol = nFk;
    ++      res = xConflict(pCtx, SQLITE_CHANGESET_FOREIGN_KEY, &sIter);
    ++      if( res!=SQLITE_CHANGESET_OMIT ){
    ++        rc = SQLITE_CONSTRAINT;
    ++      }
    ++    }
    ++  }
    ++  sqlite3_exec(db, "PRAGMA defer_foreign_keys = 0", 0, 0, 0);
    ++
    ++  if( rc==SQLITE_OK ){
    ++    rc = sqlite3_exec(db, "RELEASE changeset_apply", 0, 0, 0);
    ++  }else{
    ++    sqlite3_exec(db, "ROLLBACK TO changeset_apply", 0, 0, 0);
    ++    sqlite3_exec(db, "RELEASE changeset_apply", 0, 0, 0);
    ++  }
    ++
    ++  sqlite3_finalize(sApply.pInsert);
    ++  sqlite3_finalize(sApply.pDelete);
    ++  sqlite3_finalize(sApply.pUpdate);
    ++  sqlite3_finalize(sApply.pSelect);
    ++  sqlite3_free((char*)sApply.azCol);  /* cast works around VC++ bug */
    ++  sqlite3_free((char*)sApply.constraints.aBuf);
    ++  sqlite3_mutex_leave(sqlite3_db_mutex(db));
    ++  return rc;
    ++}
    ++
    ++/*
    ++** Apply the changeset passed via pChangeset/nChangeset to the main database
    ++** attached to handle "db". Invoke the supplied conflict handler callback
    ++** to resolve any conflicts encountered while applying the change.
    ++*/
    ++SQLITE_API int sqlite3changeset_apply(
    ++  sqlite3 *db,                    /* Apply change to "main" db of this handle */
    ++  int nChangeset,                 /* Size of changeset in bytes */
    ++  void *pChangeset,               /* Changeset blob */
    ++  int(*xFilter)(
    ++    void *pCtx,                   /* Copy of sixth arg to _apply() */
    ++    const char *zTab              /* Table name */
    ++  ),
    ++  int(*xConflict)(
    ++    void *pCtx,                   /* Copy of fifth arg to _apply() */
    ++    int eConflict,                /* DATA, MISSING, CONFLICT, CONSTRAINT */
    ++    sqlite3_changeset_iter *p     /* Handle describing change and conflict */
    ++  ),
    ++  void *pCtx                      /* First argument passed to xConflict */
    ++){
    ++  sqlite3_changeset_iter *pIter;  /* Iterator to skip through changeset */  
    ++  int rc = sqlite3changeset_start(&pIter, nChangeset, pChangeset);
    ++  if( rc==SQLITE_OK ){
    ++    rc = sessionChangesetApply(db, pIter, xFilter, xConflict, pCtx);
    ++  }
    ++  return rc;
    ++}
    ++
    ++/*
    ++** Apply the changeset passed via xInput/pIn to the main database
    ++** attached to handle "db". Invoke the supplied conflict handler callback
    ++** to resolve any conflicts encountered while applying the change.
    ++*/
    ++SQLITE_API int sqlite3changeset_apply_strm(
    ++  sqlite3 *db,                    /* Apply change to "main" db of this handle */
    ++  int (*xInput)(void *pIn, void *pData, int *pnData), /* Input function */
    ++  void *pIn,                                          /* First arg for xInput */
    ++  int(*xFilter)(
    ++    void *pCtx,                   /* Copy of sixth arg to _apply() */
    ++    const char *zTab              /* Table name */
    ++  ),
    ++  int(*xConflict)(
    ++    void *pCtx,                   /* Copy of sixth arg to _apply() */
    ++    int eConflict,                /* DATA, MISSING, CONFLICT, CONSTRAINT */
    ++    sqlite3_changeset_iter *p     /* Handle describing change and conflict */
    ++  ),
    ++  void *pCtx                      /* First argument passed to xConflict */
    ++){
    ++  sqlite3_changeset_iter *pIter;  /* Iterator to skip through changeset */  
    ++  int rc = sqlite3changeset_start_strm(&pIter, xInput, pIn);
    ++  if( rc==SQLITE_OK ){
    ++    rc = sessionChangesetApply(db, pIter, xFilter, xConflict, pCtx);
    ++  }
    ++  return rc;
    ++}
    ++
    ++/*
    ++** sqlite3_changegroup handle.
    ++*/
    ++struct sqlite3_changegroup {
    ++  int rc;                         /* Error code */
    ++  int bPatch;                     /* True to accumulate patchsets */
    ++  SessionTable *pList;            /* List of tables in current patch */
    ++};
    ++
    ++/*
    ++** This function is called to merge two changes to the same row together as
    ++** part of an sqlite3changeset_concat() operation. A new change object is
    ++** allocated and a pointer to it stored in *ppNew.
    ++*/
    ++static int sessionChangeMerge(
    ++  SessionTable *pTab,             /* Table structure */
    ++  int bPatchset,                  /* True for patchsets */
    ++  SessionChange *pExist,          /* Existing change */
    ++  int op2,                        /* Second change operation */
    ++  int bIndirect,                  /* True if second change is indirect */
    ++  u8 *aRec,                       /* Second change record */
    ++  int nRec,                       /* Number of bytes in aRec */
    ++  SessionChange **ppNew           /* OUT: Merged change */
    ++){
    ++  SessionChange *pNew = 0;
    ++
    ++  if( !pExist ){
    ++    pNew = (SessionChange *)sqlite3_malloc(sizeof(SessionChange) + nRec);
    ++    if( !pNew ){
    ++      return SQLITE_NOMEM;
    ++    }
    ++    memset(pNew, 0, sizeof(SessionChange));
    ++    pNew->op = op2;
    ++    pNew->bIndirect = bIndirect;
    ++    pNew->nRecord = nRec;
    ++    pNew->aRecord = (u8*)&pNew[1];
    ++    memcpy(pNew->aRecord, aRec, nRec);
    ++  }else{
    ++    int op1 = pExist->op;
    ++
    ++    /* 
    ++    **   op1=INSERT, op2=INSERT      ->      Unsupported. Discard op2.
    ++    **   op1=INSERT, op2=UPDATE      ->      INSERT.
    ++    **   op1=INSERT, op2=DELETE      ->      (none)
    ++    **
    ++    **   op1=UPDATE, op2=INSERT      ->      Unsupported. Discard op2.
    ++    **   op1=UPDATE, op2=UPDATE      ->      UPDATE.
    ++    **   op1=UPDATE, op2=DELETE      ->      DELETE.
    ++    **
    ++    **   op1=DELETE, op2=INSERT      ->      UPDATE.
    ++    **   op1=DELETE, op2=UPDATE      ->      Unsupported. Discard op2.
    ++    **   op1=DELETE, op2=DELETE      ->      Unsupported. Discard op2.
    ++    */   
    ++    if( (op1==SQLITE_INSERT && op2==SQLITE_INSERT)
    ++     || (op1==SQLITE_UPDATE && op2==SQLITE_INSERT)
    ++     || (op1==SQLITE_DELETE && op2==SQLITE_UPDATE)
    ++     || (op1==SQLITE_DELETE && op2==SQLITE_DELETE)
    ++    ){
    ++      pNew = pExist;
    ++    }else if( op1==SQLITE_INSERT && op2==SQLITE_DELETE ){
    ++      sqlite3_free(pExist);
    ++      assert( pNew==0 );
    ++    }else{
    ++      u8 *aExist = pExist->aRecord;
    ++      int nByte;
    ++      u8 *aCsr;
    ++
    ++      /* Allocate a new SessionChange object. Ensure that the aRecord[]
    ++      ** buffer of the new object is large enough to hold any record that
    ++      ** may be generated by combining the input records.  */
    ++      nByte = sizeof(SessionChange) + pExist->nRecord + nRec;
    ++      pNew = (SessionChange *)sqlite3_malloc(nByte);
    ++      if( !pNew ){
    ++        sqlite3_free(pExist);
    ++        return SQLITE_NOMEM;
    ++      }
    ++      memset(pNew, 0, sizeof(SessionChange));
    ++      pNew->bIndirect = (bIndirect && pExist->bIndirect);
    ++      aCsr = pNew->aRecord = (u8 *)&pNew[1];
    ++
    ++      if( op1==SQLITE_INSERT ){             /* INSERT + UPDATE */
    ++        u8 *a1 = aRec;
    ++        assert( op2==SQLITE_UPDATE );
    ++        pNew->op = SQLITE_INSERT;
    ++        if( bPatchset==0 ) sessionSkipRecord(&a1, pTab->nCol);
    ++        sessionMergeRecord(&aCsr, pTab->nCol, aExist, a1);
    ++      }else if( op1==SQLITE_DELETE ){       /* DELETE + INSERT */
    ++        assert( op2==SQLITE_INSERT );
    ++        pNew->op = SQLITE_UPDATE;
    ++        if( bPatchset ){
    ++          memcpy(aCsr, aRec, nRec);
    ++          aCsr += nRec;
    ++        }else{
    ++          if( 0==sessionMergeUpdate(&aCsr, pTab, bPatchset, aExist, 0,aRec,0) ){
    ++            sqlite3_free(pNew);
    ++            pNew = 0;
    ++          }
    ++        }
    ++      }else if( op2==SQLITE_UPDATE ){       /* UPDATE + UPDATE */
    ++        u8 *a1 = aExist;
    ++        u8 *a2 = aRec;
    ++        assert( op1==SQLITE_UPDATE );
    ++        if( bPatchset==0 ){
    ++          sessionSkipRecord(&a1, pTab->nCol);
    ++          sessionSkipRecord(&a2, pTab->nCol);
    ++        }
    ++        pNew->op = SQLITE_UPDATE;
    ++        if( 0==sessionMergeUpdate(&aCsr, pTab, bPatchset, aRec, aExist,a1,a2) ){
    ++          sqlite3_free(pNew);
    ++          pNew = 0;
    ++        }
    ++      }else{                                /* UPDATE + DELETE */
    ++        assert( op1==SQLITE_UPDATE && op2==SQLITE_DELETE );
    ++        pNew->op = SQLITE_DELETE;
    ++        if( bPatchset ){
    ++          memcpy(aCsr, aRec, nRec);
    ++          aCsr += nRec;
    ++        }else{
    ++          sessionMergeRecord(&aCsr, pTab->nCol, aRec, aExist);
    ++        }
    ++      }
    ++
    ++      if( pNew ){
    ++        pNew->nRecord = (int)(aCsr - pNew->aRecord);
    ++      }
    ++      sqlite3_free(pExist);
    ++    }
    ++  }
    ++
    ++  *ppNew = pNew;
    ++  return SQLITE_OK;
    ++}
    ++
    ++/*
    ++** Add all changes in the changeset traversed by the iterator passed as
    ++** the first argument to the changegroup hash tables.
    ++*/
    ++static int sessionChangesetToHash(
    ++  sqlite3_changeset_iter *pIter,   /* Iterator to read from */
    ++  sqlite3_changegroup *pGrp        /* Changegroup object to add changeset to */
    ++){
    ++  u8 *aRec;
    ++  int nRec;
    ++  int rc = SQLITE_OK;
    ++  SessionTable *pTab = 0;
    ++
    ++
    ++  while( SQLITE_ROW==sessionChangesetNext(pIter, &aRec, &nRec) ){
    ++    const char *zNew;
    ++    int nCol;
    ++    int op;
    ++    int iHash;
    ++    int bIndirect;
    ++    SessionChange *pChange;
    ++    SessionChange *pExist = 0;
    ++    SessionChange **pp;
    ++
    ++    if( pGrp->pList==0 ){
    ++      pGrp->bPatch = pIter->bPatchset;
    ++    }else if( pIter->bPatchset!=pGrp->bPatch ){
    ++      rc = SQLITE_ERROR;
    ++      break;
    ++    }
    ++
    ++    sqlite3changeset_op(pIter, &zNew, &nCol, &op, &bIndirect);
    ++    if( !pTab || sqlite3_stricmp(zNew, pTab->zName) ){
    ++      /* Search the list for a matching table */
    ++      int nNew = (int)strlen(zNew);
    ++      u8 *abPK;
    ++
    ++      sqlite3changeset_pk(pIter, &abPK, 0);
    ++      for(pTab = pGrp->pList; pTab; pTab=pTab->pNext){
    ++        if( 0==sqlite3_strnicmp(pTab->zName, zNew, nNew+1) ) break;
    ++      }
    ++      if( !pTab ){
    ++        SessionTable **ppTab;
    ++
    ++        pTab = sqlite3_malloc(sizeof(SessionTable) + nCol + nNew+1);
    ++        if( !pTab ){
    ++          rc = SQLITE_NOMEM;
    ++          break;
    ++        }
    ++        memset(pTab, 0, sizeof(SessionTable));
    ++        pTab->nCol = nCol;
    ++        pTab->abPK = (u8*)&pTab[1];
    ++        memcpy(pTab->abPK, abPK, nCol);
    ++        pTab->zName = (char*)&pTab->abPK[nCol];
    ++        memcpy(pTab->zName, zNew, nNew+1);
    ++
    ++        /* The new object must be linked on to the end of the list, not
    ++        ** simply added to the start of it. This is to ensure that the
    ++        ** tables within the output of sqlite3changegroup_output() are in 
    ++        ** the right order.  */
    ++        for(ppTab=&pGrp->pList; *ppTab; ppTab=&(*ppTab)->pNext);
    ++        *ppTab = pTab;
    ++      }else if( pTab->nCol!=nCol || memcmp(pTab->abPK, abPK, nCol) ){
    ++        rc = SQLITE_SCHEMA;
    ++        break;
    ++      }
    ++    }
    ++
    ++    if( sessionGrowHash(pIter->bPatchset, pTab) ){
    ++      rc = SQLITE_NOMEM;
    ++      break;
    ++    }
    ++    iHash = sessionChangeHash(
    ++        pTab, (pIter->bPatchset && op==SQLITE_DELETE), aRec, pTab->nChange
    ++    );
    ++
    ++    /* Search for existing entry. If found, remove it from the hash table. 
    ++    ** Code below may link it back in.
    ++    */
    ++    for(pp=&pTab->apChange[iHash]; *pp; pp=&(*pp)->pNext){
    ++      int bPkOnly1 = 0;
    ++      int bPkOnly2 = 0;
    ++      if( pIter->bPatchset ){
    ++        bPkOnly1 = (*pp)->op==SQLITE_DELETE;
    ++        bPkOnly2 = op==SQLITE_DELETE;
    ++      }
    ++      if( sessionChangeEqual(pTab, bPkOnly1, (*pp)->aRecord, bPkOnly2, aRec) ){
    ++        pExist = *pp;
    ++        *pp = (*pp)->pNext;
    ++        pTab->nEntry--;
    ++        break;
    ++      }
    ++    }
    ++
    ++    rc = sessionChangeMerge(pTab, 
    ++        pIter->bPatchset, pExist, op, bIndirect, aRec, nRec, &pChange
    ++    );
    ++    if( rc ) break;
    ++    if( pChange ){
    ++      pChange->pNext = pTab->apChange[iHash];
    ++      pTab->apChange[iHash] = pChange;
    ++      pTab->nEntry++;
    ++    }
    ++  }
    ++
    ++  if( rc==SQLITE_OK ) rc = pIter->rc;
    ++  return rc;
    ++}
    ++
    ++/*
    ++** Serialize a changeset (or patchset) based on all changesets (or patchsets)
    ++** added to the changegroup object passed as the first argument.
    ++**
    ++** If xOutput is not NULL, then the changeset/patchset is returned to the
    ++** user via one or more calls to xOutput, as with the other streaming
    ++** interfaces. 
    ++**
    ++** Or, if xOutput is NULL, then (*ppOut) is populated with a pointer to a
    ++** buffer containing the output changeset before this function returns. In
    ++** this case (*pnOut) is set to the size of the output buffer in bytes. It
    ++** is the responsibility of the caller to free the output buffer using
    ++** sqlite3_free() when it is no longer required.
    ++**
    ++** If successful, SQLITE_OK is returned. Or, if an error occurs, an SQLite
    ++** error code. If an error occurs and xOutput is NULL, (*ppOut) and (*pnOut)
    ++** are both set to 0 before returning.
    ++*/
    ++static int sessionChangegroupOutput(
    ++  sqlite3_changegroup *pGrp,
    ++  int (*xOutput)(void *pOut, const void *pData, int nData),
    ++  void *pOut,
    ++  int *pnOut,
    ++  void **ppOut
    ++){
    ++  int rc = SQLITE_OK;
    ++  SessionBuffer buf = {0, 0, 0};
    ++  SessionTable *pTab;
    ++  assert( xOutput==0 || (ppOut==0 && pnOut==0) );
    ++
    ++  /* Create the serialized output changeset based on the contents of the
    ++  ** hash tables attached to the SessionTable objects in list p->pList. 
    ++  */
    ++  for(pTab=pGrp->pList; rc==SQLITE_OK && pTab; pTab=pTab->pNext){
    ++    int i;
    ++    if( pTab->nEntry==0 ) continue;
    ++
    ++    sessionAppendTableHdr(&buf, pGrp->bPatch, pTab, &rc);
    ++    for(i=0; i<pTab->nChange; i++){
    ++      SessionChange *p;
    ++      for(p=pTab->apChange[i]; p; p=p->pNext){
    ++        sessionAppendByte(&buf, p->op, &rc);
    ++        sessionAppendByte(&buf, p->bIndirect, &rc);
    ++        sessionAppendBlob(&buf, p->aRecord, p->nRecord, &rc);
    ++      }
    ++    }
    ++
    ++    if( rc==SQLITE_OK && xOutput && buf.nBuf>=SESSIONS_STRM_CHUNK_SIZE ){
    ++      rc = xOutput(pOut, buf.aBuf, buf.nBuf);
    ++      buf.nBuf = 0;
    ++    }
    ++  }
    ++
    ++  if( rc==SQLITE_OK ){
    ++    if( xOutput ){
    ++      if( buf.nBuf>0 ) rc = xOutput(pOut, buf.aBuf, buf.nBuf);
    ++    }else{
    ++      *ppOut = buf.aBuf;
    ++      *pnOut = buf.nBuf;
    ++      buf.aBuf = 0;
    ++    }
    ++  }
    ++  sqlite3_free(buf.aBuf);
    ++
    ++  return rc;
    ++}
    ++
    ++/*
    ++** Allocate a new, empty, sqlite3_changegroup.
    ++*/
    ++SQLITE_API int sqlite3changegroup_new(sqlite3_changegroup **pp){
    ++  int rc = SQLITE_OK;             /* Return code */
    ++  sqlite3_changegroup *p;         /* New object */
    ++  p = (sqlite3_changegroup*)sqlite3_malloc(sizeof(sqlite3_changegroup));
    ++  if( p==0 ){
    ++    rc = SQLITE_NOMEM;
    ++  }else{
    ++    memset(p, 0, sizeof(sqlite3_changegroup));
    ++  }
    ++  *pp = p;
    ++  return rc;
    ++}
    ++
    ++/*
    ++** Add the changeset currently stored in buffer pData, size nData bytes,
    ++** to changeset-group p.
    ++*/
    ++SQLITE_API int sqlite3changegroup_add(sqlite3_changegroup *pGrp, int nData, void *pData){
    ++  sqlite3_changeset_iter *pIter;  /* Iterator opened on pData/nData */
    ++  int rc;                         /* Return code */
    ++
    ++  rc = sqlite3changeset_start(&pIter, nData, pData);
    ++  if( rc==SQLITE_OK ){
    ++    rc = sessionChangesetToHash(pIter, pGrp);
    ++  }
    ++  sqlite3changeset_finalize(pIter);
    ++  return rc;
    ++}
    ++
    ++/*
    ++** Obtain a buffer containing a changeset representing the concatenation
    ++** of all changesets added to the group so far.
    ++*/
    ++SQLITE_API int sqlite3changegroup_output(
    ++    sqlite3_changegroup *pGrp,
    ++    int *pnData,
    ++    void **ppData
    ++){
    ++  return sessionChangegroupOutput(pGrp, 0, 0, pnData, ppData);
    ++}
    ++
    ++/*
    ++** Streaming versions of changegroup_add().
    ++*/
    ++SQLITE_API int sqlite3changegroup_add_strm(
    ++  sqlite3_changegroup *pGrp,
    ++  int (*xInput)(void *pIn, void *pData, int *pnData),
    ++  void *pIn
    ++){
    ++  sqlite3_changeset_iter *pIter;  /* Iterator opened on pData/nData */
    ++  int rc;                         /* Return code */
    ++
    ++  rc = sqlite3changeset_start_strm(&pIter, xInput, pIn);
    ++  if( rc==SQLITE_OK ){
    ++    rc = sessionChangesetToHash(pIter, pGrp);
    ++  }
    ++  sqlite3changeset_finalize(pIter);
    ++  return rc;
    ++}
    ++
    ++/*
    ++** Streaming versions of changegroup_output().
    ++*/
    ++SQLITE_API int sqlite3changegroup_output_strm(
    ++  sqlite3_changegroup *pGrp,
    ++  int (*xOutput)(void *pOut, const void *pData, int nData), 
    ++  void *pOut
    ++){
    ++  return sessionChangegroupOutput(pGrp, xOutput, pOut, 0, 0);
    ++}
    ++
    ++/*
    ++** Delete a changegroup object.
    ++*/
    ++SQLITE_API void sqlite3changegroup_delete(sqlite3_changegroup *pGrp){
    ++  if( pGrp ){
    ++    sessionDeleteTable(pGrp->pList);
    ++    sqlite3_free(pGrp);
    ++  }
    ++}
    ++
    ++/* 
    ++** Combine two changesets together.
    ++*/
    ++SQLITE_API int sqlite3changeset_concat(
    ++  int nLeft,                      /* Number of bytes in lhs input */
    ++  void *pLeft,                    /* Lhs input changeset */
    ++  int nRight                      /* Number of bytes in rhs input */,
    ++  void *pRight,                   /* Rhs input changeset */
    ++  int *pnOut,                     /* OUT: Number of bytes in output changeset */
    ++  void **ppOut                    /* OUT: changeset (left <concat> right) */
    ++){
    ++  sqlite3_changegroup *pGrp;
    ++  int rc;
    ++
    ++  rc = sqlite3changegroup_new(&pGrp);
    ++  if( rc==SQLITE_OK ){
    ++    rc = sqlite3changegroup_add(pGrp, nLeft, pLeft);
    ++  }
    ++  if( rc==SQLITE_OK ){
    ++    rc = sqlite3changegroup_add(pGrp, nRight, pRight);
    ++  }
    ++  if( rc==SQLITE_OK ){
    ++    rc = sqlite3changegroup_output(pGrp, pnOut, ppOut);
    ++  }
    ++  sqlite3changegroup_delete(pGrp);
    ++
    ++  return rc;
    ++}
    ++
    ++/*
    ++** Streaming version of sqlite3changeset_concat().
    ++*/
    ++SQLITE_API int sqlite3changeset_concat_strm(
    ++  int (*xInputA)(void *pIn, void *pData, int *pnData),
    ++  void *pInA,
    ++  int (*xInputB)(void *pIn, void *pData, int *pnData),
    ++  void *pInB,
    ++  int (*xOutput)(void *pOut, const void *pData, int nData),
    ++  void *pOut
    ++){
    ++  sqlite3_changegroup *pGrp;
    ++  int rc;
    ++
    ++  rc = sqlite3changegroup_new(&pGrp);
    ++  if( rc==SQLITE_OK ){
    ++    rc = sqlite3changegroup_add_strm(pGrp, xInputA, pInA);
    ++  }
    ++  if( rc==SQLITE_OK ){
    ++    rc = sqlite3changegroup_add_strm(pGrp, xInputB, pInB);
    ++  }
    ++  if( rc==SQLITE_OK ){
    ++    rc = sqlite3changegroup_output_strm(pGrp, xOutput, pOut);
    ++  }
    ++  sqlite3changegroup_delete(pGrp);
    ++
    ++  return rc;
    ++}
    ++
    ++#endif /* SQLITE_ENABLE_SESSION && SQLITE_ENABLE_PREUPDATE_HOOK */
    ++
    ++/************** End of sqlite3session.c **************************************/
    ++/************** Begin file json1.c *******************************************/
    ++/*
    ++** 2015-08-12
    ++**
    ++** 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 SQLite extension implements JSON functions.  The interface is
    ++** modeled after MySQL JSON functions:
    ++**
    ++**     https://dev.mysql.com/doc/refman/5.7/en/json.html
    ++**
    ++** For the time being, all JSON is stored as pure text.  (We might add
    ++** a JSONB type in the future which stores a binary encoding of JSON in
    ++** a BLOB, but there is no support for JSONB in the current implementation.
    ++** This implementation parses JSON text at 250 MB/s, so it is hard to see
    ++** how JSONB might improve on that.)
    ++*/
    ++#if !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_JSON1)
    ++#if !defined(SQLITEINT_H)
    ++/* #include "sqlite3ext.h" */
    ++#endif
    ++SQLITE_EXTENSION_INIT1
    ++/* #include <assert.h> */
    ++/* #include <string.h> */
    ++/* #include <stdlib.h> */
    ++/* #include <stdarg.h> */
    ++
    ++/* Mark a function parameter as unused, to suppress nuisance compiler
    ++** warnings. */
    ++#ifndef UNUSED_PARAM
    ++# define UNUSED_PARAM(X)  (void)(X)
    ++#endif
    ++
    ++#ifndef LARGEST_INT64
    ++# define LARGEST_INT64  (0xffffffff|(((sqlite3_int64)0x7fffffff)<<32))
    ++# define SMALLEST_INT64 (((sqlite3_int64)-1) - LARGEST_INT64)
    ++#endif
    ++
    ++/*
    ++** Versions of isspace(), isalnum() and isdigit() to which it is safe
    ++** to pass signed char values.
    ++*/
    ++#ifdef sqlite3Isdigit
    ++   /* Use the SQLite core versions if this routine is part of the
    ++   ** SQLite amalgamation */
    ++#  define safe_isdigit(x)  sqlite3Isdigit(x)
    ++#  define safe_isalnum(x)  sqlite3Isalnum(x)
    ++#  define safe_isxdigit(x) sqlite3Isxdigit(x)
    ++#else
    ++   /* Use the standard library for separate compilation */
    ++#include <ctype.h>  /* amalgamator: keep */
    ++#  define safe_isdigit(x)  isdigit((unsigned char)(x))
    ++#  define safe_isalnum(x)  isalnum((unsigned char)(x))
    ++#  define safe_isxdigit(x) isxdigit((unsigned char)(x))
    ++#endif
    ++
    ++/*
    ++** Growing our own isspace() routine this way is twice as fast as
    ++** the library isspace() function, resulting in a 7% overall performance
    ++** increase for the parser.  (Ubuntu14.10 gcc 4.8.4 x64 with -Os).
    ++*/
    ++static const char jsonIsSpace[] = {
    ++  0, 0, 0, 0, 0, 0, 0, 0,     0, 1, 1, 0, 0, 1, 0, 0,
    ++  0, 0, 0, 0, 0, 0, 0, 0,     0, 0, 0, 0, 0, 0, 0, 0,
    ++  1, 0, 0, 0, 0, 0, 0, 0,     0, 0, 0, 0, 0, 0, 0, 0,
    ++  0, 0, 0, 0, 0, 0, 0, 0,     0, 0, 0, 0, 0, 0, 0, 0,
    ++  0, 0, 0, 0, 0, 0, 0, 0,     0, 0, 0, 0, 0, 0, 0, 0,
    ++  0, 0, 0, 0, 0, 0, 0, 0,     0, 0, 0, 0, 0, 0, 0, 0,
    ++  0, 0, 0, 0, 0, 0, 0, 0,     0, 0, 0, 0, 0, 0, 0, 0,
    ++  0, 0, 0, 0, 0, 0, 0, 0,     0, 0, 0, 0, 0, 0, 0, 0,
    ++  0, 0, 0, 0, 0, 0, 0, 0,     0, 0, 0, 0, 0, 0, 0, 0,
    ++  0, 0, 0, 0, 0, 0, 0, 0,     0, 0, 0, 0, 0, 0, 0, 0,
    ++  0, 0, 0, 0, 0, 0, 0, 0,     0, 0, 0, 0, 0, 0, 0, 0,
    ++  0, 0, 0, 0, 0, 0, 0, 0,     0, 0, 0, 0, 0, 0, 0, 0,
    ++  0, 0, 0, 0, 0, 0, 0, 0,     0, 0, 0, 0, 0, 0, 0, 0,
    ++  0, 0, 0, 0, 0, 0, 0, 0,     0, 0, 0, 0, 0, 0, 0, 0,
    ++  0, 0, 0, 0, 0, 0, 0, 0,     0, 0, 0, 0, 0, 0, 0, 0,
    ++  0, 0, 0, 0, 0, 0, 0, 0,     0, 0, 0, 0, 0, 0, 0, 0,
    ++};
    ++#define safe_isspace(x) (jsonIsSpace[(unsigned char)x])
    ++
    ++#ifndef SQLITE_AMALGAMATION
    ++  /* Unsigned integer types.  These are already defined in the sqliteInt.h,
    ++  ** but the definitions need to be repeated for separate compilation. */
    ++  typedef sqlite3_uint64 u64;
    ++  typedef unsigned int u32;
    ++  typedef unsigned short int u16;
    ++  typedef unsigned char u8;
    ++#endif
    ++
    ++/* Objects */
    ++typedef struct JsonString JsonString;
    ++typedef struct JsonNode JsonNode;
    ++typedef struct JsonParse JsonParse;
    ++
    ++/* An instance of this object represents a JSON string
    ++** under construction.  Really, this is a generic string accumulator
    ++** that can be and is used to create strings other than JSON.
    ++*/
    ++struct JsonString {
    ++  sqlite3_context *pCtx;   /* Function context - put error messages here */
    ++  char *zBuf;              /* Append JSON content here */
    ++  u64 nAlloc;              /* Bytes of storage available in zBuf[] */
    ++  u64 nUsed;               /* Bytes of zBuf[] currently used */
    ++  u8 bStatic;              /* True if zBuf is static space */
    ++  u8 bErr;                 /* True if an error has been encountered */
    ++  char zSpace[100];        /* Initial static space */
    ++};
    ++
    ++/* JSON type values
    ++*/
    ++#define JSON_NULL     0
    ++#define JSON_TRUE     1
    ++#define JSON_FALSE    2
    ++#define JSON_INT      3
    ++#define JSON_REAL     4
    ++#define JSON_STRING   5
    ++#define JSON_ARRAY    6
    ++#define JSON_OBJECT   7
    ++
    ++/* The "subtype" set for JSON values */
    ++#define JSON_SUBTYPE  74    /* Ascii for "J" */
    ++
    ++/*
    ++** Names of the various JSON types:
    ++*/
    ++static const char * const jsonType[] = {
    ++  "null", "true", "false", "integer", "real", "text", "array", "object"
    ++};
    ++
    ++/* Bit values for the JsonNode.jnFlag field
    ++*/
    ++#define JNODE_RAW     0x01         /* Content is raw, not JSON encoded */
    ++#define JNODE_ESCAPE  0x02         /* Content is text with \ escapes */
    ++#define JNODE_REMOVE  0x04         /* Do not output */
    ++#define JNODE_REPLACE 0x08         /* Replace with JsonNode.u.iReplace */
    ++#define JNODE_PATCH   0x10         /* Patch with JsonNode.u.pPatch */
    ++#define JNODE_APPEND  0x20         /* More ARRAY/OBJECT entries at u.iAppend */
    ++#define JNODE_LABEL   0x40         /* Is a label of an object */
    ++
    ++
    ++/* A single node of parsed JSON
    ++*/
    ++struct JsonNode {
    ++  u8 eType;              /* One of the JSON_ type values */
    ++  u8 jnFlags;            /* JNODE flags */
    ++  u32 n;                 /* Bytes of content, or number of sub-nodes */
    ++  union {
    ++    const char *zJContent; /* Content for INT, REAL, and STRING */
    ++    u32 iAppend;           /* More terms for ARRAY and OBJECT */
    ++    u32 iKey;              /* Key for ARRAY objects in json_tree() */
    ++    u32 iReplace;          /* Replacement content for JNODE_REPLACE */
    ++    JsonNode *pPatch;      /* Node chain of patch for JNODE_PATCH */
    ++  } u;
    ++};
    ++
    ++/* A completely parsed JSON string
    ++*/
    ++struct JsonParse {
    ++  u32 nNode;         /* Number of slots of aNode[] used */
    ++  u32 nAlloc;        /* Number of slots of aNode[] allocated */
    ++  JsonNode *aNode;   /* Array of nodes containing the parse */
    ++  const char *zJson; /* Original JSON string */
    ++  u32 *aUp;          /* Index of parent of each node */
    ++  u8 oom;            /* Set to true if out of memory */
    ++  u8 nErr;           /* Number of errors seen */
    ++  u16 iDepth;        /* Nesting depth */
    ++  int nJson;         /* Length of the zJson string in bytes */
    ++};
    ++
    ++/*
    ++** Maximum nesting depth of JSON for this implementation.
    ++**
    ++** This limit is needed to avoid a stack overflow in the recursive
    ++** descent parser.  A depth of 2000 is far deeper than any sane JSON
    ++** should go.
    ++*/
    ++#define JSON_MAX_DEPTH  2000
    ++
    ++/**************************************************************************
    ++** Utility routines for dealing with JsonString objects
    ++**************************************************************************/
    ++
    ++/* Set the JsonString object to an empty string
    ++*/
    ++static void jsonZero(JsonString *p){
    ++  p->zBuf = p->zSpace;
    ++  p->nAlloc = sizeof(p->zSpace);
    ++  p->nUsed = 0;
    ++  p->bStatic = 1;
    ++}
    ++
    ++/* Initialize the JsonString object
    ++*/
    ++static void jsonInit(JsonString *p, sqlite3_context *pCtx){
    ++  p->pCtx = pCtx;
    ++  p->bErr = 0;
    ++  jsonZero(p);
    ++}
    ++
    ++
    ++/* Free all allocated memory and reset the JsonString object back to its
    ++** initial state.
    ++*/
    ++static void jsonReset(JsonString *p){
    ++  if( !p->bStatic ) sqlite3_free(p->zBuf);
    ++  jsonZero(p);
    ++}
    ++
    ++
    ++/* Report an out-of-memory (OOM) condition 
    ++*/
    ++static void jsonOom(JsonString *p){
    ++  p->bErr = 1;
    ++  sqlite3_result_error_nomem(p->pCtx);
    ++  jsonReset(p);
    ++}
    ++
    ++/* Enlarge pJson->zBuf so that it can hold at least N more bytes.
    ++** Return zero on success.  Return non-zero on an OOM error
    ++*/
    ++static int jsonGrow(JsonString *p, u32 N){
    ++  u64 nTotal = N<p->nAlloc ? p->nAlloc*2 : p->nAlloc+N+10;
    ++  char *zNew;
    ++  if( p->bStatic ){
    ++    if( p->bErr ) return 1;
    ++    zNew = sqlite3_malloc64(nTotal);
    ++    if( zNew==0 ){
    ++      jsonOom(p);
    ++      return SQLITE_NOMEM;
    ++    }
    ++    memcpy(zNew, p->zBuf, (size_t)p->nUsed);
    ++    p->zBuf = zNew;
    ++    p->bStatic = 0;
    ++  }else{
    ++    zNew = sqlite3_realloc64(p->zBuf, nTotal);
    ++    if( zNew==0 ){
    ++      jsonOom(p);
    ++      return SQLITE_NOMEM;
    ++    }
    ++    p->zBuf = zNew;
    ++  }
    ++  p->nAlloc = nTotal;
    ++  return SQLITE_OK;
    ++}
    ++
    ++/* Append N bytes from zIn onto the end of the JsonString string.
    ++*/
    ++static void jsonAppendRaw(JsonString *p, const char *zIn, u32 N){
    ++  if( (N+p->nUsed >= p->nAlloc) && jsonGrow(p,N)!=0 ) return;
    ++  memcpy(p->zBuf+p->nUsed, zIn, N);
    ++  p->nUsed += N;
    ++}
    ++
    ++/* Append formatted text (not to exceed N bytes) to the JsonString.
    ++*/
    ++static void jsonPrintf(int N, JsonString *p, const char *zFormat, ...){
    ++  va_list ap;
    ++  if( (p->nUsed + N >= p->nAlloc) && jsonGrow(p, N) ) return;
    ++  va_start(ap, zFormat);
    ++  sqlite3_vsnprintf(N, p->zBuf+p->nUsed, zFormat, ap);
    ++  va_end(ap);
    ++  p->nUsed += (int)strlen(p->zBuf+p->nUsed);
    ++}
    ++
    ++/* Append a single character
    ++*/
    ++static void jsonAppendChar(JsonString *p, char c){
    ++  if( p->nUsed>=p->nAlloc && jsonGrow(p,1)!=0 ) return;
    ++  p->zBuf[p->nUsed++] = c;
    ++}
    ++
    ++/* Append a comma separator to the output buffer, if the previous
    ++** character is not '[' or '{'.
    ++*/
    ++static void jsonAppendSeparator(JsonString *p){
    ++  char c;
    ++  if( p->nUsed==0 ) return;
    ++  c = p->zBuf[p->nUsed-1];
    ++  if( c!='[' && c!='{' ) jsonAppendChar(p, ',');
    ++}
    ++
    ++/* Append the N-byte string in zIn to the end of the JsonString string
    ++** under construction.  Enclose the string in "..." and escape
    ++** any double-quotes or backslash characters contained within the
    ++** string.
    ++*/
    ++static void jsonAppendString(JsonString *p, const char *zIn, u32 N){
    ++  u32 i;
    ++  if( (N+p->nUsed+2 >= p->nAlloc) && jsonGrow(p,N+2)!=0 ) return;
    ++  p->zBuf[p->nUsed++] = '"';
    ++  for(i=0; i<N; i++){
    ++    unsigned char c = ((unsigned const char*)zIn)[i];
    ++    if( c=='"' || c=='\\' ){
    ++      json_simple_escape:
    ++      if( (p->nUsed+N+3-i > p->nAlloc) && jsonGrow(p,N+3-i)!=0 ) return;
    ++      p->zBuf[p->nUsed++] = '\\';
    ++    }else if( c<=0x1f ){
    ++      static const char aSpecial[] = {
    ++         0, 0, 0, 0, 0, 0, 0, 0, 'b', 't', 'n', 0, 'f', 'r', 0, 0,
    ++         0, 0, 0, 0, 0, 0, 0, 0,   0,   0,   0, 0,   0,   0, 0, 0
    ++      };
    ++      assert( sizeof(aSpecial)==32 );
    ++      assert( aSpecial['\b']=='b' );
    ++      assert( aSpecial['\f']=='f' );
    ++      assert( aSpecial['\n']=='n' );
    ++      assert( aSpecial['\r']=='r' );
    ++      assert( aSpecial['\t']=='t' );
    ++      if( aSpecial[c] ){
    ++        c = aSpecial[c];
    ++        goto json_simple_escape;
    ++      }
    ++      if( (p->nUsed+N+7+i > p->nAlloc) && jsonGrow(p,N+7-i)!=0 ) return;
    ++      p->zBuf[p->nUsed++] = '\\';
    ++      p->zBuf[p->nUsed++] = 'u';
    ++      p->zBuf[p->nUsed++] = '0';
    ++      p->zBuf[p->nUsed++] = '0';
    ++      p->zBuf[p->nUsed++] = '0' + (c>>4);
    ++      c = "0123456789abcdef"[c&0xf];
    ++    }
    ++    p->zBuf[p->nUsed++] = c;
    ++  }
    ++  p->zBuf[p->nUsed++] = '"';
    ++  assert( p->nUsed<p->nAlloc );
    ++}
    ++
    ++/*
    ++** Append a function parameter value to the JSON string under 
    ++** construction.
    ++*/
    ++static void jsonAppendValue(
    ++  JsonString *p,                 /* Append to this JSON string */
    ++  sqlite3_value *pValue          /* Value to append */
    ++){
    ++  switch( sqlite3_value_type(pValue) ){
    ++    case SQLITE_NULL: {
    ++      jsonAppendRaw(p, "null", 4);
    ++      break;
    ++    }
    ++    case SQLITE_INTEGER:
    ++    case SQLITE_FLOAT: {
    ++      const char *z = (const char*)sqlite3_value_text(pValue);
    ++      u32 n = (u32)sqlite3_value_bytes(pValue);
    ++      jsonAppendRaw(p, z, n);
    ++      break;
    ++    }
    ++    case SQLITE_TEXT: {
    ++      const char *z = (const char*)sqlite3_value_text(pValue);
    ++      u32 n = (u32)sqlite3_value_bytes(pValue);
    ++      if( sqlite3_value_subtype(pValue)==JSON_SUBTYPE ){
    ++        jsonAppendRaw(p, z, n);
    ++      }else{
    ++        jsonAppendString(p, z, n);
    ++      }
    ++      break;
    ++    }
    ++    default: {
    ++      if( p->bErr==0 ){
    ++        sqlite3_result_error(p->pCtx, "JSON cannot hold BLOB values", -1);
    ++        p->bErr = 2;
    ++        jsonReset(p);
    ++      }
    ++      break;
    ++    }
    ++  }
    ++}
    ++
    ++
    ++/* Make the JSON in p the result of the SQL function.
    ++*/
    ++static void jsonResult(JsonString *p){
    ++  if( p->bErr==0 ){
    ++    sqlite3_result_text64(p->pCtx, p->zBuf, p->nUsed, 
    ++                          p->bStatic ? SQLITE_TRANSIENT : sqlite3_free,
    ++                          SQLITE_UTF8);
    ++    jsonZero(p);
    ++  }
    ++  assert( p->bStatic );
    ++}
    ++
    ++/**************************************************************************
    ++** Utility routines for dealing with JsonNode and JsonParse objects
    ++**************************************************************************/
    ++
    ++/*
    ++** Return the number of consecutive JsonNode slots need to represent
    ++** the parsed JSON at pNode.  The minimum answer is 1.  For ARRAY and
    ++** OBJECT types, the number might be larger.
    ++**
    ++** Appended elements are not counted.  The value returned is the number
    ++** by which the JsonNode counter should increment in order to go to the
    ++** next peer value.
    ++*/
    ++static u32 jsonNodeSize(JsonNode *pNode){
    ++  return pNode->eType>=JSON_ARRAY ? pNode->n+1 : 1;
    ++}
    ++
    ++/*
    ++** Reclaim all memory allocated by a JsonParse object.  But do not
    ++** delete the JsonParse object itself.
    ++*/
    ++static void jsonParseReset(JsonParse *pParse){
    ++  sqlite3_free(pParse->aNode);
    ++  pParse->aNode = 0;
    ++  pParse->nNode = 0;
    ++  pParse->nAlloc = 0;
    ++  sqlite3_free(pParse->aUp);
    ++  pParse->aUp = 0;
    ++}
    ++
    ++/*
    ++** Free a JsonParse object that was obtained from sqlite3_malloc().
    ++*/
    ++static void jsonParseFree(JsonParse *pParse){
    ++  jsonParseReset(pParse);
    ++  sqlite3_free(pParse);
    ++}
    ++
    ++/*
    ++** Convert the JsonNode pNode into a pure JSON string and
    ++** append to pOut.  Subsubstructure is also included.  Return
    ++** the number of JsonNode objects that are encoded.
    ++*/
    ++static void jsonRenderNode(
    ++  JsonNode *pNode,               /* The node to render */
    ++  JsonString *pOut,              /* Write JSON here */
    ++  sqlite3_value **aReplace       /* Replacement values */
    ++){
    ++  if( pNode->jnFlags & (JNODE_REPLACE|JNODE_PATCH) ){
    ++    if( pNode->jnFlags & JNODE_REPLACE ){
    ++      jsonAppendValue(pOut, aReplace[pNode->u.iReplace]);
    ++      return;
    ++    }
    ++    pNode = pNode->u.pPatch;
    ++  }
    ++  switch( pNode->eType ){
    ++    default: {
    ++      assert( pNode->eType==JSON_NULL );
    ++      jsonAppendRaw(pOut, "null", 4);
    ++      break;
    ++    }
    ++    case JSON_TRUE: {
    ++      jsonAppendRaw(pOut, "true", 4);
    ++      break;
    ++    }
    ++    case JSON_FALSE: {
    ++      jsonAppendRaw(pOut, "false", 5);
    ++      break;
    ++    }
    ++    case JSON_STRING: {
    ++      if( pNode->jnFlags & JNODE_RAW ){
    ++        jsonAppendString(pOut, pNode->u.zJContent, pNode->n);
    ++        break;
    ++      }
    ++      /* Fall through into the next case */
    ++    }
    ++    case JSON_REAL:
    ++    case JSON_INT: {
    ++      jsonAppendRaw(pOut, pNode->u.zJContent, pNode->n);
    ++      break;
    ++    }
    ++    case JSON_ARRAY: {
    ++      u32 j = 1;
    ++      jsonAppendChar(pOut, '[');
    ++      for(;;){
    ++        while( j<=pNode->n ){
    ++          if( (pNode[j].jnFlags & JNODE_REMOVE)==0 ){
    ++            jsonAppendSeparator(pOut);
    ++            jsonRenderNode(&pNode[j], pOut, aReplace);
    ++          }
    ++          j += jsonNodeSize(&pNode[j]);
    ++        }
    ++        if( (pNode->jnFlags & JNODE_APPEND)==0 ) break;
    ++        pNode = &pNode[pNode->u.iAppend];
    ++        j = 1;
    ++      }
    ++      jsonAppendChar(pOut, ']');
    ++      break;
    ++    }
    ++    case JSON_OBJECT: {
    ++      u32 j = 1;
    ++      jsonAppendChar(pOut, '{');
    ++      for(;;){
    ++        while( j<=pNode->n ){
    ++          if( (pNode[j+1].jnFlags & JNODE_REMOVE)==0 ){
    ++            jsonAppendSeparator(pOut);
    ++            jsonRenderNode(&pNode[j], pOut, aReplace);
    ++            jsonAppendChar(pOut, ':');
    ++            jsonRenderNode(&pNode[j+1], pOut, aReplace);
    ++          }
    ++          j += 1 + jsonNodeSize(&pNode[j+1]);
    ++        }
    ++        if( (pNode->jnFlags & JNODE_APPEND)==0 ) break;
    ++        pNode = &pNode[pNode->u.iAppend];
    ++        j = 1;
    ++      }
    ++      jsonAppendChar(pOut, '}');
    ++      break;
    ++    }
    ++  }
    ++}
    ++
    ++/*
    ++** Return a JsonNode and all its descendents as a JSON string.
    ++*/
    ++static void jsonReturnJson(
    ++  JsonNode *pNode,            /* Node to return */
    ++  sqlite3_context *pCtx,      /* Return value for this function */
    ++  sqlite3_value **aReplace    /* Array of replacement values */
    ++){
    ++  JsonString s;
    ++  jsonInit(&s, pCtx);
    ++  jsonRenderNode(pNode, &s, aReplace);
    ++  jsonResult(&s);
    ++  sqlite3_result_subtype(pCtx, JSON_SUBTYPE);
    ++}
    ++
    ++/*
    ++** Make the JsonNode the return value of the function.
    ++*/
    ++static void jsonReturn(
    ++  JsonNode *pNode,            /* Node to return */
    ++  sqlite3_context *pCtx,      /* Return value for this function */
    ++  sqlite3_value **aReplace    /* Array of replacement values */
    ++){
    ++  switch( pNode->eType ){
    ++    default: {
    ++      assert( pNode->eType==JSON_NULL );
    ++      sqlite3_result_null(pCtx);
    ++      break;
    ++    }
    ++    case JSON_TRUE: {
    ++      sqlite3_result_int(pCtx, 1);
    ++      break;
    ++    }
    ++    case JSON_FALSE: {
    ++      sqlite3_result_int(pCtx, 0);
    ++      break;
    ++    }
    ++    case JSON_INT: {
    ++      sqlite3_int64 i = 0;
    ++      const char *z = pNode->u.zJContent;
    ++      if( z[0]=='-' ){ z++; }
    ++      while( z[0]>='0' && z[0]<='9' ){
    ++        unsigned v = *(z++) - '0';
    ++        if( i>=LARGEST_INT64/10 ){
    ++          if( i>LARGEST_INT64/10 ) goto int_as_real;
    ++          if( z[0]>='0' && z[0]<='9' ) goto int_as_real;
    ++          if( v==9 ) goto int_as_real;
    ++          if( v==8 ){
    ++            if( pNode->u.zJContent[0]=='-' ){
    ++              sqlite3_result_int64(pCtx, SMALLEST_INT64);
    ++              goto int_done;
    ++            }else{
    ++              goto int_as_real;
    ++            }
    ++          }
    ++        }
    ++        i = i*10 + v;
    ++      }
    ++      if( pNode->u.zJContent[0]=='-' ){ i = -i; }
    ++      sqlite3_result_int64(pCtx, i);
    ++      int_done:
    ++      break;
    ++      int_as_real: /* fall through to real */;
    ++    }
    ++    case JSON_REAL: {
    ++      double r;
    ++#ifdef SQLITE_AMALGAMATION
    ++      const char *z = pNode->u.zJContent;
    ++      sqlite3AtoF(z, &r, sqlite3Strlen30(z), SQLITE_UTF8);
    ++#else
    ++      r = strtod(pNode->u.zJContent, 0);
    ++#endif
    ++      sqlite3_result_double(pCtx, r);
    ++      break;
    ++    }
    ++    case JSON_STRING: {
    ++#if 0 /* Never happens because JNODE_RAW is only set by json_set(),
    ++      ** json_insert() and json_replace() and those routines do not
    ++      ** call jsonReturn() */
    ++      if( pNode->jnFlags & JNODE_RAW ){
    ++        sqlite3_result_text(pCtx, pNode->u.zJContent, pNode->n,
    ++                            SQLITE_TRANSIENT);
    ++      }else 
    ++#endif
    ++      assert( (pNode->jnFlags & JNODE_RAW)==0 );
    ++      if( (pNode->jnFlags & JNODE_ESCAPE)==0 ){
    ++        /* JSON formatted without any backslash-escapes */
    ++        sqlite3_result_text(pCtx, pNode->u.zJContent+1, pNode->n-2,
    ++                            SQLITE_TRANSIENT);
    ++      }else{
    ++        /* Translate JSON formatted string into raw text */
    ++        u32 i;
    ++        u32 n = pNode->n;
    ++        const char *z = pNode->u.zJContent;
    ++        char *zOut;
    ++        u32 j;
    ++        zOut = sqlite3_malloc( n+1 );
    ++        if( zOut==0 ){
    ++          sqlite3_result_error_nomem(pCtx);
    ++          break;
    ++        }
    ++        for(i=1, j=0; i<n-1; i++){
    ++          char c = z[i];
    ++          if( c!='\\' ){
    ++            zOut[j++] = c;
    ++          }else{
    ++            c = z[++i];
    ++            if( c=='u' ){
    ++              u32 v = 0, k;
    ++              for(k=0; k<4; i++, k++){
    ++                assert( i<n-2 );
    ++                c = z[i+1];
    ++                assert( safe_isxdigit(c) );
    ++                if( c<='9' ) v = v*16 + c - '0';
    ++                else if( c<='F' ) v = v*16 + c - 'A' + 10;
    ++                else v = v*16 + c - 'a' + 10;
    ++              }
    ++              if( v==0 ) break;
    ++              if( v<=0x7f ){
    ++                zOut[j++] = (char)v;
    ++              }else if( v<=0x7ff ){
    ++                zOut[j++] = (char)(0xc0 | (v>>6));
    ++                zOut[j++] = 0x80 | (v&0x3f);
    ++              }else{
    ++                zOut[j++] = (char)(0xe0 | (v>>12));
    ++                zOut[j++] = 0x80 | ((v>>6)&0x3f);
    ++                zOut[j++] = 0x80 | (v&0x3f);
    ++              }
    ++            }else{
    ++              if( c=='b' ){
    ++                c = '\b';
    ++              }else if( c=='f' ){
    ++                c = '\f';
    ++              }else if( c=='n' ){
    ++                c = '\n';
    ++              }else if( c=='r' ){
    ++                c = '\r';
    ++              }else if( c=='t' ){
    ++                c = '\t';
    ++              }
    ++              zOut[j++] = c;
    ++            }
    ++          }
    ++        }
    ++        zOut[j] = 0;
    ++        sqlite3_result_text(pCtx, zOut, j, sqlite3_free);
    ++      }
    ++      break;
    ++    }
    ++    case JSON_ARRAY:
    ++    case JSON_OBJECT: {
    ++      jsonReturnJson(pNode, pCtx, aReplace);
    ++      break;
    ++    }
    ++  }
    ++}
    ++
    ++/* Forward reference */
    ++static int jsonParseAddNode(JsonParse*,u32,u32,const char*);
    ++
    ++/*
    ++** A macro to hint to the compiler that a function should not be
    ++** inlined.
    ++*/
    ++#if defined(__GNUC__)
    ++#  define JSON_NOINLINE  __attribute__((noinline))
    ++#elif defined(_MSC_VER) && _MSC_VER>=1310
    ++#  define JSON_NOINLINE  __declspec(noinline)
    ++#else
    ++#  define JSON_NOINLINE
    ++#endif
    ++
    ++
    ++static JSON_NOINLINE int jsonParseAddNodeExpand(
    ++  JsonParse *pParse,        /* Append the node to this object */
    ++  u32 eType,                /* Node type */
    ++  u32 n,                    /* Content size or sub-node count */
    ++  const char *zContent      /* Content */
    ++){
    ++  u32 nNew;
    ++  JsonNode *pNew;
    ++  assert( pParse->nNode>=pParse->nAlloc );
    ++  if( pParse->oom ) return -1;
    ++  nNew = pParse->nAlloc*2 + 10;
    ++  pNew = sqlite3_realloc(pParse->aNode, sizeof(JsonNode)*nNew);
    ++  if( pNew==0 ){
    ++    pParse->oom = 1;
    ++    return -1;
    ++  }
    ++  pParse->nAlloc = nNew;
    ++  pParse->aNode = pNew;
    ++  assert( pParse->nNode<pParse->nAlloc );
    ++  return jsonParseAddNode(pParse, eType, n, zContent);
    ++}
    ++
    ++/*
    ++** Create a new JsonNode instance based on the arguments and append that
    ++** instance to the JsonParse.  Return the index in pParse->aNode[] of the
    ++** new node, or -1 if a memory allocation fails.
    ++*/
    ++static int jsonParseAddNode(
    ++  JsonParse *pParse,        /* Append the node to this object */
    ++  u32 eType,                /* Node type */
    ++  u32 n,                    /* Content size or sub-node count */
    ++  const char *zContent      /* Content */
    ++){
    ++  JsonNode *p;
    ++  if( pParse->nNode>=pParse->nAlloc ){
    ++    return jsonParseAddNodeExpand(pParse, eType, n, zContent);
    ++  }
    ++  p = &pParse->aNode[pParse->nNode];
    ++  p->eType = (u8)eType;
    ++  p->jnFlags = 0;
    ++  p->n = n;
    ++  p->u.zJContent = zContent;
    ++  return pParse->nNode++;
    ++}
    ++
    ++/*
    ++** Return true if z[] begins with 4 (or more) hexadecimal digits
    ++*/
    ++static int jsonIs4Hex(const char *z){
    ++  int i;
    ++  for(i=0; i<4; i++) if( !safe_isxdigit(z[i]) ) return 0;
    ++  return 1;
    ++}
    ++
    ++/*
    ++** Parse a single JSON value which begins at pParse->zJson[i].  Return the
    ++** index of the first character past the end of the value parsed.
    ++**
    ++** Return negative for a syntax error.  Special cases:  return -2 if the
    ++** first non-whitespace character is '}' and return -3 if the first
    ++** non-whitespace character is ']'.
    ++*/
    ++static int jsonParseValue(JsonParse *pParse, u32 i){
    ++  char c;
    ++  u32 j;
    ++  int iThis;
    ++  int x;
    ++  JsonNode *pNode;
    ++  const char *z = pParse->zJson;
    ++  while( safe_isspace(z[i]) ){ i++; }
    ++  if( (c = z[i])=='{' ){
    ++    /* Parse object */
    ++    iThis = jsonParseAddNode(pParse, JSON_OBJECT, 0, 0);
    ++    if( iThis<0 ) return -1;
    ++    for(j=i+1;;j++){
    ++      while( safe_isspace(z[j]) ){ j++; }
    ++      if( ++pParse->iDepth > JSON_MAX_DEPTH ) return -1;
    ++      x = jsonParseValue(pParse, j);
    ++      if( x<0 ){
    ++        pParse->iDepth--;
    ++        if( x==(-2) && pParse->nNode==(u32)iThis+1 ) return j+1;
    ++        return -1;
    ++      }
    ++      if( pParse->oom ) return -1;
    ++      pNode = &pParse->aNode[pParse->nNode-1];
    ++      if( pNode->eType!=JSON_STRING ) return -1;
    ++      pNode->jnFlags |= JNODE_LABEL;
    ++      j = x;
    ++      while( safe_isspace(z[j]) ){ j++; }
    ++      if( z[j]!=':' ) return -1;
    ++      j++;
    ++      x = jsonParseValue(pParse, j);
    ++      pParse->iDepth--;
    +       if( x<0 ) return -1;
    +       j = x;
    +-      while( safe_isspace(pParse->zJson[j]) ){ j++; }
    +-      c = pParse->zJson[j];
    ++      while( safe_isspace(z[j]) ){ j++; }
    ++      c = z[j];
    +       if( c==',' ) continue;
    +       if( c!='}' ) return -1;
    +       break;
    +@@ -164308,15 +184382,17 @@ static int jsonParseValue(JsonParse *pParse, u32 i){
    +     iThis = jsonParseAddNode(pParse, JSON_ARRAY, 0, 0);
    +     if( iThis<0 ) return -1;
    +     for(j=i+1;;j++){
    +-      while( safe_isspace(pParse->zJson[j]) ){ j++; }
    ++      while( safe_isspace(z[j]) ){ j++; }
    ++      if( ++pParse->iDepth > JSON_MAX_DEPTH ) return -1;
    +       x = jsonParseValue(pParse, j);
    ++      pParse->iDepth--;
    +       if( x<0 ){
    +         if( x==(-3) && pParse->nNode==(u32)iThis+1 ) return j+1;
    +         return -1;
    +       }
    +       j = x;
    +-      while( safe_isspace(pParse->zJson[j]) ){ j++; }
    +-      c = pParse->zJson[j];
    ++      while( safe_isspace(z[j]) ){ j++; }
    ++      c = z[j];
    +       if( c==',' ) continue;
    +       if( c!=']' ) return -1;
    +       break;
    +@@ -164328,66 +184404,79 @@ static int jsonParseValue(JsonParse *pParse, u32 i){
    +     u8 jnFlags = 0;
    +     j = i+1;
    +     for(;;){
    +-      c = pParse->zJson[j];
    +-      if( c==0 ) return -1;
    ++      c = z[j];
    ++      if( (c & ~0x1f)==0 ){
    ++        /* Control characters are not allowed in strings */
    ++        return -1;
    ++      }
    +       if( c=='\\' ){
    +-        c = pParse->zJson[++j];
    +-        if( c==0 ) return -1;
    +-        jnFlags = JNODE_ESCAPE;
    ++        c = z[++j];
    ++        if( c=='"' || c=='\\' || c=='/' || c=='b' || c=='f'
    ++           || c=='n' || c=='r' || c=='t'
    ++           || (c=='u' && jsonIs4Hex(z+j+1)) ){
    ++          jnFlags = JNODE_ESCAPE;
    ++        }else{
    ++          return -1;
    ++        }
    +       }else if( c=='"' ){
    +         break;
    +       }
    +       j++;
    +     }
    +-    jsonParseAddNode(pParse, JSON_STRING, j+1-i, &pParse->zJson[i]);
    ++    jsonParseAddNode(pParse, JSON_STRING, j+1-i, &z[i]);
    +     if( !pParse->oom ) pParse->aNode[pParse->nNode-1].jnFlags = jnFlags;
    +     return j+1;
    +   }else if( c=='n'
    +-         && strncmp(pParse->zJson+i,"null",4)==0
    +-         && !safe_isalnum(pParse->zJson[i+4]) ){
    ++         && strncmp(z+i,"null",4)==0
    ++         && !safe_isalnum(z[i+4]) ){
    +     jsonParseAddNode(pParse, JSON_NULL, 0, 0);
    +     return i+4;
    +   }else if( c=='t'
    +-         && strncmp(pParse->zJson+i,"true",4)==0
    +-         && !safe_isalnum(pParse->zJson[i+4]) ){
    ++         && strncmp(z+i,"true",4)==0
    ++         && !safe_isalnum(z[i+4]) ){
    +     jsonParseAddNode(pParse, JSON_TRUE, 0, 0);
    +     return i+4;
    +   }else if( c=='f'
    +-         && strncmp(pParse->zJson+i,"false",5)==0
    +-         && !safe_isalnum(pParse->zJson[i+5]) ){
    ++         && strncmp(z+i,"false",5)==0
    ++         && !safe_isalnum(z[i+5]) ){
    +     jsonParseAddNode(pParse, JSON_FALSE, 0, 0);
    +     return i+5;
    +   }else if( c=='-' || (c>='0' && c<='9') ){
    +     /* Parse number */
    +     u8 seenDP = 0;
    +     u8 seenE = 0;
    ++    assert( '-' < '0' );
    ++    if( c<='0' ){
    ++      j = c=='-' ? i+1 : i;
    ++      if( z[j]=='0' && z[j+1]>='0' && z[j+1]<='9' ) return -1;
    ++    }
    +     j = i+1;
    +     for(;; j++){
    +-      c = pParse->zJson[j];
    ++      c = z[j];
    +       if( c>='0' && c<='9' ) continue;
    +       if( c=='.' ){
    +-        if( pParse->zJson[j-1]=='-' ) return -1;
    ++        if( z[j-1]=='-' ) return -1;
    +         if( seenDP ) return -1;
    +         seenDP = 1;
    +         continue;
    +       }
    +       if( c=='e' || c=='E' ){
    +-        if( pParse->zJson[j-1]<'0' ) return -1;
    ++        if( z[j-1]<'0' ) return -1;
    +         if( seenE ) return -1;
    +         seenDP = seenE = 1;
    +-        c = pParse->zJson[j+1];
    ++        c = z[j+1];
    +         if( c=='+' || c=='-' ){
    +           j++;
    +-          c = pParse->zJson[j+1];
    ++          c = z[j+1];
    +         }
    +         if( c<'0' || c>'9' ) return -1;
    +         continue;
    +       }
    +       break;
    +     }
    +-    if( pParse->zJson[j-1]<'0' ) return -1;
    ++    if( z[j-1]<'0' ) return -1;
    +     jsonParseAddNode(pParse, seenDP ? JSON_REAL : JSON_INT,
    +-                        j - i, &pParse->zJson[i]);
    ++                        j - i, &z[i]);
    +     return j;
    +   }else if( c=='}' ){
    +     return -2;  /* End of {...} */
    +@@ -164419,6 +184508,7 @@ static int jsonParse(
    +   i = jsonParseValue(pParse, 0);
    +   if( pParse->oom ) i = -1;
    +   if( i>0 ){
    ++    assert( pParse->iDepth==0 );
    +     while( safe_isspace(zJson[i]) ) i++;
    +     if( zJson[i] ) i = -1;
    +   }
    +@@ -164478,6 +184568,49 @@ static int jsonParseFindParents(JsonParse *pParse){
    +   return SQLITE_OK;
    + }
    + 
    ++/*
    ++** Magic number used for the JSON parse cache in sqlite3_get_auxdata()
    ++*/
    ++#define JSON_CACHE_ID  (-429938)
    ++
    ++/*
    ++** Obtain a complete parse of the JSON found in the first argument
    ++** of the argv array.  Use the sqlite3_get_auxdata() cache for this
    ++** parse if it is available.  If the cache is not available or if it
    ++** is no longer valid, parse the JSON again and return the new parse,
    ++** and also register the new parse so that it will be available for
    ++** future sqlite3_get_auxdata() calls.
    ++*/
    ++static JsonParse *jsonParseCached(
    ++  sqlite3_context *pCtx,
    ++  sqlite3_value **argv
    ++){
    ++  const char *zJson = (const char*)sqlite3_value_text(argv[0]);
    ++  int nJson = sqlite3_value_bytes(argv[0]);
    ++  JsonParse *p;
    ++  if( zJson==0 ) return 0;
    ++  p = (JsonParse*)sqlite3_get_auxdata(pCtx, JSON_CACHE_ID);
    ++  if( p && p->nJson==nJson && memcmp(p->zJson,zJson,nJson)==0 ){
    ++    p->nErr = 0;
    ++    return p; /* The cached entry matches, so return it */
    ++  }
    ++  p = sqlite3_malloc( sizeof(*p) + nJson + 1 );
    ++  if( p==0 ){
    ++    sqlite3_result_error_nomem(pCtx);
    ++    return 0;
    ++  }
    ++  memset(p, 0, sizeof(*p));
    ++  p->zJson = (char*)&p[1];
    ++  memcpy((char*)p->zJson, zJson, nJson+1);
    ++  if( jsonParse(p, pCtx, p->zJson) ){
    ++    sqlite3_free(p);
    ++    return 0;
    ++  }
    ++  p->nJson = nJson;
    ++  sqlite3_set_auxdata(pCtx, JSON_CACHE_ID, p, (void(*)(void*))jsonParseFree);
    ++  return (JsonParse*)sqlite3_get_auxdata(pCtx, JSON_CACHE_ID);
    ++}
    ++
    + /*
    + ** Compare the OBJECT label at pNode against zKey,nKey.  Return true on
    + ** a match.
    +@@ -164704,6 +184837,25 @@ static void jsonWrongNumArgs(
    +   sqlite3_free(zMsg);     
    + }
    + 
    ++/*
    ++** Mark all NULL entries in the Object passed in as JNODE_REMOVE.
    ++*/
    ++static void jsonRemoveAllNulls(JsonNode *pNode){
    ++  int i, n;
    ++  assert( pNode->eType==JSON_OBJECT );
    ++  n = pNode->n;
    ++  for(i=2; i<=n; i += jsonNodeSize(&pNode[i])+1){
    ++    switch( pNode[i].eType ){
    ++      case JSON_NULL:
    ++        pNode[i].jnFlags |= JNODE_REMOVE;
    ++        break;
    ++      case JSON_OBJECT:
    ++        jsonRemoveAllNulls(&pNode[i]);
    ++        break;
    ++    }
    ++  }
    ++}
    ++
    + 
    + /****************************************************************************
    + ** SQL functions used for testing and debugging
    +@@ -164764,9 +184916,29 @@ static void jsonTest1Func(
    + #endif /* SQLITE_DEBUG */
    + 
    + /****************************************************************************
    +-** SQL function implementations
    ++** Scalar SQL function implementations
    + ****************************************************************************/
    + 
    ++/*
    ++** Implementation of the json_QUOTE(VALUE) function.  Return a JSON value
    ++** corresponding to the SQL value input.  Mostly this means putting 
    ++** double-quotes around strings and returning the unquoted string "null"
    ++** when given a NULL input.
    ++*/
    ++static void jsonQuoteFunc(
    ++  sqlite3_context *ctx,
    ++  int argc,
    ++  sqlite3_value **argv
    ++){
    ++  JsonString jx;
    ++  UNUSED_PARAM(argc);
    ++
    ++  jsonInit(&jx, ctx);
    ++  jsonAppendValue(&jx, argv[0]);
    ++  jsonResult(&jx);
    ++  sqlite3_result_subtype(ctx, JSON_SUBTYPE);
    ++}
    ++
    + /*
    + ** Implementation of the json_array(VALUE,...) function.  Return a JSON
    + ** array that contains all values given in arguments.  Or if any argument
    +@@ -164804,29 +184976,30 @@ static void jsonArrayLengthFunc(
    +   int argc,
    +   sqlite3_value **argv
    + ){
    +-  JsonParse x;          /* The parse */
    ++  JsonParse *p;          /* The parse */
    +   sqlite3_int64 n = 0;
    +   u32 i;
    +   JsonNode *pNode;
    + 
    +-  if( jsonParse(&x, ctx, (const char*)sqlite3_value_text(argv[0])) ) return;
    +-  assert( x.nNode );
    ++  p = jsonParseCached(ctx, argv);
    ++  if( p==0 ) return;
    ++  assert( p->nNode );
    +   if( argc==2 ){
    +     const char *zPath = (const char*)sqlite3_value_text(argv[1]);
    +-    pNode = jsonLookup(&x, zPath, 0, ctx);
    ++    pNode = jsonLookup(p, zPath, 0, ctx);
    +   }else{
    +-    pNode = x.aNode;
    ++    pNode = p->aNode;
    +   }
    +   if( pNode==0 ){
    +-    x.nErr = 1;
    +-  }else if( pNode->eType==JSON_ARRAY ){
    ++    return;
    ++  }
    ++  if( pNode->eType==JSON_ARRAY ){
    +     assert( (pNode->jnFlags & JNODE_APPEND)==0 );
    +     for(i=1; i<=pNode->n; n++){
    +       i += jsonNodeSize(&pNode[i]);
    +     }
    +   }
    +-  if( x.nErr==0 ) sqlite3_result_int64(ctx, n);
    +-  jsonParseReset(&x);
    ++  sqlite3_result_int64(ctx, n);
    + }
    + 
    + /*
    +@@ -164842,20 +185015,21 @@ static void jsonExtractFunc(
    +   int argc,
    +   sqlite3_value **argv
    + ){
    +-  JsonParse x;          /* The parse */
    ++  JsonParse *p;          /* The parse */
    +   JsonNode *pNode;
    +   const char *zPath;
    +   JsonString jx;
    +   int i;
    + 
    +   if( argc<2 ) return;
    +-  if( jsonParse(&x, ctx, (const char*)sqlite3_value_text(argv[0])) ) return;
    ++  p = jsonParseCached(ctx, argv);
    ++  if( p==0 ) return;
    +   jsonInit(&jx, ctx);
    +   jsonAppendChar(&jx, '[');
    +   for(i=1; i<argc; i++){
    +     zPath = (const char*)sqlite3_value_text(argv[i]);
    +-    pNode = jsonLookup(&x, zPath, 0, ctx);
    +-    if( x.nErr ) break;
    ++    pNode = jsonLookup(p, zPath, 0, ctx);
    ++    if( p->nErr ) break;
    +     if( argc>2 ){
    +       jsonAppendSeparator(&jx);
    +       if( pNode ){
    +@@ -164873,9 +185047,107 @@ static void jsonExtractFunc(
    +     sqlite3_result_subtype(ctx, JSON_SUBTYPE);
    +   }
    +   jsonReset(&jx);
    ++}
    ++
    ++/* This is the RFC 7396 MergePatch algorithm.
    ++*/
    ++static JsonNode *jsonMergePatch(
    ++  JsonParse *pParse,   /* The JSON parser that contains the TARGET */
    ++  u32 iTarget,         /* Node of the TARGET in pParse */
    ++  JsonNode *pPatch     /* The PATCH */
    ++){
    ++  u32 i, j;
    ++  u32 iRoot;
    ++  JsonNode *pTarget;
    ++  if( pPatch->eType!=JSON_OBJECT ){
    ++    return pPatch;
    ++  }
    ++  assert( iTarget>=0 && iTarget<pParse->nNode );
    ++  pTarget = &pParse->aNode[iTarget];
    ++  assert( (pPatch->jnFlags & JNODE_APPEND)==0 );
    ++  if( pTarget->eType!=JSON_OBJECT ){
    ++    jsonRemoveAllNulls(pPatch);
    ++    return pPatch;
    ++  }
    ++  iRoot = iTarget;
    ++  for(i=1; i<pPatch->n; i += jsonNodeSize(&pPatch[i+1])+1){
    ++    u32 nKey;
    ++    const char *zKey;
    ++    assert( pPatch[i].eType==JSON_STRING );
    ++    assert( pPatch[i].jnFlags & JNODE_LABEL );
    ++    nKey = pPatch[i].n;
    ++    zKey = pPatch[i].u.zJContent;
    ++    assert( (pPatch[i].jnFlags & JNODE_RAW)==0 );
    ++    for(j=1; j<pTarget->n; j += jsonNodeSize(&pTarget[j+1])+1 ){
    ++      assert( pTarget[j].eType==JSON_STRING );
    ++      assert( pTarget[j].jnFlags & JNODE_LABEL );
    ++      assert( (pPatch[i].jnFlags & JNODE_RAW)==0 );
    ++      if( pTarget[j].n==nKey && strncmp(pTarget[j].u.zJContent,zKey,nKey)==0 ){
    ++        if( pTarget[j+1].jnFlags & (JNODE_REMOVE|JNODE_PATCH) ) break;
    ++        if( pPatch[i+1].eType==JSON_NULL ){
    ++          pTarget[j+1].jnFlags |= JNODE_REMOVE;
    ++        }else{
    ++          JsonNode *pNew = jsonMergePatch(pParse, iTarget+j+1, &pPatch[i+1]);
    ++          if( pNew==0 ) return 0;
    ++          pTarget = &pParse->aNode[iTarget];
    ++          if( pNew!=&pTarget[j+1] ){
    ++            pTarget[j+1].u.pPatch = pNew;
    ++            pTarget[j+1].jnFlags |= JNODE_PATCH;
    ++          }
    ++        }
    ++        break;
    ++      }
    ++    }
    ++    if( j>=pTarget->n && pPatch[i+1].eType!=JSON_NULL ){
    ++      int iStart, iPatch;
    ++      iStart = jsonParseAddNode(pParse, JSON_OBJECT, 2, 0);
    ++      jsonParseAddNode(pParse, JSON_STRING, nKey, zKey);
    ++      iPatch = jsonParseAddNode(pParse, JSON_TRUE, 0, 0);
    ++      if( pParse->oom ) return 0;
    ++      jsonRemoveAllNulls(pPatch);
    ++      pTarget = &pParse->aNode[iTarget];
    ++      pParse->aNode[iRoot].jnFlags |= JNODE_APPEND;
    ++      pParse->aNode[iRoot].u.iAppend = iStart - iRoot;
    ++      iRoot = iStart;
    ++      pParse->aNode[iPatch].jnFlags |= JNODE_PATCH;
    ++      pParse->aNode[iPatch].u.pPatch = &pPatch[i+1];
    ++    }
    ++  }
    ++  return pTarget;
    ++}
    ++
    ++/*
    ++** Implementation of the json_mergepatch(JSON1,JSON2) function.  Return a JSON
    ++** object that is the result of running the RFC 7396 MergePatch() algorithm
    ++** on the two arguments.
    ++*/
    ++static void jsonPatchFunc(
    ++  sqlite3_context *ctx,
    ++  int argc,
    ++  sqlite3_value **argv
    ++){
    ++  JsonParse x;     /* The JSON that is being patched */
    ++  JsonParse y;     /* The patch */
    ++  JsonNode *pResult;   /* The result of the merge */
    ++
    ++  UNUSED_PARAM(argc);
    ++  if( jsonParse(&x, ctx, (const char*)sqlite3_value_text(argv[0])) ) return;
    ++  if( jsonParse(&y, ctx, (const char*)sqlite3_value_text(argv[1])) ){
    ++    jsonParseReset(&x);
    ++    return;
    ++  }
    ++  pResult = jsonMergePatch(&x, 0, y.aNode);
    ++  assert( pResult!=0 || x.oom );
    ++  if( pResult ){
    ++    jsonReturnJson(pResult, ctx, 0);
    ++  }else{
    ++    sqlite3_result_error_nomem(ctx);
    ++  }
    +   jsonParseReset(&x);
    ++  jsonParseReset(&y);
    + }
    + 
    ++
    + /*
    + ** Implementation of the json_object(NAME,VALUE,...) function.  Return a JSON
    + ** object that contains all name/value given in arguments.  Or if any name
    +@@ -164979,11 +185251,11 @@ static void jsonReplaceFunc(
    +     if( x.nErr ) goto replace_err;
    +     if( pNode ){
    +       pNode->jnFlags |= (u8)JNODE_REPLACE;
    +-      pNode->iVal = (u8)(i+1);
    ++      pNode->u.iReplace = i + 1;
    +     }
    +   }
    +   if( x.aNode[0].jnFlags & JNODE_REPLACE ){
    +-    sqlite3_result_value(ctx, argv[x.aNode[0].iVal]);
    ++    sqlite3_result_value(ctx, argv[x.aNode[0].u.iReplace]);
    +   }else{
    +     jsonReturnJson(x.aNode, ctx, argv);
    +   }
    +@@ -165033,11 +185305,11 @@ static void jsonSetFunc(
    +       goto jsonSetDone;
    +     }else if( pNode && (bApnd || bIsSet) ){
    +       pNode->jnFlags |= (u8)JNODE_REPLACE;
    +-      pNode->iVal = (u8)(i+1);
    ++      pNode->u.iReplace = i + 1;
    +     }
    +   }
    +   if( x.aNode[0].jnFlags & JNODE_REPLACE ){
    +-    sqlite3_result_value(ctx, argv[x.aNode[0].iVal]);
    ++    sqlite3_result_value(ctx, argv[x.aNode[0].u.iReplace]);
    +   }else{
    +     jsonReturnJson(x.aNode, ctx, argv);
    +   }
    +@@ -165097,6 +185369,104 @@ static void jsonValidFunc(
    +   sqlite3_result_int(ctx, rc);
    + }
    + 
    ++
    ++/****************************************************************************
    ++** Aggregate SQL function implementations
    ++****************************************************************************/
    ++/*
    ++** json_group_array(VALUE)
    ++**
    ++** Return a JSON array composed of all values in the aggregate.
    ++*/
    ++static void jsonArrayStep(
    ++  sqlite3_context *ctx,
    ++  int argc,
    ++  sqlite3_value **argv
    ++){
    ++  JsonString *pStr;
    ++  UNUSED_PARAM(argc);
    ++  pStr = (JsonString*)sqlite3_aggregate_context(ctx, sizeof(*pStr));
    ++  if( pStr ){
    ++    if( pStr->zBuf==0 ){
    ++      jsonInit(pStr, ctx);
    ++      jsonAppendChar(pStr, '[');
    ++    }else{
    ++      jsonAppendChar(pStr, ',');
    ++      pStr->pCtx = ctx;
    ++    }
    ++    jsonAppendValue(pStr, argv[0]);
    ++  }
    ++}
    ++static void jsonArrayFinal(sqlite3_context *ctx){
    ++  JsonString *pStr;
    ++  pStr = (JsonString*)sqlite3_aggregate_context(ctx, 0);
    ++  if( pStr ){
    ++    pStr->pCtx = ctx;
    ++    jsonAppendChar(pStr, ']');
    ++    if( pStr->bErr ){
    ++      if( pStr->bErr==1 ) sqlite3_result_error_nomem(ctx);
    ++      assert( pStr->bStatic );
    ++    }else{
    ++      sqlite3_result_text(ctx, pStr->zBuf, pStr->nUsed,
    ++                          pStr->bStatic ? SQLITE_TRANSIENT : sqlite3_free);
    ++      pStr->bStatic = 1;
    ++    }
    ++  }else{
    ++    sqlite3_result_text(ctx, "[]", 2, SQLITE_STATIC);
    ++  }
    ++  sqlite3_result_subtype(ctx, JSON_SUBTYPE);
    ++}
    ++
    ++/*
    ++** json_group_obj(NAME,VALUE)
    ++**
    ++** Return a JSON object composed of all names and values in the aggregate.
    ++*/
    ++static void jsonObjectStep(
    ++  sqlite3_context *ctx,
    ++  int argc,
    ++  sqlite3_value **argv
    ++){
    ++  JsonString *pStr;
    ++  const char *z;
    ++  u32 n;
    ++  UNUSED_PARAM(argc);
    ++  pStr = (JsonString*)sqlite3_aggregate_context(ctx, sizeof(*pStr));
    ++  if( pStr ){
    ++    if( pStr->zBuf==0 ){
    ++      jsonInit(pStr, ctx);
    ++      jsonAppendChar(pStr, '{');
    ++    }else{
    ++      jsonAppendChar(pStr, ',');
    ++      pStr->pCtx = ctx;
    ++    }
    ++    z = (const char*)sqlite3_value_text(argv[0]);
    ++    n = (u32)sqlite3_value_bytes(argv[0]);
    ++    jsonAppendString(pStr, z, n);
    ++    jsonAppendChar(pStr, ':');
    ++    jsonAppendValue(pStr, argv[1]);
    ++  }
    ++}
    ++static void jsonObjectFinal(sqlite3_context *ctx){
    ++  JsonString *pStr;
    ++  pStr = (JsonString*)sqlite3_aggregate_context(ctx, 0);
    ++  if( pStr ){
    ++    jsonAppendChar(pStr, '}');
    ++    if( pStr->bErr ){
    ++      if( pStr->bErr==1 ) sqlite3_result_error_nomem(ctx);
    ++      assert( pStr->bStatic );
    ++    }else{
    ++      sqlite3_result_text(ctx, pStr->zBuf, pStr->nUsed,
    ++                          pStr->bStatic ? SQLITE_TRANSIENT : sqlite3_free);
    ++      pStr->bStatic = 1;
    ++    }
    ++  }else{
    ++    sqlite3_result_text(ctx, "{}", 2, SQLITE_STATIC);
    ++  }
    ++  sqlite3_result_subtype(ctx, JSON_SUBTYPE);
    ++}
    ++
    ++
    + #ifndef SQLITE_OMIT_VIRTUALTABLE
    + /****************************************************************************
    + ** The json_each virtual table
    +@@ -165361,9 +185731,9 @@ static int jsonEachColumn(
    +       /* For json_each() path and root are the same so fall through
    +       ** into the root case */
    +     }
    +-    case JEACH_ROOT: {
    ++    default: {
    +       const char *zRoot = p->zRoot;
    +-       if( zRoot==0 ) zRoot = "$";
    ++      if( zRoot==0 ) zRoot = "$";
    +       sqlite3_result_text(ctx, zRoot, -1, SQLITE_STATIC);
    +       break;
    +     }
    +@@ -165582,6 +185952,8 @@ SQLITE_PRIVATE int sqlite3Json1Init(sqlite3 *db){
    +     { "json_extract",        -1, 0,   jsonExtractFunc       },
    +     { "json_insert",         -1, 0,   jsonSetFunc           },
    +     { "json_object",         -1, 0,   jsonObjectFunc        },
    ++    { "json_patch",           2, 0,   jsonPatchFunc         },
    ++    { "json_quote",           1, 0,   jsonQuoteFunc         },
    +     { "json_remove",         -1, 0,   jsonRemoveFunc        },
    +     { "json_replace",        -1, 0,   jsonReplaceFunc       },
    +     { "json_set",            -1, 1,   jsonSetFunc           },
    +@@ -165595,6 +185967,15 @@ SQLITE_PRIVATE int sqlite3Json1Init(sqlite3 *db){
    +     { "json_test1",           1, 0,   jsonTest1Func         },
    + #endif
    +   };
    ++  static const struct {
    ++     const char *zName;
    ++     int nArg;
    ++     void (*xStep)(sqlite3_context*,int,sqlite3_value**);
    ++     void (*xFinal)(sqlite3_context*);
    ++  } aAgg[] = {
    ++    { "json_group_array",     1,   jsonArrayStep,   jsonArrayFinal  },
    ++    { "json_group_object",    2,   jsonObjectStep,  jsonObjectFinal },
    ++  };
    + #ifndef SQLITE_OMIT_VIRTUALTABLE
    +   static const struct {
    +      const char *zName;
    +@@ -165610,6 +185991,11 @@ SQLITE_PRIVATE int sqlite3Json1Init(sqlite3 *db){
    +                                  (void*)&aFunc[i].flag,
    +                                  aFunc[i].xFunc, 0, 0);
    +   }
    ++  for(i=0; i<sizeof(aAgg)/sizeof(aAgg[0]) && rc==SQLITE_OK; i++){
    ++    rc = sqlite3_create_function(db, aAgg[i].zName, aAgg[i].nArg,
    ++                                 SQLITE_UTF8 | SQLITE_DETERMINISTIC, 0,
    ++                                 0, aAgg[i].xStep, aAgg[i].xFinal);
    ++  }
    + #ifndef SQLITE_OMIT_VIRTUALTABLE
    +   for(i=0; i<sizeof(aMod)/sizeof(aMod[0]) && rc==SQLITE_OK; i++){
    +     rc = sqlite3_create_module(db, aMod[i].zName, aMod[i].pModule, 0);
    +@@ -165623,7 +186009,7 @@ SQLITE_PRIVATE int sqlite3Json1Init(sqlite3 *db){
    + #ifdef _WIN32
    + __declspec(dllexport)
    + #endif
    +-SQLITE_API int SQLITE_STDCALL sqlite3_json_init(
    ++SQLITE_API int sqlite3_json_init(
    +   sqlite3 *db, 
    +   char **pzErrMsg, 
    +   const sqlite3_api_routines *pApi
    +@@ -165734,6 +186120,9 @@ struct Fts5PhraseIter {
    + **   an OOM condition or IO error), an appropriate SQLite error code is 
    + **   returned.
    + **
    ++**   This function may be quite inefficient if used with an FTS5 table
    ++**   created with the "columnsize=0" option.
    ++**
    + ** xColumnText:
    + **   This function attempts to retrieve the text of column iCol of the
    + **   current document. If successful, (*pz) is set to point to a buffer
    +@@ -165754,15 +186143,29 @@ struct Fts5PhraseIter {
    + **   the query within the current row. Return SQLITE_OK if successful, or
    + **   an error code (i.e. SQLITE_NOMEM) if an error occurs.
    + **
    ++**   This API can be quite slow if used with an FTS5 table created with the
    ++**   "detail=none" or "detail=column" option. If the FTS5 table is created 
    ++**   with either "detail=none" or "detail=column" and "content=" option 
    ++**   (i.e. if it is a contentless table), then this API always returns 0.
    ++**
    + ** xInst:
    + **   Query for the details of phrase match iIdx within the current row.
    + **   Phrase matches are numbered starting from zero, so the iIdx argument
    + **   should be greater than or equal to zero and smaller than the value
    + **   output by xInstCount().
    + **
    ++**   Usually, output parameter *piPhrase is set to the phrase number, *piCol
    ++**   to the column in which it occurs and *piOff the token offset of the
    ++**   first token of the phrase. The exception is if the table was created
    ++**   with the offsets=0 option specified. In this case *piOff is always
    ++**   set to -1.
    ++**
    + **   Returns SQLITE_OK if successful, or an error code (i.e. SQLITE_NOMEM) 
    + **   if an error occurs.
    + **
    ++**   This API can be quite slow if used with an FTS5 table created with the
    ++**   "detail=none" or "detail=column" option. 
    ++**
    + ** xRowid:
    + **   Returns the rowid of the current row.
    + **
    +@@ -165776,11 +186179,13 @@ struct Fts5PhraseIter {
    + **       ... FROM ftstable WHERE ftstable MATCH $p ORDER BY rowid
    + **
    + **   with $p set to a phrase equivalent to the phrase iPhrase of the
    +-**   current query is executed. For each row visited, the callback function
    +-**   passed as the fourth argument is invoked. The context and API objects 
    +-**   passed to the callback function may be used to access the properties of
    +-**   each matched row. Invoking Api.xUserData() returns a copy of the pointer
    +-**   passed as the third argument to pUserData.
    ++**   current query is executed. Any column filter that applies to
    ++**   phrase iPhrase of the current query is included in $p. For each 
    ++**   row visited, the callback function passed as the fourth argument 
    ++**   is invoked. The context and API objects passed to the callback 
    ++**   function may be used to access the properties of each matched row.
    ++**   Invoking Api.xUserData() returns a copy of the pointer passed as 
    ++**   the third argument to pUserData.
    + **
    + **   If the callback function returns any value other than SQLITE_OK, the
    + **   query is abandoned and the xQueryPhrase function returns immediately.
    +@@ -165846,7 +186251,7 @@ struct Fts5PhraseIter {
    + **       Fts5PhraseIter iter;
    + **       int iCol, iOff;
    + **       for(pApi->xPhraseFirst(pFts, iPhrase, &iter, &iCol, &iOff);
    +-**           iOff>=0;
    ++**           iCol>=0;
    + **           pApi->xPhraseNext(pFts, &iter, &iCol, &iOff)
    + **       ){
    + **         // An instance of phrase iPhrase at offset iOff of column iCol
    +@@ -165854,13 +186259,51 @@ struct Fts5PhraseIter {
    + **
    + **   The Fts5PhraseIter structure is defined above. Applications should not
    + **   modify this structure directly - it should only be used as shown above
    +-**   with the xPhraseFirst() and xPhraseNext() API methods.
    ++**   with the xPhraseFirst() and xPhraseNext() API methods (and by
    ++**   xPhraseFirstColumn() and xPhraseNextColumn() as illustrated below).
    ++**
    ++**   This API can be quite slow if used with an FTS5 table created with the
    ++**   "detail=none" or "detail=column" option. If the FTS5 table is created 
    ++**   with either "detail=none" or "detail=column" and "content=" option 
    ++**   (i.e. if it is a contentless table), then this API always iterates
    ++**   through an empty set (all calls to xPhraseFirst() set iCol to -1).
    + **
    + ** xPhraseNext()
    + **   See xPhraseFirst above.
    ++**
    ++** xPhraseFirstColumn()
    ++**   This function and xPhraseNextColumn() are similar to the xPhraseFirst()
    ++**   and xPhraseNext() APIs described above. The difference is that instead
    ++**   of iterating through all instances of a phrase in the current row, these
    ++**   APIs are used to iterate through the set of columns in the current row
    ++**   that contain one or more instances of a specified phrase. For example:
    ++**
    ++**       Fts5PhraseIter iter;
    ++**       int iCol;
    ++**       for(pApi->xPhraseFirstColumn(pFts, iPhrase, &iter, &iCol);
    ++**           iCol>=0;
    ++**           pApi->xPhraseNextColumn(pFts, &iter, &iCol)
    ++**       ){
    ++**         // Column iCol contains at least one instance of phrase iPhrase
    ++**       }
    ++**
    ++**   This API can be quite slow if used with an FTS5 table created with the
    ++**   "detail=none" option. If the FTS5 table is created with either 
    ++**   "detail=none" "content=" option (i.e. if it is a contentless table), 
    ++**   then this API always iterates through an empty set (all calls to 
    ++**   xPhraseFirstColumn() set iCol to -1).
    ++**
    ++**   The information accessed using this API and its companion
    ++**   xPhraseFirstColumn() may also be obtained using xPhraseFirst/xPhraseNext
    ++**   (or xInst/xInstCount). The chief advantage of this API is that it is
    ++**   significantly more efficient than those alternatives when used with
    ++**   "detail=column" tables.  
    ++**
    ++** xPhraseNextColumn()
    ++**   See xPhraseFirstColumn above.
    + */
    + struct Fts5ExtensionApi {
    +-  int iVersion;                   /* Currently always set to 1 */
    ++  int iVersion;                   /* Currently always set to 3 */
    + 
    +   void *(*xUserData)(Fts5Context*);
    + 
    +@@ -165890,8 +186333,11 @@ struct Fts5ExtensionApi {
    +   int (*xSetAuxdata)(Fts5Context*, void *pAux, void(*xDelete)(void*));
    +   void *(*xGetAuxdata)(Fts5Context*, int bClear);
    + 
    +-  void (*xPhraseFirst)(Fts5Context*, int iPhrase, Fts5PhraseIter*, int*, int*);
    ++  int (*xPhraseFirst)(Fts5Context*, int iPhrase, Fts5PhraseIter*, int*, int*);
    +   void (*xPhraseNext)(Fts5Context*, Fts5PhraseIter*, int *piCol, int *piOff);
    ++
    ++  int (*xPhraseFirstColumn)(Fts5Context*, int iPhrase, Fts5PhraseIter*, int*);
    ++  void (*xPhraseNextColumn)(Fts5Context*, Fts5PhraseIter*, int *piCol);
    + };
    + 
    + /* 
    +@@ -165908,7 +186354,7 @@ struct Fts5ExtensionApi {
    + ** behaviour. The structure methods are expected to function as follows:
    + **
    + ** xCreate:
    +-**   This function is used to allocate and inititalize a tokenizer instance.
    ++**   This function is used to allocate and initialize a tokenizer instance.
    + **   A tokenizer instance is required to actually tokenize text.
    + **
    + **   The first argument passed to this function is a copy of the (void*)
    +@@ -166168,7 +186614,6 @@ struct fts5_api {
    + 
    + #endif /* _FTS5_H */
    + 
    +-
    + /*
    + ** 2014 May 31
    + **
    +@@ -166185,6 +186630,7 @@ struct fts5_api {
    + #ifndef _FTS5INT_H
    + #define _FTS5INT_H
    + 
    ++/* #include "fts5.h" */
    + /* #include "sqlite3ext.h" */
    + SQLITE_EXTENSION_INIT1
    + 
    +@@ -166196,10 +186642,13 @@ SQLITE_EXTENSION_INIT1
    + typedef unsigned char  u8;
    + typedef unsigned int   u32;
    + typedef unsigned short u16;
    ++typedef short i16;
    + typedef sqlite3_int64 i64;
    + typedef sqlite3_uint64 u64;
    + 
    +-#define ArraySize(x) (sizeof(x) / sizeof(x[0]))
    ++#ifndef ArraySize
    ++# define ArraySize(x) ((int)(sizeof(x) / sizeof(x[0])))
    ++#endif
    + 
    + #define testcase(x)
    + #define ALWAYS(x) 1
    +@@ -166216,6 +186665,10 @@ typedef sqlite3_uint64 u64;
    + 
    + #endif
    + 
    ++/* Truncate very long tokens to this many bytes. Hard limit is 
    ++** (65536-1-1-4-9)==65521 bytes. The limiting factor is the 16-bit offset
    ++** field that occurs at the start of each leaf page (see fts5_index.c). */
    ++#define FTS5_MAX_TOKEN_SIZE 32768
    + 
    + /*
    + ** Maximum number of prefix indexes on single FTS5 table. This must be
    +@@ -166250,6 +186703,16 @@ SQLITE_API extern int sqlite3_fts5_may_be_corrupt;
    + # define assert_nc(x) assert(x)
    + #endif
    + 
    ++/* Mark a function parameter as unused, to suppress nuisance compiler
    ++** warnings. */
    ++#ifndef UNUSED_PARAM
    ++# define UNUSED_PARAM(X)  (void)(X)
    ++#endif
    ++
    ++#ifndef UNUSED_PARAM2
    ++# define UNUSED_PARAM2(X, Y)  (void)(X), (void)(Y)
    ++#endif
    ++
    + typedef struct Fts5Global Fts5Global;
    + typedef struct Fts5Colset Fts5Colset;
    + 
    +@@ -166321,6 +186784,7 @@ struct Fts5Config {
    +   char *zContent;                 /* content table */ 
    +   char *zContentRowid;            /* "content_rowid=" option value */ 
    +   int bColumnsize;                /* "columnsize=" option value (dflt==1) */
    ++  int eDetail;                    /* FTS5_DETAIL_XXX value */
    +   char *zContentExprlist;
    +   Fts5Tokenizer *pTok;
    +   fts5_tokenizer *pTokApi;
    +@@ -166330,6 +186794,8 @@ struct Fts5Config {
    +   int pgsz;                       /* Approximate page size used in %_data */
    +   int nAutomerge;                 /* 'automerge' setting */
    +   int nCrisisMerge;               /* Maximum allowed segments per level */
    ++  int nUsermerge;                 /* 'usermerge' setting */
    ++  int nHashSize;                  /* Bytes of memory for in-memory hash */
    +   char *zRank;                    /* Name of rank function */
    +   char *zRankArgs;                /* Arguments to rank function */
    + 
    +@@ -166348,6 +186814,9 @@ struct Fts5Config {
    + #define FTS5_CONTENT_NONE     1
    + #define FTS5_CONTENT_EXTERNAL 2
    + 
    ++#define FTS5_DETAIL_FULL    0
    ++#define FTS5_DETAIL_NONE    1
    ++#define FTS5_DETAIL_COLUMNS 2
    + 
    + 
    + 
    +@@ -166394,25 +186863,27 @@ struct Fts5Buffer {
    +   int nSpace;
    + };
    + 
    +-static int sqlite3Fts5BufferGrow(int*, Fts5Buffer*, int);
    ++static int sqlite3Fts5BufferSize(int*, Fts5Buffer*, u32);
    + static void sqlite3Fts5BufferAppendVarint(int*, Fts5Buffer*, i64);
    +-static void sqlite3Fts5BufferAppendBlob(int*, Fts5Buffer*, int, const u8*);
    ++static void sqlite3Fts5BufferAppendBlob(int*, Fts5Buffer*, u32, const u8*);
    + static void sqlite3Fts5BufferAppendString(int *, Fts5Buffer*, const char*);
    + static void sqlite3Fts5BufferFree(Fts5Buffer*);
    + static void sqlite3Fts5BufferZero(Fts5Buffer*);
    + static void sqlite3Fts5BufferSet(int*, Fts5Buffer*, int, const u8*);
    + static void sqlite3Fts5BufferAppendPrintf(int *, Fts5Buffer*, char *zFmt, ...);
    +-static void sqlite3Fts5BufferAppend32(int*, Fts5Buffer*, int);
    + 
    + static char *sqlite3Fts5Mprintf(int *pRc, const char *zFmt, ...);
    + 
    + #define fts5BufferZero(x)             sqlite3Fts5BufferZero(x)
    +-#define fts5BufferGrow(a,b,c)         sqlite3Fts5BufferGrow(a,b,c)
    + #define fts5BufferAppendVarint(a,b,c) sqlite3Fts5BufferAppendVarint(a,b,c)
    + #define fts5BufferFree(a)             sqlite3Fts5BufferFree(a)
    + #define fts5BufferAppendBlob(a,b,c,d) sqlite3Fts5BufferAppendBlob(a,b,c,d)
    + #define fts5BufferSet(a,b,c,d)        sqlite3Fts5BufferSet(a,b,c,d)
    +-#define fts5BufferAppend32(a,b,c)     sqlite3Fts5BufferAppend32(a,b,c)
    ++
    ++#define fts5BufferGrow(pRc,pBuf,nn) ( \
    ++  (u32)((pBuf)->n) + (u32)(nn) <= (u32)((pBuf)->nSpace) ? 0 : \
    ++    sqlite3Fts5BufferSize((pRc),(pBuf),(nn)+(pBuf)->n) \
    ++)
    + 
    + /* Write and decode big-endian 32-bit integer values */
    + static void sqlite3Fts5Put32(u8*, int);
    +@@ -166445,6 +186916,7 @@ struct Fts5PoslistWriter {
    +   i64 iPrev;
    + };
    + static int sqlite3Fts5PoslistWriterAppend(Fts5Buffer*, Fts5PoslistWriter*, i64);
    ++static void sqlite3Fts5PoslistSafeAppend(Fts5Buffer*, i64*, i64);
    + 
    + static int sqlite3Fts5PoslistNext64(
    +   const u8 *a, int n,             /* Buffer containing poslist */
    +@@ -166459,6 +186931,13 @@ static char *sqlite3Fts5Strndup(int *pRc, const char *pIn, int nIn);
    + /* Character set tests (like isspace(), isalpha() etc.) */
    + static int sqlite3Fts5IsBareword(char t);
    + 
    ++
    ++/* Bucket of terms object used by the integrity-check in offsets=0 mode. */
    ++typedef struct Fts5Termset Fts5Termset;
    ++static int sqlite3Fts5TermsetNew(Fts5Termset**);
    ++static int sqlite3Fts5TermsetAdd(Fts5Termset*, int, const char*, int, int *pbPresent);
    ++static void sqlite3Fts5TermsetFree(Fts5Termset*);
    ++
    + /*
    + ** End of interface to code in fts5_buffer.c.
    + **************************************************************************/
    +@@ -166471,6 +186950,15 @@ static int sqlite3Fts5IsBareword(char t);
    + typedef struct Fts5Index Fts5Index;
    + typedef struct Fts5IndexIter Fts5IndexIter;
    + 
    ++struct Fts5IndexIter {
    ++  i64 iRowid;
    ++  const u8 *pData;
    ++  int nData;
    ++  u8 bEof;
    ++};
    ++
    ++#define sqlite3Fts5IterEof(x) ((x)->bEof)
    ++
    + /*
    + ** Values used as part of the flags argument passed to IndexQuery().
    + */
    +@@ -166479,6 +186967,12 @@ typedef struct Fts5IndexIter Fts5IndexIter;
    + #define FTS5INDEX_QUERY_TEST_NOIDX 0x0004   /* Do not use prefix index */
    + #define FTS5INDEX_QUERY_SCAN       0x0008   /* Scan query (fts5vocab) */
    + 
    ++/* The following are used internally by the fts5_index.c module. They are
    ++** defined here only to make it easier to avoid clashes with the flags
    ++** above. */
    ++#define FTS5INDEX_QUERY_SKIPEMPTY  0x0010
    ++#define FTS5INDEX_QUERY_NOOUTPUT   0x0020
    ++
    + /*
    + ** Create/destroy an Fts5Index object.
    + */
    +@@ -166486,14 +186980,27 @@ static int sqlite3Fts5IndexOpen(Fts5Config *pConfig, int bCreate, Fts5Index**, c
    + static int sqlite3Fts5IndexClose(Fts5Index *p);
    + 
    + /*
    +-** for(
    +-**   sqlite3Fts5IndexQuery(p, "token", 5, 0, 0, &pIter);
    +-**   0==sqlite3Fts5IterEof(pIter);
    +-**   sqlite3Fts5IterNext(pIter)
    +-** ){
    +-**   i64 iRowid = sqlite3Fts5IterRowid(pIter);
    +-** }
    ++** Return a simple checksum value based on the arguments.
    + */
    ++static u64 sqlite3Fts5IndexEntryCksum(
    ++  i64 iRowid, 
    ++  int iCol, 
    ++  int iPos, 
    ++  int iIdx,
    ++  const char *pTerm,
    ++  int nTerm
    ++);
    ++
    ++/*
    ++** Argument p points to a buffer containing utf-8 text that is n bytes in 
    ++** size. Return the number of bytes in the nChar character prefix of the
    ++** buffer, or 0 if there are less than nChar characters in total.
    ++*/
    ++static int sqlite3Fts5IndexCharlenToBytelen(
    ++  const char *p, 
    ++  int nByte, 
    ++  int nChar
    ++);
    + 
    + /*
    + ** Open a new iterator to iterate though all rowids that match the 
    +@@ -166511,12 +187018,8 @@ static int sqlite3Fts5IndexQuery(
    + ** The various operations on open token or token prefix iterators opened
    + ** using sqlite3Fts5IndexQuery().
    + */
    +-static int sqlite3Fts5IterEof(Fts5IndexIter*);
    + static int sqlite3Fts5IterNext(Fts5IndexIter*);
    + static int sqlite3Fts5IterNextFrom(Fts5IndexIter*, i64 iMatch);
    +-static i64 sqlite3Fts5IterRowid(Fts5IndexIter*);
    +-static int sqlite3Fts5IterPoslist(Fts5IndexIter*,Fts5Colset*, const u8**, int*, i64*);
    +-static int sqlite3Fts5IterPoslistBuffer(Fts5IndexIter *pIter, Fts5Buffer *pBuf);
    + 
    + /*
    + ** Close an iterator opened by sqlite3Fts5IndexQuery().
    +@@ -166559,9 +187062,9 @@ static int sqlite3Fts5IndexBeginWrite(
    + 
    + /*
    + ** Flush any data stored in the in-memory hash tables to the database.
    +-** If the bCommit flag is true, also close any open blob handles.
    ++** Also close any open blob handles.
    + */
    +-static int sqlite3Fts5IndexSync(Fts5Index *p, int bCommit);
    ++static int sqlite3Fts5IndexSync(Fts5Index *p);
    + 
    + /*
    + ** Discard any data stored in the in-memory hash tables. Do not write it
    +@@ -166580,7 +187083,6 @@ static int sqlite3Fts5IndexSetAverages(Fts5Index *p, const u8*, int);
    + /*
    + ** Functions called by the storage module as part of integrity-check.
    + */
    +-static u64 sqlite3Fts5IndexCksum(Fts5Config*,i64,int,int,const char*,int);
    + static int sqlite3Fts5IndexIntegrityCheck(Fts5Index*, u64 cksum);
    + 
    + /* 
    +@@ -166600,6 +187102,7 @@ static int sqlite3Fts5IndexReads(Fts5Index *p);
    + static int sqlite3Fts5IndexReinit(Fts5Index *p);
    + static int sqlite3Fts5IndexOptimize(Fts5Index *p);
    + static int sqlite3Fts5IndexMerge(Fts5Index *p, int nMerge);
    ++static int sqlite3Fts5IndexReset(Fts5Index *p);
    + 
    + static int sqlite3Fts5IndexLoadConfig(Fts5Index *p);
    + 
    +@@ -166645,7 +187148,7 @@ static int sqlite3Fts5GetTokenizer(
    +   char **pzErr
    + );
    + 
    +-static Fts5Index *sqlite3Fts5IndexFromCsrid(Fts5Global*, i64, int*);
    ++static Fts5Index *sqlite3Fts5IndexFromCsrid(Fts5Global*, i64, Fts5Config **);
    + 
    + /*
    + ** End of interface to code in fts5.c.
    +@@ -166659,7 +187162,7 @@ typedef struct Fts5Hash Fts5Hash;
    + /*
    + ** Create a hash table, free a hash table.
    + */
    +-static int sqlite3Fts5HashNew(Fts5Hash**, int *pnSize);
    ++static int sqlite3Fts5HashNew(Fts5Config*, Fts5Hash**, int *pnSize);
    + static void sqlite3Fts5HashFree(Fts5Hash*);
    + 
    + static int sqlite3Fts5HashWrite(
    +@@ -166718,7 +187221,7 @@ static int sqlite3Fts5StorageRename(Fts5Storage*, const char *zName);
    + static int sqlite3Fts5DropAll(Fts5Config*);
    + static int sqlite3Fts5CreateTable(Fts5Config*, const char*, const char*, int, char **);
    + 
    +-static int sqlite3Fts5StorageDelete(Fts5Storage *p, i64);
    ++static int sqlite3Fts5StorageDelete(Fts5Storage *p, i64, sqlite3_value**);
    + static int sqlite3Fts5StorageContentInsert(Fts5Storage *p, sqlite3_value**, i64*);
    + static int sqlite3Fts5StorageIndexInsert(Fts5Storage *p, sqlite3_value**, i64);
    + 
    +@@ -166731,19 +187234,18 @@ static int sqlite3Fts5StorageDocsize(Fts5Storage *p, i64 iRowid, int *aCol);
    + static int sqlite3Fts5StorageSize(Fts5Storage *p, int iCol, i64 *pnAvg);
    + static int sqlite3Fts5StorageRowCount(Fts5Storage *p, i64 *pnRow);
    + 
    +-static int sqlite3Fts5StorageSync(Fts5Storage *p, int bCommit);
    ++static int sqlite3Fts5StorageSync(Fts5Storage *p);
    + static int sqlite3Fts5StorageRollback(Fts5Storage *p);
    + 
    + static int sqlite3Fts5StorageConfigValue(
    +     Fts5Storage *p, const char*, sqlite3_value*, int
    + );
    + 
    +-static int sqlite3Fts5StorageSpecialDelete(Fts5Storage *p, i64 iDel, sqlite3_value**);
    +-
    + static int sqlite3Fts5StorageDeleteAll(Fts5Storage *p);
    + static int sqlite3Fts5StorageRebuild(Fts5Storage *p);
    + static int sqlite3Fts5StorageOptimize(Fts5Storage *p);
    + static int sqlite3Fts5StorageMerge(Fts5Storage *p, int nMerge);
    ++static int sqlite3Fts5StorageReset(Fts5Storage *p);
    + 
    + /*
    + ** End of interface to code in fts5_storage.c.
    +@@ -166768,6 +187270,7 @@ struct Fts5Token {
    + /* Parse a MATCH expression. */
    + static int sqlite3Fts5ExprNew(
    +   Fts5Config *pConfig, 
    ++  int iCol,                       /* Column on LHS of MATCH operator */
    +   const char *zExpr,
    +   Fts5Expr **ppNew, 
    +   char **pzErr
    +@@ -166796,7 +187299,16 @@ static int sqlite3Fts5ExprPhraseCount(Fts5Expr*);
    + static int sqlite3Fts5ExprPhraseSize(Fts5Expr*, int iPhrase);
    + static int sqlite3Fts5ExprPoslist(Fts5Expr*, int, const u8 **);
    + 
    +-static int sqlite3Fts5ExprClonePhrase(Fts5Config*, Fts5Expr*, int, Fts5Expr**);
    ++typedef struct Fts5PoslistPopulator Fts5PoslistPopulator;
    ++static Fts5PoslistPopulator *sqlite3Fts5ExprClearPoslists(Fts5Expr*, int);
    ++static int sqlite3Fts5ExprPopulatePoslists(
    ++    Fts5Config*, Fts5Expr*, Fts5PoslistPopulator*, int, const char*, int
    ++);
    ++static void sqlite3Fts5ExprCheckPoslists(Fts5Expr*, i64);
    ++
    ++static int sqlite3Fts5ExprClonePhrase(Fts5Expr*, int, Fts5Expr**);
    ++
    ++static int sqlite3Fts5ExprPhraseCollist(Fts5Expr *, int, const u8 **, int *);
    + 
    + /*******************************************
    + ** The fts5_expr.c API above this point is used by the other hand-written
    +@@ -166813,6 +187325,12 @@ static Fts5ExprNode *sqlite3Fts5ParseNode(
    +   Fts5ExprNearset *pNear
    + );
    + 
    ++static Fts5ExprNode *sqlite3Fts5ParseImplicitAnd(
    ++  Fts5Parse *pParse,
    ++  Fts5ExprNode *pLeft,
    ++  Fts5ExprNode *pRight
    ++);
    ++
    + static Fts5ExprPhrase *sqlite3Fts5ParseTerm(
    +   Fts5Parse *pParse, 
    +   Fts5ExprPhrase *pPhrase, 
    +@@ -166820,6 +187338,8 @@ static Fts5ExprPhrase *sqlite3Fts5ParseTerm(
    +   int bPrefix
    + );
    + 
    ++static void sqlite3Fts5ParseSetCaret(Fts5ExprPhrase*);
    ++
    + static Fts5ExprNearset *sqlite3Fts5ParseNearset(
    +   Fts5Parse*, 
    +   Fts5ExprNearset*,
    +@@ -166837,7 +187357,8 @@ static void sqlite3Fts5ParseNearsetFree(Fts5ExprNearset*);
    + static void sqlite3Fts5ParseNodeFree(Fts5ExprNode*);
    + 
    + static void sqlite3Fts5ParseSetDistance(Fts5Parse*, Fts5ExprNearset*, Fts5Token*);
    +-static void sqlite3Fts5ParseSetColset(Fts5Parse*, Fts5ExprNearset*, Fts5Colset*);
    ++static void sqlite3Fts5ParseSetColset(Fts5Parse*, Fts5ExprNode*, Fts5Colset*);
    ++static Fts5Colset *sqlite3Fts5ParseColsetInvert(Fts5Parse*, Fts5Colset*);
    + static void sqlite3Fts5ParseFinished(Fts5Parse *pParse, Fts5ExprNode *p);
    + static void sqlite3Fts5ParseNear(Fts5Parse *pParse, Fts5Token*);
    + 
    +@@ -166893,28 +187414,46 @@ static int sqlite3Fts5UnicodeFold(int c, int bRemoveDiacritic);
    + #define FTS5_NOT                              3
    + #define FTS5_TERM                             4
    + #define FTS5_COLON                            5
    +-#define FTS5_LP                               6
    +-#define FTS5_RP                               7
    +-#define FTS5_LCP                              8
    +-#define FTS5_RCP                              9
    +-#define FTS5_STRING                          10
    +-#define FTS5_COMMA                           11
    +-#define FTS5_PLUS                            12
    +-#define FTS5_STAR                            13
    +-
    +-/* Driver template for the LEMON parser generator.
    +-** The author disclaims copyright to this source code.
    ++#define FTS5_MINUS                            6
    ++#define FTS5_LCP                              7
    ++#define FTS5_RCP                              8
    ++#define FTS5_STRING                           9
    ++#define FTS5_LP                              10
    ++#define FTS5_RP                              11
    ++#define FTS5_CARET                           12
    ++#define FTS5_COMMA                           13
    ++#define FTS5_PLUS                            14
    ++#define FTS5_STAR                            15
    ++
    ++/*
    ++** 2000-05-29
    ++**
    ++** 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.
    ++**
    ++*************************************************************************
    ++** Driver template for the LEMON parser generator.
    ++**
    ++** The "lemon" program processes an LALR(1) input grammar file, then uses
    ++** this template to construct a parser.  The "lemon" program inserts text
    ++** at each "%%" line.  Also, any "P-a-r-s-e" identifer prefix (without the
    ++** interstitial "-" characters) contained in this template is changed into
    ++** the value of the %name directive from the grammar.  Otherwise, the content
    ++** of this template is copied straight through into the generate parser
    ++** source file.
    + **
    +-** This version of "lempar.c" is modified, slightly, for use by SQLite.
    +-** The only modifications are the addition of a couple of NEVER()
    +-** macros to disable tests that are needed in the case of a general
    +-** LALR(1) grammar but which are always false in the
    +-** specific grammar used by SQLite.
    ++** The following is the concatenation of all %include directives from the
    ++** input grammar file:
    + */
    +-/* First off, code is included that follows the "include" declaration
    +-** in the input grammar file. */
    + /* #include <stdio.h> */
    ++/************ Begin %include sections from the grammar ************************/
    + 
    ++/* #include "fts5Int.h" */
    ++/* #include "fts5parse.h" */
    + 
    + /*
    + ** Disable all error recovery processing in the parser push-down
    +@@ -166927,44 +187466,54 @@ static int sqlite3Fts5UnicodeFold(int c, int bRemoveDiacritic);
    + */
    + #define fts5yytestcase(X) testcase(X)
    + 
    +-/* Next is all token values, in a form suitable for use by makeheaders.
    +-** This section will be null unless lemon is run with the -m switch.
    +-*/
    +-/* 
    +-** These constants (all generated automatically by the parser generator)
    +-** specify the various kinds of tokens (terminals) that the parser
    +-** understands. 
    +-**
    +-** Each symbol here is a terminal symbol in the grammar.
    ++/*
    ++** Indicate that sqlite3ParserFree() will never be called with a null
    ++** pointer.
    + */
    +-/* Make sure the INTERFACE macro is defined.
    ++#define fts5YYPARSEFREENOTNULL 1
    ++
    ++/*
    ++** Alternative datatype for the argument to the malloc() routine passed
    ++** into sqlite3ParserAlloc().  The default is size_t.
    + */
    +-#ifndef INTERFACE
    +-# define INTERFACE 1
    +-#endif
    +-/* The next thing included is series of defines which control
    ++#define fts5YYMALLOCARGTYPE  u64
    ++
    ++/**************** End of %include directives **********************************/
    ++/* These constants specify the various numeric values for terminal symbols
    ++** in a format understandable to "makeheaders".  This section is blank unless
    ++** "lemon" is run with the "-m" command-line option.
    ++***************** Begin makeheaders token definitions *************************/
    ++/**************** End makeheaders token definitions ***************************/
    ++
    ++/* The next sections is a series of control #defines.
    + ** various aspects of the generated parser.
    +-**    fts5YYCODETYPE         is the data type used for storing terminal
    +-**                       and nonterminal numbers.  "unsigned char" is
    +-**                       used if there are fewer than 250 terminals
    +-**                       and nonterminals.  "int" is used otherwise.
    +-**    fts5YYNOCODE           is a number of type fts5YYCODETYPE which corresponds
    +-**                       to no legal terminal or nonterminal number.  This
    +-**                       number is used to fill in empty slots of the hash 
    +-**                       table.
    ++**    fts5YYCODETYPE         is the data type used to store the integer codes
    ++**                       that represent terminal and non-terminal symbols.
    ++**                       "unsigned char" is used if there are fewer than
    ++**                       256 symbols.  Larger types otherwise.
    ++**    fts5YYNOCODE           is a number of type fts5YYCODETYPE that is not used for
    ++**                       any terminal or nonterminal symbol.
    + **    fts5YYFALLBACK         If defined, this indicates that one or more tokens
    +-**                       have fall-back values which should be used if the
    +-**                       original value of the token will not parse.
    +-**    fts5YYACTIONTYPE       is the data type used for storing terminal
    +-**                       and nonterminal numbers.  "unsigned char" is
    +-**                       used if there are fewer than 250 rules and
    +-**                       states combined.  "int" is used otherwise.
    +-**    sqlite3Fts5ParserFTS5TOKENTYPE     is the data type used for minor tokens given 
    +-**                       directly to the parser from the tokenizer.
    +-**    fts5YYMINORTYPE        is the data type used for all minor tokens.
    ++**                       (also known as: "terminal symbols") have fall-back
    ++**                       values which should be used if the original symbol
    ++**                       would not parse.  This permits keywords to sometimes
    ++**                       be used as identifiers, for example.
    ++**    fts5YYACTIONTYPE       is the data type used for "action codes" - numbers
    ++**                       that indicate what to do in response to the next
    ++**                       token.
    ++**    sqlite3Fts5ParserFTS5TOKENTYPE     is the data type used for minor type for terminal
    ++**                       symbols.  Background: A "minor type" is a semantic
    ++**                       value associated with a terminal or non-terminal
    ++**                       symbols.  For example, for an "ID" terminal symbol,
    ++**                       the minor type might be the name of the identifier.
    ++**                       Each non-terminal can have a different minor type.
    ++**                       Terminal symbols all have the same minor type, though.
    ++**                       This macros defines the minor type for terminal 
    ++**                       symbols.
    ++**    fts5YYMINORTYPE        is the data type used for all minor types.
    + **                       This is typically a union of many types, one of
    + **                       which is sqlite3Fts5ParserFTS5TOKENTYPE.  The entry in the union
    +-**                       for base tokens is called "fts5yy0".
    ++**                       for terminal symbols is called "fts5yy0".
    + **    fts5YYSTACKDEPTH       is the maximum depth of the parser's stack.  If
    + **                       zero the stack is dynamically sized using realloc()
    + **    sqlite3Fts5ParserARG_SDECL     A static variable declaration for the %extra_argument
    +@@ -166975,26 +187524,32 @@ static int sqlite3Fts5UnicodeFold(int c, int bRemoveDiacritic);
    + **                       defined, then do no error processing.
    + **    fts5YYNSTATE           the combined number of states.
    + **    fts5YYNRULE            the number of rules in the grammar
    ++**    fts5YYNFTS5TOKEN           Number of terminal symbols
    + **    fts5YY_MAX_SHIFT       Maximum value for shift actions
    + **    fts5YY_MIN_SHIFTREDUCE Minimum value for shift-reduce actions
    + **    fts5YY_MAX_SHIFTREDUCE Maximum value for shift-reduce actions
    +-**    fts5YY_MIN_REDUCE      Maximum value for reduce actions
    + **    fts5YY_ERROR_ACTION    The fts5yy_action[] code for syntax error
    + **    fts5YY_ACCEPT_ACTION   The fts5yy_action[] code for accept
    + **    fts5YY_NO_ACTION       The fts5yy_action[] code for no-op
    ++**    fts5YY_MIN_REDUCE      Minimum value for reduce actions
    ++**    fts5YY_MAX_REDUCE      Maximum value for reduce actions
    + */
    ++#ifndef INTERFACE
    ++# define INTERFACE 1
    ++#endif
    ++/************* Begin control #defines *****************************************/
    + #define fts5YYCODETYPE unsigned char
    +-#define fts5YYNOCODE 27
    ++#define fts5YYNOCODE 29
    + #define fts5YYACTIONTYPE unsigned char
    + #define sqlite3Fts5ParserFTS5TOKENTYPE Fts5Token
    + typedef union {
    +   int fts5yyinit;
    +   sqlite3Fts5ParserFTS5TOKENTYPE fts5yy0;
    +-  Fts5Colset* fts5yy3;
    ++  int fts5yy4;
    +   Fts5ExprPhrase* fts5yy11;
    +-  Fts5ExprNode* fts5yy18;
    +-  int fts5yy20;
    +-  Fts5ExprNearset* fts5yy26;
    ++  Fts5ExprNearset* fts5yy14;
    ++  Fts5Colset* fts5yy43;
    ++  Fts5ExprNode* fts5yy54;
    + } fts5YYMINORTYPE;
    + #ifndef fts5YYSTACKDEPTH
    + #define fts5YYSTACKDEPTH 100
    +@@ -167003,20 +187558,18 @@ typedef union {
    + #define sqlite3Fts5ParserARG_PDECL ,Fts5Parse *pParse
    + #define sqlite3Fts5ParserARG_FETCH Fts5Parse *pParse = fts5yypParser->pParse
    + #define sqlite3Fts5ParserARG_STORE fts5yypParser->pParse = pParse
    +-#define fts5YYNSTATE             26
    +-#define fts5YYNRULE              24
    +-#define fts5YY_MAX_SHIFT         25
    +-#define fts5YY_MIN_SHIFTREDUCE   40
    +-#define fts5YY_MAX_SHIFTREDUCE   63
    +-#define fts5YY_MIN_REDUCE        64
    +-#define fts5YY_MAX_REDUCE        87
    +-#define fts5YY_ERROR_ACTION      88
    +-#define fts5YY_ACCEPT_ACTION     89
    +-#define fts5YY_NO_ACTION         90
    +-
    +-/* The fts5yyzerominor constant is used to initialize instances of
    +-** fts5YYMINORTYPE objects to zero. */
    +-static const fts5YYMINORTYPE fts5yyzerominor = { 0 };
    ++#define fts5YYNSTATE             35
    ++#define fts5YYNRULE              28
    ++#define fts5YYNFTS5TOKEN             16
    ++#define fts5YY_MAX_SHIFT         34
    ++#define fts5YY_MIN_SHIFTREDUCE   52
    ++#define fts5YY_MAX_SHIFTREDUCE   79
    ++#define fts5YY_ERROR_ACTION      80
    ++#define fts5YY_ACCEPT_ACTION     81
    ++#define fts5YY_NO_ACTION         82
    ++#define fts5YY_MIN_REDUCE        83
    ++#define fts5YY_MAX_REDUCE        110
    ++/************* End control #defines *******************************************/
    + 
    + /* Define the fts5yytestcase() macro to be a no-op if is not already defined
    + ** otherwise.
    +@@ -167045,9 +187598,6 @@ static const fts5YYMINORTYPE fts5yyzerominor = { 0 };
    + **   N between fts5YY_MIN_SHIFTREDUCE       Shift to an arbitrary state then
    + **     and fts5YY_MAX_SHIFTREDUCE           reduce by rule N-fts5YY_MIN_SHIFTREDUCE.
    + **
    +-**   N between fts5YY_MIN_REDUCE            Reduce by rule N-fts5YY_MIN_REDUCE
    +-**     and fts5YY_MAX_REDUCE
    +-
    + **   N == fts5YY_ERROR_ACTION               A syntax error has occurred.
    + **
    + **   N == fts5YY_ACCEPT_ACTION              The parser accepts its input.
    +@@ -167055,21 +187605,22 @@ static const fts5YYMINORTYPE fts5yyzerominor = { 0 };
    + **   N == fts5YY_NO_ACTION                  No such action.  Denotes unused
    + **                                      slots in the fts5yy_action[] table.
    + **
    ++**   N between fts5YY_MIN_REDUCE            Reduce by rule N-fts5YY_MIN_REDUCE
    ++**     and fts5YY_MAX_REDUCE
    ++**
    + ** The action table is constructed as a single large table named fts5yy_action[].
    +-** Given state S and lookahead X, the action is computed as
    ++** Given state S and lookahead X, the action is computed as either:
    + **
    +-**      fts5yy_action[ fts5yy_shift_ofst[S] + X ]
    ++**    (A)   N = fts5yy_action[ fts5yy_shift_ofst[S] + X ]
    ++**    (B)   N = fts5yy_default[S]
    + **
    +-** If the index value fts5yy_shift_ofst[S]+X is out of range or if the value
    +-** fts5yy_lookahead[fts5yy_shift_ofst[S]+X] is not equal to X or if fts5yy_shift_ofst[S]
    +-** is equal to fts5YY_SHIFT_USE_DFLT, it means that the action is not in the table
    +-** and that fts5yy_default[S] should be used instead.  
    ++** The (A) formula is preferred.  The B formula is used instead if
    ++** fts5yy_lookahead[fts5yy_shift_ofst[S]+X] is not equal to X.
    + **
    +-** The formula above is for computing the action when the lookahead is
    ++** The formulas above are for computing the action when the lookahead is
    + ** a terminal symbol.  If the lookahead is a non-terminal (as occurs after
    + ** a reduce action) then the fts5yy_reduce_ofst[] array is used in place of
    +-** the fts5yy_shift_ofst[] array and fts5YY_REDUCE_USE_DFLT is used in place of
    +-** fts5YY_SHIFT_USE_DFLT.
    ++** the fts5yy_shift_ofst[] array.
    + **
    + ** The following are the tables generated in this section:
    + **
    +@@ -167081,53 +187632,63 @@ static const fts5YYMINORTYPE fts5yyzerominor = { 0 };
    + **  fts5yy_reduce_ofst[]   For each state, the offset into fts5yy_action for
    + **                     shifting non-terminals after a reduce.
    + **  fts5yy_default[]       Default action for each state.
    +-*/
    +-#define fts5YY_ACTTAB_COUNT (78)
    ++**
    ++*********** Begin parsing tables **********************************************/
    ++#define fts5YY_ACTTAB_COUNT (105)
    + static const fts5YYACTIONTYPE fts5yy_action[] = {
    +- /*     0 */    89,   15,   46,    5,   48,   24,   12,   19,   23,   14,
    +- /*    10 */    46,    5,   48,   24,   20,   21,   23,   43,   46,    5,
    +- /*    20 */    48,   24,    6,   18,   23,   17,   46,    5,   48,   24,
    +- /*    30 */    75,    7,   23,   25,   46,    5,   48,   24,   62,   47,
    +- /*    40 */    23,   48,   24,    7,   11,   23,    9,    3,    4,    2,
    +- /*    50 */    62,   50,   52,   44,   64,    3,    4,    2,   49,    4,
    +- /*    60 */     2,    1,   23,   11,   16,    9,   12,    2,   10,   61,
    +- /*    70 */    53,   59,   62,   60,   22,   13,   55,    8,
    ++ /*     0 */    81,   20,   96,    6,   28,   99,   98,   26,   26,   18,
    ++ /*    10 */    96,    6,   28,   17,   98,   56,   26,   19,   96,    6,
    ++ /*    20 */    28,   14,   98,  108,   26,   92,   96,    6,   28,   25,
    ++ /*    30 */    98,   78,   26,   21,   96,    6,   28,  107,   98,   58,
    ++ /*    40 */    26,   29,   96,    6,   28,   32,   98,   22,   26,   24,
    ++ /*    50 */    16,   23,   11,    1,   14,   13,   24,   16,   31,   11,
    ++ /*    60 */     3,   97,   13,   27,    8,   98,   82,   26,    7,    4,
    ++ /*    70 */     5,    3,    4,    5,    3,   83,    4,    5,    3,   63,
    ++ /*    80 */    33,   34,   62,   12,    2,   86,   13,   10,   12,   71,
    ++ /*    90 */    10,   13,   78,    5,    3,   78,    9,   30,   75,   82,
    ++ /*   100 */    54,   57,   53,   57,   15,
    + };
    + static const fts5YYCODETYPE fts5yy_lookahead[] = {
    +- /*     0 */    15,   16,   17,   18,   19,   20,   10,   11,   23,   16,
    +- /*    10 */    17,   18,   19,   20,   23,   24,   23,   16,   17,   18,
    +- /*    20 */    19,   20,   22,   23,   23,   16,   17,   18,   19,   20,
    +- /*    30 */     5,    6,   23,   16,   17,   18,   19,   20,   13,   17,
    +- /*    40 */    23,   19,   20,    6,    8,   23,   10,    1,    2,    3,
    +- /*    50 */    13,    9,   10,    7,    0,    1,    2,    3,   19,    2,
    +- /*    60 */     3,    6,   23,    8,   21,   10,   10,    3,   10,   25,
    +- /*    70 */    10,   10,   13,   25,   12,   10,    7,    5,
    ++ /*     0 */    17,   18,   19,   20,   21,   23,   23,   25,   25,   18,
    ++ /*    10 */    19,   20,   21,    7,   23,    9,   25,   18,   19,   20,
    ++ /*    20 */    21,    9,   23,   27,   25,   18,   19,   20,   21,   25,
    ++ /*    30 */    23,   15,   25,   18,   19,   20,   21,   27,   23,    9,
    ++ /*    40 */    25,   18,   19,   20,   21,   14,   23,   22,   25,    6,
    ++ /*    50 */     7,   22,    9,   10,    9,   12,    6,    7,   13,    9,
    ++ /*    60 */     3,   19,   12,   21,    5,   23,   28,   25,    5,    1,
    ++ /*    70 */     2,    3,    1,    2,    3,    0,    1,    2,    3,   11,
    ++ /*    80 */    25,   26,   11,    9,   10,    5,   12,   10,    9,   11,
    ++ /*    90 */    10,   12,   15,    2,    3,   15,   24,   25,    9,   28,
    ++ /*   100 */     8,    9,    8,    9,    9,   28,   28,   28,   28,   28,
    ++ /*   110 */    28,   28,   28,   28,   28,   28,   28,   28,   28,   28,
    ++ /*   120 */    28,
    + };
    +-#define fts5YY_SHIFT_USE_DFLT (-5)
    +-#define fts5YY_SHIFT_COUNT (25)
    +-#define fts5YY_SHIFT_MIN   (-4)
    +-#define fts5YY_SHIFT_MAX   (72)
    +-static const signed char fts5yy_shift_ofst[] = {
    +- /*     0 */    55,   55,   55,   55,   55,   36,   -4,   56,   58,   25,
    +- /*    10 */    37,   60,   59,   59,   46,   54,   42,   57,   62,   61,
    +- /*    20 */    62,   69,   65,   62,   72,   64,
    ++#define fts5YY_SHIFT_COUNT    (34)
    ++#define fts5YY_SHIFT_MIN      (0)
    ++#define fts5YY_SHIFT_MAX      (95)
    ++static const unsigned char fts5yy_shift_ofst[] = {
    ++ /*     0 */    43,   43,   43,   43,   43,   43,   50,   74,   79,   45,
    ++ /*    10 */    12,   80,   77,   12,   16,   16,   30,   30,   68,   71,
    ++ /*    20 */    75,   91,   92,   94,    6,   31,   31,   59,   63,   57,
    ++ /*    30 */    31,   89,   95,   31,   78,
    + };
    +-#define fts5YY_REDUCE_USE_DFLT (-16)
    +-#define fts5YY_REDUCE_COUNT (13)
    +-#define fts5YY_REDUCE_MIN   (-15)
    +-#define fts5YY_REDUCE_MAX   (48)
    ++#define fts5YY_REDUCE_COUNT (17)
    ++#define fts5YY_REDUCE_MIN   (-18)
    ++#define fts5YY_REDUCE_MAX   (72)
    + static const signed char fts5yy_reduce_ofst[] = {
    +- /*     0 */   -15,   -7,    1,    9,   17,   22,   -9,    0,   39,   44,
    +- /*    10 */    44,   43,   44,   48,
    ++ /*     0 */   -17,   -9,   -1,    7,   15,   23,   42,  -18,  -18,   55,
    ++ /*    10 */    72,   -4,   -4,    4,   -4,   10,   25,   29,
    + };
    + static const fts5YYACTIONTYPE fts5yy_default[] = {
    +- /*     0 */    88,   88,   88,   88,   88,   69,   82,   88,   88,   87,
    +- /*    10 */    87,   88,   87,   87,   88,   88,   88,   66,   80,   88,
    +- /*    20 */    81,   88,   88,   78,   88,   65,
    ++ /*     0 */    80,   80,   80,   80,   80,   80,   95,   80,   80,  105,
    ++ /*    10 */    80,  110,  110,   80,  110,  110,   80,   80,   80,   80,
    ++ /*    20 */    80,   91,   80,   80,   80,  101,  100,   80,   80,   90,
    ++ /*    30 */   103,   80,   80,  104,   80,
    + };
    ++/********** End of lemon-generated parsing tables *****************************/
    + 
    +-/* The next table maps tokens into fallback tokens.  If a construct
    +-** like the following:
    ++/* The next table maps tokens (terminal symbols) into fallback tokens.  
    ++** If a construct like the following:
    + ** 
    + **      %fallback ID X Y Z.
    + **
    +@@ -167135,6 +187696,10 @@ static const fts5YYACTIONTYPE fts5yy_default[] = {
    + ** and Z.  Whenever one of the tokens X, Y, or Z is input to the parser
    + ** but it does not parse, the type of the token is changed to ID and
    + ** the parse is retried before an error is thrown.
    ++**
    ++** This feature can be used, for example, to cause some keywords in a language
    ++** to revert to identifiers if they keyword does not apply in the context where
    ++** it appears.
    + */
    + #ifdef fts5YYFALLBACK
    + static const fts5YYCODETYPE fts5yyFallback[] = {
    +@@ -167169,17 +187734,21 @@ typedef struct fts5yyStackEntry fts5yyStackEntry;
    + /* The state of the parser is completely contained in an instance of
    + ** the following structure */
    + struct fts5yyParser {
    +-  int fts5yyidx;                    /* Index of top element in stack */
    ++  fts5yyStackEntry *fts5yytos;          /* Pointer to top element of the stack */
    + #ifdef fts5YYTRACKMAXSTACKDEPTH
    +-  int fts5yyidxMax;                 /* Maximum value of fts5yyidx */
    ++  int fts5yyhwm;                    /* High-water mark of the stack */
    + #endif
    ++#ifndef fts5YYNOERRORRECOVERY
    +   int fts5yyerrcnt;                 /* Shifts left before out of the error */
    ++#endif
    +   sqlite3Fts5ParserARG_SDECL                /* A place to hold %extra_argument */
    + #if fts5YYSTACKDEPTH<=0
    +   int fts5yystksz;                  /* Current side of the stack */
    +   fts5yyStackEntry *fts5yystack;        /* The parser's stack */
    ++  fts5yyStackEntry fts5yystk0;          /* First stack entry */
    + #else
    +   fts5yyStackEntry fts5yystack[fts5YYSTACKDEPTH];  /* The parser's stack */
    ++  fts5yyStackEntry *fts5yystackEnd;            /* Last entry in the stack */
    + #endif
    + };
    + typedef struct fts5yyParser fts5yyParser;
    +@@ -167216,75 +187785,147 @@ static void sqlite3Fts5ParserTrace(FILE *TraceFILE, char *zTracePrompt){
    + }
    + #endif /* NDEBUG */
    + 
    +-#ifndef NDEBUG
    ++#if defined(fts5YYCOVERAGE) || !defined(NDEBUG)
    + /* For tracing shifts, the names of all terminals and nonterminals
    + ** are required.  The following table supplies these names */
    + static const char *const fts5yyTokenName[] = { 
    +-  "$",             "OR",            "AND",           "NOT",         
    +-  "TERM",          "COLON",         "LP",            "RP",          
    +-  "LCP",           "RCP",           "STRING",        "COMMA",       
    +-  "PLUS",          "STAR",          "error",         "input",       
    +-  "expr",          "cnearset",      "exprlist",      "nearset",     
    +-  "colset",        "colsetlist",    "nearphrases",   "phrase",      
    +-  "neardist_opt",  "star_opt",    
    ++  /*    0 */ "$",
    ++  /*    1 */ "OR",
    ++  /*    2 */ "AND",
    ++  /*    3 */ "NOT",
    ++  /*    4 */ "TERM",
    ++  /*    5 */ "COLON",
    ++  /*    6 */ "MINUS",
    ++  /*    7 */ "LCP",
    ++  /*    8 */ "RCP",
    ++  /*    9 */ "STRING",
    ++  /*   10 */ "LP",
    ++  /*   11 */ "RP",
    ++  /*   12 */ "CARET",
    ++  /*   13 */ "COMMA",
    ++  /*   14 */ "PLUS",
    ++  /*   15 */ "STAR",
    ++  /*   16 */ "error",
    ++  /*   17 */ "input",
    ++  /*   18 */ "expr",
    ++  /*   19 */ "cnearset",
    ++  /*   20 */ "exprlist",
    ++  /*   21 */ "colset",
    ++  /*   22 */ "colsetlist",
    ++  /*   23 */ "nearset",
    ++  /*   24 */ "nearphrases",
    ++  /*   25 */ "phrase",
    ++  /*   26 */ "neardist_opt",
    ++  /*   27 */ "star_opt",
    + };
    +-#endif /* NDEBUG */
    ++#endif /* defined(fts5YYCOVERAGE) || !defined(NDEBUG) */
    + 
    + #ifndef NDEBUG
    + /* For tracing reduce actions, the names of all rules are required.
    + */
    + static const char *const fts5yyRuleName[] = {
    +  /*   0 */ "input ::= expr",
    +- /*   1 */ "expr ::= expr AND expr",
    +- /*   2 */ "expr ::= expr OR expr",
    +- /*   3 */ "expr ::= expr NOT expr",
    +- /*   4 */ "expr ::= LP expr RP",
    +- /*   5 */ "expr ::= exprlist",
    +- /*   6 */ "exprlist ::= cnearset",
    +- /*   7 */ "exprlist ::= exprlist cnearset",
    +- /*   8 */ "cnearset ::= nearset",
    +- /*   9 */ "cnearset ::= colset COLON nearset",
    +- /*  10 */ "colset ::= LCP colsetlist RCP",
    +- /*  11 */ "colset ::= STRING",
    +- /*  12 */ "colsetlist ::= colsetlist STRING",
    +- /*  13 */ "colsetlist ::= STRING",
    +- /*  14 */ "nearset ::= phrase",
    +- /*  15 */ "nearset ::= STRING LP nearphrases neardist_opt RP",
    +- /*  16 */ "nearphrases ::= phrase",
    +- /*  17 */ "nearphrases ::= nearphrases phrase",
    +- /*  18 */ "neardist_opt ::=",
    +- /*  19 */ "neardist_opt ::= COMMA STRING",
    +- /*  20 */ "phrase ::= phrase PLUS STRING star_opt",
    +- /*  21 */ "phrase ::= STRING star_opt",
    +- /*  22 */ "star_opt ::= STAR",
    +- /*  23 */ "star_opt ::=",
    ++ /*   1 */ "colset ::= MINUS LCP colsetlist RCP",
    ++ /*   2 */ "colset ::= LCP colsetlist RCP",
    ++ /*   3 */ "colset ::= STRING",
    ++ /*   4 */ "colset ::= MINUS STRING",
    ++ /*   5 */ "colsetlist ::= colsetlist STRING",
    ++ /*   6 */ "colsetlist ::= STRING",
    ++ /*   7 */ "expr ::= expr AND expr",
    ++ /*   8 */ "expr ::= expr OR expr",
    ++ /*   9 */ "expr ::= expr NOT expr",
    ++ /*  10 */ "expr ::= colset COLON LP expr RP",
    ++ /*  11 */ "expr ::= LP expr RP",
    ++ /*  12 */ "expr ::= exprlist",
    ++ /*  13 */ "exprlist ::= cnearset",
    ++ /*  14 */ "exprlist ::= exprlist cnearset",
    ++ /*  15 */ "cnearset ::= nearset",
    ++ /*  16 */ "cnearset ::= colset COLON nearset",
    ++ /*  17 */ "nearset ::= phrase",
    ++ /*  18 */ "nearset ::= CARET phrase",
    ++ /*  19 */ "nearset ::= STRING LP nearphrases neardist_opt RP",
    ++ /*  20 */ "nearphrases ::= phrase",
    ++ /*  21 */ "nearphrases ::= nearphrases phrase",
    ++ /*  22 */ "neardist_opt ::=",
    ++ /*  23 */ "neardist_opt ::= COMMA STRING",
    ++ /*  24 */ "phrase ::= phrase PLUS STRING star_opt",
    ++ /*  25 */ "phrase ::= STRING star_opt",
    ++ /*  26 */ "star_opt ::= STAR",
    ++ /*  27 */ "star_opt ::=",
    + };
    + #endif /* NDEBUG */
    + 
    + 
    + #if fts5YYSTACKDEPTH<=0
    + /*
    +-** Try to increase the size of the parser stack.
    ++** Try to increase the size of the parser stack.  Return the number
    ++** of errors.  Return 0 on success.
    + */
    +-static void fts5yyGrowStack(fts5yyParser *p){
    ++static int fts5yyGrowStack(fts5yyParser *p){
    +   int newSize;
    ++  int idx;
    +   fts5yyStackEntry *pNew;
    + 
    +   newSize = p->fts5yystksz*2 + 100;
    +-  pNew = realloc(p->fts5yystack, newSize*sizeof(pNew[0]));
    ++  idx = p->fts5yytos ? (int)(p->fts5yytos - p->fts5yystack) : 0;
    ++  if( p->fts5yystack==&p->fts5yystk0 ){
    ++    pNew = malloc(newSize*sizeof(pNew[0]));
    ++    if( pNew ) pNew[0] = p->fts5yystk0;
    ++  }else{
    ++    pNew = realloc(p->fts5yystack, newSize*sizeof(pNew[0]));
    ++  }
    +   if( pNew ){
    +     p->fts5yystack = pNew;
    +-    p->fts5yystksz = newSize;
    ++    p->fts5yytos = &p->fts5yystack[idx];
    + #ifndef NDEBUG
    +     if( fts5yyTraceFILE ){
    +-      fprintf(fts5yyTraceFILE,"%sStack grows to %d entries!\n",
    +-              fts5yyTracePrompt, p->fts5yystksz);
    ++      fprintf(fts5yyTraceFILE,"%sStack grows from %d to %d entries.\n",
    ++              fts5yyTracePrompt, p->fts5yystksz, newSize);
    +     }
    + #endif
    ++    p->fts5yystksz = newSize;
    +   }
    ++  return pNew==0; 
    + }
    + #endif
    + 
    ++/* Datatype of the argument to the memory allocated passed as the
    ++** second argument to sqlite3Fts5ParserAlloc() below.  This can be changed by
    ++** putting an appropriate #define in the %include section of the input
    ++** grammar.
    ++*/
    ++#ifndef fts5YYMALLOCARGTYPE
    ++# define fts5YYMALLOCARGTYPE size_t
    ++#endif
    ++
    ++/* Initialize a new parser that has already been allocated.
    ++*/
    ++static void sqlite3Fts5ParserInit(void *fts5yypParser){
    ++  fts5yyParser *pParser = (fts5yyParser*)fts5yypParser;
    ++#ifdef fts5YYTRACKMAXSTACKDEPTH
    ++  pParser->fts5yyhwm = 0;
    ++#endif
    ++#if fts5YYSTACKDEPTH<=0
    ++  pParser->fts5yytos = NULL;
    ++  pParser->fts5yystack = NULL;
    ++  pParser->fts5yystksz = 0;
    ++  if( fts5yyGrowStack(pParser) ){
    ++    pParser->fts5yystack = &pParser->fts5yystk0;
    ++    pParser->fts5yystksz = 1;
    ++  }
    ++#endif
    ++#ifndef fts5YYNOERRORRECOVERY
    ++  pParser->fts5yyerrcnt = -1;
    ++#endif
    ++  pParser->fts5yytos = pParser->fts5yystack;
    ++  pParser->fts5yystack[0].stateno = 0;
    ++  pParser->fts5yystack[0].major = 0;
    ++#if fts5YYSTACKDEPTH>0
    ++  pParser->fts5yystackEnd = &pParser->fts5yystack[fts5YYSTACKDEPTH-1];
    ++#endif
    ++}
    ++
    ++#ifndef sqlite3Fts5Parser_ENGINEALWAYSONSTACK
    + /* 
    + ** This function allocates a new parser.
    + ** The only argument is a pointer to a function which works like
    +@@ -167297,27 +187938,21 @@ static void fts5yyGrowStack(fts5yyParser *p){
    + ** A pointer to a parser.  This pointer is used in subsequent calls
    + ** to sqlite3Fts5Parser and sqlite3Fts5ParserFree.
    + */
    +-static void *sqlite3Fts5ParserAlloc(void *(*mallocProc)(u64)){
    ++static void *sqlite3Fts5ParserAlloc(void *(*mallocProc)(fts5YYMALLOCARGTYPE)){
    +   fts5yyParser *pParser;
    +-  pParser = (fts5yyParser*)(*mallocProc)( (u64)sizeof(fts5yyParser) );
    +-  if( pParser ){
    +-    pParser->fts5yyidx = -1;
    +-#ifdef fts5YYTRACKMAXSTACKDEPTH
    +-    pParser->fts5yyidxMax = 0;
    +-#endif
    +-#if fts5YYSTACKDEPTH<=0
    +-    pParser->fts5yystack = NULL;
    +-    pParser->fts5yystksz = 0;
    +-    fts5yyGrowStack(pParser);
    +-#endif
    +-  }
    ++  pParser = (fts5yyParser*)(*mallocProc)( (fts5YYMALLOCARGTYPE)sizeof(fts5yyParser) );
    ++  if( pParser ) sqlite3Fts5ParserInit(pParser);
    +   return pParser;
    + }
    ++#endif /* sqlite3Fts5Parser_ENGINEALWAYSONSTACK */
    + 
    +-/* The following function deletes the value associated with a
    +-** symbol.  The symbol can be either a terminal or nonterminal.
    +-** "fts5yymajor" is the symbol code, and "fts5yypminor" is a pointer to
    +-** the value.
    ++
    ++/* The following function deletes the "minor type" or semantic value
    ++** associated with a symbol.  The symbol can be either a terminal
    ++** or nonterminal. "fts5yymajor" is the symbol code, and "fts5yypminor" is
    ++** a pointer to the value to be deleted.  The code used to do the 
    ++** deletions is derived from the %destructor and/or %token_destructor
    ++** directives of the input grammar.
    + */
    + static void fts5yy_destructor(
    +   fts5yyParser *fts5yypParser,    /* The parser */
    +@@ -167333,38 +187968,40 @@ static void fts5yy_destructor(
    +     ** being destroyed before it is finished parsing.
    +     **
    +     ** Note: during a reduce, the only symbols destroyed are those
    +-    ** which appear on the RHS of the rule, but which are not used
    ++    ** which appear on the RHS of the rule, but which are *not* used
    +     ** inside the C code.
    +     */
    +-    case 15: /* input */
    ++/********* Begin destructor definitions ***************************************/
    ++    case 17: /* input */
    + {
    +  (void)pParse; 
    + }
    +       break;
    +-    case 16: /* expr */
    +-    case 17: /* cnearset */
    +-    case 18: /* exprlist */
    ++    case 18: /* expr */
    ++    case 19: /* cnearset */
    ++    case 20: /* exprlist */
    + {
    +- sqlite3Fts5ParseNodeFree((fts5yypminor->fts5yy18)); 
    ++ sqlite3Fts5ParseNodeFree((fts5yypminor->fts5yy54)); 
    + }
    +       break;
    +-    case 19: /* nearset */
    +-    case 22: /* nearphrases */
    ++    case 21: /* colset */
    ++    case 22: /* colsetlist */
    + {
    +- sqlite3Fts5ParseNearsetFree((fts5yypminor->fts5yy26)); 
    ++ sqlite3_free((fts5yypminor->fts5yy43)); 
    + }
    +       break;
    +-    case 20: /* colset */
    +-    case 21: /* colsetlist */
    ++    case 23: /* nearset */
    ++    case 24: /* nearphrases */
    + {
    +- sqlite3_free((fts5yypminor->fts5yy3)); 
    ++ sqlite3Fts5ParseNearsetFree((fts5yypminor->fts5yy14)); 
    + }
    +       break;
    +-    case 23: /* phrase */
    ++    case 25: /* phrase */
    + {
    +  sqlite3Fts5ParsePhraseFree((fts5yypminor->fts5yy11)); 
    + }
    +       break;
    ++/********* End destructor definitions *****************************************/
    +     default:  break;   /* If no destructor action specified: do nothing */
    +   }
    + }
    +@@ -167374,55 +188011,53 @@ static void fts5yy_destructor(
    + **
    + ** If there is a destructor routine associated with the token which
    + ** is popped from the stack, then call it.
    +-**
    +-** Return the major token number for the symbol popped.
    + */
    +-static int fts5yy_pop_parser_stack(fts5yyParser *pParser){
    +-  fts5YYCODETYPE fts5yymajor;
    +-  fts5yyStackEntry *fts5yytos = &pParser->fts5yystack[pParser->fts5yyidx];
    +-
    +-  /* There is no mechanism by which the parser stack can be popped below
    +-  ** empty in SQLite.  */
    +-  assert( pParser->fts5yyidx>=0 );
    ++static void fts5yy_pop_parser_stack(fts5yyParser *pParser){
    ++  fts5yyStackEntry *fts5yytos;
    ++  assert( pParser->fts5yytos!=0 );
    ++  assert( pParser->fts5yytos > pParser->fts5yystack );
    ++  fts5yytos = pParser->fts5yytos--;
    + #ifndef NDEBUG
    +-  if( fts5yyTraceFILE && pParser->fts5yyidx>=0 ){
    ++  if( fts5yyTraceFILE ){
    +     fprintf(fts5yyTraceFILE,"%sPopping %s\n",
    +       fts5yyTracePrompt,
    +       fts5yyTokenName[fts5yytos->major]);
    +   }
    + #endif
    +-  fts5yymajor = fts5yytos->major;
    +-  fts5yy_destructor(pParser, fts5yymajor, &fts5yytos->minor);
    +-  pParser->fts5yyidx--;
    +-  return fts5yymajor;
    ++  fts5yy_destructor(pParser, fts5yytos->major, &fts5yytos->minor);
    ++}
    ++
    ++/*
    ++** Clear all secondary memory allocations from the parser
    ++*/
    ++static void sqlite3Fts5ParserFinalize(void *p){
    ++  fts5yyParser *pParser = (fts5yyParser*)p;
    ++  while( pParser->fts5yytos>pParser->fts5yystack ) fts5yy_pop_parser_stack(pParser);
    ++#if fts5YYSTACKDEPTH<=0
    ++  if( pParser->fts5yystack!=&pParser->fts5yystk0 ) free(pParser->fts5yystack);
    ++#endif
    + }
    + 
    ++#ifndef sqlite3Fts5Parser_ENGINEALWAYSONSTACK
    + /* 
    +-** Deallocate and destroy a parser.  Destructors are all called for
    ++** Deallocate and destroy a parser.  Destructors are called for
    + ** all stack elements before shutting the parser down.
    + **
    +-** Inputs:
    +-** <ul>
    +-** <li>  A pointer to the parser.  This should be a pointer
    +-**       obtained from sqlite3Fts5ParserAlloc.
    +-** <li>  A pointer to a function used to reclaim memory obtained
    +-**       from malloc.
    +-** </ul>
    ++** If the fts5YYPARSEFREENEVERNULL macro exists (for example because it
    ++** is defined in a %include section of the input grammar) then it is
    ++** assumed that the input pointer is never NULL.
    + */
    + static void sqlite3Fts5ParserFree(
    +   void *p,                    /* The parser to be deleted */
    +   void (*freeProc)(void*)     /* Function used to reclaim memory */
    + ){
    +-  fts5yyParser *pParser = (fts5yyParser*)p;
    +-  /* In SQLite, we never try to destroy a parser that was not successfully
    +-  ** created in the first place. */
    +-  if( NEVER(pParser==0) ) return;
    +-  while( pParser->fts5yyidx>=0 ) fts5yy_pop_parser_stack(pParser);
    +-#if fts5YYSTACKDEPTH<=0
    +-  free(pParser->fts5yystack);
    ++#ifndef fts5YYPARSEFREENEVERNULL
    ++  if( p==0 ) return;
    + #endif
    +-  (*freeProc)((void*)pParser);
    ++  sqlite3Fts5ParserFinalize(p);
    ++  (*freeProc)(p);
    + }
    ++#endif /* sqlite3Fts5Parser_ENGINEALWAYSONSTACK */
    + 
    + /*
    + ** Return the peak depth of the stack for a parser.
    +@@ -167430,33 +188065,70 @@ static void sqlite3Fts5ParserFree(
    + #ifdef fts5YYTRACKMAXSTACKDEPTH
    + static int sqlite3Fts5ParserStackPeak(void *p){
    +   fts5yyParser *pParser = (fts5yyParser*)p;
    +-  return pParser->fts5yyidxMax;
    ++  return pParser->fts5yyhwm;
    ++}
    ++#endif
    ++
    ++/* This array of booleans keeps track of the parser statement
    ++** coverage.  The element fts5yycoverage[X][Y] is set when the parser
    ++** is in state X and has a lookahead token Y.  In a well-tested
    ++** systems, every element of this matrix should end up being set.
    ++*/
    ++#if defined(fts5YYCOVERAGE)
    ++static unsigned char fts5yycoverage[fts5YYNSTATE][fts5YYNFTS5TOKEN];
    ++#endif
    ++
    ++/*
    ++** Write into out a description of every state/lookahead combination that
    ++**
    ++**   (1)  has not been used by the parser, and
    ++**   (2)  is not a syntax error.
    ++**
    ++** Return the number of missed state/lookahead combinations.
    ++*/
    ++#if defined(fts5YYCOVERAGE)
    ++static int sqlite3Fts5ParserCoverage(FILE *out){
    ++  int stateno, iLookAhead, i;
    ++  int nMissed = 0;
    ++  for(stateno=0; stateno<fts5YYNSTATE; stateno++){
    ++    i = fts5yy_shift_ofst[stateno];
    ++    for(iLookAhead=0; iLookAhead<fts5YYNFTS5TOKEN; iLookAhead++){
    ++      if( fts5yy_lookahead[i+iLookAhead]!=iLookAhead ) continue;
    ++      if( fts5yycoverage[stateno][iLookAhead]==0 ) nMissed++;
    ++      if( out ){
    ++        fprintf(out,"State %d lookahead %s %s\n", stateno,
    ++                fts5yyTokenName[iLookAhead],
    ++                fts5yycoverage[stateno][iLookAhead] ? "ok" : "missed");
    ++      }
    ++    }
    ++  }
    ++  return nMissed;
    + }
    + #endif
    + 
    + /*
    + ** Find the appropriate action for a parser given the terminal
    + ** look-ahead token iLookAhead.
    +-**
    +-** If the look-ahead token is fts5YYNOCODE, then check to see if the action is
    +-** independent of the look-ahead.  If it is, return the action, otherwise
    +-** return fts5YY_NO_ACTION.
    + */
    +-static int fts5yy_find_shift_action(
    ++static unsigned int fts5yy_find_shift_action(
    +   fts5yyParser *pParser,        /* The parser */
    +   fts5YYCODETYPE iLookAhead     /* The look-ahead token */
    + ){
    +   int i;
    +-  int stateno = pParser->fts5yystack[pParser->fts5yyidx].stateno;
    ++  int stateno = pParser->fts5yytos->stateno;
    +  
    +-  if( stateno>=fts5YY_MIN_REDUCE ) return stateno;
    ++  if( stateno>fts5YY_MAX_SHIFT ) return stateno;
    +   assert( stateno <= fts5YY_SHIFT_COUNT );
    +-  i = fts5yy_shift_ofst[stateno];
    +-  if( i==fts5YY_SHIFT_USE_DFLT ) return fts5yy_default[stateno];
    +-  assert( iLookAhead!=fts5YYNOCODE );
    +-  i += iLookAhead;
    +-  if( i<0 || i>=fts5YY_ACTTAB_COUNT || fts5yy_lookahead[i]!=iLookAhead ){
    +-    if( iLookAhead>0 ){
    ++#if defined(fts5YYCOVERAGE)
    ++  fts5yycoverage[stateno][iLookAhead] = 1;
    ++#endif
    ++  do{
    ++    i = fts5yy_shift_ofst[stateno];
    ++    assert( i>=0 && i+fts5YYNFTS5TOKEN<=sizeof(fts5yy_lookahead)/sizeof(fts5yy_lookahead[0]) );
    ++    assert( iLookAhead!=fts5YYNOCODE );
    ++    assert( iLookAhead < fts5YYNFTS5TOKEN );
    ++    i += iLookAhead;
    ++    if( fts5yy_lookahead[i]!=iLookAhead ){
    + #ifdef fts5YYFALLBACK
    +       fts5YYCODETYPE iFallback;            /* Fallback token */
    +       if( iLookAhead<sizeof(fts5yyFallback)/sizeof(fts5yyFallback[0])
    +@@ -167467,7 +188139,9 @@ static int fts5yy_find_shift_action(
    +              fts5yyTracePrompt, fts5yyTokenName[iLookAhead], fts5yyTokenName[iFallback]);
    +         }
    + #endif
    +-        return fts5yy_find_shift_action(pParser, iFallback);
    ++        assert( fts5yyFallback[iFallback]==0 ); /* Fallback loop must terminate */
    ++        iLookAhead = iFallback;
    ++        continue;
    +       }
    + #endif
    + #ifdef fts5YYWILDCARD
    +@@ -167480,32 +188154,29 @@ static int fts5yy_find_shift_action(
    + #if fts5YY_SHIFT_MAX+fts5YYWILDCARD>=fts5YY_ACTTAB_COUNT
    +           j<fts5YY_ACTTAB_COUNT &&
    + #endif
    +-          fts5yy_lookahead[j]==fts5YYWILDCARD
    ++          fts5yy_lookahead[j]==fts5YYWILDCARD && iLookAhead>0
    +         ){
    + #ifndef NDEBUG
    +           if( fts5yyTraceFILE ){
    +             fprintf(fts5yyTraceFILE, "%sWILDCARD %s => %s\n",
    +-               fts5yyTracePrompt, fts5yyTokenName[iLookAhead], fts5yyTokenName[fts5YYWILDCARD]);
    ++               fts5yyTracePrompt, fts5yyTokenName[iLookAhead],
    ++               fts5yyTokenName[fts5YYWILDCARD]);
    +           }
    + #endif /* NDEBUG */
    +           return fts5yy_action[j];
    +         }
    +       }
    + #endif /* fts5YYWILDCARD */
    ++      return fts5yy_default[stateno];
    ++    }else{
    ++      return fts5yy_action[i];
    +     }
    +-    return fts5yy_default[stateno];
    +-  }else{
    +-    return fts5yy_action[i];
    +-  }
    ++  }while(1);
    + }
    + 
    + /*
    + ** Find the appropriate action for a parser given the non-terminal
    + ** look-ahead token iLookAhead.
    +-**
    +-** If the look-ahead token is fts5YYNOCODE, then check to see if the action is
    +-** independent of the look-ahead.  If it is, return the action, otherwise
    +-** return fts5YY_NO_ACTION.
    + */
    + static int fts5yy_find_reduce_action(
    +   int stateno,              /* Current state number */
    +@@ -167520,7 +188191,6 @@ static int fts5yy_find_reduce_action(
    +   assert( stateno<=fts5YY_REDUCE_COUNT );
    + #endif
    +   i = fts5yy_reduce_ofst[stateno];
    +-  assert( i!=fts5YY_REDUCE_USE_DFLT );
    +   assert( iLookAhead!=fts5YYNOCODE );
    +   i += iLookAhead;
    + #ifdef fts5YYERRORSYMBOL
    +@@ -167537,19 +188207,20 @@ static int fts5yy_find_reduce_action(
    + /*
    + ** The following routine is called if the stack overflows.
    + */
    +-static void fts5yyStackOverflow(fts5yyParser *fts5yypParser, fts5YYMINORTYPE *fts5yypMinor){
    ++static void fts5yyStackOverflow(fts5yyParser *fts5yypParser){
    +    sqlite3Fts5ParserARG_FETCH;
    +-   fts5yypParser->fts5yyidx--;
    + #ifndef NDEBUG
    +    if( fts5yyTraceFILE ){
    +      fprintf(fts5yyTraceFILE,"%sStack Overflow!\n",fts5yyTracePrompt);
    +    }
    + #endif
    +-   while( fts5yypParser->fts5yyidx>=0 ) fts5yy_pop_parser_stack(fts5yypParser);
    ++   while( fts5yypParser->fts5yytos>fts5yypParser->fts5yystack ) fts5yy_pop_parser_stack(fts5yypParser);
    +    /* Here code is inserted which will execute if the parser
    +    ** stack every overflows */
    ++/******** Begin %stack_overflow code ******************************************/
    + 
    +-  assert( 0 );
    ++  sqlite3Fts5ParseError(pParse, "fts5: parser stack overflow");
    ++/******** End %stack_overflow code ********************************************/
    +    sqlite3Fts5ParserARG_STORE; /* Suppress warning about unused %extra_argument var */
    + }
    + 
    +@@ -167557,92 +188228,100 @@ static void fts5yyStackOverflow(fts5yyParser *fts5yypParser, fts5YYMINORTYPE *ft
    + ** Print tracing information for a SHIFT action
    + */
    + #ifndef NDEBUG
    +-static void fts5yyTraceShift(fts5yyParser *fts5yypParser, int fts5yyNewState){
    ++static void fts5yyTraceShift(fts5yyParser *fts5yypParser, int fts5yyNewState, const char *zTag){
    +   if( fts5yyTraceFILE ){
    +-    int i;
    +     if( fts5yyNewState<fts5YYNSTATE ){
    +-      fprintf(fts5yyTraceFILE,"%sShift %d\n",fts5yyTracePrompt,fts5yyNewState);
    +-      fprintf(fts5yyTraceFILE,"%sStack:",fts5yyTracePrompt);
    +-      for(i=1; i<=fts5yypParser->fts5yyidx; i++)
    +-        fprintf(fts5yyTraceFILE," %s",fts5yyTokenName[fts5yypParser->fts5yystack[i].major]);
    +-      fprintf(fts5yyTraceFILE,"\n");
    ++      fprintf(fts5yyTraceFILE,"%s%s '%s', go to state %d\n",
    ++         fts5yyTracePrompt, zTag, fts5yyTokenName[fts5yypParser->fts5yytos->major],
    ++         fts5yyNewState);
    +     }else{
    +-      fprintf(fts5yyTraceFILE,"%sShift *\n",fts5yyTracePrompt);
    ++      fprintf(fts5yyTraceFILE,"%s%s '%s', pending reduce %d\n",
    ++         fts5yyTracePrompt, zTag, fts5yyTokenName[fts5yypParser->fts5yytos->major],
    ++         fts5yyNewState - fts5YY_MIN_REDUCE);
    +     }
    +   }
    + }
    + #else
    +-# define fts5yyTraceShift(X,Y)
    ++# define fts5yyTraceShift(X,Y,Z)
    + #endif
    + 
    + /*
    +-** Perform a shift action.  Return the number of errors.
    ++** Perform a shift action.
    + */
    + static void fts5yy_shift(
    +   fts5yyParser *fts5yypParser,          /* The parser to be shifted */
    +   int fts5yyNewState,               /* The new state to shift in */
    +   int fts5yyMajor,                  /* The major token to shift in */
    +-  fts5YYMINORTYPE *fts5yypMinor         /* Pointer to the minor token to shift in */
    ++  sqlite3Fts5ParserFTS5TOKENTYPE fts5yyMinor        /* The minor token to shift in */
    + ){
    +   fts5yyStackEntry *fts5yytos;
    +-  fts5yypParser->fts5yyidx++;
    ++  fts5yypParser->fts5yytos++;
    + #ifdef fts5YYTRACKMAXSTACKDEPTH
    +-  if( fts5yypParser->fts5yyidx>fts5yypParser->fts5yyidxMax ){
    +-    fts5yypParser->fts5yyidxMax = fts5yypParser->fts5yyidx;
    ++  if( (int)(fts5yypParser->fts5yytos - fts5yypParser->fts5yystack)>fts5yypParser->fts5yyhwm ){
    ++    fts5yypParser->fts5yyhwm++;
    ++    assert( fts5yypParser->fts5yyhwm == (int)(fts5yypParser->fts5yytos - fts5yypParser->fts5yystack) );
    +   }
    + #endif
    + #if fts5YYSTACKDEPTH>0 
    +-  if( fts5yypParser->fts5yyidx>=fts5YYSTACKDEPTH ){
    +-    fts5yyStackOverflow(fts5yypParser, fts5yypMinor);
    ++  if( fts5yypParser->fts5yytos>fts5yypParser->fts5yystackEnd ){
    ++    fts5yypParser->fts5yytos--;
    ++    fts5yyStackOverflow(fts5yypParser);
    +     return;
    +   }
    + #else
    +-  if( fts5yypParser->fts5yyidx>=fts5yypParser->fts5yystksz ){
    +-    fts5yyGrowStack(fts5yypParser);
    +-    if( fts5yypParser->fts5yyidx>=fts5yypParser->fts5yystksz ){
    +-      fts5yyStackOverflow(fts5yypParser, fts5yypMinor);
    ++  if( fts5yypParser->fts5yytos>=&fts5yypParser->fts5yystack[fts5yypParser->fts5yystksz] ){
    ++    if( fts5yyGrowStack(fts5yypParser) ){
    ++      fts5yypParser->fts5yytos--;
    ++      fts5yyStackOverflow(fts5yypParser);
    +       return;
    +     }
    +   }
    + #endif
    +-  fts5yytos = &fts5yypParser->fts5yystack[fts5yypParser->fts5yyidx];
    ++  if( fts5yyNewState > fts5YY_MAX_SHIFT ){
    ++    fts5yyNewState += fts5YY_MIN_REDUCE - fts5YY_MIN_SHIFTREDUCE;
    ++  }
    ++  fts5yytos = fts5yypParser->fts5yytos;
    +   fts5yytos->stateno = (fts5YYACTIONTYPE)fts5yyNewState;
    +   fts5yytos->major = (fts5YYCODETYPE)fts5yyMajor;
    +-  fts5yytos->minor = *fts5yypMinor;
    +-  fts5yyTraceShift(fts5yypParser, fts5yyNewState);
    ++  fts5yytos->minor.fts5yy0 = fts5yyMinor;
    ++  fts5yyTraceShift(fts5yypParser, fts5yyNewState, "Shift");
    + }
    + 
    + /* The following table contains information about every rule that
    + ** is used during the reduce.
    + */
    + static const struct {
    +-  fts5YYCODETYPE lhs;         /* Symbol on the left-hand side of the rule */
    +-  unsigned char nrhs;     /* Number of right-hand side symbols in the rule */
    ++  fts5YYCODETYPE lhs;       /* Symbol on the left-hand side of the rule */
    ++  signed char nrhs;     /* Negative of the number of RHS symbols in the rule */
    + } fts5yyRuleInfo[] = {
    +-  { 15, 1 },
    +-  { 16, 3 },
    +-  { 16, 3 },
    +-  { 16, 3 },
    +-  { 16, 3 },
    +-  { 16, 1 },
    +-  { 18, 1 },
    +-  { 18, 2 },
    +-  { 17, 1 },
    +-  { 17, 3 },
    +-  { 20, 3 },
    +-  { 20, 1 },
    +-  { 21, 2 },
    +-  { 21, 1 },
    +-  { 19, 1 },
    +-  { 19, 5 },
    +-  { 22, 1 },
    +-  { 22, 2 },
    +-  { 24, 0 },
    +-  { 24, 2 },
    +-  { 23, 4 },
    +-  { 23, 2 },
    +-  { 25, 1 },
    +-  { 25, 0 },
    ++  {   17,   -1 }, /* (0) input ::= expr */
    ++  {   21,   -4 }, /* (1) colset ::= MINUS LCP colsetlist RCP */
    ++  {   21,   -3 }, /* (2) colset ::= LCP colsetlist RCP */
    ++  {   21,   -1 }, /* (3) colset ::= STRING */
    ++  {   21,   -2 }, /* (4) colset ::= MINUS STRING */
    ++  {   22,   -2 }, /* (5) colsetlist ::= colsetlist STRING */
    ++  {   22,   -1 }, /* (6) colsetlist ::= STRING */
    ++  {   18,   -3 }, /* (7) expr ::= expr AND expr */
    ++  {   18,   -3 }, /* (8) expr ::= expr OR expr */
    ++  {   18,   -3 }, /* (9) expr ::= expr NOT expr */
    ++  {   18,   -5 }, /* (10) expr ::= colset COLON LP expr RP */
    ++  {   18,   -3 }, /* (11) expr ::= LP expr RP */
    ++  {   18,   -1 }, /* (12) expr ::= exprlist */
    ++  {   20,   -1 }, /* (13) exprlist ::= cnearset */
    ++  {   20,   -2 }, /* (14) exprlist ::= exprlist cnearset */
    ++  {   19,   -1 }, /* (15) cnearset ::= nearset */
    ++  {   19,   -3 }, /* (16) cnearset ::= colset COLON nearset */
    ++  {   23,   -1 }, /* (17) nearset ::= phrase */
    ++  {   23,   -2 }, /* (18) nearset ::= CARET phrase */
    ++  {   23,   -5 }, /* (19) nearset ::= STRING LP nearphrases neardist_opt RP */
    ++  {   24,   -1 }, /* (20) nearphrases ::= phrase */
    ++  {   24,   -2 }, /* (21) nearphrases ::= nearphrases phrase */
    ++  {   26,    0 }, /* (22) neardist_opt ::= */
    ++  {   26,   -2 }, /* (23) neardist_opt ::= COMMA STRING */
    ++  {   25,   -4 }, /* (24) phrase ::= phrase PLUS STRING star_opt */
    ++  {   25,   -2 }, /* (25) phrase ::= STRING star_opt */
    ++  {   27,   -1 }, /* (26) star_opt ::= STAR */
    ++  {   27,    0 }, /* (27) star_opt ::= */
    + };
    + 
    + static void fts5yy_accept(fts5yyParser*);  /* Forward Declaration */
    +@@ -167650,44 +188329,66 @@ static void fts5yy_accept(fts5yyParser*);  /* Forward Declaration */
    + /*
    + ** Perform a reduce action and the shift that must immediately
    + ** follow the reduce.
    ++**
    ++** The fts5yyLookahead and fts5yyLookaheadToken parameters provide reduce actions
    ++** access to the lookahead token (if any).  The fts5yyLookahead will be fts5YYNOCODE
    ++** if the lookahead token has already been consumed.  As this procedure is
    ++** only called from one place, optimizing compilers will in-line it, which
    ++** means that the extra parameters have no performance impact.
    + */
    + static void fts5yy_reduce(
    +   fts5yyParser *fts5yypParser,         /* The parser */
    +-  int fts5yyruleno                 /* Number of the rule by which to reduce */
    ++  unsigned int fts5yyruleno,       /* Number of the rule by which to reduce */
    ++  int fts5yyLookahead,             /* Lookahead token, or fts5YYNOCODE if none */
    ++  sqlite3Fts5ParserFTS5TOKENTYPE fts5yyLookaheadToken  /* Value of the lookahead token */
    + ){
    +   int fts5yygoto;                     /* The next state */
    +   int fts5yyact;                      /* The next action */
    +-  fts5YYMINORTYPE fts5yygotominor;        /* The LHS of the rule reduced */
    +   fts5yyStackEntry *fts5yymsp;            /* The top of the parser's stack */
    +   int fts5yysize;                     /* Amount to pop the stack */
    +   sqlite3Fts5ParserARG_FETCH;
    +-  fts5yymsp = &fts5yypParser->fts5yystack[fts5yypParser->fts5yyidx];
    ++  (void)fts5yyLookahead;
    ++  (void)fts5yyLookaheadToken;
    ++  fts5yymsp = fts5yypParser->fts5yytos;
    + #ifndef NDEBUG
    +-  if( fts5yyTraceFILE && fts5yyruleno>=0 
    +-        && fts5yyruleno<(int)(sizeof(fts5yyRuleName)/sizeof(fts5yyRuleName[0])) ){
    ++  if( fts5yyTraceFILE && fts5yyruleno<(int)(sizeof(fts5yyRuleName)/sizeof(fts5yyRuleName[0])) ){
    +     fts5yysize = fts5yyRuleInfo[fts5yyruleno].nrhs;
    +-    fprintf(fts5yyTraceFILE, "%sReduce [%s] -> state %d.\n", fts5yyTracePrompt,
    +-      fts5yyRuleName[fts5yyruleno], fts5yymsp[-fts5yysize].stateno);
    ++    if( fts5yysize ){
    ++      fprintf(fts5yyTraceFILE, "%sReduce %d [%s], go to state %d.\n",
    ++        fts5yyTracePrompt,
    ++        fts5yyruleno, fts5yyRuleName[fts5yyruleno], fts5yymsp[fts5yysize].stateno);
    ++    }else{
    ++      fprintf(fts5yyTraceFILE, "%sReduce %d [%s].\n",
    ++        fts5yyTracePrompt, fts5yyruleno, fts5yyRuleName[fts5yyruleno]);
    ++    }
    +   }
    + #endif /* NDEBUG */
    + 
    +-  /* Silence complaints from purify about fts5yygotominor being uninitialized
    +-  ** in some cases when it is copied into the stack after the following
    +-  ** switch.  fts5yygotominor is uninitialized when a rule reduces that does
    +-  ** not set the value of its left-hand side nonterminal.  Leaving the
    +-  ** value of the nonterminal uninitialized is utterly harmless as long
    +-  ** as the value is never used.  So really the only thing this code
    +-  ** accomplishes is to quieten purify.  
    +-  **
    +-  ** 2007-01-16:  The wireshark project (www.wireshark.org) reports that
    +-  ** without this code, their parser segfaults.  I'm not sure what there
    +-  ** parser is doing to make this happen.  This is the second bug report
    +-  ** from wireshark this week.  Clearly they are stressing Lemon in ways
    +-  ** that it has not been previously stressed...  (SQLite ticket #2172)
    +-  */
    +-  /*memset(&fts5yygotominor, 0, sizeof(fts5yygotominor));*/
    +-  fts5yygotominor = fts5yyzerominor;
    +-
    ++  /* Check that the stack is large enough to grow by a single entry
    ++  ** if the RHS of the rule is empty.  This ensures that there is room
    ++  ** enough on the stack to push the LHS value */
    ++  if( fts5yyRuleInfo[fts5yyruleno].nrhs==0 ){
    ++#ifdef fts5YYTRACKMAXSTACKDEPTH
    ++    if( (int)(fts5yypParser->fts5yytos - fts5yypParser->fts5yystack)>fts5yypParser->fts5yyhwm ){
    ++      fts5yypParser->fts5yyhwm++;
    ++      assert( fts5yypParser->fts5yyhwm == (int)(fts5yypParser->fts5yytos - fts5yypParser->fts5yystack));
    ++    }
    ++#endif
    ++#if fts5YYSTACKDEPTH>0 
    ++    if( fts5yypParser->fts5yytos>=fts5yypParser->fts5yystackEnd ){
    ++      fts5yyStackOverflow(fts5yypParser);
    ++      return;
    ++    }
    ++#else
    ++    if( fts5yypParser->fts5yytos>=&fts5yypParser->fts5yystack[fts5yypParser->fts5yystksz-1] ){
    ++      if( fts5yyGrowStack(fts5yypParser) ){
    ++        fts5yyStackOverflow(fts5yypParser);
    ++        return;
    ++      }
    ++      fts5yymsp = fts5yypParser->fts5yytos;
    ++    }
    ++#endif
    ++  }
    + 
    +   switch( fts5yyruleno ){
    +   /* Beginning here are the reduction cases.  A typical example
    +@@ -167698,134 +188399,169 @@ static void fts5yy_reduce(
    +   **  #line <lineno> <thisfile>
    +   **     break;
    +   */
    ++/********** Begin reduce actions **********************************************/
    ++        fts5YYMINORTYPE fts5yylhsminor;
    +       case 0: /* input ::= expr */
    +-{ sqlite3Fts5ParseFinished(pParse, fts5yymsp[0].minor.fts5yy18); }
    ++{ sqlite3Fts5ParseFinished(pParse, fts5yymsp[0].minor.fts5yy54); }
    +         break;
    +-      case 1: /* expr ::= expr AND expr */
    +-{
    +-  fts5yygotominor.fts5yy18 = sqlite3Fts5ParseNode(pParse, FTS5_AND, fts5yymsp[-2].minor.fts5yy18, fts5yymsp[0].minor.fts5yy18, 0);
    ++      case 1: /* colset ::= MINUS LCP colsetlist RCP */
    ++{ 
    ++    fts5yymsp[-3].minor.fts5yy43 = sqlite3Fts5ParseColsetInvert(pParse, fts5yymsp[-1].minor.fts5yy43);
    + }
    +         break;
    +-      case 2: /* expr ::= expr OR expr */
    ++      case 2: /* colset ::= LCP colsetlist RCP */
    ++{ fts5yymsp[-2].minor.fts5yy43 = fts5yymsp[-1].minor.fts5yy43; }
    ++        break;
    ++      case 3: /* colset ::= STRING */
    + {
    +-  fts5yygotominor.fts5yy18 = sqlite3Fts5ParseNode(pParse, FTS5_OR, fts5yymsp[-2].minor.fts5yy18, fts5yymsp[0].minor.fts5yy18, 0);
    ++  fts5yylhsminor.fts5yy43 = sqlite3Fts5ParseColset(pParse, 0, &fts5yymsp[0].minor.fts5yy0);
    + }
    ++  fts5yymsp[0].minor.fts5yy43 = fts5yylhsminor.fts5yy43;
    +         break;
    +-      case 3: /* expr ::= expr NOT expr */
    ++      case 4: /* colset ::= MINUS STRING */
    + {
    +-  fts5yygotominor.fts5yy18 = sqlite3Fts5ParseNode(pParse, FTS5_NOT, fts5yymsp[-2].minor.fts5yy18, fts5yymsp[0].minor.fts5yy18, 0);
    ++  fts5yymsp[-1].minor.fts5yy43 = sqlite3Fts5ParseColset(pParse, 0, &fts5yymsp[0].minor.fts5yy0);
    ++  fts5yymsp[-1].minor.fts5yy43 = sqlite3Fts5ParseColsetInvert(pParse, fts5yymsp[-1].minor.fts5yy43);
    + }
    +         break;
    +-      case 4: /* expr ::= LP expr RP */
    +-{fts5yygotominor.fts5yy18 = fts5yymsp[-1].minor.fts5yy18;}
    ++      case 5: /* colsetlist ::= colsetlist STRING */
    ++{ 
    ++  fts5yylhsminor.fts5yy43 = sqlite3Fts5ParseColset(pParse, fts5yymsp[-1].minor.fts5yy43, &fts5yymsp[0].minor.fts5yy0); }
    ++  fts5yymsp[-1].minor.fts5yy43 = fts5yylhsminor.fts5yy43;
    +         break;
    +-      case 5: /* expr ::= exprlist */
    +-      case 6: /* exprlist ::= cnearset */ fts5yytestcase(fts5yyruleno==6);
    +-{fts5yygotominor.fts5yy18 = fts5yymsp[0].minor.fts5yy18;}
    ++      case 6: /* colsetlist ::= STRING */
    ++{ 
    ++  fts5yylhsminor.fts5yy43 = sqlite3Fts5ParseColset(pParse, 0, &fts5yymsp[0].minor.fts5yy0); 
    ++}
    ++  fts5yymsp[0].minor.fts5yy43 = fts5yylhsminor.fts5yy43;
    +         break;
    +-      case 7: /* exprlist ::= exprlist cnearset */
    ++      case 7: /* expr ::= expr AND expr */
    + {
    +-  fts5yygotominor.fts5yy18 = sqlite3Fts5ParseNode(pParse, FTS5_AND, fts5yymsp[-1].minor.fts5yy18, fts5yymsp[0].minor.fts5yy18, 0);
    ++  fts5yylhsminor.fts5yy54 = sqlite3Fts5ParseNode(pParse, FTS5_AND, fts5yymsp[-2].minor.fts5yy54, fts5yymsp[0].minor.fts5yy54, 0);
    + }
    ++  fts5yymsp[-2].minor.fts5yy54 = fts5yylhsminor.fts5yy54;
    +         break;
    +-      case 8: /* cnearset ::= nearset */
    +-{ 
    +-  fts5yygotominor.fts5yy18 = sqlite3Fts5ParseNode(pParse, FTS5_STRING, 0, 0, fts5yymsp[0].minor.fts5yy26); 
    ++      case 8: /* expr ::= expr OR expr */
    ++{
    ++  fts5yylhsminor.fts5yy54 = sqlite3Fts5ParseNode(pParse, FTS5_OR, fts5yymsp[-2].minor.fts5yy54, fts5yymsp[0].minor.fts5yy54, 0);
    + }
    ++  fts5yymsp[-2].minor.fts5yy54 = fts5yylhsminor.fts5yy54;
    +         break;
    +-      case 9: /* cnearset ::= colset COLON nearset */
    +-{ 
    +-  sqlite3Fts5ParseSetColset(pParse, fts5yymsp[0].minor.fts5yy26, fts5yymsp[-2].minor.fts5yy3);
    +-  fts5yygotominor.fts5yy18 = sqlite3Fts5ParseNode(pParse, FTS5_STRING, 0, 0, fts5yymsp[0].minor.fts5yy26); 
    ++      case 9: /* expr ::= expr NOT expr */
    ++{
    ++  fts5yylhsminor.fts5yy54 = sqlite3Fts5ParseNode(pParse, FTS5_NOT, fts5yymsp[-2].minor.fts5yy54, fts5yymsp[0].minor.fts5yy54, 0);
    + }
    ++  fts5yymsp[-2].minor.fts5yy54 = fts5yylhsminor.fts5yy54;
    ++        break;
    ++      case 10: /* expr ::= colset COLON LP expr RP */
    ++{
    ++  sqlite3Fts5ParseSetColset(pParse, fts5yymsp[-1].minor.fts5yy54, fts5yymsp[-4].minor.fts5yy43);
    ++  fts5yylhsminor.fts5yy54 = fts5yymsp[-1].minor.fts5yy54;
    ++}
    ++  fts5yymsp[-4].minor.fts5yy54 = fts5yylhsminor.fts5yy54;
    ++        break;
    ++      case 11: /* expr ::= LP expr RP */
    ++{fts5yymsp[-2].minor.fts5yy54 = fts5yymsp[-1].minor.fts5yy54;}
    +         break;
    +-      case 10: /* colset ::= LCP colsetlist RCP */
    +-{ fts5yygotominor.fts5yy3 = fts5yymsp[-1].minor.fts5yy3; }
    ++      case 12: /* expr ::= exprlist */
    ++      case 13: /* exprlist ::= cnearset */ fts5yytestcase(fts5yyruleno==13);
    ++{fts5yylhsminor.fts5yy54 = fts5yymsp[0].minor.fts5yy54;}
    ++  fts5yymsp[0].minor.fts5yy54 = fts5yylhsminor.fts5yy54;
    +         break;
    +-      case 11: /* colset ::= STRING */
    ++      case 14: /* exprlist ::= exprlist cnearset */
    + {
    +-  fts5yygotominor.fts5yy3 = sqlite3Fts5ParseColset(pParse, 0, &fts5yymsp[0].minor.fts5yy0);
    ++  fts5yylhsminor.fts5yy54 = sqlite3Fts5ParseImplicitAnd(pParse, fts5yymsp[-1].minor.fts5yy54, fts5yymsp[0].minor.fts5yy54);
    + }
    ++  fts5yymsp[-1].minor.fts5yy54 = fts5yylhsminor.fts5yy54;
    +         break;
    +-      case 12: /* colsetlist ::= colsetlist STRING */
    ++      case 15: /* cnearset ::= nearset */
    + { 
    +-  fts5yygotominor.fts5yy3 = sqlite3Fts5ParseColset(pParse, fts5yymsp[-1].minor.fts5yy3, &fts5yymsp[0].minor.fts5yy0); }
    ++  fts5yylhsminor.fts5yy54 = sqlite3Fts5ParseNode(pParse, FTS5_STRING, 0, 0, fts5yymsp[0].minor.fts5yy14); 
    ++}
    ++  fts5yymsp[0].minor.fts5yy54 = fts5yylhsminor.fts5yy54;
    +         break;
    +-      case 13: /* colsetlist ::= STRING */
    ++      case 16: /* cnearset ::= colset COLON nearset */
    + { 
    +-  fts5yygotominor.fts5yy3 = sqlite3Fts5ParseColset(pParse, 0, &fts5yymsp[0].minor.fts5yy0); 
    ++  fts5yylhsminor.fts5yy54 = sqlite3Fts5ParseNode(pParse, FTS5_STRING, 0, 0, fts5yymsp[0].minor.fts5yy14); 
    ++  sqlite3Fts5ParseSetColset(pParse, fts5yylhsminor.fts5yy54, fts5yymsp[-2].minor.fts5yy43);
    + }
    ++  fts5yymsp[-2].minor.fts5yy54 = fts5yylhsminor.fts5yy54;
    +         break;
    +-      case 14: /* nearset ::= phrase */
    +-{ fts5yygotominor.fts5yy26 = sqlite3Fts5ParseNearset(pParse, 0, fts5yymsp[0].minor.fts5yy11); }
    ++      case 17: /* nearset ::= phrase */
    ++{ fts5yylhsminor.fts5yy14 = sqlite3Fts5ParseNearset(pParse, 0, fts5yymsp[0].minor.fts5yy11); }
    ++  fts5yymsp[0].minor.fts5yy14 = fts5yylhsminor.fts5yy14;
    +         break;
    +-      case 15: /* nearset ::= STRING LP nearphrases neardist_opt RP */
    ++      case 18: /* nearset ::= CARET phrase */
    ++{ 
    ++  sqlite3Fts5ParseSetCaret(fts5yymsp[0].minor.fts5yy11);
    ++  fts5yymsp[-1].minor.fts5yy14 = sqlite3Fts5ParseNearset(pParse, 0, fts5yymsp[0].minor.fts5yy11); 
    ++}
    ++        break;
    ++      case 19: /* nearset ::= STRING LP nearphrases neardist_opt RP */
    + {
    +   sqlite3Fts5ParseNear(pParse, &fts5yymsp[-4].minor.fts5yy0);
    +-  sqlite3Fts5ParseSetDistance(pParse, fts5yymsp[-2].minor.fts5yy26, &fts5yymsp[-1].minor.fts5yy0);
    +-  fts5yygotominor.fts5yy26 = fts5yymsp[-2].minor.fts5yy26;
    ++  sqlite3Fts5ParseSetDistance(pParse, fts5yymsp[-2].minor.fts5yy14, &fts5yymsp[-1].minor.fts5yy0);
    ++  fts5yylhsminor.fts5yy14 = fts5yymsp[-2].minor.fts5yy14;
    + }
    ++  fts5yymsp[-4].minor.fts5yy14 = fts5yylhsminor.fts5yy14;
    +         break;
    +-      case 16: /* nearphrases ::= phrase */
    ++      case 20: /* nearphrases ::= phrase */
    + { 
    +-  fts5yygotominor.fts5yy26 = sqlite3Fts5ParseNearset(pParse, 0, fts5yymsp[0].minor.fts5yy11); 
    ++  fts5yylhsminor.fts5yy14 = sqlite3Fts5ParseNearset(pParse, 0, fts5yymsp[0].minor.fts5yy11); 
    + }
    ++  fts5yymsp[0].minor.fts5yy14 = fts5yylhsminor.fts5yy14;
    +         break;
    +-      case 17: /* nearphrases ::= nearphrases phrase */
    ++      case 21: /* nearphrases ::= nearphrases phrase */
    + {
    +-  fts5yygotominor.fts5yy26 = sqlite3Fts5ParseNearset(pParse, fts5yymsp[-1].minor.fts5yy26, fts5yymsp[0].minor.fts5yy11);
    ++  fts5yylhsminor.fts5yy14 = sqlite3Fts5ParseNearset(pParse, fts5yymsp[-1].minor.fts5yy14, fts5yymsp[0].minor.fts5yy11);
    + }
    ++  fts5yymsp[-1].minor.fts5yy14 = fts5yylhsminor.fts5yy14;
    +         break;
    +-      case 18: /* neardist_opt ::= */
    +-{ fts5yygotominor.fts5yy0.p = 0; fts5yygotominor.fts5yy0.n = 0; }
    ++      case 22: /* neardist_opt ::= */
    ++{ fts5yymsp[1].minor.fts5yy0.p = 0; fts5yymsp[1].minor.fts5yy0.n = 0; }
    +         break;
    +-      case 19: /* neardist_opt ::= COMMA STRING */
    +-{ fts5yygotominor.fts5yy0 = fts5yymsp[0].minor.fts5yy0; }
    ++      case 23: /* neardist_opt ::= COMMA STRING */
    ++{ fts5yymsp[-1].minor.fts5yy0 = fts5yymsp[0].minor.fts5yy0; }
    +         break;
    +-      case 20: /* phrase ::= phrase PLUS STRING star_opt */
    ++      case 24: /* phrase ::= phrase PLUS STRING star_opt */
    + { 
    +-  fts5yygotominor.fts5yy11 = sqlite3Fts5ParseTerm(pParse, fts5yymsp[-3].minor.fts5yy11, &fts5yymsp[-1].minor.fts5yy0, fts5yymsp[0].minor.fts5yy20);
    ++  fts5yylhsminor.fts5yy11 = sqlite3Fts5ParseTerm(pParse, fts5yymsp[-3].minor.fts5yy11, &fts5yymsp[-1].minor.fts5yy0, fts5yymsp[0].minor.fts5yy4);
    + }
    ++  fts5yymsp[-3].minor.fts5yy11 = fts5yylhsminor.fts5yy11;
    +         break;
    +-      case 21: /* phrase ::= STRING star_opt */
    ++      case 25: /* phrase ::= STRING star_opt */
    + { 
    +-  fts5yygotominor.fts5yy11 = sqlite3Fts5ParseTerm(pParse, 0, &fts5yymsp[-1].minor.fts5yy0, fts5yymsp[0].minor.fts5yy20);
    ++  fts5yylhsminor.fts5yy11 = sqlite3Fts5ParseTerm(pParse, 0, &fts5yymsp[-1].minor.fts5yy0, fts5yymsp[0].minor.fts5yy4);
    + }
    ++  fts5yymsp[-1].minor.fts5yy11 = fts5yylhsminor.fts5yy11;
    +         break;
    +-      case 22: /* star_opt ::= STAR */
    +-{ fts5yygotominor.fts5yy20 = 1; }
    ++      case 26: /* star_opt ::= STAR */
    ++{ fts5yymsp[0].minor.fts5yy4 = 1; }
    +         break;
    +-      case 23: /* star_opt ::= */
    +-{ fts5yygotominor.fts5yy20 = 0; }
    ++      case 27: /* star_opt ::= */
    ++{ fts5yymsp[1].minor.fts5yy4 = 0; }
    +         break;
    +       default:
    +         break;
    ++/********** End reduce actions ************************************************/
    +   };
    +-  assert( fts5yyruleno>=0 && fts5yyruleno<sizeof(fts5yyRuleInfo)/sizeof(fts5yyRuleInfo[0]) );
    ++  assert( fts5yyruleno<sizeof(fts5yyRuleInfo)/sizeof(fts5yyRuleInfo[0]) );
    +   fts5yygoto = fts5yyRuleInfo[fts5yyruleno].lhs;
    +   fts5yysize = fts5yyRuleInfo[fts5yyruleno].nrhs;
    +-  fts5yypParser->fts5yyidx -= fts5yysize;
    +-  fts5yyact = fts5yy_find_reduce_action(fts5yymsp[-fts5yysize].stateno,(fts5YYCODETYPE)fts5yygoto);
    +-  if( fts5yyact <= fts5YY_MAX_SHIFTREDUCE ){
    +-    if( fts5yyact>fts5YY_MAX_SHIFT ) fts5yyact += fts5YY_MIN_REDUCE - fts5YY_MIN_SHIFTREDUCE;
    +-    /* If the reduce action popped at least
    +-    ** one element off the stack, then we can push the new element back
    +-    ** onto the stack here, and skip the stack overflow test in fts5yy_shift().
    +-    ** That gives a significant speed improvement. */
    +-    if( fts5yysize ){
    +-      fts5yypParser->fts5yyidx++;
    +-      fts5yymsp -= fts5yysize-1;
    +-      fts5yymsp->stateno = (fts5YYACTIONTYPE)fts5yyact;
    +-      fts5yymsp->major = (fts5YYCODETYPE)fts5yygoto;
    +-      fts5yymsp->minor = fts5yygotominor;
    +-      fts5yyTraceShift(fts5yypParser, fts5yyact);
    +-    }else{
    +-      fts5yy_shift(fts5yypParser,fts5yyact,fts5yygoto,&fts5yygotominor);
    +-    }
    +-  }else{
    +-    assert( fts5yyact == fts5YY_ACCEPT_ACTION );
    +-    fts5yy_accept(fts5yypParser);
    +-  }
    ++  fts5yyact = fts5yy_find_reduce_action(fts5yymsp[fts5yysize].stateno,(fts5YYCODETYPE)fts5yygoto);
    ++
    ++  /* There are no SHIFTREDUCE actions on nonterminals because the table
    ++  ** generator has simplified them to pure REDUCE actions. */
    ++  assert( !(fts5yyact>fts5YY_MAX_SHIFT && fts5yyact<=fts5YY_MAX_SHIFTREDUCE) );
    ++
    ++  /* It is not possible for a REDUCE to be followed by an error */
    ++  assert( fts5yyact!=fts5YY_ERROR_ACTION );
    ++
    ++  fts5yymsp += fts5yysize+1;
    ++  fts5yypParser->fts5yytos = fts5yymsp;
    ++  fts5yymsp->stateno = (fts5YYACTIONTYPE)fts5yyact;
    ++  fts5yymsp->major = (fts5YYCODETYPE)fts5yygoto;
    ++  fts5yyTraceShift(fts5yypParser, fts5yyact, "... then shift");
    + }
    + 
    + /*
    +@@ -167841,9 +188577,11 @@ static void fts5yy_parse_failed(
    +     fprintf(fts5yyTraceFILE,"%sFail!\n",fts5yyTracePrompt);
    +   }
    + #endif
    +-  while( fts5yypParser->fts5yyidx>=0 ) fts5yy_pop_parser_stack(fts5yypParser);
    ++  while( fts5yypParser->fts5yytos>fts5yypParser->fts5yystack ) fts5yy_pop_parser_stack(fts5yypParser);
    +   /* Here code is inserted which will be executed whenever the
    +   ** parser fails */
    ++/************ Begin %parse_failure code ***************************************/
    ++/************ End %parse_failure code *****************************************/
    +   sqlite3Fts5ParserARG_STORE; /* Suppress warning about unused %extra_argument variable */
    + }
    + #endif /* fts5YYNOERRORRECOVERY */
    +@@ -167854,14 +188592,17 @@ static void fts5yy_parse_failed(
    + static void fts5yy_syntax_error(
    +   fts5yyParser *fts5yypParser,           /* The parser */
    +   int fts5yymajor,                   /* The major type of the error token */
    +-  fts5YYMINORTYPE fts5yyminor            /* The minor type of the error token */
    ++  sqlite3Fts5ParserFTS5TOKENTYPE fts5yyminor         /* The minor type of the error token */
    + ){
    +   sqlite3Fts5ParserARG_FETCH;
    +-#define FTS5TOKEN (fts5yyminor.fts5yy0)
    ++#define FTS5TOKEN fts5yyminor
    ++/************ Begin %syntax_error code ****************************************/
    + 
    ++  UNUSED_PARAM(fts5yymajor); /* Silence a compiler warning */
    +   sqlite3Fts5ParseError(
    +     pParse, "fts5: syntax error near \"%.*s\"",FTS5TOKEN.n,FTS5TOKEN.p
    +   );
    ++/************ End %syntax_error code ******************************************/
    +   sqlite3Fts5ParserARG_STORE; /* Suppress warning about unused %extra_argument variable */
    + }
    + 
    +@@ -167877,9 +188618,14 @@ static void fts5yy_accept(
    +     fprintf(fts5yyTraceFILE,"%sAccept!\n",fts5yyTracePrompt);
    +   }
    + #endif
    +-  while( fts5yypParser->fts5yyidx>=0 ) fts5yy_pop_parser_stack(fts5yypParser);
    ++#ifndef fts5YYNOERRORRECOVERY
    ++  fts5yypParser->fts5yyerrcnt = -1;
    ++#endif
    ++  assert( fts5yypParser->fts5yytos==fts5yypParser->fts5yystack );
    +   /* Here code is inserted which will be executed whenever the
    +   ** parser accepts */
    ++/*********** Begin %parse_accept code *****************************************/
    ++/*********** End %parse_accept code *******************************************/
    +   sqlite3Fts5ParserARG_STORE; /* Suppress warning about unused %extra_argument variable */
    + }
    + 
    +@@ -167909,7 +188655,7 @@ static void sqlite3Fts5Parser(
    +   sqlite3Fts5ParserARG_PDECL               /* Optional %extra_argument parameter */
    + ){
    +   fts5YYMINORTYPE fts5yyminorunion;
    +-  int fts5yyact;            /* The parser action. */
    ++  unsigned int fts5yyact;   /* The parser action. */
    + #if !defined(fts5YYERRORSYMBOL) && !defined(fts5YYNOERRORRECOVERY)
    +   int fts5yyendofinput;     /* True if we are at the end of input */
    + #endif
    +@@ -167918,23 +188664,8 @@ static void sqlite3Fts5Parser(
    + #endif
    +   fts5yyParser *fts5yypParser;  /* The parser */
    + 
    +-  /* (re)initialize the parser, if necessary */
    +   fts5yypParser = (fts5yyParser*)fts5yyp;
    +-  if( fts5yypParser->fts5yyidx<0 ){
    +-#if fts5YYSTACKDEPTH<=0
    +-    if( fts5yypParser->fts5yystksz <=0 ){
    +-      /*memset(&fts5yyminorunion, 0, sizeof(fts5yyminorunion));*/
    +-      fts5yyminorunion = fts5yyzerominor;
    +-      fts5yyStackOverflow(fts5yypParser, &fts5yyminorunion);
    +-      return;
    +-    }
    +-#endif
    +-    fts5yypParser->fts5yyidx = 0;
    +-    fts5yypParser->fts5yyerrcnt = -1;
    +-    fts5yypParser->fts5yystack[0].stateno = 0;
    +-    fts5yypParser->fts5yystack[0].major = 0;
    +-  }
    +-  fts5yyminorunion.fts5yy0 = fts5yyminor;
    ++  assert( fts5yypParser->fts5yytos!=0 );
    + #if !defined(fts5YYERRORSYMBOL) && !defined(fts5YYNOERRORRECOVERY)
    +   fts5yyendofinput = (fts5yymajor==0);
    + #endif
    +@@ -167942,21 +188673,34 @@ static void sqlite3Fts5Parser(
    + 
    + #ifndef NDEBUG
    +   if( fts5yyTraceFILE ){
    +-    fprintf(fts5yyTraceFILE,"%sInput %s\n",fts5yyTracePrompt,fts5yyTokenName[fts5yymajor]);
    ++    int stateno = fts5yypParser->fts5yytos->stateno;
    ++    if( stateno < fts5YY_MIN_REDUCE ){
    ++      fprintf(fts5yyTraceFILE,"%sInput '%s' in state %d\n",
    ++              fts5yyTracePrompt,fts5yyTokenName[fts5yymajor],stateno);
    ++    }else{
    ++      fprintf(fts5yyTraceFILE,"%sInput '%s' with pending reduce %d\n",
    ++              fts5yyTracePrompt,fts5yyTokenName[fts5yymajor],stateno-fts5YY_MIN_REDUCE);
    ++    }
    +   }
    + #endif
    + 
    +   do{
    +     fts5yyact = fts5yy_find_shift_action(fts5yypParser,(fts5YYCODETYPE)fts5yymajor);
    +-    if( fts5yyact <= fts5YY_MAX_SHIFTREDUCE ){
    +-      if( fts5yyact > fts5YY_MAX_SHIFT ) fts5yyact += fts5YY_MIN_REDUCE - fts5YY_MIN_SHIFTREDUCE;
    +-      fts5yy_shift(fts5yypParser,fts5yyact,fts5yymajor,&fts5yyminorunion);
    ++    if( fts5yyact >= fts5YY_MIN_REDUCE ){
    ++      fts5yy_reduce(fts5yypParser,fts5yyact-fts5YY_MIN_REDUCE,fts5yymajor,fts5yyminor);
    ++    }else if( fts5yyact <= fts5YY_MAX_SHIFTREDUCE ){
    ++      fts5yy_shift(fts5yypParser,fts5yyact,fts5yymajor,fts5yyminor);
    ++#ifndef fts5YYNOERRORRECOVERY
    +       fts5yypParser->fts5yyerrcnt--;
    ++#endif
    +       fts5yymajor = fts5YYNOCODE;
    +-    }else if( fts5yyact <= fts5YY_MAX_REDUCE ){
    +-      fts5yy_reduce(fts5yypParser,fts5yyact-fts5YY_MIN_REDUCE);
    ++    }else if( fts5yyact==fts5YY_ACCEPT_ACTION ){
    ++      fts5yypParser->fts5yytos--;
    ++      fts5yy_accept(fts5yypParser);
    ++      return;
    +     }else{
    +       assert( fts5yyact == fts5YY_ERROR_ACTION );
    ++      fts5yyminorunion.fts5yy0 = fts5yyminor;
    + #ifdef fts5YYERRORSYMBOL
    +       int fts5yymx;
    + #endif
    +@@ -167986,9 +188730,9 @@ static void sqlite3Fts5Parser(
    +       **
    +       */
    +       if( fts5yypParser->fts5yyerrcnt<0 ){
    +-        fts5yy_syntax_error(fts5yypParser,fts5yymajor,fts5yyminorunion);
    ++        fts5yy_syntax_error(fts5yypParser,fts5yymajor,fts5yyminor);
    +       }
    +-      fts5yymx = fts5yypParser->fts5yystack[fts5yypParser->fts5yyidx].major;
    ++      fts5yymx = fts5yypParser->fts5yytos->major;
    +       if( fts5yymx==fts5YYERRORSYMBOL || fts5yyerrorhit ){
    + #ifndef NDEBUG
    +         if( fts5yyTraceFILE ){
    +@@ -167996,26 +188740,26 @@ static void sqlite3Fts5Parser(
    +              fts5yyTracePrompt,fts5yyTokenName[fts5yymajor]);
    +         }
    + #endif
    +-        fts5yy_destructor(fts5yypParser, (fts5YYCODETYPE)fts5yymajor,&fts5yyminorunion);
    ++        fts5yy_destructor(fts5yypParser, (fts5YYCODETYPE)fts5yymajor, &fts5yyminorunion);
    +         fts5yymajor = fts5YYNOCODE;
    +       }else{
    +-         while(
    +-          fts5yypParser->fts5yyidx >= 0 &&
    +-          fts5yymx != fts5YYERRORSYMBOL &&
    +-          (fts5yyact = fts5yy_find_reduce_action(
    +-                        fts5yypParser->fts5yystack[fts5yypParser->fts5yyidx].stateno,
    ++        while( fts5yypParser->fts5yytos >= fts5yypParser->fts5yystack
    ++            && fts5yymx != fts5YYERRORSYMBOL
    ++            && (fts5yyact = fts5yy_find_reduce_action(
    ++                        fts5yypParser->fts5yytos->stateno,
    +                         fts5YYERRORSYMBOL)) >= fts5YY_MIN_REDUCE
    +         ){
    +           fts5yy_pop_parser_stack(fts5yypParser);
    +         }
    +-        if( fts5yypParser->fts5yyidx < 0 || fts5yymajor==0 ){
    ++        if( fts5yypParser->fts5yytos < fts5yypParser->fts5yystack || fts5yymajor==0 ){
    +           fts5yy_destructor(fts5yypParser,(fts5YYCODETYPE)fts5yymajor,&fts5yyminorunion);
    +           fts5yy_parse_failed(fts5yypParser);
    ++#ifndef fts5YYNOERRORRECOVERY
    ++          fts5yypParser->fts5yyerrcnt = -1;
    ++#endif
    +           fts5yymajor = fts5YYNOCODE;
    +         }else if( fts5yymx!=fts5YYERRORSYMBOL ){
    +-          fts5YYMINORTYPE u2;
    +-          u2.fts5YYERRSYMDT = 0;
    +-          fts5yy_shift(fts5yypParser,fts5yyact,fts5YYERRORSYMBOL,&u2);
    ++          fts5yy_shift(fts5yypParser,fts5yyact,fts5YYERRORSYMBOL,fts5yyminor);
    +         }
    +       }
    +       fts5yypParser->fts5yyerrcnt = 3;
    +@@ -168028,7 +188772,7 @@ static void sqlite3Fts5Parser(
    +       ** Applications can set this macro (for example inside %include) if
    +       ** they intend to abandon the parse upon the first syntax error seen.
    +       */
    +-      fts5yy_syntax_error(fts5yypParser,fts5yymajor,fts5yyminorunion);
    ++      fts5yy_syntax_error(fts5yypParser,fts5yymajor, fts5yyminor);
    +       fts5yy_destructor(fts5yypParser,(fts5YYCODETYPE)fts5yymajor,&fts5yyminorunion);
    +       fts5yymajor = fts5YYNOCODE;
    +       
    +@@ -168043,20 +188787,30 @@ static void sqlite3Fts5Parser(
    +       ** three input tokens have been successfully shifted.
    +       */
    +       if( fts5yypParser->fts5yyerrcnt<=0 ){
    +-        fts5yy_syntax_error(fts5yypParser,fts5yymajor,fts5yyminorunion);
    ++        fts5yy_syntax_error(fts5yypParser,fts5yymajor, fts5yyminor);
    +       }
    +       fts5yypParser->fts5yyerrcnt = 3;
    +       fts5yy_destructor(fts5yypParser,(fts5YYCODETYPE)fts5yymajor,&fts5yyminorunion);
    +       if( fts5yyendofinput ){
    +         fts5yy_parse_failed(fts5yypParser);
    ++#ifndef fts5YYNOERRORRECOVERY
    ++        fts5yypParser->fts5yyerrcnt = -1;
    ++#endif
    +       }
    +       fts5yymajor = fts5YYNOCODE;
    + #endif
    +     }
    +-  }while( fts5yymajor!=fts5YYNOCODE && fts5yypParser->fts5yyidx>=0 );
    ++  }while( fts5yymajor!=fts5YYNOCODE && fts5yypParser->fts5yytos>fts5yypParser->fts5yystack );
    + #ifndef NDEBUG
    +   if( fts5yyTraceFILE ){
    +-    fprintf(fts5yyTraceFILE,"%sReturn\n",fts5yyTracePrompt);
    ++    fts5yyStackEntry *i;
    ++    char cDiv = '[';
    ++    fprintf(fts5yyTraceFILE,"%sReturn. Stack=",fts5yyTracePrompt);
    ++    for(i=&fts5yypParser->fts5yystack[1]; i<=fts5yypParser->fts5yytos; i++){
    ++      fprintf(fts5yyTraceFILE,"%c%s", cDiv, fts5yyTokenName[i->major]);
    ++      cDiv = ' ';
    ++    }
    ++    fprintf(fts5yyTraceFILE,"]\n");
    +   }
    + #endif
    +   return;
    +@@ -168076,6 +188830,7 @@ static void sqlite3Fts5Parser(
    + */
    + 
    + 
    ++/* #include "fts5Int.h" */
    + #include <math.h>                 /* amalgamator: keep */
    + 
    + /*
    +@@ -168200,7 +188955,7 @@ static void fts5HighlightAppend(
    +   const char *z, int n
    + ){
    +   if( *pRc==SQLITE_OK ){
    +-    if( n<0 ) n = strlen(z);
    ++    if( n<0 ) n = (int)strlen(z);
    +     p->zOut = sqlite3_mprintf("%z%.*s", p->zOut, n, z);
    +     if( p->zOut==0 ) *pRc = SQLITE_NOMEM;
    +   }
    +@@ -168221,6 +188976,8 @@ static int fts5HighlightCb(
    +   int rc = SQLITE_OK;
    +   int iPos;
    + 
    ++  UNUSED_PARAM2(pToken, nToken);
    ++
    +   if( tflags & FTS5_TOKEN_COLOCATED ) return SQLITE_OK;
    +   iPos = p->iPos++;
    + 
    +@@ -168250,7 +189007,7 @@ static int fts5HighlightCb(
    +   if( p->iRangeEnd>0 && iPos==p->iRangeEnd ){
    +     fts5HighlightAppend(&rc, p, &p->zIn[p->iOff], iEndOff - p->iOff);
    +     p->iOff = iEndOff;
    +-    if( iPos<p->iter.iEnd ){
    ++    if( iPos>=p->iter.iStart && iPos<p->iter.iEnd ){
    +       fts5HighlightAppend(&rc, p, p->zClose, -1);
    +     }
    +   }
    +@@ -168307,6 +189064,128 @@ static void fts5HighlightFunction(
    + ** End of highlight() implementation.
    + **************************************************************************/
    + 
    ++/*
    ++** Context object passed to the fts5SentenceFinderCb() function.
    ++*/
    ++typedef struct Fts5SFinder Fts5SFinder;
    ++struct Fts5SFinder {
    ++  int iPos;                       /* Current token position */
    ++  int nFirstAlloc;                /* Allocated size of aFirst[] */
    ++  int nFirst;                     /* Number of entries in aFirst[] */
    ++  int *aFirst;                    /* Array of first token in each sentence */
    ++  const char *zDoc;               /* Document being tokenized */
    ++};
    ++
    ++/*
    ++** Add an entry to the Fts5SFinder.aFirst[] array. Grow the array if
    ++** necessary. Return SQLITE_OK if successful, or SQLITE_NOMEM if an
    ++** error occurs.
    ++*/
    ++static int fts5SentenceFinderAdd(Fts5SFinder *p, int iAdd){
    ++  if( p->nFirstAlloc==p->nFirst ){
    ++    int nNew = p->nFirstAlloc ? p->nFirstAlloc*2 : 64;
    ++    int *aNew;
    ++
    ++    aNew = (int*)sqlite3_realloc(p->aFirst, nNew*sizeof(int));
    ++    if( aNew==0 ) return SQLITE_NOMEM;
    ++    p->aFirst = aNew;
    ++    p->nFirstAlloc = nNew;
    ++  }
    ++  p->aFirst[p->nFirst++] = iAdd;
    ++  return SQLITE_OK;
    ++}
    ++
    ++/*
    ++** This function is an xTokenize() callback used by the auxiliary snippet()
    ++** function. Its job is to identify tokens that are the first in a sentence.
    ++** For each such token, an entry is added to the SFinder.aFirst[] array.
    ++*/
    ++static int fts5SentenceFinderCb(
    ++  void *pContext,                 /* Pointer to HighlightContext object */
    ++  int tflags,                     /* Mask of FTS5_TOKEN_* flags */
    ++  const char *pToken,             /* Buffer containing token */
    ++  int nToken,                     /* Size of token in bytes */
    ++  int iStartOff,                  /* Start offset of token */
    ++  int iEndOff                     /* End offset of token */
    ++){
    ++  int rc = SQLITE_OK;
    ++
    ++  UNUSED_PARAM2(pToken, nToken);
    ++  UNUSED_PARAM(iEndOff);
    ++
    ++  if( (tflags & FTS5_TOKEN_COLOCATED)==0 ){
    ++    Fts5SFinder *p = (Fts5SFinder*)pContext;
    ++    if( p->iPos>0 ){
    ++      int i;
    ++      char c = 0;
    ++      for(i=iStartOff-1; i>=0; i--){
    ++        c = p->zDoc[i];
    ++        if( c!=' ' && c!='\t' && c!='\n' && c!='\r' ) break;
    ++      }
    ++      if( i!=iStartOff-1 && (c=='.' || c==':') ){
    ++        rc = fts5SentenceFinderAdd(p, p->iPos);
    ++      }
    ++    }else{
    ++      rc = fts5SentenceFinderAdd(p, 0);
    ++    }
    ++    p->iPos++;
    ++  }
    ++  return rc;
    ++}
    ++
    ++static int fts5SnippetScore(
    ++  const Fts5ExtensionApi *pApi,   /* API offered by current FTS version */
    ++  Fts5Context *pFts,              /* First arg to pass to pApi functions */
    ++  int nDocsize,                   /* Size of column in tokens */
    ++  unsigned char *aSeen,           /* Array with one element per query phrase */
    ++  int iCol,                       /* Column to score */
    ++  int iPos,                       /* Starting offset to score */
    ++  int nToken,                     /* Max tokens per snippet */
    ++  int *pnScore,                   /* OUT: Score */
    ++  int *piPos                      /* OUT: Adjusted offset */
    ++){
    ++  int rc;
    ++  int i;
    ++  int ip = 0;
    ++  int ic = 0;
    ++  int iOff = 0;
    ++  int iFirst = -1;
    ++  int nInst;
    ++  int nScore = 0;
    ++  int iLast = 0;
    ++
    ++  rc = pApi->xInstCount(pFts, &nInst);
    ++  for(i=0; i<nInst && rc==SQLITE_OK; i++){
    ++    rc = pApi->xInst(pFts, i, &ip, &ic, &iOff);
    ++    if( rc==SQLITE_OK && ic==iCol && iOff>=iPos && iOff<(iPos+nToken) ){
    ++      nScore += (aSeen[ip] ? 1 : 1000);
    ++      aSeen[ip] = 1;
    ++      if( iFirst<0 ) iFirst = iOff;
    ++      iLast = iOff + pApi->xPhraseSize(pFts, ip);
    ++    }
    ++  }
    ++
    ++  *pnScore = nScore;
    ++  if( piPos ){
    ++    int iAdj = iFirst - (nToken - (iLast-iFirst)) / 2;
    ++    if( (iAdj+nToken)>nDocsize ) iAdj = nDocsize - nToken;
    ++    if( iAdj<0 ) iAdj = 0;
    ++    *piPos = iAdj;
    ++  }
    ++
    ++  return rc;
    ++}
    ++
    ++/*
    ++** Return the value in pVal interpreted as utf-8 text. Except, if pVal 
    ++** contains a NULL value, return a pointer to a static string zero
    ++** bytes in length instead of a NULL pointer.
    ++*/
    ++static const char *fts5ValueToText(sqlite3_value *pVal){
    ++  const char *zRet = (const char*)sqlite3_value_text(pVal);
    ++  return zRet ? zRet : "";
    ++}
    ++
    + /*
    + ** Implementation of snippet() function.
    + */
    +@@ -168328,9 +189207,10 @@ static void fts5SnippetFunction(
    +   unsigned char *aSeen;           /* Array of "seen instance" flags */
    +   int iBestCol;                   /* Column containing best snippet */
    +   int iBestStart = 0;             /* First token of best snippet */
    +-  int iBestLast;                  /* Last token of best snippet */
    +   int nBestScore = 0;             /* Score of best snippet */
    +   int nColSize = 0;               /* Total size of iBestCol in tokens */
    ++  Fts5SFinder sFinder;            /* Used to find the beginnings of sentences */
    ++  int nCol;
    + 
    +   if( nVal!=5 ){
    +     const char *zErr = "wrong number of arguments to function snippet()";
    +@@ -168338,13 +189218,13 @@ static void fts5SnippetFunction(
    +     return;
    +   }
    + 
    ++  nCol = pApi->xColumnCount(pFts);
    +   memset(&ctx, 0, sizeof(HighlightContext));
    +   iCol = sqlite3_value_int(apVal[0]);
    +-  ctx.zOpen = (const char*)sqlite3_value_text(apVal[1]);
    +-  ctx.zClose = (const char*)sqlite3_value_text(apVal[2]);
    +-  zEllips = (const char*)sqlite3_value_text(apVal[3]);
    ++  ctx.zOpen = fts5ValueToText(apVal[1]);
    ++  ctx.zClose = fts5ValueToText(apVal[2]);
    ++  zEllips = fts5ValueToText(apVal[3]);
    +   nToken = sqlite3_value_int(apVal[4]);
    +-  iBestLast = nToken-1;
    + 
    +   iBestCol = (iCol>=0 ? iCol : 0);
    +   nPhrase = pApi->xPhraseCount(pFts);
    +@@ -168352,65 +189232,94 @@ static void fts5SnippetFunction(
    +   if( aSeen==0 ){
    +     rc = SQLITE_NOMEM;
    +   }
    +-
    +   if( rc==SQLITE_OK ){
    +     rc = pApi->xInstCount(pFts, &nInst);
    +   }
    +-  for(i=0; rc==SQLITE_OK && i<nInst; i++){
    +-    int ip, iSnippetCol, iStart;
    +-    memset(aSeen, 0, nPhrase);
    +-    rc = pApi->xInst(pFts, i, &ip, &iSnippetCol, &iStart);
    +-    if( rc==SQLITE_OK && (iCol<0 || iSnippetCol==iCol) ){
    +-      int nScore = 1000;
    +-      int iLast = iStart - 1 + pApi->xPhraseSize(pFts, ip);
    +-      int j;
    +-      aSeen[ip] = 1;
    + 
    +-      for(j=i+1; rc==SQLITE_OK && j<nInst; j++){
    +-        int ic; int io; int iFinal;
    +-        rc = pApi->xInst(pFts, j, &ip, &ic, &io);
    +-        iFinal = io + pApi->xPhraseSize(pFts, ip) - 1;
    +-        if( rc==SQLITE_OK && ic==iSnippetCol && iLast<iStart+nToken ){
    +-          nScore += aSeen[ip] ? 1000 : 1;
    +-          aSeen[ip] = 1;
    +-          if( iFinal>iLast ) iLast = iFinal;
    ++  memset(&sFinder, 0, sizeof(Fts5SFinder));
    ++  for(i=0; i<nCol; i++){
    ++    if( iCol<0 || iCol==i ){
    ++      int nDoc;
    ++      int nDocsize;
    ++      int ii;
    ++      sFinder.iPos = 0;
    ++      sFinder.nFirst = 0;
    ++      rc = pApi->xColumnText(pFts, i, &sFinder.zDoc, &nDoc);
    ++      if( rc!=SQLITE_OK ) break;
    ++      rc = pApi->xTokenize(pFts, 
    ++          sFinder.zDoc, nDoc, (void*)&sFinder,fts5SentenceFinderCb
    ++      );
    ++      if( rc!=SQLITE_OK ) break;
    ++      rc = pApi->xColumnSize(pFts, i, &nDocsize);
    ++      if( rc!=SQLITE_OK ) break;
    ++
    ++      for(ii=0; rc==SQLITE_OK && ii<nInst; ii++){
    ++        int ip, ic, io;
    ++        int iAdj;
    ++        int nScore;
    ++        int jj;
    ++
    ++        rc = pApi->xInst(pFts, ii, &ip, &ic, &io);
    ++        if( ic!=i || rc!=SQLITE_OK ) continue;
    ++        memset(aSeen, 0, nPhrase);
    ++        rc = fts5SnippetScore(pApi, pFts, nDocsize, aSeen, i,
    ++            io, nToken, &nScore, &iAdj
    ++        );
    ++        if( rc==SQLITE_OK && nScore>nBestScore ){
    ++          nBestScore = nScore;
    ++          iBestCol = i;
    ++          iBestStart = iAdj;
    ++          nColSize = nDocsize;
    +         }
    +-      }
    + 
    +-      if( rc==SQLITE_OK && nScore>nBestScore ){
    +-        iBestCol = iSnippetCol;
    +-        iBestStart = iStart;
    +-        iBestLast = iLast;
    +-        nBestScore = nScore;
    ++        if( rc==SQLITE_OK && sFinder.nFirst && nDocsize>nToken ){
    ++          for(jj=0; jj<(sFinder.nFirst-1); jj++){
    ++            if( sFinder.aFirst[jj+1]>io ) break;
    ++          }
    ++
    ++          if( sFinder.aFirst[jj]<io ){
    ++            memset(aSeen, 0, nPhrase);
    ++            rc = fts5SnippetScore(pApi, pFts, nDocsize, aSeen, i, 
    ++              sFinder.aFirst[jj], nToken, &nScore, 0
    ++            );
    ++
    ++            nScore += (sFinder.aFirst[jj]==0 ? 120 : 100);
    ++            if( rc==SQLITE_OK && nScore>nBestScore ){
    ++              nBestScore = nScore;
    ++              iBestCol = i;
    ++              iBestStart = sFinder.aFirst[jj];
    ++              nColSize = nDocsize;
    ++            }
    ++          }
    ++        }
    +       }
    +     }
    +   }
    + 
    +-  if( rc==SQLITE_OK ){
    +-    rc = pApi->xColumnSize(pFts, iBestCol, &nColSize);
    +-  }
    +   if( rc==SQLITE_OK ){
    +     rc = pApi->xColumnText(pFts, iBestCol, &ctx.zIn, &ctx.nIn);
    +   }
    ++  if( rc==SQLITE_OK && nColSize==0 ){
    ++    rc = pApi->xColumnSize(pFts, iBestCol, &nColSize);
    ++  }
    +   if( ctx.zIn ){
    +     if( rc==SQLITE_OK ){
    +       rc = fts5CInstIterInit(pApi, pFts, iBestCol, &ctx.iter);
    +     }
    + 
    +-    if( (iBestStart+nToken-1)>iBestLast ){
    +-      iBestStart -= (iBestStart+nToken-1-iBestLast) / 2;
    +-    }
    +-    if( iBestStart+nToken>nColSize ){
    +-      iBestStart = nColSize - nToken;
    +-    }
    +-    if( iBestStart<0 ) iBestStart = 0;
    +-
    +     ctx.iRangeStart = iBestStart;
    +     ctx.iRangeEnd = iBestStart + nToken - 1;
    + 
    +     if( iBestStart>0 ){
    +       fts5HighlightAppend(&rc, &ctx, zEllips, -1);
    +     }
    ++
    ++    /* Advance iterator ctx.iter so that it points to the first coalesced
    ++    ** phrase instance at or following position iBestStart. */
    ++    while( ctx.iter.iStart>=0 && ctx.iter.iStart<iBestStart && rc==SQLITE_OK ){
    ++      rc = fts5CInstIterNext(&ctx.iter);
    ++    }
    ++
    +     if( rc==SQLITE_OK ){
    +       rc = pApi->xTokenize(pFts, ctx.zIn, ctx.nIn, (void*)&ctx,fts5HighlightCb);
    +     }
    +@@ -168419,15 +189328,15 @@ static void fts5SnippetFunction(
    +     }else{
    +       fts5HighlightAppend(&rc, &ctx, zEllips, -1);
    +     }
    +-
    +-    if( rc==SQLITE_OK ){
    +-      sqlite3_result_text(pCtx, (const char*)ctx.zOut, -1, SQLITE_TRANSIENT);
    +-    }else{
    +-      sqlite3_result_error_code(pCtx, rc);
    +-    }
    +-    sqlite3_free(ctx.zOut);
    +   }
    ++  if( rc==SQLITE_OK ){
    ++    sqlite3_result_text(pCtx, (const char*)ctx.zOut, -1, SQLITE_TRANSIENT);
    ++  }else{
    ++    sqlite3_result_error_code(pCtx, rc);
    ++  }
    ++  sqlite3_free(ctx.zOut);
    +   sqlite3_free(aSeen);
    ++  sqlite3_free(sFinder.aFirst);
    + }
    + 
    + /************************************************************************/
    +@@ -168454,6 +189363,7 @@ static int fts5CountCb(
    +   void *pUserData                 /* Pointer to sqlite3_int64 variable */
    + ){
    +   sqlite3_int64 *pn = (sqlite3_int64*)pUserData;
    ++  UNUSED_PARAM2(pApi, pFts);
    +   (*pn)++;
    +   return SQLITE_OK;
    + }
    +@@ -168607,7 +189517,7 @@ static int sqlite3Fts5AuxInit(fts5_api *pApi){
    +   int rc = SQLITE_OK;             /* Return code */
    +   int i;                          /* To iterate through builtin functions */
    + 
    +-  for(i=0; rc==SQLITE_OK && i<sizeof(aBuiltin)/sizeof(aBuiltin[0]); i++){
    ++  for(i=0; rc==SQLITE_OK && i<ArraySize(aBuiltin); i++){
    +     rc = pApi->xCreateFunction(pApi,
    +         aBuiltin[i].zFunc,
    +         aBuiltin[i].pUserData,
    +@@ -168636,17 +189546,13 @@ static int sqlite3Fts5AuxInit(fts5_api *pApi){
    + 
    + 
    + 
    ++/* #include "fts5Int.h" */
    + 
    +-static int sqlite3Fts5BufferGrow(int *pRc, Fts5Buffer *pBuf, int nByte){
    +-
    +-  if( (pBuf->n + nByte) > pBuf->nSpace ){
    ++static int sqlite3Fts5BufferSize(int *pRc, Fts5Buffer *pBuf, u32 nByte){
    ++  if( (u32)pBuf->nSpace<nByte ){
    ++    u32 nNew = pBuf->nSpace ? pBuf->nSpace : 64;
    +     u8 *pNew;
    +-    int nNew = pBuf->nSpace ? pBuf->nSpace*2 : 64;
    +-
    +-    /* A no-op if an error has already occurred */
    +-    if( *pRc ) return 1;
    +-
    +-    while( nNew<(pBuf->n + nByte) ){
    ++    while( nNew<nByte ){
    +       nNew = nNew * 2;
    +     }
    +     pNew = sqlite3_realloc(pBuf->p, nNew);
    +@@ -168661,12 +189567,13 @@ static int sqlite3Fts5BufferGrow(int *pRc, Fts5Buffer *pBuf, int nByte){
    +   return 0;
    + }
    + 
    ++
    + /*
    + ** Encode value iVal as an SQLite varint and append it to the buffer object
    + ** pBuf. If an OOM error occurs, set the error code in p.
    + */
    + static void sqlite3Fts5BufferAppendVarint(int *pRc, Fts5Buffer *pBuf, i64 iVal){
    +-  if( sqlite3Fts5BufferGrow(pRc, pBuf, 9) ) return;
    ++  if( fts5BufferGrow(pRc, pBuf, 9) ) return;
    +   pBuf->n += sqlite3Fts5PutVarint(&pBuf->p[pBuf->n], iVal);
    + }
    + 
    +@@ -168681,12 +189588,6 @@ static int sqlite3Fts5Get32(const u8 *aBuf){
    +   return (aBuf[0] << 24) + (aBuf[1] << 16) + (aBuf[2] << 8) + aBuf[3];
    + }
    + 
    +-static void sqlite3Fts5BufferAppend32(int *pRc, Fts5Buffer *pBuf, int iVal){
    +-  if( sqlite3Fts5BufferGrow(pRc, pBuf, 4) ) return;
    +-  sqlite3Fts5Put32(&pBuf->p[pBuf->n], iVal);
    +-  pBuf->n += 4;
    +-}
    +-
    + /*
    + ** Append buffer nData/pData to buffer pBuf. If an OOM error occurs, set 
    + ** the error code in p. If an error has already occurred when this function
    +@@ -168695,13 +189596,15 @@ static void sqlite3Fts5BufferAppend32(int *pRc, Fts5Buffer *pBuf, int iVal){
    + static void sqlite3Fts5BufferAppendBlob(
    +   int *pRc,
    +   Fts5Buffer *pBuf, 
    +-  int nData, 
    ++  u32 nData, 
    +   const u8 *pData
    + ){
    +-  assert( *pRc || nData>=0 );
    +-  if( sqlite3Fts5BufferGrow(pRc, pBuf, nData) ) return;
    +-  memcpy(&pBuf->p[pBuf->n], pData, nData);
    +-  pBuf->n += nData;
    ++  assert_nc( *pRc || nData>=0 );
    ++  if( nData ){
    ++    if( fts5BufferGrow(pRc, pBuf, nData) ) return;
    ++    memcpy(&pBuf->p[pBuf->n], pData, nData);
    ++    pBuf->n += nData;
    ++  }
    + }
    + 
    + /*
    +@@ -168714,7 +189617,7 @@ static void sqlite3Fts5BufferAppendString(
    +   Fts5Buffer *pBuf, 
    +   const char *zStr
    + ){
    +-  int nStr = strlen(zStr);
    ++  int nStr = (int)strlen(zStr);
    +   sqlite3Fts5BufferAppendBlob(pRc, pBuf, nStr+1, (const u8*)zStr);
    +   pBuf->n--;
    + }
    +@@ -168842,31 +189745,44 @@ static int sqlite3Fts5PoslistReaderInit(
    +   return pIter->bEof;
    + }
    + 
    +-static int sqlite3Fts5PoslistWriterAppend(
    ++/*
    ++** Append position iPos to the position list being accumulated in buffer
    ++** pBuf, which must be already be large enough to hold the new data.
    ++** The previous position written to this list is *piPrev. *piPrev is set
    ++** to iPos before returning.
    ++*/
    ++static void sqlite3Fts5PoslistSafeAppend(
    +   Fts5Buffer *pBuf, 
    +-  Fts5PoslistWriter *pWriter,
    ++  i64 *piPrev, 
    +   i64 iPos
    + ){
    +   static const i64 colmask = ((i64)(0x7FFFFFFF)) << 32;
    +-  int rc = SQLITE_OK;
    +-  if( 0==sqlite3Fts5BufferGrow(&rc, pBuf, 5+5+5) ){
    +-    if( (iPos & colmask) != (pWriter->iPrev & colmask) ){
    +-      pBuf->p[pBuf->n++] = 1;
    +-      pBuf->n += sqlite3Fts5PutVarint(&pBuf->p[pBuf->n], (iPos>>32));
    +-      pWriter->iPrev = (iPos & colmask);
    +-    }
    +-    pBuf->n += sqlite3Fts5PutVarint(&pBuf->p[pBuf->n], (iPos-pWriter->iPrev)+2);
    +-    pWriter->iPrev = iPos;
    ++  if( (iPos & colmask) != (*piPrev & colmask) ){
    ++    pBuf->p[pBuf->n++] = 1;
    ++    pBuf->n += sqlite3Fts5PutVarint(&pBuf->p[pBuf->n], (iPos>>32));
    ++    *piPrev = (iPos & colmask);
    +   }
    +-  return rc;
    ++  pBuf->n += sqlite3Fts5PutVarint(&pBuf->p[pBuf->n], (iPos-*piPrev)+2);
    ++  *piPrev = iPos;
    ++}
    ++
    ++static int sqlite3Fts5PoslistWriterAppend(
    ++  Fts5Buffer *pBuf, 
    ++  Fts5PoslistWriter *pWriter,
    ++  i64 iPos
    ++){
    ++  int rc = 0;   /* Initialized only to suppress erroneous warning from Clang */
    ++  if( fts5BufferGrow(&rc, pBuf, 5+5+5) ) return rc;
    ++  sqlite3Fts5PoslistSafeAppend(pBuf, &pWriter->iPrev, iPos);
    ++  return SQLITE_OK;
    + }
    + 
    + static void *sqlite3Fts5MallocZero(int *pRc, int nByte){
    +   void *pRet = 0;
    +   if( *pRc==SQLITE_OK ){
    +     pRet = sqlite3_malloc(nByte);
    +-    if( pRet==0 && nByte>0 ){
    +-      *pRc = SQLITE_NOMEM;
    ++    if( pRet==0 ){
    ++      if( nByte>0 ) *pRc = SQLITE_NOMEM;
    +     }else{
    +       memset(pRet, 0, nByte);
    +     }
    +@@ -168886,7 +189802,7 @@ static char *sqlite3Fts5Strndup(int *pRc, const char *pIn, int nIn){
    +   char *zRet = 0;
    +   if( *pRc==SQLITE_OK ){
    +     if( nIn<0 ){
    +-      nIn = strlen(pIn);
    ++      nIn = (int)strlen(pIn);
    +     }
    +     zRet = (char*)sqlite3_malloc(nIn+1);
    +     if( zRet ){
    +@@ -168926,6 +189842,89 @@ static int sqlite3Fts5IsBareword(char t){
    + }
    + 
    + 
    ++/*************************************************************************
    ++*/
    ++typedef struct Fts5TermsetEntry Fts5TermsetEntry;
    ++struct Fts5TermsetEntry {
    ++  char *pTerm;
    ++  int nTerm;
    ++  int iIdx;                       /* Index (main or aPrefix[] entry) */
    ++  Fts5TermsetEntry *pNext;
    ++};
    ++
    ++struct Fts5Termset {
    ++  Fts5TermsetEntry *apHash[512];
    ++};
    ++
    ++static int sqlite3Fts5TermsetNew(Fts5Termset **pp){
    ++  int rc = SQLITE_OK;
    ++  *pp = sqlite3Fts5MallocZero(&rc, sizeof(Fts5Termset));
    ++  return rc;
    ++}
    ++
    ++static int sqlite3Fts5TermsetAdd(
    ++  Fts5Termset *p, 
    ++  int iIdx,
    ++  const char *pTerm, int nTerm, 
    ++  int *pbPresent
    ++){
    ++  int rc = SQLITE_OK;
    ++  *pbPresent = 0;
    ++  if( p ){
    ++    int i;
    ++    u32 hash = 13;
    ++    Fts5TermsetEntry *pEntry;
    ++
    ++    /* Calculate a hash value for this term. This is the same hash checksum
    ++    ** used by the fts5_hash.c module. This is not important for correct
    ++    ** operation of the module, but is necessary to ensure that some tests
    ++    ** designed to produce hash table collisions really do work.  */
    ++    for(i=nTerm-1; i>=0; i--){
    ++      hash = (hash << 3) ^ hash ^ pTerm[i];
    ++    }
    ++    hash = (hash << 3) ^ hash ^ iIdx;
    ++    hash = hash % ArraySize(p->apHash);
    ++
    ++    for(pEntry=p->apHash[hash]; pEntry; pEntry=pEntry->pNext){
    ++      if( pEntry->iIdx==iIdx 
    ++          && pEntry->nTerm==nTerm 
    ++          && memcmp(pEntry->pTerm, pTerm, nTerm)==0 
    ++      ){
    ++        *pbPresent = 1;
    ++        break;
    ++      }
    ++    }
    ++
    ++    if( pEntry==0 ){
    ++      pEntry = sqlite3Fts5MallocZero(&rc, sizeof(Fts5TermsetEntry) + nTerm);
    ++      if( pEntry ){
    ++        pEntry->pTerm = (char*)&pEntry[1];
    ++        pEntry->nTerm = nTerm;
    ++        pEntry->iIdx = iIdx;
    ++        memcpy(pEntry->pTerm, pTerm, nTerm);
    ++        pEntry->pNext = p->apHash[hash];
    ++        p->apHash[hash] = pEntry;
    ++      }
    ++    }
    ++  }
    ++
    ++  return rc;
    ++}
    ++
    ++static void sqlite3Fts5TermsetFree(Fts5Termset *p){
    ++  if( p ){
    ++    u32 i;
    ++    for(i=0; i<ArraySize(p->apHash); i++){
    ++      Fts5TermsetEntry *pEntry = p->apHash[i];
    ++      while( pEntry ){
    ++        Fts5TermsetEntry *pDel = pEntry;
    ++        pEntry = pEntry->pNext;
    ++        sqlite3_free(pDel);
    ++      }
    ++    }
    ++    sqlite3_free(p);
    ++  }
    ++}
    + 
    + /*
    + ** 2014 Jun 09
    +@@ -168943,11 +189942,13 @@ static int sqlite3Fts5IsBareword(char t){
    + */
    + 
    + 
    +-
    ++/* #include "fts5Int.h" */
    + 
    + #define FTS5_DEFAULT_PAGE_SIZE   4050
    + #define FTS5_DEFAULT_AUTOMERGE      4
    ++#define FTS5_DEFAULT_USERMERGE      4
    + #define FTS5_DEFAULT_CRISISMERGE   16
    ++#define FTS5_DEFAULT_HASHSIZE    (1024*1024)
    + 
    + /* Maximum allowed page size */
    + #define FTS5_MAX_PAGE_SIZE (128*1024)
    +@@ -169122,6 +190123,33 @@ static void sqlite3Fts5Dequote(char *z){
    +   }
    + }
    + 
    ++
    ++struct Fts5Enum {
    ++  const char *zName;
    ++  int eVal;
    ++};
    ++typedef struct Fts5Enum Fts5Enum;
    ++
    ++static int fts5ConfigSetEnum(
    ++  const Fts5Enum *aEnum, 
    ++  const char *zEnum, 
    ++  int *peVal
    ++){
    ++  int nEnum = (int)strlen(zEnum);
    ++  int i;
    ++  int iVal = -1;
    ++
    ++  for(i=0; aEnum[i].zName; i++){
    ++    if( sqlite3_strnicmp(aEnum[i].zName, zEnum, nEnum)==0 ){
    ++      if( iVal>=0 ) return SQLITE_ERROR;
    ++      iVal = aEnum[i].eVal;
    ++    }
    ++  }
    ++
    ++  *peVal = iVal;
    ++  return iVal<0 ? SQLITE_ERROR : SQLITE_OK;
    ++}
    ++
    + /*
    + ** Parse a "special" CREATE VIRTUAL TABLE directive and update
    + ** configuration object pConfig as appropriate.
    +@@ -169139,44 +190167,63 @@ static int fts5ConfigParseSpecial(
    +   char **pzErr                    /* OUT: Error message */
    + ){
    +   int rc = SQLITE_OK;
    +-  int nCmd = strlen(zCmd);
    ++  int nCmd = (int)strlen(zCmd);
    +   if( sqlite3_strnicmp("prefix", zCmd, nCmd)==0 ){
    +     const int nByte = sizeof(int) * FTS5_MAX_PREFIX_INDEXES;
    +     const char *p;
    +-    if( pConfig->aPrefix ){
    +-      *pzErr = sqlite3_mprintf("multiple prefix=... directives");
    +-      rc = SQLITE_ERROR;
    +-    }else{
    ++    int bFirst = 1;
    ++    if( pConfig->aPrefix==0 ){
    +       pConfig->aPrefix = sqlite3Fts5MallocZero(&rc, nByte);
    ++      if( rc ) return rc;
    +     }
    ++
    +     p = zArg;
    +-    while( rc==SQLITE_OK && p[0] ){
    ++    while( 1 ){
    +       int nPre = 0;
    ++
    +       while( p[0]==' ' ) p++;
    +-      while( p[0]>='0' && p[0]<='9' && nPre<1000 ){
    +-        nPre = nPre*10 + (p[0] - '0');
    ++      if( bFirst==0 && p[0]==',' ){
    +         p++;
    ++        while( p[0]==' ' ) p++;
    ++      }else if( p[0]=='\0' ){
    ++        break;
    +       }
    +-      while( p[0]==' ' ) p++;
    +-      if( p[0]==',' ){
    +-        p++;
    +-      }else if( p[0] ){
    ++      if( p[0]<'0' || p[0]>'9' ){
    +         *pzErr = sqlite3_mprintf("malformed prefix=... directive");
    +         rc = SQLITE_ERROR;
    ++        break;
    +       }
    +-      if( rc==SQLITE_OK && (nPre==0 || nPre>=1000) ){
    +-        *pzErr = sqlite3_mprintf("prefix length out of range: %d", nPre);
    ++
    ++      if( pConfig->nPrefix==FTS5_MAX_PREFIX_INDEXES ){
    ++        *pzErr = sqlite3_mprintf(
    ++            "too many prefix indexes (max %d)", FTS5_MAX_PREFIX_INDEXES
    ++        );
    +         rc = SQLITE_ERROR;
    ++        break;
    +       }
    ++
    ++      while( p[0]>='0' && p[0]<='9' && nPre<1000 ){
    ++        nPre = nPre*10 + (p[0] - '0');
    ++        p++;
    ++      }
    ++
    ++      if( nPre<=0 || nPre>=1000 ){
    ++        *pzErr = sqlite3_mprintf("prefix length out of range (max 999)");
    ++        rc = SQLITE_ERROR;
    ++        break;
    ++      }
    ++
    +       pConfig->aPrefix[pConfig->nPrefix] = nPre;
    +       pConfig->nPrefix++;
    ++      bFirst = 0;
    +     }
    ++    assert( pConfig->nPrefix<=FTS5_MAX_PREFIX_INDEXES );
    +     return rc;
    +   }
    + 
    +   if( sqlite3_strnicmp("tokenize", zCmd, nCmd)==0 ){
    +     const char *p = (const char*)zArg;
    +-    int nArg = strlen(zArg) + 1;
    ++    int nArg = (int)strlen(zArg) + 1;
    +     char **azArg = sqlite3Fts5MallocZero(&rc, sizeof(char*) * nArg);
    +     char *pDel = sqlite3Fts5MallocZero(&rc, nArg * 2);
    +     char *pSpace = pDel;
    +@@ -169253,6 +190300,20 @@ static int fts5ConfigParseSpecial(
    +     return rc;
    +   }
    + 
    ++  if( sqlite3_strnicmp("detail", zCmd, nCmd)==0 ){
    ++    const Fts5Enum aDetail[] = {
    ++      { "none", FTS5_DETAIL_NONE },
    ++      { "full", FTS5_DETAIL_FULL },
    ++      { "columns", FTS5_DETAIL_COLUMNS },
    ++      { 0, 0 }
    ++    };
    ++
    ++    if( (rc = fts5ConfigSetEnum(aDetail, zArg, &pConfig->eDetail)) ){
    ++      *pzErr = sqlite3_mprintf("malformed detail=... directive");
    ++    }
    ++    return rc;
    ++  }
    ++
    +   *pzErr = sqlite3_mprintf("unrecognized option: \"%.*s\"", nCmd, zCmd);
    +   return SQLITE_ERROR;
    + }
    +@@ -169292,7 +190353,7 @@ static const char *fts5ConfigGobbleWord(
    + ){
    +   const char *zRet = 0;
    + 
    +-  int nIn = strlen(zIn);
    ++  int nIn = (int)strlen(zIn);
    +   char *zOut = sqlite3_malloc(nIn+1);
    + 
    +   assert( *pRc==SQLITE_OK );
    +@@ -169309,7 +190370,9 @@ static const char *fts5ConfigGobbleWord(
    +       *pbQuoted = 1;
    +     }else{
    +       zRet = fts5ConfigSkipBareword(zIn);
    +-      zOut[zRet-zIn] = '\0';
    ++      if( zRet ){
    ++        zOut[zRet-zIn] = '\0';
    ++      }
    +     }
    +   }
    + 
    +@@ -169408,6 +190471,7 @@ static int sqlite3Fts5ConfigParse(
    +   pRet->zDb = sqlite3Fts5Strndup(&rc, azArg[1], -1);
    +   pRet->zName = sqlite3Fts5Strndup(&rc, azArg[2], -1);
    +   pRet->bColumnsize = 1;
    ++  pRet->eDetail = FTS5_DETAIL_FULL;
    + #ifdef SQLITE_DEBUG
    +   pRet->bPrefixIndex = 1;
    + #endif
    +@@ -169634,33 +190698,37 @@ static int sqlite3Fts5ConfigParseRank(
    +   *pzRank = 0;
    +   *pzRankArgs = 0;
    + 
    +-  p = fts5ConfigSkipWhitespace(p);
    +-  pRank = p;
    +-  p = fts5ConfigSkipBareword(p);
    +-
    +-  if( p ){
    +-    zRank = sqlite3Fts5MallocZero(&rc, 1 + p - pRank);
    +-    if( zRank ) memcpy(zRank, pRank, p-pRank);
    +-  }else{
    ++  if( p==0 ){
    +     rc = SQLITE_ERROR;
    +-  }
    +-
    +-  if( rc==SQLITE_OK ){
    +-    p = fts5ConfigSkipWhitespace(p);
    +-    if( *p!='(' ) rc = SQLITE_ERROR;
    +-    p++;
    +-  }
    +-  if( rc==SQLITE_OK ){
    +-    const char *pArgs; 
    ++  }else{
    +     p = fts5ConfigSkipWhitespace(p);
    +-    pArgs = p;
    +-    if( *p!=')' ){
    +-      p = fts5ConfigSkipArgs(p);
    +-      if( p==0 ){
    +-        rc = SQLITE_ERROR;
    +-      }else{
    +-        zRankArgs = sqlite3Fts5MallocZero(&rc, 1 + p - pArgs);
    +-        if( zRankArgs ) memcpy(zRankArgs, pArgs, p-pArgs);
    ++    pRank = p;
    ++    p = fts5ConfigSkipBareword(p);
    ++
    ++    if( p ){
    ++      zRank = sqlite3Fts5MallocZero(&rc, 1 + p - pRank);
    ++      if( zRank ) memcpy(zRank, pRank, p-pRank);
    ++    }else{
    ++      rc = SQLITE_ERROR;
    ++    }
    ++
    ++    if( rc==SQLITE_OK ){
    ++      p = fts5ConfigSkipWhitespace(p);
    ++      if( *p!='(' ) rc = SQLITE_ERROR;
    ++      p++;
    ++    }
    ++    if( rc==SQLITE_OK ){
    ++      const char *pArgs; 
    ++      p = fts5ConfigSkipWhitespace(p);
    ++      pArgs = p;
    ++      if( *p!=')' ){
    ++        p = fts5ConfigSkipArgs(p);
    ++        if( p==0 ){
    ++          rc = SQLITE_ERROR;
    ++        }else{
    ++          zRankArgs = sqlite3Fts5MallocZero(&rc, 1 + p - pArgs);
    ++          if( zRankArgs ) memcpy(zRankArgs, pArgs, p-pArgs);
    ++        }
    +       }
    +     }
    +   }
    +@@ -169695,6 +190763,18 @@ static int sqlite3Fts5ConfigSetValue(
    +     }
    +   }
    + 
    ++  else if( 0==sqlite3_stricmp(zKey, "hashsize") ){
    ++    int nHashSize = -1;
    ++    if( SQLITE_INTEGER==sqlite3_value_numeric_type(pVal) ){
    ++      nHashSize = sqlite3_value_int(pVal);
    ++    }
    ++    if( nHashSize<=0 ){
    ++      *pbBadkey = 1;
    ++    }else{
    ++      pConfig->nHashSize = nHashSize;
    ++    }
    ++  }
    ++
    +   else if( 0==sqlite3_stricmp(zKey, "automerge") ){
    +     int nAutomerge = -1;
    +     if( SQLITE_INTEGER==sqlite3_value_numeric_type(pVal) ){
    +@@ -169708,6 +190788,18 @@ static int sqlite3Fts5ConfigSetValue(
    +     }
    +   }
    + 
    ++  else if( 0==sqlite3_stricmp(zKey, "usermerge") ){
    ++    int nUsermerge = -1;
    ++    if( SQLITE_INTEGER==sqlite3_value_numeric_type(pVal) ){
    ++      nUsermerge = sqlite3_value_int(pVal);
    ++    }
    ++    if( nUsermerge<2 || nUsermerge>16 ){
    ++      *pbBadkey = 1;
    ++    }else{
    ++      pConfig->nUsermerge = nUsermerge;
    ++    }
    ++  }
    ++
    +   else if( 0==sqlite3_stricmp(zKey, "crisismerge") ){
    +     int nCrisisMerge = -1;
    +     if( SQLITE_INTEGER==sqlite3_value_numeric_type(pVal) ){
    +@@ -169754,7 +190846,9 @@ static int sqlite3Fts5ConfigLoad(Fts5Config *pConfig, int iCookie){
    +   /* Set default values */
    +   pConfig->pgsz = FTS5_DEFAULT_PAGE_SIZE;
    +   pConfig->nAutomerge = FTS5_DEFAULT_AUTOMERGE;
    ++  pConfig->nUsermerge = FTS5_DEFAULT_USERMERGE;
    +   pConfig->nCrisisMerge = FTS5_DEFAULT_CRISISMERGE;
    ++  pConfig->nHashSize = FTS5_DEFAULT_HASHSIZE;
    + 
    +   zSql = sqlite3Fts5Mprintf(&rc, zSelect, pConfig->zDb, pConfig->zName);
    +   if( zSql ){
    +@@ -169794,7 +190888,6 @@ static int sqlite3Fts5ConfigLoad(Fts5Config *pConfig, int iCookie){
    +   return rc;
    + }
    + 
    +-
    + /*
    + ** 2014 May 31
    + **
    +@@ -169811,6 +190904,8 @@ static int sqlite3Fts5ConfigLoad(Fts5Config *pConfig, int iCookie){
    + 
    + 
    + 
    ++/* #include "fts5Int.h" */
    ++/* #include "fts5parse.h" */
    + 
    + /*
    + ** All token types in the generated fts5parse.h file are greater than 0.
    +@@ -169835,6 +190930,7 @@ static void sqlite3Fts5ParserTrace(FILE*, char*);
    + 
    + struct Fts5Expr {
    +   Fts5Index *pIndex;
    ++  Fts5Config *pConfig;
    +   Fts5ExprNode *pRoot;
    +   int bDesc;                      /* Iterate in descending rowid order */
    +   int nPhrase;                    /* Number of phrases in expression */
    +@@ -169856,6 +190952,9 @@ struct Fts5ExprNode {
    +   int bEof;                       /* True at EOF */
    +   int bNomatch;                   /* True if entry is not a match */
    + 
    ++  /* Next method for this node. */
    ++  int (*xNext)(Fts5Expr*, Fts5ExprNode*, int, i64);
    ++
    +   i64 iRowid;                     /* Current rowid */
    +   Fts5ExprNearset *pNear;         /* For FTS5_STRING - cluster of phrases */
    + 
    +@@ -169867,12 +190966,19 @@ struct Fts5ExprNode {
    + 
    + #define Fts5NodeIsString(p) ((p)->eType==FTS5_TERM || (p)->eType==FTS5_STRING)
    + 
    ++/*
    ++** Invoke the xNext method of an Fts5ExprNode object. This macro should be
    ++** used as if it has the same signature as the xNext() methods themselves.
    ++*/
    ++#define fts5ExprNodeNext(a,b,c,d) (b)->xNext((a), (b), (c), (d))
    ++
    + /*
    + ** An instance of the following structure represents a single search term
    + ** or term prefix.
    + */
    + struct Fts5ExprTerm {
    +-  int bPrefix;                    /* True for a prefix term */
    ++  u8 bPrefix;                     /* True for a prefix term */
    ++  u8 bFirst;                      /* True if token must be first in column */
    +   char *zTerm;                    /* nul-terminated term */
    +   Fts5IndexIter *pIter;           /* Iterator for this term */
    +   Fts5ExprTerm *pSynonym;         /* Pointer to first in list of synonyms */
    +@@ -169952,6 +191058,8 @@ static int fts5ExprGetToken(
    +     case ',':  tok = FTS5_COMMA; break;
    +     case '+':  tok = FTS5_PLUS;  break;
    +     case '*':  tok = FTS5_STAR;  break;
    ++    case '-':  tok = FTS5_MINUS; break;
    ++    case '^':  tok = FTS5_CARET; break;
    +     case '\0': tok = FTS5_EOF;   break;
    + 
    +     case '"': {
    +@@ -169997,6 +191105,7 @@ static void fts5ParseFree(void *p){ sqlite3_free(p); }
    + 
    + static int sqlite3Fts5ExprNew(
    +   Fts5Config *pConfig,            /* FTS5 Configuration */
    ++  int iCol,
    +   const char *zExpr,              /* Expression text */
    +   Fts5Expr **ppNew, 
    +   char **pzErr
    +@@ -170021,6 +191130,18 @@ static int sqlite3Fts5ExprNew(
    +   }while( sParse.rc==SQLITE_OK && t!=FTS5_EOF );
    +   sqlite3Fts5ParserFree(pEngine, fts5ParseFree);
    + 
    ++  /* If the LHS of the MATCH expression was a user column, apply the
    ++  ** implicit column-filter.  */
    ++  if( iCol<pConfig->nCol && sParse.pExpr && sParse.rc==SQLITE_OK ){
    ++    int n = sizeof(Fts5Colset);
    ++    Fts5Colset *pColset = (Fts5Colset*)sqlite3Fts5MallocZero(&sParse.rc, n);
    ++    if( pColset ){
    ++      pColset->nCol = 1;
    ++      pColset->aiCol[0] = iCol;
    ++      sqlite3Fts5ParseSetColset(&sParse, sParse.pExpr, pColset);
    ++    }
    ++  }
    ++
    +   assert( sParse.rc!=SQLITE_OK || sParse.zErr==0 );
    +   if( sParse.rc==SQLITE_OK ){
    +     *ppNew = pNew = sqlite3_malloc(sizeof(Fts5Expr));
    +@@ -170028,12 +191149,23 @@ static int sqlite3Fts5ExprNew(
    +       sParse.rc = SQLITE_NOMEM;
    +       sqlite3Fts5ParseNodeFree(sParse.pExpr);
    +     }else{
    +-      pNew->pRoot = sParse.pExpr;
    ++      if( !sParse.pExpr ){
    ++        const int nByte = sizeof(Fts5ExprNode);
    ++        pNew->pRoot = (Fts5ExprNode*)sqlite3Fts5MallocZero(&sParse.rc, nByte);
    ++        if( pNew->pRoot ){
    ++          pNew->pRoot->bEof = 1;
    ++        }
    ++      }else{
    ++        pNew->pRoot = sParse.pExpr;
    ++      }
    +       pNew->pIndex = 0;
    ++      pNew->pConfig = pConfig;
    +       pNew->apExprPhrase = sParse.apPhrase;
    +       pNew->nPhrase = sParse.nPhrase;
    +       sParse.apPhrase = 0;
    +     }
    ++  }else{
    ++    sqlite3Fts5ParseNodeFree(sParse.pExpr);
    +   }
    + 
    +   sqlite3_free(sParse.apPhrase);
    +@@ -170079,7 +191211,7 @@ static i64 fts5ExprSynonymRowid(Fts5ExprTerm *pTerm, int bDesc, int *pbEof){
    +   assert( bDesc==0 || bDesc==1 );
    +   for(p=pTerm; p; p=p->pSynonym){
    +     if( 0==sqlite3Fts5IterEof(p->pIter) ){
    +-      i64 iRowid = sqlite3Fts5IterRowid(p->pIter);
    ++      i64 iRowid = p->pIter->iRowid;
    +       if( bRetValid==0 || (bDesc!=(iRowid<iRet)) ){
    +         iRet = iRowid;
    +         bRetValid = 1;
    +@@ -170094,11 +191226,10 @@ static i64 fts5ExprSynonymRowid(Fts5ExprTerm *pTerm, int bDesc, int *pbEof){
    + /*
    + ** Argument pTerm must be a synonym iterator.
    + */
    +-static int fts5ExprSynonymPoslist(
    ++static int fts5ExprSynonymList(
    +   Fts5ExprTerm *pTerm, 
    +-  Fts5Colset *pColset,
    +   i64 iRowid,
    +-  int *pbDel,                     /* OUT: Caller should sqlite3_free(*pa) */
    ++  Fts5Buffer *pBuf,               /* Use this buffer for space if required */
    +   u8 **pa, int *pn
    + ){
    +   Fts5PoslistReader aStatic[4];
    +@@ -170111,12 +191242,8 @@ static int fts5ExprSynonymPoslist(
    +   assert( pTerm->pSynonym );
    +   for(p=pTerm; p; p=p->pSynonym){
    +     Fts5IndexIter *pIter = p->pIter;
    +-    if( sqlite3Fts5IterEof(pIter)==0 && sqlite3Fts5IterRowid(pIter)==iRowid ){
    +-      const u8 *a;
    +-      int n;
    +-      i64 dummy;
    +-      rc = sqlite3Fts5IterPoslist(pIter, pColset, &a, &n, &dummy);
    +-      if( rc!=SQLITE_OK ) goto synonym_poslist_out;
    ++    if( sqlite3Fts5IterEof(pIter)==0 && pIter->iRowid==iRowid ){
    ++      if( pIter->nData==0 ) continue;
    +       if( nIter==nAlloc ){
    +         int nByte = sizeof(Fts5PoslistReader) * nAlloc * 2;
    +         Fts5PoslistReader *aNew = (Fts5PoslistReader*)sqlite3_malloc(nByte);
    +@@ -170129,20 +191256,19 @@ static int fts5ExprSynonymPoslist(
    +         if( aIter!=aStatic ) sqlite3_free(aIter);
    +         aIter = aNew;
    +       }
    +-      sqlite3Fts5PoslistReaderInit(a, n, &aIter[nIter]);
    ++      sqlite3Fts5PoslistReaderInit(pIter->pData, pIter->nData, &aIter[nIter]);
    +       assert( aIter[nIter].bEof==0 );
    +       nIter++;
    +     }
    +   }
    + 
    +-  assert( *pbDel==0 );
    +   if( nIter==1 ){
    +     *pa = (u8*)aIter[0].a;
    +     *pn = aIter[0].n;
    +   }else{
    +     Fts5PoslistWriter writer = {0};
    +-    Fts5Buffer buf = {0,0,0};
    +     i64 iPrev = -1;
    ++    fts5BufferZero(pBuf);
    +     while( 1 ){
    +       int i;
    +       i64 iMin = FTS5_LARGEST_INT64;
    +@@ -170157,15 +191283,12 @@ static int fts5ExprSynonymPoslist(
    +         }
    +       }
    +       if( iMin==FTS5_LARGEST_INT64 || rc!=SQLITE_OK ) break;
    +-      rc = sqlite3Fts5PoslistWriterAppend(&buf, &writer, iMin);
    ++      rc = sqlite3Fts5PoslistWriterAppend(pBuf, &writer, iMin);
    +       iPrev = iMin;
    +     }
    +-    if( rc ){
    +-      sqlite3_free(buf.p);
    +-    }else{
    +-      *pa = buf.p;
    +-      *pn = buf.n;
    +-      *pbDel = 1;
    ++    if( rc==SQLITE_OK ){
    ++      *pa = pBuf->p;
    ++      *pn = pBuf->n;
    +     }
    +   }
    + 
    +@@ -170188,7 +191311,6 @@ static int fts5ExprSynonymPoslist(
    + */
    + static int fts5ExprPhraseIsMatch(
    +   Fts5ExprNode *pNode,            /* Node pPhrase belongs to */
    +-  Fts5Colset *pColset,            /* Restrict matches to these columns */
    +   Fts5ExprPhrase *pPhrase,        /* Phrase object to initialize */
    +   int *pbMatch                    /* OUT: Set to true if really a match */
    + ){
    +@@ -170197,12 +191319,13 @@ static int fts5ExprPhraseIsMatch(
    +   Fts5PoslistReader *aIter = aStatic;
    +   int i;
    +   int rc = SQLITE_OK;
    ++  int bFirst = pPhrase->aTerm[0].bFirst;
    +   
    +   fts5BufferZero(&pPhrase->poslist);
    + 
    +   /* If the aStatic[] array is not large enough, allocate a large array
    +   ** using sqlite3_malloc(). This approach could be improved upon. */
    +-  if( pPhrase->nTerm>(sizeof(aStatic) / sizeof(aStatic[0])) ){
    ++  if( pPhrase->nTerm>ArraySize(aStatic) ){
    +     int nByte = sizeof(Fts5PoslistReader) * pPhrase->nTerm;
    +     aIter = (Fts5PoslistReader*)sqlite3_malloc(nByte);
    +     if( !aIter ) return SQLITE_NOMEM;
    +@@ -170212,20 +191335,23 @@ static int fts5ExprPhraseIsMatch(
    +   /* Initialize a term iterator for each term in the phrase */
    +   for(i=0; i<pPhrase->nTerm; i++){
    +     Fts5ExprTerm *pTerm = &pPhrase->aTerm[i];
    +-    i64 dummy;
    +     int n = 0;
    +     int bFlag = 0;
    +-    const u8 *a = 0;
    ++    u8 *a = 0;
    +     if( pTerm->pSynonym ){
    +-      rc = fts5ExprSynonymPoslist(
    +-          pTerm, pColset, pNode->iRowid, &bFlag, (u8**)&a, &n
    +-      );
    ++      Fts5Buffer buf = {0, 0, 0};
    ++      rc = fts5ExprSynonymList(pTerm, pNode->iRowid, &buf, &a, &n);
    ++      if( rc ){
    ++        sqlite3_free(a);
    ++        goto ismatch_out;
    ++      }
    ++      if( a==buf.p ) bFlag = 1;
    +     }else{
    +-      rc = sqlite3Fts5IterPoslist(pTerm->pIter, pColset, &a, &n, &dummy);
    ++      a = (u8*)pTerm->pIter->pData;
    ++      n = pTerm->pIter->nData;
    +     }
    +-    if( rc!=SQLITE_OK ) goto ismatch_out;
    +     sqlite3Fts5PoslistReaderInit(a, n, &aIter[i]);
    +-    aIter[i].bFlag = bFlag;
    ++    aIter[i].bFlag = (u8)bFlag;
    +     if( aIter[i].bEof ) goto ismatch_out;
    +   }
    + 
    +@@ -170248,8 +191374,10 @@ static int fts5ExprPhraseIsMatch(
    +     }while( bMatch==0 );
    + 
    +     /* Append position iPos to the output */
    +-    rc = sqlite3Fts5PoslistWriterAppend(&pPhrase->poslist, &writer, iPos);
    +-    if( rc!=SQLITE_OK ) goto ismatch_out;
    ++    if( bFirst==0 || FTS5_POS2OFFSET(iPos)==0 ){
    ++      rc = sqlite3Fts5PoslistWriterAppend(&pPhrase->poslist, &writer, iPos);
    ++      if( rc!=SQLITE_OK ) goto ismatch_out;
    ++    }
    + 
    +     for(i=0; i<pPhrase->nTerm; i++){
    +       if( sqlite3Fts5PoslistReaderNext(&aIter[i]) ) goto ismatch_out;
    +@@ -170295,12 +191423,6 @@ static int fts5LookaheadReaderInit(
    +   return fts5LookaheadReaderNext(p);
    + }
    + 
    +-#if 0
    +-static int fts5LookaheadReaderEof(Fts5LookaheadReader *p){
    +-  return (p->iPos==FTS5_LOOKAHEAD_EOF);
    +-}
    +-#endif
    +-
    + typedef struct Fts5NearTrimmer Fts5NearTrimmer;
    + struct Fts5NearTrimmer {
    +   Fts5LookaheadReader reader;     /* Input iterator */
    +@@ -170338,7 +191460,7 @@ static int fts5ExprNearIsMatch(int *pRc, Fts5ExprNearset *pNear){
    + 
    +   /* If the aStatic[] array is not large enough, allocate a large array
    +   ** using sqlite3_malloc(). This approach could be improved upon. */
    +-  if( pNear->nPhrase>(sizeof(aStatic) / sizeof(aStatic[0])) ){
    ++  if( pNear->nPhrase>ArraySize(aStatic) ){
    +     int nByte = sizeof(Fts5NearTrimmer) * pNear->nPhrase;
    +     a = (Fts5NearTrimmer*)sqlite3Fts5MallocZero(&rc, nByte);
    +   }else{
    +@@ -170415,71 +191537,6 @@ static int fts5ExprNearIsMatch(int *pRc, Fts5ExprNearset *pNear){
    +   }
    + }
    + 
    +-/*
    +-** Advance the first term iterator in the first phrase of pNear. Set output
    +-** variable *pbEof to true if it reaches EOF or if an error occurs.
    +-**
    +-** Return SQLITE_OK if successful, or an SQLite error code if an error
    +-** occurs.
    +-*/
    +-static int fts5ExprNearAdvanceFirst(
    +-  Fts5Expr *pExpr,                /* Expression pPhrase belongs to */
    +-  Fts5ExprNode *pNode,            /* FTS5_STRING or FTS5_TERM node */
    +-  int bFromValid,
    +-  i64 iFrom 
    +-){
    +-  Fts5ExprTerm *pTerm = &pNode->pNear->apPhrase[0]->aTerm[0];
    +-  int rc = SQLITE_OK;
    +-
    +-  if( pTerm->pSynonym ){
    +-    int bEof = 1;
    +-    Fts5ExprTerm *p;
    +-
    +-    /* Find the firstest rowid any synonym points to. */
    +-    i64 iRowid = fts5ExprSynonymRowid(pTerm, pExpr->bDesc, 0);
    +-
    +-    /* Advance each iterator that currently points to iRowid. Or, if iFrom
    +-    ** is valid - each iterator that points to a rowid before iFrom.  */
    +-    for(p=pTerm; p; p=p->pSynonym){
    +-      if( sqlite3Fts5IterEof(p->pIter)==0 ){
    +-        i64 ii = sqlite3Fts5IterRowid(p->pIter);
    +-        if( ii==iRowid 
    +-         || (bFromValid && ii!=iFrom && (ii>iFrom)==pExpr->bDesc) 
    +-        ){
    +-          if( bFromValid ){
    +-            rc = sqlite3Fts5IterNextFrom(p->pIter, iFrom);
    +-          }else{
    +-            rc = sqlite3Fts5IterNext(p->pIter);
    +-          }
    +-          if( rc!=SQLITE_OK ) break;
    +-          if( sqlite3Fts5IterEof(p->pIter)==0 ){
    +-            bEof = 0;
    +-          }
    +-        }else{
    +-          bEof = 0;
    +-        }
    +-      }
    +-    }
    +-
    +-    /* Set the EOF flag if either all synonym iterators are at EOF or an
    +-    ** error has occurred.  */
    +-    pNode->bEof = (rc || bEof);
    +-  }else{
    +-    Fts5IndexIter *pIter = pTerm->pIter;
    +-
    +-    assert( Fts5NodeIsString(pNode) );
    +-    if( bFromValid ){
    +-      rc = sqlite3Fts5IterNextFrom(pIter, iFrom);
    +-    }else{
    +-      rc = sqlite3Fts5IterNext(pIter);
    +-    }
    +-
    +-    pNode->bEof = (rc || sqlite3Fts5IterEof(pIter));
    +-  }
    +-
    +-  return rc;
    +-}
    +-
    + /*
    + ** Advance iterator pIter until it points to a value equal to or laster
    + ** than the initial value of *piLast. If this means the iterator points
    +@@ -170499,7 +191556,7 @@ static int fts5ExprAdvanceto(
    +   i64 iLast = *piLast;
    +   i64 iRowid;
    + 
    +-  iRowid = sqlite3Fts5IterRowid(pIter);
    ++  iRowid = pIter->iRowid;
    +   if( (bDesc==0 && iLast>iRowid) || (bDesc && iLast<iRowid) ){
    +     int rc = sqlite3Fts5IterNextFrom(pIter, iLast);
    +     if( rc || sqlite3Fts5IterEof(pIter) ){
    +@@ -170507,7 +191564,7 @@ static int fts5ExprAdvanceto(
    +       *pbEof = 1;
    +       return 1;
    +     }
    +-    iRowid = sqlite3Fts5IterRowid(pIter);
    ++    iRowid = pIter->iRowid;
    +     assert( (bDesc==0 && iRowid>=iLast) || (bDesc==1 && iRowid<=iLast) );
    +   }
    +   *piLast = iRowid;
    +@@ -170528,7 +191585,7 @@ static int fts5ExprSynonymAdvanceto(
    + 
    +   for(p=pTerm; rc==SQLITE_OK && p; p=p->pSynonym){
    +     if( sqlite3Fts5IterEof(p->pIter)==0 ){
    +-      i64 iRowid = sqlite3Fts5IterRowid(p->pIter);
    ++      i64 iRowid = p->pIter->iRowid;
    +       if( (bDesc==0 && iLast>iRowid) || (bDesc && iLast<iRowid) ){
    +         rc = sqlite3Fts5IterNextFrom(p->pIter, iLast);
    +       }
    +@@ -170552,56 +191609,182 @@ static int fts5ExprNearTest(
    + ){
    +   Fts5ExprNearset *pNear = pNode->pNear;
    +   int rc = *pRc;
    ++
    ++  if( pExpr->pConfig->eDetail!=FTS5_DETAIL_FULL ){
    ++    Fts5ExprTerm *pTerm;
    ++    Fts5ExprPhrase *pPhrase = pNear->apPhrase[0];
    ++    pPhrase->poslist.n = 0;
    ++    for(pTerm=&pPhrase->aTerm[0]; pTerm; pTerm=pTerm->pSynonym){
    ++      Fts5IndexIter *pIter = pTerm->pIter;
    ++      if( sqlite3Fts5IterEof(pIter)==0 ){
    ++        if( pIter->iRowid==pNode->iRowid && pIter->nData>0 ){
    ++          pPhrase->poslist.n = 1;
    ++        }
    ++      }
    ++    }
    ++    return pPhrase->poslist.n;
    ++  }else{
    ++    int i;
    ++
    ++    /* Check that each phrase in the nearset matches the current row.
    ++    ** Populate the pPhrase->poslist buffers at the same time. If any
    ++    ** phrase is not a match, break out of the loop early.  */
    ++    for(i=0; rc==SQLITE_OK && i<pNear->nPhrase; i++){
    ++      Fts5ExprPhrase *pPhrase = pNear->apPhrase[i];
    ++      if( pPhrase->nTerm>1 || pPhrase->aTerm[0].pSynonym 
    ++       || pNear->pColset || pPhrase->aTerm[0].bFirst
    ++      ){
    ++        int bMatch = 0;
    ++        rc = fts5ExprPhraseIsMatch(pNode, pPhrase, &bMatch);
    ++        if( bMatch==0 ) break;
    ++      }else{
    ++        Fts5IndexIter *pIter = pPhrase->aTerm[0].pIter;
    ++        fts5BufferSet(&rc, &pPhrase->poslist, pIter->nData, pIter->pData);
    ++      }
    ++    }
    ++
    ++    *pRc = rc;
    ++    if( i==pNear->nPhrase && (i==1 || fts5ExprNearIsMatch(pRc, pNear)) ){
    ++      return 1;
    ++    }
    ++    return 0;
    ++  }
    ++}
    ++
    ++
    ++/*
    ++** Initialize all term iterators in the pNear object. If any term is found
    ++** to match no documents at all, return immediately without initializing any
    ++** further iterators.
    ++**
    ++** If an error occurs, return an SQLite error code. Otherwise, return
    ++** SQLITE_OK. It is not considered an error if some term matches zero
    ++** documents.
    ++*/
    ++static int fts5ExprNearInitAll(
    ++  Fts5Expr *pExpr,
    ++  Fts5ExprNode *pNode
    ++){
    ++  Fts5ExprNearset *pNear = pNode->pNear;
    +   int i;
    + 
    +-  /* Check that each phrase in the nearset matches the current row.
    +-  ** Populate the pPhrase->poslist buffers at the same time. If any
    +-  ** phrase is not a match, break out of the loop early.  */
    +-  for(i=0; rc==SQLITE_OK && i<pNear->nPhrase; i++){
    ++  assert( pNode->bNomatch==0 );
    ++  for(i=0; i<pNear->nPhrase; i++){
    +     Fts5ExprPhrase *pPhrase = pNear->apPhrase[i];
    +-    if( pPhrase->nTerm>1 || pPhrase->aTerm[0].pSynonym || pNear->pColset ){
    +-      int bMatch = 0;
    +-      rc = fts5ExprPhraseIsMatch(pNode, pNear->pColset, pPhrase, &bMatch);
    +-      if( bMatch==0 ) break;
    ++    if( pPhrase->nTerm==0 ){
    ++      pNode->bEof = 1;
    ++      return SQLITE_OK;
    +     }else{
    +-      rc = sqlite3Fts5IterPoslistBuffer(
    +-          pPhrase->aTerm[0].pIter, &pPhrase->poslist
    +-      );
    ++      int j;
    ++      for(j=0; j<pPhrase->nTerm; j++){
    ++        Fts5ExprTerm *pTerm = &pPhrase->aTerm[j];
    ++        Fts5ExprTerm *p;
    ++        int bHit = 0;
    ++
    ++        for(p=pTerm; p; p=p->pSynonym){
    ++          int rc;
    ++          if( p->pIter ){
    ++            sqlite3Fts5IterClose(p->pIter);
    ++            p->pIter = 0;
    ++          }
    ++          rc = sqlite3Fts5IndexQuery(
    ++              pExpr->pIndex, p->zTerm, (int)strlen(p->zTerm),
    ++              (pTerm->bPrefix ? FTS5INDEX_QUERY_PREFIX : 0) |
    ++              (pExpr->bDesc ? FTS5INDEX_QUERY_DESC : 0),
    ++              pNear->pColset,
    ++              &p->pIter
    ++          );
    ++          assert( (rc==SQLITE_OK)==(p->pIter!=0) );
    ++          if( rc!=SQLITE_OK ) return rc;
    ++          if( 0==sqlite3Fts5IterEof(p->pIter) ){
    ++            bHit = 1;
    ++          }
    ++        }
    ++
    ++        if( bHit==0 ){
    ++          pNode->bEof = 1;
    ++          return SQLITE_OK;
    ++        }
    ++      }
    +     }
    +   }
    + 
    +-  *pRc = rc;
    +-  if( i==pNear->nPhrase && (i==1 || fts5ExprNearIsMatch(pRc, pNear)) ){
    +-    return 1;
    ++  pNode->bEof = 0;
    ++  return SQLITE_OK;
    ++}
    ++
    ++/*
    ++** If pExpr is an ASC iterator, this function returns a value with the
    ++** same sign as:
    ++**
    ++**   (iLhs - iRhs)
    ++**
    ++** Otherwise, if this is a DESC iterator, the opposite is returned:
    ++**
    ++**   (iRhs - iLhs)
    ++*/
    ++static int fts5RowidCmp(
    ++  Fts5Expr *pExpr,
    ++  i64 iLhs,
    ++  i64 iRhs
    ++){
    ++  assert( pExpr->bDesc==0 || pExpr->bDesc==1 );
    ++  if( pExpr->bDesc==0 ){
    ++    if( iLhs<iRhs ) return -1;
    ++    return (iLhs > iRhs);
    ++  }else{
    ++    if( iLhs>iRhs ) return -1;
    ++    return (iLhs < iRhs);
    +   }
    ++}
    + 
    +-  return 0;
    ++static void fts5ExprSetEof(Fts5ExprNode *pNode){
    ++  int i;
    ++  pNode->bEof = 1;
    ++  pNode->bNomatch = 0;
    ++  for(i=0; i<pNode->nChild; i++){
    ++    fts5ExprSetEof(pNode->apChild[i]);
    ++  }
    + }
    + 
    +-static int fts5ExprTokenTest(
    +-  Fts5Expr *pExpr,                /* Expression that pNear is a part of */
    +-  Fts5ExprNode *pNode             /* The "NEAR" node (FTS5_TERM) */
    +-){
    +-  /* As this "NEAR" object is actually a single phrase that consists 
    +-  ** of a single term only, grab pointers into the poslist managed by the
    +-  ** fts5_index.c iterator object. This is much faster than synthesizing 
    +-  ** a new poslist the way we have to for more complicated phrase or NEAR
    +-  ** expressions.  */
    +-  Fts5ExprNearset *pNear = pNode->pNear;
    +-  Fts5ExprPhrase *pPhrase = pNear->apPhrase[0];
    +-  Fts5IndexIter *pIter = pPhrase->aTerm[0].pIter;
    +-  Fts5Colset *pColset = pNear->pColset;
    +-  int rc;
    ++static void fts5ExprNodeZeroPoslist(Fts5ExprNode *pNode){
    ++  if( pNode->eType==FTS5_STRING || pNode->eType==FTS5_TERM ){
    ++    Fts5ExprNearset *pNear = pNode->pNear;
    ++    int i;
    ++    for(i=0; i<pNear->nPhrase; i++){
    ++      Fts5ExprPhrase *pPhrase = pNear->apPhrase[i];
    ++      pPhrase->poslist.n = 0;
    ++    }
    ++  }else{
    ++    int i;
    ++    for(i=0; i<pNode->nChild; i++){
    ++      fts5ExprNodeZeroPoslist(pNode->apChild[i]);
    ++    }
    ++  }
    ++}
    + 
    +-  assert( pNode->eType==FTS5_TERM );
    +-  assert( pNear->nPhrase==1 && pPhrase->nTerm==1 );
    +-  assert( pPhrase->aTerm[0].pSynonym==0 );
    + 
    +-  rc = sqlite3Fts5IterPoslist(pIter, pColset, 
    +-      (const u8**)&pPhrase->poslist.p, &pPhrase->poslist.n, &pNode->iRowid
    +-  );
    +-  pNode->bNomatch = (pPhrase->poslist.n==0);
    +-  return rc;
    ++
    ++/*
    ++** Compare the values currently indicated by the two nodes as follows:
    ++**
    ++**    res = (*p1) - (*p2)
    ++**
    ++** Nodes that point to values that come later in the iteration order are
    ++** considered to be larger. Nodes at EOF are the largest of all.
    ++**
    ++** This means that if the iteration order is ASC, then numerically larger
    ++** rowids are considered larger. Or if it is the default DESC, numerically
    ++** smaller rowids are larger.
    ++*/
    ++static int fts5NodeCompare(
    ++  Fts5Expr *pExpr,
    ++  Fts5ExprNode *p1, 
    ++  Fts5ExprNode *p2
    ++){
    ++  if( p2->bEof ) return -1;
    ++  if( p1->bEof ) return +1;
    ++  return fts5RowidCmp(pExpr, p1->iRowid, p2->iRowid);
    + }
    + 
    + /*
    +@@ -170615,7 +191798,7 @@ static int fts5ExprTokenTest(
    + ** otherwise. It is not considered an error code if an iterator reaches
    + ** EOF.
    + */
    +-static int fts5ExprNearNextMatch(
    ++static int fts5ExprNodeTest_STRING(
    +   Fts5Expr *pExpr,                /* Expression pPhrase belongs to */
    +   Fts5ExprNode *pNode
    + ){
    +@@ -170631,6 +191814,7 @@ static int fts5ExprNearNextMatch(
    +   assert( pNear->nPhrase>1 
    +        || pNear->apPhrase[0]->nTerm>1 
    +        || pNear->apPhrase[0]->aTerm[0].pSynonym
    ++       || pNear->apPhrase[0]->aTerm[0].bFirst
    +   );
    + 
    +   /* Initialize iLast, the "lastest" rowid any iterator points to. If the
    +@@ -170640,7 +191824,7 @@ static int fts5ExprNearNextMatch(
    +   if( pLeft->aTerm[0].pSynonym ){
    +     iLast = fts5ExprSynonymRowid(&pLeft->aTerm[0], bDesc, 0);
    +   }else{
    +-    iLast = sqlite3Fts5IterRowid(pLeft->aTerm[0].pIter);
    ++    iLast = pLeft->aTerm[0].pIter->iRowid;
    +   }
    + 
    +   do {
    +@@ -170654,13 +191838,13 @@ static int fts5ExprNearNextMatch(
    +           if( iRowid==iLast ) continue;
    +           bMatch = 0;
    +           if( fts5ExprSynonymAdvanceto(pTerm, bDesc, &iLast, &rc) ){
    ++            pNode->bNomatch = 0;
    +             pNode->bEof = 1;
    +             return rc;
    +           }
    +         }else{
    +           Fts5IndexIter *pIter = pPhrase->aTerm[j].pIter;
    +-          i64 iRowid = sqlite3Fts5IterRowid(pIter);
    +-          if( iRowid==iLast ) continue;
    ++          if( pIter->iRowid==iLast || pIter->bEof ) continue;
    +           bMatch = 0;
    +           if( fts5ExprAdvanceto(pIter, bDesc, &iLast, &rc, &pNode->bEof) ){
    +             return rc;
    +@@ -170671,119 +191855,188 @@ static int fts5ExprNearNextMatch(
    +   }while( bMatch==0 );
    + 
    +   pNode->iRowid = iLast;
    +-  pNode->bNomatch = (0==fts5ExprNearTest(&rc, pExpr, pNode));
    ++  pNode->bNomatch = ((0==fts5ExprNearTest(&rc, pExpr, pNode)) && rc==SQLITE_OK);
    ++  assert( pNode->bEof==0 || pNode->bNomatch==0 );
    + 
    +   return rc;
    + }
    + 
    + /*
    +-** Initialize all term iterators in the pNear object. If any term is found
    +-** to match no documents at all, return immediately without initializing any
    +-** further iterators.
    ++** Advance the first term iterator in the first phrase of pNear. Set output
    ++** variable *pbEof to true if it reaches EOF or if an error occurs.
    ++**
    ++** Return SQLITE_OK if successful, or an SQLite error code if an error
    ++** occurs.
    + */
    +-static int fts5ExprNearInitAll(
    +-  Fts5Expr *pExpr,
    +-  Fts5ExprNode *pNode
    ++static int fts5ExprNodeNext_STRING(
    ++  Fts5Expr *pExpr,                /* Expression pPhrase belongs to */
    ++  Fts5ExprNode *pNode,            /* FTS5_STRING or FTS5_TERM node */
    ++  int bFromValid,
    ++  i64 iFrom 
    + ){
    +-  Fts5ExprNearset *pNear = pNode->pNear;
    +-  int i, j;
    ++  Fts5ExprTerm *pTerm = &pNode->pNear->apPhrase[0]->aTerm[0];
    +   int rc = SQLITE_OK;
    + 
    +-  for(i=0; rc==SQLITE_OK && i<pNear->nPhrase; i++){
    +-    Fts5ExprPhrase *pPhrase = pNear->apPhrase[i];
    +-    for(j=0; j<pPhrase->nTerm; j++){
    +-      Fts5ExprTerm *pTerm = &pPhrase->aTerm[j];
    +-      Fts5ExprTerm *p;
    +-      int bEof = 1;
    +-
    +-      for(p=pTerm; p && rc==SQLITE_OK; p=p->pSynonym){
    +-        if( p->pIter ){
    +-          sqlite3Fts5IterClose(p->pIter);
    +-          p->pIter = 0;
    +-        }
    +-        rc = sqlite3Fts5IndexQuery(
    +-            pExpr->pIndex, p->zTerm, strlen(p->zTerm),
    +-            (pTerm->bPrefix ? FTS5INDEX_QUERY_PREFIX : 0) |
    +-            (pExpr->bDesc ? FTS5INDEX_QUERY_DESC : 0),
    +-            pNear->pColset,
    +-            &p->pIter
    +-        );
    +-        assert( rc==SQLITE_OK || p->pIter==0 );
    +-        if( p->pIter && 0==sqlite3Fts5IterEof(p->pIter) ){
    ++  pNode->bNomatch = 0;
    ++  if( pTerm->pSynonym ){
    ++    int bEof = 1;
    ++    Fts5ExprTerm *p;
    ++
    ++    /* Find the firstest rowid any synonym points to. */
    ++    i64 iRowid = fts5ExprSynonymRowid(pTerm, pExpr->bDesc, 0);
    ++
    ++    /* Advance each iterator that currently points to iRowid. Or, if iFrom
    ++    ** is valid - each iterator that points to a rowid before iFrom.  */
    ++    for(p=pTerm; p; p=p->pSynonym){
    ++      if( sqlite3Fts5IterEof(p->pIter)==0 ){
    ++        i64 ii = p->pIter->iRowid;
    ++        if( ii==iRowid 
    ++         || (bFromValid && ii!=iFrom && (ii>iFrom)==pExpr->bDesc) 
    ++        ){
    ++          if( bFromValid ){
    ++            rc = sqlite3Fts5IterNextFrom(p->pIter, iFrom);
    ++          }else{
    ++            rc = sqlite3Fts5IterNext(p->pIter);
    ++          }
    ++          if( rc!=SQLITE_OK ) break;
    ++          if( sqlite3Fts5IterEof(p->pIter)==0 ){
    ++            bEof = 0;
    ++          }
    ++        }else{
    +           bEof = 0;
    +         }
    +       }
    ++    }
    + 
    +-      if( bEof ){
    +-        pNode->bEof = 1;
    +-        return rc;
    +-      }
    ++    /* Set the EOF flag if either all synonym iterators are at EOF or an
    ++    ** error has occurred.  */
    ++    pNode->bEof = (rc || bEof);
    ++  }else{
    ++    Fts5IndexIter *pIter = pTerm->pIter;
    ++
    ++    assert( Fts5NodeIsString(pNode) );
    ++    if( bFromValid ){
    ++      rc = sqlite3Fts5IterNextFrom(pIter, iFrom);
    ++    }else{
    ++      rc = sqlite3Fts5IterNext(pIter);
    +     }
    ++
    ++    pNode->bEof = (rc || sqlite3Fts5IterEof(pIter));
    ++  }
    ++
    ++  if( pNode->bEof==0 ){
    ++    assert( rc==SQLITE_OK );
    ++    rc = fts5ExprNodeTest_STRING(pExpr, pNode);
    +   }
    + 
    +   return rc;
    + }
    + 
    +-/* fts5ExprNodeNext() calls fts5ExprNodeNextMatch(). And vice-versa. */
    +-static int fts5ExprNodeNextMatch(Fts5Expr*, Fts5ExprNode*);
    + 
    ++static int fts5ExprNodeTest_TERM(
    ++  Fts5Expr *pExpr,                /* Expression that pNear is a part of */
    ++  Fts5ExprNode *pNode             /* The "NEAR" node (FTS5_TERM) */
    ++){
    ++  /* As this "NEAR" object is actually a single phrase that consists 
    ++  ** of a single term only, grab pointers into the poslist managed by the
    ++  ** fts5_index.c iterator object. This is much faster than synthesizing 
    ++  ** a new poslist the way we have to for more complicated phrase or NEAR
    ++  ** expressions.  */
    ++  Fts5ExprPhrase *pPhrase = pNode->pNear->apPhrase[0];
    ++  Fts5IndexIter *pIter = pPhrase->aTerm[0].pIter;
    ++
    ++  assert( pNode->eType==FTS5_TERM );
    ++  assert( pNode->pNear->nPhrase==1 && pPhrase->nTerm==1 );
    ++  assert( pPhrase->aTerm[0].pSynonym==0 );
    ++
    ++  pPhrase->poslist.n = pIter->nData;
    ++  if( pExpr->pConfig->eDetail==FTS5_DETAIL_FULL ){
    ++    pPhrase->poslist.p = (u8*)pIter->pData;
    ++  }
    ++  pNode->iRowid = pIter->iRowid;
    ++  pNode->bNomatch = (pPhrase->poslist.n==0);
    ++  return SQLITE_OK;
    ++}
    + 
    + /*
    +-** If pExpr is an ASC iterator, this function returns a value with the
    +-** same sign as:
    +-**
    +-**   (iLhs - iRhs)
    +-**
    +-** Otherwise, if this is a DESC iterator, the opposite is returned:
    +-**
    +-**   (iRhs - iLhs)
    ++** xNext() method for a node of type FTS5_TERM.
    + */
    +-static int fts5RowidCmp(
    +-  Fts5Expr *pExpr,
    +-  i64 iLhs,
    +-  i64 iRhs
    ++static int fts5ExprNodeNext_TERM(
    ++  Fts5Expr *pExpr, 
    ++  Fts5ExprNode *pNode,
    ++  int bFromValid,
    ++  i64 iFrom
    + ){
    +-  assert( pExpr->bDesc==0 || pExpr->bDesc==1 );
    +-  if( pExpr->bDesc==0 ){
    +-    if( iLhs<iRhs ) return -1;
    +-    return (iLhs > iRhs);
    ++  int rc;
    ++  Fts5IndexIter *pIter = pNode->pNear->apPhrase[0]->aTerm[0].pIter;
    ++
    ++  assert( pNode->bEof==0 );
    ++  if( bFromValid ){
    ++    rc = sqlite3Fts5IterNextFrom(pIter, iFrom);
    +   }else{
    +-    if( iLhs>iRhs ) return -1;
    +-    return (iLhs < iRhs);
    ++    rc = sqlite3Fts5IterNext(pIter);
    +   }
    ++  if( rc==SQLITE_OK && sqlite3Fts5IterEof(pIter)==0 ){
    ++    rc = fts5ExprNodeTest_TERM(pExpr, pNode);
    ++  }else{
    ++    pNode->bEof = 1;
    ++    pNode->bNomatch = 0;
    ++  }
    ++  return rc;
    + }
    + 
    +-static void fts5ExprSetEof(Fts5ExprNode *pNode){
    ++static void fts5ExprNodeTest_OR(
    ++  Fts5Expr *pExpr,                /* Expression of which pNode is a part */
    ++  Fts5ExprNode *pNode             /* Expression node to test */
    ++){
    ++  Fts5ExprNode *pNext = pNode->apChild[0];
    +   int i;
    +-  pNode->bEof = 1;
    +-  for(i=0; i<pNode->nChild; i++){
    +-    fts5ExprSetEof(pNode->apChild[i]);
    +-  }
    +-}
    + 
    +-static void fts5ExprNodeZeroPoslist(Fts5ExprNode *pNode){
    +-  if( pNode->eType==FTS5_STRING || pNode->eType==FTS5_TERM ){
    +-    Fts5ExprNearset *pNear = pNode->pNear;
    +-    int i;
    +-    for(i=0; i<pNear->nPhrase; i++){
    +-      Fts5ExprPhrase *pPhrase = pNear->apPhrase[i];
    +-      pPhrase->poslist.n = 0;
    +-    }
    +-  }else{
    +-    int i;
    +-    for(i=0; i<pNode->nChild; i++){
    +-      fts5ExprNodeZeroPoslist(pNode->apChild[i]);
    ++  for(i=1; i<pNode->nChild; i++){
    ++    Fts5ExprNode *pChild = pNode->apChild[i];
    ++    int cmp = fts5NodeCompare(pExpr, pNext, pChild);
    ++    if( cmp>0 || (cmp==0 && pChild->bNomatch==0) ){
    ++      pNext = pChild;
    +     }
    +   }
    ++  pNode->iRowid = pNext->iRowid;
    ++  pNode->bEof = pNext->bEof;
    ++  pNode->bNomatch = pNext->bNomatch;
    + }
    + 
    ++static int fts5ExprNodeNext_OR(
    ++  Fts5Expr *pExpr, 
    ++  Fts5ExprNode *pNode,
    ++  int bFromValid,
    ++  i64 iFrom
    ++){
    ++  int i;
    ++  i64 iLast = pNode->iRowid;
    + 
    +-static int fts5ExprNodeNext(Fts5Expr*, Fts5ExprNode*, int, i64);
    ++  for(i=0; i<pNode->nChild; i++){
    ++    Fts5ExprNode *p1 = pNode->apChild[i];
    ++    assert( p1->bEof || fts5RowidCmp(pExpr, p1->iRowid, iLast)>=0 );
    ++    if( p1->bEof==0 ){
    ++      if( (p1->iRowid==iLast) 
    ++       || (bFromValid && fts5RowidCmp(pExpr, p1->iRowid, iFrom)<0)
    ++      ){
    ++        int rc = fts5ExprNodeNext(pExpr, p1, bFromValid, iFrom);
    ++        if( rc!=SQLITE_OK ){
    ++          pNode->bNomatch = 0;
    ++          return rc;
    ++        }
    ++      }
    ++    }
    ++  }
    ++
    ++  fts5ExprNodeTest_OR(pExpr, pNode);
    ++  return SQLITE_OK;
    ++}
    + 
    + /*
    + ** Argument pNode is an FTS5_AND node.
    + */
    +-static int fts5ExprAndNextRowid(
    ++static int fts5ExprNodeTest_AND(
    +   Fts5Expr *pExpr,                /* Expression pPhrase belongs to */
    +   Fts5ExprNode *pAnd              /* FTS5_AND node to advance */
    + ){
    +@@ -170798,14 +192051,13 @@ static int fts5ExprAndNextRowid(
    +     bMatch = 1;
    +     for(iChild=0; iChild<pAnd->nChild; iChild++){
    +       Fts5ExprNode *pChild = pAnd->apChild[iChild];
    +-      if( 0 && pChild->eType==FTS5_STRING ){
    +-        /* TODO */
    +-      }else{
    +-        int cmp = fts5RowidCmp(pExpr, iLast, pChild->iRowid);
    +-        if( cmp>0 ){
    +-          /* Advance pChild until it points to iLast or laster */
    +-          rc = fts5ExprNodeNext(pExpr, pChild, 1, iLast);
    +-          if( rc!=SQLITE_OK ) return rc;
    ++      int cmp = fts5RowidCmp(pExpr, iLast, pChild->iRowid);
    ++      if( cmp>0 ){
    ++        /* Advance pChild until it points to iLast or laster */
    ++        rc = fts5ExprNodeNext(pExpr, pChild, 1, iLast);
    ++        if( rc!=SQLITE_OK ){
    ++          pAnd->bNomatch = 0;
    ++          return rc;
    +         }
    +       }
    + 
    +@@ -170836,126 +192088,71 @@ static int fts5ExprAndNextRowid(
    +   return SQLITE_OK;
    + }
    + 
    +-
    +-/*
    +-** Compare the values currently indicated by the two nodes as follows:
    +-**
    +-**    res = (*p1) - (*p2)
    +-**
    +-** Nodes that point to values that come later in the iteration order are
    +-** considered to be larger. Nodes at EOF are the largest of all.
    +-**
    +-** This means that if the iteration order is ASC, then numerically larger
    +-** rowids are considered larger. Or if it is the default DESC, numerically
    +-** smaller rowids are larger.
    +-*/
    +-static int fts5NodeCompare(
    +-  Fts5Expr *pExpr,
    +-  Fts5ExprNode *p1, 
    +-  Fts5ExprNode *p2
    +-){
    +-  if( p2->bEof ) return -1;
    +-  if( p1->bEof ) return +1;
    +-  return fts5RowidCmp(pExpr, p1->iRowid, p2->iRowid);
    +-}
    +-
    +-/*
    +-** Advance node iterator pNode, part of expression pExpr. If argument
    +-** bFromValid is zero, then pNode is advanced exactly once. Or, if argument
    +-** bFromValid is non-zero, then pNode is advanced until it is at or past
    +-** rowid value iFrom. Whether "past" means "less than" or "greater than"
    +-** depends on whether this is an ASC or DESC iterator.
    +-*/
    +-static int fts5ExprNodeNext(
    ++static int fts5ExprNodeNext_AND(
    +   Fts5Expr *pExpr, 
    +   Fts5ExprNode *pNode,
    +   int bFromValid,
    +   i64 iFrom
    + ){
    +-  int rc = SQLITE_OK;
    +-
    +-  if( pNode->bEof==0 ){
    +-    switch( pNode->eType ){
    +-      case FTS5_STRING: {
    +-        rc = fts5ExprNearAdvanceFirst(pExpr, pNode, bFromValid, iFrom);
    +-        break;
    +-      };
    +-
    +-      case FTS5_TERM: {
    +-        Fts5IndexIter *pIter = pNode->pNear->apPhrase[0]->aTerm[0].pIter;
    +-        if( bFromValid ){
    +-          rc = sqlite3Fts5IterNextFrom(pIter, iFrom);
    +-        }else{
    +-          rc = sqlite3Fts5IterNext(pIter);
    +-        }
    +-        if( rc==SQLITE_OK && sqlite3Fts5IterEof(pIter)==0 ){
    +-          assert( rc==SQLITE_OK );
    +-          rc = fts5ExprTokenTest(pExpr, pNode);
    +-        }else{
    +-          pNode->bEof = 1;
    +-        }
    +-        return rc;
    +-      };
    +-
    +-      case FTS5_AND: {
    +-        Fts5ExprNode *pLeft = pNode->apChild[0];
    +-        rc = fts5ExprNodeNext(pExpr, pLeft, bFromValid, iFrom);
    +-        break;
    +-      }
    +-
    +-      case FTS5_OR: {
    +-        int i;
    +-        i64 iLast = pNode->iRowid;
    +-
    +-        for(i=0; rc==SQLITE_OK && i<pNode->nChild; i++){
    +-          Fts5ExprNode *p1 = pNode->apChild[i];
    +-          assert( p1->bEof || fts5RowidCmp(pExpr, p1->iRowid, iLast)>=0 );
    +-          if( p1->bEof==0 ){
    +-            if( (p1->iRowid==iLast) 
    +-             || (bFromValid && fts5RowidCmp(pExpr, p1->iRowid, iFrom)<0)
    +-            ){
    +-              rc = fts5ExprNodeNext(pExpr, p1, bFromValid, iFrom);
    +-            }
    +-          }
    +-        }
    +-
    +-        break;
    +-      }
    ++  int rc = fts5ExprNodeNext(pExpr, pNode->apChild[0], bFromValid, iFrom);
    ++  if( rc==SQLITE_OK ){
    ++    rc = fts5ExprNodeTest_AND(pExpr, pNode);
    ++  }else{
    ++    pNode->bNomatch = 0;
    ++  }
    ++  return rc;
    ++}
    + 
    +-      default: assert( pNode->eType==FTS5_NOT ); {
    +-        assert( pNode->nChild==2 );
    +-        rc = fts5ExprNodeNext(pExpr, pNode->apChild[0], bFromValid, iFrom);
    +-        break;
    +-      }
    +-    }
    ++static int fts5ExprNodeTest_NOT(
    ++  Fts5Expr *pExpr,                /* Expression pPhrase belongs to */
    ++  Fts5ExprNode *pNode             /* FTS5_NOT node to advance */
    ++){
    ++  int rc = SQLITE_OK;
    ++  Fts5ExprNode *p1 = pNode->apChild[0];
    ++  Fts5ExprNode *p2 = pNode->apChild[1];
    ++  assert( pNode->nChild==2 );
    + 
    +-    if( rc==SQLITE_OK ){
    +-      rc = fts5ExprNodeNextMatch(pExpr, pNode);
    ++  while( rc==SQLITE_OK && p1->bEof==0 ){
    ++    int cmp = fts5NodeCompare(pExpr, p1, p2);
    ++    if( cmp>0 ){
    ++      rc = fts5ExprNodeNext(pExpr, p2, 1, p1->iRowid);
    ++      cmp = fts5NodeCompare(pExpr, p1, p2);
    +     }
    ++    assert( rc!=SQLITE_OK || cmp<=0 );
    ++    if( cmp || p2->bNomatch ) break;
    ++    rc = fts5ExprNodeNext(pExpr, p1, 0, 0);
    ++  }
    ++  pNode->bEof = p1->bEof;
    ++  pNode->bNomatch = p1->bNomatch;
    ++  pNode->iRowid = p1->iRowid;
    ++  if( p1->bEof ){
    ++    fts5ExprNodeZeroPoslist(p2);
    +   }
    +-
    +-  /* Assert that if bFromValid was true, either:
    +-  **
    +-  **   a) an error occurred, or
    +-  **   b) the node is now at EOF, or
    +-  **   c) the node is now at or past rowid iFrom.
    +-  */
    +-  assert( bFromValid==0 
    +-      || rc!=SQLITE_OK                                                  /* a */
    +-      || pNode->bEof                                                    /* b */
    +-      || pNode->iRowid==iFrom || pExpr->bDesc==(pNode->iRowid<iFrom)    /* c */
    +-  );
    +-
    +   return rc;
    + }
    + 
    ++static int fts5ExprNodeNext_NOT(
    ++  Fts5Expr *pExpr, 
    ++  Fts5ExprNode *pNode,
    ++  int bFromValid,
    ++  i64 iFrom
    ++){
    ++  int rc = fts5ExprNodeNext(pExpr, pNode->apChild[0], bFromValid, iFrom);
    ++  if( rc==SQLITE_OK ){
    ++    rc = fts5ExprNodeTest_NOT(pExpr, pNode);
    ++  }
    ++  if( rc!=SQLITE_OK ){
    ++    pNode->bNomatch = 0;
    ++  }
    ++  return rc;
    ++}
    + 
    + /*
    + ** If pNode currently points to a match, this function returns SQLITE_OK
    + ** without modifying it. Otherwise, pNode is advanced until it does point
    + ** to a match or EOF is reached.
    + */
    +-static int fts5ExprNodeNextMatch(
    ++static int fts5ExprNodeTest(
    +   Fts5Expr *pExpr,                /* Expression of which pNode is a part */
    +   Fts5ExprNode *pNode             /* Expression node to test */
    + ){
    +@@ -170964,55 +192161,27 @@ static int fts5ExprNodeNextMatch(
    +     switch( pNode->eType ){
    + 
    +       case FTS5_STRING: {
    +-        /* Advance the iterators until they all point to the same rowid */
    +-        rc = fts5ExprNearNextMatch(pExpr, pNode);
    ++        rc = fts5ExprNodeTest_STRING(pExpr, pNode);
    +         break;
    +       }
    + 
    +       case FTS5_TERM: {
    +-        rc = fts5ExprTokenTest(pExpr, pNode);
    ++        rc = fts5ExprNodeTest_TERM(pExpr, pNode);
    +         break;
    +       }
    + 
    +       case FTS5_AND: {
    +-        rc = fts5ExprAndNextRowid(pExpr, pNode);
    ++        rc = fts5ExprNodeTest_AND(pExpr, pNode);
    +         break;
    +       }
    + 
    +       case FTS5_OR: {
    +-        Fts5ExprNode *pNext = pNode->apChild[0];
    +-        int i;
    +-
    +-        for(i=1; i<pNode->nChild; i++){
    +-          Fts5ExprNode *pChild = pNode->apChild[i];
    +-          int cmp = fts5NodeCompare(pExpr, pNext, pChild);
    +-          if( cmp>0 || (cmp==0 && pChild->bNomatch==0) ){
    +-            pNext = pChild;
    +-          }
    +-        }
    +-        pNode->iRowid = pNext->iRowid;
    +-        pNode->bEof = pNext->bEof;
    +-        pNode->bNomatch = pNext->bNomatch;
    ++        fts5ExprNodeTest_OR(pExpr, pNode);
    +         break;
    +       }
    + 
    +       default: assert( pNode->eType==FTS5_NOT ); {
    +-        Fts5ExprNode *p1 = pNode->apChild[0];
    +-        Fts5ExprNode *p2 = pNode->apChild[1];
    +-        assert( pNode->nChild==2 );
    +-
    +-        while( rc==SQLITE_OK && p1->bEof==0 ){
    +-          int cmp = fts5NodeCompare(pExpr, p1, p2);
    +-          if( cmp>0 ){
    +-            rc = fts5ExprNodeNext(pExpr, p2, 1, p1->iRowid);
    +-            cmp = fts5NodeCompare(pExpr, p1, p2);
    +-          }
    +-          assert( rc!=SQLITE_OK || cmp<=0 );
    +-          if( cmp || p2->bNomatch ) break;
    +-          rc = fts5ExprNodeNext(pExpr, p1, 0, 0);
    +-        }
    +-        pNode->bEof = p1->bEof;
    +-        pNode->iRowid = p1->iRowid;
    ++        rc = fts5ExprNodeTest_NOT(pExpr, pNode);
    +         break;
    +       }
    +     }
    +@@ -171031,20 +192200,42 @@ static int fts5ExprNodeNextMatch(
    + static int fts5ExprNodeFirst(Fts5Expr *pExpr, Fts5ExprNode *pNode){
    +   int rc = SQLITE_OK;
    +   pNode->bEof = 0;
    ++  pNode->bNomatch = 0;
    + 
    +   if( Fts5NodeIsString(pNode) ){
    +     /* Initialize all term iterators in the NEAR object. */
    +     rc = fts5ExprNearInitAll(pExpr, pNode);
    ++  }else if( pNode->xNext==0 ){
    ++    pNode->bEof = 1;
    +   }else{
    +     int i;
    ++    int nEof = 0;
    +     for(i=0; i<pNode->nChild && rc==SQLITE_OK; i++){
    ++      Fts5ExprNode *pChild = pNode->apChild[i];
    +       rc = fts5ExprNodeFirst(pExpr, pNode->apChild[i]);
    ++      assert( pChild->bEof==0 || pChild->bEof==1 );
    ++      nEof += pChild->bEof;
    +     }
    +     pNode->iRowid = pNode->apChild[0]->iRowid;
    ++
    ++    switch( pNode->eType ){
    ++      case FTS5_AND:
    ++        if( nEof>0 ) fts5ExprSetEof(pNode);
    ++        break;
    ++
    ++      case FTS5_OR:
    ++        if( pNode->nChild==nEof ) fts5ExprSetEof(pNode);
    ++        break;
    ++
    ++      default:
    ++        assert( pNode->eType==FTS5_NOT );
    ++        pNode->bEof = pNode->apChild[0]->bEof;
    ++        break;
    ++    }
    +   }
    + 
    +   if( rc==SQLITE_OK ){
    +-    rc = fts5ExprNodeNextMatch(pExpr, pNode);
    ++    rc = fts5ExprNodeTest(pExpr, pNode);
    +   }
    +   return rc;
    + }
    +@@ -171067,22 +192258,25 @@ static int fts5ExprNodeFirst(Fts5Expr *pExpr, Fts5ExprNode *pNode){
    + */
    + static int sqlite3Fts5ExprFirst(Fts5Expr *p, Fts5Index *pIdx, i64 iFirst, int bDesc){
    +   Fts5ExprNode *pRoot = p->pRoot;
    +-  int rc = SQLITE_OK;
    +-  if( pRoot ){
    +-    p->pIndex = pIdx;
    +-    p->bDesc = bDesc;
    +-    rc = fts5ExprNodeFirst(p, pRoot);
    ++  int rc;                         /* Return code */
    + 
    +-    /* If not at EOF but the current rowid occurs earlier than iFirst in
    +-    ** the iteration order, move to document iFirst or later. */
    +-    if( pRoot->bEof==0 && fts5RowidCmp(p, pRoot->iRowid, iFirst)<0 ){
    +-      rc = fts5ExprNodeNext(p, pRoot, 1, iFirst);
    +-    }
    ++  p->pIndex = pIdx;
    ++  p->bDesc = bDesc;
    ++  rc = fts5ExprNodeFirst(p, pRoot);
    + 
    +-    /* If the iterator is not at a real match, skip forward until it is. */
    +-    while( pRoot->bNomatch && rc==SQLITE_OK && pRoot->bEof==0 ){
    +-      rc = fts5ExprNodeNext(p, pRoot, 0, 0);
    +-    }
    ++  /* If not at EOF but the current rowid occurs earlier than iFirst in
    ++  ** the iteration order, move to document iFirst or later. */
    ++  if( rc==SQLITE_OK 
    ++   && 0==pRoot->bEof 
    ++   && fts5RowidCmp(p, pRoot->iRowid, iFirst)<0 
    ++  ){
    ++    rc = fts5ExprNodeNext(p, pRoot, 1, iFirst);
    ++  }
    ++
    ++  /* If the iterator is not at a real match, skip forward until it is. */
    ++  while( pRoot->bNomatch ){
    ++    assert( pRoot->bEof==0 && rc==SQLITE_OK );
    ++    rc = fts5ExprNodeNext(p, pRoot, 0, 0);
    +   }
    +   return rc;
    + }
    +@@ -171096,9 +192290,11 @@ static int sqlite3Fts5ExprFirst(Fts5Expr *p, Fts5Index *pIdx, i64 iFirst, int bD
    + static int sqlite3Fts5ExprNext(Fts5Expr *p, i64 iLast){
    +   int rc;
    +   Fts5ExprNode *pRoot = p->pRoot;
    ++  assert( pRoot->bEof==0 && pRoot->bNomatch==0 );
    +   do {
    +     rc = fts5ExprNodeNext(p, pRoot, 0, 0);
    +-  }while( pRoot->bNomatch && pRoot->bEof==0 && rc==SQLITE_OK );
    ++    assert( pRoot->bNomatch==0 || (rc==SQLITE_OK && pRoot->bEof==0) );
    ++  }while( pRoot->bNomatch );
    +   if( fts5RowidCmp(p, pRoot->iRowid, iLast)>0 ){
    +     pRoot->bEof = 1;
    +   }
    +@@ -171106,7 +192302,7 @@ static int sqlite3Fts5ExprNext(Fts5Expr *p, i64 iLast){
    + }
    + 
    + static int sqlite3Fts5ExprEof(Fts5Expr *p){
    +-  return (p->pRoot==0 || p->pRoot->bEof);
    ++  return p->pRoot->bEof;
    + }
    + 
    + static i64 sqlite3Fts5ExprRowid(Fts5Expr *p){
    +@@ -171131,10 +192327,10 @@ static void fts5ExprPhraseFree(Fts5ExprPhrase *pPhrase){
    +       Fts5ExprTerm *pTerm = &pPhrase->aTerm[i];
    +       sqlite3_free(pTerm->zTerm);
    +       sqlite3Fts5IterClose(pTerm->pIter);
    +-
    +       for(pSyn=pTerm->pSynonym; pSyn; pSyn=pNext){
    +         pNext = pSyn->pSynonym;
    +         sqlite3Fts5IterClose(pSyn->pIter);
    ++        fts5BufferFree((Fts5Buffer*)&pSyn[1]);
    +         sqlite3_free(pSyn);
    +       }
    +     }
    +@@ -171143,6 +192339,16 @@ static void fts5ExprPhraseFree(Fts5ExprPhrase *pPhrase){
    +   }
    + }
    + 
    ++/*
    ++** Set the "bFirst" flag on the first token of the phrase passed as the
    ++** only argument.
    ++*/
    ++static void sqlite3Fts5ParseSetCaret(Fts5ExprPhrase *pPhrase){
    ++  if( pPhrase && pPhrase->nTerm ){
    ++    pPhrase->aTerm[0].bFirst = 1;
    ++  }
    ++}
    ++
    + /*
    + ** If argument pNear is NULL, then a new Fts5ExprNearset object is allocated
    + ** and populated with pPhrase. Or, if pNear is not NULL, phrase pPhrase is
    +@@ -171189,6 +192395,21 @@ static Fts5ExprNearset *sqlite3Fts5ParseNearset(
    +     sqlite3Fts5ParseNearsetFree(pNear);
    +     sqlite3Fts5ParsePhraseFree(pPhrase);
    +   }else{
    ++    if( pRet->nPhrase>0 ){
    ++      Fts5ExprPhrase *pLast = pRet->apPhrase[pRet->nPhrase-1];
    ++      assert( pLast==pParse->apPhrase[pParse->nPhrase-2] );
    ++      if( pPhrase->nTerm==0 ){
    ++        fts5ExprPhraseFree(pPhrase);
    ++        pRet->nPhrase--;
    ++        pParse->nPhrase--;
    ++        pPhrase = pLast;
    ++      }else if( pLast->nTerm==0 ){
    ++        fts5ExprPhraseFree(pLast);
    ++        pParse->apPhrase[pParse->nPhrase-2] = pPhrase;
    ++        pParse->nPhrase--;
    ++        pRet->nPhrase--;
    ++      }
    ++    }
    +     pRet->apPhrase[pRet->nPhrase++] = pPhrase;
    +   }
    +   return pRet;
    +@@ -171216,19 +192437,21 @@ static int fts5ParseTokenize(
    +   TokenCtx *pCtx = (TokenCtx*)pContext;
    +   Fts5ExprPhrase *pPhrase = pCtx->pPhrase;
    + 
    ++  UNUSED_PARAM2(iUnused1, iUnused2);
    ++
    +   /* If an error has already occurred, this is a no-op */
    +   if( pCtx->rc!=SQLITE_OK ) return pCtx->rc;
    ++  if( nToken>FTS5_MAX_TOKEN_SIZE ) nToken = FTS5_MAX_TOKEN_SIZE;
    + 
    +-  assert( pPhrase==0 || pPhrase->nTerm>0 );
    +-  if( pPhrase && (tflags & FTS5_TOKEN_COLOCATED) ){
    ++  if( pPhrase && pPhrase->nTerm>0 && (tflags & FTS5_TOKEN_COLOCATED) ){
    +     Fts5ExprTerm *pSyn;
    +-    int nByte = sizeof(Fts5ExprTerm) + nToken+1;
    ++    int nByte = sizeof(Fts5ExprTerm) + sizeof(Fts5Buffer) + nToken+1;
    +     pSyn = (Fts5ExprTerm*)sqlite3_malloc(nByte);
    +     if( pSyn==0 ){
    +       rc = SQLITE_NOMEM;
    +     }else{
    +       memset(pSyn, 0, nByte);
    +-      pSyn->zTerm = (char*)&pSyn[1];
    ++      pSyn->zTerm = ((char*)pSyn) + sizeof(Fts5ExprTerm) + sizeof(Fts5Buffer);
    +       memcpy(pSyn->zTerm, pToken, nToken);
    +       pSyn->pSynonym = pPhrase->aTerm[pPhrase->nTerm-1].pSynonym;
    +       pPhrase->aTerm[pPhrase->nTerm-1].pSynonym = pSyn;
    +@@ -171310,10 +192533,10 @@ static Fts5ExprPhrase *sqlite3Fts5ParseTerm(
    + 
    +   rc = fts5ParseStringFromToken(pToken, &z);
    +   if( rc==SQLITE_OK ){
    +-    int flags = FTS5_TOKENIZE_QUERY | (bPrefix ? FTS5_TOKENIZE_QUERY : 0);
    ++    int flags = FTS5_TOKENIZE_QUERY | (bPrefix ? FTS5_TOKENIZE_PREFIX : 0);
    +     int n;
    +     sqlite3Fts5Dequote(z);
    +-    n = strlen(z);
    ++    n = (int)strlen(z);
    +     rc = sqlite3Fts5Tokenize(pConfig, flags, z, n, &sCtx, fts5ParseTokenize);
    +   }
    +   sqlite3_free(z);
    +@@ -171321,7 +192544,7 @@ static Fts5ExprPhrase *sqlite3Fts5ParseTerm(
    +     pParse->rc = rc;
    +     fts5ExprPhraseFree(sCtx.pPhrase);
    +     sCtx.pPhrase = 0;
    +-  }else if( sCtx.pPhrase ){
    ++  }else{
    + 
    +     if( pAppend==0 ){
    +       if( (pParse->nPhrase % 8)==0 ){
    +@@ -171338,9 +192561,14 @@ static Fts5ExprPhrase *sqlite3Fts5ParseTerm(
    +       pParse->nPhrase++;
    +     }
    + 
    ++    if( sCtx.pPhrase==0 ){
    ++      /* This happens when parsing a token or quoted phrase that contains
    ++      ** no token characters at all. (e.g ... MATCH '""'). */
    ++      sCtx.pPhrase = sqlite3Fts5MallocZero(&pParse->rc, sizeof(Fts5ExprPhrase));
    ++    }else if( sCtx.pPhrase->nTerm ){
    ++      sCtx.pPhrase->aTerm[sCtx.pPhrase->nTerm-1].bPrefix = bPrefix;
    ++    }
    +     pParse->apPhrase[pParse->nPhrase-1] = sCtx.pPhrase;
    +-    assert( sCtx.pPhrase->nTerm>0 );
    +-    sCtx.pPhrase->aTerm[sCtx.pPhrase->nTerm-1].bPrefix = bPrefix;
    +   }
    + 
    +   return sCtx.pPhrase;
    +@@ -171351,22 +192579,16 @@ static Fts5ExprPhrase *sqlite3Fts5ParseTerm(
    + ** expression passed as the second argument.
    + */
    + static int sqlite3Fts5ExprClonePhrase(
    +-  Fts5Config *pConfig,
    +   Fts5Expr *pExpr, 
    +   int iPhrase, 
    +   Fts5Expr **ppNew
    + ){
    +   int rc = SQLITE_OK;             /* Return code */
    +   Fts5ExprPhrase *pOrig;          /* The phrase extracted from pExpr */
    +-  int i;                          /* Used to iterate through phrase terms */
    +-
    +   Fts5Expr *pNew = 0;             /* Expression to return via *ppNew */
    +-
    +   TokenCtx sCtx = {0,0};          /* Context object for fts5ParseTokenize */
    + 
    +-
    +   pOrig = pExpr->apExprPhrase[iPhrase];
    +-
    +   pNew = (Fts5Expr*)sqlite3Fts5MallocZero(&rc, sizeof(Fts5Expr));
    +   if( rc==SQLITE_OK ){
    +     pNew->apExprPhrase = (Fts5ExprPhrase**)sqlite3Fts5MallocZero(&rc, 
    +@@ -171380,33 +192602,59 @@ static int sqlite3Fts5ExprClonePhrase(
    +     pNew->pRoot->pNear = (Fts5ExprNearset*)sqlite3Fts5MallocZero(&rc, 
    +         sizeof(Fts5ExprNearset) + sizeof(Fts5ExprPhrase*));
    +   }
    +-
    +-  for(i=0; rc==SQLITE_OK && i<pOrig->nTerm; i++){
    +-    int tflags = 0;
    +-    Fts5ExprTerm *p;
    +-    for(p=&pOrig->aTerm[i]; p && rc==SQLITE_OK; p=p->pSynonym){
    +-      const char *zTerm = p->zTerm;
    +-      rc = fts5ParseTokenize((void*)&sCtx, tflags, zTerm, strlen(zTerm), 0, 0);
    +-      tflags = FTS5_TOKEN_COLOCATED;
    ++  if( rc==SQLITE_OK ){
    ++    Fts5Colset *pColsetOrig = pOrig->pNode->pNear->pColset;
    ++    if( pColsetOrig ){
    ++      int nByte = sizeof(Fts5Colset) + (pColsetOrig->nCol-1) * sizeof(int);
    ++      Fts5Colset *pColset = (Fts5Colset*)sqlite3Fts5MallocZero(&rc, nByte);
    ++      if( pColset ){ 
    ++        memcpy(pColset, pColsetOrig, nByte);
    ++      }
    ++      pNew->pRoot->pNear->pColset = pColset;
    +     }
    +-    if( rc==SQLITE_OK ){
    +-      sCtx.pPhrase->aTerm[i].bPrefix = pOrig->aTerm[i].bPrefix;
    ++  }
    ++
    ++  if( pOrig->nTerm ){
    ++    int i;                          /* Used to iterate through phrase terms */
    ++    for(i=0; rc==SQLITE_OK && i<pOrig->nTerm; i++){
    ++      int tflags = 0;
    ++      Fts5ExprTerm *p;
    ++      for(p=&pOrig->aTerm[i]; p && rc==SQLITE_OK; p=p->pSynonym){
    ++        const char *zTerm = p->zTerm;
    ++        rc = fts5ParseTokenize((void*)&sCtx, tflags, zTerm, (int)strlen(zTerm),
    ++            0, 0);
    ++        tflags = FTS5_TOKEN_COLOCATED;
    ++      }
    ++      if( rc==SQLITE_OK ){
    ++        sCtx.pPhrase->aTerm[i].bPrefix = pOrig->aTerm[i].bPrefix;
    ++        sCtx.pPhrase->aTerm[i].bFirst = pOrig->aTerm[i].bFirst;
    ++      }
    +     }
    ++  }else{
    ++    /* This happens when parsing a token or quoted phrase that contains
    ++    ** no token characters at all. (e.g ... MATCH '""'). */
    ++    sCtx.pPhrase = sqlite3Fts5MallocZero(&rc, sizeof(Fts5ExprPhrase));
    +   }
    + 
    +   if( rc==SQLITE_OK ){
    +     /* All the allocations succeeded. Put the expression object together. */
    +     pNew->pIndex = pExpr->pIndex;
    ++    pNew->pConfig = pExpr->pConfig;
    +     pNew->nPhrase = 1;
    +     pNew->apExprPhrase[0] = sCtx.pPhrase;
    +     pNew->pRoot->pNear->apPhrase[0] = sCtx.pPhrase;
    +     pNew->pRoot->pNear->nPhrase = 1;
    +     sCtx.pPhrase->pNode = pNew->pRoot;
    + 
    +-    if( pOrig->nTerm==1 && pOrig->aTerm[0].pSynonym==0 ){
    ++    if( pOrig->nTerm==1 
    ++     && pOrig->aTerm[0].pSynonym==0 
    ++     && pOrig->aTerm[0].bFirst==0 
    ++    ){
    +       pNew->pRoot->eType = FTS5_TERM;
    ++      pNew->pRoot->xNext = fts5ExprNodeNext_TERM;
    +     }else{
    +       pNew->pRoot->eType = FTS5_STRING;
    ++      pNew->pRoot->xNext = fts5ExprNodeNext_STRING;
    +     }
    +   }else{
    +     sqlite3Fts5ExprFree(pNew);
    +@@ -171437,23 +192685,25 @@ static void sqlite3Fts5ParseSetDistance(
    +   Fts5ExprNearset *pNear,
    +   Fts5Token *p
    + ){
    +-  int nNear = 0;
    +-  int i;
    +-  if( p->n ){
    +-    for(i=0; i<p->n; i++){
    +-      char c = (char)p->p[i];
    +-      if( c<'0' || c>'9' ){
    +-        sqlite3Fts5ParseError(
    +-            pParse, "expected integer, got \"%.*s\"", p->n, p->p
    +-        );
    +-        return;
    ++  if( pNear ){
    ++    int nNear = 0;
    ++    int i;
    ++    if( p->n ){
    ++      for(i=0; i<p->n; i++){
    ++        char c = (char)p->p[i];
    ++        if( c<'0' || c>'9' ){
    ++          sqlite3Fts5ParseError(
    ++              pParse, "expected integer, got \"%.*s\"", p->n, p->p
    ++              );
    ++          return;
    ++        }
    ++        nNear = nNear * 10 + (p->p[i] - '0');
    +       }
    +-      nNear = nNear * 10 + (p->p[i] - '0');
    ++    }else{
    ++      nNear = FTS5_DEFAULT_NEARDIST;
    +     }
    +-  }else{
    +-    nNear = FTS5_DEFAULT_NEARDIST;
    ++    pNear->nNear = nNear;
    +   }
    +-  pNear->nNear = nNear;
    + }
    + 
    + /*
    +@@ -171501,6 +192751,34 @@ static Fts5Colset *fts5ParseColset(
    +   return pNew;
    + }
    + 
    ++/*
    ++** Allocate and return an Fts5Colset object specifying the inverse of
    ++** the colset passed as the second argument. Free the colset passed
    ++** as the second argument before returning.
    ++*/
    ++static Fts5Colset *sqlite3Fts5ParseColsetInvert(Fts5Parse *pParse, Fts5Colset *p){
    ++  Fts5Colset *pRet;
    ++  int nCol = pParse->pConfig->nCol;
    ++
    ++  pRet = (Fts5Colset*)sqlite3Fts5MallocZero(&pParse->rc, 
    ++      sizeof(Fts5Colset) + sizeof(int)*nCol
    ++  );
    ++  if( pRet ){
    ++    int i;
    ++    int iOld = 0;
    ++    for(i=0; i<nCol; i++){
    ++      if( iOld>=p->nCol || p->aiCol[iOld]!=i ){
    ++        pRet->aiCol[pRet->nCol++] = i;
    ++      }else{
    ++        iOld++;
    ++      }
    ++    }
    ++  }
    ++
    ++  sqlite3_free(p);
    ++  return pRet;
    ++}
    ++
    + static Fts5Colset *sqlite3Fts5ParseColset(
    +   Fts5Parse *pParse,              /* Store SQLITE_NOMEM here if required */
    +   Fts5Colset *pColset,            /* Existing colset object */
    +@@ -171533,15 +192811,142 @@ static Fts5Colset *sqlite3Fts5ParseColset(
    +   return pRet;
    + }
    + 
    ++/*
    ++** If argument pOrig is NULL, or if (*pRc) is set to anything other than
    ++** SQLITE_OK when this function is called, NULL is returned. 
    ++**
    ++** Otherwise, a copy of (*pOrig) is made into memory obtained from
    ++** sqlite3Fts5MallocZero() and a pointer to it returned. If the allocation
    ++** fails, (*pRc) is set to SQLITE_NOMEM and NULL is returned.
    ++*/
    ++static Fts5Colset *fts5CloneColset(int *pRc, Fts5Colset *pOrig){
    ++  Fts5Colset *pRet;
    ++  if( pOrig ){
    ++    int nByte = sizeof(Fts5Colset) + (pOrig->nCol-1) * sizeof(int);
    ++    pRet = (Fts5Colset*)sqlite3Fts5MallocZero(pRc, nByte);
    ++    if( pRet ){ 
    ++      memcpy(pRet, pOrig, nByte);
    ++    }
    ++  }else{
    ++    pRet = 0;
    ++  }
    ++  return pRet;
    ++}
    ++
    ++/*
    ++** Remove from colset pColset any columns that are not also in colset pMerge.
    ++*/
    ++static void fts5MergeColset(Fts5Colset *pColset, Fts5Colset *pMerge){
    ++  int iIn = 0;          /* Next input in pColset */
    ++  int iMerge = 0;       /* Next input in pMerge */
    ++  int iOut = 0;         /* Next output slot in pColset */
    ++
    ++  while( iIn<pColset->nCol && iMerge<pMerge->nCol ){
    ++    int iDiff = pColset->aiCol[iIn] - pMerge->aiCol[iMerge];
    ++    if( iDiff==0 ){
    ++      pColset->aiCol[iOut++] = pMerge->aiCol[iMerge];
    ++      iMerge++;
    ++      iIn++;
    ++    }else if( iDiff>0 ){
    ++      iMerge++;
    ++    }else{
    ++      iIn++;
    ++    }
    ++  }
    ++  pColset->nCol = iOut;
    ++}
    ++
    ++/*
    ++** Recursively apply colset pColset to expression node pNode and all of
    ++** its decendents. If (*ppFree) is not NULL, it contains a spare copy
    ++** of pColset. This function may use the spare copy and set (*ppFree) to
    ++** zero, or it may create copies of pColset using fts5CloneColset().
    ++*/
    ++static void fts5ParseSetColset(
    ++  Fts5Parse *pParse, 
    ++  Fts5ExprNode *pNode, 
    ++  Fts5Colset *pColset,
    ++  Fts5Colset **ppFree
    ++){
    ++  if( pParse->rc==SQLITE_OK ){
    ++    assert( pNode->eType==FTS5_TERM || pNode->eType==FTS5_STRING 
    ++         || pNode->eType==FTS5_AND  || pNode->eType==FTS5_OR
    ++         || pNode->eType==FTS5_NOT  || pNode->eType==FTS5_EOF
    ++    );
    ++    if( pNode->eType==FTS5_STRING || pNode->eType==FTS5_TERM ){
    ++      Fts5ExprNearset *pNear = pNode->pNear;
    ++      if( pNear->pColset ){
    ++        fts5MergeColset(pNear->pColset, pColset);
    ++        if( pNear->pColset->nCol==0 ){
    ++          pNode->eType = FTS5_EOF;
    ++          pNode->xNext = 0;
    ++        }
    ++      }else if( *ppFree ){
    ++        pNear->pColset = pColset;
    ++        *ppFree = 0;
    ++      }else{
    ++        pNear->pColset = fts5CloneColset(&pParse->rc, pColset);
    ++      }
    ++    }else{
    ++      int i;
    ++      assert( pNode->eType!=FTS5_EOF || pNode->nChild==0 );
    ++      for(i=0; i<pNode->nChild; i++){
    ++        fts5ParseSetColset(pParse, pNode->apChild[i], pColset, ppFree);
    ++      }
    ++    }
    ++  }
    ++}
    ++
    ++/*
    ++** Apply colset pColset to expression node pExpr and all of its descendents.
    ++*/
    + static void sqlite3Fts5ParseSetColset(
    +   Fts5Parse *pParse, 
    +-  Fts5ExprNearset *pNear, 
    ++  Fts5ExprNode *pExpr, 
    +   Fts5Colset *pColset 
    + ){
    +-  if( pNear ){
    +-    pNear->pColset = pColset;
    ++  Fts5Colset *pFree = pColset;
    ++  if( pParse->pConfig->eDetail==FTS5_DETAIL_NONE ){
    ++    pParse->rc = SQLITE_ERROR;
    ++    pParse->zErr = sqlite3_mprintf(
    ++      "fts5: column queries are not supported (detail=none)"
    ++    );
    +   }else{
    +-    sqlite3_free(pColset);
    ++    fts5ParseSetColset(pParse, pExpr, pColset, &pFree);
    ++  }
    ++  sqlite3_free(pFree);
    ++}
    ++
    ++static void fts5ExprAssignXNext(Fts5ExprNode *pNode){
    ++  switch( pNode->eType ){
    ++    case FTS5_STRING: {
    ++      Fts5ExprNearset *pNear = pNode->pNear;
    ++      if( pNear->nPhrase==1 && pNear->apPhrase[0]->nTerm==1 
    ++       && pNear->apPhrase[0]->aTerm[0].pSynonym==0
    ++       && pNear->apPhrase[0]->aTerm[0].bFirst==0
    ++      ){
    ++        pNode->eType = FTS5_TERM;
    ++        pNode->xNext = fts5ExprNodeNext_TERM;
    ++      }else{
    ++        pNode->xNext = fts5ExprNodeNext_STRING;
    ++      }
    ++      break;
    ++    };
    ++
    ++    case FTS5_OR: {
    ++      pNode->xNext = fts5ExprNodeNext_OR;
    ++      break;
    ++    };
    ++
    ++    case FTS5_AND: {
    ++      pNode->xNext = fts5ExprNodeNext_AND;
    ++      break;
    ++    };
    ++
    ++    default: assert( pNode->eType==FTS5_NOT ); {
    ++      pNode->xNext = fts5ExprNodeNext_NOT;
    ++      break;
    ++    };
    +   }
    + }
    + 
    +@@ -171594,16 +192999,33 @@ static Fts5ExprNode *sqlite3Fts5ParseNode(
    +     if( pRet ){
    +       pRet->eType = eType;
    +       pRet->pNear = pNear;
    ++      fts5ExprAssignXNext(pRet);
    +       if( eType==FTS5_STRING ){
    +         int iPhrase;
    +         for(iPhrase=0; iPhrase<pNear->nPhrase; iPhrase++){
    +           pNear->apPhrase[iPhrase]->pNode = pRet;
    ++          if( pNear->apPhrase[iPhrase]->nTerm==0 ){
    ++            pRet->xNext = 0;
    ++            pRet->eType = FTS5_EOF;
    ++          }
    +         }
    +-        if( pNear->nPhrase==1 
    +-         && pNear->apPhrase[0]->nTerm==1 
    +-         && pNear->apPhrase[0]->aTerm[0].pSynonym==0
    +-        ){
    +-          pRet->eType = FTS5_TERM;
    ++
    ++        if( pParse->pConfig->eDetail!=FTS5_DETAIL_FULL ){
    ++          Fts5ExprPhrase *pPhrase = pNear->apPhrase[0];
    ++          if( pNear->nPhrase!=1 
    ++           || pPhrase->nTerm>1
    ++           || (pPhrase->nTerm>0 && pPhrase->aTerm[0].bFirst)
    ++          ){
    ++            assert( pParse->rc==SQLITE_OK );
    ++            pParse->rc = SQLITE_ERROR;
    ++            assert( pParse->zErr==0 );
    ++            pParse->zErr = sqlite3_mprintf(
    ++                "fts5: %s queries are not supported (detail!=full)", 
    ++                pNear->nPhrase==1 ? "phrase": "NEAR"
    ++                );
    ++            sqlite3_free(pRet);
    ++            pRet = 0;
    ++          }
    +         }
    +       }else{
    +         fts5ExprAddChildren(pRet, pLeft);
    +@@ -171621,6 +193043,70 @@ static Fts5ExprNode *sqlite3Fts5ParseNode(
    +   return pRet;
    + }
    + 
    ++static Fts5ExprNode *sqlite3Fts5ParseImplicitAnd(
    ++  Fts5Parse *pParse,              /* Parse context */
    ++  Fts5ExprNode *pLeft,            /* Left hand child expression */
    ++  Fts5ExprNode *pRight            /* Right hand child expression */
    ++){
    ++  Fts5ExprNode *pRet = 0;
    ++  Fts5ExprNode *pPrev;
    ++
    ++  if( pParse->rc ){
    ++    sqlite3Fts5ParseNodeFree(pLeft);
    ++    sqlite3Fts5ParseNodeFree(pRight);
    ++  }else{
    ++
    ++    assert( pLeft->eType==FTS5_STRING 
    ++        || pLeft->eType==FTS5_TERM
    ++        || pLeft->eType==FTS5_EOF
    ++        || pLeft->eType==FTS5_AND
    ++    );
    ++    assert( pRight->eType==FTS5_STRING 
    ++        || pRight->eType==FTS5_TERM 
    ++        || pRight->eType==FTS5_EOF 
    ++    );
    ++
    ++    if( pLeft->eType==FTS5_AND ){
    ++      pPrev = pLeft->apChild[pLeft->nChild-1];
    ++    }else{
    ++      pPrev = pLeft;
    ++    }
    ++    assert( pPrev->eType==FTS5_STRING 
    ++        || pPrev->eType==FTS5_TERM 
    ++        || pPrev->eType==FTS5_EOF 
    ++        );
    ++
    ++    if( pRight->eType==FTS5_EOF ){
    ++      assert( pParse->apPhrase[pParse->nPhrase-1]==pRight->pNear->apPhrase[0] );
    ++      sqlite3Fts5ParseNodeFree(pRight);
    ++      pRet = pLeft;
    ++      pParse->nPhrase--;
    ++    }
    ++    else if( pPrev->eType==FTS5_EOF ){
    ++      Fts5ExprPhrase **ap;
    ++
    ++      if( pPrev==pLeft ){
    ++        pRet = pRight;
    ++      }else{
    ++        pLeft->apChild[pLeft->nChild-1] = pRight;
    ++        pRet = pLeft;
    ++      }
    ++
    ++      ap = &pParse->apPhrase[pParse->nPhrase-1-pRight->pNear->nPhrase];
    ++      assert( ap[0]==pPrev->pNear->apPhrase[0] );
    ++      memmove(ap, &ap[1], sizeof(Fts5ExprPhrase*)*pRight->pNear->nPhrase);
    ++      pParse->nPhrase--;
    ++
    ++      sqlite3Fts5ParseNodeFree(pPrev);
    ++    }
    ++    else{
    ++      pRet = sqlite3Fts5ParseNode(pParse, FTS5_AND, pLeft, pRight, 0);
    ++    }
    ++  }
    ++
    ++  return pRet;
    ++}
    ++
    + static char *fts5ExprTermPrint(Fts5ExprTerm *pTerm){
    +   int nByte = 0;
    +   Fts5ExprTerm *p;
    +@@ -171628,7 +193114,7 @@ static char *fts5ExprTermPrint(Fts5ExprTerm *pTerm){
    + 
    +   /* Determine the maximum amount of space required. */
    +   for(p=pTerm; p; p=p->pSynonym){
    +-    nByte += strlen(pTerm->zTerm) * 2 + 3 + 2;
    ++    nByte += (int)strlen(pTerm->zTerm) * 2 + 3 + 2;
    +   }
    +   zQuoted = sqlite3_malloc(nByte);
    + 
    +@@ -171717,6 +193203,9 @@ static char *fts5ExprPrintTcl(
    +       for(iTerm=0; zRet && iTerm<pPhrase->nTerm; iTerm++){
    +         char *zTerm = pPhrase->aTerm[iTerm].zTerm;
    +         zRet = fts5PrintfAppend(zRet, "%s%s", iTerm==0?"":" ", zTerm);
    ++        if( pPhrase->aTerm[iTerm].bPrefix ){
    ++          zRet = fts5PrintfAppend(zRet, "*");
    ++        }
    +       }
    + 
    +       if( zRet ) zRet = fts5PrintfAppend(zRet, "}");
    +@@ -171752,6 +193241,9 @@ static char *fts5ExprPrintTcl(
    + 
    + static char *fts5ExprPrint(Fts5Config *pConfig, Fts5ExprNode *pExpr){
    +   char *zRet = 0;
    ++  if( pExpr->eType==0 ){
    ++    return sqlite3_mprintf("\"\"");
    ++  }else
    +   if( pExpr->eType==FTS5_STRING || pExpr->eType==FTS5_TERM ){
    +     Fts5ExprNearset *pNear = pExpr->pNear;
    +     int i; 
    +@@ -171812,7 +193304,7 @@ static char *fts5ExprPrint(Fts5Config *pConfig, Fts5ExprNode *pExpr){
    +         zRet = 0;
    +       }else{
    +         int e = pExpr->apChild[i]->eType;
    +-        int b = (e!=FTS5_STRING && e!=FTS5_TERM);
    ++        int b = (e!=FTS5_STRING && e!=FTS5_TERM && e!=FTS5_EOF);
    +         zRet = fts5PrintfAppend(zRet, "%s%s%z%s", 
    +             (i==0 ? "" : zOp),
    +             (b?"(":""), z, (b?")":"")
    +@@ -171880,11 +193372,11 @@ static void fts5ExprFunction(
    + 
    +   rc = sqlite3Fts5ConfigParse(pGlobal, db, nConfig, azConfig, &pConfig, &zErr);
    +   if( rc==SQLITE_OK ){
    +-    rc = sqlite3Fts5ExprNew(pConfig, zExpr, &pExpr, &zErr);
    ++    rc = sqlite3Fts5ExprNew(pConfig, pConfig->nCol, zExpr, &pExpr, &zErr);
    +   }
    +   if( rc==SQLITE_OK ){
    +     char *zText;
    +-    if( pExpr->pRoot==0 ){
    ++    if( pExpr->pRoot->xNext==0 ){
    +       zText = sqlite3_mprintf("");
    +     }else if( bTcl ){
    +       zText = fts5ExprPrintTcl(pConfig, zNearsetCmd, pExpr->pRoot);
    +@@ -171984,7 +193476,7 @@ static int sqlite3Fts5ExprInit(Fts5Global *pGlobal, sqlite3 *db){
    +   int rc = SQLITE_OK;
    +   void *pCtx = (void*)pGlobal;
    + 
    +-  for(i=0; rc==SQLITE_OK && i<(sizeof(aFunc) / sizeof(aFunc[0])); i++){
    ++  for(i=0; rc==SQLITE_OK && i<ArraySize(aFunc); i++){
    +     struct Fts5ExprFunc *p = &aFunc[i];
    +     rc = sqlite3_create_function(db, p->z, -1, SQLITE_UTF8, pCtx, p->x, 0, 0);
    +   }
    +@@ -172030,6 +193522,215 @@ static int sqlite3Fts5ExprPoslist(Fts5Expr *pExpr, int iPhrase, const u8 **pa){
    +   return nRet;
    + }
    + 
    ++struct Fts5PoslistPopulator {
    ++  Fts5PoslistWriter writer;
    ++  int bOk;                        /* True if ok to populate */
    ++  int bMiss;
    ++};
    ++
    ++static Fts5PoslistPopulator *sqlite3Fts5ExprClearPoslists(Fts5Expr *pExpr, int bLive){
    ++  Fts5PoslistPopulator *pRet;
    ++  pRet = sqlite3_malloc(sizeof(Fts5PoslistPopulator)*pExpr->nPhrase);
    ++  if( pRet ){
    ++    int i;
    ++    memset(pRet, 0, sizeof(Fts5PoslistPopulator)*pExpr->nPhrase);
    ++    for(i=0; i<pExpr->nPhrase; i++){
    ++      Fts5Buffer *pBuf = &pExpr->apExprPhrase[i]->poslist;
    ++      Fts5ExprNode *pNode = pExpr->apExprPhrase[i]->pNode;
    ++      assert( pExpr->apExprPhrase[i]->nTerm==1 );
    ++      if( bLive && 
    ++          (pBuf->n==0 || pNode->iRowid!=pExpr->pRoot->iRowid || pNode->bEof)
    ++      ){
    ++        pRet[i].bMiss = 1;
    ++      }else{
    ++        pBuf->n = 0;
    ++      }
    ++    }
    ++  }
    ++  return pRet;
    ++}
    ++
    ++struct Fts5ExprCtx {
    ++  Fts5Expr *pExpr;
    ++  Fts5PoslistPopulator *aPopulator;
    ++  i64 iOff;
    ++};
    ++typedef struct Fts5ExprCtx Fts5ExprCtx;
    ++
    ++/*
    ++** TODO: Make this more efficient!
    ++*/
    ++static int fts5ExprColsetTest(Fts5Colset *pColset, int iCol){
    ++  int i;
    ++  for(i=0; i<pColset->nCol; i++){
    ++    if( pColset->aiCol[i]==iCol ) return 1;
    ++  }
    ++  return 0;
    ++}
    ++
    ++static int fts5ExprPopulatePoslistsCb(
    ++  void *pCtx,                /* Copy of 2nd argument to xTokenize() */
    ++  int tflags,                /* Mask of FTS5_TOKEN_* flags */
    ++  const char *pToken,        /* Pointer to buffer containing token */
    ++  int nToken,                /* Size of token in bytes */
    ++  int iUnused1,              /* Byte offset of token within input text */
    ++  int iUnused2               /* Byte offset of end of token within input text */
    ++){
    ++  Fts5ExprCtx *p = (Fts5ExprCtx*)pCtx;
    ++  Fts5Expr *pExpr = p->pExpr;
    ++  int i;
    ++
    ++  UNUSED_PARAM2(iUnused1, iUnused2);
    ++
    ++  if( nToken>FTS5_MAX_TOKEN_SIZE ) nToken = FTS5_MAX_TOKEN_SIZE;
    ++  if( (tflags & FTS5_TOKEN_COLOCATED)==0 ) p->iOff++;
    ++  for(i=0; i<pExpr->nPhrase; i++){
    ++    Fts5ExprTerm *pTerm;
    ++    if( p->aPopulator[i].bOk==0 ) continue;
    ++    for(pTerm=&pExpr->apExprPhrase[i]->aTerm[0]; pTerm; pTerm=pTerm->pSynonym){
    ++      int nTerm = (int)strlen(pTerm->zTerm);
    ++      if( (nTerm==nToken || (nTerm<nToken && pTerm->bPrefix))
    ++       && memcmp(pTerm->zTerm, pToken, nTerm)==0
    ++      ){
    ++        int rc = sqlite3Fts5PoslistWriterAppend(
    ++            &pExpr->apExprPhrase[i]->poslist, &p->aPopulator[i].writer, p->iOff
    ++        );
    ++        if( rc ) return rc;
    ++        break;
    ++      }
    ++    }
    ++  }
    ++  return SQLITE_OK;
    ++}
    ++
    ++static int sqlite3Fts5ExprPopulatePoslists(
    ++  Fts5Config *pConfig,
    ++  Fts5Expr *pExpr, 
    ++  Fts5PoslistPopulator *aPopulator,
    ++  int iCol, 
    ++  const char *z, int n
    ++){
    ++  int i;
    ++  Fts5ExprCtx sCtx;
    ++  sCtx.pExpr = pExpr;
    ++  sCtx.aPopulator = aPopulator;
    ++  sCtx.iOff = (((i64)iCol) << 32) - 1;
    ++
    ++  for(i=0; i<pExpr->nPhrase; i++){
    ++    Fts5ExprNode *pNode = pExpr->apExprPhrase[i]->pNode;
    ++    Fts5Colset *pColset = pNode->pNear->pColset;
    ++    if( (pColset && 0==fts5ExprColsetTest(pColset, iCol)) 
    ++     || aPopulator[i].bMiss
    ++    ){
    ++      aPopulator[i].bOk = 0;
    ++    }else{
    ++      aPopulator[i].bOk = 1;
    ++    }
    ++  }
    ++
    ++  return sqlite3Fts5Tokenize(pConfig, 
    ++      FTS5_TOKENIZE_DOCUMENT, z, n, (void*)&sCtx, fts5ExprPopulatePoslistsCb
    ++  );
    ++}
    ++
    ++static void fts5ExprClearPoslists(Fts5ExprNode *pNode){
    ++  if( pNode->eType==FTS5_TERM || pNode->eType==FTS5_STRING ){
    ++    pNode->pNear->apPhrase[0]->poslist.n = 0;
    ++  }else{
    ++    int i;
    ++    for(i=0; i<pNode->nChild; i++){
    ++      fts5ExprClearPoslists(pNode->apChild[i]);
    ++    }
    ++  }
    ++}
    ++
    ++static int fts5ExprCheckPoslists(Fts5ExprNode *pNode, i64 iRowid){
    ++  pNode->iRowid = iRowid;
    ++  pNode->bEof = 0;
    ++  switch( pNode->eType ){
    ++    case FTS5_TERM:
    ++    case FTS5_STRING:
    ++      return (pNode->pNear->apPhrase[0]->poslist.n>0);
    ++
    ++    case FTS5_AND: {
    ++      int i;
    ++      for(i=0; i<pNode->nChild; i++){
    ++        if( fts5ExprCheckPoslists(pNode->apChild[i], iRowid)==0 ){
    ++          fts5ExprClearPoslists(pNode);
    ++          return 0;
    ++        }
    ++      }
    ++      break;
    ++    }
    ++
    ++    case FTS5_OR: {
    ++      int i;
    ++      int bRet = 0;
    ++      for(i=0; i<pNode->nChild; i++){
    ++        if( fts5ExprCheckPoslists(pNode->apChild[i], iRowid) ){
    ++          bRet = 1;
    ++        }
    ++      }
    ++      return bRet;
    ++    }
    ++
    ++    default: {
    ++      assert( pNode->eType==FTS5_NOT );
    ++      if( 0==fts5ExprCheckPoslists(pNode->apChild[0], iRowid)
    ++          || 0!=fts5ExprCheckPoslists(pNode->apChild[1], iRowid)
    ++        ){
    ++        fts5ExprClearPoslists(pNode);
    ++        return 0;
    ++      }
    ++      break;
    ++    }
    ++  }
    ++  return 1;
    ++}
    ++
    ++static void sqlite3Fts5ExprCheckPoslists(Fts5Expr *pExpr, i64 iRowid){
    ++  fts5ExprCheckPoslists(pExpr->pRoot, iRowid);
    ++}
    ++
    ++/*
    ++** This function is only called for detail=columns tables. 
    ++*/
    ++static int sqlite3Fts5ExprPhraseCollist(
    ++  Fts5Expr *pExpr, 
    ++  int iPhrase, 
    ++  const u8 **ppCollist, 
    ++  int *pnCollist
    ++){
    ++  Fts5ExprPhrase *pPhrase = pExpr->apExprPhrase[iPhrase];
    ++  Fts5ExprNode *pNode = pPhrase->pNode;
    ++  int rc = SQLITE_OK;
    ++
    ++  assert( iPhrase>=0 && iPhrase<pExpr->nPhrase );
    ++  assert( pExpr->pConfig->eDetail==FTS5_DETAIL_COLUMNS );
    ++
    ++  if( pNode->bEof==0 
    ++   && pNode->iRowid==pExpr->pRoot->iRowid 
    ++   && pPhrase->poslist.n>0
    ++  ){
    ++    Fts5ExprTerm *pTerm = &pPhrase->aTerm[0];
    ++    if( pTerm->pSynonym ){
    ++      Fts5Buffer *pBuf = (Fts5Buffer*)&pTerm->pSynonym[1];
    ++      rc = fts5ExprSynonymList(
    ++          pTerm, pNode->iRowid, pBuf, (u8**)ppCollist, pnCollist
    ++      );
    ++    }else{
    ++      *ppCollist = pPhrase->aTerm[0].pIter->pData;
    ++      *pnCollist = pPhrase->aTerm[0].pIter->nData;
    ++    }
    ++  }else{
    ++    *ppCollist = 0;
    ++    *pnCollist = 0;
    ++  }
    ++
    ++  return rc;
    ++}
    ++
    ++
    + /*
    + ** 2014 August 11
    + **
    +@@ -172046,6 +193747,7 @@ static int sqlite3Fts5ExprPoslist(Fts5Expr *pExpr, int iPhrase, const u8 **pa){
    + 
    + 
    + 
    ++/* #include "fts5Int.h" */
    + 
    + typedef struct Fts5HashEntry Fts5HashEntry;
    + 
    +@@ -172057,6 +193759,7 @@ typedef struct Fts5HashEntry Fts5HashEntry;
    + 
    + 
    + struct Fts5Hash {
    ++  int eDetail;                    /* Copy of Fts5Config.eDetail */
    +   int *pnByte;                    /* Pointer to bytes counter */
    +   int nEntry;                     /* Number of entries currently in hash */
    +   int nSlot;                      /* Size of aSlot[] array */
    +@@ -172066,9 +193769,10 @@ struct Fts5Hash {
    + 
    + /*
    + ** Each entry in the hash table is represented by an object of the 
    +-** following type. Each object, its key (zKey[]) and its current data
    +-** are stored in a single memory allocation. The position list data 
    +-** immediately follows the key data in memory.
    ++** following type. Each object, its key (a nul-terminated string) and 
    ++** its current data are stored in a single memory allocation. The 
    ++** key immediately follows the object in memory. The position list
    ++** data immediately follows the key data in memory.
    + **
    + ** The data that follows the key is in a similar, but not identical format
    + ** to the doclist data stored in the database. It is:
    +@@ -172092,25 +193796,26 @@ struct Fts5HashEntry {
    +   int nAlloc;                     /* Total size of allocation */
    +   int iSzPoslist;                 /* Offset of space for 4-byte poslist size */
    +   int nData;                      /* Total bytes of data (incl. structure) */
    ++  int nKey;                       /* Length of key in bytes */
    +   u8 bDel;                        /* Set delete-flag @ iSzPoslist */
    +-
    +-  int iCol;                       /* Column of last value written */
    ++  u8 bContent;                    /* Set content-flag (detail=none mode) */
    ++  i16 iCol;                       /* Column of last value written */
    +   int iPos;                       /* Position of last value written */
    +   i64 iRowid;                     /* Rowid of last value written */
    +-  char zKey[8];                   /* Nul-terminated entry key */
    + };
    + 
    + /*
    +-** Size of Fts5HashEntry without the zKey[] array.
    ++** Eqivalent to:
    ++**
    ++**   char *fts5EntryKey(Fts5HashEntry *pEntry){ return zKey; }
    + */
    +-#define FTS5_HASHENTRYSIZE (sizeof(Fts5HashEntry)-8)
    +-
    ++#define fts5EntryKey(p) ( ((char *)(&(p)[1])) )
    + 
    + 
    + /*
    + ** Allocate a new hash table.
    + */
    +-static int sqlite3Fts5HashNew(Fts5Hash **ppNew, int *pnByte){
    ++static int sqlite3Fts5HashNew(Fts5Config *pConfig, Fts5Hash **ppNew, int *pnByte){
    +   int rc = SQLITE_OK;
    +   Fts5Hash *pNew;
    + 
    +@@ -172121,6 +193826,7 @@ static int sqlite3Fts5HashNew(Fts5Hash **ppNew, int *pnByte){
    +     int nByte;
    +     memset(pNew, 0, sizeof(Fts5Hash));
    +     pNew->pnByte = pnByte;
    ++    pNew->eDetail = pConfig->eDetail;
    + 
    +     pNew->nSlot = 1024;
    +     nByte = sizeof(Fts5HashEntry*) * pNew->nSlot;
    +@@ -172198,10 +193904,11 @@ static int fts5HashResize(Fts5Hash *pHash){
    + 
    +   for(i=0; i<pHash->nSlot; i++){
    +     while( apOld[i] ){
    +-      int iHash;
    ++      unsigned int iHash;
    +       Fts5HashEntry *p = apOld[i];
    +       apOld[i] = p->pHashNext;
    +-      iHash = fts5HashKey(nNew, (u8*)p->zKey, strlen(p->zKey));
    ++      iHash = fts5HashKey(nNew, (u8*)fts5EntryKey(p),
    ++                          (int)strlen(fts5EntryKey(p)));
    +       p->pHashNext = apNew[iHash];
    +       apNew[iHash] = p;
    +     }
    +@@ -172213,26 +193920,46 @@ static int fts5HashResize(Fts5Hash *pHash){
    +   return SQLITE_OK;
    + }
    + 
    +-static void fts5HashAddPoslistSize(Fts5HashEntry *p){
    ++static void fts5HashAddPoslistSize(Fts5Hash *pHash, Fts5HashEntry *p){
    +   if( p->iSzPoslist ){
    +     u8 *pPtr = (u8*)p;
    +-    int nSz = (p->nData - p->iSzPoslist - 1);         /* Size in bytes */
    +-    int nPos = nSz*2 + p->bDel;                       /* Value of nPos field */
    +-
    +-    assert( p->bDel==0 || p->bDel==1 );
    +-    if( nPos<=127 ){
    +-      pPtr[p->iSzPoslist] = nPos;
    ++    if( pHash->eDetail==FTS5_DETAIL_NONE ){
    ++      assert( p->nData==p->iSzPoslist );
    ++      if( p->bDel ){
    ++        pPtr[p->nData++] = 0x00;
    ++        if( p->bContent ){
    ++          pPtr[p->nData++] = 0x00;
    ++        }
    ++      }
    +     }else{
    +-      int nByte = sqlite3Fts5GetVarintLen((u32)nPos);
    +-      memmove(&pPtr[p->iSzPoslist + nByte], &pPtr[p->iSzPoslist + 1], nSz);
    +-      sqlite3Fts5PutVarint(&pPtr[p->iSzPoslist], nPos);
    +-      p->nData += (nByte-1);
    ++      int nSz = (p->nData - p->iSzPoslist - 1);       /* Size in bytes */
    ++      int nPos = nSz*2 + p->bDel;                     /* Value of nPos field */
    ++
    ++      assert( p->bDel==0 || p->bDel==1 );
    ++      if( nPos<=127 ){
    ++        pPtr[p->iSzPoslist] = (u8)nPos;
    ++      }else{
    ++        int nByte = sqlite3Fts5GetVarintLen((u32)nPos);
    ++        memmove(&pPtr[p->iSzPoslist + nByte], &pPtr[p->iSzPoslist + 1], nSz);
    ++        sqlite3Fts5PutVarint(&pPtr[p->iSzPoslist], nPos);
    ++        p->nData += (nByte-1);
    ++      }
    +     }
    +-    p->bDel = 0;
    ++
    +     p->iSzPoslist = 0;
    ++    p->bDel = 0;
    ++    p->bContent = 0;
    +   }
    + }
    + 
    ++/*
    ++** Add an entry to the in-memory hash table. The key is the concatenation
    ++** of bByte and (pToken/nToken). The value is (iRowid/iCol/iPos).
    ++**
    ++**     (bByte || pToken) -> (iRowid,iCol,iPos)
    ++**
    ++** Or, if iCol is negative, then the value is a delete marker.
    ++*/
    + static int sqlite3Fts5HashWrite(
    +   Fts5Hash *pHash,
    +   i64 iRowid,                     /* Rowid for this entry */
    +@@ -172245,13 +193972,17 @@ static int sqlite3Fts5HashWrite(
    +   Fts5HashEntry *p;
    +   u8 *pPtr;
    +   int nIncr = 0;                  /* Amount to increment (*pHash->pnByte) by */
    ++  int bNew;                       /* If non-delete entry should be written */
    ++  
    ++  bNew = (pHash->eDetail==FTS5_DETAIL_FULL);
    + 
    +   /* Attempt to locate an existing hash entry */
    +   iHash = fts5HashKey2(pHash->nSlot, (u8)bByte, (const u8*)pToken, nToken);
    +   for(p=pHash->aSlot[iHash]; p; p=p->pHashNext){
    +-    if( p->zKey[0]==bByte 
    +-     && memcmp(&p->zKey[1], pToken, nToken)==0 
    +-     && p->zKey[nToken+1]==0 
    ++    char *zKey = fts5EntryKey(p);
    ++    if( zKey[0]==bByte 
    ++     && p->nKey==nToken
    ++     && memcmp(&zKey[1], pToken, nToken)==0 
    +     ){
    +       break;
    +     }
    +@@ -172259,88 +193990,119 @@ static int sqlite3Fts5HashWrite(
    + 
    +   /* If an existing hash entry cannot be found, create a new one. */
    +   if( p==0 ){
    +-    int nByte = FTS5_HASHENTRYSIZE + (nToken+1) + 1 + 64;
    ++    /* Figure out how much space to allocate */
    ++    char *zKey;
    ++    int nByte = sizeof(Fts5HashEntry) + (nToken+1) + 1 + 64;
    +     if( nByte<128 ) nByte = 128;
    + 
    ++    /* Grow the Fts5Hash.aSlot[] array if necessary. */
    +     if( (pHash->nEntry*2)>=pHash->nSlot ){
    +       int rc = fts5HashResize(pHash);
    +       if( rc!=SQLITE_OK ) return rc;
    +       iHash = fts5HashKey2(pHash->nSlot, (u8)bByte, (const u8*)pToken, nToken);
    +     }
    + 
    ++    /* Allocate new Fts5HashEntry and add it to the hash table. */
    +     p = (Fts5HashEntry*)sqlite3_malloc(nByte);
    +     if( !p ) return SQLITE_NOMEM;
    +-    memset(p, 0, FTS5_HASHENTRYSIZE);
    ++    memset(p, 0, sizeof(Fts5HashEntry));
    +     p->nAlloc = nByte;
    +-    p->zKey[0] = bByte;
    +-    memcpy(&p->zKey[1], pToken, nToken);
    +-    assert( iHash==fts5HashKey(pHash->nSlot, (u8*)p->zKey, nToken+1) );
    +-    p->zKey[nToken+1] = '\0';
    +-    p->nData = nToken+1 + 1 + FTS5_HASHENTRYSIZE;
    +-    p->nData += sqlite3Fts5PutVarint(&((u8*)p)[p->nData], iRowid);
    +-    p->iSzPoslist = p->nData;
    +-    p->nData += 1;
    +-    p->iRowid = iRowid;
    ++    zKey = fts5EntryKey(p);
    ++    zKey[0] = bByte;
    ++    memcpy(&zKey[1], pToken, nToken);
    ++    assert( iHash==fts5HashKey(pHash->nSlot, (u8*)zKey, nToken+1) );
    ++    p->nKey = nToken;
    ++    zKey[nToken+1] = '\0';
    ++    p->nData = nToken+1 + 1 + sizeof(Fts5HashEntry);
    +     p->pHashNext = pHash->aSlot[iHash];
    +     pHash->aSlot[iHash] = p;
    +     pHash->nEntry++;
    ++
    ++    /* Add the first rowid field to the hash-entry */
    ++    p->nData += sqlite3Fts5PutVarint(&((u8*)p)[p->nData], iRowid);
    ++    p->iRowid = iRowid;
    ++
    ++    p->iSzPoslist = p->nData;
    ++    if( pHash->eDetail!=FTS5_DETAIL_NONE ){
    ++      p->nData += 1;
    ++      p->iCol = (pHash->eDetail==FTS5_DETAIL_FULL ? 0 : -1);
    ++    }
    ++
    +     nIncr += p->nData;
    +-  }
    ++  }else{
    + 
    +-  /* Check there is enough space to append a new entry. Worst case scenario
    +-  ** is:
    +-  **
    +-  **     + 9 bytes for a new rowid,
    +-  **     + 4 byte reserved for the "poslist size" varint.
    +-  **     + 1 byte for a "new column" byte,
    +-  **     + 3 bytes for a new column number (16-bit max) as a varint,
    +-  **     + 5 bytes for the new position offset (32-bit max).
    +-  */
    +-  if( (p->nAlloc - p->nData) < (9 + 4 + 1 + 3 + 5) ){
    +-    int nNew = p->nAlloc * 2;
    +-    Fts5HashEntry *pNew;
    +-    Fts5HashEntry **pp;
    +-    pNew = (Fts5HashEntry*)sqlite3_realloc(p, nNew);
    +-    if( pNew==0 ) return SQLITE_NOMEM;
    +-    pNew->nAlloc = nNew;
    +-    for(pp=&pHash->aSlot[iHash]; *pp!=p; pp=&(*pp)->pHashNext);
    +-    *pp = pNew;
    +-    p = pNew;
    ++    /* Appending to an existing hash-entry. Check that there is enough 
    ++    ** space to append the largest possible new entry. Worst case scenario 
    ++    ** is:
    ++    **
    ++    **     + 9 bytes for a new rowid,
    ++    **     + 4 byte reserved for the "poslist size" varint.
    ++    **     + 1 byte for a "new column" byte,
    ++    **     + 3 bytes for a new column number (16-bit max) as a varint,
    ++    **     + 5 bytes for the new position offset (32-bit max).
    ++    */
    ++    if( (p->nAlloc - p->nData) < (9 + 4 + 1 + 3 + 5) ){
    ++      int nNew = p->nAlloc * 2;
    ++      Fts5HashEntry *pNew;
    ++      Fts5HashEntry **pp;
    ++      pNew = (Fts5HashEntry*)sqlite3_realloc(p, nNew);
    ++      if( pNew==0 ) return SQLITE_NOMEM;
    ++      pNew->nAlloc = nNew;
    ++      for(pp=&pHash->aSlot[iHash]; *pp!=p; pp=&(*pp)->pHashNext);
    ++      *pp = pNew;
    ++      p = pNew;
    ++    }
    ++    nIncr -= p->nData;
    +   }
    ++  assert( (p->nAlloc - p->nData) >= (9 + 4 + 1 + 3 + 5) );
    ++
    +   pPtr = (u8*)p;
    +-  nIncr -= p->nData;
    + 
    +   /* If this is a new rowid, append the 4-byte size field for the previous
    +   ** entry, and the new rowid for this entry.  */
    +   if( iRowid!=p->iRowid ){
    +-    fts5HashAddPoslistSize(p);
    ++    fts5HashAddPoslistSize(pHash, p);
    +     p->nData += sqlite3Fts5PutVarint(&pPtr[p->nData], iRowid - p->iRowid);
    +-    p->iSzPoslist = p->nData;
    +-    p->nData += 1;
    +-    p->iCol = 0;
    +-    p->iPos = 0;
    +     p->iRowid = iRowid;
    ++    bNew = 1;
    ++    p->iSzPoslist = p->nData;
    ++    if( pHash->eDetail!=FTS5_DETAIL_NONE ){
    ++      p->nData += 1;
    ++      p->iCol = (pHash->eDetail==FTS5_DETAIL_FULL ? 0 : -1);
    ++      p->iPos = 0;
    ++    }
    +   }
    + 
    +   if( iCol>=0 ){
    +-    /* Append a new column value, if necessary */
    +-    assert( iCol>=p->iCol );
    +-    if( iCol!=p->iCol ){
    +-      pPtr[p->nData++] = 0x01;
    +-      p->nData += sqlite3Fts5PutVarint(&pPtr[p->nData], iCol);
    +-      p->iCol = iCol;
    +-      p->iPos = 0;
    +-    }
    ++    if( pHash->eDetail==FTS5_DETAIL_NONE ){
    ++      p->bContent = 1;
    ++    }else{
    ++      /* Append a new column value, if necessary */
    ++      assert( iCol>=p->iCol );
    ++      if( iCol!=p->iCol ){
    ++        if( pHash->eDetail==FTS5_DETAIL_FULL ){
    ++          pPtr[p->nData++] = 0x01;
    ++          p->nData += sqlite3Fts5PutVarint(&pPtr[p->nData], iCol);
    ++          p->iCol = (i16)iCol;
    ++          p->iPos = 0;
    ++        }else{
    ++          bNew = 1;
    ++          p->iCol = (i16)(iPos = iCol);
    ++        }
    ++      }
    + 
    +-    /* Append the new position offset */
    +-    p->nData += sqlite3Fts5PutVarint(&pPtr[p->nData], iPos - p->iPos + 2);
    +-    p->iPos = iPos;
    ++      /* Append the new position offset, if necessary */
    ++      if( bNew ){
    ++        p->nData += sqlite3Fts5PutVarint(&pPtr[p->nData], iPos - p->iPos + 2);
    ++        p->iPos = iPos;
    ++      }
    ++    }
    +   }else{
    +     /* This is a delete. Set the delete flag. */
    +     p->bDel = 1;
    +   }
    +-  nIncr += p->nData;
    + 
    ++  nIncr += p->nData;
    +   *pHash->pnByte += nIncr;
    +   return SQLITE_OK;
    + }
    +@@ -172369,9 +194131,11 @@ static Fts5HashEntry *fts5HashEntryMerge(
    +       p1 = 0;
    +     }else{
    +       int i = 0;
    +-      while( p1->zKey[i]==p2->zKey[i] ) i++;
    ++      char *zKey1 = fts5EntryKey(p1);
    ++      char *zKey2 = fts5EntryKey(p2);
    ++      while( zKey1[i]==zKey2[i] ) i++;
    + 
    +-      if( ((u8)p1->zKey[i])>((u8)p2->zKey[i]) ){
    ++      if( ((u8)zKey1[i])>((u8)zKey2[i]) ){
    +         /* p2 is smaller */
    +         *ppOut = p2;
    +         ppOut = &p2->pScanNext;
    +@@ -172414,7 +194178,7 @@ static int fts5HashEntrySort(
    +   for(iSlot=0; iSlot<pHash->nSlot; iSlot++){
    +     Fts5HashEntry *pIter;
    +     for(pIter=pHash->aSlot[iSlot]; pIter; pIter=pIter->pHashNext){
    +-      if( pTerm==0 || 0==memcmp(pIter->zKey, pTerm, nTerm) ){
    ++      if( pTerm==0 || 0==memcmp(fts5EntryKey(pIter), pTerm, nTerm) ){
    +         Fts5HashEntry *pEntry = pIter;
    +         pEntry->pScanNext = 0;
    +         for(i=0; ap[i]; i++){
    +@@ -172447,16 +194211,18 @@ static int sqlite3Fts5HashQuery(
    +   int *pnDoclist                  /* OUT: Size of doclist in bytes */
    + ){
    +   unsigned int iHash = fts5HashKey(pHash->nSlot, (const u8*)pTerm, nTerm);
    ++  char *zKey = 0;
    +   Fts5HashEntry *p;
    + 
    +   for(p=pHash->aSlot[iHash]; p; p=p->pHashNext){
    +-    if( memcmp(p->zKey, pTerm, nTerm)==0 && p->zKey[nTerm]==0 ) break;
    ++    zKey = fts5EntryKey(p);
    ++    if( memcmp(zKey, pTerm, nTerm)==0 && zKey[nTerm]==0 ) break;
    +   }
    + 
    +   if( p ){
    +-    fts5HashAddPoslistSize(p);
    +-    *ppDoclist = (const u8*)&p->zKey[nTerm+1];
    +-    *pnDoclist = p->nData - (FTS5_HASHENTRYSIZE + nTerm + 1);
    ++    fts5HashAddPoslistSize(pHash, p);
    ++    *ppDoclist = (const u8*)&zKey[nTerm+1];
    ++    *pnDoclist = p->nData - (sizeof(Fts5HashEntry) + nTerm + 1);
    +   }else{
    +     *ppDoclist = 0;
    +     *pnDoclist = 0;
    +@@ -172489,11 +194255,12 @@ static void sqlite3Fts5HashScanEntry(
    + ){
    +   Fts5HashEntry *p;
    +   if( (p = pHash->pScan) ){
    +-    int nTerm = strlen(p->zKey);
    +-    fts5HashAddPoslistSize(p);
    +-    *pzTerm = p->zKey;
    +-    *ppDoclist = (const u8*)&p->zKey[nTerm+1];
    +-    *pnDoclist = p->nData - (FTS5_HASHENTRYSIZE + nTerm + 1);
    ++    char *zKey = fts5EntryKey(p);
    ++    int nTerm = (int)strlen(zKey);
    ++    fts5HashAddPoslistSize(pHash, p);
    ++    *pzTerm = zKey;
    ++    *ppDoclist = (const u8*)&zKey[nTerm+1];
    ++    *pnDoclist = p->nData - (sizeof(Fts5HashEntry) + nTerm + 1);
    +   }else{
    +     *pzTerm = 0;
    +     *ppDoclist = 0;
    +@@ -172521,6 +194288,7 @@ static void sqlite3Fts5HashScanEntry(
    + */
    + 
    + 
    ++/* #include "fts5Int.h" */
    + 
    + /*
    + ** Overview:
    +@@ -172764,6 +194532,7 @@ typedef struct Fts5Data Fts5Data;
    + typedef struct Fts5DlidxIter Fts5DlidxIter;
    + typedef struct Fts5DlidxLvl Fts5DlidxLvl;
    + typedef struct Fts5DlidxWriter Fts5DlidxWriter;
    ++typedef struct Fts5Iter Fts5Iter;
    + typedef struct Fts5PageWriter Fts5PageWriter;
    + typedef struct Fts5SegIter Fts5SegIter;
    + typedef struct Fts5DoclistIter Fts5DoclistIter;
    +@@ -172791,7 +194560,6 @@ struct Fts5Index {
    +   ** in-memory hash tables before they are flushed to disk.
    +   */
    +   Fts5Hash *pHash;                /* Hash table for in-memory data */
    +-  int nMaxPendingData;            /* Max pending data before flush to disk */
    +   int nPendingData;               /* Current bytes of pending data */
    +   i64 iWriteRowid;                /* Rowid for current doc being written */
    +   int bDelete;                    /* Current write is a delete */
    +@@ -172807,6 +194575,10 @@ struct Fts5Index {
    +   sqlite3_stmt *pIdxDeleter;      /* "DELETE FROM %_idx WHERE segid=? */
    +   sqlite3_stmt *pIdxSelect;
    +   int nRead;                      /* Total number of blocks read */
    ++
    ++  sqlite3_stmt *pDataVersion;
    ++  i64 iStructVersion;             /* data_version when pStruct read */
    ++  Fts5Structure *pStruct;         /* Current db structure (or NULL) */
    + };
    + 
    + struct Fts5DoclistIter {
    +@@ -172877,26 +194649,6 @@ struct Fts5SegWriter {
    +   int iBtPage;                    /* Page number corresponding to btterm */
    + };
    + 
    +-/*
    +-** Object for iterating through the merged results of one or more segments,
    +-** visiting each term/rowid pair in the merged data.
    +-**
    +-** nSeg is always a power of two greater than or equal to the number of
    +-** segments that this object is merging data from. Both the aSeg[] and
    +-** aFirst[] arrays are sized at nSeg entries. The aSeg[] array is padded
    +-** with zeroed objects - these are handled as if they were iterators opened
    +-** on empty segments.
    +-**
    +-** The results of comparing segments aSeg[N] and aSeg[N+1], where N is an
    +-** even number, is stored in aFirst[(nSeg+N)/2]. The "result" of the 
    +-** comparison in this context is the index of the iterator that currently
    +-** points to the smaller term/rowid combination. Iterators at EOF are
    +-** considered to be greater than all other iterators.
    +-**
    +-** aFirst[1] contains the index in aSeg[] of the iterator that points to
    +-** the smallest key overall. aFirst[0] is unused. 
    +-*/
    +-
    + typedef struct Fts5CResult Fts5CResult;
    + struct Fts5CResult {
    +   u16 iFirst;                     /* aSeg[] index of firstest iterator */
    +@@ -172957,6 +194709,9 @@ struct Fts5SegIter {
    +   Fts5Data *pNextLeaf;            /* Leaf page (iLeafPgno+1) */
    +   int iLeafOffset;                /* Byte offset within current leaf */
    + 
    ++  /* Next method */
    ++  void (*xNext)(Fts5Index*, Fts5SegIter*, int*);
    ++
    +   /* The page and offset from which the current term was read. The offset 
    +   ** is the offset of the first rowid in the current doclist.  */
    +   int iTermLeafPgno;
    +@@ -172976,7 +194731,7 @@ struct Fts5SegIter {
    +   Fts5Buffer term;                /* Current term */
    +   i64 iRowid;                     /* Current rowid */
    +   int nPos;                       /* Number of bytes in current position list */
    +-  int bDel;                       /* True if the delete flag is set */
    ++  u8 bDel;                        /* True if the delete flag is set */
    + };
    + 
    + /*
    +@@ -172990,7 +194745,6 @@ struct Fts5SegIter {
    + #define FTS5_SEGITER_ONETERM 0x01
    + #define FTS5_SEGITER_REVERSE 0x02
    + 
    +-
    + /* 
    + ** Argument is a pointer to an Fts5Data structure that contains a leaf
    + ** page. This macro evaluates to true if the leaf contains no terms, or
    +@@ -173003,20 +194757,42 @@ struct Fts5SegIter {
    + #define fts5LeafFirstRowidOff(x) (fts5GetU16((x)->p))
    + 
    + /*
    ++** Object for iterating through the merged results of one or more segments,
    ++** visiting each term/rowid pair in the merged data.
    ++**
    ++** nSeg is always a power of two greater than or equal to the number of
    ++** segments that this object is merging data from. Both the aSeg[] and
    ++** aFirst[] arrays are sized at nSeg entries. The aSeg[] array is padded
    ++** with zeroed objects - these are handled as if they were iterators opened
    ++** on empty segments.
    ++**
    ++** The results of comparing segments aSeg[N] and aSeg[N+1], where N is an
    ++** even number, is stored in aFirst[(nSeg+N)/2]. The "result" of the 
    ++** comparison in this context is the index of the iterator that currently
    ++** points to the smaller term/rowid combination. Iterators at EOF are
    ++** considered to be greater than all other iterators.
    ++**
    ++** aFirst[1] contains the index in aSeg[] of the iterator that points to
    ++** the smallest key overall. aFirst[0] is unused. 
    ++**
    + ** poslist:
    + **   Used by sqlite3Fts5IterPoslist() when the poslist needs to be buffered.
    + **   There is no way to tell if this is populated or not.
    + */
    +-struct Fts5IndexIter {
    ++struct Fts5Iter {
    ++  Fts5IndexIter base;             /* Base class containing output vars */
    ++
    +   Fts5Index *pIndex;              /* Index that owns this iterator */
    +   Fts5Structure *pStruct;         /* Database structure for this iterator */
    +   Fts5Buffer poslist;             /* Buffer containing current poslist */
    ++  Fts5Colset *pColset;            /* Restrict matches to these columns */
    ++
    ++  /* Invoked to set output variables. */
    ++  void (*xSetOutputs)(Fts5Iter*, Fts5SegIter*);
    + 
    +   int nSeg;                       /* Size of aSeg[] array */
    +   int bRev;                       /* True to iterate in reverse order */
    +   u8 bSkipEmpty;                  /* True to skip deleted entries */
    +-  u8 bEof;                        /* True at EOF */
    +-  u8 bFiltered;                   /* True if column-filter already applied */
    + 
    +   i64 iSwitchRowid;               /* Firstest rowid of other than aFirst[1] */
    +   Fts5CResult *aFirst;            /* Current merge state (see above) */
    +@@ -173106,17 +194882,6 @@ static int fts5BufferCompare(Fts5Buffer *pLeft, Fts5Buffer *pRight){
    +   return (res==0 ? (pLeft->n - pRight->n) : res);
    + }
    + 
    +-#ifdef SQLITE_DEBUG
    +-static int fts5BlobCompare(
    +-  const u8 *pLeft, int nLeft, 
    +-  const u8 *pRight, int nRight
    +-){
    +-  int nCmp = MIN(nLeft, nRight);
    +-  int res = memcmp(pLeft, pRight, nCmp);
    +-  return (res==0 ? (nLeft - nRight) : res);
    +-}
    +-#endif
    +-
    + static int fts5LeafFirstTermOff(Fts5Data *pLeaf){
    +   int ret;
    +   fts5GetVarint32(&pLeaf->p[pLeaf->szLeaf], ret);
    +@@ -173134,7 +194899,6 @@ static void fts5CloseReader(Fts5Index *p){
    +   }
    + }
    + 
    +-
    + /*
    + ** Retrieve a record from the %_data table.
    + **
    +@@ -173216,6 +194980,18 @@ static void fts5DataRelease(Fts5Data *pData){
    +   sqlite3_free(pData);
    + }
    + 
    ++static Fts5Data *fts5LeafRead(Fts5Index *p, i64 iRowid){
    ++  Fts5Data *pRet = fts5DataRead(p, iRowid);
    ++  if( pRet ){
    ++    if( pRet->szLeaf>pRet->nn ){
    ++      p->rc = FTS5_CORRUPT;
    ++      fts5DataRelease(pRet);
    ++      pRet = 0;
    ++    }
    ++  }
    ++  return pRet;
    ++}
    ++
    + static int fts5IndexPrepareStmt(
    +   Fts5Index *p,
    +   sqlite3_stmt **ppStmt,
    +@@ -173223,7 +194999,8 @@ static int fts5IndexPrepareStmt(
    + ){
    +   if( p->rc==SQLITE_OK ){
    +     if( zSql ){
    +-      p->rc = sqlite3_prepare_v2(p->pConfig->db, zSql, -1, ppStmt, 0);
    ++      p->rc = sqlite3_prepare_v3(p->pConfig->db, zSql, -1,
    ++                                 SQLITE_PREPARE_PERSISTENT, ppStmt, 0);
    +     }else{
    +       p->rc = SQLITE_NOMEM;
    +     }
    +@@ -173272,7 +195049,8 @@ static void fts5DataDelete(Fts5Index *p, i64 iFirst, i64 iLast){
    +     if( zSql==0 ){
    +       rc = SQLITE_NOMEM;
    +     }else{
    +-      rc = sqlite3_prepare_v2(pConfig->db, zSql, -1, &p->pDeleter, 0);
    ++      rc = sqlite3_prepare_v3(pConfig->db, zSql, -1,
    ++                              SQLITE_PREPARE_PERSISTENT, &p->pDeleter, 0);
    +       sqlite3_free(zSql);
    +     }
    +     if( rc!=SQLITE_OK ){
    +@@ -173375,28 +195153,37 @@ static int fts5StructureDecode(
    + 
    +     for(iLvl=0; rc==SQLITE_OK && iLvl<nLevel; iLvl++){
    +       Fts5StructureLevel *pLvl = &pRet->aLevel[iLvl];
    +-      int nTotal;
    ++      int nTotal = 0;
    +       int iSeg;
    + 
    +-      i += fts5GetVarint32(&pData[i], pLvl->nMerge);
    +-      i += fts5GetVarint32(&pData[i], nTotal);
    +-      assert( nTotal>=pLvl->nMerge );
    +-      pLvl->aSeg = (Fts5StructureSegment*)sqlite3Fts5MallocZero(&rc, 
    +-          nTotal * sizeof(Fts5StructureSegment)
    +-      );
    ++      if( i>=nData ){
    ++        rc = FTS5_CORRUPT;
    ++      }else{
    ++        i += fts5GetVarint32(&pData[i], pLvl->nMerge);
    ++        i += fts5GetVarint32(&pData[i], nTotal);
    ++        assert( nTotal>=pLvl->nMerge );
    ++        pLvl->aSeg = (Fts5StructureSegment*)sqlite3Fts5MallocZero(&rc, 
    ++            nTotal * sizeof(Fts5StructureSegment)
    ++        );
    ++      }
    + 
    +       if( rc==SQLITE_OK ){
    +         pLvl->nSeg = nTotal;
    +         for(iSeg=0; iSeg<nTotal; iSeg++){
    ++          if( i>=nData ){
    ++            rc = FTS5_CORRUPT;
    ++            break;
    ++          }
    +           i += fts5GetVarint32(&pData[i], pLvl->aSeg[iSeg].iSegid);
    +           i += fts5GetVarint32(&pData[i], pLvl->aSeg[iSeg].pgnoFirst);
    +           i += fts5GetVarint32(&pData[i], pLvl->aSeg[iSeg].pgnoLast);
    +         }
    +-      }else{
    +-        fts5StructureRelease(pRet);
    +-        pRet = 0;
    +       }
    +     }
    ++    if( rc!=SQLITE_OK ){
    ++      fts5StructureRelease(pRet);
    ++      pRet = 0;
    ++    }
    +   }
    + 
    +   *ppOut = pRet;
    +@@ -173459,6 +195246,50 @@ static void fts5StructureExtendLevel(
    +   }
    + }
    + 
    ++static Fts5Structure *fts5StructureReadUncached(Fts5Index *p){
    ++  Fts5Structure *pRet = 0;
    ++  Fts5Config *pConfig = p->pConfig;
    ++  int iCookie;                    /* Configuration cookie */
    ++  Fts5Data *pData;
    ++
    ++  pData = fts5DataRead(p, FTS5_STRUCTURE_ROWID);
    ++  if( p->rc==SQLITE_OK ){
    ++    /* TODO: Do we need this if the leaf-index is appended? Probably... */
    ++    memset(&pData->p[pData->nn], 0, FTS5_DATA_PADDING);
    ++    p->rc = fts5StructureDecode(pData->p, pData->nn, &iCookie, &pRet);
    ++    if( p->rc==SQLITE_OK && pConfig->iCookie!=iCookie ){
    ++      p->rc = sqlite3Fts5ConfigLoad(pConfig, iCookie);
    ++    }
    ++    fts5DataRelease(pData);
    ++    if( p->rc!=SQLITE_OK ){
    ++      fts5StructureRelease(pRet);
    ++      pRet = 0;
    ++    }
    ++  }
    ++
    ++  return pRet;
    ++}
    ++
    ++static i64 fts5IndexDataVersion(Fts5Index *p){
    ++  i64 iVersion = 0;
    ++
    ++  if( p->rc==SQLITE_OK ){
    ++    if( p->pDataVersion==0 ){
    ++      p->rc = fts5IndexPrepareStmt(p, &p->pDataVersion, 
    ++          sqlite3_mprintf("PRAGMA %Q.data_version", p->pConfig->zDb)
    ++          );
    ++      if( p->rc ) return 0;
    ++    }
    ++
    ++    if( SQLITE_ROW==sqlite3_step(p->pDataVersion) ){
    ++      iVersion = sqlite3_column_int64(p->pDataVersion, 0);
    ++    }
    ++    p->rc = sqlite3_reset(p->pDataVersion);
    ++  }
    ++
    ++  return iVersion;
    ++}
    ++
    + /*
    + ** Read, deserialize and return the structure record.
    + **
    +@@ -173471,26 +195302,49 @@ static void fts5StructureExtendLevel(
    + ** is called, it is a no-op.
    + */
    + static Fts5Structure *fts5StructureRead(Fts5Index *p){
    +-  Fts5Config *pConfig = p->pConfig;
    +-  Fts5Structure *pRet = 0;        /* Object to return */
    +-  int iCookie;                    /* Configuration cookie */
    +-  Fts5Data *pData;
    + 
    +-  pData = fts5DataRead(p, FTS5_STRUCTURE_ROWID);
    +-  if( p->rc ) return 0;
    +-  /* TODO: Do we need this if the leaf-index is appended? Probably... */
    +-  memset(&pData->p[pData->nn], 0, FTS5_DATA_PADDING);
    +-  p->rc = fts5StructureDecode(pData->p, pData->nn, &iCookie, &pRet);
    +-  if( p->rc==SQLITE_OK && pConfig->iCookie!=iCookie ){
    +-    p->rc = sqlite3Fts5ConfigLoad(pConfig, iCookie);
    ++  if( p->pStruct==0 ){
    ++    p->iStructVersion = fts5IndexDataVersion(p);
    ++    if( p->rc==SQLITE_OK ){
    ++      p->pStruct = fts5StructureReadUncached(p);
    ++    }
    +   }
    + 
    +-  fts5DataRelease(pData);
    +-  if( p->rc!=SQLITE_OK ){
    +-    fts5StructureRelease(pRet);
    +-    pRet = 0;
    ++#if 0
    ++  else{
    ++    Fts5Structure *pTest = fts5StructureReadUncached(p);
    ++    if( pTest ){
    ++      int i, j;
    ++      assert_nc( p->pStruct->nSegment==pTest->nSegment );
    ++      assert_nc( p->pStruct->nLevel==pTest->nLevel );
    ++      for(i=0; i<pTest->nLevel; i++){
    ++        assert_nc( p->pStruct->aLevel[i].nMerge==pTest->aLevel[i].nMerge );
    ++        assert_nc( p->pStruct->aLevel[i].nSeg==pTest->aLevel[i].nSeg );
    ++        for(j=0; j<pTest->aLevel[i].nSeg; j++){
    ++          Fts5StructureSegment *p1 = &pTest->aLevel[i].aSeg[j];
    ++          Fts5StructureSegment *p2 = &p->pStruct->aLevel[i].aSeg[j];
    ++          assert_nc( p1->iSegid==p2->iSegid );
    ++          assert_nc( p1->pgnoFirst==p2->pgnoFirst );
    ++          assert_nc( p1->pgnoLast==p2->pgnoLast );
    ++        }
    ++      }
    ++      fts5StructureRelease(pTest);
    ++    }
    ++  }
    ++#endif
    ++
    ++  if( p->rc!=SQLITE_OK ) return 0;
    ++  assert( p->iStructVersion!=0 );
    ++  assert( p->pStruct!=0 );
    ++  fts5StructureRef(p->pStruct);
    ++  return p->pStruct;
    ++}
    ++
    ++static void fts5StructureInvalidate(Fts5Index *p){
    ++  if( p->pStruct ){
    ++    fts5StructureRelease(p->pStruct);
    ++    p->pStruct = 0;
    +   }
    +-  return pRet;
    + }
    + 
    + /*
    +@@ -173511,6 +195365,18 @@ static int fts5StructureCountSegments(Fts5Structure *pStruct){
    + }
    + #endif
    + 
    ++#define fts5BufferSafeAppendBlob(pBuf, pBlob, nBlob) {     \
    ++  assert( (pBuf)->nSpace>=((pBuf)->n+nBlob) );             \
    ++  memcpy(&(pBuf)->p[(pBuf)->n], pBlob, nBlob);             \
    ++  (pBuf)->n += nBlob;                                      \
    ++}
    ++
    ++#define fts5BufferSafeAppendVarint(pBuf, iVal) {                \
    ++  (pBuf)->n += sqlite3Fts5PutVarint(&(pBuf)->p[(pBuf)->n], (iVal));  \
    ++  assert( (pBuf)->nSpace>=(pBuf)->n );                          \
    ++}
    ++
    ++
    + /*
    + ** Serialize and store the "structure" record.
    + **
    +@@ -173529,11 +195395,14 @@ static void fts5StructureWrite(Fts5Index *p, Fts5Structure *pStruct){
    +     /* Append the current configuration cookie */
    +     iCookie = p->pConfig->iCookie;
    +     if( iCookie<0 ) iCookie = 0;
    +-    fts5BufferAppend32(&p->rc, &buf, iCookie);
    + 
    +-    fts5BufferAppendVarint(&p->rc, &buf, pStruct->nLevel);
    +-    fts5BufferAppendVarint(&p->rc, &buf, pStruct->nSegment);
    +-    fts5BufferAppendVarint(&p->rc, &buf, (i64)pStruct->nWriteCounter);
    ++    if( 0==sqlite3Fts5BufferSize(&p->rc, &buf, 4+9+9+9) ){
    ++      sqlite3Fts5Put32(buf.p, iCookie);
    ++      buf.n = 4;
    ++      fts5BufferSafeAppendVarint(&buf, pStruct->nLevel);
    ++      fts5BufferSafeAppendVarint(&buf, pStruct->nSegment);
    ++      fts5BufferSafeAppendVarint(&buf, (i64)pStruct->nWriteCounter);
    ++    }
    + 
    +     for(iLvl=0; iLvl<pStruct->nLevel; iLvl++){
    +       int iSeg;                     /* Used to iterate through segments */
    +@@ -173933,7 +195802,7 @@ static void fts5SegIterNextPage(
    +     pIter->pLeaf = pIter->pNextLeaf;
    +     pIter->pNextLeaf = 0;
    +   }else if( pIter->iLeafPgno<=pSeg->pgnoLast ){
    +-    pIter->pLeaf = fts5DataRead(p, 
    ++    pIter->pLeaf = fts5LeafRead(p, 
    +         FTS5_SEGMENT_ROWID(pSeg->iSegid, pIter->iLeafPgno)
    +     );
    +   }else{
    +@@ -173983,11 +195852,28 @@ static int fts5GetPoslistSize(const u8 *p, int *pnSz, int *pbDel){
    + static void fts5SegIterLoadNPos(Fts5Index *p, Fts5SegIter *pIter){
    +   if( p->rc==SQLITE_OK ){
    +     int iOff = pIter->iLeafOffset;  /* Offset to read at */
    +-    int nSz;
    +     ASSERT_SZLEAF_OK(pIter->pLeaf);
    +-    fts5FastGetVarint32(pIter->pLeaf->p, iOff, nSz);
    +-    pIter->bDel = (nSz & 0x0001);
    +-    pIter->nPos = nSz>>1;
    ++    if( p->pConfig->eDetail==FTS5_DETAIL_NONE ){
    ++      int iEod = MIN(pIter->iEndofDoclist, pIter->pLeaf->szLeaf);
    ++      pIter->bDel = 0;
    ++      pIter->nPos = 1;
    ++      if( iOff<iEod && pIter->pLeaf->p[iOff]==0 ){
    ++        pIter->bDel = 1;
    ++        iOff++;
    ++        if( iOff<iEod && pIter->pLeaf->p[iOff]==0 ){
    ++          pIter->nPos = 1;
    ++          iOff++;
    ++        }else{
    ++          pIter->nPos = 0;
    ++        }
    ++      }
    ++    }else{
    ++      int nSz;
    ++      fts5FastGetVarint32(pIter->pLeaf->p, iOff, nSz);
    ++      pIter->bDel = (nSz & 0x0001);
    ++      pIter->nPos = nSz>>1;
    ++      assert_nc( pIter->nPos>=0 );
    ++    }
    +     pIter->iLeafOffset = iOff;
    +   }
    + }
    +@@ -174031,6 +195917,10 @@ static void fts5SegIterLoadTerm(Fts5Index *p, Fts5SegIter *pIter, int nKeep){
    +   int nNew;                       /* Bytes of new data */
    + 
    +   iOff += fts5GetVarint32(&a[iOff], nNew);
    ++  if( iOff+nNew>pIter->pLeaf->nn ){
    ++    p->rc = FTS5_CORRUPT;
    ++    return;
    ++  }
    +   pIter->term.n = nKeep;
    +   fts5BufferAppendBlob(&p->rc, &pIter->term, nNew, &a[iOff]);
    +   iOff += nNew;
    +@@ -174049,6 +195939,20 @@ static void fts5SegIterLoadTerm(Fts5Index *p, Fts5SegIter *pIter, int nKeep){
    +   fts5SegIterLoadRowid(p, pIter);
    + }
    + 
    ++static void fts5SegIterNext(Fts5Index*, Fts5SegIter*, int*);
    ++static void fts5SegIterNext_Reverse(Fts5Index*, Fts5SegIter*, int*);
    ++static void fts5SegIterNext_None(Fts5Index*, Fts5SegIter*, int*);
    ++
    ++static void fts5SegIterSetNext(Fts5Index *p, Fts5SegIter *pIter){
    ++  if( pIter->flags & FTS5_SEGITER_REVERSE ){
    ++    pIter->xNext = fts5SegIterNext_Reverse;
    ++  }else if( p->pConfig->eDetail==FTS5_DETAIL_NONE ){
    ++    pIter->xNext = fts5SegIterNext_None;
    ++  }else{
    ++    pIter->xNext = fts5SegIterNext;
    ++  }
    ++}
    ++
    + /*
    + ** Initialize the iterator object pIter to iterate through the entries in
    + ** segment pSeg. The iterator is left pointing to the first entry when 
    +@@ -174074,6 +195978,7 @@ static void fts5SegIterInit(
    + 
    +   if( p->rc==SQLITE_OK ){
    +     memset(pIter, 0, sizeof(*pIter));
    ++    fts5SegIterSetNext(p, pIter);
    +     pIter->pSeg = pSeg;
    +     pIter->iLeafPgno = pSeg->pgnoFirst-1;
    +     fts5SegIterNextPage(p, pIter);
    +@@ -174105,6 +196010,7 @@ static void fts5SegIterInit(
    + ** byte of the position list content associated with said rowid.
    + */
    + static void fts5SegIterReverseInitPage(Fts5Index *p, Fts5SegIter *pIter){
    ++  int eDetail = p->pConfig->eDetail;
    +   int n = pIter->pLeaf->szLeaf;
    +   int i = pIter->iLeafOffset;
    +   u8 *a = pIter->pLeaf->p;
    +@@ -174117,15 +196023,24 @@ static void fts5SegIterReverseInitPage(Fts5Index *p, Fts5SegIter *pIter){
    +   ASSERT_SZLEAF_OK(pIter->pLeaf);
    +   while( 1 ){
    +     i64 iDelta = 0;
    +-    int nPos;
    +-    int bDummy;
    + 
    +-    i += fts5GetPoslistSize(&a[i], &nPos, &bDummy);
    +-    i += nPos;
    ++    if( eDetail==FTS5_DETAIL_NONE ){
    ++      /* todo */
    ++      if( i<n && a[i]==0 ){
    ++        i++;
    ++        if( i<n && a[i]==0 ) i++;
    ++      }
    ++    }else{
    ++      int nPos;
    ++      int bDummy;
    ++      i += fts5GetPoslistSize(&a[i], &nPos, &bDummy);
    ++      i += nPos;
    ++    }
    +     if( i>=n ) break;
    +     i += fts5GetVarint(&a[i], (u64*)&iDelta);
    +     pIter->iRowid += iDelta;
    + 
    ++    /* If necessary, grow the pIter->aRowidOffset[] array. */
    +     if( iRowidOffset>=pIter->nRowidOffset ){
    +       int nNew = pIter->nRowidOffset + 8;
    +       int *aNew = (int*)sqlite3_realloc(pIter->aRowidOffset, nNew*sizeof(int));
    +@@ -174162,12 +196077,13 @@ static void fts5SegIterReverseNewPage(Fts5Index *p, Fts5SegIter *pIter){
    +     if( pNew ){
    +       /* iTermLeafOffset may be equal to szLeaf if the term is the last
    +       ** thing on the page - i.e. the first rowid is on the following page.
    +-      ** In this case leaf pIter->pLeaf==0, this iterator is at EOF. */
    +-      if( pIter->iLeafPgno==pIter->iTermLeafPgno 
    +-       && pIter->iTermLeafOffset<pNew->szLeaf 
    +-      ){
    +-        pIter->pLeaf = pNew;
    +-        pIter->iLeafOffset = pIter->iTermLeafOffset;
    ++      ** In this case leave pIter->pLeaf==0, this iterator is at EOF. */
    ++      if( pIter->iLeafPgno==pIter->iTermLeafPgno ){
    ++        assert( pIter->pLeaf==0 );
    ++        if( pIter->iTermLeafOffset<pNew->szLeaf ){
    ++          pIter->pLeaf = pNew;
    ++          pIter->iLeafOffset = pIter->iTermLeafOffset;
    ++        }
    +       }else{
    +         int iRowidOff;
    +         iRowidOff = fts5LeafFirstRowidOff(pNew);
    +@@ -174198,11 +196114,115 @@ static void fts5SegIterReverseNewPage(Fts5Index *p, Fts5SegIter *pIter){
    + ** points to a delete marker. A delete marker is an entry with a 0 byte
    + ** position-list.
    + */
    +-static int fts5MultiIterIsEmpty(Fts5Index *p, Fts5IndexIter *pIter){
    ++static int fts5MultiIterIsEmpty(Fts5Index *p, Fts5Iter *pIter){
    +   Fts5SegIter *pSeg = &pIter->aSeg[pIter->aFirst[1].iFirst];
    +   return (p->rc==SQLITE_OK && pSeg->pLeaf && pSeg->nPos==0);
    + }
    + 
    ++/*
    ++** Advance iterator pIter to the next entry.
    ++**
    ++** This version of fts5SegIterNext() is only used by reverse iterators.
    ++*/
    ++static void fts5SegIterNext_Reverse(
    ++  Fts5Index *p,                   /* FTS5 backend object */
    ++  Fts5SegIter *pIter,             /* Iterator to advance */
    ++  int *pbUnused                   /* Unused */
    ++){
    ++  assert( pIter->flags & FTS5_SEGITER_REVERSE );
    ++  assert( pIter->pNextLeaf==0 );
    ++  UNUSED_PARAM(pbUnused);
    ++
    ++  if( pIter->iRowidOffset>0 ){
    ++    u8 *a = pIter->pLeaf->p;
    ++    int iOff;
    ++    i64 iDelta;
    ++
    ++    pIter->iRowidOffset--;
    ++    pIter->iLeafOffset = pIter->aRowidOffset[pIter->iRowidOffset];
    ++    fts5SegIterLoadNPos(p, pIter);
    ++    iOff = pIter->iLeafOffset;
    ++    if( p->pConfig->eDetail!=FTS5_DETAIL_NONE ){
    ++      iOff += pIter->nPos;
    ++    }
    ++    fts5GetVarint(&a[iOff], (u64*)&iDelta);
    ++    pIter->iRowid -= iDelta;
    ++  }else{
    ++    fts5SegIterReverseNewPage(p, pIter);
    ++  }
    ++}
    ++
    ++/*
    ++** Advance iterator pIter to the next entry.
    ++**
    ++** This version of fts5SegIterNext() is only used if detail=none and the
    ++** iterator is not a reverse direction iterator.
    ++*/
    ++static void fts5SegIterNext_None(
    ++  Fts5Index *p,                   /* FTS5 backend object */
    ++  Fts5SegIter *pIter,             /* Iterator to advance */
    ++  int *pbNewTerm                  /* OUT: Set for new term */
    ++){
    ++  int iOff;
    ++
    ++  assert( p->rc==SQLITE_OK );
    ++  assert( (pIter->flags & FTS5_SEGITER_REVERSE)==0 );
    ++  assert( p->pConfig->eDetail==FTS5_DETAIL_NONE );
    ++
    ++  ASSERT_SZLEAF_OK(pIter->pLeaf);
    ++  iOff = pIter->iLeafOffset;
    ++
    ++  /* Next entry is on the next page */
    ++  if( pIter->pSeg && iOff>=pIter->pLeaf->szLeaf ){
    ++    fts5SegIterNextPage(p, pIter);
    ++    if( p->rc || pIter->pLeaf==0 ) return;
    ++    pIter->iRowid = 0;
    ++    iOff = 4;
    ++  }
    ++
    ++  if( iOff<pIter->iEndofDoclist ){
    ++    /* Next entry is on the current page */
    ++    i64 iDelta;
    ++    iOff += sqlite3Fts5GetVarint(&pIter->pLeaf->p[iOff], (u64*)&iDelta);
    ++    pIter->iLeafOffset = iOff;
    ++    pIter->iRowid += iDelta;
    ++  }else if( (pIter->flags & FTS5_SEGITER_ONETERM)==0 ){
    ++    if( pIter->pSeg ){
    ++      int nKeep = 0;
    ++      if( iOff!=fts5LeafFirstTermOff(pIter->pLeaf) ){
    ++        iOff += fts5GetVarint32(&pIter->pLeaf->p[iOff], nKeep);
    ++      }
    ++      pIter->iLeafOffset = iOff;
    ++      fts5SegIterLoadTerm(p, pIter, nKeep);
    ++    }else{
    ++      const u8 *pList = 0;
    ++      const char *zTerm = 0;
    ++      int nList;
    ++      sqlite3Fts5HashScanNext(p->pHash);
    ++      sqlite3Fts5HashScanEntry(p->pHash, &zTerm, &pList, &nList);
    ++      if( pList==0 ) goto next_none_eof;
    ++      pIter->pLeaf->p = (u8*)pList;
    ++      pIter->pLeaf->nn = nList;
    ++      pIter->pLeaf->szLeaf = nList;
    ++      pIter->iEndofDoclist = nList;
    ++      sqlite3Fts5BufferSet(&p->rc,&pIter->term, (int)strlen(zTerm), (u8*)zTerm);
    ++      pIter->iLeafOffset = fts5GetVarint(pList, (u64*)&pIter->iRowid);
    ++    }
    ++
    ++    if( pbNewTerm ) *pbNewTerm = 1;
    ++  }else{
    ++    goto next_none_eof;
    ++  }
    ++
    ++  fts5SegIterLoadNPos(p, pIter);
    ++
    ++  return;
    ++ next_none_eof:
    ++  fts5DataRelease(pIter->pLeaf);
    ++  pIter->pLeaf = 0;
    ++}
    ++
    ++
    + /*
    + ** Advance iterator pIter to the next entry. 
    + **
    +@@ -174215,131 +196235,132 @@ static void fts5SegIterNext(
    +   Fts5SegIter *pIter,             /* Iterator to advance */
    +   int *pbNewTerm                  /* OUT: Set for new term */
    + ){
    ++  Fts5Data *pLeaf = pIter->pLeaf;
    ++  int iOff;
    ++  int bNewTerm = 0;
    ++  int nKeep = 0;
    ++  u8 *a;
    ++  int n;
    ++
    +   assert( pbNewTerm==0 || *pbNewTerm==0 );
    +-  if( p->rc==SQLITE_OK ){
    +-    if( pIter->flags & FTS5_SEGITER_REVERSE ){
    +-      assert( pIter->pNextLeaf==0 );
    +-      if( pIter->iRowidOffset>0 ){
    +-        u8 *a = pIter->pLeaf->p;
    +-        int iOff;
    +-        int nPos;
    +-        int bDummy;
    +-        i64 iDelta;
    +-
    +-        pIter->iRowidOffset--;
    +-        pIter->iLeafOffset = iOff = pIter->aRowidOffset[pIter->iRowidOffset];
    +-        iOff += fts5GetPoslistSize(&a[iOff], &nPos, &bDummy);
    +-        iOff += nPos;
    +-        fts5GetVarint(&a[iOff], (u64*)&iDelta);
    +-        pIter->iRowid -= iDelta;
    +-        fts5SegIterLoadNPos(p, pIter);
    +-      }else{
    +-        fts5SegIterReverseNewPage(p, pIter);
    ++  assert( p->pConfig->eDetail!=FTS5_DETAIL_NONE );
    ++
    ++  /* Search for the end of the position list within the current page. */
    ++  a = pLeaf->p;
    ++  n = pLeaf->szLeaf;
    ++
    ++  ASSERT_SZLEAF_OK(pLeaf);
    ++  iOff = pIter->iLeafOffset + pIter->nPos;
    ++
    ++  if( iOff<n ){
    ++    /* The next entry is on the current page. */
    ++    assert_nc( iOff<=pIter->iEndofDoclist );
    ++    if( iOff>=pIter->iEndofDoclist ){
    ++      bNewTerm = 1;
    ++      if( iOff!=fts5LeafFirstTermOff(pLeaf) ){
    ++        iOff += fts5GetVarint32(&a[iOff], nKeep);
    +       }
    +     }else{
    +-      Fts5Data *pLeaf = pIter->pLeaf;
    +-      int iOff;
    +-      int bNewTerm = 0;
    +-      int nKeep = 0;
    +-
    +-      /* Search for the end of the position list within the current page. */
    +-      u8 *a = pLeaf->p;
    +-      int n = pLeaf->szLeaf;
    ++      u64 iDelta;
    ++      iOff += sqlite3Fts5GetVarint(&a[iOff], &iDelta);
    ++      pIter->iRowid += iDelta;
    ++      assert_nc( iDelta>0 );
    ++    }
    ++    pIter->iLeafOffset = iOff;
    + 
    ++  }else if( pIter->pSeg==0 ){
    ++    const u8 *pList = 0;
    ++    const char *zTerm = 0;
    ++    int nList = 0;
    ++    assert( (pIter->flags & FTS5_SEGITER_ONETERM) || pbNewTerm );
    ++    if( 0==(pIter->flags & FTS5_SEGITER_ONETERM) ){
    ++      sqlite3Fts5HashScanNext(p->pHash);
    ++      sqlite3Fts5HashScanEntry(p->pHash, &zTerm, &pList, &nList);
    ++    }
    ++    if( pList==0 ){
    ++      fts5DataRelease(pIter->pLeaf);
    ++      pIter->pLeaf = 0;
    ++    }else{
    ++      pIter->pLeaf->p = (u8*)pList;
    ++      pIter->pLeaf->nn = nList;
    ++      pIter->pLeaf->szLeaf = nList;
    ++      pIter->iEndofDoclist = nList+1;
    ++      sqlite3Fts5BufferSet(&p->rc, &pIter->term, (int)strlen(zTerm),
    ++          (u8*)zTerm);
    ++      pIter->iLeafOffset = fts5GetVarint(pList, (u64*)&pIter->iRowid);
    ++      *pbNewTerm = 1;
    ++    }
    ++  }else{
    ++    iOff = 0;
    ++    /* Next entry is not on the current page */
    ++    while( iOff==0 ){
    ++      fts5SegIterNextPage(p, pIter);
    ++      pLeaf = pIter->pLeaf;
    ++      if( pLeaf==0 ) break;
    +       ASSERT_SZLEAF_OK(pLeaf);
    +-      iOff = pIter->iLeafOffset + pIter->nPos;
    +-
    +-      if( iOff<n ){
    +-        /* The next entry is on the current page. */
    +-        assert_nc( iOff<=pIter->iEndofDoclist );
    +-        if( iOff>=pIter->iEndofDoclist ){
    +-          bNewTerm = 1;
    +-          if( iOff!=fts5LeafFirstTermOff(pLeaf) ){
    +-            iOff += fts5GetVarint32(&a[iOff], nKeep);
    +-          }
    +-        }else{
    +-          u64 iDelta;
    +-          iOff += sqlite3Fts5GetVarint(&a[iOff], &iDelta);
    +-          pIter->iRowid += iDelta;
    +-          assert_nc( iDelta>0 );
    +-        }
    ++      if( (iOff = fts5LeafFirstRowidOff(pLeaf)) && iOff<pLeaf->szLeaf ){
    ++        iOff += sqlite3Fts5GetVarint(&pLeaf->p[iOff], (u64*)&pIter->iRowid);
    +         pIter->iLeafOffset = iOff;
    + 
    +-      }else if( pIter->pSeg==0 ){
    +-        const u8 *pList = 0;
    +-        const char *zTerm = 0;
    +-        int nList = 0;
    +-        if( 0==(pIter->flags & FTS5_SEGITER_ONETERM) ){
    +-          sqlite3Fts5HashScanNext(p->pHash);
    +-          sqlite3Fts5HashScanEntry(p->pHash, &zTerm, &pList, &nList);
    +-        }
    +-        if( pList==0 ){
    +-          fts5DataRelease(pIter->pLeaf);
    +-          pIter->pLeaf = 0;
    +-        }else{
    +-          pIter->pLeaf->p = (u8*)pList;
    +-          pIter->pLeaf->nn = nList;
    +-          pIter->pLeaf->szLeaf = nList;
    +-          pIter->iEndofDoclist = nList+1;
    +-          sqlite3Fts5BufferSet(&p->rc, &pIter->term, strlen(zTerm), (u8*)zTerm);
    +-          pIter->iLeafOffset = fts5GetVarint(pList, (u64*)&pIter->iRowid);
    +-          if( pbNewTerm ) *pbNewTerm = 1;
    +-        }
    +-      }else{
    +-        iOff = 0;
    +-        /* Next entry is not on the current page */
    +-        while( iOff==0 ){
    +-          fts5SegIterNextPage(p, pIter);
    +-          pLeaf = pIter->pLeaf;
    +-          if( pLeaf==0 ) break;
    +-          ASSERT_SZLEAF_OK(pLeaf);
    +-          if( (iOff = fts5LeafFirstRowidOff(pLeaf)) && iOff<pLeaf->szLeaf ){
    +-            iOff += sqlite3Fts5GetVarint(&pLeaf->p[iOff], (u64*)&pIter->iRowid);
    +-            pIter->iLeafOffset = iOff;
    +-
    +-            if( pLeaf->nn>pLeaf->szLeaf ){
    +-              pIter->iPgidxOff = pLeaf->szLeaf + fts5GetVarint32(
    +-                  &pLeaf->p[pLeaf->szLeaf], pIter->iEndofDoclist
    +-              );
    +-            }
    +-
    +-          }
    +-          else if( pLeaf->nn>pLeaf->szLeaf ){
    +-            pIter->iPgidxOff = pLeaf->szLeaf + fts5GetVarint32(
    +-                &pLeaf->p[pLeaf->szLeaf], iOff
    +-            );
    +-            pIter->iLeafOffset = iOff;
    +-            pIter->iEndofDoclist = iOff;
    +-            bNewTerm = 1;
    +-          }
    +-          if( iOff>=pLeaf->szLeaf ){
    +-            p->rc = FTS5_CORRUPT;
    +-            return;
    +-          }
    ++        if( pLeaf->nn>pLeaf->szLeaf ){
    ++          pIter->iPgidxOff = pLeaf->szLeaf + fts5GetVarint32(
    ++              &pLeaf->p[pLeaf->szLeaf], pIter->iEndofDoclist
    ++          );
    +         }
    +       }
    ++      else if( pLeaf->nn>pLeaf->szLeaf ){
    ++        pIter->iPgidxOff = pLeaf->szLeaf + fts5GetVarint32(
    ++            &pLeaf->p[pLeaf->szLeaf], iOff
    ++        );
    ++        pIter->iLeafOffset = iOff;
    ++        pIter->iEndofDoclist = iOff;
    ++        bNewTerm = 1;
    ++      }
    ++      assert_nc( iOff<pLeaf->szLeaf );
    ++      if( iOff>pLeaf->szLeaf ){
    ++        p->rc = FTS5_CORRUPT;
    ++        return;
    ++      }
    ++    }
    ++  }
    + 
    +-      /* Check if the iterator is now at EOF. If so, return early. */
    +-      if( pIter->pLeaf ){
    +-        if( bNewTerm ){
    +-          if( pIter->flags & FTS5_SEGITER_ONETERM ){
    +-            fts5DataRelease(pIter->pLeaf);
    +-            pIter->pLeaf = 0;
    +-          }else{
    +-            fts5SegIterLoadTerm(p, pIter, nKeep);
    +-            fts5SegIterLoadNPos(p, pIter);
    +-            if( pbNewTerm ) *pbNewTerm = 1;
    +-          }
    +-        }else{
    +-          fts5SegIterLoadNPos(p, pIter);
    +-        }
    ++  /* Check if the iterator is now at EOF. If so, return early. */
    ++  if( pIter->pLeaf ){
    ++    if( bNewTerm ){
    ++      if( pIter->flags & FTS5_SEGITER_ONETERM ){
    ++        fts5DataRelease(pIter->pLeaf);
    ++        pIter->pLeaf = 0;
    ++      }else{
    ++        fts5SegIterLoadTerm(p, pIter, nKeep);
    ++        fts5SegIterLoadNPos(p, pIter);
    ++        if( pbNewTerm ) *pbNewTerm = 1;
    +       }
    ++    }else{
    ++      /* The following could be done by calling fts5SegIterLoadNPos(). But
    ++      ** this block is particularly performance critical, so equivalent
    ++      ** code is inlined. 
    ++      **
    ++      ** Later: Switched back to fts5SegIterLoadNPos() because it supports
    ++      ** detail=none mode. Not ideal.
    ++      */
    ++      int nSz;
    ++      assert( p->rc==SQLITE_OK );
    ++      assert( pIter->iLeafOffset<=pIter->pLeaf->nn );
    ++      fts5FastGetVarint32(pIter->pLeaf->p, pIter->iLeafOffset, nSz);
    ++      pIter->bDel = (nSz & 0x0001);
    ++      pIter->nPos = nSz>>1;
    ++      assert_nc( pIter->nPos>=0 );
    +     }
    +   }
    + }
    + 
    + #define SWAPVAL(T, a, b) { T tmp; tmp=a; a=b; b=tmp; }
    + 
    ++#define fts5IndexSkipVarint(a, iOff) {            \
    ++  int iEnd = iOff+9;                              \
    ++  while( (a[iOff++] & 0x80) && iOff<iEnd );       \
    ++}
    ++
    + /*
    + ** Iterator pIter currently points to the first rowid in a doclist. This
    + ** function sets the iterator up so that iterates in reverse order through
    +@@ -174360,7 +196381,14 @@ static void fts5SegIterReverse(Fts5Index *p, Fts5SegIter *pIter){
    +     /* Currently, Fts5SegIter.iLeafOffset points to the first byte of
    +     ** position-list content for the current rowid. Back it up so that it
    +     ** points to the start of the position-list size field. */
    +-    pIter->iLeafOffset -= sqlite3Fts5GetVarintLen(pIter->nPos*2+pIter->bDel);
    ++    int iPoslist;
    ++    if( pIter->iTermLeafPgno==pIter->iLeafPgno ){
    ++      iPoslist = pIter->iTermLeafOffset;
    ++    }else{
    ++      iPoslist = 4;
    ++    }
    ++    fts5IndexSkipVarint(pLeaf->p, iPoslist);
    ++    pIter->iLeafOffset = iPoslist;
    + 
    +     /* If this condition is true then the largest rowid for the current
    +     ** term may not be stored on the current page. So search forward to
    +@@ -174444,11 +196472,6 @@ static void fts5SegIterLoadDlidx(Fts5Index *p, Fts5SegIter *pIter){
    +   pIter->pDlidx = fts5DlidxIterInit(p, bRev, iSeg, pIter->iTermLeafPgno);
    + }
    + 
    +-#define fts5IndexSkipVarint(a, iOff) {            \
    +-  int iEnd = iOff+9;                              \
    +-  while( (a[iOff++] & 0x80) && iOff<iEnd );       \
    +-}
    +-
    + /*
    + ** The iterator object passed as the second argument currently contains
    + ** no valid values except for the Fts5SegIter.pLeaf member variable. This
    +@@ -174486,6 +196509,10 @@ static void fts5LeafSeek(
    +   iPgidx = szLeaf;
    +   iPgidx += fts5GetVarint32(&a[iPgidx], iTermOff);
    +   iOff = iTermOff;
    ++  if( iOff>n ){
    ++    p->rc = FTS5_CORRUPT;
    ++    return;
    ++  }
    + 
    +   while( 1 ){
    + 
    +@@ -174525,6 +196552,11 @@ static void fts5LeafSeek(
    +     iTermOff += nKeep;
    +     iOff = iTermOff;
    + 
    ++    if( iOff>=n ){
    ++      p->rc = FTS5_CORRUPT;
    ++      return;
    ++    }
    ++
    +     /* Read the nKeep field of the next term. */
    +     fts5FastGetVarint32(a, iOff, nKeep);
    +   }
    +@@ -174540,11 +196572,14 @@ static void fts5LeafSeek(
    +       if( pIter->pLeaf==0 ) return;
    +       a = pIter->pLeaf->p;
    +       if( fts5LeafIsTermless(pIter->pLeaf)==0 ){
    +-        fts5GetVarint32(&pIter->pLeaf->p[pIter->pLeaf->szLeaf], iOff);
    ++        iPgidx = pIter->pLeaf->szLeaf;
    ++        iPgidx += fts5GetVarint32(&pIter->pLeaf->p[iPgidx], iOff);
    +         if( iOff<4 || iOff>=pIter->pLeaf->szLeaf ){
    +           p->rc = FTS5_CORRUPT;
    +         }else{
    +           nKeep = 0;
    ++          iTermOff = iOff;
    ++          n = pIter->pLeaf->nn;
    +           iOff += fts5GetVarint32(&a[iOff], nNew);
    +           break;
    +         }
    +@@ -174574,6 +196609,18 @@ static void fts5LeafSeek(
    +   fts5SegIterLoadNPos(p, pIter);
    + }
    + 
    ++static sqlite3_stmt *fts5IdxSelectStmt(Fts5Index *p){
    ++  if( p->pIdxSelect==0 ){
    ++    Fts5Config *pConfig = p->pConfig;
    ++    fts5IndexPrepareStmt(p, &p->pIdxSelect, sqlite3_mprintf(
    ++          "SELECT pgno FROM '%q'.'%q_idx' WHERE "
    ++          "segid=? AND term<=? ORDER BY term DESC LIMIT 1",
    ++          pConfig->zDb, pConfig->zName
    ++    ));
    ++  }
    ++  return p->pIdxSelect;
    ++}
    ++
    + /*
    + ** Initialize the object pIter to point to term pTerm/nTerm within segment
    + ** pSeg. If there is no such term in the index, the iterator is set to EOF.
    +@@ -174583,7 +196630,6 @@ static void fts5LeafSeek(
    + */
    + static void fts5SegIterSeekInit(
    +   Fts5Index *p,                   /* FTS5 backend */
    +-  Fts5Buffer *pBuf,               /* Buffer to use for loading pages */
    +   const u8 *pTerm, int nTerm,     /* Term to seek to */
    +   int flags,                      /* Mask of FTS5INDEX_XXX flags */
    +   Fts5StructureSegment *pSeg,     /* Description of segment */
    +@@ -174592,9 +196638,7 @@ static void fts5SegIterSeekInit(
    +   int iPg = 1;
    +   int bGe = (flags & FTS5INDEX_QUERY_SCAN);
    +   int bDlidx = 0;                 /* True if there is a doclist-index */
    +-
    +-  static int nCall = 0;
    +-  nCall++;
    ++  sqlite3_stmt *pIdxSelect = 0;
    + 
    +   assert( bGe==0 || (flags & FTS5INDEX_QUERY_DESC)==0 );
    +   assert( pTerm && nTerm );
    +@@ -174603,23 +196647,16 @@ static void fts5SegIterSeekInit(
    + 
    +   /* This block sets stack variable iPg to the leaf page number that may
    +   ** contain term (pTerm/nTerm), if it is present in the segment. */
    +-  if( p->pIdxSelect==0 ){
    +-    Fts5Config *pConfig = p->pConfig;
    +-    fts5IndexPrepareStmt(p, &p->pIdxSelect, sqlite3_mprintf(
    +-          "SELECT pgno FROM '%q'.'%q_idx' WHERE "
    +-          "segid=? AND term<=? ORDER BY term DESC LIMIT 1",
    +-          pConfig->zDb, pConfig->zName
    +-    ));
    +-  }
    ++  pIdxSelect = fts5IdxSelectStmt(p);
    +   if( p->rc ) return;
    +-  sqlite3_bind_int(p->pIdxSelect, 1, pSeg->iSegid);
    +-  sqlite3_bind_blob(p->pIdxSelect, 2, pTerm, nTerm, SQLITE_STATIC);
    +-  if( SQLITE_ROW==sqlite3_step(p->pIdxSelect) ){
    +-    i64 val = sqlite3_column_int(p->pIdxSelect, 0);
    ++  sqlite3_bind_int(pIdxSelect, 1, pSeg->iSegid);
    ++  sqlite3_bind_blob(pIdxSelect, 2, pTerm, nTerm, SQLITE_STATIC);
    ++  if( SQLITE_ROW==sqlite3_step(pIdxSelect) ){
    ++    i64 val = sqlite3_column_int(pIdxSelect, 0);
    +     iPg = (int)(val>>1);
    +     bDlidx = (val & 0x0001);
    +   }
    +-  p->rc = sqlite3_reset(p->pIdxSelect);
    ++  p->rc = sqlite3_reset(pIdxSelect);
    + 
    +   if( iPg<pSeg->pgnoFirst ){
    +     iPg = pSeg->pgnoFirst;
    +@@ -174648,6 +196685,8 @@ static void fts5SegIterSeekInit(
    +     }
    +   }
    + 
    ++  fts5SegIterSetNext(p, pIter);
    ++
    +   /* Either:
    +   **
    +   **   1) an error has occurred, or
    +@@ -174688,7 +196727,7 @@ static void fts5SegIterHashInit(
    +   if( pTerm==0 || (flags & FTS5INDEX_QUERY_SCAN) ){
    +     p->rc = sqlite3Fts5HashScanInit(p->pHash, (const char*)pTerm, nTerm);
    +     sqlite3Fts5HashScanEntry(p->pHash, (const char**)&z, &pList, &nList);
    +-    n = (z ? strlen((const char*)z) : 0);
    ++    n = (z ? (int)strlen((const char*)z) : 0);
    +   }else{
    +     pIter->flags |= FTS5_SEGITER_ONETERM;
    +     sqlite3Fts5HashQuery(p->pHash, (const char*)pTerm, nTerm, &pList, &nList);
    +@@ -174705,7 +196744,7 @@ static void fts5SegIterHashInit(
    +     pLeaf->nn = pLeaf->szLeaf = nList;
    +     pIter->pLeaf = pLeaf;
    +     pIter->iLeafOffset = fts5GetVarint(pLeaf->p, (u64*)&pIter->iRowid);
    +-    pIter->iEndofDoclist = pLeaf->nn+1;
    ++    pIter->iEndofDoclist = pLeaf->nn;
    + 
    +     if( flags & FTS5INDEX_QUERY_DESC ){
    +       pIter->flags |= FTS5_SEGITER_REVERSE;
    +@@ -174714,6 +196753,8 @@ static void fts5SegIterHashInit(
    +       fts5SegIterLoadNPos(p, pIter);
    +     }
    +   }
    ++
    ++  fts5SegIterSetNext(p, pIter);
    + }
    + 
    + /*
    +@@ -174737,7 +196778,7 @@ static void fts5SegIterClear(Fts5SegIter *pIter){
    + ** two iterators.
    + */
    + static void fts5AssertComparisonResult(
    +-  Fts5IndexIter *pIter, 
    ++  Fts5Iter *pIter, 
    +   Fts5SegIter *p1,
    +   Fts5SegIter *p2,
    +   Fts5CResult *pRes
    +@@ -174778,12 +196819,12 @@ static void fts5AssertComparisonResult(
    + ** statement used to verify that the contents of the pIter->aFirst[] array
    + ** are correct.
    + */
    +-static void fts5AssertMultiIterSetup(Fts5Index *p, Fts5IndexIter *pIter){
    ++static void fts5AssertMultiIterSetup(Fts5Index *p, Fts5Iter *pIter){
    +   if( p->rc==SQLITE_OK ){
    +     Fts5SegIter *pFirst = &pIter->aSeg[ pIter->aFirst[1].iFirst ];
    +     int i;
    + 
    +-    assert( (pFirst->pLeaf==0)==pIter->bEof );
    ++    assert( (pFirst->pLeaf==0)==pIter->base.bEof );
    + 
    +     /* Check that pIter->iSwitchRowid is set correctly. */
    +     for(i=0; i<pIter->nSeg; i++){
    +@@ -174823,7 +196864,7 @@ static void fts5AssertMultiIterSetup(Fts5Index *p, Fts5IndexIter *pIter){
    + ** to a key that is a duplicate of another, higher priority, 
    + ** segment-iterator in the pSeg->aSeg[] array.
    + */
    +-static int fts5MultiIterDoCompare(Fts5IndexIter *pIter, int iOut){
    ++static int fts5MultiIterDoCompare(Fts5Iter *pIter, int iOut){
    +   int i1;                         /* Index of left-hand Fts5SegIter */
    +   int i2;                         /* Index of right-hand Fts5SegIter */
    +   int iRes;
    +@@ -174869,7 +196910,7 @@ static int fts5MultiIterDoCompare(Fts5IndexIter *pIter, int iOut){
    +     }
    +   }
    + 
    +-  pRes->iFirst = iRes;
    ++  pRes->iFirst = (u16)iRes;
    +   return 0;
    + }
    + 
    +@@ -174957,7 +196998,7 @@ static void fts5SegIterNextFrom(
    +   }
    + 
    +   do{
    +-    if( bMove ) fts5SegIterNext(p, pIter, 0);
    ++    if( bMove && p->rc==SQLITE_OK ) pIter->xNext(p, pIter, 0);
    +     if( pIter->pLeaf==0 ) break;
    +     if( bRev==0 && pIter->iRowid>=iMatch ) break;
    +     if( bRev!=0 && pIter->iRowid<=iMatch ) break;
    +@@ -174969,7 +197010,7 @@ static void fts5SegIterNextFrom(
    + /*
    + ** Free the iterator object passed as the second argument.
    + */
    +-static void fts5MultiIterFree(Fts5Index *p, Fts5IndexIter *pIter){
    ++static void fts5MultiIterFree(Fts5Iter *pIter){
    +   if( pIter ){
    +     int i;
    +     for(i=0; i<pIter->nSeg; i++){
    +@@ -174983,7 +197024,7 @@ static void fts5MultiIterFree(Fts5Index *p, Fts5IndexIter *pIter){
    + 
    + static void fts5MultiIterAdvanced(
    +   Fts5Index *p,                   /* FTS5 backend to iterate within */
    +-  Fts5IndexIter *pIter,           /* Iterator to update aFirst[] array for */
    ++  Fts5Iter *pIter,                /* Iterator to update aFirst[] array for */
    +   int iChanged,                   /* Index of sub-iterator just advanced */
    +   int iMinset                     /* Minimum entry in aFirst[] to set */
    + ){
    +@@ -174991,7 +197032,9 @@ static void fts5MultiIterAdvanced(
    +   for(i=(pIter->nSeg+iChanged)/2; i>=iMinset && p->rc==SQLITE_OK; i=i/2){
    +     int iEq;
    +     if( (iEq = fts5MultiIterDoCompare(pIter, i)) ){
    +-      fts5SegIterNext(p, &pIter->aSeg[iEq], 0);
    ++      Fts5SegIter *pSeg = &pIter->aSeg[iEq];
    ++      assert( p->rc==SQLITE_OK );
    ++      pSeg->xNext(p, pSeg, 0);
    +       i = pIter->nSeg + iEq;
    +     }
    +   }
    +@@ -175008,9 +197051,9 @@ static void fts5MultiIterAdvanced(
    + ** that it deals with more complicated cases as well.
    + */ 
    + static int fts5MultiIterAdvanceRowid(
    +-  Fts5Index *p,                   /* FTS5 backend to iterate within */
    +-  Fts5IndexIter *pIter,           /* Iterator to update aFirst[] array for */
    +-  int iChanged                    /* Index of sub-iterator just advanced */
    ++  Fts5Iter *pIter,                /* Iterator to update aFirst[] array for */
    ++  int iChanged,                   /* Index of sub-iterator just advanced */
    ++  Fts5SegIter **ppFirst
    + ){
    +   Fts5SegIter *pNew = &pIter->aSeg[iChanged];
    + 
    +@@ -175036,22 +197079,23 @@ static int fts5MultiIterAdvanceRowid(
    +           pIter->iSwitchRowid = pOther->iRowid;
    +         }
    +       }
    +-      pRes->iFirst = (pNew - pIter->aSeg);
    ++      pRes->iFirst = (u16)(pNew - pIter->aSeg);
    +       if( i==1 ) break;
    + 
    +       pOther = &pIter->aSeg[ pIter->aFirst[i ^ 0x0001].iFirst ];
    +     }
    +   }
    + 
    ++  *ppFirst = pNew;
    +   return 0;
    + }
    + 
    + /*
    + ** Set the pIter->bEof variable based on the state of the sub-iterators.
    + */
    +-static void fts5MultiIterSetEof(Fts5IndexIter *pIter){
    ++static void fts5MultiIterSetEof(Fts5Iter *pIter){
    +   Fts5SegIter *pSeg = &pIter->aSeg[ pIter->aFirst[1].iFirst ];
    +-  pIter->bEof = pSeg->pLeaf==0;
    ++  pIter->base.bEof = pSeg->pLeaf==0;
    +   pIter->iSwitchRowid = pSeg->iRowid;
    + }
    + 
    +@@ -175064,46 +197108,84 @@ static void fts5MultiIterSetEof(Fts5IndexIter *pIter){
    + */
    + static void fts5MultiIterNext(
    +   Fts5Index *p, 
    +-  Fts5IndexIter *pIter,
    ++  Fts5Iter *pIter,
    +   int bFrom,                      /* True if argument iFrom is valid */
    +   i64 iFrom                       /* Advance at least as far as this */
    + ){
    ++  int bUseFrom = bFrom;
    ++  assert( pIter->base.bEof==0 );
    ++  while( p->rc==SQLITE_OK ){
    ++    int iFirst = pIter->aFirst[1].iFirst;
    ++    int bNewTerm = 0;
    ++    Fts5SegIter *pSeg = &pIter->aSeg[iFirst];
    ++    assert( p->rc==SQLITE_OK );
    ++    if( bUseFrom && pSeg->pDlidx ){
    ++      fts5SegIterNextFrom(p, pSeg, iFrom);
    ++    }else{
    ++      pSeg->xNext(p, pSeg, &bNewTerm);
    ++    }
    ++
    ++    if( pSeg->pLeaf==0 || bNewTerm 
    ++     || fts5MultiIterAdvanceRowid(pIter, iFirst, &pSeg)
    ++    ){
    ++      fts5MultiIterAdvanced(p, pIter, iFirst, 1);
    ++      fts5MultiIterSetEof(pIter);
    ++      pSeg = &pIter->aSeg[pIter->aFirst[1].iFirst];
    ++      if( pSeg->pLeaf==0 ) return;
    ++    }
    ++
    ++    fts5AssertMultiIterSetup(p, pIter);
    ++    assert( pSeg==&pIter->aSeg[pIter->aFirst[1].iFirst] && pSeg->pLeaf );
    ++    if( pIter->bSkipEmpty==0 || pSeg->nPos ){
    ++      pIter->xSetOutputs(pIter, pSeg);
    ++      return;
    ++    }
    ++    bUseFrom = 0;
    ++  }
    ++}
    ++
    ++static void fts5MultiIterNext2(
    ++  Fts5Index *p, 
    ++  Fts5Iter *pIter,
    ++  int *pbNewTerm                  /* OUT: True if *might* be new term */
    ++){
    ++  assert( pIter->bSkipEmpty );
    +   if( p->rc==SQLITE_OK ){
    +-    int bUseFrom = bFrom;
    +-    do {
    ++    *pbNewTerm = 0;
    ++    do{
    +       int iFirst = pIter->aFirst[1].iFirst;
    +-      int bNewTerm = 0;
    +       Fts5SegIter *pSeg = &pIter->aSeg[iFirst];
    +-      assert( p->rc==SQLITE_OK );
    +-      if( bUseFrom && pSeg->pDlidx ){
    +-        fts5SegIterNextFrom(p, pSeg, iFrom);
    +-      }else{
    +-        fts5SegIterNext(p, pSeg, &bNewTerm);
    +-      }
    ++      int bNewTerm = 0;
    + 
    ++      assert( p->rc==SQLITE_OK );
    ++      pSeg->xNext(p, pSeg, &bNewTerm);
    +       if( pSeg->pLeaf==0 || bNewTerm 
    +-       || fts5MultiIterAdvanceRowid(p, pIter, iFirst)
    ++       || fts5MultiIterAdvanceRowid(pIter, iFirst, &pSeg)
    +       ){
    +         fts5MultiIterAdvanced(p, pIter, iFirst, 1);
    +         fts5MultiIterSetEof(pIter);
    ++        *pbNewTerm = 1;
    +       }
    +       fts5AssertMultiIterSetup(p, pIter);
    + 
    +-      bUseFrom = 0;
    +-    }while( pIter->bSkipEmpty && fts5MultiIterIsEmpty(p, pIter) );
    ++    }while( fts5MultiIterIsEmpty(p, pIter) );
    +   }
    + }
    + 
    +-static Fts5IndexIter *fts5MultiIterAlloc(
    ++static void fts5IterSetOutputs_Noop(Fts5Iter *pUnused1, Fts5SegIter *pUnused2){
    ++  UNUSED_PARAM2(pUnused1, pUnused2);
    ++}
    ++
    ++static Fts5Iter *fts5MultiIterAlloc(
    +   Fts5Index *p,                   /* FTS5 backend to iterate within */
    +   int nSeg
    + ){
    +-  Fts5IndexIter *pNew;
    ++  Fts5Iter *pNew;
    +   int nSlot;                      /* Power of two >= nSeg */
    + 
    +   for(nSlot=2; nSlot<nSeg; nSlot=nSlot*2);
    +   pNew = fts5IdxMalloc(p, 
    +-      sizeof(Fts5IndexIter) +             /* pNew */
    ++      sizeof(Fts5Iter) +                  /* pNew */
    +       sizeof(Fts5SegIter) * (nSlot-1) +   /* pNew->aSeg[] */
    +       sizeof(Fts5CResult) * nSlot         /* pNew->aFirst[] */
    +   );
    +@@ -175111,12 +197193,434 @@ static Fts5IndexIter *fts5MultiIterAlloc(
    +     pNew->nSeg = nSlot;
    +     pNew->aFirst = (Fts5CResult*)&pNew->aSeg[nSlot];
    +     pNew->pIndex = p;
    ++    pNew->xSetOutputs = fts5IterSetOutputs_Noop;
    +   }
    +   return pNew;
    + }
    + 
    ++static void fts5PoslistCallback(
    ++  Fts5Index *pUnused, 
    ++  void *pContext, 
    ++  const u8 *pChunk, int nChunk
    ++){
    ++  UNUSED_PARAM(pUnused);
    ++  assert_nc( nChunk>=0 );
    ++  if( nChunk>0 ){
    ++    fts5BufferSafeAppendBlob((Fts5Buffer*)pContext, pChunk, nChunk);
    ++  }
    ++}
    ++
    ++typedef struct PoslistCallbackCtx PoslistCallbackCtx;
    ++struct PoslistCallbackCtx {
    ++  Fts5Buffer *pBuf;               /* Append to this buffer */
    ++  Fts5Colset *pColset;            /* Restrict matches to this column */
    ++  int eState;                     /* See above */
    ++};
    ++
    ++typedef struct PoslistOffsetsCtx PoslistOffsetsCtx;
    ++struct PoslistOffsetsCtx {
    ++  Fts5Buffer *pBuf;               /* Append to this buffer */
    ++  Fts5Colset *pColset;            /* Restrict matches to this column */
    ++  int iRead;
    ++  int iWrite;
    ++};
    ++
    + /*
    +-** Allocate a new Fts5IndexIter object.
    ++** TODO: Make this more efficient!
    ++*/
    ++static int fts5IndexColsetTest(Fts5Colset *pColset, int iCol){
    ++  int i;
    ++  for(i=0; i<pColset->nCol; i++){
    ++    if( pColset->aiCol[i]==iCol ) return 1;
    ++  }
    ++  return 0;
    ++}
    ++
    ++static void fts5PoslistOffsetsCallback(
    ++  Fts5Index *pUnused, 
    ++  void *pContext, 
    ++  const u8 *pChunk, int nChunk
    ++){
    ++  PoslistOffsetsCtx *pCtx = (PoslistOffsetsCtx*)pContext;
    ++  UNUSED_PARAM(pUnused);
    ++  assert_nc( nChunk>=0 );
    ++  if( nChunk>0 ){
    ++    int i = 0;
    ++    while( i<nChunk ){
    ++      int iVal;
    ++      i += fts5GetVarint32(&pChunk[i], iVal);
    ++      iVal += pCtx->iRead - 2;
    ++      pCtx->iRead = iVal;
    ++      if( fts5IndexColsetTest(pCtx->pColset, iVal) ){
    ++        fts5BufferSafeAppendVarint(pCtx->pBuf, iVal + 2 - pCtx->iWrite);
    ++        pCtx->iWrite = iVal;
    ++      }
    ++    }
    ++  }
    ++}
    ++
    ++static void fts5PoslistFilterCallback(
    ++  Fts5Index *pUnused,
    ++  void *pContext, 
    ++  const u8 *pChunk, int nChunk
    ++){
    ++  PoslistCallbackCtx *pCtx = (PoslistCallbackCtx*)pContext;
    ++  UNUSED_PARAM(pUnused);
    ++  assert_nc( nChunk>=0 );
    ++  if( nChunk>0 ){
    ++    /* Search through to find the first varint with value 1. This is the
    ++    ** start of the next columns hits. */
    ++    int i = 0;
    ++    int iStart = 0;
    ++
    ++    if( pCtx->eState==2 ){
    ++      int iCol;
    ++      fts5FastGetVarint32(pChunk, i, iCol);
    ++      if( fts5IndexColsetTest(pCtx->pColset, iCol) ){
    ++        pCtx->eState = 1;
    ++        fts5BufferSafeAppendVarint(pCtx->pBuf, 1);
    ++      }else{
    ++        pCtx->eState = 0;
    ++      }
    ++    }
    ++
    ++    do {
    ++      while( i<nChunk && pChunk[i]!=0x01 ){
    ++        while( pChunk[i] & 0x80 ) i++;
    ++        i++;
    ++      }
    ++      if( pCtx->eState ){
    ++        fts5BufferSafeAppendBlob(pCtx->pBuf, &pChunk[iStart], i-iStart);
    ++      }
    ++      if( i<nChunk ){
    ++        int iCol;
    ++        iStart = i;
    ++        i++;
    ++        if( i>=nChunk ){
    ++          pCtx->eState = 2;
    ++        }else{
    ++          fts5FastGetVarint32(pChunk, i, iCol);
    ++          pCtx->eState = fts5IndexColsetTest(pCtx->pColset, iCol);
    ++          if( pCtx->eState ){
    ++            fts5BufferSafeAppendBlob(pCtx->pBuf, &pChunk[iStart], i-iStart);
    ++            iStart = i;
    ++          }
    ++        }
    ++      }
    ++    }while( i<nChunk );
    ++  }
    ++}
    ++
    ++static void fts5ChunkIterate(
    ++  Fts5Index *p,                   /* Index object */
    ++  Fts5SegIter *pSeg,              /* Poslist of this iterator */
    ++  void *pCtx,                     /* Context pointer for xChunk callback */
    ++  void (*xChunk)(Fts5Index*, void*, const u8*, int)
    ++){
    ++  int nRem = pSeg->nPos;          /* Number of bytes still to come */
    ++  Fts5Data *pData = 0;
    ++  u8 *pChunk = &pSeg->pLeaf->p[pSeg->iLeafOffset];
    ++  int nChunk = MIN(nRem, pSeg->pLeaf->szLeaf - pSeg->iLeafOffset);
    ++  int pgno = pSeg->iLeafPgno;
    ++  int pgnoSave = 0;
    ++
    ++  /* This function does notmwork with detail=none databases. */
    ++  assert( p->pConfig->eDetail!=FTS5_DETAIL_NONE );
    ++
    ++  if( (pSeg->flags & FTS5_SEGITER_REVERSE)==0 ){
    ++    pgnoSave = pgno+1;
    ++  }
    ++
    ++  while( 1 ){
    ++    xChunk(p, pCtx, pChunk, nChunk);
    ++    nRem -= nChunk;
    ++    fts5DataRelease(pData);
    ++    if( nRem<=0 ){
    ++      break;
    ++    }else{
    ++      pgno++;
    ++      pData = fts5LeafRead(p, FTS5_SEGMENT_ROWID(pSeg->pSeg->iSegid, pgno));
    ++      if( pData==0 ) break;
    ++      pChunk = &pData->p[4];
    ++      nChunk = MIN(nRem, pData->szLeaf - 4);
    ++      if( pgno==pgnoSave ){
    ++        assert( pSeg->pNextLeaf==0 );
    ++        pSeg->pNextLeaf = pData;
    ++        pData = 0;
    ++      }
    ++    }
    ++  }
    ++}
    ++
    ++/*
    ++** Iterator pIter currently points to a valid entry (not EOF). This
    ++** function appends the position list data for the current entry to
    ++** buffer pBuf. It does not make a copy of the position-list size
    ++** field.
    ++*/
    ++static void fts5SegiterPoslist(
    ++  Fts5Index *p,
    ++  Fts5SegIter *pSeg,
    ++  Fts5Colset *pColset,
    ++  Fts5Buffer *pBuf
    ++){
    ++  if( 0==fts5BufferGrow(&p->rc, pBuf, pSeg->nPos) ){
    ++    if( pColset==0 ){
    ++      fts5ChunkIterate(p, pSeg, (void*)pBuf, fts5PoslistCallback);
    ++    }else{
    ++      if( p->pConfig->eDetail==FTS5_DETAIL_FULL ){
    ++        PoslistCallbackCtx sCtx;
    ++        sCtx.pBuf = pBuf;
    ++        sCtx.pColset = pColset;
    ++        sCtx.eState = fts5IndexColsetTest(pColset, 0);
    ++        assert( sCtx.eState==0 || sCtx.eState==1 );
    ++        fts5ChunkIterate(p, pSeg, (void*)&sCtx, fts5PoslistFilterCallback);
    ++      }else{
    ++        PoslistOffsetsCtx sCtx;
    ++        memset(&sCtx, 0, sizeof(sCtx));
    ++        sCtx.pBuf = pBuf;
    ++        sCtx.pColset = pColset;
    ++        fts5ChunkIterate(p, pSeg, (void*)&sCtx, fts5PoslistOffsetsCallback);
    ++      }
    ++    }
    ++  }
    ++}
    ++
    ++/*
    ++** IN/OUT parameter (*pa) points to a position list n bytes in size. If
    ++** the position list contains entries for column iCol, then (*pa) is set
    ++** to point to the sub-position-list for that column and the number of
    ++** bytes in it returned. Or, if the argument position list does not
    ++** contain any entries for column iCol, return 0.
    ++*/
    ++static int fts5IndexExtractCol(
    ++  const u8 **pa,                  /* IN/OUT: Pointer to poslist */
    ++  int n,                          /* IN: Size of poslist in bytes */
    ++  int iCol                        /* Column to extract from poslist */
    ++){
    ++  int iCurrent = 0;               /* Anything before the first 0x01 is col 0 */
    ++  const u8 *p = *pa;
    ++  const u8 *pEnd = &p[n];         /* One byte past end of position list */
    ++
    ++  while( iCol>iCurrent ){
    ++    /* Advance pointer p until it points to pEnd or an 0x01 byte that is
    ++    ** not part of a varint. Note that it is not possible for a negative
    ++    ** or extremely large varint to occur within an uncorrupted position 
    ++    ** list. So the last byte of each varint may be assumed to have a clear
    ++    ** 0x80 bit.  */
    ++    while( *p!=0x01 ){
    ++      while( *p++ & 0x80 );
    ++      if( p>=pEnd ) return 0;
    ++    }
    ++    *pa = p++;
    ++    iCurrent = *p++;
    ++    if( iCurrent & 0x80 ){
    ++      p--;
    ++      p += fts5GetVarint32(p, iCurrent);
    ++    }
    ++  }
    ++  if( iCol!=iCurrent ) return 0;
    ++
    ++  /* Advance pointer p until it points to pEnd or an 0x01 byte that is
    ++  ** not part of a varint */
    ++  while( p<pEnd && *p!=0x01 ){
    ++    while( *p++ & 0x80 );
    ++  }
    ++
    ++  return p - (*pa);
    ++}
    ++
    ++static void fts5IndexExtractColset(
    ++  int *pRc,
    ++  Fts5Colset *pColset,            /* Colset to filter on */
    ++  const u8 *pPos, int nPos,       /* Position list */
    ++  Fts5Buffer *pBuf                /* Output buffer */
    ++){
    ++  if( *pRc==SQLITE_OK ){
    ++    int i;
    ++    fts5BufferZero(pBuf);
    ++    for(i=0; i<pColset->nCol; i++){
    ++      const u8 *pSub = pPos;
    ++      int nSub = fts5IndexExtractCol(&pSub, nPos, pColset->aiCol[i]);
    ++      if( nSub ){
    ++        fts5BufferAppendBlob(pRc, pBuf, nSub, pSub);
    ++      }
    ++    }
    ++  }
    ++}
    ++
    ++/*
    ++** xSetOutputs callback used by detail=none tables.
    ++*/
    ++static void fts5IterSetOutputs_None(Fts5Iter *pIter, Fts5SegIter *pSeg){
    ++  assert( pIter->pIndex->pConfig->eDetail==FTS5_DETAIL_NONE );
    ++  pIter->base.iRowid = pSeg->iRowid;
    ++  pIter->base.nData = pSeg->nPos;
    ++}
    ++
    ++/*
    ++** xSetOutputs callback used by detail=full and detail=col tables when no
    ++** column filters are specified.
    ++*/
    ++static void fts5IterSetOutputs_Nocolset(Fts5Iter *pIter, Fts5SegIter *pSeg){
    ++  pIter->base.iRowid = pSeg->iRowid;
    ++  pIter->base.nData = pSeg->nPos;
    ++
    ++  assert( pIter->pIndex->pConfig->eDetail!=FTS5_DETAIL_NONE );
    ++  assert( pIter->pColset==0 );
    ++
    ++  if( pSeg->iLeafOffset+pSeg->nPos<=pSeg->pLeaf->szLeaf ){
    ++    /* All data is stored on the current page. Populate the output 
    ++    ** variables to point into the body of the page object. */
    ++    pIter->base.pData = &pSeg->pLeaf->p[pSeg->iLeafOffset];
    ++  }else{
    ++    /* The data is distributed over two or more pages. Copy it into the
    ++    ** Fts5Iter.poslist buffer and then set the output pointer to point
    ++    ** to this buffer.  */
    ++    fts5BufferZero(&pIter->poslist);
    ++    fts5SegiterPoslist(pIter->pIndex, pSeg, 0, &pIter->poslist);
    ++    pIter->base.pData = pIter->poslist.p;
    ++  }
    ++}
    ++
    ++/*
    ++** xSetOutputs callback used when the Fts5Colset object has nCol==0 (match
    ++** against no columns at all).
    ++*/
    ++static void fts5IterSetOutputs_ZeroColset(Fts5Iter *pIter, Fts5SegIter *pSeg){
    ++  UNUSED_PARAM(pSeg);
    ++  pIter->base.nData = 0;
    ++}
    ++
    ++/*
    ++** xSetOutputs callback used by detail=col when there is a column filter
    ++** and there are 100 or more columns. Also called as a fallback from
    ++** fts5IterSetOutputs_Col100 if the column-list spans more than one page.
    ++*/
    ++static void fts5IterSetOutputs_Col(Fts5Iter *pIter, Fts5SegIter *pSeg){
    ++  fts5BufferZero(&pIter->poslist);
    ++  fts5SegiterPoslist(pIter->pIndex, pSeg, pIter->pColset, &pIter->poslist);
    ++  pIter->base.iRowid = pSeg->iRowid;
    ++  pIter->base.pData = pIter->poslist.p;
    ++  pIter->base.nData = pIter->poslist.n;
    ++}
    ++
    ++/*
    ++** xSetOutputs callback used when: 
    ++**
    ++**   * detail=col,
    ++**   * there is a column filter, and
    ++**   * the table contains 100 or fewer columns. 
    ++**
    ++** The last point is to ensure all column numbers are stored as 
    ++** single-byte varints.
    ++*/
    ++static void fts5IterSetOutputs_Col100(Fts5Iter *pIter, Fts5SegIter *pSeg){
    ++
    ++  assert( pIter->pIndex->pConfig->eDetail==FTS5_DETAIL_COLUMNS );
    ++  assert( pIter->pColset );
    ++
    ++  if( pSeg->iLeafOffset+pSeg->nPos>pSeg->pLeaf->szLeaf ){
    ++    fts5IterSetOutputs_Col(pIter, pSeg);
    ++  }else{
    ++    u8 *a = (u8*)&pSeg->pLeaf->p[pSeg->iLeafOffset];
    ++    u8 *pEnd = (u8*)&a[pSeg->nPos]; 
    ++    int iPrev = 0;
    ++    int *aiCol = pIter->pColset->aiCol;
    ++    int *aiColEnd = &aiCol[pIter->pColset->nCol];
    ++
    ++    u8 *aOut = pIter->poslist.p;
    ++    int iPrevOut = 0;
    ++
    ++    pIter->base.iRowid = pSeg->iRowid;
    ++
    ++    while( a<pEnd ){
    ++      iPrev += (int)a++[0] - 2;
    ++      while( *aiCol<iPrev ){
    ++        aiCol++;
    ++        if( aiCol==aiColEnd ) goto setoutputs_col_out;
    ++      }
    ++      if( *aiCol==iPrev ){
    ++        *aOut++ = (u8)((iPrev - iPrevOut) + 2);
    ++        iPrevOut = iPrev;
    ++      }
    ++    }
    ++
    ++setoutputs_col_out:
    ++    pIter->base.pData = pIter->poslist.p;
    ++    pIter->base.nData = aOut - pIter->poslist.p;
    ++  }
    ++}
    ++
    ++/*
    ++** xSetOutputs callback used by detail=full when there is a column filter.
    ++*/
    ++static void fts5IterSetOutputs_Full(Fts5Iter *pIter, Fts5SegIter *pSeg){
    ++  Fts5Colset *pColset = pIter->pColset;
    ++  pIter->base.iRowid = pSeg->iRowid;
    ++
    ++  assert( pIter->pIndex->pConfig->eDetail==FTS5_DETAIL_FULL );
    ++  assert( pColset );
    ++
    ++  if( pSeg->iLeafOffset+pSeg->nPos<=pSeg->pLeaf->szLeaf ){
    ++    /* All data is stored on the current page. Populate the output 
    ++    ** variables to point into the body of the page object. */
    ++    const u8 *a = &pSeg->pLeaf->p[pSeg->iLeafOffset];
    ++    if( pColset->nCol==1 ){
    ++      pIter->base.nData = fts5IndexExtractCol(&a, pSeg->nPos,pColset->aiCol[0]);
    ++      pIter->base.pData = a;
    ++    }else{
    ++      int *pRc = &pIter->pIndex->rc;
    ++      fts5BufferZero(&pIter->poslist);
    ++      fts5IndexExtractColset(pRc, pColset, a, pSeg->nPos, &pIter->poslist);
    ++      pIter->base.pData = pIter->poslist.p;
    ++      pIter->base.nData = pIter->poslist.n;
    ++    }
    ++  }else{
    ++    /* The data is distributed over two or more pages. Copy it into the
    ++    ** Fts5Iter.poslist buffer and then set the output pointer to point
    ++    ** to this buffer.  */
    ++    fts5BufferZero(&pIter->poslist);
    ++    fts5SegiterPoslist(pIter->pIndex, pSeg, pColset, &pIter->poslist);
    ++    pIter->base.pData = pIter->poslist.p;
    ++    pIter->base.nData = pIter->poslist.n;
    ++  }
    ++}
    ++
    ++static void fts5IterSetOutputCb(int *pRc, Fts5Iter *pIter){
    ++  if( *pRc==SQLITE_OK ){
    ++    Fts5Config *pConfig = pIter->pIndex->pConfig;
    ++    if( pConfig->eDetail==FTS5_DETAIL_NONE ){
    ++      pIter->xSetOutputs = fts5IterSetOutputs_None;
    ++    }
    ++
    ++    else if( pIter->pColset==0 ){
    ++      pIter->xSetOutputs = fts5IterSetOutputs_Nocolset;
    ++    }
    ++
    ++    else if( pIter->pColset->nCol==0 ){
    ++      pIter->xSetOutputs = fts5IterSetOutputs_ZeroColset;
    ++    }
    ++
    ++    else if( pConfig->eDetail==FTS5_DETAIL_FULL ){
    ++      pIter->xSetOutputs = fts5IterSetOutputs_Full;
    ++    }
    ++
    ++    else{
    ++      assert( pConfig->eDetail==FTS5_DETAIL_COLUMNS );
    ++      if( pConfig->nCol<=100 ){
    ++        pIter->xSetOutputs = fts5IterSetOutputs_Col100;
    ++        sqlite3Fts5BufferSize(pRc, &pIter->poslist, pConfig->nCol);
    ++      }else{
    ++        pIter->xSetOutputs = fts5IterSetOutputs_Col;
    ++      }
    ++    }
    ++  }
    ++}
    ++
    ++
    ++/*
    ++** Allocate a new Fts5Iter object.
    + **
    + ** The new object will be used to iterate through data in structure pStruct.
    + ** If iLevel is -ve, then all data in all segments is merged. Or, if iLevel
    +@@ -175129,19 +197633,18 @@ static Fts5IndexIter *fts5MultiIterAlloc(
    + static void fts5MultiIterNew(
    +   Fts5Index *p,                   /* FTS5 backend to iterate within */
    +   Fts5Structure *pStruct,         /* Structure of specific index */
    +-  int bSkipEmpty,                 /* True to ignore delete-keys */
    +   int flags,                      /* FTS5INDEX_QUERY_XXX flags */
    ++  Fts5Colset *pColset,            /* Colset to filter on (or NULL) */
    +   const u8 *pTerm, int nTerm,     /* Term to seek to (or NULL/0) */
    +   int iLevel,                     /* Level to iterate (-1 for all) */
    +   int nSegment,                   /* Number of segments to merge (iLevel>=0) */
    +-  Fts5IndexIter **ppOut           /* New object */
    ++  Fts5Iter **ppOut                /* New object */
    + ){
    +   int nSeg = 0;                   /* Number of segment-iters in use */
    +   int iIter = 0;                  /* */
    +   int iSeg;                       /* Used to iterate through segments */
    +-  Fts5Buffer buf = {0,0,0};       /* Buffer used by fts5SegIterSeekInit() */
    +   Fts5StructureLevel *pLvl;
    +-  Fts5IndexIter *pNew;
    ++  Fts5Iter *pNew;
    + 
    +   assert( (pTerm==0 && nTerm==0) || iLevel<0 );
    + 
    +@@ -175158,36 +197661,42 @@ static void fts5MultiIterNew(
    +   *ppOut = pNew = fts5MultiIterAlloc(p, nSeg);
    +   if( pNew==0 ) return;
    +   pNew->bRev = (0!=(flags & FTS5INDEX_QUERY_DESC));
    +-  pNew->bSkipEmpty = bSkipEmpty;
    ++  pNew->bSkipEmpty = (0!=(flags & FTS5INDEX_QUERY_SKIPEMPTY));
    +   pNew->pStruct = pStruct;
    ++  pNew->pColset = pColset;
    +   fts5StructureRef(pStruct);
    ++  if( (flags & FTS5INDEX_QUERY_NOOUTPUT)==0 ){
    ++    fts5IterSetOutputCb(&p->rc, pNew);
    ++  }
    + 
    +   /* Initialize each of the component segment iterators. */
    +-  if( iLevel<0 ){
    +-    Fts5StructureLevel *pEnd = &pStruct->aLevel[pStruct->nLevel];
    +-    if( p->pHash ){
    +-      /* Add a segment iterator for the current contents of the hash table. */
    +-      Fts5SegIter *pIter = &pNew->aSeg[iIter++];
    +-      fts5SegIterHashInit(p, pTerm, nTerm, flags, pIter);
    +-    }
    +-    for(pLvl=&pStruct->aLevel[0]; pLvl<pEnd; pLvl++){
    +-      for(iSeg=pLvl->nSeg-1; iSeg>=0; iSeg--){
    +-        Fts5StructureSegment *pSeg = &pLvl->aSeg[iSeg];
    ++  if( p->rc==SQLITE_OK ){
    ++    if( iLevel<0 ){
    ++      Fts5StructureLevel *pEnd = &pStruct->aLevel[pStruct->nLevel];
    ++      if( p->pHash ){
    ++        /* Add a segment iterator for the current contents of the hash table. */
    +         Fts5SegIter *pIter = &pNew->aSeg[iIter++];
    +-        if( pTerm==0 ){
    +-          fts5SegIterInit(p, pSeg, pIter);
    +-        }else{
    +-          fts5SegIterSeekInit(p, &buf, pTerm, nTerm, flags, pSeg, pIter);
    ++        fts5SegIterHashInit(p, pTerm, nTerm, flags, pIter);
    ++      }
    ++      for(pLvl=&pStruct->aLevel[0]; pLvl<pEnd; pLvl++){
    ++        for(iSeg=pLvl->nSeg-1; iSeg>=0; iSeg--){
    ++          Fts5StructureSegment *pSeg = &pLvl->aSeg[iSeg];
    ++          Fts5SegIter *pIter = &pNew->aSeg[iIter++];
    ++          if( pTerm==0 ){
    ++            fts5SegIterInit(p, pSeg, pIter);
    ++          }else{
    ++            fts5SegIterSeekInit(p, pTerm, nTerm, flags, pSeg, pIter);
    ++          }
    +         }
    +       }
    ++    }else{
    ++      pLvl = &pStruct->aLevel[iLevel];
    ++      for(iSeg=nSeg-1; iSeg>=0; iSeg--){
    ++        fts5SegIterInit(p, &pLvl->aSeg[iSeg], &pNew->aSeg[iIter++]);
    ++      }
    +     }
    +-  }else{
    +-    pLvl = &pStruct->aLevel[iLevel];
    +-    for(iSeg=nSeg-1; iSeg>=0; iSeg--){
    +-      fts5SegIterInit(p, &pLvl->aSeg[iSeg], &pNew->aSeg[iIter++]);
    +-    }
    ++    assert( iIter==nSeg );
    +   }
    +-  assert( iIter==nSeg );
    + 
    +   /* If the above was successful, each component iterators now points 
    +   ** to the first entry in its segment. In this case initialize the 
    +@@ -175197,7 +197706,8 @@ static void fts5MultiIterNew(
    +     for(iIter=pNew->nSeg-1; iIter>0; iIter--){
    +       int iEq;
    +       if( (iEq = fts5MultiIterDoCompare(pNew, iIter)) ){
    +-        fts5SegIterNext(p, &pNew->aSeg[iEq], 0);
    ++        Fts5SegIter *pSeg = &pNew->aSeg[iEq];
    ++        if( p->rc==SQLITE_OK ) pSeg->xNext(p, pSeg, 0);
    +         fts5MultiIterAdvanced(p, pNew, iEq, iIter);
    +       }
    +     }
    +@@ -175206,30 +197716,32 @@ static void fts5MultiIterNew(
    + 
    +     if( pNew->bSkipEmpty && fts5MultiIterIsEmpty(p, pNew) ){
    +       fts5MultiIterNext(p, pNew, 0, 0);
    ++    }else if( pNew->base.bEof==0 ){
    ++      Fts5SegIter *pSeg = &pNew->aSeg[pNew->aFirst[1].iFirst];
    ++      pNew->xSetOutputs(pNew, pSeg);
    +     }
    ++
    +   }else{
    +-    fts5MultiIterFree(p, pNew);
    ++    fts5MultiIterFree(pNew);
    +     *ppOut = 0;
    +   }
    +-  fts5BufferFree(&buf);
    + }
    + 
    + /*
    +-** Create an Fts5IndexIter that iterates through the doclist provided
    ++** Create an Fts5Iter that iterates through the doclist provided
    + ** as the second argument.
    + */
    + static void fts5MultiIterNew2(
    +   Fts5Index *p,                   /* FTS5 backend to iterate within */
    +   Fts5Data *pData,                /* Doclist to iterate through */
    +   int bDesc,                      /* True for descending rowid order */
    +-  Fts5IndexIter **ppOut           /* New object */
    ++  Fts5Iter **ppOut                /* New object */
    + ){
    +-  Fts5IndexIter *pNew;
    ++  Fts5Iter *pNew;
    +   pNew = fts5MultiIterAlloc(p, 2);
    +   if( pNew ){
    +     Fts5SegIter *pIter = &pNew->aSeg[1];
    + 
    +-    pNew->bFiltered = 1;
    +     pIter->flags = FTS5_SEGITER_ONETERM;
    +     if( pData->szLeaf>0 ){
    +       pIter->pLeaf = pData;
    +@@ -175245,8 +197757,9 @@ static void fts5MultiIterNew2(
    +       }
    +       pData = 0;
    +     }else{
    +-      pNew->bEof = 1;
    ++      pNew->base.bEof = 1;
    +     }
    ++    fts5SegIterSetNext(p, pIter);
    + 
    +     *ppOut = pNew;
    +   }
    +@@ -175258,11 +197771,11 @@ static void fts5MultiIterNew2(
    + ** Return true if the iterator is at EOF or if an error has occurred. 
    + ** False otherwise.
    + */
    +-static int fts5MultiIterEof(Fts5Index *p, Fts5IndexIter *pIter){
    ++static int fts5MultiIterEof(Fts5Index *p, Fts5Iter *pIter){
    +   assert( p->rc 
    +-      || (pIter->aSeg[ pIter->aFirst[1].iFirst ].pLeaf==0)==pIter->bEof 
    ++      || (pIter->aSeg[ pIter->aFirst[1].iFirst ].pLeaf==0)==pIter->base.bEof 
    +   );
    +-  return (p->rc || pIter->bEof);
    ++  return (p->rc || pIter->base.bEof);
    + }
    + 
    + /*
    +@@ -175270,7 +197783,7 @@ static int fts5MultiIterEof(Fts5Index *p, Fts5IndexIter *pIter){
    + ** to. If the iterator points to EOF when this function is called the
    + ** results are undefined.
    + */
    +-static i64 fts5MultiIterRowid(Fts5IndexIter *pIter){
    ++static i64 fts5MultiIterRowid(Fts5Iter *pIter){
    +   assert( pIter->aSeg[ pIter->aFirst[1].iFirst ].pLeaf );
    +   return pIter->aSeg[ pIter->aFirst[1].iFirst ].iRowid;
    + }
    +@@ -175280,7 +197793,7 @@ static i64 fts5MultiIterRowid(Fts5IndexIter *pIter){
    + */
    + static void fts5MultiIterNextFrom(
    +   Fts5Index *p, 
    +-  Fts5IndexIter *pIter, 
    ++  Fts5Iter *pIter, 
    +   i64 iMatch
    + ){
    +   while( 1 ){
    +@@ -175297,52 +197810,12 @@ static void fts5MultiIterNextFrom(
    + ** Return a pointer to a buffer containing the term associated with the 
    + ** entry that the iterator currently points to.
    + */
    +-static const u8 *fts5MultiIterTerm(Fts5IndexIter *pIter, int *pn){
    ++static const u8 *fts5MultiIterTerm(Fts5Iter *pIter, int *pn){
    +   Fts5SegIter *p = &pIter->aSeg[ pIter->aFirst[1].iFirst ];
    +   *pn = p->term.n;
    +   return p->term.p;
    + }
    + 
    +-static void fts5ChunkIterate(
    +-  Fts5Index *p,                   /* Index object */
    +-  Fts5SegIter *pSeg,              /* Poslist of this iterator */
    +-  void *pCtx,                     /* Context pointer for xChunk callback */
    +-  void (*xChunk)(Fts5Index*, void*, const u8*, int)
    +-){
    +-  int nRem = pSeg->nPos;          /* Number of bytes still to come */
    +-  Fts5Data *pData = 0;
    +-  u8 *pChunk = &pSeg->pLeaf->p[pSeg->iLeafOffset];
    +-  int nChunk = MIN(nRem, pSeg->pLeaf->szLeaf - pSeg->iLeafOffset);
    +-  int pgno = pSeg->iLeafPgno;
    +-  int pgnoSave = 0;
    +-
    +-  if( (pSeg->flags & FTS5_SEGITER_REVERSE)==0 ){
    +-    pgnoSave = pgno+1;
    +-  }
    +-
    +-  while( 1 ){
    +-    xChunk(p, pCtx, pChunk, nChunk);
    +-    nRem -= nChunk;
    +-    fts5DataRelease(pData);
    +-    if( nRem<=0 ){
    +-      break;
    +-    }else{
    +-      pgno++;
    +-      pData = fts5DataRead(p, FTS5_SEGMENT_ROWID(pSeg->pSeg->iSegid, pgno));
    +-      if( pData==0 ) break;
    +-      pChunk = &pData->p[4];
    +-      nChunk = MIN(nRem, pData->szLeaf - 4);
    +-      if( pgno==pgnoSave ){
    +-        assert( pSeg->pNextLeaf==0 );
    +-        pSeg->pNextLeaf = pData;
    +-        pData = 0;
    +-      }
    +-    }
    +-  }
    +-}
    +-
    +-
    +-
    + /*
    + ** Allocate a new segment-id for the structure pStruct. The new segment
    + ** id must be between 1 and 65335 inclusive, and must not be used by 
    +@@ -175359,18 +197832,46 @@ static int fts5AllocateSegid(Fts5Index *p, Fts5Structure *pStruct){
    +     if( pStruct->nSegment>=FTS5_MAX_SEGMENT ){
    +       p->rc = SQLITE_FULL;
    +     }else{
    +-      while( iSegid==0 ){
    +-        int iLvl, iSeg;
    +-        sqlite3_randomness(sizeof(u32), (void*)&iSegid);
    +-        iSegid = iSegid & ((1 << FTS5_DATA_ID_B)-1);
    +-        for(iLvl=0; iLvl<pStruct->nLevel; iLvl++){
    +-          for(iSeg=0; iSeg<pStruct->aLevel[iLvl].nSeg; iSeg++){
    +-            if( iSegid==pStruct->aLevel[iLvl].aSeg[iSeg].iSegid ){
    +-              iSegid = 0;
    +-            }
    ++      /* FTS5_MAX_SEGMENT is currently defined as 2000. So the following
    ++      ** array is 63 elements, or 252 bytes, in size.  */
    ++      u32 aUsed[(FTS5_MAX_SEGMENT+31) / 32];
    ++      int iLvl, iSeg;
    ++      int i;
    ++      u32 mask;
    ++      memset(aUsed, 0, sizeof(aUsed));
    ++      for(iLvl=0; iLvl<pStruct->nLevel; iLvl++){
    ++        for(iSeg=0; iSeg<pStruct->aLevel[iLvl].nSeg; iSeg++){
    ++          int iId = pStruct->aLevel[iLvl].aSeg[iSeg].iSegid;
    ++          if( iId<=FTS5_MAX_SEGMENT ){
    ++            aUsed[(iId-1) / 32] |= 1 << ((iId-1) % 32);
    +           }
    +         }
    +       }
    ++
    ++      for(i=0; aUsed[i]==0xFFFFFFFF; i++);
    ++      mask = aUsed[i];
    ++      for(iSegid=0; mask & (1 << iSegid); iSegid++);
    ++      iSegid += 1 + i*32;
    ++
    ++#ifdef SQLITE_DEBUG
    ++      for(iLvl=0; iLvl<pStruct->nLevel; iLvl++){
    ++        for(iSeg=0; iSeg<pStruct->aLevel[iLvl].nSeg; iSeg++){
    ++          assert( iSegid!=pStruct->aLevel[iLvl].aSeg[iSeg].iSegid );
    ++        }
    ++      }
    ++      assert( iSegid>0 && iSegid<=FTS5_MAX_SEGMENT );
    ++
    ++      {
    ++        sqlite3_stmt *pIdxSelect = fts5IdxSelectStmt(p);
    ++        if( p->rc==SQLITE_OK ){
    ++          u8 aBlob[2] = {0xff, 0xff};
    ++          sqlite3_bind_int(pIdxSelect, 1, iSegid);
    ++          sqlite3_bind_blob(pIdxSelect, 2, aBlob, 2, SQLITE_STATIC);
    ++          assert( sqlite3_step(pIdxSelect)!=SQLITE_ROW );
    ++          p->rc = sqlite3_reset(pIdxSelect);
    ++        }
    ++      }
    ++#endif
    +     }
    +   }
    + 
    +@@ -175389,15 +197890,14 @@ static void fts5IndexDiscardData(Fts5Index *p){
    + }
    + 
    + /*
    +-** Return the size of the prefix, in bytes, that buffer (nNew/pNew) shares
    +-** with buffer (nOld/pOld).
    ++** Return the size of the prefix, in bytes, that buffer 
    ++** (pNew/<length-unknown>) shares with buffer (pOld/nOld).
    ++**
    ++** Buffer (pNew/<length-unknown>) is guaranteed to be greater 
    ++** than buffer (pOld/nOld).
    + */
    +-static int fts5PrefixCompress(
    +-  int nOld, const u8 *pOld,
    +-  int nNew, const u8 *pNew
    +-){
    ++static int fts5PrefixCompress(int nOld, const u8 *pOld, const u8 *pNew){
    +   int i;
    +-  assert( fts5BlobCompare(pOld, nOld, pNew, nNew)<0 );
    +   for(i=0; i<nOld; i++){
    +     if( pOld[i]!=pNew[i] ) break;
    +   }
    +@@ -175621,7 +198121,7 @@ static void fts5WriteFlushLeaf(Fts5Index *p, Fts5SegWriter *pWriter){
    + 
    +   /* Set the szLeaf header field. */
    +   assert( 0==fts5GetU16(&pPage->buf.p[2]) );
    +-  fts5PutU16(&pPage->buf.p[2], pPage->buf.n);
    ++  fts5PutU16(&pPage->buf.p[2], (u16)pPage->buf.n);
    + 
    +   if( pWriter->bFirstTermInPage ){
    +     /* No term was written to this page. */
    +@@ -175707,13 +198207,13 @@ static void fts5WriteAppendTerm(
    +       ** inefficient, but still correct.  */
    +       int n = nTerm;
    +       if( pPage->term.n ){
    +-        n = 1 + fts5PrefixCompress(pPage->term.n, pPage->term.p, nTerm, pTerm);
    ++        n = 1 + fts5PrefixCompress(pPage->term.n, pPage->term.p, pTerm);
    +       }
    +       fts5WriteBtreeTerm(p, pWriter, n, pTerm);
    +       pPage = &pWriter->writer;
    +     }
    +   }else{
    +-    nPrefix = fts5PrefixCompress(pPage->term.n, pPage->term.p, nTerm, pTerm);
    ++    nPrefix = fts5PrefixCompress(pPage->term.n, pPage->term.p, pTerm);
    +     fts5BufferAppendVarint(&p->rc, &pPage->buf, nPrefix);
    +   }
    + 
    +@@ -175739,8 +198239,7 @@ static void fts5WriteAppendTerm(
    + static void fts5WriteAppendRowid(
    +   Fts5Index *p, 
    +   Fts5SegWriter *pWriter,
    +-  i64 iRowid,
    +-  int nPos
    ++  i64 iRowid
    + ){
    +   if( p->rc==SQLITE_OK ){
    +     Fts5PageWriter *pPage = &pWriter->writer;
    +@@ -175753,7 +198252,7 @@ static void fts5WriteAppendRowid(
    +     ** rowid-pointer in the page-header. Also append a value to the dlidx
    +     ** buffer, in case a doclist-index is required.  */
    +     if( pWriter->bFirstRowidInPage ){
    +-      fts5PutU16(pPage->buf.p, pPage->buf.n);
    ++      fts5PutU16(pPage->buf.p, (u16)pPage->buf.n);
    +       fts5WriteDlidxAppend(p, pWriter, iRowid);
    +     }
    + 
    +@@ -175767,8 +198266,6 @@ static void fts5WriteAppendRowid(
    +     pWriter->iPrevRowid = iRowid;
    +     pWriter->bFirstRowidInDoclist = 0;
    +     pWriter->bFirstRowidInPage = 0;
    +-
    +-    fts5BufferAppendVarint(&p->rc, &pPage->buf, nPos);
    +   }
    + }
    + 
    +@@ -175819,7 +198316,9 @@ static void fts5WriteFinish(
    +       fts5WriteFlushLeaf(p, pWriter);
    +     }
    +     *pnLeaf = pLeaf->pgno-1;
    +-    fts5WriteFlushBtree(p, pWriter);
    ++    if( pLeaf->pgno>1 ){
    ++      fts5WriteFlushBtree(p, pWriter);
    ++    }
    +   }
    +   fts5BufferFree(&pLeaf->term);
    +   fts5BufferFree(&pLeaf->buf);
    +@@ -175847,9 +198346,12 @@ static void fts5WriteInit(
    +   pWriter->bFirstTermInPage = 1;
    +   pWriter->iBtPage = 1;
    + 
    ++  assert( pWriter->writer.buf.n==0 );
    ++  assert( pWriter->writer.pgidx.n==0 );
    ++
    +   /* Grow the two buffers to pgsz + padding bytes in size. */
    +-  fts5BufferGrow(&p->rc, &pWriter->writer.pgidx, nBuffer);
    +-  fts5BufferGrow(&p->rc, &pWriter->writer.buf, nBuffer);
    ++  sqlite3Fts5BufferSize(&p->rc, &pWriter->writer.pgidx, nBuffer);
    ++  sqlite3Fts5BufferSize(&p->rc, &pWriter->writer.buf, nBuffer);
    + 
    +   if( p->pIdxWriter==0 ){
    +     Fts5Config *pConfig = p->pConfig;
    +@@ -175876,7 +198378,7 @@ static void fts5WriteInit(
    + ** incremental merge operation. This function is called if the incremental
    + ** merge step has finished but the input has not been completely exhausted.
    + */
    +-static void fts5TrimSegments(Fts5Index *p, Fts5IndexIter *pIter){
    ++static void fts5TrimSegments(Fts5Index *p, Fts5Iter *pIter){
    +   int i;
    +   Fts5Buffer buf;
    +   memset(&buf, 0, sizeof(Fts5Buffer));
    +@@ -175908,7 +198410,7 @@ static void fts5TrimSegments(Fts5Index *p, Fts5IndexIter *pIter){
    +         fts5BufferAppendBlob(&p->rc, &buf, pData->szLeaf-iOff, &pData->p[iOff]);
    +         if( p->rc==SQLITE_OK ){
    +           /* Set the szLeaf field */
    +-          fts5PutU16(&buf.p[2], buf.n);
    ++          fts5PutU16(&buf.p[2], (u16)buf.n);
    +         }
    + 
    +         /* Set up the new page-index array */
    +@@ -175954,13 +198456,16 @@ static void fts5IndexMergeLevel(
    +   Fts5Structure *pStruct = *ppStruct;
    +   Fts5StructureLevel *pLvl = &pStruct->aLevel[iLvl];
    +   Fts5StructureLevel *pLvlOut;
    +-  Fts5IndexIter *pIter = 0;       /* Iterator to read input data */
    ++  Fts5Iter *pIter = 0;       /* Iterator to read input data */
    +   int nRem = pnRem ? *pnRem : 0;  /* Output leaf pages left to write */
    +   int nInput;                     /* Number of input segments */
    +   Fts5SegWriter writer;           /* Writer object */
    +   Fts5StructureSegment *pSeg;     /* Output segment */
    +   Fts5Buffer term;
    +   int bOldest;                    /* True if the output segment is the oldest */
    ++  int eDetail = p->pConfig->eDetail;
    ++  const int flags = FTS5INDEX_QUERY_NOOUTPUT;
    ++  int bTermWritten = 0;           /* True if current term already output */
    + 
    +   assert( iLvl<pStruct->nLevel );
    +   assert( pLvl->nMerge<=pLvl->nSeg );
    +@@ -176005,7 +198510,7 @@ static void fts5IndexMergeLevel(
    +   bOldest = (pLvlOut->nSeg==1 && pStruct->nLevel==iLvl+2);
    + 
    +   assert( iLvl>=0 );
    +-  for(fts5MultiIterNew(p, pStruct, 0, 0, 0, 0, iLvl, nInput, &pIter);
    ++  for(fts5MultiIterNew(p, pStruct, flags, 0, 0, 0, iLvl, nInput, &pIter);
    +       fts5MultiIterEof(p, pIter)==0;
    +       fts5MultiIterNext(p, pIter, 0, 0)
    +   ){
    +@@ -176014,27 +198519,41 @@ static void fts5IndexMergeLevel(
    +     int nTerm;
    +     const u8 *pTerm;
    + 
    +-    /* Check for key annihilation. */
    +-    if( pSegIter->nPos==0 && (bOldest || pSegIter->bDel==0) ) continue;
    +-
    +     pTerm = fts5MultiIterTerm(pIter, &nTerm);
    +     if( nTerm!=term.n || memcmp(pTerm, term.p, nTerm) ){
    +       if( pnRem && writer.nLeafWritten>nRem ){
    +         break;
    +       }
    ++      fts5BufferSet(&p->rc, &term, nTerm, pTerm);
    ++      bTermWritten =0;
    ++    }
    ++
    ++    /* Check for key annihilation. */
    ++    if( pSegIter->nPos==0 && (bOldest || pSegIter->bDel==0) ) continue;
    + 
    ++    if( p->rc==SQLITE_OK && bTermWritten==0 ){
    +       /* This is a new term. Append a term to the output segment. */
    +       fts5WriteAppendTerm(p, &writer, nTerm, pTerm);
    +-      fts5BufferSet(&p->rc, &term, nTerm, pTerm);
    ++      bTermWritten = 1;
    +     }
    + 
    +     /* Append the rowid to the output */
    +     /* WRITEPOSLISTSIZE */
    +-    nPos = pSegIter->nPos*2 + pSegIter->bDel;
    +-    fts5WriteAppendRowid(p, &writer, fts5MultiIterRowid(pIter), nPos);
    ++    fts5WriteAppendRowid(p, &writer, fts5MultiIterRowid(pIter));
    + 
    +-    /* Append the position-list data to the output */
    +-    fts5ChunkIterate(p, pSegIter, (void*)&writer, fts5MergeChunkCallback);
    ++    if( eDetail==FTS5_DETAIL_NONE ){
    ++      if( pSegIter->bDel ){
    ++        fts5BufferAppendVarint(&p->rc, &writer.writer.buf, 0);
    ++        if( pSegIter->nPos>0 ){
    ++          fts5BufferAppendVarint(&p->rc, &writer.writer.buf, 0);
    ++        }
    ++      }
    ++    }else{
    ++      /* Append the position-list data to the output */
    ++      nPos = pSegIter->nPos*2 + pSegIter->bDel;
    ++      fts5BufferAppendVarint(&p->rc, &writer.writer.buf, nPos);
    ++      fts5ChunkIterate(p, pSegIter, (void*)&writer, fts5MergeChunkCallback);
    ++    }
    +   }
    + 
    +   /* Flush the last leaf page to disk. Set the output segment b-tree height
    +@@ -176067,20 +198586,24 @@ static void fts5IndexMergeLevel(
    +     pLvl->nMerge = nInput;
    +   }
    + 
    +-  fts5MultiIterFree(p, pIter);
    ++  fts5MultiIterFree(pIter);
    +   fts5BufferFree(&term);
    +   if( pnRem ) *pnRem -= writer.nLeafWritten;
    + }
    + 
    + /*
    + ** Do up to nPg pages of automerge work on the index.
    ++**
    ++** Return true if any changes were actually made, or false otherwise.
    + */
    +-static void fts5IndexMerge(
    ++static int fts5IndexMerge(
    +   Fts5Index *p,                   /* FTS5 backend object */
    +   Fts5Structure **ppStruct,       /* IN/OUT: Current structure of index */
    +-  int nPg                         /* Pages of work to do */
    ++  int nPg,                        /* Pages of work to do */
    ++  int nMin                        /* Minimum number of segments to merge */
    + ){
    +   int nRem = nPg;
    ++  int bRet = 0;
    +   Fts5Structure *pStruct = *ppStruct;
    +   while( nRem>0 && p->rc==SQLITE_OK ){
    +     int iLvl;                   /* To iterate through levels */
    +@@ -176111,17 +198634,17 @@ static void fts5IndexMerge(
    +     }
    + #endif
    + 
    +-    if( nBest<p->pConfig->nAutomerge 
    +-        && pStruct->aLevel[iBestLvl].nMerge==0 
    +-      ){
    ++    if( nBest<nMin && pStruct->aLevel[iBestLvl].nMerge==0 ){
    +       break;
    +     }
    ++    bRet = 1;
    +     fts5IndexMergeLevel(p, &pStruct, iBestLvl, &nRem);
    +     if( p->rc==SQLITE_OK && pStruct->aLevel[iBestLvl].nMerge==0 ){
    +       fts5StructurePromote(p, iBestLvl+1, pStruct);
    +     }
    +   }
    +   *ppStruct = pStruct;
    ++  return bRet;
    + }
    + 
    + /*
    +@@ -176149,7 +198672,7 @@ static void fts5IndexAutomerge(
    +     pStruct->nWriteCounter += nLeaf;
    +     nRem = (int)(p->nWorkUnit * nWork * pStruct->nLevel);
    + 
    +-    fts5IndexMerge(p, ppStruct, nRem);
    ++    fts5IndexMerge(p, ppStruct, nRem, p->pConfig->nAutomerge);
    +   }
    + }
    + 
    +@@ -176202,17 +198725,6 @@ static int fts5PoslistPrefix(const u8 *aBuf, int nMax){
    +   return ret;
    + }
    + 
    +-#define fts5BufferSafeAppendBlob(pBuf, pBlob, nBlob) {     \
    +-  assert( (pBuf)->nSpace>=((pBuf)->n+nBlob) );             \
    +-  memcpy(&(pBuf)->p[(pBuf)->n], pBlob, nBlob);             \
    +-  (pBuf)->n += nBlob;                                      \
    +-}
    +-
    +-#define fts5BufferSafeAppendVarint(pBuf, iVal) {                \
    +-  (pBuf)->n += sqlite3Fts5PutVarint(&(pBuf)->p[(pBuf)->n], (iVal));  \
    +-  assert( (pBuf)->nSpace>=(pBuf)->n );                          \
    +-}
    +-
    + /*
    + ** Flush the contents of in-memory hash table iHash to a new level-0 
    + ** segment on disk. Also update the corresponding structure record.
    +@@ -176230,10 +198742,11 @@ static void fts5FlushOneHash(Fts5Index *p){
    +   ** for the new level-0 segment.  */
    +   pStruct = fts5StructureRead(p);
    +   iSegid = fts5AllocateSegid(p, pStruct);
    ++  fts5StructureInvalidate(p);
    + 
    +   if( iSegid ){
    +     const int pgsz = p->pConfig->pgsz;
    +-
    ++    int eDetail = p->pConfig->eDetail;
    +     Fts5StructureSegment *pSeg;   /* New segment within pStruct */
    +     Fts5Buffer *pBuf;             /* Buffer in which to assemble leaf page */
    +     Fts5Buffer *pPgidx;           /* Buffer in which to assemble pgidx */
    +@@ -176261,7 +198774,7 @@ static void fts5FlushOneHash(Fts5Index *p){
    + 
    +       /* Write the term for this entry to disk. */
    +       sqlite3Fts5HashScanEntry(pHash, &zTerm, &pDoclist, &nDoclist);
    +-      fts5WriteAppendTerm(p, &writer, strlen(zTerm), (const u8*)zTerm);
    ++      fts5WriteAppendTerm(p, &writer, (int)strlen(zTerm), (const u8*)zTerm);
    + 
    +       assert( writer.bFirstRowidInPage==0 );
    +       if( pgsz>=(pBuf->n + pPgidx->n + nDoclist + 1) ){
    +@@ -176276,16 +198789,11 @@ static void fts5FlushOneHash(Fts5Index *p){
    +         ** loop iterates through the poslists that make up the current 
    +         ** doclist.  */
    +         while( p->rc==SQLITE_OK && iOff<nDoclist ){
    +-          int nPos;
    +-          int nCopy;
    +-          int bDummy;
    +           iOff += fts5GetVarint(&pDoclist[iOff], (u64*)&iDelta);
    +-          nCopy = fts5GetPoslistSize(&pDoclist[iOff], &nPos, &bDummy);
    +-          nCopy += nPos;
    +           iRowid += iDelta;
    +           
    +           if( writer.bFirstRowidInPage ){
    +-            fts5PutU16(&pBuf->p[0], pBuf->n);   /* first rowid on page */
    ++            fts5PutU16(&pBuf->p[0], (u16)pBuf->n);   /* first rowid on page */
    +             pBuf->n += sqlite3Fts5PutVarint(&pBuf->p[pBuf->n], iRowid);
    +             writer.bFirstRowidInPage = 0;
    +             fts5WriteDlidxAppend(p, &writer, iRowid);
    +@@ -176294,34 +198802,52 @@ static void fts5FlushOneHash(Fts5Index *p){
    +           }
    +           assert( pBuf->n<=pBuf->nSpace );
    + 
    +-          if( (pBuf->n + pPgidx->n + nCopy) <= pgsz ){
    +-            /* The entire poslist will fit on the current leaf. So copy
    +-            ** it in one go. */
    +-            fts5BufferSafeAppendBlob(pBuf, &pDoclist[iOff], nCopy);
    +-          }else{
    +-            /* The entire poslist will not fit on this leaf. So it needs
    +-            ** to be broken into sections. The only qualification being
    +-            ** that each varint must be stored contiguously.  */
    +-            const u8 *pPoslist = &pDoclist[iOff];
    +-            int iPos = 0;
    +-            while( p->rc==SQLITE_OK ){
    +-              int nSpace = pgsz - pBuf->n - pPgidx->n;
    +-              int n = 0;
    +-              if( (nCopy - iPos)<=nSpace ){
    +-                n = nCopy - iPos;
    +-              }else{
    +-                n = fts5PoslistPrefix(&pPoslist[iPos], nSpace);
    ++          if( eDetail==FTS5_DETAIL_NONE ){
    ++            if( iOff<nDoclist && pDoclist[iOff]==0 ){
    ++              pBuf->p[pBuf->n++] = 0;
    ++              iOff++;
    ++              if( iOff<nDoclist && pDoclist[iOff]==0 ){
    ++                pBuf->p[pBuf->n++] = 0;
    ++                iOff++;
    +               }
    +-              assert( n>0 );
    +-              fts5BufferSafeAppendBlob(pBuf, &pPoslist[iPos], n);
    +-              iPos += n;
    +-              if( (pBuf->n + pPgidx->n)>=pgsz ){
    +-                fts5WriteFlushLeaf(p, &writer);
    ++            }
    ++            if( (pBuf->n + pPgidx->n)>=pgsz ){
    ++              fts5WriteFlushLeaf(p, &writer);
    ++            }
    ++          }else{
    ++            int bDummy;
    ++            int nPos;
    ++            int nCopy = fts5GetPoslistSize(&pDoclist[iOff], &nPos, &bDummy);
    ++            nCopy += nPos;
    ++            if( (pBuf->n + pPgidx->n + nCopy) <= pgsz ){
    ++              /* The entire poslist will fit on the current leaf. So copy
    ++              ** it in one go. */
    ++              fts5BufferSafeAppendBlob(pBuf, &pDoclist[iOff], nCopy);
    ++            }else{
    ++              /* The entire poslist will not fit on this leaf. So it needs
    ++              ** to be broken into sections. The only qualification being
    ++              ** that each varint must be stored contiguously.  */
    ++              const u8 *pPoslist = &pDoclist[iOff];
    ++              int iPos = 0;
    ++              while( p->rc==SQLITE_OK ){
    ++                int nSpace = pgsz - pBuf->n - pPgidx->n;
    ++                int n = 0;
    ++                if( (nCopy - iPos)<=nSpace ){
    ++                  n = nCopy - iPos;
    ++                }else{
    ++                  n = fts5PoslistPrefix(&pPoslist[iPos], nSpace);
    ++                }
    ++                assert( n>0 );
    ++                fts5BufferSafeAppendBlob(pBuf, &pPoslist[iPos], n);
    ++                iPos += n;
    ++                if( (pBuf->n + pPgidx->n)>=pgsz ){
    ++                  fts5WriteFlushLeaf(p, &writer);
    ++                }
    ++                if( iPos>=nCopy ) break;
    +               }
    +-              if( iPos>=nCopy ) break;
    +             }
    ++            iOff += nCopy;
    +           }
    +-          iOff += nCopy;
    +         }
    +       }
    + 
    +@@ -176367,28 +198893,41 @@ static void fts5IndexFlush(Fts5Index *p){
    +   }
    + }
    + 
    +-
    +-static int sqlite3Fts5IndexOptimize(Fts5Index *p){
    +-  Fts5Structure *pStruct;
    ++static Fts5Structure *fts5IndexOptimizeStruct(
    ++  Fts5Index *p, 
    ++  Fts5Structure *pStruct
    ++){
    +   Fts5Structure *pNew = 0;
    +-  int nSeg = 0;
    +-
    +-  assert( p->rc==SQLITE_OK );
    +-  fts5IndexFlush(p);
    +-  pStruct = fts5StructureRead(p);
    ++  int nByte = sizeof(Fts5Structure);
    ++  int nSeg = pStruct->nSegment;
    ++  int i;
    + 
    +-  if( pStruct ){
    +-    assert( pStruct->nSegment==fts5StructureCountSegments(pStruct) );
    +-    nSeg = pStruct->nSegment;
    +-    if( nSeg>1 ){
    +-      int nByte = sizeof(Fts5Structure);
    +-      nByte += (pStruct->nLevel+1) * sizeof(Fts5StructureLevel);
    +-      pNew = (Fts5Structure*)sqlite3Fts5MallocZero(&p->rc, nByte);
    ++  /* Figure out if this structure requires optimization. A structure does
    ++  ** not require optimization if either:
    ++  **
    ++  **  + it consists of fewer than two segments, or 
    ++  **  + all segments are on the same level, or
    ++  **  + all segments except one are currently inputs to a merge operation.
    ++  **
    ++  ** In the first case, return NULL. In the second, increment the ref-count
    ++  ** on *pStruct and return a copy of the pointer to it.
    ++  */
    ++  if( nSeg<2 ) return 0;
    ++  for(i=0; i<pStruct->nLevel; i++){
    ++    int nThis = pStruct->aLevel[i].nSeg;
    ++    if( nThis==nSeg || (nThis==nSeg-1 && pStruct->aLevel[i].nMerge==nThis) ){
    ++      fts5StructureRef(pStruct);
    ++      return pStruct;
    +     }
    ++    assert( pStruct->aLevel[i].nMerge<=nThis );
    +   }
    ++
    ++  nByte += (pStruct->nLevel+1) * sizeof(Fts5StructureLevel);
    ++  pNew = (Fts5Structure*)sqlite3Fts5MallocZero(&p->rc, nByte);
    ++
    +   if( pNew ){
    +     Fts5StructureLevel *pLvl;
    +-    int nByte = nSeg * sizeof(Fts5StructureSegment);
    ++    nByte = nSeg * sizeof(Fts5StructureSegment);
    +     pNew->nLevel = pStruct->nLevel+1;
    +     pNew->nRef = 1;
    +     pNew->nWriteCounter = pStruct->nWriteCounter;
    +@@ -176397,7 +198936,10 @@ static int sqlite3Fts5IndexOptimize(Fts5Index *p){
    +     if( pLvl->aSeg ){
    +       int iLvl, iSeg;
    +       int iSegOut = 0;
    +-      for(iLvl=0; iLvl<pStruct->nLevel; iLvl++){
    ++      /* Iterate through all segments, from oldest to newest. Add them to
    ++      ** the new Fts5Level object so that pLvl->aSeg[0] is the oldest
    ++      ** segment in the data structure.  */
    ++      for(iLvl=pStruct->nLevel-1; iLvl>=0; iLvl--){
    +         for(iSeg=0; iSeg<pStruct->aLevel[iLvl].nSeg; iSeg++){
    +           pLvl->aSeg[iSegOut] = pStruct->aLevel[iLvl].aSeg[iSeg];
    +           iSegOut++;
    +@@ -176410,8 +198952,27 @@ static int sqlite3Fts5IndexOptimize(Fts5Index *p){
    +     }
    +   }
    + 
    ++  return pNew;
    ++}
    ++
    ++static int sqlite3Fts5IndexOptimize(Fts5Index *p){
    ++  Fts5Structure *pStruct;
    ++  Fts5Structure *pNew = 0;
    ++
    ++  assert( p->rc==SQLITE_OK );
    ++  fts5IndexFlush(p);
    ++  pStruct = fts5StructureRead(p);
    ++  fts5StructureInvalidate(p);
    ++
    ++  if( pStruct ){
    ++    pNew = fts5IndexOptimizeStruct(p, pStruct);
    ++  }
    ++  fts5StructureRelease(pStruct);
    ++
    ++  assert( pNew==0 || pNew->nSegment>0 );
    +   if( pNew ){
    +-    int iLvl = pNew->nLevel-1;
    ++    int iLvl;
    ++    for(iLvl=0; pNew->aLevel[iLvl].nSeg==0; iLvl++){}
    +     while( p->rc==SQLITE_OK && pNew->aLevel[iLvl].nSeg>0 ){
    +       int nRem = FTS5_OPT_WORK_UNIT;
    +       fts5IndexMergeLevel(p, &pNew, iLvl, &nRem);
    +@@ -176421,240 +198982,61 @@ static int sqlite3Fts5IndexOptimize(Fts5Index *p){
    +     fts5StructureRelease(pNew);
    +   }
    + 
    +-  fts5StructureRelease(pStruct);
    +   return fts5IndexReturn(p); 
    + }
    + 
    +-static int sqlite3Fts5IndexMerge(Fts5Index *p, int nMerge){
    +-  Fts5Structure *pStruct;
    +-
    +-  pStruct = fts5StructureRead(p);
    +-  if( pStruct && pStruct->nLevel ){
    +-    fts5IndexMerge(p, &pStruct, nMerge);
    +-    fts5StructureWrite(p, pStruct);
    +-  }
    +-  fts5StructureRelease(pStruct);
    +-
    +-  return fts5IndexReturn(p);
    +-}
    +-
    +-static void fts5PoslistCallback(
    +-  Fts5Index *p, 
    +-  void *pContext, 
    +-  const u8 *pChunk, int nChunk
    +-){
    +-  assert_nc( nChunk>=0 );
    +-  if( nChunk>0 ){
    +-    fts5BufferSafeAppendBlob((Fts5Buffer*)pContext, pChunk, nChunk);
    +-  }
    +-}
    +-
    +-typedef struct PoslistCallbackCtx PoslistCallbackCtx;
    +-struct PoslistCallbackCtx {
    +-  Fts5Buffer *pBuf;               /* Append to this buffer */
    +-  Fts5Colset *pColset;            /* Restrict matches to this column */
    +-  int eState;                     /* See above */
    +-};
    +-
    + /*
    +-** TODO: Make this more efficient!
    ++** This is called to implement the special "VALUES('merge', $nMerge)"
    ++** INSERT command.
    + */
    +-static int fts5IndexColsetTest(Fts5Colset *pColset, int iCol){
    +-  int i;
    +-  for(i=0; i<pColset->nCol; i++){
    +-    if( pColset->aiCol[i]==iCol ) return 1;
    +-  }
    +-  return 0;
    +-}
    +-
    +-static void fts5PoslistFilterCallback(
    +-  Fts5Index *p, 
    +-  void *pContext, 
    +-  const u8 *pChunk, int nChunk
    +-){
    +-  PoslistCallbackCtx *pCtx = (PoslistCallbackCtx*)pContext;
    +-  assert_nc( nChunk>=0 );
    +-  if( nChunk>0 ){
    +-    /* Search through to find the first varint with value 1. This is the
    +-    ** start of the next columns hits. */
    +-    int i = 0;
    +-    int iStart = 0;
    +-
    +-    if( pCtx->eState==2 ){
    +-      int iCol;
    +-      fts5FastGetVarint32(pChunk, i, iCol);
    +-      if( fts5IndexColsetTest(pCtx->pColset, iCol) ){
    +-        pCtx->eState = 1;
    +-        fts5BufferSafeAppendVarint(pCtx->pBuf, 1);
    +-      }else{
    +-        pCtx->eState = 0;
    +-      }
    ++static int sqlite3Fts5IndexMerge(Fts5Index *p, int nMerge){
    ++  Fts5Structure *pStruct = fts5StructureRead(p);
    ++  if( pStruct ){
    ++    int nMin = p->pConfig->nUsermerge;
    ++    fts5StructureInvalidate(p);
    ++    if( nMerge<0 ){
    ++      Fts5Structure *pNew = fts5IndexOptimizeStruct(p, pStruct);
    ++      fts5StructureRelease(pStruct);
    ++      pStruct = pNew;
    ++      nMin = 2;
    ++      nMerge = nMerge*-1;
    +     }
    +-
    +-    do {
    +-      while( i<nChunk && pChunk[i]!=0x01 ){
    +-        while( pChunk[i] & 0x80 ) i++;
    +-        i++;
    +-      }
    +-      if( pCtx->eState ){
    +-        fts5BufferSafeAppendBlob(pCtx->pBuf, &pChunk[iStart], i-iStart);
    +-      }
    +-      if( i<nChunk ){
    +-        int iCol;
    +-        iStart = i;
    +-        i++;
    +-        if( i>=nChunk ){
    +-          pCtx->eState = 2;
    +-        }else{
    +-          fts5FastGetVarint32(pChunk, i, iCol);
    +-          pCtx->eState = fts5IndexColsetTest(pCtx->pColset, iCol);
    +-          if( pCtx->eState ){
    +-            fts5BufferSafeAppendBlob(pCtx->pBuf, &pChunk[iStart], i-iStart);
    +-            iStart = i;
    +-          }
    +-        }
    ++    if( pStruct && pStruct->nLevel ){
    ++      if( fts5IndexMerge(p, &pStruct, nMerge, nMin) ){
    ++        fts5StructureWrite(p, pStruct);
    +       }
    +-    }while( i<nChunk );
    ++    }
    ++    fts5StructureRelease(pStruct);
    +   }
    ++  return fts5IndexReturn(p);
    + }
    + 
    +-/*
    +-** Iterator pIter currently points to a valid entry (not EOF). This
    +-** function appends the position list data for the current entry to
    +-** buffer pBuf. It does not make a copy of the position-list size
    +-** field.
    +-*/
    +-static void fts5SegiterPoslist(
    ++static void fts5AppendRowid(
    +   Fts5Index *p,
    +-  Fts5SegIter *pSeg,
    +-  Fts5Colset *pColset,
    ++  i64 iDelta,
    ++  Fts5Iter *pUnused,
    +   Fts5Buffer *pBuf
    + ){
    +-  if( 0==fts5BufferGrow(&p->rc, pBuf, pSeg->nPos) ){
    +-    if( pColset==0 ){
    +-      fts5ChunkIterate(p, pSeg, (void*)pBuf, fts5PoslistCallback);
    +-    }else{
    +-      PoslistCallbackCtx sCtx;
    +-      sCtx.pBuf = pBuf;
    +-      sCtx.pColset = pColset;
    +-      sCtx.eState = pColset ? fts5IndexColsetTest(pColset, 0) : 1;
    +-      assert( sCtx.eState==0 || sCtx.eState==1 );
    +-      fts5ChunkIterate(p, pSeg, (void*)&sCtx, fts5PoslistFilterCallback);
    +-    }
    +-  }
    ++  UNUSED_PARAM(pUnused);
    ++  fts5BufferAppendVarint(&p->rc, pBuf, iDelta);
    + }
    + 
    +-/*
    +-** IN/OUT parameter (*pa) points to a position list n bytes in size. If
    +-** the position list contains entries for column iCol, then (*pa) is set
    +-** to point to the sub-position-list for that column and the number of
    +-** bytes in it returned. Or, if the argument position list does not
    +-** contain any entries for column iCol, return 0.
    +-*/
    +-static int fts5IndexExtractCol(
    +-  const u8 **pa,                  /* IN/OUT: Pointer to poslist */
    +-  int n,                          /* IN: Size of poslist in bytes */
    +-  int iCol                        /* Column to extract from poslist */
    +-){
    +-  int iCurrent = 0;               /* Anything before the first 0x01 is col 0 */
    +-  const u8 *p = *pa;
    +-  const u8 *pEnd = &p[n];         /* One byte past end of position list */
    +-  u8 prev = 0;
    +-
    +-  while( iCol!=iCurrent ){
    +-    /* Advance pointer p until it points to pEnd or an 0x01 byte that is
    +-    ** not part of a varint */
    +-    while( (prev & 0x80) || *p!=0x01 ){
    +-      prev = *p++;
    +-      if( p==pEnd ) return 0;
    +-    }
    +-    *pa = p++;
    +-    p += fts5GetVarint32(p, iCurrent);
    +-  }
    +-
    +-  /* Advance pointer p until it points to pEnd or an 0x01 byte that is
    +-  ** not part of a varint */
    +-  assert( (prev & 0x80)==0 );
    +-  while( p<pEnd && ((prev & 0x80) || *p!=0x01) ){
    +-    prev = *p++;
    +-  }
    +-  return p - (*pa);
    +-}
    +-
    +-
    +-/*
    +-** Iterator pMulti currently points to a valid entry (not EOF). This
    +-** function appends the following to buffer pBuf:
    +-**
    +-**   * The varint iDelta, and
    +-**   * the position list that currently points to, including the size field.
    +-**
    +-** If argument pColset is NULL, then the position list is filtered according
    +-** to pColset before being appended to the buffer. If this means there are
    +-** no entries in the position list, nothing is appended to the buffer (not
    +-** even iDelta).
    +-**
    +-** If an error occurs, an error code is left in p->rc. 
    +-*/
    +-static int fts5AppendPoslist(
    ++static void fts5AppendPoslist(
    +   Fts5Index *p,
    +   i64 iDelta,
    +-  Fts5IndexIter *pMulti,
    +-  Fts5Colset *pColset,
    ++  Fts5Iter *pMulti,
    +   Fts5Buffer *pBuf
    + ){
    +-  if( p->rc==SQLITE_OK ){
    +-    Fts5SegIter *pSeg = &pMulti->aSeg[ pMulti->aFirst[1].iFirst ];
    +-    assert( fts5MultiIterEof(p, pMulti)==0 );
    +-    assert( pSeg->nPos>0 );
    +-    if( 0==fts5BufferGrow(&p->rc, pBuf, pSeg->nPos+9+9) ){
    +-      int iSv1;
    +-      int iSv2;
    +-      int iData;
    +-
    +-      /* Append iDelta */
    +-      iSv1 = pBuf->n;
    +-      fts5BufferSafeAppendVarint(pBuf, iDelta);
    +-
    +-      /* WRITEPOSLISTSIZE */
    +-      iSv2 = pBuf->n;
    +-      fts5BufferSafeAppendVarint(pBuf, pSeg->nPos*2);
    +-      iData = pBuf->n;
    +-
    +-      if( pSeg->iLeafOffset+pSeg->nPos<=pSeg->pLeaf->szLeaf 
    +-       && (pColset==0 || pColset->nCol==1)
    +-      ){
    +-        const u8 *pPos = &pSeg->pLeaf->p[pSeg->iLeafOffset];
    +-        int nPos;
    +-        if( pColset ){
    +-          nPos = fts5IndexExtractCol(&pPos, pSeg->nPos, pColset->aiCol[0]);
    +-        }else{
    +-          nPos = pSeg->nPos;
    +-        }
    +-        fts5BufferSafeAppendBlob(pBuf, pPos, nPos);
    +-      }else{
    +-        fts5SegiterPoslist(p, pSeg, pColset, pBuf);
    +-      }
    +-
    +-      if( pColset ){
    +-        int nActual = pBuf->n - iData;
    +-        if( nActual!=pSeg->nPos ){
    +-          if( nActual==0 ){
    +-            pBuf->n = iSv1;
    +-            return 1;
    +-          }else{
    +-            int nReq = sqlite3Fts5GetVarintLen((u32)(nActual*2));
    +-            while( iSv2<(iData-nReq) ){ pBuf->p[iSv2++] = 0x80; }
    +-            sqlite3Fts5PutVarint(&pBuf->p[iSv2], nActual*2);
    +-          }
    +-        }
    +-      }
    +-    }
    ++  int nData = pMulti->base.nData;
    ++  assert( nData>0 );
    ++  if( p->rc==SQLITE_OK && 0==fts5BufferGrow(&p->rc, pBuf, nData+9+9) ){
    ++    fts5BufferSafeAppendVarint(pBuf, iDelta);
    ++    fts5BufferSafeAppendVarint(pBuf, nData*2);
    ++    fts5BufferSafeAppendBlob(pBuf, pMulti->base.pData, nData);
    +   }
    +-
    +-  return 0;
    + }
    + 
    ++
    + static void fts5DoclistIterNext(Fts5DoclistIter *pIter){
    +   u8 *p = pIter->aPoslist + pIter->nSize + pIter->nPoslist;
    + 
    +@@ -176715,6 +199097,69 @@ static void fts5MergeAppendDocid(
    +   (iLastRowid) = (iRowid);                                     \
    + }
    + 
    ++/*
    ++** Swap the contents of buffer *p1 with that of *p2.
    ++*/
    ++static void fts5BufferSwap(Fts5Buffer *p1, Fts5Buffer *p2){
    ++  Fts5Buffer tmp = *p1;
    ++  *p1 = *p2;
    ++  *p2 = tmp;
    ++}
    ++
    ++static void fts5NextRowid(Fts5Buffer *pBuf, int *piOff, i64 *piRowid){
    ++  int i = *piOff;
    ++  if( i>=pBuf->n ){
    ++    *piOff = -1;
    ++  }else{
    ++    u64 iVal;
    ++    *piOff = i + sqlite3Fts5GetVarint(&pBuf->p[i], &iVal);
    ++    *piRowid += iVal;
    ++  }
    ++}
    ++
    ++/*
    ++** This is the equivalent of fts5MergePrefixLists() for detail=none mode.
    ++** In this case the buffers consist of a delta-encoded list of rowids only.
    ++*/
    ++static void fts5MergeRowidLists(
    ++  Fts5Index *p,                   /* FTS5 backend object */
    ++  Fts5Buffer *p1,                 /* First list to merge */
    ++  Fts5Buffer *p2                  /* Second list to merge */
    ++){
    ++  int i1 = 0;
    ++  int i2 = 0;
    ++  i64 iRowid1 = 0;
    ++  i64 iRowid2 = 0;
    ++  i64 iOut = 0;
    ++
    ++  Fts5Buffer out;
    ++  memset(&out, 0, sizeof(out));
    ++  sqlite3Fts5BufferSize(&p->rc, &out, p1->n + p2->n);
    ++  if( p->rc ) return;
    ++
    ++  fts5NextRowid(p1, &i1, &iRowid1);
    ++  fts5NextRowid(p2, &i2, &iRowid2);
    ++  while( i1>=0 || i2>=0 ){
    ++    if( i1>=0 && (i2<0 || iRowid1<iRowid2) ){
    ++      assert( iOut==0 || iRowid1>iOut );
    ++      fts5BufferSafeAppendVarint(&out, iRowid1 - iOut);
    ++      iOut = iRowid1;
    ++      fts5NextRowid(p1, &i1, &iRowid1);
    ++    }else{
    ++      assert( iOut==0 || iRowid2>iOut );
    ++      fts5BufferSafeAppendVarint(&out, iRowid2 - iOut);
    ++      iOut = iRowid2;
    ++      if( i1>=0 && iRowid1==iRowid2 ){
    ++        fts5NextRowid(p1, &i1, &iRowid1);
    ++      }
    ++      fts5NextRowid(p2, &i2, &iRowid2);
    ++    }
    ++  }
    ++
    ++  fts5BufferSwap(&out, p1);
    ++  fts5BufferFree(&out);
    ++}
    ++
    + /*
    + ** Buffers p1 and p2 contain doclists. This function merges the content
    + ** of the two doclists together and sets buffer p1 to the result before
    +@@ -176732,28 +199177,36 @@ static void fts5MergePrefixLists(
    +     i64 iLastRowid = 0;
    +     Fts5DoclistIter i1;
    +     Fts5DoclistIter i2;
    +-    Fts5Buffer out;
    +-    Fts5Buffer tmp;
    +-    memset(&out, 0, sizeof(out));
    +-    memset(&tmp, 0, sizeof(tmp));
    +-
    +-    sqlite3Fts5BufferGrow(&p->rc, &out, p1->n + p2->n);
    ++    Fts5Buffer out = {0, 0, 0};
    ++    Fts5Buffer tmp = {0, 0, 0};
    ++
    ++    /* The maximum size of the output is equal to the sum of the two 
    ++    ** input sizes + 1 varint (9 bytes). The extra varint is because if the
    ++    ** first rowid in one input is a large negative number, and the first in
    ++    ** the other a non-negative number, the delta for the non-negative
    ++    ** number will be larger on disk than the literal integer value
    ++    ** was.  */
    ++    if( sqlite3Fts5BufferSize(&p->rc, &out, p1->n + p2->n + 9) ) return;
    +     fts5DoclistIterInit(p1, &i1);
    +     fts5DoclistIterInit(p2, &i2);
    +-    while( p->rc==SQLITE_OK && (i1.aPoslist!=0 || i2.aPoslist!=0) ){
    +-      if( i2.aPoslist==0 || (i1.aPoslist && i1.iRowid<i2.iRowid) ){
    ++
    ++    while( 1 ){
    ++      if( i1.iRowid<i2.iRowid ){
    +         /* Copy entry from i1 */
    +         fts5MergeAppendDocid(&out, iLastRowid, i1.iRowid);
    +         fts5BufferSafeAppendBlob(&out, i1.aPoslist, i1.nPoslist+i1.nSize);
    +         fts5DoclistIterNext(&i1);
    ++        if( i1.aPoslist==0 ) break;
    +       }
    +-      else if( i1.aPoslist==0 || i2.iRowid!=i1.iRowid ){
    ++      else if( i2.iRowid!=i1.iRowid ){
    +         /* Copy entry from i2 */
    +         fts5MergeAppendDocid(&out, iLastRowid, i2.iRowid);
    +         fts5BufferSafeAppendBlob(&out, i2.aPoslist, i2.nPoslist+i2.nSize);
    +         fts5DoclistIterNext(&i2);
    ++        if( i2.aPoslist==0 ) break;
    +       }
    +       else{
    ++        /* Merge the two position lists. */ 
    +         i64 iPos1 = 0;
    +         i64 iPos2 = 0;
    +         int iOff1 = 0;
    +@@ -176761,29 +199214,53 @@ static void fts5MergePrefixLists(
    +         u8 *a1 = &i1.aPoslist[i1.nSize];
    +         u8 *a2 = &i2.aPoslist[i2.nSize];
    + 
    ++        i64 iPrev = 0;
    +         Fts5PoslistWriter writer;
    +         memset(&writer, 0, sizeof(writer));
    + 
    +-        /* Merge the two position lists. */ 
    +         fts5MergeAppendDocid(&out, iLastRowid, i2.iRowid);
    +         fts5BufferZero(&tmp);
    ++        sqlite3Fts5BufferSize(&p->rc, &tmp, i1.nPoslist + i2.nPoslist);
    ++        if( p->rc ) break;
    + 
    +         sqlite3Fts5PoslistNext64(a1, i1.nPoslist, &iOff1, &iPos1);
    +         sqlite3Fts5PoslistNext64(a2, i2.nPoslist, &iOff2, &iPos2);
    ++        assert( iPos1>=0 && iPos2>=0 );
    + 
    +-        while( p->rc==SQLITE_OK && (iPos1>=0 || iPos2>=0) ){
    +-          i64 iNew;
    +-          if( iPos2<0 || (iPos1>=0 && iPos1<iPos2) ){
    +-            iNew = iPos1;
    +-            sqlite3Fts5PoslistNext64(a1, i1.nPoslist, &iOff1, &iPos1);
    +-          }else{
    +-            iNew = iPos2;
    +-            sqlite3Fts5PoslistNext64(a2, i2.nPoslist, &iOff2, &iPos2);
    +-            if( iPos1==iPos2 ){
    +-              sqlite3Fts5PoslistNext64(a1, i1.nPoslist, &iOff1,&iPos1);
    ++        if( iPos1<iPos2 ){
    ++          sqlite3Fts5PoslistSafeAppend(&tmp, &iPrev, iPos1);
    ++          sqlite3Fts5PoslistNext64(a1, i1.nPoslist, &iOff1, &iPos1);
    ++        }else{
    ++          sqlite3Fts5PoslistSafeAppend(&tmp, &iPrev, iPos2);
    ++          sqlite3Fts5PoslistNext64(a2, i2.nPoslist, &iOff2, &iPos2);
    ++        }
    ++
    ++        if( iPos1>=0 && iPos2>=0 ){
    ++          while( 1 ){
    ++            if( iPos1<iPos2 ){
    ++              if( iPos1!=iPrev ){
    ++                sqlite3Fts5PoslistSafeAppend(&tmp, &iPrev, iPos1);
    ++              }
    ++              sqlite3Fts5PoslistNext64(a1, i1.nPoslist, &iOff1, &iPos1);
    ++              if( iPos1<0 ) break;
    ++            }else{
    ++              assert( iPos2!=iPrev );
    ++              sqlite3Fts5PoslistSafeAppend(&tmp, &iPrev, iPos2);
    ++              sqlite3Fts5PoslistNext64(a2, i2.nPoslist, &iOff2, &iPos2);
    ++              if( iPos2<0 ) break;
    +             }
    +           }
    +-          p->rc = sqlite3Fts5PoslistWriterAppend(&tmp, &writer, iNew);
    ++        }
    ++
    ++        if( iPos1>=0 ){
    ++          if( iPos1!=iPrev ){
    ++            sqlite3Fts5PoslistSafeAppend(&tmp, &iPrev, iPos1);
    ++          }
    ++          fts5BufferSafeAppendBlob(&tmp, &a1[iOff1], i1.nPoslist-iOff1);
    ++        }else{
    ++          assert( iPos2>=0 && iPos2!=iPrev );
    ++          sqlite3Fts5PoslistSafeAppend(&tmp, &iPrev, iPos2);
    ++          fts5BufferSafeAppendBlob(&tmp, &a2[iOff2], i2.nPoslist-iOff2);
    +         }
    + 
    +         /* WRITEPOSLISTSIZE */
    +@@ -176791,87 +199268,112 @@ static void fts5MergePrefixLists(
    +         fts5BufferSafeAppendBlob(&out, tmp.p, tmp.n);
    +         fts5DoclistIterNext(&i1);
    +         fts5DoclistIterNext(&i2);
    ++        if( i1.aPoslist==0 || i2.aPoslist==0 ) break;
    +       }
    +     }
    + 
    ++    if( i1.aPoslist ){
    ++      fts5MergeAppendDocid(&out, iLastRowid, i1.iRowid);
    ++      fts5BufferSafeAppendBlob(&out, i1.aPoslist, i1.aEof - i1.aPoslist);
    ++    }
    ++    else if( i2.aPoslist ){
    ++      fts5MergeAppendDocid(&out, iLastRowid, i2.iRowid);
    ++      fts5BufferSafeAppendBlob(&out, i2.aPoslist, i2.aEof - i2.aPoslist);
    ++    }
    ++    assert( out.n<=(p1->n+p2->n+9) );
    ++
    +     fts5BufferSet(&p->rc, p1, out.n, out.p);
    +     fts5BufferFree(&tmp);
    +     fts5BufferFree(&out);
    +   }
    + }
    + 
    +-static void fts5BufferSwap(Fts5Buffer *p1, Fts5Buffer *p2){
    +-  Fts5Buffer tmp = *p1;
    +-  *p1 = *p2;
    +-  *p2 = tmp;
    +-}
    +-
    + static void fts5SetupPrefixIter(
    +   Fts5Index *p,                   /* Index to read from */
    +   int bDesc,                      /* True for "ORDER BY rowid DESC" */
    +   const u8 *pToken,               /* Buffer containing prefix to match */
    +   int nToken,                     /* Size of buffer pToken in bytes */
    +   Fts5Colset *pColset,            /* Restrict matches to these columns */
    +-  Fts5IndexIter **ppIter          /* OUT: New iterator */
    ++  Fts5Iter **ppIter          /* OUT: New iterator */
    + ){
    +   Fts5Structure *pStruct;
    +   Fts5Buffer *aBuf;
    +   const int nBuf = 32;
    + 
    ++  void (*xMerge)(Fts5Index*, Fts5Buffer*, Fts5Buffer*);
    ++  void (*xAppend)(Fts5Index*, i64, Fts5Iter*, Fts5Buffer*);
    ++  if( p->pConfig->eDetail==FTS5_DETAIL_NONE ){
    ++    xMerge = fts5MergeRowidLists;
    ++    xAppend = fts5AppendRowid;
    ++  }else{
    ++    xMerge = fts5MergePrefixLists;
    ++    xAppend = fts5AppendPoslist;
    ++  }
    ++
    +   aBuf = (Fts5Buffer*)fts5IdxMalloc(p, sizeof(Fts5Buffer)*nBuf);
    +   pStruct = fts5StructureRead(p);
    + 
    +   if( aBuf && pStruct ){
    +-    const int flags = FTS5INDEX_QUERY_SCAN;
    ++    const int flags = FTS5INDEX_QUERY_SCAN 
    ++                    | FTS5INDEX_QUERY_SKIPEMPTY 
    ++                    | FTS5INDEX_QUERY_NOOUTPUT;
    +     int i;
    +     i64 iLastRowid = 0;
    +-    Fts5IndexIter *p1 = 0;     /* Iterator used to gather data from index */
    ++    Fts5Iter *p1 = 0;     /* Iterator used to gather data from index */
    +     Fts5Data *pData;
    +     Fts5Buffer doclist;
    ++    int bNewTerm = 1;
    + 
    +     memset(&doclist, 0, sizeof(doclist));
    +-    for(fts5MultiIterNew(p, pStruct, 1, flags, pToken, nToken, -1, 0, &p1);
    ++    fts5MultiIterNew(p, pStruct, flags, pColset, pToken, nToken, -1, 0, &p1);
    ++    fts5IterSetOutputCb(&p->rc, p1);
    ++    for( /* no-op */ ;
    +         fts5MultiIterEof(p, p1)==0;
    +-        fts5MultiIterNext(p, p1, 0, 0)
    ++        fts5MultiIterNext2(p, p1, &bNewTerm)
    +     ){
    +-      i64 iRowid = fts5MultiIterRowid(p1);
    +-      int nTerm;
    +-      const u8 *pTerm = fts5MultiIterTerm(p1, &nTerm);
    ++      Fts5SegIter *pSeg = &p1->aSeg[ p1->aFirst[1].iFirst ];
    ++      int nTerm = pSeg->term.n;
    ++      const u8 *pTerm = pSeg->term.p;
    ++      p1->xSetOutputs(p1, pSeg);
    ++
    +       assert_nc( memcmp(pToken, pTerm, MIN(nToken, nTerm))<=0 );
    +-      if( nTerm<nToken || memcmp(pToken, pTerm, nToken) ) break;
    ++      if( bNewTerm ){
    ++        if( nTerm<nToken || memcmp(pToken, pTerm, nToken) ) break;
    ++      }
    ++
    ++      if( p1->base.nData==0 ) continue;
    + 
    +-      if( doclist.n>0 && iRowid<=iLastRowid ){
    ++      if( p1->base.iRowid<=iLastRowid && doclist.n>0 ){
    +         for(i=0; p->rc==SQLITE_OK && doclist.n; i++){
    +           assert( i<nBuf );
    +           if( aBuf[i].n==0 ){
    +             fts5BufferSwap(&doclist, &aBuf[i]);
    +             fts5BufferZero(&doclist);
    +           }else{
    +-            fts5MergePrefixLists(p, &doclist, &aBuf[i]);
    ++            xMerge(p, &doclist, &aBuf[i]);
    +             fts5BufferZero(&aBuf[i]);
    +           }
    +         }
    +         iLastRowid = 0;
    +       }
    + 
    +-      if( !fts5AppendPoslist(p, iRowid-iLastRowid, p1, pColset, &doclist) ){
    +-        iLastRowid = iRowid;
    +-      }
    ++      xAppend(p, p1->base.iRowid-iLastRowid, p1, &doclist);
    ++      iLastRowid = p1->base.iRowid;
    +     }
    + 
    +     for(i=0; i<nBuf; i++){
    +       if( p->rc==SQLITE_OK ){
    +-        fts5MergePrefixLists(p, &doclist, &aBuf[i]);
    ++        xMerge(p, &doclist, &aBuf[i]);
    +       }
    +       fts5BufferFree(&aBuf[i]);
    +     }
    +-    fts5MultiIterFree(p, p1);
    ++    fts5MultiIterFree(p1);
    + 
    +     pData = fts5IdxMalloc(p, sizeof(Fts5Data) + doclist.n);
    +     if( pData ){
    +       pData->p = (u8*)&pData[1];
    +       pData->nn = pData->szLeaf = doclist.n;
    +-      memcpy(pData->p, doclist.p, doclist.n);
    ++      if( doclist.n ) memcpy(pData->p, doclist.p, doclist.n);
    +       fts5MultiIterNew2(p, pData, bDesc, ppIter);
    +     }
    +     fts5BufferFree(&doclist);
    +@@ -176891,13 +199393,13 @@ static int sqlite3Fts5IndexBeginWrite(Fts5Index *p, int bDelete, i64 iRowid){
    + 
    +   /* Allocate the hash table if it has not already been allocated */
    +   if( p->pHash==0 ){
    +-    p->rc = sqlite3Fts5HashNew(&p->pHash, &p->nPendingData);
    ++    p->rc = sqlite3Fts5HashNew(p->pConfig, &p->pHash, &p->nPendingData);
    +   }
    + 
    +   /* Flush the hash table to disk if required */
    +   if( iRowid<p->iWriteRowid 
    +    || (iRowid==p->iWriteRowid && p->bDelete==0)
    +-   || (p->nPendingData > p->nMaxPendingData) 
    ++   || (p->nPendingData > p->pConfig->nHashSize) 
    +   ){
    +     fts5IndexFlush(p);
    +   }
    +@@ -176910,10 +199412,10 @@ static int sqlite3Fts5IndexBeginWrite(Fts5Index *p, int bDelete, i64 iRowid){
    + /*
    + ** Commit data to disk.
    + */
    +-static int sqlite3Fts5IndexSync(Fts5Index *p, int bCommit){
    ++static int sqlite3Fts5IndexSync(Fts5Index *p){
    +   assert( p->rc==SQLITE_OK );
    +   fts5IndexFlush(p);
    +-  if( bCommit ) fts5CloseReader(p);
    ++  fts5CloseReader(p);
    +   return fts5IndexReturn(p);
    + }
    + 
    +@@ -176926,7 +199428,8 @@ static int sqlite3Fts5IndexSync(Fts5Index *p, int bCommit){
    + static int sqlite3Fts5IndexRollback(Fts5Index *p){
    +   fts5CloseReader(p);
    +   fts5IndexDiscardData(p);
    +-  assert( p->rc==SQLITE_OK );
    ++  fts5StructureInvalidate(p);
    ++  /* assert( p->rc==SQLITE_OK ); */
    +   return SQLITE_OK;
    + }
    + 
    +@@ -176937,6 +199440,7 @@ static int sqlite3Fts5IndexRollback(Fts5Index *p){
    + */
    + static int sqlite3Fts5IndexReinit(Fts5Index *p){
    +   Fts5Structure s;
    ++  fts5StructureInvalidate(p);
    +   memset(&s, 0, sizeof(Fts5Structure));
    +   fts5DataWrite(p, FTS5_AVERAGES_ROWID, (const u8*)"", 0);
    +   fts5StructureWrite(p, &s);
    +@@ -176963,7 +199467,6 @@ static int sqlite3Fts5IndexOpen(
    +   if( rc==SQLITE_OK ){
    +     p->pConfig = pConfig;
    +     p->nWorkUnit = FTS5_WORK_UNIT;
    +-    p->nMaxPendingData = 1024*1024;
    +     p->zDataTbl = sqlite3Fts5Mprintf(&rc, "%s_data", pConfig->zName);
    +     if( p->zDataTbl && bCreate ){
    +       rc = sqlite3Fts5CreateTable(
    +@@ -176996,11 +199499,13 @@ static int sqlite3Fts5IndexClose(Fts5Index *p){
    +   int rc = SQLITE_OK;
    +   if( p ){
    +     assert( p->pReader==0 );
    ++    fts5StructureInvalidate(p);
    +     sqlite3_finalize(p->pWriter);
    +     sqlite3_finalize(p->pDeleter);
    +     sqlite3_finalize(p->pIdxWriter);
    +     sqlite3_finalize(p->pIdxDeleter);
    +     sqlite3_finalize(p->pIdxSelect);
    ++    sqlite3_finalize(p->pDataVersion);
    +     sqlite3Fts5HashFree(p->pHash);
    +     sqlite3_free(p->zDataTbl);
    +     sqlite3_free(p);
    +@@ -177013,7 +199518,11 @@ static int sqlite3Fts5IndexClose(Fts5Index *p){
    + ** size. Return the number of bytes in the nChar character prefix of the
    + ** buffer, or 0 if there are less than nChar characters in total.
    + */
    +-static int fts5IndexCharlenToBytelen(const char *p, int nByte, int nChar){
    ++static int sqlite3Fts5IndexCharlenToBytelen(
    ++  const char *p, 
    ++  int nByte, 
    ++  int nChar
    ++){
    +   int n = 0;
    +   int i;
    +   for(i=0; i<nChar; i++){
    +@@ -177070,10 +199579,12 @@ static int sqlite3Fts5IndexWrite(
    +   );
    + 
    +   for(i=0; i<pConfig->nPrefix && rc==SQLITE_OK; i++){
    +-    int nByte = fts5IndexCharlenToBytelen(pToken, nToken, pConfig->aPrefix[i]);
    ++    const int nChar = pConfig->aPrefix[i];
    ++    int nByte = sqlite3Fts5IndexCharlenToBytelen(pToken, nToken, nChar);
    +     if( nByte ){
    +       rc = sqlite3Fts5HashWrite(p->pHash, 
    +-          p->iWriteRowid, iCol, iPos, FTS5_MAIN_PREFIX+i+1, pToken, nByte
    ++          p->iWriteRowid, iCol, iPos, (char)(FTS5_MAIN_PREFIX+i+1), pToken,
    ++          nByte
    +       );
    +     }
    +   }
    +@@ -177093,24 +199604,27 @@ static int sqlite3Fts5IndexQuery(
    +   Fts5IndexIter **ppIter          /* OUT: New iterator object */
    + ){
    +   Fts5Config *pConfig = p->pConfig;
    +-  Fts5IndexIter *pRet = 0;
    +-  int iIdx = 0;
    ++  Fts5Iter *pRet = 0;
    +   Fts5Buffer buf = {0, 0, 0};
    + 
    +   /* If the QUERY_SCAN flag is set, all other flags must be clear. */
    +-  assert( (flags & FTS5INDEX_QUERY_SCAN)==0
    +-       || (flags & FTS5INDEX_QUERY_SCAN)==FTS5INDEX_QUERY_SCAN
    +-  );
    ++  assert( (flags & FTS5INDEX_QUERY_SCAN)==0 || flags==FTS5INDEX_QUERY_SCAN );
    + 
    +-  if( sqlite3Fts5BufferGrow(&p->rc, &buf, nToken+1)==0 ){
    +-    memcpy(&buf.p[1], pToken, nToken);
    ++  if( sqlite3Fts5BufferSize(&p->rc, &buf, nToken+1)==0 ){
    ++    int iIdx = 0;                 /* Index to search */
    ++    if( nToken ) memcpy(&buf.p[1], pToken, nToken);
    + 
    +-#ifdef SQLITE_DEBUG
    +-    /* If the QUERY_TEST_NOIDX flag was specified, then this must be a
    ++    /* Figure out which index to search and set iIdx accordingly. If this
    ++    ** is a prefix query for which there is no prefix index, set iIdx to
    ++    ** greater than pConfig->nPrefix to indicate that the query will be
    ++    ** satisfied by scanning multiple terms in the main index.
    ++    **
    ++    ** If the QUERY_TEST_NOIDX flag was specified, then this must be a
    +     ** prefix-query. Instead of using a prefix-index (if one exists), 
    +     ** evaluate the prefix query using the main FTS index. This is used
    +     ** for internal sanity checking by the integrity-check in debug 
    +     ** mode only.  */
    ++#ifdef SQLITE_DEBUG
    +     if( pConfig->bPrefixIndex==0 || (flags & FTS5INDEX_QUERY_TEST_NOIDX) ){
    +       assert( flags & FTS5INDEX_QUERY_PREFIX );
    +       iIdx = 1+pConfig->nPrefix;
    +@@ -177124,24 +199638,35 @@ static int sqlite3Fts5IndexQuery(
    +     }
    + 
    +     if( iIdx<=pConfig->nPrefix ){
    ++      /* Straight index lookup */
    +       Fts5Structure *pStruct = fts5StructureRead(p);
    +-      buf.p[0] = FTS5_MAIN_PREFIX + iIdx;
    ++      buf.p[0] = (u8)(FTS5_MAIN_PREFIX + iIdx);
    +       if( pStruct ){
    +-        fts5MultiIterNew(p, pStruct, 1, flags, buf.p, nToken+1, -1, 0, &pRet);
    ++        fts5MultiIterNew(p, pStruct, flags | FTS5INDEX_QUERY_SKIPEMPTY, 
    ++            pColset, buf.p, nToken+1, -1, 0, &pRet
    ++        );
    +         fts5StructureRelease(pStruct);
    +       }
    +     }else{
    ++      /* Scan multiple terms in the main index */
    +       int bDesc = (flags & FTS5INDEX_QUERY_DESC)!=0;
    +       buf.p[0] = FTS5_MAIN_PREFIX;
    +       fts5SetupPrefixIter(p, bDesc, buf.p, nToken+1, pColset, &pRet);
    ++      assert( p->rc!=SQLITE_OK || pRet->pColset==0 );
    ++      fts5IterSetOutputCb(&p->rc, pRet);
    ++      if( p->rc==SQLITE_OK ){
    ++        Fts5SegIter *pSeg = &pRet->aSeg[pRet->aFirst[1].iFirst];
    ++        if( pSeg->pLeaf ) pRet->xSetOutputs(pRet, pSeg);
    ++      }
    +     }
    + 
    +     if( p->rc ){
    +-      sqlite3Fts5IterClose(pRet);
    ++      sqlite3Fts5IterClose((Fts5IndexIter*)pRet);
    +       pRet = 0;
    +       fts5CloseReader(p);
    +     }
    +-    *ppIter = pRet;
    ++
    ++    *ppIter = &pRet->base;
    +     sqlite3Fts5BufferFree(&buf);
    +   }
    +   return fts5IndexReturn(p);
    +@@ -177150,15 +199675,11 @@ static int sqlite3Fts5IndexQuery(
    + /*
    + ** Return true if the iterator passed as the only argument is at EOF.
    + */
    +-static int sqlite3Fts5IterEof(Fts5IndexIter *pIter){
    +-  assert( pIter->pIndex->rc==SQLITE_OK );
    +-  return pIter->bEof;
    +-}
    +-
    + /*
    + ** Move to the next matching rowid. 
    + */
    +-static int sqlite3Fts5IterNext(Fts5IndexIter *pIter){
    ++static int sqlite3Fts5IterNext(Fts5IndexIter *pIndexIter){
    ++  Fts5Iter *pIter = (Fts5Iter*)pIndexIter;
    +   assert( pIter->pIndex->rc==SQLITE_OK );
    +   fts5MultiIterNext(pIter->pIndex, pIter, 0, 0);
    +   return fts5IndexReturn(pIter->pIndex);
    +@@ -177167,7 +199688,8 @@ static int sqlite3Fts5IterNext(Fts5IndexIter *pIter){
    + /*
    + ** Move to the next matching term/rowid. Used by the fts5vocab module.
    + */
    +-static int sqlite3Fts5IterNextScan(Fts5IndexIter *pIter){
    ++static int sqlite3Fts5IterNextScan(Fts5IndexIter *pIndexIter){
    ++  Fts5Iter *pIter = (Fts5Iter*)pIndexIter;
    +   Fts5Index *p = pIter->pIndex;
    + 
    +   assert( pIter->pIndex->rc==SQLITE_OK );
    +@@ -177178,7 +199700,7 @@ static int sqlite3Fts5IterNextScan(Fts5IndexIter *pIter){
    +     if( pSeg->pLeaf && pSeg->term.p[0]!=FTS5_MAIN_PREFIX ){
    +       fts5DataRelease(pSeg->pLeaf);
    +       pSeg->pLeaf = 0;
    +-      pIter->bEof = 1;
    ++      pIter->base.bEof = 1;
    +     }
    +   }
    + 
    +@@ -177190,111 +199712,30 @@ static int sqlite3Fts5IterNextScan(Fts5IndexIter *pIter){
    + ** definition of "at or after" depends on whether this iterator iterates
    + ** in ascending or descending rowid order.
    + */
    +-static int sqlite3Fts5IterNextFrom(Fts5IndexIter *pIter, i64 iMatch){
    ++static int sqlite3Fts5IterNextFrom(Fts5IndexIter *pIndexIter, i64 iMatch){
    ++  Fts5Iter *pIter = (Fts5Iter*)pIndexIter;
    +   fts5MultiIterNextFrom(pIter->pIndex, pIter, iMatch);
    +   return fts5IndexReturn(pIter->pIndex);
    + }
    + 
    +-/*
    +-** Return the current rowid.
    +-*/
    +-static i64 sqlite3Fts5IterRowid(Fts5IndexIter *pIter){
    +-  return fts5MultiIterRowid(pIter);
    +-}
    +-
    + /*
    + ** Return the current term.
    + */
    +-static const char *sqlite3Fts5IterTerm(Fts5IndexIter *pIter, int *pn){
    ++static const char *sqlite3Fts5IterTerm(Fts5IndexIter *pIndexIter, int *pn){
    +   int n;
    +-  const char *z = (const char*)fts5MultiIterTerm(pIter, &n);
    ++  const char *z = (const char*)fts5MultiIterTerm((Fts5Iter*)pIndexIter, &n);
    +   *pn = n-1;
    +   return &z[1];
    + }
    + 
    +-
    +-static int fts5IndexExtractColset (
    +-  Fts5Colset *pColset,            /* Colset to filter on */
    +-  const u8 *pPos, int nPos,       /* Position list */
    +-  Fts5Buffer *pBuf                /* Output buffer */
    +-){
    +-  int rc = SQLITE_OK;
    +-  int i;
    +-
    +-  fts5BufferZero(pBuf);
    +-  for(i=0; i<pColset->nCol; i++){
    +-    const u8 *pSub = pPos;
    +-    int nSub = fts5IndexExtractCol(&pSub, nPos, pColset->aiCol[i]);
    +-    if( nSub ){
    +-      fts5BufferAppendBlob(&rc, pBuf, nSub, pSub);
    +-    }
    +-  }
    +-  return rc;
    +-}
    +-
    +-
    +-/*
    +-** Return a pointer to a buffer containing a copy of the position list for
    +-** the current entry. Output variable *pn is set to the size of the buffer 
    +-** in bytes before returning.
    +-**
    +-** The returned position list does not include the "number of bytes" varint
    +-** field that starts the position list on disk.
    +-*/
    +-static int sqlite3Fts5IterPoslist(
    +-  Fts5IndexIter *pIter, 
    +-  Fts5Colset *pColset,            /* Column filter (or NULL) */
    +-  const u8 **pp,                  /* OUT: Pointer to position-list data */
    +-  int *pn,                        /* OUT: Size of position-list in bytes */
    +-  i64 *piRowid                    /* OUT: Current rowid */
    +-){
    +-  Fts5SegIter *pSeg = &pIter->aSeg[ pIter->aFirst[1].iFirst ];
    +-  assert( pIter->pIndex->rc==SQLITE_OK );
    +-  *piRowid = pSeg->iRowid;
    +-  if( pSeg->iLeafOffset+pSeg->nPos<=pSeg->pLeaf->szLeaf ){
    +-    u8 *pPos = &pSeg->pLeaf->p[pSeg->iLeafOffset];
    +-    if( pColset==0 || pIter->bFiltered ){
    +-      *pn = pSeg->nPos;
    +-      *pp = pPos;
    +-    }else if( pColset->nCol==1 ){
    +-      *pp = pPos;
    +-      *pn = fts5IndexExtractCol(pp, pSeg->nPos, pColset->aiCol[0]);
    +-    }else{
    +-      fts5BufferZero(&pIter->poslist);
    +-      fts5IndexExtractColset(pColset, pPos, pSeg->nPos, &pIter->poslist);
    +-      *pp = pIter->poslist.p;
    +-      *pn = pIter->poslist.n;
    +-    }
    +-  }else{
    +-    fts5BufferZero(&pIter->poslist);
    +-    fts5SegiterPoslist(pIter->pIndex, pSeg, pColset, &pIter->poslist);
    +-    *pp = pIter->poslist.p;
    +-    *pn = pIter->poslist.n;
    +-  }
    +-  return fts5IndexReturn(pIter->pIndex);
    +-}
    +-
    +-/*
    +-** This function is similar to sqlite3Fts5IterPoslist(), except that it
    +-** copies the position list into the buffer supplied as the second 
    +-** argument.
    +-*/
    +-static int sqlite3Fts5IterPoslistBuffer(Fts5IndexIter *pIter, Fts5Buffer *pBuf){
    +-  Fts5Index *p = pIter->pIndex;
    +-  Fts5SegIter *pSeg = &pIter->aSeg[ pIter->aFirst[1].iFirst ];
    +-  assert( p->rc==SQLITE_OK );
    +-  fts5BufferZero(pBuf);
    +-  fts5SegiterPoslist(p, pSeg, 0, pBuf);
    +-  return fts5IndexReturn(p);
    +-}
    +-
    + /*
    + ** Close an iterator opened by an earlier call to sqlite3Fts5IndexQuery().
    + */
    +-static void sqlite3Fts5IterClose(Fts5IndexIter *pIter){
    +-  if( pIter ){
    ++static void sqlite3Fts5IterClose(Fts5IndexIter *pIndexIter){
    ++  if( pIndexIter ){
    ++    Fts5Iter *pIter = (Fts5Iter*)pIndexIter;
    +     Fts5Index *pIndex = pIter->pIndex;
    +-    fts5MultiIterFree(pIter->pIndex, pIter);
    ++    fts5MultiIterFree(pIter);
    +     fts5CloseReader(pIndex);
    +   }
    + }
    +@@ -177387,7 +199828,7 @@ static int sqlite3Fts5IndexLoadConfig(Fts5Index *p){
    + /*
    + ** Return a simple checksum value based on the arguments.
    + */
    +-static u64 fts5IndexEntryCksum(
    ++static u64 sqlite3Fts5IndexEntryCksum(
    +   i64 iRowid, 
    +   int iCol, 
    +   int iPos, 
    +@@ -177457,30 +199898,32 @@ static int fts5QueryCksum(
    +   int flags,                      /* Flags for Fts5IndexQuery */
    +   u64 *pCksum                     /* IN/OUT: Checksum value */
    + ){
    ++  int eDetail = p->pConfig->eDetail;
    +   u64 cksum = *pCksum;
    +-  Fts5IndexIter *pIdxIter = 0;
    +-  int rc = sqlite3Fts5IndexQuery(p, z, n, flags, 0, &pIdxIter);
    ++  Fts5IndexIter *pIter = 0;
    ++  int rc = sqlite3Fts5IndexQuery(p, z, n, flags, 0, &pIter);
    + 
    +-  while( rc==SQLITE_OK && 0==sqlite3Fts5IterEof(pIdxIter) ){
    +-    i64 dummy;
    +-    const u8 *pPos;
    +-    int nPos;
    +-    i64 rowid = sqlite3Fts5IterRowid(pIdxIter);
    +-    rc = sqlite3Fts5IterPoslist(pIdxIter, 0, &pPos, &nPos, &dummy);
    +-    if( rc==SQLITE_OK ){
    ++  while( rc==SQLITE_OK && 0==sqlite3Fts5IterEof(pIter) ){
    ++    i64 rowid = pIter->iRowid;
    ++
    ++    if( eDetail==FTS5_DETAIL_NONE ){
    ++      cksum ^= sqlite3Fts5IndexEntryCksum(rowid, 0, 0, iIdx, z, n);
    ++    }else{
    +       Fts5PoslistReader sReader;
    +-      for(sqlite3Fts5PoslistReaderInit(pPos, nPos, &sReader);
    ++      for(sqlite3Fts5PoslistReaderInit(pIter->pData, pIter->nData, &sReader);
    +           sReader.bEof==0;
    +           sqlite3Fts5PoslistReaderNext(&sReader)
    +       ){
    +         int iCol = FTS5_POS2COLUMN(sReader.iPos);
    +         int iOff = FTS5_POS2OFFSET(sReader.iPos);
    +-        cksum ^= fts5IndexEntryCksum(rowid, iCol, iOff, iIdx, z, n);
    ++        cksum ^= sqlite3Fts5IndexEntryCksum(rowid, iCol, iOff, iIdx, z, n);
    +       }
    +-      rc = sqlite3Fts5IterNext(pIdxIter);
    ++    }
    ++    if( rc==SQLITE_OK ){
    ++      rc = sqlite3Fts5IterNext(pIter);
    +     }
    +   }
    +-  sqlite3Fts5IterClose(pIdxIter);
    ++  sqlite3Fts5IterClose(pIter);
    + 
    +   *pCksum = cksum;
    +   return rc;
    +@@ -177668,7 +200111,7 @@ static void fts5IndexIntegrityCheckSegment(
    +     ** ignore this b-tree entry. Otherwise, load it into memory. */
    +     if( iIdxLeaf<pSeg->pgnoFirst ) continue;
    +     iRow = FTS5_SEGMENT_ROWID(pSeg->iSegid, iIdxLeaf);
    +-    pLeaf = fts5DataRead(p, iRow);
    ++    pLeaf = fts5LeafRead(p, iRow);
    +     if( pLeaf==0 ) break;
    + 
    +     /* Check that the leaf contains at least one term, and that it is equal
    +@@ -177699,7 +200142,6 @@ static void fts5IndexIntegrityCheckSegment(
    +     fts5DataRelease(pLeaf);
    +     if( p->rc ) break;
    + 
    +-
    +     /* Now check that the iter.nEmpty leaves following the current leaf
    +     ** (a) exist and (b) contain no terms. */
    +     fts5IndexIntegrityCheckEmpty(
    +@@ -177775,7 +200217,7 @@ static void fts5IndexIntegrityCheckSegment(
    + /*
    + ** Run internal checks to ensure that the FTS index (a) is internally 
    + ** consistent and (b) contains entries for which the XOR of the checksums
    +-** as calculated by fts5IndexEntryCksum() is cksum.
    ++** as calculated by sqlite3Fts5IndexEntryCksum() is cksum.
    + **
    + ** Return SQLITE_CORRUPT if any of the internal checks fail, or if the
    + ** checksum does not match. Return SQLITE_OK if all checks pass without
    +@@ -177783,14 +200225,18 @@ static void fts5IndexIntegrityCheckSegment(
    + ** occurs.
    + */
    + static int sqlite3Fts5IndexIntegrityCheck(Fts5Index *p, u64 cksum){
    ++  int eDetail = p->pConfig->eDetail;
    +   u64 cksum2 = 0;                 /* Checksum based on contents of indexes */
    +   Fts5Buffer poslist = {0,0,0};   /* Buffer used to hold a poslist */
    +-  Fts5IndexIter *pIter;           /* Used to iterate through entire index */
    ++  Fts5Iter *pIter;                /* Used to iterate through entire index */
    +   Fts5Structure *pStruct;         /* Index structure */
    + 
    ++#ifdef SQLITE_DEBUG
    +   /* Used by extra internal tests only run if NDEBUG is not defined */
    +   u64 cksum3 = 0;                 /* Checksum based on contents of indexes */
    +   Fts5Buffer term = {0,0,0};      /* Buffer used to hold most recent term */
    ++#endif
    ++  const int flags = FTS5INDEX_QUERY_NOOUTPUT;
    +   
    +   /* Load the FTS index structure */
    +   pStruct = fts5StructureRead(p);
    +@@ -177819,7 +200265,7 @@ static int sqlite3Fts5IndexIntegrityCheck(Fts5Index *p, u64 cksum){
    +   ** same term is performed. cksum3 is calculated based on the entries
    +   ** extracted by these queries.
    +   */
    +-  for(fts5MultiIterNew(p, pStruct, 0, 0, 0, 0, -1, 0, &pIter);
    ++  for(fts5MultiIterNew(p, pStruct, flags, 0, 0, 0, -1, 0, &pIter);
    +       fts5MultiIterEof(p, pIter)==0;
    +       fts5MultiIterNext(p, pIter, 0, 0)
    +   ){
    +@@ -177832,53 +200278,33 @@ static int sqlite3Fts5IndexIntegrityCheck(Fts5Index *p, u64 cksum){
    +     /* If this is a new term, query for it. Update cksum3 with the results. */
    +     fts5TestTerm(p, &term, z, n, cksum2, &cksum3);
    + 
    +-    poslist.n = 0;
    +-    fts5SegiterPoslist(p, &pIter->aSeg[pIter->aFirst[1].iFirst] , 0, &poslist);
    +-    while( 0==sqlite3Fts5PoslistNext64(poslist.p, poslist.n, &iOff, &iPos) ){
    +-      int iCol = FTS5_POS2COLUMN(iPos);
    +-      int iTokOff = FTS5_POS2OFFSET(iPos);
    +-      cksum2 ^= fts5IndexEntryCksum(iRowid, iCol, iTokOff, -1, z, n);
    ++    if( eDetail==FTS5_DETAIL_NONE ){
    ++      if( 0==fts5MultiIterIsEmpty(p, pIter) ){
    ++        cksum2 ^= sqlite3Fts5IndexEntryCksum(iRowid, 0, 0, -1, z, n);
    ++      }
    ++    }else{
    ++      poslist.n = 0;
    ++      fts5SegiterPoslist(p, &pIter->aSeg[pIter->aFirst[1].iFirst], 0, &poslist);
    ++      while( 0==sqlite3Fts5PoslistNext64(poslist.p, poslist.n, &iOff, &iPos) ){
    ++        int iCol = FTS5_POS2COLUMN(iPos);
    ++        int iTokOff = FTS5_POS2OFFSET(iPos);
    ++        cksum2 ^= sqlite3Fts5IndexEntryCksum(iRowid, iCol, iTokOff, -1, z, n);
    ++      }
    +     }
    +   }
    +   fts5TestTerm(p, &term, 0, 0, cksum2, &cksum3);
    + 
    +-  fts5MultiIterFree(p, pIter);
    ++  fts5MultiIterFree(pIter);
    +   if( p->rc==SQLITE_OK && cksum!=cksum2 ) p->rc = FTS5_CORRUPT;
    + 
    +   fts5StructureRelease(pStruct);
    ++#ifdef SQLITE_DEBUG
    +   fts5BufferFree(&term);
    ++#endif
    +   fts5BufferFree(&poslist);
    +   return fts5IndexReturn(p);
    + }
    + 
    +-
    +-/*
    +-** Calculate and return a checksum that is the XOR of the index entry
    +-** checksum of all entries that would be generated by the token specified
    +-** by the final 5 arguments.
    +-*/
    +-static u64 sqlite3Fts5IndexCksum(
    +-  Fts5Config *pConfig,            /* Configuration object */
    +-  i64 iRowid,                     /* Document term appears in */
    +-  int iCol,                       /* Column term appears in */
    +-  int iPos,                       /* Position term appears in */
    +-  const char *pTerm, int nTerm    /* Term at iPos */
    +-){
    +-  u64 ret = 0;                    /* Return value */
    +-  int iIdx;                       /* For iterating through indexes */
    +-
    +-  ret = fts5IndexEntryCksum(iRowid, iCol, iPos, 0, pTerm, nTerm);
    +-
    +-  for(iIdx=0; iIdx<pConfig->nPrefix; iIdx++){
    +-    int nByte = fts5IndexCharlenToBytelen(pTerm, nTerm, pConfig->aPrefix[iIdx]);
    +-    if( nByte ){
    +-      ret ^= fts5IndexEntryCksum(iRowid, iCol, iPos, iIdx+1, pTerm, nByte);
    +-    }
    +-  }
    +-
    +-  return ret;
    +-}
    +-
    + /*************************************************************************
    + **************************************************************************
    + ** Below this point is the implementation of the fts5_decode() scalar
    +@@ -178031,8 +200457,9 @@ static int fts5DecodeDoclist(int *pRc, Fts5Buffer *pBuf, const u8 *a, int n){
    +   }
    +   while( iOff<n ){
    +     int nPos;
    +-    int bDummy;
    +-    iOff += fts5GetPoslistSize(&a[iOff], &nPos, &bDummy);
    ++    int bDel;
    ++    iOff += fts5GetPoslistSize(&a[iOff], &nPos, &bDel);
    ++    sqlite3Fts5BufferAppendPrintf(pRc, pBuf, " nPos=%d%s", nPos, bDel?"*":"");
    +     iOff += fts5DecodePoslist(pRc, pBuf, &a[iOff], MIN(n-iOff, nPos));
    +     if( iOff<n ){
    +       i64 iDelta;
    +@@ -178045,6 +200472,47 @@ static int fts5DecodeDoclist(int *pRc, Fts5Buffer *pBuf, const u8 *a, int n){
    +   return iOff;
    + }
    + 
    ++/*
    ++** This function is part of the fts5_decode() debugging function. It is 
    ++** only ever used with detail=none tables.
    ++**
    ++** Buffer (pData/nData) contains a doclist in the format used by detail=none
    ++** tables. This function appends a human-readable version of that list to
    ++** buffer pBuf.
    ++**
    ++** If *pRc is other than SQLITE_OK when this function is called, it is a
    ++** no-op. If an OOM or other error occurs within this function, *pRc is
    ++** set to an SQLite error code before returning. The final state of buffer
    ++** pBuf is undefined in this case.
    ++*/
    ++static void fts5DecodeRowidList(
    ++  int *pRc,                       /* IN/OUT: Error code */
    ++  Fts5Buffer *pBuf,               /* Buffer to append text to */
    ++  const u8 *pData, int nData      /* Data to decode list-of-rowids from */
    ++){
    ++  int i = 0;
    ++  i64 iRowid = 0;
    ++
    ++  while( i<nData ){
    ++    const char *zApp = "";
    ++    u64 iVal;
    ++    i += sqlite3Fts5GetVarint(&pData[i], &iVal);
    ++    iRowid += iVal;
    ++
    ++    if( i<nData && pData[i]==0x00 ){
    ++      i++;
    ++      if( i<nData && pData[i]==0x00 ){
    ++        i++;
    ++        zApp = "+";
    ++      }else{
    ++        zApp = "*";
    ++      }
    ++    }
    ++
    ++    sqlite3Fts5BufferAppendPrintf(pRc, pBuf, " %lld%s", iRowid, zApp);
    ++  }
    ++}
    ++
    + /*
    + ** The implementation of user-defined scalar function fts5_decode().
    + */
    +@@ -178060,8 +200528,10 @@ static void fts5DecodeFunction(
    +   Fts5Buffer s;                   /* Build up text to return here */
    +   int rc = SQLITE_OK;             /* Return code */
    +   int nSpace = 0;
    ++  int eDetailNone = (sqlite3_user_data(pCtx)!=0);
    + 
    +   assert( nArg==2 );
    ++  UNUSED_PARAM(nArg);
    +   memset(&s, 0, sizeof(Fts5Buffer));
    +   iRowid = sqlite3_value_int64(apVal[0]);
    + 
    +@@ -178101,6 +200571,54 @@ static void fts5DecodeFunction(
    +     }else{
    +       fts5DecodeStructure(&rc, &s, a, n);
    +     }
    ++  }else if( eDetailNone ){
    ++    Fts5Buffer term;              /* Current term read from page */
    ++    int szLeaf;
    ++    int iPgidxOff = szLeaf = fts5GetU16(&a[2]);
    ++    int iTermOff;
    ++    int nKeep = 0;
    ++    int iOff;
    ++
    ++    memset(&term, 0, sizeof(Fts5Buffer));
    ++
    ++    /* Decode any entries that occur before the first term. */
    ++    if( szLeaf<n ){
    ++      iPgidxOff += fts5GetVarint32(&a[iPgidxOff], iTermOff);
    ++    }else{
    ++      iTermOff = szLeaf;
    ++    }
    ++    fts5DecodeRowidList(&rc, &s, &a[4], iTermOff-4);
    ++
    ++    iOff = iTermOff;
    ++    while( iOff<szLeaf ){
    ++      int nAppend;
    ++
    ++      /* Read the term data for the next term*/
    ++      iOff += fts5GetVarint32(&a[iOff], nAppend);
    ++      term.n = nKeep;
    ++      fts5BufferAppendBlob(&rc, &term, nAppend, &a[iOff]);
    ++      sqlite3Fts5BufferAppendPrintf(
    ++          &rc, &s, " term=%.*s", term.n, (const char*)term.p
    ++      );
    ++      iOff += nAppend;
    ++
    ++      /* Figure out where the doclist for this term ends */
    ++      if( iPgidxOff<n ){
    ++        int nIncr;
    ++        iPgidxOff += fts5GetVarint32(&a[iPgidxOff], nIncr);
    ++        iTermOff += nIncr;
    ++      }else{
    ++        iTermOff = szLeaf;
    ++      }
    ++
    ++      fts5DecodeRowidList(&rc, &s, &a[iOff], iTermOff-iOff);
    ++      iOff = iTermOff;
    ++      if( iOff<szLeaf ){
    ++        iOff += fts5GetVarint32(&a[iOff], nKeep);
    ++      }
    ++    }
    ++
    ++    fts5BufferFree(&term);
    +   }else{
    +     Fts5Buffer term;              /* Current term read from page */
    +     int szLeaf;                   /* Offset of pgidx in a[] */
    +@@ -178228,6 +200746,14 @@ static int sqlite3Fts5IndexInit(sqlite3 *db){
    +   int rc = sqlite3_create_function(
    +       db, "fts5_decode", 2, SQLITE_UTF8, 0, fts5DecodeFunction, 0, 0
    +   );
    ++
    ++  if( rc==SQLITE_OK ){
    ++    rc = sqlite3_create_function(
    ++        db, "fts5_decode_none", 2, 
    ++        SQLITE_UTF8, (void*)db, fts5DecodeFunction, 0, 0
    ++    );
    ++  }
    ++
    +   if( rc==SQLITE_OK ){
    +     rc = sqlite3_create_function(
    +         db, "fts5_rowid", -1, SQLITE_UTF8, 0, fts5RowidFunction, 0, 0
    +@@ -178237,6 +200763,14 @@ static int sqlite3Fts5IndexInit(sqlite3 *db){
    + }
    + 
    + 
    ++static int sqlite3Fts5IndexReset(Fts5Index *p){
    ++  assert( p->pStruct==0 || p->iStructVersion!=0 );
    ++  if( fts5IndexDataVersion(p)!=p->iStructVersion ){
    ++    fts5StructureInvalidate(p);
    ++  }
    ++  return fts5IndexReturn(p);
    ++}
    ++
    + /*
    + ** 2014 Jun 09
    + **
    +@@ -178253,6 +200787,7 @@ static int sqlite3Fts5IndexInit(sqlite3 *db){
    + */
    + 
    + 
    ++/* #include "fts5Int.h" */
    + 
    + /*
    + ** This variable is set to false when running tests for which the on disk
    +@@ -178458,12 +200993,13 @@ struct Fts5Cursor {
    + /*
    + ** Values for Fts5Cursor.csrflags
    + */
    +-#define FTS5CSR_REQUIRE_CONTENT   0x01
    +-#define FTS5CSR_REQUIRE_DOCSIZE   0x02
    +-#define FTS5CSR_REQUIRE_INST      0x04
    +-#define FTS5CSR_EOF               0x08
    ++#define FTS5CSR_EOF               0x01
    ++#define FTS5CSR_REQUIRE_CONTENT   0x02
    ++#define FTS5CSR_REQUIRE_DOCSIZE   0x04
    ++#define FTS5CSR_REQUIRE_INST      0x08
    + #define FTS5CSR_FREE_ZRANK        0x10
    + #define FTS5CSR_REQUIRE_RESEEK    0x20
    ++#define FTS5CSR_REQUIRE_POSLIST   0x40
    + 
    + #define BitFlagAllTest(x,y) (((x) & (y))==(y))
    + #define BitFlagTest(x,y)    (((x) & (y))!=0)
    +@@ -178633,6 +201169,15 @@ static int fts5InitVtab(
    +     rc = sqlite3Fts5ConfigDeclareVtab(pConfig);
    +   }
    + 
    ++  /* Load the initial configuration */
    ++  if( rc==SQLITE_OK ){
    ++    assert( pConfig->pzErrmsg==0 );
    ++    pConfig->pzErrmsg = pzErr;
    ++    rc = sqlite3Fts5IndexLoadConfig(pTab->pIndex);
    ++    sqlite3Fts5IndexRollback(pTab->pIndex);
    ++    pConfig->pzErrmsg = 0;
    ++  }
    ++
    +   if( rc!=SQLITE_OK ){
    +     fts5FreeVtab(pTab);
    +     pTab = 0;
    +@@ -178685,7 +201230,10 @@ static int fts5CreateMethod(
    + */
    + static void fts5SetUniqueFlag(sqlite3_index_info *pIdxInfo){
    + #if SQLITE_VERSION_NUMBER>=3008012
    +-  if( sqlite3_libversion_number()>=3008012 ){
    ++#ifndef SQLITE_CORE
    ++  if( sqlite3_libversion_number()>=3008012 )
    ++#endif
    ++  {
    +     pIdxInfo->idxFlags |= SQLITE_INDEX_SCAN_UNIQUE;
    +   }
    + #endif
    +@@ -178731,6 +201279,7 @@ static void fts5SetUniqueFlag(sqlite3_index_info *pIdxInfo){
    + static int fts5BestIndexMethod(sqlite3_vtab *pVTab, sqlite3_index_info *pInfo){
    +   Fts5Table *pTab = (Fts5Table*)pVTab;
    +   Fts5Config *pConfig = pTab->pConfig;
    ++  const int nCol = pConfig->nCol;
    +   int idxFlags = 0;               /* Parameter passed through to xFilter() */
    +   int bHasMatch;
    +   int iNext;
    +@@ -178756,24 +201305,34 @@ static int fts5BestIndexMethod(sqlite3_vtab *pVTab, sqlite3_index_info *pInfo){
    + 
    +   int aColMap[3];
    +   aColMap[0] = -1;
    +-  aColMap[1] = pConfig->nCol;
    +-  aColMap[2] = pConfig->nCol+1;
    ++  aColMap[1] = nCol;
    ++  aColMap[2] = nCol+1;
    + 
    +   /* Set idxFlags flags for all WHERE clause terms that will be used. */
    +   for(i=0; i<pInfo->nConstraint; i++){
    +     struct sqlite3_index_constraint *p = &pInfo->aConstraint[i];
    +-    int j;
    +-    for(j=0; j<sizeof(aConstraint)/sizeof(aConstraint[0]); j++){
    +-      struct Constraint *pC = &aConstraint[j];
    +-      if( p->iColumn==aColMap[pC->iCol] && p->op & pC->op ){
    +-        if( p->usable ){
    ++    int iCol = p->iColumn;
    ++
    ++    if( (p->op==SQLITE_INDEX_CONSTRAINT_MATCH && iCol>=0 && iCol<=nCol)
    ++     || (p->op==SQLITE_INDEX_CONSTRAINT_EQ && iCol==nCol)
    ++    ){
    ++      /* A MATCH operator or equivalent */
    ++      if( p->usable ){
    ++        idxFlags = (idxFlags & 0xFFFF) | FTS5_BI_MATCH | (iCol << 16);
    ++        aConstraint[0].iConsIndex = i;
    ++      }else{
    ++        /* As there exists an unusable MATCH constraint this is an 
    ++        ** unusable plan. Set a prohibitively high cost. */
    ++        pInfo->estimatedCost = 1e50;
    ++        return SQLITE_OK;
    ++      }
    ++    }else{
    ++      int j;
    ++      for(j=1; j<ArraySize(aConstraint); j++){
    ++        struct Constraint *pC = &aConstraint[j];
    ++        if( iCol==aColMap[pC->iCol] && p->op & pC->op && p->usable ){
    +           pC->iConsIndex = i;
    +           idxFlags |= pC->fts5op;
    +-        }else if( j==0 ){
    +-          /* As there exists an unusable MATCH constraint this is an 
    +-          ** unusable plan. Set a prohibitively high cost. */
    +-          pInfo->estimatedCost = 1e50;
    +-          return SQLITE_OK;
    +         }
    +       }
    +     }
    +@@ -178810,11 +201369,11 @@ static int fts5BestIndexMethod(sqlite3_vtab *pVTab, sqlite3_index_info *pInfo){
    + 
    +   /* Assign argvIndex values to each constraint in use. */
    +   iNext = 1;
    +-  for(i=0; i<sizeof(aConstraint)/sizeof(aConstraint[0]); i++){
    ++  for(i=0; i<ArraySize(aConstraint); i++){
    +     struct Constraint *pC = &aConstraint[i];
    +     if( pC->iConsIndex>=0 ){
    +       pInfo->aConstraintUsage[pC->iConsIndex].argvIndex = iNext++;
    +-      pInfo->aConstraintUsage[pC->iConsIndex].omit = pC->omit;
    ++      pInfo->aConstraintUsage[pC->iConsIndex].omit = (unsigned char)pC->omit;
    +     }
    +   }
    + 
    +@@ -178822,27 +201381,38 @@ static int fts5BestIndexMethod(sqlite3_vtab *pVTab, sqlite3_index_info *pInfo){
    +   return SQLITE_OK;
    + }
    + 
    ++static int fts5NewTransaction(Fts5Table *pTab){
    ++  Fts5Cursor *pCsr;
    ++  for(pCsr=pTab->pGlobal->pCsr; pCsr; pCsr=pCsr->pNext){
    ++    if( pCsr->base.pVtab==(sqlite3_vtab*)pTab ) return SQLITE_OK;
    ++  }
    ++  return sqlite3Fts5StorageReset(pTab->pStorage);
    ++}
    ++
    + /*
    + ** Implementation of xOpen method.
    + */
    + static int fts5OpenMethod(sqlite3_vtab *pVTab, sqlite3_vtab_cursor **ppCsr){
    +   Fts5Table *pTab = (Fts5Table*)pVTab;
    +   Fts5Config *pConfig = pTab->pConfig;
    +-  Fts5Cursor *pCsr;               /* New cursor object */
    ++  Fts5Cursor *pCsr = 0;           /* New cursor object */
    +   int nByte;                      /* Bytes of space to allocate */
    +-  int rc = SQLITE_OK;             /* Return code */
    ++  int rc;                         /* Return code */
    + 
    +-  nByte = sizeof(Fts5Cursor) + pConfig->nCol * sizeof(int);
    +-  pCsr = (Fts5Cursor*)sqlite3_malloc(nByte);
    +-  if( pCsr ){
    +-    Fts5Global *pGlobal = pTab->pGlobal;
    +-    memset(pCsr, 0, nByte);
    +-    pCsr->aColumnSize = (int*)&pCsr[1];
    +-    pCsr->pNext = pGlobal->pCsr;
    +-    pGlobal->pCsr = pCsr;
    +-    pCsr->iCsrId = ++pGlobal->iNextId;
    +-  }else{
    +-    rc = SQLITE_NOMEM;
    ++  rc = fts5NewTransaction(pTab);
    ++  if( rc==SQLITE_OK ){
    ++    nByte = sizeof(Fts5Cursor) + pConfig->nCol * sizeof(int);
    ++    pCsr = (Fts5Cursor*)sqlite3_malloc(nByte);
    ++    if( pCsr ){
    ++      Fts5Global *pGlobal = pTab->pGlobal;
    ++      memset(pCsr, 0, nByte);
    ++      pCsr->aColumnSize = (int*)&pCsr[1];
    ++      pCsr->pNext = pGlobal->pCsr;
    ++      pGlobal->pCsr = pCsr;
    ++      pCsr->iCsrId = ++pGlobal->iNextId;
    ++    }else{
    ++      rc = SQLITE_NOMEM;
    ++    }
    +   }
    +   *ppCsr = (sqlite3_vtab_cursor*)pCsr;
    +   return rc;
    +@@ -178865,6 +201435,7 @@ static void fts5CsrNewrow(Fts5Cursor *pCsr){
    +       FTS5CSR_REQUIRE_CONTENT 
    +     | FTS5CSR_REQUIRE_DOCSIZE 
    +     | FTS5CSR_REQUIRE_INST 
    ++    | FTS5CSR_REQUIRE_POSLIST 
    +   );
    + }
    + 
    +@@ -178947,15 +201518,18 @@ static int fts5SorterNext(Fts5Cursor *pCsr){
    +     nBlob = sqlite3_column_bytes(pSorter->pStmt, 1);
    +     aBlob = a = sqlite3_column_blob(pSorter->pStmt, 1);
    + 
    +-    for(i=0; i<(pSorter->nIdx-1); i++){
    +-      int iVal;
    +-      a += fts5GetVarint32(a, iVal);
    +-      iOff += iVal;
    +-      pSorter->aIdx[i] = iOff;
    ++    /* nBlob==0 in detail=none mode. */
    ++    if( nBlob>0 ){
    ++      for(i=0; i<(pSorter->nIdx-1); i++){
    ++        int iVal;
    ++        a += fts5GetVarint32(a, iVal);
    ++        iOff += iVal;
    ++        pSorter->aIdx[i] = iOff;
    ++      }
    ++      pSorter->aIdx[i] = &aBlob[nBlob] - a;
    ++      pSorter->aPoslist = a;
    +     }
    +-    pSorter->aIdx[i] = &aBlob[nBlob] - a;
    + 
    +-    pSorter->aPoslist = a;
    +     fts5CsrNewrow(pCsr);
    +   }
    + 
    +@@ -178999,7 +201573,7 @@ static int fts5CursorReseek(Fts5Cursor *pCsr, int *pbSkip){
    +     i64 iRowid = sqlite3Fts5ExprRowid(pCsr->pExpr);
    + 
    +     rc = sqlite3Fts5ExprFirst(pCsr->pExpr, pTab->pIndex, iRowid, bDesc);
    +-    if( rc==SQLITE_OK && iRowid!=sqlite3Fts5ExprRowid(pCsr->pExpr) ){
    ++    if( rc==SQLITE_OK &&  iRowid!=sqlite3Fts5ExprRowid(pCsr->pExpr) ){
    +       *pbSkip = 1;
    +     }
    + 
    +@@ -179007,6 +201581,7 @@ static int fts5CursorReseek(Fts5Cursor *pCsr, int *pbSkip){
    +     fts5CsrNewrow(pCsr);
    +     if( sqlite3Fts5ExprEof(pCsr->pExpr) ){
    +       CsrFlagSet(pCsr, FTS5CSR_EOF);
    ++      *pbSkip = 1;
    +     }
    +   }
    +   return rc;
    +@@ -179023,24 +201598,24 @@ static int fts5CursorReseek(Fts5Cursor *pCsr, int *pbSkip){
    + */
    + static int fts5NextMethod(sqlite3_vtab_cursor *pCursor){
    +   Fts5Cursor *pCsr = (Fts5Cursor*)pCursor;
    +-  int rc = SQLITE_OK;
    ++  int rc;
    + 
    +   assert( (pCsr->ePlan<3)==
    +           (pCsr->ePlan==FTS5_PLAN_MATCH || pCsr->ePlan==FTS5_PLAN_SOURCE) 
    +   );
    ++  assert( !CsrFlagTest(pCsr, FTS5CSR_EOF) );
    + 
    +   if( pCsr->ePlan<3 ){
    +     int bSkip = 0;
    +     if( (rc = fts5CursorReseek(pCsr, &bSkip)) || bSkip ) return rc;
    +     rc = sqlite3Fts5ExprNext(pCsr->pExpr, pCsr->iLastRowid);
    +-    if( sqlite3Fts5ExprEof(pCsr->pExpr) ){
    +-      CsrFlagSet(pCsr, FTS5CSR_EOF);
    +-    }
    ++    CsrFlagSet(pCsr, sqlite3Fts5ExprEof(pCsr->pExpr));
    +     fts5CsrNewrow(pCsr);
    +   }else{
    +     switch( pCsr->ePlan ){
    +       case FTS5_PLAN_SPECIAL: {
    +         CsrFlagSet(pCsr, FTS5CSR_EOF);
    ++        rc = SQLITE_OK;
    +         break;
    +       }
    +   
    +@@ -179064,13 +201639,42 @@ static int fts5NextMethod(sqlite3_vtab_cursor *pCursor){
    +   return rc;
    + }
    + 
    ++
    ++static int fts5PrepareStatement(
    ++  sqlite3_stmt **ppStmt,
    ++  Fts5Config *pConfig, 
    ++  const char *zFmt,
    ++  ...
    ++){
    ++  sqlite3_stmt *pRet = 0;
    ++  int rc;
    ++  char *zSql;
    ++  va_list ap;
    ++
    ++  va_start(ap, zFmt);
    ++  zSql = sqlite3_vmprintf(zFmt, ap);
    ++  if( zSql==0 ){
    ++    rc = SQLITE_NOMEM; 
    ++  }else{
    ++    rc = sqlite3_prepare_v3(pConfig->db, zSql, -1, 
    ++                            SQLITE_PREPARE_PERSISTENT, &pRet, 0);
    ++    if( rc!=SQLITE_OK ){
    ++      *pConfig->pzErrmsg = sqlite3_mprintf("%s", sqlite3_errmsg(pConfig->db));
    ++    }
    ++    sqlite3_free(zSql);
    ++  }
    ++
    ++  va_end(ap);
    ++  *ppStmt = pRet;
    ++  return rc;
    ++} 
    ++
    + static int fts5CursorFirstSorted(Fts5Table *pTab, Fts5Cursor *pCsr, int bDesc){
    +   Fts5Config *pConfig = pTab->pConfig;
    +   Fts5Sorter *pSorter;
    +   int nPhrase;
    +   int nByte;
    +-  int rc = SQLITE_OK;
    +-  char *zSql;
    ++  int rc;
    +   const char *zRank = pCsr->zRank;
    +   const char *zRankArgs = pCsr->zRankArgs;
    +   
    +@@ -179088,17 +201692,13 @@ static int fts5CursorFirstSorted(Fts5Table *pTab, Fts5Cursor *pCsr, int bDesc){
    +   ** table, saving it creates a circular reference.
    +   **
    +   ** If SQLite a built-in statement cache, this wouldn't be a problem. */
    +-  zSql = sqlite3Fts5Mprintf(&rc, 
    ++  rc = fts5PrepareStatement(&pSorter->pStmt, pConfig,
    +       "SELECT rowid, rank FROM %Q.%Q ORDER BY %s(%s%s%s) %s",
    +       pConfig->zDb, pConfig->zName, zRank, pConfig->zName,
    +       (zRankArgs ? ", " : ""),
    +       (zRankArgs ? zRankArgs : ""),
    +       bDesc ? "DESC" : "ASC"
    +   );
    +-  if( zSql ){
    +-    rc = sqlite3_prepare_v2(pConfig->db, zSql, -1, &pSorter->pStmt, 0);
    +-    sqlite3_free(zSql);
    +-  }
    + 
    +   pCsr->pSorter = pSorter;
    +   if( rc==SQLITE_OK ){
    +@@ -179193,7 +201793,8 @@ static int fts5FindRankFunction(Fts5Cursor *pCsr){
    +     char *zSql = sqlite3Fts5Mprintf(&rc, "SELECT %s", zRankArgs);
    +     if( zSql ){
    +       sqlite3_stmt *pStmt = 0;
    +-      rc = sqlite3_prepare_v2(pConfig->db, zSql, -1, &pStmt, 0);
    ++      rc = sqlite3_prepare_v3(pConfig->db, zSql, -1,
    ++                              SQLITE_PREPARE_PERSISTENT, &pStmt, 0);
    +       sqlite3_free(zSql);
    +       assert( rc==SQLITE_OK || pCsr->pRankArgStmt==0 );
    +       if( rc==SQLITE_OK ){
    +@@ -179292,7 +201893,7 @@ static i64 fts5GetRowidLimit(sqlite3_value *pVal, i64 iDefault){
    + static int fts5FilterMethod(
    +   sqlite3_vtab_cursor *pCursor,   /* The cursor used for this query */
    +   int idxNum,                     /* Strategy index */
    +-  const char *idxStr,             /* Unused */
    ++  const char *zUnused,            /* Unused */
    +   int nVal,                       /* Number of elements in apVal */
    +   sqlite3_value **apVal           /* Arguments for the indexing scheme */
    + ){
    +@@ -179308,8 +201909,12 @@ static int fts5FilterMethod(
    +   sqlite3_value *pRowidEq = 0;    /* rowid = ? expression (or NULL) */
    +   sqlite3_value *pRowidLe = 0;    /* rowid <= ? expression (or NULL) */
    +   sqlite3_value *pRowidGe = 0;    /* rowid >= ? expression (or NULL) */
    ++  int iCol;                       /* Column on LHS of MATCH operator */
    +   char **pzErrmsg = pConfig->pzErrmsg;
    + 
    ++  UNUSED_PARAM(zUnused);
    ++  UNUSED_PARAM(nVal);
    ++
    +   if( pCsr->ePlan ){
    +     fts5FreeCursorComponents(pCsr);
    +     memset(&pCsr->ePlan, 0, sizeof(Fts5Cursor) - ((u8*)&pCsr->ePlan-(u8*)pCsr));
    +@@ -179335,6 +201940,8 @@ static int fts5FilterMethod(
    +   if( BitFlagTest(idxNum, FTS5_BI_ROWID_EQ) ) pRowidEq = apVal[iVal++];
    +   if( BitFlagTest(idxNum, FTS5_BI_ROWID_LE) ) pRowidLe = apVal[iVal++];
    +   if( BitFlagTest(idxNum, FTS5_BI_ROWID_GE) ) pRowidGe = apVal[iVal++];
    ++  iCol = (idxNum>>16);
    ++  assert( iCol>=0 && iCol<=pConfig->nCol );
    +   assert( iVal==nVal );
    +   bOrderByRank = ((idxNum & FTS5_BI_ORDER_RANK) ? 1 : 0);
    +   pCsr->bDesc = bDesc = ((idxNum & FTS5_BI_ORDER_DESC) ? 1 : 0);
    +@@ -179381,7 +201988,7 @@ static int fts5FilterMethod(
    +         rc = fts5SpecialMatch(pTab, pCsr, &zExpr[1]);
    +       }else{
    +         char **pzErr = &pTab->base.zErrMsg;
    +-        rc = sqlite3Fts5ExprNew(pConfig, zExpr, &pCsr->pExpr, pzErr);
    ++        rc = sqlite3Fts5ExprNew(pConfig, iCol, zExpr, &pCsr->pExpr, pzErr);
    +         if( rc==SQLITE_OK ){
    +           if( bOrderByRank ){
    +             pCsr->ePlan = FTS5_PLAN_SORTED_MATCH;
    +@@ -179593,14 +202200,13 @@ static int fts5SpecialInsert(
    + 
    + static int fts5SpecialDelete(
    +   Fts5Table *pTab, 
    +-  sqlite3_value **apVal, 
    +-  sqlite3_int64 *piRowid
    ++  sqlite3_value **apVal
    + ){
    +   int rc = SQLITE_OK;
    +   int eType1 = sqlite3_value_type(apVal[1]);
    +   if( eType1==SQLITE_INTEGER ){
    +     sqlite3_int64 iDel = sqlite3_value_int64(apVal[1]);
    +-    rc = sqlite3Fts5StorageSpecialDelete(pTab->pStorage, iDel, &apVal[2]);
    ++    rc = sqlite3Fts5StorageDelete(pTab->pStorage, iDel, &apVal[2]);
    +   }
    +   return rc;
    + }
    +@@ -179670,7 +202276,7 @@ static int fts5UpdateMethod(
    +     if( pConfig->eContent!=FTS5_CONTENT_NORMAL 
    +       && 0==sqlite3_stricmp("delete", z) 
    +     ){
    +-      rc = fts5SpecialDelete(pTab, apVal, pRowid);
    ++      rc = fts5SpecialDelete(pTab, apVal);
    +     }else{
    +       rc = fts5SpecialInsert(pTab, z, apVal[2 + pConfig->nCol + 1]);
    +     }
    +@@ -179686,7 +202292,10 @@ static int fts5UpdateMethod(
    +     **
    +     ** Cases 3 and 4 may violate the rowid constraint.
    +     */
    +-    int eConflict = sqlite3_vtab_on_conflict(pConfig->db);
    ++    int eConflict = SQLITE_ABORT;
    ++    if( pConfig->eContent==FTS5_CONTENT_NORMAL ){
    ++      eConflict = sqlite3_vtab_on_conflict(pConfig->db);
    ++    }
    + 
    +     assert( eType0==SQLITE_INTEGER || eType0==SQLITE_NULL );
    +     assert( nArg!=1 || eType0==SQLITE_INTEGER );
    +@@ -179701,46 +202310,46 @@ static int fts5UpdateMethod(
    +       rc = SQLITE_ERROR;
    +     }
    + 
    +-    /* Case 1: DELETE */
    ++    /* DELETE */
    +     else if( nArg==1 ){
    +       i64 iDel = sqlite3_value_int64(apVal[0]);  /* Rowid to delete */
    +-      rc = sqlite3Fts5StorageDelete(pTab->pStorage, iDel);
    ++      rc = sqlite3Fts5StorageDelete(pTab->pStorage, iDel, 0);
    +     }
    + 
    +-    /* Case 2: INSERT */
    ++    /* INSERT */
    +     else if( eType0!=SQLITE_INTEGER ){     
    +       /* If this is a REPLACE, first remove the current entry (if any) */
    +       if( eConflict==SQLITE_REPLACE 
    +        && sqlite3_value_type(apVal[1])==SQLITE_INTEGER 
    +       ){
    +         i64 iNew = sqlite3_value_int64(apVal[1]);  /* Rowid to delete */
    +-        rc = sqlite3Fts5StorageDelete(pTab->pStorage, iNew);
    ++        rc = sqlite3Fts5StorageDelete(pTab->pStorage, iNew, 0);
    +       }
    +       fts5StorageInsert(&rc, pTab, apVal, pRowid);
    +     }
    + 
    +-    /* Case 2: UPDATE */
    ++    /* UPDATE */
    +     else{
    +       i64 iOld = sqlite3_value_int64(apVal[0]);  /* Old rowid */
    +       i64 iNew = sqlite3_value_int64(apVal[1]);  /* New rowid */
    +       if( iOld!=iNew ){
    +         if( eConflict==SQLITE_REPLACE ){
    +-          rc = sqlite3Fts5StorageDelete(pTab->pStorage, iOld);
    ++          rc = sqlite3Fts5StorageDelete(pTab->pStorage, iOld, 0);
    +           if( rc==SQLITE_OK ){
    +-            rc = sqlite3Fts5StorageDelete(pTab->pStorage, iNew);
    ++            rc = sqlite3Fts5StorageDelete(pTab->pStorage, iNew, 0);
    +           }
    +           fts5StorageInsert(&rc, pTab, apVal, pRowid);
    +         }else{
    +           rc = sqlite3Fts5StorageContentInsert(pTab->pStorage, apVal, pRowid);
    +           if( rc==SQLITE_OK ){
    +-            rc = sqlite3Fts5StorageDelete(pTab->pStorage, iOld);
    ++            rc = sqlite3Fts5StorageDelete(pTab->pStorage, iOld, 0);
    +           }
    +           if( rc==SQLITE_OK ){
    +             rc = sqlite3Fts5StorageIndexInsert(pTab->pStorage, apVal, *pRowid);
    +           }
    +         }
    +       }else{
    +-        rc = sqlite3Fts5StorageDelete(pTab->pStorage, iOld);
    ++        rc = sqlite3Fts5StorageDelete(pTab->pStorage, iOld, 0);
    +         fts5StorageInsert(&rc, pTab, apVal, pRowid);
    +       }
    +     }
    +@@ -179759,7 +202368,7 @@ static int fts5SyncMethod(sqlite3_vtab *pVtab){
    +   fts5CheckTransactionState(pTab, FTS5_SYNC, 0);
    +   pTab->pConfig->pzErrmsg = &pTab->base.zErrMsg;
    +   fts5TripCursors(pTab);
    +-  rc = sqlite3Fts5StorageSync(pTab->pStorage, 1);
    ++  rc = sqlite3Fts5StorageSync(pTab->pStorage);
    +   pTab->pConfig->pzErrmsg = 0;
    +   return rc;
    + }
    +@@ -179769,6 +202378,7 @@ static int fts5SyncMethod(sqlite3_vtab *pVtab){
    + */
    + static int fts5BeginMethod(sqlite3_vtab *pVtab){
    +   fts5CheckTransactionState((Fts5Table*)pVtab, FTS5_BEGIN, 0);
    ++  fts5NewTransaction((Fts5Table*)pVtab);
    +   return SQLITE_OK;
    + }
    + 
    +@@ -179778,6 +202388,7 @@ static int fts5BeginMethod(sqlite3_vtab *pVtab){
    + ** by fts5SyncMethod().
    + */
    + static int fts5CommitMethod(sqlite3_vtab *pVtab){
    ++  UNUSED_PARAM(pVtab);  /* Call below is a no-op for NDEBUG builds */
    +   fts5CheckTransactionState((Fts5Table*)pVtab, FTS5_COMMIT, 0);
    +   return SQLITE_OK;
    + }
    +@@ -179794,6 +202405,8 @@ static int fts5RollbackMethod(sqlite3_vtab *pVtab){
    +   return rc;
    + }
    + 
    ++static int fts5CsrPoslist(Fts5Cursor*, int, const u8**, int*);
    ++
    + static void *fts5ApiUserData(Fts5Context *pCtx){
    +   Fts5Cursor *pCsr = (Fts5Cursor*)pCtx;
    +   return pCsr->pAux->pUserData;
    +@@ -179843,17 +202456,72 @@ static int fts5ApiPhraseSize(Fts5Context *pCtx, int iPhrase){
    +   return sqlite3Fts5ExprPhraseSize(pCsr->pExpr, iPhrase);
    + }
    + 
    +-static int fts5CsrPoslist(Fts5Cursor *pCsr, int iPhrase, const u8 **pa){
    +-  int n;
    +-  if( pCsr->pSorter ){
    ++static int fts5ApiColumnText(
    ++  Fts5Context *pCtx, 
    ++  int iCol, 
    ++  const char **pz, 
    ++  int *pn
    ++){
    ++  int rc = SQLITE_OK;
    ++  Fts5Cursor *pCsr = (Fts5Cursor*)pCtx;
    ++  if( fts5IsContentless((Fts5Table*)(pCsr->base.pVtab)) ){
    ++    *pz = 0;
    ++    *pn = 0;
    ++  }else{
    ++    rc = fts5SeekCursor(pCsr, 0);
    ++    if( rc==SQLITE_OK ){
    ++      *pz = (const char*)sqlite3_column_text(pCsr->pStmt, iCol+1);
    ++      *pn = sqlite3_column_bytes(pCsr->pStmt, iCol+1);
    ++    }
    ++  }
    ++  return rc;
    ++}
    ++
    ++static int fts5CsrPoslist(
    ++  Fts5Cursor *pCsr, 
    ++  int iPhrase, 
    ++  const u8 **pa,
    ++  int *pn
    ++){
    ++  Fts5Config *pConfig = ((Fts5Table*)(pCsr->base.pVtab))->pConfig;
    ++  int rc = SQLITE_OK;
    ++  int bLive = (pCsr->pSorter==0);
    ++
    ++  if( CsrFlagTest(pCsr, FTS5CSR_REQUIRE_POSLIST) ){
    ++
    ++    if( pConfig->eDetail!=FTS5_DETAIL_FULL ){
    ++      Fts5PoslistPopulator *aPopulator;
    ++      int i;
    ++      aPopulator = sqlite3Fts5ExprClearPoslists(pCsr->pExpr, bLive);
    ++      if( aPopulator==0 ) rc = SQLITE_NOMEM;
    ++      for(i=0; i<pConfig->nCol && rc==SQLITE_OK; i++){
    ++        int n; const char *z;
    ++        rc = fts5ApiColumnText((Fts5Context*)pCsr, i, &z, &n);
    ++        if( rc==SQLITE_OK ){
    ++          rc = sqlite3Fts5ExprPopulatePoslists(
    ++              pConfig, pCsr->pExpr, aPopulator, i, z, n
    ++          );
    ++        }
    ++      }
    ++      sqlite3_free(aPopulator);
    ++
    ++      if( pCsr->pSorter ){
    ++        sqlite3Fts5ExprCheckPoslists(pCsr->pExpr, pCsr->pSorter->iRowid);
    ++      }
    ++    }
    ++    CsrFlagClear(pCsr, FTS5CSR_REQUIRE_POSLIST);
    ++  }
    ++
    ++  if( pCsr->pSorter && pConfig->eDetail==FTS5_DETAIL_FULL ){
    +     Fts5Sorter *pSorter = pCsr->pSorter;
    +     int i1 = (iPhrase==0 ? 0 : pSorter->aIdx[iPhrase-1]);
    +-    n = pSorter->aIdx[iPhrase] - i1;
    ++    *pn = pSorter->aIdx[iPhrase] - i1;
    +     *pa = &pSorter->aPoslist[i1];
    +   }else{
    +-    n = sqlite3Fts5ExprPoslist(pCsr->pExpr, iPhrase, pa);
    ++    *pn = sqlite3Fts5ExprPoslist(pCsr->pExpr, iPhrase, pa);
    +   }
    +-  return n;
    ++
    ++  return rc;
    + }
    + 
    + /*
    +@@ -179878,43 +202546,48 @@ static int fts5CacheInstArray(Fts5Cursor *pCsr){
    +     int i;
    + 
    +     /* Initialize all iterators */
    +-    for(i=0; i<nIter; i++){
    ++    for(i=0; i<nIter && rc==SQLITE_OK; i++){
    +       const u8 *a;
    +-      int n = fts5CsrPoslist(pCsr, i, &a);
    +-      sqlite3Fts5PoslistReaderInit(a, n, &aIter[i]);
    ++      int n; 
    ++      rc = fts5CsrPoslist(pCsr, i, &a, &n);
    ++      if( rc==SQLITE_OK ){
    ++        sqlite3Fts5PoslistReaderInit(a, n, &aIter[i]);
    ++      }
    +     }
    + 
    +-    while( 1 ){
    +-      int *aInst;
    +-      int iBest = -1;
    +-      for(i=0; i<nIter; i++){
    +-        if( (aIter[i].bEof==0) 
    +-         && (iBest<0 || aIter[i].iPos<aIter[iBest].iPos) 
    +-        ){
    +-          iBest = i;
    ++    if( rc==SQLITE_OK ){
    ++      while( 1 ){
    ++        int *aInst;
    ++        int iBest = -1;
    ++        for(i=0; i<nIter; i++){
    ++          if( (aIter[i].bEof==0) 
    ++              && (iBest<0 || aIter[i].iPos<aIter[iBest].iPos) 
    ++            ){
    ++            iBest = i;
    ++          }
    +         }
    +-      }
    +-      if( iBest<0 ) break;
    ++        if( iBest<0 ) break;
    + 
    +-      nInst++;
    +-      if( nInst>=pCsr->nInstAlloc ){
    +-        pCsr->nInstAlloc = pCsr->nInstAlloc ? pCsr->nInstAlloc*2 : 32;
    +-        aInst = (int*)sqlite3_realloc(
    +-            pCsr->aInst, pCsr->nInstAlloc*sizeof(int)*3
    +-        );
    +-        if( aInst ){
    +-          pCsr->aInst = aInst;
    +-        }else{
    +-          rc = SQLITE_NOMEM;
    +-          break;
    ++        nInst++;
    ++        if( nInst>=pCsr->nInstAlloc ){
    ++          pCsr->nInstAlloc = pCsr->nInstAlloc ? pCsr->nInstAlloc*2 : 32;
    ++          aInst = (int*)sqlite3_realloc(
    ++              pCsr->aInst, pCsr->nInstAlloc*sizeof(int)*3
    ++              );
    ++          if( aInst ){
    ++            pCsr->aInst = aInst;
    ++          }else{
    ++            rc = SQLITE_NOMEM;
    ++            break;
    ++          }
    +         }
    +-      }
    + 
    +-      aInst = &pCsr->aInst[3 * (nInst-1)];
    +-      aInst[0] = iBest;
    +-      aInst[1] = FTS5_POS2COLUMN(aIter[iBest].iPos);
    +-      aInst[2] = FTS5_POS2OFFSET(aIter[iBest].iPos);
    +-      sqlite3Fts5PoslistReaderNext(&aIter[iBest]);
    ++        aInst = &pCsr->aInst[3 * (nInst-1)];
    ++        aInst[0] = iBest;
    ++        aInst[1] = FTS5_POS2COLUMN(aIter[iBest].iPos);
    ++        aInst[2] = FTS5_POS2OFFSET(aIter[iBest].iPos);
    ++        sqlite3Fts5PoslistReaderNext(&aIter[iBest]);
    ++      }
    +     }
    + 
    +     pCsr->nInstCount = nInst;
    +@@ -179947,6 +202620,12 @@ static int fts5ApiInst(
    +   ){
    +     if( iIdx<0 || iIdx>=pCsr->nInstCount ){
    +       rc = SQLITE_RANGE;
    ++#if 0
    ++    }else if( fts5IsOffsetless((Fts5Table*)pCsr->base.pVtab) ){
    ++      *piPhrase = pCsr->aInst[iIdx*3];
    ++      *piCol = pCsr->aInst[iIdx*3 + 2];
    ++      *piOff = -1;
    ++#endif
    +     }else{
    +       *piPhrase = pCsr->aInst[iIdx*3];
    +       *piCol = pCsr->aInst[iIdx*3 + 1];
    +@@ -179960,36 +202639,17 @@ static sqlite3_int64 fts5ApiRowid(Fts5Context *pCtx){
    +   return fts5CursorRowid((Fts5Cursor*)pCtx);
    + }
    + 
    +-static int fts5ApiColumnText(
    +-  Fts5Context *pCtx, 
    +-  int iCol, 
    +-  const char **pz, 
    +-  int *pn
    +-){
    +-  int rc = SQLITE_OK;
    +-  Fts5Cursor *pCsr = (Fts5Cursor*)pCtx;
    +-  if( fts5IsContentless((Fts5Table*)(pCsr->base.pVtab)) ){
    +-    *pz = 0;
    +-    *pn = 0;
    +-  }else{
    +-    rc = fts5SeekCursor(pCsr, 0);
    +-    if( rc==SQLITE_OK ){
    +-      *pz = (const char*)sqlite3_column_text(pCsr->pStmt, iCol+1);
    +-      *pn = sqlite3_column_bytes(pCsr->pStmt, iCol+1);
    +-    }
    +-  }
    +-  return rc;
    +-}
    +-
    + static int fts5ColumnSizeCb(
    +   void *pContext,                 /* Pointer to int */
    +   int tflags,
    +-  const char *pToken,             /* Buffer containing token */
    +-  int nToken,                     /* Size of token in bytes */
    +-  int iStart,                     /* Start offset of token */
    +-  int iEnd                        /* End offset of token */
    ++  const char *pUnused,            /* Buffer containing token */
    ++  int nUnused,                    /* Size of token in bytes */
    ++  int iUnused1,                   /* Start offset of token */
    ++  int iUnused2                    /* End offset of token */
    + ){
    +   int *pCnt = (int*)pContext;
    ++  UNUSED_PARAM2(pUnused, nUnused);
    ++  UNUSED_PARAM2(iUnused1, iUnused2);
    +   if( (tflags & FTS5_TOKEN_COLOCATED)==0 ){
    +     (*pCnt)++;
    +   }
    +@@ -180105,10 +202765,11 @@ static void *fts5ApiGetAuxdata(Fts5Context *pCtx, int bClear){
    + }
    + 
    + static void fts5ApiPhraseNext(
    +-  Fts5Context *pCtx, 
    ++  Fts5Context *pUnused, 
    +   Fts5PhraseIter *pIter, 
    +   int *piCol, int *piOff
    + ){
    ++  UNUSED_PARAM(pUnused);
    +   if( pIter->a>=pIter->b ){
    +     *piCol = -1;
    +     *piOff = -1;
    +@@ -180125,20 +202786,98 @@ static void fts5ApiPhraseNext(
    +   }
    + }
    + 
    +-static void fts5ApiPhraseFirst(
    ++static int fts5ApiPhraseFirst(
    +   Fts5Context *pCtx, 
    +   int iPhrase, 
    +   Fts5PhraseIter *pIter, 
    +   int *piCol, int *piOff
    + ){
    +   Fts5Cursor *pCsr = (Fts5Cursor*)pCtx;
    +-  int n = fts5CsrPoslist(pCsr, iPhrase, &pIter->a);
    +-  pIter->b = &pIter->a[n];
    +-  *piCol = 0;
    +-  *piOff = 0;
    +-  fts5ApiPhraseNext(pCtx, pIter, piCol, piOff);
    ++  int n;
    ++  int rc = fts5CsrPoslist(pCsr, iPhrase, &pIter->a, &n);
    ++  if( rc==SQLITE_OK ){
    ++    pIter->b = &pIter->a[n];
    ++    *piCol = 0;
    ++    *piOff = 0;
    ++    fts5ApiPhraseNext(pCtx, pIter, piCol, piOff);
    ++  }
    ++  return rc;
    ++}
    ++
    ++static void fts5ApiPhraseNextColumn(
    ++  Fts5Context *pCtx, 
    ++  Fts5PhraseIter *pIter, 
    ++  int *piCol
    ++){
    ++  Fts5Cursor *pCsr = (Fts5Cursor*)pCtx;
    ++  Fts5Config *pConfig = ((Fts5Table*)(pCsr->base.pVtab))->pConfig;
    ++
    ++  if( pConfig->eDetail==FTS5_DETAIL_COLUMNS ){
    ++    if( pIter->a>=pIter->b ){
    ++      *piCol = -1;
    ++    }else{
    ++      int iIncr;
    ++      pIter->a += fts5GetVarint32(&pIter->a[0], iIncr);
    ++      *piCol += (iIncr-2);
    ++    }
    ++  }else{
    ++    while( 1 ){
    ++      int dummy;
    ++      if( pIter->a>=pIter->b ){
    ++        *piCol = -1;
    ++        return;
    ++      }
    ++      if( pIter->a[0]==0x01 ) break;
    ++      pIter->a += fts5GetVarint32(pIter->a, dummy);
    ++    }
    ++    pIter->a += 1 + fts5GetVarint32(&pIter->a[1], *piCol);
    ++  }
    ++}
    ++
    ++static int fts5ApiPhraseFirstColumn(
    ++  Fts5Context *pCtx, 
    ++  int iPhrase, 
    ++  Fts5PhraseIter *pIter, 
    ++  int *piCol
    ++){
    ++  int rc = SQLITE_OK;
    ++  Fts5Cursor *pCsr = (Fts5Cursor*)pCtx;
    ++  Fts5Config *pConfig = ((Fts5Table*)(pCsr->base.pVtab))->pConfig;
    ++
    ++  if( pConfig->eDetail==FTS5_DETAIL_COLUMNS ){
    ++    Fts5Sorter *pSorter = pCsr->pSorter;
    ++    int n;
    ++    if( pSorter ){
    ++      int i1 = (iPhrase==0 ? 0 : pSorter->aIdx[iPhrase-1]);
    ++      n = pSorter->aIdx[iPhrase] - i1;
    ++      pIter->a = &pSorter->aPoslist[i1];
    ++    }else{
    ++      rc = sqlite3Fts5ExprPhraseCollist(pCsr->pExpr, iPhrase, &pIter->a, &n);
    ++    }
    ++    if( rc==SQLITE_OK ){
    ++      pIter->b = &pIter->a[n];
    ++      *piCol = 0;
    ++      fts5ApiPhraseNextColumn(pCtx, pIter, piCol);
    ++    }
    ++  }else{
    ++    int n;
    ++    rc = fts5CsrPoslist(pCsr, iPhrase, &pIter->a, &n);
    ++    if( rc==SQLITE_OK ){
    ++      pIter->b = &pIter->a[n];
    ++      if( n<=0 ){
    ++        *piCol = -1;
    ++      }else if( pIter->a[0]==0x01 ){
    ++        pIter->a += 1 + fts5GetVarint32(&pIter->a[1], *piCol);
    ++      }else{
    ++        *piCol = 0;
    ++      }
    ++    }
    ++  }
    ++
    ++  return rc;
    + }
    + 
    ++
    + static int fts5ApiQueryPhrase(Fts5Context*, int, void*, 
    +     int(*)(const Fts5ExtensionApi*, Fts5Context*, void*)
    + );
    +@@ -180162,9 +202901,10 @@ static const Fts5ExtensionApi sFts5Api = {
    +   fts5ApiGetAuxdata,
    +   fts5ApiPhraseFirst,
    +   fts5ApiPhraseNext,
    ++  fts5ApiPhraseFirstColumn,
    ++  fts5ApiPhraseNextColumn,
    + };
    + 
    +-
    + /*
    + ** Implementation of API function xQueryPhrase().
    + */
    +@@ -180181,12 +202921,11 @@ static int fts5ApiQueryPhrase(
    + 
    +   rc = fts5OpenMethod(pCsr->base.pVtab, (sqlite3_vtab_cursor**)&pNew);
    +   if( rc==SQLITE_OK ){
    +-    Fts5Config *pConf = pTab->pConfig;
    +     pNew->ePlan = FTS5_PLAN_MATCH;
    +     pNew->iFirstRowid = SMALLEST_INT64;
    +     pNew->iLastRowid = LARGEST_INT64;
    +     pNew->base.pVtab = (sqlite3_vtab*)pTab;
    +-    rc = sqlite3Fts5ExprClonePhrase(pConf, pCsr->pExpr, iPhrase, &pNew->pExpr);
    ++    rc = sqlite3Fts5ExprClonePhrase(pCsr->pExpr, iPhrase, &pNew->pExpr);
    +   }
    + 
    +   if( rc==SQLITE_OK ){
    +@@ -180256,20 +202995,20 @@ static void fts5ApiCallback(
    + ** Given cursor id iId, return a pointer to the corresponding Fts5Index 
    + ** object. Or NULL If the cursor id does not exist.
    + **
    +-** If successful, set *pnCol to the number of indexed columns in the
    +-** table before returning.
    ++** If successful, set *ppConfig to point to the associated config object 
    ++** before returning.
    + */
    + static Fts5Index *sqlite3Fts5IndexFromCsrid(
    +-  Fts5Global *pGlobal, 
    +-  i64 iCsrId, 
    +-  int *pnCol
    ++  Fts5Global *pGlobal,            /* FTS5 global context for db handle */
    ++  i64 iCsrId,                     /* Id of cursor to find */
    ++  Fts5Config **ppConfig           /* OUT: Configuration object */
    + ){
    +   Fts5Cursor *pCsr;
    +   Fts5Table *pTab;
    + 
    +   pCsr = fts5CursorFromCsrid(pGlobal, iCsrId);
    +   pTab = (Fts5Table*)pCsr->base.pVtab;
    +-  *pnCol = pTab->pConfig->nCol;
    ++  *ppConfig = pTab->pConfig;
    + 
    +   return pTab->pIndex;
    + }
    +@@ -180296,20 +203035,46 @@ static int fts5PoslistBlob(sqlite3_context *pCtx, Fts5Cursor *pCsr){
    +   Fts5Buffer val;
    + 
    +   memset(&val, 0, sizeof(Fts5Buffer));
    ++  switch( ((Fts5Table*)(pCsr->base.pVtab))->pConfig->eDetail ){
    ++    case FTS5_DETAIL_FULL:
    + 
    +-  /* Append the varints */
    +-  for(i=0; i<(nPhrase-1); i++){
    +-    const u8 *dummy;
    +-    int nByte = sqlite3Fts5ExprPoslist(pCsr->pExpr, i, &dummy);
    +-    sqlite3Fts5BufferAppendVarint(&rc, &val, nByte);
    +-  }
    ++      /* Append the varints */
    ++      for(i=0; i<(nPhrase-1); i++){
    ++        const u8 *dummy;
    ++        int nByte = sqlite3Fts5ExprPoslist(pCsr->pExpr, i, &dummy);
    ++        sqlite3Fts5BufferAppendVarint(&rc, &val, nByte);
    ++      }
    ++
    ++      /* Append the position lists */
    ++      for(i=0; i<nPhrase; i++){
    ++        const u8 *pPoslist;
    ++        int nPoslist;
    ++        nPoslist = sqlite3Fts5ExprPoslist(pCsr->pExpr, i, &pPoslist);
    ++        sqlite3Fts5BufferAppendBlob(&rc, &val, nPoslist, pPoslist);
    ++      }
    ++      break;
    ++
    ++    case FTS5_DETAIL_COLUMNS:
    ++
    ++      /* Append the varints */
    ++      for(i=0; rc==SQLITE_OK && i<(nPhrase-1); i++){
    ++        const u8 *dummy;
    ++        int nByte;
    ++        rc = sqlite3Fts5ExprPhraseCollist(pCsr->pExpr, i, &dummy, &nByte);
    ++        sqlite3Fts5BufferAppendVarint(&rc, &val, nByte);
    ++      }
    + 
    +-  /* Append the position lists */
    +-  for(i=0; i<nPhrase; i++){
    +-    const u8 *pPoslist;
    +-    int nPoslist;
    +-    nPoslist = sqlite3Fts5ExprPoslist(pCsr->pExpr, i, &pPoslist);
    +-    sqlite3Fts5BufferAppendBlob(&rc, &val, nPoslist, pPoslist);
    ++      /* Append the position lists */
    ++      for(i=0; rc==SQLITE_OK && i<nPhrase; i++){
    ++        const u8 *pPoslist;
    ++        int nPoslist;
    ++        rc = sqlite3Fts5ExprPhraseCollist(pCsr->pExpr, i, &pPoslist, &nPoslist);
    ++        sqlite3Fts5BufferAppendBlob(&rc, &val, nPoslist, pPoslist);
    ++      }
    ++      break;
    ++
    ++    default:
    ++      break;
    +   }
    + 
    +   sqlite3_result_blob(pCtx, val.p, val.n, sqlite3_free);
    +@@ -180373,7 +203138,7 @@ static int fts5ColumnMethod(
    + */
    + static int fts5FindFunctionMethod(
    +   sqlite3_vtab *pVtab,            /* Virtual table handle */
    +-  int nArg,                       /* Number of SQL function arguments */
    ++  int nUnused,                    /* Number of SQL function arguments */
    +   const char *zName,              /* Name of SQL function */
    +   void (**pxFunc)(sqlite3_context*,int,sqlite3_value**), /* OUT: Result */
    +   void **ppArg                    /* OUT: User data for *pxFunc */
    +@@ -180381,6 +203146,7 @@ static int fts5FindFunctionMethod(
    +   Fts5Table *pTab = (Fts5Table*)pVtab;
    +   Fts5Auxiliary *pAux;
    + 
    ++  UNUSED_PARAM(nUnused);
    +   pAux = fts5FindAuxiliary(pTab, zName);
    +   if( pAux ){
    +     *pxFunc = fts5ApiCallback;
    +@@ -180410,9 +203176,10 @@ static int fts5RenameMethod(
    + */
    + static int fts5SavepointMethod(sqlite3_vtab *pVtab, int iSavepoint){
    +   Fts5Table *pTab = (Fts5Table*)pVtab;
    ++  UNUSED_PARAM(iSavepoint);  /* Call below is a no-op for NDEBUG builds */
    +   fts5CheckTransactionState(pTab, FTS5_SAVEPOINT, iSavepoint);
    +   fts5TripCursors(pTab);
    +-  return sqlite3Fts5StorageSync(pTab->pStorage, 0);
    ++  return sqlite3Fts5StorageSync(pTab->pStorage);
    + }
    + 
    + /*
    +@@ -180422,9 +203189,10 @@ static int fts5SavepointMethod(sqlite3_vtab *pVtab, int iSavepoint){
    + */
    + static int fts5ReleaseMethod(sqlite3_vtab *pVtab, int iSavepoint){
    +   Fts5Table *pTab = (Fts5Table*)pVtab;
    ++  UNUSED_PARAM(iSavepoint);  /* Call below is a no-op for NDEBUG builds */
    +   fts5CheckTransactionState(pTab, FTS5_RELEASE, iSavepoint);
    +   fts5TripCursors(pTab);
    +-  return sqlite3Fts5StorageSync(pTab->pStorage, 0);
    ++  return sqlite3Fts5StorageSync(pTab->pStorage);
    + }
    + 
    + /*
    +@@ -180434,6 +203202,7 @@ static int fts5ReleaseMethod(sqlite3_vtab *pVtab, int iSavepoint){
    + */
    + static int fts5RollbackToMethod(sqlite3_vtab *pVtab, int iSavepoint){
    +   Fts5Table *pTab = (Fts5Table*)pVtab;
    ++  UNUSED_PARAM(iSavepoint);  /* Call below is a no-op for NDEBUG builds */
    +   fts5CheckTransactionState(pTab, FTS5_ROLLBACKTO, iSavepoint);
    +   fts5TripCursors(pTab);
    +   return sqlite3Fts5StorageRollback(pTab->pStorage);
    +@@ -180613,14 +203382,14 @@ static void fts5ModuleDestroy(void *pCtx){
    + static void fts5Fts5Func(
    +   sqlite3_context *pCtx,          /* Function call context */
    +   int nArg,                       /* Number of args */
    +-  sqlite3_value **apVal           /* Function arguments */
    ++  sqlite3_value **apArg           /* Function arguments */
    + ){
    +   Fts5Global *pGlobal = (Fts5Global*)sqlite3_user_data(pCtx);
    +-  char buf[8];
    +-  assert( nArg==0 );
    +-  assert( sizeof(buf)>=sizeof(pGlobal) );
    +-  memcpy(buf, (void*)&pGlobal, sizeof(pGlobal));
    +-  sqlite3_result_blob(pCtx, buf, sizeof(pGlobal), SQLITE_TRANSIENT);
    ++  fts5_api **ppApi;
    ++  UNUSED_PARAM(nArg);
    ++  assert( nArg==1 );
    ++  ppApi = (fts5_api**)sqlite3_value_pointer(apArg[0], "fts5_api_ptr");
    ++  if( ppApi ) *ppApi = &pGlobal->api;
    + }
    + 
    + /*
    +@@ -180629,10 +203398,11 @@ static void fts5Fts5Func(
    + static void fts5SourceIdFunc(
    +   sqlite3_context *pCtx,          /* Function call context */
    +   int nArg,                       /* Number of args */
    +-  sqlite3_value **apVal           /* Function arguments */
    ++  sqlite3_value **apUnused        /* Function arguments */
    + ){
    +   assert( nArg==0 );
    +-  sqlite3_result_text(pCtx, "fts5: 2015-11-02 18:31:45 bda77dda9697c463c3d0704014d51627fceee328", -1, SQLITE_TRANSIENT);
    ++  UNUSED_PARAM2(nArg, apUnused);
    ++  sqlite3_result_text(pCtx, "fts5: 2018-12-19 01:30:22 c255889bd95bd5430dc7ced3317011ae2abb483d6c9af883af3dc7d6c2c2f234", -1, SQLITE_TRANSIENT);
    + }
    + 
    + static int fts5Init(sqlite3 *db){
    +@@ -180684,7 +203454,7 @@ static int fts5Init(sqlite3 *db){
    +     if( rc==SQLITE_OK ) rc = sqlite3Fts5VocabInit(pGlobal, db);
    +     if( rc==SQLITE_OK ){
    +       rc = sqlite3_create_function(
    +-          db, "fts5", 0, SQLITE_UTF8, p, fts5Fts5Func, 0, 0
    ++          db, "fts5", 1, SQLITE_UTF8, p, fts5Fts5Func, 0, 0
    +       );
    +     }
    +     if( rc==SQLITE_OK ){
    +@@ -180693,6 +203463,17 @@ static int fts5Init(sqlite3 *db){
    +       );
    +     }
    +   }
    ++
    ++  /* If SQLITE_FTS5_ENABLE_TEST_MI is defined, assume that the file
    ++  ** fts5_test_mi.c is compiled and linked into the executable. And call
    ++  ** its entry point to enable the matchinfo() demo.  */
    ++#ifdef SQLITE_FTS5_ENABLE_TEST_MI
    ++  if( rc==SQLITE_OK ){
    ++    extern int sqlite3Fts5TestRegisterMatchinfo(sqlite3*);
    ++    rc = sqlite3Fts5TestRegisterMatchinfo(db);
    ++  }
    ++#endif
    ++
    +   return rc;
    + }
    + 
    +@@ -180709,7 +203490,7 @@ static int fts5Init(sqlite3 *db){
    + #ifdef _WIN32
    + __declspec(dllexport)
    + #endif
    +-SQLITE_API int SQLITE_STDCALL sqlite3_fts_init(
    ++SQLITE_API int sqlite3_fts_init(
    +   sqlite3 *db,
    +   char **pzErrMsg,
    +   const sqlite3_api_routines *pApi
    +@@ -180722,7 +203503,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_fts_init(
    + #ifdef _WIN32
    + __declspec(dllexport)
    + #endif
    +-SQLITE_API int SQLITE_STDCALL sqlite3_fts5_init(
    ++SQLITE_API int sqlite3_fts5_init(
    +   sqlite3 *db,
    +   char **pzErrMsg,
    +   const sqlite3_api_routines *pApi
    +@@ -180753,6 +203534,7 @@ SQLITE_PRIVATE int sqlite3Fts5Init(sqlite3 *db){
    + 
    + 
    + 
    ++/* #include "fts5Int.h" */
    + 
    + struct Fts5Storage {
    +   Fts5Config *pConfig;
    +@@ -180874,7 +203656,8 @@ static int fts5StorageGetStmt(
    +     if( zSql==0 ){
    +       rc = SQLITE_NOMEM;
    +     }else{
    +-      rc = sqlite3_prepare_v2(pC->db, zSql, -1, &p->aStmt[eStmt], 0);
    ++      rc = sqlite3_prepare_v3(pC->db, zSql, -1,
    ++                              SQLITE_PREPARE_PERSISTENT, &p->aStmt[eStmt], 0);
    +       sqlite3_free(zSql);
    +       if( rc!=SQLITE_OK && pzErrMsg ){
    +         *pzErrMsg = sqlite3_mprintf("%s", sqlite3_errmsg(pC->db));
    +@@ -180883,6 +203666,7 @@ static int fts5StorageGetStmt(
    +   }
    + 
    +   *ppStmt = p->aStmt[eStmt];
    ++  sqlite3_reset(*ppStmt);
    +   return rc;
    + }
    + 
    +@@ -180955,7 +203739,7 @@ static void fts5StorageRenameOne(
    + 
    + static int sqlite3Fts5StorageRename(Fts5Storage *pStorage, const char *zName){
    +   Fts5Config *pConfig = pStorage->pConfig;
    +-  int rc = sqlite3Fts5StorageSync(pStorage, 1);
    ++  int rc = sqlite3Fts5StorageSync(pStorage);
    + 
    +   fts5StorageRenameOne(pConfig, &rc, "data", zName);
    +   fts5StorageRenameOne(pConfig, &rc, "idx", zName);
    +@@ -180984,7 +203768,11 @@ static int sqlite3Fts5CreateTable(
    +   char *zErr = 0;
    + 
    +   rc = fts5ExecPrintf(pConfig->db, &zErr, "CREATE TABLE %Q.'%q_%q'(%s)%s",
    +-      pConfig->zDb, pConfig->zName, zPost, zDefn, bWithout?" WITHOUT ROWID":""
    ++      pConfig->zDb, pConfig->zName, zPost, zDefn, 
    ++#ifndef SQLITE_FTS5_NO_WITHOUT_ROWID
    ++      bWithout?" WITHOUT ROWID":
    ++#endif
    ++      ""
    +   );
    +   if( zErr ){
    +     *pzErr = sqlite3_mprintf(
    +@@ -181035,10 +203823,10 @@ static int sqlite3Fts5StorageOpen(
    +         int i;
    +         int iOff;
    +         sqlite3_snprintf(nDefn, zDefn, "id INTEGER PRIMARY KEY");
    +-        iOff = strlen(zDefn);
    ++        iOff = (int)strlen(zDefn);
    +         for(i=0; i<pConfig->nCol; i++){
    +           sqlite3_snprintf(nDefn-iOff, &zDefn[iOff], ", c%d", i);
    +-          iOff += strlen(&zDefn[iOff]);
    ++          iOff += (int)strlen(&zDefn[iOff]);
    +         }
    +         rc = sqlite3Fts5CreateTable(pConfig, "content", zDefn, 0, pzErr);
    +       }
    +@@ -181100,11 +203888,13 @@ static int fts5StorageInsertCallback(
    +   int tflags,
    +   const char *pToken,             /* Buffer containing token */
    +   int nToken,                     /* Size of token in bytes */
    +-  int iStart,                     /* Start offset of token */
    +-  int iEnd                        /* End offset of token */
    ++  int iUnused1,                   /* Start offset of token */
    ++  int iUnused2                    /* End offset of token */
    + ){
    +   Fts5InsertCtx *pCtx = (Fts5InsertCtx*)pContext;
    +   Fts5Index *pIdx = pCtx->pStorage->pIndex;
    ++  UNUSED_PARAM2(iUnused1, iUnused2);
    ++  if( nToken>FTS5_MAX_TOKEN_SIZE ) nToken = FTS5_MAX_TOKEN_SIZE;
    +   if( (tflags & FTS5_TOKEN_COLOCATED)==0 || pCtx->szCol==0 ){
    +     pCtx->szCol++;
    +   }
    +@@ -181116,39 +203906,52 @@ static int fts5StorageInsertCallback(
    + ** delete-markers to the FTS index necessary to delete it. Do not actually
    + ** remove the %_content row at this time though.
    + */
    +-static int fts5StorageDeleteFromIndex(Fts5Storage *p, i64 iDel){
    ++static int fts5StorageDeleteFromIndex(
    ++  Fts5Storage *p, 
    ++  i64 iDel, 
    ++  sqlite3_value **apVal
    ++){
    +   Fts5Config *pConfig = p->pConfig;
    +-  sqlite3_stmt *pSeek;            /* SELECT to read row iDel from %_data */
    ++  sqlite3_stmt *pSeek = 0;        /* SELECT to read row iDel from %_data */
    +   int rc;                         /* Return code */
    ++  int rc2;                        /* sqlite3_reset() return code */
    ++  int iCol;
    ++  Fts5InsertCtx ctx;
    + 
    +-  rc = fts5StorageGetStmt(p, FTS5_STMT_LOOKUP, &pSeek, 0);
    +-  if( rc==SQLITE_OK ){
    +-    int rc2;
    ++  if( apVal==0 ){
    ++    rc = fts5StorageGetStmt(p, FTS5_STMT_LOOKUP, &pSeek, 0);
    ++    if( rc!=SQLITE_OK ) return rc;
    +     sqlite3_bind_int64(pSeek, 1, iDel);
    +-    if( sqlite3_step(pSeek)==SQLITE_ROW ){
    +-      int iCol;
    +-      Fts5InsertCtx ctx;
    +-      ctx.pStorage = p;
    +-      ctx.iCol = -1;
    +-      rc = sqlite3Fts5IndexBeginWrite(p->pIndex, 1, iDel);
    +-      for(iCol=1; rc==SQLITE_OK && iCol<=pConfig->nCol; iCol++){
    +-        if( pConfig->abUnindexed[iCol-1] ) continue;
    +-        ctx.szCol = 0;
    +-        rc = sqlite3Fts5Tokenize(pConfig, 
    +-            FTS5_TOKENIZE_DOCUMENT,
    +-            (const char*)sqlite3_column_text(pSeek, iCol),
    +-            sqlite3_column_bytes(pSeek, iCol),
    +-            (void*)&ctx,
    +-            fts5StorageInsertCallback
    +-        );
    +-        p->aTotalSize[iCol-1] -= (i64)ctx.szCol;
    ++    if( sqlite3_step(pSeek)!=SQLITE_ROW ){
    ++      return sqlite3_reset(pSeek);
    ++    }
    ++  }
    ++
    ++  ctx.pStorage = p;
    ++  ctx.iCol = -1;
    ++  rc = sqlite3Fts5IndexBeginWrite(p->pIndex, 1, iDel);
    ++  for(iCol=1; rc==SQLITE_OK && iCol<=pConfig->nCol; iCol++){
    ++    if( pConfig->abUnindexed[iCol-1]==0 ){
    ++      const char *zText;
    ++      int nText;
    ++      if( pSeek ){
    ++        zText = (const char*)sqlite3_column_text(pSeek, iCol);
    ++        nText = sqlite3_column_bytes(pSeek, iCol);
    ++      }else{
    ++        zText = (const char*)sqlite3_value_text(apVal[iCol-1]);
    ++        nText = sqlite3_value_bytes(apVal[iCol-1]);
    +       }
    +-      p->nTotalRow--;
    ++      ctx.szCol = 0;
    ++      rc = sqlite3Fts5Tokenize(pConfig, FTS5_TOKENIZE_DOCUMENT, 
    ++          zText, nText, (void*)&ctx, fts5StorageInsertCallback
    ++      );
    ++      p->aTotalSize[iCol-1] -= (i64)ctx.szCol;
    +     }
    +-    rc2 = sqlite3_reset(pSeek);
    +-    if( rc==SQLITE_OK ) rc = rc2;
    +   }
    ++  p->nTotalRow--;
    + 
    ++  rc2 = sqlite3_reset(pSeek);
    ++  if( rc==SQLITE_OK ) rc = rc2;
    +   return rc;
    + }
    + 
    +@@ -181228,16 +204031,17 @@ static int fts5StorageSaveTotals(Fts5Storage *p){
    + /*
    + ** Remove a row from the FTS table.
    + */
    +-static int sqlite3Fts5StorageDelete(Fts5Storage *p, i64 iDel){
    ++static int sqlite3Fts5StorageDelete(Fts5Storage *p, i64 iDel, sqlite3_value **apVal){
    +   Fts5Config *pConfig = p->pConfig;
    +   int rc;
    +   sqlite3_stmt *pDel = 0;
    + 
    ++  assert( pConfig->eContent!=FTS5_CONTENT_NORMAL || apVal==0 );
    +   rc = fts5StorageLoadTotals(p, 1);
    + 
    +   /* Delete the index records */
    +   if( rc==SQLITE_OK ){
    +-    rc = fts5StorageDeleteFromIndex(p, iDel);
    ++    rc = fts5StorageDeleteFromIndex(p, iDel, apVal);
    +   }
    + 
    +   /* Delete the %_docsize record */
    +@@ -181251,62 +204055,9 @@ static int sqlite3Fts5StorageDelete(Fts5Storage *p, i64 iDel){
    +   }
    + 
    +   /* Delete the %_content record */
    +-  if( rc==SQLITE_OK ){
    +-    rc = fts5StorageGetStmt(p, FTS5_STMT_DELETE_CONTENT, &pDel, 0);
    +-  }
    +-  if( rc==SQLITE_OK ){
    +-    sqlite3_bind_int64(pDel, 1, iDel);
    +-    sqlite3_step(pDel);
    +-    rc = sqlite3_reset(pDel);
    +-  }
    +-
    +-  /* Write the averages record */
    +-  if( rc==SQLITE_OK ){
    +-    rc = fts5StorageSaveTotals(p);
    +-  }
    +-
    +-  return rc;
    +-}
    +-
    +-static int sqlite3Fts5StorageSpecialDelete(
    +-  Fts5Storage *p, 
    +-  i64 iDel, 
    +-  sqlite3_value **apVal
    +-){
    +-  Fts5Config *pConfig = p->pConfig;
    +-  int rc;
    +-  sqlite3_stmt *pDel = 0;
    +-
    +-  assert( pConfig->eContent!=FTS5_CONTENT_NORMAL );
    +-  rc = fts5StorageLoadTotals(p, 1);
    +-
    +-  /* Delete the index records */
    +-  if( rc==SQLITE_OK ){
    +-    int iCol;
    +-    Fts5InsertCtx ctx;
    +-    ctx.pStorage = p;
    +-    ctx.iCol = -1;
    +-
    +-    rc = sqlite3Fts5IndexBeginWrite(p->pIndex, 1, iDel);
    +-    for(iCol=0; rc==SQLITE_OK && iCol<pConfig->nCol; iCol++){
    +-      if( pConfig->abUnindexed[iCol] ) continue;
    +-      ctx.szCol = 0;
    +-      rc = sqlite3Fts5Tokenize(pConfig, 
    +-        FTS5_TOKENIZE_DOCUMENT,
    +-        (const char*)sqlite3_value_text(apVal[iCol]),
    +-        sqlite3_value_bytes(apVal[iCol]),
    +-        (void*)&ctx,
    +-        fts5StorageInsertCallback
    +-      );
    +-      p->aTotalSize[iCol] -= (i64)ctx.szCol;
    +-    }
    +-    p->nTotalRow--;
    +-  }
    +-
    +-  /* Delete the %_docsize record */
    +-  if( pConfig->bColumnsize ){
    ++  if( pConfig->eContent==FTS5_CONTENT_NORMAL ){
    +     if( rc==SQLITE_OK ){
    +-      rc = fts5StorageGetStmt(p, FTS5_STMT_DELETE_DOCSIZE, &pDel, 0);
    ++      rc = fts5StorageGetStmt(p, FTS5_STMT_DELETE_CONTENT, &pDel, 0);
    +     }
    +     if( rc==SQLITE_OK ){
    +       sqlite3_bind_int64(pDel, 1, iDel);
    +@@ -181315,11 +204066,6 @@ static int sqlite3Fts5StorageSpecialDelete(
    +     }
    +   }
    + 
    +-  /* Write the averages record */
    +-  if( rc==SQLITE_OK ){
    +-    rc = fts5StorageSaveTotals(p);
    +-  }
    +-
    +   return rc;
    + }
    + 
    +@@ -181415,6 +204161,10 @@ static int sqlite3Fts5StorageMerge(Fts5Storage *p, int nMerge){
    +   return sqlite3Fts5IndexMerge(p->pIndex, nMerge);
    + }
    + 
    ++static int sqlite3Fts5StorageReset(Fts5Storage *p){
    ++  return sqlite3Fts5IndexReset(p->pIndex);
    ++}
    ++
    + /*
    + ** Allocate a new rowid. This is used for "external content" tables when
    + ** a NULL value is inserted into the rowid column. The new rowid is allocated
    +@@ -181463,17 +204213,7 @@ static int sqlite3Fts5StorageContentInsert(
    +   }else{
    +     sqlite3_stmt *pInsert = 0;    /* Statement to write %_content table */
    +     int i;                        /* Counter variable */
    +-#if 0
    +-    if( eConflict==SQLITE_REPLACE ){
    +-      eStmt = FTS5_STMT_REPLACE_CONTENT;
    +-      rc = fts5StorageDeleteFromIndex(p, sqlite3_value_int64(apVal[1]));
    +-    }else{
    +-      eStmt = FTS5_STMT_INSERT_CONTENT;
    +-    }
    +-#endif
    +-    if( rc==SQLITE_OK ){
    +-      rc = fts5StorageGetStmt(p, FTS5_STMT_INSERT_CONTENT, &pInsert, 0);
    +-    }
    ++    rc = fts5StorageGetStmt(p, FTS5_STMT_INSERT_CONTENT, &pInsert, 0);
    +     for(i=1; rc==SQLITE_OK && i<=pConfig->nCol+1; i++){
    +       rc = sqlite3_bind_value(pInsert, i, apVal[i]);
    +     }
    +@@ -181529,11 +204269,6 @@ static int sqlite3Fts5StorageIndexInsert(
    +   }
    +   sqlite3_free(buf.p);
    + 
    +-  /* Write the averages record */
    +-  if( rc==SQLITE_OK ){
    +-    rc = fts5StorageSaveTotals(p);
    +-  }
    +-
    +   return rc;
    + }
    + 
    +@@ -181571,28 +204306,76 @@ struct Fts5IntegrityCtx {
    +   int iCol;
    +   int szCol;
    +   u64 cksum;
    ++  Fts5Termset *pTermset;
    +   Fts5Config *pConfig;
    + };
    + 
    ++
    + /*
    + ** Tokenization callback used by integrity check.
    + */
    + static int fts5StorageIntegrityCallback(
    +-  void *pContext,                 /* Pointer to Fts5InsertCtx object */
    ++  void *pContext,                 /* Pointer to Fts5IntegrityCtx object */
    +   int tflags,
    +   const char *pToken,             /* Buffer containing token */
    +   int nToken,                     /* Size of token in bytes */
    +-  int iStart,                     /* Start offset of token */
    +-  int iEnd                        /* End offset of token */
    ++  int iUnused1,                   /* Start offset of token */
    ++  int iUnused2                    /* End offset of token */
    + ){
    +   Fts5IntegrityCtx *pCtx = (Fts5IntegrityCtx*)pContext;
    ++  Fts5Termset *pTermset = pCtx->pTermset;
    ++  int bPresent;
    ++  int ii;
    ++  int rc = SQLITE_OK;
    ++  int iPos;
    ++  int iCol;
    ++
    ++  UNUSED_PARAM2(iUnused1, iUnused2);
    ++  if( nToken>FTS5_MAX_TOKEN_SIZE ) nToken = FTS5_MAX_TOKEN_SIZE;
    ++
    +   if( (tflags & FTS5_TOKEN_COLOCATED)==0 || pCtx->szCol==0 ){
    +     pCtx->szCol++;
    +   }
    +-  pCtx->cksum ^= sqlite3Fts5IndexCksum(
    +-      pCtx->pConfig, pCtx->iRowid, pCtx->iCol, pCtx->szCol-1, pToken, nToken
    +-  );
    +-  return SQLITE_OK;
    ++
    ++  switch( pCtx->pConfig->eDetail ){
    ++    case FTS5_DETAIL_FULL:
    ++      iPos = pCtx->szCol-1;
    ++      iCol = pCtx->iCol;
    ++      break;
    ++
    ++    case FTS5_DETAIL_COLUMNS:
    ++      iPos = pCtx->iCol;
    ++      iCol = 0;
    ++      break;
    ++
    ++    default:
    ++      assert( pCtx->pConfig->eDetail==FTS5_DETAIL_NONE );
    ++      iPos = 0;
    ++      iCol = 0;
    ++      break;
    ++  }
    ++
    ++  rc = sqlite3Fts5TermsetAdd(pTermset, 0, pToken, nToken, &bPresent);
    ++  if( rc==SQLITE_OK && bPresent==0 ){
    ++    pCtx->cksum ^= sqlite3Fts5IndexEntryCksum(
    ++        pCtx->iRowid, iCol, iPos, 0, pToken, nToken
    ++    );
    ++  }
    ++
    ++  for(ii=0; rc==SQLITE_OK && ii<pCtx->pConfig->nPrefix; ii++){
    ++    const int nChar = pCtx->pConfig->aPrefix[ii];
    ++    int nByte = sqlite3Fts5IndexCharlenToBytelen(pToken, nToken, nChar);
    ++    if( nByte ){
    ++      rc = sqlite3Fts5TermsetAdd(pTermset, ii+1, pToken, nByte, &bPresent);
    ++      if( bPresent==0 ){
    ++        pCtx->cksum ^= sqlite3Fts5IndexEntryCksum(
    ++            pCtx->iRowid, iCol, iPos, ii+1, pToken, nByte
    ++        );
    ++      }
    ++    }
    ++  }
    ++
    ++  return rc;
    + }
    + 
    + /*
    +@@ -181628,22 +204411,37 @@ static int sqlite3Fts5StorageIntegrity(Fts5Storage *p){
    +       if( pConfig->bColumnsize ){
    +         rc = sqlite3Fts5StorageDocsize(p, ctx.iRowid, aColSize);
    +       }
    ++      if( rc==SQLITE_OK && pConfig->eDetail==FTS5_DETAIL_NONE ){
    ++        rc = sqlite3Fts5TermsetNew(&ctx.pTermset);
    ++      }
    +       for(i=0; rc==SQLITE_OK && i<pConfig->nCol; i++){
    +         if( pConfig->abUnindexed[i] ) continue;
    +         ctx.iCol = i;
    +         ctx.szCol = 0;
    +-        rc = sqlite3Fts5Tokenize(pConfig, 
    +-            FTS5_TOKENIZE_DOCUMENT,
    +-            (const char*)sqlite3_column_text(pScan, i+1),
    +-            sqlite3_column_bytes(pScan, i+1),
    +-            (void*)&ctx,
    +-            fts5StorageIntegrityCallback
    +-        );
    +-        if( pConfig->bColumnsize && ctx.szCol!=aColSize[i] ){
    ++        if( pConfig->eDetail==FTS5_DETAIL_COLUMNS ){
    ++          rc = sqlite3Fts5TermsetNew(&ctx.pTermset);
    ++        }
    ++        if( rc==SQLITE_OK ){
    ++          rc = sqlite3Fts5Tokenize(pConfig, 
    ++              FTS5_TOKENIZE_DOCUMENT,
    ++              (const char*)sqlite3_column_text(pScan, i+1),
    ++              sqlite3_column_bytes(pScan, i+1),
    ++              (void*)&ctx,
    ++              fts5StorageIntegrityCallback
    ++          );
    ++        }
    ++        if( rc==SQLITE_OK && pConfig->bColumnsize && ctx.szCol!=aColSize[i] ){
    +           rc = FTS5_CORRUPT;
    +         }
    +         aTotalSize[i] += ctx.szCol;
    ++        if( pConfig->eDetail==FTS5_DETAIL_COLUMNS ){
    ++          sqlite3Fts5TermsetFree(ctx.pTermset);
    ++          ctx.pTermset = 0;
    ++        }
    +       }
    ++      sqlite3Fts5TermsetFree(ctx.pTermset);
    ++      ctx.pTermset = 0;
    ++
    +       if( rc!=SQLITE_OK ) break;
    +     }
    +     rc2 = sqlite3_reset(pScan);
    +@@ -181662,12 +204460,12 @@ static int sqlite3Fts5StorageIntegrity(Fts5Storage *p){
    +   /* Check that the %_docsize and %_content tables contain the expected
    +   ** number of rows.  */
    +   if( rc==SQLITE_OK && pConfig->eContent==FTS5_CONTENT_NORMAL ){
    +-    i64 nRow;
    ++    i64 nRow = 0;
    +     rc = fts5StorageCount(p, "content", &nRow);
    +     if( rc==SQLITE_OK && nRow!=p->nTotalRow ) rc = FTS5_CORRUPT;
    +   }
    +   if( rc==SQLITE_OK && pConfig->bColumnsize ){
    +-    i64 nRow;
    ++    i64 nRow = 0;
    +     rc = fts5StorageCount(p, "docsize", &nRow);
    +     if( rc==SQLITE_OK && nRow!=p->nTotalRow ) rc = FTS5_CORRUPT;
    +   }
    +@@ -181804,13 +204602,18 @@ static int sqlite3Fts5StorageRowCount(Fts5Storage *p, i64 *pnRow){
    + /*
    + ** Flush any data currently held in-memory to disk.
    + */
    +-static int sqlite3Fts5StorageSync(Fts5Storage *p, int bCommit){
    +-  if( bCommit && p->bTotalsValid ){
    +-    int rc = fts5StorageSaveTotals(p);
    ++static int sqlite3Fts5StorageSync(Fts5Storage *p){
    ++  int rc = SQLITE_OK;
    ++  i64 iLastRowid = sqlite3_last_insert_rowid(p->pConfig->db);
    ++  if( p->bTotalsValid ){
    ++    rc = fts5StorageSaveTotals(p);
    +     p->bTotalsValid = 0;
    +-    if( rc!=SQLITE_OK ) return rc;
    +   }
    +-  return sqlite3Fts5IndexSync(p->pIndex, bCommit);
    ++  if( rc==SQLITE_OK ){
    ++    rc = sqlite3Fts5IndexSync(p->pIndex);
    ++  }
    ++  sqlite3_set_last_insert_rowid(p->pConfig->db, iLastRowid);
    ++  return rc;
    + }
    + 
    + static int sqlite3Fts5StorageRollback(Fts5Storage *p){
    +@@ -181846,8 +204649,6 @@ static int sqlite3Fts5StorageConfigValue(
    +   return rc;
    + }
    + 
    +-
    +-
    + /*
    + ** 2014 May 31
    + **
    +@@ -181862,6 +204663,7 @@ static int sqlite3Fts5StorageConfigValue(
    + */
    + 
    + 
    ++/* #include "fts5Int.h" */
    + 
    + /**************************************************************************
    + ** Start of ascii tokenizer implementation.
    +@@ -181911,12 +204713,13 @@ static void fts5AsciiDelete(Fts5Tokenizer *p){
    + ** Create an "ascii" tokenizer.
    + */
    + static int fts5AsciiCreate(
    +-  void *pCtx, 
    ++  void *pUnused, 
    +   const char **azArg, int nArg,
    +   Fts5Tokenizer **ppOut
    + ){
    +   int rc = SQLITE_OK;
    +   AsciiTokenizer *p = 0;
    ++  UNUSED_PARAM(pUnused);
    +   if( nArg%2 ){
    +     rc = SQLITE_ERROR;
    +   }else{
    +@@ -181965,7 +204768,7 @@ static void asciiFold(char *aOut, const char *aIn, int nByte){
    + static int fts5AsciiTokenize(
    +   Fts5Tokenizer *pTokenizer,
    +   void *pCtx,
    +-  int flags,
    ++  int iUnused,
    +   const char *pText, int nText,
    +   int (*xToken)(void*, int, const char*, int nToken, int iStart, int iEnd)
    + ){
    +@@ -181979,6 +204782,8 @@ static int fts5AsciiTokenize(
    +   char *pFold = aFold;
    +   unsigned char *a = p->aTokenChar;
    + 
    ++  UNUSED_PARAM(iUnused);
    ++
    +   while( is<nText && rc==SQLITE_OK ){
    +     int nByte;
    + 
    +@@ -182091,7 +204896,7 @@ static int fts5UnicodeAddExceptions(
    +   int bTokenChars                 /* 1 for 'tokenchars', 0 for 'separators' */
    + ){
    +   int rc = SQLITE_OK;
    +-  int n = strlen(z);
    ++  int n = (int)strlen(z);
    +   int *aNew;
    + 
    +   if( n>0 ){
    +@@ -182105,7 +204910,7 @@ static int fts5UnicodeAddExceptions(
    +         int bToken;
    +         READ_UTF8(zCsr, zTerm, iCode);
    +         if( iCode<128 ){
    +-          p->aTokenChar[iCode] = bTokenChars;
    ++          p->aTokenChar[iCode] = (unsigned char)bTokenChars;
    +         }else{
    +           bToken = sqlite3Fts5UnicodeIsalnum(iCode);
    +           assert( (bToken==0 || bToken==1) ); 
    +@@ -182172,13 +204977,15 @@ static void fts5UnicodeDelete(Fts5Tokenizer *pTok){
    + ** Create a "unicode61" tokenizer.
    + */
    + static int fts5UnicodeCreate(
    +-  void *pCtx, 
    ++  void *pUnused, 
    +   const char **azArg, int nArg,
    +   Fts5Tokenizer **ppOut
    + ){
    +   int rc = SQLITE_OK;             /* Return code */
    +   Unicode61Tokenizer *p = 0;      /* New tokenizer object */ 
    + 
    ++  UNUSED_PARAM(pUnused);
    ++
    +   if( nArg%2 ){
    +     rc = SQLITE_ERROR;
    +   }else{
    +@@ -182235,7 +205042,7 @@ static int fts5UnicodeIsAlnum(Unicode61Tokenizer *p, int iCode){
    + static int fts5UnicodeTokenize(
    +   Fts5Tokenizer *pTokenizer,
    +   void *pCtx,
    +-  int flags,
    ++  int iUnused,
    +   const char *pText, int nText,
    +   int (*xToken)(void*, int, const char*, int nToken, int iStart, int iEnd)
    + ){
    +@@ -182251,6 +205058,8 @@ static int fts5UnicodeTokenize(
    +   int nFold = p->nFold;
    +   const char *pEnd = &aFold[nFold-6];
    + 
    ++  UNUSED_PARAM(iUnused);
    ++
    +   /* Each iteration of this loop gobbles up a contiguous run of separators,
    +   ** then the next token.  */
    +   while( rc==SQLITE_OK ){
    +@@ -183069,7 +205878,7 @@ static int sqlite3Fts5TokenizerInit(fts5_api *pApi){
    +   int rc = SQLITE_OK;             /* Return code */
    +   int i;                          /* To iterate through builtin functions */
    + 
    +-  for(i=0; rc==SQLITE_OK && i<sizeof(aBuiltin)/sizeof(aBuiltin[0]); i++){
    ++  for(i=0; rc==SQLITE_OK && i<ArraySize(aBuiltin); i++){
    +     rc = pApi->xCreateTokenizer(pApi,
    +         aBuiltin[i].zName,
    +         (void*)pApi,
    +@@ -183210,9 +206019,9 @@ static int sqlite3Fts5UnicodeIsalnum(int c){
    +     0xFFFFFFFF, 0xFC00FFFF, 0xF8000001, 0xF8000001,
    +   };
    + 
    +-  if( c<128 ){
    ++  if( (unsigned int)c<128 ){
    +     return ( (aAscii[c >> 5] & (1 << (c & 0x001F)))==0 );
    +-  }else if( c<(1<<22) ){
    ++  }else if( (unsigned int)c<(1<<22) ){
    +     unsigned int key = (((unsigned int)c)<<10) | 0x000003FF;
    +     int iRes = 0;
    +     int iHi = sizeof(aEntry)/sizeof(aEntry[0]) - 1;
    +@@ -183460,6 +206269,7 @@ static int sqlite3Fts5UnicodeFold(int c, int bRemoveDiacritic){
    + */
    + 
    + 
    ++/* #include "fts5Int.h" */
    + 
    + /*
    + ** This is a copy of the sqlite3GetVarint32() routine from the SQLite core.
    +@@ -183778,7 +206588,10 @@ static int sqlite3Fts5PutVarint(unsigned char *p, u64 v){
    + 
    + 
    + static int sqlite3Fts5GetVarintLen(u32 iVal){
    ++#if 0
    +   if( iVal<(1 << 7 ) ) return 1;
    ++#endif
    ++  assert( iVal>=(1 << 7) );
    +   if( iVal<(1 << 14) ) return 2;
    +   if( iVal<(1 << 21) ) return 3;
    +   if( iVal<(1 << 28) ) return 4;
    +@@ -183817,9 +206630,15 @@ static int sqlite3Fts5GetVarintLen(u32 iVal){
    + **   the number of fts5 rows that contain at least one instance of term
    + **   $term. Field $cnt is set to the total number of instances of term 
    + **   $term in the database.
    ++**
    ++** instance:
    ++**     CREATE TABLE vocab(term, doc, col, offset, PRIMARY KEY(<all-fields>));
    ++**
    ++**   One row for each term instance in the database. 
    + */
    + 
    + 
    ++/* #include "fts5Int.h" */
    + 
    + 
    + typedef struct Fts5VocabTable Fts5VocabTable;
    +@@ -183831,7 +206650,7 @@ struct Fts5VocabTable {
    +   char *zFts5Db;                  /* Db containing fts5 table */
    +   sqlite3 *db;                    /* Database handle */
    +   Fts5Global *pGlobal;            /* FTS5 global object for this database */
    +-  int eType;                      /* FTS5_VOCAB_COL or ROW */
    ++  int eType;                      /* FTS5_VOCAB_COL, ROW or INSTANCE */
    + };
    + 
    + struct Fts5VocabCursor {
    +@@ -183842,23 +206661,39 @@ struct Fts5VocabCursor {
    +   int bEof;                       /* True if this cursor is at EOF */
    +   Fts5IndexIter *pIter;           /* Term/rowid iterator object */
    + 
    ++  int nLeTerm;                    /* Size of zLeTerm in bytes */
    ++  char *zLeTerm;                  /* (term <= $zLeTerm) paramater, or NULL */
    ++
    +   /* These are used by 'col' tables only */
    +-  int nCol;
    ++  Fts5Config *pConfig;            /* Fts5 table configuration */
    +   int iCol;
    +   i64 *aCnt;
    +   i64 *aDoc;
    + 
    +-  /* Output values */
    ++  /* Output values used by all tables. */
    +   i64 rowid;                      /* This table's current rowid value */
    +   Fts5Buffer term;                /* Current value of 'term' column */
    +-  i64 aVal[3];                    /* Up to three columns left of 'term' */
    ++
    ++  /* Output values Used by 'instance' tables only */
    ++  i64 iInstPos;
    ++  int iInstOff;
    + };
    + 
    +-#define FTS5_VOCAB_COL    0
    +-#define FTS5_VOCAB_ROW    1
    ++#define FTS5_VOCAB_COL      0
    ++#define FTS5_VOCAB_ROW      1
    ++#define FTS5_VOCAB_INSTANCE 2
    + 
    + #define FTS5_VOCAB_COL_SCHEMA  "term, col, doc, cnt"
    + #define FTS5_VOCAB_ROW_SCHEMA  "term, doc, cnt"
    ++#define FTS5_VOCAB_INST_SCHEMA "term, doc, col, offset"
    ++
    ++/*
    ++** Bits for the mask used as the idxNum value by xBestIndex/xFilter.
    ++*/
    ++#define FTS5_VOCAB_TERM_EQ 0x01
    ++#define FTS5_VOCAB_TERM_GE 0x02
    ++#define FTS5_VOCAB_TERM_LE 0x04
    ++
    + 
    + /*
    + ** Translate a string containing an fts5vocab table type to an 
    +@@ -183878,6 +206713,9 @@ static int fts5VocabTableType(const char *zType, char **pzErr, int *peType){
    +     if( sqlite3_stricmp(zCopy, "row")==0 ){
    +       *peType = FTS5_VOCAB_ROW;
    +     }else
    ++    if( sqlite3_stricmp(zCopy, "instance")==0 ){
    ++      *peType = FTS5_VOCAB_INSTANCE;
    ++    }else
    +     {
    +       *pzErr = sqlite3_mprintf("fts5vocab: unknown table type: %Q", zCopy);
    +       rc = SQLITE_ERROR;
    +@@ -183938,7 +206776,8 @@ static int fts5VocabInitVtab(
    + ){
    +   const char *azSchema[] = { 
    +     "CREATE TABlE vocab(" FTS5_VOCAB_COL_SCHEMA  ")", 
    +-    "CREATE TABlE vocab(" FTS5_VOCAB_ROW_SCHEMA  ")"
    ++    "CREATE TABlE vocab(" FTS5_VOCAB_ROW_SCHEMA  ")",
    ++    "CREATE TABlE vocab(" FTS5_VOCAB_INST_SCHEMA ")"
    +   };
    + 
    +   Fts5VocabTable *pRet = 0;
    +@@ -183955,13 +206794,13 @@ static int fts5VocabInitVtab(
    +     const char *zDb = bDb ? argv[3] : argv[1];
    +     const char *zTab = bDb ? argv[4] : argv[3];
    +     const char *zType = bDb ? argv[5] : argv[4];
    +-    int nDb = strlen(zDb)+1; 
    +-    int nTab = strlen(zTab)+1;
    +-    int eType;
    ++    int nDb = (int)strlen(zDb)+1; 
    ++    int nTab = (int)strlen(zTab)+1;
    ++    int eType = 0;
    +     
    +     rc = fts5VocabTableType(zType, pzErr, &eType);
    +     if( rc==SQLITE_OK ){
    +-      assert( eType>=0 && eType<sizeof(azSchema)/sizeof(azSchema[0]) );
    ++      assert( eType>=0 && eType<ArraySize(azSchema) );
    +       rc = sqlite3_declare_vtab(db, azSchema[eType]);
    +     }
    + 
    +@@ -184012,11 +206851,72 @@ static int fts5VocabCreateMethod(
    + 
    + /* 
    + ** Implementation of the xBestIndex method.
    ++**
    ++** Only constraints of the form:
    ++**
    ++**     term <= ?
    ++**     term == ?
    ++**     term >= ?
    ++**
    ++** are interpreted. Less-than and less-than-or-equal are treated 
    ++** identically, as are greater-than and greater-than-or-equal.
    + */
    + static int fts5VocabBestIndexMethod(
    +-  sqlite3_vtab *pVTab, 
    ++  sqlite3_vtab *pUnused,
    +   sqlite3_index_info *pInfo
    + ){
    ++  int i;
    ++  int iTermEq = -1;
    ++  int iTermGe = -1;
    ++  int iTermLe = -1;
    ++  int idxNum = 0;
    ++  int nArg = 0;
    ++
    ++  UNUSED_PARAM(pUnused);
    ++
    ++  for(i=0; i<pInfo->nConstraint; i++){
    ++    struct sqlite3_index_constraint *p = &pInfo->aConstraint[i];
    ++    if( p->usable==0 ) continue;
    ++    if( p->iColumn==0 ){          /* term column */
    ++      if( p->op==SQLITE_INDEX_CONSTRAINT_EQ ) iTermEq = i;
    ++      if( p->op==SQLITE_INDEX_CONSTRAINT_LE ) iTermLe = i;
    ++      if( p->op==SQLITE_INDEX_CONSTRAINT_LT ) iTermLe = i;
    ++      if( p->op==SQLITE_INDEX_CONSTRAINT_GE ) iTermGe = i;
    ++      if( p->op==SQLITE_INDEX_CONSTRAINT_GT ) iTermGe = i;
    ++    }
    ++  }
    ++
    ++  if( iTermEq>=0 ){
    ++    idxNum |= FTS5_VOCAB_TERM_EQ;
    ++    pInfo->aConstraintUsage[iTermEq].argvIndex = ++nArg;
    ++    pInfo->estimatedCost = 100;
    ++  }else{
    ++    pInfo->estimatedCost = 1000000;
    ++    if( iTermGe>=0 ){
    ++      idxNum |= FTS5_VOCAB_TERM_GE;
    ++      pInfo->aConstraintUsage[iTermGe].argvIndex = ++nArg;
    ++      pInfo->estimatedCost = pInfo->estimatedCost / 2;
    ++    }
    ++    if( iTermLe>=0 ){
    ++      idxNum |= FTS5_VOCAB_TERM_LE;
    ++      pInfo->aConstraintUsage[iTermLe].argvIndex = ++nArg;
    ++      pInfo->estimatedCost = pInfo->estimatedCost / 2;
    ++    }
    ++  }
    ++
    ++  /* This virtual table always delivers results in ascending order of
    ++  ** the "term" column (column 0). So if the user has requested this
    ++  ** specifically - "ORDER BY term" or "ORDER BY term ASC" - set the
    ++  ** sqlite3_index_info.orderByConsumed flag to tell the core the results
    ++  ** are already in sorted order.  */
    ++  if( pInfo->nOrderBy==1 
    ++   && pInfo->aOrderBy[0].iColumn==0 
    ++   && pInfo->aOrderBy[0].desc==0
    ++  ){
    ++    pInfo->orderByConsumed = 1;
    ++  }
    ++
    ++  pInfo->idxNum = idxNum;
    +   return SQLITE_OK;
    + }
    + 
    +@@ -184029,12 +206929,11 @@ static int fts5VocabOpenMethod(
    + ){
    +   Fts5VocabTable *pTab = (Fts5VocabTable*)pVTab;
    +   Fts5Index *pIndex = 0;
    +-  int nCol = 0;
    ++  Fts5Config *pConfig = 0;
    +   Fts5VocabCursor *pCsr = 0;
    +   int rc = SQLITE_OK;
    +   sqlite3_stmt *pStmt = 0;
    +   char *zSql = 0;
    +-  int nByte;
    + 
    +   zSql = sqlite3Fts5Mprintf(&rc,
    +       "SELECT t.%Q FROM %Q.%Q AS t WHERE t.%Q MATCH '*id'",
    +@@ -184049,7 +206948,7 @@ static int fts5VocabOpenMethod(
    + 
    +   if( pStmt && sqlite3_step(pStmt)==SQLITE_ROW ){
    +     i64 iId = sqlite3_column_int64(pStmt, 0);
    +-    pIndex = sqlite3Fts5IndexFromCsrid(pTab->pGlobal, iId, &nCol);
    ++    pIndex = sqlite3Fts5IndexFromCsrid(pTab->pGlobal, iId, &pConfig);
    +   }
    + 
    +   if( rc==SQLITE_OK && pIndex==0 ){
    +@@ -184063,14 +206962,17 @@ static int fts5VocabOpenMethod(
    +     }
    +   }
    + 
    +-  nByte = nCol * sizeof(i64) * 2 + sizeof(Fts5VocabCursor);
    +-  pCsr = (Fts5VocabCursor*)sqlite3Fts5MallocZero(&rc, nByte);
    ++  if( rc==SQLITE_OK ){
    ++    int nByte = pConfig->nCol * sizeof(i64) * 2 + sizeof(Fts5VocabCursor);
    ++    pCsr = (Fts5VocabCursor*)sqlite3Fts5MallocZero(&rc, nByte);
    ++  }
    ++
    +   if( pCsr ){
    +     pCsr->pIndex = pIndex;
    +     pCsr->pStmt = pStmt;
    +-    pCsr->nCol = nCol;
    ++    pCsr->pConfig = pConfig;
    +     pCsr->aCnt = (i64*)&pCsr[1];
    +-    pCsr->aDoc = &pCsr->aCnt[nCol];
    ++    pCsr->aDoc = &pCsr->aCnt[pConfig->nCol];
    +   }else{
    +     sqlite3_finalize(pStmt);
    +   }
    +@@ -184083,6 +206985,9 @@ static void fts5VocabResetCursor(Fts5VocabCursor *pCsr){
    +   pCsr->rowid = 0;
    +   sqlite3Fts5IterClose(pCsr->pIter);
    +   pCsr->pIter = 0;
    ++  sqlite3_free(pCsr->zLeTerm);
    ++  pCsr->nLeTerm = -1;
    ++  pCsr->zLeTerm = 0;
    + }
    + 
    + /*
    +@@ -184098,6 +207003,54 @@ static int fts5VocabCloseMethod(sqlite3_vtab_cursor *pCursor){
    +   return SQLITE_OK;
    + }
    + 
    ++static int fts5VocabInstanceNewTerm(Fts5VocabCursor *pCsr){
    ++  int rc = SQLITE_OK;
    ++  
    ++  if( sqlite3Fts5IterEof(pCsr->pIter) ){
    ++    pCsr->bEof = 1;
    ++  }else{
    ++    const char *zTerm;
    ++    int nTerm;
    ++    zTerm = sqlite3Fts5IterTerm(pCsr->pIter, &nTerm);
    ++    if( pCsr->nLeTerm>=0 ){
    ++      int nCmp = MIN(nTerm, pCsr->nLeTerm);
    ++      int bCmp = memcmp(pCsr->zLeTerm, zTerm, nCmp);
    ++      if( bCmp<0 || (bCmp==0 && pCsr->nLeTerm<nTerm) ){
    ++        pCsr->bEof = 1;
    ++      }
    ++    }
    ++
    ++    sqlite3Fts5BufferSet(&rc, &pCsr->term, nTerm, (const u8*)zTerm);
    ++  }
    ++  return rc;
    ++}
    ++
    ++static int fts5VocabInstanceNext(Fts5VocabCursor *pCsr){
    ++  int eDetail = pCsr->pConfig->eDetail;
    ++  int rc = SQLITE_OK;
    ++  Fts5IndexIter *pIter = pCsr->pIter;
    ++  i64 *pp = &pCsr->iInstPos;
    ++  int *po = &pCsr->iInstOff;
    ++  
    ++  while( eDetail==FTS5_DETAIL_NONE
    ++      || sqlite3Fts5PoslistNext64(pIter->pData, pIter->nData, po, pp) 
    ++  ){
    ++    pCsr->iInstPos = 0;
    ++    pCsr->iInstOff = 0;
    ++
    ++    rc = sqlite3Fts5IterNextScan(pCsr->pIter);
    ++    if( rc==SQLITE_OK ){
    ++      rc = fts5VocabInstanceNewTerm(pCsr);
    ++      if( eDetail==FTS5_DETAIL_NONE ) break;
    ++    }
    ++    if( rc ){
    ++      pCsr->bEof = 1;
    ++      break;
    ++    }
    ++  }
    ++
    ++  return rc;
    ++}
    + 
    + /*
    + ** Advance the cursor to the next row in the table.
    +@@ -184106,16 +207059,21 @@ static int fts5VocabNextMethod(sqlite3_vtab_cursor *pCursor){
    +   Fts5VocabCursor *pCsr = (Fts5VocabCursor*)pCursor;
    +   Fts5VocabTable *pTab = (Fts5VocabTable*)pCursor->pVtab;
    +   int rc = SQLITE_OK;
    ++  int nCol = pCsr->pConfig->nCol;
    + 
    +   pCsr->rowid++;
    + 
    ++  if( pTab->eType==FTS5_VOCAB_INSTANCE ){
    ++    return fts5VocabInstanceNext(pCsr);
    ++  }
    ++
    +   if( pTab->eType==FTS5_VOCAB_COL ){
    +-    for(pCsr->iCol++; pCsr->iCol<pCsr->nCol; pCsr->iCol++){
    +-      if( pCsr->aCnt[pCsr->iCol] ) break;
    ++    for(pCsr->iCol++; pCsr->iCol<nCol; pCsr->iCol++){
    ++      if( pCsr->aDoc[pCsr->iCol] ) break;
    +     }
    +   }
    + 
    +-  if( pTab->eType==FTS5_VOCAB_ROW || pCsr->iCol>=pCsr->nCol ){
    ++  if( pTab->eType!=FTS5_VOCAB_COL || pCsr->iCol>=nCol ){
    +     if( sqlite3Fts5IterEof(pCsr->pIter) ){
    +       pCsr->bEof = 1;
    +     }else{
    +@@ -184123,53 +207081,94 @@ static int fts5VocabNextMethod(sqlite3_vtab_cursor *pCursor){
    +       int nTerm;
    + 
    +       zTerm = sqlite3Fts5IterTerm(pCsr->pIter, &nTerm);
    ++      if( pCsr->nLeTerm>=0 ){
    ++        int nCmp = MIN(nTerm, pCsr->nLeTerm);
    ++        int bCmp = memcmp(pCsr->zLeTerm, zTerm, nCmp);
    ++        if( bCmp<0 || (bCmp==0 && pCsr->nLeTerm<nTerm) ){
    ++          pCsr->bEof = 1;
    ++          return SQLITE_OK;
    ++        }
    ++      }
    ++
    +       sqlite3Fts5BufferSet(&rc, &pCsr->term, nTerm, (const u8*)zTerm);
    +-      memset(pCsr->aVal, 0, sizeof(pCsr->aVal));
    +-      memset(pCsr->aCnt, 0, pCsr->nCol * sizeof(i64));
    +-      memset(pCsr->aDoc, 0, pCsr->nCol * sizeof(i64));
    ++      memset(pCsr->aCnt, 0, nCol * sizeof(i64));
    ++      memset(pCsr->aDoc, 0, nCol * sizeof(i64));
    +       pCsr->iCol = 0;
    + 
    +       assert( pTab->eType==FTS5_VOCAB_COL || pTab->eType==FTS5_VOCAB_ROW );
    +       while( rc==SQLITE_OK ){
    +-        i64 dummy;
    ++        int eDetail = pCsr->pConfig->eDetail;
    +         const u8 *pPos; int nPos;   /* Position list */
    +         i64 iPos = 0;               /* 64-bit position read from poslist */
    +         int iOff = 0;               /* Current offset within position list */
    + 
    +-        rc = sqlite3Fts5IterPoslist(pCsr->pIter, 0, &pPos, &nPos, &dummy);
    +-        if( rc==SQLITE_OK ){
    +-          if( pTab->eType==FTS5_VOCAB_ROW ){
    +-            while( 0==sqlite3Fts5PoslistNext64(pPos, nPos, &iOff, &iPos) ){
    +-              pCsr->aVal[1]++;
    ++        pPos = pCsr->pIter->pData;
    ++        nPos = pCsr->pIter->nData;
    ++
    ++        switch( pTab->eType ){
    ++          case FTS5_VOCAB_ROW:
    ++            if( eDetail==FTS5_DETAIL_FULL ){
    ++              while( 0==sqlite3Fts5PoslistNext64(pPos, nPos, &iOff, &iPos) ){
    ++                pCsr->aCnt[0]++;
    ++              }
    +             }
    +-            pCsr->aVal[0]++;
    +-          }else{
    +-            int iCol = -1;
    +-            while( 0==sqlite3Fts5PoslistNext64(pPos, nPos, &iOff, &iPos) ){
    +-              int ii = FTS5_POS2COLUMN(iPos);
    +-              pCsr->aCnt[ii]++;
    +-              if( iCol!=ii ){
    +-                pCsr->aDoc[ii]++;
    +-                iCol = ii;
    ++            pCsr->aDoc[0]++;
    ++            break;
    ++
    ++          case FTS5_VOCAB_COL:
    ++            if( eDetail==FTS5_DETAIL_FULL ){
    ++              int iCol = -1;
    ++              while( 0==sqlite3Fts5PoslistNext64(pPos, nPos, &iOff, &iPos) ){
    ++                int ii = FTS5_POS2COLUMN(iPos);
    ++                pCsr->aCnt[ii]++;
    ++                if( iCol!=ii ){
    ++                  if( ii>=nCol ){
    ++                    rc = FTS5_CORRUPT;
    ++                    break;
    ++                  }
    ++                  pCsr->aDoc[ii]++;
    ++                  iCol = ii;
    ++                }
    +               }
    ++            }else if( eDetail==FTS5_DETAIL_COLUMNS ){
    ++              while( 0==sqlite3Fts5PoslistNext64(pPos, nPos, &iOff,&iPos) ){
    ++                assert_nc( iPos>=0 && iPos<nCol );
    ++                if( iPos>=nCol ){
    ++                  rc = FTS5_CORRUPT;
    ++                  break;
    ++                }
    ++                pCsr->aDoc[iPos]++;
    ++              }
    ++            }else{
    ++              assert( eDetail==FTS5_DETAIL_NONE );
    ++              pCsr->aDoc[0]++;
    +             }
    +-          }
    ++            break;
    ++
    ++          default:
    ++            assert( pTab->eType==FTS5_VOCAB_INSTANCE );
    ++            break;
    ++        }
    ++
    ++        if( rc==SQLITE_OK ){
    +           rc = sqlite3Fts5IterNextScan(pCsr->pIter);
    +         }
    ++        if( pTab->eType==FTS5_VOCAB_INSTANCE ) break;
    ++
    +         if( rc==SQLITE_OK ){
    +           zTerm = sqlite3Fts5IterTerm(pCsr->pIter, &nTerm);
    +-          if( nTerm!=pCsr->term.n || memcmp(zTerm, pCsr->term.p, nTerm) ) break;
    ++          if( nTerm!=pCsr->term.n || memcmp(zTerm, pCsr->term.p, nTerm) ){
    ++            break;
    ++          }
    +           if( sqlite3Fts5IterEof(pCsr->pIter) ) break;
    +         }
    +       }
    +     }
    +   }
    + 
    +-  if( pCsr->bEof==0 && pTab->eType==FTS5_VOCAB_COL ){
    +-    while( pCsr->aCnt[pCsr->iCol]==0 ) pCsr->iCol++;
    +-    pCsr->aVal[0] = pCsr->iCol;
    +-    pCsr->aVal[1] = pCsr->aDoc[pCsr->iCol];
    +-    pCsr->aVal[2] = pCsr->aCnt[pCsr->iCol];
    ++  if( rc==SQLITE_OK && pCsr->bEof==0 && pTab->eType==FTS5_VOCAB_COL ){
    ++    while( pCsr->aDoc[pCsr->iCol]==0 ) pCsr->iCol++;
    ++    assert( pCsr->iCol<pCsr->pConfig->nCol );
    +   }
    +   return rc;
    + }
    +@@ -184180,17 +207179,62 @@ static int fts5VocabNextMethod(sqlite3_vtab_cursor *pCursor){
    + static int fts5VocabFilterMethod(
    +   sqlite3_vtab_cursor *pCursor,   /* The cursor used for this query */
    +   int idxNum,                     /* Strategy index */
    +-  const char *idxStr,             /* Unused */
    +-  int nVal,                       /* Number of elements in apVal */
    ++  const char *zUnused,            /* Unused */
    ++  int nUnused,                    /* Number of elements in apVal */
    +   sqlite3_value **apVal           /* Arguments for the indexing scheme */
    + ){
    ++  Fts5VocabTable *pTab = (Fts5VocabTable*)pCursor->pVtab;
    +   Fts5VocabCursor *pCsr = (Fts5VocabCursor*)pCursor;
    +-  int rc;
    +-  const int flags = FTS5INDEX_QUERY_SCAN;
    ++  int eType = pTab->eType;
    ++  int rc = SQLITE_OK;
    ++
    ++  int iVal = 0;
    ++  int f = FTS5INDEX_QUERY_SCAN;
    ++  const char *zTerm = 0;
    ++  int nTerm = 0;
    ++
    ++  sqlite3_value *pEq = 0;
    ++  sqlite3_value *pGe = 0;
    ++  sqlite3_value *pLe = 0;
    ++
    ++  UNUSED_PARAM2(zUnused, nUnused);
    + 
    +   fts5VocabResetCursor(pCsr);
    +-  rc = sqlite3Fts5IndexQuery(pCsr->pIndex, 0, 0, flags, 0, &pCsr->pIter);
    ++  if( idxNum & FTS5_VOCAB_TERM_EQ ) pEq = apVal[iVal++];
    ++  if( idxNum & FTS5_VOCAB_TERM_GE ) pGe = apVal[iVal++];
    ++  if( idxNum & FTS5_VOCAB_TERM_LE ) pLe = apVal[iVal++];
    ++
    ++  if( pEq ){
    ++    zTerm = (const char *)sqlite3_value_text(pEq);
    ++    nTerm = sqlite3_value_bytes(pEq);
    ++    f = 0;
    ++  }else{
    ++    if( pGe ){
    ++      zTerm = (const char *)sqlite3_value_text(pGe);
    ++      nTerm = sqlite3_value_bytes(pGe);
    ++    }
    ++    if( pLe ){
    ++      const char *zCopy = (const char *)sqlite3_value_text(pLe);
    ++      pCsr->nLeTerm = sqlite3_value_bytes(pLe);
    ++      pCsr->zLeTerm = sqlite3_malloc(pCsr->nLeTerm+1);
    ++      if( pCsr->zLeTerm==0 ){
    ++        rc = SQLITE_NOMEM;
    ++      }else{
    ++        memcpy(pCsr->zLeTerm, zCopy, pCsr->nLeTerm+1);
    ++      }
    ++    }
    ++  }
    ++
    +   if( rc==SQLITE_OK ){
    ++    rc = sqlite3Fts5IndexQuery(pCsr->pIndex, zTerm, nTerm, f, 0, &pCsr->pIter);
    ++  }
    ++  if( rc==SQLITE_OK && eType==FTS5_VOCAB_INSTANCE ){
    ++    rc = fts5VocabInstanceNewTerm(pCsr);
    ++  }
    ++  if( rc==SQLITE_OK 
    ++   && !pCsr->bEof 
    ++   && (eType!=FTS5_VOCAB_INSTANCE || pCsr->pConfig->eDetail!=FTS5_DETAIL_NONE)
    ++  ){
    +     rc = fts5VocabNextMethod(pCursor);
    +   }
    + 
    +@@ -184212,18 +207256,64 @@ static int fts5VocabColumnMethod(
    +   int iCol                        /* Index of column to read value from */
    + ){
    +   Fts5VocabCursor *pCsr = (Fts5VocabCursor*)pCursor;
    +-  switch( iCol ){
    +-    case 0: /* term */
    +-      sqlite3_result_text(
    +-          pCtx, (const char*)pCsr->term.p, pCsr->term.n, SQLITE_TRANSIENT
    +-      );
    +-      break;
    ++  int eDetail = pCsr->pConfig->eDetail;
    ++  int eType = ((Fts5VocabTable*)(pCursor->pVtab))->eType;
    ++  i64 iVal = 0;
    + 
    +-    default:
    +-      assert( iCol<4 && iCol>0 );
    +-      sqlite3_result_int64(pCtx, pCsr->aVal[iCol-1]);
    +-      break;
    ++  if( iCol==0 ){
    ++    sqlite3_result_text(
    ++        pCtx, (const char*)pCsr->term.p, pCsr->term.n, SQLITE_TRANSIENT
    ++    );
    ++  }else if( eType==FTS5_VOCAB_COL ){
    ++    assert( iCol==1 || iCol==2 || iCol==3 );
    ++    if( iCol==1 ){
    ++      if( eDetail!=FTS5_DETAIL_NONE ){
    ++        const char *z = pCsr->pConfig->azCol[pCsr->iCol];
    ++        sqlite3_result_text(pCtx, z, -1, SQLITE_STATIC);
    ++      }
    ++    }else if( iCol==2 ){
    ++      iVal = pCsr->aDoc[pCsr->iCol];
    ++    }else{
    ++      iVal = pCsr->aCnt[pCsr->iCol];
    ++    }
    ++  }else if( eType==FTS5_VOCAB_ROW ){
    ++    assert( iCol==1 || iCol==2 );
    ++    if( iCol==1 ){
    ++      iVal = pCsr->aDoc[0];
    ++    }else{
    ++      iVal = pCsr->aCnt[0];
    ++    }
    ++  }else{
    ++    assert( eType==FTS5_VOCAB_INSTANCE );
    ++    switch( iCol ){
    ++      case 1:
    ++        sqlite3_result_int64(pCtx, pCsr->pIter->iRowid);
    ++        break;
    ++      case 2: {
    ++        int ii = -1;
    ++        if( eDetail==FTS5_DETAIL_FULL ){
    ++          ii = FTS5_POS2COLUMN(pCsr->iInstPos);
    ++        }else if( eDetail==FTS5_DETAIL_COLUMNS ){
    ++          ii = (int)pCsr->iInstPos;
    ++        }
    ++        if( ii>=0 && ii<pCsr->pConfig->nCol ){
    ++          const char *z = pCsr->pConfig->azCol[ii];
    ++          sqlite3_result_text(pCtx, z, -1, SQLITE_STATIC);
    ++        }
    ++        break;
    ++      }
    ++      default: {
    ++        assert( iCol==3 );
    ++        if( eDetail==FTS5_DETAIL_FULL ){
    ++          int ii = FTS5_POS2OFFSET(pCsr->iInstPos);
    ++          sqlite3_result_int(pCtx, ii);
    ++        }
    ++        break;
    ++      }
    ++    }
    +   }
    ++
    ++  if( iVal>0 ) sqlite3_result_int64(pCtx, iVal);
    +   return SQLITE_OK;
    + }
    + 
    +@@ -184279,3 +207369,311 @@ static int sqlite3Fts5VocabInit(Fts5Global *pGlobal, sqlite3 *db){
    + #endif /* !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_FTS5) */
    + 
    + /************** End of fts5.c ************************************************/
    ++/************** Begin file stmt.c ********************************************/
    ++/*
    ++** 2017-05-31
    ++**
    ++** 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 demonstrates an eponymous virtual table that returns information
    ++** about all prepared statements for the database connection.
    ++**
    ++** Usage example:
    ++**
    ++**     .load ./stmt
    ++**     .mode line
    ++**     .header on
    ++**     SELECT * FROM stmt;
    ++*/
    ++#if !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_STMTVTAB)
    ++#if !defined(SQLITEINT_H)
    ++/* #include "sqlite3ext.h" */
    ++#endif
    ++SQLITE_EXTENSION_INIT1
    ++/* #include <assert.h> */
    ++/* #include <string.h> */
    ++
    ++#ifndef SQLITE_OMIT_VIRTUALTABLE
    ++
    ++/* stmt_vtab is a subclass of sqlite3_vtab which will
    ++** serve as the underlying representation of a stmt virtual table
    ++*/
    ++typedef struct stmt_vtab stmt_vtab;
    ++struct stmt_vtab {
    ++  sqlite3_vtab base;  /* Base class - must be first */
    ++  sqlite3 *db;        /* Database connection for this stmt vtab */
    ++};
    ++
    ++/* stmt_cursor is a subclass of sqlite3_vtab_cursor which will
    ++** serve as the underlying representation of a cursor that scans
    ++** over rows of the result
    ++*/
    ++typedef struct stmt_cursor stmt_cursor;
    ++struct stmt_cursor {
    ++  sqlite3_vtab_cursor base;  /* Base class - must be first */
    ++  sqlite3 *db;               /* Database connection for this cursor */
    ++  sqlite3_stmt *pStmt;       /* Statement cursor is currently pointing at */
    ++  sqlite3_int64 iRowid;      /* The rowid */
    ++};
    ++
    ++/*
    ++** The stmtConnect() method is invoked to create a new
    ++** stmt_vtab that describes the stmt virtual table.
    ++**
    ++** Think of this routine as the constructor for stmt_vtab objects.
    ++**
    ++** All this routine needs to do is:
    ++**
    ++**    (1) Allocate the stmt_vtab object and initialize all fields.
    ++**
    ++**    (2) Tell SQLite (via the sqlite3_declare_vtab() interface) what the
    ++**        result set of queries against stmt will look like.
    ++*/
    ++static int stmtConnect(
    ++  sqlite3 *db,
    ++  void *pAux,
    ++  int argc, const char *const*argv,
    ++  sqlite3_vtab **ppVtab,
    ++  char **pzErr
    ++){
    ++  stmt_vtab *pNew;
    ++  int rc;
    ++
    ++/* Column numbers */
    ++#define STMT_COLUMN_SQL     0   /* SQL for the statement */
    ++#define STMT_COLUMN_NCOL    1   /* Number of result columns */
    ++#define STMT_COLUMN_RO      2   /* True if read-only */
    ++#define STMT_COLUMN_BUSY    3   /* True if currently busy */
    ++#define STMT_COLUMN_NSCAN   4   /* SQLITE_STMTSTATUS_FULLSCAN_STEP */
    ++#define STMT_COLUMN_NSORT   5   /* SQLITE_STMTSTATUS_SORT */
    ++#define STMT_COLUMN_NAIDX   6   /* SQLITE_STMTSTATUS_AUTOINDEX */
    ++#define STMT_COLUMN_NSTEP   7   /* SQLITE_STMTSTATUS_VM_STEP */
    ++#define STMT_COLUMN_REPREP  8   /* SQLITE_STMTSTATUS_REPREPARE */
    ++#define STMT_COLUMN_RUN     9   /* SQLITE_STMTSTATUS_RUN */
    ++#define STMT_COLUMN_MEM    10   /* SQLITE_STMTSTATUS_MEMUSED */
    ++
    ++
    ++  rc = sqlite3_declare_vtab(db,
    ++     "CREATE TABLE x(sql,ncol,ro,busy,nscan,nsort,naidx,nstep,"
    ++                    "reprep,run,mem)");
    ++  if( rc==SQLITE_OK ){
    ++    pNew = sqlite3_malloc( sizeof(*pNew) );
    ++    *ppVtab = (sqlite3_vtab*)pNew;
    ++    if( pNew==0 ) return SQLITE_NOMEM;
    ++    memset(pNew, 0, sizeof(*pNew));
    ++    pNew->db = db;
    ++  }
    ++  return rc;
    ++}
    ++
    ++/*
    ++** This method is the destructor for stmt_cursor objects.
    ++*/
    ++static int stmtDisconnect(sqlite3_vtab *pVtab){
    ++  sqlite3_free(pVtab);
    ++  return SQLITE_OK;
    ++}
    ++
    ++/*
    ++** Constructor for a new stmt_cursor object.
    ++*/
    ++static int stmtOpen(sqlite3_vtab *p, sqlite3_vtab_cursor **ppCursor){
    ++  stmt_cursor *pCur;
    ++  pCur = sqlite3_malloc( sizeof(*pCur) );
    ++  if( pCur==0 ) return SQLITE_NOMEM;
    ++  memset(pCur, 0, sizeof(*pCur));
    ++  pCur->db = ((stmt_vtab*)p)->db;
    ++  *ppCursor = &pCur->base;
    ++  return SQLITE_OK;
    ++}
    ++
    ++/*
    ++** Destructor for a stmt_cursor.
    ++*/
    ++static int stmtClose(sqlite3_vtab_cursor *cur){
    ++  sqlite3_free(cur);
    ++  return SQLITE_OK;
    ++}
    ++
    ++
    ++/*
    ++** Advance a stmt_cursor to its next row of output.
    ++*/
    ++static int stmtNext(sqlite3_vtab_cursor *cur){
    ++  stmt_cursor *pCur = (stmt_cursor*)cur;
    ++  pCur->iRowid++;
    ++  pCur->pStmt = sqlite3_next_stmt(pCur->db, pCur->pStmt);
    ++  return SQLITE_OK;
    ++}
    ++
    ++/*
    ++** Return values of columns for the row at which the stmt_cursor
    ++** is currently pointing.
    ++*/
    ++static int stmtColumn(
    ++  sqlite3_vtab_cursor *cur,   /* The cursor */
    ++  sqlite3_context *ctx,       /* First argument to sqlite3_result_...() */
    ++  int i                       /* Which column to return */
    ++){
    ++  stmt_cursor *pCur = (stmt_cursor*)cur;
    ++  switch( i ){
    ++    case STMT_COLUMN_SQL: {
    ++      sqlite3_result_text(ctx, sqlite3_sql(pCur->pStmt), -1, SQLITE_TRANSIENT);
    ++      break;
    ++    }
    ++    case STMT_COLUMN_NCOL: {
    ++      sqlite3_result_int(ctx, sqlite3_column_count(pCur->pStmt));
    ++      break;
    ++    }
    ++    case STMT_COLUMN_RO: {
    ++      sqlite3_result_int(ctx, sqlite3_stmt_readonly(pCur->pStmt));
    ++      break;
    ++    }
    ++    case STMT_COLUMN_BUSY: {
    ++      sqlite3_result_int(ctx, sqlite3_stmt_busy(pCur->pStmt));
    ++      break;
    ++    }
    ++    case STMT_COLUMN_MEM: {
    ++      i = SQLITE_STMTSTATUS_MEMUSED + 
    ++            STMT_COLUMN_NSCAN - SQLITE_STMTSTATUS_FULLSCAN_STEP;
    ++      /* Fall thru */
    ++    }
    ++    case STMT_COLUMN_NSCAN:
    ++    case STMT_COLUMN_NSORT:
    ++    case STMT_COLUMN_NAIDX:
    ++    case STMT_COLUMN_NSTEP:
    ++    case STMT_COLUMN_REPREP:
    ++    case STMT_COLUMN_RUN: {
    ++      sqlite3_result_int(ctx, sqlite3_stmt_status(pCur->pStmt,
    ++                      i-STMT_COLUMN_NSCAN+SQLITE_STMTSTATUS_FULLSCAN_STEP, 0));
    ++      break;
    ++    }
    ++  }
    ++  return SQLITE_OK;
    ++}
    ++
    ++/*
    ++** Return the rowid for the current row.  In this implementation, the
    ++** rowid is the same as the output value.
    ++*/
    ++static int stmtRowid(sqlite3_vtab_cursor *cur, sqlite_int64 *pRowid){
    ++  stmt_cursor *pCur = (stmt_cursor*)cur;
    ++  *pRowid = pCur->iRowid;
    ++  return SQLITE_OK;
    ++}
    ++
    ++/*
    ++** Return TRUE if the cursor has been moved off of the last
    ++** row of output.
    ++*/
    ++static int stmtEof(sqlite3_vtab_cursor *cur){
    ++  stmt_cursor *pCur = (stmt_cursor*)cur;
    ++  return pCur->pStmt==0;
    ++}
    ++
    ++/*
    ++** This method is called to "rewind" the stmt_cursor object back
    ++** to the first row of output.  This method is always called at least
    ++** once prior to any call to stmtColumn() or stmtRowid() or 
    ++** stmtEof().
    ++*/
    ++static int stmtFilter(
    ++  sqlite3_vtab_cursor *pVtabCursor, 
    ++  int idxNum, const char *idxStr,
    ++  int argc, sqlite3_value **argv
    ++){
    ++  stmt_cursor *pCur = (stmt_cursor *)pVtabCursor;
    ++  pCur->pStmt = 0;
    ++  pCur->iRowid = 0;
    ++  return stmtNext(pVtabCursor);
    ++}
    ++
    ++/*
    ++** SQLite will invoke this method one or more times while planning a query
    ++** that uses the stmt virtual table.  This routine needs to create
    ++** a query plan for each invocation and compute an estimated cost for that
    ++** plan.
    ++*/
    ++static int stmtBestIndex(
    ++  sqlite3_vtab *tab,
    ++  sqlite3_index_info *pIdxInfo
    ++){
    ++  pIdxInfo->estimatedCost = (double)500;
    ++  pIdxInfo->estimatedRows = 500;
    ++  return SQLITE_OK;
    ++}
    ++
    ++/*
    ++** This following structure defines all the methods for the 
    ++** stmt virtual table.
    ++*/
    ++static sqlite3_module stmtModule = {
    ++  0,                         /* iVersion */
    ++  0,                         /* xCreate */
    ++  stmtConnect,               /* xConnect */
    ++  stmtBestIndex,             /* xBestIndex */
    ++  stmtDisconnect,            /* xDisconnect */
    ++  0,                         /* xDestroy */
    ++  stmtOpen,                  /* xOpen - open a cursor */
    ++  stmtClose,                 /* xClose - close a cursor */
    ++  stmtFilter,                /* xFilter - configure scan constraints */
    ++  stmtNext,                  /* xNext - advance a cursor */
    ++  stmtEof,                   /* xEof - check for end of scan */
    ++  stmtColumn,                /* xColumn - read data */
    ++  stmtRowid,                 /* xRowid - read data */
    ++  0,                         /* xUpdate */
    ++  0,                         /* xBegin */
    ++  0,                         /* xSync */
    ++  0,                         /* xCommit */
    ++  0,                         /* xRollback */
    ++  0,                         /* xFindMethod */
    ++  0,                         /* xRename */
    ++  0,                         /* xSavepoint */
    ++  0,                         /* xRelease */
    ++  0,                         /* xRollbackTo */
    ++};
    ++
    ++#endif /* SQLITE_OMIT_VIRTUALTABLE */
    ++
    ++SQLITE_PRIVATE int sqlite3StmtVtabInit(sqlite3 *db){
    ++  int rc = SQLITE_OK;
    ++#ifndef SQLITE_OMIT_VIRTUALTABLE
    ++  rc = sqlite3_create_module(db, "sqlite_stmt", &stmtModule, 0);
    ++#endif
    ++  return rc;
    ++}
    ++
    ++#ifndef SQLITE_CORE
    ++#ifdef _WIN32
    ++__declspec(dllexport)
    ++#endif
    ++SQLITE_API int sqlite3_stmt_init(
    ++  sqlite3 *db, 
    ++  char **pzErrMsg, 
    ++  const sqlite3_api_routines *pApi
    ++){
    ++  int rc = SQLITE_OK;
    ++  SQLITE_EXTENSION_INIT2(pApi);
    ++#ifndef SQLITE_OMIT_VIRTUALTABLE
    ++  rc = sqlite3StmtVtabInit(db);
    ++#endif
    ++  return rc;
    ++}
    ++#endif /* SQLITE_CORE */
    ++#endif /* !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_STMTVTAB) */
    ++
    ++/************** End of stmt.c ************************************************/
    ++#if __LINE__!=207661
    ++#undef SQLITE_SOURCE_ID
    ++#define SQLITE_SOURCE_ID      "2018-12-19 01:30:22 c255889bd95bd5430dc7ced3317011ae2abb483d6c9af883af3dc7d6c2c2alt2"
    ++#endif
    ++/* Return the source-id for this library */
    ++SQLITE_API const char *sqlite3_sourceid(void){ return SQLITE_SOURCE_ID; }
    ++/************************** End of sqlite3.c ******************************/
    +diff --git a/dist/sqlite3.h b/dist/sqlite3.h
    +index 7cca0ac..57669e1 100644
    +--- a/dist/sqlite3.h
    ++++ b/dist/sqlite3.h
    +@@ -1,5 +1,5 @@
    + /*
    +-** 2001 September 15
    ++** 2001-09-15
    + **
    + ** The author disclaims copyright to this source code.  In place of
    + ** a legal notice, here is a blessing:
    +@@ -30,8 +30,8 @@
    + ** the version number) and changes its name to "sqlite3.h" as
    + ** part of the build process.
    + */
    +-#ifndef _SQLITE3_H_
    +-#define _SQLITE3_H_
    ++#ifndef SQLITE3_H
    ++#define SQLITE3_H
    + #include <stdarg.h>     /* Needed for the definition of va_list */
    + 
    + /*
    +@@ -54,8 +54,17 @@ extern "C" {
    + #ifndef SQLITE_CDECL
    + # define SQLITE_CDECL
    + #endif
    ++#ifndef SQLITE_APICALL
    ++# define SQLITE_APICALL
    ++#endif
    + #ifndef SQLITE_STDCALL
    +-# define SQLITE_STDCALL
    ++# define SQLITE_STDCALL SQLITE_APICALL
    ++#endif
    ++#ifndef SQLITE_CALLBACK
    ++# define SQLITE_CALLBACK
    ++#endif
    ++#ifndef SQLITE_SYSAPI
    ++# define SQLITE_SYSAPI
    + #endif
    + 
    + /*
    +@@ -99,25 +108,28 @@ extern "C" {
    + ** be held constant and Z will be incremented or else Y will be incremented
    + ** and Z will be reset to zero.
    + **
    +-** Since version 3.6.18, SQLite source code has been stored in the
    ++** Since [version 3.6.18] ([dateof:3.6.18]), 
    ++** SQLite source code has been stored in the
    + ** <a href="http://www.fossil-scm.org/">Fossil configuration management
    + ** system</a>.  ^The SQLITE_SOURCE_ID macro evaluates to
    + ** a string which identifies a particular check-in of SQLite
    + ** within its configuration management system.  ^The SQLITE_SOURCE_ID
    +-** string contains the date and time of the check-in (UTC) and an SHA1
    +-** hash of the entire source tree.
    ++** string contains the date and time of the check-in (UTC) and a SHA1
    ++** or SHA3-256 hash of the entire source tree.  If the source code has
    ++** been edited in any way since it was last checked in, then the last
    ++** four hexadecimal digits of the hash may be modified.
    + **
    + ** See also: [sqlite3_libversion()],
    + ** [sqlite3_libversion_number()], [sqlite3_sourceid()],
    + ** [sqlite_version()] and [sqlite_source_id()].
    + */
    +-#define SQLITE_VERSION        "3.9.2"
    +-#define SQLITE_VERSION_NUMBER 3009002
    +-#define SQLITE_SOURCE_ID      "2015-11-02 18:31:45 bda77dda9697c463c3d0704014d51627fceee328"
    ++#define SQLITE_VERSION        "3.22.0"
    ++#define SQLITE_VERSION_NUMBER 3022000
    ++#define SQLITE_SOURCE_ID      "2018-12-19 01:30:22 c255889bd95bd5430dc7ced3317011ae2abb483d6c9af883af3dc7d6c2c2f234"
    + 
    + /*
    + ** CAPI3REF: Run-Time Library Version Numbers
    +-** KEYWORDS: sqlite3_version, sqlite3_sourceid
    ++** KEYWORDS: sqlite3_version sqlite3_sourceid
    + **
    + ** These interfaces provide the same information as the [SQLITE_VERSION],
    + ** [SQLITE_VERSION_NUMBER], and [SQLITE_SOURCE_ID] C preprocessor macros
    +@@ -129,7 +141,7 @@ extern "C" {
    + **
    + ** <blockquote><pre>
    + ** assert( sqlite3_libversion_number()==SQLITE_VERSION_NUMBER );
    +-** assert( strcmp(sqlite3_sourceid(),SQLITE_SOURCE_ID)==0 );
    ++** assert( strncmp(sqlite3_sourceid(),SQLITE_SOURCE_ID,80)==0 );
    + ** assert( strcmp(sqlite3_libversion(),SQLITE_VERSION)==0 );
    + ** </pre></blockquote>)^
    + **
    +@@ -139,16 +151,18 @@ extern "C" {
    + ** function is provided for use in DLLs since DLL users usually do not have
    + ** direct access to string constants within the DLL.  ^The
    + ** sqlite3_libversion_number() function returns an integer equal to
    +-** [SQLITE_VERSION_NUMBER].  ^The sqlite3_sourceid() function returns 
    ++** [SQLITE_VERSION_NUMBER].  ^(The sqlite3_sourceid() function returns 
    + ** a pointer to a string constant whose value is the same as the 
    +-** [SQLITE_SOURCE_ID] C preprocessor macro.
    ++** [SQLITE_SOURCE_ID] C preprocessor macro.  Except if SQLite is built
    ++** using an edited copy of [the amalgamation], then the last four characters
    ++** of the hash might be different from [SQLITE_SOURCE_ID].)^
    + **
    + ** See also: [sqlite_version()] and [sqlite_source_id()].
    + */
    + SQLITE_API SQLITE_EXTERN const char sqlite3_version[];
    +-SQLITE_API const char *SQLITE_STDCALL sqlite3_libversion(void);
    +-SQLITE_API const char *SQLITE_STDCALL sqlite3_sourceid(void);
    +-SQLITE_API int SQLITE_STDCALL sqlite3_libversion_number(void);
    ++SQLITE_API const char *sqlite3_libversion(void);
    ++SQLITE_API const char *sqlite3_sourceid(void);
    ++SQLITE_API int sqlite3_libversion_number(void);
    + 
    + /*
    + ** CAPI3REF: Run-Time Library Compilation Options Diagnostics
    +@@ -173,8 +187,8 @@ SQLITE_API int SQLITE_STDCALL sqlite3_libversion_number(void);
    + ** [sqlite_compileoption_get()] and the [compile_options pragma].
    + */
    + #ifndef SQLITE_OMIT_COMPILEOPTION_DIAGS
    +-SQLITE_API int SQLITE_STDCALL sqlite3_compileoption_used(const char *zOptName);
    +-SQLITE_API const char *SQLITE_STDCALL sqlite3_compileoption_get(int N);
    ++SQLITE_API int sqlite3_compileoption_used(const char *zOptName);
    ++SQLITE_API const char *sqlite3_compileoption_get(int N);
    + #endif
    + 
    + /*
    +@@ -213,7 +227,7 @@ SQLITE_API const char *SQLITE_STDCALL sqlite3_compileoption_get(int N);
    + **
    + ** See the [threading mode] documentation for additional information.
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_threadsafe(void);
    ++SQLITE_API int sqlite3_threadsafe(void);
    + 
    + /*
    + ** CAPI3REF: Database Connection Handle
    +@@ -249,7 +263,11 @@ typedef struct sqlite3 sqlite3;
    + */
    + #ifdef SQLITE_INT64_TYPE
    +   typedef SQLITE_INT64_TYPE sqlite_int64;
    +-  typedef unsigned SQLITE_INT64_TYPE sqlite_uint64;
    ++# ifdef SQLITE_UINT64_TYPE
    ++    typedef SQLITE_UINT64_TYPE sqlite_uint64;
    ++# else  
    ++    typedef unsigned SQLITE_INT64_TYPE sqlite_uint64;
    ++# endif
    + #elif defined(_MSC_VER) || defined(__BORLANDC__)
    +   typedef __int64 sqlite_int64;
    +   typedef unsigned __int64 sqlite_uint64;
    +@@ -310,8 +328,8 @@ typedef sqlite_uint64 sqlite3_uint64;
    + ** ^Calling sqlite3_close() or sqlite3_close_v2() with a NULL pointer
    + ** argument is a harmless no-op.
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_close(sqlite3*);
    +-SQLITE_API int SQLITE_STDCALL sqlite3_close_v2(sqlite3*);
    ++SQLITE_API int sqlite3_close(sqlite3*);
    ++SQLITE_API int sqlite3_close_v2(sqlite3*);
    + 
    + /*
    + ** The type for a callback function.
    +@@ -347,7 +365,7 @@ typedef int (*sqlite3_callback)(void*,int,char**, char**);
    + ** from [sqlite3_malloc()] and passed back through the 5th parameter.
    + ** To avoid memory leaks, the application should invoke [sqlite3_free()]
    + ** on error message strings returned through the 5th parameter of
    +-** of sqlite3_exec() after the error message string is no longer needed.
    ++** sqlite3_exec() after the error message string is no longer needed.
    + ** ^If the 5th parameter to sqlite3_exec() is not NULL and no errors
    + ** occur, then sqlite3_exec() sets the pointer in its 5th parameter to
    + ** NULL before returning.
    +@@ -382,7 +400,7 @@ typedef int (*sqlite3_callback)(void*,int,char**, char**);
    + **      the 2nd parameter of sqlite3_exec() while sqlite3_exec() is running.
    + ** </ul>
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_exec(
    ++SQLITE_API int sqlite3_exec(
    +   sqlite3*,                                  /* An open database */
    +   const char *sql,                           /* SQL to be evaluated */
    +   int (*callback)(void*,int,char**,char**),  /* Callback function */
    +@@ -403,7 +421,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_exec(
    + */
    + #define SQLITE_OK           0   /* Successful result */
    + /* beginning-of-error-codes */
    +-#define SQLITE_ERROR        1   /* SQL error or missing database */
    ++#define SQLITE_ERROR        1   /* Generic error */
    + #define SQLITE_INTERNAL     2   /* Internal logic error in SQLite */
    + #define SQLITE_PERM         3   /* Access permission denied */
    + #define SQLITE_ABORT        4   /* Callback routine requested an abort */
    +@@ -418,7 +436,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_exec(
    + #define SQLITE_FULL        13   /* Insertion failed because database is full */
    + #define SQLITE_CANTOPEN    14   /* Unable to open the database file */
    + #define SQLITE_PROTOCOL    15   /* Database lock protocol error */
    +-#define SQLITE_EMPTY       16   /* Database is empty */
    ++#define SQLITE_EMPTY       16   /* Internal use only */
    + #define SQLITE_SCHEMA      17   /* The database schema changed */
    + #define SQLITE_TOOBIG      18   /* String or BLOB exceeds size limit */
    + #define SQLITE_CONSTRAINT  19   /* Abort due to constraint violation */
    +@@ -426,7 +444,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_exec(
    + #define SQLITE_MISUSE      21   /* Library used incorrectly */
    + #define SQLITE_NOLFS       22   /* Uses OS features not supported on host */
    + #define SQLITE_AUTH        23   /* Authorization denied */
    +-#define SQLITE_FORMAT      24   /* Auxiliary database format error */
    ++#define SQLITE_FORMAT      24   /* Not used */
    + #define SQLITE_RANGE       25   /* 2nd parameter to sqlite3_bind out of range */
    + #define SQLITE_NOTADB      26   /* File opened that is not a database file */
    + #define SQLITE_NOTICE      27   /* Notifications from sqlite3_log() */
    +@@ -443,7 +461,8 @@ SQLITE_API int SQLITE_STDCALL sqlite3_exec(
    + ** [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
    ++** address this, newer versions of SQLite (version 3.3.8 [dateof:3.3.8]
    ++** and later) include
    + ** support for additional result codes that provide more detailed information
    + ** about errors. These [extended result codes] are enabled or disabled
    + ** on a per database connection basis using the
    +@@ -451,6 +470,8 @@ SQLITE_API int SQLITE_STDCALL sqlite3_exec(
    + ** the most recent error can be obtained using
    + ** [sqlite3_extended_errcode()].
    + */
    ++#define SQLITE_ERROR_MISSING_COLLSEQ   (SQLITE_ERROR | (1<<8))
    ++#define SQLITE_ERROR_RETRY             (SQLITE_ERROR | (2<<8))
    + #define SQLITE_IOERR_READ              (SQLITE_IOERR | (1<<8))
    + #define SQLITE_IOERR_SHORT_READ        (SQLITE_IOERR | (2<<8))
    + #define SQLITE_IOERR_WRITE             (SQLITE_IOERR | (3<<8))
    +@@ -478,6 +499,10 @@ SQLITE_API int SQLITE_STDCALL sqlite3_exec(
    + #define SQLITE_IOERR_GETTEMPPATH       (SQLITE_IOERR | (25<<8))
    + #define SQLITE_IOERR_CONVPATH          (SQLITE_IOERR | (26<<8))
    + #define SQLITE_IOERR_VNODE             (SQLITE_IOERR | (27<<8))
    ++#define SQLITE_IOERR_AUTH              (SQLITE_IOERR | (28<<8))
    ++#define SQLITE_IOERR_BEGIN_ATOMIC      (SQLITE_IOERR | (29<<8))
    ++#define SQLITE_IOERR_COMMIT_ATOMIC     (SQLITE_IOERR | (30<<8))
    ++#define SQLITE_IOERR_ROLLBACK_ATOMIC   (SQLITE_IOERR | (31<<8))
    + #define SQLITE_LOCKED_SHAREDCACHE      (SQLITE_LOCKED |  (1<<8))
    + #define SQLITE_BUSY_RECOVERY           (SQLITE_BUSY   |  (1<<8))
    + #define SQLITE_BUSY_SNAPSHOT           (SQLITE_BUSY   |  (2<<8))
    +@@ -490,6 +515,8 @@ SQLITE_API int SQLITE_STDCALL sqlite3_exec(
    + #define SQLITE_READONLY_CANTLOCK       (SQLITE_READONLY | (2<<8))
    + #define SQLITE_READONLY_ROLLBACK       (SQLITE_READONLY | (3<<8))
    + #define SQLITE_READONLY_DBMOVED        (SQLITE_READONLY | (4<<8))
    ++#define SQLITE_READONLY_CANTINIT       (SQLITE_READONLY | (5<<8))
    ++#define SQLITE_READONLY_DIRECTORY      (SQLITE_READONLY | (6<<8))
    + #define SQLITE_ABORT_ROLLBACK          (SQLITE_ABORT | (2<<8))
    + #define SQLITE_CONSTRAINT_CHECK        (SQLITE_CONSTRAINT | (1<<8))
    + #define SQLITE_CONSTRAINT_COMMITHOOK   (SQLITE_CONSTRAINT | (2<<8))
    +@@ -505,6 +532,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_exec(
    + #define SQLITE_NOTICE_RECOVER_ROLLBACK (SQLITE_NOTICE | (2<<8))
    + #define SQLITE_WARNING_AUTOINDEX       (SQLITE_WARNING | (1<<8))
    + #define SQLITE_AUTH_USER               (SQLITE_AUTH | (1<<8))
    ++#define SQLITE_OK_LOAD_PERMANENTLY     (SQLITE_OK | (1<<8))
    + 
    + /*
    + ** CAPI3REF: Flags For File Open Operations
    +@@ -559,10 +587,15 @@ SQLITE_API int SQLITE_STDCALL 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.  The
    ++** flag indicates 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.
    ++**
    ++** The SQLITE_IOCAP_BATCH_ATOMIC property means that the underlying
    ++** filesystem supports doing multiple write operations atomically when those
    ++** write operations are bracketed by [SQLITE_FCNTL_BEGIN_ATOMIC_WRITE] and
    ++** [SQLITE_FCNTL_COMMIT_ATOMIC_WRITE].
    + */
    + #define SQLITE_IOCAP_ATOMIC                 0x00000001
    + #define SQLITE_IOCAP_ATOMIC512              0x00000002
    +@@ -578,6 +611,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_exec(
    + #define SQLITE_IOCAP_UNDELETABLE_WHEN_OPEN  0x00000800
    + #define SQLITE_IOCAP_POWERSAFE_OVERWRITE    0x00001000
    + #define SQLITE_IOCAP_IMMUTABLE              0x00002000
    ++#define SQLITE_IOCAP_BATCH_ATOMIC           0x00004000
    + 
    + /*
    + ** CAPI3REF: File Locking Levels
    +@@ -709,6 +743,10 @@ struct sqlite3_file {
    + ** <li> [SQLITE_IOCAP_ATOMIC64K]
    + ** <li> [SQLITE_IOCAP_SAFE_APPEND]
    + ** <li> [SQLITE_IOCAP_SEQUENTIAL]
    ++** <li> [SQLITE_IOCAP_UNDELETABLE_WHEN_OPEN]
    ++** <li> [SQLITE_IOCAP_POWERSAFE_OVERWRITE]
    ++** <li> [SQLITE_IOCAP_IMMUTABLE]
    ++** <li> [SQLITE_IOCAP_BATCH_ATOMIC]
    + ** </ul>
    + **
    + ** The SQLITE_IOCAP_ATOMIC property means that all writes of
    +@@ -793,8 +831,13 @@ struct sqlite3_io_methods {
    + ** <li>[[SQLITE_FCNTL_FILE_POINTER]]
    + ** The [SQLITE_FCNTL_FILE_POINTER] opcode is used to obtain a pointer
    + ** to the [sqlite3_file] object associated with a particular database
    +-** connection.  See the [sqlite3_file_control()] documentation for
    +-** additional information.
    ++** connection.  See also [SQLITE_FCNTL_JOURNAL_POINTER].
    ++**
    ++** <li>[[SQLITE_FCNTL_JOURNAL_POINTER]]
    ++** The [SQLITE_FCNTL_JOURNAL_POINTER] opcode is used to obtain a pointer
    ++** to the [sqlite3_file] object associated with the journal file (either
    ++** the [rollback journal] or the [write-ahead log]) for a particular database
    ++** connection.  See also [SQLITE_FCNTL_FILE_POINTER].
    + **
    + ** <li>[[SQLITE_FCNTL_SYNC_OMITTED]]
    + ** No longer in use.
    +@@ -832,7 +875,7 @@ struct sqlite3_io_methods {
    + ** opcode allows these two values (10 retries and 25 milliseconds of delay)
    + ** to be adjusted.  The values are changed for all database connections
    + ** within the same process.  The argument is a pointer to an array of two
    +-** integers where the first integer i the new retry count and the second
    ++** integers where the first integer is the new retry count and the second
    + ** integer is the delay.  If either integer is negative, then the setting
    + ** is not changed but instead the prior value of that setting is written
    + ** into the array entry, allowing the current retry settings to be
    +@@ -881,6 +924,15 @@ struct sqlite3_io_methods {
    + ** pointer in case this file-control is not implemented.  This file-control
    + ** is intended for diagnostic use only.
    + **
    ++** <li>[[SQLITE_FCNTL_VFS_POINTER]]
    ++** ^The [SQLITE_FCNTL_VFS_POINTER] opcode finds a pointer to the top-level
    ++** [VFSes] currently in use.  ^(The argument X in
    ++** sqlite3_file_control(db,SQLITE_FCNTL_VFS_POINTER,X) must be
    ++** of type "[sqlite3_vfs] **".  This opcodes will set *X
    ++** to a pointer to the top-level VFS.)^
    ++** ^When there are multiple VFS shims in the stack, this opcode finds the
    ++** upper-most shim only.
    ++**
    + ** <li>[[SQLITE_FCNTL_PRAGMA]]
    + ** ^Whenever a [PRAGMA] statement is parsed, an [SQLITE_FCNTL_PRAGMA] 
    + ** file control is sent to the open [sqlite3_file] object corresponding
    +@@ -951,6 +1003,12 @@ struct sqlite3_io_methods {
    + ** on whether or not the file has been renamed, moved, or deleted since it
    + ** was first opened.
    + **
    ++** <li>[[SQLITE_FCNTL_WIN32_GET_HANDLE]]
    ++** The [SQLITE_FCNTL_WIN32_GET_HANDLE] opcode can be used to obtain the
    ++** underlying native file handle associated with a file handle.  This file
    ++** control interprets its argument as a pointer to a native file handle and
    ++** writes the resulting value there.
    ++**
    + ** <li>[[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
    +@@ -972,6 +1030,40 @@ struct sqlite3_io_methods {
    + ** The [SQLITE_FCNTL_RBU] opcode is implemented by the special VFS used by
    + ** the RBU extension only.  All other VFS should return SQLITE_NOTFOUND for
    + ** this opcode.  
    ++**
    ++** <li>[[SQLITE_FCNTL_BEGIN_ATOMIC_WRITE]]
    ++** If the [SQLITE_FCNTL_BEGIN_ATOMIC_WRITE] opcode returns SQLITE_OK, then
    ++** the file descriptor is placed in "batch write mode", which
    ++** means all subsequent write operations will be deferred and done
    ++** atomically at the next [SQLITE_FCNTL_COMMIT_ATOMIC_WRITE].  Systems
    ++** that do not support batch atomic writes will return SQLITE_NOTFOUND.
    ++** ^Following a successful SQLITE_FCNTL_BEGIN_ATOMIC_WRITE and prior to
    ++** the closing [SQLITE_FCNTL_COMMIT_ATOMIC_WRITE] or
    ++** [SQLITE_FCNTL_ROLLBACK_ATOMIC_WRITE], SQLite will make
    ++** no VFS interface calls on the same [sqlite3_file] file descriptor
    ++** except for calls to the xWrite method and the xFileControl method
    ++** with [SQLITE_FCNTL_SIZE_HINT].
    ++**
    ++** <li>[[SQLITE_FCNTL_COMMIT_ATOMIC_WRITE]]
    ++** The [SQLITE_FCNTL_COMMIT_ATOMIC_WRITE] opcode causes all write
    ++** operations since the previous successful call to 
    ++** [SQLITE_FCNTL_BEGIN_ATOMIC_WRITE] to be performed atomically.
    ++** This file control returns [SQLITE_OK] if and only if the writes were
    ++** all performed successfully and have been committed to persistent storage.
    ++** ^Regardless of whether or not it is successful, this file control takes
    ++** the file descriptor out of batch write mode so that all subsequent
    ++** write operations are independent.
    ++** ^SQLite will never invoke SQLITE_FCNTL_COMMIT_ATOMIC_WRITE without
    ++** a prior successful call to [SQLITE_FCNTL_BEGIN_ATOMIC_WRITE].
    ++**
    ++** <li>[[SQLITE_FCNTL_ROLLBACK_ATOMIC_WRITE]]
    ++** The [SQLITE_FCNTL_ROLLBACK_ATOMIC_WRITE] opcode causes all write
    ++** operations since the previous successful call to 
    ++** [SQLITE_FCNTL_BEGIN_ATOMIC_WRITE] to be rolled back.
    ++** ^This file control takes the file descriptor out of batch write mode
    ++** so that all subsequent write operations are independent.
    ++** ^SQLite will never invoke SQLITE_FCNTL_ROLLBACK_ATOMIC_WRITE without
    ++** a prior successful call to [SQLITE_FCNTL_BEGIN_ATOMIC_WRITE].
    + ** </ul>
    + */
    + #define SQLITE_FCNTL_LOCKSTATE               1
    +@@ -999,6 +1091,13 @@ struct sqlite3_io_methods {
    + #define SQLITE_FCNTL_WAL_BLOCK              24
    + #define SQLITE_FCNTL_ZIPVFS                 25
    + #define SQLITE_FCNTL_RBU                    26
    ++#define SQLITE_FCNTL_VFS_POINTER            27
    ++#define SQLITE_FCNTL_JOURNAL_POINTER        28
    ++#define SQLITE_FCNTL_WIN32_GET_HANDLE       29
    ++#define SQLITE_FCNTL_PDB                    30
    ++#define SQLITE_FCNTL_BEGIN_ATOMIC_WRITE     31
    ++#define SQLITE_FCNTL_COMMIT_ATOMIC_WRITE    32
    ++#define SQLITE_FCNTL_ROLLBACK_ATOMIC_WRITE  33
    + 
    + /* deprecated names */
    + #define SQLITE_GET_LOCKPROXYFILE      SQLITE_FCNTL_GET_LOCKPROXYFILE
    +@@ -1018,6 +1117,16 @@ struct sqlite3_io_methods {
    + */
    + typedef struct sqlite3_mutex sqlite3_mutex;
    + 
    ++/*
    ++** CAPI3REF: Loadable Extension Thunk
    ++**
    ++** A pointer to the opaque sqlite3_api_routines structure is passed as
    ++** the third parameter to entry points of [loadable extensions].  This
    ++** structure must be typedefed in order to work around compiler warnings
    ++** on some platforms.
    ++*/
    ++typedef struct sqlite3_api_routines sqlite3_api_routines;
    ++
    + /*
    + ** CAPI3REF: OS Interface Object
    + **
    +@@ -1026,12 +1135,18 @@ typedef struct sqlite3_mutex sqlite3_mutex;
    + ** in the name of the object stands for "virtual file system".  See
    + ** the [VFS | VFS documentation] for further information.
    + **
    +-** The value of the iVersion field is initially 1 but may be larger in
    +-** future versions of SQLite.  Additional fields may be appended to this
    +-** object when the iVersion value is increased.  Note that the structure
    +-** of the sqlite3_vfs object changes in the transaction between
    +-** SQLite version 3.5.9 and 3.6.0 and yet the iVersion field was not
    +-** modified.
    ++** The VFS interface is sometimes extended by adding new methods onto
    ++** the end.  Each time such an extension occurs, the iVersion field
    ++** is incremented.  The iVersion value started out as 1 in
    ++** SQLite [version 3.5.0] on [dateof:3.5.0], then increased to 2
    ++** with SQLite [version 3.7.0] on [dateof:3.7.0], and then increased
    ++** to 3 with SQLite [version 3.7.6] on [dateof:3.7.6].  Additional fields
    ++** may be appended to the sqlite3_vfs object and the iVersion value
    ++** may increase again in future versions of SQLite.
    ++** Note that the structure
    ++** of the sqlite3_vfs object changes in the transition from
    ++** SQLite [version 3.5.9] to [version 3.6.0] on [dateof:3.6.0]
    ++** and yet the iVersion field was not modified.
    + **
    + ** The szOsFile field is the size of the subclassed [sqlite3_file]
    + ** structure used by this VFS.  mxPathname is the maximum length of
    +@@ -1211,7 +1326,7 @@ struct sqlite3_vfs {
    +   const char *(*xNextSystemCall)(sqlite3_vfs*, const char *zName);
    +   /*
    +   ** The methods above are in versions 1 through 3 of the sqlite_vfs object.
    +-  ** New fields may be appended in figure versions.  The iVersion
    ++  ** New fields may be appended in future versions.  The iVersion
    +   ** value will increment whenever this happens. 
    +   */
    + };
    +@@ -1353,10 +1468,10 @@ struct sqlite3_vfs {
    + ** must return [SQLITE_OK] on success and some other [error code] upon
    + ** failure.
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_initialize(void);
    +-SQLITE_API int SQLITE_STDCALL sqlite3_shutdown(void);
    +-SQLITE_API int SQLITE_STDCALL sqlite3_os_init(void);
    +-SQLITE_API int SQLITE_STDCALL sqlite3_os_end(void);
    ++SQLITE_API int sqlite3_initialize(void);
    ++SQLITE_API int sqlite3_shutdown(void);
    ++SQLITE_API int sqlite3_os_init(void);
    ++SQLITE_API int sqlite3_os_end(void);
    + 
    + /*
    + ** CAPI3REF: Configuring The SQLite Library
    +@@ -1389,7 +1504,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_os_end(void);
    + ** ^If the option is unknown or SQLite is unable to set the option
    + ** then this routine returns a non-zero [error code].
    + */
    +-SQLITE_API int SQLITE_CDECL sqlite3_config(int, ...);
    ++SQLITE_API int sqlite3_config(int, ...);
    + 
    + /*
    + ** CAPI3REF: Configure database connections
    +@@ -1408,7 +1523,7 @@ SQLITE_API int SQLITE_CDECL sqlite3_config(int, ...);
    + ** ^Calls to sqlite3_db_config() return SQLITE_OK if and only if
    + ** the call is considered successful.
    + */
    +-SQLITE_API int SQLITE_CDECL sqlite3_db_config(sqlite3*, int op, ...);
    ++SQLITE_API int sqlite3_db_config(sqlite3*, int op, ...);
    + 
    + /*
    + ** CAPI3REF: Memory Allocation Routines
    +@@ -1559,6 +1674,16 @@ struct sqlite3_mem_methods {
    + ** routines with a wrapper that simulations memory allocation failure or
    + ** tracks memory usage, for example. </dd>
    + **
    ++** [[SQLITE_CONFIG_SMALL_MALLOC]] <dt>SQLITE_CONFIG_SMALL_MALLOC</dt>
    ++** <dd> ^The SQLITE_CONFIG_SMALL_MALLOC option takes single argument of
    ++** type int, interpreted as a boolean, which if true provides a hint to
    ++** SQLite that it should avoid large memory allocations if possible.
    ++** SQLite will run faster if it is free to make large memory allocations,
    ++** but some application might prefer to run slower in exchange for
    ++** guarantees about memory fragmentation that are possible if large
    ++** allocations are avoided.  This hint is normally off.
    ++** </dd>
    ++**
    + ** [[SQLITE_CONFIG_MEMSTATUS]] <dt>SQLITE_CONFIG_MEMSTATUS</dt>
    + ** <dd> ^The SQLITE_CONFIG_MEMSTATUS option takes single argument of type int,
    + ** interpreted as a boolean, which enables or disables the collection of
    +@@ -1576,57 +1701,43 @@ struct sqlite3_mem_methods {
    + ** </dd>
    + **
    + ** [[SQLITE_CONFIG_SCRATCH]] <dt>SQLITE_CONFIG_SCRATCH</dt>
    +-** <dd> ^The SQLITE_CONFIG_SCRATCH option specifies a static memory buffer
    +-** that SQLite can use for scratch memory.  ^(There are three arguments
    +-** to SQLITE_CONFIG_SCRATCH:  A pointer an 8-byte
    +-** aligned memory buffer from which the scratch allocations will be
    +-** drawn, the size of each scratch allocation (sz),
    +-** and the maximum number of scratch allocations (N).)^
    +-** The first argument must be a pointer to an 8-byte aligned buffer
    +-** of at least sz*N bytes of memory.
    +-** ^SQLite will not use more than one scratch buffers per thread.
    +-** ^SQLite will never request a scratch buffer that is more than 6
    +-** times the database page size.
    +-** ^If SQLite needs needs additional
    +-** scratch memory beyond what is provided by this configuration option, then 
    +-** [sqlite3_malloc()] will be used to obtain the memory needed.<p>
    +-** ^When the application provides any amount of scratch memory using
    +-** SQLITE_CONFIG_SCRATCH, SQLite avoids unnecessary large
    +-** [sqlite3_malloc|heap allocations].
    +-** This can help [Robson proof|prevent memory allocation failures] due to heap
    +-** fragmentation in low-memory embedded systems.
    ++** <dd> The SQLITE_CONFIG_SCRATCH option is no longer used.
    + ** </dd>
    + **
    + ** [[SQLITE_CONFIG_PAGECACHE]] <dt>SQLITE_CONFIG_PAGECACHE</dt>
    +-** <dd> ^The SQLITE_CONFIG_PAGECACHE option specifies a static memory buffer
    ++** <dd> ^The SQLITE_CONFIG_PAGECACHE option specifies a memory pool
    + ** that SQLite can use for the database page cache with the default page
    + ** cache implementation.  
    +-** This configuration should not be used if an application-define page
    +-** cache implementation is loaded using the [SQLITE_CONFIG_PCACHE2]
    +-** configuration option.
    ++** This configuration option is a no-op if an application-define page
    ++** cache implementation is loaded using the [SQLITE_CONFIG_PCACHE2].
    + ** ^There are three arguments to SQLITE_CONFIG_PAGECACHE: A pointer to
    +-** 8-byte aligned
    +-** memory, the size of each page buffer (sz), and the number of pages (N).
    ++** 8-byte aligned memory (pMem), the size of each page cache line (sz),
    ++** and the number of cache lines (N).
    + ** The sz argument should be the size of the largest database page
    + ** (a power of two between 512 and 65536) plus some extra bytes for each
    + ** page header.  ^The number of extra bytes needed by the page header
    +-** can be determined using the [SQLITE_CONFIG_PCACHE_HDRSZ] option 
    +-** to [sqlite3_config()].
    ++** can be determined using [SQLITE_CONFIG_PCACHE_HDRSZ].
    + ** ^It is harmless, apart from the wasted memory,
    +-** for the sz parameter to be larger than necessary.  The first
    +-** argument should pointer to an 8-byte aligned block of memory that
    +-** is at least sz*N bytes of memory, otherwise subsequent behavior is
    +-** undefined.
    +-** ^SQLite will use the memory provided by the first argument to satisfy its
    +-** memory needs for the first N pages that it adds to cache.  ^If additional
    +-** page cache memory is needed beyond what is provided by this option, then
    +-** SQLite goes to [sqlite3_malloc()] for the additional storage space.</dd>
    ++** for the sz parameter to be larger than necessary.  The pMem
    ++** argument must be either a NULL pointer or a pointer to an 8-byte
    ++** aligned block of memory of at least sz*N bytes, otherwise
    ++** subsequent behavior is undefined.
    ++** ^When pMem is not NULL, SQLite will strive to use the memory provided
    ++** to satisfy page cache needs, falling back to [sqlite3_malloc()] if
    ++** a page cache line is larger than sz bytes or if all of the pMem buffer
    ++** is exhausted.
    ++** ^If pMem is NULL and N is non-zero, then each database connection
    ++** does an initial bulk allocation for page cache memory
    ++** from [sqlite3_malloc()] sufficient for N cache lines if N is positive or
    ++** of -1024*N bytes if N is negative, . ^If additional
    ++** page cache memory is needed beyond what is provided by the initial
    ++** allocation, then SQLite goes to [sqlite3_malloc()] separately for each
    ++** additional cache line. </dd>
    + **
    + ** [[SQLITE_CONFIG_HEAP]] <dt>SQLITE_CONFIG_HEAP</dt>
    + ** <dd> ^The SQLITE_CONFIG_HEAP option specifies a static memory buffer 
    + ** that SQLite will use for all of its dynamic memory allocation needs
    +-** beyond those provided for by [SQLITE_CONFIG_SCRATCH] and
    +-** [SQLITE_CONFIG_PAGECACHE].
    ++** beyond those provided for by [SQLITE_CONFIG_PAGECACHE].
    + ** ^The SQLITE_CONFIG_HEAP option is only available if SQLite is compiled
    + ** with either [SQLITE_ENABLE_MEMSYS3] or [SQLITE_ENABLE_MEMSYS5] and returns
    + ** [SQLITE_ERROR] if invoked otherwise.
    +@@ -1798,6 +1909,20 @@ struct sqlite3_mem_methods {
    + ** is enabled (using the [PRAGMA threads] command) and the amount of content
    + ** to be sorted exceeds the page size times the minimum of the
    + ** [PRAGMA cache_size] setting and this value.
    ++**
    ++** [[SQLITE_CONFIG_STMTJRNL_SPILL]]
    ++** <dt>SQLITE_CONFIG_STMTJRNL_SPILL
    ++** <dd>^The SQLITE_CONFIG_STMTJRNL_SPILL option takes a single parameter which
    ++** becomes the [statement journal] spill-to-disk threshold.  
    ++** [Statement journals] are held in memory until their size (in bytes)
    ++** exceeds this threshold, at which point they are written to disk.
    ++** Or if the threshold is -1, statement journals are always held
    ++** exclusively in memory.
    ++** Since many statement journals never become large, setting the spill
    ++** threshold to a value such as 64KiB can greatly reduce the amount of
    ++** I/O required to support statement rollback.
    ++** The default value for this setting is controlled by the
    ++** [SQLITE_STMTJRNL_SPILL] compile-time option.
    + ** </dl>
    + */
    + #define SQLITE_CONFIG_SINGLETHREAD  1  /* nil */
    +@@ -1805,7 +1930,7 @@ struct sqlite3_mem_methods {
    + #define SQLITE_CONFIG_SERIALIZED    3  /* nil */
    + #define SQLITE_CONFIG_MALLOC        4  /* sqlite3_mem_methods* */
    + #define SQLITE_CONFIG_GETMALLOC     5  /* sqlite3_mem_methods* */
    +-#define SQLITE_CONFIG_SCRATCH       6  /* void*, int sz, int N */
    ++#define SQLITE_CONFIG_SCRATCH       6  /* No longer used */
    + #define SQLITE_CONFIG_PAGECACHE     7  /* void*, int sz, int N */
    + #define SQLITE_CONFIG_HEAP          8  /* void*, int nByte, int min */
    + #define SQLITE_CONFIG_MEMSTATUS     9  /* boolean */
    +@@ -1825,6 +1950,8 @@ struct sqlite3_mem_methods {
    + #define SQLITE_CONFIG_WIN32_HEAPSIZE      23  /* int nByte */
    + #define SQLITE_CONFIG_PCACHE_HDRSZ        24  /* int *psz */
    + #define SQLITE_CONFIG_PMASZ               25  /* unsigned int szPma */
    ++#define SQLITE_CONFIG_STMTJRNL_SPILL      26  /* int nByte */
    ++#define SQLITE_CONFIG_SMALL_MALLOC        27  /* boolean */
    + 
    + /*
    + ** CAPI3REF: Database Connection Configuration Options
    +@@ -1882,12 +2009,88 @@ struct sqlite3_mem_methods {
    + ** following this call.  The second parameter may be a NULL pointer, in
    + ** which case the trigger setting is not reported back. </dd>
    + **
    ++** <dt>SQLITE_DBCONFIG_ENABLE_FTS3_TOKENIZER</dt>
    ++** <dd> ^This option is used to enable or disable the two-argument
    ++** version of the [fts3_tokenizer()] function which is part of the
    ++** [FTS3] full-text search engine extension.
    ++** There should be two additional arguments.
    ++** The first argument is an integer which is 0 to disable fts3_tokenizer() or
    ++** positive to enable fts3_tokenizer() or negative to leave the setting
    ++** unchanged.
    ++** The second parameter is a pointer to an integer into which
    ++** is written 0 or 1 to indicate whether fts3_tokenizer is disabled or enabled
    ++** following this call.  The second parameter may be a NULL pointer, in
    ++** which case the new setting is not reported back. </dd>
    ++**
    ++** <dt>SQLITE_DBCONFIG_ENABLE_LOAD_EXTENSION</dt>
    ++** <dd> ^This option is used to enable or disable the [sqlite3_load_extension()]
    ++** interface independently of the [load_extension()] SQL function.
    ++** The [sqlite3_enable_load_extension()] API enables or disables both the
    ++** C-API [sqlite3_load_extension()] and the SQL function [load_extension()].
    ++** There should be two additional arguments.
    ++** When the first argument to this interface is 1, then only the C-API is
    ++** enabled and the SQL function remains disabled.  If the first argument to
    ++** this interface is 0, then both the C-API and the SQL function are disabled.
    ++** If the first argument is -1, then no changes are made to state of either the
    ++** C-API or the SQL function.
    ++** The second parameter is a pointer to an integer into which
    ++** is written 0 or 1 to indicate whether [sqlite3_load_extension()] interface
    ++** is disabled or enabled following this call.  The second parameter may
    ++** be a NULL pointer, in which case the new setting is not reported back.
    ++** </dd>
    ++**
    ++** <dt>SQLITE_DBCONFIG_MAINDBNAME</dt>
    ++** <dd> ^This option is used to change the name of the "main" database
    ++** schema.  ^The sole argument is a pointer to a constant UTF8 string
    ++** which will become the new schema name in place of "main".  ^SQLite
    ++** does not make a copy of the new main schema name string, so the application
    ++** must ensure that the argument passed into this DBCONFIG option is unchanged
    ++** until after the database connection closes.
    ++** </dd>
    ++**
    ++** <dt>SQLITE_DBCONFIG_NO_CKPT_ON_CLOSE</dt>
    ++** <dd> Usually, when a database in wal mode is closed or detached from a 
    ++** database handle, SQLite checks if this will mean that there are now no 
    ++** connections at all to the database. If so, it performs a checkpoint 
    ++** operation before closing the connection. This option may be used to
    ++** override this behaviour. The first parameter passed to this operation
    ++** is an integer - non-zero to disable checkpoints-on-close, or zero (the
    ++** default) to enable them. The second parameter is a pointer to an integer
    ++** into which is written 0 or 1 to indicate whether checkpoints-on-close
    ++** have been disabled - 0 if they are not disabled, 1 if they are.
    ++** </dd>
    ++** <dt>SQLITE_DBCONFIG_ENABLE_QPSG</dt>
    ++** <dd>^(The SQLITE_DBCONFIG_ENABLE_QPSG option activates or deactivates
    ++** the [query planner stability guarantee] (QPSG).  When the QPSG is active,
    ++** a single SQL query statement will always use the same algorithm regardless
    ++** of values of [bound parameters].)^ The QPSG disables some query optimizations
    ++** that look at the values of bound parameters, which can make some queries
    ++** slower.  But the QPSG has the advantage of more predictable behavior.  With
    ++** the QPSG active, SQLite will always use the same query plan in the field as
    ++** was used during testing in the lab.
    ++** </dd>
    ++** <dt>SQLITE_DBCONFIG_TRIGGER_EQP</dt>
    ++** <dd> By default, the output of EXPLAIN QUERY PLAN commands does not 
    ++** include output for any operations performed by trigger programs. This
    ++** option is used to set or clear (the default) a flag that governs this
    ++** behavior. The first parameter passed to this operation is an integer -
    ++** non-zero to enable output for trigger programs, or zero to disable it.
    ++** The second parameter is a pointer to an integer into which is written 
    ++** 0 or 1 to indicate whether output-for-triggers has been disabled - 0 if 
    ++** it is not disabled, 1 if it is.  
    ++** </dd>
    + ** </dl>
    + */
    +-#define SQLITE_DBCONFIG_LOOKASIDE       1001  /* void* int int */
    +-#define SQLITE_DBCONFIG_ENABLE_FKEY     1002  /* int int* */
    +-#define SQLITE_DBCONFIG_ENABLE_TRIGGER  1003  /* int int* */
    +-
    ++#define SQLITE_DBCONFIG_MAINDBNAME            1000 /* const char* */
    ++#define SQLITE_DBCONFIG_LOOKASIDE             1001 /* void* int int */
    ++#define SQLITE_DBCONFIG_ENABLE_FKEY           1002 /* int int* */
    ++#define SQLITE_DBCONFIG_ENABLE_TRIGGER        1003 /* int int* */
    ++#define SQLITE_DBCONFIG_ENABLE_FTS3_TOKENIZER 1004 /* int int* */
    ++#define SQLITE_DBCONFIG_ENABLE_LOAD_EXTENSION 1005 /* int int* */
    ++#define SQLITE_DBCONFIG_NO_CKPT_ON_CLOSE      1006 /* int int* */
    ++#define SQLITE_DBCONFIG_ENABLE_QPSG           1007 /* int int* */
    ++#define SQLITE_DBCONFIG_TRIGGER_EQP           1008 /* int int* */
    ++#define SQLITE_DBCONFIG_MAX                   1008 /* Largest DBCONFIG */
    + 
    + /*
    + ** CAPI3REF: Enable Or Disable Extended Result Codes
    +@@ -1897,7 +2100,7 @@ struct sqlite3_mem_methods {
    + ** [extended result codes] feature of SQLite. ^The extended result
    + ** codes are disabled by default for historical compatibility.
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_extended_result_codes(sqlite3*, int onoff);
    ++SQLITE_API int sqlite3_extended_result_codes(sqlite3*, int onoff);
    + 
    + /*
    + ** CAPI3REF: Last Insert Rowid
    +@@ -1911,20 +2114,30 @@ SQLITE_API int SQLITE_STDCALL sqlite3_extended_result_codes(sqlite3*, int onoff)
    + ** the table has a column of type [INTEGER PRIMARY KEY] then that column
    + ** is another alias for the rowid.
    + **
    +-** ^The sqlite3_last_insert_rowid(D) interface returns the [rowid] of the 
    +-** most recent successful [INSERT] into a rowid table or [virtual table]
    +-** on database connection D.
    +-** ^Inserts into [WITHOUT ROWID] tables are not recorded.
    +-** ^If no successful [INSERT]s into rowid tables
    +-** have ever occurred on the database connection D, 
    +-** then sqlite3_last_insert_rowid(D) returns zero.
    +-**
    +-** ^(If an [INSERT] occurs within a trigger or within a [virtual table]
    +-** method, then this routine will return the [rowid] of the inserted
    +-** row as long as the trigger or virtual table method is running.
    +-** But once the trigger or virtual table method ends, the value returned 
    +-** by this routine reverts to what it was before the trigger or virtual
    +-** table method began.)^
    ++** ^The sqlite3_last_insert_rowid(D) interface usually returns the [rowid] of
    ++** the most recent successful [INSERT] into a rowid table or [virtual table]
    ++** on database connection D. ^Inserts into [WITHOUT ROWID] tables are not
    ++** recorded. ^If no successful [INSERT]s into rowid tables have ever occurred 
    ++** on the database connection D, then sqlite3_last_insert_rowid(D) returns 
    ++** zero.
    ++**
    ++** As well as being set automatically as rows are inserted into database
    ++** tables, the value returned by this function may be set explicitly by
    ++** [sqlite3_set_last_insert_rowid()]
    ++**
    ++** Some virtual table implementations may INSERT rows into rowid tables as
    ++** part of committing a transaction (e.g. to flush data accumulated in memory
    ++** to disk). In this case subsequent calls to this function return the rowid
    ++** associated with these internal INSERT operations, which leads to 
    ++** unintuitive results. Virtual table implementations that do write to rowid
    ++** tables in this way can avoid this problem by restoring the original 
    ++** rowid value using [sqlite3_set_last_insert_rowid()] before returning 
    ++** control to the user.
    ++**
    ++** ^(If an [INSERT] occurs within a trigger then this routine will 
    ++** return the [rowid] of the inserted row as long as the trigger is 
    ++** running. Once the trigger program ends, the value returned 
    ++** by this routine reverts to what it was before the trigger was fired.)^
    + **
    + ** ^An [INSERT] that fails due to a constraint violation is not a
    + ** successful [INSERT] and does not change the value returned by this
    +@@ -1949,7 +2162,17 @@ SQLITE_API int SQLITE_STDCALL sqlite3_extended_result_codes(sqlite3*, int onoff)
    + ** unpredictable and might not equal either the old or the new
    + ** last insert [rowid].
    + */
    +-SQLITE_API sqlite3_int64 SQLITE_STDCALL sqlite3_last_insert_rowid(sqlite3*);
    ++SQLITE_API sqlite3_int64 sqlite3_last_insert_rowid(sqlite3*);
    ++
    ++/*
    ++** CAPI3REF: Set the Last Insert Rowid value.
    ++** METHOD: sqlite3
    ++**
    ++** The sqlite3_set_last_insert_rowid(D, R) method allows the application to
    ++** set the value returned by calling sqlite3_last_insert_rowid(D) to R 
    ++** without inserting a row into the database.
    ++*/
    ++SQLITE_API void sqlite3_set_last_insert_rowid(sqlite3*,sqlite3_int64);
    + 
    + /*
    + ** CAPI3REF: Count The Number Of Rows Modified
    +@@ -2002,7 +2225,7 @@ SQLITE_API sqlite3_int64 SQLITE_STDCALL sqlite3_last_insert_rowid(sqlite3*);
    + ** while [sqlite3_changes()] is running then the value returned
    + ** is unpredictable and not meaningful.
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_changes(sqlite3*);
    ++SQLITE_API int sqlite3_changes(sqlite3*);
    + 
    + /*
    + ** CAPI3REF: Total Number Of Rows Modified
    +@@ -2026,7 +2249,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_changes(sqlite3*);
    + ** while [sqlite3_total_changes()] is running then the value
    + ** returned is unpredictable and not meaningful.
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_total_changes(sqlite3*);
    ++SQLITE_API int sqlite3_total_changes(sqlite3*);
    + 
    + /*
    + ** CAPI3REF: Interrupt A Long-Running Query
    +@@ -2062,11 +2285,8 @@ SQLITE_API int SQLITE_STDCALL sqlite3_total_changes(sqlite3*);
    + ** ^A call to sqlite3_interrupt(D) that occurs when there are no running
    + ** SQL statements is a no-op and has no effect on SQL statements
    + ** that are started after the sqlite3_interrupt() call returns.
    +-**
    +-** If the database connection closes while [sqlite3_interrupt()]
    +-** is running then bad things will likely happen.
    + */
    +-SQLITE_API void SQLITE_STDCALL sqlite3_interrupt(sqlite3*);
    ++SQLITE_API void sqlite3_interrupt(sqlite3*);
    + 
    + /*
    + ** CAPI3REF: Determine If An SQL Statement Is Complete
    +@@ -2101,8 +2321,8 @@ SQLITE_API void SQLITE_STDCALL sqlite3_interrupt(sqlite3*);
    + ** The input to [sqlite3_complete16()] must be a zero-terminated
    + ** UTF-16 string in native byte order.
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_complete(const char *sql);
    +-SQLITE_API int SQLITE_STDCALL sqlite3_complete16(const void *sql);
    ++SQLITE_API int sqlite3_complete(const char *sql);
    ++SQLITE_API int sqlite3_complete16(const void *sql);
    + 
    + /*
    + ** CAPI3REF: Register A Callback To Handle SQLITE_BUSY Errors
    +@@ -2163,7 +2383,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_complete16(const void *sql);
    + ** A busy handler must not close the database connection
    + ** or [prepared statement] that invoked the busy handler.
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_busy_handler(sqlite3*, int(*)(void*,int), void*);
    ++SQLITE_API int sqlite3_busy_handler(sqlite3*,int(*)(void*,int),void*);
    + 
    + /*
    + ** CAPI3REF: Set A Busy Timeout
    +@@ -2186,7 +2406,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_busy_handler(sqlite3*, int(*)(void*,int),
    + **
    + ** See also:  [PRAGMA busy_timeout]
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_busy_timeout(sqlite3*, int ms);
    ++SQLITE_API int sqlite3_busy_timeout(sqlite3*, int ms);
    + 
    + /*
    + ** CAPI3REF: Convenience Routines For Running Queries
    +@@ -2261,7 +2481,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_busy_timeout(sqlite3*, int ms);
    + ** reflected in subsequent calls to [sqlite3_errcode()] or
    + ** [sqlite3_errmsg()].
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_get_table(
    ++SQLITE_API int sqlite3_get_table(
    +   sqlite3 *db,          /* An open database */
    +   const char *zSql,     /* SQL to be evaluated */
    +   char ***pazResult,    /* Results of the query */
    +@@ -2269,7 +2489,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_get_table(
    +   int *pnColumn,        /* Number of result columns written here */
    +   char **pzErrmsg       /* Error msg written here */
    + );
    +-SQLITE_API void SQLITE_STDCALL sqlite3_free_table(char **result);
    ++SQLITE_API void sqlite3_free_table(char **result);
    + 
    + /*
    + ** CAPI3REF: Formatted String Printing Functions
    +@@ -2375,10 +2595,10 @@ SQLITE_API void SQLITE_STDCALL sqlite3_free_table(char **result);
    + ** addition that after the string has been read and copied into
    + ** the result, [sqlite3_free()] is called on the input string.)^
    + */
    +-SQLITE_API char *SQLITE_CDECL sqlite3_mprintf(const char*,...);
    +-SQLITE_API char *SQLITE_STDCALL sqlite3_vmprintf(const char*, va_list);
    +-SQLITE_API char *SQLITE_CDECL sqlite3_snprintf(int,char*,const char*, ...);
    +-SQLITE_API char *SQLITE_STDCALL sqlite3_vsnprintf(int,char*,const char*, va_list);
    ++SQLITE_API char *sqlite3_mprintf(const char*,...);
    ++SQLITE_API char *sqlite3_vmprintf(const char*, va_list);
    ++SQLITE_API char *sqlite3_snprintf(int,char*,const char*, ...);
    ++SQLITE_API char *sqlite3_vsnprintf(int,char*,const char*, va_list);
    + 
    + /*
    + ** CAPI3REF: Memory Allocation Subsystem
    +@@ -2468,12 +2688,12 @@ SQLITE_API char *SQLITE_STDCALL sqlite3_vsnprintf(int,char*,const char*, va_list
    + ** a block of memory after it has been released using
    + ** [sqlite3_free()] or [sqlite3_realloc()].
    + */
    +-SQLITE_API void *SQLITE_STDCALL sqlite3_malloc(int);
    +-SQLITE_API void *SQLITE_STDCALL sqlite3_malloc64(sqlite3_uint64);
    +-SQLITE_API void *SQLITE_STDCALL sqlite3_realloc(void*, int);
    +-SQLITE_API void *SQLITE_STDCALL sqlite3_realloc64(void*, sqlite3_uint64);
    +-SQLITE_API void SQLITE_STDCALL sqlite3_free(void*);
    +-SQLITE_API sqlite3_uint64 SQLITE_STDCALL sqlite3_msize(void*);
    ++SQLITE_API void *sqlite3_malloc(int);
    ++SQLITE_API void *sqlite3_malloc64(sqlite3_uint64);
    ++SQLITE_API void *sqlite3_realloc(void*, int);
    ++SQLITE_API void *sqlite3_realloc64(void*, sqlite3_uint64);
    ++SQLITE_API void sqlite3_free(void*);
    ++SQLITE_API sqlite3_uint64 sqlite3_msize(void*);
    + 
    + /*
    + ** CAPI3REF: Memory Allocator Statistics
    +@@ -2498,8 +2718,8 @@ SQLITE_API sqlite3_uint64 SQLITE_STDCALL sqlite3_msize(void*);
    + ** by [sqlite3_memory_highwater(1)] is the high-water mark
    + ** prior to the reset.
    + */
    +-SQLITE_API sqlite3_int64 SQLITE_STDCALL sqlite3_memory_used(void);
    +-SQLITE_API sqlite3_int64 SQLITE_STDCALL sqlite3_memory_highwater(int resetFlag);
    ++SQLITE_API sqlite3_int64 sqlite3_memory_used(void);
    ++SQLITE_API sqlite3_int64 sqlite3_memory_highwater(int resetFlag);
    + 
    + /*
    + ** CAPI3REF: Pseudo-Random Number Generator
    +@@ -2522,17 +2742,19 @@ SQLITE_API sqlite3_int64 SQLITE_STDCALL sqlite3_memory_highwater(int resetFlag);
    + ** internally and without recourse to the [sqlite3_vfs] xRandomness
    + ** method.
    + */
    +-SQLITE_API void SQLITE_STDCALL sqlite3_randomness(int N, void *P);
    ++SQLITE_API void sqlite3_randomness(int N, void *P);
    + 
    + /*
    + ** CAPI3REF: Compile-Time Authorization Callbacks
    + ** METHOD: sqlite3
    ++** KEYWORDS: {authorizer callback}
    + **
    + ** ^This routine registers an authorizer callback with a particular
    + ** [database connection], supplied in the first argument.
    + ** ^The authorizer callback is invoked as SQL statements are being compiled
    + ** by [sqlite3_prepare()] or its variants [sqlite3_prepare_v2()],
    +-** [sqlite3_prepare16()] and [sqlite3_prepare16_v2()].  ^At various
    ++** [sqlite3_prepare_v3()], [sqlite3_prepare16()], [sqlite3_prepare16_v2()],
    ++** and [sqlite3_prepare16_v3()].  ^At various
    + ** points during the compilation process, as logic is being created
    + ** to perform various actions, the authorizer callback is invoked to
    + ** see if those actions are allowed.  ^The authorizer callback should
    +@@ -2554,8 +2776,10 @@ SQLITE_API void SQLITE_STDCALL sqlite3_randomness(int N, void *P);
    + ** parameter to the sqlite3_set_authorizer() interface. ^The second parameter
    + ** to the callback is an integer [SQLITE_COPY | action code] that specifies
    + ** the particular action to be authorized. ^The third through sixth parameters
    +-** to the callback are zero-terminated strings that contain additional
    +-** details about the action to be authorized.
    ++** to the callback are either NULL pointers or zero-terminated strings
    ++** that contain additional details about the action to be authorized.
    ++** Applications must always be prepared to encounter a NULL pointer in any
    ++** of the third through the sixth parameters of the authorization callback.
    + **
    + ** ^If the action code is [SQLITE_READ]
    + ** and the callback returns [SQLITE_IGNORE] then the
    +@@ -2564,6 +2788,10 @@ SQLITE_API void SQLITE_STDCALL sqlite3_randomness(int N, void *P);
    + ** been read if [SQLITE_OK] had been returned.  The [SQLITE_IGNORE]
    + ** return can be used to deny an untrusted user access to individual
    + ** columns of a table.
    ++** ^When a table is referenced by a [SELECT] but no column values are
    ++** extracted from that table (for example in a query like
    ++** "SELECT count(*) FROM tab") then the [SQLITE_READ] authorizer callback
    ++** is invoked once for that table with a column name that is an empty string.
    + ** ^If the action code is [SQLITE_DELETE] and the callback returns
    + ** [SQLITE_IGNORE] then the [DELETE] operation proceeds but the
    + ** [truncate optimization] is disabled and all rows are deleted individually.
    +@@ -2605,7 +2833,7 @@ SQLITE_API void SQLITE_STDCALL sqlite3_randomness(int N, void *P);
    + ** as stated in the previous paragraph, sqlite3_step() invokes
    + ** sqlite3_prepare_v2() to reprepare a statement after a schema change.
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_set_authorizer(
    ++SQLITE_API int sqlite3_set_authorizer(
    +   sqlite3*,
    +   int (*xAuth)(void*,int,const char*,const char*,const char*,const char*),
    +   void *pUserData
    +@@ -2685,6 +2913,9 @@ SQLITE_API int SQLITE_STDCALL sqlite3_set_authorizer(
    + ** CAPI3REF: Tracing And Profiling Functions
    + ** METHOD: sqlite3
    + **
    ++** These routines are deprecated. Use the [sqlite3_trace_v2()] interface
    ++** instead of the routines described here.
    ++**
    + ** These routines register callback functions that can be used for
    + ** tracing and profiling the execution of SQL statements.
    + **
    +@@ -2710,10 +2941,104 @@ SQLITE_API int SQLITE_STDCALL sqlite3_set_authorizer(
    + ** sqlite3_profile() function is considered experimental and is
    + ** subject to change in future versions of SQLite.
    + */
    +-SQLITE_API void *SQLITE_STDCALL sqlite3_trace(sqlite3*, void(*xTrace)(void*,const char*), void*);
    +-SQLITE_API SQLITE_EXPERIMENTAL void *SQLITE_STDCALL sqlite3_profile(sqlite3*,
    ++SQLITE_API SQLITE_DEPRECATED void *sqlite3_trace(sqlite3*,
    ++   void(*xTrace)(void*,const char*), void*);
    ++SQLITE_API SQLITE_DEPRECATED void *sqlite3_profile(sqlite3*,
    +    void(*xProfile)(void*,const char*,sqlite3_uint64), void*);
    + 
    ++/*
    ++** CAPI3REF: SQL Trace Event Codes
    ++** KEYWORDS: SQLITE_TRACE
    ++**
    ++** These constants identify classes of events that can be monitored
    ++** using the [sqlite3_trace_v2()] tracing logic.  The M argument
    ++** to [sqlite3_trace_v2(D,M,X,P)] is an OR-ed combination of one or more of
    ++** the following constants.  ^The first argument to the trace callback
    ++** is one of the following constants.
    ++**
    ++** New tracing constants may be added in future releases.
    ++**
    ++** ^A trace callback has four arguments: xCallback(T,C,P,X).
    ++** ^The T argument is one of the integer type codes above.
    ++** ^The C argument is a copy of the context pointer passed in as the
    ++** fourth argument to [sqlite3_trace_v2()].
    ++** The P and X arguments are pointers whose meanings depend on T.
    ++**
    ++** <dl>
    ++** [[SQLITE_TRACE_STMT]] <dt>SQLITE_TRACE_STMT</dt>
    ++** <dd>^An SQLITE_TRACE_STMT callback is invoked when a prepared statement
    ++** first begins running and possibly at other times during the
    ++** execution of the prepared statement, such as at the start of each
    ++** trigger subprogram. ^The P argument is a pointer to the
    ++** [prepared statement]. ^The X argument is a pointer to a string which
    ++** is the unexpanded SQL text of the prepared statement or an SQL comment 
    ++** that indicates the invocation of a trigger.  ^The callback can compute
    ++** the same text that would have been returned by the legacy [sqlite3_trace()]
    ++** interface by using the X argument when X begins with "--" and invoking
    ++** [sqlite3_expanded_sql(P)] otherwise.
    ++**
    ++** [[SQLITE_TRACE_PROFILE]] <dt>SQLITE_TRACE_PROFILE</dt>
    ++** <dd>^An SQLITE_TRACE_PROFILE callback provides approximately the same
    ++** information as is provided by the [sqlite3_profile()] callback.
    ++** ^The P argument is a pointer to the [prepared statement] and the
    ++** X argument points to a 64-bit integer which is the estimated of
    ++** the number of nanosecond that the prepared statement took to run.
    ++** ^The SQLITE_TRACE_PROFILE callback is invoked when the statement finishes.
    ++**
    ++** [[SQLITE_TRACE_ROW]] <dt>SQLITE_TRACE_ROW</dt>
    ++** <dd>^An SQLITE_TRACE_ROW callback is invoked whenever a prepared
    ++** statement generates a single row of result.  
    ++** ^The P argument is a pointer to the [prepared statement] and the
    ++** X argument is unused.
    ++**
    ++** [[SQLITE_TRACE_CLOSE]] <dt>SQLITE_TRACE_CLOSE</dt>
    ++** <dd>^An SQLITE_TRACE_CLOSE callback is invoked when a database
    ++** connection closes.
    ++** ^The P argument is a pointer to the [database connection] object
    ++** and the X argument is unused.
    ++** </dl>
    ++*/
    ++#define SQLITE_TRACE_STMT       0x01
    ++#define SQLITE_TRACE_PROFILE    0x02
    ++#define SQLITE_TRACE_ROW        0x04
    ++#define SQLITE_TRACE_CLOSE      0x08
    ++
    ++/*
    ++** CAPI3REF: SQL Trace Hook
    ++** METHOD: sqlite3
    ++**
    ++** ^The sqlite3_trace_v2(D,M,X,P) interface registers a trace callback
    ++** function X against [database connection] D, using property mask M
    ++** and context pointer P.  ^If the X callback is
    ++** NULL or if the M mask is zero, then tracing is disabled.  The
    ++** M argument should be the bitwise OR-ed combination of
    ++** zero or more [SQLITE_TRACE] constants.
    ++**
    ++** ^Each call to either sqlite3_trace() or sqlite3_trace_v2() overrides 
    ++** (cancels) any prior calls to sqlite3_trace() or sqlite3_trace_v2().
    ++**
    ++** ^The X callback is invoked whenever any of the events identified by 
    ++** mask M occur.  ^The integer return value from the callback is currently
    ++** ignored, though this may change in future releases.  Callback
    ++** implementations should return zero to ensure future compatibility.
    ++**
    ++** ^A trace callback is invoked with four arguments: callback(T,C,P,X).
    ++** ^The T argument is one of the [SQLITE_TRACE]
    ++** constants to indicate why the callback was invoked.
    ++** ^The C argument is a copy of the context pointer.
    ++** The P and X arguments are pointers whose meanings depend on T.
    ++**
    ++** The sqlite3_trace_v2() interface is intended to replace the legacy
    ++** interfaces [sqlite3_trace()] and [sqlite3_profile()], both of which
    ++** are deprecated.
    ++*/
    ++SQLITE_API int sqlite3_trace_v2(
    ++  sqlite3*,
    ++  unsigned uMask,
    ++  int(*xCallback)(unsigned,void*,void*,void*),
    ++  void *pCtx
    ++);
    ++
    + /*
    + ** CAPI3REF: Query Progress Callbacks
    + ** METHOD: sqlite3
    +@@ -2746,7 +3071,7 @@ SQLITE_API SQLITE_EXPERIMENTAL void *SQLITE_STDCALL sqlite3_profile(sqlite3*,
    + ** database connections for the meaning of "modify" in this paragraph.
    + **
    + */
    +-SQLITE_API void SQLITE_STDCALL sqlite3_progress_handler(sqlite3*, int, int(*)(void*), void*);
    ++SQLITE_API void sqlite3_progress_handler(sqlite3*, int, int(*)(void*), void*);
    + 
    + /*
    + ** CAPI3REF: Opening A New Database Connection
    +@@ -2836,10 +3161,10 @@ SQLITE_API void SQLITE_STDCALL sqlite3_progress_handler(sqlite3*, int, int(*)(vo
    + ** ^If [URI filename] interpretation is enabled, and the filename argument
    + ** begins with "file:", then the filename is interpreted as a URI. ^URI
    + ** filename interpretation is enabled if the [SQLITE_OPEN_URI] flag is
    +-** set in the fourth argument to sqlite3_open_v2(), or if it has
    ++** set in the third argument to sqlite3_open_v2(), or if it has
    + ** been enabled globally using the [SQLITE_CONFIG_URI] option with the
    + ** [sqlite3_config()] method or by the [SQLITE_USE_URI] compile-time option.
    +-** As of SQLite version 3.7.7, URI filename interpretation is turned off
    ++** URI filename interpretation is turned off
    + ** by default, but future releases of SQLite might enable URI filename
    + ** interpretation by default.  See "[URI filenames]" for additional
    + ** information.
    +@@ -2975,15 +3300,15 @@ SQLITE_API void SQLITE_STDCALL sqlite3_progress_handler(sqlite3*, int, int(*)(vo
    + **
    + ** See also: [sqlite3_temp_directory]
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_open(
    ++SQLITE_API int sqlite3_open(
    +   const char *filename,   /* Database filename (UTF-8) */
    +   sqlite3 **ppDb          /* OUT: SQLite db handle */
    + );
    +-SQLITE_API int SQLITE_STDCALL sqlite3_open16(
    ++SQLITE_API int sqlite3_open16(
    +   const void *filename,   /* Database filename (UTF-16) */
    +   sqlite3 **ppDb          /* OUT: SQLite db handle */
    + );
    +-SQLITE_API int SQLITE_STDCALL sqlite3_open_v2(
    ++SQLITE_API int sqlite3_open_v2(
    +   const char *filename,   /* Database filename (UTF-8) */
    +   sqlite3 **ppDb,         /* OUT: SQLite db handle */
    +   int flags,              /* Flags */
    +@@ -3029,9 +3354,9 @@ SQLITE_API int SQLITE_STDCALL sqlite3_open_v2(
    + ** VFS method, then the behavior of this routine is undefined and probably
    + ** undesirable.
    + */
    +-SQLITE_API const char *SQLITE_STDCALL sqlite3_uri_parameter(const char *zFilename, const char *zParam);
    +-SQLITE_API int SQLITE_STDCALL sqlite3_uri_boolean(const char *zFile, const char *zParam, int bDefault);
    +-SQLITE_API sqlite3_int64 SQLITE_STDCALL sqlite3_uri_int64(const char*, const char*, sqlite3_int64);
    ++SQLITE_API const char *sqlite3_uri_parameter(const char *zFilename, const char *zParam);
    ++SQLITE_API int sqlite3_uri_boolean(const char *zFile, const char *zParam, int bDefault);
    ++SQLITE_API sqlite3_int64 sqlite3_uri_int64(const char*, const char*, sqlite3_int64);
    + 
    + 
    + /*
    +@@ -3075,11 +3400,11 @@ SQLITE_API sqlite3_int64 SQLITE_STDCALL sqlite3_uri_int64(const char*, const cha
    + ** was invoked incorrectly by the application.  In that case, the
    + ** error code and message may or may not be set.
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_errcode(sqlite3 *db);
    +-SQLITE_API int SQLITE_STDCALL sqlite3_extended_errcode(sqlite3 *db);
    +-SQLITE_API const char *SQLITE_STDCALL sqlite3_errmsg(sqlite3*);
    +-SQLITE_API const void *SQLITE_STDCALL sqlite3_errmsg16(sqlite3*);
    +-SQLITE_API const char *SQLITE_STDCALL sqlite3_errstr(int);
    ++SQLITE_API int sqlite3_errcode(sqlite3 *db);
    ++SQLITE_API int sqlite3_extended_errcode(sqlite3 *db);
    ++SQLITE_API const char *sqlite3_errmsg(sqlite3*);
    ++SQLITE_API const void *sqlite3_errmsg16(sqlite3*);
    ++SQLITE_API const char *sqlite3_errstr(int);
    + 
    + /*
    + ** CAPI3REF: Prepared Statement Object
    +@@ -3147,7 +3472,7 @@ typedef struct sqlite3_stmt sqlite3_stmt;
    + **
    + ** New run-time limit categories may be added in future releases.
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_limit(sqlite3*, int id, int newVal);
    ++SQLITE_API int sqlite3_limit(sqlite3*, int id, int newVal);
    + 
    + /*
    + ** CAPI3REF: Run-Time Limit Categories
    +@@ -3178,9 +3503,9 @@ SQLITE_API int SQLITE_STDCALL sqlite3_limit(sqlite3*, int id, int newVal);
    + **
    + ** [[SQLITE_LIMIT_VDBE_OP]] ^(<dt>SQLITE_LIMIT_VDBE_OP</dt>
    + ** <dd>The maximum number of instructions in a virtual machine program
    +-** used to implement an SQL statement.  This limit is not currently
    +-** enforced, though that might be added in some future release of
    +-** SQLite.</dd>)^
    ++** used to implement an SQL statement.  If [sqlite3_prepare_v2()] or
    ++** the equivalent tries to allocate space for more than this many opcodes
    ++** in a single prepared statement, an SQLITE_NOMEM error is returned.</dd>)^
    + **
    + ** [[SQLITE_LIMIT_FUNCTION_ARG]] ^(<dt>SQLITE_LIMIT_FUNCTION_ARG</dt>
    + ** <dd>The maximum number of arguments on a function.</dd>)^
    +@@ -3218,23 +3543,59 @@ SQLITE_API int SQLITE_STDCALL sqlite3_limit(sqlite3*, int id, int newVal);
    + #define SQLITE_LIMIT_TRIGGER_DEPTH            10
    + #define SQLITE_LIMIT_WORKER_THREADS           11
    + 
    ++/*
    ++** CAPI3REF: Prepare Flags
    ++**
    ++** These constants define various flags that can be passed into
    ++** "prepFlags" parameter of the [sqlite3_prepare_v3()] and
    ++** [sqlite3_prepare16_v3()] interfaces.
    ++**
    ++** New flags may be added in future releases of SQLite.
    ++**
    ++** <dl>
    ++** [[SQLITE_PREPARE_PERSISTENT]] ^(<dt>SQLITE_PREPARE_PERSISTENT</dt>
    ++** <dd>The SQLITE_PREPARE_PERSISTENT flag is a hint to the query planner
    ++** that the prepared statement will be retained for a long time and
    ++** probably reused many times.)^ ^Without this flag, [sqlite3_prepare_v3()]
    ++** and [sqlite3_prepare16_v3()] assume that the prepared statement will 
    ++** be used just once or at most a few times and then destroyed using
    ++** [sqlite3_finalize()] relatively soon. The current implementation acts
    ++** on this hint by avoiding the use of [lookaside memory] so as not to
    ++** deplete the limited store of lookaside memory. Future versions of
    ++** SQLite may act on this hint differently.
    ++** </dl>
    ++*/
    ++#define SQLITE_PREPARE_PERSISTENT              0x01
    ++
    + /*
    + ** CAPI3REF: Compiling An SQL Statement
    + ** KEYWORDS: {SQL statement compiler}
    + ** METHOD: sqlite3
    + ** CONSTRUCTOR: sqlite3_stmt
    + **
    +-** To execute an SQL query, it must first be compiled into a byte-code
    +-** program using one of these routines.
    ++** To execute an SQL statement, it must first be compiled into a byte-code
    ++** program using one of these routines.  Or, in other words, these routines
    ++** are constructors for the [prepared statement] object.
    ++**
    ++** The preferred routine to use is [sqlite3_prepare_v2()].  The
    ++** [sqlite3_prepare()] interface is legacy and should be avoided.
    ++** [sqlite3_prepare_v3()] has an extra "prepFlags" option that is used
    ++** for special purposes.
    ++**
    ++** The use of the UTF-8 interfaces is preferred, as SQLite currently
    ++** does all parsing using UTF-8.  The UTF-16 interfaces are provided
    ++** as a convenience.  The UTF-16 interfaces work by converting the
    ++** input text into UTF-8, then invoking the corresponding UTF-8 interface.
    + **
    + ** The first argument, "db", is a [database connection] obtained from a
    + ** prior successful call to [sqlite3_open()], [sqlite3_open_v2()] or
    + ** [sqlite3_open16()].  The database connection must not have been closed.
    + **
    + ** The second argument, "zSql", is the statement to be compiled, encoded
    +-** as either UTF-8 or UTF-16.  The sqlite3_prepare() and sqlite3_prepare_v2()
    +-** interfaces use UTF-8, and sqlite3_prepare16() and sqlite3_prepare16_v2()
    +-** use UTF-16.
    ++** as either UTF-8 or UTF-16.  The sqlite3_prepare(), sqlite3_prepare_v2(),
    ++** and sqlite3_prepare_v3()
    ++** interfaces use UTF-8, and sqlite3_prepare16(), sqlite3_prepare16_v2(),
    ++** and sqlite3_prepare16_v3() use UTF-16.
    + **
    + ** ^If the nByte argument is negative, then zSql is read up to the
    + ** first zero terminator. ^If nByte is positive, then it is the
    +@@ -3261,10 +3622,11 @@ SQLITE_API int SQLITE_STDCALL sqlite3_limit(sqlite3*, int id, int newVal);
    + ** ^On success, the sqlite3_prepare() family of routines return [SQLITE_OK];
    + ** otherwise an [error code] is returned.
    + **
    +-** The sqlite3_prepare_v2() and sqlite3_prepare16_v2() interfaces are
    +-** recommended for all new programs. The two older interfaces are retained
    +-** for backwards compatibility, but their use is discouraged.
    +-** ^In the "v2" interfaces, the prepared statement
    ++** The sqlite3_prepare_v2(), sqlite3_prepare_v3(), sqlite3_prepare16_v2(),
    ++** and sqlite3_prepare16_v3() interfaces are recommended for all new programs.
    ++** The older interfaces (sqlite3_prepare() and sqlite3_prepare16())
    ++** are retained for backwards compatibility, but their use is discouraged.
    ++** ^In the "vX" interfaces, the prepared statement
    + ** that is returned (the [sqlite3_stmt] object) contains a copy of the
    + ** original SQL text. This causes the [sqlite3_step()] interface to
    + ** behave differently in three ways:
    +@@ -3297,33 +3659,55 @@ SQLITE_API int SQLITE_STDCALL sqlite3_limit(sqlite3*, int id, int newVal);
    + ** or [GLOB] operator or if the parameter is compared to an indexed column
    + ** and the [SQLITE_ENABLE_STAT3] compile-time option is enabled.
    + ** </li>
    ++**
    ++** <p>^sqlite3_prepare_v3() differs from sqlite3_prepare_v2() only in having
    ++** the extra prepFlags parameter, which is a bit array consisting of zero or
    ++** more of the [SQLITE_PREPARE_PERSISTENT|SQLITE_PREPARE_*] flags.  ^The
    ++** sqlite3_prepare_v2() interface works exactly the same as
    ++** sqlite3_prepare_v3() with a zero prepFlags parameter.
    + ** </ol>
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_prepare(
    ++SQLITE_API int sqlite3_prepare(
    ++  sqlite3 *db,            /* Database handle */
    ++  const char *zSql,       /* SQL statement, UTF-8 encoded */
    ++  int nByte,              /* Maximum length of zSql in bytes. */
    ++  sqlite3_stmt **ppStmt,  /* OUT: Statement handle */
    ++  const char **pzTail     /* OUT: Pointer to unused portion of zSql */
    ++);
    ++SQLITE_API int sqlite3_prepare_v2(
    +   sqlite3 *db,            /* Database handle */
    +   const char *zSql,       /* SQL statement, UTF-8 encoded */
    +   int nByte,              /* Maximum length of zSql in bytes. */
    +   sqlite3_stmt **ppStmt,  /* OUT: Statement handle */
    +   const char **pzTail     /* OUT: Pointer to unused portion of zSql */
    + );
    +-SQLITE_API int SQLITE_STDCALL sqlite3_prepare_v2(
    ++SQLITE_API int sqlite3_prepare_v3(
    +   sqlite3 *db,            /* Database handle */
    +   const char *zSql,       /* SQL statement, UTF-8 encoded */
    +   int nByte,              /* Maximum length of zSql in bytes. */
    ++  unsigned int prepFlags, /* Zero or more SQLITE_PREPARE_ flags */
    +   sqlite3_stmt **ppStmt,  /* OUT: Statement handle */
    +   const char **pzTail     /* OUT: Pointer to unused portion of zSql */
    + );
    +-SQLITE_API int SQLITE_STDCALL sqlite3_prepare16(
    ++SQLITE_API int sqlite3_prepare16(
    ++  sqlite3 *db,            /* Database handle */
    ++  const void *zSql,       /* SQL statement, UTF-16 encoded */
    ++  int nByte,              /* Maximum length of zSql in bytes. */
    ++  sqlite3_stmt **ppStmt,  /* OUT: Statement handle */
    ++  const void **pzTail     /* OUT: Pointer to unused portion of zSql */
    ++);
    ++SQLITE_API int sqlite3_prepare16_v2(
    +   sqlite3 *db,            /* Database handle */
    +   const void *zSql,       /* SQL statement, UTF-16 encoded */
    +   int nByte,              /* Maximum length of zSql in bytes. */
    +   sqlite3_stmt **ppStmt,  /* OUT: Statement handle */
    +   const void **pzTail     /* OUT: Pointer to unused portion of zSql */
    + );
    +-SQLITE_API int SQLITE_STDCALL sqlite3_prepare16_v2(
    ++SQLITE_API int sqlite3_prepare16_v3(
    +   sqlite3 *db,            /* Database handle */
    +   const void *zSql,       /* SQL statement, UTF-16 encoded */
    +   int nByte,              /* Maximum length of zSql in bytes. */
    ++  unsigned int prepFlags, /* Zero or more SQLITE_PREPARE_ flags */
    +   sqlite3_stmt **ppStmt,  /* OUT: Statement handle */
    +   const void **pzTail     /* OUT: Pointer to unused portion of zSql */
    + );
    +@@ -3332,11 +3716,36 @@ SQLITE_API int SQLITE_STDCALL sqlite3_prepare16_v2(
    + ** CAPI3REF: Retrieving Statement SQL
    + ** METHOD: sqlite3_stmt
    + **
    +-** ^This interface can be used to retrieve a saved copy of the original
    +-** SQL text used to create a [prepared statement] if that statement was
    +-** compiled using either [sqlite3_prepare_v2()] or [sqlite3_prepare16_v2()].
    ++** ^The sqlite3_sql(P) interface returns a pointer to a copy of the UTF-8
    ++** SQL text used to create [prepared statement] P if P was
    ++** created by [sqlite3_prepare_v2()], [sqlite3_prepare_v3()],
    ++** [sqlite3_prepare16_v2()], or [sqlite3_prepare16_v3()].
    ++** ^The sqlite3_expanded_sql(P) interface returns a pointer to a UTF-8
    ++** string containing the SQL text of prepared statement P with
    ++** [bound parameters] expanded.
    ++**
    ++** ^(For example, if a prepared statement is created using the SQL
    ++** text "SELECT $abc,:xyz" and if parameter $abc is bound to integer 2345
    ++** and parameter :xyz is unbound, then sqlite3_sql() will return
    ++** the original string, "SELECT $abc,:xyz" but sqlite3_expanded_sql()
    ++** will return "SELECT 2345,NULL".)^
    ++**
    ++** ^The sqlite3_expanded_sql() interface returns NULL if insufficient memory
    ++** is available to hold the result, or if the result would exceed the
    ++** the maximum string length determined by the [SQLITE_LIMIT_LENGTH].
    ++**
    ++** ^The [SQLITE_TRACE_SIZE_LIMIT] compile-time option limits the size of
    ++** bound parameter expansions.  ^The [SQLITE_OMIT_TRACE] compile-time
    ++** option causes sqlite3_expanded_sql() to always return NULL.
    ++**
    ++** ^The string returned by sqlite3_sql(P) is managed by SQLite and is
    ++** automatically freed when the prepared statement is finalized.
    ++** ^The string returned by sqlite3_expanded_sql(P), on the other hand,
    ++** is obtained from [sqlite3_malloc()] and must be free by the application
    ++** by passing it to [sqlite3_free()].
    + */
    +-SQLITE_API const char *SQLITE_STDCALL sqlite3_sql(sqlite3_stmt *pStmt);
    ++SQLITE_API const char *sqlite3_sql(sqlite3_stmt *pStmt);
    ++SQLITE_API char *sqlite3_expanded_sql(sqlite3_stmt *pStmt);
    + 
    + /*
    + ** CAPI3REF: Determine If An SQL Statement Writes The Database
    +@@ -3367,8 +3776,12 @@ SQLITE_API const char *SQLITE_STDCALL sqlite3_sql(sqlite3_stmt *pStmt);
    + ** sqlite3_stmt_readonly() to return true since, while those statements
    + ** change the configuration of a database connection, they do not make 
    + ** changes to the content of the database files on disk.
    ++** ^The sqlite3_stmt_readonly() interface returns true for [BEGIN] since
    ++** [BEGIN] merely sets internal flags, but the [BEGIN|BEGIN IMMEDIATE] and
    ++** [BEGIN|BEGIN EXCLUSIVE] commands do touch the database and so
    ++** sqlite3_stmt_readonly() returns false for those commands.
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_stmt_readonly(sqlite3_stmt *pStmt);
    ++SQLITE_API int sqlite3_stmt_readonly(sqlite3_stmt *pStmt);
    + 
    + /*
    + ** CAPI3REF: Determine If A Prepared Statement Has Been Reset
    +@@ -3389,7 +3802,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_stmt_readonly(sqlite3_stmt *pStmt);
    + ** for example, in diagnostic routines to search for prepared 
    + ** statements that are holding a transaction open.
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_stmt_busy(sqlite3_stmt*);
    ++SQLITE_API int sqlite3_stmt_busy(sqlite3_stmt*);
    + 
    + /*
    + ** CAPI3REF: Dynamically Typed Value Object
    +@@ -3425,12 +3838,13 @@ SQLITE_API int SQLITE_STDCALL sqlite3_stmt_busy(sqlite3_stmt*);
    + ** implementation of [application-defined SQL functions] are protected.
    + ** ^The sqlite3_value object returned by
    + ** [sqlite3_column_value()] is unprotected.
    +-** Unprotected sqlite3_value objects may only be used with
    +-** [sqlite3_result_value()] and [sqlite3_bind_value()].
    ++** Unprotected sqlite3_value objects may only be used as arguments
    ++** to [sqlite3_result_value()], [sqlite3_bind_value()], and
    ++** [sqlite3_value_dup()].
    + ** The [sqlite3_value_blob | sqlite3_value_type()] family of
    + ** interfaces require protected sqlite3_value objects.
    + */
    +-typedef struct Mem sqlite3_value;
    ++typedef struct sqlite3_value sqlite3_value;
    + 
    + /*
    + ** CAPI3REF: SQL Function Context Object
    +@@ -3532,6 +3946,15 @@ typedef struct sqlite3_context sqlite3_context;
    + ** [sqlite3_blob_open | incremental BLOB I/O] routines.
    + ** ^A negative value for the zeroblob results in a zero-length BLOB.
    + **
    ++** ^The sqlite3_bind_pointer(S,I,P,T,D) routine causes the I-th parameter in
    ++** [prepared statement] S to have an SQL value of NULL, but to also be
    ++** associated with the pointer P of type T.  ^D is either a NULL pointer or
    ++** a pointer to a destructor function for P. ^SQLite will invoke the
    ++** destructor D with a single argument of P when it is finished using
    ++** P.  The T parameter should be a static string, preferably a string
    ++** literal. The sqlite3_bind_pointer() routine is part of the
    ++** [pointer passing interface] added for SQLite 3.20.0.
    ++**
    + ** ^If any of the sqlite3_bind_*() routines are called with a NULL pointer
    + ** for the [prepared statement] or with a prepared statement for which
    + ** [sqlite3_step()] has been called more recently than [sqlite3_reset()],
    +@@ -3553,20 +3976,21 @@ typedef struct sqlite3_context sqlite3_context;
    + ** See also: [sqlite3_bind_parameter_count()],
    + ** [sqlite3_bind_parameter_name()], and [sqlite3_bind_parameter_index()].
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_bind_blob(sqlite3_stmt*, int, const void*, int n, void(*)(void*));
    +-SQLITE_API int SQLITE_STDCALL sqlite3_bind_blob64(sqlite3_stmt*, int, const void*, sqlite3_uint64,
    ++SQLITE_API int sqlite3_bind_blob(sqlite3_stmt*, int, const void*, int n, void(*)(void*));
    ++SQLITE_API int sqlite3_bind_blob64(sqlite3_stmt*, int, const void*, sqlite3_uint64,
    +                         void(*)(void*));
    +-SQLITE_API int SQLITE_STDCALL sqlite3_bind_double(sqlite3_stmt*, int, double);
    +-SQLITE_API int SQLITE_STDCALL sqlite3_bind_int(sqlite3_stmt*, int, int);
    +-SQLITE_API int SQLITE_STDCALL sqlite3_bind_int64(sqlite3_stmt*, int, sqlite3_int64);
    +-SQLITE_API int SQLITE_STDCALL sqlite3_bind_null(sqlite3_stmt*, int);
    +-SQLITE_API int SQLITE_STDCALL sqlite3_bind_text(sqlite3_stmt*,int,const char*,int,void(*)(void*));
    +-SQLITE_API int SQLITE_STDCALL sqlite3_bind_text16(sqlite3_stmt*, int, const void*, int, void(*)(void*));
    +-SQLITE_API int SQLITE_STDCALL sqlite3_bind_text64(sqlite3_stmt*, int, const char*, sqlite3_uint64,
    ++SQLITE_API int sqlite3_bind_double(sqlite3_stmt*, int, double);
    ++SQLITE_API int sqlite3_bind_int(sqlite3_stmt*, int, int);
    ++SQLITE_API int sqlite3_bind_int64(sqlite3_stmt*, int, sqlite3_int64);
    ++SQLITE_API int sqlite3_bind_null(sqlite3_stmt*, int);
    ++SQLITE_API int sqlite3_bind_text(sqlite3_stmt*,int,const char*,int,void(*)(void*));
    ++SQLITE_API int sqlite3_bind_text16(sqlite3_stmt*, int, const void*, int, void(*)(void*));
    ++SQLITE_API int sqlite3_bind_text64(sqlite3_stmt*, int, const char*, sqlite3_uint64,
    +                          void(*)(void*), unsigned char encoding);
    +-SQLITE_API int SQLITE_STDCALL sqlite3_bind_value(sqlite3_stmt*, int, const sqlite3_value*);
    +-SQLITE_API int SQLITE_STDCALL sqlite3_bind_zeroblob(sqlite3_stmt*, int, int n);
    +-SQLITE_API int SQLITE_STDCALL sqlite3_bind_zeroblob64(sqlite3_stmt*, int, sqlite3_uint64);
    ++SQLITE_API int sqlite3_bind_value(sqlite3_stmt*, int, const sqlite3_value*);
    ++SQLITE_API int sqlite3_bind_pointer(sqlite3_stmt*, int, void*, const char*,void(*)(void*));
    ++SQLITE_API int sqlite3_bind_zeroblob(sqlite3_stmt*, int, int n);
    ++SQLITE_API int sqlite3_bind_zeroblob64(sqlite3_stmt*, int, sqlite3_uint64);
    + 
    + /*
    + ** CAPI3REF: Number Of SQL Parameters
    +@@ -3587,7 +4011,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_bind_zeroblob64(sqlite3_stmt*, int, sqlite
    + ** [sqlite3_bind_parameter_name()], and
    + ** [sqlite3_bind_parameter_index()].
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_bind_parameter_count(sqlite3_stmt*);
    ++SQLITE_API int sqlite3_bind_parameter_count(sqlite3_stmt*);
    + 
    + /*
    + ** CAPI3REF: Name Of A Host Parameter
    +@@ -3608,14 +4032,14 @@ SQLITE_API int SQLITE_STDCALL sqlite3_bind_parameter_count(sqlite3_stmt*);
    + ** ^If the value N is out of range or if the N-th parameter is
    + ** nameless, then NULL is returned.  ^The returned string is
    + ** always in UTF-8 encoding even if the named parameter was
    +-** originally specified as UTF-16 in [sqlite3_prepare16()] or
    +-** [sqlite3_prepare16_v2()].
    ++** originally specified as UTF-16 in [sqlite3_prepare16()],
    ++** [sqlite3_prepare16_v2()], or [sqlite3_prepare16_v3()].
    + **
    + ** See also: [sqlite3_bind_blob|sqlite3_bind()],
    + ** [sqlite3_bind_parameter_count()], and
    + ** [sqlite3_bind_parameter_index()].
    + */
    +-SQLITE_API const char *SQLITE_STDCALL sqlite3_bind_parameter_name(sqlite3_stmt*, int);
    ++SQLITE_API const char *sqlite3_bind_parameter_name(sqlite3_stmt*, int);
    + 
    + /*
    + ** CAPI3REF: Index Of A Parameter With A Given Name
    +@@ -3626,13 +4050,14 @@ SQLITE_API const char *SQLITE_STDCALL sqlite3_bind_parameter_name(sqlite3_stmt*,
    + ** parameter to [sqlite3_bind_blob|sqlite3_bind()].  ^A zero
    + ** is returned if no matching parameter is found.  ^The parameter
    + ** name must be given in UTF-8 even if the original statement
    +-** was prepared from UTF-16 text using [sqlite3_prepare16_v2()].
    ++** was prepared from UTF-16 text using [sqlite3_prepare16_v2()] or
    ++** [sqlite3_prepare16_v3()].
    + **
    + ** See also: [sqlite3_bind_blob|sqlite3_bind()],
    + ** [sqlite3_bind_parameter_count()], and
    + ** [sqlite3_bind_parameter_name()].
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_bind_parameter_index(sqlite3_stmt*, const char *zName);
    ++SQLITE_API int sqlite3_bind_parameter_index(sqlite3_stmt*, const char *zName);
    + 
    + /*
    + ** CAPI3REF: Reset All Bindings On A Prepared Statement
    +@@ -3642,19 +4067,23 @@ SQLITE_API int SQLITE_STDCALL sqlite3_bind_parameter_index(sqlite3_stmt*, const
    + ** the [sqlite3_bind_blob | bindings] on a [prepared statement].
    + ** ^Use this routine to reset all host parameters to NULL.
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_clear_bindings(sqlite3_stmt*);
    ++SQLITE_API int sqlite3_clear_bindings(sqlite3_stmt*);
    + 
    + /*
    + ** CAPI3REF: Number Of Columns In A Result Set
    + ** METHOD: sqlite3_stmt
    + **
    + ** ^Return the number of columns in the result set returned by the
    +-** [prepared statement]. ^This routine returns 0 if pStmt is an SQL
    +-** statement that does not return data (for example an [UPDATE]).
    ++** [prepared statement]. ^If this routine returns 0, that means the 
    ++** [prepared statement] returns no data (for example an [UPDATE]).
    ++** ^However, just because this routine returns a positive number does not
    ++** mean that one or more rows of data will be returned.  ^A SELECT statement
    ++** will always have a positive sqlite3_column_count() but depending on the
    ++** WHERE clause constraints and the table content, it might return no rows.
    + **
    + ** See also: [sqlite3_data_count()]
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_column_count(sqlite3_stmt *pStmt);
    ++SQLITE_API int sqlite3_column_count(sqlite3_stmt *pStmt);
    + 
    + /*
    + ** CAPI3REF: Column Names In A Result Set
    +@@ -3683,8 +4112,8 @@ SQLITE_API int SQLITE_STDCALL sqlite3_column_count(sqlite3_stmt *pStmt);
    + ** then the name of the column is unspecified and may change from
    + ** one release of SQLite to the next.
    + */
    +-SQLITE_API const char *SQLITE_STDCALL sqlite3_column_name(sqlite3_stmt*, int N);
    +-SQLITE_API const void *SQLITE_STDCALL sqlite3_column_name16(sqlite3_stmt*, int N);
    ++SQLITE_API const char *sqlite3_column_name(sqlite3_stmt*, int N);
    ++SQLITE_API const void *sqlite3_column_name16(sqlite3_stmt*, int N);
    + 
    + /*
    + ** CAPI3REF: Source Of Data In A Query Result
    +@@ -3732,12 +4161,12 @@ SQLITE_API const void *SQLITE_STDCALL sqlite3_column_name16(sqlite3_stmt*, int N
    + ** for the same [prepared statement] and result column
    + ** at the same time then the results are undefined.
    + */
    +-SQLITE_API const char *SQLITE_STDCALL sqlite3_column_database_name(sqlite3_stmt*,int);
    +-SQLITE_API const void *SQLITE_STDCALL sqlite3_column_database_name16(sqlite3_stmt*,int);
    +-SQLITE_API const char *SQLITE_STDCALL sqlite3_column_table_name(sqlite3_stmt*,int);
    +-SQLITE_API const void *SQLITE_STDCALL sqlite3_column_table_name16(sqlite3_stmt*,int);
    +-SQLITE_API const char *SQLITE_STDCALL sqlite3_column_origin_name(sqlite3_stmt*,int);
    +-SQLITE_API const void *SQLITE_STDCALL sqlite3_column_origin_name16(sqlite3_stmt*,int);
    ++SQLITE_API const char *sqlite3_column_database_name(sqlite3_stmt*,int);
    ++SQLITE_API const void *sqlite3_column_database_name16(sqlite3_stmt*,int);
    ++SQLITE_API const char *sqlite3_column_table_name(sqlite3_stmt*,int);
    ++SQLITE_API const void *sqlite3_column_table_name16(sqlite3_stmt*,int);
    ++SQLITE_API const char *sqlite3_column_origin_name(sqlite3_stmt*,int);
    ++SQLITE_API const void *sqlite3_column_origin_name16(sqlite3_stmt*,int);
    + 
    + /*
    + ** CAPI3REF: Declared Datatype Of A Query Result
    +@@ -3769,23 +4198,25 @@ SQLITE_API const void *SQLITE_STDCALL sqlite3_column_origin_name16(sqlite3_stmt*
    + ** is associated with individual values, not with the containers
    + ** used to hold those values.
    + */
    +-SQLITE_API const char *SQLITE_STDCALL sqlite3_column_decltype(sqlite3_stmt*,int);
    +-SQLITE_API const void *SQLITE_STDCALL sqlite3_column_decltype16(sqlite3_stmt*,int);
    ++SQLITE_API const char *sqlite3_column_decltype(sqlite3_stmt*,int);
    ++SQLITE_API const void *sqlite3_column_decltype16(sqlite3_stmt*,int);
    + 
    + /*
    + ** CAPI3REF: Evaluate An SQL Statement
    + ** METHOD: sqlite3_stmt
    + **
    +-** After a [prepared statement] has been prepared using either
    +-** [sqlite3_prepare_v2()] or [sqlite3_prepare16_v2()] or one of the legacy
    ++** After a [prepared statement] has been prepared using any of
    ++** [sqlite3_prepare_v2()], [sqlite3_prepare_v3()], [sqlite3_prepare16_v2()],
    ++** or [sqlite3_prepare16_v3()] or one of the legacy
    + ** interfaces [sqlite3_prepare()] or [sqlite3_prepare16()], this function
    + ** must be called one or more times to evaluate the statement.
    + **
    + ** The details of the behavior of the sqlite3_step() interface depend
    +-** on whether the statement was prepared using the newer "v2" interface
    +-** [sqlite3_prepare_v2()] and [sqlite3_prepare16_v2()] or the older legacy
    +-** interface [sqlite3_prepare()] and [sqlite3_prepare16()].  The use of the
    +-** new "v2" interface is recommended for new applications but the legacy
    ++** on whether the statement was prepared using the newer "vX" interfaces
    ++** [sqlite3_prepare_v3()], [sqlite3_prepare_v2()], [sqlite3_prepare16_v3()],
    ++** [sqlite3_prepare16_v2()] or the older legacy
    ++** interfaces [sqlite3_prepare()] and [sqlite3_prepare16()].  The use of the
    ++** new "vX" interface is recommended for new applications but the legacy
    + ** interface will continue to be supported.
    + **
    + ** ^In the legacy interface, the return value will be either [SQLITE_BUSY],
    +@@ -3831,7 +4262,8 @@ SQLITE_API const void *SQLITE_STDCALL sqlite3_column_decltype16(sqlite3_stmt*,in
    + ** other than [SQLITE_ROW] before any subsequent invocation of
    + ** sqlite3_step().  Failure to reset the prepared statement using 
    + ** [sqlite3_reset()] would result in an [SQLITE_MISUSE] return from
    +-** sqlite3_step().  But after version 3.6.23.1, sqlite3_step() began
    ++** sqlite3_step().  But after [version 3.6.23.1] ([dateof:3.6.23.1],
    ++** sqlite3_step() began
    + ** calling [sqlite3_reset()] automatically in this circumstance rather
    + ** than returning [SQLITE_MISUSE].  This is not considered a compatibility
    + ** break because any application that ever receives an SQLITE_MISUSE error
    +@@ -3845,12 +4277,13 @@ SQLITE_API const void *SQLITE_STDCALL sqlite3_column_decltype16(sqlite3_stmt*,in
    + ** specific [error codes] that better describes the error.
    + ** We admit that this is a goofy design.  The problem has been fixed
    + ** with the "v2" interface.  If you prepare all of your SQL statements
    +-** using either [sqlite3_prepare_v2()] or [sqlite3_prepare16_v2()] instead
    ++** using [sqlite3_prepare_v3()] or [sqlite3_prepare_v2()]
    ++** or [sqlite3_prepare16_v2()] or [sqlite3_prepare16_v3()] instead
    + ** of the legacy [sqlite3_prepare()] and [sqlite3_prepare16()] interfaces,
    + ** then the more specific [error codes] are returned directly
    +-** by sqlite3_step().  The use of the "v2" interface is recommended.
    ++** by sqlite3_step().  The use of the "vX" interfaces is recommended.
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_step(sqlite3_stmt*);
    ++SQLITE_API int sqlite3_step(sqlite3_stmt*);
    + 
    + /*
    + ** CAPI3REF: Number of columns in a result set
    +@@ -3871,7 +4304,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_step(sqlite3_stmt*);
    + **
    + ** See also: [sqlite3_column_count()]
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_data_count(sqlite3_stmt *pStmt);
    ++SQLITE_API int sqlite3_data_count(sqlite3_stmt *pStmt);
    + 
    + /*
    + ** CAPI3REF: Fundamental Datatypes
    +@@ -3910,6 +4343,28 @@ SQLITE_API int SQLITE_STDCALL sqlite3_data_count(sqlite3_stmt *pStmt);
    + ** KEYWORDS: {column access functions}
    + ** METHOD: sqlite3_stmt
    + **
    ++** <b>Summary:</b>
    ++** <blockquote><table border=0 cellpadding=0 cellspacing=0>
    ++** <tr><td><b>sqlite3_column_blob</b><td>&rarr;<td>BLOB result
    ++** <tr><td><b>sqlite3_column_double</b><td>&rarr;<td>REAL result
    ++** <tr><td><b>sqlite3_column_int</b><td>&rarr;<td>32-bit INTEGER result
    ++** <tr><td><b>sqlite3_column_int64</b><td>&rarr;<td>64-bit INTEGER result
    ++** <tr><td><b>sqlite3_column_text</b><td>&rarr;<td>UTF-8 TEXT result
    ++** <tr><td><b>sqlite3_column_text16</b><td>&rarr;<td>UTF-16 TEXT result
    ++** <tr><td><b>sqlite3_column_value</b><td>&rarr;<td>The result as an 
    ++** [sqlite3_value|unprotected sqlite3_value] object.
    ++** <tr><td>&nbsp;<td>&nbsp;<td>&nbsp;
    ++** <tr><td><b>sqlite3_column_bytes</b><td>&rarr;<td>Size of a BLOB
    ++** or a UTF-8 TEXT result in bytes
    ++** <tr><td><b>sqlite3_column_bytes16&nbsp;&nbsp;</b>
    ++** <td>&rarr;&nbsp;&nbsp;<td>Size of UTF-16
    ++** TEXT in bytes
    ++** <tr><td><b>sqlite3_column_type</b><td>&rarr;<td>Default
    ++** datatype of the result
    ++** </table></blockquote>
    ++**
    ++** <b>Details:</b>
    ++**
    + ** ^These routines return information about a single column of the current
    + ** result row of a query.  ^In every case the first argument is a pointer
    + ** to the [prepared statement] that is being evaluated (the [sqlite3_stmt*]
    +@@ -3931,16 +4386,29 @@ SQLITE_API int SQLITE_STDCALL sqlite3_data_count(sqlite3_stmt *pStmt);
    + ** are called from a different thread while any of these routines
    + ** are pending, then the results are undefined.
    + **
    ++** The first six interfaces (_blob, _double, _int, _int64, _text, and _text16)
    ++** each return the value of a result column in a specific data format.  If
    ++** the result column is not initially in the requested format (for example,
    ++** if the query returns an integer but the sqlite3_column_text() interface
    ++** is used to extract the value) then an automatic type conversion is performed.
    ++**
    + ** ^The sqlite3_column_type() routine returns the
    + ** [SQLITE_INTEGER | datatype code] for the initial data type
    + ** of the result column.  ^The returned value is one of [SQLITE_INTEGER],
    +-** [SQLITE_FLOAT], [SQLITE_TEXT], [SQLITE_BLOB], or [SQLITE_NULL].  The value
    +-** returned by sqlite3_column_type() is only meaningful if no type
    +-** conversions have occurred as described below.  After a type conversion,
    +-** the value returned by sqlite3_column_type() is undefined.  Future
    ++** [SQLITE_FLOAT], [SQLITE_TEXT], [SQLITE_BLOB], or [SQLITE_NULL].
    ++** The return value of sqlite3_column_type() can be used to decide which
    ++** of the first six interface should be used to extract the column value.
    ++** The value returned by sqlite3_column_type() is only meaningful if no
    ++** automatic type conversions have occurred for the value in question.  
    ++** After a type conversion, the result of calling sqlite3_column_type()
    ++** is undefined, though harmless.  Future
    + ** versions of SQLite may change the behavior of sqlite3_column_type()
    + ** following a type conversion.
    + **
    ++** If the result is a BLOB or a TEXT string, then the sqlite3_column_bytes()
    ++** or sqlite3_column_bytes16() interfaces can be used to determine the size
    ++** of that BLOB or string.
    ++**
    + ** ^If the result is a BLOB or UTF-8 string then the sqlite3_column_bytes()
    + ** routine returns the number of bytes in that BLOB or string.
    + ** ^If the result is a UTF-16 string, then sqlite3_column_bytes() converts
    +@@ -3977,9 +4445,13 @@ SQLITE_API int SQLITE_STDCALL sqlite3_data_count(sqlite3_stmt *pStmt);
    + ** [sqlite3_column_value()] is used in any other way, including calls
    + ** to routines like [sqlite3_value_int()], [sqlite3_value_text()],
    + ** or [sqlite3_value_bytes()], the behavior is not threadsafe.
    ++** Hence, the sqlite3_column_value() interface
    ++** is normally only useful within the implementation of 
    ++** [application-defined SQL functions] or [virtual tables], not within
    ++** top-level application code.
    + **
    +-** These routines attempt to convert the value where appropriate.  ^For
    +-** example, if the internal representation is FLOAT and a text result
    ++** The these routines may attempt to convert the datatype of the result.
    ++** ^For example, if the internal representation is FLOAT and a text result
    + ** is requested, [sqlite3_snprintf()] is used internally to perform the
    + ** conversion automatically.  ^(The following table details the conversions
    + ** that are applied:
    +@@ -4051,7 +4523,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_data_count(sqlite3_stmt *pStmt);
    + ** ^The pointers returned are valid until a type conversion occurs as
    + ** described above, or until [sqlite3_step()] or [sqlite3_reset()] or
    + ** [sqlite3_finalize()] is called.  ^The memory space used to hold strings
    +-** and BLOBs is freed automatically.  Do <em>not</em> pass the pointers returned
    ++** and BLOBs is freed automatically.  Do not pass the pointers returned
    + ** from [sqlite3_column_blob()], [sqlite3_column_text()], etc. into
    + ** [sqlite3_free()].
    + **
    +@@ -4061,16 +4533,16 @@ SQLITE_API int SQLITE_STDCALL sqlite3_data_count(sqlite3_stmt *pStmt);
    + ** pointer.  Subsequent calls to [sqlite3_errcode()] will return
    + ** [SQLITE_NOMEM].)^
    + */
    +-SQLITE_API const void *SQLITE_STDCALL sqlite3_column_blob(sqlite3_stmt*, int iCol);
    +-SQLITE_API int SQLITE_STDCALL sqlite3_column_bytes(sqlite3_stmt*, int iCol);
    +-SQLITE_API int SQLITE_STDCALL sqlite3_column_bytes16(sqlite3_stmt*, int iCol);
    +-SQLITE_API double SQLITE_STDCALL sqlite3_column_double(sqlite3_stmt*, int iCol);
    +-SQLITE_API int SQLITE_STDCALL sqlite3_column_int(sqlite3_stmt*, int iCol);
    +-SQLITE_API sqlite3_int64 SQLITE_STDCALL sqlite3_column_int64(sqlite3_stmt*, int iCol);
    +-SQLITE_API const unsigned char *SQLITE_STDCALL sqlite3_column_text(sqlite3_stmt*, int iCol);
    +-SQLITE_API const void *SQLITE_STDCALL sqlite3_column_text16(sqlite3_stmt*, int iCol);
    +-SQLITE_API int SQLITE_STDCALL sqlite3_column_type(sqlite3_stmt*, int iCol);
    +-SQLITE_API sqlite3_value *SQLITE_STDCALL sqlite3_column_value(sqlite3_stmt*, int iCol);
    ++SQLITE_API const void *sqlite3_column_blob(sqlite3_stmt*, int iCol);
    ++SQLITE_API double sqlite3_column_double(sqlite3_stmt*, int iCol);
    ++SQLITE_API int sqlite3_column_int(sqlite3_stmt*, int iCol);
    ++SQLITE_API sqlite3_int64 sqlite3_column_int64(sqlite3_stmt*, int iCol);
    ++SQLITE_API const unsigned char *sqlite3_column_text(sqlite3_stmt*, int iCol);
    ++SQLITE_API const void *sqlite3_column_text16(sqlite3_stmt*, int iCol);
    ++SQLITE_API sqlite3_value *sqlite3_column_value(sqlite3_stmt*, int iCol);
    ++SQLITE_API int sqlite3_column_bytes(sqlite3_stmt*, int iCol);
    ++SQLITE_API int sqlite3_column_bytes16(sqlite3_stmt*, int iCol);
    ++SQLITE_API int sqlite3_column_type(sqlite3_stmt*, int iCol);
    + 
    + /*
    + ** CAPI3REF: Destroy A Prepared Statement Object
    +@@ -4098,7 +4570,7 @@ SQLITE_API sqlite3_value *SQLITE_STDCALL sqlite3_column_value(sqlite3_stmt*, int
    + ** statement after it has been finalized can result in undefined and
    + ** undesirable behavior such as segfaults and heap corruption.
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_finalize(sqlite3_stmt *pStmt);
    ++SQLITE_API int sqlite3_finalize(sqlite3_stmt *pStmt);
    + 
    + /*
    + ** CAPI3REF: Reset A Prepared Statement Object
    +@@ -4125,7 +4597,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_finalize(sqlite3_stmt *pStmt);
    + ** ^The [sqlite3_reset(S)] interface does not change the values
    + ** of any [sqlite3_bind_blob|bindings] on the [prepared statement] S.
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_reset(sqlite3_stmt *pStmt);
    ++SQLITE_API int sqlite3_reset(sqlite3_stmt *pStmt);
    + 
    + /*
    + ** CAPI3REF: Create Or Redefine SQL Functions
    +@@ -4225,7 +4697,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_reset(sqlite3_stmt *pStmt);
    + ** close the database connection nor finalize or reset the prepared
    + ** statement in which the function is running.
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_create_function(
    ++SQLITE_API int sqlite3_create_function(
    +   sqlite3 *db,
    +   const char *zFunctionName,
    +   int nArg,
    +@@ -4235,7 +4707,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_create_function(
    +   void (*xStep)(sqlite3_context*,int,sqlite3_value**),
    +   void (*xFinal)(sqlite3_context*)
    + );
    +-SQLITE_API int SQLITE_STDCALL sqlite3_create_function16(
    ++SQLITE_API int sqlite3_create_function16(
    +   sqlite3 *db,
    +   const void *zFunctionName,
    +   int nArg,
    +@@ -4245,7 +4717,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_create_function16(
    +   void (*xStep)(sqlite3_context*,int,sqlite3_value**),
    +   void (*xFinal)(sqlite3_context*)
    + );
    +-SQLITE_API int SQLITE_STDCALL sqlite3_create_function_v2(
    ++SQLITE_API int sqlite3_create_function_v2(
    +   sqlite3 *db,
    +   const char *zFunctionName,
    +   int nArg,
    +@@ -4291,12 +4763,12 @@ SQLITE_API int SQLITE_STDCALL sqlite3_create_function_v2(
    + ** these functions, we will not explain what they do.
    + */
    + #ifndef SQLITE_OMIT_DEPRECATED
    +-SQLITE_API SQLITE_DEPRECATED int SQLITE_STDCALL sqlite3_aggregate_count(sqlite3_context*);
    +-SQLITE_API SQLITE_DEPRECATED int SQLITE_STDCALL sqlite3_expired(sqlite3_stmt*);
    +-SQLITE_API SQLITE_DEPRECATED int SQLITE_STDCALL sqlite3_transfer_bindings(sqlite3_stmt*, sqlite3_stmt*);
    +-SQLITE_API SQLITE_DEPRECATED int SQLITE_STDCALL sqlite3_global_recover(void);
    +-SQLITE_API SQLITE_DEPRECATED void SQLITE_STDCALL sqlite3_thread_cleanup(void);
    +-SQLITE_API SQLITE_DEPRECATED int SQLITE_STDCALL sqlite3_memory_alarm(void(*)(void*,sqlite3_int64,int),
    ++SQLITE_API SQLITE_DEPRECATED int sqlite3_aggregate_count(sqlite3_context*);
    ++SQLITE_API SQLITE_DEPRECATED int sqlite3_expired(sqlite3_stmt*);
    ++SQLITE_API SQLITE_DEPRECATED int sqlite3_transfer_bindings(sqlite3_stmt*, sqlite3_stmt*);
    ++SQLITE_API SQLITE_DEPRECATED int sqlite3_global_recover(void);
    ++SQLITE_API SQLITE_DEPRECATED void sqlite3_thread_cleanup(void);
    ++SQLITE_API SQLITE_DEPRECATED int sqlite3_memory_alarm(void(*)(void*,sqlite3_int64,int),
    +                       void*,sqlite3_int64);
    + #endif
    + 
    +@@ -4304,21 +4776,43 @@ SQLITE_API SQLITE_DEPRECATED int SQLITE_STDCALL sqlite3_memory_alarm(void(*)(voi
    + ** CAPI3REF: Obtaining SQL Values
    + ** METHOD: sqlite3_value
    + **
    +-** The C-language implementation of SQL functions and aggregates uses
    +-** this set of interface routines to access the parameter values on
    +-** the function or aggregate.  
    +-**
    +-** The xFunc (for scalar functions) or xStep (for aggregates) parameters
    +-** to [sqlite3_create_function()] and [sqlite3_create_function16()]
    +-** define callbacks that implement the SQL functions and aggregates.
    +-** The 3rd parameter to these callbacks is an array of pointers to
    +-** [protected sqlite3_value] objects.  There is one [sqlite3_value] object for
    +-** each parameter to the SQL function.  These routines are used to
    +-** extract values from the [sqlite3_value] objects.
    ++** <b>Summary:</b>
    ++** <blockquote><table border=0 cellpadding=0 cellspacing=0>
    ++** <tr><td><b>sqlite3_value_blob</b><td>&rarr;<td>BLOB value
    ++** <tr><td><b>sqlite3_value_double</b><td>&rarr;<td>REAL value
    ++** <tr><td><b>sqlite3_value_int</b><td>&rarr;<td>32-bit INTEGER value
    ++** <tr><td><b>sqlite3_value_int64</b><td>&rarr;<td>64-bit INTEGER value
    ++** <tr><td><b>sqlite3_value_pointer</b><td>&rarr;<td>Pointer value
    ++** <tr><td><b>sqlite3_value_text</b><td>&rarr;<td>UTF-8 TEXT value
    ++** <tr><td><b>sqlite3_value_text16</b><td>&rarr;<td>UTF-16 TEXT value in
    ++** the native byteorder
    ++** <tr><td><b>sqlite3_value_text16be</b><td>&rarr;<td>UTF-16be TEXT value
    ++** <tr><td><b>sqlite3_value_text16le</b><td>&rarr;<td>UTF-16le TEXT value
    ++** <tr><td>&nbsp;<td>&nbsp;<td>&nbsp;
    ++** <tr><td><b>sqlite3_value_bytes</b><td>&rarr;<td>Size of a BLOB
    ++** or a UTF-8 TEXT in bytes
    ++** <tr><td><b>sqlite3_value_bytes16&nbsp;&nbsp;</b>
    ++** <td>&rarr;&nbsp;&nbsp;<td>Size of UTF-16
    ++** TEXT in bytes
    ++** <tr><td><b>sqlite3_value_type</b><td>&rarr;<td>Default
    ++** datatype of the value
    ++** <tr><td><b>sqlite3_value_numeric_type&nbsp;&nbsp;</b>
    ++** <td>&rarr;&nbsp;&nbsp;<td>Best numeric datatype of the value
    ++** <tr><td><b>sqlite3_value_nochange&nbsp;&nbsp;</b>
    ++** <td>&rarr;&nbsp;&nbsp;<td>True if the column is unchanged in an UPDATE
    ++** against a virtual table.
    ++** </table></blockquote>
    ++**
    ++** <b>Details:</b>
    ++**
    ++** These routines extract type, size, and content information from
    ++** [protected sqlite3_value] objects.  Protected sqlite3_value objects
    ++** are used to pass parameter information into implementation of
    ++** [application-defined SQL functions] and [virtual tables].
    + **
    + ** These routines work only with [protected sqlite3_value] objects.
    + ** Any attempt to use these routines on an [unprotected sqlite3_value]
    +-** object results in undefined behavior.
    ++** is not threadsafe.
    + **
    + ** ^These routines work just like the corresponding [column access functions]
    + ** except that these routines take a single [protected sqlite3_value] object
    +@@ -4329,6 +4823,24 @@ SQLITE_API SQLITE_DEPRECATED int SQLITE_STDCALL sqlite3_memory_alarm(void(*)(voi
    + ** sqlite3_value_text16be() and sqlite3_value_text16le() interfaces
    + ** extract UTF-16 strings as big-endian and little-endian respectively.
    + **
    ++** ^If [sqlite3_value] object V was initialized 
    ++** using [sqlite3_bind_pointer(S,I,P,X,D)] or [sqlite3_result_pointer(C,P,X,D)]
    ++** and if X and Y are strings that compare equal according to strcmp(X,Y),
    ++** then sqlite3_value_pointer(V,Y) will return the pointer P.  ^Otherwise,
    ++** sqlite3_value_pointer(V,Y) returns a NULL. The sqlite3_bind_pointer() 
    ++** routine is part of the [pointer passing interface] added for SQLite 3.20.0.
    ++**
    ++** ^(The sqlite3_value_type(V) interface returns the
    ++** [SQLITE_INTEGER | datatype code] for the initial datatype of the
    ++** [sqlite3_value] object V. The returned value is one of [SQLITE_INTEGER],
    ++** [SQLITE_FLOAT], [SQLITE_TEXT], [SQLITE_BLOB], or [SQLITE_NULL].)^
    ++** Other interfaces might change the datatype for an sqlite3_value object.
    ++** For example, if the datatype is initially SQLITE_INTEGER and
    ++** sqlite3_value_text(V) is called to extract a text value for that
    ++** integer, then subsequent calls to sqlite3_value_type(V) might return
    ++** SQLITE_TEXT.  Whether or not a persistent internal datatype conversion
    ++** occurs is undefined and may change from one release of SQLite to the next.
    ++**
    + ** ^(The sqlite3_value_numeric_type() interface attempts to apply
    + ** numeric affinity to the value.  This means that an attempt is
    + ** made to convert the value to an integer or floating point.  If
    +@@ -4337,6 +4849,19 @@ SQLITE_API SQLITE_DEPRECATED int SQLITE_STDCALL sqlite3_memory_alarm(void(*)(voi
    + ** then the conversion is performed.  Otherwise no conversion occurs.
    + ** The [SQLITE_INTEGER | datatype] after conversion is returned.)^
    + **
    ++** ^Within the [xUpdate] method of a [virtual table], the
    ++** sqlite3_value_nochange(X) interface returns true if and only if
    ++** the column corresponding to X is unchanged by the UPDATE operation
    ++** that the xUpdate method call was invoked to implement and if
    ++** and the prior [xColumn] method call that was invoked to extracted
    ++** the value for that column returned without setting a result (probably
    ++** because it queried [sqlite3_vtab_nochange()] and found that the column
    ++** was unchanging).  ^Within an [xUpdate] method, any value for which
    ++** sqlite3_value_nochange(X) is true will in all other respects appear
    ++** to be a NULL value.  If sqlite3_value_nochange(X) is invoked anywhere other
    ++** than within an [xUpdate] method call for an UPDATE statement, then
    ++** the return value is arbitrary and meaningless.
    ++**
    + ** Please pay particular attention to the fact that the pointer returned
    + ** from [sqlite3_value_blob()], [sqlite3_value_text()], or
    + ** [sqlite3_value_text16()] can be invalidated by a subsequent call to
    +@@ -4346,18 +4871,20 @@ SQLITE_API SQLITE_DEPRECATED int SQLITE_STDCALL sqlite3_memory_alarm(void(*)(voi
    + ** These routines must be called from the same thread as
    + ** the SQL function that supplied the [sqlite3_value*] parameters.
    + */
    +-SQLITE_API const void *SQLITE_STDCALL sqlite3_value_blob(sqlite3_value*);
    +-SQLITE_API int SQLITE_STDCALL sqlite3_value_bytes(sqlite3_value*);
    +-SQLITE_API int SQLITE_STDCALL sqlite3_value_bytes16(sqlite3_value*);
    +-SQLITE_API double SQLITE_STDCALL sqlite3_value_double(sqlite3_value*);
    +-SQLITE_API int SQLITE_STDCALL sqlite3_value_int(sqlite3_value*);
    +-SQLITE_API sqlite3_int64 SQLITE_STDCALL sqlite3_value_int64(sqlite3_value*);
    +-SQLITE_API const unsigned char *SQLITE_STDCALL sqlite3_value_text(sqlite3_value*);
    +-SQLITE_API const void *SQLITE_STDCALL sqlite3_value_text16(sqlite3_value*);
    +-SQLITE_API const void *SQLITE_STDCALL sqlite3_value_text16le(sqlite3_value*);
    +-SQLITE_API const void *SQLITE_STDCALL sqlite3_value_text16be(sqlite3_value*);
    +-SQLITE_API int SQLITE_STDCALL sqlite3_value_type(sqlite3_value*);
    +-SQLITE_API int SQLITE_STDCALL sqlite3_value_numeric_type(sqlite3_value*);
    ++SQLITE_API const void *sqlite3_value_blob(sqlite3_value*);
    ++SQLITE_API double sqlite3_value_double(sqlite3_value*);
    ++SQLITE_API int sqlite3_value_int(sqlite3_value*);
    ++SQLITE_API sqlite3_int64 sqlite3_value_int64(sqlite3_value*);
    ++SQLITE_API void *sqlite3_value_pointer(sqlite3_value*, const char*);
    ++SQLITE_API const unsigned char *sqlite3_value_text(sqlite3_value*);
    ++SQLITE_API const void *sqlite3_value_text16(sqlite3_value*);
    ++SQLITE_API const void *sqlite3_value_text16le(sqlite3_value*);
    ++SQLITE_API const void *sqlite3_value_text16be(sqlite3_value*);
    ++SQLITE_API int sqlite3_value_bytes(sqlite3_value*);
    ++SQLITE_API int sqlite3_value_bytes16(sqlite3_value*);
    ++SQLITE_API int sqlite3_value_type(sqlite3_value*);
    ++SQLITE_API int sqlite3_value_numeric_type(sqlite3_value*);
    ++SQLITE_API int sqlite3_value_nochange(sqlite3_value*);
    + 
    + /*
    + ** CAPI3REF: Finding The Subtype Of SQL Values
    +@@ -4368,12 +4895,8 @@ SQLITE_API int SQLITE_STDCALL sqlite3_value_numeric_type(sqlite3_value*);
    + ** information can be used to pass a limited amount of context from
    + ** one SQL function to another.  Use the [sqlite3_result_subtype()]
    + ** routine to set the subtype for the return value of an SQL function.
    +-**
    +-** SQLite makes no use of subtype itself.  It merely passes the subtype
    +-** from the result of one [application-defined SQL function] into the
    +-** input of another.
    + */
    +-SQLITE_API unsigned int SQLITE_STDCALL sqlite3_value_subtype(sqlite3_value*);
    ++SQLITE_API unsigned int sqlite3_value_subtype(sqlite3_value*);
    + 
    + /*
    + ** CAPI3REF: Copy And Free SQL Values
    +@@ -4389,8 +4912,8 @@ SQLITE_API unsigned int SQLITE_STDCALL sqlite3_value_subtype(sqlite3_value*);
    + ** previously obtained from [sqlite3_value_dup()].  ^If V is a NULL pointer
    + ** then sqlite3_value_free(V) is a harmless no-op.
    + */
    +-SQLITE_API SQLITE_EXPERIMENTAL sqlite3_value *SQLITE_STDCALL sqlite3_value_dup(const sqlite3_value*);
    +-SQLITE_API SQLITE_EXPERIMENTAL void SQLITE_STDCALL sqlite3_value_free(sqlite3_value*);
    ++SQLITE_API sqlite3_value *sqlite3_value_dup(const sqlite3_value*);
    ++SQLITE_API void sqlite3_value_free(sqlite3_value*);
    + 
    + /*
    + ** CAPI3REF: Obtain Aggregate Function Context
    +@@ -4435,7 +4958,7 @@ SQLITE_API SQLITE_EXPERIMENTAL void SQLITE_STDCALL sqlite3_value_free(sqlite3_va
    + ** This routine must be called from the same thread in which
    + ** the aggregate SQL function is running.
    + */
    +-SQLITE_API void *SQLITE_STDCALL sqlite3_aggregate_context(sqlite3_context*, int nBytes);
    ++SQLITE_API void *sqlite3_aggregate_context(sqlite3_context*, int nBytes);
    + 
    + /*
    + ** CAPI3REF: User Data For Functions
    +@@ -4450,7 +4973,7 @@ SQLITE_API void *SQLITE_STDCALL sqlite3_aggregate_context(sqlite3_context*, int
    + ** This routine must be called from the same thread in which
    + ** the application-defined function is running.
    + */
    +-SQLITE_API void *SQLITE_STDCALL sqlite3_user_data(sqlite3_context*);
    ++SQLITE_API void *sqlite3_user_data(sqlite3_context*);
    + 
    + /*
    + ** CAPI3REF: Database Connection For Functions
    +@@ -4462,7 +4985,7 @@ SQLITE_API void *SQLITE_STDCALL sqlite3_user_data(sqlite3_context*);
    + ** and [sqlite3_create_function16()] routines that originally
    + ** registered the application defined function.
    + */
    +-SQLITE_API sqlite3 *SQLITE_STDCALL sqlite3_context_db_handle(sqlite3_context*);
    ++SQLITE_API sqlite3 *sqlite3_context_db_handle(sqlite3_context*);
    + 
    + /*
    + ** CAPI3REF: Function Auxiliary Data
    +@@ -4479,10 +5002,11 @@ SQLITE_API sqlite3 *SQLITE_STDCALL sqlite3_context_db_handle(sqlite3_context*);
    + ** the compiled regular expression can be reused on multiple
    + ** invocations of the same function.
    + **
    +-** ^The sqlite3_get_auxdata() interface returns a pointer to the metadata
    +-** associated by the sqlite3_set_auxdata() function with the Nth argument
    +-** value to the application-defined function. ^If there is no metadata
    +-** associated with the function argument, this sqlite3_get_auxdata() interface
    ++** ^The sqlite3_get_auxdata(C,N) interface returns a pointer to the metadata
    ++** associated by the sqlite3_set_auxdata(C,N,P,X) function with the Nth argument
    ++** value to the application-defined function.  ^N is zero for the left-most
    ++** function argument.  ^If there is no metadata
    ++** associated with the function argument, the sqlite3_get_auxdata(C,N) interface
    + ** returns a NULL pointer.
    + **
    + ** ^The sqlite3_set_auxdata(C,N,P,X) interface saves P as metadata for the N-th
    +@@ -4494,12 +5018,13 @@ SQLITE_API sqlite3 *SQLITE_STDCALL sqlite3_context_db_handle(sqlite3_context*);
    + ** SQLite will invoke the destructor function X with parameter P exactly
    + ** once, when the metadata is discarded.
    + ** SQLite is free to discard the metadata at any time, including: <ul>
    +-** <li> when the corresponding function parameter changes, or
    +-** <li> when [sqlite3_reset()] or [sqlite3_finalize()] is called for the
    +-**      SQL statement, or
    +-** <li> when sqlite3_set_auxdata() is invoked again on the same parameter, or
    +-** <li> during the original sqlite3_set_auxdata() call when a memory 
    +-**      allocation error occurs. </ul>)^
    ++** <li> ^(when the corresponding function parameter changes)^, or
    ++** <li> ^(when [sqlite3_reset()] or [sqlite3_finalize()] is called for the
    ++**      SQL statement)^, or
    ++** <li> ^(when sqlite3_set_auxdata() is invoked again on the same
    ++**       parameter)^, or
    ++** <li> ^(during the original sqlite3_set_auxdata() call when a memory 
    ++**      allocation error occurs.)^ </ul>
    + **
    + ** Note the last bullet in particular.  The destructor X in 
    + ** sqlite3_set_auxdata(C,N,P,X) might be called immediately, before the
    +@@ -4512,11 +5037,15 @@ SQLITE_API sqlite3 *SQLITE_STDCALL sqlite3_context_db_handle(sqlite3_context*);
    + ** function parameters that are compile-time constants, including literal
    + ** values and [parameters] and expressions composed from the same.)^
    + **
    ++** The value of the N parameter to these interfaces should be non-negative.
    ++** Future enhancements may make use of negative N values to define new
    ++** kinds of function caching behavior.
    ++**
    + ** These routines must be called from the same thread in which
    + ** the SQL function is running.
    + */
    +-SQLITE_API void *SQLITE_STDCALL sqlite3_get_auxdata(sqlite3_context*, int N);
    +-SQLITE_API void SQLITE_STDCALL sqlite3_set_auxdata(sqlite3_context*, int N, void*, void (*)(void*));
    ++SQLITE_API void *sqlite3_get_auxdata(sqlite3_context*, int N);
    ++SQLITE_API void sqlite3_set_auxdata(sqlite3_context*, int N, void*, void (*)(void*));
    + 
    + 
    + /*
    +@@ -4635,7 +5164,7 @@ typedef void (*sqlite3_destructor_type)(void*);
    + ** when it has finished using that result.
    + ** ^If the 4th parameter to the sqlite3_result_text* interfaces
    + ** or sqlite3_result_blob is the special constant SQLITE_TRANSIENT
    +-** then SQLite makes a copy of the result into space obtained from
    ++** then SQLite makes a copy of the result into space obtained
    + ** from [sqlite3_malloc()] before it returns.
    + **
    + ** ^The sqlite3_result_value() interface sets the result of
    +@@ -4648,31 +5177,43 @@ typedef void (*sqlite3_destructor_type)(void*);
    + ** [unprotected sqlite3_value] object is required, so either
    + ** kind of [sqlite3_value] object can be used with this interface.
    + **
    ++** ^The sqlite3_result_pointer(C,P,T,D) interface sets the result to an
    ++** SQL NULL value, just like [sqlite3_result_null(C)], except that it
    ++** also associates the host-language pointer P or type T with that 
    ++** NULL value such that the pointer can be retrieved within an
    ++** [application-defined SQL function] using [sqlite3_value_pointer()].
    ++** ^If the D parameter is not NULL, then it is a pointer to a destructor
    ++** for the P parameter.  ^SQLite invokes D with P as its only argument
    ++** when SQLite is finished with P.  The T parameter should be a static
    ++** string and preferably a string literal. The sqlite3_result_pointer()
    ++** routine is part of the [pointer passing interface] added for SQLite 3.20.0.
    ++**
    + ** If these routines are called from within the different thread
    + ** than the one containing the application-defined function that received
    + ** the [sqlite3_context] pointer, the results are undefined.
    + */
    +-SQLITE_API void SQLITE_STDCALL sqlite3_result_blob(sqlite3_context*, const void*, int, void(*)(void*));
    +-SQLITE_API void SQLITE_STDCALL sqlite3_result_blob64(sqlite3_context*,const void*,
    ++SQLITE_API void sqlite3_result_blob(sqlite3_context*, const void*, int, void(*)(void*));
    ++SQLITE_API void sqlite3_result_blob64(sqlite3_context*,const void*,
    +                            sqlite3_uint64,void(*)(void*));
    +-SQLITE_API void SQLITE_STDCALL sqlite3_result_double(sqlite3_context*, double);
    +-SQLITE_API void SQLITE_STDCALL sqlite3_result_error(sqlite3_context*, const char*, int);
    +-SQLITE_API void SQLITE_STDCALL sqlite3_result_error16(sqlite3_context*, const void*, int);
    +-SQLITE_API void SQLITE_STDCALL sqlite3_result_error_toobig(sqlite3_context*);
    +-SQLITE_API void SQLITE_STDCALL sqlite3_result_error_nomem(sqlite3_context*);
    +-SQLITE_API void SQLITE_STDCALL sqlite3_result_error_code(sqlite3_context*, int);
    +-SQLITE_API void SQLITE_STDCALL sqlite3_result_int(sqlite3_context*, int);
    +-SQLITE_API void SQLITE_STDCALL sqlite3_result_int64(sqlite3_context*, sqlite3_int64);
    +-SQLITE_API void SQLITE_STDCALL sqlite3_result_null(sqlite3_context*);
    +-SQLITE_API void SQLITE_STDCALL sqlite3_result_text(sqlite3_context*, const char*, int, void(*)(void*));
    +-SQLITE_API void SQLITE_STDCALL sqlite3_result_text64(sqlite3_context*, const char*,sqlite3_uint64,
    ++SQLITE_API void sqlite3_result_double(sqlite3_context*, double);
    ++SQLITE_API void sqlite3_result_error(sqlite3_context*, const char*, int);
    ++SQLITE_API void sqlite3_result_error16(sqlite3_context*, const void*, int);
    ++SQLITE_API void sqlite3_result_error_toobig(sqlite3_context*);
    ++SQLITE_API void sqlite3_result_error_nomem(sqlite3_context*);
    ++SQLITE_API void sqlite3_result_error_code(sqlite3_context*, int);
    ++SQLITE_API void sqlite3_result_int(sqlite3_context*, int);
    ++SQLITE_API void sqlite3_result_int64(sqlite3_context*, sqlite3_int64);
    ++SQLITE_API void sqlite3_result_null(sqlite3_context*);
    ++SQLITE_API void sqlite3_result_text(sqlite3_context*, const char*, int, void(*)(void*));
    ++SQLITE_API void sqlite3_result_text64(sqlite3_context*, const char*,sqlite3_uint64,
    +                            void(*)(void*), unsigned char encoding);
    +-SQLITE_API void SQLITE_STDCALL sqlite3_result_text16(sqlite3_context*, const void*, int, void(*)(void*));
    +-SQLITE_API void SQLITE_STDCALL sqlite3_result_text16le(sqlite3_context*, const void*, int,void(*)(void*));
    +-SQLITE_API void SQLITE_STDCALL sqlite3_result_text16be(sqlite3_context*, const void*, int,void(*)(void*));
    +-SQLITE_API void SQLITE_STDCALL sqlite3_result_value(sqlite3_context*, sqlite3_value*);
    +-SQLITE_API void SQLITE_STDCALL sqlite3_result_zeroblob(sqlite3_context*, int n);
    +-SQLITE_API int SQLITE_STDCALL sqlite3_result_zeroblob64(sqlite3_context*, sqlite3_uint64 n);
    ++SQLITE_API void sqlite3_result_text16(sqlite3_context*, const void*, int, void(*)(void*));
    ++SQLITE_API void sqlite3_result_text16le(sqlite3_context*, const void*, int,void(*)(void*));
    ++SQLITE_API void sqlite3_result_text16be(sqlite3_context*, const void*, int,void(*)(void*));
    ++SQLITE_API void sqlite3_result_value(sqlite3_context*, sqlite3_value*);
    ++SQLITE_API void sqlite3_result_pointer(sqlite3_context*, void*,const char*,void(*)(void*));
    ++SQLITE_API void sqlite3_result_zeroblob(sqlite3_context*, int n);
    ++SQLITE_API int sqlite3_result_zeroblob64(sqlite3_context*, sqlite3_uint64 n);
    + 
    + 
    + /*
    +@@ -4687,7 +5228,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_result_zeroblob64(sqlite3_context*, sqlite
    + ** The number of subtype bytes preserved by SQLite might increase
    + ** in future releases of SQLite.
    + */
    +-SQLITE_API void SQLITE_STDCALL sqlite3_result_subtype(sqlite3_context*,unsigned int);
    ++SQLITE_API void sqlite3_result_subtype(sqlite3_context*,unsigned int);
    + 
    + /*
    + ** CAPI3REF: Define New Collating Sequences
    +@@ -4769,14 +5310,14 @@ SQLITE_API void SQLITE_STDCALL sqlite3_result_subtype(sqlite3_context*,unsigned
    + **
    + ** See also:  [sqlite3_collation_needed()] and [sqlite3_collation_needed16()].
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_create_collation(
    ++SQLITE_API int sqlite3_create_collation(
    +   sqlite3*, 
    +   const char *zName, 
    +   int eTextRep, 
    +   void *pArg,
    +   int(*xCompare)(void*,int,const void*,int,const void*)
    + );
    +-SQLITE_API int SQLITE_STDCALL sqlite3_create_collation_v2(
    ++SQLITE_API int sqlite3_create_collation_v2(
    +   sqlite3*, 
    +   const char *zName, 
    +   int eTextRep, 
    +@@ -4784,7 +5325,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_create_collation_v2(
    +   int(*xCompare)(void*,int,const void*,int,const void*),
    +   void(*xDestroy)(void*)
    + );
    +-SQLITE_API int SQLITE_STDCALL sqlite3_create_collation16(
    ++SQLITE_API int sqlite3_create_collation16(
    +   sqlite3*, 
    +   const void *zName,
    +   int eTextRep, 
    +@@ -4819,12 +5360,12 @@ SQLITE_API int SQLITE_STDCALL sqlite3_create_collation16(
    + ** [sqlite3_create_collation()], [sqlite3_create_collation16()], or
    + ** [sqlite3_create_collation_v2()].
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_collation_needed(
    ++SQLITE_API int sqlite3_collation_needed(
    +   sqlite3*, 
    +   void*, 
    +   void(*)(void*,sqlite3*,int eTextRep,const char*)
    + );
    +-SQLITE_API int SQLITE_STDCALL sqlite3_collation_needed16(
    ++SQLITE_API int sqlite3_collation_needed16(
    +   sqlite3*, 
    +   void*,
    +   void(*)(void*,sqlite3*,int eTextRep,const void*)
    +@@ -4838,11 +5379,11 @@ SQLITE_API int SQLITE_STDCALL sqlite3_collation_needed16(
    + ** The code to implement this API is not available in the public release
    + ** of SQLite.
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_key(
    ++SQLITE_API int sqlite3_key(
    +   sqlite3 *db,                   /* Database to be rekeyed */
    +   const void *pKey, int nKey     /* The key */
    + );
    +-SQLITE_API int SQLITE_STDCALL sqlite3_key_v2(
    ++SQLITE_API int sqlite3_key_v2(
    +   sqlite3 *db,                   /* Database to be rekeyed */
    +   const char *zDbName,           /* Name of the database */
    +   const void *pKey, int nKey     /* The key */
    +@@ -4856,11 +5397,11 @@ SQLITE_API int SQLITE_STDCALL sqlite3_key_v2(
    + ** The code to implement this API is not available in the public release
    + ** of SQLite.
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_rekey(
    ++SQLITE_API int sqlite3_rekey(
    +   sqlite3 *db,                   /* Database to be rekeyed */
    +   const void *pKey, int nKey     /* The new key */
    + );
    +-SQLITE_API int SQLITE_STDCALL sqlite3_rekey_v2(
    ++SQLITE_API int sqlite3_rekey_v2(
    +   sqlite3 *db,                   /* Database to be rekeyed */
    +   const char *zDbName,           /* Name of the database */
    +   const void *pKey, int nKey     /* The new key */
    +@@ -4870,7 +5411,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_rekey_v2(
    + ** Specify the activation key for a SEE database.  Unless 
    + ** activated, none of the SEE routines will work.
    + */
    +-SQLITE_API void SQLITE_STDCALL sqlite3_activate_see(
    ++SQLITE_API void sqlite3_activate_see(
    +   const char *zPassPhrase        /* Activation phrase */
    + );
    + #endif
    +@@ -4880,7 +5421,7 @@ SQLITE_API void SQLITE_STDCALL sqlite3_activate_see(
    + ** Specify the activation key for a CEROD database.  Unless 
    + ** activated, none of the CEROD routines will work.
    + */
    +-SQLITE_API void SQLITE_STDCALL sqlite3_activate_cerod(
    ++SQLITE_API void sqlite3_activate_cerod(
    +   const char *zPassPhrase        /* Activation phrase */
    + );
    + #endif
    +@@ -4902,7 +5443,7 @@ SQLITE_API void SQLITE_STDCALL sqlite3_activate_cerod(
    + ** all, then the behavior of sqlite3_sleep() may deviate from the description
    + ** in the previous paragraphs.
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_sleep(int);
    ++SQLITE_API int sqlite3_sleep(int);
    + 
    + /*
    + ** CAPI3REF: Name Of The Folder Holding Temporary Files
    +@@ -5021,7 +5562,7 @@ SQLITE_API SQLITE_EXTERN char *sqlite3_data_directory;
    + ** connection while this routine is running, then the return value
    + ** is undefined.
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_get_autocommit(sqlite3*);
    ++SQLITE_API int sqlite3_get_autocommit(sqlite3*);
    + 
    + /*
    + ** CAPI3REF: Find The Database Handle Of A Prepared Statement
    +@@ -5034,7 +5575,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_get_autocommit(sqlite3*);
    + ** to the [sqlite3_prepare_v2()] call (or its variants) that was used to
    + ** create the statement in the first place.
    + */
    +-SQLITE_API sqlite3 *SQLITE_STDCALL sqlite3_db_handle(sqlite3_stmt*);
    ++SQLITE_API sqlite3 *sqlite3_db_handle(sqlite3_stmt*);
    + 
    + /*
    + ** CAPI3REF: Return The Filename For A Database Connection
    +@@ -5051,7 +5592,7 @@ SQLITE_API sqlite3 *SQLITE_STDCALL sqlite3_db_handle(sqlite3_stmt*);
    + ** will be an absolute pathname, even if the filename used
    + ** to open the database originally was a URI or relative pathname.
    + */
    +-SQLITE_API const char *SQLITE_STDCALL sqlite3_db_filename(sqlite3 *db, const char *zDbName);
    ++SQLITE_API const char *sqlite3_db_filename(sqlite3 *db, const char *zDbName);
    + 
    + /*
    + ** CAPI3REF: Determine if a database is read-only
    +@@ -5061,7 +5602,7 @@ SQLITE_API const char *SQLITE_STDCALL sqlite3_db_filename(sqlite3 *db, const cha
    + ** of connection D is read-only, 0 if it is read/write, or -1 if N is not
    + ** the name of a database on connection D.
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_db_readonly(sqlite3 *db, const char *zDbName);
    ++SQLITE_API int sqlite3_db_readonly(sqlite3 *db, const char *zDbName);
    + 
    + /*
    + ** CAPI3REF: Find the next prepared statement
    +@@ -5077,7 +5618,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_db_readonly(sqlite3 *db, const char *zDbNa
    + ** [sqlite3_next_stmt(D,S)] must refer to an open database
    + ** connection and in particular must not be a NULL pointer.
    + */
    +-SQLITE_API sqlite3_stmt *SQLITE_STDCALL sqlite3_next_stmt(sqlite3 *pDb, sqlite3_stmt *pStmt);
    ++SQLITE_API sqlite3_stmt *sqlite3_next_stmt(sqlite3 *pDb, sqlite3_stmt *pStmt);
    + 
    + /*
    + ** CAPI3REF: Commit And Rollback Notification Callbacks
    +@@ -5126,8 +5667,8 @@ SQLITE_API sqlite3_stmt *SQLITE_STDCALL sqlite3_next_stmt(sqlite3 *pDb, sqlite3_
    + **
    + ** See also the [sqlite3_update_hook()] interface.
    + */
    +-SQLITE_API void *SQLITE_STDCALL sqlite3_commit_hook(sqlite3*, int(*)(void*), void*);
    +-SQLITE_API void *SQLITE_STDCALL sqlite3_rollback_hook(sqlite3*, void(*)(void *), void*);
    ++SQLITE_API void *sqlite3_commit_hook(sqlite3*, int(*)(void*), void*);
    ++SQLITE_API void *sqlite3_rollback_hook(sqlite3*, void(*)(void *), void*);
    + 
    + /*
    + ** CAPI3REF: Data Change Notification Callbacks
    +@@ -5136,7 +5677,7 @@ SQLITE_API void *SQLITE_STDCALL sqlite3_rollback_hook(sqlite3*, void(*)(void *),
    + ** ^The sqlite3_update_hook() interface registers a callback function
    + ** with the [database connection] identified by the first argument
    + ** to be invoked whenever a row is updated, inserted or deleted in
    +-** a rowid table.
    ++** a [rowid table].
    + ** ^Any callback set by a previous call to this function
    + ** for the same database connection is overridden.
    + **
    +@@ -5157,7 +5698,7 @@ SQLITE_API void *SQLITE_STDCALL sqlite3_rollback_hook(sqlite3*, void(*)(void *),
    + ** ^The update hook is not invoked when [WITHOUT ROWID] tables are modified.
    + **
    + ** ^In the current implementation, the update hook
    +-** is not invoked when duplication rows are deleted because of an
    ++** is not invoked when conflicting rows are deleted because of an
    + ** [ON CONFLICT | ON CONFLICT REPLACE] clause.  ^Nor is the update hook
    + ** invoked when rows are deleted using the [truncate optimization].
    + ** The exceptions defined in this paragraph might change in a future
    +@@ -5175,10 +5716,10 @@ SQLITE_API void *SQLITE_STDCALL sqlite3_rollback_hook(sqlite3*, void(*)(void *),
    + ** on the same [database connection] D, or NULL for
    + ** the first call on D.
    + **
    +-** See also the [sqlite3_commit_hook()] and [sqlite3_rollback_hook()]
    +-** interfaces.
    ++** See also the [sqlite3_commit_hook()], [sqlite3_rollback_hook()],
    ++** and [sqlite3_preupdate_hook()] interfaces.
    + */
    +-SQLITE_API void *SQLITE_STDCALL sqlite3_update_hook(
    ++SQLITE_API void *sqlite3_update_hook(
    +   sqlite3*, 
    +   void(*)(void *,int ,char const *,char const *,sqlite3_int64),
    +   void*
    +@@ -5193,7 +5734,8 @@ SQLITE_API void *SQLITE_STDCALL sqlite3_update_hook(
    + ** and disabled if the argument is false.)^
    + **
    + ** ^Cache sharing is enabled and disabled for an entire process.
    +-** This is a change as of SQLite version 3.5.0. In prior versions of SQLite,
    ++** This is a change as of SQLite [version 3.5.0] ([dateof:3.5.0]). 
    ++** In prior versions of SQLite,
    + ** sharing was enabled or disabled for each thread separately.
    + **
    + ** ^(The cache sharing mode set by this interface effects all subsequent
    +@@ -5218,7 +5760,7 @@ SQLITE_API void *SQLITE_STDCALL sqlite3_update_hook(
    + **
    + ** See Also:  [SQLite Shared-Cache Mode]
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_enable_shared_cache(int);
    ++SQLITE_API int sqlite3_enable_shared_cache(int);
    + 
    + /*
    + ** CAPI3REF: Attempt To Free Heap Memory
    +@@ -5234,7 +5776,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_enable_shared_cache(int);
    + **
    + ** See also: [sqlite3_db_release_memory()]
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_release_memory(int);
    ++SQLITE_API int sqlite3_release_memory(int);
    + 
    + /*
    + ** CAPI3REF: Free Memory Used By A Database Connection
    +@@ -5248,7 +5790,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_release_memory(int);
    + **
    + ** See also: [sqlite3_release_memory()]
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_db_release_memory(sqlite3*);
    ++SQLITE_API int sqlite3_db_release_memory(sqlite3*);
    + 
    + /*
    + ** CAPI3REF: Impose A Limit On Heap Size
    +@@ -5287,7 +5829,8 @@ SQLITE_API int SQLITE_STDCALL sqlite3_db_release_memory(sqlite3*);
    + **      from the heap.
    + ** </ul>)^
    + **
    +-** Beginning with SQLite version 3.7.3, the soft heap limit is enforced
    ++** Beginning with SQLite [version 3.7.3] ([dateof:3.7.3]), 
    ++** the soft heap limit is enforced
    + ** regardless of whether or not the [SQLITE_ENABLE_MEMORY_MANAGEMENT]
    + ** compile-time option is invoked.  With [SQLITE_ENABLE_MEMORY_MANAGEMENT],
    + ** the soft heap limit is enforced on every memory allocation.  Without
    +@@ -5300,7 +5843,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_db_release_memory(sqlite3*);
    + ** The circumstances under which SQLite will enforce the soft heap limit may
    + ** changes in future releases of SQLite.
    + */
    +-SQLITE_API sqlite3_int64 SQLITE_STDCALL sqlite3_soft_heap_limit64(sqlite3_int64 N);
    ++SQLITE_API sqlite3_int64 sqlite3_soft_heap_limit64(sqlite3_int64 N);
    + 
    + /*
    + ** CAPI3REF: Deprecated Soft Heap Limit Interface
    +@@ -5311,7 +5854,7 @@ SQLITE_API sqlite3_int64 SQLITE_STDCALL sqlite3_soft_heap_limit64(sqlite3_int64
    + ** only.  All new applications should use the
    + ** [sqlite3_soft_heap_limit64()] interface rather than this one.
    + */
    +-SQLITE_API SQLITE_DEPRECATED void SQLITE_STDCALL sqlite3_soft_heap_limit(int N);
    ++SQLITE_API SQLITE_DEPRECATED void sqlite3_soft_heap_limit(int N);
    + 
    + 
    + /*
    +@@ -5326,9 +5869,11 @@ SQLITE_API SQLITE_DEPRECATED void SQLITE_STDCALL sqlite3_soft_heap_limit(int N);
    + ** column exists.  ^The sqlite3_table_column_metadata() interface returns
    + ** SQLITE_ERROR and if the specified column does not exist.
    + ** ^If the column-name parameter to sqlite3_table_column_metadata() is a
    +-** NULL pointer, then this routine simply checks for the existance of the
    ++** NULL pointer, then this routine simply checks for the existence of the
    + ** table and returns SQLITE_OK if the table exists and SQLITE_ERROR if it
    +-** does not.
    ++** does not.  If the table name parameter T in a call to
    ++** sqlite3_table_column_metadata(X,D,T,C,...) is NULL then the result is
    ++** undefined behavior.
    + **
    + ** ^The column is identified by the second, third and fourth parameters to
    + ** this function. ^(The second parameter is either the name of the database
    +@@ -5381,7 +5926,7 @@ SQLITE_API SQLITE_DEPRECATED void SQLITE_STDCALL sqlite3_soft_heap_limit(int N);
    + ** parsed, if that has not already been done, and returns an error if
    + ** any errors are encountered while loading the schema.
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_table_column_metadata(
    ++SQLITE_API int sqlite3_table_column_metadata(
    +   sqlite3 *db,                /* Connection handle */
    +   const char *zDbName,        /* Database name or NULL */
    +   const char *zTableName,     /* Table name */
    +@@ -5423,12 +5968,21 @@ SQLITE_API int SQLITE_STDCALL sqlite3_table_column_metadata(
    + ** should free this memory by calling [sqlite3_free()].
    + **
    + ** ^Extension loading must be enabled using
    +-** [sqlite3_enable_load_extension()] prior to calling this API,
    ++** [sqlite3_enable_load_extension()] or
    ++** [sqlite3_db_config](db,[SQLITE_DBCONFIG_ENABLE_LOAD_EXTENSION],1,NULL)
    ++** prior to calling this API,
    + ** otherwise an error will be returned.
    + **
    ++** <b>Security warning:</b> It is recommended that the 
    ++** [SQLITE_DBCONFIG_ENABLE_LOAD_EXTENSION] method be used to enable only this
    ++** interface.  The use of the [sqlite3_enable_load_extension()] interface
    ++** should be avoided.  This will keep the SQL function [load_extension()]
    ++** disabled and prevent SQL injections from giving attackers
    ++** access to extension loading capabilities.
    ++**
    + ** See also the [load_extension() SQL function].
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_load_extension(
    ++SQLITE_API int sqlite3_load_extension(
    +   sqlite3 *db,          /* Load the extension into this database connection */
    +   const char *zFile,    /* Name of the shared library containing extension */
    +   const char *zProc,    /* Entry point.  Derived from zFile if 0 */
    +@@ -5448,8 +6002,19 @@ SQLITE_API int SQLITE_STDCALL sqlite3_load_extension(
    + ** ^Call the sqlite3_enable_load_extension() routine with onoff==1
    + ** to turn extension loading on and call it with onoff==0 to turn
    + ** it back off again.
    ++**
    ++** ^This interface enables or disables both the C-API
    ++** [sqlite3_load_extension()] and the SQL function [load_extension()].
    ++** ^(Use [sqlite3_db_config](db,[SQLITE_DBCONFIG_ENABLE_LOAD_EXTENSION],..)
    ++** to enable or disable only the C-API.)^
    ++**
    ++** <b>Security warning:</b> It is recommended that extension loading
    ++** be disabled using the [SQLITE_DBCONFIG_ENABLE_LOAD_EXTENSION] method
    ++** rather than this interface, so the [load_extension()] SQL function
    ++** remains disabled. This will prevent SQL injections from giving attackers
    ++** access to extension loading capabilities.
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_enable_load_extension(sqlite3 *db, int onoff);
    ++SQLITE_API int sqlite3_enable_load_extension(sqlite3 *db, int onoff);
    + 
    + /*
    + ** CAPI3REF: Automatically Load Statically Linked Extensions
    +@@ -5461,7 +6026,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_enable_load_extension(sqlite3 *db, int ono
    + **
    + ** ^(Even though the function prototype shows that xEntryPoint() takes
    + ** no arguments and returns void, SQLite invokes xEntryPoint() with three
    +-** arguments and expects and integer result as if the signature of the
    ++** arguments and expects an integer result as if the signature of the
    + ** entry point where as follows:
    + **
    + ** <blockquote><pre>
    +@@ -5487,7 +6052,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_enable_load_extension(sqlite3 *db, int ono
    + ** See also: [sqlite3_reset_auto_extension()]
    + ** and [sqlite3_cancel_auto_extension()]
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_auto_extension(void (*xEntryPoint)(void));
    ++SQLITE_API int sqlite3_auto_extension(void(*xEntryPoint)(void));
    + 
    + /*
    + ** CAPI3REF: Cancel Automatic Extension Loading
    +@@ -5499,7 +6064,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_auto_extension(void (*xEntryPoint)(void));
    + ** unregistered and it returns 0 if X was not on the list of initialization
    + ** routines.
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_cancel_auto_extension(void (*xEntryPoint)(void));
    ++SQLITE_API int sqlite3_cancel_auto_extension(void(*xEntryPoint)(void));
    + 
    + /*
    + ** CAPI3REF: Reset Automatic Extension Loading
    +@@ -5507,7 +6072,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_cancel_auto_extension(void (*xEntryPoint)(
    + ** ^This interface disables all automatic extensions previously
    + ** registered using [sqlite3_auto_extension()].
    + */
    +-SQLITE_API void SQLITE_STDCALL sqlite3_reset_auto_extension(void);
    ++SQLITE_API void sqlite3_reset_auto_extension(void);
    + 
    + /*
    + ** The interface to the virtual-table mechanism is currently considered
    +@@ -5609,6 +6174,17 @@ struct sqlite3_module {
    + ** ^Information about the ORDER BY clause is stored in aOrderBy[].
    + ** ^Each term of aOrderBy records a column of the ORDER BY clause.
    + **
    ++** The colUsed field indicates which columns of the virtual table may be
    ++** required by the current scan. Virtual table columns are numbered from
    ++** zero in the order in which they appear within the CREATE TABLE statement
    ++** passed to sqlite3_declare_vtab(). For the first 63 columns (columns 0-62),
    ++** the corresponding bit is set within the colUsed mask if the column may be
    ++** required by SQLite. If the table has at least 64 columns and any column
    ++** to the right of the first 63 is required, then bit 63 of colUsed is also
    ++** set. In other words, column iCol may be required if the expression
    ++** (colUsed & ((sqlite3_uint64)1 << (iCol>=63 ? 63 : iCol))) evaluates to 
    ++** non-zero.
    ++**
    + ** The [xBestIndex] method must fill aConstraintUsage[] with information
    + ** about what parameters to pass to xFilter.  ^If argvIndex>0 then
    + ** the right-hand side of the corresponding aConstraint[] is evaluated
    +@@ -5650,13 +6226,15 @@ struct sqlite3_module {
    + ** the xUpdate method are automatically rolled back by SQLite.
    + **
    + ** IMPORTANT: The estimatedRows field was added to the sqlite3_index_info
    +-** structure for SQLite version 3.8.2. If a virtual table extension is
    ++** structure for SQLite [version 3.8.2] ([dateof:3.8.2]). 
    ++** If a virtual table extension is
    + ** used with an SQLite version earlier than 3.8.2, the results of attempting 
    + ** to read or write the estimatedRows field are undefined (but are likely 
    + ** to included crashing the application). The estimatedRows field should
    + ** therefore only be used if [sqlite3_libversion_number()] returns a
    + ** value greater than or equal to 3008002. Similarly, the idxFlags field
    +-** was added for version 3.9.0. It may therefore only be used if
    ++** was added for [version 3.9.0] ([dateof:3.9.0]). 
    ++** It may therefore only be used if
    + ** sqlite3_libversion_number() returns a value greater than or equal to
    + ** 3009000.
    + */
    +@@ -5664,7 +6242,7 @@ struct sqlite3_index_info {
    +   /* Inputs */
    +   int nConstraint;           /* Number of entries in aConstraint */
    +   struct sqlite3_index_constraint {
    +-     int iColumn;              /* Column on left-hand side of constraint */
    ++     int iColumn;              /* Column constrained.  -1 for ROWID */
    +      unsigned char op;         /* Constraint operator */
    +      unsigned char usable;     /* True if this constraint is usable */
    +      int iTermOffset;          /* Used internally - xBestIndex should ignore */
    +@@ -5688,6 +6266,8 @@ struct sqlite3_index_info {
    +   sqlite3_int64 estimatedRows;    /* Estimated number of rows returned */
    +   /* Fields below are only available in SQLite 3.9.0 and later */
    +   int idxFlags;              /* Mask of SQLITE_INDEX_SCAN_* flags */
    ++  /* Fields below are only available in SQLite 3.10.0 and later */
    ++  sqlite3_uint64 colUsed;    /* Input: Mask of columns used by statement */
    + };
    + 
    + /*
    +@@ -5703,12 +6283,20 @@ struct sqlite3_index_info {
    + ** an operator that is part of a constraint term in the wHERE clause of
    + ** a query that uses a [virtual table].
    + */
    +-#define SQLITE_INDEX_CONSTRAINT_EQ    2
    +-#define SQLITE_INDEX_CONSTRAINT_GT    4
    +-#define SQLITE_INDEX_CONSTRAINT_LE    8
    +-#define SQLITE_INDEX_CONSTRAINT_LT    16
    +-#define SQLITE_INDEX_CONSTRAINT_GE    32
    +-#define SQLITE_INDEX_CONSTRAINT_MATCH 64
    ++#define SQLITE_INDEX_CONSTRAINT_EQ         2
    ++#define SQLITE_INDEX_CONSTRAINT_GT         4
    ++#define SQLITE_INDEX_CONSTRAINT_LE         8
    ++#define SQLITE_INDEX_CONSTRAINT_LT        16
    ++#define SQLITE_INDEX_CONSTRAINT_GE        32
    ++#define SQLITE_INDEX_CONSTRAINT_MATCH     64
    ++#define SQLITE_INDEX_CONSTRAINT_LIKE      65
    ++#define SQLITE_INDEX_CONSTRAINT_GLOB      66
    ++#define SQLITE_INDEX_CONSTRAINT_REGEXP    67
    ++#define SQLITE_INDEX_CONSTRAINT_NE        68
    ++#define SQLITE_INDEX_CONSTRAINT_ISNOT     69
    ++#define SQLITE_INDEX_CONSTRAINT_ISNOTNULL 70
    ++#define SQLITE_INDEX_CONSTRAINT_ISNULL    71
    ++#define SQLITE_INDEX_CONSTRAINT_IS        72
    + 
    + /*
    + ** CAPI3REF: Register A Virtual Table Implementation
    +@@ -5736,13 +6324,13 @@ struct sqlite3_index_info {
    + ** interface is equivalent to sqlite3_create_module_v2() with a NULL
    + ** destructor.
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_create_module(
    ++SQLITE_API int sqlite3_create_module(
    +   sqlite3 *db,               /* SQLite connection to register module with */
    +   const char *zName,         /* Name of the module */
    +   const sqlite3_module *p,   /* Methods for the module */
    +   void *pClientData          /* Client data for xCreate/xConnect */
    + );
    +-SQLITE_API int SQLITE_STDCALL sqlite3_create_module_v2(
    ++SQLITE_API int sqlite3_create_module_v2(
    +   sqlite3 *db,               /* SQLite connection to register module with */
    +   const char *zName,         /* Name of the module */
    +   const sqlite3_module *p,   /* Methods for the module */
    +@@ -5805,7 +6393,7 @@ struct sqlite3_vtab_cursor {
    + ** to declare the format (the names and datatypes of the columns) of
    + ** the virtual tables they implement.
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_declare_vtab(sqlite3*, const char *zSQL);
    ++SQLITE_API int sqlite3_declare_vtab(sqlite3*, const char *zSQL);
    + 
    + /*
    + ** CAPI3REF: Overload A Function For A Virtual Table
    +@@ -5824,7 +6412,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_declare_vtab(sqlite3*, const char *zSQL);
    + ** purpose is to be a placeholder function that can be overloaded
    + ** by a [virtual table].
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_overload_function(sqlite3*, const char *zFuncName, int nArg);
    ++SQLITE_API int sqlite3_overload_function(sqlite3*, const char *zFuncName, int nArg);
    + 
    + /*
    + ** The interface to the virtual-table mechanism defined above (back up
    +@@ -5899,6 +6487,12 @@ typedef struct sqlite3_blob sqlite3_blob;
    + ** [database connection] error code and message accessible via 
    + ** [sqlite3_errcode()] and [sqlite3_errmsg()] and related functions. 
    + **
    ++** A BLOB referenced by sqlite3_blob_open() may be read using the
    ++** [sqlite3_blob_read()] interface and modified by using
    ++** [sqlite3_blob_write()].  The [BLOB handle] can be moved to a
    ++** different row of the same table using the [sqlite3_blob_reopen()]
    ++** interface.  However, the column, table, or database of a [BLOB handle]
    ++** cannot be changed after the [BLOB handle] is opened.
    + **
    + ** ^(If the row that a BLOB handle points to is modified by an
    + ** [UPDATE], [DELETE], or by [ON CONFLICT] side-effects
    +@@ -5922,8 +6516,12 @@ typedef struct sqlite3_blob sqlite3_blob;
    + **
    + ** To avoid a resource leak, every open [BLOB handle] should eventually
    + ** be released by a call to [sqlite3_blob_close()].
    ++**
    ++** See also: [sqlite3_blob_close()],
    ++** [sqlite3_blob_reopen()], [sqlite3_blob_read()],
    ++** [sqlite3_blob_bytes()], [sqlite3_blob_write()].
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_blob_open(
    ++SQLITE_API int sqlite3_blob_open(
    +   sqlite3*,
    +   const char *zDb,
    +   const char *zTable,
    +@@ -5937,11 +6535,11 @@ SQLITE_API int SQLITE_STDCALL sqlite3_blob_open(
    + ** CAPI3REF: Move a BLOB Handle to a New Row
    + ** METHOD: sqlite3_blob
    + **
    +-** ^This function is used to move an existing blob handle so that it points
    ++** ^This function is used to move an existing [BLOB handle] so that it points
    + ** to a different row of the same database table. ^The new row is identified
    + ** by the rowid value passed as the second argument. Only the row can be
    + ** changed. ^The database, table and column on which the blob handle is open
    +-** remain the same. Moving an existing blob handle to a new row can be
    ++** remain the same. Moving an existing [BLOB handle] to a new row is
    + ** faster than closing the existing handle and opening a new one.
    + **
    + ** ^(The new row must meet the same criteria as for [sqlite3_blob_open()] -
    +@@ -5956,7 +6554,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_blob_open(
    + **
    + ** ^This function sets the database handle error code and message.
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_blob_reopen(sqlite3_blob *, sqlite3_int64);
    ++SQLITE_API int sqlite3_blob_reopen(sqlite3_blob *, sqlite3_int64);
    + 
    + /*
    + ** CAPI3REF: Close A BLOB Handle
    +@@ -5979,7 +6577,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_blob_reopen(sqlite3_blob *, sqlite3_int64)
    + ** is passed a valid open blob handle, the values returned by the 
    + ** sqlite3_errcode() and sqlite3_errmsg() functions are set before returning.
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_blob_close(sqlite3_blob *);
    ++SQLITE_API int sqlite3_blob_close(sqlite3_blob *);
    + 
    + /*
    + ** CAPI3REF: Return The Size Of An Open BLOB
    +@@ -5995,7 +6593,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_blob_close(sqlite3_blob *);
    + ** been closed by [sqlite3_blob_close()].  Passing any other pointer in
    + ** to this routine results in undefined and probably undesirable behavior.
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_blob_bytes(sqlite3_blob *);
    ++SQLITE_API int sqlite3_blob_bytes(sqlite3_blob *);
    + 
    + /*
    + ** CAPI3REF: Read Data From A BLOB Incrementally
    +@@ -6024,7 +6622,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_blob_bytes(sqlite3_blob *);
    + **
    + ** See also: [sqlite3_blob_write()].
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_blob_read(sqlite3_blob *, void *Z, int N, int iOffset);
    ++SQLITE_API int sqlite3_blob_read(sqlite3_blob *, void *Z, int N, int iOffset);
    + 
    + /*
    + ** CAPI3REF: Write Data Into A BLOB Incrementally
    +@@ -6066,7 +6664,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_blob_read(sqlite3_blob *, void *Z, int N,
    + **
    + ** See also: [sqlite3_blob_read()].
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_blob_write(sqlite3_blob *, const void *z, int n, int iOffset);
    ++SQLITE_API int sqlite3_blob_write(sqlite3_blob *, const void *z, int n, int iOffset);
    + 
    + /*
    + ** CAPI3REF: Virtual File System Objects
    +@@ -6097,9 +6695,9 @@ SQLITE_API int SQLITE_STDCALL sqlite3_blob_write(sqlite3_blob *, const void *z,
    + ** ^(If the default VFS is unregistered, another VFS is chosen as
    + ** the default.  The choice for the new VFS is arbitrary.)^
    + */
    +-SQLITE_API sqlite3_vfs *SQLITE_STDCALL sqlite3_vfs_find(const char *zVfsName);
    +-SQLITE_API int SQLITE_STDCALL sqlite3_vfs_register(sqlite3_vfs*, int makeDflt);
    +-SQLITE_API int SQLITE_STDCALL sqlite3_vfs_unregister(sqlite3_vfs*);
    ++SQLITE_API sqlite3_vfs *sqlite3_vfs_find(const char *zVfsName);
    ++SQLITE_API int sqlite3_vfs_register(sqlite3_vfs*, int makeDflt);
    ++SQLITE_API int sqlite3_vfs_unregister(sqlite3_vfs*);
    + 
    + /*
    + ** CAPI3REF: Mutexes
    +@@ -6215,11 +6813,11 @@ SQLITE_API int SQLITE_STDCALL sqlite3_vfs_unregister(sqlite3_vfs*);
    + **
    + ** See also: [sqlite3_mutex_held()] and [sqlite3_mutex_notheld()].
    + */
    +-SQLITE_API sqlite3_mutex *SQLITE_STDCALL sqlite3_mutex_alloc(int);
    +-SQLITE_API void SQLITE_STDCALL sqlite3_mutex_free(sqlite3_mutex*);
    +-SQLITE_API void SQLITE_STDCALL sqlite3_mutex_enter(sqlite3_mutex*);
    +-SQLITE_API int SQLITE_STDCALL sqlite3_mutex_try(sqlite3_mutex*);
    +-SQLITE_API void SQLITE_STDCALL sqlite3_mutex_leave(sqlite3_mutex*);
    ++SQLITE_API sqlite3_mutex *sqlite3_mutex_alloc(int);
    ++SQLITE_API void sqlite3_mutex_free(sqlite3_mutex*);
    ++SQLITE_API void sqlite3_mutex_enter(sqlite3_mutex*);
    ++SQLITE_API int sqlite3_mutex_try(sqlite3_mutex*);
    ++SQLITE_API void sqlite3_mutex_leave(sqlite3_mutex*);
    + 
    + /*
    + ** CAPI3REF: Mutex Methods Object
    +@@ -6329,8 +6927,8 @@ struct sqlite3_mutex_methods {
    + ** interface should also return 1 when given a NULL pointer.
    + */
    + #ifndef NDEBUG
    +-SQLITE_API int SQLITE_STDCALL sqlite3_mutex_held(sqlite3_mutex*);
    +-SQLITE_API int SQLITE_STDCALL sqlite3_mutex_notheld(sqlite3_mutex*);
    ++SQLITE_API int sqlite3_mutex_held(sqlite3_mutex*);
    ++SQLITE_API int sqlite3_mutex_notheld(sqlite3_mutex*);
    + #endif
    + 
    + /*
    +@@ -6349,7 +6947,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_mutex_notheld(sqlite3_mutex*);
    + #define SQLITE_MUTEX_STATIC_MEM       3  /* sqlite3_malloc() */
    + #define SQLITE_MUTEX_STATIC_MEM2      4  /* NOT USED */
    + #define SQLITE_MUTEX_STATIC_OPEN      4  /* sqlite3BtreeOpen() */
    +-#define SQLITE_MUTEX_STATIC_PRNG      5  /* sqlite3_random() */
    ++#define SQLITE_MUTEX_STATIC_PRNG      5  /* sqlite3_randomness() */
    + #define SQLITE_MUTEX_STATIC_LRU       6  /* lru page list */
    + #define SQLITE_MUTEX_STATIC_LRU2      7  /* NOT USED */
    + #define SQLITE_MUTEX_STATIC_PMEM      7  /* sqlite3PageMalloc() */
    +@@ -6370,7 +6968,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_mutex_notheld(sqlite3_mutex*);
    + ** ^If the [threading mode] is Single-thread or Multi-thread then this
    + ** routine returns a NULL pointer.
    + */
    +-SQLITE_API sqlite3_mutex *SQLITE_STDCALL sqlite3_db_mutex(sqlite3*);
    ++SQLITE_API sqlite3_mutex *sqlite3_db_mutex(sqlite3*);
    + 
    + /*
    + ** CAPI3REF: Low-Level Control Of Database Files
    +@@ -6389,9 +6987,9 @@ SQLITE_API sqlite3_mutex *SQLITE_STDCALL sqlite3_db_mutex(sqlite3*);
    + ** the xFileControl method.  ^The return value of the xFileControl
    + ** method becomes the return value of this routine.
    + **
    +-** ^The SQLITE_FCNTL_FILE_POINTER value for the op parameter causes
    ++** ^The [SQLITE_FCNTL_FILE_POINTER] value for the op parameter causes
    + ** a pointer to the underlying [sqlite3_file] object to be written into
    +-** the space pointed to by the 4th parameter.  ^The SQLITE_FCNTL_FILE_POINTER
    ++** the space pointed to by the 4th parameter.  ^The [SQLITE_FCNTL_FILE_POINTER]
    + ** case is a short-circuit path which does not actually invoke the
    + ** underlying sqlite3_io_methods.xFileControl method.
    + **
    +@@ -6403,9 +7001,9 @@ SQLITE_API sqlite3_mutex *SQLITE_STDCALL sqlite3_db_mutex(sqlite3*);
    + ** an incorrect zDbName and an SQLITE_ERROR return from the underlying
    + ** xFileControl method.
    + **
    +-** See also: [SQLITE_FCNTL_LOCKSTATE]
    ++** See also: [file control opcodes]
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_file_control(sqlite3*, const char *zDbName, int op, void*);
    ++SQLITE_API int sqlite3_file_control(sqlite3*, const char *zDbName, int op, void*);
    + 
    + /*
    + ** CAPI3REF: Testing Interface
    +@@ -6424,7 +7022,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_file_control(sqlite3*, const char *zDbName
    + ** Unlike most of the SQLite API, this function is not guaranteed to
    + ** operate consistently from one release to the next.
    + */
    +-SQLITE_API int SQLITE_CDECL sqlite3_test_control(int op, ...);
    ++SQLITE_API int sqlite3_test_control(int op, ...);
    + 
    + /*
    + ** CAPI3REF: Testing Interface Operation Codes
    +@@ -6450,16 +7048,18 @@ SQLITE_API int SQLITE_CDECL sqlite3_test_control(int op, ...);
    + #define SQLITE_TESTCTRL_RESERVE                 14
    + #define SQLITE_TESTCTRL_OPTIMIZATIONS           15
    + #define SQLITE_TESTCTRL_ISKEYWORD               16
    +-#define SQLITE_TESTCTRL_SCRATCHMALLOC           17
    ++#define SQLITE_TESTCTRL_SCRATCHMALLOC           17  /* NOT USED */
    + #define SQLITE_TESTCTRL_LOCALTIME_FAULT         18
    + #define SQLITE_TESTCTRL_EXPLAIN_STMT            19  /* NOT USED */
    ++#define SQLITE_TESTCTRL_ONCE_RESET_THRESHOLD    19
    + #define SQLITE_TESTCTRL_NEVER_CORRUPT           20
    + #define SQLITE_TESTCTRL_VDBE_COVERAGE           21
    + #define SQLITE_TESTCTRL_BYTEORDER               22
    + #define SQLITE_TESTCTRL_ISINIT                  23
    + #define SQLITE_TESTCTRL_SORTER_MMAP             24
    + #define SQLITE_TESTCTRL_IMPOSTER                25
    +-#define SQLITE_TESTCTRL_LAST                    25
    ++#define SQLITE_TESTCTRL_PARSER_COVERAGE         26
    ++#define SQLITE_TESTCTRL_LAST                    26  /* Largest TESTCTRL */
    + 
    + /*
    + ** CAPI3REF: SQLite Runtime Status
    +@@ -6487,8 +7087,8 @@ SQLITE_API int SQLITE_CDECL sqlite3_test_control(int op, ...);
    + **
    + ** See also: [sqlite3_db_status()]
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_status(int op, int *pCurrent, int *pHighwater, int resetFlag);
    +-SQLITE_API int SQLITE_STDCALL sqlite3_status64(
    ++SQLITE_API int sqlite3_status(int op, int *pCurrent, int *pHighwater, int resetFlag);
    ++SQLITE_API int sqlite3_status64(
    +   int op,
    +   sqlite3_int64 *pCurrent,
    +   sqlite3_int64 *pHighwater,
    +@@ -6508,8 +7108,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_status64(
    + ** <dd>This parameter is the current amount of memory checked out
    + ** using [sqlite3_malloc()], either directly or indirectly.  The
    + ** figure includes calls made to [sqlite3_malloc()] by the application
    +-** and internal memory usage by the SQLite library.  Scratch memory
    +-** controlled by [SQLITE_CONFIG_SCRATCH] and auxiliary page-cache
    ++** and internal memory usage by the SQLite library.  Auxiliary page-cache
    + ** memory controlled by [SQLITE_CONFIG_PAGECACHE] is not included in
    + ** this parameter.  The amount returned is the sum of the allocation
    + ** sizes as reported by the xSize method in [sqlite3_mem_methods].</dd>)^
    +@@ -6547,32 +7146,18 @@ SQLITE_API int SQLITE_STDCALL sqlite3_status64(
    + ** *pHighwater parameter to [sqlite3_status()] is of interest.  
    + ** The value written into the *pCurrent parameter is undefined.</dd>)^
    + **
    +-** [[SQLITE_STATUS_SCRATCH_USED]] ^(<dt>SQLITE_STATUS_SCRATCH_USED</dt>
    +-** <dd>This parameter returns the number of allocations used out of the
    +-** [scratch memory allocator] configured using
    +-** [SQLITE_CONFIG_SCRATCH].  The value returned is in allocations, not
    +-** in bytes.  Since a single thread may only have one scratch allocation
    +-** outstanding at time, this parameter also reports the number of threads
    +-** using scratch memory at the same time.</dd>)^
    ++** [[SQLITE_STATUS_SCRATCH_USED]] <dt>SQLITE_STATUS_SCRATCH_USED</dt>
    ++** <dd>No longer used.</dd>
    + **
    + ** [[SQLITE_STATUS_SCRATCH_OVERFLOW]] ^(<dt>SQLITE_STATUS_SCRATCH_OVERFLOW</dt>
    +-** <dd>This parameter returns the number of bytes of scratch memory
    +-** allocation which could not be satisfied by the [SQLITE_CONFIG_SCRATCH]
    +-** buffer and where forced to overflow to [sqlite3_malloc()].  The values
    +-** returned include overflows because the requested allocation was too
    +-** larger (that is, because the requested allocation was larger than the
    +-** "sz" parameter to [SQLITE_CONFIG_SCRATCH]) and because no scratch buffer
    +-** slots were available.
    +-** </dd>)^
    +-**
    +-** [[SQLITE_STATUS_SCRATCH_SIZE]] ^(<dt>SQLITE_STATUS_SCRATCH_SIZE</dt>
    +-** <dd>This parameter records the largest memory allocation request
    +-** handed to [scratch memory allocator].  Only the value returned in the
    +-** *pHighwater parameter to [sqlite3_status()] is of interest.  
    +-** The value written into the *pCurrent parameter is undefined.</dd>)^
    ++** <dd>No longer used.</dd>
    ++**
    ++** [[SQLITE_STATUS_SCRATCH_SIZE]] <dt>SQLITE_STATUS_SCRATCH_SIZE</dt>
    ++** <dd>No longer used.</dd>
    + **
    + ** [[SQLITE_STATUS_PARSER_STACK]] ^(<dt>SQLITE_STATUS_PARSER_STACK</dt>
    +-** <dd>This parameter records the deepest parser stack.  It is only
    ++** <dd>The *pHighwater parameter records the deepest parser stack. 
    ++** The *pCurrent value is undefined.  The *pHighwater value is only
    + ** meaningful if SQLite is compiled with [YYTRACKMAXSTACKDEPTH].</dd>)^
    + ** </dl>
    + **
    +@@ -6581,12 +7166,12 @@ SQLITE_API int SQLITE_STDCALL sqlite3_status64(
    + #define SQLITE_STATUS_MEMORY_USED          0
    + #define SQLITE_STATUS_PAGECACHE_USED       1
    + #define SQLITE_STATUS_PAGECACHE_OVERFLOW   2
    +-#define SQLITE_STATUS_SCRATCH_USED         3
    +-#define SQLITE_STATUS_SCRATCH_OVERFLOW     4
    ++#define SQLITE_STATUS_SCRATCH_USED         3  /* NOT USED */
    ++#define SQLITE_STATUS_SCRATCH_OVERFLOW     4  /* NOT USED */
    + #define SQLITE_STATUS_MALLOC_SIZE          5
    + #define SQLITE_STATUS_PARSER_STACK         6
    + #define SQLITE_STATUS_PAGECACHE_SIZE       7
    +-#define SQLITE_STATUS_SCRATCH_SIZE         8
    ++#define SQLITE_STATUS_SCRATCH_SIZE         8  /* NOT USED */
    + #define SQLITE_STATUS_MALLOC_COUNT         9
    + 
    + /*
    +@@ -6612,7 +7197,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_status64(
    + **
    + ** See also: [sqlite3_status()] and [sqlite3_stmt_status()].
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_db_status(sqlite3*, int op, int *pCur, int *pHiwtr, int resetFlg);
    ++SQLITE_API int sqlite3_db_status(sqlite3*, int op, int *pCur, int *pHiwtr, int resetFlg);
    + 
    + /*
    + ** CAPI3REF: Status Parameters for database connections
    +@@ -6658,6 +7243,18 @@ SQLITE_API int SQLITE_STDCALL sqlite3_db_status(sqlite3*, int op, int *pCur, int
    + ** memory used by all pager caches associated with the database connection.)^
    + ** ^The highwater mark associated with SQLITE_DBSTATUS_CACHE_USED is always 0.
    + **
    ++** [[SQLITE_DBSTATUS_CACHE_USED_SHARED]] 
    ++** ^(<dt>SQLITE_DBSTATUS_CACHE_USED_SHARED</dt>
    ++** <dd>This parameter is similar to DBSTATUS_CACHE_USED, except that if a
    ++** pager cache is shared between two or more connections the bytes of heap
    ++** memory used by that pager cache is divided evenly between the attached
    ++** connections.)^  In other words, if none of the pager caches associated
    ++** with the database connection are shared, this request returns the same
    ++** value as DBSTATUS_CACHE_USED. Or, if one or more or the pager caches are
    ++** shared, the value returned by this call will be smaller than that returned
    ++** by DBSTATUS_CACHE_USED. ^The highwater mark associated with
    ++** SQLITE_DBSTATUS_CACHE_USED_SHARED is always 0.
    ++**
    + ** [[SQLITE_DBSTATUS_SCHEMA_USED]] ^(<dt>SQLITE_DBSTATUS_SCHEMA_USED</dt>
    + ** <dd>This parameter returns the approximate number of bytes of heap
    + ** memory used to store the schema for all databases associated
    +@@ -6715,7 +7312,8 @@ SQLITE_API int SQLITE_STDCALL sqlite3_db_status(sqlite3*, int op, int *pCur, int
    + #define SQLITE_DBSTATUS_CACHE_MISS           8
    + #define SQLITE_DBSTATUS_CACHE_WRITE          9
    + #define SQLITE_DBSTATUS_DEFERRED_FKS        10
    +-#define SQLITE_DBSTATUS_MAX                 10   /* Largest defined DBSTATUS */
    ++#define SQLITE_DBSTATUS_CACHE_USED_SHARED   11
    ++#define SQLITE_DBSTATUS_MAX                 11   /* Largest defined DBSTATUS */
    + 
    + 
    + /*
    +@@ -6742,7 +7340,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_db_status(sqlite3*, int op, int *pCur, int
    + **
    + ** See also: [sqlite3_status()] and [sqlite3_db_status()].
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_stmt_status(sqlite3_stmt*, int op,int resetFlg);
    ++SQLITE_API int sqlite3_stmt_status(sqlite3_stmt*, int op,int resetFlg);
    + 
    + /*
    + ** CAPI3REF: Status Parameters for prepared statements
    +@@ -6778,6 +7376,24 @@ SQLITE_API int SQLITE_STDCALL sqlite3_stmt_status(sqlite3_stmt*, int op,int rese
    + ** used as a proxy for the total work done by the prepared statement.
    + ** If the number of virtual machine operations exceeds 2147483647
    + ** then the value returned by this statement status code is undefined.
    ++**
    ++** [[SQLITE_STMTSTATUS_REPREPARE]] <dt>SQLITE_STMTSTATUS_REPREPARE</dt>
    ++** <dd>^This is the number of times that the prepare statement has been
    ++** automatically regenerated due to schema changes or change to 
    ++** [bound parameters] that might affect the query plan.
    ++**
    ++** [[SQLITE_STMTSTATUS_RUN]] <dt>SQLITE_STMTSTATUS_RUN</dt>
    ++** <dd>^This is the number of times that the prepared statement has
    ++** been run.  A single "run" for the purposes of this counter is one
    ++** or more calls to [sqlite3_step()] followed by a call to [sqlite3_reset()].
    ++** The counter is incremented on the first [sqlite3_step()] call of each
    ++** cycle.
    ++**
    ++** [[SQLITE_STMTSTATUS_MEMUSED]] <dt>SQLITE_STMTSTATUS_MEMUSED</dt>
    ++** <dd>^This is the approximate number of bytes of heap memory
    ++** used to store the prepared statement.  ^This value is not actually
    ++** a counter, and so the resetFlg parameter to sqlite3_stmt_status()
    ++** is ignored when the opcode is SQLITE_STMTSTATUS_MEMUSED.
    + ** </dd>
    + ** </dl>
    + */
    +@@ -6785,6 +7401,9 @@ SQLITE_API int SQLITE_STDCALL sqlite3_stmt_status(sqlite3_stmt*, int op,int rese
    + #define SQLITE_STMTSTATUS_SORT              2
    + #define SQLITE_STMTSTATUS_AUTOINDEX         3
    + #define SQLITE_STMTSTATUS_VM_STEP           4
    ++#define SQLITE_STMTSTATUS_REPREPARE         5
    ++#define SQLITE_STMTSTATUS_RUN               6
    ++#define SQLITE_STMTSTATUS_MEMUSED           99
    + 
    + /*
    + ** CAPI3REF: Custom Page Cache Object
    +@@ -7069,7 +7688,7 @@ typedef struct sqlite3_backup sqlite3_backup;
    + ** must be different or else sqlite3_backup_init(D,N,S,M) will fail with
    + ** an error.
    + **
    +-** ^A call to sqlite3_backup_init() will fail, returning SQLITE_ERROR, if 
    ++** ^A call to sqlite3_backup_init() will fail, returning NULL, if 
    + ** there is already a read or read-write transaction open on the 
    + ** destination database.
    + **
    +@@ -7211,16 +7830,16 @@ typedef struct sqlite3_backup sqlite3_backup;
    + ** same time as another thread is invoking sqlite3_backup_step() it is
    + ** possible that they return invalid values.
    + */
    +-SQLITE_API sqlite3_backup *SQLITE_STDCALL sqlite3_backup_init(
    ++SQLITE_API sqlite3_backup *sqlite3_backup_init(
    +   sqlite3 *pDest,                        /* Destination database handle */
    +   const char *zDestName,                 /* Destination database name */
    +   sqlite3 *pSource,                      /* Source database handle */
    +   const char *zSourceName                /* Source database name */
    + );
    +-SQLITE_API int SQLITE_STDCALL sqlite3_backup_step(sqlite3_backup *p, int nPage);
    +-SQLITE_API int SQLITE_STDCALL sqlite3_backup_finish(sqlite3_backup *p);
    +-SQLITE_API int SQLITE_STDCALL sqlite3_backup_remaining(sqlite3_backup *p);
    +-SQLITE_API int SQLITE_STDCALL sqlite3_backup_pagecount(sqlite3_backup *p);
    ++SQLITE_API int sqlite3_backup_step(sqlite3_backup *p, int nPage);
    ++SQLITE_API int sqlite3_backup_finish(sqlite3_backup *p);
    ++SQLITE_API int sqlite3_backup_remaining(sqlite3_backup *p);
    ++SQLITE_API int sqlite3_backup_pagecount(sqlite3_backup *p);
    + 
    + /*
    + ** CAPI3REF: Unlock Notification
    +@@ -7337,7 +7956,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_backup_pagecount(sqlite3_backup *p);
    + ** the special "DROP TABLE/INDEX" case, the extended error code is just 
    + ** SQLITE_LOCKED.)^
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_unlock_notify(
    ++SQLITE_API int sqlite3_unlock_notify(
    +   sqlite3 *pBlocked,                          /* Waiting connection */
    +   void (*xNotify)(void **apArg, int nArg),    /* Callback function to invoke */
    +   void *pNotifyArg                            /* Argument to pass to xNotify */
    +@@ -7352,23 +7971,48 @@ SQLITE_API int SQLITE_STDCALL sqlite3_unlock_notify(
    + ** strings in a case-independent fashion, using the same definition of "case
    + ** independence" that SQLite uses internally when comparing identifiers.
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_stricmp(const char *, const char *);
    +-SQLITE_API int SQLITE_STDCALL sqlite3_strnicmp(const char *, const char *, int);
    ++SQLITE_API int sqlite3_stricmp(const char *, const char *);
    ++SQLITE_API int sqlite3_strnicmp(const char *, const char *, int);
    + 
    + /*
    + ** CAPI3REF: String Globbing
    + *
    +-** ^The [sqlite3_strglob(P,X)] interface returns zero if string X matches
    +-** the glob pattern P, and it returns non-zero if string X does not match
    +-** the glob pattern P.  ^The definition of glob pattern matching used in
    ++** ^The [sqlite3_strglob(P,X)] interface returns zero if and only if
    ++** string X matches the [GLOB] pattern P.
    ++** ^The definition of [GLOB] pattern matching used in
    + ** [sqlite3_strglob(P,X)] is the same as for the "X GLOB P" operator in the
    +-** SQL dialect used by SQLite.  ^The sqlite3_strglob(P,X) function is case
    +-** sensitive.
    ++** SQL dialect understood by SQLite.  ^The [sqlite3_strglob(P,X)] function
    ++** is case sensitive.
    ++**
    ++** Note that this routine returns zero on a match and non-zero if the strings
    ++** do not match, the same as [sqlite3_stricmp()] and [sqlite3_strnicmp()].
    ++**
    ++** See also: [sqlite3_strlike()].
    ++*/
    ++SQLITE_API int sqlite3_strglob(const char *zGlob, const char *zStr);
    ++
    ++/*
    ++** CAPI3REF: String LIKE Matching
    ++*
    ++** ^The [sqlite3_strlike(P,X,E)] interface returns zero if and only if
    ++** string X matches the [LIKE] pattern P with escape character E.
    ++** ^The definition of [LIKE] pattern matching used in
    ++** [sqlite3_strlike(P,X,E)] is the same as for the "X LIKE P ESCAPE E"
    ++** operator in the SQL dialect understood by SQLite.  ^For "X LIKE P" without
    ++** the ESCAPE clause, set the E parameter of [sqlite3_strlike(P,X,E)] to 0.
    ++** ^As with the LIKE operator, the [sqlite3_strlike(P,X,E)] function is case
    ++** insensitive - equivalent upper and lower case ASCII characters match
    ++** one another.
    ++**
    ++** ^The [sqlite3_strlike(P,X,E)] function matches Unicode characters, though
    ++** only ASCII characters are case folded.
    + **
    + ** Note that this routine returns zero on a match and non-zero if the strings
    + ** do not match, the same as [sqlite3_stricmp()] and [sqlite3_strnicmp()].
    ++**
    ++** See also: [sqlite3_strglob()].
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_strglob(const char *zGlob, const char *zStr);
    ++SQLITE_API int sqlite3_strlike(const char *zGlob, const char *zStr, unsigned int cEsc);
    + 
    + /*
    + ** CAPI3REF: Error Logging Interface
    +@@ -7391,7 +8035,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_strglob(const char *zGlob, const char *zSt
    + ** a few hundred characters, it will be truncated to the length of the
    + ** buffer.
    + */
    +-SQLITE_API void SQLITE_CDECL sqlite3_log(int iErrCode, const char *zFormat, ...);
    ++SQLITE_API void sqlite3_log(int iErrCode, const char *zFormat, ...);
    + 
    + /*
    + ** CAPI3REF: Write-Ahead Log Commit Hook
    +@@ -7425,9 +8069,9 @@ SQLITE_API void SQLITE_CDECL sqlite3_log(int iErrCode, const char *zFormat, ...)
    + ** previously registered write-ahead log callback. ^Note that the
    + ** [sqlite3_wal_autocheckpoint()] interface and the
    + ** [wal_autocheckpoint pragma] both invoke [sqlite3_wal_hook()] and will
    +-** those overwrite any prior [sqlite3_wal_hook()] settings.
    ++** overwrite any prior [sqlite3_wal_hook()] settings.
    + */
    +-SQLITE_API void *SQLITE_STDCALL sqlite3_wal_hook(
    ++SQLITE_API void *sqlite3_wal_hook(
    +   sqlite3*, 
    +   int(*)(void *,sqlite3*,const char*,int),
    +   void*
    +@@ -7462,7 +8106,7 @@ SQLITE_API void *SQLITE_STDCALL sqlite3_wal_hook(
    + ** is only necessary if the default setting is found to be suboptimal
    + ** for a particular application.
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_wal_autocheckpoint(sqlite3 *db, int N);
    ++SQLITE_API int sqlite3_wal_autocheckpoint(sqlite3 *db, int N);
    + 
    + /*
    + ** CAPI3REF: Checkpoint a database
    +@@ -7484,7 +8128,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_wal_autocheckpoint(sqlite3 *db, int N);
    + ** start a callback but which do not need the full power (and corresponding
    + ** complication) of [sqlite3_wal_checkpoint_v2()].
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_wal_checkpoint(sqlite3 *db, const char *zDb);
    ++SQLITE_API int sqlite3_wal_checkpoint(sqlite3 *db, const char *zDb);
    + 
    + /*
    + ** CAPI3REF: Checkpoint a database
    +@@ -7578,7 +8222,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_wal_checkpoint(sqlite3 *db, const char *zD
    + ** ^The [PRAGMA wal_checkpoint] command can be used to invoke this interface
    + ** from SQL.
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_wal_checkpoint_v2(
    ++SQLITE_API int sqlite3_wal_checkpoint_v2(
    +   sqlite3 *db,                    /* Database handle */
    +   const char *zDb,                /* Name of attached database (or NULL) */
    +   int eMode,                      /* SQLITE_CHECKPOINT_* value */
    +@@ -7614,7 +8258,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_wal_checkpoint_v2(
    + ** this function. (See [SQLITE_VTAB_CONSTRAINT_SUPPORT].)  Further options
    + ** may be added in the future.
    + */
    +-SQLITE_API int SQLITE_CDECL sqlite3_vtab_config(sqlite3*, int op, ...);
    ++SQLITE_API int sqlite3_vtab_config(sqlite3*, int op, ...);
    + 
    + /*
    + ** CAPI3REF: Virtual Table Configuration Options
    +@@ -7667,7 +8311,41 @@ SQLITE_API int SQLITE_CDECL sqlite3_vtab_config(sqlite3*, int op, ...);
    + ** of the SQL statement that triggered the call to the [xUpdate] method of the
    + ** [virtual table].
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_vtab_on_conflict(sqlite3 *);
    ++SQLITE_API int sqlite3_vtab_on_conflict(sqlite3 *);
    ++
    ++/*
    ++** CAPI3REF: Determine If Virtual Table Column Access Is For UPDATE
    ++**
    ++** If the sqlite3_vtab_nochange(X) routine is called within the [xColumn]
    ++** method of a [virtual table], then it returns true if and only if the
    ++** column is being fetched as part of an UPDATE operation during which the
    ++** column value will not change.  Applications might use this to substitute
    ++** a lighter-weight value to return that the corresponding [xUpdate] method
    ++** understands as a "no-change" value.
    ++**
    ++** If the [xColumn] method calls sqlite3_vtab_nochange() and finds that
    ++** the column is not changed by the UPDATE statement, they the xColumn
    ++** method can optionally return without setting a result, without calling
    ++** any of the [sqlite3_result_int|sqlite3_result_xxxxx() interfaces].
    ++** In that case, [sqlite3_value_nochange(X)] will return true for the
    ++** same column in the [xUpdate] method.
    ++*/
    ++SQLITE_API int sqlite3_vtab_nochange(sqlite3_context*);
    ++
    ++/*
    ++** CAPI3REF: Determine The Collation For a Virtual Table Constraint
    ++**
    ++** This function may only be called from within a call to the [xBestIndex]
    ++** method of a [virtual table]. 
    ++**
    ++** The first argument must be the sqlite3_index_info object that is the
    ++** first parameter to the xBestIndex() method. The second argument must be
    ++** an index into the aConstraint[] array belonging to the sqlite3_index_info
    ++** structure passed to xBestIndex. This function returns a pointer to a buffer 
    ++** containing the name of the collation sequence for the corresponding
    ++** constraint.
    ++*/
    ++SQLITE_API SQLITE_EXPERIMENTAL const char *sqlite3_vtab_collation(sqlite3_index_info*,int);
    + 
    + /*
    + ** CAPI3REF: Conflict resolution modes
    +@@ -7772,7 +8450,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_vtab_on_conflict(sqlite3 *);
    + **
    + ** See also: [sqlite3_stmt_scanstatus_reset()]
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_stmt_scanstatus(
    ++SQLITE_API int sqlite3_stmt_scanstatus(
    +   sqlite3_stmt *pStmt,      /* Prepared statement for which info desired */
    +   int idx,                  /* Index of loop to report on */
    +   int iScanStatusOp,        /* Information desired.  SQLITE_SCANSTAT_* */
    +@@ -7788,8 +8466,332 @@ SQLITE_API int SQLITE_STDCALL sqlite3_stmt_scanstatus(
    + ** This API is only available if the library is built with pre-processor
    + ** symbol [SQLITE_ENABLE_STMT_SCANSTATUS] defined.
    + */
    +-SQLITE_API void SQLITE_STDCALL sqlite3_stmt_scanstatus_reset(sqlite3_stmt*);
    ++SQLITE_API void sqlite3_stmt_scanstatus_reset(sqlite3_stmt*);
    ++
    ++/*
    ++** CAPI3REF: Flush caches to disk mid-transaction
    ++**
    ++** ^If a write-transaction is open on [database connection] D when the
    ++** [sqlite3_db_cacheflush(D)] interface invoked, any dirty
    ++** pages in the pager-cache that are not currently in use are written out 
    ++** to disk. A dirty page may be in use if a database cursor created by an
    ++** active SQL statement is reading from it, or if it is page 1 of a database
    ++** file (page 1 is always "in use").  ^The [sqlite3_db_cacheflush(D)]
    ++** interface flushes caches for all schemas - "main", "temp", and
    ++** any [attached] databases.
    ++**
    ++** ^If this function needs to obtain extra database locks before dirty pages 
    ++** can be flushed to disk, it does so. ^If those locks cannot be obtained 
    ++** immediately and there is a busy-handler callback configured, it is invoked
    ++** in the usual manner. ^If the required lock still cannot be obtained, then
    ++** the database is skipped and an attempt made to flush any dirty pages
    ++** belonging to the next (if any) database. ^If any databases are skipped
    ++** because locks cannot be obtained, but no other error occurs, this
    ++** function returns SQLITE_BUSY.
    ++**
    ++** ^If any other error occurs while flushing dirty pages to disk (for
    ++** example an IO error or out-of-memory condition), then processing is
    ++** abandoned and an SQLite [error code] is returned to the caller immediately.
    ++**
    ++** ^Otherwise, if no error occurs, [sqlite3_db_cacheflush()] returns SQLITE_OK.
    ++**
    ++** ^This function does not set the database handle error code or message
    ++** returned by the [sqlite3_errcode()] and [sqlite3_errmsg()] functions.
    ++*/
    ++SQLITE_API int sqlite3_db_cacheflush(sqlite3*);
    ++
    ++/*
    ++** CAPI3REF: The pre-update hook.
    ++**
    ++** ^These interfaces are only available if SQLite is compiled using the
    ++** [SQLITE_ENABLE_PREUPDATE_HOOK] compile-time option.
    ++**
    ++** ^The [sqlite3_preupdate_hook()] interface registers a callback function
    ++** that is invoked prior to each [INSERT], [UPDATE], and [DELETE] operation
    ++** on a database table.
    ++** ^At most one preupdate hook may be registered at a time on a single
    ++** [database connection]; each call to [sqlite3_preupdate_hook()] overrides
    ++** the previous setting.
    ++** ^The preupdate hook is disabled by invoking [sqlite3_preupdate_hook()]
    ++** with a NULL pointer as the second parameter.
    ++** ^The third parameter to [sqlite3_preupdate_hook()] is passed through as
    ++** the first parameter to callbacks.
    ++**
    ++** ^The preupdate hook only fires for changes to real database tables; the
    ++** preupdate hook is not invoked for changes to [virtual tables] or to
    ++** system tables like sqlite_master or sqlite_stat1.
    ++**
    ++** ^The second parameter to the preupdate callback is a pointer to
    ++** the [database connection] that registered the preupdate hook.
    ++** ^The third parameter to the preupdate callback is one of the constants
    ++** [SQLITE_INSERT], [SQLITE_DELETE], or [SQLITE_UPDATE] to identify the
    ++** kind of update operation that is about to occur.
    ++** ^(The fourth parameter to the preupdate callback is the name of the
    ++** database within the database connection that is being modified.  This
    ++** will be "main" for the main database or "temp" for TEMP tables or 
    ++** the name given after the AS keyword in the [ATTACH] statement for attached
    ++** databases.)^
    ++** ^The fifth parameter to the preupdate callback is the name of the
    ++** table that is being modified.
    ++**
    ++** For an UPDATE or DELETE operation on a [rowid table], the sixth
    ++** parameter passed to the preupdate callback is the initial [rowid] of the 
    ++** row being modified or deleted. For an INSERT operation on a rowid table,
    ++** or any operation on a WITHOUT ROWID table, the value of the sixth 
    ++** parameter is undefined. For an INSERT or UPDATE on a rowid table the
    ++** seventh parameter is the final rowid value of the row being inserted
    ++** or updated. The value of the seventh parameter passed to the callback
    ++** function is not defined for operations on WITHOUT ROWID tables, or for
    ++** INSERT operations on rowid tables.
    ++**
    ++** The [sqlite3_preupdate_old()], [sqlite3_preupdate_new()],
    ++** [sqlite3_preupdate_count()], and [sqlite3_preupdate_depth()] interfaces
    ++** provide additional information about a preupdate event. These routines
    ++** may only be called from within a preupdate callback.  Invoking any of
    ++** these routines from outside of a preupdate callback or with a
    ++** [database connection] pointer that is different from the one supplied
    ++** to the preupdate callback results in undefined and probably undesirable
    ++** behavior.
    ++**
    ++** ^The [sqlite3_preupdate_count(D)] interface returns the number of columns
    ++** in the row that is being inserted, updated, or deleted.
    ++**
    ++** ^The [sqlite3_preupdate_old(D,N,P)] interface writes into P a pointer to
    ++** a [protected sqlite3_value] that contains the value of the Nth column of
    ++** the table row before it is updated.  The N parameter must be between 0
    ++** and one less than the number of columns or the behavior will be
    ++** undefined. This must only be used within SQLITE_UPDATE and SQLITE_DELETE
    ++** preupdate callbacks; if it is used by an SQLITE_INSERT callback then the
    ++** behavior is undefined.  The [sqlite3_value] that P points to
    ++** will be destroyed when the preupdate callback returns.
    ++**
    ++** ^The [sqlite3_preupdate_new(D,N,P)] interface writes into P a pointer to
    ++** a [protected sqlite3_value] that contains the value of the Nth column of
    ++** the table row after it is updated.  The N parameter must be between 0
    ++** and one less than the number of columns or the behavior will be
    ++** undefined. This must only be used within SQLITE_INSERT and SQLITE_UPDATE
    ++** preupdate callbacks; if it is used by an SQLITE_DELETE callback then the
    ++** behavior is undefined.  The [sqlite3_value] that P points to
    ++** will be destroyed when the preupdate callback returns.
    ++**
    ++** ^The [sqlite3_preupdate_depth(D)] interface returns 0 if the preupdate
    ++** callback was invoked as a result of a direct insert, update, or delete
    ++** operation; or 1 for inserts, updates, or deletes invoked by top-level 
    ++** triggers; or 2 for changes resulting from triggers called by top-level
    ++** triggers; and so forth.
    ++**
    ++** See also:  [sqlite3_update_hook()]
    ++*/
    ++#if defined(SQLITE_ENABLE_PREUPDATE_HOOK)
    ++SQLITE_API void *sqlite3_preupdate_hook(
    ++  sqlite3 *db,
    ++  void(*xPreUpdate)(
    ++    void *pCtx,                   /* Copy of third arg to preupdate_hook() */
    ++    sqlite3 *db,                  /* Database handle */
    ++    int op,                       /* SQLITE_UPDATE, DELETE or INSERT */
    ++    char const *zDb,              /* Database name */
    ++    char const *zName,            /* Table name */
    ++    sqlite3_int64 iKey1,          /* Rowid of row about to be deleted/updated */
    ++    sqlite3_int64 iKey2           /* New rowid value (for a rowid UPDATE) */
    ++  ),
    ++  void*
    ++);
    ++SQLITE_API int sqlite3_preupdate_old(sqlite3 *, int, sqlite3_value **);
    ++SQLITE_API int sqlite3_preupdate_count(sqlite3 *);
    ++SQLITE_API int sqlite3_preupdate_depth(sqlite3 *);
    ++SQLITE_API int sqlite3_preupdate_new(sqlite3 *, int, sqlite3_value **);
    ++#endif
    ++
    ++/*
    ++** CAPI3REF: Low-level system error code
    ++**
    ++** ^Attempt to return the underlying operating system error code or error
    ++** number that caused the most recent I/O error or failure to open a file.
    ++** The return value is OS-dependent.  For example, on unix systems, after
    ++** [sqlite3_open_v2()] returns [SQLITE_CANTOPEN], this interface could be
    ++** called to get back the underlying "errno" that caused the problem, such
    ++** as ENOSPC, EAUTH, EISDIR, and so forth.  
    ++*/
    ++SQLITE_API int sqlite3_system_errno(sqlite3*);
    ++
    ++/*
    ++** CAPI3REF: Database Snapshot
    ++** KEYWORDS: {snapshot} {sqlite3_snapshot}
    ++** EXPERIMENTAL
    ++**
    ++** An instance of the snapshot object records the state of a [WAL mode]
    ++** database for some specific point in history.
    ++**
    ++** In [WAL mode], multiple [database connections] that are open on the
    ++** same database file can each be reading a different historical version
    ++** of the database file.  When a [database connection] begins a read
    ++** transaction, that connection sees an unchanging copy of the database
    ++** as it existed for the point in time when the transaction first started.
    ++** Subsequent changes to the database from other connections are not seen
    ++** by the reader until a new read transaction is started.
    ++**
    ++** The sqlite3_snapshot object records state information about an historical
    ++** version of the database file so that it is possible to later open a new read
    ++** transaction that sees that historical version of the database rather than
    ++** the most recent version.
    ++**
    ++** The constructor for this object is [sqlite3_snapshot_get()].  The
    ++** [sqlite3_snapshot_open()] method causes a fresh read transaction to refer
    ++** to an historical snapshot (if possible).  The destructor for 
    ++** sqlite3_snapshot objects is [sqlite3_snapshot_free()].
    ++*/
    ++typedef struct sqlite3_snapshot {
    ++  unsigned char hidden[48];
    ++} sqlite3_snapshot;
    ++
    ++/*
    ++** CAPI3REF: Record A Database Snapshot
    ++** EXPERIMENTAL
    ++**
    ++** ^The [sqlite3_snapshot_get(D,S,P)] interface attempts to make a
    ++** new [sqlite3_snapshot] object that records the current state of
    ++** schema S in database connection D.  ^On success, the
    ++** [sqlite3_snapshot_get(D,S,P)] interface writes a pointer to the newly
    ++** created [sqlite3_snapshot] object into *P and returns SQLITE_OK.
    ++** If there is not already a read-transaction open on schema S when
    ++** this function is called, one is opened automatically. 
    ++**
    ++** The following must be true for this function to succeed. If any of
    ++** the following statements are false when sqlite3_snapshot_get() is
    ++** called, SQLITE_ERROR is returned. The final value of *P is undefined
    ++** in this case. 
    ++**
    ++** <ul>
    ++**   <li> The database handle must be in [autocommit mode].
    ++**
    ++**   <li> Schema S of [database connection] D must be a [WAL mode] database.
    ++**
    ++**   <li> There must not be a write transaction open on schema S of database
    ++**        connection D.
    ++**
    ++**   <li> One or more transactions must have been written to the current wal
    ++**        file since it was created on disk (by any connection). This means
    ++**        that a snapshot cannot be taken on a wal mode database with no wal 
    ++**        file immediately after it is first opened. At least one transaction
    ++**        must be written to it first.
    ++** </ul>
    ++**
    ++** This function may also return SQLITE_NOMEM.  If it is called with the
    ++** database handle in autocommit mode but fails for some other reason, 
    ++** whether or not a read transaction is opened on schema S is undefined.
    ++**
    ++** The [sqlite3_snapshot] object returned from a successful call to
    ++** [sqlite3_snapshot_get()] must be freed using [sqlite3_snapshot_free()]
    ++** to avoid a memory leak.
    ++**
    ++** The [sqlite3_snapshot_get()] interface is only available when the
    ++** SQLITE_ENABLE_SNAPSHOT compile-time option is used.
    ++*/
    ++SQLITE_API SQLITE_EXPERIMENTAL int sqlite3_snapshot_get(
    ++  sqlite3 *db,
    ++  const char *zSchema,
    ++  sqlite3_snapshot **ppSnapshot
    ++);
    ++
    ++/*
    ++** CAPI3REF: Start a read transaction on an historical snapshot
    ++** EXPERIMENTAL
    ++**
    ++** ^The [sqlite3_snapshot_open(D,S,P)] interface starts a
    ++** read transaction for schema S of
    ++** [database connection] D such that the read transaction
    ++** refers to historical [snapshot] P, rather than the most
    ++** recent change to the database.
    ++** ^The [sqlite3_snapshot_open()] interface returns SQLITE_OK on success
    ++** or an appropriate [error code] if it fails.
    ++**
    ++** ^In order to succeed, a call to [sqlite3_snapshot_open(D,S,P)] must be
    ++** the first operation following the [BEGIN] that takes the schema S
    ++** out of [autocommit mode].
    ++** ^In other words, schema S must not currently be in
    ++** a transaction for [sqlite3_snapshot_open(D,S,P)] to work, but the
    ++** database connection D must be out of [autocommit mode].
    ++** ^A [snapshot] will fail to open if it has been overwritten by a
    ++** [checkpoint].
    ++** ^(A call to [sqlite3_snapshot_open(D,S,P)] will fail if the
    ++** database connection D does not know that the database file for
    ++** schema S is in [WAL mode].  A database connection might not know
    ++** that the database file is in [WAL mode] if there has been no prior
    ++** I/O on that database connection, or if the database entered [WAL mode] 
    ++** after the most recent I/O on the database connection.)^
    ++** (Hint: Run "[PRAGMA application_id]" against a newly opened
    ++** database connection in order to make it ready to use snapshots.)
    ++**
    ++** The [sqlite3_snapshot_open()] interface is only available when the
    ++** SQLITE_ENABLE_SNAPSHOT compile-time option is used.
    ++*/
    ++SQLITE_API SQLITE_EXPERIMENTAL int sqlite3_snapshot_open(
    ++  sqlite3 *db,
    ++  const char *zSchema,
    ++  sqlite3_snapshot *pSnapshot
    ++);
    ++
    ++/*
    ++** CAPI3REF: Destroy a snapshot
    ++** EXPERIMENTAL
    ++**
    ++** ^The [sqlite3_snapshot_free(P)] interface destroys [sqlite3_snapshot] P.
    ++** The application must eventually free every [sqlite3_snapshot] object
    ++** using this routine to avoid a memory leak.
    ++**
    ++** The [sqlite3_snapshot_free()] interface is only available when the
    ++** SQLITE_ENABLE_SNAPSHOT compile-time option is used.
    ++*/
    ++SQLITE_API SQLITE_EXPERIMENTAL void sqlite3_snapshot_free(sqlite3_snapshot*);
    ++
    ++/*
    ++** CAPI3REF: Compare the ages of two snapshot handles.
    ++** EXPERIMENTAL
    ++**
    ++** The sqlite3_snapshot_cmp(P1, P2) interface is used to compare the ages
    ++** of two valid snapshot handles. 
    ++**
    ++** If the two snapshot handles are not associated with the same database 
    ++** file, the result of the comparison is undefined. 
    ++**
    ++** Additionally, the result of the comparison is only valid if both of the
    ++** snapshot handles were obtained by calling sqlite3_snapshot_get() since the
    ++** last time the wal file was deleted. The wal file is deleted when the
    ++** database is changed back to rollback mode or when the number of database
    ++** clients drops to zero. If either snapshot handle was obtained before the 
    ++** wal file was last deleted, the value returned by this function 
    ++** is undefined.
    ++**
    ++** Otherwise, this API returns a negative value if P1 refers to an older
    ++** snapshot than P2, zero if the two handles refer to the same database
    ++** snapshot, and a positive value if P1 is a newer snapshot than P2.
    ++*/
    ++SQLITE_API SQLITE_EXPERIMENTAL int sqlite3_snapshot_cmp(
    ++  sqlite3_snapshot *p1,
    ++  sqlite3_snapshot *p2
    ++);
    + 
    ++/*
    ++** CAPI3REF: Recover snapshots from a wal file
    ++** EXPERIMENTAL
    ++**
    ++** If all connections disconnect from a database file but do not perform
    ++** a checkpoint, the existing wal file is opened along with the database
    ++** file the next time the database is opened. At this point it is only
    ++** possible to successfully call sqlite3_snapshot_open() to open the most
    ++** recent snapshot of the database (the one at the head of the wal file),
    ++** even though the wal file may contain other valid snapshots for which
    ++** clients have sqlite3_snapshot handles.
    ++**
    ++** This function attempts to scan the wal file associated with database zDb
    ++** of database handle db and make all valid snapshots available to
    ++** sqlite3_snapshot_open(). It is an error if there is already a read
    ++** transaction open on the database, or if the database is not a wal mode
    ++** database.
    ++**
    ++** SQLITE_OK is returned if successful, or an SQLite error code otherwise.
    ++*/
    ++SQLITE_API SQLITE_EXPERIMENTAL int sqlite3_snapshot_recover(sqlite3 *db, const char *zDb);
    + 
    + /*
    + ** Undo the hack that converts floating point types to integer for
    +@@ -7802,8 +8804,9 @@ SQLITE_API void SQLITE_STDCALL sqlite3_stmt_scanstatus_reset(sqlite3_stmt*);
    + #ifdef __cplusplus
    + }  /* End of the 'extern "C"' block */
    + #endif
    +-#endif /* _SQLITE3_H_ */
    ++#endif /* SQLITE3_H */
    + 
    ++/******** Begin file sqlite3rtree.h *********/
    + /*
    + ** 2010 August 30
    + **
    +@@ -7843,7 +8846,7 @@ typedef struct sqlite3_rtree_query_info sqlite3_rtree_query_info;
    + **
    + **   SELECT ... FROM <rtree> WHERE <rtree col> MATCH $zGeom(... params ...)
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_rtree_geometry_callback(
    ++SQLITE_API int sqlite3_rtree_geometry_callback(
    +   sqlite3 *db,
    +   const char *zGeom,
    +   int (*xGeom)(sqlite3_rtree_geometry*, int, sqlite3_rtree_dbl*,int*),
    +@@ -7869,7 +8872,7 @@ struct sqlite3_rtree_geometry {
    + **
    + **   SELECT ... FROM <rtree> WHERE <rtree col> MATCH $zQueryFunc(... params ...)
    + */
    +-SQLITE_API int SQLITE_STDCALL sqlite3_rtree_query_callback(
    ++SQLITE_API int sqlite3_rtree_query_callback(
    +   sqlite3 *db,
    +   const char *zQueryFunc,
    +   int (*xQueryFunc)(sqlite3_rtree_query_info*),
    +@@ -7921,6 +8924,1327 @@ struct sqlite3_rtree_query_info {
    + 
    + #endif  /* ifndef _SQLITE3RTREE_H_ */
    + 
    ++/******** End of sqlite3rtree.h *********/
    ++/******** Begin file sqlite3session.h *********/
    ++
    ++#if !defined(__SQLITESESSION_H_) && defined(SQLITE_ENABLE_SESSION)
    ++#define __SQLITESESSION_H_ 1
    ++
    ++/*
    ++** Make sure we can call this stuff from C++.
    ++*/
    ++#ifdef __cplusplus
    ++extern "C" {
    ++#endif
    ++
    ++
    ++/*
    ++** CAPI3REF: Session Object Handle
    ++*/
    ++typedef struct sqlite3_session sqlite3_session;
    ++
    ++/*
    ++** CAPI3REF: Changeset Iterator Handle
    ++*/
    ++typedef struct sqlite3_changeset_iter sqlite3_changeset_iter;
    ++
    ++/*
    ++** CAPI3REF: Create A New Session Object
    ++**
    ++** Create a new session object attached to database handle db. If successful,
    ++** a pointer to the new object is written to *ppSession and SQLITE_OK is
    ++** returned. If an error occurs, *ppSession is set to NULL and an SQLite
    ++** error code (e.g. SQLITE_NOMEM) is returned.
    ++**
    ++** It is possible to create multiple session objects attached to a single
    ++** database handle.
    ++**
    ++** Session objects created using this function should be deleted using the
    ++** [sqlite3session_delete()] function before the database handle that they
    ++** are attached to is itself closed. If the database handle is closed before
    ++** the session object is deleted, then the results of calling any session
    ++** module function, including [sqlite3session_delete()] on the session object
    ++** are undefined.
    ++**
    ++** Because the session module uses the [sqlite3_preupdate_hook()] API, it
    ++** is not possible for an application to register a pre-update hook on a
    ++** database handle that has one or more session objects attached. Nor is
    ++** it possible to create a session object attached to a database handle for
    ++** which a pre-update hook is already defined. The results of attempting 
    ++** either of these things are undefined.
    ++**
    ++** The session object will be used to create changesets for tables in
    ++** database zDb, where zDb is either "main", or "temp", or the name of an
    ++** attached database. It is not an error if database zDb is not attached
    ++** to the database when the session object is created.
    ++*/
    ++SQLITE_API int sqlite3session_create(
    ++  sqlite3 *db,                    /* Database handle */
    ++  const char *zDb,                /* Name of db (e.g. "main") */
    ++  sqlite3_session **ppSession     /* OUT: New session object */
    ++);
    ++
    ++/*
    ++** CAPI3REF: Delete A Session Object
    ++**
    ++** Delete a session object previously allocated using 
    ++** [sqlite3session_create()]. Once a session object has been deleted, the
    ++** results of attempting to use pSession with any other session module
    ++** function are undefined.
    ++**
    ++** Session objects must be deleted before the database handle to which they
    ++** are attached is closed. Refer to the documentation for 
    ++** [sqlite3session_create()] for details.
    ++*/
    ++SQLITE_API void sqlite3session_delete(sqlite3_session *pSession);
    ++
    ++
    ++/*
    ++** CAPI3REF: Enable Or Disable A Session Object
    ++**
    ++** Enable or disable the recording of changes by a session object. When
    ++** enabled, a session object records changes made to the database. When
    ++** disabled - it does not. A newly created session object is enabled.
    ++** Refer to the documentation for [sqlite3session_changeset()] for further
    ++** details regarding how enabling and disabling a session object affects
    ++** the eventual changesets.
    ++**
    ++** Passing zero to this function disables the session. Passing a value
    ++** greater than zero enables it. Passing a value less than zero is a 
    ++** no-op, and may be used to query the current state of the session.
    ++**
    ++** The return value indicates the final state of the session object: 0 if 
    ++** the session is disabled, or 1 if it is enabled.
    ++*/
    ++SQLITE_API int sqlite3session_enable(sqlite3_session *pSession, int bEnable);
    ++
    ++/*
    ++** CAPI3REF: Set Or Clear the Indirect Change Flag
    ++**
    ++** Each change recorded by a session object is marked as either direct or
    ++** indirect. A change is marked as indirect if either:
    ++**
    ++** <ul>
    ++**   <li> The session object "indirect" flag is set when the change is
    ++**        made, or
    ++**   <li> The change is made by an SQL trigger or foreign key action 
    ++**        instead of directly as a result of a users SQL statement.
    ++** </ul>
    ++**
    ++** If a single row is affected by more than one operation within a session,
    ++** then the change is considered indirect if all operations meet the criteria
    ++** for an indirect change above, or direct otherwise.
    ++**
    ++** This function is used to set, clear or query the session object indirect
    ++** flag.  If the second argument passed to this function is zero, then the
    ++** indirect flag is cleared. If it is greater than zero, the indirect flag
    ++** is set. Passing a value less than zero does not modify the current value
    ++** of the indirect flag, and may be used to query the current state of the 
    ++** indirect flag for the specified session object.
    ++**
    ++** The return value indicates the final state of the indirect flag: 0 if 
    ++** it is clear, or 1 if it is set.
    ++*/
    ++SQLITE_API int sqlite3session_indirect(sqlite3_session *pSession, int bIndirect);
    ++
    ++/*
    ++** CAPI3REF: Attach A Table To A Session Object
    ++**
    ++** If argument zTab is not NULL, then it is the name of a table to attach
    ++** to the session object passed as the first argument. All subsequent changes 
    ++** made to the table while the session object is enabled will be recorded. See 
    ++** documentation for [sqlite3session_changeset()] for further details.
    ++**
    ++** Or, if argument zTab is NULL, then changes are recorded for all tables
    ++** in the database. If additional tables are added to the database (by 
    ++** executing "CREATE TABLE" statements) after this call is made, changes for 
    ++** the new tables are also recorded.
    ++**
    ++** Changes can only be recorded for tables that have a PRIMARY KEY explicitly
    ++** defined as part of their CREATE TABLE statement. It does not matter if the 
    ++** PRIMARY KEY is an "INTEGER PRIMARY KEY" (rowid alias) or not. The PRIMARY
    ++** KEY may consist of a single column, or may be a composite key.
    ++** 
    ++** It is not an error if the named table does not exist in the database. Nor
    ++** is it an error if the named table does not have a PRIMARY KEY. However,
    ++** no changes will be recorded in either of these scenarios.
    ++**
    ++** Changes are not recorded for individual rows that have NULL values stored
    ++** in one or more of their PRIMARY KEY columns.
    ++**
    ++** SQLITE_OK is returned if the call completes without error. Or, if an error 
    ++** occurs, an SQLite error code (e.g. SQLITE_NOMEM) is returned.
    ++**
    ++** <h3>Special sqlite_stat1 Handling</h3>
    ++**
    ++** As of SQLite version 3.22.0, the "sqlite_stat1" table is an exception to 
    ++** some of the rules above. In SQLite, the schema of sqlite_stat1 is:
    ++**  <pre>
    ++**  &nbsp;     CREATE TABLE sqlite_stat1(tbl,idx,stat)  
    ++**  </pre>
    ++**
    ++** Even though sqlite_stat1 does not have a PRIMARY KEY, changes are 
    ++** recorded for it as if the PRIMARY KEY is (tbl,idx). Additionally, changes 
    ++** are recorded for rows for which (idx IS NULL) is true. However, for such
    ++** rows a zero-length blob (SQL value X'') is stored in the changeset or
    ++** patchset instead of a NULL value. This allows such changesets to be
    ++** manipulated by legacy implementations of sqlite3changeset_invert(),
    ++** concat() and similar.
    ++**
    ++** The sqlite3changeset_apply() function automatically converts the 
    ++** zero-length blob back to a NULL value when updating the sqlite_stat1
    ++** table. However, if the application calls sqlite3changeset_new(),
    ++** sqlite3changeset_old() or sqlite3changeset_conflict on a changeset 
    ++** iterator directly (including on a changeset iterator passed to a
    ++** conflict-handler callback) then the X'' value is returned. The application
    ++** must translate X'' to NULL itself if required.
    ++**
    ++** Legacy (older than 3.22.0) versions of the sessions module cannot capture
    ++** changes made to the sqlite_stat1 table. Legacy versions of the
    ++** sqlite3changeset_apply() function silently ignore any modifications to the
    ++** sqlite_stat1 table that are part of a changeset or patchset.
    ++*/
    ++SQLITE_API int sqlite3session_attach(
    ++  sqlite3_session *pSession,      /* Session object */
    ++  const char *zTab                /* Table name */
    ++);
    ++
    ++/*
    ++** CAPI3REF: Set a table filter on a Session Object.
    ++**
    ++** The second argument (xFilter) is the "filter callback". For changes to rows 
    ++** in tables that are not attached to the Session object, the filter is called
    ++** to determine whether changes to the table's rows should be tracked or not. 
    ++** If xFilter returns 0, changes is not tracked. Note that once a table is 
    ++** attached, xFilter will not be called again.
    ++*/
    ++SQLITE_API void sqlite3session_table_filter(
    ++  sqlite3_session *pSession,      /* Session object */
    ++  int(*xFilter)(
    ++    void *pCtx,                   /* Copy of third arg to _filter_table() */
    ++    const char *zTab              /* Table name */
    ++  ),
    ++  void *pCtx                      /* First argument passed to xFilter */
    ++);
    ++
    ++/*
    ++** CAPI3REF: Generate A Changeset From A Session Object
    ++**
    ++** Obtain a changeset containing changes to the tables attached to the 
    ++** session object passed as the first argument. If successful, 
    ++** set *ppChangeset to point to a buffer containing the changeset 
    ++** and *pnChangeset to the size of the changeset in bytes before returning
    ++** SQLITE_OK. If an error occurs, set both *ppChangeset and *pnChangeset to
    ++** zero and return an SQLite error code.
    ++**
    ++** A changeset consists of zero or more INSERT, UPDATE and/or DELETE changes,
    ++** each representing a change to a single row of an attached table. An INSERT
    ++** change contains the values of each field of a new database row. A DELETE
    ++** contains the original values of each field of a deleted database row. An
    ++** UPDATE change contains the original values of each field of an updated
    ++** database row along with the updated values for each updated non-primary-key
    ++** column. It is not possible for an UPDATE change to represent a change that
    ++** modifies the values of primary key columns. If such a change is made, it
    ++** is represented in a changeset as a DELETE followed by an INSERT.
    ++**
    ++** Changes are not recorded for rows that have NULL values stored in one or 
    ++** more of their PRIMARY KEY columns. If such a row is inserted or deleted,
    ++** no corresponding change is present in the changesets returned by this
    ++** function. If an existing row with one or more NULL values stored in
    ++** PRIMARY KEY columns is updated so that all PRIMARY KEY columns are non-NULL,
    ++** only an INSERT is appears in the changeset. Similarly, if an existing row
    ++** with non-NULL PRIMARY KEY values is updated so that one or more of its
    ++** PRIMARY KEY columns are set to NULL, the resulting changeset contains a
    ++** DELETE change only.
    ++**
    ++** The contents of a changeset may be traversed using an iterator created
    ++** using the [sqlite3changeset_start()] API. A changeset may be applied to
    ++** a database with a compatible schema using the [sqlite3changeset_apply()]
    ++** API.
    ++**
    ++** Within a changeset generated by this function, all changes related to a
    ++** single table are grouped together. In other words, when iterating through
    ++** a changeset or when applying a changeset to a database, all changes related
    ++** to a single table are processed before moving on to the next table. Tables
    ++** are sorted in the same order in which they were attached (or auto-attached)
    ++** to the sqlite3_session object. The order in which the changes related to
    ++** a single table are stored is undefined.
    ++**
    ++** Following a successful call to this function, it is the responsibility of
    ++** the caller to eventually free the buffer that *ppChangeset points to using
    ++** [sqlite3_free()].
    ++**
    ++** <h3>Changeset Generation</h3>
    ++**
    ++** Once a table has been attached to a session object, the session object
    ++** records the primary key values of all new rows inserted into the table.
    ++** It also records the original primary key and other column values of any
    ++** deleted or updated rows. For each unique primary key value, data is only
    ++** recorded once - the first time a row with said primary key is inserted,
    ++** updated or deleted in the lifetime of the session.
    ++**
    ++** There is one exception to the previous paragraph: when a row is inserted,
    ++** updated or deleted, if one or more of its primary key columns contain a
    ++** NULL value, no record of the change is made.
    ++**
    ++** The session object therefore accumulates two types of records - those
    ++** that consist of primary key values only (created when the user inserts
    ++** a new record) and those that consist of the primary key values and the
    ++** original values of other table columns (created when the users deletes
    ++** or updates a record).
    ++**
    ++** When this function is called, the requested changeset is created using
    ++** both the accumulated records and the current contents of the database
    ++** file. Specifically:
    ++**
    ++** <ul>
    ++**   <li> For each record generated by an insert, the database is queried
    ++**        for a row with a matching primary key. If one is found, an INSERT
    ++**        change is added to the changeset. If no such row is found, no change 
    ++**        is added to the changeset.
    ++**
    ++**   <li> For each record generated by an update or delete, the database is 
    ++**        queried for a row with a matching primary key. If such a row is
    ++**        found and one or more of the non-primary key fields have been
    ++**        modified from their original values, an UPDATE change is added to 
    ++**        the changeset. Or, if no such row is found in the table, a DELETE 
    ++**        change is added to the changeset. If there is a row with a matching
    ++**        primary key in the database, but all fields contain their original
    ++**        values, no change is added to the changeset.
    ++** </ul>
    ++**
    ++** This means, amongst other things, that if a row is inserted and then later
    ++** deleted while a session object is active, neither the insert nor the delete
    ++** will be present in the changeset. Or if a row is deleted and then later a 
    ++** row with the same primary key values inserted while a session object is
    ++** active, the resulting changeset will contain an UPDATE change instead of
    ++** a DELETE and an INSERT.
    ++**
    ++** When a session object is disabled (see the [sqlite3session_enable()] API),
    ++** it does not accumulate records when rows are inserted, updated or deleted.
    ++** This may appear to have some counter-intuitive effects if a single row
    ++** is written to more than once during a session. For example, if a row
    ++** is inserted while a session object is enabled, then later deleted while 
    ++** the same session object is disabled, no INSERT record will appear in the
    ++** changeset, even though the delete took place while the session was disabled.
    ++** Or, if one field of a row is updated while a session is disabled, and 
    ++** another field of the same row is updated while the session is enabled, the
    ++** resulting changeset will contain an UPDATE change that updates both fields.
    ++*/
    ++SQLITE_API int sqlite3session_changeset(
    ++  sqlite3_session *pSession,      /* Session object */
    ++  int *pnChangeset,               /* OUT: Size of buffer at *ppChangeset */
    ++  void **ppChangeset              /* OUT: Buffer containing changeset */
    ++);
    ++
    ++/*
    ++** CAPI3REF: Load The Difference Between Tables Into A Session 
    ++**
    ++** If it is not already attached to the session object passed as the first
    ++** argument, this function attaches table zTbl in the same manner as the
    ++** [sqlite3session_attach()] function. If zTbl does not exist, or if it
    ++** does not have a primary key, this function is a no-op (but does not return
    ++** an error).
    ++**
    ++** Argument zFromDb must be the name of a database ("main", "temp" etc.)
    ++** attached to the same database handle as the session object that contains 
    ++** a table compatible with the table attached to the session by this function.
    ++** A table is considered compatible if it:
    ++**
    ++** <ul>
    ++**   <li> Has the same name,
    ++**   <li> Has the same set of columns declared in the same order, and
    ++**   <li> Has the same PRIMARY KEY definition.
    ++** </ul>
    ++**
    ++** If the tables are not compatible, SQLITE_SCHEMA is returned. If the tables
    ++** are compatible but do not have any PRIMARY KEY columns, it is not an error
    ++** but no changes are added to the session object. As with other session
    ++** APIs, tables without PRIMARY KEYs are simply ignored.
    ++**
    ++** This function adds a set of changes to the session object that could be
    ++** used to update the table in database zFrom (call this the "from-table") 
    ++** so that its content is the same as the table attached to the session 
    ++** object (call this the "to-table"). Specifically:
    ++**
    ++** <ul>
    ++**   <li> For each row (primary key) that exists in the to-table but not in 
    ++**     the from-table, an INSERT record is added to the session object.
    ++**
    ++**   <li> For each row (primary key) that exists in the to-table but not in 
    ++**     the from-table, a DELETE record is added to the session object.
    ++**
    ++**   <li> For each row (primary key) that exists in both tables, but features 
    ++**     different non-PK values in each, an UPDATE record is added to the
    ++**     session.  
    ++** </ul>
    ++**
    ++** To clarify, if this function is called and then a changeset constructed
    ++** using [sqlite3session_changeset()], then after applying that changeset to 
    ++** database zFrom the contents of the two compatible tables would be 
    ++** identical.
    ++**
    ++** It an error if database zFrom does not exist or does not contain the
    ++** required compatible table.
    ++**
    ++** If the operation successful, SQLITE_OK is returned. Otherwise, an SQLite
    ++** error code. In this case, if argument pzErrMsg is not NULL, *pzErrMsg
    ++** may be set to point to a buffer containing an English language error 
    ++** message. It is the responsibility of the caller to free this buffer using
    ++** sqlite3_free().
    ++*/
    ++SQLITE_API int sqlite3session_diff(
    ++  sqlite3_session *pSession,
    ++  const char *zFromDb,
    ++  const char *zTbl,
    ++  char **pzErrMsg
    ++);
    ++
    ++
    ++/*
    ++** CAPI3REF: Generate A Patchset From A Session Object
    ++**
    ++** The differences between a patchset and a changeset are that:
    ++**
    ++** <ul>
    ++**   <li> DELETE records consist of the primary key fields only. The 
    ++**        original values of other fields are omitted.
    ++**   <li> The original values of any modified fields are omitted from 
    ++**        UPDATE records.
    ++** </ul>
    ++**
    ++** A patchset blob may be used with up to date versions of all 
    ++** sqlite3changeset_xxx API functions except for sqlite3changeset_invert(), 
    ++** which returns SQLITE_CORRUPT if it is passed a patchset. Similarly,
    ++** attempting to use a patchset blob with old versions of the
    ++** sqlite3changeset_xxx APIs also provokes an SQLITE_CORRUPT error. 
    ++**
    ++** Because the non-primary key "old.*" fields are omitted, no 
    ++** SQLITE_CHANGESET_DATA conflicts can be detected or reported if a patchset
    ++** is passed to the sqlite3changeset_apply() API. Other conflict types work
    ++** in the same way as for changesets.
    ++**
    ++** Changes within a patchset are ordered in the same way as for changesets
    ++** generated by the sqlite3session_changeset() function (i.e. all changes for
    ++** a single table are grouped together, tables appear in the order in which
    ++** they were attached to the session object).
    ++*/
    ++SQLITE_API int sqlite3session_patchset(
    ++  sqlite3_session *pSession,      /* Session object */
    ++  int *pnPatchset,                /* OUT: Size of buffer at *ppPatchset */
    ++  void **ppPatchset               /* OUT: Buffer containing patchset */
    ++);
    ++
    ++/*
    ++** CAPI3REF: Test if a changeset has recorded any changes.
    ++**
    ++** Return non-zero if no changes to attached tables have been recorded by 
    ++** the session object passed as the first argument. Otherwise, if one or 
    ++** more changes have been recorded, return zero.
    ++**
    ++** Even if this function returns zero, it is possible that calling
    ++** [sqlite3session_changeset()] on the session handle may still return a
    ++** changeset that contains no changes. This can happen when a row in 
    ++** an attached table is modified and then later on the original values 
    ++** are restored. However, if this function returns non-zero, then it is
    ++** guaranteed that a call to sqlite3session_changeset() will return a 
    ++** changeset containing zero changes.
    ++*/
    ++SQLITE_API int sqlite3session_isempty(sqlite3_session *pSession);
    ++
    ++/*
    ++** CAPI3REF: Create An Iterator To Traverse A Changeset 
    ++**
    ++** Create an iterator used to iterate through the contents of a changeset.
    ++** If successful, *pp is set to point to the iterator handle and SQLITE_OK
    ++** is returned. Otherwise, if an error occurs, *pp is set to zero and an
    ++** SQLite error code is returned.
    ++**
    ++** The following functions can be used to advance and query a changeset 
    ++** iterator created by this function:
    ++**
    ++** <ul>
    ++**   <li> [sqlite3changeset_next()]
    ++**   <li> [sqlite3changeset_op()]
    ++**   <li> [sqlite3changeset_new()]
    ++**   <li> [sqlite3changeset_old()]
    ++** </ul>
    ++**
    ++** It is the responsibility of the caller to eventually destroy the iterator
    ++** by passing it to [sqlite3changeset_finalize()]. The buffer containing the
    ++** changeset (pChangeset) must remain valid until after the iterator is
    ++** destroyed.
    ++**
    ++** Assuming the changeset blob was created by one of the
    ++** [sqlite3session_changeset()], [sqlite3changeset_concat()] or
    ++** [sqlite3changeset_invert()] functions, all changes within the changeset 
    ++** that apply to a single table are grouped together. This means that when 
    ++** an application iterates through a changeset using an iterator created by 
    ++** this function, all changes that relate to a single table are visited 
    ++** consecutively. There is no chance that the iterator will visit a change 
    ++** the applies to table X, then one for table Y, and then later on visit 
    ++** another change for table X.
    ++*/
    ++SQLITE_API int sqlite3changeset_start(
    ++  sqlite3_changeset_iter **pp,    /* OUT: New changeset iterator handle */
    ++  int nChangeset,                 /* Size of changeset blob in bytes */
    ++  void *pChangeset                /* Pointer to blob containing changeset */
    ++);
    ++
    ++
    ++/*
    ++** CAPI3REF: Advance A Changeset Iterator
    ++**
    ++** This function may only be used with iterators created by function
    ++** [sqlite3changeset_start()]. If it is called on an iterator passed to
    ++** a conflict-handler callback by [sqlite3changeset_apply()], SQLITE_MISUSE
    ++** is returned and the call has no effect.
    ++**
    ++** Immediately after an iterator is created by sqlite3changeset_start(), it
    ++** does not point to any change in the changeset. Assuming the changeset
    ++** is not empty, the first call to this function advances the iterator to
    ++** point to the first change in the changeset. Each subsequent call advances
    ++** the iterator to point to the next change in the changeset (if any). If
    ++** no error occurs and the iterator points to a valid change after a call
    ++** to sqlite3changeset_next() has advanced it, SQLITE_ROW is returned. 
    ++** Otherwise, if all changes in the changeset have already been visited,
    ++** SQLITE_DONE is returned.
    ++**
    ++** If an error occurs, an SQLite error code is returned. Possible error 
    ++** codes include SQLITE_CORRUPT (if the changeset buffer is corrupt) or 
    ++** SQLITE_NOMEM.
    ++*/
    ++SQLITE_API int sqlite3changeset_next(sqlite3_changeset_iter *pIter);
    ++
    ++/*
    ++** CAPI3REF: Obtain The Current Operation From A Changeset Iterator
    ++**
    ++** The pIter argument passed to this function may either be an iterator
    ++** passed to a conflict-handler by [sqlite3changeset_apply()], or an iterator
    ++** created by [sqlite3changeset_start()]. In the latter case, the most recent
    ++** call to [sqlite3changeset_next()] must have returned [SQLITE_ROW]. If this
    ++** is not the case, this function returns [SQLITE_MISUSE].
    ++**
    ++** If argument pzTab is not NULL, then *pzTab is set to point to a
    ++** nul-terminated utf-8 encoded string containing the name of the table
    ++** affected by the current change. The buffer remains valid until either
    ++** sqlite3changeset_next() is called on the iterator or until the 
    ++** conflict-handler function returns. If pnCol is not NULL, then *pnCol is 
    ++** set to the number of columns in the table affected by the change. If
    ++** pbIncorrect is not NULL, then *pbIndirect is set to true (1) if the change
    ++** is an indirect change, or false (0) otherwise. See the documentation for
    ++** [sqlite3session_indirect()] for a description of direct and indirect
    ++** changes. Finally, if pOp is not NULL, then *pOp is set to one of 
    ++** [SQLITE_INSERT], [SQLITE_DELETE] or [SQLITE_UPDATE], depending on the 
    ++** type of change that the iterator currently points to.
    ++**
    ++** If no error occurs, SQLITE_OK is returned. If an error does occur, an
    ++** SQLite error code is returned. The values of the output variables may not
    ++** be trusted in this case.
    ++*/
    ++SQLITE_API int sqlite3changeset_op(
    ++  sqlite3_changeset_iter *pIter,  /* Iterator object */
    ++  const char **pzTab,             /* OUT: Pointer to table name */
    ++  int *pnCol,                     /* OUT: Number of columns in table */
    ++  int *pOp,                       /* OUT: SQLITE_INSERT, DELETE or UPDATE */
    ++  int *pbIndirect                 /* OUT: True for an 'indirect' change */
    ++);
    ++
    ++/*
    ++** CAPI3REF: Obtain The Primary Key Definition Of A Table
    ++**
    ++** For each modified table, a changeset includes the following:
    ++**
    ++** <ul>
    ++**   <li> The number of columns in the table, and
    ++**   <li> Which of those columns make up the tables PRIMARY KEY.
    ++** </ul>
    ++**
    ++** This function is used to find which columns comprise the PRIMARY KEY of
    ++** the table modified by the change that iterator pIter currently points to.
    ++** If successful, *pabPK is set to point to an array of nCol entries, where
    ++** nCol is the number of columns in the table. Elements of *pabPK are set to
    ++** 0x01 if the corresponding column is part of the tables primary key, or
    ++** 0x00 if it is not.
    ++**
    ++** If argument pnCol is not NULL, then *pnCol is set to the number of columns
    ++** in the table.
    ++**
    ++** If this function is called when the iterator does not point to a valid
    ++** entry, SQLITE_MISUSE is returned and the output variables zeroed. Otherwise,
    ++** SQLITE_OK is returned and the output variables populated as described
    ++** above.
    ++*/
    ++SQLITE_API int sqlite3changeset_pk(
    ++  sqlite3_changeset_iter *pIter,  /* Iterator object */
    ++  unsigned char **pabPK,          /* OUT: Array of boolean - true for PK cols */
    ++  int *pnCol                      /* OUT: Number of entries in output array */
    ++);
    ++
    ++/*
    ++** CAPI3REF: Obtain old.* Values From A Changeset Iterator
    ++**
    ++** The pIter argument passed to this function may either be an iterator
    ++** passed to a conflict-handler by [sqlite3changeset_apply()], or an iterator
    ++** created by [sqlite3changeset_start()]. In the latter case, the most recent
    ++** call to [sqlite3changeset_next()] must have returned SQLITE_ROW. 
    ++** Furthermore, it may only be called if the type of change that the iterator
    ++** currently points to is either [SQLITE_DELETE] or [SQLITE_UPDATE]. Otherwise,
    ++** this function returns [SQLITE_MISUSE] and sets *ppValue to NULL.
    ++**
    ++** Argument iVal must be greater than or equal to 0, and less than the number
    ++** of columns in the table affected by the current change. Otherwise,
    ++** [SQLITE_RANGE] is returned and *ppValue is set to NULL.
    ++**
    ++** If successful, this function sets *ppValue to point to a protected
    ++** sqlite3_value object containing the iVal'th value from the vector of 
    ++** original row values stored as part of the UPDATE or DELETE change and
    ++** returns SQLITE_OK. The name of the function comes from the fact that this 
    ++** is similar to the "old.*" columns available to update or delete triggers.
    ++**
    ++** If some other error occurs (e.g. an OOM condition), an SQLite error code
    ++** is returned and *ppValue is set to NULL.
    ++*/
    ++SQLITE_API int sqlite3changeset_old(
    ++  sqlite3_changeset_iter *pIter,  /* Changeset iterator */
    ++  int iVal,                       /* Column number */
    ++  sqlite3_value **ppValue         /* OUT: Old value (or NULL pointer) */
    ++);
    ++
    ++/*
    ++** CAPI3REF: Obtain new.* Values From A Changeset Iterator
    ++**
    ++** The pIter argument passed to this function may either be an iterator
    ++** passed to a conflict-handler by [sqlite3changeset_apply()], or an iterator
    ++** created by [sqlite3changeset_start()]. In the latter case, the most recent
    ++** call to [sqlite3changeset_next()] must have returned SQLITE_ROW. 
    ++** Furthermore, it may only be called if the type of change that the iterator
    ++** currently points to is either [SQLITE_UPDATE] or [SQLITE_INSERT]. Otherwise,
    ++** this function returns [SQLITE_MISUSE] and sets *ppValue to NULL.
    ++**
    ++** Argument iVal must be greater than or equal to 0, and less than the number
    ++** of columns in the table affected by the current change. Otherwise,
    ++** [SQLITE_RANGE] is returned and *ppValue is set to NULL.
    ++**
    ++** If successful, this function sets *ppValue to point to a protected
    ++** sqlite3_value object containing the iVal'th value from the vector of 
    ++** new row values stored as part of the UPDATE or INSERT change and
    ++** returns SQLITE_OK. If the change is an UPDATE and does not include
    ++** a new value for the requested column, *ppValue is set to NULL and 
    ++** SQLITE_OK returned. The name of the function comes from the fact that 
    ++** this is similar to the "new.*" columns available to update or delete 
    ++** triggers.
    ++**
    ++** If some other error occurs (e.g. an OOM condition), an SQLite error code
    ++** is returned and *ppValue is set to NULL.
    ++*/
    ++SQLITE_API int sqlite3changeset_new(
    ++  sqlite3_changeset_iter *pIter,  /* Changeset iterator */
    ++  int iVal,                       /* Column number */
    ++  sqlite3_value **ppValue         /* OUT: New value (or NULL pointer) */
    ++);
    ++
    ++/*
    ++** CAPI3REF: Obtain Conflicting Row Values From A Changeset Iterator
    ++**
    ++** This function should only be used with iterator objects passed to a
    ++** conflict-handler callback by [sqlite3changeset_apply()] with either
    ++** [SQLITE_CHANGESET_DATA] or [SQLITE_CHANGESET_CONFLICT]. If this function
    ++** is called on any other iterator, [SQLITE_MISUSE] is returned and *ppValue
    ++** is set to NULL.
    ++**
    ++** Argument iVal must be greater than or equal to 0, and less than the number
    ++** of columns in the table affected by the current change. Otherwise,
    ++** [SQLITE_RANGE] is returned and *ppValue is set to NULL.
    ++**
    ++** If successful, this function sets *ppValue to point to a protected
    ++** sqlite3_value object containing the iVal'th value from the 
    ++** "conflicting row" associated with the current conflict-handler callback
    ++** and returns SQLITE_OK.
    ++**
    ++** If some other error occurs (e.g. an OOM condition), an SQLite error code
    ++** is returned and *ppValue is set to NULL.
    ++*/
    ++SQLITE_API int sqlite3changeset_conflict(
    ++  sqlite3_changeset_iter *pIter,  /* Changeset iterator */
    ++  int iVal,                       /* Column number */
    ++  sqlite3_value **ppValue         /* OUT: Value from conflicting row */
    ++);
    ++
    ++/*
    ++** CAPI3REF: Determine The Number Of Foreign Key Constraint Violations
    ++**
    ++** This function may only be called with an iterator passed to an
    ++** SQLITE_CHANGESET_FOREIGN_KEY conflict handler callback. In this case
    ++** it sets the output variable to the total number of known foreign key
    ++** violations in the destination database and returns SQLITE_OK.
    ++**
    ++** In all other cases this function returns SQLITE_MISUSE.
    ++*/
    ++SQLITE_API int sqlite3changeset_fk_conflicts(
    ++  sqlite3_changeset_iter *pIter,  /* Changeset iterator */
    ++  int *pnOut                      /* OUT: Number of FK violations */
    ++);
    ++
    ++
    ++/*
    ++** CAPI3REF: Finalize A Changeset Iterator
    ++**
    ++** This function is used to finalize an iterator allocated with
    ++** [sqlite3changeset_start()].
    ++**
    ++** This function should only be called on iterators created using the
    ++** [sqlite3changeset_start()] function. If an application calls this
    ++** function with an iterator passed to a conflict-handler by
    ++** [sqlite3changeset_apply()], [SQLITE_MISUSE] is immediately returned and the
    ++** call has no effect.
    ++**
    ++** If an error was encountered within a call to an sqlite3changeset_xxx()
    ++** function (for example an [SQLITE_CORRUPT] in [sqlite3changeset_next()] or an 
    ++** [SQLITE_NOMEM] in [sqlite3changeset_new()]) then an error code corresponding
    ++** to that error is returned by this function. Otherwise, SQLITE_OK is
    ++** returned. This is to allow the following pattern (pseudo-code):
    ++**
    ++**   sqlite3changeset_start();
    ++**   while( SQLITE_ROW==sqlite3changeset_next() ){
    ++**     // Do something with change.
    ++**   }
    ++**   rc = sqlite3changeset_finalize();
    ++**   if( rc!=SQLITE_OK ){
    ++**     // An error has occurred 
    ++**   }
    ++*/
    ++SQLITE_API int sqlite3changeset_finalize(sqlite3_changeset_iter *pIter);
    ++
    ++/*
    ++** CAPI3REF: Invert A Changeset
    ++**
    ++** This function is used to "invert" a changeset object. Applying an inverted
    ++** changeset to a database reverses the effects of applying the uninverted
    ++** changeset. Specifically:
    ++**
    ++** <ul>
    ++**   <li> Each DELETE change is changed to an INSERT, and
    ++**   <li> Each INSERT change is changed to a DELETE, and
    ++**   <li> For each UPDATE change, the old.* and new.* values are exchanged.
    ++** </ul>
    ++**
    ++** This function does not change the order in which changes appear within
    ++** the changeset. It merely reverses the sense of each individual change.
    ++**
    ++** If successful, a pointer to a buffer containing the inverted changeset
    ++** is stored in *ppOut, the size of the same buffer is stored in *pnOut, and
    ++** SQLITE_OK is returned. If an error occurs, both *pnOut and *ppOut are
    ++** zeroed and an SQLite error code returned.
    ++**
    ++** It is the responsibility of the caller to eventually call sqlite3_free()
    ++** on the *ppOut pointer to free the buffer allocation following a successful 
    ++** call to this function.
    ++**
    ++** WARNING/TODO: This function currently assumes that the input is a valid
    ++** changeset. If it is not, the results are undefined.
    ++*/
    ++SQLITE_API int sqlite3changeset_invert(
    ++  int nIn, const void *pIn,       /* Input changeset */
    ++  int *pnOut, void **ppOut        /* OUT: Inverse of input */
    ++);
    ++
    ++/*
    ++** CAPI3REF: Concatenate Two Changeset Objects
    ++**
    ++** This function is used to concatenate two changesets, A and B, into a 
    ++** single changeset. The result is a changeset equivalent to applying
    ++** changeset A followed by changeset B. 
    ++**
    ++** This function combines the two input changesets using an 
    ++** sqlite3_changegroup object. Calling it produces similar results as the
    ++** following code fragment:
    ++**
    ++**   sqlite3_changegroup *pGrp;
    ++**   rc = sqlite3_changegroup_new(&pGrp);
    ++**   if( rc==SQLITE_OK ) rc = sqlite3changegroup_add(pGrp, nA, pA);
    ++**   if( rc==SQLITE_OK ) rc = sqlite3changegroup_add(pGrp, nB, pB);
    ++**   if( rc==SQLITE_OK ){
    ++**     rc = sqlite3changegroup_output(pGrp, pnOut, ppOut);
    ++**   }else{
    ++**     *ppOut = 0;
    ++**     *pnOut = 0;
    ++**   }
    ++**
    ++** Refer to the sqlite3_changegroup documentation below for details.
    ++*/
    ++SQLITE_API int sqlite3changeset_concat(
    ++  int nA,                         /* Number of bytes in buffer pA */
    ++  void *pA,                       /* Pointer to buffer containing changeset A */
    ++  int nB,                         /* Number of bytes in buffer pB */
    ++  void *pB,                       /* Pointer to buffer containing changeset B */
    ++  int *pnOut,                     /* OUT: Number of bytes in output changeset */
    ++  void **ppOut                    /* OUT: Buffer containing output changeset */
    ++);
    ++
    ++
    ++/*
    ++** CAPI3REF: Changegroup Handle
    ++*/
    ++typedef struct sqlite3_changegroup sqlite3_changegroup;
    ++
    ++/*
    ++** CAPI3REF: Create A New Changegroup Object
    ++**
    ++** An sqlite3_changegroup object is used to combine two or more changesets
    ++** (or patchsets) into a single changeset (or patchset). A single changegroup
    ++** object may combine changesets or patchsets, but not both. The output is
    ++** always in the same format as the input.
    ++**
    ++** If successful, this function returns SQLITE_OK and populates (*pp) with
    ++** a pointer to a new sqlite3_changegroup object before returning. The caller
    ++** should eventually free the returned object using a call to 
    ++** sqlite3changegroup_delete(). If an error occurs, an SQLite error code
    ++** (i.e. SQLITE_NOMEM) is returned and *pp is set to NULL.
    ++**
    ++** The usual usage pattern for an sqlite3_changegroup object is as follows:
    ++**
    ++** <ul>
    ++**   <li> It is created using a call to sqlite3changegroup_new().
    ++**
    ++**   <li> Zero or more changesets (or patchsets) are added to the object
    ++**        by calling sqlite3changegroup_add().
    ++**
    ++**   <li> The result of combining all input changesets together is obtained 
    ++**        by the application via a call to sqlite3changegroup_output().
    ++**
    ++**   <li> The object is deleted using a call to sqlite3changegroup_delete().
    ++** </ul>
    ++**
    ++** Any number of calls to add() and output() may be made between the calls to
    ++** new() and delete(), and in any order.
    ++**
    ++** As well as the regular sqlite3changegroup_add() and 
    ++** sqlite3changegroup_output() functions, also available are the streaming
    ++** versions sqlite3changegroup_add_strm() and sqlite3changegroup_output_strm().
    ++*/
    ++SQLITE_API int sqlite3changegroup_new(sqlite3_changegroup **pp);
    ++
    ++/*
    ++** CAPI3REF: Add A Changeset To A Changegroup
    ++**
    ++** Add all changes within the changeset (or patchset) in buffer pData (size
    ++** nData bytes) to the changegroup. 
    ++**
    ++** If the buffer contains a patchset, then all prior calls to this function
    ++** on the same changegroup object must also have specified patchsets. Or, if
    ++** the buffer contains a changeset, so must have the earlier calls to this
    ++** function. Otherwise, SQLITE_ERROR is returned and no changes are added
    ++** to the changegroup.
    ++**
    ++** Rows within the changeset and changegroup are identified by the values in
    ++** their PRIMARY KEY columns. A change in the changeset is considered to
    ++** apply to the same row as a change already present in the changegroup if
    ++** the two rows have the same primary key.
    ++**
    ++** Changes to rows that do not already appear in the changegroup are
    ++** simply copied into it. Or, if both the new changeset and the changegroup
    ++** contain changes that apply to a single row, the final contents of the
    ++** changegroup depends on the type of each change, as follows:
    ++**
    ++** <table border=1 style="margin-left:8ex;margin-right:8ex">
    ++**   <tr><th style="white-space:pre">Existing Change  </th>
    ++**       <th style="white-space:pre">New Change       </th>
    ++**       <th>Output Change
    ++**   <tr><td>INSERT <td>INSERT <td>
    ++**       The new change is ignored. This case does not occur if the new
    ++**       changeset was recorded immediately after the changesets already
    ++**       added to the changegroup.
    ++**   <tr><td>INSERT <td>UPDATE <td>
    ++**       The INSERT change remains in the changegroup. The values in the 
    ++**       INSERT change are modified as if the row was inserted by the
    ++**       existing change and then updated according to the new change.
    ++**   <tr><td>INSERT <td>DELETE <td>
    ++**       The existing INSERT is removed from the changegroup. The DELETE is
    ++**       not added.
    ++**   <tr><td>UPDATE <td>INSERT <td>
    ++**       The new change is ignored. This case does not occur if the new
    ++**       changeset was recorded immediately after the changesets already
    ++**       added to the changegroup.
    ++**   <tr><td>UPDATE <td>UPDATE <td>
    ++**       The existing UPDATE remains within the changegroup. It is amended 
    ++**       so that the accompanying values are as if the row was updated once 
    ++**       by the existing change and then again by the new change.
    ++**   <tr><td>UPDATE <td>DELETE <td>
    ++**       The existing UPDATE is replaced by the new DELETE within the
    ++**       changegroup.
    ++**   <tr><td>DELETE <td>INSERT <td>
    ++**       If one or more of the column values in the row inserted by the
    ++**       new change differ from those in the row deleted by the existing 
    ++**       change, the existing DELETE is replaced by an UPDATE within the
    ++**       changegroup. Otherwise, if the inserted row is exactly the same 
    ++**       as the deleted row, the existing DELETE is simply discarded.
    ++**   <tr><td>DELETE <td>UPDATE <td>
    ++**       The new change is ignored. This case does not occur if the new
    ++**       changeset was recorded immediately after the changesets already
    ++**       added to the changegroup.
    ++**   <tr><td>DELETE <td>DELETE <td>
    ++**       The new change is ignored. This case does not occur if the new
    ++**       changeset was recorded immediately after the changesets already
    ++**       added to the changegroup.
    ++** </table>
    ++**
    ++** If the new changeset contains changes to a table that is already present
    ++** in the changegroup, then the number of columns and the position of the
    ++** primary key columns for the table must be consistent. If this is not the
    ++** case, this function fails with SQLITE_SCHEMA. If the input changeset
    ++** appears to be corrupt and the corruption is detected, SQLITE_CORRUPT is
    ++** returned. Or, if an out-of-memory condition occurs during processing, this
    ++** function returns SQLITE_NOMEM. In all cases, if an error occurs the
    ++** final contents of the changegroup is undefined.
    ++**
    ++** If no error occurs, SQLITE_OK is returned.
    ++*/
    ++SQLITE_API int sqlite3changegroup_add(sqlite3_changegroup*, int nData, void *pData);
    ++
    ++/*
    ++** CAPI3REF: Obtain A Composite Changeset From A Changegroup
    ++**
    ++** Obtain a buffer containing a changeset (or patchset) representing the
    ++** current contents of the changegroup. If the inputs to the changegroup
    ++** were themselves changesets, the output is a changeset. Or, if the
    ++** inputs were patchsets, the output is also a patchset.
    ++**
    ++** As with the output of the sqlite3session_changeset() and
    ++** sqlite3session_patchset() functions, all changes related to a single
    ++** table are grouped together in the output of this function. Tables appear
    ++** in the same order as for the very first changeset added to the changegroup.
    ++** If the second or subsequent changesets added to the changegroup contain
    ++** changes for tables that do not appear in the first changeset, they are
    ++** appended onto the end of the output changeset, again in the order in
    ++** which they are first encountered.
    ++**
    ++** If an error occurs, an SQLite error code is returned and the output
    ++** variables (*pnData) and (*ppData) are set to 0. Otherwise, SQLITE_OK
    ++** is returned and the output variables are set to the size of and a 
    ++** pointer to the output buffer, respectively. In this case it is the
    ++** responsibility of the caller to eventually free the buffer using a
    ++** call to sqlite3_free().
    ++*/
    ++SQLITE_API int sqlite3changegroup_output(
    ++  sqlite3_changegroup*,
    ++  int *pnData,                    /* OUT: Size of output buffer in bytes */
    ++  void **ppData                   /* OUT: Pointer to output buffer */
    ++);
    ++
    ++/*
    ++** CAPI3REF: Delete A Changegroup Object
    ++*/
    ++SQLITE_API void sqlite3changegroup_delete(sqlite3_changegroup*);
    ++
    ++/*
    ++** CAPI3REF: Apply A Changeset To A Database
    ++**
    ++** Apply a changeset to a database. This function attempts to update the
    ++** "main" database attached to handle db with the changes found in the
    ++** changeset passed via the second and third arguments.
    ++**
    ++** The fourth argument (xFilter) passed to this function is the "filter
    ++** callback". If it is not NULL, then for each table affected by at least one
    ++** change in the changeset, the filter callback is invoked with
    ++** the table name as the second argument, and a copy of the context pointer
    ++** passed as the sixth argument to this function as the first. If the "filter
    ++** callback" returns zero, then no attempt is made to apply any changes to 
    ++** the table. Otherwise, if the return value is non-zero or the xFilter
    ++** argument to this function is NULL, all changes related to the table are
    ++** attempted.
    ++**
    ++** For each table that is not excluded by the filter callback, this function 
    ++** tests that the target database contains a compatible table. A table is 
    ++** considered compatible if all of the following are true:
    ++**
    ++** <ul>
    ++**   <li> The table has the same name as the name recorded in the 
    ++**        changeset, and
    ++**   <li> The table has at least as many columns as recorded in the 
    ++**        changeset, and
    ++**   <li> The table has primary key columns in the same position as 
    ++**        recorded in the changeset.
    ++** </ul>
    ++**
    ++** If there is no compatible table, it is not an error, but none of the
    ++** changes associated with the table are applied. A warning message is issued
    ++** via the sqlite3_log() mechanism with the error code SQLITE_SCHEMA. At most
    ++** one such warning is issued for each table in the changeset.
    ++**
    ++** For each change for which there is a compatible table, an attempt is made 
    ++** to modify the table contents according to the UPDATE, INSERT or DELETE 
    ++** change. If a change cannot be applied cleanly, the conflict handler 
    ++** function passed as the fifth argument to sqlite3changeset_apply() may be 
    ++** invoked. A description of exactly when the conflict handler is invoked for 
    ++** each type of change is below.
    ++**
    ++** Unlike the xFilter argument, xConflict may not be passed NULL. The results
    ++** of passing anything other than a valid function pointer as the xConflict
    ++** argument are undefined.
    ++**
    ++** Each time the conflict handler function is invoked, it must return one
    ++** of [SQLITE_CHANGESET_OMIT], [SQLITE_CHANGESET_ABORT] or 
    ++** [SQLITE_CHANGESET_REPLACE]. SQLITE_CHANGESET_REPLACE may only be returned
    ++** if the second argument passed to the conflict handler is either
    ++** SQLITE_CHANGESET_DATA or SQLITE_CHANGESET_CONFLICT. If the conflict-handler
    ++** returns an illegal value, any changes already made are rolled back and
    ++** the call to sqlite3changeset_apply() returns SQLITE_MISUSE. Different 
    ++** actions are taken by sqlite3changeset_apply() depending on the value
    ++** returned by each invocation of the conflict-handler function. Refer to
    ++** the documentation for the three 
    ++** [SQLITE_CHANGESET_OMIT|available return values] for details.
    ++**
    ++** <dl>
    ++** <dt>DELETE Changes<dd>
    ++**   For each DELETE change, this function checks if the target database 
    ++**   contains a row with the same primary key value (or values) as the 
    ++**   original row values stored in the changeset. If it does, and the values 
    ++**   stored in all non-primary key columns also match the values stored in 
    ++**   the changeset the row is deleted from the target database.
    ++**
    ++**   If a row with matching primary key values is found, but one or more of
    ++**   the non-primary key fields contains a value different from the original
    ++**   row value stored in the changeset, the conflict-handler function is
    ++**   invoked with [SQLITE_CHANGESET_DATA] as the second argument. If the
    ++**   database table has more columns than are recorded in the changeset,
    ++**   only the values of those non-primary key fields are compared against
    ++**   the current database contents - any trailing database table columns
    ++**   are ignored.
    ++**
    ++**   If no row with matching primary key values is found in the database,
    ++**   the conflict-handler function is invoked with [SQLITE_CHANGESET_NOTFOUND]
    ++**   passed as the second argument.
    ++**
    ++**   If the DELETE operation is attempted, but SQLite returns SQLITE_CONSTRAINT
    ++**   (which can only happen if a foreign key constraint is violated), the
    ++**   conflict-handler function is invoked with [SQLITE_CHANGESET_CONSTRAINT]
    ++**   passed as the second argument. This includes the case where the DELETE
    ++**   operation is attempted because an earlier call to the conflict handler
    ++**   function returned [SQLITE_CHANGESET_REPLACE].
    ++**
    ++** <dt>INSERT Changes<dd>
    ++**   For each INSERT change, an attempt is made to insert the new row into
    ++**   the database. If the changeset row contains fewer fields than the
    ++**   database table, the trailing fields are populated with their default
    ++**   values.
    ++**
    ++**   If the attempt to insert the row fails because the database already 
    ++**   contains a row with the same primary key values, the conflict handler
    ++**   function is invoked with the second argument set to 
    ++**   [SQLITE_CHANGESET_CONFLICT].
    ++**
    ++**   If the attempt to insert the row fails because of some other constraint
    ++**   violation (e.g. NOT NULL or UNIQUE), the conflict handler function is 
    ++**   invoked with the second argument set to [SQLITE_CHANGESET_CONSTRAINT].
    ++**   This includes the case where the INSERT operation is re-attempted because 
    ++**   an earlier call to the conflict handler function returned 
    ++**   [SQLITE_CHANGESET_REPLACE].
    ++**
    ++** <dt>UPDATE Changes<dd>
    ++**   For each UPDATE change, this function checks if the target database 
    ++**   contains a row with the same primary key value (or values) as the 
    ++**   original row values stored in the changeset. If it does, and the values 
    ++**   stored in all modified non-primary key columns also match the values
    ++**   stored in the changeset the row is updated within the target database.
    ++**
    ++**   If a row with matching primary key values is found, but one or more of
    ++**   the modified non-primary key fields contains a value different from an
    ++**   original row value stored in the changeset, the conflict-handler function
    ++**   is invoked with [SQLITE_CHANGESET_DATA] as the second argument. Since
    ++**   UPDATE changes only contain values for non-primary key fields that are
    ++**   to be modified, only those fields need to match the original values to
    ++**   avoid the SQLITE_CHANGESET_DATA conflict-handler callback.
    ++**
    ++**   If no row with matching primary key values is found in the database,
    ++**   the conflict-handler function is invoked with [SQLITE_CHANGESET_NOTFOUND]
    ++**   passed as the second argument.
    ++**
    ++**   If the UPDATE operation is attempted, but SQLite returns 
    ++**   SQLITE_CONSTRAINT, the conflict-handler function is invoked with 
    ++**   [SQLITE_CHANGESET_CONSTRAINT] passed as the second argument.
    ++**   This includes the case where the UPDATE operation is attempted after 
    ++**   an earlier call to the conflict handler function returned
    ++**   [SQLITE_CHANGESET_REPLACE].  
    ++** </dl>
    ++**
    ++** It is safe to execute SQL statements, including those that write to the
    ++** table that the callback related to, from within the xConflict callback.
    ++** This can be used to further customize the applications conflict
    ++** resolution strategy.
    ++**
    ++** All changes made by this function are enclosed in a savepoint transaction.
    ++** If any other error (aside from a constraint failure when attempting to
    ++** write to the target database) occurs, then the savepoint transaction is
    ++** rolled back, restoring the target database to its original state, and an 
    ++** SQLite error code returned.
    ++*/
    ++SQLITE_API int sqlite3changeset_apply(
    ++  sqlite3 *db,                    /* Apply change to "main" db of this handle */
    ++  int nChangeset,                 /* Size of changeset in bytes */
    ++  void *pChangeset,               /* Changeset blob */
    ++  int(*xFilter)(
    ++    void *pCtx,                   /* Copy of sixth arg to _apply() */
    ++    const char *zTab              /* Table name */
    ++  ),
    ++  int(*xConflict)(
    ++    void *pCtx,                   /* Copy of sixth arg to _apply() */
    ++    int eConflict,                /* DATA, MISSING, CONFLICT, CONSTRAINT */
    ++    sqlite3_changeset_iter *p     /* Handle describing change and conflict */
    ++  ),
    ++  void *pCtx                      /* First argument passed to xConflict */
    ++);
    ++
    ++/* 
    ++** CAPI3REF: Constants Passed To The Conflict Handler
    ++**
    ++** Values that may be passed as the second argument to a conflict-handler.
    ++**
    ++** <dl>
    ++** <dt>SQLITE_CHANGESET_DATA<dd>
    ++**   The conflict handler is invoked with CHANGESET_DATA as the second argument
    ++**   when processing a DELETE or UPDATE change if a row with the required
    ++**   PRIMARY KEY fields is present in the database, but one or more other 
    ++**   (non primary-key) fields modified by the update do not contain the 
    ++**   expected "before" values.
    ++** 
    ++**   The conflicting row, in this case, is the database row with the matching
    ++**   primary key.
    ++** 
    ++** <dt>SQLITE_CHANGESET_NOTFOUND<dd>
    ++**   The conflict handler is invoked with CHANGESET_NOTFOUND as the second
    ++**   argument when processing a DELETE or UPDATE change if a row with the
    ++**   required PRIMARY KEY fields is not present in the database.
    ++** 
    ++**   There is no conflicting row in this case. The results of invoking the
    ++**   sqlite3changeset_conflict() API are undefined.
    ++** 
    ++** <dt>SQLITE_CHANGESET_CONFLICT<dd>
    ++**   CHANGESET_CONFLICT is passed as the second argument to the conflict
    ++**   handler while processing an INSERT change if the operation would result 
    ++**   in duplicate primary key values.
    ++** 
    ++**   The conflicting row in this case is the database row with the matching
    ++**   primary key.
    ++**
    ++** <dt>SQLITE_CHANGESET_FOREIGN_KEY<dd>
    ++**   If foreign key handling is enabled, and applying a changeset leaves the
    ++**   database in a state containing foreign key violations, the conflict 
    ++**   handler is invoked with CHANGESET_FOREIGN_KEY as the second argument
    ++**   exactly once before the changeset is committed. If the conflict handler
    ++**   returns CHANGESET_OMIT, the changes, including those that caused the
    ++**   foreign key constraint violation, are committed. Or, if it returns
    ++**   CHANGESET_ABORT, the changeset is rolled back.
    ++**
    ++**   No current or conflicting row information is provided. The only function
    ++**   it is possible to call on the supplied sqlite3_changeset_iter handle
    ++**   is sqlite3changeset_fk_conflicts().
    ++** 
    ++** <dt>SQLITE_CHANGESET_CONSTRAINT<dd>
    ++**   If any other constraint violation occurs while applying a change (i.e. 
    ++**   a UNIQUE, CHECK or NOT NULL constraint), the conflict handler is 
    ++**   invoked with CHANGESET_CONSTRAINT as the second argument.
    ++** 
    ++**   There is no conflicting row in this case. The results of invoking the
    ++**   sqlite3changeset_conflict() API are undefined.
    ++**
    ++** </dl>
    ++*/
    ++#define SQLITE_CHANGESET_DATA        1
    ++#define SQLITE_CHANGESET_NOTFOUND    2
    ++#define SQLITE_CHANGESET_CONFLICT    3
    ++#define SQLITE_CHANGESET_CONSTRAINT  4
    ++#define SQLITE_CHANGESET_FOREIGN_KEY 5
    ++
    ++/* 
    ++** CAPI3REF: Constants Returned By The Conflict Handler
    ++**
    ++** A conflict handler callback must return one of the following three values.
    ++**
    ++** <dl>
    ++** <dt>SQLITE_CHANGESET_OMIT<dd>
    ++**   If a conflict handler returns this value no special action is taken. The
    ++**   change that caused the conflict is not applied. The session module 
    ++**   continues to the next change in the changeset.
    ++**
    ++** <dt>SQLITE_CHANGESET_REPLACE<dd>
    ++**   This value may only be returned if the second argument to the conflict
    ++**   handler was SQLITE_CHANGESET_DATA or SQLITE_CHANGESET_CONFLICT. If this
    ++**   is not the case, any changes applied so far are rolled back and the 
    ++**   call to sqlite3changeset_apply() returns SQLITE_MISUSE.
    ++**
    ++**   If CHANGESET_REPLACE is returned by an SQLITE_CHANGESET_DATA conflict
    ++**   handler, then the conflicting row is either updated or deleted, depending
    ++**   on the type of change.
    ++**
    ++**   If CHANGESET_REPLACE is returned by an SQLITE_CHANGESET_CONFLICT conflict
    ++**   handler, then the conflicting row is removed from the database and a
    ++**   second attempt to apply the change is made. If this second attempt fails,
    ++**   the original row is restored to the database before continuing.
    ++**
    ++** <dt>SQLITE_CHANGESET_ABORT<dd>
    ++**   If this value is returned, any changes applied so far are rolled back 
    ++**   and the call to sqlite3changeset_apply() returns SQLITE_ABORT.
    ++** </dl>
    ++*/
    ++#define SQLITE_CHANGESET_OMIT       0
    ++#define SQLITE_CHANGESET_REPLACE    1
    ++#define SQLITE_CHANGESET_ABORT      2
    ++
    ++/*
    ++** CAPI3REF: Streaming Versions of API functions.
    ++**
    ++** The six streaming API xxx_strm() functions serve similar purposes to the 
    ++** corresponding non-streaming API functions:
    ++**
    ++** <table border=1 style="margin-left:8ex;margin-right:8ex">
    ++**   <tr><th>Streaming function<th>Non-streaming equivalent</th>
    ++**   <tr><td>sqlite3changeset_apply_strm<td>[sqlite3changeset_apply] 
    ++**   <tr><td>sqlite3changeset_concat_strm<td>[sqlite3changeset_concat] 
    ++**   <tr><td>sqlite3changeset_invert_strm<td>[sqlite3changeset_invert] 
    ++**   <tr><td>sqlite3changeset_start_strm<td>[sqlite3changeset_start] 
    ++**   <tr><td>sqlite3session_changeset_strm<td>[sqlite3session_changeset] 
    ++**   <tr><td>sqlite3session_patchset_strm<td>[sqlite3session_patchset] 
    ++** </table>
    ++**
    ++** Non-streaming functions that accept changesets (or patchsets) as input
    ++** require that the entire changeset be stored in a single buffer in memory. 
    ++** Similarly, those that return a changeset or patchset do so by returning 
    ++** a pointer to a single large buffer allocated using sqlite3_malloc(). 
    ++** Normally this is convenient. However, if an application running in a 
    ++** low-memory environment is required to handle very large changesets, the
    ++** large contiguous memory allocations required can become onerous.
    ++**
    ++** In order to avoid this problem, instead of a single large buffer, input
    ++** is passed to a streaming API functions by way of a callback function that
    ++** the sessions module invokes to incrementally request input data as it is
    ++** required. In all cases, a pair of API function parameters such as
    ++**
    ++**  <pre>
    ++**  &nbsp;     int nChangeset,
    ++**  &nbsp;     void *pChangeset,
    ++**  </pre>
    ++**
    ++** Is replaced by:
    ++**
    ++**  <pre>
    ++**  &nbsp;     int (*xInput)(void *pIn, void *pData, int *pnData),
    ++**  &nbsp;     void *pIn,
    ++**  </pre>
    ++**
    ++** Each time the xInput callback is invoked by the sessions module, the first
    ++** argument passed is a copy of the supplied pIn context pointer. The second 
    ++** argument, pData, points to a buffer (*pnData) bytes in size. Assuming no 
    ++** error occurs the xInput method should copy up to (*pnData) bytes of data 
    ++** into the buffer and set (*pnData) to the actual number of bytes copied 
    ++** before returning SQLITE_OK. If the input is completely exhausted, (*pnData) 
    ++** should be set to zero to indicate this. Or, if an error occurs, an SQLite 
    ++** error code should be returned. In all cases, if an xInput callback returns
    ++** an error, all processing is abandoned and the streaming API function
    ++** returns a copy of the error code to the caller.
    ++**
    ++** In the case of sqlite3changeset_start_strm(), the xInput callback may be
    ++** invoked by the sessions module at any point during the lifetime of the
    ++** iterator. If such an xInput callback returns an error, the iterator enters
    ++** an error state, whereby all subsequent calls to iterator functions 
    ++** immediately fail with the same error code as returned by xInput.
    ++**
    ++** Similarly, streaming API functions that return changesets (or patchsets)
    ++** return them in chunks by way of a callback function instead of via a
    ++** pointer to a single large buffer. In this case, a pair of parameters such
    ++** as:
    ++**
    ++**  <pre>
    ++**  &nbsp;     int *pnChangeset,
    ++**  &nbsp;     void **ppChangeset,
    ++**  </pre>
    ++**
    ++** Is replaced by:
    ++**
    ++**  <pre>
    ++**  &nbsp;     int (*xOutput)(void *pOut, const void *pData, int nData),
    ++**  &nbsp;     void *pOut
    ++**  </pre>
    ++**
    ++** The xOutput callback is invoked zero or more times to return data to
    ++** the application. The first parameter passed to each call is a copy of the
    ++** pOut pointer supplied by the application. The second parameter, pData,
    ++** points to a buffer nData bytes in size containing the chunk of output
    ++** data being returned. If the xOutput callback successfully processes the
    ++** supplied data, it should return SQLITE_OK to indicate success. Otherwise,
    ++** it should return some other SQLite error code. In this case processing
    ++** is immediately abandoned and the streaming API function returns a copy
    ++** of the xOutput error code to the application.
    ++**
    ++** The sessions module never invokes an xOutput callback with the third 
    ++** parameter set to a value less than or equal to zero. Other than this,
    ++** no guarantees are made as to the size of the chunks of data returned.
    ++*/
    ++SQLITE_API int sqlite3changeset_apply_strm(
    ++  sqlite3 *db,                    /* Apply change to "main" db of this handle */
    ++  int (*xInput)(void *pIn, void *pData, int *pnData), /* Input function */
    ++  void *pIn,                                          /* First arg for xInput */
    ++  int(*xFilter)(
    ++    void *pCtx,                   /* Copy of sixth arg to _apply() */
    ++    const char *zTab              /* Table name */
    ++  ),
    ++  int(*xConflict)(
    ++    void *pCtx,                   /* Copy of sixth arg to _apply() */
    ++    int eConflict,                /* DATA, MISSING, CONFLICT, CONSTRAINT */
    ++    sqlite3_changeset_iter *p     /* Handle describing change and conflict */
    ++  ),
    ++  void *pCtx                      /* First argument passed to xConflict */
    ++);
    ++SQLITE_API int sqlite3changeset_concat_strm(
    ++  int (*xInputA)(void *pIn, void *pData, int *pnData),
    ++  void *pInA,
    ++  int (*xInputB)(void *pIn, void *pData, int *pnData),
    ++  void *pInB,
    ++  int (*xOutput)(void *pOut, const void *pData, int nData),
    ++  void *pOut
    ++);
    ++SQLITE_API int sqlite3changeset_invert_strm(
    ++  int (*xInput)(void *pIn, void *pData, int *pnData),
    ++  void *pIn,
    ++  int (*xOutput)(void *pOut, const void *pData, int nData),
    ++  void *pOut
    ++);
    ++SQLITE_API int sqlite3changeset_start_strm(
    ++  sqlite3_changeset_iter **pp,
    ++  int (*xInput)(void *pIn, void *pData, int *pnData),
    ++  void *pIn
    ++);
    ++SQLITE_API int sqlite3session_changeset_strm(
    ++  sqlite3_session *pSession,
    ++  int (*xOutput)(void *pOut, const void *pData, int nData),
    ++  void *pOut
    ++);
    ++SQLITE_API int sqlite3session_patchset_strm(
    ++  sqlite3_session *pSession,
    ++  int (*xOutput)(void *pOut, const void *pData, int nData),
    ++  void *pOut
    ++);
    ++SQLITE_API int sqlite3changegroup_add_strm(sqlite3_changegroup*, 
    ++    int (*xInput)(void *pIn, void *pData, int *pnData),
    ++    void *pIn
    ++);
    ++SQLITE_API int sqlite3changegroup_output_strm(sqlite3_changegroup*,
    ++    int (*xOutput)(void *pOut, const void *pData, int nData), 
    ++    void *pOut
    ++);
    ++
    ++
    ++/*
    ++** Make sure we can call this stuff from C++.
    ++*/
    ++#ifdef __cplusplus
    ++}
    ++#endif
    ++
    ++#endif  /* !defined(__SQLITESESSION_H_) && defined(SQLITE_ENABLE_SESSION) */
    ++
    ++/******** End of sqlite3session.h *********/
    ++/******** Begin file fts5.h *********/
    + /*
    + ** 2014 May 31
    + **
    +@@ -8006,6 +10330,9 @@ struct Fts5PhraseIter {
    + **   an OOM condition or IO error), an appropriate SQLite error code is 
    + **   returned.
    + **
    ++**   This function may be quite inefficient if used with an FTS5 table
    ++**   created with the "columnsize=0" option.
    ++**
    + ** xColumnText:
    + **   This function attempts to retrieve the text of column iCol of the
    + **   current document. If successful, (*pz) is set to point to a buffer
    +@@ -8026,15 +10353,29 @@ struct Fts5PhraseIter {
    + **   the query within the current row. Return SQLITE_OK if successful, or
    + **   an error code (i.e. SQLITE_NOMEM) if an error occurs.
    + **
    ++**   This API can be quite slow if used with an FTS5 table created with the
    ++**   "detail=none" or "detail=column" option. If the FTS5 table is created 
    ++**   with either "detail=none" or "detail=column" and "content=" option 
    ++**   (i.e. if it is a contentless table), then this API always returns 0.
    ++**
    + ** xInst:
    + **   Query for the details of phrase match iIdx within the current row.
    + **   Phrase matches are numbered starting from zero, so the iIdx argument
    + **   should be greater than or equal to zero and smaller than the value
    + **   output by xInstCount().
    + **
    ++**   Usually, output parameter *piPhrase is set to the phrase number, *piCol
    ++**   to the column in which it occurs and *piOff the token offset of the
    ++**   first token of the phrase. The exception is if the table was created
    ++**   with the offsets=0 option specified. In this case *piOff is always
    ++**   set to -1.
    ++**
    + **   Returns SQLITE_OK if successful, or an error code (i.e. SQLITE_NOMEM) 
    + **   if an error occurs.
    + **
    ++**   This API can be quite slow if used with an FTS5 table created with the
    ++**   "detail=none" or "detail=column" option. 
    ++**
    + ** xRowid:
    + **   Returns the rowid of the current row.
    + **
    +@@ -8048,11 +10389,13 @@ struct Fts5PhraseIter {
    + **       ... FROM ftstable WHERE ftstable MATCH $p ORDER BY rowid
    + **
    + **   with $p set to a phrase equivalent to the phrase iPhrase of the
    +-**   current query is executed. For each row visited, the callback function
    +-**   passed as the fourth argument is invoked. The context and API objects 
    +-**   passed to the callback function may be used to access the properties of
    +-**   each matched row. Invoking Api.xUserData() returns a copy of the pointer
    +-**   passed as the third argument to pUserData.
    ++**   current query is executed. Any column filter that applies to
    ++**   phrase iPhrase of the current query is included in $p. For each 
    ++**   row visited, the callback function passed as the fourth argument 
    ++**   is invoked. The context and API objects passed to the callback 
    ++**   function may be used to access the properties of each matched row.
    ++**   Invoking Api.xUserData() returns a copy of the pointer passed as 
    ++**   the third argument to pUserData.
    + **
    + **   If the callback function returns any value other than SQLITE_OK, the
    + **   query is abandoned and the xQueryPhrase function returns immediately.
    +@@ -8118,7 +10461,7 @@ struct Fts5PhraseIter {
    + **       Fts5PhraseIter iter;
    + **       int iCol, iOff;
    + **       for(pApi->xPhraseFirst(pFts, iPhrase, &iter, &iCol, &iOff);
    +-**           iOff>=0;
    ++**           iCol>=0;
    + **           pApi->xPhraseNext(pFts, &iter, &iCol, &iOff)
    + **       ){
    + **         // An instance of phrase iPhrase at offset iOff of column iCol
    +@@ -8126,13 +10469,51 @@ struct Fts5PhraseIter {
    + **
    + **   The Fts5PhraseIter structure is defined above. Applications should not
    + **   modify this structure directly - it should only be used as shown above
    +-**   with the xPhraseFirst() and xPhraseNext() API methods.
    ++**   with the xPhraseFirst() and xPhraseNext() API methods (and by
    ++**   xPhraseFirstColumn() and xPhraseNextColumn() as illustrated below).
    ++**
    ++**   This API can be quite slow if used with an FTS5 table created with the
    ++**   "detail=none" or "detail=column" option. If the FTS5 table is created 
    ++**   with either "detail=none" or "detail=column" and "content=" option 
    ++**   (i.e. if it is a contentless table), then this API always iterates
    ++**   through an empty set (all calls to xPhraseFirst() set iCol to -1).
    + **
    + ** xPhraseNext()
    + **   See xPhraseFirst above.
    ++**
    ++** xPhraseFirstColumn()
    ++**   This function and xPhraseNextColumn() are similar to the xPhraseFirst()
    ++**   and xPhraseNext() APIs described above. The difference is that instead
    ++**   of iterating through all instances of a phrase in the current row, these
    ++**   APIs are used to iterate through the set of columns in the current row
    ++**   that contain one or more instances of a specified phrase. For example:
    ++**
    ++**       Fts5PhraseIter iter;
    ++**       int iCol;
    ++**       for(pApi->xPhraseFirstColumn(pFts, iPhrase, &iter, &iCol);
    ++**           iCol>=0;
    ++**           pApi->xPhraseNextColumn(pFts, &iter, &iCol)
    ++**       ){
    ++**         // Column iCol contains at least one instance of phrase iPhrase
    ++**       }
    ++**
    ++**   This API can be quite slow if used with an FTS5 table created with the
    ++**   "detail=none" option. If the FTS5 table is created with either 
    ++**   "detail=none" "content=" option (i.e. if it is a contentless table), 
    ++**   then this API always iterates through an empty set (all calls to 
    ++**   xPhraseFirstColumn() set iCol to -1).
    ++**
    ++**   The information accessed using this API and its companion
    ++**   xPhraseFirstColumn() may also be obtained using xPhraseFirst/xPhraseNext
    ++**   (or xInst/xInstCount). The chief advantage of this API is that it is
    ++**   significantly more efficient than those alternatives when used with
    ++**   "detail=column" tables.  
    ++**
    ++** xPhraseNextColumn()
    ++**   See xPhraseFirstColumn above.
    + */
    + struct Fts5ExtensionApi {
    +-  int iVersion;                   /* Currently always set to 1 */
    ++  int iVersion;                   /* Currently always set to 3 */
    + 
    +   void *(*xUserData)(Fts5Context*);
    + 
    +@@ -8162,8 +10543,11 @@ struct Fts5ExtensionApi {
    +   int (*xSetAuxdata)(Fts5Context*, void *pAux, void(*xDelete)(void*));
    +   void *(*xGetAuxdata)(Fts5Context*, int bClear);
    + 
    +-  void (*xPhraseFirst)(Fts5Context*, int iPhrase, Fts5PhraseIter*, int*, int*);
    ++  int (*xPhraseFirst)(Fts5Context*, int iPhrase, Fts5PhraseIter*, int*, int*);
    +   void (*xPhraseNext)(Fts5Context*, Fts5PhraseIter*, int *piCol, int *piOff);
    ++
    ++  int (*xPhraseFirstColumn)(Fts5Context*, int iPhrase, Fts5PhraseIter*, int*);
    ++  void (*xPhraseNextColumn)(Fts5Context*, Fts5PhraseIter*, int *piCol);
    + };
    + 
    + /* 
    +@@ -8180,7 +10564,7 @@ struct Fts5ExtensionApi {
    + ** behaviour. The structure methods are expected to function as follows:
    + **
    + ** xCreate:
    +-**   This function is used to allocate and inititalize a tokenizer instance.
    ++**   This function is used to allocate and initialize a tokenizer instance.
    + **   A tokenizer instance is required to actually tokenize text.
    + **
    + **   The first argument passed to this function is a copy of the (void*)
    +@@ -8440,4 +10824,4 @@ struct fts5_api {
    + 
    + #endif /* _FTS5_H */
    + 
    +-
    ++/******** End of fts5.h *********/
    +diff --git a/dist/sqlite3ext.h b/dist/sqlite3ext.h
    +index 017ea30..ac92a74 100644
    +--- a/dist/sqlite3ext.h
    ++++ b/dist/sqlite3ext.h
    +@@ -15,12 +15,10 @@
    + ** as extensions by SQLite should #include this file instead of 
    + ** sqlite3.h.
    + */
    +-#ifndef _SQLITE3EXT_H_
    +-#define _SQLITE3EXT_H_
    ++#ifndef SQLITE3EXT_H
    ++#define SQLITE3EXT_H
    + #include "sqlite3.h"
    + 
    +-typedef struct sqlite3_api_routines sqlite3_api_routines;
    +-
    + /*
    + ** The following structure holds pointers to all of the SQLite API
    + ** routines.
    +@@ -136,7 +134,7 @@ struct sqlite3_api_routines {
    +   int  (*set_authorizer)(sqlite3*,int(*)(void*,int,const char*,const char*,
    +                          const char*,const char*),void*);
    +   void  (*set_auxdata)(sqlite3_context*,int,void*,void (*)(void*));
    +-  char * (*snprintf)(int,char*,const char*,...);
    ++  char * (*xsnprintf)(int,char*,const char*,...);
    +   int  (*step)(sqlite3_stmt*);
    +   int  (*table_column_metadata)(sqlite3*,const char*,const char*,const char*,
    +                                 char const**,char const**,int*,int*,int*);
    +@@ -248,7 +246,7 @@ struct sqlite3_api_routines {
    +   int (*uri_boolean)(const char*,const char*,int);
    +   sqlite3_int64 (*uri_int64)(const char*,const char*,sqlite3_int64);
    +   const char *(*uri_parameter)(const char*,const char*);
    +-  char *(*vsnprintf)(int,char*,const char*,va_list);
    ++  char *(*xvsnprintf)(int,char*,const char*,va_list);
    +   int (*wal_checkpoint_v2)(sqlite3*,const char*,int,int*,int*);
    +   /* Version 3.8.7 and later */
    +   int (*auto_extension)(void(*)(void));
    +@@ -275,8 +273,40 @@ struct sqlite3_api_routines {
    +   /* Version 3.9.0 and later */
    +   unsigned int (*value_subtype)(sqlite3_value*);
    +   void (*result_subtype)(sqlite3_context*,unsigned int);
    ++  /* Version 3.10.0 and later */
    ++  int (*status64)(int,sqlite3_int64*,sqlite3_int64*,int);
    ++  int (*strlike)(const char*,const char*,unsigned int);
    ++  int (*db_cacheflush)(sqlite3*);
    ++  /* Version 3.12.0 and later */
    ++  int (*system_errno)(sqlite3*);
    ++  /* Version 3.14.0 and later */
    ++  int (*trace_v2)(sqlite3*,unsigned,int(*)(unsigned,void*,void*,void*),void*);
    ++  char *(*expanded_sql)(sqlite3_stmt*);
    ++  /* Version 3.18.0 and later */
    ++  void (*set_last_insert_rowid)(sqlite3*,sqlite3_int64);
    ++  /* Version 3.20.0 and later */
    ++  int (*prepare_v3)(sqlite3*,const char*,int,unsigned int,
    ++                    sqlite3_stmt**,const char**);
    ++  int (*prepare16_v3)(sqlite3*,const void*,int,unsigned int,
    ++                      sqlite3_stmt**,const void**);
    ++  int (*bind_pointer)(sqlite3_stmt*,int,void*,const char*,void(*)(void*));
    ++  void (*result_pointer)(sqlite3_context*,void*,const char*,void(*)(void*));
    ++  void *(*value_pointer)(sqlite3_value*,const char*);
    ++  int (*vtab_nochange)(sqlite3_context*);
    ++  int (*value_nochange)(sqlite3_value*);
    ++  const char *(*vtab_collation)(sqlite3_index_info*,int);
    + };
    + 
    ++/*
    ++** This is the function signature used for all extension entry points.  It
    ++** is also defined in the file "loadext.c".
    ++*/
    ++typedef int (*sqlite3_loadext_entry)(
    ++  sqlite3 *db,                       /* Handle to the database. */
    ++  char **pzErrMsg,                   /* Used to set error string on failure. */
    ++  const sqlite3_api_routines *pThunk /* Extension API function pointers. */
    ++);
    ++
    + /*
    + ** The following macros redefine the API routines so that they are
    + ** redirected through the global sqlite3_api structure.
    +@@ -391,7 +421,7 @@ struct sqlite3_api_routines {
    + #define sqlite3_rollback_hook          sqlite3_api->rollback_hook
    + #define sqlite3_set_authorizer         sqlite3_api->set_authorizer
    + #define sqlite3_set_auxdata            sqlite3_api->set_auxdata
    +-#define sqlite3_snprintf               sqlite3_api->snprintf
    ++#define sqlite3_snprintf               sqlite3_api->xsnprintf
    + #define sqlite3_step                   sqlite3_api->step
    + #define sqlite3_table_column_metadata  sqlite3_api->table_column_metadata
    + #define sqlite3_thread_cleanup         sqlite3_api->thread_cleanup
    +@@ -415,7 +445,7 @@ struct sqlite3_api_routines {
    + #define sqlite3_value_text16le         sqlite3_api->value_text16le
    + #define sqlite3_value_type             sqlite3_api->value_type
    + #define sqlite3_vmprintf               sqlite3_api->vmprintf
    +-#define sqlite3_vsnprintf              sqlite3_api->vsnprintf
    ++#define sqlite3_vsnprintf              sqlite3_api->xvsnprintf
    + #define sqlite3_overload_function      sqlite3_api->overload_function
    + #define sqlite3_prepare_v2             sqlite3_api->prepare_v2
    + #define sqlite3_prepare16_v2           sqlite3_api->prepare16_v2
    +@@ -491,7 +521,7 @@ struct sqlite3_api_routines {
    + #define sqlite3_uri_boolean            sqlite3_api->uri_boolean
    + #define sqlite3_uri_int64              sqlite3_api->uri_int64
    + #define sqlite3_uri_parameter          sqlite3_api->uri_parameter
    +-#define sqlite3_uri_vsnprintf          sqlite3_api->vsnprintf
    ++#define sqlite3_uri_vsnprintf          sqlite3_api->xvsnprintf
    + #define sqlite3_wal_checkpoint_v2      sqlite3_api->wal_checkpoint_v2
    + /* Version 3.8.7 and later */
    + #define sqlite3_auto_extension         sqlite3_api->auto_extension
    +@@ -514,6 +544,27 @@ struct sqlite3_api_routines {
    + /* Version 3.9.0 and later */
    + #define sqlite3_value_subtype          sqlite3_api->value_subtype
    + #define sqlite3_result_subtype         sqlite3_api->result_subtype
    ++/* Version 3.10.0 and later */
    ++#define sqlite3_status64               sqlite3_api->status64
    ++#define sqlite3_strlike                sqlite3_api->strlike
    ++#define sqlite3_db_cacheflush          sqlite3_api->db_cacheflush
    ++/* Version 3.12.0 and later */
    ++#define sqlite3_system_errno           sqlite3_api->system_errno
    ++/* Version 3.14.0 and later */
    ++#define sqlite3_trace_v2               sqlite3_api->trace_v2
    ++#define sqlite3_expanded_sql           sqlite3_api->expanded_sql
    ++/* Version 3.18.0 and later */
    ++#define sqlite3_set_last_insert_rowid  sqlite3_api->set_last_insert_rowid
    ++/* Version 3.20.0 and later */
    ++#define sqlite3_prepare_v3             sqlite3_api->prepare_v3
    ++#define sqlite3_prepare16_v3           sqlite3_api->prepare16_v3
    ++#define sqlite3_bind_pointer           sqlite3_api->bind_pointer
    ++#define sqlite3_result_pointer         sqlite3_api->result_pointer
    ++#define sqlite3_value_pointer          sqlite3_api->value_pointer
    ++/* Version 3.22.0 and later */
    ++#define sqlite3_vtab_nochange          sqlite3_api->vtab_nochange
    ++#define sqlite3_value_nochange         sqltie3_api->value_nochange
    ++#define sqlite3_vtab_collation         sqltie3_api->vtab_collation
    + #endif /* !defined(SQLITE_CORE) && !defined(SQLITE_OMIT_LOAD_EXTENSION) */
    + 
    + #if !defined(SQLITE_CORE) && !defined(SQLITE_OMIT_LOAD_EXTENSION)
    +@@ -531,4 +582,4 @@ struct sqlite3_api_routines {
    + # define SQLITE_EXTENSION_INIT3     /*no-op*/
    + #endif
    + 
    +-#endif /* _SQLITE3EXT_H_ */
    ++#endif /* SQLITE3EXT_H */
     diff --git a/dist/version b/dist/version
     deleted file mode 100644
     index 6fadefa..0000000
    diff --git a/frameworks_av.patch b/frameworks_av.patch
    index a0b96e8..143900b 100644
    --- a/frameworks_av.patch
    +++ b/frameworks_av.patch
    @@ -396,23 +396,1362 @@ index 9823c5516..cb4be7503 100644
                      cmd->vsize, cmd->data + sizeof(int32_t));
              break;
     diff --git a/media/libeffects/lvm/wrapper/Bundle/EffectBundle.cpp b/media/libeffects/lvm/wrapper/Bundle/EffectBundle.cpp
    -index dcf3fa0a5..07ea8187c 100644
    +index dcf3fa0a5..8a248e50c 100644
     --- a/media/libeffects/lvm/wrapper/Bundle/EffectBundle.cpp
     +++ b/media/libeffects/lvm/wrapper/Bundle/EffectBundle.cpp
    -@@ -2439,6 +2439,13 @@ int Equalizer_getParameter(EffectContext     *pContext,
    +@@ -33,6 +33,15 @@
    + // effect_handle_t interface implementation for bass boost
    + extern "C" const struct effect_interface_s gLvmEffectInterface;
    + 
    ++// Turn on VERY_VERY_VERBOSE_LOGGING to log parameter get and set for effects.
    ++
    ++//#define VERY_VERY_VERBOSE_LOGGING
    ++#ifdef VERY_VERY_VERBOSE_LOGGING
    ++#define ALOGVV ALOGV
    ++#else
    ++#define ALOGVV(a...) do { } while (false)
    ++#endif
    ++
    + #define LVM_ERROR_CHECK(LvmStatus, callingFunc, calledFunc){\
    +         if (LvmStatus == LVM_NULLADDRESS){\
    +             ALOGV("\tLVM_ERROR : Parameter error - "\
    +@@ -138,26 +147,43 @@ int  LvmEffect_disable         (EffectContext *pContext);
    + void LvmEffect_free            (EffectContext *pContext);
    + int  Effect_setConfig          (EffectContext *pContext, effect_config_t *pConfig);
    + void Effect_getConfig          (EffectContext *pContext, effect_config_t *pConfig);
    +-int  BassBoost_setParameter    (EffectContext *pContext, void *pParam, void *pValue);
    ++int  BassBoost_setParameter    (EffectContext *pContext,
    ++                                uint32_t       paramSize,
    ++                                void          *pParam,
    ++                                uint32_t       valueSize,
    ++                                void          *pValue);
    + int  BassBoost_getParameter    (EffectContext *pContext,
    +-                               void           *pParam,
    +-                               uint32_t       *pValueSize,
    +-                               void           *pValue);
    +-int  Virtualizer_setParameter  (EffectContext *pContext, void *pParam, void *pValue);
    ++                                uint32_t       paramSize,
    ++                                void          *pParam,
    ++                                uint32_t      *pValueSize,
    ++                                void          *pValue);
    ++int  Virtualizer_setParameter  (EffectContext *pContext,
    ++                                uint32_t       paramSize,
    ++                                void          *pParam,
    ++                                uint32_t       valueSize,
    ++                                void          *pValue);
    + int  Virtualizer_getParameter  (EffectContext *pContext,
    +-                               void           *pParam,
    +-                               uint32_t       *pValueSize,
    +-                               void           *pValue);
    ++                                uint32_t       paramSize,
    ++                                void          *pParam,
    ++                                uint32_t      *pValueSize,
    ++                                void          *pValue);
    + int  Equalizer_setParameter    (EffectContext *pContext,
    +-                               void *pParam,
    +-                               uint32_t valueSize,
    +-                               void *pValue);
    ++                                uint32_t       paramSize,
    ++                                void          *pParam,
    ++                                uint32_t       valueSize,
    ++                                void          *pValue);
    + int  Equalizer_getParameter    (EffectContext *pContext,
    ++                                uint32_t       paramSize,
    +                                 void          *pParam,
    +                                 uint32_t      *pValueSize,
    +                                 void          *pValue);
    +-int  Volume_setParameter       (EffectContext *pContext, void *pParam, void *pValue);
    ++int  Volume_setParameter       (EffectContext *pContext,
    ++                                uint32_t       paramSize,
    ++                                void          *pParam,
    ++                                uint32_t       valueSize,
    ++                                void          *pValue);
    + int  Volume_getParameter       (EffectContext *pContext,
    ++                                uint32_t       paramSize,
    +                                 void          *pParam,
    +                                 uint32_t      *pValueSize,
    +                                 void          *pValue);
    +@@ -2011,61 +2037,54 @@ int32_t VolumeEnableStereoPosition(EffectContext *pContext, uint32_t enabled){
    + //
    + //----------------------------------------------------------------------------
    + 
    +-int BassBoost_getParameter(EffectContext     *pContext,
    +-                           void              *pParam,
    +-                           uint32_t          *pValueSize,
    +-                           void              *pValue){
    ++int BassBoost_getParameter(EffectContext *pContext,
    ++                           uint32_t       paramSize,
    ++                           void          *pParam,
    ++                           uint32_t      *pValueSize,
    ++                           void          *pValue) {
    +     int status = 0;
    +-    int32_t *pParamTemp = (int32_t *)pParam;
    +-    int32_t param = *pParamTemp++;
    +-    int32_t param2;
    +-    char *name;
    ++    int32_t *params = (int32_t *)pParam;
    + 
    +-    //ALOGV("\tBassBoost_getParameter start");
    ++    ALOGVV("%s start", __func__);
    + 
    +-    switch (param){
    ++    if (paramSize < sizeof(int32_t)) {
    ++        ALOGV("%s invalid paramSize: %u", __func__, paramSize);
    ++        return -EINVAL;
    ++    }
    ++    switch (params[0]) {
    +         case BASSBOOST_PARAM_STRENGTH_SUPPORTED:
    +-            if (*pValueSize != sizeof(uint32_t)){
    +-                ALOGV("\tLVM_ERROR : BassBoost_getParameter() invalid pValueSize1 %d", *pValueSize);
    +-                return -EINVAL;
    +-            }
    +-            *pValueSize = sizeof(uint32_t);
    +-            break;
    +-        case BASSBOOST_PARAM_STRENGTH:
    +-            if (*pValueSize != sizeof(int16_t)){
    +-                ALOGV("\tLVM_ERROR : BassBoost_getParameter() invalid pValueSize2 %d", *pValueSize);
    +-                return -EINVAL;
    ++            if (*pValueSize != sizeof(uint32_t)) {  // legacy: check equality here.
    ++                ALOGV("%s BASSBOOST_PARAM_STRENGTH_SUPPORTED invalid *pValueSize %u",
    ++                        __func__, *pValueSize);
    ++                status = -EINVAL;
    ++                break;
                  }
    +-            *pValueSize = sizeof(int16_t);
    +-            break;
    ++            // no need to set *pValueSize
    + 
    +-        default:
    +-            ALOGV("\tLVM_ERROR : BassBoost_getParameter() invalid param %d", param);
    +-            return -EINVAL;
    +-    }
    +-
    +-    switch (param){
    +-        case BASSBOOST_PARAM_STRENGTH_SUPPORTED:
    +             *(uint32_t *)pValue = 1;
    +-
    +-            //ALOGV("\tBassBoost_getParameter() BASSBOOST_PARAM_STRENGTH_SUPPORTED Value is %d",
    +-            //        *(uint32_t *)pValue);
    ++            ALOGVV("%s BASSBOOST_PARAM_STRENGTH_SUPPORTED %u", __func__, *(uint32_t *)pValue);
                  break;
    + 
    +         case BASSBOOST_PARAM_STRENGTH:
    +-            *(int16_t *)pValue = BassGetStrength(pContext);
    ++            if (*pValueSize != sizeof(int16_t)) {  // legacy: check equality here.
    ++                ALOGV("%s BASSBOOST_PARAM_STRENGTH invalid *pValueSize %u",
    ++                        __func__, *pValueSize);
    ++                status = -EINVAL;
    ++                break;
    ++            }
    ++            // no need to set *pValueSize
    + 
    +-            //ALOGV("\tBassBoost_getParameter() BASSBOOST_PARAM_STRENGTH Value is %d",
    +-            //        *(int16_t *)pValue);
    ++            *(int16_t *)pValue = BassGetStrength(pContext);
    ++            ALOGVV("%s BASSBOOST_PARAM_STRENGTH %d", __func__, *(int16_t *)pValue);
    +             break;
    + 
    +         default:
    +-            ALOGV("\tLVM_ERROR : BassBoost_getParameter() invalid param %d", param);
    ++            ALOGV("%s invalid param %d", __func__, params[0]);
    +             status = -EINVAL;
    +             break;
    +     }
    + 
    +-    //ALOGV("\tBassBoost_getParameter end");
    ++    ALOGVV("%s end param: %d, status: %d", __func__, params[0], status);
    +     return status;
    + } /* end BassBoost_getParameter */
    + 
    +@@ -2084,27 +2103,42 @@ int BassBoost_getParameter(EffectContext     *pContext,
    + //
    + //----------------------------------------------------------------------------
    + 
    +-int BassBoost_setParameter (EffectContext *pContext, void *pParam, void *pValue){
    ++int BassBoost_setParameter(EffectContext *pContext,
    ++                           uint32_t       paramSize,
    ++                           void          *pParam,
    ++                           uint32_t       valueSize,
    ++                           void          *pValue) {
    +     int status = 0;
    +-    int16_t strength;
    +-    int32_t *pParamTemp = (int32_t *)pParam;
    ++    int32_t *params = (int32_t *)pParam;
    + 
    +-    //ALOGV("\tBassBoost_setParameter start");
    ++    ALOGVV("%s start", __func__);
    + 
    +-    switch (*pParamTemp){
    +-        case BASSBOOST_PARAM_STRENGTH:
    +-            strength = *(int16_t *)pValue;
    +-            //ALOGV("\tBassBoost_setParameter() BASSBOOST_PARAM_STRENGTH value is %d", strength);
    +-            //ALOGV("\tBassBoost_setParameter() Calling pBassBoost->BassSetStrength");
    ++    if (paramSize != sizeof(int32_t)) {  // legacy: check equality here.
    ++        ALOGV("%s invalid paramSize: %u", __func__, paramSize);
    ++        return -EINVAL;
    ++    }
    ++    switch (params[0]) {
    ++        case BASSBOOST_PARAM_STRENGTH: {
    ++            if (valueSize < sizeof(int16_t)) {
    ++                ALOGV("%s BASSBOOST_PARAM_STRENGTH invalid valueSize: %u", __func__, valueSize);
    ++                status = -EINVAL;
    ++                break;
    ++            }
    ++
    ++            const int16_t strength = *(int16_t *)pValue;
    ++            ALOGVV("%s BASSBOOST_PARAM_STRENGTH %d", __func__, strength);
    ++            ALOGVV("%s BASSBOOST_PARAM_STRENGTH Calling BassSetStrength", __func__);
    +             BassSetStrength(pContext, (int32_t)strength);
    +-            //ALOGV("\tBassBoost_setParameter() Called pBassBoost->BassSetStrength");
    +-           break;
    ++            ALOGVV("%s BASSBOOST_PARAM_STRENGTH Called BassSetStrength", __func__);
    ++        } break;
    ++
    +         default:
    +-            ALOGV("\tLVM_ERROR : BassBoost_setParameter() invalid param %d", *pParamTemp);
    ++            ALOGV("%s invalid param %d", __func__, params[0]);
    ++            status = -EINVAL;
    +             break;
    +     }
    + 
    +-    //ALOGV("\tBassBoost_setParameter end");
    ++    ALOGVV("%s end param: %d, status: %d", __func__, params[0], status);
    +     return status;
    + } /* end BassBoost_setParameter */
    + 
    +@@ -2129,93 +2163,97 @@ int BassBoost_setParameter (EffectContext *pContext, void *pParam, void *pValue)
    + //
    + //----------------------------------------------------------------------------
    + 
    +-int Virtualizer_getParameter(EffectContext        *pContext,
    +-                             void                 *pParam,
    +-                             uint32_t             *pValueSize,
    +-                             void                 *pValue){
    ++int Virtualizer_getParameter(EffectContext *pContext,
    ++                             uint32_t       paramSize,
    ++                             void          *pParam,
    ++                             uint32_t      *pValueSize,
    ++                             void          *pValue) {
    +     int status = 0;
    +-    int32_t *pParamTemp = (int32_t *)pParam;
    +-    int32_t param = *pParamTemp++;
    +-    char *name;
    ++    int32_t *params = (int32_t *)pParam;
    + 
    +-    //ALOGV("\tVirtualizer_getParameter start");
    ++    ALOGVV("%s start", __func__);
    + 
    +-    switch (param){
    ++    if (paramSize < sizeof(int32_t)) {
    ++        ALOGV("%s invalid paramSize: %u", __func__, paramSize);
    ++        return -EINVAL;
    ++    }
    ++    switch (params[0]) {
    +         case VIRTUALIZER_PARAM_STRENGTH_SUPPORTED:
    +-            if (*pValueSize != sizeof(uint32_t)){
    +-                ALOGV("\tLVM_ERROR : Virtualizer_getParameter() invalid pValueSize %d",*pValueSize);
    +-                return -EINVAL;
    +-            }
    +-            *pValueSize = sizeof(uint32_t);
    +-            break;
    +-        case VIRTUALIZER_PARAM_STRENGTH:
    +-            if (*pValueSize != sizeof(int16_t)){
    +-                ALOGV("\tLVM_ERROR : Virtualizer_getParameter() invalid pValueSize2 %d",*pValueSize);
    +-                return -EINVAL;
    +-            }
    +-            *pValueSize = sizeof(int16_t);
    +-            break;
    +-        case VIRTUALIZER_PARAM_VIRTUAL_SPEAKER_ANGLES:
    +-            // return value size can only be interpreted as relative to input value,
    +-            // deferring validity check to below
    +-            break;
    +-        case VIRTUALIZER_PARAM_VIRTUALIZATION_MODE:
    +-            if (*pValueSize != sizeof(uint32_t)){
    +-                ALOGV("\tLVM_ERROR : Virtualizer_getParameter() invalid pValueSize %d",*pValueSize);
    +-                return -EINVAL;
    ++            if (*pValueSize != sizeof(uint32_t)) { // legacy: check equality here.
    ++                ALOGV("%s VIRTUALIZER_PARAM_STRENGTH_SUPPORTED invalid *pValueSize %u",
    ++                        __func__, *pValueSize);
    ++                status = -EINVAL;
    ++                break;
    +             }
    +-            *pValueSize = sizeof(uint32_t);
    +-            break;
    +-        default:
    +-            ALOGV("\tLVM_ERROR : Virtualizer_getParameter() invalid param %d", param);
    +-            return -EINVAL;
    +-    }
    ++            // no need to set *pValueSize
    + 
    +-    switch (param){
    +-        case VIRTUALIZER_PARAM_STRENGTH_SUPPORTED:
    +             *(uint32_t *)pValue = 1;
    +-
    +-            //ALOGV("\tVirtualizer_getParameter() VIRTUALIZER_PARAM_STRENGTH_SUPPORTED Value is %d",
    +-            //        *(uint32_t *)pValue);
    ++            ALOGVV("%s VIRTUALIZER_PARAM_STRENGTH_SUPPORTED %d", __func__, *(uint32_t *)pValue);
    +             break;
    + 
    +         case VIRTUALIZER_PARAM_STRENGTH:
    ++            if (*pValueSize != sizeof(int16_t)) { // legacy: check equality here.
    ++                ALOGV("%s VIRTUALIZER_PARAM_STRENGTH invalid *pValueSize %u",
    ++                        __func__, *pValueSize);
    ++                status = -EINVAL;
    ++                break;
    ++            }
    ++            // no need to set *pValueSize
    ++
    +             *(int16_t *)pValue = VirtualizerGetStrength(pContext);
    + 
    +-            //ALOGV("\tVirtualizer_getParameter() VIRTUALIZER_PARAM_STRENGTH Value is %d",
    +-            //        *(int16_t *)pValue);
    ++            ALOGVV("%s VIRTUALIZER_PARAM_STRENGTH %d", __func__, *(int16_t *)pValue);
    +             break;
    + 
    +         case VIRTUALIZER_PARAM_VIRTUAL_SPEAKER_ANGLES: {
    +-            const audio_channel_mask_t channelMask = (audio_channel_mask_t) *pParamTemp++;
    +-            const audio_devices_t deviceType = (audio_devices_t) *pParamTemp;
    +-            uint32_t nbChannels = audio_channel_count_from_out_mask(channelMask);
    +-            if (*pValueSize < 3 * nbChannels * sizeof(int32_t)){
    +-                ALOGV("\tLVM_ERROR : Virtualizer_getParameter() invalid pValueSize %d",*pValueSize);
    +-                return -EINVAL;
    ++            if (paramSize < 3 * sizeof(int32_t)) {
    ++                ALOGV("%s VIRTUALIZER_PARAM_SPEAKER_ANGLES invalid paramSize: %u",
    ++                        __func__, paramSize);
    ++                status = -EINVAL;
    ++                break;
    ++            }
    ++
    ++            const audio_channel_mask_t channelMask = (audio_channel_mask_t) params[1];
    ++            const audio_devices_t deviceType = (audio_devices_t) params[2];
    ++            const uint32_t nbChannels = audio_channel_count_from_out_mask(channelMask);
    ++            const uint32_t valueSizeRequired = 3 * nbChannels * sizeof(int32_t);
    ++            if (*pValueSize < valueSizeRequired) {
    ++                ALOGV("%s VIRTUALIZER_PARAM_SPEAKER_ANGLES invalid *pValueSize %u",
    ++                        __func__, *pValueSize);
    ++                status = -EINVAL;
    ++                break;
    +             }
    ++            *pValueSize = valueSizeRequired;
    ++
    +             // verify the configuration is supported
    +             status = VirtualizerIsConfigurationSupported(channelMask, deviceType);
    +             if (status == 0) {
    +-                ALOGV("VIRTUALIZER_PARAM_VIRTUAL_SPEAKER_ANGLES supports mask=0x%x device=0x%x",
    +-                        channelMask, deviceType);
    ++                ALOGV("%s VIRTUALIZER_PARAM_VIRTUAL_SPEAKER_ANGLES mask=0x%x device=0x%x",
    ++                        __func__, channelMask, deviceType);
    +                 // configuration is supported, get the angles
    +                 VirtualizerGetSpeakerAngles(channelMask, deviceType, (int32_t *)pValue);
    +             }
    +-            }
    +-            break;
    ++        } break;
    + 
    +         case VIRTUALIZER_PARAM_VIRTUALIZATION_MODE:
    +-            *(uint32_t *)pValue  = (uint32_t) VirtualizerGetVirtualizationMode(pContext);
    ++            if (*pValueSize != sizeof(uint32_t)) { // legacy: check equality here.
    ++                ALOGV("%s VIRTUALIZER_PARAM_VIRTUALIZATION_MODE invalid *pValueSize %u",
    ++                        __func__, *pValueSize);
    ++                status = -EINVAL;
    ++                break;
    ++            }
    ++            // no need to set *pValueSize
    ++
    ++            *(uint32_t *)pValue = (uint32_t) VirtualizerGetVirtualizationMode(pContext);
    +             break;
    + 
    +         default:
    +-            ALOGV("\tLVM_ERROR : Virtualizer_getParameter() invalid param %d", param);
    ++            ALOGV("%s invalid param %d", __func__, params[0]);
    +             status = -EINVAL;
    +             break;
    +     }
    + 
    +-    ALOGV("\tVirtualizer_getParameter end returning status=%d", status);
    ++    ALOGVV("%s end param: %d, status: %d", __func__, params[0], status);
    +     return status;
    + } /* end Virtualizer_getParameter */
    + 
    +@@ -2234,37 +2272,57 @@ int Virtualizer_getParameter(EffectContext        *pContext,
    + //
    + //----------------------------------------------------------------------------
    + 
    +-int Virtualizer_setParameter (EffectContext *pContext, void *pParam, void *pValue){
    ++int Virtualizer_setParameter(EffectContext *pContext,
    ++                             uint32_t       paramSize,
    ++                             void          *pParam,
    ++                             uint32_t       valueSize,
    ++                             void          *pValue) {
    +     int status = 0;
    +-    int16_t strength;
    +-    int32_t *pParamTemp = (int32_t *)pParam;
    +-    int32_t param = *pParamTemp++;
    ++    int32_t *params = (int32_t *)pParam;
    + 
    +-    //ALOGV("\tVirtualizer_setParameter start");
    ++    ALOGVV("%s start", __func__);
    + 
    +-    switch (param){
    +-        case VIRTUALIZER_PARAM_STRENGTH:
    +-            strength = *(int16_t *)pValue;
    +-            //ALOGV("\tVirtualizer_setParameter() VIRTUALIZER_PARAM_STRENGTH value is %d", strength);
    +-            //ALOGV("\tVirtualizer_setParameter() Calling pVirtualizer->setStrength");
    ++    if (paramSize != sizeof(int32_t)) { // legacy: check equality here.
    ++        ALOGV("%s invalid paramSize: %u", __func__, paramSize);
    ++        return -EINVAL;
    ++    }
    ++    switch (params[0]) {
    ++        case VIRTUALIZER_PARAM_STRENGTH: {
    ++            if (valueSize < sizeof(int16_t)) {
    ++                ALOGV("%s VIRTUALIZER_PARAM_STRENGTH invalid valueSize: %u", __func__, valueSize);
    ++                status = -EINVAL;
    ++                break;
    ++            }
    ++
    ++            const int16_t strength = *(int16_t *)pValue;
    ++            ALOGVV("%s VIRTUALIZER_PARAM_STRENGTH %d", __func__, strength);
    ++            ALOGVV("%s VIRTUALIZER_PARAM_STRENGTH Calling VirtualizerSetStrength", __func__);
    +             VirtualizerSetStrength(pContext, (int32_t)strength);
    +-            //ALOGV("\tVirtualizer_setParameter() Called pVirtualizer->setStrength");
    +-           break;
    ++            ALOGVV("%s VIRTUALIZER_PARAM_STRENGTH Called VirtualizerSetStrength", __func__);
    ++        } break;
    + 
    +         case VIRTUALIZER_PARAM_FORCE_VIRTUALIZATION_MODE: {
    +-            const audio_devices_t deviceType = *(audio_devices_t *) pValue;
    +-            status = VirtualizerForceVirtualizationMode(pContext, deviceType);
    +-            //ALOGV("VIRTUALIZER_PARAM_FORCE_VIRTUALIZATION_MODE device=0x%x result=%d",
    +-            //        deviceType, status);
    ++            if (valueSize < sizeof(int32_t)) {
    ++                ALOGV("%s VIRTUALIZER_PARAM_FORCE_VIRTUALIZATION_MODE invalid valueSize: %u",
    ++                        __func__, valueSize);
    ++                android_errorWriteLog(0x534e4554, "64478003");
    ++                status = -EINVAL;
    ++                break;
    +             }
    +-            break;
    ++
    ++            const audio_devices_t deviceType = (audio_devices_t)*(int32_t *)pValue;
    ++            status = VirtualizerForceVirtualizationMode(pContext, deviceType);
    ++            ALOGVV("%s VIRTUALIZER_PARAM_FORCE_VIRTUALIZATION_MODE device=%#x result=%d",
    ++                    __func__, deviceType, status);
    ++        } break;
    + 
    +         default:
    +-            ALOGV("\tLVM_ERROR : Virtualizer_setParameter() invalid param %d", param);
    ++            ALOGV("%s invalid param %d", __func__, params[0]);
    ++            status = -EINVAL;
    +             break;
    +     }
    + 
    +-    //ALOGV("\tVirtualizer_setParameter end");
    ++    ALOGVV("%s end param: %d, status: %d", __func__, params[0], status);
    +     return status;
    + } /* end Virtualizer_setParameter */
    + 
    +@@ -2288,168 +2346,215 @@ int Virtualizer_setParameter (EffectContext *pContext, void *pParam, void *pValu
    + // Side Effects:
    + //
    + //----------------------------------------------------------------------------
    +-int Equalizer_getParameter(EffectContext     *pContext,
    +-                           void              *pParam,
    +-                           uint32_t          *pValueSize,
    +-                           void              *pValue){
    ++int Equalizer_getParameter(EffectContext *pContext,
    ++                           uint32_t       paramSize,
    ++                           void          *pParam,
    ++                           uint32_t      *pValueSize,
    ++                           void          *pValue) {
    +     int status = 0;
    +-    int bMute = 0;
    +-    int32_t *pParamTemp = (int32_t *)pParam;
    +-    int32_t param = *pParamTemp++;
    +-    int32_t param2;
    +-    char *name;
    ++    int32_t *params = (int32_t *)pParam;
    + 
    +-    //ALOGV("\tEqualizer_getParameter start");
    ++    ALOGVV("%s start", __func__);
    + 
    +-    switch (param) {
    ++    if (paramSize < sizeof(int32_t)) {
    ++        ALOGV("%s invalid paramSize: %u", __func__, paramSize);
    ++        return -EINVAL;
    ++    }
    ++    switch (params[0]) {
    +     case EQ_PARAM_NUM_BANDS:
    +-    case EQ_PARAM_CUR_PRESET:
    +-    case EQ_PARAM_GET_NUM_OF_PRESETS:
    +-    case EQ_PARAM_BAND_LEVEL:
    +-    case EQ_PARAM_GET_BAND:
    +-        if (*pValueSize < sizeof(int16_t)) {
    +-            ALOGV("\tLVM_ERROR : Equalizer_getParameter() invalid pValueSize 1  %d", *pValueSize);
    +-            return -EINVAL;
    ++        if (*pValueSize < sizeof(uint16_t)) {
    ++            ALOGV("%s EQ_PARAM_NUM_BANDS invalid *pValueSize %u", __func__, *pValueSize);
    ++            status = -EINVAL;
    ++            break;
              }
    +-        *pValueSize = sizeof(int16_t);
    +-        break;
    ++        *pValueSize = sizeof(uint16_t);
    + 
    +-    case EQ_PARAM_LEVEL_RANGE:
    +-        if (*pValueSize < 2 * sizeof(int16_t)) {
    +-            ALOGV("\tLVM_ERROR : Equalizer_getParameter() invalid pValueSize 2  %d", *pValueSize);
    +-            return -EINVAL;
    +-        }
    +-        *pValueSize = 2 * sizeof(int16_t);
    ++        *(uint16_t *)pValue = (uint16_t)FIVEBAND_NUMBANDS;
    ++        ALOGVV("%s EQ_PARAM_NUM_BANDS %u", __func__, *(uint16_t *)pValue);
    +         break;
    +-    case EQ_PARAM_BAND_FREQ_RANGE:
    +-        if (*pValueSize < 2 * sizeof(int32_t)) {
    +-            ALOGV("\tLVM_ERROR : Equalizer_getParameter() invalid pValueSize 3  %d", *pValueSize);
    +-            return -EINVAL;
     +
    -+        if (*pValueSize < 1) {
    ++    case EQ_PARAM_CUR_PRESET:
    ++        if (*pValueSize < sizeof(uint16_t)) {
    ++            ALOGV("%s EQ_PARAM_CUR_PRESET invalid *pValueSize %u", __func__, *pValueSize);
    ++            status = -EINVAL;
    ++            break;
    +         }
    +-        *pValueSize = 2 * sizeof(int32_t);
    ++        *pValueSize = sizeof(uint16_t);
    ++
    ++        *(uint16_t *)pValue = (uint16_t)EqualizerGetPreset(pContext);
    ++        ALOGVV("%s EQ_PARAM_CUR_PRESET %u", __func__, *(uint16_t *)pValue);
    +         break;
    + 
    +-    case EQ_PARAM_CENTER_FREQ:
    +-        if (*pValueSize < sizeof(int32_t)) {
    +-            ALOGV("\tLVM_ERROR : Equalizer_getParameter() invalid pValueSize 5  %d", *pValueSize);
    +-            return -EINVAL;
    ++    case EQ_PARAM_GET_NUM_OF_PRESETS:
    ++        if (*pValueSize < sizeof(uint16_t)) {
    ++            ALOGV("%s EQ_PARAM_GET_NUM_OF_PRESETS invalid *pValueSize %u", __func__, *pValueSize);
    ++            status = -EINVAL;
    ++            break;
    +         }
    +-        *pValueSize = sizeof(int32_t);
    +-        break;
    ++        *pValueSize = sizeof(uint16_t);
    + 
    +-    case EQ_PARAM_GET_PRESET_NAME:
    ++        *(uint16_t *)pValue = (uint16_t)EqualizerGetNumPresets();
    ++        ALOGVV("%s EQ_PARAM_GET_NUM_OF_PRESETS %u", __func__, *(uint16_t *)pValue);
    +         break;
    + 
    +-    case EQ_PARAM_PROPERTIES:
    +-        if (*pValueSize < (2 + FIVEBAND_NUMBANDS) * sizeof(uint16_t)) {
    +-            ALOGV("\tLVM_ERROR : Equalizer_getParameter() invalid pValueSize 1  %d", *pValueSize);
    +-            return -EINVAL;
    ++    case EQ_PARAM_GET_BAND: {
    ++        if (paramSize < 2 * sizeof(int32_t)) {
    ++            ALOGV("%s EQ_PARAM_GET_BAND invalid paramSize: %u", __func__, paramSize);
    ++            status = -EINVAL;
    ++            break;
    +         }
    +-        *pValueSize = (2 + FIVEBAND_NUMBANDS) * sizeof(uint16_t);
    +-        break;
    ++        if (*pValueSize < sizeof(uint16_t)) {
    ++            ALOGV("%s EQ_PARAM_GET_BAND invalid *pValueSize %u", __func__, *pValueSize);
    ++            status = -EINVAL;
    ++            break;
    ++        }
    ++        *pValueSize = sizeof(uint16_t);
    + 
    +-    default:
    +-        ALOGV("\tLVM_ERROR : Equalizer_getParameter unknown param %d", param);
    +-        return -EINVAL;
    +-    }
    ++        const int32_t frequency = params[1];
    ++        *(uint16_t *)pValue = (uint16_t)EqualizerGetBand(pContext, frequency);
    ++        ALOGVV("%s EQ_PARAM_GET_BAND frequency %d, band %u",
    ++                __func__, frequency, *(uint16_t *)pValue);
    ++    } break;
    + 
    +-    switch (param) {
    +-    case EQ_PARAM_NUM_BANDS:
    +-        *(uint16_t *)pValue = (uint16_t)FIVEBAND_NUMBANDS;
    +-        //ALOGV("\tEqualizer_getParameter() EQ_PARAM_NUM_BANDS %d", *(int16_t *)pValue);
    +-        break;
    ++    case EQ_PARAM_BAND_LEVEL: {
    ++        if (paramSize < 2 * sizeof(int32_t)) {
    ++            ALOGV("%s EQ_PARAM_BAND_LEVEL invalid paramSize %u", __func__, paramSize);
    ++            status = -EINVAL;
    ++            break;
    ++        }
    ++        if (*pValueSize < sizeof(int16_t)) {
    ++            ALOGV("%s EQ_PARAM_BAND_LEVEL invalid *pValueSize %u", __func__, *pValueSize);
    ++            status = -EINVAL;
    ++            break;
    ++        }
    ++        *pValueSize = sizeof(int16_t);
    ++
    ++        const int32_t band = params[1];
    ++        if (band < 0 || band >= FIVEBAND_NUMBANDS) {
    ++            if (band < 0) {
    ++                android_errorWriteLog(0x534e4554, "32438598");
    ++                ALOGW("%s EQ_PARAM_BAND_LEVEL invalid band %d", __func__, band);
    ++            }
    ++            status = -EINVAL;
    ++            break;
    ++        }
    ++        *(int16_t *)pValue = (int16_t)EqualizerGetBandLevel(pContext, band);
    ++        ALOGVV("%s EQ_PARAM_BAND_LEVEL band %d, level %d",
    ++                __func__, band, *(int16_t *)pValue);
    ++    } break;
    + 
    +     case EQ_PARAM_LEVEL_RANGE:
    ++        if (*pValueSize < 2 * sizeof(int16_t)) {
    ++            ALOGV("%s EQ_PARAM_LEVEL_RANGE invalid *pValueSize %u", __func__, *pValueSize);
    ++            status = -EINVAL;
    ++            break;
    ++        }
    ++        *pValueSize = 2 * sizeof(int16_t);
    ++
    +         *(int16_t *)pValue = -1500;
    +         *((int16_t *)pValue + 1) = 1500;
    +-        //ALOGV("\tEqualizer_getParameter() EQ_PARAM_LEVEL_RANGE min %d, max %d",
    +-        //      *(int16_t *)pValue, *((int16_t *)pValue + 1));
    ++        ALOGVV("%s EQ_PARAM_LEVEL_RANGE min %d, max %d",
    ++                __func__, *(int16_t *)pValue, *((int16_t *)pValue + 1));
    +         break;
    + 
    +-    case EQ_PARAM_BAND_LEVEL:
    +-        param2 = *pParamTemp;
    +-        if (param2 < 0 || param2 >= FIVEBAND_NUMBANDS) {
    ++    case EQ_PARAM_BAND_FREQ_RANGE: {
    ++        if (paramSize < 2 * sizeof(int32_t)) {
    ++            ALOGV("%s EQ_PARAM_BAND_FREQ_RANGE invalid paramSize: %u", __func__, paramSize);
    +             status = -EINVAL;
    +-            if (param2 < 0) {
    +-                android_errorWriteLog(0x534e4554, "32438598");
    +-                ALOGW("\tERROR Equalizer_getParameter() EQ_PARAM_BAND_LEVEL band %d", param2);
    +-            }
    +             break;
    +         }
    +-        *(int16_t *)pValue = (int16_t)EqualizerGetBandLevel(pContext, param2);
    +-        //ALOGV("\tEqualizer_getParameter() EQ_PARAM_BAND_LEVEL band %d, level %d",
    +-        //      param2, *(int32_t *)pValue);
    +-        break;
    +-
    +-    case EQ_PARAM_CENTER_FREQ:
    +-        param2 = *pParamTemp;
    +-        if (param2 < 0 || param2 >= FIVEBAND_NUMBANDS) {
    ++        if (*pValueSize < 2 * sizeof(int32_t)) {
    ++            ALOGV("%s EQ_PARAM_BAND_FREQ_RANGE invalid *pValueSize %u", __func__, *pValueSize);
    +             status = -EINVAL;
    +-            if (param2 < 0) {
    +-                android_errorWriteLog(0x534e4554, "32436341");
    +-                ALOGW("\tERROR Equalizer_getParameter() EQ_PARAM_CENTER_FREQ band %d", param2);
    +-            }
    +             break;
    +         }
    +-        *(int32_t *)pValue = EqualizerGetCentreFrequency(pContext, param2);
    +-        //ALOGV("\tEqualizer_getParameter() EQ_PARAM_CENTER_FREQ band %d, frequency %d",
    +-        //      param2, *(int32_t *)pValue);
    +-        break;
    ++        *pValueSize = 2 * sizeof(int32_t);
    + 
    +-    case EQ_PARAM_BAND_FREQ_RANGE:
    +-        param2 = *pParamTemp;
    +-        if (param2 < 0 || param2 >= FIVEBAND_NUMBANDS) {
    +-            status = -EINVAL;
    +-            if (param2 < 0) {
    ++        const int32_t band = params[1];
    ++        if (band < 0 || band >= FIVEBAND_NUMBANDS) {
    ++            if (band < 0) {
    +                 android_errorWriteLog(0x534e4554, "32247948");
    +-                ALOGW("\tERROR Equalizer_getParameter() EQ_PARAM_BAND_FREQ_RANGE band %d", param2);
    ++                ALOGW("%s EQ_PARAM_BAND_FREQ_RANGE invalid band %d",
    ++                        __func__, band);
    +             }
     +            status = -EINVAL;
    +             break;
    +         }
    +-        EqualizerGetBandFreqRange(pContext, param2, (uint32_t *)pValue, ((uint32_t *)pValue + 1));
    +-        //ALOGV("\tEqualizer_getParameter() EQ_PARAM_BAND_FREQ_RANGE band %d, min %d, max %d",
    +-        //      param2, *(int32_t *)pValue, *((int32_t *)pValue + 1));
    +-        break;
    ++        EqualizerGetBandFreqRange(pContext, band, (uint32_t *)pValue, ((uint32_t *)pValue + 1));
    ++        ALOGVV("%s EQ_PARAM_BAND_FREQ_RANGE band %d, min %d, max %d",
    ++                __func__, band, *(int32_t *)pValue, *((int32_t *)pValue + 1));
    + 
    +-    case EQ_PARAM_GET_BAND:
    +-        param2 = *pParamTemp;
    +-        *(uint16_t *)pValue = (uint16_t)EqualizerGetBand(pContext, param2);
    +-        //ALOGV("\tEqualizer_getParameter() EQ_PARAM_GET_BAND frequency %d, band %d",
    +-        //      param2, *(uint16_t *)pValue);
    +-        break;
    ++    } break;
    + 
    +-    case EQ_PARAM_CUR_PRESET:
    +-        *(uint16_t *)pValue = (uint16_t)EqualizerGetPreset(pContext);
    +-        //ALOGV("\tEqualizer_getParameter() EQ_PARAM_CUR_PRESET %d", *(int32_t *)pValue);
    +-        break;
    ++    case EQ_PARAM_CENTER_FREQ: {
    ++        if (paramSize < 2 * sizeof(int32_t)) {
    ++            ALOGV("%s EQ_PARAM_CENTER_FREQ invalid paramSize: %u", __func__, paramSize);
    ++            status = -EINVAL;
    ++            break;
    ++        }
    ++        if (*pValueSize < sizeof(int32_t)) {
    ++            ALOGV("%s EQ_PARAM_CENTER_FREQ invalid *pValueSize %u", __func__, *pValueSize);
    ++            status = -EINVAL;
    ++            break;
    ++        }
    ++        *pValueSize = sizeof(int32_t);
    + 
    +-    case EQ_PARAM_GET_NUM_OF_PRESETS:
    +-        *(uint16_t *)pValue = (uint16_t)EqualizerGetNumPresets();
    +-        //ALOGV("\tEqualizer_getParameter() EQ_PARAM_GET_NUM_OF_PRESETS %d", *(int16_t *)pValue);
    +-        break;
    ++        const int32_t band = params[1];
    ++        if (band < 0 || band >= FIVEBAND_NUMBANDS) {
    ++            status = -EINVAL;
    ++            if (band < 0) {
    ++                android_errorWriteLog(0x534e4554, "32436341");
    ++                ALOGW("%s EQ_PARAM_CENTER_FREQ invalid band %d", __func__, band);
    ++            }
    ++            break;
    ++        }
    ++        *(int32_t *)pValue = EqualizerGetCentreFrequency(pContext, band);
    ++        ALOGVV("%s EQ_PARAM_CENTER_FREQ band %d, frequency %d",
    ++                __func__, band, *(int32_t *)pValue);
    ++    } break;
    + 
    +-    case EQ_PARAM_GET_PRESET_NAME:
    +-        param2 = *pParamTemp;
    +-        if ((param2 < 0 && param2 != PRESET_CUSTOM) ||  param2 >= EqualizerGetNumPresets()) {
    ++    case EQ_PARAM_GET_PRESET_NAME: {
    ++        if (paramSize < 2 * sizeof(int32_t)) {
    ++            ALOGV("%s EQ_PARAM_PRESET_NAME invalid paramSize: %u", __func__, paramSize);
    +             status = -EINVAL;
    +-            if (param2 < 0) {
    ++            break;
    ++        }
    ++        if (*pValueSize < 1) {
     +            android_errorWriteLog(0x534e4554, "37536407");
    ++            status = -EINVAL;
     +            break;
     +        }
     +
    -         name = (char *)pValue;
    -         strncpy(name, EqualizerGetPresetName(param2), *pValueSize - 1);
    ++        const int32_t preset = params[1];
    ++        if ((preset < 0 && preset != PRESET_CUSTOM) ||  preset >= EqualizerGetNumPresets()) {
    ++            if (preset < 0) {
    +                 android_errorWriteLog(0x534e4554, "32448258");
    +-                ALOGE("\tERROR Equalizer_getParameter() EQ_PARAM_GET_PRESET_NAME preset %d",
    +-                        param2);
    ++                ALOGE("%s EQ_PARAM_GET_PRESET_NAME preset %d", __func__, preset);
    +             }
    ++            status = -EINVAL;
    +             break;
    +         }
    +-        name = (char *)pValue;
    +-        strncpy(name, EqualizerGetPresetName(param2), *pValueSize - 1);
    ++
    ++        char * const name = (char *)pValue;
    ++        strncpy(name, EqualizerGetPresetName(preset), *pValueSize - 1);
              name[*pValueSize - 1] = 0;
    +         *pValueSize = strlen(name) + 1;
    +-        //ALOGV("\tEqualizer_getParameter() EQ_PARAM_GET_PRESET_NAME preset %d, name %s len %d",
    +-        //      param2, gEqualizerPresets[param2].name, *pValueSize);
    +-        break;
    ++        ALOGVV("%s EQ_PARAM_GET_PRESET_NAME preset %d, name %s len %d",
    ++                __func__, preset, gEqualizerPresets[preset].name, *pValueSize);
    ++
    ++    } break;
    + 
    +     case EQ_PARAM_PROPERTIES: {
    ++        const uint32_t requiredValueSize = (2 + FIVEBAND_NUMBANDS) * sizeof(uint16_t);
    ++        if (*pValueSize < requiredValueSize) {
    ++            ALOGV("%s EQ_PARAM_PROPERTIES invalid *pValueSize %u", __func__, *pValueSize);
    ++            status = -EINVAL;
    ++            break;
    ++        }
    ++        *pValueSize = requiredValueSize;
    ++
    +         int16_t *p = (int16_t *)pValue;
    +-        ALOGV("\tEqualizer_getParameter() EQ_PARAM_PROPERTIES");
    ++        ALOGV("%s EQ_PARAM_PROPERTIES", __func__);
    +         p[0] = (int16_t)EqualizerGetPreset(pContext);
    +         p[1] = (int16_t)FIVEBAND_NUMBANDS;
    +         for (int i = 0; i < FIVEBAND_NUMBANDS; i++) {
    +@@ -2458,12 +2563,12 @@ int Equalizer_getParameter(EffectContext     *pContext,
    +     } break;
    + 
    +     default:
    +-        ALOGV("\tLVM_ERROR : Equalizer_getParameter() invalid param %d", param);
    ++        ALOGV("%s invalid param %d", __func__, params[0]);
    +         status = -EINVAL;
    +         break;
    +     }
    + 
    +-    //GV("\tEqualizer_getParameter end\n");
    ++    ALOGVV("%s end param: %d, status: %d", __func__, params[0], status);
    +     return status;
    + } /* end Equalizer_getParameter */
    + 
    +@@ -2483,74 +2588,89 @@ int Equalizer_getParameter(EffectContext     *pContext,
    + // Outputs:
    + //
    + //----------------------------------------------------------------------------
    +-int Equalizer_setParameter (EffectContext *pContext,
    +-                            void *pParam,
    +-                            uint32_t valueSize,
    +-                            void *pValue) {
    ++int Equalizer_setParameter(EffectContext *pContext,
    ++                           uint32_t       paramSize,
    ++                           void          *pParam,
    ++                           uint32_t       valueSize,
    ++                           void          *pValue) {
    +     int status = 0;
    +-    int32_t preset;
    +-    int32_t band;
    +-    int32_t level;
    +-    int32_t *pParamTemp = (int32_t *)pParam;
    +-    int32_t param = *pParamTemp++;
    ++    int32_t *params = (int32_t *)pParam;
    + 
    ++    ALOGVV("%s start", __func__);
    + 
    +-    //ALOGV("\tEqualizer_setParameter start");
    +-    switch (param) {
    +-    case EQ_PARAM_CUR_PRESET:
    ++    if (paramSize < sizeof(int32_t)) {
    ++        ALOGV("%s invalid paramSize: %u", __func__, paramSize);
    ++        return -EINVAL;
    ++    }
    ++    switch (params[0]) {
    ++    case EQ_PARAM_CUR_PRESET: {
    +         if (valueSize < sizeof(int16_t)) {
    +-          status = -EINVAL;
    +-          break;
    ++            ALOGV("%s EQ_PARAM_CUR_PRESET invalid valueSize %u", __func__, valueSize);
    ++            status = -EINVAL;
    ++            break;
    +         }
    +-        preset = (int32_t)(*(uint16_t *)pValue);
    ++        const int32_t preset = (int32_t)*(uint16_t *)pValue;
    + 
    +-        //ALOGV("\tEqualizer_setParameter() EQ_PARAM_CUR_PRESET %d", preset);
    +-        if ((preset >= EqualizerGetNumPresets())||(preset < 0)) {
    ++        ALOGVV("%s EQ_PARAM_CUR_PRESET %d", __func__, preset);
    ++        if (preset >= EqualizerGetNumPresets() || preset < 0) {
    ++            ALOGV("%s EQ_PARAM_CUR_PRESET invalid preset %d", __func__, preset);
    +             status = -EINVAL;
    +             break;
    +         }
    +         EqualizerSetPreset(pContext, preset);
    +-        break;
    +-    case EQ_PARAM_BAND_LEVEL:
    ++    } break;
    ++
    ++    case EQ_PARAM_BAND_LEVEL: {
    ++        if (paramSize < 2 * sizeof(int32_t)) {
    ++            ALOGV("%s EQ_PARAM_BAND_LEVEL invalid paramSize: %u", __func__, paramSize);
    ++            status = -EINVAL;
    ++            break;
    ++        }
    +         if (valueSize < sizeof(int16_t)) {
    +-          status = -EINVAL;
    +-          break;
    ++            ALOGV("%s EQ_PARAM_BAND_LEVEL invalid valueSize %u", __func__, valueSize);
    ++            status = -EINVAL;
    ++            break;
    +         }
    +-        band =  *pParamTemp;
    +-        level = (int32_t)(*(int16_t *)pValue);
    +-        //ALOGV("\tEqualizer_setParameter() EQ_PARAM_BAND_LEVEL band %d, level %d", band, level);
    ++        const int32_t band =  params[1];
    ++        const int32_t level = (int32_t)*(int16_t *)pValue;
    ++        ALOGVV("%s EQ_PARAM_BAND_LEVEL band %d, level %d", __func__, band, level);
    +         if (band < 0 || band >= FIVEBAND_NUMBANDS) {
    +-            status = -EINVAL;
    +             if (band < 0) {
    +                 android_errorWriteLog(0x534e4554, "32095626");
    +-                ALOGE("\tERROR Equalizer_setParameter() EQ_PARAM_BAND_LEVEL band %d", band);
    ++                ALOGE("%s EQ_PARAM_BAND_LEVEL invalid band %d", __func__, band);
    +             }
    ++            status = -EINVAL;
    +             break;
    +         }
    +         EqualizerSetBandLevel(pContext, band, level);
    +-        break;
    ++    } break;
    ++
    +     case EQ_PARAM_PROPERTIES: {
    +-        //ALOGV("\tEqualizer_setParameter() EQ_PARAM_PROPERTIES");
    ++        ALOGVV("%s EQ_PARAM_PROPERTIES", __func__);
    +         if (valueSize < sizeof(int16_t)) {
    +-          status = -EINVAL;
    +-          break;
    ++            ALOGV("%s EQ_PARAM_PROPERTIES invalid valueSize %u", __func__, valueSize);
    ++            status = -EINVAL;
    ++            break;
    +         }
    +         int16_t *p = (int16_t *)pValue;
    +         if ((int)p[0] >= EqualizerGetNumPresets()) {
    ++            ALOGV("%s EQ_PARAM_PROPERTIES invalid preset %d", __func__, (int)p[0]);
    +             status = -EINVAL;
    +             break;
    +         }
    +         if (p[0] >= 0) {
    +             EqualizerSetPreset(pContext, (int)p[0]);
    +         } else {
    +-            if (valueSize < (2 + FIVEBAND_NUMBANDS) * sizeof(int16_t)) {
    ++            const uint32_t valueSizeRequired = (2 + FIVEBAND_NUMBANDS) * sizeof(int16_t);
    ++            if (valueSize < valueSizeRequired) {
    +               android_errorWriteLog(0x534e4554, "37563371");
    +-              ALOGE("\tERROR Equalizer_setParameter() EQ_PARAM_PROPERTIES valueSize %d < %d",
    +-                    (int)valueSize, (int)((2 + FIVEBAND_NUMBANDS) * sizeof(int16_t)));
    ++              ALOGE("%s EQ_PARAM_PROPERTIES invalid valueSize %u < %u",
    ++                      __func__, valueSize, valueSizeRequired);
    +               status = -EINVAL;
    +               break;
    +             }
    +             if ((int)p[1] != FIVEBAND_NUMBANDS) {
    ++                ALOGV("%s EQ_PARAM_PROPERTIES invalid bands %d", __func__, (int)p[1]);
    +                 status = -EINVAL;
    +                 break;
    +             }
    +@@ -2559,13 +2679,14 @@ int Equalizer_setParameter (EffectContext *pContext,
    +             }
    +         }
    +     } break;
    ++
    +     default:
    +-        ALOGV("\tLVM_ERROR : Equalizer_setParameter() invalid param %d", param);
    ++        ALOGV("%s invalid param %d", __func__, params[0]);
    +         status = -EINVAL;
    +         break;
    +     }
    + 
    +-    //ALOGV("\tEqualizer_setParameter end");
    ++    ALOGVV("%s end param: %d, status: %d", __func__, params[0], status);
    +     return status;
    + } /* end Equalizer_setParameter */
    + 
    +@@ -2590,81 +2711,92 @@ int Equalizer_setParameter (EffectContext *pContext,
    + //
    + //----------------------------------------------------------------------------
    + 
    +-int Volume_getParameter(EffectContext     *pContext,
    +-                        void              *pParam,
    +-                        uint32_t          *pValueSize,
    +-                        void              *pValue){
    ++int Volume_getParameter(EffectContext *pContext,
    ++                        uint32_t       paramSize,
    ++                        void          *pParam,
    ++                        uint32_t      *pValueSize,
    ++                        void          *pValue) {
    +     int status = 0;
    +-    int bMute = 0;
    +-    int32_t *pParamTemp = (int32_t *)pParam;
    +-    int32_t param = *pParamTemp++;;
    +-    char *name;
    ++    int32_t *params = (int32_t *)pParam;
    + 
    +-    //ALOGV("\tVolume_getParameter start");
    ++    ALOGVV("%s start", __func__);
    + 
    +-    switch (param){
    ++    if (paramSize < sizeof(int32_t)) {
    ++        ALOGV("%s invalid paramSize: %u", __func__, paramSize);
    ++        return -EINVAL;
    ++    }
    ++    switch (params[0]) {
    +         case VOLUME_PARAM_LEVEL:
    +-        case VOLUME_PARAM_MAXLEVEL:
    +-        case VOLUME_PARAM_STEREOPOSITION:
    +-            if (*pValueSize != sizeof(int16_t)){
    +-                ALOGV("\tLVM_ERROR : Volume_getParameter() invalid pValueSize 1  %d", *pValueSize);
    +-                return -EINVAL;
    +-            }
    +-            *pValueSize = sizeof(int16_t);
    +-            break;
    +-
    +-        case VOLUME_PARAM_MUTE:
    +-        case VOLUME_PARAM_ENABLESTEREOPOSITION:
    +-            if (*pValueSize < sizeof(int32_t)){
    +-                ALOGV("\tLVM_ERROR : Volume_getParameter() invalid pValueSize 2  %d", *pValueSize);
    +-                return -EINVAL;
    ++            if (*pValueSize != sizeof(int16_t)) { // legacy: check equality here.
    ++                ALOGV("%s VOLUME_PARAM_LEVEL invalid *pValueSize %u", __func__, *pValueSize);
    ++                status = -EINVAL;
    ++                break;
    +             }
    +-            *pValueSize = sizeof(int32_t);
    +-            break;
    ++            // no need to set *pValueSize
    + 
    +-        default:
    +-            ALOGV("\tLVM_ERROR : Volume_getParameter unknown param %d", param);
    +-            return -EINVAL;
    +-    }
    +-
    +-    switch (param){
    +-        case VOLUME_PARAM_LEVEL:
    +             status = VolumeGetVolumeLevel(pContext, (int16_t *)(pValue));
    +-            //ALOGV("\tVolume_getParameter() VOLUME_PARAM_LEVEL Value is %d",
    +-            //        *(int16_t *)pValue);
    ++            ALOGVV("%s VOLUME_PARAM_LEVEL %d", __func__, *(int16_t *)pValue);
    +             break;
    + 
    +         case VOLUME_PARAM_MAXLEVEL:
    ++            if (*pValueSize != sizeof(int16_t)) { // legacy: check equality here.
    ++                ALOGV("%s VOLUME_PARAM_MAXLEVEL invalid *pValueSize %u", __func__, *pValueSize);
    ++                status = -EINVAL;
    ++                break;
    ++            }
    ++            // no need to set *pValueSize
    ++
    ++            // in millibel
    +             *(int16_t *)pValue = 0;
    +-            //ALOGV("\tVolume_getParameter() VOLUME_PARAM_MAXLEVEL Value is %d",
    +-            //        *(int16_t *)pValue);
    ++            ALOGVV("%s VOLUME_PARAM_MAXLEVEL %d", __func__, *(int16_t *)pValue);
    +             break;
    + 
    +         case VOLUME_PARAM_STEREOPOSITION:
    ++            if (*pValueSize != sizeof(int16_t)) { // legacy: check equality here.
    ++                ALOGV("%s VOLUME_PARAM_STEREOPOSITION invalid *pValueSize %u",
    ++                        __func__, *pValueSize);
    ++                status = -EINVAL;
    ++                break;
    ++            }
    ++            // no need to set *pValueSize
    ++
    +             VolumeGetStereoPosition(pContext, (int16_t *)pValue);
    +-            //ALOGV("\tVolume_getParameter() VOLUME_PARAM_STEREOPOSITION Value is %d",
    +-            //        *(int16_t *)pValue);
    ++            ALOGVV("%s VOLUME_PARAM_STEREOPOSITION %d", __func__, *(int16_t *)pValue);
    +             break;
    + 
    +         case VOLUME_PARAM_MUTE:
    ++            if (*pValueSize < sizeof(uint32_t)) {
    ++                ALOGV("%s VOLUME_PARAM_MUTE invalid *pValueSize %u", __func__, *pValueSize);
    ++                status = -EINVAL;
    ++                break;
    ++            }
    ++            *pValueSize = sizeof(uint32_t);
    ++
    +             status = VolumeGetMute(pContext, (uint32_t *)pValue);
    +-            ALOGV("\tVolume_getParameter() VOLUME_PARAM_MUTE Value is %d",
    +-                    *(uint32_t *)pValue);
    ++            ALOGV("%s VOLUME_PARAM_MUTE %u", __func__, *(uint32_t *)pValue);
    +             break;
    + 
    +         case VOLUME_PARAM_ENABLESTEREOPOSITION:
    ++            if (*pValueSize < sizeof(int32_t)) {
    ++                ALOGV("%s VOLUME_PARAM_ENABLESTEREOPOSITION invalid *pValueSize %u",
    ++                        __func__, *pValueSize);
    ++                status = -EINVAL;
    ++                break;
    ++            }
    ++            *pValueSize = sizeof(int32_t);
    ++
    +             *(int32_t *)pValue = pContext->pBundledContext->bStereoPositionEnabled;
    +-            //ALOGV("\tVolume_getParameter() VOLUME_PARAM_ENABLESTEREOPOSITION Value is %d",
    +-            //        *(uint32_t *)pValue);
    ++            ALOGVV("%s VOLUME_PARAM_ENABLESTEREOPOSITION %d", __func__, *(int32_t *)pValue);
    ++
    +             break;
    + 
    +         default:
    +-            ALOGV("\tLVM_ERROR : Volume_getParameter() invalid param %d", param);
    ++            ALOGV("%s invalid param %d", __func__, params[0]);
    +             status = -EINVAL;
    +             break;
    +     }
    + 
    +-    //ALOGV("\tVolume_getParameter end");
    ++    ALOGVV("%s end param: %d, status: %d", __func__, params[0], status);
    +     return status;
    + } /* end Volume_getParameter */
    + 
    +@@ -2684,55 +2816,87 @@ int Volume_getParameter(EffectContext     *pContext,
    + //
    + //----------------------------------------------------------------------------
    + 
    +-int Volume_setParameter (EffectContext *pContext, void *pParam, void *pValue){
    +-    int      status = 0;
    +-    int16_t  level;
    +-    int16_t  position;
    +-    uint32_t mute;
    +-    uint32_t positionEnabled;
    +-    int32_t *pParamTemp = (int32_t *)pParam;
    +-    int32_t param = *pParamTemp++;
    ++int Volume_setParameter(EffectContext *pContext,
    ++                        uint32_t       paramSize,
    ++                        void          *pParam,
    ++                        uint32_t       valueSize,
    ++                        void          *pValue) {
    ++    int status = 0;
    ++    int32_t *params = (int32_t *)pParam;
    ++
    ++    ALOGVV("%s start", __func__);
    + 
    +-    //ALOGV("\tVolume_setParameter start");
    ++    if (paramSize < sizeof(int32_t)) {
    ++        ALOGV("%s invalid paramSize: %u", __func__, paramSize);
    ++        return -EINVAL;
    ++    }
    ++    switch (params[0]) {
    ++        case VOLUME_PARAM_LEVEL: {
    ++            if (valueSize < sizeof(int16_t)) {
    ++                ALOGV("%s VOLUME_PARAM_LEVEL invalid valueSize %u", __func__, valueSize);
    ++                status = -EINVAL;
    ++                break;
    ++            }
    + 
    +-    switch (param){
    +-        case VOLUME_PARAM_LEVEL:
    +-            level = *(int16_t *)pValue;
    +-            //ALOGV("\tVolume_setParameter() VOLUME_PARAM_LEVEL value is %d", level);
    +-            //ALOGV("\tVolume_setParameter() Calling pVolume->setVolumeLevel");
    +-            status = VolumeSetVolumeLevel(pContext, (int16_t)level);
    +-            //ALOGV("\tVolume_setParameter() Called pVolume->setVolumeLevel");
    +-            break;
    ++            const int16_t level = *(int16_t *)pValue;
    ++            ALOGVV("%s VOLUME_PARAM_LEVEL %d", __func__, level);
    ++            ALOGVV("%s VOLUME_PARAM_LEVEL Calling VolumeSetVolumeLevel", __func__);
    ++            status = VolumeSetVolumeLevel(pContext, level);
    ++            ALOGVV("%s VOLUME_PARAM_LEVEL Called VolumeSetVolumeLevel", __func__);
    ++        } break;
    + 
    +-        case VOLUME_PARAM_MUTE:
    +-            mute = *(uint32_t *)pValue;
    +-            //ALOGV("\tVolume_setParameter() Calling pVolume->setMute, mute is %d", mute);
    +-            //ALOGV("\tVolume_setParameter() Calling pVolume->setMute");
    ++        case VOLUME_PARAM_MUTE: {
    ++            if (valueSize < sizeof(uint32_t)) {
    ++                ALOGV("%s VOLUME_PARAM_MUTE invalid valueSize %u", __func__, valueSize);
    ++                android_errorWriteLog(0x534e4554, "64477217");
    ++                status = -EINVAL;
    ++                break;
    ++            }
    ++
    ++            const uint32_t mute = *(uint32_t *)pValue;
    ++            ALOGVV("%s VOLUME_PARAM_MUTE %d", __func__, mute);
    ++            ALOGVV("%s VOLUME_PARAM_MUTE Calling VolumeSetMute", __func__);
    +             status = VolumeSetMute(pContext, mute);
    +-            //ALOGV("\tVolume_setParameter() Called pVolume->setMute");
    +-            break;
    ++            ALOGVV("%s VOLUME_PARAM_MUTE Called VolumeSetMute", __func__);
    ++        } break;
    + 
    +-        case VOLUME_PARAM_ENABLESTEREOPOSITION:
    +-            positionEnabled = *(uint32_t *)pValue;
    +-            status = VolumeEnableStereoPosition(pContext, positionEnabled);
    +-            status = VolumeSetStereoPosition(pContext, pContext->pBundledContext->positionSaved);
    +-            //ALOGV("\tVolume_setParameter() VOLUME_PARAM_ENABLESTEREOPOSITION called");
    +-            break;
    ++        case VOLUME_PARAM_ENABLESTEREOPOSITION: {
    ++            if (valueSize < sizeof(uint32_t)) {
    ++                ALOGV("%s VOLUME_PARAM_ENABLESTEREOPOSITION invalid valueSize %u",
    ++                        __func__, valueSize);
    ++                status = -EINVAL;
    ++                break;
    ++            }
    + 
    +-        case VOLUME_PARAM_STEREOPOSITION:
    +-            position = *(int16_t *)pValue;
    +-            //ALOGV("\tVolume_setParameter() VOLUME_PARAM_STEREOPOSITION value is %d", position);
    +-            //ALOGV("\tVolume_setParameter() Calling pVolume->VolumeSetStereoPosition");
    +-            status = VolumeSetStereoPosition(pContext, (int16_t)position);
    +-            //ALOGV("\tVolume_setParameter() Called pVolume->VolumeSetStereoPosition");
    +-            break;
    ++            const uint32_t positionEnabled = *(uint32_t *)pValue;
    ++            status = VolumeEnableStereoPosition(pContext, positionEnabled)
    ++                    ?: VolumeSetStereoPosition(pContext, pContext->pBundledContext->positionSaved);
    ++            ALOGVV("%s VOLUME_PARAM_ENABLESTEREOPOSITION called", __func__);
    ++        } break;
    ++
    ++        case VOLUME_PARAM_STEREOPOSITION: {
    ++            if (valueSize < sizeof(int16_t)) {
    ++                ALOGV("%s VOLUME_PARAM_STEREOPOSITION invalid valueSize %u", __func__, valueSize);
    ++                status = -EINVAL;
    ++                break;
    ++            }
    ++
    ++            const int16_t position = *(int16_t *)pValue;
    ++            ALOGVV("%s VOLUME_PARAM_STEREOPOSITION %d", __func__, position);
    ++            ALOGVV("%s VOLUME_PARAM_STEREOPOSITION Calling VolumeSetStereoPosition",
    ++                    __func__);
    ++            status = VolumeSetStereoPosition(pContext, position);
    ++            ALOGVV("%s VOLUME_PARAM_STEREOPOSITION Called VolumeSetStereoPosition",
    ++                    __func__);
    ++        } break;
    + 
    +         default:
    +-            ALOGV("\tLVM_ERROR : Volume_setParameter() invalid param %d", param);
    ++            ALOGV("%s invalid param %d", __func__, params[0]);
    ++            status = -EINVAL;
    +             break;
    +     }
    + 
    +-    //ALOGV("\tVolume_setParameter end");
    ++    ALOGVV("%s end param: %d, status: %d", __func__, params[0], status);
    +     return status;
    + } /* end Volume_setParameter */
    + 
    +@@ -3053,6 +3217,13 @@ int Effect_process(effect_handle_t     self,
    +     return status;
    + }   /* end Effect_process */
    + 
    ++// The value offset of an effect parameter is computed by rounding up
    ++// the parameter size to the next 32 bit alignment.
    ++static inline uint32_t computeParamVOffset(const effect_param_t *p) {
    ++    return ((p->psize + sizeof(int32_t) - 1) / sizeof(int32_t)) *
    ++            sizeof(int32_t);
    ++}
    ++
    + /* Effect Control Interface Implementation: Command */
    + int Effect_command(effect_handle_t  self,
    +                               uint32_t            cmdCode,
    +@@ -3164,8 +3335,7 @@ int Effect_command(effect_handle_t  self,
    +                 ALOGV("\tLVM_ERROR : EFFECT_CMD_GET_PARAM: psize too big");
    +                 return -EINVAL;
    +             }
    +-            uint32_t paddedParamSize = ((p->psize + sizeof(int32_t) - 1) / sizeof(int32_t)) *
    +-                    sizeof(int32_t);
    ++            const uint32_t paddedParamSize = computeParamVOffset(p);
    +             if ((EFFECT_PARAM_SIZE_MAX - sizeof(effect_param_t) < paddedParamSize) ||
    +                 (EFFECT_PARAM_SIZE_MAX - sizeof(effect_param_t) - paddedParamSize <
    +                     p->vsize)) {
    +@@ -3187,6 +3357,7 @@ int Effect_command(effect_handle_t  self,
    +             uint32_t voffset = paddedParamSize;
    +             if(pContext->EffectType == LVM_BASS_BOOST){
    +                 p->status = android::BassBoost_getParameter(pContext,
    ++                                                            p->psize,
    +                                                             p->data,
    +                                                             &p->vsize,
    +                                                             p->data + voffset);
    +@@ -3199,6 +3370,7 @@ int Effect_command(effect_handle_t  self,
    + 
    +             if(pContext->EffectType == LVM_VIRTUALIZER){
    +                 p->status = android::Virtualizer_getParameter(pContext,
    ++                                                              p->psize,
    +                                                               (void *)p->data,
    +                                                               &p->vsize,
    +                                                               p->data + voffset);
    +@@ -3213,6 +3385,7 @@ int Effect_command(effect_handle_t  self,
    +                 //ALOGV("\tEqualizer_command cmdCode Case: "
    +                 //        "EFFECT_CMD_GET_PARAM start");
    +                 p->status = android::Equalizer_getParameter(pContext,
    ++                                                            p->psize,
    +                                                             p->data,
    +                                                             &p->vsize,
    +                                                             p->data + voffset);
    +@@ -3227,6 +3400,7 @@ int Effect_command(effect_handle_t  self,
    +             if(pContext->EffectType == LVM_VOLUME){
    +                 //ALOGV("\tVolume_command cmdCode Case: EFFECT_CMD_GET_PARAM start");
    +                 p->status = android::Volume_getParameter(pContext,
    ++                                                         p->psize,
    +                                                          (void *)p->data,
    +                                                          &p->vsize,
    +                                                          p->data + voffset);
    +@@ -3256,13 +3430,9 @@ int Effect_command(effect_handle_t  self,
    +                             "EFFECT_CMD_SET_PARAM: ERROR");
    +                     return -EINVAL;
    +                 }
    +-                effect_param_t *p = (effect_param_t *) pCmdData;
    + 
    +-                if (p->psize != sizeof(int32_t)){
    +-                    ALOGV("\tLVM_ERROR : BassBoost_command cmdCode Case: "
    +-                            "EFFECT_CMD_SET_PARAM: ERROR, psize is not sizeof(int32_t)");
    +-                    return -EINVAL;
    +-                }
    ++                effect_param_t * const p = (effect_param_t *) pCmdData;
    ++                const uint32_t voffset = computeParamVOffset(p);
    + 
    +                 //ALOGV("\tnBassBoost_command cmdSize is %d\n"
    +                 //        "\tsizeof(effect_param_t) is  %d\n"
    +@@ -3272,8 +3442,10 @@ int Effect_command(effect_handle_t  self,
    +                 //        cmdSize, sizeof(effect_param_t), p->psize, p->vsize );
    + 
    +                 *(int *)pReplyData = android::BassBoost_setParameter(pContext,
    +-                                                                    (void *)p->data,
    +-                                                                    p->data + p->psize);
    ++                                                                     p->psize,
    ++                                                                     (void *)p->data,
    ++                                                                     p->vsize,
    ++                                                                     p->data + voffset);
    +             }
    +             if(pContext->EffectType == LVM_VIRTUALIZER){
    +               // Warning this log will fail to properly read an int32_t value, assumes int16_t
    +@@ -3291,13 +3463,9 @@ int Effect_command(effect_handle_t  self,
    +                             "EFFECT_CMD_SET_PARAM: ERROR");
    +                     return -EINVAL;
    +                 }
    +-                effect_param_t *p = (effect_param_t *) pCmdData;
    + 
    +-                if (p->psize != sizeof(int32_t)){
    +-                    ALOGV("\tLVM_ERROR : Virtualizer_command cmdCode Case: "
    +-                            "EFFECT_CMD_SET_PARAM: ERROR, psize is not sizeof(int32_t)");
    +-                    return -EINVAL;
    +-                }
    ++                effect_param_t * const p = (effect_param_t *) pCmdData;
    ++                const uint32_t voffset = computeParamVOffset(p);
    + 
    +                 //ALOGV("\tnVirtualizer_command cmdSize is %d\n"
    +                 //        "\tsizeof(effect_param_t) is  %d\n"
    +@@ -3307,8 +3475,10 @@ int Effect_command(effect_handle_t  self,
    +                 //        cmdSize, sizeof(effect_param_t), p->psize, p->vsize );
    + 
    +                 *(int *)pReplyData = android::Virtualizer_setParameter(pContext,
    +-                                                                      (void *)p->data,
    +-                                                                       p->data + p->psize);
    ++                                                                       p->psize,
    ++                                                                       (void *)p->data,
    ++                                                                       p->vsize,
    ++                                                                       p->data + voffset);
    +             }
    +             if(pContext->EffectType == LVM_EQUALIZER){
    +                //ALOGV("\tEqualizer_command cmdCode Case: "
    +@@ -3324,12 +3494,15 @@ int Effect_command(effect_handle_t  self,
    +                             "EFFECT_CMD_SET_PARAM: ERROR");
    +                     return -EINVAL;
    +                 }
    +-                effect_param_t *p = (effect_param_t *) pCmdData;
    ++
    ++                effect_param_t * const p = (effect_param_t *) pCmdData;
    ++                const uint32_t voffset = computeParamVOffset(p);
    + 
    +                 *(int *)pReplyData = android::Equalizer_setParameter(pContext,
    +-                                                                    (void *)p->data,
    +-                                                                    p->vsize,
    +-                                                                    p->data + p->psize);
    ++                                                                     p->psize,
    ++                                                                     (void *)p->data,
    ++                                                                     p->vsize,
    ++                                                                     p->data + voffset);
    +             }
    +             if(pContext->EffectType == LVM_VOLUME){
    +                 //ALOGV("\tVolume_command cmdCode Case: EFFECT_CMD_SET_PARAM start");
    +@@ -3346,11 +3519,15 @@ int Effect_command(effect_handle_t  self,
    +                             "EFFECT_CMD_SET_PARAM: ERROR");
    +                     return -EINVAL;
    +                 }
    +-                effect_param_t *p = (effect_param_t *) pCmdData;
    ++
    ++                effect_param_t * const p = (effect_param_t *) pCmdData;
    ++                const uint32_t voffset = computeParamVOffset(p);
    + 
    +                 *(int *)pReplyData = android::Volume_setParameter(pContext,
    +-                                                                 (void *)p->data,
    +-                                                                 p->data + p->psize);
    ++                                                                  p->psize,
    ++                                                                  (void *)p->data,
    ++                                                                  p->vsize,
    ++                                                                  p->data + voffset);
    +             }
    +             //ALOGV("\tEffect_command cmdCode Case: EFFECT_CMD_SET_PARAM end");
    +         } break;
     diff --git a/media/libeffects/lvm/wrapper/Reverb/EffectReverb.cpp b/media/libeffects/lvm/wrapper/Reverb/EffectReverb.cpp
     index 4dc8b4592..80c8a3878 100644
     --- a/media/libeffects/lvm/wrapper/Reverb/EffectReverb.cpp
    @@ -684,6 +2023,26 @@ index 6405d6de5..be826abda 100644
      // ----------------------------------------------------------------------------
      
      } // namespace android
    +diff --git a/media/libmedia/ICrypto.cpp b/media/libmedia/ICrypto.cpp
    +index 302e6ee9a..0045cffc6 100644
    +--- a/media/libmedia/ICrypto.cpp
    ++++ b/media/libmedia/ICrypto.cpp
    +@@ -199,8 +199,13 @@ IMPLEMENT_META_INTERFACE(Crypto, "android.hardware.ICrypto");
    + 
    + void BnCrypto::readVector(const Parcel &data, Vector<uint8_t> &vector) const {
    +     uint32_t size = data.readInt32();
    +-    vector.insertAt((size_t)0, size);
    +-    data.read(vector.editArray(), size);
    ++    if (vector.insertAt((size_t)0, size) < 0) {
    ++        vector.clear();
    ++    }
    ++    if (data.read(vector.editArray(), size) != NO_ERROR) {
    ++        vector.clear();
    ++        ALOGE("62872384");
    ++    }
    + }
    + 
    + void BnCrypto::writeVector(Parcel *reply, Vector<uint8_t> const &vector) const {
     diff --git a/media/libmedia/IDataSource.cpp b/media/libmedia/IDataSource.cpp
     index 51c9938f6..5ad39fe81 100644
     --- a/media/libmedia/IDataSource.cpp
    @@ -2375,14 +3734,14 @@ index 56e1f7734..04d8dda07 100644
                      ConvertYUV420SemiPlanarToYUV420Planar(
                              source, mConversionBuffer, mWidth, mHeight);
     diff --git a/media/libstagefright/foundation/MediaBuffer.cpp b/media/libstagefright/foundation/MediaBuffer.cpp
    -index 16000ef5c..82b989c9e 100644
    +index 16000ef5c..2c4a76211 100644
     --- a/media/libstagefright/foundation/MediaBuffer.cpp
     +++ b/media/libstagefright/foundation/MediaBuffer.cpp
     @@ -155,6 +155,7 @@ size_t MediaBuffer::range_length() const {
      void MediaBuffer::set_range(size_t offset, size_t length) {
          if ((mGraphicBuffer == NULL) && (offset + length > mSize)) {
              ALOGE("offset = %zu, length = %zu, mSize = %zu", offset, length, mSize);
    -+	offset = 0;
    ++        offset = 0;
          }
          CHECK((mGraphicBuffer != NULL) || (offset + length <= mSize));
      
    @@ -2601,10 +3960,10 @@ index fa648ed7d..c85335abc 100644
      
          status_t mInitCheck;
     diff --git a/media/libstagefright/id3/ID3.cpp b/media/libstagefright/id3/ID3.cpp
    -index 8b80ae949..0791ee9a2 100644
    +index 8b80ae949..ca2be5488 100644
     --- a/media/libstagefright/id3/ID3.cpp
     +++ b/media/libstagefright/id3/ID3.cpp
    -@@ -328,12 +328,24 @@ struct id3_header {
    +@@ -328,12 +328,25 @@ struct id3_header {
      }
      
      void ID3::removeUnsynchronization() {
    @@ -2612,6 +3971,7 @@ index 8b80ae949..0791ee9a2 100644
     -        if (mData[i] == 0xff && mData[i + 1] == 0x00) {
     -            memmove(&mData[i + 1], &mData[i + 2], mSize - i - 2);
     -            --mSize;
    ++
     +    // This file has "unsynchronization", so we have to replace occurrences
     +    // of 0xff 0x00 with just 0xff in order to get the real data.
     +
    @@ -2633,7 +3993,7 @@ index 8b80ae949..0791ee9a2 100644
      }
      
      static void WriteSyncsafeInteger(uint8_t *dst, size_t x) {
    -@@ -392,7 +404,12 @@ bool ID3::removeUnsynchronizationV2_4(bool iTunesHack) {
    +@@ -392,7 +405,12 @@ bool ID3::removeUnsynchronizationV2_4(bool iTunesHack) {
                          --mSize;
                          --dataSize;
                      }
    @@ -2647,6 +4007,16 @@ index 8b80ae949..0791ee9a2 100644
                  }
                  // move the remaining data following this frame
                  if (readOffset <= oldSize) {
    +@@ -585,6 +603,9 @@ void ID3::Iterator::getstring(String8 *id, bool otherdata) const {
    +         // UCS-2
    +         // API wants number of characters, not number of bytes...
    +         int len = n / 2;
    ++        if (len == 0) {
    ++            return;
    ++        }
    +         const char16_t *framedata = (const char16_t *) (frameData + 1);
    +         char16_t *framedatacopy = NULL;
    +         if (*framedata == 0xfffe) {
     diff --git a/media/libstagefright/include/OMXNodeInstance.h b/media/libstagefright/include/OMXNodeInstance.h
     index 94cf15abd..dd396e812 100644
     --- a/media/libstagefright/include/OMXNodeInstance.h
    diff --git a/frameworks_base.patch b/frameworks_base.patch
    index 3ea3479..7034917 100644
    --- a/frameworks_base.patch
    +++ b/frameworks_base.patch
    @@ -50,6 +50,85 @@ index 5cfcac33050..010b871c1d4 100644
                  final Network network = cm.getBoundNetworkForProcess();
                  if (network != null) {
                      Proxy.setHttpProxySystemProperty(cm.getDefaultProxy());
    +diff --git a/core/java/android/app/DownloadManager.java b/core/java/android/app/DownloadManager.java
    +index 6e38347f7c9..462f66f38de 100644
    +--- a/core/java/android/app/DownloadManager.java
    ++++ b/core/java/android/app/DownloadManager.java
    +@@ -832,6 +832,7 @@ public class DownloadManager {
    + 
    +         private long[] mIds = null;
    +         private Integer mStatusFlags = null;
    ++        private String mFilterString = null;
    +         private String mOrderByColumn = Downloads.Impl.COLUMN_LAST_MODIFICATION;
    +         private int mOrderDirection = ORDER_DESCENDING;
    +         private boolean mOnlyIncludeVisibleInDownloadsUi = false;
    +@@ -845,6 +846,17 @@ public class DownloadManager {
    +             return this;
    +         }
    + 
    ++        /**
    ++         *
    ++         * Include only the downloads that contains the given string in its name.
    ++         * @return this object
    ++         * @hide
    ++         */
    ++        public Query setFilterByString(@Nullable String filter) {
    ++            mFilterString = filter;
    ++            return this;
    ++        }
    ++
    +         /**
    +          * Include only downloads with status matching any the given status flags.
    +          * @param flags any combination of the STATUS_* bit flags
    +@@ -904,9 +916,20 @@ public class DownloadManager {
    +             List<String> selectionParts = new ArrayList<String>();
    +             String[] selectionArgs = null;
    + 
    +-            if (mIds != null) {
    +-                selectionParts.add(getWhereClauseForIds(mIds));
    +-                selectionArgs = getWhereArgsForIds(mIds);
    ++            int whereArgsCount = (mIds == null) ? 0 : mIds.length;
    ++            whereArgsCount = (mFilterString == null) ? whereArgsCount : whereArgsCount + 1;
    ++            selectionArgs = new String[whereArgsCount];
    ++
    ++            if (whereArgsCount > 0) {
    ++                if (mIds != null) {
    ++                    selectionParts.add(getWhereClauseForIds(mIds));
    ++                    getWhereArgsForIds(mIds, selectionArgs);
    ++                }
    ++
    ++                if (mFilterString != null) {
    ++                    selectionParts.add(Downloads.Impl.COLUMN_TITLE + " LIKE ?");
    ++                    selectionArgs[selectionArgs.length - 1] = "%" + mFilterString + "%";
    ++                }
    +             }
    + 
    +             if (mStatusFlags != null) {
    +@@ -1450,12 +1473,22 @@ public class DownloadManager {
    +      */
    +     static String[] getWhereArgsForIds(long[] ids) {
    +         String[] whereArgs = new String[ids.length];
    ++        return getWhereArgsForIds(ids, whereArgs);
    ++    }
    ++
    ++    /**
    ++     * Get selection args for a clause returned by {@link #getWhereClauseForIds(long[])}
    ++     * and write it to the supplied args array.
    ++     */
    ++    static String[] getWhereArgsForIds(long[] ids, String[] args) {
    ++        assert(args.length >= ids.length);
    +         for (int i = 0; i < ids.length; i++) {
    +-            whereArgs[i] = Long.toString(ids[i]);
    ++            args[i] = Long.toString(ids[i]);
    +         }
    +-        return whereArgs;
    ++        return args;
    +     }
    + 
    ++
    +     /**
    +      * This class wraps a cursor returned by DownloadProvider -- the "underlying cursor" -- and
    +      * presents a different set of columns, those defined in the DownloadManager.COLUMN_* constants.
     diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java
     index 0dd9c63c40c..bcdf3f49251 100644
     --- a/core/java/android/app/Notification.java
    @@ -130,7 +209,7 @@ index cd5eff29237..d329175646e 100644
              return null;
          }
     diff --git a/core/java/android/content/ContentProvider.java b/core/java/android/content/ContentProvider.java
    -index bc2d788bf4c..1072b5d7902 100644
    +index bc2d788bf4c..e61ac70de8d 100644
     --- a/core/java/android/content/ContentProvider.java
     +++ b/core/java/android/content/ContentProvider.java
     @@ -53,6 +53,7 @@ import java.io.IOException;
    @@ -141,22 +220,25 @@ index bc2d788bf4c..1072b5d7902 100644
      
      /**
       * Content providers are one of the primary building blocks of Android applications, providing
    -@@ -207,7 +208,7 @@ public abstract class ContentProvider implements ComponentCallbacks2 {
    +@@ -207,8 +208,8 @@ public abstract class ContentProvider implements ComponentCallbacks2 {
              public Cursor query(String callingPkg, Uri uri, String[] projection,
                      String selection, String[] selectionArgs, String sortOrder,
                      ICancellationSignal cancellationSignal) {
     -            validateIncomingUri(uri);
    +-            uri = getUriWithoutUserId(uri);
     +            uri = validateIncomingUri(uri);
    -             uri = getUriWithoutUserId(uri);
    ++            uri = maybeGetUriWithoutUserId(uri);
                  if (enforceReadPermission(callingPkg, uri, null) != AppOpsManager.MODE_ALLOWED) {
                      // The caller has no access to the data, so return an empty cursor with
    -@@ -246,14 +247,14 @@ public abstract class ContentProvider implements ComponentCallbacks2 {
    +                 // the columns in the requested order. The caller may ask for an invalid
    +@@ -246,16 +247,16 @@ public abstract class ContentProvider implements ComponentCallbacks2 {
      
              @Override
              public String getType(Uri uri) {
     -            validateIncomingUri(uri);
    +-            uri = getUriWithoutUserId(uri);
     +            uri = validateIncomingUri(uri);
    -             uri = getUriWithoutUserId(uri);
    ++            uri = maybeGetUriWithoutUserId(uri);
                  return ContentProvider.this.getType(uri);
              }
      
    @@ -165,17 +247,22 @@ index bc2d788bf4c..1072b5d7902 100644
     -            validateIncomingUri(uri);
     +            uri = validateIncomingUri(uri);
                  int userId = getUserIdFromUri(uri);
    -             uri = getUriWithoutUserId(uri);
    +-            uri = getUriWithoutUserId(uri);
    ++            uri = maybeGetUriWithoutUserId(uri);
                  if (enforceWritePermission(callingPkg, uri, null) != AppOpsManager.MODE_ALLOWED) {
    -@@ -269,7 +270,7 @@ public abstract class ContentProvider implements ComponentCallbacks2 {
    +                 return rejectInsert(uri, initialValues);
    +             }
    +@@ -269,8 +270,8 @@ public abstract class ContentProvider implements ComponentCallbacks2 {
      
              @Override
              public int bulkInsert(String callingPkg, Uri uri, ContentValues[] initialValues) {
     -            validateIncomingUri(uri);
    +-            uri = getUriWithoutUserId(uri);
     +            uri = validateIncomingUri(uri);
    -             uri = getUriWithoutUserId(uri);
    ++            uri = maybeGetUriWithoutUserId(uri);
                  if (enforceWritePermission(callingPkg, uri, null) != AppOpsManager.MODE_ALLOWED) {
                      return 0;
    +             }
     @@ -291,11 +292,12 @@ public abstract class ContentProvider implements ComponentCallbacks2 {
                  for (int i = 0; i < numOperations; i++) {
                      ContentProviderOperation operation = operations.get(i);
    @@ -186,67 +273,79 @@ index bc2d788bf4c..1072b5d7902 100644
     -                    // Removing the user id from the uri.
     -                    operation = new ContentProviderOperation(operation, true);
     +                uri = validateIncomingUri(uri);
    -+                uri = getUriWithoutUserId(uri);
    ++                uri = maybeGetUriWithoutUserId(uri);
     +                // Rebuild operation if we changed the Uri above
     +                if (!Objects.equals(operation.getUri(), uri)) {
     +                    operation = new ContentProviderOperation(operation, uri);
                          operations.set(i, operation);
                      }
                      if (operation.isReadOperation()) {
    -@@ -330,7 +332,7 @@ public abstract class ContentProvider implements ComponentCallbacks2 {
    +@@ -330,8 +332,8 @@ public abstract class ContentProvider implements ComponentCallbacks2 {
      
              @Override
              public int delete(String callingPkg, Uri uri, String selection, String[] selectionArgs) {
     -            validateIncomingUri(uri);
    +-            uri = getUriWithoutUserId(uri);
     +            uri = validateIncomingUri(uri);
    -             uri = getUriWithoutUserId(uri);
    ++            uri = maybeGetUriWithoutUserId(uri);
                  if (enforceWritePermission(callingPkg, uri, null) != AppOpsManager.MODE_ALLOWED) {
                      return 0;
    -@@ -346,7 +348,7 @@ public abstract class ContentProvider implements ComponentCallbacks2 {
    +             }
    +@@ -346,8 +348,8 @@ public abstract class ContentProvider implements ComponentCallbacks2 {
              @Override
              public int update(String callingPkg, Uri uri, ContentValues values, String selection,
                      String[] selectionArgs) {
     -            validateIncomingUri(uri);
    +-            uri = getUriWithoutUserId(uri);
     +            uri = validateIncomingUri(uri);
    -             uri = getUriWithoutUserId(uri);
    ++            uri = maybeGetUriWithoutUserId(uri);
                  if (enforceWritePermission(callingPkg, uri, null) != AppOpsManager.MODE_ALLOWED) {
                      return 0;
    -@@ -363,7 +365,7 @@ public abstract class ContentProvider implements ComponentCallbacks2 {
    +             }
    +@@ -363,8 +365,8 @@ public abstract class ContentProvider implements ComponentCallbacks2 {
              public ParcelFileDescriptor openFile(
                      String callingPkg, Uri uri, String mode, ICancellationSignal cancellationSignal,
                      IBinder callerToken) throws FileNotFoundException {
     -            validateIncomingUri(uri);
    +-            uri = getUriWithoutUserId(uri);
     +            uri = validateIncomingUri(uri);
    -             uri = getUriWithoutUserId(uri);
    ++            uri = maybeGetUriWithoutUserId(uri);
                  enforceFilePermission(callingPkg, uri, mode, callerToken);
                  final String original = setCallingPackage(callingPkg);
    -@@ -379,7 +381,7 @@ public abstract class ContentProvider implements ComponentCallbacks2 {
    +             try {
    +@@ -379,8 +381,8 @@ public abstract class ContentProvider implements ComponentCallbacks2 {
              public AssetFileDescriptor openAssetFile(
                      String callingPkg, Uri uri, String mode, ICancellationSignal cancellationSignal)
                      throws FileNotFoundException {
     -            validateIncomingUri(uri);
    +-            uri = getUriWithoutUserId(uri);
     +            uri = validateIncomingUri(uri);
    -             uri = getUriWithoutUserId(uri);
    ++            uri = maybeGetUriWithoutUserId(uri);
                  enforceFilePermission(callingPkg, uri, mode, null);
                  final String original = setCallingPackage(callingPkg);
    -@@ -405,7 +407,7 @@ public abstract class ContentProvider implements ComponentCallbacks2 {
    +             try {
    +@@ -405,8 +407,8 @@ public abstract class ContentProvider implements ComponentCallbacks2 {
      
              @Override
              public String[] getStreamTypes(Uri uri, String mimeTypeFilter) {
     -            validateIncomingUri(uri);
    +-            uri = getUriWithoutUserId(uri);
     +            uri = validateIncomingUri(uri);
    -             uri = getUriWithoutUserId(uri);
    ++            uri = maybeGetUriWithoutUserId(uri);
                  return ContentProvider.this.getStreamTypes(uri, mimeTypeFilter);
              }
    -@@ -414,7 +416,7 @@ public abstract class ContentProvider implements ComponentCallbacks2 {
    + 
    +@@ -414,8 +416,8 @@ public abstract class ContentProvider implements ComponentCallbacks2 {
              public AssetFileDescriptor openTypedAssetFile(String callingPkg, Uri uri, String mimeType,
                      Bundle opts, ICancellationSignal cancellationSignal) throws FileNotFoundException {
                  Bundle.setDefusable(opts, true);
     -            validateIncomingUri(uri);
    +-            uri = getUriWithoutUserId(uri);
     +            uri = validateIncomingUri(uri);
    -             uri = getUriWithoutUserId(uri);
    ++            uri = maybeGetUriWithoutUserId(uri);
                  enforceFilePermission(callingPkg, uri, "r", null);
                  final String original = setCallingPackage(callingPkg);
    +             try {
     @@ -433,7 +435,7 @@ public abstract class ContentProvider implements ComponentCallbacks2 {
      
              @Override
    @@ -274,16 +373,27 @@ index bc2d788bf4c..1072b5d7902 100644
                      mTransport.mAppOpsManager = (AppOpsManager) context.getSystemService(
                              Context.APP_OPS_SERVICE);
                  }
    -@@ -1844,7 +1846,7 @@ public abstract class ContentProvider implements ComponentCallbacks2 {
    +@@ -1844,12 +1846,14 @@ public abstract class ContentProvider implements ComponentCallbacks2 {
          }
      
          /** @hide */
     -    private void validateIncomingUri(Uri uri) throws SecurityException {
     +    public Uri validateIncomingUri(Uri uri) throws SecurityException {
              String auth = uri.getAuthority();
    -         int userId = getUserIdFromAuthority(auth, UserHandle.USER_CURRENT);
    -         if (userId != UserHandle.USER_CURRENT && userId != mContext.getUserId()) {
    -@@ -1861,6 +1863,19 @@ public abstract class ContentProvider implements ComponentCallbacks2 {
    +-        int userId = getUserIdFromAuthority(auth, UserHandle.USER_CURRENT);
    +-        if (userId != UserHandle.USER_CURRENT && userId != mContext.getUserId()) {
    +-            throw new SecurityException("trying to query a ContentProvider in user "
    +-                    + mContext.getUserId() + " with a uri belonging to user " + userId);
    ++        if (!mSingleUser) {
    ++            int userId = getUserIdFromAuthority(auth, UserHandle.USER_CURRENT);
    ++            if (userId != UserHandle.USER_CURRENT && userId != mContext.getUserId()) {
    ++                throw new SecurityException("trying to query a ContentProvider in user "
    ++                        + mContext.getUserId() + " with a uri belonging to user " + userId);
    ++            }
    +         }
    +         if (!matchesOurAuthorities(getAuthorityWithoutUserId(auth))) {
    +             String message = "The authority of the uri " + uri + " does not match the one of the "
    +@@ -1861,6 +1865,27 @@ public abstract class ContentProvider implements ComponentCallbacks2 {
                  }
                  throw new SecurityException(message);
              }
    @@ -300,6 +410,14 @@ index bc2d788bf4c..1072b5d7902 100644
     +        } else {
     +            return uri;
     +        }
    ++    }
    ++
    ++    /** @hide */
    ++    private Uri maybeGetUriWithoutUserId(Uri uri) {
    ++        if (mSingleUser) {
    ++            return uri;
    ++        }
    ++        return getUriWithoutUserId(uri);
          }
      
          /** @hide */
    @@ -501,6 +619,54 @@ index 00000000000..a4b2fe0c10e
     +                Binder.getCallingUid(), packageName);
     +    }
     +}
    +diff --git a/core/java/android/content/pm/PackageItemInfo.java b/core/java/android/content/pm/PackageItemInfo.java
    +index bc79f41b1fc..73ae83e32f6 100644
    +--- a/core/java/android/content/pm/PackageItemInfo.java
    ++++ b/core/java/android/content/pm/PackageItemInfo.java
    +@@ -46,6 +46,9 @@ import java.util.Comparator;
    +  */
    + public class PackageItemInfo {
    +     private static final float MAX_LABEL_SIZE_PX = 500f;
    ++    /** The maximum length of a safe label, in characters */
    ++    private static final int MAX_SAFE_LABEL_LENGTH = 50000;
    ++
    +     /**
    +      * Public name of this item. From the "android:name" attribute.
    +      */
    +@@ -173,7 +176,8 @@ public class PackageItemInfo {
    +         // If the label contains new line characters it may push the UI
    +         // down to hide a part of it. Labels shouldn't have new line
    +         // characters, so just truncate at the first time one is seen.
    +-        final int labelLength = labelStr.length();
    ++        final int labelLength = Math.min(labelStr.length(), MAX_SAFE_LABEL_LENGTH);
    ++        final StringBuffer sb = new StringBuffer(labelLength);
    +         int offset = 0;
    +         while (offset < labelLength) {
    +             final int codePoint = labelStr.codePointAt(offset);
    +@@ -185,14 +189,19 @@ public class PackageItemInfo {
    +                 break;
    +             }
    +             // replace all non-break space to " " in order to be trimmed
    ++            final int charCount = Character.charCount(codePoint);
    +             if (type == Character.SPACE_SEPARATOR) {
    +-                labelStr = labelStr.substring(0, offset) + " " + labelStr.substring(offset +
    +-                        Character.charCount(codePoint));
    ++                sb.append(' ');
    ++            } else {
    ++                sb.append(labelStr.charAt(offset));
    ++                if (charCount == 2) {
    ++                    sb.append(labelStr.charAt(offset + 1));
    ++                }
    +             }
    +-            offset += Character.charCount(codePoint);
    ++            offset += charCount;
    +         }
    + 
    +-        labelStr = labelStr.trim();
    ++        labelStr = sb.toString().trim();
    +         if (labelStr.isEmpty()) {
    +             return packageName;
    +         }
     diff --git a/core/java/android/content/pm/RegisteredServicesCache.java b/core/java/android/content/pm/RegisteredServicesCache.java
     index a1103838280..aea843adbd4 100644
     --- a/core/java/android/content/pm/RegisteredServicesCache.java
    @@ -1063,7 +1229,7 @@ index 674f809ef0f..70dfef574ca 100644
              }
              try {
     diff --git a/core/java/android/text/Layout.java b/core/java/android/text/Layout.java
    -index 0bd5071b6ea..bc55ee798e2 100644
    +index 0bd5071b6ea..3bc9390c581 100644
     --- a/core/java/android/text/Layout.java
     +++ b/core/java/android/text/Layout.java
     @@ -824,6 +824,32 @@ public abstract class Layout {
    @@ -1099,10 +1265,52 @@ index 0bd5071b6ea..bc55ee798e2 100644
          private boolean primaryIsTrailingPrevious(int offset) {
              int line = getLineForOffset(offset);
              int lineStart = getLineStart(line);
    -@@ -873,6 +899,95 @@ public abstract class Layout {
    +@@ -873,6 +899,41 @@ public abstract class Layout {
              return levelBefore < levelAt;
          }
      
    ++    /**
    ++     * Computes in linear time the results of calling
    ++     * #primaryIsTrailingPrevious for all offsets on a line.
    ++     * @param line The line giving the offsets we compute the information for
    ++     * @return The array of results, indexed from 0, where 0 corresponds to the line start offset
    ++     */
    ++    private boolean[] primaryIsTrailingPreviousAllLineOffsets(int line) {
    ++        int lineStart = getLineStart(line);
    ++        int lineEnd = getLineEnd(line);
    ++        int[] runs = getLineDirections(line).mDirections;
    ++
    ++        boolean[] trailing = new boolean[lineEnd - lineStart + 1];
    ++
    ++        byte[] level = new byte[lineEnd - lineStart + 1];
    ++        for (int i = 0; i < runs.length; i += 2) {
    ++            int start = lineStart + runs[i];
    ++            int limit = start + (runs[i + 1] & RUN_LENGTH_MASK);
    ++            if (limit > lineEnd) {
    ++                limit = lineEnd;
    ++            }
    ++            level[limit - lineStart - 1] =
    ++                    (byte) ((runs[i + 1] >>> RUN_LEVEL_SHIFT) & RUN_LEVEL_MASK);
    ++        }
    ++
    ++        for (int i = 0; i < runs.length; i += 2) {
    ++            int start = lineStart + runs[i];
    ++            byte currentLevel = (byte) ((runs[i + 1] >>> RUN_LEVEL_SHIFT) & RUN_LEVEL_MASK);
    ++            trailing[start - lineStart] = currentLevel > (start == lineStart
    ++                    ? (getParagraphDirection(line) == 1 ? 0 : 1)
    ++                    : level[start - lineStart - 1]);
    ++        }
    ++
    ++        return trailing;
    ++    }
    ++
    +     /**
    +      * Get the primary horizontal position for the specified text offset.
    +      * This is the location where a new character would be inserted in
    +@@ -952,6 +1013,60 @@ public abstract class Layout {
    +         return getLineStartPos(line, left, right) + wid;
    +     }
    + 
     +    /**
     +     * Computes in linear time the results of calling
     +     * #getHorizontal for all offsets on a line.
    @@ -1156,53 +1364,25 @@ index 0bd5071b6ea..bc55ee798e2 100644
     +        }
     +        return horizontal;
     +    }
    -+
    -+    /**
    -+     * Computes in linear time the results of calling
    -+     * #primaryIsTrailingPrevious for all offsets on a line.
    -+     * @param line The line giving the offsets we compute the information for
    -+     * @return The array of results, indexed from 0, where 0 corresponds to the line start offset
    -+     */
    -+    private boolean[] primaryIsTrailingPreviousAllLineOffsets(int line) {
    -+        int lineStart = getLineStart(line);
    -+        int lineEnd = getLineEnd(line);
    -+        int[] runs = getLineDirections(line).mDirections;
    -+
    -+        boolean[] trailing = new boolean[lineEnd - lineStart + 1];
    -+
    -+        byte[] level = new byte[lineEnd - lineStart + 1];
    -+        for (int i = 0; i < runs.length; i += 2) {
    -+            int start = lineStart + runs[i];
    -+            int limit = start + (runs[i + 1] & RUN_LENGTH_MASK);
    -+            if (limit > lineEnd) {
    -+                limit = lineEnd;
    -+            }
    -+            level[limit - lineStart - 1] =
    -+                    (byte) ((runs[i + 1] >>> RUN_LEVEL_SHIFT) & RUN_LEVEL_MASK);
    -+        }
    -+
    -+        for (int i = 0; i < runs.length; i += 2) {
    -+            int start = lineStart + runs[i];
    -+            byte currentLevel = (byte) ((runs[i + 1] >>> RUN_LEVEL_SHIFT) & RUN_LEVEL_MASK);
    -+            trailing[start - lineStart] = currentLevel > (start == lineStart
    -+                    ? (getParagraphDirection(line) == 1 ? 0 : 1)
    -+                    : level[start - lineStart - 1]);
    -+        }
    -+
    -+        return trailing;
    -+    }
     +
          /**
    -      * Get the primary horizontal position for the specified text offset.
    -      * This is the location where a new character would be inserted in
    -@@ -1176,7 +1291,9 @@ public abstract class Layout {
    +      * Get the leftmost position that should be exposed for horizontal
    +      * scrolling on the specified line.
    +@@ -1167,6 +1282,8 @@ public abstract class Layout {
    +         // XXX: we don't care about tabs as we just use TextLine#getOffsetToLeftRightOf here.
    +         tl.set(mPaint, mText, lineStartOffset, lineEndOffset, getParagraphDirection(line), dirs,
    +                 false, null);
    ++        final HorizontalMeasurementProvider horizontal =
    ++                new HorizontalMeasurementProvider(line, primary);
    + 
    +         final int max;
    +         if (line == getLineCount() - 1) {
    +@@ -1176,7 +1293,7 @@ public abstract class Layout {
                          !isRtlCharAt(lineEndOffset - 1)) + lineStartOffset;
              }
              int best = lineStartOffset;
     -        float bestdist = Math.abs(getHorizontal(best, primary) - horiz);
    -+	final HorizontalMeasurementProvider horizontal =
    -+              new HorizontalMeasurementProvider(line);
    -+	float bestdist = Math.abs(horizontal.get(best) - horiz);
    ++        float bestdist = Math.abs(horizontal.get(lineStartOffset) - horiz);
      
              for (int i = 0; i < dirs.mDirections.length; i += 2) {
                  int here = lineStartOffset + dirs.mDirections[i];
    @@ -1245,7 +1425,7 @@ index 0bd5071b6ea..bc55ee798e2 100644
      
              if (dist <= bestdist) {
                  bestdist = dist;
    -@@ -1241,6 +1358,45 @@ public abstract class Layout {
    +@@ -1241,6 +1358,47 @@ public abstract class Layout {
              return best;
          }
      
    @@ -1259,12 +1439,14 @@ index 0bd5071b6ea..bc55ee798e2 100644
     +     */
     +    private class HorizontalMeasurementProvider {
     +        private final int mLine;
    ++        private final boolean mPrimary;
     +
     +        private float[] mHorizontals;
     +        private int mLineStartOffset;
     +
    -+        HorizontalMeasurementProvider(final int line) {
    ++        HorizontalMeasurementProvider(final int line, final boolean primary) {
     +            mLine = line;
    ++            mPrimary = primary;
     +            init();
     +        }
     +
    @@ -1274,14 +1456,14 @@ index 0bd5071b6ea..bc55ee798e2 100644
     +                return;
     +            }
     +
    -+            mHorizontals = getLineHorizontals(mLine, false, true);
    ++            mHorizontals = getLineHorizontals(mLine, false, mPrimary);
     +            mLineStartOffset = getLineStart(mLine);
     +        }
     +
     +        float get(final int offset) {
     +            if (mHorizontals == null || offset < mLineStartOffset
     +                    || offset >= mLineStartOffset + mHorizontals.length) {
    -+                return getPrimaryHorizontal(offset);
    ++                return getHorizontal(offset, mPrimary);
     +            } else {
     +                return mHorizontals[offset - mLineStartOffset];
     +            }
    @@ -1394,6 +1576,82 @@ index 2a52961984f..79333563af1 100644
          /**
           * Draws a unidirectional (but possibly multi-styled) run of text.
           *
    +diff --git a/core/java/android/text/util/Linkify.java b/core/java/android/text/util/Linkify.java
    +index ca037a229b0..51ef650c000 100644
    +--- a/core/java/android/text/util/Linkify.java
    ++++ b/core/java/android/text/util/Linkify.java
    +@@ -23,6 +23,7 @@ import android.telephony.PhoneNumberUtils;
    + import android.text.method.LinkMovementMethod;
    + import android.text.method.MovementMethod;
    + import android.text.style.URLSpan;
    ++import android.util.Log;
    + import android.text.Spannable;
    + import android.text.SpannableString;
    + import android.text.Spanned;
    +@@ -65,6 +66,9 @@ import libcore.util.EmptyArray;
    +  */
    + 
    + public class Linkify {
    ++
    ++    private static final String LOG_TAG = "Linkify";
    ++
    +     /**
    +      *  Bit field indicating that web URLs should be matched in methods that
    +      *  take an options mask
    +@@ -222,6 +226,11 @@ public class Linkify {
    +      *  @return True if at least one link is found and applied.
    +      */
    +     public static final boolean addLinks(@NonNull Spannable text, @LinkifyMask int mask) {
    ++        if (text != null && containsUnsupportedCharacters(text.toString())) {
    ++            android.util.EventLog.writeEvent(0x534e4554, "116321860", -1, "");
    ++            return false;
    ++        }
    ++
    +         if (mask == 0) {
    +             return false;
    +         }
    +@@ -267,6 +276,29 @@ public class Linkify {
    +         return true;
    +     }
    + 
    ++    /**
    ++     * Returns true if the specified text contains at least one unsupported character for applying
    ++     * links. Also logs the error.
    ++     *
    ++     * @param text the text to apply links to
    ++     * @hide
    ++     */
    ++    public static boolean containsUnsupportedCharacters(String text) {
    ++        if (text.contains("\u202C")) {
    ++            Log.e(LOG_TAG, "Unsupported character for applying links: u202C");
    ++            return true;
    ++        }
    ++        if (text.contains("\u202D")) {
    ++            Log.e(LOG_TAG, "Unsupported character for applying links: u202D");
    ++            return true;
    ++        }
    ++        if (text.contains("\u202E")) {
    ++            Log.e(LOG_TAG, "Unsupported character for applying links: u202E");
    ++            return true;
    ++        }
    ++        return false;
    ++    }
    ++
    +     /**
    +      *  Scans the text of the provided TextView and turns all occurrences of
    +      *  the link types indicated in the mask into clickable links.  If matches
    +@@ -437,6 +469,11 @@ public class Linkify {
    +     public static final boolean addLinks(@NonNull Spannable spannable, @NonNull Pattern pattern,
    +             @Nullable  String defaultScheme, @Nullable String[] schemes,
    +             @Nullable MatchFilter matchFilter, @Nullable TransformFilter transformFilter) {
    ++        if (spannable != null && containsUnsupportedCharacters(spannable.toString())) {
    ++            android.util.EventLog.writeEvent(0x534e4554, "116321860", -1, "");
    ++            return false;
    ++        }
    ++
    +         final String[] schemesCopy;
    +         if (defaultScheme == null) defaultScheme = "";
    +         if (schemes == null || schemes.length < 1) {
     diff --git a/core/java/android/view/WindowManager.java b/core/java/android/view/WindowManager.java
     index 395f73844b0..169f7e170dd 100644
     --- a/core/java/android/view/WindowManager.java
    @@ -1604,6 +1862,19 @@ index d5b6def9742..df1ed7d392b 100644
                  if (loader == null) {
                      loader = getClass().getClassLoader();
                  }
    +diff --git a/core/jni/android/graphics/Bitmap.cpp b/core/jni/android/graphics/Bitmap.cpp
    +index 72755ce105c..3e6fe3f38a5 100755
    +--- a/core/jni/android/graphics/Bitmap.cpp
    ++++ b/core/jni/android/graphics/Bitmap.cpp
    +@@ -725,6 +725,8 @@ static jobject Bitmap_creator(JNIEnv* env, jobject, jintArray jColors,
    + 
    +     Bitmap* nativeBitmap = GraphicsJNI::allocateJavaPixelRef(env, &bitmap, NULL);
    +     if (!nativeBitmap) {
    ++        ALOGE("OOM allocating Bitmap with dimensions %i x %i", width, height);
    ++        doThrowOOME(env);
    +         return NULL;
    +     }
    + 
     diff --git a/core/jni/android/graphics/BitmapFactory.cpp b/core/jni/android/graphics/BitmapFactory.cpp
     index 4001283c4c6..0a143610ebd 100644
     --- a/core/jni/android/graphics/BitmapFactory.cpp
    @@ -1719,6 +1990,88 @@ index 011884cb549..8403e80ae31 100644
          <!-- @SystemApi Allows an application to manage (create, destroy,
               Z-order) application tokens in the window manager.
               <p>Not for use by third-party applications.
    +diff --git a/core/res/res/drawable-sw600dp-nodpi/default_wallpaper.png b/core/res/res/drawable-sw600dp-nodpi/default_wallpaper.png
    +index af8e2512385..52af11d8f5a 100644
    +Binary files a/core/res/res/drawable-sw600dp-nodpi/default_wallpaper.png and b/core/res/res/drawable-sw600dp-nodpi/default_wallpaper.png differ
    +diff --git a/core/res/res/drawable-sw720dp-nodpi/default_wallpaper.png b/core/res/res/drawable-sw720dp-nodpi/default_wallpaper.png
    +index cb00d82a826..e3e66721c86 100644
    +Binary files a/core/res/res/drawable-sw720dp-nodpi/default_wallpaper.png and b/core/res/res/drawable-sw720dp-nodpi/default_wallpaper.png differ
    +diff --git a/core/res/res/values-mcc302-mnc220/config.xml b/core/res/res/values-mcc302-mnc220/config.xml
    +index 422f7c92648..e6ddadc37cc 100644
    +--- a/core/res/res/values-mcc302-mnc220/config.xml
    ++++ b/core/res/res/values-mcc302-mnc220/config.xml
    +@@ -50,7 +50,7 @@
    +         <item>ERR_ESTIMATE=0</item>
    +         <item>INTERMEDIATE_POS=0</item>
    +         <item>GPS_LOCK=0</item>
    +-        <item>SUPL_ES=0</item>
    ++        <item>SUPL_ES=1</item>
    +     </string-array>
    + 
    + </resources>
    +diff --git a/core/res/res/values-mcc302-mnc221/config.xml b/core/res/res/values-mcc302-mnc221/config.xml
    +index 14442500757..0f01f537902 100644
    +--- a/core/res/res/values-mcc302-mnc221/config.xml
    ++++ b/core/res/res/values-mcc302-mnc221/config.xml
    +@@ -48,7 +48,7 @@
    +         <item>ERR_ESTIMATE=0</item>
    +         <item>INTERMEDIATE_POS=0</item>
    +         <item>GPS_LOCK=0</item>
    +-        <item>SUPL_ES=0</item>
    ++        <item>SUPL_ES=1</item>
    +     </string-array>
    + 
    + </resources>
    +diff --git a/core/res/res/values-mcc302-mnc370/config.xml b/core/res/res/values-mcc302-mnc370/config.xml
    +index 05265c7fcd7..9231691db58 100644
    +--- a/core/res/res/values-mcc302-mnc370/config.xml
    ++++ b/core/res/res/values-mcc302-mnc370/config.xml
    +@@ -59,7 +59,7 @@
    +         <item>ERR_ESTIMATE=0</item>
    +         <item>INTERMEDIATE_POS=0</item>
    +         <item>GPS_LOCK=0</item>
    +-        <item>SUPL_ES=0</item>
    ++        <item>SUPL_ES=1</item>
    +     </string-array>
    + 
    + </resources>
    +diff --git a/core/res/res/values-mcc302-mnc610/config.xml b/core/res/res/values-mcc302-mnc610/config.xml
    +index 0af2c39e786..b85da2bf047 100644
    +--- a/core/res/res/values-mcc302-mnc610/config.xml
    ++++ b/core/res/res/values-mcc302-mnc610/config.xml
    +@@ -43,6 +43,6 @@
    +         <item>ERR_ESTIMATE=0</item>
    +         <item>INTERMEDIATE_POS=0</item>
    +         <item>GPS_LOCK=0</item>
    +-        <item>SUPL_ES=0</item>
    ++        <item>SUPL_ES=1</item>
    +     </string-array>
    + </resources>
    +diff --git a/core/res/res/values-mcc302-mnc640/config.xml b/core/res/res/values-mcc302-mnc640/config.xml
    +index e005bc00a27..0454c580442 100644
    +--- a/core/res/res/values-mcc302-mnc640/config.xml
    ++++ b/core/res/res/values-mcc302-mnc640/config.xml
    +@@ -39,6 +39,6 @@
    +         <item>ERR_ESTIMATE=0</item>
    +         <item>INTERMEDIATE_POS=0</item>
    +         <item>GPS_LOCK=0</item>
    +-        <item>SUPL_ES=0</item>
    ++        <item>SUPL_ES=1</item>
    +     </string-array>
    + </resources>
    +diff --git a/core/res/res/values-mcc302-mnc720/config.xml b/core/res/res/values-mcc302-mnc720/config.xml
    +index 7a3540aa3bd..eef85e18e8d 100644
    +--- a/core/res/res/values-mcc302-mnc720/config.xml
    ++++ b/core/res/res/values-mcc302-mnc720/config.xml
    +@@ -61,7 +61,7 @@
    +         <item>ERR_ESTIMATE=0</item>
    +         <item>INTERMEDIATE_POS=0</item>
    +         <item>GPS_LOCK=0</item>
    +-        <item>SUPL_ES=0</item>
    ++        <item>SUPL_ES=1</item>
    +     </string-array>
    + 
    + </resources>
     diff --git a/core/res/res/values-mcc310-mnc490-fr/strings.xml b/core/res/res/values-mcc310-mnc490-fr/strings.xml
     deleted file mode 100644
     index 33e0c97b2fb..00000000000
    @@ -1758,25 +2111,38 @@ index 33e0c97b2fb..00000000000
     -    <string name="wfcSpnFormat" msgid="1518868466785799436">"Appels Wi-Fi %s"</string>
     -</resources>
     diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
    -index 7baed78a51b..a0fbdac7360 100644
    +index 7baed78a51b..bf421043bc2 100644
     --- a/core/res/res/values/config.xml
     +++ b/core/res/res/values/config.xml
    -@@ -2710,4 +2710,6 @@
    +@@ -2325,6 +2325,7 @@
    +         <item>NTP_SERVER=north-america.pool.ntp.org</item>
    +         <item>SUPL_VER=0x20000</item>
    +         <item>SUPL_MODE=1</item>
    ++        <item>SUPL_ES=1</item>
    +     </string-array>
    + 
    +     <!-- If there is no preload VM number in the sim card, carriers such as
    +@@ -2710,4 +2711,10 @@
               is installed. -->
          <bool name="config_permissionReviewRequired">false</bool>
      
    ++    <!-- Older rotation sensors are not setting event.timestamp correctly. Setting to
    ++         true will use SystemClock.elapsedRealtimeNanos() to set timestamp. -->
    ++    <bool name="config_useSystemClockforRotationSensor">false</bool>
    ++
     +    <!-- Whether to enable HumanInteractionController by default -->
     +    <bool name="config_HICEnabledDefault">true</bool>
      </resources>
     diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
    -index 08ac0436d63..9e6f3b8b83f 100644
    +index 08ac0436d63..82a2ff12d5d 100644
     --- a/core/res/res/values/symbols.xml
     +++ b/core/res/res/values/symbols.xml
    -@@ -2749,4 +2749,7 @@
    +@@ -2749,4 +2749,8 @@
        <java-symbol type="bool" name="use_lock_pattern_drawable" />
        <java-symbol type="drawable" name="lockscreen_notselected" />
        <java-symbol type="drawable" name="lockscreen_selected" />
     +
    ++  <java-symbol type="bool" name="config_useSystemClockforRotationSensor" />
     +  <!-- Whether to enable HumanInteractionController by default -->
     +  <java-symbol type="bool" name="config_HICEnabledDefault" />
      </resources>
    @@ -1831,8 +2197,31 @@ index 6fa28b1ccda..ea0347d67ad 100644
          }
      
          @SmallTest
    +diff --git a/core/tests/coretests/src/android/widget/TextViewActivityTest.java b/core/tests/coretests/src/android/widget/TextViewActivityTest.java
    +index 67ffd2b0ca3..381597670f8 100644
    +--- a/core/tests/coretests/src/android/widget/TextViewActivityTest.java
    ++++ b/core/tests/coretests/src/android/widget/TextViewActivityTest.java
    +@@ -699,4 +699,18 @@ public class TextViewActivityTest extends ActivityInstrumentationTestCase2<TextV
    +         // hasTransientState should return false when selection is created by API.
    +         assertFalse(textView.hasTransientState());
    +     }
    ++/*
    ++    @SmallTest
    ++    public void testNoAssistItemForTextFieldWithUnsupportedCharacters() throws Throwable {
    ++        useSystemDefaultTextClassifier();
    ++        final String text = "\u202Emoc.diordna.com";
    ++        final TextView textView = mActivity.findViewById(R.id.textview);
    ++        mActivityRule.runOnUiThread(() -> textView.setText(text));
    ++        mInstrumentation.waitForIdleSync();
    ++
    ++        onView(withId(R.id.textview)).perform(longPressOnTextAtIndex(text.indexOf('.')));
    ++        sleepForFloatingToolbarPopup();
    ++        assertFloatingToolbarDoesNotContainItem(android.R.id.textAssist);
    ++    }
    ++*/
    + }
     diff --git a/libs/androidfw/ResourceTypes.cpp b/libs/androidfw/ResourceTypes.cpp
    -index ceeb12bab20..d9efe2b6739 100644
    +index ceeb12bab20..65588b2fafc 100644
     --- a/libs/androidfw/ResourceTypes.cpp
     +++ b/libs/androidfw/ResourceTypes.cpp
     @@ -457,6 +457,22 @@ status_t ResStringPool::setTo(const void* data, size_t size, bool copyData)
    @@ -1867,7 +2256,22 @@ index ceeb12bab20..d9efe2b6739 100644
          mHeader = (const ResStringPool_header*)data;
      
          if (notDeviceEndian) {
    -@@ -6391,8 +6409,16 @@ status_t ResTable::parsePackage(const ResTable_package* const pkg,
    +@@ -807,7 +825,13 @@ const char* ResStringPool::string8At(size_t idx, size_t* outLen) const
    +             *outLen = decodeLength(&str);
    +             size_t encLen = decodeLength(&str);
    +             if ((uint32_t)(str+encLen-strings) < mStringPoolSize) {
    +-                return (const char*)str;
    ++                // Reject malformed (non null-terminated) strings
    ++                if (str[encLen] != 0x00) {
    ++                    ALOGW("Bad string block: string #%d is not null-terminated",
    ++                          (int)idx);
    ++                    return NULL;
    ++                }
    ++              return (const char*)str;
    +             } else {
    +                 ALOGW("Bad string block: string #%d extends to %d, past end at %d\n",
    +                         (int)idx, (int)(str+encLen-strings), (int)mStringPoolSize);
    +@@ -6391,8 +6415,16 @@ status_t ResTable::parsePackage(const ResTable_package* const pkg,
                  }
      
              } else if (ctype == RES_TABLE_LIBRARY_TYPE) {
    @@ -2115,6 +2519,120 @@ index 7217832bac6..feff102850f 100644
                          }
                      }
                      break;
    +diff --git a/packages/DocumentsUI/tests/src/com/android/documentsui/SearchViewUiTest.java b/packages/DocumentsUI/tests/src/com/android/documentsui/SearchViewUiTest.java
    +index a9451a6e379..b6190821c2d 100644
    +--- a/packages/DocumentsUI/tests/src/com/android/documentsui/SearchViewUiTest.java
    ++++ b/packages/DocumentsUI/tests/src/com/android/documentsui/SearchViewUiTest.java
    +@@ -72,6 +72,32 @@ public class SearchViewUiTest extends ActivityTest<FilesActivity> {
    +         bots.main.assertSearchTextField(false, query);
    +     }
    + 
    ++    public void testSearchDownloads() throws Exception {
    ++        initTestFiles();
    ++        bots.roots.openRoot(ROOT_0_ID);
    ++
    ++        bots.directory.copyFilesToClipboard(fileName1, fileName2);
    ++        device.waitForIdle();
    ++
    ++        bots.roots.openRoot("Downloads");
    ++        bots.directory.pasteFilesFromClipboard();
    ++
    ++        //TODO: linben Why do we need to click on Downloads again so this will work?
    ++        bots.roots.openRoot("Downloads");
    ++        device.waitForIdle();
    ++
    ++        String query = "file12";
    ++        bots.main.openSearchView();
    ++        bots.main.setSearchQuery(query);
    ++
    ++        device.pressEnter();
    ++
    ++        bots.directory.assertDocumentsCountOnList(true, 1);
    ++        bots.directory.assertDocumentsPresent(fileName2);
    ++
    ++        device.pressBack();
    ++    }
    ++
    +     @Suppress
    +     public void testSearchResultsFound_ClearsOnBack() throws Exception {
    +         initTestFiles();
    +@@ -151,4 +177,18 @@ public class SearchViewUiTest extends ActivityTest<FilesActivity> {
    +         bots.main.assertSearchTextFiledAndIcon(false, false);
    +     }
    + 
    ++    @Override
    ++    public void tearDown() throws Exception {
    ++        try {
    ++            // Proper clean up of #testSearchDownloads
    ++            bots.directory.clickDocument(fileName1 + ".txt");
    ++            bots.directory.clickDocument(fileName2);
    ++            device.waitForIdle();
    ++            bots.main.menuDelete().click();
    ++            bots.main.findDialogOkButton().click();
    ++        } catch (Exception e) {
    ++        } finally {
    ++            super.tearDown();
    ++        }
    ++    }
    + }
    +diff --git a/packages/DocumentsUI/tests/src/com/android/documentsui/bots/DirectoryListBot.java b/packages/DocumentsUI/tests/src/com/android/documentsui/bots/DirectoryListBot.java
    +index 7c1e2196f6d..e2aabc7c2ba 100644
    +--- a/packages/DocumentsUI/tests/src/com/android/documentsui/bots/DirectoryListBot.java
    ++++ b/packages/DocumentsUI/tests/src/com/android/documentsui/bots/DirectoryListBot.java
    +@@ -30,6 +30,7 @@ import android.support.test.uiautomator.UiObject2;
    + import android.support.test.uiautomator.UiObjectNotFoundException;
    + import android.support.test.uiautomator.UiSelector;
    + import android.support.test.uiautomator.Until;
    ++import android.view.KeyEvent;
    + import android.view.MotionEvent;
    + 
    + import junit.framework.Assert;
    +@@ -129,6 +130,17 @@ public class DirectoryListBot extends BaseBot {
    +         return doc;
    +     }
    + 
    ++    public void copyFilesToClipboard(String...labels) throws UiObjectNotFoundException {
    ++        for (String label: labels) {
    ++            clickDocument(label);
    ++        }
    ++        mDevice.pressKeyCode(KeyEvent.KEYCODE_C, KeyEvent.META_CTRL_ON);
    ++    }
    ++
    ++    public void pasteFilesFromClipboard() {
    ++        mDevice.pressKeyCode(KeyEvent.KEYCODE_V, KeyEvent.META_CTRL_ON);
    ++    }
    ++
    +     public UiObject2 getSnackbar(String message) {
    +         return mDevice.wait(Until.findObject(By.text(message)), mTimeout);
    +     }
    +diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
    +index fec33a27086..d89219f1bdc 100644
    +--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
    ++++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
    +@@ -511,6 +511,13 @@ public class SettingsProvider extends ContentProvider {
    + 
    +     @Override
    +     public ParcelFileDescriptor openFile(Uri uri, String mode) throws FileNotFoundException {
    ++        final int userId = getUserIdFromUri(uri, UserHandle.getCallingUserId());
    ++        if (userId != UserHandle.getCallingUserId()) {
    ++            getContext().enforceCallingPermission(Manifest.permission.INTERACT_ACROSS_USERS,
    ++                    "Access files from the settings of another user");
    ++        }
    ++        uri = ContentProvider.getUriWithoutUserId(uri);
    ++
    +         final String cacheName;
    +         if (Settings.System.RINGTONE_CACHE_URI.equals(uri)) {
    +             cacheName = Settings.System.RINGTONE_CACHE;
    +@@ -523,8 +530,7 @@ public class SettingsProvider extends ContentProvider {
    +                     + "ringtone playback is available through android.media.Ringtone");
    +         }
    + 
    +-        final File cacheFile = new File(
    +-                getRingtoneCacheDir(UserHandle.getCallingUserId()), cacheName);
    ++        final File cacheFile = new File(getRingtoneCacheDir(userId), cacheName);
    +         return ParcelFileDescriptor.open(cacheFile, ParcelFileDescriptor.parseMode(mode));
    +     }
    + 
     diff --git a/packages/SystemUI/AndroidManifest.xml b/packages/SystemUI/AndroidManifest.xml
     index 3ee844cd8ef..9e03307fa31 100644
     --- a/packages/SystemUI/AndroidManifest.xml
    @@ -2455,6 +2973,58 @@ index 70f2fdcfa8d..ba50161aae9 100644
          }
      
          @Override
    +diff --git a/packages/SystemUI/src/com/android/systemui/usb/UsbDebuggingActivity.java b/packages/SystemUI/src/com/android/systemui/usb/UsbDebuggingActivity.java
    +index f5447a29350..329dd9917a7 100644
    +--- a/packages/SystemUI/src/com/android/systemui/usb/UsbDebuggingActivity.java
    ++++ b/packages/SystemUI/src/com/android/systemui/usb/UsbDebuggingActivity.java
    +@@ -31,8 +31,12 @@ import android.os.ServiceManager;
    + import android.os.SystemProperties;
    + import android.util.Log;
    + import android.view.LayoutInflater;
    ++import android.view.MotionEvent;
    + import android.view.View;
    ++import android.view.Window;
    ++import android.view.WindowManager;
    + import android.widget.CheckBox;
    ++import android.widget.Toast;
    + 
    + import com.android.internal.app.AlertActivity;
    + import com.android.internal.app.AlertController;
    +@@ -48,6 +52,10 @@ public class UsbDebuggingActivity extends AlertActivity
    + 
    +     @Override
    +     public void onCreate(Bundle icicle) {
    ++        Window window = getWindow();
    ++        window.addPrivateFlags(WindowManager.LayoutParams.PRIVATE_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS);
    ++        window.setType(WindowManager.LayoutParams.TYPE_SYSTEM_DIALOG);
    ++
    +         super.onCreate(icicle);
    + 
    +         if (SystemProperties.getInt("service.adb.tcp.port", 0) == 0) {
    +@@ -79,6 +87,23 @@ public class UsbDebuggingActivity extends AlertActivity
    +         ap.mView = checkbox;
    + 
    +         setupAlert();
    ++
    ++        // adding touch listener on affirmative button - checks if window is obscured
    ++        // if obscured, do not let user give permissions (could be tapjacking involved)
    ++        final View.OnTouchListener filterTouchListener = (View v, MotionEvent event) -> {
    ++            // Filter obscured touches by consuming them.
    ++            if (((event.getFlags() & MotionEvent.FLAG_WINDOW_IS_OBSCURED) != 0)
    ++                    || ((event.getFlags() & MotionEvent.FLAG_WINDOW_IS_PARTIALLY_OBSCURED) != 0)) {
    ++                if (event.getAction() == MotionEvent.ACTION_UP) {
    ++                    Toast.makeText(v.getContext(),
    ++                            R.string.touch_filtered_warning,
    ++                            Toast.LENGTH_SHORT).show();
    ++                }
    ++                return true;
    ++            }
    ++            return false;
    ++        };
    ++        mAlert.getButton(BUTTON_POSITIVE).setOnTouchListener(filterTouchListener);
    +     }
    + 
    +     private class UsbDisconnectedReceiver extends BroadcastReceiver {
     diff --git a/services/core/java/com/android/server/AppOpsService.java b/services/core/java/com/android/server/AppOpsService.java
     index 4caeba84b20..c95b9d52ad8 100644
     --- a/services/core/java/com/android/server/AppOpsService.java
    @@ -2717,6 +3287,47 @@ index a7a79cd5b3e..a085b716bd8 100644
                  long bid = Binder.clearCallingIdentity();
                  try {
                      PackageManager pm = mContext.getPackageManager();
    +diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
    +index 91c4571ee49..7be177a1bc2 100644
    +--- a/services/core/java/com/android/server/am/ActivityManagerService.java
    ++++ b/services/core/java/com/android/server/am/ActivityManagerService.java
    +@@ -8112,13 +8112,26 @@ public final class ActivityManagerService extends ActivityManagerNative
    +             }
    +         }
    + 
    ++        // Figure out the value returned when access is allowed
    ++        final int allowedResult;
    ++        if ((modeFlags & Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION) != 0) {
    ++            // If we're extending a persistable grant, then we need to return
    ++            // "targetUid" so that we always create a grant data structure to
    ++            // support take/release APIs
    ++            allowedResult = targetUid;
    ++        } else {
    ++            // Otherwise, we can return "-1" to indicate that no grant data
    ++            // structures need to be created
    ++            allowedResult = -1;
    ++        }
    ++
    +         if (targetUid >= 0) {
    +             // First...  does the target actually need this permission?
    +             if (checkHoldingPermissionsLocked(pm, pi, grantUri, targetUid, modeFlags)) {
    +                 // No need to grant the target this permission.
    +                 if (DEBUG_URI_PERMISSION) Slog.v(TAG_URI_PERMISSION,
    +                         "Target " + targetPkg + " already has full permission to " + grantUri);
    +-                return -1;
    ++                return allowedResult;
    +             }
    +         } else {
    +             // First...  there is no target package, so can anyone access it?
    +@@ -8134,7 +8147,7 @@ public final class ActivityManagerService extends ActivityManagerNative
    +                 }
    +             }
    +             if (allowed) {
    +-                return -1;
    ++                return allowedResult;
    +             }
    +         }
    + 
     diff --git a/services/core/java/com/android/server/am/ActivityStackSupervisor.java b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
     index c6ab9186456..8ba368b0b00 100644
     --- a/services/core/java/com/android/server/am/ActivityStackSupervisor.java
    @@ -2934,6 +3545,45 @@ index 069ae739431..f804fa1cff3 100644
                          }
                      }
                  }
    +diff --git a/services/core/java/com/android/server/display/ColorFade.java b/services/core/java/com/android/server/display/ColorFade.java
    +index a16fcd2fa11..7a5f5231869 100644
    +--- a/services/core/java/com/android/server/display/ColorFade.java
    ++++ b/services/core/java/com/android/server/display/ColorFade.java
    +@@ -36,6 +36,7 @@ import android.opengl.EGLDisplay;
    + import android.opengl.EGLSurface;
    + import android.opengl.GLES20;
    + import android.opengl.GLES11Ext;
    ++import android.os.SystemProperties;
    + import android.util.Slog;
    + import android.view.DisplayInfo;
    + import android.view.Surface.OutOfResourcesException;
    +@@ -70,6 +71,9 @@ final class ColorFade {
    +     // See code for details.
    +     private static final int DEJANK_FRAMES = 3;
    + 
    ++    private static final boolean DESTROY_SURFACE_AFTER_DETACH =
    ++            SystemProperties.getBoolean("ro.egl.destroy_after_detach", false);
    ++
    +     private final int mDisplayId;
    + 
    +     // Set to true when the animation context has been fully prepared.
    +@@ -331,10 +335,15 @@ final class ColorFade {
    +                 destroyScreenshotTexture();
    +                 destroyGLShaders();
    +                 destroyGLBuffers();
    +-                destroyEglSurface();
    ++                if (!DESTROY_SURFACE_AFTER_DETACH) {
    ++                    destroyEglSurface();
    ++                }
    +             } finally {
    +                 detachEglContext();
    +             }
    ++            if (DESTROY_SURFACE_AFTER_DETACH) {
    ++                destroyEglSurface();
    ++            }
    +             // This is being called with no active context so shouldn't be
    +             // needed but is safer to not change for now.
    +             GLES20.glFlush();
     diff --git a/services/core/java/com/android/server/input/InputManagerService.java b/services/core/java/com/android/server/input/InputManagerService.java
     index 719ce7618fd..df2c00be83d 100644
     --- a/services/core/java/com/android/server/input/InputManagerService.java
    @@ -3129,6 +3779,38 @@ index 889c52afa37..872b03d2f09 100644
                  case KeyEvent.KEYCODE_ENDCALL: {
                      result &= ~ACTION_PASS_TO_USER;
                      if (down) {
    +diff --git a/services/core/java/com/android/server/policy/WindowOrientationListener.java b/services/core/java/com/android/server/policy/WindowOrientationListener.java
    +index 8ef0acbd380..a884851d242 100644
    +--- a/services/core/java/com/android/server/policy/WindowOrientationListener.java
    ++++ b/services/core/java/com/android/server/policy/WindowOrientationListener.java
    +@@ -56,6 +56,7 @@ public abstract class WindowOrientationListener {
    +     private boolean mEnabled;
    +     private int mRate;
    +     private String mSensorType;
    ++    private boolean mUseSystemClockforRotationSensor;
    +     private Sensor mSensor;
    +     private OrientationJudge mOrientationJudge;
    +     private int mCurrentRotation = -1;
    +@@ -90,6 +91,9 @@ public abstract class WindowOrientationListener {
    +         mRate = rate;
    +         mSensor = mSensorManager.getDefaultSensor(Sensor.TYPE_DEVICE_ORIENTATION);
    + 
    ++        mUseSystemClockforRotationSensor = context.getResources().getBoolean(
    ++                com.android.internal.R.bool.config_useSystemClockforRotationSensor);
    ++
    +         if (mSensor != null) {
    +             mOrientationJudge = new OrientationSensorJudge();
    +         }
    +@@ -592,7 +596,8 @@ public abstract class WindowOrientationListener {
    +                 // Reset the orientation listener state if the samples are too far apart in time
    +                 // or when we see values of (0, 0, 0) which indicates that we polled the
    +                 // accelerometer too soon after turning it on and we don't have any data yet.
    +-                final long now = event.timestamp;
    ++                final long now = mUseSystemClockforRotationSensor
    ++                        ? SystemClock.elapsedRealtimeNanos() : event.timestamp;
    +                 final long then = mLastFilteredTimestampNanos;
    +                 final float timeDeltaMS = (now - then) * 0.000001f;
    +                 final boolean skipSample;
     diff --git a/services/core/java/com/android/server/wm/InputMonitor.java b/services/core/java/com/android/server/wm/InputMonitor.java
     index be9fb26bb28..d835e884615 100644
     --- a/services/core/java/com/android/server/wm/InputMonitor.java
    @@ -3181,7 +3863,7 @@ index 08c0a4b0135..b5c4202dc10 100644
              StringBuilder sb = new StringBuilder();
              sb.append("Session{");
     diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
    -index ca2610af3f6..2203ebbee94 100644
    +index ca2610af3f6..be1d84f11ee 100644
     --- a/services/core/java/com/android/server/wm/WindowManagerService.java
     +++ b/services/core/java/com/android/server/wm/WindowManagerService.java
     @@ -16,6 +16,7 @@
    @@ -3192,7 +3874,15 @@ index ca2610af3f6..2203ebbee94 100644
      import android.Manifest;
      import android.animation.ValueAnimator;
      import android.annotation.IntDef;
    -@@ -490,6 +491,9 @@ public class WindowManagerService extends IWindowManager.Stub
    +@@ -189,6 +190,7 @@ import static android.view.WindowManager.LayoutParams.INPUT_FEATURE_NO_INPUT_CHA
    + import static android.view.WindowManager.LayoutParams.LAST_APPLICATION_WINDOW;
    + import static android.view.WindowManager.LayoutParams.LAST_SUB_WINDOW;
    + import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_COMPATIBLE_WINDOW;
    ++import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS;
    + import static android.view.WindowManager.LayoutParams.TYPE_ACCESSIBILITY_OVERLAY;
    + import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION;
    + import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_STARTING;
    +@@ -490,6 +492,9 @@ public class WindowManagerService extends IWindowManager.Stub
           */
          final ArrayList<WindowState> mForceRemoves = new ArrayList<>();
      
    @@ -3202,7 +3892,7 @@ index ca2610af3f6..2203ebbee94 100644
          /**
           * Windows that clients are waiting to have drawn.
           */
    -@@ -2129,6 +2133,9 @@ public class WindowManagerService extends IWindowManager.Stub
    +@@ -2129,6 +2134,9 @@ public class WindowManagerService extends IWindowManager.Stub
                      }
                  }
      
    @@ -3212,7 +3902,7 @@ index ca2610af3f6..2203ebbee94 100644
                  if (type == TYPE_APPLICATION_STARTING && token.appWindowToken != null) {
                      token.appWindowToken.startingWindow = win;
                      if (DEBUG_STARTING_WINDOW) Slog.v (TAG_WM, "addWindow: " + token.appWindowToken
    -@@ -2576,6 +2583,7 @@ public class WindowManagerService extends IWindowManager.Stub
    +@@ -2576,6 +2584,7 @@ public class WindowManagerService extends IWindowManager.Stub
      
              mPendingRemove.remove(win);
              mResizingWindows.remove(win);
    @@ -3220,7 +3910,7 @@ index ca2610af3f6..2203ebbee94 100644
              mWindowsChanged = true;
              if (DEBUG_WINDOW_MOVEMENT) Slog.v(TAG_WM, "Final remove of window: " + win);
      
    -@@ -2893,6 +2901,11 @@ public class WindowManagerService extends IWindowManager.Stub
    +@@ -2893,6 +2902,11 @@ public class WindowManagerService extends IWindowManager.Stub
                              | WindowManager.LayoutParams.SYSTEM_UI_VISIBILITY_CHANGED)) != 0) {
                          win.mLayoutNeeded = true;
                      }
    @@ -3232,7 +3922,7 @@ index ca2610af3f6..2203ebbee94 100644
                  }
      
                  if (DEBUG_LAYOUT) Slog.v(TAG_WM, "Relayout " + win + ": viewVisibility=" + viewVisibility
    -@@ -11771,4 +11784,35 @@ public class WindowManagerService extends IWindowManager.Stub
    +@@ -11771,4 +11785,35 @@ public class WindowManagerService extends IWindowManager.Stub
                  }
              }
          }
    diff --git a/frameworks_native.patch b/frameworks_native.patch
    index 24f1e09..08fc09e 100644
    --- a/frameworks_native.patch
    +++ b/frameworks_native.patch
    @@ -176,6 +176,71 @@ index 74a4123bb..8dc6f6a9d 100644
      
          /* Clears the frame statistics for animations.
           *
    +diff --git a/include/input/InputTransport.h b/include/input/InputTransport.h
    +index f31bceabd..baf143038 100644
    +--- a/include/input/InputTransport.h
    ++++ b/include/input/InputTransport.h
    +@@ -42,6 +42,13 @@ namespace android {
    +  *
    +  * Note that this structure is used for IPCs so its layout must be identical
    +  * on 64 and 32 bit processes. This is tested in StructLayout_test.cpp.
    ++ *
    ++ * Since the struct must be aligned to an 8-byte boundary, there could be uninitialized bytes
    ++ * in-between the defined fields. This padding data should be explicitly accounted for by adding
    ++ * "empty" fields into the struct. This data is memset to zero before sending the struct across
    ++ * the socket. Adding the explicit fields ensures that the memset is not optimized away by the
    ++ * compiler. When a new field is added to the struct, the corresponding change
    ++ * in StructLayout_test should be made.
    +  */
    + struct InputMessage {
    +     enum {
    +@@ -62,6 +69,7 @@ struct InputMessage {
    +     union Body {
    +         struct Key {
    +             uint32_t seq;
    ++            uint32_t empty1;
    +             nsecs_t eventTime __attribute__((aligned(8)));
    +             int32_t deviceId;
    +             int32_t source;
    +@@ -71,6 +79,7 @@ struct InputMessage {
    +             int32_t scanCode;
    +             int32_t metaState;
    +             int32_t repeatCount;
    ++            uint32_t empty2;
    +             nsecs_t downTime __attribute__((aligned(8)));
    + 
    +             inline size_t size() const {
    +@@ -80,6 +89,7 @@ struct InputMessage {
    + 
    +         struct Motion {
    +             uint32_t seq;
    ++            uint32_t empty1;
    +             nsecs_t eventTime __attribute__((aligned(8)));
    +             int32_t deviceId;
    +             int32_t source;
    +@@ -89,12 +99,14 @@ struct InputMessage {
    +             int32_t metaState;
    +             int32_t buttonState;
    +             int32_t edgeFlags;
    ++            uint32_t empty2;
    +             nsecs_t downTime __attribute__((aligned(8)));
    +             float xOffset;
    +             float yOffset;
    +             float xPrecision;
    +             float yPrecision;
    +             uint32_t pointerCount;
    ++            uint32_t empty3;
    +             // Note that PointerCoords requires 8 byte alignment.
    +             struct Pointer {
    +                 PointerProperties properties;
    +@@ -125,6 +137,7 @@ struct InputMessage {
    + 
    +     bool isValid(size_t actualSize) const;
    +     size_t size() const;
    ++    void getSanitizedCopy(InputMessage* msg) const;
    + };
    + 
    + /*
     diff --git a/include/ui/FramebufferNativeWindow.h b/include/ui/FramebufferNativeWindow.h
     new file mode 100644
     index 000000000..2eb1cc16e
    @@ -659,6 +724,142 @@ index 5a2ca8d7a..16ccbc30e 100644
              if (inOutDirtyBounds) {
                  *inOutDirtyBounds = newDirtyRegion.getBounds();
              }
    +diff --git a/libs/input/InputTransport.cpp b/libs/input/InputTransport.cpp
    +index 2dff4e091..f6d2c1563 100644
    +--- a/libs/input/InputTransport.cpp
    ++++ b/libs/input/InputTransport.cpp
    +@@ -97,6 +97,102 @@ size_t InputMessage::size() const {
    +     return sizeof(Header);
    + }
    + 
    ++/**
    ++ * There could be non-zero bytes in-between InputMessage fields. Force-initialize the entire
    ++ * memory to zero, then only copy the valid bytes on a per-field basis.
    ++ */
    ++void InputMessage::getSanitizedCopy(InputMessage* msg) const {
    ++    memset(msg, 0, sizeof(*msg));
    ++
    ++    // Write the header
    ++    msg->header.type = header.type;
    ++
    ++    // Write the body
    ++    switch(header.type) {
    ++        case InputMessage::TYPE_KEY: {
    ++            // uint32_t seq
    ++            msg->body.key.seq = body.key.seq;
    ++            // nsecs_t eventTime
    ++            msg->body.key.eventTime = body.key.eventTime;
    ++            // int32_t deviceId
    ++            msg->body.key.deviceId = body.key.deviceId;
    ++            // int32_t source
    ++            msg->body.key.source = body.key.source;
    ++            // int32_t action
    ++            msg->body.key.action = body.key.action;
    ++            // int32_t flags
    ++            msg->body.key.flags = body.key.flags;
    ++            // int32_t keyCode
    ++            msg->body.key.keyCode = body.key.keyCode;
    ++            // int32_t scanCode
    ++            msg->body.key.scanCode = body.key.scanCode;
    ++            // int32_t metaState
    ++            msg->body.key.metaState = body.key.metaState;
    ++            // int32_t repeatCount
    ++            msg->body.key.repeatCount = body.key.repeatCount;
    ++            // nsecs_t downTime
    ++            msg->body.key.downTime = body.key.downTime;
    ++            break;
    ++        }
    ++        case InputMessage::TYPE_MOTION: {
    ++            // uint32_t seq
    ++            msg->body.motion.seq = body.motion.seq;
    ++            // nsecs_t eventTime
    ++            msg->body.motion.eventTime = body.motion.eventTime;
    ++            // int32_t deviceId
    ++            msg->body.motion.deviceId = body.motion.deviceId;
    ++            // int32_t source
    ++            msg->body.motion.source = body.motion.source;
    ++            // int32_t action
    ++            msg->body.motion.action = body.motion.action;
    ++            // int32_t actionButton
    ++            msg->body.motion.actionButton = body.motion.actionButton;
    ++            // int32_t flags
    ++            msg->body.motion.flags = body.motion.flags;
    ++            // int32_t metaState
    ++            msg->body.motion.metaState = body.motion.metaState;
    ++            // int32_t buttonState
    ++            msg->body.motion.buttonState = body.motion.buttonState;
    ++            // int32_t edgeFlags
    ++            msg->body.motion.edgeFlags = body.motion.edgeFlags;
    ++            // nsecs_t downTime
    ++            msg->body.motion.downTime = body.motion.downTime;
    ++            // float xOffset
    ++            msg->body.motion.xOffset = body.motion.xOffset;
    ++            // float yOffset
    ++            msg->body.motion.yOffset = body.motion.yOffset;
    ++            // float xPrecision
    ++            msg->body.motion.xPrecision = body.motion.xPrecision;
    ++            // float yPrecision
    ++            msg->body.motion.yPrecision = body.motion.yPrecision;
    ++            // uint32_t pointerCount
    ++            msg->body.motion.pointerCount = body.motion.pointerCount;
    ++            //struct Pointer pointers[MAX_POINTERS]
    ++            for (size_t i = 0; i < body.motion.pointerCount; i++) {
    ++                // PointerProperties properties
    ++                msg->body.motion.pointers[i].properties.id = body.motion.pointers[i].properties.id;
    ++                msg->body.motion.pointers[i].properties.toolType =
    ++                        body.motion.pointers[i].properties.toolType,
    ++                // PointerCoords coords
    ++                msg->body.motion.pointers[i].coords.bits = body.motion.pointers[i].coords.bits;
    ++                const uint32_t count = BitSet64::count(body.motion.pointers[i].coords.bits);
    ++                memcpy(&msg->body.motion.pointers[i].coords.values[0],
    ++                        &body.motion.pointers[i].coords.values[0],
    ++                        count * (sizeof(body.motion.pointers[i].coords.values[0])));
    ++            }
    ++            break;
    ++        }
    ++        case InputMessage::TYPE_FINISHED: {
    ++            msg->body.finished.seq = body.finished.seq;
    ++            msg->body.finished.handled = body.finished.handled;
    ++            break;
    ++        }
    ++        default: {
    ++            LOG_FATAL("Unexpected message type %i", header.type);
    ++            break;
    ++        }
    ++    }
    ++}
    + 
    + // --- InputChannel ---
    + 
    +@@ -150,10 +246,12 @@ status_t InputChannel::openInputChannelPair(const String8& name,
    + }
    + 
    + status_t InputChannel::sendMessage(const InputMessage* msg) {
    +-    size_t msgLength = msg->size();
    ++    const size_t msgLength = msg->size();
    ++    InputMessage cleanMsg;
    ++    msg->getSanitizedCopy(&cleanMsg);
    +     ssize_t nWrite;
    +     do {
    +-        nWrite = ::send(mFd, msg, msgLength, MSG_DONTWAIT | MSG_NOSIGNAL);
    ++        nWrite = ::send(mFd, &cleanMsg, msgLength, MSG_DONTWAIT | MSG_NOSIGNAL);
    +     } while (nWrite == -1 && errno == EINTR);
    + 
    +     if (nWrite < 0) {
    +diff --git a/libs/input/tests/StructLayout_test.cpp b/libs/input/tests/StructLayout_test.cpp
    +index 8d73f453e..5172681e3 100644
    +--- a/libs/input/tests/StructLayout_test.cpp
    ++++ b/libs/input/tests/StructLayout_test.cpp
    +@@ -63,6 +63,9 @@ void TestInputMessageAlignment() {
    +   CHECK_OFFSET(InputMessage::Body::Motion, yPrecision, 68);
    +   CHECK_OFFSET(InputMessage::Body::Motion, pointerCount, 72);
    +   CHECK_OFFSET(InputMessage::Body::Motion, pointers, 80);
    ++
    ++  CHECK_OFFSET(InputMessage::Body::Finished, seq, 0);
    ++  CHECK_OFFSET(InputMessage::Body::Finished, handled, 4);
    + }
    + 
    + } // namespace android
     diff --git a/libs/ui/Android.mk b/libs/ui/Android.mk
     index e690ede19..392703167 100644
     --- a/libs/ui/Android.mk
    diff --git a/packages_apps_settings.patch b/packages_apps_settings.patch
    index 51aa5a3..0be0462 100644
    --- a/packages_apps_settings.patch
    +++ b/packages_apps_settings.patch
    @@ -38,6 +38,33 @@ index 2c3436fc70..ae61944cbe 100644
              } else {
                  mBaseIntent = new Intent(Intent.ACTION_MAIN, null);
                  mBaseIntent.addCategory(Intent.CATEGORY_DEFAULT);
    +diff --git a/src/com/android/settings/ChooseLockGeneric.java b/src/com/android/settings/ChooseLockGeneric.java
    +index 1a70f541b4..88c65d7f97 100644
    +--- a/src/com/android/settings/ChooseLockGeneric.java
    ++++ b/src/com/android/settings/ChooseLockGeneric.java
    +@@ -140,6 +140,11 @@ public class ChooseLockGeneric extends SettingsActivity {
    +         @Override
    +         public void onCreate(Bundle savedInstanceState) {
    +             super.onCreate(savedInstanceState);
    ++            final Activity activity = getActivity();
    ++            if (!Utils.isDeviceProvisioned(activity) && !canRunBeforeDeviceProvisioned()) {
    ++                activity.finish();
    ++                return;
    ++            }
    + 
    +             String chooseLockAction = getActivity().getIntent().getAction();
    +             mFingerprintManager =
    +@@ -217,6 +222,10 @@ public class ChooseLockGeneric extends SettingsActivity {
    +             addHeaderView();
    +         }
    + 
    ++        protected boolean canRunBeforeDeviceProvisioned() {
    ++            return false;
    ++        }
    ++
    +         protected void addHeaderView() {
    +             if (mForFingerprint) {
    +                 setHeaderView(R.layout.choose_lock_generic_fingerprint_header);
     diff --git a/src/com/android/settings/DeviceAdminAdd.java b/src/com/android/settings/DeviceAdminAdd.java
     index 9d4d895330..2f6afd790f 100644
     --- a/src/com/android/settings/DeviceAdminAdd.java
    @@ -107,6 +134,37 @@ index 9d4d895330..2f6afd790f 100644
              try {
                  ActivityManagerNative.getDefault().resumeAppSwitches();
              } catch (RemoteException e) {
    +diff --git a/src/com/android/settings/SettingsActivity.java b/src/com/android/settings/SettingsActivity.java
    +index db9c0906ef..76041f2d1b 100644
    +--- a/src/com/android/settings/SettingsActivity.java
    ++++ b/src/com/android/settings/SettingsActivity.java
    +@@ -625,8 +625,8 @@ public class SettingsActivity extends SettingsDrawerActivity
    +             } else {
    +                 // No UP affordance if we are displaying the main Dashboard
    +                 mDisplayHomeAsUpEnabled = false;
    +-                // Show Search affordance
    +-                mDisplaySearch = true;
    ++                // Show Search affordance (if device is provisioned)
    ++                mDisplaySearch = Utils.isDeviceProvisioned(this);
    +                 mInitialTitleResId = R.string.dashboard_title;
    + 
    +                 // add argument to indicate which settings tab should be initially selected
    +diff --git a/src/com/android/settings/SetupChooseLockGeneric.java b/src/com/android/settings/SetupChooseLockGeneric.java
    +index 71679f30a8..21fad53b8f 100644
    +--- a/src/com/android/settings/SetupChooseLockGeneric.java
    ++++ b/src/com/android/settings/SetupChooseLockGeneric.java
    +@@ -138,6 +138,11 @@ public class SetupChooseLockGeneric extends ChooseLockGeneric {
    +             return layout.onCreateRecyclerView(inflater, parent, savedInstanceState);
    +         }
    + 
    ++        @Override
    ++        protected boolean canRunBeforeDeviceProvisioned() {
    ++            return true;
    ++        }
    ++
    +         /***
    +          * Disables preferences that are less secure than required quality and shows only secure
    +          * screen lock options here.
     diff --git a/src/com/android/settings/accessibility/ToggleAccessibilityServicePreferenceFragment.java b/src/com/android/settings/accessibility/ToggleAccessibilityServicePreferenceFragment.java
     index 196a4ab372..1f69768c0d 100644
     --- a/src/com/android/settings/accessibility/ToggleAccessibilityServicePreferenceFragment.java
    diff --git a/system_bt.patch b/system_bt.patch
    index efab3bf..80bde9f 100644
    --- a/system_bt.patch
    +++ b/system_bt.patch
    @@ -957,10 +957,10 @@ index ed0b67536..350f28e41 100644
          return p_start;
      }
     diff --git a/stack/avrc/avrc_pars_ct.c b/stack/avrc/avrc_pars_ct.c
    -index 63cc38407..eb1ff99c5 100644
    +index 63cc38407..ebdb47c7b 100644
     --- a/stack/avrc/avrc_pars_ct.c
     +++ b/stack/avrc/avrc_pars_ct.c
    -@@ -22,6 +22,7 @@
    +@@ -22,11 +22,14 @@
      #include "avrc_defs.h"
      #include "avrc_int.h"
      #include "bt_utils.h"
    @@ -968,19 +968,208 @@ index 63cc38407..eb1ff99c5 100644
      
      /*****************************************************************************
      **  Global data
    -@@ -121,6 +122,10 @@ void avrc_parse_notification_rsp (UINT8 *p_stream, tAVRC_REG_NOTIF_RSP *p_rsp)
    + *****************************************************************************/
    + 
    ++#define MIN(x, y) ((x) < (y) ? (x) : (y))
    ++
    + #if (AVRC_METADATA_INCLUDED == TRUE)
    + 
    + /*******************************************************************************
    +@@ -55,14 +58,37 @@ static tAVRC_STS avrc_pars_vendor_rsp(tAVRC_MSG_VENDOR *p_msg, tAVRC_RESPONSE *p
    +     if (p_msg->p_vendor_data == NULL)
    +         return AVRC_STS_INTERNAL_ERR;
    + 
    ++    if (p_msg->vendor_len < 4)
    ++    {
    ++        android_errorWriteLog(0x534e4554, "111450531");
    ++        AVRC_TRACE_WARNING("%s: message length %d too short: must be at least 4",
    ++                           __func__, p_msg->vendor_len);
    ++        return AVRC_STS_INTERNAL_ERR;
    ++    }
    +     p = p_msg->p_vendor_data;
    +     BE_STREAM_TO_UINT8 (p_result->pdu, p);
    +     p++; /* skip the reserved/packe_type byte */
    +     BE_STREAM_TO_UINT16 (len, p);
    +-    AVRC_TRACE_DEBUG("%s ctype:0x%x pdu:0x%x, len:%d/0x%x",
    +-                     __func__, p_msg->hdr.ctype, p_result->pdu, len, len);
    ++    AVRC_TRACE_DEBUG("%s ctype:0x%x pdu:0x%x, len:%d/0x%x vendor_len=0x%x",
    ++                     __func__, p_msg->hdr.ctype, p_result->pdu, len, len,
    ++                     p_msg->vendor_len);
    ++    if (p_msg->vendor_len < len + 4)
    ++    {
    ++        android_errorWriteLog(0x534e4554, "111450531");
    ++        AVRC_TRACE_WARNING("%s: message length %d too short: must be at least %d",
    ++                           __func__, p_msg->vendor_len, len + 4);
    ++        return AVRC_STS_INTERNAL_ERR;
    ++    }
    ++
    +     if (p_msg->hdr.ctype == AVRC_RSP_REJ)
    +     {
    ++        if (len < 1)
    ++        {
    ++            android_errorWriteLog(0x534e4554, "111450531");
    ++            AVRC_TRACE_WARNING("%s: invalid parameter length %d: must be at least 1",
    ++                               __func__, len);
    ++            return AVRC_STS_INTERNAL_ERR;
    ++        }
    +         p_result->rsp.status = *p;
    +         return p_result->rsp.status;
    +     }
    +@@ -85,11 +111,25 @@ static tAVRC_STS avrc_pars_vendor_rsp(tAVRC_MSG_VENDOR *p_msg, tAVRC_RESPONSE *p
    + 
    +     case AVRC_PDU_REGISTER_NOTIFICATION:    /* 0x31 */
    + #if (AVRC_ADV_CTRL_INCLUDED == TRUE)
    ++        if (len < 1)
    ++        {
    ++            android_errorWriteLog(0x534e4554, "111450531");
    ++            AVRC_TRACE_WARNING("%s: invalid parameter length %d: must be at least 1",
    ++                               __func__, len);
    ++            return AVRC_STS_INTERNAL_ERR;
    ++        }
    +         BE_STREAM_TO_UINT8 (eventid, p);
    +         if(AVRC_EVT_VOLUME_CHANGE==eventid
    +             && (AVRC_RSP_CHANGED==p_msg->hdr.ctype || AVRC_RSP_INTERIM==p_msg->hdr.ctype
    +             || AVRC_RSP_REJ==p_msg->hdr.ctype || AVRC_RSP_NOT_IMPL==p_msg->hdr.ctype))
    +         {
    ++            if (len < 2)
    ++            {
    ++                android_errorWriteLog(0x534e4554, "111450531");
    ++                AVRC_TRACE_WARNING("%s: invalid parameter length %d: must be at least 2",
    ++                                   __func__, len);
    ++                return AVRC_STS_INTERNAL_ERR;
    ++            }
    +             p_result->reg_notif.status=p_msg->hdr.ctype;
    +             p_result->reg_notif.event_id=eventid;
    +             BE_STREAM_TO_UINT8 (p_result->reg_notif.param.volume, p);
    +@@ -106,21 +146,32 @@ static tAVRC_STS avrc_pars_vendor_rsp(tAVRC_MSG_VENDOR *p_msg, tAVRC_RESPONSE *p
    +     return status;
    + }
    + 
    +-void avrc_parse_notification_rsp (UINT8 *p_stream, tAVRC_REG_NOTIF_RSP *p_rsp)
    +-{
    ++tAVRC_STS avrc_parse_notification_rsp(UINT8* p_stream, UINT16 len,
    ++                                      tAVRC_REG_NOTIF_RSP* p_rsp) {
    ++    UINT16 min_len = 1;
    ++
    ++    if (len < min_len) goto length_error;
    +     BE_STREAM_TO_UINT8(p_rsp->event_id, p_stream);
    +     switch (p_rsp->event_id)
    +     {
    +         case AVRC_EVT_PLAY_STATUS_CHANGE:
    ++            min_len += 1;
    ++            if (len < min_len) goto length_error;
    +             BE_STREAM_TO_UINT8(p_rsp->param.play_status, p_stream);
    +             break;
    + 
    +         case AVRC_EVT_TRACK_CHANGE:
    ++            min_len += 8;
    ++            if (len < min_len) goto length_error;
    +             BE_STREAM_TO_ARRAY(p_stream, p_rsp->param.track, 8);
    +             break;
      
              case AVRC_EVT_APP_SETTING_CHANGE:
    ++            min_len += 1;
    ++            if (len < min_len) goto length_error;
                  BE_STREAM_TO_UINT8(p_rsp->param.player_setting.num_attr, p_stream);
    -+            if (p_rsp->param.player_setting.num_attr > AVRC_MAX_APP_SETTINGS) {
    -+              android_errorWriteLog(0x534e4554, "73782082");
    -+              p_rsp->param.player_setting.num_attr = AVRC_MAX_APP_SETTINGS;
    -+            }
    ++            min_len += p_rsp->param.player_setting.num_attr * 2;
    ++            if (len < min_len) goto length_error;
                  for (int index = 0; index < p_rsp->param.player_setting.num_attr; index++)
                  {
                      BE_STREAM_TO_UINT8(p_rsp->param.player_setting.attr_id[index], p_stream);
    -@@ -227,6 +232,12 @@ static tAVRC_STS avrc_ctrl_pars_vendor_rsp(
    +@@ -148,6 +199,14 @@ void avrc_parse_notification_rsp (UINT8 *p_stream, tAVRC_REG_NOTIF_RSP *p_rsp)
    +         default:
    +             break;
    +     }
    ++
    ++    return AVRC_STS_NO_ERROR;
    ++
    ++length_error:
    ++    android_errorWriteLog(0x534e4554, "111450417");
    ++    AVRC_TRACE_WARNING("%s: invalid parameter length %d: must be at least %d",
    ++                     __func__, len, min_len);
    ++    return AVRC_STS_INTERNAL_ERR;
    + }
    + 
    + #if (AVRC_CTLR_INCLUDED == TRUE)
    +@@ -165,17 +224,35 @@ void avrc_parse_notification_rsp (UINT8 *p_stream, tAVRC_REG_NOTIF_RSP *p_rsp)
    + static tAVRC_STS avrc_ctrl_pars_vendor_rsp(
    +     tAVRC_MSG_VENDOR *p_msg, tAVRC_RESPONSE *p_result, UINT8* p_buf, UINT16* buf_len)
    + {
    ++    if (p_msg->vendor_len < 4)
    ++    {
    ++        android_errorWriteLog(0x534e4554, "111450417");
    ++        AVRC_TRACE_WARNING("%s: message length %d too short: must be at least 4",
    ++                           __func__, p_msg->vendor_len);
    ++        return AVRC_STS_INTERNAL_ERR;
    ++    }
    ++
    +     UINT8   *p = p_msg->p_vendor_data;
    +     BE_STREAM_TO_UINT8 (p_result->pdu, p);
    +     p++; /* skip the reserved/packe_type byte */
    + 
    +     UINT16  len;
    ++    UINT16  min_len = 0;
    +     BE_STREAM_TO_UINT16 (len, p);
    +-    AVRC_TRACE_DEBUG("%s ctype:0x%x pdu:0x%x, len:%d",
    +-                     __func__, p_msg->hdr.ctype, p_result->pdu, len);
    ++    AVRC_TRACE_DEBUG("%s ctype:0x%x pdu:0x%x, len:%d  vendor_len=0x%x", __func__,
    ++                    p_msg->hdr.ctype, p_result->pdu, len, p_msg->vendor_len);
    ++    if (p_msg->vendor_len < len + 4)
    ++    {
    ++        android_errorWriteLog(0x534e4554, "111450417");
    ++        AVRC_TRACE_WARNING("%s: message length %d too short: must be at least %d",
    ++                           __func__, p_msg->vendor_len, len + 4);
    ++        return AVRC_STS_INTERNAL_ERR;
    ++    }
    +     /* Todo: Issue in handling reject, check */
    +     if (p_msg->hdr.ctype == AVRC_RSP_REJ)
    +     {
    ++        min_len += 1;
    ++        if (len < min_len) goto length_error;
    +         p_result->rsp.status = *p;
    +         return p_result->rsp.status;
    +     }
    +@@ -187,8 +264,7 @@ static tAVRC_STS avrc_ctrl_pars_vendor_rsp(
    +     /* case AVRC_PDU_ABORT_CONTINUATION_RSP:   0x41 */
    + 
    +     case AVRC_PDU_REGISTER_NOTIFICATION:
    +-        avrc_parse_notification_rsp(p, &p_result->reg_notif);
    +-        break;
    ++        return avrc_parse_notification_rsp(p, len, &p_result->reg_notif);
    + 
    +     case AVRC_PDU_GET_CAPABILITIES:
    +         if (len == 0)
    +@@ -197,12 +273,16 @@ static tAVRC_STS avrc_ctrl_pars_vendor_rsp(
    +             p_result->get_caps.capability_id = 0;
    +             break;
              }
    ++        min_len += 2;
    ++        if (len < min_len) goto length_error;
    +         BE_STREAM_TO_UINT8(p_result->get_caps.capability_id, p);
    +         BE_STREAM_TO_UINT8(p_result->get_caps.count, p);
    +         AVRC_TRACE_DEBUG("%s cap id = %d, cap_count = %d ",
    +                          __func__, p_result->get_caps.capability_id, p_result->get_caps.count);
    +         if (p_result->get_caps.capability_id == AVRC_CAP_COMPANY_ID)
    +         {
    ++            min_len += MIN(p_result->get_caps.count, AVRC_CAP_MAX_NUM_COMP_ID) * 3;
    ++            if (len < min_len) goto length_error;
    +             for(int xx = 0; ((xx < p_result->get_caps.count) && (xx < AVRC_CAP_MAX_NUM_COMP_ID));
    +                 xx++)
    +             {
    +@@ -211,6 +291,8 @@ static tAVRC_STS avrc_ctrl_pars_vendor_rsp(
    +         }
    +         else if (p_result->get_caps.capability_id == AVRC_CAP_EVENTS_SUPPORTED)
    +         {
    ++            min_len += MIN(p_result->get_caps.count, AVRC_CAP_MAX_NUM_EVT_ID);
    ++            if (len < min_len) goto length_error;
    +             for(int xx = 0; ((xx < p_result->get_caps.count) && (xx < AVRC_CAP_MAX_NUM_EVT_ID));
    +                 xx++)
    +             {
    +@@ -225,8 +307,17 @@ static tAVRC_STS avrc_ctrl_pars_vendor_rsp(
    +             p_result->list_app_attr.num_attr = 0;
    +             break;
    +         }
    ++        min_len += 1;
              BE_STREAM_TO_UINT8(p_result->list_app_attr.num_attr, p);
              AVRC_TRACE_DEBUG("%s attr count = %d ", __func__, p_result->list_app_attr.num_attr);
     +
    @@ -989,12 +1178,16 @@ index 63cc38407..eb1ff99c5 100644
     +            p_result->list_app_attr.num_attr = AVRC_MAX_APP_ATTR_SIZE;
     +        }
     +
    ++        min_len += p_result->list_app_attr.num_attr;
    ++        if (len < min_len) goto length_error;
              for(int xx = 0; xx < p_result->list_app_attr.num_attr; xx++)
              {
                  BE_STREAM_TO_UINT8(p_result->list_app_attr.attrs[xx], p);
    -@@ -240,6 +251,12 @@ static tAVRC_STS avrc_ctrl_pars_vendor_rsp(
    +@@ -239,8 +330,17 @@ static tAVRC_STS avrc_ctrl_pars_vendor_rsp(
    +             p_result->list_app_values.num_val = 0;
                  break;
              }
    ++        min_len += 1;
              BE_STREAM_TO_UINT8(p_result->list_app_values.num_val, p);
     +        if (p_result->list_app_values.num_val > AVRC_MAX_APP_ATTR_SIZE)
     +        {
    @@ -1003,11 +1196,19 @@ index 63cc38407..eb1ff99c5 100644
     +        }
     +
              AVRC_TRACE_DEBUG("%s value count = %d ", __func__, p_result->list_app_values.num_val);
    ++        min_len += p_result->list_app_values.num_val;
    ++        if (len < min_len) goto length_error;
              for(int xx = 0; xx < p_result->list_app_values.num_val; xx++)
              {
    -@@ -258,6 +275,12 @@ static tAVRC_STS avrc_ctrl_pars_vendor_rsp(
    -         tAVRC_APP_SETTING *app_sett =
    -             (tAVRC_APP_SETTING*)osi_malloc(p_result->get_cur_app_val.num_val*sizeof(tAVRC_APP_SETTING));
    +             BE_STREAM_TO_UINT8(p_result->list_app_values.vals[xx], p);
    +@@ -254,10 +354,23 @@ static tAVRC_STS avrc_ctrl_pars_vendor_rsp(
    +             p_result->get_cur_app_val.num_val = 0;
    +             break;
    +         }
    ++        min_len += 1;
    +         BE_STREAM_TO_UINT8(p_result->get_cur_app_val.num_val, p);
    +-        tAVRC_APP_SETTING *app_sett =
    +-            (tAVRC_APP_SETTING*)osi_malloc(p_result->get_cur_app_val.num_val*sizeof(tAVRC_APP_SETTING));
              AVRC_TRACE_DEBUG("%s attr count = %d ", __func__, p_result->get_cur_app_val.num_val);
     +
     +        if (p_result->get_cur_app_val.num_val > AVRC_MAX_APP_ATTR_SIZE) {
    @@ -1015,10 +1216,18 @@ index 63cc38407..eb1ff99c5 100644
     +            p_result->get_cur_app_val.num_val = AVRC_MAX_APP_ATTR_SIZE;
     +        }
     +
    ++        min_len += p_result->get_cur_app_val.num_val * 2;
    ++        if (len < min_len)
    ++        {
    ++            p_result->get_cur_app_val.num_val = 0;
    ++            goto length_error;
    ++        }
    ++        tAVRC_APP_SETTING* app_sett = (tAVRC_APP_SETTING*)osi_calloc(
    ++            p_result->get_cur_app_val.num_val * sizeof(tAVRC_APP_SETTING));
              for (int xx = 0; xx < p_result->get_cur_app_val.num_val; xx++)
              {
                  BE_STREAM_TO_UINT8(app_sett[xx].attr_id, p);
    -@@ -269,7 +292,6 @@ static tAVRC_STS avrc_ctrl_pars_vendor_rsp(
    +@@ -269,7 +382,6 @@ static tAVRC_STS avrc_ctrl_pars_vendor_rsp(
      
          case AVRC_PDU_GET_PLAYER_APP_ATTR_TEXT:
          {
    @@ -1026,9 +1235,11 @@ index 63cc38407..eb1ff99c5 100644
              UINT8                    num_attrs;
      
              if (len == 0)
    -@@ -278,9 +300,12 @@ static tAVRC_STS avrc_ctrl_pars_vendor_rsp(
    +@@ -277,18 +389,44 @@ static tAVRC_STS avrc_ctrl_pars_vendor_rsp(
    +             p_result->get_app_attr_txt.num_attr = 0;
                  break;
              }
    ++        min_len += 1;
              BE_STREAM_TO_UINT8(num_attrs, p);
     +        if (num_attrs > AVRC_MAX_APP_ATTR_SIZE) {
     +            num_attrs = AVRC_MAX_APP_ATTR_SIZE;
    @@ -1036,11 +1247,42 @@ index 63cc38407..eb1ff99c5 100644
              AVRC_TRACE_DEBUG("%s attr count = %d ", __func__, p_result->get_app_attr_txt.num_attr);
              p_result->get_app_attr_txt.num_attr = num_attrs;
     -        p_setting_text = (tAVRC_APP_SETTING_TEXT*)osi_malloc(num_attrs * sizeof(tAVRC_APP_SETTING_TEXT));
    -+        p_result->get_app_attr_txt.p_attrs = (tAVRC_APP_SETTING_TEXT*)osi_malloc(num_attrs * sizeof(tAVRC_APP_SETTING_TEXT));
    ++        p_result->get_app_attr_txt.p_attrs = (tAVRC_APP_SETTING_TEXT*)osi_calloc(num_attrs * sizeof(tAVRC_APP_SETTING_TEXT));
              for (int xx = 0; xx < num_attrs; xx++)
              {
    ++            min_len += 4;
    ++            if (len < min_len)
    ++            {
    ++                for (int j = 0; j < xx; j++)
    ++                {
    ++                     osi_free(p_result->get_app_attr_txt.p_attrs[j].p_str);
    ++                }
    ++                osi_free_and_reset((void**)&p_result->get_app_attr_txt.p_attrs);
    ++                p_result->get_app_attr_txt.num_attr = 0;
    ++                goto length_error;
    ++            }
                  BE_STREAM_TO_UINT8(p_result->get_app_attr_txt.p_attrs[xx].attr_id, p);
    -@@ -300,7 +325,6 @@ static tAVRC_STS avrc_ctrl_pars_vendor_rsp(
    +             BE_STREAM_TO_UINT16(p_result->get_app_attr_txt.p_attrs[xx].charset_id, p);
    +             BE_STREAM_TO_UINT8(p_result->get_app_attr_txt.p_attrs[xx].str_len, p);
    ++            min_len += p_result->get_app_attr_txt.p_attrs[xx].str_len;
    ++            if (len < min_len)
    ++            {
    ++               for (int j = 0; j < xx; j++)
    ++               {
    ++                   osi_free(p_result->get_app_attr_txt.p_attrs[j].p_str);
    ++               }
    ++            osi_free_and_reset((void**)&p_result->get_app_attr_txt.p_attrs);
    ++            p_result->get_app_attr_txt.num_attr = 0;
    ++            goto length_error;
    ++            }
    +             if (p_result->get_app_attr_txt.p_attrs[xx].str_len != 0)
    +             {
    +-                UINT8 *p_str = (UINT8 *)osi_malloc(p_result->get_app_attr_txt.p_attrs[xx].str_len);
    ++                UINT8 *p_str = (UINT8 *)osi_calloc(p_result->get_app_attr_txt.p_attrs[xx].str_len);
    +                 BE_STREAM_TO_ARRAY(p, p_str, p_result->get_app_attr_txt.p_attrs[xx].str_len);
    +                 p_result->get_app_attr_txt.p_attrs[xx].p_str = p_str;
    +             } else {
    +@@ -300,7 +438,6 @@ static tAVRC_STS avrc_ctrl_pars_vendor_rsp(
      
          case AVRC_PDU_GET_PLAYER_APP_VALUE_TEXT:
          {
    @@ -1048,9 +1290,11 @@ index 63cc38407..eb1ff99c5 100644
              UINT8                    num_vals;
      
              if (len == 0)
    -@@ -309,10 +333,13 @@ static tAVRC_STS avrc_ctrl_pars_vendor_rsp(
    +@@ -308,17 +445,43 @@ static tAVRC_STS avrc_ctrl_pars_vendor_rsp(
    +             p_result->get_app_val_txt.num_attr = 0;
                  break;
              }
    ++        min_len += 1;
              BE_STREAM_TO_UINT8(num_vals, p);
     +        if (num_vals > AVRC_MAX_APP_ATTR_SIZE) {
     +            num_vals = AVRC_MAX_APP_ATTR_SIZE;
    @@ -1059,10 +1303,115 @@ index 63cc38407..eb1ff99c5 100644
              AVRC_TRACE_DEBUG("%s value count = %d ", __func__, p_result->get_app_val_txt.num_attr);
      
     -        p_setting_text = (tAVRC_APP_SETTING_TEXT *)osi_malloc(num_vals * sizeof(tAVRC_APP_SETTING_TEXT));
    -+        p_result->get_app_val_txt.p_attrs = (tAVRC_APP_SETTING_TEXT *)osi_malloc(num_vals * sizeof(tAVRC_APP_SETTING_TEXT));
    ++        p_result->get_app_val_txt.p_attrs = (tAVRC_APP_SETTING_TEXT *)osi_calloc(num_vals * sizeof(tAVRC_APP_SETTING_TEXT));
              for (int i = 0; i < num_vals; i++) {
    ++            min_len += 4;
    ++            if (len < min_len)
    ++            {
    ++                for (int j = 0; j < i; j++)
    ++                {
    ++                     osi_free(p_result->get_app_val_txt.p_attrs[j].p_str);
    ++                }
    ++                osi_free_and_reset((void**)&p_result->get_app_val_txt.p_attrs);
    ++                p_result->get_app_val_txt.num_attr = 0;
    ++                goto length_error;
    ++            }
                  BE_STREAM_TO_UINT8(p_result->get_app_val_txt.p_attrs[i].attr_id, p);
                  BE_STREAM_TO_UINT16(p_result->get_app_val_txt.p_attrs[i].charset_id, p);
    +             BE_STREAM_TO_UINT8(p_result->get_app_val_txt.p_attrs[i].str_len, p);
    ++            min_len += p_result->get_app_val_txt.p_attrs[i].str_len;
    ++            if (len < min_len)
    ++            {
    ++                for (int j = 0; j < i; j++)
    ++                {
    ++                     osi_free(p_result->get_app_val_txt.p_attrs[j].p_str);
    ++                }
    ++                osi_free_and_reset((void**)&p_result->get_app_val_txt.p_attrs);
    ++                p_result->get_app_val_txt.num_attr = 0;
    ++                goto length_error;
    ++            }
    +             if (p_result->get_app_val_txt.p_attrs[i].str_len != 0) {
    +-                UINT8 *p_str = (UINT8 *)osi_malloc(p_result->get_app_val_txt.p_attrs[i].str_len);
    ++                UINT8 *p_str = (UINT8 *)osi_calloc(p_result->get_app_val_txt.p_attrs[i].str_len);
    +                 BE_STREAM_TO_ARRAY(p, p_str, p_result->get_app_val_txt.p_attrs[i].str_len);
    +                 p_result->get_app_val_txt.p_attrs[i].p_str = p_str;
    +             } else {
    +@@ -341,20 +504,49 @@ static tAVRC_STS avrc_ctrl_pars_vendor_rsp(
    +             p_result->get_elem_attrs.num_attr = 0;
    +             break;
    +         }
    ++        min_len += 1;
    +         BE_STREAM_TO_UINT8(num_attrs, p);
    +         p_result->get_elem_attrs.num_attr = num_attrs;
    +         if (num_attrs)
    +         {
    +             tAVRC_ATTR_ENTRY *p_attrs =
    +-                (tAVRC_ATTR_ENTRY*)osi_malloc(num_attrs * sizeof(tAVRC_ATTR_ENTRY));
    +-            for (int i = 0; i < num_attrs; i++) {
    ++                (tAVRC_ATTR_ENTRY*)osi_calloc(num_attrs * sizeof(tAVRC_ATTR_ENTRY));
    ++            for (int i = 0; i < num_attrs; i++)
    ++            {
    ++                min_len += 8;
    ++                if (len < min_len)
    ++                {
    ++                   for (int j = 0; j < i; j++)
    ++                   {
    ++                       osi_free(p_attrs[j].name.p_str);
    ++                   }
    ++                   osi_free(p_attrs);
    ++                   p_result->get_elem_attrs.num_attr = 0;
    ++                   goto length_error;
    ++                }
    +                 BE_STREAM_TO_UINT32(p_attrs[i].attr_id, p);
    +                 BE_STREAM_TO_UINT16(p_attrs[i].name.charset_id, p);
    +                 BE_STREAM_TO_UINT16(p_attrs[i].name.str_len, p);
    +-                if (p_attrs[i].name.str_len > 0) {
    +-                    p_attrs[i].name.p_str = (UINT8 *)osi_malloc(p_attrs[i].name.str_len);
    ++                min_len += p_attrs[i].name.str_len;
    ++                if (len < min_len)
    ++                {
    ++                   for (int j = 0; j < i; j++)
    ++                   {
    ++                       osi_free(p_attrs[j].name.p_str);
    ++                   }
    ++                   osi_free(p_attrs);
    ++                   p_result->get_elem_attrs.num_attr = 0;
    ++                   goto length_error;
    ++                }
    ++                if (p_attrs[i].name.str_len > 0)
    ++                {
    ++                    p_attrs[i].name.p_str = (UINT8 *)osi_calloc(p_attrs[i].name.str_len);
    +                     BE_STREAM_TO_ARRAY(p, p_attrs[i].name.p_str, p_attrs[i].name.str_len);
    +                 }
    ++                else
    ++                {
    ++                    p_attrs[i].name.p_str = NULL;
    ++                }
    +             }
    +             p_result->get_elem_attrs.p_attrs = p_attrs;
    +         }
    +@@ -366,6 +558,8 @@ static tAVRC_STS avrc_ctrl_pars_vendor_rsp(
    +         {
    +             break;
    +         }
    ++        min_len += 9;
    ++        if (len < min_len) goto length_error;
    +         BE_STREAM_TO_UINT32(p_result->get_play_status.song_len, p);
    +         BE_STREAM_TO_UINT32(p_result->get_play_status.song_pos, p);
    +         BE_STREAM_TO_UINT8(p_result->get_play_status.status, p);
    +@@ -375,6 +569,12 @@ static tAVRC_STS avrc_ctrl_pars_vendor_rsp(
    +         return AVRC_STS_BAD_CMD;
    +     }
    +     return AVRC_STS_NO_ERROR;
    ++
    ++length_error:
    ++    android_errorWriteLog(0x534e4554, "111450417");
    ++    AVRC_TRACE_WARNING("%s: invalid parameter length %d: must be at least %d",
    ++                       __func__, len, min_len);
    ++    return AVRC_STS_INTERNAL_ERR;
    + }
    + 
    + /*******************************************************************************
     diff --git a/stack/avrc/avrc_pars_tg.c b/stack/avrc/avrc_pars_tg.c
     index 3f3fe9385..6d3c67e3f 100644
     --- a/stack/avrc/avrc_pars_tg.c
    @@ -1786,7 +2135,7 @@ index 95de4e34c..f5072e364 100644
                  STREAM_TO_UINT16 (lcid, p);
      
     diff --git a/stack/l2cap/l2c_fcr.c b/stack/l2cap/l2c_fcr.c
    -index 5ba8b5619..2b041f193 100644
    +index 5ba8b5619..69e330b07 100644
     --- a/stack/l2cap/l2c_fcr.c
     +++ b/stack/l2cap/l2c_fcr.c
     @@ -24,6 +24,7 @@
    @@ -1797,10 +2146,28 @@ index 5ba8b5619..2b041f193 100644
      #include <stdio.h>
      #include <stdlib.h>
      #include <string.h>
    -@@ -848,6 +849,13 @@ void l2c_lcc_proc_pdu(tL2C_CCB *p_ccb, BT_HDR *p_buf)
    +@@ -839,6 +840,14 @@ void l2c_lcc_proc_pdu(tL2C_CCB *p_ccb, BT_HDR *p_buf)
    + 
    +     if (p_ccb->is_first_seg)
    +     {
    ++        if (p_buf->len < sizeof(sdu_length)) {
    ++            L2CAP_TRACE_ERROR("%s: buffer length=%d too small. Need at least 2.",
    ++                              __func__, p_buf->len);
    ++            android_errorWriteWithInfoLog(0x534e4554, "120665616", -1, NULL, 0);
    ++            /* Discard the buffer */
    ++            osi_free(p_buf);
    ++            return;
    ++        }
    +         STREAM_TO_UINT16(sdu_length, p);
    +         /* Check the SDU Length with local MTU size */
    +         if (sdu_length > p_ccb->local_conn_cfg.mtu)
    +@@ -848,6 +857,16 @@ void l2c_lcc_proc_pdu(tL2C_CCB *p_ccb, BT_HDR *p_buf)
                  return;
              }
      
    ++        p_buf->len -= sizeof(sdu_length);
    ++        p_buf->offset += sizeof(sdu_length);
    ++
     +        if (sdu_length < p_buf->len) {
     +            L2CAP_TRACE_ERROR("%s: Invalid sdu_length: %d", __func__, sdu_length);
     +            android_errorWriteWithInfoLog(0x534e4554, "112321180", -1, NULL, 0);
    @@ -1811,7 +2178,13 @@ index 5ba8b5619..2b041f193 100644
      
              if ((p_data = (BT_HDR *) osi_malloc(L2CAP_MAX_BUF_SIZE)) == NULL)
              {
    -@@ -865,7 +873,24 @@ void l2c_lcc_proc_pdu(tL2C_CCB *p_ccb, BT_HDR *p_buf)
    +@@ -859,13 +878,28 @@ void l2c_lcc_proc_pdu(tL2C_CCB *p_ccb, BT_HDR *p_buf)
    +         p_data->len = 0;
    +         p_ccb->ble_sdu_length = sdu_length;
    +         L2CAP_TRACE_DEBUG ("%s SDU Length = %d",__func__,sdu_length);
    +-        p_buf->len -= sizeof(sdu_length);
    +-        p_buf->offset += sizeof(sdu_length);
    +         p_data->offset = 0;
      
          }
          else
    @@ -1836,7 +2209,7 @@ index 5ba8b5619..2b041f193 100644
      
          memcpy((UINT8*)(p_data + 1) + p_data->offset + p_data->len, (UINT8*)(p_buf + 1) + p_buf->offset, p_buf->len);
          p_data->len += p_buf->len;
    -@@ -881,11 +906,6 @@ void l2c_lcc_proc_pdu(tL2C_CCB *p_ccb, BT_HDR *p_buf)
    +@@ -881,11 +915,6 @@ void l2c_lcc_proc_pdu(tL2C_CCB *p_ccb, BT_HDR *p_buf)
          {
              p_ccb->is_first_seg = FALSE;
          }
    
    From 28e55824845c169f8f052e6b1ca89a0105f55c2a Mon Sep 17 00:00:00 2001
    From: AndDiSa <anddisa@googlemail.com>
    Date: Sat, 18 May 2019 13:24:28 +0200
    Subject: [PATCH 113/159] switch branch for kernel
    
    Change-Id: Ie9c6b2515928e8bac6d437ea787881bc67c990b8
    ---
     default.xml | 2 +-
     1 file changed, 1 insertion(+), 1 deletion(-)
    
    diff --git a/default.xml b/default.xml
    index 96bee37..ae5beff 100644
    --- a/default.xml
    +++ b/default.xml
    @@ -368,7 +368,7 @@
       <project path="hardware/ti/omap3" name="platform/hardware/ti/omap3" groups="omap3" />
       <project path="hardware/ti/omap4-aah" name="platform/hardware/ti/omap4-aah" groups="omap4-aah" />
       <project path="hardware/ti/omap4xxx" name="platform/hardware/ti/omap4xxx" groups="omap4" />
    -  <project path="kernel/asus/grouper" name="android_kernel_asus_grouper" remote="ads" revision="ads-7.0.1" />
    +  <project path="kernel/asus/grouper" name="android_kernel_asus_grouper" remote="ads" revision="ads-7.1.0-stable" />
       <project path="libcore" name="platform/libcore" groups="pdk" />
       <project path="libnativehelper" name="platform/libnativehelper" groups="pdk" />
       <project path="ndk" name="platform/ndk" groups="generic_fs" />
    
    From f807c2b87bb789c0db2f7885e11f41f0a75c0273 Mon Sep 17 00:00:00 2001
    From: AndDiSa <anddisa@googlemail.com>
    Date: Sat, 18 May 2019 13:29:45 +0200
    Subject: [PATCH 114/159] update patches
    
    Change-Id: I8bfa60c1295870e25baf574c29d0fdb9716e05d5
    ---
     build.patch                     |   4 +-
     external_libmpeg2.patch         | 242 ++++++++++++++++++++++++++++++++
     external_libnfc-nci.patch       | 240 ++++++++++++++++++++++++++++++-
     external_tremolo.patch          |  67 ++++++---
     external_wpa_supplicant_8.patch |  13 +-
     frameworks_av.patch             |  15 ++
     system_bt.patch                 | 117 +++++++++++----
     system_core.patch               | 119 ++++++++++++++--
     8 files changed, 752 insertions(+), 65 deletions(-)
    
    diff --git a/build.patch b/build.patch
    index 53c6c6c..5247dbb 100644
    --- a/build.patch
    +++ b/build.patch
    @@ -323,7 +323,7 @@ index 000000000..80664faf2
     +ALL_PREBUILT += $(INSTALLED_KERNEL_TARGET)
     +endif
     diff --git a/core/version_defaults.mk b/core/version_defaults.mk
    -index 7c9634490..5376c6b46 100644
    +index 7c9634490..c0ceb52a2 100644
     --- a/core/version_defaults.mk
     +++ b/core/version_defaults.mk
     @@ -131,7 +131,7 @@ ifeq "" "$(PLATFORM_SECURITY_PATCH)"
    @@ -331,7 +331,7 @@ index 7c9634490..5376c6b46 100644
          #  It must match one of the Android Security Patch Level strings of the Public Security Bulletins.
          #  If there is no $PLATFORM_SECURITY_PATCH set, keep it empty.
     -    PLATFORM_SECURITY_PATCH := 2017-08-05
    -+    PLATFORM_SECURITY_PATCH := 2019-03-05
    ++    PLATFORM_SECURITY_PATCH := 2019-05-05
      endif
      
      ifeq "" "$(PLATFORM_BASE_OS)"
    diff --git a/external_libmpeg2.patch b/external_libmpeg2.patch
    index 345816c..9eabca3 100644
    --- a/external_libmpeg2.patch
    +++ b/external_libmpeg2.patch
    @@ -1,3 +1,245 @@
    +diff --git a/common/arm/ideint_cac_a9.s b/common/arm/ideint_cac_a9.s
    +index 964c5e6..9de9752 100644
    +--- a/common/arm/ideint_cac_a9.s
    ++++ b/common/arm/ideint_cac_a9.s
    +@@ -66,6 +66,7 @@
    + ideint_cac_8x8_a9:
    + 
    +     stmfd       sp!,    {r4-r10, lr}
    ++    vpush      {d9}
    + 
    +     @ Load first row of top
    +     vld1.u8     d28,    [r0],   r2
    +@@ -210,4 +211,5 @@ ideint_cac_8x8_a9:
    +     vmov.u32    r0,     d0[0]
    +     cmp         r0,     #0
    +     movne       r0,     #1
    ++    vpop        {d9}
    +     ldmfd       sp!,    {r4-r10, pc}
    +diff --git a/common/arm/impeg2_idct.s b/common/arm/impeg2_idct.s
    +index 0b83b72..2f29f43 100644
    +--- a/common/arm/impeg2_idct.s
    ++++ b/common/arm/impeg2_idct.s
    +@@ -108,6 +108,7 @@ gai2_impeg2_idct_first_col_q11_addr2:
    +     .global impeg2_idct_recon_dc_a9q
    + impeg2_idct_recon_dc_a9q:
    +     stmfd           sp!, {r4, r6, r12, lr}
    ++    vpush           {d8-d15}
    +     @//r0: pi2_src
    +     @//r1: pi2_tmp - not used, used as pred_strd
    +     @//r2: pu1_pred
    +@@ -115,8 +116,8 @@ impeg2_idct_recon_dc_a9q:
    +     @//r4: used as scratch
    +     @//r5:
    + 
    +-    ldr             r1, [sp, #20]       @//pred_strd
    +-    ldr             r6, [sp, #24]       @//dst_strd
    ++    ldr             r1, [sp, #84]       @//pred_strd
    ++    ldr             r6, [sp, #88]       @//dst_strd
    + 
    +     ldr             r14, gai2_impeg2_idct_q15_addr1
    + q15lbl1:
    +@@ -188,6 +189,7 @@ q11lbl1:
    + 
    +     vst1.8          d7, [r3], r6
    + 
    ++    vpop            {d8-d15}
    +     ldmfd           sp!, {r4, r6, r12, pc}
    + 
    + 
    +@@ -196,9 +198,10 @@ q11lbl1:
    +     .global impeg2_idct_recon_dc_mismatch_a9q
    + impeg2_idct_recon_dc_mismatch_a9q:
    +     stmfd           sp!, {r4-r12, lr}
    ++    vpush           {d8-d15}
    + 
    +-    ldr             r1, [sp, #44]       @//pred_strd
    +-    ldr             r6, [sp, #48]       @//dst_strd
    ++    ldr             r1, [sp, #108]      @//pred_strd
    ++    ldr             r6, [sp, #112]      @//dst_strd
    + 
    +     ldr             r14, gai2_impeg2_idct_q15_addr2
    + q15lbl2:
    +@@ -304,6 +307,7 @@ additive_lbl:
    +     vst1.8          d30, [r3], r6
    + 
    + 
    ++    vpop            {d8-d15}
    +     ldmfd           sp!, {r4-r12, pc}
    + 
    + 
    +@@ -406,12 +410,14 @@ impeg2_idct_recon_a9q:
    +     @// Copy the input pointer to another register
    +     @// Step 1 : load all constants
    +     stmfd           sp!, {r4-r12, lr}
    ++    vpush           {d8-d15}
    ++
    ++    ldr             r8, [sp, #108]        @ prediction stride
    ++    ldr             r7, [sp, #112]        @ destination stride
    ++    ldr             r6, [sp, #104]            @ src stride
    ++    ldr             r12, [sp, #116]
    ++    ldr             r11, [sp, #120]
    + 
    +-    ldr             r8, [sp, #44]        @ prediction stride
    +-    ldr             r7, [sp, #48]        @ destination stride
    +-    ldr             r6, [sp, #40]            @ src stride
    +-    ldr             r12, [sp, #52]
    +-    ldr             r11, [sp, #56]
    +     mov             r6, r6, lsl #1      @ x sizeof(word16)
    +     add             r9, r0, r6, lsl #1  @ 2 rows
    + 
    +@@ -1198,6 +1204,7 @@ pred_buff_addition:
    + 
    + 
    + 
    ++    vpop            {d8-d15}
    +     ldmfd           sp!, {r4-r12, pc}
    + 
    + 
    +diff --git a/common/arm/impeg2_inter_pred.s b/common/arm/impeg2_inter_pred.s
    +index f1b3dde..23beca1 100644
    +--- a/common/arm/impeg2_inter_pred.s
    ++++ b/common/arm/impeg2_inter_pred.s
    +@@ -100,7 +100,7 @@
    + 
    + impeg2_copy_mb_a9q:
    + 
    +-    stmfd           r13!, {r4, r5, r14}
    ++    stmfd           sp!, {r4, r5, r14}
    + 
    + 
    +     ldr             r4, [r0]            @src->y
    +@@ -188,7 +188,7 @@ impeg2_copy_mb_a9q:
    +     vld1.8          {d0}, [r4], r2      @Load and increment src
    +     vst1.8          {d0}, [r5], r3      @Store and increment dst
    + 
    +-    ldmfd           r13!, {r4, r5, pc}
    ++    ldmfd           sp!, {r4, r5, pc}
    + 
    + 
    + 
    +@@ -223,7 +223,8 @@ impeg2_copy_mb_a9q:
    + 
    + impeg2_mc_fullx_halfy_8x8_a9q:
    + 
    +-    stmfd           r13!, {r14}
    ++    stmfd           sp!, {r14}
    ++    vpush           {d8-d9}
    +     add             r14, r1, r2
    +     mov             r2, r2, lsl #1
    + 
    +@@ -257,6 +258,7 @@ impeg2_mc_fullx_halfy_8x8_a9q:
    +     vst1.8          {d7}, [r14], r3     @// eighth row hence r8 = D7
    +     vst1.8          {d5}, [r0], r3      @// seventh row hence r7 = D5
    + 
    ++    vpop            {d8-d9}
    +     ldmfd           sp!, {pc}
    + 
    + 
    +@@ -315,27 +317,27 @@ impeg2_mc_halfx_fully_8x8_a9q:
    +     vld1.8          {d6, d7}, [r14], r2 @row6
    + 
    + 
    +-    vext.8          d8, d0, d1, #1      @Extract pixels (1-8) of row1
    ++    vext.8          d24, d0, d1, #1     @Extract pixels (1-8) of row1
    + 
    +-    vext.8          d12, d2, d3, #1     @Extract pixels (1-8) of row5
    ++    vext.8          d28, d2, d3, #1     @Extract pixels (1-8) of row5
    + 
    +     vext.8          d16, d4, d5, #1     @Extract pixels (1-8) of row2
    + 
    +     vext.8          d20, d6, d7, #1     @Extract pixels (1-8) of row6
    + 
    + 
    +-    vld1.8          {d9, d10}, [r1], r2 @load row3
    ++    vld1.8          {d25, d26}, [r1], r2 @load row3
    + 
    +-    vld1.8          {d13, d14}, [r14], r2 @load row7
    ++    vld1.8          {d29, d30}, [r14], r2 @load row7
    + 
    +     vld1.8          {d17, d18}, [r1], r2 @load  row4
    + 
    +     vld1.8          {d21, d22}, [r14], r2 @load  row8
    + 
    + 
    +-    vext.8          d1, d9, d10, #1     @Extract pixels (1-8) of row3
    ++    vext.8          d1, d25, d26, #1    @Extract pixels (1-8) of row3
    + 
    +-    vext.8          d3, d13, d14, #1    @Extract pixels (1-8) of row7
    ++    vext.8          d3, d29, d30, #1    @Extract pixels (1-8) of row7
    + 
    + 
    + 
    +@@ -344,9 +346,9 @@ impeg2_mc_halfx_fully_8x8_a9q:
    +     vext.8          d7, d21, d22, #1    @Extract pixels (1-8) of row8
    + 
    + 
    +-    vrhadd.u8       q0, q0, q4          @operate on row1 and row3
    ++    vrhadd.u8       q0, q0, q12         @operate on row1 and row3
    + 
    +-    vrhadd.u8       q1, q1, q6          @operate on row5 and row7
    ++    vrhadd.u8       q1, q1, q14         @operate on row5 and row7
    + 
    + 
    +     vrhadd.u8       q2, q2, q8          @operate on row2 and row4
    +@@ -415,6 +417,7 @@ impeg2_mc_halfx_fully_8x8_a9q:
    + impeg2_mc_halfx_halfy_8x8_a9q:
    + 
    +     stmfd           sp!, {r14}
    ++    vpush           {d8-d15}
    + 
    +     add             r14, r1, r2, lsl #2
    + 
    +@@ -548,6 +551,7 @@ impeg2_mc_halfx_halfy_8x8_a9q:
    + 
    + 
    + 
    ++    vpop            {d8-d15}
    +     ldmfd           sp!, {pc}
    + 
    + 
    +@@ -663,7 +667,8 @@ impeg2_mc_fullx_fully_8x8_a9q:
    + 
    + impeg2_interpolate_a9q:
    + 
    +-    stmfd           r13!, {r4, r5, r7, r12, r14}
    ++    stmfd           sp!, {r4, r5, r7, r12, r14}
    ++    vpush           {d8-d15}
    + 
    +     ldr             r4, [r0, #0]        @ptr_y src1
    + 
    +@@ -793,7 +798,8 @@ interp_chromablocks_stride:
    +     bne             interp_chromablocks_stride
    + 
    + 
    +-    ldmfd           r13!, {r4, r5, r7, r12, pc}
    ++    vpop            {d8-d15}
    ++    ldmfd           sp!, {r4, r5, r7, r12, pc}
    + 
    + 
    + 
    +diff --git a/common/arm/impeg2_mem_func.s b/common/arm/impeg2_mem_func.s
    +index 869b7d7..ea34db4 100644
    +--- a/common/arm/impeg2_mem_func.s
    ++++ b/common/arm/impeg2_mem_func.s
    +@@ -146,7 +146,7 @@ impeg2_memset_8bit_8x8_block_a9q:
    + 
    + impeg2_memset0_16bit_8x8_linear_block_a9q:
    + 
    +-    stmfd           r13!, {r14}
    ++    stmfd           sp!, {r14}
    + 
    +     vmov.i16        q0, #0
    + 
    +@@ -170,7 +170,7 @@ impeg2_memset0_16bit_8x8_linear_block_a9q:
    + 
    + 
    + 
    +-    ldmfd           r13!, {pc}
    ++    ldmfd           sp!, {pc}
    + 
    + 
    + 
     diff --git a/decoder/impeg2d_api_main.c b/decoder/impeg2d_api_main.c
     index c0813c4..847c4f7 100644
     --- a/decoder/impeg2d_api_main.c
    diff --git a/external_libnfc-nci.patch b/external_libnfc-nci.patch
    index a0eaf05..37867db 100644
    --- a/external_libnfc-nci.patch
    +++ b/external_libnfc-nci.patch
    @@ -563,6 +563,210 @@ index b812cff..84e55db 100644
              }
          }
      
    +diff --git a/src/nfc/tags/rw_i93.c b/src/nfc/tags/rw_i93.c
    +index cec6af9..61dd913 100644
    +--- a/src/nfc/tags/rw_i93.c
    ++++ b/src/nfc/tags/rw_i93.c
    +@@ -23,6 +23,7 @@
    +  *  mode.
    +  *
    +  ******************************************************************************/
    ++#include <log/log.h>
    + #include <string.h>
    + #include "nfc_target.h"
    + #include "bt_types.h"
    +@@ -203,7 +204,7 @@ void rw_i93_get_product_version (UINT8 *p_uid)
    + ** Returns          FALSE if retrying with protocol extension flag
    + **
    + *******************************************************************************/
    +-BOOLEAN rw_i93_process_sys_info (UINT8* p_data)
    ++BOOLEAN rw_i93_process_sys_info (UINT8* p_data, UINT16 length)
    + {
    +     UINT8      *p     = p_data;
    +     tRW_I93_CB *p_i93 = &rw_cb.tcb.i93;
    +@@ -211,38 +212,62 @@ BOOLEAN rw_i93_process_sys_info (UINT8* p_data)
    + 
    +     RW_TRACE_DEBUG0 ("rw_i93_process_sys_info ()");
    + 
    ++    if (length < (I93_UID_BYTE_LEN + 1)) {
    ++        android_errorWriteLog(0x534e4554, "121259048");
    ++        return false;
    ++    }
    +     STREAM_TO_UINT8 (p_i93->info_flags, p);
    ++    length--;
    + 
    +     p_uid = uid;
    +     STREAM_TO_ARRAY8 (p_uid, p);
    ++    length -= I93_UID_BYTE_LEN;
    + 
    +     if (p_i93->info_flags & I93_INFO_FLAG_DSFID)
    +     {
    ++        if (length == 0) {
    ++            android_errorWriteLog(0x534e4554, "121259048");
    ++            return false;
    ++        }
    +         STREAM_TO_UINT8 (p_i93->dsfid, p);
    ++	length--;
    +     }
    +     if (p_i93->info_flags & I93_INFO_FLAG_AFI)
    +     {
    ++        if (length == 0) {
    ++            android_errorWriteLog(0x534e4554, "121259048");
    ++            return false;
    ++        }
    +         STREAM_TO_UINT8 (p_i93->afi, p);
    ++	length--;
    +     }
    +     if (p_i93->info_flags & I93_INFO_FLAG_MEM_SIZE)
    +     {
    +-        if (p_i93->intl_flags & RW_I93_FLAG_16BIT_NUM_BLOCK)
    +-        {
    ++        bool block_16_bit = p_i93->intl_flags & RW_I93_FLAG_16BIT_NUM_BLOCK;
    ++        if (block_16_bit && length > 2) {
    +             STREAM_TO_UINT16 (p_i93->num_block, p);
    +-        }
    +-        else
    +-        {
    ++            length -= 2;
    ++        } else if (!block_16_bit && length > 1) {
    +             STREAM_TO_UINT8 (p_i93->num_block, p);
    ++            length--;
    ++        } else {
    ++           android_errorWriteLog(0x534e4554, "121259048");
    ++           return false;
    +         }
    +         /* it is one less than actual number of bytes */
    +         p_i93->num_block += 1;
    + 
    +         STREAM_TO_UINT8 (p_i93->block_size, p);
    ++	length--;
    +         /* it is one less than actual number of blocks */
    +         p_i93->block_size = (p_i93->block_size & 0x1F) + 1;
    +     }
    +     if (p_i93->info_flags & I93_INFO_FLAG_IC_REF)
    +     {
    ++        if (length == 0) {
    ++            android_errorWriteLog(0x534e4554, "121259048");
    ++            return false;
    ++        }
    +         STREAM_TO_UINT8 (p_i93->ic_reference, p);
    + 
    +         /* clear existing UID to set product version */
    +@@ -447,7 +472,7 @@ void rw_i93_send_to_upper (BT_HDR *p_resp)
    + 
    +     case I93_CMD_GET_SYS_INFO:
    + 
    +-        if (rw_i93_process_sys_info (p))
    ++        if (rw_i93_process_sys_info (p, length))
    +         {
    +             rw_data.i93_sys_info.status     = NFC_STATUS_OK;
    +             rw_data.i93_sys_info.info_flags = p_i93->info_flags;
    +@@ -1506,6 +1531,11 @@ void rw_i93_sm_detect_ndef (BT_HDR *p_resp)
    +     RW_TRACE_DEBUG1 ("rw_i93_sm_detect_ndef () sub_state:0x%x", p_i93->sub_state);
    + #endif
    + 
    ++    if (length == 0) {
    ++        android_errorWriteLog(0x534e4554, "121260197");
    ++        rw_i93_handle_error(NFC_STATUS_FAILED);
    ++        return;
    ++    }
    +     STREAM_TO_UINT8 (flags, p);
    +     length--;
    + 
    +@@ -1529,6 +1559,11 @@ void rw_i93_sm_detect_ndef (BT_HDR *p_resp)
    +     {
    +     case RW_I93_SUBSTATE_WAIT_UID:
    + 
    ++        if (length < (I93_UID_BYTE_LEN + 1)) {
    ++            android_errorWriteLog(0x534e4554, "121260197");
    ++            rw_i93_handle_error(NFC_STATUS_FAILED);
    ++            return;
    ++        }
    +         STREAM_TO_UINT8 (u8, p); /* DSFID */
    +         p_uid = p_i93->uid;
    +         STREAM_TO_ARRAY8 (p_uid, p);
    +@@ -1558,7 +1593,7 @@ void rw_i93_sm_detect_ndef (BT_HDR *p_resp)
    +         p_i93->block_size = 0;
    +         p_i93->num_block  = 0;
    + 
    +-        if (!rw_i93_process_sys_info (p))
    ++        if (!rw_i93_process_sys_info (p, length))
    +         {
    +             /* retrying with protocol extension flag */
    +             break;
    +@@ -1952,6 +1987,12 @@ void rw_i93_sm_read_ndef (BT_HDR *p_resp)
    + 
    +     RW_TRACE_DEBUG0 ("rw_i93_sm_read_ndef ()");
    + 
    ++    if (length == 0) {
    ++        android_errorWriteLog(0x534e4554, "122035770");
    ++        rw_i93_handle_error(NFC_STATUS_FAILED);
    ++        return;
    ++    }
    ++
    +     STREAM_TO_UINT8 (flags, p);
    +     length--;
    + 
    +@@ -2067,6 +2108,12 @@ void rw_i93_sm_update_ndef (BT_HDR *p_resp)
    +     RW_TRACE_DEBUG1 ("rw_i93_sm_update_ndef () sub_state:0x%x", p_i93->sub_state);
    + #endif
    + 
    ++    if (length == 0 || p_i93->block_size > I93_MAX_BLOCK_LENGH) {
    ++        android_errorWriteLog(0x534e4554, "122320256");
    ++        rw_i93_handle_error(NFC_STATUS_FAILED);
    ++        return;
    ++    }
    ++
    +     STREAM_TO_UINT8 (flags, p);
    +     length--;
    + 
    +@@ -2096,6 +2143,12 @@ void rw_i93_sm_update_ndef (BT_HDR *p_resp)
    +         /* get offset of length field */
    +         length_offset = (p_i93->ndef_tlv_start_offset + 1) % p_i93->block_size;
    + 
    ++        if (length < length_offset) {
    ++            android_errorWriteLog(0x534e4554, "122320256");
    ++            rw_i93_handle_error(NFC_STATUS_FAILED);
    ++            return;
    ++        }
    ++ 
    +         /* set length to zero */
    +         *(p + length_offset) = 0x00;
    + 
    +@@ -2114,6 +2167,11 @@ void rw_i93_sm_update_ndef (BT_HDR *p_resp)
    +             /* write the first part of NDEF in the same block */
    +             for ( ; xx < p_i93->block_size; xx++)
    +             {
    ++                if (xx > length || p_i93->rw_length > p_i93->ndef_length) {
    ++                    android_errorWriteLog(0x534e4554, "122320256");
    ++                    rw_i93_handle_error(NFC_STATUS_FAILED);
    ++                    return;
    ++                }
    +                 if (p_i93->rw_length < p_i93->ndef_length)
    +                 {
    +                     *(p + xx) = *(p_i93->p_update_data + p_i93->rw_length++);
    +@@ -2289,6 +2347,12 @@ void rw_i93_sm_update_ndef (BT_HDR *p_resp)
    +                 /* update length field within the read block */
    +                 for (xx = length_offset; xx < p_i93->block_size; xx++)
    +                 {
    ++                    if (xx > length) {
    ++                        android_errorWriteLog(0x534e4554, "122320256");
    ++                        rw_i93_handle_error(NFC_STATUS_FAILED);
    ++                        return;
    ++                    }
    ++
    +                     if (p_i93->rw_length == 3)
    +                         *(p + xx) = 0xFF;
    +                     else if (p_i93->rw_length == 2)
    +@@ -2418,7 +2482,7 @@ void rw_i93_sm_format (BT_HDR *p_resp)
    +         p_i93->block_size = 0;
    +         p_i93->num_block  = 0;
    + 
    +-        if (!rw_i93_process_sys_info (p))
    ++        if (!rw_i93_process_sys_info (p, length))
    +         {
    +             /* retrying with protocol extension flag */
    +             break;
     diff --git a/src/nfc/tags/rw_t2t_ndef.c b/src/nfc/tags/rw_t2t_ndef.c
     index 3304a90..37dd8e4 100644
     --- a/src/nfc/tags/rw_t2t_ndef.c
    @@ -629,7 +833,7 @@ index 3304a90..37dd8e4 100644
                      {
                          found = TRUE;
     diff --git a/src/nfc/tags/rw_t3t.c b/src/nfc/tags/rw_t3t.c
    -index f8ec361..70cb2e3 100644
    +index f8ec361..45a74dd 100644
     --- a/src/nfc/tags/rw_t3t.c
     +++ b/src/nfc/tags/rw_t3t.c
     @@ -1285,6 +1285,10 @@ void rw_t3t_act_handle_ndef_detect_rsp (tRW_T3T_CB *p_cb, BT_HDR *p_msg_rsp)
    @@ -663,7 +867,35 @@ index f8ec361..70cb2e3 100644
          }
      
      
    -@@ -1667,8 +1675,12 @@ static void rw_t3t_handle_get_sc_poll_rsp (tRW_T3T_CB *p_cb, UINT8 nci_status, U
    +@@ -1514,11 +1522,11 @@ void rw_t3t_act_handle_check_ndef_rsp (tRW_T3T_CB *p_cb, BT_HDR *p_msg_rsp)
    +         RW_TRACE_ERROR2 ("Response error: expecting rsp_code %02X, but got %02X", T3T_MSG_OPC_CHECK_RSP, p_t3t_rsp[T3T_MSG_RSP_OFFSET_RSPCODE]);
    +         nfc_status = NFC_STATUS_FAILED;
    +         GKI_freebuf (p_msg_rsp);
    +-    }
    +-    else
    +-    {
    ++    } else if (p_msg_rsp->len >= T3T_MSG_RSP_OFFSET_CHECK_DATA &&
    ++               p_t3t_rsp[T3T_MSG_RSP_OFFSET_NUMBLOCKS] > 0) {
    +         /* Notify app of NDEF segment received */
    +-        rsp_num_bytes_rx = p_t3t_rsp[T3T_MSG_RSP_OFFSET_NUMBLOCKS] * 16;    /* Number of bytes received, according to header */
    ++        /* Number of bytes received, according to header */
    ++        rsp_num_bytes_rx = p_t3t_rsp[T3T_MSG_RSP_OFFSET_NUMBLOCKS] * 16;
    +         p_cb->ndef_rx_offset += p_cb->ndef_rx_readlen;
    +         read_data.status = NFC_STATUS_OK;
    +         p_msg_rsp->offset += T3T_MSG_RSP_OFFSET_CHECK_DATA;     /* Skip over t3t header (point to block data) */
    +@@ -1553,6 +1561,11 @@ void rw_t3t_act_handle_check_ndef_rsp (tRW_T3T_CB *p_cb, BT_HDR *p_msg_rsp)
    +                 }
    +             }
    +         }
    ++    } else {
    ++       android_errorWriteLog(0x534e4554, "120502559");
    ++       GKI_freebuf(p_msg_rsp);
    ++       nfc_status = NFC_STATUS_FAILED;
    ++       RW_TRACE_ERROR0("Underflow in p_msg_rsp->len!");
    +     }
    + 
    +     /* Notify app of RW_T3T_CHECK_CPLT_EVT if entire NDEF has been read, or if failure */
    +@@ -1667,8 +1680,12 @@ static void rw_t3t_handle_get_sc_poll_rsp (tRW_T3T_CB *p_cb, UINT8 nci_status, U
                  {
                      RW_TRACE_DEBUG1 ("FeliCa Lite tag detected (system code %04X)", sc);
                      /* Store system code */
    @@ -678,7 +910,7 @@ index f8ec361..70cb2e3 100644
                      /* Poll for NDEF system code */
                      if ((status = (tNFC_STATUS) nci_snd_t3t_polling (T3T_SYSTEM_CODE_NDEF, 0, 0)) == NCI_STATUS_OK)
                      {
    -@@ -1956,6 +1968,10 @@ void rw_t3t_act_handle_fmt_rsp (tRW_T3T_CB *p_cb, BT_HDR *p_msg_rsp)
    +@@ -1956,6 +1973,10 @@ void rw_t3t_act_handle_fmt_rsp (tRW_T3T_CB *p_cb, BT_HDR *p_msg_rsp)
                       ||(memcmp (p_cb->peer_nfcid2, &p_t3t_rsp[T3T_MSG_RSP_OFFSET_IDM], NCI_NFCID2_LEN) != 0)  )   /* verify response IDm */
              {
                  evt_data.status = NFC_STATUS_FAILED;
    @@ -689,7 +921,7 @@ index f8ec361..70cb2e3 100644
              }
              else
              {
    -@@ -2168,19 +2184,17 @@ void rw_t3t_act_handle_sro_rsp (tRW_T3T_CB *p_cb, BT_HDR *p_msg_rsp)
    +@@ -2168,19 +2189,17 @@ void rw_t3t_act_handle_sro_rsp (tRW_T3T_CB *p_cb, BT_HDR *p_msg_rsp)
                       ||(memcmp (p_cb->peer_nfcid2, &p_t3t_rsp[T3T_MSG_RSP_OFFSET_IDM], NCI_NFCID2_LEN) != 0)  )   /* verify response IDm */
              {
                  evt_data.status = NFC_STATUS_FAILED;
    diff --git a/external_tremolo.patch b/external_tremolo.patch
    index 8fd4003..31bf5b5 100644
    --- a/external_tremolo.patch
    +++ b/external_tremolo.patch
    @@ -1,5 +1,5 @@
     diff --git a/Tremolo/codebook.c b/Tremolo/codebook.c
    -index 4d0dd91..467640d 100644
    +index 4d0dd91..a06302d 100644
     --- a/Tremolo/codebook.c
     +++ b/Tremolo/codebook.c
     @@ -59,7 +59,7 @@ int _ilog(unsigned int v){
    @@ -300,7 +300,34 @@ index 4d0dd91..467640d 100644
            }
          }
        }
    -@@ -436,23 +436,23 @@ int vorbis_book_unpack(oggpack_buffer *opb,codebook *s){
    +@@ -376,14 +376,21 @@ long _book_maptype1_quantvals(codebook *b){
    +     long acc=1;
    +     long acc1=1;
    +     int i;
    +-    for(i=0;i<b->dim;i++){
    +-      acc*=vals;
    +-      acc1*=vals+1;
    ++    for (i = 0; i < b->dim; i++) {
    ++      if (acc > b->entries / vals) {
    ++          break;
    ++      }
    ++      acc *= vals;
    ++      if (acc1 > LONG_MAX / (vals + 1)) {
    ++        acc1 = LONG_MAX;
    ++      } else {
    ++        acc1 *= (vals + 1);
    ++      }
    +     }
    +-    if(acc<=b->entries && acc1>b->entries){
    ++    if (i >= b->dim && acc <= b->entries && acc1 > b->entries) {
    +       return(vals);
    +     }else{
    +-      if(acc>b->entries){
    ++      if (i < b->dim || acc > b->entries) {
    +         vals--;
    +       }else{
    +         vals++;
    +@@ -436,23 +443,23 @@ int vorbis_book_unpack(oggpack_buffer *opb,codebook *s){
            /* yes, unused entries */
      
            for(i=0;i<s->entries;i++){
    @@ -336,7 +363,7 @@ index 4d0dd91..467640d 100644
            }
          }
      
    -@@ -467,12 +467,12 @@ int vorbis_book_unpack(oggpack_buffer *opb,codebook *s){
    +@@ -467,12 +474,12 @@ int vorbis_book_unpack(oggpack_buffer *opb,codebook *s){
            if (!lengthlist) goto _eofout;
      
            for(i=0;i<s->entries;){
    @@ -355,7 +382,7 @@ index 4d0dd91..467640d 100644
            }
          }
          break;
    -@@ -524,55 +524,55 @@ int vorbis_book_unpack(oggpack_buffer *opb,codebook *s){
    +@@ -524,55 +531,55 @@ int vorbis_book_unpack(oggpack_buffer *opb,codebook *s){
      
      
            if(total1<=4 && total1<=total2){
    @@ -458,7 +485,7 @@ index 4d0dd91..467640d 100644
      
            }
          }
    -@@ -604,11 +604,11 @@ int vorbis_book_unpack(oggpack_buffer *opb,codebook *s){
    +@@ -604,11 +611,11 @@ int vorbis_book_unpack(oggpack_buffer *opb,codebook *s){
            s->q_val=_ogg_malloc(s->q_pack*s->used_entries);
      
            if(s->q_bits<=8){
    @@ -474,7 +501,7 @@ index 4d0dd91..467640d 100644
            }
          }
          break;
    -@@ -646,7 +646,7 @@ ogg_uint32_t decode_packed_entry_number(codebook *book,
    +@@ -646,7 +653,7 @@ ogg_uint32_t decode_packed_entry_number(codebook *book,
                                              oggpack_buffer *b);
      #else
      static inline ogg_uint32_t decode_packed_entry_number(codebook *book,
    @@ -483,7 +510,7 @@ index 4d0dd91..467640d 100644
        ogg_uint32_t chase=0;
        int  read=book->dec_maxlength;
        long lok = oggpack_look(b,read),i;
    -@@ -669,8 +669,8 @@ static inline ogg_uint32_t decode_packed_entry_number(codebook *book,
    +@@ -669,8 +676,8 @@ static inline ogg_uint32_t decode_packed_entry_number(codebook *book,
            unsigned char *t=(unsigned char *)book->dec_table;
      
            for(i=0;i<read;i++){
    @@ -494,7 +521,7 @@ index 4d0dd91..467640d 100644
            }
            chase&=0x7fUL;
            break;
    -@@ -681,13 +681,13 @@ static inline ogg_uint32_t decode_packed_entry_number(codebook *book,
    +@@ -681,13 +688,13 @@ static inline ogg_uint32_t decode_packed_entry_number(codebook *book,
            /* 8/16 - Used by infile2 */
            unsigned char *t=(unsigned char *)book->dec_table;
            for(i=0;i<read;i++){
    @@ -515,7 +542,7 @@ index 4d0dd91..467640d 100644
            }
            //chase&=0x7fffUL;
            chase&=~0x8000UL;
    -@@ -698,8 +698,8 @@ static inline ogg_uint32_t decode_packed_entry_number(codebook *book,
    +@@ -698,8 +705,8 @@ static inline ogg_uint32_t decode_packed_entry_number(codebook *book,
            /* book->dec_nodeb==2, book->dec_leafw==1 */
            /* 16/16 - Used */
            for(i=0;i<read;i++){
    @@ -526,7 +553,7 @@ index 4d0dd91..467640d 100644
            }
            //chase&=0x7fffUL;
            chase&=~0x8000UL;
    -@@ -711,13 +711,13 @@ static inline ogg_uint32_t decode_packed_entry_number(codebook *book,
    +@@ -711,13 +718,13 @@ static inline ogg_uint32_t decode_packed_entry_number(codebook *book,
            /* 16/32 - Used by infile2 */
            ogg_uint16_t *t=(ogg_uint16_t *)book->dec_table;
            for(i=0;i<read;i++){
    @@ -547,7 +574,7 @@ index 4d0dd91..467640d 100644
            }
            //chase&=0x7fffffffUL;
            chase&=~0x80000000UL;
    -@@ -727,8 +727,8 @@ static inline ogg_uint32_t decode_packed_entry_number(codebook *book,
    +@@ -727,8 +734,8 @@ static inline ogg_uint32_t decode_packed_entry_number(codebook *book,
          {
            //Output("32/32");
            for(i=0;i<read;i++){
    @@ -558,7 +585,7 @@ index 4d0dd91..467640d 100644
            }
            //chase&=0x7fffffffUL;
            chase&=~0x80000000UL;
    -@@ -777,9 +777,9 @@ static int decode_map(codebook *s, oggpack_buffer *b, ogg_int32_t *v, int point)
    +@@ -777,9 +784,9 @@ static int decode_map(codebook *s, oggpack_buffer *b, ogg_int32_t *v, int point)
          int mask=(1<<s->q_pack)-1;
          for(i=0;i<s->dim;i++){
            if(s->q_bits<=8)
    @@ -570,7 +597,7 @@ index 4d0dd91..467640d 100644
            entry>>=s->q_pack;
          }
          break;
    -@@ -790,10 +790,10 @@ static int decode_map(codebook *s, oggpack_buffer *b, ogg_int32_t *v, int point)
    +@@ -790,10 +797,10 @@ static int decode_map(codebook *s, oggpack_buffer *b, ogg_int32_t *v, int point)
      
          if(s->q_bits<=8){
            for(i=0;i<s->dim;i++)
    @@ -583,7 +610,7 @@ index 4d0dd91..467640d 100644
          }
          break;
        }
    -@@ -823,7 +823,7 @@ static int decode_map(codebook *s, oggpack_buffer *b, ogg_int32_t *v, int point)
    +@@ -823,7 +830,7 @@ static int decode_map(codebook *s, oggpack_buffer *b, ogg_int32_t *v, int point)
      
          if(s->q_seq)
            for(i=1;i<s->dim;i++)
    @@ -592,7 +619,7 @@ index 4d0dd91..467640d 100644
        }
      
        return 0;
    -@@ -832,7 +832,7 @@ static int decode_map(codebook *s, oggpack_buffer *b, ogg_int32_t *v, int point)
    +@@ -832,7 +839,7 @@ static int decode_map(codebook *s, oggpack_buffer *b, ogg_int32_t *v, int point)
      
      /* returns 0 on OK or -1 on eof *************************************/
      long vorbis_book_decodevs_add(codebook *book,ogg_int32_t *a,
    @@ -601,7 +628,7 @@ index 4d0dd91..467640d 100644
        if(book->used_entries>0){
          int step=n/book->dim;
          ogg_int32_t *v = book->dec_buf;//(ogg_int32_t *)alloca(sizeof(*v)*book->dim);
    -@@ -842,14 +842,14 @@ long vorbis_book_decodevs_add(codebook *book,ogg_int32_t *a,
    +@@ -842,14 +849,14 @@ long vorbis_book_decodevs_add(codebook *book,ogg_int32_t *a,
          for (j=0;j<step;j++){
            if(decode_map(book,b,v,point))return -1;
            for(i=0,o=j;i<book->dim;i++,o+=step)
    @@ -618,7 +645,7 @@ index 4d0dd91..467640d 100644
        if(book->used_entries>0){
          ogg_int32_t *v = book->dec_buf;//(ogg_int32_t *)alloca(sizeof(*v)*book->dim);
          int i,j;
    -@@ -857,15 +857,15 @@ long vorbis_book_decodev_add(codebook *book,ogg_int32_t *a,
    +@@ -857,15 +864,15 @@ long vorbis_book_decodev_add(codebook *book,ogg_int32_t *a,
          if (!v) return -1;
          for(i=0;i<n;){
            if(decode_map(book,b,v,point))return -1;
    @@ -637,7 +664,7 @@ index 4d0dd91..467640d 100644
        if(book->used_entries>0){
          ogg_int32_t *v = book->dec_buf;//(ogg_int32_t *)alloca(sizeof(*v)*book->dim);
          int i,j;
    -@@ -873,15 +873,15 @@ long vorbis_book_decodev_set(codebook *book,ogg_int32_t *a,
    +@@ -873,15 +880,15 @@ long vorbis_book_decodev_set(codebook *book,ogg_int32_t *a,
          if (!v) return -1;
          for(i=0;i<n;){
            if(decode_map(book,b,v,point))return -1;
    @@ -657,7 +684,7 @@ index 4d0dd91..467640d 100644
          }
        }
      
    -@@ -890,12 +890,12 @@ long vorbis_book_decodev_set(codebook *book,ogg_int32_t *a,
    +@@ -890,12 +897,12 @@ long vorbis_book_decodev_set(codebook *book,ogg_int32_t *a,
      
      #ifndef ONLY_C
      long vorbis_book_decodevv_add(codebook *book,ogg_int32_t **a,
    @@ -674,7 +701,7 @@ index 4d0dd91..467640d 100644
        if(book->used_entries>0){
      
          ogg_int32_t *v = book->dec_buf;//(ogg_int32_t *)alloca(sizeof(*v)*book->dim);
    -@@ -905,12 +905,12 @@ long vorbis_book_decodevv_add(codebook *book,ogg_int32_t **a,
    +@@ -905,12 +912,12 @@ long vorbis_book_decodevv_add(codebook *book,ogg_int32_t **a,
          if (!v) return -1;
          for(i=offset;i<offset+n;){
            if(decode_map(book,b,v,point))return -1;
    diff --git a/external_wpa_supplicant_8.patch b/external_wpa_supplicant_8.patch
    index 61b33e4..49f28f6 100644
    --- a/external_wpa_supplicant_8.patch
    +++ b/external_wpa_supplicant_8.patch
    @@ -3643,7 +3643,7 @@ index 1b3d8a91..46f29240 100644
      	case EVENT_TDLS:
      		wpa_supplicant_event_tdls(wpa_s, data);
     diff --git a/wpa_supplicant/wnm_sta.c b/wpa_supplicant/wnm_sta.c
    -index f77d51ae..7dc1909d 100644
    +index f77d51ae..63a87aff 100644
     --- a/wpa_supplicant/wnm_sta.c
     +++ b/wpa_supplicant/wnm_sta.c
     @@ -259,7 +259,7 @@ static void ieee802_11_rx_wnmsleep_resp(struct wpa_supplicant *wpa_s,
    @@ -3664,6 +3664,17 @@ index f77d51ae..7dc1909d 100644
      	if (wnmsleep_ie->status == WNM_STATUS_SLEEP_ACCEPT ||
      	    wnmsleep_ie->status == WNM_STATUS_SLEEP_EXIT_ACCEPT_GTK_UPDATE) {
      		wpa_printf(MSG_DEBUG, "Successfully recv WNM-Sleep Response "
    +@@ -370,6 +372,10 @@ static void wnm_parse_neighbor_report_elem(struct neighbor_report *rep,
    + 		rep->preference_present = 1;
    + 		break;
    + 	case WNM_NEIGHBOR_BSS_TERMINATION_DURATION:
    ++		if (elen < 10) {
    ++			wpa_printf(MSG_DEBUG, "WNM: Too short bss_term_tsf");
    ++			break;
    ++		}
    + 		rep->bss_term_tsf = WPA_GET_LE64(pos);
    + 		rep->bss_term_dur = WPA_GET_LE16(pos + 8);
    + 		rep->bss_term_present = 1;
     diff --git a/wpa_supplicant/wpa_cli.c b/wpa_supplicant/wpa_cli.c
     index 36a7a4eb..ac1a36fb 100644
     --- a/wpa_supplicant/wpa_cli.c
    diff --git a/frameworks_av.patch b/frameworks_av.patch
    index 143900b..2ff125c 100644
    --- a/frameworks_av.patch
    +++ b/frameworks_av.patch
    @@ -4358,6 +4358,21 @@ index 0f9c11869..9d302ddbd 100644
     +}
     +
      }  // namespace android
    +diff --git a/media/libstagefright/rtsp/APacketSource.cpp b/media/libstagefright/rtsp/APacketSource.cpp
    +index cfafaa74b..a7545ad51 100644
    +--- a/media/libstagefright/rtsp/APacketSource.cpp
    ++++ b/media/libstagefright/rtsp/APacketSource.cpp
    +@@ -377,8 +377,8 @@ static sp<ABuffer> MakeMPEG4VideoCodecSpecificData(
    +     ALOGI("VOL dimensions = %dx%d", *width, *height);
    + 
    +     size_t len1 = config->size() + GetSizeWidth(config->size()) + 1;
    +-    size_t len2 = len1 + GetSizeWidth(len1) + 1 + 13;
    +-    size_t len3 = len2 + GetSizeWidth(len2) + 1 + 3;
    ++    size_t len2 = len1 + GetSizeWidth(len1 + 13) + 1 + 13;
    ++    size_t len3 = len2 + GetSizeWidth(len2 + 3) + 1 + 3;
    + 
    +     sp<ABuffer> csd = new ABuffer(len3);
    +     uint8_t *dst = csd->data();
     diff --git a/media/mediaserver/Android.mk b/media/mediaserver/Android.mk
     index 1738df80d..c2b9c1f95 100644
     --- a/media/mediaserver/Android.mk
    diff --git a/system_bt.patch b/system_bt.patch
    index 80bde9f..82b87fa 100644
    --- a/system_bt.patch
    +++ b/system_bt.patch
    @@ -1810,6 +1810,31 @@ index 13fb189e7..65acd33f6 100644
      }
      
      
    +diff --git a/stack/btm/btm_ble.c b/stack/btm/btm_ble.c
    +index 542c87a9b..813bf13fa 100644
    +--- a/stack/btm/btm_ble.c
    ++++ b/stack/btm/btm_ble.c
    +@@ -39,6 +39,7 @@
    + #include "device/include/controller.h"
    + #include "gap_api.h"
    + #include "hcimsgs.h"
    ++#include "log/log.h"
    + #include "l2c_int.h"
    + #include "osi/include/log.h"
    + #include "smp_api.h"
    +@@ -2090,6 +2091,12 @@ UINT8 btm_proc_smp_cback(tSMP_EVT event, BD_ADDR bd_addr, tSMP_EVT_DATA *p_data)
    + 
    +                 if (event == SMP_COMPLT_EVT)
    +                 {
    ++                    p_dev_rec = btm_find_dev(bd_addr);
    ++                    if (p_dev_rec == NULL) {
    ++                        BTM_TRACE_ERROR("%s: p_dev_rec is NULL", __func__);
    ++                        android_errorWriteLog(0x534e4554, "120612744");
    ++                        return 0;
    ++                    }
    +                     BTM_TRACE_DEBUG ("evt=SMP_COMPLT_EVT before update sec_level=0x%x sec_flags=0x%x", p_data->cmplt.sec_level , p_dev_rec->sec_flags );
    + 
    +                     res = (p_data->cmplt.reason == SMP_SUCCESS) ? BTM_SUCCESS : BTM_ERR_PROCESSING;
     diff --git a/stack/btm/btm_dev.c b/stack/btm/btm_dev.c
     index 8df005bf8..b278dea8f 100644
     --- a/stack/btm/btm_dev.c
    @@ -2222,7 +2247,7 @@ index 5ba8b5619..69e330b07 100644
          osi_free(p_buf);
          return;
     diff --git a/stack/l2cap/l2c_main.c b/stack/l2cap/l2c_main.c
    -index 3c48d6974..5eced537a 100644
    +index 3c48d6974..c0576c7da 100644
     --- a/stack/l2cap/l2c_main.c
     +++ b/stack/l2cap/l2c_main.c
     @@ -339,9 +339,17 @@ static void process_l2cap_cmd (tL2C_LCB *p_lcb, UINT8 *p, UINT16 pkt_len)
    @@ -2392,67 +2417,91 @@ index 3c48d6974..5eced537a 100644
                      STREAM_TO_UINT8 (cfg_code, p);
                      STREAM_TO_UINT8 (cfg_len, p);
      
    -@@ -564,16 +629,28 @@ static void process_l2cap_cmd (tL2C_LCB *p_lcb, UINT8 *p, UINT16 pkt_len)
    +@@ -564,16 +629,40 @@ static void process_l2cap_cmd (tL2C_LCB *p_lcb, UINT8 *p, UINT16 pkt_len)
                      {
                      case L2CAP_CFG_TYPE_MTU:
                          cfg_info.mtu_present = TRUE;
    -+                    if (p + 2 > p_next_cmd) {
    -+                      android_errorWriteLog(0x534e4554, "74202041");
    -+                      return;
    ++                    if (cfg_len != 2) {
    ++                        android_errorWriteLog(0x534e4554, "119870451");
    ++                        return;
    ++                    }
    ++                    if (p + cfg_len > p_next_cmd) {
    ++                        android_errorWriteLog(0x534e4554, "74202041");
    ++                        return;
     +                    }
                          STREAM_TO_UINT16 (cfg_info.mtu, p);
                          break;
      
                      case L2CAP_CFG_TYPE_FLUSH_TOUT:
                          cfg_info.flush_to_present = TRUE;
    -+                    if (p + 2 > p_next_cmd) {
    -+                      android_errorWriteLog(0x534e4554, "74202041");
    -+                      return;
    ++                    if (cfg_len != 2) {
    ++                        android_errorWriteLog(0x534e4554, "119870451");
    ++                        return;
    ++                    }
    ++                    if (p + cfg_len > p_next_cmd) {
    ++                        android_errorWriteLog(0x534e4554, "74202041");
    ++                        return;
     +                    }
                          STREAM_TO_UINT16 (cfg_info.flush_to, p);
                          break;
      
                      case L2CAP_CFG_TYPE_QOS:
                          cfg_info.qos_present = TRUE;
    -+                    if (p + 2 + 5 * 4 > p_next_cmd) {
    -+                      android_errorWriteLog(0x534e4554, "74202041");
    -+                      return;
    ++                    if (cfg_len != 2 + 5 * 4) {
    ++                        android_errorWriteLog(0x534e4554, "119870451");
    ++                        return;
    ++                    }
    ++                    if (p + cfg_len > p_next_cmd) {
    ++                        android_errorWriteLog(0x534e4554, "74202041");
    ++                        return;
     +                    }
                          STREAM_TO_UINT8  (cfg_info.qos.qos_flags, p);
                          STREAM_TO_UINT8  (cfg_info.qos.service_type, p);
                          STREAM_TO_UINT32 (cfg_info.qos.token_rate, p);
    -@@ -585,6 +662,10 @@ static void process_l2cap_cmd (tL2C_LCB *p_lcb, UINT8 *p, UINT16 pkt_len)
    +@@ -585,6 +674,14 @@ static void process_l2cap_cmd (tL2C_LCB *p_lcb, UINT8 *p, UINT16 pkt_len)
      
                      case L2CAP_CFG_TYPE_FCR:
                          cfg_info.fcr_present = TRUE;
    -+                    if (p + 3 + 3 * 2 > p_next_cmd) {
    -+                      android_errorWriteLog(0x534e4554, "74202041");
    -+                      return;
    ++                    if (cfg_len != 3 + 3 * 2) {
    ++                        android_errorWriteLog(0x534e4554, "119870451");
    ++                        return;
    ++                    }
    ++                    if (p + cfg_len > p_next_cmd) {
    ++                        android_errorWriteLog(0x534e4554, "74202041");
    ++                        return;
     +                    }
                          STREAM_TO_UINT8 (cfg_info.fcr.mode, p);
                          STREAM_TO_UINT8 (cfg_info.fcr.tx_win_sz, p);
                          STREAM_TO_UINT8 (cfg_info.fcr.max_transmit, p);
    -@@ -595,11 +676,19 @@ static void process_l2cap_cmd (tL2C_LCB *p_lcb, UINT8 *p, UINT16 pkt_len)
    +@@ -595,11 +692,27 @@ static void process_l2cap_cmd (tL2C_LCB *p_lcb, UINT8 *p, UINT16 pkt_len)
      
                      case L2CAP_CFG_TYPE_FCS:
                          cfg_info.fcs_present = TRUE;
    -+                    if (p + 1 > p_next_cmd) {
    -+                      android_errorWriteLog(0x534e4554, "74202041");
    -+                      return;
    ++                    if (cfg_len != 1) {
    ++                        android_errorWriteLog(0x534e4554, "119870451");
    ++                        return;
    ++                    }
    ++                    if (p + cfg_len > p_next_cmd) {
    ++                        android_errorWriteLog(0x534e4554, "74202041");
    ++                        return;
     +                    }
                          STREAM_TO_UINT8 (cfg_info.fcs, p);
                          break;
      
                      case L2CAP_CFG_TYPE_EXT_FLOW:
                          cfg_info.ext_flow_spec_present = TRUE;
    -+                    if (p + 2 + 2 + 3 * 4 > p_next_cmd) {
    -+                      android_errorWriteLog(0x534e4554, "74202041");
    -+                      return;
    ++                    if (cfg_len != 2 + 2 + 3 * 4) {
    ++                        android_errorWriteLog(0x534e4554, "119870451");
    ++                        return;
    ++                    }
    ++                    if (p + cfg_len > p_next_cmd) {
    ++                        android_errorWriteLog(0x534e4554, "74202041");
    ++                        return;
     +                    }
                          STREAM_TO_UINT8  (cfg_info.ext_flow_spec.id, p);
                          STREAM_TO_UINT8  (cfg_info.ext_flow_spec.stype, p);
                          STREAM_TO_UINT16 (cfg_info.ext_flow_spec.max_sdu_size, p);
    -@@ -630,6 +719,10 @@ static void process_l2cap_cmd (tL2C_LCB *p_lcb, UINT8 *p, UINT16 pkt_len)
    +@@ -630,6 +743,10 @@ static void process_l2cap_cmd (tL2C_LCB *p_lcb, UINT8 *p, UINT16 pkt_len)
                  break;
      
              case L2CAP_CMD_DISC_REQ:
    @@ -2463,7 +2512,7 @@ index 3c48d6974..5eced537a 100644
                  STREAM_TO_UINT16 (lcid, p);
                  STREAM_TO_UINT16 (rcid, p);
      
    -@@ -647,6 +740,10 @@ static void process_l2cap_cmd (tL2C_LCB *p_lcb, UINT8 *p, UINT16 pkt_len)
    +@@ -647,6 +764,10 @@ static void process_l2cap_cmd (tL2C_LCB *p_lcb, UINT8 *p, UINT16 pkt_len)
                  break;
      
              case L2CAP_CMD_DISC_RSP:
    @@ -2474,7 +2523,7 @@ index 3c48d6974..5eced537a 100644
                  STREAM_TO_UINT16 (rcid, p);
                  STREAM_TO_UINT16 (lcid, p);
      
    -@@ -676,6 +773,10 @@ static void process_l2cap_cmd (tL2C_LCB *p_lcb, UINT8 *p, UINT16 pkt_len)
    +@@ -676,6 +797,10 @@ static void process_l2cap_cmd (tL2C_LCB *p_lcb, UINT8 *p, UINT16 pkt_len)
                  break;
      
              case L2CAP_CMD_INFO_REQ:
    @@ -2485,7 +2534,7 @@ index 3c48d6974..5eced537a 100644
                  STREAM_TO_UINT16 (info_type, p);
                  l2cu_send_peer_info_rsp (p_lcb, id, info_type);
                  break;
    -@@ -688,6 +789,10 @@ static void process_l2cap_cmd (tL2C_LCB *p_lcb, UINT8 *p, UINT16 pkt_len)
    +@@ -688,6 +813,10 @@ static void process_l2cap_cmd (tL2C_LCB *p_lcb, UINT8 *p, UINT16 pkt_len)
                      p_lcb->w4_info_rsp = FALSE;
                  }
      
    @@ -2496,7 +2545,7 @@ index 3c48d6974..5eced537a 100644
                  STREAM_TO_UINT16 (info_type, p);
                  STREAM_TO_UINT16 (result, p);
      
    -@@ -696,6 +801,10 @@ static void process_l2cap_cmd (tL2C_LCB *p_lcb, UINT8 *p, UINT16 pkt_len)
    +@@ -696,6 +825,10 @@ static void process_l2cap_cmd (tL2C_LCB *p_lcb, UINT8 *p, UINT16 pkt_len)
                  if ( (info_type == L2CAP_EXTENDED_FEATURES_INFO_TYPE)
                    && (result == L2CAP_INFO_RESP_RESULT_SUCCESS) )
                  {
    @@ -2507,6 +2556,20 @@ index 3c48d6974..5eced537a 100644
                      STREAM_TO_UINT32( p_lcb->peer_ext_fea, p );
      
      #if (L2CAP_NUM_FIXED_CHNLS > 0)
    +diff --git a/stack/l2cap/l2c_utils.c b/stack/l2cap/l2c_utils.c
    +index 58ac4b06b..72bd52ed1 100644
    +--- a/stack/l2cap/l2c_utils.c
    ++++ b/stack/l2cap/l2c_utils.c
    +@@ -859,6 +859,9 @@ void l2cu_send_peer_config_rej (tL2C_CCB *p_ccb, UINT8 *p_data, UINT16 data_len,
    +             case L2CAP_CFG_TYPE_MTU:
    +             case L2CAP_CFG_TYPE_FLUSH_TOUT:
    +             case L2CAP_CFG_TYPE_QOS:
    ++            case L2CAP_CFG_TYPE_FCR:
    ++            case L2CAP_CFG_TYPE_FCS:
    ++            case L2CAP_CFG_TYPE_EXT_FLOW:
    +                 p_data += cfg_len + L2CAP_CFG_OPTION_OVERHEAD;
    +                 break;
    + 
     diff --git a/stack/l2cap/l2cap_client.c b/stack/l2cap/l2cap_client.c
     index 7e8b3cb6f..cd7edfe1f 100644
     --- a/stack/l2cap/l2cap_client.c
    diff --git a/system_core.patch b/system_core.patch
    index 302db7f..cd5b156 100644
    --- a/system_core.patch
    +++ b/system_core.patch
    @@ -580,6 +580,108 @@ index cd26d058a..bfc5f4d4e 100644
          saddr = packet.ip.saddr;
          daddr = packet.ip.daddr;
          nread = ntohs(packet.ip.tot_len);
    +diff --git a/libsuspend/autosuspend_autosleep.c b/libsuspend/autosuspend_autosleep.c
    +index 7262cc7e8..2160ba655 100644
    +--- a/libsuspend/autosuspend_autosleep.c
    ++++ b/libsuspend/autosuspend_autosleep.c
    +@@ -17,6 +17,7 @@
    + #include <errno.h>
    + #include <fcntl.h>
    + #include <stddef.h>
    ++#include <stdbool.h>
    + #include <string.h>
    + #include <sys/stat.h>
    + #include <sys/types.h>
    +diff --git a/libsuspend/autosuspend_earlysuspend.c b/libsuspend/autosuspend_earlysuspend.c
    +index 3793a699e..1bb09371f 100644
    +--- a/libsuspend/autosuspend_earlysuspend.c
    ++++ b/libsuspend/autosuspend_earlysuspend.c
    +@@ -14,18 +14,19 @@
    +  * limitations under the License.
    +  */
    + 
    ++#define LOG_TAG "libsuspend"
    ++
    + #include <errno.h>
    + #include <fcntl.h>
    + #include <pthread.h>
    + #include <stdbool.h>
    + #include <stddef.h>
    + #include <string.h>
    +-#include <sys/types.h>
    + #include <sys/stat.h>
    ++#include <sys/types.h>
    + #include <unistd.h>
    + 
    +-#define LOG_TAG "libsuspend"
    +-#include <cutils/log.h>
    ++#include <log/log.h>
    + 
    + #include "autosuspend_ops.h"
    + 
    +@@ -36,6 +37,7 @@
    + static int sPowerStatefd;
    + static const char *pwr_state_mem = "mem";
    + static const char *pwr_state_on = "on";
    ++static void (*wakeup_func)(bool success) = NULL;
    + static pthread_t earlysuspend_thread;
    + static pthread_mutex_t earlysuspend_mutex = PTHREAD_MUTEX_INITIALIZER;
    + static pthread_cond_t earlysuspend_cond = PTHREAD_COND_INITIALIZER;
    +@@ -107,6 +109,10 @@ static int autosuspend_earlysuspend_enable(void)
    +         goto err;
    +     }
    + 
    ++    if (wakeup_func != NULL) {
    ++        (*wakeup_func)(true);
    ++    }
    ++
    +     if (wait_for_earlysuspend) {
    +         pthread_mutex_lock(&earlysuspend_mutex);
    +         while (earlysuspend_state != EARLYSUSPEND_MEM) {
    +@@ -153,9 +159,27 @@ err:
    +     return ret;
    + }
    + 
    ++static int autosuspend_force_suspend(int timeout_ms) {
    ++    ALOGV("force_suspend called with timeout: %d\n", timeout_ms);
    ++
    ++    int ret = write(sPowerStatefd, pwr_state_mem, strlen(pwr_state_mem));
    ++
    ++    return ret < 0 ? ret : 0;
    ++}
    ++
    ++static void autosuspend_set_wakeup_callback(void (*func)(bool success)) {
    ++    if (wakeup_func != NULL) {
    ++        ALOGE("duplicate wakeup callback applied, keeping original\n");
    ++        return;
    ++    }
    ++    wakeup_func = func;
    ++}
    ++
    + struct autosuspend_ops autosuspend_earlysuspend_ops = {
    +         .enable = autosuspend_earlysuspend_enable,
    +         .disable = autosuspend_earlysuspend_disable,
    ++        .force_suspend = autosuspend_force_suspend,
    ++        .set_wakeup_callback = autosuspend_set_wakeup_callback,
    + };
    + 
    + void start_earlysuspend_thread(void)
    +diff --git a/libsuspend/autosuspend_ops.h b/libsuspend/autosuspend_ops.h
    +index 698e25be8..51b0bd5de 100644
    +--- a/libsuspend/autosuspend_ops.h
    ++++ b/libsuspend/autosuspend_ops.h
    +@@ -20,9 +20,10 @@
    + struct autosuspend_ops {
    +     int (*enable)(void);
    +     int (*disable)(void);
    ++    int (*force_suspend)(int timeout_ms);
    ++    void (*set_wakeup_callback)(void (*func)(bool success));
    + };
    + 
    +-struct autosuspend_ops *autosuspend_autosleep_init(void);
    + struct autosuspend_ops *autosuspend_earlysuspend_init(void);
    + struct autosuspend_ops *autosuspend_wakeup_count_init(void);
    + 
     diff --git a/libutils/String16.cpp b/libutils/String16.cpp
     index 65396caca..32e026bac 100644
     --- a/libutils/String16.cpp
    @@ -839,7 +941,7 @@ index 6aee1bbdf..b8db6a4d3 100644
        ::testing::InitGoogleTest(&argc, argv);
      
     diff --git a/rootdir/init.rc b/rootdir/init.rc
    -index 7dc9e5509..35ea5811e 100644
    +index 7dc9e5509..0fe1cb7fa 100644
     --- a/rootdir/init.rc
     +++ b/rootdir/init.rc
     @@ -136,6 +136,9 @@ on init
    @@ -852,13 +954,8 @@ index 7dc9e5509..35ea5811e 100644
          # Create cgroup mount points for process groups
          mkdir /dev/cpuctl
          mount cgroup none /dev/cpuctl cpu
    -@@ -656,6 +659,6 @@ on property:ro.debuggable=1
    -     chmod 0773 /data/misc/trace
    -     start console
    - 
    --service flash_recovery /system/bin/install-recovery.sh
    --    class main
    --    oneshot
    -+#service flash_recovery /system/bin/install-recovery.sh
    -+#    class main
    -+#    oneshot
    +@@ -659,3 +662,4 @@ on property:ro.debuggable=1
    + service flash_recovery /system/bin/install-recovery.sh
    +     class main
    +     oneshot
    ++    disabled
    
    From 60396849dd5006ad7c4af84ff0594d889f1306ab Mon Sep 17 00:00:00 2001
    From: AndDiSa <anddisa@googlemail.com>
    Date: Mon, 17 Jun 2019 12:58:18 +0200
    Subject: [PATCH 115/159] update unlegacy repo references
    
    Change-Id: If8e6b8d3f7f9bcddc1a50da73d760bf9d7d46ff4
    ---
     default.xml | 4 ++--
     1 file changed, 2 insertions(+), 2 deletions(-)
    
    diff --git a/default.xml b/default.xml
    index ae5beff..a73ed16 100644
    --- a/default.xml
    +++ b/default.xml
    @@ -329,7 +329,7 @@
       <project path="frameworks/wilhelm" name="platform/frameworks/wilhelm" groups="pdk-cw-fs,pdk-fs" />
       <project path="hardware/akm" name="platform/hardware/akm" />
       <project path="hardware/broadcom/libbt" name="platform/hardware/broadcom/libbt" groups="pdk" />
    -  <project path="hardware/broadcom/wlan" name="platform/hardware/broadcom/wlan" remote="unlegacy" revision="aosp-7.1" groups="pdk,broadcom_wlan" />
    +  <project path="hardware/broadcom/wlan" name="android_hardware_broadcom_wlan" remote="unlegacy" revision="aosp-7.1" groups="pdk,broadcom_wlan" />
       <project path="hardware/google/apf" name="platform/hardware/google/apf" groups="pdk" />
       <project path="hardware/intel/audio_media" name="platform/hardware/intel/audio_media" groups="intel" />
       <project path="hardware/intel/bootstub" name="platform/hardware/intel/bootstub" groups="intel" />
    @@ -471,7 +471,7 @@
       <project path="prebuilts/sdk" name="platform/prebuilts/sdk" groups="pdk" />
       <project path="prebuilts/tools" name="platform/prebuilts/tools" groups="pdk,tools" />
       <project path="sdk" name="platform/sdk" groups="pdk-cw-fs,pdk-fs" />
    -  <project path="system/bt" name="platform/system/bt" groups="pdk" remote="unlegacy" revision="aosp-7.1"/>
    +  <project path="system/bt" name="android_system_bt" groups="pdk" remote="unlegacy" revision="aosp-7.1"/>
       <project path="system/ca-certificates" name="platform/system/ca-certificates" groups="pdk" />
       <project path="system/connectivity/apmanager" name="platform/system/connectivity/apmanager" />
       <project path="system/connectivity/dhcp_client" name="platform/system/connectivity/dhcp_client" />
    
    From 7a41992fb81a2b2b163ea5aa5eddfef239c63cdb Mon Sep 17 00:00:00 2001
    From: AndDiSa <anddisa@googlemail.com>
    Date: Mon, 17 Jun 2019 16:37:28 +0200
    Subject: [PATCH 116/159] use forked repos
    
    Change-Id: I4c175948fa2df3310a444e232e4bf099027cdea6
    ---
     default.xml | 94 ++++++++++++++++++++++++++---------------------------
     1 file changed, 47 insertions(+), 47 deletions(-)
    
    diff --git a/default.xml b/default.xml
    index a73ed16..d9e0890 100644
    --- a/default.xml
    +++ b/default.xml
    @@ -11,7 +11,7 @@
                remote="aosp"
                sync-j="4" />
     
    -  <project path="build" name="platform/build" groups="pdk,tradefed" >
    +  <project path="build" name="platform_build" remote="ads" revision="ads-7.1.0" groups="pdk,tradefed" >
         <copyfile src="core/root.mk" dest="Makefile" />
       </project>
       <project path="build/blueprint" name="platform/build/blueprint" groups="pdk,tradefed" />
    @@ -21,7 +21,7 @@
         <linkfile src="bootstrap.bash" dest="bootstrap.bash" />
       </project>
       <project path="art" name="platform/art" groups="pdk" />
    -  <project path="bionic" name="platform/bionic" groups="pdk" />
    +  <project path="bionic" name="platform_bionic" remote="ads" revision="ads-7.1.0" groups="pdk" />
       <project path="bootable/recovery" name="platform/bootable/recovery" groups="pdk" />
       <project path="dalvik" name="platform/dalvik" groups="pdk-cw-fs,pdk-fs" />
       <project path="developers/build" name="platform/developers/build" />
    @@ -49,15 +49,15 @@
       <project path="device/google/contexthub" name="device/google/contexthub" groups="device" />
       <project path="device/sample" name="device/sample" groups="pdk" />
       <project path="docs/source.android.com" name="platform/docs/source.android.com" groups="pdk-cw-fs,pdk-fs" />
    -  <project path="external/aac" name="platform/external/aac" groups="pdk" />
    +  <project path="external/aac" name="external_aac" remote="ads" revision="ads-7.1.0" groups="pdk" />
       <project path="external/adt-infra" name="platform/external/adt-infra" groups="adt-infra,notdefault" />
    -  <project path="external/android-clat" name="platform/external/android-clat" groups="pdk-cw-fs,pdk-fs" />
    +  <project path="external/android-clat" name="external_android-clat" remote="ads" revision="ads-7.1.0" groups="pdk-cw-fs,pdk-fs" />
       <project path="external/androidplot" name="platform/external/androidplot" groups="pdk-cw-fs,pdk-fs" />
       <project path="external/ant-glob" name="platform/external/ant-glob" groups="pdk-cw-fs,pdk-fs" />
       <project path="external/antlr" name="platform/external/antlr" groups="pdk-cw-fs,pdk-fs" />
       <project path="external/apache-commons-math" name="platform/external/apache-commons-math" groups="pdk-cw-fs,pdk-fs" />
       <project path="external/apache-harmony" name="platform/external/apache-harmony" groups="pdk-cw-fs,pdk-fs" />
    -  <project path="external/apache-http" name="platform/external/apache-http" groups="pdk" />
    +  <project path="external/apache-http" name="external_apache-http" remote="ads" revision="ads-7.1.0" groups="pdk" />
       <project path="external/apache-xml" name="platform/external/apache-xml" groups="pdk" />
       <project path="external/archive-patcher" name="platform/external/archive-patcher" groups="pdk" />
       <project path="external/autotest" name="platform/external/autotest" />
    @@ -72,7 +72,7 @@
       <project path="external/caliper" name="platform/external/caliper" />
       <project path="external/cblas" name="platform/external/cblas" groups="pdk" />
       <project path="external/ceres-solver" name="platform/external/ceres-solver" groups="pdk-cw-fs,pdk-fs" />
    -  <project path="external/chromium-libpac" name="platform/external/chromium-libpac" groups="pdk-fs" />
    +  <project path="external/chromium-libpac" name="external_chromium-libpac" remote="ads" revision="ads-7.1.0" groups="pdk-fs" />
       <project path="external/chromium-trace" name="platform/external/chromium-trace" groups="pdk" />
       <project path="external/chromium-webview" name="platform/external/chromium-webview" groups="pdk" />
       <project path="external/clang" name="platform/external/clang" groups="pdk" />
    @@ -96,7 +96,7 @@
       <project path="external/drm_gralloc" name="platform/external/drm_gralloc" groups="drm_gralloc" />
       <project path="external/drm_hwcomposer" name="platform/external/drm_hwcomposer" groups="drm_hwcomposer" />
       <project path="external/droiddriver" name="platform/external/droiddriver" groups="pdk-cw-fs,pdk-fs" />
    -  <project path="external/e2fsprogs" name="platform/external/e2fsprogs" groups="pdk" />
    +  <project path="external/e2fsprogs" name="external_e2fsgrogs" remote="ads" revision="ads-7.1.2" groups="pdk" />
       <project path="external/easymock" name="platform/external/easymock" groups="pdk-cw-fs,pdk-fs" />
       <project path="external/eclipse-basebuilder" name="platform/external/eclipse-basebuilder" groups="pdk-cw-fs,pdk-fs" />
       <project path="external/eclipse-windowbuilder" name="platform/external/eclipse-windowbuilder" groups="pdk-cw-fs,pdk-fs" />
    @@ -158,7 +158,7 @@
       <project path="external/junit" name="platform/external/junit" groups="pdk-cw-fs,pdk-fs" />
       <project path="external/kernel-headers" name="platform/external/kernel-headers" groups="pdk-cw-fs,pdk-fs" />
       <project path="external/ksoap2" name="platform/external/ksoap2" groups="pdk-cw-fs,pdk-fs" />
    -  <project path="external/libavc" name="platform/external/libavc" groups="pdk" />
    +  <project path="external/libavc" name="external_libavc" remote="ads" revision="ads-7.1.0" groups="pdk" />
       <project path="external/libbrillo" name="platform/external/libbrillo" />
       <project path="external/libcap" name="platform/external/libcap" />
       <project path="external/libcap-ng" name="platform/external/libcap-ng" groups="pdk-cw-fs,pdk-fs" />
    @@ -166,19 +166,19 @@
       <project path="external/libcxx" name="platform/external/libcxx" groups="pdk" />
       <project path="external/libcxxabi" name="platform/external/libcxxabi" groups="pdk" />
       <project path="external/libdivsufsort" name="platform/external/libdivsufsort" groups="pdk" />
    -  <project path="external/libdrm" name="platform/external/libdrm" groups="pdk" />
    +  <project path="external/libdrm" name="external_libdrm" remote="ads" revision="ads-7.1.0" groups="pdk" />
       <project path="external/libedit" name="platform/external/libedit" groups="pdk-fs" />
       <project path="external/libdaemon" name="platform/external/libdaemon" />
       <project path="external/libevent" name="platform/external/libevent" />
       <project path="external/libexif" name="platform/external/libexif" groups="pdk-cw-fs,pdk-fs" />
       <project path="external/libgsm" name="platform/external/libgsm" groups="pdk" />
    -  <project path="external/libhevc" name="platform/external/libhevc" groups="pdk-fs" />
    +  <project path="external/libhevc" name="external_libhevc" remote="ads" revison="ads-7.1.0" groups="pdk-fs" />
       <project path="external/libjpeg-turbo" name="platform/external/libjpeg-turbo" groups="pdk" />
       <project path="external/liblzf" name="platform/external/liblzf" groups="pdk" />
       <project path="external/libmicrohttpd" name="platform/external/libmicrohttpd" />
    -  <project path="external/libmpeg2" name="platform/external/libmpeg2" groups="pdk" />
    +  <project path="external/libmpeg2" name="external_libmpeg2" remote="ads" revision="ads-7.1.0" groups="pdk" />
       <project path="external/libmtp" name="platform/external/libmtp" groups="pdk-cw-fs,pdk-fs" />
    -  <project path="external/libnfc-nci" name="platform/external/libnfc-nci" groups="pdk" />
    +  <project path="external/libnfc-nci" name="external_libnfc-nci" remote="ads" revision="ads-7.1.0" groups="pdk" />
       <project path="external/libnfc-nxp" name="android_external_libnfc-nxp" remote="ads" revision="ads-7.1" groups="pdk" />
       <project path="external/libnl" name="platform/external/libnl" groups="pdk" />
       <project path="external/libogg" name="platform/external/libogg" groups="pdk" />
    @@ -194,7 +194,7 @@
       <project path="external/libutf" name="platform/external/libutf" groups="pdk-cw-fs,pdk-fs" />
       <project path="external/libvncserver" name="platform/external/libvncserver" groups="pdk-cw-fs,pdk-fs" />
       <project path="external/libvorbis" name="platform/external/libvorbis" groups="pdk-cw-fs,pdk-fs" />
    -  <project path="external/libvpx" name="platform/external/libvpx" groups="pdk" />
    +  <project path="external/libvpx" name="external_libvpx" remote="ads" revision="ads-7.1.0" groups="pdk" />
       <project path="external/libvterm" name="platform/external/libvterm" groups="pdk-cw-fs,pdk-fs" />
       <project path="external/libweave" name="platform/external/libweave" />
       <project path="external/libxml2" name="platform/external/libxml2" groups="pdk-cw-fs,pdk-fs,libxml2" />
    @@ -223,7 +223,7 @@
       <project path="external/naver-fonts" name="platform/external/naver-fonts" groups="pdk-cw-fs,pdk-fs" />
       <project path="external/netcat" name="platform/external/netcat" groups="pdk-cw-fs,pdk-fs" />
       <project path="external/netperf" name="platform/external/netperf" groups="pdk-cw-fs,pdk-fs" />
    -  <project path="external/neven" name="platform/external/neven" groups="pdk-cw-fs,pdk-fs" />
    +  <project path="external/neven" name="external_neven" remote="ads" revision="ads-7.1.0" groups="pdk-cw-fs,pdk-fs" />
       <project path="external/nfacct" name="platform/external/nfacct" groups="pdk-cw-fs,pdk-fs" />
       <project path="external/nist-pkits" name="platform/external/nist-pkits" groups="pdk-cw-fs,pdk-fs" />
       <project path="external/nist-sip" name="platform/external/nist-sip" groups="pdk-cw-fs,pdk-fs" />
    @@ -231,7 +231,7 @@
       <project path="external/oauth" name="platform/external/oauth" groups="pdk-cw-fs,pdk-fs" />
       <project path="external/objenesis" name="platform/external/objenesis" groups="pdk-cw-fs,pdk-fs" />
       <project path="external/okhttp" name="platform/external/okhttp" groups="pdk-cw-fs,pdk-fs" />
    -  <project path="external/opencv" name="platform/external/opencv" groups="pdk-cw-fs,pdk-fs" />
    +  <project path="external/opencv" name="external_opencv" remote="ads" revision="ads-7.1.0" groups="pdk-cw-fs,pdk-fs" />
       <project path="external/owasp/sanitizer" name="platform/external/owasp/sanitizer" groups="pdk-fs" />
       <project path="external/parameter-framework" name="platform/external/parameter-framework" groups="pdk-fs" />
       <project path="external/pcre" name="platform/external/pcre" groups="pdk" />
    @@ -251,19 +251,19 @@
       <project path="external/selinux" name="platform/external/selinux" groups="pdk" />
       <project path="external/shflags" name="platform/external/shflags" groups="pdk" />
       <project path="external/sfntly" name="platform/external/sfntly" groups="pdk,qcom_msm8x26" />
    -  <project path="external/skia" name="platform/external/skia" groups="pdk,qcom_msm8x26" />
    +  <project path="external/skia" name="external_skia" remote="ads" revision="ads-7.1.0" groups="pdk,qcom_msm8x26" />
       <project path="external/sl4a" name="platform/external/sl4a" />
       <project path="external/slf4j" name="platform/external/slf4j" groups="pdk-fs" />
       <project path="external/smali" name="platform/external/smali" groups="pdk-cw-fs,pdk-fs" />
       <project path="external/snakeyaml" name="platform/external/snakeyaml" groups="pdk" />
       <project path="external/sonic" name="platform/external/sonic" groups="pdk" />
    -  <project path="external/sonivox" name="platform/external/sonivox" groups="pdk" />
    +  <project path="external/sonivox" name="external_sonivox" remote="ads" revision="ads-7.1.0" groups="pdk" />
       <project path="external/speex" name="platform/external/speex" groups="pdk" />
    -  <project path="external/sqlite" name="platform/external/sqlite" groups="pdk" />
    +  <project path="external/sqlite" name="external_sqlite" remote="ads" revision="ads-7.1.0" groups="pdk" />
       <project path="external/squashfs-tools" name="platform/external/squashfs-tools" groups="pdk" />
       <project path="external/srtp" name="platform/external/srtp" groups="pdk-cw-fs,pdk-fs" />
       <project path="external/strace" name="platform/external/strace" groups="pdk-cw-fs,pdk-fs" />
    -  <project path="external/svox" name="platform/external/svox" groups="pdk-cw-fs,pdk-fs" />
    +  <project path="external/svox" name="external_svox" remote="ads" revision="ads-7.1.0" groups="pdk-cw-fs,pdk-fs" />
       <project path="external/tagsoup" name="platform/external/tagsoup" groups="pdk-cw-fs,pdk-fs" />
       <project path="external/testng" name="platform/external/testng" groups="pdk" />
       <project path="external/tcpdump" name="platform/external/tcpdump" groups="pdk,pdk-cw-fs,pdk-fs" />
    @@ -275,10 +275,10 @@
       <project path="external/tlsdate" name="platform/external/tlsdate" />
       <project path="external/toybox" name="platform/external/toybox" groups="pdk" />
       <project path="external/tpm2" name="platform/external/tpm2" />
    -  <project path="external/tremolo" name="platform/external/tremolo" groups="pdk" />
    +  <project path="external/tremolo" name="external_tremolo" remote="ads" revision="ads-7.1.0" groups="pdk" />
       <project path="external/unicode" name="platform/external/unicode" groups="pdk" />
       <project path="external/universal-tween-engine" name="platform/external/universal-tween-engine" />
    -  <project path="external/v8" name="platform/external/v8" groups="pdk" />
    +  <project path="external/v8" name="external_v8" remote="ads" revision="ads-7.1.0" groups="pdk" />
       <project path="external/valgrind" name="platform/external/valgrind" groups="pdk" />
       <project path="external/vboot_reference" name="platform/external/vboot_reference" groups="vboot" />
       <project path="external/vixl" name="platform/external/vixl" groups="pdk" />
    @@ -286,23 +286,23 @@
       <project path="external/vulkan-validation-layers" name="platform/external/vulkan-validation-layers" />
       <project path="external/webp" name="platform/external/webp" groups="pdk,qcom_msm8x26" />
       <project path="external/webrtc" name="platform/external/webrtc" groups="pdk" />
    -  <project path="external/wpa_supplicant_8" name="platform/external/wpa_supplicant_8" groups="pdk" />
    +  <project path="external/wpa_supplicant_8" name="external_wpa_supplicant_8" remote="ads" revision="ads-7.1.0" groups="pdk" />
       <project path="external/xmlrpcpp" name="platform/external/xmlrpcpp" groups="pdk" />
       <project path="external/xmlwriter" name="platform/external/xmlwriter" groups="pdk-cw-fs,pdk-fs" />
       <project path="external/xmp_toolkit" name="platform/external/xmp_toolkit" groups="pdk-cw-fs,pdk-fs" />
       <project path="external/zlib" name="platform/external/zlib" groups="pdk" />
       <project path="external/zopfli" name="platform/external/zopfli" groups="pdk-cw-fs,pdk-fs" />
       <project path="external/zxing" name="platform/external/zxing" groups="pdk-cw-fs,pdk-fs" />
    -  <project path="frameworks/av" name="platform/frameworks/av" groups="pdk" />
    -  <project path="frameworks/base" name="platform/frameworks/base" groups="pdk-cw-fs,pdk-fs" />
    +  <project path="frameworks/av" name="android_frameworks_av" remote="ads" revision="ads-7.1.0" groups="pdk" />
    +  <project path="frameworks/base" name="platform_frameworks_base" remote="ads" revision"ads-7.1.0" groups="pdk-cw-fs,pdk-fs" />
       <project path="frameworks/compile/libbcc" name="platform/frameworks/compile/libbcc" groups="pdk" />
       <project path="frameworks/compile/mclinker" name="platform/frameworks/compile/mclinker" groups="pdk" />
       <project path="frameworks/compile/slang" name="platform/frameworks/compile/slang" groups="pdk" />
    -  <project path="frameworks/ex" name="platform/frameworks/ex" groups="pdk-cw-fs,pdk-fs" />
    -  <project path="frameworks/minikin" name="platform/frameworks/minikin" groups="pdk-cw-fs,pdk-fs" />
    +  <project path="frameworks/ex" name="platform_frameworks_ex" remote="ads" revision="ads-7.1.0" groups="pdk-cw-fs,pdk-fs" />
    +  <project path="frameworks/minikin" name="platform_frameworks_minikin" remote="ads" revision="ads-7.1.0" groups="pdk-cw-fs,pdk-fs" />
       <project path="frameworks/ml" name="platform/frameworks/ml" groups="pdk-cw-fs,pdk-fs" />
       <project path="frameworks/multidex" name="platform/frameworks/multidex" groups="pdk-cw-fs,pdk-fs" />
    -  <project path="frameworks/native" name="platform/frameworks/native" groups="pdk" />
    +  <project path="frameworks/native" name="platform_frameworks_native-1" remote="ads" revision="ads-7.1.0" groups="pdk" />
       <project path="frameworks/opt/bitmap" name="platform/frameworks/opt/bitmap" groups="pdk-fs" />
       <project path="frameworks/opt/bluetooth" name="platform/frameworks/opt/bluetooth" groups="pdk-cw-fs,pdk-fs" />
       <project path="frameworks/opt/calendar" name="platform/frameworks/opt/calendar" groups="pdk-cw-fs,pdk-fs" />
    @@ -315,14 +315,14 @@
       <project path="frameworks/opt/net/ethernet" name="platform/frameworks/opt/net/ethernet" groups="pdk-fs" />
       <project path="frameworks/opt/net/ims" name="platform/frameworks/opt/net/ims" groups="frameworks_ims,pdk-cw-fs,pdk-fs" />
       <project path="frameworks/opt/net/voip" name="platform/frameworks/opt/net/voip" groups="pdk-cw-fs,pdk-fs" />
    -  <project path="frameworks/opt/net/wifi" name="platform/frameworks/opt/net/wifi" groups="pdk" />
    +  <project path="frameworks/opt/net/wifi" name="platform_frameworks_opt_net_wifi" remote="ads" revision="ads-7.1.0" groups="pdk" />
       <project path="frameworks/opt/photoviewer" name="platform/frameworks/opt/photoviewer" groups="pdk-cw-fs,pdk-fs" />
       <project path="frameworks/opt/setupwizard" name="platform/frameworks/opt/setupwizard" groups="pdk-cw-fs,pdk-fs" />
       <project path="frameworks/opt/telephony" name="platform/frameworks/opt/telephony" groups="pdk" />
       <project path="frameworks/opt/timezonepicker" name="platform/frameworks/opt/timezonepicker" groups="pdk-cw-fs,pdk-fs" />
       <project path="frameworks/opt/vcard" name="platform/frameworks/opt/vcard" groups="pdk-cw-fs,pdk-fs" />
       <project path="frameworks/rs" name="platform/frameworks/rs" groups="pdk" />
    -  <project path="frameworks/support" name="platform/frameworks/support" groups="pdk-cw-fs,pdk-fs" />
    +  <project path="frameworks/support" name="platform_frameworks_support" remote="ads" revision="ads-7.1.0" groups="pdk-cw-fs,pdk-fs" />
       <project path="frameworks/data-binding" name="platform/frameworks/data-binding" groups="pdk-cw-fs,pdk-fs" />
       <project path="frameworks/volley" name="platform/frameworks/volley" groups="pdk-cw-fs,pdk-fs" />
       <project path="frameworks/webview" name="platform/frameworks/webview" groups="pdk-cw-fs,pdk-fs" />
    @@ -346,10 +346,10 @@
       <project path="hardware/intel/img/psb_video" name="platform/hardware/intel/img/psb_video" groups="intel" />
       <project path="hardware/intel/sensors" name="platform/hardware/intel/sensors" groups="intel_sensors" />
       <project path="hardware/invensense" name="platform/hardware/invensense" groups="invensense" />
    -  <project path="hardware/libhardware" name="platform/hardware/libhardware" groups="pdk" />
    +  <project path="hardware/libhardware" name="hardware_libhardware" remote="ads" revision="ads-7.1.0" groups="pdk" />
       <project path="hardware/libhardware_legacy" name="platform/hardware/libhardware_legacy" groups="pdk" />
       <project path="hardware/marvell/bt" name="platform/hardware/marvell/bt" groups="marvell_bt" />
    -  <project path="hardware/qcom/audio" name="platform/hardware/qcom/audio" groups="qcom,qcom_audio" />
    +  <project path="hardware/qcom/audio" name="hardware_qcom_audio" remote="ads" revision="ads-7.1.0" groups="qcom,qcom_audio" />
       <project path="hardware/qcom/bootctrl" name="platform/hardware/qcom/bootctrl" groups="pdk" />
       <project path="hardware/qcom/bt" name="platform/hardware/qcom/bt" groups="qcom" />
       <project path="hardware/qcom/camera" name="platform/hardware/qcom/camera" groups="qcom" />
    @@ -364,12 +364,12 @@
       <project path="hardware/qcom/msm8x84" name="platform/hardware/qcom/msm8x84" groups="qcom_msm8x84" />
       <project path="hardware/qcom/power" name="platform/hardware/qcom/power" groups="qcom" />
       <project path="hardware/qcom/wlan" name="platform/hardware/qcom/wlan" groups="qcom_wlan" />
    -  <project path="hardware/ril" name="platform/hardware/ril" groups="pdk" />
    +  <project path="hardware/ril" name="hardware_ril" remote="ads" revision="ads-7.1.0" groups="pdk" />
       <project path="hardware/ti/omap3" name="platform/hardware/ti/omap3" groups="omap3" />
       <project path="hardware/ti/omap4-aah" name="platform/hardware/ti/omap4-aah" groups="omap4-aah" />
       <project path="hardware/ti/omap4xxx" name="platform/hardware/ti/omap4xxx" groups="omap4" />
       <project path="kernel/asus/grouper" name="android_kernel_asus_grouper" remote="ads" revision="ads-7.1.0-stable" />
    -  <project path="libcore" name="platform/libcore" groups="pdk" />
    +  <project path="libcore" name="platform_libcore" remote="ads" revision="ads-7.1.0" groups="pdk" />
       <project path="libnativehelper" name="platform/libnativehelper" groups="pdk" />
       <project path="ndk" name="platform/ndk" groups="generic_fs" />
       <project path="packages/apps/BasicSmsReceiver" name="platform/packages/apps/BasicSmsReceiver" groups="pdk-cw-fs,pdk-fs" />
    @@ -380,12 +380,12 @@
       <project path="packages/apps/CarrierConfig" name="platform/packages/apps/CarrierConfig" groups="pdk-fs" />
       <project path="packages/apps/CellBroadcastReceiver" name="platform/packages/apps/CellBroadcastReceiver" groups="pdk-fs" />
       <project path="packages/apps/CertInstaller" name="platform/packages/apps/CertInstaller" groups="pdk-cw-fs,pdk-fs" />
    -  <project path="packages/apps/Contacts" name="platform/packages/apps/Contacts" groups="pdk-fs" />
    +  <project path="packages/apps/Contacts" name="packages_apps_Contacts" remote="ads" revision="ads-7.1.0" groups="pdk-fs" />
       <project path="packages/apps/ContactsCommon" name="platform/packages/apps/ContactsCommon" groups="pdk-fs"/>
       <project path="packages/apps/DeskClock" name="platform/packages/apps/DeskClock" groups="pdk-fs" />
       <project path="packages/apps/DevCamera" name="platform/packages/apps/DevCamera" groups="pdk" />
       <project path="packages/apps/Dialer" name="platform/packages/apps/Dialer" groups="pdk-fs" />
    -  <project path="packages/apps/Email" name="platform/packages/apps/Email" groups="pdk-fs" />
    +  <project path="packages/apps/Email" name="packages_apps_Email" remote="ads" revision="ads-7.1.0" groups="pdk-fs" />
       <project path="packages/apps/EmergencyInfo" name="platform/packages/apps/EmergencyInfo" />
       <project path="packages/apps/ExactCalculator" name="platform/packages/apps/ExactCalculator" groups="pdk-fs" />
       <project path="packages/apps/Gallery" name="platform/packages/apps/Gallery" groups="pdk-fs" />
    @@ -395,11 +395,11 @@
       <project path="packages/apps/Launcher2" name="platform/packages/apps/Launcher2" groups="pdk-fs" />
       <project path="packages/apps/Launcher3" name="platform/packages/apps/Launcher3" groups="pdk-fs" />
       <!-- <project path="packages/apps/LegacyCamera" name="platform/packages/apps/LegacyCamera" groups="pdk-fs" /> -->
    -  <project path="packages/apps/ManagedProvisioning" name="platform/packages/apps/ManagedProvisioning" groups="pdk-fs" />
    -  <project path="packages/apps/Messaging" name="platform/packages/apps/Messaging" groups="pdk-fs" />
    +  <project path="packages/apps/ManagedProvisioning" name="packages_apps_managedprovisioning" remote="ads" revision="ads-7.1.0" groups="pdk-fs" />
    +  <project path="packages/apps/Messaging" name="packages_apps_messaging" remote="ads" revision="ads-7.1.0" groups="pdk-fs" />
       <!--  <project path="packages/apps/Music" name="platform/packages/apps/Music" groups="pdk-fs" /> -->
       <project path="packages/apps/MusicFX" name="platform/packages/apps/MusicFX" groups="pdk-fs" />
    -  <project path="packages/apps/Nfc" name="platform/packages/apps/Nfc" groups="apps_nfc,pdk-fs" />
    +  <project path="packages/apps/Nfc" name="packages_apps_nfc" remote="ads" revision="ads-7.1.0" groups="apps_nfc,pdk-fs" />
       <project path="packages/apps/OneTimeInitializer" name="platform/packages/apps/OneTimeInitializer" groups="pdk-fs" />
       <project path="packages/apps/PackageInstaller" name="platform/packages/apps/PackageInstaller" groups="pdk-fs" />
       <!--  <project path="packages/apps/PerformanceControl" name="android_packages_apps_PerformanceControl" remote="ads" revision="cm-13.0" /> -->
    @@ -409,7 +409,7 @@
       <project path="packages/apps/Provision" name="platform/packages/apps/Provision" groups="pdk-fs" />
       <!-- <project path="packages/apps/QuickSearchBox" name="platform/packages/apps/QuickSearchBox" groups="pdk-fs" /> -->
       <project path="packages/apps/SafetyRegulatoryInfo" name="platform/packages/apps/SafetyRegulatoryInfo" />
    -  <project path="packages/apps/Settings" name="platform/packages/apps/Settings" groups="pdk-fs" />
    +  <project path="packages/apps/Settings" name="packages_apps_settings" remote="ads" revision="ads-7.1.0" groups="pdk-fs" />
       <project path="packages/apps/SoundRecorder" name="platform/packages/apps/SoundRecorder" groups="pdk-fs" />
       <project path="packages/apps/SpareParts" name="platform/packages/apps/SpareParts" groups="pdk-fs" />
       <project path="packages/apps/SpeechRecorder" name="platform/packages/apps/SpeechRecorder" groups="pdk-fs" />
    @@ -430,7 +430,7 @@
       <project path="packages/providers/CalendarProvider" name="platform/packages/providers/CalendarProvider" groups="pdk-cw-fs,pdk-fs" />
       <project path="packages/providers/CallLogProvider" name="platform/packages/providers/CallLogProvider" groups="pdk-fs" />
       <project path="packages/providers/ContactsProvider" name="platform/packages/providers/ContactsProvider" groups="pdk-cw-fs,pdk-fs" />
    -  <project path="packages/providers/DownloadProvider" name="platform/packages/providers/DownloadProvider" groups="pdk-cw-fs,pdk-fs" />
    +  <project path="packages/providers/DownloadProvider" name="providers_downloadprovider" remote="ads" revision="ads-7.1.0" groups="pdk-cw-fs,pdk-fs" />
       <project path="packages/providers/MediaProvider" name="platform/packages/providers/MediaProvider" groups="pdk-cw-fs,pdk-fs" />
       <project path="packages/providers/PartnerBookmarksProvider" name="platform/packages/providers/PartnerBookmarksProvider" groups="pdk-fs" />
       <project path="packages/providers/TelephonyProvider" name="platform/packages/providers/TelephonyProvider" groups="pdk-cw-fs,pdk-fs" />
    @@ -471,26 +471,26 @@
       <project path="prebuilts/sdk" name="platform/prebuilts/sdk" groups="pdk" />
       <project path="prebuilts/tools" name="platform/prebuilts/tools" groups="pdk,tools" />
       <project path="sdk" name="platform/sdk" groups="pdk-cw-fs,pdk-fs" />
    -  <project path="system/bt" name="android_system_bt" groups="pdk" remote="unlegacy" revision="aosp-7.1"/>
    +  <project path="system/bt" name="android_system_bt" groups="pdk" remote="ads" revision="ads-7.1.0-ua"/>
       <project path="system/ca-certificates" name="platform/system/ca-certificates" groups="pdk" />
       <project path="system/connectivity/apmanager" name="platform/system/connectivity/apmanager" />
       <project path="system/connectivity/dhcp_client" name="platform/system/connectivity/dhcp_client" />
       <project path="system/connectivity/shill" name="platform/system/connectivity/shill" />
    -  <project path="system/core" name="platform/system/core" groups="pdk" />
    +  <project path="system/core" name="android_system_core" remote="ads" revision="ads-7.1.0" groups="pdk" />
       <project path="system/extras" name="platform/system/extras" groups="pdk" />
       <project path="system/firewalld" name="platform/system/firewalld" />
       <project path="system/gatekeeper" name="platform/system/gatekeeper" groups="pdk" />
       <project path="system/keymaster" name="platform/system/keymaster" groups="pdk" />
    -  <project path="system/media" name="platform/system/media" groups="pdk" />
    +  <project path="system/media" name="android_system_media" remote="ads" revision="ads-7.1.0" groups="pdk" />
       <project path="system/nativepower" name="platform/system/nativepower" />
       <project path="system/netd" name="platform/system/netd" groups="pdk" />
       <project path="system/nvram" name="platform/system/nvram" />
    -  <project path="system/security" name="platform/system/security" groups="pdk" />
    -  <project path="system/sepolicy" name="platform/system/sepolicy" groups="pdk" />
    +  <project path="system/security" name="android_system_security" remote="ads" revision="ads-7.1.0" groups="pdk" />
    +  <project path="system/sepolicy" name="android_system_sepolicy" remote="ads" revision="ads-7.1.0" groups="pdk" />
       <project path="system/tools/aidl" name="platform/system/tools/aidl" groups="pdk-cw-fs,pdk-fs" />
       <project path="system/tpm" name="platform/system/tpm" />
    -  <project path="system/update_engine" name="platform/system/update_engine" />
    -  <project path="system/vold" name="platform/system/vold" groups="pdk" />
    +  <project path="system/update_engine" name="android_system_updateengine" remote="ads" revision="ads-7.1.0" />
    +  <project path="system/vold" name="android_system_vold" remote="ads" revision="ads-7.1.2" groups="pdk" />
       <project path="system/weaved" name="platform/system/weaved" />
       <project path="system/webservd" name="platform/system/webservd" />
       <project path="toolchain/binutils" name="toolchain/binutils" />
    
    From 2ddeaf989107312e71f01c4d6c86d7106977a9ee Mon Sep 17 00:00:00 2001
    From: AndDiSa <anddisa@googlemail.com>
    Date: Mon, 17 Jun 2019 16:40:09 +0200
    Subject: [PATCH 117/159] update build instructions
    
    Change-Id: I03733d35e70f7f41267ae9860c979ee198ba19d2
    ---
     README.md | 50 --------------------------------------------------
     1 file changed, 50 deletions(-)
    
    diff --git a/README.md b/README.md
    index caf30e2..903933d 100644
    --- a/README.md
    +++ b/README.md
    @@ -6,56 +6,6 @@ repo init -u https://github.com/AndDiSa/platform_manifest-Grouper-AOSP.git -b ad
     
     repo sync
     
    -...
    -
    -cd build
    -
    -patch -p 1 < ../.repo/manifests/build.patch
    -
    -cd ..
    -
    -cd frameworks/av
    -
    -patch -p 1 < ../../.repo/manifests/frameworks_av.patch
    -
    -cd ../..
    -
    -cd frameworks/base
    -
    -patch -p 1 < ../../.repo/manifests/frameworks_base.patch
    -
    -cd ../..
    -
    -cd frameworks/native
    -
    -patch -p 1 < ../../.repo/manifests/frameworks_native.patch
    -
    -cd ../..
    -
    -cd hardware/ril
    -
    -patch -p 1 < ../../.repo/manifests/hardware_ril.patch
    -
    -cd ../..
    -
    -cd packages/apps/Music
    -
    -patch -p 1 < ../../../.repo/manifests/packages_apps_music.patch
    -
    -cd ../../..
    -
    -cd system/core
    -
    -patch -p 1 < ../../.repo/manifests/system_core.patch
    -
    -cd ../..
    -
    -cd system/sepolicy
    -
    -patch -p 1 < ../../.repo/manifests/system_sepolicy.patch
    -
    -cd ../..
    -
     . build/envsetup.sh
     
     lunch 7 # for making grouper
    
    From 15cda4c82710d727e18063c9767683fe81bc379e Mon Sep 17 00:00:00 2001
    From: fidoedidoe <30518992+fidoedidoe@users.noreply.github.com>
    Date: Tue, 18 Jun 2019 10:35:54 +0100
    Subject: [PATCH 118/159] Typo in platform_frameworks_base definition
    
    ---
     default.xml | 2 +-
     1 file changed, 1 insertion(+), 1 deletion(-)
    
    diff --git a/default.xml b/default.xml
    index d9e0890..ea1807f 100644
    --- a/default.xml
    +++ b/default.xml
    @@ -294,7 +294,7 @@
       <project path="external/zopfli" name="platform/external/zopfli" groups="pdk-cw-fs,pdk-fs" />
       <project path="external/zxing" name="platform/external/zxing" groups="pdk-cw-fs,pdk-fs" />
       <project path="frameworks/av" name="android_frameworks_av" remote="ads" revision="ads-7.1.0" groups="pdk" />
    -  <project path="frameworks/base" name="platform_frameworks_base" remote="ads" revision"ads-7.1.0" groups="pdk-cw-fs,pdk-fs" />
    +  <project path="frameworks/base" name="platform_frameworks_base" remote="ads" revision="ads-7.1.0" groups="pdk-cw-fs,pdk-fs" />
       <project path="frameworks/compile/libbcc" name="platform/frameworks/compile/libbcc" groups="pdk" />
       <project path="frameworks/compile/mclinker" name="platform/frameworks/compile/mclinker" groups="pdk" />
       <project path="frameworks/compile/slang" name="platform/frameworks/compile/slang" groups="pdk" />
    
    From b8fdb99afdc1044e49eb01c6b8f87191809d92f2 Mon Sep 17 00:00:00 2001
    From: fidoedidoe <30518992+fidoedidoe@users.noreply.github.com>
    Date: Tue, 18 Jun 2019 11:37:12 +0100
    Subject: [PATCH 119/159] Corrected typo in external_libhevc definition
    
    ---
     default.xml | 2 +-
     1 file changed, 1 insertion(+), 1 deletion(-)
    
    diff --git a/default.xml b/default.xml
    index ea1807f..f647b9b 100644
    --- a/default.xml
    +++ b/default.xml
    @@ -172,7 +172,7 @@
       <project path="external/libevent" name="platform/external/libevent" />
       <project path="external/libexif" name="platform/external/libexif" groups="pdk-cw-fs,pdk-fs" />
       <project path="external/libgsm" name="platform/external/libgsm" groups="pdk" />
    -  <project path="external/libhevc" name="external_libhevc" remote="ads" revison="ads-7.1.0" groups="pdk-fs" />
    +  <project path="external/libhevc" name="external_libhevc" remote="ads" revision="ads-7.1.0" groups="pdk-fs" />
       <project path="external/libjpeg-turbo" name="platform/external/libjpeg-turbo" groups="pdk" />
       <project path="external/liblzf" name="platform/external/liblzf" groups="pdk" />
       <project path="external/libmicrohttpd" name="platform/external/libmicrohttpd" />
    
    From 047cc5197baab72b73fbc4f5e1f2c8dab9bc7760 Mon Sep 17 00:00:00 2001
    From: fidoedidoe <30518992+fidoedidoe@users.noreply.github.com>
    Date: Tue, 18 Jun 2019 14:19:42 +0100
    Subject: [PATCH 120/159] Corrected typo in external/e2fsprogs definition
    
    ---
     default.xml | 2 +-
     1 file changed, 1 insertion(+), 1 deletion(-)
    
    diff --git a/default.xml b/default.xml
    index f647b9b..574aa35 100644
    --- a/default.xml
    +++ b/default.xml
    @@ -96,7 +96,7 @@
       <project path="external/drm_gralloc" name="platform/external/drm_gralloc" groups="drm_gralloc" />
       <project path="external/drm_hwcomposer" name="platform/external/drm_hwcomposer" groups="drm_hwcomposer" />
       <project path="external/droiddriver" name="platform/external/droiddriver" groups="pdk-cw-fs,pdk-fs" />
    -  <project path="external/e2fsprogs" name="external_e2fsgrogs" remote="ads" revision="ads-7.1.2" groups="pdk" />
    +  <project path="external/e2fsprogs" name="external_e2fsprogs" remote="ads" revision="ads-7.1.2" groups="pdk" />
       <project path="external/easymock" name="platform/external/easymock" groups="pdk-cw-fs,pdk-fs" />
       <project path="external/eclipse-basebuilder" name="platform/external/eclipse-basebuilder" groups="pdk-cw-fs,pdk-fs" />
       <project path="external/eclipse-windowbuilder" name="platform/external/eclipse-windowbuilder" groups="pdk-cw-fs,pdk-fs" />
    
    From 63a1b0bfbef31e00d2b50130c0f641054ea13e74 Mon Sep 17 00:00:00 2001
    From: AndDiSa <anddisa@googlemail.com>
    Date: Tue, 18 Jun 2019 19:07:27 +0200
    Subject: [PATCH 121/159] correct wrong naming of repo
    
    Change-Id: I7bec2f675390cac9dd8a981e7c05d34d1cc8d5ba
    ---
     default.xml | 2 +-
     1 file changed, 1 insertion(+), 1 deletion(-)
    
    diff --git a/default.xml b/default.xml
    index f647b9b..8e859dd 100644
    --- a/default.xml
    +++ b/default.xml
    @@ -302,7 +302,7 @@
       <project path="frameworks/minikin" name="platform_frameworks_minikin" remote="ads" revision="ads-7.1.0" groups="pdk-cw-fs,pdk-fs" />
       <project path="frameworks/ml" name="platform/frameworks/ml" groups="pdk-cw-fs,pdk-fs" />
       <project path="frameworks/multidex" name="platform/frameworks/multidex" groups="pdk-cw-fs,pdk-fs" />
    -  <project path="frameworks/native" name="platform_frameworks_native-1" remote="ads" revision="ads-7.1.0" groups="pdk" />
    +  <project path="frameworks/native" name="android_frameworks_native-1" remote="ads" revision="ads-7.1.0" groups="pdk" />
       <project path="frameworks/opt/bitmap" name="platform/frameworks/opt/bitmap" groups="pdk-fs" />
       <project path="frameworks/opt/bluetooth" name="platform/frameworks/opt/bluetooth" groups="pdk-cw-fs,pdk-fs" />
       <project path="frameworks/opt/calendar" name="platform/frameworks/opt/calendar" groups="pdk-cw-fs,pdk-fs" />
    
    From 7b0be6dec195e11f1da55fd51aa54b13037bcce2 Mon Sep 17 00:00:00 2001
    From: AndDiSa <anddisa@googlemail.com>
    Date: Thu, 20 Jun 2019 15:26:53 +0200
    Subject: [PATCH 122/159] use forked frameworks/opt/telephony repo
    
    Change-Id: Ifa30bf142dd935b930b8f6bdd721732c88cd3808
    ---
     default.xml | 4 ++--
     1 file changed, 2 insertions(+), 2 deletions(-)
    
    diff --git a/default.xml b/default.xml
    index 8e859dd..48ced7e 100644
    --- a/default.xml
    +++ b/default.xml
    @@ -96,7 +96,7 @@
       <project path="external/drm_gralloc" name="platform/external/drm_gralloc" groups="drm_gralloc" />
       <project path="external/drm_hwcomposer" name="platform/external/drm_hwcomposer" groups="drm_hwcomposer" />
       <project path="external/droiddriver" name="platform/external/droiddriver" groups="pdk-cw-fs,pdk-fs" />
    -  <project path="external/e2fsprogs" name="external_e2fsgrogs" remote="ads" revision="ads-7.1.2" groups="pdk" />
    +  <project path="external/e2fsprogs" name="external_e2fsprogs" remote="ads" revision="ads-7.1.2" groups="pdk" />
       <project path="external/easymock" name="platform/external/easymock" groups="pdk-cw-fs,pdk-fs" />
       <project path="external/eclipse-basebuilder" name="platform/external/eclipse-basebuilder" groups="pdk-cw-fs,pdk-fs" />
       <project path="external/eclipse-windowbuilder" name="platform/external/eclipse-windowbuilder" groups="pdk-cw-fs,pdk-fs" />
    @@ -318,7 +318,7 @@
       <project path="frameworks/opt/net/wifi" name="platform_frameworks_opt_net_wifi" remote="ads" revision="ads-7.1.0" groups="pdk" />
       <project path="frameworks/opt/photoviewer" name="platform/frameworks/opt/photoviewer" groups="pdk-cw-fs,pdk-fs" />
       <project path="frameworks/opt/setupwizard" name="platform/frameworks/opt/setupwizard" groups="pdk-cw-fs,pdk-fs" />
    -  <project path="frameworks/opt/telephony" name="platform/frameworks/opt/telephony" groups="pdk" />
    +  <project path="frameworks/opt/telephony" name="platform_frameworks_opt_telephony" remote="ads" revision="ads-7.1.0" groups="pdk" />
       <project path="frameworks/opt/timezonepicker" name="platform/frameworks/opt/timezonepicker" groups="pdk-cw-fs,pdk-fs" />
       <project path="frameworks/opt/vcard" name="platform/frameworks/opt/vcard" groups="pdk-cw-fs,pdk-fs" />
       <project path="frameworks/rs" name="platform/frameworks/rs" groups="pdk" />
    
    From 31cd8260fd8f089e28254864a33d1338ec3724a4 Mon Sep 17 00:00:00 2001
    From: AndDiSa <anddisa@googlemail.com>
    Date: Thu, 20 Jun 2019 15:42:48 +0200
    Subject: [PATCH 123/159] switch to own repo for packages/services/Telecomm
    
    Change-Id: Ied22b00da1cd54af46d701f52054e12d62f48824
    ---
     default.xml | 2 +-
     1 file changed, 1 insertion(+), 1 deletion(-)
    
    diff --git a/default.xml b/default.xml
    index 48ced7e..2971cbf 100644
    --- a/default.xml
    +++ b/default.xml
    @@ -441,7 +441,7 @@
       <project path="packages/screensavers/WebView" name="platform/packages/screensavers/WebView" groups="pdk-fs" />
       <project path="packages/services/Car" name="platform/packages/services/Car" groups="adp8064,pdk-cw-fs,pdk-fs" />
       <project path="packages/services/Mms" name="platform/packages/services/Mms" groups="pdk-cw-fs,pdk-fs" />
    -  <project path="packages/services/Telecomm" name="platform/packages/services/Telecomm" groups="pdk-cw-fs,pdk-fs" />
    +  <project path="packages/services/Telecomm" name="packages_services_telecomm" remote="ads" revision="ads-7.1.0" groups="pdk-cw-fs,pdk-fs" />
       <project path="packages/services/Telephony" name="platform/packages/services/Telephony" groups="pdk-cw-fs,pdk-fs" />
       <project path="packages/wallpapers/LivePicker" name="platform/packages/wallpapers/LivePicker" groups="pdk-fs" />
       <project path="pdk" name="platform/pdk" groups="pdk" />
    
    From d5d22cc91361bbb5846430aa01c3ef908b3107ef Mon Sep 17 00:00:00 2001
    From: AndDiSa <anddisa@googlemail.com>
    Date: Thu, 20 Jun 2019 17:21:28 +0200
    Subject: [PATCH 124/159] switch to own repo for unified email
    
    Change-Id: Ief260b67000be8e6ff6d0a58b86164ccbddb2a1a
    ---
     default.xml | 4 ++--
     1 file changed, 2 insertions(+), 2 deletions(-)
    
    diff --git a/default.xml b/default.xml
    index 2971cbf..42f1c2f 100644
    --- a/default.xml
    +++ b/default.xml
    @@ -419,7 +419,7 @@
       <project path="packages/apps/Terminal" name="platform/packages/apps/Terminal" groups="pdk-fs" />
       <project path="packages/apps/Test/connectivity" name="platform/packages/apps/Test/connectivity" />
       <project path="packages/apps/TvSettings" name="platform/packages/apps/TvSettings" groups="generic_fs" />
    -  <project path="packages/apps/UnifiedEmail" name="platform/packages/apps/UnifiedEmail" groups="pdk-fs" />
    +  <project path="packages/apps/UnifiedEmail" name="packages_apps_unifiedemail" remote="ads" revision="ads-7.1.2" groups="pdk-fs" />
       <project path="packages/apps/WallpaperPicker" name="platform/packages/apps/WallpaperPicker" groups="pdk-fs" />
       <project path="packages/experimental" name="platform/packages/experimental" />
       <project path="packages/inputmethods/LatinIME" name="platform/packages/inputmethods/LatinIME" groups="pdk-fs" />
    @@ -441,7 +441,7 @@
       <project path="packages/screensavers/WebView" name="platform/packages/screensavers/WebView" groups="pdk-fs" />
       <project path="packages/services/Car" name="platform/packages/services/Car" groups="adp8064,pdk-cw-fs,pdk-fs" />
       <project path="packages/services/Mms" name="platform/packages/services/Mms" groups="pdk-cw-fs,pdk-fs" />
    -  <project path="packages/services/Telecomm" name="packages_services_telecomm" remote="ads" revision="ads-7.1.0" groups="pdk-cw-fs,pdk-fs" />
    +  <project path="packages/services/Telecomm" name="platform/packages/services/Telecomm" groups="pdk-cw-fs,pdk-fs" />
       <project path="packages/services/Telephony" name="platform/packages/services/Telephony" groups="pdk-cw-fs,pdk-fs" />
       <project path="packages/wallpapers/LivePicker" name="platform/packages/wallpapers/LivePicker" groups="pdk-fs" />
       <project path="pdk" name="platform/pdk" groups="pdk" />
    
    From ba43082fc3a96028a001366a3e30d729306b7d1b Mon Sep 17 00:00:00 2001
    From: AndDiSa <anddisa@googlemail.com>
    Date: Mon, 24 Jun 2019 14:22:01 +0200
    Subject: [PATCH 125/159] revert unintended change
    
    Change-Id: I0c053a105430089d9a817b4705a35ccd3b9f039e
    ---
     default.xml | 2 +-
     1 file changed, 1 insertion(+), 1 deletion(-)
    
    diff --git a/default.xml b/default.xml
    index 42f1c2f..a3e8d5f 100644
    --- a/default.xml
    +++ b/default.xml
    @@ -441,7 +441,7 @@
       <project path="packages/screensavers/WebView" name="platform/packages/screensavers/WebView" groups="pdk-fs" />
       <project path="packages/services/Car" name="platform/packages/services/Car" groups="adp8064,pdk-cw-fs,pdk-fs" />
       <project path="packages/services/Mms" name="platform/packages/services/Mms" groups="pdk-cw-fs,pdk-fs" />
    -  <project path="packages/services/Telecomm" name="platform/packages/services/Telecomm" groups="pdk-cw-fs,pdk-fs" />
    +  <project path="packages/services/Telecomm" name="packages_services_telecomm" remote="ads" revision="ads-7.1.0" groups="pdk-cw-fs,pdk-fs" />
       <project path="packages/services/Telephony" name="platform/packages/services/Telephony" groups="pdk-cw-fs,pdk-fs" />
       <project path="packages/wallpapers/LivePicker" name="platform/packages/wallpapers/LivePicker" groups="pdk-fs" />
       <project path="pdk" name="platform/pdk" groups="pdk" />
    
    From 61bf5c35fa6974e52da9dc2fa948b10ea95472b0 Mon Sep 17 00:00:00 2001
    From: AndDiSa <anddisa@googlemail.com>
    Date: Sat, 6 Jul 2019 13:41:41 +0200
    Subject: [PATCH 126/159] fork sfntly and use own branch
    
    Change-Id: Ifa34fcb5df15caec9e16802fac751fd294f47ac1
    ---
     default.xml | 2 +-
     1 file changed, 1 insertion(+), 1 deletion(-)
    
    diff --git a/default.xml b/default.xml
    index a3e8d5f..77ca8e8 100644
    --- a/default.xml
    +++ b/default.xml
    @@ -250,7 +250,7 @@
       <project path="external/scrypt" name="platform/external/scrypt" groups="pdk" />
       <project path="external/selinux" name="platform/external/selinux" groups="pdk" />
       <project path="external/shflags" name="platform/external/shflags" groups="pdk" />
    -  <project path="external/sfntly" name="platform/external/sfntly" groups="pdk,qcom_msm8x26" />
    +  <project path="external/sfntly" name="platform_external_sfntly" remote="ads" revision="ads-7.1.0" groups="pdk,qcom_msm8x26" />
       <project path="external/skia" name="external_skia" remote="ads" revision="ads-7.1.0" groups="pdk,qcom_msm8x26" />
       <project path="external/sl4a" name="platform/external/sl4a" />
       <project path="external/slf4j" name="platform/external/slf4j" groups="pdk-fs" />
    
    From aaa0918ae94c344b1169d1c782105bc60739555a Mon Sep 17 00:00:00 2001
    From: AndDiSa <anddisa@googlemail.com>
    Date: Sat, 6 Jul 2019 13:50:26 +0200
    Subject: [PATCH 127/159] fork telephony providers and use own branch
    
    Change-Id: I05ed490544f766236aad48cabcb91bc2c1b4d805
    ---
     default.xml | 2 +-
     1 file changed, 1 insertion(+), 1 deletion(-)
    
    diff --git a/default.xml b/default.xml
    index 77ca8e8..0b67828 100644
    --- a/default.xml
    +++ b/default.xml
    @@ -433,7 +433,7 @@
       <project path="packages/providers/DownloadProvider" name="providers_downloadprovider" remote="ads" revision="ads-7.1.0" groups="pdk-cw-fs,pdk-fs" />
       <project path="packages/providers/MediaProvider" name="platform/packages/providers/MediaProvider" groups="pdk-cw-fs,pdk-fs" />
       <project path="packages/providers/PartnerBookmarksProvider" name="platform/packages/providers/PartnerBookmarksProvider" groups="pdk-fs" />
    -  <project path="packages/providers/TelephonyProvider" name="platform/packages/providers/TelephonyProvider" groups="pdk-cw-fs,pdk-fs" />
    +  <project path="packages/providers/TelephonyProvider" name="packages_providers_telephonyprovider" remote="ads" revision="ads-7.1.0" groups="pdk-cw-fs,pdk-fs" />
       <project path="packages/providers/TvProvider" name="platform/packages/providers/TvProvider" groups="pdk-fs" />
       <project path="packages/providers/UserDictionaryProvider" name="platform/packages/providers/UserDictionaryProvider" groups="pdk-cw-fs,pdk-fs" />
       <project path="packages/screensavers/Basic" name="platform/packages/screensavers/Basic" groups="pdk-fs" />
    
    From 611ac87f273fd642b638212f507173ac0b42d070 Mon Sep 17 00:00:00 2001
    From: AndDiSa <anddisa@googlemail.com>
    Date: Thu, 22 Aug 2019 22:18:20 +0200
    Subject: [PATCH 128/159] update patches
    
    Change-Id: If7841dc8187b960608cab4a5651b6cf556593dc5
    ---
     build.patch                     |    4 +-
     external_chromium_libpac.patch  |   99 +-
     external_libavc.patch           |   99 +-
     external_libhevc.patch          |  221 +-
     external_libnfc-nci.patch       |   32 +
     external_libvpx.patch           |   25 +-
     external_wpa_supplicant_8.patch | 3791 -------------------------------
     frameworks_av.patch             |  843 ++++++-
     frameworks_base.patch           |  146 +-
     frameworks_native.patch         |   49 +-
     packages_apps_nfc.patch         |   50 +
     packages_apps_settings.patch    |   88 +
     system_bt.patch                 |  555 ++++-
     13 files changed, 2052 insertions(+), 3950 deletions(-)
    
    diff --git a/build.patch b/build.patch
    index 5247dbb..d80a6a9 100644
    --- a/build.patch
    +++ b/build.patch
    @@ -323,7 +323,7 @@ index 000000000..80664faf2
     +ALL_PREBUILT += $(INSTALLED_KERNEL_TARGET)
     +endif
     diff --git a/core/version_defaults.mk b/core/version_defaults.mk
    -index 7c9634490..c0ceb52a2 100644
    +index 7c9634490..824768113 100644
     --- a/core/version_defaults.mk
     +++ b/core/version_defaults.mk
     @@ -131,7 +131,7 @@ ifeq "" "$(PLATFORM_SECURITY_PATCH)"
    @@ -331,7 +331,7 @@ index 7c9634490..c0ceb52a2 100644
          #  It must match one of the Android Security Patch Level strings of the Public Security Bulletins.
          #  If there is no $PLATFORM_SECURITY_PATCH set, keep it empty.
     -    PLATFORM_SECURITY_PATCH := 2017-08-05
    -+    PLATFORM_SECURITY_PATCH := 2019-05-05
    ++    PLATFORM_SECURITY_PATCH := 2019-08-05
      endif
      
      ifeq "" "$(PLATFORM_BASE_OS)"
    diff --git a/external_chromium_libpac.patch b/external_chromium_libpac.patch
    index 27db9a9..762e79b 100644
    --- a/external_chromium_libpac.patch
    +++ b/external_chromium_libpac.patch
    @@ -29,6 +29,21 @@ index 992cdd1..8eef03a 100644
        if (split == std::string::npos)
          return false;
        parts.push_back(cidr_literal.substr(0, split));
    +diff --git a/src/proxy_resolver_v8.cc b/src/proxy_resolver_v8.cc
    +index f978694..0504b03 100644
    +--- a/src/proxy_resolver_v8.cc
    ++++ b/src/proxy_resolver_v8.cc
    +@@ -762,6 +762,10 @@ int ProxyResolverV8::SetPacScript(const android::String16& script_data) {
    +   if (script_data.size() == 0)
    +     return ERR_PAC_SCRIPT_FAILED;
    + 
    ++  // Disable JIT
    ++  static const char kNoOpt[] = "--no-opt";
    ++  v8::V8::SetFlagsFromString(kNoOpt, strlen(kNoOpt));
    ++
    +   // Try parsing the PAC script.
    +   ArrayBufferAllocator allocator;
    +   v8::Isolate::CreateParams create_params;
     diff --git a/test/Android.mk b/test/Android.mk
     index 9c9722e..edf9107 100644
     --- a/test/Android.mk
    @@ -41,6 +56,34 @@ index 9c9722e..edf9107 100644
     +LOCAL_SHARED_LIBRARIES := libpac libutils liblog libandroid_runtime
      
      include $(BUILD_NATIVE_TEST)
    +diff --git a/test/js-unittest/b_132073833.js b/test/js-unittest/b_132073833.js
    +new file mode 100644
    +index 0000000..79d1967
    +--- /dev/null
    ++++ b/test/js-unittest/b_132073833.js
    +@@ -0,0 +1,21 @@
    ++function FindProxyForURL(url, host){
    ++    function opt() {
    ++        opt['x'] = 1.1;
    ++        try {
    ++            Object.create(object);
    ++        } catch (e) {
    ++        }
    ++
    ++        for (let i = 0; i < 100000; i++) {
    ++
    ++        }
    ++    }
    ++
    ++    opt();
    ++    object = opt;
    ++    opt();
    ++
    ++    return "DIRECT";
    ++}
    ++
    ++var object;
    +\ No newline at end of file
     diff --git a/test/js-unittest/change_element_kind.js b/test/js-unittest/change_element_kind.js
     new file mode 100644
     index 0000000..335d59e
    @@ -63,10 +106,10 @@ index 0000000..335d59e
     +  return "DIRECT";
     +}
     diff --git a/test/proxy_resolver_v8_unittest.cc b/test/proxy_resolver_v8_unittest.cc
    -index ad9c826..be7ecee 100644
    +index ad9c826..73e4405 100644
     --- a/test/proxy_resolver_v8_unittest.cc
     +++ b/test/proxy_resolver_v8_unittest.cc
    -@@ -544,5 +544,19 @@ TEST(ProxyResolverV8Test, DNSResolutionOfInternationDomainName) {
    +@@ -544,5 +544,33 @@ TEST(ProxyResolverV8Test, DNSResolutionOfInternationDomainName) {
        EXPECT_EQ("xn--bcher-kva.ch", bindings->dns_resolves_ex[0]);
      }
      
    @@ -83,20 +126,64 @@ index ad9c826..be7ecee 100644
     +  EXPECT_EQ(1U, proxies.size());
     +  EXPECT_EQ("DIRECT", proxies[0]);
     +}
    ++
    ++TEST(ProxyResolverV8Test, B_132073833) {
    ++  ProxyResolverV8WithMockBindings resolver(new MockJSBindings());
    ++  int result = resolver.SetPacScript(String16(B_132073833_JS));
    ++  EXPECT_EQ(OK, result);
    ++
    ++  // Execute FindProxyForURL().
    ++  result = resolver.GetProxyForURL(kQueryUrl, kQueryHost, &kResults);
    ++
    ++  EXPECT_EQ(OK, result);
    ++  std::vector<std::string> proxies = string16ToProxyList(kResults);
    ++  EXPECT_EQ(1U, proxies.size());
    ++  EXPECT_EQ("DIRECT", proxies[0]);
    ++}
     +
      }  // namespace
      }  // namespace net
     diff --git a/test/proxy_test_script.h b/test/proxy_test_script.h
    -index 1042366..80c96c7 100644
    +index 1042366..aa10016 100644
     --- a/test/proxy_test_script.h
     +++ b/test/proxy_test_script.h
    -@@ -78,6 +78,23 @@
    +@@ -4,6 +4,29 @@
    + #ifndef PROXY_TEST_SCRIPT_H_
    + #define PROXY_TEST_SCRIPT_H_
    + 
    ++#define B_132073833_JS \
    ++  "function FindProxyForURL(url, host){\n" \
    ++  "    function opt() {\n" \
    ++  "        opt['x'] = 1.1;\n" \
    ++  "        try {\n" \
    ++  "            Object.create(object);\n" \
    ++  "        } catch (e) {\n" \
    ++  "        }\n" \
    ++  "\n" \
    ++  "        for (let i = 0; i < 100000; i++) {\n" \
    ++  "\n" \
    ++  "        }\n" \
    ++  "    }\n" \
    ++  "\n" \
    ++  "    opt();\n" \
    ++  "    object = opt;\n" \
    ++  "    opt();\n" \
    ++  "\n" \
    ++  "    return \"DIRECT\";\n" \
    ++  "}\n" \
    ++  "\n" \
    ++  "var object;\n" \
    ++
    + #define BINDING_FROM_GLOBAL_JS \
    +   "// Calls a bindings outside of FindProxyForURL(). This causes the code to\n" \
    +   "// get exercised during initialization.\n" \
    +@@ -78,6 +101,23 @@
        "function fn() {}\n" \
        "\n" \
      
     +#define CHANGE_ELEMENT_KIND_JS \
     +  "// PAC script with getter that changes element kind.\n" \
    -+  "	\n" \
    ++  "\n" \
     +  "function FindProxyForURL(url, host) {\n" \
     +  "  let arr = [];\n" \
     +  "  arr[1000] = 0x1234;\n" \
    @@ -107,7 +194,7 @@ index 1042366..80c96c7 100644
     +  "  });\n" \
     +  "\n" \
     +  "  let results = Object.entries(arr);\n" \
    -+  "  let str = results.toString(); \n" \
    ++  "  let str = results.toString();\n" \
     +  "  return \"DIRECT\";\n" \
     +  "}\n" \
     +
    diff --git a/external_libavc.patch b/external_libavc.patch
    index 57dcecf..dfb3d7e 100644
    --- a/external_libavc.patch
    +++ b/external_libavc.patch
    @@ -485,7 +485,7 @@ index bcfbe05..9b9256b 100644
                  size = num_entries * sizeof(void *);
                  size += PAD_MAP_IDX_POC * sizeof(void *);
     diff --git a/decoder/ih264d_parse_slice.c b/decoder/ih264d_parse_slice.c
    -index fad2dff..2d8a9af 100644
    +index fad2dff..063594b 100644
     --- a/decoder/ih264d_parse_slice.c
     +++ b/decoder/ih264d_parse_slice.c
     @@ -72,6 +72,7 @@
    @@ -532,7 +532,77 @@ index fad2dff..2d8a9af 100644
              }
      
              if(!ps_dec->ps_cur_pic)
    -@@ -1365,9 +1382,8 @@ WORD32 ih264d_parse_decode_slice(UWORD8 u1_is_idr_slice,
    +@@ -962,6 +979,69 @@ WORD32 ih264d_end_of_pic(dec_struct_t *ps_dec)
    +     return OK;
    + }
    + 
    ++
    ++/*!
    ++ **************************************************************************
    ++ * \if Function name : ih264d_fix_error_in_dpb \endif
    ++ *
    ++ * \brief
    ++ *    fix error in DPB
    ++ *
    ++ * \return
    ++ *    Number of node(s) deleted
    ++ **************************************************************************
    ++ */
    ++
    ++WORD32 ih264d_fix_error_in_dpb(dec_struct_t *ps_dec)
    ++{
    ++    /*--------------------------------------------------------------------*/
    ++    /* If there is common node in lt_list and st_list then delete it from */
    ++    /* st_list                                                            */
    ++    /*--------------------------------------------------------------------*/
    ++    UWORD8 no_of_nodes_deleted = 0;
    ++    UWORD8 lt_ref_num = ps_dec->ps_dpb_mgr->u1_num_lt_ref_bufs;
    ++    struct dpb_info_t *ps_lt_curr_dpb = ps_dec->ps_dpb_mgr->ps_dpb_ht_head;
    ++    while(lt_ref_num && ps_lt_curr_dpb)
    ++    {
    ++        if(ps_dec->ps_dpb_mgr->ps_dpb_st_head
    ++                && ((ps_lt_curr_dpb->s_bot_field.u1_reference_info
    ++                        | ps_lt_curr_dpb->s_top_field.u1_reference_info)
    ++                        == (IS_SHORT_TERM | IS_LONG_TERM)))
    ++        {
    ++            struct dpb_info_t *ps_st_next_dpb = ps_dec->ps_dpb_mgr->ps_dpb_st_head;
    ++            struct dpb_info_t *ps_st_curr_dpb = ps_dec->ps_dpb_mgr->ps_dpb_st_head;
    ++            UWORD8 st_ref_num = ps_dec->ps_dpb_mgr->u1_num_st_ref_bufs;
    ++            while(st_ref_num && ps_st_curr_dpb)
    ++            {
    ++                if(ps_st_curr_dpb == ps_lt_curr_dpb)
    ++                {
    ++                    if(st_ref_num == ps_dec->ps_dpb_mgr->u1_num_st_ref_bufs)
    ++                    {
    ++                        ps_dec->ps_dpb_mgr->ps_dpb_st_head =
    ++                                ps_dec->ps_dpb_mgr->ps_dpb_st_head->ps_prev_short;
    ++                        ps_st_curr_dpb = ps_dec->ps_dpb_mgr->ps_dpb_st_head;
    ++                    }
    ++                    else
    ++                    {
    ++                        ps_st_next_dpb->ps_prev_short = ps_st_curr_dpb->ps_prev_short;
    ++                    }
    ++                    ps_dec->ps_dpb_mgr->u1_num_st_ref_bufs--;
    ++                    ps_dec->ps_dpb_mgr->u1_num_lt_ref_bufs++;
    ++                    no_of_nodes_deleted++;
    ++                    break;
    ++                }
    ++                ps_st_next_dpb = ps_st_curr_dpb;
    ++                ps_st_curr_dpb = ps_st_curr_dpb->ps_prev_short;
    ++                st_ref_num--;
    ++            }
    ++        }
    ++        ps_lt_curr_dpb = ps_lt_curr_dpb->ps_prev_long;
    ++        lt_ref_num--;
    ++    }
    ++    return no_of_nodes_deleted;
    ++}
    ++
    ++
    + /*!
    +  **************************************************************************
    +  * \if Function name : DecodeSlice \endif
    +@@ -1365,9 +1445,8 @@ WORD32 ih264d_parse_decode_slice(UWORD8 u1_is_idr_slice,
              if(ps_dec->u1_dangling_field == 1)
              {
                  ps_dec->u1_second_field = 1 - ps_dec->u1_second_field;
    @@ -543,7 +613,7 @@ index fad2dff..2d8a9af 100644
                  return ERROR_DANGLING_FIELD_IN_PIC;
              }
      
    -@@ -1785,10 +1801,8 @@ WORD32 ih264d_parse_decode_slice(UWORD8 u1_is_idr_slice,
    +@@ -1785,10 +1864,8 @@ WORD32 ih264d_parse_decode_slice(UWORD8 u1_is_idr_slice,
                  num_entries = 1;
              }
              num_entries = ((2 * num_entries) + 1);
    @@ -556,6 +626,29 @@ index fad2dff..2d8a9af 100644
      
              size = num_entries * sizeof(void *);
              size += PAD_MAP_IDX_POC * sizeof(void *);
    +@@ -1807,6 +1884,10 @@ WORD32 ih264d_parse_decode_slice(UWORD8 u1_is_idr_slice,
    +         ps_dec->pv_proc_tu_coeff_data = ps_dec->pv_parse_tu_coeff_data;
    +     }
    + 
    ++    ret = ih264d_fix_error_in_dpb(ps_dec);
    ++    if(ret < 0)
    ++        return ERROR_DBP_MANAGER_T;
    ++
    +     if(u1_slice_type == I_SLICE)
    +     {
    +         ps_dec->ps_cur_pic->u4_pack_slc_typ |= I_SLC_BIT;
    +diff --git a/decoder/ih264d_parse_slice.h b/decoder/ih264d_parse_slice.h
    +index c012062..0f82ec9 100644
    +--- a/decoder/ih264d_parse_slice.h
    ++++ b/decoder/ih264d_parse_slice.h
    +@@ -37,6 +37,7 @@
    + #include "ih264_platform_macros.h"
    + #include "ih264d_structs.h"
    + #include "ih264d_error_handler.h"
    ++WORD32 ih264d_fix_error_in_dpb(dec_struct_t * ps_dec);
    + WORD32 ih264d_parse_decode_slice(UWORD8 u1_is_idr_slice,
    +                                  UWORD8 u1_nal_ref_idc,
    +                                  dec_struct_t * ps_dec );
     diff --git a/decoder/ih264d_process_bslice.c b/decoder/ih264d_process_bslice.c
     index 7784110..42fad03 100644
     --- a/decoder/ih264d_process_bslice.c
    diff --git a/external_libhevc.patch b/external_libhevc.patch
    index b29738f..efc7816 100644
    --- a/external_libhevc.patch
    +++ b/external_libhevc.patch
    @@ -3955,7 +3955,7 @@ index e9b69c1..1f99ff8 100644
      
      
     diff --git a/common/ihevc_defs.h b/common/ihevc_defs.h
    -index a2b7eda..c4e34ba 100644
    +index a2b7eda..9294e51 100644
     --- a/common/ihevc_defs.h
     +++ b/common/ihevc_defs.h
     @@ -274,7 +274,7 @@ typedef enum {
    @@ -3967,6 +3967,37 @@ index a2b7eda..c4e34ba 100644
      
      #define MAX_STREF_PICS_SPS 64
      
    +@@ -294,10 +294,14 @@ typedef enum {
    + /* CTB Size Range */
    + #define MAX_CTB_SIZE        64
    + #define MIN_CTB_SIZE        16
    ++#define LOG2_MAX_CTB_SIZE   6
    ++#define LOG2_MIN_CTB_SIZE   4
    + 
    + /* TU Size Range */
    + #define MAX_TU_SIZE         32
    + #define MIN_TU_SIZE         4
    ++#define LOG2_MAX_TU_SIZE    5
    ++#define LOG2_MIN_TU_SIZE    2
    + 
    + /* Max Transform Size */
    + #define MAX_TRANS_SIZE      (MAX_TU_SIZE*MAX_TU_SIZE)
    +@@ -305,11 +309,14 @@ typedef enum {
    + /* PU Size Range */
    + #define MAX_PU_SIZE         64
    + #define MIN_PU_SIZE         4
    ++#define LOG2_MAX_PU_SIZE    6
    ++#define LOG2_MIN_PU_SIZE    2
    + 
    + /* CU Size Range */
    + #define MAX_CU_SIZE         64
    + #define MIN_CU_SIZE         8
    +-
    ++#define LOG2_MAX_CU_SIZE    6
    ++#define LOG2_MIN_CU_SIZE    3
    + 
    + /* Number of max TU in a CTB row */
    + #define MAX_TU_IN_CTB_ROW   ((MAX_CTB_SIZE / MIN_TU_SIZE))
     diff --git a/common/ihevc_structs.h b/common/ihevc_structs.h
     index 93d2ad4..baa6375 100644
     --- a/common/ihevc_structs.h
    @@ -4011,6 +4042,122 @@ index 93d2ad4..baa6375 100644
      
      }hrd_params_t;
      
    +diff --git a/decoder/arm/ihevcd_fmt_conv_420sp_to_rgba8888.s b/decoder/arm/ihevcd_fmt_conv_420sp_to_rgba8888.s
    +index a9a75cb..caf7123 100644
    +--- a/decoder/arm/ihevcd_fmt_conv_420sp_to_rgba8888.s
    ++++ b/decoder/arm/ihevcd_fmt_conv_420sp_to_rgba8888.s
    +@@ -68,13 +68,13 @@
    + @*                                                                            *
    + @*  Register Usage   : R0 - R14                                               *
    + @*                                                                            *
    +-@*  Stack Usage      : 40 Bytes                                               *
    ++@*  Stack Usage      : 104 Bytes                                              *
    + @*                                                                            *
    + @*  Interruptibility : Interruptible                                          *
    + @*                                                                            *
    + @*  Known Limitations                                                         *
    + @*       Assumptions: Image Width:     Assumed to be multiple of 16 and       *
    +-@*                     greater than or equal to 16                *
    ++@*                     greater than or equal to 16                            *
    + @*                     Image Height:    Assumed to be even.                   *
    + @*                                                                            *
    + @*  Revision History :                                                        *
    +@@ -82,6 +82,7 @@
    + @*         07 06 2010   Varshita        Draft                                 *
    + @*         07 06 2010   Naveen Kr T     Completed                             *
    + @*         05 08 2013   Naveen K P      Modified for HEVC                     *
    ++@*         30 10 2018   Saurabh Sood    Store D registers to stack            *
    + @*****************************************************************************/
    +     .global ihevcd_fmt_conv_420sp_to_rgba8888_a9q
    + .type ihevcd_fmt_conv_420sp_to_rgba8888_a9q, function
    +@@ -89,7 +90,7 @@ ihevcd_fmt_conv_420sp_to_rgba8888_a9q:
    + 
    +     @// push the registers on the stack
    +     STMFD       SP!,{R4-R12,LR}
    +-
    ++    VPUSH       {d8-d15}
    + 
    +     @//R0 - Y PTR
    +     @//R1 - UV PTR
    +@@ -131,12 +132,12 @@ ihevcd_fmt_conv_420sp_to_rgba8888_a9q:
    + 
    +     @//D0 HAS C1-C2-C3-C4
    +     @// load other parameters from stack
    +-    LDR         R5,[sp,#40]
    ++    LDR         R5,[sp,#104]
    +     @LDR  R4,[sp,#44]
    +-    LDR         R6,[sp,#44]
    +-    LDR         R7,[sp,#48]
    ++    LDR         R6,[sp,#108]
    ++    LDR         R7,[sp,#112]
    +     @LDR  R8,[sp,#52]
    +-    LDR         R9,[sp,#52]
    ++    LDR         R9,[sp,#116]
    + 
    +     @// calculate offsets, offset = stride - width
    +     SUB         R10,R6,R3                   @// luma offset
    +@@ -445,10 +446,8 @@ LABEL_YUV420SP_TO_RGB8888_WIDTH_LOOP_SKIP:
    +     BNE         LABEL_YUV420SP_TO_RGB8888_HEIGHT_LOOP
    + 
    +     @//POP THE REGISTERS
    ++    VPOP        {d8-d15}
    +     LDMFD       SP!,{R4-R12,PC}
    + 
    + 
    +-
    +-
    +     .section .note.GNU-stack,"",%progbits
    +-
    +diff --git a/decoder/arm/ihevcd_itrans_recon_dc_chroma.s b/decoder/arm/ihevcd_itrans_recon_dc_chroma.s
    +index 6732ce0..9184b80 100644
    +--- a/decoder/arm/ihevcd_itrans_recon_dc_chroma.s
    ++++ b/decoder/arm/ihevcd_itrans_recon_dc_chroma.s
    +@@ -58,9 +58,9 @@ ihevcd_itrans_recon_dc_chroma_a9q:
    + 
    + 
    +     push        {r0-r11,lr}
    +-    ldr         r4,[sp,#0x34]               @loads log2_trans_size
    +-    ldr         r5,[sp,#0x38]               @ loads i2_coeff_value
    +-
    ++    vpush       {d8-d15}
    ++    ldr         r4,[sp,#0x74]               @loads log2_trans_size
    ++    ldr         r5,[sp,#0x78]               @ loads i2_coeff_value
    +     mov         r10,#1
    +     lsl         r4,r10,r4                   @    trans_size = (1 << log2_trans_size)@
    +     mov         r6,#64 @ 1 << (shift1 - 1)@
    +@@ -188,6 +188,7 @@ col_loop_4chroma:
    +     vst1.u32    {d8},[r1]
    + 
    + end_loops_chroma:
    ++    vpop        {d8-d15}
    +     pop         {r0-r11,pc}
    + 
    + 
    +diff --git a/decoder/arm/ihevcd_itrans_recon_dc_luma.s b/decoder/arm/ihevcd_itrans_recon_dc_luma.s
    +index 8aee84c..da1f1ad 100644
    +--- a/decoder/arm/ihevcd_itrans_recon_dc_luma.s
    ++++ b/decoder/arm/ihevcd_itrans_recon_dc_luma.s
    +@@ -59,9 +59,9 @@ ihevcd_itrans_recon_dc_luma_a9q:
    + 
    + 
    +     push        {r0-r11,lr}
    +-    ldr         r4,[sp,#0x34]               @loads log2_trans_size
    +-    ldr         r5,[sp,#0x38]               @ loads i2_coeff_value
    +-
    ++    vpush       {d8-d15}
    ++    ldr         r4,[sp,#0x74]               @loads log2_trans_size
    ++    ldr         r5,[sp,#0x78]               @ loads i2_coeff_value
    +     mov         r10,#1
    +     lsl         r4,r10,r4                   @    trans_size = (1 << log2_trans_size)@
    +     mov         r6,#64 @ 1 << (shift1 - 1)@
    +@@ -182,6 +182,7 @@ col_loop_4:
    +     vst1.u32    {d5[0]},[r1]
    + 
    + end_loops:
    ++    vpop        {d8-d15}
    +     pop         {r0-r11,pc}
    + 
    + 
     diff --git a/decoder/ihevcd_api.c b/decoder/ihevcd_api.c
     index c661083..2ae90b0 100644
     --- a/decoder/ihevcd_api.c
    @@ -4182,7 +4329,7 @@ index d656519..d2ea7a5 100644
      
          if(1 == ps_codec->i4_pic_present)
     diff --git a/decoder/ihevcd_parse_headers.c b/decoder/ihevcd_parse_headers.c
    -index c0f1564..78b578a 100644
    +index c0f1564..5397617 100644
     --- a/decoder/ihevcd_parse_headers.c
     +++ b/decoder/ihevcd_parse_headers.c
     @@ -1272,12 +1272,6 @@ IHEVCD_ERROR_T ihevcd_parse_sps(codec_t *ps_codec)
    @@ -4230,7 +4377,45 @@ index c0f1564..78b578a 100644
              ps_sps->i2_pic_crop_bottom_offset = value;
          }
          else
    -@@ -1402,7 +1412,9 @@ IHEVCD_ERROR_T ihevcd_parse_sps(codec_t *ps_codec)
    +@@ -1372,17 +1382,37 @@ IHEVCD_ERROR_T ihevcd_parse_sps(codec_t *ps_codec)
    +     }
    + 
    +     UEV_PARSE("log2_min_coding_block_size_minus3", value, ps_bitstrm);
    ++    if(value > (LOG2_MAX_CU_SIZE - 3))
    ++    {
    ++        return IHEVCD_INVALID_PARAMETER;
    ++    }
    +     ps_sps->i1_log2_min_coding_block_size = value + 3;
    + 
    +     UEV_PARSE("log2_diff_max_min_coding_block_size", value, ps_bitstrm);
    ++    if(value > (LOG2_MAX_CU_SIZE - LOG2_MIN_CU_SIZE))
    ++    {
    ++        return IHEVCD_INVALID_PARAMETER;
    ++    }
    +     ps_sps->i1_log2_diff_max_min_coding_block_size = value;
    + 
    +     ctb_log2_size_y = ps_sps->i1_log2_min_coding_block_size + ps_sps->i1_log2_diff_max_min_coding_block_size;
    + 
    +     UEV_PARSE("log2_min_transform_block_size_minus2", value, ps_bitstrm);
    ++    if(value > (LOG2_MAX_TU_SIZE - 2))
    ++    {
    ++        return IHEVCD_INVALID_PARAMETER;
    ++    }
    +     ps_sps->i1_log2_min_transform_block_size = value + 2;
    ++    if(ps_sps->i1_log2_min_transform_block_size >= ps_sps->i1_log2_min_coding_block_size)
    ++    {
    ++        return IHEVCD_INVALID_PARAMETER;
    ++    }
    + 
    +     UEV_PARSE("log2_diff_max_min_transform_block_size", value, ps_bitstrm);
    ++    if(value > (LOG2_MAX_TU_SIZE - LOG2_MIN_TU_SIZE))
    ++    {
    ++        return IHEVCD_INVALID_PARAMETER;
    ++    }
    +     ps_sps->i1_log2_diff_max_min_transform_block_size = value;
    + 
    +     ps_sps->i1_log2_max_transform_block_size = ps_sps->i1_log2_min_transform_block_size +
    +@@ -1402,7 +1432,9 @@ IHEVCD_ERROR_T ihevcd_parse_sps(codec_t *ps_codec)
                          (ps_sps->i1_log2_diff_max_min_transform_block_size < 0) ||
                          (ps_sps->i1_log2_max_transform_block_size > ps_sps->i1_log2_ctb_size) ||
                          (ps_sps->i1_log2_ctb_size < 4) ||
    @@ -4241,7 +4426,7 @@ index c0f1564..78b578a 100644
          {
              return IHEVCD_INVALID_PARAMETER;
          }
    -@@ -1461,10 +1473,12 @@ IHEVCD_ERROR_T ihevcd_parse_sps(codec_t *ps_codec)
    +@@ -1461,10 +1493,12 @@ IHEVCD_ERROR_T ihevcd_parse_sps(codec_t *ps_codec)
      
          }
          UEV_PARSE("num_short_term_ref_pic_sets", value, ps_bitstrm);
    @@ -4256,7 +4441,7 @@ index c0f1564..78b578a 100644
          for(i = 0; i < ps_sps->i1_num_short_term_ref_pic_sets; i++)
              ihevcd_short_term_ref_pic_set(ps_bitstrm, &ps_sps->as_stref_picset[0], ps_sps->i1_num_short_term_ref_pic_sets, i, &ps_sps->as_stref_picset[i]);
      
    -@@ -1474,6 +1488,10 @@ IHEVCD_ERROR_T ihevcd_parse_sps(codec_t *ps_codec)
    +@@ -1474,6 +1508,10 @@ IHEVCD_ERROR_T ihevcd_parse_sps(codec_t *ps_codec)
          if(ps_sps->i1_long_term_ref_pics_present_flag)
          {
              UEV_PARSE("num_long_term_ref_pics_sps", value, ps_bitstrm);
    @@ -4267,7 +4452,7 @@ index c0f1564..78b578a 100644
              ps_sps->i1_num_long_term_ref_pics_sps = value;
      
              for(i = 0; i < ps_sps->i1_num_long_term_ref_pics_sps; i++)
    -@@ -1576,6 +1594,18 @@ IHEVCD_ERROR_T ihevcd_parse_sps(codec_t *ps_codec)
    +@@ -1576,6 +1614,18 @@ IHEVCD_ERROR_T ihevcd_parse_sps(codec_t *ps_codec)
              if((0 >= disp_wd) || (0 >= disp_ht))
                  return IHEVCD_INVALID_PARAMETER;
      
    @@ -4286,7 +4471,7 @@ index c0f1564..78b578a 100644
              ps_codec->i4_disp_wd = disp_wd;
              ps_codec->i4_disp_ht = disp_ht;
      
    -@@ -1797,6 +1827,35 @@ IHEVCD_ERROR_T ihevcd_parse_pps(codec_t *ps_codec)
    +@@ -1797,6 +1847,35 @@ IHEVCD_ERROR_T ihevcd_parse_pps(codec_t *ps_codec)
          BITS_PARSE("tiles_enabled_flag", value, ps_bitstrm, 1);
          ps_pps->i1_tiles_enabled_flag = value;
      
    @@ -4322,6 +4507,28 @@ index c0f1564..78b578a 100644
          BITS_PARSE("entropy_coding_sync_enabled_flag", value, ps_bitstrm, 1);
          ps_pps->i1_entropy_coding_sync_enabled_flag = value;
      
    +@@ -1841,6 +1920,10 @@ IHEVCD_ERROR_T ihevcd_parse_pps(codec_t *ps_codec)
    +                     {
    +                         UEV_PARSE("column_width_minus1[ i ]", value, ps_bitstrm);
    +                         value += 1;
    ++                        if (value >= ps_sps->i2_pic_wd_in_ctb - start)
    ++                        {
    ++                            return IHEVCD_INVALID_HEADER;
    ++                        }
    +                     }
    +                     else
    +                     {
    +@@ -1877,6 +1960,10 @@ IHEVCD_ERROR_T ihevcd_parse_pps(codec_t *ps_codec)
    + 
    +                         UEV_PARSE("row_height_minus1[ i ]", value, ps_bitstrm);
    +                         value += 1;
    ++                        if (value >= ps_sps->i2_pic_ht_in_ctb - start)
    ++                        {
    ++                            return IHEVCD_INVALID_HEADER;
    ++                        }
    +                     }
    +                     else
    +                     {
     diff --git a/decoder/ihevcd_parse_slice.c b/decoder/ihevcd_parse_slice.c
     index 126b14c..e394a4e 100644
     --- a/decoder/ihevcd_parse_slice.c
    diff --git a/external_libnfc-nci.patch b/external_libnfc-nci.patch
    index 37867db..f7bc9ad 100644
    --- a/external_libnfc-nci.patch
    +++ b/external_libnfc-nci.patch
    @@ -51,6 +51,38 @@ index 89f667f..fb4bdf9 100644
          if ((p_msg = (BT_HDR *) GKI_getbuf (size)) != NULL)
          {
              p_msg->event  = NFA_DM_API_RAW_FRAME_EVT;
    +diff --git a/src/nfa/rw/nfa_rw_act.c b/src/nfa/rw/nfa_rw_act.c
    +index 5a1091d..3821e25 100644
    +--- a/src/nfa/rw/nfa_rw_act.c
    ++++ b/src/nfa/rw/nfa_rw_act.c
    +@@ -22,6 +22,7 @@
    +  *  This file contains the action functions the NFA_RW state machine.
    +  *
    +  ******************************************************************************/
    ++#include <log/log.h>
    + #include <string.h>
    + #include "nfa_rw_int.h"
    + #include "nfa_dm_int.h"
    +@@ -77,9 +78,16 @@ static void nfa_rw_store_ndef_rx_buf (tRW_DATA *p_rw_data)
    + 
    +     p = (UINT8 *)(p_rw_data->data.p_data + 1) + p_rw_data->data.p_data->offset;
    + 
    +-    /* Save data into buffer */
    +-    memcpy(&nfa_rw_cb.p_ndef_buf[nfa_rw_cb.ndef_rd_offset], p, p_rw_data->data.p_data->len);
    +-    nfa_rw_cb.ndef_rd_offset += p_rw_data->data.p_data->len;
    ++    if ((nfa_rw_cb.ndef_rd_offset + p_rw_data->data.p_data->len) <=
    ++        nfa_rw_cb.ndef_cur_size) {
    ++      /* Save data into buffer */
    ++      memcpy(&nfa_rw_cb.p_ndef_buf[nfa_rw_cb.ndef_rd_offset], p,
    ++             p_rw_data->data.p_data->len);
    ++      nfa_rw_cb.ndef_rd_offset += p_rw_data->data.p_data->len;
    ++    } else {
    ++      NFA_TRACE_ERROR0("RW_SetActivatedTagType failed.");
    ++      android_errorWriteLog(0x534e4554, "123583388");
    ++    }
    + 
    +     GKI_freebuf(p_rw_data->data.p_data);
    +     p_rw_data->data.p_data = NULL;
     diff --git a/src/nfc/llcp/llcp_dlc.c b/src/nfc/llcp/llcp_dlc.c
     index 95bcac5..c8a300b 100644
     --- a/src/nfc/llcp/llcp_dlc.c
    diff --git a/external_libvpx.patch b/external_libvpx.patch
    index 4753aa8..48919d3 100644
    --- a/external_libvpx.patch
    +++ b/external_libvpx.patch
    @@ -1,8 +1,29 @@
     diff --git a/libwebm/mkvparser/mkvparser.cc b/libwebm/mkvparser/mkvparser.cc
    -index ff13327..70c1f04 100644
    +index ff13327..efd3545 100644
     --- a/libwebm/mkvparser/mkvparser.cc
     +++ b/libwebm/mkvparser/mkvparser.cc
    -@@ -4983,29 +4983,27 @@ bool PrimaryChromaticity::Parse(IMkvReader* reader, long long read_pos,
    +@@ -4233,6 +4233,7 @@ long ContentEncoding::ParseContentEncodingEntry(long long start, long long size,
    +         new (std::nothrow) ContentEncryption*[encryption_count];
    +     if (!encryption_entries_) {
    +       delete[] compression_entries_;
    ++      compression_entries_ = NULL;
    +       return -1;
    +     }
    +     encryption_entries_end_ = encryption_entries_;
    +@@ -4328,6 +4329,12 @@ long ContentEncoding::ParseCompressionEntry(long long start, long long size,
    +         return status;
    +       }
    + 
    ++      // There should be only one settings element per content compression.
    ++      if (compression->settings != NULL) {
    ++        delete[] buf;
    ++        return E_FILE_FORMAT_INVALID;
    ++      }
    ++
    +       compression->settings = buf;
    +       compression->settings_len = buflen;
    +     }
    +@@ -4983,29 +4990,27 @@ bool PrimaryChromaticity::Parse(IMkvReader* reader, long long read_pos,
        if (!reader)
          return false;
      
    diff --git a/external_wpa_supplicant_8.patch b/external_wpa_supplicant_8.patch
    index 49f28f6..e69de29 100644
    --- a/external_wpa_supplicant_8.patch
    +++ b/external_wpa_supplicant_8.patch
    @@ -1,3791 +0,0 @@
    -diff --git a/hostapd/Android.mk b/hostapd/Android.mk
    -index 67ca1295..588fed90 100644
    ---- a/hostapd/Android.mk
    -+++ b/hostapd/Android.mk
    -@@ -210,11 +210,6 @@ L_CFLAGS += -DCONFIG_RSN_PREAUTH
    - CONFIG_L2_PACKET=y
    - endif
    - 
    --ifdef CONFIG_PEERKEY
    --L_CFLAGS += -DCONFIG_PEERKEY
    --OBJS += src/ap/peerkey_auth.c
    --endif
    --
    - ifdef CONFIG_HS20
    - NEED_AES_OMAC1=y
    - CONFIG_PROXYARP=y
    -diff --git a/hostapd/Makefile b/hostapd/Makefile
    -index fa4af82a..7a5781f1 100644
    ---- a/hostapd/Makefile
    -+++ b/hostapd/Makefile
    -@@ -248,11 +248,6 @@ CFLAGS += -DCONFIG_RSN_PREAUTH
    - CONFIG_L2_PACKET=y
    - endif
    - 
    --ifdef CONFIG_PEERKEY
    --CFLAGS += -DCONFIG_PEERKEY
    --OBJS += ../src/ap/peerkey_auth.o
    --endif
    --
    - ifdef CONFIG_HS20
    - NEED_AES_OMAC1=y
    - CONFIG_PROXYARP=y
    -diff --git a/hostapd/android.config b/hostapd/android.config
    -index e382c408..e8fd2dfd 100644
    ---- a/hostapd/android.config
    -+++ b/hostapd/android.config
    -@@ -44,9 +44,6 @@ CONFIG_DRIVER_NL80211_QCA=y
    - # WPA2/IEEE 802.11i RSN pre-authentication
    - #CONFIG_RSN_PREAUTH=y
    - 
    --# PeerKey handshake for Station to Station Link (IEEE 802.11e DLS)
    --#CONFIG_PEERKEY=y
    --
    - # IEEE 802.11w (management frame protection)
    - # This version is an experimental implementation based on IEEE 802.11w/D1.0
    - # draft and is subject to change since the standard has not yet been finalized.
    -diff --git a/hostapd/config_file.c b/hostapd/config_file.c
    -index c35d5aec..8f49179d 100644
    ---- a/hostapd/config_file.c
    -+++ b/hostapd/config_file.c
    -@@ -2515,10 +2515,9 @@ static int hostapd_config_fill(struct hostapd_config *conf,
    - 		os_free(bss->rsn_preauth_interfaces);
    - 		bss->rsn_preauth_interfaces = os_strdup(pos);
    - #endif /* CONFIG_RSN_PREAUTH */
    --#ifdef CONFIG_PEERKEY
    - 	} else if (os_strcmp(buf, "peerkey") == 0) {
    --		bss->peerkey = atoi(pos);
    --#endif /* CONFIG_PEERKEY */
    -+		wpa_printf(MSG_INFO,
    -+			   "Line %d: Obsolete peerkey parameter ignored", line);
    - #ifdef CONFIG_IEEE80211R
    - 	} else if (os_strcmp(buf, "mobility_domain") == 0) {
    - 		if (os_strlen(pos) != 2 * MOBILITY_DOMAIN_ID_LEN ||
    -diff --git a/hostapd/ctrl_iface.c b/hostapd/ctrl_iface.c
    -index a87f1174..09e3bc40 100644
    ---- a/hostapd/ctrl_iface.c
    -+++ b/hostapd/ctrl_iface.c
    -@@ -1531,6 +1531,67 @@ static int hostapd_ctrl_iface_mgmt_tx(struct hostapd_data *hapd, char *cmd)
    - }
    - 
    - 
    -+static int hostapd_ctrl_iface_mgmt_tx_status_process(struct hostapd_data *hapd,
    -+						     char *cmd)
    -+{
    -+	char *pos, *param;
    -+	size_t len;
    -+	u8 *buf;
    -+	int stype = 0, ok = 0;
    -+	union wpa_event_data event;
    -+
    -+	if (!hapd->ext_mgmt_frame_handling)
    -+		return -1;
    -+
    -+	/* stype=<val> ok=<0/1> buf=<frame hexdump> */
    -+
    -+	wpa_printf(MSG_DEBUG, "External MGMT TX status process: %s", cmd);
    -+
    -+	pos = cmd;
    -+	param = os_strstr(pos, "stype=");
    -+	if (param) {
    -+		param += 6;
    -+		stype = atoi(param);
    -+	}
    -+
    -+	param = os_strstr(pos, " ok=");
    -+	if (param) {
    -+		param += 4;
    -+		ok = atoi(param);
    -+	}
    -+
    -+	param = os_strstr(pos, " buf=");
    -+	if (!param)
    -+		return -1;
    -+	param += 5;
    -+
    -+	len = os_strlen(param);
    -+	if (len & 1)
    -+		return -1;
    -+	len /= 2;
    -+
    -+	buf = os_malloc(len);
    -+	if (!buf || hexstr2bin(param, buf, len) < 0) {
    -+		os_free(buf);
    -+		return -1;
    -+	}
    -+
    -+	os_memset(&event, 0, sizeof(event));
    -+	event.tx_status.type = WLAN_FC_TYPE_MGMT;
    -+	event.tx_status.data = buf;
    -+	event.tx_status.data_len = len;
    -+	event.tx_status.stype = stype;
    -+	event.tx_status.ack = ok;
    -+	hapd->ext_mgmt_frame_handling = 0;
    -+	wpa_supplicant_event(hapd, EVENT_TX_STATUS, &event);
    -+	hapd->ext_mgmt_frame_handling = 1;
    -+
    -+	os_free(buf);
    -+
    -+	return 0;
    -+}
    -+
    -+
    - static int hostapd_ctrl_iface_eapol_rx(struct hostapd_data *hapd, char *cmd)
    - {
    - 	char *pos;
    -@@ -2258,6 +2319,10 @@ static int hostapd_ctrl_iface_receive_process(struct hostapd_data *hapd,
    - 	} else if (os_strncmp(buf, "MGMT_TX ", 8) == 0) {
    - 		if (hostapd_ctrl_iface_mgmt_tx(hapd, buf + 8))
    - 			reply_len = -1;
    -+	} else if (os_strncmp(buf, "MGMT_TX_STATUS_PROCESS ", 23) == 0) {
    -+		if (hostapd_ctrl_iface_mgmt_tx_status_process(hapd,
    -+							      buf + 23) < 0)
    -+			reply_len = -1;
    - 	} else if (os_strncmp(buf, "EAPOL_RX ", 9) == 0) {
    - 		if (hostapd_ctrl_iface_eapol_rx(hapd, buf + 9) < 0)
    - 			reply_len = -1;
    -diff --git a/hostapd/defconfig b/hostapd/defconfig
    -index f7b60e04..5ee37dd9 100644
    ---- a/hostapd/defconfig
    -+++ b/hostapd/defconfig
    -@@ -50,9 +50,6 @@ CONFIG_IAPP=y
    - # WPA2/IEEE 802.11i RSN pre-authentication
    - CONFIG_RSN_PREAUTH=y
    - 
    --# PeerKey handshake for Station to Station Link (IEEE 802.11e DLS)
    --CONFIG_PEERKEY=y
    --
    - # IEEE 802.11w (management frame protection)
    - CONFIG_IEEE80211W=y
    - 
    -diff --git a/hostapd/hostapd.conf b/hostapd/hostapd.conf
    -index d943a43d..1648fd0b 100644
    ---- a/hostapd/hostapd.conf
    -+++ b/hostapd/hostapd.conf
    -@@ -1192,12 +1192,6 @@ own_ip_addr=127.0.0.1
    - # one.
    - #rsn_preauth_interfaces=eth0
    - 
    --# peerkey: Whether PeerKey negotiation for direct links (IEEE 802.11e) is
    --# allowed. This is only used with RSN/WPA2.
    --# 0 = disabled (default)
    --# 1 = enabled
    --#peerkey=1
    --
    - # ieee80211w: Whether management frame protection (MFP) is enabled
    - # 0 = disabled (default)
    - # 1 = optional
    -diff --git a/src/ap/Makefile b/src/ap/Makefile
    -index 98788fef..d67405f8 100644
    ---- a/src/ap/Makefile
    -+++ b/src/ap/Makefile
    -@@ -45,7 +45,6 @@ LIB_OBJS= \
    - 	ieee802_1x.o \
    - 	ndisc_snoop.o \
    - 	p2p_hostapd.o \
    --	peerkey_auth.o \
    - 	pmksa_cache_auth.o \
    - 	preauth_auth.o \
    - 	sta_info.o \
    -diff --git a/src/ap/ap_config.h b/src/ap/ap_config.h
    -index 2d07c67b..4b00c296 100644
    ---- a/src/ap/ap_config.h
    -+++ b/src/ap/ap_config.h
    -@@ -322,7 +322,6 @@ struct hostapd_bss_config {
    - 	int rsn_pairwise;
    - 	int rsn_preauth;
    - 	char *rsn_preauth_interfaces;
    --	int peerkey;
    - 
    - #ifdef CONFIG_IEEE80211R
    - 	/* IEEE 802.11r - Fast BSS Transition */
    -diff --git a/src/ap/ieee802_11.c b/src/ap/ieee802_11.c
    -index 6a373c54..b1cfb51c 100644
    ---- a/src/ap/ieee802_11.c
    -+++ b/src/ap/ieee802_11.c
    -@@ -1774,6 +1774,7 @@ static int add_associated_sta(struct hostapd_data *hapd,
    - {
    - 	struct ieee80211_ht_capabilities ht_cap;
    - 	struct ieee80211_vht_capabilities vht_cap;
    -+	int set = 1;
    - 
    - 	/*
    - 	 * Remove the STA entry to ensure the STA PS state gets cleared and
    -@@ -1781,9 +1782,18 @@ static int add_associated_sta(struct hostapd_data *hapd,
    - 	 * FT-over-the-DS, where a station re-associates back to the same AP but
    - 	 * skips the authentication flow, or if working with a driver that
    - 	 * does not support full AP client state.
    -+	 *
    -+	 * Skip this if the STA has already completed FT reassociation and the
    -+	 * TK has been configured since the TX/RX PN must not be reset to 0 for
    -+	 * the same key.
    - 	 */
    --	if (!sta->added_unassoc)
    -+	if (!sta->added_unassoc &&
    -+	    (!(sta->flags & WLAN_STA_AUTHORIZED) ||
    -+	     !wpa_auth_sta_ft_tk_already_set(sta->wpa_sm))) {
    - 		hostapd_drv_sta_remove(hapd, sta->addr);
    -+		wpa_auth_sm_event(sta->wpa_sm, WPA_DRV_STA_REMOVED);
    -+		set = 0;
    -+	}
    - 
    - #ifdef CONFIG_IEEE80211N
    - 	if (sta->flags & WLAN_STA_HT)
    -@@ -1805,11 +1815,11 @@ static int add_associated_sta(struct hostapd_data *hapd,
    - 			    sta->flags & WLAN_STA_HT ? &ht_cap : NULL,
    - 			    sta->flags & WLAN_STA_VHT ? &vht_cap : NULL,
    - 			    sta->flags | WLAN_STA_ASSOC, sta->qosinfo,
    --			    sta->vht_opmode, sta->added_unassoc)) {
    -+			    sta->vht_opmode, set)) {
    - 		hostapd_logger(hapd, sta->addr,
    - 			       HOSTAPD_MODULE_IEEE80211, HOSTAPD_LEVEL_NOTICE,
    - 			       "Could not %s STA to kernel driver",
    --			       sta->added_unassoc ? "set" : "add");
    -+			       set ? "set" : "add");
    - 
    - 		if (sta->added_unassoc) {
    - 			hostapd_drv_sta_remove(hapd, sta->addr);
    -@@ -2883,8 +2893,16 @@ void ieee802_11_mgmt_cb(struct hostapd_data *hapd, const u8 *buf, size_t len,
    - 
    - #ifdef CONFIG_TESTING_OPTIONS
    - 	if (hapd->ext_mgmt_frame_handling) {
    --		wpa_msg(hapd->msg_ctx, MSG_INFO, "MGMT-TX-STATUS stype=%u ok=%d",
    --			stype, ok);
    -+		size_t hex_len = 2 * len + 1;
    -+		char *hex = os_malloc(hex_len);
    -+
    -+		if (hex) {
    -+			wpa_snprintf_hex(hex, hex_len, buf, len);
    -+			wpa_msg(hapd->msg_ctx, MSG_INFO,
    -+				"MGMT-TX-STATUS stype=%u ok=%d buf=%s",
    -+				stype, ok, hex);
    -+			os_free(hex);
    -+		}
    - 		return;
    - 	}
    - #endif /* CONFIG_TESTING_OPTIONS */
    -diff --git a/src/ap/peerkey_auth.c b/src/ap/peerkey_auth.c
    -deleted file mode 100644
    -index efc1d7e4..00000000
    ---- a/src/ap/peerkey_auth.c
    -+++ /dev/null
    -@@ -1,396 +0,0 @@
    --/*
    -- * hostapd - PeerKey for Direct Link Setup (DLS)
    -- * Copyright (c) 2006-2009, Jouni Malinen <j@w1.fi>
    -- *
    -- * This software may be distributed under the terms of the BSD license.
    -- * See README for more details.
    -- */
    --
    --#include "utils/includes.h"
    --
    --#include "utils/common.h"
    --#include "utils/eloop.h"
    --#include "crypto/sha1.h"
    --#include "crypto/sha256.h"
    --#include "crypto/random.h"
    --#include "wpa_auth.h"
    --#include "wpa_auth_i.h"
    --#include "wpa_auth_ie.h"
    --
    --#ifdef CONFIG_PEERKEY
    --
    --static void wpa_stsl_step(void *eloop_ctx, void *timeout_ctx)
    --{
    --#if 0
    --	struct wpa_authenticator *wpa_auth = eloop_ctx;
    --	struct wpa_stsl_negotiation *neg = timeout_ctx;
    --#endif
    --
    --	/* TODO: ? */
    --}
    --
    --
    --struct wpa_stsl_search {
    --	const u8 *addr;
    --	struct wpa_state_machine *sm;
    --};
    --
    --
    --static int wpa_stsl_select_sta(struct wpa_state_machine *sm, void *ctx)
    --{
    --	struct wpa_stsl_search *search = ctx;
    --	if (os_memcmp(search->addr, sm->addr, ETH_ALEN) == 0) {
    --		search->sm = sm;
    --		return 1;
    --	}
    --	return 0;
    --}
    --
    --
    --static void wpa_smk_send_error(struct wpa_authenticator *wpa_auth,
    --			       struct wpa_state_machine *sm, const u8 *peer,
    --			       u16 mui, u16 error_type)
    --{
    --	u8 kde[2 + RSN_SELECTOR_LEN + ETH_ALEN +
    --	       2 + RSN_SELECTOR_LEN + sizeof(struct rsn_error_kde)];
    --	u8 *pos;
    --	struct rsn_error_kde error;
    --
    --	wpa_auth_logger(wpa_auth, sm->addr, LOGGER_DEBUG,
    --			"Sending SMK Error");
    --
    --	pos = kde;
    --
    --	if (peer) {
    --		pos = wpa_add_kde(pos, RSN_KEY_DATA_MAC_ADDR, peer, ETH_ALEN,
    --				  NULL, 0);
    --	}
    --
    --	error.mui = host_to_be16(mui);
    --	error.error_type = host_to_be16(error_type);
    --	pos = wpa_add_kde(pos, RSN_KEY_DATA_ERROR,
    --			  (u8 *) &error, sizeof(error), NULL, 0);
    --
    --	__wpa_send_eapol(wpa_auth, sm,
    --			 WPA_KEY_INFO_SECURE | WPA_KEY_INFO_MIC |
    --			 WPA_KEY_INFO_SMK_MESSAGE | WPA_KEY_INFO_ERROR,
    --			 NULL, NULL, kde, pos - kde, 0, 0, 0);
    --}
    --
    --
    --void wpa_smk_m1(struct wpa_authenticator *wpa_auth,
    --		struct wpa_state_machine *sm, struct wpa_eapol_key *key,
    --		const u8 *key_data, size_t key_data_len)
    --{
    --	struct wpa_eapol_ie_parse kde;
    --	struct wpa_stsl_search search;
    --	u8 *buf, *pos;
    --	size_t buf_len;
    --
    --	if (wpa_parse_kde_ies(key_data, key_data_len, &kde) < 0) {
    --		wpa_printf(MSG_INFO, "RSN: Failed to parse KDEs in SMK M1");
    --		return;
    --	}
    --
    --	if (kde.rsn_ie == NULL || kde.mac_addr == NULL ||
    --	    kde.mac_addr_len < ETH_ALEN) {
    --		wpa_printf(MSG_INFO, "RSN: No RSN IE or MAC address KDE in "
    --			   "SMK M1");
    --		return;
    --	}
    --
    --	/* Initiator = sm->addr; Peer = kde.mac_addr */
    --
    --	search.addr = kde.mac_addr;
    --	search.sm = NULL;
    --	if (wpa_auth_for_each_sta(wpa_auth, wpa_stsl_select_sta, &search) ==
    --	    0 || search.sm == NULL) {
    --		wpa_printf(MSG_DEBUG, "RSN: SMK handshake with " MACSTR
    --			   " aborted - STA not associated anymore",
    --			   MAC2STR(kde.mac_addr));
    --		wpa_smk_send_error(wpa_auth, sm, kde.mac_addr, STK_MUI_SMK,
    --				   STK_ERR_STA_NR);
    --		/* FIX: wpa_stsl_remove(wpa_auth, neg); */
    --		return;
    --	}
    --
    --	buf_len = kde.rsn_ie_len + 2 + RSN_SELECTOR_LEN + ETH_ALEN;
    --	buf = os_malloc(buf_len);
    --	if (buf == NULL)
    --		return;
    --	/* Initiator RSN IE */
    --	os_memcpy(buf, kde.rsn_ie, kde.rsn_ie_len);
    --	pos = buf + kde.rsn_ie_len;
    --	/* Initiator MAC Address */
    --	pos = wpa_add_kde(pos, RSN_KEY_DATA_MAC_ADDR, sm->addr, ETH_ALEN,
    --			  NULL, 0);
    --
    --	/* SMK M2:
    --	 * EAPOL-Key(S=1, M=1, A=1, I=0, K=0, SM=1, KeyRSC=0, Nonce=INonce,
    --	 *           MIC=MIC, DataKDs=(RSNIE_I, MAC_I KDE)
    --	 */
    --
    --	wpa_auth_logger(wpa_auth, search.sm->addr, LOGGER_DEBUG,
    --			"Sending SMK M2");
    --
    --	__wpa_send_eapol(wpa_auth, search.sm,
    --			 WPA_KEY_INFO_SECURE | WPA_KEY_INFO_MIC |
    --			 WPA_KEY_INFO_ACK | WPA_KEY_INFO_SMK_MESSAGE,
    --			 NULL, key->key_nonce, buf, pos - buf, 0, 0, 0);
    --
    --	os_free(buf);
    --}
    --
    --
    --static void wpa_send_smk_m4(struct wpa_authenticator *wpa_auth,
    --			    struct wpa_state_machine *sm,
    --			    struct wpa_eapol_key *key,
    --			    struct wpa_eapol_ie_parse *kde,
    --			    const u8 *smk)
    --{
    --	u8 *buf, *pos;
    --	size_t buf_len;
    --	u32 lifetime;
    --
    --	/* SMK M4:
    --	 * EAPOL-Key(S=1, M=1, A=0, I=1, K=0, SM=1, KeyRSC=0, Nonce=PNonce,
    --	 *           MIC=MIC, DataKDs=(MAC_I KDE, INonce KDE, SMK KDE,
    --	 *           Lifetime KDE)
    --	 */
    --
    --	buf_len = 2 + RSN_SELECTOR_LEN + ETH_ALEN +
    --		2 + RSN_SELECTOR_LEN + WPA_NONCE_LEN +
    --		2 + RSN_SELECTOR_LEN + PMK_LEN + WPA_NONCE_LEN +
    --		2 + RSN_SELECTOR_LEN + sizeof(lifetime);
    --	pos = buf = os_malloc(buf_len);
    --	if (buf == NULL)
    --		return;
    --
    --	/* Initiator MAC Address */
    --	pos = wpa_add_kde(pos, RSN_KEY_DATA_MAC_ADDR, kde->mac_addr, ETH_ALEN,
    --			  NULL, 0);
    --
    --	/* Initiator Nonce */
    --	pos = wpa_add_kde(pos, RSN_KEY_DATA_NONCE, kde->nonce, WPA_NONCE_LEN,
    --			  NULL, 0);
    --
    --	/* SMK with PNonce */
    --	pos = wpa_add_kde(pos, RSN_KEY_DATA_SMK, smk, PMK_LEN,
    --			  key->key_nonce, WPA_NONCE_LEN);
    --
    --	/* Lifetime */
    --	lifetime = htonl(43200); /* dot11RSNAConfigSMKLifetime */
    --	pos = wpa_add_kde(pos, RSN_KEY_DATA_LIFETIME,
    --			  (u8 *) &lifetime, sizeof(lifetime), NULL, 0);
    --
    --	wpa_auth_logger(sm->wpa_auth, sm->addr, LOGGER_DEBUG,
    --			"Sending SMK M4");
    --
    --	__wpa_send_eapol(wpa_auth, sm,
    --			 WPA_KEY_INFO_SECURE | WPA_KEY_INFO_MIC |
    --			 WPA_KEY_INFO_INSTALL | WPA_KEY_INFO_SMK_MESSAGE,
    --			 NULL, key->key_nonce, buf, pos - buf, 0, 1, 0);
    --
    --	os_free(buf);
    --}
    --
    --
    --static void wpa_send_smk_m5(struct wpa_authenticator *wpa_auth,
    --			    struct wpa_state_machine *sm,
    --			    struct wpa_eapol_key *key,
    --			    struct wpa_eapol_ie_parse *kde,
    --			    const u8 *smk, const u8 *peer)
    --{
    --	u8 *buf, *pos;
    --	size_t buf_len;
    --	u32 lifetime;
    --
    --	/* SMK M5:
    --	 * EAPOL-Key(S=1, M=1, A=0, I=0, K=0, SM=1, KeyRSC=0, Nonce=INonce,
    --	 *           MIC=MIC, DataKDs=(RSNIE_P, MAC_P KDE, PNonce, SMK KDE,
    --	 *                             Lifetime KDE))
    --	 */
    --
    --	buf_len = kde->rsn_ie_len +
    --		2 + RSN_SELECTOR_LEN + ETH_ALEN +
    --		2 + RSN_SELECTOR_LEN + WPA_NONCE_LEN +
    --		2 + RSN_SELECTOR_LEN + PMK_LEN + WPA_NONCE_LEN +
    --		2 + RSN_SELECTOR_LEN + sizeof(lifetime);
    --	pos = buf = os_malloc(buf_len);
    --	if (buf == NULL)
    --		return;
    --
    --	/* Peer RSN IE */
    --	os_memcpy(pos, kde->rsn_ie, kde->rsn_ie_len);
    --	pos += kde->rsn_ie_len;
    --
    --	/* Peer MAC Address */
    --	pos = wpa_add_kde(pos, RSN_KEY_DATA_MAC_ADDR, peer, ETH_ALEN, NULL, 0);
    --
    --	/* PNonce */
    --	pos = wpa_add_kde(pos, RSN_KEY_DATA_NONCE, key->key_nonce,
    --			  WPA_NONCE_LEN, NULL, 0);
    --
    --	/* SMK and INonce */
    --	pos = wpa_add_kde(pos, RSN_KEY_DATA_SMK, smk, PMK_LEN,
    --			  kde->nonce, WPA_NONCE_LEN);
    --
    --	/* Lifetime */
    --	lifetime = htonl(43200); /* dot11RSNAConfigSMKLifetime */
    --	pos = wpa_add_kde(pos, RSN_KEY_DATA_LIFETIME,
    --			  (u8 *) &lifetime, sizeof(lifetime), NULL, 0);
    --
    --	wpa_auth_logger(sm->wpa_auth, sm->addr, LOGGER_DEBUG,
    --			"Sending SMK M5");
    --
    --	__wpa_send_eapol(wpa_auth, sm,
    --			 WPA_KEY_INFO_SECURE | WPA_KEY_INFO_MIC |
    --			 WPA_KEY_INFO_SMK_MESSAGE,
    --			 NULL, kde->nonce, buf, pos - buf, 0, 1, 0);
    --
    --	os_free(buf);
    --}
    --
    --
    --void wpa_smk_m3(struct wpa_authenticator *wpa_auth,
    --		struct wpa_state_machine *sm, struct wpa_eapol_key *key,
    --		const u8 *key_data, size_t key_data_len)
    --{
    --	struct wpa_eapol_ie_parse kde;
    --	struct wpa_stsl_search search;
    --	u8 smk[32], buf[ETH_ALEN + 8 + 2 * WPA_NONCE_LEN], *pos;
    --
    --	if (wpa_parse_kde_ies(key_data, key_data_len, &kde) < 0) {
    --		wpa_printf(MSG_INFO, "RSN: Failed to parse KDEs in SMK M3");
    --		return;
    --	}
    --
    --	if (kde.rsn_ie == NULL ||
    --	    kde.mac_addr == NULL || kde.mac_addr_len < ETH_ALEN ||
    --	    kde.nonce == NULL || kde.nonce_len < WPA_NONCE_LEN) {
    --		wpa_printf(MSG_INFO, "RSN: No RSN IE, MAC address KDE, or "
    --			   "Nonce KDE in SMK M3");
    --		return;
    --	}
    --
    --	/* Peer = sm->addr; Initiator = kde.mac_addr;
    --	 * Peer Nonce = key->key_nonce; Initiator Nonce = kde.nonce */
    --
    --	search.addr = kde.mac_addr;
    --	search.sm = NULL;
    --	if (wpa_auth_for_each_sta(wpa_auth, wpa_stsl_select_sta, &search) ==
    --	    0 || search.sm == NULL) {
    --		wpa_printf(MSG_DEBUG, "RSN: SMK handshake with " MACSTR
    --			   " aborted - STA not associated anymore",
    --			   MAC2STR(kde.mac_addr));
    --		wpa_smk_send_error(wpa_auth, sm, kde.mac_addr, STK_MUI_SMK,
    --				   STK_ERR_STA_NR);
    --		/* FIX: wpa_stsl_remove(wpa_auth, neg); */
    --		return;
    --	}
    --
    --	if (random_get_bytes(smk, PMK_LEN)) {
    --		wpa_printf(MSG_DEBUG, "RSN: Failed to generate SMK");
    --		return;
    --	}
    --
    --	/* SMK = PRF-256(Random number, "SMK Derivation",
    --	 *               AA || Time || INonce || PNonce)
    --	 */
    --	os_memcpy(buf, wpa_auth->addr, ETH_ALEN);
    --	pos = buf + ETH_ALEN;
    --	wpa_get_ntp_timestamp(pos);
    --	pos += 8;
    --	os_memcpy(pos, kde.nonce, WPA_NONCE_LEN);
    --	pos += WPA_NONCE_LEN;
    --	os_memcpy(pos, key->key_nonce, WPA_NONCE_LEN);
    --#ifdef CONFIG_IEEE80211W
    --	sha256_prf(smk, PMK_LEN, "SMK Derivation", buf, sizeof(buf),
    --		   smk, PMK_LEN);
    --#else /* CONFIG_IEEE80211W */
    --	sha1_prf(smk, PMK_LEN, "SMK Derivation", buf, sizeof(buf),
    --		 smk, PMK_LEN);
    --#endif /* CONFIG_IEEE80211W */
    --
    --	wpa_hexdump_key(MSG_DEBUG, "RSN: SMK", smk, PMK_LEN);
    --
    --	wpa_send_smk_m4(wpa_auth, sm, key, &kde, smk);
    --	wpa_send_smk_m5(wpa_auth, search.sm, key, &kde, smk, sm->addr);
    --
    --	/* Authenticator does not need SMK anymore and it is required to forget
    --	 * it. */
    --	os_memset(smk, 0, sizeof(*smk));
    --}
    --
    --
    --void wpa_smk_error(struct wpa_authenticator *wpa_auth,
    --		   struct wpa_state_machine *sm,
    --		   const u8 *key_data, size_t key_data_len)
    --{
    --	struct wpa_eapol_ie_parse kde;
    --	struct wpa_stsl_search search;
    --	struct rsn_error_kde error;
    --	u16 mui, error_type;
    --
    --	if (wpa_parse_kde_ies(key_data, key_data_len, &kde) < 0) {
    --		wpa_printf(MSG_INFO, "RSN: Failed to parse KDEs in SMK Error");
    --		return;
    --	}
    --
    --	if (kde.mac_addr == NULL || kde.mac_addr_len < ETH_ALEN ||
    --	    kde.error == NULL || kde.error_len < sizeof(error)) {
    --		wpa_printf(MSG_INFO, "RSN: No MAC address or Error KDE in "
    --			   "SMK Error");
    --		return;
    --	}
    --
    --	search.addr = kde.mac_addr;
    --	search.sm = NULL;
    --	if (wpa_auth_for_each_sta(wpa_auth, wpa_stsl_select_sta, &search) ==
    --	    0 || search.sm == NULL) {
    --		wpa_printf(MSG_DEBUG, "RSN: Peer STA " MACSTR " not "
    --			   "associated for SMK Error message from " MACSTR,
    --			   MAC2STR(kde.mac_addr), MAC2STR(sm->addr));
    --		return;
    --	}
    --
    --	os_memcpy(&error, kde.error, sizeof(error));
    --	mui = be_to_host16(error.mui);
    --	error_type = be_to_host16(error.error_type);
    --	wpa_auth_vlogger(wpa_auth, sm->addr, LOGGER_INFO,
    --			 "STA reported SMK Error: Peer " MACSTR
    --			 " MUI %d Error Type %d",
    --			 MAC2STR(kde.mac_addr), mui, error_type);
    --
    --	wpa_smk_send_error(wpa_auth, search.sm, sm->addr, mui, error_type);
    --}
    --
    --
    --int wpa_stsl_remove(struct wpa_authenticator *wpa_auth,
    --		    struct wpa_stsl_negotiation *neg)
    --{
    --	struct wpa_stsl_negotiation *pos, *prev;
    --
    --	if (wpa_auth == NULL)
    --		return -1;
    --	pos = wpa_auth->stsl_negotiations;
    --	prev = NULL;
    --	while (pos) {
    --		if (pos == neg) {
    --			if (prev)
    --				prev->next = pos->next;
    --			else
    --				wpa_auth->stsl_negotiations = pos->next;
    --
    --			eloop_cancel_timeout(wpa_stsl_step, wpa_auth, pos);
    --			os_free(pos);
    --			return 0;
    --		}
    --		prev = pos;
    --		pos = pos->next;
    --	}
    --
    --	return -1;
    --}
    --
    --#endif /* CONFIG_PEERKEY */
    -diff --git a/src/ap/wnm_ap.c b/src/ap/wnm_ap.c
    -index 41d50ceb..02daa9bc 100644
    ---- a/src/ap/wnm_ap.c
    -+++ b/src/ap/wnm_ap.c
    -@@ -202,6 +202,13 @@ static void ieee802_11_rx_wnmsleep_req(struct hostapd_data *hapd,
    - 	u8 *tfsreq_ie_end = NULL;
    - 	u16 tfsreq_ie_len = 0;
    - 
    -+	if (len < 1) {
    -+		wpa_printf(MSG_DEBUG,
    -+			   "WNM: Ignore too short WNM-Sleep Mode Request from "
    -+			   MACSTR, MAC2STR(addr));
    -+		return;
    -+	}
    -+
    - 	dialog_token = *pos++;
    - 	while (pos + 1 < frm + len) {
    - 		u8 ie_len = pos[1];
    -diff --git a/src/ap/wpa_auth.c b/src/ap/wpa_auth.c
    -index 35870864..e5974ff1 100644
    ---- a/src/ap/wpa_auth.c
    -+++ b/src/ap/wpa_auth.c
    -@@ -879,8 +879,7 @@ void wpa_receive(struct wpa_authenticator *wpa_auth,
    - 	struct wpa_eapol_key *key;
    - 	struct wpa_eapol_key_192 *key192;
    - 	u16 key_info, key_data_length;
    --	enum { PAIRWISE_2, PAIRWISE_4, GROUP_2, REQUEST,
    --	       SMK_M1, SMK_M3, SMK_ERROR } msg;
    -+	enum { PAIRWISE_2, PAIRWISE_4, GROUP_2, REQUEST } msg;
    - 	char *msgtxt;
    - 	struct wpa_eapol_ie_parse kde;
    - 	int ft;
    -@@ -950,19 +949,12 @@ void wpa_receive(struct wpa_authenticator *wpa_auth,
    - 	/* FIX: verify that the EAPOL-Key frame was encrypted if pairwise keys
    - 	 * are set */
    - 
    --	if ((key_info & (WPA_KEY_INFO_SMK_MESSAGE | WPA_KEY_INFO_REQUEST)) ==
    --	    (WPA_KEY_INFO_SMK_MESSAGE | WPA_KEY_INFO_REQUEST)) {
    --		if (key_info & WPA_KEY_INFO_ERROR) {
    --			msg = SMK_ERROR;
    --			msgtxt = "SMK Error";
    --		} else {
    --			msg = SMK_M1;
    --			msgtxt = "SMK M1";
    --		}
    --	} else if (key_info & WPA_KEY_INFO_SMK_MESSAGE) {
    --		msg = SMK_M3;
    --		msgtxt = "SMK M3";
    --	} else if (key_info & WPA_KEY_INFO_REQUEST) {
    -+	if (key_info & WPA_KEY_INFO_SMK_MESSAGE) {
    -+		wpa_printf(MSG_DEBUG, "WPA: Ignore SMK message");
    -+		return;
    -+	}
    -+
    -+	if (key_info & WPA_KEY_INFO_REQUEST) {
    - 		msg = REQUEST;
    - 		msgtxt = "Request";
    - 	} else if (!(key_info & WPA_KEY_INFO_KEY_TYPE)) {
    -@@ -976,7 +968,6 @@ void wpa_receive(struct wpa_authenticator *wpa_auth,
    - 		msgtxt = "2/4 Pairwise";
    - 	}
    - 
    --	/* TODO: key_info type validation for PeerKey */
    - 	if (msg == REQUEST || msg == PAIRWISE_2 || msg == PAIRWISE_4 ||
    - 	    msg == GROUP_2) {
    - 		u16 ver = key_info & WPA_KEY_INFO_TYPE_MASK;
    -@@ -1204,28 +1195,6 @@ continue_processing:
    - 			return;
    - 		}
    - 		break;
    --#ifdef CONFIG_PEERKEY
    --	case SMK_M1:
    --	case SMK_M3:
    --	case SMK_ERROR:
    --		if (!wpa_auth->conf.peerkey) {
    --			wpa_printf(MSG_DEBUG, "RSN: SMK M1/M3/Error, but "
    --				   "PeerKey use disabled - ignoring message");
    --			return;
    --		}
    --		if (!sm->PTK_valid) {
    --			wpa_auth_logger(wpa_auth, sm->addr, LOGGER_INFO,
    --					"received EAPOL-Key msg SMK in "
    --					"invalid state - dropped");
    --			return;
    --		}
    --		break;
    --#else /* CONFIG_PEERKEY */
    --	case SMK_M1:
    --	case SMK_M3:
    --	case SMK_ERROR:
    --		return; /* STSL disabled - ignore SMK messages */
    --#endif /* CONFIG_PEERKEY */
    - 	case REQUEST:
    - 		break;
    - 	}
    -@@ -1277,12 +1246,7 @@ continue_processing:
    - 		 * even though MAC address KDE is not normally encrypted,
    - 		 * supplicant is allowed to encrypt it.
    - 		 */
    --		if (msg == SMK_ERROR) {
    --#ifdef CONFIG_PEERKEY
    --			wpa_smk_error(wpa_auth, sm, key_data, key_data_length);
    --#endif /* CONFIG_PEERKEY */
    --			return;
    --		} else if (key_info & WPA_KEY_INFO_ERROR) {
    -+		if (key_info & WPA_KEY_INFO_ERROR) {
    - 			if (wpa_receive_error_report(
    - 				    wpa_auth, sm,
    - 				    !(key_info & WPA_KEY_INFO_KEY_TYPE)) > 0)
    -@@ -1292,11 +1256,6 @@ continue_processing:
    - 					"received EAPOL-Key Request for new "
    - 					"4-Way Handshake");
    - 			wpa_request_new_ptk(sm);
    --#ifdef CONFIG_PEERKEY
    --		} else if (msg == SMK_M1) {
    --			wpa_smk_m1(wpa_auth, sm, key, key_data,
    --				   key_data_length);
    --#endif /* CONFIG_PEERKEY */
    - 		} else if (key_data_length > 0 &&
    - 			   wpa_parse_kde_ies(key_data, key_data_length,
    - 					     &kde) == 0 &&
    -@@ -1335,13 +1294,6 @@ continue_processing:
    - 		wpa_replay_counter_mark_invalid(sm->key_replay, NULL);
    - 	}
    - 
    --#ifdef CONFIG_PEERKEY
    --	if (msg == SMK_M3) {
    --		wpa_smk_m3(wpa_auth, sm, key, key_data, key_data_length);
    --		return;
    --	}
    --#endif /* CONFIG_PEERKEY */
    --
    - 	os_free(sm->last_rx_eapol_key);
    - 	sm->last_rx_eapol_key = os_malloc(data_len);
    - 	if (sm->last_rx_eapol_key == NULL)
    -@@ -1484,11 +1436,11 @@ void __wpa_send_eapol(struct wpa_authenticator *wpa_auth,
    - 	WPA_PUT_BE16(key->key_info, key_info);
    - 
    - 	alg = pairwise ? sm->pairwise : wpa_auth->conf.wpa_group;
    --	WPA_PUT_BE16(key->key_length, wpa_cipher_key_len(alg));
    --	if (key_info & WPA_KEY_INFO_SMK_MESSAGE)
    -+	if (sm->wpa == WPA_VERSION_WPA2 && !pairwise)
    - 		WPA_PUT_BE16(key->key_length, 0);
    -+	else
    -+		WPA_PUT_BE16(key->key_length, wpa_cipher_key_len(alg));
    - 
    --	/* FIX: STSL: what to use as key_replay_counter? */
    - 	for (i = RSNA_MAX_EAPOL_RETRIES - 1; i > 0; i--) {
    - 		sm->key_replay[i].valid = sm->key_replay[i - 1].valid;
    - 		os_memcpy(sm->key_replay[i].counter,
    -@@ -1745,6 +1697,9 @@ int wpa_auth_sm_event(struct wpa_state_machine *sm, enum wpa_event event)
    - #else /* CONFIG_IEEE80211R */
    - 		break;
    - #endif /* CONFIG_IEEE80211R */
    -+	case WPA_DRV_STA_REMOVED:
    -+		sm->tk_already_set = FALSE;
    -+		return 0;
    - 	}
    - 
    - #ifdef CONFIG_IEEE80211R
    -@@ -1898,6 +1853,21 @@ SM_STATE(WPA_PTK, AUTHENTICATION2)
    - }
    - 
    - 
    -+static int wpa_auth_sm_ptk_update(struct wpa_state_machine *sm)
    -+{
    -+	if (random_get_bytes(sm->ANonce, WPA_NONCE_LEN)) {
    -+		wpa_printf(MSG_ERROR,
    -+			   "WPA: Failed to get random data for ANonce");
    -+		sm->Disconnect = TRUE;
    -+		return -1;
    -+	}
    -+	wpa_hexdump(MSG_DEBUG, "WPA: Assign new ANonce", sm->ANonce,
    -+		    WPA_NONCE_LEN);
    -+	sm->TimeoutCtr = 0;
    -+	return 0;
    -+}
    -+
    -+
    - SM_STATE(WPA_PTK, INITPMK)
    - {
    - 	u8 msk[2 * PMK_LEN];
    -@@ -2455,9 +2425,12 @@ SM_STEP(WPA_PTK)
    - 		SM_ENTER(WPA_PTK, AUTHENTICATION);
    - 	else if (sm->ReAuthenticationRequest)
    - 		SM_ENTER(WPA_PTK, AUTHENTICATION2);
    --	else if (sm->PTKRequest)
    --		SM_ENTER(WPA_PTK, PTKSTART);
    --	else switch (sm->wpa_ptk_state) {
    -+	else if (sm->PTKRequest) {
    -+		if (wpa_auth_sm_ptk_update(sm) < 0)
    -+			SM_ENTER(WPA_PTK, DISCONNECTED);
    -+		else
    -+			SM_ENTER(WPA_PTK, PTKSTART);
    -+	} else switch (sm->wpa_ptk_state) {
    - 	case WPA_PTK_INITIALIZE:
    - 		break;
    - 	case WPA_PTK_DISCONNECT:
    -@@ -3250,6 +3223,14 @@ int wpa_auth_sta_wpa_version(struct wpa_state_machine *sm)
    - }
    - 
    - 
    -+int wpa_auth_sta_ft_tk_already_set(struct wpa_state_machine *sm)
    -+{
    -+	if (!sm || !wpa_key_mgmt_ft(sm->wpa_key_mgmt))
    -+		return 0;
    -+	return sm->tk_already_set;
    -+}
    -+
    -+
    - int wpa_auth_sta_clear_pmksa(struct wpa_state_machine *sm,
    - 			     struct rsn_pmksa_cache_entry *entry)
    - {
    -diff --git a/src/ap/wpa_auth.h b/src/ap/wpa_auth.h
    -index 0de8d976..032b0a32 100644
    ---- a/src/ap/wpa_auth.h
    -+++ b/src/ap/wpa_auth.h
    -@@ -147,7 +147,6 @@ struct wpa_auth_config {
    - 	int rsn_pairwise;
    - 	int rsn_preauth;
    - 	int eapol_version;
    --	int peerkey;
    - 	int wmm_enabled;
    - 	int wmm_uapsd;
    - 	int disable_pmksa_caching;
    -@@ -267,7 +266,7 @@ void wpa_receive(struct wpa_authenticator *wpa_auth,
    - 		 u8 *data, size_t data_len);
    - enum wpa_event {
    - 	WPA_AUTH, WPA_ASSOC, WPA_DISASSOC, WPA_DEAUTH, WPA_REAUTH,
    --	WPA_REAUTH_EAPOL, WPA_ASSOC_FT
    -+	WPA_REAUTH_EAPOL, WPA_ASSOC_FT, WPA_DRV_STA_REMOVED
    - };
    - void wpa_remove_ptk(struct wpa_state_machine *sm);
    - int wpa_auth_sm_event(struct wpa_state_machine *sm, enum wpa_event event);
    -@@ -280,6 +279,7 @@ int wpa_auth_pairwise_set(struct wpa_state_machine *sm);
    - int wpa_auth_get_pairwise(struct wpa_state_machine *sm);
    - int wpa_auth_sta_key_mgmt(struct wpa_state_machine *sm);
    - int wpa_auth_sta_wpa_version(struct wpa_state_machine *sm);
    -+int wpa_auth_sta_ft_tk_already_set(struct wpa_state_machine *sm);
    - int wpa_auth_sta_clear_pmksa(struct wpa_state_machine *sm,
    - 			     struct rsn_pmksa_cache_entry *entry);
    - struct rsn_pmksa_cache_entry *
    -diff --git a/src/ap/wpa_auth_ft.c b/src/ap/wpa_auth_ft.c
    -index 42242a54..e63b99ad 100644
    ---- a/src/ap/wpa_auth_ft.c
    -+++ b/src/ap/wpa_auth_ft.c
    -@@ -780,6 +780,14 @@ void wpa_ft_install_ptk(struct wpa_state_machine *sm)
    - 		return;
    - 	}
    - 
    -+	if (sm->tk_already_set) {
    -+		/* Must avoid TK reconfiguration to prevent clearing of TX/RX
    -+		 * PN in the driver */
    -+		wpa_printf(MSG_DEBUG,
    -+			   "FT: Do not re-install same PTK to the driver");
    -+		return;
    -+	}
    -+
    - 	/* FIX: add STA entry to kernel/driver here? The set_key will fail
    - 	 * most likely without this.. At the moment, STA entry is added only
    - 	 * after association has been completed. This function will be called
    -@@ -792,6 +800,7 @@ void wpa_ft_install_ptk(struct wpa_state_machine *sm)
    - 
    - 	/* FIX: MLME-SetProtection.Request(TA, Tx_Rx) */
    - 	sm->pairwise_set = TRUE;
    -+	sm->tk_already_set = TRUE;
    - }
    - 
    - 
    -@@ -898,6 +907,7 @@ static int wpa_ft_process_auth_req(struct wpa_state_machine *sm,
    - 
    - 	sm->pairwise = pairwise;
    - 	sm->PTK_valid = TRUE;
    -+	sm->tk_already_set = FALSE;
    - 	wpa_ft_install_ptk(sm);
    - 
    - 	buflen = 2 + sizeof(struct rsn_mdie) + 2 + sizeof(struct rsn_ftie) +
    -diff --git a/src/ap/wpa_auth_glue.c b/src/ap/wpa_auth_glue.c
    -index 5fe0987f..cbc1dbc4 100644
    ---- a/src/ap/wpa_auth_glue.c
    -+++ b/src/ap/wpa_auth_glue.c
    -@@ -44,7 +44,6 @@ static void hostapd_wpa_auth_conf(struct hostapd_bss_config *conf,
    - 	wconf->rsn_pairwise = conf->rsn_pairwise;
    - 	wconf->rsn_preauth = conf->rsn_preauth;
    - 	wconf->eapol_version = conf->eapol_version;
    --	wconf->peerkey = conf->peerkey;
    - 	wconf->wmm_enabled = conf->wmm_enabled;
    - 	wconf->wmm_uapsd = conf->wmm_uapsd;
    - 	wconf->disable_pmksa_caching = conf->disable_pmksa_caching;
    -diff --git a/src/ap/wpa_auth_i.h b/src/ap/wpa_auth_i.h
    -index 72b7eb37..b781605e 100644
    ---- a/src/ap/wpa_auth_i.h
    -+++ b/src/ap/wpa_auth_i.h
    -@@ -65,6 +65,7 @@ struct wpa_state_machine {
    - 	struct wpa_ptk PTK;
    - 	Boolean PTK_valid;
    - 	Boolean pairwise_set;
    -+	Boolean tk_already_set;
    - 	int keycount;
    - 	Boolean Pair;
    - 	struct wpa_key_replay_counter {
    -@@ -230,20 +231,6 @@ int wpa_auth_for_each_auth(struct wpa_authenticator *wpa_auth,
    - 			   int (*cb)(struct wpa_authenticator *a, void *ctx),
    - 			   void *cb_ctx);
    - 
    --#ifdef CONFIG_PEERKEY
    --int wpa_stsl_remove(struct wpa_authenticator *wpa_auth,
    --		    struct wpa_stsl_negotiation *neg);
    --void wpa_smk_error(struct wpa_authenticator *wpa_auth,
    --		   struct wpa_state_machine *sm,
    --		   const u8 *key_data, size_t key_data_len);
    --void wpa_smk_m1(struct wpa_authenticator *wpa_auth,
    --		struct wpa_state_machine *sm, struct wpa_eapol_key *key,
    --		const u8 *key_data, size_t key_data_len);
    --void wpa_smk_m3(struct wpa_authenticator *wpa_auth,
    --		struct wpa_state_machine *sm, struct wpa_eapol_key *key,
    --		const u8 *key_data, size_t key_data_len);
    --#endif /* CONFIG_PEERKEY */
    --
    - #ifdef CONFIG_IEEE80211R
    - int wpa_write_mdie(struct wpa_auth_config *conf, u8 *buf, size_t len);
    - int wpa_write_ftie(struct wpa_auth_config *conf, const u8 *r0kh_id,
    -diff --git a/src/ap/wpa_auth_ie.c b/src/ap/wpa_auth_ie.c
    -index f79783b9..8f855b83 100644
    ---- a/src/ap/wpa_auth_ie.c
    -+++ b/src/ap/wpa_auth_ie.c
    -@@ -230,8 +230,6 @@ int wpa_write_rsn_ie(struct wpa_auth_config *conf, u8 *buf, size_t len,
    - 	capab = 0;
    - 	if (conf->rsn_preauth)
    - 		capab |= WPA_CAPABILITY_PREAUTH;
    --	if (conf->peerkey)
    --		capab |= WPA_CAPABILITY_PEERKEY_ENABLED;
    - 	if (conf->wmm_enabled) {
    - 		/* 4 PTKSA replay counters when using WMM */
    - 		capab |= (RSN_NUM_REPLAY_COUNTERS_16 << 2);
    -@@ -815,36 +813,6 @@ static int wpa_parse_generic(const u8 *pos, const u8 *end,
    - 		return 0;
    - 	}
    - 
    --#ifdef CONFIG_PEERKEY
    --	if (pos[1] > RSN_SELECTOR_LEN + 2 &&
    --	    RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_SMK) {
    --		ie->smk = pos + 2 + RSN_SELECTOR_LEN;
    --		ie->smk_len = pos[1] - RSN_SELECTOR_LEN;
    --		return 0;
    --	}
    --
    --	if (pos[1] > RSN_SELECTOR_LEN + 2 &&
    --	    RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_NONCE) {
    --		ie->nonce = pos + 2 + RSN_SELECTOR_LEN;
    --		ie->nonce_len = pos[1] - RSN_SELECTOR_LEN;
    --		return 0;
    --	}
    --
    --	if (pos[1] > RSN_SELECTOR_LEN + 2 &&
    --	    RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_LIFETIME) {
    --		ie->lifetime = pos + 2 + RSN_SELECTOR_LEN;
    --		ie->lifetime_len = pos[1] - RSN_SELECTOR_LEN;
    --		return 0;
    --	}
    --
    --	if (pos[1] > RSN_SELECTOR_LEN + 2 &&
    --	    RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_ERROR) {
    --		ie->error = pos + 2 + RSN_SELECTOR_LEN;
    --		ie->error_len = pos[1] - RSN_SELECTOR_LEN;
    --		return 0;
    --	}
    --#endif /* CONFIG_PEERKEY */
    --
    - #ifdef CONFIG_IEEE80211W
    - 	if (pos[1] > RSN_SELECTOR_LEN + 2 &&
    - 	    RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_IGTK) {
    -diff --git a/src/ap/wpa_auth_ie.h b/src/ap/wpa_auth_ie.h
    -index d2067ba3..0e2b3df3 100644
    ---- a/src/ap/wpa_auth_ie.h
    -+++ b/src/ap/wpa_auth_ie.h
    -@@ -19,16 +19,6 @@ struct wpa_eapol_ie_parse {
    - 	size_t gtk_len;
    - 	const u8 *mac_addr;
    - 	size_t mac_addr_len;
    --#ifdef CONFIG_PEERKEY
    --	const u8 *smk;
    --	size_t smk_len;
    --	const u8 *nonce;
    --	size_t nonce_len;
    --	const u8 *lifetime;
    --	size_t lifetime_len;
    --	const u8 *error;
    --	size_t error_len;
    --#endif /* CONFIG_PEERKEY */
    - #ifdef CONFIG_IEEE80211W
    - 	const u8 *igtk;
    - 	size_t igtk_len;
    -diff --git a/src/common/privsep_commands.h b/src/common/privsep_commands.h
    -index 8dff3038..15a1bfcd 100644
    ---- a/src/common/privsep_commands.h
    -+++ b/src/common/privsep_commands.h
    -@@ -84,7 +84,6 @@ enum privsep_event {
    - 	PRIVSEP_EVENT_MICHAEL_MIC_FAILURE,
    - 	PRIVSEP_EVENT_INTERFACE_STATUS,
    - 	PRIVSEP_EVENT_PMKID_CANDIDATE,
    --	PRIVSEP_EVENT_STKSTART,
    - 	PRIVSEP_EVENT_FT_RESPONSE,
    - 	PRIVSEP_EVENT_RX_EAPOL,
    - 	PRIVSEP_EVENT_SCAN_STARTED,
    -diff --git a/src/common/wpa_common.c b/src/common/wpa_common.c
    -index d6295b2d..41a49d0e 100644
    ---- a/src/common/wpa_common.c
    -+++ b/src/common/wpa_common.c
    -@@ -133,10 +133,6 @@ int wpa_eapol_key_mic(const u8 *key, size_t key_len, int akmp, int ver,
    -  * PTK = PRF-X(PMK, "Pairwise key expansion",
    -  *             Min(AA, SA) || Max(AA, SA) ||
    -  *             Min(ANonce, SNonce) || Max(ANonce, SNonce))
    -- *
    -- * STK = PRF-X(SMK, "Peer key expansion",
    -- *             Min(MAC_I, MAC_P) || Max(MAC_I, MAC_P) ||
    -- *             Min(INonce, PNonce) || Max(INonce, PNonce))
    -  */
    - int wpa_pmk_to_ptk(const u8 *pmk, size_t pmk_len, const char *label,
    - 		   const u8 *addr1, const u8 *addr2,
    -@@ -147,6 +143,11 @@ int wpa_pmk_to_ptk(const u8 *pmk, size_t pmk_len, const char *label,
    - 	u8 tmp[WPA_KCK_MAX_LEN + WPA_KEK_MAX_LEN + WPA_TK_MAX_LEN];
    - 	size_t ptk_len;
    - 
    -+	if (pmk_len == 0) {
    -+		wpa_printf(MSG_ERROR, "WPA: No PMK set for PT derivation");
    -+		return -1;
    -+	}
    -+
    - 	if (os_memcmp(addr1, addr2, ETH_ALEN) < 0) {
    - 		os_memcpy(data, addr1, ETH_ALEN);
    - 		os_memcpy(data + ETH_ALEN, addr2, ETH_ALEN);
    -diff --git a/src/common/wpa_common.h b/src/common/wpa_common.h
    -index af1d0f0c..642b28c3 100644
    ---- a/src/common/wpa_common.h
    -+++ b/src/common/wpa_common.h
    -@@ -88,12 +88,6 @@ RSN_SELECTOR(0x00, 0x0f, 0xac, 13)
    - #endif
    - #define RSN_KEY_DATA_MAC_ADDR RSN_SELECTOR(0x00, 0x0f, 0xac, 3)
    - #define RSN_KEY_DATA_PMKID RSN_SELECTOR(0x00, 0x0f, 0xac, 4)
    --#ifdef CONFIG_PEERKEY
    --#define RSN_KEY_DATA_SMK RSN_SELECTOR(0x00, 0x0f, 0xac, 5)
    --#define RSN_KEY_DATA_NONCE RSN_SELECTOR(0x00, 0x0f, 0xac, 6)
    --#define RSN_KEY_DATA_LIFETIME RSN_SELECTOR(0x00, 0x0f, 0xac, 7)
    --#define RSN_KEY_DATA_ERROR RSN_SELECTOR(0x00, 0x0f, 0xac, 8)
    --#endif /* CONFIG_PEERKEY */
    - #ifdef CONFIG_IEEE80211W
    - #define RSN_KEY_DATA_IGTK RSN_SELECTOR(0x00, 0x0f, 0xac, 9)
    - #endif /* CONFIG_IEEE80211W */
    -@@ -215,8 +209,20 @@ struct wpa_ptk {
    - 	size_t kck_len;
    - 	size_t kek_len;
    - 	size_t tk_len;
    -+	int installed; /* 1 if key has already been installed to driver */
    - };
    - 
    -+struct wpa_gtk {
    -+	u8 gtk[WPA_GTK_MAX_LEN];
    -+	size_t gtk_len;
    -+};
    -+
    -+#ifdef CONFIG_IEEE80211W
    -+struct wpa_igtk {
    -+	u8 igtk[WPA_IGTK_MAX_LEN];
    -+	size_t igtk_len;
    -+};
    -+#endif /* CONFIG_IEEE80211W */
    - 
    - /* WPA IE version 1
    -  * 00-50-f2:1 (OUI:OUI type)
    -@@ -271,22 +277,6 @@ struct rsn_ie_hdr {
    - } STRUCT_PACKED;
    - 
    - 
    --#ifdef CONFIG_PEERKEY
    --enum {
    --	STK_MUI_4WAY_STA_AP = 1,
    --	STK_MUI_4WAY_STAT_STA = 2,
    --	STK_MUI_GTK = 3,
    --	STK_MUI_SMK = 4
    --};
    --
    --enum {
    --	STK_ERR_STA_NR = 1,
    --	STK_ERR_STA_NRSN = 2,
    --	STK_ERR_CPHR_NS = 3,
    --	STK_ERR_NO_STSL = 4
    --};
    --#endif /* CONFIG_PEERKEY */
    --
    - struct rsn_error_kde {
    - 	be16 mui;
    - 	be16 error_type;
    -diff --git a/src/crypto/random.c b/src/crypto/random.c
    -index 3a86a93a..5d671bdc 100644
    ---- a/src/crypto/random.c
    -+++ b/src/crypto/random.c
    -@@ -160,10 +160,17 @@ int random_get_bytes(void *buf, size_t len)
    - 	wpa_printf(MSG_MSGDUMP, "Get randomness: len=%u entropy=%u",
    - 		   (unsigned int) len, entropy);
    - 
    -+#ifdef CONFIG_USE_OPENSSL_RNG
    -+	/* Start with assumed strong randomness from OpenSSL */
    -+	ret = crypto_get_random(buf, len);
    -+	wpa_hexdump_key(MSG_EXCESSIVE, "random from crypto_get_random",
    -+			buf, len);
    -+#else /* CONFIG_USE_OPENSSL_RNG */
    - 	/* Start with assumed strong randomness from OS */
    - 	ret = os_get_random(buf, len);
    - 	wpa_hexdump_key(MSG_EXCESSIVE, "random from os_get_random",
    - 			buf, len);
    -+#endif /* CONFIG_USE_OPENSSL_RNG */
    - 
    - 	/* Mix in additional entropy extracted from the internal pool */
    - 	left = len;
    -diff --git a/src/drivers/driver.h b/src/drivers/driver.h
    -index b7e0d163..bae47778 100644
    ---- a/src/drivers/driver.h
    -+++ b/src/drivers/driver.h
    -@@ -3647,17 +3647,6 @@ enum wpa_event_type {
    - 	 */
    - 	EVENT_PMKID_CANDIDATE,
    - 
    --	/**
    --	 * EVENT_STKSTART - Request STK handshake (MLME-STKSTART.request)
    --	 *
    --	 * This event can be used to inform wpa_supplicant about desire to set
    --	 * up secure direct link connection between two stations as defined in
    --	 * IEEE 802.11e with a new PeerKey mechanism that replaced the original
    --	 * STAKey negotiation. The caller will need to set peer address for the
    --	 * event.
    --	 */
    --	EVENT_STKSTART,
    --
    - 	/**
    - 	 * EVENT_TDLS - Request TDLS operation
    - 	 *
    -@@ -4297,13 +4286,6 @@ union wpa_event_data {
    - 		int preauth;
    - 	} pmkid_candidate;
    - 
    --	/**
    --	 * struct stkstart - Data for EVENT_STKSTART
    --	 */
    --	struct stkstart {
    --		u8 peer[ETH_ALEN];
    --	} stkstart;
    --
    - 	/**
    - 	 * struct tdls - Data for EVENT_TDLS
    - 	 */
    -diff --git a/src/drivers/driver_common.c b/src/drivers/driver_common.c
    -index b32d35f4..7c35277e 100644
    ---- a/src/drivers/driver_common.c
    -+++ b/src/drivers/driver_common.c
    -@@ -35,7 +35,6 @@ const char * event_to_string(enum wpa_event_type event)
    - 	E2S(ASSOCINFO);
    - 	E2S(INTERFACE_STATUS);
    - 	E2S(PMKID_CANDIDATE);
    --	E2S(STKSTART);
    - 	E2S(TDLS);
    - 	E2S(FT_RESPONSE);
    - 	E2S(IBSS_RSN_START);
    -diff --git a/src/drivers/driver_privsep.c b/src/drivers/driver_privsep.c
    -index 43d41937..6fd298d6 100644
    ---- a/src/drivers/driver_privsep.c
    -+++ b/src/drivers/driver_privsep.c
    -@@ -464,19 +464,6 @@ static void wpa_driver_privsep_event_pmkid_candidate(void *ctx, u8 *buf,
    - }
    - 
    - 
    --static void wpa_driver_privsep_event_stkstart(void *ctx, u8 *buf, size_t len)
    --{
    --	union wpa_event_data data;
    --
    --	if (len != ETH_ALEN)
    --		return;
    --
    --	os_memset(&data, 0, sizeof(data));
    --	os_memcpy(data.stkstart.peer, buf, ETH_ALEN);
    --	wpa_supplicant_event(ctx, EVENT_STKSTART, &data);
    --}
    --
    --
    - static void wpa_driver_privsep_event_ft_response(void *ctx, u8 *buf,
    - 						 size_t len)
    - {
    -@@ -570,10 +557,6 @@ static void wpa_driver_privsep_receive(int sock, void *eloop_ctx,
    - 		wpa_driver_privsep_event_pmkid_candidate(drv->ctx, event_buf,
    - 							 event_len);
    - 		break;
    --	case PRIVSEP_EVENT_STKSTART:
    --		wpa_driver_privsep_event_stkstart(drv->ctx, event_buf,
    --						  event_len);
    --		break;
    - 	case PRIVSEP_EVENT_FT_RESPONSE:
    - 		wpa_driver_privsep_event_ft_response(drv->ctx, event_buf,
    - 						     event_len);
    -diff --git a/src/drivers/driver_wext.c b/src/drivers/driver_wext.c
    -index 791cd5d4..e149ed2d 100644
    ---- a/src/drivers/driver_wext.c
    -+++ b/src/drivers/driver_wext.c
    -@@ -290,15 +290,6 @@ wpa_driver_wext_event_wireless_custom(void *ctx, char *custom)
    - 	done:
    - 		os_free(resp_ies);
    - 		os_free(req_ies);
    --#ifdef CONFIG_PEERKEY
    --	} else if (os_strncmp(custom, "STKSTART.request=", 17) == 0) {
    --		if (hwaddr_aton(custom + 17, data.stkstart.peer)) {
    --			wpa_printf(MSG_DEBUG, "WEXT: unrecognized "
    --				   "STKSTART.request '%s'", custom + 17);
    --			return;
    --		}
    --		wpa_supplicant_event(ctx, EVENT_STKSTART, &data);
    --#endif /* CONFIG_PEERKEY */
    - 	}
    - }
    - 
    -@@ -472,7 +463,7 @@ static void wpa_driver_wext_event_wireless(struct wpa_driver_wext_data *drv,
    - 				drv->assoc_resp_ies = NULL;
    - 				wpa_supplicant_event(drv->ctx, EVENT_DISASSOC,
    - 						     NULL);
    --			
    -+
    - 			} else {
    - 				wpa_driver_wext_event_assoc_ies(drv);
    - 				wpa_supplicant_event(drv->ctx, EVENT_ASSOC,
    -diff --git a/src/rsn_supp/Makefile b/src/rsn_supp/Makefile
    -index d5e61fe7..c2d81f27 100644
    ---- a/src/rsn_supp/Makefile
    -+++ b/src/rsn_supp/Makefile
    -@@ -10,7 +10,6 @@ include ../lib.rules
    - 
    - CFLAGS += -DCONFIG_IEEE80211W
    - CFLAGS += -DCONFIG_IEEE80211R
    --CFLAGS += -DCONFIG_PEERKEY
    - CFLAGS += -DCONFIG_TDLS
    - CFLAGS += -DCONFIG_WNM
    - CFLAGS += -DIEEE8021X_EAPOL
    -@@ -18,7 +17,6 @@ CFLAGS += -DIEEE8021X_EAPOL
    - LIB_OBJS= \
    - 	pmksa_cache.o \
    - 	wpa_ft.o \
    --	peerkey.o \
    - 	tdls.o \
    - 	preauth.o \
    - 	wpa.o \
    -diff --git a/src/rsn_supp/peerkey.c b/src/rsn_supp/peerkey.c
    -deleted file mode 100644
    -index 79764d94..00000000
    ---- a/src/rsn_supp/peerkey.c
    -+++ /dev/null
    -@@ -1,1155 +0,0 @@
    --/*
    -- * WPA Supplicant - PeerKey for Direct Link Setup (DLS)
    -- * Copyright (c) 2006-2015, Jouni Malinen <j@w1.fi>
    -- *
    -- * This software may be distributed under the terms of the BSD license.
    -- * See README for more details.
    -- */
    --
    --#include "includes.h"
    --
    --#ifdef CONFIG_PEERKEY
    --
    --#include "common.h"
    --#include "eloop.h"
    --#include "crypto/sha1.h"
    --#include "crypto/sha256.h"
    --#include "crypto/random.h"
    --#include "common/ieee802_11_defs.h"
    --#include "wpa.h"
    --#include "wpa_i.h"
    --#include "wpa_ie.h"
    --#include "peerkey.h"
    --
    --
    --static u8 * wpa_add_ie(u8 *pos, const u8 *ie, size_t ie_len)
    --{
    --	os_memcpy(pos, ie, ie_len);
    --	return pos + ie_len;
    --}
    --
    --
    --static u8 * wpa_add_kde(u8 *pos, u32 kde, const u8 *data, size_t data_len)
    --{
    --	*pos++ = WLAN_EID_VENDOR_SPECIFIC;
    --	*pos++ = RSN_SELECTOR_LEN + data_len;
    --	RSN_SELECTOR_PUT(pos, kde);
    --	pos += RSN_SELECTOR_LEN;
    --	os_memcpy(pos, data, data_len);
    --	pos += data_len;
    --	return pos;
    --}
    --
    --
    --static void wpa_supplicant_smk_timeout(void *eloop_ctx, void *timeout_ctx)
    --{
    --#if 0
    --	struct wpa_sm *sm = eloop_ctx;
    --	struct wpa_peerkey *peerkey = timeout_ctx;
    --#endif
    --	/* TODO: time out SMK and any STK that was generated using this SMK */
    --}
    --
    --
    --static void wpa_supplicant_peerkey_free(struct wpa_sm *sm,
    --					struct wpa_peerkey *peerkey)
    --{
    --	eloop_cancel_timeout(wpa_supplicant_smk_timeout, sm, peerkey);
    --	os_free(peerkey);
    --}
    --
    --
    --static int wpa_supplicant_send_smk_error(struct wpa_sm *sm, const u8 *dst,
    --					 const u8 *peer,
    --					 u16 mui, u16 error_type, int ver)
    --{
    --	size_t rlen;
    --	struct wpa_eapol_key *err;
    --	struct wpa_eapol_key_192 *err192;
    --	struct rsn_error_kde error;
    --	u8 *rbuf, *pos;
    --	size_t kde_len;
    --	u16 key_info;
    --
    --	kde_len = 2 + RSN_SELECTOR_LEN + sizeof(error);
    --	if (peer)
    --		kde_len += 2 + RSN_SELECTOR_LEN + ETH_ALEN;
    --
    --	rbuf = wpa_sm_alloc_eapol(sm, IEEE802_1X_TYPE_EAPOL_KEY,
    --				  NULL, sizeof(*err) + kde_len, &rlen,
    --				  (void *) &err);
    --	if (rbuf == NULL)
    --		return -1;
    --	err192 = (struct wpa_eapol_key_192 *) err;
    --
    --	err->type = EAPOL_KEY_TYPE_RSN;
    --	key_info = ver | WPA_KEY_INFO_SMK_MESSAGE | WPA_KEY_INFO_MIC |
    --		WPA_KEY_INFO_SECURE | WPA_KEY_INFO_ERROR |
    --		WPA_KEY_INFO_REQUEST;
    --	WPA_PUT_BE16(err->key_info, key_info);
    --	WPA_PUT_BE16(err->key_length, 0);
    --	os_memcpy(err->replay_counter, sm->request_counter,
    --		  WPA_REPLAY_COUNTER_LEN);
    --	inc_byte_array(sm->request_counter, WPA_REPLAY_COUNTER_LEN);
    --
    --	WPA_PUT_BE16(err->key_data_length, (u16) kde_len);
    --	pos = (u8 *) (err + 1);
    --
    --	if (peer) {
    --		/* Peer MAC Address KDE */
    --		pos = wpa_add_kde(pos, RSN_KEY_DATA_MAC_ADDR, peer, ETH_ALEN);
    --	}
    --
    --	/* Error KDE */
    --	error.mui = host_to_be16(mui);
    --	error.error_type = host_to_be16(error_type);
    --	wpa_add_kde(pos, RSN_KEY_DATA_ERROR, (u8 *) &error, sizeof(error));
    --
    --	if (peer) {
    --		wpa_printf(MSG_DEBUG, "RSN: Sending EAPOL-Key SMK Error (peer "
    --			   MACSTR " mui %d error_type %d)",
    --			   MAC2STR(peer), mui, error_type);
    --	} else {
    --		wpa_printf(MSG_DEBUG, "RSN: Sending EAPOL-Key SMK Error "
    --			   "(mui %d error_type %d)", mui, error_type);
    --	}
    --
    --	wpa_eapol_key_send(sm, sm->ptk.kck, sm->ptk.kck_len, ver, dst,
    --			   ETH_P_EAPOL, rbuf, rlen, err192->key_mic);
    --
    --	return 0;
    --}
    --
    --
    --static int wpa_supplicant_send_smk_m3(struct wpa_sm *sm,
    --				      const unsigned char *src_addr,
    --				      const struct wpa_eapol_key *key,
    --				      int ver, struct wpa_peerkey *peerkey)
    --{
    --	size_t rlen;
    --	struct wpa_eapol_key *reply;
    --	struct wpa_eapol_key_192 *reply192;
    --	u8 *rbuf, *pos;
    --	size_t kde_len;
    --	u16 key_info;
    --
    --	/* KDEs: Peer RSN IE, Initiator MAC Address, Initiator Nonce */
    --	kde_len = peerkey->rsnie_p_len +
    --		2 + RSN_SELECTOR_LEN + ETH_ALEN +
    --		2 + RSN_SELECTOR_LEN + WPA_NONCE_LEN;
    --
    --	rbuf = wpa_sm_alloc_eapol(sm, IEEE802_1X_TYPE_EAPOL_KEY,
    --				  NULL, sizeof(*reply) + kde_len, &rlen,
    --				  (void *) &reply);
    --	if (rbuf == NULL)
    --		return -1;
    --	reply192 = (struct wpa_eapol_key_192 *) reply;
    --
    --	reply->type = EAPOL_KEY_TYPE_RSN;
    --	key_info = ver | WPA_KEY_INFO_SMK_MESSAGE | WPA_KEY_INFO_MIC |
    --		WPA_KEY_INFO_SECURE;
    --	WPA_PUT_BE16(reply->key_info, key_info);
    --	WPA_PUT_BE16(reply->key_length, 0);
    --	os_memcpy(reply->replay_counter, key->replay_counter,
    --		  WPA_REPLAY_COUNTER_LEN);
    --
    --	os_memcpy(reply->key_nonce, peerkey->pnonce, WPA_NONCE_LEN);
    --
    --	WPA_PUT_BE16(reply->key_data_length, (u16) kde_len);
    --	pos = (u8 *) (reply + 1);
    --
    --	/* Peer RSN IE */
    --	pos = wpa_add_ie(pos, peerkey->rsnie_p, peerkey->rsnie_p_len);
    --
    --	/* Initiator MAC Address KDE */
    --	pos = wpa_add_kde(pos, RSN_KEY_DATA_MAC_ADDR, peerkey->addr, ETH_ALEN);
    --
    --	/* Initiator Nonce */
    --	wpa_add_kde(pos, RSN_KEY_DATA_NONCE, peerkey->inonce, WPA_NONCE_LEN);
    --
    --	wpa_printf(MSG_DEBUG, "RSN: Sending EAPOL-Key SMK M3");
    --	wpa_eapol_key_send(sm, sm->ptk.kck, sm->ptk.kck_len, ver, src_addr,
    --			   ETH_P_EAPOL, rbuf, rlen, reply192->key_mic);
    --
    --	return 0;
    --}
    --
    --
    --static int wpa_supplicant_process_smk_m2(
    --	struct wpa_sm *sm, const unsigned char *src_addr,
    --	const struct wpa_eapol_key *key, size_t extra_len, int ver)
    --{
    --	struct wpa_peerkey *peerkey;
    --	struct wpa_eapol_ie_parse kde;
    --	struct wpa_ie_data ie;
    --	int cipher;
    --	struct rsn_ie_hdr *hdr;
    --	u8 *pos;
    --
    --	wpa_printf(MSG_DEBUG, "RSN: Received SMK M2");
    --
    --	if (!sm->peerkey_enabled || sm->proto != WPA_PROTO_RSN) {
    --		wpa_printf(MSG_INFO, "RSN: SMK handshake not allowed for "
    --			   "the current network");
    --		return -1;
    --	}
    --
    --	if (wpa_supplicant_parse_ies((const u8 *) (key + 1), extra_len, &kde) <
    --	    0) {
    --		wpa_printf(MSG_INFO, "RSN: Failed to parse KDEs in SMK M2");
    --		return -1;
    --	}
    --
    --	if (kde.rsn_ie == NULL || kde.mac_addr == NULL ||
    --	    kde.mac_addr_len < ETH_ALEN) {
    --		wpa_printf(MSG_INFO, "RSN: No RSN IE or MAC address KDE in "
    --			   "SMK M2");
    --		return -1;
    --	}
    --
    --	wpa_printf(MSG_DEBUG, "RSN: SMK M2 - SMK initiator " MACSTR,
    --		   MAC2STR(kde.mac_addr));
    --
    --	if (kde.rsn_ie_len > PEERKEY_MAX_IE_LEN) {
    --		wpa_printf(MSG_INFO, "RSN: Too long Initiator RSN IE in SMK "
    --			   "M2");
    --		return -1;
    --	}
    --
    --	if (wpa_parse_wpa_ie_rsn(kde.rsn_ie, kde.rsn_ie_len, &ie) < 0) {
    --		wpa_printf(MSG_INFO, "RSN: Failed to parse RSN IE in SMK M2");
    --		return -1;
    --	}
    --
    --	cipher = wpa_pick_pairwise_cipher(ie.pairwise_cipher &
    --					  sm->allowed_pairwise_cipher, 0);
    --	if (cipher < 0) {
    --		wpa_printf(MSG_INFO, "RSN: No acceptable cipher in SMK M2");
    --		wpa_supplicant_send_smk_error(sm, src_addr, kde.mac_addr,
    --					      STK_MUI_SMK, STK_ERR_CPHR_NS,
    --					      ver);
    --		return -1;
    --	}
    --	wpa_printf(MSG_DEBUG, "RSN: Using %s for PeerKey",
    --		   wpa_cipher_txt(cipher));
    --
    --	/* TODO: find existing entry and if found, use that instead of adding
    --	 * a new one; how to handle the case where both ends initiate at the
    --	 * same time? */
    --	peerkey = os_zalloc(sizeof(*peerkey));
    --	if (peerkey == NULL)
    --		return -1;
    --	os_memcpy(peerkey->addr, kde.mac_addr, ETH_ALEN);
    --	os_memcpy(peerkey->inonce, key->key_nonce, WPA_NONCE_LEN);
    --	os_memcpy(peerkey->rsnie_i, kde.rsn_ie, kde.rsn_ie_len);
    --	peerkey->rsnie_i_len = kde.rsn_ie_len;
    --	peerkey->cipher = cipher;
    --	peerkey->akmp = ie.key_mgmt;
    --
    --	if (random_get_bytes(peerkey->pnonce, WPA_NONCE_LEN)) {
    --		wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
    --			"WPA: Failed to get random data for PNonce");
    --		wpa_supplicant_peerkey_free(sm, peerkey);
    --		return -1;
    --	}
    --
    --	hdr = (struct rsn_ie_hdr *) peerkey->rsnie_p;
    --	hdr->elem_id = WLAN_EID_RSN;
    --	WPA_PUT_LE16(hdr->version, RSN_VERSION);
    --	pos = (u8 *) (hdr + 1);
    --	/* Group Suite can be anything for SMK RSN IE; receiver will just
    --	 * ignore it. */
    --	RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_CCMP);
    --	pos += RSN_SELECTOR_LEN;
    --	/* Include only the selected cipher in pairwise cipher suite */
    --	WPA_PUT_LE16(pos, 1);
    --	pos += 2;
    --	RSN_SELECTOR_PUT(pos, wpa_cipher_to_suite(WPA_PROTO_RSN, cipher));
    --	pos += RSN_SELECTOR_LEN;
    --
    --	hdr->len = (pos - peerkey->rsnie_p) - 2;
    --	peerkey->rsnie_p_len = pos - peerkey->rsnie_p;
    --	wpa_hexdump(MSG_DEBUG, "WPA: RSN IE for SMK handshake",
    --		    peerkey->rsnie_p, peerkey->rsnie_p_len);
    --
    --	wpa_supplicant_send_smk_m3(sm, src_addr, key, ver, peerkey);
    --
    --	peerkey->next = sm->peerkey;
    --	sm->peerkey = peerkey;
    --
    --	return 0;
    --}
    --
    --
    --/**
    -- * rsn_smkid - Derive SMK identifier
    -- * @smk: Station master key (32 bytes)
    -- * @pnonce: Peer Nonce
    -- * @mac_p: Peer MAC address
    -- * @inonce: Initiator Nonce
    -- * @mac_i: Initiator MAC address
    -- * @akmp: Negotiated AKM
    -- *
    -- * 8.5.1.4 Station to station (STK) key hierarchy
    -- * SMKID = HMAC-SHA1-128(SMK, "SMK Name" || PNonce || MAC_P || INonce || MAC_I)
    -- */
    --static void rsn_smkid(const u8 *smk, const u8 *pnonce, const u8 *mac_p,
    --		      const u8 *inonce, const u8 *mac_i, u8 *smkid,
    --		      int akmp)
    --{
    --	char *title = "SMK Name";
    --	const u8 *addr[5];
    --	const size_t len[5] = { 8, WPA_NONCE_LEN, ETH_ALEN, WPA_NONCE_LEN,
    --				ETH_ALEN };
    --	unsigned char hash[SHA256_MAC_LEN];
    --
    --	addr[0] = (u8 *) title;
    --	addr[1] = pnonce;
    --	addr[2] = mac_p;
    --	addr[3] = inonce;
    --	addr[4] = mac_i;
    --
    --#ifdef CONFIG_IEEE80211W
    --	if (wpa_key_mgmt_sha256(akmp))
    --		hmac_sha256_vector(smk, PMK_LEN, 5, addr, len, hash);
    --	else
    --#endif /* CONFIG_IEEE80211W */
    --		hmac_sha1_vector(smk, PMK_LEN, 5, addr, len, hash);
    --	os_memcpy(smkid, hash, PMKID_LEN);
    --}
    --
    --
    --static void wpa_supplicant_send_stk_1_of_4(struct wpa_sm *sm,
    --					   struct wpa_peerkey *peerkey)
    --{
    --	size_t mlen;
    --	struct wpa_eapol_key *msg;
    --	u8 *mbuf;
    --	size_t kde_len;
    --	u16 key_info, ver;
    --
    --	kde_len = 2 + RSN_SELECTOR_LEN + PMKID_LEN;
    --
    --	mbuf = wpa_sm_alloc_eapol(sm, IEEE802_1X_TYPE_EAPOL_KEY, NULL,
    --				  sizeof(*msg) + kde_len, &mlen,
    --				  (void *) &msg);
    --	if (mbuf == NULL)
    --		return;
    --
    --	msg->type = EAPOL_KEY_TYPE_RSN;
    --
    --	if (peerkey->cipher != WPA_CIPHER_TKIP)
    --		ver = WPA_KEY_INFO_TYPE_HMAC_SHA1_AES;
    --	else
    --		ver = WPA_KEY_INFO_TYPE_HMAC_MD5_RC4;
    --
    --	key_info = ver | WPA_KEY_INFO_KEY_TYPE | WPA_KEY_INFO_ACK;
    --	WPA_PUT_BE16(msg->key_info, key_info);
    --
    --	if (peerkey->cipher != WPA_CIPHER_TKIP)
    --		WPA_PUT_BE16(msg->key_length, 16);
    --	else
    --		WPA_PUT_BE16(msg->key_length, 32);
    --
    --	os_memcpy(msg->replay_counter, peerkey->replay_counter,
    --		  WPA_REPLAY_COUNTER_LEN);
    --	inc_byte_array(peerkey->replay_counter, WPA_REPLAY_COUNTER_LEN);
    --
    --	WPA_PUT_BE16(msg->key_data_length, kde_len);
    --	wpa_add_kde((u8 *) (msg + 1), RSN_KEY_DATA_PMKID,
    --		    peerkey->smkid, PMKID_LEN);
    --
    --	if (random_get_bytes(peerkey->inonce, WPA_NONCE_LEN)) {
    --		wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
    --			"RSN: Failed to get random data for INonce (STK)");
    --		os_free(mbuf);
    --		return;
    --	}
    --	wpa_hexdump(MSG_DEBUG, "RSN: INonce for STK 4-Way Handshake",
    --		    peerkey->inonce, WPA_NONCE_LEN);
    --	os_memcpy(msg->key_nonce, peerkey->inonce, WPA_NONCE_LEN);
    --
    --	wpa_printf(MSG_DEBUG, "RSN: Sending EAPOL-Key STK 1/4 to " MACSTR,
    --		   MAC2STR(peerkey->addr));
    --	wpa_eapol_key_send(sm, NULL, 0, ver, peerkey->addr, ETH_P_EAPOL,
    --			   mbuf, mlen, NULL);
    --}
    --
    --
    --static void wpa_supplicant_send_stk_3_of_4(struct wpa_sm *sm,
    --					   struct wpa_peerkey *peerkey)
    --{
    --	size_t mlen;
    --	struct wpa_eapol_key *msg;
    --	u8 *mbuf, *pos;
    --	size_t kde_len;
    --	u16 key_info, ver;
    --	be32 lifetime;
    --
    --	kde_len = peerkey->rsnie_i_len +
    --		2 + RSN_SELECTOR_LEN + sizeof(lifetime);
    --
    --	mbuf = wpa_sm_alloc_eapol(sm, IEEE802_1X_TYPE_EAPOL_KEY, NULL,
    --				  sizeof(*msg) + kde_len, &mlen,
    --				  (void *) &msg);
    --	if (mbuf == NULL)
    --		return;
    --
    --	msg->type = EAPOL_KEY_TYPE_RSN;
    --
    --	if (peerkey->cipher != WPA_CIPHER_TKIP)
    --		ver = WPA_KEY_INFO_TYPE_HMAC_SHA1_AES;
    --	else
    --		ver = WPA_KEY_INFO_TYPE_HMAC_MD5_RC4;
    --
    --	key_info = ver | WPA_KEY_INFO_KEY_TYPE | WPA_KEY_INFO_ACK |
    --		WPA_KEY_INFO_MIC | WPA_KEY_INFO_SECURE;
    --	WPA_PUT_BE16(msg->key_info, key_info);
    --
    --	if (peerkey->cipher != WPA_CIPHER_TKIP)
    --		WPA_PUT_BE16(msg->key_length, 16);
    --	else
    --		WPA_PUT_BE16(msg->key_length, 32);
    --
    --	os_memcpy(msg->replay_counter, peerkey->replay_counter,
    --		  WPA_REPLAY_COUNTER_LEN);
    --	inc_byte_array(peerkey->replay_counter, WPA_REPLAY_COUNTER_LEN);
    --
    --	WPA_PUT_BE16(msg->key_data_length, kde_len);
    --	pos = (u8 *) (msg + 1);
    --	pos = wpa_add_ie(pos, peerkey->rsnie_i, peerkey->rsnie_i_len);
    --	lifetime = host_to_be32(peerkey->lifetime);
    --	wpa_add_kde(pos, RSN_KEY_DATA_LIFETIME,
    --		    (u8 *) &lifetime, sizeof(lifetime));
    --
    --	os_memcpy(msg->key_nonce, peerkey->inonce, WPA_NONCE_LEN);
    --
    --	wpa_printf(MSG_DEBUG, "RSN: Sending EAPOL-Key STK 3/4 to " MACSTR,
    --		   MAC2STR(peerkey->addr));
    --	wpa_eapol_key_send(sm, peerkey->stk.kck, peerkey->stk.kck_len, ver,
    --			   peerkey->addr, ETH_P_EAPOL, mbuf, mlen,
    --			   msg->key_mic);
    --}
    --
    --
    --static int wpa_supplicant_process_smk_m4(struct wpa_peerkey *peerkey,
    --					 struct wpa_eapol_ie_parse *kde)
    --{
    --	wpa_printf(MSG_DEBUG, "RSN: Received SMK M4 (Initiator " MACSTR ")",
    --		   MAC2STR(kde->mac_addr));
    --
    --	if (os_memcmp(kde->smk + PMK_LEN, peerkey->pnonce, WPA_NONCE_LEN) != 0)
    --	{
    --		wpa_printf(MSG_INFO, "RSN: PNonce in SMK KDE does not "
    --			   "match with the one used in SMK M3");
    --		return -1;
    --	}
    --
    --	if (os_memcmp(kde->nonce, peerkey->inonce, WPA_NONCE_LEN) != 0) {
    --		wpa_printf(MSG_INFO, "RSN: INonce in SMK M4 did not "
    --			   "match with the one received in SMK M2");
    --		return -1;
    --	}
    --
    --	return 0;
    --}
    --
    --
    --static int wpa_supplicant_process_smk_m5(struct wpa_sm *sm,
    --					 const unsigned char *src_addr,
    --					 const struct wpa_eapol_key *key,
    --					 int ver,
    --					 struct wpa_peerkey *peerkey,
    --					 struct wpa_eapol_ie_parse *kde)
    --{
    --	int cipher;
    --	struct wpa_ie_data ie;
    --
    --	wpa_printf(MSG_DEBUG, "RSN: Received SMK M5 (Peer " MACSTR ")",
    --		   MAC2STR(kde->mac_addr));
    --	if (kde->rsn_ie == NULL || kde->rsn_ie_len > PEERKEY_MAX_IE_LEN ||
    --	    wpa_parse_wpa_ie_rsn(kde->rsn_ie, kde->rsn_ie_len, &ie) < 0) {
    --		wpa_printf(MSG_INFO, "RSN: No RSN IE in SMK M5");
    --		/* TODO: abort negotiation */
    --		return -1;
    --	}
    --
    --	if (os_memcmp(key->key_nonce, peerkey->inonce, WPA_NONCE_LEN) != 0) {
    --		wpa_printf(MSG_INFO, "RSN: Key Nonce in SMK M5 does "
    --			   "not match with INonce used in SMK M1");
    --		return -1;
    --	}
    --
    --	if (os_memcmp(kde->smk + PMK_LEN, peerkey->inonce, WPA_NONCE_LEN) != 0)
    --	{
    --		wpa_printf(MSG_INFO, "RSN: INonce in SMK KDE does not "
    --			   "match with the one used in SMK M1");
    --		return -1;
    --	}
    --
    --	os_memcpy(peerkey->rsnie_p, kde->rsn_ie, kde->rsn_ie_len);
    --	peerkey->rsnie_p_len = kde->rsn_ie_len;
    --	os_memcpy(peerkey->pnonce, kde->nonce, WPA_NONCE_LEN);
    --
    --	cipher = wpa_pick_pairwise_cipher(ie.pairwise_cipher &
    --					  sm->allowed_pairwise_cipher, 0);
    --	if (cipher < 0) {
    --		wpa_printf(MSG_INFO, "RSN: SMK Peer STA " MACSTR " selected "
    --			   "unacceptable cipher", MAC2STR(kde->mac_addr));
    --		wpa_supplicant_send_smk_error(sm, src_addr, kde->mac_addr,
    --					      STK_MUI_SMK, STK_ERR_CPHR_NS,
    --					      ver);
    --		/* TODO: abort negotiation */
    --		return -1;
    --	}
    --	wpa_printf(MSG_DEBUG, "RSN: Using %s for PeerKey",
    --		   wpa_cipher_txt(cipher));
    --	peerkey->cipher = cipher;
    --
    --	return 0;
    --}
    --
    --
    --static int wpa_supplicant_process_smk_m45(
    --	struct wpa_sm *sm, const unsigned char *src_addr,
    --	const struct wpa_eapol_key *key, size_t extra_len, int ver)
    --{
    --	struct wpa_peerkey *peerkey;
    --	struct wpa_eapol_ie_parse kde;
    --	u32 lifetime;
    --
    --	if (!sm->peerkey_enabled || sm->proto != WPA_PROTO_RSN) {
    --		wpa_printf(MSG_DEBUG, "RSN: SMK handshake not allowed for "
    --			   "the current network");
    --		return -1;
    --	}
    --
    --	if (wpa_supplicant_parse_ies((const u8 *) (key + 1), extra_len, &kde) <
    --	    0) {
    --		wpa_printf(MSG_INFO, "RSN: Failed to parse KDEs in SMK M4/M5");
    --		return -1;
    --	}
    --
    --	if (kde.mac_addr == NULL || kde.mac_addr_len < ETH_ALEN ||
    --	    kde.nonce == NULL || kde.nonce_len < WPA_NONCE_LEN ||
    --	    kde.smk == NULL || kde.smk_len < PMK_LEN + WPA_NONCE_LEN ||
    --	    kde.lifetime == NULL || kde.lifetime_len < 4) {
    --		wpa_printf(MSG_INFO, "RSN: No MAC Address, Nonce, SMK, or "
    --			   "Lifetime KDE in SMK M4/M5");
    --		return -1;
    --	}
    --
    --	for (peerkey = sm->peerkey; peerkey; peerkey = peerkey->next) {
    --		if (os_memcmp(peerkey->addr, kde.mac_addr, ETH_ALEN) == 0 &&
    --		    os_memcmp(peerkey->initiator ? peerkey->inonce :
    --			   peerkey->pnonce,
    --			   key->key_nonce, WPA_NONCE_LEN) == 0)
    --			break;
    --	}
    --	if (peerkey == NULL) {
    --		wpa_printf(MSG_INFO, "RSN: No matching SMK handshake found "
    --			   "for SMK M4/M5: peer " MACSTR,
    --			   MAC2STR(kde.mac_addr));
    --		return -1;
    --	}
    --
    --	if (peerkey->initiator) {
    --		if (wpa_supplicant_process_smk_m5(sm, src_addr, key, ver,
    --						  peerkey, &kde) < 0)
    --			return -1;
    --	} else {
    --		if (wpa_supplicant_process_smk_m4(peerkey, &kde) < 0)
    --			return -1;
    --	}
    --
    --	os_memcpy(peerkey->smk, kde.smk, PMK_LEN);
    --	peerkey->smk_complete = 1;
    --	wpa_hexdump_key(MSG_DEBUG, "RSN: SMK", peerkey->smk, PMK_LEN);
    --	lifetime = WPA_GET_BE32(kde.lifetime);
    --	wpa_printf(MSG_DEBUG, "RSN: SMK lifetime %u seconds", lifetime);
    --	if (lifetime > 1000000000)
    --		lifetime = 1000000000; /* avoid overflowing eloop time */
    --	peerkey->lifetime = lifetime;
    --	eloop_register_timeout(lifetime, 0, wpa_supplicant_smk_timeout,
    --			       sm, peerkey);
    --
    --	if (peerkey->initiator) {
    --		rsn_smkid(peerkey->smk, peerkey->pnonce, peerkey->addr,
    --			  peerkey->inonce, sm->own_addr, peerkey->smkid,
    --			  peerkey->akmp);
    --		wpa_supplicant_send_stk_1_of_4(sm, peerkey);
    --	} else {
    --		rsn_smkid(peerkey->smk, peerkey->pnonce, sm->own_addr,
    --			  peerkey->inonce, peerkey->addr, peerkey->smkid,
    --			  peerkey->akmp);
    --	}
    --	wpa_hexdump(MSG_DEBUG, "RSN: SMKID", peerkey->smkid, PMKID_LEN);
    --
    --	return 0;
    --}
    --
    --
    --static int wpa_supplicant_process_smk_error(
    --	struct wpa_sm *sm, const unsigned char *src_addr,
    --	const struct wpa_eapol_key *key, size_t extra_len)
    --{
    --	struct wpa_eapol_ie_parse kde;
    --	struct rsn_error_kde error;
    --	u8 peer[ETH_ALEN];
    --	u16 error_type;
    --
    --	wpa_printf(MSG_DEBUG, "RSN: Received SMK Error");
    --
    --	if (!sm->peerkey_enabled || sm->proto != WPA_PROTO_RSN) {
    --		wpa_printf(MSG_DEBUG, "RSN: SMK handshake not allowed for "
    --			   "the current network");
    --		return -1;
    --	}
    --
    --	if (wpa_supplicant_parse_ies((const u8 *) (key + 1), extra_len, &kde) <
    --	    0) {
    --		wpa_printf(MSG_INFO, "RSN: Failed to parse KDEs in SMK Error");
    --		return -1;
    --	}
    --
    --	if (kde.error == NULL || kde.error_len < sizeof(error)) {
    --		wpa_printf(MSG_INFO, "RSN: No Error KDE in SMK Error");
    --		return -1;
    --	}
    --
    --	if (kde.mac_addr && kde.mac_addr_len >= ETH_ALEN)
    --		os_memcpy(peer, kde.mac_addr, ETH_ALEN);
    --	else
    --		os_memset(peer, 0, ETH_ALEN);
    --	os_memcpy(&error, kde.error, sizeof(error));
    --	error_type = be_to_host16(error.error_type);
    --	wpa_msg(sm->ctx->msg_ctx, MSG_INFO,
    --		"RSN: SMK Error KDE received: MUI %d error_type %d peer "
    --		MACSTR,
    --		be_to_host16(error.mui), error_type,
    --		MAC2STR(peer));
    --
    --	if (kde.mac_addr &&
    --	    (error_type == STK_ERR_STA_NR || error_type == STK_ERR_STA_NRSN ||
    --	     error_type == STK_ERR_CPHR_NS)) {
    --		struct wpa_peerkey *peerkey;
    --
    --		for (peerkey = sm->peerkey; peerkey; peerkey = peerkey->next) {
    --			if (os_memcmp(peerkey->addr, kde.mac_addr, ETH_ALEN) ==
    --			    0)
    --				break;
    --		}
    --		if (peerkey == NULL) {
    --			wpa_printf(MSG_DEBUG, "RSN: No matching SMK handshake "
    --				   "found for SMK Error");
    --			return -1;
    --		}
    --		/* TODO: abort SMK/STK handshake and remove all related keys */
    --	}
    --
    --	return 0;
    --}
    --
    --
    --static void wpa_supplicant_process_stk_1_of_4(struct wpa_sm *sm,
    --					      struct wpa_peerkey *peerkey,
    --					      const struct wpa_eapol_key *key,
    --					      u16 ver, const u8 *key_data,
    --					      size_t key_data_len)
    --{
    --	struct wpa_eapol_ie_parse ie;
    --	size_t kde_buf_len;
    --	struct wpa_ptk *stk;
    --	u8 buf[8], *kde_buf, *pos;
    --	be32 lifetime;
    --
    --	wpa_printf(MSG_DEBUG, "RSN: RX message 1 of STK 4-Way Handshake from "
    --		   MACSTR " (ver=%d)", MAC2STR(peerkey->addr), ver);
    --
    --	os_memset(&ie, 0, sizeof(ie));
    --
    --	/* RSN: msg 1/4 should contain SMKID for the selected SMK */
    --	wpa_hexdump(MSG_DEBUG, "RSN: msg 1/4 key data", key_data, key_data_len);
    --	if (wpa_supplicant_parse_ies(key_data, key_data_len, &ie) < 0 ||
    --	    ie.pmkid == NULL) {
    --		wpa_printf(MSG_DEBUG, "RSN: No SMKID in STK 1/4");
    --		return;
    --	}
    --	if (os_memcmp_const(ie.pmkid, peerkey->smkid, PMKID_LEN) != 0) {
    --		wpa_hexdump(MSG_DEBUG, "RSN: Unknown SMKID in STK 1/4",
    --			    ie.pmkid, PMKID_LEN);
    --		return;
    --	}
    --
    --	if (random_get_bytes(peerkey->pnonce, WPA_NONCE_LEN)) {
    --		wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
    --			"RSN: Failed to get random data for PNonce");
    --		return;
    --	}
    --	wpa_hexdump(MSG_DEBUG, "WPA: Renewed PNonce",
    --		    peerkey->pnonce, WPA_NONCE_LEN);
    --
    --	/* Calculate STK which will be stored as a temporary STK until it has
    --	 * been verified when processing message 3/4. */
    --	stk = &peerkey->tstk;
    --	wpa_pmk_to_ptk(peerkey->smk, PMK_LEN, "Peer key expansion",
    --		       sm->own_addr, peerkey->addr,
    --		       peerkey->pnonce, key->key_nonce,
    --		       stk, peerkey->akmp, peerkey->cipher);
    --	/* Supplicant: swap tx/rx Mic keys */
    --	os_memcpy(buf, &stk->tk[16], 8);
    --	os_memcpy(&stk->tk[16], &stk->tk[24], 8);
    --	os_memcpy(&stk->tk[24], buf, 8);
    --	peerkey->tstk_set = 1;
    --
    --	kde_buf_len = peerkey->rsnie_p_len +
    --		2 + RSN_SELECTOR_LEN + sizeof(lifetime) +
    --		2 + RSN_SELECTOR_LEN + PMKID_LEN;
    --	kde_buf = os_malloc(kde_buf_len);
    --	if (kde_buf == NULL)
    --		return;
    --	pos = kde_buf;
    --	pos = wpa_add_ie(pos, peerkey->rsnie_p, peerkey->rsnie_p_len);
    --	lifetime = host_to_be32(peerkey->lifetime);
    --	pos = wpa_add_kde(pos, RSN_KEY_DATA_LIFETIME,
    --			  (u8 *) &lifetime, sizeof(lifetime));
    --	wpa_add_kde(pos, RSN_KEY_DATA_PMKID, peerkey->smkid, PMKID_LEN);
    --
    --	if (wpa_supplicant_send_2_of_4(sm, peerkey->addr, key, ver,
    --				       peerkey->pnonce, kde_buf, kde_buf_len,
    --				       stk)) {
    --		os_free(kde_buf);
    --		return;
    --	}
    --	os_free(kde_buf);
    --
    --	os_memcpy(peerkey->inonce, key->key_nonce, WPA_NONCE_LEN);
    --}
    --
    --
    --static void wpa_supplicant_update_smk_lifetime(struct wpa_sm *sm,
    --					       struct wpa_peerkey *peerkey,
    --					       struct wpa_eapol_ie_parse *kde)
    --{
    --	u32 lifetime;
    --
    --	if (kde->lifetime == NULL || kde->lifetime_len < sizeof(lifetime))
    --		return;
    --
    --	lifetime = WPA_GET_BE32(kde->lifetime);
    --
    --	if (lifetime >= peerkey->lifetime) {
    --		wpa_printf(MSG_DEBUG, "RSN: Peer used SMK lifetime %u seconds "
    --			   "which is larger than or equal to own value %u "
    --			   "seconds - ignored", lifetime, peerkey->lifetime);
    --		return;
    --	}
    --
    --	wpa_printf(MSG_DEBUG, "RSN: Peer used shorter SMK lifetime %u seconds "
    --		   "(own was %u seconds) - updated",
    --		   lifetime, peerkey->lifetime);
    --	peerkey->lifetime = lifetime;
    --
    --	eloop_cancel_timeout(wpa_supplicant_smk_timeout, sm, peerkey);
    --	eloop_register_timeout(lifetime, 0, wpa_supplicant_smk_timeout,
    --			       sm, peerkey);
    --}
    --
    --
    --static void wpa_supplicant_process_stk_2_of_4(struct wpa_sm *sm,
    --					      struct wpa_peerkey *peerkey,
    --					      const struct wpa_eapol_key *key,
    --					      u16 ver, const u8 *key_data,
    --					      size_t key_data_len)
    --{
    --	struct wpa_eapol_ie_parse kde;
    --
    --	wpa_printf(MSG_DEBUG, "RSN: RX message 2 of STK 4-Way Handshake from "
    --		   MACSTR " (ver=%d)", MAC2STR(peerkey->addr), ver);
    --
    --	os_memset(&kde, 0, sizeof(kde));
    --
    --	/* RSN: msg 2/4 should contain SMKID for the selected SMK and RSN IE
    --	 * from the peer. It may also include Lifetime KDE. */
    --	wpa_hexdump(MSG_DEBUG, "RSN: msg 2/4 key data", key_data, key_data_len);
    --	if (wpa_supplicant_parse_ies(key_data, key_data_len, &kde) < 0 ||
    --	    kde.pmkid == NULL || kde.rsn_ie == NULL) {
    --		wpa_printf(MSG_DEBUG, "RSN: No SMKID or RSN IE in STK 2/4");
    --		return;
    --	}
    --
    --	if (os_memcmp_const(kde.pmkid, peerkey->smkid, PMKID_LEN) != 0) {
    --		wpa_hexdump(MSG_DEBUG, "RSN: Unknown SMKID in STK 2/4",
    --			    kde.pmkid, PMKID_LEN);
    --		return;
    --	}
    --
    --	if (kde.rsn_ie_len != peerkey->rsnie_p_len ||
    --	    os_memcmp(kde.rsn_ie, peerkey->rsnie_p, kde.rsn_ie_len) != 0) {
    --		wpa_printf(MSG_INFO, "RSN: Peer RSN IE in SMK and STK "
    --			   "handshakes did not match");
    --		wpa_hexdump(MSG_DEBUG, "RSN: Peer RSN IE in SMK handshake",
    --			    peerkey->rsnie_p, peerkey->rsnie_p_len);
    --		wpa_hexdump(MSG_DEBUG, "RSN: Peer RSN IE in STK handshake",
    --			    kde.rsn_ie, kde.rsn_ie_len);
    --		return;
    --	}
    --
    --	wpa_supplicant_update_smk_lifetime(sm, peerkey, &kde);
    --
    --	wpa_supplicant_send_stk_3_of_4(sm, peerkey);
    --	os_memcpy(peerkey->pnonce, key->key_nonce, WPA_NONCE_LEN);
    --}
    --
    --
    --static void wpa_supplicant_process_stk_3_of_4(struct wpa_sm *sm,
    --					      struct wpa_peerkey *peerkey,
    --					      const struct wpa_eapol_key *key,
    --					      u16 ver, const u8 *key_data,
    --					      size_t key_data_len)
    --{
    --	struct wpa_eapol_ie_parse kde;
    --	size_t key_len;
    --	const u8 *_key;
    --	u8 key_buf[32], rsc[6];
    --
    --	wpa_printf(MSG_DEBUG, "RSN: RX message 3 of STK 4-Way Handshake from "
    --		   MACSTR " (ver=%d)", MAC2STR(peerkey->addr), ver);
    --
    --	os_memset(&kde, 0, sizeof(kde));
    --
    --	/* RSN: msg 3/4 should contain Initiator RSN IE. It may also include
    --	 * Lifetime KDE. */
    --	wpa_hexdump(MSG_DEBUG, "RSN: msg 3/4 key data", key_data, key_data_len);
    --	if (wpa_supplicant_parse_ies(key_data, key_data_len, &kde) < 0) {
    --		wpa_printf(MSG_DEBUG, "RSN: Failed to parse key data in "
    --			   "STK 3/4");
    --		return;
    --	}
    --
    --	if (kde.rsn_ie_len != peerkey->rsnie_i_len ||
    --	    os_memcmp(kde.rsn_ie, peerkey->rsnie_i, kde.rsn_ie_len) != 0) {
    --		wpa_printf(MSG_INFO, "RSN: Initiator RSN IE in SMK and STK "
    --			   "handshakes did not match");
    --		wpa_hexdump(MSG_DEBUG, "RSN: Initiator RSN IE in SMK "
    --			    "handshake",
    --			    peerkey->rsnie_i, peerkey->rsnie_i_len);
    --		wpa_hexdump(MSG_DEBUG, "RSN: Initiator RSN IE in STK "
    --			    "handshake",
    --			    kde.rsn_ie, kde.rsn_ie_len);
    --		return;
    --	}
    --
    --	if (os_memcmp(peerkey->inonce, key->key_nonce, WPA_NONCE_LEN) != 0) {
    --		wpa_printf(MSG_WARNING, "RSN: INonce from message 1 of STK "
    --			   "4-Way Handshake differs from 3 of STK 4-Way "
    --			   "Handshake - drop packet (src=" MACSTR ")",
    --			   MAC2STR(peerkey->addr));
    --		return;
    --	}
    --
    --	wpa_supplicant_update_smk_lifetime(sm, peerkey, &kde);
    --
    --	if (wpa_supplicant_send_4_of_4(sm, peerkey->addr, key, ver,
    --				       WPA_GET_BE16(key->key_info),
    --				       &peerkey->stk))
    --		return;
    --
    --	_key = peerkey->stk.tk;
    --	if (peerkey->cipher == WPA_CIPHER_TKIP) {
    --		/* Swap Tx/Rx keys for Michael MIC */
    --		os_memcpy(key_buf, _key, 16);
    --		os_memcpy(key_buf + 16, _key + 24, 8);
    --		os_memcpy(key_buf + 24, _key + 16, 8);
    --		_key = key_buf;
    --		key_len = 32;
    --	} else
    --		key_len = 16;
    --
    --	os_memset(rsc, 0, 6);
    --	if (wpa_sm_set_key(sm, peerkey->cipher, peerkey->addr, 0, 1,
    --			   rsc, sizeof(rsc), _key, key_len) < 0) {
    --		os_memset(key_buf, 0, sizeof(key_buf));
    --		wpa_printf(MSG_WARNING, "RSN: Failed to set STK to the "
    --			   "driver.");
    --		return;
    --	}
    --	os_memset(key_buf, 0, sizeof(key_buf));
    --}
    --
    --
    --static void wpa_supplicant_process_stk_4_of_4(struct wpa_sm *sm,
    --					      struct wpa_peerkey *peerkey,
    --					      const struct wpa_eapol_key *key,
    --					      u16 ver)
    --{
    --	u8 rsc[6];
    --
    --	wpa_printf(MSG_DEBUG, "RSN: RX message 4 of STK 4-Way Handshake from "
    --		   MACSTR " (ver=%d)", MAC2STR(peerkey->addr), ver);
    --
    --	os_memset(rsc, 0, 6);
    --	if (wpa_sm_set_key(sm, peerkey->cipher, peerkey->addr, 0, 1,
    --			   rsc, sizeof(rsc), peerkey->stk.tk,
    --			   peerkey->cipher == WPA_CIPHER_TKIP ? 32 : 16) < 0) {
    --		wpa_printf(MSG_WARNING, "RSN: Failed to set STK to the "
    --			   "driver.");
    --		return;
    --	}
    --}
    --
    --
    --/**
    -- * peerkey_verify_eapol_key_mic - Verify PeerKey MIC
    -- * @sm: Pointer to WPA state machine data from wpa_sm_init()
    -- * @peerkey: Pointer to the PeerKey data for the peer
    -- * @key: Pointer to the EAPOL-Key frame header
    -- * @ver: Version bits from EAPOL-Key Key Info
    -- * @buf: Pointer to the beginning of EAPOL-Key frame
    -- * @len: Length of the EAPOL-Key frame
    -- * Returns: 0 on success, -1 on failure
    -- */
    --int peerkey_verify_eapol_key_mic(struct wpa_sm *sm,
    --				 struct wpa_peerkey *peerkey,
    --				 struct wpa_eapol_key_192 *key, u16 ver,
    --				 const u8 *buf, size_t len)
    --{
    --	u8 mic[WPA_EAPOL_KEY_MIC_MAX_LEN];
    --	size_t mic_len = 16;
    --	int ok = 0;
    --
    --	if (peerkey->initiator && !peerkey->stk_set) {
    --		wpa_pmk_to_ptk(peerkey->smk, PMK_LEN, "Peer key expansion",
    --			       sm->own_addr, peerkey->addr,
    --			       peerkey->inonce, key->key_nonce,
    --			       &peerkey->stk, peerkey->akmp, peerkey->cipher);
    --		peerkey->stk_set = 1;
    --	}
    --
    --	os_memcpy(mic, key->key_mic, mic_len);
    --	if (peerkey->tstk_set) {
    --		os_memset(key->key_mic, 0, mic_len);
    --		wpa_eapol_key_mic(peerkey->tstk.kck, peerkey->tstk.kck_len,
    --				  sm->key_mgmt, ver, buf, len, key->key_mic);
    --		if (os_memcmp_const(mic, key->key_mic, mic_len) != 0) {
    --			wpa_printf(MSG_WARNING, "RSN: Invalid EAPOL-Key MIC "
    --				   "when using TSTK - ignoring TSTK");
    --		} else {
    --			ok = 1;
    --			peerkey->tstk_set = 0;
    --			peerkey->stk_set = 1;
    --			os_memcpy(&peerkey->stk, &peerkey->tstk,
    --				  sizeof(peerkey->stk));
    --			os_memset(&peerkey->tstk, 0, sizeof(peerkey->tstk));
    --		}
    --	}
    --
    --	if (!ok && peerkey->stk_set) {
    --		os_memset(key->key_mic, 0, mic_len);
    --		wpa_eapol_key_mic(peerkey->stk.kck, peerkey->stk.kck_len,
    --				  sm->key_mgmt, ver, buf, len, key->key_mic);
    --		if (os_memcmp_const(mic, key->key_mic, mic_len) != 0) {
    --			wpa_printf(MSG_WARNING, "RSN: Invalid EAPOL-Key MIC "
    --				   "- dropping packet");
    --			return -1;
    --		}
    --		ok = 1;
    --	}
    --
    --	if (!ok) {
    --		wpa_printf(MSG_WARNING, "RSN: Could not verify EAPOL-Key MIC "
    --			   "- dropping packet");
    --		return -1;
    --	}
    --
    --	os_memcpy(peerkey->replay_counter, key->replay_counter,
    --		  WPA_REPLAY_COUNTER_LEN);
    --	peerkey->replay_counter_set = 1;
    --	return 0;
    --}
    --
    --
    --/**
    -- * wpa_sm_stkstart - Send EAPOL-Key Request for STK handshake (STK M1)
    -- * @sm: Pointer to WPA state machine data from wpa_sm_init()
    -- * @peer: MAC address of the peer STA
    -- * Returns: 0 on success, or -1 on failure
    -- *
    -- * Send an EAPOL-Key Request to the current authenticator to start STK
    -- * handshake with the peer.
    -- */
    --int wpa_sm_stkstart(struct wpa_sm *sm, const u8 *peer)
    --{
    --	size_t rlen, kde_len;
    --	struct wpa_eapol_key *req;
    --	int key_info, ver;
    --	u8 bssid[ETH_ALEN], *rbuf, *pos, *count_pos;
    --	u16 count;
    --	struct rsn_ie_hdr *hdr;
    --	struct wpa_peerkey *peerkey;
    --	struct wpa_ie_data ie;
    --
    --	if (sm->proto != WPA_PROTO_RSN || !sm->ptk_set || !sm->peerkey_enabled)
    --		return -1;
    --
    --	if (sm->ap_rsn_ie &&
    --	    wpa_parse_wpa_ie_rsn(sm->ap_rsn_ie, sm->ap_rsn_ie_len, &ie) == 0 &&
    --	    !(ie.capabilities & WPA_CAPABILITY_PEERKEY_ENABLED)) {
    --		wpa_printf(MSG_DEBUG, "RSN: Current AP does not support STK");
    --		return -1;
    --	}
    --
    --	if (sm->pairwise_cipher != WPA_CIPHER_TKIP)
    --		ver = WPA_KEY_INFO_TYPE_HMAC_SHA1_AES;
    --	else
    --		ver = WPA_KEY_INFO_TYPE_HMAC_MD5_RC4;
    --
    --	if (wpa_sm_get_bssid(sm, bssid) < 0) {
    --		wpa_printf(MSG_WARNING, "Failed to read BSSID for EAPOL-Key "
    --			   "SMK M1");
    --		return -1;
    --	}
    --
    --	/* TODO: find existing entry and if found, use that instead of adding
    --	 * a new one */
    --	peerkey = os_zalloc(sizeof(*peerkey));
    --	if (peerkey == NULL)
    --		return -1;
    --	peerkey->initiator = 1;
    --	os_memcpy(peerkey->addr, peer, ETH_ALEN);
    --	peerkey->akmp = sm->key_mgmt;
    --
    --	/* SMK M1:
    --	 * EAPOL-Key(S=1, M=1, A=0, I=0, K=0, SM=1, KeyRSC=0, Nonce=INonce,
    --	 *           MIC=MIC, DataKDs=(RSNIE_I, MAC_P KDE))
    --	 */
    --
    --	hdr = (struct rsn_ie_hdr *) peerkey->rsnie_i;
    --	hdr->elem_id = WLAN_EID_RSN;
    --	WPA_PUT_LE16(hdr->version, RSN_VERSION);
    --	pos = (u8 *) (hdr + 1);
    --	/* Group Suite can be anything for SMK RSN IE; receiver will just
    --	 * ignore it. */
    --	RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_CCMP);
    --	pos += RSN_SELECTOR_LEN;
    --	count_pos = pos;
    --	pos += 2;
    --
    --	count = rsn_cipher_put_suites(pos, sm->allowed_pairwise_cipher);
    --	pos += count * RSN_SELECTOR_LEN;
    --	WPA_PUT_LE16(count_pos, count);
    --
    --	hdr->len = (pos - peerkey->rsnie_i) - 2;
    --	peerkey->rsnie_i_len = pos - peerkey->rsnie_i;
    --	wpa_hexdump(MSG_DEBUG, "WPA: RSN IE for SMK handshake",
    --		    peerkey->rsnie_i, peerkey->rsnie_i_len);
    --
    --	kde_len = peerkey->rsnie_i_len + 2 + RSN_SELECTOR_LEN + ETH_ALEN;
    --
    --	rbuf = wpa_sm_alloc_eapol(sm, IEEE802_1X_TYPE_EAPOL_KEY, NULL,
    --				  sizeof(*req) + kde_len, &rlen,
    --				  (void *) &req);
    --	if (rbuf == NULL) {
    --		wpa_supplicant_peerkey_free(sm, peerkey);
    --		return -1;
    --	}
    --
    --	req->type = EAPOL_KEY_TYPE_RSN;
    --	key_info = WPA_KEY_INFO_SMK_MESSAGE | WPA_KEY_INFO_MIC |
    --		WPA_KEY_INFO_SECURE | WPA_KEY_INFO_REQUEST | ver;
    --	WPA_PUT_BE16(req->key_info, key_info);
    --	WPA_PUT_BE16(req->key_length, 0);
    --	os_memcpy(req->replay_counter, sm->request_counter,
    --		  WPA_REPLAY_COUNTER_LEN);
    --	inc_byte_array(sm->request_counter, WPA_REPLAY_COUNTER_LEN);
    --
    --	if (random_get_bytes(peerkey->inonce, WPA_NONCE_LEN)) {
    --		wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
    --			"WPA: Failed to get random data for INonce");
    --		os_free(rbuf);
    --		wpa_supplicant_peerkey_free(sm, peerkey);
    --		return -1;
    --	}
    --	os_memcpy(req->key_nonce, peerkey->inonce, WPA_NONCE_LEN);
    --	wpa_hexdump(MSG_DEBUG, "WPA: INonce for SMK handshake",
    --		    req->key_nonce, WPA_NONCE_LEN);
    --
    --	WPA_PUT_BE16(req->key_data_length, (u16) kde_len);
    --	pos = (u8 *) (req + 1);
    --
    --	/* Initiator RSN IE */
    --	pos = wpa_add_ie(pos, peerkey->rsnie_i, peerkey->rsnie_i_len);
    --	/* Peer MAC address KDE */
    --	wpa_add_kde(pos, RSN_KEY_DATA_MAC_ADDR, peer, ETH_ALEN);
    --
    --	wpa_printf(MSG_INFO, "RSN: Sending EAPOL-Key SMK M1 Request (peer "
    --		   MACSTR ")", MAC2STR(peer));
    --	wpa_eapol_key_send(sm, sm->ptk.kck, sm->ptk.kck_len, ver, bssid,
    --			   ETH_P_EAPOL, rbuf, rlen, req->key_mic);
    --
    --	peerkey->next = sm->peerkey;
    --	sm->peerkey = peerkey;
    --
    --	return 0;
    --}
    --
    --
    --/**
    -- * peerkey_deinit - Free PeerKey values
    -- * @sm: Pointer to WPA state machine data from wpa_sm_init()
    -- */
    --void peerkey_deinit(struct wpa_sm *sm)
    --{
    --	struct wpa_peerkey *prev, *peerkey = sm->peerkey;
    --	while (peerkey) {
    --		prev = peerkey;
    --		peerkey = peerkey->next;
    --		wpa_supplicant_peerkey_free(sm, prev);
    --	}
    --	sm->peerkey = NULL;
    --}
    --
    --
    --void peerkey_rx_eapol_4way(struct wpa_sm *sm, struct wpa_peerkey *peerkey,
    --			   struct wpa_eapol_key *key, u16 key_info, u16 ver,
    --			   const u8 *key_data, size_t key_data_len)
    --{
    --	if ((key_info & (WPA_KEY_INFO_MIC | WPA_KEY_INFO_ACK)) ==
    --	    (WPA_KEY_INFO_MIC | WPA_KEY_INFO_ACK)) {
    --		/* 3/4 STK 4-Way Handshake */
    --		wpa_supplicant_process_stk_3_of_4(sm, peerkey, key, ver,
    --						  key_data, key_data_len);
    --	} else if (key_info & WPA_KEY_INFO_ACK) {
    --		/* 1/4 STK 4-Way Handshake */
    --		wpa_supplicant_process_stk_1_of_4(sm, peerkey, key, ver,
    --						  key_data, key_data_len);
    --	} else if (key_info & WPA_KEY_INFO_SECURE) {
    --		/* 4/4 STK 4-Way Handshake */
    --		wpa_supplicant_process_stk_4_of_4(sm, peerkey, key, ver);
    --	} else {
    --		/* 2/4 STK 4-Way Handshake */
    --		wpa_supplicant_process_stk_2_of_4(sm, peerkey, key, ver,
    --						  key_data, key_data_len);
    --	}
    --}
    --
    --
    --void peerkey_rx_eapol_smk(struct wpa_sm *sm, const u8 *src_addr,
    --			  struct wpa_eapol_key *key, size_t extra_len,
    --			  u16 key_info, u16 ver)
    --{
    --	if (key_info & WPA_KEY_INFO_ERROR) {
    --		/* SMK Error */
    --		wpa_supplicant_process_smk_error(sm, src_addr, key, extra_len);
    --	} else if (key_info & WPA_KEY_INFO_ACK) {
    --		/* SMK M2 */
    --		wpa_supplicant_process_smk_m2(sm, src_addr, key, extra_len,
    --					      ver);
    --	} else {
    --		/* SMK M4 or M5 */
    --		wpa_supplicant_process_smk_m45(sm, src_addr, key, extra_len,
    --					       ver);
    --	}
    --}
    --
    --#endif /* CONFIG_PEERKEY */
    -diff --git a/src/rsn_supp/peerkey.h b/src/rsn_supp/peerkey.h
    -deleted file mode 100644
    -index 6ccd948b..00000000
    ---- a/src/rsn_supp/peerkey.h
    -+++ /dev/null
    -@@ -1,82 +0,0 @@
    --/*
    -- * WPA Supplicant - PeerKey for Direct Link Setup (DLS)
    -- * Copyright (c) 2006-2015, Jouni Malinen <j@w1.fi>
    -- *
    -- * This software may be distributed under the terms of the BSD license.
    -- * See README for more details.
    -- */
    --
    --#ifndef PEERKEY_H
    --#define PEERKEY_H
    --
    --#define PEERKEY_MAX_IE_LEN 80
    --struct wpa_peerkey {
    --	struct wpa_peerkey *next;
    --	int initiator; /* whether this end was initator for SMK handshake */
    --	u8 addr[ETH_ALEN]; /* other end MAC address */
    --	u8 inonce[WPA_NONCE_LEN]; /* Initiator Nonce */
    --	u8 pnonce[WPA_NONCE_LEN]; /* Peer Nonce */
    --	u8 rsnie_i[PEERKEY_MAX_IE_LEN]; /* Initiator RSN IE */
    --	size_t rsnie_i_len;
    --	u8 rsnie_p[PEERKEY_MAX_IE_LEN]; /* Peer RSN IE */
    --	size_t rsnie_p_len;
    --	u8 smk[PMK_LEN];
    --	int smk_complete;
    --	u8 smkid[PMKID_LEN];
    --	u32 lifetime;
    --	int cipher; /* Selected cipher (WPA_CIPHER_*) */
    --	u8 replay_counter[WPA_REPLAY_COUNTER_LEN];
    --	int replay_counter_set;
    --	int akmp;
    --
    --	struct wpa_ptk stk, tstk;
    --	int stk_set, tstk_set;
    --};
    --
    --
    --#ifdef CONFIG_PEERKEY
    --
    --int peerkey_verify_eapol_key_mic(struct wpa_sm *sm,
    --				 struct wpa_peerkey *peerkey,
    --				 struct wpa_eapol_key_192 *key, u16 ver,
    --				 const u8 *buf, size_t len);
    --void peerkey_rx_eapol_4way(struct wpa_sm *sm, struct wpa_peerkey *peerkey,
    --			   struct wpa_eapol_key *key, u16 key_info, u16 ver,
    --			   const u8 *key_data, size_t key_data_len);
    --void peerkey_rx_eapol_smk(struct wpa_sm *sm, const u8 *src_addr,
    --			  struct wpa_eapol_key *key, size_t extra_len,
    --			  u16 key_info, u16 ver);
    --void peerkey_deinit(struct wpa_sm *sm);
    --
    --#else /* CONFIG_PEERKEY */
    --
    --static inline int
    --peerkey_verify_eapol_key_mic(struct wpa_sm *sm,
    --			     struct wpa_peerkey *peerkey,
    --			     struct wpa_eapol_key *key, u16 ver,
    --			     const u8 *buf, size_t len)
    --{
    --	return -1;
    --}
    --
    --static inline void
    --peerkey_rx_eapol_4way(struct wpa_sm *sm, struct wpa_peerkey *peerkey,
    --		      struct wpa_eapol_key *key, u16 key_info, u16 ver,
    --		      const u8 *key_data, size_t key_data_len)
    --{
    --}
    --
    --static inline void
    --peerkey_rx_eapol_smk(struct wpa_sm *sm, const u8 *src_addr,
    --		     struct wpa_eapol_key *key, size_t extra_len,
    --		     u16 key_info, u16 ver)
    --{
    --}
    --
    --static inline void peerkey_deinit(struct wpa_sm *sm)
    --{
    --}
    --
    --#endif /* CONFIG_PEERKEY */
    --
    --#endif /* PEERKEY_H */
    -diff --git a/src/rsn_supp/tdls.c b/src/rsn_supp/tdls.c
    -index e4241681..9eb97386 100644
    ---- a/src/rsn_supp/tdls.c
    -+++ b/src/rsn_supp/tdls.c
    -@@ -112,6 +112,7 @@ struct wpa_tdls_peer {
    - 		u8 tk[16]; /* TPK-TK; assuming only CCMP will be used */
    - 	} tpk;
    - 	int tpk_set;
    -+	int tk_set; /* TPK-TK configured to the driver */
    - 	int tpk_success;
    - 	int tpk_in_progress;
    - 
    -@@ -192,6 +193,20 @@ static int wpa_tdls_set_key(struct wpa_sm *sm, struct wpa_tdls_peer *peer)
    - 	u8 rsc[6];
    - 	enum wpa_alg alg;
    - 
    -+	if (peer->tk_set) {
    -+		/*
    -+		 * This same TPK-TK has already been configured to the driver
    -+		 * and this new configuration attempt (likely due to an
    -+		 * unexpected retransmitted frame) would result in clearing
    -+		 * the TX/RX sequence number which can break security, so must
    -+		 * not allow that to happen.
    -+		 */
    -+		wpa_printf(MSG_INFO, "TDLS: TPK-TK for the peer " MACSTR
    -+			   " has already been configured to the driver - do not reconfigure",
    -+			   MAC2STR(peer->addr));
    -+		return -1;
    -+	}
    -+
    - 	os_memset(rsc, 0, 6);
    - 
    - 	switch (peer->cipher) {
    -@@ -209,12 +224,15 @@ static int wpa_tdls_set_key(struct wpa_sm *sm, struct wpa_tdls_peer *peer)
    - 		return -1;
    - 	}
    - 
    -+	wpa_printf(MSG_DEBUG, "TDLS: Configure pairwise key for peer " MACSTR,
    -+		   MAC2STR(peer->addr));
    - 	if (wpa_sm_set_key(sm, alg, peer->addr, -1, 1,
    - 			   rsc, sizeof(rsc), peer->tpk.tk, key_len) < 0) {
    - 		wpa_printf(MSG_WARNING, "TDLS: Failed to set TPK to the "
    - 			   "driver");
    - 		return -1;
    - 	}
    -+	peer->tk_set = 1;
    - 	return 0;
    - }
    - 
    -@@ -696,7 +714,7 @@ static void wpa_tdls_peer_clear(struct wpa_sm *sm, struct wpa_tdls_peer *peer)
    - 	peer->cipher = 0;
    - 	peer->qos_info = 0;
    - 	peer->wmm_capable = 0;
    --	peer->tpk_set = peer->tpk_success = 0;
    -+	peer->tk_set = peer->tpk_set = peer->tpk_success = 0;
    - 	peer->chan_switch_enabled = 0;
    - 	os_memset(&peer->tpk, 0, sizeof(peer->tpk));
    - 	os_memset(peer->inonce, 0, WPA_NONCE_LEN);
    -@@ -1159,6 +1177,7 @@ skip_rsnie:
    - 		wpa_tdls_peer_free(sm, peer);
    - 		return -1;
    - 	}
    -+	peer->tk_set = 0; /* A new nonce results in a new TK */
    - 	wpa_hexdump(MSG_DEBUG, "TDLS: Initiator Nonce for TPK handshake",
    - 		    peer->inonce, WPA_NONCE_LEN);
    - 	os_memcpy(ftie->Snonce, peer->inonce, WPA_NONCE_LEN);
    -@@ -1751,6 +1770,19 @@ static int wpa_tdls_addset_peer(struct wpa_sm *sm, struct wpa_tdls_peer *peer,
    - }
    - 
    - 
    -+static int tdls_nonce_set(const u8 *nonce)
    -+{
    -+	int i;
    -+
    -+	for (i = 0; i < WPA_NONCE_LEN; i++) {
    -+		if (nonce[i])
    -+			return 1;
    -+	}
    -+
    -+	return 0;
    -+}
    -+
    -+
    - static int wpa_tdls_process_tpk_m1(struct wpa_sm *sm, const u8 *src_addr,
    - 				   const u8 *buf, size_t len)
    - {
    -@@ -2004,7 +2036,8 @@ skip_rsn:
    - 	peer->rsnie_i_len = kde.rsn_ie_len;
    - 	peer->cipher = cipher;
    - 
    --	if (os_memcmp(peer->inonce, ftie->Snonce, WPA_NONCE_LEN) != 0) {
    -+	if (os_memcmp(peer->inonce, ftie->Snonce, WPA_NONCE_LEN) != 0 ||
    -+	    !tdls_nonce_set(peer->inonce)) {
    - 		/*
    - 		 * There is no point in updating the RNonce for every obtained
    - 		 * TPK M1 frame (e.g., retransmission due to timeout) with the
    -@@ -2020,6 +2053,7 @@ skip_rsn:
    - 				"TDLS: Failed to get random data for responder nonce");
    - 			goto error;
    - 		}
    -+		peer->tk_set = 0; /* A new nonce results in a new TK */
    - 	}
    - 
    - #if 0
    -diff --git a/src/rsn_supp/wpa.c b/src/rsn_supp/wpa.c
    -index 3c478792..a22e36da 100644
    ---- a/src/rsn_supp/wpa.c
    -+++ b/src/rsn_supp/wpa.c
    -@@ -21,7 +21,6 @@
    - #include "pmksa_cache.h"
    - #include "wpa_i.h"
    - #include "wpa_ie.h"
    --#include "peerkey.h"
    - 
    - 
    - static const u8 null_rsc[8] = { 0, 0, 0, 0, 0, 0, 0, 0 };
    -@@ -500,7 +499,8 @@ static void wpa_supplicant_process_1_of_4(struct wpa_sm *sm,
    - 	/* Calculate PTK which will be stored as a temporary PTK until it has
    - 	 * been verified when processing message 3/4. */
    - 	ptk = &sm->tptk;
    --	wpa_derive_ptk(sm, src_addr, key, ptk);
    -+	if (wpa_derive_ptk(sm, src_addr, key, ptk) < 0)
    -+		goto failed;
    - 	if (sm->pairwise_cipher == WPA_CIPHER_TKIP) {
    - 		u8 buf[8];
    - 		/* Supplicant: swap tx/rx Mic keys */
    -@@ -510,7 +510,6 @@ static void wpa_supplicant_process_1_of_4(struct wpa_sm *sm,
    - 		os_memset(buf, 0, sizeof(buf));
    - 	}
    - 	sm->tptk_set = 1;
    --	sm->tk_to_set = 1;
    - 
    - 	kde = sm->assoc_wpa_ie;
    - 	kde_len = sm->assoc_wpa_ie_len;
    -@@ -615,7 +614,7 @@ static int wpa_supplicant_install_ptk(struct wpa_sm *sm,
    - 	enum wpa_alg alg;
    - 	const u8 *key_rsc;
    - 
    --	if (!sm->tk_to_set) {
    -+	if (sm->ptk.installed) {
    - 		wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG,
    - 			"WPA: Do not re-install same PTK to the driver");
    - 		return 0;
    -@@ -659,7 +658,7 @@ static int wpa_supplicant_install_ptk(struct wpa_sm *sm,
    - 
    - 	/* TK is not needed anymore in supplicant */
    - 	os_memset(sm->ptk.tk, 0, WPA_TK_MAX_LEN);
    --	sm->tk_to_set = 0;
    -+	sm->ptk.installed = 1;
    - 
    - 	if (sm->wpa_ptk_rekey) {
    - 		eloop_cancel_timeout(wpa_sm_rekey_ptk, sm, NULL);
    -@@ -709,11 +708,23 @@ struct wpa_gtk_data {
    - 
    - static int wpa_supplicant_install_gtk(struct wpa_sm *sm,
    - 				      const struct wpa_gtk_data *gd,
    --				      const u8 *key_rsc)
    -+				      const u8 *key_rsc, int wnm_sleep)
    - {
    - 	const u8 *_gtk = gd->gtk;
    - 	u8 gtk_buf[32];
    - 
    -+	/* Detect possible key reinstallation */
    -+	if ((sm->gtk.gtk_len == (size_t) gd->gtk_len &&
    -+	     os_memcmp(sm->gtk.gtk, gd->gtk, sm->gtk.gtk_len) == 0) ||
    -+	    (sm->gtk_wnm_sleep.gtk_len == (size_t) gd->gtk_len &&
    -+	     os_memcmp(sm->gtk_wnm_sleep.gtk, gd->gtk,
    -+		       sm->gtk_wnm_sleep.gtk_len) == 0)) {
    -+		wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG,
    -+			"WPA: Not reinstalling already in-use GTK to the driver (keyidx=%d tx=%d len=%d)",
    -+			gd->keyidx, gd->tx, gd->gtk_len);
    -+		return 0;
    -+	}
    -+
    - 	wpa_hexdump_key(MSG_DEBUG, "WPA: Group Key", gd->gtk, gd->gtk_len);
    - 	wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG,
    - 		"WPA: Installing GTK to the driver (keyidx=%d tx=%d len=%d)",
    -@@ -748,6 +759,15 @@ static int wpa_supplicant_install_gtk(struct wpa_sm *sm,
    - 	}
    - 	os_memset(gtk_buf, 0, sizeof(gtk_buf));
    - 
    -+	if (wnm_sleep) {
    -+		sm->gtk_wnm_sleep.gtk_len = gd->gtk_len;
    -+		os_memcpy(sm->gtk_wnm_sleep.gtk, gd->gtk,
    -+			  sm->gtk_wnm_sleep.gtk_len);
    -+	} else {
    -+		sm->gtk.gtk_len = gd->gtk_len;
    -+		os_memcpy(sm->gtk.gtk, gd->gtk, sm->gtk.gtk_len);
    -+	}
    -+
    - 	return 0;
    - }
    - 
    -@@ -840,7 +860,7 @@ static int wpa_supplicant_pairwise_gtk(struct wpa_sm *sm,
    - 	    (wpa_supplicant_check_group_cipher(sm, sm->group_cipher,
    - 					       gtk_len, gtk_len,
    - 					       &gd.key_rsc_len, &gd.alg) ||
    --	     wpa_supplicant_install_gtk(sm, &gd, key_rsc))) {
    -+	     wpa_supplicant_install_gtk(sm, &gd, key_rsc, 0))) {
    - 		wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG,
    - 			"RSN: Failed to install GTK");
    - 		os_memset(&gd, 0, sizeof(gd));
    -@@ -854,6 +874,58 @@ static int wpa_supplicant_pairwise_gtk(struct wpa_sm *sm,
    - }
    - 
    - 
    -+#ifdef CONFIG_IEEE80211W
    -+static int wpa_supplicant_install_igtk(struct wpa_sm *sm,
    -+				       const struct wpa_igtk_kde *igtk,
    -+				       int wnm_sleep)
    -+{
    -+	size_t len = wpa_cipher_key_len(sm->mgmt_group_cipher);
    -+	u16 keyidx = WPA_GET_LE16(igtk->keyid);
    -+
    -+	/* Detect possible key reinstallation */
    -+	if ((sm->igtk.igtk_len == len &&
    -+	     os_memcmp(sm->igtk.igtk, igtk->igtk, sm->igtk.igtk_len) == 0) ||
    -+	    (sm->igtk_wnm_sleep.igtk_len == len &&
    -+	     os_memcmp(sm->igtk_wnm_sleep.igtk, igtk->igtk,
    -+		       sm->igtk_wnm_sleep.igtk_len) == 0)) {
    -+		wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG,
    -+			"WPA: Not reinstalling already in-use IGTK to the driver (keyidx=%d)",
    -+			keyidx);
    -+		return  0;
    -+	}
    -+
    -+	wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG,
    -+		"WPA: IGTK keyid %d pn %02x%02x%02x%02x%02x%02x",
    -+		keyidx, MAC2STR(igtk->pn));
    -+	wpa_hexdump_key(MSG_DEBUG, "WPA: IGTK", igtk->igtk, len);
    -+	if (keyidx > 4095) {
    -+		wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
    -+			"WPA: Invalid IGTK KeyID %d", keyidx);
    -+		return -1;
    -+	}
    -+	if (wpa_sm_set_key(sm, wpa_cipher_to_alg(sm->mgmt_group_cipher),
    -+			   broadcast_ether_addr,
    -+			   keyidx, 0, igtk->pn, sizeof(igtk->pn),
    -+			   igtk->igtk, len) < 0) {
    -+		wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
    -+			"WPA: Failed to configure IGTK to the driver");
    -+		return -1;
    -+	}
    -+
    -+	if (wnm_sleep) {
    -+		sm->igtk_wnm_sleep.igtk_len = len;
    -+		os_memcpy(sm->igtk_wnm_sleep.igtk, igtk->igtk,
    -+			  sm->igtk_wnm_sleep.igtk_len);
    -+	} else {
    -+		sm->igtk.igtk_len = len;
    -+		os_memcpy(sm->igtk.igtk, igtk->igtk, sm->igtk.igtk_len);
    -+	}
    -+
    -+	return 0;
    -+}
    -+#endif /* CONFIG_IEEE80211W */
    -+
    -+
    - static int ieee80211w_set_keys(struct wpa_sm *sm,
    - 			       struct wpa_eapol_ie_parse *ie)
    - {
    -@@ -864,30 +936,14 @@ static int ieee80211w_set_keys(struct wpa_sm *sm,
    - 	if (ie->igtk) {
    - 		size_t len;
    - 		const struct wpa_igtk_kde *igtk;
    --		u16 keyidx;
    -+
    - 		len = wpa_cipher_key_len(sm->mgmt_group_cipher);
    - 		if (ie->igtk_len != WPA_IGTK_KDE_PREFIX_LEN + len)
    - 			return -1;
    -+
    - 		igtk = (const struct wpa_igtk_kde *) ie->igtk;
    --		keyidx = WPA_GET_LE16(igtk->keyid);
    --		wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG, "WPA: IGTK keyid %d "
    --			"pn %02x%02x%02x%02x%02x%02x",
    --			keyidx, MAC2STR(igtk->pn));
    --		wpa_hexdump_key(MSG_DEBUG, "WPA: IGTK",
    --				igtk->igtk, len);
    --		if (keyidx > 4095) {
    --			wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
    --				"WPA: Invalid IGTK KeyID %d", keyidx);
    --			return -1;
    --		}
    --		if (wpa_sm_set_key(sm, wpa_cipher_to_alg(sm->mgmt_group_cipher),
    --				   broadcast_ether_addr,
    --				   keyidx, 0, igtk->pn, sizeof(igtk->pn),
    --				   igtk->igtk, len) < 0) {
    --			wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
    --				"WPA: Failed to configure IGTK to the driver");
    -+		if (wpa_supplicant_install_igtk(sm, igtk, 0) < 0)
    - 			return -1;
    --		}
    - 	}
    - 
    - 	return 0;
    -@@ -1536,7 +1592,7 @@ static void wpa_supplicant_process_1_of_2(struct wpa_sm *sm,
    - 	if (wpa_supplicant_rsc_relaxation(sm, key->key_rsc))
    - 		key_rsc = null_rsc;
    - 
    --	if (wpa_supplicant_install_gtk(sm, &gd, key_rsc) ||
    -+	if (wpa_supplicant_install_gtk(sm, &gd, key_rsc, 0) ||
    - 	    wpa_supplicant_send_2_of_2(sm, key, ver, key_info) < 0)
    - 		goto failed;
    - 	os_memset(&gd, 0, sizeof(gd));
    -@@ -1587,6 +1643,14 @@ static int wpa_supplicant_verify_eapol_key_mic(struct wpa_sm *sm,
    - 			sm->ptk_set = 1;
    - 			os_memcpy(&sm->ptk, &sm->tptk, sizeof(sm->ptk));
    - 			os_memset(&sm->tptk, 0, sizeof(sm->tptk));
    -+			/*
    -+			 * This assures the same TPTK in sm->tptk can never be
    -+			 * copied twice to sm->pkt as the new PTK. In
    -+			 * combination with the installed flag in the wpa_ptk
    -+			 * struct, this assures the same PTK is only installed
    -+			 * once.
    -+			 */
    -+			sm->renew_snonce = 1;
    - 		}
    - 	}
    - 
    -@@ -1767,7 +1831,6 @@ int wpa_sm_rx_eapol(struct wpa_sm *sm, const u8 *src_addr,
    - 	u16 key_info, ver;
    - 	u8 *tmp = NULL;
    - 	int ret = -1;
    --	struct wpa_peerkey *peerkey = NULL;
    - 	u8 *key_data;
    - 	size_t mic_len, keyhdrlen;
    - 
    -@@ -1941,44 +2004,7 @@ int wpa_sm_rx_eapol(struct wpa_sm *sm, const u8 *src_addr,
    - 		goto out;
    - 	}
    - 
    --#ifdef CONFIG_PEERKEY
    --	for (peerkey = sm->peerkey; peerkey; peerkey = peerkey->next) {
    --		if (os_memcmp(peerkey->addr, src_addr, ETH_ALEN) == 0)
    --			break;
    --	}
    --
    --	if (!(key_info & WPA_KEY_INFO_SMK_MESSAGE) && peerkey) {
    --		if (!peerkey->initiator && peerkey->replay_counter_set &&
    --		    os_memcmp(key->replay_counter, peerkey->replay_counter,
    --			      WPA_REPLAY_COUNTER_LEN) <= 0) {
    --			wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
    --				"RSN: EAPOL-Key Replay Counter did not "
    --				"increase (STK) - dropping packet");
    --			goto out;
    --		} else if (peerkey->initiator) {
    --			u8 _tmp[WPA_REPLAY_COUNTER_LEN];
    --			os_memcpy(_tmp, key->replay_counter,
    --				  WPA_REPLAY_COUNTER_LEN);
    --			inc_byte_array(_tmp, WPA_REPLAY_COUNTER_LEN);
    --			if (os_memcmp(_tmp, peerkey->replay_counter,
    --				      WPA_REPLAY_COUNTER_LEN) != 0) {
    --				wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG,
    --					"RSN: EAPOL-Key Replay "
    --					"Counter did not match (STK) - "
    --					"dropping packet");
    --				goto out;
    --			}
    --		}
    --	}
    --
    --	if (peerkey && peerkey->initiator && (key_info & WPA_KEY_INFO_ACK)) {
    --		wpa_msg(sm->ctx->msg_ctx, MSG_INFO,
    --			"RSN: Ack bit in key_info from STK peer");
    --		goto out;
    --	}
    --#endif /* CONFIG_PEERKEY */
    --
    --	if (!peerkey && sm->rx_replay_counter_set &&
    -+	if (sm->rx_replay_counter_set &&
    - 	    os_memcmp(key->replay_counter, sm->rx_replay_counter,
    - 		      WPA_REPLAY_COUNTER_LEN) <= 0) {
    - 		wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
    -@@ -1987,11 +2013,13 @@ int wpa_sm_rx_eapol(struct wpa_sm *sm, const u8 *src_addr,
    - 		goto out;
    - 	}
    - 
    --	if (!(key_info & (WPA_KEY_INFO_ACK | WPA_KEY_INFO_SMK_MESSAGE))
    --#ifdef CONFIG_PEERKEY
    --	    && (peerkey == NULL || !peerkey->initiator)
    --#endif /* CONFIG_PEERKEY */
    --		) {
    -+	if (key_info & WPA_KEY_INFO_SMK_MESSAGE) {
    -+		wpa_msg(sm->ctx->msg_ctx, MSG_INFO,
    -+			"WPA: Unsupported SMK bit in key_info");
    -+		goto out;
    -+	}
    -+
    -+	if (!(key_info & WPA_KEY_INFO_ACK)) {
    - 		wpa_msg(sm->ctx->msg_ctx, MSG_INFO,
    - 			"WPA: No Ack bit in key_info");
    - 		goto out;
    -@@ -2003,17 +2031,10 @@ int wpa_sm_rx_eapol(struct wpa_sm *sm, const u8 *src_addr,
    - 		goto out;
    - 	}
    - 
    --	if ((key_info & WPA_KEY_INFO_MIC) && !peerkey &&
    -+	if ((key_info & WPA_KEY_INFO_MIC) &&
    - 	    wpa_supplicant_verify_eapol_key_mic(sm, key192, ver, tmp, data_len))
    - 		goto out;
    - 
    --#ifdef CONFIG_PEERKEY
    --	if ((key_info & WPA_KEY_INFO_MIC) && peerkey &&
    --	    peerkey_verify_eapol_key_mic(sm, peerkey, key192, ver, tmp,
    --					 data_len))
    --		goto out;
    --#endif /* CONFIG_PEERKEY */
    --
    - 	if ((sm->proto == WPA_PROTO_RSN || sm->proto == WPA_PROTO_OSEN) &&
    - 	    (key_info & WPA_KEY_INFO_ENCR_KEY_DATA)) {
    - 		if (wpa_supplicant_decrypt_key_data(sm, key, ver, key_data,
    -@@ -2028,11 +2049,7 @@ int wpa_sm_rx_eapol(struct wpa_sm *sm, const u8 *src_addr,
    - 				"non-zero key index");
    - 			goto out;
    - 		}
    --		if (peerkey) {
    --			/* PeerKey 4-Way Handshake */
    --			peerkey_rx_eapol_4way(sm, peerkey, key, key_info, ver,
    --					      key_data, key_data_len);
    --		} else if (key_info & WPA_KEY_INFO_MIC) {
    -+		if (key_info & WPA_KEY_INFO_MIC) {
    - 			/* 3/4 4-Way Handshake */
    - 			wpa_supplicant_process_3_of_4(sm, key, ver, key_data,
    - 						      key_data_len);
    -@@ -2042,10 +2059,6 @@ int wpa_sm_rx_eapol(struct wpa_sm *sm, const u8 *src_addr,
    - 						      ver, key_data,
    - 						      key_data_len);
    - 		}
    --	} else if (key_info & WPA_KEY_INFO_SMK_MESSAGE) {
    --		/* PeerKey SMK Handshake */
    --		peerkey_rx_eapol_smk(sm, src_addr, key, key_data_len, key_info,
    --				     ver);
    - 	} else {
    - 		if (key_info & WPA_KEY_INFO_MIC) {
    - 			/* 1/2 Group Key Handshake */
    -@@ -2286,7 +2299,6 @@ void wpa_sm_deinit(struct wpa_sm *sm)
    - 	os_free(sm->ap_rsn_ie);
    - 	wpa_sm_drop_sa(sm);
    - 	os_free(sm->ctx);
    --	peerkey_deinit(sm);
    - #ifdef CONFIG_IEEE80211R
    - 	os_free(sm->assoc_resp_ies);
    - #endif /* CONFIG_IEEE80211R */
    -@@ -2307,7 +2319,7 @@ void wpa_sm_deinit(struct wpa_sm *sm)
    -  */
    - void wpa_sm_notify_assoc(struct wpa_sm *sm, const u8 *bssid)
    - {
    --	int clear_ptk = 1;
    -+	int clear_keys = 1;
    - 
    - 	if (sm == NULL)
    - 		return;
    -@@ -2333,11 +2345,11 @@ void wpa_sm_notify_assoc(struct wpa_sm *sm, const u8 *bssid)
    - 		/* Prepare for the next transition */
    - 		wpa_ft_prepare_auth_request(sm, NULL);
    - 
    --		clear_ptk = 0;
    -+		clear_keys = 0;
    - 	}
    - #endif /* CONFIG_IEEE80211R */
    - 
    --	if (clear_ptk) {
    -+	if (clear_keys) {
    - 		/*
    - 		 * IEEE 802.11, 8.4.10: Delete PTK SA on (re)association if
    - 		 * this is not part of a Fast BSS Transition.
    -@@ -2347,6 +2359,12 @@ void wpa_sm_notify_assoc(struct wpa_sm *sm, const u8 *bssid)
    - 		os_memset(&sm->ptk, 0, sizeof(sm->ptk));
    - 		sm->tptk_set = 0;
    - 		os_memset(&sm->tptk, 0, sizeof(sm->tptk));
    -+		os_memset(&sm->gtk, 0, sizeof(sm->gtk));
    -+		os_memset(&sm->gtk_wnm_sleep, 0, sizeof(sm->gtk_wnm_sleep));
    -+#ifdef CONFIG_IEEE80211W
    -+		os_memset(&sm->igtk, 0, sizeof(sm->igtk));
    -+		os_memset(&sm->igtk_wnm_sleep, 0, sizeof(sm->igtk_wnm_sleep));
    -+#endif /* CONFIG_IEEE80211W */
    - 	}
    - 
    - #ifdef CONFIG_TDLS
    -@@ -2370,7 +2388,6 @@ void wpa_sm_notify_disassoc(struct wpa_sm *sm)
    - {
    - 	eloop_cancel_timeout(wpa_sm_start_preauth, sm, NULL);
    - 	eloop_cancel_timeout(wpa_sm_rekey_ptk, sm, NULL);
    --	peerkey_deinit(sm);
    - 	rsn_preauth_deinit(sm);
    - 	pmksa_cache_clear_current(sm);
    - 	if (wpa_sm_get_state(sm) == WPA_4WAY_HANDSHAKE)
    -@@ -2378,6 +2395,9 @@ void wpa_sm_notify_disassoc(struct wpa_sm *sm)
    - #ifdef CONFIG_TDLS
    - 	wpa_tdls_disassoc(sm);
    - #endif /* CONFIG_TDLS */
    -+#ifdef CONFIG_IEEE80211R
    -+	sm->ft_reassoc_completed = 0;
    -+#endif /* CONFIG_IEEE80211R */
    - 
    - 	/* Keys are not needed in the WPA state machine anymore */
    - 	wpa_sm_drop_sa(sm);
    -@@ -2402,6 +2422,8 @@ void wpa_sm_set_pmk(struct wpa_sm *sm, const u8 *pmk, size_t pmk_len,
    - 	if (sm == NULL)
    - 		return;
    - 
    -+	wpa_hexdump_key(MSG_DEBUG, "WPA: Set PMK based on external data",
    -+			pmk, pmk_len);
    - 	sm->pmk_len = pmk_len;
    - 	os_memcpy(sm->pmk, pmk, pmk_len);
    - 
    -@@ -2432,11 +2454,15 @@ void wpa_sm_set_pmk_from_pmksa(struct wpa_sm *sm)
    - 		return;
    - 
    - 	if (sm->cur_pmksa) {
    -+		wpa_hexdump_key(MSG_DEBUG,
    -+				"WPA: Set PMK based on current PMKSA",
    -+				sm->cur_pmksa->pmk, sm->cur_pmksa->pmk_len);
    - 		sm->pmk_len = sm->cur_pmksa->pmk_len;
    - 		os_memcpy(sm->pmk, sm->cur_pmksa->pmk, sm->pmk_len);
    - 	} else {
    --		sm->pmk_len = PMK_LEN;
    --		os_memset(sm->pmk, 0, PMK_LEN);
    -+		wpa_printf(MSG_DEBUG, "WPA: No current PMKSA - clear PMK");
    -+		sm->pmk_len = 0;
    -+		os_memset(sm->pmk, 0, PMK_LEN_MAX);
    - 	}
    - }
    - 
    -@@ -2484,7 +2510,6 @@ void wpa_sm_set_config(struct wpa_sm *sm, struct rsn_supp_config *config)
    - 
    - 	if (config) {
    - 		sm->network_ctx = config->network_ctx;
    --		sm->peerkey_enabled = config->peerkey_enabled;
    - 		sm->allowed_pairwise_cipher = config->allowed_pairwise_cipher;
    - 		sm->proactive_key_caching = config->proactive_key_caching;
    - 		sm->eap_workaround = config->eap_workaround;
    -@@ -2499,7 +2524,6 @@ void wpa_sm_set_config(struct wpa_sm *sm, struct rsn_supp_config *config)
    - 		sm->wpa_rsc_relaxation = config->wpa_rsc_relaxation;
    - 	} else {
    - 		sm->network_ctx = NULL;
    --		sm->peerkey_enabled = 0;
    - 		sm->allowed_pairwise_cipher = 0;
    - 		sm->proactive_key_caching = 0;
    - 		sm->eap_workaround = 0;
    -@@ -2877,6 +2901,12 @@ void wpa_sm_drop_sa(struct wpa_sm *sm)
    - 	os_memset(sm->pmk, 0, sizeof(sm->pmk));
    - 	os_memset(&sm->ptk, 0, sizeof(sm->ptk));
    - 	os_memset(&sm->tptk, 0, sizeof(sm->tptk));
    -+	os_memset(&sm->gtk, 0, sizeof(sm->gtk));
    -+	os_memset(&sm->gtk_wnm_sleep, 0, sizeof(sm->gtk_wnm_sleep));
    -+#ifdef CONFIG_IEEE80211W
    -+	os_memset(&sm->igtk, 0, sizeof(sm->igtk));
    -+	os_memset(&sm->igtk_wnm_sleep, 0, sizeof(sm->igtk_wnm_sleep));
    -+#endif /* CONFIG_IEEE80211W */
    - #ifdef CONFIG_IEEE80211R
    - 	os_memset(sm->xxkey, 0, sizeof(sm->xxkey));
    - 	os_memset(sm->pmk_r0, 0, sizeof(sm->pmk_r0));
    -@@ -2940,7 +2970,7 @@ int wpa_wnmsleep_install_key(struct wpa_sm *sm, u8 subelem_id, u8 *buf)
    - 
    - 		wpa_hexdump_key(MSG_DEBUG, "Install GTK (WNM SLEEP)",
    - 				gd.gtk, gd.gtk_len);
    --		if (wpa_supplicant_install_gtk(sm, &gd, key_rsc)) {
    -+		if (wpa_supplicant_install_gtk(sm, &gd, key_rsc, 1)) {
    - 			os_memset(&gd, 0, sizeof(gd));
    - 			wpa_printf(MSG_DEBUG, "Failed to install the GTK in "
    - 				   "WNM mode");
    -@@ -2949,29 +2979,11 @@ int wpa_wnmsleep_install_key(struct wpa_sm *sm, u8 subelem_id, u8 *buf)
    - 		os_memset(&gd, 0, sizeof(gd));
    - #ifdef CONFIG_IEEE80211W
    - 	} else if (subelem_id == WNM_SLEEP_SUBELEM_IGTK) {
    --		struct wpa_igtk_kde igd;
    --		u16 keyidx;
    --
    --		os_memset(&igd, 0, sizeof(igd));
    --		keylen = wpa_cipher_key_len(sm->mgmt_group_cipher);
    --		os_memcpy(igd.keyid, buf + 2, 2);
    --		os_memcpy(igd.pn, buf + 4, 6);
    --
    --		keyidx = WPA_GET_LE16(igd.keyid);
    --		os_memcpy(igd.igtk, buf + 10, keylen);
    --
    --		wpa_hexdump_key(MSG_DEBUG, "Install IGTK (WNM SLEEP)",
    --				igd.igtk, keylen);
    --		if (wpa_sm_set_key(sm, wpa_cipher_to_alg(sm->mgmt_group_cipher),
    --				   broadcast_ether_addr,
    --				   keyidx, 0, igd.pn, sizeof(igd.pn),
    --				   igd.igtk, keylen) < 0) {
    --			wpa_printf(MSG_DEBUG, "Failed to install the IGTK in "
    --				   "WNM mode");
    --			os_memset(&igd, 0, sizeof(igd));
    -+		const struct wpa_igtk_kde *igtk;
    -+
    -+		igtk = (const struct wpa_igtk_kde *) (buf + 2);
    -+		if (wpa_supplicant_install_igtk(sm, igtk, 1) < 0)
    - 			return -1;
    --		}
    --		os_memset(&igd, 0, sizeof(igd));
    - #endif /* CONFIG_IEEE80211W */
    - 	} else {
    - 		wpa_printf(MSG_DEBUG, "Unknown element id");
    -@@ -2983,27 +2995,6 @@ int wpa_wnmsleep_install_key(struct wpa_sm *sm, u8 subelem_id, u8 *buf)
    - #endif /* CONFIG_WNM */
    - 
    - 
    --#ifdef CONFIG_PEERKEY
    --int wpa_sm_rx_eapol_peerkey(struct wpa_sm *sm, const u8 *src_addr,
    --			    const u8 *buf, size_t len)
    --{
    --	struct wpa_peerkey *peerkey;
    --
    --	for (peerkey = sm->peerkey; peerkey; peerkey = peerkey->next) {
    --		if (os_memcmp(peerkey->addr, src_addr, ETH_ALEN) == 0)
    --			break;
    --	}
    --
    --	if (!peerkey)
    --		return 0;
    --
    --	wpa_sm_rx_eapol(sm, src_addr, buf, len);
    --
    --	return 1;
    --}
    --#endif /* CONFIG_PEERKEY */
    --
    --
    - #ifdef CONFIG_P2P
    - 
    - int wpa_sm_get_p2p_ip_addr(struct wpa_sm *sm, u8 *buf)
    -diff --git a/src/rsn_supp/wpa.h b/src/rsn_supp/wpa.h
    -index c89799ac..b55baac6 100644
    ---- a/src/rsn_supp/wpa.h
    -+++ b/src/rsn_supp/wpa.h
    -@@ -95,7 +95,6 @@ enum wpa_sm_conf_params {
    - 
    - struct rsn_supp_config {
    - 	void *network_ctx;
    --	int peerkey_enabled;
    - 	int allowed_pairwise_cipher; /* bitfield of WPA_CIPHER_* */
    - 	int proactive_key_caching;
    - 	int eap_workaround;
    -@@ -329,23 +328,6 @@ static inline void wpa_sm_set_ptk_kck_kek(struct wpa_sm *sm, const u8 *ptk_kck,
    - 
    - #endif /* CONFIG_NO_WPA */
    - 
    --#ifdef CONFIG_PEERKEY
    --int wpa_sm_stkstart(struct wpa_sm *sm, const u8 *peer);
    --int wpa_sm_rx_eapol_peerkey(struct wpa_sm *sm, const u8 *src_addr,
    --			    const u8 *buf, size_t len);
    --#else /* CONFIG_PEERKEY */
    --static inline int wpa_sm_stkstart(struct wpa_sm *sm, const u8 *peer)
    --{
    --	return -1;
    --}
    --
    --static inline int wpa_sm_rx_eapol_peerkey(struct wpa_sm *sm, const u8 *src_addr,
    --					  const u8 *buf, size_t len)
    --{
    --	return 0;
    --}
    --#endif /* CONFIG_PEERKEY */
    --
    - #ifdef CONFIG_IEEE80211R
    - 
    - int wpa_sm_set_ft_params(struct wpa_sm *sm, const u8 *ies, size_t ies_len);
    -diff --git a/src/rsn_supp/wpa_ft.c b/src/rsn_supp/wpa_ft.c
    -index 205793e7..d45bb458 100644
    ---- a/src/rsn_supp/wpa_ft.c
    -+++ b/src/rsn_supp/wpa_ft.c
    -@@ -153,6 +153,7 @@ static u8 * wpa_ft_gen_req_ies(struct wpa_sm *sm, size_t *len,
    - 	u16 capab;
    - 
    - 	sm->ft_completed = 0;
    -+	sm->ft_reassoc_completed = 0;
    - 
    - 	buf_len = 2 + sizeof(struct rsn_mdie) + 2 + sizeof(struct rsn_ftie) +
    - 		2 + sm->r0kh_id_len + ric_ies_len + 100;
    -@@ -681,6 +682,11 @@ int wpa_ft_validate_reassoc_resp(struct wpa_sm *sm, const u8 *ies,
    - 		return -1;
    - 	}
    - 
    -+	if (sm->ft_reassoc_completed) {
    -+		wpa_printf(MSG_DEBUG, "FT: Reassociation has already been completed for this FT protocol instance - ignore unexpected retransmission");
    -+		return 0;
    -+	}
    -+
    - 	if (wpa_ft_parse_ies(ies, ies_len, &parse) < 0) {
    - 		wpa_printf(MSG_DEBUG, "FT: Failed to parse IEs");
    - 		return -1;
    -@@ -781,6 +787,8 @@ int wpa_ft_validate_reassoc_resp(struct wpa_sm *sm, const u8 *ies,
    - 		return -1;
    - 	}
    - 
    -+	sm->ft_reassoc_completed = 1;
    -+
    - 	if (wpa_ft_process_gtk_subelem(sm, parse.gtk, parse.gtk_len) < 0)
    - 		return -1;
    - 
    -diff --git a/src/rsn_supp/wpa_i.h b/src/rsn_supp/wpa_i.h
    -index f653ba6e..2243613f 100644
    ---- a/src/rsn_supp/wpa_i.h
    -+++ b/src/rsn_supp/wpa_i.h
    -@@ -11,7 +11,6 @@
    - 
    - #include "utils/list.h"
    - 
    --struct wpa_peerkey;
    - struct wpa_tdls_peer;
    - struct wpa_eapol_key;
    - 
    -@@ -24,13 +23,18 @@ struct wpa_sm {
    - 	struct wpa_ptk ptk, tptk;
    - 	int ptk_set, tptk_set;
    - 	unsigned int msg_3_of_4_ok:1;
    --	unsigned int tk_to_set:1;
    - 	u8 snonce[WPA_NONCE_LEN];
    - 	u8 anonce[WPA_NONCE_LEN]; /* ANonce from the last 1/4 msg */
    - 	int renew_snonce;
    - 	u8 rx_replay_counter[WPA_REPLAY_COUNTER_LEN];
    - 	int rx_replay_counter_set;
    - 	u8 request_counter[WPA_REPLAY_COUNTER_LEN];
    -+	struct wpa_gtk gtk;
    -+	struct wpa_gtk gtk_wnm_sleep;
    -+#ifdef CONFIG_IEEE80211W
    -+	struct wpa_igtk igtk;
    -+	struct wpa_igtk igtk_wnm_sleep;
    -+#endif /* CONFIG_IEEE80211W */
    - 
    - 	struct eapol_sm *eapol; /* EAPOL state machine from upper level code */
    - 
    -@@ -52,7 +56,6 @@ struct wpa_sm {
    - 	int fast_reauth; /* whether EAP fast re-authentication is enabled */
    - 
    - 	void *network_ctx;
    --	int peerkey_enabled;
    - 	int allowed_pairwise_cipher; /* bitfield of WPA_CIPHER_* */
    - 	int proactive_key_caching;
    - 	int eap_workaround;
    -@@ -89,9 +92,6 @@ struct wpa_sm {
    - 	u8 *ap_wpa_ie, *ap_rsn_ie;
    - 	size_t ap_wpa_ie_len, ap_rsn_ie_len;
    - 
    --#ifdef CONFIG_PEERKEY
    --	struct wpa_peerkey *peerkey;
    --#endif /* CONFIG_PEERKEY */
    - #ifdef CONFIG_TDLS
    - 	struct wpa_tdls_peer *tdls;
    - 	int tdls_prohibited;
    -@@ -123,6 +123,7 @@ struct wpa_sm {
    - 	size_t r0kh_id_len;
    - 	u8 r1kh_id[FT_R1KH_ID_LEN];
    - 	int ft_completed;
    -+	int ft_reassoc_completed;
    - 	int over_the_ds_in_progress;
    - 	u8 target_ap[ETH_ALEN]; /* over-the-DS target AP */
    - 	int set_ptk_after_assoc;
    -diff --git a/src/rsn_supp/wpa_ie.c b/src/rsn_supp/wpa_ie.c
    -index c44844ec..4e0c3f45 100644
    ---- a/src/rsn_supp/wpa_ie.c
    -+++ b/src/rsn_supp/wpa_ie.c
    -@@ -405,44 +405,6 @@ static int wpa_parse_generic(const u8 *pos, const u8 *end,
    - 		return 0;
    - 	}
    - 
    --#ifdef CONFIG_PEERKEY
    --	if (pos[1] > RSN_SELECTOR_LEN + 2 &&
    --	    RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_SMK) {
    --		ie->smk = pos + 2 + RSN_SELECTOR_LEN;
    --		ie->smk_len = pos[1] - RSN_SELECTOR_LEN;
    --		wpa_hexdump_key(MSG_DEBUG, "WPA: SMK in EAPOL-Key",
    --				pos, pos[1] + 2);
    --		return 0;
    --	}
    --
    --	if (pos[1] > RSN_SELECTOR_LEN + 2 &&
    --	    RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_NONCE) {
    --		ie->nonce = pos + 2 + RSN_SELECTOR_LEN;
    --		ie->nonce_len = pos[1] - RSN_SELECTOR_LEN;
    --		wpa_hexdump(MSG_DEBUG, "WPA: Nonce in EAPOL-Key",
    --			    pos, pos[1] + 2);
    --		return 0;
    --	}
    --
    --	if (pos[1] > RSN_SELECTOR_LEN + 2 &&
    --	    RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_LIFETIME) {
    --		ie->lifetime = pos + 2 + RSN_SELECTOR_LEN;
    --		ie->lifetime_len = pos[1] - RSN_SELECTOR_LEN;
    --		wpa_hexdump(MSG_DEBUG, "WPA: Lifetime in EAPOL-Key",
    --			    pos, pos[1] + 2);
    --		return 0;
    --	}
    --
    --	if (pos[1] > RSN_SELECTOR_LEN + 2 &&
    --	    RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_ERROR) {
    --		ie->error = pos + 2 + RSN_SELECTOR_LEN;
    --		ie->error_len = pos[1] - RSN_SELECTOR_LEN;
    --		wpa_hexdump(MSG_DEBUG, "WPA: Error in EAPOL-Key",
    --			    pos, pos[1] + 2);
    --		return 0;
    --	}
    --#endif /* CONFIG_PEERKEY */
    --
    - #ifdef CONFIG_IEEE80211W
    - 	if (pos[1] > RSN_SELECTOR_LEN + 2 &&
    - 	    RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_IGTK) {
    -diff --git a/src/rsn_supp/wpa_ie.h b/src/rsn_supp/wpa_ie.h
    -index fe95af0a..0e72af56 100644
    ---- a/src/rsn_supp/wpa_ie.h
    -+++ b/src/rsn_supp/wpa_ie.h
    -@@ -21,16 +21,6 @@ struct wpa_eapol_ie_parse {
    - 	size_t gtk_len;
    - 	const u8 *mac_addr;
    - 	size_t mac_addr_len;
    --#ifdef CONFIG_PEERKEY
    --	const u8 *smk;
    --	size_t smk_len;
    --	const u8 *nonce;
    --	size_t nonce_len;
    --	const u8 *lifetime;
    --	size_t lifetime_len;
    --	const u8 *error;
    --	size_t error_len;
    --#endif /* CONFIG_PEERKEY */
    - #ifdef CONFIG_IEEE80211W
    - 	const u8 *igtk;
    - 	size_t igtk_len;
    -diff --git a/wpa_supplicant/Android.mk b/wpa_supplicant/Android.mk
    -index f65076c7..802c4ae9 100644
    ---- a/wpa_supplicant/Android.mk
    -+++ b/wpa_supplicant/Android.mk
    -@@ -247,15 +247,10 @@ ifdef CONFIG_TDLS_TESTING
    - L_CFLAGS += -DCONFIG_TDLS_TESTING
    - endif
    - 
    --ifdef CONFIG_PEERKEY
    --L_CFLAGS += -DCONFIG_PEERKEY
    --endif
    --
    - ifndef CONFIG_NO_WPA
    - OBJS += src/rsn_supp/wpa.c
    - OBJS += src/rsn_supp/preauth.c
    - OBJS += src/rsn_supp/pmksa_cache.c
    --OBJS += src/rsn_supp/peerkey.c
    - OBJS += src/rsn_supp/wpa_ie.c
    - OBJS += src/common/wpa_common.c
    - NEED_AES=y
    -@@ -860,9 +855,6 @@ OBJS += src/ap/pmksa_cache_auth.c
    - ifdef CONFIG_IEEE80211R
    - OBJS += src/ap/wpa_auth_ft.c
    - endif
    --ifdef CONFIG_PEERKEY
    --OBJS += src/ap/peerkey_auth.c
    --endif
    - endif
    - 
    - ifdef CONFIG_ACS
    -@@ -931,6 +923,7 @@ endif
    - 
    - ifndef CONFIG_TLS
    - CONFIG_TLS=openssl
    -+L_CFLAGS += -DCONFIG_USE_OPENSSL_RNG
    - endif
    - 
    - ifdef CONFIG_TLSV11
    -diff --git a/wpa_supplicant/Makefile b/wpa_supplicant/Makefile
    -index 550d44b2..b057f7f1 100644
    ---- a/wpa_supplicant/Makefile
    -+++ b/wpa_supplicant/Makefile
    -@@ -286,15 +286,10 @@ ifdef CONFIG_TDLS_TESTING
    - CFLAGS += -DCONFIG_TDLS_TESTING
    - endif
    - 
    --ifdef CONFIG_PEERKEY
    --CFLAGS += -DCONFIG_PEERKEY
    --endif
    --
    - ifndef CONFIG_NO_WPA
    - OBJS += ../src/rsn_supp/wpa.o
    - OBJS += ../src/rsn_supp/preauth.o
    - OBJS += ../src/rsn_supp/pmksa_cache.o
    --OBJS += ../src/rsn_supp/peerkey.o
    - OBJS += ../src/rsn_supp/wpa_ie.o
    - OBJS += ../src/common/wpa_common.o
    - NEED_AES=y
    -@@ -907,9 +902,6 @@ OBJS += ../src/ap/pmksa_cache_auth.o
    - ifdef CONFIG_IEEE80211R
    - OBJS += ../src/ap/wpa_auth_ft.o
    - endif
    --ifdef CONFIG_PEERKEY
    --OBJS += ../src/ap/peerkey_auth.o
    --endif
    - endif
    - 
    - ifdef CONFIG_ACS
    -diff --git a/wpa_supplicant/android.config b/wpa_supplicant/android.config
    -index 0a8bf981..8eb64431 100644
    ---- a/wpa_supplicant/android.config
    -+++ b/wpa_supplicant/android.config
    -@@ -263,9 +263,6 @@ CONFIG_ELOOP=eloop
    - # none = Empty template
    - CONFIG_L2_PACKET=linux
    - 
    --# PeerKey handshake for Station to Station Link (IEEE 802.11e DLS)
    --CONFIG_PEERKEY=y
    --
    - # IEEE 802.11w (management frame protection), also known as PMF
    - # Driver support is also needed for IEEE 802.11w.
    - CONFIG_IEEE80211W=y
    -diff --git a/wpa_supplicant/config.c b/wpa_supplicant/config.c
    -index 43766763..6cbbe2d7 100644
    ---- a/wpa_supplicant/config.c
    -+++ b/wpa_supplicant/config.c
    -@@ -1810,6 +1810,24 @@ static char * wpa_config_write_mesh_basic_rates(const struct parse_data *data,
    - #endif /* CONFIG_MESH */
    - 
    - 
    -+static int wpa_config_parse_peerkey(const struct parse_data *data,
    -+				    struct wpa_ssid *ssid, int line,
    -+				    const char *value)
    -+{
    -+	wpa_printf(MSG_INFO, "NOTE: Obsolete peerkey parameter ignored");
    -+	return 0;
    -+}
    -+
    -+
    -+#ifndef NO_CONFIG_WRITE
    -+static char * wpa_config_write_peerkey(const struct parse_data *data,
    -+				       struct wpa_ssid *ssid)
    -+{
    -+	return NULL;
    -+}
    -+#endif /* NO_CONFIG_WRITE */
    -+
    -+
    - /* Helper macros for network block parser */
    - 
    - #ifdef OFFSET
    -@@ -1984,7 +2002,7 @@ static const struct parse_data ssid_fields[] = {
    - #ifdef CONFIG_IEEE80211W
    - 	{ INT_RANGE(ieee80211w, 0, 2) },
    - #endif /* CONFIG_IEEE80211W */
    --	{ INT_RANGE(peerkey, 0, 1) },
    -+	{ FUNC(peerkey) /* obsolete - removed */ },
    - 	{ INT_RANGE(mixed_cell, 0, 1) },
    - 	{ INT_RANGE(frequency, 0, 65000) },
    - 	{ INT_RANGE(fixed_freq, 0, 1) },
    -diff --git a/wpa_supplicant/config_file.c b/wpa_supplicant/config_file.c
    -index 38061f1c..1d317fc5 100644
    ---- a/wpa_supplicant/config_file.c
    -+++ b/wpa_supplicant/config_file.c
    -@@ -752,7 +752,6 @@ static void wpa_config_write_network(FILE *f, struct wpa_ssid *ssid)
    - #endif /* CONFIG_ACS */
    - 	write_int(f, "proactive_key_caching", ssid->proactive_key_caching, -1);
    - 	INT(disabled);
    --	INT(peerkey);
    - 	INT(mixed_cell);
    - 	INT(max_oper_chwidth);
    - 	INT(pbss);
    -diff --git a/wpa_supplicant/config_ssid.h b/wpa_supplicant/config_ssid.h
    -index eb7b87be..5b6f426d 100644
    ---- a/wpa_supplicant/config_ssid.h
    -+++ b/wpa_supplicant/config_ssid.h
    -@@ -387,17 +387,6 @@ struct wpa_ssid {
    - 	 */
    - 	int disabled_for_connect;
    - 
    --	/**
    --	 * peerkey -  Whether PeerKey handshake for direct links is allowed
    --	 *
    --	 * This is only used when both RSN/WPA2 and IEEE 802.11e (QoS) are
    --	 * enabled.
    --	 *
    --	 * 0 = disabled (default)
    --	 * 1 = enabled
    --	 */
    --	int peerkey;
    --
    - 	/**
    - 	 * id_str - Network identifier string for external scripts
    - 	 *
    -diff --git a/wpa_supplicant/config_winreg.c b/wpa_supplicant/config_winreg.c
    -index 199f04fb..ca70474e 100644
    ---- a/wpa_supplicant/config_winreg.c
    -+++ b/wpa_supplicant/config_winreg.c
    -@@ -924,7 +924,6 @@ static int wpa_config_write_network(HKEY hk, struct wpa_ssid *ssid, int id)
    - 	write_int(netw, "proactive_key_caching", ssid->proactive_key_caching,
    - 		  -1);
    - 	INT(disabled);
    --	INT(peerkey);
    - #ifdef CONFIG_IEEE80211W
    - 	write_int(netw, "ieee80211w", ssid->ieee80211w,
    - 		  MGMT_FRAME_PROTECTION_DEFAULT);
    -diff --git a/wpa_supplicant/ctrl_iface.c b/wpa_supplicant/ctrl_iface.c
    -index 85744379..80f1d410 100644
    ---- a/wpa_supplicant/ctrl_iface.c
    -+++ b/wpa_supplicant/ctrl_iface.c
    -@@ -575,27 +575,6 @@ static int wpa_supplicant_ctrl_iface_preauth(struct wpa_supplicant *wpa_s,
    - #endif /* IEEE8021X_EAPOL */
    - 
    - 
    --#ifdef CONFIG_PEERKEY
    --/* MLME-STKSTART.request(peer) */
    --static int wpa_supplicant_ctrl_iface_stkstart(
    --	struct wpa_supplicant *wpa_s, char *addr)
    --{
    --	u8 peer[ETH_ALEN];
    --
    --	if (hwaddr_aton(addr, peer)) {
    --		wpa_printf(MSG_DEBUG, "CTRL_IFACE STKSTART: invalid "
    --			   "address '%s'", addr);
    --		return -1;
    --	}
    --
    --	wpa_printf(MSG_DEBUG, "CTRL_IFACE STKSTART " MACSTR,
    --		   MAC2STR(peer));
    --
    --	return wpa_sm_stkstart(wpa_s->wpa, peer);
    --}
    --#endif /* CONFIG_PEERKEY */
    --
    --
    - #ifdef CONFIG_TDLS
    - 
    - static int wpa_supplicant_ctrl_iface_tdls_discover(
    -@@ -8502,11 +8481,6 @@ char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s,
    - 		if (wpa_supplicant_ctrl_iface_preauth(wpa_s, buf + 8))
    - 			reply_len = -1;
    - #endif /* IEEE8021X_EAPOL */
    --#ifdef CONFIG_PEERKEY
    --	} else if (os_strncmp(buf, "STKSTART ", 9) == 0) {
    --		if (wpa_supplicant_ctrl_iface_stkstart(wpa_s, buf + 9))
    --			reply_len = -1;
    --#endif /* CONFIG_PEERKEY */
    - #ifdef CONFIG_IEEE80211R
    - 	} else if (os_strncmp(buf, "FT_DS ", 6) == 0) {
    - 		if (wpa_supplicant_ctrl_iface_ft_ds(wpa_s, buf + 6))
    -diff --git a/wpa_supplicant/defconfig b/wpa_supplicant/defconfig
    -index 1d05198f..55313869 100644
    ---- a/wpa_supplicant/defconfig
    -+++ b/wpa_supplicant/defconfig
    -@@ -288,9 +288,6 @@ CONFIG_BACKEND=file
    - # bridge interfaces (commit 'bridge: respect RFC2863 operational state')').
    - #CONFIG_NO_LINUX_PACKET_SOCKET_WAR=y
    - 
    --# PeerKey handshake for Station to Station Link (IEEE 802.11e DLS)
    --CONFIG_PEERKEY=y
    --
    - # IEEE 802.11w (management frame protection), also known as PMF
    - # Driver support is also needed for IEEE 802.11w.
    - #CONFIG_IEEE80211W=y
    -diff --git a/wpa_supplicant/events.c b/wpa_supplicant/events.c
    -index 1b3d8a91..46f29240 100644
    ---- a/wpa_supplicant/events.c
    -+++ b/wpa_supplicant/events.c
    -@@ -2790,18 +2790,6 @@ wpa_supplicant_event_interface_status(struct wpa_supplicant *wpa_s,
    - }
    - 
    - 
    --#ifdef CONFIG_PEERKEY
    --static void
    --wpa_supplicant_event_stkstart(struct wpa_supplicant *wpa_s,
    --			      union wpa_event_data *data)
    --{
    --	if (data == NULL)
    --		return;
    --	wpa_sm_stkstart(wpa_s->wpa, data->stkstart.peer);
    --}
    --#endif /* CONFIG_PEERKEY */
    --
    --
    - #ifdef CONFIG_TDLS
    - static void wpa_supplicant_event_tdls(struct wpa_supplicant *wpa_s,
    - 				      union wpa_event_data *data)
    -@@ -3490,11 +3478,6 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event,
    - 	case EVENT_PMKID_CANDIDATE:
    - 		wpa_supplicant_event_pmkid_candidate(wpa_s, data);
    - 		break;
    --#ifdef CONFIG_PEERKEY
    --	case EVENT_STKSTART:
    --		wpa_supplicant_event_stkstart(wpa_s, data);
    --		break;
    --#endif /* CONFIG_PEERKEY */
    - #ifdef CONFIG_TDLS
    - 	case EVENT_TDLS:
    - 		wpa_supplicant_event_tdls(wpa_s, data);
    -diff --git a/wpa_supplicant/wnm_sta.c b/wpa_supplicant/wnm_sta.c
    -index f77d51ae..63a87aff 100644
    ---- a/wpa_supplicant/wnm_sta.c
    -+++ b/wpa_supplicant/wnm_sta.c
    -@@ -259,7 +259,7 @@ static void ieee802_11_rx_wnmsleep_resp(struct wpa_supplicant *wpa_s,
    - 
    - 	if (!wpa_s->wnmsleep_used) {
    - 		wpa_printf(MSG_DEBUG,
    --			   "WNM: Ignore WNM-Sleep Mode Response frame since WNM-Sleep Mode has not been used in this association");
    -+			   "WNM: Ignore WNM-Sleep Mode Response frame since WNM-Sleep Mode operation has not been requested");
    - 		return;
    - 	}
    - 
    -@@ -298,6 +298,8 @@ static void ieee802_11_rx_wnmsleep_resp(struct wpa_supplicant *wpa_s,
    - 		return;
    - 	}
    - 
    -+	wpa_s->wnmsleep_used = 0;
    -+
    - 	if (wnmsleep_ie->status == WNM_STATUS_SLEEP_ACCEPT ||
    - 	    wnmsleep_ie->status == WNM_STATUS_SLEEP_EXIT_ACCEPT_GTK_UPDATE) {
    - 		wpa_printf(MSG_DEBUG, "Successfully recv WNM-Sleep Response "
    -@@ -370,6 +372,10 @@ static void wnm_parse_neighbor_report_elem(struct neighbor_report *rep,
    - 		rep->preference_present = 1;
    - 		break;
    - 	case WNM_NEIGHBOR_BSS_TERMINATION_DURATION:
    -+		if (elen < 10) {
    -+			wpa_printf(MSG_DEBUG, "WNM: Too short bss_term_tsf");
    -+			break;
    -+		}
    - 		rep->bss_term_tsf = WPA_GET_LE64(pos);
    - 		rep->bss_term_dur = WPA_GET_LE16(pos + 8);
    - 		rep->bss_term_present = 1;
    -diff --git a/wpa_supplicant/wpa_cli.c b/wpa_supplicant/wpa_cli.c
    -index 36a7a4eb..ac1a36fb 100644
    ---- a/wpa_supplicant/wpa_cli.c
    -+++ b/wpa_supplicant/wpa_cli.c
    -@@ -861,13 +861,6 @@ static int wpa_cli_cmd_bss_flush(struct wpa_ctrl *ctrl, int argc, char *argv[])
    - }
    - 
    - 
    --static int wpa_cli_cmd_stkstart(struct wpa_ctrl *ctrl, int argc,
    --				char *argv[])
    --{
    --	return wpa_cli_cmd(ctrl, "STKSTART", 1, argc, argv);
    --}
    --
    --
    - static int wpa_cli_cmd_ft_ds(struct wpa_ctrl *ctrl, int argc, char *argv[])
    - {
    - 	return wpa_cli_cmd(ctrl, "FT_DS", 1, argc, argv);
    -@@ -1582,7 +1575,7 @@ static const char *network_fields[] = {
    - #ifdef CONFIG_IEEE80211W
    - 	"ieee80211w",
    - #endif /* CONFIG_IEEE80211W */
    --	"peerkey", "mixed_cell", "frequency", "fixed_freq",
    -+	"mixed_cell", "frequency", "fixed_freq",
    - #ifdef CONFIG_MESH
    - 	"mesh_basic_rates", "dot11MeshMaxRetries",
    - 	"dot11MeshRetryTimeout", "dot11MeshConfirmTimeout",
    -@@ -3107,9 +3100,6 @@ static const struct wpa_cli_cmd wpa_cli_commands[] = {
    - 	{ "bss_flush", wpa_cli_cmd_bss_flush, NULL,
    - 	  cli_cmd_flag_none,
    - 	  "<value> = set BSS flush age (0 by default)" },
    --	{ "stkstart", wpa_cli_cmd_stkstart, NULL,
    --	  cli_cmd_flag_none,
    --	  "<addr> = request STK negotiation with <addr>" },
    - 	{ "ft_ds", wpa_cli_cmd_ft_ds, wpa_cli_complete_bss,
    - 	  cli_cmd_flag_none,
    - 	  "<addr> = request over-the-DS FT with <addr>" },
    -diff --git a/wpa_supplicant/wpa_priv.c b/wpa_supplicant/wpa_priv.c
    -index 511df4f1..483b6d85 100644
    ---- a/wpa_supplicant/wpa_priv.c
    -+++ b/wpa_supplicant/wpa_priv.c
    -@@ -990,12 +990,6 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event,
    - 				    &data->pmkid_candidate,
    - 				    sizeof(struct pmkid_candidate));
    - 		break;
    --	case EVENT_STKSTART:
    --		if (data == NULL)
    --			return;
    --		wpa_priv_send_event(iface, PRIVSEP_EVENT_STKSTART,
    --				    &data->stkstart.peer, ETH_ALEN);
    --		break;
    - 	case EVENT_FT_RESPONSE:
    - 		wpa_priv_send_ft_response(iface, data);
    - 		break;
    -diff --git a/wpa_supplicant/wpa_supplicant.c b/wpa_supplicant/wpa_supplicant.c
    -index 51bb2457..aba93da1 100644
    ---- a/wpa_supplicant/wpa_supplicant.c
    -+++ b/wpa_supplicant/wpa_supplicant.c
    -@@ -3238,16 +3238,6 @@ void wpa_supplicant_rx_eapol(void *ctx, const u8 *src_addr,
    - 	wpa_dbg(wpa_s, MSG_DEBUG, "RX EAPOL from " MACSTR, MAC2STR(src_addr));
    - 	wpa_hexdump(MSG_MSGDUMP, "RX EAPOL", buf, len);
    - 
    --#ifdef CONFIG_PEERKEY
    --	if (wpa_s->wpa_state > WPA_ASSOCIATED && wpa_s->current_ssid &&
    --	    wpa_s->current_ssid->peerkey &&
    --	    !(wpa_s->drv_flags & WPA_DRIVER_FLAGS_4WAY_HANDSHAKE) &&
    --	    wpa_sm_rx_eapol_peerkey(wpa_s->wpa, src_addr, buf, len) == 1) {
    --		wpa_dbg(wpa_s, MSG_DEBUG, "RSN: Processed PeerKey EAPOL-Key");
    --		return;
    --	}
    --#endif /* CONFIG_PEERKEY */
    --
    - 	if (wpa_s->wpa_state < WPA_ASSOCIATED ||
    - 	    (wpa_s->last_eapol_matches_bssid &&
    - #ifdef CONFIG_AP
    -diff --git a/wpa_supplicant/wpa_supplicant.conf b/wpa_supplicant/wpa_supplicant.conf
    -index e55b380f..512116a0 100644
    ---- a/wpa_supplicant/wpa_supplicant.conf
    -+++ b/wpa_supplicant/wpa_supplicant.conf
    -@@ -865,12 +865,6 @@ fast_reauth=1
    - # hex without quotation, e.g., 0102030405)
    - # wep_tx_keyidx: Default WEP key index (TX) (0..3)
    - #
    --# peerkey: Whether PeerKey negotiation for direct links (IEEE 802.11e DLS) is
    --# allowed. This is only used with RSN/WPA2.
    --# 0 = disabled (default)
    --# 1 = enabled
    --#peerkey=1
    --#
    - # wpa_ptk_rekey: Maximum lifetime for PTK in seconds. This can be used to
    - # enforce rekeying of PTK to mitigate some attacks against TKIP deficiencies.
    - #
    -diff --git a/wpa_supplicant/wpa_supplicant_template.conf b/wpa_supplicant/wpa_supplicant_template.conf
    -index f3f2a641..d5110295 100644
    ---- a/wpa_supplicant/wpa_supplicant_template.conf
    -+++ b/wpa_supplicant/wpa_supplicant_template.conf
    -@@ -3,4 +3,4 @@ update_config=1
    - eapol_version=1
    - ap_scan=1
    - fast_reauth=1
    --pmf=1
    -+pmf=0
    -diff --git a/wpa_supplicant/wpas_glue.c b/wpa_supplicant/wpas_glue.c
    -index f84c8b90..8c1d4fcb 100644
    ---- a/wpa_supplicant/wpas_glue.c
    -+++ b/wpa_supplicant/wpas_glue.c
    -@@ -1105,7 +1105,6 @@ void wpa_supplicant_rsn_supp_set_config(struct wpa_supplicant *wpa_s,
    - 	if (ssid) {
    - 		os_memset(&conf, 0, sizeof(conf));
    - 		conf.network_ctx = ssid;
    --		conf.peerkey_enabled = ssid->peerkey;
    - 		conf.allowed_pairwise_cipher = ssid->pairwise_cipher;
    - #ifdef IEEE8021X_EAPOL
    - 		conf.proactive_key_caching = ssid->proactive_key_caching < 0 ?
    diff --git a/frameworks_av.patch b/frameworks_av.patch
    index 2ff125c..5a658dd 100644
    --- a/frameworks_av.patch
    +++ b/frameworks_av.patch
    @@ -1,5 +1,5 @@
     diff --git a/camera/ICameraClient.cpp b/camera/ICameraClient.cpp
    -index 68cbfb8e4..8a7430fd1 100644
    +index 68cbfb8e43..8a7430fd15 100644
     --- a/camera/ICameraClient.cpp
     +++ b/camera/ICameraClient.cpp
     @@ -50,7 +50,12 @@ public:
    @@ -34,7 +34,7 @@ index 68cbfb8e4..8a7430fd1 100644
                  return NO_ERROR;
              } break;
     diff --git a/camera/cameraserver/Android.mk b/camera/cameraserver/Android.mk
    -index 7e36c5e74..aca7a190c 100644
    +index 7e36c5e74a..aca7a190c6 100644
     --- a/camera/cameraserver/Android.mk
     +++ b/camera/cameraserver/Android.mk
     @@ -14,6 +14,9 @@
    @@ -53,7 +53,7 @@ index 7e36c5e74..aca7a190c 100644
      include $(BUILD_EXECUTABLE)
     +endif
     diff --git a/camera/cameraserver/main_cameraserver.cpp b/camera/cameraserver/main_cameraserver.cpp
    -index f4be468e4..ea80ad49d 100644
    +index f4be468e4e..ea80ad49d0 100644
     --- a/camera/cameraserver/main_cameraserver.cpp
     +++ b/camera/cameraserver/main_cameraserver.cpp
     @@ -31,5 +31,6 @@ int main(int argc __unused, char** argv __unused)
    @@ -64,7 +64,7 @@ index f4be468e4..ea80ad49d 100644
          IPCThreadState::self()->joinThreadPool();
      }
     diff --git a/camera/ndk/NdkCaptureRequest.cpp b/camera/ndk/NdkCaptureRequest.cpp
    -index 77b9a3390..7c3795502 100644
    +index 77b9a3390f..7c37955027 100644
     --- a/camera/ndk/NdkCaptureRequest.cpp
     +++ b/camera/ndk/NdkCaptureRequest.cpp
     @@ -51,8 +51,13 @@ camera_status_t ACaptureRequest_addTarget(
    @@ -98,7 +98,7 @@ index 77b9a3390..7c3795502 100644
          }
          req->targets->mOutputs.erase(*target);
     diff --git a/cmds/stagefright/stagefright.cpp b/cmds/stagefright/stagefright.cpp
    -index ca68722c5..cd284f697 100644
    +index ca68722c5a..cd284f6972 100644
     --- a/cmds/stagefright/stagefright.cpp
     +++ b/cmds/stagefright/stagefright.cpp
     @@ -1037,6 +1037,10 @@ int main(int argc, char **argv) {
    @@ -124,7 +124,7 @@ index ca68722c5..cd284f697 100644
              }
      
     diff --git a/cmds/stagefright/stream.cpp b/cmds/stagefright/stream.cpp
    -index bca383211..cf593577f 100644
    +index bca3832111..cf593577f3 100644
     --- a/cmds/stagefright/stream.cpp
     +++ b/cmds/stagefright/stream.cpp
     @@ -171,7 +171,8 @@ MyConvertingStreamSource::MyConvertingStreamSource(const char *filename)
    @@ -152,7 +152,7 @@ index bca383211..cf593577f 100644
      
          CHECK_EQ(mWriter->start(), (status_t)OK);
     diff --git a/drm/mediadrm/plugins/clearkey/AesCtrDecryptor.cpp b/drm/mediadrm/plugins/clearkey/AesCtrDecryptor.cpp
    -index 01f8d6570..f7106b275 100644
    +index 01f8d65702..f7106b275e 100644
     --- a/drm/mediadrm/plugins/clearkey/AesCtrDecryptor.cpp
     +++ b/drm/mediadrm/plugins/clearkey/AesCtrDecryptor.cpp
     @@ -36,6 +36,11 @@ android::status_t AesCtrDecryptor::decrypt(const android::Vector<uint8_t>& key,
    @@ -168,7 +168,7 @@ index 01f8d6570..f7106b275 100644
          AES_KEY opensslKey;
          AES_set_encrypt_key(key.array(), kBlockBitCount, &opensslKey);
     diff --git a/drm/mediadrm/plugins/clearkey/AesCtrDecryptor.h b/drm/mediadrm/plugins/clearkey/AesCtrDecryptor.h
    -index b416266dd..edb84458a 100644
    +index b416266ddf..edb84458a7 100644
     --- a/drm/mediadrm/plugins/clearkey/AesCtrDecryptor.h
     +++ b/drm/mediadrm/plugins/clearkey/AesCtrDecryptor.h
     @@ -18,6 +18,7 @@
    @@ -180,7 +180,7 @@ index b416266dd..edb84458a 100644
      #include <utils/Errors.h>
      #include <utils/Vector.h>
     diff --git a/drm/mediadrm/plugins/clearkey/tests/AesCtrDecryptorUnittest.cpp b/drm/mediadrm/plugins/clearkey/tests/AesCtrDecryptorUnittest.cpp
    -index 039e40226..5db8290a9 100644
    +index 039e40226b..5db8290a91 100644
     --- a/drm/mediadrm/plugins/clearkey/tests/AesCtrDecryptorUnittest.cpp
     +++ b/drm/mediadrm/plugins/clearkey/tests/AesCtrDecryptorUnittest.cpp
     @@ -34,7 +34,7 @@ class AesCtrDecryptorTest : public ::testing::Test {
    @@ -261,7 +261,7 @@ index 039e40226..5db8290a9 100644
          const size_t kTotalSize = 64;
          const size_t kNumSubsamples = 1;
     diff --git a/include/media/IAudioPolicyService.h b/include/media/IAudioPolicyService.h
    -index 0e9e3bc89..9ffcc77f0 100644
    +index 0e9e3bc89b..9ffcc77f0e 100644
     --- a/include/media/IAudioPolicyService.h
     +++ b/include/media/IAudioPolicyService.h
     @@ -181,6 +181,10 @@ public:
    @@ -276,7 +276,7 @@ index 0e9e3bc89..9ffcc77f0 100644
      
      // ----------------------------------------------------------------------------
     diff --git a/include/media/IMediaExtractor.h b/include/media/IMediaExtractor.h
    -index 34b15e928..743ef7f83 100644
    +index 34b15e9287..743ef7f834 100644
     --- a/include/media/IMediaExtractor.h
     +++ b/include/media/IMediaExtractor.h
     @@ -30,6 +30,9 @@ public:
    @@ -290,7 +290,7 @@ index 34b15e928..743ef7f83 100644
      
          enum GetTrackMetaDataFlags {
     diff --git a/include/media/MediaPlayerInterface.h b/include/media/MediaPlayerInterface.h
    -index 4977efd65..c1bd8eb3e 100644
    +index 4977efd65f..c1bd8eb3ee 100644
     --- a/include/media/MediaPlayerInterface.h
     +++ b/include/media/MediaPlayerInterface.h
     @@ -65,14 +65,17 @@ enum player_type {
    @@ -365,7 +365,7 @@ index 4977efd65..c1bd8eb3e 100644
      
      // Implement this class for media players that use the AudioFlinger software mixer
     diff --git a/include/media/stagefright/MediaBufferGroup.h b/include/media/stagefright/MediaBufferGroup.h
    -index 30514062d..870bb9b9d 100644
    +index 30514062da..870bb9b9db 100644
     --- a/include/media/stagefright/MediaBufferGroup.h
     +++ b/include/media/stagefright/MediaBufferGroup.h
     @@ -49,7 +49,10 @@ public:
    @@ -381,7 +381,7 @@ index 30514062d..870bb9b9d 100644
          size_t buffers() const { return mBuffers.size(); }
      
     diff --git a/media/libeffects/downmix/EffectDownmix.c b/media/libeffects/downmix/EffectDownmix.c
    -index 9823c5516..cb4be7503 100644
    +index 9823c55167..cb4be75032 100644
     --- a/media/libeffects/downmix/EffectDownmix.c
     +++ b/media/libeffects/downmix/EffectDownmix.c
     @@ -445,6 +445,10 @@ static int Downmix_Command(effect_handle_t self, uint32_t cmdCode, uint32_t cmdS
    @@ -396,7 +396,7 @@ index 9823c5516..cb4be7503 100644
                      cmd->vsize, cmd->data + sizeof(int32_t));
              break;
     diff --git a/media/libeffects/lvm/wrapper/Bundle/EffectBundle.cpp b/media/libeffects/lvm/wrapper/Bundle/EffectBundle.cpp
    -index dcf3fa0a5..8a248e50c 100644
    +index dcf3fa0a5e..8a248e50cf 100644
     --- a/media/libeffects/lvm/wrapper/Bundle/EffectBundle.cpp
     +++ b/media/libeffects/lvm/wrapper/Bundle/EffectBundle.cpp
     @@ -33,6 +33,15 @@
    @@ -1753,7 +1753,7 @@ index dcf3fa0a5..8a248e50c 100644
                  //ALOGV("\tEffect_command cmdCode Case: EFFECT_CMD_SET_PARAM end");
              } break;
     diff --git a/media/libeffects/lvm/wrapper/Reverb/EffectReverb.cpp b/media/libeffects/lvm/wrapper/Reverb/EffectReverb.cpp
    -index 4dc8b4592..80c8a3878 100644
    +index 4dc8b45926..80c8a3878f 100644
     --- a/media/libeffects/lvm/wrapper/Reverb/EffectReverb.cpp
     +++ b/media/libeffects/lvm/wrapper/Reverb/EffectReverb.cpp
     @@ -180,12 +180,13 @@ int  Reverb_init            (ReverbContext *pContext);
    @@ -1852,7 +1852,7 @@ index 4dc8b4592..80c8a3878 100644
      
              case EFFECT_CMD_ENABLE:
     diff --git a/media/libmedia/IAudioPolicyService.cpp b/media/libmedia/IAudioPolicyService.cpp
    -index 6405d6de5..be826abda 100644
    +index 6405d6de58..be826abda0 100644
     --- a/media/libmedia/IAudioPolicyService.cpp
     +++ b/media/libmedia/IAudioPolicyService.cpp
     @@ -873,7 +873,7 @@ status_t BnAudioPolicyService::onTransact(
    @@ -2024,7 +2024,7 @@ index 6405d6de5..be826abda 100644
      
      } // namespace android
     diff --git a/media/libmedia/ICrypto.cpp b/media/libmedia/ICrypto.cpp
    -index 302e6ee9a..0045cffc6 100644
    +index 302e6ee9a9..0045cffc6e 100644
     --- a/media/libmedia/ICrypto.cpp
     +++ b/media/libmedia/ICrypto.cpp
     @@ -199,8 +199,13 @@ IMPLEMENT_META_INTERFACE(Crypto, "android.hardware.ICrypto");
    @@ -2044,7 +2044,7 @@ index 302e6ee9a..0045cffc6 100644
      
      void BnCrypto::writeVector(Parcel *reply, Vector<uint8_t> const &vector) const {
     diff --git a/media/libmedia/IDataSource.cpp b/media/libmedia/IDataSource.cpp
    -index 51c9938f6..5ad39fe81 100644
    +index 51c9938f66..5ad39fe81c 100644
     --- a/media/libmedia/IDataSource.cpp
     +++ b/media/libmedia/IDataSource.cpp
     @@ -54,8 +54,16 @@ struct BpDataSource : public BpInterface<IDataSource> {
    @@ -2067,7 +2067,7 @@ index 51c9938f6..5ad39fe81 100644
      
          virtual status_t getSize(off64_t* size) {
     diff --git a/media/libmedia/IDrm.cpp b/media/libmedia/IDrm.cpp
    -index 51a113031..393286dcf 100644
    +index 51a113031d..393286dcf8 100644
     --- a/media/libmedia/IDrm.cpp
     +++ b/media/libmedia/IDrm.cpp
     @@ -559,8 +559,13 @@ IMPLEMENT_META_INTERFACE(Drm, "android.drm.IDrm");
    @@ -2087,7 +2087,7 @@ index 51a113031..393286dcf 100644
      
      void BnDrm::writeVector(Parcel *reply, Vector<uint8_t> const &vector) const {
     diff --git a/media/libmedia/IMediaExtractor.cpp b/media/libmedia/IMediaExtractor.cpp
    -index 72d1d7c57..744af1be0 100644
    +index 72d1d7c57f..744af1be00 100644
     --- a/media/libmedia/IMediaExtractor.cpp
     +++ b/media/libmedia/IMediaExtractor.cpp
     @@ -23,6 +23,7 @@
    @@ -2165,7 +2165,7 @@ index 72d1d7c57..744af1be0 100644
          }
          write(fd, out.string(), out.size());
     diff --git a/media/libmediaplayerservice/MediaPlayerFactory.cpp b/media/libmediaplayerservice/MediaPlayerFactory.cpp
    -index 605c71014..f5ec20c38 100644
    +index 605c71014b..f5ec20c389 100644
     --- a/media/libmediaplayerservice/MediaPlayerFactory.cpp
     +++ b/media/libmediaplayerservice/MediaPlayerFactory.cpp
     @@ -127,8 +127,7 @@ player_type MediaPlayerFactory::getPlayerType(const sp<IMediaPlayer>& client,
    @@ -2188,7 +2188,7 @@ index 605c71014..f5ec20c38 100644
              ALOGE("Failed to create player object of type %d, initCheck failed"
                    " (res = %d)", playerType, init_result);
     diff --git a/media/libmediaplayerservice/MediaPlayerFactory.h b/media/libmediaplayerservice/MediaPlayerFactory.h
    -index e22a56fe6..e88700cf5 100644
    +index e22a56fe6e..e88700cf58 100644
     --- a/media/libmediaplayerservice/MediaPlayerFactory.h
     +++ b/media/libmediaplayerservice/MediaPlayerFactory.h
     @@ -65,8 +65,7 @@ class MediaPlayerFactory {
    @@ -2202,7 +2202,7 @@ index e22a56fe6..e88700cf5 100644
      
          static void registerBuiltinFactories();
     diff --git a/media/libmediaplayerservice/MediaPlayerService.cpp b/media/libmediaplayerservice/MediaPlayerService.cpp
    -index bd16e91e3..7196f420f 100644
    +index bd16e91e36..7196f420ff 100644
     --- a/media/libmediaplayerservice/MediaPlayerService.cpp
     +++ b/media/libmediaplayerservice/MediaPlayerService.cpp
     @@ -82,6 +82,9 @@
    @@ -2412,7 +2412,7 @@ index bd16e91e3..7196f420f 100644
              usleep(interval);
          }
     diff --git a/media/libmediaplayerservice/MediaPlayerService.h b/media/libmediaplayerservice/MediaPlayerService.h
    -index 7a41d9cfe..99b1d4dfa 100644
    +index 7a41d9cfe4..99b1d4dfa1 100644
     --- a/media/libmediaplayerservice/MediaPlayerService.h
     +++ b/media/libmediaplayerservice/MediaPlayerService.h
     @@ -49,7 +49,7 @@ class MediaRecorderClient;
    @@ -2526,7 +2526,7 @@ index 7a41d9cfe..99b1d4dfa 100644
          }; // Client
      
     diff --git a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp
    -index dc4e5d4a3..b64d899b1 100644
    +index dc4e5d4a36..b64d899b13 100644
     --- a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp
     +++ b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp
     @@ -1534,6 +1534,7 @@ void NuPlayer::restartAudio(
    @@ -2548,8 +2548,66 @@ index dc4e5d4a3..b64d899b1 100644
      }
      
      void NuPlayer::determineAudioModeChange(const sp<AMessage> &audioFormat) {
    +diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerCCDecoder.cpp b/media/libmediaplayerservice/nuplayer/NuPlayerCCDecoder.cpp
    +index 13716cf4c7..eec1731c88 100644
    +--- a/media/libmediaplayerservice/nuplayer/NuPlayerCCDecoder.cpp
    ++++ b/media/libmediaplayerservice/nuplayer/NuPlayerCCDecoder.cpp
    +@@ -308,6 +308,11 @@ bool NuPlayer::CCDecoder::extractFromMPEGUserData(const sp<ABuffer> &accessUnit)
    +     const size_t *userData = (size_t *)mpegUserData->data();
    + 
    +     for (size_t i = 0; i < mpegUserData->size() / sizeof(size_t); ++i) {
    ++        if (accessUnit->size() < userData[i]) {
    ++            ALOGW("b/129068792, skip invalid offset for user data");
    ++            android_errorWriteLog(0x534e4554, "129068792");
    ++            continue;
    ++        }
    +         trackAdded |= parseMPEGUserDataUnit(
    +                 timeUs, accessUnit->data() + userData[i], accessUnit->size() - userData[i]);
    +     }
    +@@ -317,6 +322,12 @@ bool NuPlayer::CCDecoder::extractFromMPEGUserData(const sp<ABuffer> &accessUnit)
    + 
    + // returns true if a new CC track is found
    + bool NuPlayer::CCDecoder::parseMPEGUserDataUnit(int64_t timeUs, const uint8_t *data, size_t size) {
    ++    if (size < 9) {
    ++        ALOGW("b/129068792, MPEG user data size too small %zu", size);
    ++        android_errorWriteLog(0x534e4554, "129068792");
    ++        return false;
    ++    }
    ++
    +     ABitReader br(data + 4, 5);
    + 
    +     uint32_t user_identifier = br.getBits(32);
    +@@ -369,8 +380,14 @@ bool NuPlayer::CCDecoder::parseMPEGCCData(int64_t timeUs, const uint8_t *data, s
    +                 mDTVCCPacket->setRange(0, mDTVCCPacket->size() + 2);
    +                 br.skipBits(16);
    +             } else if (mDTVCCPacket->size() > 0 && cc_type == 2) {
    +-                memcpy(mDTVCCPacket->data() + mDTVCCPacket->size(), br.data(), 2);
    +-                mDTVCCPacket->setRange(0, mDTVCCPacket->size() + 2);
    ++                if (mDTVCCPacket->capacity() - mDTVCCPacket->size() >= 2) {
    ++                    memcpy(mDTVCCPacket->data() + mDTVCCPacket->size(), br.data(), 2);
    ++                    mDTVCCPacket->setRange(0, mDTVCCPacket->size() + 2);
    ++                } else {
    ++                    ALOGW("b/129068792, skip CC due to too much data(%zu, %zu)",
    ++                          mDTVCCPacket->capacity(), mDTVCCPacket->size());
    ++                    android_errorWriteLog(0x534e4554, "129068792");
    ++                }
    +                 br.skipBits(16);
    +             } else if (cc_type == 0 || cc_type == 1) {
    +                 uint8_t cc_data_1 = br.getBits(8) & 0x7f;
    +@@ -457,6 +474,11 @@ bool NuPlayer::CCDecoder::parseDTVCCPacket(int64_t timeUs, const uint8_t *data,
    +             size_t trackIndex = getTrackIndex(kTrackTypeCEA708, service_number, &trackAdded);
    +             if (mSelectedTrack == (ssize_t)trackIndex) {
    +                 sp<ABuffer> ccPacket = new ABuffer(block_size);
    ++                if (ccPacket->capacity() == 0) {
    ++                    ALOGW("b/129068792, no memory available, %zu", block_size);
    ++                    android_errorWriteLog(0x534e4554, "129068792");
    ++                    return false;
    ++                }
    +                 memcpy(ccPacket->data(), br.data(), block_size);
    +                 mCCMap.add(timeUs, ccPacket);
    +             }
     diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp b/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp
    -index 594128c83..caaa7356b 100644
    +index 594128c835..caaa7356b9 100644
     --- a/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp
     +++ b/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp
     @@ -631,6 +631,11 @@ bool NuPlayer::Decoder::handleAnOutputBuffer(
    @@ -2565,7 +2623,7 @@ index 594128c83..caaa7356b 100644
              for (size_t i = mOutputBuffers.size(); i <= index; ++i) {
                  mOutputBuffers.add();
     diff --git a/media/libstagefright/AACExtractor.cpp b/media/libstagefright/AACExtractor.cpp
    -index 7449aa7d9..3ba18586b 100644
    +index 7449aa7d90..3ba18586b4 100644
     --- a/media/libstagefright/AACExtractor.cpp
     +++ b/media/libstagefright/AACExtractor.cpp
     @@ -294,6 +294,10 @@ status_t AACSource::read(
    @@ -2580,7 +2638,7 @@ index 7449aa7d9..3ba18586b 100644
      
                  mOffset = mOffsetVector.itemAt(seekFrame);
     diff --git a/media/libstagefright/ACodec.cpp b/media/libstagefright/ACodec.cpp
    -index 37fd5a51e..337fb2de5 100644
    +index 37fd5a51e3..337fb2de5e 100644
     --- a/media/libstagefright/ACodec.cpp
     +++ b/media/libstagefright/ACodec.cpp
     @@ -804,13 +804,22 @@ status_t ACodec::allocateBuffersOnPort(OMX_U32 portIndex) {
    @@ -2740,7 +2798,7 @@ index 37fd5a51e..337fb2de5 100644
      
          if (err == OK) {
     diff --git a/media/libstagefright/Android.mk b/media/libstagefright/Android.mk
    -index 38485021e..07f926c77 100644
    +index 38485021e0..07f926c77b 100644
     --- a/media/libstagefright/Android.mk
     +++ b/media/libstagefright/Android.mk
     @@ -102,6 +102,10 @@ LOCAL_SHARED_LIBRARIES := \
    @@ -2777,7 +2835,7 @@ index 38485021e..07f926c77 100644
      LOCAL_SANITIZE := unsigned-integer-overflow signed-integer-overflow
      
     diff --git a/media/libstagefright/CameraSource.cpp b/media/libstagefright/CameraSource.cpp
    -index 893da89bb..215245472 100644
    +index 893da89bbb..215245472d 100644
     --- a/media/libstagefright/CameraSource.cpp
     +++ b/media/libstagefright/CameraSource.cpp
     @@ -950,6 +950,14 @@ void CameraSource::releaseRecordingFrame(const sp<IMemory>& frame) {
    @@ -2816,7 +2874,7 @@ index 893da89bb..215245472 100644
          // buffer queue.
          switch (mVideoBufferMode) {
     diff --git a/media/libstagefright/MPEG4Extractor.cpp b/media/libstagefright/MPEG4Extractor.cpp
    -index 544171496..d1603c1ef 100644
    +index 544171496c..d1603c1efe 100644
     --- a/media/libstagefright/MPEG4Extractor.cpp
     +++ b/media/libstagefright/MPEG4Extractor.cpp
     @@ -72,6 +72,7 @@ public:
    @@ -3079,7 +3137,7 @@ index 544171496..d1603c1ef 100644
              }
          }
     diff --git a/media/libstagefright/MPEG4Writer.cpp b/media/libstagefright/MPEG4Writer.cpp
    -index 5e96c2b25..6ca2abb93 100644
    +index 5e96c2b251..6ca2abb937 100644
     --- a/media/libstagefright/MPEG4Writer.cpp
     +++ b/media/libstagefright/MPEG4Writer.cpp
     @@ -1674,10 +1674,12 @@ void MPEG4Writer::Track::getCodecSpecificDataFromInputFormatIfPossible() {
    @@ -3099,7 +3157,7 @@ index 5e96c2b25..6ca2abb93 100644
          }
          if (data != NULL && copyCodecSpecificData((uint8_t *)data, size) == OK) {
     diff --git a/media/libstagefright/MediaCodecList.cpp b/media/libstagefright/MediaCodecList.cpp
    -index 0fb5072a4..a25c47d12 100644
    +index 0fb5072a45..a25c47d127 100644
     --- a/media/libstagefright/MediaCodecList.cpp
     +++ b/media/libstagefright/MediaCodecList.cpp
     @@ -1165,7 +1165,9 @@ void MediaCodecList::findMatchingCodecs(
    @@ -3114,7 +3172,7 @@ index 0fb5072a4..a25c47d12 100644
                  ALOGV("matching '%s'", componentName.c_str());
              }
     diff --git a/media/libstagefright/MediaSource.cpp b/media/libstagefright/MediaSource.cpp
    -index a17757a8e..f1ad5c573 100644
    +index a17757a8eb..f1ad5c5731 100644
     --- a/media/libstagefright/MediaSource.cpp
     +++ b/media/libstagefright/MediaSource.cpp
     @@ -22,4 +22,10 @@ MediaSource::MediaSource() {}
    @@ -3129,7 +3187,7 @@ index a17757a8e..f1ad5c573 100644
     +}
      }  // namespace android
     diff --git a/media/libstagefright/MidiExtractor.cpp b/media/libstagefright/MidiExtractor.cpp
    -index 7930bbb63..214513403 100644
    +index 7930bbb63c..214513403b 100644
     --- a/media/libstagefright/MidiExtractor.cpp
     +++ b/media/libstagefright/MidiExtractor.cpp
     @@ -246,8 +246,9 @@ MediaBuffer* MidiEngine::readBuffer() {
    @@ -3145,7 +3203,7 @@ index 7930bbb63..214513403 100644
              p += numRendered * mEasConfig->numChannels;
              numBytesOutput += numRendered * mEasConfig->numChannels * sizeof(EAS_PCM);
     diff --git a/media/libstagefright/NuMediaExtractor.cpp b/media/libstagefright/NuMediaExtractor.cpp
    -index 4558b3c1c..c3e8f2047 100644
    +index 4558b3c1cf..c3e8f20473 100644
     --- a/media/libstagefright/NuMediaExtractor.cpp
     +++ b/media/libstagefright/NuMediaExtractor.cpp
     @@ -305,6 +305,10 @@ status_t NuMediaExtractor::selectTrack(size_t index) {
    @@ -3160,7 +3218,7 @@ index 4558b3c1c..c3e8f2047 100644
          if (ret != OK) {
              return ret;
     diff --git a/media/libstagefright/OggExtractor.cpp b/media/libstagefright/OggExtractor.cpp
    -index ebbe5102e..752f2fe20 100644
    +index ebbe5102ed..752f2fe20c 100644
     --- a/media/libstagefright/OggExtractor.cpp
     +++ b/media/libstagefright/OggExtractor.cpp
     @@ -578,6 +578,10 @@ status_t MyOpusExtractor::readNextPacket(MediaBuffer **out) {
    @@ -3175,7 +3233,7 @@ index ebbe5102e..752f2fe20 100644
                  }
                  curGranulePosition = mCurrentPage.mGranulePosition;
     diff --git a/media/libstagefright/SampleTable.cpp b/media/libstagefright/SampleTable.cpp
    -index ee5fdf041..597896b28 100644
    +index ee5fdf0419..597896b284 100644
     --- a/media/libstagefright/SampleTable.cpp
     +++ b/media/libstagefright/SampleTable.cpp
     @@ -517,6 +517,8 @@ status_t SampleTable::setSyncSampleParams(off64_t data_offset, size_t data_size)
    @@ -3202,7 +3260,7 @@ index ee5fdf041..597896b28 100644
      }  // namespace android
     -
     diff --git a/media/libstagefright/StagefrightMetadataRetriever.cpp b/media/libstagefright/StagefrightMetadataRetriever.cpp
    -index be5067d59..2fef7caeb 100644
    +index be5067d59d..2fef7caebe 100644
     --- a/media/libstagefright/StagefrightMetadataRetriever.cpp
     +++ b/media/libstagefright/StagefrightMetadataRetriever.cpp
     @@ -483,6 +483,10 @@ VideoFrame *StagefrightMetadataRetriever::getFrameAtTime(
    @@ -3238,7 +3296,7 @@ index be5067d59..2fef7caeb 100644
              int64_t durationUs;
              if (trackMeta->findInt64(kKeyDuration, &durationUs)) {
     diff --git a/media/libstagefright/SurfaceMediaSource.cpp b/media/libstagefright/SurfaceMediaSource.cpp
    -index 15ff5697d..547267ce0 100644
    +index 15ff5697d9..547267ce07 100644
     --- a/media/libstagefright/SurfaceMediaSource.cpp
     +++ b/media/libstagefright/SurfaceMediaSource.cpp
     @@ -129,7 +129,11 @@ status_t SurfaceMediaSource::setFrameRate(int32_t fps)
    @@ -3328,7 +3386,7 @@ index 15ff5697d..547267ce0 100644
                          mSlots[id].mGraphicBuffer->handle);
      
     diff --git a/media/libstagefright/VideoFrameScheduler.cpp b/media/libstagefright/VideoFrameScheduler.cpp
    -index 03226c753..6819bba40 100644
    +index 03226c753e..6819bba40c 100644
     --- a/media/libstagefright/VideoFrameScheduler.cpp
     +++ b/media/libstagefright/VideoFrameScheduler.cpp
     @@ -129,6 +129,11 @@ bool VideoFrameScheduler::PLL::fit(
    @@ -3344,7 +3402,7 @@ index 03226c753..6819bba40 100644
          int64_t sumXX = 0;
          int64_t sumXY = 0;
     diff --git a/media/libstagefright/avc_utils.cpp b/media/libstagefright/avc_utils.cpp
    -index 763381e1c..78aae8cc2 100644
    +index 763381e1c7..78aae8cc24 100644
     --- a/media/libstagefright/avc_utils.cpp
     +++ b/media/libstagefright/avc_utils.cpp
     @@ -330,7 +330,7 @@ static sp<ABuffer> FindNAL(const uint8_t *data, size_t size, unsigned nalType) {
    @@ -3369,7 +3427,7 @@ index 763381e1c..78aae8cc2 100644
              unsigned nalType = nalStart[0] & 0x1f;
      
     diff --git a/media/libstagefright/codecs/aacenc/SoftAACEncoder2.cpp b/media/libstagefright/codecs/aacenc/SoftAACEncoder2.cpp
    -index f00a5d1b0..44415e2e0 100644
    +index f00a5d1b0c..44415e2e01 100644
     --- a/media/libstagefright/codecs/aacenc/SoftAACEncoder2.cpp
     +++ b/media/libstagefright/codecs/aacenc/SoftAACEncoder2.cpp
     @@ -16,6 +16,7 @@
    @@ -3413,7 +3471,7 @@ index f00a5d1b0..44415e2e0 100644
          mSentCodecSpecificData = false;
          mInputTimeUs = -1ll;
     diff --git a/media/libstagefright/codecs/aacenc/SoftAACEncoder2.h b/media/libstagefright/codecs/aacenc/SoftAACEncoder2.h
    -index f1b81e18f..123fd253f 100644
    +index f1b81e18f6..123fd253f7 100644
     --- a/media/libstagefright/codecs/aacenc/SoftAACEncoder2.h
     +++ b/media/libstagefright/codecs/aacenc/SoftAACEncoder2.h
     @@ -62,6 +62,7 @@ private:
    @@ -3424,8 +3482,70 @@ index f1b81e18f..123fd253f 100644
          int64_t mInputTimeUs;
      
          bool mSawInputEOS;
    +diff --git a/media/libstagefright/codecs/amrwbenc/Android.mk b/media/libstagefright/codecs/amrwbenc/Android.mk
    +index 026006e23f..006a034007 100644
    +--- a/media/libstagefright/codecs/amrwbenc/Android.mk
    ++++ b/media/libstagefright/codecs/amrwbenc/Android.mk
    +@@ -92,7 +92,8 @@ LOCAL_ARM_MODE := arm
    + 
    + LOCAL_STATIC_LIBRARIES :=
    + 
    +-LOCAL_SHARED_LIBRARIES :=
    ++LOCAL_SHARED_LIBRARIES := \
    ++        liblog
    + 
    + LOCAL_C_INCLUDES := \
    + 	frameworks/av/include \
    +diff --git a/media/libstagefright/codecs/amrwbenc/SampleCode/Android.mk b/media/libstagefright/codecs/amrwbenc/SampleCode/Android.mk
    +index 65d69a2c28..0d6549eea7 100644
    +--- a/media/libstagefright/codecs/amrwbenc/SampleCode/Android.mk
    ++++ b/media/libstagefright/codecs/amrwbenc/SampleCode/Android.mk
    +@@ -14,7 +14,8 @@ LOCAL_CFLAGS :=
    + 
    + LOCAL_SHARED_LIBRARIES := \
    +     libstagefright \
    +-    libdl
    ++    libdl \
    ++    liblog
    + 
    + LOCAL_STATIC_LIBRARIES := \
    +     libstagefright_amrwbenc
    +diff --git a/media/libstagefright/codecs/amrwbenc/src/c4t64fx.c b/media/libstagefright/codecs/amrwbenc/src/c4t64fx.c
    +index 8cebb097bd..b26eedb508 100644
    +--- a/media/libstagefright/codecs/amrwbenc/src/c4t64fx.c
    ++++ b/media/libstagefright/codecs/amrwbenc/src/c4t64fx.c
    +@@ -47,6 +47,10 @@
    + 
    + #include "q_pulse.h"
    + 
    ++#undef LOG_TAG
    ++#define LOG_TAG "amrwbenc"
    ++#include <log/log.h>
    ++
    + static Word16 tipos[36] = {
    +     0, 1, 2, 3,                            /* starting point &ipos[0], 1st iter */
    +     1, 2, 3, 0,                            /* starting point &ipos[4], 2nd iter */
    +@@ -745,11 +749,16 @@ void ACELP_4t64_fx(
    + 
    +         i = (Word16)((vo_L_mult(track, NPMAXPT) >> 1));
    + 
    +-        while (ind[i] >= 0)
    ++        while (i < NPMAXPT * NB_TRACK && ind[i] >= 0)
    +         {
    +             i += 1;
    +         }
    +-        ind[i] = index;
    ++        if (i < NPMAXPT * NB_TRACK) {
    ++            ind[i] = index;
    ++        } else {
    ++            ALOGE("b/132647222, OOB access in ind array track=%d i=%d", track, i);
    ++            android_errorWriteLog(0x534e4554, "132647222");
    ++        }
    +     }
    + 
    +     k = 0;
     diff --git a/media/libstagefright/codecs/avcdec/SoftAVCDec.cpp b/media/libstagefright/codecs/avcdec/SoftAVCDec.cpp
    -index cecc52bb1..43ef4a455 100644
    +index cecc52bb11..43ef4a455f 100644
     --- a/media/libstagefright/codecs/avcdec/SoftAVCDec.cpp
     +++ b/media/libstagefright/codecs/avcdec/SoftAVCDec.cpp
     @@ -318,10 +318,6 @@ status_t SoftAVC::initDecoder() {
    @@ -3460,7 +3580,7 @@ index cecc52bb1..43ef4a455 100644
      
                      mReceivedEOS = true;
     diff --git a/media/libstagefright/codecs/avcenc/SoftAVCEnc.cpp b/media/libstagefright/codecs/avcenc/SoftAVCEnc.cpp
    -index 5b06722fb..7bfa051ce 100644
    +index 5b06722fbc..7bfa051ce8 100644
     --- a/media/libstagefright/codecs/avcenc/SoftAVCEnc.cpp
     +++ b/media/libstagefright/codecs/avcenc/SoftAVCEnc.cpp
     @@ -1191,6 +1191,12 @@ OMX_ERRORTYPE SoftAVC::setEncodeArgs(
    @@ -3477,7 +3597,7 @@ index 5b06722fb..7bfa051ce 100644
      
              if (mInputDataIsMeta) {
     diff --git a/media/libstagefright/codecs/hevcdec/SoftHEVC.cpp b/media/libstagefright/codecs/hevcdec/SoftHEVC.cpp
    -index 5c70387f4..194a078e1 100644
    +index 5c70387f4e..194a078e12 100644
     --- a/media/libstagefright/codecs/hevcdec/SoftHEVC.cpp
     +++ b/media/libstagefright/codecs/hevcdec/SoftHEVC.cpp
     @@ -320,10 +320,6 @@ status_t SoftHEVC::initDecoder() {
    @@ -3503,7 +3623,7 @@ index 5c70387f4..194a078e1 100644
      
          /* Reset the plugin state */
     diff --git a/media/libstagefright/codecs/m4v_h263/dec/src/vlc_decode.cpp b/media/libstagefright/codecs/m4v_h263/dec/src/vlc_decode.cpp
    -index f7192b1c0..7202f982e 100644
    +index f7192b1c0f..7202f982eb 100644
     --- a/media/libstagefright/codecs/m4v_h263/dec/src/vlc_decode.cpp
     +++ b/media/libstagefright/codecs/m4v_h263/dec/src/vlc_decode.cpp
     @@ -560,7 +560,7 @@ int PV_VlcDecMCBPC_com_inter_H263(BitstreamDecVideo *stream)
    @@ -3516,7 +3636,7 @@ index f7192b1c0..7202f982e 100644
              return VLC_CODE_ERROR;
          }
     diff --git a/media/libstagefright/codecs/m4v_h263/enc/SoftMPEG4Encoder.cpp b/media/libstagefright/codecs/m4v_h263/enc/SoftMPEG4Encoder.cpp
    -index d5a26d372..7d2131df0 100644
    +index d5a26d3729..7d2131df07 100644
     --- a/media/libstagefright/codecs/m4v_h263/enc/SoftMPEG4Encoder.cpp
     +++ b/media/libstagefright/codecs/m4v_h263/enc/SoftMPEG4Encoder.cpp
     @@ -437,6 +437,14 @@ void SoftMPEG4Encoder::onQueueFilled(OMX_U32 /* portIndex */) {
    @@ -3535,7 +3655,7 @@ index d5a26d372..7d2131df0 100644
                  if (mInputDataIsMeta) {
                      inputData =
     diff --git a/media/libstagefright/codecs/mp3dec/src/pvmp3_decode_header.cpp b/media/libstagefright/codecs/mp3dec/src/pvmp3_decode_header.cpp
    -index d443b7ccf..bc5fd7952 100644
    +index d443b7ccfe..bc5fd79526 100644
     --- a/media/libstagefright/codecs/mp3dec/src/pvmp3_decode_header.cpp
     +++ b/media/libstagefright/codecs/mp3dec/src/pvmp3_decode_header.cpp
     @@ -184,7 +184,7 @@ ERROR_CODE pvmp3_decode_header(tmp3Bits  *inputStream,
    @@ -3548,7 +3668,7 @@ index d443b7ccf..bc5fd7952 100644
              err = UNSUPPORTED_FREE_BITRATE;
          }
     diff --git a/media/libstagefright/codecs/mpeg2dec/SoftMPEG2.cpp b/media/libstagefright/codecs/mpeg2dec/SoftMPEG2.cpp
    -index 5ed037ac7..7297f40fe 100644
    +index 5ed037ac77..7297f40fed 100644
     --- a/media/libstagefright/codecs/mpeg2dec/SoftMPEG2.cpp
     +++ b/media/libstagefright/codecs/mpeg2dec/SoftMPEG2.cpp
     @@ -68,6 +68,7 @@ SoftMPEG2::SoftMPEG2(
    @@ -3689,7 +3809,7 @@ index 5ed037ac7..7297f40fe 100644
                      mTimeStampsValid[timeStampIdx] = false;
      
     diff --git a/media/libstagefright/codecs/mpeg2dec/SoftMPEG2.h b/media/libstagefright/codecs/mpeg2dec/SoftMPEG2.h
    -index 700ef5f36..1285c5be4 100644
    +index 700ef5f36a..1285c5be4a 100644
     --- a/media/libstagefright/codecs/mpeg2dec/SoftMPEG2.h
     +++ b/media/libstagefright/codecs/mpeg2dec/SoftMPEG2.h
     @@ -106,6 +106,7 @@ private:
    @@ -3701,7 +3821,7 @@ index 700ef5f36..1285c5be4 100644
          size_t mStride;
      
     diff --git a/media/libstagefright/codecs/on2/enc/SoftVPXEncoder.cpp b/media/libstagefright/codecs/on2/enc/SoftVPXEncoder.cpp
    -index 56e1f7734..04d8dda07 100644
    +index 56e1f7734e..04d8dda075 100644
     --- a/media/libstagefright/codecs/on2/enc/SoftVPXEncoder.cpp
     +++ b/media/libstagefright/codecs/on2/enc/SoftVPXEncoder.cpp
     @@ -731,6 +731,13 @@ void SoftVPXEncoder::onQueueFilled(OMX_U32 /* portIndex */) {
    @@ -3734,7 +3854,7 @@ index 56e1f7734..04d8dda07 100644
                      ConvertYUV420SemiPlanarToYUV420Planar(
                              source, mConversionBuffer, mWidth, mHeight);
     diff --git a/media/libstagefright/foundation/MediaBuffer.cpp b/media/libstagefright/foundation/MediaBuffer.cpp
    -index 16000ef5c..2c4a76211 100644
    +index 16000ef5c5..2c4a762113 100644
     --- a/media/libstagefright/foundation/MediaBuffer.cpp
     +++ b/media/libstagefright/foundation/MediaBuffer.cpp
     @@ -155,6 +155,7 @@ size_t MediaBuffer::range_length() const {
    @@ -3746,7 +3866,7 @@ index 16000ef5c..2c4a76211 100644
          CHECK((mGraphicBuffer != NULL) || (offset + length <= mSize));
      
     diff --git a/media/libstagefright/foundation/MediaBufferGroup.cpp b/media/libstagefright/foundation/MediaBufferGroup.cpp
    -index 8e4d0641c..66992d72b 100644
    +index 8e4d0641c2..66992d72bb 100644
     --- a/media/libstagefright/foundation/MediaBufferGroup.cpp
     +++ b/media/libstagefright/foundation/MediaBufferGroup.cpp
     @@ -105,6 +105,11 @@ MediaBufferGroup::~MediaBufferGroup() {
    @@ -3779,7 +3899,7 @@ index 8e4d0641c..66992d72b 100644
          mCondition.signal();
      }
     diff --git a/media/libstagefright/foundation/base64.cpp b/media/libstagefright/foundation/base64.cpp
    -index 7da7db941..cc8906406 100644
    +index 7da7db9411..cc89064067 100644
     --- a/media/libstagefright/foundation/base64.cpp
     +++ b/media/libstagefright/foundation/base64.cpp
     @@ -78,8 +78,7 @@ sp<ABuffer> decodeBase64(const AString &s) {
    @@ -3792,8 +3912,25 @@ index 7da7db941..cc8906406 100644
                  if (j < outLen) { out[j++] = (accum >> 8) & 0xff; }
                  if (j < outLen) { out[j++] = accum & 0xff; }
      
    +diff --git a/media/libstagefright/httplive/HTTPDownloader.cpp b/media/libstagefright/httplive/HTTPDownloader.cpp
    +index 861b85a64d..5d6634efa4 100644
    +--- a/media/libstagefright/httplive/HTTPDownloader.cpp
    ++++ b/media/libstagefright/httplive/HTTPDownloader.cpp
    +@@ -157,6 +157,12 @@ ssize_t HTTPDownloader::fetchBlock(
    +                  buffer->size() + bufferRemaining);
    + 
    +             sp<ABuffer> copy = new ABuffer(buffer->size() + bufferRemaining);
    ++            if (copy->data() == NULL) {
    ++                android_errorWriteLog(0x534e4554, "68399439");
    ++                ALOGE("not enough memory to download: requesting %zu + %zu",
    ++                        buffer->size(), bufferRemaining);
    ++                return NO_MEMORY;
    ++            }
    +             memcpy(copy->data(), buffer->data(), buffer->size());
    +             copy->setRange(0, buffer->size());
    + 
     diff --git a/media/libstagefright/httplive/LiveSession.cpp b/media/libstagefright/httplive/LiveSession.cpp
    -index 7abc0197a..590146db9 100644
    +index 7abc0197a8..590146db93 100644
     --- a/media/libstagefright/httplive/LiveSession.cpp
     +++ b/media/libstagefright/httplive/LiveSession.cpp
     @@ -157,6 +157,11 @@ bool LiveSession::BandwidthEstimator::estimateBandwidth(
    @@ -3809,7 +3946,7 @@ index 7abc0197a..590146db9 100644
          while (mPrevEstimates.size() > 3) {
              mPrevEstimates.erase(mPrevEstimates.begin());
     diff --git a/media/libstagefright/httplive/M3UParser.cpp b/media/libstagefright/httplive/M3UParser.cpp
    -index c04549ab0..a092a1bdc 100644
    +index c04549ab0e..a092a1bdc9 100644
     --- a/media/libstagefright/httplive/M3UParser.cpp
     +++ b/media/libstagefright/httplive/M3UParser.cpp
     @@ -56,7 +56,7 @@ struct M3UParser::MediaGroup : public RefBase {
    @@ -3948,7 +4085,7 @@ index c04549ab0..a092a1bdc 100644
                  haveGroupURI = true;
              }
     diff --git a/media/libstagefright/httplive/M3UParser.h b/media/libstagefright/httplive/M3UParser.h
    -index fa648ed7d..c85335abc 100644
    +index fa648ed7d3..c85335abc2 100644
     --- a/media/libstagefright/httplive/M3UParser.h
     +++ b/media/libstagefright/httplive/M3UParser.h
     @@ -64,6 +64,7 @@ private:
    @@ -3960,7 +4097,7 @@ index fa648ed7d..c85335abc 100644
      
          status_t mInitCheck;
     diff --git a/media/libstagefright/id3/ID3.cpp b/media/libstagefright/id3/ID3.cpp
    -index 8b80ae949..ca2be5488 100644
    +index 8b80ae9496..ca2be5488a 100644
     --- a/media/libstagefright/id3/ID3.cpp
     +++ b/media/libstagefright/id3/ID3.cpp
     @@ -328,12 +328,25 @@ struct id3_header {
    @@ -4018,7 +4155,7 @@ index 8b80ae949..ca2be5488 100644
              char16_t *framedatacopy = NULL;
              if (*framedata == 0xfffe) {
     diff --git a/media/libstagefright/include/OMXNodeInstance.h b/media/libstagefright/include/OMXNodeInstance.h
    -index 94cf15abd..dd396e812 100644
    +index 94cf15abdd..dd396e8126 100644
     --- a/media/libstagefright/include/OMXNodeInstance.h
     +++ b/media/libstagefright/include/OMXNodeInstance.h
     @@ -175,7 +175,7 @@ private:
    @@ -4039,7 +4176,7 @@ index 94cf15abd..dd396e812 100644
          // For debug support
          char *mName;
     diff --git a/media/libstagefright/include/SoftVideoEncoderOMXComponent.h b/media/libstagefright/include/SoftVideoEncoderOMXComponent.h
    -index b43635deb..02555a2f3 100644
    +index b43635deba..02555a2f34 100644
     --- a/media/libstagefright/include/SoftVideoEncoderOMXComponent.h
     +++ b/media/libstagefright/include/SoftVideoEncoderOMXComponent.h
     @@ -68,6 +68,8 @@ protected:
    @@ -4052,7 +4189,7 @@ index b43635deb..02555a2f3 100644
              kInputPortIndex = 0,
              kOutputPortIndex = 1,
     diff --git a/media/libstagefright/mpeg2ts/ESQueue.cpp b/media/libstagefright/mpeg2ts/ESQueue.cpp
    -index 96ca40509..c454a0e49 100644
    +index 96ca405098..c454a0e49b 100644
     --- a/media/libstagefright/mpeg2ts/ESQueue.cpp
     +++ b/media/libstagefright/mpeg2ts/ESQueue.cpp
     @@ -716,6 +716,11 @@ sp<ABuffer> ElementaryStreamQueue::dequeueAccessUnitAAC() {
    @@ -4098,7 +4235,7 @@ index 96ca40509..c454a0e49 100644
                      break;
                  }
     diff --git a/media/libstagefright/omx/Android.mk b/media/libstagefright/omx/Android.mk
    -index e4fbd815c..8fc788f4b 100644
    +index e4fbd815c7..8fc788f4bc 100644
     --- a/media/libstagefright/omx/Android.mk
     +++ b/media/libstagefright/omx/Android.mk
     @@ -31,6 +31,12 @@ LOCAL_SHARED_LIBRARIES :=               \
    @@ -4115,7 +4252,7 @@ index e4fbd815c..8fc788f4b 100644
      LOCAL_CFLAGS += -Werror -Wall
      LOCAL_CLANG := true
     diff --git a/media/libstagefright/omx/GraphicBufferSource.cpp b/media/libstagefright/omx/GraphicBufferSource.cpp
    -index e1bcd285b..5f21eacfd 100644
    +index e1bcd285ba..5f21eacfde 100644
     --- a/media/libstagefright/omx/GraphicBufferSource.cpp
     +++ b/media/libstagefright/omx/GraphicBufferSource.cpp
     @@ -736,6 +736,8 @@ bool GraphicBufferSource::repeatLatestBuffer_l() {
    @@ -4128,7 +4265,7 @@ index e1bcd285b..5f21eacfd 100644
              if (mBufferUseCount[mLatestBufferId] == 0) {
                  releaseBuffer(mLatestBufferId, mLatestBufferFrameNum,
     diff --git a/media/libstagefright/omx/OMXMaster.cpp b/media/libstagefright/omx/OMXMaster.cpp
    -index 6132a2cf7..7f0d27008 100644
    +index 6132a2cf74..7f0d27008e 100644
     --- a/media/libstagefright/omx/OMXMaster.cpp
     +++ b/media/libstagefright/omx/OMXMaster.cpp
     @@ -69,6 +69,7 @@ OMXMaster::~OMXMaster() {
    @@ -4140,7 +4277,7 @@ index 6132a2cf7..7f0d27008 100644
      
      void OMXMaster::addPlugin(const char *libname) {
     diff --git a/media/libstagefright/omx/OMXNodeInstance.cpp b/media/libstagefright/omx/OMXNodeInstance.cpp
    -index e7aaeadf9..18778f7a6 100644
    +index e7aaeadf9c..18778f7a6d 100644
     --- a/media/libstagefright/omx/OMXNodeInstance.cpp
     +++ b/media/libstagefright/omx/OMXNodeInstance.cpp
     @@ -226,6 +226,8 @@ OMXNodeInstance::OMXNodeInstance(
    @@ -4310,7 +4447,7 @@ index e7aaeadf9..18778f7a6 100644
          } else {
              // rangeLength and rangeOffset must be a subset of the allocated data in the buffer.
     diff --git a/media/libstagefright/omx/SimpleSoftOMXComponent.cpp b/media/libstagefright/omx/SimpleSoftOMXComponent.cpp
    -index 7c975f7b5..76cbbc45d 100644
    +index 7c975f7b5a..76cbbc45d0 100644
     --- a/media/libstagefright/omx/SimpleSoftOMXComponent.cpp
     +++ b/media/libstagefright/omx/SimpleSoftOMXComponent.cpp
     @@ -199,6 +199,13 @@ OMX_ERRORTYPE SimpleSoftOMXComponent::useBuffer(
    @@ -4337,7 +4474,7 @@ index 7c975f7b5..76cbbc45d 100644
      
          CHECK_LT(port->mBuffers.size(), port->mDef.nBufferCountActual);
     diff --git a/media/libstagefright/omx/SoftVideoEncoderOMXComponent.cpp b/media/libstagefright/omx/SoftVideoEncoderOMXComponent.cpp
    -index 0f9c11869..9d302ddbd 100644
    +index 0f9c11869e..9d302ddbdf 100644
     --- a/media/libstagefright/omx/SoftVideoEncoderOMXComponent.cpp
     +++ b/media/libstagefright/omx/SoftVideoEncoderOMXComponent.cpp
     @@ -656,4 +656,17 @@ OMX_ERRORTYPE SoftVideoEncoderOMXComponent::getExtensionIndex(
    @@ -4359,7 +4496,7 @@ index 0f9c11869..9d302ddbd 100644
     +
      }  // namespace android
     diff --git a/media/libstagefright/rtsp/APacketSource.cpp b/media/libstagefright/rtsp/APacketSource.cpp
    -index cfafaa74b..a7545ad51 100644
    +index cfafaa74bf..a7545ad51c 100644
     --- a/media/libstagefright/rtsp/APacketSource.cpp
     +++ b/media/libstagefright/rtsp/APacketSource.cpp
     @@ -377,8 +377,8 @@ static sp<ABuffer> MakeMPEG4VideoCodecSpecificData(
    @@ -4373,8 +4510,21 @@ index cfafaa74b..a7545ad51 100644
      
          sp<ABuffer> csd = new ABuffer(len3);
          uint8_t *dst = csd->data();
    +diff --git a/media/libstagefright/timedtext/TextDescriptions.cpp b/media/libstagefright/timedtext/TextDescriptions.cpp
    +index c762a74d08..83d15a28ca 100644
    +--- a/media/libstagefright/timedtext/TextDescriptions.cpp
    ++++ b/media/libstagefright/timedtext/TextDescriptions.cpp
    +@@ -383,7 +383,7 @@ status_t TextDescriptions::extract3GPPGlobalDescriptions(
    +         tmpData += 8;
    +         size_t remaining = size - 8;
    + 
    +-        if (size < chunkSize) {
    ++        if (chunkSize <= 8 || size < chunkSize) {
    +             return OK;
    +         }
    +         switch(chunkType) {
     diff --git a/media/mediaserver/Android.mk b/media/mediaserver/Android.mk
    -index 1738df80d..c2b9c1f95 100644
    +index 1738df80dc..c2b9c1f959 100644
     --- a/media/mediaserver/Android.mk
     +++ b/media/mediaserver/Android.mk
     @@ -42,4 +42,8 @@ LOCAL_INIT_RC := mediaserver.rc
    @@ -4387,7 +4537,7 @@ index 1738df80d..c2b9c1f95 100644
     +
      include $(BUILD_EXECUTABLE)
     diff --git a/media/mediaserver/main_mediaserver.cpp b/media/mediaserver/main_mediaserver.cpp
    -index ecddc4827..0abe6ac95 100644
    +index ecddc48272..0abe6ac959 100644
     --- a/media/mediaserver/main_mediaserver.cpp
     +++ b/media/mediaserver/main_mediaserver.cpp
     @@ -25,6 +25,9 @@
    @@ -4411,7 +4561,7 @@ index ecddc4827..0abe6ac95 100644
          ProcessState::self()->startThreadPool();
          IPCThreadState::self()->joinThreadPool();
     diff --git a/media/mtp/MtpServer.cpp b/media/mtp/MtpServer.cpp
    -index e39dcddb7..65a241527 100644
    +index e39dcddb79..65a241527d 100644
     --- a/media/mtp/MtpServer.cpp
     +++ b/media/mtp/MtpServer.cpp
     @@ -136,20 +136,9 @@ void MtpServer::removeStorage(MtpStorage* storage) {
    @@ -4480,7 +4630,7 @@ index e39dcddb7..65a241527 100644
          if (!storage)
              return MTP_RESPONSE_INVALID_STORAGE_ID;
     diff --git a/media/mtp/MtpServer.h b/media/mtp/MtpServer.h
    -index b3a11e0a5..cd543c859 100644
    +index b3a11e0a54..cd543c859b 100644
     --- a/media/mtp/MtpServer.h
     +++ b/media/mtp/MtpServer.h
     @@ -95,8 +95,6 @@ public:
    @@ -4504,7 +4654,7 @@ index b3a11e0a5..cd543c859 100644
          void                sendStoreRemoved(MtpStorageID id);
          void                sendEvent(MtpEventCode code, uint32_t param1);
     diff --git a/media/ndk/NdkMediaCodec.cpp b/media/ndk/NdkMediaCodec.cpp
    -index 50b490d45..73e733e77 100644
    +index 50b490d457..73e733e77b 100644
     --- a/media/ndk/NdkMediaCodec.cpp
     +++ b/media/ndk/NdkMediaCodec.cpp
     @@ -447,7 +447,13 @@ AMediaCodecCryptoInfo *AMediaCodecCryptoInfo_new(
    @@ -4523,7 +4673,7 @@ index 50b490d45..73e733e77 100644
          if (!ret) {
              ALOGE("couldn't allocate %zu bytes", cryptosize);
     diff --git a/services/audioflinger/AudioFlinger.cpp b/services/audioflinger/AudioFlinger.cpp
    -index fec3a57c1..4aad2c219 100644
    +index fec3a57c1f..8b47fdbcbc 100644
     --- a/services/audioflinger/AudioFlinger.cpp
     +++ b/services/audioflinger/AudioFlinger.cpp
     @@ -1509,7 +1509,8 @@ sp<IAudioRecord> AudioFlinger::openRecord(
    @@ -4536,8 +4686,46 @@ index fec3a57c1..4aad2c219 100644
              ALOGE("openRecord() permission denied: recording not allowed");
              lStatus = PERMISSION_DENIED;
              goto Exit;
    +@@ -2759,9 +2760,13 @@ sp<IEffect> AudioFlinger::createEffect(
    +             }
    +             // look for the thread where the specified audio session is present
    +             for (size_t i = 0; i < mPlaybackThreads.size(); i++) {
    +-                if (mPlaybackThreads.valueAt(i)->hasAudioSession(sessionId) != 0) {
    ++                uint32_t sessionType = mPlaybackThreads.valueAt(i)->hasAudioSession(sessionId);
    ++                if (sessionType != 0) {
    +                     io = mPlaybackThreads.keyAt(i);
    +-                    break;
    ++                    // thread with same effect session is preferable
    ++                    if ((sessionType & ThreadBase::EFFECT_SESSION) != 0) {
    ++                        break;
    ++                    }
    +                 }
    +             }
    +             if (io == 0) {
    +@@ -2779,6 +2784,21 @@ sp<IEffect> AudioFlinger::createEffect(
    +                 io = mPlaybackThreads.keyAt(0);
    +             }
    +             ALOGV("createEffect() got io %d for effect %s", io, desc.name);
    ++        } else if (checkPlaybackThread_l(io) != nullptr) {
    ++            // allow only one effect chain per sessionId on mPlaybackThreads.
    ++            for (size_t i = 0; i < mPlaybackThreads.size(); i++) {
    ++                const audio_io_handle_t checkIo = mPlaybackThreads.keyAt(i);
    ++                if (io == checkIo) continue;
    ++                const uint32_t sessionType =
    ++                        mPlaybackThreads.valueAt(i)->hasAudioSession(sessionId);
    ++                if ((sessionType & ThreadBase::EFFECT_SESSION) != 0) {
    ++                    ALOGE("%s: effect %s io %d denied because session %d effect exists on io %d",
    ++                            __func__, desc.name, (int)io, (int)sessionId, (int)checkIo);
    ++                    android_errorWriteLog(0x534e4554, "123237974");
    ++                    lStatus = BAD_VALUE;
    ++                    goto Exit;
    ++                }
    ++            }
    +         }
    +         ThreadBase *thread = checkRecordThread_l(io);
    +         if (thread == NULL) {
     diff --git a/services/audioflinger/Effects.cpp b/services/audioflinger/Effects.cpp
    -index f908d6df3..b58868598 100644
    +index f908d6df3a..b58868598d 100644
     --- a/services/audioflinger/Effects.cpp
     +++ b/services/audioflinger/Effects.cpp
     @@ -1309,6 +1309,24 @@ status_t AudioFlinger::EffectHandle::command(uint32_t cmdCode,
    @@ -4566,7 +4754,7 @@ index f908d6df3..b58868598 100644
              if (*replySize < sizeof(int)) {
                  android_errorWriteLog(0x534e4554, "32095713");
     diff --git a/services/audioflinger/Threads.cpp b/services/audioflinger/Threads.cpp
    -index 7423ea9ae..1bc9516c4 100644
    +index 7423ea9aee..1bc9516c4a 100644
     --- a/services/audioflinger/Threads.cpp
     +++ b/services/audioflinger/Threads.cpp
     @@ -1412,6 +1412,7 @@ sp<AudioFlinger::EffectHandle> AudioFlinger::ThreadBase::createEffect_l(
    @@ -4608,7 +4796,7 @@ index 7423ea9ae..1bc9516c4 100644
              if (chainCreated) {
                  removeEffectChain_l(chain);
     diff --git a/services/audioflinger/Tracks.cpp b/services/audioflinger/Tracks.cpp
    -index f18b88d72..a3f3ea5cf 100644
    +index f18b88d724..a3f3ea5cf6 100644
     --- a/services/audioflinger/Tracks.cpp
     +++ b/services/audioflinger/Tracks.cpp
     @@ -141,9 +141,11 @@ AudioFlinger::ThreadBase::TrackBase::TrackBase(
    @@ -4661,8 +4849,303 @@ index f18b88d72..a3f3ea5cf 100644
              mAudioTrackServerProxy = new StaticAudioTrackServerProxy(mCblk, mBuffer, frameCount,
                      mFrameSize);
          }
    +diff --git a/services/audiopolicy/common/managerdefinitions/include/AudioInputDescriptor.h b/services/audiopolicy/common/managerdefinitions/include/AudioInputDescriptor.h
    +index f2b39f2956..815f065f37 100644
    +--- a/services/audiopolicy/common/managerdefinitions/include/AudioInputDescriptor.h
    ++++ b/services/audiopolicy/common/managerdefinitions/include/AudioInputDescriptor.h
    +@@ -27,7 +27,7 @@
    + namespace android {
    + 
    + class IOProfile;
    +-class AudioMix;
    ++class AudioPolicyMix;
    + 
    + // descriptor for audio inputs. Used to maintain current configuration of each opened audio input
    + // and keep track of the usage of this input.
    +@@ -44,7 +44,7 @@ public:
    + 
    +     audio_io_handle_t             mIoHandle;       // input handle
    +     audio_devices_t               mDevice;         // current device this input is routed to
    +-    AudioMix                      *mPolicyMix;     // non NULL when used by a dynamic policy
    ++    wp<AudioPolicyMix>            mPolicyMix;      // non NULL when used by a dynamic policy
    +     const sp<IOProfile>           mProfile;        // I/O profile this output derives from
    + 
    +     virtual void toAudioPortConfig(struct audio_port_config *dstConfig,
    +diff --git a/services/audiopolicy/common/managerdefinitions/include/AudioOutputDescriptor.h b/services/audiopolicy/common/managerdefinitions/include/AudioOutputDescriptor.h
    +index dd3f8ae353..b0cdba94cf 100644
    +--- a/services/audiopolicy/common/managerdefinitions/include/AudioOutputDescriptor.h
    ++++ b/services/audiopolicy/common/managerdefinitions/include/AudioOutputDescriptor.h
    +@@ -27,7 +27,7 @@
    + namespace android {
    + 
    + class IOProfile;
    +-class AudioMix;
    ++class AudioPolicyMix;
    + class AudioPolicyClientInterface;
    + class DeviceDescriptor;
    + 
    +@@ -124,7 +124,7 @@ public:
    +     audio_io_handle_t mIoHandle;           // output handle
    +     uint32_t mLatency;                  //
    +     audio_output_flags_t mFlags;   //
    +-    AudioMix *mPolicyMix;             // non NULL when used by a dynamic policy
    ++    wp<AudioPolicyMix> mPolicyMix;           // non NULL when used by a dynamic policy
    +     sp<SwAudioOutputDescriptor> mOutput1;    // used by duplicated outputs: first output
    +     sp<SwAudioOutputDescriptor> mOutput2;    // used by duplicated outputs: second output
    +     uint32_t mDirectOpenCount; // number of clients using this output (direct outputs only)
    +diff --git a/services/audiopolicy/common/managerdefinitions/include/AudioPolicyMix.h b/services/audiopolicy/common/managerdefinitions/include/AudioPolicyMix.h
    +index 8f5ebefbae..c70da39de5 100644
    +--- a/services/audiopolicy/common/managerdefinitions/include/AudioPolicyMix.h
    ++++ b/services/audiopolicy/common/managerdefinitions/include/AudioPolicyMix.h
    +@@ -29,9 +29,11 @@ class SwAudioOutputDescriptor;
    + /**
    +  * custom mix entry in mPolicyMixes
    +  */
    +-class AudioPolicyMix : public RefBase {
    ++class AudioPolicyMix : public AudioMix, public RefBase {
    + public:
    +-    AudioPolicyMix() {}
    ++    AudioPolicyMix(const AudioMix &mix);
    ++    AudioPolicyMix(const AudioPolicyMix&) = delete;
    ++    AudioPolicyMix& operator=(const AudioPolicyMix&) = delete;
    + 
    +     const sp<SwAudioOutputDescriptor> &getOutput() const;
    + 
    +@@ -39,12 +41,7 @@ public:
    + 
    +     void clearOutput();
    + 
    +-    android::AudioMix *getMix();
    +-
    +-    void setMix(AudioMix &mix);
    +-
    + private:
    +-    AudioMix    mMix;                   // Audio policy mix descriptor
    +     sp<SwAudioOutputDescriptor> mOutput;  // Corresponding output stream
    + };
    + 
    +@@ -74,9 +71,9 @@ public:
    + 
    +     audio_devices_t getDeviceAndMixForInputSource(audio_source_t inputSource,
    +                                                   audio_devices_t availableDeviceTypes,
    +-                                                  AudioMix **policyMix);
    ++                                                  sp<AudioPolicyMix> *policyMix);
    + 
    +-    status_t getInputMixForAttr(audio_attributes_t attr, AudioMix **policyMix);
    ++    status_t getInputMixForAttr(audio_attributes_t attr, sp<AudioPolicyMix> *policyMix);
    + };
    + 
    + }; // namespace android
    +diff --git a/services/audiopolicy/common/managerdefinitions/include/AudioSession.h b/services/audiopolicy/common/managerdefinitions/include/AudioSession.h
    +index 388c25d11b..3b0ce71380 100644
    +--- a/services/audiopolicy/common/managerdefinitions/include/AudioSession.h
    ++++ b/services/audiopolicy/common/managerdefinitions/include/AudioSession.h
    +@@ -27,6 +27,7 @@
    + namespace android {
    + 
    + class AudioPolicyClientInterface;
    ++class AudioPolicyMix;
    + 
    + class AudioSession : public RefBase, public AudioSessionInfoUpdateListener
    + {
    +@@ -39,7 +40,7 @@ public:
    +                  audio_input_flags_t flags,
    +                  uid_t uid,
    +                  bool isSoundTrigger,
    +-                 AudioMix* policyMix,
    ++                 const sp<AudioPolicyMix> &policyMix,
    +                  AudioPolicyClientInterface *clientInterface);
    + 
    +     status_t dump(int fd, int spaces, int index) const;
    +@@ -72,7 +73,7 @@ private:
    +     bool  mIsSoundTrigger;
    +     uint32_t  mOpenCount;
    +     uint32_t  mActiveCount;
    +-    AudioMix* mPolicyMix; // non NULL when used by a dynamic policy
    ++    wp<AudioPolicyMix> mPolicyMix; // non NULL when used by a dynamic policy
    +     AudioPolicyClientInterface* mClientInterface;
    +     const AudioSessionInfoProvider* mInfoProvider;
    + };
    +diff --git a/services/audiopolicy/common/managerdefinitions/src/AudioInputDescriptor.cpp b/services/audiopolicy/common/managerdefinitions/src/AudioInputDescriptor.cpp
    +index c7d2ee4552..9a87751c8b 100644
    +--- a/services/audiopolicy/common/managerdefinitions/src/AudioInputDescriptor.cpp
    ++++ b/services/audiopolicy/common/managerdefinitions/src/AudioInputDescriptor.cpp
    +@@ -20,6 +20,7 @@
    + #include "AudioInputDescriptor.h"
    + #include "IOProfile.h"
    + #include "AudioGain.h"
    ++#include "AudioPolicyMix.h"
    + #include "HwModule.h"
    + #include <media/AudioPolicy.h>
    + #include <policy.h>
    +diff --git a/services/audiopolicy/common/managerdefinitions/src/AudioOutputDescriptor.cpp b/services/audiopolicy/common/managerdefinitions/src/AudioOutputDescriptor.cpp
    +index 79bbc548c6..124b73512a 100644
    +--- a/services/audiopolicy/common/managerdefinitions/src/AudioOutputDescriptor.cpp
    ++++ b/services/audiopolicy/common/managerdefinitions/src/AudioOutputDescriptor.cpp
    +@@ -19,6 +19,7 @@
    + 
    + #include <AudioPolicyInterface.h>
    + #include "AudioOutputDescriptor.h"
    ++#include "AudioPolicyMix.h"
    + #include "IOProfile.h"
    + #include "AudioGain.h"
    + #include "Volume.h"
    +@@ -312,17 +313,18 @@ void SwAudioOutputDescriptor::changeRefCount(audio_stream_type_t stream,
    +     } else {
    +         mGlobalRefCount += delta;
    +     }
    ++    sp<AudioPolicyMix> policyMix = mPolicyMix.promote();
    +     if ((oldGlobalRefCount == 0) && (mGlobalRefCount > 0)) {
    +-        if ((mPolicyMix != NULL) && ((mPolicyMix->mCbFlags & AudioMix::kCbFlagNotifyActivity) != 0))
    ++        if ((policyMix != NULL) && ((policyMix->mCbFlags & AudioMix::kCbFlagNotifyActivity) != 0))
    +         {
    +-            mClientInterface->onDynamicPolicyMixStateUpdate(mPolicyMix->mDeviceAddress,
    ++            mClientInterface->onDynamicPolicyMixStateUpdate(policyMix->mDeviceAddress,
    +                     MIX_STATE_MIXING);
    +         }
    + 
    +     } else if ((oldGlobalRefCount > 0) && (mGlobalRefCount == 0)) {
    +-        if ((mPolicyMix != NULL) && ((mPolicyMix->mCbFlags & AudioMix::kCbFlagNotifyActivity) != 0))
    ++        if ((policyMix != NULL) && ((policyMix->mCbFlags & AudioMix::kCbFlagNotifyActivity) != 0))
    +         {
    +-            mClientInterface->onDynamicPolicyMixStateUpdate(mPolicyMix->mDeviceAddress,
    ++            mClientInterface->onDynamicPolicyMixStateUpdate(policyMix->mDeviceAddress,
    +                     MIX_STATE_IDLE);
    +         }
    +     }
    +diff --git a/services/audiopolicy/common/managerdefinitions/src/AudioPolicyMix.cpp b/services/audiopolicy/common/managerdefinitions/src/AudioPolicyMix.cpp
    +index 7ee98b675e..d88b2652a0 100644
    +--- a/services/audiopolicy/common/managerdefinitions/src/AudioPolicyMix.cpp
    ++++ b/services/audiopolicy/common/managerdefinitions/src/AudioPolicyMix.cpp
    +@@ -26,6 +26,10 @@
    + 
    + namespace android {
    + 
    ++AudioPolicyMix::AudioPolicyMix(const AudioMix &mix) : AudioMix(mix)
    ++{
    ++}
    ++
    + void AudioPolicyMix::setOutput(sp<SwAudioOutputDescriptor> &output)
    + {
    +     mOutput = output;
    +@@ -41,16 +45,6 @@ void AudioPolicyMix::clearOutput()
    +     mOutput.clear();
    + }
    + 
    +-void AudioPolicyMix::setMix(AudioMix &mix)
    +-{
    +-    mMix = mix;
    +-}
    +-
    +-android::AudioMix *AudioPolicyMix::getMix()
    +-{
    +-    return &mMix;
    +-}
    +-
    + status_t AudioPolicyMixCollection::registerMix(String8 address, AudioMix mix,
    +                                                sp<SwAudioOutputDescriptor> desc)
    + {
    +@@ -59,12 +53,11 @@ status_t AudioPolicyMixCollection::registerMix(String8 address, AudioMix mix,
    +         ALOGE("registerPolicyMixes(): mix for address %s already registered", address.string());
    +         return BAD_VALUE;
    +     }
    +-    sp<AudioPolicyMix> policyMix = new AudioPolicyMix();
    +-    policyMix->setMix(mix);
    ++    sp<AudioPolicyMix> policyMix = new AudioPolicyMix(mix);
    +     add(address, policyMix);
    + 
    +     if (desc != 0) {
    +-        desc->mPolicyMix = policyMix->getMix();
    ++        desc->mPolicyMix = policyMix;
    +         policyMix->setOutput(desc);
    +     }
    +     return NO_ERROR;
    +@@ -110,8 +103,7 @@ status_t AudioPolicyMixCollection::getOutputForAttr(audio_attributes_t attribute
    +     ALOGV("getOutputForAttr() querying %zu mixes:", size());
    +     desc = 0;
    +     for (size_t i = 0; i < size(); i++) {
    +-        sp<AudioPolicyMix> policyMix = valueAt(i);
    +-        AudioMix *mix = policyMix->getMix();
    ++        sp<AudioPolicyMix> mix = valueAt(i);
    + 
    +         if (mix->mMixType == MIX_TYPE_PLAYERS) {
    +             // TODO if adding more player rules (currently only 2), make rule handling "generic"
    +@@ -208,7 +200,7 @@ status_t AudioPolicyMixCollection::getOutputForAttr(audio_attributes_t attribute
    +                       (hasUidExcludeRules && uidExclusionFound) ||
    +                       (hasUidMatchRules && !uidMatchFound))) {
    +                 ALOGV("\tgetOutputForAttr will use mix %zu", i);
    +-                desc = policyMix->getOutput();
    ++                desc = mix->getOutput();
    +             }
    + 
    +         } else if (mix->mMixType == MIX_TYPE_RECORDERS) {
    +@@ -217,7 +209,7 @@ status_t AudioPolicyMixCollection::getOutputForAttr(audio_attributes_t attribute
    +                     strncmp(attributes.tags + strlen("addr="),
    +                             mix->mDeviceAddress.string(),
    +                             AUDIO_ATTRIBUTES_TAGS_MAX_SIZE - strlen("addr=") - 1) == 0) {
    +-                desc = policyMix->getOutput();
    ++                desc = mix->getOutput();
    +             }
    +         }
    +         if (desc != 0) {
    +@@ -228,12 +220,13 @@ status_t AudioPolicyMixCollection::getOutputForAttr(audio_attributes_t attribute
    +     return BAD_VALUE;
    + }
    + 
    +-audio_devices_t AudioPolicyMixCollection::getDeviceAndMixForInputSource(audio_source_t inputSource,
    +-                                                                        audio_devices_t availDevices,
    +-                                                                        AudioMix **policyMix)
    ++audio_devices_t AudioPolicyMixCollection::getDeviceAndMixForInputSource(
    ++        audio_source_t inputSource,
    ++        audio_devices_t availDevices,
    ++        sp<AudioPolicyMix> *policyMix)
    + {
    +     for (size_t i = 0; i < size(); i++) {
    +-        AudioMix *mix = valueAt(i)->getMix();
    ++        AudioPolicyMix *mix = valueAt(i).get();
    + 
    +         if (mix->mMixType != MIX_TYPE_RECORDERS) {
    +             continue;
    +@@ -256,7 +249,8 @@ audio_devices_t AudioPolicyMixCollection::getDeviceAndMixForInputSource(audio_so
    +     return AUDIO_DEVICE_NONE;
    + }
    + 
    +-status_t AudioPolicyMixCollection::getInputMixForAttr(audio_attributes_t attr, AudioMix **policyMix)
    ++status_t AudioPolicyMixCollection::getInputMixForAttr(
    ++        audio_attributes_t attr, sp<AudioPolicyMix> *policyMix)
    + {
    +     if (strncmp(attr.tags, "addr=", strlen("addr=")) != 0) {
    +         return BAD_VALUE;
    +@@ -266,8 +260,7 @@ status_t AudioPolicyMixCollection::getInputMixForAttr(audio_attributes_t attr, A
    + #ifdef LOG_NDEBUG
    +     ALOGV("getInputMixForAttr looking for address %s\n  mixes available:", address.string());
    +     for (size_t i = 0; i < size(); i++) {
    +-            sp<AudioPolicyMix> policyMix = valueAt(i);
    +-            AudioMix *mix = policyMix->getMix();
    ++            sp<AudioPolicyMix> mix = valueAt(i);
    +             ALOGV("\tmix %zu address=%s", i, mix->mDeviceAddress.string());
    +     }
    + #endif
    +@@ -278,13 +271,14 @@ status_t AudioPolicyMixCollection::getInputMixForAttr(audio_attributes_t attr, A
    +         return BAD_VALUE;
    +     }
    +     sp<AudioPolicyMix> audioPolicyMix = valueAt(index);
    +-    AudioMix *mix = audioPolicyMix->getMix();
    + 
    +-    if (mix->mMixType != MIX_TYPE_PLAYERS) {
    ++    if (audioPolicyMix->mMixType != MIX_TYPE_PLAYERS) {
    +         ALOGW("getInputMixForAttr() bad policy mix type for address %s", address.string());
    +         return BAD_VALUE;
    +     }
    +-    *policyMix = mix;
    ++    if (policyMix != nullptr) {
    ++        *policyMix = audioPolicyMix;
    ++    }
    +     return NO_ERROR;
    + }
    + 
     diff --git a/services/audiopolicy/common/managerdefinitions/src/AudioPort.cpp b/services/audiopolicy/common/managerdefinitions/src/AudioPort.cpp
    -index 17ed537fc..ce9bdc212 100644
    +index 17ed537fc9..ce9bdc2125 100644
     --- a/services/audiopolicy/common/managerdefinitions/src/AudioPort.cpp
     +++ b/services/audiopolicy/common/managerdefinitions/src/AudioPort.cpp
     @@ -384,6 +384,7 @@ AudioPortConfig::AudioPortConfig()
    @@ -4673,8 +5156,42 @@ index 17ed537fc..ce9bdc212 100644
          mGain.index = -1;
      }
      
    +diff --git a/services/audiopolicy/common/managerdefinitions/src/AudioSession.cpp b/services/audiopolicy/common/managerdefinitions/src/AudioSession.cpp
    +index da983c5f94..498fa62135 100644
    +--- a/services/audiopolicy/common/managerdefinitions/src/AudioSession.cpp
    ++++ b/services/audiopolicy/common/managerdefinitions/src/AudioSession.cpp
    +@@ -18,6 +18,7 @@
    + //#define LOG_NDEBUG 0
    + 
    + #include <AudioPolicyInterface.h>
    ++#include "AudioPolicyMix.h"
    + #include "AudioSession.h"
    + #include "AudioGain.h"
    + #include "TypeConverter.h"
    +@@ -34,7 +35,7 @@ AudioSession::AudioSession(audio_session_t session,
    +                            audio_input_flags_t flags,
    +                            uid_t uid,
    +                            bool isSoundTrigger,
    +-                           AudioMix* policyMix,
    ++                           const sp<AudioPolicyMix> &policyMix,
    +                            AudioPolicyClientInterface *clientInterface) :
    +     mSession(session), mInputSource(inputSource),
    +     mConfig({ .format = format, .sample_rate = sampleRate, .channel_mask = channelMask}),
    +@@ -77,9 +78,10 @@ uint32_t AudioSession::changeActiveCount(int delta)
    +     if (event != RECORD_CONFIG_EVENT_NONE) {
    +         // Dynamic policy callback:
    +         // if input maps to a dynamic policy with an activity listener, notify of state change
    +-        if ((mPolicyMix != NULL) && ((mPolicyMix->mCbFlags & AudioMix::kCbFlagNotifyActivity) != 0))
    ++        sp<AudioPolicyMix> policyMix = mPolicyMix.promote();
    ++        if ((policyMix != NULL) && ((policyMix->mCbFlags & AudioMix::kCbFlagNotifyActivity) != 0))
    +         {
    +-            mClientInterface->onDynamicPolicyMixStateUpdate(mPolicyMix->mDeviceAddress,
    ++            mClientInterface->onDynamicPolicyMixStateUpdate(policyMix->mDeviceAddress,
    +                     (event == RECORD_CONFIG_EVENT_START) ? MIX_STATE_MIXING : MIX_STATE_IDLE);
    +         }
    + 
     diff --git a/services/audiopolicy/common/managerdefinitions/src/Serializer.cpp b/services/audiopolicy/common/managerdefinitions/src/Serializer.cpp
    -index 3e5bb7d3e..2ecd6b179 100644
    +index 3e5bb7d3ec..2ecd6b1798 100644
     --- a/services/audiopolicy/common/managerdefinitions/src/Serializer.cpp
     +++ b/services/audiopolicy/common/managerdefinitions/src/Serializer.cpp
     @@ -383,6 +383,7 @@ status_t RouteTraits::deserialize(_xmlDoc */*doc*/, const _xmlNode *root, PtrEle
    @@ -4685,8 +5202,158 @@ index 3e5bb7d3e..2ecd6b179 100644
                      return BAD_VALUE;
                  }
                  sources.add(source);
    +diff --git a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
    +index d265f11672..26453999e0 100644
    +--- a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
    ++++ b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
    +@@ -1106,10 +1106,9 @@ status_t AudioPolicyManager::startOutput(audio_io_handle_t output,
    +     mOutputRoutes.incRouteActivity(session);
    + 
    +     audio_devices_t newDevice;
    +-    AudioMix *policyMix = NULL;
    ++    sp<AudioPolicyMix> policyMix = outputDesc->mPolicyMix.promote();
    +     const char *address = NULL;
    +-    if (outputDesc->mPolicyMix != NULL) {
    +-        policyMix = outputDesc->mPolicyMix;
    ++    if (policyMix != NULL) {
    +         address = policyMix->mDeviceAddress.string();
    +         if ((policyMix->mRouteFlags & MIX_ROUTE_FLAG_RENDER) == MIX_ROUTE_FLAG_RENDER) {
    +             newDevice = policyMix->mDeviceType;
    +@@ -1262,12 +1261,13 @@ status_t AudioPolicyManager::stopOutput(audio_io_handle_t output,
    +     if (outputDesc->mRefCount[stream] == 1) {
    +         // Automatically disable the remote submix input when output is stopped on a
    +         // re routing mix of type MIX_TYPE_RECORDERS
    ++        sp<AudioPolicyMix> policyMix = outputDesc->mPolicyMix.promote();
    +         if (audio_is_remote_submix_device(outputDesc->mDevice) &&
    +-                outputDesc->mPolicyMix != NULL &&
    +-                outputDesc->mPolicyMix->mMixType == MIX_TYPE_RECORDERS) {
    ++                policyMix != NULL &&
    ++                policyMix->mMixType == MIX_TYPE_RECORDERS) {
    +             setDeviceConnectionStateInt(AUDIO_DEVICE_IN_REMOTE_SUBMIX,
    +                     AUDIO_POLICY_DEVICE_STATE_UNAVAILABLE,
    +-                    outputDesc->mPolicyMix->mDeviceAddress,
    ++                    policyMix->mDeviceAddress,
    +                     "remote-submix");
    +         }
    +     }
    +@@ -1415,7 +1415,7 @@ status_t AudioPolicyManager::getInputForAttr(const audio_attributes_t *attr,
    +     String8 address = String8("");
    +     audio_source_t inputSource = attr->source;
    +     audio_source_t halInputSource;
    +-    AudioMix *policyMix = NULL;
    ++    sp<AudioPolicyMix> policyMix;
    + 
    +     if (inputSource == AUDIO_SOURCE_DEFAULT) {
    +         inputSource = AUDIO_SOURCE_MIC;
    +@@ -1491,7 +1491,7 @@ audio_io_handle_t AudioPolicyManager::getInputForDevice(audio_devices_t device,
    +                                                         audio_format_t format,
    +                                                         audio_channel_mask_t channelMask,
    +                                                         audio_input_flags_t flags,
    +-                                                        AudioMix *policyMix)
    ++                                                        const sp<AudioPolicyMix> &policyMix)
    + {
    +     audio_io_handle_t input = AUDIO_IO_HANDLE_NONE;
    +     audio_source_t halInputSource = inputSource;
    +@@ -1681,10 +1681,11 @@ status_t AudioPolicyManager::startInput(audio_io_handle_t input,
    +     mInputRoutes.incRouteActivity(session);
    + 
    +     if (!inputDesc->isActive() || mInputRoutes.hasRouteChanged(session)) {
    ++        sp<AudioPolicyMix> policyMix = inputDesc->mPolicyMix.promote();
    +         // if input maps to a dynamic policy with an activity listener, notify of state change
    +-        if ((inputDesc->mPolicyMix != NULL)
    +-                && ((inputDesc->mPolicyMix->mCbFlags & AudioMix::kCbFlagNotifyActivity) != 0)) {
    +-            mpClientInterface->onDynamicPolicyMixStateUpdate(inputDesc->mPolicyMix->mDeviceAddress,
    ++        if ((policyMix != NULL)
    ++                && ((policyMix->mCbFlags & AudioMix::kCbFlagNotifyActivity) != 0)) {
    ++            mpClientInterface->onDynamicPolicyMixStateUpdate(policyMix->mDeviceAddress,
    +                     MIX_STATE_MIXING);
    +         }
    + 
    +@@ -1703,10 +1704,10 @@ status_t AudioPolicyManager::startInput(audio_io_handle_t input,
    +         // For remote submix (a virtual device), we open only one input per capture request.
    +         if (audio_is_remote_submix_device(inputDesc->mDevice)) {
    +             String8 address = String8("");
    +-            if (inputDesc->mPolicyMix == NULL) {
    ++            if (policyMix == NULL) {
    +                 address = String8("0");
    +-            } else if (inputDesc->mPolicyMix->mMixType == MIX_TYPE_PLAYERS) {
    +-                address = inputDesc->mPolicyMix->mDeviceAddress;
    ++            } else if (policyMix->mMixType == MIX_TYPE_PLAYERS) {
    ++                address = policyMix->mDeviceAddress;
    +             }
    +             if (address != "") {
    +                 setDeviceConnectionStateInt(AUDIO_DEVICE_OUT_REMOTE_SUBMIX,
    +@@ -1750,10 +1751,11 @@ status_t AudioPolicyManager::stopInput(audio_io_handle_t input,
    +     mInputRoutes.decRouteActivity(session);
    + 
    +     if (!inputDesc->isActive()) {
    ++        sp<AudioPolicyMix> policyMix = inputDesc->mPolicyMix.promote();
    +         // if input maps to a dynamic policy with an activity listener, notify of state change
    +-        if ((inputDesc->mPolicyMix != NULL)
    +-                && ((inputDesc->mPolicyMix->mCbFlags & AudioMix::kCbFlagNotifyActivity) != 0)) {
    +-            mpClientInterface->onDynamicPolicyMixStateUpdate(inputDesc->mPolicyMix->mDeviceAddress,
    ++        if ((policyMix != NULL)
    ++                && ((policyMix->mCbFlags & AudioMix::kCbFlagNotifyActivity) != 0)) {
    ++            mpClientInterface->onDynamicPolicyMixStateUpdate(policyMix->mDeviceAddress,
    +                     MIX_STATE_IDLE);
    +         }
    + 
    +@@ -1761,10 +1763,10 @@ status_t AudioPolicyManager::stopInput(audio_io_handle_t input,
    +         // used by a policy mix of type MIX_TYPE_RECORDERS
    +         if (audio_is_remote_submix_device(inputDesc->mDevice)) {
    +             String8 address = String8("");
    +-            if (inputDesc->mPolicyMix == NULL) {
    ++            if (policyMix == NULL) {
    +                 address = String8("0");
    +-            } else if (inputDesc->mPolicyMix->mMixType == MIX_TYPE_PLAYERS) {
    +-                address = inputDesc->mPolicyMix->mDeviceAddress;
    ++            } else if (policyMix->mMixType == MIX_TYPE_PLAYERS) {
    ++                address = policyMix->mDeviceAddress;
    +             }
    +             if (address != "") {
    +                 setDeviceConnectionStateInt(AUDIO_DEVICE_OUT_REMOTE_SUBMIX,
    +@@ -3809,7 +3811,7 @@ status_t AudioPolicyManager::checkOutputsForDevice(const sp<DeviceDescriptor> de
    +                                   address.string());
    +                         }
    +                         policyMix->setOutput(desc);
    +-                        desc->mPolicyMix = policyMix->getMix();
    ++                        desc->mPolicyMix = policyMix;
    + 
    +                     } else if (((desc->mFlags & AUDIO_OUTPUT_FLAG_DIRECT) == 0) &&
    +                                     hasPrimaryOutput()) {
    +@@ -4927,7 +4929,7 @@ sp<IOProfile> AudioPolicyManager::getInputProfile(audio_devices_t device,
    + 
    + 
    + audio_devices_t AudioPolicyManager::getDeviceAndMixForInputSource(audio_source_t inputSource,
    +-                                                                  AudioMix **policyMix)
    ++                                                                  sp<AudioPolicyMix> *policyMix)
    + {
    +     audio_devices_t availableDeviceTypes = mAvailableInputDevices.types() & ~AUDIO_DEVICE_BIT_IN;
    +     audio_devices_t selectedDeviceFromMix =
    +diff --git a/services/audiopolicy/managerdefault/AudioPolicyManager.h b/services/audiopolicy/managerdefault/AudioPolicyManager.h
    +index 71bcd5f7e0..3db9dbc62a 100644
    +--- a/services/audiopolicy/managerdefault/AudioPolicyManager.h
    ++++ b/services/audiopolicy/managerdefault/AudioPolicyManager.h
    +@@ -627,7 +627,7 @@ private:
    +                 audio_format_t format,
    +                 audio_channel_mask_t channelMask,
    +                 audio_input_flags_t flags,
    +-                AudioMix *policyMix);
    ++                const sp<AudioPolicyMix> &policyMix);
    + 
    +         // internal function to derive a stream type value from audio attributes
    +         audio_stream_type_t streamTypefromAttributesInt(const audio_attributes_t *attr);
    +@@ -641,7 +641,7 @@ private:
    +         // select input device corresponding to requested audio source and return associated policy
    +         // mix if any. Calls getDeviceForInputSource().
    +         audio_devices_t getDeviceAndMixForInputSource(audio_source_t inputSource,
    +-                                                        AudioMix **policyMix = NULL);
    ++                                                      sp<AudioPolicyMix> *policyMix = NULL);
    + 
    +         // Called by setDeviceConnectionState().
    +         status_t setDeviceConnectionStateInt(audio_devices_t device,
     diff --git a/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp b/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp
    -index a75e3ddcc..cf81d9abb 100644
    +index a75e3ddcc0..cf81d9abbe 100644
     --- a/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp
     +++ b/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp
     @@ -318,7 +318,7 @@ status_t AudioPolicyService::getInputForAttr(const audio_attributes_t *attr,
    @@ -4715,7 +5382,7 @@ index a75e3ddcc..cf81d9abb 100644
              return NO_INIT;
          }
     diff --git a/services/camera/libcameraservice/Android.mk b/services/camera/libcameraservice/Android.mk
    -index 8d7f71cef..d98ad470e 100644
    +index 8d7f71cef9..d98ad470e0 100644
     --- a/services/camera/libcameraservice/Android.mk
     +++ b/services/camera/libcameraservice/Android.mk
     @@ -80,6 +80,10 @@ LOCAL_EXPORT_C_INCLUDE_DIRS := \
    @@ -4730,7 +5397,7 @@ index 8d7f71cef..d98ad470e 100644
      
      include $(BUILD_SHARED_LIBRARY)
     diff --git a/services/camera/libcameraservice/CameraService.cpp b/services/camera/libcameraservice/CameraService.cpp
    -index 6124fedde..de7ea037f 100644
    +index 6124fedde2..de7ea037f5 100644
     --- a/services/camera/libcameraservice/CameraService.cpp
     +++ b/services/camera/libcameraservice/CameraService.cpp
     @@ -273,7 +273,10 @@ void CameraService::onFirstRef()
    @@ -4769,7 +5436,7 @@ index 6124fedde..de7ea037f 100644
                  return true;
              default:
     diff --git a/services/camera/libcameraservice/api1/CameraClient.cpp b/services/camera/libcameraservice/api1/CameraClient.cpp
    -index 266fb03d4..3c2b98a85 100644
    +index 266fb03d40..3c2b98a85e 100644
     --- a/services/camera/libcameraservice/api1/CameraClient.cpp
     +++ b/services/camera/libcameraservice/api1/CameraClient.cpp
     @@ -520,6 +520,9 @@ void CameraClient::releaseRecordingFrameHandle(native_handle_t *handle) {
    @@ -4783,7 +5450,7 @@ index 266fb03d4..3c2b98a85 100644
      
      status_t CameraClient::setVideoBufferMode(int32_t videoBufferMode) {
     diff --git a/services/soundtrigger/SoundTriggerHwService.cpp b/services/soundtrigger/SoundTriggerHwService.cpp
    -index eebc48705..9d98a3039 100644
    +index eebc487053..9d98a30390 100644
     --- a/services/soundtrigger/SoundTriggerHwService.cpp
     +++ b/services/soundtrigger/SoundTriggerHwService.cpp
     @@ -278,6 +278,37 @@ void SoundTriggerHwService::sendRecognitionEvent(struct sound_trigger_recognitio
    @@ -4959,7 +5626,7 @@ index eebc48705..9d98a3039 100644
      
      status_t SoundTriggerHwService::Module::startRecognition(sound_model_handle_t handle,
     diff --git a/services/soundtrigger/SoundTriggerHwService.h b/services/soundtrigger/SoundTriggerHwService.h
    -index 2619a5fb4..d05dacdb7 100644
    +index 2619a5fb49..d05dacdb7f 100644
     --- a/services/soundtrigger/SoundTriggerHwService.h
     +++ b/services/soundtrigger/SoundTriggerHwService.h
     @@ -141,9 +141,6 @@ public:
    diff --git a/frameworks_base.patch b/frameworks_base.patch
    index 7034917..810b93c 100644
    --- a/frameworks_base.patch
    +++ b/frameworks_base.patch
    @@ -2197,29 +2197,6 @@ index 6fa28b1ccda..ea0347d67ad 100644
          }
      
          @SmallTest
    -diff --git a/core/tests/coretests/src/android/widget/TextViewActivityTest.java b/core/tests/coretests/src/android/widget/TextViewActivityTest.java
    -index 67ffd2b0ca3..381597670f8 100644
    ---- a/core/tests/coretests/src/android/widget/TextViewActivityTest.java
    -+++ b/core/tests/coretests/src/android/widget/TextViewActivityTest.java
    -@@ -699,4 +699,18 @@ public class TextViewActivityTest extends ActivityInstrumentationTestCase2<TextV
    -         // hasTransientState should return false when selection is created by API.
    -         assertFalse(textView.hasTransientState());
    -     }
    -+/*
    -+    @SmallTest
    -+    public void testNoAssistItemForTextFieldWithUnsupportedCharacters() throws Throwable {
    -+        useSystemDefaultTextClassifier();
    -+        final String text = "\u202Emoc.diordna.com";
    -+        final TextView textView = mActivity.findViewById(R.id.textview);
    -+        mActivityRule.runOnUiThread(() -> textView.setText(text));
    -+        mInstrumentation.waitForIdleSync();
    -+
    -+        onView(withId(R.id.textview)).perform(longPressOnTextAtIndex(text.indexOf('.')));
    -+        sleepForFloatingToolbarPopup();
    -+        assertFloatingToolbarDoesNotContainItem(android.R.id.textAssist);
    -+    }
    -+*/
    - }
     diff --git a/libs/androidfw/ResourceTypes.cpp b/libs/androidfw/ResourceTypes.cpp
     index ceeb12bab20..65588b2fafc 100644
     --- a/libs/androidfw/ResourceTypes.cpp
    @@ -3025,6 +3002,39 @@ index f5447a29350..329dd9917a7 100644
          }
      
          private class UsbDisconnectedReceiver extends BroadcastReceiver {
    +diff --git a/packages/VpnDialogs/AndroidManifest.xml b/packages/VpnDialogs/AndroidManifest.xml
    +index a3d27ce8a3d..60ed3245bc2 100644
    +--- a/packages/VpnDialogs/AndroidManifest.xml
    ++++ b/packages/VpnDialogs/AndroidManifest.xml
    +@@ -21,6 +21,7 @@
    + 
    +     <uses-permission android:name="android.permission.CONTROL_VPN" />
    +     <uses-permission android:name="android.permission.CONNECTIVITY_INTERNAL" />
    ++    <uses-permission android:name="android.permission.HIDE_NON_SYSTEM_OVERLAY_WINDOWS"/>
    + 
    +     <application android:label="VpnDialogs"
    +             android:allowBackup="false" >
    +diff --git a/packages/VpnDialogs/src/com/android/vpndialogs/ConfirmDialog.java b/packages/VpnDialogs/src/com/android/vpndialogs/ConfirmDialog.java
    +index 72ce9c4efdc..09339743db5 100644
    +--- a/packages/VpnDialogs/src/com/android/vpndialogs/ConfirmDialog.java
    ++++ b/packages/VpnDialogs/src/com/android/vpndialogs/ConfirmDialog.java
    +@@ -16,6 +16,8 @@
    + 
    + package com.android.vpndialogs;
    + 
    ++import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS;
    ++
    + import android.content.Context;
    + import android.content.DialogInterface;
    + import android.content.pm.PackageManager;
    +@@ -78,6 +80,7 @@ public class ConfirmDialog extends AlertActivity
    +         setupAlert();
    + 
    +         getWindow().setCloseOnTouchOutside(false);
    ++        getWindow().addPrivateFlags(PRIVATE_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS);
    +         Button button = mAlert.getButton(DialogInterface.BUTTON_POSITIVE);
    +         button.setFilterTouchesWhenObscured(true);
    +     }
     diff --git a/services/core/java/com/android/server/AppOpsService.java b/services/core/java/com/android/server/AppOpsService.java
     index 4caeba84b20..c95b9d52ad8 100644
     --- a/services/core/java/com/android/server/AppOpsService.java
    @@ -3329,7 +3339,7 @@ index 91c4571ee49..7be177a1bc2 100644
              }
      
     diff --git a/services/core/java/com/android/server/am/ActivityStackSupervisor.java b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
    -index c6ab9186456..8ba368b0b00 100644
    +index c6ab9186456..6115bf3ffd0 100644
     --- a/services/core/java/com/android/server/am/ActivityStackSupervisor.java
     +++ b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
     @@ -2855,10 +2855,10 @@ public final class ActivityStackSupervisor implements DisplayListener {
    @@ -3344,6 +3354,52 @@ index c6ab9186456..8ba368b0b00 100644
              if (mService.mShuttingDown) {
                  mService.notifyAll();
              }
    +@@ -3977,18 +3977,11 @@ public final class ActivityStackSupervisor implements DisplayListener {
    +                             mLockTaskNotify = new LockTaskNotify(mService.mContext);
    +                         }
    +                         mLockTaskNotify.show(false);
    +-                        try {
    +-                            boolean shouldLockKeyguard = Settings.Secure.getInt(
    +-                                    mService.mContext.getContentResolver(),
    +-                                    Settings.Secure.LOCK_TO_APP_EXIT_LOCKED) != 0;
    +-                            if (mLockTaskModeState == LOCK_TASK_MODE_PINNED && shouldLockKeyguard) {
    +-                                mWindowManager.lockNow(null);
    +-                                mWindowManager.dismissKeyguard();
    +-                                new LockPatternUtils(mService.mContext)
    +-                                        .requireCredentialEntry(UserHandle.USER_ALL);
    +-                            }
    +-                        } catch (SettingNotFoundException e) {
    +-                            // No setting, don't lock.
    ++                        if (mLockTaskModeState == LOCK_TASK_MODE_PINNED && shouldLockKeyguard()) {
    ++                            mWindowManager.lockNow(null);
    ++                            mWindowManager.dismissKeyguard();
    ++                            new LockPatternUtils(mService.mContext)
    ++                                    .requireCredentialEntry(UserHandle.USER_ALL);
    +                         }
    +                     } catch (RemoteException ex) {
    +                         throw new RuntimeException(ex);
    +@@ -4025,6 +4018,21 @@ public final class ActivityStackSupervisor implements DisplayListener {
    +         }
    +     }
    + 
    ++    private boolean shouldLockKeyguard() {
    ++        // This functionality should be kept consistent with
    ++        // com.android.settings.security.ScreenPinningSettings (see b/127605586)
    ++        try {
    ++            return Settings.Secure.getInt(
    ++                    mService.mContext.getContentResolver(),
    ++                    Settings.Secure.LOCK_TO_APP_EXIT_LOCKED) != 0;
    ++        } catch (Settings.SettingNotFoundException e) {
    ++            // Log to SafetyNet for b/127605586
    ++            android.util.EventLog.writeEvent(0x534e4554, "127605586", -1, "");
    ++            LockPatternUtils lockPatternUtils = new LockPatternUtils(mService.mContext);
    ++            return lockPatternUtils.isSecure(mCurrentUser);
    ++        }
    ++    }
    ++
    +     class ActivityContainer extends android.app.IActivityContainer.Stub {
    +         final static int FORCE_NEW_TASK_FLAGS = FLAG_ACTIVITY_NEW_TASK |
    +                 FLAG_ACTIVITY_MULTIPLE_TASK | Intent.FLAG_ACTIVITY_NO_ANIMATION;
     diff --git a/services/core/java/com/android/server/clipboard/ClipboardService.java b/services/core/java/com/android/server/clipboard/ClipboardService.java
     index 66aa40325a4..6f59e845219 100644
     --- a/services/core/java/com/android/server/clipboard/ClipboardService.java
    @@ -3628,7 +3684,7 @@ index 719ce7618fd..df2c00be83d 100644
      
              public long notifyANR(InputApplicationHandle inputApplicationHandle,
     diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
    -index b6a99408122..11b5832ad6a 100644
    +index b6a99408122..6ccc128fff7 100644
     --- a/services/core/java/com/android/server/pm/PackageManagerService.java
     +++ b/services/core/java/com/android/server/pm/PackageManagerService.java
     @@ -423,7 +423,7 @@ public class PackageManagerService extends IPackageManager.Stub {
    @@ -3640,6 +3696,20 @@ index b6a99408122..11b5832ad6a 100644
      
          /**
           * Whether verification is enabled by default.
    +@@ -15686,6 +15686,13 @@ public class PackageManagerService extends IPackageManager.Stub {
    + 
    +     @Override
    +     public boolean isPackageDeviceAdminOnAnyUser(String packageName) {
    ++	final int callingUid = Binder.getCallingUid();
    ++        if (checkUidPermission(android.Manifest.permission.MANAGE_USERS, callingUid)
    ++                != PERMISSION_GRANTED) {
    ++            EventLog.writeEvent(0x534e4554, "128599183", -1, "");
    ++            throw new SecurityException(android.Manifest.permission.MANAGE_USERS
    ++                    + " permission is required to call this API");
    ++        }
    +         return isPackageDeviceAdmin(packageName, UserHandle.USER_ALL);
    +     }
    + 
     diff --git a/services/core/java/com/android/server/pm/ShortcutService.java b/services/core/java/com/android/server/pm/ShortcutService.java
     index 6e8799e8132..b33cbfd6b0c 100644
     --- a/services/core/java/com/android/server/pm/ShortcutService.java
    @@ -4078,7 +4148,7 @@ index aa8e781b1c0..ec3208b3cc6 100644
                  if (DEBUG_VISIBILITY) Slog.v(TAG, "Show surface turning screen on: " + mWin);
                  mWin.mTurnOnScreen = false;
     diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
    -index e3b6ecc749c..ff63b08e96e 100644
    +index e3b6ecc749c..e7f01282268 100644
     --- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
     +++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
     @@ -71,6 +71,7 @@ import android.content.pm.PackageManager;
    @@ -4097,7 +4167,25 @@ index e3b6ecc749c..ff63b08e96e 100644
      import android.util.Log;
      import android.util.Pair;
      import android.util.Slog;
    -@@ -8621,6 +8623,10 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
    +@@ -3153,6 +3155,9 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
    + 
    +     @Override
    +     public boolean isSeparateProfileChallengeAllowed(int userHandle) {
    ++        if (!isCallerWithSystemUid()) {
    ++            throw new SecurityException("Caller must be system");
    ++        }
    +         ComponentName profileOwner = getProfileOwner(userHandle);
    +         // Profile challenge is supported on N or newer release.
    +         return profileOwner != null &&
    +@@ -7115,6 +7120,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
    +         if (!mHasFeature) {
    +             return null;
    +         }
    ++        enforceManageUsers();
    +         synchronized (this) {
    +             List<String> result = null;
    +             // If we have multiple profiles we return the intersection of the
    +@@ -8621,6 +8627,10 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
                              < android.os.Build.VERSION_CODES.M) {
                          return false;
                      }
    @@ -4108,7 +4196,7 @@ index e3b6ecc749c..ff63b08e96e 100644
                      final PackageManager packageManager = mContext.getPackageManager();
                      switch (grantState) {
                          case DevicePolicyManager.PERMISSION_GRANT_STATE_GRANTED: {
    -@@ -8646,6 +8652,8 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
    +@@ -8646,6 +8656,8 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
                      return true;
                  } catch (SecurityException se) {
                      return false;
    @@ -4117,7 +4205,7 @@ index e3b6ecc749c..ff63b08e96e 100644
                  } finally {
                      mInjector.binderRestoreCallingIdentity(ident);
                  }
    -@@ -8691,6 +8699,13 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
    +@@ -8691,6 +8703,13 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
              }
          }
      
    diff --git a/frameworks_native.patch b/frameworks_native.patch
    index 08fc09e..6eb72fe 100644
    --- a/frameworks_native.patch
    +++ b/frameworks_native.patch
    @@ -389,7 +389,7 @@ index eccc400c0..3efebf7ea 100644
          }
      }
     diff --git a/libs/binder/Parcel.cpp b/libs/binder/Parcel.cpp
    -index 19ce3ebae..e6630d549 100644
    +index 19ce3ebae..1626376e3 100644
     --- a/libs/binder/Parcel.cpp
     +++ b/libs/binder/Parcel.cpp
     @@ -459,6 +459,7 @@ void Parcel::setDataPosition(size_t pos) const
    @@ -508,6 +508,17 @@ index 19ce3ebae..e6630d549 100644
              const void* data = mData+mDataPos;
              mDataPos += sizeof(T);
              *pArg =  *reinterpret_cast<const T*>(data);
    +@@ -1825,8 +1906,8 @@ status_t Parcel::readUtf8FromUtf16(std::unique_ptr<std::string>* str) const {
    + 
    + const char* Parcel::readCString() const
    + {
    +-    const size_t avail = mDataSize-mDataPos;
    +-    if (avail > 0) {
    ++    if (mDataPos < mDataSize) {
    ++        const size_t avail = mDataSize-mDataPos;
    +         const char* str = reinterpret_cast<const char*>(mData+mDataPos);
    +         // is the string's trailing NUL within the parcel's valid bounds?
    +         const char* eos = reinterpret_cast<const char*>(memchr(str, 0, avail));
     @@ -2206,6 +2287,7 @@ void Parcel::ipcSetDataReference(const uint8_t* data, size_t dataSize,
          mObjects = const_cast<binder_size_t*>(objects);
          mObjectsSize = mObjectsCapacity = objectsCount;
    @@ -551,6 +562,42 @@ index f13f49fe9..e45b5f1ff 100644
      }
              
      }; // namespace android
    +diff --git a/libs/binder/Status.cpp b/libs/binder/Status.cpp
    +index d3520d62e..352754602 100644
    +--- a/libs/binder/Status.cpp
    ++++ b/libs/binder/Status.cpp
    +@@ -66,13 +66,22 @@ status_t Status::readFromParcel(const Parcel& parcel) {
    +     // Skip over fat response headers.  Not used (or propagated) in native code.
    +     if (mException == EX_HAS_REPLY_HEADER) {
    +         // Note that the header size includes the 4 byte size field.
    +-        const int32_t header_start = parcel.dataPosition();
    ++        const size_t header_start = parcel.dataPosition();
    ++        const size_t header_avail = parcel.dataAvail();
    ++
    +         int32_t header_size;
    +         status = parcel.readInt32(&header_size);
    +         if (status != OK) {
    +             setFromStatusT(status);
    +             return status;
    +         }
    ++
    ++        if (header_size < 0 || static_cast<size_t>(header_size) > header_avail) {
    ++          android_errorWriteLog(0x534e4554, "132650049");
    ++          setFromStatusT(UNKNOWN_ERROR);
    ++          return UNKNOWN_ERROR;
    ++        }
    ++
    +         parcel.setDataPosition(header_start + header_size);
    +         // And fat response headers are currently only used when there are no
    +         // exceptions, so act like there was no error.
    +@@ -95,6 +104,7 @@ status_t Status::readFromParcel(const Parcel& parcel) {
    +     if (mException == EX_SERVICE_SPECIFIC) {
    +         status = parcel.readInt32(&mErrorCode);
    +     }
    ++
    +     if (status != OK) {
    +         setFromStatusT(status);
    +         return status;
     diff --git a/libs/binder/tests/binderDriverInterfaceTest.cpp b/libs/binder/tests/binderDriverInterfaceTest.cpp
     index 027755025..d8fd81c92 100644
     --- a/libs/binder/tests/binderDriverInterfaceTest.cpp
    diff --git a/packages_apps_nfc.patch b/packages_apps_nfc.patch
    index 2a7860a..fd13132 100644
    --- a/packages_apps_nfc.patch
    +++ b/packages_apps_nfc.patch
    @@ -1,3 +1,53 @@
    +diff --git a/nci/jni/extns/pn54x/src/mifare/phNxpExtns_MifareStd.c b/nci/jni/extns/pn54x/src/mifare/phNxpExtns_MifareStd.c
    +index 6f58e08c..50e2deea 100755
    +--- a/nci/jni/extns/pn54x/src/mifare/phNxpExtns_MifareStd.c
    ++++ b/nci/jni/extns/pn54x/src/mifare/phNxpExtns_MifareStd.c
    +@@ -14,6 +14,7 @@
    +  * limitations under the License.
    +  */
    + 
    ++#include <log/log.h>
    + #include <nfc_api.h>
    + #include <rw_api.h>
    + #include <phNfcCompId.h>
    +@@ -1067,6 +1068,12 @@ NFCSTATUS Mfc_Transceive(uint8_t *p_data, uint32_t len)
    +     NFCSTATUS status = NFCSTATUS_FAILED;
    +     uint8_t i = 0x00;
    + 
    ++    if( len == 0 )
    ++    {
    ++        android_errorWriteLog(0x534e4554, "132082342");
    ++        return status;
    ++    }
    ++
    +     gphNxpExtns_Context.RawWriteCallBack = FALSE;
    +     gphNxpExtns_Context.CallBackMifare = NULL;
    +     gphNxpExtns_Context.CallBackCtxt   = NdefMap;
    +@@ -1074,6 +1081,11 @@ NFCSTATUS Mfc_Transceive(uint8_t *p_data, uint32_t len)
    +     EXTNS_SetCallBackFlag(TRUE);
    +     if( p_data[0] == 0x60 || p_data[0] == 0x61 )
    +     {
    ++        if ( len < 12 )
    ++        {
    ++            android_errorWriteLog(0x534e4554, "125900276");
    ++            return status;
    ++        }
    + 
    +         NdefMap->Cmd.MfCmd = p_data[0];
    + 
    +@@ -2051,6 +2063,12 @@ NFCSTATUS phFriNfc_ExtnsTransceive(phNfc_sTransceiveInfo_t *pTransceiveInfo,
    +     uint32_t length = SendLength;
    +     uint8_t restore_payload[]={0x00, 0x00, 0x00, 0x00,};
    + 
    ++    if( SendLength == 0 )
    ++    {
    ++        android_errorWriteLog(0x534e4554, "132083376");
    ++        return status;
    ++    }
    ++
    +     buff = (uint8_t *)malloc((uint32_t)MAX_BUFF_SIZE);
    +     if( NULL == buff )
    +     {
     diff --git a/src/com/android/nfc/BeamShareActivity.java b/src/com/android/nfc/BeamShareActivity.java
     index 5b8acacd..f06bfdba 100644
     --- a/src/com/android/nfc/BeamShareActivity.java
    diff --git a/packages_apps_settings.patch b/packages_apps_settings.patch
    index 0be0462..1a9e0a4 100644
    --- a/packages_apps_settings.patch
    +++ b/packages_apps_settings.patch
    @@ -134,6 +134,24 @@ index 9d4d895330..2f6afd790f 100644
              try {
                  ActivityManagerNative.getDefault().resumeAppSwitches();
              } catch (RemoteException e) {
    +diff --git a/src/com/android/settings/ScreenPinningSettings.java b/src/com/android/settings/ScreenPinningSettings.java
    +index fb28dfbfc1..9ff4893303 100644
    +--- a/src/com/android/settings/ScreenPinningSettings.java
    ++++ b/src/com/android/settings/ScreenPinningSettings.java
    +@@ -106,9 +106,11 @@ public class ScreenPinningSettings extends SettingsPreferenceFragment
    +     }
    + 
    +     private boolean isScreenLockUsed() {
    +-        int def = getCurrentSecurityTitle() != R.string.screen_pinning_unlock_none ? 1 : 0;
    ++        // This functionality should be kept consistent with
    ++        // com.android.server.am.ActivityStackSupervisor (see b/127605586)
    ++        int defaultValueIfSettingNull = mLockPatternUtils.isSecure(UserHandle.myUserId()) ? 1 : 0;
    +         return Settings.Secure.getInt(getContentResolver(),
    +-                Settings.Secure.LOCK_TO_APP_EXIT_LOCKED, def) != 0;
    ++                Settings.Secure.LOCK_TO_APP_EXIT_LOCKED, defaultValueIfSettingNull) != 0;
    +     }
    + 
    +     private boolean setScreenLockUsed(boolean isEnabled) {
     diff --git a/src/com/android/settings/SettingsActivity.java b/src/com/android/settings/SettingsActivity.java
     index db9c0906ef..76041f2d1b 100644
     --- a/src/com/android/settings/SettingsActivity.java
    @@ -198,3 +216,73 @@ index 196a4ab372..1f69768c0d 100644
                      return ad;
                  }
                  case DIALOG_ID_DISABLE_WARNING: {
    +diff --git a/src/com/android/settings/notification/AppNotificationSettings.java b/src/com/android/settings/notification/AppNotificationSettings.java
    +index fd7a750111..6d5ae0d049 100644
    +--- a/src/com/android/settings/notification/AppNotificationSettings.java
    ++++ b/src/com/android/settings/notification/AppNotificationSettings.java
    +@@ -16,6 +16,8 @@
    + 
    + package com.android.settings.notification;
    + 
    ++import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS;
    ++
    + import android.app.Notification;
    + import android.app.NotificationManager;
    + import android.content.Intent;
    +@@ -28,15 +30,14 @@ import android.os.UserHandle;
    + import android.service.notification.NotificationListenerService.Ranking;
    + import android.util.ArrayMap;
    + import android.util.Log;
    +-
    ++import android.view.Window;
    ++import android.view.WindowManager;
    + import com.android.internal.logging.MetricsProto.MetricsEvent;
    + import com.android.internal.widget.LockPatternUtils;
    + import com.android.settings.AppHeader;
    + import com.android.settings.R;
    + import com.android.settings.notification.NotificationBackend.AppRow;
    + import com.android.settingslib.RestrictedSwitchPreference;
    +-
    +-
    + import java.util.List;
    + 
    + /** These settings are per app, so should not be returned in global search results. */
    +@@ -83,7 +84,8 @@ public class AppNotificationSettings extends NotificationSettingsBase {
    + 
    +             NotificationManager.Policy policy =
    +                     NotificationManager.from(mContext).getNotificationPolicy();
    +-            mDndVisualEffectsSuppressed = policy == null ? false : policy.suppressedVisualEffects != 0;
    ++            mDndVisualEffectsSuppressed =
    ++                    policy == null ? false : policy.suppressedVisualEffects != 0;
    + 
    +             // load settings intent
    +             ArrayMap<String, AppRow> rows = new ArrayMap<String, AppRow>();
    +@@ -98,12 +100,27 @@ public class AppNotificationSettings extends NotificationSettingsBase {
    +         }
    +     }
    + 
    ++    @Override
    ++    public void onResume() {
    ++        super.onResume();
    ++        getActivity().getWindow().addPrivateFlags(PRIVATE_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS);
    ++        android.util.EventLog.writeEvent(0x534e4554, "119115683", -1, "");
    ++    }
    ++
    ++    public void onPause() {
    ++        super.onPause();
    ++        final Window window = getActivity().getWindow();
    ++        final WindowManager.LayoutParams attrs = window.getAttributes();
    ++        attrs.privateFlags &= ~PRIVATE_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS;
    ++        window.setAttributes(attrs);
    ++    }
    ++
    +     @Override
    +     protected void updateDependents(int importance) {
    +         LockPatternUtils utils = new LockPatternUtils(getActivity());
    +         boolean lockscreenSecure = utils.isSecure(UserHandle.myUserId());
    +         UserInfo parentUser = mUm.getProfileParent(UserHandle.myUserId());
    +-        if (parentUser != null){
    ++        if (parentUser != null) {
    +             lockscreenSecure |= utils.isSecure(parentUser.id);
    +         }
    + 
    diff --git a/system_bt.patch b/system_bt.patch
    index 82b87fa..33e6177 100644
    --- a/system_bt.patch
    +++ b/system_bt.patch
    @@ -589,10 +589,26 @@ index d02dfa0b8..90d74cf53 100644
              return handle;
          }
     diff --git a/btif/src/btif_storage.c b/btif/src/btif_storage.c
    -index 83dcc8c47..d02b09a55 100644
    +index 83dcc8c47..670af4f4d 100644
     --- a/btif/src/btif_storage.c
     +++ b/btif/src/btif_storage.c
    -@@ -229,6 +229,10 @@ static int prop2cfg(bt_bdaddr_t *remote_bd_addr, bt_property_t *prop)
    +@@ -35,6 +35,7 @@
    + #include <alloca.h>
    + #include <assert.h>
    + #include <ctype.h>
    ++#include <log/log.h>
    + #include <stdlib.h>
    + #include <string.h>
    + #include <time.h>
    +@@ -49,6 +50,7 @@
    + #include "osi/include/allocator.h"
    + #include "osi/include/compat.h"
    + #include "osi/include/config.h"
    ++#include "osi/include/list.h"
    + #include "osi/include/log.h"
    + #include "osi/include/osi.h"
    + 
    +@@ -229,6 +231,10 @@ static int prop2cfg(bt_bdaddr_t *remote_bd_addr, bt_property_t *prop)
                      bt_uuid_t *p_uuid = (bt_uuid_t*)prop->val + i;
                      memset(buf, 0, sizeof(buf));
                      uuid_to_string_legacy(p_uuid, buf);
    @@ -603,6 +619,76 @@ index 83dcc8c47..d02b09a55 100644
                      strcat(value, buf);
                      //strcat(value, ";");
                      strcat(value, " ");
    +@@ -829,6 +835,47 @@ bt_status_t btif_storage_remove_bonded_device(bt_bdaddr_t *remote_bd_addr)
    + 
    + }
    + 
    ++/* Some devices hardcode sample LTK value from spec, instead of generating one.
    ++ * Treat such devices as insecure, and remove such bonds when bluetooth restarts.
    ++ * Removing them after disconnection is handled separately.
    ++ *
    ++ * We still allow such devices to bond in order to give the user a chance to update
    ++ * firmware.
    ++ */
    ++static void remove_devices_with_sample_ltk() {
    ++    list_t *bad_ltk = list_new(osi_free);
    ++
    ++    for (const btif_config_section_iter_t *iter = btif_config_section_begin(); iter != btif_config_section_end(); iter = btif_config_section_next(iter)) {
    ++        const char *name = btif_config_section_name(iter);
    ++        if (!string_is_bdaddr(name)) {
    ++            continue;
    ++        }
    ++
    ++        bt_bdaddr_t *bda = osi_malloc(sizeof(bt_bdaddr_t));
    ++        string_to_bdaddr(name, bda);
    ++
    ++        tBTA_LE_KEY_VALUE key;
    ++        memset(&key, 0, sizeof(key));
    ++
    ++        if (btif_storage_get_ble_bonding_key(bda, BTIF_DM_LE_KEY_PENC, (char*)&key, sizeof(tBTM_LE_PENC_KEYS)) ==
    ++              BT_STATUS_SUCCESS) {
    ++              if (is_sample_ltk(key.penc_key.ltk)) {
    ++                  list_append(bad_ltk, (void*)bda);
    ++              }
    ++        }
    ++    }
    ++
    ++    for (list_node_t *sn = list_begin(bad_ltk); sn != list_end(bad_ltk); sn = list_next(sn)) {
    ++        android_errorWriteLog(0x534e4554, "128437297");
    ++        BTIF_TRACE_ERROR("%s: removing bond to device using test TLK", __func__);
    ++
    ++        bt_bdaddr_t *bda = (bt_bdaddr_t*)list_node(sn);
    ++        btif_storage_remove_bonded_device(bda);
    ++    }
    ++
    ++    list_free(bad_ltk);
    ++}
    ++
    + /*******************************************************************************
    + **
    + ** Function         btif_storage_load_bonded_devices
    +@@ -855,6 +902,8 @@ bt_status_t btif_storage_load_bonded_devices(void)
    +     bt_uuid_t local_uuids[BT_MAX_NUM_UUIDS];
    +     bt_uuid_t remote_uuids[BT_MAX_NUM_UUIDS];
    + 
    ++    remove_devices_with_sample_ltk();
    ++
    +     btif_in_fetch_bonded_devices(&bonded_devices, 1);
    + 
    +     /* Now send the adapter_properties_cb with all adapter_properties */
    +diff --git a/device/src/controller.c b/device/src/controller.c
    +index 4440ea55a..23799d803 100644
    +--- a/device/src/controller.c
    ++++ b/device/src/controller.c
    +@@ -252,6 +252,8 @@ static future_t *start_up(void) {
    +         &number_of_local_supported_codecs, local_supported_codecs);
    +   }
    + 
    ++  assert(HCI_READ_ENCR_KEY_SIZE_SUPPORTED(supported_commands));
    ++
    +   readable = true;
    +   return future_new_immediate(FUTURE_SUCCESS);
    + }
     diff --git a/osi/src/alarm.c b/osi/src/alarm.c
     index 69ded69e4..5f9e42ce3 100644
     --- a/osi/src/alarm.c
    @@ -1880,6 +1966,182 @@ index 8df005bf8..b278dea8f 100644
          }
      
          return TRUE;
    +diff --git a/stack/btm/btm_sec.c b/stack/btm/btm_sec.c
    +index 83f6494c4..5b3a57684 100644
    +--- a/stack/btm/btm_sec.c
    ++++ b/stack/btm/btm_sec.c
    +@@ -24,6 +24,7 @@
    + 
    + #define LOG_TAG "bt_btm_sec"
    + 
    ++#include <log/log.h>
    + #include <stdarg.h>
    + #include <string.h>
    + 
    +@@ -47,6 +48,9 @@
    +     #include "gatt_int.h"
    + #endif
    + 
    ++#include "bta/sys/bta_sys.h"
    ++#include "bta/dm/bta_dm_int.h"
    ++
    + #define BTM_SEC_MAX_COLLISION_DELAY     (5000)
    + 
    + extern fixed_queue_t *btu_general_alarm_queue;
    +@@ -4808,6 +4812,19 @@ void btm_sec_disconnected (UINT16 handle, UINT8 reason)
    +                 | BTM_SEC_ROLE_SWITCHED | BTM_SEC_16_DIGIT_PIN_AUTHED);
    +     }
    + 
    ++    /* Some devices hardcode sample LTK value from spec, instead of generating
    ++     * one. Treat such devices as insecure, and remove such bonds on
    ++     * disconnection.
    ++     */
    ++    if (is_sample_ltk(p_dev_rec->ble.keys.pltk)) {
    ++      android_errorWriteLog(0x534e4554, "128437297");
    ++      BTM_TRACE_ERROR("%s: removing bond to device that used sample LTK", __func__);
    ++
    ++      tBTA_DM_MSG p_data;
    ++      memcpy(p_data.remove_dev.bd_addr, p_dev_rec->bd_addr, BD_ADDR_LEN);
    ++      bta_dm_remove_device(&p_data);
    ++    }
    ++
    + #if BLE_INCLUDED == TRUE && SMP_INCLUDED == TRUE
    +     if (p_dev_rec->sec_state == BTM_SEC_STATE_DISCONNECTING_BOTH)
    +     {
    +diff --git a/stack/btu/btu_hcif.c b/stack/btu/btu_hcif.c
    +index ade7a9b59..cf8922a99 100644
    +--- a/stack/btu/btu_hcif.c
    ++++ b/stack/btu/btu_hcif.c
    +@@ -28,6 +28,7 @@
    + #define LOG_TAG "bt_btu_hcif"
    + 
    + #include <assert.h>
    ++#include <log/log.h>
    + #include <stdio.h>
    + #include <stdlib.h>
    + #include <string.h>
    +@@ -601,6 +602,55 @@ static void btu_hcif_rmt_name_request_comp_evt (UINT8 *p, UINT16 evt_len)
    +     btm_sec_rmt_name_request_complete (bd_addr, p, status);
    + }
    + 
    ++const uint8_t MIN_KEY_SIZE = 7;
    ++bool read_key_send_from_key_refresh = false;
    ++
    ++static void read_encryption_key_size_complete_after_key_refresh(
    ++    uint8_t status, uint16_t handle, uint8_t key_size) {
    ++  if (status != HCI_SUCCESS) {
    ++    HCI_TRACE_WARNING("%s: disconnecting, status: 0x%02x", __func__, status);
    ++    btsnd_hcic_disconnect(handle, HCI_ERR_PEER_USER);
    ++    return;
    ++  }
    ++
    ++  if (key_size < MIN_KEY_SIZE) {
    ++    android_errorWriteLog(0x534e4554, "124301137");
    ++    HCI_TRACE_ERROR(
    ++        "%s encryption key too short, disconnecting. handle: 0x%02x, key_size: "
    ++        "%d",
    ++        __func__, handle, key_size);
    ++
    ++    btsnd_hcic_disconnect(handle, HCI_ERR_HOST_REJECT_SECURITY);
    ++    return;
    ++  }
    ++  
    ++  btm_sec_encrypt_change(handle, status, 1 /* enc_enable */);
    ++}
    ++
    ++static void read_encryption_key_size_complete_after_encryption_change(
    ++    uint8_t status, uint16_t handle, uint8_t key_size) {
    ++  if (status != HCI_SUCCESS) {
    ++    HCI_TRACE_WARNING("%s: disconnecting, status: 0x%02x", __func__, status);
    ++    btsnd_hcic_disconnect(handle, HCI_ERR_PEER_USER);
    ++    return;
    ++  }
    ++
    ++  if (key_size < MIN_KEY_SIZE) {
    ++    android_errorWriteLog(0x534e4554, "124301137");
    ++    HCI_TRACE_ERROR(
    ++        "%s encryption key too short, disconnecting. handle: 0x%02x, key_size: "
    ++        "%d",
    ++        __func__, handle, key_size);
    ++
    ++    btsnd_hcic_disconnect(handle, HCI_ERR_HOST_REJECT_SECURITY);
    ++    return;
    ++  }
    ++
    ++  // good key size - succeed
    ++  btm_acl_encrypt_change(handle, status, 1 /* enable */);
    ++  btm_sec_encrypt_change(handle, status, 1 /* enable */);
    ++}
    ++
    + /*******************************************************************************
    + **
    + ** Function         btu_hcif_encryption_change_evt
    +@@ -620,8 +670,14 @@ static void btu_hcif_encryption_change_evt (UINT8 *p)
    +     STREAM_TO_UINT16 (handle, p);
    +     STREAM_TO_UINT8  (encr_enable, p);
    + 
    +-    btm_acl_encrypt_change (handle, status, encr_enable);
    +-    btm_sec_encrypt_change (handle, status, encr_enable);
    ++    if (status != HCI_SUCCESS || encr_enable == 0 ||
    ++        BTM_IsBleConnection(handle)) {
    ++        btm_acl_encrypt_change (handle, status, encr_enable);
    ++        btm_sec_encrypt_change (handle, status, encr_enable);
    ++    } else {
    ++        read_key_send_from_key_refresh = false;
    ++        btsnd_hcic_read_encryption_key_size(handle);
    ++    }
    + }
    + 
    + /*******************************************************************************
    +@@ -824,6 +880,26 @@ static void btu_hcif_hdl_command_complete (UINT16 opcode, UINT8 *p, UINT16 evt_l
    +             btm_read_inq_tx_power_complete(p);
    +             break;
    + 
    ++        case HCI_READ_ENCR_KEY_SIZE: {
    ++            UINT8 *pp = p;
    ++
    ++            UINT8   status;
    ++            UINT16  handle;
    ++            UINT8   key_size;
    ++
    ++            STREAM_TO_UINT8  (status, pp);
    ++            STREAM_TO_UINT16 (handle, pp);
    ++            STREAM_TO_UINT8  (key_size, pp);
    ++
    ++            if (read_key_send_from_key_refresh) {
    ++                read_encryption_key_size_complete_after_encryption_change(status, handle, key_size);
    ++            } else {
    ++                read_encryption_key_size_complete_after_key_refresh(status, handle, key_size);
    ++            }
    ++
    ++            }
    ++            break;
    ++
    + #if (BLE_INCLUDED == TRUE)
    + /* BLE Commands sComplete*/
    +         case HCI_BLE_ADD_WHITE_LIST:
    +@@ -1595,6 +1671,7 @@ static void btu_hcif_enhanced_flush_complete_evt (void)
    + ** BLE Events
    + ***********************************************/
    + #if (defined BLE_INCLUDED) && (BLE_INCLUDED == TRUE)
    ++
    + static void btu_hcif_encryption_key_refresh_cmpl_evt (UINT8 *p)
    + {
    +     UINT8   status;
    +@@ -1606,7 +1683,12 @@ static void btu_hcif_encryption_key_refresh_cmpl_evt (UINT8 *p)
    + 
    +     if (status == HCI_SUCCESS) enc_enable = 1;
    + 
    +-    btm_sec_encrypt_change (handle, status, enc_enable);
    ++    if (status != HCI_SUCCESS || BTM_IsBleConnection(handle)) {
    ++        btm_sec_encrypt_change (handle, status, enc_enable);
    ++    } else  {
    ++        read_key_send_from_key_refresh = true;
    ++        btsnd_hcic_read_encryption_key_size(handle);
    ++    }
    + }
    + 
    + static void btu_ble_process_adv_pkt (UINT8 *p)
     diff --git a/stack/btu/btu_init.c b/stack/btu/btu_init.c
     index 688ed889d..9f9ed0a50 100644
     --- a/stack/btu/btu_init.c
    @@ -1977,6 +2239,57 @@ index 11ef79c83..c2cdb885d 100644
          UNUSED(len);
      
          if (op_code == GATT_REQ_READ_BLOB)
    +diff --git a/stack/hcic/hcicmds.c b/stack/hcic/hcicmds.c
    +index 34fce493d..ef0670df7 100644
    +--- a/stack/hcic/hcicmds.c
    ++++ b/stack/hcic/hcicmds.c
    +@@ -1356,6 +1356,20 @@ BOOLEAN btsnd_hcic_read_rssi (UINT16 handle)
    +     return (TRUE);
    + }
    + 
    ++BOOLEAN btsnd_hcic_read_encryption_key_size(UINT16 handle) {
    ++    BT_HDR *p = (BT_HDR *)osi_malloc(HCI_CMD_BUF_SIZE);
    ++    UINT8 *pp = (UINT8 *)(p + 1);
    ++
    ++    p->len    = HCIC_PREAMBLE_SIZE + 2;
    ++    p->offset = 0;
    ++
    ++    UINT16_TO_STREAM (pp, handle);
    ++
    ++    btu_hcif_send_cmd (LOCAL_BR_EDR_CONTROLLER_ID,  p);
    ++    return (TRUE);
    ++}
    ++
    ++
    + BOOLEAN btsnd_hcic_enable_test_mode (void)
    + {
    +     BT_HDR *p = (BT_HDR *)osi_malloc(HCI_CMD_BUF_SIZE);
    +@@ -1427,6 +1441,25 @@ BOOLEAN btsnd_hcic_write_pagescan_type (UINT8 type)
    + #error "HCI_CMD_BUF_SIZE must be larger than 268"
    + #endif
    + 
    ++void btsnd_hcic_raw_cmd (void *buffer, UINT16 opcode, UINT8 len,
    ++                                 UINT8 *p_data, void *p_cmd_cplt_cback)
    ++{
    ++    BT_HDR *p = (BT_HDR *)buffer;
    ++    UINT8 *pp = (UINT8 *)(p + 1);
    ++
    ++    p->len    = HCIC_PREAMBLE_SIZE + len;
    ++    p->offset = sizeof(void *);
    ++
    ++    *((void **)pp) = p_cmd_cplt_cback;  /* Store command complete callback in buffer */
    ++    pp += sizeof(void *);               /* Skip over callback pointer */
    ++
    ++    UINT16_TO_STREAM (pp, opcode);
    ++    UINT8_TO_STREAM  (pp, len);
    ++    ARRAY_TO_STREAM  (pp, p_data, len);
    ++
    ++    btu_hcif_send_cmd (LOCAL_BR_EDR_CONTROLLER_ID,  p);
    ++}
    ++
    + void btsnd_hcic_vendor_spec_cmd (void *buffer, UINT16 opcode, UINT8 len,
    +                                  UINT8 *p_data, void *p_cmd_cplt_cback)
    + {
     diff --git a/stack/hid/hidh_conn.c b/stack/hid/hidh_conn.c
     index ffbafe428..0e6a05d76 100644
     --- a/stack/hid/hidh_conn.c
    @@ -2004,6 +2317,32 @@ index ffbafe428..0e6a05d76 100644
      
          ttype    = HID_GET_TRANS_FROM_HDR(*p_data);
          param    = HID_GET_PARAM_FROM_HDR(*p_data);
    +diff --git a/stack/include/bt_types.h b/stack/include/bt_types.h
    +index 34447b62f..ce9859272 100644
    +--- a/stack/include/bt_types.h
    ++++ b/stack/include/bt_types.h
    +@@ -21,6 +21,7 @@
    + 
    + #include <stdint.h>
    + #include <stdbool.h>
    ++#include <string.h>
    + 
    + #ifndef FALSE
    + #  define FALSE  false
    +@@ -791,4 +792,13 @@ static inline void bdsetany(BD_ADDR a)
    + {
    +     bdcpy(a, bd_addr_any);
    + }
    ++
    ++static inline bool is_sample_ltk(const BT_OCTET16 ltk) {
    ++  /* Sample LTK from BT Spec 5.1 | Vol 6, Part C 1
    ++   * 0x4C68384139F574D836BCF34E9DFB01BF */
    ++  const uint8_t SAMPLE_LTK[] = {0xbf, 0x01, 0xfb, 0x9d, 0x4e, 0xf3, 0xbc, 0x36,
    ++                                0xd8, 0x74, 0xf5, 0x39, 0x41, 0x38, 0x68, 0x4c};
    ++  return memcmp(ltk, SAMPLE_LTK, BT_OCTET16_LEN) == 0;
    ++}
    ++
    + #endif
     diff --git a/stack/include/btm_api.h b/stack/include/btm_api.h
     index 451cd6ff7..360dd48b2 100644
     --- a/stack/include/btm_api.h
    @@ -2034,6 +2373,41 @@ index 451cd6ff7..360dd48b2 100644
      extern BOOLEAN BTM_SecDeleteDevice (BD_ADDR bd_addr);
      
      /*******************************************************************************
    +diff --git a/stack/include/btm_ble_api.h b/stack/include/btm_ble_api.h
    +index 412fa8ea3..0cc2e18a2 100644
    +--- a/stack/include/btm_ble_api.h
    ++++ b/stack/include/btm_ble_api.h
    +@@ -1304,7 +1304,17 @@ extern BOOLEAN BTM_BleVerifySignature (BD_ADDR bd_addr, UINT8 *p_orig,
    + extern void BTM_ReadConnectionAddr (BD_ADDR remote_bda, BD_ADDR local_conn_addr,
    +                                             tBLE_ADDR_TYPE *p_addr_type);
    + 
    +-
    ++/*******************************************************************************
    ++ *
    ++ * Function         BTM_IsBleConnection
    ++ *
    ++ * Description      This function is called to check if the connection handle
    ++ *                  for an LE link
    ++ *
    ++ * Returns          true if connection is LE link, otherwise false.
    ++ *
    ++ ******************************************************************************/
    ++extern bool BTM_IsBleConnection(uint16_t conn_handle);
    + 
    + /*******************************************************************************
    + **
    +diff --git a/stack/include/hcimsgs.h b/stack/include/hcimsgs.h
    +index b59cbfa5a..30d861fbe 100644
    +--- a/stack/include/hcimsgs.h
    ++++ b/stack/include/hcimsgs.h
    +@@ -603,6 +603,7 @@ extern BOOLEAN btsnd_hcic_write_cur_iac_lap (UINT8 num_cur_iac,
    + 
    + extern BOOLEAN btsnd_hcic_get_link_quality (UINT16 handle);            /* Get Link Quality */
    + extern BOOLEAN btsnd_hcic_read_rssi (UINT16 handle);                   /* Read RSSI */
    ++extern BOOLEAN btsnd_hcic_read_encryption_key_size (UINT16 handle);    /* Read encryption key size */
    + extern BOOLEAN btsnd_hcic_enable_test_mode (void);                     /* Enable Device Under Test Mode */
    + extern BOOLEAN btsnd_hcic_write_pagescan_type(UINT8 type);             /* Write Page Scan Type */
    + extern BOOLEAN btsnd_hcic_write_inqscan_type(UINT8 type);              /* Write Inquiry Scan Type */
     diff --git a/stack/include/rfcdefs.h b/stack/include/rfcdefs.h
     index dcc37bc72..1c751f3f5 100644
     --- a/stack/include/rfcdefs.h
    @@ -2825,8 +3199,26 @@ index 739469f64..d7fb8e5cf 100644
      
              ea                   = *p_data & RFCOMM_EA;
              cr                   = (*p_data & RFCOMM_CR_MASK) >> RFCOMM_SHIFT_CR;
    +diff --git a/stack/sdp/sdp_db.c b/stack/sdp/sdp_db.c
    +index 8546536aa..cd1bf9e44 100644
    +--- a/stack/sdp/sdp_db.c
    ++++ b/stack/sdp/sdp_db.c
    +@@ -129,7 +129,12 @@ static BOOLEAN find_uuid_in_seq (UINT8 *p , UINT32 seq_len, UINT8 *p_uuid,
    +     while (p < p_end)
    +     {
    +         type = *p++;
    +-        p = sdpu_get_len_from_type (p, type, &len);
    ++        p = sdpu_get_len_from_type(p, p_end, type, &len);
    ++        if (p == NULL || (p + len) > p_end)
    ++        {
    ++            SDP_TRACE_WARNING("%s: bad length", __func__);
    ++            break;
    ++        }
    +         type = type >> 3;
    +         if (type == UUID_DESC_TYPE)
    +         {
     diff --git a/stack/sdp/sdp_discovery.c b/stack/sdp/sdp_discovery.c
    -index ec20689e3..416085db4 100644
    +index ec20689e3..1c0607707 100644
     --- a/stack/sdp/sdp_discovery.c
     +++ b/stack/sdp/sdp_discovery.c
     @@ -29,6 +29,7 @@
    @@ -2956,14 +3348,32 @@ index ec20689e3..416085db4 100644
          }
      }
      
    -@@ -367,10 +390,18 @@ static void sdp_copy_raw_data (tCONN_CB *p_ccb, BOOLEAN offset)
    +@@ -346,6 +369,7 @@ static void sdp_copy_raw_data (tCONN_CB *p_ccb, BOOLEAN offset)
    +     unsigned int    cpy_len;
    +     UINT32          list_len;
    +     UINT8           *p;
    ++    UINT8           *p_end;
    +     UINT8           type;
    + 
    + #if (SDP_DEBUG_RAW == TRUE)
    +@@ -364,13 +388,27 @@ static void sdp_copy_raw_data (tCONN_CB *p_ccb, BOOLEAN offset)
    +         cpy_len = p_ccb->p_db->raw_size - p_ccb->p_db->raw_used;
    +         list_len = p_ccb->list_len;
    +         p = &p_ccb->rsp_list[0];
    ++        p_end = &p_ccb->rsp_list[0] + list_len;
      
              if(offset)
              {
     +            cpy_len -= 1;
                  type = *p++;
    +-            p = sdpu_get_len_from_type (p, type, &list_len);
     +            uint8_t* old_p = p;
    -             p = sdpu_get_len_from_type (p, type, &list_len);
    ++            p = sdpu_get_len_from_type(p, p_end, type, &list_len);
    ++            if (p == NULL || (p + list_len) > p_end)
    ++            {
    ++                SDP_TRACE_WARNING("%s: bad length", __func__);
    ++                return;
    ++            }
     +            if ((int)cpy_len < (p - old_p))
     +            {
     +                SDP_TRACE_WARNING("%s: no bytes left for data", __func__);
    @@ -2976,7 +3386,7 @@ index ec20689e3..416085db4 100644
              {
                  cpy_len = list_len;
              }
    -@@ -395,7 +426,8 @@ static void sdp_copy_raw_data (tCONN_CB *p_ccb, BOOLEAN offset)
    +@@ -395,7 +433,8 @@ static void sdp_copy_raw_data (tCONN_CB *p_ccb, BOOLEAN offset)
      ** Returns          void
      **
      *******************************************************************************/
    @@ -2986,7 +3396,7 @@ index ec20689e3..416085db4 100644
      {
          UINT8           *p_start, *p_param_len;
          UINT16          param_len, list_byte_count;
    -@@ -502,8 +534,12 @@ static void process_service_attr_rsp (tCONN_CB *p_ccb, UINT8 *p_reply)
    +@@ -502,8 +541,12 @@ static void process_service_attr_rsp (tCONN_CB *p_ccb, UINT8 *p_reply)
              /* Was this a continuation request ? */
              if (cont_request_needed)
              {
    @@ -3001,7 +3411,7 @@ index ec20689e3..416085db4 100644
              }
              else
                  UINT8_TO_BE_STREAM (p, 0);
    -@@ -541,7 +577,8 @@ static void process_service_attr_rsp (tCONN_CB *p_ccb, UINT8 *p_reply)
    +@@ -541,7 +584,8 @@ static void process_service_attr_rsp (tCONN_CB *p_ccb, UINT8 *p_reply)
      ** Returns          void
      **
      *******************************************************************************/
    @@ -3011,7 +3421,7 @@ index ec20689e3..416085db4 100644
      {
          UINT8           *p, *p_start, *p_end, *p_param_len;
          UINT8           type;
    -@@ -555,6 +592,14 @@ static void process_service_search_attr_rsp (tCONN_CB *p_ccb, UINT8 *p_reply)
    +@@ -555,6 +599,14 @@ static void process_service_search_attr_rsp (tCONN_CB *p_ccb, UINT8 *p_reply)
          /* If p_reply is NULL, we were called for the initial read */
          if (p_reply)
          {
    @@ -3026,7 +3436,7 @@ index ec20689e3..416085db4 100644
      #if (SDP_DEBUG_RAW == TRUE)
              SDP_TRACE_WARNING("ID & len: 0x%02x-%02x-%02x-%02x",
                  p_reply[0], p_reply[1], p_reply[2], p_reply[3]);
    -@@ -578,6 +623,14 @@ static void process_service_search_attr_rsp (tCONN_CB *p_ccb, UINT8 *p_reply)
    +@@ -578,6 +630,14 @@ static void process_service_search_attr_rsp (tCONN_CB *p_ccb, UINT8 *p_reply)
              SDP_TRACE_WARNING("list_len: %d, list_byte_count: %d",
                  p_ccb->list_len, lists_byte_count);
      #endif
    @@ -3041,7 +3451,7 @@ index ec20689e3..416085db4 100644
              if (p_ccb->rsp_list == NULL)
                  p_ccb->rsp_list = (UINT8 *)osi_malloc(SDP_MAX_LIST_BYTE_COUNT);
              memcpy (&p_ccb->rsp_list[p_ccb->list_len], p_reply, lists_byte_count);
    -@@ -641,8 +694,12 @@ static void process_service_search_attr_rsp (tCONN_CB *p_ccb, UINT8 *p_reply)
    +@@ -641,8 +701,12 @@ static void process_service_search_attr_rsp (tCONN_CB *p_ccb, UINT8 *p_reply)
              /* No continuation for first request */
              if (p_reply)
              {
    @@ -3056,7 +3466,48 @@ index ec20689e3..416085db4 100644
              }
              else
                  UINT8_TO_BE_STREAM (p, 0);
    -@@ -764,7 +821,7 @@ static UINT8 *save_attr_seq (tCONN_CB *p_ccb, UINT8 *p, UINT8 *p_msg_end)
    +@@ -685,8 +749,12 @@ static void process_service_search_attr_rsp (tCONN_CB *p_ccb, UINT8 *p_reply)
    +         SDP_TRACE_WARNING ("SDP - Wrong type: 0x%02x in attr_rsp", type);
    +         return;
    +     }
    +-    p = sdpu_get_len_from_type (p, type, &seq_len);
    +-
    ++    p = sdpu_get_len_from_type(p, p + p_ccb->list_len, type, &seq_len);
    ++    if (p == NULL || (p + seq_len) > (p + p_ccb->list_len))
    ++    {
    ++        SDP_TRACE_WARNING("%s: bad length", __func__);
    ++        return;
    ++    }
    +     p_end = &p_ccb->rsp_list[p_ccb->list_len];
    + 
    +     if ((p + seq_len) != p_end)
    +@@ -733,9 +801,8 @@ static UINT8 *save_attr_seq (tCONN_CB *p_ccb, UINT8 *p, UINT8 *p_msg_end)
    +         SDP_TRACE_WARNING ("SDP - Wrong type: 0x%02x in attr_rsp", type);
    +         return (NULL);
    +     }
    +-
    +-    p = sdpu_get_len_from_type (p, type, &seq_len);
    +-    if ((p + seq_len) > p_msg_end)
    ++    p = sdpu_get_len_from_type(p, p_msg_end, type, &seq_len);
    ++    if (p == NULL || (p + seq_len) > p_msg_end)
    +     {
    +         SDP_TRACE_WARNING ("SDP - Bad len in attr_rsp %d", seq_len);
    +         return (NULL);
    +@@ -755,7 +822,12 @@ static UINT8 *save_attr_seq (tCONN_CB *p_ccb, UINT8 *p, UINT8 *p_msg_end)
    +     {
    +         /* First get the attribute ID */
    +         type = *p++;
    +-        p = sdpu_get_len_from_type (p, type, &attr_len);
    ++        p = sdpu_get_len_from_type(p, p_msg_end, type, &attr_len);
    ++        if (p == NULL || (p + attr_len) > p_seq_end)
    ++        {
    ++            SDP_TRACE_WARNING("%s: Bad len in attr_rsp %d", __func__, attr_len);
    ++            return (NULL);
    ++        }
    +         if (((type >> 3) != UINT_DESC_TYPE) || (attr_len != 2))
    +         {
    +             SDP_TRACE_WARNING ("SDP - Bad type: 0x%02x or len: %d in attr_rsp", type, attr_len);
    +@@ -764,7 +836,7 @@ static UINT8 *save_attr_seq (tCONN_CB *p_ccb, UINT8 *p, UINT8 *p_msg_end)
              BE_STREAM_TO_UINT16 (attr_id, p);
      
              /* Now, add the attribute value */
    @@ -3065,7 +3516,7 @@ index ec20689e3..416085db4 100644
      
              if (!p)
              {
    -@@ -830,7 +887,7 @@ tSDP_DISC_REC *add_record (tSDP_DISCOVERY_DB *p_db, BD_ADDR p_bda)
    +@@ -830,7 +902,7 @@ tSDP_DISC_REC *add_record (tSDP_DISCOVERY_DB *p_db, BD_ADDR p_bda)
      ** Returns          pointer to next byte in data stream
      **
      *******************************************************************************/
    @@ -3074,7 +3525,7 @@ index ec20689e3..416085db4 100644
                              UINT16 attr_id, tSDP_DISC_ATTR *p_parent_attr, UINT8 nest_level)
      {
          tSDP_DISC_ATTR  *p_attr;
    -@@ -839,7 +896,7 @@ static UINT8 *add_attr (UINT8 *p, tSDP_DISCOVERY_DB *p_db, tSDP_DISC_REC *p_rec,
    +@@ -839,14 +911,18 @@ static UINT8 *add_attr (UINT8 *p, tSDP_DISCOVERY_DB *p_db, tSDP_DISC_REC *p_rec,
          UINT16          attr_type;
          UINT16          id;
          UINT8           type;
    @@ -3083,7 +3534,20 @@ index ec20689e3..416085db4 100644
          UINT8           is_additional_list = nest_level & SDP_ADDITIONAL_LIST_MASK;
      
          nest_level &= ~(SDP_ADDITIONAL_LIST_MASK);
    -@@ -856,6 +913,13 @@ static UINT8 *add_attr (UINT8 *p, tSDP_DISCOVERY_DB *p_db, tSDP_DISC_REC *p_rec,
    + 
    +     type = *p++;
    +-    p = sdpu_get_len_from_type (p, type, &attr_len);
    +-
    ++    p = sdpu_get_len_from_type(p, p_end, type, &attr_len);
    ++    if (p == NULL || (p + attr_len) > p_end)
    ++    {
    ++        SDP_TRACE_WARNING("%s: bad length in attr_rsp", __func__);
    ++        return NULL;
    ++    }
    +     attr_len &= SDP_DISC_ATTR_LEN_MASK;
    +     attr_type = (type >> 3) & 0x0f;
    + 
    +@@ -856,6 +932,13 @@ static UINT8 *add_attr (UINT8 *p, tSDP_DISCOVERY_DB *p_db, tSDP_DISC_REC *p_rec,
          else
              total_len = sizeof (tSDP_DISC_ATTR);
      
    @@ -3097,7 +3561,7 @@ index ec20689e3..416085db4 100644
          /* Ensure it is a multiple of 4 */
          total_len = (total_len + 3) & ~3;
      
    -@@ -882,18 +946,17 @@ static UINT8 *add_attr (UINT8 *p, tSDP_DISCOVERY_DB *p_db, tSDP_DISC_REC *p_rec,
    +@@ -882,18 +965,17 @@ static UINT8 *add_attr (UINT8 *p, tSDP_DISCOVERY_DB *p_db, tSDP_DISC_REC *p_rec,
                      /* Reserve the memory for the attribute now, as we need to add sub-attributes */
                      p_db->p_free_mem += sizeof (tSDP_DISC_ATTR);
                      p_db->mem_free   -= sizeof (tSDP_DISC_ATTR);
    @@ -3118,7 +3582,7 @@ index ec20689e3..416085db4 100644
      
                      break;
                  }
    -@@ -966,7 +1029,7 @@ static UINT8 *add_attr (UINT8 *p, tSDP_DISCOVERY_DB *p_db, tSDP_DISC_REC *p_rec,
    +@@ -966,7 +1048,7 @@ static UINT8 *add_attr (UINT8 *p, tSDP_DISCOVERY_DB *p_db, tSDP_DISC_REC *p_rec,
                  break;
              default:
                  SDP_TRACE_WARNING ("SDP - bad len in UUID attr: %d", attr_len);
    @@ -3127,7 +3591,7 @@ index ec20689e3..416085db4 100644
              }
              break;
      
    -@@ -988,10 +1051,10 @@ static UINT8 *add_attr (UINT8 *p, tSDP_DISCOVERY_DB *p_db, tSDP_DISC_REC *p_rec,
    +@@ -988,10 +1070,10 @@ static UINT8 *add_attr (UINT8 *p, tSDP_DISCOVERY_DB *p_db, tSDP_DISC_REC *p_rec,
                  nest_level |= SDP_ADDITIONAL_LIST_MASK;
              /* SDP_TRACE_DEBUG ("SDP - attr nest level:0x%x(finish)", nest_level); */
      
    @@ -3140,7 +3604,7 @@ index ec20689e3..416085db4 100644
      
                  if (!p)
                      return (NULL);
    -@@ -1011,7 +1074,7 @@ static UINT8 *add_attr (UINT8 *p, tSDP_DISCOVERY_DB *p_db, tSDP_DISC_REC *p_rec,
    +@@ -1011,7 +1093,7 @@ static UINT8 *add_attr (UINT8 *p, tSDP_DISCOVERY_DB *p_db, tSDP_DISC_REC *p_rec,
                  break;
              default:
                  SDP_TRACE_WARNING ("SDP - bad len in boolean attr: %d", attr_len);
    @@ -3392,7 +3856,7 @@ index 627f4cf18..64a1b9f86 100644
                                                                   &p_ccb->cont_info.attr_offset);
      
     diff --git a/stack/sdp/sdp_utils.c b/stack/sdp/sdp_utils.c
    -index a6f0ba6a9..6b503cb70 100644
    +index a6f0ba6a9..6c7e3b8f0 100644
     --- a/stack/sdp/sdp_utils.c
     +++ b/stack/sdp/sdp_utils.c
     @@ -120,8 +120,9 @@ tCONN_CB *sdpu_allocate_ccb (void)
    @@ -3559,8 +4023,48 @@ index a6f0ba6a9..6b503cb70 100644
              if (attr_len == 2)
              {
                  BE_STREAM_TO_UINT16 (p_seq->attr_entry[p_seq->num_attr].start, p);
    +@@ -577,7 +600,8 @@ UINT8 *sdpu_extract_attr_seq (UINT8 *p, UINT16 param_len, tSDP_ATTR_SEQ *p_seq)
    + ** Returns          void
    + **
    + *******************************************************************************/
    +-UINT8 *sdpu_get_len_from_type (UINT8 *p, UINT8 type, UINT32 *p_len)
    ++UINT8 *sdpu_get_len_from_type (UINT8 *p, UINT8 *p_end, UINT8 type,
    ++                               UINT32 *p_len)
    + {
    +     UINT8   u8;
    +     UINT16  u16;
    +@@ -601,14 +625,29 @@ UINT8 *sdpu_get_len_from_type (UINT8 *p, UINT8 type, UINT32 *p_len)
    +         *p_len = 16;
    +         break;
    +     case SIZE_IN_NEXT_BYTE:
    ++        if (p + 1 > p_end)
    ++        {
    ++            *p_len = 0;
    ++            return NULL;
    ++        }
    +         BE_STREAM_TO_UINT8 (u8, p);
    +         *p_len = u8;
    +         break;
    +     case SIZE_IN_NEXT_WORD:
    ++        if (p + 2 > p_end)
    ++        {
    ++            *p_len = 0;
    ++            return NULL;
    ++        }
    +         BE_STREAM_TO_UINT16 (u16, p);
    +         *p_len = u16;
    +         break;
    +     case SIZE_IN_NEXT_LONG:
    ++        if (p + 4 > p_end)
    ++        {
    ++            *p_len = 0;
    ++            return NULL;
    ++        }
    +         BE_STREAM_TO_UINT32 (u32, p);
    +         *p_len = (UINT16) u32;
    +         break;
     diff --git a/stack/sdp/sdpint.h b/stack/sdp/sdpint.h
    -index 05414cd3c..71dab9265 100644
    +index 05414cd3c..b0548f5b9 100644
     --- a/stack/sdp/sdpint.h
     +++ b/stack/sdp/sdpint.h
     @@ -246,6 +246,7 @@ extern tSDP_CB *sdp_cb_ptr;
    @@ -3571,6 +4075,15 @@ index 05414cd3c..71dab9265 100644
      extern void     sdp_disconnect (tCONN_CB*p_ccb, UINT16 reason);
      
      #if (defined(SDP_DEBUG) && SDP_DEBUG == TRUE)
    +@@ -281,7 +282,7 @@ extern void      sdpu_build_n_send_error (tCONN_CB *p_ccb, UINT16 trans_num, UIN
    + extern UINT8    *sdpu_extract_attr_seq (UINT8 *p, UINT16 param_len, tSDP_ATTR_SEQ *p_seq);
    + extern UINT8    *sdpu_extract_uid_seq (UINT8 *p, UINT16 param_len, tSDP_UUID_SEQ *p_seq);
    + 
    +-extern UINT8    *sdpu_get_len_from_type (UINT8 *p, UINT8 type, UINT32 *p_len);
    ++extern UINT8    *sdpu_get_len_from_type (UINT8 *p, UINT8 *p_end, UINT8 type, UINT32 *p_len);
    + extern BOOLEAN  sdpu_is_base_uuid (UINT8 *p_uuid);
    + extern BOOLEAN  sdpu_compare_uuid_arrays (UINT8 *p_uuid1, UINT32 len1, UINT8 *p_uuid2, UINT16 len2);
    + extern BOOLEAN  sdpu_compare_bt_uuids (tBT_UUID *p_uuid1, tBT_UUID *p_uuid2);
     diff --git a/stack/smp/p_256_ecc_pp.c b/stack/smp/p_256_ecc_pp.c
     index 2eaebd4eb..832ce11e7 100644
     --- a/stack/smp/p_256_ecc_pp.c
    
    From 52e9fbcbb304dcb101cfba2b07a0c42bf32a6c51 Mon Sep 17 00:00:00 2001
    From: AndDiSa <anddisa@googlemail.com>
    Date: Sun, 29 Sep 2019 10:46:38 +0200
    Subject: [PATCH 129/159] cleanup
    
    Change-Id: Ie0b878434ab45f0c9ad436a442800585139f451b
    ---
     default.xml | 4 ++--
     1 file changed, 2 insertions(+), 2 deletions(-)
    
    diff --git a/default.xml b/default.xml
    index 0b67828..2a2f04e 100644
    --- a/default.xml
    +++ b/default.xml
    @@ -20,7 +20,7 @@
         <linkfile src="root.bp" dest="Android.bp" />
         <linkfile src="bootstrap.bash" dest="bootstrap.bash" />
       </project>
    -  <project path="art" name="platform/art" groups="pdk" />
    +  <project path="art" name="platform/art" remote="ads" revision="ads-7.1.0" groups="pdk" />
       <project path="bionic" name="platform_bionic" remote="ads" revision="ads-7.1.0" groups="pdk" />
       <project path="bootable/recovery" name="platform/bootable/recovery" groups="pdk" />
       <project path="dalvik" name="platform/dalvik" groups="pdk-cw-fs,pdk-fs" />
    @@ -81,7 +81,7 @@
       <project path="external/conscrypt" name="platform/external/conscrypt" groups="pdk-cw-fs,pdk-fs" />
       <project path="external/crcalc" name="platform/external/crcalc" groups="pdk-fs" />
       <project path="external/cros/system_api" name="platform/external/cros/system_api" />
    -  <project path="external/curl" name="platform/external/curl" />
    +  <project path="external/curl" name="platform/external/curl" remote="ads" revision="ads-7.1.0" />
       <project path="external/dagger2" name="platform/external/dagger2" />
       <project path="external/dbus" name="platform/external/dbus" />
       <project path="external/dbus-binding-generator" name="platform/external/dbus-binding-generator" />
    
    From 87130b3e9ff0cd2e5b0d6ffb6d016e78442f7e4a Mon Sep 17 00:00:00 2001
    From: AndDiSa <anddisa@googlemail.com>
    Date: Sun, 29 Sep 2019 11:00:03 +0200
    Subject: [PATCH 130/159] use own gatekeeper
    
    Change-Id: I2db204d33afa4a39068beaaaa0207c5de0fc68fd
    ---
     default.xml | 2 +-
     1 file changed, 1 insertion(+), 1 deletion(-)
    
    diff --git a/default.xml b/default.xml
    index 2a2f04e..ff3b370 100644
    --- a/default.xml
    +++ b/default.xml
    @@ -479,7 +479,7 @@
       <project path="system/core" name="android_system_core" remote="ads" revision="ads-7.1.0" groups="pdk" />
       <project path="system/extras" name="platform/system/extras" groups="pdk" />
       <project path="system/firewalld" name="platform/system/firewalld" />
    -  <project path="system/gatekeeper" name="platform/system/gatekeeper" groups="pdk" />
    +  <project path="system/gatekeeper" name="android_system_gatekeeper" remote="ads" revision="ads-7.1.0" groups="pdk" />
       <project path="system/keymaster" name="platform/system/keymaster" groups="pdk" />
       <project path="system/media" name="android_system_media" remote="ads" revision="ads-7.1.0" groups="pdk" />
       <project path="system/nativepower" name="platform/system/nativepower" />
    
    From 2005bcee4030a3acad006ed0704efac978aaf6a5 Mon Sep 17 00:00:00 2001
    From: AndDiSa <anddisa@googlemail.com>
    Date: Sun, 29 Sep 2019 12:42:15 +0200
    Subject: [PATCH 131/159] fix repo url for platform/art
    
    Change-Id: I2e6bdb58adff3c7756a85b46ac714b5b83e51029
    ---
     default.xml | 2 +-
     1 file changed, 1 insertion(+), 1 deletion(-)
    
    diff --git a/default.xml b/default.xml
    index ff3b370..9a5010d 100644
    --- a/default.xml
    +++ b/default.xml
    @@ -20,7 +20,7 @@
         <linkfile src="root.bp" dest="Android.bp" />
         <linkfile src="bootstrap.bash" dest="bootstrap.bash" />
       </project>
    -  <project path="art" name="platform/art" remote="ads" revision="ads-7.1.0" groups="pdk" />
    +  <project path="art" name="platform_art" remote="ads" revision="ads-7.1.0" groups="pdk" />
       <project path="bionic" name="platform_bionic" remote="ads" revision="ads-7.1.0" groups="pdk" />
       <project path="bootable/recovery" name="platform/bootable/recovery" groups="pdk" />
       <project path="dalvik" name="platform/dalvik" groups="pdk-cw-fs,pdk-fs" />
    
    From 1920420e8d906e69ba4d3d5b7bc7c2dbb4dec8a3 Mon Sep 17 00:00:00 2001
    From: AndDiSa <anddisa@googlemail.com>
    Date: Sun, 29 Sep 2019 15:16:01 +0200
    Subject: [PATCH 132/159] fix repo name
    
    Change-Id: I1635b2f789d3d738480b2887d260806351646506
    ---
     default.xml | 2 +-
     1 file changed, 1 insertion(+), 1 deletion(-)
    
    diff --git a/default.xml b/default.xml
    index 9a5010d..076950b 100644
    --- a/default.xml
    +++ b/default.xml
    @@ -81,7 +81,7 @@
       <project path="external/conscrypt" name="platform/external/conscrypt" groups="pdk-cw-fs,pdk-fs" />
       <project path="external/crcalc" name="platform/external/crcalc" groups="pdk-fs" />
       <project path="external/cros/system_api" name="platform/external/cros/system_api" />
    -  <project path="external/curl" name="platform/external/curl" remote="ads" revision="ads-7.1.0" />
    +  <project path="external/curl" name="external_curl" remote="ads" revision="ads-7.1.0" />
       <project path="external/dagger2" name="platform/external/dagger2" />
       <project path="external/dbus" name="platform/external/dbus" />
       <project path="external/dbus-binding-generator" name="platform/external/dbus-binding-generator" />
    
    From 5701c717a4139c41da0df4e17cddbf0d7ddc84f2 Mon Sep 17 00:00:00 2001
    From: AndDiSa <anddisa@googlemail.com>
    Date: Fri, 15 Nov 2019 10:52:51 +0100
    Subject: [PATCH 133/159] switch some repos to own forks
    
    Change-Id: I2bb73bd340c44a12ffe07ff63b0675fd708532c7
    ---
     default.xml | 8 ++++----
     1 file changed, 4 insertions(+), 4 deletions(-)
    
    diff --git a/default.xml b/default.xml
    index 076950b..adf14d9 100644
    --- a/default.xml
    +++ b/default.xml
    @@ -163,7 +163,7 @@
       <project path="external/libcap" name="platform/external/libcap" />
       <project path="external/libcap-ng" name="platform/external/libcap-ng" groups="pdk-cw-fs,pdk-fs" />
       <project path="external/libchrome" name="platform/external/libchrome" />
    -  <project path="external/libcxx" name="platform/external/libcxx" groups="pdk" />
    +  <project path="external/libcxx" name="android_external_libcxx" remote="ads" revision="ads-7.1.0" groups="pdk" />
       <project path="external/libcxxabi" name="platform/external/libcxxabi" groups="pdk" />
       <project path="external/libdivsufsort" name="platform/external/libdivsufsort" groups="pdk" />
       <project path="external/libdrm" name="external_libdrm" remote="ads" revision="ads-7.1.0" groups="pdk" />
    @@ -173,7 +173,7 @@
       <project path="external/libexif" name="platform/external/libexif" groups="pdk-cw-fs,pdk-fs" />
       <project path="external/libgsm" name="platform/external/libgsm" groups="pdk" />
       <project path="external/libhevc" name="external_libhevc" remote="ads" revision="ads-7.1.0" groups="pdk-fs" />
    -  <project path="external/libjpeg-turbo" name="platform/external/libjpeg-turbo" groups="pdk" />
    +  <project path="external/libjpeg-turbo" name="android_external_libjpeg-turbo" remote="ads" revision="ads-7.1.0" groups="pdk" />
       <project path="external/liblzf" name="platform/external/liblzf" groups="pdk" />
       <project path="external/libmicrohttpd" name="platform/external/libmicrohttpd" />
       <project path="external/libmpeg2" name="external_libmpeg2" remote="ads" revision="ads-7.1.0" groups="pdk" />
    @@ -373,7 +373,7 @@
       <project path="libnativehelper" name="platform/libnativehelper" groups="pdk" />
       <project path="ndk" name="platform/ndk" groups="generic_fs" />
       <project path="packages/apps/BasicSmsReceiver" name="platform/packages/apps/BasicSmsReceiver" groups="pdk-cw-fs,pdk-fs" />
    -  <project path="packages/apps/Bluetooth" name="platform/packages/apps/Bluetooth" groups="pdk-cw-fs,pdk-fs" />
    +  <project path="packages/apps/Bluetooth" name="android_packages_apps_Bluetooth" remote="ads" revision="ads-7.1.0" groups="pdk-cw-fs,pdk-fs" />
       <!-- <project path="packages/apps/Browser2" name="platform/packages/apps/Browser2" /> -->
       <project path="packages/apps/Calculator" name="platform/packages/apps/Calculator" groups="pdk-fs" />
       <!--  <project path="packages/apps/Calendar" name="platform/packages/apps/Calendar" groups="pdk-fs" /> -->
    @@ -434,7 +434,7 @@
       <project path="packages/providers/MediaProvider" name="platform/packages/providers/MediaProvider" groups="pdk-cw-fs,pdk-fs" />
       <project path="packages/providers/PartnerBookmarksProvider" name="platform/packages/providers/PartnerBookmarksProvider" groups="pdk-fs" />
       <project path="packages/providers/TelephonyProvider" name="packages_providers_telephonyprovider" remote="ads" revision="ads-7.1.0" groups="pdk-cw-fs,pdk-fs" />
    -  <project path="packages/providers/TvProvider" name="platform/packages/providers/TvProvider" groups="pdk-fs" />
    +  <project path="packages/providers/TvProvider" name="packages_providers_TvProvider" remote="ads" revision="ads-7.1.0" groups="pdk-fs" />
       <project path="packages/providers/UserDictionaryProvider" name="platform/packages/providers/UserDictionaryProvider" groups="pdk-cw-fs,pdk-fs" />
       <project path="packages/screensavers/Basic" name="platform/packages/screensavers/Basic" groups="pdk-fs" />
       <project path="packages/screensavers/PhotoTable" name="platform/packages/screensavers/PhotoTable" groups="pdk-fs" />
    
    From 49c20dc0ba6cb162a217f8e4c752821ec220c6c1 Mon Sep 17 00:00:00 2001
    From: AndDiSa <anddisa@googlemail.com>
    Date: Sun, 15 Dec 2019 10:09:26 +0100
    Subject: [PATCH 134/159] manifest: Updates for 2019-12 N ASB
    
    * Track our own projects in order to apply respective patches:
      - external/ImageMagick
    
    Change-Id: Id0a4c43bb65173ed5ff51b6fecbd14bc0b07fbd9
    ---
     default.xml | 2 +-
     1 file changed, 1 insertion(+), 1 deletion(-)
    
    diff --git a/default.xml b/default.xml
    index adf14d9..e1e053b 100644
    --- a/default.xml
    +++ b/default.xml
    @@ -133,7 +133,7 @@
       <project path="external/harfbuzz_ng" name="platform/external/harfbuzz_ng" groups="pdk,qcom_msm8x26" />
       <project path="external/hyphenation-patterns" name="platform/external/hyphenation-patterns" groups="pdk-fs" />
       <project path="external/icu" name="platform/external/icu" groups="pdk" />
    -  <project path="external/ImageMagick" name="platform/external/ImageMagick" groups="pdk" />
    +  <project path="external/ImageMagick" name="external_ImageMagick" remote="ads" revision="ads-7.1.0" groups="pdk" />
       <project path="external/ims" name="platform/external/ims" groups="pdk" />
       <project path="external/iproute2" name="platform/external/iproute2" groups="pdk" />
       <project path="external/ipsec-tools" name="platform/external/ipsec-tools" groups="pdk-cw-fs,pdk-fs" />
    
    From acc7f119154d89ede3475e86a6c9012c4072ba05 Mon Sep 17 00:00:00 2001
    From: AndDiSa <anddisa@googlemail.com>
    Date: Sun, 9 Feb 2020 10:23:23 +0100
    Subject: [PATCH 135/159] use own CertInstaller branch
    
    Change-Id: I99a293005b8a416a8cf12058f6aed596bdbae136
    ---
     default.xml | 2 +-
     1 file changed, 1 insertion(+), 1 deletion(-)
    
    diff --git a/default.xml b/default.xml
    index e1e053b..51d469f 100644
    --- a/default.xml
    +++ b/default.xml
    @@ -379,7 +379,7 @@
       <!--  <project path="packages/apps/Calendar" name="platform/packages/apps/Calendar" groups="pdk-fs" /> -->
       <project path="packages/apps/CarrierConfig" name="platform/packages/apps/CarrierConfig" groups="pdk-fs" />
       <project path="packages/apps/CellBroadcastReceiver" name="platform/packages/apps/CellBroadcastReceiver" groups="pdk-fs" />
    -  <project path="packages/apps/CertInstaller" name="platform/packages/apps/CertInstaller" groups="pdk-cw-fs,pdk-fs" />
    +  <project path="packages/apps/CertInstaller" name="platform/packages/apps/CertInstaller" remote="ads" revision="ads-7.1.0" groups="pdk-cw-fs,pdk-fs" />
       <project path="packages/apps/Contacts" name="packages_apps_Contacts" remote="ads" revision="ads-7.1.0" groups="pdk-fs" />
       <project path="packages/apps/ContactsCommon" name="platform/packages/apps/ContactsCommon" groups="pdk-fs"/>
       <project path="packages/apps/DeskClock" name="platform/packages/apps/DeskClock" groups="pdk-fs" />
    
    From ebcb7e080555867b3f40760af7597e0209b4fddc Mon Sep 17 00:00:00 2001
    From: AndDiSa <anddisa@googlemail.com>
    Date: Mon, 17 Feb 2020 08:41:31 +0100
    Subject: [PATCH 136/159] fix name of remote cert installer repo
    
    Change-Id: Ice1fc448fa9ccb9a60640370d25788e8bef36f40
    ---
     default.xml | 2 +-
     1 file changed, 1 insertion(+), 1 deletion(-)
    
    diff --git a/default.xml b/default.xml
    index 51d469f..c0bfc76 100644
    --- a/default.xml
    +++ b/default.xml
    @@ -379,7 +379,7 @@
       <!--  <project path="packages/apps/Calendar" name="platform/packages/apps/Calendar" groups="pdk-fs" /> -->
       <project path="packages/apps/CarrierConfig" name="platform/packages/apps/CarrierConfig" groups="pdk-fs" />
       <project path="packages/apps/CellBroadcastReceiver" name="platform/packages/apps/CellBroadcastReceiver" groups="pdk-fs" />
    -  <project path="packages/apps/CertInstaller" name="platform/packages/apps/CertInstaller" remote="ads" revision="ads-7.1.0" groups="pdk-cw-fs,pdk-fs" />
    +  <project path="packages/apps/CertInstaller" name="packages_apps_CertInstaller" remote="ads" revision="ads-7.1.0" groups="pdk-cw-fs,pdk-fs" />
       <project path="packages/apps/Contacts" name="packages_apps_Contacts" remote="ads" revision="ads-7.1.0" groups="pdk-fs" />
       <project path="packages/apps/ContactsCommon" name="platform/packages/apps/ContactsCommon" groups="pdk-fs"/>
       <project path="packages/apps/DeskClock" name="platform/packages/apps/DeskClock" groups="pdk-fs" />
    
    From 8baf155423c02b6e8a7db289ea470ad79a99c3d1 Mon Sep 17 00:00:00 2001
    From: AndDiSa <anddisa@googlemail.com>
    Date: Fri, 8 May 2020 17:46:42 +0200
    Subject: [PATCH 137/159] manifest: Track our own libexif
    
    Change-Id: Ib6ba6f6ee0d82f04d78ae0107646328fb4a9335c
    ---
     default.xml | 2 +-
     1 file changed, 1 insertion(+), 1 deletion(-)
    
    diff --git a/default.xml b/default.xml
    index c0bfc76..6544e92 100644
    --- a/default.xml
    +++ b/default.xml
    @@ -170,7 +170,7 @@
       <project path="external/libedit" name="platform/external/libedit" groups="pdk-fs" />
       <project path="external/libdaemon" name="platform/external/libdaemon" />
       <project path="external/libevent" name="platform/external/libevent" />
    -  <project path="external/libexif" name="platform/external/libexif" groups="pdk-cw-fs,pdk-fs" />
    +  <project path="external/libexif" name="android_external_libexif" remote="ads" revision="ads-7.1.0" groups="pdk-cw-fs,pdk-fs" />
       <project path="external/libgsm" name="platform/external/libgsm" groups="pdk" />
       <project path="external/libhevc" name="external_libhevc" remote="ads" revision="ads-7.1.0" groups="pdk-fs" />
       <project path="external/libjpeg-turbo" name="android_external_libjpeg-turbo" remote="ads" revision="ads-7.1.0" groups="pdk" />
    
    From 1ee2ade73218962db766759134ad7ff97840e4c3 Mon Sep 17 00:00:00 2001
    From: AndDiSa <anddisa@googlemail.com>
    Date: Wed, 8 Jul 2020 17:52:25 +0200
    Subject: [PATCH 138/159] manifest: Track our own dng_sdk
    
    Change-Id: Id8427c5d84e43dc732c698df16edcb5625d13484
    ---
     default.xml | 2 +-
     1 file changed, 1 insertion(+), 1 deletion(-)
    
    diff --git a/default.xml b/default.xml
    index 6544e92..510fab3 100644
    --- a/default.xml
    +++ b/default.xml
    @@ -89,7 +89,7 @@
       <project path="external/dexmaker" name="platform/external/dexmaker" groups="pdk-cw-fs,pdk-fs" />
       <project path="external/dhcpcd-6.8.2" name="platform/external/dhcpcd-6.8.2" />
       <project path="external/dlmalloc" name="platform/external/dlmalloc" />
    -  <project path="external/dng_sdk" name="platform/external/dng_sdk" />
    +  <project path="external/dng_sdk" name="external_dng_sdk" remote="ads" revision="ads-7.1.2" />
       <project path="external/dnsmasq" name="platform/external/dnsmasq" groups="pdk" />
       <project path="external/doclava" name="platform/external/doclava" groups="pdk-cw-fs,pdk-fs" />
       <project path="external/donuts" name="platform/external/donuts" groups="pdk-fs" />
    
    From 3fa2fd4fa980d38b0e72d94a8d2021d2014d24b5 Mon Sep 17 00:00:00 2001
    From: AndDiSa <anddisa@googlemail.com>
    Date: Wed, 5 Aug 2020 21:01:30 +0200
    Subject: [PATCH 139/159] create own repo of gptfsdisk
    
    Change-Id: I652ea660d9d04b0116cecfa352f5b1bbfe3bc687
    ---
     default.xml | 2 +-
     1 file changed, 1 insertion(+), 1 deletion(-)
    
    diff --git a/default.xml b/default.xml
    index 510fab3..8a7f119 100644
    --- a/default.xml
    +++ b/default.xml
    @@ -125,7 +125,7 @@
       <project path="external/google-fonts/cutive-mono" name="platform/external/google-fonts/cutive-mono" groups="pdk-cw-fs,pdk-fs" />
       <project path="external/google-fonts/dancing-script" name="platform/external/google-fonts/dancing-script" groups="pdk-cw-fs,pdk-fs" />
       <project path="external/google-tv-pairing-protocol" name="platform/external/google-tv-pairing-protocol" groups="pdk-fs" />
    -  <project path="external/gptfdisk" name="platform/external/gptfdisk" groups="pdk-fs" />
    +  <project path="external/gptfdisk" name="external_gptfdisk" remote="ads" revision="ads-7.1.2" groups="pdk-fs" />
       <project path="external/gtest" name="platform/external/gtest" groups="pdk" /> 
       <project path="external/guava" name="platform/external/guava" groups="pdk-cw-fs,pdk-fs" />
       <project path="external/guice" name="platform/external/guice" groups="pdk" />
    
    From f85f9c2d813c9ca0d276648d6918d118625bdc80 Mon Sep 17 00:00:00 2001
    From: AndDiSa <anddisa@googlemail.com>
    Date: Fri, 11 Sep 2020 15:35:50 +0200
    Subject: [PATCH 140/159] update own forks
    
    Change-Id: Id13385ccd2f9c5538ec3ab1beb527bbf341168bf
    ---
     default.xml | 2 +-
     1 file changed, 1 insertion(+), 1 deletion(-)
    
    diff --git a/default.xml b/default.xml
    index 8a7f119..d8a3746 100644
    --- a/default.xml
    +++ b/default.xml
    @@ -442,7 +442,7 @@
       <project path="packages/services/Car" name="platform/packages/services/Car" groups="adp8064,pdk-cw-fs,pdk-fs" />
       <project path="packages/services/Mms" name="platform/packages/services/Mms" groups="pdk-cw-fs,pdk-fs" />
       <project path="packages/services/Telecomm" name="packages_services_telecomm" remote="ads" revision="ads-7.1.0" groups="pdk-cw-fs,pdk-fs" />
    -  <project path="packages/services/Telephony" name="platform/packages/services/Telephony" groups="pdk-cw-fs,pdk-fs" />
    +  <project path="packages/services/Telephony" name="services_telephony" remote="ads" revision="ads-7.1.0" groups="pdk-cw-fs,pdk-fs" />
       <project path="packages/wallpapers/LivePicker" name="platform/packages/wallpapers/LivePicker" groups="pdk-fs" />
       <project path="pdk" name="platform/pdk" groups="pdk" />
       <project path="prebuilts/clang/linux-x86/host/3.6" name="platform/prebuilts/clang/linux-x86/host/3.6" groups="pdk,linux" />
    
    From 549904e6ae2fbdc3c78c760b93a9948d771e2211 Mon Sep 17 00:00:00 2001
    From: AndDiSa <anddisa@googlemail.com>
    Date: Thu, 17 Dec 2020 16:29:00 +0100
    Subject: [PATCH 141/159] switch to branch ads-7.1.2
    
    Change-Id: I3587d29bf929b2f8a73ea6804c9a9fc642fe3b05
    ---
     default.xml | 2 +-
     1 file changed, 1 insertion(+), 1 deletion(-)
    
    diff --git a/default.xml b/default.xml
    index d8a3746..5ea66fd 100644
    --- a/default.xml
    +++ b/default.xml
    @@ -481,7 +481,7 @@
       <project path="system/firewalld" name="platform/system/firewalld" />
       <project path="system/gatekeeper" name="android_system_gatekeeper" remote="ads" revision="ads-7.1.0" groups="pdk" />
       <project path="system/keymaster" name="platform/system/keymaster" groups="pdk" />
    -  <project path="system/media" name="android_system_media" remote="ads" revision="ads-7.1.0" groups="pdk" />
    +  <project path="system/media" name="android_system_media" remote="ads" revision="ads-7.1.2" groups="pdk" />
       <project path="system/nativepower" name="platform/system/nativepower" />
       <project path="system/netd" name="platform/system/netd" groups="pdk" />
       <project path="system/nvram" name="platform/system/nvram" />
    
    From 5a2f74d2874cf21f060303442230d92d70c19b3f Mon Sep 17 00:00:00 2001
    From: AndDiSa <anddisa@googlemail.com>
    Date: Sat, 9 Jan 2021 12:13:22 +0100
    Subject: [PATCH 142/159] switch to own PackageInstaller
    
    Change-Id: Id324fd1f6e97b6a32a598ae17b5615b63a77afb5
    ---
     default.xml | 2 +-
     1 file changed, 1 insertion(+), 1 deletion(-)
    
    diff --git a/default.xml b/default.xml
    index 5ea66fd..aa5468f 100644
    --- a/default.xml
    +++ b/default.xml
    @@ -401,7 +401,7 @@
       <project path="packages/apps/MusicFX" name="platform/packages/apps/MusicFX" groups="pdk-fs" />
       <project path="packages/apps/Nfc" name="packages_apps_nfc" remote="ads" revision="ads-7.1.0" groups="apps_nfc,pdk-fs" />
       <project path="packages/apps/OneTimeInitializer" name="platform/packages/apps/OneTimeInitializer" groups="pdk-fs" />
    -  <project path="packages/apps/PackageInstaller" name="platform/packages/apps/PackageInstaller" groups="pdk-fs" />
    +  <project path="packages/apps/PackageInstaller" name="packages_apps_PackageInstaller" remote="ads" revision="ads-7.1.2" groups="pdk-fs"/>
       <!--  <project path="packages/apps/PerformanceControl" name="android_packages_apps_PerformanceControl" remote="ads" revision="cm-13.0" /> -->
       <project path="packages/apps/Phone" name="platform/packages/apps/Phone" groups="pdk-fs" />
       <project path="packages/apps/PhoneCommon" name="platform/packages/apps/PhoneCommon" groups="pdk-cw-fs,pdk-fs"/>
    
    From 774ef1404fa52cbf323bb239c62bc6e5a911ab3a Mon Sep 17 00:00:00 2001
    From: AndDiSa <anddisa@googlemail.com>
    Date: Sat, 13 Feb 2021 09:37:57 +0100
    Subject: [PATCH 143/159] switch to own okhttp repo
    
    Change-Id: I66aeb8e8d5f078374b359b136fea076a4c8fc897
    ---
     default.xml | 2 +-
     1 file changed, 1 insertion(+), 1 deletion(-)
    
    diff --git a/default.xml b/default.xml
    index aa5468f..d8f84ac 100644
    --- a/default.xml
    +++ b/default.xml
    @@ -230,7 +230,7 @@
       <project path="external/noto-fonts" name="platform/external/noto-fonts" groups="pdk" />
       <project path="external/oauth" name="platform/external/oauth" groups="pdk-cw-fs,pdk-fs" />
       <project path="external/objenesis" name="platform/external/objenesis" groups="pdk-cw-fs,pdk-fs" />
    -  <project path="external/okhttp" name="platform/external/okhttp" groups="pdk-cw-fs,pdk-fs" />
    +  <project path="external/okhttp" name="external_okhttp" remote="ads" revision="ads-7.1.0" groups="pdk-cw-fs,pdk-fs" />
       <project path="external/opencv" name="external_opencv" remote="ads" revision="ads-7.1.0" groups="pdk-cw-fs,pdk-fs" />
       <project path="external/owasp/sanitizer" name="platform/external/owasp/sanitizer" groups="pdk-fs" />
       <project path="external/parameter-framework" name="platform/external/parameter-framework" groups="pdk-fs" />
    
    From 5910e25b16cf8edaa5972ee99318a6b49df1d586 Mon Sep 17 00:00:00 2001
    From: AndDiSa <anddisa@googlemail.com>
    Date: Fri, 5 Mar 2021 17:09:01 +0100
    Subject: [PATCH 144/159] switch to own dnsmask repo
    
    Change-Id: I1ba35be9f93107f56bc490b3b3747bcd9c3aee6d
    ---
     default.xml | 2 +-
     1 file changed, 1 insertion(+), 1 deletion(-)
    
    diff --git a/default.xml b/default.xml
    index d8f84ac..528ab56 100644
    --- a/default.xml
    +++ b/default.xml
    @@ -90,7 +90,7 @@
       <project path="external/dhcpcd-6.8.2" name="platform/external/dhcpcd-6.8.2" />
       <project path="external/dlmalloc" name="platform/external/dlmalloc" />
       <project path="external/dng_sdk" name="external_dng_sdk" remote="ads" revision="ads-7.1.2" />
    -  <project path="external/dnsmasq" name="platform/external/dnsmasq" groups="pdk" />
    +  <project path="external/dnsmasq" name="external_dnsmasq" remote="ads" revision="ads-7.1.0" groups="pdk" />
       <project path="external/doclava" name="platform/external/doclava" groups="pdk-cw-fs,pdk-fs" />
       <project path="external/donuts" name="platform/external/donuts" groups="pdk-fs" />
       <project path="external/drm_gralloc" name="platform/external/drm_gralloc" groups="drm_gralloc" />
    
    From 0ea3283bb4c656a969db4175dccf2fbe24eeb364 Mon Sep 17 00:00:00 2001
    From: AndDiSa <anddisa@googlemail.com>
    Date: Tue, 13 Jul 2021 18:12:34 +0200
    Subject: [PATCH 145/159] switch to own frameworks/opt/net/voip repo
    
    Change-Id: I00b69a689616723b1db8193b3e50f9bfbf5a7f52
    ---
     default.xml | 2 +-
     1 file changed, 1 insertion(+), 1 deletion(-)
    
    diff --git a/default.xml b/default.xml
    index 528ab56..4aa849a 100644
    --- a/default.xml
    +++ b/default.xml
    @@ -314,7 +314,7 @@
       <project path="frameworks/opt/inputmethodcommon" name="platform/frameworks/opt/inputmethodcommon" groups="pdk-cw-fs,pdk-fs" />
       <project path="frameworks/opt/net/ethernet" name="platform/frameworks/opt/net/ethernet" groups="pdk-fs" />
       <project path="frameworks/opt/net/ims" name="platform/frameworks/opt/net/ims" groups="frameworks_ims,pdk-cw-fs,pdk-fs" />
    -  <project path="frameworks/opt/net/voip" name="platform/frameworks/opt/net/voip" groups="pdk-cw-fs,pdk-fs" />
    +  <project path="frameworks/opt/net/voip" name="frameworks_opt_net_voip" remote="ads" revision="ads-7.1.0" groups="pdk-cw-fs,pdk-fs" />
       <project path="frameworks/opt/net/wifi" name="platform_frameworks_opt_net_wifi" remote="ads" revision="ads-7.1.0" groups="pdk" />
       <project path="frameworks/opt/photoviewer" name="platform/frameworks/opt/photoviewer" groups="pdk-cw-fs,pdk-fs" />
       <project path="frameworks/opt/setupwizard" name="platform/frameworks/opt/setupwizard" groups="pdk-cw-fs,pdk-fs" />
    
    From e933d965a0489113720fe7e4eb675ad396315a90 Mon Sep 17 00:00:00 2001
    From: AndDiSa <anddisa@googlemail.com>
    Date: Thu, 12 Aug 2021 18:29:33 +0200
    Subject: [PATCH 146/159] setup own repo for system/netd
    
    Change-Id: Idd87c6d45ce4aac173db20420fa032f605ad2c1e
    ---
     default.xml | 2 +-
     1 file changed, 1 insertion(+), 1 deletion(-)
    
    diff --git a/default.xml b/default.xml
    index 4aa849a..126afd1 100644
    --- a/default.xml
    +++ b/default.xml
    @@ -483,7 +483,7 @@
       <project path="system/keymaster" name="platform/system/keymaster" groups="pdk" />
       <project path="system/media" name="android_system_media" remote="ads" revision="ads-7.1.2" groups="pdk" />
       <project path="system/nativepower" name="platform/system/nativepower" />
    -  <project path="system/netd" name="platform/system/netd" groups="pdk" />
    +  <project path="system/netd" name="system_netd" remote="ads" revision="ads-7.1.0" groups="pdk" />
       <project path="system/nvram" name="platform/system/nvram" />
       <project path="system/security" name="android_system_security" remote="ads" revision="ads-7.1.0" groups="pdk" />
       <project path="system/sepolicy" name="android_system_sepolicy" remote="ads" revision="ads-7.1.0" groups="pdk" />
    
    From f70d60afb511a0c2b54213a3e86b444c28c1a547 Mon Sep 17 00:00:00 2001
    From: AndDiSa <anddisa@googlemail.com>
    Date: Thu, 12 Aug 2021 18:55:09 +0200
    Subject: [PATCH 147/159] setup own repo for external/icu
    
    Change-Id: I1ee06e3fab48d96237295cf7a72b28c231b880d6
    ---
     default.xml | 2 +-
     1 file changed, 1 insertion(+), 1 deletion(-)
    
    diff --git a/default.xml b/default.xml
    index 126afd1..325e326 100644
    --- a/default.xml
    +++ b/default.xml
    @@ -132,7 +132,7 @@
       <project path="external/hamcrest" name="platform/external/hamcrest" groups="pdk-cw-fs,pdk-fs" />
       <project path="external/harfbuzz_ng" name="platform/external/harfbuzz_ng" groups="pdk,qcom_msm8x26" />
       <project path="external/hyphenation-patterns" name="platform/external/hyphenation-patterns" groups="pdk-fs" />
    -  <project path="external/icu" name="platform/external/icu" groups="pdk" />
    +  <project path="external/icu" name="android_external_icu" remote="ads" revision="ads-7.1.2" groups="pdk" />
       <project path="external/ImageMagick" name="external_ImageMagick" remote="ads" revision="ads-7.1.0" groups="pdk" />
       <project path="external/ims" name="platform/external/ims" groups="pdk" />
       <project path="external/iproute2" name="platform/external/iproute2" groups="pdk" />
    
    From a84c312f841871b6c3490ce5395168616ea12cf7 Mon Sep 17 00:00:00 2001
    From: AndDiSa <anddisa@googlemail.com>
    Date: Sat, 14 Aug 2021 14:19:22 +0200
    Subject: [PATCH 148/159] use own repo for external/iptables
    
    Change-Id: If4ef235ce9c855198ae838f652c71875eb12049c
    ---
     default.xml | 2 +-
     1 file changed, 1 insertion(+), 1 deletion(-)
    
    diff --git a/default.xml b/default.xml
    index 325e326..6f30d33 100644
    --- a/default.xml
    +++ b/default.xml
    @@ -137,7 +137,7 @@
       <project path="external/ims" name="platform/external/ims" groups="pdk" />
       <project path="external/iproute2" name="platform/external/iproute2" groups="pdk" />
       <project path="external/ipsec-tools" name="platform/external/ipsec-tools" groups="pdk-cw-fs,pdk-fs" />
    -  <project path="external/iptables" name="platform/external/iptables" groups="pdk-cw-fs,pdk-fs" />
    +  <project path="external/iptables" name="android_external_iptables" remote="ads" revision="ads-7.1.0" groups="pdk-cw-fs,pdk-fs" />
       <project path="external/iputils" name="platform/external/iputils" groups="pdk-cw-fs,pdk-fs" />
       <project path="external/iw" name="platform/external/iw" />
       <project path="external/jacoco" name="platform/external/jacoco" />
    
    From fb4935a97d1bf81693c903a65f1c57f650a1a92e Mon Sep 17 00:00:00 2001
    From: AndDiSa <anddisa@googlemail.com>
    Date: Sat, 14 Aug 2021 14:30:16 +0200
    Subject: [PATCH 149/159] use own repo for external/freetype
    
    Change-Id: Icc52ab6ecfa5ecedd988f43954d46736cf73b082
    ---
     default.xml | 2 +-
     1 file changed, 1 insertion(+), 1 deletion(-)
    
    diff --git a/default.xml b/default.xml
    index 6f30d33..50979b7 100644
    --- a/default.xml
    +++ b/default.xml
    @@ -112,7 +112,7 @@
       <project path="external/fio" name="platform/external/fio" groups="pdk-fs" />
       <project path="external/flac" name="platform/external/flac" groups="pdk" />
       <project path="external/fonttools" name="platform/external/fonttools" groups="pdk-fs" />
    -  <project path="external/freetype" name="platform/external/freetype" groups="pdk" />
    +  <project path="external/freetype" name="android_external_freetype" remote="ads" revision="ads-7.1.0" groups="pdk" />
       <project path="external/fsck_msdos" name="platform/external/fsck_msdos" groups="pdk-cw-fs,pdk-fs" />
       <project path="external/gemmlowp" name="platform/external/gemmlowp" />
       <project path="external/giflib" name="platform/external/giflib" groups="pdk,qcom_msm8x26" />
    
    From 7dd82d6c0aa35208285f5101440ff1be4e54466b Mon Sep 17 00:00:00 2001
    From: AndDiSa <anddisa@googlemail.com>
    Date: Sat, 14 Aug 2021 14:35:28 +0200
    Subject: [PATCH 150/159] use own repo for external/ppp
    
    Change-Id: I34c2599e52b13aa6907d0c2349c04fc548cd2b96
    ---
     default.xml | 2 +-
     1 file changed, 1 insertion(+), 1 deletion(-)
    
    diff --git a/default.xml b/default.xml
    index 50979b7..14a5881 100644
    --- a/default.xml
    +++ b/default.xml
    @@ -237,7 +237,7 @@
       <project path="external/pcre" name="platform/external/pcre" groups="pdk" />
       <project path="external/pdfium" name="platform/external/pdfium" groups="pdk" />
       <project path="external/piex" name="platform/external/piex" />
    -  <project path="external/ppp" name="platform/external/ppp" groups="pdk-cw-fs,pdk-fs" />
    +  <project path="external/ppp" name="android_external_ppp" remote="ads" revision="ads-7.1.0" groups="pdk-cw-fs,pdk-fs" />
       <project path="external/proguard" name="platform/external/proguard" groups="pdk" />
       <project path="external/protobuf" name="platform/external/protobuf" groups="pdk" />
       <project path="external/regex-re2" name="platform/external/regex-re2" groups="pdk-cw-fs,pdk-fs" />
    
    From e2914e77facf683428a9930ff9c89476e8fcacba Mon Sep 17 00:00:00 2001
    From: AndDiSa <anddisa@googlemail.com>
    Date: Wed, 3 Nov 2021 18:14:34 +0100
    Subject: [PATCH 151/159] fix wrongly referenced netd branch
    
    Change-Id: Ia9fceb5e70a5f36c87d24d82768b0fc1e68fa1b4
    ---
     default.xml | 2 +-
     1 file changed, 1 insertion(+), 1 deletion(-)
    
    diff --git a/default.xml b/default.xml
    index 14a5881..dfba8aa 100644
    --- a/default.xml
    +++ b/default.xml
    @@ -483,7 +483,7 @@
       <project path="system/keymaster" name="platform/system/keymaster" groups="pdk" />
       <project path="system/media" name="android_system_media" remote="ads" revision="ads-7.1.2" groups="pdk" />
       <project path="system/nativepower" name="platform/system/nativepower" />
    -  <project path="system/netd" name="system_netd" remote="ads" revision="ads-7.1.0" groups="pdk" />
    +  <project path="system/netd" name="system_netd" remote="ads" revision="ads-7.1.2" groups="pdk" />
       <project path="system/nvram" name="platform/system/nvram" />
       <project path="system/security" name="android_system_security" remote="ads" revision="ads-7.1.0" groups="pdk" />
       <project path="system/sepolicy" name="android_system_sepolicy" remote="ads" revision="ads-7.1.0" groups="pdk" />
    
    From b0d705f2ed8a53deeff20bdf7e403cf96eef112a Mon Sep 17 00:00:00 2001
    From: AndDiSa <anddisa@googlemail.com>
    Date: Wed, 8 Dec 2021 18:10:04 +0100
    Subject: [PATCH 152/159] use own KeyChain repo
    
    Change-Id: I6c7555f47dd1317715a25a6022040eaa4700ac47
    ---
     default.xml | 2 +-
     1 file changed, 1 insertion(+), 1 deletion(-)
    
    diff --git a/default.xml b/default.xml
    index dfba8aa..e368980 100644
    --- a/default.xml
    +++ b/default.xml
    @@ -391,7 +391,7 @@
       <project path="packages/apps/Gallery" name="platform/packages/apps/Gallery" groups="pdk-fs" />
       <project path="packages/apps/Gallery2" name="platform/packages/apps/Gallery2" groups="pdk-fs" />
       <project path="packages/apps/HTMLViewer" name="platform/packages/apps/HTMLViewer" groups="pdk-fs" />
    -  <project path="packages/apps/KeyChain" name="platform/packages/apps/KeyChain" groups="pdk-fs" />
    +  <project path="packages/apps/KeyChain" name="platform/packages/apps/KeyChain" remote="ads" revision="ads-7.1.0" groups="pdk-fs" />
       <project path="packages/apps/Launcher2" name="platform/packages/apps/Launcher2" groups="pdk-fs" />
       <project path="packages/apps/Launcher3" name="platform/packages/apps/Launcher3" groups="pdk-fs" />
       <!-- <project path="packages/apps/LegacyCamera" name="platform/packages/apps/LegacyCamera" groups="pdk-fs" /> -->
    
    From 20d54630d37334b6a7ec41bc8006fff7511dd5db Mon Sep 17 00:00:00 2001
    From: AndDiSa <anddisa@googlemail.com>
    Date: Fri, 18 Feb 2022 10:36:46 +0100
    Subject: [PATCH 153/159] switch to own repo for MediaProvider
    
    Change-Id: I5042ea51f78d9a193afc63d5dfccbc20e64ca9e5
    ---
     default.xml | 2 +-
     1 file changed, 1 insertion(+), 1 deletion(-)
    
    diff --git a/default.xml b/default.xml
    index e368980..4f8eedf 100644
    --- a/default.xml
    +++ b/default.xml
    @@ -431,7 +431,7 @@
       <project path="packages/providers/CallLogProvider" name="platform/packages/providers/CallLogProvider" groups="pdk-fs" />
       <project path="packages/providers/ContactsProvider" name="platform/packages/providers/ContactsProvider" groups="pdk-cw-fs,pdk-fs" />
       <project path="packages/providers/DownloadProvider" name="providers_downloadprovider" remote="ads" revision="ads-7.1.0" groups="pdk-cw-fs,pdk-fs" />
    -  <project path="packages/providers/MediaProvider" name="platform/packages/providers/MediaProvider" groups="pdk-cw-fs,pdk-fs" />
    +  <project path="packages/providers/MediaProvider" name="packages_providers_MediaProvider" remote="ads" revision="ads-7.1.0" groups="pdk-cw-fs,pdk-fs" />
       <project path="packages/providers/PartnerBookmarksProvider" name="platform/packages/providers/PartnerBookmarksProvider" groups="pdk-fs" />
       <project path="packages/providers/TelephonyProvider" name="packages_providers_telephonyprovider" remote="ads" revision="ads-7.1.0" groups="pdk-cw-fs,pdk-fs" />
       <project path="packages/providers/TvProvider" name="packages_providers_TvProvider" remote="ads" revision="ads-7.1.0" groups="pdk-fs" />
    
    From c4fb02e9b107d425e90e5c9f52c60bf0c8e60363 Mon Sep 17 00:00:00 2001
    From: AndDiSa <anddisa@googlemail.com>
    Date: Wed, 17 Aug 2022 17:17:08 +0200
    Subject: [PATCH 154/159] use own copy of ContactProvider
    
    Change-Id: I2950ae50ce1f1ff075be5db654ea7affd5e97954
    ---
     default.xml | 2 +-
     1 file changed, 1 insertion(+), 1 deletion(-)
    
    diff --git a/default.xml b/default.xml
    index 4f8eedf..cd77d1f 100644
    --- a/default.xml
    +++ b/default.xml
    @@ -429,7 +429,7 @@
       <project path="packages/providers/BookmarkProvider" name="platform/packages/providers/BookmarkProvider" groups="pdk-fs" />
       <project path="packages/providers/CalendarProvider" name="platform/packages/providers/CalendarProvider" groups="pdk-cw-fs,pdk-fs" />
       <project path="packages/providers/CallLogProvider" name="platform/packages/providers/CallLogProvider" groups="pdk-fs" />
    -  <project path="packages/providers/ContactsProvider" name="platform/packages/providers/ContactsProvider" groups="pdk-cw-fs,pdk-fs" />
    +  <project path="packages/providers/ContactsProvider" name="android_providers_ContactProvider" remote="ads" revision="ads-7.1.0" groups="pdk-cw-fs,pdk-fs" />
       <project path="packages/providers/DownloadProvider" name="providers_downloadprovider" remote="ads" revision="ads-7.1.0" groups="pdk-cw-fs,pdk-fs" />
       <project path="packages/providers/MediaProvider" name="packages_providers_MediaProvider" remote="ads" revision="ads-7.1.0" groups="pdk-cw-fs,pdk-fs" />
       <project path="packages/providers/PartnerBookmarksProvider" name="platform/packages/providers/PartnerBookmarksProvider" groups="pdk-fs" />
    
    From c73ad55c75169c69cf82c2ed00266c8d85c68fd3 Mon Sep 17 00:00:00 2001
    From: AndDiSa <anddisa@googlemail.com>
    Date: Sat, 17 Sep 2022 13:58:32 +0200
    Subject: [PATCH 155/159] use own expat repo
    
    Change-Id: Iec18f8619d39e58c4ed86a1012b8b1b413fb41e7
    ---
     default.xml | 2 +-
     1 file changed, 1 insertion(+), 1 deletion(-)
    
    diff --git a/default.xml b/default.xml
    index cd77d1f..2487d09 100644
    --- a/default.xml
    +++ b/default.xml
    @@ -104,7 +104,7 @@
       <project path="external/elfutils" name="platform/external/elfutils" groups="pdk" />
       <project path="external/emma" name="platform/external/emma" groups="pdk-cw-fs,pdk-fs" />
       <project path="external/esd" name="platform/external/esd" groups="pdk-cw-fs,pdk-fs" />
    -  <project path="external/expat" name="platform/external/expat" groups="pdk" />
    +  <project path="external/expat" name="android_external_expat" remote="ads" revision="ads-7.1.0" groups="pdk" />
       <project path="external/eyes-free" name="platform/external/eyes-free" groups="pdk-cw-fs,pdk-fs" />
       <project path="external/f2fs-tools" name="platform/external/f2fs-tools" groups="pdk" />
       <project path="external/fdlibm" name="platform/external/fdlibm" groups="pdk" />
    
    From ab23a411224c85e8fd0ce4e055c6d2a98ec18360 Mon Sep 17 00:00:00 2001
    From: AndDiSa <anddisa@googlemail.com>
    Date: Wed, 16 Nov 2022 17:32:53 +0100
    Subject: [PATCH 156/159] fix wrong repo reference
    
    Change-Id: Ib5260b7080728527e1e896017e20ca5271387505
    ---
     default.xml | 2 +-
     1 file changed, 1 insertion(+), 1 deletion(-)
    
    diff --git a/default.xml b/default.xml
    index 2487d09..a632d22 100644
    --- a/default.xml
    +++ b/default.xml
    @@ -391,7 +391,7 @@
       <project path="packages/apps/Gallery" name="platform/packages/apps/Gallery" groups="pdk-fs" />
       <project path="packages/apps/Gallery2" name="platform/packages/apps/Gallery2" groups="pdk-fs" />
       <project path="packages/apps/HTMLViewer" name="platform/packages/apps/HTMLViewer" groups="pdk-fs" />
    -  <project path="packages/apps/KeyChain" name="platform/packages/apps/KeyChain" remote="ads" revision="ads-7.1.0" groups="pdk-fs" />
    +  <project path="packages/apps/KeyChain" name="packages_apps_KeyChain" remote="ads" revision="ads-7.1.0" groups="pdk-fs" />
       <project path="packages/apps/Launcher2" name="platform/packages/apps/Launcher2" groups="pdk-fs" />
       <project path="packages/apps/Launcher3" name="platform/packages/apps/Launcher3" groups="pdk-fs" />
       <!-- <project path="packages/apps/LegacyCamera" name="platform/packages/apps/LegacyCamera" groups="pdk-fs" /> -->
    
    From 4169b67ed09cec879b4a43c80a7e0f168baf65d2 Mon Sep 17 00:00:00 2001
    From: AndDiSa <anddisa@googlemail.com>
    Date: Thu, 16 Mar 2023 17:56:33 +0100
    Subject: [PATCH 157/159] switch to own zlib repo
    
    Change-Id: I58fa2f1852d66304612dd623c75c4bf7062e724c
    ---
     default.xml | 2 +-
     1 file changed, 1 insertion(+), 1 deletion(-)
    
    diff --git a/default.xml b/default.xml
    index a632d22..c9f776c 100644
    --- a/default.xml
    +++ b/default.xml
    @@ -290,7 +290,7 @@
       <project path="external/xmlrpcpp" name="platform/external/xmlrpcpp" groups="pdk" />
       <project path="external/xmlwriter" name="platform/external/xmlwriter" groups="pdk-cw-fs,pdk-fs" />
       <project path="external/xmp_toolkit" name="platform/external/xmp_toolkit" groups="pdk-cw-fs,pdk-fs" />
    -  <project path="external/zlib" name="platform/external/zlib" groups="pdk" />
    +  <project path="external/zlib" name="external_zlib" remote="ads" revision="ads-7.1.0" groups="pdk" />
       <project path="external/zopfli" name="platform/external/zopfli" groups="pdk-cw-fs,pdk-fs" />
       <project path="external/zxing" name="platform/external/zxing" groups="pdk-cw-fs,pdk-fs" />
       <project path="frameworks/av" name="android_frameworks_av" remote="ads" revision="ads-7.1.0" groups="pdk" />
    
    From b427cf0bf740d457afe96b36b0fe0abe73ce7b6b Mon Sep 17 00:00:00 2001
    From: AndDiSa <anddisa@googlemail.com>
    Date: Sat, 10 Jun 2023 17:04:42 +0200
    Subject: [PATCH 158/159] switch to own repo for tv settings
    
    Change-Id: Ia737c517e601ee462f0972131e328e40e2318965
    ---
     default.xml | 2 +-
     1 file changed, 1 insertion(+), 1 deletion(-)
    
    diff --git a/default.xml b/default.xml
    index c9f776c..8efafaf 100644
    --- a/default.xml
    +++ b/default.xml
    @@ -418,7 +418,7 @@
       <project path="packages/apps/Tag" name="platform/packages/apps/Tag" groups="pdk-fs" />
       <project path="packages/apps/Terminal" name="platform/packages/apps/Terminal" groups="pdk-fs" />
       <project path="packages/apps/Test/connectivity" name="platform/packages/apps/Test/connectivity" />
    -  <project path="packages/apps/TvSettings" name="platform/packages/apps/TvSettings" groups="generic_fs" />
    +  <project path="packages/apps/TvSettings" name="packages_apps_tv_settings" remote="ads" revision="ads-7.1.0" groups="generic_fs" />
       <project path="packages/apps/UnifiedEmail" name="packages_apps_unifiedemail" remote="ads" revision="ads-7.1.2" groups="pdk-fs" />
       <project path="packages/apps/WallpaperPicker" name="platform/packages/apps/WallpaperPicker" groups="pdk-fs" />
       <project path="packages/experimental" name="platform/packages/experimental" />
    
    From a4f6d4d45d54bcba012c22eb100bf4acbdae9bab Mon Sep 17 00:00:00 2001
    From: AndDiSa <anddisa@googlemail.com>
    Date: Sat, 4 Nov 2023 10:41:29 +0100
    Subject: [PATCH 159/159] use own libxml2 library
    
    Change-Id: I9e5c221cd791c233cc1240c36e362c6e6385bb3a
    ---
     default.xml | 2 +-
     1 file changed, 1 insertion(+), 1 deletion(-)
    
    diff --git a/default.xml b/default.xml
    index 8efafaf..9e65418 100644
    --- a/default.xml
    +++ b/default.xml
    @@ -197,7 +197,7 @@
       <project path="external/libvpx" name="external_libvpx" remote="ads" revision="ads-7.1.0" groups="pdk" />
       <project path="external/libvterm" name="platform/external/libvterm" groups="pdk-cw-fs,pdk-fs" />
       <project path="external/libweave" name="platform/external/libweave" />
    -  <project path="external/libxml2" name="platform/external/libxml2" groups="pdk-cw-fs,pdk-fs,libxml2" />
    +  <project path="external/libxml2" name="android_external_libxml2" remote="ads" revision="ads-7.1.0" groups="pdk-cw-fs,pdk-fs,libxml2" />
       <project path="external/libyuv" name="platform/external/libyuv" groups="libyuv,pdk-cw-fs,pdk-fs" />
       <project path="external/littlemock" name="platform/external/littlemock" groups="pdk-cw-fs,pdk-fs" />
       <project path="external/lld" name="platform/external/lld" groups="pdk-fs" />